summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
Diffstat (limited to 'source3')
-rw-r--r--source3/.dmallocrc2
-rw-r--r--source3/.indent.pro30
-rw-r--r--source3/Doxyfile192
-rw-r--r--source3/Makefile.in2734
-rw-r--r--source3/VERSION105
-rw-r--r--source3/auth/auth.c550
-rw-r--r--source3/auth/auth_builtin.c174
-rw-r--r--source3/auth/auth_compat.c130
-rw-r--r--source3/auth/auth_domain.c477
-rw-r--r--source3/auth/auth_ntlmssp.c214
-rw-r--r--source3/auth/auth_sam.c450
-rw-r--r--source3/auth/auth_script.c147
-rw-r--r--source3/auth/auth_server.c466
-rw-r--r--source3/auth/auth_unix.c145
-rw-r--r--source3/auth/auth_util.c2166
-rw-r--r--source3/auth/auth_winbind.c153
-rw-r--r--source3/auth/pampass.c886
-rw-r--r--source3/auth/pass_check.c874
-rw-r--r--source3/auth/token_util.c556
-rwxr-xr-xsource3/autogen.sh68
-rw-r--r--source3/change-log1878
-rw-r--r--source3/client/cifs.upcall.c391
-rw-r--r--source3/client/cifs_spnego.h46
-rw-r--r--source3/client/client.c4977
-rw-r--r--source3/client/client_proto.h52
-rw-r--r--source3/client/clitar.c1921
-rw-r--r--source3/client/dnsbrowse.c237
-rw-r--r--source3/client/mount.cifs.c1449
-rw-r--r--source3/client/smbspool.c624
-rw-r--r--source3/client/tree.c812
-rw-r--r--source3/client/umount.cifs.c386
-rw-r--r--source3/codepages/lowcase.datbin0 -> 131072 bytes
-rw-r--r--source3/codepages/upcase.datbin0 -> 131072 bytes
-rw-r--r--source3/codepages/valid.datbin0 -> 65536 bytes
-rwxr-xr-xsource3/config.guess1463
-rwxr-xr-xsource3/config.sub1577
-rwxr-xr-xsource3/configure.developer6
-rw-r--r--source3/configure.in6268
-rw-r--r--source3/dynconfig.c104
-rw-r--r--source3/exports/libaddns.syms5
-rw-r--r--source3/exports/modules-darwin.syms1
-rw-r--r--source3/groupdb/mapping.c808
-rw-r--r--source3/groupdb/mapping.h33
-rw-r--r--source3/groupdb/mapping_ldb.c699
-rw-r--r--source3/groupdb/mapping_tdb.c744
-rw-r--r--source3/include/MacExtensions.h245
-rw-r--r--source3/include/ads.h425
-rw-r--r--source3/include/ads_dns.h61
-rw-r--r--source3/include/ads_protos.h122
-rw-r--r--source3/include/adt_tree.h61
-rw-r--r--source3/include/asn_1.h71
-rw-r--r--source3/include/async_req.h137
-rw-r--r--source3/include/async_smb.h145
-rw-r--r--source3/include/async_sock.h45
-rw-r--r--source3/include/auth.h148
-rw-r--r--source3/include/authdata.h39
-rw-r--r--source3/include/byteorder.h176
-rw-r--r--source3/include/charset.h126
-rw-r--r--source3/include/client.h252
-rw-r--r--source3/include/clitar.h40
-rw-r--r--source3/include/core.h3
-rw-r--r--source3/include/ctdbd_conn.h77
-rw-r--r--source3/include/dbwrap.h91
-rw-r--r--source3/include/dcerpc.h0
-rw-r--r--source3/include/debug.h240
-rw-r--r--source3/include/debugparse.h126
-rw-r--r--source3/include/dlinklist.h113
-rw-r--r--source3/include/doserr.h303
-rw-r--r--source3/include/dynconfig.h89
-rw-r--r--source3/include/event.h24
-rw-r--r--source3/include/fake_file.h39
-rw-r--r--source3/include/gpo.h158
-rw-r--r--source3/include/hmacmd5.h29
-rw-r--r--source3/include/idmap.h81
-rw-r--r--source3/include/includes.h1320
-rw-r--r--source3/include/interfaces.h51
-rw-r--r--source3/include/intl.h23
-rw-r--r--source3/include/libmsrpc.h3045
-rw-r--r--source3/include/libmsrpc_internal.h73
-rw-r--r--source3/include/libsmb_internal.h536
-rw-r--r--source3/include/libsmbclient.h2819
-rw-r--r--source3/include/local.h256
-rw-r--r--source3/include/locking.h78
-rw-r--r--source3/include/mangle.h23
-rw-r--r--source3/include/mapping.h32
-rw-r--r--source3/include/md5.h19
-rw-r--r--source3/include/memcache.h115
-rw-r--r--source3/include/messages.h153
-rw-r--r--source3/include/module.h35
-rw-r--r--source3/include/msdfs.h75
-rw-r--r--source3/include/nameserv.h628
-rw-r--r--source3/include/ndr.h1
-rw-r--r--source3/include/nss_info.h90
-rw-r--r--source3/include/nt_printing.h485
-rw-r--r--source3/include/nt_status.h115
-rw-r--r--source3/include/ntdomain.h376
-rw-r--r--source3/include/nterr.h571
-rw-r--r--source3/include/ntioctl.h88
-rw-r--r--source3/include/ntlmssp.h175
-rw-r--r--source3/include/ntquotas.h91
-rw-r--r--source3/include/packet.h83
-rw-r--r--source3/include/passdb.h399
-rw-r--r--source3/include/popt_common.h58
-rw-r--r--source3/include/printing.h102
-rw-r--r--source3/include/privileges.h112
-rw-r--r--source3/include/proto.h10554
-rw-r--r--source3/include/rap.h506
-rw-r--r--source3/include/rbtree.h132
-rw-r--r--source3/include/reg_db.h30
-rw-r--r--source3/include/reg_objects.h172
-rw-r--r--source3/include/regfio.h222
-rw-r--r--source3/include/rpc_client.h74
-rw-r--r--source3/include/rpc_dce.h310
-rw-r--r--source3/include/rpc_eventlog.h123
-rw-r--r--source3/include/rpc_lsa.h59
-rw-r--r--source3/include/rpc_misc.h342
-rw-r--r--source3/include/rpc_ntsvcs.h69
-rw-r--r--source3/include/rpc_perfcount.h126
-rw-r--r--source3/include/rpc_perfcount_defs.h93
-rw-r--r--source3/include/rpc_secdes.h496
-rw-r--r--source3/include/rpc_spoolss.h2224
-rw-r--r--source3/include/rpc_svcctl.h259
-rw-r--r--source3/include/safe_string.h226
-rw-r--r--source3/include/samba_linux_quota.h335
-rw-r--r--source3/include/secrets.h102
-rw-r--r--source3/include/session.h42
-rw-r--r--source3/include/smb.h1904
-rw-r--r--source3/include/smb_acls.h65
-rw-r--r--source3/include/smb_ldap.h255
-rw-r--r--source3/include/smb_macros.h396
-rw-r--r--source3/include/smb_share_modes.h105
-rw-r--r--source3/include/smbldap.h234
-rw-r--r--source3/include/smbprofile.h866
-rw-r--r--source3/include/spnego.h64
-rw-r--r--source3/include/srvstr.h37
-rw-r--r--source3/include/stamp-h.in1
-rw-r--r--source3/include/sysquotas.h75
-rw-r--r--source3/include/talloc_stack.h56
-rw-r--r--source3/include/trans2.h772
-rw-r--r--source3/include/transfer_file.h32
-rw-r--r--source3/include/util_getent.h60
-rw-r--r--source3/include/util_tdb.h108
-rw-r--r--source3/include/vfs.h694
-rw-r--r--source3/include/vfs_macros.h399
-rw-r--r--source3/include/xfile.h48
-rw-r--r--source3/iniparser/AUTHORS5
-rw-r--r--source3/iniparser/INSTALL12
-rw-r--r--source3/iniparser/LICENSE21
-rw-r--r--source3/iniparser/Makefile63
-rw-r--r--source3/iniparser/README11
-rw-r--r--source3/iniparser/html/doxygen.css358
-rw-r--r--source3/iniparser/html/doxygen.pngbin0 -> 1281 bytes
-rw-r--r--source3/iniparser/html/globals_func.html54
-rw-r--r--source3/iniparser/html/index.html156
-rw-r--r--source3/iniparser/html/iniparser_8h.html629
-rw-r--r--source3/iniparser/html/iniparser_8main.html19
-rw-r--r--source3/iniparser/html/tab_b.gifbin0 -> 35 bytes
-rw-r--r--source3/iniparser/html/tab_l.gifbin0 -> 706 bytes
-rw-r--r--source3/iniparser/html/tab_r.gifbin0 -> 2585 bytes
-rw-r--r--source3/iniparser/html/tabs.css102
-rw-r--r--source3/iniparser/src/dictionary.c514
-rw-r--r--source3/iniparser/src/dictionary.h244
-rw-r--r--source3/iniparser/src/iniparser.c536
-rw-r--r--source3/iniparser/src/iniparser.h296
-rw-r--r--source3/iniparser/src/strlib.c211
-rw-r--r--source3/iniparser/src/strlib.h108
-rw-r--r--source3/iniparser/test/Makefile24
-rw-r--r--source3/iniparser/test/iniexample.c117
-rw-r--r--source3/iniparser_build/dictionary.c7
-rw-r--r--source3/iniparser_build/iniparser.c7
-rw-r--r--source3/iniparser_build/strlib.c7
-rwxr-xr-xsource3/install-sh238
-rw-r--r--source3/intl/lang_tdb.c246
-rw-r--r--source3/intl/linux-msg.sed99
-rw-r--r--source3/lib/access.c415
-rw-r--r--source3/lib/account_pol.c454
-rw-r--r--source3/lib/adt_tree.c430
-rw-r--r--source3/lib/afs.c298
-rw-r--r--source3/lib/afs_settoken.c239
-rw-r--r--source3/lib/arc4.c79
-rw-r--r--source3/lib/async_req.c174
-rw-r--r--source3/lib/async_sock.c674
-rw-r--r--source3/lib/audit.c148
-rw-r--r--source3/lib/bitmap.c176
-rw-r--r--source3/lib/charcnv.c1937
-rw-r--r--source3/lib/clobber.c63
-rw-r--r--source3/lib/compression/mszip.c676
-rw-r--r--source3/lib/compression/mszip.h33
-rw-r--r--source3/lib/conn_tdb.c126
-rw-r--r--source3/lib/crc32.c103
-rw-r--r--source3/lib/ctdbd_conn.c1247
-rw-r--r--source3/lib/data_blob.c180
-rw-r--r--source3/lib/dbwrap.c148
-rw-r--r--source3/lib/dbwrap_ctdb.c1223
-rw-r--r--source3/lib/dbwrap_file.c410
-rw-r--r--source3/lib/dbwrap_rbt.c390
-rw-r--r--source3/lib/dbwrap_tdb.c358
-rw-r--r--source3/lib/dbwrap_util.c309
-rw-r--r--source3/lib/debug.c1100
-rw-r--r--source3/lib/display_sec.c317
-rw-r--r--source3/lib/dmallocmsg.c78
-rw-r--r--source3/lib/dprintf.c118
-rw-r--r--source3/lib/dummyroot.c34
-rw-r--r--source3/lib/dummysmbd.c53
-rw-r--r--source3/lib/errmap_unix.c130
-rw-r--r--source3/lib/events.c449
-rw-r--r--source3/lib/fault.c223
-rw-r--r--source3/lib/file_id.c88
-rw-r--r--source3/lib/fsusage.c157
-rw-r--r--source3/lib/gencache.c506
-rw-r--r--source3/lib/genrand.c223
-rw-r--r--source3/lib/hmacmd5.c135
-rw-r--r--source3/lib/iconv.c775
-rw-r--r--source3/lib/idmap_cache.c260
-rw-r--r--source3/lib/interface.c577
-rw-r--r--source3/lib/interfaces.c351
-rw-r--r--source3/lib/ldap_debug_handler.c52
-rw-r--r--source3/lib/ldap_escape.c134
-rw-r--r--source3/lib/ldb/Doxyfile26
-rw-r--r--source3/lib/ldb/Makefile.in173
-rw-r--r--source3/lib/ldb/README_gcov.txt29
-rw-r--r--source3/lib/ldb/aclocal.m41
-rwxr-xr-xsource3/lib/ldb/autogen.sh17
-rw-r--r--source3/lib/ldb/common/attrib_handlers.c405
-rw-r--r--source3/lib/ldb/common/ldb.c1132
-rw-r--r--source3/lib/ldb/common/ldb_attributes.c308
-rw-r--r--source3/lib/ldb/common/ldb_controls.c105
-rw-r--r--source3/lib/ldb/common/ldb_debug.c104
-rw-r--r--source3/lib/ldb/common/ldb_dn.c1027
-rw-r--r--source3/lib/ldb/common/ldb_ldif.c760
-rw-r--r--source3/lib/ldb/common/ldb_match.c430
-rw-r--r--source3/lib/ldb/common/ldb_modules.c459
-rw-r--r--source3/lib/ldb/common/ldb_msg.c829
-rw-r--r--source3/lib/ldb/common/ldb_parse.c818
-rw-r--r--source3/lib/ldb/common/ldb_utf8.c148
-rw-r--r--source3/lib/ldb/common/qsort.c252
-rwxr-xr-xsource3/lib/ldb/config.guess1464
-rw-r--r--source3/lib/ldb/config.mk315
-rwxr-xr-xsource3/lib/ldb/config.sub1577
-rw-r--r--source3/lib/ldb/configure.ac74
-rwxr-xr-xsource3/lib/ldb/docs/builddocs.sh52
-rw-r--r--source3/lib/ldb/docs/design.txt41
-rwxr-xr-xsource3/lib/ldb/docs/installdocs.sh17
-rw-r--r--source3/lib/ldb/examples.dox16
-rw-r--r--source3/lib/ldb/examples/ldbreader.c123
-rw-r--r--source3/lib/ldb/examples/ldifreader.c127
-rw-r--r--source3/lib/ldb/include/dlinklist.h110
-rw-r--r--source3/lib/ldb/include/includes.h29
-rw-r--r--source3/lib/ldb/include/ldb.h1560
-rw-r--r--source3/lib/ldb/include/ldb_errors.h310
-rw-r--r--source3/lib/ldb/include/ldb_private.h224
-rwxr-xr-xsource3/lib/ldb/install-sh238
-rw-r--r--source3/lib/ldb/ldap.m490
-rw-r--r--source3/lib/ldb/ldb.pc.in15
-rw-r--r--source3/lib/ldb/ldb_ildap/ldb_ildap.c827
-rw-r--r--source3/lib/ldb/ldb_ldap/ldb_ldap.c846
-rw-r--r--source3/lib/ldb/ldb_sqlite3/README7
-rw-r--r--source3/lib/ldb/ldb_sqlite3/base160.c154
-rw-r--r--source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c1911
-rw-r--r--source3/lib/ldb/ldb_sqlite3/schema363
-rw-r--r--source3/lib/ldb/ldb_sqlite3/trees.ps1760
-rw-r--r--source3/lib/ldb/ldb_tdb/ldb_cache.c560
-rw-r--r--source3/lib/ldb/ldb_tdb/ldb_index.c1178
-rw-r--r--source3/lib/ldb/ldb_tdb/ldb_pack.c293
-rw-r--r--source3/lib/ldb/ldb_tdb/ldb_search.c527
-rw-r--r--source3/lib/ldb/ldb_tdb/ldb_tdb.c1084
-rw-r--r--source3/lib/ldb/ldb_tdb/ldb_tdb.h129
-rw-r--r--source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c154
-rw-r--r--source3/lib/ldb/libldb.m433
-rw-r--r--source3/lib/ldb/mainpage.dox80
-rw-r--r--source3/lib/ldb/man/ad2oLschema.1.xml87
-rw-r--r--source3/lib/ldb/man/ldb.3.xml262
-rw-r--r--source3/lib/ldb/man/ldbadd.1.xml105
-rw-r--r--source3/lib/ldb/man/ldbdel.1.xml105
-rw-r--r--source3/lib/ldb/man/ldbedit.1.xml200
-rw-r--r--source3/lib/ldb/man/ldbmodify.1.xml93
-rw-r--r--source3/lib/ldb/man/ldbrename.1.xml107
-rw-r--r--source3/lib/ldb/man/ldbsearch.1.xml119
-rw-r--r--source3/lib/ldb/man/oLschema2ldif.1.xml79
-rw-r--r--source3/lib/ldb/modules/asq.c488
-rw-r--r--source3/lib/ldb/modules/ldb_map.c1337
-rw-r--r--source3/lib/ldb/modules/ldb_map.h157
-rw-r--r--source3/lib/ldb/modules/ldb_map_inbound.c723
-rw-r--r--source3/lib/ldb/modules/ldb_map_outbound.c1285
-rw-r--r--source3/lib/ldb/modules/ldb_map_private.h117
-rw-r--r--source3/lib/ldb/modules/objectclass.c693
-rw-r--r--source3/lib/ldb/modules/operational.c311
-rw-r--r--source3/lib/ldb/modules/paged_results.c566
-rw-r--r--source3/lib/ldb/modules/paged_searches.c467
-rw-r--r--source3/lib/ldb/modules/rdn_name.c342
-rw-r--r--source3/lib/ldb/modules/skel.c136
-rw-r--r--source3/lib/ldb/modules/sort.c442
-rw-r--r--source3/lib/ldb/nssldb/README.txt34
-rw-r--r--source3/lib/ldb/nssldb/ldb-grp.c425
-rw-r--r--source3/lib/ldb/nssldb/ldb-nss.c400
-rw-r--r--source3/lib/ldb/nssldb/ldb-nss.h84
-rw-r--r--source3/lib/ldb/nssldb/ldb-pwd.c239
-rw-r--r--source3/lib/ldb/samba/README7
-rw-r--r--source3/lib/ldb/samba/ldif_handlers.c483
-rw-r--r--source3/lib/ldb/sqlite3.m462
-rwxr-xr-xsource3/lib/ldb/standalone.sh25
-rw-r--r--source3/lib/ldb/swig/Ldb.py178
-rw-r--r--source3/lib/ldb/swig/ldb.i239
-rw-r--r--source3/lib/ldb/tests/init.ldif40
-rwxr-xr-xsource3/lib/ldb/tests/init_slapd.sh41
-rwxr-xr-xsource3/lib/ldb/tests/kill_slapd.sh12
-rwxr-xr-xsource3/lib/ldb/tests/ldapi_url.sh11
-rw-r--r--source3/lib/ldb/tests/photo.ldif5
-rw-r--r--source3/lib/ldb/tests/samba4.pngbin0 -> 6239 bytes
-rw-r--r--source3/lib/ldb/tests/schema-tests/schema-add-test.ldif66
-rw-r--r--source3/lib/ldb/tests/schema-tests/schema-mod-test-1.ldif5
-rw-r--r--source3/lib/ldb/tests/schema-tests/schema-mod-test-2.ldif5
-rw-r--r--source3/lib/ldb/tests/schema-tests/schema-mod-test-3.ldif5
-rw-r--r--source3/lib/ldb/tests/schema-tests/schema-mod-test-4.ldif5
-rw-r--r--source3/lib/ldb/tests/schema-tests/schema-mod-test-5.ldif5
-rw-r--r--source3/lib/ldb/tests/schema-tests/schema.ldif112
-rw-r--r--source3/lib/ldb/tests/slapd.conf26
-rwxr-xr-xsource3/lib/ldb/tests/start_slapd.sh14
-rw-r--r--source3/lib/ldb/tests/test-attribs.ldif15
-rw-r--r--source3/lib/ldb/tests/test-config.ldif67
-rw-r--r--source3/lib/ldb/tests/test-default-config.ldif17
-rwxr-xr-xsource3/lib/ldb/tests/test-extended.sh69
-rwxr-xr-xsource3/lib/ldb/tests/test-generic.sh128
-rw-r--r--source3/lib/ldb/tests/test-index.ldif11
-rwxr-xr-xsource3/lib/ldb/tests/test-ldap.sh54
-rw-r--r--source3/lib/ldb/tests/test-modify.ldif23
-rwxr-xr-xsource3/lib/ldb/tests/test-schema.sh34
-rwxr-xr-xsource3/lib/ldb/tests/test-sqlite3.sh25
-rw-r--r--source3/lib/ldb/tests/test-tdb-features.sh119
-rwxr-xr-xsource3/lib/ldb/tests/test-tdb.sh31
-rw-r--r--source3/lib/ldb/tests/test-wildcard.ldif5
-rw-r--r--source3/lib/ldb/tests/test-wrong_attributes.ldif3
-rw-r--r--source3/lib/ldb/tests/test.ldif411
-rw-r--r--source3/lib/ldb/tests/testdata.txt8
-rw-r--r--source3/lib/ldb/tests/testsearch.txt5
-rw-r--r--source3/lib/ldb/tools/ad2oLschema.c629
-rw-r--r--source3/lib/ldb/tools/cmdline.c754
-rw-r--r--source3/lib/ldb/tools/cmdline.h53
-rw-r--r--source3/lib/ldb/tools/convert.c165
-rw-r--r--source3/lib/ldb/tools/convert.h10
-rw-r--r--source3/lib/ldb/tools/ldbadd.c119
-rw-r--r--source3/lib/ldb/tools/ldbdel.c118
-rw-r--r--source3/lib/ldb/tools/ldbedit.c330
-rw-r--r--source3/lib/ldb/tools/ldbmodify.c119
-rw-r--r--source3/lib/ldb/tools/ldbrename.c84
-rw-r--r--source3/lib/ldb/tools/ldbsearch.c320
-rw-r--r--source3/lib/ldb/tools/ldbtest.c409
-rw-r--r--source3/lib/ldb/tools/oLschema2ldif.c607
-rw-r--r--source3/lib/ldb/web/index.html85
-rw-r--r--source3/lib/md4.c174
-rw-r--r--source3/lib/md5.c247
-rw-r--r--source3/lib/memcache.c417
-rw-r--r--source3/lib/messages.c363
-rw-r--r--source3/lib/messages_ctdbd.c158
-rw-r--r--source3/lib/messages_local.c436
-rw-r--r--source3/lib/module.c166
-rw-r--r--source3/lib/ms_fnmatch.c238
-rw-r--r--source3/lib/netapi/Doxyfile1362
-rw-r--r--source3/lib/netapi/cm.c198
-rw-r--r--source3/lib/netapi/examples/Makefile.in328
-rw-r--r--source3/lib/netapi/examples/common.c65
-rw-r--r--source3/lib/netapi/examples/common.h11
-rw-r--r--source3/lib/netapi/examples/dsgetdc/dsgetdc.c101
-rw-r--r--source3/lib/netapi/examples/file/file_close.c83
-rw-r--r--source3/lib/netapi/examples/file/file_enum.c146
-rw-r--r--source3/lib/netapi/examples/file/file_getinfo.c112
-rw-r--r--source3/lib/netapi/examples/getdc/getdc.c86
-rw-r--r--source3/lib/netapi/examples/group/group_add.c90
-rw-r--r--source3/lib/netapi/examples/group/group_adduser.c91
-rw-r--r--source3/lib/netapi/examples/group/group_del.c82
-rw-r--r--source3/lib/netapi/examples/group/group_deluser.c91
-rw-r--r--source3/lib/netapi/examples/group/group_enum.c153
-rw-r--r--source3/lib/netapi/examples/group/group_getinfo.c127
-rw-r--r--source3/lib/netapi/examples/group/group_getusers.c132
-rw-r--r--source3/lib/netapi/examples/group/group_setinfo.c142
-rw-r--r--source3/lib/netapi/examples/group/group_setusers.c142
-rw-r--r--source3/lib/netapi/examples/join/getjoinableous.c95
-rw-r--r--source3/lib/netapi/examples/join/netdomjoin.c104
-rw-r--r--source3/lib/netapi/examples/join/rename_machine.c86
-rw-r--r--source3/lib/netapi/examples/localgroup/localgroup_add.c106
-rw-r--r--source3/lib/netapi/examples/localgroup/localgroup_addmembers.c141
-rw-r--r--source3/lib/netapi/examples/localgroup/localgroup_del.c83
-rw-r--r--source3/lib/netapi/examples/localgroup/localgroup_delmembers.c141
-rw-r--r--source3/lib/netapi/examples/localgroup/localgroup_enum.c126
-rw-r--r--source3/lib/netapi/examples/localgroup/localgroup_getinfo.c112
-rw-r--r--source3/lib/netapi/examples/localgroup/localgroup_getmembers.c165
-rw-r--r--source3/lib/netapi/examples/localgroup/localgroup_setinfo.c128
-rw-r--r--source3/lib/netapi/examples/localgroup/localgroup_setmembers.c146
-rw-r--r--source3/lib/netapi/examples/netdomjoin-gui/logo-small.pngbin0 -> 4485 bytes
-rw-r--r--source3/lib/netapi/examples/netdomjoin-gui/logo.pngbin0 -> 9329 bytes
-rw-r--r--source3/lib/netapi/examples/netdomjoin-gui/netdomjoin-gui.c1817
-rwxr-xr-xsource3/lib/netapi/examples/netdomjoin-gui/samba.icobin0 -> 1406 bytes
-rw-r--r--source3/lib/netapi/examples/server/remote_tod.c83
-rw-r--r--source3/lib/netapi/examples/server/server_getinfo.c128
-rw-r--r--source3/lib/netapi/examples/share/share_add.c110
-rw-r--r--source3/lib/netapi/examples/share/share_del.c85
-rw-r--r--source3/lib/netapi/examples/share/share_enum.c142
-rw-r--r--source3/lib/netapi/examples/share/share_getinfo.c152
-rw-r--r--source3/lib/netapi/examples/share/share_setinfo.c105
-rw-r--r--source3/lib/netapi/examples/user/user_add.c103
-rw-r--r--source3/lib/netapi/examples/user/user_chgpwd.c99
-rw-r--r--source3/lib/netapi/examples/user/user_del.c82
-rw-r--r--source3/lib/netapi/examples/user/user_dispinfo.c100
-rw-r--r--source3/lib/netapi/examples/user/user_enum.c157
-rw-r--r--source3/lib/netapi/examples/user/user_getgroups.c133
-rw-r--r--source3/lib/netapi/examples/user/user_getinfo.c293
-rw-r--r--source3/lib/netapi/examples/user/user_getlocalgroups.c122
-rw-r--r--source3/lib/netapi/examples/user/user_modalsget.c131
-rw-r--r--source3/lib/netapi/examples/user/user_modalsset.c141
-rw-r--r--source3/lib/netapi/examples/user/user_setgroups.c144
-rw-r--r--source3/lib/netapi/examples/user/user_setinfo.c207
-rw-r--r--source3/lib/netapi/file.c289
-rw-r--r--source3/lib/netapi/getdc.c167
-rw-r--r--source3/lib/netapi/group.c1691
-rw-r--r--source3/lib/netapi/joindomain.c501
-rw-r--r--source3/lib/netapi/libnetapi.c2355
-rw-r--r--source3/lib/netapi/libnetapi.h429
-rw-r--r--source3/lib/netapi/localgroup.c1358
-rw-r--r--source3/lib/netapi/netapi.c348
-rw-r--r--source3/lib/netapi/netapi.h1840
-rw-r--r--source3/lib/netapi/netapi_private.h87
-rw-r--r--source3/lib/netapi/samr.c319
-rw-r--r--source3/lib/netapi/serverinfo.c360
-rw-r--r--source3/lib/netapi/share.c555
-rw-r--r--source3/lib/netapi/sid.c76
-rw-r--r--source3/lib/netapi/tests/Makefile.in57
-rw-r--r--source3/lib/netapi/tests/common.c86
-rw-r--r--source3/lib/netapi/tests/common.h57
-rw-r--r--source3/lib/netapi/tests/netapitest.c97
-rw-r--r--source3/lib/netapi/tests/netdisplay.c150
-rw-r--r--source3/lib/netapi/tests/netgroup.c286
-rw-r--r--source3/lib/netapi/tests/netlocalgroup.c226
-rw-r--r--source3/lib/netapi/tests/netshare.c232
-rw-r--r--source3/lib/netapi/tests/netuser.c458
-rw-r--r--source3/lib/netapi/user.c3440
-rw-r--r--source3/lib/nss_wrapper/config.m419
-rw-r--r--source3/lib/nss_wrapper/config.mk10
-rw-r--r--source3/lib/nss_wrapper/nss_wrapper.c1130
-rw-r--r--source3/lib/nss_wrapper/nss_wrapper.h165
-rw-r--r--source3/lib/nss_wrapper/nss_wrapper.pl265
-rw-r--r--source3/lib/packet.c257
-rw-r--r--source3/lib/pam_errors.c139
-rw-r--r--source3/lib/pidfile.c147
-rw-r--r--source3/lib/popt_common.c555
-rw-r--r--source3/lib/privileges.c464
-rw-r--r--source3/lib/privileges_basic.c515
-rw-r--r--source3/lib/rbtree.c422
-rw-r--r--source3/lib/readline.c181
-rw-r--r--source3/lib/recvfile.c233
-rw-r--r--source3/lib/replace/.checker_innocent4
-rw-r--r--source3/lib/replace/Makefile.in63
-rw-r--r--source3/lib/replace/README113
-rw-r--r--source3/lib/replace/aclocal.m41
-rw-r--r--source3/lib/replace/autoconf-2.60.m4210
-rwxr-xr-xsource3/lib/replace/autogen.sh13
-rwxr-xr-xsource3/lib/replace/config.guess1464
-rwxr-xr-xsource3/lib/replace/config.sub1577
-rw-r--r--source3/lib/replace/configure.ac30
-rw-r--r--source3/lib/replace/dlfcn.c75
-rw-r--r--source3/lib/replace/dlfcn.m431
-rw-r--r--source3/lib/replace/getaddrinfo.c497
-rw-r--r--source3/lib/replace/getaddrinfo.h89
-rw-r--r--source3/lib/replace/getifaddrs.c361
-rw-r--r--source3/lib/replace/getpass.c222
-rw-r--r--source3/lib/replace/getpass.m424
-rw-r--r--source3/lib/replace/inet_aton.c33
-rw-r--r--source3/lib/replace/inet_ntoa.c39
-rw-r--r--source3/lib/replace/inet_ntop.c191
-rw-r--r--source3/lib/replace/inet_pton.c213
-rwxr-xr-xsource3/lib/replace/install-sh238
-rw-r--r--source3/lib/replace/libreplace.m4303
-rw-r--r--source3/lib/replace/libreplace_cc.m4182
-rw-r--r--source3/lib/replace/libreplace_ld.m4319
-rw-r--r--source3/lib/replace/libreplace_macros.m4332
-rw-r--r--source3/lib/replace/libreplace_network.m4377
-rw-r--r--source3/lib/replace/repdir.m478
-rw-r--r--source3/lib/replace/repdir_getdents.c166
-rw-r--r--source3/lib/replace/repdir_getdirentries.c183
-rw-r--r--source3/lib/replace/replace.c616
-rw-r--r--source3/lib/replace/replace.h582
-rw-r--r--source3/lib/replace/samba.m435
-rw-r--r--source3/lib/replace/snprintf.c1530
-rw-r--r--source3/lib/replace/socket.c35
-rw-r--r--source3/lib/replace/socketpair.c46
-rw-r--r--source3/lib/replace/strptime.c990
-rw-r--r--source3/lib/replace/strptime.m413
-rw-r--r--source3/lib/replace/system/README4
-rw-r--r--source3/lib/replace/system/aio.h32
-rw-r--r--source3/lib/replace/system/capability.h55
-rw-r--r--source3/lib/replace/system/config.m4130
-rw-r--r--source3/lib/replace/system/dir.h67
-rw-r--r--source3/lib/replace/system/filesys.h182
-rw-r--r--source3/lib/replace/system/glob.h37
-rw-r--r--source3/lib/replace/system/iconv.h57
-rw-r--r--source3/lib/replace/system/kerberos.h137
-rw-r--r--source3/lib/replace/system/locale.h38
-rw-r--r--source3/lib/replace/system/network.h332
-rw-r--r--source3/lib/replace/system/passwd.h110
-rw-r--r--source3/lib/replace/system/readline.h52
-rw-r--r--source3/lib/replace/system/select.h41
-rw-r--r--source3/lib/replace/system/shmem.h59
-rw-r--r--source3/lib/replace/system/syslog.h70
-rw-r--r--source3/lib/replace/system/terminal.h46
-rw-r--r--source3/lib/replace/system/time.h69
-rw-r--r--source3/lib/replace/system/wait.h55
-rw-r--r--source3/lib/replace/test/getifaddrs.c100
-rw-r--r--source3/lib/replace/test/os2_delete.c124
-rw-r--r--source3/lib/replace/test/shared_mmap.c68
-rw-r--r--source3/lib/replace/test/strptime.c172
-rw-r--r--source3/lib/replace/test/testsuite.c1080
-rw-r--r--source3/lib/replace/timegm.c78
-rw-r--r--source3/lib/replace/timegm.m41
-rw-r--r--source3/lib/replace/win32.m420
-rw-r--r--source3/lib/replace/win32_replace.h159
-rw-r--r--source3/lib/secace.c293
-rw-r--r--source3/lib/secacl.c118
-rw-r--r--source3/lib/secdesc.c559
-rw-r--r--source3/lib/select.c192
-rw-r--r--source3/lib/sendfile.c461
-rw-r--r--source3/lib/server_mutex.c78
-rw-r--r--source3/lib/sharesec.c400
-rw-r--r--source3/lib/signal.c138
-rw-r--r--source3/lib/smbconf/smbconf.c388
-rw-r--r--source3/lib/smbconf/smbconf.h114
-rw-r--r--source3/lib/smbconf/smbconf_init.c95
-rw-r--r--source3/lib/smbconf/smbconf_private.h85
-rw-r--r--source3/lib/smbconf/smbconf_reg.c1148
-rw-r--r--source3/lib/smbconf/smbconf_txt.c641
-rw-r--r--source3/lib/smbconf/smbconf_util.c151
-rw-r--r--source3/lib/smbconf/testsuite.c283
-rw-r--r--source3/lib/smbldap.c1824
-rw-r--r--source3/lib/smbldap_util.c334
-rw-r--r--source3/lib/smbrun.c341
-rw-r--r--source3/lib/sock_exec.c118
-rw-r--r--source3/lib/socket_wrapper/config.m422
-rw-r--r--source3/lib/socket_wrapper/config.mk8
-rw-r--r--source3/lib/socket_wrapper/socket_wrapper.c1841
-rw-r--r--source3/lib/socket_wrapper/socket_wrapper.h136
-rw-r--r--source3/lib/socket_wrapper/testsuite.c105
-rw-r--r--source3/lib/substitute.c915
-rw-r--r--source3/lib/sysacls.c621
-rw-r--r--source3/lib/sysquotas.c547
-rw-r--r--source3/lib/sysquotas_4A.c346
-rw-r--r--source3/lib/sysquotas_linux.c568
-rw-r--r--source3/lib/sysquotas_xfs.c336
-rw-r--r--source3/lib/system.c2492
-rw-r--r--source3/lib/system_smbd.c198
-rw-r--r--source3/lib/talloc/Makefile.in43
-rw-r--r--source3/lib/talloc/NEWS13
-rw-r--r--source3/lib/talloc/aclocal.m41
-rwxr-xr-xsource3/lib/talloc/autogen.sh14
-rwxr-xr-xsource3/lib/talloc/config.guess1464
-rw-r--r--source3/lib/talloc/config.mk7
-rwxr-xr-xsource3/lib/talloc/config.sub1577
-rw-r--r--source3/lib/talloc/configure.ac24
-rwxr-xr-xsource3/lib/talloc/install-sh238
-rw-r--r--source3/lib/talloc/libtalloc.m433
-rw-r--r--source3/lib/talloc/rules.mk18
-rw-r--r--source3/lib/talloc/talloc.3.xml738
-rw-r--r--source3/lib/talloc/talloc.c1732
-rw-r--r--source3/lib/talloc/talloc.h183
-rw-r--r--source3/lib/talloc/talloc.i31
-rw-r--r--source3/lib/talloc/talloc.mk37
-rw-r--r--source3/lib/talloc/talloc.pc.in11
-rw-r--r--source3/lib/talloc/talloc_guide.txt685
-rw-r--r--source3/lib/talloc/testsuite.c1152
-rw-r--r--source3/lib/talloc/web/index.html46
-rw-r--r--source3/lib/talloc_stack.c130
-rw-r--r--source3/lib/tallocmsg.c107
-rw-r--r--source3/lib/tdb/Makefile.in59
-rw-r--r--source3/lib/tdb/aclocal.m41
-rwxr-xr-xsource3/lib/tdb/autogen.sh16
-rw-r--r--source3/lib/tdb/common/dump.c137
-rw-r--r--source3/lib/tdb/common/error.c57
-rw-r--r--source3/lib/tdb/common/freelist.c382
-rw-r--r--source3/lib/tdb/common/freelistcheck.c107
-rw-r--r--source3/lib/tdb/common/io.c473
-rw-r--r--source3/lib/tdb/common/lock.c553
-rw-r--r--source3/lib/tdb/common/open.c488
-rw-r--r--source3/lib/tdb/common/tdb.c802
-rw-r--r--source3/lib/tdb/common/tdb_private.h213
-rw-r--r--source3/lib/tdb/common/transaction.c1119
-rw-r--r--source3/lib/tdb/common/traverse.c348
-rwxr-xr-xsource3/lib/tdb/config.guess1464
-rw-r--r--source3/lib/tdb/config.mk57
-rwxr-xr-xsource3/lib/tdb/config.sub1577
-rw-r--r--source3/lib/tdb/configure.ac30
-rw-r--r--source3/lib/tdb/docs/README238
-rw-r--r--source3/lib/tdb/docs/tdb.magic10
-rw-r--r--source3/lib/tdb/include/tdb.h167
-rwxr-xr-xsource3/lib/tdb/install-sh238
-rw-r--r--source3/lib/tdb/libtdb.m430
-rw-r--r--source3/lib/tdb/python.mk10
-rw-r--r--source3/lib/tdb/python/tdbdump.py12
-rw-r--r--source3/lib/tdb/python/tests/simple.py152
-rw-r--r--source3/lib/tdb/rules.mk21
-rw-r--r--source3/lib/tdb/tdb.i323
-rw-r--r--source3/lib/tdb/tdb.mk86
-rw-r--r--source3/lib/tdb/tdb.pc.in11
-rw-r--r--source3/lib/tdb/tdb.py341
-rw-r--r--source3/lib/tdb/tdb_wrap.c4307
-rw-r--r--source3/lib/tdb/tools/tdbbackup.c300
-rw-r--r--source3/lib/tdb/tools/tdbdump.c116
-rw-r--r--source3/lib/tdb/tools/tdbtest.c265
-rw-r--r--source3/lib/tdb/tools/tdbtool.c659
-rw-r--r--source3/lib/tdb/tools/tdbtorture.c318
-rw-r--r--source3/lib/tdb/web/index.html42
-rw-r--r--source3/lib/time.c1505
-rw-r--r--source3/lib/ufc.c770
-rw-r--r--source3/lib/username.c196
-rw-r--r--source3/lib/util.c3523
-rw-r--r--source3/lib/util_file.c424
-rw-r--r--source3/lib/util_nscd.c41
-rw-r--r--source3/lib/util_nttoken.c117
-rw-r--r--source3/lib/util_pw.c89
-rw-r--r--source3/lib/util_reg.c112
-rw-r--r--source3/lib/util_reg_api.c223
-rw-r--r--source3/lib/util_seaccess.c359
-rw-r--r--source3/lib/util_sec.c482
-rw-r--r--source3/lib/util_sid.c751
-rw-r--r--source3/lib/util_sock.c2104
-rw-r--r--source3/lib/util_str.c2897
-rw-r--r--source3/lib/util_tdb.c1481
-rw-r--r--source3/lib/util_transfer_file.c110
-rw-r--r--source3/lib/util_unistr.c1104
-rw-r--r--source3/lib/util_uuid.c131
-rw-r--r--source3/lib/version.c27
-rw-r--r--source3/lib/winbind_util.c321
-rw-r--r--source3/lib/wins_srv.c361
-rw-r--r--source3/lib/xfile.c417
-rw-r--r--source3/libaddns/addns.h30
-rw-r--r--source3/libaddns/dns.h535
-rw-r--r--source3/libaddns/dnserr.h87
-rw-r--r--source3/libaddns/dnsgss.c332
-rw-r--r--source3/libaddns/dnsmarshall.c529
-rw-r--r--source3/libaddns/dnsrecord.c422
-rw-r--r--source3/libaddns/dnssock.c377
-rw-r--r--source3/libaddns/dnsutils.c151
-rw-r--r--source3/libads/ads_status.c152
-rw-r--r--source3/libads/ads_struct.c183
-rw-r--r--source3/libads/ads_utils.c150
-rw-r--r--source3/libads/authdata.c563
-rw-r--r--source3/libads/cldap.c368
-rw-r--r--source3/libads/disp_sec.c237
-rw-r--r--source3/libads/dns.c1011
-rw-r--r--source3/libads/kerberos.c1019
-rw-r--r--source3/libads/kerberos_keytab.c777
-rw-r--r--source3/libads/kerberos_verify.c576
-rw-r--r--source3/libads/krb5_errs.c116
-rw-r--r--source3/libads/krb5_setpw.c819
-rw-r--r--source3/libads/ldap.c3824
-rw-r--r--source3/libads/ldap_printer.c373
-rw-r--r--source3/libads/ldap_schema.c384
-rw-r--r--source3/libads/ldap_user.c127
-rw-r--r--source3/libads/ldap_utils.c373
-rw-r--r--source3/libads/ndr.c118
-rw-r--r--source3/libads/sasl.c1127
-rw-r--r--source3/libads/sasl_wrapping.c312
-rw-r--r--source3/libads/util.c113
-rw-r--r--source3/libcli/nbt/libnbt.h353
-rw-r--r--source3/libcli/nbt/nbtname.c626
-rw-r--r--source3/libgpo/gpext/gpext.c746
-rw-r--r--source3/libgpo/gpext/gpext.h79
-rw-r--r--source3/libgpo/gpext/registry.c643
-rw-r--r--source3/libgpo/gpext/scripts.c443
-rw-r--r--source3/libgpo/gpo_fetch.c187
-rw-r--r--source3/libgpo/gpo_filesync.c238
-rw-r--r--source3/libgpo/gpo_ini.c245
-rw-r--r--source3/libgpo/gpo_ini.h33
-rw-r--r--source3/libgpo/gpo_ldap.c866
-rw-r--r--source3/libgpo/gpo_reg.c1009
-rw-r--r--source3/libgpo/gpo_sec.c186
-rw-r--r--source3/libgpo/gpo_util.c870
-rw-r--r--source3/libnet/libnet.h29
-rw-r--r--source3/libnet/libnet_dssync.c720
-rw-r--r--source3/libnet/libnet_dssync.h57
-rw-r--r--source3/libnet/libnet_dssync_keytab.c641
-rw-r--r--source3/libnet/libnet_join.c2018
-rw-r--r--source3/libnet/libnet_keytab.c404
-rw-r--r--source3/libnet/libnet_keytab.h42
-rw-r--r--source3/libnet/libnet_proto.h78
-rw-r--r--source3/libnet/libnet_samsync.c411
-rw-r--r--source3/libnet/libnet_samsync.h73
-rw-r--r--source3/libnet/libnet_samsync_display.c303
-rw-r--r--source3/libnet/libnet_samsync_keytab.c193
-rw-r--r--source3/libnet/libnet_samsync_ldif.c1229
-rw-r--r--source3/libnet/libnet_samsync_passdb.c789
-rw-r--r--source3/librpc/gen_ndr/cli_dfs.c1099
-rw-r--r--source3/librpc/gen_ndr/cli_dfs.h138
-rw-r--r--source3/librpc/gen_ndr/cli_drsuapi.c1167
-rw-r--r--source3/librpc/gen_ndr/cli_drsuapi.h144
-rw-r--r--source3/librpc/gen_ndr/cli_dssetup.c465
-rw-r--r--source3/librpc/gen_ndr/cli_dssetup.h39
-rw-r--r--source3/librpc/gen_ndr/cli_echo.c410
-rw-r--r--source3/librpc/gen_ndr/cli_echo.h43
-rw-r--r--source3/librpc/gen_ndr/cli_epmapper.c347
-rw-r--r--source3/librpc/gen_ndr/cli_epmapper.h44
-rw-r--r--source3/librpc/gen_ndr/cli_eventlog.c915
-rw-r--r--source3/librpc/gen_ndr/cli_eventlog.h73
-rw-r--r--source3/librpc/gen_ndr/cli_initshutdown.c155
-rw-r--r--source3/librpc/gen_ndr/cli_initshutdown.h25
-rw-r--r--source3/librpc/gen_ndr/cli_lsa.c3401
-rw-r--r--source3/librpc/gen_ndr/cli_lsa.h370
-rw-r--r--source3/librpc/gen_ndr/cli_netlogon.c2338
-rw-r--r--source3/librpc/gen_ndr/cli_netlogon.h361
-rw-r--r--source3/librpc/gen_ndr/cli_ntsvcs.c2735
-rw-r--r--source3/librpc/gen_ndr/cli_ntsvcs.h225
-rw-r--r--source3/librpc/gen_ndr/cli_samr.c2962
-rw-r--r--source3/librpc/gen_ndr/cli_samr.h389
-rw-r--r--source3/librpc/gen_ndr/cli_srvsvc.c2641
-rw-r--r--source3/librpc/gen_ndr/cli_srvsvc.h347
-rw-r--r--source3/librpc/gen_ndr/cli_svcctl.c2245
-rw-r--r--source3/librpc/gen_ndr/cli_svcctl.h336
-rw-r--r--source3/librpc/gen_ndr/cli_winreg.c1726
-rw-r--r--source3/librpc/gen_ndr/cli_winreg.h229
-rw-r--r--source3/librpc/gen_ndr/cli_wkssvc.c1570
-rw-r--r--source3/librpc/gen_ndr/cli_wkssvc.h230
-rw-r--r--source3/librpc/gen_ndr/dfs.h581
-rw-r--r--source3/librpc/gen_ndr/drsblobs.h427
-rw-r--r--source3/librpc/gen_ndr/drsuapi.h1762
-rw-r--r--source3/librpc/gen_ndr/dssetup.h211
-rw-r--r--source3/librpc/gen_ndr/echo.h213
-rw-r--r--source3/librpc/gen_ndr/epmapper.h354
-rw-r--r--source3/librpc/gen_ndr/eventlog.h287
-rw-r--r--source3/librpc/gen_ndr/initshutdown.h64
-rw-r--r--source3/librpc/gen_ndr/krb5pac.h137
-rw-r--r--source3/librpc/gen_ndr/libnet_join.h82
-rw-r--r--source3/librpc/gen_ndr/libnetapi.h1457
-rw-r--r--source3/librpc/gen_ndr/lsa.h1647
-rw-r--r--source3/librpc/gen_ndr/messaging.h146
-rw-r--r--source3/librpc/gen_ndr/misc.h73
-rw-r--r--source3/librpc/gen_ndr/nbt.h820
-rw-r--r--source3/librpc/gen_ndr/ndr_dfs.c5802
-rw-r--r--source3/librpc/gen_ndr/ndr_dfs.h132
-rw-r--r--source3/librpc/gen_ndr/ndr_drsblobs.c3534
-rw-r--r--source3/librpc/gen_ndr/ndr_drsblobs.h133
-rw-r--r--source3/librpc/gen_ndr/ndr_drsuapi.c14559
-rw-r--r--source3/librpc/gen_ndr/ndr_drsuapi.h291
-rw-r--r--source3/librpc/gen_ndr/ndr_dssetup.c1082
-rw-r--r--source3/librpc/gen_ndr/ndr_dssetup.h58
-rw-r--r--source3/librpc/gen_ndr/ndr_echo.c1513
-rw-r--r--source3/librpc/gen_ndr/ndr_echo.h58
-rw-r--r--source3/librpc/gen_ndr/ndr_epmapper.c2699
-rw-r--r--source3/librpc/gen_ndr/ndr_epmapper.h76
-rw-r--r--source3/librpc/gen_ndr/ndr_eventlog.c1730
-rw-r--r--source3/librpc/gen_ndr/ndr_eventlog.h91
-rw-r--r--source3/librpc/gen_ndr/ndr_initshutdown.c429
-rw-r--r--source3/librpc/gen_ndr/ndr_initshutdown.h28
-rw-r--r--source3/librpc/gen_ndr/ndr_krb5pac.c892
-rw-r--r--source3/librpc/gen_ndr/ndr_krb5pac.h55
-rw-r--r--source3/librpc/gen_ndr/ndr_libnet_join.c120
-rw-r--r--source3/librpc/gen_ndr/ndr_libnet_join.h16
-rw-r--r--source3/librpc/gen_ndr/ndr_libnetapi.c3977
-rw-r--r--source3/librpc/gen_ndr/ndr_libnetapi.h393
-rw-r--r--source3/librpc/gen_ndr/ndr_lsa.c12547
-rw-r--r--source3/librpc/gen_ndr/ndr_lsa.h383
-rw-r--r--source3/librpc/gen_ndr/ndr_messaging.c270
-rw-r--r--source3/librpc/gen_ndr/ndr_messaging.h22
-rw-r--r--source3/librpc/gen_ndr/ndr_misc.c185
-rw-r--r--source3/librpc/gen_ndr/ndr_misc.h29
-rw-r--r--source3/librpc/gen_ndr/ndr_nbt.c4807
-rw-r--r--source3/librpc/gen_ndr/ndr_nbt.h97
-rw-r--r--source3/librpc/gen_ndr/ndr_netlogon.c15131
-rw-r--r--source3/librpc/gen_ndr/ndr_netlogon.h261
-rw-r--r--source3/librpc/gen_ndr/ndr_notify.c240
-rw-r--r--source3/librpc/gen_ndr/ndr_notify.h20
-rw-r--r--source3/librpc/gen_ndr/ndr_ntsvcs.c3769
-rw-r--r--source3/librpc/gen_ndr/ndr_ntsvcs.h211
-rw-r--r--source3/librpc/gen_ndr/ndr_samr.c12702
-rw-r--r--source3/librpc/gen_ndr/ndr_samr.h342
-rw-r--r--source3/librpc/gen_ndr/ndr_security.c1026
-rw-r--r--source3/librpc/gen_ndr/ndr_security.h41
-rw-r--r--source3/librpc/gen_ndr/ndr_srvsvc.c19654
-rw-r--r--source3/librpc/gen_ndr/ndr_srvsvc.h315
-rw-r--r--source3/librpc/gen_ndr/ndr_svcctl.c6079
-rw-r--r--source3/librpc/gen_ndr/ndr_svcctl.h155
-rw-r--r--source3/librpc/gen_ndr/ndr_winreg.c4542
-rw-r--r--source3/librpc/gen_ndr/ndr_winreg.h132
-rw-r--r--source3/librpc/gen_ndr/ndr_wkssvc.c10679
-rw-r--r--source3/librpc/gen_ndr/ndr_wkssvc.h175
-rw-r--r--source3/librpc/gen_ndr/ndr_xattr.c327
-rw-r--r--source3/librpc/gen_ndr/ndr_xattr.h23
-rw-r--r--source3/librpc/gen_ndr/netlogon.h1610
-rw-r--r--source3/librpc/gen_ndr/notify.h35
-rw-r--r--source3/librpc/gen_ndr/ntsvcs.h582
-rw-r--r--source3/librpc/gen_ndr/samr.h1759
-rw-r--r--source3/librpc/gen_ndr/security.h327
-rw-r--r--source3/librpc/gen_ndr/srv_dfs.c1754
-rw-r--r--source3/librpc/gen_ndr/srv_dfs.h29
-rw-r--r--source3/librpc/gen_ndr/srv_dssetup.c845
-rw-r--r--source3/librpc/gen_ndr/srv_dssetup.h17
-rw-r--r--source3/librpc/gen_ndr/srv_echo.c805
-rw-r--r--source3/librpc/gen_ndr/srv_echo.h16
-rw-r--r--source3/librpc/gen_ndr/srv_epmapper.c646
-rw-r--r--source3/librpc/gen_ndr/srv_epmapper.h14
-rw-r--r--source3/librpc/gen_ndr/srv_eventlog.c1842
-rw-r--r--source3/librpc/gen_ndr/srv_eventlog.h30
-rw-r--r--source3/librpc/gen_ndr/srv_initshutdown.c246
-rw-r--r--source3/librpc/gen_ndr/srv_initshutdown.h9
-rw-r--r--source3/librpc/gen_ndr/srv_lsa.c6375
-rw-r--r--source3/librpc/gen_ndr/srv_lsa.h88
-rw-r--r--source3/librpc/gen_ndr/srv_netlogon.c3866
-rw-r--r--source3/librpc/gen_ndr/srv_netlogon.h53
-rw-r--r--source3/librpc/gen_ndr/srv_ntsvcs.c4869
-rw-r--r--source3/librpc/gen_ndr/srv_ntsvcs.h71
-rw-r--r--source3/librpc/gen_ndr/srv_samr.c5482
-rw-r--r--source3/librpc/gen_ndr/srv_samr.h74
-rw-r--r--source3/librpc/gen_ndr/srv_srvsvc.c4199
-rw-r--r--source3/librpc/gen_ndr/srv_srvsvc.h60
-rw-r--r--source3/librpc/gen_ndr/srv_svcctl.c3621
-rw-r--r--source3/librpc/gen_ndr/srv_svcctl.h50
-rw-r--r--source3/librpc/gen_ndr/srv_winreg.c2772
-rw-r--r--source3/librpc/gen_ndr/srv_winreg.h41
-rw-r--r--source3/librpc/gen_ndr/srv_wkssvc.c2412
-rw-r--r--source3/librpc/gen_ndr/srv_wkssvc.h37
-rw-r--r--source3/librpc/gen_ndr/srvsvc.h1793
-rw-r--r--source3/librpc/gen_ndr/svcctl.h781
-rw-r--r--source3/librpc/gen_ndr/winreg.h624
-rw-r--r--source3/librpc/gen_ndr/wkssvc.h981
-rw-r--r--source3/librpc/gen_ndr/xattr.h34
-rw-r--r--source3/librpc/idl/dfs.idl417
-rw-r--r--source3/librpc/idl/drsblobs.idl436
-rw-r--r--source3/librpc/idl/drsuapi.idl1601
-rw-r--r--source3/librpc/idl/dssetup.idl101
-rw-r--r--source3/librpc/idl/echo.idl127
-rw-r--r--source3/librpc/idl/epmapper.idl302
-rw-r--r--source3/librpc/idl/eventlog.idl181
-rw-r--r--source3/librpc/idl/idl_types.h86
-rw-r--r--source3/librpc/idl/initshutdown.idl46
-rw-r--r--source3/librpc/idl/krb5pac.idl120
-rw-r--r--source3/librpc/idl/libnet_join.idl70
-rw-r--r--source3/librpc/idl/libnetapi.idl1237
-rw-r--r--source3/librpc/idl/lsa.idl1103
-rw-r--r--source3/librpc/idl/messaging.idl123
-rw-r--r--source3/librpc/idl/misc.idl51
-rw-r--r--source3/librpc/idl/nbt.idl781
-rw-r--r--source3/librpc/idl/netlogon.idl1408
-rw-r--r--source3/librpc/idl/notify.idl56
-rw-r--r--source3/librpc/idl/ntsvcs.idl375
-rw-r--r--source3/librpc/idl/samr.idl1430
-rw-r--r--source3/librpc/idl/security.idl376
-rw-r--r--source3/librpc/idl/spoolss.idl1571
-rw-r--r--source3/librpc/idl/srvsvc.idl1525
-rw-r--r--source3/librpc/idl/svcctl.idl528
-rw-r--r--source3/librpc/idl/winreg.idl395
-rw-r--r--source3/librpc/idl/wkssvc.idl795
-rw-r--r--source3/librpc/idl/xattr.idl54
-rw-r--r--source3/librpc/ndr/libndr.h354
-rw-r--r--source3/librpc/ndr/ndr.c1101
-rw-r--r--source3/librpc/ndr/ndr_basic.c859
-rw-r--r--source3/librpc/ndr/ndr_compression.c293
-rw-r--r--source3/librpc/ndr/ndr_compression.h51
-rw-r--r--source3/librpc/ndr/ndr_drsuapi.c177
-rw-r--r--source3/librpc/ndr/ndr_drsuapi.h35
-rw-r--r--source3/librpc/ndr/ndr_krb5pac.c141
-rw-r--r--source3/librpc/ndr/ndr_misc.c94
-rw-r--r--source3/librpc/ndr/ndr_sec.h35
-rw-r--r--source3/librpc/ndr/ndr_sec_helper.c117
-rw-r--r--source3/librpc/ndr/ndr_string.c738
-rw-r--r--source3/librpc/ndr/sid.c230
-rw-r--r--source3/librpc/ndr/uuid.c227
-rw-r--r--source3/librpc/rpc/binding.c709
-rw-r--r--source3/librpc/rpc/dcerpc.c180
-rw-r--r--source3/librpc/rpc/dcerpc.h75
-rw-r--r--source3/librpc/rpc/dcerpc_util.c1438
-rwxr-xr-xsource3/librpc/tables.pl89
-rw-r--r--source3/librpc/tools/ndrdump.c453
-rw-r--r--source3/libsmb/asn1.c603
-rw-r--r--source3/libsmb/async_smb.c999
-rw-r--r--source3/libsmb/cliconnect.c2011
-rw-r--r--source3/libsmb/clidfs.c1125
-rw-r--r--source3/libsmb/clidgram.c357
-rw-r--r--source3/libsmb/clientgen.c789
-rw-r--r--source3/libsmb/clierror.c497
-rw-r--r--source3/libsmb/clifile.c2281
-rw-r--r--source3/libsmb/clifsinfo.c664
-rw-r--r--source3/libsmb/clikrb5.c1923
-rw-r--r--source3/libsmb/clilist.c683
-rw-r--r--source3/libsmb/climessage.c162
-rw-r--r--source3/libsmb/clioplock.c66
-rw-r--r--source3/libsmb/cliprint.c260
-rw-r--r--source3/libsmb/cliquota.c642
-rw-r--r--source3/libsmb/clirap.c1264
-rw-r--r--source3/libsmb/clirap2.c2675
-rw-r--r--source3/libsmb/clireadwrite.c717
-rw-r--r--source3/libsmb/clisecdesc.c130
-rw-r--r--source3/libsmb/clispnego.c600
-rw-r--r--source3/libsmb/clistr.c94
-rw-r--r--source3/libsmb/clitrans.c1409
-rw-r--r--source3/libsmb/conncache.c256
-rw-r--r--source3/libsmb/credentials.c361
-rw-r--r--source3/libsmb/dcerpc_err.c55
-rw-r--r--source3/libsmb/doserr.c202
-rw-r--r--source3/libsmb/dsgetdcname.c1449
-rw-r--r--source3/libsmb/errormap.c1609
-rw-r--r--source3/libsmb/libsmb_cache.c244
-rw-r--r--source3/libsmb/libsmb_compat.c542
-rw-r--r--source3/libsmb/libsmb_context.c645
-rw-r--r--source3/libsmb/libsmb_dir.c1949
-rw-r--r--source3/libsmb/libsmb_file.c864
-rw-r--r--source3/libsmb/libsmb_misc.c73
-rw-r--r--source3/libsmb/libsmb_path.c400
-rw-r--r--source3/libsmb/libsmb_printjob.c336
-rw-r--r--source3/libsmb/libsmb_server.c699
-rw-r--r--source3/libsmb/libsmb_setget.c905
-rw-r--r--source3/libsmb/libsmb_stat.c302
-rw-r--r--source3/libsmb/libsmb_xattr.c2323
-rw-r--r--source3/libsmb/namecache.c394
-rw-r--r--source3/libsmb/namequery.c2145
-rw-r--r--source3/libsmb/namequery_dc.c247
-rw-r--r--source3/libsmb/nmblib.c1400
-rw-r--r--source3/libsmb/nterr.c759
-rw-r--r--source3/libsmb/ntlm_check.c463
-rw-r--r--source3/libsmb/ntlmssp.c1251
-rw-r--r--source3/libsmb/ntlmssp_parse.c384
-rw-r--r--source3/libsmb/ntlmssp_sign.c468
-rw-r--r--source3/libsmb/passchange.c257
-rw-r--r--source3/libsmb/pwd_cache.c61
-rw-r--r--source3/libsmb/samlogon_cache.c258
-rw-r--r--source3/libsmb/smb_seal.c497
-rw-r--r--source3/libsmb/smb_share_modes.c520
-rw-r--r--source3/libsmb/smb_signing.c1004
-rw-r--r--source3/libsmb/smbdes.c420
-rw-r--r--source3/libsmb/smbencrypt.c898
-rw-r--r--source3/libsmb/smberr.c266
-rw-r--r--source3/libsmb/spnego.c346
-rw-r--r--source3/libsmb/trustdom_cache.c338
-rw-r--r--source3/libsmb/trusts_util.c283
-rw-r--r--source3/libsmb/unexpected.c202
-rw-r--r--source3/locking/brlock.c1807
-rw-r--r--source3/locking/locking.c1511
-rw-r--r--source3/locking/posix.c1309
-rw-r--r--source3/m4/aclocal.m4889
-rw-r--r--source3/m4/check_path.m4327
-rw-r--r--source3/m4/samba_version.m429
-rw-r--r--source3/m4/swat.m427
-rw-r--r--source3/mainpage.dox7
-rw-r--r--source3/modules/CP437.c135
-rw-r--r--source3/modules/CP850.c121
-rw-r--r--source3/modules/README-gpfs-acl.txt82
-rw-r--r--source3/modules/README.nfs4acls.txt82
-rw-r--r--source3/modules/charset_macosxfs.c601
-rw-r--r--source3/modules/developer.c131
-rw-r--r--source3/modules/getdate.c2458
-rw-r--r--source3/modules/getdate.h45
-rw-r--r--source3/modules/getdate.y1115
-rw-r--r--source3/modules/gpfs.c236
-rw-r--r--source3/modules/nfs4_acls.c792
-rw-r--r--source3/modules/nfs4_acls.h150
-rw-r--r--source3/modules/vfs_afsacl.c1081
-rw-r--r--source3/modules/vfs_aio_fork.c729
-rw-r--r--source3/modules/vfs_aixacl.c214
-rw-r--r--source3/modules/vfs_aixacl2.c534
-rw-r--r--source3/modules/vfs_aixacl_util.c296
-rw-r--r--source3/modules/vfs_audit.c307
-rw-r--r--source3/modules/vfs_cacheprime.c196
-rw-r--r--source3/modules/vfs_cap.c624
-rw-r--r--source3/modules/vfs_catia.c374
-rw-r--r--source3/modules/vfs_commit.c318
-rw-r--r--source3/modules/vfs_default.c1564
-rw-r--r--source3/modules/vfs_default_quota.c230
-rw-r--r--source3/modules/vfs_expand_msdfs.c215
-rw-r--r--source3/modules/vfs_extd_audit.c370
-rw-r--r--source3/modules/vfs_fake_perms.c77
-rw-r--r--source3/modules/vfs_fileid.c288
-rw-r--r--source3/modules/vfs_full_audit.c2209
-rw-r--r--source3/modules/vfs_gpfs.c877
-rw-r--r--source3/modules/vfs_gpfs.h32
-rw-r--r--source3/modules/vfs_hpuxacl.c1184
-rw-r--r--source3/modules/vfs_hpuxacl.h58
-rw-r--r--source3/modules/vfs_irixacl.c103
-rw-r--r--source3/modules/vfs_irixacl.h45
-rw-r--r--source3/modules/vfs_netatalk.c433
-rw-r--r--source3/modules/vfs_notify_fam.c304
-rw-r--r--source3/modules/vfs_posixacl.c396
-rw-r--r--source3/modules/vfs_posixacl.h46
-rw-r--r--source3/modules/vfs_prealloc.c220
-rw-r--r--source3/modules/vfs_readahead.c180
-rw-r--r--source3/modules/vfs_readonly.c97
-rw-r--r--source3/modules/vfs_recycle.c604
-rw-r--r--source3/modules/vfs_shadow_copy.c249
-rw-r--r--source3/modules/vfs_shadow_copy2.c629
-rw-r--r--source3/modules/vfs_solarisacl.c787
-rw-r--r--source3/modules/vfs_solarisacl.h45
-rw-r--r--source3/modules/vfs_streams_depot.c641
-rw-r--r--source3/modules/vfs_streams_xattr.c685
-rw-r--r--source3/modules/vfs_syncops.c210
-rw-r--r--source3/modules/vfs_tru64acl.c503
-rw-r--r--source3/modules/vfs_tru64acl.h45
-rw-r--r--source3/modules/vfs_tsmsm.c396
-rw-r--r--source3/modules/vfs_xattr_tdb.c759
-rw-r--r--source3/modules/vfs_zfsacl.c232
-rw-r--r--source3/modules/weird.c131
-rw-r--r--source3/nmbd/asyncdns.c365
-rw-r--r--source3/nmbd/nmbd.c993
-rw-r--r--source3/nmbd/nmbd_become_dmb.c395
-rw-r--r--source3/nmbd/nmbd_become_lmb.c593
-rw-r--r--source3/nmbd/nmbd_browserdb.c175
-rw-r--r--source3/nmbd/nmbd_browsesync.c676
-rw-r--r--source3/nmbd/nmbd_elections.c400
-rw-r--r--source3/nmbd/nmbd_incomingdgrams.c847
-rw-r--r--source3/nmbd/nmbd_incomingrequests.c586
-rw-r--r--source3/nmbd/nmbd_lmhosts.c103
-rw-r--r--source3/nmbd/nmbd_logonnames.c170
-rw-r--r--source3/nmbd/nmbd_mynames.c252
-rw-r--r--source3/nmbd/nmbd_namelistdb.c660
-rw-r--r--source3/nmbd/nmbd_namequery.c275
-rw-r--r--source3/nmbd/nmbd_nameregister.c538
-rw-r--r--source3/nmbd/nmbd_namerelease.c221
-rw-r--r--source3/nmbd/nmbd_nodestatus.c91
-rw-r--r--source3/nmbd/nmbd_packets.c1977
-rw-r--r--source3/nmbd/nmbd_processlogon.c695
-rw-r--r--source3/nmbd/nmbd_responserecordsdb.c243
-rw-r--r--source3/nmbd/nmbd_sendannounce.c586
-rw-r--r--source3/nmbd/nmbd_serverlistdb.c431
-rw-r--r--source3/nmbd/nmbd_subnetdb.c389
-rw-r--r--source3/nmbd/nmbd_synclists.c325
-rw-r--r--source3/nmbd/nmbd_winsproxy.c232
-rw-r--r--source3/nmbd/nmbd_winsserver.c2568
-rw-r--r--source3/nmbd/nmbd_workgroupdb.c329
-rw-r--r--source3/nsswitch/libwbclient/Doxyfile1297
-rw-r--r--source3/nsswitch/libwbclient/libwbclient.h46
-rw-r--r--source3/nsswitch/libwbclient/wbc_err_internal.h45
-rw-r--r--source3/nsswitch/libwbclient/wbc_idmap.c423
-rw-r--r--source3/nsswitch/libwbclient/wbc_pam.c796
-rw-r--r--source3/nsswitch/libwbclient/wbc_pwd.c438
-rw-r--r--source3/nsswitch/libwbclient/wbc_sid.c677
-rw-r--r--source3/nsswitch/libwbclient/wbc_util.c552
-rw-r--r--source3/nsswitch/libwbclient/wbclient.c165
-rw-r--r--source3/nsswitch/libwbclient/wbclient.h571
-rw-r--r--source3/nsswitch/libwbclient/wbclient_internal.h32
-rw-r--r--source3/nsswitch/pam_winbind.c2817
-rw-r--r--source3/nsswitch/pam_winbind.h211
-rw-r--r--source3/nsswitch/wb_common.c690
-rw-r--r--source3/nsswitch/wbinfo.c1763
-rw-r--r--source3/nsswitch/winbind_client.h30
-rw-r--r--source3/nsswitch/winbind_krb5_locator.c397
-rw-r--r--source3/nsswitch/winbind_nss.h76
-rw-r--r--source3/nsswitch/winbind_nss_aix.c1077
-rw-r--r--source3/nsswitch/winbind_nss_config.h69
-rw-r--r--source3/nsswitch/winbind_nss_freebsd.c79
-rw-r--r--source3/nsswitch/winbind_nss_hpux.h137
-rw-r--r--source3/nsswitch/winbind_nss_irix.c634
-rw-r--r--source3/nsswitch/winbind_nss_irix.h42
-rw-r--r--source3/nsswitch/winbind_nss_linux.c1477
-rw-r--r--source3/nsswitch/winbind_nss_linux.h29
-rw-r--r--source3/nsswitch/winbind_nss_netbsd.c442
-rw-r--r--source3/nsswitch/winbind_nss_netbsd.h40
-rw-r--r--source3/nsswitch/winbind_nss_solaris.c654
-rw-r--r--source3/nsswitch/winbind_nss_solaris.h85
-rw-r--r--source3/nsswitch/winbind_struct_protocol.h493
-rw-r--r--source3/nsswitch/wins.c414
-rw-r--r--source3/pam_smbpass/CHANGELOG31
-rw-r--r--source3/pam_smbpass/INSTALL64
-rw-r--r--source3/pam_smbpass/README60
-rw-r--r--source3/pam_smbpass/TODO7
-rw-r--r--source3/pam_smbpass/general.h134
-rw-r--r--source3/pam_smbpass/pam_smb_acct.c144
-rw-r--r--source3/pam_smbpass/pam_smb_auth.c256
-rw-r--r--source3/pam_smbpass/pam_smb_passwd.c358
-rw-r--r--source3/pam_smbpass/samples/README3
-rw-r--r--source3/pam_smbpass/samples/kdc-pdc15
-rw-r--r--source3/pam_smbpass/samples/password-mature14
-rw-r--r--source3/pam_smbpass/samples/password-migration18
-rw-r--r--source3/pam_smbpass/samples/password-sync15
-rw-r--r--source3/pam_smbpass/support.c632
-rw-r--r--source3/pam_smbpass/support.h50
-rw-r--r--source3/param/loadparm.c9498
-rw-r--r--source3/param/params.c590
-rw-r--r--source3/param/util.c50
-rw-r--r--source3/passdb/login_cache.c188
-rw-r--r--source3/passdb/lookup_sid.c1501
-rw-r--r--source3/passdb/machine_sid.c248
-rw-r--r--source3/passdb/passdb.c1657
-rw-r--r--source3/passdb/pdb_compat.c103
-rw-r--r--source3/passdb/pdb_get_set.c1081
-rw-r--r--source3/passdb/pdb_interface.c2071
-rw-r--r--source3/passdb/pdb_ldap.c6389
-rw-r--r--source3/passdb/pdb_nds.c913
-rw-r--r--source3/passdb/pdb_smbpasswd.c1718
-rw-r--r--source3/passdb/pdb_tdb.c1639
-rw-r--r--source3/passdb/secrets.c1366
-rw-r--r--source3/passdb/util_builtin.c109
-rw-r--r--source3/passdb/util_unixsids.c105
-rw-r--r--source3/passdb/util_wellknown.c172
-rw-r--r--source3/pkgconfig/netapi.pc.in14
-rw-r--r--source3/pkgconfig/smbclient.pc.in14
-rw-r--r--source3/pkgconfig/smbsharemodes.pc.in14
-rw-r--r--source3/pkgconfig/wbclient.pc.in13
-rw-r--r--source3/po/de.msg592
-rw-r--r--source3/po/en.msg592
-rw-r--r--source3/po/fi.msg610
-rw-r--r--source3/po/fr.msg592
-rwxr-xr-xsource3/po/genmsg39
-rw-r--r--source3/po/it.msg592
-rw-r--r--source3/po/ja.msg594
-rw-r--r--source3/po/nl.msg592
-rw-r--r--source3/po/pl.msg592
-rw-r--r--source3/po/tr.msg593
-rw-r--r--source3/popt/CHANGES46
-rw-r--r--source3/popt/COPYING22
-rw-r--r--source3/popt/README18
-rw-r--r--source3/popt/dummy.in0
-rw-r--r--source3/popt/findme.c50
-rw-r--r--source3/popt/findme.h20
-rw-r--r--source3/popt/popt.c1249
-rw-r--r--source3/popt/popt.h545
-rw-r--r--source3/popt/poptconfig.c190
-rw-r--r--source3/popt/popthelp.c740
-rw-r--r--source3/popt/poptint.h116
-rw-r--r--source3/popt/poptparse.c227
-rw-r--r--source3/popt/system.h76
-rw-r--r--source3/printing/load.c64
-rw-r--r--source3/printing/lpq_parse.c1152
-rw-r--r--source3/printing/notify.c571
-rw-r--r--source3/printing/nt_printing.c5892
-rw-r--r--source3/printing/pcap.c263
-rw-r--r--source3/printing/print_aix.c123
-rw-r--r--source3/printing/print_cups.c1347
-rw-r--r--source3/printing/print_generic.c301
-rw-r--r--source3/printing/print_iprint.c1240
-rw-r--r--source3/printing/print_svid.c127
-rw-r--r--source3/printing/printfsp.c122
-rw-r--r--source3/printing/printing.c2888
-rw-r--r--source3/printing/printing_db.c215
-rw-r--r--source3/profile/profile.c458
-rw-r--r--source3/registry/reg_api.c1247
-rw-r--r--source3/registry/reg_backend_current_version.c81
-rw-r--r--source3/registry/reg_backend_db.c1271
-rw-r--r--source3/registry/reg_backend_hkpt_params.c70
-rw-r--r--source3/registry/reg_backend_netlogon_params.c57
-rw-r--r--source3/registry/reg_backend_perflib.c106
-rw-r--r--source3/registry/reg_backend_printing.c1268
-rw-r--r--source3/registry/reg_backend_prod_options.c70
-rw-r--r--source3/registry/reg_backend_shares.c164
-rw-r--r--source3/registry/reg_backend_smbconf.c85
-rw-r--r--source3/registry/reg_backend_tcpip_params.c67
-rw-r--r--source3/registry/reg_cachehook.c147
-rw-r--r--source3/registry/reg_dispatcher.c245
-rw-r--r--source3/registry/reg_eventlog.c380
-rw-r--r--source3/registry/reg_init_basic.c55
-rw-r--r--source3/registry/reg_init_full.c105
-rw-r--r--source3/registry/reg_init_smbconf.c104
-rw-r--r--source3/registry/reg_objects.c431
-rw-r--r--source3/registry/reg_perfcount.c1372
-rw-r--r--source3/registry/reg_util.c267
-rw-r--r--source3/registry/reg_util_legacy.c47
-rw-r--r--source3/registry/regfio.c1915
-rw-r--r--source3/rpc_client/cli_lsarpc.c469
-rw-r--r--source3/rpc_client/cli_netlogon.c540
-rw-r--r--source3/rpc_client/cli_pipe.c3451
-rw-r--r--source3/rpc_client/cli_reg.c79
-rw-r--r--source3/rpc_client/cli_samr.c324
-rw-r--r--source3/rpc_client/cli_spoolss.c2052
-rw-r--r--source3/rpc_client/cli_spoolss_notify.c218
-rw-r--r--source3/rpc_client/cli_svcctl.c168
-rw-r--r--source3/rpc_client/init_lsa.c128
-rw-r--r--source3/rpc_client/init_netlogon.c393
-rw-r--r--source3/rpc_client/init_samr.c508
-rw-r--r--source3/rpc_client/init_srvsvc.c402
-rw-r--r--source3/rpc_client/ndr.c95
-rw-r--r--source3/rpc_parse/parse_buffer.c508
-rw-r--r--source3/rpc_parse/parse_eventlog.c193
-rw-r--r--source3/rpc_parse/parse_misc.c1834
-rw-r--r--source3/rpc_parse/parse_ntsvcs.c147
-rw-r--r--source3/rpc_parse/parse_prs.c1868
-rw-r--r--source3/rpc_parse/parse_rpc.c651
-rw-r--r--source3/rpc_parse/parse_sec.c436
-rw-r--r--source3/rpc_parse/parse_spoolss.c7726
-rw-r--r--source3/rpc_parse/parse_svcctl.c535
-rw-r--r--source3/rpc_server/srv_dfs_nt.c530
-rw-r--r--source3/rpc_server/srv_dssetup_nt.c223
-rw-r--r--source3/rpc_server/srv_echo_nt.c125
-rw-r--r--source3/rpc_server/srv_eventlog.c118
-rw-r--r--source3/rpc_server/srv_eventlog_lib.c742
-rw-r--r--source3/rpc_server/srv_eventlog_nt.c968
-rw-r--r--source3/rpc_server/srv_initshutdown_nt.c77
-rw-r--r--source3/rpc_server/srv_lsa_hnd.c271
-rw-r--r--source3/rpc_server/srv_lsa_nt.c2426
-rw-r--r--source3/rpc_server/srv_netlog_nt.c1414
-rw-r--r--source3/rpc_server/srv_ntsvcs.c163
-rw-r--r--source3/rpc_server/srv_ntsvcs_nt.c778
-rw-r--r--source3/rpc_server/srv_pipe.c2419
-rw-r--r--source3/rpc_server/srv_pipe_hnd.c1249
-rw-r--r--source3/rpc_server/srv_samr_nt.c5956
-rw-r--r--source3/rpc_server/srv_samr_util.c382
-rw-r--r--source3/rpc_server/srv_spoolss.c1639
-rw-r--r--source3/rpc_server/srv_spoolss_nt.c9946
-rw-r--r--source3/rpc_server/srv_srvsvc_nt.c2624
-rw-r--r--source3/rpc_server/srv_svcctl.c273
-rw-r--r--source3/rpc_server/srv_svcctl_nt.c1109
-rw-r--r--source3/rpc_server/srv_util.c82
-rw-r--r--source3/rpc_server/srv_winreg_nt.c965
-rw-r--r--source3/rpc_server/srv_wkssvc_nt.c494
-rw-r--r--source3/rpcclient/cmd_dfs.c329
-rw-r--r--source3/rpcclient/cmd_drsuapi.c566
-rw-r--r--source3/rpcclient/cmd_dssetup.c69
-rw-r--r--source3/rpcclient/cmd_echo.c184
-rw-r--r--source3/rpcclient/cmd_lsarpc.c1395
-rw-r--r--source3/rpcclient/cmd_netlogon.c1034
-rw-r--r--source3/rpcclient/cmd_ntsvcs.c229
-rw-r--r--source3/rpcclient/cmd_samr.c2763
-rw-r--r--source3/rpcclient/cmd_shutdown.c117
-rw-r--r--source3/rpcclient/cmd_spoolss.c2782
-rw-r--r--source3/rpcclient/cmd_srvsvc.c891
-rw-r--r--source3/rpcclient/cmd_test.c75
-rw-r--r--source3/rpcclient/cmd_wkssvc.c170
-rw-r--r--source3/rpcclient/rpcclient.c959
-rw-r--r--source3/rpcclient/rpcclient.h42
-rwxr-xr-xsource3/script/build_env.sh41
-rwxr-xr-xsource3/script/build_idl.sh47
-rwxr-xr-xsource3/script/count_80_col.pl16
-rwxr-xr-xsource3/script/creategroup27
-rwxr-xr-xsource3/script/extract_allparms.sh2
-rwxr-xr-xsource3/script/findsmb.in161
-rwxr-xr-xsource3/script/findstatic.pl70
-rwxr-xr-xsource3/script/fix_bool.pl19
-rwxr-xr-xsource3/script/format_indent.sh12
-rw-r--r--source3/script/gap.awk39
-rw-r--r--source3/script/gaptab.awk48
-rw-r--r--source3/script/gen-8bit-gap.awk18
-rwxr-xr-xsource3/script/gen-8bit-gap.sh.in48
-rwxr-xr-xsource3/script/installbin.sh.in34
-rwxr-xr-xsource3/script/installdat.sh65
-rwxr-xr-xsource3/script/installdirs.sh18
-rwxr-xr-xsource3/script/installman.sh86
-rwxr-xr-xsource3/script/installmodules.sh37
-rw-r--r--source3/script/installmsg.sh65
-rwxr-xr-xsource3/script/installscripts.sh47
-rwxr-xr-xsource3/script/installswat.sh296
-rwxr-xr-xsource3/script/linkmodules.sh12
-rw-r--r--source3/script/makeunicodecasemap.awk59
-rw-r--r--source3/script/mkbuildoptions.awk270
-rwxr-xr-xsource3/script/mkinstalldirs38
-rwxr-xr-xsource3/script/mknissmbpasswd.sh31
-rwxr-xr-xsource3/script/mknissmbpwdtbl.sh42
-rwxr-xr-xsource3/script/mksmbpasswd.sh6
-rw-r--r--source3/script/mksyms.awk76
-rwxr-xr-xsource3/script/mksyms.sh45
-rwxr-xr-xsource3/script/mkversion.sh145
-rwxr-xr-xsource3/script/revert.sh18
-rwxr-xr-xsource3/script/scancvslog.pl112
-rw-r--r--source3/script/smbtar165
-rwxr-xr-xsource3/script/strip_trail_ws.pl18
-rwxr-xr-xsource3/script/tests/dlopen.sh90
-rwxr-xr-xsource3/script/tests/gdb_backtrace87
-rwxr-xr-xsource3/script/tests/selftest.sh324
-rw-r--r--source3/script/tests/test_functions.sh333
-rwxr-xr-xsource3/script/tests/test_groupmap.sh214
-rwxr-xr-xsource3/script/tests/test_local_s3.sh29
-rwxr-xr-xsource3/script/tests/test_net_misc.sh50
-rwxr-xr-xsource3/script/tests/test_net_registry.sh442
-rwxr-xr-xsource3/script/tests/test_net_s3.sh33
-rwxr-xr-xsource3/script/tests/test_ntlm_auth_s3.sh21
-rwxr-xr-xsource3/script/tests/test_posix_s3.sh84
-rwxr-xr-xsource3/script/tests/test_smbclient_s3.sh87
-rwxr-xr-xsource3/script/tests/test_smbtorture_s3.sh48
-rwxr-xr-xsource3/script/tests/test_testparm_s3.sh90
-rwxr-xr-xsource3/script/tests/test_wbinfo_s3.sh50
-rwxr-xr-xsource3/script/tests/tests_all.sh94
-rw-r--r--source3/script/tests/tests_smbclient_s3.sh1
-rw-r--r--source3/script/tests/timelimit.c102
-rwxr-xr-xsource3/script/uninstallbin.sh.in41
l---------source3/script/uninstalldat.sh1
-rwxr-xr-xsource3/script/uninstallman.sh37
-rwxr-xr-xsource3/script/uninstallmodules.sh39
l---------source3/script/uninstallmsg.sh1
-rwxr-xr-xsource3/script/uninstallscripts.sh36
l---------source3/script/uninstallswat.sh1
-rwxr-xr-xsource3/script/updatesmbpasswd.sh14
-rw-r--r--source3/services/services_db.c746
-rw-r--r--source3/services/svc_netlogon.c74
-rw-r--r--source3/services/svc_rcinit.c124
-rw-r--r--source3/services/svc_spoolss.c80
-rw-r--r--source3/services/svc_winreg.c63
-rw-r--r--source3/services/svc_wins.c71
-rw-r--r--source3/smbadduser.in79
-rw-r--r--source3/smbd/aio.c832
-rw-r--r--source3/smbd/blocking.c931
-rw-r--r--source3/smbd/change_trust_pw.c101
-rw-r--r--source3/smbd/chgpasswd.c1208
-rw-r--r--source3/smbd/close.c772
-rw-r--r--source3/smbd/conn.c329
-rw-r--r--source3/smbd/connection.c332
-rw-r--r--source3/smbd/dfree.c223
-rw-r--r--source3/smbd/dir.c1316
-rw-r--r--source3/smbd/dmapi.c340
-rw-r--r--source3/smbd/dnsregister.c212
-rw-r--r--source3/smbd/dosmode.c666
-rw-r--r--source3/smbd/error.c169
-rw-r--r--source3/smbd/fake_file.c161
-rw-r--r--source3/smbd/file_access.c222
-rw-r--r--source3/smbd/fileio.c955
-rw-r--r--source3/smbd/filename.c956
-rw-r--r--source3/smbd/files.c547
-rw-r--r--source3/smbd/ipc.c813
-rw-r--r--source3/smbd/lanman.c4642
-rw-r--r--source3/smbd/mangle.c152
-rw-r--r--source3/smbd/mangle_hash.c695
-rw-r--r--source3/smbd/mangle_hash2.c761
-rw-r--r--source3/smbd/map_username.c215
-rw-r--r--source3/smbd/message.c309
-rw-r--r--source3/smbd/msdfs.c1724
-rw-r--r--source3/smbd/negprot.c691
-rw-r--r--source3/smbd/noquotas.c37
-rw-r--r--source3/smbd/notify.c524
-rw-r--r--source3/smbd/notify_inotify.c434
-rw-r--r--source3/smbd/notify_internal.c690
-rw-r--r--source3/smbd/ntquotas.c247
-rw-r--r--source3/smbd/nttrans.c2864
-rw-r--r--source3/smbd/open.c3093
-rw-r--r--source3/smbd/oplock.c897
-rw-r--r--source3/smbd/oplock_irix.c301
-rw-r--r--source3/smbd/oplock_linux.c249
-rw-r--r--source3/smbd/password.c829
-rw-r--r--source3/smbd/pipes.c320
-rw-r--r--source3/smbd/posix_acls.c4322
-rw-r--r--source3/smbd/process.c2113
-rw-r--r--source3/smbd/quotas.c1539
-rw-r--r--source3/smbd/reply.c7184
-rw-r--r--source3/smbd/seal.c742
-rw-r--r--source3/smbd/sec_ctx.c476
-rw-r--r--source3/smbd/server.c1471
-rw-r--r--source3/smbd/service.c1353
-rw-r--r--source3/smbd/session.c329
-rw-r--r--source3/smbd/sesssetup.c1820
-rw-r--r--source3/smbd/share_access.c280
-rw-r--r--source3/smbd/srvstr.c77
-rw-r--r--source3/smbd/statcache.c391
-rw-r--r--source3/smbd/statvfs.c149
-rw-r--r--source3/smbd/trans2.c7846
-rw-r--r--source3/smbd/uid.c449
-rw-r--r--source3/smbd/utmp.c630
-rw-r--r--source3/smbd/vfs.c968
-rw-r--r--source3/stf/README.stf3
-rw-r--r--source3/stf/comfychair.py443
-rwxr-xr-xsource3/stf/example.py36
-rwxr-xr-xsource3/stf/info3cache.py54
-rw-r--r--source3/stf/notes.txt175
-rwxr-xr-xsource3/stf/osver.py55
-rwxr-xr-xsource3/stf/pythoncheck.py46
-rw-r--r--source3/stf/sambalib.py39
-rwxr-xr-xsource3/stf/smbcontrol.py238
-rwxr-xr-xsource3/stf/spoolss.py288
-rw-r--r--source3/stf/standardcheck.py32
-rwxr-xr-xsource3/stf/stf.py101
-rwxr-xr-xsource3/stf/strings.py149
-rwxr-xr-xsource3/stf/test.py33
-rw-r--r--source3/stf/unicodenames.py31
-rw-r--r--source3/tests/README10
-rw-r--r--source3/tests/crypttest.c851
-rw-r--r--source3/tests/fcntl_lock.c121
-rw-r--r--source3/tests/fcntl_lock64.c96
-rw-r--r--source3/tests/ftruncate.c27
-rw-r--r--source3/tests/getgroups.c66
-rw-r--r--source3/tests/shlib.c8
-rw-r--r--source3/tests/summary.c31
-rw-r--r--source3/tests/sysquotas.c98
-rw-r--r--source3/tests/trivial.c4
-rw-r--r--source3/torture/cmd_vfs.c1071
-rw-r--r--source3/torture/denytest.c1574
-rw-r--r--source3/torture/locktest.c707
-rw-r--r--source3/torture/locktest2.c565
-rw-r--r--source3/torture/mangle_test.c217
-rw-r--r--source3/torture/masktest.c565
-rw-r--r--source3/torture/msgtest.c145
-rw-r--r--source3/torture/nbio.c315
-rw-r--r--source3/torture/nsstest.c487
-rw-r--r--source3/torture/pdbtest.c373
-rw-r--r--source3/torture/rpc_open_tcp.c109
-rw-r--r--source3/torture/scanner.c430
-rw-r--r--source3/torture/smbiconv.c243
-rw-r--r--source3/torture/t_asn1.c61
-rw-r--r--source3/torture/t_push_ucs2.c55
-rw-r--r--source3/torture/t_strappend.c45
-rw-r--r--source3/torture/t_strcmp.c32
-rw-r--r--source3/torture/t_stringoverflow.c23
-rw-r--r--source3/torture/t_strstr.c38
-rwxr-xr-xsource3/torture/test_ntlm_auth.py218
-rw-r--r--source3/torture/torture.c5770
-rw-r--r--source3/torture/utable.c190
-rw-r--r--source3/torture/vfstest.c611
-rw-r--r--source3/torture/vfstest.h44
-rw-r--r--source3/utils/debug2html.c256
-rw-r--r--source3/utils/debugparse.c308
-rw-r--r--source3/utils/eventlogadm.c229
-rw-r--r--source3/utils/log2pcaphex.c304
-rw-r--r--source3/utils/net.c777
-rw-r--r--source3/utils/net.h152
-rw-r--r--source3/utils/net_ads.c2586
-rw-r--r--source3/utils/net_ads_gpo.c695
-rw-r--r--source3/utils/net_afs.c114
-rw-r--r--source3/utils/net_afs.h29
-rw-r--r--source3/utils/net_cache.c373
-rw-r--r--source3/utils/net_conf.c1179
-rw-r--r--source3/utils/net_dns.c210
-rw-r--r--source3/utils/net_dom.c265
-rw-r--r--source3/utils/net_file.c57
-rw-r--r--source3/utils/net_group.c65
-rw-r--r--source3/utils/net_groupmap.c906
-rw-r--r--source3/utils/net_help.c69
-rw-r--r--source3/utils/net_help_common.c55
-rw-r--r--source3/utils/net_help_common.h49
-rw-r--r--source3/utils/net_idmap.c441
-rw-r--r--source3/utils/net_join.c54
-rw-r--r--source3/utils/net_lookup.c447
-rw-r--r--source3/utils/net_proto.h489
-rw-r--r--source3/utils/net_rap.c1374
-rw-r--r--source3/utils/net_registry.c531
-rw-r--r--source3/utils/net_registry_util.c143
-rw-r--r--source3/utils/net_registry_util.h41
-rw-r--r--source3/utils/net_rpc.c7209
-rw-r--r--source3/utils/net_rpc_audit.c494
-rw-r--r--source3/utils/net_rpc_join.c506
-rw-r--r--source3/utils/net_rpc_printer.c2517
-rw-r--r--source3/utils/net_rpc_registry.c1311
-rw-r--r--source3/utils/net_rpc_rights.c708
-rw-r--r--source3/utils/net_rpc_samsync.c362
-rw-r--r--source3/utils/net_rpc_service.c725
-rw-r--r--source3/utils/net_rpc_sh_acct.c453
-rw-r--r--source3/utils/net_rpc_shell.c298
-rw-r--r--source3/utils/net_sam.c1938
-rw-r--r--source3/utils/net_share.c77
-rw-r--r--source3/utils/net_status.c269
-rw-r--r--source3/utils/net_time.c238
-rw-r--r--source3/utils/net_user.c67
-rw-r--r--source3/utils/net_usershare.c1073
-rw-r--r--source3/utils/net_util.c597
-rw-r--r--source3/utils/netlookup.c227
-rw-r--r--source3/utils/nmblookup.c369
-rw-r--r--source3/utils/ntlm_auth.c2491
-rw-r--r--source3/utils/ntlm_auth.h26
-rw-r--r--source3/utils/ntlm_auth_diagnostics.c607
-rw-r--r--source3/utils/ntlm_auth_proto.h48
-rw-r--r--source3/utils/passwd_proto.h32
-rw-r--r--source3/utils/passwd_util.c68
-rw-r--r--source3/utils/pdbedit.c1101
-rw-r--r--source3/utils/profiles.c303
-rw-r--r--source3/utils/rpccheck.c62
-rw-r--r--source3/utils/sharesec.c619
-rw-r--r--source3/utils/smbcacls.c1032
-rw-r--r--source3/utils/smbcontrol.c1401
-rw-r--r--source3/utils/smbcquotas.c619
-rw-r--r--source3/utils/smbfilter.c287
-rw-r--r--source3/utils/smbget.c644
-rw-r--r--source3/utils/smbpasswd.c603
-rw-r--r--source3/utils/smbtree.c332
-rw-r--r--source3/utils/smbw_sample.c96
-rw-r--r--source3/utils/status.c485
-rw-r--r--source3/utils/status_profile.c541
-rw-r--r--source3/utils/testparm.c434
-rw-r--r--source3/web/cgi.c672
-rw-r--r--source3/web/diagnose.c84
-rw-r--r--source3/web/neg_lang.c120
-rw-r--r--source3/web/startstop.c130
-rw-r--r--source3/web/statuspage.c453
-rw-r--r--source3/web/swat.c1488
-rw-r--r--source3/web/swat_proto.h70
-rw-r--r--source3/winbindd/idmap.c790
-rw-r--r--source3/winbindd/idmap_ad.c852
-rw-r--r--source3/winbindd/idmap_ldap.c1480
-rw-r--r--source3/winbindd/idmap_nss.c217
-rw-r--r--source3/winbindd/idmap_passdb.c130
-rw-r--r--source3/winbindd/idmap_rid.c251
-rw-r--r--source3/winbindd/idmap_tdb.c1179
-rw-r--r--source3/winbindd/idmap_tdb2.c856
-rw-r--r--source3/winbindd/idmap_util.c270
-rw-r--r--source3/winbindd/nss_info.c301
-rw-r--r--source3/winbindd/nss_info_template.c83
-rw-r--r--source3/winbindd/winbindd.c1257
-rw-r--r--source3/winbindd/winbindd.h393
-rw-r--r--source3/winbindd/winbindd_ads.c1354
-rw-r--r--source3/winbindd/winbindd_async.c1125
-rw-r--r--source3/winbindd/winbindd_cache.c4008
-rw-r--r--source3/winbindd/winbindd_ccache_access.c283
-rw-r--r--source3/winbindd/winbindd_cm.c2399
-rw-r--r--source3/winbindd/winbindd_cred_cache.c802
-rw-r--r--source3/winbindd/winbindd_creds.c162
-rw-r--r--source3/winbindd/winbindd_domain.c119
-rw-r--r--source3/winbindd/winbindd_dual.c1358
-rw-r--r--source3/winbindd/winbindd_group.c1728
-rw-r--r--source3/winbindd/winbindd_idmap.c503
-rw-r--r--source3/winbindd/winbindd_locator.c147
-rw-r--r--source3/winbindd/winbindd_misc.c802
-rw-r--r--source3/winbindd/winbindd_ndr.c156
-rw-r--r--source3/winbindd/winbindd_pam.c2431
-rw-r--r--source3/winbindd/winbindd_passdb.c751
-rw-r--r--source3/winbindd/winbindd_proto.h601
-rw-r--r--source3/winbindd/winbindd_reconnect.c316
-rw-r--r--source3/winbindd/winbindd_rpc.c1167
-rw-r--r--source3/winbindd/winbindd_sid.c612
-rw-r--r--source3/winbindd/winbindd_user.c783
-rw-r--r--source3/winbindd/winbindd_util.c1583
-rw-r--r--source3/winbindd/winbindd_wins.c241
1494 files changed, 909442 insertions, 0 deletions
diff --git a/source3/.dmallocrc b/source3/.dmallocrc
new file mode 100644
index 0000000000..5e5c45e124
--- /dev/null
+++ b/source3/.dmallocrc
@@ -0,0 +1,2 @@
+samba allow-free-null, log-stats, log-non-free, log-trans, \
+ check-fence, check-heap, check-lists, error-abort \ No newline at end of file
diff --git a/source3/.indent.pro b/source3/.indent.pro
new file mode 100644
index 0000000000..05445f4492
--- /dev/null
+++ b/source3/.indent.pro
@@ -0,0 +1,30 @@
+-bad
+-bap
+-bbb
+-br
+-ce
+-ut
+-ts8
+-i8
+-di1
+-brs
+-npsl
+-npcs
+-prs
+-bbo
+-hnl
+-bad
+-bap
+-bbb
+-br
+-ce
+-ut
+-ts8
+-i8
+-di1
+-brs
+-npsl
+-npcs
+-prs
+-bbo
+-hnl
diff --git a/source3/Doxyfile b/source3/Doxyfile
new file mode 100644
index 0000000000..9ade25c9a6
--- /dev/null
+++ b/source3/Doxyfile
@@ -0,0 +1,192 @@
+# Doxyfile 1.5.3
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = Samba
+PROJECT_NUMBER = HEAD
+
+# NOTE: By default, Doxygen writes into the dox/ subdirectory of the
+# invocation directory. If you want to put it somewhere else, for
+# example, to write straight into a webserver directory, then override
+# this variable in a configuration concatenated to this one: Doxygen
+# doesn't mind variables being redefined.
+
+OUTPUT_DIRECTORY = dox
+OUTPUT_LANGUAGE = English
+DOXYFILE_ENCODING = UTF-8
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ALWAYS_DETAILED_SEC = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH = $(PWD)/
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = YES
+INHERIT_DOCS = YES
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = YES
+DISTRIBUTE_GROUP_DOC = NO
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+EXTRACT_LOCAL_CLASSES = YES
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+INTERNAL_DOCS = YES
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = YES
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = NO
+SORT_BRIEF_DOCS = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = YES
+WARNINGS = NO
+WARN_IF_UNDOCUMENTED = NO
+WARN_IF_DOC_ERROR = NO
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = .
+INPUT_ENCODING = UTF-8
+FILE_PATTERNS = *.c \
+ *.h \
+ *.idl
+RECURSIVE = YES
+EXCLUDE = include/includes.h \
+ include/proto.h
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = YES
+INLINE_SOURCES = YES
+STRIP_CODE_COMMENTS = NO
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+REFERENCES_LINK_SOURCE = YES
+VERBATIM_HEADERS = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 1
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = .
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 3
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = YES
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+#---------------------------------------------------------------------------
+# configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = NO
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# configuration options related to the dot tool
+#---------------------------------------------------------------------------
+HAVE_DOT = NO
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+TEMPLATE_RELATIONS = YES
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = YES
+CALLER_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+DOT_GRAPH_MAX_NODES = 50
+MAX_DOT_GRAPH_DEPTH = 0
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/source3/Makefile.in b/source3/Makefile.in
new file mode 100644
index 0000000000..b67cfe8bb8
--- /dev/null
+++ b/source3/Makefile.in
@@ -0,0 +1,2734 @@
+#########################################################################
+# Makefile.in for Samba - rewritten for autoconf support
+# Copyright Andrew Tridgell 1992-1998
+# Copyright (C) 2001 by Martin Pool <mbp@samba.org>
+# Copyright Andrew Bartlett 2002
+# Copyright (C) 2003 Jim McDonough <jmcd@us.ibm.com>
+# Copyright (C) 2002-2003 Jelmer Vernooij <jelmer@samba.org>
+# Copyright (C) 2006 Lars Mueller <lars@samba.org>
+# Copyright (C) 2007 James Peach <jpeach@samba.org>
+# Copyright (C) 2008 Michael Adam <obnox@samba.org>
+###########################################################################
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+sysconfdir=@sysconfdir@
+localstatedir=@localstatedir@
+datarootdir=@datarootdir@
+
+selftest_prefix=@selftest_prefix@
+smbtorture4_path=@smbtorture4_path@
+
+LIBS=@LIBS@
+CC=@CC@
+SHLD=@SHLD@
+LIB_PATH_VAR=@LIB_PATH_VAR@
+
+## Dynamic shared libraries build settings
+DSO_EXPORTS_CMD=-Wl,--version-script,$(srcdir)/exports/`basename $@ | sed 's/@SHLIBEXT@\(.[0-9]\{1,\}\)\{0,1\}$$/@SYMSEXT@/'`
+DSO_EXPORTS=@DSO_EXPORTS@
+SHLD_DSO = $(SHLD) $(LDSHFLAGS) $(DSO_EXPORTS) -o $@
+
+# The MODULE_EXPORTS variable contains the platform-specific linker flags
+# needed to restrict the exports for VFS, IDMAP, RPC and PASSDB modules.
+MODULE_EXPORTS=@MODULE_EXPORTS@
+
+# Add $(DEVELOPER_CFLAGS) to $(CFLAGS) to enable extra compiler
+# (GCC) warnings. This is done automtically for --enable-developer,
+# --enable-picky-developer and --enable-krb5developer.
+DEVELOPER_CFLAGS=@DEVELOPER_CFLAGS@
+CFLAGS=@CFLAGS@
+CPPFLAGS=-DHAVE_CONFIG_H @CPPFLAGS@
+
+EXEEXT=@EXEEXT@
+AR=@AR@
+LDSHFLAGS=@LDSHFLAGS@ @RELRO_LDFLAGS@ @LDFLAGS@
+LDFLAGS=@PIE_LDFLAGS@ @RELRO_LDFLAGS@ @LDFLAGS@
+
+WINBIND_NSS_LDSHFLAGS=@WINBIND_NSS_LDSHFLAGS@ @LDFLAGS@
+AWK=@AWK@
+PICFLAG=@PICFLAG@
+DYNEXP=@DYNEXP@
+PERL=@PERL@
+
+PIDL_ARGS=@PIDL_ARGS@
+
+TERMLDFLAGS=@TERMLDFLAGS@
+TERMLIBS=@TERMLIBS@
+PRINT_LIBS=@PRINT_LIBS@
+AUTH_LIBS=@AUTH_LIBS@
+ACL_LIBS=@ACL_LIBS@
+PASSDB_LIBS=@PASSDB_LIBS@
+IDMAP_LIBS=@IDMAP_LIBS@
+KRB5LIBS=@KRB5_LIBS@
+LDAP_LIBS=@LDAP_LIBS@
+NSCD_LIBS=@NSCD_LIBS@
+UUID_LIBS=@UUID_LIBS@
+WINBIND_LIBS=@WINBIND_LIBS@
+WINBIND_NSS_EXTRA_LIBS=@WINBIND_NSS_EXTRA_LIBS@
+WINBIND_NSS_PTHREAD=@WINBIND_NSS_PTHREAD@
+PAM_WINBIND_EXTRA_LIBS=@PAM_WINBIND_EXTRA_LIBS@
+DNSSD_LIBS=@DNSSD_LIBS@
+POPT_LIBS=@POPTLIBS@
+LIBTALLOC_LIBS=@LIBTALLOC_LIBS@
+LIBTDB_LIBS=@LIBTDB_LIBS@
+LIBNETAPI_LIBS=@LIBNETAPI_LIBS@
+
+INSTALLCMD=@INSTALL@
+INSTALLLIBCMD_SH=@INSTALLLIBCMD_SH@
+INSTALLLIBCMD_A=@INSTALLLIBCMD_A@
+UNINSTALLLIBCMD_SH=@UNINSTALLLIBCMD_SH@
+UNINSTALLLIBCMD_A=@UNINSTALLLIBCMD_A@
+
+VPATH=@srcdir@
+srcdir=@abs_srcdir@
+builddir=@abs_builddir@
+SHELL=/bin/sh
+DESTDIR=/
+
+# XXX: Perhaps this should be @SHELL@ instead -- apparently autoconf
+# will search for a POSIX-compliant shell, and that might not be
+# /bin/sh on some platforms. I guess it's not a big problem -- mbp
+
+# See the autoconf manual "Installation Directory Variables" for a
+# discussion of the subtle use of these variables.
+
+BASEDIR= @prefix@
+BINDIR = @bindir@
+# sbindir is mapped to bindir when compiling SAMBA in 2.0.x compatibility mode.
+SBINDIR = @sbindir@
+ROOTSBINDIR = @rootsbindir@
+LIBDIR = @libdir@
+MODULESDIR = @modulesdir@
+INCLUDEDIR=@includedir@
+PAMMODULESDIR = @pammodulesdir@
+VFSLIBDIR = $(MODULESDIR)/vfs
+PDBLIBDIR = $(MODULESDIR)/pdb
+RPCLIBDIR = $(MODULESDIR)/rpc
+IDMAPLIBDIR = $(MODULESDIR)/idmap
+NSSINFOLIBDIR = $(MODULESDIR)/nss_info
+CHARSETLIBDIR = $(MODULESDIR)/charset
+AUTHLIBDIR = $(MODULESDIR)/auth
+CONFIGLIBDIR = $(MODULESDIR)/config
+GPEXTLIBDIR = $(MODULESDIR)/gpext
+CONFIGDIR = @configdir@
+VARDIR = @localstatedir@
+MANDIR = @mandir@
+DATADIR = @datadir@
+
+# The permissions to give the executables and other data
+INSTALLPERMS_BIN = 0755
+INSTALLPERMS_DATA = 0644
+
+# set these to where to find various files
+# These can be overridden by command line switches (see smbd(8))
+# or in smb.conf (see smb.conf(5))
+LOGFILEBASE = @logfilebase@
+CONFIGFILE = $(CONFIGDIR)/smb.conf
+LMHOSTSFILE = $(CONFIGDIR)/lmhosts
+CTDBDIR = @ctdbdir@
+
+# This is where smbpasswd et al go
+PRIVATEDIR = @privatedir@
+
+SMB_PASSWD_FILE = $(PRIVATEDIR)/smbpasswd
+PRIVATE_DIR = $(PRIVATEDIR)
+
+# This is where SWAT images and help files go
+SWATDIR = @swatdir@
+
+# the directory where lock files go
+LOCKDIR = @lockdir@
+
+# FHS directories; equal to LOCKDIR if not using --with-fhs
+CACHEDIR = @cachedir@
+STATEDIR = @statedir@
+
+# Where to look for (and install) codepage databases.
+CODEPAGEDIR = @codepagedir@
+
+# the directory where pid files go
+PIDDIR = @piddir@
+
+FLAGS1 = $(CFLAGS) @FLAGS1@ @SAMBA_CPPFLAGS@ $(CPPFLAGS)
+FLAGS2 =
+FLAGS3 =
+FLAGS4 = -I$(CTDBDIR)/include
+FLAGS5 = $(FLAGS1) $(FLAGS2) $(FLAGS3) $(FLAGS4)
+FLAGS = $(ISA) $(FLAGS5) -I$(srcdir)/lib -D_SAMBA_BUILD_=3
+
+PATH_FLAGS = -DSMB_PASSWD_FILE=\"$(SMB_PASSWD_FILE)\" \
+ -DPRIVATE_DIR=\"$(PRIVATE_DIR)\" \
+ -DCONFIGFILE=\"$(CONFIGFILE)\" \
+ -DSBINDIR=\"$(SBINDIR)\" \
+ -DBINDIR=\"$(BINDIR)\" \
+ -DLMHOSTSFILE=\"$(LMHOSTSFILE)\" \
+ -DSWATDIR=\"$(SWATDIR)\" \
+ -DLOCKDIR=\"$(LOCKDIR)\" \
+ -DPIDDIR=\"$(PIDDIR)\" \
+ -DLIBDIR=\"$(LIBDIR)\" \
+ -DMODULESDIR=\"$(MODULESDIR)\" \
+ -DLOGFILEBASE=\"$(LOGFILEBASE)\" \
+ -DSHLIBEXT=\"@SHLIBEXT@\" \
+ -DCTDBDIR=\"$(CTDBDIR)\" \
+ -DCONFIGDIR=\"$(CONFIGDIR)\" \
+ -DCODEPAGEDIR=\"$(CODEPAGEDIR)\" \
+ -DCACHEDIR=\"$(CACHEDIR)\" \
+ -DSTATEDIR=\"$(STATEDIR)\"
+
+# Note that all executable programs now provide for an optional executable suffix.
+
+SBIN_PROGS = bin/smbd@EXEEXT@ bin/nmbd@EXEEXT@ @SWAT_SBIN_TARGETS@ @EXTRA_SBIN_PROGS@
+
+ROOT_SBIN_PROGS = @CIFSMOUNT_PROGS@
+
+BIN_PROGS1 = bin/smbclient@EXEEXT@ bin/net@EXEEXT@ bin/smbspool@EXEEXT@ \
+ bin/testparm@EXEEXT@ bin/smbstatus@EXEEXT@ bin/smbget@EXEEXT@
+BIN_PROGS2 = bin/smbcontrol@EXEEXT@ bin/smbtree@EXEEXT@ bin/tdbbackup@EXEEXT@ \
+ bin/nmblookup@EXEEXT@ bin/pdbedit@EXEEXT@ bin/tdbdump@EXEEXT@ \
+ bin/tdbtool@EXEEXT@
+BIN_PROGS3 = bin/smbpasswd@EXEEXT@ bin/rpcclient@EXEEXT@ bin/smbcacls@EXEEXT@ \
+ bin/profiles@EXEEXT@ bin/ntlm_auth@EXEEXT@ \
+ bin/smbcquotas@EXEEXT@ bin/eventlogadm@EXEEXT@
+BIN_PROGS4 = bin/ldbedit@EXEEXT@ bin/ldbsearch@EXEEXT@ bin/ldbadd@EXEEXT@ \
+ bin/ldbdel@EXEEXT@ bin/ldbmodify@EXEEXT@
+
+TORTURE_PROGS = bin/smbtorture@EXEEXT@ bin/msgtest@EXEEXT@ \
+ bin/masktest@EXEEXT@ bin/locktest@EXEEXT@ \
+ bin/locktest2@EXEEXT@ bin/nsstest@EXEEXT@ bin/vfstest@EXEEXT@ \
+ bin/pdbtest@EXEEXT@ bin/talloctort@EXEEXT@ bin/replacetort@EXEEXT@ \
+ bin/tdbtorture@EXEEXT@ \
+ bin/smbconftort@EXEEXT@
+
+BIN_PROGS = @EXTRA_BIN_PROGS@ \
+ $(BIN_PROGS1) $(BIN_PROGS2) $(BIN_PROGS3) $(BIN_PROGS4)
+
+EVERYTHING_PROGS = bin/debug2html@EXEEXT@ bin/smbfilter@EXEEXT@ \
+ bin/talloctort@EXEEXT@ bin/replacetort@EXEEXT@ \
+ bin/log2pcap@EXEEXT@ bin/sharesec@EXEEXT@ bin/ndrdump@EXEEXT@ \
+ bin/vlp@EXEEXT@ bin/smbiconv@EXEEXT@
+
+PAM_MODULES = @PAM_MODULES@
+
+NSS_MODULES = @NSS_MODULES@
+
+SCRIPTS = $(srcdir)/script/smbtar $(builddir)/script/findsmb
+
+VFS_MODULES = @VFS_MODULES@
+PDB_MODULES = @PDB_MODULES@
+RPC_MODULES = @RPC_MODULES@
+IDMAP_MODULES = @IDMAP_MODULES@
+CHARSET_MODULES = @CHARSET_MODULES@
+AUTH_MODULES = @AUTH_MODULES@
+NSS_INFO_MODULES = @NSS_INFO_MODULES@
+GPEXT_MODULES = @GPEXT_MODULES@
+MODULES = $(VFS_MODULES) $(PDB_MODULES) $(RPC_MODULES) $(IDMAP_MODULES) \
+ $(CHARSET_MODULES) $(AUTH_MODULES) $(NSS_INFO_MODULES) \
+ $(GPEXT_MODULES)
+
+######################################################################
+# object file lists
+######################################################################
+
+TDB_LIB_OBJ = lib/util_tdb.o \
+ lib/dbwrap.o lib/dbwrap_tdb.o \
+ lib/dbwrap_ctdb.o \
+ lib/dbwrap_rbt.o @LIBTDB_STATIC@
+
+SMBLDAP_OBJ = @SMBLDAP@ @SMBLDAPUTIL@
+
+VERSION_OBJ = lib/version.o
+
+WBCOMMON_OBJ = nsswitch/wb_common.o
+
+AFS_OBJ = lib/afs.o
+
+AFS_SETTOKEN_OBJ = lib/afs_settoken.o
+
+SERVER_MUTEX_OBJ = lib/server_mutex.o
+
+PASSCHANGE_OBJ = libsmb/passchange.o
+
+LIBNDR_DRSUAPI_OBJ = librpc/ndr/ndr_drsuapi.o \
+ librpc/ndr/ndr_compression.o \
+ librpc/gen_ndr/ndr_drsuapi.o \
+ librpc/gen_ndr/ndr_drsblobs.o
+
+COMPRESSION_OBJ = lib/compression/mszip.o
+
+DRSUAPI_OBJ = $(LIBNDR_DRSUAPI_OBJ) \
+ $(COMPRESSION_OBJ)
+
+LIBNDR_OBJ = librpc/ndr/ndr_basic.o \
+ librpc/ndr/ndr.o \
+ librpc/ndr/ndr_misc.o \
+ librpc/gen_ndr/ndr_misc.o \
+ librpc/gen_ndr/ndr_security.o \
+ librpc/ndr/ndr_sec_helper.o \
+ librpc/ndr/ndr_string.o \
+ librpc/ndr/sid.o \
+ librpc/ndr/uuid.o
+
+RPCCLIENT_NDR_OBJ = rpc_client/ndr.o
+
+LIBNDR_GEN_OBJ0 = librpc/gen_ndr/ndr_samr.o \
+ librpc/gen_ndr/ndr_lsa.o
+
+LIBNDR_GEN_OBJ1 = librpc/gen_ndr/ndr_netlogon.o
+
+LIBNDR_GEN_OBJ = librpc/gen_ndr/ndr_wkssvc.o \
+ $(LIBNDR_GEN_OBJ0) \
+ librpc/gen_ndr/ndr_dfs.o \
+ librpc/gen_ndr/ndr_echo.o \
+ librpc/gen_ndr/ndr_winreg.o \
+ librpc/gen_ndr/ndr_initshutdown.o \
+ librpc/gen_ndr/ndr_srvsvc.o \
+ librpc/gen_ndr/ndr_eventlog.o \
+ $(LIBNDR_GEN_OBJ1) \
+ librpc/gen_ndr/ndr_dssetup.o \
+ librpc/gen_ndr/ndr_notify.o \
+ librpc/gen_ndr/ndr_xattr.o \
+ librpc/gen_ndr/ndr_epmapper.o \
+ librpc/gen_ndr/ndr_ntsvcs.o
+
+RPC_PARSE_OBJ0 = rpc_parse/parse_prs.o rpc_parse/parse_misc.o
+
+# this includes only the low level parse code, not stuff
+# that requires knowledge of security contexts
+RPC_PARSE_OBJ1 = $(RPC_PARSE_OBJ0) rpc_parse/parse_sec.o
+
+RPC_PARSE_OBJ2 = rpc_parse/parse_rpc.o \
+ rpc_client/init_netlogon.o \
+ rpc_client/init_lsa.o \
+ rpc_client/init_srvsvc.o
+
+LIBREPLACE_OBJ = @LIBREPLACE_OBJS@
+
+SOCKET_WRAPPER_OBJ = @SOCKET_WRAPPER_OBJS@
+NSS_WRAPPER_OBJ = @NSS_WRAPPER_OBJS@
+
+LIBSAMBAUTIL_OBJ = @LIBTALLOC_STATIC@ \
+ $(LIBREPLACE_OBJ) \
+ $(SOCKET_WRAPPER_OBJ) \
+ $(NSS_WRAPPER_OBJ)
+
+LIB_OBJ = $(LIBSAMBAUTIL_OBJ) \
+ lib/messages.o librpc/gen_ndr/ndr_messaging.o lib/messages_local.o \
+ lib/messages_ctdbd.o lib/packet.o lib/ctdbd_conn.o lib/talloc_stack.o \
+ lib/interfaces.o lib/rbtree.o lib/memcache.o \
+ lib/util_transfer_file.o lib/async_req.o \
+ lib/async_sock.o \
+ $(TDB_LIB_OBJ) \
+ $(VERSION_OBJ) lib/charcnv.o lib/debug.o lib/fault.o \
+ lib/interface.o lib/md4.o \
+ lib/pidfile.o \
+ lib/signal.o lib/system.o lib/sendfile.o lib/recvfile.o lib/time.o \
+ lib/ufc.o lib/genrand.o lib/username.o \
+ lib/util_pw.o lib/access.o lib/smbrun.o \
+ lib/bitmap.o lib/crc32.o lib/dprintf.o \
+ lib/xfile.o lib/wins_srv.o $(UTIL_REG_OBJ) \
+ lib/util_str.o lib/clobber.o lib/util_sid.o lib/util_uuid.o \
+ lib/util_unistr.o lib/util_file.o lib/data_blob.o \
+ lib/util.o lib/util_sock.o lib/sock_exec.o lib/util_sec.o \
+ lib/substitute.o lib/fsusage.o lib/dbwrap_util.o \
+ lib/ms_fnmatch.o lib/select.o lib/errmap_unix.o \
+ lib/tallocmsg.o lib/dmallocmsg.o libsmb/smb_signing.o \
+ lib/md5.o lib/hmacmd5.o lib/arc4.o lib/iconv.o \
+ lib/pam_errors.o intl/lang_tdb.o lib/conn_tdb.o \
+ lib/adt_tree.o lib/gencache.o \
+ lib/module.o lib/events.o lib/ldap_escape.o @CHARSET_STATIC@ \
+ lib/secdesc.o lib/util_seaccess.o lib/secace.o lib/secacl.o \
+ libads/krb5_errs.o lib/system_smbd.o lib/audit.o $(LIBNDR_OBJ) \
+ lib/file_id.o lib/idmap_cache.o
+
+LIB_DUMMY_OBJ = lib/dummysmbd.o lib/dummyroot.o
+LIB_NONSMBD_OBJ = $(LIB_OBJ) $(LIB_DUMMY_OBJ)
+
+READLINE_OBJ = lib/readline.o
+
+# Also depends on $(SECRETS_OBJ) $(LIBSAMBA_OBJ)
+# Be sure to include them into your application
+POPT_LIB_OBJ = lib/popt_common.o
+
+PARAM_WITHOUT_REG_OBJ = dynconfig.o param/loadparm.o param/params.o param/util.o lib/sharesec.o lib/ldap_debug_handler.o
+PARAM_REG_ADD_OBJ = $(REG_SMBCONF_OBJ) $(LIBSMBCONF_OBJ) $(PRIVILEGES_BASIC_OBJ)
+PARAM_OBJ = $(PARAM_WITHOUT_REG_OBJ) $(PARAM_REG_ADD_OBJ)
+
+KRBCLIENT_OBJ = libads/kerberos.o libads/ads_status.o
+
+LIBADDNS_OBJ0 = libaddns/dnsrecord.o libaddns/dnsutils.o libaddns/dnssock.o \
+ libaddns/dnsgss.o libaddns/dnsmarshall.o
+LIBADDNS_OBJ = $(LIBADDNS_OBJ0) $(SOCKET_WRAPPER_OBJ) @LIBTALLOC_STATIC@
+
+GPEXT_OBJ = libgpo/gpext/gpext.o @GPEXT_STATIC@
+
+LIBGPO_OBJ0 = libgpo/gpo_ldap.o libgpo/gpo_ini.o libgpo/gpo_util.o \
+ libgpo/gpo_fetch.o libgpo/gpo_filesync.o libgpo/gpo_sec.o \
+ libgpo/gpo_reg.o \
+ $(GPEXT_OBJ)
+LIBGPO_OBJ = $(LIBGPO_OBJ0)
+
+LIBADS_OBJ = libads/ldap.o libads/ldap_printer.o \
+ libads/sasl.o libads/sasl_wrapping.o \
+ libads/krb5_setpw.o libads/ldap_user.o \
+ libads/ads_struct.o libads/kerberos_keytab.o \
+ libads/disp_sec.o libads/ads_utils.o libads/ldap_utils.o \
+ libads/ldap_schema.o libads/util.o libads/ndr.o
+
+LIBADS_SERVER_OBJ = libads/kerberos_verify.o libads/authdata.o \
+ librpc/ndr/ndr_krb5pac.o \
+ librpc/gen_ndr/ndr_krb5pac.o
+
+SECRETS_OBJ = passdb/secrets.o passdb/machine_sid.o
+
+LIBNBT_OBJ = libcli/nbt/nbtname.o \
+ librpc/gen_ndr/ndr_nbt.o \
+ librpc/gen_ndr/ndr_svcctl.o
+
+LIBNMB_OBJ = libsmb/unexpected.o libsmb/namecache.o libsmb/nmblib.o \
+ libsmb/namequery.o libsmb/conncache.o libads/dns.o
+
+NTERR_OBJ = libsmb/nterr.o
+DOSERR_OBJ = libsmb/doserr.o
+ERRORMAP_OBJ = libsmb/errormap.o
+DCE_RPC_ERR_OBJ = libsmb/dcerpc_err.o
+
+LIBSMB_ERR_OBJ0 = $(NTERR_OBJ) $(DOSERR_OBJ) $(ERRORMAP_OBJ) $(DCE_RPC_ERR_OBJ) \
+ libsmb/smbdes.o libsmb/smbencrypt.o libsmb/ntlmssp_parse.o
+
+LIBSMB_ERR_OBJ = $(LIBSMB_ERR_OBJ0) \
+ $(RPC_PARSE_OBJ1) \
+ $(SECRETS_OBJ)
+
+LIBSMB_OBJ0 = \
+ libsmb/ntlm_check.o \
+ libsmb/ntlmssp.o \
+ libsmb/ntlmssp_sign.o
+
+LIBSAMBA_OBJ = $(LIBSMB_OBJ0) \
+ $(LIBSMB_ERR_OBJ)
+
+CLDAP_OBJ = libads/cldap.o
+
+LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
+ libsmb/clikrb5.o libsmb/clispnego.o libsmb/asn1.o \
+ libsmb/clirap.o libsmb/clierror.o libsmb/climessage.o \
+ libsmb/clireadwrite.o libsmb/clilist.o libsmb/cliprint.o \
+ libsmb/clitrans.o libsmb/clisecdesc.o libsmb/clidgram.o \
+ libsmb/clistr.o libsmb/cliquota.o libsmb/clifsinfo.o libsmb/clidfs.o \
+ libsmb/smberr.o libsmb/credentials.o libsmb/pwd_cache.o \
+ libsmb/clioplock.o libsmb/clirap2.o \
+ libsmb/smb_seal.o libsmb/async_smb.o \
+ $(LIBSAMBA_OBJ) \
+ $(LIBNMB_OBJ) \
+ $(LIBNBT_OBJ) \
+ $(CLDAP_OBJ) \
+ $(DRSUAPI_OBJ)
+
+RPC_CLIENT_OBJ1 = rpc_client/cli_netlogon.o
+
+LIBMSRPC_OBJ = rpc_client/cli_lsarpc.o rpc_client/cli_samr.o \
+ $(RPC_CLIENT_OBJ1) rpc_client/cli_reg.o $(RPC_CLIENT_OBJ) \
+ rpc_client/cli_spoolss.o rpc_client/cli_spoolss_notify.o \
+ rpc_client/cli_svcctl.o \
+ rpc_client/init_samr.o \
+ librpc/rpc/dcerpc.o \
+ librpc/rpc/binding.o
+
+LIBMSRPC_GEN_OBJ = librpc/gen_ndr/cli_lsa.o \
+ librpc/gen_ndr/cli_dfs.o \
+ librpc/gen_ndr/cli_echo.o \
+ librpc/gen_ndr/cli_srvsvc.o \
+ librpc/gen_ndr/cli_svcctl.o \
+ librpc/gen_ndr/cli_winreg.o \
+ librpc/gen_ndr/cli_initshutdown.o \
+ librpc/gen_ndr/cli_eventlog.o \
+ librpc/gen_ndr/cli_wkssvc.o \
+ librpc/gen_ndr/cli_netlogon.o \
+ librpc/gen_ndr/cli_samr.o \
+ librpc/gen_ndr/cli_dssetup.o \
+ librpc/gen_ndr/cli_ntsvcs.o \
+ librpc/gen_ndr/cli_epmapper.o \
+ librpc/gen_ndr/cli_drsuapi.o \
+ $(LIBNDR_GEN_OBJ) \
+ $(RPCCLIENT_NDR_OBJ)
+
+#
+# registry-related objects
+#
+UTIL_REG_OBJ = lib/util_reg.o
+UTIL_REG_API_OBJ = lib/util_reg_api.o
+
+REG_INIT_BASIC_OBJ = registry/reg_init_basic.o
+REG_INIT_SMBCONF_OBJ = registry/reg_init_smbconf.o
+REG_INIT_FULL_OBJ = registry/reg_init_full.o
+
+REGFIO_OBJ = registry/regfio.o
+
+REGOBJS_OBJ = registry/reg_objects.o
+
+REG_BACKENDS_BASE_OBJ = registry/reg_backend_db.o
+
+REG_BACKENDS_SMBCONF_OBJ = registry/reg_backend_smbconf.o
+
+REG_BACKENDS_EXTRA_OBJ = registry/reg_backend_printing.o \
+ registry/reg_backend_shares.o \
+ registry/reg_backend_netlogon_params.o \
+ registry/reg_backend_prod_options.o \
+ registry/reg_backend_tcpip_params.o \
+ registry/reg_backend_hkpt_params.o \
+ registry/reg_backend_current_version.o \
+ registry/reg_backend_perflib.o
+
+REG_BASE_OBJ = registry/reg_api.o \
+ registry/reg_dispatcher.o \
+ registry/reg_cachehook.o \
+ $(REGFIO_OBJ) \
+ $(REGOBJS_OBJ) \
+ registry/reg_util.o \
+ $(UTIL_REG_API_OBJ) \
+ lib/util_nttoken.o \
+ $(REG_BACKENDS_BASE_OBJ) \
+ $(REG_INIT_BASIC_OBJ)
+
+REG_SMBCONF_OBJ = $(REG_BASE_OBJ) \
+ $(REG_BACKENDS_SMBCONF_OBJ) \
+ $(REG_INIT_SMBCONF_OBJ)
+
+REG_FULL_OBJ = $(REG_SMBCONF_OBJ) \
+ $(REG_BACKENDS_EXTRA_OBJ) \
+ $(REG_INIT_FULL_OBJ) \
+ registry/reg_eventlog.o \
+ registry/reg_perfcount.o \
+ registry/reg_util_legacy.o
+
+
+RPC_LSA_OBJ = rpc_server/srv_lsa_nt.o librpc/gen_ndr/srv_lsa.o
+
+RPC_NETLOG_OBJ = rpc_server/srv_netlog_nt.o \
+ librpc/gen_ndr/srv_netlogon.o
+
+RPC_SAMR_OBJ = rpc_server/srv_samr_nt.o \
+ rpc_server/srv_samr_util.o \
+ librpc/gen_ndr/srv_samr.o
+
+RPC_INITSHUTDOWN_OBJ = librpc/gen_ndr/srv_initshutdown.o rpc_server/srv_initshutdown_nt.o
+
+RPC_REG_OBJ = rpc_server/srv_winreg_nt.o \
+ librpc/gen_ndr/srv_winreg.o
+
+RPC_DSSETUP_OBJ = rpc_server/srv_dssetup_nt.o librpc/gen_ndr/srv_dssetup.o
+
+RPC_SVC_OBJ = rpc_server/srv_srvsvc_nt.o \
+ librpc/gen_ndr/srv_srvsvc.o
+
+RPC_WKS_OBJ = librpc/gen_ndr/srv_wkssvc.o rpc_server/srv_wkssvc_nt.o
+
+RPC_SVCCTL_OBJ = rpc_server/srv_svcctl.o rpc_server/srv_svcctl_nt.o \
+ librpc/gen_ndr/srv_svcctl.o \
+ services/svc_spoolss.o services/svc_rcinit.o services/services_db.o \
+ services/svc_netlogon.o services/svc_winreg.o \
+ services/svc_wins.o
+
+RPC_NTSVCS_OBJ = rpc_server/srv_ntsvcs.o rpc_server/srv_ntsvcs_nt.o \
+ librpc/gen_ndr/srv_ntsvcs.o
+
+RPC_DFS_OBJ = librpc/gen_ndr/srv_dfs.o rpc_server/srv_dfs_nt.o
+
+RPC_SPOOLSS_OBJ = rpc_server/srv_spoolss.o rpc_server/srv_spoolss_nt.o
+
+RPC_EVENTLOG_OBJ = rpc_server/srv_eventlog.o rpc_server/srv_eventlog_nt.o \
+ rpc_server/srv_eventlog_lib.o librpc/gen_ndr/srv_eventlog.o
+
+RPC_PIPE_OBJ = rpc_server/srv_pipe_hnd.o \
+ rpc_server/srv_pipe.o rpc_server/srv_lsa_hnd.o
+
+RPC_ECHO_OBJ = rpc_server/srv_echo_nt.o librpc/gen_ndr/srv_echo.o
+
+RPC_SERVER_OBJ = @RPC_STATIC@ $(RPC_PIPE_OBJ)
+
+RPC_PARSE_OBJ = $(RPC_PARSE_OBJ2) \
+ rpc_parse/parse_spoolss.o \
+ rpc_parse/parse_eventlog.o rpc_parse/parse_buffer.o \
+ rpc_parse/parse_ntsvcs.o rpc_parse/parse_svcctl.o
+
+RPC_CLIENT_OBJ = rpc_client/cli_pipe.o
+
+LOCKING_OBJ = locking/locking.o locking/brlock.o locking/posix.o
+
+PRIVILEGES_BASIC_OBJ = lib/privileges_basic.o
+
+PRIVILEGES_OBJ = lib/privileges.o
+
+PASSDB_GET_SET_OBJ = passdb/pdb_get_set.o
+
+PASSDB_OBJ = $(PASSDB_GET_SET_OBJ) passdb/passdb.o passdb/pdb_interface.o \
+ passdb/util_wellknown.o passdb/util_builtin.o passdb/pdb_compat.o \
+ passdb/util_unixsids.o passdb/lookup_sid.o \
+ passdb/login_cache.o @PDB_STATIC@ \
+ lib/account_pol.o $(PRIVILEGES_OBJ) \
+ lib/util_nscd.o lib/winbind_util.o
+
+DEVEL_HELP_WEIRD_OBJ = modules/weird.o
+CP850_OBJ = modules/CP850.o
+CP437_OBJ = modules/CP437.o
+CHARSET_MACOSXFS_OBJ = modules/charset_macosxfs.o
+
+GROUPDB_OBJ = groupdb/mapping.o groupdb/mapping_tdb.o groupdb/mapping_ldb.o
+
+PROFILE_OBJ = profile/profile.o
+PROFILES_OBJ = utils/profiles.o \
+ $(LIBSAMBA_OBJ) \
+ $(PARAM_OBJ) \
+ $(LIB_OBJ) $(LIB_DUMMY_OBJ) \
+ $(POPT_LIB_OBJ)
+
+OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o smbd/oplock_linux.o
+
+NOTIFY_OBJ = smbd/notify.o smbd/notify_inotify.o smbd/notify_internal.o
+
+VFS_DEFAULT_OBJ = modules/vfs_default.o
+VFS_AUDIT_OBJ = modules/vfs_audit.o
+VFS_EXTD_AUDIT_OBJ = modules/vfs_extd_audit.o
+VFS_FULL_AUDIT_OBJ = modules/vfs_full_audit.o
+VFS_FAKE_PERMS_OBJ = modules/vfs_fake_perms.o
+VFS_RECYCLE_OBJ = modules/vfs_recycle.o
+VFS_NETATALK_OBJ = modules/vfs_netatalk.o
+VFS_DEFAULT_QUOTA_OBJ = modules/vfs_default_quota.o
+VFS_READONLY_OBJ = modules/vfs_readonly.o modules/getdate.o
+VFS_CAP_OBJ = modules/vfs_cap.o
+VFS_EXPAND_MSDFS_OBJ = modules/vfs_expand_msdfs.o
+VFS_SHADOW_COPY_OBJ = modules/vfs_shadow_copy.o
+VFS_SHADOW_COPY2_OBJ = modules/vfs_shadow_copy2.o
+VFS_AFSACL_OBJ = modules/vfs_afsacl.o
+VFS_XATTR_TDB_OBJ = modules/vfs_xattr_tdb.o
+VFS_POSIXACL_OBJ = modules/vfs_posixacl.o
+VFS_AIXACL_OBJ = modules/vfs_aixacl.o modules/vfs_aixacl_util.o
+VFS_AIXACL2_OBJ = modules/vfs_aixacl2.o modules/vfs_aixacl_util.o modules/nfs4_acls.o
+VFS_SOLARISACL_OBJ = modules/vfs_solarisacl.o
+VFS_ZFSACL_OBJ = modules/vfs_zfsacl.o modules/nfs4_acls.o
+VFS_HPUXACL_OBJ = modules/vfs_hpuxacl.o
+VFS_IRIXACL_OBJ = modules/vfs_irixacl.o
+VFS_TRU64ACL_OBJ = modules/vfs_tru64acl.o
+VFS_CATIA_OBJ = modules/vfs_catia.o
+VFS_STREAMS_XATTR_OBJ = modules/vfs_streams_xattr.o
+VFS_STREAMS_DEPOT_OBJ = modules/vfs_streams_depot.o
+VFS_CACHEPRIME_OBJ = modules/vfs_cacheprime.o
+VFS_PREALLOC_OBJ = modules/vfs_prealloc.o
+VFS_COMMIT_OBJ = modules/vfs_commit.o
+VFS_GPFS_OBJ = modules/vfs_gpfs.o modules/gpfs.o modules/nfs4_acls.o
+VFS_NOTIFY_FAM_OBJ = modules/vfs_notify_fam.o
+VFS_READAHEAD_OBJ = modules/vfs_readahead.o
+VFS_TSMSM_OBJ = modules/vfs_tsmsm.o
+VFS_FILEID_OBJ = modules/vfs_fileid.o
+VFS_AIO_FORK_OBJ = modules/vfs_aio_fork.o
+VFS_SYNCOPS_OBJ = modules/vfs_syncops.o
+
+PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o
+
+SLCACHE_OBJ = libsmb/samlogon_cache.o
+
+DCUTIL_OBJ = libsmb/namequery_dc.o libsmb/trustdom_cache.o libsmb/trusts_util.o libsmb/dsgetdcname.o
+
+AUTH_BUILTIN_OBJ = auth/auth_builtin.o
+AUTH_DOMAIN_OBJ = auth/auth_domain.o
+AUTH_SAM_OBJ = auth/auth_sam.o
+AUTH_SERVER_OBJ = auth/auth_server.o
+AUTH_UNIX_OBJ = auth/auth_unix.o
+AUTH_WINBIND_OBJ = auth/auth_winbind.o
+AUTH_SCRIPT_OBJ = auth/auth_script.o
+
+AUTH_OBJ = auth/auth.o @AUTH_STATIC@ auth/auth_util.o auth/token_util.o \
+ auth/auth_compat.o auth/auth_ntlmssp.o \
+ $(PLAINTEXT_AUTH_OBJ) $(SLCACHE_OBJ) $(DCUTIL_OBJ)
+
+MANGLE_OBJ = smbd/mangle.o smbd/mangle_hash.o smbd/mangle_hash2.o
+
+SMBD_OBJ_MAIN = smbd/server.o
+
+BUILDOPT_OBJ = smbd/build_options.o
+
+SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \
+ smbd/utmp.o smbd/session.o smbd/map_username.o \
+ smbd/dfree.o smbd/dir.o smbd/password.o smbd/conn.o \
+ smbd/share_access.o smbd/fileio.o \
+ smbd/ipc.o smbd/lanman.o smbd/negprot.o \
+ smbd/message.o smbd/nttrans.o smbd/pipes.o \
+ smbd/reply.o smbd/sesssetup.o smbd/trans2.o smbd/uid.o \
+ smbd/dosmode.o smbd/filename.o smbd/open.o smbd/close.o \
+ smbd/blocking.o smbd/sec_ctx.o smbd/srvstr.o \
+ smbd/vfs.o smbd/statcache.o smbd/seal.o \
+ smbd/posix_acls.o lib/sysacls.o $(SERVER_MUTEX_OBJ) \
+ smbd/process.o smbd/service.o smbd/error.o \
+ printing/printfsp.o lib/sysquotas.o lib/sysquotas_linux.o \
+ lib/sysquotas_xfs.o lib/sysquotas_4A.o \
+ smbd/change_trust_pw.o smbd/fake_file.o \
+ smbd/quotas.o smbd/ntquotas.o $(AFS_OBJ) smbd/msdfs.o \
+ $(AFS_SETTOKEN_OBJ) smbd/aio.o smbd/statvfs.o \
+ smbd/dmapi.o \
+ smbd/file_access.o \
+ smbd/dnsregister.o \
+ $(MANGLE_OBJ) @VFS_STATIC@
+
+SMBD_OBJ_BASE = $(PARAM_WITHOUT_REG_OBJ) $(SMBD_OBJ_SRV) $(LIBSMB_OBJ) \
+ $(RPC_SERVER_OBJ) $(RPC_PARSE_OBJ) \
+ $(LOCKING_OBJ) $(PASSDB_OBJ) $(PRINTING_OBJ) $(PROFILE_OBJ) \
+ $(LIB_OBJ) $(PRINTBACKEND_OBJ) $(OPLOCK_OBJ) \
+ $(NOTIFY_OBJ) $(GROUPDB_OBJ) $(AUTH_OBJ) \
+ $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) \
+ $(LIBADS_OBJ) $(KRBCLIENT_OBJ) $(LIBADS_SERVER_OBJ) \
+ $(REG_FULL_OBJ) $(POPT_LIB_OBJ) $(BUILDOPT_OBJ) \
+ $(SMBLDAP_OBJ) $(LDB_OBJ) $(LIBNET_OBJ) @LIBWBCLIENT_STATIC@ \
+ $(LIBSMBCONF_OBJ) \
+ $(PRIVILEGES_BASIC_OBJ)
+
+PRINTING_OBJ = printing/pcap.o printing/print_svid.o printing/print_aix.o \
+ printing/print_cups.o printing/print_generic.o \
+ printing/lpq_parse.o printing/load.o \
+ printing/print_iprint.o
+
+PRINTBASE_OBJ = printing/notify.o printing/printing_db.o
+PRINTBACKEND_OBJ = printing/printing.o printing/nt_printing.o $(PRINTBASE_OBJ)
+
+SMBD_OBJ = $(SMBD_OBJ_BASE) $(SMBD_OBJ_MAIN)
+
+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 smbd/connection.o
+
+NMBD_OBJ = $(NMBD_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
+ $(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \
+ $(LIBNDR_GEN_OBJ0)
+
+SWAT_OBJ1 = web/cgi.o web/diagnose.o web/startstop.o web/statuspage.o \
+ web/swat.o web/neg_lang.o
+
+SWAT_OBJ = $(SWAT_OBJ1) $(PARAM_OBJ) $(PRINTING_OBJ) $(LIBSMB_OBJ) \
+ $(LOCKING_OBJ) $(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ $(KRBCLIENT_OBJ) \
+ $(LIB_NONSMBD_OBJ) $(GROUPDB_OBJ) $(PLAINTEXT_AUTH_OBJ) \
+ $(POPT_LIB_OBJ) $(SMBLDAP_OBJ) $(RPC_PARSE_OBJ) $(LIBMSRPC_GEN_OBJ) $(LIBMSRPC_OBJ) \
+ $(PASSCHANGE_OBJ) $(LDB_OBJ)
+
+STATUS_OBJ = utils/status.o utils/status_profile.o \
+ $(LOCKING_OBJ) $(PARAM_OBJ) \
+ $(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \
+ $(LIBSAMBA_OBJ)
+
+SMBCONTROL_OBJ = utils/smbcontrol.o $(LOCKING_OBJ) $(PARAM_OBJ) \
+ $(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \
+ $(LIBSAMBA_OBJ) \
+ $(PRINTBASE_OBJ)
+
+SMBTREE_OBJ = utils/smbtree.o $(PARAM_OBJ) \
+ $(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(LIBSMB_OBJ) \
+ $(KRBCLIENT_OBJ) $(POPT_LIB_OBJ) \
+ rpc_client/cli_pipe.o librpc/rpc/binding.o $(RPC_PARSE_OBJ2) \
+ $(RPC_CLIENT_OBJ1) \
+ $(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ $(SMBLDAP_OBJ) $(LDB_OBJ) $(GROUPDB_OBJ) \
+ $(LIBMSRPC_GEN_OBJ)
+
+TESTPARM_OBJ = utils/testparm.o \
+ $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \
+ $(LIBSAMBA_OBJ)
+
+PASSWD_UTIL_OBJ = utils/passwd_util.o
+
+SMBPASSWD_OBJ = utils/smbpasswd.o $(PASSWD_UTIL_OBJ) $(PASSCHANGE_OBJ) \
+ $(PARAM_OBJ) $(LIBSMB_OBJ) $(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ \
+ $(GROUPDB_OBJ) $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) \
+ $(POPT_LIB_OBJ) $(SMBLDAP_OBJ) $(RPC_PARSE_OBJ) \
+ $(LIBMSRPC_GEN_OBJ) $(LIBMSRPC_OBJ) $(LDB_OBJ)
+
+PDBEDIT_OBJ = utils/pdbedit.o $(PASSWD_UTIL_OBJ) $(PARAM_OBJ) $(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ \
+ $(LIBSAMBA_OBJ) \
+ $(LIB_NONSMBD_OBJ) $(GROUPDB_OBJ) \
+ $(POPT_LIB_OBJ) $(SMBLDAP_OBJ) libsmb/asn1.o \
+ $(LDB_OBJ)
+
+SMBGET_OBJ = utils/smbget.o $(POPT_LIB_OBJ) $(LIBSMBCLIENT_OBJ1) @LIBWBCLIENT_STATIC@
+
+DISPLAY_SEC_OBJ= lib/display_sec.o
+
+RPCCLIENT_OBJ1 = rpcclient/rpcclient.o rpcclient/cmd_lsarpc.o \
+ rpcclient/cmd_samr.o rpcclient/cmd_spoolss.o \
+ rpcclient/cmd_netlogon.o rpcclient/cmd_srvsvc.o \
+ rpcclient/cmd_dfs.o \
+ rpcclient/cmd_dssetup.o rpcclient/cmd_echo.o \
+ rpcclient/cmd_shutdown.o rpcclient/cmd_test.o \
+ rpcclient/cmd_wkssvc.o rpcclient/cmd_ntsvcs.o \
+ rpcclient/cmd_drsuapi.o \
+ $(DISPLAY_SEC_OBJ)
+
+RPCCLIENT_OBJ = $(RPCCLIENT_OBJ1) \
+ $(PARAM_OBJ) $(LIBSMB_OBJ) $(LIB_NONSMBD_OBJ) \
+ $(RPC_PARSE_OBJ) $(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ $(LIBMSRPC_GEN_OBJ) $(LIBMSRPC_OBJ) \
+ $(READLINE_OBJ) $(GROUPDB_OBJ) $(KRBCLIENT_OBJ) \
+ $(LIBADS_OBJ) $(POPT_LIB_OBJ) \
+ $(SMBLDAP_OBJ) $(DCUTIL_OBJ) $(LDB_OBJ)
+
+PAM_WINBIND_OBJ = nsswitch/pam_winbind.o $(WBCOMMON_OBJ) \
+ $(LIBREPLACE_OBJ) @BUILD_INIPARSER@
+
+LIBSMBCLIENT_OBJ0 = \
+ libsmb/libsmb_cache.o \
+ libsmb/libsmb_compat.o \
+ libsmb/libsmb_context.o \
+ libsmb/libsmb_dir.o \
+ libsmb/libsmb_file.o \
+ libsmb/libsmb_misc.o \
+ libsmb/libsmb_path.o \
+ libsmb/libsmb_printjob.o \
+ libsmb/libsmb_server.o \
+ libsmb/libsmb_stat.o \
+ libsmb/libsmb_xattr.o \
+ libsmb/libsmb_setget.o
+
+LIBSMBCLIENT_OBJ1 = $(LIBSMBCLIENT_OBJ0) \
+ $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
+ $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
+ $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(RPC_PARSE_OBJ) \
+ $(PASSDB_OBJ) $(SMBLDAP_OBJ) $(GROUPDB_OBJ) $(LDB_OBJ)
+
+LIBSMBCLIENT_OBJ = $(LIBSMBCLIENT_OBJ1) @LIBWBCLIENT_STATIC@
+
+# This shared library is intended for linking with unit test programs
+# to test Samba internals. It's called libbigballofmud.so to
+# discourage casual usage.
+
+LIBBIGBALLOFMUD_MAJOR = 0
+
+LIBBIGBALLOFMUD_OBJ = $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
+ $(LIBSMB_OBJ) $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(RPC_PARSE_OBJ) $(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ \
+ $(GROUPDB_OBJ) $(KRBCLIENT_OBJ) $(SMBLDAP_OBJ) $(LDB_OBJ)
+
+CLIENT_OBJ1 = client/client.o client/clitar.o rpc_client/cli_pipe.o \
+ librpc/rpc/binding.o \
+ client/dnsbrowse.o \
+ $(RPC_CLIENT_OBJ1) \
+ $(RPC_PARSE_OBJ2)
+
+CLIENT_OBJ = $(CLIENT_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) \
+ $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) $(LIBMSRPC_GEN_OBJ) \
+ $(READLINE_OBJ) $(POPT_LIB_OBJ) \
+ $(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ $(SMBLDAP_OBJ) $(GROUPDB_OBJ) $(LDB_OBJ) \
+ $(DISPLAY_SEC_OBJ)
+
+LIBSMBCONF_OBJ = lib/smbconf/smbconf.o lib/smbconf/smbconf_util.o \
+ lib/smbconf/smbconf_reg.o \
+ lib/smbconf/smbconf_txt.o \
+ lib/smbconf/smbconf_init.o
+
+SMBCONFTORT_OBJ0 = lib/smbconf/testsuite.o
+
+SMBCONFTORT_OBJ = $(SMBCONFTORT_OBJ0) \
+ $(LIB_NONSMBD_OBJ) \
+ $(PARAM_OBJ) \
+ $(LIBSMB_ERR_OBJ) \
+ $(POPT_LIB_OBJ)
+
+LIBNET_OBJ = libnet/libnet_join.o \
+ libnet/libnet_keytab.o \
+ libnet/libnet_samsync.o \
+ libnet/libnet_samsync_ldif.o \
+ libnet/libnet_samsync_passdb.o \
+ libnet/libnet_samsync_display.o \
+ libnet/libnet_samsync_keytab.o \
+ libnet/libnet_dssync.o \
+ libnet/libnet_dssync_keytab.o \
+ librpc/gen_ndr/ndr_libnet_join.o
+
+NET_OBJ1 = utils/net.o utils/net_ads.o utils/net_help.o \
+ utils/net_rap.o utils/net_rpc.o utils/net_rpc_samsync.o \
+ utils/net_rpc_join.o utils/net_time.o utils/net_lookup.o \
+ utils/net_cache.o utils/net_groupmap.o utils/net_idmap.o \
+ utils/net_status.o utils/net_rpc_printer.o utils/net_rpc_rights.o \
+ utils/net_rpc_service.o utils/net_rpc_registry.o utils/net_usershare.o \
+ utils/netlookup.o utils/net_sam.o utils/net_rpc_shell.o \
+ utils/net_util.o utils/net_rpc_sh_acct.o utils/net_rpc_audit.o \
+ $(PASSWD_UTIL_OBJ) utils/net_dns.o utils/net_ads_gpo.o \
+ utils/net_conf.o utils/net_join.o utils/net_user.o \
+ utils/net_group.o utils/net_file.o utils/net_registry.o \
+ auth/token_util.o utils/net_dom.o utils/net_share.o
+
+# these are not processed by make proto
+NET_OBJ2 = utils/net_registry_util.o utils/net_help_common.o
+
+NET_OBJ = $(NET_OBJ1) \
+ $(NET_OBJ2) @FAKE_KASERVER_OBJ@\
+ $(PARAM_WITHOUT_REG_OBJ) $(LIBSMB_OBJ) \
+ $(RPC_PARSE_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ) \
+ $(KRBCLIENT_OBJ) $(LIB_NONSMBD_OBJ) $(LIBADDNS_OBJ0) \
+ $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) \
+ $(LIBADS_OBJ) $(LIBADS_SERVER_OBJ) $(POPT_LIB_OBJ) \
+ $(SMBLDAP_OBJ) $(DCUTIL_OBJ) $(SERVER_MUTEX_OBJ) \
+ $(AFS_OBJ) $(AFS_SETTOKEN_OBJ) $(READLINE_OBJ) \
+ $(LDB_OBJ) $(LIBGPO_OBJ) @BUILD_INIPARSER@ $(DISPLAY_SEC_OBJ) \
+ $(REG_SMBCONF_OBJ) @LIBNETAPI_STATIC@ $(LIBNET_OBJ) \
+ $(LIBSMBCONF_OBJ) \
+ @LIBWBCLIENT_STATIC@ \
+ $(PRIVILEGES_BASIC_OBJ)
+
+CUPS_OBJ = client/smbspool.o $(PARAM_OBJ) $(LIBSMB_OBJ) \
+ $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) $(POPT_LIB_OBJ) \
+ $(LIBNDR_GEN_OBJ0)
+
+CIFS_MOUNT_OBJ = client/mount.cifs.o
+
+CIFS_UMOUNT_OBJ = client/umount.cifs.o
+
+CIFS_UPCALL_OBJ = client/cifs.upcall.o
+
+NMBLOOKUP_OBJ = utils/nmblookup.o $(PARAM_OBJ) $(LIBNMB_OBJ) \
+ $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(LIBSAMBA_OBJ)
+
+SMBTORTURE_OBJ1 = torture/torture.o torture/nbio.o torture/scanner.o torture/utable.o \
+ torture/denytest.o torture/mangle_test.o
+
+SMBTORTURE_OBJ = $(SMBTORTURE_OBJ1) $(PARAM_OBJ) \
+ $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) $(LIB_NONSMBD_OBJ) \
+ $(LIBNDR_GEN_OBJ0)
+
+MASKTEST_OBJ = torture/masktest.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
+ $(LIB_NONSMBD_OBJ) \
+ $(LIBNDR_GEN_OBJ0)
+
+MSGTEST_OBJ = torture/msgtest.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
+ $(LIB_NONSMBD_OBJ) \
+ $(LIBNDR_GEN_OBJ0)
+
+LOCKTEST_OBJ = torture/locktest.o $(PARAM_OBJ) $(LOCKING_OBJ) $(KRBCLIENT_OBJ) \
+ $(LIBSMB_OBJ) $(LIB_NONSMBD_OBJ) \
+ $(LIBNDR_GEN_OBJ0)
+
+NSSTEST_OBJ = torture/nsstest.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
+ $(LIB_NONSMBD_OBJ) \
+ $(LIBNDR_GEN_OBJ0)
+
+PDBTEST_OBJ = torture/pdbtest.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
+ $(LIB_NONSMBD_OBJ) $(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ $(GROUPDB_OBJ) \
+ $(SMBLDAP_OBJ) $(POPT_LIB_OBJ) $(LDB_OBJ) \
+ $(LIBNDR_GEN_OBJ0)
+
+VFSTEST_OBJ = torture/cmd_vfs.o torture/vfstest.o $(SMBD_OBJ_BASE) $(READLINE_OBJ)
+
+SMBICONV_OBJ = $(PARAM_OBJ) torture/smbiconv.o $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(LIBSAMBA_OBJ)
+
+LOG2PCAP_OBJ = utils/log2pcaphex.o
+
+LOCKTEST2_OBJ = torture/locktest2.o $(PARAM_OBJ) $(LOCKING_OBJ) $(LIBSMB_OBJ) \
+ $(KRBCLIENT_OBJ) $(LIB_NONSMBD_OBJ) \
+ $(LIBNDR_GEN_OBJ0)
+
+SMBCACLS_OBJ = utils/smbcacls.o $(PARAM_OBJ) $(LIBSMB_OBJ) \
+ $(KRBCLIENT_OBJ) $(LIB_NONSMBD_OBJ) $(RPC_PARSE_OBJ) \
+ $(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ $(GROUPDB_OBJ) $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) \
+ $(POPT_LIB_OBJ) $(DCUTIL_OBJ) $(LIBADS_OBJ) $(SMBLDAP_OBJ) $(LDB_OBJ)
+
+SMBCQUOTAS_OBJ = utils/smbcquotas.o $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
+ $(PARAM_OBJ) \
+ $(LIB_NONSMBD_OBJ) $(RPC_PARSE_OBJ) \
+ $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(POPT_LIB_OBJ) \
+ $(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ $(SMBLDAP_OBJ) $(GROUPDB_OBJ) $(LDB_OBJ)
+
+EVTLOGADM_OBJ0 = utils/eventlogadm.o
+
+EVTLOGADM_OBJ = $(EVTLOGADM_OBJ0) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
+ $(LIBSAMBA_OBJ) \
+ registry/reg_eventlog.o rpc_server/srv_eventlog_lib.o
+
+SHARESEC_OBJ0 = utils/sharesec.o
+SHARESEC_OBJ = $(SHARESEC_OBJ0) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
+ $(LIBSAMBA_OBJ) \
+ $(POPT_LIB_OBJ)
+
+TALLOCTORT_OBJ = @tallocdir@/testsuite.o $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
+ $(LIBSAMBA_OBJ)
+
+REPLACETORT_OBJ = lib/replace/test/testsuite.o \
+ lib/replace/test/getifaddrs.o \
+ lib/replace/test/os2_delete.o \
+ lib/replace/test/strptime.o \
+ $(LIBREPLACE_OBJ)
+
+NDRDUMP_OBJ = librpc/tools/ndrdump.o \
+ $(PARAM_OBJ) $(LIBNDR_GEN_OBJ) \
+ $(LIBSAMBA_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \
+ librpc/gen_ndr/ndr_svcctl.o
+
+DEBUG2HTML_OBJ = utils/debug2html.o utils/debugparse.o
+
+SMBFILTER_OBJ = utils/smbfilter.o $(PARAM_OBJ) $(LIBSMB_OBJ) \
+ $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) \
+ $(LIBNDR_GEN_OBJ0)
+
+WINBIND_WINS_NSS_OBJ = nsswitch/wins.o $(PARAM_OBJ) \
+ $(LIBSMB_OBJ) $(LIB_NONSMBD_OBJ) $(NSSWINS_OBJ) $(KRBCLIENT_OBJ) \
+ $(LIBNDR_GEN_OBJ0)
+
+PAM_SMBPASS_OBJ_0 = pam_smbpass/pam_smb_auth.o pam_smbpass/pam_smb_passwd.o \
+ pam_smbpass/pam_smb_acct.o pam_smbpass/support.o
+PAM_SMBPASS_OBJ = $(PAM_SMBPASS_OBJ_0) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ $(GROUPDB_OBJ) \
+ $(SMBLDAP_OBJ) $(LIBSAMBA_OBJ) \
+ $(LDB_OBJ)
+
+IDMAP_OBJ = winbindd/idmap.o winbindd/idmap_util.o @IDMAP_STATIC@
+
+NSS_INFO_OBJ = winbindd/nss_info.o @NSS_INFO_STATIC@
+
+WINBINDD_OBJ1 = \
+ winbindd/winbindd.o \
+ winbindd/winbindd_user.o \
+ winbindd/winbindd_group.o \
+ winbindd/winbindd_util.o \
+ winbindd/winbindd_cache.o \
+ winbindd/winbindd_pam.o \
+ winbindd/winbindd_sid.o \
+ winbindd/winbindd_misc.o \
+ winbindd/winbindd_cm.o \
+ winbindd/winbindd_wins.o \
+ winbindd/winbindd_rpc.o \
+ winbindd/winbindd_reconnect.o \
+ winbindd/winbindd_ads.o \
+ winbindd/winbindd_passdb.o \
+ winbindd/winbindd_dual.o \
+ winbindd/winbindd_async.o \
+ winbindd/winbindd_creds.o \
+ winbindd/winbindd_cred_cache.o \
+ winbindd/winbindd_ccache_access.o \
+ winbindd/winbindd_domain.o \
+ winbindd/winbindd_idmap.o \
+ winbindd/winbindd_locator.o \
+ winbindd/winbindd_ndr.o \
+ auth/token_util.o \
+ smbd/connection.o
+
+WINBINDD_OBJ = \
+ $(WINBINDD_OBJ1) $(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ $(GROUPDB_OBJ) \
+ $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
+ $(LIBSMB_OBJ) $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(RPC_PARSE_OBJ) \
+ $(PROFILE_OBJ) $(SLCACHE_OBJ) $(SMBLDAP_OBJ) \
+ $(LIBADS_OBJ) $(KRBCLIENT_OBJ) $(POPT_LIB_OBJ) \
+ $(DCUTIL_OBJ) $(IDMAP_OBJ) $(NSS_INFO_OBJ) \
+ $(AFS_OBJ) $(AFS_SETTOKEN_OBJ) \
+ $(LIBADS_SERVER_OBJ) $(SERVER_MUTEX_OBJ) $(LDB_OBJ)
+
+WBINFO_OBJ = nsswitch/wbinfo.o $(LIBSAMBA_OBJ) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
+ $(POPT_LIB_OBJ) $(AFS_SETTOKEN_OBJ) \
+ lib/winbind_util.o $(WBCOMMON_OBJ) @LIBWBCLIENT_STATIC@
+
+WINBIND_NSS_OBJ = $(WBCOMMON_OBJ) $(LIBREPLACE_OBJ) @WINBIND_NSS_EXTRA_OBJS@
+
+LDB_COMMON_OBJ=lib/ldb/common/ldb.o lib/ldb/common/ldb_ldif.o \
+ lib/ldb/common/ldb_parse.o lib/ldb/common/ldb_msg.o lib/ldb/common/ldb_utf8.o \
+ lib/ldb/common/ldb_debug.o lib/ldb/common/ldb_modules.o \
+ lib/ldb/common/ldb_dn.o lib/ldb/common/ldb_match.o lib/ldb/common/ldb_attributes.o \
+ lib/ldb/common/attrib_handlers.o lib/ldb/common/ldb_controls.o lib/ldb/common/qsort.o
+
+LDB_TDB_OBJ=lib/ldb/ldb_tdb/ldb_tdb.o \
+ lib/ldb/ldb_tdb/ldb_pack.o lib/ldb/ldb_tdb/ldb_search.o lib/ldb/ldb_tdb/ldb_index.o \
+ lib/ldb/ldb_tdb/ldb_cache.o lib/ldb/ldb_tdb/ldb_tdb_wrap.o
+
+LDB_MODULES_OBJ=lib/ldb/modules/operational.o lib/ldb/modules/rdn_name.o \
+ lib/ldb/modules/objectclass.o \
+ lib/ldb/modules/paged_results.o lib/ldb/modules/sort.o lib/ldb/modules/asq.o
+
+# enabled in configure.in
+LDB_LDAP_OBJ=@LDBLDAP@
+
+LDB_OBJ = ${LDB_COMMON_OBJ} ${LDB_TDB_OBJ} ${LDB_LDAP_OBJ} ${LDB_MODULES_OBJ}
+
+LDB_CMDLINE_OBJ = $(PARAM_OBJ) \
+ $(POPT_LIB_OBJ) $(LIB_OBJ) $(LIB_DUMMY_OBJ) $(LIBSMB_ERR_OBJ0) \
+ $(RPC_PARSE_OBJ1) $(SECRETS_OBJ) \
+ $(LDB_OBJ) lib/ldb/tools/cmdline.o
+
+
+LDBEDIT_OBJ = $(LDB_CMDLINE_OBJ) lib/ldb/tools/ldbedit.o
+LDBSEARCH_OBJ = $(LDB_CMDLINE_OBJ) lib/ldb/tools/ldbsearch.o
+LDBADD_OBJ = $(LDB_CMDLINE_OBJ) lib/ldb/tools/ldbadd.o
+LDBDEL_OBJ = $(LDB_CMDLINE_OBJ) lib/ldb/tools/ldbdel.o
+LDBMODIFY_OBJ = $(LDB_CMDLINE_OBJ) lib/ldb/tools/ldbmodify.o
+
+WINBIND_KRB5_LOCATOR_OBJ1 = nsswitch/winbind_krb5_locator.o
+WINBIND_KRB5_LOCATOR_OBJ = $(WINBIND_KRB5_LOCATOR_OBJ1) $(WBCOMMON_OBJ) $(LIBREPLACE_OBJ)
+
+POPT_OBJ=popt/findme.o popt/popt.o popt/poptconfig.o \
+ popt/popthelp.o popt/poptparse.o
+
+INIPARSER_OBJ = iniparser_build/iniparser.o iniparser_build/dictionary.o \
+ iniparser_build/strlib.o
+
+TDBBACKUP_OBJ = @tdbdir@/tools/tdbbackup.o $(LIBREPLACE_OBJ) \
+ @LIBTDB_STATIC@ $(SOCKET_WRAPPER_OBJ)
+
+TDBTOOL_OBJ = @tdbdir@/tools/tdbtool.o @LIBTDB_STATIC@ $(LIBREPLACE_OBJ) \
+ $(SOCKET_WRAPPER_OBJ)
+
+TDBDUMP_OBJ = @tdbdir@/tools/tdbdump.o @LIBTDB_STATIC@ $(LIBREPLACE_OBJ) \
+ $(SOCKET_WRAPPER_OBJ)
+
+TDBTORTURE_OBJ = @tdbdir@/tools/tdbtorture.o @LIBTDB_STATIC@ $(LIBREPLACE_OBJ) \
+ $(SOCKET_WRAPPER_OBJ)
+
+
+NTLM_AUTH_OBJ1 = utils/ntlm_auth.o utils/ntlm_auth_diagnostics.o
+
+NTLM_AUTH_OBJ = ${NTLM_AUTH_OBJ1} $(LIBSAMBA_OBJ) $(POPT_LIB_OBJ) \
+ libsmb/asn1.o libsmb/spnego.o libsmb/clikrb5.o libads/kerberos.o \
+ $(SERVER_MUTEX_OBJ) $(LIBADS_SERVER_OBJ) \
+ $(PASSDB_OBJ) $(GROUPDB_OBJ) \
+ $(SMBLDAP_OBJ) $(LIBNMB_OBJ) \
+ $(LDB_OBJ) $(WBCOMMON_OBJ) @LIBWBCLIENT_STATIC@ \
+ $(LIBNDR_GEN_OBJ0) $(LIBNDR_GEN_OBJ1)
+
+
+VLP_OBJ1 = ../testsuite/printing/vlp.o $(RPC_CLIENT_OBJ1) $(RPC_PARSE_OBJ2) $(RPC_CLIENT_OBJ) librpc/rpc/binding.o
+
+VLP_OBJ = $(VLP_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) \
+ $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) $(LIBMSRPC_GEN_OBJ) \
+ $(READLINE_OBJ) $(POPT_LIB_OBJ) \
+ $(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ $(SMBLDAP_OBJ) $(GROUPDB_OBJ) $(LDB_OBJ) \
+ $(DISPLAY_SEC_OBJ)
+
+RPC_OPEN_TCP_OBJ = torture/rpc_open_tcp.o \
+ $(LIBSMB_OBJ) \
+ $(PARAM_OBJ) \
+ $(PASSDB_OBJ) \
+ @LIBWBCLIENT_STATIC@ $(SMBLDAP_OBJ) $(LDB_OBJ) $(GROUPDB_OBJ) \
+ $(LIB_NONSMBD_OBJ) \
+ $(KRBCLIENT_OBJ) \
+ $(RPC_PARSE_OBJ2) \
+ $(RPC_CLIENT_OBJ1) \
+ rpc_client/cli_pipe.o \
+ librpc/rpc/binding.o \
+ $(LIBMSRPC_GEN_OBJ)
+
+
+######################################################################
+# now the rules...
+######################################################################
+all:: SHOWFLAGS libs $(SBIN_PROGS) $(BIN_PROGS) $(ROOT_SBIN_PROGS) \
+ $(MODULES) $(NSS_MODULES) $(PAM_MODULES) @EXTRA_ALL_TARGETS@
+
+nss_modules:: $(NSS_MODULES)
+
+pam_modules:: $(PAM_MODULES)
+
+pam_smbpass: SHOWFLAGS bin/pam_smbpass.@SHLIBEXT@
+
+pam_winbind: SHOWFLAGS bin/pam_winbind.@SHLIBEXT@
+
+torture:: SHOWFLAGS $(TORTURE_PROGS)
+
+smbtorture : SHOWFLAGS bin/smbtorture@EXEEXT@
+
+masktest : SHOWFLAGS bin/masktest@EXEEXT@
+
+msgtest : SHOWFLAGS bin/msgtest@EXEEXT@
+
+locktest : SHOWFLAGS bin/locktest@EXEEXT@
+
+smbcacls : SHOWFLAGS bin/smbcacls@EXEEXT@
+
+smbcquotas : SHOWFLAGS bin/smbcquotas@EXEEXT@
+
+locktest2 : SHOWFLAGS bin/locktest2@EXEEXT@
+
+debug2html : SHOWFLAGS bin/debug2html@EXEEXT@
+
+smbfilter : SHOWFLAGS bin/smbfilter@EXEEXT@
+
+eventlogadm: SHOWFLAGS bin/eventlogadm@EXEEXT@
+
+sharesec: SHOWFLAGS bin/sharesec@EXEEXT@
+
+talloctort : SHOWFLAGS bin/talloctort@EXEEXT@
+
+replacetort : SHOWFLAGS bin/replacetort@EXEEXT@
+
+smbconftort : SHOWFLAGS bin/smbconftort@EXEEXT@
+
+timelimit : SHOWFLAGS bin/timelimit@EXEEXT@
+
+nsswitch : SHOWFLAGS bin/winbindd@EXEEXT@ bin/wbinfo@EXEEXT@ @WINBIND_NSS@ \
+ @WINBIND_WINS_NSS@ @WINBIND_KRB5_LOCATOR@ \
+ bin/pam_winbind.@SHLIBEXT@ bin/smbcontrol@EXEEXT@
+
+wins : SHOWFLAGS @WINBIND_WINS_NSS@
+
+modules:: SHOWFLAGS $(MODULES)
+
+#####################################################################
+## Perl IDL Compiler
+IDL_FILES = lsa.idl dfs.idl echo.idl winreg.idl initshutdown.idl \
+ srvsvc.idl svcctl.idl eventlog.idl wkssvc.idl netlogon.idl notify.idl \
+ epmapper.idl messaging.idl xattr.idl misc.idl samr.idl security.idl \
+ dssetup.idl krb5pac.idl ntsvcs.idl libnetapi.idl drsuapi.idl drsblobs.idl \
+ nbt.idl
+
+idl::
+ @IDL_FILES="$(IDL_FILES)" CPP="$(CPP)" PERL="$(PERL)" \
+ srcdir="$(srcdir)" $(srcdir)/script/build_idl.sh $(PIDL_ARGS)
+
+
+#####################################################################
+
+
+everything:: all libtalloc libsmbclient libnetapi debug2html smbfilter talloctort replacetort smbconftort modules torture \
+ $(EVERYTHING_PROGS)
+
+.SUFFIXES:
+.SUFFIXES: .c .o .lo
+
+SHOWFLAGS::
+ @echo "Using FLAGS = $(FLAGS)"
+ @echo " PICFLAG = $(PICFLAG)"
+ @echo " LIBS = $(LIBS)"
+ @echo " LDFLAGS = $(LDFLAGS)"
+ @echo " DYNEXP = $(DYNEXP)"
+ @echo " LDSHFLAGS = $(LDSHFLAGS)"
+ @echo " SHLIBEXT = @SHLIBEXT@"
+ @echo " SONAMEFLAG = @SONAMEFLAG@"
+
+MAKEDIR = || exec false; \
+ if test -d "$$dir"; then :; else \
+ echo mkdir "$$dir"; \
+ mkdir -p "$$dir" >/dev/null 2>&1 || \
+ test -d "$$dir" || \
+ mkdir "$$dir" || \
+ exec false; fi || exec false
+
+# Run a static checker.
+CHECK_CC = $(CC_CHECKER) -I. -I$(srcdir) $(FLAGS) $(PICFLAG) -c $< -o $@
+# Compile a source file.
+COMPILE_CC = $(CC) -I. -I$(srcdir) $(FLAGS) $(PICFLAG) -c $< -o $@
+# Compile a source file with the installation paths defined.
+COMPILE_CC_PATH = $(CC) -I. -I$(srcdir) $(PATH_FLAGS) $(FLAGS) $(PICFLAG) -c $< -o $@
+
+COMPILE = $(COMPILE_CC)
+
+.c.o:
+ @if (: >> $@ || : > $@) >/dev/null 2>&1; then rm -f $@; else \
+ dir=`echo $@ | sed 's,/[^/]*$$,,;s,^$$,.,'` $(MAKEDIR); fi
+ @if test -n "$(CC_CHECKER)"; then \
+ echo "Checking $*.c with '$(CC_CHECKER)'";\
+ $(CHECK_CC); \
+ fi
+ @echo Compiling $*.c
+ @$(COMPILE) && exit 0;\
+ echo "The following command failed:" 1>&2;\
+ echo "$(COMPILE_CC)" 1>&2;\
+ $(COMPILE_CC) >/dev/null 2>&1
+@BROKEN_CC@ -mv `echo $@ | sed 's%^.*/%%g'` $@
+
+PRECOMPILED_HEADER = $(builddir)/include/includes.h.gch
+
+# this adds support for precompiled headers. To use it, install a snapshot
+# of gcc-3.4 and run 'make pch' before you do the main build.
+pch::
+ rm -f $(PRECOMPILED_HEADER)
+ $(MAKE) $(PRECOMPILED_HEADER)
+
+$(PRECOMPILED_HEADER): $(srcdir)/include/includes.h
+ $(COMPILE)
+
+BINARY_PREREQS = bin/.dummy
+
+# These dependencies are only approximately correct: we want to make
+# sure Samba's paths are updated if ./configure is re-run. Really it
+# would be nice if "make prefix=/opt/samba all" also rebuilt things,
+# but since we also require "make install prefix=/opt/samba" *not* to
+# rebuild it's a bit hard.
+
+dynconfig.o: dynconfig.c Makefile
+ @echo Compiling $*.c
+ @$(COMPILE_CC_PATH) && exit 0;\
+ echo "The following command failed:" 1>&2;\
+ echo "$(COMPILE_CC_PATH)" 1>&2;\
+ $(COMPILE_CC_PATH) >/dev/null 2>&1
+
+lib/pidfile.o: lib/pidfile.c
+ @echo Compiling $*.c
+ @$(COMPILE_CC_PATH) && exit 0;\
+ echo "The following command failed:" 1>&2;\
+ echo "$(COMPILE_CC_PATH)" 1>&2;\
+ $(COMPILE_CC_PATH) >/dev/null 2>&1
+
+lib/version.o: lib/version.c include/version.h
+ @echo Compiling $*.c
+ @$(COMPILE_CC_PATH) && exit 0;\
+ echo "The following command failed:" 1>&2;\
+ echo "$(COMPILE_CC_PATH)" 1>&2;\
+ $(COMPILE_CC_PATH) >/dev/null 2>&1
+
+smbd/build_options.o: smbd/build_options.c Makefile include/config.h include/build_env.h include/proto.h
+ @echo Compiling $*.c
+ @$(COMPILE_CC_PATH) && exit 0;\
+ echo "The following command failed:" 1>&2;\
+ echo "$(COMPILE_CC_PATH)" 1>&2;\
+ $(COMPILE_CC_PATH) >/dev/null 2>&1
+
+smbd/build_options.c: include/config.h.in script/mkbuildoptions.awk
+ @echo Generating $@
+ @dir=smbd $(MAKEDIR) && $(AWK) -f $(srcdir)/script/mkbuildoptions.awk > $(builddir)/smbd/build_options.c < $(srcdir)/include/config.h.in
+
+bin/.dummy:
+ @if (: >> $@ || : > $@) >/dev/null 2>&1; then :; else \
+ dir=bin $(MAKEDIR); fi
+ @: >> $@ || : > $@ # what a fancy emoticon!
+
+bin/smbd@EXEEXT@: $(BINARY_PREREQS) $(SMBD_OBJ) @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@ @BUILD_POPT@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBD_OBJ) $(LDFLAGS) $(LDAP_LIBS) \
+ $(KRB5LIBS) $(DYNEXP) $(PRINT_LIBS) $(AUTH_LIBS) \
+ $(ACL_LIBS) $(PASSDB_LIBS) $(LIBS) $(DNSSD_LIBS) \
+ $(POPT_LIBS) @SMBD_LIBS@ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) \
+ $(WINBIND_LIBS)
+
+bin/nmbd@EXEEXT@: $(BINARY_PREREQS) $(NMBD_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(NMBD_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(POPT_LIBS) \
+ $(KRB5LIBS) $(LDAP_LIBS)
+
+bin/swat@EXEEXT@: $(BINARY_PREREQS) $(SWAT_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SWAT_OBJ) $(LDFLAGS) $(DYNEXP) $(PRINT_LIBS) \
+ $(AUTH_LIBS) $(LIBS) $(PASSDB_LIBS) $(POPT_LIBS) $(KRB5LIBS) \
+ $(LDAP_LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+bin/rpcclient@EXEEXT@: $(BINARY_PREREQS) $(RPCCLIENT_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LDFLAGS) $(PASSDB_LIBS) $(RPCCLIENT_OBJ) \
+ $(DYNEXP) $(TERMLDFLAGS) $(TERMLIBS) $(LIBS) $(POPT_LIBS) \
+ $(KRB5LIBS) $(LDAP_LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) \
+ $(WINBIND_LIBS)
+
+bin/smbclient@EXEEXT@: $(BINARY_PREREQS) $(CLIENT_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(CLIENT_OBJ) $(LDFLAGS) $(DYNEXP) \
+ $(TERMLDFLAGS) $(TERMLIBS) $(LIBS) $(POPT_LIBS) \
+ $(KRB5LIBS) $(LDAP_LIBS) $(NSCD_LIBS) $(DNSSD_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+bin/net@EXEEXT@: $(BINARY_PREREQS) $(NET_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@ @LIBNETAPI_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(NET_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) \
+ $(POPT_LIBS) $(KRB5LIBS) $(UUID_LIBS) $(LDAP_LIBS) \
+ $(PASSDB_LIBS) $(TERMLDFLAGS) $(TERMLIBS) $(NSCD_LIBS) \
+ @INIPARSERLIBS@ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS) $(LIBNETAPI_LIBS)
+
+bin/profiles@EXEEXT@: $(BINARY_PREREQS) $(PROFILES_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(PROFILES_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) \
+ $(LDAP_LIBS) $(POPT_LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/smbspool@EXEEXT@: $(BINARY_PREREQS) $(CUPS_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(CUPS_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) \
+ $(KRB5LIBS) $(LDAP_LIBS) $(POPT_LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/mount.cifs@EXEEXT@: $(BINARY_PREREQS) $(CIFS_MOUNT_OBJ) @BUILD_POPT@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(CIFS_MOUNT_OBJ) $(DYNEXP) $(LDFLAGS) $(POPT_LIBS)
+
+bin/umount.cifs@EXEEXT@: $(BINARY_PREREQS) $(CIFS_UMOUNT_OBJ) @BUILD_POPT@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(CIFS_UMOUNT_OBJ) $(DYNEXP) $(LDFLAGS) $(POPT_LIBS)
+
+bin/cifs.upcall@EXEEXT@: $(BINARY_PREREQS) $(CIFS_UPCALL_OBJ) $(LIBSMBCLIENT_OBJ1) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(CIFS_UPCALL_OBJ) $(DYNEXP) $(LDFLAGS) \
+ -lkeyutils $(LIBS) $(LIBSMBCLIENT_OBJ1) $(KRB5LIBS) \
+ $(LDAP_LIBS) $(POPT_LIBS) $(LIBTALLOC_LIBS) $(WINBIND_LIBS) \
+ $(LIBTDB_LIBS) $(NSCD_LIBS)
+
+bin/testparm@EXEEXT@: $(BINARY_PREREQS) $(TESTPARM_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(TESTPARM_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) \
+ $(LDAP_LIBS) $(POPT_LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/smbstatus@EXEEXT@: $(BINARY_PREREQS) $(STATUS_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(STATUS_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) \
+ $(LDAP_LIBS) $(POPT_LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/smbcontrol@EXEEXT@: $(BINARY_PREREQS) $(SMBCONTROL_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) -DUSING_SMBCONTROL $(FLAGS) -o $@ \
+ $(SMBCONTROL_OBJ) $(DYNEXP) $(LDFLAGS) \
+ $(LIBS) $(LDAP_LIBS) @LIBUNWIND_PTRACE@ $(POPT_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/smbtree@EXEEXT@: $(BINARY_PREREQS) $(SMBTREE_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBTREE_OBJ) $(LDFLAGS) $(DYNEXP) \
+ $(LIBS) $(POPT_LIBS) $(KRB5LIBS) $(LDAP_LIBS) $(NSCD_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+bin/smbpasswd@EXEEXT@: $(BINARY_PREREQS) $(SMBPASSWD_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBPASSWD_OBJ) $(LDFLAGS) $(PASSDB_LIBS) \
+ $(DYNEXP) $(LIBS) $(POPT_LIBS) $(KRB5LIBS) $(LDAP_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+bin/pdbedit@EXEEXT@: $(BINARY_PREREQS) $(PDBEDIT_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(PDBEDIT_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) \
+ $(POPT_LIBS) $(PASSDB_LIBS) $(LDAP_LIBS) $(LIBTALLOC_LIBS) \
+ $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+bin/smbget@EXEEXT@: $(BINARY_PREREQS) $(SMBGET_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBGET_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) \
+ $(POPT_LIBS) $(KRB5LIBS) $(LDAP_LIBS) $(NSCD_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+bin/nmblookup@EXEEXT@: $(BINARY_PREREQS) $(NMBLOOKUP_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(NMBLOOKUP_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) \
+ $(POPT_LIBS) $(LDAP_LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/smbtorture@EXEEXT@: $(BINARY_PREREQS) $(SMBTORTURE_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBTORTURE_OBJ) $(LDFLAGS) $(DYNEXP) \
+ $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) $(POPT_LIBS) $(LIBTALLOC_LIBS) \
+ $(LIBTDB_LIBS)
+
+bin/talloctort@EXEEXT@: $(BINARY_PREREQS) $(TALLOCTORT_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(TALLOCTORT_OBJ) $(LDFLAGS) \
+ $(DYNEXP) $(LIBS) $(LDAP_LIBS) $(POPT_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/replacetort@EXEEXT@: $(REPLACETORT_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) @PIE_LDFLAGS@ -o $@ $(REPLACETORT_OBJ) $(LDFLAGS) \
+ $(DYNEXP) $(LIBS) $(POPT_LIBS) $(LIBTALLOC_LIBS)
+
+bin/smbconftort@EXEEXT@: $(SMBCONFTORT_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) @PIE_LDFLAGS@ -o $@ $(SMBCONFTORT_OBJ) $(LDFLAGS) \
+ $(DYNEXP) $(LIBS) $(LDAP_LIBS) $(POPT_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/masktest@EXEEXT@: $(BINARY_PREREQS) $(MASKTEST_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(MASKTEST_OBJ) $(LDFLAGS) $(DYNEXP) \
+ $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) $(POPT_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/msgtest@EXEEXT@: $(BINARY_PREREQS) $(MSGTEST_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(MSGTEST_OBJ) $(LDFLAGS) $(DYNEXP) \
+ $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) $(POPT_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/smbcacls@EXEEXT@: $(BINARY_PREREQS) $(SMBCACLS_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBCACLS_OBJ) $(DYNEXP) $(LDFLAGS) \
+ $(LIBS) $(POPT_LIBS) $(KRB5LIBS) $(LDAP_LIBS) $(NSCD_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+bin/smbcquotas@EXEEXT@: $(BINARY_PREREQS) $(SMBCQUOTAS_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBCQUOTAS_OBJ) $(DYNEXP) $(LDFLAGS) \
+ $(LIBS) $(POPT_LIBS) $(KRB5LIBS) $(LDAP_LIBS) $(NSCD_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+bin/eventlogadm@EXEEXT@: $(BINARY_PREREQS) $(EVTLOGADM_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(EVTLOGADM_OBJ) $(DYNEXP) $(LDFLAGS) \
+ $(LIBS) $(LDAP_LIBS) $(POPT_LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/sharesec@EXEEXT@: $(BINARY_PREREQS) $(SHARESEC_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SHARESEC_OBJ) $(DYNEXP) $(LDFLAGS) \
+ $(LIBS) $(LDAP_LIBS) $(POPT_LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/locktest@EXEEXT@: $(BINARY_PREREQS) $(LOCKTEST_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LOCKTEST_OBJ) $(LDFLAGS) $(DYNEXP) \
+ $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) $(POPT_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/nsstest@EXEEXT@: $(BINARY_PREREQS) $(NSSTEST_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(NSSTEST_OBJ) $(LDFLAGS) $(DYNEXP) \
+ $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) $(POPT_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/pdbtest@EXEEXT@: $(BINARY_PREREQS) $(PDBTEST_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(PDBTEST_OBJ) $(LDFLAGS) $(DYNEXP) \
+ $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) $(PASSDB_LIBS) \
+ $(POPT_LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+bin/vfstest@EXEEXT@: $(BINARY_PREREQS) $(VFSTEST_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(VFSTEST_OBJ) $(LDFLAGS) $(TERMLDFLAGS) \
+ $(TERMLIBS) $(DYNEXP) $(PRINT_LIBS) $(AUTH_LIBS) \
+ $(ACL_LIBS) $(LIBS) $(POPT_LIBS) $(KRB5LIBS) $(LDAP_LIBS) \
+ @SMBD_LIBS@ $(NSCD_LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) \
+ $(WINBIND_LIBS)
+
+bin/smbiconv@EXEEXT@: $(BINARY_PREREQS) $(SMBICONV_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBICONV_OBJ) $(LDFLAGS) $(TERMLDFLAGS) \
+ $(TERMLIBS) $(DYNEXP) $(LIBS) $(LDAP_LIBS) $(POPT_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/log2pcap@EXEEXT@: $(BINARY_PREREQS) $(LOG2PCAP_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LOG2PCAP_OBJ) $(LDFLAGS) $(DYNEXP) \
+ $(POPT_LIBS) $(LIBS) $(LIBTALLOC_LIBS)
+
+bin/locktest2@EXEEXT@: $(BINARY_PREREQS) $(LOCKTEST2_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LOCKTEST2_OBJ) $(LDFLAGS) $(DYNEXP) \
+ $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) $(POPT_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/ndrdump@EXEEXT@: $(BINARY_PREREQS) $(NDRDUMP_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(NDRDUMP_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) \
+ $(POPT_LIBS) $(LDAP_LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/debug2html@EXEEXT@: $(BINARY_PREREQS) $(DEBUG2HTML_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(DEBUG2HTML_OBJ) $(LDFLAGS) $(DYNEXP) \
+ $(LIBS) $(LIBTALLOC_LIBS)
+
+bin/smbfilter@EXEEXT@: $(BINARY_PREREQS) $(SMBFILTER_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBFILTER_OBJ) $(LDFLAGS) $(LIBS) \
+ $(KRB5LIBS) $(LDAP_LIBS) $(POPT_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/ldbedit: $(BINARY_PREREQS) $(LDBEDIT_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LDBEDIT_OBJ) $(DYNEXP) $(LDFLAGS) \
+ $(LIBS) $(POPT_LIBS) $(LDAP_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+bin/ldbsearch: $(BINARY_PREREQS) $(LDBSEARCH_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LDBSEARCH_OBJ) $(DYNEXP) $(LDFLAGS) \
+ $(LIBS) $(POPT_LIBS) $(LDAP_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+bin/ldbadd: $(BINARY_PREREQS) $(LDBADD_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LDBADD_OBJ) $(DYNEXP) $(LDFLAGS) \
+ $(LIBS) $(POPT_LIBS) $(LDAP_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+bin/ldbmodify: $(BINARY_PREREQS) $(LDBMODIFY_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LDBMODIFY_OBJ) $(DYNEXP) $(LDFLAGS) \
+ $(LIBS) $(POPT_LIBS) $(LDAP_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+bin/ldbdel: $(BINARY_PREREQS) $(LDBDEL_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LDBDEL_OBJ) $(DYNEXP) $(LDFLAGS) \
+ $(LIBS) $(POPT_LIBS) $(LDAP_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+
+#####################################################################
+#
+# libraries
+#
+#####################################################################
+
+MKSYMS_SH = $(srcdir)/script/mksyms.sh
+
+
+#-------------------------------------------------------------------
+#
+# libtalloc
+#
+#-------------------------------------------------------------------
+
+
+LIBTALLOC_OBJ0 = @LIBTALLOC_OBJ0@
+LIBTALLOC_OBJ = $(LIBTALLOC_OBJ0) $(LIBREPLACE_OBJ)
+
+LIBTALLOC_SHARED_TARGET=@LIBTALLOC_SHARED_TARGET@
+LIBTALLOC_SOVER=@LIBTALLOC_SOVER@
+LIBTALLOC_SHARED_TARGET_SONAME=$(LIBTALLOC_SHARED_TARGET).$(LIBTALLOC_SOVER)
+LIBTALLOC_STATIC_TARGET=@LIBTALLOC_STATIC_TARGET@
+LIBTALLOC=$(LIBTALLOC_STATIC_TARGET) @LIBTALLOC_SHARED@
+LIBTALLOC_SYMS=$(srcdir)/exports/libtalloc.@SYMSEXT@
+LIBTALLOC_HEADERS=$(srcdir)/@tallocdir@/talloc.h
+
+$(LIBTALLOC_SYMS): $(LIBTALLOC_HEADERS)
+ @$(MKSYMS_SH) $(AWK) $@ $(LIBTALLOC_HEADERS)
+
+$(LIBTALLOC_SHARED_TARGET_SONAME): $(BINARY_PREREQS) $(LIBTALLOC_OBJ) $(LIBTALLOC_SYMS)
+ @echo Linking shared library $@
+ @$(SHLD_DSO) $(LIBTALLOC_OBJ) @SONAMEFLAG@`basename $@`
+
+$(LIBTALLOC_SHARED_TARGET): $(LIBTALLOC_SHARED_TARGET_SONAME)
+ @rm -f $@
+ @ln -s -f `basename $(LIBTALLOC_SHARED_TARGET_SONAME)` $@
+
+$(LIBTALLOC_STATIC_TARGET): $(BINARY_PREREQS) $(LIBTALLOC_OBJ0)
+ @echo Linking non-shared library $@
+ @-$(AR) -rc $@ $(LIBTALLOC_OBJ0)
+
+libtalloc: $(LIBTALLOC)
+
+cleanlibtalloc::
+ -rm -f \
+ $(LIBTALLOC_SYMS) \
+ $(LIBTALLOC_STATIC_TARGET) \
+ $(LIBTALLOC_SHARED_TARGET) \
+ $(LIBTALLOC_SHARED_TARGET_SONAME)
+
+installlibtalloc:: installdirs libtalloc
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(LIBDIR)
+ -$(INSTALLLIBCMD_SH) $(LIBTALLOC_SHARED_TARGET_SONAME) $(DESTDIR)$(LIBDIR)
+ @rm -f $(DESTDIR)$(LIBDIR)/`basename $(LIBTALLOC_SHARED_TARGET)`
+ -if test -e $(LIBTALLOC_SHARED_TARGET_SONAME) ; then \
+ ln -s -f `basename $(LIBTALLOC_SHARED_TARGET_SONAME)` \
+ $(DESTDIR)$(LIBDIR)/`basename $(LIBTALLOC_SHARED_TARGET)` ; \
+ fi
+ -$(INSTALLLIBCMD_A) $(LIBTALLOC_STATIC_TARGET) $(DESTDIR)$(LIBDIR)
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) ${prefix}/include
+ -$(INSTALLCMD) -m $(INSTALLPERMS_DATA) $(LIBTALLOC_HEADERS) $(DESTDIR)${prefix}/include
+
+uninstalllibtalloc::
+ -rm -f $(DESTDIR)$(LIBDIR)/`basename $(LIBTALLOC_SHARED_TARGET)`
+ -$(UNINSTALLLIBCMD_SH) $(DESTDIR)$(LIBDIR)/`basename $(LIBTALLOC_SHARED_TARGET_SONAME)`
+ -$(UNINSTALLLIBCMD_A) $(DESTDIR)$(LIBDIR)/`basename $(LIBTALLOC_STATIC_TARGET)`
+ -rm -f $(DESTDIR)${prefix}/include/talloc.h
+
+libs:: libtalloc
+installlibs:: @INSTALL_LIBTALLOC@
+uninstalllibs:: @UNINSTALL_LIBTALLOC@
+cleanlibs:: cleanlibtalloc
+shlibs test_shlibs: @LIBTALLOC_SHARED@
+
+#-------------------------------------------------------------------
+#
+# libtdb
+#
+#-------------------------------------------------------------------
+
+LIBTDB_OBJ0 = @LIBTDB_OBJ0@
+LIBTDB_OBJ = $(LIBTDB_OBJ0) $(LIBREPLACE_OBJ)
+
+LIBTDB_SHARED_TARGET=@LIBTDB_SHARED_TARGET@
+LIBTDB_SOVER=@LIBTDB_SOVER@
+LIBTDB_SHARED_TARGET_SONAME=$(LIBTDB_SHARED_TARGET).$(LIBTDB_SOVER)
+LIBTDB_STATIC_TARGET=@LIBTDB_STATIC_TARGET@
+LIBTDB=$(LIBTDB_STATIC_TARGET) @LIBTDB_SHARED@
+LIBTDB_SYMS=$(srcdir)/exports/libtdb.@SYMSEXT@
+LIBTDB_HEADERS=$(srcdir)/@tdbdir@/include/tdb.h
+
+$(LIBTDB_SYMS): $(LIBTDB_HEADERS)
+ @$(MKSYMS_SH) $(AWK) $@ $(LIBTDB_HEADERS)
+
+$(LIBTDB_SHARED_TARGET_SONAME): $(BINARY_PREREQS) $(LIBTDB_OBJ) $(LIBTDB_SYMS)
+ @echo Linking shared library $@
+ @$(SHLD_DSO) $(LIBTDB_OBJ) \
+ @SONAMEFLAG@`basename $@`
+
+$(LIBTDB_SHARED_TARGET): $(LIBTDB_SHARED_TARGET_SONAME)
+ @rm -f $@
+ @ln -s -f `basename $(LIBTDB_SHARED_TARGET_SONAME)` $@
+
+$(LIBTDB_STATIC_TARGET): $(BINARY_PREREQS) $(LIBTDB_OBJ0)
+ @echo Linking non-shared library $@
+ @-$(AR) -rc $@ $(LIBTDB_OBJ0)
+
+libtdb: $(LIBTDB)
+
+cleanlibtdb::
+ -rm -f \
+ $(LIBTDB_SYMS) \
+ $(LIBTDB_STATIC_TARGET) \
+ $(LIBTDB_SHARED_TARGET) \
+ $(LIBTDB_SHARED_TARGET_SONAME)
+
+
+installlibtdb:: installdirs libtdb
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(LIBDIR)
+ -$(INSTALLLIBCMD_SH) $(LIBTDB_SHARED_TARGET_SONAME) $(DESTDIR)$(LIBDIR)
+ @rm -f $(DESTDIR)$(LIBDIR)/`basename $(LIBTDB_SHARED_TARGET)`
+ -if test -e $(LIBTDB_SHARED_TARGET_SONAME) ; then \
+ ln -s -f `basename $(LIBTDB_SHARED_TARGET_SONAME)` \
+ $(DESTDIR)$(LIBDIR)/`basename $(LIBTDB_SHARED_TARGET)` ; \
+ fi
+ -$(INSTALLLIBCMD_A) $(LIBTDB_STATIC_TARGET) $(DESTDIR)$(LIBDIR)
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) ${prefix}/include
+ -$(INSTALLCMD) -m $(INSTALLPERMS_DATA) $(LIBTDB_HEADERS) $(DESTDIR)${prefix}/include
+
+uninstalllibtdb::
+ -rm -f $(DESTDIR)$(LIBDIR)/`basename $(LIBTDB_SHARED_TARGET)`
+ -$(UNINSTALLLIBCMD_SH) $(DESTDIR)$(LIBDIR)/`basename $(LIBTDB_SHARED_TARGET_SONAME)`
+ -$(UNINSTALLLIBCMD_A) $(DESTDIR)$(LIBDIR)/`basename $(LIBTDB_STATIC_TARGET)`
+ -rm -f $(DESTDIR)${prefix}/include/tdb.h
+
+libs:: libtdb
+installlibs:: @INSTALL_LIBTDB@
+uninstalllibs:: @UNINSTALL_LIBTDB@
+cleanlibs:: cleanlibtdb
+shlibs test_shlibs: @LIBTDB_SHARED@
+
+#-------------------------------------------------------------------
+#
+# libwbclient
+#
+#-------------------------------------------------------------------
+
+LIBWBCLIENT_OBJ0 = nsswitch/libwbclient/wbclient.o \
+ nsswitch/libwbclient/wbc_util.o \
+ nsswitch/libwbclient/wbc_pwd.o \
+ nsswitch/libwbclient/wbc_idmap.o \
+ nsswitch/libwbclient/wbc_sid.o \
+ nsswitch/libwbclient/wbc_pam.o
+LIBWBCLIENT_OBJ = $(LIBWBCLIENT_OBJ0) \
+ $(WBCOMMON_OBJ) \
+ @LIBTALLOC_STATIC@ $(LIBREPLACE_OBJ)
+
+LIBWBCLIENT_SHARED_TARGET=@LIBWBCLIENT_SHARED_TARGET@
+LIBWBCLIENT_SOVER=@LIBWBCLIENT_SOVER@
+LIBWBCLIENT_SHARED_TARGET_SONAME=$(LIBWBCLIENT_SHARED_TARGET).$(LIBWBCLIENT_SOVER)
+LIBWBCLIENT_STATIC_TARGET=@LIBWBCLIENT_STATIC_TARGET@
+LIBWBCLIENT=@LIBWBCLIENT_STATIC@ @LIBWBCLIENT_SHARED@
+LIBWBCLIENT_SYMS=$(srcdir)/exports/libwbclient.@SYMSEXT@
+LIBWBCLIENT_HEADERS=$(srcdir)/nsswitch/libwbclient/wbclient.h
+
+$(LIBWBCLIENT_SYMS): $(LIBWBCLIENT_HEADERS)
+ @$(MKSYMS_SH) $(AWK) $@ $(LIBWBCLIENT_HEADERS)
+
+$(LIBWBCLIENT_SHARED_TARGET_SONAME): $(BINARY_PREREQS) $(LIBWBCLIENT_OBJ) $(LIBWBCLIENT_SYMS) @LIBTALLOC_SHARED@
+ @echo Linking shared library $@
+ @$(SHLD_DSO) $(LIBTALLOC_LIBS) $(LIBWBCLIENT_OBJ) \
+ @SONAMEFLAG@`basename $@`
+
+$(LIBWBCLIENT_SHARED_TARGET): $(LIBWBCLIENT_SHARED_TARGET_SONAME)
+ @rm -f $@
+ @ln -s -f `basename $(LIBWBCLIENT_SHARED_TARGET_SONAME)` $@
+
+$(LIBWBCLIENT_STATIC_TARGET): $(BINARY_PREREQS) $(LIBWBCLIENT_OBJ0) $(WBCOMMON_OBJ)
+ @echo Linking non-shared library $@
+ @-$(AR) -rc $@ $(LIBWBCLIENT_OBJ0) $(WBCOMMON_OBJ)
+
+libwbclient: $(LIBWBCLIENT)
+
+cleanlibwbclient::
+ -rm -f \
+ $(LIBWBCLIENT_SYMS) \
+ $(LIBWBCLIENT_STATIC_TARGET) \
+ $(LIBWBCLIENT_SHARED_TARGET) \
+ $(LIBWBCLIENT_SHARED_TARGET_SONAME)
+
+installlibwbclient:: installdirs libwbclient
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(LIBDIR)
+ -$(INSTALLLIBCMD_SH) $(LIBWBCLIENT_SHARED_TARGET_SONAME) $(DESTDIR)$(LIBDIR)
+ @rm -f $(DESTDIR)$(LIBDIR)/`basename $(LIBWBCLIENT_SHARED_TARGET)`
+ -if test -e $(LIBWBCLIENT_SHARED_TARGET_SONAME) ; then \
+ ln -s -f `basename $(LIBWBCLIENT_SHARED_TARGET_SONAME)` \
+ $(DESTDIR)$(LIBDIR)/`basename $(LIBWBCLIENT_SHARED_TARGET)` ; \
+ fi
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) ${prefix}/include
+ -$(INSTALLCMD) -m $(INSTALLPERMS_DATA) $(LIBWBCLIENT_HEADERS) $(DESTDIR)${prefix}/include
+
+uninstalllibwbclient::
+ -rm -f $(DESTDIR)$(LIBDIR)/`basename $(LIBWBCLIENT_SHARED_TARGET)`
+ -$(UNINSTALLLIBCMD_SH) $(DESTDIR)$(LIBDIR)/`basename $(LIBWBCLIENT_SHARED_TARGET_SONAME)`
+ -rm -f $(DESTDIR)${prefix}/include/wbclient.h
+
+libs:: libwbclient
+installlibs:: @INSTALL_LIBWBCLIENT@
+uninstalllibs:: uninstalllibwbclient
+cleanlibs:: cleanlibwbclient
+shlibs test_shlibs: @LIBWBCLIENT_SHARED@
+
+
+#-------------------------------------------------------------------
+#
+# libaddns
+#
+#-------------------------------------------------------------------
+
+
+LIBADDNS_SHARED_TARGET=@LIBADDNS_SHARED_TARGET@
+LIBADDNS_SOVER=@LIBADDNS_SOVER@
+LIBADDNS_SHARED_TARGET_SONAME=$(LIBADDNS_SHARED_TARGET).$(LIBADDNS_SOVER)
+LIBADDNS_STATIC_TARGET=@LIBADDNS_STATIC_TARGET@
+LIBADDNS=$(LIBADDNS_STATIC_TARGET) @LIBADDNS_SHARED@
+#LIBADDNS_SYMS=$(srcdir)/exports/libaddns.@SYMSEXT@
+LIBADDNS_HEADERS=$(srcdir)/libaddns/addns.h
+
+$(LIBADDNS_SHARED_TARGET_SONAME): $(BINARY_PREREQS) $(LIBADDNS_OBJ) @LIBTALLOC_SHARED@
+ @echo Linking shared library $@
+ @$(SHLD_DSO) $(LIBADDNS_OBJ) $(LIBS) \
+ $(KRB5LIBS) $(UUID_LIBS) $(LIBTALLOC_LIBS) \
+ @SONAMEFLAG@`basename $@`
+
+$(LIBADDNS_SHARED_TARGET): $(LIBADDNS_SHARED_TARGET_SONAME)
+ @rm -f $@
+ @ln -s -f `basename $(LIBADDNS_SHARED_TARGET_SONAME)` $@
+
+$(LIBADDNS_STATIC_TARGET): $(BINARY_PREREQS) $(LIBADDNS_OBJ0)
+ @echo Linking non-shared library $@
+ @-$(AR) -rc $@ $(LIBADDNS_OBJ0)
+
+libaddns: $(LIBADDNS)
+
+cleanlibaddns::
+ -rm -f \
+ $(LIBADDNS_SHARED_TARGET) \
+ $(LIBADDNS_SHARED_TARGET_SONAME) \
+ $(LIBADDNS_STATIC_TARGET)
+
+installlibaddns:: installdirs libaddns
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(LIBDIR)
+ -$(INSTALLLIBCMD_SH) $(LIBADDNS_SHARED_TARGET_SONAME) $(DESTDIR)$(LIBDIR)
+ @rm -f $(DESTDIR)$(LIBDIR)/`basename $(LIBADDNS_SHARED_TARGET)`
+ -if test -e $(LIBADDNS_SHARED_TARGET_SONAME) ; then \
+ ln -s -f `basename $(LIBADDNS_SHARED_TARGET_SONAME)` \
+ $(DESTDIR)$(LIBDIR)/`basename $(LIBADDNS_SHARED_TARGET)` ; \
+ fi
+ -$(INSTALLLIBCMD_A) $(LIBADDNS_STATIC_TARGET) $(DESTDIR)$(LIBDIR)
+
+uninstalllibaddns::
+ -$(UNINSTALLLIBCMD_SH) $(DESTDIR)$(LIBDIR)/`basename $(LIBADDNS_SHARED_TARGET_SONAME)`
+ -rm -f $(DESTDIR)$(LIBDIR)/`basename $(LIBADDNS_SHARED_TARGET)`
+ -$(UNINSTALLLIBCMD_A) $(DESTDIR)$(LIBDIR)/`basename $(LIBADDNS_STATIC_TARGET)`
+
+libs:: libaddns
+installlibs:: @INSTALL_LIBADDNS@
+uninstalllibs:: @UNINSTALL_LIBADDNS@
+cleanlibs:: cleanlibaddns
+shlibs test_shlibs: @LIBADDNS_SHARED@
+
+#-------------------------------------------------------------------
+#
+# libnetapi
+#
+#-------------------------------------------------------------------
+
+LIBNETAPI_OBJ0 = lib/netapi/netapi.o \
+ lib/netapi/cm.o \
+ librpc/gen_ndr/ndr_libnetapi.o \
+ lib/netapi/libnetapi.o \
+ lib/netapi/joindomain.o \
+ lib/netapi/serverinfo.o \
+ lib/netapi/getdc.o \
+ lib/netapi/user.o \
+ lib/netapi/group.o \
+ lib/netapi/localgroup.o \
+ lib/netapi/samr.o \
+ lib/netapi/sid.o \
+ lib/netapi/share.o \
+ lib/netapi/file.o
+
+LIBNETAPI_OBJ = $(LIBNETAPI_OBJ0) $(LIBNET_OBJ) \
+ $(LIBSMBCONF_OBJ) \
+ $(REG_SMBCONF_OBJ) \
+ $(PARAM_WITHOUT_REG_OBJ) $(LIB_NONSMBD_OBJ) \
+ $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
+ $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(RPC_PARSE_OBJ) \
+ $(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ $(SMBLDAP_OBJ) $(GROUPDB_OBJ) $(LDB_OBJ) \
+ $(DCUTIL_OBJ) $(LIBADS_OBJ) $(PRIVILEGES_BASIC_OBJ) \
+ auth/token_util.o
+
+LIBNETAPI_SHARED_TARGET=@LIBNETAPI_SHARED_TARGET@
+LIBNETAPI_SOVER=@LIBNETAPI_SOVER@
+LIBNETAPI_SHARED_TARGET_SONAME=$(LIBNETAPI_SHARED_TARGET).$(LIBNETAPI_SOVER)
+LIBNETAPI_STATIC_TARGET=@LIBNETAPI_STATIC_TARGET@
+LIBNETAPI=$(LIBNETAPI_STATIC_TARGET) @LIBNETAPI_SHARED@
+LIBNETAPI_SYMS=$(srcdir)/exports/libnetapi.@SYMSEXT@
+LIBNETAPI_HEADERS=$(srcdir)/lib/netapi/netapi.h
+
+$(LIBNETAPI_SYMS): $(LIBNETAPI_HEADERS)
+ @$(MKSYMS_SH) $(AWK) $@ $(LIBNETAPI_HEADERS)
+
+$(LIBNETAPI_SHARED_TARGET_SONAME): $(BINARY_PREREQS) $(LIBNETAPI_OBJ) $(LIBNETAPI_SYMS) @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking shared library $@
+ @$(SHLD_DSO) $(LIBNETAPI_OBJ) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS) $(LIBS) \
+ $(LDAP_LIBS) $(KRB5LIBS) $(NSCD_LIBS) \
+ @SONAMEFLAG@`basename $@`
+
+$(LIBNETAPI_SHARED_TARGET): $(LIBNETAPI_SHARED_TARGET_SONAME)
+ @rm -f $@
+ @ln -s -f `basename $(LIBNETAPI_SHARED_TARGET_SONAME)` $@
+
+$(LIBNETAPI_STATIC_TARGET): $(BINARY_PREREQS) $(LIBNETAPI_OBJ0)
+ @echo Linking non-shared library $@
+ @-$(AR) -rc $@ $(LIBNETAPI_OBJ0)
+
+libnetapi: $(LIBNETAPI)
+
+cleanlibnetapi::
+ -rm -f \
+ $(LIBNETAPI_SYMS) \
+ $(LIBNETAPI_STATIC_TARGET) \
+ $(LIBNETAPI_SHARED_TARGET) \
+ $(LIBNETAPI_SHARED_TARGET_SONAME)
+
+installlibnetapi:: installdirs libnetapi
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(LIBDIR)
+ -$(INSTALLLIBCMD_SH) $(LIBNETAPI_SHARED_TARGET_SONAME) $(DESTDIR)$(LIBDIR)
+ @rm -f $(DESTDIR)$(LIBDIR)/`basename $(LIBNETAPI_SHARED_TARGET)`
+ -if test -e $(LIBNETAPI_SHARED_TARGET_SONAME) ; then \
+ ln -s -f `basename $(LIBNETAPI_SHARED_TARGET_SONAME)` \
+ $(DESTDIR)$(LIBDIR)/`basename $(LIBNETAPI_SHARED_TARGET)` ; \
+ fi
+ -$(INSTALLLIBCMD_A) $(LIBNETAPI_STATIC_TARGET) $(DESTDIR)$(LIBDIR)
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) ${prefix}/include
+ -$(INSTALLCMD) -m $(INSTALLPERMS_DATA) $(srcdir)/lib/netapi/netapi.h $(DESTDIR)${prefix}/include
+
+uninstalllibnetapi::
+ -rm -f $(DESTDIR)$(LIBDIR)/`basename $(LIBNETAPI_SHARED_TARGET)`
+ -$(UNINSTALLLIBCMD_SH) $(DESTDIR)$(LIBDIR)/`basename $(LIBNETAPI_SHARED_TARGET_SONAME)`
+ -$(UNINSTALLLIBCMD_A) $(DESTDIR)$(LIBDIR)/`basename $(LIBNETAPI_STATIC_TARGET)`
+ -rm -f $(DESTDIR)${prefix}/include/netapi.h
+
+libs:: libnetapi
+installlibs:: @INSTALL_LIBNETAPI@
+uninstalllibs:: @UNINSTALL_LIBNETAPI@
+cleanlibs:: cleanlibnetapi
+shlibs test_shlibs: @LIBNETAPI_SHARED@
+
+#-------------------------------------------------------------------
+#
+# libsmbclient
+#
+#-------------------------------------------------------------------
+
+LIBSMBCLIENT_SHARED_TARGET=@LIBSMBCLIENT_SHARED_TARGET@
+LIBSMBCLIENT_SOVER=@LIBSMBCLIENT_SOVER@
+LIBSMBCLIENT_SHARED_TARGET_SONAME=$(LIBSMBCLIENT_SHARED_TARGET).$(LIBSMBCLIENT_SOVER)
+LIBSMBCLIENT_STATIC_TARGET=@LIBSMBCLIENT_STATIC_TARGET@
+LIBSMBCLIENT=$(LIBSMBCLIENT_STATIC_TARGET) @LIBSMBCLIENT_SHARED@
+LIBSMBCLIENT_SYMS=$(srcdir)/exports/libsmbclient.@SYMSEXT@
+LIBSMBCLIENT_HEADERS=$(srcdir)/include/libsmbclient.h
+
+$(LIBSMBCLIENT_SYMS): $(LIBSMBCLIENT_HEADERS)
+ @$(MKSYMS_SH) $(AWK) $@ $(LIBSMBCLIENT_HEADERS)
+
+$(LIBSMBCLIENT_SHARED_TARGET_SONAME): $(BINARY_PREREQS) $(LIBSMBCLIENT_OBJ) $(LIBSMBCLIENT_SYMS) @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking shared library $@
+ @$(SHLD_DSO) $(LIBSMBCLIENT_OBJ) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS) $(LIBS) \
+ $(KRB5LIBS) $(LDAP_LIBS) $(NSCD_LIBS) \
+ @SONAMEFLAG@`basename $@`
+
+$(LIBSMBCLIENT_SHARED_TARGET): $(LIBSMBCLIENT_SHARED_TARGET_SONAME)
+ @rm -f $@
+ @ln -s `basename $(LIBSMBCLIENT_SHARED_TARGET_SONAME)` $@
+
+$(LIBSMBCLIENT_STATIC_TARGET): $(BINARY_PREREQS) $(LIBSMBCLIENT_OBJ1)
+ @echo Linking non-shared library $@
+ @-$(AR) -rc $@ $(LIBSMBCLIENT_OBJ1)
+
+libsmbclient: $(LIBSMBCLIENT)
+
+cleanlibsmbclient::
+ -rm -f \
+ $(LIBSMBCLIENT_SHARED_TARGET) \
+ $(LIBSMBCLIENT_SHARED_TARGET_SONAME) \
+ $(LIBSMBCLIENT_STATIC_TARGET)
+
+installlibsmbclient:: installdirs libsmbclient
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(LIBDIR)
+ -$(INSTALLLIBCMD_SH) $(LIBSMBCLIENT_SHARED_TARGET_SONAME) $(DESTDIR)$(LIBDIR)
+ @rm -f $(DESTDIR)$(LIBDIR)/`basename $(LIBSMBCLIENT_SHARED_TARGET)`
+ -if test -e $(LIBSMBCLIENT_SHARED_TARGET_SONAME) ; then \
+ ln -s -f `basename $(LIBSMBCLIENT_SHARED_TARGET_SONAME)` \
+ $(DESTDIR)$(LIBDIR)/`basename $(LIBSMBCLIENT_SHARED_TARGET)` ; \
+ fi
+ -$(INSTALLLIBCMD_A) $(LIBSMBCLIENT_STATIC_TARGET) $(DESTDIR)$(LIBDIR)
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) ${prefix}/include
+ -$(INSTALLCMD) -m $(INSTALLPERMS_DATA) $(LIBSMBCLIENT_HEADERS) $(DESTDIR)${prefix}/include
+
+installclientlib:: installlibsmbclient
+
+uninstalllibsmbclient::
+ -rm -f $(DESTDIR)$(LIBDIR)/`basename $(LIBSMBCLIENT_SHARED_TARGET)`
+ -$(UNINSTALLLIBCMD_SH) $(DESTDIR)$(LIBDIR)/`basename $(LIBSMBCLIENT_SHARED_TARGET_SONAME)`
+ -$(UNINSTALLLIBCMD_A) $(DESTDIR)$(LIBDIR)/`basename $(LIBSMBCLIENT_STATIC_TARGET)`
+ -rm -f $(DESTDIR)${prefix}/include/libsmbclient.h
+
+uninstallclientlib:: uninstalllibsmbclient
+
+libs:: libsmbclient
+installlibs:: @INSTALL_LIBSMBCLIENT@
+uninstalllibs:: @UNINSTALL_LIBSMBCLIENT@
+cleanlibs:: cleanlibsmbclient
+shlibs test_shlibs: @LIBSMBCLIENT_SHARED@
+
+#-------------------------------------------------------------------
+#
+# libsmbsharemodes
+#
+#-------------------------------------------------------------------
+
+LIBSMBSHAREMODES_OBJ0 = libsmb/smb_share_modes.o
+
+LIBSMBSHAREMODES_OBJ = $(LIBSMBSHAREMODES_OBJ0) @LIBTDB_STATIC@
+
+LIBSMBSHAREMODES_SHARED_TARGET=@LIBSMBSHAREMODES_SHARED_TARGET@
+LIBSMBSHAREMODES_SOVER=@LIBSMBSHAREMODES_SOVER@
+LIBSMBSHAREMODES_SHARED_TARGET_SONAME=$(LIBSMBSHAREMODES_SHARED_TARGET).$(LIBSMBSHAREMODES_SOVER)
+LIBSMBSHAREMODES_STATIC_TARGET=@LIBSMBSHAREMODES_STATIC_TARGET@
+LIBSMBSHAREMODES=$(LIBSMBSHAREMODES_STATIC_TARGET) @LIBSMBSHAREMODES_SHARED@
+LIBSMBSHAREMODES_SYMS=$(srcdir)/exports/libsmbsharemodes.@SYMSEXT@
+LIBSMBSHAREMODES_HEADERS=$(srcdir)/include/smb_share_modes.h
+
+$(LIBSMBSHAREMODES_SYMS): $(LIBSMBSHAREMODES_HEADERS)
+ @$(MKSYMS_SH) $(AWK) $@ $(LIBSMBSHAREMODES_HEADERS)
+
+$(LIBSMBSHAREMODES_SHARED_TARGET_SONAME): $(BINARY_PREREQS) $(LIBSMBSHAREMODES_OBJ) $(LIBSMBSHAREMODES_SYMS) @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking shared library $@
+ @$(SHLD_DSO) $(LIBSMBSHAREMODES_OBJ) \
+ $(LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) \
+ $(KRB5LIBS) $(LDAP_LIBS) \
+ @SONAMEFLAG@`basename $@`
+
+$(LIBSMBSHAREMODES_SHARED_TARGET): $(LIBSMBSHAREMODES_SHARED_TARGET_SONAME)
+ @rm -f $@
+ @ln -s -f `basename $(LIBSMBSHAREMODES_SHARED_TARGET_SONAME)` $@
+
+$(LIBSMBSHAREMODES_STATIC_TARGET): $(BINARY_PREREQS) $(LIBSMBSHAREMODES_OBJ0)
+ @echo Linking non-shared library $@
+ @-$(AR) -rc $@ $(LIBSMBSHAREMODES_OBJ0)
+
+libsmbsharemodes: $(LIBSMBSHAREMODES)
+
+cleanlibsmbsharemodes::
+ -rm -f \
+ $(LIBSMBSHAREMODES_SHARED_TARGET) \
+ $(LIBSMBSHAREMODES_SHARED_TARGET_SONAME) \
+ $(LIBSMBSHAREMODES_STATIC_TARGET)
+
+installlibsmbsharemodes:: installdirs libsmbsharemodes
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(LIBDIR)
+ -$(INSTALLLIBCMD_SH) $(LIBSMBSHAREMODES_SHARED_TARGET_SONAME) $(DESTDIR)$(LIBDIR)
+ @rm -f $(DESTDIR)$(LIBDIR)/`basename $(LIBSMBSHAREMODES_SHARED_TARGET)`
+ -if test -e $(LIBSMBSHAREMODES_SHARED_TARGET_SONAME) ; then \
+ ln -s -f `basename $(LIBSMBSHAREMODES_SHARED_TARGET_SONAME)` \
+ $(DESTDIR)$(LIBDIR)/`basename $(LIBSMBSHAREMODES_SHARED_TARGET)` ; \
+ fi
+ -$(INSTALLLIBCMD_A) $(LIBSMBSHAREMODES_STATIC_TARGET) $(DESTDIR)$(LIBDIR)
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) ${prefix}/include
+ -$(INSTALLCMD) -m $(INSTALLPERMS_DATA) $(LIBSMBSHAREMODES_HEADERS) $(DESTDIR)${prefix}/include
+
+uninstalllibsmbsharemodes::
+ -rm -f $(DESTDIR)$(LIBDIR)/`basename $(LIBSMBSHAREMODES_SHARED_TARGET)`
+ -$(UNINSTALLLIBCMD_SH) $(DESTDIR)$(LIBDIR)/`basename $(LIBSMBSHAREMODES_SHARED_TARGET_SONAME)`
+ -$(UNINSTALLLIBCMD_A) $(DESTDIR)$(LIBDIR)/`basename $(LIBSMBSHAREMODES_STATIC_TARGET)`
+ -rm -f $(DESTDIR)${prefix}/include/smb_share_modes.h
+
+libs:: libsmbsharemodes
+installlibs:: @INSTALL_LIBSMBSHAREMODES@
+uninstalllibs:: @UNINSTALL_LIBSMBSHAREMODES@
+cleanlibs:: cleanlibsmbsharemodes
+shlibs test_shlibs: @LIBSMBSHAREMODES_SHARED@
+
+#-------------------------------------------------------------------
+#
+# libbigballofmud
+#
+#-------------------------------------------------------------------
+
+# This is probably wrong for anything other than the GNU linker.
+bin/libbigballofmud.@SHLIBEXT@: $(BINARY_PREREQS) $(LIBBIGBALLOFMUD_OBJ) @LIBTALLOC_SHARED@
+ @echo Linking shared library $@
+ @$(SHLD) $(LDSHFLAGS) -o $@ $(LIBBIGBALLOFMUD_OBJ) \
+ $(LIBS) $(LIBTALLOC_LIBS) \
+ $(PASSDB_LIBS) $(IDMAP_LIBS) $(KRB5LIBS) $(LDAP_LIBS) \
+ @SONAMEFLAG@`basename $@`.$(LIBBIGBALLOFMUD_MAJOR)
+ ln -snf libbigballofmud.so bin/libbigballofmud.so.0
+
+# It would be nice to build a static bigballofmud too, but when I try
+# I get linker errors about dl_open and similar things. I'm not sure if
+# it can be fixed or if they just can't be called from a static
+# library.
+
+
+
+#####################################################################
+#
+# shared modules
+#
+#####################################################################
+
+# Linker command to link a RPC, VFS, AUTH, CHARSET or PASSDB module.
+SHLD_MODULE = $(SHLD) $(LDSHFLAGS) $(MODULE_EXPORTS) \
+ -o $@ @SONAMEFLAG@`basename $@`
+
+bin/librpc_lsarpc.@SHLIBEXT@: $(BINARY_PREREQS) $(RPC_LSA_OBJ)
+ @echo "Linking $@"
+ @$(SHLD_MODULE) $(RPC_LSA_OBJ)
+
+bin/librpc_samr.@SHLIBEXT@: $(BINARY_PREREQS) $(RPC_SAMR_OBJ)
+ @echo "Linking $@"
+ @$(SHLD_MODULE) $(RPC_SAMR_OBJ)
+
+bin/librpc_srvsvc.@SHLIBEXT@: $(BINARY_PREREQS) $(RPC_SVC_OBJ)
+ @echo "Linking $@"
+ @$(SHLD_MODULE) $(RPC_SVC_OBJ)
+
+bin/librpc_svcctl.@SHLIBEXT@: $(BINARY_PREREQS) $(RPC_SVCCTL_OBJ)
+ @echo "Linking $@"
+ @$(SHLD_MODULE) $(RPC_SVCCTL_OBJ)
+
+bin/librpc_ntsvcs.@SHLIBEXT@: $(BINARY_PREREQS) $(RPC_NTSVCS_OBJ)
+ @echo "Linking $@"
+ @$(SHLD_MODULE) $(RPC_NTSVCS_OBJ)
+
+bin/librpc_wkssvc.@SHLIBEXT@: $(BINARY_PREREQS) $(RPC_WKS_OBJ)
+ @echo "Linking $@"
+ @$(SHLD_MODULE) $(RPC_WKS_OBJ)
+
+bin/librpc_NETLOGON.@SHLIBEXT@: $(BINARY_PREREQS) $(RPC_NETLOG_OBJ)
+ @echo "Linking $@"
+ @$(SHLD_MODULE) $(RPC_NETLOG_OBJ)
+
+bin/librpc_winreg.@SHLIBEXT@: $(BINARY_PREREQS) $(RPC_REG_OBJ)
+ @echo "Linking $@"
+ @$(SHLD_MODULE) $(RPC_REG_OBJ)
+
+bin/librpc_initshutdown.@SHLIBEXT@: $(BINARY_PREREQS) $(RPC_INITSHUTDOWN_OBJ)
+ @echo "Linking $@"
+ @$(SHLD_MODULE) $(RPC_INITSHUTDOWN_OBJ)
+
+bin/librpc_dssetup.@SHLIBEXT@: $(BINARY_PREREQS) $(RPC_DSSETUP_OBJ)
+ @echo "Linking $@"
+ @$(SHLD_MODULE) $(RPC_DSSETUP_OBJ)
+
+bin/librpc_spoolss.@SHLIBEXT@: $(BINARY_PREREQS) $(RPC_SPOOLSS_OBJ)
+ @echo "Linking $@"
+ @$(SHLD_MODULE) $(RPC_SPOOLSS_OBJ)
+
+bin/librpc_eventlog.@SHLIBEXT@: $(BINARY_PREREQS) $(RPC_EVENTLOG_OBJ)
+ @echo "Linking $@"
+ @$(SHLD_MODULE) $(RPC_EVENTLOG_OBJ)
+
+bin/librpc_netdfs.@SHLIBEXT@: $(BINARY_PREREQS) $(RPC_DFS_OBJ)
+ @echo "Linking $@"
+ @$(SHLD_MODULE) $(RPC_DFS_OBJ)
+
+bin/librpc_echo.@SHLIBEXT@: $(BINARY_PREREQS) $(RPC_ECHO_OBJ)
+ @echo "Linking $@"
+ @$(SHLD_MODULE) $(RPC_ECHO_OBJ)
+
+bin/winbindd@EXEEXT@: $(BINARY_PREREQS) $(WINBINDD_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo "Linking $@"
+ @$(CC) $(FLAGS) -o $@ $(WINBINDD_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) \
+ $(POPT_LIBS) $(KRB5LIBS) $(LDAP_LIBS) \
+ $(PASSDB_LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+bin/vlp@EXEEXT@: $(BINARY_PREREQS) $(VLP_OBJ) @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo "Linking $@"
+ @$(CC) $(FLAGS) -o $@ $(VLP_OBJ) $(LDFLAGS) $(DYNEXP) \
+ $(TERMLDFLAGS) $(TERMLIBS) $(LIBS) $(POPT_LIBS) \
+ $(KRB5LIBS) $(LDAP_LIBS) $(NSCD_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+@WINBIND_NSS@: $(BINARY_PREREQS) $(WINBIND_NSS_OBJ)
+ @echo "Linking $@"
+ @$(SHLD) $(WINBIND_NSS_LDSHFLAGS) -o $@ $(WINBIND_NSS_OBJ) \
+ $(WINBIND_NSS_EXTRA_LIBS) $(WINBIND_NSS_PTHREAD) \
+ @SONAMEFLAG@`basename $@`@NSSSONAMEVERSIONSUFFIX@
+
+@WINBIND_WINS_NSS@: $(BINARY_PREREQS) $(WINBIND_WINS_NSS_OBJ) @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo "Linking $@"
+ @$(SHLD) $(LDSHFLAGS) -o $@ $(WINBIND_WINS_NSS_OBJ) \
+ $(LDAP_LIBS) $(KRB5LIBS) $(LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) \
+ @SONAMEFLAG@`basename $@`@NSSSONAMEVERSIONSUFFIX@
+
+bin/winbind_krb5_locator.@SHLIBEXT@: $(BINARY_PREREQS) $(WINBIND_KRB5_LOCATOR_OBJ)
+ @echo "Linking $@"
+ @$(SHLD) $(LDSHFLAGS) -o $@ $(WINBIND_KRB5_LOCATOR_OBJ) \
+ @SONAMEFLAG@`basename $@`
+
+bin/pam_winbind.@SHLIBEXT@: $(BINARY_PREREQS) $(PAM_WINBIND_OBJ)
+ @echo "Linking shared library $@"
+ @$(SHLD) $(LDSHFLAGS) -o $@ $(PAM_WINBIND_OBJ) -lpam @INIPARSERLIBS@ \
+ $(PAM_WINBIND_EXTRA_LIBS) @SONAMEFLAG@`basename $@`
+
+bin/builtin.@SHLIBEXT@: $(BINARY_PREREQS) $(AUTH_BUILTIN_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(AUTH_BUILTIN_OBJ)
+
+bin/domain.@SHLIBEXT@: $(BINARY_PREREQS) $(AUTH_DOMAIN_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(AUTH_DOMAIN_OBJ)
+
+bin/script.@SHLIBEXT@: $(BINARY_PREREQS) $(AUTH_SCRIPT_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(AUTH_SCRIPT_OBJ)
+
+bin/smbserver.@SHLIBEXT@: $(BINARY_PREREQS) $(AUTH_SERVER_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(AUTH_SERVER_OBJ)
+
+bin/winbind.@SHLIBEXT@: $(BINARY_PREREQS) $(AUTH_WINBIND_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(AUTH_WINBIND_OBJ)
+
+bin/unix.@SHLIBEXT@: $(BINARY_PREREQS) $(AUTH_UNIX_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(AUTH_UNIX_OBJ)
+
+bin/sam.@SHLIBEXT@: $(BINARY_PREREQS) $(AUTH_SAM_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(AUTH_SAM_OBJ)
+
+bin/ldapsam.@SHLIBEXT@: $(BINARY_PREREQS) passdb/pdb_ldap.o passdb/pdb_nds.o
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) passdb/pdb_ldap.o passdb/pdb_nds.o $(LDAP_LIBS)
+
+bin/tdbsam.@SHLIBEXT@: $(BINARY_PREREQS) passdb/pdb_tdb.o
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) passdb/pdb_tdb.o
+
+bin/smbpasswd.@SHLIBEXT@: $(BINARY_PREREQS) passdb/pdb_smbpasswd.o
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) passdb/pdb_smbpasswd.o
+
+bin/rid.@SHLIBEXT@: $(BINARY_PREREQS) winbindd/idmap_rid.o
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) winbindd/idmap_rid.o
+
+bin/ad.@SHLIBEXT@: $(BINARY_PREREQS) winbindd/idmap_ad.o
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) winbindd/idmap_ad.o
+
+bin/tdb2.@SHLIBEXT@: $(BINARY_PREREQS) winbindd/idmap_tdb2.o
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) winbindd/idmap_tdb2.o
+
+bin/ldap.@SHLIBEXT@: $(BINARY_PREREQS) winbindd/idmap_ldap.o
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) winbindd/idmap_ldap.o
+
+bin/weird.@SHLIBEXT@: $(BINARY_PREREQS) $(DEVEL_HELP_WEIRD_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(DEVEL_HELP_WEIRD_OBJ)
+
+bin/CP850.@SHLIBEXT@: $(BINARY_PREREQS) $(CP850_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(CP850_OBJ)
+
+bin/CP437.@SHLIBEXT@: $(BINARY_PREREQS) $(CP437_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(CP437_OBJ)
+
+bin/macosxfs.@SHLIBEXT@: $(BINARY_PREREQS) $(CHARSET_MACOSXFS_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(CHARSET_MACOSXFS_OBJ) -framework CoreFoundation
+
+# NOTE, there is no build rule for a dynamic default VFS module because
+# this one MUST MUST MUST be built statically.
+
+bin/audit.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_AUDIT_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_AUDIT_OBJ)
+
+bin/extd_audit.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_EXTD_AUDIT_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_EXTD_AUDIT_OBJ)
+
+bin/full_audit.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_FULL_AUDIT_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_FULL_AUDIT_OBJ)
+
+bin/recycle.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_RECYCLE_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_RECYCLE_OBJ)
+
+bin/netatalk.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_NETATALK_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_NETATALK_OBJ)
+
+bin/fake_perms.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_FAKE_PERMS_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_FAKE_PERMS_OBJ)
+
+bin/default_quota.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_DEFAULT_QUOTA_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_DEFAULT_QUOTA_OBJ)
+
+bin/readonly.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_READONLY_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_READONLY_OBJ)
+
+bin/shadow_copy.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_SHADOW_COPY_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_SHADOW_COPY_OBJ)
+
+bin/shadow_copy2.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_SHADOW_COPY2_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_SHADOW_COPY2_OBJ)
+
+bin/syncops.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_SYNCOPS_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_SYNCOPS_OBJ)
+
+bin/cap.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_CAP_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_CAP_OBJ)
+
+bin/expand_msdfs.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_EXPAND_MSDFS_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_EXPAND_MSDFS_OBJ)
+
+bin/afsacl.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_AFSACL_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_AFSACL_OBJ)
+
+bin/xattr_tdb.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_XATTR_TDB_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_XATTR_TDB_OBJ)
+
+bin/posixacl.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_POSIXACL_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_POSIXACL_OBJ)
+
+bin/aixacl.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_AIXACL_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_AIXACL_OBJ)
+
+bin/aixacl2.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_AIXACL2_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_AIXACL2_OBJ)
+
+bin/solarisacl.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_SOLARISACL_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_SOLARISACL_OBJ)
+
+bin/zfsacl.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_ZFSACL_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_ZFSACL_OBJ)
+
+bin/irixacl.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_IRIXACL_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_IRIXACL_OBJ)
+
+bin/hpuxacl.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_HPUXACL_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_HPUXACL_OBJ)
+
+bin/tru64acl.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_TRU64ACL_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_TRU64ACL_OBJ)
+
+bin/catia.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_CATIA_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_CATIA_OBJ)
+
+bin/streams_xattr.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_STREAMS_XATTR_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_STREAMS_XATTR_OBJ)
+
+bin/streams_depot.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_STREAMS_DEPOT_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_STREAMS_DEPOT_OBJ)
+
+bin/cacheprime.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_CACHEPRIME_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_CACHEPRIME_OBJ)
+
+bin/prealloc.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_PREALLOC_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_PREALLOC_OBJ)
+
+bin/commit.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_COMMIT_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_COMMIT_OBJ)
+
+bin/gpfs.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_GPFS_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_GPFS_OBJ)
+
+bin/notify_fam.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_NOTIFY_FAM_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_NOTIFY_FAM_OBJ) @SMB_FAM_LIBS@
+
+bin/readahead.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_READAHEAD_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_READAHEAD_OBJ)
+
+bin/tsmsm.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_TSMSM_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_TSMSM_OBJ)
+
+bin/fileid.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_FILEID_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_FILEID_OBJ)
+
+bin/aio_fork.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_AIO_FORK_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_AIO_FORK_OBJ)
+
+bin/registry.@SHLIBEXT@: $(BINARY_PREREQS) libgpo/gpext/registry.o
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) libgpo/gpext/registry.o
+
+bin/scripts.@SHLIBEXT@: $(BINARY_PREREQS) libgpo/gpext/scripts.o
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) libgpo/gpext/scripts.o
+
+#########################################################
+## IdMap NSS plugins
+
+## None here right now
+#########################################################
+
+bin/wbinfo@EXEEXT@: $(BINARY_PREREQS) $(WBINFO_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LDFLAGS) $(WBINFO_OBJ) $(DYNEXP) $(LIBS) \
+ $(LDAP_LIBS) $(POPT_LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) \
+ $(WINBIND_LIBS)
+
+bin/ntlm_auth@EXEEXT@: $(BINARY_PREREQS) $(NTLM_AUTH_OBJ) $(PARAM_OBJ) \
+ $(LIB_NONSMBD_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LDFLAGS) $(DYNEXP) $(NTLM_AUTH_OBJ) \
+ $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(LIBS) \
+ $(POPT_LIBS) $(KRB5LIBS) $(LDAP_LIBS) $(NSCD_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+bin/pam_smbpass.@SHLIBEXT@: $(BINARY_PREREQS) $(PAM_SMBPASS_OBJ) @LIBTALLOC_SHARED@ @LIBWBCLIENT_SHARED@ @LIBTDB_SHARED@
+ @echo "Linking shared library $@"
+ @$(SHLD) $(LDSHFLAGS) -o $@ $(PAM_SMBPASS_OBJ) -lpam $(DYNEXP) \
+ $(LIBS) $(LDAP_LIBS) $(KRB5LIBS) $(NSCD_LIBS) \
+ $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
+
+bin/tdbbackup@EXEEXT@: $(BINARY_PREREQS) $(TDBBACKUP_OBJ) @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LDFLAGS) $(TDBBACKUP_OBJ) $(DYNEXP) \
+ $(LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/tdbtool@EXEEXT@: $(BINARY_PREREQS) $(TDBTOOL_OBJ) @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LDFLAGS) $(TDBTOOL_OBJ) $(DYNEXP) \
+ $(LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/tdbdump@EXEEXT@: $(BINARY_PREREQS) $(TDBDUMP_OBJ) @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LDFLAGS) $(TDBDUMP_OBJ) $(DYNEXP) \
+ $(LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/tdbtorture@EXEEXT@: $(BINARY_PREREQS) $(TDBTORTURE_OBJ) @LIBTALLOC_SHARED@ @LIBTDB_SHARED@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LDFLAGS) $(TDBTORTURE_OBJ) $(DYNEXP) \
+ $(LIBS) $(LIBTALLOC_LIBS) $(LIBTDB_LIBS)
+
+bin/t_strcmp@EXEEXT@: $(BINARY_PREREQS) @LIBTALLOC_SHARED@ bin/libbigballofmud.@SHLIBEXT@ torture/t_strcmp.o
+ $(CC) $(FLAGS) -o $@ $(DYNEXP) $(LIBS) $(LIBTALLOC_LIBS) \
+ torture/t_strcmp.o -L ./bin -lbigballofmud
+
+bin/t_strstr@EXEEXT@: $(BINARY_PREREQS) @LIBTALLOC_SHARED@ bin/libbigballofmud.@SHLIBEXT@ torture/t_strstr.o
+ $(CC) $(FLAGS) -o $@ $(DYNEXP) $(LIBS) $(LIBTALLOC_LIBS) \
+ torture/t_strstr.o -L ./bin -lbigballofmud
+
+bin/t_strappend@EXEEXT@: $(BINARY_PREREQS) @LIBTALLOC_SHARED@ bin/libbigballofmud.@SHLIBEXT@ torture/t_strappend.o
+ $(CC) $(FLAGS) -o $@ $(DYNEXP) $(LIBS) $(LIBTALLOC_LIBS) \
+ torture/t_strappend.o -L ./bin -lbigballofmud
+
+bin/t_stringoverflow@EXEEXT@: $(BINARY_PREREQS) bin/libbigballofmud.@SHLIBEXT@ torture/t_stringoverflow.o
+ $(CC) $(FLAGS) -o $@ $(DYNEXP) torture/t_stringoverflow.o \
+ -L./bin -lbigballofmud
+
+bin/timelimit@EXEEXT@: script/tests/timelimit.o
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(DYNEXP) script/tests/timelimit.o
+
+bin/rpc_open_tcp@EXEEXT@: $(BINARY_PREREQS) $(RPC_OPEN_TCP_OBJ) @LIBTALLOC_SHARED@ @LIBTDB_SHARED@ @LIBWBCLIENT_SHARED@
+ @echo "Linking $@"
+ @$(CC) $(FLAGS) -o $@ $(RPC_OPEN_TCP_OBJ) $(LDFLAGS) $(DYNEXP) \
+ $(LIBS) $(LIBTALLOC_LIBS) @LIBTDB_SHARED@ $(WINBIND_LIBS) \
+ $(LDAP_LIBS) $(KRB5LIBS) $(NSCD_LIBS)
+
+install:: installservers installbin @INSTALL_CIFSMOUNT@ @INSTALL_CIFSUPCALL@ installman \
+ installscripts installdat installmodules @SWAT_INSTALL_TARGETS@ \
+ @INSTALL_PAM_MODULES@ installlibs
+
+install-everything:: install installmodules
+
+# DESTDIR is used here to prevent packagers wasting their time
+# duplicating the Makefile. Remove it and you will have the privelege
+# of package each samba release for muliple versions of multiple
+# distributions and operating systems, or at least supplying patches
+# to all the packaging files required for this, prior to committing
+# the removal of DESTDIR. Do not remove it even though you think it
+# is not used
+
+installdirs::
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(BINDIR) $(SBINDIR) $(LIBDIR) $(VARDIR) $(PRIVATEDIR) $(PIDDIR) $(LOCKDIR) $(MANDIR) $(CODEPAGEDIR) $(MODULESDIR)
+
+installservers:: all installdirs
+ @$(SHELL) script/installbin.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(SBINDIR) $(SBIN_PROGS)
+
+installbin:: all installdirs
+ @$(SHELL) script/installbin.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(BINDIR) $(BIN_PROGS)
+
+installcifsmount:: @CIFSMOUNT_PROGS@
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(ROOTSBINDIR)
+ @$(SHELL) script/installbin.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(ROOTSBINDIR) @CIFSMOUNT_PROGS@
+
+installcifsupcall:: @CIFSUPCALL_PROGS@
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(SBINDIR)
+ @$(SHELL) script/installbin.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(SBINDIR) @CIFSUPCALL_PROGS@
+
+# Some symlinks are required for the 'probing' of modules.
+# This mechanism should go at some point..
+installmodules:: modules installdirs
+ @$(SHELL) $(srcdir)/script/installmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(VFSLIBDIR) $(VFS_MODULES)
+ @$(SHELL) $(srcdir)/script/installmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(PDBLIBDIR) $(PDB_MODULES)
+ @$(SHELL) $(srcdir)/script/installmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(RPCLIBDIR) $(RPC_MODULES)
+ @$(SHELL) $(srcdir)/script/installmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(IDMAPLIBDIR) $(IDMAP_MODULES)
+ @$(SHELL) $(srcdir)/script/installmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(NSSINFOLIBDIR) $(NSS_INFO_MODULES)
+ @$(SHELL) $(srcdir)/script/installmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(CHARSETLIBDIR) $(CHARSET_MODULES)
+ @$(SHELL) $(srcdir)/script/installmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(AUTHLIBDIR) $(AUTH_MODULES)
+ @$(SHELL) $(srcdir)/script/installmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(GPEXTLIBDIR) $(GPEXT_MODULES)
+ @$(SHELL) $(srcdir)/script/linkmodules.sh $(DESTDIR)$(PDBLIBDIR) ldapsam.@SHLIBEXT@ NDS_ldapsam.@SHLIBEXT@
+ @$(SHELL) $(srcdir)/script/linkmodules.sh $(DESTDIR)$(PDBLIBDIR) ldapsam.@SHLIBEXT@ NDS_ldapsam_compat.@SHLIBEXT@
+ @$(SHELL) $(srcdir)/script/linkmodules.sh $(DESTDIR)$(PDBLIBDIR) ldapsam.@SHLIBEXT@ ldapsam_compat.@SHLIBEXT@
+ @$(SHELL) $(srcdir)/script/linkmodules.sh $(DESTDIR)$(AUTHLIBDIR) rhosts.@SHLIBEXT@ hostsequiv.@SHLIBEXT@
+ @$(SHELL) $(srcdir)/script/linkmodules.sh $(DESTDIR)$(AUTHLIBDIR) sam.@SHLIBEXT@ sam_ignoredomain.@SHLIBEXT@
+ @$(SHELL) $(srcdir)/script/linkmodules.sh $(DESTDIR)$(AUTHLIBDIR) domain.@SHLIBEXT@ trustdomain.@SHLIBEXT@ ntdomain.@SHLIBEXT@
+ @$(SHELL) $(srcdir)/script/linkmodules.sh $(DESTDIR)$(AUTHLIBDIR) builtin.@SHLIBEXT@ guest.@SHLIBEXT@ fixed_challenge.@SHLIBEXT@ name_to_ntstatus.@SHLIBEXT@
+ @$(SHELL) $(srcdir)/script/linkmodules.sh $(DESTDIR)$(NSSINFOLIBDIR) ../idmap/ad.@SHLIBEXT@ rfc2307.@SHLIBEXT@ sfu.@SHLIBEXT@ sfu20.@SHLIBEXT@
+
+installscripts:: installdirs
+ @$(SHELL) $(srcdir)/script/installscripts.sh $(INSTALLPERMS_BIN) $(DESTDIR)$(BINDIR) $(SCRIPTS)
+
+installdat:: installdirs
+ @$(SHELL) $(srcdir)/script/installdat.sh $(DESTDIR) $(CODEPAGEDIR) $(srcdir)
+
+installmsg:: installdirs
+ @$(SHELL) $(srcdir)/script/installmsg.sh $(DESTDIR) $(CODEPAGEDIR) $(srcdir)
+
+installswat:: installdirs installmsg
+ @$(SHELL) $(srcdir)/script/installswat.sh $(DESTDIR) $(SWATDIR) $(srcdir)
+
+installpammodules:: $(PAM_MODULES)
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(PAMMODULESDIR)
+ @for module in $(PAM_MODULES); do \
+ echo "Installing module $${module} as $(DESTDIR)/$(PAMMODULESDIR)/$${module}.@SHLIBEXT@ "; \
+ $(INSTALLCMD) -m $(INSTALLPERMS_BIN) bin/$${module}.@SHLIBEXT@ \
+ "$(DESTDIR)/$(PAMMODULESDIR)"; \
+ done
+
+# revert to the previously installed version
+revert::
+ @$(SHELL) $(srcdir)/script/revert.sh $(SBINDIR) $(SBIN_PROGS)
+ @$(SHELL) $(srcdir)/script/revert.sh $(BINDIR) $(BIN_PROGS) $(SCRIPTS)
+
+installman:: installdirs
+ @$(SHELL) $(srcdir)/script/installman.sh $(DESTDIR)$(MANDIR) $(srcdir) C "@ROFF@"
+
+.PHONY: showlayout
+
+showlayout::
+ @echo "Samba will be installed into:"
+ @echo " prefix: $(prefix)"
+ @echo " bindir: $(BINDIR)"
+ @echo " sbindir: $(SBINDIR)"
+ @echo " libdir: $(LIBDIR)"
+ @echo " modulesdir: $(MODULESDIR)"
+ @echo " vardir: $(VARDIR)"
+ @echo " mandir: $(MANDIR)"
+ @echo " privatedir: $(PRIVATE_DIR)"
+ @echo " configdir: $(CONFIGDIR)"
+ @echo " lockdir: $(LOCKDIR)"
+ @echo " piddir: $(PIDDIR)"
+ @echo " swatdir: $(SWATDIR)"
+ @echo " codepagedir: $(CODEPAGEDIR)"
+
+
+uninstall:: uninstallman uninstallservers uninstallbin @UNINSTALL_CIFSMOUNT@ @UNINSTALL_CIFSUPCALL@ uninstallscripts uninstalldat uninstallswat uninstallmodules uninstalllibs @UNINSTALL_PAM_MODULES@
+
+uninstallman::
+ @$(SHELL) $(srcdir)/script/uninstallman.sh $(DESTDIR)$(MANDIR) $(srcdir) C
+
+uninstallservers::
+ @$(SHELL) script/uninstallbin.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(SBINDIR) $(SBIN_PROGS)
+
+uninstallbin::
+ @$(SHELL) script/uninstallbin.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(BINDIR) $(BIN_PROGS)
+
+uninstallcifsmount::
+ @$(SHELL) script/uninstallbin.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(ROOTSBINDIR) @CIFSMOUNT_PROGS@
+
+uninstallcifsupcall::
+ @$(SHELL) script/uninstallbin.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(ROOTSBINDIR) @CIFSUPCALL_PROGS@
+
+uninstallmodules::
+ @$(SHELL) $(srcdir)/script/uninstallmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(VFSLIBDIR) $(VFS_MODULES)
+ @$(SHELL) $(srcdir)/script/uninstallmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(PDBLIBDIR) $(PDB_MODULES)
+ @$(SHELL) $(srcdir)/script/uninstallmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(RPCLIBDIR) $(RPC_MODULES)
+ @$(SHELL) $(srcdir)/script/uninstallmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(IDMAPLIBDIR) $(IDMAP_MODULES)
+ @$(SHELL) $(srcdir)/script/uninstallmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(CHARSETLIBDIR) $(CHARSET_MODULES)
+ @$(SHELL) $(srcdir)/script/uninstallmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(AUTHLIBDIR) $(AUTH_MODULES)
+ @$(SHELL) $(srcdir)/script/uninstallmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(GPEXTLIBDIR) $(GPEXT_MODULES)
+
+uninstallscripts::
+ @$(SHELL) $(srcdir)/script/uninstallscripts.sh $(INSTALLPERMS_BIN) $(DESTDIR)$(BINDIR) $(SCRIPTS)
+
+uninstalldat::
+ @$(SHELL) $(srcdir)/script/uninstalldat.sh $(DESTDIR) $(LIBDIR) $(srcdir)
+
+uninstallmsg::
+ @$(SHELL) $(srcdir)/script/uninstallmsg.sh $(DESTDIR) $(LIBDIR) $(srcdir)
+
+uninstallswat:: uninstallmsg
+ @$(SHELL) $(srcdir)/script/uninstallswat.sh $(DESTDIR) $(SWATDIR) $(srcdir)
+
+uninstallpammodules::
+ @for module in $(PAM_MODULES); do \
+ echo "Removing $(DESTDIR)/$(PAMMODULESDIR)/$${module}.@SHLIBEXT@ "; \
+ rm -f "$(DESTDIR)/$(PAMMODULESDIR)/$${module}.@SHLIBEXT@"; \
+ done
+
+# Toplevel clean files
+TOPFILES=dynconfig.o
+
+clean:: cleanlibs
+ -rm -f include/build_env.h
+ -rm -f smbd/build_options.c
+ -rm -f $(PRECOMPILED_HEADER)
+ -rm -f core */*~ *~ \
+ */*.o */*/*.o */*/*/*.o \
+ ../testsuite/*/*.o \
+ */*.@SHLIBEXT@ */*/*.@SHLIBEXT@ */*/*/*.@SHLIBEXT@ \
+ $(TOPFILES) $(BIN_PROGS) $(SBIN_PROGS) $(ROOT_SBIN_PROGS) \
+ $(MODULES) $(TORTURE_PROGS) \
+ $(EVERYTHING_PROGS) \
+ bin/timelimit \
+ .headers.stamp */src/*.o
+ -rm -rf t_dir
+
+include/build_env.h: script/build_env.sh
+ @echo Building include/build_env.h
+ @$(SHELL) $(srcdir)/script/build_env.sh $(srcdir) $(builddir) $(CC) \
+ > $(builddir)/include/build_env.h
+
+proto::
+ @echo
+ @echo "NOTE: 'proto' is no longer a valid make target as proto.h"
+ @echo "and other prototype headers are not generated anymore."
+ @echo
+
+.PHONY: proto
+
+etags:
+ etags `find $(srcdir) -name "*.[ch]"`
+
+ctags:
+ ctags `find $(srcdir) -name "*.[ch]"`
+
+realclean:: clean
+ -rm -f config.log bin/.dummy script/findsmb script/gen-8bit-gap.sh
+ -rm -f script/installbin.sh script/uninstallbin.sh
+
+distclean:: realclean
+ -rm -f smbadduser
+ -rm -f include/config.h Makefile
+ -rm -f config.status config.cache so_locations
+ -rm -rf .deps TAGS
+
+realdistclean:: distclean
+ -rm -f include/config.h.in
+ -rm -f include/version.h
+ -rm -f configure
+
+# this target is really just for my use. It only works on a limited
+# range of machines and is used to produce a list of potentially
+# dead (ie. unused) functions in the code. (tridge)
+finddead::
+ nm */*.o |grep 'U ' | awk '{print $$2}' | sort -u > nmused.txt
+ nm */*.o |grep 'T ' | awk '{print $$3}' | sort -u > nmfns.txt
+ comm -13 nmused.txt nmfns.txt
+
+
+# when configure.in is updated, reconfigure
+$(srcdir)/configure: $(srcdir)/configure.in
+ @echo "WARNING: you need to rerun ./autogen.sh"
+
+config.status: $(srcdir)/configure
+ @echo "WARNING: you need to run ./configure"
+
+Makefile: $(srcdir)/Makefile.in config.status
+ @echo "WARNING: you need to run ./config.status"
+
+######################################################################
+# Samba Testing Framework
+
+# Check shared libs for unresolved symbols
+test_shlibs:
+ @echo "Testing $? "
+ @export $(LIB_PATH_VAR)=./bin && \
+ for module in $?; do \
+ ./script/tests/dlopen.sh $${module} \
+ || exit 1; \
+ done
+
+# Check for NSS module problems.
+test_nss_modules:: nss_modules
+ @echo "Testing $(NSS_MODULES) "
+ @export $(LIB_PATH_VAR)=./bin && \
+ for module in $(NSS_MODULES); do \
+ ./script/tests/dlopen.sh $${module} \
+ || exit 1; \
+ done
+
+# Check for PAM module problems. Specifically, check that every module we
+# built can actually be loaded by a minimal PAM-aware application.
+test_pam_modules:: pam_modules
+ @echo "Testing $(PAM_MODULES) "
+ @export $(LIB_PATH_VAR)=./bin && \
+ for module in $(PAM_MODULES); do \
+ ./script/tests/dlopen.sh -lpam -ldl bin/$${module}.@SHLIBEXT@ \
+ || exit 1; \
+ done
+
+
+##
+## Targets for 'make test'
+##
+test:: all torture timelimit
+ @echo Running Test suite
+ @LIB_PATH_VAR=$(LIB_PATH_VAR) PERL="$(PERL)" $(srcdir)/script/tests/selftest.sh ${selftest_prefix} all "${smbtorture4_path}"
+
+valgrindtest:: all torture timelimit
+ @echo Running Test suite with valgrind
+ @LIB_PATH_VAR=$(LIB_PATH_VAR) \
+ NMBD_VALGRIND="xterm -n nmbd -e valgrind -q --db-attach=yes --num-callers=30" \
+ WINBINDD_VALGRIND="xterm -n winbindd -e valgrind -q --db-attach=yes --num-callers=30" \
+ SMBD_VALGRIND="xterm -n smbd -e valgrind -q --db-attach=yes --num-callers=30" \
+ VALGRIND="valgrind -q --num-callers=30 --log-file=${selftest_prefix}/valgrind.log" \
+ PERL="$(PERL)" $(srcdir)/script/tests/selftest.sh ${selftest_prefix} all "${smbtorture4_path}"
+
+
+##
+## Examples:
+##
+
+libsmbclient_examples:
+ $(MAKE) -C ../examples/libsmbclient -f Makefile.internal
+
+clean_libsmbclient_examples:
+ $(MAKE) -C ../examples/libsmbclient -f Makefile.internal clean
diff --git a/source3/VERSION b/source3/VERSION
new file mode 100644
index 0000000000..180d04e882
--- /dev/null
+++ b/source3/VERSION
@@ -0,0 +1,105 @@
+########################################################
+# SAMBA Version #
+# #
+# Samba versions are as follows #
+# 3.0.x New production series #
+# 3.0.x{pre,rc}y Preview/Testing & RC #
+# 3.0.x[a-z] Patch releases #
+# 3.0.x[a-z]-VENDOR-z Vendor patch releases #
+# #
+# script/mkversion.sh #
+# will use this file to create #
+# include/version.h #
+# #
+########################################################
+
+########################################################
+# This are the main SAMBA version numbers #
+# #
+# <MAJOR>.<MINOR>.<RELEASE> #
+# #
+# e.g. SAMBA_VERSION_MAJOR=3 #
+# SAMBA_VERSION_MINOR=0 #
+# SAMBA_VERSION_RELEASE=0 #
+# -> "3.0.0" #
+########################################################
+SAMBA_VERSION_MAJOR=3
+SAMBA_VERSION_MINOR=4
+SAMBA_VERSION_RELEASE=0
+
+########################################################
+# Bug fix releases use a letter for the patch revision #
+# #
+# so SAMBA's version will be #
+# <MAJOR>.<MINOR>.<RELEASE><REVISION> #
+# #
+# e.g. SAMBA_VERSION_REVISION=a #
+# -> "2.2.8a" #
+########################################################
+SAMBA_VERSION_REVISION=
+
+########################################################
+# For 'pre' releases the version will be #
+# #
+# <MAJOR>.<MINOR>.<RELEASE>pre<PRE_RELEASE> #
+# #
+# e.g. SAMBA_VERSION_PRE_RELEASE=1 #
+# -> "2.2.9pre1" #
+########################################################
+SAMBA_VERSION_PRE_RELEASE=
+
+########################################################
+# For 'rc' releases the version will be #
+# #
+# <MAJOR>.<MINOR>.<RELEASE>rc<RC_RELEASE> #
+# #
+# e.g. SAMBA_VERSION_RC_RELEASE=1 #
+# -> "3.0.0rc1" #
+########################################################
+SAMBA_VERSION_RC_RELEASE=
+
+########################################################
+# To mark SVN snapshots this should be set to 'yes' #
+# in the development BRANCH, and set to 'no' only in #
+# the SAMBA_X_X_RELEASE BRANCH #
+# #
+# <MAJOR>.<MINOR>.<RELEASE>[...]cvs #
+# #
+# e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes #
+# -> "3.0.0-SVN-build-199" #
+########################################################
+SAMBA_VERSION_IS_GIT_SNAPSHOT=yes
+
+########################################################
+# This can be set by vendors if they want... #
+# #
+# <MAJOR>.<MINOR>.<RELEASE>[...]-<VENDOR_SUFFIX> #
+# #
+# Note the '-' is automaticaly added #
+# #
+# e.g. SAMBA_VERSION_VENDOR_SUFFIX="VendorVersion" #
+# -> "CVS 3.0.0rc2-VendorVersion" #
+# #
+# Note: If you want to use a function, take a look at #
+# SAMBA_VERSION_VENDOR_FUNCTION #
+# #
+########################################################
+SAMBA_VERSION_VENDOR_SUFFIX="devel"
+SAMBA_VERSION_VENDOR_PATCH=
+
+########################################################
+# This can be set by vendors if they want.. #
+# This have to be a function which returns a string #
+# (const char *). #
+# #
+# Patch for example lib/version.c and add something #
+# like the following example: #
+# #
+# const char *samba_vendor_version(void) #
+# { #
+# return SAMBA_VERSION_OFFICIAL_STRING "-ENREDO-1.0" #
+# } #
+# #
+# -> "Version 3.2.0-ENREDO-1.0 #
+########################################################
+SAMBA_VERSION_VENDOR_FUNCTION=
diff --git a/source3/auth/auth.c b/source3/auth/auth.c
new file mode 100644
index 0000000000..754cb7a508
--- /dev/null
+++ b/source3/auth/auth.c
@@ -0,0 +1,550 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Andrew Bartlett 2001-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+static_decl_auth;
+
+static struct auth_init_function_entry *backends = NULL;
+
+static struct auth_init_function_entry *auth_find_backend_entry(const char *name);
+
+NTSTATUS smb_register_auth(int version, const char *name, auth_init_function init)
+{
+ struct auth_init_function_entry *entry = backends;
+
+ if (version != AUTH_INTERFACE_VERSION) {
+ DEBUG(0,("Can't register auth_method!\n"
+ "You tried to register an auth module with AUTH_INTERFACE_VERSION %d, while this version of samba uses %d\n",
+ version,AUTH_INTERFACE_VERSION));
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ if (!name || !init) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ DEBUG(5,("Attempting to register auth backend %s\n", name));
+
+ if (auth_find_backend_entry(name)) {
+ DEBUG(0,("There already is an auth method registered with the name %s!\n", name));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ entry = SMB_XMALLOC_P(struct auth_init_function_entry);
+ entry->name = smb_xstrdup(name);
+ entry->init = init;
+
+ DLIST_ADD(backends, entry);
+ DEBUG(5,("Successfully added auth method '%s'\n", name));
+ return NT_STATUS_OK;
+}
+
+static struct auth_init_function_entry *auth_find_backend_entry(const char *name)
+{
+ struct auth_init_function_entry *entry = backends;
+
+ while(entry) {
+ if (strcmp(entry->name, name)==0) return entry;
+ entry = entry->next;
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Try to get a challenge out of the various authentication modules.
+ Returns a const char of length 8 bytes.
+****************************************************************************/
+
+static const uint8 *get_ntlm_challenge(struct auth_context *auth_context)
+{
+ DATA_BLOB challenge = data_blob_null;
+ const char *challenge_set_by = NULL;
+ auth_methods *auth_method;
+ TALLOC_CTX *mem_ctx;
+
+ if (auth_context->challenge.length) {
+ DEBUG(5, ("get_ntlm_challenge (auth subsystem): returning previous challenge by module %s (normal)\n",
+ auth_context->challenge_set_by));
+ return auth_context->challenge.data;
+ }
+
+ auth_context->challenge_may_be_modified = False;
+
+ for (auth_method = auth_context->auth_method_list; auth_method; auth_method = auth_method->next) {
+ if (auth_method->get_chal == NULL) {
+ DEBUG(5, ("auth_get_challenge: module %s did not want to specify a challenge\n", auth_method->name));
+ continue;
+ }
+
+ DEBUG(5, ("auth_get_challenge: getting challenge from module %s\n", auth_method->name));
+ if (challenge_set_by != NULL) {
+ DEBUG(1, ("auth_get_challenge: CONFIGURATION ERROR: authentication method %s has already specified a challenge. Challenge by %s ignored.\n",
+ challenge_set_by, auth_method->name));
+ continue;
+ }
+
+ mem_ctx = talloc_init("auth_get_challenge for module %s", auth_method->name);
+ if (!mem_ctx) {
+ smb_panic("talloc_init() failed!");
+ }
+
+ challenge = auth_method->get_chal(auth_context, &auth_method->private_data, mem_ctx);
+ if (!challenge.length) {
+ DEBUG(3, ("auth_get_challenge: getting challenge from authentication method %s FAILED.\n",
+ auth_method->name));
+ } else {
+ DEBUG(5, ("auth_get_challenge: successfully got challenge from module %s\n", auth_method->name));
+ auth_context->challenge = challenge;
+ challenge_set_by = auth_method->name;
+ auth_context->challenge_set_method = auth_method;
+ }
+ talloc_destroy(mem_ctx);
+ }
+
+ if (!challenge_set_by) {
+ uchar chal[8];
+
+ generate_random_buffer(chal, sizeof(chal));
+ auth_context->challenge = data_blob_talloc(auth_context->mem_ctx,
+ chal, sizeof(chal));
+
+ challenge_set_by = "random";
+ auth_context->challenge_may_be_modified = True;
+ }
+
+ DEBUG(5, ("auth_context challenge created by %s\n", challenge_set_by));
+ DEBUG(5, ("challenge is: \n"));
+ dump_data(5, auth_context->challenge.data, auth_context->challenge.length);
+
+ SMB_ASSERT(auth_context->challenge.length == 8);
+
+ auth_context->challenge_set_by=challenge_set_by;
+
+ return auth_context->challenge.data;
+}
+
+
+/**
+ * Check user is in correct domain (if required)
+ *
+ * @param user Only used to fill in the debug message
+ *
+ * @param domain The domain to be verified
+ *
+ * @return True if the user can connect with that domain,
+ * False otherwise.
+**/
+
+static bool check_domain_match(const char *user, const char *domain)
+{
+ /*
+ * If we aren't serving to trusted domains, we must make sure that
+ * the validation request comes from an account in the same domain
+ * as the Samba server
+ */
+
+ if (!lp_allow_trusted_domains() &&
+ !(strequal("", domain) ||
+ strequal(lp_workgroup(), domain) ||
+ is_myname(domain))) {
+ DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain));
+ return False;
+ } else {
+ return True;
+ }
+}
+
+/**
+ * Check a user's Plaintext, LM or NTLM password.
+ *
+ * Check a user's password, as given in the user_info struct and return various
+ * interesting details in the server_info struct.
+ *
+ * This function does NOT need to be in a become_root()/unbecome_root() pair
+ * as it makes the calls itself when needed.
+ *
+ * The return value takes precedence over the contents of the server_info
+ * struct. When the return is other than NT_STATUS_OK the contents
+ * of that structure is undefined.
+ *
+ * @param user_info Contains the user supplied components, including the passwords.
+ * Must be created with make_user_info() or one of its wrappers.
+ *
+ * @param auth_context Supplies the challenges and some other data.
+ * Must be created with make_auth_context(), and the challenges should be
+ * filled in, either at creation or by calling the challenge geneation
+ * function auth_get_challenge().
+ *
+ * @param server_info If successful, contains information about the authentication,
+ * including a struct samu struct describing the user.
+ *
+ * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
+ *
+ **/
+
+static NTSTATUS check_ntlm_password(const struct auth_context *auth_context,
+ const struct auth_usersupplied_info *user_info,
+ struct auth_serversupplied_info **server_info)
+{
+ /* if all the modules say 'not for me' this is reasonable */
+ NTSTATUS nt_status = NT_STATUS_NO_SUCH_USER;
+ const char *unix_username;
+ auth_methods *auth_method;
+ TALLOC_CTX *mem_ctx;
+
+ if (!user_info || !auth_context || !server_info)
+ return NT_STATUS_LOGON_FAILURE;
+
+ DEBUG(3, ("check_ntlm_password: Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n",
+ user_info->client_domain, user_info->smb_name, user_info->wksta_name));
+
+ DEBUG(3, ("check_ntlm_password: mapped user is: [%s]\\[%s]@[%s]\n",
+ user_info->domain, user_info->internal_username, user_info->wksta_name));
+
+ if (auth_context->challenge.length != 8) {
+ DEBUG(0, ("check_ntlm_password: Invalid challenge stored for this auth context - cannot continue\n"));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ if (auth_context->challenge_set_by)
+ DEBUG(10, ("check_ntlm_password: auth_context challenge created by %s\n",
+ auth_context->challenge_set_by));
+
+ DEBUG(10, ("challenge is: \n"));
+ dump_data(5, auth_context->challenge.data, auth_context->challenge.length);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("user_info has passwords of length %d and %d\n",
+ (int)user_info->lm_resp.length, (int)user_info->nt_resp.length));
+ DEBUG(100, ("lm:\n"));
+ dump_data(100, user_info->lm_resp.data, user_info->lm_resp.length);
+ DEBUG(100, ("nt:\n"));
+ dump_data(100, user_info->nt_resp.data, user_info->nt_resp.length);
+#endif
+
+ /* This needs to be sorted: If it doesn't match, what should we do? */
+ if (!check_domain_match(user_info->smb_name, user_info->domain))
+ return NT_STATUS_LOGON_FAILURE;
+
+ for (auth_method = auth_context->auth_method_list;auth_method; auth_method = auth_method->next) {
+ NTSTATUS result;
+
+ mem_ctx = talloc_init("%s authentication for user %s\\%s", auth_method->name,
+ user_info->domain, user_info->smb_name);
+
+ result = auth_method->auth(auth_context, auth_method->private_data, mem_ctx, user_info, server_info);
+
+ /* check if the module did anything */
+ if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ) {
+ DEBUG(10,("check_ntlm_password: %s had nothing to say\n", auth_method->name));
+ talloc_destroy(mem_ctx);
+ continue;
+ }
+
+ nt_status = result;
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(3, ("check_ntlm_password: %s authentication for user [%s] succeeded\n",
+ auth_method->name, user_info->smb_name));
+ } else {
+ DEBUG(5, ("check_ntlm_password: %s authentication for user [%s] FAILED with error %s\n",
+ auth_method->name, user_info->smb_name, nt_errstr(nt_status)));
+ }
+
+ talloc_destroy(mem_ctx);
+
+ if ( NT_STATUS_IS_OK(nt_status))
+ {
+ break;
+ }
+ }
+
+ /* successful authentication */
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ unix_username = (*server_info)->unix_name;
+ if (!(*server_info)->guest) {
+ /* We might not be root if we are an RPC call */
+ become_root();
+ nt_status = smb_pam_accountcheck(unix_username);
+ unbecome_root();
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(5, ("check_ntlm_password: PAM Account for user [%s] succeeded\n",
+ unix_username));
+ } else {
+ DEBUG(3, ("check_ntlm_password: PAM Account for user [%s] FAILED with error %s\n",
+ unix_username, nt_errstr(nt_status)));
+ }
+ }
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG((*server_info)->guest ? 5 : 2,
+ ("check_ntlm_password: %sauthentication for user [%s] -> [%s] -> [%s] succeeded\n",
+ (*server_info)->guest ? "guest " : "",
+ user_info->smb_name,
+ user_info->internal_username,
+ unix_username));
+ }
+
+ return nt_status;
+ }
+
+ /* failed authentication; check for guest lapping */
+
+ DEBUG(2, ("check_ntlm_password: Authentication for user [%s] -> [%s] FAILED with error %s\n",
+ user_info->smb_name, user_info->internal_username,
+ nt_errstr(nt_status)));
+ ZERO_STRUCTP(server_info);
+
+ return nt_status;
+}
+
+/***************************************************************************
+ Clear out a auth_context, and destroy the attached TALLOC_CTX
+***************************************************************************/
+
+static void free_auth_context(struct auth_context **auth_context)
+{
+ auth_methods *auth_method;
+
+ if (*auth_context) {
+ /* Free private data of context's authentication methods */
+ for (auth_method = (*auth_context)->auth_method_list; auth_method; auth_method = auth_method->next) {
+ TALLOC_FREE(auth_method->private_data);
+ }
+
+ talloc_destroy((*auth_context)->mem_ctx);
+ *auth_context = NULL;
+ }
+}
+
+/***************************************************************************
+ Make a auth_info struct
+***************************************************************************/
+
+static NTSTATUS make_auth_context(struct auth_context **auth_context)
+{
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("authentication context");
+
+ *auth_context = TALLOC_P(mem_ctx, struct auth_context);
+ if (!*auth_context) {
+ DEBUG(0,("make_auth_context: talloc failed!\n"));
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ ZERO_STRUCTP(*auth_context);
+
+ (*auth_context)->mem_ctx = mem_ctx;
+ (*auth_context)->check_ntlm_password = check_ntlm_password;
+ (*auth_context)->get_ntlm_challenge = get_ntlm_challenge;
+ (*auth_context)->free = free_auth_context;
+
+ return NT_STATUS_OK;
+}
+
+bool load_auth_module(struct auth_context *auth_context,
+ const char *module, auth_methods **ret)
+{
+ static bool initialised_static_modules = False;
+
+ struct auth_init_function_entry *entry;
+ char *module_name = smb_xstrdup(module);
+ char *module_params = NULL;
+ char *p;
+ bool good = False;
+
+ /* Initialise static modules if not done so yet */
+ if(!initialised_static_modules) {
+ static_init_auth;
+ initialised_static_modules = True;
+ }
+
+ DEBUG(5,("load_auth_module: Attempting to find an auth method to match %s\n",
+ module));
+
+ p = strchr(module_name, ':');
+ if (p) {
+ *p = 0;
+ module_params = p+1;
+ trim_char(module_params, ' ', ' ');
+ }
+
+ trim_char(module_name, ' ', ' ');
+
+ entry = auth_find_backend_entry(module_name);
+
+ if (entry == NULL) {
+ if (NT_STATUS_IS_OK(smb_probe_module("auth", module_name))) {
+ entry = auth_find_backend_entry(module_name);
+ }
+ }
+
+ if (entry != NULL) {
+ if (!NT_STATUS_IS_OK(entry->init(auth_context, module_params, ret))) {
+ DEBUG(0,("load_auth_module: auth method %s did not correctly init\n",
+ module_name));
+ } else {
+ DEBUG(5,("load_auth_module: auth method %s has a valid init\n",
+ module_name));
+ good = True;
+ }
+ } else {
+ DEBUG(0,("load_auth_module: can't find auth method %s!\n", module_name));
+ }
+
+ SAFE_FREE(module_name);
+ return good;
+}
+
+/***************************************************************************
+ Make a auth_info struct for the auth subsystem
+***************************************************************************/
+
+static NTSTATUS make_auth_context_text_list(struct auth_context **auth_context, char **text_list)
+{
+ auth_methods *list = NULL;
+ auth_methods *t = NULL;
+ NTSTATUS nt_status;
+
+ if (!text_list) {
+ DEBUG(2,("make_auth_context_text_list: No auth method list!?\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = make_auth_context(auth_context)))
+ return nt_status;
+
+ for (;*text_list; text_list++) {
+ if (load_auth_module(*auth_context, *text_list, &t)) {
+ DLIST_ADD_END(list, t, auth_methods *);
+ }
+ }
+
+ (*auth_context)->auth_method_list = list;
+
+ return nt_status;
+}
+
+/***************************************************************************
+ Make a auth_context struct for the auth subsystem
+***************************************************************************/
+
+NTSTATUS make_auth_context_subsystem(struct auth_context **auth_context)
+{
+ char **auth_method_list = NULL;
+ NTSTATUS nt_status;
+
+ if (lp_auth_methods()
+ && !str_list_copy(talloc_tos(), &auth_method_list,
+ lp_auth_methods())) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (auth_method_list == NULL) {
+ switch (lp_security())
+ {
+ case SEC_DOMAIN:
+ DEBUG(5,("Making default auth method list for security=domain\n"));
+ auth_method_list = str_list_make(
+ talloc_tos(), "guest sam winbind:ntdomain",
+ NULL);
+ break;
+ case SEC_SERVER:
+ DEBUG(5,("Making default auth method list for security=server\n"));
+ auth_method_list = str_list_make(
+ talloc_tos(), "guest sam smbserver",
+ NULL);
+ break;
+ case SEC_USER:
+ if (lp_encrypted_passwords()) {
+ if ((lp_server_role() == ROLE_DOMAIN_PDC) || (lp_server_role() == ROLE_DOMAIN_BDC)) {
+ DEBUG(5,("Making default auth method list for DC, security=user, encrypt passwords = yes\n"));
+ auth_method_list = str_list_make(
+ talloc_tos(),
+ "guest sam winbind:trustdomain",
+ NULL);
+ } else {
+ DEBUG(5,("Making default auth method list for standalone security=user, encrypt passwords = yes\n"));
+ auth_method_list = str_list_make(
+ talloc_tos(), "guest sam",
+ NULL);
+ }
+ } else {
+ DEBUG(5,("Making default auth method list for security=user, encrypt passwords = no\n"));
+ auth_method_list = str_list_make(
+ talloc_tos(), "guest unix", NULL);
+ }
+ break;
+ case SEC_SHARE:
+ if (lp_encrypted_passwords()) {
+ DEBUG(5,("Making default auth method list for security=share, encrypt passwords = yes\n"));
+ auth_method_list = str_list_make(
+ talloc_tos(), "guest sam", NULL);
+ } else {
+ DEBUG(5,("Making default auth method list for security=share, encrypt passwords = no\n"));
+ auth_method_list = str_list_make(
+ talloc_tos(), "guest unix", NULL);
+ }
+ break;
+ case SEC_ADS:
+ DEBUG(5,("Making default auth method list for security=ADS\n"));
+ auth_method_list = str_list_make(
+ talloc_tos(), "guest sam winbind:ntdomain",
+ NULL);
+ break;
+ default:
+ DEBUG(5,("Unknown auth method!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ } else {
+ DEBUG(5,("Using specified auth order\n"));
+ }
+
+ nt_status = make_auth_context_text_list(auth_context,
+ auth_method_list);
+
+ TALLOC_FREE(auth_method_list);
+ return nt_status;
+}
+
+/***************************************************************************
+ Make a auth_info struct with a fixed challenge
+***************************************************************************/
+
+NTSTATUS make_auth_context_fixed(struct auth_context **auth_context, uchar chal[8])
+{
+ NTSTATUS nt_status;
+ if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(auth_context))) {
+ return nt_status;
+ }
+
+ (*auth_context)->challenge = data_blob_talloc((*auth_context)->mem_ctx, chal, 8);
+ (*auth_context)->challenge_set_by = "fixed";
+ return nt_status;
+}
+
+
diff --git a/source3/auth/auth_builtin.c b/source3/auth/auth_builtin.c
new file mode 100644
index 0000000000..3741f29779
--- /dev/null
+++ b/source3/auth/auth_builtin.c
@@ -0,0 +1,174 @@
+/*
+ Unix SMB/CIFS implementation.
+ Generic authentication types
+ Copyright (C) Andrew Bartlett 2001-2002
+ Copyright (C) Jelmer Vernooij 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+/**
+ * Return a guest logon for guest users (username = "")
+ *
+ * Typically used as the first module in the auth chain, this allows
+ * guest logons to be dealt with in one place. Non-guest logons 'fail'
+ * and pass onto the next module.
+ **/
+
+static NTSTATUS check_guest_security(const struct auth_context *auth_context,
+ void *my_private_data,
+ TALLOC_CTX *mem_ctx,
+ const auth_usersupplied_info *user_info,
+ auth_serversupplied_info **server_info)
+{
+ /* mark this as 'not for me' */
+ NTSTATUS nt_status = NT_STATUS_NOT_IMPLEMENTED;
+
+ if (!(user_info->internal_username
+ && *user_info->internal_username)) {
+ nt_status = make_server_info_guest(NULL, server_info);
+ }
+
+ return nt_status;
+}
+
+/* Guest modules initialisation */
+
+static NTSTATUS auth_init_guest(struct auth_context *auth_context, const char *options, auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_context, auth_method))
+ return NT_STATUS_NO_MEMORY;
+
+ (*auth_method)->auth = check_guest_security;
+ (*auth_method)->name = "guest";
+ return NT_STATUS_OK;
+}
+
+#ifdef DEVELOPER
+/**
+ * Return an error based on username
+ *
+ * This function allows the testing of obsure errors, as well as the generation
+ * of NT_STATUS -> DOS error mapping tables.
+ *
+ * This module is of no value to end-users.
+ *
+ * The password is ignored.
+ *
+ * @return An NTSTATUS value based on the username
+ **/
+
+static NTSTATUS check_name_to_ntstatus_security(const struct auth_context *auth_context,
+ void *my_private_data,
+ TALLOC_CTX *mem_ctx,
+ const auth_usersupplied_info *user_info,
+ auth_serversupplied_info **server_info)
+{
+ NTSTATUS nt_status;
+ fstring user;
+ long error_num;
+ fstrcpy(user, user_info->smb_name);
+
+ if (strnequal("NT_STATUS", user, strlen("NT_STATUS"))) {
+ strupper_m(user);
+ return nt_status_string_to_code(user);
+ }
+
+ strlower_m(user);
+ error_num = strtoul(user, NULL, 16);
+
+ DEBUG(5,("check_name_to_ntstatus_security: Error for user %s was %lx\n", user, error_num));
+
+ nt_status = NT_STATUS(error_num);
+
+ return nt_status;
+}
+
+/** Module initialisation function */
+
+static NTSTATUS auth_init_name_to_ntstatus(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_context, auth_method))
+ return NT_STATUS_NO_MEMORY;
+
+ (*auth_method)->auth = check_name_to_ntstatus_security;
+ (*auth_method)->name = "name_to_ntstatus";
+ return NT_STATUS_OK;
+}
+
+/**
+ * Return a 'fixed' challenge instead of a variable one.
+ *
+ * The idea of this function is to make packet snifs consistant
+ * with a fixed challenge, so as to aid debugging.
+ *
+ * This module is of no value to end-users.
+ *
+ * This module does not actually authenticate the user, but
+ * just pretenteds to need a specified challenge.
+ * This module removes *all* security from the challenge-response system
+ *
+ * @return NT_STATUS_UNSUCCESSFUL
+ **/
+
+static NTSTATUS check_fixed_challenge_security(const struct auth_context *auth_context,
+ void *my_private_data,
+ TALLOC_CTX *mem_ctx,
+ const auth_usersupplied_info *user_info,
+ auth_serversupplied_info **server_info)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************************
+ Get the challenge out of a password server.
+****************************************************************************/
+
+static DATA_BLOB auth_get_fixed_challenge(const struct auth_context *auth_context,
+ void **my_private_data,
+ TALLOC_CTX *mem_ctx)
+{
+ const char *challenge = "I am a teapot";
+ return data_blob(challenge, 8);
+}
+
+
+/** Module initailisation function */
+
+static NTSTATUS auth_init_fixed_challenge(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_context, auth_method))
+ return NT_STATUS_NO_MEMORY;
+
+ (*auth_method)->auth = check_fixed_challenge_security;
+ (*auth_method)->get_chal = auth_get_fixed_challenge;
+ (*auth_method)->name = "fixed_challenge";
+ return NT_STATUS_OK;
+}
+#endif /* DEVELOPER */
+
+NTSTATUS auth_builtin_init(void)
+{
+ smb_register_auth(AUTH_INTERFACE_VERSION, "guest", auth_init_guest);
+#ifdef DEVELOPER
+ smb_register_auth(AUTH_INTERFACE_VERSION, "fixed_challenge", auth_init_fixed_challenge);
+ smb_register_auth(AUTH_INTERFACE_VERSION, "name_to_ntstatus", auth_init_name_to_ntstatus);
+#endif
+ return NT_STATUS_OK;
+}
diff --git a/source3/auth/auth_compat.c b/source3/auth/auth_compat.c
new file mode 100644
index 0000000000..ad2686c003
--- /dev/null
+++ b/source3/auth/auth_compat.c
@@ -0,0 +1,130 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Andrew Bartlett 2001-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern struct auth_context *negprot_global_auth_context;
+extern bool global_encrypted_passwords_negotiated;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+/****************************************************************************
+ COMPATIBILITY INTERFACES:
+ ***************************************************************************/
+
+/****************************************************************************
+check if a username/password is OK assuming the password is a 24 byte
+SMB hash
+return True if the password is correct, False otherwise
+****************************************************************************/
+
+NTSTATUS check_plaintext_password(const char *smb_name, DATA_BLOB plaintext_password, auth_serversupplied_info **server_info)
+{
+ struct auth_context *plaintext_auth_context = NULL;
+ auth_usersupplied_info *user_info = NULL;
+ const uint8 *chal;
+ NTSTATUS nt_status;
+ if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
+ return nt_status;
+ }
+
+ chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
+
+ if (!make_user_info_for_reply(&user_info,
+ smb_name, lp_workgroup(), chal,
+ plaintext_password)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context,
+ user_info, server_info);
+
+ (plaintext_auth_context->free)(&plaintext_auth_context);
+ free_user_info(&user_info);
+ return nt_status;
+}
+
+static NTSTATUS pass_check_smb(const char *smb_name,
+ const char *domain,
+ DATA_BLOB lm_pwd,
+ DATA_BLOB nt_pwd,
+ DATA_BLOB plaintext_password,
+ bool encrypted)
+
+{
+ NTSTATUS nt_status;
+ auth_serversupplied_info *server_info = NULL;
+ if (encrypted) {
+ auth_usersupplied_info *user_info = NULL;
+ make_user_info_for_reply_enc(&user_info, smb_name,
+ domain,
+ lm_pwd,
+ nt_pwd);
+ nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context,
+ user_info, &server_info);
+ free_user_info(&user_info);
+ } else {
+ nt_status = check_plaintext_password(smb_name, plaintext_password, &server_info);
+ }
+ TALLOC_FREE(server_info);
+ return nt_status;
+}
+
+/****************************************************************************
+check if a username/password pair is ok via the auth subsystem.
+return True if the password is correct, False otherwise
+****************************************************************************/
+
+bool password_ok(const char *smb_name, DATA_BLOB password_blob)
+{
+
+ DATA_BLOB null_password = data_blob_null;
+ bool encrypted = (global_encrypted_passwords_negotiated && (password_blob.length == 24 || password_blob.length > 46));
+
+ if (encrypted) {
+ /*
+ * The password could be either NTLM or plain LM. Try NTLM first,
+ * but fall-through as required.
+ * Vista sends NTLMv2 here - we need to try the client given workgroup.
+ */
+ if (get_session_workgroup()) {
+ if (NT_STATUS_IS_OK(pass_check_smb(smb_name, get_session_workgroup(), null_password, password_blob, null_password, encrypted))) {
+ return True;
+ }
+ if (NT_STATUS_IS_OK(pass_check_smb(smb_name, get_session_workgroup(), password_blob, null_password, null_password, encrypted))) {
+ return True;
+ }
+ }
+
+ if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, password_blob, null_password, encrypted))) {
+ return True;
+ }
+
+ if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), password_blob, null_password, null_password, encrypted))) {
+ return True;
+ }
+ } else {
+ if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, null_password, password_blob, encrypted))) {
+ return True;
+ }
+ }
+
+ return False;
+}
diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c
new file mode 100644
index 0000000000..c25e62ab80
--- /dev/null
+++ b/source3/auth/auth_domain.c
@@ -0,0 +1,477 @@
+/*
+ Unix SMB/CIFS implementation.
+ Authenticate against a remote domain
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+extern bool global_machine_password_needs_changing;
+static struct named_mutex *mutex;
+
+/**
+ * Connect to a remote server for (inter)domain security authenticaion.
+ *
+ * @param cli the cli to return containing the active connection
+ * @param server either a machine name or text IP address to
+ * connect to.
+ * @param setup_creds_as domain account to setup credentials as
+ * @param sec_chan a switch value to distinguish between domain
+ * member and interdomain authentication
+ * @param trust_passwd the trust password to establish the
+ * credentials with.
+ *
+ **/
+
+static NTSTATUS connect_to_domain_password_server(struct cli_state **cli,
+ const char *domain,
+ const char *dc_name,
+ struct sockaddr_storage *dc_ss,
+ struct rpc_pipe_client **pipe_ret,
+ bool *retry)
+{
+ NTSTATUS result;
+ struct rpc_pipe_client *netlogon_pipe = NULL;
+
+ *cli = NULL;
+
+ *pipe_ret = NULL;
+
+ /* TODO: Send a SAMLOGON request to determine whether this is a valid
+ logonserver. We can avoid a 30-second timeout if the DC is down
+ if the SAMLOGON request fails as it is only over UDP. */
+
+ /* we use a mutex to prevent two connections at once - when a
+ Win2k PDC get two connections where one hasn't completed a
+ session setup yet it will send a TCP reset to the first
+ connection (tridge) */
+
+ /*
+ * With NT4.x DC's *all* authentication must be serialized to avoid
+ * ACCESS_DENIED errors if 2 auths are done from the same machine. JRA.
+ */
+
+ mutex = grab_named_mutex(NULL, dc_name, 10);
+ if (mutex == NULL) {
+ return NT_STATUS_NO_LOGON_SERVERS;
+ }
+
+ /* Attempt connection */
+ *retry = True;
+ result = cli_full_connection(cli, global_myname(), dc_name, dc_ss, 0,
+ "IPC$", "IPC", "", "", "", 0, Undefined, retry);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ /* map to something more useful */
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
+ result = NT_STATUS_NO_LOGON_SERVERS;
+ }
+
+ if (*cli) {
+ cli_shutdown(*cli);
+ *cli = NULL;
+ }
+
+ TALLOC_FREE(mutex);
+ return result;
+ }
+
+ /*
+ * We now have an anonymous connection to IPC$ on the domain password server.
+ */
+
+ /*
+ * Even if the connect succeeds we need to setup the netlogon
+ * pipe here. We do this as we may just have changed the domain
+ * account password on the PDC and yet we may be talking to
+ * a BDC that doesn't have this replicated yet. In this case
+ * a successful connect to a DC needs to take the netlogon connect
+ * into account also. This patch from "Bjart Kvarme" <bjart.kvarme@usit.uio.no>.
+ */
+
+ /* open the netlogon pipe. */
+ if (lp_client_schannel()) {
+ /* We also setup the creds chain in the open_schannel call. */
+ result = cli_rpc_pipe_open_schannel(
+ *cli, &ndr_table_netlogon.syntax_id,
+ PIPE_AUTH_LEVEL_PRIVACY, domain, &netlogon_pipe);
+ } else {
+ result = cli_rpc_pipe_open_noauth(
+ *cli, &ndr_table_netlogon.syntax_id, &netlogon_pipe);
+ }
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("connect_to_domain_password_server: unable to open the domain client session to \
+machine %s. Error was : %s.\n", dc_name, nt_errstr(result)));
+ cli_shutdown(*cli);
+ *cli = NULL;
+ TALLOC_FREE(mutex);
+ return result;
+ }
+
+ if (!lp_client_schannel()) {
+ /* We need to set up a creds chain on an unauthenticated netlogon pipe. */
+ uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+ uint32 sec_chan_type = 0;
+ unsigned char machine_pwd[16];
+ const char *account_name;
+
+ if (!get_trust_pw_hash(domain, machine_pwd, &account_name,
+ &sec_chan_type))
+ {
+ DEBUG(0, ("connect_to_domain_password_server: could not fetch "
+ "trust account password for domain '%s'\n",
+ domain));
+ cli_shutdown(*cli);
+ *cli = NULL;
+ TALLOC_FREE(mutex);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ result = rpccli_netlogon_setup_creds(netlogon_pipe,
+ dc_name, /* server name */
+ domain, /* domain */
+ global_myname(), /* client name */
+ account_name, /* machine account name */
+ machine_pwd,
+ sec_chan_type,
+ &neg_flags);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ cli_shutdown(*cli);
+ *cli = NULL;
+ TALLOC_FREE(mutex);
+ return result;
+ }
+ }
+
+ if(!netlogon_pipe) {
+ DEBUG(0,("connect_to_domain_password_server: unable to open the domain client session to \
+machine %s. Error was : %s.\n", dc_name, cli_errstr(*cli)));
+ cli_shutdown(*cli);
+ *cli = NULL;
+ TALLOC_FREE(mutex);
+ return NT_STATUS_NO_LOGON_SERVERS;
+ }
+
+ /* We exit here with the mutex *locked*. JRA */
+
+ *pipe_ret = netlogon_pipe;
+
+ return NT_STATUS_OK;
+}
+
+/***********************************************************************
+ Do the same as security=server, but using NT Domain calls and a session
+ key from the machine password. If the server parameter is specified
+ use it, otherwise figure out a server from the 'password server' param.
+************************************************************************/
+
+static NTSTATUS domain_client_validate(TALLOC_CTX *mem_ctx,
+ const auth_usersupplied_info *user_info,
+ const char *domain,
+ uchar chal[8],
+ auth_serversupplied_info **server_info,
+ const char *dc_name,
+ struct sockaddr_storage *dc_ss)
+
+{
+ struct netr_SamInfo3 *info3 = NULL;
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *netlogon_pipe = NULL;
+ NTSTATUS nt_status = NT_STATUS_NO_LOGON_SERVERS;
+ int i;
+ bool retry = 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.
+ */
+
+ /* rety loop for robustness */
+
+ for (i = 0; !NT_STATUS_IS_OK(nt_status) && retry && (i < 3); i++) {
+ nt_status = connect_to_domain_password_server(&cli,
+ domain,
+ dc_name,
+ dc_ss,
+ &netlogon_pipe,
+ &retry);
+ }
+
+ if ( !NT_STATUS_IS_OK(nt_status) ) {
+ DEBUG(0,("domain_client_validate: Domain password server not available.\n"));
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
+ return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
+ }
+ return nt_status;
+ }
+
+ /* store a successful connection */
+
+ saf_store( domain, cli->desthost );
+
+ /*
+ * If this call succeeds, we now have lots of info about the user
+ * in the info3 structure.
+ */
+
+ nt_status = rpccli_netlogon_sam_network_logon(netlogon_pipe,
+ mem_ctx,
+ user_info->logon_parameters,/* flags such as 'allow workstation logon' */
+ dc_name, /* server name */
+ user_info->smb_name, /* user name logging on. */
+ user_info->client_domain, /* domain name */
+ user_info->wksta_name, /* workstation name */
+ chal, /* 8 byte challenge. */
+ user_info->lm_resp, /* lanman 24 byte response */
+ user_info->nt_resp, /* nt 24 byte response */
+ &info3); /* info3 out */
+
+ /* Let go as soon as possible so we avoid any potential deadlocks
+ with winbind lookup up users or groups. */
+
+ TALLOC_FREE(mutex);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0,("domain_client_validate: unable to validate password "
+ "for user %s in domain %s to Domain controller %s. "
+ "Error was %s.\n", user_info->smb_name,
+ user_info->client_domain, dc_name,
+ nt_errstr(nt_status)));
+
+ /* map to something more useful */
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) {
+ nt_status = NT_STATUS_NO_LOGON_SERVERS;
+ }
+ } else {
+ nt_status = make_server_info_info3(mem_ctx,
+ user_info->smb_name,
+ domain,
+ server_info,
+ info3);
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ (*server_info)->nss_token |= user_info->was_mapped;
+
+ if ( ! (*server_info)->guest) {
+ /* if a real user check pam account restrictions */
+ /* only really perfomed if "obey pam restriction" is true */
+ nt_status = smb_pam_accountcheck((*server_info)->unix_name);
+ if ( !NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1, ("PAM account restriction prevents user login\n"));
+ cli_shutdown(cli);
+ TALLOC_FREE(info3);
+ return nt_status;
+ }
+ }
+ }
+
+ netsamlogon_cache_store(user_info->smb_name, info3);
+ TALLOC_FREE(info3);
+ }
+
+ /* Note - once the cli stream is shutdown the mem_ctx used
+ to allocate the other_sids and gids structures has been deleted - so
+ these pointers are no longer valid..... */
+
+ cli_shutdown(cli);
+ return nt_status;
+}
+
+/****************************************************************************
+ Check for a valid username and password in security=domain mode.
+****************************************************************************/
+
+static NTSTATUS check_ntdomain_security(const struct auth_context *auth_context,
+ void *my_private_data,
+ TALLOC_CTX *mem_ctx,
+ const auth_usersupplied_info *user_info,
+ auth_serversupplied_info **server_info)
+{
+ NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+ const char *domain = lp_workgroup();
+ fstring dc_name;
+ struct sockaddr_storage dc_ss;
+
+ if ( lp_server_role() != ROLE_DOMAIN_MEMBER ) {
+ DEBUG(0,("check_ntdomain_security: Configuration error! Cannot use "
+ "ntdomain auth method when not a member of a domain.\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!user_info || !server_info || !auth_context) {
+ DEBUG(1,("check_ntdomain_security: Critical variables not present. Failing.\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /*
+ * 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(get_global_sam_name(), user_info->domain)) {
+ DEBUG(3,("check_ntdomain_security: Requested domain was for this machine.\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* we need our DC to send the net_sam_logon() request to */
+
+ if ( !get_dc_name(domain, NULL, dc_name, &dc_ss) ) {
+ DEBUG(5,("check_ntdomain_security: unable to locate a DC for domain %s\n",
+ user_info->domain));
+ return NT_STATUS_NO_LOGON_SERVERS;
+ }
+
+ nt_status = domain_client_validate(mem_ctx,
+ user_info,
+ domain,
+ (uchar *)auth_context->challenge.data,
+ server_info,
+ dc_name,
+ &dc_ss);
+
+ return nt_status;
+}
+
+/* module initialisation */
+static NTSTATUS auth_init_ntdomain(struct auth_context *auth_context, const char* param, auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_context, auth_method)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*auth_method)->name = "ntdomain";
+ (*auth_method)->auth = check_ntdomain_security;
+ return NT_STATUS_OK;
+}
+
+
+/****************************************************************************
+ Check for a valid username and password in a trusted domain
+****************************************************************************/
+
+static NTSTATUS check_trustdomain_security(const struct auth_context *auth_context,
+ void *my_private_data,
+ TALLOC_CTX *mem_ctx,
+ const auth_usersupplied_info *user_info,
+ auth_serversupplied_info **server_info)
+{
+ NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+ unsigned char trust_md4_password[16];
+ char *trust_password;
+ time_t last_change_time;
+ DOM_SID sid;
+ fstring dc_name;
+ struct sockaddr_storage dc_ss;
+
+ if (!user_info || !server_info || !auth_context) {
+ DEBUG(1,("check_trustdomain_security: Critical variables not present. Failing.\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /*
+ * Check that the requested domain is not our own machine name or domain name.
+ */
+
+ if( strequal(get_global_sam_name(), user_info->domain)) {
+ DEBUG(3,("check_trustdomain_security: Requested domain [%s] was for this machine.\n",
+ user_info->domain));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* No point is bothering if this is not a trusted domain.
+ This return makes "map to guest = bad user" work again.
+ The logic is that if we know nothing about the domain, that
+ user is not known to us and does not exist */
+
+ if ( !is_trusted_domain( user_info->domain ) )
+ return NT_STATUS_NOT_IMPLEMENTED;
+
+ /*
+ * Get the trusted account password for the trusted domain
+ * No need to become_root() as secrets_init() is done at startup.
+ */
+
+ if (!pdb_get_trusteddom_pw(user_info->domain, &trust_password,
+ &sid, &last_change_time)) {
+ DEBUG(0, ("check_trustdomain_security: could not fetch trust "
+ "account password for domain %s\n",
+ user_info->domain));
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("Trust password for domain %s is %s\n", user_info->domain,
+ trust_password));
+#endif
+ E_md4hash(trust_password, trust_md4_password);
+ SAFE_FREE(trust_password);
+
+#if 0
+ /* Test if machine password is expired and need to be changed */
+ if (time(NULL) > last_change_time + (time_t)lp_machine_password_timeout())
+ {
+ global_machine_password_needs_changing = True;
+ }
+#endif
+
+ /* use get_dc_name() for consistency even through we know that it will be
+ a netbios name */
+
+ if ( !get_dc_name(user_info->domain, NULL, dc_name, &dc_ss) ) {
+ DEBUG(5,("check_trustdomain_security: unable to locate a DC for domain %s\n",
+ user_info->domain));
+ return NT_STATUS_NO_LOGON_SERVERS;
+ }
+
+ nt_status = domain_client_validate(mem_ctx,
+ user_info,
+ user_info->domain,
+ (uchar *)auth_context->challenge.data,
+ server_info,
+ dc_name,
+ &dc_ss);
+
+ return nt_status;
+}
+
+/* module initialisation */
+static NTSTATUS auth_init_trustdomain(struct auth_context *auth_context, const char* param, auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_context, auth_method)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*auth_method)->name = "trustdomain";
+ (*auth_method)->auth = check_trustdomain_security;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS auth_domain_init(void)
+{
+ smb_register_auth(AUTH_INTERFACE_VERSION, "trustdomain", auth_init_trustdomain);
+ smb_register_auth(AUTH_INTERFACE_VERSION, "ntdomain", auth_init_ntdomain);
+ return NT_STATUS_OK;
+}
diff --git a/source3/auth/auth_ntlmssp.c b/source3/auth/auth_ntlmssp.c
new file mode 100644
index 0000000000..0d46b14f97
--- /dev/null
+++ b/source3/auth/auth_ntlmssp.c
@@ -0,0 +1,214 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ handle NLTMSSP, server side
+
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Andrew Bartlett 2001-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/**
+ * Return the challenge as determined by the authentication subsystem
+ * @return an 8 byte random challenge
+ */
+
+static const uint8 *auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_state)
+{
+ AUTH_NTLMSSP_STATE *auth_ntlmssp_state =
+ (AUTH_NTLMSSP_STATE *)ntlmssp_state->auth_context;
+ return auth_ntlmssp_state->auth_context->get_ntlm_challenge(auth_ntlmssp_state->auth_context);
+}
+
+/**
+ * Some authentication methods 'fix' the challenge, so we may not be able to set it
+ *
+ * @return If the effective challenge used by the auth subsystem may be modified
+ */
+static bool auth_ntlmssp_may_set_challenge(const struct ntlmssp_state *ntlmssp_state)
+{
+ AUTH_NTLMSSP_STATE *auth_ntlmssp_state =
+ (AUTH_NTLMSSP_STATE *)ntlmssp_state->auth_context;
+ struct auth_context *auth_context = auth_ntlmssp_state->auth_context;
+
+ return auth_context->challenge_may_be_modified;
+}
+
+/**
+ * NTLM2 authentication modifies the effective challenge,
+ * @param challenge The new challenge value
+ */
+static NTSTATUS auth_ntlmssp_set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge)
+{
+ AUTH_NTLMSSP_STATE *auth_ntlmssp_state =
+ (AUTH_NTLMSSP_STATE *)ntlmssp_state->auth_context;
+ struct auth_context *auth_context = auth_ntlmssp_state->auth_context;
+
+ SMB_ASSERT(challenge->length == 8);
+
+ auth_context->challenge = data_blob_talloc(auth_context->mem_ctx,
+ challenge->data, challenge->length);
+
+ auth_context->challenge_set_by = "NTLMSSP callback (NTLM2)";
+
+ DEBUG(5, ("auth_context challenge set by %s\n", auth_context->challenge_set_by));
+ DEBUG(5, ("challenge is: \n"));
+ dump_data(5, auth_context->challenge.data, auth_context->challenge.length);
+ return NT_STATUS_OK;
+}
+
+/**
+ * Check the password on an NTLMSSP login.
+ *
+ * Return the session keys used on the connection.
+ */
+
+static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
+{
+ AUTH_NTLMSSP_STATE *auth_ntlmssp_state =
+ (AUTH_NTLMSSP_STATE *)ntlmssp_state->auth_context;
+ auth_usersupplied_info *user_info = NULL;
+ NTSTATUS nt_status;
+ bool username_was_mapped;
+
+ /* the client has given us its machine name (which we otherwise would not get on port 445).
+ we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
+
+ set_remote_machine_name(auth_ntlmssp_state->ntlmssp_state->workstation, True);
+
+ /* setup the string used by %U */
+ /* sub_set_smb_name checks for weird internally */
+ sub_set_smb_name(auth_ntlmssp_state->ntlmssp_state->user);
+
+ reload_services(True);
+
+ nt_status = make_user_info_map(&user_info,
+ auth_ntlmssp_state->ntlmssp_state->user,
+ auth_ntlmssp_state->ntlmssp_state->domain,
+ auth_ntlmssp_state->ntlmssp_state->workstation,
+ auth_ntlmssp_state->ntlmssp_state->lm_resp.data ? &auth_ntlmssp_state->ntlmssp_state->lm_resp : NULL,
+ auth_ntlmssp_state->ntlmssp_state->nt_resp.data ? &auth_ntlmssp_state->ntlmssp_state->nt_resp : NULL,
+ NULL, NULL, NULL,
+ True);
+
+ user_info->logon_parameters = MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ nt_status = auth_ntlmssp_state->auth_context->check_ntlm_password(auth_ntlmssp_state->auth_context,
+ user_info, &auth_ntlmssp_state->server_info);
+
+ username_was_mapped = user_info->was_mapped;
+
+ free_user_info(&user_info);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ auth_ntlmssp_state->server_info->nss_token |= username_was_mapped;
+
+ nt_status = create_local_token(auth_ntlmssp_state->server_info);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(10, ("create_local_token failed: %s\n",
+ nt_errstr(nt_status)));
+ return nt_status;
+ }
+
+ if (auth_ntlmssp_state->server_info->user_session_key.length) {
+ DEBUG(10, ("Got NT session key of length %u\n",
+ (unsigned int)auth_ntlmssp_state->server_info->user_session_key.length));
+ *user_session_key = data_blob_talloc(auth_ntlmssp_state->mem_ctx,
+ auth_ntlmssp_state->server_info->user_session_key.data,
+ auth_ntlmssp_state->server_info->user_session_key.length);
+ }
+ if (auth_ntlmssp_state->server_info->lm_session_key.length) {
+ DEBUG(10, ("Got LM session key of length %u\n",
+ (unsigned int)auth_ntlmssp_state->server_info->lm_session_key.length));
+ *lm_session_key = data_blob_talloc(auth_ntlmssp_state->mem_ctx,
+ auth_ntlmssp_state->server_info->lm_session_key.data,
+ auth_ntlmssp_state->server_info->lm_session_key.length);
+ }
+ return nt_status;
+}
+
+NTSTATUS auth_ntlmssp_start(AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
+{
+ NTSTATUS nt_status;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("AUTH NTLMSSP context");
+
+ *auth_ntlmssp_state = TALLOC_ZERO_P(mem_ctx, AUTH_NTLMSSP_STATE);
+ if (!*auth_ntlmssp_state) {
+ DEBUG(0,("auth_ntlmssp_start: talloc failed!\n"));
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCTP(*auth_ntlmssp_state);
+
+ (*auth_ntlmssp_state)->mem_ctx = mem_ctx;
+
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_server_start(&(*auth_ntlmssp_state)->ntlmssp_state))) {
+ return nt_status;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&(*auth_ntlmssp_state)->auth_context))) {
+ return nt_status;
+ }
+
+ (*auth_ntlmssp_state)->ntlmssp_state->auth_context = (*auth_ntlmssp_state);
+ (*auth_ntlmssp_state)->ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge;
+ (*auth_ntlmssp_state)->ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge;
+ (*auth_ntlmssp_state)->ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge;
+ (*auth_ntlmssp_state)->ntlmssp_state->check_password = auth_ntlmssp_check_password;
+ (*auth_ntlmssp_state)->ntlmssp_state->server_role = (enum server_types)lp_server_role();
+
+ return NT_STATUS_OK;
+}
+
+void auth_ntlmssp_end(AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
+{
+ TALLOC_CTX *mem_ctx;
+
+ if (*auth_ntlmssp_state == NULL) {
+ return;
+ }
+
+ mem_ctx = (*auth_ntlmssp_state)->mem_ctx;
+ if ((*auth_ntlmssp_state)->ntlmssp_state) {
+ ntlmssp_end(&(*auth_ntlmssp_state)->ntlmssp_state);
+ }
+ if ((*auth_ntlmssp_state)->auth_context) {
+ ((*auth_ntlmssp_state)->auth_context->free)(&(*auth_ntlmssp_state)->auth_context);
+ }
+ if ((*auth_ntlmssp_state)->server_info) {
+ TALLOC_FREE((*auth_ntlmssp_state)->server_info);
+ }
+ talloc_destroy(mem_ctx);
+ *auth_ntlmssp_state = NULL;
+}
+
+NTSTATUS auth_ntlmssp_update(AUTH_NTLMSSP_STATE *auth_ntlmssp_state,
+ const DATA_BLOB request, DATA_BLOB *reply)
+{
+ return ntlmssp_update(auth_ntlmssp_state->ntlmssp_state, request, reply);
+}
diff --git a/source3/auth/auth_sam.c b/source3/auth/auth_sam.c
new file mode 100644
index 0000000000..50bf15318b
--- /dev/null
+++ b/source3/auth/auth_sam.c
@@ -0,0 +1,450 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Andrew Bartlett 2001-2003
+ Copyright (C) Gerald Carter 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+/****************************************************************************
+ Do a specific test for an smb password being correct, given a smb_password and
+ the lanman and NT responses.
+****************************************************************************/
+
+static NTSTATUS sam_password_ok(const struct auth_context *auth_context,
+ TALLOC_CTX *mem_ctx,
+ struct samu *sampass,
+ const auth_usersupplied_info *user_info,
+ DATA_BLOB *user_sess_key,
+ DATA_BLOB *lm_sess_key)
+{
+ uint32 acct_ctrl;
+ const uint8 *lm_pw, *nt_pw;
+ const char *username = pdb_get_username(sampass);
+
+ acct_ctrl = pdb_get_acct_ctrl(sampass);
+ if (acct_ctrl & ACB_PWNOTREQ) {
+ if (lp_null_passwords()) {
+ DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", username));
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", username));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ }
+
+ lm_pw = pdb_get_lanman_passwd(sampass);
+ nt_pw = pdb_get_nt_passwd(sampass);
+
+ return ntlm_password_check(mem_ctx, &auth_context->challenge,
+ &user_info->lm_resp, &user_info->nt_resp,
+ &user_info->lm_interactive_pwd, &user_info->nt_interactive_pwd,
+ username,
+ user_info->smb_name,
+ user_info->client_domain,
+ lm_pw, nt_pw, user_sess_key, lm_sess_key);
+}
+
+/****************************************************************************
+ Check if a user is allowed to logon at this time. Note this is the
+ servers local time, as logon hours are just specified as a weekly
+ bitmask.
+****************************************************************************/
+
+static bool logon_hours_ok(struct samu *sampass)
+{
+ /* In logon hours first bit is Sunday from 12AM to 1AM */
+ const uint8 *hours;
+ struct tm *utctime;
+ time_t lasttime;
+ const char *asct;
+ uint8 bitmask, bitpos;
+
+ hours = pdb_get_hours(sampass);
+ if (!hours) {
+ DEBUG(5,("logon_hours_ok: No hours restrictions for user %s\n",pdb_get_username(sampass)));
+ return True;
+ }
+
+ lasttime = time(NULL);
+ utctime = gmtime(&lasttime);
+ if (!utctime) {
+ DEBUG(1, ("logon_hours_ok: failed to get gmtime. Failing logon for user %s\n",
+ pdb_get_username(sampass) ));
+ return False;
+ }
+
+ /* find the corresponding byte and bit */
+ bitpos = (utctime->tm_wday * 24 + utctime->tm_hour) % 168;
+ bitmask = 1 << (bitpos % 8);
+
+ if (! (hours[bitpos/8] & bitmask)) {
+ struct tm *t = localtime(&lasttime);
+ if (!t) {
+ asct = "INVALID TIME";
+ } else {
+ asct = asctime(t);
+ if (!asct) {
+ asct = "INVALID TIME";
+ }
+ }
+
+ DEBUG(1, ("logon_hours_ok: Account for user %s not allowed to "
+ "logon at this time (%s).\n",
+ pdb_get_username(sampass), asct ));
+ return False;
+ }
+
+ asct = asctime(utctime);
+ DEBUG(5,("logon_hours_ok: user %s allowed to logon at this time (%s)\n",
+ pdb_get_username(sampass), asct ? asct : "UNKNOWN TIME" ));
+
+ return True;
+}
+
+/****************************************************************************
+ Do a specific test for a struct samu being valid for this connection
+ (ie not disabled, expired and the like).
+****************************************************************************/
+
+static NTSTATUS sam_account_ok(TALLOC_CTX *mem_ctx,
+ struct samu *sampass,
+ const auth_usersupplied_info *user_info)
+{
+ uint32 acct_ctrl = pdb_get_acct_ctrl(sampass);
+ char *workstation_list;
+ time_t kickoff_time;
+
+ DEBUG(4,("sam_account_ok: Checking SMB password for user %s\n",pdb_get_username(sampass)));
+
+ /* Quit if the account was disabled. */
+ if (acct_ctrl & ACB_DISABLED) {
+ DEBUG(1,("sam_account_ok: Account for user '%s' was disabled.\n", pdb_get_username(sampass)));
+ return NT_STATUS_ACCOUNT_DISABLED;
+ }
+
+ /* Quit if the account was locked out. */
+ if (acct_ctrl & ACB_AUTOLOCK) {
+ DEBUG(1,("sam_account_ok: Account for user %s was locked out.\n", pdb_get_username(sampass)));
+ return NT_STATUS_ACCOUNT_LOCKED_OUT;
+ }
+
+ /* Quit if the account is not allowed to logon at this time. */
+ if (! logon_hours_ok(sampass)) {
+ return NT_STATUS_INVALID_LOGON_HOURS;
+ }
+
+ /* Test account expire time */
+
+ kickoff_time = pdb_get_kickoff_time(sampass);
+ if (kickoff_time != 0 && time(NULL) > kickoff_time) {
+ DEBUG(1,("sam_account_ok: Account for user '%s' has expired.\n", pdb_get_username(sampass)));
+ DEBUG(3,("sam_account_ok: Account expired at '%ld' unix time.\n", (long)kickoff_time));
+ return NT_STATUS_ACCOUNT_EXPIRED;
+ }
+
+ if (!(pdb_get_acct_ctrl(sampass) & ACB_PWNOEXP) && !(pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ)) {
+ time_t must_change_time = pdb_get_pass_must_change_time(sampass);
+ time_t last_set_time = pdb_get_pass_last_set_time(sampass);
+
+ /* check for immediate expiry "must change at next logon"
+ * for a user account. */
+ if (((acct_ctrl & (ACB_WSTRUST|ACB_SVRTRUST)) == 0) && (last_set_time == 0)) {
+ DEBUG(1,("sam_account_ok: Account for user '%s' password must change!.\n", pdb_get_username(sampass)));
+ return NT_STATUS_PASSWORD_MUST_CHANGE;
+ }
+
+ /* check for expired password */
+ if (must_change_time < time(NULL) && must_change_time != 0) {
+ DEBUG(1,("sam_account_ok: Account for user '%s' password expired!.\n", pdb_get_username(sampass)));
+ DEBUG(1,("sam_account_ok: Password expired at '%s' (%ld) unix time.\n", http_timestring(must_change_time), (long)must_change_time));
+ return NT_STATUS_PASSWORD_EXPIRED;
+ }
+ }
+
+ /* Test workstation. Workstation list is comma separated. */
+
+ workstation_list = talloc_strdup(mem_ctx, pdb_get_workstations(sampass));
+ if (!workstation_list)
+ return NT_STATUS_NO_MEMORY;
+
+ if (*workstation_list) {
+ bool invalid_ws = True;
+ char *tok;
+ const char *s = workstation_list;
+
+ const char *machine_name = talloc_asprintf(mem_ctx, "%s$", user_info->wksta_name);
+ if (machine_name == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ while (next_token_talloc(mem_ctx, &s, &tok, ",")) {
+ DEBUG(10,("sam_account_ok: checking for workstation match %s and %s\n",
+ tok, user_info->wksta_name));
+ if(strequal(tok, user_info->wksta_name)) {
+ invalid_ws = False;
+ break;
+ }
+ if (tok[0] == '+') {
+ DEBUG(10,("sam_account_ok: checking for workstation %s in group: %s\n",
+ machine_name, tok + 1));
+ if (user_in_group(machine_name, tok + 1)) {
+ invalid_ws = False;
+ break;
+ }
+ }
+ TALLOC_FREE(tok);
+ }
+ TALLOC_FREE(tok);
+
+ if (invalid_ws)
+ return NT_STATUS_INVALID_WORKSTATION;
+ }
+
+ if (acct_ctrl & ACB_DOMTRUST) {
+ DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", pdb_get_username(sampass)));
+ return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
+ }
+
+ if (acct_ctrl & ACB_SVRTRUST) {
+ if (!(user_info->logon_parameters & MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT)) {
+ DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", pdb_get_username(sampass)));
+ return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
+ }
+ }
+
+ if (acct_ctrl & ACB_WSTRUST) {
+ if (!(user_info->logon_parameters & MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT)) {
+ DEBUG(2,("sam_account_ok: Wksta trust account %s denied by server\n", pdb_get_username(sampass)));
+ return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+check if a username/password is OK assuming the password is a 24 byte
+SMB hash supplied in the user_info structure
+return an NT_STATUS constant.
+****************************************************************************/
+
+static NTSTATUS check_sam_security(const struct auth_context *auth_context,
+ void *my_private_data,
+ TALLOC_CTX *mem_ctx,
+ const auth_usersupplied_info *user_info,
+ auth_serversupplied_info **server_info)
+{
+ struct samu *sampass=NULL;
+ bool ret;
+ NTSTATUS nt_status;
+ NTSTATUS update_login_attempts_status;
+ DATA_BLOB user_sess_key = data_blob_null;
+ DATA_BLOB lm_sess_key = data_blob_null;
+ bool updated_autolock = False, updated_badpw = False;
+
+ if (!user_info || !auth_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* the returned struct gets kept on the server_info, by means
+ of a steal further down */
+
+ if ( !(sampass = samu_new( mem_ctx )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* get the account information */
+
+ become_root();
+ ret = pdb_getsampwnam(sampass, user_info->internal_username);
+ unbecome_root();
+
+ if (ret == False) {
+ DEBUG(3,("check_sam_security: Couldn't find user '%s' in "
+ "passdb.\n", user_info->internal_username));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* see if autolock flag needs to be updated */
+ if (pdb_get_acct_ctrl(sampass) & ACB_NORMAL)
+ pdb_update_autolock_flag(sampass, &updated_autolock);
+ /* Quit if the account was locked out. */
+ if (pdb_get_acct_ctrl(sampass) & ACB_AUTOLOCK) {
+ DEBUG(3,("check_sam_security: Account for user %s was locked out.\n", pdb_get_username(sampass)));
+ return NT_STATUS_ACCOUNT_LOCKED_OUT;
+ }
+
+ nt_status = sam_password_ok(auth_context, mem_ctx, sampass,
+ user_info, &user_sess_key, &lm_sess_key);
+
+ /* Notify passdb backend of login success/failure. If not
+ NT_STATUS_OK the backend doesn't like the login */
+
+ update_login_attempts_status = pdb_update_login_attempts(sampass, NT_STATUS_IS_OK(nt_status));
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ if (NT_STATUS_EQUAL(nt_status,NT_STATUS_WRONG_PASSWORD) &&
+ pdb_get_acct_ctrl(sampass) &ACB_NORMAL &&
+ NT_STATUS_IS_OK(update_login_attempts_status))
+ {
+ pdb_increment_bad_password_count(sampass);
+ updated_badpw = True;
+ } else {
+ pdb_update_bad_password_count(sampass,
+ &updated_badpw);
+ }
+ if (updated_autolock || updated_badpw){
+ become_root();
+ if(!NT_STATUS_IS_OK(pdb_update_sam_account(sampass)))
+ DEBUG(1, ("Failed to modify entry.\n"));
+ unbecome_root();
+ }
+ data_blob_free(&user_sess_key);
+ data_blob_free(&lm_sess_key);
+ TALLOC_FREE(sampass);
+ return nt_status;
+ }
+
+ if ((pdb_get_acct_ctrl(sampass) & ACB_NORMAL) &&
+ (pdb_get_bad_password_count(sampass) > 0)){
+ pdb_set_bad_password_count(sampass, 0, PDB_CHANGED);
+ pdb_set_bad_password_time(sampass, 0, PDB_CHANGED);
+ updated_badpw = True;
+ }
+
+ if (updated_autolock || updated_badpw){
+ become_root();
+ if(!NT_STATUS_IS_OK(pdb_update_sam_account(sampass)))
+ DEBUG(1, ("Failed to modify entry.\n"));
+ unbecome_root();
+ }
+
+ nt_status = sam_account_ok(mem_ctx, sampass, user_info);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ TALLOC_FREE(sampass);
+ data_blob_free(&user_sess_key);
+ data_blob_free(&lm_sess_key);
+ return nt_status;
+ }
+
+ become_root();
+ nt_status = make_server_info_sam(server_info, sampass);
+ unbecome_root();
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0,("check_sam_security: make_server_info_sam() failed with '%s'\n", nt_errstr(nt_status)));
+ data_blob_free(&user_sess_key);
+ data_blob_free(&lm_sess_key);
+ return nt_status;
+ }
+
+ (*server_info)->user_session_key =
+ data_blob_talloc(*server_info, user_sess_key.data,
+ user_sess_key.length);
+ data_blob_free(&user_sess_key);
+
+ (*server_info)->lm_session_key =
+ data_blob_talloc(*server_info, lm_sess_key.data,
+ lm_sess_key.length);
+ data_blob_free(&lm_sess_key);
+
+ (*server_info)->nss_token |= user_info->was_mapped;
+
+ return nt_status;
+}
+
+/* module initialisation */
+static NTSTATUS auth_init_sam_ignoredomain(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_context, auth_method)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*auth_method)->auth = check_sam_security;
+ (*auth_method)->name = "sam_ignoredomain";
+ return NT_STATUS_OK;
+}
+
+
+/****************************************************************************
+Check SAM security (above) but with a few extra checks.
+****************************************************************************/
+
+static NTSTATUS check_samstrict_security(const struct auth_context *auth_context,
+ void *my_private_data,
+ TALLOC_CTX *mem_ctx,
+ const auth_usersupplied_info *user_info,
+ auth_serversupplied_info **server_info)
+{
+ bool is_local_name, is_my_domain;
+
+ if (!user_info || !auth_context) {
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ is_local_name = is_myname(user_info->domain);
+ is_my_domain = strequal(user_info->domain, lp_workgroup());
+
+ /* check whether or not we service this domain/workgroup name */
+
+ switch ( lp_server_role() ) {
+ case ROLE_STANDALONE:
+ case ROLE_DOMAIN_MEMBER:
+ if ( !is_local_name ) {
+ DEBUG(6,("check_samstrict_security: %s is not one of my local names (%s)\n",
+ user_info->domain, (lp_server_role() == ROLE_DOMAIN_MEMBER
+ ? "ROLE_DOMAIN_MEMBER" : "ROLE_STANDALONE") ));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ case ROLE_DOMAIN_PDC:
+ case ROLE_DOMAIN_BDC:
+ if ( !is_local_name && !is_my_domain ) {
+ DEBUG(6,("check_samstrict_security: %s is not one of my local names or domain name (DC)\n",
+ user_info->domain));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ default: /* name is ok */
+ break;
+ }
+
+ return check_sam_security(auth_context, my_private_data, mem_ctx, user_info, server_info);
+}
+
+/* module initialisation */
+static NTSTATUS auth_init_sam(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_context, auth_method)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*auth_method)->auth = check_samstrict_security;
+ (*auth_method)->name = "sam";
+ return NT_STATUS_OK;
+}
+
+NTSTATUS auth_sam_init(void)
+{
+ smb_register_auth(AUTH_INTERFACE_VERSION, "sam", auth_init_sam);
+ smb_register_auth(AUTH_INTERFACE_VERSION, "sam_ignoredomain", auth_init_sam_ignoredomain);
+ return NT_STATUS_OK;
+}
diff --git a/source3/auth/auth_script.c b/source3/auth/auth_script.c
new file mode 100644
index 0000000000..6cbace71e8
--- /dev/null
+++ b/source3/auth/auth_script.c
@@ -0,0 +1,147 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Call out to a shell script for an authentication check.
+
+ Copyright (C) Jeremy Allison 2005.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef malloc
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+/* Create a string containing the supplied :
+ * domain\n
+ * user\n
+ * ascii hex challenge\n
+ * ascii hex LM response\n
+ * ascii hex NT response\n\0
+ * and execute a shell script to check this.
+ * Allows external programs to create users on demand.
+ * Script returns zero on success, non-zero on fail.
+ */
+
+static NTSTATUS script_check_user_credentials(const struct auth_context *auth_context,
+ void *my_private_data,
+ TALLOC_CTX *mem_ctx,
+ const auth_usersupplied_info *user_info,
+ auth_serversupplied_info **server_info)
+{
+ const char *script = lp_parm_const_string( GLOBAL_SECTION_SNUM, "auth_script", "script", NULL);
+ char *secret_str;
+ size_t secret_str_len;
+ char hex_str[49];
+ int ret, i;
+
+ if (!script) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!user_info) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!auth_context) {
+ DEBUG(3,("script_check_user_credentials: no auth_info !\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ secret_str_len = strlen(user_info->domain) + 1 +
+ strlen(user_info->smb_name) + 1 +
+ 16 + 1 + /* 8 bytes of challenge going to 16 */
+ 48 + 1 + /* 24 bytes of challenge going to 48 */
+ 48 + 1;
+
+ secret_str = (char *)malloc(secret_str_len);
+ if (!secret_str) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ safe_strcpy( secret_str, user_info->domain, secret_str_len - 1);
+ safe_strcat( secret_str, "\n", secret_str_len - 1);
+ safe_strcat( secret_str, user_info->smb_name, secret_str_len - 1);
+ safe_strcat( secret_str, "\n", secret_str_len - 1);
+
+ for (i = 0; i < 8; i++) {
+ slprintf(&hex_str[i*2], 3, "%02X", auth_context->challenge.data[i]);
+ }
+ safe_strcat( secret_str, hex_str, secret_str_len - 1);
+ safe_strcat( secret_str, "\n", secret_str_len - 1);
+
+ if (user_info->lm_resp.data) {
+ for (i = 0; i < 24; i++) {
+ slprintf(&hex_str[i*2], 3, "%02X", user_info->lm_resp.data[i]);
+ }
+ safe_strcat( secret_str, hex_str, secret_str_len - 1);
+ }
+ safe_strcat( secret_str, "\n", secret_str_len - 1);
+
+ if (user_info->nt_resp.data) {
+ for (i = 0; i < 24; i++) {
+ slprintf(&hex_str[i*2], 3, "%02X", user_info->nt_resp.data[i]);
+ }
+ safe_strcat( secret_str, hex_str, secret_str_len - 1);
+ }
+ safe_strcat( secret_str, "\n", secret_str_len - 1);
+
+ DEBUG(10,("script_check_user_credentials: running %s with parameters:\n%s\n",
+ script, secret_str ));
+
+ ret = smbrunsecret( script, secret_str);
+
+ SAFE_FREE(secret_str);
+
+ if (ret) {
+ DEBUG(1,("script_check_user_credentials: failed to authenticate %s\\%s\n",
+ user_info->domain, user_info->smb_name ));
+ /* auth failed. */
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* Cause the auth system to keep going.... */
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/* module initialisation */
+static NTSTATUS auth_init_script(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_context, auth_method)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*auth_method)->name = "script";
+ (*auth_method)->auth = script_check_user_credentials;
+
+ if (param && *param) {
+ /* we load the 'fallback' module - if script isn't here, call this
+ module */
+ auth_methods *priv;
+ if (!load_auth_module(auth_context, param, &priv)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ (*auth_method)->private_data = (void *)priv;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS auth_script_init(void);
+NTSTATUS auth_script_init(void)
+{
+ return smb_register_auth(AUTH_INTERFACE_VERSION, "script", auth_init_script);
+}
diff --git a/source3/auth/auth_server.c b/source3/auth/auth_server.c
new file mode 100644
index 0000000000..696b42621e
--- /dev/null
+++ b/source3/auth/auth_server.c
@@ -0,0 +1,466 @@
+/*
+ Unix SMB/CIFS implementation.
+ Authenticate to a remote server
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+extern userdom_struct current_user_info;
+
+/****************************************************************************
+ Support for server level security.
+****************************************************************************/
+
+static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx)
+{
+ struct cli_state *cli = NULL;
+ char *desthost = NULL;
+ struct sockaddr_storage dest_ss;
+ const char *p;
+ char *pserver = NULL;
+ bool connected_ok = False;
+ struct named_mutex *mutex = NULL;
+
+ if (!(cli = cli_initialise()))
+ return NULL;
+
+ /* security = server just can't function with spnego */
+ cli->use_spnego = False;
+
+ pserver = talloc_strdup(mem_ctx, lp_passwordserver());
+ p = pserver;
+
+ while(next_token_talloc(mem_ctx, &p, &desthost, LIST_SEP)) {
+ NTSTATUS status;
+
+ desthost = talloc_sub_basic(mem_ctx,
+ current_user_info.smb_name,
+ current_user_info.domain,
+ desthost);
+ if (!desthost) {
+ return NULL;
+ }
+ strupper_m(desthost);
+
+ if(!resolve_name( desthost, &dest_ss, 0x20)) {
+ DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
+ continue;
+ }
+
+ if (ismyaddr(&dest_ss)) {
+ DEBUG(1,("Password server loop - disabling password server %s\n",desthost));
+ continue;
+ }
+
+ /* we use a mutex to prevent two connections at once - when a
+ Win2k PDC get two connections where one hasn't completed a
+ session setup yet it will send a TCP reset to the first
+ connection (tridge) */
+
+ mutex = grab_named_mutex(talloc_tos(), desthost, 10);
+ if (mutex == NULL) {
+ cli_shutdown(cli);
+ return NULL;
+ }
+
+ status = cli_connect(cli, desthost, &dest_ss);
+ if (NT_STATUS_IS_OK(status)) {
+ DEBUG(3,("connected to password server %s\n",desthost));
+ connected_ok = True;
+ break;
+ }
+ DEBUG(10,("server_cryptkey: failed to connect to server %s. Error %s\n",
+ desthost, nt_errstr(status) ));
+ TALLOC_FREE(mutex);
+ }
+
+ if (!connected_ok) {
+ DEBUG(0,("password server not available\n"));
+ cli_shutdown(cli);
+ return NULL;
+ }
+
+ if (!attempt_netbios_session_request(&cli, global_myname(),
+ desthost, &dest_ss)) {
+ TALLOC_FREE(mutex);
+ DEBUG(1,("password server fails session request\n"));
+ cli_shutdown(cli);
+ return NULL;
+ }
+
+ if (strequal(desthost,myhostname())) {
+ exit_server_cleanly("Password server loop!");
+ }
+
+ DEBUG(3,("got session\n"));
+
+ if (!cli_negprot(cli)) {
+ TALLOC_FREE(mutex);
+ DEBUG(1,("%s rejected the negprot\n",desthost));
+ cli_shutdown(cli);
+ return NULL;
+ }
+
+ if (cli->protocol < PROTOCOL_LANMAN2 ||
+ !(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
+ TALLOC_FREE(mutex);
+ DEBUG(1,("%s isn't in user level security mode\n",desthost));
+ cli_shutdown(cli);
+ return NULL;
+ }
+
+ /* Get the first session setup done quickly, to avoid silly
+ Win2k bugs. (The next connection to the server will kill
+ this one...
+ */
+
+ if (!NT_STATUS_IS_OK(cli_session_setup(cli, "", "", 0, "", 0,
+ ""))) {
+ TALLOC_FREE(mutex);
+ DEBUG(0,("%s rejected the initial session setup (%s)\n",
+ desthost, cli_errstr(cli)));
+ cli_shutdown(cli);
+ return NULL;
+ }
+
+ TALLOC_FREE(mutex);
+
+ DEBUG(3,("password server OK\n"));
+
+ return cli;
+}
+
+struct server_security_state {
+ struct cli_state *cli;
+};
+
+/****************************************************************************
+ Send a 'keepalive' packet down the cli pipe.
+****************************************************************************/
+
+static bool send_server_keepalive(const struct timeval *now,
+ void *private_data)
+{
+ struct server_security_state *state = talloc_get_type_abort(
+ private_data, struct server_security_state);
+
+ if (!state->cli || !state->cli->initialised) {
+ return False;
+ }
+
+ if (send_keepalive(state->cli->fd)) {
+ return True;
+ }
+
+ DEBUG( 2, ( "send_server_keepalive: password server keepalive "
+ "failed.\n"));
+ cli_shutdown(state->cli);
+ state->cli = NULL;
+ return False;
+}
+
+static int destroy_server_security(struct server_security_state *state)
+{
+ if (state->cli) {
+ cli_shutdown(state->cli);
+ }
+ return 0;
+}
+
+static struct server_security_state *make_server_security_state(struct cli_state *cli)
+{
+ struct server_security_state *result;
+
+ if (!(result = talloc(NULL, struct server_security_state))) {
+ DEBUG(0, ("talloc failed\n"));
+ cli_shutdown(cli);
+ return NULL;
+ }
+
+ result->cli = cli;
+ talloc_set_destructor(result, destroy_server_security);
+
+ if (lp_keepalive() != 0) {
+ struct timeval interval;
+ interval.tv_sec = lp_keepalive();
+ interval.tv_usec = 0;
+
+ if (event_add_idle(smbd_event_context(), result, interval,
+ "server_security_keepalive",
+ send_server_keepalive,
+ result) == NULL) {
+ DEBUG(0, ("event_add_idle failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+ }
+
+ return result;
+}
+
+/****************************************************************************
+ Get the challenge out of a password server.
+****************************************************************************/
+
+static DATA_BLOB auth_get_challenge_server(const struct auth_context *auth_context,
+ void **my_private_data,
+ TALLOC_CTX *mem_ctx)
+{
+ struct cli_state *cli = server_cryptkey(mem_ctx);
+
+ if (cli) {
+ DEBUG(3,("using password server validation\n"));
+
+ if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
+ /* We can't work with unencrypted password servers
+ unless 'encrypt passwords = no' */
+ DEBUG(5,("make_auth_info_server: Server is unencrypted, no challenge available..\n"));
+
+ /* However, it is still a perfectly fine connection
+ to pass that unencrypted password over */
+ *my_private_data =
+ (void *)make_server_security_state(cli);
+ return data_blob_null;
+ } else if (cli->secblob.length < 8) {
+ /* We can't do much if we don't get a full challenge */
+ DEBUG(2,("make_auth_info_server: Didn't receive a full challenge from server\n"));
+ cli_shutdown(cli);
+ return data_blob_null;
+ }
+
+ if (!(*my_private_data = (void *)make_server_security_state(cli))) {
+ return data_blob(NULL,0);
+ }
+
+ /* The return must be allocated on the caller's mem_ctx, as our own will be
+ destoyed just after the call. */
+ return data_blob_talloc(auth_context->mem_ctx, cli->secblob.data,8);
+ } else {
+ return data_blob_null;
+ }
+}
+
+
+/****************************************************************************
+ Check for a valid username and password in security=server mode.
+ - Validate a password with the password server.
+****************************************************************************/
+
+static NTSTATUS check_smbserver_security(const struct auth_context *auth_context,
+ void *my_private_data,
+ TALLOC_CTX *mem_ctx,
+ const auth_usersupplied_info *user_info,
+ auth_serversupplied_info **server_info)
+{
+ struct server_security_state *state = talloc_get_type_abort(
+ my_private_data, struct server_security_state);
+ struct cli_state *cli;
+ static bool tested_password_server = False;
+ static bool bad_password_server = False;
+ NTSTATUS nt_status = NT_STATUS_NOT_IMPLEMENTED;
+ bool locally_made_cli = False;
+
+ cli = state->cli;
+
+ if (cli) {
+ } else {
+ cli = server_cryptkey(mem_ctx);
+ locally_made_cli = True;
+ }
+
+ if (!cli || !cli->initialised) {
+ DEBUG(1,("password server is not connected (cli not initialised)\n"));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
+ if (user_info->encrypted) {
+ DEBUG(1,("password server %s is plaintext, but we are encrypted. This just can't work :-(\n", cli->desthost));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ } else {
+ if (memcmp(cli->secblob.data, auth_context->challenge.data, 8) != 0) {
+ DEBUG(1,("the challenge that the password server (%s) supplied us is not the one we gave our client. This just can't work :-(\n", cli->desthost));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ }
+
+ /*
+ * Attempt a session setup with a totally incorrect password.
+ * If this succeeds with the guest bit *NOT* set then the password
+ * server is broken and is not correctly setting the guest bit. We
+ * need to detect this as some versions of NT4.x are broken. JRA.
+ */
+
+ /* I sure as hell hope that there aren't servers out there that take
+ * NTLMv2 and have this bug, as we don't test for that...
+ * - abartlet@samba.org
+ */
+
+ if ((!tested_password_server) && (lp_paranoid_server_security())) {
+ unsigned char badpass[24];
+ char *baduser = NULL;
+
+ memset(badpass, 0x1f, sizeof(badpass));
+
+ if((user_info->nt_resp.length == sizeof(badpass)) &&
+ !memcmp(badpass, user_info->nt_resp.data, sizeof(badpass))) {
+ /*
+ * Very unlikely, our random bad password is the same as the users
+ * password.
+ */
+ memset(badpass, badpass[0]+1, sizeof(badpass));
+ }
+
+ baduser = talloc_asprintf(mem_ctx,
+ "%s%s",
+ INVALID_USER_PREFIX,
+ global_myname());
+ if (!baduser) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (NT_STATUS_IS_OK(cli_session_setup(cli, baduser,
+ (char *)badpass,
+ sizeof(badpass),
+ (char *)badpass,
+ sizeof(badpass),
+ user_info->domain))) {
+
+ /*
+ * We connected to the password server so we
+ * can say we've tested it.
+ */
+ tested_password_server = True;
+
+ if ((SVAL(cli->inbuf,smb_vwv2) & 1) == 0) {
+ DEBUG(0,("server_validate: password server %s allows users as non-guest \
+with a bad password.\n", cli->desthost));
+ DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \
+use this machine as the password server.\n"));
+ cli_ulogoff(cli);
+
+ /*
+ * Password server has the bug.
+ */
+ bad_password_server = True;
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ cli_ulogoff(cli);
+ }
+ } else {
+
+ /*
+ * We have already tested the password server.
+ * Fail immediately if it has the bug.
+ */
+
+ if(bad_password_server) {
+ DEBUG(0,("server_validate: [1] password server %s allows users as non-guest \
+with a bad password.\n", cli->desthost));
+ DEBUG(0,("server_validate: [1] This is broken (and insecure) behaviour. Please do not \
+use this machine as the password server.\n"));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ }
+
+ /*
+ * Now we know the password server will correctly set the guest bit, or is
+ * not guest enabled, we can try with the real password.
+ */
+
+ if (!user_info->encrypted) {
+ /* Plaintext available */
+ nt_status = cli_session_setup(
+ cli, user_info->smb_name,
+ (char *)user_info->plaintext_password.data,
+ user_info->plaintext_password.length,
+ NULL, 0, user_info->domain);
+
+ } else {
+ nt_status = cli_session_setup(
+ cli, user_info->smb_name,
+ (char *)user_info->lm_resp.data,
+ user_info->lm_resp.length,
+ (char *)user_info->nt_resp.data,
+ user_info->nt_resp.length,
+ user_info->domain);
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1,("password server %s rejected the password: %s\n",
+ cli->desthost, nt_errstr(nt_status)));
+ }
+
+ /* if logged in as guest then reject */
+ if ((SVAL(cli->inbuf,smb_vwv2) & 1) != 0) {
+ DEBUG(1,("password server %s gave us guest only\n", cli->desthost));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ }
+
+ cli_ulogoff(cli);
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ fstring real_username;
+ struct passwd *pass;
+
+ if ( (pass = smb_getpwnam( NULL, user_info->internal_username,
+ real_username, True )) != NULL )
+ {
+ /* if a real user check pam account restrictions */
+ /* only really perfomed if "obey pam restriction" is true */
+ nt_status = smb_pam_accountcheck(pass->pw_name);
+ if ( !NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1, ("PAM account restriction prevents user login\n"));
+ } else {
+
+ nt_status = make_server_info_pw(server_info, pass->pw_name, pass);
+ }
+ TALLOC_FREE(pass);
+ }
+ else
+ {
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ }
+ }
+
+ if (locally_made_cli) {
+ cli_shutdown(cli);
+ }
+
+ return(nt_status);
+}
+
+static NTSTATUS auth_init_smbserver(struct auth_context *auth_context, const char* param, auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_context, auth_method)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ (*auth_method)->name = "smbserver";
+ (*auth_method)->auth = check_smbserver_security;
+ (*auth_method)->get_chal = auth_get_challenge_server;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS auth_server_init(void)
+{
+ return smb_register_auth(AUTH_INTERFACE_VERSION, "smbserver", auth_init_smbserver);
+}
diff --git a/source3/auth/auth_unix.c b/source3/auth/auth_unix.c
new file mode 100644
index 0000000000..58c765226d
--- /dev/null
+++ b/source3/auth/auth_unix.c
@@ -0,0 +1,145 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+/**
+ * update the encrypted smbpasswd file from the plaintext username and password
+ *
+ * this ugly hack needs to die, but not quite yet, I think people still use it...
+ **/
+static bool update_smbpassword_file(const char *user, const char *password)
+{
+ struct samu *sampass;
+ bool ret;
+
+ if ( !(sampass = samu_new( NULL )) ) {
+ return False;
+ }
+
+ become_root();
+ ret = pdb_getsampwnam(sampass, user);
+ unbecome_root();
+
+ if(ret == False) {
+ DEBUG(0,("pdb_getsampwnam returned NULL\n"));
+ TALLOC_FREE(sampass);
+ return False;
+ }
+
+ /*
+ * Remove the account disabled flag - we are updating the
+ * users password from a login.
+ */
+ if (!pdb_set_acct_ctrl(sampass, pdb_get_acct_ctrl(sampass) & ~ACB_DISABLED, PDB_CHANGED)) {
+ TALLOC_FREE(sampass);
+ return False;
+ }
+
+ if (!pdb_set_plaintext_passwd (sampass, password)) {
+ TALLOC_FREE(sampass);
+ return False;
+ }
+
+ /* Now write it into the file. */
+ become_root();
+
+ ret = NT_STATUS_IS_OK(pdb_update_sam_account (sampass));
+
+ unbecome_root();
+
+ if (ret) {
+ DEBUG(3,("pdb_update_sam_account returned %d\n",ret));
+ }
+
+ TALLOC_FREE(sampass);
+ return ret;
+}
+
+
+/** Check a plaintext username/password
+ *
+ * Cannot deal with an encrupted password in any manner whatsoever,
+ * unless the account has a null password.
+ **/
+
+static NTSTATUS check_unix_security(const struct auth_context *auth_context,
+ void *my_private_data,
+ TALLOC_CTX *mem_ctx,
+ const auth_usersupplied_info *user_info,
+ auth_serversupplied_info **server_info)
+{
+ NTSTATUS nt_status;
+ struct passwd *pass = NULL;
+
+ become_root();
+ pass = Get_Pwnam_alloc(talloc_tos(), user_info->internal_username);
+
+
+ /** @todo This call assumes a ASCII password, no charset transformation is
+ done. We may need to revisit this **/
+ nt_status = pass_check(pass,
+ pass ? pass->pw_name : user_info->internal_username,
+ (char *)user_info->plaintext_password.data,
+ user_info->plaintext_password.length-1,
+ lp_update_encrypted() ?
+ update_smbpassword_file : NULL,
+ True);
+
+ unbecome_root();
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ if (pass) {
+ /* if a real user check pam account restrictions */
+ /* only really perfomed if "obey pam restriction" is true */
+ nt_status = smb_pam_accountcheck(pass->pw_name);
+ if ( !NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1, ("PAM account restriction prevents user login\n"));
+ } else {
+ make_server_info_pw(server_info, pass->pw_name, pass);
+ }
+ } else {
+ /* we need to do somthing more useful here */
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ }
+ }
+
+ TALLOC_FREE(pass);
+ return nt_status;
+}
+
+/* module initialisation */
+static NTSTATUS auth_init_unix(struct auth_context *auth_context, const char* param, auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_context, auth_method)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*auth_method)->name = "unix";
+ (*auth_method)->auth = check_unix_security;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS auth_unix_init(void)
+{
+ return smb_register_auth(AUTH_INTERFACE_VERSION, "unix", auth_init_unix);
+}
diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c
new file mode 100644
index 0000000000..9220df01c0
--- /dev/null
+++ b/source3/auth/auth_util.c
@@ -0,0 +1,2166 @@
+/*
+ Unix SMB/CIFS implementation.
+ Authentication utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Andrew Bartlett 2001
+ Copyright (C) Jeremy Allison 2000-2001
+ Copyright (C) Rafal Szczesniak 2002
+ Copyright (C) Volker Lendecke 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+/****************************************************************************
+ Ensure primary group SID is always at position 0 in a
+ auth_serversupplied_info struct.
+****************************************************************************/
+
+static void sort_sid_array_for_smbd(auth_serversupplied_info *result,
+ const DOM_SID *pgroup_sid)
+{
+ unsigned int i;
+
+ if (!result->sids) {
+ return;
+ }
+
+ if (sid_compare(&result->sids[0], pgroup_sid)==0) {
+ return;
+ }
+
+ for (i = 1; i < result->num_sids; i++) {
+ if (sid_compare(pgroup_sid,
+ &result->sids[i]) == 0) {
+ sid_copy(&result->sids[i], &result->sids[0]);
+ sid_copy(&result->sids[0], pgroup_sid);
+ return;
+ }
+ }
+}
+
+/****************************************************************************
+ Create a UNIX user on demand.
+****************************************************************************/
+
+static int smb_create_user(const char *domain, const char *unix_username, const char *homedir)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *add_script;
+ int ret;
+
+ add_script = talloc_strdup(ctx, lp_adduser_script());
+ if (!add_script || !*add_script) {
+ return -1;
+ }
+ add_script = talloc_all_string_sub(ctx,
+ add_script,
+ "%u",
+ unix_username);
+ if (!add_script) {
+ return -1;
+ }
+ if (domain) {
+ add_script = talloc_all_string_sub(ctx,
+ add_script,
+ "%D",
+ domain);
+ if (!add_script) {
+ return -1;
+ }
+ }
+ if (homedir) {
+ add_script = talloc_all_string_sub(ctx,
+ add_script,
+ "%H",
+ homedir);
+ if (!add_script) {
+ return -1;
+ }
+ }
+ ret = smbrun(add_script,NULL);
+ flush_pwnam_cache();
+ DEBUG(ret ? 0 : 3,
+ ("smb_create_user: Running the command `%s' gave %d\n",
+ add_script,ret));
+ return ret;
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data structure
+****************************************************************************/
+
+static NTSTATUS make_user_info(auth_usersupplied_info **user_info,
+ const char *smb_name,
+ const char *internal_username,
+ const char *client_domain,
+ const char *domain,
+ const char *wksta_name,
+ DATA_BLOB *lm_pwd, DATA_BLOB *nt_pwd,
+ DATA_BLOB *lm_interactive_pwd, DATA_BLOB *nt_interactive_pwd,
+ DATA_BLOB *plaintext,
+ bool encrypted)
+{
+
+ DEBUG(5,("attempting to make a user_info for %s (%s)\n", internal_username, smb_name));
+
+ *user_info = SMB_MALLOC_P(auth_usersupplied_info);
+ if (*user_info == NULL) {
+ DEBUG(0,("malloc failed for user_info (size %lu)\n", (unsigned long)sizeof(*user_info)));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCTP(*user_info);
+
+ DEBUG(5,("making strings for %s's user_info struct\n", internal_username));
+
+ (*user_info)->smb_name = SMB_STRDUP(smb_name);
+ if ((*user_info)->smb_name == NULL) {
+ free_user_info(user_info);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*user_info)->internal_username = SMB_STRDUP(internal_username);
+ if ((*user_info)->internal_username == NULL) {
+ free_user_info(user_info);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*user_info)->domain = SMB_STRDUP(domain);
+ if ((*user_info)->domain == NULL) {
+ free_user_info(user_info);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*user_info)->client_domain = SMB_STRDUP(client_domain);
+ if ((*user_info)->client_domain == NULL) {
+ free_user_info(user_info);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*user_info)->wksta_name = SMB_STRDUP(wksta_name);
+ if ((*user_info)->wksta_name == NULL) {
+ free_user_info(user_info);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(5,("making blobs for %s's user_info struct\n", internal_username));
+
+ if (lm_pwd)
+ (*user_info)->lm_resp = data_blob(lm_pwd->data, lm_pwd->length);
+ if (nt_pwd)
+ (*user_info)->nt_resp = data_blob(nt_pwd->data, nt_pwd->length);
+ if (lm_interactive_pwd)
+ (*user_info)->lm_interactive_pwd = data_blob(lm_interactive_pwd->data, lm_interactive_pwd->length);
+ if (nt_interactive_pwd)
+ (*user_info)->nt_interactive_pwd = data_blob(nt_interactive_pwd->data, nt_interactive_pwd->length);
+
+ if (plaintext)
+ (*user_info)->plaintext_password = data_blob(plaintext->data, plaintext->length);
+
+ (*user_info)->encrypted = encrypted;
+
+ (*user_info)->logon_parameters = 0;
+
+ DEBUG(10,("made an %sencrypted user_info for %s (%s)\n", encrypted ? "":"un" , internal_username, smb_name));
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data structure after appropriate mapping.
+****************************************************************************/
+
+NTSTATUS make_user_info_map(auth_usersupplied_info **user_info,
+ const char *smb_name,
+ const char *client_domain,
+ const char *wksta_name,
+ DATA_BLOB *lm_pwd, DATA_BLOB *nt_pwd,
+ DATA_BLOB *lm_interactive_pwd, DATA_BLOB *nt_interactive_pwd,
+ DATA_BLOB *plaintext,
+ bool encrypted)
+{
+ const char *domain;
+ NTSTATUS result;
+ bool was_mapped;
+ fstring internal_username;
+ fstrcpy(internal_username, smb_name);
+ was_mapped = map_username(internal_username);
+
+ DEBUG(5, ("make_user_info_map: Mapping user [%s]\\[%s] from workstation [%s]\n",
+ client_domain, smb_name, wksta_name));
+
+ /* don't allow "" as a domain, fixes a Win9X bug
+ where it doens't supply a domain for logon script
+ 'net use' commands. */
+
+ if ( *client_domain )
+ domain = client_domain;
+ else
+ domain = lp_workgroup();
+
+ /* do what win2k does. Always map unknown domains to our own
+ and let the "passdb backend" handle unknown users. */
+
+ if ( !is_trusted_domain(domain) && !strequal(domain, get_global_sam_name()) )
+ domain = my_sam_name();
+
+ /* we know that it is a trusted domain (and we are allowing them) or it is our domain */
+
+ result = make_user_info(user_info, smb_name, internal_username,
+ client_domain, domain, wksta_name,
+ lm_pwd, nt_pwd,
+ lm_interactive_pwd, nt_interactive_pwd,
+ plaintext, encrypted);
+ if (NT_STATUS_IS_OK(result)) {
+ (*user_info)->was_mapped = was_mapped;
+ }
+ return result;
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data, making the DATA_BLOBs here.
+ Decrypt and encrypt the passwords.
+****************************************************************************/
+
+bool make_user_info_netlogon_network(auth_usersupplied_info **user_info,
+ const char *smb_name,
+ const char *client_domain,
+ const char *wksta_name,
+ uint32 logon_parameters,
+ const uchar *lm_network_pwd,
+ int lm_pwd_len,
+ const uchar *nt_network_pwd,
+ int nt_pwd_len)
+{
+ bool ret;
+ NTSTATUS status;
+ DATA_BLOB lm_blob = data_blob(lm_network_pwd, lm_pwd_len);
+ DATA_BLOB nt_blob = data_blob(nt_network_pwd, nt_pwd_len);
+
+ status = make_user_info_map(user_info,
+ smb_name, client_domain,
+ wksta_name,
+ lm_pwd_len ? &lm_blob : NULL,
+ nt_pwd_len ? &nt_blob : NULL,
+ NULL, NULL, NULL,
+ True);
+
+ if (NT_STATUS_IS_OK(status)) {
+ (*user_info)->logon_parameters = logon_parameters;
+ }
+ ret = NT_STATUS_IS_OK(status) ? True : False;
+
+ data_blob_free(&lm_blob);
+ data_blob_free(&nt_blob);
+ return ret;
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data, making the DATA_BLOBs here.
+ Decrypt and encrypt the passwords.
+****************************************************************************/
+
+bool make_user_info_netlogon_interactive(auth_usersupplied_info **user_info,
+ const char *smb_name,
+ const char *client_domain,
+ const char *wksta_name,
+ uint32 logon_parameters,
+ const uchar chal[8],
+ const uchar lm_interactive_pwd[16],
+ const uchar nt_interactive_pwd[16],
+ const uchar *dc_sess_key)
+{
+ unsigned char lm_pwd[16];
+ unsigned char nt_pwd[16];
+ unsigned char local_lm_response[24];
+ unsigned char local_nt_response[24];
+ unsigned char key[16];
+
+ ZERO_STRUCT(key);
+ memcpy(key, dc_sess_key, 8);
+
+ if (lm_interactive_pwd)
+ memcpy(lm_pwd, lm_interactive_pwd, sizeof(lm_pwd));
+
+ if (nt_interactive_pwd)
+ memcpy(nt_pwd, nt_interactive_pwd, sizeof(nt_pwd));
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("key:"));
+ dump_data(100, key, sizeof(key));
+
+ DEBUG(100,("lm owf password:"));
+ dump_data(100, lm_pwd, sizeof(lm_pwd));
+
+ DEBUG(100,("nt owf password:"));
+ dump_data(100, nt_pwd, sizeof(nt_pwd));
+#endif
+
+ if (lm_interactive_pwd)
+ SamOEMhash(lm_pwd, key, sizeof(lm_pwd));
+
+ if (nt_interactive_pwd)
+ SamOEMhash(nt_pwd, key, sizeof(nt_pwd));
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("decrypt of lm owf password:"));
+ dump_data(100, lm_pwd, sizeof(lm_pwd));
+
+ DEBUG(100,("decrypt of nt owf password:"));
+ dump_data(100, nt_pwd, sizeof(nt_pwd));
+#endif
+
+ if (lm_interactive_pwd)
+ SMBOWFencrypt(lm_pwd, chal,
+ local_lm_response);
+
+ if (nt_interactive_pwd)
+ SMBOWFencrypt(nt_pwd, chal,
+ local_nt_response);
+
+ /* Password info paranoia */
+ ZERO_STRUCT(key);
+
+ {
+ bool ret;
+ NTSTATUS nt_status;
+ DATA_BLOB local_lm_blob;
+ DATA_BLOB local_nt_blob;
+
+ DATA_BLOB lm_interactive_blob;
+ DATA_BLOB nt_interactive_blob;
+
+ if (lm_interactive_pwd) {
+ local_lm_blob = data_blob(local_lm_response,
+ sizeof(local_lm_response));
+ lm_interactive_blob = data_blob(lm_pwd,
+ sizeof(lm_pwd));
+ ZERO_STRUCT(lm_pwd);
+ }
+
+ if (nt_interactive_pwd) {
+ local_nt_blob = data_blob(local_nt_response,
+ sizeof(local_nt_response));
+ nt_interactive_blob = data_blob(nt_pwd,
+ sizeof(nt_pwd));
+ ZERO_STRUCT(nt_pwd);
+ }
+
+ nt_status = make_user_info_map(
+ user_info,
+ smb_name, client_domain, wksta_name,
+ lm_interactive_pwd ? &local_lm_blob : NULL,
+ nt_interactive_pwd ? &local_nt_blob : NULL,
+ lm_interactive_pwd ? &lm_interactive_blob : NULL,
+ nt_interactive_pwd ? &nt_interactive_blob : NULL,
+ NULL, True);
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ (*user_info)->logon_parameters = logon_parameters;
+ }
+
+ ret = NT_STATUS_IS_OK(nt_status) ? True : False;
+ data_blob_free(&local_lm_blob);
+ data_blob_free(&local_nt_blob);
+ data_blob_free(&lm_interactive_blob);
+ data_blob_free(&nt_interactive_blob);
+ return ret;
+ }
+}
+
+
+/****************************************************************************
+ Create an auth_usersupplied_data structure
+****************************************************************************/
+
+bool make_user_info_for_reply(auth_usersupplied_info **user_info,
+ const char *smb_name,
+ const char *client_domain,
+ const uint8 chal[8],
+ DATA_BLOB plaintext_password)
+{
+
+ DATA_BLOB local_lm_blob;
+ DATA_BLOB local_nt_blob;
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ /*
+ * Not encrypted - do so.
+ */
+
+ DEBUG(5,("make_user_info_for_reply: User passwords not in encrypted "
+ "format.\n"));
+
+ if (plaintext_password.data) {
+ unsigned char local_lm_response[24];
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(10,("Unencrypted password (len %d):\n",
+ (int)plaintext_password.length));
+ dump_data(100, plaintext_password.data,
+ plaintext_password.length);
+#endif
+
+ SMBencrypt( (const char *)plaintext_password.data,
+ (const uchar*)chal, local_lm_response);
+ local_lm_blob = data_blob(local_lm_response, 24);
+
+ /* We can't do an NT hash here, as the password needs to be
+ case insensitive */
+ local_nt_blob = data_blob_null;
+
+ } else {
+ local_lm_blob = data_blob_null;
+ local_nt_blob = data_blob_null;
+ }
+
+ ret = make_user_info_map(
+ user_info, smb_name, client_domain,
+ get_remote_machine_name(),
+ local_lm_blob.data ? &local_lm_blob : NULL,
+ local_nt_blob.data ? &local_nt_blob : NULL,
+ NULL, NULL,
+ plaintext_password.data ? &plaintext_password : NULL,
+ False);
+
+ data_blob_free(&local_lm_blob);
+ return NT_STATUS_IS_OK(ret) ? True : False;
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data structure
+****************************************************************************/
+
+NTSTATUS make_user_info_for_reply_enc(auth_usersupplied_info **user_info,
+ const char *smb_name,
+ const char *client_domain,
+ DATA_BLOB lm_resp, DATA_BLOB nt_resp)
+{
+ return make_user_info_map(user_info, smb_name,
+ client_domain,
+ get_remote_machine_name(),
+ lm_resp.data ? &lm_resp : NULL,
+ nt_resp.data ? &nt_resp : NULL,
+ NULL, NULL, NULL,
+ True);
+}
+
+/****************************************************************************
+ Create a guest user_info blob, for anonymous authenticaion.
+****************************************************************************/
+
+bool make_user_info_guest(auth_usersupplied_info **user_info)
+{
+ NTSTATUS nt_status;
+
+ nt_status = make_user_info(user_info,
+ "","",
+ "","",
+ "",
+ NULL, NULL,
+ NULL, NULL,
+ NULL,
+ True);
+
+ return NT_STATUS_IS_OK(nt_status) ? True : False;
+}
+
+static int server_info_dtor(auth_serversupplied_info *server_info)
+{
+ TALLOC_FREE(server_info->sam_account);
+ ZERO_STRUCTP(server_info);
+ return 0;
+}
+
+/***************************************************************************
+ Make a server_info struct. Free with TALLOC_FREE().
+***************************************************************************/
+
+static auth_serversupplied_info *make_server_info(TALLOC_CTX *mem_ctx)
+{
+ struct auth_serversupplied_info *result;
+
+ result = TALLOC_ZERO_P(mem_ctx, auth_serversupplied_info);
+ if (result == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ talloc_set_destructor(result, server_info_dtor);
+
+ /* Initialise the uid and gid values to something non-zero
+ which may save us from giving away root access if there
+ is a bug in allocating these fields. */
+
+ result->utok.uid = -1;
+ result->utok.gid = -1;
+ return result;
+}
+
+static char *sanitize_username(TALLOC_CTX *mem_ctx, const char *username)
+{
+ fstring tmp;
+
+ alpha_strcpy(tmp, username, ". _-$", sizeof(tmp));
+ return talloc_strdup(mem_ctx, tmp);
+}
+
+/***************************************************************************
+ Is the incoming username our own machine account ?
+ If so, the connection is almost certainly from winbindd.
+***************************************************************************/
+
+static bool is_our_machine_account(const char *username)
+{
+ bool ret;
+ char *truncname = NULL;
+ size_t ulen = strlen(username);
+
+ if (ulen == 0 || username[ulen-1] != '$') {
+ return false;
+ }
+ truncname = SMB_STRDUP(username);
+ if (!truncname) {
+ return false;
+ }
+ truncname[ulen-1] = '\0';
+ ret = strequal(truncname, global_myname());
+ SAFE_FREE(truncname);
+ return ret;
+}
+
+/***************************************************************************
+ Make (and fill) a user_info struct from a struct samu
+***************************************************************************/
+
+NTSTATUS make_server_info_sam(auth_serversupplied_info **server_info,
+ struct samu *sampass)
+{
+ struct passwd *pwd;
+ gid_t *gids;
+ auth_serversupplied_info *result;
+ int i;
+ size_t num_gids;
+ DOM_SID unix_group_sid;
+ const char *username = pdb_get_username(sampass);
+ NTSTATUS status;
+
+ if ( !(result = make_server_info(NULL)) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( !(pwd = getpwnam_alloc(result, username)) ) {
+ DEBUG(1, ("User %s in passdb, but getpwnam() fails!\n",
+ pdb_get_username(sampass)));
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ result->sam_account = sampass;
+ /* Ensure thaat the sampass will be freed with the result */
+ talloc_steal(result, sampass);
+ result->unix_name = pwd->pw_name;
+ /* Ensure that we keep pwd->pw_name, because we will free pwd below */
+ talloc_steal(result, pwd->pw_name);
+ result->utok.gid = pwd->pw_gid;
+ result->utok.uid = pwd->pw_uid;
+
+ TALLOC_FREE(pwd);
+
+ result->sanitized_username = sanitize_username(result,
+ result->unix_name);
+ if (result->sanitized_username == NULL) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (IS_DC && is_our_machine_account(username)) {
+ /*
+ * Ensure for a connection from our own
+ * machine account (from winbindd on a DC)
+ * there are no supplementary groups.
+ * Prevents loops in calling gid_to_sid().
+ */
+ result->sids = NULL;
+ gids = NULL;
+ result->num_sids = 0;
+
+ /*
+ * This is a hack of monstrous proportions.
+ * If we know it's winbindd talking to us,
+ * we know we must never recurse into it,
+ * so turn off contacting winbindd for this
+ * entire process. This will get fixed when
+ * winbindd doesn't need to talk to smbd on
+ * a PDC. JRA.
+ */
+
+ (void)winbind_off();
+
+ DEBUG(10, ("make_server_info_sam: our machine account %s "
+ "setting supplementary group list empty and "
+ "turning off winbindd requests.\n",
+ username));
+ } else {
+ status = pdb_enum_group_memberships(result, sampass,
+ &result->sids, &gids,
+ &result->num_sids);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("pdb_enum_group_memberships failed: %s\n",
+ nt_errstr(status)));
+ result->sam_account = NULL; /* Don't free on error exit. */
+ TALLOC_FREE(result);
+ return status;
+ }
+ }
+
+ /* Add the "Unix Group" SID for each gid to catch mapped groups
+ and their Unix equivalent. This is to solve the backwards
+ compatibility problem of 'valid users = +ntadmin' where
+ ntadmin has been paired with "Domain Admins" in the group
+ mapping table. Otherwise smb.conf would need to be changed
+ to 'valid user = "Domain Admins"'. --jerry */
+
+ num_gids = result->num_sids;
+ for ( i=0; i<num_gids; i++ ) {
+ if ( !gid_to_unix_groups_sid( gids[i], &unix_group_sid ) ) {
+ DEBUG(1,("make_server_info_sam: Failed to create SID "
+ "for gid %d!\n", gids[i]));
+ continue;
+ }
+ status = add_sid_to_array_unique(result, &unix_group_sid,
+ &result->sids,
+ &result->num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ result->sam_account = NULL; /* Don't free on error exit. */
+ TALLOC_FREE(result);
+ return status;
+ }
+ }
+
+ /* For now we throw away the gids and convert via sid_to_gid
+ * later. This needs fixing, but I'd like to get the code straight and
+ * simple first. */
+
+ TALLOC_FREE(gids);
+
+ DEBUG(5,("make_server_info_sam: made server info for user %s -> %s\n",
+ pdb_get_username(sampass), result->unix_name));
+
+ *server_info = result;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS log_nt_token(NT_USER_TOKEN *token)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *command;
+ char *group_sidstr;
+ size_t i;
+
+ if ((lp_log_nt_token_command() == NULL) ||
+ (strlen(lp_log_nt_token_command()) == 0)) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
+
+ group_sidstr = talloc_strdup(frame, "");
+ for (i=1; i<token->num_sids; i++) {
+ group_sidstr = talloc_asprintf(
+ frame, "%s %s", group_sidstr,
+ sid_string_talloc(frame, &token->user_sids[i]));
+ }
+
+ command = talloc_string_sub(
+ frame, lp_log_nt_token_command(),
+ "%s", sid_string_talloc(frame, &token->user_sids[0]));
+ command = talloc_string_sub(frame, command, "%t", group_sidstr);
+
+ if (command == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(8, ("running command: [%s]\n", command));
+ if (smbrun(command, NULL) != 0) {
+ DEBUG(0, ("Could not log NT token\n"));
+ TALLOC_FREE(frame);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+/*
+ * Create the token to use from server_info->sam_account and
+ * server_info->sids (the info3/sam groups). Find the unix gids.
+ */
+
+NTSTATUS create_local_token(auth_serversupplied_info *server_info)
+{
+ NTSTATUS status;
+ size_t i;
+
+ /*
+ * If winbind is not around, we can not make much use of the SIDs the
+ * domain controller provided us with. Likewise if the user name was
+ * mapped to some local unix user.
+ */
+
+ if (((lp_server_role() == ROLE_DOMAIN_MEMBER) && !winbind_ping()) ||
+ (server_info->nss_token)) {
+ status = create_token_from_username(server_info,
+ server_info->unix_name,
+ server_info->guest,
+ &server_info->utok.uid,
+ &server_info->utok.gid,
+ &server_info->unix_name,
+ &server_info->ptok);
+
+ } else {
+ server_info->ptok = create_local_nt_token(
+ server_info,
+ pdb_get_user_sid(server_info->sam_account),
+ server_info->guest,
+ server_info->num_sids, server_info->sids);
+ status = server_info->ptok ?
+ NT_STATUS_OK : NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Convert the SIDs to gids. */
+
+ server_info->utok.ngroups = 0;
+ server_info->utok.groups = NULL;
+
+ /* Start at index 1, where the groups start. */
+
+ for (i=1; i<server_info->ptok->num_sids; i++) {
+ gid_t gid;
+ DOM_SID *sid = &server_info->ptok->user_sids[i];
+
+ if (!sid_to_gid(sid, &gid)) {
+ DEBUG(10, ("Could not convert SID %s to gid, "
+ "ignoring it\n", sid_string_dbg(sid)));
+ continue;
+ }
+ add_gid_to_array_unique(server_info, gid,
+ &server_info->utok.groups,
+ &server_info->utok.ngroups);
+ }
+
+ debug_nt_user_token(DBGC_AUTH, 10, server_info->ptok);
+
+ status = log_nt_token(server_info->ptok);
+ return status;
+}
+
+/*
+ * Create an artificial NT token given just a username. (Initially indended
+ * for force user)
+ *
+ * We go through lookup_name() to avoid problems we had with 'winbind use
+ * default domain'.
+ *
+ * We have 3 cases:
+ *
+ * unmapped unix users: Go directly to nss to find the user's group.
+ *
+ * A passdb user: The list of groups is provided by pdb_enum_group_memberships.
+ *
+ * If the user is provided by winbind, the primary gid is set to "domain
+ * users" of the user's domain. For an explanation why this is necessary, see
+ * the thread starting at
+ * http://lists.samba.org/archive/samba-technical/2006-January/044803.html.
+ */
+
+NTSTATUS create_token_from_username(TALLOC_CTX *mem_ctx, const char *username,
+ bool is_guest,
+ uid_t *uid, gid_t *gid,
+ char **found_username,
+ struct nt_user_token **token)
+{
+ NTSTATUS result = NT_STATUS_NO_SUCH_USER;
+ TALLOC_CTX *tmp_ctx;
+ DOM_SID user_sid;
+ enum lsa_SidType type;
+ gid_t *gids;
+ DOM_SID *group_sids;
+ DOM_SID unix_group_sid;
+ size_t num_group_sids;
+ size_t num_gids;
+ size_t i;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!lookup_name_smbconf(tmp_ctx, username, LOOKUP_NAME_ALL,
+ NULL, NULL, &user_sid, &type)) {
+ DEBUG(1, ("lookup_name_smbconf for %s failed\n", username));
+ goto done;
+ }
+
+ if (type != SID_NAME_USER) {
+ DEBUG(1, ("%s is a %s, not a user\n", username,
+ sid_type_lookup(type)));
+ goto done;
+ }
+
+ if (!sid_to_uid(&user_sid, uid)) {
+ DEBUG(1, ("sid_to_uid for %s (%s) failed\n",
+ username, sid_string_dbg(&user_sid)));
+ goto done;
+ }
+
+ if (sid_check_is_in_our_domain(&user_sid)) {
+ bool ret;
+
+ /* This is a passdb user, so ask passdb */
+
+ struct samu *sam_acct = NULL;
+
+ if ( !(sam_acct = samu_new( tmp_ctx )) ) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ become_root();
+ ret = pdb_getsampwsid(sam_acct, &user_sid);
+ unbecome_root();
+
+ if (!ret) {
+ DEBUG(1, ("pdb_getsampwsid(%s) for user %s failed\n",
+ sid_string_dbg(&user_sid), username));
+ DEBUGADD(1, ("Fall back to unix user %s\n", username));
+ goto unix_user;
+ }
+
+ result = pdb_enum_group_memberships(tmp_ctx, sam_acct,
+ &group_sids, &gids,
+ &num_group_sids);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10, ("enum_group_memberships failed for %s\n",
+ username));
+ DEBUGADD(1, ("Fall back to unix user %s\n", username));
+ goto unix_user;
+ }
+
+ /* see the smb_panic() in pdb_default_enum_group_memberships */
+ SMB_ASSERT(num_group_sids > 0);
+
+ *gid = gids[0];
+
+ /* Ensure we're returning the found_username on the right context. */
+ *found_username = talloc_strdup(mem_ctx,
+ pdb_get_username(sam_acct));
+
+ } else if (sid_check_is_in_unix_users(&user_sid)) {
+
+ /* This is a unix user not in passdb. We need to ask nss
+ * directly, without consulting passdb */
+
+ struct passwd *pass;
+
+ /*
+ * This goto target is used as a fallback for the passdb
+ * case. The concrete bug report is when passdb gave us an
+ * unmapped gid.
+ */
+
+ unix_user:
+
+ uid_to_unix_users_sid(*uid, &user_sid);
+
+ pass = getpwuid_alloc(tmp_ctx, *uid);
+ if (pass == NULL) {
+ DEBUG(1, ("getpwuid(%d) for user %s failed\n",
+ *uid, username));
+ goto done;
+ }
+
+ if (!getgroups_unix_user(tmp_ctx, username, pass->pw_gid,
+ &gids, &num_group_sids)) {
+ DEBUG(1, ("getgroups_unix_user for user %s failed\n",
+ username));
+ goto done;
+ }
+
+ if (num_group_sids) {
+ group_sids = TALLOC_ARRAY(tmp_ctx, DOM_SID, num_group_sids);
+ if (group_sids == NULL) {
+ DEBUG(1, ("TALLOC_ARRAY failed\n"));
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ } else {
+ group_sids = NULL;
+ }
+
+ for (i=0; i<num_group_sids; i++) {
+ gid_to_sid(&group_sids[i], gids[i]);
+ }
+
+ /* In getgroups_unix_user we always set the primary gid */
+ SMB_ASSERT(num_group_sids > 0);
+
+ *gid = gids[0];
+
+ /* Ensure we're returning the found_username on the right context. */
+ *found_username = talloc_strdup(mem_ctx, pass->pw_name);
+ } else {
+
+ /* This user is from winbind, force the primary gid to the
+ * user's "domain users" group. Under certain circumstances
+ * (user comes from NT4), this might be a loss of
+ * information. But we can not rely on winbind getting the
+ * correct info. AD might prohibit winbind looking up that
+ * information. */
+
+ uint32 dummy;
+
+ num_group_sids = 1;
+ group_sids = TALLOC_ARRAY(tmp_ctx, DOM_SID, num_group_sids);
+ if (group_sids == NULL) {
+ DEBUG(1, ("TALLOC_ARRAY failed\n"));
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ sid_copy(&group_sids[0], &user_sid);
+ sid_split_rid(&group_sids[0], &dummy);
+ sid_append_rid(&group_sids[0], DOMAIN_GROUP_RID_USERS);
+
+ if (!sid_to_gid(&group_sids[0], gid)) {
+ DEBUG(1, ("sid_to_gid(%s) failed\n",
+ sid_string_dbg(&group_sids[0])));
+ goto done;
+ }
+
+ gids = gid;
+
+ /* Ensure we're returning the found_username on the right context. */
+ *found_username = talloc_strdup(mem_ctx, username);
+ }
+
+ /* Add the "Unix Group" SID for each gid to catch mapped groups
+ and their Unix equivalent. This is to solve the backwards
+ compatibility problem of 'valid users = +ntadmin' where
+ ntadmin has been paired with "Domain Admins" in the group
+ mapping table. Otherwise smb.conf would need to be changed
+ to 'valid user = "Domain Admins"'. --jerry */
+
+ num_gids = num_group_sids;
+ for ( i=0; i<num_gids; i++ ) {
+ gid_t high, low;
+
+ /* don't pickup anything managed by Winbind */
+
+ if ( lp_idmap_gid(&low, &high) && (gids[i] >= low) && (gids[i] <= high) )
+ continue;
+
+ if ( !gid_to_unix_groups_sid( gids[i], &unix_group_sid ) ) {
+ DEBUG(1,("create_token_from_username: Failed to create SID "
+ "for gid %d!\n", gids[i]));
+ continue;
+ }
+ result = add_sid_to_array_unique(tmp_ctx, &unix_group_sid,
+ &group_sids, &num_group_sids);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+ }
+
+ /* Ensure we're creating the nt_token on the right context. */
+ *token = create_local_nt_token(mem_ctx, &user_sid,
+ is_guest, num_group_sids, group_sids);
+
+ if ((*token == NULL) || (*found_username == NULL)) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ result = NT_STATUS_OK;
+ done:
+ TALLOC_FREE(tmp_ctx);
+ return result;
+}
+
+/***************************************************************************
+ Build upon create_token_from_username:
+
+ Expensive helper function to figure out whether a user given its name is
+ member of a particular group.
+***************************************************************************/
+
+bool user_in_group_sid(const char *username, const DOM_SID *group_sid)
+{
+ NTSTATUS status;
+ uid_t uid;
+ gid_t gid;
+ char *found_username;
+ struct nt_user_token *token;
+ bool result;
+
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return False;
+ }
+
+ status = create_token_from_username(mem_ctx, username, False,
+ &uid, &gid, &found_username,
+ &token);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("could not create token for %s\n", username));
+ return False;
+ }
+
+ result = nt_token_check_sid(group_sid, token);
+
+ TALLOC_FREE(mem_ctx);
+ return result;
+
+}
+
+bool user_in_group(const char *username, const char *groupname)
+{
+ TALLOC_CTX *mem_ctx;
+ DOM_SID group_sid;
+ bool ret;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return False;
+ }
+
+ ret = lookup_name(mem_ctx, groupname, LOOKUP_NAME_ALL,
+ NULL, NULL, &group_sid, NULL);
+ TALLOC_FREE(mem_ctx);
+
+ if (!ret) {
+ DEBUG(10, ("lookup_name for (%s) failed.\n", groupname));
+ return False;
+ }
+
+ return user_in_group_sid(username, &group_sid);
+}
+
+/***************************************************************************
+ Make (and fill) a server_info struct from a 'struct passwd' by conversion
+ to a struct samu
+***************************************************************************/
+
+NTSTATUS make_server_info_pw(auth_serversupplied_info **server_info,
+ char *unix_username,
+ struct passwd *pwd)
+{
+ NTSTATUS status;
+ struct samu *sampass = NULL;
+ gid_t *gids;
+ char *qualified_name = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+ DOM_SID u_sid;
+ enum lsa_SidType type;
+ auth_serversupplied_info *result;
+
+ if ( !(sampass = samu_new( NULL )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = samu_set_unix( sampass, pwd );
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ result = make_server_info(NULL);
+ if (result == NULL) {
+ TALLOC_FREE(sampass);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result->sam_account = sampass;
+
+ result->unix_name = talloc_strdup(result, unix_username);
+ result->sanitized_username = sanitize_username(result, unix_username);
+
+ if ((result->unix_name == NULL)
+ || (result->sanitized_username == NULL)) {
+ TALLOC_FREE(sampass);
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result->utok.uid = pwd->pw_uid;
+ result->utok.gid = pwd->pw_gid;
+
+ status = pdb_enum_group_memberships(result, sampass,
+ &result->sids, &gids,
+ &result->num_sids);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("pdb_enum_group_memberships failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(result);
+ return status;
+ }
+
+ /*
+ * The SID returned in server_info->sam_account is based
+ * on our SAM sid even though for a pure UNIX account this should
+ * not be the case as it doesn't really exist in the SAM db.
+ * This causes lookups on "[in]valid users" to fail as they
+ * will lookup this name as a "Unix User" SID to check against
+ * the user token. Fix this by adding the "Unix User"\unix_username
+ * SID to the sid array. The correct fix should probably be
+ * changing the server_info->sam_account user SID to be a
+ * S-1-22 Unix SID, but this might break old configs where
+ * plaintext passwords were used with no SAM backend.
+ */
+
+ mem_ctx = talloc_init("make_server_info_pw_tmp");
+ if (!mem_ctx) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
+ unix_users_domain_name(),
+ unix_username );
+ if (!qualified_name) {
+ TALLOC_FREE(result);
+ TALLOC_FREE(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!lookup_name(mem_ctx, qualified_name, LOOKUP_NAME_ALL,
+ NULL, NULL,
+ &u_sid, &type)) {
+ TALLOC_FREE(result);
+ TALLOC_FREE(mem_ctx);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ TALLOC_FREE(mem_ctx);
+
+ if (type != SID_NAME_USER) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ status = add_sid_to_array_unique(result, &u_sid,
+ &result->sids,
+ &result->num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(result);
+ return status;
+ }
+
+ /* For now we throw away the gids and convert via sid_to_gid
+ * later. This needs fixing, but I'd like to get the code straight and
+ * simple first. */
+ TALLOC_FREE(gids);
+
+ *server_info = result;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ Make (and fill) a user_info struct for a guest login.
+ This *must* succeed for smbd to start. If there is no mapping entry for
+ the guest gid, then create one.
+***************************************************************************/
+
+static NTSTATUS make_new_server_info_guest(auth_serversupplied_info **server_info)
+{
+ NTSTATUS status;
+ struct samu *sampass = NULL;
+ DOM_SID guest_sid;
+ bool ret;
+ char zeros[16];
+ fstring tmp;
+
+ if ( !(sampass = samu_new( NULL )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ sid_copy(&guest_sid, get_global_sam_sid());
+ sid_append_rid(&guest_sid, DOMAIN_USER_RID_GUEST);
+
+ become_root();
+ ret = pdb_getsampwsid(sampass, &guest_sid);
+ unbecome_root();
+
+ if (!ret) {
+ TALLOC_FREE(sampass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ status = make_server_info_sam(server_info, sampass);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(sampass);
+ return status;
+ }
+
+ (*server_info)->guest = True;
+
+ status = create_local_token(*server_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("create_local_token failed: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ /* annoying, but the Guest really does have a session key, and it is
+ all zeros! */
+ ZERO_STRUCT(zeros);
+ (*server_info)->user_session_key = data_blob(zeros, sizeof(zeros));
+ (*server_info)->lm_session_key = data_blob(zeros, sizeof(zeros));
+
+ alpha_strcpy(tmp, pdb_get_username(sampass), ". _-$", sizeof(tmp));
+ (*server_info)->sanitized_username = talloc_strdup(*server_info, tmp);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Fake a auth_serversupplied_info just from a username
+****************************************************************************/
+
+NTSTATUS make_serverinfo_from_username(TALLOC_CTX *mem_ctx,
+ const char *username,
+ bool is_guest,
+ struct auth_serversupplied_info **presult)
+{
+ struct auth_serversupplied_info *result;
+ struct passwd *pwd;
+ NTSTATUS status;
+
+ pwd = getpwnam_alloc(talloc_tos(), username);
+ if (pwd == NULL) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ status = make_server_info_pw(&result, pwd->pw_name, pwd);
+
+ TALLOC_FREE(pwd);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ result->nss_token = true;
+ result->guest = is_guest;
+
+ status = create_local_token(result);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(result);
+ return status;
+ }
+
+ *presult = result;
+ return NT_STATUS_OK;
+}
+
+
+struct auth_serversupplied_info *copy_serverinfo(TALLOC_CTX *mem_ctx,
+ auth_serversupplied_info *src)
+{
+ auth_serversupplied_info *dst;
+
+ dst = make_server_info(mem_ctx);
+ if (dst == NULL) {
+ return NULL;
+ }
+
+ dst->guest = src->guest;
+ dst->utok.uid = src->utok.uid;
+ dst->utok.gid = src->utok.gid;
+ dst->utok.ngroups = src->utok.ngroups;
+ if (src->utok.ngroups != 0) {
+ dst->utok.groups = (gid_t *)TALLOC_MEMDUP(
+ dst, src->utok.groups,
+ sizeof(gid_t)*dst->utok.ngroups);
+ } else {
+ dst->utok.groups = NULL;
+ }
+
+ if (src->ptok) {
+ dst->ptok = dup_nt_token(dst, src->ptok);
+ if (!dst->ptok) {
+ TALLOC_FREE(dst);
+ return NULL;
+ }
+ }
+
+ dst->user_session_key = data_blob_talloc( dst, src->user_session_key.data,
+ src->user_session_key.length);
+
+ dst->lm_session_key = data_blob_talloc(dst, src->lm_session_key.data,
+ src->lm_session_key.length);
+
+ dst->sam_account = samu_new(NULL);
+ if (!dst->sam_account) {
+ TALLOC_FREE(dst);
+ return NULL;
+ }
+
+ if (!pdb_copy_sam_account(dst->sam_account, src->sam_account)) {
+ TALLOC_FREE(dst);
+ return NULL;
+ }
+
+ dst->pam_handle = NULL;
+ dst->unix_name = talloc_strdup(dst, src->unix_name);
+ if (!dst->unix_name) {
+ TALLOC_FREE(dst);
+ return NULL;
+ }
+
+ dst->sanitized_username = talloc_strdup(dst, src->sanitized_username);
+ if (!dst->sanitized_username) {
+ TALLOC_FREE(dst);
+ return NULL;
+ }
+
+ return dst;
+}
+
+/*
+ * Set a new session key. Used in the rpc server where we have to override the
+ * SMB level session key with SystemLibraryDTC
+ */
+
+bool server_info_set_session_key(struct auth_serversupplied_info *info,
+ DATA_BLOB session_key)
+{
+ TALLOC_FREE(info->user_session_key.data);
+
+ info->user_session_key = data_blob_talloc(
+ info, session_key.data, session_key.length);
+
+ return (info->user_session_key.data != NULL);
+}
+
+static auth_serversupplied_info *guest_info = NULL;
+
+bool init_guest_info(void)
+{
+ if (guest_info != NULL)
+ return True;
+
+ return NT_STATUS_IS_OK(make_new_server_info_guest(&guest_info));
+}
+
+NTSTATUS make_server_info_guest(TALLOC_CTX *mem_ctx,
+ auth_serversupplied_info **server_info)
+{
+ *server_info = copy_serverinfo(mem_ctx, guest_info);
+ return (*server_info != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
+}
+
+bool copy_current_user(struct current_user *dst, struct current_user *src)
+{
+ gid_t *groups;
+ NT_USER_TOKEN *nt_token;
+
+ groups = (gid_t *)memdup(src->ut.groups,
+ sizeof(gid_t) * src->ut.ngroups);
+ if ((src->ut.ngroups != 0) && (groups == NULL)) {
+ return False;
+ }
+
+ nt_token = dup_nt_token(NULL, src->nt_user_token);
+ if (nt_token == NULL) {
+ SAFE_FREE(groups);
+ return False;
+ }
+
+ dst->conn = src->conn;
+ dst->vuid = src->vuid;
+ dst->ut.uid = src->ut.uid;
+ dst->ut.gid = src->ut.gid;
+ dst->ut.ngroups = src->ut.ngroups;
+ dst->ut.groups = groups;
+ dst->nt_user_token = nt_token;
+ return True;
+}
+
+/***************************************************************************
+ Purely internal function for make_server_info_info3
+ Fill the sam account from getpwnam
+***************************************************************************/
+static NTSTATUS fill_sam_account(TALLOC_CTX *mem_ctx,
+ const char *domain,
+ const char *username,
+ char **found_username,
+ uid_t *uid, gid_t *gid,
+ struct samu *account,
+ bool *username_was_mapped)
+{
+ NTSTATUS nt_status;
+ fstring dom_user, lower_username;
+ fstring real_username;
+ struct passwd *passwd;
+
+ fstrcpy( lower_username, username );
+ strlower_m( lower_username );
+
+ fstr_sprintf(dom_user, "%s%c%s", domain, *lp_winbind_separator(),
+ lower_username);
+
+ /* Get the passwd struct. Try to create the account is necessary. */
+
+ *username_was_mapped = map_username( dom_user );
+
+ if ( !(passwd = smb_getpwnam( NULL, dom_user, real_username, True )) )
+ return NT_STATUS_NO_SUCH_USER;
+
+ *uid = passwd->pw_uid;
+ *gid = passwd->pw_gid;
+
+ /* This is pointless -- there is no suport for differing
+ unix and windows names. Make sure to always store the
+ one we actually looked up and succeeded. Have I mentioned
+ why I hate the 'winbind use default domain' parameter?
+ --jerry */
+
+ *found_username = talloc_strdup( mem_ctx, real_username );
+
+ DEBUG(5,("fill_sam_account: located username was [%s]\n", *found_username));
+
+ nt_status = samu_set_unix( account, passwd );
+
+ TALLOC_FREE(passwd);
+
+ return nt_status;
+}
+
+/****************************************************************************
+ Wrapper to allow the getpwnam() call to strip the domain name and
+ try again in case a local UNIX user is already there. Also run through
+ the username if we fallback to the username only.
+ ****************************************************************************/
+
+struct passwd *smb_getpwnam( TALLOC_CTX *mem_ctx, char *domuser,
+ fstring save_username, bool create )
+{
+ struct passwd *pw = NULL;
+ char *p;
+ fstring username;
+
+ /* we only save a copy of the username it has been mangled
+ by winbindd use default domain */
+
+ save_username[0] = '\0';
+
+ /* don't call map_username() here since it has to be done higher
+ up the stack so we don't call it mutliple times */
+
+ fstrcpy( username, domuser );
+
+ p = strchr_m( username, *lp_winbind_separator() );
+
+ /* code for a DOMAIN\user string */
+
+ if ( p ) {
+ fstring strip_username;
+
+ pw = Get_Pwnam_alloc( mem_ctx, domuser );
+ if ( pw ) {
+ /* make sure we get the case of the username correct */
+ /* work around 'winbind use default domain = yes' */
+
+ if ( !strchr_m( pw->pw_name, *lp_winbind_separator() ) ) {
+ char *domain;
+
+ /* split the domain and username into 2 strings */
+ *p = '\0';
+ domain = username;
+
+ fstr_sprintf(save_username, "%s%c%s", domain, *lp_winbind_separator(), pw->pw_name);
+ }
+ else
+ fstrcpy( save_username, pw->pw_name );
+
+ /* whew -- done! */
+ return pw;
+ }
+
+ /* setup for lookup of just the username */
+ /* remember that p and username are overlapping memory */
+
+ p++;
+ fstrcpy( strip_username, p );
+ fstrcpy( username, strip_username );
+ }
+
+ /* just lookup a plain username */
+
+ pw = Get_Pwnam_alloc(mem_ctx, username);
+
+ /* Create local user if requested but only if winbindd
+ is not running. We need to protect against cases
+ where winbindd is failing and then prematurely
+ creating users in /etc/passwd */
+
+ if ( !pw && create && !winbind_ping() ) {
+ /* Don't add a machine account. */
+ if (username[strlen(username)-1] == '$')
+ return NULL;
+
+ smb_create_user(NULL, username, NULL);
+ pw = Get_Pwnam_alloc(mem_ctx, username);
+ }
+
+ /* one last check for a valid passwd struct */
+
+ if ( pw )
+ fstrcpy( save_username, pw->pw_name );
+
+ return pw;
+}
+
+/***************************************************************************
+ Make a server_info struct from the info3 returned by a domain logon
+***************************************************************************/
+
+NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
+ const char *sent_nt_username,
+ const char *domain,
+ auth_serversupplied_info **server_info,
+ struct netr_SamInfo3 *info3)
+{
+ char zeros[16];
+
+ NTSTATUS nt_status = NT_STATUS_OK;
+ char *found_username = NULL;
+ const char *nt_domain;
+ const char *nt_username;
+ struct samu *sam_account = NULL;
+ DOM_SID user_sid;
+ DOM_SID group_sid;
+ bool username_was_mapped;
+
+ uid_t uid = (uid_t)-1;
+ gid_t gid = (gid_t)-1;
+
+ auth_serversupplied_info *result;
+
+ /*
+ Here is where we should check the list of
+ trusted domains, and verify that the SID
+ matches.
+ */
+
+ sid_copy(&user_sid, info3->base.domain_sid);
+ if (!sid_append_rid(&user_sid, info3->base.rid)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ sid_copy(&group_sid, info3->base.domain_sid);
+ if (!sid_append_rid(&group_sid, info3->base.primary_gid)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ nt_username = talloc_strdup(mem_ctx, info3->base.account_name.string);
+ if (!nt_username) {
+ /* If the server didn't give us one, just use the one we sent
+ * them */
+ nt_username = sent_nt_username;
+ }
+
+ nt_domain = talloc_strdup(mem_ctx, info3->base.domain.string);
+ if (!nt_domain) {
+ /* If the server didn't give us one, just use the one we sent
+ * them */
+ nt_domain = domain;
+ }
+
+ /* try to fill the SAM account.. If getpwnam() fails, then try the
+ add user script (2.2.x behavior).
+
+ We use the _unmapped_ username here in an attempt to provide
+ consistent username mapping behavior between kerberos and NTLM[SSP]
+ authentication in domain mode security. I.E. Username mapping
+ should be applied to the fully qualified username
+ (e.g. DOMAIN\user) and not just the login name. Yes this means we
+ called map_username() unnecessarily in make_user_info_map() but
+ that is how the current code is designed. Making the change here
+ is the least disruptive place. -- jerry */
+
+ if ( !(sam_account = samu_new( NULL )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* this call will try to create the user if necessary */
+
+ nt_status = fill_sam_account(mem_ctx, nt_domain, sent_nt_username,
+ &found_username, &uid, &gid, sam_account,
+ &username_was_mapped);
+
+
+ /* if we still don't have a valid unix account check for
+ 'map to guest = bad uid' */
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ TALLOC_FREE( sam_account );
+ if ( lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID ) {
+ make_server_info_guest(NULL, server_info);
+ return NT_STATUS_OK;
+ }
+ return nt_status;
+ }
+
+ if (!pdb_set_nt_username(sam_account, nt_username, PDB_CHANGED)) {
+ TALLOC_FREE(sam_account);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_username(sam_account, nt_username, PDB_CHANGED)) {
+ TALLOC_FREE(sam_account);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_domain(sam_account, nt_domain, PDB_CHANGED)) {
+ TALLOC_FREE(sam_account);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_user_sid(sam_account, &user_sid, PDB_CHANGED)) {
+ TALLOC_FREE(sam_account);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!pdb_set_group_sid(sam_account, &group_sid, PDB_CHANGED)) {
+ TALLOC_FREE(sam_account);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!pdb_set_fullname(sam_account,
+ info3->base.full_name.string,
+ PDB_CHANGED)) {
+ TALLOC_FREE(sam_account);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_logon_script(sam_account,
+ info3->base.logon_script.string,
+ PDB_CHANGED)) {
+ TALLOC_FREE(sam_account);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_profile_path(sam_account,
+ info3->base.profile_path.string,
+ PDB_CHANGED)) {
+ TALLOC_FREE(sam_account);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_homedir(sam_account,
+ info3->base.home_directory.string,
+ PDB_CHANGED)) {
+ TALLOC_FREE(sam_account);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_dir_drive(sam_account,
+ info3->base.home_drive.string,
+ PDB_CHANGED)) {
+ TALLOC_FREE(sam_account);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_acct_ctrl(sam_account, info3->base.acct_flags, PDB_CHANGED)) {
+ TALLOC_FREE(sam_account);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_pass_last_set_time(
+ sam_account,
+ nt_time_to_unix(info3->base.last_password_change),
+ PDB_CHANGED)) {
+ TALLOC_FREE(sam_account);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_pass_can_change_time(
+ sam_account,
+ nt_time_to_unix(info3->base.allow_password_change),
+ PDB_CHANGED)) {
+ TALLOC_FREE(sam_account);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_pass_must_change_time(
+ sam_account,
+ nt_time_to_unix(info3->base.force_password_change),
+ PDB_CHANGED)) {
+ TALLOC_FREE(sam_account);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result = make_server_info(NULL);
+ if (result == NULL) {
+ DEBUG(4, ("make_server_info failed!\n"));
+ TALLOC_FREE(sam_account);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* save this here to _net_sam_logon() doesn't fail (it assumes a
+ valid struct samu) */
+
+ result->sam_account = sam_account;
+ result->unix_name = talloc_strdup(result, found_username);
+
+ result->sanitized_username = sanitize_username(result,
+ result->unix_name);
+ if (result->sanitized_username == NULL) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Fill in the unix info we found on the way */
+
+ result->utok.uid = uid;
+ result->utok.gid = gid;
+
+ /* Create a 'combined' list of all SIDs we might want in the SD */
+
+ result->num_sids = 0;
+ result->sids = NULL;
+
+ nt_status = sid_array_from_info3(result, info3,
+ &result->sids,
+ &result->num_sids,
+ false, false);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ TALLOC_FREE(result);
+ return nt_status;
+ }
+
+ /* Ensure the primary group sid is at position 0. */
+ sort_sid_array_for_smbd(result, &group_sid);
+
+ result->login_server = talloc_strdup(result,
+ info3->base.logon_server.string);
+
+ /* ensure we are never given NULL session keys */
+
+ ZERO_STRUCT(zeros);
+
+ if (memcmp(info3->base.key.key, zeros, sizeof(zeros)) == 0) {
+ result->user_session_key = data_blob_null;
+ } else {
+ result->user_session_key = data_blob_talloc(
+ result, info3->base.key.key,
+ sizeof(info3->base.key.key));
+ }
+
+ if (memcmp(info3->base.LMSessKey.key, zeros, 8) == 0) {
+ result->lm_session_key = data_blob_null;
+ } else {
+ result->lm_session_key = data_blob_talloc(
+ result, info3->base.LMSessKey.key,
+ sizeof(info3->base.LMSessKey.key));
+ }
+
+ result->nss_token |= username_was_mapped;
+
+ *server_info = result;
+
+ return NT_STATUS_OK;
+}
+
+/*****************************************************************************
+ Make a server_info struct from the wbcAuthUserInfo returned by a domain logon
+******************************************************************************/
+
+NTSTATUS make_server_info_wbcAuthUserInfo(TALLOC_CTX *mem_ctx,
+ const char *sent_nt_username,
+ const char *domain,
+ const struct wbcAuthUserInfo *info,
+ auth_serversupplied_info **server_info)
+{
+ char zeros[16];
+
+ NTSTATUS nt_status = NT_STATUS_OK;
+ char *found_username = NULL;
+ const char *nt_domain;
+ const char *nt_username;
+ struct samu *sam_account = NULL;
+ DOM_SID user_sid;
+ DOM_SID group_sid;
+ bool username_was_mapped;
+ uint32_t i;
+
+ uid_t uid = (uid_t)-1;
+ gid_t gid = (gid_t)-1;
+
+ auth_serversupplied_info *result;
+
+ result = make_server_info(NULL);
+ if (result == NULL) {
+ DEBUG(4, ("make_server_info failed!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ Here is where we should check the list of
+ trusted domains, and verify that the SID
+ matches.
+ */
+
+ memcpy(&user_sid, &info->sids[0].sid, sizeof(user_sid));
+ memcpy(&group_sid, &info->sids[1].sid, sizeof(group_sid));
+
+ if (info->account_name) {
+ nt_username = talloc_strdup(result, info->account_name);
+ } else {
+ /* If the server didn't give us one, just use the one we sent
+ * them */
+ nt_username = talloc_strdup(result, sent_nt_username);
+ }
+ if (!nt_username) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (info->domain_name) {
+ nt_domain = talloc_strdup(result, info->domain_name);
+ } else {
+ /* If the server didn't give us one, just use the one we sent
+ * them */
+ nt_domain = talloc_strdup(result, domain);
+ }
+ if (!nt_domain) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* try to fill the SAM account.. If getpwnam() fails, then try the
+ add user script (2.2.x behavior).
+
+ We use the _unmapped_ username here in an attempt to provide
+ consistent username mapping behavior between kerberos and NTLM[SSP]
+ authentication in domain mode security. I.E. Username mapping
+ should be applied to the fully qualified username
+ (e.g. DOMAIN\user) and not just the login name. Yes this means we
+ called map_username() unnecessarily in make_user_info_map() but
+ that is how the current code is designed. Making the change here
+ is the least disruptive place. -- jerry */
+
+ if ( !(sam_account = samu_new( result )) ) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* this call will try to create the user if necessary */
+
+ nt_status = fill_sam_account(result, nt_domain, sent_nt_username,
+ &found_username, &uid, &gid, sam_account,
+ &username_was_mapped);
+
+ /* if we still don't have a valid unix account check for
+ 'map to guest = bad uid' */
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ TALLOC_FREE( result );
+ if ( lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID ) {
+ make_server_info_guest(NULL, server_info);
+ return NT_STATUS_OK;
+ }
+ return nt_status;
+ }
+
+ if (!pdb_set_nt_username(sam_account, nt_username, PDB_CHANGED)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_username(sam_account, nt_username, PDB_CHANGED)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_domain(sam_account, nt_domain, PDB_CHANGED)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_user_sid(sam_account, &user_sid, PDB_CHANGED)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!pdb_set_group_sid(sam_account, &group_sid, PDB_CHANGED)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!pdb_set_fullname(sam_account, info->full_name, PDB_CHANGED)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_logon_script(sam_account, info->logon_script, PDB_CHANGED)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_profile_path(sam_account, info->profile_path, PDB_CHANGED)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_homedir(sam_account, info->home_directory, PDB_CHANGED)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_dir_drive(sam_account, info->home_drive, PDB_CHANGED)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_acct_ctrl(sam_account, info->acct_flags, PDB_CHANGED)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_pass_last_set_time(
+ sam_account,
+ nt_time_to_unix(info->pass_last_set_time),
+ PDB_CHANGED)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_pass_can_change_time(
+ sam_account,
+ nt_time_to_unix(info->pass_can_change_time),
+ PDB_CHANGED)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_pass_must_change_time(
+ sam_account,
+ nt_time_to_unix(info->pass_must_change_time),
+ PDB_CHANGED)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* save this here to _net_sam_logon() doesn't fail (it assumes a
+ valid struct samu) */
+
+ result->sam_account = sam_account;
+ result->unix_name = talloc_strdup(result, found_username);
+
+ result->sanitized_username = sanitize_username(result,
+ result->unix_name);
+ result->login_server = talloc_strdup(result, info->logon_server);
+
+ if ((result->unix_name == NULL)
+ || (result->sanitized_username == NULL)
+ || (result->login_server == NULL)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Fill in the unix info we found on the way */
+
+ result->utok.uid = uid;
+ result->utok.gid = gid;
+
+ /* Create a 'combined' list of all SIDs we might want in the SD */
+
+ result->num_sids = info->num_sids - 2;
+ result->sids = talloc_array(result, DOM_SID, result->num_sids);
+ if (result->sids == NULL) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i < result->num_sids; i++) {
+ memcpy(&result->sids[i], &info->sids[i+2].sid, sizeof(result->sids[i]));
+ }
+
+ /* Ensure the primary group sid is at position 0. */
+ sort_sid_array_for_smbd(result, &group_sid);
+
+ /* ensure we are never given NULL session keys */
+
+ ZERO_STRUCT(zeros);
+
+ if (memcmp(info->user_session_key, zeros, sizeof(zeros)) == 0) {
+ result->user_session_key = data_blob_null;
+ } else {
+ result->user_session_key = data_blob_talloc(
+ result, info->user_session_key,
+ sizeof(info->user_session_key));
+ }
+
+ if (memcmp(info->lm_session_key, zeros, 8) == 0) {
+ result->lm_session_key = data_blob_null;
+ } else {
+ result->lm_session_key = data_blob_talloc(
+ result, info->lm_session_key,
+ sizeof(info->lm_session_key));
+ }
+
+ result->nss_token |= username_was_mapped;
+
+ *server_info = result;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ Free a user_info struct
+***************************************************************************/
+
+void free_user_info(auth_usersupplied_info **user_info)
+{
+ DEBUG(5,("attempting to free (and zero) a user_info structure\n"));
+ if (*user_info != NULL) {
+ if ((*user_info)->smb_name) {
+ DEBUG(10,("structure was created for %s\n",
+ (*user_info)->smb_name));
+ }
+ SAFE_FREE((*user_info)->smb_name);
+ SAFE_FREE((*user_info)->internal_username);
+ SAFE_FREE((*user_info)->client_domain);
+ SAFE_FREE((*user_info)->domain);
+ SAFE_FREE((*user_info)->wksta_name);
+ data_blob_free(&(*user_info)->lm_resp);
+ data_blob_free(&(*user_info)->nt_resp);
+ data_blob_clear_free(&(*user_info)->lm_interactive_pwd);
+ data_blob_clear_free(&(*user_info)->nt_interactive_pwd);
+ data_blob_clear_free(&(*user_info)->plaintext_password);
+ ZERO_STRUCT(**user_info);
+ }
+ SAFE_FREE(*user_info);
+}
+
+/***************************************************************************
+ Make an auth_methods struct
+***************************************************************************/
+
+bool make_auth_methods(struct auth_context *auth_context, auth_methods **auth_method)
+{
+ if (!auth_context) {
+ smb_panic("no auth_context supplied to "
+ "make_auth_methods()!\n");
+ }
+
+ if (!auth_method) {
+ smb_panic("make_auth_methods: pointer to auth_method pointer "
+ "is NULL!\n");
+ }
+
+ *auth_method = TALLOC_P(auth_context->mem_ctx, auth_methods);
+ if (!*auth_method) {
+ DEBUG(0,("make_auth_method: malloc failed!\n"));
+ return False;
+ }
+ ZERO_STRUCTP(*auth_method);
+
+ return True;
+}
+
+/**
+ * Verify whether or not given domain is trusted.
+ *
+ * @param domain_name name of the domain to be verified
+ * @return true if domain is one of the trusted once or
+ * false if otherwise
+ **/
+
+bool is_trusted_domain(const char* dom_name)
+{
+ DOM_SID trustdom_sid;
+ bool ret;
+
+ /* no trusted domains for a standalone server */
+
+ if ( lp_server_role() == ROLE_STANDALONE )
+ return False;
+
+ /* if we are a DC, then check for a direct trust relationships */
+
+ if ( IS_DC ) {
+ become_root();
+ DEBUG (5,("is_trusted_domain: Checking for domain trust with "
+ "[%s]\n", dom_name ));
+ ret = pdb_get_trusteddom_pw(dom_name, NULL, NULL, NULL);
+ unbecome_root();
+ if (ret)
+ return True;
+ }
+ else {
+ wbcErr result;
+
+ /* If winbind is around, ask it */
+
+ result = wb_is_trusted_domain(dom_name);
+
+ if (result == WBC_ERR_SUCCESS) {
+ return True;
+ }
+
+ if (result == WBC_ERR_DOMAIN_NOT_FOUND) {
+ /* winbind could not find the domain */
+ return False;
+ }
+
+ /* The only other possible result is that winbind is not up
+ and running. We need to update the trustdom_cache
+ ourselves */
+
+ update_trustdom_cache();
+ }
+
+ /* now the trustdom cache should be available a DC could still
+ * have a transitive trust so fall back to the cache of trusted
+ * domains (like a domain member would use */
+
+ if ( trustdom_cache_fetch(dom_name, &trustdom_sid) ) {
+ return True;
+ }
+
+ return False;
+}
+
diff --git a/source3/auth/auth_winbind.c b/source3/auth/auth_winbind.c
new file mode 100644
index 0000000000..d1b00a3268
--- /dev/null
+++ b/source3/auth/auth_winbind.c
@@ -0,0 +1,153 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind authentication mechnism
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Andrew Bartlett 2001 - 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+/* Authenticate a user with a challenge/response */
+
+static NTSTATUS check_winbind_security(const struct auth_context *auth_context,
+ void *my_private_data,
+ TALLOC_CTX *mem_ctx,
+ const auth_usersupplied_info *user_info,
+ auth_serversupplied_info **server_info)
+{
+ NTSTATUS nt_status;
+ wbcErr wbc_status;
+ struct wbcAuthUserParams params;
+ struct wbcAuthUserInfo *info = NULL;
+ struct wbcAuthErrorInfo *err = NULL;
+
+ if (!user_info) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!auth_context) {
+ DEBUG(3,("Password for user %s cannot be checked because we have no auth_info to get the challenge from.\n",
+ user_info->internal_username));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (strequal(user_info->domain, get_global_sam_name())) {
+ DEBUG(3,("check_winbind_security: Not using winbind, requested domain [%s] was for this SAM.\n",
+ user_info->domain));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* Send off request */
+
+ params.account_name = user_info->smb_name;
+ params.domain_name = user_info->domain;
+ params.workstation_name = user_info->wksta_name;
+
+ params.flags = 0;
+ params.parameter_control= user_info->logon_parameters;
+
+ params.level = WBC_AUTH_USER_LEVEL_RESPONSE;
+
+ memcpy(params.password.response.challenge,
+ auth_context->challenge.data,
+ sizeof(params.password.response.challenge));
+
+ params.password.response.nt_length = user_info->nt_resp.length;
+ params.password.response.nt_data = user_info->nt_resp.data;
+ params.password.response.lm_length = user_info->lm_resp.length;
+ params.password.response.lm_data = user_info->lm_resp.data;
+
+ /* we are contacting the privileged pipe */
+ become_root();
+ wbc_status = wbcAuthenticateUserEx(&params, &info, &err);
+ unbecome_root();
+
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ DEBUG(10,("check_winbind_security: wbcAuthenticateUserEx failed: %s\n",
+ wbcErrorString(wbc_status)));
+ }
+
+ if (wbc_status == WBC_ERR_NO_MEMORY) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (wbc_status == WBC_ERR_WINBIND_NOT_AVAILABLE) {
+ struct auth_methods *auth_method =
+ (struct auth_methods *)my_private_data;
+
+ if ( auth_method )
+ return auth_method->auth(auth_context, auth_method->private_data,
+ mem_ctx, user_info, server_info);
+ else
+ /* log an error since this should not happen */
+ DEBUG(0,("check_winbind_security: ERROR! my_private_data == NULL!\n"));
+ }
+
+ if (wbc_status == WBC_ERR_AUTH_ERROR) {
+ nt_status = NT_STATUS(err->nt_status);
+ wbcFreeMemory(err);
+ return nt_status;
+ }
+
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ nt_status = make_server_info_wbcAuthUserInfo(mem_ctx,
+ user_info->smb_name,
+ user_info->domain,
+ info, server_info);
+ wbcFreeMemory(info);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ (*server_info)->nss_token |= user_info->was_mapped;
+
+ return nt_status;
+}
+
+/* module initialisation */
+static NTSTATUS auth_init_winbind(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_context, auth_method)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*auth_method)->name = "winbind";
+ (*auth_method)->auth = check_winbind_security;
+
+ if (param && *param) {
+ /* we load the 'fallback' module - if winbind isn't here, call this
+ module */
+ auth_methods *priv;
+ if (!load_auth_module(auth_context, param, &priv)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ (*auth_method)->private_data = (void *)priv;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS auth_winbind_init(void)
+{
+ return smb_register_auth(AUTH_INTERFACE_VERSION, "winbind", auth_init_winbind);
+}
diff --git a/source3/auth/pampass.c b/source3/auth/pampass.c
new file mode 100644
index 0000000000..9345eed27a
--- /dev/null
+++ b/source3/auth/pampass.c
@@ -0,0 +1,886 @@
+/*
+ Unix SMB/CIFS implementation.
+ PAM Password checking
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) John H Terpsta 1999-2001
+ Copyright (C) Andrew Bartlett 2001
+ Copyright (C) Jeremy Allison 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * This module provides PAM based functions for validation of
+ * username/password pairs, account managment, session and access control.
+ * Note: SMB password checking is done in smbpass.c
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+#ifdef WITH_PAM
+
+/*******************************************************************
+ * Handle PAM authentication
+ * - Access, Authentication, Session, Password
+ * Note: See PAM Documentation and refer to local system PAM implementation
+ * which determines what actions/limitations/allowances become affected.
+ *********************************************************************/
+
+#if defined(HAVE_SECURITY_PAM_APPL_H)
+#include <security/pam_appl.h>
+#elif defined(HAVE_PAM_PAM_APPL_H)
+#include <pam/pam_appl.h>
+#endif
+
+/*
+ * Structure used to communicate between the conversation function
+ * and the server_login/change password functions.
+ */
+
+struct smb_pam_userdata {
+ const char *PAM_username;
+ const char *PAM_password;
+ const char *PAM_newpassword;
+};
+
+typedef int (*smb_pam_conv_fn)(int, const struct pam_message **, struct pam_response **, void *appdata_ptr);
+
+/*
+ * Macros to help make life easy
+ */
+#define COPY_STRING(s) (s) ? SMB_STRDUP(s) : NULL
+#define COPY_FSTRING(s) (s[0]) ? SMB_STRDUP(s) : NULL
+
+/*******************************************************************
+ PAM error handler.
+ *********************************************************************/
+
+static bool smb_pam_error_handler(pam_handle_t *pamh, int pam_error, const char *msg, int dbglvl)
+{
+
+ if( pam_error != PAM_SUCCESS) {
+ DEBUG(dbglvl, ("smb_pam_error_handler: PAM: %s : %s\n",
+ msg, pam_strerror(pamh, pam_error)));
+
+ return False;
+ }
+ return True;
+}
+
+/*******************************************************************
+ This function is a sanity check, to make sure that we NEVER report
+ failure as sucess.
+*********************************************************************/
+
+static bool smb_pam_nt_status_error_handler(pam_handle_t *pamh, int pam_error,
+ const char *msg, int dbglvl,
+ NTSTATUS *nt_status)
+{
+ *nt_status = pam_to_nt_status(pam_error);
+
+ if (smb_pam_error_handler(pamh, pam_error, msg, dbglvl))
+ return True;
+
+ if (NT_STATUS_IS_OK(*nt_status)) {
+ /* Complain LOUDLY */
+ DEBUG(0, ("smb_pam_nt_status_error_handler: PAM: BUG: PAM and NT_STATUS \
+error MISMATCH, forcing to NT_STATUS_LOGON_FAILURE"));
+ *nt_status = NT_STATUS_LOGON_FAILURE;
+ }
+ return False;
+}
+
+/*
+ * PAM conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+
+static int smb_pam_conv(int num_msg,
+ const struct pam_message **msg,
+ struct pam_response **resp,
+ void *appdata_ptr)
+{
+ int replies = 0;
+ struct pam_response *reply = NULL;
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr;
+
+ *resp = NULL;
+
+ if (num_msg <= 0)
+ return PAM_CONV_ERR;
+
+ /*
+ * Apparantly HPUX has a buggy PAM that doesn't support the
+ * appdata_ptr. Fail if this is the case. JRA.
+ */
+
+ if (udp == NULL) {
+ DEBUG(0,("smb_pam_conv: PAM on this system is broken - appdata_ptr == NULL !\n"));
+ return PAM_CONV_ERR;
+ }
+
+ reply = SMB_MALLOC_ARRAY(struct pam_response, num_msg);
+ if (!reply)
+ return PAM_CONV_ERR;
+
+ memset(reply, '\0', sizeof(struct pam_response) * num_msg);
+
+ for (replies = 0; replies < num_msg; replies++) {
+ switch (msg[replies]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(udp->PAM_username);
+ /* PAM frees resp */
+ break;
+
+ case PAM_PROMPT_ECHO_OFF:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(udp->PAM_password);
+ /* PAM frees resp */
+ break;
+
+ case PAM_TEXT_INFO:
+ /* fall through */
+
+ case PAM_ERROR_MSG:
+ /* ignore it... */
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = NULL;
+ break;
+
+ default:
+ /* Must be an error of some sort... */
+ SAFE_FREE(reply);
+ return PAM_CONV_ERR;
+ }
+ }
+ if (reply)
+ *resp = reply;
+ return PAM_SUCCESS;
+}
+
+/*
+ * PAM password change conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+
+static void special_char_sub(char *buf)
+{
+ all_string_sub(buf, "\\n", "", 0);
+ all_string_sub(buf, "\\r", "", 0);
+ all_string_sub(buf, "\\s", " ", 0);
+ all_string_sub(buf, "\\t", "\t", 0);
+}
+
+static void pwd_sub(char *buf, const char *username, const char *oldpass, const char *newpass)
+{
+ fstring_sub(buf, "%u", username);
+ all_string_sub(buf, "%o", oldpass, sizeof(fstring));
+ all_string_sub(buf, "%n", newpass, sizeof(fstring));
+}
+
+
+struct chat_struct {
+ struct chat_struct *next, *prev;
+ fstring prompt;
+ fstring reply;
+};
+
+/**************************************************************
+ Create a linked list containing chat data.
+***************************************************************/
+
+static struct chat_struct *make_pw_chat(const char *p)
+{
+ char *prompt;
+ char *reply;
+ struct chat_struct *list = NULL;
+ struct chat_struct *t;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ while (1) {
+ t = SMB_MALLOC_P(struct chat_struct);
+ if (!t) {
+ DEBUG(0,("make_pw_chat: malloc failed!\n"));
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ ZERO_STRUCTP(t);
+
+ DLIST_ADD_END(list, t, struct chat_struct*);
+
+ if (!next_token_talloc(frame, &p, &prompt, NULL)) {
+ break;
+ }
+
+ if (strequal(prompt,".")) {
+ fstrcpy(prompt,"*");
+ }
+
+ special_char_sub(prompt);
+ fstrcpy(t->prompt, prompt);
+ strlower_m(t->prompt);
+ trim_char(t->prompt, ' ', ' ');
+
+ if (!next_token_talloc(frame, &p, &reply, NULL)) {
+ break;
+ }
+
+ if (strequal(reply,".")) {
+ fstrcpy(reply,"");
+ }
+
+ special_char_sub(reply);
+ fstrcpy(t->reply, reply);
+ strlower_m(t->reply);
+ trim_char(t->reply, ' ', ' ');
+
+ }
+ TALLOC_FREE(frame);
+ return list;
+}
+
+static void free_pw_chat(struct chat_struct *list)
+{
+ while (list) {
+ struct chat_struct *old_head = list;
+ DLIST_REMOVE(list, list);
+ SAFE_FREE(old_head);
+ }
+}
+
+static int smb_pam_passchange_conv(int num_msg,
+ const struct pam_message **msg,
+ struct pam_response **resp,
+ void *appdata_ptr)
+{
+ int replies = 0;
+ struct pam_response *reply = NULL;
+ fstring current_prompt;
+ fstring current_reply;
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr;
+ struct chat_struct *pw_chat= make_pw_chat(lp_passwd_chat());
+ struct chat_struct *t;
+ bool found;
+ *resp = NULL;
+
+ DEBUG(10,("smb_pam_passchange_conv: starting converstation for %d messages\n", num_msg));
+
+ if (num_msg <= 0)
+ return PAM_CONV_ERR;
+
+ if (pw_chat == NULL)
+ return PAM_CONV_ERR;
+
+ /*
+ * Apparantly HPUX has a buggy PAM that doesn't support the
+ * appdata_ptr. Fail if this is the case. JRA.
+ */
+
+ if (udp == NULL) {
+ DEBUG(0,("smb_pam_passchange_conv: PAM on this system is broken - appdata_ptr == NULL !\n"));
+ free_pw_chat(pw_chat);
+ return PAM_CONV_ERR;
+ }
+
+ reply = SMB_MALLOC_ARRAY(struct pam_response, num_msg);
+ if (!reply) {
+ DEBUG(0,("smb_pam_passchange_conv: malloc for reply failed!\n"));
+ free_pw_chat(pw_chat);
+ return PAM_CONV_ERR;
+ }
+
+ for (replies = 0; replies < num_msg; replies++) {
+ found = False;
+ DEBUG(10,("smb_pam_passchange_conv: Processing message %d\n", replies));
+ switch (msg[replies]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: PAM said: %s\n", msg[replies]->msg));
+ fstrcpy(current_prompt, msg[replies]->msg);
+ trim_char(current_prompt, ' ', ' ');
+ for (t=pw_chat; t; t=t->next) {
+
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: trying to match |%s| to |%s|\n",
+ t->prompt, current_prompt ));
+
+ if (unix_wild_match(t->prompt, current_prompt)) {
+ fstrcpy(current_reply, t->reply);
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: We sent: %s\n", current_reply));
+ pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword);
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: We actualy sent: %s\n", current_reply));
+#endif
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_FSTRING(current_reply);
+ found = True;
+ break;
+ }
+ }
+ /* PAM frees resp */
+ if (!found) {
+ DEBUG(3,("smb_pam_passchange_conv: Could not find reply for PAM prompt: %s\n",msg[replies]->msg));
+ free_pw_chat(pw_chat);
+ SAFE_FREE(reply);
+ return PAM_CONV_ERR;
+ }
+ break;
+
+ case PAM_PROMPT_ECHO_OFF:
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: PAM said: %s\n", msg[replies]->msg));
+ fstrcpy(current_prompt, msg[replies]->msg);
+ trim_char(current_prompt, ' ', ' ');
+ for (t=pw_chat; t; t=t->next) {
+
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: trying to match |%s| to |%s|\n",
+ t->prompt, current_prompt ));
+
+ if (unix_wild_match(t->prompt, current_prompt)) {
+ fstrcpy(current_reply, t->reply);
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: We sent: %s\n", current_reply));
+ pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword);
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_FSTRING(current_reply);
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: We actualy sent: %s\n", current_reply));
+#endif
+ found = True;
+ break;
+ }
+ }
+ /* PAM frees resp */
+
+ if (!found) {
+ DEBUG(3,("smb_pam_passchange_conv: Could not find reply for PAM prompt: %s\n",msg[replies]->msg));
+ free_pw_chat(pw_chat);
+ SAFE_FREE(reply);
+ return PAM_CONV_ERR;
+ }
+ break;
+
+ case PAM_TEXT_INFO:
+ /* fall through */
+
+ case PAM_ERROR_MSG:
+ /* ignore it... */
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = NULL;
+ break;
+
+ default:
+ /* Must be an error of some sort... */
+ free_pw_chat(pw_chat);
+ SAFE_FREE(reply);
+ return PAM_CONV_ERR;
+ }
+ }
+
+ free_pw_chat(pw_chat);
+ if (reply)
+ *resp = reply;
+ return PAM_SUCCESS;
+}
+
+/***************************************************************************
+ Free up a malloced pam_conv struct.
+****************************************************************************/
+
+static void smb_free_pam_conv(struct pam_conv *pconv)
+{
+ if (pconv)
+ SAFE_FREE(pconv->appdata_ptr);
+
+ SAFE_FREE(pconv);
+}
+
+/***************************************************************************
+ Allocate a pam_conv struct.
+****************************************************************************/
+
+static struct pam_conv *smb_setup_pam_conv(smb_pam_conv_fn smb_pam_conv_fnptr, const char *user,
+ const char *passwd, const char *newpass)
+{
+ struct pam_conv *pconv = SMB_MALLOC_P(struct pam_conv);
+ struct smb_pam_userdata *udp = SMB_MALLOC_P(struct smb_pam_userdata);
+
+ if (pconv == NULL || udp == NULL) {
+ SAFE_FREE(pconv);
+ SAFE_FREE(udp);
+ return NULL;
+ }
+
+ udp->PAM_username = user;
+ udp->PAM_password = passwd;
+ udp->PAM_newpassword = newpass;
+
+ pconv->conv = smb_pam_conv_fnptr;
+ pconv->appdata_ptr = (void *)udp;
+ return pconv;
+}
+
+/*
+ * PAM Closing out cleanup handler
+ */
+
+static bool smb_pam_end(pam_handle_t *pamh, struct pam_conv *smb_pam_conv_ptr)
+{
+ int pam_error;
+
+ smb_free_pam_conv(smb_pam_conv_ptr);
+
+ if( pamh != NULL ) {
+ pam_error = pam_end(pamh, 0);
+ if(smb_pam_error_handler(pamh, pam_error, "End Cleanup Failed", 2) == True) {
+ DEBUG(4, ("smb_pam_end: PAM: PAM_END OK.\n"));
+ return True;
+ }
+ }
+ DEBUG(2,("smb_pam_end: PAM: not initialised"));
+ return False;
+}
+
+/*
+ * Start PAM authentication for specified account
+ */
+
+static bool smb_pam_start(pam_handle_t **pamh, const char *user, const char *rhost, struct pam_conv *pconv)
+{
+ int pam_error;
+ const char *our_rhost;
+ char addr[INET6_ADDRSTRLEN];
+
+ *pamh = (pam_handle_t *)NULL;
+
+ DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", user));
+
+ pam_error = pam_start("samba", user, pconv, pamh);
+ if( !smb_pam_error_handler(*pamh, pam_error, "Init Failed", 0)) {
+ *pamh = (pam_handle_t *)NULL;
+ return False;
+ }
+
+ if (rhost == NULL) {
+ our_rhost = client_name(get_client_fd());
+ if (strequal(our_rhost,"UNKNOWN"))
+ our_rhost = client_addr(get_client_fd(),addr,sizeof(addr));
+ } else {
+ our_rhost = rhost;
+ }
+
+#ifdef PAM_RHOST
+ DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", our_rhost));
+ pam_error = pam_set_item(*pamh, PAM_RHOST, our_rhost);
+ if(!smb_pam_error_handler(*pamh, pam_error, "set rhost failed", 0)) {
+ smb_pam_end(*pamh, pconv);
+ *pamh = (pam_handle_t *)NULL;
+ return False;
+ }
+#endif
+#ifdef PAM_TTY
+ DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
+ pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
+ if (!smb_pam_error_handler(*pamh, pam_error, "set tty failed", 0)) {
+ smb_pam_end(*pamh, pconv);
+ *pamh = (pam_handle_t *)NULL;
+ return False;
+ }
+#endif
+ DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", user));
+ return True;
+}
+
+/*
+ * PAM Authentication Handler
+ */
+static NTSTATUS smb_pam_auth(pam_handle_t *pamh, const char *user)
+{
+ int pam_error;
+ NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+
+ /*
+ * To enable debugging set in /etc/pam.d/samba:
+ * auth required /lib/security/pam_pwdb.so nullok shadow audit
+ */
+
+ DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
+ pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
+ switch( pam_error ){
+ case PAM_AUTH_ERR:
+ DEBUG(2, ("smb_pam_auth: PAM: Authentication Error for user %s\n", user));
+ break;
+ case PAM_CRED_INSUFFICIENT:
+ DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
+ break;
+ case PAM_AUTHINFO_UNAVAIL:
+ DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
+ break;
+ case PAM_MAXTRIES:
+ DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
+ break;
+ case PAM_ABORT:
+ DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
+ break;
+ default:
+ DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
+ break;
+ }
+
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Authentication Failure", 2, &nt_status);
+ return nt_status;
+}
+
+/*
+ * PAM Account Handler
+ */
+static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user)
+{
+ int pam_error;
+ NTSTATUS nt_status = NT_STATUS_ACCOUNT_DISABLED;
+
+ DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
+ pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
+ switch( pam_error ) {
+ case PAM_AUTHTOK_EXPIRED:
+ DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
+ break;
+ case PAM_ACCT_EXPIRED:
+ DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
+ break;
+ case PAM_AUTH_ERR:
+ DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
+ break;
+ case PAM_PERM_DENIED:
+ DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
+ break;
+ default:
+ DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
+ break;
+ }
+
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Account Check Failed", 2, &nt_status);
+ return nt_status;
+}
+
+/*
+ * PAM Credential Setting
+ */
+
+static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user)
+{
+ int pam_error;
+ NTSTATUS nt_status = NT_STATUS_NO_TOKEN;
+
+ /*
+ * This will allow samba to aquire a kerberos token. And, when
+ * exporting an AFS cell, be able to /write/ to this cell.
+ */
+
+ DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
+ pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
+ switch( pam_error ) {
+ case PAM_CRED_UNAVAIL:
+ DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
+ break;
+ case PAM_CRED_EXPIRED:
+ DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
+ break;
+ case PAM_CRED_ERR:
+ DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
+ break;
+ default:
+ DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
+ break;
+ }
+
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Set Credential Failure", 2, &nt_status);
+ return nt_status;
+}
+
+/*
+ * PAM Internal Session Handler
+ */
+static bool smb_internal_pam_session(pam_handle_t *pamh, const char *user, const char *tty, bool flag)
+{
+ int pam_error;
+
+#ifdef PAM_TTY
+ DEBUG(4,("smb_internal_pam_session: PAM: tty set to: %s\n", tty));
+ pam_error = pam_set_item(pamh, PAM_TTY, tty);
+ if (!smb_pam_error_handler(pamh, pam_error, "set tty failed", 0))
+ return False;
+#endif
+
+ if (flag) {
+ pam_error = pam_open_session(pamh, PAM_SILENT);
+ if (!smb_pam_error_handler(pamh, pam_error, "session setup failed", 0))
+ return False;
+ } else {
+ pam_setcred(pamh, (PAM_DELETE_CRED|PAM_SILENT)); /* We don't care if this fails */
+ pam_error = pam_close_session(pamh, PAM_SILENT); /* This will probably pick up the error anyway */
+ if (!smb_pam_error_handler(pamh, pam_error, "session close failed", 0))
+ return False;
+ }
+ return (True);
+}
+
+/*
+ * Internal PAM Password Changer.
+ */
+
+static bool smb_pam_chauthtok(pam_handle_t *pamh, const char * user)
+{
+ int pam_error;
+
+ DEBUG(4,("smb_pam_chauthtok: PAM: Password Change for User: %s\n", user));
+
+ pam_error = pam_chauthtok(pamh, PAM_SILENT); /* Change Password */
+
+ switch( pam_error ) {
+ case PAM_AUTHTOK_ERR:
+ DEBUG(2, ("PAM: unable to obtain the new authentication token - is password to weak?\n"));
+ break;
+
+ /* This doesn't seem to be defined on Solaris. JRA */
+#ifdef PAM_AUTHTOK_RECOVER_ERR
+ case PAM_AUTHTOK_RECOVER_ERR:
+ DEBUG(2, ("PAM: unable to obtain the old authentication token - was the old password wrong?.\n"));
+ break;
+#endif
+
+ case PAM_AUTHTOK_LOCK_BUSY:
+ DEBUG(2, ("PAM: unable to change the authentication token since it is currently locked.\n"));
+ break;
+ case PAM_AUTHTOK_DISABLE_AGING:
+ DEBUG(2, ("PAM: Authentication token aging has been disabled.\n"));
+ break;
+ case PAM_PERM_DENIED:
+ DEBUG(0, ("PAM: Permission denied.\n"));
+ break;
+ case PAM_TRY_AGAIN:
+ DEBUG(0, ("PAM: Could not update all authentication token(s). No authentication tokens were updated.\n"));
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(0, ("PAM: User not known to PAM\n"));
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("PAM: Account OK for User: %s\n", user));
+ break;
+ default:
+ DEBUG(0, ("PAM: UNKNOWN PAM ERROR (%d) for User: %s\n", pam_error, user));
+ }
+
+ if(!smb_pam_error_handler(pamh, pam_error, "Password Change Failed", 2)) {
+ return False;
+ }
+
+ /* If this point is reached, the password has changed. */
+ return True;
+}
+
+/*
+ * PAM Externally accessible Session handler
+ */
+
+bool smb_pam_claim_session(char *user, char *tty, char *rhost)
+{
+ pam_handle_t *pamh = NULL;
+ struct pam_conv *pconv = NULL;
+
+ /* Ignore PAM if told to. */
+
+ if (!lp_obey_pam_restrictions())
+ return True;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
+ return False;
+
+ if (!smb_pam_start(&pamh, user, rhost, pconv))
+ return False;
+
+ if (!smb_internal_pam_session(pamh, user, tty, True)) {
+ smb_pam_end(pamh, pconv);
+ return False;
+ }
+
+ return smb_pam_end(pamh, pconv);
+}
+
+/*
+ * PAM Externally accessible Session handler
+ */
+
+bool smb_pam_close_session(char *user, char *tty, char *rhost)
+{
+ pam_handle_t *pamh = NULL;
+ struct pam_conv *pconv = NULL;
+
+ /* Ignore PAM if told to. */
+
+ if (!lp_obey_pam_restrictions())
+ return True;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
+ return False;
+
+ if (!smb_pam_start(&pamh, user, rhost, pconv))
+ return False;
+
+ if (!smb_internal_pam_session(pamh, user, tty, False)) {
+ smb_pam_end(pamh, pconv);
+ return False;
+ }
+
+ return smb_pam_end(pamh, pconv);
+}
+
+/*
+ * PAM Externally accessible Account handler
+ */
+
+NTSTATUS smb_pam_accountcheck(const char * user)
+{
+ NTSTATUS nt_status = NT_STATUS_ACCOUNT_DISABLED;
+ pam_handle_t *pamh = NULL;
+ struct pam_conv *pconv = NULL;
+
+ /* Ignore PAM if told to. */
+
+ if (!lp_obey_pam_restrictions())
+ return NT_STATUS_OK;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if (!smb_pam_start(&pamh, user, NULL, pconv))
+ return NT_STATUS_ACCOUNT_DISABLED;
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_pam_account(pamh, user)))
+ DEBUG(0, ("smb_pam_accountcheck: PAM: Account Validation Failed - Rejecting User %s!\n", user));
+
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+}
+
+/*
+ * PAM Password Validation Suite
+ */
+
+NTSTATUS smb_pam_passcheck(const char * user, const char * password)
+{
+ pam_handle_t *pamh = NULL;
+ NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+ struct pam_conv *pconv = NULL;
+
+ /*
+ * Note we can't ignore PAM here as this is the only
+ * way of doing auths on plaintext passwords when
+ * compiled --with-pam.
+ */
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, password, NULL)) == NULL)
+ return NT_STATUS_LOGON_FAILURE;
+
+ if (!smb_pam_start(&pamh, user, NULL, pconv))
+ return NT_STATUS_LOGON_FAILURE;
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_pam_auth(pamh, user))) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_auth failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_pam_account(pamh, user))) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_account failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_pam_setcred(pamh, user))) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_setcred failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+ }
+
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+}
+
+/*
+ * PAM Password Change Suite
+ */
+
+bool smb_pam_passchange(const char * user, const char * oldpassword, const char * newpassword)
+{
+ /* Appropriate quantities of root should be obtained BEFORE calling this function */
+ struct pam_conv *pconv = NULL;
+ pam_handle_t *pamh = NULL;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_passchange_conv, user, oldpassword, newpassword)) == NULL)
+ return False;
+
+ if(!smb_pam_start(&pamh, user, NULL, pconv))
+ return False;
+
+ if (!smb_pam_chauthtok(pamh, user)) {
+ DEBUG(0, ("smb_pam_passchange: PAM: Password Change Failed for user %s!\n", user));
+ smb_pam_end(pamh, pconv);
+ return False;
+ }
+
+ return smb_pam_end(pamh, pconv);
+}
+
+#else
+
+/* If PAM not used, no PAM restrictions on accounts. */
+NTSTATUS smb_pam_accountcheck(const char * user)
+{
+ return NT_STATUS_OK;
+}
+
+/* If PAM not used, also no PAM restrictions on sessions. */
+bool smb_pam_claim_session(char *user, char *tty, char *rhost)
+{
+ return True;
+}
+
+/* If PAM not used, also no PAM restrictions on sessions. */
+bool smb_pam_close_session(char *in_user, char *tty, char *rhost)
+{
+ return True;
+}
+#endif /* WITH_PAM */
diff --git a/source3/auth/pass_check.c b/source3/auth/pass_check.c
new file mode 100644
index 0000000000..813540d9fa
--- /dev/null
+++ b/source3/auth/pass_check.c
@@ -0,0 +1,874 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* this module is for checking a username/password against a system
+ password database. The SMB encrypted password support is elsewhere */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+/* these are kept here to keep the string_combinations function simple */
+static char *ths_user;
+
+static const char *get_this_user(void)
+{
+ if (!ths_user) {
+ return "";
+ }
+ return ths_user;
+}
+
+#if defined(WITH_PAM) || defined(OSF1_ENH_SEC)
+static const char *set_this_user(const char *newuser)
+{
+ char *orig_user = ths_user;
+ ths_user = SMB_STRDUP(newuser);
+ SAFE_FREE(orig_user);
+ return ths_user;
+}
+#endif
+
+#if !defined(WITH_PAM)
+static char *ths_salt;
+/* This must be writable. */
+static char *get_this_salt(void)
+{
+ return ths_salt;
+}
+
+/* We may be setting a modified version of the same
+ * string, so don't free before use. */
+
+static const char *set_this_salt(const char *newsalt)
+{
+ char *orig_salt = ths_salt;
+ ths_salt = SMB_STRDUP(newsalt);
+ SAFE_FREE(orig_salt);
+ return ths_salt;
+}
+
+static char *ths_crypted;
+static const char *get_this_crypted(void)
+{
+ if (!ths_crypted) {
+ return "";
+ }
+ return ths_crypted;
+}
+
+static const char *set_this_crypted(const char *newcrypted)
+{
+ char *orig_crypted = ths_crypted;
+ ths_crypted = SMB_STRDUP(newcrypted);
+ SAFE_FREE(orig_crypted);
+ return ths_crypted;
+}
+#endif
+
+#ifdef WITH_AFS
+
+#include <afs/stds.h>
+#include <afs/kautils.h>
+
+/*******************************************************************
+check on AFS authentication
+********************************************************************/
+static bool afs_auth(char *user, char *password)
+{
+ long password_expires = 0;
+ char *reason;
+
+ /* For versions of AFS prior to 3.3, this routine has few arguments, */
+ /* but since I can't find the old documentation... :-) */
+ setpag();
+ if (ka_UserAuthenticateGeneral
+ (KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG, user, (char *)0, /* instance */
+ (char *)0, /* cell */
+ password, 0, /* lifetime, default */
+ &password_expires, /*days 'til it expires */
+ 0, /* spare 2 */
+ &reason) == 0)
+ {
+ return (True);
+ }
+ DEBUG(1,
+ ("AFS authentication for \"%s\" failed (%s)\n", user, reason));
+ return (False);
+}
+#endif
+
+
+#ifdef WITH_DFS
+
+#include <dce/dce_error.h>
+#include <dce/sec_login.h>
+
+/*****************************************************************
+ This new version of the DFS_AUTH code was donated by Karsten Muuss
+ <muuss@or.uni-bonn.de>. It fixes the following problems with the
+ old code :
+
+ - Server credentials may expire
+ - Client credential cache files have wrong owner
+ - purge_context() function is called with invalid argument
+
+ This new code was modified to ensure that on exit the uid/gid is
+ still root, and the original directory is restored. JRA.
+******************************************************************/
+
+sec_login_handle_t my_dce_sec_context;
+int dcelogin_atmost_once = 0;
+
+/*******************************************************************
+check on a DCE/DFS authentication
+********************************************************************/
+static bool dfs_auth(char *user, char *password)
+{
+ struct tm *t;
+ error_status_t err;
+ int err2;
+ int prterr;
+ signed32 expire_time, current_time;
+ boolean32 password_reset;
+ struct passwd *pw;
+ sec_passwd_rec_t passwd_rec;
+ sec_login_auth_src_t auth_src = sec_login_auth_src_network;
+ unsigned char dce_errstr[dce_c_error_string_len];
+ gid_t egid;
+
+ if (dcelogin_atmost_once)
+ return (False);
+
+#ifdef HAVE_CRYPT
+ /*
+ * We only go for a DCE login context if the given password
+ * matches that stored in the local password file..
+ * Assumes local passwd file is kept in sync w/ DCE RGY!
+ */
+
+ if (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()))
+ {
+ return (False);
+ }
+#endif
+
+ sec_login_get_current_context(&my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_certify_identity(my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ time(&current_time);
+
+ if (expire_time < (current_time + 60))
+ {
+ struct passwd *pw;
+ sec_passwd_rec_t *key;
+
+ sec_login_get_pwent(my_dce_sec_context,
+ (sec_login_passwd_t *) & pw, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_refresh_identity(my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't refresh identity. %s\n",
+ dce_errstr));
+
+ return (False);
+ }
+
+ sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL,
+ (unsigned char *)pw->pw_name,
+ sec_c_key_version_none,
+ (void **)&key, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get key for %s. %s\n",
+ pw->pw_name, dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_valid_and_cert_ident(my_dce_sec_context, key,
+ &password_reset, &auth_src,
+ &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0,
+ ("DCE can't validate and certify identity for %s. %s\n",
+ pw->pw_name, dce_errstr));
+ }
+
+ sec_key_mgmt_free_key(key, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't free key.\n", dce_errstr));
+ }
+ }
+
+ if (sec_login_setup_identity((unsigned char *)user,
+ sec_login_no_flags,
+ &my_dce_sec_context, &err) == 0)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
+ user, dce_errstr));
+ return (False);
+ }
+
+ sec_login_get_pwent(my_dce_sec_context,
+ (sec_login_passwd_t *) & pw, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_purge_context(&my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ /*
+ * NB. I'd like to change these to call something like change_to_user()
+ * instead but currently we don't have a connection
+ * context to become the correct user. This is already
+ * fairly platform specific code however, so I think
+ * this should be ok. I have added code to go
+ * back to being root on error though. JRA.
+ */
+
+ egid = getegid();
+
+ set_effective_gid(pw->pw_gid);
+ set_effective_uid(pw->pw_uid);
+
+ if (sec_login_setup_identity((unsigned char *)user,
+ sec_login_no_flags,
+ &my_dce_sec_context, &err) == 0)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
+ user, dce_errstr));
+ goto err;
+ }
+
+ sec_login_get_pwent(my_dce_sec_context,
+ (sec_login_passwd_t *) & pw, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
+ goto err;
+ }
+
+ passwd_rec.version_number = sec_passwd_c_version_none;
+ passwd_rec.pepper = NULL;
+ passwd_rec.key.key_type = sec_passwd_plain;
+ passwd_rec.key.tagged_union.plain = (idl_char *) password;
+
+ sec_login_validate_identity(my_dce_sec_context,
+ &passwd_rec, &password_reset,
+ &auth_src, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0,
+ ("DCE Identity Validation failed for principal %s: %s\n",
+ user, dce_errstr));
+ goto err;
+ }
+
+ sec_login_certify_identity(my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr));
+ goto err;
+ }
+
+ if (auth_src != sec_login_auth_src_network)
+ {
+ DEBUG(0, ("DCE context has no network credentials.\n"));
+ }
+
+ sec_login_set_context(my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0,
+ ("DCE login failed for principal %s, cant set context: %s\n",
+ user, dce_errstr));
+
+ sec_login_purge_context(&my_dce_sec_context, &err);
+ goto err;
+ }
+
+ sec_login_get_pwent(my_dce_sec_context,
+ (sec_login_passwd_t *) & pw, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
+ goto err;
+ }
+
+ DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n",
+ user, sys_getpid()));
+
+ DEBUG(3, ("DCE principal: %s\n"
+ " uid: %d\n"
+ " gid: %d\n",
+ pw->pw_name, pw->pw_uid, pw->pw_gid));
+ DEBUG(3, (" info: %s\n"
+ " dir: %s\n"
+ " shell: %s\n",
+ pw->pw_gecos, pw->pw_dir, pw->pw_shell));
+
+ sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
+ goto err;
+ }
+
+ set_effective_uid(0);
+ set_effective_gid(0);
+
+ t = localtime(&expire_time);
+ if (t) {
+ const char *asct = asctime(t);
+ if (asct) {
+ DEBUG(0,("DCE context expires: %s", asct));
+ }
+ }
+
+ dcelogin_atmost_once = 1;
+ return (True);
+
+ err:
+
+ /* Go back to root, JRA. */
+ set_effective_uid(0);
+ set_effective_gid(egid);
+ return (False);
+}
+
+void dfs_unlogin(void)
+{
+ error_status_t err;
+ int err2;
+ unsigned char dce_errstr[dce_c_error_string_len];
+
+ sec_login_purge_context(&my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0,
+ ("DCE purge login context failed for server instance %d: %s\n",
+ sys_getpid(), dce_errstr));
+ }
+}
+#endif
+
+#ifdef LINUX_BIGCRYPT
+/****************************************************************************
+an enhanced crypt for Linux to handle password longer than 8 characters
+****************************************************************************/
+static int linux_bigcrypt(char *password, char *salt1, char *crypted)
+{
+#define LINUX_PASSWORD_SEG_CHARS 8
+ char salt[3];
+ int i;
+
+ StrnCpy(salt, salt1, 2);
+ crypted += 2;
+
+ for (i = strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
+ char *p = crypt(password, salt) + 2;
+ if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
+ return (0);
+ password += LINUX_PASSWORD_SEG_CHARS;
+ crypted += strlen(p);
+ }
+
+ return (1);
+}
+#endif
+
+#ifdef OSF1_ENH_SEC
+/****************************************************************************
+an enhanced crypt for OSF1
+****************************************************************************/
+static char *osf1_bigcrypt(char *password, char *salt1)
+{
+ static char result[AUTH_MAX_PASSWD_LENGTH] = "";
+ char *p1;
+ char *p2 = password;
+ char salt[3];
+ int i;
+ int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
+ if (strlen(password) % AUTH_CLEARTEXT_SEG_CHARS)
+ parts++;
+
+ StrnCpy(salt, salt1, 2);
+ StrnCpy(result, salt1, 2);
+ result[2] = '\0';
+
+ for (i = 0; i < parts; i++) {
+ p1 = crypt(p2, salt);
+ strncat(result, p1 + 2,
+ AUTH_MAX_PASSWD_LENGTH - strlen(p1 + 2) - 1);
+ StrnCpy(salt, &result[2 + i * AUTH_CIPHERTEXT_SEG_CHARS], 2);
+ p2 += AUTH_CLEARTEXT_SEG_CHARS;
+ }
+
+ return (result);
+}
+#endif
+
+
+/****************************************************************************
+apply a function to upper/lower case combinations
+of a string and return true if one of them returns true.
+try all combinations with N uppercase letters.
+offset is the first char to try and change (start with 0)
+it assumes the string starts lowercased
+****************************************************************************/
+static NTSTATUS string_combinations2(char *s, int offset, NTSTATUS (*fn) (const char *),
+ int N)
+{
+ int len = strlen(s);
+ int i;
+ NTSTATUS nt_status;
+
+#ifdef PASSWORD_LENGTH
+ len = MIN(len, PASSWORD_LENGTH);
+#endif
+
+ if (N <= 0 || offset >= len)
+ return (fn(s));
+
+ for (i = offset; i < (len - (N - 1)); i++) {
+ char c = s[i];
+ if (!islower_ascii(c))
+ continue;
+ s[i] = toupper_ascii(c);
+ if (!NT_STATUS_EQUAL(nt_status = string_combinations2(s, i + 1, fn, N - 1),NT_STATUS_WRONG_PASSWORD)) {
+ return (nt_status);
+ }
+ s[i] = c;
+ }
+ return (NT_STATUS_WRONG_PASSWORD);
+}
+
+/****************************************************************************
+apply a function to upper/lower case combinations
+of a string and return true if one of them returns true.
+try all combinations with up to N uppercase letters.
+offset is the first char to try and change (start with 0)
+it assumes the string starts lowercased
+****************************************************************************/
+static NTSTATUS string_combinations(char *s, NTSTATUS (*fn) (const char *), int N)
+{
+ int n;
+ NTSTATUS nt_status;
+ for (n = 1; n <= N; n++)
+ if (!NT_STATUS_EQUAL(nt_status = string_combinations2(s, 0, fn, n), NT_STATUS_WRONG_PASSWORD))
+ return nt_status;
+ return NT_STATUS_WRONG_PASSWORD;
+}
+
+
+/****************************************************************************
+core of password checking routine
+****************************************************************************/
+static NTSTATUS password_check(const char *password)
+{
+#ifdef WITH_PAM
+ return smb_pam_passcheck(get_this_user(), password);
+#else
+
+ bool ret;
+
+#ifdef WITH_AFS
+ if (afs_auth(get_this_user(), password))
+ return NT_STATUS_OK;
+#endif /* WITH_AFS */
+
+#ifdef WITH_DFS
+ if (dfs_auth(get_this_user(), password))
+ return NT_STATUS_OK;
+#endif /* WITH_DFS */
+
+#ifdef OSF1_ENH_SEC
+
+ ret = (strcmp(osf1_bigcrypt(password, get_this_salt()),
+ get_this_crypted()) == 0);
+ if (!ret) {
+ DEBUG(2,
+ ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
+ ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
+ }
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+#endif /* OSF1_ENH_SEC */
+
+#ifdef ULTRIX_AUTH
+ ret = (strcmp((char *)crypt16(password, get_this_salt()), get_this_crypted()) == 0);
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+#endif /* ULTRIX_AUTH */
+
+#ifdef LINUX_BIGCRYPT
+ ret = (linux_bigcrypt(password, get_this_salt(), get_this_crypted()));
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#endif /* LINUX_BIGCRYPT */
+
+#if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
+
+ /*
+ * Some systems have bigcrypt in the C library but might not
+ * actually use it for the password hashes (HPUX 10.20) is
+ * a noteable example. So we try bigcrypt first, followed
+ * by crypt.
+ */
+
+ if (strcmp(bigcrypt(password, get_this_salt()), get_this_crypted()) == 0)
+ return NT_STATUS_OK;
+ else
+ ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
+
+#ifdef HAVE_BIGCRYPT
+ ret = (strcmp(bigcrypt(password, get_this_salt()), get_this_crypted()) == 0);
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#endif /* HAVE_BIGCRYPT */
+
+#ifndef HAVE_CRYPT
+ DEBUG(1, ("Warning - no crypt available\n"));
+ return NT_STATUS_LOGON_FAILURE;
+#else /* HAVE_CRYPT */
+ ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#endif /* HAVE_CRYPT */
+#endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
+#endif /* WITH_PAM */
+}
+
+
+
+/****************************************************************************
+CHECK if a username/password is OK
+the function pointer fn() points to a function to call when a successful
+match is found and is used to update the encrypted password file
+return NT_STATUS_OK on correct match, appropriate error otherwise
+****************************************************************************/
+
+NTSTATUS pass_check(const struct passwd *pass, const char *user, const char *password,
+ int pwlen, bool (*fn) (const char *, const char *), bool run_cracker)
+{
+ char *pass2 = NULL;
+ int level = lp_passwordlevel();
+
+ NTSTATUS nt_status;
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
+#endif
+
+ if (!password)
+ return NT_STATUS_LOGON_FAILURE;
+
+ if (((!*password) || (!pwlen)) && !lp_null_passwords())
+ return NT_STATUS_LOGON_FAILURE;
+
+#if defined(WITH_PAM)
+
+ /*
+ * If we're using PAM we want to short-circuit all the
+ * checks below and dive straight into the PAM code.
+ */
+
+ if (set_this_user(user) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(4, ("pass_check: Checking (PAM) password for user %s (l=%d)\n", user, pwlen));
+
+#else /* Not using PAM */
+
+ DEBUG(4, ("pass_check: Checking password for user %s (l=%d)\n", user, pwlen));
+
+ if (!pass) {
+ DEBUG(3, ("Couldn't find user %s\n", user));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+
+ /* Copy into global for the convenience of looping code */
+ /* Also the place to keep the 'password' no matter what
+ crazy struct it started in... */
+ if (set_this_crypted(pass->pw_passwd) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (set_this_salt(pass->pw_passwd) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+#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) {
+ if (set_this_crypted(spass->sp_pwdp) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (set_this_salt(spass->sp_pwdp) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ }
+#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) {
+ if (set_this_crypted(pr_pw->ufld.fd_encrypt) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ }
+#endif
+
+#ifdef HAVE_GETPWANAM
+ {
+ struct passwd_adjunct *pwret;
+ pwret = getpwanam(s);
+ if (pwret && pwret->pwa_passwd) {
+ if (set_this_crypted(pwret->pwa_passwd) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ }
+#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) {
+ if (set_this_user(mypasswd->ufld.fd_name) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (set_this_crypted(mypasswd->ufld.fd_encrypt) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ DEBUG(5,
+ ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
+ user));
+ }
+ }
+#endif
+
+#ifdef ULTRIX_AUTH
+ {
+ AUTHORIZATION *ap = getauthuid(pass->pw_uid);
+ if (ap) {
+ if (set_this_crypted(ap->a_password) == NULL) {
+ endauthent();
+ return NT_STATUS_NO_MEMORY;
+ }
+ endauthent();
+ }
+ }
+#endif
+
+#if defined(HAVE_TRUNCATED_SALT)
+ /* crypt on some platforms (HPUX in particular)
+ won't work with more than 2 salt characters. */
+ {
+ char *trunc_salt = get_this_salt();
+ if (!trunc_salt || strlen(trunc_salt) < 2) {
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ trunc_salt[2] = 0;
+ if (set_this_salt(trunc_salt) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+#endif
+
+ if (!get_this_crypted() || !*get_this_crypted()) {
+ if (!lp_null_passwords()) {
+ DEBUG(2, ("Disallowing %s with null password\n",
+ get_this_user()));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ if (!*password) {
+ DEBUG(3,
+ ("Allowing access to %s with null password\n",
+ get_this_user()));
+ return NT_STATUS_OK;
+ }
+ }
+
+#endif /* defined(WITH_PAM) */
+
+ /* try it as it came to us */
+ nt_status = password_check(password);
+ if NT_STATUS_IS_OK(nt_status) {
+ if (fn) {
+ fn(user, password);
+ }
+ return (nt_status);
+ } else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
+ /* No point continuing if its not the password thats to blame (ie PAM disabled). */
+ return (nt_status);
+ }
+
+ if (!run_cracker) {
+ return (nt_status);
+ }
+
+ /* if the password was given to us with mixed case then we don't
+ * need to proceed as we know it hasn't been case modified by the
+ * client */
+ if (strhasupper(password) && strhaslower(password)) {
+ return nt_status;
+ }
+
+ /* make a copy of it */
+ pass2 = talloc_strdup(talloc_tos(), password);
+ if (!pass2) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* try all lowercase if it's currently all uppercase */
+ if (strhasupper(pass2)) {
+ strlower_m(pass2);
+ if NT_STATUS_IS_OK(nt_status = password_check(pass2)) {
+ if (fn)
+ fn(user, pass2);
+ return (nt_status);
+ }
+ }
+
+ /* give up? */
+ if (level < 1) {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /* last chance - all combinations of up to level chars upper! */
+ strlower_m(pass2);
+
+ if (NT_STATUS_IS_OK(nt_status = string_combinations(pass2, password_check, level))) {
+ if (fn)
+ fn(user, pass2);
+ return nt_status;
+ }
+
+ return NT_STATUS_WRONG_PASSWORD;
+}
diff --git a/source3/auth/token_util.c b/source3/auth/token_util.c
new file mode 100644
index 0000000000..d6cd2ea3a8
--- /dev/null
+++ b/source3/auth/token_util.c
@@ -0,0 +1,556 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Authentication utility functions
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Andrew Bartlett 2001
+ * Copyright (C) Jeremy Allison 2000-2001
+ * Copyright (C) Rafal Szczesniak 2002
+ * Copyright (C) Volker Lendecke 2006
+ * Copyright (C) Michael Adam 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* functions moved from auth/auth_util.c to minimize linker deps */
+
+#include "includes.h"
+
+/****************************************************************************
+ Check for a SID in an NT_USER_TOKEN
+****************************************************************************/
+
+bool nt_token_check_sid ( const DOM_SID *sid, const NT_USER_TOKEN *token )
+{
+ int i;
+
+ if ( !sid || !token )
+ return False;
+
+ for ( i=0; i<token->num_sids; i++ ) {
+ if ( sid_equal( sid, &token->user_sids[i] ) )
+ return True;
+ }
+
+ return False;
+}
+
+bool nt_token_check_domain_rid( NT_USER_TOKEN *token, uint32 rid )
+{
+ DOM_SID domain_sid;
+
+ /* if we are a domain member, the get the domain SID, else for
+ a DC or standalone server, use our own SID */
+
+ if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
+ if ( !secrets_fetch_domain_sid( lp_workgroup(),
+ &domain_sid ) ) {
+ DEBUG(1,("nt_token_check_domain_rid: Cannot lookup "
+ "SID for domain [%s]\n", lp_workgroup()));
+ return False;
+ }
+ }
+ else
+ sid_copy( &domain_sid, get_global_sam_sid() );
+
+ sid_append_rid( &domain_sid, rid );
+
+ return nt_token_check_sid( &domain_sid, token );\
+}
+
+/******************************************************************************
+ Create a token for the root user to be used internally by smbd.
+ This is similar to running under the context of the LOCAL_SYSTEM account
+ in Windows. This is a read-only token. Do not modify it or free() it.
+ Create a copy if your need to change it.
+******************************************************************************/
+
+NT_USER_TOKEN *get_root_nt_token( void )
+{
+ struct nt_user_token *token = NULL;
+ DOM_SID u_sid, g_sid;
+ struct passwd *pw;
+ void *cache_data;
+
+ cache_data = memcache_lookup_talloc(
+ NULL, SINGLETON_CACHE_TALLOC,
+ data_blob_string_const("root_nt_token"));
+
+ if (cache_data != NULL) {
+ return talloc_get_type_abort(
+ cache_data, struct nt_user_token);
+ }
+
+ if ( !(pw = sys_getpwnam( "root" )) ) {
+ DEBUG(0,("get_root_nt_token: getpwnam(\"root\") failed!\n"));
+ return NULL;
+ }
+
+ /* get the user and primary group SIDs; although the
+ BUILTIN\Administrators SId is really the one that matters here */
+
+ uid_to_sid(&u_sid, pw->pw_uid);
+ gid_to_sid(&g_sid, pw->pw_gid);
+
+ token = create_local_nt_token(NULL, &u_sid, False,
+ 1, &global_sid_Builtin_Administrators);
+
+ token->privileges = se_disk_operators;
+
+ memcache_add_talloc(
+ NULL, SINGLETON_CACHE_TALLOC,
+ data_blob_string_const("root_nt_token"), token);
+
+ return token;
+}
+
+
+/*
+ * Add alias SIDs from memberships within the partially created token SID list
+ */
+
+NTSTATUS add_aliases(const DOM_SID *domain_sid,
+ struct nt_user_token *token)
+{
+ uint32 *aliases;
+ size_t i, num_aliases;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx;
+
+ if (!(tmp_ctx = talloc_init("add_aliases"))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ aliases = NULL;
+ num_aliases = 0;
+
+ status = pdb_enum_alias_memberships(tmp_ctx, domain_sid,
+ token->user_sids,
+ token->num_sids,
+ &aliases, &num_aliases);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("pdb_enum_alias_memberships failed: %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ for (i=0; i<num_aliases; i++) {
+ DOM_SID alias_sid;
+ sid_compose(&alias_sid, domain_sid, aliases[i]);
+ status = add_sid_to_array_unique(token, &alias_sid,
+ &token->user_sids,
+ &token->num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("add_sid_to_array failed\n"));
+ goto done;
+ }
+ }
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static NTSTATUS add_builtin_administrators(struct nt_user_token *token,
+ const DOM_SID *dom_sid)
+{
+ DOM_SID domadm;
+ NTSTATUS status;
+
+ /* nothing to do if we aren't in a domain */
+
+ if ( !(IS_DC || lp_server_role()==ROLE_DOMAIN_MEMBER) ) {
+ return NT_STATUS_OK;
+ }
+
+ /* Find the Domain Admins SID */
+
+ if ( IS_DC ) {
+ sid_copy( &domadm, get_global_sam_sid() );
+ } else {
+ sid_copy(&domadm, dom_sid);
+ }
+ sid_append_rid( &domadm, DOMAIN_GROUP_RID_ADMINS );
+
+ /* Add Administrators if the user beloongs to Domain Admins */
+
+ if ( nt_token_check_sid( &domadm, token ) ) {
+ status = add_sid_to_array(token,
+ &global_sid_Builtin_Administrators,
+ &token->user_sids, &token->num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Create the requested BUILTIN if it doesn't already exist. This requires
+ * winbindd to be running.
+ *
+ * @param[in] rid BUILTIN rid to create
+ * @return Normal NTSTATUS return.
+ */
+static NTSTATUS create_builtin(uint32 rid)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ DOM_SID sid;
+ gid_t gid;
+
+ if (!sid_compose(&sid, &global_sid_Builtin, rid)) {
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ if (!sid_to_gid(&sid, &gid)) {
+ if (!lp_winbind_nested_groups() || !winbind_ping()) {
+ return NT_STATUS_PROTOCOL_UNREACHABLE;
+ }
+ status = pdb_create_builtin_alias(rid);
+ }
+ return status;
+}
+
+/**
+ * Add sid as a member of builtin_sid.
+ *
+ * @param[in] builtin_sid An existing builtin group.
+ * @param[in] dom_sid sid to add as a member of builtin_sid.
+ * @return Normal NTSTATUS return
+ */
+static NTSTATUS add_sid_to_builtin(const DOM_SID *builtin_sid,
+ const DOM_SID *dom_sid)
+{
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (!dom_sid || !builtin_sid) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = pdb_add_aliasmem(builtin_sid, dom_sid);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MEMBER_IN_ALIAS)) {
+ DEBUG(5, ("add_sid_to_builtin %s is already a member of %s\n",
+ sid_string_dbg(dom_sid),
+ sid_string_dbg(builtin_sid)));
+ return NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(4, ("add_sid_to_builtin %s could not be added to %s: "
+ "%s\n", sid_string_dbg(dom_sid),
+ sid_string_dbg(builtin_sid), nt_errstr(status)));
+ }
+ return status;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+NTSTATUS create_builtin_users(const DOM_SID *dom_sid)
+{
+ NTSTATUS status;
+ DOM_SID dom_users;
+
+ status = create_builtin(BUILTIN_ALIAS_RID_USERS);
+ if ( !NT_STATUS_IS_OK(status) ) {
+ DEBUG(5,("create_builtin_users: Failed to create Users\n"));
+ return status;
+ }
+
+ /* add domain users */
+ if ((IS_DC || (lp_server_role() == ROLE_DOMAIN_MEMBER))
+ && sid_compose(&dom_users, dom_sid, DOMAIN_GROUP_RID_USERS))
+ {
+ status = add_sid_to_builtin(&global_sid_Builtin_Users,
+ &dom_users);
+ }
+
+ return status;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+NTSTATUS create_builtin_administrators(const DOM_SID *dom_sid)
+{
+ NTSTATUS status;
+ DOM_SID dom_admins, root_sid;
+ fstring root_name;
+ enum lsa_SidType type;
+ TALLOC_CTX *ctx;
+ bool ret;
+
+ status = create_builtin(BUILTIN_ALIAS_RID_ADMINS);
+ if ( !NT_STATUS_IS_OK(status) ) {
+ DEBUG(5,("create_builtin_administrators: Failed to create Administrators\n"));
+ return status;
+ }
+
+ /* add domain admins */
+ if ((IS_DC || (lp_server_role() == ROLE_DOMAIN_MEMBER))
+ && sid_compose(&dom_admins, dom_sid, DOMAIN_GROUP_RID_ADMINS))
+ {
+ status = add_sid_to_builtin(&global_sid_Builtin_Administrators,
+ &dom_admins);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ /* add root */
+ if ( (ctx = talloc_init("create_builtin_administrators")) == NULL ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ fstr_sprintf( root_name, "%s\\root", get_global_sam_name() );
+ ret = lookup_name(ctx, root_name, LOOKUP_NAME_DOMAIN, NULL, NULL,
+ &root_sid, &type);
+ TALLOC_FREE( ctx );
+
+ if ( ret ) {
+ status = add_sid_to_builtin(&global_sid_Builtin_Administrators,
+ &root_sid);
+ }
+
+ return status;
+}
+
+
+/*******************************************************************
+ Create a NT token for the user, expanding local aliases
+*******************************************************************/
+
+struct nt_user_token *create_local_nt_token(TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ bool is_guest,
+ int num_groupsids,
+ const DOM_SID *groupsids)
+{
+ struct nt_user_token *result = NULL;
+ int i;
+ NTSTATUS status;
+ gid_t gid;
+ DOM_SID dom_sid;
+
+ DEBUG(10, ("Create local NT token for %s\n",
+ sid_string_dbg(user_sid)));
+
+ if (!(result = TALLOC_ZERO_P(mem_ctx, struct nt_user_token))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ /* Add the user and primary group sid */
+
+ status = add_sid_to_array(result, user_sid,
+ &result->user_sids, &result->num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ /* For guest, num_groupsids may be zero. */
+ if (num_groupsids) {
+ status = add_sid_to_array(result, &groupsids[0],
+ &result->user_sids,
+ &result->num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ }
+
+ /* Add in BUILTIN sids */
+
+ status = add_sid_to_array(result, &global_sid_World,
+ &result->user_sids, &result->num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ status = add_sid_to_array(result, &global_sid_Network,
+ &result->user_sids, &result->num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ if (is_guest) {
+ status = add_sid_to_array(result, &global_sid_Builtin_Guests,
+ &result->user_sids,
+ &result->num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ } else {
+ status = add_sid_to_array(result,
+ &global_sid_Authenticated_Users,
+ &result->user_sids,
+ &result->num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ }
+
+ /* Now the SIDs we got from authentication. These are the ones from
+ * the info3 struct or from the pdb_enum_group_memberships, depending
+ * on who authenticated the user.
+ * Note that we start the for loop at "1" here, we already added the
+ * first group sid as primary above. */
+
+ for (i=1; i<num_groupsids; i++) {
+ status = add_sid_to_array_unique(result, &groupsids[i],
+ &result->user_sids,
+ &result->num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ }
+
+ /* Deal with the BUILTIN\Administrators group. If the SID can
+ be resolved then assume that the add_aliasmem( S-1-5-32 )
+ handled it. */
+
+ if (!sid_to_gid(&global_sid_Builtin_Administrators, &gid)) {
+
+ become_root();
+ if (!secrets_fetch_domain_sid(lp_workgroup(), &dom_sid)) {
+ status = NT_STATUS_OK;
+ DEBUG(3, ("Failed to fetch domain sid for %s\n",
+ lp_workgroup()));
+ } else {
+ status = create_builtin_administrators(&dom_sid);
+ }
+ unbecome_root();
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
+ /* Add BUILTIN\Administrators directly to token. */
+ status = add_builtin_administrators(result, &dom_sid);
+ if ( !NT_STATUS_IS_OK(status) ) {
+ DEBUG(3, ("Failed to check for local "
+ "Administrators membership (%s)\n",
+ nt_errstr(status)));
+ }
+ } else if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(2, ("WARNING: Failed to create "
+ "BUILTIN\\Administrators group! Can "
+ "Winbind allocate gids?\n"));
+ }
+ }
+
+ /* Deal with the BUILTIN\Users group. If the SID can
+ be resolved then assume that the add_aliasmem( S-1-5-32 )
+ handled it. */
+
+ if (!sid_to_gid(&global_sid_Builtin_Users, &gid)) {
+
+ become_root();
+ if (!secrets_fetch_domain_sid(lp_workgroup(), &dom_sid)) {
+ status = NT_STATUS_OK;
+ DEBUG(3, ("Failed to fetch domain sid for %s\n",
+ lp_workgroup()));
+ } else {
+ status = create_builtin_users(&dom_sid);
+ }
+ unbecome_root();
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE) &&
+ !NT_STATUS_IS_OK(status))
+ {
+ DEBUG(2, ("WARNING: Failed to create BUILTIN\\Users group! "
+ "Can Winbind allocate gids?\n"));
+ }
+ }
+
+ /* Deal with local groups */
+
+ if (lp_winbind_nested_groups()) {
+
+ become_root();
+
+ /* Now add the aliases. First the one from our local SAM */
+
+ status = add_aliases(get_global_sam_sid(), result);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ unbecome_root();
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ /* Finally the builtin ones */
+
+ status = add_aliases(&global_sid_Builtin, result);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ unbecome_root();
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ unbecome_root();
+ }
+
+
+ get_privileges_for_sids(&result->privileges, result->user_sids,
+ result->num_sids);
+ return result;
+}
+
+/****************************************************************************
+ prints a NT_USER_TOKEN to debug output.
+****************************************************************************/
+
+void debug_nt_user_token(int dbg_class, int dbg_lev, NT_USER_TOKEN *token)
+{
+ size_t i;
+
+ if (!token) {
+ DEBUGC(dbg_class, dbg_lev, ("NT user token: (NULL)\n"));
+ return;
+ }
+
+ DEBUGC(dbg_class, dbg_lev,
+ ("NT user token of user %s\n",
+ sid_string_dbg(&token->user_sids[0]) ));
+ DEBUGADDC(dbg_class, dbg_lev,
+ ("contains %lu SIDs\n", (unsigned long)token->num_sids));
+ for (i = 0; i < token->num_sids; i++)
+ DEBUGADDC(dbg_class, dbg_lev,
+ ("SID[%3lu]: %s\n", (unsigned long)i,
+ sid_string_dbg(&token->user_sids[i])));
+
+ dump_se_priv( dbg_class, dbg_lev, &token->privileges );
+}
+
+/****************************************************************************
+ prints a UNIX 'token' to debug output.
+****************************************************************************/
+
+void debug_unix_user_token(int dbg_class, int dbg_lev, uid_t uid, gid_t gid,
+ int n_groups, gid_t *groups)
+{
+ int i;
+ DEBUGC(dbg_class, dbg_lev,
+ ("UNIX token of user %ld\n", (long int)uid));
+
+ DEBUGADDC(dbg_class, dbg_lev,
+ ("Primary group is %ld and contains %i supplementary "
+ "groups\n", (long int)gid, n_groups));
+ for (i = 0; i < n_groups; i++)
+ DEBUGADDC(dbg_class, dbg_lev, ("Group[%3i]: %ld\n", i,
+ (long int)groups[i]));
+}
+
+/* END */
diff --git a/source3/autogen.sh b/source3/autogen.sh
new file mode 100755
index 0000000000..018944e684
--- /dev/null
+++ b/source3/autogen.sh
@@ -0,0 +1,68 @@
+#!/bin/sh
+
+# Run this script to build samba from GIT.
+
+## insert all possible names (only works with
+## autoconf 2.x)
+TESTAUTOHEADER="autoheader autoheader-2.53 autoheader2.50 autoheader259 autoheader253"
+TESTAUTOCONF="autoconf autoconf-2.53 autoconf2.50 autoconf259 autoconf253"
+
+AUTOHEADERFOUND="0"
+AUTOCONFFOUND="0"
+
+
+##
+## Look for autoheader
+##
+for i in $TESTAUTOHEADER; do
+ if which $i > /dev/null 2>&1; then
+ if test `$i --version | head -n 1 | cut -d. -f 2 | sed "s/[^0-9]//g"` -ge 53; then
+ AUTOHEADER=$i
+ AUTOHEADERFOUND="1"
+ break
+ fi
+ fi
+done
+
+##
+## Look for autoconf
+##
+
+for i in $TESTAUTOCONF; do
+ if which $i > /dev/null 2>&1; then
+ if test `$i --version | head -n 1 | cut -d. -f 2 | sed "s/[^0-9]//g"` -ge 53; then
+ AUTOCONF=$i
+ AUTOCONFFOUND="1"
+ break
+ fi
+ fi
+done
+
+
+##
+## do we have it?
+##
+if test "$AUTOCONFFOUND" = "0" -o "$AUTOHEADERFOUND" = "0"; then
+ echo "$0: need autoconf 2.53 or later to build samba from GIT" >&2
+ exit 1
+fi
+
+echo "$0: running script/mkversion.sh"
+./script/mkversion.sh || exit 1
+
+rm -rf autom4te*.cache
+rm -f configure include/config.h*
+
+IPATHS="-Im4 -Ilib/replace"
+
+echo "$0: running $AUTOHEADER $IPATHS"
+$AUTOHEADER $IPATHS || exit 1
+
+echo "$0: running $AUTOCONF $IPATHS"
+$AUTOCONF $IPATHS || exit 1
+
+rm -rf autom4te*.cache
+
+echo "Now run ./configure and then make."
+exit 0
+
diff --git a/source3/change-log b/source3/change-log
new file mode 100644
index 0000000000..1f7798b541
--- /dev/null
+++ b/source3/change-log
@@ -0,0 +1,1878 @@
+SUPERCEDED Change Log for Samba
+^^^^^^^^^^
+
+Unless otherwise attributed, all changes were made by
+Andrew.Tridgell@anu.edu.au. All bugs to samba-bugs@samba.org.
+
+NOTE: THIS LOG IS IN CHRONOLOGICAL ORDER
+
+NOTE: From now on the cvs.log file will be used to give a complete log of
+changes to samba. This change-log is now obsolete.
+
+1.5.00 announced to mailing list
+
+1.5.01 1/12/93
+ - configuration through makefile only
+ - fixed silly bug that made the client not accept dir's from
+ the server
+ - tested and updated include files for ultrix, aix and solaris
+ - several things fixed thanks to pierson@ketje.enet.dec.com
+ who provided invaluable help and advice.
+
+1.5.02 1/12/93
+ - added username option to services file so connection
+ as non guest from lanmanager is possible
+ - made server abort when it can't read/write on a socket
+ - added logging to client
+
+1.5.03 2/12/93
+ - printing now works
+ - fixed a minor bug to do with hidden and system attributes
+
+1.5.04 2/12/93
+ - added reduce_name() call to fill in security hole.
+ - cleanup up debug stuff a little
+
+1.5.05 2/12/93
+ - fixed bug in reduce_name that affects services with base paths
+ that have a soft link in them.
+
+1.5.06 3/12/93
+ - used the reserved server field in the search status to hold the
+ directory pointer. This allows lots of directories to be open
+ at once by clients without stuffing things up.
+ - preserved all the client reserved bytes in the search status
+ in case they actually use them. Hopefully this will fix the annoying
+ empty directory dir bug. (it does)
+
+1.5.07 3/12/93
+ - fixed silly bug that caused volume ids to appear twice
+ - fixed a wrote-too-few bug in smb_send()
+
+1.5.08 3/12/93
+ - did the SMBsearch properly. It can now handle recursive searches.
+ In order to keep the required dir info I encode the dirptr and
+ the current dir offset (from telldir) into 5 bytes by using a table
+ on the last 7 bits of the first byte. The first bit is always on
+ as this byte must by != 0
+ This is all put in the "server reserved" search field.
+
+1.5.09 5/12/93
+ - added a prototype nameserver. It's broken but can at least interpret
+ incoming packets.
+ - minor fixes to the server and client
+
+
+1.5.10 5/12/93
+ - fixed silly unsigned/signed char bug that made dosshell noot see all files
+ - added nmbd to Makefile
+
+1.5.11 6/12/93
+ - made the volume label appear as the service name, rather than "Remote"
+ - made the nmbd actually work (a little) for lanman for dos
+
+1.5.12 7/12/93
+ - fixed broadcasting in the nameserver
+ - the smbd now correctly sets the pid and uid
+ - nmbd now seems to work enough to satisfy the MS client.
+
+
+1.5.13 7/12/93
+ - fixed a silly bug that truncated filenames
+ - added -B option to nameserver to specify bcast address
+ - added -R option to nameserver to prevent name registering
+ - fixed minor read() bug. Does this fix the "cmp" bug?
+
+1.5.14 8/12/93
+ - fixed a bug in send_login() in the client. Thanks to
+ tim.hudson@gslmail.mincom.oz.au for pointing this out.
+ - changed name_mangle() to pad to minimum of 32 bytes with spaces
+ - changed the returned buffer size in reply_connect() to not
+ count the 4 byte length field. This fixes the "can execute" bug
+ and the "comp" bug
+ - once again re-wrote the directory pointer handling code.
+ now "tree" works correctly
+
+1.5.15 9/12/93
+ - fixed name mangle bug introduced in 1.5.14 which stopped
+ nameserver from working
+
+1.5.16 9/12/93
+ - arrgh. another silly bug in name_mangle() causes the client to die.
+
+
+1.5.17 13/12/93
+ - some cosmetic cleanups to the code
+ - changed make_connection not to lower case the password (thanks
+ to bryan@alex.com)
+ - fixed accept() bug not initialising in_addrlen (thanks to
+ bogstad@cs.jhu.edu)
+ - fixed cd bug in client.c (thanks to joergs@toppoint.de)
+ - lots of fixes to the nameserver to read_socket and
+ associated routines. It should now correctly reply to the originating
+ address and use the correct broadcast.
+ (thanks to troyer@saifr00.ateng.az.honeywell.com)
+ - SVR4 patches from mark@scot1.ucsalf.ac.uk
+ - changed the default BUFFER_SIZE to 0xFFFF
+
+1.5.18 15/12/93
+ - minor fix to reply_printqueue() to zero data buffer array.
+ - added print command to client.
+ - fixed minor bug in cmd_put() in client where a handle could
+ be closed without being previously opened.
+ - minor cleanups to the client
+ - minor solaris fixes from lonnie@itg.ti.com
+ - SYSV, shadow password and dfree() fixes from mark@scot1.ucsalf.ac.uk
+ - fixed reply_delete() to not delete read-only files
+ - fixed infinite loop in reply_delete on "del ."
+ Thanks to mark@scot1.ucsalf.ac.uk for pointing this out.
+ - posix mode definitions and changes from mark@scot1.ucsalf.ac.uk
+
+
+1.5.19 18/12/93
+ - another very minor fix to dfree().
+ - minor change to SVR4 makefile entry from rossw@march.co.uk
+ - changed reply_open not to open directories, this fixes the
+ "copy .." bug pointed out by mark@scot1.ucsalf.ac.uk
+ - changed dos_mode() so it doesn't return hidden and system info
+ on directories.
+ - changed get_dir_entry() not to descend into proc/self under linux
+ control this with the DONT_DESCEND define in includes.h
+ - changed smb_setlen() to add in the SMB id. (thanks
+ to troyer@saifr00.ateng.az.honeywell.com)
+ - fixed minor bug in reply_dir() so it won't return a ACCESS_DENIED
+ when searching a directory that is unreadable
+ - removed second stat() from get_dir_entry() (speed up)
+ - made null searches close the dirptr (fixes big filesystem problem)
+ - fixed clean_name for cd .. (from magnus@axiom.se)
+
+
+1.5.20 28/12/93
+ - added debug statement in case of SMBcreate with volid set (leefi@microsoft.com)
+ - fixed a bug in dptr_close() so it sets the next_key to a better
+ value, this fixes a annoying dir bug
+ - LOTS of changes from jeremy@netcom.com (Jeremy Allison). This
+ makes it possible to at least connect to a NT server with the client
+ and also fixes up much of the socket/process code. This also includes
+ stuff for compiling on a sun386
+ - got the client working with the Syntax server (a commercial
+ smb-based server). This required a few minor changes so the xmit
+ sizes were negotiated properly.
+ - added support for OSF1, tested on a DEC3000/400 alpha.
+ - fixed the ifconf support under ultrix
+
+1.5.21 31/12/93
+ - minor cosmetic change to reduce_name()
+ - changes for HPUX from ppk@atk.tpo.fi (Pasi Kaara)
+ - minor fix to nameserver
+ - revamped configuration file format. It now takes a Windows-style
+ (.INI style) configuration file. See the file services for
+ full details of the format. New files: loadparm.c, loadparm.h,
+ params.c, params.h, testparm.c. Several changes to smb.h, local.h,
+ server.c, Makefile. The services structure is no longer visible
+ to the rest of the system. (Karl Auer)
+ - added ability to specify a print command on a per service basis
+ and globally via the configuration file. Also allows guest account
+ to be specified in the configuration file. Made appropriate changes
+ to server.c so that these data items are obtained from the config
+ module rather than from hardcoded strings (though the hardcoded
+ strings are still the source of the defaults). (Karl Auer)
+ - renamed old-style configuration file to services.old (Karl Auer)
+ - changed README to reflect new configuration details. (Karl Auer)
+ - removed an item from the bugs wishlist (now supplied!) (Karl Auer)
+ - protected smb.h against multiple compilation. (Karl Auer)
+ - protected local.h against multiple compilation. (Karl Auer)
+ - made config stuff do dynamic allocation
+ - added "homes" capability
+ - added create_mask to each service in config
+
+1.5.22 3/1/94
+ - added "root dir" option for extra security
+ - added -n option to client (useful for OS/2)
+ - changed operation of -n to nameserver to be more useful
+ - patches from Jeremy Allison (jeremy@netcom.com)
+ fixing bug in set_message(), fixing up wait3() for SYSV,
+ making cd check the path in the client, allowing fetching to stdin
+ in client, and enhancing prompt in client to include directory.
+ - made the -D become_daemon() actually detach from the tty. This
+ may need tuning for different flavors of unix.
+ - added "dont descend" option to each service to prevent infinite
+ loops on recursive filesystems.
+ - updated README to add "running as a daemon" and a simple
+ smb.conf file.
+ - HP/UX fixes from ppk@atk.tpo.fi
+ - made lock calls only if opened with write enabled, as pointed out
+ by gadams@ddrive.demon.co.uk
+
+1.5.23 4/1/94
+ - minor fix to logging of data in receive_smb(). It used to
+ miss the last 4 bytes of packets.
+ - added the pid,uid and mid fields to the negotiation phase of
+ the client.
+ - made client able to print from stdin
+ - added password on command line for client
+ - created a sample printcap input filter "smbprint"
+ - several fixes to client to work with OS/2
+ - added mput, mget, prompt and lcd to client
+
+1.5.24 5/1/94
+ - a resend of 1.5.23 as I managed to not include the new
+ prompt, mput and mget code.
+
+1.5.25 7/1/94
+ - change -B on nameserver so it can override the broadcast address
+ - minor changes to printing in client so OS/2 server can handle it.
+ - fixed reply_access() where OK was not being initialised
+ - added "max xmit" to global parameters.
+ - changed create to open with O_RDWR instead of O_WRONLY
+ - added printmode command to client
+ - made help return extra help on a specified command in client
+ - fixed return code in chkpath
+ - added "recurse" and "lowercase" options to client
+ - fixed some error codes from server
+ - added -I option to client
+ - fix for become_daemon() for HPUX from ppk@atk.tpo.fi
+ - added "hosts allow" and "hosts deny" to server
+ - added keepalives to server
+ - added "access" feature to testparam
+ - NetBSD patches from sreiz@aie.nl
+
+1.5.26 8/1/94
+ - changed semantics of hosts access code to do more sensible defaults
+ when either of "hosts allow" or "hosts deny" is blank
+ - added the SO_KEEPALIVE option to configurations of sockets in the
+ server
+ - made some of the SVAL fns into macros to keep fussy compilers from
+ complaining
+ - fixed several null pointer bugs in check_access(). These bugs
+ made 1.5.25 unuseable for many people.
+ - fixed null pointer reference of lp_dontdescend()
+ - reload services file after each new connection.
+
+1.5.27 11/1/94
+ - fixed opening mode for reply_open() in server
+ - patches from Jeremy Allison (jeremy@netcom.com) to support the
+ "core+" protocol. The patches also inclued some other features, such
+ as a new read_with_timeout() call (used by SMBreadbraw), and auto
+ detection of the need to create a socket.
+ - changed the default KEEPALIVE value to 0, as it caused
+ problems with Lanmanager.
+ - added tar capability to client when getting files
+ - altered unix_mode() to return x bits for directories
+ - fixed bug in trim_string()
+
+1.5.28 12/1/94
+ - cleaned up the debug levels a little so debug level 1 is a practical
+ level for general use
+ - fixed a bug in add_a_service() where a freed pointer was referenced. Thanks
+ to bryan@alex.com for finding the bug.
+ - fixed bug in time structure handling in server and client. Thanks to
+ bryan@alex.com for pointing out the bug.
+
+
+1.5.29 15/1/94
+ - fixed a silly bug in reply_open(). Thanks to
+ jeremy@netcom.com for pointing this out.
+ - fixed debug levels in client to be more sensible
+ - added raw read to client
+ - added -B option to client
+ - fixed several bugs in the client, mostly to do with the tar option
+ - added -E option to client
+
+1.5.30 16/1/94
+ - added lots of prototypes so compilers don't complain
+ - fixed minor bug in reply_rename() (thanks to ppk@atk.tpo.fi)
+ - added more support for LANMAN1.0 protocol.
+ - added SESSION SETUP AND X call
+ - added READ AND X call
+ - added TREE CONNECT AND X call
+ - added support for setbuffer for HPUX (thanks to ppk@atk.tpo.fi)
+
+1.5.31 29/1/94
+ - added support for user level security in smbclient eg:
+ smbclient "\\SERVER\SHARE" -U USERNAME%PASSWORD
+ - added error message decode as per SMB File Sharing
+ protocol extensions. (thanks to merik@blackadder.dsh.oz.au)
+ - added selection masks to smbclient that recurse down directory
+ tree. eg: mget *.* with recurse and mask *.c on will retrieve all
+ *.c files in the tree.
+ - patches for FreeBSD from kuku@acds.physik.rwth-aachen.de
+ - changed reduce_name() to trim ./ from front of strings and / from
+ back
+ - fixed a nasty bug in trim_string().
+ - numerous small changes to lots of stuff that I didn't
+ document while I was doing them. Sorry :-(
+ - slightly updated sockspy
+
+ - The following was done by Karl Auer (Karl.Auer@anu.edu.au)
+ - added processing in configuration file of a [printers] section. Allows
+ connection to any printer specified in /etc/printcap (or the file
+ specified in the global parameter 'printcap name').
+ - added full processing of 'available' flag to configuration file. A
+ service can now be 'turned off' by specifying 'available = no'. Of
+ dubious utility.
+ - added 'printcap =' parameter to [global] section in the configuration
+ file. This allows the normal /etc/printcap to be bypassed when
+ checking printer names for dynamic printer connections via [printers].
+ - added 'printer name =' parameters to both the [global] section and
+ services sections of the configuration file. This allows the printer
+ name only to be set, without having to specify an entire print
+ command.
+ - added some synonyms: 'writable' and 'write ok' have the opposite sense
+ to 'read only'. 'public' may be used instead of 'guest ok'. 'printer'
+ may be used instead of 'printer name'. 'printable' is the same as
+ 'print ok'. 'root' may be used instead of 'root dir' or 'root
+ directory'.
+ - added lots more detail to the sample configuration file to take
+ account of the above.
+ - many minor fixes to internal documentation in the configuration
+ sources.
+ - also - Man pages!
+
+
+1.5.32 3/2/94
+ - addition of smbd, smbclient and testparm man pages
+ from Karl Auer
+ - zombie process fix from lendecke@namu01.gwdg.de
+ - added capability to nmbd to serve names available
+ via gethostbyname().
+
+1.5.33 3/2/94
+ - fixed up getting of netmask so it works on more unix variants
+ - added -N option to nmbd
+ - changed GMT diff calculation. need to check it's right for
+ lots of OSes
+ - fixed a bug in read_and_X() and chain_reply() chaining now
+ seems to work correctly
+
+1.5.34 4/2/94
+ - fixed bug in client that meant it couldn't get/put files from WfWg
+ - fixed a bug in the server that caused lpr to return -1 under sunos
+ - fixed a few errors in the hosts allow section of the
+ smb.conf.5 manual page and added examples
+
+1.5.35 6/2/1994
+ - minor bugfix in reduce_name().
+ - changed width of "size" in client during a dir
+ - patches for NEXT (among other things) from lendecke@namu01.gwdg.de
+ - added -a switch to server, and made default action to append
+ to log file
+ - added deadtime options to [global] section for timing out
+ dead connections to the smbd.
+ - HPUX changes from Pasi.Kaara@atk.tpo.fi
+ - made use of unsigned char more consistent
+ - changed the way of getting the default username and host in the
+ client
+ - made LANMAN1 default to on in the client, off in server.
+ Use -DLANMAN1=1 to make it on in both.
+ - lots of casts and cleanups for various operating systems
+ - changes to the Makefile from Karl to auto-instal the man pages
+ - added a short history of the project to the distribution
+
+1.5.36 15/2/94
+ - fixed minor bug in Debug() (thanks to Pasi.Kaara@atk.tpo.fi)
+ - fixed bug in server.c so -a wasn't accepted.
+ - minor fixes to the client
+ - added hosts file to name server (-H option)
+ - added -G option for groups to nameserver
+ - cleanups and additions from Jeremy Allison, taking us
+ closer to LANMAN1.0. In particular the locking code was cleaned up
+ considerably.
+
+1.5.37 16/2/94
+ - fixed bug introduced in 1.5.36 which disabled SMBcreate
+
+1.5.38 18/2/94
+ - fixed get_broadcast() for ultrix (fix from iversen@dsfys1.fi.uib.no)
+ - added automatic group registration
+ - fixed bug in registration code
+ - made nmbd work better with WfWg, and probably others
+ - updated the man pages to include the new nmbd options.
+ - minor updates to the README
+ - fixed double log_out() in send_packet().
+ - fixed bug in smbclient so that "dir" didn't work correctly
+ with pathworks
+ - possibly fixed bug in server that led to "abort retry ignore" from
+ pathworks client when doing a "dir".
+ - changed behaviour of smbclient login slightly, to try a
+ blank password in SMBtcon if the right password fails, and a
+ session setup has succeeded. Some clients seem to use a blank
+ one if a session setup has succeeded.
+ - ISC patches from imb@asstdc.scgt.oz.au
+ - the client now tries to do name registration using a unicast.
+ Let me know if this helps anyone.
+ - tried to add a "contributed" line to each OS in the Makefile.
+
+1.5.39 18/2/94
+ - fixed silly C code that only worked with some compilers
+ - fixed another silly bug in nameserv.c that caused it to seg fault
+
+1.5.40 21/2/94
+ - removed the from (IP) message so people don't worry about 0.0.0.0,
+ it's redundant anyway.
+ - changed the client so the crypt key isn't printed
+ - changed the structure of switch_message() to use a list of functions.
+ This improves the debug info.
+ - made SMBopen ignore supplied attribute as per X/Open spec
+ - made SMBopen fail if file doesn't exist in all cases. Let me know
+ if this breaks something. It is implied in the X/Open spec. This
+ fixes the pkzip bug.
+ - added dptr_demote() to replace dptr_close() to try and fix
+ pathworks dir bug. This has the potential disadvantage of
+ leaving lots of open file descriptors.
+ - changed mask_match to disallow two .s in a name
+
+1.5.41 2/3/94
+ - added "dfree command" global option to smbd to support an
+ external "disk free" executable (typically a script). This gets
+ around the problem of getting disk free info reliably on lots
+ of systems.
+ - added ffirst and fclose to client
+ - simple SYSVR4 patch from mark@scot1.ucsalf.ac.uk
+ - added better uid/gid reporting for debugging purposes
+ - several changes to the logon procedure for the client, so hopefully
+ it will connect correctly to a wider range of servers.
+ - server should no longer crash if it can't open the debug
+ file (thanks to MGK@newton.npl.co.uk)
+ - added the THANKS file.
+
+1.5.42 6/3/94
+ - lots of changes from Jeremy Allison, implementing more of
+ the LANMAN1.0 protocol, and fixing a few bugs.
+ - fixed delete bug, so hopefully wildcards are correct now
+ - pcap changes from Martin Kiff so non-aliased printers in
+ /etc/printcap are recognised
+ - wrote announce file ready for 1.6
+ - re-wrote browse code in client (still doesn't work)
+ - updates to man-pages from Karl Auer
+ - made raw packet dumps mode 0600 and only if -dA is given
+ - changed socket code to use utility functions in util.c
+
+1.6.00 17/3/94
+ - made server always return to original directory (rather than /)
+ - fixed bug in params.c that caused a seg fault if no parms in a
+ section
+ - minor clean ups for clean compile under solaris
+ - solaris fix for running from inetd from Karl Auer
+ - fixes for dfree() under solaris
+ - minor changes that might help BSDI
+ - changes to the Makefile, manual-pages and sample config file from
+ Karl Auer
+ - fixed dfree for Ultrix
+
+1.6.01 19/3/94
+ - fixed setatr bug that allowed directories to be unusable
+
+1.6.02 27/3/94
+ - added timestamps to connection message in log
+ - added idle timeout of 10 minutes to name server
+ - made HAVE_SYSCONF==0 the default in includes.h
+ - made the client not register by default
+ - ISC patches from imb@asstdc.scgt.oz.au
+ - GetWd() cache code from Martin Kiff
+ - rewrote the locking code in terms of fcntl() calls.
+ - fixed "can't delete directory" bug
+ - added code to close old dirptrs for duplicate searches
+ - removed exchange_uids() and the access() call and replaced them.
+
+1.6.03 28/3/94
+ - tried to clean up the time handling a little (local vs gmt time)
+ - added debug level global to server config
+ - added protocol level global to server config
+ - added SMBecho command to server
+ - included Karl Auers SMBGuide in the distribution.
+
+1.6.04 31/3/94
+ - fixed time zeroing bug in smb_close and smb_setatr
+ - re-wrote the username/password handling to be more flexible
+ - added "guest only" service setting to smb.conf
+ - updated man pages for new username/password handling
+ - fixed parse bug in reply_tconX
+ - improved error return code from tcon
+ - several changes to fix printing from WfWg
+
+1.6.05 2/4/94
+ - changed the name of the whole package to Samba
+ - removed SMBexit call from client to stop exiting error message
+ - added interpret_addr() call to replace inet_addr() so
+ a hostname can be used whenever a IP is required
+
+1.6.06 8/4/94
+ - added random tid choice to reduce problem of clients not
+ detecting a server disconnection.
+ - made client not report spurious time from CORE or COREPLUS server.
+ - minor HPUX fix from gunjkoa@dep.sa.gov.au
+ - turned off GETWD_CACHE until we track down a minor bug in it
+
+1.6.07: 10/4/94
+ - added helpful error messages to connection failure in client.
+ - fixed problem with mput in client
+ - changed server to allow guest-only sesssetup messages with any
+ password. Control this with GUEST_SESSION_SETUP in local.h.
+ - minor change to session setup handling in make_connection()
+ - added check for right number of \s in the client.
+ - made the server not exit on last close if the deadtime is != 0
+ - added malloc and realloc wrappers. enable them with -DWRAP_MALLOC=1
+ - if smbd is started with a debug level of 10 or greater it creates
+ a log file ending in the process number
+
+1.6.08: 18/4/94
+ - updated the THANKS file
+ - changes from marcel@fanout.et.tudelft.nl (Marcel Mol) for AMPM
+ times and error report on connect().
+ - made the get_myname() routine discard any part after the first '.'
+ - added a wrapper for free from Martin Kiff
+ - added simpleminded code to handle trapdoor uid systems (untested)
+ - added Martin Kiffs "paranoid" getwd code.
+ - added default MAXPATHLEN if undefined of 1024
+ - made get_broadcast() continue to get netmask if it can't get
+ broadcast (suggestion from Hannu Martikk)
+ - replaced fchmod() calls with chmod() to satisfy some unixes
+
+
+
+1.6.09: 4/5/94
+ - changed perror() calls to strerror() in server.c
+ - fix for dfree on OSF1 from
+ Maximilian Errath (errath@balu.kfunigraz.ac.at)
+ - fixed server time reporting for protocol >= LANMAN1
+ - fixed TimeDiff() for machines without TIMEZONE or TIMELOCAL
+ (thanks to Vesa S{rkel{ <vesku@rankki.kcl.fi>)
+ - added SYSV defs to AIX and HPUX to fix "memory" problem
+ (actually a signal problem).
+ - added version to client banner in log file
+ - Ultrix patches from Vesa S{rkel{ <vesku@rankki.kcl.fi>
+ - added ! command to client for executing shell commands
+ - fixed ERRnofids bug in server
+ - fixed name_equal bug
+ (thanks to cjkiick@flinx.b11.ingr.com (Chris Kiick))
+ - wrapped gethostbyname() with Get_Hostbyname() to prevent
+ case sensitive problems on name lookups
+ - limit printer tmp filename to 14 chars
+ (from Paul Thomas Mahoney <ptm@xact1.xact.com>)
+ - added ability to understand 64 bit file times
+ (thanks to davidb@ndl.co.uk (David Boreham))
+ - added Gwt_Pwnam() wrapper to cover server case-sensitivity
+ problems (suggestion from J.M.OConnor@massey.ac.nz (John O'Connor))
+ - changed the setuid() calls to try and work for more systems
+ without breaking the ones it currently works for
+ - added version number to usage()
+ (suggestion from peter@prospect.anprod.csiro.au)
+ - added "security=" option for share or user level security
+ - allowed multiple usernames in "user=" field
+ - changed display method for recursive dorectory listings
+ - switched client to use long filenames where supported
+ - added speed reporting to client transfers
+ - several NT fixes to server from jra@vantive.com (Jeremy Allison)
+ - ISC fixes from ptm@xact.demon.co.uk (Paul Mahoney)
+ - fix to README from grif@cs.ucr.edu (Michael A. Griffith)
+ - default netmask and broadcast from Ian A Young <iay@threel.co.uk>
+ - changed default of is_locked() on fcntl() error.
+ - fixed bug in read_with_timeout() that could cause a runaway
+ smbd process.
+ - fixed findnext bug for long filenames in client
+ - changed default protocol level to LANMAN1
+ - change default reported security level to SHARE.
+ - changed password_ok() so that if pwdauth() fails it tries
+ with standard crypt.
+ - added "translate" command to the client to do CR/LF translation
+ for printing, and add a form feed at the end.
+ (thanks to mh2620@sarek.sbc.com (Mark A. Horstman ) )
+ - added "locking=yes/no" toggle for each service
+ - SCO unix patches from Heinz Mauelshagen (mauelsha@ez.da.telekom.de)
+
+1.6.10: 7/5/94
+ - fixed important bug in readbraw/writebraw
+ - added -A option to client
+ - fixed delete bug on long filenames (untested). Thanks to
+ Stefan Wessels <SWESSELS@dos-lan.cs.up.ac.za>
+ - neatened up the byte swapping code
+
+1.6.11: 3/6/94
+ - fixed bug in client in receive_trans2_response() that caused
+ some strange behaviour with LANMAN2.
+ - fixed some offset/alignment problems with lockingX (thanks to
+ Jeremy Allison)
+ - allow locking on O_RDONLY files. Thanks to Martin N Dey <mnd@netmgrs.co.uk>
+ - fixed del bug in client thanks to paulzn@olivetti.nl (Paul van der Zwan)
+ - fixed multiple user= bug thanks to MDGrosen@spectron.COM (Mark Grosen)
+ - added translate ability for all files. Thanks to mh2620@sarek.sbc.com (Mark A. Horstman )
+ - mask out negative lock offsets. Thanks to bgm@atml.co.uk (Barry G Merrick)
+ - more attempts to get the structure alignment better for some machines
+ - cleaned up the machine dependencies a little
+ - ISC fixes from Paul Thomas Mahoney <ptm@xact1.xact.com>
+ - enabled printing with a SMBclose and SMBwrite for NT
+ thanks to jkf@frisky.Franz.COM (Sean Foderaro)
+ - SGI changes from Michael Chua <lpc@solomon.technet.sg>
+ - CLIX patches from cjkiick@ingr.com
+ - NEXT2 and NEXT3_0 patches from Brad Greer (brad@cac.washington.edu)
+ - BSDI changes from tomh@metrics.com (Tom Haapanen)
+ - SCO patches from John Owens (john@micros.com)
+ - fix psz bug in pcap.c (thanks to Karl Auer)
+ - added widelinks option (global and per service). Suggestion from
+ Karl Auer. Defaults to True.
+ - made locking able to be global or local (default is give by global)
+ - added check_name() to dir listings
+ - added "packet size" option to globals. default to 32767. This
+ "fixes" a WfWg bug (thanks to Karl Auer)
+ - fixes for getattrE and setattrE and minor fix in util.c from Jeremy Allison.
+ - Karl updated the man pages o be current
+ - disabled writebraw and readbraw until a possible bug can be investigated further
+
+1.7.00: 14/7/94
+ - added session_users list, to overcome problem of missing usernames in SMBTconX.
+ - added term support to the client
+ - added "default service"
+ - fork for print so user is not root
+ - added name mangling to 8.3 (rudimentary)
+ - fixed bug in in_group()
+ - changed to use gid in place of egid
+ - fixed client connection to OS/2 (1.3 + lanman2.2) and long filenames
+ - added patches from mcochran@wellfeet.com (Marc Cochran)
+ these implement scope ids and fix some udp bugs. It means
+ the -L option to nmbd now works.
+ - made nmbd respond to incoming port rather than only 137
+ - made wide links refuse .. components
+ - fixed "dir foo." bug to stop it showing "foo.???"
+ - improved name mangling (added stack)
+ - added valid FNUM check to most calls
+ - fixed important do_put bug in the client
+ - added magic scripts to the server
+ - re-enabled getwd_cache code
+ - added optional agressive password checking
+ - removed dptr_closepath from SMBsearch to try and stop "dos for loop"
+ bug
+ - DGUX patches from ross@augie.insci.com (ross andrus)
+ - updated the README and THANKS file.
+ - added node status request to -L option of nmbd
+ - stripped trailing spaces in mask_match() (thanks to mike hench hench@cae.uwm.edu)
+ - added COREPLUS style print queue reporting and "lpq command"
+ in globals.
+ - cleaned up date handling and fixed byte order dependancy on dates
+ in SMBgetattrE.
+ - cleaned up the password handling and added "password level" with
+ the possability of checking all case combinations up to N upper
+ case chars.
+ - changed to use recvfrom only on udp ports (fixed read raw!)
+ - added TCB password support for SCO (thanks to lance@fox.com)
+ - updated README, THANKS and announce files.
+ - fixed timezone reporting to be signed (thanks to noses@oink.rhein.de)
+ - disabled max packet as it could cause problems with WfWg (no longer
+ needed now readraw is "fixed")
+ - changed from creat() to open() in mktemp and mknew.
+ - changed umask handling
+ - sped up nmbd by making it cache names
+ - changed idle timeout on nmbd to 2 mins
+ - Netbsd changes from noses@oink.rhein.de
+ - released alpha2
+ - added name timeout to nmbd
+ - changed bind port retry in nmbd
+ - added Limitations sections to README
+ - fixed two . in is_83()
+ - fixed compilations warnings in util.c (thanks to njw@cpsg.com.au)
+ - made [homes] honour multiple user list
+ - fixed mask match bug introduced in alpha1
+ - added "mangled stack" option for stack size
+ - added mangled stack promotion
+ - released alpha3
+ - netbsd-1.0 fix for statfs().
+ - added null_string to util.c to reduce memory usage
+ - changed the way directory structures are put together
+ - added smbrun for system() requests
+ - changed maxmux to 0 in hope of avoiding mpx commands problem
+ - fixed zero response length for session keepalives
+ - removed called name from session users list
+ - added F_RDLCK support to try and handle locks on readonly files
+ - made directory creation honour the lowercase flag in client (thanks
+ to charlie@edina.demon.co.uk)
+ - made checksum for mangling independant of extension if extension is
+ lowercase
+ - added ability to rename files with different extension, preserving
+ root name
+ - released alpha4
+ - better command line error checking in client
+ - changed all debug statements to new format
+ - fixed delete error code reporting
+ - released alpha5
+ - added mangled name support to wildcard delete in server
+ - fixed mask bug in SMBsearch
+ - cleaned up prototypes
+ - released alpha6
+ - fixed important bug in session_setup which made WfWg freeze
+ (maxmux was 0 - this bug was introduced in alpha4)
+ - released alpha7
+ - two printing bug fixes thanks to bgm@atml.co.uk (Barry G Merrick)
+ - uid fix to smbrun (thanks to larry@witch.mitra.com)
+ - man page updates from Karl Auer
+ - FAQ file from Karl Auer
+ - released alpha8
+ - fixed read-only flag in dos_mode() for non writeable services
+ - fixed error code reporting in open() and openX().
+ - minor secureware fix from (thanks to lance@fox.com)
+ - released alpha9
+ - casting cleanups for memcpy().
+ - cleaned up error code names to be more consistant
+
+1.7.01: 17/7/94
+ - minor man page fix from baeder@cadence.com (Scott Baeder)
+ - changed usage() error message in client
+ - made nmbd not exit if can't register own name
+ - made nmbd only register if running as a daemon
+ - fixed stdout problem in smbrun by closing stdin/stdout/stderr
+ - minor fix to lmhosts parsing
+
+
+1.7.02: 20/7/94
+ - made nmbd not call get_broadcast if both -B and -N are used (thanks
+ to Chris Woodrow <Chris.Woodrow@actrix.gen.nz>)
+ - disabled GETWD_CACHE again
+ - fixed INCLUDES list in Makefile to add version.h (thanks to
+ jimw@PE-Nelson.COM (Jim Watt))
+ - made checkname do a become user if it hasn't already done so.
+ - added consistancy check to become_user().
+ - removed mask extension expansion from SMBsearch
+ - small change to chkpth
+ - fix to snum select for lpq status (thanks to Rafi Sadowsky
+ rafi@tavor.openu.ac.il)
+ - changed daemon to is_daemon for NetBSD (thanks to noses@oink.rhein.de)
+ - removed STAFS3 stuff for NETBSD_1_0
+
+
+1.7.03: 29/7/94
+ - updated docs for new distribution structure
+ - made getatr return 0 size for directories (thanks to Bernd Esser
+ esser@pib1.physik.uni-bonn.de)
+ - added valid dos filename checks from Stefan Wessels
+ (swessels@cs.up.ac.za)
+ - added trimming of . in hostnames to -S mode of nmbd
+ - removed become_user() and OPEN_CNUM calls. Now make them
+ in switch_message instead which simplifies a lot of code.
+ - added GETFNUM macro to make chain_fnum more consistant and
+ reliable.
+ - added flags to protocol structures to simplify CAN_WRITE and AS_USER
+ checking
+ - added getwd cache boolean option to globals
+ - added fclose() to lpq status routine thanks to
+ dgb900@durras.anu.edu.au (David Baldwin)
+ - added "only user" option, to limit connection usernames to those
+ in the user= line
+ - changed to badpath from badfile in chkpath despite specs (following
+ what WfWg does). This fixes "file not found" error in copy command.
+ Thanks to rwa@aber.ac.uk for pointing out the bug
+ - changes for apollo from Stephen C. Steel <steve@qv3donald.LeidenUniv.nl>
+ - more changes for Apollo from jmi@csd.cri.dk (John Mills)
+ - released alpha release
+ - added FTRUNCATE_CAN_EXTEND=0 as default to fix problem with word6.
+ Possibly not needed on many OSes? Thanks to Charlie Hussey
+ charlie@edina.demon.co.uk
+ - started adding max connections code
+ - much improved group handling contributed by
+ Ian Heath (ih@ecs.soton.ac.uk)
+
+1.7.04: 29/7/94
+ - fixed one line bug in SMBopenX that got error code wrong.
+
+1.7.05: 2/8/94
+ - added UNIXERROR() macro to get error code from unix errno.
+ - fixed lpq status for MSTCPB3
+ - added @ option for user= line to lookup groups in group file
+ - added become_user optimisation and process timeout (thanks to
+ Jeanette Pauline Middelink (middelin@calvin.iaf.nl)
+ - added malloc optimisation in readbraw
+ - released alpha
+ - patches for OSF1 enhanced security from Udo Linauer <ul@eacpc4.tuwien.ac.at>
+ - made level 2 a more useful debug level (less guff)
+ - added "max connections" and "lock dir" options to allow
+ limiting of the number of connections to a service at one time.
+ - released alpha2
+ - updated man pages
+ - released alpha3
+ - added read prediction code for better read performance
+ - released alpha4
+ - minor tuning to receive_smb()
+ - changed the order of mangled stack checking
+ - bug fix in read_predict().
+ - released alpha5
+ - minor search optimisation
+ - fixed keep alive bug in writebraw and in readbraw in the client
+ - released alpha6
+ - disabled writeraw by default pending a bug fix
+ - added profiling code (off by default)
+ - minor delete tuning
+
+
+1.7.06: 4/8/94
+ - OSF1 crypt fix thanks to Udo Linauer <ul@eacpc4.tuwien.ac.at>
+ - ifdef'd EDQUOT in case you don't have it (thanks to Paul Blackman <ictinus@Lake.canberra.edu.au>)
+ - tidied up UNIXERROR stuff to work on more systems.
+ - made Makefile more sophisticated and added "make revert"
+
+1.7.07: 4/8/94
+ - fixed one line fatal bug in receive_smb. Thanks to bruce@pixar.com
+
+1.7.08: 2/9/94
+ - initgroups call for SCO from lance@fox.com
+ - code cleanups from cap@isac.hces.com (Simon Casady)
+ - use full pathname in print command construction
+ - ISC includes fix from Martin Tomes <mt00@ecl.etherm.co.uk>
+ - added GID_TYPE define to cope with ultrix. Thanks to
+ brad@cac.washington.edu
+ - added umask call to main in server
+ - fixed several minor problems with the max connections
+ code. Thanks to lehmann@klizix.mpi-stuttgart.mpg.de (Arno Lehmann).
+ - fixed filetime in writeclose. Thanks to Andreas Bahrdt
+ <100321.2431@compuserve.com>
+ - df fix for large disks from Andreas Bahrdt
+ - getpwanam support from horn@mickey.jsc.nasa.gov
+ - clean name change from Bernd Esser
+ <be@syli30.physik.uni-bonn.de>
+ - released alpha1
+ - more locking changes to fix Excel problem
+ - released alpha3
+ - another minor locking change
+ - smarter masking in the locking code. Excel now apparently works.
+ - minor FAQ updates
+ - changed max connections refusal error to access denied.
+ - added queue command to client to show the print queue
+ - changed some print queue reporting stuff
+
+1.8.0: 14/10/94
+ - added international chars to valid_dos_char(). Thanks
+ to Daniel.Grandjean@dgr.epfl.ch
+ - volume label fix
+ - released alpha1
+ - important off by 4 fix in the server
+ - readbraw size adaption in the client
+ - released alpha2
+ - wait3 cast for NeXt fixed. Thanks to dbrandon@politics.tamu.edu.
+ - man page fix for max xmit. Thanks to mmoore@wexford (Mike Moore)
+ - is_8_3() fixes from Jochen Roderburg <Roderburg@rrz.Uni-Koeln.DE>
+ - list_match() fix from jkf@soton.ac.uk
+ - statfs3 fix for BSDI from dan@supra.com
+ - changed file open/close/read in server in preparation for mmap()
+ based IO.
+ - added mmap() support for reading files in the server. Optional
+ at compile time. Thanks to suggestion from Roger Binns <rogerb@x.co.uk>
+ - mmap bug fixes
+ - added __SAMBA__ name in nmbd
+ - major changes for support of lanman2 and long filenames from
+ Jeremy Allison (jeremy@netcom.com)
+ - lseek optimisation. Thanks to Linus Torvalds.
+ - released alpha4
+ - date patches for lanman2 from Jeremy Allison
+ - added protocol aliases to handle WfWg (untested)
+ - allow for zero params or data in reply_trans2
+ - small lanman2 patches from jeremy
+ - more prototype additions for clean compilation
+ - postscript patches from tim@fsg.com
+ - more lanman2 patches from Jeremy
+ - added null ioctl support
+ - kanji patches from fujita@ainix.isac.co.jp
+ - released alpha6
+ - disallowed null password access (thanks to Birger Kraegelin krg@iitb.fhg.de)
+ - Makefile fix for ultrix from andrew@d2bsys.demon.co.uk (Andrew Stirling)
+ - added per-service mangled names
+ - totally re-vamped loadparm.c
+ - added "mangling char" parameter
+ - released alpha7
+ - added "default case = lower|upper" service option
+ - change mangling char to a service parameter
+ - ultrix enhanced security patch from steven@gopher.dosli.govt.nz
+ - more changes to loadparm.c
+ - printer name always set in [printers]
+ - string_free() fix thanks to jef_iwaniw@pts.mot.com
+ - changed group handling to be faster and work for large numbers
+ of groups
+ - added dynamic gid_t type determination
+ - released alpha8
+ - fixed become_user() problem for services with invalid
+ directories
+ - added "invalid users" list on per service basis
+ - fixed pointer problems in alpha8 (thanks to murnaghant@a1uproar.yuppy.rdgmts.MTS.dec.com)
+ - fixed some date setting problems
+ - trans2 fixes from jeremy to stop infinite directory listings of
+ long filenames
+ - "standard input" lpq patch from root@tlspu.demon.co.uk (Adrian Hungate)
+ - changed password checking to check session list and validated ids
+ before user list
+ - split off password functions into password.c
+ - added hosts equiv and rhosts code (thanks to Tim Murnaghan <murnaghant@a1uproar.yuppy.hhl.MTS.dec.com>)
+ - released alpha11
+ - added "newer" command to the client
+ - attempt at aix trapdoor uid workaround
+ - released alpha12
+ - minor trans2 bugfix
+ - added ufc crypt (fast crypt) support. Thanks to suggestion from
+ forrest d whitcher <fw@world.std.com>
+ - socket() fix for getting bcast and netmask thanks to
+ Brian.Onn@Canada.Sun.COM
+ - added beginnings of IPC and named pipe support in the server
+ - changed file structure a bit, creating reply.c
+ - finished print queue support for lanman1
+ - changed default protocol to LANMAN2
+ - released alpha13
+ - logged IPC connects at a higher debug level
+ - added netgroup support to hosts equiv search
+ - disallowed root access though hosts.equiv (thanks to Colin.Dean@Smallworld.co.uk)
+ - kanji and password handling fixes from fujita@ainix.isac.co.jp
+ - several bug fixes for lanman and other things from
+ esser@pib1.physik.uni-bonn.de (Bernd Esser)
+ - updated man pages, README and announce files.
+ - released 1.8.00alpha1
+ - reply_close() time change fix from Andreas Bahrdt <100321.2431@compuserve.com>
+ - added valid users list to compliment invalid users list.
+ - aix fixes from tomc@osi.curtin.edu.au (Tom Crawley)
+ - changed testparm output format
+ - support for getting time from the server (nearly untested)
+ - fixed device type error for wild device ????
+ - fixed groups problem when in 0 groups
+ - more IPC fixups
+ - added support for "net view \\server" command to list
+ available services (like browsing)
+ - released 1.8.00alpha2
+ - changed port choice for nmbd -L
+ - added -L option to client to view share list on a host
+ - bug fixes for NetShareEnum code
+ - added "server string" option
+ - changed default print file name to include remote machine name.
+ - added hooks for browsing in nmbd
+ - added browsing to nmbd
+ - freebsd fixed from Steve Sims SimsS@Infi.Net
+ - got rid of tell()
+ - added subnet browsing with the S option in lmhosts
+ - made smbd prime nmbd with a 1 byte dgram
+ - added REUSADDR to open_socket_in() thanks to peter@ifm.liu.se
+
+
+1.8.01: 18/10/94
+
+ - auto add group "LANGROUP" if no group specified in nmbd
+ - made nmbd more responsive at startup
+ - lots of cleanups and consistancy checks
+ - added -C option to nmbd to set "machine comment".
+ - fixed postscript option
+ - force print_file in print_open()
+ - restructured the browsing a little
+ - casesignames fix for lanman-dos
+ - auto-load home directory from session setup
+ - changed to StrnCpy() for safety
+ - fixed "out of file descriptors" bug in the client (a WfWg bug?)
+
+
+1.8.02: 22/10/94
+ - fixed uppercase username problem
+ - added "hide dot files" option
+ - changed auto debug log in nmbd
+ - added LMHOSTS to Makefile
+ - added M flag in lmhosts to specify own netbios name
+ - added "load printers" option to auto-load all printers
+ - substitution of %p in lpq command
+ - substitution of %h and %v in server string and -C option of
+ nmbd
+ - string substitions substitute all occurances of a pattern
+ - added casesignames global option
+ - fix for man pages thanks to David Gardiner <dgardine@cssip.edu.au>
+ - changed debug options a bit
+ - added default for lpq command and lpr command
+ - changed default shell path to /bin/sh
+ - forced lpq under api to run as root - should speed things up
+ - added "group" option to force group of a connection
+ - added "read list" and "write list" options
+ - added max mux option - seems to fix NT browsing?
+ - added "mangled map" option thanks to
+ Martin.Tomes@uk.co.eurotherm.controls
+ - separated mangling functions into mangle.c
+ - allowed all dos chars in mangled names
+ - apollo changes from Helmut Buchsbaum <buc@eze22.siemens.co.at>
+ - password changing code from Bob Nance <Bob.Nance@niehs.nih.gov>
+ it doesn't quite work yet, but it's a start (disabled by default)
+
+
+1.8.03: 25/10/94
+ - made auto loaded services browsable as per default service
+ so you can hide homes but keep home directories.
+ - changed check_name() to handle "direct to network" printing
+ - auto 3 minute deadtime if all connections are closed. This
+ prevents restart when polling the print queue.
+ - fix for newer command in client from Rich-Hoesly@uai.com
+ - changed connection recording method
+ - added the program smbstatus
+ - changed timeout mechanism
+ - "null passwords" option from Pim Zandbergen <pim@cti-software.nl>
+ - made new files with casesignames=False set their case to the default
+ case.
+ - fixed problem of uppercasing first letter of printers in printcap
+ - debug level fixes in trans2 from jimw@PE-Nelson.COM (Jim Watt)
+ - made null printer default to lp
+
+1.8.04: 27/10/94
+ - added OS2.txt from riiber@oslonett.no
+ - another "auto services" fix. A silly strtok() bug :-(
+ - fixed the status locking and max connections (broken in 1.8.03)
+ - released alpha1
+ - added gets_slash so lines can be continued in smb.conf and
+ lmhosts
+ - browse list bugfix
+ - default to "load printers=yes"
+ - rewrote pcap.c
+ - intergraph bugfix from tarjeij@ulrik.uio.no
+ - changed properties flags in nmbd (to fix NT print browsing)
+ - allowed very long lines in printcap parsing.
+
+1.8.05: 28/10/94
+ - lanman2 fix from Jeremy
+
+1.9.00: 22/1/95
+ - only add home if not already there.
+ - added ulogoffX support
+ - PTR_DIFF() cleanups
+ - fixed a bug that caused STATUS..LCK to grow very large
+ - changed mangling to handle names ending in . a little better
+ - added "strip dot" option
+ - SGI and setgroups() fix from bill@sg25.npt.nuwc.navy.mil
+ - fixed password preservation in password_ok() (again?)
+ - unink fix from emer@vssad.enet.dec.com (Joel S. Emer)
+ - changed username part of spool filename to max 10 chars (from 6)
+ - magic script fix from beverly@datacube.com (Beverly Brown)
+ - reply_special() fix from Peter Brouwer <pb@apd.dec.com>
+ - stopped nmbd from listening on 138. It didn't seem to help much.
+ - clix fixes from ttj@sknsws61.sjo.statkart.no
+ - fixed select behaviour under Linux
+ - man page fix from Robin Cutshaw <robin@intercore.com>
+ - ISC block size fix from ralf@rbsoft.sdata.de (Ralf Beck)
+ - ISC fixes from Martin.Tomes@controls.eurotherm.co.uk
+ - attrib bit fix in smbclient (pointed out by Rich-Hoesly@uai.com)
+ - japanese extensions from fujita@ainix.isac.co.jp (Takashi
+ Fujita) and ouki@gssm.otuska.tsukuba.ac.jp.
+ - SCO patches from Stephen.Rothwell@pd.necisa.oz.au
+ - changed the system commands to redirect stderr
+ - changed default printername to service name for all print ops
+ - added ability to delete print queue entries
+ - added warning if you try to print without -P in smbclient
+ - INTERACTIVE patches from cardinal@settimo.italtel.it
+ - patch to handle spaces in group names from GJC@vax1.village.com
+ (GEORGE J. CARRETTE)
+ - lockingX fix from stefank@esi.COM.AU (Stefan Kjellberg)
+ - some fairly radical changes to filename handling. We can now
+ handle mixed case filenames properly
+ - released alpha2
+ - added sysv printing support and improved bsd support
+ - changed the user that does print queues and lprm jobs
+ - return code support in the client from doylen@nbslib.isc-br.com (Doyle Nickless)
+ - added "strict locking" option. Defaults to no.
+
+ - added -I switch to nmbd
+ - fixed DEV bug thanks to Dirk.DeWachter@rug.ac.be
+ - use pw_encrypt() for shadow passords in Linux (from begemot@begemot.iko.kharkov.ua (Dmitry Gorodchanin))
+ - disabled read prediction by default
+ - added varient handling code to ipc.c for printQ and printDel.
+ - released alpha5
+ - AUX patches from root@dolphin.csudh.edu
+ - struct timeval fix from gkb1@york.ac.uk
+ - patches to merge ISC and INTERACTIVE from pim@cti-software.nl
+ - changed to "printing ="
+ - fixed problem with long print queues.
+ - fixed node status request in nmbd to go to non bcast
+ - made default path in services /tmp if not specified
+ - added %u in passwd program
+ - fixed up the password changing code for Linux
+ - no guest sess setup when user level security
+ - changed timeouts to kill dirptrs so cdroms can be unmounted
+ - added auto-reload of smb.conf if changed
+ - added SIGHUP to reload the config files
+ - added -M option to nmbd to search for a master browser
+ - added support for continue bit in trans2findnext
+ - changed to dynamic strings in some more structures
+ - changed default deadtime to 30 minutes
+ - cleaned up the memory swapping code a bit
+ - updated the man pages somewhat
+ - added %m and %u in the "path=" of services
+ - released alpha6
+ - simple testing and fixups for solaris, sunos, aix, ultrix and
+ osf/1 (this is all I have access to).
+ - fixed chdir bug
+ - added hashing to cnum selection
+ - released alpha7
+ - fixed printing bug
+ - reduced chance of "hung" smbd with dead client
+ - fixed do_match() bug (recently introduced)
+ - released alpha8
+ - nameserver fix from W.J.M.vGeest@et.tudelft.nl (W.J.M. van Geest)
+ - rewrote readbraw to try and overlap reads with writes
+ - client optimisations
+ - rewrote getwd cache and enabled it by default
+ - added partial smb packet reads (hopefully faster writes)
+ - added log file and log level options (with subs)
+ - added "read size" option
+ - tried setting some more socket options
+ - can use subs in "config file=" and will auto-reload
+ - added "include" options, with some subs
+ - finally got print manager working with NT
+ - auto-respond in nmbd to non-broadcast (auto WINS server, no -A
+ needed)
+ - released alpha10
+ - auto-delet unused services when reloading
+ - fixed auto-deletion
+ - fixed long names in printing
+ - fixed double loading of services file
+ - added printer file name support
+ - reformatted man pages for better www conversion
+ - renamed to 1.9.00.
+ - added support for RNetServerGetInfo and NetWkstaGetInfo API's
+ - updated the docs a bit
+ - released alpha1
+ - added -M -
+ - changed nmbd announce interval to 10 mins in outgoing packets
+ - hopefully fixed idle timeout reconnects
+ - strupper all command lines in nmbd
+ - added %a substitution for "remote architecture"
+ - added "Samba" protocol (same as lanman2)
+ - added "security = SERVER"
+ - released alpha2
+ - lowercase password fix
+ - fixed connect path length bug (thanks to JOHN YTSENG
+ <jtseng@cory.EECS.Berkeley.EDU>)
+ - added subs on "password server".
+ - fixed printing filename bug from smbclient
+ - disk quotas and hpux printing support from Dirk.DeWachter@rug.ac.be
+ - Makefile patches from pappinm@ayr_srv2.nth.dpi.qld.gov.au
+ - AFS patches from Mike Allard (mgrmja@nextwork.rose-hulman.edu)
+ - fixed grp name = server name problem
+ - man page updates from Charlie Brady (charlieb@budge.apana.org.au)
+ - fixed file search bug by adding "finished" flag
+ - added "max log size". Suggestion from Mark Hastings <mark.hastings@gain.com>
+ - released alpha3
+ - changed the read/write routines to handle partial read/writes
+ - released alpha4
+ - changed "guest account" to per-service
+ - changed so "guest ok" allows access to the guest account,
+ not the "user=" line
+ - changed default readsize to 2048
+ - try bind to 137 in nmbd if possible
+ - added server lookup to -L option in smbclient (gets list of servers)
+ - added -M switch to smbclient for sending winpopup messages
+ - released alpha5
+ - FAQ updates from Paul Blackman ictinus@lake.canberra.edu.au
+
+1.9.01: 23/1/95
+ - changed comment in print Q info to service rather than server comment
+ - fixed smbclient -L to NT when in user level security mode
+ - hopefully finally fixed NT print manager problems
+ - added informative messages during smbclient -M
+ - added node status replies to nmbd
+ - changed the lock offset fixup calculation to be more friendly
+ to dumb lockd daemons.
+ - added sigbus and sigsegv handlers to catch any silly errors and
+ print a message
+ - added message receipt to smbd and "message command =" option
+
+1.9.02: 25/1/95
+ - added argv/argc mangling for people who start the server the
+ wrong way.
+ - some man page updates
+ - added "revalidate" option
+ - added hosts allow/deny access check to messaging access
+ - added timeouts in the client
+ - added check for existance of smbrun binary
+ - man page updates from Colin.Dean@Smallworld.co.uk
+ - freebsd patches from dfr@render.com
+ - added mask sanity check in SMBsearch
+ - added more useful substitutions (%S, %P, %I and %T)
+ - added "exec =" option to execute commands on each connection
+
+1.9.03: 13/3/95
+ - added "socket options" option
+ - close base fd's (0,1 and 2)
+ - use dup(0) for inetd operation
+ - better detection of is_daemon
+ - hopefully finally fixed silly put bug that gave the wrong
+ date on files.
+ - fixed segv in readbraw bug
+ - added improved checing for invalid (or null) print file name
+ - several patches from ad@papyrus.hamburg.com (Andreas Degert)
+ - fixed slow logout bug in smbclient
+ - fixed automounter problems
+ - added subs on lock dir
+ - BSDI patch from John.Terpstra@Aquasoft.com.au
+ - added separate nmb and smb logfile entries in the Makefile
+ - fixed return code error in open calls
+ - added simple status display of printer in lpq parsing
+ - rewrote the directory handling to avoid seekdir (added dir.c)
+ - added uid=65535 check (thanks to grant@gear.torque.net)
+ - enhanced transfer_file() to add header (used in readbraw)
+ - reply_special bugfix from ferret@pc8871.seqeb.gov.au
+ - added HAVE_PATHCONF
+ - RiscIX patches from Jim Barry <jim@ilp.com> and
+ Charles Gay-Jones <charlie@ilp.com>
+ - CLIX patches from ttj@sknsws61.sjo.statkart.no
+ - fixed aix lpq parser from kvintus@acd.com
+ - added substitutions to "include="
+ - M88K_S3 patches from tonyb@plaza.ds.adp.com (Tony D. Birnseth)
+ - fixed mangled stack problem
+ - added code to handle broken readdir() setups on solaris
+ - initgroups() fix from jarit@to.icl.fi
+ - dgux dfree fix from listwork@cloud9.net
+ - dnix support from Peter Olsson <pol@leissner.se>
+ - getgrgid() patch from tpg@bailey.com (Tom Gall)
+ - Makefile patch from obrien@Sea.Legent.com (David O'Brien)
+ - password changing fixes from Dirk.DeWachter@rug.ac.be
+ - minor man page updates
+ - tried to enhance the read prediction code a little bit
+
+1.9.04: 16/3/95
+ - a bit better handling of global include lists
+ - fixed GSTRING bug in loadparm.c (affected "socket options =")
+ - fixed broken lpq parsing code (recent bug).
+ Thanks to Dirk.DeWachter@rug.ac.be
+
+1.9.05: 20/3/95
+ - improved mget in client to take multiple arguments and default
+ to *.*
+ - socket option fixes for both nmbd and smbd
+ - changed the byteorder handling scheme to be more portable (and
+ faster)
+ - lint cleanups from kast@kcs.planet.net (Robert Kast)
+ - added crude segv, sigbus and sighup recovery to nmbd
+ - rewrote lanman2_match to be closer to NT and WfWg behaviour
+ - Cray support from velo@sesun3.epfl.ch (Martin Ouwehand)
+ - "admin users" patch from Tim Leamy <tcleamy@ucdavis.edu>
+ - released alpha1
+ - added samba.7 man page
+ - no chdir when doing non AS_USER protocols
+ - become_guest() returns true in trapdoor uid system
+ - added more sophisticated segv/sigbus reporting (Linux only)
+ - released alpha2
+ - minor code cleanups (output of -Wall)
+ - smbprint fix from James Dryfoos <dryfoos@ll.mit.edu>
+ - improved testparm a little
+ - updated INSTALL.txt a little
+
+
+1.9.06: 21/3/95
+ - added %S substitution to users, valid users and invalid
+ users. This is useful for [homes].
+ - split off printing routines into printing.c and more dir
+ commands into dir.c
+ - postexec patch from jpm@gin.Mens.DE (Jan-Piet Mens)
+ - smbstatus updates from jpm@gin.Mens.DE (Jan-Piet Mens)
+ - reload sighup after use
+ - fixed name ptr offset bug
+ - added %f in print commands
+ - fixed byte ordering in nmbd which caused browsing to fail in
+ 1.9.05
+
+1.9.07: 22/3/95
+ - important directory listing fix
+ - allowed path= in [homes] section
+ - printer status patches from Dirk.DeWachter@rug.ac.be
+
+1.9.08: 24/3/95
+ - fixed . and .. in root dir for lanman2
+ - better default comment in [homes]
+ - added time stamping to directory entries
+ - check directory access at connection time
+ - rlimit code from loebach@homer.atria.com (Thomas M. Loebach)
+ - fixed home dir default comment
+ - totally rewrote dptr handling to overcome a persistant bug
+ - added [globals] as well as [global]
+
+1.9.09: 30/3/95
+ - fixed static string bug in nmbd
+ - better null password handling
+ - split CFLAGS in Makefile
+ - fixed typo in smbclient messaging
+ - made home dir not inherit path from [global]
+ - standard input printing patch from xiao@ic.ac.uk
+ - added O_CREAT to all print opens (bug in Win95)
+ - use /proc for process_exists under Linux and solaris
+ - fixed another segv problem in readbraw
+ - fixed volume label problem
+ - lots of changes to try and support the NT1 protocol
+ - released alpha1
+ - fixed session setup bug with NT in NT1 protocol
+ - released alpha2
+ - fixed "get" bug in smbclient that affected NT3.5
+ - added SO_KEEPALIVE as a default socket option in smbd
+ - changed some error codes to match those that NT 3.5 produces
+ - updated trans2 with some new calls for Win95 and WinNT (better
+ long file support)
+ - released alpha3
+ - fixed "nmbd -D -b" timeouts
+ - added IS_LONG_NAME flag to getattr in NT1
+ - added the NT qfileinfo trans2 commands
+ - merged qpathinfo with qfileinfo
+ - changed idling technique to try and be more friendly to
+ clients
+ - merged setfileinfo with setpathinfo and updated them with the NT fns
+ - improved read prediction a lot
+ - added read prediction to readbraw
+ - improved fault reporting (last packet dump)
+
+1.9.10: 30/3/95
+ - fixed read prediction+readbraw bug for read/write files
+
+1.9.11: 9/4/95
+ - fixed trans2 qpathinfo bug
+ - fixed bug with % in service name when doing print queue requests
+ - default readsize now 16K
+ - minor read prediction changes
+ - fixed status initialisation in print queue reporting
+ - fixed const compile problem for hpux
+ - minor SMBread fix from Volker Lendecke <lendecke@namu01.gwdg.de>
+ - removed space after -P in print commands (for fussy systems)
+ - disabled level2 of setfilepathinfo
+ - changed to a single read dir model, saving all dir names in
+ the Dir structure
+ - disabled NT protocols in the client due to reported problems
+ - fixed QUERY_FS_VOLUME_INFO which caused Win95 to hang on drive
+ properties
+ - minor lseek bug fix
+ - fixed up keepalives
+ - new timezone handling code (hopefully better!)
+ from steve@qv3pluto.LeidenUniv.nl
+ - BSDI interface patch from jrb@csi.compuserve.com
+ - gettimeofday changes from Roger Binns <rogerb@x.co.uk>
+ - added smbrun option
+ - added "root preexec" and "root postexec" options
+
+1.9.12: 12/4/95
+ - hopefully fixed some recently introduced NT problems
+ - fixed a unlink error code problem
+ - minor testparm fix
+ - fixed silly error messages about comments in config files
+ - added "valid chars" option for other languages
+
+1.9.13: 28/4/95
+ - patches from David O'Brien (obrien@Sea.Legent.com) improving the
+ netgroup suport, and adding the "map archive" option, as well as
+ other minor cleanups.
+ - tried to add info level 3 and 4 support for OS/2
+ - default deadtime set to 0 as in docs
+ - cleaned up the trans2 code a little
+ - cleaned up the Makefile a little
+ - added charset.c and charset.h
+ - expanded "valid chars" option to handle case mapping
+ - lots of changes to try and get timezones right
+ - released alpha1
+ - win95 fixups
+ - released alpha2
+ - added %H substitution (gives home directory)
+ - nameserv.c cleanups and minor bug fixes
+ - redid the browse hook logic
+ - fixed daylight saving time offset for logfile messages
+ - added name cacheing to nmbd
+ - added send counts to node status in nmbd
+ - added STRICT_TIMEZONES compile time option (very computationally
+ expensive)
+ - removed the partial read code
+ - cleaned up the permission checking a lot
+ - added share modes (DENY_READ, DENY_WRITE, DENY_ALL, DENY_NONE,
+ DENY_FCB and DENY_DOS)
+ - added "share modes" option
+ - cleaned up the file open calls
+ - released alpha4
+ - fixed important one line bug in open_file()
+ - trans2 client fix from lendecke@namu01.gwdg.de
+ - netgroup patche from David O'Brien (obrien@Sea.Legent.com)
+ - case sensitive fix from lenneis@statrix2.wu-wien.ac.at (Joerg Lenneis)
+ - got long filenames working from Win95 dos prompt
+ - added "workgroup=" option
+ - added "username map" option including multiple maps, group maps etc
+ - fixed password server for NT1 protocol and made it more robust
+ - changed unix_mode() to add IWUSR to read-only directories. This
+ is much closer to what clients expect.
+ - added preservation of unused permission bits when a chmod() is
+ called from a client.
+ - made static those fns that could be
+ - fixed typo in access.c (thanks to Andrew J Cole
+ <A.J.Cole@cbl.leeds.ac.uk>)
+ - added %d substitution for process id
+ (thanks to lenneis@statrix2.wu-wien.ac.at (Joerg Lenneis))
+ - changed share error code to ERRbadshare
+ - added locked files list to smbstatus if share modes is enabled
+ - changed DENY_DOS to allow read by other tasks
+ - added shared_pending checks to server
+ - preserverd all possible permission bits during a chmod, and
+ fixed a trans2 chmod bug
+ - open /dev/null to use up first 3 fds, in an attempt to stop rogue
+ library routines from causing havoc
+ - fixed NT username problem when in server security
+ - added "force user" and "force group" options
+ - cleaned up some of the IPC calls a bit
+ - added writeraw to the client and cleaned up write raw in the server
+ - osf1 big-crypt bugfix from Udo Linauer <ul@eacpc4.tuwien.ac.at>
+ - hopefully better disk-full checking
+ - next uid bugfix from patrick@graphics.cornell.edu
+ - changed share modes so lock directory doesn't need to be world
+ writeable
+ - enabled write-raw by default
+ - added server_info() in client
+ - added level checks in some ipc calls
+ - added defines for the important timeouts in local.h
+ - added print queue deletion to smbclient (untested)
+ - removed the sysconf() calls
+ - optimised writebraw a bit
+ - fixed some file deletion problems
+ - added total_data check for extended attribs in trans2 (for OS/2)
+ - fixed broadcast reply bug in nmbd
+ - added careful core dumping code
+ - added faster password level searches (suggestion
+ by lydick@cvpsun104.csc.ti.com (Dan Lydick))
+
+
+1.9.14: 22/9/95
+ - fixed up level 3 and 4 trans2 requests for OS/2
+ - minor optimisations in a few places
+ - cleaned up the closing of low fds a bit
+ - added SO_REUSEADDR to socket as a daemon
+ - override aDIR bit for directories in dos_chmod()
+ - SGI5 fixes from ymd@biosym.com (Yuri Diomin)
+ - bsize sanity check and removed sunos force to 1k
+ - force the create mode to be at least 0700
+ - SCO and freebsd include changes from Peter Olsson
+ <pol@leissner.se>
+ - check with FQDN in access.c (thanks to Arne Ansper <arne@ioc.ee>)
+ - default broadcast for dnix from Peter Olsson <pol@leissner.se>
+ - solaris patches from Ronald Guilmette <rfg@segfault.us.com>
+ - added EXDEV handling
+ - small AFS Makefile patch from mgrlhc@nextwork.rose-hulman.edu
+ - hopefully fixed the Win95 dates to work in other than my
+ timezone
+ - attempted alignment fixups (to speed up memcpy)
+ - added some DCE/DFS support (thanks to Jim Doyle <doyle@oec.com>)
+ - added fix so that root doesn't have special privilages to open
+ readonly files for writing (but admin users do). This fixes the MS
+ office install problem.
+ - fixed trans2 response bug in client
+ - got dual names working for NT
+ - enabled lock_and_read in NT protocol
+ - added %L macro for "local machine"
+ - changed dfree reporting to use "sectors per unit"
+ - fixed "not enough memory" bug in MS print manger by limiting
+ share name length in share enum.
+ - "short preserve case" option from Rabin Ezra (rabin@acm.org)
+ - added archive option to client
+ - changed openX in client to be able to open hidden and system files
+ - added "sync always" option
+ - rewrote writebmpx and readbmpx
+ - added auto string_sub_basic to all loadparm strings
+ - lots of nmbd fixups (add registration, refresh etc)
+ - released alpha1
+ - added smbtar patches from Ricky Poulten (poultenr@logica.co.uk)
+ - added a lpq cache and the "lpq cache time" option
+ - released alpha 2
+ - sun includes fix from Kimmo Suominen <kim@deshaw.com>
+ - change nmbd -L lookup type to workstation from server
+ - added min print space option
+ - added user and group names to smbstatus (thanks to
+ davide.migliavacca@inferentia.it)
+ - fixed %f in print command bug (thanks to huver@amgraf.com)
+ - added wildcard support to SMBmv
+ - misc patches from David Elm (delm@hookup.net)
+ - changed default of "share modes" to yes
+ - changed default of "status" to yes
+ - aix qconfig parsing from Jean-Pierre.Boulard@univ-rennes1.fr
+ - more long_date fixups
+ - added wildcards to nmbd
+ - extensive changes to ipc.c and miscellaneous other changes
+ from ad@papyrus.hamburg.com (Andreas Degert). Should especially
+ help OS/2 users
+ - added name release to nmbd
+ - relesed alpha4
+ - fixed "SOLARIS" to SUNOS5 in Makefile
+ - several minor fixups to get it to compile on aix, osf1, ultrix,
+ solaris and sunos
+ - released alpha5
+ - minor bug fixes and cleanups in ipc.c
+ - fixed "only user" bug
+ - changed lpq to report guest queue entries as sesssetup_user to
+ allow for deletion by windows
+ - released alpha6
+ - added __SAMBA__ as type 0 in nmbd (was type 20)
+ - fixed null print job bug
+ - added 8 char warnings to testparm and smbclient
+ - changed to 8 char limit for names in pcap.c
+ - added linked list of config files to detect all date changes
+ that require a reload
+ - simplified pcap guessing heuristics
+ - added space trimming to the name mapping
+ - updated Get_Pwnam to add allow_change field for username mapping
+ - fixed MemMove bug (thanks to mass@tanner.com (Massimo
+ Sivilotti))
+ - released alpha7
+ - rewrote MemMove to be a little more efficient
+ - ipc va_arg bug fix from djg@tas.com (Dave Gesswein)
+ - added check for illegal chars in long filenames
+ - fixed name cache init bug in nmbd
+ - Convex patches from Victor Balashov <balashov@cv.jinr.dubna.su>
+ - timestring() bugfix from staale@spacetec.no
+ - changed %H to give path of forced user if one is set
+ - added quoting to smbclient to allow spaces in filenames
+ - convex and other patches from Ulrich Hahn
+ <ulrich.hahn@zdv.uni-tuebingen.de>
+ - released alpha8
+ - fixed rename directory bug
+ - nmbd wins fix from Maximilian Errath <errath@balu.kfunigraz.ac.at>
+ - client and AFS changes + password.c reorganisation + "more" and
+ "pwd" commands in client from Todd j. Derr (tjd@smi.med.pitt.edu)
+ - fixed several nmbd bugs
+ - released alpha9
+ - fixed another "cd" bug in smbclient
+ - password encryption from Jeremy Allison
+ - added "passwd chat" option and chat interpretation code
+ - added "smb passwd file" option
+ - released alpha10
+ - cleaned up chgpasswd.c a little
+ - portability changes to the encryption handling code
+ - added password encryption to smbclient
+ - fixed a share level security encryption bug
+ - added "ENCRYPTION.txt" document
+ - released alpha11
+ - added code to detect a password server loop
+ - fixed typo in chkpath in client.c that broken cd (again)
+ - LINUX_BIGCRYPT from marsj@ida.liu.se
+ - AFS password fixup from jbushey@primenet.com (Jeffrey G. Bushey)
+ - iso/8859-1 charcnv patches from Dan.Oscarsson@malmo.trab.se
+ - strtok/user_in_list fix from roderich@nodebonn.muc.bmw.de
+ - NETGROUP patches from J.W.Schilperoort@research.ptt.nl
+ - trim_string patch from J.W.Schilperoort@research.ptt.nl
+ - fixed problem with files with no extension getting mixed up
+ - ipc bugfix for print job deletion from Rainer Leberle <rleberle@auspex.de>
+ - released alpha12
+ - pwlen fix in NETGROUP from Andrew J Cole <A.J.Cole@cbl.leeds.ac.uk>
+ - lots of uid and encryption changes from Jeremy Allison. WinDD
+ should now work.
+ - released alpha13
+ - fixed max_xmit bug in client
+ - select fix in server (fixed critical drive errors under ISC)
+ - released alpha14
+ - wildcard fix from Jeremy
+ - changes to make IPC code more robust
+ - small select loop change to reduce cleaning of share files
+ - vtp, altos and mktime patches from Christian A. Lademann
+ <cal@zls.com>
+ - EEXIST bugfix in server.c
+ - changed mangled map to apply in all cases
+ - released alpha15
+ - fixed fcb open permissions (should mean apps know when a file is
+ read only)
+ - released alpha16
+ - client help formatting fix and docs fix from Peter Jones
+ <thanatos@drealm.org>
+ - added a directory cache
+ - use /proc whenever possible for pid detection
+ - TCSANOW fix in getsmbpasswd from roderich@nodebonn.muc.bmw.de
+ - fixed default printing mode for sysv systems
+ - make client always expand mask
+ - more minor IPC fixups
+ - pyramid makefile entry from jeffrey@itm.org
+ - client fixups for passlen, maxvcs and session redirect from
+ Charles Hoch <hoch@hplcgh.hpl.hp.com>
+ - finally fixed important IPC bug (varargs bug with int16)
+ - quota patches from Dirk.DeWachter@rug.ac.be
+ - print queue cache changes (per service) and print queue priority
+ additions from Dirk.DeWachter@rug.ac.be
+ - new japanese patches (incomplete) from
+ fujita@ainix.isac.co.jp (Takashi Fujita)
+ - moved a lot more functions into system.c via wrappers
+ - changed a lot of the connection refused error codes to be more
+ informative (or at least different)
+ - released alpha17
+ - changed error return code from cannor chdir() in make_connection
+ - fixed realloc() bug in printing.c
+ - fixed invalid username bug in sesssetupX
+ - released alpha18
+ - made default service change name to asked for service (idea
+ from Ian McEwan <ijm@doc.ic.ac.uk>)
+ - fixed "guest only" bug
+ - sambatar patches from Ricky
+ - printing.c patches from Dirk.DeWachter@rug.ac.be
+ - rewrote become_user()
+ - sunos5 patch from Niels.Baggesen@uni-c.dk
+ - more japanese extensions patches from fujita@ainix.isac.co.jp
+ - released alpha20
+ - added force_user to conn struct
+
+
+1.9.15: 14/11/95
+ - removed bcast override from workgroup announce in nmbd
+ - aix patch, added NO_SYSMOUNTH, from
+ lionel leston <102624.346@compuserve.com>
+ - quick fix in lp_string() to try and stop some core dumps
+ - added uid cache in connections structure
+ to make user level security faster
+ - changed dos_mode() to show read-only on read-only shares only if
+ user w bit not set
+ - added check to stop exit_server() looping
+ - core dump fix in string_sub()
+ - fix client bug for long dirs in NT1 mode.
+ Thanks to Erwin Authried (erwin@ws1.atv.tuwien.ac.at)
+ - switched to a safer (but probably slower) readbraw implementation
+ - released p1
+ - readbraw fix from Stefaan.Eeckels@eunet.lu
+ - fixed groups bug when user is in 1 group
+ - fixed NT1 dir bug
+ - changed default protocol in client to NT1
+ - changed trans2 to not return both names in long listing if long
+ name is 8.3
+ - made stat of "" return RONLY if not writeable drive
+ - wrapped strcpy() to stop nulls propogating (hack)
+ - made rename and unlink look at share locks on file
+ - clitar memory leak fix from jjm@jjm.com
+ - added -p option to smbstatus to list smbd processes
+ - added rename to the client
+ - released p2
+ - fixed SMBmv for case where the destination exists
+ - man page patch from michal@ellpspace.math.ualberta.ca (Michal Jaegermann)
+ - once again redid the time handling, but finally explained what
+ is going on, this is written up in TIME.txt. The "kludge-GMT" used
+ by NT is a bastard and led to a lot of the confusion
+ - kanji patch from fujita@ainix.isac.co.jp (Takashi Fujita)
+ - is08859-1 patches from eauth@mail.cso.co.at
+ - starting rewriting nmbd, new nmbd is nmbd2, old one still around
+ for time being
+ - released p3
+ - rewrote more of nmbd2 to use new structures
+ - CLIX patches from Jason.J.Faultless@bechtel.btx400.co.uk
+ - DirCacheFlush() bugfix from Michael Joosten
+ <joost@ori.cadlab.de>. This bug explains a lot of the crashes.
+ - fixed a bug in ChDir() that caused reversion to / in some
+ situations
+ - ipc fix from Magnus Hyllander <mhy@os.se>
+ - released p4
+ - smbpasswd fix from Jeremy
+ - compilation fixes from Magnus Hyllander <mhy@os.se>
+ - added NetServerEnum to ipc.c (needed for master browser stuff)
+ - Makefile fix from Gunther Mayer <gmayer@physik.uni-kl.de>
+ - cleanups for clean compile on several OSes
+ - added browse mastering code
+ - started integration with smb.conf for nmbd2
+ - released p5
+ - fixed death_time (should be t+ttl*3)
+ - fixed non-removal of dead servers
+ - added smbstatus -u patch from oskarh@spornet.is (Oskar Hannesson)
+ - NETGROUP fix from J.W.Schilperoort@research.kpn.com
+ - select and NO_SETGROUPS patches from lennylim@netcom.com (Lenny
+ Lim)
+ - added LINKS_READ_ONLY define in dos_mode() for LM/X
+ compatability
+ - "dir a.c" bug fixed thanks to roderich@nodebonn.muc.bmw.de
+ (Roderich Schupp)
+ - job cancel fix in client from peo@mtek.chalmers.se
+ - changed nmbd2 to nmbd
+ - fixed "dir a*" under trans2 lookups
+ - added StrnCaseCmp()
+ - updated docs a bit for new browsing stuff
+ - updated INSTALL.txt
+ - hopefully fixed server level security with WfWg
+
+1.9.15 (patches):
+ - major/minor fix for solaris from Jeroen Schipper
+ <Jeroen.Schipper@let.ruu.nl>
+ - fixed critical bug in directory listings
+ - released p1
+ - fixed one of the causes of "out of memory" while browsing
+ - fixed manpage install script (Paul Blackman)
+ - added DNS failures to name cache
+ - fixed writebmpx bug (affects OS/2)
+ - misc OS/2 fixes, mostly for EA handling
+ - added SMBcopy
+ - added "max ttl" option
+ - arch detection patch from Bas Laarhoven <bas@vimec.nl>
+ - released p2
+ - another OS/2 fix - the level 4 getpathinfo for EAs
+ - added "alternate permissions" option
+ - changed client to parse destination names into name + domain
+ - fixed problem with PrimaryGroup and lmhosts loading
+ - added domain master ability to nmbd
+ - added "domain master" option
+ - added "domain controller" option and code
+ - pwd fix to client from Erik Devriendt (de@te6.siemens.be)
+ - fixed problem in smbmv that led to ar not working in mks
+ - added transs2
+ - released p3
+ - updated email addresses
+ - fix for innetgr from Olaf Seibert (rhialto@polder.ubc.kun.nl)
+ - client translate fix from bandc@dircon.co.uk
+ - netbsd bcast fix from from Olaf Seibert (rhialto@polder.ubc.kun.nl)
+ - syslog code from Alex Nash <alex@fa.tca.com>
+ - strip dot fix from Arne Ansper <arne@ioc.ee>
+ - added addtosmbpass + man page from
+ michal@ellpspace.math.ualberta.ca (Michal Jaegermann)
+ - pcap fix for AIX from Jon Christiansen <jchristi@sctcorp.com>
+ - fixed servertype bug in remote announcements
+ - fixed up illegal name checks (should also be faster)
+ - kanji patches from fujita@ainix.isac.co.jp (Takashi Fujita)
+ - fixed bug handling non-encrypted passwords
+ - released p4
+ - fixed makefile for addtosmbpass
+ - DCE/DFS fixes from John Brezak (brezak@ch.hp.com)
+ - client patch for partial command matching from Andrew Wiseman
+ <bandc@dircon.co.uk>
+ - made is_8_3() handle full paths
+ - rewrote open_file_shared() with help from Charles Hoch
+ <hoch@hplcgh.hpl.hp.com>
+ - changed syslog to handle interactive programs
+ - fixed syslog problem with full path in argv[0]
+ - illegal name fixup for kanji from fujita@ainix.isac.co.jp
+ - fixed server level security to allow fallback to encryption
+ - changed reply_read() and reply_lockread() to ignore clients
+ smb_bufsize in order to handle broken lanman clients
+ - fixed NT wildcard problem with old style programs
+ - man page patches from "John M. Sellens"
+ <jmsellen@watdragon.uwaterloo.ca>
+ - partially documented the "character set" option
+ - changed default for MAXDIR to 64
+ - changed default DPTR idle time to 120
+ - released p5
+ - QNX patches from eldo@invisa.satlink.net (Eldo Loguzzo)
+ - made nmbd use the "max log size" option and changed log handling
+ code a bit
+ - sunos patches, remote protocol (%R) addition and arch detection
+ changes to stop compiler warning from Timothy Hunt <tim@fsg.com>
+ - fixed become_user() bug that led to incorrect permissions in
+ some situations.
+ - released p6
+ - is_8_3() fix from Charles Hoch <hoch@hplcgh.hpl.hp.com>
+ - nmblib bugfix from gmk@mhcnet.att.com (George Kull)
+ - aix pcap fix from Jon Christiansen <jchristi@sctcorp.com>
+ - added explicit sig_pipe() in server.c
+ - added domain logins option (not fully implemented)
+ - added HAVE_GMTOFF code
+ - got rid of PM_MAXLINE
+ - minor client fix from goggi@eflir (Garðar Georg Nielsen)
+ - added SIGCLD_IGNORE for HPUX (from Tor Lillqvist
+ <tml@hemuli.tte.vtt.fi>)
+ - OSF/1 lpq patch from scooter@GENE.COM (Scooter Morris)
+ - NeXT patches from pmarcos@next.com (Paul Marcos)
+ - dstdiff patch to stop infinite loop from Erwin Authried (eauth@cso.co.at)
+ - password server option can now take a list of password servers
+ - patches to let samba run on OS/2 from Jason Rumney <jasonr@pec.co.nz>
+ - added domain logon and logon script suport
+ - SCO openserver 5 patches from Scott Michel <scottm@intime.intime.com>
+ - Makefile changes from Marty Leisner <leisner@sdsp.mc.xerox.com>
+ - chgpasswd changes from Roman Dumych <roman@nyxis.unibase.com>
+ for SVR4
+ - GUEST_SESSSETUP change from David.Chappell@mail.cc.trincoll.edu
+ - released p7
+ - moved SO_REUSEADDR before bind() (thanks to Thomas Bellman
+ <tbe@ivab.se>)
+ - added more flexible GUEST_SESSSETUP to local.h and restored
+ pre-p7 behaviour as default
+ - released p8
+
+1.9.16:
+ - Makefile fix from Marty Leisner <leisner@sdsp.mc.xerox.com>
+ - added %g and %G substitutions
+ - changed IDLE_CLOSED_TIMEOUT to 60
+ - fixed the "admin user" status in domain logons
+ - hpux 10 "trusted security" patches from David-Michael Lincke
+ (dlincke@sgcl1.unisg.ch)
+ - added nmb lookups to client from Adrian Hill <Adrian.Hill@softimage.co.uk>
+ - svr4 pause/resume printing patch from Brendan O'Dea (bod@tyndall.com.au)
+ - fixed master announcement thanks to Luke Leighton <rah14@dial.pipex.com>
+ - changed srcdir usage in Makefile to be friendly to more systems
+ - NT4 alignment patches from Jeremy Allison (jra@vantive.com)
+ - updated share mode code for new spec
+ - minor client bugfix (for smbclient '\\\')
+ - fix for level 260 when magling disabled. From Martin Tomes
+ <Martin.Tomes@ecl.etherm.co.uk>
+ - SMBtranss2 fix for OS/2 from Jeremy Allison
+ - profiles fixup from Timm Wetzel <twetzel@cage.mpibpc.gwdg.de>
+ - man page updates from Dirk.DeWachter@rug.ac.be
+ - nmbsync fix from Andy Whitcroft <andy@soi.city.ac.uk>
+ - Lynx patches from Manfred Woelfel <woelfel@hpesco1.fzk.de>
+ - new smbtar stuff from Ricky
+ - changed to share mode DENY_NONE for tar
+ - fixed -D option of smbclient when in tar mode
+ - added aARCH to open modes
+ - added code to cope with select/read errors
+ - fixed blank browse entries after smb.conf reread
+ - integrated new browse stuff from Luke into ipc.c
+ - added workgroup list to smbclient -L
+ - improved archive attribute handling in close_file() and
+ write_file()
+ - smbtar fixes from Martin.Kraemer@mch.sni.de
+ - 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.
+
+
+==========
+todo:
+
+
+64 bit longs and IP addresses may give problems with unsigned longs?
+
+set archive bit whenever file is modified??
+
+fix man page dates
+
+reply only to own workgroup in server enum
+
+patch to compile with g++ and possibly solaris c++
+
+nmbd needs to keep browse list uptodate by talking to the master if it loses
+an election as others may still think its a valid backup and use it to get
+lists.
+
+leftover lock files can end up belonging to non-smbd processes after a reboot.
+
+hosts allow in nmbd
+
+hosts allow cache
+
+add password command in smbclient
+
+drag long filename to samba under os/2 gives short name
+
+document max ttl option
+
+dup/close 0 for getopt?
+
+implement SMBmove ??
+
+add option to print more info about locked files (full path, share name
+etc)
+
+very slow listing CD, perhaps because of order of stat and readdir or add
+masking to opendir?
+
+protocol drop back in client to avoid openX etc.
+
+handle exported fat drives to a long filename capable client
+
+add check for existance of lpq commands etc (use stat?)
+
+get rid of the silly +4 and -4 by removing NBT stuff
+
+write-only shares
+
+document cnvchar stuff
+
+allow smbd to serve user and group lists to win95
+
+document homes behaviour with WinDD
+
+add "hide file = *.o" "hide dir = .Foo*" "show file = xx*" type options.
+
+ALLOW_PASSWORD_CHANGE only compiles/works on some systems
+
+weird foooooooo/open.exe bug on NT
+
+%a detection can't detect Win95 versus WinNT
+
+reverse mangled maps, so (*.html *.htm) works for new files.
+
+install problems with w95. could be some sort of race?
+
+more efficient Files[] structure to handle thousands of open files
+
+lpd stuff:
+ Tony Aiuto (tony@ics.com)
+
+make max disk size local
+
diff --git a/source3/client/cifs.upcall.c b/source3/client/cifs.upcall.c
new file mode 100644
index 0000000000..4110de35fd
--- /dev/null
+++ b/source3/client/cifs.upcall.c
@@ -0,0 +1,391 @@
+/*
+* CIFS user-space helper.
+* Copyright (C) Igor Mammedov (niallain@gmail.com) 2007
+*
+* Used by /sbin/request-key for handling
+* cifs upcall for kerberos authorization of access to share and
+* cifs upcall for DFS srver name resolving (IPv4/IPv6 aware).
+* You should have keyutils installed and add something like the
+* following lines to /etc/request-key.conf file:
+
+create cifs.spnego * * /usr/local/sbin/cifs.upcall %k
+create dns_resolver * * /usr/local/sbin/cifs.upcall %k
+
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+* You 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
+*/
+
+#include "includes.h"
+#include <keyutils.h>
+
+#include "cifs_spnego.h"
+
+const char *CIFSSPNEGO_VERSION = "1.2";
+static const char *prog = "cifs.upcall";
+typedef enum _secType {
+ NONE = 0,
+ KRB5,
+ MS_KRB5
+} secType_t;
+
+/*
+ * Prepares AP-REQ data for mechToken and gets session key
+ * Uses credentials from cache. It will not ask for password
+ * you should receive credentials for yuor name manually using
+ * kinit or whatever you wish.
+ *
+ * in:
+ * oid - string with OID/ Could be OID_KERBEROS5
+ * or OID_KERBEROS5_OLD
+ * principal - Service name.
+ * Could be "cifs/FQDN" for KRB5 OID
+ * or for MS_KRB5 OID style server principal
+ * like "pdc$@YOUR.REALM.NAME"
+ *
+ * out:
+ * secblob - pointer for spnego wrapped AP-REQ data to be stored
+ * sess_key- pointer for SessionKey data to be stored
+ *
+ * ret: 0 - success, others - failure
+*/
+static int
+handle_krb5_mech(const char *oid, const char *principal,
+ DATA_BLOB * secblob, DATA_BLOB * sess_key)
+{
+ int retval;
+ DATA_BLOB tkt, tkt_wrapped;
+
+ /* get a kerberos ticket for the service and extract the session key */
+ retval = cli_krb5_get_ticket(principal, 0,
+ &tkt, sess_key, 0, NULL, NULL);
+
+ if (retval)
+ return retval;
+
+ /* wrap that up in a nice GSS-API wrapping */
+ tkt_wrapped = spnego_gen_krb5_wrap(tkt, TOK_ID_KRB_AP_REQ);
+
+ /* and wrap that in a shiny SPNEGO wrapper */
+ *secblob = gen_negTokenInit(oid, tkt_wrapped);
+
+ data_blob_free(&tkt_wrapped);
+ data_blob_free(&tkt);
+ return retval;
+}
+
+#define DKD_HAVE_HOSTNAME 1
+#define DKD_HAVE_VERSION 2
+#define DKD_HAVE_SEC 4
+#define DKD_HAVE_IPV4 8
+#define DKD_HAVE_IPV6 16
+#define DKD_HAVE_UID 32
+#define DKD_MUSTHAVE_SET (DKD_HAVE_HOSTNAME|DKD_HAVE_VERSION|DKD_HAVE_SEC)
+
+static int
+decode_key_description(const char *desc, int *ver, secType_t * sec,
+ char **hostname, uid_t * uid)
+{
+ int retval = 0;
+ char *pos;
+ const char *tkn = desc;
+
+ do {
+ pos = index(tkn, ';');
+ if (strncmp(tkn, "host=", 5) == 0) {
+ int len;
+
+ if (pos == NULL) {
+ len = strlen(tkn);
+ } else {
+ len = pos - tkn;
+ }
+ len -= 4;
+ SAFE_FREE(*hostname);
+ *hostname = SMB_XMALLOC_ARRAY(char, len);
+ strlcpy(*hostname, tkn + 5, len);
+ retval |= DKD_HAVE_HOSTNAME;
+ } else if (strncmp(tkn, "ipv4=", 5) == 0) {
+ /* BB: do we need it if we have hostname already? */
+ } else if (strncmp(tkn, "ipv6=", 5) == 0) {
+ /* BB: do we need it if we have hostname already? */
+ } else if (strncmp(tkn, "sec=", 4) == 0) {
+ if (strncmp(tkn + 4, "krb5", 4) == 0) {
+ retval |= DKD_HAVE_SEC;
+ *sec = KRB5;
+ } else if (strncmp(tkn + 4, "mskrb5", 6) == 0) {
+ retval |= DKD_HAVE_SEC;
+ *sec = MS_KRB5;
+ }
+ } else if (strncmp(tkn, "uid=", 4) == 0) {
+ errno = 0;
+ *uid = strtol(tkn + 4, NULL, 16);
+ if (errno != 0) {
+ syslog(LOG_WARNING, "Invalid uid format: %s",
+ strerror(errno));
+ return 1;
+ } else {
+ retval |= DKD_HAVE_UID;
+ }
+ } else if (strncmp(tkn, "ver=", 4) == 0) { /* if version */
+ errno = 0;
+ *ver = strtol(tkn + 4, NULL, 16);
+ if (errno != 0) {
+ syslog(LOG_WARNING,
+ "Invalid version format: %s",
+ strerror(errno));
+ return 1;
+ } else {
+ retval |= DKD_HAVE_VERSION;
+ }
+ }
+ if (pos == NULL)
+ break;
+ tkn = pos + 1;
+ } while (tkn);
+ return retval;
+}
+
+static int
+cifs_resolver(const key_serial_t key, const char *key_descr)
+{
+ int c;
+ struct addrinfo *addr;
+ char ip[INET6_ADDRSTRLEN];
+ void *p;
+ const char *keyend = key_descr;
+ /* skip next 4 ';' delimiters to get to description */
+ for (c = 1; c <= 4; c++) {
+ keyend = index(keyend+1, ';');
+ if (!keyend) {
+ syslog(LOG_WARNING, "invalid key description: %s",
+ key_descr);
+ return 1;
+ }
+ }
+ keyend++;
+
+ /* resolve name to ip */
+ c = getaddrinfo(keyend, NULL, NULL, &addr);
+ if (c) {
+ syslog(LOG_WARNING, "unable to resolve hostname: %s [%s]",
+ keyend, gai_strerror(c));
+ return 1;
+ }
+
+ /* conver ip to string form */
+ if (addr->ai_family == AF_INET) {
+ p = &(((struct sockaddr_in *)addr->ai_addr)->sin_addr);
+ } else {
+ p = &(((struct sockaddr_in6 *)addr->ai_addr)->sin6_addr);
+ }
+ if (!inet_ntop(addr->ai_family, p, ip, sizeof(ip))) {
+ syslog(LOG_WARNING, "%s: inet_ntop: %s",
+ __FUNCTION__, strerror(errno));
+ freeaddrinfo(addr);
+ return 1;
+ }
+
+ /* setup key */
+ c = keyctl_instantiate(key, ip, strlen(ip)+1, 0);
+ if (c == -1) {
+ syslog(LOG_WARNING, "%s: keyctl_instantiate: %s",
+ __FUNCTION__, strerror(errno));
+ freeaddrinfo(addr);
+ return 1;
+ }
+
+ freeaddrinfo(addr);
+ return 0;
+}
+
+static void
+usage(void)
+{
+ syslog(LOG_WARNING, "Usage: %s [-c] [-v] key_serial", prog);
+ fprintf(stderr, "Usage: %s [-c] [-v] key_serial\n", prog);
+}
+
+int main(const int argc, char *const argv[])
+{
+ struct cifs_spnego_msg *keydata = NULL;
+ DATA_BLOB secblob = data_blob_null;
+ DATA_BLOB sess_key = data_blob_null;
+ secType_t sectype = NONE;
+ key_serial_t key = 0;
+ size_t datalen;
+ long rc = 1;
+ uid_t uid = 0;
+ int kernel_upcall_version = 0;
+ int c, use_cifs_service_prefix = 0;
+ char *buf, *hostname = NULL;
+ const char *oid;
+
+ openlog(prog, 0, LOG_DAEMON);
+
+ while ((c = getopt(argc, argv, "cv")) != -1) {
+ switch (c) {
+ case 'c':{
+ use_cifs_service_prefix = 1;
+ break;
+ }
+ case 'v':{
+ printf("version: %s\n", CIFSSPNEGO_VERSION);
+ goto out;
+ }
+ default:{
+ syslog(LOG_WARNING, "unknown option: %c", c);
+ goto out;
+ }
+ }
+ }
+
+ /* is there a key? */
+ if (argc <= optind) {
+ usage();
+ goto out;
+ }
+
+ /* get key and keyring values */
+ errno = 0;
+ key = strtol(argv[optind], NULL, 10);
+ if (errno != 0) {
+ key = 0;
+ syslog(LOG_WARNING, "Invalid key format: %s", strerror(errno));
+ goto out;
+ }
+
+ rc = keyctl_describe_alloc(key, &buf);
+ if (rc == -1) {
+ syslog(LOG_WARNING, "keyctl_describe_alloc failed: %s",
+ strerror(errno));
+ rc = 1;
+ goto out;
+ }
+
+ if ((strncmp(buf, "cifs.resolver", sizeof("cifs.resolver")-1) == 0) ||
+ (strncmp(buf, "dns_resolver", sizeof("dns_resolver")-1) == 0)) {
+ rc = cifs_resolver(key, buf);
+ goto out;
+ }
+
+ rc = decode_key_description(buf, &kernel_upcall_version, &sectype,
+ &hostname, &uid);
+ if ((rc & DKD_MUSTHAVE_SET) != DKD_MUSTHAVE_SET) {
+ syslog(LOG_WARNING,
+ "unable to get from description necessary params");
+ rc = 1;
+ SAFE_FREE(buf);
+ goto out;
+ }
+ SAFE_FREE(buf);
+
+ if (kernel_upcall_version > CIFS_SPNEGO_UPCALL_VERSION) {
+ syslog(LOG_WARNING,
+ "incompatible kernel upcall version: 0x%x",
+ kernel_upcall_version);
+ rc = 1;
+ goto out;
+ }
+
+ if (rc & DKD_HAVE_UID) {
+ rc = setuid(uid);
+ if (rc == -1) {
+ syslog(LOG_WARNING, "setuid: %s", strerror(errno));
+ goto out;
+ }
+ }
+
+ /* BB: someday upcall SPNEGO blob could be checked here to decide
+ * what mech to use */
+
+ // do mech specific authorization
+ switch (sectype) {
+ case MS_KRB5:
+ case KRB5:{
+ char *princ;
+ size_t len;
+
+ /* for "cifs/" service name + terminating 0 */
+ len = strlen(hostname) + 5 + 1;
+ princ = SMB_XMALLOC_ARRAY(char, len);
+ if (!princ) {
+ rc = 1;
+ break;
+ }
+ if (use_cifs_service_prefix) {
+ strlcpy(princ, "cifs/", len);
+ } else {
+ strlcpy(princ, "host/", len);
+ }
+ strlcpy(princ + 5, hostname, len - 5);
+
+ if (sectype == MS_KRB5)
+ oid = OID_KERBEROS5_OLD;
+ else
+ oid = OID_KERBEROS5;
+
+ rc = handle_krb5_mech(oid, princ, &secblob, &sess_key);
+ SAFE_FREE(princ);
+ break;
+ }
+ default:{
+ syslog(LOG_WARNING, "sectype: %d is not implemented",
+ sectype);
+ rc = 1;
+ break;
+ }
+ }
+
+ if (rc) {
+ goto out;
+ }
+
+ /* pack SecurityBLob and SessionKey into downcall packet */
+ datalen =
+ sizeof(struct cifs_spnego_msg) + secblob.length + sess_key.length;
+ keydata = (struct cifs_spnego_msg*)SMB_XMALLOC_ARRAY(char, datalen);
+ if (!keydata) {
+ rc = 1;
+ goto out;
+ }
+ keydata->version = kernel_upcall_version;
+ keydata->flags = 0;
+ keydata->sesskey_len = sess_key.length;
+ keydata->secblob_len = secblob.length;
+ memcpy(&(keydata->data), sess_key.data, sess_key.length);
+ memcpy(&(keydata->data) + keydata->sesskey_len,
+ secblob.data, secblob.length);
+
+ /* setup key */
+ rc = keyctl_instantiate(key, keydata, datalen, 0);
+ if (rc == -1) {
+ syslog(LOG_WARNING, "keyctl_instantiate: %s", strerror(errno));
+ goto out;
+ }
+
+ /* BB: maybe we need use timeout for key: for example no more then
+ * ticket lifietime? */
+ /* keyctl_set_timeout( key, 60); */
+out:
+ /*
+ * on error, negatively instantiate the key ourselves so that we can
+ * make sure the kernel doesn't hang it off of a searchable keyring
+ * and interfere with the next attempt to instantiate the key.
+ */
+ if (rc != 0 && key == 0)
+ keyctl_negate(key, 1, KEY_REQKEY_DEFL_DEFAULT);
+ data_blob_free(&secblob);
+ data_blob_free(&sess_key);
+ SAFE_FREE(hostname);
+ SAFE_FREE(keydata);
+ return rc;
+}
diff --git a/source3/client/cifs_spnego.h b/source3/client/cifs_spnego.h
new file mode 100644
index 0000000000..f8753a7d59
--- /dev/null
+++ b/source3/client/cifs_spnego.h
@@ -0,0 +1,46 @@
+/*
+ * fs/cifs/cifs_spnego.h -- SPNEGO upcall management for CIFS
+ *
+ * Copyright (c) 2007 Red Hat, Inc.
+ * Author(s): Jeff Layton (jlayton@redhat.com)
+ * Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _CIFS_SPNEGO_H
+#define _CIFS_SPNEGO_H
+
+#define CIFS_SPNEGO_UPCALL_VERSION 2
+
+/*
+ * The version field should always be set to CIFS_SPNEGO_UPCALL_VERSION.
+ * The flags field is for future use. The request-key callout should set
+ * sesskey_len and secblob_len, and then concatenate the SessKey+SecBlob
+ * and stuff it in the data field.
+ */
+struct cifs_spnego_msg {
+ uint32_t version;
+ uint32_t flags;
+ uint32_t sesskey_len;
+ uint32_t secblob_len;
+ uint8_t data[1];
+};
+
+#ifdef __KERNEL__
+extern struct key_type cifs_spnego_key_type;
+#endif /* KERNEL */
+
+#endif /* _CIFS_SPNEGO_H */
diff --git a/source3/client/client.c b/source3/client/client.c
new file mode 100644
index 0000000000..1c05c4035d
--- /dev/null
+++ b/source3/client/client.c
@@ -0,0 +1,4977 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Simo Sorce 2001-2002
+ Copyright (C) Jelmer Vernooij 2003
+ Copyright (C) Gerald (Jerry) Carter 2004
+ Copyright (C) Jeremy Allison 1994-2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "client/client_proto.h"
+#include "include/rpc_client.h"
+#ifndef REGISTER
+#define REGISTER 0
+#endif
+
+extern int do_smb_browse(void); /* mDNS browsing */
+
+extern bool AllowDebugChange;
+extern bool override_logfile;
+extern char tar_type;
+
+static int port = 0;
+static char *service;
+static char *desthost;
+static char *calling_name;
+static bool grepable = false;
+static char *cmdstr = NULL;
+const char *cmd_ptr = NULL;
+
+static int io_bufsize = 524288;
+
+static int name_type = 0x20;
+extern int max_protocol;
+
+static int process_tok(char *tok);
+static int cmd_help(void);
+
+#define CREATE_ACCESS_READ READ_CONTROL_ACCESS
+
+/* 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)
+
+time_t newer_than = 0;
+static int archive_level = 0;
+
+static bool translation = false;
+static bool have_ip;
+
+/* clitar bits insert */
+extern int blocksize;
+extern bool tar_inc;
+extern bool tar_reset;
+/* clitar bits end */
+
+static bool prompt = true;
+
+static bool recurse = false;
+static bool showacls = false;
+bool lowercase = false;
+
+static struct sockaddr_storage dest_ss;
+
+#define SEPARATORS " \t\n\r"
+
+static bool abort_mget = true;
+
+/* timing globals */
+SMB_BIG_UINT get_total_size = 0;
+unsigned int get_total_time_ms = 0;
+static SMB_BIG_UINT put_total_size = 0;
+static unsigned int put_total_time_ms = 0;
+
+/* totals globals */
+static double dir_total;
+
+/* encrypted state. */
+static bool smb_encrypt;
+
+/* root cli_state connection */
+
+struct cli_state *cli;
+
+static char CLI_DIRSEP_CHAR = '\\';
+static char CLI_DIRSEP_STR[] = { '\\', '\0' };
+
+/* Accessor functions for directory paths. */
+static char *fileselection;
+static const char *client_get_fileselection(void)
+{
+ if (fileselection) {
+ return fileselection;
+ }
+ return "";
+}
+
+static const char *client_set_fileselection(const char *new_fs)
+{
+ SAFE_FREE(fileselection);
+ if (new_fs) {
+ fileselection = SMB_STRDUP(new_fs);
+ }
+ return client_get_fileselection();
+}
+
+static char *cwd;
+static const char *client_get_cwd(void)
+{
+ if (cwd) {
+ return cwd;
+ }
+ return CLI_DIRSEP_STR;
+}
+
+static const char *client_set_cwd(const char *new_cwd)
+{
+ SAFE_FREE(cwd);
+ if (new_cwd) {
+ cwd = SMB_STRDUP(new_cwd);
+ }
+ return client_get_cwd();
+}
+
+static char *cur_dir;
+const char *client_get_cur_dir(void)
+{
+ if (cur_dir) {
+ return cur_dir;
+ }
+ return CLI_DIRSEP_STR;
+}
+
+const char *client_set_cur_dir(const char *newdir)
+{
+ SAFE_FREE(cur_dir);
+ if (newdir) {
+ cur_dir = SMB_STRDUP(newdir);
+ }
+ return client_get_cur_dir();
+}
+
+/****************************************************************************
+ Write to a local file with CR/LF->LF translation if appropriate. Return the
+ number taken from the buffer. This may not equal the number written.
+****************************************************************************/
+
+static int writefile(int f, char *b, int n)
+{
+ int i;
+
+ if (!translation) {
+ return write(f,b,n);
+ }
+
+ i = 0;
+ while (i < n) {
+ if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
+ b++;i++;
+ }
+ if (write(f, b, 1) != 1) {
+ break;
+ }
+ b++;
+ i++;
+ }
+
+ return(i);
+}
+
+/****************************************************************************
+ Read from a file with LF->CR/LF translation if appropriate. Return the
+ number read. read approx n bytes.
+****************************************************************************/
+
+static int readfile(char *b, int n, XFILE *f)
+{
+ int i;
+ int c;
+
+ if (!translation)
+ return x_fread(b,1,n,f);
+
+ i = 0;
+ while (i < (n - 1) && (i < BUFFER_SIZE)) {
+ if ((c = x_getc(f)) == EOF) {
+ break;
+ }
+
+ if (c == '\n') { /* change all LFs to CR/LF */
+ b[i++] = '\r';
+ }
+
+ b[i++] = c;
+ }
+
+ return(i);
+}
+
+/****************************************************************************
+ Send a message.
+****************************************************************************/
+
+static void send_message(void)
+{
+ int total_len = 0;
+ int grp_id;
+
+ if (!cli_message_start(cli, desthost,
+ get_cmdline_auth_info_username(), &grp_id)) {
+ d_printf("message start: %s\n", cli_errstr(cli));
+ return;
+ }
+
+
+ d_printf("Connected. Type your message, ending it with a Control-D\n");
+
+ while (!feof(stdin) && total_len < 1600) {
+ int maxlen = MIN(1600 - total_len,127);
+ char msg[1024];
+ int l=0;
+ int c;
+
+ ZERO_ARRAY(msg);
+
+ for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++) {
+ if (c == '\n')
+ msg[l++] = '\r';
+ msg[l] = c;
+ }
+
+ if ((total_len > 0) && (strlen(msg) == 0)) {
+ break;
+ }
+
+ if (!cli_message_text(cli, msg, l, grp_id)) {
+ d_printf("SMBsendtxt failed (%s)\n",cli_errstr(cli));
+ return;
+ }
+
+ total_len += l;
+ }
+
+ if (total_len >= 1600)
+ d_printf("the message was truncated to 1600 bytes\n");
+ else
+ d_printf("sent %d bytes\n",total_len);
+
+ if (!cli_message_end(cli, grp_id)) {
+ d_printf("SMBsendend failed (%s)\n",cli_errstr(cli));
+ return;
+ }
+}
+
+/****************************************************************************
+ Check the space on a device.
+****************************************************************************/
+
+static int do_dskattr(void)
+{
+ int total, bsize, avail;
+ struct cli_state *targetcli = NULL;
+ char *targetpath = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if ( !cli_resolve_path(ctx, "", cli, client_get_cur_dir(), &targetcli, &targetpath)) {
+ d_printf("Error in dskattr: %s\n", cli_errstr(cli));
+ return 1;
+ }
+
+ if (!cli_dskattr(targetcli, &bsize, &total, &avail)) {
+ d_printf("Error in dskattr: %s\n",cli_errstr(targetcli));
+ return 1;
+ }
+
+ d_printf("\n\t\t%d blocks of size %d. %d blocks available\n",
+ total, bsize, avail);
+
+ return 0;
+}
+
+/****************************************************************************
+ Show cd/pwd.
+****************************************************************************/
+
+static int cmd_pwd(void)
+{
+ d_printf("Current directory is %s",service);
+ d_printf("%s\n",client_get_cur_dir());
+ return 0;
+}
+
+/****************************************************************************
+ Ensure name has correct directory separators.
+****************************************************************************/
+
+static void normalize_name(char *newdir)
+{
+ if (!(cli->posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
+ string_replace(newdir,'/','\\');
+ }
+}
+
+/****************************************************************************
+ Change directory - inner section.
+****************************************************************************/
+
+static int do_cd(const char *new_dir)
+{
+ char *newdir = NULL;
+ char *saved_dir = NULL;
+ char *new_cd = NULL;
+ char *targetpath = NULL;
+ struct cli_state *targetcli = NULL;
+ SMB_STRUCT_STAT sbuf;
+ uint32 attributes;
+ int ret = 1;
+ TALLOC_CTX *ctx = talloc_stackframe();
+
+ newdir = talloc_strdup(ctx, new_dir);
+ if (!newdir) {
+ TALLOC_FREE(ctx);
+ return 1;
+ }
+
+ normalize_name(newdir);
+
+ /* Save the current directory in case the new directory is invalid */
+
+ saved_dir = talloc_strdup(ctx, client_get_cur_dir());
+ if (!saved_dir) {
+ TALLOC_FREE(ctx);
+ return 1;
+ }
+
+ if (*newdir == CLI_DIRSEP_CHAR) {
+ client_set_cur_dir(newdir);
+ new_cd = newdir;
+ } else {
+ new_cd = talloc_asprintf(ctx, "%s%s",
+ client_get_cur_dir(),
+ newdir);
+ if (!new_cd) {
+ goto out;
+ }
+ }
+
+ /* Ensure cur_dir ends in a DIRSEP */
+ if ((new_cd[0] != '\0') && (*(new_cd+strlen(new_cd)-1) != CLI_DIRSEP_CHAR)) {
+ new_cd = talloc_asprintf_append(new_cd, CLI_DIRSEP_STR);
+ if (!new_cd) {
+ goto out;
+ }
+ }
+ client_set_cur_dir(new_cd);
+
+ new_cd = clean_name(ctx, new_cd);
+ client_set_cur_dir(new_cd);
+
+ if ( !cli_resolve_path(ctx, "", cli, new_cd, &targetcli, &targetpath)) {
+ d_printf("cd %s: %s\n", new_cd, cli_errstr(cli));
+ client_set_cur_dir(saved_dir);
+ goto out;
+ }
+
+ if (strequal(targetpath,CLI_DIRSEP_STR )) {
+ TALLOC_FREE(ctx);
+ return 0;
+ }
+
+ /* Use a trans2_qpathinfo to test directories for modern servers.
+ Except Win9x doesn't support the qpathinfo_basic() call..... */
+
+ if (targetcli->protocol > PROTOCOL_LANMAN2 && !targetcli->win95) {
+ if (!cli_qpathinfo_basic( targetcli, targetpath, &sbuf, &attributes ) ) {
+ d_printf("cd %s: %s\n", new_cd, cli_errstr(targetcli));
+ client_set_cur_dir(saved_dir);
+ goto out;
+ }
+
+ if (!(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ d_printf("cd %s: not a directory\n", new_cd);
+ client_set_cur_dir(saved_dir);
+ goto out;
+ }
+ } else {
+ targetpath = talloc_asprintf(ctx,
+ "%s%s",
+ targetpath,
+ CLI_DIRSEP_STR );
+ if (!targetpath) {
+ client_set_cur_dir(saved_dir);
+ goto out;
+ }
+ targetpath = clean_name(ctx, targetpath);
+ if (!targetpath) {
+ client_set_cur_dir(saved_dir);
+ goto out;
+ }
+
+ if (!cli_chkpath(targetcli, targetpath)) {
+ d_printf("cd %s: %s\n", new_cd, cli_errstr(targetcli));
+ client_set_cur_dir(saved_dir);
+ goto out;
+ }
+ }
+
+ ret = 0;
+
+out:
+
+ TALLOC_FREE(ctx);
+ return ret;
+}
+
+/****************************************************************************
+ Change directory.
+****************************************************************************/
+
+static int cmd_cd(void)
+{
+ char *buf = NULL;
+ int rc = 0;
+
+ if (next_token_talloc(talloc_tos(), &cmd_ptr, &buf,NULL)) {
+ rc = do_cd(buf);
+ } else {
+ d_printf("Current directory is %s\n",client_get_cur_dir());
+ }
+
+ return rc;
+}
+
+/****************************************************************************
+ Change directory.
+****************************************************************************/
+
+static int cmd_cd_oneup(void)
+{
+ return do_cd("..");
+}
+
+/*******************************************************************
+ Decide if a file should be operated on.
+********************************************************************/
+
+static bool do_this_one(file_info *finfo)
+{
+ if (!finfo->name) {
+ return false;
+ }
+
+ if (finfo->mode & aDIR) {
+ return true;
+ }
+
+ if (*client_get_fileselection() &&
+ !mask_match(finfo->name,client_get_fileselection(),false)) {
+ DEBUG(3,("mask_match %s failed\n", finfo->name));
+ return false;
+ }
+
+ if (newer_than && finfo->mtime_ts.tv_sec < newer_than) {
+ DEBUG(3,("newer_than %s failed\n", finfo->name));
+ return false;
+ }
+
+ if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH)) {
+ DEBUG(3,("archive %s failed\n", finfo->name));
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************************
+ Display info about a file.
+****************************************************************************/
+
+static void display_finfo(file_info *finfo, const char *dir)
+{
+ time_t t;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if (!do_this_one(finfo)) {
+ return;
+ }
+
+ t = finfo->mtime_ts.tv_sec; /* the time is assumed to be passed as GMT */
+ if (!showacls) {
+ d_printf(" %-30s%7.7s %8.0f %s",
+ finfo->name,
+ attrib_string(finfo->mode),
+ (double)finfo->size,
+ time_to_asc(t));
+ dir_total += finfo->size;
+ } else {
+ char *afname = NULL;
+ int fnum;
+
+ /* skip if this is . or .. */
+ if ( strequal(finfo->name,"..") || strequal(finfo->name,".") )
+ return;
+ /* create absolute filename for cli_nt_create() FIXME */
+ afname = talloc_asprintf(ctx,
+ "%s%s%s",
+ dir,
+ CLI_DIRSEP_STR,
+ finfo->name);
+ if (!afname) {
+ return;
+ }
+ /* print file meta date header */
+ d_printf( "FILENAME:%s\n", finfo->name);
+ d_printf( "MODE:%s\n", attrib_string(finfo->mode));
+ d_printf( "SIZE:%.0f\n", (double)finfo->size);
+ d_printf( "MTIME:%s", time_to_asc(t));
+ fnum = cli_nt_create(finfo->cli, afname, CREATE_ACCESS_READ);
+ if (fnum == -1) {
+ DEBUG( 0, ("display_finfo() Failed to open %s: %s\n",
+ afname,
+ cli_errstr( finfo->cli)));
+ } else {
+ SEC_DESC *sd = NULL;
+ sd = cli_query_secdesc(finfo->cli, fnum, ctx);
+ if (!sd) {
+ DEBUG( 0, ("display_finfo() failed to "
+ "get security descriptor: %s",
+ cli_errstr( finfo->cli)));
+ } else {
+ display_sec_desc(sd);
+ }
+ TALLOC_FREE(sd);
+ }
+ TALLOC_FREE(afname);
+ }
+}
+
+/****************************************************************************
+ Accumulate size of a file.
+****************************************************************************/
+
+static void do_du(file_info *finfo, const char *dir)
+{
+ if (do_this_one(finfo)) {
+ dir_total += finfo->size;
+ }
+}
+
+static bool do_list_recurse;
+static bool do_list_dirs;
+static char *do_list_queue = 0;
+static long do_list_queue_size = 0;
+static long do_list_queue_start = 0;
+static long do_list_queue_end = 0;
+static void (*do_list_fn)(file_info *, const char *dir);
+
+/****************************************************************************
+ Functions for do_list_queue.
+****************************************************************************/
+
+/*
+ * The do_list_queue is a NUL-separated list of strings stored in a
+ * char*. Since this is a FIFO, we keep track of the beginning and
+ * ending locations of the data in the queue. When we overflow, we
+ * double the size of the char*. When the start of the data passes
+ * the midpoint, we move everything back. This is logically more
+ * complex than a linked list, but easier from a memory management
+ * angle. In any memory error condition, do_list_queue is reset.
+ * Functions check to ensure that do_list_queue is non-NULL before
+ * accessing it.
+ */
+
+static void reset_do_list_queue(void)
+{
+ SAFE_FREE(do_list_queue);
+ do_list_queue_size = 0;
+ do_list_queue_start = 0;
+ do_list_queue_end = 0;
+}
+
+static void init_do_list_queue(void)
+{
+ reset_do_list_queue();
+ do_list_queue_size = 1024;
+ do_list_queue = (char *)SMB_MALLOC(do_list_queue_size);
+ if (do_list_queue == 0) {
+ d_printf("malloc fail for size %d\n",
+ (int)do_list_queue_size);
+ reset_do_list_queue();
+ } else {
+ memset(do_list_queue, 0, do_list_queue_size);
+ }
+}
+
+static void adjust_do_list_queue(void)
+{
+ /*
+ * If the starting point of the queue is more than half way through,
+ * move everything toward the beginning.
+ */
+
+ if (do_list_queue == NULL) {
+ DEBUG(4,("do_list_queue is empty\n"));
+ do_list_queue_start = do_list_queue_end = 0;
+ return;
+ }
+
+ if (do_list_queue_start == do_list_queue_end) {
+ DEBUG(4,("do_list_queue is empty\n"));
+ do_list_queue_start = do_list_queue_end = 0;
+ *do_list_queue = '\0';
+ } else if (do_list_queue_start > (do_list_queue_size / 2)) {
+ DEBUG(4,("sliding do_list_queue backward\n"));
+ memmove(do_list_queue,
+ do_list_queue + do_list_queue_start,
+ do_list_queue_end - do_list_queue_start);
+ do_list_queue_end -= do_list_queue_start;
+ do_list_queue_start = 0;
+ }
+}
+
+static void add_to_do_list_queue(const char *entry)
+{
+ long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
+ while (new_end > do_list_queue_size) {
+ do_list_queue_size *= 2;
+ DEBUG(4,("enlarging do_list_queue to %d\n",
+ (int)do_list_queue_size));
+ do_list_queue = (char *)SMB_REALLOC(do_list_queue, do_list_queue_size);
+ if (! do_list_queue) {
+ d_printf("failure enlarging do_list_queue to %d bytes\n",
+ (int)do_list_queue_size);
+ reset_do_list_queue();
+ } else {
+ memset(do_list_queue + do_list_queue_size / 2,
+ 0, do_list_queue_size / 2);
+ }
+ }
+ if (do_list_queue) {
+ safe_strcpy_base(do_list_queue + do_list_queue_end,
+ entry, do_list_queue, do_list_queue_size);
+ do_list_queue_end = new_end;
+ DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
+ entry, (int)do_list_queue_start, (int)do_list_queue_end));
+ }
+}
+
+static char *do_list_queue_head(void)
+{
+ return do_list_queue + do_list_queue_start;
+}
+
+static void remove_do_list_queue_head(void)
+{
+ if (do_list_queue_end > do_list_queue_start) {
+ do_list_queue_start += strlen(do_list_queue_head()) + 1;
+ adjust_do_list_queue();
+ DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
+ (int)do_list_queue_start, (int)do_list_queue_end));
+ }
+}
+
+static int do_list_queue_empty(void)
+{
+ return (! (do_list_queue && *do_list_queue));
+}
+
+/****************************************************************************
+ A helper for do_list.
+****************************************************************************/
+
+static void do_list_helper(const char *mntpoint, file_info *f, const char *mask, void *state)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *dir = NULL;
+ char *dir_end = NULL;
+
+ /* Work out the directory. */
+ dir = talloc_strdup(ctx, mask);
+ if (!dir) {
+ return;
+ }
+ if ((dir_end = strrchr(dir, CLI_DIRSEP_CHAR)) != NULL) {
+ *dir_end = '\0';
+ }
+
+ if (f->mode & aDIR) {
+ if (do_list_dirs && do_this_one(f)) {
+ do_list_fn(f, dir);
+ }
+ if (do_list_recurse &&
+ f->name &&
+ !strequal(f->name,".") &&
+ !strequal(f->name,"..")) {
+ char *mask2 = NULL;
+ char *p = NULL;
+
+ if (!f->name[0]) {
+ d_printf("Empty dir name returned. Possible server misconfiguration.\n");
+ TALLOC_FREE(dir);
+ return;
+ }
+
+ mask2 = talloc_asprintf(ctx,
+ "%s%s",
+ mntpoint,
+ mask);
+ if (!mask2) {
+ TALLOC_FREE(dir);
+ return;
+ }
+ p = strrchr_m(mask2,CLI_DIRSEP_CHAR);
+ if (!p) {
+ TALLOC_FREE(dir);
+ return;
+ }
+ p[1] = 0;
+ mask2 = talloc_asprintf_append(mask2,
+ "%s%s*",
+ f->name,
+ CLI_DIRSEP_STR);
+ if (!mask2) {
+ TALLOC_FREE(dir);
+ return;
+ }
+ add_to_do_list_queue(mask2);
+ TALLOC_FREE(mask2);
+ }
+ TALLOC_FREE(dir);
+ return;
+ }
+
+ if (do_this_one(f)) {
+ do_list_fn(f,dir);
+ }
+ TALLOC_FREE(dir);
+}
+
+/****************************************************************************
+ A wrapper around cli_list that adds recursion.
+****************************************************************************/
+
+void do_list(const char *mask,
+ uint16 attribute,
+ void (*fn)(file_info *, const char *dir),
+ bool rec,
+ bool dirs)
+{
+ static int in_do_list = 0;
+ TALLOC_CTX *ctx = talloc_tos();
+ struct cli_state *targetcli = NULL;
+ char *targetpath = NULL;
+
+ if (in_do_list && rec) {
+ fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
+ exit(1);
+ }
+
+ in_do_list = 1;
+
+ do_list_recurse = rec;
+ do_list_dirs = dirs;
+ do_list_fn = fn;
+
+ if (rec) {
+ init_do_list_queue();
+ add_to_do_list_queue(mask);
+
+ while (!do_list_queue_empty()) {
+ /*
+ * Need to copy head so that it doesn't become
+ * invalid inside the call to cli_list. This
+ * would happen if the list were expanded
+ * during the call.
+ * Fix from E. Jay Berkenbilt (ejb@ql.org)
+ */
+ char *head = talloc_strdup(ctx, do_list_queue_head());
+
+ if (!head) {
+ return;
+ }
+
+ /* check for dfs */
+
+ if ( !cli_resolve_path(ctx, "", cli, head, &targetcli, &targetpath ) ) {
+ d_printf("do_list: [%s] %s\n", head, cli_errstr(cli));
+ remove_do_list_queue_head();
+ continue;
+ }
+
+ cli_list(targetcli, targetpath, attribute, do_list_helper, NULL);
+ remove_do_list_queue_head();
+ if ((! do_list_queue_empty()) && (fn == display_finfo)) {
+ char *next_file = do_list_queue_head();
+ char *save_ch = 0;
+ if ((strlen(next_file) >= 2) &&
+ (next_file[strlen(next_file) - 1] == '*') &&
+ (next_file[strlen(next_file) - 2] == CLI_DIRSEP_CHAR)) {
+ save_ch = next_file +
+ strlen(next_file) - 2;
+ *save_ch = '\0';
+ if (showacls) {
+ /* cwd is only used if showacls is on */
+ client_set_cwd(next_file);
+ }
+ }
+ if (!showacls) /* don't disturbe the showacls output */
+ d_printf("\n%s\n",next_file);
+ if (save_ch) {
+ *save_ch = CLI_DIRSEP_CHAR;
+ }
+ }
+ TALLOC_FREE(head);
+ TALLOC_FREE(targetpath);
+ }
+ } else {
+ /* check for dfs */
+ if (cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetpath)) {
+ if (cli_list(targetcli, targetpath, attribute, do_list_helper, NULL) == -1) {
+ d_printf("%s listing %s\n",
+ cli_errstr(targetcli), targetpath);
+ }
+ TALLOC_FREE(targetpath);
+ } else {
+ d_printf("do_list: [%s] %s\n", mask, cli_errstr(cli));
+ }
+ }
+
+ in_do_list = 0;
+ reset_do_list_queue();
+}
+
+/****************************************************************************
+ Get a directory listing.
+****************************************************************************/
+
+static int cmd_dir(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
+ char *mask = NULL;
+ char *buf = NULL;
+ int rc = 1;
+
+ dir_total = 0;
+ mask = talloc_strdup(ctx, client_get_cur_dir());
+ if (!mask) {
+ return 1;
+ }
+
+ if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ normalize_name(buf);
+ if (*buf == CLI_DIRSEP_CHAR) {
+ mask = talloc_strdup(ctx, buf);
+ } else {
+ mask = talloc_asprintf_append(mask, buf);
+ }
+ } else {
+ mask = talloc_asprintf_append(mask, "*");
+ }
+ if (!mask) {
+ return 1;
+ }
+
+ if (showacls) {
+ /* cwd is only used if showacls is on */
+ client_set_cwd(client_get_cur_dir());
+ }
+
+ do_list(mask, attribute, display_finfo, recurse, true);
+
+ rc = do_dskattr();
+
+ DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
+
+ return rc;
+}
+
+/****************************************************************************
+ Get a directory listing.
+****************************************************************************/
+
+static int cmd_du(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
+ char *mask = NULL;
+ char *buf = NULL;
+ int rc = 1;
+
+ dir_total = 0;
+ mask = talloc_strdup(ctx, client_get_cur_dir());
+ if (!mask) {
+ return 1;
+ }
+ if ((mask[0] != '\0') && (mask[strlen(mask)-1]!=CLI_DIRSEP_CHAR)) {
+ mask = talloc_asprintf_append(mask, CLI_DIRSEP_STR);
+ if (!mask) {
+ return 1;
+ }
+ }
+
+ if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ normalize_name(buf);
+ if (*buf == CLI_DIRSEP_CHAR) {
+ mask = talloc_strdup(ctx, buf);
+ } else {
+ mask = talloc_asprintf_append(mask, buf);
+ }
+ } else {
+ mask = talloc_strdup(ctx, "*");
+ }
+
+ do_list(mask, attribute, do_du, recurse, true);
+
+ rc = do_dskattr();
+
+ d_printf("Total number of bytes: %.0f\n", dir_total);
+
+ return rc;
+}
+
+static int cmd_echo(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *num;
+ char *data;
+ NTSTATUS status;
+
+ if (!next_token_talloc(ctx, &cmd_ptr, &num, NULL)
+ || !next_token_talloc(ctx, &cmd_ptr, &data, NULL)) {
+ d_printf("echo <num> <data>\n");
+ return 1;
+ }
+
+ status = cli_echo(cli, atoi(num), data_blob_const(data, strlen(data)));
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("echo failed: %s\n", nt_errstr(status));
+ return 1;
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Get a file from rname to lname
+****************************************************************************/
+
+static NTSTATUS writefile_sink(char *buf, size_t n, void *priv)
+{
+ int *pfd = (int *)priv;
+ if (writefile(*pfd, buf, n) == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+ return NT_STATUS_OK;
+}
+
+static int do_get(const char *rname, const char *lname_in, bool reget)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ int handle = 0, fnum;
+ bool newhandle = false;
+ struct timeval tp_start;
+ uint16 attr;
+ SMB_OFF_T size;
+ off_t start = 0;
+ SMB_OFF_T nread = 0;
+ int rc = 0;
+ struct cli_state *targetcli = NULL;
+ char *targetname = NULL;
+ char *lname = NULL;
+ NTSTATUS status;
+
+ lname = talloc_strdup(ctx, lname_in);
+ if (!lname) {
+ return 1;
+ }
+
+ if (lowercase) {
+ strlower_m(lname);
+ }
+
+ if (!cli_resolve_path(ctx, "", cli, rname, &targetcli, &targetname ) ) {
+ d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
+ return 1;
+ }
+
+ GetTimeOfDay(&tp_start);
+
+ fnum = cli_open(targetcli, targetname, O_RDONLY, DENY_NONE);
+
+ if (fnum == -1) {
+ d_printf("%s opening remote file %s\n",cli_errstr(cli),rname);
+ return 1;
+ }
+
+ if(!strcmp(lname,"-")) {
+ handle = fileno(stdout);
+ } else {
+ if (reget) {
+ handle = sys_open(lname, O_WRONLY|O_CREAT, 0644);
+ if (handle >= 0) {
+ start = sys_lseek(handle, 0, SEEK_END);
+ if (start == -1) {
+ d_printf("Error seeking local file\n");
+ return 1;
+ }
+ }
+ } else {
+ handle = sys_open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ }
+ newhandle = true;
+ }
+ if (handle < 0) {
+ d_printf("Error opening local file %s\n",lname);
+ return 1;
+ }
+
+
+ if (!cli_qfileinfo(targetcli, fnum,
+ &attr, &size, NULL, NULL, NULL, NULL, NULL) &&
+ !cli_getattrE(targetcli, fnum,
+ &attr, &size, NULL, NULL, NULL)) {
+ d_printf("getattrib: %s\n",cli_errstr(targetcli));
+ return 1;
+ }
+
+ DEBUG(1,("getting file %s of size %.0f as %s ",
+ rname, (double)size, lname));
+
+ status = cli_pull(targetcli, fnum, start, size, io_bufsize,
+ writefile_sink, (void *)&handle, &nread);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "parallel_read returned %s\n",
+ nt_errstr(status));
+ cli_close(targetcli, fnum);
+ return 1;
+ }
+
+ if (!cli_close(targetcli, fnum)) {
+ d_printf("Error %s closing remote file\n",cli_errstr(cli));
+ rc = 1;
+ }
+
+ if (newhandle) {
+ close(handle);
+ }
+
+ if (archive_level >= 2 && (attr & aARCH)) {
+ cli_setatr(cli, rname, attr & ~(uint16)aARCH, 0);
+ }
+
+ {
+ struct timeval tp_end;
+ int this_time;
+
+ GetTimeOfDay(&tp_end);
+ this_time =
+ (tp_end.tv_sec - tp_start.tv_sec)*1000 +
+ (tp_end.tv_usec - tp_start.tv_usec)/1000;
+ get_total_time_ms += this_time;
+ get_total_size += nread;
+
+ DEBUG(1,("(%3.1f KiloBytes/sec) (average %3.1f KiloBytes/sec)\n",
+ nread / (1.024*this_time + 1.0e-4),
+ get_total_size / (1.024*get_total_time_ms)));
+ }
+
+ TALLOC_FREE(targetname);
+ return rc;
+}
+
+/****************************************************************************
+ Get a file.
+****************************************************************************/
+
+static int cmd_get(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *lname = NULL;
+ char *rname = NULL;
+ char *fname = NULL;
+
+ rname = talloc_strdup(ctx, client_get_cur_dir());
+ if (!rname) {
+ return 1;
+ }
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
+ d_printf("get <filename> [localname]\n");
+ return 1;
+ }
+ rname = talloc_asprintf_append(rname, fname);
+ if (!rname) {
+ return 1;
+ }
+ rname = clean_name(ctx, rname);
+ if (!rname) {
+ return 1;
+ }
+
+ next_token_talloc(ctx, &cmd_ptr,&lname,NULL);
+ if (!lname) {
+ lname = fname;
+ }
+
+ return do_get(rname, lname, false);
+}
+
+/****************************************************************************
+ Do an mget operation on one file.
+****************************************************************************/
+
+static void do_mget(file_info *finfo, const char *dir)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *rname = NULL;
+ char *quest = NULL;
+ char *saved_curdir = NULL;
+ char *mget_mask = NULL;
+ char *new_cd = NULL;
+
+ if (!finfo->name) {
+ return;
+ }
+
+ if (strequal(finfo->name,".") || strequal(finfo->name,".."))
+ return;
+
+ if (abort_mget) {
+ d_printf("mget aborted\n");
+ return;
+ }
+
+ if (finfo->mode & aDIR) {
+ if (asprintf(&quest,
+ "Get directory %s? ",finfo->name) < 0) {
+ return;
+ }
+ } else {
+ if (asprintf(&quest,
+ "Get file %s? ",finfo->name) < 0) {
+ return;
+ }
+ }
+
+ if (prompt && !yesno(quest)) {
+ SAFE_FREE(quest);
+ return;
+ }
+ SAFE_FREE(quest);
+
+ if (!(finfo->mode & aDIR)) {
+ rname = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ finfo->name);
+ if (!rname) {
+ return;
+ }
+ do_get(rname, finfo->name, false);
+ TALLOC_FREE(rname);
+ return;
+ }
+
+ /* handle directories */
+ saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
+ if (!saved_curdir) {
+ return;
+ }
+
+ new_cd = talloc_asprintf(ctx,
+ "%s%s%s",
+ client_get_cur_dir(),
+ finfo->name,
+ CLI_DIRSEP_STR);
+ if (!new_cd) {
+ return;
+ }
+ client_set_cur_dir(new_cd);
+
+ string_replace(finfo->name,'\\','/');
+ if (lowercase) {
+ strlower_m(finfo->name);
+ }
+
+ if (!directory_exist(finfo->name,NULL) &&
+ mkdir(finfo->name,0777) != 0) {
+ d_printf("failed to create directory %s\n",finfo->name);
+ client_set_cur_dir(saved_curdir);
+ return;
+ }
+
+ if (chdir(finfo->name) != 0) {
+ d_printf("failed to chdir to directory %s\n",finfo->name);
+ client_set_cur_dir(saved_curdir);
+ return;
+ }
+
+ mget_mask = talloc_asprintf(ctx,
+ "%s*",
+ client_get_cur_dir());
+
+ if (!mget_mask) {
+ return;
+ }
+
+ do_list(mget_mask, aSYSTEM | aHIDDEN | aDIR,do_mget,false, true);
+ chdir("..");
+ client_set_cur_dir(saved_curdir);
+ TALLOC_FREE(mget_mask);
+ TALLOC_FREE(saved_curdir);
+ TALLOC_FREE(new_cd);
+}
+
+/****************************************************************************
+ View the file using the pager.
+****************************************************************************/
+
+static int cmd_more(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *rname = NULL;
+ char *fname = NULL;
+ char *lname = NULL;
+ char *pager_cmd = NULL;
+ const char *pager;
+ int fd;
+ int rc = 0;
+
+ rname = talloc_strdup(ctx, client_get_cur_dir());
+ if (!rname) {
+ return 1;
+ }
+
+ lname = talloc_asprintf(ctx, "%s/smbmore.XXXXXX",tmpdir());
+ if (!lname) {
+ return 1;
+ }
+ fd = smb_mkstemp(lname);
+ if (fd == -1) {
+ d_printf("failed to create temporary file for more\n");
+ return 1;
+ }
+ close(fd);
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
+ d_printf("more <filename>\n");
+ unlink(lname);
+ return 1;
+ }
+ rname = talloc_asprintf_append(rname, fname);
+ if (!rname) {
+ return 1;
+ }
+ rname = clean_name(ctx,rname);
+ if (!rname) {
+ return 1;
+ }
+
+ rc = do_get(rname, lname, false);
+
+ pager=getenv("PAGER");
+
+ pager_cmd = talloc_asprintf(ctx,
+ "%s %s",
+ (pager? pager:PAGER),
+ lname);
+ if (!pager_cmd) {
+ return 1;
+ }
+ system(pager_cmd);
+ unlink(lname);
+
+ return rc;
+}
+
+/****************************************************************************
+ Do a mget command.
+****************************************************************************/
+
+static int cmd_mget(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ uint16 attribute = aSYSTEM | aHIDDEN;
+ char *mget_mask = NULL;
+ char *buf = NULL;
+
+ if (recurse) {
+ attribute |= aDIR;
+ }
+
+ abort_mget = false;
+
+ while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ mget_mask = talloc_strdup(ctx, client_get_cur_dir());
+ if (!mget_mask) {
+ return 1;
+ }
+ if (*buf == CLI_DIRSEP_CHAR) {
+ mget_mask = talloc_strdup(ctx, buf);
+ } else {
+ mget_mask = talloc_asprintf_append(mget_mask,
+ buf);
+ }
+ if (!mget_mask) {
+ return 1;
+ }
+ do_list(mget_mask, attribute, do_mget, false, true);
+ }
+
+ if (!*mget_mask) {
+ mget_mask = talloc_asprintf(ctx,
+ "%s*",
+ client_get_cur_dir());
+ if (!mget_mask) {
+ return 1;
+ }
+ do_list(mget_mask, attribute, do_mget, false, true);
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Make a directory of name "name".
+****************************************************************************/
+
+static bool do_mkdir(const char *name)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ struct cli_state *targetcli;
+ char *targetname = NULL;
+
+ if (!cli_resolve_path(ctx, "", cli, name, &targetcli, &targetname)) {
+ d_printf("mkdir %s: %s\n", name, cli_errstr(cli));
+ return false;
+ }
+
+ if (!cli_mkdir(targetcli, targetname)) {
+ d_printf("%s making remote directory %s\n",
+ cli_errstr(targetcli),name);
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************************
+ Show 8.3 name of a file.
+****************************************************************************/
+
+static bool do_altname(const char *name)
+{
+ fstring altname;
+
+ if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
+ d_printf("%s getting alt name for %s\n",
+ cli_errstr(cli),name);
+ return false;
+ }
+ d_printf("%s\n", altname);
+
+ return true;
+}
+
+/****************************************************************************
+ Exit client.
+****************************************************************************/
+
+static int cmd_quit(void)
+{
+ cli_cm_shutdown();
+ exit(0);
+ /* NOTREACHED */
+ return 0;
+}
+
+/****************************************************************************
+ Make a directory.
+****************************************************************************/
+
+static int cmd_mkdir(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *mask = NULL;
+ char *buf = NULL;
+
+ mask = talloc_strdup(ctx, client_get_cur_dir());
+ if (!mask) {
+ return 1;
+ }
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ if (!recurse) {
+ d_printf("mkdir <dirname>\n");
+ }
+ return 1;
+ }
+ mask = talloc_asprintf_append(mask, buf);
+ if (!mask) {
+ return 1;
+ }
+
+ if (recurse) {
+ char *ddir = NULL;
+ char *ddir2 = NULL;
+ struct cli_state *targetcli;
+ char *targetname = NULL;
+ char *p = NULL;
+ char *saveptr;
+
+ ddir2 = talloc_strdup(ctx, "");
+ if (!ddir2) {
+ return 1;
+ }
+
+ if (!cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetname)) {
+ return 1;
+ }
+
+ ddir = talloc_strdup(ctx, targetname);
+ if (!ddir) {
+ return 1;
+ }
+ trim_char(ddir,'.','\0');
+ p = strtok_r(ddir, "/\\", &saveptr);
+ while (p) {
+ ddir2 = talloc_asprintf_append(ddir2, p);
+ if (!ddir2) {
+ return 1;
+ }
+ if (!cli_chkpath(targetcli, ddir2)) {
+ do_mkdir(ddir2);
+ }
+ ddir2 = talloc_asprintf_append(ddir2, CLI_DIRSEP_STR);
+ if (!ddir2) {
+ return 1;
+ }
+ p = strtok_r(NULL, "/\\", &saveptr);
+ }
+ } else {
+ do_mkdir(mask);
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Show alt name.
+****************************************************************************/
+
+static int cmd_altname(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *name;
+ char *buf;
+
+ name = talloc_strdup(ctx, client_get_cur_dir());
+ if (!name) {
+ return 1;
+ }
+
+ if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
+ d_printf("altname <file>\n");
+ return 1;
+ }
+ name = talloc_asprintf_append(name, buf);
+ if (!name) {
+ return 1;
+ }
+ do_altname(name);
+ return 0;
+}
+
+/****************************************************************************
+ Show all info we can get
+****************************************************************************/
+
+static int do_allinfo(const char *name)
+{
+ fstring altname;
+ struct timespec b_time, a_time, m_time, c_time;
+ SMB_OFF_T size;
+ uint16_t mode;
+ SMB_INO_T ino;
+ NTTIME tmp;
+ unsigned int num_streams;
+ struct stream_struct *streams;
+ unsigned int i;
+
+ if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
+ d_printf("%s getting alt name for %s\n",
+ cli_errstr(cli),name);
+ return false;
+ }
+ d_printf("altname: %s\n", altname);
+
+ if (!cli_qpathinfo2(cli, name, &b_time, &a_time, &m_time, &c_time,
+ &size, &mode, &ino)) {
+ d_printf("%s getting pathinfo for %s\n",
+ cli_errstr(cli),name);
+ return false;
+ }
+
+ unix_timespec_to_nt_time(&tmp, b_time);
+ d_printf("create_time: %s\n", nt_time_string(talloc_tos(), tmp));
+
+ unix_timespec_to_nt_time(&tmp, a_time);
+ d_printf("access_time: %s\n", nt_time_string(talloc_tos(), tmp));
+
+ unix_timespec_to_nt_time(&tmp, m_time);
+ d_printf("write_time: %s\n", nt_time_string(talloc_tos(), tmp));
+
+ unix_timespec_to_nt_time(&tmp, c_time);
+ d_printf("change_time: %s\n", nt_time_string(talloc_tos(), tmp));
+
+ if (!cli_qpathinfo_streams(cli, name, talloc_tos(), &num_streams,
+ &streams)) {
+ d_printf("%s getting streams for %s\n",
+ cli_errstr(cli),name);
+ return false;
+ }
+
+ for (i=0; i<num_streams; i++) {
+ d_printf("stream: [%s], %lld bytes\n", streams[i].name,
+ (unsigned long long)streams[i].size);
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Show all info we can get
+****************************************************************************/
+
+static int cmd_allinfo(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *name;
+ char *buf;
+
+ name = talloc_strdup(ctx, client_get_cur_dir());
+ if (!name) {
+ return 1;
+ }
+
+ if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
+ d_printf("allinfo <file>\n");
+ return 1;
+ }
+ name = talloc_asprintf_append(name, buf);
+ if (!name) {
+ return 1;
+ }
+
+ do_allinfo(name);
+
+ return 0;
+}
+
+/****************************************************************************
+ Put a single file.
+****************************************************************************/
+
+static int do_put(const char *rname, const char *lname, bool reput)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ int fnum;
+ XFILE *f;
+ SMB_OFF_T start = 0;
+ off_t nread = 0;
+ char *buf = NULL;
+ int maxwrite = io_bufsize;
+ int rc = 0;
+ struct timeval tp_start;
+ struct cli_state *targetcli;
+ char *targetname = NULL;
+
+ if (!cli_resolve_path(ctx, "", cli, rname, &targetcli, &targetname)) {
+ d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
+ return 1;
+ }
+
+ GetTimeOfDay(&tp_start);
+
+ if (reput) {
+ fnum = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum >= 0) {
+ if (!cli_qfileinfo(targetcli, fnum, NULL, &start, NULL, NULL, NULL, NULL, NULL) &&
+ !cli_getattrE(targetcli, fnum, NULL, &start, NULL, NULL, NULL)) {
+ d_printf("getattrib: %s\n",cli_errstr(cli));
+ return 1;
+ }
+ }
+ } else {
+ fnum = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
+ }
+
+ if (fnum == -1) {
+ d_printf("%s opening remote file %s\n",cli_errstr(targetcli),rname);
+ return 1;
+ }
+
+ /* allow files to be piped into smbclient
+ jdblair 24.jun.98
+
+ Note that in this case this function will exit(0) rather
+ than returning. */
+ if (!strcmp(lname, "-")) {
+ f = x_stdin;
+ /* size of file is not known */
+ } else {
+ f = x_fopen(lname,O_RDONLY, 0);
+ if (f && reput) {
+ if (x_tseek(f, start, SEEK_SET) == -1) {
+ d_printf("Error seeking local file\n");
+ return 1;
+ }
+ }
+ }
+
+ if (!f) {
+ d_printf("Error opening local file %s\n",lname);
+ return 1;
+ }
+
+ DEBUG(1,("putting file %s as %s ",lname,
+ rname));
+
+ buf = (char *)SMB_MALLOC(maxwrite);
+ if (!buf) {
+ d_printf("ERROR: Not enough memory!\n");
+ return 1;
+ }
+ while (!x_feof(f)) {
+ int n = maxwrite;
+ int ret;
+
+ if ((n = readfile(buf,n,f)) < 1) {
+ if((n == 0) && x_feof(f))
+ break; /* Empty local file. */
+
+ d_printf("Error reading local file: %s\n", strerror(errno));
+ rc = 1;
+ break;
+ }
+
+ ret = cli_write(targetcli, fnum, 0, buf, nread + start, n);
+
+ if (n != ret) {
+ d_printf("Error writing file: %s\n", cli_errstr(cli));
+ rc = 1;
+ break;
+ }
+
+ nread += n;
+ }
+
+ if (!cli_close(targetcli, fnum)) {
+ d_printf("%s closing remote file %s\n",cli_errstr(cli),rname);
+ x_fclose(f);
+ SAFE_FREE(buf);
+ return 1;
+ }
+
+ if (f != x_stdin) {
+ x_fclose(f);
+ }
+
+ SAFE_FREE(buf);
+
+ {
+ struct timeval tp_end;
+ int this_time;
+
+ GetTimeOfDay(&tp_end);
+ this_time =
+ (tp_end.tv_sec - tp_start.tv_sec)*1000 +
+ (tp_end.tv_usec - tp_start.tv_usec)/1000;
+ put_total_time_ms += this_time;
+ put_total_size += nread;
+
+ DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
+ nread / (1.024*this_time + 1.0e-4),
+ put_total_size / (1.024*put_total_time_ms)));
+ }
+
+ if (f == x_stdin) {
+ cli_cm_shutdown();
+ exit(0);
+ }
+
+ return rc;
+}
+
+/****************************************************************************
+ Put a file.
+****************************************************************************/
+
+static int cmd_put(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *lname;
+ char *rname;
+ char *buf;
+
+ rname = talloc_strdup(ctx, client_get_cur_dir());
+ if (!rname) {
+ return 1;
+ }
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&lname,NULL)) {
+ d_printf("put <filename>\n");
+ return 1;
+ }
+
+ if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ rname = talloc_asprintf_append(rname, buf);
+ } else {
+ rname = talloc_asprintf_append(rname, lname);
+ }
+ if (!rname) {
+ return 1;
+ }
+
+ rname = clean_name(ctx, rname);
+ if (!rname) {
+ return 1;
+ }
+
+ {
+ SMB_STRUCT_STAT st;
+ /* allow '-' to represent stdin
+ jdblair, 24.jun.98 */
+ if (!file_exist(lname,&st) &&
+ (strcmp(lname,"-"))) {
+ d_printf("%s does not exist\n",lname);
+ return 1;
+ }
+ }
+
+ return do_put(rname, lname, false);
+}
+
+/*************************************
+ File list structure.
+*************************************/
+
+static struct file_list {
+ struct file_list *prev, *next;
+ char *file_path;
+ bool isdir;
+} *file_list;
+
+/****************************************************************************
+ Free a file_list structure.
+****************************************************************************/
+
+static void free_file_list (struct file_list *list_head)
+{
+ struct file_list *list, *next;
+
+ for (list = list_head; list; list = next) {
+ next = list->next;
+ DLIST_REMOVE(list_head, list);
+ SAFE_FREE(list->file_path);
+ SAFE_FREE(list);
+ }
+}
+
+/****************************************************************************
+ Seek in a directory/file list until you get something that doesn't start with
+ the specified name.
+****************************************************************************/
+
+static bool seek_list(struct file_list *list, char *name)
+{
+ while (list) {
+ trim_string(list->file_path,"./","\n");
+ if (strncmp(list->file_path, name, strlen(name)) != 0) {
+ return true;
+ }
+ list = list->next;
+ }
+
+ return false;
+}
+
+/****************************************************************************
+ Set the file selection mask.
+****************************************************************************/
+
+static int cmd_select(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *new_fs = NULL;
+ next_token_talloc(ctx, &cmd_ptr,&new_fs,NULL)
+ ;
+ if (new_fs) {
+ client_set_fileselection(new_fs);
+ } else {
+ client_set_fileselection("");
+ }
+ return 0;
+}
+
+/****************************************************************************
+ Recursive file matching function act as find
+ match must be always set to true when calling this function
+****************************************************************************/
+
+static int file_find(struct file_list **list, const char *directory,
+ const char *expression, bool match)
+{
+ SMB_STRUCT_DIR *dir;
+ struct file_list *entry;
+ struct stat statbuf;
+ int ret;
+ char *path;
+ bool isdir;
+ const char *dname;
+
+ dir = sys_opendir(directory);
+ if (!dir)
+ return -1;
+
+ while ((dname = readdirname(dir))) {
+ if (!strcmp("..", dname))
+ continue;
+ if (!strcmp(".", dname))
+ continue;
+
+ if (asprintf(&path, "%s/%s", directory, dname) <= 0) {
+ continue;
+ }
+
+ isdir = false;
+ if (!match || !gen_fnmatch(expression, dname)) {
+ if (recurse) {
+ ret = stat(path, &statbuf);
+ if (ret == 0) {
+ if (S_ISDIR(statbuf.st_mode)) {
+ isdir = true;
+ ret = file_find(list, path, expression, false);
+ }
+ } else {
+ d_printf("file_find: cannot stat file %s\n", path);
+ }
+
+ if (ret == -1) {
+ SAFE_FREE(path);
+ sys_closedir(dir);
+ return -1;
+ }
+ }
+ entry = SMB_MALLOC_P(struct file_list);
+ if (!entry) {
+ d_printf("Out of memory in file_find\n");
+ sys_closedir(dir);
+ return -1;
+ }
+ entry->file_path = path;
+ entry->isdir = isdir;
+ DLIST_ADD(*list, entry);
+ } else {
+ SAFE_FREE(path);
+ }
+ }
+
+ sys_closedir(dir);
+ return 0;
+}
+
+/****************************************************************************
+ mput some files.
+****************************************************************************/
+
+static int cmd_mput(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *p = NULL;
+
+ while (next_token_talloc(ctx, &cmd_ptr,&p,NULL)) {
+ int ret;
+ struct file_list *temp_list;
+ char *quest, *lname, *rname;
+
+ file_list = NULL;
+
+ ret = file_find(&file_list, ".", p, true);
+ if (ret) {
+ free_file_list(file_list);
+ continue;
+ }
+
+ quest = NULL;
+ lname = NULL;
+ rname = NULL;
+
+ for (temp_list = file_list; temp_list;
+ temp_list = temp_list->next) {
+
+ SAFE_FREE(lname);
+ if (asprintf(&lname, "%s/", temp_list->file_path) <= 0) {
+ continue;
+ }
+ trim_string(lname, "./", "/");
+
+ /* check if it's a directory */
+ if (temp_list->isdir) {
+ /* if (!recurse) continue; */
+
+ SAFE_FREE(quest);
+ if (asprintf(&quest, "Put directory %s? ", lname) < 0) {
+ break;
+ }
+ if (prompt && !yesno(quest)) { /* No */
+ /* Skip the directory */
+ lname[strlen(lname)-1] = '/';
+ if (!seek_list(temp_list, lname))
+ break;
+ } else { /* Yes */
+ SAFE_FREE(rname);
+ if(asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
+ break;
+ }
+ normalize_name(rname);
+ if (!cli_chkpath(cli, rname) &&
+ !do_mkdir(rname)) {
+ DEBUG (0, ("Unable to make dir, skipping..."));
+ /* Skip the directory */
+ lname[strlen(lname)-1] = '/';
+ if (!seek_list(temp_list, lname)) {
+ break;
+ }
+ }
+ }
+ continue;
+ } else {
+ SAFE_FREE(quest);
+ if (asprintf(&quest,"Put file %s? ", lname) < 0) {
+ break;
+ }
+ if (prompt && !yesno(quest)) {
+ /* No */
+ continue;
+ }
+
+ /* Yes */
+ SAFE_FREE(rname);
+ if (asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
+ break;
+ }
+ }
+
+ normalize_name(rname);
+
+ do_put(rname, lname, false);
+ }
+ free_file_list(file_list);
+ SAFE_FREE(quest);
+ SAFE_FREE(lname);
+ SAFE_FREE(rname);
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Cancel a print job.
+****************************************************************************/
+
+static int do_cancel(int job)
+{
+ if (cli_printjob_del(cli, job)) {
+ d_printf("Job %d cancelled\n",job);
+ return 0;
+ } else {
+ d_printf("Error cancelling job %d : %s\n",job,cli_errstr(cli));
+ return 1;
+ }
+}
+
+/****************************************************************************
+ Cancel a print job.
+****************************************************************************/
+
+static int cmd_cancel(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *buf = NULL;
+ int job;
+
+ if (!next_token_talloc(ctx, &cmd_ptr, &buf,NULL)) {
+ d_printf("cancel <jobid> ...\n");
+ return 1;
+ }
+ do {
+ job = atoi(buf);
+ do_cancel(job);
+ } while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL));
+
+ return 0;
+}
+
+/****************************************************************************
+ Print a file.
+****************************************************************************/
+
+static int cmd_print(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *lname = NULL;
+ char *rname = NULL;
+ char *p = NULL;
+
+ if (!next_token_talloc(ctx, &cmd_ptr, &lname,NULL)) {
+ d_printf("print <filename>\n");
+ return 1;
+ }
+
+ rname = talloc_strdup(ctx, lname);
+ if (!rname) {
+ return 1;
+ }
+ p = strrchr_m(rname,'/');
+ if (p) {
+ rname = talloc_asprintf(ctx,
+ "%s-%d",
+ p+1,
+ (int)sys_getpid());
+ }
+ if (strequal(lname,"-")) {
+ rname = talloc_asprintf(ctx,
+ "stdin-%d",
+ (int)sys_getpid());
+ }
+ if (!rname) {
+ return 1;
+ }
+
+ return do_put(rname, lname, false);
+}
+
+/****************************************************************************
+ Show a print queue entry.
+****************************************************************************/
+
+static void queue_fn(struct print_job_info *p)
+{
+ d_printf("%-6d %-9d %s\n", (int)p->id, (int)p->size, p->name);
+}
+
+/****************************************************************************
+ Show a print queue.
+****************************************************************************/
+
+static int cmd_queue(void)
+{
+ cli_print_queue(cli, queue_fn);
+ return 0;
+}
+
+/****************************************************************************
+ Delete some files.
+****************************************************************************/
+
+static void do_del(file_info *finfo, const char *dir)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *mask = NULL;
+
+ mask = talloc_asprintf(ctx,
+ "%s%c%s",
+ dir,
+ CLI_DIRSEP_CHAR,
+ finfo->name);
+ if (!mask) {
+ return;
+ }
+
+ if (finfo->mode & aDIR) {
+ TALLOC_FREE(mask);
+ return;
+ }
+
+ if (!cli_unlink(finfo->cli, mask)) {
+ d_printf("%s deleting remote file %s\n",
+ cli_errstr(finfo->cli),mask);
+ }
+ TALLOC_FREE(mask);
+}
+
+/****************************************************************************
+ Delete some files.
+****************************************************************************/
+
+static int cmd_del(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *mask = NULL;
+ char *buf = NULL;
+ uint16 attribute = aSYSTEM | aHIDDEN;
+
+ if (recurse) {
+ attribute |= aDIR;
+ }
+
+ mask = talloc_strdup(ctx, client_get_cur_dir());
+ if (!mask) {
+ return 1;
+ }
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("del <filename>\n");
+ return 1;
+ }
+ mask = talloc_asprintf_append(mask, buf);
+ if (!mask) {
+ return 1;
+ }
+
+ do_list(mask,attribute,do_del,false,false);
+ return 0;
+}
+
+/****************************************************************************
+ Wildcard delete some files.
+****************************************************************************/
+
+static int cmd_wdel(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *mask = NULL;
+ char *buf = NULL;
+ uint16 attribute;
+ struct cli_state *targetcli;
+ char *targetname = NULL;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("wdel 0x<attrib> <wcard>\n");
+ return 1;
+ }
+
+ attribute = (uint16)strtol(buf, (char **)NULL, 16);
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("wdel 0x<attrib> <wcard>\n");
+ return 1;
+ }
+
+ mask = talloc_asprintf(ctx, "%s%s",
+ client_get_cur_dir(),
+ buf);
+ if (!mask) {
+ return 1;
+ }
+
+ if (!cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetname)) {
+ d_printf("cmd_wdel %s: %s\n", mask, cli_errstr(cli));
+ return 1;
+ }
+
+ if (!cli_unlink_full(targetcli, targetname, attribute)) {
+ d_printf("%s deleting remote files %s\n",cli_errstr(targetcli),targetname);
+ }
+ return 0;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static int cmd_open(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *mask = NULL;
+ char *buf = NULL;
+ char *targetname = NULL;
+ struct cli_state *targetcli;
+ int fnum;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("open <filename>\n");
+ return 1;
+ }
+ mask = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf);
+ if (!mask) {
+ return 1;
+ }
+
+ if (!cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetname)) {
+ d_printf("open %s: %s\n", mask, cli_errstr(cli));
+ return 1;
+ }
+
+ fnum = cli_nt_create(targetcli, targetname, FILE_READ_DATA|FILE_WRITE_DATA);
+ if (fnum == -1) {
+ fnum = cli_nt_create(targetcli, targetname, FILE_READ_DATA);
+ if (fnum != -1) {
+ d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
+ } else {
+ d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
+ }
+ } else {
+ d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
+ }
+ return 0;
+}
+
+static int cmd_posix_encrypt(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+ if (cli->use_kerberos) {
+ status = cli_gss_smb_encryption_start(cli);
+ } else {
+ char *domain = NULL;
+ char *user = NULL;
+ char *password = NULL;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&domain,NULL)) {
+ d_printf("posix_encrypt domain user password\n");
+ return 1;
+ }
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&user,NULL)) {
+ d_printf("posix_encrypt domain user password\n");
+ return 1;
+ }
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&password,NULL)) {
+ d_printf("posix_encrypt domain user password\n");
+ return 1;
+ }
+
+ status = cli_raw_ntlm_smb_encryption_start(cli,
+ user,
+ password,
+ domain);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("posix_encrypt failed with error %s\n", nt_errstr(status));
+ } else {
+ d_printf("encryption on\n");
+ smb_encrypt = true;
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static int cmd_posix_open(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *mask = NULL;
+ char *buf = NULL;
+ char *targetname = NULL;
+ struct cli_state *targetcli;
+ mode_t mode;
+ int fnum;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("posix_open <filename> 0<mode>\n");
+ return 1;
+ }
+ mask = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf);
+ if (!mask) {
+ return 1;
+ }
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("posix_open <filename> 0<mode>\n");
+ return 1;
+ }
+ mode = (mode_t)strtol(buf, (char **)NULL, 8);
+
+ if (!cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetname)) {
+ d_printf("posix_open %s: %s\n", mask, cli_errstr(cli));
+ return 1;
+ }
+
+ fnum = cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode);
+ if (fnum == -1) {
+ fnum = cli_posix_open(targetcli, targetname, O_CREAT|O_RDONLY, mode);
+ if (fnum != -1) {
+ d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
+ } else {
+ d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
+ }
+ } else {
+ d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
+ }
+
+ return 0;
+}
+
+static int cmd_posix_mkdir(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *mask = NULL;
+ char *buf = NULL;
+ char *targetname = NULL;
+ struct cli_state *targetcli;
+ mode_t mode;
+ int fnum;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("posix_mkdir <filename> 0<mode>\n");
+ return 1;
+ }
+ mask = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf);
+ if (!mask) {
+ return 1;
+ }
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("posix_mkdir <filename> 0<mode>\n");
+ return 1;
+ }
+ mode = (mode_t)strtol(buf, (char **)NULL, 8);
+
+ if (!cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetname)) {
+ d_printf("posix_mkdir %s: %s\n", mask, cli_errstr(cli));
+ return 1;
+ }
+
+ fnum = cli_posix_mkdir(targetcli, targetname, mode);
+ if (fnum == -1) {
+ d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
+ } else {
+ d_printf("posix_mkdir created directory %s\n", targetname);
+ }
+ return 0;
+}
+
+static int cmd_posix_unlink(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *mask = NULL;
+ char *buf = NULL;
+ char *targetname = NULL;
+ struct cli_state *targetcli;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("posix_unlink <filename>\n");
+ return 1;
+ }
+ mask = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf);
+ if (!mask) {
+ return 1;
+ }
+
+ if (!cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetname)) {
+ d_printf("posix_unlink %s: %s\n", mask, cli_errstr(cli));
+ return 1;
+ }
+
+ if (!cli_posix_unlink(targetcli, targetname)) {
+ d_printf("Failed to unlink file %s. %s\n", targetname, cli_errstr(cli));
+ } else {
+ d_printf("posix_unlink deleted file %s\n", targetname);
+ }
+
+ return 0;
+}
+
+static int cmd_posix_rmdir(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *mask = NULL;
+ char *buf = NULL;
+ char *targetname = NULL;
+ struct cli_state *targetcli;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("posix_rmdir <filename>\n");
+ return 1;
+ }
+ mask = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf);
+ if (!mask) {
+ return 1;
+ }
+
+ if (!cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetname)) {
+ d_printf("posix_rmdir %s: %s\n", mask, cli_errstr(cli));
+ return 1;
+ }
+
+ if (!cli_posix_rmdir(targetcli, targetname)) {
+ d_printf("Failed to unlink directory %s. %s\n", targetname, cli_errstr(cli));
+ } else {
+ d_printf("posix_rmdir deleted directory %s\n", targetname);
+ }
+
+ return 0;
+}
+
+static int cmd_close(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *buf = NULL;
+ int fnum;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("close <fnum>\n");
+ return 1;
+ }
+
+ fnum = atoi(buf);
+ /* We really should use the targetcli here.... */
+ if (!cli_close(cli, fnum)) {
+ d_printf("close %d: %s\n", fnum, cli_errstr(cli));
+ return 1;
+ }
+ return 0;
+}
+
+static int cmd_posix(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ uint16 major, minor;
+ uint32 caplow, caphigh;
+ char *caps;
+
+ if (!SERVER_HAS_UNIX_CIFS(cli)) {
+ d_printf("Server doesn't support UNIX CIFS extensions.\n");
+ return 1;
+ }
+
+ if (!cli_unix_extensions_version(cli, &major, &minor, &caplow, &caphigh)) {
+ d_printf("Can't get UNIX CIFS extensions version from server.\n");
+ return 1;
+ }
+
+ d_printf("Server supports CIFS extensions %u.%u\n", (unsigned int)major, (unsigned int)minor);
+
+ caps = talloc_strdup(ctx, "");
+ if (!caps) {
+ return 1;
+ }
+ if (caplow & CIFS_UNIX_FCNTL_LOCKS_CAP) {
+ caps = talloc_asprintf_append(caps, "locks ");
+ if (!caps) {
+ return 1;
+ }
+ }
+ if (caplow & CIFS_UNIX_POSIX_ACLS_CAP) {
+ caps = talloc_asprintf_append(caps, "acls ");
+ if (!caps) {
+ return 1;
+ }
+ }
+ if (caplow & CIFS_UNIX_XATTTR_CAP) {
+ caps = talloc_asprintf_append(caps, "eas ");
+ if (!caps) {
+ return 1;
+ }
+ }
+ if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+ caps = talloc_asprintf_append(caps, "pathnames ");
+ if (!caps) {
+ return 1;
+ }
+ }
+ if (caplow & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) {
+ caps = talloc_asprintf_append(caps, "posix_path_operations ");
+ if (!caps) {
+ return 1;
+ }
+ }
+ if (caplow & CIFS_UNIX_LARGE_READ_CAP) {
+ caps = talloc_asprintf_append(caps, "large_read ");
+ if (!caps) {
+ return 1;
+ }
+ }
+ if (caplow & CIFS_UNIX_LARGE_WRITE_CAP) {
+ caps = talloc_asprintf_append(caps, "large_write ");
+ if (!caps) {
+ return 1;
+ }
+ }
+ if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP) {
+ caps = talloc_asprintf_append(caps, "posix_encrypt ");
+ if (!caps) {
+ return 1;
+ }
+ }
+ if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) {
+ caps = talloc_asprintf_append(caps, "mandatory_posix_encrypt ");
+ if (!caps) {
+ return 1;
+ }
+ }
+
+ if (*caps && caps[strlen(caps)-1] == ' ') {
+ caps[strlen(caps)-1] = '\0';
+ }
+
+ d_printf("Server supports CIFS capabilities %s\n", caps);
+
+ if (!cli_set_unix_extensions_capabilities(cli, major, minor, caplow, caphigh)) {
+ d_printf("Can't set UNIX CIFS extensions capabilities. %s.\n", cli_errstr(cli));
+ return 1;
+ }
+
+ if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+ CLI_DIRSEP_CHAR = '/';
+ *CLI_DIRSEP_STR = '/';
+ client_set_cur_dir(CLI_DIRSEP_STR);
+ }
+
+ return 0;
+}
+
+static int cmd_lock(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *buf = NULL;
+ SMB_BIG_UINT start, len;
+ enum brl_type lock_type;
+ int fnum;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
+ return 1;
+ }
+ fnum = atoi(buf);
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
+ return 1;
+ }
+
+ if (*buf == 'r' || *buf == 'R') {
+ lock_type = READ_LOCK;
+ } else if (*buf == 'w' || *buf == 'W') {
+ lock_type = WRITE_LOCK;
+ } else {
+ d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
+ return 1;
+ }
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
+ return 1;
+ }
+
+ start = (SMB_BIG_UINT)strtol(buf, (char **)NULL, 16);
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
+ return 1;
+ }
+
+ len = (SMB_BIG_UINT)strtol(buf, (char **)NULL, 16);
+
+ if (!cli_posix_lock(cli, fnum, start, len, true, lock_type)) {
+ d_printf("lock failed %d: %s\n", fnum, cli_errstr(cli));
+ }
+
+ return 0;
+}
+
+static int cmd_unlock(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *buf = NULL;
+ SMB_BIG_UINT start, len;
+ int fnum;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("unlock <fnum> <hex-start> <hex-len>\n");
+ return 1;
+ }
+ fnum = atoi(buf);
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("unlock <fnum> <hex-start> <hex-len>\n");
+ return 1;
+ }
+
+ start = (SMB_BIG_UINT)strtol(buf, (char **)NULL, 16);
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("unlock <fnum> <hex-start> <hex-len>\n");
+ return 1;
+ }
+
+ len = (SMB_BIG_UINT)strtol(buf, (char **)NULL, 16);
+
+ if (!cli_posix_unlock(cli, fnum, start, len)) {
+ d_printf("unlock failed %d: %s\n", fnum, cli_errstr(cli));
+ }
+
+ return 0;
+}
+
+
+/****************************************************************************
+ Remove a directory.
+****************************************************************************/
+
+static int cmd_rmdir(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *mask = NULL;
+ char *buf = NULL;
+ char *targetname = NULL;
+ struct cli_state *targetcli;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("rmdir <dirname>\n");
+ return 1;
+ }
+ mask = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf);
+ if (!mask) {
+ return 1;
+ }
+
+ if (!cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetname)) {
+ d_printf("rmdir %s: %s\n", mask, cli_errstr(cli));
+ return 1;
+ }
+
+ if (!cli_rmdir(targetcli, targetname)) {
+ d_printf("%s removing remote directory file %s\n",
+ cli_errstr(targetcli),mask);
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ UNIX hardlink.
+****************************************************************************/
+
+static int cmd_link(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *oldname = NULL;
+ char *newname = NULL;
+ char *buf = NULL;
+ char *buf2 = NULL;
+ char *targetname = NULL;
+ struct cli_state *targetcli;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
+ !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
+ d_printf("link <oldname> <newname>\n");
+ return 1;
+ }
+ oldname = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf);
+ if (!oldname) {
+ return 1;
+ }
+ newname = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf2);
+ if (!newname) {
+ return 1;
+ }
+
+ if (!cli_resolve_path(ctx, "", cli, oldname, &targetcli, &targetname)) {
+ d_printf("link %s: %s\n", oldname, cli_errstr(cli));
+ return 1;
+ }
+
+ if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
+ d_printf("Server doesn't support UNIX CIFS calls.\n");
+ return 1;
+ }
+
+ if (!cli_unix_hardlink(targetcli, targetname, newname)) {
+ d_printf("%s linking files (%s -> %s)\n", cli_errstr(targetcli), newname, oldname);
+ return 1;
+ }
+ return 0;
+}
+
+/****************************************************************************
+ UNIX symlink.
+****************************************************************************/
+
+static int cmd_symlink(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *oldname = NULL;
+ char *newname = NULL;
+ char *buf = NULL;
+ char *buf2 = NULL;
+ char *targetname = NULL;
+ struct cli_state *targetcli;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
+ !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
+ d_printf("symlink <oldname> <newname>\n");
+ return 1;
+ }
+ oldname = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf);
+ if (!oldname) {
+ return 1;
+ }
+ newname = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf2);
+ if (!newname) {
+ return 1;
+ }
+
+ if (!cli_resolve_path(ctx, "", cli, oldname, &targetcli, &targetname)) {
+ d_printf("link %s: %s\n", oldname, cli_errstr(cli));
+ return 1;
+ }
+
+ if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
+ d_printf("Server doesn't support UNIX CIFS calls.\n");
+ return 1;
+ }
+
+ if (!cli_unix_symlink(targetcli, targetname, newname)) {
+ d_printf("%s symlinking files (%s -> %s)\n",
+ cli_errstr(targetcli), newname, targetname);
+ return 1;
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ UNIX chmod.
+****************************************************************************/
+
+static int cmd_chmod(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *src = NULL;
+ char *buf = NULL;
+ char *buf2 = NULL;
+ char *targetname = NULL;
+ struct cli_state *targetcli;
+ mode_t mode;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
+ !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
+ d_printf("chmod mode file\n");
+ return 1;
+ }
+ src = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf2);
+ if (!src) {
+ return 1;
+ }
+
+ mode = (mode_t)strtol(buf, NULL, 8);
+
+ if (!cli_resolve_path(ctx, "", cli, src, &targetcli, &targetname)) {
+ d_printf("chmod %s: %s\n", src, cli_errstr(cli));
+ return 1;
+ }
+
+ if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
+ d_printf("Server doesn't support UNIX CIFS calls.\n");
+ return 1;
+ }
+
+ if (!cli_unix_chmod(targetcli, targetname, mode)) {
+ d_printf("%s chmod file %s 0%o\n",
+ cli_errstr(targetcli), src, (unsigned int)mode);
+ return 1;
+ }
+
+ return 0;
+}
+
+static const char *filetype_to_str(mode_t mode)
+{
+ if (S_ISREG(mode)) {
+ return "regular file";
+ } else if (S_ISDIR(mode)) {
+ return "directory";
+ } else
+#ifdef S_ISCHR
+ if (S_ISCHR(mode)) {
+ return "character device";
+ } else
+#endif
+#ifdef S_ISBLK
+ if (S_ISBLK(mode)) {
+ return "block device";
+ } else
+#endif
+#ifdef S_ISFIFO
+ if (S_ISFIFO(mode)) {
+ return "fifo";
+ } else
+#endif
+#ifdef S_ISLNK
+ if (S_ISLNK(mode)) {
+ return "symbolic link";
+ } else
+#endif
+#ifdef S_ISSOCK
+ if (S_ISSOCK(mode)) {
+ return "socket";
+ } else
+#endif
+ return "";
+}
+
+static char rwx_to_str(mode_t m, mode_t bt, char ret)
+{
+ if (m & bt) {
+ return ret;
+ } else {
+ return '-';
+ }
+}
+
+static char *unix_mode_to_str(char *s, mode_t m)
+{
+ char *p = s;
+ const char *str = filetype_to_str(m);
+
+ switch(str[0]) {
+ case 'd':
+ *p++ = 'd';
+ break;
+ case 'c':
+ *p++ = 'c';
+ break;
+ case 'b':
+ *p++ = 'b';
+ break;
+ case 'f':
+ *p++ = 'p';
+ break;
+ case 's':
+ *p++ = str[1] == 'y' ? 'l' : 's';
+ break;
+ case 'r':
+ default:
+ *p++ = '-';
+ break;
+ }
+ *p++ = rwx_to_str(m, S_IRUSR, 'r');
+ *p++ = rwx_to_str(m, S_IWUSR, 'w');
+ *p++ = rwx_to_str(m, S_IXUSR, 'x');
+ *p++ = rwx_to_str(m, S_IRGRP, 'r');
+ *p++ = rwx_to_str(m, S_IWGRP, 'w');
+ *p++ = rwx_to_str(m, S_IXGRP, 'x');
+ *p++ = rwx_to_str(m, S_IROTH, 'r');
+ *p++ = rwx_to_str(m, S_IWOTH, 'w');
+ *p++ = rwx_to_str(m, S_IXOTH, 'x');
+ *p++ = '\0';
+ return s;
+}
+
+/****************************************************************************
+ Utility function for UNIX getfacl.
+****************************************************************************/
+
+static char *perms_to_string(fstring permstr, unsigned char perms)
+{
+ fstrcpy(permstr, "---");
+ if (perms & SMB_POSIX_ACL_READ) {
+ permstr[0] = 'r';
+ }
+ if (perms & SMB_POSIX_ACL_WRITE) {
+ permstr[1] = 'w';
+ }
+ if (perms & SMB_POSIX_ACL_EXECUTE) {
+ permstr[2] = 'x';
+ }
+ return permstr;
+}
+
+/****************************************************************************
+ UNIX getfacl.
+****************************************************************************/
+
+static int cmd_getfacl(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *src = NULL;
+ char *name = NULL;
+ char *targetname = NULL;
+ struct cli_state *targetcli;
+ uint16 major, minor;
+ uint32 caplow, caphigh;
+ char *retbuf = NULL;
+ size_t rb_size = 0;
+ SMB_STRUCT_STAT sbuf;
+ uint16 num_file_acls = 0;
+ uint16 num_dir_acls = 0;
+ uint16 i;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
+ d_printf("getfacl filename\n");
+ return 1;
+ }
+ src = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ name);
+ if (!src) {
+ return 1;
+ }
+
+ if (!cli_resolve_path(ctx, "", cli, src, &targetcli, &targetname)) {
+ d_printf("stat %s: %s\n", src, cli_errstr(cli));
+ return 1;
+ }
+
+ if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
+ d_printf("Server doesn't support UNIX CIFS calls.\n");
+ return 1;
+ }
+
+ if (!cli_unix_extensions_version(targetcli, &major, &minor,
+ &caplow, &caphigh)) {
+ d_printf("Can't get UNIX CIFS version from server.\n");
+ return 1;
+ }
+
+ if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) {
+ d_printf("This server supports UNIX extensions "
+ "but doesn't support POSIX ACLs.\n");
+ return 1;
+ }
+
+ if (!cli_unix_stat(targetcli, targetname, &sbuf)) {
+ d_printf("%s getfacl doing a stat on file %s\n",
+ cli_errstr(targetcli), src);
+ return 1;
+ }
+
+ if (!cli_unix_getfacl(targetcli, targetname, &rb_size, &retbuf)) {
+ d_printf("%s getfacl file %s\n",
+ cli_errstr(targetcli), src);
+ return 1;
+ }
+
+ /* ToDo : Print out the ACL values. */
+ if (SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION || rb_size < 6) {
+ d_printf("getfacl file %s, unknown POSIX acl version %u.\n",
+ src, (unsigned int)CVAL(retbuf,0) );
+ SAFE_FREE(retbuf);
+ return 1;
+ }
+
+ num_file_acls = SVAL(retbuf,2);
+ num_dir_acls = SVAL(retbuf,4);
+ if (rb_size != SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)) {
+ d_printf("getfacl file %s, incorrect POSIX acl buffer size (should be %u, was %u).\n",
+ src,
+ (unsigned int)(SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)),
+ (unsigned int)rb_size);
+
+ SAFE_FREE(retbuf);
+ return 1;
+ }
+
+ d_printf("# file: %s\n", src);
+ d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_uid, (unsigned int)sbuf.st_gid);
+
+ if (num_file_acls == 0 && num_dir_acls == 0) {
+ d_printf("No acls found.\n");
+ }
+
+ for (i = 0; i < num_file_acls; i++) {
+ uint32 uorg;
+ fstring permstring;
+ unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE));
+ unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1);
+
+ switch(tagtype) {
+ case SMB_POSIX_ACL_USER_OBJ:
+ d_printf("user::");
+ break;
+ case SMB_POSIX_ACL_USER:
+ uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
+ d_printf("user:%u:", uorg);
+ break;
+ case SMB_POSIX_ACL_GROUP_OBJ:
+ d_printf("group::");
+ break;
+ case SMB_POSIX_ACL_GROUP:
+ uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
+ d_printf("group:%u", uorg);
+ break;
+ case SMB_POSIX_ACL_MASK:
+ d_printf("mask::");
+ break;
+ case SMB_POSIX_ACL_OTHER:
+ d_printf("other::");
+ break;
+ default:
+ d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
+ src, (unsigned int)tagtype );
+ SAFE_FREE(retbuf);
+ return 1;
+ }
+
+ d_printf("%s\n", perms_to_string(permstring, perms));
+ }
+
+ for (i = 0; i < num_dir_acls; i++) {
+ uint32 uorg;
+ fstring permstring;
+ unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE));
+ unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1);
+
+ switch(tagtype) {
+ case SMB_POSIX_ACL_USER_OBJ:
+ d_printf("default:user::");
+ break;
+ case SMB_POSIX_ACL_USER:
+ uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
+ d_printf("default:user:%u:", uorg);
+ break;
+ case SMB_POSIX_ACL_GROUP_OBJ:
+ d_printf("default:group::");
+ break;
+ case SMB_POSIX_ACL_GROUP:
+ uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
+ d_printf("default:group:%u", uorg);
+ break;
+ case SMB_POSIX_ACL_MASK:
+ d_printf("default:mask::");
+ break;
+ case SMB_POSIX_ACL_OTHER:
+ d_printf("default:other::");
+ break;
+ default:
+ d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
+ src, (unsigned int)tagtype );
+ SAFE_FREE(retbuf);
+ return 1;
+ }
+
+ d_printf("%s\n", perms_to_string(permstring, perms));
+ }
+
+ SAFE_FREE(retbuf);
+ return 0;
+}
+
+/****************************************************************************
+ UNIX stat.
+****************************************************************************/
+
+static int cmd_stat(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *src = NULL;
+ char *name = NULL;
+ char *targetname = NULL;
+ struct cli_state *targetcli;
+ fstring mode_str;
+ SMB_STRUCT_STAT sbuf;
+ struct tm *lt;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
+ d_printf("stat file\n");
+ return 1;
+ }
+ src = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ name);
+ if (!src) {
+ return 1;
+ }
+
+ if (!cli_resolve_path(ctx, "", cli, src, &targetcli, &targetname)) {
+ d_printf("stat %s: %s\n", src, cli_errstr(cli));
+ return 1;
+ }
+
+ if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
+ d_printf("Server doesn't support UNIX CIFS calls.\n");
+ return 1;
+ }
+
+ if (!cli_unix_stat(targetcli, targetname, &sbuf)) {
+ d_printf("%s stat file %s\n",
+ cli_errstr(targetcli), src);
+ return 1;
+ }
+
+ /* Print out the stat values. */
+ d_printf("File: %s\n", src);
+ d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
+ (double)sbuf.st_size,
+ (unsigned int)sbuf.st_blocks,
+ filetype_to_str(sbuf.st_mode));
+
+#if defined(S_ISCHR) && defined(S_ISBLK)
+ if (S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode)) {
+ d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
+ (double)sbuf.st_ino,
+ (unsigned int)sbuf.st_nlink,
+ unix_dev_major(sbuf.st_rdev),
+ unix_dev_minor(sbuf.st_rdev));
+ } else
+#endif
+ d_printf("Inode: %.0f\tLinks: %u\n",
+ (double)sbuf.st_ino,
+ (unsigned int)sbuf.st_nlink);
+
+ d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
+ ((int)sbuf.st_mode & 0777),
+ unix_mode_to_str(mode_str, sbuf.st_mode),
+ (unsigned int)sbuf.st_uid,
+ (unsigned int)sbuf.st_gid);
+
+ lt = localtime(&sbuf.st_atime);
+ if (lt) {
+ strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
+ } else {
+ fstrcpy(mode_str, "unknown");
+ }
+ d_printf("Access: %s\n", mode_str);
+
+ lt = localtime(&sbuf.st_mtime);
+ if (lt) {
+ strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
+ } else {
+ fstrcpy(mode_str, "unknown");
+ }
+ d_printf("Modify: %s\n", mode_str);
+
+ lt = localtime(&sbuf.st_ctime);
+ if (lt) {
+ strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
+ } else {
+ fstrcpy(mode_str, "unknown");
+ }
+ d_printf("Change: %s\n", mode_str);
+
+ return 0;
+}
+
+
+/****************************************************************************
+ UNIX chown.
+****************************************************************************/
+
+static int cmd_chown(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *src = NULL;
+ uid_t uid;
+ gid_t gid;
+ char *buf, *buf2, *buf3;
+ struct cli_state *targetcli;
+ char *targetname = NULL;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
+ !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL) ||
+ !next_token_talloc(ctx, &cmd_ptr,&buf3,NULL)) {
+ d_printf("chown uid gid file\n");
+ return 1;
+ }
+
+ uid = (uid_t)atoi(buf);
+ gid = (gid_t)atoi(buf2);
+
+ src = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf3);
+ if (!src) {
+ return 1;
+ }
+ if (!cli_resolve_path(ctx, "", cli, src, &targetcli, &targetname) ) {
+ d_printf("chown %s: %s\n", src, cli_errstr(cli));
+ return 1;
+ }
+
+ if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
+ d_printf("Server doesn't support UNIX CIFS calls.\n");
+ return 1;
+ }
+
+ if (!cli_unix_chown(targetcli, targetname, uid, gid)) {
+ d_printf("%s chown file %s uid=%d, gid=%d\n",
+ cli_errstr(targetcli), src, (int)uid, (int)gid);
+ return 1;
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Rename some file.
+****************************************************************************/
+
+static int cmd_rename(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *src, *dest;
+ char *buf, *buf2;
+ struct cli_state *targetcli;
+ char *targetsrc;
+ char *targetdest;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
+ !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
+ d_printf("rename <src> <dest>\n");
+ return 1;
+ }
+
+ src = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf);
+ if (!src) {
+ return 1;
+ }
+
+ dest = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf2);
+ if (!dest) {
+ return 1;
+ }
+
+ if (!cli_resolve_path(ctx, "", cli, src, &targetcli, &targetsrc)) {
+ d_printf("rename %s: %s\n", src, cli_errstr(cli));
+ return 1;
+ }
+
+ if (!cli_resolve_path(ctx, "", cli, dest, &targetcli, &targetdest)) {
+ d_printf("rename %s: %s\n", dest, cli_errstr(cli));
+ return 1;
+ }
+
+ if (!cli_rename(targetcli, targetsrc, targetdest)) {
+ d_printf("%s renaming files %s -> %s \n",
+ cli_errstr(targetcli),
+ targetsrc,
+ targetdest);
+ return 1;
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Print the volume name.
+****************************************************************************/
+
+static int cmd_volume(void)
+{
+ fstring volname;
+ uint32 serial_num;
+ time_t create_date;
+
+ if (!cli_get_fs_volume_info(cli, volname, &serial_num, &create_date)) {
+ d_printf("Errr %s getting volume info\n",cli_errstr(cli));
+ return 1;
+ }
+
+ d_printf("Volume: |%s| serial number 0x%x\n",
+ volname, (unsigned int)serial_num);
+ return 0;
+}
+
+/****************************************************************************
+ Hard link files using the NT call.
+****************************************************************************/
+
+static int cmd_hardlink(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *src, *dest;
+ char *buf, *buf2;
+ struct cli_state *targetcli;
+ char *targetname;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
+ !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
+ d_printf("hardlink <src> <dest>\n");
+ return 1;
+ }
+
+ src = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf);
+ if (!src) {
+ return 1;
+ }
+
+ dest = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf2);
+ if (!dest) {
+ return 1;
+ }
+
+ if (!cli_resolve_path(ctx, "", cli, src, &targetcli, &targetname)) {
+ d_printf("hardlink %s: %s\n", src, cli_errstr(cli));
+ return 1;
+ }
+
+ if (!cli_nt_hardlink(targetcli, targetname, dest)) {
+ d_printf("%s doing an NT hard link of files\n",cli_errstr(targetcli));
+ return 1;
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Toggle the prompt flag.
+****************************************************************************/
+
+static int cmd_prompt(void)
+{
+ prompt = !prompt;
+ DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
+ return 1;
+}
+
+/****************************************************************************
+ Set the newer than time.
+****************************************************************************/
+
+static int cmd_newer(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *buf;
+ bool ok;
+ SMB_STRUCT_STAT sbuf;
+
+ ok = next_token_talloc(ctx, &cmd_ptr,&buf,NULL);
+ if (ok && (sys_stat(buf,&sbuf) == 0)) {
+ newer_than = sbuf.st_mtime;
+ DEBUG(1,("Getting files newer than %s",
+ time_to_asc(newer_than)));
+ } else {
+ newer_than = 0;
+ }
+
+ if (ok && newer_than == 0) {
+ d_printf("Error setting newer-than time\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Set the archive level.
+****************************************************************************/
+
+static int cmd_archive(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *buf;
+
+ if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ archive_level = atoi(buf);
+ } else {
+ d_printf("Archive level is %d\n",archive_level);
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Toggle the lowercaseflag.
+****************************************************************************/
+
+static int cmd_lowercase(void)
+{
+ lowercase = !lowercase;
+ DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
+ return 0;
+}
+
+/****************************************************************************
+ Toggle the case sensitive flag.
+****************************************************************************/
+
+static int cmd_setcase(void)
+{
+ bool orig_case_sensitive = cli_set_case_sensitive(cli, false);
+
+ cli_set_case_sensitive(cli, !orig_case_sensitive);
+ DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ?
+ "on":"off"));
+ return 0;
+}
+
+/****************************************************************************
+ Toggle the showacls flag.
+****************************************************************************/
+
+static int cmd_showacls(void)
+{
+ showacls = !showacls;
+ DEBUG(2,("showacls is now %s\n",showacls?"on":"off"));
+ return 0;
+}
+
+
+/****************************************************************************
+ Toggle the recurse flag.
+****************************************************************************/
+
+static int cmd_recurse(void)
+{
+ recurse = !recurse;
+ DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
+ return 0;
+}
+
+/****************************************************************************
+ Toggle the translate flag.
+****************************************************************************/
+
+static int cmd_translate(void)
+{
+ translation = !translation;
+ DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
+ translation?"on":"off"));
+ return 0;
+}
+
+/****************************************************************************
+ Do the lcd command.
+ ****************************************************************************/
+
+static int cmd_lcd(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *buf;
+ char *d;
+
+ if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ chdir(buf);
+ }
+ d = TALLOC_ARRAY(ctx, char, PATH_MAX+1);
+ if (!d) {
+ return 1;
+ }
+ DEBUG(2,("the local directory is now %s\n",sys_getwd(d)));
+ return 0;
+}
+
+/****************************************************************************
+ Get a file restarting at end of local file.
+ ****************************************************************************/
+
+static int cmd_reget(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *local_name = NULL;
+ char *remote_name = NULL;
+ char *fname = NULL;
+ char *p = NULL;
+
+ remote_name = talloc_strdup(ctx, client_get_cur_dir());
+ if (!remote_name) {
+ return 1;
+ }
+
+ if (!next_token_talloc(ctx, &cmd_ptr, &fname, NULL)) {
+ d_printf("reget <filename>\n");
+ return 1;
+ }
+ remote_name = talloc_asprintf_append(remote_name, fname);
+ if (!remote_name) {
+ return 1;
+ }
+ remote_name = clean_name(ctx,remote_name);
+ if (!remote_name) {
+ return 1;
+ }
+
+ local_name = fname;
+ next_token_talloc(ctx, &cmd_ptr, &p, NULL);
+ if (p) {
+ local_name = p;
+ }
+
+ return do_get(remote_name, local_name, true);
+}
+
+/****************************************************************************
+ Put a file restarting at end of local file.
+ ****************************************************************************/
+
+static int cmd_reput(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *local_name = NULL;
+ char *remote_name = NULL;
+ char *buf;
+ SMB_STRUCT_STAT st;
+
+ remote_name = talloc_strdup(ctx, client_get_cur_dir());
+ if (!remote_name) {
+ return 1;
+ }
+
+ if (!next_token_talloc(ctx, &cmd_ptr, &local_name, NULL)) {
+ d_printf("reput <filename>\n");
+ return 1;
+ }
+
+ if (!file_exist(local_name, &st)) {
+ d_printf("%s does not exist\n", local_name);
+ return 1;
+ }
+
+ if (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
+ remote_name = talloc_asprintf_append(remote_name,
+ buf);
+ } else {
+ remote_name = talloc_asprintf_append(remote_name,
+ local_name);
+ }
+ if (!remote_name) {
+ return 1;
+ }
+
+ remote_name = clean_name(ctx, remote_name);
+ if (!remote_name) {
+ return 1;
+ }
+
+ return do_put(remote_name, local_name, true);
+}
+
+/****************************************************************************
+ List a share name.
+ ****************************************************************************/
+
+static void browse_fn(const char *name, uint32 m,
+ const char *comment, void *state)
+{
+ const char *typestr = "";
+
+ switch (m & 7) {
+ case STYPE_DISKTREE:
+ typestr = "Disk";
+ break;
+ case STYPE_PRINTQ:
+ typestr = "Printer";
+ break;
+ case STYPE_DEVICE:
+ typestr = "Device";
+ break;
+ case STYPE_IPC:
+ typestr = "IPC";
+ break;
+ }
+ /* FIXME: If the remote machine returns non-ascii characters
+ in any of these fields, they can corrupt the output. We
+ should remove them. */
+ if (!grepable) {
+ d_printf("\t%-15s %-10.10s%s\n",
+ name,typestr,comment);
+ } else {
+ d_printf ("%s|%s|%s\n",typestr,name,comment);
+ }
+}
+
+static bool browse_host_rpc(bool sort)
+{
+ NTSTATUS status;
+ struct rpc_pipe_client *pipe_hnd;
+ TALLOC_CTX *frame = talloc_stackframe();
+ WERROR werr;
+ struct srvsvc_NetShareInfoCtr info_ctr;
+ struct srvsvc_NetShareCtr1 ctr1;
+ uint32_t resume_handle = 0;
+ uint32_t total_entries = 0;
+ int i;
+
+ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc.syntax_id,
+ &pipe_hnd);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Could not connect to srvsvc pipe: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ ZERO_STRUCT(info_ctr);
+ ZERO_STRUCT(ctr1);
+
+ info_ctr.level = 1;
+ info_ctr.ctr.ctr1 = &ctr1;
+
+ status = rpccli_srvsvc_NetShareEnumAll(pipe_hnd, frame,
+ pipe_hnd->desthost,
+ &info_ctr,
+ 0xffffffff,
+ &total_entries,
+ &resume_handle,
+ &werr);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(werr)) {
+ TALLOC_FREE(pipe_hnd);
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ for (i=0; i < info_ctr.ctr.ctr1->count; i++) {
+ struct srvsvc_NetShareInfo1 info = info_ctr.ctr.ctr1->array[i];
+ browse_fn(info.name, info.type, info.comment, NULL);
+ }
+
+ TALLOC_FREE(pipe_hnd);
+ TALLOC_FREE(frame);
+ return true;
+}
+
+/****************************************************************************
+ Try and browse available connections on a host.
+****************************************************************************/
+
+static bool browse_host(bool sort)
+{
+ int ret;
+ if (!grepable) {
+ d_printf("\n\tSharename Type Comment\n");
+ d_printf("\t--------- ---- -------\n");
+ }
+
+ if (browse_host_rpc(sort)) {
+ return true;
+ }
+
+ if((ret = cli_RNetShareEnum(cli, browse_fn, NULL)) == -1)
+ d_printf("Error returning browse list: %s\n", cli_errstr(cli));
+
+ return (ret != -1);
+}
+
+/****************************************************************************
+ List a server name.
+****************************************************************************/
+
+static void server_fn(const char *name, uint32 m,
+ const char *comment, void *state)
+{
+
+ if (!grepable){
+ d_printf("\t%-16s %s\n", name, comment);
+ } else {
+ d_printf("%s|%s|%s\n",(char *)state, name, comment);
+ }
+}
+
+/****************************************************************************
+ Try and browse available connections on a host.
+****************************************************************************/
+
+static bool list_servers(const char *wk_grp)
+{
+ fstring state;
+
+ if (!cli->server_domain)
+ return false;
+
+ if (!grepable) {
+ d_printf("\n\tServer Comment\n");
+ d_printf("\t--------- -------\n");
+ };
+ fstrcpy( state, "Server" );
+ cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, server_fn,
+ state);
+
+ if (!grepable) {
+ d_printf("\n\tWorkgroup Master\n");
+ d_printf("\t--------- -------\n");
+ };
+
+ fstrcpy( state, "Workgroup" );
+ cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM,
+ server_fn, state);
+ return true;
+}
+
+/****************************************************************************
+ Print or set current VUID
+****************************************************************************/
+
+static int cmd_vuid(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *buf;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ d_printf("Current VUID is %d\n", cli->vuid);
+ return 0;
+ }
+
+ cli->vuid = atoi(buf);
+ return 0;
+}
+
+/****************************************************************************
+ Setup a new VUID, by issuing a session setup
+****************************************************************************/
+
+static int cmd_logon(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *l_username, *l_password;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&l_username,NULL)) {
+ d_printf("logon <username> [<password>]\n");
+ return 0;
+ }
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&l_password,NULL)) {
+ char *pass = getpass("Password: ");
+ if (pass) {
+ l_password = talloc_strdup(ctx,pass);
+ }
+ }
+ if (!l_password) {
+ return 1;
+ }
+
+ if (!NT_STATUS_IS_OK(cli_session_setup(cli, l_username,
+ l_password, strlen(l_password),
+ l_password, strlen(l_password),
+ lp_workgroup()))) {
+ d_printf("session setup failed: %s\n", cli_errstr(cli));
+ return -1;
+ }
+
+ d_printf("Current VUID is %d\n", cli->vuid);
+ return 0;
+}
+
+
+/****************************************************************************
+ list active connections
+****************************************************************************/
+
+static int cmd_list_connect(void)
+{
+ cli_cm_display();
+ return 0;
+}
+
+/****************************************************************************
+ display the current active client connection
+****************************************************************************/
+
+static int cmd_show_connect( void )
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ struct cli_state *targetcli;
+ char *targetpath;
+
+ if (!cli_resolve_path(ctx, "", cli, client_get_cur_dir(),
+ &targetcli, &targetpath ) ) {
+ d_printf("showconnect %s: %s\n", cur_dir, cli_errstr(cli));
+ return 1;
+ }
+
+ d_printf("//%s/%s\n", targetcli->desthost, targetcli->share);
+ return 0;
+}
+
+/****************************************************************************
+ iosize command
+***************************************************************************/
+
+int cmd_iosize(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *buf;
+ int iosize;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ if (!smb_encrypt) {
+ d_printf("iosize <n> or iosize 0x<n>. "
+ "Minimum is 16384 (0x4000), "
+ "max is 16776960 (0xFFFF00)\n");
+ } else {
+ d_printf("iosize <n> or iosize 0x<n>. "
+ "(Encrypted connection) ,"
+ "Minimum is 16384 (0x4000), "
+ "max is 130048 (0x1FC00)\n");
+ }
+ return 1;
+ }
+
+ iosize = strtol(buf,NULL,0);
+ if (smb_encrypt && (iosize < 0x4000 || iosize > 0xFC00)) {
+ d_printf("iosize out of range for encrypted "
+ "connection (min = 16384 (0x4000), "
+ "max = 130048 (0x1FC00)");
+ return 1;
+ } else if (!smb_encrypt && (iosize < 0x4000 || iosize > 0xFFFF00)) {
+ d_printf("iosize out of range (min = 16384 (0x4000), "
+ "max = 16776960 (0xFFFF00)");
+ return 1;
+ }
+
+ io_bufsize = iosize;
+ d_printf("iosize is now %d\n", io_bufsize);
+ return 0;
+}
+
+
+/* Some constants for completing filename arguments */
+
+#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.
+ * NOTE: The "!" must be the last one in the list because it's fn pointer
+ * field is NULL, and NULL in that field is used in process_tok()
+ * (below) to indicate the end of the list. crh
+ */
+static struct {
+ const char *name;
+ int (*fn)(void);
+ const char *description;
+ char compl_args[2]; /* Completion argument info */
+} commands[] = {
+ {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
+ {"allinfo",cmd_allinfo,"<file> show all available info",
+ {COMPL_NONE,COMPL_NONE}},
+ {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,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}},
+ {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
+ {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
+ {"case_sensitive",cmd_setcase,"toggle the case sensitive flag to server",{COMPL_NONE,COMPL_NONE}},
+ {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
+ {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}},
+ {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}},
+ {"close",cmd_close,"<fid> close a file given a fid",{COMPL_REMOTE,COMPL_REMOTE}},
+ {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
+ {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
+ {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
+ {"echo",cmd_echo,"ping the server",{COMPL_NONE,COMPL_NONE}},
+ {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
+ {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
+ {"getfacl",cmd_getfacl,"<file name> get the POSIX ACL on a file (UNIX extensions only)",{COMPL_REMOTE,COMPL_LOCAL}},
+ {"hardlink",cmd_hardlink,"<src> <dest> create a Windows hard link",{COMPL_REMOTE,COMPL_REMOTE}},
+ {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
+ {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
+ {"iosize",cmd_iosize,"iosize <number> (default 64512)",{COMPL_NONE,COMPL_NONE}},
+ {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
+ {"link",cmd_link,"<oldname> <newname> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}},
+ {"lock",cmd_lock,"lock <fnum> [r|w] <hex-start> <hex-len> : set a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
+ {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},
+ {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
+ {"l",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
+ {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
+ {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
+ {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
+ {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
+ {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},
+ {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
+ {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
+ {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
+ {"posix", cmd_posix, "turn on all POSIX capabilities", {COMPL_REMOTE,COMPL_NONE}},
+ {"posix_encrypt",cmd_posix_encrypt,"<domain> <user> <password> start up transport encryption",{COMPL_REMOTE,COMPL_NONE}},
+ {"posix_open",cmd_posix_open,"<name> 0<mode> open_flags mode open a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
+ {"posix_mkdir",cmd_posix_mkdir,"<name> 0<mode> creates a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
+ {"posix_rmdir",cmd_posix_rmdir,"<name> removes a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
+ {"posix_unlink",cmd_posix_unlink,"<name> removes a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
+ {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
+ {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},
+ {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
+ {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
+ {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
+ {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
+ {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
+ {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
+ {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},
+ {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
+ {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
+ {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
+ {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
+ {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
+ {"showacls",cmd_showacls,"toggle if ACLs are shown or not",{COMPL_NONE,COMPL_NONE}},
+ {"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
+ {"stat",cmd_stat,"filename Do a UNIX extensions stat call on a file",{COMPL_REMOTE,COMPL_REMOTE}},
+ {"symlink",cmd_symlink,"<oldname> <newname> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
+ {"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
+ {"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
+ {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
+ {"unlock",cmd_unlock,"unlock <fnum> <hex-start> <hex-len> : remove a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
+ {"volume",cmd_volume,"print the volume name",{COMPL_NONE,COMPL_NONE}},
+ {"vuid",cmd_vuid,"change current vuid",{COMPL_NONE,COMPL_NONE}},
+ {"wdel",cmd_wdel,"<attrib> <mask> wildcard delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
+ {"logon",cmd_logon,"establish new logon",{COMPL_NONE,COMPL_NONE}},
+ {"listconnect",cmd_list_connect,"list open connections",{COMPL_NONE,COMPL_NONE}},
+ {"showconnect",cmd_show_connect,"display the current active connection",{COMPL_NONE,COMPL_NONE}},
+ {"..",cmd_cd_oneup,"change the remote directory (up one level)",{COMPL_REMOTE,COMPL_NONE}},
+
+ /* Yes, this must be here, see crh's comment above. */
+ {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
+ {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}}
+};
+
+/*******************************************************************
+ Lookup a command string in the list of commands, including
+ abbreviations.
+******************************************************************/
+
+static int process_tok(char *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.
+****************************************************************************/
+
+static int cmd_help(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ int i=0,j;
+ char *buf;
+
+ if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ if ((i = process_tok(buf)) >= 0)
+ d_printf("HELP %s:\n\t%s\n\n",
+ commands[i].name,commands[i].description);
+ } else {
+ while (commands[i].description) {
+ for (j=0; commands[i].description && (j<5); j++) {
+ d_printf("%-15s",commands[i].name);
+ i++;
+ }
+ d_printf("\n");
+ }
+ }
+ return 0;
+}
+
+/****************************************************************************
+ Process a -c command string.
+****************************************************************************/
+
+static int process_command_string(const char *cmd_in)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *cmd = talloc_strdup(ctx, cmd_in);
+ int rc = 0;
+
+ if (!cmd) {
+ return 1;
+ }
+ /* establish the connection if not already */
+
+ if (!cli) {
+ cli = cli_cm_open(talloc_tos(), NULL, desthost,
+ service, true, smb_encrypt);
+ if (!cli) {
+ return 1;
+ }
+ }
+
+ while (cmd[0] != '\0') {
+ char *line;
+ char *p;
+ char *tok;
+ int i;
+
+ if ((p = strchr_m(cmd, ';')) == 0) {
+ line = cmd;
+ cmd += strlen(cmd);
+ } else {
+ *p = '\0';
+ line = cmd;
+ cmd = p + 1;
+ }
+
+ /* and get the first part of the command */
+ cmd_ptr = line;
+ if (!next_token_talloc(ctx, &cmd_ptr,&tok,NULL)) {
+ continue;
+ }
+
+ if ((i = process_tok(tok)) >= 0) {
+ rc = commands[i].fn();
+ } else if (i == -2) {
+ d_printf("%s: command abbreviation ambiguous\n",tok);
+ } else {
+ d_printf("%s: command not found\n",tok);
+ }
+ }
+
+ return rc;
+}
+
+#define MAX_COMPLETIONS 100
+
+typedef struct {
+ char *dirmask;
+ char **matches;
+ int count, samelen;
+ const char *text;
+ int len;
+} completion_remote_t;
+
+static void completion_remote_filter(const char *mnt,
+ file_info *f,
+ const char *mask,
+ void *state)
+{
+ completion_remote_t *info = (completion_remote_t *)state;
+
+ if ((info->count < MAX_COMPLETIONS - 1) &&
+ (strncmp(info->text, f->name, info->len) == 0) &&
+ (strcmp(f->name, ".") != 0) &&
+ (strcmp(f->name, "..") != 0)) {
+ if ((info->dirmask[0] == 0) && !(f->mode & aDIR))
+ info->matches[info->count] = SMB_STRDUP(f->name);
+ else {
+ TALLOC_CTX *ctx = talloc_stackframe();
+ char *tmp;
+
+ tmp = talloc_strdup(ctx,info->dirmask);
+ if (!tmp) {
+ TALLOC_FREE(ctx);
+ return;
+ }
+ tmp = talloc_asprintf_append(tmp, f->name);
+ if (!tmp) {
+ TALLOC_FREE(ctx);
+ return;
+ }
+ if (f->mode & aDIR) {
+ tmp = talloc_asprintf_append(tmp, CLI_DIRSEP_STR);
+ }
+ if (!tmp) {
+ TALLOC_FREE(ctx);
+ return;
+ }
+ info->matches[info->count] = SMB_STRDUP(tmp);
+ TALLOC_FREE(ctx);
+ }
+ if (info->matches[info->count] == NULL) {
+ return;
+ }
+ if (f->mode & aDIR) {
+ smb_readline_ca_char(0);
+ }
+ if (info->count == 1) {
+ info->samelen = strlen(info->matches[info->count]);
+ } else {
+ while (strncmp(info->matches[info->count],
+ info->matches[info->count-1],
+ info->samelen) != 0) {
+ info->samelen--;
+ }
+ }
+ info->count++;
+ }
+}
+
+static char **remote_completion(const char *text, int len)
+{
+ TALLOC_CTX *ctx = talloc_stackframe();
+ char *dirmask = NULL;
+ char *targetpath = NULL;
+ struct cli_state *targetcli = NULL;
+ int i;
+ completion_remote_t info = { NULL, NULL, 1, 0, NULL, 0 };
+
+ /* can't have non-static intialisation on Sun CC, so do it
+ at run time here */
+ info.samelen = len;
+ info.text = text;
+ info.len = len;
+
+ info.matches = SMB_MALLOC_ARRAY(char *,MAX_COMPLETIONS);
+ if (!info.matches) {
+ TALLOC_FREE(ctx);
+ return NULL;
+ }
+
+ /*
+ * We're leaving matches[0] free to fill it later with the text to
+ * display: Either the one single match or the longest common subset
+ * of the matches.
+ */
+ info.matches[0] = NULL;
+ info.count = 1;
+
+ for (i = len-1; i >= 0; i--) {
+ if ((text[i] == '/') || (text[i] == CLI_DIRSEP_CHAR)) {
+ break;
+ }
+ }
+
+ info.text = text+i+1;
+ info.samelen = info.len = len-i-1;
+
+ if (i > 0) {
+ info.dirmask = SMB_MALLOC_ARRAY(char, i+2);
+ if (!info.dirmask) {
+ goto cleanup;
+ }
+ strncpy(info.dirmask, text, i+1);
+ info.dirmask[i+1] = 0;
+ dirmask = talloc_asprintf(ctx,
+ "%s%*s*",
+ client_get_cur_dir(),
+ i-1,
+ text);
+ } else {
+ info.dirmask = SMB_STRDUP("");
+ if (!info.dirmask) {
+ goto cleanup;
+ }
+ dirmask = talloc_asprintf(ctx,
+ "%s*",
+ client_get_cur_dir());
+ }
+ if (!dirmask) {
+ goto cleanup;
+ }
+
+ if (!cli_resolve_path(ctx, "", cli, dirmask, &targetcli, &targetpath)) {
+ goto cleanup;
+ }
+ if (cli_list(targetcli, targetpath, aDIR | aSYSTEM | aHIDDEN,
+ completion_remote_filter, (void *)&info) < 0) {
+ goto cleanup;
+ }
+
+ if (info.count == 1) {
+ /*
+ * No matches at all, NULL indicates there is nothing
+ */
+ SAFE_FREE(info.matches[0]);
+ SAFE_FREE(info.matches);
+ TALLOC_FREE(ctx);
+ return NULL;
+ }
+
+ if (info.count == 2) {
+ /*
+ * Exactly one match in matches[1], indicate this is the one
+ * in matches[0].
+ */
+ info.matches[0] = info.matches[1];
+ info.matches[1] = NULL;
+ info.count -= 1;
+ TALLOC_FREE(ctx);
+ return info.matches;
+ }
+
+ /*
+ * We got more than one possible match, set the result to the maximum
+ * common subset
+ */
+
+ info.matches[0] = SMB_STRNDUP(info.matches[1], info.samelen);
+ info.matches[info.count] = NULL;
+ return info.matches;
+
+cleanup:
+ for (i = 0; i < info.count; i++) {
+ SAFE_FREE(info.matches[i]);
+ }
+ SAFE_FREE(info.matches);
+ SAFE_FREE(info.dirmask);
+ TALLOC_FREE(ctx);
+ return NULL;
+}
+
+static char **completion_fn(const char *text, int start, int end)
+{
+ smb_readline_ca_char(' ');
+
+ if (start) {
+ const char *buf, *sp;
+ int i;
+ char compl_type;
+
+ buf = smb_readline_get_line_buffer();
+ if (buf == NULL)
+ return NULL;
+
+ sp = strchr(buf, ' ');
+ if (sp == NULL)
+ return NULL;
+
+ for (i = 0; commands[i].name; i++) {
+ if ((strncmp(commands[i].name, buf, sp - buf) == 0) &&
+ (commands[i].name[sp - buf] == 0)) {
+ break;
+ }
+ }
+ if (commands[i].name == NULL)
+ return NULL;
+
+ while (*sp == ' ')
+ sp++;
+
+ if (sp == (buf + start))
+ compl_type = commands[i].compl_args[0];
+ else
+ compl_type = commands[i].compl_args[1];
+
+ if (compl_type == COMPL_REMOTE)
+ return remote_completion(text, end - start);
+ else /* fall back to local filename completion */
+ return NULL;
+ } else {
+ char **matches;
+ int i, len, samelen = 0, count=1;
+
+ matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS);
+ if (!matches) {
+ return NULL;
+ }
+ matches[0] = NULL;
+
+ len = strlen(text);
+ for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
+ if (strncmp(text, commands[i].name, len) == 0) {
+ matches[count] = SMB_STRDUP(commands[i].name);
+ if (!matches[count])
+ goto cleanup;
+ if (count == 1)
+ samelen = strlen(matches[count]);
+ else
+ while (strncmp(matches[count], matches[count-1], samelen) != 0)
+ samelen--;
+ count++;
+ }
+ }
+
+ switch (count) {
+ case 0: /* should never happen */
+ case 1:
+ goto cleanup;
+ case 2:
+ matches[0] = SMB_STRDUP(matches[1]);
+ break;
+ default:
+ matches[0] = (char *)SMB_MALLOC(samelen+1);
+ if (!matches[0])
+ goto cleanup;
+ strncpy(matches[0], matches[1], samelen);
+ matches[0][samelen] = 0;
+ }
+ matches[count] = NULL;
+ return matches;
+
+cleanup:
+ for (i = 0; i < count; i++)
+ free(matches[i]);
+
+ free(matches);
+ return NULL;
+ }
+}
+
+/****************************************************************************
+ Make sure we swallow keepalives during idle time.
+****************************************************************************/
+
+static void readline_callback(void)
+{
+ fd_set fds;
+ struct timeval timeout;
+ static time_t last_t;
+ time_t t;
+
+ t = time(NULL);
+
+ if (t - last_t < 5)
+ return;
+
+ last_t = t;
+
+ again:
+
+ if (cli->fd == -1)
+ return;
+
+ FD_ZERO(&fds);
+ FD_SET(cli->fd,&fds);
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ sys_select_intr(cli->fd+1,&fds,NULL,NULL,&timeout);
+
+ /* We deliberately use receive_smb_raw instead of
+ client_receive_smb as we want to receive
+ session keepalives and then drop them here.
+ */
+ if (FD_ISSET(cli->fd,&fds)) {
+ NTSTATUS status;
+ size_t len;
+
+ set_smb_read_error(&cli->smb_rw_error, SMB_READ_OK);
+
+ status = receive_smb_raw(cli->fd, cli->inbuf, cli->bufsize, 0, 0, &len);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Read from server failed, maybe it closed "
+ "the connection\n"));
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
+ set_smb_read_error(&cli->smb_rw_error,
+ SMB_READ_EOF);
+ return;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ set_smb_read_error(&cli->smb_rw_error,
+ SMB_READ_TIMEOUT);
+ return;
+ }
+
+ set_smb_read_error(&cli->smb_rw_error, SMB_READ_ERROR);
+ return;
+ }
+ if(CVAL(cli->inbuf,0) != SMBkeepalive) {
+ DEBUG(0, ("Read from server "
+ "returned unexpected packet!\n"));
+ return;
+ }
+
+ goto again;
+ }
+
+ /* Ping the server to keep the connection alive using SMBecho. */
+ {
+ unsigned char garbage[16];
+ memset(garbage, 0xf0, sizeof(garbage));
+ cli_echo(cli, 1, data_blob_const(garbage, sizeof(garbage)));
+ }
+}
+
+/****************************************************************************
+ Process commands on stdin.
+****************************************************************************/
+
+static int process_stdin(void)
+{
+ int rc = 0;
+
+ while (1) {
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *tok = NULL;
+ char *the_prompt = NULL;
+ char *line = NULL;
+ int i;
+
+ /* display a prompt */
+ if (asprintf(&the_prompt, "smb: %s> ", client_get_cur_dir()) < 0) {
+ TALLOC_FREE(frame);
+ break;
+ }
+ line = smb_readline(the_prompt, readline_callback, completion_fn);
+ SAFE_FREE(the_prompt);
+ if (!line) {
+ TALLOC_FREE(frame);
+ break;
+ }
+
+ /* special case - first char is ! */
+ if (*line == '!') {
+ system(line + 1);
+ SAFE_FREE(line);
+ TALLOC_FREE(frame);
+ continue;
+ }
+
+ /* and get the first part of the command */
+ cmd_ptr = line;
+ if (!next_token_talloc(frame, &cmd_ptr,&tok,NULL)) {
+ TALLOC_FREE(frame);
+ SAFE_FREE(line);
+ continue;
+ }
+
+ if ((i = process_tok(tok)) >= 0) {
+ rc = commands[i].fn();
+ } else if (i == -2) {
+ d_printf("%s: command abbreviation ambiguous\n",tok);
+ } else {
+ d_printf("%s: command not found\n",tok);
+ }
+ SAFE_FREE(line);
+ TALLOC_FREE(frame);
+ }
+ return rc;
+}
+
+/****************************************************************************
+ Process commands from the client.
+****************************************************************************/
+
+static int process(const char *base_directory)
+{
+ int rc = 0;
+
+ cli = cli_cm_open(talloc_tos(), NULL,
+ desthost, service, true, smb_encrypt);
+ if (!cli) {
+ return 1;
+ }
+
+ if (base_directory && *base_directory) {
+ rc = do_cd(base_directory);
+ if (rc) {
+ cli_cm_shutdown();
+ return rc;
+ }
+ }
+
+ if (cmdstr) {
+ rc = process_command_string(cmdstr);
+ } else {
+ process_stdin();
+ }
+
+ cli_cm_shutdown();
+ return rc;
+}
+
+/****************************************************************************
+ Handle a -L query.
+****************************************************************************/
+
+static int do_host_query(const char *query_host)
+{
+ struct sockaddr_storage ss;
+
+ cli = cli_cm_open(talloc_tos(), NULL,
+ query_host, "IPC$", true, smb_encrypt);
+ if (!cli)
+ return 1;
+
+ browse_host(true);
+
+ if (interpret_string_addr(&ss, query_host, 0) && (ss.ss_family != AF_INET)) {
+ d_printf("%s is an IPv6 address -- no workgroup available\n",
+ query_host);
+ return 1;
+ }
+
+ if (port != 139) {
+
+ /* Workgroups simply don't make sense over anything
+ else but port 139... */
+
+ cli_cm_shutdown();
+ cli_cm_set_port( 139 );
+ cli = cli_cm_open(talloc_tos(), NULL,
+ query_host, "IPC$", true, smb_encrypt);
+ }
+
+ if (cli == NULL) {
+ d_printf("NetBIOS over TCP disabled -- no workgroup available\n");
+ return 1;
+ }
+
+ list_servers(lp_workgroup());
+
+ cli_cm_shutdown();
+
+ return(0);
+}
+
+/****************************************************************************
+ Handle a tar operation.
+****************************************************************************/
+
+static int do_tar_op(const char *base_directory)
+{
+ int ret;
+
+ /* do we already have a connection? */
+ if (!cli) {
+ cli = cli_cm_open(talloc_tos(), NULL,
+ desthost, service, true, smb_encrypt);
+ if (!cli)
+ return 1;
+ }
+
+ recurse=true;
+
+ if (base_directory && *base_directory) {
+ ret = do_cd(base_directory);
+ if (ret) {
+ cli_cm_shutdown();
+ return ret;
+ }
+ }
+
+ ret=process_tar();
+
+ cli_cm_shutdown();
+
+ return(ret);
+}
+
+/****************************************************************************
+ Handle a message operation.
+****************************************************************************/
+
+static int do_message_op(void)
+{
+ struct sockaddr_storage ss;
+ struct nmb_name called, calling;
+ fstring server_name;
+ char name_type_hex[10];
+ int msg_port;
+ NTSTATUS status;
+
+ make_nmb_name(&calling, calling_name, 0x0);
+ make_nmb_name(&called , desthost, name_type);
+
+ fstrcpy(server_name, desthost);
+ snprintf(name_type_hex, sizeof(name_type_hex), "#%X", name_type);
+ fstrcat(server_name, name_type_hex);
+
+ zero_addr(&ss);
+ if (have_ip)
+ ss = dest_ss;
+
+ /* we can only do messages over port 139 (to windows clients at least) */
+
+ msg_port = port ? port : 139;
+
+ if (!(cli=cli_initialise()) || (cli_set_port(cli, msg_port) != msg_port)) {
+ d_printf("Connection to %s failed\n", desthost);
+ return 1;
+ }
+
+ status = cli_connect(cli, server_name, &ss);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("Connection to %s failed. Error %s\n", desthost, nt_errstr(status));
+ return 1;
+ }
+
+ if (!cli_session_request(cli, &calling, &called)) {
+ d_printf("session request failed\n");
+ cli_cm_shutdown();
+ return 1;
+ }
+
+ send_message();
+ cli_cm_shutdown();
+
+ return 0;
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+
+ int main(int argc,char *argv[])
+{
+ char *base_directory = NULL;
+ int opt;
+ char *query_host = NULL;
+ bool message = false;
+ char *term_code = NULL;
+ static const char *new_name_resolve_order = NULL;
+ poptContext pc;
+ char *p;
+ int rc = 0;
+ fstring new_workgroup;
+ bool tar_opt = false;
+ bool service_opt = false;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+
+ { "name-resolve", 'R', POPT_ARG_STRING, &new_name_resolve_order, 'R', "Use these name resolution services only", "NAME-RESOLVE-ORDER" },
+ { "message", 'M', POPT_ARG_STRING, NULL, 'M', "Send message", "HOST" },
+ { "ip-address", 'I', POPT_ARG_STRING, NULL, 'I', "Use this IP to connect to", "IP" },
+ { "stderr", 'E', POPT_ARG_NONE, NULL, 'E', "Write messages to stderr instead of stdout" },
+ { "list", 'L', POPT_ARG_STRING, NULL, 'L', "Get a list of shares available on a host", "HOST" },
+ { "terminal", 't', POPT_ARG_STRING, NULL, 't', "Terminal I/O code {sjis|euc|jis7|jis8|junet|hex}", "CODE" },
+ { "max-protocol", 'm', POPT_ARG_STRING, NULL, 'm', "Set the max protocol level", "LEVEL" },
+ { "tar", 'T', POPT_ARG_STRING, NULL, 'T', "Command line tar", "<c|x>IXFqgbNan" },
+ { "directory", 'D', POPT_ARG_STRING, NULL, 'D', "Start from directory", "DIR" },
+ { "command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated commands" },
+ { "send-buffer", 'b', POPT_ARG_INT, &io_bufsize, 'b', "Changes the transmit/send buffer", "BYTES" },
+ { "port", 'p', POPT_ARG_INT, &port, 'p', "Port to connect to", "PORT" },
+ { "grepable", 'g', POPT_ARG_NONE, NULL, 'g', "Produce grepable output" },
+ { "browse", 'B', POPT_ARG_NONE, NULL, 'B', "Browse SMB servers using DNS" },
+ POPT_COMMON_SAMBA
+ POPT_COMMON_CONNECTION
+ POPT_COMMON_CREDENTIALS
+ POPT_TABLEEND
+ };
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!client_set_cur_dir("\\")) {
+ exit(ENOMEM);
+ }
+
+#ifdef KANJI
+ term_code = talloc_strdup(frame,KANJI);
+#else /* KANJI */
+ term_code = talloc_strdup(frame,"");
+#endif /* KANJI */
+ if (!term_code) {
+ exit(ENOMEM);
+ }
+
+ /* initialize the workgroup name so we can determine whether or
+ not it was set by a command line option */
+
+ set_global_myworkgroup( "" );
+ set_global_myname( "" );
+
+ /* set default debug level to 1 regardless of what smb.conf sets */
+ setup_logging( "smbclient", true );
+ DEBUGLEVEL_CLASS[DBGC_ALL] = 1;
+ if ((dbf = x_fdup(x_stderr))) {
+ x_setbuf( dbf, NULL );
+ }
+
+ load_case_tables();
+
+ /* skip argv(0) */
+ pc = poptGetContext("smbclient", argc, (const char **) argv, long_options, 0);
+ poptSetOtherOptionHelp(pc, "service <password>");
+
+ lp_set_in_client(true); /* Make sure that we tell lp_load we are */
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+
+ /* if the tar option has been called previouslt, now we need to eat out the leftovers */
+ /* I see no other way to keep things sane --SSS */
+ if (tar_opt == true) {
+ while (poptPeekArg(pc)) {
+ poptGetArg(pc);
+ }
+ tar_opt = false;
+ }
+
+ /* if the service has not yet been specified lets see if it is available in the popt stack */
+ if (!service_opt && poptPeekArg(pc)) {
+ service = talloc_strdup(frame, poptGetArg(pc));
+ if (!service) {
+ exit(ENOMEM);
+ }
+ service_opt = true;
+ }
+
+ /* if the service has already been retrieved then check if we have also a password */
+ if (service_opt && (!get_cmdline_auth_info_got_pass()) && poptPeekArg(pc)) {
+ set_cmdline_auth_info_password(poptGetArg(pc));
+ }
+
+ switch (opt) {
+ case 'M':
+ /* Messages are sent to NetBIOS name type 0x3
+ * (Messenger Service). Make sure we default
+ * to port 139 instead of port 445. srl,crh
+ */
+ name_type = 0x03;
+ cli_cm_set_dest_name_type( name_type );
+ desthost = talloc_strdup(frame,poptGetOptArg(pc));
+ if (!desthost) {
+ exit(ENOMEM);
+ }
+ if( !port )
+ cli_cm_set_port( 139 );
+ message = true;
+ break;
+ case 'I':
+ {
+ if (!interpret_string_addr(&dest_ss, poptGetOptArg(pc), 0)) {
+ exit(1);
+ }
+ have_ip = true;
+
+ cli_cm_set_dest_ss(&dest_ss);
+ }
+ break;
+ case 'E':
+ if (dbf) {
+ x_fclose(dbf);
+ }
+ dbf = x_stderr;
+ display_set_stderr();
+ break;
+
+ case 'L':
+ query_host = talloc_strdup(frame, poptGetOptArg(pc));
+ if (!query_host) {
+ exit(ENOMEM);
+ }
+ break;
+ case 't':
+ term_code = talloc_strdup(frame,poptGetOptArg(pc));
+ if (!term_code) {
+ exit(ENOMEM);
+ }
+ break;
+ case 'm':
+ max_protocol = interpret_protocol(poptGetOptArg(pc), max_protocol);
+ break;
+ case 'T':
+ /* We must use old option processing for this. Find the
+ * position of the -T option in the raw argv[]. */
+ {
+ int i;
+ for (i = 1; i < argc; i++) {
+ if (strncmp("-T", argv[i],2)==0)
+ break;
+ }
+ i++;
+ if (!tar_parseargs(argc, argv, poptGetOptArg(pc), i)) {
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+ }
+ /* this must be the last option, mark we have parsed it so that we know we have */
+ tar_opt = true;
+ break;
+ case 'D':
+ base_directory = talloc_strdup(frame, poptGetOptArg(pc));
+ if (!base_directory) {
+ exit(ENOMEM);
+ }
+ break;
+ case 'g':
+ grepable=true;
+ break;
+ case 'e':
+ smb_encrypt=true;
+ break;
+ case 'B':
+ return(do_smb_browse());
+
+ }
+ }
+
+ /* We may still have some leftovers after the last popt option has been called */
+ if (tar_opt == true) {
+ while (poptPeekArg(pc)) {
+ poptGetArg(pc);
+ }
+ tar_opt = false;
+ }
+
+ /* if the service has not yet been specified lets see if it is available in the popt stack */
+ if (!service_opt && poptPeekArg(pc)) {
+ service = talloc_strdup(frame,poptGetArg(pc));
+ if (!service) {
+ exit(ENOMEM);
+ }
+ service_opt = true;
+ }
+
+ /* if the service has already been retrieved then check if we have also a password */
+ if (service_opt && !get_cmdline_auth_info_got_pass() && poptPeekArg(pc)) {
+ set_cmdline_auth_info_password(poptGetArg(pc));
+ }
+
+ /* check for the -P option */
+
+ if ( port != 0 )
+ cli_cm_set_port( port );
+
+ /*
+ * Don't load debug level from smb.conf. It should be
+ * set by cmdline arg or remain default (0)
+ */
+ AllowDebugChange = false;
+
+ /* save the workgroup...
+
+ FIXME!! do we need to do this for other options as well
+ (or maybe a generic way to keep lp_load() from overwriting
+ everything)? */
+
+ fstrcpy( new_workgroup, lp_workgroup() );
+ calling_name = talloc_strdup(frame, global_myname() );
+ if (!calling_name) {
+ exit(ENOMEM);
+ }
+
+ if ( override_logfile )
+ setup_logging( lp_logfile(), false );
+
+ if (!lp_load(get_dyn_CONFIGFILE(),true,false,false,true)) {
+ fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n",
+ argv[0], get_dyn_CONFIGFILE());
+ }
+
+ if (get_cmdline_auth_info_use_machine_account() &&
+ !set_cmdline_auth_info_machine_account_creds()) {
+ exit(-1);
+ }
+
+ load_interfaces();
+
+ if (service_opt && service) {
+ size_t len;
+
+ /* Convert any '/' characters in the service name to '\' characters */
+ string_replace(service, '/','\\');
+ if (count_chars(service,'\\') < 3) {
+ d_printf("\n%s: Not enough '\\' characters in service\n",service);
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+ /* Remove trailing slashes */
+ len = strlen(service);
+ while(len > 0 && service[len - 1] == '\\') {
+ --len;
+ service[len] = '\0';
+ }
+ }
+
+ if ( strlen(new_workgroup) != 0 ) {
+ set_global_myworkgroup( new_workgroup );
+ }
+
+ if ( strlen(calling_name) != 0 ) {
+ set_global_myname( calling_name );
+ } else {
+ TALLOC_FREE(calling_name);
+ calling_name = talloc_strdup(frame, global_myname() );
+ }
+
+ smb_encrypt = get_cmdline_auth_info_smb_encrypt();
+ if (!init_names()) {
+ fprintf(stderr, "init_names() failed\n");
+ exit(1);
+ }
+
+ if(new_name_resolve_order)
+ lp_set_name_resolve_order(new_name_resolve_order);
+
+ if (!tar_type && !query_host && !service && !message) {
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+
+ poptFreeContext(pc);
+
+ /* Store the username and password for dfs support */
+
+ cli_cm_set_credentials();
+
+ DEBUG(3,("Client started (version %s).\n", SAMBA_VERSION_STRING));
+
+ if (tar_type) {
+ if (cmdstr)
+ process_command_string(cmdstr);
+ return do_tar_op(base_directory);
+ }
+
+ if (query_host && *query_host) {
+ char *qhost = query_host;
+ char *slash;
+
+ while (*qhost == '\\' || *qhost == '/')
+ qhost++;
+
+ if ((slash = strchr_m(qhost, '/'))
+ || (slash = strchr_m(qhost, '\\'))) {
+ *slash = 0;
+ }
+
+ if ((p=strchr_m(qhost, '#'))) {
+ *p = 0;
+ p++;
+ sscanf(p, "%x", &name_type);
+ cli_cm_set_dest_name_type( name_type );
+ }
+
+ return do_host_query(qhost);
+ }
+
+ if (message) {
+ return do_message_op();
+ }
+
+ if (process(base_directory)) {
+ return 1;
+ }
+
+ TALLOC_FREE(frame);
+ return rc;
+}
diff --git a/source3/client/client_proto.h b/source3/client/client_proto.h
new file mode 100644
index 0000000000..aa3eb0e8af
--- /dev/null
+++ b/source3/client/client_proto.h
@@ -0,0 +1,52 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * collected prototypes header
+ *
+ * frozen from "make proto" in May 2008
+ *
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CLIENT_PROTO_H_
+#define _CLIENT_PROTO_H_
+
+
+/* The following definitions come from client/client.c */
+
+const char *client_get_cur_dir(void);
+const char *client_set_cur_dir(const char *newdir);
+void do_list(const char *mask,
+ uint16 attribute,
+ void (*fn)(file_info *, const char *dir),
+ bool rec,
+ bool dirs);
+int cmd_iosize(void);
+
+/* The following definitions come from client/clitar.c */
+
+int cmd_block(void);
+int cmd_tarmode(void);
+int cmd_setmode(void);
+int cmd_tar(void);
+int process_tar(void);
+int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind);
+
+/* The following definitions come from client/dnsbrowse.c */
+
+int do_smb_browse(void);
+int do_smb_browse(void);
+
+#endif /* _CLIENT_PROTO_H_ */
diff --git a/source3/client/clitar.c b/source3/client/clitar.c
new file mode 100644
index 0000000000..084f87e399
--- /dev/null
+++ b/source3/client/clitar.c
@@ -0,0 +1,1921 @@
+/*
+ Unix SMB/CIFS implementation.
+ Tar Extensions
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/* 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"
+#include "client/client_proto.h"
+
+static int clipfind(char **aret, int ret, char *tok);
+
+typedef struct file_info_struct file_info2;
+
+struct file_info_struct {
+ SMB_OFF_T size;
+ uint16 mode;
+ uid_t uid;
+ gid_t gid;
+ /* These times are normally kept in GMT */
+ struct timespec mtime_ts;
+ struct timespec atime_ts;
+ struct timespec ctime_ts;
+ char *name; /* This is dynamically allocated */
+ file_info2 *next, *prev; /* Used in the stack ... */
+};
+
+typedef struct {
+ file_info2 *top;
+ int items;
+} stack;
+
+#define SEPARATORS " \t\n\r"
+extern time_t newer_than;
+extern struct cli_state *cli;
+
+/* These defines are for the do_setrattr routine, to indicate
+ * setting and reseting of file attributes in the function call */
+#define ATTRSET 1
+#define ATTRRESET 0
+
+static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
+
+#ifndef CLIENT_TIMEOUT
+#define CLIENT_TIMEOUT (30*1000)
+#endif
+
+static char *tarbuf, *buffer_p;
+static int tp, ntarf, tbufsiz;
+static double ttarf;
+/* Incremental mode */
+static bool tar_inc=False;
+/* Reset archive bit */
+static bool tar_reset=False;
+/* Include / exclude mode (true=include, false=exclude) */
+static bool tar_excl=True;
+/* use regular expressions for search on file names */
+static bool tar_re_search=False;
+/* Do not dump anything, just calculate sizes */
+static bool dry_run=False;
+/* Dump files with System attribute */
+static bool tar_system=True;
+/* Dump files with Hidden attribute */
+static bool tar_hidden=True;
+/* Be noisy - make a catalogue */
+static bool tar_noisy=True;
+static 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 const char *cmd_ptr;
+
+extern bool lowercase;
+extern uint16 cnum;
+extern bool readbraw_supported;
+extern int max_xmit;
+extern int get_total_time_ms;
+extern int get_total_size;
+
+static int blocksize=20;
+static int tarhandle;
+
+static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
+ const char *amode, unsigned char ftype);
+static void do_atar(const char *rname_in,char *lname,file_info *finfo1);
+static void do_tar(file_info *finfo, const char *dir);
+static void oct_it(SMB_BIG_UINT value, int ndgs, char *p);
+static void fixtarname(char *tptr, const char *fp, size_t l);
+static int dotarbuf(int f, char *b, int n);
+static void dozerobuf(int f, int n);
+static void dotareof(int f);
+static void initarbuf(void);
+
+/* restore functions */
+static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix);
+static long unoct(char *p, int ndgs);
+static void do_tarput(void);
+static void unfixtarname(char *tptr, char *fp, int l, bool first);
+
+/*
+ * tar specific utitlities
+ */
+
+/*******************************************************************
+Create a string of size size+1 (for the null)
+*******************************************************************/
+
+static char *string_create_s(int size)
+{
+ char *tmp;
+
+ tmp = (char *)SMB_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, const char *aname, SMB_BIG_UINT size, time_t mtime,
+ const char *amode, unsigned char ftype)
+{
+ union hblock hb;
+ int i, chk, l;
+ char *jp;
+
+ DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
+
+ memset(hb.dummy, 0, sizeof(hb.dummy));
+
+ l=strlen(aname);
+ /* We will be prepending a '.' in fixtarheader so use +2 to
+ * take care of the . and terminating zero. JRA.
+ */
+ if (l+2 >= NAMSIZ) {
+ /* write a GNU tar style long header */
+ char *b;
+ b = (char *)SMB_MALLOC(l+TBLOCK+100);
+ if (!b) {
+ DEBUG(0,("out of memory\n"));
+ exit(1);
+ }
+ writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
+ memset(b, 0, l+TBLOCK+100);
+ fixtarname(b, aname, l+2);
+ i = strlen(b)+1;
+ DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
+ dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
+ SAFE_FREE(b);
+ }
+
+ fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
+
+ if (lowercase)
+ strlower_m(hb.dbuf.name);
+
+ /* write out a "standard" tar format header */
+
+ hb.dbuf.name[NAMSIZ-1]='\0';
+ safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
+ oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.uid);
+ oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.gid);
+ oct_it((SMB_BIG_UINT) size, 13, hb.dbuf.size);
+ if (size > (SMB_BIG_UINT)077777777777LL) {
+ /* This is a non-POSIX compatible extention to store files
+ greater than 8GB. */
+
+ memset(hb.dbuf.size, 0, 4);
+ hb.dbuf.size[0]=128;
+ for (i = 8, jp=(char*)&size; i; i--)
+ hb.dbuf.size[i+3] = *(jp++);
+ }
+ oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
+ memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
+ 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++);
+
+ oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
+ hb.dbuf.chksum[6] = '\0';
+
+ (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
+}
+
+/****************************************************************************
+Read a tar header into a hblock structure, and validate
+***************************************************************************/
+
+static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix)
+{
+ long chk, fchk;
+ int i;
+ char *jp;
+
+ /*
+ * read in a "standard" tar format header - we're not that interested
+ * in that many fields, though
+ */
+
+ /* check the checksum */
+ for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
+ chk+=(0xFF & *jp++);
+
+ if (chk == 0)
+ return chk;
+
+ /* compensate for blanks in chksum header */
+ for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
+ chk-=(0xFF & *jp++);
+
+ chk += ' ' * sizeof(hb->dbuf.chksum);
+
+ fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
+
+ 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 %ld %ld\n", fchk, chk));
+ dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3);
+ return -1;
+ }
+
+ 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, True);
+
+ /* 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 {
+ 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;
+ }
+ }
+ }
+
+ if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
+ (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
+ finfo->mode=aDIR;
+ } else {
+ finfo->mode=0; /* we don't care about mode at the moment, we'll
+ * just make it a regular file */
+ }
+
+ /*
+ * Bug fix by richard@sj.co.uk
+ *
+ * REC: restore times correctly (as does tar)
+ * We only get the modification time of the file; set the creation time
+ * from the mod. time, and the access time to current time
+ */
+ finfo->mtime_ts = finfo->ctime_ts =
+ convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
+ finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
+ finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
+
+ return True;
+}
+
+/****************************************************************************
+Write out the tar buffer to tape or wherever
+****************************************************************************/
+
+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) {
+ int diff;
+
+ diff=tbufsiz-tp;
+ memcpy(tarbuf + tp, b, diff);
+ fail=fail && (1+write(f, tarbuf, tbufsiz));
+ n-=diff;
+ b+=diff;
+ tp=0;
+
+ while (n >= tbufsiz) {
+ fail=fail && (1 + write(f, b, tbufsiz));
+ n-=tbufsiz;
+ b+=tbufsiz;
+ }
+ }
+
+ if (n>0) {
+ memcpy(tarbuf+tp, b, n);
+ tp+=n;
+ }
+
+ return(fail ? writ : 0);
+}
+
+/****************************************************************************
+Write zeros to buffer / tape
+****************************************************************************/
+
+static void dozerobuf(int f, int n)
+{
+ /* short routine just to write out n zeros to buffer -
+ * 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));
+ } else {
+ memset(tarbuf+tp, 0, n);
+ tp+=n;
+ }
+}
+
+/****************************************************************************
+Malloc tape buffer
+****************************************************************************/
+
+static void initarbuf(void)
+{
+ /* initialize tar buffer */
+ tbufsiz=blocksize*TBLOCK;
+ tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
+
+ /* reset tar buffer pointer and tar file counter and total dumped */
+ tp=0; ntarf=0; ttarf=0;
+}
+
+/****************************************************************************
+Write two zero blocks at end of file
+****************************************************************************/
+
+static void dotareof(int f)
+{
+ 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 (sys_fstat(f, &stbuf) == -1) {
+ DEBUG(0, ("Couldn't stat file handle\n"));
+ return;
+ }
+
+ /* Could be a pipe, in which case S_ISREG should fail,
+ * and we should write out at full size */
+ if (tp > 0)
+ write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
+}
+
+/****************************************************************************
+(Un)mangle DOS pathname, make nonabsolute
+****************************************************************************/
+
+static void fixtarname(char *tptr, const char *fp, size_t l)
+{
+ /* add a '.' to start of file name, convert from ugly dos \'s in path
+ * to lovely unix /'s :-} */
+ *tptr++='.';
+ l--;
+
+ StrnCpy(tptr, fp, l-1);
+ string_replace(tptr, '\\', '/');
+}
+
+/****************************************************************************
+Convert from decimal to octal string
+****************************************************************************/
+
+static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
+{
+ /* Converts long to octal string, pads with leading zeros */
+
+ /* skip final null, but do final space */
+ --ndgs;
+ p[--ndgs] = ' ';
+
+ /* Loop does at least one digit */
+ do {
+ p[--ndgs] = '0' + (char) (value & 7);
+ value >>= 3;
+ } while (ndgs > 0 && value != 0);
+
+ /* Do leading zeros */
+ while (ndgs > 0)
+ p[--ndgs] = '0';
+}
+
+/****************************************************************************
+Convert from octal string to long
+***************************************************************************/
+
+static long unoct(char *p, int ndgs)
+{
+ long value=0;
+ /* Converts octal string to long, ignoring any non-digit */
+
+ while (--ndgs) {
+ if (isdigit((int)*p))
+ value = (value << 3) | (long) (*p - '0');
+
+ p++;
+ }
+
+ return value;
+}
+
+/****************************************************************************
+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.
+***************************************************************************/
+
+static int strslashcmp(char *s1, char *s2)
+{
+ char *s1_0=s1;
+
+ while(*s1 && *s2 && (*s1 == *s2 || tolower_ascii(*s1) == tolower_ascii(*s2) ||
+ (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *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 == '\\') && !*s1)
+ return 0;
+
+ return *s1-*s2;
+}
+
+/****************************************************************************
+Ensure a remote path exists (make if necessary)
+***************************************************************************/
+
+static bool ensurepath(const char *fname)
+{
+ /* *must* be called with buffer ready malloc'ed */
+ /* ensures path exists */
+
+ char *partpath, *ffname;
+ const char *p=fname;
+ char *basehack;
+ char *saveptr;
+
+ 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));
+ SAFE_FREE(partpath);
+ SAFE_FREE(ffname);
+ return(False);
+ }
+
+ *partpath = 0;
+
+ /* fname copied to ffname so can strtok_r */
+
+ safe_strcpy(ffname, fname, strlen(fname));
+
+ /* do a `basename' on ffname, so don't try and make file name directory */
+ if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
+ SAFE_FREE(partpath);
+ SAFE_FREE(ffname);
+ return True;
+ } else {
+ *basehack='\0';
+ }
+
+ p=strtok_r(ffname, "\\", &saveptr);
+
+ while (p) {
+ safe_strcat(partpath, p, strlen(fname) + 1);
+
+ if (!cli_chkpath(cli, partpath)) {
+ if (!cli_mkdir(cli, partpath)) {
+ SAFE_FREE(partpath);
+ SAFE_FREE(ffname);
+ DEBUG(0, ("Error mkdir %s\n", cli_errstr(cli)));
+ return False;
+ } else {
+ DEBUG(3, ("mkdirhiering %s\n", partpath));
+ }
+ }
+
+ safe_strcat(partpath, "\\", strlen(fname) + 1);
+ p = strtok_r(NULL, "/\\", &saveptr);
+ }
+
+ SAFE_FREE(partpath);
+ SAFE_FREE(ffname);
+ return True;
+}
+
+static int padit(char *buf, SMB_BIG_UINT bufsize, SMB_BIG_UINT padsize)
+{
+ int berr= 0;
+ int bytestowrite;
+
+ DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
+ memset(buf, 0, (size_t)bufsize);
+ while( !berr && padsize > 0 ) {
+ bytestowrite= (int)MIN(bufsize, padsize);
+ berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
+ padsize -= bytestowrite;
+ }
+
+ return berr;
+}
+
+static void do_setrattr(char *name, uint16 attr, int set)
+{
+ uint16 oldattr;
+
+ if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
+
+ if (set == ATTRSET) {
+ attr |= oldattr;
+ } else {
+ attr = oldattr & ~attr;
+ }
+
+ if (!cli_setatr(cli, name, attr, 0)) {
+ DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
+ }
+}
+
+/****************************************************************************
+append one remote file to the tar file
+***************************************************************************/
+
+static void do_atar(const char *rname_in,char *lname,file_info *finfo1)
+{
+ int fnum = -1;
+ SMB_BIG_UINT nread=0;
+ char ftype;
+ file_info2 finfo;
+ bool shallitime=True;
+ char *data = NULL;
+ int read_size = 65520;
+ int datalen=0;
+ char *rname = NULL;
+ TALLOC_CTX *ctx = talloc_stackframe();
+
+ struct timeval tp_start;
+
+ GetTimeOfDay(&tp_start);
+
+ data = SMB_MALLOC_ARRAY(char, read_size);
+ if (!data) {
+ DEBUG(0,("do_atar: out of memory.\n"));
+ goto cleanup;
+ }
+
+ ftype = '0'; /* An ordinary file ... */
+
+ ZERO_STRUCT(finfo);
+
+ finfo.size = finfo1 -> size;
+ finfo.mode = finfo1 -> mode;
+ finfo.uid = finfo1 -> uid;
+ finfo.gid = finfo1 -> gid;
+ finfo.mtime_ts = finfo1 -> mtime_ts;
+ finfo.atime_ts = finfo1 -> atime_ts;
+ finfo.ctime_ts = finfo1 -> ctime_ts;
+
+ if (dry_run) {
+ DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
+ (double)finfo.size));
+ shallitime=0;
+ ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
+ ntarf++;
+ goto cleanup;
+ }
+
+ rname = clean_name(ctx, rname_in);
+ if (!rname) {
+ goto cleanup;
+ }
+
+ fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
+
+ if (fnum == -1) {
+ DEBUG(0,("%s opening remote file %s (%s)\n",
+ cli_errstr(cli),rname, client_get_cur_dir()));
+ goto cleanup;
+ }
+
+ finfo.name = string_create_s(strlen(rname));
+ if (finfo.name == NULL) {
+ DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
+ goto cleanup;
+ }
+
+ safe_strcpy(finfo.name,rname, strlen(rname));
+
+ DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
+
+ if (tar_inc && !(finfo.mode & aARCH)) {
+ DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
+ shallitime=0;
+ } else if (!tar_system && (finfo.mode & aSYSTEM)) {
+ DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
+ shallitime=0;
+ } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
+ DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
+ shallitime=0;
+ } else {
+ bool wrote_tar_header = False;
+
+ DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
+ finfo.name, (double)finfo.size, lname));
+
+ do {
+
+ DEBUG(3,("nread=%.0f\n",(double)nread));
+
+ datalen = cli_read(cli, fnum, data, nread, read_size);
+
+ if (datalen == -1) {
+ DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
+ break;
+ }
+
+ nread += datalen;
+
+ /* Only if the first read succeeds, write out the tar header. */
+ if (!wrote_tar_header) {
+ /* write a tar header, don't bother with mode - just set to 100644 */
+ writetarheader(tarhandle, rname, finfo.size,
+ finfo.mtime_ts.tv_sec, "100644 \0", ftype);
+ wrote_tar_header = True;
+ }
+
+ /* if file size has increased since we made file size query, truncate
+ read so tar header for this file will be correct.
+ */
+
+ if (nread > finfo.size) {
+ datalen -= nread - finfo.size;
+ DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
+ finfo.name, (double)finfo.size));
+ }
+
+ /* add received bits of file to buffer - dotarbuf will
+ * write out in 512 byte intervals */
+
+ if (dotarbuf(tarhandle,data,datalen) != datalen) {
+ DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
+ break;
+ }
+
+ if ( (datalen == 0) && (finfo.size != 0) ) {
+ DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
+ break;
+ }
+
+ datalen=0;
+ } while ( nread < finfo.size );
+
+ if (wrote_tar_header) {
+ /* 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=%.0f, nread=%d\n",
+ (double)finfo.size, (int)nread));
+ if (padit(data, (SMB_BIG_UINT)sizeof(data), finfo.size - nread))
+ DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
+ }
+
+ /* round tar file to nearest block */
+ if (finfo.size % TBLOCK)
+ dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
+
+ ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
+ ntarf++;
+ } else {
+ DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
+ shallitime=0;
+ }
+ }
+
+ cli_close(cli, fnum);
+ fnum = -1;
+
+ if (shallitime) {
+ struct timeval tp_end;
+ int this_time;
+
+ /* if shallitime is true then we didn't skip */
+ if (tar_reset && !dry_run)
+ (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
+
+ GetTimeOfDay(&tp_end);
+ this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
+ get_total_time_ms += this_time;
+ get_total_size += finfo.size;
+
+ if (tar_noisy) {
+ DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
+ (double)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(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))));
+ }
+
+ cleanup:
+
+ if (fnum != -1) {
+ cli_close(cli, fnum);
+ fnum = -1;
+ }
+ TALLOC_FREE(ctx);
+ SAFE_FREE(data);
+}
+
+/****************************************************************************
+Append single file to tar file (or not)
+***************************************************************************/
+
+static void do_tar(file_info *finfo, const char *dir)
+{
+ TALLOC_CTX *ctx = talloc_stackframe();
+
+ if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
+ return;
+
+ /* Is it on the exclude list ? */
+ if (!tar_excl && clipn) {
+ char *exclaim;
+
+ DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
+
+ exclaim = talloc_asprintf(ctx,
+ "%s\\%s",
+ client_get_cur_dir(),
+ finfo->name);
+ if (!exclaim) {
+ return;
+ }
+
+ DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
+
+ if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
+ (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
+ DEBUG(3,("Skipping file %s\n", exclaim));
+ TALLOC_FREE(exclaim);
+ return;
+ }
+ TALLOC_FREE(exclaim);
+ }
+
+ if (finfo->mode & aDIR) {
+ char *saved_curdir = NULL;
+ char *new_cd = NULL;
+ char *mtar_mask = NULL;
+
+ saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
+ if (!saved_curdir) {
+ return;
+ }
+
+ DEBUG(5, ("strlen(cur_dir)=%d, \
+strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
+ (int)strlen(saved_curdir),
+ (int)strlen(finfo->name), finfo->name, saved_curdir));
+
+ new_cd = talloc_asprintf(ctx,
+ "%s%s\\",
+ client_get_cur_dir(),
+ finfo->name);
+ if (!new_cd) {
+ return;
+ }
+ client_set_cur_dir(new_cd);
+
+ DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
+
+ /* write a tar directory, don't bother with mode - just
+ * set it to 40755 */
+ writetarheader(tarhandle, client_get_cur_dir(), 0,
+ finfo->mtime_ts.tv_sec, "040755 \0", '5');
+ if (tar_noisy) {
+ DEBUG(0,(" directory %s\n",
+ client_get_cur_dir()));
+ }
+ ntarf++; /* Make sure we have a file on there */
+ mtar_mask = talloc_asprintf(ctx,
+ "%s*",
+ client_get_cur_dir());
+ if (!mtar_mask) {
+ return;
+ }
+ DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
+ do_list(mtar_mask, attribute, do_tar, False, True);
+ client_set_cur_dir(saved_curdir);
+ TALLOC_FREE(saved_curdir);
+ TALLOC_FREE(new_cd);
+ TALLOC_FREE(mtar_mask);
+ } else {
+ char *rname = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ finfo->name);
+ if (!rname) {
+ return;
+ }
+ do_atar(rname,finfo->name,finfo);
+ TALLOC_FREE(rname);
+ }
+}
+
+/****************************************************************************
+Convert from UNIX to DOS file names
+***************************************************************************/
+
+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. But only if first!
+ */
+
+ DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
+
+ if (first) {
+ if (*fp == '.') {
+ fp++;
+ l--;
+ }
+ if (*fp == '\\' || *fp == '/') {
+ fp++;
+ l--;
+ }
+ }
+
+ safe_strcpy(tptr, fp, l);
+ string_replace(tptr, '/', '\\');
+}
+
+/****************************************************************************
+Move to the next block in the buffer, which may mean read in another set of
+blocks. FIXME, we should allow more than one block to be skipped.
+****************************************************************************/
+
+static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
+{
+ int bufread, total = 0;
+
+ DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
+ *bufferp += TBLOCK;
+ total = TBLOCK;
+
+ if (*bufferp >= (ltarbuf + bufsiz)) {
+
+ DEBUG(5, ("Reading more data into ltarbuf ...\n"));
+
+ /*
+ * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
+ * Fixes bug where read can return short if coming from
+ * a pipe.
+ */
+
+ bufread = read(tarhandle, ltarbuf, bufsiz);
+ total = bufread;
+
+ while (total < bufsiz) {
+ if (bufread < 0) { /* An error, return false */
+ return (total > 0 ? -2 : bufread);
+ }
+ if (bufread == 0) {
+ if (total <= 0) {
+ return -2;
+ }
+ break;
+ }
+ bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
+ total += bufread;
+ }
+
+ DEBUG(5, ("Total bytes read ... %i\n", total));
+
+ *bufferp = ltarbuf;
+ }
+
+ 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);
+}
+
+/*************************************************************
+ Get a file from the tar file and store it.
+ When this is called, tarbuf already contains the first
+ file block. This is a bit broken & needs fixing.
+**************************************************************/
+
+static int get_file(file_info2 finfo)
+{
+ int fnum = -1, pos = 0, dsize = 0, bpos = 0;
+ SMB_BIG_UINT rsize = 0;
+
+ DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
+
+ if (ensurepath(finfo.name) &&
+ (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
+ DEBUG(0, ("abandoning restore\n"));
+ return(False);
+ }
+
+ /* read the blocks from the tar file and write to the remote file */
+
+ rsize = finfo.size; /* This is how much to write */
+
+ while (rsize > 0) {
+
+ /* We can only write up to the end of the buffer */
+ dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
+ dsize = MIN(dsize, rsize); /* Should be only what is left */
+ DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
+
+ if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
+ DEBUG(0, ("Error writing remote file\n"));
+ return 0;
+ }
+
+ rsize -= dsize;
+ pos += dsize;
+
+ /* Now figure out how much to move in the buffer */
+
+ /* FIXME, we should skip more than one block at a time */
+
+ /* First, skip any initial part of the part written that is left over */
+ /* from the end of the first TBLOCK */
+
+ if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
+ dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
+ bpos = 0;
+
+ if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
+ DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
+ return False;
+ }
+ }
+
+ /*
+ * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
+ * If the file being extracted is an exact multiple of
+ * TBLOCK bytes then we don't want to extract the next
+ * block from the tarfile here, as it will be done in
+ * the caller of get_file().
+ */
+
+ while (((rsize != 0) && (dsize >= TBLOCK)) ||
+ ((rsize == 0) && (dsize > TBLOCK))) {
+
+ if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
+ DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
+ return False;
+ }
+
+ dsize -= TBLOCK;
+ }
+ bpos = dsize;
+ }
+
+ /* Now close the file ... */
+
+ if (!cli_close(cli, fnum)) {
+ DEBUG(0, ("Error closing remote file\n"));
+ return(False);
+ }
+
+ /* Now we update the creation date ... */
+ DEBUG(5, ("Updating creation date on %s\n", finfo.name));
+
+ if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec)) {
+ 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 %.0f bytes\n", finfo.name, (double)finfo.size));
+ return(True);
+}
+
+/* Create a directory. We just ensure that the path exists and return as there
+ is no file associated with a directory
+*/
+static int get_dir(file_info2 finfo)
+{
+ DEBUG(0, ("restore directory %s\n", finfo.name));
+
+ if (!ensurepath(finfo.name)) {
+ DEBUG(0, ("Problems creating directory\n"));
+ return(False);
+ }
+ ntarf++;
+ return(True);
+}
+
+/* Get a file with a long file name ... first file has file name, next file
+ has the data. We only want the long file name, as the loop in do_tarput
+ will deal with the rest.
+*/
+static char *get_longfilename(file_info2 finfo)
+{
+ /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
+ * header call. */
+ int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
+ char *longname = (char *)SMB_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 = %.0f\n", (double)finfo.size));
+
+ if (longname == NULL) {
+ DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
+ return(NULL);
+ }
+
+ /* First, add cur_dir to the long file name */
+
+ if (strlen(client_get_cur_dir()) > 0) {
+ strncpy(longname, client_get_cur_dir(), namesize);
+ offset = strlen(client_get_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)));
+ SAFE_FREE(longname);
+ 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 *longfilename = NULL, linkflag;
+ int skip = False;
+
+ ZERO_STRUCT(finfo);
+
+ GetTimeOfDay(&tp_start);
+ DEBUG(5, ("RJS do_tarput called ...\n"));
+
+ buffer_p = tarbuf + tbufsiz; /* init this to force first read */
+
+ /* Now read through those files ... */
+ while (True) {
+ /* Get us to the next block, or the first block first time around */
+ if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
+ DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
+ SAFE_FREE(longfilename);
+ return;
+ }
+
+ DEBUG(5, ("Reading the next header ...\n"));
+
+ switch (readtarheader((union hblock *) buffer_p,
+ &finfo, client_get_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"));
+ return;
+ }
+ break;
+
+ case -1:
+ DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
+ return;
+
+ case 0: /* chksum is zero - looks like an EOF */
+ DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
+ return; /* Hmmm, bad here ... */
+
+ default:
+ /* No action */
+ break;
+ }
+
+ /* Now, do we have a long file name? */
+ if (longfilename != NULL) {
+ SAFE_FREE(finfo.name); /* Free the space already allocated */
+ finfo.name = longfilename;
+ longfilename = NULL;
+ }
+
+ /* 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) ||
+ (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
+
+ DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
+ if (skip) {
+ skip_file(finfo.size);
+ continue;
+ }
+
+ /* We only get this far if we should process the file */
+ linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
+ switch (linkflag) {
+ case '0': /* Should use symbolic names--FIXME */
+ /*
+ * Skip to the next block first, so we can get the file, FIXME, should
+ * be in get_file ...
+ * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
+ * Fixes bug where file size in tarfile is zero.
+ */
+ if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
+ DEBUG(0, ("Short file, bailing out...\n"));
+ return;
+ }
+ if (!get_file(finfo)) {
+ DEBUG(0, ("Abandoning restore\n"));
+ return;
+ }
+ break;
+ case '5':
+ if (!get_dir(finfo)) {
+ DEBUG(0, ("Abandoning restore \n"));
+ return;
+ }
+ break;
+ case 'L':
+ SAFE_FREE(longfilename);
+ longfilename = get_longfilename(finfo);
+ if (!longfilename) {
+ DEBUG(0, ("abandoning restore\n"));
+ return;
+ }
+ DEBUG(5, ("Long file name: %s\n", longfilename));
+ break;
+
+ default:
+ skip_file(finfo.size); /* Don't handle these yet */
+ break;
+ }
+ }
+}
+
+/*
+ * samba interactive commands
+ */
+
+/****************************************************************************
+Blocksize command
+***************************************************************************/
+
+int cmd_block(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *buf;
+ int block;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ DEBUG(0, ("blocksize <n>\n"));
+ return 1;
+ }
+
+ block=atoi(buf);
+ if (block < 0 || block > 65535) {
+ DEBUG(0, ("blocksize out of range"));
+ return 1;
+ }
+
+ blocksize=block;
+ DEBUG(2,("blocksize is now %d\n", blocksize));
+ return 0;
+}
+
+/****************************************************************************
+command to set incremental / reset mode
+***************************************************************************/
+
+int cmd_tarmode(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *buf;
+
+ while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ if (strequal(buf, "full"))
+ tar_inc=False;
+ else if (strequal(buf, "inc"))
+ tar_inc=True;
+ else if (strequal(buf, "reset"))
+ 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));
+ TALLOC_FREE(buf);
+ }
+
+ DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
+ tar_inc ? "incremental" : "full",
+ tar_system ? "system" : "nosystem",
+ tar_hidden ? "hidden" : "nohidden",
+ tar_reset ? "reset" : "noreset",
+ tar_noisy ? "verbose" : "quiet"));
+ return 0;
+}
+
+/****************************************************************************
+Feeble attrib command
+***************************************************************************/
+
+int cmd_setmode(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *q;
+ char *buf;
+ char *fname = NULL;
+ uint16 attra[2];
+ int direct=1;
+
+ attra[0] = attra[1] = 0;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
+ return 1;
+ }
+
+ fname = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf);
+ if (!fname) {
+ return 1;
+ }
+
+ while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ q=buf;
+
+ while(*q) {
+ switch (*q++) {
+ case '+':
+ direct=1;
+ break;
+ case '-':
+ direct=0;
+ break;
+ case 'r':
+ attra[direct]|=aRONLY;
+ break;
+ case 'h':
+ attra[direct]|=aHIDDEN;
+ break;
+ case 's':
+ attra[direct]|=aSYSTEM;
+ break;
+ case 'a':
+ attra[direct]|=aARCH;
+ break;
+ default:
+ DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
+ return 1;
+ }
+ }
+ }
+
+ if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
+ DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
+ return 1;
+ }
+
+ DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
+ do_setrattr(fname, attra[ATTRSET], ATTRSET);
+ do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
+ return 0;
+}
+
+/**
+ Convert list of tokens to array; dependent on above routine.
+ Uses the global cmd_ptr from above - bit of a hack.
+**/
+
+static char **toktocliplist(int *ctok, const char *sep)
+{
+ char *s=(char *)cmd_ptr;
+ int ictok=0;
+ char **ret, **iret;
+
+ if (!sep)
+ sep = " \t\n\r";
+
+ while(*s && strchr_m(sep,*s))
+ s++;
+
+ /* nothing left? */
+ if (!*s)
+ return(NULL);
+
+ do {
+ ictok++;
+ while(*s && (!strchr_m(sep,*s)))
+ s++;
+ while(*s && strchr_m(sep,*s))
+ *s++=0;
+ } while(*s);
+
+ *ctok=ictok;
+ s=(char *)cmd_ptr;
+
+ if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
+ return NULL;
+
+ while(ictok--) {
+ *iret++=s;
+ if (ictok > 0) {
+ while(*s++)
+ ;
+ while(!*s)
+ s++;
+ }
+ }
+
+ ret[*ctok] = NULL;
+ return ret;
+}
+
+/****************************************************************************
+Principal command for creating / extracting
+***************************************************************************/
+
+int cmd_tar(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *buf;
+ char **argl = NULL;
+ int argcl = 0;
+ int ret;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+ DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
+ return 1;
+ }
+
+ argl=toktocliplist(&argcl, NULL);
+ if (!tar_parseargs(argcl, argl, buf, 0)) {
+ SAFE_FREE(argl);
+ return 1;
+ }
+
+ ret = process_tar();
+ SAFE_FREE(argl);
+ return ret;
+}
+
+/****************************************************************************
+Command line (option) version
+***************************************************************************/
+
+int process_tar(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ int rc = 0;
+ initarbuf();
+ switch(tar_type) {
+ case 'x':
+
+#if 0
+ do_tarput2();
+#else
+ do_tarput();
+#endif
+ SAFE_FREE(tarbuf);
+ close(tarhandle);
+ break;
+ case 'r':
+ case 'c':
+ if (clipn && tar_excl) {
+ int i;
+ char *tarmac = NULL;
+
+ for (i=0; i<clipn; i++) {
+ DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
+
+ if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
+ *(cliplist[i]+strlen(cliplist[i])-1)='\0';
+ }
+
+ if (strrchr_m(cliplist[i], '\\')) {
+ char *p;
+ char *saved_dir = talloc_strdup(ctx,
+ client_get_cur_dir());
+ if (!saved_dir) {
+ return 1;
+ }
+
+ if (*cliplist[i]=='\\') {
+ tarmac = talloc_strdup(ctx,
+ cliplist[i]);
+ } else {
+ tarmac = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ cliplist[i]);
+ }
+ if (!tarmac) {
+ return 1;
+ }
+ p = strrchr_m(tarmac, '\\');
+ if (!p) {
+ return 1;
+ }
+ p[1] = '\0';
+ client_set_cur_dir(tarmac);
+
+ DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
+ do_list(tarmac,attribute,do_tar, False, True);
+
+ client_set_cur_dir(saved_dir);
+
+ TALLOC_FREE(saved_dir);
+ TALLOC_FREE(tarmac);
+ } else {
+ tarmac = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ cliplist[i]);
+ if (!tarmac) {
+ return 1;
+ }
+ DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
+ do_list(tarmac,attribute,do_tar, False, True);
+ TALLOC_FREE(tarmac);
+ }
+ }
+ } else {
+ char *mask = talloc_asprintf(ctx,
+ "%s\\*",
+ client_get_cur_dir());
+ if (!mask) {
+ return 1;
+ }
+ DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
+ do_list(mask,attribute,do_tar,False, True);
+ TALLOC_FREE(mask);
+ }
+
+ if (ntarf) {
+ dotareof(tarhandle);
+ }
+ close(tarhandle);
+ SAFE_FREE(tarbuf);
+
+ DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
+ DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
+ break;
+ }
+
+ if (must_free_cliplist) {
+ int i;
+ for (i = 0; i < clipn; ++i) {
+ SAFE_FREE(cliplist[i]);
+ }
+ SAFE_FREE(cliplist);
+ cliplist = NULL;
+ clipn = 0;
+ must_free_cliplist = False;
+ }
+ return rc;
+}
+
+/****************************************************************************
+Find a token (filename) in a clip list
+***************************************************************************/
+
+static int clipfind(char **aret, int ret, char *tok)
+{
+ if (aret==NULL)
+ return 0;
+
+ /* ignore leading slashes or dots in token */
+ while(strchr_m("/\\.", *tok))
+ tok++;
+
+ while(ret--) {
+ char *pkey=*aret++;
+
+ /* ignore leading slashes or dots in list */
+ while(strchr_m("/\\.", *pkey))
+ pkey++;
+
+ if (!strslashcmp(pkey, tok))
+ return 1;
+ }
+ return 0;
+}
+
+/****************************************************************************
+Read list of files to include from the file and initialize cliplist
+accordingly.
+***************************************************************************/
+
+static int read_inclusion_file(char *filename)
+{
+ XFILE *inclusion = NULL;
+ char buf[PATH_MAX + 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[PATH_MAX] = '\0'; /* guarantee null-termination */
+ if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
+ /* XXX It would be better to include a reason for failure, but without
+ * autoconf, it's hard to use strerror, sys_errlist, etc.
+ */
+ DEBUG(0,("Unable to open inclusion file %s\n", filename));
+ return 0;
+ }
+
+ while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
+ if (inclusion_buffer == NULL) {
+ inclusion_buffer_size = 1024;
+ if ((inclusion_buffer = (char *)SMB_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 = (char *)SMB_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++;
+ }
+ x_fclose(inclusion);
+
+ if (! error) {
+ /* Allocate an array of clipn + 1 char*'s for cliplist */
+ cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
+ 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 *)SMB_MALLOC(strlen(p)+1)) == NULL) {
+ DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
+ error = 1;
+ } else {
+ unfixtarname(tmpstr, p, strlen(p) + 1, True);
+ cliplist[i] = tmpstr;
+ if ((p = strchr_m(p, '\000')) == NULL) {
+ DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
+ abort();
+ }
+ }
+ ++p;
+ }
+ must_free_cliplist = True;
+ }
+ }
+
+ SAFE_FREE(inclusion_buffer);
+ if (error) {
+ if (cliplist) {
+ char **pp;
+ /* We know cliplist is always null-terminated */
+ for (pp = cliplist; *pp; ++pp) {
+ SAFE_FREE(*pp);
+ }
+ SAFE_FREE(cliplist);
+ cliplist = NULL;
+ must_free_cliplist = False;
+ }
+ return 0;
+ }
+
+ /* cliplist and its elements are freed at the end of process_tar. */
+ return 1;
+}
+
+/****************************************************************************
+Parse tar arguments. Sets tar_type, tar_excl, etc.
+***************************************************************************/
+
+int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
+{
+ int newOptind = Optind;
+ char tar_clipfl='\0';
+
+ /* Reset back to defaults - could be from interactive version
+ * reset mode and archive mode left as they are though
+ */
+ tar_type='\0';
+ tar_excl=True;
+ dry_run=False;
+
+ while (*Optarg) {
+ switch(*Optarg++) {
+ case 'c':
+ tar_type='c';
+ break;
+ case 'x':
+ if (tar_type=='c') {
+ printf("Tar must be followed by only one of c or x.\n");
+ return 0;
+ }
+ tar_type='x';
+ break;
+ case 'b':
+ if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
+ DEBUG(0,("Option b must be followed by valid blocksize\n"));
+ return 0;
+ } else {
+ Optind++;
+ newOptind++;
+ }
+ break;
+ case 'g':
+ tar_inc=True;
+ break;
+ case 'N':
+ if (Optind>=argc) {
+ DEBUG(0,("Option N must be followed by valid file name\n"));
+ return 0;
+ } else {
+ SMB_STRUCT_STAT stbuf;
+
+ if (sys_stat(argv[Optind], &stbuf) == 0) {
+ newer_than = stbuf.st_mtime;
+ DEBUG(1,("Getting files newer than %s",
+ time_to_asc(newer_than)));
+ newOptind++;
+ Optind++;
+ } else {
+ DEBUG(0,("Error setting newer-than time\n"));
+ return 0;
+ }
+ }
+ break;
+ case 'a':
+ tar_reset=True;
+ break;
+ case 'q':
+ tar_noisy=False;
+ break;
+ case 'I':
+ if (tar_clipfl) {
+ 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,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;
+ }
+ }
+
+ if (!tar_type) {
+ printf("Option T must be followed by one of c or x.\n");
+ 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;
+ }
+ newOptind++;
+ /* Optind points at the tar output file, Optind+1 at the inclusion file. */
+ 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=SMB_MALLOC_ARRAY(char *,clipn)) == 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 *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
+ DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
+ SAFE_FREE(tmplist);
+ 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;
+
+ newOptind += clipn;
+ }
+
+ if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
+ /* Doing regular expression seaches not from an inclusion file. */
+ clipn=argc-Optind-1;
+ cliplist=argv+Optind+1;
+ newOptind += clipn;
+ }
+
+ if (Optind>=argc || !strcmp(argv[Optind], "-")) {
+ /* Sets tar handle to either 0 or 1, as appropriate */
+ tarhandle=(tar_type=='c');
+ /*
+ * Make sure that dbf points to stderr if we are using stdout for
+ * tar output
+ */
+ if (tarhandle == 1) {
+ dbf = x_stderr;
+ }
+ if (!argv[Optind]) {
+ DEBUG(0,("Must specify tar filename\n"));
+ return 0;
+ }
+ if (!strcmp(argv[Optind], "-")) {
+ newOptind++;
+ }
+
+ } else {
+ if (tar_type=='c' && dry_run) {
+ tarhandle=-1;
+ } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
+ || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
+ DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
+ return(0);
+ }
+ newOptind++;
+ }
+
+ return newOptind;
+}
diff --git a/source3/client/dnsbrowse.c b/source3/client/dnsbrowse.c
new file mode 100644
index 0000000000..5e3a4de9cf
--- /dev/null
+++ b/source3/client/dnsbrowse.c
@@ -0,0 +1,237 @@
+/*
+ Unix SMB/CIFS implementation.
+ DNS-SD browse client
+ Copyright (C) Rishi Srivatsavai 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "client/client_proto.h"
+
+#ifdef WITH_DNSSD_SUPPORT
+
+#include <dns_sd.h>
+
+/* Holds service instances found during DNS browse */
+struct mdns_smbsrv_result
+{
+ char *serviceName;
+ char *regType;
+ char *domain;
+ uint32_t ifIndex;
+ struct mdns_smbsrv_result *nextResult;
+};
+
+/* Maintains state during DNS browse */
+struct mdns_browse_state
+{
+ struct mdns_smbsrv_result *listhead; /* Browse result list head */
+ int browseDone;
+
+};
+
+
+static void
+do_smb_resolve_reply (DNSServiceRef sdRef, DNSServiceFlags flags,
+ uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+ const char *fullname, const char *hosttarget, uint16_t port,
+ uint16_t txtLen, const unsigned char *txtRecord, void *context)
+{
+ printf("SMB service available on %s port %u\n",
+ hosttarget, ntohs(port));
+}
+
+
+static void do_smb_resolve(struct mdns_smbsrv_result *browsesrv)
+{
+ DNSServiceRef mdns_conn_sdref = NULL;
+ int mdnsfd;
+ int fdsetsz;
+ int ret;
+ fd_set *fdset = NULL;
+ struct timeval tv;
+ DNSServiceErrorType err;
+
+ TALLOC_CTX * ctx = talloc_tos();
+
+ err = DNSServiceResolve(&mdns_conn_sdref, 0 /* flags */,
+ browsesrv->ifIndex,
+ browsesrv->serviceName, browsesrv->regType, browsesrv->domain,
+ do_smb_resolve_reply, NULL);
+
+ if (err != kDNSServiceErr_NoError) {
+ return;
+ }
+
+ mdnsfd = DNSServiceRefSockFD(mdns_conn_sdref);
+ for (;;) {
+ if (fdset != NULL) {
+ TALLOC_FREE(fdset);
+ }
+
+ fdsetsz = howmany(mdnsfd + 1, NFDBITS) * sizeof(fd_mask);
+ fdset = TALLOC_ZERO(ctx, fdsetsz);
+ FD_SET(mdnsfd, fdset);
+
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+
+ /* Wait until response received from mDNS daemon */
+ ret = sys_select(mdnsfd + 1, fdset, NULL, NULL, &tv);
+ if (ret <= 0 && errno != EINTR) {
+ break;
+ }
+
+ if (FD_ISSET(mdnsfd, fdset)) {
+ /* Invoke callback function */
+ DNSServiceProcessResult(mdns_conn_sdref);
+ break;
+ }
+ }
+
+ TALLOC_FREE(fdset);
+ DNSServiceRefDeallocate(mdns_conn_sdref);
+}
+
+
+static void
+do_smb_browse_reply(DNSServiceRef sdRef, DNSServiceFlags flags,
+ uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+ const char *serviceName, const char *regtype,
+ const char *replyDomain, void *context)
+{
+ struct mdns_browse_state *bstatep = (struct mdns_browse_state *)context;
+ struct mdns_smbsrv_result *bresult;
+
+ if (bstatep == NULL) {
+ return;
+ }
+
+ if (errorCode != kDNSServiceErr_NoError) {
+ bstatep->browseDone = 1;
+ return;
+ }
+
+ if (flags & kDNSServiceFlagsMoreComing) {
+ bstatep->browseDone = 0;
+ } else {
+ bstatep->browseDone = 1;
+ }
+
+ if (!(flags & kDNSServiceFlagsAdd)) {
+ return;
+ }
+
+ bresult = TALLOC_ARRAY(talloc_tos(), struct mdns_smbsrv_result, 1);
+ if (bresult == NULL) {
+ return;
+ }
+
+ if (bstatep->listhead != NULL) {
+ bresult->nextResult = bstatep->listhead;
+ }
+
+ bresult->serviceName = talloc_strdup(talloc_tos(), serviceName);
+ bresult->regType = talloc_strdup(talloc_tos(), regtype);
+ bresult->domain = talloc_strdup(talloc_tos(), replyDomain);
+ bresult->ifIndex = interfaceIndex;
+ bstatep->listhead = bresult;
+}
+
+int do_smb_browse(void)
+{
+ int mdnsfd;
+ int fdsetsz;
+ int ret;
+ fd_set *fdset = NULL;
+ struct mdns_browse_state bstate;
+ struct mdns_smbsrv_result *resptr;
+ struct timeval tv;
+ DNSServiceRef mdns_conn_sdref = NULL;
+ DNSServiceErrorType err;
+
+ TALLOC_CTX * ctx = talloc_stackframe();
+
+ ZERO_STRUCT(bstate);
+
+ err = DNSServiceBrowse(&mdns_conn_sdref, 0, 0, "_smb._tcp", "",
+ do_smb_browse_reply, &bstate);
+
+ if (err != kDNSServiceErr_NoError) {
+ d_printf("Error connecting to the Multicast DNS daemon\n");
+ TALLOC_FREE(ctx);
+ return 1;
+ }
+
+ mdnsfd = DNSServiceRefSockFD(mdns_conn_sdref);
+ for (;;) {
+ if (fdset != NULL) {
+ TALLOC_FREE(fdset);
+ }
+
+ fdsetsz = howmany(mdnsfd + 1, NFDBITS) * sizeof(fd_mask);
+ fdset = TALLOC_ZERO(ctx, fdsetsz);
+ FD_SET(mdnsfd, fdset);
+
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+
+ /* Wait until response received from mDNS daemon */
+ ret = sys_select(mdnsfd + 1, fdset, NULL, NULL, &tv);
+ if (ret <= 0 && errno != EINTR) {
+ break;
+ }
+
+ if (FD_ISSET(mdnsfd, fdset)) {
+ /* Invoke callback function */
+ if (DNSServiceProcessResult(mdns_conn_sdref)) {
+ break;
+ }
+ if (bstate.browseDone) {
+ break;
+ }
+ }
+ }
+
+ DNSServiceRefDeallocate(mdns_conn_sdref);
+
+ if (bstate.listhead != NULL) {
+ resptr = bstate.listhead;
+ while (resptr != NULL) {
+ struct mdns_smbsrv_result *oldresptr;
+ oldresptr = resptr;
+
+ /* Resolve smb service instance */
+ do_smb_resolve(resptr);
+
+ resptr = resptr->nextResult;
+ }
+ }
+
+ TALLOC_FREE(ctx);
+ return 0;
+}
+
+#else /* WITH_DNSSD_SUPPORT */
+
+int do_smb_browse(void)
+{
+ d_printf("DNS-SD browsing is not supported on this platform\n");
+ return 1;
+}
+
+#endif /* WITH_DNSSD_SUPPORT */
+
+
diff --git a/source3/client/mount.cifs.c b/source3/client/mount.cifs.c
new file mode 100644
index 0000000000..3b56e5f861
--- /dev/null
+++ b/source3/client/mount.cifs.c
@@ -0,0 +1,1449 @@
+/*
+ Mount helper utility for Linux CIFS VFS (virtual filesystem) client
+ Copyright (C) 2003,2008 Steve French (sfrench@us.ibm.com)
+ Copyright (C) 2008 Jeremy Allison (jra@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <getopt.h>
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <mntent.h>
+#include <fcntl.h>
+#include <limits.h>
+
+#define MOUNT_CIFS_VERSION_MAJOR "1"
+#define MOUNT_CIFS_VERSION_MINOR "11"
+
+#ifndef MOUNT_CIFS_VENDOR_SUFFIX
+ #ifdef _SAMBA_BUILD_
+ #include "include/version.h"
+ #ifdef SAMBA_VERSION_VENDOR_SUFFIX
+ #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING"-"SAMBA_VERSION_VENDOR_SUFFIX
+ #else
+ #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING
+ #endif /* SAMBA_VERSION_OFFICIAL_STRING and SAMBA_VERSION_VENDOR_SUFFIX */
+ #else
+ #define MOUNT_CIFS_VENDOR_SUFFIX ""
+ #endif /* _SAMBA_BUILD_ */
+#endif /* MOUNT_CIFS_VENDOR_SUFFIX */
+
+#ifndef MS_MOVE
+#define MS_MOVE 8192
+#endif
+
+#ifndef MS_BIND
+#define MS_BIND 4096
+#endif
+
+#define MAX_UNC_LEN 1024
+
+#define CONST_DISCARD(type, ptr) ((type) ((void *) (ptr)))
+
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
+#endif
+
+#define MOUNT_PASSWD_SIZE 64
+#define DOMAIN_SIZE 64
+
+const char *thisprogram;
+int verboseflag = 0;
+static int got_password = 0;
+static int got_user = 0;
+static int got_domain = 0;
+static int got_ip = 0;
+static int got_unc = 0;
+static int got_uid = 0;
+static int got_gid = 0;
+static char * user_name = NULL;
+static char * mountpassword = NULL;
+char * domain_name = NULL;
+char * prefixpath = NULL;
+
+/* glibc doesn't have strlcpy, strlcat. Ensure we do. JRA. We
+ * don't link to libreplace so need them here. */
+
+/* like strncpy but does not 0 fill the buffer and always null
+ * terminates. bufsize is the size of the destination buffer */
+static size_t strlcpy(char *d, const char *s, size_t bufsize)
+{
+ size_t len = strlen(s);
+ size_t ret = len;
+ if (bufsize <= 0) return 0;
+ if (len >= bufsize) len = bufsize-1;
+ memcpy(d, s, len);
+ d[len] = 0;
+ return ret;
+}
+
+/* like strncat but does not 0 fill the buffer and always null
+ * terminates. bufsize is the length of the buffer, which should
+ * be one more than the maximum resulting string length */
+static size_t strlcat(char *d, const char *s, size_t bufsize)
+{
+ size_t len1 = strlen(d);
+ size_t len2 = strlen(s);
+ size_t ret = len1 + len2;
+
+ if (len1+len2 >= bufsize) {
+ if (bufsize < (len1+1)) {
+ return ret;
+ }
+ len2 = bufsize - (len1+1);
+ }
+ if (len2 > 0) {
+ memcpy(d+len1, s, len2);
+ d[len1+len2] = 0;
+ }
+ return ret;
+}
+
+/* BB finish BB
+
+ cifs_umount
+ open nofollow - avoid symlink exposure?
+ get owner of dir see if matches self or if root
+ call system(umount argv) etc.
+
+BB end finish BB */
+
+static char * check_for_domain(char **);
+
+
+static void mount_cifs_usage(void)
+{
+ printf("\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram);
+ printf("\nMount the remote target, specified as a UNC name,");
+ printf(" to a local directory.\n\nOptions:\n");
+ printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
+ printf("\nLess commonly used options:");
+ printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
+ printf("\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
+ printf("\n\tmapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
+ printf("\n\tdirectio,nounix,cifsacl,sec=<authentication mechanism>,sign");
+ printf("\n\nOptions not needed for servers supporting CIFS Unix extensions");
+ printf("\n\t(e.g. unneeded for mounts to most Samba versions):");
+ printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
+ printf("\n\nRarely used options:");
+ printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
+ printf("\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
+ printf("\n\tnointr,ignorecase,noposixpaths,noacl,prefixpath=<path>,nobrl");
+ printf("\n\tin6_addr");
+ printf("\n\nOptions are described in more detail in the manual page");
+ printf("\n\tman 8 mount.cifs\n");
+ printf("\nTo display the version number of the mount helper:");
+ printf("\n\t%s -V\n",thisprogram);
+
+ SAFE_FREE(mountpassword);
+ exit(1);
+}
+
+/* caller frees username if necessary */
+static char * getusername(void) {
+ char *username = NULL;
+ struct passwd *password = getpwuid(getuid());
+
+ if (password) {
+ username = password->pw_name;
+ }
+ return username;
+}
+
+static char * parse_cifs_url(char * unc_name)
+{
+ printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
+ return NULL;
+}
+
+static int open_cred_file(char * file_name)
+{
+ char * line_buf;
+ char * temp_val;
+ FILE * fs;
+ int i, length;
+ fs = fopen(file_name,"r");
+ if(fs == NULL)
+ return errno;
+ line_buf = (char *)malloc(4096);
+ if(line_buf == NULL) {
+ fclose(fs);
+ return ENOMEM;
+ }
+
+ while(fgets(line_buf,4096,fs)) {
+ /* parse line from credential file */
+
+ /* eat leading white space */
+ for(i=0;i<4086;i++) {
+ if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
+ break;
+ /* if whitespace - skip past it */
+ }
+ if (strncasecmp("username",line_buf+i,8) == 0) {
+ temp_val = strchr(line_buf + i,'=');
+ if(temp_val) {
+ /* go past equals sign */
+ temp_val++;
+ for(length = 0;length<4087;length++) {
+ if ((temp_val[length] == '\n')
+ || (temp_val[length] == '\0')) {
+ temp_val[length] = '\0';
+ break;
+ }
+ }
+ if(length > 4086) {
+ printf("mount.cifs failed due to malformed username in credentials file");
+ memset(line_buf,0,4096);
+ exit(1);
+ } else {
+ got_user = 1;
+ user_name = (char *)calloc(1 + length,1);
+ /* BB adding free of user_name string before exit,
+ not really necessary but would be cleaner */
+ strlcpy(user_name,temp_val, length+1);
+ }
+ }
+ } else if (strncasecmp("password",line_buf+i,8) == 0) {
+ temp_val = strchr(line_buf+i,'=');
+ if(temp_val) {
+ /* go past equals sign */
+ temp_val++;
+ for(length = 0;length<MOUNT_PASSWD_SIZE+1;length++) {
+ if ((temp_val[length] == '\n')
+ || (temp_val[length] == '\0')) {
+ temp_val[length] = '\0';
+ break;
+ }
+ }
+ if(length > MOUNT_PASSWD_SIZE) {
+ printf("mount.cifs failed: password in credentials file too long\n");
+ memset(line_buf,0, 4096);
+ exit(1);
+ } else {
+ if(mountpassword == NULL) {
+ mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
+ } else
+ memset(mountpassword,0,MOUNT_PASSWD_SIZE);
+ if(mountpassword) {
+ strlcpy(mountpassword,temp_val,MOUNT_PASSWD_SIZE+1);
+ got_password = 1;
+ }
+ }
+ }
+ } else if (strncasecmp("domain",line_buf+i,6) == 0) {
+ temp_val = strchr(line_buf+i,'=');
+ if(temp_val) {
+ /* go past equals sign */
+ temp_val++;
+ if(verboseflag)
+ printf("\nDomain %s\n",temp_val);
+ for(length = 0;length<DOMAIN_SIZE+1;length++) {
+ if ((temp_val[length] == '\n')
+ || (temp_val[length] == '\0')) {
+ temp_val[length] = '\0';
+ break;
+ }
+ }
+ if(length > DOMAIN_SIZE) {
+ printf("mount.cifs failed: domain in credentials file too long\n");
+ exit(1);
+ } else {
+ if(domain_name == NULL) {
+ domain_name = (char *)calloc(DOMAIN_SIZE+1,1);
+ } else
+ memset(domain_name,0,DOMAIN_SIZE);
+ if(domain_name) {
+ strlcpy(domain_name,temp_val,DOMAIN_SIZE+1);
+ got_domain = 1;
+ }
+ }
+ }
+ }
+
+ }
+ fclose(fs);
+ SAFE_FREE(line_buf);
+ return 0;
+}
+
+static int get_password_from_file(int file_descript, char * filename)
+{
+ int rc = 0;
+ int i;
+ char c;
+
+ if(mountpassword == NULL)
+ mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
+ else
+ memset(mountpassword, 0, MOUNT_PASSWD_SIZE);
+
+ if (mountpassword == NULL) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+
+ if(filename != NULL) {
+ file_descript = open(filename, O_RDONLY);
+ if(file_descript < 0) {
+ printf("mount.cifs failed. %s attempting to open password file %s\n",
+ strerror(errno),filename);
+ exit(1);
+ }
+ }
+ /* else file already open and fd provided */
+
+ for(i=0;i<MOUNT_PASSWD_SIZE;i++) {
+ rc = read(file_descript,&c,1);
+ if(rc < 0) {
+ printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
+ if(filename != NULL)
+ close(file_descript);
+ exit(1);
+ } else if(rc == 0) {
+ if(mountpassword[0] == 0) {
+ if(verboseflag)
+ printf("\nWarning: null password used since cifs password file empty");
+ }
+ break;
+ } else /* read valid character */ {
+ if((c == 0) || (c == '\n')) {
+ mountpassword[i] = '\0';
+ break;
+ } else
+ mountpassword[i] = c;
+ }
+ }
+ if((i == MOUNT_PASSWD_SIZE) && (verboseflag)) {
+ printf("\nWarning: password longer than %d characters specified in cifs password file",
+ MOUNT_PASSWD_SIZE);
+ }
+ got_password = 1;
+ if(filename != NULL) {
+ close(file_descript);
+ }
+
+ return rc;
+}
+
+static int parse_options(char ** optionsp, int * filesys_flags)
+{
+ const char * data;
+ char * percent_char = NULL;
+ char * value = NULL;
+ char * next_keyword = NULL;
+ char * out = NULL;
+ int out_len = 0;
+ int word_len;
+ int rc = 0;
+ char user[32];
+ char group[32];
+
+ if (!optionsp || !*optionsp)
+ return 1;
+ data = *optionsp;
+
+ if(verboseflag)
+ printf("parsing options: %s\n", data);
+
+ /* BB fixme check for separator override BB */
+
+ if (getuid()) {
+ got_uid = 1;
+ snprintf(user,sizeof(user),"%u",getuid());
+ got_gid = 1;
+ snprintf(group,sizeof(group),"%u",getgid());
+ }
+
+/* while ((data = strsep(&options, ",")) != NULL) { */
+ while(data != NULL) {
+ /* check if ends with trailing comma */
+ if(*data == 0)
+ break;
+
+ /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
+ /* data = next keyword */
+ /* value = next value ie stuff after equal sign */
+
+ next_keyword = strchr(data,','); /* BB handle sep= */
+
+ /* temporarily null terminate end of keyword=value pair */
+ if(next_keyword)
+ *next_keyword++ = 0;
+
+ /* temporarily null terminate keyword to make keyword and value distinct */
+ if ((value = strchr(data, '=')) != NULL) {
+ *value = '\0';
+ value++;
+ }
+
+ if (strncmp(data, "users",5) == 0) {
+ if(!value || !*value) {
+ goto nocopy;
+ }
+ } else if (strncmp(data, "user_xattr",10) == 0) {
+ /* do nothing - need to skip so not parsed as user name */
+ } else if (strncmp(data, "user", 4) == 0) {
+
+ if (!value || !*value) {
+ if(data[4] == '\0') {
+ if(verboseflag)
+ printf("\nskipping empty user mount parameter\n");
+ /* remove the parm since it would otherwise be confusing
+ to the kernel code which would think it was a real username */
+ goto nocopy;
+ } else {
+ printf("username specified with no parameter\n");
+ return 1; /* needs_arg; */
+ }
+ } else {
+ if (strnlen(value, 260) < 260) {
+ got_user=1;
+ percent_char = strchr(value,'%');
+ if(percent_char) {
+ *percent_char = ',';
+ if(mountpassword == NULL)
+ mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
+ if(mountpassword) {
+ if(got_password)
+ printf("\nmount.cifs warning - password specified twice\n");
+ got_password = 1;
+ percent_char++;
+ strlcpy(mountpassword, percent_char,MOUNT_PASSWD_SIZE+1);
+ /* remove password from username */
+ while(*percent_char != 0) {
+ *percent_char = ',';
+ percent_char++;
+ }
+ }
+ }
+ /* this is only case in which the user
+ name buf is not malloc - so we have to
+ check for domain name embedded within
+ the user name here since the later
+ call to check_for_domain will not be
+ invoked */
+ domain_name = check_for_domain(&value);
+ } else {
+ printf("username too long\n");
+ return 1;
+ }
+ }
+ } else if (strncmp(data, "pass", 4) == 0) {
+ if (!value || !*value) {
+ if(got_password) {
+ printf("\npassword specified twice, ignoring second\n");
+ } else
+ got_password = 1;
+ } else if (strnlen(value, 17) < 17) {
+ if(got_password)
+ printf("\nmount.cifs warning - password specified twice\n");
+ got_password = 1;
+ } else {
+ printf("password too long\n");
+ return 1;
+ }
+ } else if (strncmp(data, "sec", 3) == 0) {
+ if (value) {
+ if (!strncmp(value, "none", 4) ||
+ !strncmp(value, "krb5", 4))
+ got_password = 1;
+ }
+ } else if (strncmp(data, "ip", 2) == 0) {
+ if (!value || !*value) {
+ printf("target ip address argument missing");
+ } else if (strnlen(value, 35) < 35) {
+ if(verboseflag)
+ printf("ip address %s override specified\n",value);
+ got_ip = 1;
+ } else {
+ printf("ip address too long\n");
+ return 1;
+ }
+ } else if ((strncmp(data, "unc", 3) == 0)
+ || (strncmp(data, "target", 6) == 0)
+ || (strncmp(data, "path", 4) == 0)) {
+ if (!value || !*value) {
+ printf("invalid path to network resource\n");
+ return 1; /* needs_arg; */
+ } else if(strnlen(value,5) < 5) {
+ printf("UNC name too short");
+ }
+
+ if (strnlen(value, 300) < 300) {
+ got_unc = 1;
+ if (strncmp(value, "//", 2) == 0) {
+ if(got_unc)
+ printf("unc name specified twice, ignoring second\n");
+ else
+ got_unc = 1;
+ } else if (strncmp(value, "\\\\", 2) != 0) {
+ printf("UNC Path does not begin with // or \\\\ \n");
+ return 1;
+ } else {
+ if(got_unc)
+ printf("unc name specified twice, ignoring second\n");
+ else
+ got_unc = 1;
+ }
+ } else {
+ printf("CIFS: UNC name too long\n");
+ return 1;
+ }
+ } else if ((strncmp(data, "dom" /* domain */, 3) == 0)
+ || (strncmp(data, "workg", 5) == 0)) {
+ /* note this allows for synonyms of "domain"
+ such as "DOM" and "dom" and "workgroup"
+ and "WORKGRP" etc. */
+ if (!value || !*value) {
+ printf("CIFS: invalid domain name\n");
+ return 1; /* needs_arg; */
+ }
+ if (strnlen(value, DOMAIN_SIZE+1) < DOMAIN_SIZE+1) {
+ got_domain = 1;
+ } else {
+ printf("domain name too long\n");
+ return 1;
+ }
+ } else if (strncmp(data, "cred", 4) == 0) {
+ if (value && *value) {
+ rc = open_cred_file(value);
+ if(rc) {
+ printf("error %d (%s) opening credential file %s\n",
+ rc, strerror(rc), value);
+ return 1;
+ }
+ } else {
+ printf("invalid credential file name specified\n");
+ return 1;
+ }
+ } else if (strncmp(data, "uid", 3) == 0) {
+ if (value && *value) {
+ got_uid = 1;
+ if (!isdigit(*value)) {
+ struct passwd *pw;
+
+ if (!(pw = getpwnam(value))) {
+ printf("bad user name \"%s\"\n", value);
+ exit(1);
+ }
+ snprintf(user, sizeof(user), "%u", pw->pw_uid);
+ } else {
+ strlcpy(user,value,sizeof(user));
+ }
+ }
+ goto nocopy;
+ } else if (strncmp(data, "gid", 3) == 0) {
+ if (value && *value) {
+ got_gid = 1;
+ if (!isdigit(*value)) {
+ struct group *gr;
+
+ if (!(gr = getgrnam(value))) {
+ printf("bad group name \"%s\"\n", value);
+ exit(1);
+ }
+ snprintf(group, sizeof(group), "%u", gr->gr_gid);
+ } else {
+ strlcpy(group,value,sizeof(group));
+ }
+ }
+ goto nocopy;
+ /* fmask and dmask synonyms for people used to smbfs syntax */
+ } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
+ if (!value || !*value) {
+ printf ("Option '%s' requires a numerical argument\n", data);
+ return 1;
+ }
+
+ if (value[0] != '0') {
+ printf ("WARNING: '%s' not expressed in octal.\n", data);
+ }
+
+ if (strcmp (data, "fmask") == 0) {
+ printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
+ data = "file_mode"; /* BB fix this */
+ }
+ } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
+ if (!value || !*value) {
+ printf ("Option '%s' requires a numerical argument\n", data);
+ return 1;
+ }
+
+ if (value[0] != '0') {
+ printf ("WARNING: '%s' not expressed in octal.\n", data);
+ }
+
+ if (strcmp (data, "dmask") == 0) {
+ printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
+ data = "dir_mode";
+ }
+ /* the following eight mount options should be
+ stripped out from what is passed into the kernel
+ since these eight options are best passed as the
+ mount flags rather than redundantly to the kernel
+ and could generate spurious warnings depending on the
+ level of the corresponding cifs vfs kernel code */
+ } else if (strncmp(data, "nosuid", 6) == 0) {
+ *filesys_flags |= MS_NOSUID;
+ } else if (strncmp(data, "suid", 4) == 0) {
+ *filesys_flags &= ~MS_NOSUID;
+ } else if (strncmp(data, "nodev", 5) == 0) {
+ *filesys_flags |= MS_NODEV;
+ } else if ((strncmp(data, "nobrl", 5) == 0) ||
+ (strncmp(data, "nolock", 6) == 0)) {
+ *filesys_flags &= ~MS_MANDLOCK;
+ } else if (strncmp(data, "dev", 3) == 0) {
+ *filesys_flags &= ~MS_NODEV;
+ } else if (strncmp(data, "noexec", 6) == 0) {
+ *filesys_flags |= MS_NOEXEC;
+ } else if (strncmp(data, "exec", 4) == 0) {
+ *filesys_flags &= ~MS_NOEXEC;
+ } else if (strncmp(data, "guest", 5) == 0) {
+ got_password=1;
+ } else if (strncmp(data, "ro", 2) == 0) {
+ *filesys_flags |= MS_RDONLY;
+ } else if (strncmp(data, "rw", 2) == 0) {
+ *filesys_flags &= ~MS_RDONLY;
+ } else if (strncmp(data, "remount", 7) == 0) {
+ *filesys_flags |= MS_REMOUNT;
+ } /* else if (strnicmp(data, "port", 4) == 0) {
+ if (value && *value) {
+ vol->port =
+ simple_strtoul(value, &value, 0);
+ }
+ } else if (strnicmp(data, "rsize", 5) == 0) {
+ if (value && *value) {
+ vol->rsize =
+ simple_strtoul(value, &value, 0);
+ }
+ } else if (strnicmp(data, "wsize", 5) == 0) {
+ if (value && *value) {
+ vol->wsize =
+ simple_strtoul(value, &value, 0);
+ }
+ } else if (strnicmp(data, "version", 3) == 0) {
+ } else {
+ printf("CIFS: Unknown mount option %s\n",data);
+ } */ /* nothing to do on those four mount options above.
+ Just pass to kernel and ignore them here */
+
+ /* Copy (possibly modified) option to out */
+ word_len = strlen(data);
+ if (value)
+ word_len += 1 + strlen(value);
+
+ out = (char *)realloc(out, out_len + word_len + 2);
+ if (out == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ if (out_len) {
+ strlcat(out, ",", out_len + word_len + 2);
+ out_len++;
+ }
+
+ if (value)
+ snprintf(out + out_len, word_len + 1, "%s=%s", data, value);
+ else
+ snprintf(out + out_len, word_len + 1, "%s", data);
+ out_len = strlen(out);
+
+nocopy:
+ data = next_keyword;
+ }
+
+ /* special-case the uid and gid */
+ if (got_uid) {
+ word_len = strlen(user);
+
+ out = (char *)realloc(out, out_len + word_len + 6);
+ if (out == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ if (out_len) {
+ strlcat(out, ",", out_len + word_len + 6);
+ out_len++;
+ }
+ snprintf(out + out_len, word_len + 5, "uid=%s", user);
+ out_len = strlen(out);
+ }
+ if (got_gid) {
+ word_len = strlen(group);
+
+ out = (char *)realloc(out, out_len + 1 + word_len + 6);
+ if (out == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ if (out_len) {
+ strlcat(out, ",", out_len + word_len + 6);
+ out_len++;
+ }
+ snprintf(out + out_len, word_len + 5, "gid=%s", group);
+ out_len = strlen(out);
+ }
+
+ SAFE_FREE(*optionsp);
+ *optionsp = out;
+ return 0;
+}
+
+/* replace all (one or more) commas with double commas */
+static void check_for_comma(char ** ppasswrd)
+{
+ char *new_pass_buf;
+ char *pass;
+ int i,j;
+ int number_of_commas = 0;
+ int len;
+
+ if(ppasswrd == NULL)
+ return;
+ else
+ (pass = *ppasswrd);
+
+ len = strlen(pass);
+
+ for(i=0;i<len;i++) {
+ if(pass[i] == ',')
+ number_of_commas++;
+ }
+
+ if(number_of_commas == 0)
+ return;
+ if(number_of_commas > MOUNT_PASSWD_SIZE) {
+ /* would otherwise overflow the mount options buffer */
+ printf("\nInvalid password. Password contains too many commas.\n");
+ return;
+ }
+
+ new_pass_buf = (char *)malloc(len+number_of_commas+1);
+ if(new_pass_buf == NULL)
+ return;
+
+ for(i=0,j=0;i<len;i++,j++) {
+ new_pass_buf[j] = pass[i];
+ if(pass[i] == ',') {
+ j++;
+ new_pass_buf[j] = pass[i];
+ }
+ }
+ new_pass_buf[len+number_of_commas] = 0;
+
+ SAFE_FREE(*ppasswrd);
+ *ppasswrd = new_pass_buf;
+
+ return;
+}
+
+/* Usernames can not have backslash in them and we use
+ [BB check if usernames can have forward slash in them BB]
+ backslash as domain\user separator character
+*/
+static char * check_for_domain(char **ppuser)
+{
+ char * original_string;
+ char * usernm;
+ char * domainnm;
+ int original_len;
+ int len;
+ int i;
+
+ if(ppuser == NULL)
+ return NULL;
+
+ original_string = *ppuser;
+
+ if (original_string == NULL)
+ return NULL;
+
+ original_len = strlen(original_string);
+
+ usernm = strchr(*ppuser,'/');
+ if (usernm == NULL) {
+ usernm = strchr(*ppuser,'\\');
+ if (usernm == NULL)
+ return NULL;
+ }
+
+ if(got_domain) {
+ printf("Domain name specified twice. Username probably malformed\n");
+ return NULL;
+ }
+
+ usernm[0] = 0;
+ domainnm = *ppuser;
+ if (domainnm[0] != 0) {
+ got_domain = 1;
+ } else {
+ printf("null domain\n");
+ }
+ len = strlen(domainnm);
+ /* reset domainm to new buffer, and copy
+ domain name into it */
+ domainnm = (char *)malloc(len+1);
+ if(domainnm == NULL)
+ return NULL;
+
+ strlcpy(domainnm,*ppuser,len+1);
+
+/* move_string(*ppuser, usernm+1) */
+ len = strlen(usernm+1);
+
+ if(len >= original_len) {
+ /* should not happen */
+ return domainnm;
+ }
+
+ for(i=0;i<original_len;i++) {
+ if(i<len)
+ original_string[i] = usernm[i+1];
+ else /* stuff with commas to remove last parm */
+ original_string[i] = ',';
+ }
+
+ /* BB add check for more than one slash?
+ strchr(*ppuser,'/');
+ strchr(*ppuser,'\\')
+ */
+
+ return domainnm;
+}
+
+/* replace all occurances of "from" in a string with "to" */
+static void replace_char(char *string, char from, char to, int maxlen)
+{
+ char *lastchar = string + maxlen;
+ while (string) {
+ string = strchr(string, from);
+ if (string) {
+ *string = to;
+ if (string >= lastchar)
+ return;
+ }
+ }
+}
+
+/* Note that caller frees the returned buffer if necessary */
+static char * parse_server(char ** punc_name)
+{
+ char * unc_name = *punc_name;
+ int length = strnlen(unc_name, MAX_UNC_LEN);
+ char * share;
+ char * ipaddress_string = NULL;
+ struct hostent * host_entry = NULL;
+ struct in_addr server_ipaddr;
+
+ if(length > (MAX_UNC_LEN - 1)) {
+ printf("mount error: UNC name too long");
+ return NULL;
+ }
+ if (strncasecmp("cifs://",unc_name,7) == 0)
+ return parse_cifs_url(unc_name+7);
+ if (strncasecmp("smb://",unc_name,6) == 0) {
+ return parse_cifs_url(unc_name+6);
+ }
+
+ if(length < 3) {
+ /* BB add code to find DFS root here */
+ printf("\nMounting the DFS root for domain not implemented yet\n");
+ return NULL;
+ } else {
+ if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
+ /* check for nfs syntax ie server:share */
+ share = strchr(unc_name,':');
+ if(share) {
+ *punc_name = (char *)malloc(length+3);
+ if(*punc_name == NULL) {
+ /* put the original string back if
+ no memory left */
+ *punc_name = unc_name;
+ return NULL;
+ }
+ *share = '/';
+ strlcpy((*punc_name)+2,unc_name,length+1);
+ SAFE_FREE(unc_name);
+ unc_name = *punc_name;
+ unc_name[length+2] = 0;
+ goto continue_unc_parsing;
+ } else {
+ printf("mount error: improperly formatted UNC name.");
+ printf(" %s does not begin with \\\\ or //\n",unc_name);
+ return NULL;
+ }
+ } else {
+continue_unc_parsing:
+ unc_name[0] = '/';
+ unc_name[1] = '/';
+ unc_name += 2;
+
+ /* allow for either delimiter between host and sharename */
+ if ((share = strpbrk(unc_name, "/\\"))) {
+ *share = 0; /* temporarily terminate the string */
+ share += 1;
+ if(got_ip == 0) {
+ host_entry = gethostbyname(unc_name);
+ }
+ *(share - 1) = '/'; /* put delimiter back */
+
+ /* we don't convert the prefixpath delimiters since '\\' is a valid char in posix paths */
+ if ((prefixpath = strpbrk(share, "/\\"))) {
+ *prefixpath = 0; /* permanently terminate the string */
+ if (!strlen(++prefixpath))
+ prefixpath = NULL; /* this needs to be done explicitly */
+ }
+ if(got_ip) {
+ if(verboseflag)
+ printf("ip address specified explicitly\n");
+ return NULL;
+ }
+ if(host_entry == NULL) {
+ printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
+ return NULL;
+ } else {
+ /* BB should we pass an alternate version of the share name as Unicode */
+ /* BB what about ipv6? BB */
+ /* BB add retries with alternate servers in list */
+
+ memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
+
+ ipaddress_string = inet_ntoa(server_ipaddr);
+ if(ipaddress_string == NULL) {
+ printf("mount error: could not get valid ip address for target server\n");
+ return NULL;
+ }
+ return ipaddress_string;
+ }
+ } else {
+ /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
+ printf("Mounting the DFS root for a particular server not implemented yet\n");
+ return NULL;
+ }
+ }
+ }
+}
+
+static struct option longopts[] = {
+ { "all", 0, NULL, 'a' },
+ { "help",0, NULL, 'h' },
+ { "move",0, NULL, 'm' },
+ { "bind",0, NULL, 'b' },
+ { "read-only", 0, NULL, 'r' },
+ { "ro", 0, NULL, 'r' },
+ { "verbose", 0, NULL, 'v' },
+ { "version", 0, NULL, 'V' },
+ { "read-write", 0, NULL, 'w' },
+ { "rw", 0, NULL, 'w' },
+ { "options", 1, NULL, 'o' },
+ { "type", 1, NULL, 't' },
+ { "rsize",1, NULL, 'R' },
+ { "wsize",1, NULL, 'W' },
+ { "uid", 1, NULL, '1'},
+ { "gid", 1, NULL, '2'},
+ { "user",1,NULL,'u'},
+ { "username",1,NULL,'u'},
+ { "dom",1,NULL,'d'},
+ { "domain",1,NULL,'d'},
+ { "password",1,NULL,'p'},
+ { "pass",1,NULL,'p'},
+ { "credentials",1,NULL,'c'},
+ { "port",1,NULL,'P'},
+ /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
+ { NULL, 0, NULL, 0 }
+};
+
+/* convert a string to uppercase. return false if the string
+ * wasn't ASCII or was a NULL ptr */
+static int
+uppercase_string(char *string)
+{
+ if (!string)
+ return 0;
+
+ while (*string) {
+ /* check for unicode */
+ if ((unsigned char) string[0] & 0x80)
+ return 0;
+ *string = toupper((unsigned char) *string);
+ string++;
+ }
+
+ return 1;
+}
+
+int main(int argc, char ** argv)
+{
+ int c;
+ int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
+ char * orgoptions = NULL;
+ char * share_name = NULL;
+ char * ipaddr = NULL;
+ char * uuid = NULL;
+ char * mountpoint = NULL;
+ char * options = NULL;
+ char * resolved_path = NULL;
+ char * temp;
+ char * dev_name;
+ int rc;
+ int rsize = 0;
+ int wsize = 0;
+ int nomtab = 0;
+ int uid = 0;
+ int gid = 0;
+ int optlen = 0;
+ int orgoptlen = 0;
+ size_t options_size = 0;
+ int retry = 0; /* set when we have to retry mount with uppercase */
+ struct stat statbuf;
+ struct utsname sysinfo;
+ struct mntent mountent;
+ FILE * pmntfile;
+
+ /* setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE); */
+
+ if(argc && argv) {
+ thisprogram = argv[0];
+ } else {
+ mount_cifs_usage();
+ exit(1);
+ }
+
+ if(thisprogram == NULL)
+ thisprogram = "mount.cifs";
+
+ uname(&sysinfo);
+ /* BB add workstation name and domain and pass down */
+
+/* #ifdef _GNU_SOURCE
+ printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
+#endif */
+ if(argc > 2) {
+ dev_name = argv[1];
+ share_name = strndup(argv[1], MAX_UNC_LEN);
+ if (share_name == NULL) {
+ fprintf(stderr, "%s: %s", argv[0], strerror(ENOMEM));
+ exit(1);
+ }
+ mountpoint = argv[2];
+ } else {
+ mount_cifs_usage();
+ exit(1);
+ }
+
+ /* add sharename in opts string as unc= parm */
+
+ while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
+ longopts, NULL)) != -1) {
+ switch (c) {
+/* No code to do the following options yet */
+/* case 'l':
+ list_with_volumelabel = 1;
+ break;
+ case 'L':
+ volumelabel = optarg;
+ break; */
+/* case 'a':
+ ++mount_all;
+ break; */
+
+ case '?':
+ case 'h': /* help */
+ mount_cifs_usage ();
+ exit(1);
+ case 'n':
+ ++nomtab;
+ break;
+ case 'b':
+#ifdef MS_BIND
+ flags |= MS_BIND;
+#else
+ fprintf(stderr,
+ "option 'b' (MS_BIND) not supported\n");
+#endif
+ break;
+ case 'm':
+#ifdef MS_MOVE
+ flags |= MS_MOVE;
+#else
+ fprintf(stderr,
+ "option 'm' (MS_MOVE) not supported\n");
+#endif
+ break;
+ case 'o':
+ orgoptions = strdup(optarg);
+ break;
+ case 'r': /* mount readonly */
+ flags |= MS_RDONLY;
+ break;
+ case 'U':
+ uuid = optarg;
+ break;
+ case 'v':
+ ++verboseflag;
+ break;
+ case 'V':
+ printf ("mount.cifs version: %s.%s%s\n",
+ MOUNT_CIFS_VERSION_MAJOR,
+ MOUNT_CIFS_VERSION_MINOR,
+ MOUNT_CIFS_VENDOR_SUFFIX);
+ exit (0);
+ case 'w':
+ flags &= ~MS_RDONLY;
+ break;
+ case 'R':
+ rsize = atoi(optarg) ;
+ break;
+ case 'W':
+ wsize = atoi(optarg);
+ break;
+ case '1':
+ if (isdigit(*optarg)) {
+ char *ep;
+
+ uid = strtoul(optarg, &ep, 10);
+ if (*ep) {
+ printf("bad uid value \"%s\"\n", optarg);
+ exit(1);
+ }
+ } else {
+ struct passwd *pw;
+
+ if (!(pw = getpwnam(optarg))) {
+ printf("bad user name \"%s\"\n", optarg);
+ exit(1);
+ }
+ uid = pw->pw_uid;
+ endpwent();
+ }
+ break;
+ case '2':
+ if (isdigit(*optarg)) {
+ char *ep;
+
+ gid = strtoul(optarg, &ep, 10);
+ if (*ep) {
+ printf("bad gid value \"%s\"\n", optarg);
+ exit(1);
+ }
+ } else {
+ struct group *gr;
+
+ if (!(gr = getgrnam(optarg))) {
+ printf("bad user name \"%s\"\n", optarg);
+ exit(1);
+ }
+ gid = gr->gr_gid;
+ endpwent();
+ }
+ break;
+ case 'u':
+ got_user = 1;
+ user_name = optarg;
+ break;
+ case 'd':
+ domain_name = optarg; /* BB fix this - currently ignored */
+ got_domain = 1;
+ break;
+ case 'p':
+ if(mountpassword == NULL)
+ mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
+ if(mountpassword) {
+ got_password = 1;
+ strlcpy(mountpassword,optarg,MOUNT_PASSWD_SIZE+1);
+ }
+ break;
+ case 'S':
+ get_password_from_file(0 /* stdin */,NULL);
+ break;
+ case 't':
+ break;
+ default:
+ printf("unknown mount option %c\n",c);
+ mount_cifs_usage();
+ exit(1);
+ }
+ }
+
+ if((argc < 3) || (dev_name == NULL) || (mountpoint == NULL)) {
+ mount_cifs_usage();
+ exit(1);
+ }
+
+ if (getenv("PASSWD")) {
+ if(mountpassword == NULL)
+ mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
+ if(mountpassword) {
+ strlcpy(mountpassword,getenv("PASSWD"),MOUNT_PASSWD_SIZE+1);
+ got_password = 1;
+ }
+ } else if (getenv("PASSWD_FD")) {
+ get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
+ } else if (getenv("PASSWD_FILE")) {
+ get_password_from_file(0, getenv("PASSWD_FILE"));
+ }
+
+ if (orgoptions && parse_options(&orgoptions, &flags)) {
+ rc = -1;
+ goto mount_exit;
+ }
+ ipaddr = parse_server(&share_name);
+ if((ipaddr == NULL) && (got_ip == 0)) {
+ printf("No ip address specified and hostname not found\n");
+ rc = -1;
+ goto mount_exit;
+ }
+
+ /* BB save off path and pop after mount returns? */
+ resolved_path = (char *)malloc(PATH_MAX+1);
+ if(resolved_path) {
+ /* Note that if we can not canonicalize the name, we get
+ another chance to see if it is valid when we chdir to it */
+ if (realpath(mountpoint, resolved_path)) {
+ mountpoint = resolved_path;
+ }
+ }
+ if(chdir(mountpoint)) {
+ printf("mount error: can not change directory into mount target %s\n",mountpoint);
+ rc = -1;
+ goto mount_exit;
+ }
+
+ if(stat (".", &statbuf)) {
+ printf("mount error: mount point %s does not exist\n",mountpoint);
+ rc = -1;
+ goto mount_exit;
+ }
+
+ if (S_ISDIR(statbuf.st_mode) == 0) {
+ printf("mount error: mount point %s is not a directory\n",mountpoint);
+ rc = -1;
+ goto mount_exit;
+ }
+
+ if((getuid() != 0) && (geteuid() == 0)) {
+ if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
+#ifndef CIFS_ALLOW_USR_SUID
+ /* Do not allow user mounts to control suid flag
+ for mount unless explicitly built that way */
+ flags |= MS_NOSUID | MS_NODEV;
+#endif
+ } else {
+ printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
+ return -1;
+ }
+ }
+
+ if(got_user == 0) {
+ user_name = getusername();
+ got_user = 1;
+ }
+
+ if(got_password == 0) {
+ char *tmp_pass = getpass("Password: "); /* BB obsolete sys call but
+ no good replacement yet. */
+ mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
+ if (!tmp_pass || !mountpassword) {
+ printf("Password not entered, exiting\n");
+ return -1;
+ }
+ strlcpy(mountpassword, tmp_pass, MOUNT_PASSWD_SIZE+1);
+ got_password = 1;
+ }
+ /* FIXME launch daemon (handles dfs name resolution and credential change)
+ remember to clear parms and overwrite password field before launching */
+mount_retry:
+ if(orgoptions) {
+ optlen = strlen(orgoptions);
+ orgoptlen = optlen;
+ } else
+ optlen = 0;
+ if(share_name)
+ optlen += strlen(share_name) + 4;
+ else {
+ printf("No server share name specified\n");
+ printf("\nMounting the DFS root for server not implemented yet\n");
+ exit(1);
+ }
+ if(user_name)
+ optlen += strlen(user_name) + 6;
+ if(ipaddr)
+ optlen += strlen(ipaddr) + 4;
+ if(mountpassword)
+ optlen += strlen(mountpassword) + 6;
+ SAFE_FREE(options);
+ options_size = optlen + 10 + DOMAIN_SIZE;
+ options = (char *)malloc(options_size /* space for commas in password */ + 8 /* space for domain= , domain name itself was counted as part of the length username string above */);
+
+ if(options == NULL) {
+ printf("Could not allocate memory for mount options\n");
+ return -1;
+ }
+
+ options[0] = 0;
+ strlcpy(options,"unc=",options_size);
+ strlcat(options,share_name,options_size);
+ /* scan backwards and reverse direction of slash */
+ temp = strrchr(options, '/');
+ if(temp > options + 6)
+ *temp = '\\';
+ if(ipaddr) {
+ strlcat(options,",ip=",options_size);
+ strlcat(options,ipaddr,options_size);
+ }
+
+ if(user_name) {
+ /* check for syntax like user=domain\user */
+ if(got_domain == 0)
+ domain_name = check_for_domain(&user_name);
+ strlcat(options,",user=",options_size);
+ strlcat(options,user_name,options_size);
+ }
+ if(retry == 0) {
+ if(domain_name) {
+ /* extra length accounted for in option string above */
+ strlcat(options,",domain=",options_size);
+ strlcat(options,domain_name,options_size);
+ }
+ }
+ if(mountpassword) {
+ /* Commas have to be doubled, or else they will
+ look like the parameter separator */
+/* if(sep is not set)*/
+ if(retry == 0)
+ check_for_comma(&mountpassword);
+ strlcat(options,",pass=",options_size);
+ strlcat(options,mountpassword,options_size);
+ }
+
+ strlcat(options,",ver=",options_size);
+ strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
+
+ if(orgoptions) {
+ strlcat(options,",",options_size);
+ strlcat(options,orgoptions,options_size);
+ }
+ if(prefixpath) {
+ strlcat(options,",prefixpath=",options_size);
+ strlcat(options,prefixpath,options_size); /* no need to cat the / */
+ }
+ if(verboseflag)
+ printf("\nmount.cifs kernel mount options %s \n",options);
+
+ /* convert all '\\' to '/' in share portion so that /proc/mounts looks pretty */
+ replace_char(dev_name, '\\', '/', strlen(share_name));
+
+ if(mount(dev_name, mountpoint, "cifs", flags, options)) {
+ /* remember to kill daemon on error */
+ switch (errno) {
+ case 0:
+ printf("mount failed but no error number set\n");
+ break;
+ case ENODEV:
+ printf("mount error: cifs filesystem not supported by the system\n");
+ break;
+ case ENXIO:
+ if(retry == 0) {
+ retry = 1;
+ if (uppercase_string(dev_name) &&
+ uppercase_string(share_name) &&
+ uppercase_string(prefixpath)) {
+ printf("retrying with upper case share name\n");
+ goto mount_retry;
+ }
+ }
+ default:
+ printf("mount error %d = %s\n",errno,strerror(errno));
+ }
+ printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
+ rc = -1;
+ goto mount_exit;
+ } else {
+ pmntfile = setmntent(MOUNTED, "a+");
+ if(pmntfile) {
+ mountent.mnt_fsname = dev_name;
+ mountent.mnt_dir = mountpoint;
+ mountent.mnt_type = CONST_DISCARD(char *,"cifs");
+ mountent.mnt_opts = (char *)malloc(220);
+ if(mountent.mnt_opts) {
+ char * mount_user = getusername();
+ memset(mountent.mnt_opts,0,200);
+ if(flags & MS_RDONLY)
+ strlcat(mountent.mnt_opts,"ro",220);
+ else
+ strlcat(mountent.mnt_opts,"rw",220);
+ if(flags & MS_MANDLOCK)
+ strlcat(mountent.mnt_opts,",mand",220);
+ if(flags & MS_NOEXEC)
+ strlcat(mountent.mnt_opts,",noexec",220);
+ if(flags & MS_NOSUID)
+ strlcat(mountent.mnt_opts,",nosuid",220);
+ if(flags & MS_NODEV)
+ strlcat(mountent.mnt_opts,",nodev",220);
+ if(flags & MS_SYNCHRONOUS)
+ strlcat(mountent.mnt_opts,",synch",220);
+ if(mount_user) {
+ if(getuid() != 0) {
+ strlcat(mountent.mnt_opts,",user=",220);
+ strlcat(mountent.mnt_opts,mount_user,220);
+ }
+ /* free(mount_user); do not free static mem */
+ }
+ }
+ mountent.mnt_freq = 0;
+ mountent.mnt_passno = 0;
+ rc = addmntent(pmntfile,&mountent);
+ endmntent(pmntfile);
+ SAFE_FREE(mountent.mnt_opts);
+ } else {
+ printf("could not update mount table\n");
+ }
+ }
+ rc = 0;
+mount_exit:
+ if(mountpassword) {
+ int len = strlen(mountpassword);
+ memset(mountpassword,0,len);
+ SAFE_FREE(mountpassword);
+ }
+
+ SAFE_FREE(options);
+ SAFE_FREE(orgoptions);
+ SAFE_FREE(resolved_path);
+ SAFE_FREE(share_name);
+ return rc;
+}
diff --git a/source3/client/smbspool.c b/source3/client/smbspool.c
new file mode 100644
index 0000000000..4a173714fe
--- /dev/null
+++ b/source3/client/smbspool.c
@@ -0,0 +1,624 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB backend for the Common UNIX Printing System ("CUPS")
+
+ Copyright (C) Michael R Sweet 1999
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Rodrigo Fernandez-Vizarra 2005
+ Copyright (C) James Peach 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*
+ * Starting with CUPS 1.3, Kerberos support is provided by cupsd including
+ * the forwarding of user credentials via the authenticated session between
+ * user and server and the KRB5CCNAME environment variable which will point
+ * to a temporary file or an in-memory representation depending on the version
+ * of Kerberos you use. As a result, all of the ticket code that used to
+ * live here has been removed, and we depend on the user session (if you
+ * run smbspool by hand) or cupsd to provide the necessary Kerberos info.
+ *
+ * Also, the AUTH_USERNAME and AUTH_PASSWORD environment variables provide
+ * for per-job authentication for non-Kerberized printing. We use those
+ * if there is no username and password specified in the device URI.
+ *
+ * Finally, if we have an authentication failure we return exit code 2
+ * which tells CUPS to hold the job for authentication and bug the user
+ * to get the necessary credentials.
+ */
+
+#define MAX_RETRY_CONNECT 3
+
+
+/*
+ * Globals...
+ */
+
+
+
+/*
+ * Local functions...
+ */
+
+static int get_exit_code(struct cli_state * cli, NTSTATUS nt_status);
+static void list_devices(void);
+static struct cli_state *smb_complete_connection(const char *, const char *,
+ int, const char *, const char *, const char *, const char *, int, bool *need_auth);
+static struct cli_state *smb_connect(const char *, const char *, int, const
+ char *, const char *, const char *, const char *, bool *need_auth);
+static int smb_print(struct cli_state *, char *, FILE *);
+static char *uri_unescape_alloc(const char *);
+#if 0
+static bool smb_encrypt;
+#endif
+
+/*
+ * 'main()' - Main entry for SMB backend.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[])
+{ /* I - Command-line arguments */
+ int i; /* Looping var */
+ int copies; /* Number of copies */
+ int port; /* Port number */
+ char uri[1024], /* URI */
+ *sep, /* Pointer to separator */
+ *tmp, *tmp2, /* Temp pointers to do escaping */
+ *password; /* Password */
+ char *username, /* Username */
+ *server, /* Server name */
+ *printer;/* Printer name */
+ const char *workgroup; /* Workgroup */
+ FILE *fp; /* File to print */
+ int status = 1; /* Status of LPD job */
+ struct cli_state *cli; /* SMB interface */
+ char null_str[1];
+ int tries = 0;
+ bool need_auth = true;
+ const char *dev_uri;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ null_str[0] = '\0';
+
+ /*
+ * we expect the URI in argv[0]. Detect the case where it is in
+ * argv[1] and cope
+ */
+ if (argc > 2 && strncmp(argv[0], "smb://", 6) &&
+ strncmp(argv[1], "smb://", 6) == 0) {
+ argv++;
+ argc--;
+ }
+
+ if (argc == 1) {
+ /*
+ * NEW! In CUPS 1.1 the backends are run with no arguments
+ * to list the available devices. These can be devices
+ * served by this backend or any other backends (i.e. you
+ * can have an SNMP backend that is only used to enumerate
+ * the available network printers... :)
+ */
+
+ list_devices();
+ status = 0;
+ goto done;
+ }
+
+ if (argc < 6 || argc > 7) {
+ fprintf(stderr,
+"Usage: %s [DEVICE_URI] job-id user title copies options [file]\n"
+" The DEVICE_URI environment variable can also contain the\n"
+" destination printer:\n"
+"\n"
+" smb://[username:password@][workgroup/]server[:port]/printer\n",
+ argv[0]);
+ goto done;
+ }
+
+ /*
+ * If we have 7 arguments, print the file named on the command-line.
+ * Otherwise, print data from stdin...
+ */
+
+ if (argc == 6) {
+ /*
+ * Print from Copy stdin to a temporary file...
+ */
+
+ fp = stdin;
+ copies = 1;
+ } else if ((fp = fopen(argv[6], "rb")) == NULL) {
+ perror("ERROR: Unable to open print file");
+ goto done;
+ } else {
+ copies = atoi(argv[4]);
+ }
+
+ /*
+ * Find the URI...
+ */
+
+ dev_uri = getenv("DEVICE_URI");
+ if (dev_uri) {
+ strncpy(uri, dev_uri, sizeof(uri) - 1);
+ } else if (strncmp(argv[0], "smb://", 6) == 0) {
+ strncpy(uri, argv[0], sizeof(uri) - 1);
+ } else {
+ fputs("ERROR: No device URI found in DEVICE_URI environment variable or argv[0] !\n", stderr);
+ goto done;
+ }
+
+ uri[sizeof(uri) - 1] = '\0';
+
+ /*
+ * Extract the destination from the URI...
+ */
+
+ if ((sep = strrchr_m(uri, '@')) != NULL) {
+ tmp = uri + 6;
+ *sep++ = '\0';
+
+ /* username is in tmp */
+
+ server = sep;
+
+ /*
+ * Extract password as needed...
+ */
+
+ if ((tmp2 = strchr_m(tmp, ':')) != NULL) {
+ *tmp2++ = '\0';
+ password = uri_unescape_alloc(tmp2);
+ } else {
+ password = null_str;
+ }
+ username = uri_unescape_alloc(tmp);
+ } else {
+ if ((username = getenv("AUTH_USERNAME")) == NULL) {
+ username = null_str;
+ }
+
+ if ((password = getenv("AUTH_PASSWORD")) == NULL) {
+ password = null_str;
+ }
+
+ server = uri + 6;
+ }
+
+ tmp = server;
+
+ if ((sep = strchr_m(tmp, '/')) == NULL) {
+ fputs("ERROR: Bad URI - need printer name!\n", stderr);
+ goto done;
+ }
+
+ *sep++ = '\0';
+ tmp2 = sep;
+
+ if ((sep = strchr_m(tmp2, '/')) != NULL) {
+ /*
+ * Convert to smb://[username:password@]workgroup/server/printer...
+ */
+
+ *sep++ = '\0';
+
+ workgroup = uri_unescape_alloc(tmp);
+ server = uri_unescape_alloc(tmp2);
+ printer = uri_unescape_alloc(sep);
+ } else {
+ workgroup = NULL;
+ server = uri_unescape_alloc(tmp);
+ printer = uri_unescape_alloc(tmp2);
+ }
+
+ if ((sep = strrchr_m(server, ':')) != NULL) {
+ *sep++ = '\0';
+
+ port = atoi(sep);
+ } else {
+ port = 0;
+ }
+
+ /*
+ * Setup the SAMBA server state...
+ */
+
+ setup_logging("smbspool", True);
+
+ lp_set_in_client(True); /* Make sure that we tell lp_load we are */
+
+ load_case_tables();
+
+ if (!lp_load(get_dyn_CONFIGFILE(), True, False, False, True)) {
+ fprintf(stderr, "ERROR: Can't load %s - run testparm to debug it\n", get_dyn_CONFIGFILE());
+ goto done;
+ }
+
+ if (workgroup == NULL) {
+ workgroup = lp_workgroup();
+ }
+
+ load_interfaces();
+
+ do {
+ cli = smb_connect(workgroup, server, port, printer,
+ username, password, argv[2], &need_auth);
+ if (cli == NULL) {
+ if (need_auth) {
+ exit(2);
+ } else if (getenv("CLASS") == NULL) {
+ fprintf(stderr, "ERROR: Unable to connect to CIFS host, will retry in 60 seconds...\n");
+ sleep(60);
+ tries++;
+ } else {
+ fprintf(stderr, "ERROR: Unable to connect to CIFS host, trying next printer...\n");
+ goto done;
+ }
+ }
+ } while ((cli == NULL) && (tries < MAX_RETRY_CONNECT));
+
+ if (cli == NULL) {
+ fprintf(stderr, "ERROR: Unable to connect to CIFS host after (tried %d times)\n", tries);
+ goto done;
+ }
+
+ /*
+ * Now that we are connected to the server, ignore SIGTERM so that we
+ * can finish out any page data the driver sends (e.g. to eject the
+ * current page... Only ignore SIGTERM if we are printing data from
+ * stdin (otherwise you can't cancel raw jobs...)
+ */
+
+ if (argc < 7) {
+ CatchSignal(SIGTERM, SIG_IGN);
+ }
+
+ /*
+ * Queue the job...
+ */
+
+ for (i = 0; i < copies; i++) {
+ status = smb_print(cli, argv[3] /* title */ , fp);
+ if (status != 0) {
+ break;
+ }
+ }
+
+ cli_shutdown(cli);
+
+ /*
+ * Return the queue status...
+ */
+
+done:
+
+ TALLOC_FREE(frame);
+ return (status);
+}
+
+
+/*
+ * 'get_exit_code()' - Get the backend exit code based on the current error.
+ */
+
+static int
+get_exit_code(struct cli_state * cli,
+ NTSTATUS nt_status)
+{
+ int i;
+
+ /* List of NTSTATUS errors that are considered
+ * authentication errors
+ */
+ static const NTSTATUS auth_errors[] =
+ {
+ NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_VIOLATION,
+ NT_STATUS_SHARING_VIOLATION, NT_STATUS_PRIVILEGE_NOT_HELD,
+ NT_STATUS_INVALID_ACCOUNT_NAME, NT_STATUS_NO_SUCH_USER,
+ NT_STATUS_WRONG_PASSWORD, NT_STATUS_LOGON_FAILURE,
+ NT_STATUS_ACCOUNT_RESTRICTION, NT_STATUS_INVALID_LOGON_HOURS,
+ NT_STATUS_PASSWORD_EXPIRED, NT_STATUS_ACCOUNT_DISABLED
+ };
+
+
+ fprintf(stderr, "DEBUG: get_exit_code(cli=%p, nt_status=%x)\n",
+ cli, NT_STATUS_V(nt_status));
+
+ for (i = 0; i < ARRAY_SIZE(auth_errors); i++) {
+ if (!NT_STATUS_EQUAL(nt_status, auth_errors[i])) {
+ continue;
+ }
+
+ if (cli) {
+ if (cli->use_kerberos && cli->got_kerberos_mechanism)
+ fputs("ATTR: auth-info-required=negotiate\n", stderr);
+ else
+ fputs("ATTR: auth-info-required=username,password\n", stderr);
+ }
+
+ /*
+ * 2 = authentication required...
+ */
+
+ return (2);
+
+ }
+
+ /*
+ * 1 = fail
+ */
+
+ return (1);
+}
+
+
+/*
+ * 'list_devices()' - List the available printers seen on the network...
+ */
+
+static void
+list_devices(void)
+{
+ /*
+ * Eventually, search the local workgroup for available hosts and printers.
+ */
+
+ puts("network smb \"Unknown\" \"Windows Printer via SAMBA\"");
+}
+
+
+static struct cli_state *
+smb_complete_connection(const char *myname,
+ const char *server,
+ int port,
+ const char *username,
+ const char *password,
+ const char *workgroup,
+ const char *share,
+ int flags,
+ bool *need_auth)
+{
+ struct cli_state *cli; /* New connection */
+ NTSTATUS nt_status;
+
+ /* Start the SMB connection */
+ *need_auth = false;
+ nt_status = cli_start_connection(&cli, myname, server, NULL, port,
+ Undefined, flags, NULL);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ fprintf(stderr, "ERROR: Connection failed: %s\n", nt_errstr(nt_status));
+ return NULL;
+ }
+
+ /*
+ * We pretty much guarantee password must be valid or a pointer to a
+ * 0 char.
+ */
+ if (!password) {
+ *need_auth = true;
+ return NULL;
+ }
+
+ nt_status = cli_session_setup(cli, username,
+ password, strlen(password) + 1,
+ password, strlen(password) + 1,
+ workgroup);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ fprintf(stderr, "ERROR: Session setup failed: %s\n", nt_errstr(nt_status));
+
+ if (get_exit_code(cli, nt_status) == 2) {
+ *need_auth = true;
+ }
+
+ cli_shutdown(cli);
+
+ return NULL;
+ }
+
+ if (!cli_send_tconX(cli, share, "?????", password, strlen(password) + 1)) {
+ fprintf(stderr, "ERROR: Tree connect failed (%s)\n", cli_errstr(cli));
+
+ if (get_exit_code(cli, cli_nt_error(cli)) == 2) {
+ *need_auth = true;
+ }
+
+ cli_shutdown(cli);
+
+ return NULL;
+ }
+#if 0
+ /* Need to work out how to specify this on the URL. */
+ if (smb_encrypt) {
+ if (!cli_cm_force_encryption(cli,
+ username,
+ password,
+ workgroup,
+ share)) {
+ fprintf(stderr, "ERROR: encryption setup failed\n");
+ cli_shutdown(cli);
+ return NULL;
+ }
+ }
+#endif
+
+ return cli;
+}
+
+/*
+ * 'smb_connect()' - Return a connection to a server.
+ */
+
+static struct cli_state * /* O - SMB connection */
+smb_connect(const char *workgroup, /* I - Workgroup */
+ const char *server, /* I - Server */
+ const int port, /* I - Port */
+ const char *share, /* I - Printer */
+ const char *username, /* I - Username */
+ const char *password, /* I - Password */
+ const char *jobusername, /* I - User who issued the print job */
+ bool *need_auth)
+{ /* O - Need authentication? */
+ struct cli_state *cli; /* New connection */
+ char *myname = NULL; /* Client name */
+ struct passwd *pwd;
+
+ /*
+ * Get the names and addresses of the client and server...
+ */
+ myname = get_myname(talloc_tos());
+ if (!myname) {
+ return NULL;
+ }
+
+ /*
+ * See if we have a username first. This is for backwards compatible
+ * behavior with 3.0.14a
+ */
+
+ if (username && *username && !getenv("KRB5CCNAME")) {
+ cli = smb_complete_connection(myname, server, port, username,
+ password, workgroup, share, 0, need_auth);
+ if (cli) {
+ fputs("DEBUG: Connected with username/password...\n", stderr);
+ return (cli);
+ }
+ }
+
+ /*
+ * Try to use the user kerberos credentials (if any) to authenticate
+ */
+ cli = smb_complete_connection(myname, server, port, jobusername, "",
+ workgroup, share,
+ CLI_FULL_CONNECTION_USE_KERBEROS, need_auth);
+
+ if (cli) {
+ fputs("DEBUG: Connected using Kerberos...\n", stderr);
+ return (cli);
+ }
+
+ /* give a chance for a passwordless NTLMSSP session setup */
+ pwd = getpwuid(geteuid());
+ if (pwd == NULL) {
+ return NULL;
+ }
+
+ cli = smb_complete_connection(myname, server, port, pwd->pw_name, "",
+ workgroup, share, 0, need_auth);
+
+ if (cli) {
+ fputs("DEBUG: Connected with NTLMSSP...\n", stderr);
+ return (cli);
+ }
+
+ /*
+ * last try. Use anonymous authentication
+ */
+
+ cli = smb_complete_connection(myname, server, port, "", "",
+ workgroup, share, 0, need_auth);
+ /*
+ * Return the new connection...
+ */
+
+ return (cli);
+}
+
+
+/*
+ * 'smb_print()' - Queue a job for printing using the SMB protocol.
+ */
+
+static int /* O - 0 = success, non-0 = failure */
+smb_print(struct cli_state * cli, /* I - SMB connection */
+ char *title, /* I - Title/job name */
+ FILE * fp)
+{ /* I - File to print */
+ int fnum; /* File number */
+ int nbytes, /* Number of bytes read */
+ tbytes; /* Total bytes read */
+ char buffer[8192], /* Buffer for copy */
+ *ptr; /* Pointer into title */
+
+
+ /*
+ * Sanitize the title...
+ */
+
+ for (ptr = title; *ptr; ptr++) {
+ if (!isalnum((int) *ptr) && !isspace((int) *ptr)) {
+ *ptr = '_';
+ }
+ }
+
+ /*
+ * Open the printer device...
+ */
+
+ fnum = cli_open(cli, title, O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ if (fnum == -1) {
+ fprintf(stderr, "ERROR: %s opening remote spool %s\n",
+ cli_errstr(cli), title);
+ return (get_exit_code(cli, cli_nt_error(cli)));
+ }
+
+ /*
+ * Copy the file to the printer...
+ */
+
+ if (fp != stdin)
+ rewind(fp);
+
+ tbytes = 0;
+
+ while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
+ if (cli_write(cli, fnum, 0, buffer, tbytes, nbytes) != nbytes) {
+ int status = get_exit_code(cli, cli_nt_error(cli));
+
+ fprintf(stderr, "ERROR: Error writing spool: %s\n", cli_errstr(cli));
+ fprintf(stderr, "DEBUG: Returning status %d...\n", status);
+ cli_close(cli, fnum);
+
+ return (status);
+ }
+ tbytes += nbytes;
+ }
+
+ if (!cli_close(cli, fnum)) {
+ fprintf(stderr, "ERROR: %s closing remote spool %s\n",
+ cli_errstr(cli), title);
+ return (get_exit_code(cli, cli_nt_error(cli)));
+ } else {
+ return (0);
+ }
+}
+
+static char *
+uri_unescape_alloc(const char *uritok)
+{
+ char *ret;
+
+ ret = (char *) SMB_STRDUP(uritok);
+ if (!ret) {
+ return NULL;
+ }
+
+ rfc1738_unescape(ret);
+ return ret;
+}
diff --git a/source3/client/tree.c b/source3/client/tree.c
new file mode 100644
index 0000000000..e0b8c91949
--- /dev/null
+++ b/source3/client/tree.c
@@ -0,0 +1,812 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client GTK+ tree-based application
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2001
+ Copyright (C) John Terpstra 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* example-gtk+ application, ripped off from the gtk+ tree.c sample */
+
+#include <stdio.h>
+#include <errno.h>
+#include <gtk/gtk.h>
+#include "libsmbclient.h"
+
+static GtkWidget *clist;
+
+struct tree_data {
+
+ guint32 type; /* Type of tree item, an SMBC_TYPE */
+ char name[256]; /* May need to change this later */
+
+};
+
+static void tree_error_message(gchar *message) {
+
+ GtkWidget *dialog, *label, *okay_button;
+
+ /* Create the widgets */
+
+ dialog = gtk_dialog_new();
+ gtk_window_set_modal(GTK_WINDOW(dialog), True);
+ label = gtk_label_new (message);
+ okay_button = gtk_button_new_with_label("Okay");
+
+ /* Ensure that the dialog box is destroyed when the user clicks ok. */
+
+ gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy), dialog);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
+ okay_button);
+
+ /* Add the label, and show everything we've added to the dialog. */
+
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
+ label);
+ gtk_widget_show_all (dialog);
+}
+
+/*
+ * We are given a widget, and we want to retrieve its URL so we
+ * can do a directory listing.
+ *
+ * We walk back up the tree, picking up pieces until we hit a server or
+ * workgroup type and return a path from there
+ */
+
+static char *path_string;
+
+char *get_path(TALLOC_CTX *ctx, GtkWidget *item)
+{
+ GtkWidget *p = item;
+ struct tree_data *pd;
+ char *comps[1024]; /* We keep pointers to the components here */
+ int i = 0, j, level,type;
+
+ /* Walk back up the tree, getting the private data */
+
+ level = GTK_TREE(item->parent)->level;
+
+ /* Pick up this item's component info */
+
+ pd = (struct tree_data *)gtk_object_get_user_data(GTK_OBJECT(item));
+
+ comps[i++] = pd->name;
+ type = pd->type;
+
+ while (level > 0 && type != SMBC_SERVER && type != SMBC_WORKGROUP) {
+
+ /* Find the parent and extract the data etc ... */
+
+ p = GTK_WIDGET(p->parent);
+ p = GTK_WIDGET(GTK_TREE(p)->tree_owner);
+
+ pd = (struct tree_data *)gtk_object_get_user_data(GTK_OBJECT(p));
+
+ level = GTK_TREE(item->parent)->level;
+
+ comps[i++] = pd->name;
+ type = pd->type;
+
+ }
+
+ /*
+ * Got a list of comps now, should check that we did not hit a workgroup
+ * when we got other things as well ... Later
+ *
+ * Now, build the path
+ */
+
+ TALLOC_FREE(path_string);
+ path_string = talloc_strdup(ctx, "smb:/");
+
+ if (path_string) {
+ for (j = i - 1; j >= 0; j--) {
+ path_string = talloc_asprintf_append(path_string, "/%s", comps[j]);
+ }
+ }
+
+ if (path_string) {
+ fprintf(stdout, "Path string = %s\n", path_string);
+ }
+
+ return path_string;
+
+}
+
+struct tree_data *make_tree_data(guint32 type, const char *name)
+{
+ struct tree_data *p = SMB_MALLOC_P(struct tree_data);
+
+ if (p) {
+
+ p->type = type;
+ strncpy(p->name, name, sizeof(p->name));
+
+ }
+
+ return p;
+
+}
+
+/* Note that this is called every time the user clicks on an item,
+ whether it is already selected or not. */
+static void cb_select_child (GtkWidget *root_tree, GtkWidget *child,
+ GtkWidget *subtree)
+{
+ gint dh, err, dirlen;
+ char dirbuf[512];
+ struct smbc_dirent *dirp;
+ struct stat st1;
+ char *path;
+ TALLOC_CTX *ctx = talloc_stackframe();
+
+ g_print ("select_child called for root tree %p, subtree %p, child %p\n",
+ root_tree, subtree, child);
+
+ /* Now, figure out what it is, and display it in the clist ... */
+
+ gtk_clist_clear(GTK_CLIST(clist)); /* Clear the CLIST */
+
+ /* Now, get the private data for the subtree */
+
+ path = get_path(ctx, child);
+ if (!path) {
+ gtk_main_quit();
+ TALLOC_FREE(ctx);
+ return;
+ }
+
+ if ((dh = smbc_opendir(path)) < 0) { /* Handle error */
+ g_print("cb_select_child: Could not open dir %s, %s\n", path,
+ strerror(errno));
+ gtk_main_quit();
+ TALLOC_FREE(ctx);
+ return;
+ }
+
+ while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf,
+ sizeof(dirbuf))) != 0) {
+ if (err < 0) {
+ g_print("cb_select_child: Could not read dir %s, %s\n", path,
+ strerror(errno));
+ gtk_main_quit();
+ TALLOC_FREE(ctx);
+ return;
+ }
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ while (err > 0) {
+ gchar col1[128], col2[128], col3[128], col4[128];
+ gchar *rowdata[4] = {col1, col2, col3, col4};
+
+ dirlen = dirp->dirlen;
+
+ /* Format each of the items ... */
+
+ strncpy(col1, dirp->name, 128);
+
+ col2[0] = col3[0] = col4[0] = (char)0;
+
+ switch (dirp->smbc_type) {
+
+ case SMBC_WORKGROUP:
+
+ break;
+
+ case SMBC_SERVER:
+
+ strncpy(col2, (dirp->comment?dirp->comment:""), 128);
+
+ break;
+
+ case SMBC_FILE_SHARE:
+
+ strncpy(col2, (dirp->comment?dirp->comment:""), 128);
+
+ break;
+
+ case SMBC_PRINTER_SHARE:
+
+ strncpy(col2, (dirp->comment?dirp->comment:""), 128);
+ break;
+
+ case SMBC_COMMS_SHARE:
+
+ break;
+
+ case SMBC_IPC_SHARE:
+
+ break;
+
+ case SMBC_DIR:
+ case SMBC_FILE:
+
+ /* Get stats on the file/dir and see what we have */
+
+ if ((strcmp(dirp->name, ".") != 0) &&
+ (strcmp(dirp->name, "..") != 0)) {
+ char *path1;
+
+ path1 = talloc_asprintf(ctx,
+ "%s/%s",
+ path,
+ dirp->name);
+ if (!path1) {
+ gtk_main_quit();
+ TALLOC_FREE(ctx);
+ return;
+ }
+
+ if (smbc_stat(path1, &st1) < 0) {
+ if (errno != EBUSY) {
+ g_print("cb_select_child: Could not stat file %s, %s\n", path1,
+ strerror(errno));
+ gtk_main_quit();
+ TALLOC_FREE(ctx);
+ return;
+ } else {
+ strncpy(col2, "Device or resource busy", sizeof(col2));
+ }
+ }
+ else {
+ /* Now format each of the relevant things ... */
+
+ snprintf(col2, sizeof(col2), "%c%c%c%c%c%c%c%c%c(%0X)",
+ (st1.st_mode&S_IRUSR?'r':'-'),
+ (st1.st_mode&S_IWUSR?'w':'-'),
+ (st1.st_mode&S_IXUSR?'x':'-'),
+ (st1.st_mode&S_IRGRP?'r':'-'),
+ (st1.st_mode&S_IWGRP?'w':'-'),
+ (st1.st_mode&S_IXGRP?'x':'-'),
+ (st1.st_mode&S_IROTH?'r':'-'),
+ (st1.st_mode&S_IWOTH?'w':'-'),
+ (st1.st_mode&S_IXOTH?'x':'-'),
+ st1.st_mode);
+ snprintf(col3, sizeof(col3), "%u", st1.st_size);
+ snprintf(col4, sizeof(col4), "%s", ctime(&st1.st_mtime));
+ }
+ }
+
+ break;
+
+ default:
+
+ break;
+ }
+
+ gtk_clist_append(GTK_CLIST(clist), rowdata);
+
+ (char *)dirp += dirlen;
+ err -= dirlen;
+
+ }
+ }
+ TALLOC_FREE(ctx);
+}
+
+/* Note that this is never called */
+static void cb_unselect_child( GtkWidget *root_tree,
+ GtkWidget *child,
+ GtkWidget *subtree )
+{
+ g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
+ root_tree, subtree, child);
+}
+
+/* for all the GtkItem:: and GtkTreeItem:: signals */
+static void cb_itemsignal( GtkWidget *item,
+ gchar *signame )
+{
+ GtkWidget *real_tree, *aitem, *subtree;
+ gchar *name;
+ GtkLabel *label;
+ gint dh, err, dirlen, level;
+ char dirbuf[512];
+ struct smbc_dirent *dirp;
+
+ label = GTK_LABEL (GTK_BIN (item)->child);
+ /* Get the text of the label */
+ gtk_label_get (label, &name);
+
+ level = GTK_TREE(item->parent)->level;
+
+ /* Get the level of the tree which the item is in */
+ g_print ("%s called for item %s->%p, level %d\n", signame, name,
+ item, GTK_TREE (item->parent)->level);
+
+ real_tree = GTK_TREE_ITEM_SUBTREE(item); /* Get the subtree */
+
+ if (strncmp(signame, "expand", 6) == 0) { /* Expand called */
+ char server[128];
+
+ if ((dh = smbc_opendir(get_path(item))) < 0) { /* Handle error */
+ gchar errmsg[256];
+
+ g_print("cb_itemsignal: Could not open dir %s, %s\n", get_path(item),
+ strerror(errno));
+
+ slprintf(errmsg, sizeof(errmsg), "cb_itemsignal: Could not open dir %s, %s\n", get_path(item), strerror(errno));
+
+ tree_error_message(errmsg);
+
+ /* gtk_main_quit();*/
+
+ return;
+
+ }
+
+ while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf,
+ sizeof(dirbuf))) != 0) {
+
+ if (err < 0) { /* An error, report it */
+ gchar errmsg[256];
+
+ g_print("cb_itemsignal: Could not read dir smbc://, %s\n",
+ strerror(errno));
+
+ slprintf(errmsg, sizeof(errmsg), "cb_itemsignal: Could not read dir smbc://, %s\n", strerror(errno));
+
+ tree_error_message(errmsg);
+
+ /* gtk_main_quit();*/
+
+ return;
+
+ }
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ while (err > 0) {
+ struct tree_data *my_data;
+
+ dirlen = dirp->dirlen;
+
+ my_data = make_tree_data(dirp->smbc_type, dirp->name);
+
+ if (!my_data) {
+
+ g_print("Could not allocate space for tree_data: %s\n",
+ dirp->name);
+
+ gtk_main_quit();
+ return;
+
+ }
+
+ aitem = gtk_tree_item_new_with_label(dirp->name);
+
+ /* Connect all GtkItem:: and GtkTreeItem:: signals */
+ gtk_signal_connect (GTK_OBJECT(aitem), "select",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+ gtk_signal_connect (GTK_OBJECT(aitem), "deselect",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+ gtk_signal_connect (GTK_OBJECT(aitem), "toggle",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+ gtk_signal_connect (GTK_OBJECT(aitem), "expand",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+ gtk_signal_connect (GTK_OBJECT(aitem), "collapse",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+ /* Add it to the parent tree */
+ gtk_tree_append (GTK_TREE(real_tree), aitem);
+
+ gtk_widget_show (aitem);
+
+ gtk_object_set_user_data(GTK_OBJECT(aitem), (gpointer)my_data);
+
+ fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen);
+
+ if (dirp->smbc_type != SMBC_FILE &&
+ dirp->smbc_type != SMBC_IPC_SHARE &&
+ (strcmp(dirp->name, ".") != 0) &&
+ (strcmp(dirp->name, "..") !=0)){
+
+ subtree = gtk_tree_new();
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(aitem), subtree);
+
+ gtk_signal_connect(GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), real_tree);
+ gtk_signal_connect(GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), real_tree);
+
+ }
+
+ (char *)dirp += dirlen;
+ err -= dirlen;
+
+ }
+
+ }
+
+ smbc_closedir(dh);
+
+ }
+ else if (strncmp(signame, "collapse", 8) == 0) {
+ GtkWidget *subtree = gtk_tree_new();
+
+ gtk_tree_remove_items(GTK_TREE(real_tree), GTK_TREE(real_tree)->children);
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
+
+ gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), real_tree);
+ gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), real_tree);
+
+ }
+
+}
+
+static void cb_selection_changed( GtkWidget *tree )
+{
+ GList *i;
+
+ g_print ("selection_change called for tree %p\n", tree);
+ g_print ("selected objects are:\n");
+
+ i = GTK_TREE_SELECTION(tree);
+ while (i){
+ gchar *name;
+ GtkLabel *label;
+ GtkWidget *item;
+
+ /* Get a GtkWidget pointer from the list node */
+ item = GTK_WIDGET (i->data);
+ label = GTK_LABEL (GTK_BIN (item)->child);
+ gtk_label_get (label, &name);
+ g_print ("\t%s on level %d\n", name, GTK_TREE
+ (item->parent)->level);
+ i = i->next;
+ }
+}
+
+/*
+ * Expand or collapse the whole network ...
+ */
+static void cb_wholenet(GtkWidget *item, gchar *signame)
+{
+ GtkWidget *real_tree, *aitem, *subtree;
+ gchar *name;
+ GtkLabel *label;
+ gint dh, err, dirlen;
+ char dirbuf[512];
+ struct smbc_dirent *dirp;
+
+ label = GTK_LABEL (GTK_BIN (item)->child);
+ gtk_label_get (label, &name);
+ g_print ("%s called for item %s->%p, level %d\n", signame, name,
+ item, GTK_TREE (item->parent)->level);
+
+ real_tree = GTK_TREE_ITEM_SUBTREE(item); /* Get the subtree */
+
+ if (strncmp(signame, "expand", 6) == 0) { /* Expand called */
+
+ if ((dh = smbc_opendir("smb://")) < 0) { /* Handle error */
+
+ g_print("cb_wholenet: Could not open dir smbc://, %s\n",
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+
+ while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf,
+ sizeof(dirbuf))) != 0) {
+
+ if (err < 0) { /* An error, report it */
+
+ g_print("cb_wholenet: Could not read dir smbc://, %s\n",
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ while (err > 0) {
+ struct tree_data *my_data;
+
+ dirlen = dirp->dirlen;
+
+ my_data = make_tree_data(dirp->smbc_type, dirp->name);
+
+ aitem = gtk_tree_item_new_with_label(dirp->name);
+
+ /* Connect all GtkItem:: and GtkTreeItem:: signals */
+ gtk_signal_connect (GTK_OBJECT(aitem), "select",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+ gtk_signal_connect (GTK_OBJECT(aitem), "deselect",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+ gtk_signal_connect (GTK_OBJECT(aitem), "toggle",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+ gtk_signal_connect (GTK_OBJECT(aitem), "expand",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+ gtk_signal_connect (GTK_OBJECT(aitem), "collapse",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+
+ gtk_tree_append (GTK_TREE(real_tree), aitem);
+ /* Show it - this can be done at any time */
+ gtk_widget_show (aitem);
+
+ gtk_object_set_user_data(GTK_OBJECT(aitem), (gpointer)my_data);
+
+ fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen);
+
+ subtree = gtk_tree_new();
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(aitem), subtree);
+
+ gtk_signal_connect(GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), real_tree);
+ gtk_signal_connect(GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), real_tree);
+
+ (char *)dirp += dirlen;
+ err -= dirlen;
+
+ }
+
+ }
+
+ smbc_closedir(dh);
+
+ }
+ else { /* Must be collapse ... FIXME ... */
+ GtkWidget *subtree = gtk_tree_new();
+
+ gtk_tree_remove_items(GTK_TREE(real_tree), GTK_TREE(real_tree)->children);
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
+
+ gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), real_tree);
+ gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), real_tree);
+
+
+ }
+
+}
+
+/* Should put up a dialog box to ask the user for username and password */
+
+static void
+auth_fn(const char *server, const char *share,
+ char *workgroup, int wgmaxlen, char *username, int unmaxlen,
+ char *password, int pwmaxlen)
+{
+
+ strncpy(username, "test", unmaxlen);
+ strncpy(password, "test", pwmaxlen);
+
+}
+
+static char *col_titles[] = {
+ "Name", "Attributes", "Size", "Modification Date",
+};
+
+int main( int argc,
+ char *argv[] )
+{
+ GtkWidget *window, *scrolled_win, *scrolled_win2, *tree;
+ GtkWidget *subtree, *item, *main_hbox, *r_pane, *l_pane;
+ gint err, dh;
+ gint i;
+ char dirbuf[512];
+ struct smbc_dirent *dirp;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ gtk_init (&argc, &argv);
+
+ /* Init the smbclient library */
+
+ err = smbc_init(auth_fn, 10);
+
+ /* Print an error response ... */
+
+ if (err < 0) {
+
+ fprintf(stderr, "smbc_init returned %s (%i)\nDo you have a ~/.smb/smb.conf file?\n", strerror(errno), errno);
+ exit(1);
+
+ }
+
+ /* a generic toplevel window */
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_widget_set_name(window, "main browser window");
+ gtk_signal_connect (GTK_OBJECT(window), "delete_event",
+ GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+ gtk_window_set_title(GTK_WINDOW(window), "The Linux Windows Network Browser");
+ gtk_widget_set_usize(GTK_WIDGET(window), 750, -1);
+ gtk_container_set_border_width (GTK_CONTAINER(window), 5);
+
+ gtk_widget_show (window);
+
+ /* A container for the two panes ... */
+
+ main_hbox = gtk_hbox_new(FALSE, 1);
+ gtk_container_border_width(GTK_CONTAINER(main_hbox), 1);
+ gtk_container_add(GTK_CONTAINER(window), main_hbox);
+
+ gtk_widget_show(main_hbox);
+
+ l_pane = gtk_hpaned_new();
+ gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
+ r_pane = gtk_hpaned_new();
+ gtk_paned_gutter_size(GTK_PANED(r_pane), (GTK_PANED(r_pane))->handle_size);
+ gtk_container_add(GTK_CONTAINER(main_hbox), l_pane);
+ gtk_widget_show(l_pane);
+
+ /* A generic scrolled window */
+ scrolled_win = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_widget_set_usize (scrolled_win, 150, 200);
+ gtk_container_add (GTK_CONTAINER(l_pane), scrolled_win);
+ gtk_widget_show (scrolled_win);
+
+ /* Another generic scrolled window */
+ scrolled_win2 = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win2),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_widget_set_usize (scrolled_win2, 150, 200);
+ gtk_paned_add2 (GTK_PANED(l_pane), scrolled_win2);
+ gtk_widget_show (scrolled_win2);
+
+ /* Create the root tree */
+ tree = gtk_tree_new();
+ g_print ("root tree is %p\n", tree);
+ /* connect all GtkTree:: signals */
+ gtk_signal_connect (GTK_OBJECT(tree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), tree);
+ gtk_signal_connect (GTK_OBJECT(tree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), tree);
+ gtk_signal_connect (GTK_OBJECT(tree), "selection_changed",
+ GTK_SIGNAL_FUNC(cb_selection_changed), tree);
+ /* Add it to the scrolled window */
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(scrolled_win),
+ tree);
+ /* Set the selection mode */
+ gtk_tree_set_selection_mode (GTK_TREE(tree),
+ GTK_SELECTION_MULTIPLE);
+ /* Show it */
+ gtk_widget_show (tree);
+
+ /* Now, create a clist and attach it to the second pane */
+
+ clist = gtk_clist_new_with_titles(4, col_titles);
+
+ gtk_container_add (GTK_CONTAINER(scrolled_win2), clist);
+
+ gtk_widget_show(clist);
+
+ /* Now, build the top level display ... */
+
+ if ((dh = smbc_opendir("smb:///")) < 0) {
+
+ fprintf(stderr, "Could not list default workgroup: smb:///: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ /* Create a tree item for Whole Network */
+
+ item = gtk_tree_item_new_with_label ("Whole Network");
+ /* Connect all GtkItem:: and GtkTreeItem:: signals */
+ gtk_signal_connect (GTK_OBJECT(item), "select",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+ gtk_signal_connect (GTK_OBJECT(item), "deselect",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+ gtk_signal_connect (GTK_OBJECT(item), "toggle",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+ gtk_signal_connect (GTK_OBJECT(item), "expand",
+ GTK_SIGNAL_FUNC(cb_wholenet), "expand");
+ gtk_signal_connect (GTK_OBJECT(item), "collapse",
+ GTK_SIGNAL_FUNC(cb_wholenet), "collapse");
+ /* Add it to the parent tree */
+ gtk_tree_append (GTK_TREE(tree), item);
+ /* Show it - this can be done at any time */
+ gtk_widget_show (item);
+
+ subtree = gtk_tree_new(); /* A subtree for Whole Network */
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
+
+ gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), tree);
+ gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), tree);
+
+ /* Now, get the items in smb:/// and add them to the tree */
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf,
+ sizeof(dirbuf))) != 0) {
+
+ if (err < 0) { /* Handle the error */
+
+ fprintf(stderr, "Could not read directory for smbc:///: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ fprintf(stdout, "Dir len: %u\n", err);
+
+ while (err > 0) { /* Extract each entry and make a sub-tree */
+ struct tree_data *my_data;
+ int dirlen = dirp->dirlen;
+
+ my_data = make_tree_data(dirp->smbc_type, dirp->name);
+
+ item = gtk_tree_item_new_with_label(dirp->name);
+ /* Connect all GtkItem:: and GtkTreeItem:: signals */
+ gtk_signal_connect (GTK_OBJECT(item), "select",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+ gtk_signal_connect (GTK_OBJECT(item), "deselect",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+ gtk_signal_connect (GTK_OBJECT(item), "toggle",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+ gtk_signal_connect (GTK_OBJECT(item), "expand",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+ gtk_signal_connect (GTK_OBJECT(item), "collapse",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+ /* Add it to the parent tree */
+ gtk_tree_append (GTK_TREE(tree), item);
+ /* Show it - this can be done at any time */
+ gtk_widget_show (item);
+
+ gtk_object_set_user_data(GTK_OBJECT(item), (gpointer)my_data);
+
+ fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen);
+
+ subtree = gtk_tree_new();
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
+
+ gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), tree);
+ gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), tree);
+
+ (char *)dirp += dirlen;
+ err -= dirlen;
+
+ }
+
+ }
+
+ smbc_closedir(dh); /* FIXME, check for error :-) */
+
+ /* Show the window and loop endlessly */
+ gtk_main();
+ TALLOC_FREE(frame);
+ return 0;
+}
+/* example-end */
diff --git a/source3/client/umount.cifs.c b/source3/client/umount.cifs.c
new file mode 100644
index 0000000000..3e2415ad00
--- /dev/null
+++ b/source3/client/umount.cifs.c
@@ -0,0 +1,386 @@
+/*
+ Unmount utility program for Linux CIFS VFS (virtual filesystem) client
+ Copyright (C) 2005 Steve French (sfrench@us.ibm.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <errno.h>
+#include <string.h>
+#include <mntent.h>
+
+#define UNMOUNT_CIFS_VERSION_MAJOR "0"
+#define UNMOUNT_CIFS_VERSION_MINOR "5"
+
+#ifndef UNMOUNT_CIFS_VENDOR_SUFFIX
+ #ifdef _SAMBA_BUILD_
+ #include "include/version.h"
+ #ifdef SAMBA_VERSION_VENDOR_SUFFIX
+ #define UNMOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING"-"SAMBA_VERSION_VENDOR_SUFFIX
+ #else
+ #define UNMOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING
+ #endif /* SAMBA_VERSION_OFFICIAL_STRING and SAMBA_VERSION_VENDOR_SUFFIX */
+ #else
+ #define UNMOUNT_CIFS_VENDOR_SUFFIX ""
+ #endif /* _SAMBA_BUILD_ */
+#endif /* UNMOUNT_CIFS_VENDOR_SUFFIX */
+
+#ifndef MNT_DETACH
+#define MNT_DETACH 0x02
+#endif
+
+#ifndef MNT_EXPIRE
+#define MNT_EXPIRE 0x04
+#endif
+
+#ifndef MOUNTED_LOCK
+#define MOUNTED_LOCK "/etc/mtab~"
+#endif
+#ifndef MOUNTED_TEMP
+#define MOUNTED_TEMP "/etc/mtab.tmp"
+#endif
+
+#define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2)
+#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDU */
+
+static struct option longopts[] = {
+ { "all", 0, NULL, 'a' },
+ { "help",0, NULL, 'h' },
+ { "read-only", 0, NULL, 'r' },
+ { "ro", 0, NULL, 'r' },
+ { "verbose", 0, NULL, 'v' },
+ { "version", 0, NULL, 'V' },
+ { "expire", 0, NULL, 'e' },
+ { "force", 0, 0, 'f' },
+ { "lazy", 0, 0, 'l' },
+ { "no-mtab", 0, 0, 'n' },
+ { NULL, 0, NULL, 0 }
+};
+
+const char * thisprogram;
+int verboseflg = 0;
+
+static void umount_cifs_usage(void)
+{
+ printf("\nUsage: %s <remotetarget> <dir>\n", thisprogram);
+ printf("\nUnmount the specified directory\n");
+ printf("\nLess commonly used options:");
+ printf("\n\t-r\tIf mount fails, retry with readonly remount.");
+ printf("\n\t-n\tDo not write to mtab.");
+ printf("\n\t-f\tAttempt a forced unmount, even if the fs is busy.");
+ printf("\n\t-l\tAttempt lazy unmount, Unmount now, cleanup later.");
+ printf("\n\t-v\tEnable verbose mode (may be useful for debugging).");
+ printf("\n\t-h\tDisplay this help.");
+ printf("\n\nOptions are described in more detail in the manual page");
+ printf("\n\tman 8 umount.cifs\n");
+ printf("\nTo display the version number of the cifs umount utility:");
+ printf("\n\t%s -V\n",thisprogram);
+ printf("\nInvoking the umount utility on cifs mounts, can execute");
+ printf(" /sbin/umount.cifs (if present and umount -i is not specified.\n");
+}
+
+static int umount_check_perm(char * dir)
+{
+ int fileid;
+ int rc;
+
+ /* allow root to unmount, no matter what */
+ if(getuid() == 0)
+ return 0;
+
+ /* presumably can not chdir into the target as we do on mount */
+ fileid = open(dir, O_RDONLY | O_DIRECTORY | O_NOFOLLOW, 0);
+ if(fileid == -1) {
+ if(verboseflg)
+ printf("error opening mountpoint %d %s",errno,strerror(errno));
+ return errno;
+ }
+
+ rc = ioctl(fileid, CIFS_IOC_CHECKUMOUNT, NULL);
+
+ if(verboseflg)
+ printf("ioctl returned %d with errno %d %s\n",rc,errno,strerror(errno));
+
+ if(rc == ENOTTY) {
+ printf("user unmounting via %s is an optional feature of",thisprogram);
+ printf(" the cifs filesystem driver (cifs.ko)");
+ printf("\n\tand requires cifs.ko version 1.32 or later\n");
+ } else if (rc != 0)
+ printf("user unmount of %s failed with %d %s\n",dir,errno,strerror(errno));
+ close(fileid);
+
+ return rc;
+}
+
+static int lock_mtab(void)
+{
+ int rc;
+
+ rc = mknod(MOUNTED_LOCK , 0600, 0);
+ if(rc == -1)
+ printf("\ngetting lock file %s failed with %s\n",MOUNTED_LOCK,
+ strerror(errno));
+
+ return rc;
+
+}
+
+static void unlock_mtab(void)
+{
+ unlink(MOUNTED_LOCK);
+}
+
+static int remove_from_mtab(char * mountpoint)
+{
+ int rc;
+ int num_matches;
+ FILE * org_fd;
+ FILE * new_fd;
+ struct mntent * mount_entry;
+
+ /* Do we need to check if it is a symlink to e.g. /proc/mounts
+ in which case we probably do not want to update it? */
+
+ /* Do we first need to check if it is writable? */
+
+ if (lock_mtab()) {
+ printf("Mount table locked\n");
+ return -EACCES;
+ }
+
+ if(verboseflg)
+ printf("attempting to remove from mtab\n");
+
+ org_fd = setmntent(MOUNTED, "r");
+
+ if(org_fd == NULL) {
+ printf("Can not open %s\n",MOUNTED);
+ unlock_mtab();
+ return -EIO;
+ }
+
+ new_fd = setmntent(MOUNTED_TEMP,"w");
+ if(new_fd == NULL) {
+ printf("Can not open temp file %s", MOUNTED_TEMP);
+ endmntent(org_fd);
+ unlock_mtab();
+ return -EIO;
+ }
+
+ /* BB fix so we only remove the last entry that matches BB */
+ num_matches = 0;
+ while((mount_entry = getmntent(org_fd)) != NULL) {
+ if(strcmp(mount_entry->mnt_dir, mountpoint) == 0) {
+ num_matches++;
+ }
+ }
+ if(verboseflg)
+ printf("%d matching entries in mount table\n", num_matches);
+
+ /* Is there a better way to seek back to the first entry in mtab? */
+ endmntent(org_fd);
+ org_fd = setmntent(MOUNTED, "r");
+
+ if(org_fd == NULL) {
+ printf("Can not open %s\n",MOUNTED);
+ unlock_mtab();
+ return -EIO;
+ }
+
+ while((mount_entry = getmntent(org_fd)) != NULL) {
+ if(strcmp(mount_entry->mnt_dir, mountpoint) != 0) {
+ addmntent(new_fd, mount_entry);
+ } else {
+ if(num_matches != 1) {
+ addmntent(new_fd, mount_entry);
+ num_matches--;
+ } else if(verboseflg)
+ printf("entry not copied (ie entry is removed)\n");
+ }
+ }
+
+ if(verboseflg)
+ printf("done updating tmp file\n");
+ rc = fchmod (fileno (new_fd), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if(rc < 0) {
+ printf("error %s changing mode of %s\n", strerror(errno),
+ MOUNTED_TEMP);
+ }
+ endmntent(new_fd);
+
+ rc = rename(MOUNTED_TEMP, MOUNTED);
+
+ if(rc < 0) {
+ printf("failure %s renaming %s to %s\n",strerror(errno),
+ MOUNTED_TEMP, MOUNTED);
+ unlock_mtab();
+ return -EIO;
+ }
+
+ unlock_mtab();
+
+ return rc;
+}
+
+int main(int argc, char ** argv)
+{
+ int c;
+ int rc;
+ int flags = 0;
+ int nomtab = 0;
+ int retry_remount = 0;
+ struct statfs statbuf;
+ char * mountpoint;
+
+ if(argc && argv) {
+ thisprogram = argv[0];
+ } else {
+ umount_cifs_usage();
+ return -EINVAL;
+ }
+
+ if(argc < 2) {
+ umount_cifs_usage();
+ return -EINVAL;
+ }
+
+ if(thisprogram == NULL)
+ thisprogram = "umount.cifs";
+
+ /* add sharename in opts string as unc= parm */
+
+ while ((c = getopt_long (argc, argv, "afhilnrvV",
+ longopts, NULL)) != -1) {
+ switch (c) {
+/* No code to do the following option yet */
+/* case 'a':
+ ++umount_all;
+ break; */
+ case '?':
+ case 'h': /* help */
+ umount_cifs_usage();
+ exit(1);
+ case 'n':
+ ++nomtab;
+ break;
+ case 'f':
+ flags |= MNT_FORCE;
+ break;
+ case 'l':
+ flags |= MNT_DETACH; /* lazy unmount */
+ break;
+ case 'e':
+ flags |= MNT_EXPIRE; /* gradually timeout */
+ break;
+ case 'r':
+ ++retry_remount;
+ break;
+ case 'v':
+ ++verboseflg;
+ break;
+ case 'V':
+ printf ("umount.cifs version: %s.%s%s\n",
+ UNMOUNT_CIFS_VERSION_MAJOR,
+ UNMOUNT_CIFS_VERSION_MINOR,
+ UNMOUNT_CIFS_VENDOR_SUFFIX);
+ exit (0);
+ default:
+ printf("unknown unmount option %c\n",c);
+ umount_cifs_usage();
+ exit(1);
+ }
+ }
+
+ /* move past the umount options */
+ argv += optind;
+ argc -= optind;
+
+ mountpoint = argv[0];
+
+ if((argc < 1) || (argv[0] == NULL)) {
+ printf("\nMissing name of unmount directory\n");
+ umount_cifs_usage();
+ return -EINVAL;
+ }
+
+ if(verboseflg)
+ printf("optind %d unmount dir %s\n",optind, mountpoint);
+
+ /* check if running effectively root */
+ if(geteuid() != 0) {
+ printf("Trying to unmount when %s not installed suid\n",thisprogram);
+ if(verboseflg)
+ printf("euid = %d\n",geteuid());
+ return -EACCES;
+ }
+
+ /* fixup path if needed */
+
+ /* Trim any trailing slashes */
+ while ((strlen(mountpoint) > 1) &&
+ (mountpoint[strlen(mountpoint)-1] == '/'))
+ {
+ mountpoint[strlen(mountpoint)-1] = '\0';
+ }
+
+ /* make sure that this is a cifs filesystem */
+ rc = statfs(mountpoint, &statbuf);
+
+ if(rc || (statbuf.f_type != CIFS_MAGIC_NUMBER)) {
+ printf("This utility only unmounts cifs filesystems.\n");
+ return -EINVAL;
+ }
+
+ /* check if our uid was the one who mounted */
+ rc = umount_check_perm(mountpoint);
+ if (rc) {
+ printf("Not permitted to unmount\n");
+ return rc;
+ }
+
+ if(umount2(mountpoint, flags)) {
+ /* remember to kill daemon on error */
+ switch (errno) {
+ case 0:
+ printf("unmount failed but no error number set\n");
+ break;
+ default:
+ printf("unmount error %d = %s\n",errno,strerror(errno));
+ }
+ printf("Refer to the umount.cifs(8) manual page (man 8 umount.cifs)\n");
+ return -1;
+ } else {
+ if(verboseflg)
+ printf("umount2 succeeded\n");
+ if(nomtab == 0)
+ remove_from_mtab(mountpoint);
+ }
+
+ return 0;
+}
+
diff --git a/source3/codepages/lowcase.dat b/source3/codepages/lowcase.dat
new file mode 100644
index 0000000000..62b6e2e952
--- /dev/null
+++ b/source3/codepages/lowcase.dat
Binary files differ
diff --git a/source3/codepages/upcase.dat b/source3/codepages/upcase.dat
new file mode 100644
index 0000000000..bb6f9beb4e
--- /dev/null
+++ b/source3/codepages/upcase.dat
Binary files differ
diff --git a/source3/codepages/valid.dat b/source3/codepages/valid.dat
new file mode 100644
index 0000000000..78c14b33f0
--- /dev/null
+++ b/source3/codepages/valid.dat
Binary files differ
diff --git a/source3/config.guess b/source3/config.guess
new file mode 100755
index 0000000000..600580b1aa
--- /dev/null
+++ b/source3/config.guess
@@ -0,0 +1,1463 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+timestamp='2005-09-19'
+
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerppc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # 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 ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ 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 ;;
+ 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 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????: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 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ 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 ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep __LP64__ >/dev/null
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ x86:Interix*:[34]*)
+ echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
+ exit ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #ifdef __INTEL_COMPILER
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+ test x"${LIBC}" != x && {
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit
+ }
+ test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ 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 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *: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 ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# 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 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+and
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/source3/config.sub b/source3/config.sub
new file mode 100755
index 0000000000..23cd6fd75c
--- /dev/null
+++ b/source3/config.sub
@@ -0,0 +1,1577 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+timestamp='2005-07-08'
+
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \
+ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64vr | mips64vrel \
+ | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | ms1 \
+ | msp430 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b \
+ | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m32c)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | ms1-* \
+ | msp430-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ m32c-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ 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 | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16c)
+ basic_machine=cr16c-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/source3/configure.developer b/source3/configure.developer
new file mode 100755
index 0000000000..5033670209
--- /dev/null
+++ b/source3/configure.developer
@@ -0,0 +1,6 @@
+#!/bin/sh
+`dirname $0`/configure -C \
+ --enable-developer \
+ --enable-socket-wrapper \
+ --enable-nss-wrapper \
+ "$@"
diff --git a/source3/configure.in b/source3/configure.in
new file mode 100644
index 0000000000..f813e87fb7
--- /dev/null
+++ b/source3/configure.in
@@ -0,0 +1,6268 @@
+dnl Process this file with autoconf to produce a configure script.
+
+dnl We must use autotools 2.54 or above
+AC_PREREQ(2.54)
+
+AC_INIT([Samba],[3],[samba-technical@samba.org])
+
+AC_CONFIG_SRCDIR([include/includes.h])
+AC_CONFIG_HEADER(include/config.h)
+AC_DEFINE(CONFIG_H_IS_FROM_SAMBA,1,[Marker for samba's config.h])
+
+case "$PATH" in
+ */usr/ucb*)
+ AC_MSG_WARN([\$PATH contains /usr/ucb - build errors may follow])
+ ;;
+esac
+
+builddir=`pwd`
+AC_SUBST(builddir)
+
+m4_include(m4/samba_version.m4)
+m4_include(m4/check_path.m4)
+
+AC_LIBREPLACE_CC_CHECKS
+
+m4_include(lib/talloc/libtalloc.m4)
+
+LIBTALLOC_OBJ0=""
+for obj in ${TALLOC_OBJ}; do
+ LIBTALLOC_OBJ0="${LIBTALLOC_OBJ0} ${tallocdir}/${obj}"
+done
+AC_SUBST(LIBTALLOC_OBJ0)
+
+# TODO: These should come from m4_include(lib/tdb/libtdb.m4)
+# but currently this fails: things have to get merged from s4.
+tdbdir="lib/tdb"
+AC_SUBST(tdbdir)
+TDB_CFLAGS="-I${srcdir-.}/$tdbdir/include"
+AC_SUBST(TDB_CFLAGS)
+
+LIBTDB_OBJ0=""
+for o in common/tdb.o common/dump.o common/transaction.o common/error.o \
+ common/traverse.o common/freelist.o common/freelistcheck.o \
+ common/io.o common/lock.o common/open.o;
+do
+ LIBTDB_OBJ0="$LIBTDB_OBJ0 lib/tdb/$o"
+done
+
+AC_SUBST(LIBTDB_OBJ0)
+SAMBA_CPPFLAGS="-Iinclude -I${srcdir-.}/include -I. -I${srcdir-.}"
+SAMBA_CPPFLAGS="${SAMBA_CPPFLAGS} -I${srcdir-.}/lib/replace"
+SAMBA_CPPFLAGS="${SAMBA_CPPFLAGS} ${TALLOC_CFLAGS}"
+SAMBA_CPPFLAGS="${SAMBA_CPPFLAGS} ${TDB_CFLAGS}"
+SAMBA_CPPFLAGS="${SAMBA_CPPFLAGS} -I${srcdir-.}/libaddns"
+SAMBA_CPPFLAGS="${SAMBA_CPPFLAGS} -I${srcdir-.}/librpc"
+
+SAMBA_CONFIGURE_CPPFLAGS="${SAMBA_CPPFLAGS} -I${srcdir-.}/popt"
+
+## cleanup the $(srcdir) in the Makefile if we are outside of the tree
+if test "x${srcdir-.}" != "x."; then
+ SAMBA_CPPFLAGS=`echo ${SAMBA_CPPFLAGS} | sed -e "s;${srcdir};\$\(srcdir\);g"`
+fi
+
+dnl Unique-to-Samba variables we'll be playing with.
+AC_SUBST(SAMBA_CPPFLAGS)
+AC_SUBST(SHELL)
+AC_SUBST(LDSHFLAGS)
+AC_SUBST(SONAMEFLAG)
+AC_SUBST(SHLD)
+AC_SUBST(MODULE_EXPORTS)
+AC_SUBST(DSO_EXPORTS)
+AC_SUBST(HOST_OS)
+AC_SUBST(PICFLAG)
+AC_SUBST(PIE_CFLAGS)
+AC_SUBST(PIE_LDFLAGS)
+AC_SUBST(RELRO_LDFLAGS)
+AC_SUBST(SHLIBEXT)
+AC_SUBST(INSTALLLIBCMD_SH)
+AC_SUBST(INSTALLLIBCMD_A)
+AC_SUBST(UNINSTALLLIBCMD_SH)
+AC_SUBST(UNINSTALLLIBCMD_A)
+
+AC_SUBST(INSTALL_LIBWBCLIENT)
+AC_SUBST(UNINSTALL_LIBWBCLIENT)
+AC_SUBST(LIBWBCLIENT_SHARED_TARGET)
+AC_SUBST(LIBWBCLIENT_SHARED)
+AC_SUBST(LIBWBCLIENT_STATIC_TARGET)
+AC_SUBST(LIBWBCLIENT_STATIC)
+AC_SUBST(LIBWBCLIENT_SOVER)
+AC_SUBST(LIBWBCLIENT)
+AC_SUBST(WINBIND_LIBS)
+
+AC_SUBST(LIBSAMBAUTIL_SHARED)
+
+AC_SUBST(PRINT_LIBS)
+AC_SUBST(AUTH_LIBS)
+AC_SUBST(ACL_LIBS)
+AC_SUBST(PASSDB_LIBS)
+AC_SUBST(IDMAP_LIBS)
+AC_SUBST(KRB5_LIBS)
+AC_SUBST(UUID_LIBS)
+AC_SUBST(LDAP_LIBS)
+AC_SUBST(GPEXT_LIBS)
+AC_SUBST(PAM_MODULES)
+AC_SUBST(INSTALL_PAM_MODULES)
+AC_SUBST(UNINSTALL_PAM_MODULES)
+AC_SUBST(NSS_MODULES)
+AC_SUBST(EXTRA_BIN_PROGS)
+AC_SUBST(CIFSMOUNT_PROGS)
+AC_SUBST(INSTALL_CIFSMOUNT)
+AC_SUBST(UNINSTALL_CIFSMOUNT)
+AC_SUBST(CIFSUPCALL_PROGS)
+AC_SUBST(INSTALL_CIFSUPCALL)
+AC_SUBST(UNINSTALL_CIFSUPCALL)
+AC_SUBST(EXTRA_SBIN_PROGS)
+AC_SUBST(EXTRA_ALL_TARGETS)
+AC_SUBST(CONFIG_LIBS)
+AC_SUBST(NSCD_LIBS)
+
+# compile with optimization and without debugging by default, but
+# allow people to set their own preference.
+# do this here since AC_CACHE_CHECK apparently sets the CFLAGS to "-g -O2"
+# if it has no value. This prevent *very* large debug binaries from occurring
+# by default.
+if test "x$CFLAGS" = x; then
+ CFLAGS="-O"
+fi
+if test "x$debug" = "xyes" ; then
+ CFLAGS="${CFLAGS} -g"
+else
+ CFLAGS="-O"
+fi
+
+CFLAGS="${CFLAGS} -D_SAMBA_BUILD_=3"
+
+m4_include(lib/socket_wrapper/config.m4)
+m4_include(lib/nss_wrapper/config.m4)
+
+m4_include(m4/swat.m4)
+
+# Probe the gcc version for extra CFLAGS. We always stash these in
+# DEVELOPER_CFLAGS, so that you can turn them on and off with a simple
+# Makefile edit, avoiding the need to re-run configure.
+if test x"$ac_cv_prog_gcc" = x"yes" ; then
+ DEVELOPER_CFLAGS="-g -Wall -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -DDEBUG_PASSWORD -DDEVELOPER"
+ # Add -Wdeclaration-after-statement if compiler supports it
+ AC_CACHE_CHECK(
+ [that the C compiler understands -Wdeclaration-after-statement],
+ samba_cv_HAVE_Wdeclaration_after_statement, [
+ AC_TRY_RUN_STRICT([
+ int main(void)
+ {
+ return 0;
+ }],[-Wdeclaration-after-statement],[$CPPFLAGS],[$LDFLAGS],
+ samba_cv_HAVE_Wdeclaration_after_statement=yes,
+ samba_cv_HAVE_Wdeclaration_after_statement=no,
+ samba_cv_HAVE_Wdeclaration_after_statement=cross)
+ ])
+
+ if test x"$samba_cv_HAVE_Wdeclaration_after_statement" = x"yes"; then
+ DEVELOPER_CFLAGS="${DEVELOPER_CFLAGS} -Wdeclaration-after-statement"
+ fi
+
+ #-Werror-implicit-function-declaration
+ AC_CACHE_CHECK(
+ [that the C compiler understands -Werror-implicit-function-declaration],
+ samba_cv_HAVE_Werror_implicit_function_declaration, [
+ AC_TRY_RUN_STRICT([
+ int main(void)
+ {
+ return 0;
+ }],[-Werror-implicit-function-declaration],[$CPPFLAGS],[$LDFLAGS],
+ samba_cv_HAVE_Werror_implicit_function_declaration=yes,
+ samba_cv_HAVE_Werror_implicit_function_declaration=no,
+ samba_cv_HAVE_Werror_implicit_function_declaration=cross)
+ ])
+ if test x"$samba_cv_HAVE_Werror_implicit_function_declaration" = x"yes"; then
+ DEVELOPER_CFLAGS="${DEVELOPER_CFLAGS} -Werror-implicit-function-declaration"
+ fi
+
+ # krb5developer is like developer, except we don't get
+ # -Wstrict-prototypes.
+ if test x"$krb5_developer" != x"$yes" ; then
+ DEVELOPER_CFLAGS="$DEVELOPER_CFLAGS -Wstrict-prototypes"
+ fi
+
+ if test x"$picky_developer" = x"yes"; then
+ DEVELOPER_CFLAGS="$DEVELOPER_CFLAGS -Werror"
+ fi
+fi
+
+AC_ARG_ENABLE(dmalloc, [AS_HELP_STRING([--enable-dmalloc], [Enable heap debugging [default=no]])])
+
+if test "x$enable_dmalloc" = xyes
+then
+ AC_DEFINE(ENABLE_DMALLOC, 1, [Define to turn on dmalloc debugging])
+ AC_DEFINE(DMALLOC_FUNC_CHECK, 1,
+ [Define to check invariants around some common functions])
+ LIBS="$LIBS -ldmalloc"
+fi
+
+#################################################
+# check for a shared memory profiling support
+AC_MSG_CHECKING(whether to use profiling)
+AC_ARG_WITH(profiling-data,
+[AS_HELP_STRING([--with-profiling-data], [Include gathering source code profile information (default=no)])],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_PROFILE,1,[Whether to use profiling])
+ samba_cv_WITH_PROFILE=yes
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ samba_cv_WITH_PROFILE=no
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+dnl Checks for programs.
+
+AC_PROG_INSTALL
+AC_PROG_AWK
+AC_PATH_PROG(PERL, perl)
+
+AC_CHECK_TOOL(AR, ar)
+
+dnl Check if we use GNU ld
+LD=ld
+AC_PROG_LD_GNU
+
+dnl Certain versions of GNU ld the default is not to have the
+dnl --allow-shlib-undefined flag defined. This causes a stackload of
+dnl warnings when building modules.
+if test "$ac_cv_prog_gnu_ld" = "yes"; then
+ ac_cv_gnu_ld_version=`$LD -v 2>/dev/null | head -1`
+ AC_MSG_CHECKING(GNU ld release date)
+ changequote(,)dnl
+ ac_cv_gnu_ld_date=`echo $ac_cv_gnu_ld_version | sed -n 's,^.*\([2-9][0-9][0-9][0-9]\)[-]*\([01][0-9]\)[-]*\([0-3][0-9]\).*$,\1\2\3,p'`
+ changequote([,])dnl
+ AC_MSG_RESULT(${ac_cv_gnu_ld_date})
+ if test -n "$ac_cv_gnu_ld_date"; then
+ if test "$ac_cv_gnu_ld_date" -lt 20030217; then
+ ac_cv_gnu_ld_no_default_allow_shlib_undefined=yes
+ fi
+ if test "$ac_cv_gnu_ld_date" -gt 20030101; then
+ ac_cv_gnu_ld_version_script=yes
+ fi
+ else
+ AC_MSG_CHECKING(GNU ld release version)
+ changequote(,)dnl
+ ac_cv_gnu_ld_vernr=`echo $ac_cv_gnu_ld_version | sed -n 's,^.*\([1-9][0-9]*\.[0-9][0-9]*\).*$,\1,p'`
+ ac_cv_gnu_ld_vernr_major=`echo $ac_cv_gnu_ld_vernr | cut -d '.' -f 1`
+ ac_cv_gnu_ld_vernr_minor=`echo $ac_cv_gnu_ld_vernr | cut -d '.' -f 2`
+ changequote([,])dnl
+ AC_MSG_RESULT(${ac_cv_gnu_ld_vernr})
+ AC_MSG_CHECKING(GNU ld release version major)
+ AC_MSG_RESULT(${ac_cv_gnu_ld_vernr_major})
+ AC_MSG_CHECKING(GNU ld release version minor)
+ AC_MSG_RESULT(${ac_cv_gnu_ld_vernr_minor})
+ if test "$ac_cv_gnu_ld_vernr_major" -lt 2 || test "$ac_cv_gnu_ld_vernr_minor" -lt 14; then
+ ac_cv_gnu_ld_no_default_allow_shlib_undefined=yes
+ fi
+ if test "$ac_cv_gnu_ld_vernr_major" -gt 2 || test "$ac_cv_gnu_ld_vernr_major"=2 && test "$ac_cv_gnu_ld_vernr_minor" -ge 12; then
+ ac_cv_gnu_ld_version_script=yes
+ fi
+ fi
+fi
+
+dnl look for executable suffix
+AC_EXEEXT
+
+dnl Check if C compiler understands -c and -o at the same time
+AC_PROG_CC_C_O
+if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" = no"; then
+ BROKEN_CC=
+else
+ BROKEN_CC=#
+fi
+AC_SUBST(BROKEN_CC)
+
+dnl Check if the C compiler understands -Werror
+AC_CACHE_CHECK([that the C compiler understands -Werror],samba_cv_HAVE_Werror, [
+ AC_TRY_RUN_STRICT([
+ int main(void)
+ {
+ return 0;
+ }],[-Werror],[$CPPFLAGS],[$LDFLAGS],
+ samba_cv_HAVE_Werror=yes,samba_cv_HAVE_Werror=no,samba_cv_HAVE_Werror=cross)])
+if test x"$samba_cv_HAVE_Werror" = x"yes"; then
+ Werror_FLAGS="-Werror"
+else
+dnl Check if the C compiler understands -w2
+AC_CACHE_CHECK([that the C compiler understands -w2],samba_cv_HAVE_w2, [
+ AC_TRY_RUN_STRICT([
+ int main(void)
+ {
+ return 0;
+ }],[-w2],[$CPPFLAGS],[$LDFLAGS],
+ samba_cv_HAVE_w2=yes,samba_cv_HAVE_w2=no,samba_cv_HAVE_w2=cross)])
+if test x"$samba_cv_HAVE_w2" = x"yes"; then
+ Werror_FLAGS="-w2"
+else
+dnl Check if the C compiler understands -errwarn
+AC_CACHE_CHECK([that the C compiler understands -errwarn],samba_cv_HAVE_errwarn, [
+ AC_TRY_RUN_STRICT([
+ int main(void)
+ {
+ return 0;
+ }],[-errwarn=%all],[$CPPFLAGS],[$LDFLAGS],
+ samba_cv_HAVE_errwarn=yes,samba_cv_HAVE_errwarn=no,samba_cv_HAVE_errwarn=cross)])
+if test x"$samba_cv_HAVE_errwarn" = x"yes"; then
+ Werror_FLAGS="-errwarn=%all"
+fi
+fi
+fi
+
+dnl Check if the C compiler understands volatile (it should, being ANSI).
+AC_CACHE_CHECK([that the C compiler understands volatile],samba_cv_volatile, [
+ AC_TRY_COMPILE([#include <sys/types.h>],[volatile int i = 0],
+ samba_cv_volatile=yes,samba_cv_volatile=no)])
+if test x"$samba_cv_volatile" = x"yes"; then
+ AC_DEFINE(HAVE_VOLATILE, 1, [Whether the C compiler understands volatile])
+fi
+
+############################################
+# check if the compiler can handle negative enum values
+# and don't truncate the values to INT_MAX
+# a runtime test is needed here
+AC_SUBST(PIDL_ARGS)
+AC_CACHE_CHECK([that the C compiler understands negative enum values],samba_cv_CC_NEGATIVE_ENUM_VALUES, [
+ AC_TRY_RUN(
+[
+ #include <stdio.h>
+ enum negative_values { NEGATIVE_VALUE = 0xFFFFFFFF };
+ int main(void) {
+ enum negative_values v1 = NEGATIVE_VALUE;
+ unsigned v2 = NEGATIVE_VALUE;
+
+ if (v1 != 0xFFFFFFFF) {
+ printf("%u != 0xFFFFFFFF\n", v1);
+ return 1;
+ }
+ if (v2 != 0xFFFFFFFF) {
+ printf("%u != 0xFFFFFFFF\n", v2);
+ return 1;
+ }
+
+ return 0;
+ }
+],
+ samba_cv_CC_NEGATIVE_ENUM_VALUES=yes,samba_cv__CC_NEGATIVE_ENUM_VALUES=no)])
+if test x"$samba_cv_CC_NEGATIVE_ENUM_VALUES" != x"yes"; then
+ AC_MSG_WARN([using --unit-enums for pidl])
+ PIDL_ARGS="$PIDL_ARGS --uint-enums"
+fi
+
+dnl Figure out the flags to support named structure initializers
+
+LIBREPLACE_C99_STRUCT_INIT([],[AC_MSG_ERROR([c99 structure initializer are not supported])])
+
+UNAME_S=`(uname -s) 2>/dev/null` || UNAME_S="unknown"
+AC_MSG_CHECKING(uname -s)
+AC_MSG_RESULT(${UNAME_S})
+
+UNAME_R=`(uname -r) 2>/dev/null` || UNAME_R="unknown"
+AC_MSG_CHECKING(uname -r)
+AC_MSG_RESULT(${UNAME_R})
+
+UNAME_M=`(uname -m) 2>/dev/null` || UNAME_M="unknown"
+AC_MSG_CHECKING(uname -m)
+AC_MSG_RESULT(${UNAME_M})
+
+UNAME_P=`(uname -p) 2>/dev/null` || UNAME_P="unknown"
+AC_MSG_CHECKING(uname -p)
+AC_MSG_RESULT(${UNAME_P})
+
+UNAME_I=`(uname -i) 2>/dev/null` || UNAME_I="unknown"
+AC_MSG_CHECKING(uname -i)
+AC_MSG_RESULT(${UNAME_I})
+
+dnl Add #include for broken IRIX header files
+ case "$host_os" in
+ *irix6*)
+ #TODO add to libreplace
+ if test x"$ac_cv_prog_gcc" != x"yes" ; then
+ dnl Fix sensible defaults for MIPSPro compilers. The
+ dnl error numbers are valid for the 7.3 compilers,
+ dnl hopefully also valid for the 7.4 series.
+ dnl
+ dnl Bugzilla 3801. Force an error on warning 1035
+ dnl so we don't incorrectly detect stdint.h. This
+ dnl warning is emitted for #error directives.
+ CFLAGS="$CFLAGS -diag_error 1035"
+ dnl 1209: Controlling expression is constant
+ dnl 1174: Function foo declared but never referenced
+ dnl 3201: Parameter foo was never referenced
+ CFLAGS="$CFLAGS -woff 1209,1174,3201"
+ fi
+ ;;
+esac
+
+DYNEXP=
+AC_SUBST(DYNEXP)
+
+dnl Add modules that have to be built by default here
+dnl These have to be built static:
+default_static_modules="pdb_smbpasswd pdb_tdbsam rpc_lsarpc rpc_samr rpc_winreg rpc_initshutdown rpc_dssetup rpc_wkssvc rpc_svcctl2 rpc_ntsvcs2 rpc_netlogon rpc_netdfs rpc_srvsvc rpc_spoolss rpc_eventlog2 auth_sam auth_unix auth_winbind auth_server auth_domain auth_builtin vfs_default nss_info_template"
+
+dnl These are preferably build shared, and static if dlopen() is not available
+default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2 charset_CP850 charset_CP437 auth_script vfs_readahead vfs_xattr_tdb vfs_streams_xattr"
+
+if test "x$developer" = xyes; then
+ default_static_modules="$default_static_modules rpc_rpcecho"
+ default_shared_modules="$default_shared_modules charset_weird"
+fi
+
+#
+# Config CPPFLAG settings for strange OS's that must be set
+# before other tests. Do NOT invoke AC_CHECK_HEADERS within this
+# case statement; its first reference must be unconditional.
+#
+case "$host_os" in
+ *hpux*)
+#
+# Defines needed for HPUX support.
+# HPUX has bigcrypt but (sometimes?) doesn't use it for
+# password hashing - hence the USE_BOTH_CRYPT_CALLS define.
+#
+ case `uname -r` in
+ *9*|*10*|*11)
+ AC_DEFINE(USE_BOTH_CRYPT_CALLS, 1, [Whether to use both of HPUX' crypt calls])
+ ;;
+ esac
+ ;;
+
+#
+# CRAY Unicos has broken const handling
+ *unicos*)
+ AC_MSG_RESULT([disabling const])
+ CPPFLAGS="$CPPFLAGS -Dconst="
+ ;;
+
+#
+# AIX4.x doesn't even admit to having large
+# files *at all* unless the -D_LARGE_FILE or -D_LARGE_FILE_API flags are set.
+#
+ *aix4*)
+ AC_MSG_RESULT([enabling large file support])
+ CPPFLAGS="$CPPFLAGS -D_LARGE_FILES"
+ AC_DEFINE(_LARGE_FILES, 1, [Whether to enable large file support])
+ ;;
+#
+# Defines needed for Solaris 2.6/2.7 aka 7.0 to make it admit
+# to the existance of large files..
+# Note that -D_LARGEFILE64_SOURCE is different from the Sun
+# recommendations on large file support, however it makes the
+# compile work using gcc 2.7 and 2.8, whereas using the Sun
+# recommendation makes the compile fail on gcc2.7. JRA.
+#
+# Solaris uses SYSV printing. Make sure to set that here. --jerry
+#
+ *solaris*)
+ AC_DEFINE(SYSV, 1, [Whether to enable System V compatibility])
+ case `uname -r` in
+ 5.0|5.0.*|5.1|5.1.*|5.2|5.2.*|5.3|5.3.*|5.5|5.5.*)
+ AC_MSG_RESULT([no large file support])
+ ;;
+ 5.*)
+ AC_MSG_RESULT([enabling large file support])
+ if test "$ac_cv_prog_gcc" = yes; then
+ ${CC-cc} -v >conftest.c 2>&1
+ ac_cv_gcc_compiler_version_number=`grep 'gcc version' conftest.c`
+ rm -fr conftest.c
+ case "$ac_cv_gcc_compiler_version_number" in
+ *"gcc version 2.6"*|*"gcc version 2.7"*)
+ CPPFLAGS="$CPPFLAGS -D_LARGEFILE64_SOURCE -D_REENTRANT"
+ LDFLAGS="$LDFLAGS -lthread"
+ AC_DEFINE(_LARGEFILE64_SOURCE, 1, [Whether to enable large file support])
+ ;;
+ *)
+ CPPFLAGS="$CPPFLAGS -D_LARGEFILE_SOURCE -D_REENTRANT -D_FILE_OFFSET_BITS=64"
+ LDFLAGS="$LDFLAGS -lthread"
+ AC_DEFINE(_LARGEFILE64_SOURCE, 1, [Whether to enable large file support])
+ AC_DEFINE(_FILE_OFFSET_BITS, 64, [File offset bits])
+ ;;
+ esac
+ else
+ CPPFLAGS="$CPPFLAGS -D_LARGEFILE_SOURCE -D_REENTRANT -D_FILE_OFFSET_BITS=64"
+ LDFLAGS="$LDFLAGS -lthread"
+ AC_DEFINE(_LARGEFILE64_SOURCE, 1, [Whether to enable large file support])
+ AC_DEFINE(_FILE_OFFSET_BITS, 64, [File offset bits])
+ fi
+ ;;
+ esac
+ ;;
+#
+# IRIX uses SYSV printing. Make sure to set that here
+#
+ *irix*)
+ AC_DEFINE(SYSV, 1, [Whether to enable System V compatibility])
+ ;;
+ *freebsd*|*dragonfly*)
+ AC_DEFINE(FREEBSD, 1, [Whether the host os is FreeBSD])
+ ;;
+#
+# VOS may need to have POSIX support and System V compatibility enabled.
+#
+ *vos*)
+ case "$CPPFLAGS" in
+ *-D_POSIX_C_SOURCE*)
+ ;;
+ *)
+ CPPFLAGS="$CPPFLAGS -D_POSIX_C_SOURCE=200112L"
+ AC_DEFINE(_POSIX_C_SOURCE, 200112L, [Whether to enable POSIX support])
+ ;;
+ esac
+ case "$CPPFLAGS" in
+ *-D_SYSV*|*-D_SVID_SOURCE*)
+ ;;
+ *)
+ CPPFLAGS="$CPPFLAGS -D_SYSV"
+ AC_DEFINE(_SYSV, 1, [Whether to enable System V compatibility])
+ esac
+ ;;
+#
+# Tests needed for SINIX large file support.
+#
+ *sysv4*)
+ if test $host = mips-sni-sysv4 ; then
+ AC_MSG_CHECKING([for LFS support])
+ old_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="-D_LARGEFILE64_SOURCE $CPPFLAGS"
+ AC_TRY_RUN([
+#include <unistd.h>
+main () {
+#if _LFS64_LARGEFILE == 1
+exit(0);
+#else
+exit(1);
+#endif
+}], [SINIX_LFS_SUPPORT=yes], [SINIX_LFS_SUPPORT=no], [SINIX_LFS_SUPPORT=cross])
+ CPPFLAGS="$old_CPPFLAGS"
+ if test x$SINIX_LFS_SUPPORT = xyes ; then
+ CPPFLAGS="-D_LARGEFILE64_SOURCE $CPPFLAGS"
+ AC_DEFINE(_LARGEFILE64_SOURCE, 1, [Whether to enable large file support])
+ CFLAGS="`getconf LFS64_CFLAGS` $CFLAGS"
+ LDFLAGS="`getconf LFS64_LDFLAGS` $LDFLAGS"
+ LIBS="`getconf LFS64_LIBS` $LIBS"
+ fi
+ AC_MSG_RESULT([$SINIX_LFS_SUPPORT])
+ fi
+ ;;
+
+# Tests for linux LFS support. Need kernel 2.4 and glibc2.2 or greater support.
+#
+ *linux*)
+ AC_MSG_CHECKING([for LFS support])
+ old_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE $CPPFLAGS"
+ AC_TRY_RUN([
+#include <unistd.h>
+#include <sys/utsname.h>
+#include <string.h>
+#include <stdlib.h>
+main() {
+#if _LFS64_LARGEFILE == 1
+ struct utsname uts;
+ char *release;
+ int major, minor;
+
+ /* Ensure this is glibc 2.2 or higher */
+#if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
+ int libc_major = __GLIBC__;
+ int libc_minor = __GLIBC_MINOR__;
+
+ if (libc_major < 2)
+ exit(1);
+ if (libc_minor < 2)
+ exit(1);
+#endif
+
+ /* Ensure this is kernel 2.4 or higher */
+
+ uname(&uts);
+ release = strdup(uts.release);
+ major = atoi(strsep(&release, "."));
+ minor = atoi(strsep(&release, "."));
+
+ if (major > 2 || (major == 2 && minor > 3))
+ exit(0);
+ exit(1);
+#else
+ exit(1);
+#endif
+}
+], [LINUX_LFS_SUPPORT=yes], [LINUX_LFS_SUPPORT=no], [LINUX_LFS_SUPPORT=cross])
+ CPPFLAGS="$old_CPPFLAGS"
+ if test x$LINUX_LFS_SUPPORT = xyes ; then
+ CPPFLAGS="-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE $CPPFLAGS"
+ AC_DEFINE(_LARGEFILE64_SOURCE, 1, [Whether to enable large file support])
+ AC_DEFINE(_FILE_OFFSET_BITS, 64, [File offset bits])
+ AC_DEFINE(_GNU_SOURCE, 1, [Whether to use GNU libc extensions])
+ fi
+ AC_MSG_RESULT([$LINUX_LFS_SUPPORT])
+ ;;
+
+#
+# MacOS X is the *only* system that uses compose character in utf8. This
+# is so horribly broken....
+#
+ *darwin*)
+ AC_DEFINE(BROKEN_UNICODE_COMPOSE_CHARACTERS, 1, [Does this system use unicode compose characters])
+
+# Add a system specific charset module.
+ default_shared_modules="$default_shared_modules charset_macosxfs"
+
+ ;;
+ *hurd*)
+ AC_MSG_CHECKING([for LFS support])
+ old_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="-D_LARGEFILE64_SOURCE -D_GNU_SOURCE $CPPFLAGS"
+ AC_TRY_RUN([
+#include <unistd.h>
+main () {
+#if _LFS64_LARGEFILE == 1
+exit(0);
+#else
+exit(1);
+#endif
+}], [GLIBC_LFS_SUPPORT=yes], [GLIBC_LFS_SUPPORT=no], [GLIBC_LFS_SUPPORT=cross])
+ CPPFLAGS="$old_CPPFLAGS"
+ if test x$GLIBC_LFS_SUPPORT = xyes ; then
+ CPPFLAGS="-D_LARGEFILE64_SOURCE -D_GNU_SOURCE $CPPFLAGS"
+ AC_DEFINE(_LARGEFILE64_SOURCE, 1, [Whether to enable large file support])
+ AC_DEFINE(_GNU_SOURCE, 1, [Whether to use GNU libc extensions])
+ fi
+ AC_MSG_RESULT([$GLIBC_LFS_SUPPORT])
+ ;;
+
+esac
+
+SAVE_CPPFLAGS="${CPPFLAGS}"
+CPPFLAGS="${CPPFLAGS} ${SAMBA_CONFIGURE_CPPFLAGS}"
+
+AC_LIBREPLACE_BROKEN_CHECKS
+AC_LIBREPLACE_NETWORK_CHECKS
+
+CPPFLAGS="${SAVE_CPPFLAGS}"
+
+LIBREPLACE_DIR=`echo ${libreplacedir} | sed -e "s;${srcdir};;" -e "s;^/;;"`
+
+LIBREPLACE_OBJS=""
+for obj in ${LIBREPLACEOBJ}; do
+ LIBREPLACE_OBJS="${LIBREPLACE_OBJS} ${LIBREPLACE_DIR}/${obj}"
+done
+AC_SUBST(LIBREPLACE_OBJS)
+
+# add -ldl to the global LIBS
+LIBS="${LIBS} ${LIBDL} ${LIBREPLACE_NETWORK_LIBS}"
+
+AC_CHECK_HEADERS(aio.h sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h rpc/nettype.h)
+AC_CHECK_HEADERS(unistd.h utime.h grp.h sys/id.h memory.h alloca.h)
+AC_CHECK_HEADERS(limits.h float.h pthread.h)
+AC_CHECK_HEADERS(rpc/rpc.h rpcsvc/nis.h rpcsvc/ypclnt.h)
+AC_CHECK_HEADERS(sys/param.h ctype.h sys/wait.h sys/resource.h sys/ioctl.h sys/ipc.h sys/prctl.h)
+AC_CHECK_HEADERS(sys/mman.h sys/filio.h sys/priv.h sys/shm.h string.h strings.h stdlib.h)
+AC_CHECK_HEADERS(sys/mount.h sys/vfs.h sys/fs/s5param.h sys/filsys.h termios.h termio.h)
+AC_CHECK_HEADERS(sys/termio.h sys/statfs.h sys/dustat.h sys/statvfs.h stdarg.h)
+AC_CHECK_HEADERS(sys/sysmacros.h)
+AC_CHECK_HEADERS(sys/syslog.h syslog.h)
+AC_CHECK_HEADERS(langinfo.h locale.h)
+AC_CHECK_HEADERS(xfs/libxfs.h)
+AC_CHECK_HEADERS(netgroup.h)
+
+AC_CHECK_HEADERS(rpcsvc/yp_prot.h,,,[[
+#if HAVE_RPC_RPC_H
+#include <rpc/rpc.h>
+#endif
+]])
+
+## These fail to compile on IRIX so just check for their presence
+AC_CHECK_HEADERS(sys/mode.h,,,)
+
+# Look for Darwin headers
+old_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="-Iinclude $CPPFLAGS"
+AC_CHECK_HEADERS([CoreFoundation/CFStringEncodingConverter.h], [], [AC_CHECK_HEADERS([CFStringEncodingConverter.h])])
+CPPFLAGS="$old_CPPFLAGS"
+
+# In valgrind 1.0.x, it's just valgrind.h. In 1.9.x+ there's a
+# subdirectory of headers.
+AC_CHECK_HEADERS(valgrind.h valgrind/valgrind.h valgrind/memcheck.h)
+
+# check for linux on amd64 since valgrind is not quite there yet
+case "$host_os" in
+ *linux*)
+ case "$UNAME_P" in
+ *x86_64*)
+ AC_DEFINE(HAVE_64BIT_LINUX,1,[Whether we are running on 64bit linux])
+ ;;
+ esac
+ ;;
+esac
+
+
+#
+# HPUX has a bug in that including shadow.h causes a re-definition of MAXINT.
+# This causes configure to fail to detect it. Check for shadow separately on HPUX.
+#
+case "$host_os" in
+ *hpux*)
+ AC_TRY_COMPILE([#include <shadow.h>],[struct spwd testme],
+ ac_cv_header_shadow_h=yes,ac_cv_header_shadow_h=no)
+ if test x"$ac_cv_header_shadow_h" = x"yes"; then
+ AC_DEFINE(HAVE_SHADOW_H,1,[Whether we have shadow.h])
+ fi
+ ;;
+esac
+AC_CHECK_HEADERS(shadow.h)
+AC_CHECK_HEADERS(nss.h nss_common.h nsswitch.h ns_api.h sys/security.h)
+AC_CHECK_HEADERS(syscall.h sys/syscall.h)
+
+AC_CHECK_HEADERS(sys/attributes.h attr/xattr.h sys/xattr.h sys/extattr.h sys/uio.h)
+AC_CHECK_HEADERS(sys/ea.h sys/proplist.h)
+
+AC_CHECK_HEADERS(sys/cdefs.h glob.h)
+
+# For experimental utmp support (lastlog on some BSD-like systems)
+AC_CHECK_HEADERS(utmp.h utmpx.h lastlog.h)
+
+AC_CHECK_SIZEOF(int,cross)
+AC_CHECK_SIZEOF(long,cross)
+AC_CHECK_SIZEOF(long long,cross)
+AC_CHECK_SIZEOF(short,cross)
+
+AC_C_CONST
+AC_C_INLINE
+AC_C_BIGENDIAN
+AC_C_CHAR_UNSIGNED
+
+AC_TYPE_SIGNAL
+AC_TYPE_UID_T
+AC_TYPE_MODE_T
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_TYPE_PID_T
+AC_STRUCT_ST_RDEV
+AC_DIRENT_D_OFF
+AC_CHECK_TYPE(ssize_t, int)
+AC_CHECK_TYPE(wchar_t, unsigned short)
+
+############################################
+# for cups support we need libcups, and a handful of header files
+
+AC_ARG_ENABLE(cups,
+[AS_HELP_STRING([--enable-cups], [Turn on CUPS support (default=auto)])])
+
+if test x$enable_cups != xno; then
+ AC_PATH_PROG(CUPS_CONFIG, cups-config)
+
+ if test "x$CUPS_CONFIG" != x; then
+
+ ac_save_CFLAGS=$CFLAGS
+ ac_save_LDFLAGS=$LDFLAGS
+ ac_save_PRINT_LIBS=$PRINT_LIBS
+ CFLAGS="$CFLAGS `$CUPS_CONFIG --cflags`"
+ LDFLAGS="$LDFLAGS `$CUPS_CONFIG --ldflags`"
+ PRINT_LIBS="$PRINT_LIBS `$CUPS_CONFIG --libs`"
+ AC_CHECK_HEADERS(cups/cups.h cups/language.h)
+ if test x"$ac_cv_header_cups_cups_h" = xyes -a \
+ x"$ac_cv_header_cups_language_h" = xyes; then
+ AC_DEFINE(HAVE_CUPS,1,[Whether we have CUPS])
+ samba_cv_HAVE_CUPS=yes
+ else
+ AC_MSG_WARN([cups-config around but cups-devel not installed])
+ CFLAGS=$ac_save_CFLAGS
+ LDFLAGS=$ac_save_LDFLAGS
+ PRINT_LIBS=$ac_save_PRINT_LIBS
+ fi
+
+ elif test x"$enable_cups" = x"yes"; then
+ AC_MSG_ERROR(Cups support required but cups-config not located. Make sure cups-devel related files are installed.)
+ fi
+fi
+
+AC_ARG_ENABLE(iprint,
+[AS_HELP_STRING([--enable-iprint], [Turn on iPrint support (default=yes if cups is yes)])])
+
+if test x$enable_iprint != xno; then
+ if test x"$samba_cv_HAVE_CUPS" = xyes; then
+ AC_DEFINE(HAVE_IPRINT,1,[Whether we have iPrint])
+ elif test x"$enable_iprint" = x"yes"; then
+ AC_MSG_ERROR(iPrint support required but cups not enabled. Make sure cups-devel related files are installed and that cups is enabled.)
+ fi
+fi
+
+############################################
+# check if the compiler will optimize out function calls
+AC_CACHE_CHECK([if the compiler will optimize out function calls],samba_cv_optimize_out_funcation_calls, [
+ AC_TRY_LINK([
+#include <stdio.h>],
+[
+ if (0) {
+ this_function_does_not_exist();
+ } else {
+ return 1;
+ }
+
+],
+ samba_cv_optimize_out_funcation_calls=yes,samba_cv_optimize_out_funcation_calls=no)])
+if test x"$samba_cv_optimize_out_funcation_calls" = x"yes"; then
+ AC_DEFINE(HAVE_COMPILER_WILL_OPTIMIZE_OUT_FNS,1,[Whether the compiler will optimize out function calls])
+fi
+
+#############################################
+# check for fd passing struct via msg_control
+AC_CACHE_CHECK([for fd passing via msg_control],samba_cv_msghdr_msg_control, [
+ AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/un.h>],
+[
+ struct msghdr msg;
+ union {
+ struct cmsghdr cm;
+ char control[CMSG_SPACE(sizeof(int))];
+ } control_un;
+ msg.msg_control = control_un.control;
+ msg.msg_controllen = sizeof(control_un.control);
+],
+ samba_cv_msghdr_msg_control=yes,samba_cv_msghdr_msg_control=no)])
+if test x"$samba_cv_msghdr_msg_control" = x"yes"; then
+ AC_DEFINE(HAVE_MSGHDR_MSG_CONTROL,1,
+ [If we can use msg_control for passing file descriptors])
+fi
+
+#############################################
+# check for fd passing struct via msg_acctrights
+AC_CACHE_CHECK([for fd passing via msg_acctrights],
+ samba_cv_msghdr_msg_acctrights, [
+ AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/un.h>],
+[
+ struct msghdr msg;
+ int fd;
+ msg.msg_acctrights = (caddr_t) &fd;
+ msg.msg_acctrightslen = sizeof(fd);
+],
+ samba_cv_msghdr_msg_acctrights=yes,samba_cv_msghdr_msg_acctrights=no)])
+if test x"$samba_cv_msghdr_msg_acctrights" = x"yes"; then
+ AC_DEFINE(HAVE_MSGHDR_MSG_ACCTRIGHTS,1,
+ [If we can use msg_acctrights for passing file descriptors])
+fi
+
+AC_CHECK_FUNCS(dirfd)
+if test x"$ac_cv_func_dirfd" = x"yes"; then
+ default_shared_modules="$default_shared_modules vfs_syncops"
+fi
+
+AC_CACHE_CHECK([for sig_atomic_t type],samba_cv_sig_atomic_t, [
+ AC_TRY_COMPILE([
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#include <signal.h>],[sig_atomic_t i = 0],
+ samba_cv_sig_atomic_t=yes,samba_cv_sig_atomic_t=no)])
+if test x"$samba_cv_sig_atomic_t" = x"yes"; then
+ AC_DEFINE(HAVE_SIG_ATOMIC_T_TYPE,1,[Whether we have the atomic_t variable type])
+fi
+
+AC_CACHE_CHECK([for struct timespec type],samba_cv_struct_timespec, [
+ AC_TRY_COMPILE([
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+],[struct timespec ts;],
+ samba_cv_struct_timespec=yes,samba_cv_struct_timespec=no)])
+if test x"$samba_cv_struct_timespec" = x"yes"; then
+ AC_DEFINE(HAVE_STRUCT_TIMESPEC,1,[Whether we have struct timespec])
+fi
+
+# stupid headers have the functions but no declaration. grrrr.
+AC_HAVE_DECL(errno, [#include <errno.h>])
+AC_HAVE_DECL(setresuid, [#include <unistd.h>])
+AC_HAVE_DECL(setresgid, [#include <unistd.h>])
+
+# 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,1,[Whether the system has setresuid])
+fi
+
+# Do the same check for setresguid...
+#
+AC_CACHE_CHECK([for real setresgid],samba_cv_have_setresgid,[
+ AC_TRY_RUN([#include <unistd.h>
+#include <errno.h>
+main() { errno = 0; setresgid(1,1,1); exit(errno != 0 ? (errno==EPERM ? 0 : 1) : 0);}],
+ samba_cv_have_setresgid=yes,samba_cv_have_setresgid=no,samba_cv_have_setresgid=cross)])
+if test x"$samba_cv_have_setresgid" = x"yes"; then
+ AC_DEFINE(HAVE_SETRESGID,1,[Whether the system has setresgid])
+fi
+
+AC_FUNC_MEMCMP
+
+###############################################
+# Readline included by default unless explicitly asked not to
+test "${with_readline+set}" != "set" && with_readline=yes
+
+# test for where we get readline() from
+AC_MSG_CHECKING(whether to use readline)
+AC_ARG_WITH(readline,
+[AS_HELP_STRING([--with-readline[=DIR]], [Look for readline include/libs in DIR (default=auto)])],
+[ case "$with_readline" in
+ yes)
+ AC_MSG_RESULT(yes)
+
+ AC_CHECK_HEADERS(readline.h history.h readline/readline.h)
+ AC_CHECK_HEADERS(readline/history.h)
+
+ AC_CHECK_HEADERS(readline.h readline/readline.h,[
+ for termlib in ncurses curses termcap terminfo termlib tinfo; do
+ AC_CHECK_LIB(${termlib}, tgetent, [TERMLIBS="-l${termlib}"; break])
+ done
+ AC_CHECK_LIB(readline, rl_callback_handler_install,
+ [TERMLIBS="-lreadline $TERMLIBS"
+ AC_DEFINE(HAVE_LIBREADLINE,1,[Whether the system has readline])
+ break], [TERMLIBS=], $TERMLIBS)])
+ ;;
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+
+ # Needed for AC_CHECK_HEADERS and AC_CHECK_LIB to look at
+ # alternate readline path
+ _ldflags=${LDFLAGS}
+ _cppflags=${CPPFLAGS}
+
+ # Add additional search path
+ LDFLAGS="-L$with_readline/lib $LDFLAGS"
+ CPPFLAGS="-I$with_readline/include $CPPFLAGS"
+
+ AC_CHECK_HEADERS(readline.h history.h readline/readline.h)
+ AC_CHECK_HEADERS(readline/history.h)
+
+ AC_CHECK_HEADERS(readline.h readline/readline.h,[
+ for termlib in ncurses curses termcap terminfo termlib; do
+ AC_CHECK_LIB(${termlib}, tgetent, [TERMLIBS="-l${termlib}"; break])
+ done
+ AC_CHECK_LIB(readline, rl_callback_handler_install,
+ [TERMLDFLAGS="-L$with_readline/lib"
+ TERMCPPFLAGS="-I$with_readline/include"
+ CPPFLAGS="-I$with_readline/include $CPPFLAGS"
+ TERMLIBS="-lreadline $TERMLIBS"
+ AC_DEFINE(HAVE_LIBREADLINE,1,[Whether the system has readline])
+ break], [TERMLIBS= CPPFLAGS=$_cppflags], $TERMLIBS)])
+
+ LDFLAGS=$_ldflags
+ ;;
+ esac],
+ AC_MSG_RESULT(no)
+)
+AC_SUBST(TERMLIBS)
+AC_SUBST(TERMLDFLAGS)
+
+# The readline API changed slightly from readline3 to readline4, so
+# code will generate warnings on one of them unless we have a few
+# special cases.
+AC_CHECK_LIB(readline, rl_completion_matches,
+ [AC_DEFINE(HAVE_NEW_LIBREADLINE, 1,
+ [Do we have rl_completion_matches?])],
+ [],
+ [$TERMLIBS])
+
+# not all readline libs have rl_event_hook or history_list
+AC_CHECK_DECLS(rl_event_hook, [], [], [#include <readline/readline.h>])
+AC_CHECK_LIB(readline, history_list,
+ [AC_DEFINE(HAVE_HISTORY_LIST, 1, [Do we have history_list?])],
+ [],
+ [$TERMLIBS])
+
+###############################################
+# test for where we get yp_get_default_domain() from
+AC_SEARCH_LIBS(yp_get_default_domain, [nsl])
+AC_CHECK_FUNCS(yp_get_default_domain)
+
+# Check if we have execl, if not we need to compile smbrun.
+AC_CHECK_FUNCS(execl)
+if test x"$ac_cv_func_execl" = x"no"; then
+ EXTRA_BIN_PROGS="$EXTRA_BIN_PROGS bin/smbrun\$(EXEEXT)"
+fi
+
+AC_CHECK_FUNCS(waitpid getcwd strdup strndup strnlen strerror chown fchown lchown chmod fchmod chroot link mknod mknod64)
+AC_CHECK_FUNCS(strtol strtoll strtoul strtoull strtouq __strtoull)
+AC_CHECK_FUNCS(fstat strchr utime utimes chflags)
+AC_CHECK_FUNCS(getrlimit fsync fdatasync memset strlcpy strlcat setpgid)
+AC_CHECK_FUNCS(memmove setsid glob strpbrk pipe crypt16 getauthuid)
+AC_CHECK_FUNCS(strftime sigprocmask sigblock sigaction sigset innetgr setnetgrent getnetgrent endnetgrent)
+AC_CHECK_FUNCS(initgroups select poll rdchk getgrnam getgrent pathconf realpath)
+AC_CHECK_FUNCS(setpriv setgidx setuidx setgroups sysconf mktime rename ftruncate chsize stat64 fstat64)
+AC_CHECK_FUNCS(lstat64 fopen64 atexit grantpt dup2 lseek64 ftruncate64)
+AC_CHECK_FUNCS(fseek64 fseeko64 ftell64 ftello64 setluid getpwanam setlinebuf)
+AC_CHECK_FUNCS(opendir64 readdir64 seekdir64 telldir64 rewinddir64 closedir64)
+AC_CHECK_FUNCS(getpwent_r)
+AC_CHECK_FUNCS(getdents getdents64)
+AC_CHECK_FUNCS(srandom random srand rand setenv usleep strcasecmp fcvt fcvtl symlink readlink)
+AC_CHECK_FUNCS(syslog vsyslog timegm)
+AC_CHECK_FUNCS(setlocale nl_langinfo)
+AC_CHECK_FUNCS(nanosleep)
+AC_CHECK_FUNCS(mlock munlock mlockall munlockall)
+AC_CHECK_FUNCS(memalign posix_memalign hstrerror)
+AC_CHECK_HEADERS(sys/mman.h)
+# setbuffer, shmget, shm_open are needed for smbtorture
+AC_CHECK_FUNCS(setbuffer shmget shm_open)
+
+# Find a method of generating a stack trace
+AC_CHECK_HEADERS(execinfo.h libexc.h libunwind.h)
+AC_CHECK_FUNCS(backtrace_symbols)
+AC_CHECK_LIB(exc, trace_back_stack)
+
+printf "%s" "checking for GPFS GPL libs... "
+save_LIBS="$LIBS"
+LIBS="$LIBS -lgpfs_gpl"
+AC_TRY_LINK([#include <gpfs_gpl.h>],
+ [gpfs_set_share(0,GPFS_SHARE_READ,GPFS_DENY_NONE)],
+ samba_cv_HAVE_GPFS=yes,
+ samba_cv_HAVE_GPFS=no)
+echo $samba_cv_HAVE_GPFS
+if test x"$samba_cv_HAVE_GPFS" = x"yes"; then
+ AC_DEFINE(HAVE_GPFS,1,[Whether GPFS GPL libs are available])
+ default_shared_modules="$default_shared_modules vfs_gpfs"
+fi
+LIBS="$save_LIBS"
+
+# Note that all the libunwind symbols in the API are defined to internal
+# platform-specific version, so we must include libunwind.h before checking
+# any of them.
+AC_MSG_CHECKING([for libunwind])
+save_LIBS=$LIBS
+
+UNWIND_ARCH="unknown"
+if test x"$UNAME_I" != x"unknown"; then
+ UNWIND_ARCH="$UNAME_I"
+elif test x"$UNAME_M" != x"unknown"; then
+ UNWIND_ARCH="$UNAME_M"
+elif test x"$UNAME_P" != x"unknown"; then
+ UNWIND_ARCH="$UNAME_P"
+fi
+
+case "$UNWIND_ARCH" in
+ unknown)
+ # This probably won't link without
+ # the platform-specific libunwind.
+ LIBS="$LIBS -lunwind"
+ ;;
+ i386|i586|i686)
+ # Add the platform-specific libunwind module.
+ LIBS="$LIBS -lunwind -lunwind-x86"
+ ;;
+ *)
+ # Add the platform-specific libunwind module.
+ # based on uname -i, uname -m or uname -p
+ LIBS="$LIBS -lunwind -lunwind-$UNWIND_ARCH"
+ ;;
+esac
+
+AC_TRY_LINK(
+ [
+#ifdef HAVE_LIBUNWIND_H
+#include <libunwind.h>
+#endif
+ ],
+ [
+ unw_context_t ctx; unw_cursor_t cur;
+ char buf[256]; unw_word_t off;
+ unw_getcontext(&ctx); unw_init_local(&cur, &ctx);
+ unw_get_proc_name(&cur, buf, sizeof(buf), &off);
+ ],
+ [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_LIBUNWIND, 1, [Whether libunwind is available])
+
+ # If we have libunwind, test whether we also have libunwind-ptrace
+ # which would let us unwind arbitrary processes.
+ save_LIBS=$LIBS
+ AC_CHECK_HEADERS(libunwind-ptrace.h)
+ AC_CHECK_LIB(unwind-ptrace, _UPT_create,
+ [
+ LIBUNWIND_PTRACE="-lunwind-ptrace";
+ AC_DEFINE(HAVE_LIBUNWIND_PTRACE, 1,
+ [Whether libunwind-ptrace.a is available.])
+ ],
+ [ LIBUNWIND_PTRACE="" ])
+
+ LIBS=$save_LIBS
+ ],
+ [
+ AC_MSG_RESULT(no)
+ LIBS=$save_LIBS
+ ])
+
+# To use libunwind-ptrace, we also need to make some ptrace system calls.
+if test x"$LIBUNWIND_PTRACE" != x"" ; then
+ AC_CHECK_HEADERS(sys/ptrace.h)
+ AC_MSG_CHECKING([for the Linux ptrace(2) interface])
+ AC_TRY_LINK(
+ [
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_PTRACE_H
+#include <sys/ptrace.h>
+#endif
+ ],
+ [
+ int main(int argc, const char ** argv)
+ {
+ pid_t me = (pid_t)-1;
+ ptrace(PTRACE_ATTACH, me, 0, 0);
+ ptrace(PTRACE_DETACH, me, 0, 0);
+ return 0;
+ }
+ ],
+ [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_LINUX_PTRACE, 1,
+ [Whether the Linux ptrace(2) interface is available.])
+ ],
+ [
+ AC_MSG_RESULT(no)
+ LIBUNWIND_PTRACE=""
+ ])
+fi
+
+AC_SUBST(LIBUNWIND_PTRACE)
+
+AC_CHECK_FUNCS(_dup _dup2 _opendir _readdir _seekdir _telldir _closedir)
+AC_CHECK_FUNCS(__dup __dup2 __opendir __readdir __seekdir __telldir __closedir)
+AC_CHECK_FUNCS(__getcwd _getcwd)
+AC_CHECK_FUNCS(__xstat __fxstat __lxstat)
+AC_CHECK_FUNCS(_stat _lstat _fstat __stat __lstat __fstat)
+AC_CHECK_FUNCS(_acl __acl _facl __facl _open __open _chdir __chdir)
+AC_CHECK_FUNCS(_close __close _fchdir __fchdir _fcntl __fcntl)
+AC_CHECK_FUNCS(getdents __getdents _lseek __lseek _read __read)
+AC_CHECK_FUNCS(getdirentries _write __write _fork __fork)
+AC_CHECK_FUNCS(_stat64 __stat64 _fstat64 __fstat64 _lstat64 __lstat64)
+AC_CHECK_FUNCS(__sys_llseek llseek _llseek __llseek readdir64 _readdir64 __readdir64)
+AC_CHECK_FUNCS(pread _pread __pread pread64 _pread64 __pread64)
+AC_CHECK_FUNCS(pwrite _pwrite __pwrite pwrite64 _pwrite64 __pwrite64)
+AC_CHECK_FUNCS(open64 _open64 __open64 creat64)
+AC_CHECK_FUNCS(prctl)
+
+AC_TRY_COMPILE([
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
+],
+[int i; i = prtcl(0); ],
+AC_DEFINE(HAVE_PRCTL, 1, [Whether prctl is available]),[])
+
+#
+#
+#
+case "$host_os" in
+ *linux*)
+ # glibc <= 2.3.2 has a broken getgrouplist
+ AC_TRY_RUN([
+#include <unistd.h>
+#include <sys/utsname.h>
+main() {
+ /* glibc up to 2.3 has a broken getgrouplist */
+#if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
+ int libc_major = __GLIBC__;
+ int libc_minor = __GLIBC_MINOR__;
+
+ if (libc_major < 2)
+ exit(1);
+ if ((libc_major == 2) && (libc_minor <= 3))
+ exit(1);
+#endif
+ exit(0);
+}
+], [linux_getgrouplist_ok=yes], [linux_getgrouplist_ok=no])
+ if test x"$linux_getgrouplist_ok" = x"yes"; then
+ AC_DEFINE(HAVE_GETGROUPLIST, 1, [Have good getgrouplist])
+ fi
+ ;;
+ *)
+ AC_CHECK_FUNCS(getgrouplist)
+ ;;
+esac
+
+#
+# stat64 family may need <sys/stat.h> on some systems, notably ReliantUNIX
+#
+
+if test x$ac_cv_func_stat64 = xno ; then
+ AC_MSG_CHECKING([for stat64 in <sys/stat.h>])
+ AC_TRY_LINK([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+], [struct stat64 st64; exit(stat64(".",&st64));], [ac_cv_func_stat64=yes])
+ AC_MSG_RESULT([$ac_cv_func_stat64])
+ if test x$ac_cv_func_stat64 = xyes ; then
+ AC_DEFINE(HAVE_STAT64,1,[Whether stat64() is available])
+ fi
+fi
+
+if test x$ac_cv_func_lstat64 = xno ; then
+ AC_MSG_CHECKING([for lstat64 in <sys/stat.h>])
+ AC_TRY_LINK([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+], [struct stat64 st64; exit(lstat64(".",&st64));], [ac_cv_func_lstat64=yes])
+ AC_MSG_RESULT([$ac_cv_func_lstat64])
+ if test x$ac_cv_func_lstat64 = xyes ; then
+ AC_DEFINE(HAVE_LSTAT64,[Whether lstat64() is available])
+ fi
+fi
+
+if test x$ac_cv_func_fstat64 = xno ; then
+ AC_MSG_CHECKING([for fstat64 in <sys/stat.h>])
+ AC_TRY_LINK([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+], [struct stat64 st64; exit(fstat64(0,&st64));], [ac_cv_func_fstat64=yes])
+ AC_MSG_RESULT([$ac_cv_func_fstat64])
+ if test x$ac_cv_func_fstat64 = xyes ; then
+ AC_DEFINE(HAVE_FSTAT64,1,[Whether fstat64() is available])
+ fi
+fi
+
+#################################################
+# Check whether struct stat has timestamps with sub-second resolution.
+# At least IRIX and Solaris have these.
+#
+# We check that
+# all of st_mtim, st_atim and st_ctim exist
+# all of the members are in fact of type struct timespec
+#
+# There is some conflicting standards weirdness about whether we should use
+# "struct timespec" or "timespec_t". Linux doesn't have timespec_t, so we
+# prefer struct timespec.
+
+AC_CACHE_CHECK([whether struct stat has sub-second timestamps], samba_cv_stat_hires,
+ [
+ AC_TRY_COMPILE(
+ [
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+ ],
+ [
+ struct timespec t;
+ struct stat s = {0};
+ t.tv_sec = s.st_mtim.tv_sec;
+ t.tv_nsec = s.st_mtim.tv_nsec;
+ t.tv_sec = s.st_ctim.tv_sec;
+ t.tv_nsec = s.st_ctim.tv_nsec;
+ t.tv_sec = s.st_atim.tv_sec;
+ t.tv_nsec = s.st_atim.tv_nsec;
+ ],
+ samba_cv_stat_hires=yes, samba_cv_stat_hires=no)
+ ])
+
+if test x"$samba_cv_stat_hires" = x"yes" ; then
+ AC_DEFINE(HAVE_STAT_ST_MTIM, 1, [whether struct stat contains st_mtim])
+ AC_DEFINE(HAVE_STAT_ST_ATIM, 1, [whether struct stat contains st_atim])
+ AC_DEFINE(HAVE_STAT_ST_CTIM, 1, [whether struct stat contains st_ctim])
+ AC_DEFINE(HAVE_STAT_HIRES_TIMESTAMPS, 1,
+ [whether struct stat has sub-second timestamps])
+fi
+
+AC_CACHE_CHECK([whether struct stat has sub-second timestamps without struct timespec], samba_cv_stat_hires_notimespec,
+ [
+ AC_TRY_COMPILE(
+ [
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+ ],
+ [
+ struct timespec t;
+ struct stat s = {0};
+ t.tv_sec = s.st_mtime;
+ t.tv_nsec = s.st_mtimensec;
+ t.tv_sec = s.st_ctime;
+ t.tv_nsec = s.st_ctimensec;
+ t.tv_sec = s.st_atime;
+ t.tv_nsec = s.st_atimensec;
+ ],
+ samba_cv_stat_hires=yes, samba_cv_stat_hires=no)
+ ])
+
+if test x"$samba_cv_stat_hires_notimespec" = x"yes" ; then
+ AC_DEFINE(HAVE_STAT_ST_MTIMENSEC, 1, [whether struct stat contains st_mtimensec])
+ AC_DEFINE(HAVE_STAT_ST_ATIMENSEC, 1, [whether struct stat contains st_atimensec])
+ AC_DEFINE(HAVE_STAT_ST_CTIMENSEC, 1, [whether struct stat contains st_ctimensec])
+ AC_DEFINE(HAVE_STAT_HIRES_TIMESTAMPS, 1,
+ [whether struct stat has sub-second timestamps without struct timespec])
+fi
+
+AC_CACHE_CHECK([whether struct stat has st_birthtimespec], samba_cv_stat_st_birthtimespec,
+ [
+ AC_TRY_COMPILE(
+ [
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+ ],
+ [
+ struct timespec t;
+ struct stat s = {0};
+ t = s.st_birthtimespec;
+ ],
+ samba_cv_stat_st_birthtimespec=yes, samba_cv_stat_birthtimespec=no)
+ ])
+
+if test x"$samba_cv_stat_st_birthtimespec" = x"yes" ; then
+ AC_DEFINE(HAVE_STAT_ST_BIRTHTIMESPEC, 1, [whether struct stat contains st_birthtimespec])
+fi
+
+AC_CACHE_CHECK([whether struct stat has st_birthtimensec], samba_cv_stat_st_birthtimensec,
+ [
+ AC_TRY_COMPILE(
+ [
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+ ],
+ [
+ struct timespec t;
+ struct stat s = {0};
+ t.tv_nsec = s.st_birthtimensec;
+ ],
+ samba_cv_stat_st_birthtimensec=yes, samba_cv_stat_birthtimensec=no)
+ ])
+
+if test x"$samba_cv_stat_st_birthtimensec" = x"yes" ; then
+ AC_DEFINE(HAVE_STAT_ST_BIRTHTIMENSEC, 1, [whether struct stat contains st_birthtimensec])
+fi
+
+AC_CACHE_CHECK([whether struct stat has st_birthtime], samba_cv_stat_st_birthtime,
+ [
+ AC_TRY_COMPILE(
+ [
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+ ],
+ [
+ struct time_t t;
+ struct stat s = {0};
+ t = s.st_birthtime;
+ ],
+ samba_cv_stat_st_birthtime=yes, samba_cv_stat_birthtime=no)
+ ])
+
+if test x"$samba_cv_stat_st_birthtime" = x"yes" ; then
+ AC_DEFINE(HAVE_STAT_ST_BIRTHTIME, 1, [whether struct stat contains st_birthtime])
+fi
+
+#####################################
+# needed for SRV lookups
+AC_CHECK_LIB(resolv, dn_expand)
+AC_CHECK_LIB(resolv, _dn_expand)
+AC_CHECK_LIB(resolv, __dn_expand)
+
+#
+# Check for the functions putprpwnam, set_auth_parameters,
+# getspnam, bigcrypt and getprpwnam in -lsec and -lsecurity
+# Needed for OSF1 and HPUX.
+#
+
+AC_LIBTESTFUNC(security, putprpwnam)
+AC_LIBTESTFUNC(sec, putprpwnam)
+
+AC_LIBTESTFUNC(security, set_auth_parameters)
+AC_LIBTESTFUNC(sec, set_auth_parameters)
+
+# UnixWare 7.x has its getspnam in -lgen
+AC_LIBTESTFUNC(gen, getspnam)
+
+AC_LIBTESTFUNC(security, getspnam)
+AC_LIBTESTFUNC(sec, getspnam)
+
+AC_LIBTESTFUNC(security, bigcrypt)
+AC_LIBTESTFUNC(sec, bigcrypt)
+
+AC_LIBTESTFUNC(security, getprpwnam)
+AC_LIBTESTFUNC(sec, getprpwnam)
+
+AC_CHECK_FUNCS(strsignal)
+
+############################################
+# Check if we have libattr
+case "$host_os" in
+ *osf*)
+ AC_SEARCH_LIBS(getproplist, [proplist])
+ AC_CHECK_FUNCS(getproplist fgetproplist setproplist fsetproplist)
+ AC_CHECK_FUNCS(delproplist fdelproplist add_proplist_entry get_proplist_entry)
+ AC_CHECK_FUNCS(sizeof_proplist_entry)
+ ;;
+ *)
+ AC_SEARCH_LIBS(getxattr, [attr])
+ AC_CHECK_FUNCS(getxattr lgetxattr fgetxattr listxattr llistxattr)
+ AC_CHECK_FUNCS(getea fgetea lgetea listea flistea llistea)
+ AC_CHECK_FUNCS(removeea fremoveea lremoveea setea fsetea lsetea)
+ AC_CHECK_FUNCS(flistxattr removexattr lremovexattr fremovexattr)
+ AC_CHECK_FUNCS(setxattr lsetxattr fsetxattr)
+ AC_CHECK_FUNCS(attr_get attr_list attr_set attr_remove)
+ AC_CHECK_FUNCS(attr_getf attr_listf attr_setf attr_removef)
+ ;;
+esac
+
+########################################################
+# Check if attropen() is present if this is Solaris
+case "$host_os" in
+ *solaris*)
+ AC_CHECK_FUNCS(attropen)
+ ;;
+esac
+
+########################################################
+# Do xattr functions take additional options like on Darwin?
+if test x"$ac_cv_func_getxattr" = x"yes" ; then
+ AC_CACHE_CHECK([whether xattr interface takes additional options], smb_attr_cv_xattr_add_opt, [
+ old_LIBS=$LIBS
+ LIBS="$LIBS $ACL_LIBS"
+ AC_TRY_COMPILE([
+ #include <sys/types.h>
+ #if HAVE_ATTR_XATTR_H
+ #include <attr/xattr.h>
+ #elif HAVE_SYS_XATTR_H
+ #include <sys/xattr.h>
+ #endif
+ ],[
+ getxattr(0, 0, 0, 0, 0, 0);
+ ],
+ [smb_attr_cv_xattr_add_opt=yes],
+ [smb_attr_cv_xattr_add_opt=no;LIBS=$old_LIBS])
+ ])
+ if test x"$smb_attr_cv_xattr_add_opt" = x"yes"; then
+ AC_DEFINE(XATTR_ADD_OPT, 1, [xattr functions have additional options])
+ fi
+fi
+
+# Check if we have extattr
+case "$host_os" in
+ *freebsd4* | *dragonfly* )
+ AC_DEFINE(BROKEN_EXTATTR, 1, [Does extattr API work])
+ ;;
+ *)
+ AC_CHECK_FUNCS(extattr_delete_fd extattr_delete_file extattr_delete_link)
+ AC_CHECK_FUNCS(extattr_get_fd extattr_get_file extattr_get_link)
+ AC_CHECK_FUNCS(extattr_list_fd extattr_list_file extattr_list_link)
+ AC_CHECK_FUNCS(extattr_set_fd extattr_set_file extattr_set_link)
+ ;;
+esac
+
+AC_DISABLE_STATIC
+AC_ENABLE_SHARED
+
+# Set defaults
+PIE_CFLAGS=""
+PIE_LDFLAGS=""
+AC_ARG_ENABLE(pie, [AS_HELP_STRING([--enable-pie], [Turn on pie support if available (default=yes)])])
+
+if test "x$enable_pie" != xno
+then
+ AC_CACHE_CHECK(for -pie and -fPIE, samba_cv_fpie,
+ [
+ cat > conftest.c <<EOF
+int foo;
+main () { return 0;}
+EOF
+ if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -pie -fPIE -o conftest conftest.c 1>&AS_MESSAGE_LOG_FD])
+ then
+ samba_cv_fpie=yes
+ else
+ samba_cv_fpie=no
+ fi
+ rm -f conftest*
+ ])
+ if test x"${samba_cv_fpie}" = x"yes"
+ then
+ PIE_CFLAGS="-fPIE"
+ PIE_LDFLAGS="-pie"
+ fi
+fi
+
+# Set defaults
+RELRO_LDFLAGS=""
+AC_ARG_ENABLE(relro, [AS_HELP_STRING([--enable-relro], [Turn on Relocations Read-Only (relro) support if available (default=yes)])])
+
+if test "x$enable_relro" != xno
+then
+ AC_CACHE_CHECK([for -Wl,-z,relro], samba_cv_relro,
+ [
+ cat > conftest.c <<EOF
+int foo;
+main () { return 0;}
+EOF
+ if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -Wl,-z,relro -o conftest conftest.c 1>&AS_MESSAGE_LOG_FD])
+ then
+ samba_cv_relro=yes
+ else
+ samba_cv_relro=no
+ fi
+ rm -f conftest*
+ ])
+ if test x"${samba_cv_relro}" = x"yes"
+ then
+ RELRO_LDFLAGS="-Wl,-z,relro"
+ fi
+fi
+
+# Set defaults
+SYMSEXT="syms"
+AC_SUBST(SYMSEXT)
+
+# Assume non-shared by default and override below
+BLDSHARED="false"
+
+# these are the defaults, good for lots of systems
+HOST_OS="$host_os"
+LDSHFLAGS="-shared"
+MODULE_EXPORTS=""
+SONAMEFLAG="#"
+SHLD="\${CC} \${CFLAGS}"
+PICFLAG="${PIE_CFLAGS}"
+SHLIBEXT="so"
+DSO_EXPORTS=""
+
+# this bit needs to be modified for each OS that supports share libs
+# You need to specify how to create a shared library and
+ # how to compile C code to produce PIC object files
+
+ AC_MSG_CHECKING([ability to build shared libraries])
+
+ # and these are for particular systems
+ case "$host_os" in
+ *linux*) AC_DEFINE(LINUX,1,[Whether the host os is linux])
+ BLDSHARED="true"
+ if test "${ac_cv_gnu_ld_no_default_allow_shlib_undefined}" = "yes"; then
+ LDSHFLAGS="-shared -Wl,-Bsymbolic -Wl,--allow-shlib-undefined"
+ else
+ LDSHFLAGS="-shared -Wl,-Bsymbolic"
+ fi
+ DYNEXP="-Wl,--export-dynamic"
+ PICFLAG="-fPIC"
+ SONAMEFLAG="-Wl,-soname="
+ AC_DEFINE(STAT_ST_BLOCKSIZE,512)
+ ;;
+ *solaris*) AC_DEFINE(SUNOS5,1,[Whether the host os is solaris])
+ BLDSHARED="true"
+ LDSHFLAGS="-G"
+ SONAMEFLAG="-h "
+ if test "${GCC}" = "yes"; then
+ PICFLAG="-fPIC"
+ SONAMEFLAG="-Wl,-soname="
+ if test "${ac_cv_prog_gnu_ld}" = "yes"; then
+ DYNEXP="-Wl,-E"
+ fi
+ else
+ PICFLAG="-KPIC"
+ ## ${CFLAGS} added for building 64-bit shared
+ ## libs using Sun's Compiler
+ LDSHFLAGS="-G \${CFLAGS}"
+ fi
+ AC_DEFINE(STAT_ST_BLOCKSIZE,512,[The size of a block])
+ AC_DEFINE(BROKEN_GETGRNAM,1,[Does getgrnam work correctly])
+ ;;
+ *sunos*) AC_DEFINE(SUNOS4,1,[Whether the host os is sunos4])
+ BLDSHARED="true"
+ LDSHFLAGS="-G"
+ SONAMEFLAG="-Wl,-h,"
+ PICFLAG="-KPIC" # Is this correct for SunOS
+ AC_DEFINE(STAT_ST_BLOCKSIZE,512)
+ AC_DEFINE(BROKEN_GETGRNAM,1,[Does getgrnam work correctly])
+ ;;
+ *netbsd* | *freebsd* | *dragonfly* )
+ BLDSHARED="true"
+ LDSHFLAGS="-shared"
+ DYNEXP="-Wl,--export-dynamic"
+ SONAMEFLAG="-Wl,-soname,"
+ PICFLAG="-fPIC -DPIC"
+ AC_DEFINE(STAT_ST_BLOCKSIZE,512,[The size of a block])
+ AC_DEFINE(BROKEN_GETGRNAM,1,[Does getgrnam work correctly])
+ ;;
+ *openbsd*) BLDSHARED="true"
+ LDSHFLAGS="-shared"
+ DYNEXP="-Wl,-Bdynamic"
+ SONAMEFLAG="-Wl,-soname,"
+ PICFLAG="-fPIC"
+ AC_DEFINE(STAT_ST_BLOCKSIZE,512,[The size of a block])
+ AC_DEFINE(BROKEN_GETGRNAM,1,[Does getgrnam work correctly])
+ ;;
+ *irix*) AC_DEFINE(IRIX,1,[Whether the host os is irix])
+ case "$host_os" in
+ *irix6*) AC_DEFINE(IRIX6,1,[Whether the host os is irix6])
+ ;;
+ esac
+ BLDSHARED="true"
+ LDSHFLAGS="-set_version sgi1.0 -shared"
+ SONAMEFLAG="-soname "
+ SHLD="\${LD}"
+ if test "${GCC}" = "yes"; then
+ PICFLAG="-fPIC"
+ else
+ PICFLAG="-KPIC"
+ fi
+ AC_DEFINE(STAT_ST_BLOCKSIZE,512,[The size of a block])
+ ;;
+ *aix*) AC_DEFINE(AIX,1,[Whether the host os is aix])
+ BLDSHARED="true"
+ # use expfull to export underscored symbols
+ # add rtl to remove /lib/crt0.o warning
+ LDSHFLAGS="-Wl,-G,-bexpfull,-bbigtoc,-brtl"
+ DYNEXP="-Wl,-brtl,-bexpfull,-bbigtoc"
+ PICFLAG="-O2"
+ # as AIX code is always position independent...
+ # .po will just create compile warnings, use po.o:
+ if test "${GCC}" != "yes"; then
+ ## for funky AIX compiler using strncpy()
+ CFLAGS="$CFLAGS -D_LINUX_SOURCE_COMPAT -qmaxmem=32000"
+ fi
+
+ AC_DEFINE(STAT_ST_BLOCKSIZE,DEV_BSIZE,[The size of a block])
+ AC_DEFINE(BROKEN_STRNLEN,1,[Does strnlen work correctly])
+ AC_DEFINE(BROKEN_STRNDUP,1,[Does strndup work correctly])
+ ;;
+ *hpux*) AC_DEFINE(HPUX,1,[Whether the host os is HPUX])
+ # Use special PIC flags for the native HP-UX compiler.
+ BLDSHARED="true"
+ SHLD="cc"
+ LDSHFLAGS="-b -Wl,-B,symbolic,-b,-z"
+ SONAMEFLAG="-Wl,+h "
+ PICFLAG="+z"
+ if test "${GCC}" = "yes"; then
+ PICFLAG="-fPIC"
+ else
+ PICFLAG="+z +ESnolit"
+ fi
+ if test "$host_cpu" = "ia64"; then
+ SHLIBEXT="so"
+ PICFLAG="+z"
+ DYNEXP="-Wl,-E,+b/usr/local/lib/hpux32:/usr/lib/hpux32"
+ else
+ SHLIBEXT="sl"
+ DYNEXP="-Wl,-E,+b/usr/local/lib:/usr/lib"
+ fi
+ AC_DEFINE(STAT_ST_BLOCKSIZE,8192,[The size of a block])
+ AC_DEFINE(POSIX_ACL_NEEDS_MASK,1,[Does a POSIX ACL need a mask element])
+ ;;
+ *qnx*) AC_DEFINE(QNX,1,[Whether the host os is qnx])
+ AC_DEFINE(STAT_ST_BLOCKSIZE,512)
+ ;;
+ *osf*) AC_DEFINE(OSF1,1,[Whether the host os is osf1])
+ BLDSHARED="true"
+ LDSHFLAGS="-shared"
+ SONAMEFLAG="-Wl,-soname,"
+ PICFLAG="-fPIC"
+ AC_DEFINE(STAT_ST_BLOCKSIZE,512)
+ AC_DEFINE(BROKEN_GETGRNAM,1,[Does getgrnam work correctly])
+ ;;
+ *sco*) AC_DEFINE(SCO,1,[Whether the host os is sco unix])
+ AC_DEFINE(STAT_ST_BLOCKSIZE,512)
+ ;;
+ *unixware*) AC_DEFINE(UNIXWARE,1,[Whether the host os is unixware])
+ BLDSHARED="true"
+ LDSHFLAGS="-shared"
+ SONAMEFLAG="-Wl,-soname,"
+ PICFLAG="-KPIC"
+ AC_DEFINE(STAT_ST_BLOCKSIZE,512)
+ ;;
+ *next2*) AC_DEFINE(NEXT2,1,[Whether the host os is NeXT v2])
+ AC_DEFINE(STAT_ST_BLOCKSIZE,512)
+ ;;
+ *dgux*) AC_CHECK_PROG( ROFF, groff, [groff -etpsR -Tascii -man])
+ AC_DEFINE(STAT_ST_BLOCKSIZE,512)
+ ;;
+ *sysv4*) AC_DEFINE(SYSV,1,[Whether this is a system V system])
+ case "$host" in
+ *-univel-*) if [ test "$GCC" != yes ]; then
+ AC_DEFINE(HAVE_MEMSET,1,[Whether memset() is available])
+ fi
+ LDSHFLAGS="-G"
+ DYNEXP="-Bexport"
+ ;;
+ *mips-sni-sysv4*) AC_DEFINE(RELIANTUNIX,1,[Whether the host os is reliantunix]);;
+ esac
+ AC_DEFINE(STAT_ST_BLOCKSIZE,512)
+ ;;
+
+ *sysv5*) AC_DEFINE(SYSV,1,[Whether this is a system V system])
+ if [ test "$GCC" != yes ]; then
+ AC_DEFINE(HAVE_MEMSET,1,[Whether memset() is available])
+ fi
+ LDSHFLAGS="-G"
+ AC_DEFINE(STAT_ST_BLOCKSIZE,512)
+ ;;
+ *vos*) AC_DEFINE(STAT_ST_BLOCKSIZE,4096)
+ BLDSHARED="false"
+ LDSHFLAGS=""
+ ;;
+
+ *darwin*) AC_DEFINE(DARWINOS,1,[Whether the host os is Darwin/MacOSX])
+ BLDSHARED="true"
+ LDSHFLAGS="-dynamiclib -flat_namespace -undefined suppress"
+ CFLAGS="$CFLAGS -fno-common"
+ SHLD="\${CC}"
+ SHLIBEXT="dylib"
+ MODULE_EXPORTS="-exported_symbols_list \$(srcdir)/exports/modules-darwin.syms"
+ SHLIBEXT="dylib"
+ # Since gcc doesn't fail on unrecognised options, the
+ # PIE test incorrectly succeeds. Darwin gcc does not
+ # actually support the PIE stuff.
+ PIE_LDFLAGS=
+ PIE_CFLAGS=
+ AC_DEFINE(STAT_ST_BLOCKSIZE,512)
+ ;;
+
+ *)
+ AC_DEFINE(STAT_ST_BLOCKSIZE,512)
+ ;;
+ esac
+
+if test "$enable_shared" != "yes"; then
+ BLDSHARED=false
+fi
+
+if test "$enable_shared" = yes -a "${ac_cv_gnu_ld_version_script}" = yes; then
+ DSO_EXPORTS=\$\(DSO_EXPORTS_CMD\)
+fi
+
+if test x"$BLDSHARED" = x"true" ; then
+ LDFLAGS="$LDFLAGS -L./bin"
+fi
+
+AC_MSG_RESULT($BLDSHARED)
+
+AC_MSG_CHECKING([LDFLAGS])
+AC_MSG_RESULT([$LDFLAGS])
+AC_MSG_CHECKING([DYNEXP])
+AC_MSG_RESULT([$DYNEXP])
+
+#######################################################
+# test whether building a shared library actually works
+if test $BLDSHARED = true; then
+
+AC_MSG_CHECKING([SHLD])
+AC_MSG_RESULT([$SHLD])
+AC_MSG_CHECKING([LDSHFLAGS])
+AC_MSG_RESULT([$LDSHFLAGS])
+
+AC_MSG_CHECKING([SHLIBEXT])
+AC_MSG_RESULT([$SHLIBEXT])
+AC_MSG_CHECKING([SONAMEFLAG])
+AC_MSG_RESULT([$SONAMEFLAG])
+
+AC_MSG_CHECKING([PICFLAG])
+AC_MSG_RESULT([$PICFLAG])
+
+AC_MSG_CHECKING([NSSSONAMEVERSIONSUFFIX])
+AC_MSG_RESULT([$NSSSONAMEVERSIONSUFFIX])
+
+AC_CACHE_CHECK([whether building shared libraries actually works],
+ [ac_cv_shlib_works],[
+ # try building a trivial shared library
+ ac_cv_shlib_works=no
+ # The $SHLD and $LDSHFLAGS variables may contain references to other
+ # variables so they need to be eval'ed.
+ $CC $CPPFLAGS $CFLAGS $PICFLAG -c -o \
+ shlib.o ${srcdir-.}/tests/shlib.c && \
+ `eval echo $SHLD` `eval echo $LDSHFLAGS` -o "shlib.$SHLIBEXT" \
+ shlib.o && ac_cv_shlib_works=yes
+ rm -f "shlib.$SHLIBEXT" shlib.o
+
+])
+if test $ac_cv_shlib_works = no; then
+ BLDSHARED=false
+fi
+fi
+
+if test x"$BLDSHARED" != x"true"; then
+ LDSHFLAGS="shared-libraries-disabled"
+ SONAMEFLAG="shared-libraries-disabled"
+ NSSSONAMEVERSIONSUFFIX="shared-libraries-disabled"
+ SHLD="shared-libraries-disabled"
+ PICFLAG="${PIE_CFLAGS}"
+ SHLIBEXT="shared_libraries_disabled"
+fi
+
+AC_MSG_CHECKING([used PICFLAG])
+AC_MSG_RESULT([$PICFLAG])
+
+AC_DEFINE_UNQUOTED(SHLIBEXT, "$SHLIBEXT", [Shared library extension])
+
+AC_LIBREPLACE_RUNTIME_LIB_PATH_VAR
+
+################
+
+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,1,[Whether the host supports long long's])
+ AC_CHECK_TYPE(intptr_t, unsigned long long)
+else
+ AC_CHECK_TYPE(intptr_t, unsigned long)
+fi
+
+#
+# Check if the compiler supports the LL prefix on long long integers.
+# AIX needs this.
+
+AC_CACHE_CHECK([for LL suffix on long long integers],samba_cv_compiler_supports_ll, [
+ AC_TRY_COMPILE([#include <stdio.h>],[long long i = 0x8000000000LL],
+ samba_cv_compiler_supports_ll=yes,samba_cv_compiler_supports_ll=no)])
+if test x"$samba_cv_compiler_supports_ll" = x"yes"; then
+ AC_DEFINE(COMPILER_SUPPORTS_LL,1,[Whether the compiler supports the LL prefix on long long integers])
+fi
+
+
+AC_CACHE_CHECK([for 64 bit time_t],samba_cv_SIZEOF_TIME_T,[
+AC_TRY_RUN([#include <time.h>
+main() { exit((sizeof(time_t) == 8) ? 0 : 1); }],
+samba_cv_SIZEOF_TIME_T=yes,samba_cv_SIZEOF_TIME_T=no,samba_cv_SIZEOF_TIME_T=cross)])
+if test x"$samba_cv_SIZEOF_TIME_T" = x"yes"; then
+ AC_DEFINE(SIZEOF_TIME_T,8,[The size of the 'time_t' type])
+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,[The size of the 'off_t' type])
+fi
+
+AC_CACHE_CHECK([for off64_t],samba_cv_HAVE_OFF64_T,[
+AC_TRY_RUN([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <sys/stat.h>
+main() { struct stat64 st; off64_t s; if (sizeof(off_t) == sizeof(off64_t)) exit(1); exit((lstat64("/dev/null", &st)==0)?0:1); }],
+samba_cv_HAVE_OFF64_T=yes,samba_cv_HAVE_OFF64_T=no,samba_cv_HAVE_OFF64_T=cross)])
+if test x"$samba_cv_HAVE_OFF64_T" = x"yes"; then
+ AC_DEFINE(HAVE_OFF64_T,1,[Whether off64_t is available])
+fi
+
+AC_CACHE_CHECK([for 64 bit ino_t],samba_cv_SIZEOF_INO_T,[
+AC_TRY_RUN([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#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,[The size of the 'ino_t' type])
+fi
+
+AC_CACHE_CHECK([for ino64_t],samba_cv_HAVE_INO64_T,[
+AC_TRY_RUN([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <sys/stat.h>
+main() { struct stat64 st; ino64_t s; if (sizeof(ino_t) == sizeof(ino64_t)) exit(1); exit((lstat64("/dev/null", &st)==0)?0:1); }],
+samba_cv_HAVE_INO64_T=yes,samba_cv_HAVE_INO64_T=no,samba_cv_HAVE_INO64_T=cross)])
+if test x"$samba_cv_HAVE_INO64_T" = x"yes"; then
+ AC_DEFINE(HAVE_INO64_T,1,[Whether the 'ino64_t' type is available])
+fi
+
+AC_CACHE_CHECK([for 64 bit dev_t],samba_cv_SIZEOF_DEV_T,[
+AC_TRY_RUN([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <sys/stat.h>
+main() { exit((sizeof(dev_t) == 8) ? 0 : 1); }],
+samba_cv_SIZEOF_DEV_T=yes,samba_cv_SIZEOF_DEV_T=no,samba_cv_SIZEOF_DEV_T=cross)])
+if test x"$samba_cv_SIZEOF_DEV_T" = x"yes"; then
+ AC_DEFINE(SIZEOF_DEV_T,8,[The size of the 'dev_t' type])
+fi
+
+AC_CACHE_CHECK([for dev64_t],samba_cv_HAVE_DEV64_T,[
+AC_TRY_RUN([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <sys/stat.h>
+main() { struct stat64 st; dev64_t s; if (sizeof(dev_t) == sizeof(dev64_t)) exit(1); exit((lstat64("/dev/null", &st)==0)?0:1); }],
+samba_cv_HAVE_DEV64_T=yes,samba_cv_HAVE_DEV64_T=no,samba_cv_HAVE_DEV64_T=cross)])
+if test x"$samba_cv_HAVE_DEV64_T" = x"yes"; then
+ AC_DEFINE(HAVE_DEV64_T,1,[Whether the 'dev64_t' type is available])
+fi
+
+AC_CACHE_CHECK([for struct dirent64],samba_cv_HAVE_STRUCT_DIR64,[
+AC_TRY_COMPILE([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <dirent.h>],
+[DIR64 de;],
+samba_cv_HAVE_STRUCT_DIR64=yes,samba_cv_HAVE_STRUCT_DIR64=no)])
+if test x"$samba_cv_HAVE_STRUCT_DIR64" = x"yes" && test x"$ac_cv_func_readdir64" = x"yes"; then
+ AC_DEFINE(HAVE_STRUCT_DIR64,1,[Whether the 'DIR64' abstract data type is available])
+fi
+
+AC_CACHE_CHECK([for struct dirent64],samba_cv_HAVE_STRUCT_DIRENT64,[
+AC_TRY_COMPILE([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <dirent.h>],
+[struct dirent64 de;],
+samba_cv_HAVE_STRUCT_DIRENT64=yes,samba_cv_HAVE_STRUCT_DIRENT64=no)])
+if test x"$samba_cv_HAVE_STRUCT_DIRENT64" = x"yes" && test x"$ac_cv_func_readdir64" = x"yes"; then
+ AC_DEFINE(HAVE_STRUCT_DIRENT64,1,[Whether the 'dirent64' struct is available])
+fi
+
+AC_CACHE_CHECK([for major macro],samba_cv_HAVE_DEVICE_MAJOR_FN,[
+AC_TRY_RUN([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+main() { dev_t dev; int i = major(dev); return 0; }],
+samba_cv_HAVE_DEVICE_MAJOR_FN=yes,samba_cv_HAVE_DEVICE_MAJOR_FN=no,samba_cv_HAVE_DEVICE_MAJOR_FN=cross)])
+if test x"$samba_cv_HAVE_DEVICE_MAJOR_FN" = x"yes"; then
+ AC_DEFINE(HAVE_DEVICE_MAJOR_FN,1,[Whether the major macro for dev_t is available])
+fi
+
+AC_CACHE_CHECK([for minor macro],samba_cv_HAVE_DEVICE_MINOR_FN,[
+AC_TRY_RUN([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+main() { dev_t dev; int i = minor(dev); return 0; }],
+samba_cv_HAVE_DEVICE_MINOR_FN=yes,samba_cv_HAVE_DEVICE_MINOR_FN=no,samba_cv_HAVE_DEVICE_MINOR_FN=cross)])
+if test x"$samba_cv_HAVE_DEVICE_MINOR_FN" = x"yes"; then
+ AC_DEFINE(HAVE_DEVICE_MINOR_FN,1,[Whether the minor macro for dev_t is available])
+fi
+
+AC_CACHE_CHECK([for makedev macro],samba_cv_HAVE_MAKEDEV,[
+AC_TRY_RUN([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+main() { dev_t dev = makedev(1,2); return 0; }],
+samba_cv_HAVE_MAKEDEV=yes,samba_cv_HAVE_MAKEDEV=no,samba_cv_HAVE_MAKEDEV=cross)])
+if test x"$samba_cv_HAVE_MAKEDEV" = x"yes"; then
+ AC_DEFINE(HAVE_MAKEDEV,1,[Whether the macro for makedev is available])
+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,1,[Whether the 'unsigned char' type is available])
+fi
+
+AC_CACHE_CHECK([whether seekdir returns void],samba_cv_SEEKDIR_RETURNS_VOID,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <dirent.h>
+void seekdir(DIR *d, long loc) { return; }],[return 0;],
+samba_cv_SEEKDIR_RETURNS_VOID=yes,samba_cv_SEEKDIR_RETURNS_VOID=no)])
+if test x"$samba_cv_SEEKDIR_RETURNS_VOID" = x"yes"; then
+ AC_DEFINE(SEEKDIR_RETURNS_VOID,1,[Whether seekdir returns void])
+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,1,[Whether there is a __FUNCTION__ macro])
+fi
+
+AC_CACHE_CHECK([if gettimeofday takes tz argument],samba_cv_HAVE_GETTIMEOFDAY_TZ,[
+AC_TRY_LINK([
+#include <sys/time.h>
+#include <unistd.h>], [struct timeval tv; return gettimeofday(&tv, NULL);],
+ samba_cv_HAVE_GETTIMEOFDAY_TZ=yes,
+ samba_cv_HAVE_GETTIMEOFDAY_TZ=no)])
+if test x"$samba_cv_HAVE_GETTIMEOFDAY_TZ" = x"yes"; then
+ AC_DEFINE(HAVE_GETTIMEOFDAY_TZ,1,[Whether gettimeofday takes a tz argument])
+fi
+
+if test x"$samba_cv_WITH_PROFILE" = x"yes"; then
+
+ # On some systems (eg. Linux) librt can pull in libpthread. We
+ # don't want this to happen because libpthreads changes signal delivery
+ # semantics in ways we are not prepared for. This breaks Linux oplocks
+ # which rely on signals.
+
+ AC_LIBTESTFUNC(rt, clock_gettime,
+ [
+ AC_DEFINE(HAVE_CLOCK_GETTIME, 1,
+ [Whether clock_gettime is available])
+ SMB_CHECK_CLOCK_ID(CLOCK_MONOTONIC)
+ SMB_CHECK_CLOCK_ID(CLOCK_PROCESS_CPUTIME_ID)
+ SMB_CHECK_CLOCK_ID(CLOCK_REALTIME)
+ ])
+
+fi
+
+AC_CACHE_CHECK([for broken readdir name],samba_cv_HAVE_BROKEN_READDIR_NAME,[
+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_NAME=yes,samba_cv_HAVE_BROKEN_READDIR_NAME=no,samba_cv_HAVE_BROKEN_READDIR_NAME=cross)])
+if test x"$samba_cv_HAVE_BROKEN_READDIR_NAME" = x"yes"; then
+ AC_DEFINE(HAVE_BROKEN_READDIR_NAME,1,[Whether readdir() returns the wrong name offset])
+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,1,[Whether struct utimbuf is available])
+fi
+
+##############
+# Check utmp details, but only if our OS offers utmp.h
+if test x"$ac_cv_header_utmp_h" = x"yes"; then
+dnl utmp and utmpx come in many flavours
+dnl We need to check for many of them
+dnl But we don't need to do each and every one, because our code uses
+dnl mostly just the utmp (not utmpx) fields.
+
+AC_CHECK_FUNCS(pututline pututxline updwtmp updwtmpx getutmpx)
+
+AC_CACHE_CHECK([for ut_name in utmp],samba_cv_HAVE_UT_UT_NAME,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_name[0] = 'a';],
+samba_cv_HAVE_UT_UT_NAME=yes,samba_cv_HAVE_UT_UT_NAME=no,samba_cv_HAVE_UT_UT_NAME=cross)])
+if test x"$samba_cv_HAVE_UT_UT_NAME" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_NAME,1,[Whether the utmp struct has a property ut_name])
+fi
+
+AC_CACHE_CHECK([for ut_user in utmp],samba_cv_HAVE_UT_UT_USER,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_user[0] = 'a';],
+samba_cv_HAVE_UT_UT_USER=yes,samba_cv_HAVE_UT_UT_USER=no,samba_cv_HAVE_UT_UT_USER=cross)])
+if test x"$samba_cv_HAVE_UT_UT_USER" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_USER,1,[Whether the utmp struct has a property ut_user])
+fi
+
+AC_CACHE_CHECK([for ut_id in utmp],samba_cv_HAVE_UT_UT_ID,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_id[0] = 'a';],
+samba_cv_HAVE_UT_UT_ID=yes,samba_cv_HAVE_UT_UT_ID=no,samba_cv_HAVE_UT_UT_ID=cross)])
+if test x"$samba_cv_HAVE_UT_UT_ID" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_ID,1,[Whether the utmp struct has a property ut_id])
+fi
+
+AC_CACHE_CHECK([for ut_host in utmp],samba_cv_HAVE_UT_UT_HOST,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_host[0] = 'a';],
+samba_cv_HAVE_UT_UT_HOST=yes,samba_cv_HAVE_UT_UT_HOST=no,samba_cv_HAVE_UT_UT_HOST=cross)])
+if test x"$samba_cv_HAVE_UT_UT_HOST" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_HOST,1,[Whether the utmp struct has a property ut_host])
+fi
+
+AC_CACHE_CHECK([for ut_time in utmp],samba_cv_HAVE_UT_UT_TIME,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; time_t t; ut.ut_time = t;],
+samba_cv_HAVE_UT_UT_TIME=yes,samba_cv_HAVE_UT_UT_TIME=no,samba_cv_HAVE_UT_UT_TIME=cross)])
+if test x"$samba_cv_HAVE_UT_UT_TIME" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_TIME,1,[Whether the utmp struct has a property ut_time])
+fi
+
+AC_CACHE_CHECK([for ut_tv in utmp],samba_cv_HAVE_UT_UT_TV,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; struct timeval tv; ut.ut_tv = tv;],
+samba_cv_HAVE_UT_UT_TV=yes,samba_cv_HAVE_UT_UT_TV=no,samba_cv_HAVE_UT_UT_TV=cross)])
+if test x"$samba_cv_HAVE_UT_UT_TV" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_TV,1,[Whether the utmp struct has a property ut_tv])
+fi
+
+AC_CACHE_CHECK([for ut_type in utmp],samba_cv_HAVE_UT_UT_TYPE,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_type = 0;],
+samba_cv_HAVE_UT_UT_TYPE=yes,samba_cv_HAVE_UT_UT_TYPE=no,samba_cv_HAVE_UT_UT_TYPE=cross)])
+if test x"$samba_cv_HAVE_UT_UT_TYPE" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_TYPE,1,[Whether the utmp struct has a property ut_type])
+fi
+
+AC_CACHE_CHECK([for ut_pid in utmp],samba_cv_HAVE_UT_UT_PID,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_pid = 0;],
+samba_cv_HAVE_UT_UT_PID=yes,samba_cv_HAVE_UT_UT_PID=no,samba_cv_HAVE_UT_UT_PID=cross)])
+if test x"$samba_cv_HAVE_UT_UT_PID" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_PID,1,[Whether the utmp struct has a property ut_pid])
+fi
+
+AC_CACHE_CHECK([for ut_exit in utmp],samba_cv_HAVE_UT_UT_EXIT,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_exit.e_exit = 0;],
+samba_cv_HAVE_UT_UT_EXIT=yes,samba_cv_HAVE_UT_UT_EXIT=no,samba_cv_HAVE_UT_UT_EXIT=cross)])
+if test x"$samba_cv_HAVE_UT_UT_EXIT" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_EXIT,1,[Whether the utmp struct has a property ut_exit])
+fi
+
+dnl Look for the IPv6 varient by preference. Many systems have both.
+AC_CACHE_CHECK([for ut_addr_v6 in utmp],samba_cv_HAVE_UT_UT_ADDR_V6,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_addr_v6[0] = 0;],
+samba_cv_HAVE_UT_UT_ADDR_V6=yes,samba_cv_HAVE_UT_UT_ADDR_V6=no,samba_cv_HAVE_UT_UT_ADDR_V6=cross)])
+if test x"$samba_cv_HAVE_UT_UT_ADDR_V6" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_ADDR_V6,1,[Whether the utmp struct has a property ut_addr_v6])
+fi
+
+AC_CACHE_CHECK([for ut_addr in utmp],samba_cv_HAVE_UT_UT_ADDR,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_addr = 0;],
+samba_cv_HAVE_UT_UT_ADDR=yes,samba_cv_HAVE_UT_UT_ADDR=no,samba_cv_HAVE_UT_UT_ADDR=cross)])
+if test x"$samba_cv_HAVE_UT_UT_ADDR" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_ADDR,1,[Whether the utmp struct has a property ut_addr])
+fi
+
+if test x$ac_cv_func_pututline = xyes ; then
+ AC_CACHE_CHECK([whether pututline returns pointer],samba_cv_PUTUTLINE_RETURNS_UTMP,[
+ AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+ [struct utmp utarg; struct utmp *utreturn; utreturn = pututline(&utarg);],
+ samba_cv_PUTUTLINE_RETURNS_UTMP=yes,samba_cv_PUTUTLINE_RETURNS_UTMP=no)])
+ if test x"$samba_cv_PUTUTLINE_RETURNS_UTMP" = x"yes"; then
+ AC_DEFINE(PUTUTLINE_RETURNS_UTMP,1,[Whether pututline returns pointer])
+ fi
+fi
+
+AC_CACHE_CHECK([for ut_syslen in utmpx],samba_cv_HAVE_UX_UT_SYSLEN,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmpx.h>],
+[struct utmpx ux; ux.ut_syslen = 0;],
+samba_cv_HAVE_UX_UT_SYSLEN=yes,samba_cv_HAVE_UX_UT_SYSLEN=no,samba_cv_HAVE_UX_UT_SYSLEN=cross)])
+if test x"$samba_cv_HAVE_UX_UT_SYSLEN" = x"yes"; then
+ AC_DEFINE(HAVE_UX_UT_SYSLEN,1,[Whether the utmpx struct has a property ut_syslen])
+fi
+
+fi
+# end utmp details
+
+
+ICONV_LOOK_DIRS="/usr /usr/local /sw /opt"
+AC_ARG_WITH(libiconv,
+[AS_HELP_STRING([--with-libiconv=BASEDIR], [Use libiconv in BASEDIR/lib and BASEDIR/include (default=auto)])],
+[
+ if test "$withval" = "no" ; then
+ AC_MSG_ERROR([argument to --with-libiconv must be a directory])
+ else
+ if test "$withval" != "yes" ; then
+ ICONV_PATH_SPEC=yes
+ ICONV_LOOK_DIRS="$withval"
+ fi
+ fi
+])
+
+for i in $ICONV_LOOK_DIRS ; do
+
+ save_LIBS="$LIBS"
+ save_LDFLAGS="$LDFLAGS"
+ save_CPPFLAGS="$CPPFLAGS"
+
+ iconv_current_LIBS=""
+ iconv_current_LDFLAGS=""
+ iconv_current_CPPFLAGS=""
+
+ ICONV_FOUND="no"
+ unset libext
+
+ # This is here to handle -withval stuff for --with-libiconv
+ # Perhaps we should always add a -L
+ CPPFLAGS="$save_CPPFLAGS -I$i/include"
+
+ # Check lib and lib32 library variants to cater for IRIX ABI-specific
+ # installation paths. This gets a little tricky since we might have iconv
+ # in both libiconv and in libc. In this case the jm_ICONV test will always
+ # succeed when the header is found. To counter this, make sure the
+ # library directory is there and check the ABI directory first (which
+ # should be harmless on other systems, but causes tons of linker warnings on
+ # 64bit Ubuntu systems).
+ # As the build farm doesn't seem to have any IRIX machines with iconv.h
+ # installed, I've decided to fix the linker warnings.
+ # -- Kai
+ # For IA64 HPUX systems, the libs are located in lib/hpux32 instead of lib.
+ for l in "lib" "lib32" "lib/hpux32"; do
+ if test -d "$i/$l" ; then
+ LDFLAGS="$save_LDFLAGS -L$i/$l"
+ LIBS=
+ export LDFLAGS LIBS CPPFLAGS
+ # Try to find iconv(3)
+ jm_ICONV($i/$l)
+ if test x"$ICONV_FOUND" = "xyes" ; then
+ libext="$l"
+ break
+ fi
+ fi
+ done
+
+ if test x"$ICONV_FOUND" = "xyes" ; then
+ iconv_current_LDFLAGS="-L$i/$libext"
+ iconv_current_CPPFLAGS="-I$i/include"
+
+ if test x"$jm_cv_lib_iconv" != x; then
+ iconv_current_LIBS="$LIBS -l$jm_cv_lib_iconv"
+ else
+ # We found iconv in libc.
+ iconv_current_LIBS=""
+ fi
+
+ fi
+
+ if test x"$ICONV_FOUND" = "xyes" ; then
+
+ LDFLAGS="$save_LDFLAGS $iconv_current_LDFLAGS"
+ CPPFLAGS="$save_CPPFLAGS $iconv_current_CPPFLAGS"
+ LIBS="$save_LIBS $iconv_current_LIBS"
+ export LDFLAGS LIBS CPPFLAGS
+
+ default_dos_charset=no
+ default_display_charset=no
+ default_unix_charset=no
+
+ # check for default dos charset name
+ for j in CP850 IBM850 ; do
+ rjs_CHARSET($j)
+ default_dos_charset="$ICONV_CHARSET"
+ if test x"$default_dos_charset" = x"$j"; then
+ break
+ fi
+ done
+
+ # check for default display charset name
+ for j in ASCII 646 ; do
+ rjs_CHARSET($j)
+ default_display_charset="$ICONV_CHARSET"
+ if test x"$default_display_charset" = x"$j"; then
+ break
+ fi
+ done
+
+ # check for default unix charset name
+ for j in UTF-8 UTF8 ; do
+ rjs_CHARSET($j)
+ default_unix_charset="$ICONV_CHARSET"
+ if test x"$default_unix_charset" = x"$j"; then
+ break
+ fi
+ done
+
+ if test "$default_dos_charset" != "no" -a \
+ "$default_dos_charset" != "cross" -a \
+ "$default_display_charset" != "no" -a \
+ "$default_display_charset" != "cross" -a \
+ "$default_unix_charset" != "no" -a \
+ "$default_unix_charset" != "cross"
+ then
+ samba_cv_HAVE_NATIVE_ICONV=yes
+ else
+ if test "$default_dos_charset" = "cross" -o \
+ "$default_display_charset" = "cross" -o \
+ "$default_unix_charset" = "cross"
+ then
+ samba_cv_HAVE_NATIVE_ICONV=cross
+ else
+ samba_cv_HAVE_NATIVE_ICONV=no
+ fi
+ fi
+
+ # At this point, we have a libiconv candidate. We know that
+ # we have the right headers and libraries, but we don't know
+ # whether it does the conversions we want. We can't test this
+ # because we are cross-compiling. This is not necessarily a big
+ # deal, since we can't guarantee that the results we get now will
+ # match the results we get at runtime anyway.
+ if test x"$samba_cv_HAVE_NATIVE_ICONV" = x"cross" ; then
+ default_dos_charset="CP850"
+ default_display_charset="ASCII"
+ default_unix_charset="UTF-8"
+ samba_cv_HAVE_NATIVE_ICONV=yes
+ AC_MSG_WARN(assuming the libiconv in $iconv_current_LDFLAGS can convert)
+ AC_MSG_WARN([$default_dos_charset, $default_display_charset and $default_unix_charset to UCS-16LE])
+ fi
+
+ if test x"$samba_cv_HAVE_NATIVE_ICONV" = x"yes" ; then
+
+ CPPFLAGS=$save_CPPFLAGS
+ LDFLAGS=$save_LDFLAGS
+ LIBS=$save_LIBS
+
+ if test x"$iconv_current_LIBS" != x; then
+ LIBS="$LIBS $iconv_current_LIBS"
+ fi
+
+ # Add the flags we need to CPPFLAGS and LDFLAGS
+ CPPFLAGS="$CPPFLAGS $iconv_current_CPPFLAGS"
+ LDFLAGS="$LDFLAGS $iconv_current_LDFLAGS"
+
+ # Turn the #defines into string literals
+ default_dos_charset="\"$default_dos_charset\""
+ default_display_charset="\"$default_display_charset\""
+ default_unix_charset="\"$default_unix_charset\""
+
+ AC_DEFINE(HAVE_NATIVE_ICONV,1,[Whether to use native iconv])
+ AC_DEFINE_UNQUOTED(DEFAULT_DOS_CHARSET,$default_dos_charset,[Default dos charset name])
+ AC_DEFINE_UNQUOTED(DEFAULT_DISPLAY_CHARSET,$default_display_charset,[Default display charset name])
+ AC_DEFINE_UNQUOTED(DEFAULT_UNIX_CHARSET,$default_unix_charset,[Default unix charset name])
+
+ break
+ fi
+
+ # We didn't find a working iconv, so keep going
+ fi
+
+ # We only need to clean these up here for the next pass through the loop
+ CPPFLAGS=$save_CPPFLAGS
+ LDFLAGS=$save_LDFLAGS
+ LIBS=$save_LIBS
+ export LDFLAGS LIBS CPPFLAGS
+done
+unset libext
+
+
+if test x"$ICONV_FOUND" = x"no" -o x"$samba_cv_HAVE_NATIVE_ICONV" != x"yes" ; then
+ AC_MSG_WARN([Sufficient support for iconv function was not found.
+ Install libiconv from http://freshmeat.net/projects/libiconv/ for better charset compatibility!])
+ AC_DEFINE_UNQUOTED(DEFAULT_DOS_CHARSET,"ASCII",[Default dos charset name])
+ AC_DEFINE_UNQUOTED(DEFAULT_DISPLAY_CHARSET,"ASCII",[Default display charset name])
+ AC_DEFINE_UNQUOTED(DEFAULT_UNIX_CHARSET,"UTF8",[Default unix charset name])
+fi
+
+
+AC_CACHE_CHECK([for Linux kernel oplocks],samba_cv_HAVE_KERNEL_OPLOCKS_LINUX,[
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <fcntl.h>
+#ifndef F_GETLEASE
+#define F_GETLEASE 1025
+#endif
+main() {
+ int fd = open("/dev/null", O_RDONLY);
+ return fcntl(fd, F_GETLEASE, 0) == -1;
+}
+],
+samba_cv_HAVE_KERNEL_OPLOCKS_LINUX=yes,samba_cv_HAVE_KERNEL_OPLOCKS_LINUX=no,samba_cv_HAVE_KERNEL_OPLOCKS_LINUX=cross)])
+if test x"$samba_cv_HAVE_KERNEL_OPLOCKS_LINUX" = x"yes"; then
+ AC_DEFINE(HAVE_KERNEL_OPLOCKS_LINUX,1,[Whether to use linux kernel oplocks])
+fi
+
+AC_CACHE_CHECK([for kernel change notify support],samba_cv_HAVE_KERNEL_CHANGE_NOTIFY,[
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+#ifndef F_NOTIFY
+#define F_NOTIFY 1026
+#endif
+main() {
+ exit(fcntl(open("/tmp", O_RDONLY), F_NOTIFY, 0) == -1 ? 1 : 0);
+}
+],
+samba_cv_HAVE_KERNEL_CHANGE_NOTIFY=yes,samba_cv_HAVE_KERNEL_CHANGE_NOTIFY=no,samba_cv_HAVE_KERNEL_CHANGE_NOTIFY=cross)])
+if test x"$samba_cv_HAVE_KERNEL_CHANGE_NOTIFY" = x"yes"; then
+ AC_DEFINE(HAVE_KERNEL_CHANGE_NOTIFY,1,[Whether kernel notifies changes])
+fi
+
+AC_CACHE_CHECK([for inotify support],samba_cv_HAVE_INOTIFY,[
+AC_CHECK_HEADERS(linux/inotify.h asm/unistd.h)
+AC_CHECK_FUNCS(inotify_init)
+AC_HAVE_DECL(__NR_inotify_init, [#include <asm/unistd.h>])
+],
+samba_cv_HAVE_INOTIFY=yes,
+samba_cv_HAVE_INOTIFY=no,
+samba_cv_HAVE_INOTIFY=cross)
+
+if test x"$ac_cv_func_inotify_init" = x"yes" -a x"$ac_cv_header_linux_inotify_h" = x"yes"; then
+ AC_DEFINE(HAVE_INOTIFY,1,[Whether kernel has inotify support])
+fi
+
+#################################################
+# Check if FAM notifications are available. For FAM info, see
+# http://oss.sgi.com/projects/fam/
+# http://savannah.nongnu.org/projects/fam/
+AC_ARG_ENABLE(fam,
+[AS_HELP_STRING([--enable-fam], [Turn on FAM support (default=auto)])])
+
+if test x$enable_fam != xno; then
+ AC_CHECK_HEADERS(fam.h, [samba_cv_HAVE_FAM_H=yes], [samba_cv_HAVE_FAM_H=no])
+ if test x"$samba_cv_HAVE_FAM_H" = x"yes"; then
+ # On IRIX, libfam requires libC, but other FAM implementations
+ # might not need it.
+ AC_CHECK_LIB(fam, FAMOpen2,
+ [samba_cv_HAVE_LIBFAM=yes; SMB_FAM_LIBS="-lfam"],
+ [samba_cv_HAVE_LIBFAM=no])
+
+ if test x"$samba_cv_HAVE_LIBFAM" = x"no" ; then
+ samba_fam_xtra=-lC
+ AC_CHECK_LIB_EXT(fam, samba_fam_xtra, FAMOpen2,
+ [samba_cv_HAVE_LIBFAM=yes; SMB_FAM_LIBS="-lfam -lC"],
+ [samba_cv_HAVE_LIBFAM=no])
+ unset samba_fam_xtra
+ fi
+ fi
+
+ if test x"$samba_cv_HAVE_LIBFAM" = x"yes" ; then
+ default_shared_modules="$default_shared_modules vfs_notify_fam"
+ AC_TRY_COMPILE([#include <fam.h>],
+ [FAMCodes code = FAMChanged;],
+ AC_DEFINE(HAVE_FAM_H_FAMCODES_TYPEDEF, 1,
+ [Whether fam.h contains a typedef for enum FAMCodes]),
+ [])
+ fi
+
+ if test x$enable_fam = xyes && test x"$samba_cv_HAVE_LIBFAM" != xyes ; then
+ AC_MSG_ERROR(FAM support requested but FAM library not available )
+ fi
+fi
+
+AC_SUBST(SMB_FAM_LIBS)
+
+#################################################
+# Check for DMAPI interfaces in libdm/libjfsdm/libxsdm
+
+SMB_CHECK_DMAPI([], AC_MSG_NOTICE(DMAPI support not present) )
+
+# Add TSM SM VFS module only if there are both GPFS and DMAPI support
+# Theoretically it should work with AIX JFS2 too but this needs testing
+if test x"$samba_cv_HAVE_GPFS" = x"yes" && test x"$samba_dmapi_libs" != x"" ; then
+ default_shared_modules="$default_shared_modules vfs_tsmsm"
+fi
+
+AC_CACHE_CHECK([for kernel share modes],samba_cv_HAVE_KERNEL_SHARE_MODES,[
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/file.h>
+#ifndef LOCK_MAND
+#define LOCK_MAND 32
+#define LOCK_READ 64
+#endif
+main() {
+ exit(flock(open("/dev/null", O_RDWR), LOCK_MAND|LOCK_READ) != 0);
+}
+],
+samba_cv_HAVE_KERNEL_SHARE_MODES=yes,samba_cv_HAVE_KERNEL_SHARE_MODES=no,samba_cv_HAVE_KERNEL_SHARE_MODES=cross)])
+if test x"$samba_cv_HAVE_KERNEL_SHARE_MODES" = x"yes"; then
+ AC_DEFINE(HAVE_KERNEL_SHARE_MODES,1,[Whether the kernel supports share modes])
+fi
+
+
+AC_CACHE_CHECK([for IRIX kernel oplock type definitions],samba_cv_HAVE_KERNEL_OPLOCKS_IRIX,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <fcntl.h>],
+[oplock_stat_t t; t.os_state = OP_REVOKE; t.os_dev = 1; t.os_ino = 1;],
+samba_cv_HAVE_KERNEL_OPLOCKS_IRIX=yes,samba_cv_HAVE_KERNEL_OPLOCKS_IRIX=no)])
+if test x"$samba_cv_HAVE_KERNEL_OPLOCKS_IRIX" = x"yes"; then
+ AC_DEFINE(HAVE_KERNEL_OPLOCKS_IRIX,1,[Whether IRIX kernel oplock type definitions are available])
+fi
+
+#################################################
+# Check for POSIX capability support
+
+AC_CHECK_HEADER(sys/capability.h, [samba_cv_HAVE_SYS_CAPABILITY_H=yes;
+ AC_DEFINE(HAVE_SYS_CAPABILITY_H, 1, Whether sys/capability.h is present)],
+ [], [])
+
+if test x"$samba_cv_HAVE_SYS_CAPABILITY_H" = x"yes"; then
+
+ ac_save_LIBS=$LIBS
+ AC_LIBTESTFUNC(cap, cap_get_proc)
+
+ AC_CACHE_CHECK([for POSIX capabilities],
+ samba_cv_HAVE_POSIX_CAPABILITIES,
+ [
+ AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/capability.h>
+main() {
+ cap_t cap;
+ cap_value_t vals[1];
+ if (!(cap = cap_get_proc()))
+ exit(1);
+ vals[0] = CAP_CHOWN;
+ cap_set_flag(cap, CAP_INHERITABLE, 1, vals, CAP_CLEAR);
+ cap_set_proc(cap);
+ exit(0);
+}],
+ samba_cv_HAVE_POSIX_CAPABILITIES=yes,
+ samba_cv_HAVE_POSIX_CAPABILITIES=no,
+ samba_cv_HAVE_POSIX_CAPABILITIES=cross)
+ ])
+
+if test x"$samba_cv_HAVE_POSIX_CAPABILITIES" = x"yes"; then
+ AC_DEFINE(HAVE_POSIX_CAPABILITIES, 1,
+ [Whether POSIX capabilities are available])
+else
+ LIBS=$ac_save_LIBS
+fi
+
+fi
+
+#
+# Check for int16, uint16, int32 and uint32 in rpc/types.h included from rpc/rpc.h
+# This is *really* broken but some systems (DEC OSF1) do this.... JRA.
+#
+
+AC_CACHE_CHECK([for int16 typedef included by rpc/rpc.h],samba_cv_HAVE_INT16_FROM_RPC_RPC_H,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#if defined(HAVE_RPC_RPC_H)
+#include <rpc/rpc.h>
+#endif],
+[int16 testvar;],
+samba_cv_HAVE_INT16_FROM_RPC_RPC_H=yes,samba_cv_HAVE_INT16_FROM_RPC_RPC_H=no)])
+if test x"$samba_cv_HAVE_INT16_FROM_RPC_RPC_H" = x"yes"; then
+ AC_DEFINE(HAVE_INT16_FROM_RPC_RPC_H,1,[Whether int16 typedef is included by rpc/rpc.h])
+fi
+
+AC_CACHE_CHECK([for uint16 typedef included by rpc/rpc.h],samba_cv_HAVE_UINT16_FROM_RPC_RPC_H,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#if defined(HAVE_RPC_RPC_H)
+#include <rpc/rpc.h>
+#endif],
+[uint16 testvar;],
+samba_cv_HAVE_UINT16_FROM_RPC_RPC_H=yes,samba_cv_HAVE_UINT16_FROM_RPC_RPC_H=no)])
+if test x"$samba_cv_HAVE_UINT16_FROM_RPC_RPC_H" = x"yes"; then
+ AC_DEFINE(HAVE_UINT16_FROM_RPC_RPC_H,1,[Whether uint16 typedef is included by rpc/rpc.h])
+fi
+
+AC_CACHE_CHECK([for int32 typedef included by rpc/rpc.h],samba_cv_HAVE_INT32_FROM_RPC_RPC_H,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#if defined(HAVE_RPC_RPC_H)
+#include <rpc/rpc.h>
+#endif],
+[int32 testvar;],
+samba_cv_HAVE_INT32_FROM_RPC_RPC_H=yes,samba_cv_HAVE_INT32_FROM_RPC_RPC_H=no)])
+if test x"$samba_cv_HAVE_INT32_FROM_RPC_RPC_H" = x"yes"; then
+ AC_DEFINE(HAVE_INT32_FROM_RPC_RPC_H,1,[Whether int32 typedef is included by rpc/rpc.h])
+fi
+
+AC_CACHE_CHECK([for uint32 typedef included by rpc/rpc.h],samba_cv_HAVE_UINT32_FROM_RPC_RPC_H,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#if defined(HAVE_RPC_RPC_H)
+#include <rpc/rpc.h>
+#endif],
+[uint32 testvar;],
+samba_cv_HAVE_UINT32_FROM_RPC_RPC_H=yes,samba_cv_HAVE_UINT32_FROM_RPC_RPC_H=no)])
+if test x"$samba_cv_HAVE_UINT32_FROM_RPC_RPC_H" = x"yes"; then
+ AC_DEFINE(HAVE_UINT32_FROM_RPC_RPC_H,1,[Whether uint32 typedef is included by rpc/rpc.h])
+fi
+
+dnl
+dnl Some systems (SCO) have a problem including
+dnl <prot.h> and <rpc/rpc.h> due to AUTH_ERROR being defined
+dnl as a #define in <prot.h> and as part of an enum
+dnl in <rpc/rpc.h>.
+dnl
+
+AC_CACHE_CHECK([for conflicting AUTH_ERROR define in rpc/rpc.h],samba_cv_HAVE_RPC_AUTH_ERROR_CONFLICT,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#ifdef HAVE_SYS_SECURITY_H
+#include <sys/security.h>
+#include <prot.h>
+#endif /* HAVE_SYS_SECURITY_H */
+#if defined(HAVE_RPC_RPC_H)
+#include <rpc/rpc.h>
+#endif],
+[int testvar;],
+samba_cv_HAVE_RPC_AUTH_ERROR_CONFLICT=no,samba_cv_HAVE_RPC_AUTH_ERROR_CONFLICT=yes)])
+if test x"$samba_cv_HAVE_RPC_AUTH_ERROR_CONFLICT" = x"yes"; then
+ AC_DEFINE(HAVE_RPC_AUTH_ERROR_CONFLICT,1,[Whether there is a conflicting AUTH_ERROR define in rpc/rpc.h])
+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,1,[Truncate 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,1,[Whether getgroups is broken])
+fi
+
+SMB_CHECK_SYSCONF(_SC_NGROUPS_MAX)
+SMB_CHECK_SYSCONF(_SC_NPROC_ONLN)
+SMB_CHECK_SYSCONF(_SC_NPROCESSORS_ONLN)
+SMB_CHECK_SYSCONF(_SC_PAGESIZE)
+AC_CHECK_FUNCS(getpagesize)
+
+################################################
+# look for a method of setting the effective uid
+seteuid=no;
+
+if test $seteuid = no; then
+AC_CACHE_CHECK([for setreuid],samba_cv_USE_SETREUID,[
+AC_TRY_RUN([
+#define AUTOCONF_TEST 1
+#define USE_SETREUID 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/util_sec.c"],
+ samba_cv_USE_SETREUID=yes,samba_cv_USE_SETREUID=no,samba_cv_USE_SETREUID=cross)])
+if test x"$samba_cv_USE_SETREUID" = x"yes"; then
+ seteuid=yes;AC_DEFINE(USE_SETREUID,1,[Whether setreuid() is available])
+fi
+fi
+
+# we check for setresuid second as it conflicts with AIO on Linux.
+# see http://samba.org/~tridge/junkcode/aio_uid.c
+if test $seteuid = no; then
+AC_CACHE_CHECK([for setresuid],samba_cv_USE_SETRESUID,[
+AC_TRY_RUN([
+#define AUTOCONF_TEST 1
+#define USE_SETRESUID 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/util_sec.c"],
+ samba_cv_USE_SETRESUID=yes,samba_cv_USE_SETRESUID=no,samba_cv_USE_SETRESUID=cross)])
+if test x"$samba_cv_USE_SETRESUID" = x"yes"; then
+ seteuid=yes;AC_DEFINE(USE_SETRESUID,1,[Whether setresuid() is available])
+fi
+fi
+
+if test $seteuid = no; then
+AC_CACHE_CHECK([for seteuid],samba_cv_USE_SETEUID,[
+AC_TRY_RUN([
+#define AUTOCONF_TEST 1
+#define USE_SETEUID 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/util_sec.c"],
+ samba_cv_USE_SETEUID=yes,samba_cv_USE_SETEUID=no,samba_cv_USE_SETEUID=cross)])
+if test x"$samba_cv_USE_SETEUID" = x"yes"; then
+ seteuid=yes;AC_DEFINE(USE_SETEUID,1,[Whether seteuid() is available])
+fi
+fi
+
+if test $seteuid = no; then
+AC_CACHE_CHECK([for setuidx],samba_cv_USE_SETUIDX,[
+AC_TRY_RUN([
+#define AUTOCONF_TEST 1
+#define USE_SETUIDX 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/util_sec.c"],
+ samba_cv_USE_SETUIDX=yes,samba_cv_USE_SETUIDX=no,samba_cv_USE_SETUIDX=cross)])
+if test x"$samba_cv_USE_SETUIDX" = x"yes"; then
+ seteuid=yes;AC_DEFINE(USE_SETUIDX,1,[Whether setuidx() is available])
+fi
+fi
+
+AC_CACHE_CHECK([for the Darwin initgroups system call],
+ samba_cv_DARWIN_INITGROUPS,
+ AC_TRY_LINK([
+#include <sys/syscall.h>
+#include <unistd.h>
+ ],
+ [ syscall(SYS_initgroups, 16, NULL, NULL, 0); ],
+ samba_cv_DARWIN_INITGROUPS=yes,
+ samba_cv_DARWIN_INITGROUPS=no)
+)
+
+if test x"$samba_cv_DARWIN_INITGROUPS" = x"yes" ; then
+ AC_DEFINE(HAVE_DARWIN_INITGROUPS, 1,
+ [Whether to use the Darwin-specific initgroups system call])
+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,1,[Whether fcntl locking is available])
+fi
+
+AC_CACHE_CHECK([for broken (glibc2.1/x86) 64 bit fcntl locking],samba_cv_HAVE_BROKEN_FCNTL64_LOCKS,[
+AC_TRY_RUN([#include "${srcdir-.}/tests/fcntl_lock64.c"],
+ samba_cv_HAVE_BROKEN_FCNTL64_LOCKS=yes,samba_cv_HAVE_BROKEN_FCNTL64_LOCKS=no,samba_cv_HAVE_BROKEN_FCNTL64_LOCKS=cross)])
+if test x"$samba_cv_HAVE_BROKEN_FCNTL64_LOCKS" = x"yes"; then
+ AC_DEFINE(HAVE_BROKEN_FCNTL64_LOCKS,1,[Whether fcntl64 locks are broken])
+
+else
+
+dnl
+dnl Don't check for 64 bit fcntl locking if we know that the
+dnl glibc2.1 broken check has succeeded.
+dnl
+
+ AC_CACHE_CHECK([for 64 bit fcntl locking],samba_cv_HAVE_STRUCT_FLOCK64,[
+ AC_TRY_RUN([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_FCNTL_H
+#include <sys/fcntl.h>
+#endif
+main() { struct flock64 fl64;
+#if defined(F_SETLKW64) && defined(F_SETLK64) && defined(F_GETLK64)
+exit(0);
+#else
+exit(1);
+#endif
+}],
+ samba_cv_HAVE_STRUCT_FLOCK64=yes,samba_cv_HAVE_STRUCT_FLOCK64=no,samba_cv_HAVE_STRUCT_FLOCK64=cross)])
+
+ if test x"$samba_cv_HAVE_STRUCT_FLOCK64" = x"yes"; then
+ AC_DEFINE(HAVE_STRUCT_FLOCK64,1,[Whether the flock64 struct is available])
+ fi
+fi
+
+AC_CACHE_CHECK([for st_blocks in struct stat],samba_cv_HAVE_STAT_ST_BLOCKS,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>],
+[struct stat st; st.st_blocks = 0;],
+samba_cv_HAVE_STAT_ST_BLOCKS=yes,samba_cv_HAVE_STAT_ST_BLOCKS=no,samba_cv_HAVE_STAT_ST_BLOCKS=cross)])
+if test x"$samba_cv_HAVE_STAT_ST_BLOCKS" = x"yes"; then
+ AC_DEFINE(HAVE_STAT_ST_BLOCKS,1,[Whether the stat struct has a st_block property])
+fi
+
+AC_CACHE_CHECK([for st_blksize in struct stat],samba_cv_HAVE_STAT_ST_BLKSIZE,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>],
+[struct stat st; st.st_blksize = 0;],
+samba_cv_HAVE_STAT_ST_BLKSIZE=yes,samba_cv_HAVE_STAT_ST_BLKSIZE=no,samba_cv_HAVE_STAT_ST_BLKSIZE=cross)])
+if test x"$samba_cv_HAVE_STAT_ST_BLKSIZE" = x"yes"; then
+ AC_DEFINE(HAVE_STAT_ST_BLKSIZE,1,[Whether the stat struct has a st_blksize property])
+fi
+
+AC_CACHE_CHECK([for st_flags in struct stat],
+ samba_cv_HAVE_STAT_ST_FLAGS,
+ [
+ AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>],
+ [struct stat st; st.st_flags = 0;],
+ samba_cv_HAVE_STAT_ST_FLAGS=yes,
+ samba_cv_HAVE_STAT_ST_FLAGS=no,
+ samba_cv_HAVE_STAT_ST_FLAGS=cross)
+ ])
+
+if test x"$samba_cv_HAVE_STAT_ST_FLAGS" = x"yes"; then
+ AC_DEFINE(HAVE_STAT_ST_FLAGS, 1,
+ [Whether the stat struct has a st_flags member])
+fi
+
+AC_CACHE_CHECK([for broken nisplus include files],samba_cv_BROKEN_NISPLUS_INCLUDE_FILES,[
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/acl.h>
+#if defined(HAVE_RPCSVC_NIS_H)
+#include <rpcsvc/nis.h>
+#endif],
+[int i;],
+samba_cv_BROKEN_NISPLUS_INCLUDE_FILES=no,samba_cv_BROKEN_NISPLUS_INCLUDE_FILES=yes)])
+if test x"$samba_cv_BROKEN_NISPLUS_INCLUDE_FILES" = x"yes"; then
+ AC_DEFINE(BROKEN_NISPLUS_INCLUDE_FILES,1,[Whether the nisplus include files are broken])
+fi
+
+AC_CACHE_CHECK([if the realpath function allows a NULL argument],samba_cv_REALPATH_TAKES_NULL,[
+AC_TRY_RUN([
+#include <stdio.h>
+#include <limits.h>
+#include <signal.h>
+
+void exit_on_core(int ignored) {
+ exit(1);
+}
+
+main() {
+ char *newpath;
+ signal(SIGSEGV, exit_on_core);
+ newpath = realpath("/tmp", NULL);
+ exit((newpath != NULL) ? 0 : 1);
+}
+],
+samba_cv_REALPATH_TAKES_NULL=yes,samba_cv_REALPATH_TAKES_NULL=no,samba_cv_REALPATH_TAKES_NULL=cross)])
+if test x"$samba_cv_REALPATH_TAKES_NULL" = x"yes"; then
+ AC_DEFINE(REALPATH_TAKES_NULL,1,[Whether the realpath function allows NULL])
+fi
+
+#################################################
+# check for AFS clear-text auth support
+samba_cv_WITH_AFS=no
+AC_MSG_CHECKING(whether to use AFS clear-text auth)
+AC_ARG_WITH(afs,
+[AS_HELP_STRING([--with-afs], [Include AFS clear-text auth support (default=no)])],
+[ case "$withval" in
+ yes|auto)
+ AC_MSG_RESULT($withval)
+ samba_cv_WITH_AFS=$withval
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+####################################################
+# check for Linux-specific AFS fake-kaserver support
+samba_cv_WITH_FAKE_KASERVER=no
+AC_MSG_CHECKING(whether to use AFS fake-kaserver)
+AC_ARG_WITH(fake-kaserver,
+[AS_HELP_STRING([--with-fake-kaserver], [Include AFS fake-kaserver support (default=no)])],
+[ case "$withval" in
+ yes|auto)
+ AC_MSG_RESULT($withval)
+ samba_cv_WITH_FAKE_KASERVER=$withval
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# decide whether we can support WITH_AFS and / or WITH_FAKE_KASERVER
+if test x"$samba_cv_WITH_AFS" != x"no" ||
+ test x"$samba_cv_WITH_FAKE_KASERVER" != x"no"; then
+
+ # see if this box has the afs-headers in /usr/include/afs
+ AC_MSG_CHECKING(for /usr/include/afs)
+ if test -d /usr/include/afs; then
+ CFLAGS="$CFLAGS -I/usr/include/afs"
+ CPPFLAGS="$CPPFLAGS -I/usr/include/afs"
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ fi
+
+ # check for afs.h
+ have_afs_headers=no
+ AC_CHECK_HEADERS(afs.h afs/afs.h)
+ if test x"$ac_cv_header_afs_h" = x"no" && test x"$ac_cv_header_afs_afs_h" = x"no"; then
+ if test x"$samba_cv_WITH_FAKE_KASERVER" = x"auto" ||
+ test x"$samba_cv_WITH_AFS" = x"auto"; then
+ AC_MSG_WARN([AFS cannot be supported without afs.h])
+ else
+ AC_MSG_ERROR([AFS cannot be supported without afs.h])
+ fi
+ else
+ have_afs_headers=yes
+ fi
+fi
+
+FAKE_KASERVER_OBJ=""
+if test x"$samba_cv_WITH_FAKE_KASERVER" != x"no" && test x"$have_afs_headers" = x"yes"; then
+ AC_DEFINE(WITH_FAKE_KASERVER,1,[Whether to include AFS fake-kaserver support])
+ FAKE_KASERVER_OBJ="utils/net_afs.o"
+fi
+AC_SUBST(FAKE_KASERVER_OBJ)
+
+#################################################
+# check whether to compile AFS/NT ACL mapping module
+samba_cv_WITH_VFS_AFSACL=no
+AC_MSG_CHECKING(whether to use AFS ACL mapping module)
+AC_ARG_WITH(vfs-afsacl,
+[AS_HELP_STRING([--with-vfs-afsacl], [Include AFS to NT ACL mapping module (default=no)])],
+[ case "$withval" in
+ yes|auto)
+ AC_MSG_RESULT($withval)
+ samba_cv_WITH_VFS_AFSACL=yes
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+if test x"$samba_cv_WITH_VFS_AFSACL" = x"yes"; then
+ default_shared_modules="$default_shared_modules vfs_afsacl"
+fi
+
+if test x"$samba_cv_WITH_AFS" != x"no" && test x"$have_afs_headers" = x"yes"; then
+ AC_DEFINE(WITH_AFS,1,[Whether to include AFS clear-text auth support])
+fi
+
+#################################################
+# check for the DFS clear-text auth system
+AC_MSG_CHECKING(whether to use DFS clear-text auth)
+AC_ARG_WITH(dfs,
+[AS_HELP_STRING([--with-dce-dfs], [Include DCE/DFS clear-text auth support (default=no)])],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_DFS,1,[Whether to include DFS support])
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+########################################################
+# Compile with LDAP support?
+
+with_ldap_support=auto
+AC_MSG_CHECKING([for LDAP support])
+
+AC_ARG_WITH(ldap,
+[AS_HELP_STRING([--with-ldap], [LDAP support (default yes)])],
+[ case "$withval" in
+ yes|no)
+ with_ldap_support=$withval
+ ;;
+ esac ])
+
+AC_MSG_RESULT($with_ldap_support)
+
+SMBLDAP=""
+AC_SUBST(SMBLDAP)
+SMBLDAPUTIL=""
+AC_SUBST(SMBLDAPUTIL)
+LDBLDAP=""
+AC_SUBST(LDBLDAP)
+
+if test x"$with_ldap_support" != x"no"; then
+
+ ##################################################################
+ # first test for ldap.h and lber.h
+ # (ldap.h is required for this test)
+ AC_CHECK_HEADERS(ldap.h lber.h)
+
+ if test x"$ac_cv_header_ldap_h" != x"yes"; then
+ if test x"$with_ldap_support" = x"yes"; then
+ AC_MSG_ERROR(ldap.h is needed for LDAP support)
+ else
+ AC_MSG_WARN(ldap.h is needed for LDAP support)
+ fi
+
+ with_ldap_support=no
+ fi
+
+ ##################################################################
+ # HP/UX does not have ber_tag_t in lber.h - it must be configured as
+ # unsigned int in include/includes.h
+ case $host_os in
+ *hpux*)
+ AC_MSG_WARN(ber_tag_t is needed for LDAP support)
+ AC_MSG_WARN(ber_tag_t must be configured in includes.h for hpux)
+ with_ldap_support=yes
+ ;;
+ *)
+ AC_CHECK_TYPE(ber_tag_t,,,[#include <lber.h>])
+ if test x"$ac_cv_type_ber_tag_t" != x"yes"; then
+ if test x"$with_ldap_support" = x"yes"; then
+ AC_MSG_ERROR(ber_tag_t is needed for LDAP support)
+ else
+ AC_MSG_WARN(ber_tag_t is needed for LDAP support)
+ fi
+ with_ldap_support=no
+ fi
+ ;;
+ esac
+fi
+
+if test x"$with_ldap_support" != x"no"; then
+ ac_save_LIBS=$LIBS
+
+ ##################################################################
+ # we might need the lber lib on some systems. To avoid link errors
+ # this test must be before the libldap test
+ AC_CHECK_LIB_EXT(lber, LDAP_LIBS, ber_scanf)
+
+ ########################################################
+ # If ber_sockbuf_add_io() is available we can add
+ # SASL wrapping hooks
+ AC_CHECK_FUNC_EXT(ber_sockbuf_add_io,$LDAP_LIBS)
+
+ AC_CACHE_CHECK([for LDAP_OPT_SOCKBUF],samba_cv_HAVE_LDAP_OPT_SOCKBUF,[
+ AC_TRY_COMPILE([#include <ldap.h>],
+ [int val = LDAP_OPT_SOCKBUF;],
+ samba_cv_HAVE_LDAP_OPT_SOCKBUF=yes,
+ samba_cv_HAVE_LDAP_OPT_SOCKBUF=no)])
+
+ if test x"$ac_cv_func_ext_ber_sockbuf_add_io" = x"yes" -a \
+ x"$samba_cv_HAVE_LDAP_OPT_SOCKBUF" = x"yes"; then
+ AC_DEFINE(HAVE_LDAP_SASL_WRAPPING, 1, [Support for SASL wrapping])
+ fi
+
+ #######################################################
+ # if we have LBER_OPT_LOG_PRINT_FN, we can intercept
+ # ldap logging and print it out in the samba logs
+ AC_CACHE_CHECK([for LBER_OPT_LOG_PRINT_FN],
+ samba_cv_HAVE_LBER_OPT_LOG_PRINT_FN,
+ [AC_TRY_COMPILE([#include <lber.h>],
+ [int val = LBER_OPT_LOG_PRINT_FN;],
+ samba_cv_HAVE_LBER_OPT_LOG_PRINT_FN=yes,
+ samba_cv_HAVE_LBER_OPT_LOG_PRINT_FN=no)])
+
+ if test x"$samba_cv_HAVE_LBER_OPT_LOG_PRINT_FN" = x"yes"; then
+ AC_DEFINE(HAVE_LBER_LOG_PRINT_FN, 1,
+ [Support for LDAP/LBER logging interception])
+ fi
+
+ ########################################################
+ # now see if we can find the ldap libs in standard paths
+ AC_CHECK_LIB_EXT(ldap, LDAP_LIBS, ldap_init)
+
+ ########################################################
+ # If we have LDAP, does it's rebind procedure take 2 or 3 arguments?
+ # Check found in pam_ldap 145.
+ AC_CHECK_FUNC_EXT(ldap_set_rebind_proc,$LDAP_LIBS)
+
+ LIBS="$LIBS $LDAP_LIBS"
+ AC_CACHE_CHECK(whether ldap_set_rebind_proc takes 3 arguments, smb_ldap_cv_ldap_set_rebind_proc, [
+ AC_TRY_COMPILE([
+ #include <lber.h>
+ #include <ldap.h>],
+ [ldap_set_rebind_proc(0, 0, 0);],
+ [smb_ldap_cv_ldap_set_rebind_proc=3],
+ [smb_ldap_cv_ldap_set_rebind_proc=2]
+ )
+ ])
+
+ AC_DEFINE_UNQUOTED(LDAP_SET_REBIND_PROC_ARGS, $smb_ldap_cv_ldap_set_rebind_proc, [Number of arguments to ldap_set_rebind_proc])
+
+ AC_CHECK_FUNC_EXT(ldap_initialize,$LDAP_LIBS)
+
+ if test x"$ac_cv_lib_ext_ldap_ldap_init" = x"yes"; then
+ AC_DEFINE(HAVE_LDAP,1,[Whether ldap is available])
+ CPPFLAGS="$CPPFLAGS -DLDAP_DEPRECATED"
+ default_static_modules="$default_static_modules pdb_ldap idmap_ldap";
+ default_shared_modules="$default_shared_modules";
+ SMBLDAP="lib/smbldap.o"
+ SMBLDAPUTIL="lib/smbldap_util.o"
+ with_ldap_support=yes
+ AC_MSG_CHECKING(whether LDAP support is used)
+ AC_MSG_RESULT(yes)
+ else
+ if test x"$with_ldap_support" = x"yes"; then
+ AC_MSG_ERROR(libldap is needed for LDAP support)
+ else
+ AC_MSG_WARN(libldap is needed for LDAP support)
+ fi
+
+ LDAP_LIBS=""
+ with_ldap_support=no
+ fi
+ LIBS=$ac_save_LIBS
+fi
+
+
+#################################################
+# active directory support
+
+with_ads_support=auto
+AC_MSG_CHECKING([for Active Directory and krb5 support])
+
+AC_ARG_WITH(ads,
+[AS_HELP_STRING([--with-ads], [Active Directory support (default auto)])],
+[ case "$withval" in
+ yes|no)
+ with_ads_support="$withval"
+ ;;
+ esac ])
+
+AC_MSG_RESULT($with_ads_support)
+
+FOUND_KRB5=no
+KRB5_LIBS=""
+
+if test x"$with_ldap_support" != x"yes"; then
+
+ if test x"$with_ads_support" = x"yes"; then
+ AC_MSG_ERROR(Active Directory Support requires LDAP support)
+ elif test x"$with_ads_support" = x"auto"; then
+ AC_MSG_WARN(Disabling Active Directory support (requires LDAP support))
+ with_ads_support=no
+ fi
+
+else
+
+ # Check to see whether there is enough LDAP functionality to be able
+ # to build AD support.
+
+# HPUX only has ldap_init; ok, we take care of this in smbldap.c
+case "$host_os" in
+ *hpux*)
+ AC_CHECK_FUNC_EXT(ldap_init,$LDAP_LIBS)
+
+ if test x"$ac_cv_func_ext_ldap_init" != x"yes"; then
+ if test x"$with_ads_support" = x"yes"; then
+ AC_MSG_ERROR(Active Directory support on HPUX requires ldap_init)
+ elif test x"$with_ads_support" = x"auto"; then
+ AC_MSG_WARN(Disabling Active Directory support (requires ldap_init on HPUX))
+ with_ads_support=no
+ fi
+ fi
+ ;;
+ *)
+ AC_CHECK_FUNC_EXT(ldap_initialize,$LDAP_LIBS)
+
+ if test x"$ac_cv_func_ext_ldap_initialize" != x"yes"; then
+ if test x"$with_ads_support" = x"yes"; then
+ AC_MSG_ERROR(Active Directory support requires ldap_initialize)
+ elif test x"$with_ads_support" = x"auto"; then
+ AC_MSG_WARN(Disabling Active Directory support (requires ldap_initialize))
+ with_ads_support=no
+ fi
+ fi
+ ;;
+esac
+
+
+ AC_CHECK_FUNC_EXT(ldap_add_result_entry,$LDAP_LIBS)
+
+ if test x"$ac_cv_func_ext_ldap_add_result_entry" != x"yes"; then
+ if test x"$with_ads_support" = x"yes"; then
+ AC_MSG_ERROR(Active Directory support requires ldap_add_result_entry)
+ elif test x"$with_ads_support" = x"auto"; then
+ AC_MSG_WARN(Disabling Active Directory support (requires ldap_add_result_entry))
+ with_ads_support=no
+ fi
+ fi
+
+fi
+
+if test x"$with_ads_support" != x"no"; then
+
+ # Do no harm to the values of CFLAGS and LIBS while testing for
+ # Kerberos support.
+
+ if test x$FOUND_KRB5 = x"no"; then
+ #################################################
+ # check for location of Kerberos 5 install
+ AC_MSG_CHECKING(for kerberos 5 install path)
+ AC_ARG_WITH(krb5,
+ [AS_HELP_STRING([--with-krb5=base-dir], [Locate Kerberos 5 support (default=/usr)])],
+ [ case "$withval" in
+ no)
+ AC_MSG_RESULT(no krb5-path given)
+ ;;
+ yes)
+ AC_MSG_RESULT(/usr)
+ FOUND_KRB5=yes
+ ;;
+ *)
+ AC_MSG_RESULT($withval)
+ KRB5_CFLAGS="-I$withval/include"
+ KRB5_CPPFLAGS="-I$withval/include"
+ KRB5_LDFLAGS="-L$withval/lib"
+ FOUND_KRB5=yes
+ if test -x "$withval/bin/krb5-config"; then
+ KRB5CONFIG=$withval/bin/krb5-config
+ fi
+ ;;
+ esac ],
+ AC_MSG_RESULT(no krb5-path given)
+ )
+ fi
+
+ #################################################
+ # check for krb5-config from recent MIT and Heimdal kerberos 5
+ AC_PATH_PROG(KRB5CONFIG, krb5-config)
+ AC_MSG_CHECKING(for working krb5-config)
+ if test -x "$KRB5CONFIG"; then
+ ac_save_CFLAGS=$CFLAGS
+ CFLAGS="";export CFLAGS
+ ac_save_LDFLAGS=$LDFLAGS
+ LDFLAGS="";export LDFLAGS
+ KRB5_LIBS="`$KRB5CONFIG --libs gssapi`"
+ KRB5_LDFLAGS="`$KRB5CONFIG --libs gssapi | sed s/-lgss.*//`"
+ KRB5_CFLAGS="`$KRB5CONFIG --cflags | sed s/@INCLUDE_des@//`"
+ KRB5_CPPFLAGS="`$KRB5CONFIG --cflags | sed s/@INCLUDE_des@//`"
+ CFLAGS=$ac_save_CFLAGS;export CFLAGS
+ LDFLAGS=$ac_save_LDFLAGS;export LDFLAGS
+ FOUND_KRB5=yes
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no. Fallback to previous krb5 detection strategy)
+ fi
+
+ if test x$FOUND_KRB5 = x"no"; then
+ #################################################
+ # see if this box has the SuSE location for the heimdal krb implementation
+ AC_MSG_CHECKING(for /usr/include/heimdal)
+ if test -d /usr/include/heimdal; then
+ if test -f /usr/lib/heimdal/lib/libkrb5.a; then
+ KRB5_CFLAGS="-I/usr/include/heimdal"
+ KRB5_CPPFLAGS="-I/usr/include/heimdal"
+ KRB5_LDFLAGS="-L/usr/lib/heimdal/lib"
+ FOUND_KRB5=yes
+ AC_MSG_RESULT(yes)
+ else
+ KRB5_CFLAGS="-I/usr/include/heimdal"
+ KRB5_CPPFLAGS="-I/usr/include/heimdal"
+ FOUND_KRB5=yes
+ AC_MSG_RESULT(yes)
+ fi
+ else
+ AC_MSG_RESULT(no)
+ fi
+ fi
+
+ if test x$FOUND_KRB5 = x"no"; then
+ #################################################
+ # see if this box has the RedHat location for kerberos
+ AC_MSG_CHECKING(for /usr/kerberos)
+ if test -d /usr/kerberos -a -f /usr/kerberos/lib/libkrb5.a; then
+ KRB5_LDFLAGS="-L/usr/kerberos/lib"
+ KRB5_CFLAGS="-I/usr/kerberos/include"
+ KRB5_CPPFLAGS="-I/usr/kerberos/include"
+ FOUND_KRB5=yes
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ fi
+ fi
+
+ if test x$FOUND_KRB5 = x"no"; then
+ #################################################
+ # see if this box has the OpenBSD location for heimdal krb5
+ AC_MSG_CHECKING(for /usr/include/kerberosV)
+ if test -d /usr/include/kerberosV; then
+ KRB5_CPPFLAGS="-I/usr/include/kerberosV"
+ KRB5_LIBS="-lcrypto"
+ FOUND_KRB5=yes
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ fi
+ fi
+
+ ac_save_CFLAGS=$CFLAGS
+ ac_save_CPPFLAGS=$CPPFLAGS
+ ac_save_LDFLAGS=$LDFLAGS
+
+ CFLAGS="$KRB5_CFLAGS $CFLAGS"
+ CPPFLAGS="$KRB5_CPPFLAGS $CPPFLAGS"
+ LDFLAGS="$KRB5_LDFLAGS $LDFLAGS"
+
+ KRB5_LIBS="$KRB5_LDFLAGS $KRB5_LIBS"
+
+ # now check for krb5.h. Some systems have the libraries without the headers!
+ # note that this check is done here to allow for different kerberos
+ # include paths
+ AC_CHECK_HEADERS(krb5.h)
+
+ if test x"$ac_cv_header_krb5_h" = x"no"; then
+
+ # Give a warning if AD support was not explicitly requested,
+ # i.e with_ads_support = auto, otherwise die with an error.
+
+ if test x"$with_ads_support" = x"yes"; then
+ AC_MSG_ERROR([Active Directory cannot be supported without krb5.h])
+ else
+ AC_MSG_WARN([Active Directory cannot be supported without krb5.h])
+ fi
+
+ # Turn off AD support and restore CFLAGS and LIBS variables
+
+ with_ads_support="no"
+
+ CFLAGS=$ac_save_CFLAGS
+ CPPFLAGS=$ac_save_CPPFLAGS
+ LDFLAGS=$ac_save_LDFLAGS
+ fi
+ AC_CHECK_HEADERS(krb5/locate_plugin.h)
+ if test x"$ac_cv_header_krb5_locate_plugin_h" = x"yes"; then
+ WINBIND_KRB5_LOCATOR="bin/winbind_krb5_locator.$SHLIBEXT"
+ EXTRA_ALL_TARGETS="$EXTRA_ALL_TARGETS $WINBIND_KRB5_LOCATOR"
+ fi
+fi
+
+# Now we have determined whether we really want ADS support
+use_ads=no
+if test x"$with_ads_support" != x"no"; then
+ use_ads=yes
+ have_gssapi=no
+ ac_save_LIBS=$LIBS
+
+ # now check for gssapi headers. This is also done here to allow for
+ # different kerberos include paths
+ AC_CHECK_HEADERS(gssapi.h gssapi/gssapi_generic.h gssapi/gssapi.h com_err.h)
+
+ ##################################################################
+ # we might need the k5crypto and com_err libraries on some systems
+ AC_CHECK_LIB_EXT(com_err, KRB5_LIBS, _et_list)
+ AC_CHECK_LIB_EXT(k5crypto, KRB5_LIBS, krb5_encrypt_data)
+
+ # Heimdal checks.
+ AC_CHECK_LIB_EXT(crypto, KRB5_LIBS, des_set_key)
+ AC_CHECK_LIB_EXT(asn1, KRB5_LIBS, copy_Authenticator)
+ AC_CHECK_LIB_EXT(roken, KRB5_LIBS, roken_getaddrinfo_hostspec)
+
+ # Heimdal checks. On static Heimdal gssapi must be linked before krb5.
+ AC_CHECK_LIB_EXT(gssapi, KRB5_LIBS, gss_display_status,[],[],have_gssapi=yes)
+
+ ########################################################
+ # now see if we can find the krb5 libs in standard paths
+ # or as specified above
+ AC_CHECK_LIB_EXT(krb5, KRB5_LIBS, krb5_mk_req_extended)
+ AC_CHECK_LIB_EXT(krb5, KRB5_LIBS, krb5_kt_compare)
+
+ ########################################################
+ # now see if we can find the gssapi libs in standard paths
+ if test x"$have_gssapi" != x"yes"; then
+ AC_CHECK_LIB_EXT(gssapi_krb5, KRB5_LIBS,gss_display_status,[],[],have_gssapi=yes)
+ fi
+
+ AC_CHECK_FUNC_EXT(krb5_set_real_time, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_set_default_in_tkt_etypes, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_set_default_tgs_enctypes, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_set_default_tgs_ktypes, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_principal2salt, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_use_enctype, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_string_to_key, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_get_pw_salt, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_string_to_key_salt, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_auth_con_setkey, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_auth_con_setuseruserkey, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_locate_kdc, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_get_permitted_enctypes, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_get_default_in_tkt_etypes, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_free_data_contents, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_principal_get_comp_string, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_free_unparsed_name, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_free_keytab_entry_contents, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_kt_free_entry, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_krbhst_init, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_krbhst_get_addrinfo, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_c_enctype_compare, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_enctypes_compatible_keys, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_crypto_init, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_crypto_destroy, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_decode_ap_req, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(free_AP_REQ, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_verify_checksum, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_c_verify_checksum, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_principal_compare_any_realm, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_parse_name_norealm, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_princ_size, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_get_init_creds_opt_set_pac_request, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_get_renewed_creds, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_get_kdc_cred, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_free_error_contents, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(initialize_krb5_error_table, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_get_init_creds_opt_alloc, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_get_init_creds_opt_free, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_get_init_creds_opt_get_error, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_enctype_to_string, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_fwd_tgt_creds, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_auth_con_set_req_cksumtype, $KRB5_LIBS)
+
+ LIBS="$KRB5_LIBS $LIBS"
+
+ AC_CACHE_CHECK(whether krb5_ticket contains kvno and enctype,
+ smb_krb5_cv_ticket_has_keyinfo,
+ [
+ AC_TRY_COMPILE(
+ [
+ #include <krb5.h>
+ ],
+ [
+ krb5_ticket ticket;
+ krb5_kvno kvno;
+ krb5_enctype enctype;
+
+ enctype = ticket.enc_part.enctype;
+ kvno = ticket.enc_part.kvno;
+ ],
+ [ smb_krb5_cv_ticket_has_keyinfo=yes ],
+ [ smb_krb5_cv_ticket_has_keyinfo=no ])
+ ])
+
+ if test x"$smb_krb5_cv_ticket_has_keyinfo" = x"yes" ; then
+ AC_DEFINE(KRB5_TICKET_HAS_KEYINFO, 1,
+ [Whether the krb5_ticket structure contains the kvno and enctype])
+ fi
+
+ AC_CACHE_CHECK(whether krb5_get_init_creds_opt_free takes a context argument,
+ smb_krb5_cv_creds_opt_free_context,
+ [
+ AC_TRY_COMPILE([
+ #include <krb5.h>],
+ [
+ krb5_context ctx;
+ krb5_get_init_creds_opt *opt = NULL;
+ krb5_get_init_creds_opt_free(ctx, opt);
+ ],
+ [smb_krb5_cv_creds_opt_free_context=yes],
+ [smb_krb5_cv_creds_opt_free_context=no]
+ )
+ ])
+
+ if test x"$smb_krb5_cv_creds_opt_free_context" = x"yes" ; then
+ AC_DEFINE(KRB5_CREDS_OPT_FREE_REQUIRES_CONTEXT, 1,
+ [Whether krb5_get_init_creds_opt_free takes a context argument])
+ fi
+
+ AC_CACHE_CHECK(whether krb5_verify_checksum takes 7 arguments, smb_krb5_cv_verify_checksum, [
+ AC_TRY_COMPILE([
+ #include <krb5.h>],
+ [krb5_verify_checksum(0, 0, 0, 0, 0, 0, 0);],
+ [smb_krb5_cv_verify_checksum=7],
+ [smb_krb5_cv_verify_checksum=6],
+ )
+ ])
+ AC_DEFINE_UNQUOTED(KRB5_VERIFY_CHECKSUM_ARGS, $smb_krb5_cv_verify_checksum, [Number of arguments to krb5_verify_checksum])
+
+ AC_CACHE_CHECK([for checksum in krb5_checksum],
+ samba_cv_HAVE_CHECKSUM_IN_KRB5_CHECKSUM,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_checksum cksum; cksum.checksum.length = 0;],
+ samba_cv_HAVE_CHECKSUM_IN_KRB5_CHECKSUM=yes,
+ samba_cv_HAVE_CHECKSUM_IN_KRB5_CHECKSUM=no)])
+
+ if test x"$samba_cv_HAVE_CHECKSUM_IN_KRB5_CHECKSUM" = x"yes"; then
+ AC_DEFINE(HAVE_CHECKSUM_IN_KRB5_CHECKSUM,1,
+ [Whether the krb5_checksum struct has a checksum property])
+ fi
+
+ AC_CACHE_CHECK([for etype in EncryptedData],
+ samba_cv_HAVE_ETYPE_IN_ENCRYPTEDDATA,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [EncryptedData edata; edata.etype = 0;],
+ samba_cv_HAVE_ETYPE_IN_ENCRYPTEDDATA=yes,
+ samba_cv_HAVE_ETYPE_IN_ENCRYPTEDDATA=no)])
+
+ if test x"$samba_cv_HAVE_ETYPE_IN_ENCRYPTEDDATA" = x"yes"; then
+ AC_DEFINE(HAVE_ETYPE_IN_ENCRYPTEDDATA,1,
+ [Whether the EncryptedData struct has a etype property])
+ fi
+
+ AC_CACHE_CHECK([for ticket pointer in krb5_ap_req],
+ samba_cv_HAVE_TICKET_POINTER_IN_KRB5_AP_REQ,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_ap_req *ap_req; ap_req->ticket = NULL;],
+ samba_cv_HAVE_TICKET_POINTER_IN_KRB5_AP_REQ=yes,
+ samba_cv_HAVE_TICKET_POINTER_IN_KRB5_AP_REQ=no)])
+
+ if test x"$samba_cv_HAVE_TICKET_POINTER_IN_KRB5_AP_REQ" = x"yes"; then
+ AC_DEFINE(HAVE_TICKET_POINTER_IN_KRB5_AP_REQ,1,
+ [Whether the krb5_ap_req struct has a ticket pointer])
+ fi
+
+ AC_CACHE_CHECK([for e_data pointer in krb5_error],
+ samba_cv_HAVE_E_DATA_POINTER_IN_KRB5_ERROR,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_error err; err.e_data = NULL;],
+ samba_cv_HAVE_E_DATA_POINTER_IN_KRB5_ERROR=yes,
+ samba_cv_HAVE_E_DATA_POINTER_IN_KRB5_ERROR=no)])
+
+ if test x"$samba_cv_HAVE_E_DATA_POINTER_IN_KRB5_ERROR" = x"yes"; then
+ AC_DEFINE(HAVE_E_DATA_POINTER_IN_KRB5_ERROR,1,
+ [Whether the krb5_error struct has a e_data pointer])
+ fi
+
+ AC_CACHE_CHECK([for krb5_crypto type],
+ samba_cv_HAVE_KRB5_CRYPTO,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_crypto crypto;],
+ samba_cv_HAVE_KRB5_CRYPTO=yes,
+ samba_cv_HAVE_KRB5_CRYPTO=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_CRYPTO" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_CRYPTO,1,
+ [Whether the type krb5_crypto exists])
+ fi
+
+ AC_CACHE_CHECK([for krb5_encrypt_block type],
+ samba_cv_HAVE_KRB5_ENCRYPT_BLOCK,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_encrypt_block block;],
+ samba_cv_HAVE_KRB5_ENCRYPT_BLOCK=yes,
+ samba_cv_HAVE_KRB5_ENCRYPT_BLOCK=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_ENCRYPT_BLOCK" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_ENCRYPT_BLOCK,1,
+ [Whether the type krb5_encrypt_block exists])
+ fi
+
+ AC_CACHE_CHECK([for addrtype in krb5_address],
+ samba_cv_HAVE_ADDRTYPE_IN_KRB5_ADDRESS,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_address kaddr; kaddr.addrtype = ADDRTYPE_INET;],
+ samba_cv_HAVE_ADDRTYPE_IN_KRB5_ADDRESS=yes,
+ samba_cv_HAVE_ADDRTYPE_IN_KRB5_ADDRESS=no)])
+
+ if test x"$samba_cv_HAVE_ADDRTYPE_IN_KRB5_ADDRESS" = x"yes"; then
+ AC_DEFINE(HAVE_ADDRTYPE_IN_KRB5_ADDRESS,1,
+ [Whether the krb5_address struct has a addrtype property])
+ fi
+
+ AC_CACHE_CHECK([for addr_type in krb5_address],
+ samba_cv_HAVE_ADDR_TYPE_IN_KRB5_ADDRESS,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_address kaddr; kaddr.addr_type = KRB5_ADDRESS_INET;],
+ samba_cv_HAVE_ADDR_TYPE_IN_KRB5_ADDRESS=yes,
+ samba_cv_HAVE_ADDR_TYPE_IN_KRB5_ADDRESS=no)])
+
+ if test x"$samba_cv_HAVE_ADDR_TYPE_IN_KRB5_ADDRESS" = x"yes"; then
+ AC_DEFINE(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS,1,
+ [Whether the krb5_address struct has a addr_type property])
+ fi
+
+ AC_CACHE_CHECK([for enc_part2 in krb5_ticket],
+ samba_cv_HAVE_KRB5_TKT_ENC_PART2,
+ [AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_ticket tkt; tkt.enc_part2->authorization_data[0]->contents = NULL;],
+ samba_cv_HAVE_KRB5_TKT_ENC_PART2=yes,samba_cv_HAVE_KRB5_TKT_ENC_PART2=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_TKT_ENC_PART2" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_TKT_ENC_PART2,1,
+ [Whether the krb5_ticket struct has a enc_part2 property])
+ fi
+
+ AC_CACHE_CHECK([for keyblock in krb5_creds],
+ samba_cv_HAVE_KRB5_KEYBLOCK_IN_CREDS,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_creds creds; krb5_keyblock kb; creds.keyblock = kb;],
+ samba_cv_HAVE_KRB5_KEYBLOCK_IN_CREDS=yes,
+ samba_cv_HAVE_KRB5_KEYBLOCK_IN_CREDS=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_KEYBLOCK_IN_CREDS" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_KEYBLOCK_IN_CREDS,1,
+ [Whether the krb5_creds struct has a keyblock property])
+ fi
+
+ AC_CACHE_CHECK([for session in krb5_creds],
+ samba_cv_HAVE_KRB5_SESSION_IN_CREDS,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_creds creds; krb5_keyblock kb; creds.session = kb;],
+ samba_cv_HAVE_KRB5_SESSION_IN_CREDS=yes,
+ samba_cv_HAVE_KRB5_SESSION_IN_CREDS=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_SESSION_IN_CREDS" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_SESSION_IN_CREDS,1,
+ [Whether the krb5_creds struct has a session property])
+ fi
+
+ AC_CACHE_CHECK([for keyvalue in krb5_keyblock],
+ samba_cv_HAVE_KRB5_KEYBLOCK_KEYVALUE,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_keyblock key; key.keyvalue.data = NULL;],
+ samba_cv_HAVE_KRB5_KEYBLOCK_KEYVALUE=yes,
+ samba_cv_HAVE_KRB5_KEYBLOCK_KEYVALUE=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_KEYBLOCK_KEYVALUE" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_KEYBLOCK_KEYVALUE,1,
+ [Whether the krb5_keyblock struct has a keyvalue property])
+ fi
+
+ AC_CACHE_CHECK([for ENCTYPE_ARCFOUR_HMAC_MD5],
+ samba_cv_HAVE_ENCTYPE_ARCFOUR_HMAC_MD5,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_enctype enctype; enctype = ENCTYPE_ARCFOUR_HMAC_MD5;],
+ samba_cv_HAVE_ENCTYPE_ARCFOUR_HMAC_MD5=yes,
+ samba_cv_HAVE_ENCTYPE_ARCFOUR_HMAC_MD5=no)])
+ AC_CACHE_CHECK([for KEYTYPE_ARCFOUR_56],
+ samba_cv_HAVE_KEYTYPE_ARCFOUR_56,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_keytype keytype; keytype = KEYTYPE_ARCFOUR_56;],
+ samba_cv_HAVE_KEYTYPE_ARCFOUR_56=yes,
+ samba_cv_HAVE_KEYTYPE_ARCFOUR_56=no)])
+# Heimdals with KEYTYPE_ARCFOUR but not KEYTYPE_ARCFOUR_56 are broken
+# w.r.t. arcfour and windows, so we must not enable it here
+ if test x"$samba_cv_HAVE_ENCTYPE_ARCFOUR_HMAC_MD5" = x"yes" -a\
+ x"$samba_cv_HAVE_KEYTYPE_ARCFOUR_56" = x"yes"; then
+ AC_DEFINE(HAVE_ENCTYPE_ARCFOUR_HMAC_MD5,1,
+ [Whether the ENCTYPE_ARCFOUR_HMAC_MD5 key type is available])
+ fi
+
+ AC_CACHE_CHECK([for AP_OPTS_USE_SUBKEY],
+ samba_cv_HAVE_AP_OPTS_USE_SUBKEY,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_flags ap_options; ap_options = AP_OPTS_USE_SUBKEY;],
+ samba_cv_HAVE_AP_OPTS_USE_SUBKEY=yes,
+ samba_cv_HAVE_AP_OPTS_USE_SUBKEY=no)])
+
+ if test x"$samba_cv_HAVE_AP_OPTS_USE_SUBKEY" = x"yes"; then
+ AC_DEFINE(HAVE_AP_OPTS_USE_SUBKEY,1,
+ [Whether the AP_OPTS_USE_SUBKEY ap option is available])
+ fi
+
+ AC_CACHE_CHECK([for KV5M_KEYTAB],
+ samba_cv_HAVE_KV5M_KEYTAB,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_keytab_entry entry; entry.magic = KV5M_KEYTAB;],
+ samba_cv_HAVE_KV5M_KEYTAB=yes,
+ samba_cv_HAVE_KV5M_KEYTAB=no)])
+
+ if test x"$samba_cv_HAVE_KV5M_KEYTAB" = x"yes"; then
+ AC_DEFINE(HAVE_KV5M_KEYTAB,1,
+ [Whether the KV5M_KEYTAB option is available])
+ fi
+
+ AC_CACHE_CHECK([for KRB5_KU_OTHER_CKSUM],
+ samba_cv_HAVE_KRB5_KU_OTHER_CKSUM,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_keyusage usage = KRB5_KU_OTHER_CKSUM;],
+ samba_cv_HAVE_KRB5_KU_OTHER_CKSUM=yes,
+ samba_cv_HAVE_KRB5_KU_OTHER_CKSUM=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_KU_OTHER_CKSUM" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_KU_OTHER_CKSUM,1,
+ [Whether KRB5_KU_OTHER_CKSUM is available])
+ fi
+
+ AC_CACHE_CHECK([for KRB5_KEYUSAGE_APP_DATA_CKSUM],
+ samba_cv_HAVE_KRB5_KEYUSAGE_APP_DATA_CKSUM,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_keyusage usage = KRB5_KEYUSAGE_APP_DATA_CKSUM;],
+ samba_cv_HAVE_KRB5_KEYUSAGE_APP_DATA_CKSUM=yes,
+ samba_cv_HAVE_KRB5_KEYUSAGE_APP_DATA_CKSUM=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_KEYUSAGE_APP_DATA_CKSUM" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_KEYUSAGE_APP_DATA_CKSUM,1,
+ [Whether KRB5_KEYUSAGE_APP_DATA_CKSUM is available])
+ fi
+
+ AC_CACHE_CHECK([for the krb5_princ_component macro],
+ samba_cv_HAVE_KRB5_PRINC_COMPONENT,[
+ AC_TRY_LINK([#include <krb5.h>],
+ [const krb5_data *pkdata; krb5_context context; krb5_principal principal; pkdata = krb5_princ_component(context, principal, 0);],
+ samba_cv_HAVE_KRB5_PRINC_COMPONENT=yes,
+ samba_cv_HAVE_KRB5_PRINC_COMPONENT=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_PRINC_COMPONENT" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_PRINC_COMPONENT,1,
+ [Whether krb5_princ_component is available])
+ fi
+
+ AC_CACHE_CHECK([for key in krb5_keytab_entry],
+ samba_cv_HAVE_KRB5_KEYTAB_ENTRY_KEY,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_keytab_entry entry; krb5_keyblock e; entry.key = e;],
+ samba_cv_HAVE_KRB5_KEYTAB_ENTRY_KEY=yes,
+ samba_cv_HAVE_KRB5_KEYTAB_ENTRY_KEY=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_KEYTAB_ENTRY_KEY" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_KEYTAB_ENTRY_KEY,1,
+ [Whether krb5_keytab_entry has key member])
+ fi
+
+ AC_CACHE_CHECK([for keyblock in krb5_keytab_entry],
+ samba_cv_HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_keytab_entry entry; entry.keyblock.keytype = 0;],
+ samba_cv_HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK=yes,
+ samba_cv_HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK,1,
+ [Whether krb5_keytab_entry has keyblock member])
+ fi
+
+ AC_CACHE_CHECK([for magic in krb5_address],
+ samba_cv_HAVE_MAGIC_IN_KRB5_ADDRESS,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_address addr; addr.magic = 0;],
+ samba_cv_HAVE_MAGIC_IN_KRB5_ADDRESS=yes,
+ samba_cv_HAVE_MAGIC_IN_KRB5_ADDRESS=no)])
+
+ if test x"$samba_cv_HAVE_MAGIC_IN_KRB5_ADDRESS" = x"yes"; then
+ AC_DEFINE(HAVE_MAGIC_IN_KRB5_ADDRESS,1,
+ [Whether the krb5_address struct has a magic property])
+ fi
+
+ AC_CACHE_CHECK([for WRFILE: keytab support],
+ samba_cv_HAVE_WRFILE_KEYTAB,[
+ AC_TRY_RUN([
+#include<krb5.h>
+ main()
+ {
+ krb5_context context;
+ krb5_keytab keytab;
+
+ krb5_init_context(&context);
+ return krb5_kt_resolve(context, "WRFILE:api", &keytab);
+ }],
+ samba_cv_HAVE_WRFILE_KEYTAB=yes,
+ samba_cv_HAVE_WRFILE_KEYTAB=no)])
+
+ if test x"$samba_cv_HAVE_WRFILE_KEYTAB" = x"yes"; then
+ AC_DEFINE(HAVE_WRFILE_KEYTAB,1,
+ [Whether the WRFILE:-keytab is supported])
+ fi
+
+ AC_CACHE_CHECK([for krb5_princ_realm returns krb5_realm or krb5_data],
+ samba_cv_KRB5_PRINC_REALM_RETURNS_REALM,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [
+ krb5_context context;
+ krb5_principal principal;
+ krb5_realm realm; realm = *krb5_princ_realm(context, principal);],
+ samba_cv_KRB5_PRINC_REALM_RETURNS_REALM=yes,
+ samba_cv_KRB5_PRINC_REALM_RETURNS_REALM=no)])
+
+ if test x"$samba_cv_KRB5_PRINC_REALM_RETURNS_REALM" = x"yes"; then
+ AC_DEFINE(KRB5_PRINC_REALM_RETURNS_REALM,1,
+ [Whether krb5_princ_realm returns krb5_realm or krb5_data])
+ fi
+
+ AC_CACHE_CHECK([for krb5_addresses type],
+ samba_cv_HAVE_KRB5_ADDRESSES,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_addresses addr;],
+ samba_cv_HAVE_KRB5_ADDRESSES=yes,
+ samba_cv_HAVE_KRB5_ADDRESSES=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_ADDRESSES" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_ADDRESSES,1,
+ [Whether the type krb5_addresses type exists])
+ fi
+
+ AC_CACHE_CHECK([whether krb5_mk_error takes 3 arguments MIT or 9 Heimdal],
+ samba_cv_HAVE_SHORT_KRB5_MK_ERROR_INTERFACE, [
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [
+ krb5_mk_error(0,0,0);],
+ samba_cv_HAVE_SHORT_KRB5_MK_ERROR_INTERFACE=yes,
+ samba_cv_HAVE_SHORT_KRB5_MK_ERROR_INTERFACE=no)])
+
+ if test x"$samba_cv_HAVE_SHORT_KRB5_MK_ERROR_INTERFACE" = x"yes"; then
+ AC_DEFINE(HAVE_SHORT_KRB5_MK_ERROR_INTERFACE,1,
+ [whether krb5_mk_error takes 3 arguments MIT or 9 Heimdal])
+ fi
+
+ if test x"$ac_cv_func_ext_krb5_enctype_to_string" = x"yes"; then
+ AC_CACHE_CHECK([for krb5_error_code krb5_enctype_to_string(krb5_context context, krb5_enctype enctype, char **str)],
+ smb_krb5_cv_enctype_to_string_takes_krb5_context_arg,[
+ AC_TRY_RUN_STRICT([
+ #include <stdlib.h>
+ #include <krb5.h>
+ int main(void) {
+ krb5_context context = NULL;
+ char *str = NULL;
+ krb5_enctype_to_string(context, 1, &str);
+ if (str) free (str);
+ return 0;
+ }
+ ],[$Werror_FLAGS],[$CPPFLAGS],[$LDFLAGS],
+ smb_krb5_cv_enctype_to_string_takes_krb5_context_arg=yes,
+ smb_krb5_cv_enctype_to_string_takes_krb5_context_arg=no)])
+
+ if test x"$smb_krb5_cv_enctype_to_string_takes_krb5_context_arg" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_ENCTYPE_TO_STRING_WITH_KRB5_CONTEXT_ARG,1,
+ [whether krb5_enctype_to_string takes krb5_context argument])
+ fi
+
+ AC_CACHE_CHECK([for krb5_error_code krb5_enctype_to_string(krb5_enctype enctype, char *str, size_t len)],
+ smb_krb5_cv_enctype_to_string_takes_size_t_arg,[
+ AC_TRY_RUN_STRICT([
+ #include <krb5.h>
+ int main(void) {
+ char buf[256];
+ krb5_enctype_to_string(1, buf, 256);
+ return 0;
+ }
+ ],[$Werror_FLAGS],[$CPPFLAGS],[$LDFLAGS],
+ smb_krb5_cv_enctype_to_string_takes_size_t_arg=yes,
+ smb_krb5_cv_enctype_to_string_takes_size_t_arg=no)])
+
+ if test x"$smb_krb5_cv_enctype_to_string_takes_size_t_arg" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_ENCTYPE_TO_STRING_WITH_SIZE_T_ARG,1,
+ [whether krb5_enctype_to_string takes size_t argument])
+ fi
+ fi
+
+ AC_CACHE_CHECK([for krb5_principal_get_realm],
+ samba_cv_HAVE_KRB5_PRINCIPAL_GET_REALM,[
+ AC_TRY_LINK([#include <krb5.h>],
+ [krb5_context ctx = NULL; krb5_principal princ = NULL; const char *str = krb5_principal_get_realm(ctx, princ);],
+ samba_cv_HAVE_KRB5_PRINCIPAL_GET_REALM=yes,
+ samba_cv_HAVE_KRB5_PRINCIPAL_GET_REALM=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_PRINCIPAL_GET_REALM" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_PRINCIPAL_GET_REALM,1,
+ [Whether the function krb5_principal_get_realm is defined])
+ fi
+
+ AC_CACHE_CHECK([for krb5_princ_realm],
+ samba_cv_HAVE_KRB5_PRINC_REALM,[
+ AC_TRY_LINK([#include <krb5.h>],
+ [krb5_context ctx = NULL; krb5_principal princ = NULL; const char *str = krb5_princ_realm(ctx, princ)->data;],
+ samba_cv_HAVE_KRB5_PRINC_REALM=yes,
+ samba_cv_HAVE_KRB5_PRINC_REALM=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_PRINC_REALM" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_PRINC_REALM,1,
+ [Whether the macro krb5_princ_realm is defined])
+ fi
+
+ #
+ #
+ # Now the decisions whether we can support krb5
+ #
+ # NOTE: all tests should be done before this block!
+ #
+ #
+ if test x"$ac_cv_lib_ext_krb5_krb5_mk_req_extended" != x"yes"; then
+ AC_MSG_WARN(krb5_mk_req_extended not found in -lkrb5)
+ use_ads=no
+ fi
+
+ if test x"$ac_cv_func_ext_krb5_principal2salt" != x"yes" -a \
+ x"$ac_cv_func_ext_krb5_get_pw_salt" != x"yes"
+ then
+ AC_MSG_WARN(no CREATE_KEY_FUNCTIONS detected)
+ use_ads=no
+ fi
+
+ if test x"$ac_cv_func_ext_krb5_get_permitted_enctypes" != x"yes" -a \
+ x"$ac_cv_func_ext_krb5_get_default_in_tkt_etypes" != x"yes"
+ then
+ AC_MSG_WARN(no GET_ENCTYPES_FUNCTIONS detected)
+ use_ads=no
+ fi
+
+ if test x"$ac_cv_func_ext_krb5_kt_free_entry" != x"yes" -a \
+ x"$ac_cv_func_ext_krb5_free_keytab_entry_contents" != x"yes"
+ then
+ AC_MSG_WARN(no KT_FREE_FUNCTION detected)
+ use_ads=no
+ fi
+
+ if test x"$ac_cv_func_ext_krb5_c_verify_checksum" != x"yes" -a \
+ x"$ac_cv_func_ext_krb5_verify_checksum" != x"yes"
+ then
+ AC_MSG_WARN(no KRB5_VERIFY_CHECKSUM_FUNCTION detected)
+ use_ads=no
+ fi
+
+ if test x"$smb_krb5_cv_ticket_has_keyinfo" != x"yes" ; then
+
+ # We only need the following functions if we can't get the enctype
+ # and kvno out of the ticket directly (ie. on Heimdal).
+
+ if test x"$ac_cv_func_ext_free_AP_REQ" != x"yes"
+ then
+ AC_MSG_WARN(no KRB5_AP_REQ_FREE_FUNCTION detected)
+ use_ads=no
+ fi
+
+ if test x"$ac_cv_func_ext_krb5_decode_ap_req" != x"yes"
+ then
+ AC_MSG_WARN(no KRB5_AP_REQ_DECODING_FUNCTION detected)
+ use_ads=no
+ fi
+
+ fi
+
+ if test x"$use_ads" = x"yes"; then
+ AC_DEFINE(WITH_ADS,1,[Whether to include Active Directory support])
+ AC_DEFINE(HAVE_KRB5,1,[Whether to have KRB5 support])
+ if test x"$have_gssapi" = x"yes"; then
+ AC_DEFINE(HAVE_GSSAPI,1,[Whether GSSAPI is available])
+ fi
+ else
+ if test x"$with_ads_support" = x"yes"; then
+ AC_MSG_ERROR(krb5 libs don't have all features required for Active Directory support)
+ else
+ AC_MSG_WARN(krb5 libs don't have all features required for Active Directory support)
+ fi
+ AC_REMOVE_DEFINE(HAVE_KRB5_H)
+ AC_REMOVE_DEFINE(HAVE_GSSAPI_H)
+ AC_REMOVE_DEFINE(HAVE_GSSAPI_GSSAPI_GENERIC_H)
+ AC_REMOVE_DEFINE(HAVE_GSSAPI_GSSAPI_H)
+ KRB5_LIBS=""
+ with_ads_support=no
+ fi
+ AC_MSG_CHECKING(whether Active Directory and krb5 support is used)
+ AC_MSG_RESULT([$use_ads])
+
+LIBS="$ac_save_LIBS"
+fi
+
+AC_CHECK_LIB_EXT(nscd, NSCD_LIBS, nscd_flush_cache)
+PASSDB_LIBS="$PASSDB_LIBS $NSCD_LIBS"
+
+
+########################################################
+# Compile with DNS Updates support?
+
+with_dnsupdate_support=no
+AC_MSG_CHECKING([whether to enable DNS Updates support])
+
+AC_ARG_WITH(dnsupdate,
+[AS_HELP_STRING([--with-dnsupdate], [Enable DNS Updates support (default no)])],
+[ case "$withval" in
+ yes|no)
+ with_dnsupdate_support=$withval
+ ;;
+ esac ])
+
+AC_MSG_RESULT($with_dnsupdate_support)
+
+if test x"$with_dnsupdate_support" != x"no"; then
+
+ ################################################################
+ # first test for Active Directory support being enabled
+ #if test x"$with_ads_support" = x"no"; then
+ # AC_MSG_ERROR(Active Directory support is required to enable DNS Update support)
+ # with_dnsupdate_support=no
+ #fi
+ ##################################################################
+ # then test for uuid.h (necessary to generate unique DNS keynames
+ # (uuid.h is required for this test)
+ AC_CHECK_HEADERS(uuid/uuid.h)
+
+ if test x"$ac_cv_header_uuid_uuid_h" != x"yes"; then
+ if test x"$with_dnsupdate_support" = x"yes"; then
+ AC_MSG_ERROR(uuid.h is needed to enable DNS Updates support)
+ else
+ AC_MSG_WARN(uuid.h is needed to enable DNS Updates support)
+ fi
+ with_dnsupdate_support=no
+ fi
+fi
+
+if test x"$with_dnsupdate_support" != x"no"; then
+
+ ########################################################
+ # Now see if we can find the uuid libs in standard paths
+ # On some systems, the uuid API is in libc, so we have to
+ # be careful not to insert a spurious -luuid.
+
+ UUID_LIBS=""
+ AC_LIBTESTFUNC(uuid, uuid_generate,
+ [
+ case " $LIBS " in
+ *\ -luuid\ *)
+ UUID_LIBS="-luuid"
+ SMB_REMOVE_LIB(uuid)
+ ;;
+ esac
+
+ with_dnsupdate_support=yes
+ AC_DEFINE(WITH_DNS_UPDATES,1,[Whether to enable DNS Update support])
+ ],
+ [
+ if test x"$with_dnsupdate_support" = x"yes"; then
+ AC_MSG_ERROR(libuuid is needed to enable DNS Updates support)
+ else
+ AC_MSG_WARN(libuuid is needed to enable DNS Updates support)
+ fi
+ with_dnsupdate_support=no
+ ])
+fi
+
+#################################################
+# check for automount support
+AC_MSG_CHECKING(whether to use automount)
+AC_ARG_WITH(automount,
+[AS_HELP_STRING([--with-automount], [Include automount support (default=no)])],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_AUTOMOUNT,1,[Whether to include automount support])
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# check for mount- and umount.cifs support
+CIFSMOUNT_PROGS=""
+INSTALL_CIFSMOUNT=""
+UNINSTALL_CIFSMOUNT=""
+AC_MSG_CHECKING(whether to build mount.cifs and umount.cifs)
+AC_ARG_WITH(cifsmount,
+[AS_HELP_STRING([--with-cifsmount], [Include mount.cifs and umount.cifs (Linux only) support (default=yes)])],
+[ case "$withval" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ case "$host_os" in
+ *linux*)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_CIFSMOUNT,1,[Whether to build mount.cifs and umount.cifs])
+ CIFSMOUNT_PROGS="bin/mount.cifs bin/umount.cifs"
+ INSTALL_CIFSMOUNT="installcifsmount"
+ UNINSTALL_CIFSMOUNT="uninstallcifsmount"
+ ;;
+ *)
+ AC_MSG_ERROR(not on a linux system!)
+ ;;
+ esac
+ ;;
+ esac ],
+[ case "$host_os" in
+ *linux*)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_CIFSMOUNT,1,[Whether to build mount.cifs and umount.cifs])
+ CIFSMOUNT_PROGS="bin/mount.cifs bin/umount.cifs"
+ INSTALL_CIFSMOUNT="installcifsmount"
+ UNINSTALL_CIFSMOUNT="uninstallcifsmount"
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ]
+)
+
+#################################################
+# check for cifs.upcall support
+AC_CHECK_HEADERS([keyutils.h], [HAVE_KEYUTILS_H=1], [HAVE_KEYUTILS_H=0])
+CIFSUPCALL_PROGS=""
+INSTALL_CIFSUPCALL=""
+UNINSTALL_CIFSUPCALL=""
+AC_MSG_CHECKING(whether to build cifs.upcall)
+AC_ARG_WITH(cifsupcall,
+[AS_HELP_STRING([--with-cifsupcall], [Include cifs.upcall (Linux only) support (default=yes)])],
+[ case "$withval" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ case "$host_os" in
+ *linux*)
+ if test x"$use_ads" != x"yes"; then
+ AC_MSG_ERROR(ADS support should be enabled for building cifs.upcall)
+ elif test x"$HAVE_KEYUTILS_H" != "x1"; then
+ AC_MSG_ERROR(keyutils package is required for cifs.upcall)
+ else
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_CIFSUPCALL,1,[whether to build cifs.upcall])
+ CIFSUPCALL_PROGS="bin/cifs.upcall"
+ INSTALL_CIFSUPCALL="installcifsupcall"
+ UNINSTALL_CIFSUPCALL="uninstallcifsupcall"
+ fi
+ ;;
+ *)
+ AC_MSG_ERROR(not on a linux system!)
+ ;;
+ esac
+ ;;
+ esac ],
+[ case "$host_os" in
+ *linux*)
+ if test x"$use_ads" != x"yes"; then
+ AC_MSG_WARN(ADS support should be enabled for building cifs.upcall)
+ elif test x"$HAVE_KEYUTILS_H" != "x1"; then
+ AC_MSG_WARN(keyutils package is required for cifs.upcall)
+ else
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_CIFSUPCALL,1,[whether to build cifs.upcall])
+ CIFSUPCALL_PROGS="bin/cifs.upcall"
+ INSTALL_CIFSUPCALL="installcifsupcall"
+ UNINSTALL_CIFSUPCALL="uninstallcifsupcall"
+ fi
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ]
+)
+
+
+#################################################
+# Check for a PAM clear-text auth, accounts, password
+# and session support. Most PAM implementations keep their
+# headers in /usr/include/security. Darwin keeps its in
+# /usr/include/pam.
+
+with_pam_for_crypt=no
+try_pam=no
+AC_MSG_CHECKING(whether to try PAM support)
+AC_ARG_WITH(pam,
+[AS_HELP_STRING([--with-pam], [Include PAM support (default=no)])],
+[ case "$withval" in
+ yes|no)
+ try_pam=$withval
+ ;;
+ esac
+])
+AC_MSG_RESULT([$try_pam])
+
+use_pam=no
+create_pam_modules=no
+if test x"${try_pam}" != x"no";then
+ use_pam=yes
+ create_pam_modules=yes
+
+ # Most systems have PAM headers in /usr/include/security, but Darwin
+ # has them in /usr/include/pam.
+ AC_CHECK_HEADERS(security/pam_appl.h pam/pam_appl.h)
+ if test x"$ac_cv_header_security_pam_appl_h" != x"yes" -a \
+ x"$ac_cv_header_pam_pam_appl_h" != x"yes"; then
+ if test x"${try_pam}" = x"yes";then
+ AC_MSG_ERROR([--with-pam=yes but pam_appl.h not found])
+ fi
+ use_pam=no
+ create_pam_modules=no
+ fi
+
+ AC_CHECK_LIB_EXT(pam, PAM_LIBS, pam_get_data)
+ if test x"$ac_cv_lib_ext_pam_pam_get_data" != x"yes"; then
+ if test x"${try_pam}" = x"yes";then
+ AC_MSG_ERROR([--with-pam=yes but libpam not found])
+ fi
+ use_pam=no
+ create_pam_modules=no
+ fi
+
+ AC_CHECK_HEADERS(security/pam_modules.h pam/pam_modules.h,,,[[
+ #if HAVE_SECURITY_PAM_APPL_H
+ #include <security/pam_appl.h>
+ #endif
+ #if HAVE_PAM_PAM_APPL_H
+ #include <pam/pam_appl.h>
+ #endif
+ ]])
+ if test x"$ac_cv_header_security_pam_modules_h" = x"no" -a \
+ x"$ac_cv_header_pam_pam_modules_h" = x"no" ; then
+ if test x"${try_pam}" = x"yes";then
+ AC_MSG_ERROR([--with-pam=yes but pam_modules.h not found])
+ fi
+ create_pam_modules=no
+ fi
+
+ if test x"$use_pam" = x"yes"; then
+ AC_DEFINE(WITH_PAM,1,[Whether to include PAM support])
+ AC_DEFINE(HAVE_LIBPAM,1,[Whether libpam is available])
+ AUTH_LIBS="$AUTH_LIBS $PAM_LIBS"
+ with_pam_for_crypt=yes
+
+ if test x"$create_pam_modules" = x"yes"; then
+ AC_DEFINE(WITH_PAM_MODULES,1,[Whether to include PAM MODULES support])
+ # this checks are optional,
+ # we don't care about the results here
+ AC_CHECK_HEADERS(security/pam_ext.h security/_pam_macros.h)
+ AC_CHECK_HEADERS(pam/pam_ext.h pam/_pam_macros.h)
+ AC_CHECK_FUNC_EXT(pam_vsyslog,$PAM_LIBS)
+ else
+ AC_MSG_WARN([PAM support detected but PAM MODULES support is missing])
+ fi
+ fi
+ AC_MSG_CHECKING(whether to use PAM support)
+ AC_MSG_RESULT([$use_pam])
+
+ AC_MSG_CHECKING(whether to have PAM MODULES support)
+ AC_MSG_RESULT([$create_pam_modules])
+fi # try_pam != no
+
+#################################################
+# check for pam_smbpass support
+PAM_MODULES=""
+INSTALL_PAM_MODULES=""
+UNINSTALL_PAM_MODULES=""
+AC_MSG_CHECKING(whether to use pam_smbpass)
+AC_ARG_WITH(pam_smbpass,
+[AS_HELP_STRING([--with-pam_smbpass], [Build PAM module for authenticating against passdb backends (default=no)])],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+
+ # Conditions under which pam_smbpass should not be built.
+
+ if test x"$BLDSHARED" != x"true"; then
+ AC_MSG_ERROR([No support for shared modules])
+ elif test x"$create_pam_modules" != x"yes"; then
+ AC_MSG_ERROR([No support for PAM MODULES])
+ else
+ PAM_MODULES="pam_smbpass"
+ INSTALL_PAM_MODULES="installpammodules"
+ UNINSTALL_PAM_MODULES="uninstallpammodules"
+ fi
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+
+###############################################
+# test for where we get crypt() from
+AC_SEARCH_LIBS(crypt, [crypt],
+ [test "$ac_cv_search_crypt" = "none required" || AUTH_LIBS="-lcrypt $AUTH_LIBS"
+ AC_DEFINE(HAVE_CRYPT,1,[Whether the system has the crypt() function])])
+
+##
+## moved after the check for -lcrypt in order to
+## ensure that the necessary libraries are included
+## check checking for truncated salt. Wrapped by the
+## $with_pam_for_crypt variable as above --jerry
+##
+if test $with_pam_for_crypt = no; then
+AC_CACHE_CHECK([for a crypt that needs truncated salt],samba_cv_HAVE_TRUNCATED_SALT,[
+crypt_LIBS="$LIBS"
+LIBS="$AUTH_LIBS $LIBS"
+AC_TRY_RUN([#include "${srcdir-.}/tests/crypttest.c"],
+ samba_cv_HAVE_TRUNCATED_SALT=no,samba_cv_HAVE_TRUNCATED_SALT=yes,samba_cv_HAVE_TRUNCATED_SALT=cross)
+LIBS="$crypt_LIBS"])
+if test x"$samba_cv_HAVE_TRUNCATED_SALT" = x"yes"; then
+ AC_DEFINE(HAVE_TRUNCATED_SALT,1,[Whether crypt needs truncated salt])
+fi
+fi
+
+#################################################
+# check for a NISPLUS_HOME support
+AC_MSG_CHECKING(whether to use NISPLUS_HOME)
+AC_ARG_WITH(nisplus-home,
+[AS_HELP_STRING([--with-nisplus-home], [Include NISPLUS_HOME support (default=no)])],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_NISPLUS_HOME,1,[Whether to include nisplus_home support])
+ ;;
+ *)
+ 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,
+[AS_HELP_STRING([--with-syslog], [Include experimental SYSLOG support (default=no)])],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_SYSLOG,1,[Whether to include experimental syslog support])
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# check for experimental disk-quotas support
+
+samba_cv_WITH_QUOTAS=auto
+samba_cv_TRY_QUOTAS=no
+samba_cv_RUN_QUOTA_TESTS=auto
+samba_cv_WITH_SYS_QUOTAS=auto
+samba_cv_TRY_SYS_QUOTAS=auto
+samba_cv_SYSQUOTA_FOUND=no
+
+AC_MSG_CHECKING(whether to try disk-quotas support)
+AC_ARG_WITH(quotas,
+[AS_HELP_STRING([--with-quotas], [Include disk-quota support (default=no)])],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ samba_cv_WITH_QUOTAS=yes
+ samba_cv_TRY_QUOTAS=yes
+ samba_cv_RUN_QUOTA_TESTS=yes
+ #set sys quotas to auto in this case
+ samba_cv_TRY_SYS_QUOTAS=auto
+ ;;
+ auto)
+ AC_MSG_RESULT(auto)
+ samba_cv_WITH_QUOTAS=auto
+ samba_cv_TRY_QUOTAS=auto
+ samba_cv_RUN_QUOTA_TESTS=auto
+ #set sys quotas to auto in this case
+ samba_cv_TRY_SYS_QUOTAS=auto
+ ;;
+ no)
+ AC_MSG_RESULT(no)
+ samba_cv_WITH_QUOTAS=no
+ samba_cv_TRY_QUOTAS=no
+ samba_cv_RUN_QUOTA_TESTS=no
+ ;;
+ *)
+ AC_MSG_RESULT(${samba_cv_TRY_QUOTAS})
+ ;;
+ esac ],
+ AC_MSG_RESULT(${samba_cv_TRY_QUOTAS})
+)
+
+AC_MSG_CHECKING(whether to try the new lib/sysquotas.c interface)
+AC_ARG_WITH(sys-quotas,
+[AS_HELP_STRING([--with-sys-quotas], [Include lib/sysquotas.c support (default=auto)])],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ samba_cv_WITH_SYS_QUOTAS=yes
+ samba_cv_TRY_SYS_QUOTAS=yes
+ samba_cv_RUN_QUOTA_TESTS=yes
+ ;;
+ auto)
+ AC_MSG_RESULT(auto)
+ samba_cv_WITH_SYS_QUOTAS=auto
+ samba_cv_TRY_SYS_QUOTAS=auto
+ samba_cv_RUN_QUOTA_TESTS=auto
+ ;;
+ no)
+ AC_MSG_RESULT(no)
+ samba_cv_WITH_SYS_QUOTAS=no
+ samba_cv_TRY_SYS_QUOTAS=no
+ ;;
+ *)
+ AC_MSG_RESULT(${samba_cv_TRY_SYS_QUOTAS})
+ ;;
+ esac ],
+ AC_MSG_RESULT(${samba_cv_TRY_SYS_QUOTAS})
+)
+
+if test x"$samba_cv_TRY_SYS_QUOTAS" = x"auto"; then
+AC_MSG_CHECKING(whether to try the lib/sysquotas.c interface on ${host_os})
+ case "$host_os" in
+ *linux*)
+ AC_MSG_RESULT(yes)
+ samba_cv_TRY_SYS_QUOTAS=yes
+ samba_cv_RUN_QUOTA_TESTS=yes
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ samba_cv_TRY_SYS_QUOTAS=no
+ ;;
+ esac
+fi
+
+#############################################
+# only check for quota stuff if --with-quotas
+if test x"$samba_cv_RUN_QUOTA_TESTS" != x"no"; then
+
+case "$host_os" in
+ # on linux we didn't need to test we have builtin support
+ *linux*)
+ samba_cv_SYSQUOTA_FOUND=yes
+ AC_DEFINE(HAVE_QUOTACTL_LINUX,1,[Whether Linux quota support is available])
+ samba_cv_sysquotas_file="lib/sysquotas_linux.c"
+ AC_MSG_CHECKING(whether to use the lib/sysquotas_linux.c builtin support)
+ AC_MSG_RESULT(yes)
+
+ AC_DEFINE(HAVE_LINUX_XFS_QUOTAS,1,[Whether Linux xfs quota support is available])
+ samba_cv_found_xfs_header=yes
+ AC_MSG_CHECKING(whether to use the lib/sysquotas_xfs.c builtin support)
+ AC_MSG_RESULT(yes)
+ ;;
+ *solaris*)
+ # need to set this define when using static linking (BUG 1473)
+ CPPFLAGS="$CPPFLAGS -DSUNOS5"
+ ;;
+ *)
+ ;;
+esac
+
+# some broken header files need this
+AC_CHECK_HEADER(asm/types.h,[
+ AC_DEFINE(HAVE_ASM_TYPES_H,1,[check for <asm/types.h>])
+ AC_ADD_INCLUDE(<asm/types.h>)
+ ])
+
+# For quotas on Veritas VxFS filesystems
+AC_CHECK_HEADERS(sys/fs/vx_quota.h)
+
+# For quotas on Linux XFS filesystems
+AC_CHECK_HEADERS(linux/dqblk_xfs.h)
+
+# For sys/quota.h and linux/quota.h
+AC_CHECK_HEADERS(sys/quota.h)
+
+if test x"$samba_cv_found_xfs_header" != x"yes"; then
+# if we have xfs quota support <sys/quota.h> (IRIX) we should use it
+AC_CACHE_CHECK([for XFS QUOTA in <sys/quota.h>],samba_cv_HAVE_SYS_QUOTA_XFS, [
+AC_TRY_COMPILE([
+#include "confdefs.h"
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+#include <sys/quota.h>
+],[int i = Q_XGETQUOTA;],
+samba_cv_HAVE_SYS_QUOTA_XFS=yes,samba_cv_HAVE_SYS_QUOTA_XFS=no)])
+if test "$samba_cv_HAVE_SYS_QUOTA_XFS"x = "yes"x; then
+ samba_cv_found_xfs_header=yes
+fi
+fi
+
+# if we have struct dqblk .dqb_fsoftlimit instead of .dqb_isoftlimit on IRIX
+AC_CACHE_CHECK([if struct dqblk has .dqb_fsoftlimit],samba_cv_HAVE_DQB_FSOFTLIMIT, [
+AC_TRY_COMPILE([
+#include "confdefs.h"
+#ifdef HAVE_SYS_QUOTA_H
+#include <sys/quota.h>
+#endif
+],[
+struct dqblk D;
+D.dqb_fsoftlimit = 0;],
+samba_cv_HAVE_DQB_FSOFTLIMIT=yes,samba_cv_HAVE_DQB_FSOFTLIMIT=no)])
+if test "$samba_cv_HAVE_DQB_FSOFTLIMIT"x = "yes"x; then
+ AC_DEFINE(HAVE_DQB_FSOFTLIMIT,1,[struct dqblk .dqb_fsoftlimit])
+fi
+
+##################
+# look for a working quota system
+
+if test x"$samba_cv_SYSQUOTA_FOUND" != x"yes"; then
+AC_CACHE_CHECK([for long quotactl(int cmd, char *special, qid_t id, caddr_t addr)],samba_cv_HAVE_QUOTACTL_4A,[
+AC_TRY_RUN_STRICT([
+#define HAVE_QUOTACTL_4A 1
+#define AUTOCONF_TEST 1
+#include "confdefs.h"
+#include "${srcdir-.}/tests/sysquotas.c"],[$Werror_FLAGS],[$CPPFLAGS],[$LDFLAGS],
+ samba_cv_HAVE_QUOTACTL_4A=yes,samba_cv_HAVE_QUOTACTL_4A=no,samba_cv_HAVE_QUOTACTL_4A=cross)])
+if test x"$samba_cv_HAVE_QUOTACTL_4A" = x"yes"; then
+ samba_cv_SYSQUOTA_FOUND=yes;
+ AC_DEFINE(HAVE_QUOTACTL_4A,1,[Whether long quotactl(int cmd, char *special, qid_t id, caddr_t addr) is available])
+ samba_cv_sysquotas_file="lib/sysquotas_4A.c"
+fi
+fi
+
+if test x"$samba_cv_SYSQUOTA_FOUND" != x"yes"; then
+AC_CACHE_CHECK([for int quotactl(const char *path, int cmd, int id, char *addr)],samba_cv_HAVE_QUOTACTL_4B,[
+AC_TRY_RUN_STRICT([
+#define HAVE_QUOTACTL_4B 1
+#define AUTOCONF_TEST 1
+#include "confdefs.h"
+#include "${srcdir-.}/tests/sysquotas.c"],[$Werror_FLAGS],[$CPPFLAGS],[$LDFLAGS],
+ samba_cv_HAVE_QUOTACTL_4B=yes,samba_cv_HAVE_QUOTACTL_4B=no,samba_cv_HAVE_QUOTACTL_4B=cross)])
+if test x"$samba_cv_HAVE_QUOTACTL_4B" = x"yes"; then
+ echo "int quotactl(const char *path, int cmd, int id, char *addr) is not reworked for the new sys_quota api"
+ samba_cv_SYSQUOTA_FOUND=yes;
+ AC_DEFINE(HAVE_QUOTACTL_4B,1,[Whether int quotactl(const char *path, int cmd, int id, char *addr) is available])
+ samba_cv_sysquotas_file="lib/sysquotas_4B.c"
+fi
+fi
+
+if test x"$samba_cv_SYSQUOTA_FOUND" != x"yes"; then
+AC_CACHE_CHECK([for CRAY int quotactl (char *spec, int request, char *arg)],samba_cv_HAVE_QUOTACTL_3,[
+AC_TRY_RUN_STRICT([
+#define HAVE_QUOTACTL_3 1
+#define AUTOCONF_TEST 1
+#include "confdefs.h"
+#include "${srcdir-.}/tests/sysquotas.c"],[$Werror_FLAGS],[$CPPFLAGS],[$LDFLAGS],
+ samba_cv_HAVE_QUOTACTL_3=yes,samba_cv_HAVE_QUOTACTL_3=no,samba_cv_HAVE_QUOTACTL_3=cross)])
+if test x"$samba_cv_HAVE_QUOTACTL_3" = x"yes"; then
+ echo "CRAY int quotactl (char *spec, int request, char *arg) is NOT reworked for the sys_quota api"
+ samba_cv_SYSQUOTA_FOUND=yes;
+ AC_DEFINE(HAVE_QUOTACTL_3,1,[Whether CRAY int quotactl (char *spec, int request, char *arg); is available])
+ samba_cv_sysquotas_file="lib/sysquotas_3.c"
+fi
+fi
+
+#################################################
+# check for mntent.h and struct mntent
+AC_CHECK_HEADERS(mntent.h)
+#################################################
+# check for setmntent,getmntent,endmntent
+AC_CHECK_FUNCS(setmntent getmntent endmntent)
+
+#################################################
+# check for devnm.h and struct mntent
+AC_CHECK_HEADERS(devnm.h)
+#################################################
+# check for devnm
+AC_CHECK_FUNCS(devnm)
+
+if test x"$samba_cv_WITH_SYS_QUOTAS" = x"yes"; then
+ if test x"$samba_cv_SYSQUOTA_FOUND" != x"yes"; then
+ # if --with-sys-quotas=yes then build it
+ # you have can use the get/set quota command smb.conf
+ # options then
+ samba_cv_SYSQUOTA_FOUND=auto
+ fi
+ if test x"$samba_cv_TRY_SYS_QUOTAS" != x"yes"; then
+ # if --with-sys-quotas=yes then build it
+ # you have can use the get/set quota command smb.conf
+ # options then
+ samba_cv_TRY_SYS_QUOTAS=auto
+ fi
+fi
+
+if test x"$samba_cv_SYSQUOTA_FOUND" != x"no"; then
+AC_CACHE_CHECK([whether the sys_quota interface works],samba_cv_SYSQUOTA_WORKS,[
+SAVE_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS ${SAMBA_CONFIGURE_CPPFLAGS}"
+AC_TRY_COMPILE([
+#include "confdefs.h"
+#define NO_PROTO_H 1
+#define NO_CONFIG_H 1
+#define HAVE_SYS_QUOTAS 1
+#include "${srcdir-.}/${samba_cv_sysquotas_file}"
+#include "${srcdir-.}/lib/sysquotas.c"
+],[],samba_cv_SYSQUOTA_WORKS=yes,samba_cv_SYSQUOTA_WORKS=no)
+CPPFLAGS="$SAVE_CPPFLAGS"
+])
+if test x"$samba_cv_SYSQUOTA_WORKS" = x"yes"; then
+AC_MSG_CHECKING(whether to use the new lib/sysquotas.c interface)
+ if test x"$samba_cv_TRY_SYS_QUOTAS" != x"no"; then
+ AC_DEFINE(WITH_QUOTAS,1,[Whether to use disk quota support])
+ AC_DEFINE(HAVE_SYS_QUOTAS,1,[Whether the new lib/sysquotas.c interface can be used])
+ samba_cv_WE_USE_SYS_QUOTAS=yes
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ fi
+fi
+fi
+
+if test x"$samba_cv_SYSQUOTA_FOUND" != x"no" -a x"$samba_cv_found_xfs_header" = x"yes"; then
+AC_CACHE_CHECK([whether the sys_quota interface works with XFS],samba_cv_SYSQUOTA_WORKS_XFS,[
+SAVE_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS ${SAMBA_CONFIGURE_CPPFLAGS}"
+AC_TRY_COMPILE([
+#include "confdefs.h"
+#define NO_PROTO_H 1
+#define NO_CONFIG_H 1
+#define HAVE_SYS_QUOTAS 1
+#define HAVE_XFS_QUOTAS 1
+#include "${srcdir-.}/lib/sysquotas_xfs.c"
+],[],samba_cv_SYSQUOTA_WORKS_XFS=yes,samba_cv_SYSQUOTA_WORKS_XFS=no)
+CPPFLAGS="$SAVE_CPPFLAGS"
+])
+if test x"$samba_cv_SYSQUOTA_WORKS_XFS" = x"yes"; then
+ if test x"$samba_cv_WE_USE_SYS_QUOTAS" = x"yes"; then
+ AC_DEFINE(HAVE_XFS_QUOTAS,1,[Whether xfs quota support is available])
+ fi
+fi
+fi
+
+AC_CACHE_CHECK([whether the old quota support works],samba_cv_QUOTA_WORKS,[
+SAVE_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS ${SAMBA_CONFIGURE_CPPFLAGS}"
+AC_TRY_COMPILE([
+#include "confdefs.h"
+#define NO_PROTO_H 1
+#define NO_CONFIG_H 1
+#include "${srcdir-.}/smbd/quotas.c"
+],[],samba_cv_QUOTA_WORKS=yes,samba_cv_QUOTA_WORKS=no)
+CPPFLAGS="$SAVE_CPPFLAGS"
+])
+if test x"$samba_cv_QUOTA_WORKS" = x"yes"; then
+AC_MSG_CHECKING(whether to use the old quota support)
+ if test x"$samba_cv_WE_USE_SYS_QUOTAS" != x"yes"; then
+ if test x"$samba_cv_TRY_QUOTAS" != x"no"; then
+ AC_DEFINE(WITH_QUOTAS,1,[Whether to use disk quota support])
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ fi
+ else
+ AC_MSG_RESULT(no)
+ fi
+fi
+
+####################
+# End of quota check samba_cv_RUN_QUOTA_TESTS
+fi
+
+#################################################
+# check for experimental utmp accounting
+
+AC_MSG_CHECKING(whether to support utmp accounting)
+WITH_UTMP=yes
+AC_ARG_WITH(utmp,
+[AS_HELP_STRING([--with-utmp], [Include utmp accounting (default, if supported by OS)])],
+[ case "$withval" in
+ no)
+ WITH_UTMP=no
+ ;;
+ *)
+ WITH_UTMP=yes
+ ;;
+ esac ],
+)
+
+# utmp requires utmp.h
+# Note similar check earlier, when checking utmp details.
+
+if test x"$WITH_UTMP" = x"yes" -a x"$ac_cv_header_utmp_h" = x"no"; then
+ utmp_no_reason=", no utmp.h on $host_os"
+ WITH_UTMP=no
+fi
+
+# Display test results
+
+if test x"$WITH_UTMP" = x"yes"; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_UTMP,1,[Whether to include experimental utmp accounting])
+else
+ AC_MSG_RESULT(no$utmp_no_reason)
+fi
+
+INSTALLLIBCMD_SH=:
+INSTALLLIBCMD_A=:
+UNINSTALLLIBCMD_SH=:
+UNINSTALLLIBCMD_A=:
+
+if test $BLDSHARED = true; then
+ INSTALLLIBCMD_SH="\$(INSTALLCMD)"
+ UNINSTALLLIBCMD_SH="rm -f"
+fi
+if test $enable_static = yes; then
+ INSTALLLIBCMD_A="\$(INSTALLCMD)"
+ UNINSTALLLIBCMD_A="rm -f"
+fi
+
+#################################################
+# --disable-shared-libs
+# can be used to disable the internal use of shared libs altogether
+# (this only has an effect when building shared libs is enabled)
+#
+USESHARED=false
+AC_SUBST(USESHARED)
+
+AC_MSG_CHECKING(whether to use shared libraries internally)
+AC_ARG_ENABLE([shared-libs],
+ AS_HELP_STRING([--enable-shared-libs],
+ [Use shared libraries internally (default=yes)]),
+ [enable_shared_libs=$enableval],
+ [enable_shared_libs=yes])
+
+if test x"$enable_shared_libs" != x"no" ; then
+ USESHARED=$BLDSHARED
+fi
+
+AC_MSG_RESULT([$USESHARED])
+
+if test x"$enable_shared_libs" = x"yes" -a x"$BLDSHARED" != x"true" ; then
+ AC_MSG_WARN([--enable-shared-libs: no support for shared libraries])
+fi
+
+#################################################
+# --with-static-libs=LIBS:
+# link (internal) libs dynamically or statically?
+#
+# If a subsystem is built as a library then this controls whether they are
+# linked into Samba targets statically or dynamically:
+#
+# * If we build the shared library at all, we link dynamically by default.
+#
+# * We only link statically if we don't build shared or if the library
+# appears in the --with-static-libs configure option.
+#
+# Example:
+# --with-static-libs=libtalloc makes use of libtalloc.a instead
+# of linking the dynamic variant with -ltalloc.
+#
+# NOTE: This option only affects libraries that we do not only build
+# but that samba also links against as libraries (as opposed to linking
+# the plain object files. - This has to be configured in Makefile.in.
+# So in particular it does not harm to give invalid or unknown names here.
+#
+
+AC_ARG_WITH([static-libs],
+ [AS_HELP_STRING([--with-static-libs=LIBS],
+ [Comma-separated list of names of (internal) libraries to link statically (instead of dynamically)])],
+ [AS_IF([test $withval],
+ [for lib in `echo $withval | sed -e 's/,/ /g'` ; do
+ [lib=`echo $lib | tr '[a-z]' '[A-Z]'`]
+ eval LINK_$lib=STATIC
+ done], [])],
+ [])
+
+#
+# WORKAROUND:
+# until we have organized other internal subsystems (as util, registry
+# and smbconf) into shared libraries, we CAN NOT link libnetapi
+# dynamically to samba programs.
+#
+LINK_LIBNETAPI=STATIC
+
+LINK_LIBSMBCLIENT=STATIC
+
+#
+# The library versions are hardcoded here
+# and filled into the LIBFOO_SOVER variable.
+#
+# TODO: for talloc and tdb (at least), these should
+# be extracted from their respective source directories
+#
+SMB_LIBRARY(talloc, 1)
+SMB_LIBRARY(tdb, 1)
+SMB_LIBRARY(netapi, 0)
+SMB_LIBRARY(smbclient, 0)
+SMB_LIBRARY(smbsharemodes, 0)
+SMB_LIBRARY(addns, 0, no, [undefined API])
+
+
+
+#################################################
+# these tests are taken from the GNU fileutils package
+AC_CHECKING(how to get filesystem space usage)
+space=no
+
+# Test for statvfs64.
+if test $space = no; then
+ # SVR4
+ AC_CACHE_CHECK([statvfs64 function (SVR4)], fu_cv_sys_stat_statvfs64,
+ [AC_TRY_RUN([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/statvfs.h>
+ main ()
+ {
+ struct statvfs64 fsd;
+ exit (statvfs64 (".", &fsd));
+ }],
+ fu_cv_sys_stat_statvfs64=yes,
+ fu_cv_sys_stat_statvfs64=no,
+ fu_cv_sys_stat_statvfs64=cross)])
+ if test $fu_cv_sys_stat_statvfs64 = yes; then
+ space=yes
+ AC_DEFINE(STAT_STATVFS64,1,[Whether statvfs64() is available])
+ 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,1,[Whether statvfs() is available])
+ fi
+fi
+
+# smbd/statvfs.c assumes that statvfs.f_fsid is an integer.
+# This is not the case on ancient Linux systems.
+
+AC_CACHE_CHECK([that statvfs.f_fsid is an integer],samba_cv_fsid_int, [
+ AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/statvfs.h>],[struct statvfs buf; buf.f_fsid = 0],
+ samba_cv_fsid_int=yes,samba_cv_fsid_int=no)])
+if test x"$samba_cv_fsid_int" = x"yes"; then
+ AC_DEFINE(HAVE_FSID_INT, 1, [Whether statvfs.f_fsid is an integer])
+fi
+
+# fsusage.c assumes that statvfs has an f_frsize entry. Some weird
+# systems use f_bsize.
+AC_CACHE_CHECK([that statvfs.f_frsize works],samba_cv_frsize, [
+ AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/statvfs.h>],[struct statvfs buf; buf.f_frsize = 0],
+ samba_cv_frsize=yes,samba_cv_frsize=no)])
+if test x"$samba_cv_frsize" = x"yes"; then
+ AC_DEFINE(HAVE_FRSIZE, 1, [Whether statvfs.f_frsize exists])
+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,1,[Whether statfs requires 3 arguments])
+ 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,1,[Whether statfs requires two arguments and struct statfs has bsize property])
+ 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,1,[Whether statfs requires 4 arguments])
+ 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,1,[Whether statfs requires 2 arguments and struct statfs has 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,1,[Whether statfs requires 2 arguments and struct fs_data is available])
+ fi
+fi
+
+#
+# As a gating factor for large file support, in order to
+# use <4GB files we must have the following minimal support
+# available.
+# long long, and a 64 bit off_t or off64_t.
+# If we don't have all of these then disable large
+# file support.
+#
+AC_MSG_CHECKING([if large file support can be enabled])
+AC_TRY_COMPILE([
+#if defined(HAVE_LONGLONG) && (defined(HAVE_OFF64_T) || (defined(SIZEOF_OFF_T) && (SIZEOF_OFF_T == 8)))
+#include <sys/types.h>
+#else
+__COMPILE_ERROR_
+#endif
+],
+[int i],
+samba_cv_HAVE_EXPLICIT_LARGEFILE_SUPPORT=yes,samba_cv_HAVE_EXPLICIT_LARGEFILE_SUPPORT=no)
+if test x"$samba_cv_HAVE_EXPLICIT_LARGEFILE_SUPPORT" = x"yes"; then
+ AC_DEFINE(HAVE_EXPLICIT_LARGEFILE_SUPPORT,1,[Whether large file support can be enabled])
+fi
+AC_MSG_RESULT([$samba_cv_HAVE_EXPLICIT_LARGEFILE_SUPPORT])
+
+#################################################
+# check for cluster extensions
+
+AC_MSG_CHECKING(whether to include cluster support)
+AC_ARG_WITH(cluster-support,
+[AS_HELP_STRING([--with-cluster-support], [Enable cluster extensions (default=no)])])
+if test "x$with_cluster_support" = "xyes"; then
+ AC_DEFINE(CLUSTER_SUPPORT,1,[Whether to enable cluster extensions])
+ AC_MSG_RESULT(yes)
+else
+ AC_MSG_RESULT(no)
+fi
+
+
+#################################################
+# check for ACL support
+
+AC_MSG_CHECKING(whether to support ACLs)
+AC_ARG_WITH(acl-support,
+[AS_HELP_STRING([--with-acl-support], [Include ACL support (default=auto)])],
+[ case "$withval" in
+ yes|no)
+ with_acl_support="$withval"
+ ;;
+ esac ])
+
+if test x"$with_acl_support" = x ; then
+ with_acl_support="auto"
+fi
+
+AC_MSG_RESULT($with_acl_support)
+
+if test x"$with_acl_support" = x"no"; then
+ AC_MSG_RESULT(Disabling ACL support)
+ AC_DEFINE(HAVE_NO_ACLS,1,[Whether no ACLs support should be built in])
+else
+ AC_MSG_NOTICE(checking whether ACL support is available:)
+ case "$host_os" in
+ *sysv5*)
+ AC_MSG_NOTICE(Using UnixWare ACLs)
+ AC_DEFINE(HAVE_UNIXWARE_ACLS,1,[Whether UnixWare ACLs are available])
+ default_static_modules="$default_static_modules vfs_solarisacl"
+ ;;
+ *solaris*)
+ AC_MSG_NOTICE(Using solaris ACLs)
+ AC_DEFINE(HAVE_SOLARIS_ACLS,1,[Whether solaris ACLs are available])
+ ACL_LIBS="$ACL_LIBS -lsec"
+ default_static_modules="$default_static_modules vfs_solarisacl"
+ ;;
+ *hpux*)
+ AC_MSG_NOTICE(Using HPUX ACLs)
+ AC_DEFINE(HAVE_HPUX_ACLS,1,[Whether HPUX ACLs are available])
+ default_static_modules="$default_static_modules vfs_hpuxacl"
+ ;;
+ *irix*)
+ AC_MSG_NOTICE(Using IRIX ACLs)
+ AC_DEFINE(HAVE_IRIX_ACLS,1,[Whether IRIX ACLs are available])
+ default_static_modules="$default_static_modules vfs_irixacl"
+ ;;
+ *aix*)
+ AC_MSG_NOTICE(Using AIX ACLs)
+ AC_DEFINE(HAVE_AIX_ACLS,1,[Whether AIX ACLs are available])
+ default_static_modules="$default_static_modules vfs_aixacl"
+ ;;
+ *osf*)
+ AC_MSG_NOTICE(Using Tru64 ACLs)
+ AC_DEFINE(HAVE_TRU64_ACLS,1,[Whether Tru64 ACLs are available])
+ ACL_LIBS="$ACL_LIBS -lpacl"
+ default_static_modules="$default_static_modules vfs_tru64acl"
+ ;;
+ *darwin*)
+ AC_MSG_NOTICE(ACLs on Darwin currently not supported)
+ AC_DEFINE(HAVE_NO_ACLS,1,[Whether no ACLs support is available])
+ ;;
+ *)
+ AC_CHECK_LIB(acl,acl_get_file,[ACL_LIBS="$ACL_LIBS -lacl"])
+ case "$host_os" in
+ *linux*)
+ AC_CHECK_LIB(attr,getxattr,[ACL_LIBS="$ACL_LIBS -lattr"])
+ ;;
+ esac
+ AC_CACHE_CHECK([for POSIX ACL support],samba_cv_HAVE_POSIX_ACLS,[
+ acl_LIBS=$LIBS
+ LIBS="$LIBS $ACL_LIBS"
+ AC_TRY_LINK([
+ #include <sys/types.h>
+ #include <sys/acl.h>
+ ],[
+ acl_t acl;
+ int entry_id;
+ acl_entry_t *entry_p;
+ return acl_get_entry(acl, entry_id, entry_p);
+ ],
+ [samba_cv_HAVE_POSIX_ACLS=yes],
+ [samba_cv_HAVE_POSIX_ACLS=no])
+ LIBS=$acl_LIBS
+ ])
+ if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then
+ AC_MSG_NOTICE(Using posix ACLs)
+ AC_DEFINE(HAVE_POSIX_ACLS,1,[Whether POSIX ACLs are available])
+ AC_CACHE_CHECK([for acl_get_perm_np],samba_cv_HAVE_ACL_GET_PERM_NP,[
+ acl_LIBS=$LIBS
+ LIBS="$LIBS $ACL_LIBS"
+ AC_TRY_LINK([
+ #include <sys/types.h>
+ #include <sys/acl.h>
+ ],[
+ acl_permset_t permset_d;
+ acl_perm_t perm;
+ return acl_get_perm_np(permset_d, perm);
+ ],
+ [samba_cv_HAVE_ACL_GET_PERM_NP=yes],
+ [samba_cv_HAVE_ACL_GET_PERM_NP=no])
+ LIBS=$acl_LIBS
+ ])
+ if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then
+ AC_DEFINE(HAVE_ACL_GET_PERM_NP,1,[Whether acl_get_perm_np() is available])
+ fi
+ default_static_modules="$default_static_modules vfs_posixacl"
+ else
+ AC_MSG_NOTICE(ACL support is not avaliable)
+ AC_DEFINE(HAVE_NO_ACLS,1,[Whether no ACLs support is available])
+ fi
+ ;;
+ esac
+fi # with_acl_support
+
+
+
+#################################################
+# check for AIO support
+
+AC_MSG_CHECKING(whether to support asynchronous io)
+AC_ARG_WITH(aio-support,
+[AS_HELP_STRING([--with-aio-support], [Include asynchronous io support (default=no)])],
+[ case "$withval" in
+ yes)
+
+ AC_MSG_RESULT(yes)
+ case "$host_os" in
+ *)
+ AIO_LIBS=$LIBS
+ AC_CHECK_LIB(rt,aio_read,[AIO_LIBS="$LIBS -lrt"])
+ AC_CHECK_LIB(aio,aio_read,[AIO_LIBS="$LIBS -laio"])
+ AC_CACHE_CHECK([for asynchronous io support],samba_cv_HAVE_AIO,[
+ aio_LIBS=$LIBS
+ LIBS=$AIO_LIBS
+ AC_TRY_LINK([#include <sys/types.h>
+#include <aio.h>],
+[ struct aiocb a; return aio_read(&a);],
+samba_cv_HAVE_AIO=yes,samba_cv_HAVE_AIO=no)
+ LIBS=$aio_LIBS])
+ AC_CACHE_CHECK([for 64-bit asynchronous io support],samba_cv_HAVE_AIO64,[
+ aio_LIBS=$LIBS
+ LIBS=$AIO_LIBS
+ AC_TRY_LINK([#include <sys/types.h>
+#include <aio.h>],
+[ struct aiocb64 a; return aio_read64(&a);],
+samba_cv_HAVE_AIO64=yes,samba_cv_HAVE_AIO64=no)
+ LIBS=$aio_LIBS])
+ if test x"$samba_cv_HAVE_AIO64" = x"yes"; then
+ AC_DEFINE(HAVE_AIOCB64,1,[Whether 64 bit aio is available])
+ AC_DEFINE(WITH_AIO, 1, [Using asynchronous io])
+ LIBS=$AIO_LIBS
+ elif test x"$samba_cv_HAVE_AIO" = x"yes"; then
+ AC_DEFINE(WITH_AIO, 1, [Using asynchronous io])
+ LIBS=$AIO_LIBS
+ fi
+
+ if test x"$samba_cv_HAVE_AIO" = x"yes"; then
+ AC_MSG_CHECKING(for aio_read)
+ AC_LINK_IFELSE([#include <aio.h>
+int main() { struct aiocb a; return aio_read(&a); }],
+[AC_DEFINE(HAVE_AIO_READ, 1, [Have aio_read]) AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)])
+
+ AC_MSG_CHECKING(for aio_write)
+ AC_LINK_IFELSE([#include <aio.h>
+int main() { struct aiocb a; return aio_write(&a); }],
+[AC_DEFINE(HAVE_AIO_WRITE, 1, [Have aio_write]) AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)])
+
+ AC_MSG_CHECKING(for aio_fsync)
+ AC_LINK_IFELSE([#include <aio.h>
+int main() { struct aiocb a; return aio_fsync(1, &a); }],
+[AC_DEFINE(HAVE_AIO_FSYNC, 1, [Have aio_fsync]) AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)])
+
+ AC_MSG_CHECKING(for aio_return)
+ AC_LINK_IFELSE([#include <aio.h>
+int main() { struct aiocb a; return aio_return(&a); }],
+[AC_DEFINE(HAVE_AIO_RETURN, 1, [Have aio_return]) AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)])
+
+ AC_MSG_CHECKING(for aio_error)
+ AC_LINK_IFELSE([#include <aio.h>
+int main() { struct aiocb a; return aio_error(&a); }],
+[AC_DEFINE(HAVE_AIO_ERROR, 1, [Have aio_error]) AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)])
+
+ AC_MSG_CHECKING(for aio_cancel)
+ AC_LINK_IFELSE([#include <aio.h>
+int main() { struct aiocb a; return aio_cancel(1, &a); }],
+[AC_DEFINE(HAVE_AIO_CANCEL, 1, [Have aio_cancel]) AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)])
+
+ AC_MSG_CHECKING(for aio_suspend)
+ AC_LINK_IFELSE([#include <aio.h>
+int main() { struct aiocb a; return aio_suspend(&a, 1, NULL); }],
+[AC_DEFINE(HAVE_AIO_SUSPEND, 1, [Have aio_suspend]) AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)])
+ fi
+
+ if test x"$samba_cv_HAVE_AIO64" = x"yes"; then
+ AC_MSG_CHECKING(for aio_read64)
+ AC_LINK_IFELSE([#include <aio.h>
+int main() { struct aiocb a; return aio_read64(&a); }],
+[AC_DEFINE(HAVE_AIO_READ64, 1, [Have aio_read64]) AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)])
+
+ AC_MSG_CHECKING(for aio_write64)
+ AC_LINK_IFELSE([#include <aio.h>
+int main() { struct aiocb a; return aio_write64(&a); }],
+[AC_DEFINE(HAVE_AIO_WRITE64, 1, [Have aio_write64]) AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)])
+
+ AC_MSG_CHECKING(for aio_fsync64)
+ AC_LINK_IFELSE([#include <aio.h>
+int main() { struct aiocb a; return aio_fsync64(1, &a); }],
+[AC_DEFINE(HAVE_AIO_FSYNC64, 1, [Have aio_fsync64]) AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)])
+
+ AC_MSG_CHECKING(for aio_return64)
+ AC_LINK_IFELSE([#include <aio.h>
+int main() { struct aiocb a; return aio_return64(&a); }],
+[AC_DEFINE(HAVE_AIO_RETURN64, 1, [Have aio_return64]) AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)])
+
+ AC_MSG_CHECKING(for aio_error64)
+ AC_LINK_IFELSE([#include <aio.h>
+int main() { struct aiocb a; return aio_error64(&a); }],
+[AC_DEFINE(HAVE_AIO_ERROR64, 1, [Have aio_error64]) AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)])
+
+ AC_MSG_CHECKING(for aio_cancel64)
+ AC_LINK_IFELSE([#include <aio.h>
+int main() { struct aiocb a; return aio_cancel64(1, &a); }],
+[AC_DEFINE(HAVE_AIO_CANCEL64, 1, [Have aio_cancel64]) AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)])
+
+ AC_MSG_CHECKING(for aio_suspend64)
+ AC_LINK_IFELSE([#include <aio.h>
+int main() { struct aiocb a; return aio_suspend64(&a, 1, NULL); }],
+[AC_DEFINE(HAVE_AIO_SUSPEND64, 1, [Have aio_suspend64]) AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)])
+ fi
+ ;;
+ esac
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ AC_DEFINE(HAVE_NO_AIO,1,[Whether no asynchronous io support is available])
+ ;;
+ esac ],
+ AC_DEFINE(HAVE_NO_AIO,1,[Whether no asynchronous io support should be built in])
+ AC_MSG_RESULT(no)
+)
+
+if test x"$samba_cv_HAVE_AIO" = x"yes"; then
+ if test x"$samba_cv_msghdr_msg_control" = x"yes" -o \
+ x"$samba_cv_msghdr_msg_acctright" = x"yes"; then
+ default_shared_modules="$default_shared_modules vfs_aio_fork"
+ fi
+fi
+
+#################################################
+# check for sendfile support
+
+with_sendfile_support=yes
+AC_MSG_CHECKING(whether to check to support sendfile)
+AC_ARG_WITH(sendfile-support,
+[AS_HELP_STRING([--with-sendfile-support], [Check for sendfile support (default=yes)])],
+[ case "$withval" in
+ yes)
+
+ AC_MSG_RESULT(yes);
+
+ case "$host_os" in
+ *linux*)
+ AC_CACHE_CHECK([for linux sendfile64 support],samba_cv_HAVE_SENDFILE64,[
+ AC_TRY_LINK([#include <sys/sendfile.h>],
+[\
+int tofd, fromfd;
+off64_t offset;
+size_t total;
+ssize_t nwritten = sendfile64(tofd, fromfd, &offset, total);
+],
+samba_cv_HAVE_SENDFILE64=yes,samba_cv_HAVE_SENDFILE64=no)])
+
+ AC_CACHE_CHECK([for linux sendfile support],samba_cv_HAVE_SENDFILE,[
+ AC_TRY_LINK([#include <sys/sendfile.h>],
+[\
+int tofd, fromfd;
+off_t offset;
+size_t total;
+ssize_t nwritten = sendfile(tofd, fromfd, &offset, total);
+],
+samba_cv_HAVE_SENDFILE=yes,samba_cv_HAVE_SENDFILE=no)])
+
+# Try and cope with broken Linux sendfile....
+ AC_CACHE_CHECK([for broken linux sendfile support],samba_cv_HAVE_BROKEN_LINUX_SENDFILE,[
+ AC_TRY_LINK([\
+#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
+#undef _FILE_OFFSET_BITS
+#endif
+#include <sys/sendfile.h>],
+[\
+int tofd, fromfd;
+off_t offset;
+size_t total;
+ssize_t nwritten = sendfile(tofd, fromfd, &offset, total);
+],
+samba_cv_HAVE_BROKEN_LINUX_SENDFILE=yes,samba_cv_HAVE_BROKEN_LINUX_SENDFILE=no)])
+
+ if test x"$samba_cv_HAVE_SENDFILE64" = x"yes"; then
+ AC_DEFINE(HAVE_SENDFILE64,1,[Whether 64-bit sendfile() is available])
+ AC_DEFINE(LINUX_SENDFILE_API,1,[Whether linux sendfile() API is available])
+ AC_DEFINE(WITH_SENDFILE,1,[Whether sendfile() should be used])
+ elif test x"$samba_cv_HAVE_SENDFILE" = x"yes"; then
+ AC_DEFINE(HAVE_SENDFILE,1,[Whether sendfile() is available])
+ AC_DEFINE(LINUX_SENDFILE_API,1,[Whether linux sendfile() API is available])
+ AC_DEFINE(WITH_SENDFILE,1,[Whether sendfile() should be used])
+ elif test x"$samba_cv_HAVE_BROKEN_LINUX_SENDFILE" = x"yes"; then
+ AC_DEFINE(LINUX_BROKEN_SENDFILE_API,1,[Whether (linux) sendfile() is broken])
+ AC_DEFINE(WITH_SENDFILE,1,[Whether sendfile should be used])
+ else
+ AC_MSG_RESULT(no);
+ fi
+
+ ;;
+ *freebsd* | *dragonfly* )
+ AC_CACHE_CHECK([for freebsd sendfile support],samba_cv_HAVE_SENDFILE,[
+ AC_TRY_LINK([\
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/uio.h>],
+[\
+ int fromfd, tofd, ret, total=0;
+ off_t offset, nwritten;
+ struct sf_hdtr hdr;
+ struct iovec hdtrl;
+ hdr.headers = &hdtrl;
+ hdr.hdr_cnt = 1;
+ hdr.trailers = NULL;
+ hdr.trl_cnt = 0;
+ hdtrl.iov_base = NULL;
+ hdtrl.iov_len = 0;
+ ret = sendfile(fromfd, tofd, offset, total, &hdr, &nwritten, 0);
+],
+samba_cv_HAVE_SENDFILE=yes,samba_cv_HAVE_SENDFILE=no)])
+
+ if test x"$samba_cv_HAVE_SENDFILE" = x"yes"; then
+ AC_DEFINE(HAVE_SENDFILE,1,[Whether sendfile() support is available])
+ AC_DEFINE(FREEBSD_SENDFILE_API,1,[Whether the FreeBSD sendfile() API is available])
+ AC_DEFINE(WITH_SENDFILE,1,[Whether sendfile() support should be included])
+ else
+ AC_MSG_RESULT(no);
+ fi
+ ;;
+
+ *hpux*)
+ AC_CACHE_CHECK([for hpux sendfile64 support],samba_cv_HAVE_SENDFILE64,[
+ AC_TRY_LINK([\
+#include <sys/socket.h>
+#include <sys/uio.h>],
+[\
+ int fromfd, tofd;
+ size_t total=0;
+ struct iovec hdtrl[2];
+ ssize_t nwritten;
+ off64_t offset;
+
+ hdtrl[0].iov_base = 0;
+ hdtrl[0].iov_len = 0;
+
+ nwritten = sendfile64(tofd, fromfd, offset, total, &hdtrl[0], 0);
+],
+samba_cv_HAVE_SENDFILE64=yes,samba_cv_HAVE_SENDFILE64=no)])
+ if test x"$samba_cv_HAVE_SENDFILE64" = x"yes"; then
+ AC_DEFINE(HAVE_SENDFILE64,1,[Whether sendfile64() is available])
+ AC_DEFINE(HPUX_SENDFILE_API,1,[Whether the hpux sendfile() API is available])
+ AC_DEFINE(WITH_SENDFILE,1,[Whether sendfile() support should be included])
+ else
+ AC_MSG_RESULT(no);
+ fi
+
+ AC_CACHE_CHECK([for hpux sendfile support],samba_cv_HAVE_SENDFILE,[
+ AC_TRY_LINK([\
+#include <sys/socket.h>
+#include <sys/uio.h>],
+[\
+ int fromfd, tofd;
+ size_t total=0;
+ struct iovec hdtrl[2];
+ ssize_t nwritten;
+ off_t offset;
+
+ hdtrl[0].iov_base = 0;
+ hdtrl[0].iov_len = 0;
+
+ nwritten = sendfile(tofd, fromfd, offset, total, &hdtrl[0], 0);
+],
+samba_cv_HAVE_SENDFILE=yes,samba_cv_HAVE_SENDFILE=no)])
+ if test x"$samba_cv_HAVE_SENDFILE" = x"yes"; then
+ AC_DEFINE(HAVE_SENDFILE,1,[Whether sendfile() is available])
+ AC_DEFINE(HPUX_SENDFILE_API,1,[Whether the hpux sendfile() API is available])
+ AC_DEFINE(WITH_SENDFILE,1,[Whether sendfile() support should be included])
+ else
+ AC_MSG_RESULT(no);
+ fi
+ ;;
+
+ *solaris*)
+ AC_CHECK_LIB(sendfile,sendfilev)
+ AC_CACHE_CHECK([for solaris sendfilev64 support],samba_cv_HAVE_SENDFILEV64,[
+ AC_TRY_LINK([\
+#include <sys/sendfile.h>],
+[\
+ int sfvcnt;
+ size_t xferred;
+ struct sendfilevec vec[2];
+ ssize_t nwritten;
+ int tofd;
+
+ sfvcnt = 2;
+
+ vec[0].sfv_fd = SFV_FD_SELF;
+ vec[0].sfv_flag = 0;
+ vec[0].sfv_off = 0;
+ vec[0].sfv_len = 0;
+
+ vec[1].sfv_fd = 0;
+ vec[1].sfv_flag = 0;
+ vec[1].sfv_off = 0;
+ vec[1].sfv_len = 0;
+ nwritten = sendfilev64(tofd, vec, sfvcnt, &xferred);
+],
+samba_cv_HAVE_SENDFILEV64=yes,samba_cv_HAVE_SENDFILEV64=no)])
+
+ if test x"$samba_cv_HAVE_SENDFILEV64" = x"yes"; then
+ AC_DEFINE(HAVE_SENDFILEV64,1,[Whether sendfilev64() is available])
+ AC_DEFINE(SOLARIS_SENDFILE_API,1,[Whether the soloris sendfile() API is available])
+ AC_DEFINE(WITH_SENDFILE,1,[Whether sendfile() support should be included])
+ else
+ AC_MSG_RESULT(no);
+ fi
+
+ AC_CACHE_CHECK([for solaris sendfilev support],samba_cv_HAVE_SENDFILEV,[
+ AC_TRY_LINK([\
+#include <sys/sendfile.h>],
+[\
+ int sfvcnt;
+ size_t xferred;
+ struct sendfilevec vec[2];
+ ssize_t nwritten;
+ int tofd;
+
+ sfvcnt = 2;
+
+ vec[0].sfv_fd = SFV_FD_SELF;
+ vec[0].sfv_flag = 0;
+ vec[0].sfv_off = 0;
+ vec[0].sfv_len = 0;
+
+ vec[1].sfv_fd = 0;
+ vec[1].sfv_flag = 0;
+ vec[1].sfv_off = 0;
+ vec[1].sfv_len = 0;
+ nwritten = sendfilev(tofd, vec, sfvcnt, &xferred);
+],
+samba_cv_HAVE_SENDFILEV=yes,samba_cv_HAVE_SENDFILEV=no)])
+
+ if test x"$samba_cv_HAVE_SENDFILEV" = x"yes"; then
+ AC_DEFINE(HAVE_SENDFILEV,1,[Whether sendfilev() is available])
+ AC_DEFINE(SOLARIS_SENDFILE_API,1,[Whether the solaris sendfile() API is available])
+ AC_DEFINE(WITH_SENDFILE,1,[Whether to include sendfile() support])
+ else
+ AC_MSG_RESULT(no);
+ fi
+ ;;
+ *aix*)
+ AC_CACHE_CHECK([for AIX send_file support],samba_cv_HAVE_SENDFILE,[
+ AC_TRY_LINK([\
+#include <sys/socket.h>],
+[\
+ int fromfd, tofd;
+ size_t total=0;
+ struct sf_parms hdtrl;
+ ssize_t nwritten;
+ off64_t offset;
+
+ hdtrl.header_data = 0;
+ hdtrl.header_length = 0;
+ hdtrl.file_descriptor = fromfd;
+ hdtrl.file_offset = 0;
+ hdtrl.file_bytes = 0;
+ hdtrl.trailer_data = 0;
+ hdtrl.trailer_length = 0;
+
+ nwritten = send_file(&tofd, &hdtrl, 0);
+],
+samba_cv_HAVE_SENDFILE=yes,samba_cv_HAVE_SENDFILE=no)])
+ if test x"$samba_cv_HAVE_SENDFILE" = x"yes"; then
+ AC_DEFINE(HAVE_SENDFILE,1,[Whether sendfile() is available])
+ AC_DEFINE(AIX_SENDFILE_API,1,[Whether the AIX send_file() API is available])
+ AC_DEFINE(WITH_SENDFILE,1,[Whether to include sendfile() support])
+ else
+ AC_MSG_RESULT(no);
+ fi
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(yes)
+)
+
+############################################
+# See if we have the Linux readahead syscall.
+
+AC_CACHE_CHECK([for Linux readahead],
+ samba_cv_HAVE_LINUX_READAHEAD,[
+ AC_TRY_LINK([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <fcntl.h>],
+ [ssize_t err = readahead(0,0,0x80000);],
+ samba_cv_HAVE_LINUX_READAHEAD=yes,
+ samba_cv_HAVE_LINUX_READAHEAD=no)])
+
+if test x"$samba_cv_HAVE_LINUX_READAHEAD" = x"yes"; then
+ AC_DEFINE(HAVE_LINUX_READAHEAD,1,
+ [Whether Linux readahead is available])
+fi
+
+AC_HAVE_DECL(readahead, [#include <fcntl.h>])
+
+############################################
+# See if we have the posix_fadvise syscall.
+
+AC_CACHE_CHECK([for posix_fadvise],
+ samba_cv_HAVE_POSIX_FADVISE,[
+ AC_TRY_LINK([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <fcntl.h>],
+ [ssize_t err = posix_fadvise(0,0,0x80000,POSIX_FADV_WILLNEED);],
+ samba_cv_HAVE_POSIX_FADVISE=yes,
+ samba_cv_HAVE_POSIX_FADVISE=no)])
+
+if test x"$samba_cv_HAVE_POSIX_FADVISE" = x"yes"; then
+ AC_DEFINE(HAVE_POSIX_FADVISE,1,
+ [Whether posix_fadvise is available])
+fi
+
+############################################
+# See if we have the Linux splice syscall.
+
+AC_CACHE_CHECK([for Linux splice],
+ samba_cv_HAVE_LINUX_SPLICE,[
+ AC_TRY_LINK([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <fcntl.h>],
+ [long ret = splice(0,0,1,0,400,0);],
+ samba_cv_HAVE_LINUX_SPLICE=yes,
+ samba_cv_HAVE_LINUX_SPLICE=no)])
+
+if test x"$samba_cv_HAVE_LINUX_SPLICE" = x"yes"; then
+ AC_DEFINE(HAVE_LINUX_SPLICE,1,
+ [Whether Linux splice is available])
+fi
+
+AC_HAVE_DECL(splice, [#include <fcntl.h>])
+
+
+#################################################
+# Check whether winbind is supported on this platform. If so we need to
+# build and install client programs, sbin programs and shared libraries
+
+AC_MSG_CHECKING(whether to build winbind)
+
+# Initially, the value of $host_os decides whether winbind is supported
+
+HAVE_WINBIND=yes
+
+# Define the winbind shared library name and any specific linker flags
+# it needs to be built with.
+
+WINBIND_NSS="nsswitch/libnss_winbind.$SHLIBEXT"
+WINBIND_WINS_NSS="nsswitch/libnss_wins.$SHLIBEXT"
+WINBIND_NSS_LDSHFLAGS=$LDSHFLAGS
+NSSSONAMEVERSIONSUFFIX=""
+WINBIND_NSS_PTHREAD=""
+
+case "$host_os" in
+ *linux*)
+ NSSSONAMEVERSIONSUFFIX=".2"
+ WINBIND_NSS_EXTRA_OBJS="nsswitch/winbind_nss_linux.o"
+ ;;
+ *freebsd[[5-9]]*)
+ # FreeBSD winbind client is implemented as a wrapper around
+ # the Linux version.
+ NSSSONAMEVERSIONSUFFIX=".1"
+ WINBIND_NSS_EXTRA_OBJS="nsswitch/winbind_nss_freebsd.o \
+ nsswitch/winbind_nss_linux.o"
+ WINBIND_NSS="nsswitch/nss_winbind.$SHLIBEXT"
+ WINBIND_WINS_NSS="nsswitch/nss_wins.$SHLIBEXT"
+ ;;
+
+ *netbsd*[[3-9]]*)
+ # NetBSD winbind client is implemented as a wrapper
+ # around the Linux version. It needs getpwent_r() to
+ # indicate libc's use of the correct nsdispatch API.
+ #
+ if test x"$ac_cv_func_getpwent_r" = x"yes"; then
+ WINBIND_NSS_EXTRA_OBJS="\
+ nsswitch/winbind_nss_netbsd.o \
+ nsswitch/winbind_nss_linux.o"
+ WINBIND_NSS="nsswitch/nss_winbind.$SHLIBEXT"
+ WINBIND_WINS_NSS="nsswitch/nss_wins.$SHLIBEXT"
+ else
+ HAVE_WINBIND=no
+ winbind_no_reason=", getpwent_r is missing on $host_os so winbind is unsupported"
+ fi
+ ;;
+ *irix*)
+ # IRIX has differently named shared libraries
+ WINBIND_NSS_EXTRA_OBJS="nsswitch/winbind_nss_irix.o"
+ WINBIND_NSS="nsswitch/libns_winbind.$SHLIBEXT"
+ WINBIND_WINS_NSS="nsswitch/libns_wins.$SHLIBEXT"
+ ;;
+ *solaris*)
+ # Solaris winbind client is implemented as a wrapper around
+ # the Linux version.
+ NSSSONAMEVERSIONSUFFIX=".1"
+ WINBIND_NSS_EXTRA_OBJS="nsswitch/winbind_nss_solaris.o \
+ nsswitch/winbind_nss_linux.o"
+ WINBIND_NSS_EXTRA_LIBS="${LIBREPLACE_NETWORK_LIBS}"
+ PAM_WINBIND_EXTRA_LIBS="${LIBREPLACE_NETWORK_LIBS}"
+ ;;
+ *hpux11*)
+ WINBIND_NSS_EXTRA_OBJS="nsswitch/winbind_nss_solaris.o"
+ ;;
+ *aix*)
+ # AIX has even differently named shared libraries. No
+ # WINS support has been implemented yet.
+ WINBIND_NSS_EXTRA_OBJS="nsswitch/winbind_nss_aix.o"
+ WINBIND_NSS_LDSHFLAGS="-Wl,-bexpall,-bM:SRE,-ewb_aix_init"
+ WINBIND_NSS="nsswitch/WINBIND"
+ WINBIND_WINS_NSS=""
+ ;;
+ *)
+ HAVE_WINBIND=no
+ winbind_no_reason=", unsupported on $host_os"
+ ;;
+esac
+
+# Check the setting of --with-winbind
+
+AC_ARG_WITH(winbind,
+[AS_HELP_STRING([--with-winbind], [Build winbind (default, if supported by OS)])],
+[
+ case "$withval" in
+ yes)
+ HAVE_WINBIND=yes
+ ;;
+ no)
+ HAVE_WINBIND=no
+ winbind_reason=""
+ ;;
+ esac ],
+)
+
+# We need unix domain sockets for winbind
+
+if test x"$HAVE_WINBIND" = x"yes"; then
+ if test x"$libreplace_cv_HAVE_UNIXSOCKET" = x"no"; then
+ winbind_no_reason=", no unix domain socket support on $host_os"
+ HAVE_WINBIND=no
+ fi
+fi
+
+# Display test results
+
+if test x"$HAVE_WINBIND" = x"no"; then
+ WINBIND_NSS=""
+ WINBIND_WINS_NSS=""
+fi
+
+if test x"$enable_developer" = x"yes" -a x"$LINK_LIBWBCLIENT" = x"STATIC" ; then
+ BUILD_LIBWBCLIENT_SHARED=no
+else
+ BUILD_LIBWBCLIENT_SHARED=yes
+fi
+
+LIBWBCLIENT_SHARED_TARGET=bin/libwbclient.$SHLIBEXT
+LIBWBCLIENT_STATIC_TARGET=bin/libwbclient.a
+LIBWBCLIENT_SOVER=0
+if test $BLDSHARED = true -a x"$HAVE_WINBIND" = x"yes" -a x"$BUILD_LIBWBCLIENT_SHARED" = x"yes"; then
+ NSS_MODULES="${WINBIND_NSS} ${WINBIND_WINS_NSS}"
+ ## Only worry about libwbclient if we have shared library support
+ ## and winbindd
+ LIBWBCLIENT_SHARED=$LIBWBCLIENT_SHARED_TARGET
+ LIBWBCLIENT=libwbclient
+ INSTALL_LIBWBCLIENT=installlibwbclient
+ UNINSTALL_LIBWBCLIENT=uninstalllibwbclient
+ WINBIND_LIBS="-lwbclient"
+else
+ LIBWBCLIENT_STATIC=$LIBWBCLIENT_STATIC_TARGET
+fi
+
+if test x"$HAVE_WINBIND" = x"yes"; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_WINBIND,1,[Whether to build winbind])
+
+ EXTRA_BIN_PROGS="$EXTRA_BIN_PROGS bin/wbinfo\$(EXEEXT)"
+ EXTRA_SBIN_PROGS="$EXTRA_SBIN_PROGS bin/winbindd\$(EXEEXT)"
+ if test $BLDSHARED = true -a x"$create_pam_modules" = x"yes"; then
+ PAM_MODULES="$PAM_MODULES pam_winbind"
+ INSTALL_PAM_MODULES="installpammodules"
+ UNINSTALL_PAM_MODULES="uninstallpammodules"
+ fi
+else
+ AC_MSG_RESULT(no$winbind_no_reason)
+fi
+
+AC_CHECK_LIB(pthread, pthread_mutex_lock, [WINBIND_NSS_PTHREAD="-lpthread"
+ AC_DEFINE(HAVE_PTHREAD, 1, [whether pthread exists])])
+
+AC_SUBST(WINBIND_NSS_PTHREAD)
+AC_SUBST(WINBIND_NSS)
+AC_SUBST(WINBIND_WINS_NSS)
+AC_SUBST(WINBIND_NSS_LDSHFLAGS)
+AC_SUBST(WINBIND_NSS_EXTRA_OBJS)
+AC_SUBST(WINBIND_NSS_EXTRA_LIBS)
+AC_SUBST(NSSSONAMEVERSIONSUFFIX)
+AC_SUBST(PAM_WINBIND_EXTRA_LIBS)
+
+AC_SUBST(WINBIND_KRB5_LOCATOR)
+
+# Solaris 10 does have new member in nss_XbyY_key
+AC_CHECK_MEMBER(union nss_XbyY_key.ipnode.af_family,
+ AC_DEFINE(HAVE_NSS_XBYY_KEY_IPNODE, 1, [Defined if union nss_XbyY_key has ipnode field]),,
+ [#include <nss_dbdefs.h>])
+
+# Solaris has some extra fields in struct passwd that need to be
+# initialised otherwise nscd crashes.
+
+AC_CHECK_MEMBER(struct passwd.pw_comment,
+ AC_DEFINE(HAVE_PASSWD_PW_COMMENT, 1, [Defined if struct passwd has pw_comment field]),,
+ [#include <pwd.h>])
+
+AC_CHECK_MEMBER(struct passwd.pw_age,
+ AC_DEFINE(HAVE_PASSWD_PW_AGE, 1, [Defined if struct passwd has pw_age field]),,
+ [#include <pwd.h>])
+
+# AIX 4.3.x and 5.1 do not have as many members in
+# struct secmethod_table as AIX 5.2
+AC_CHECK_MEMBERS([struct secmethod_table.method_attrlist], , ,
+ [#include <usersec.h>])
+AC_CHECK_MEMBERS([struct secmethod_table.method_version], , ,
+ [#include <usersec.h>])
+
+AC_CACHE_CHECK([for SO_PEERCRED],samba_cv_HAVE_PEERCRED,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/socket.h>],
+[struct ucred cred;
+ socklen_t cred_len;
+ int ret = getsockopt(0, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len);
+],
+samba_cv_HAVE_PEERCRED=yes,samba_cv_HAVE_PEERCRED=no,samba_cv_HAVE_PEERCRED=cross)])
+if test x"$samba_cv_HAVE_PEERCRED" = x"yes"; then
+ AC_DEFINE(HAVE_PEERCRED,1,[Whether we can use SO_PEERCRED to get socket credentials])
+fi
+
+
+#################################################
+# Check to see if we should use the included popt
+
+AC_ARG_WITH(included-popt,
+[AS_HELP_STRING([--with-included-popt], [use bundled popt library, not from system])],
+[
+ case "$withval" in
+ yes)
+ INCLUDED_POPT=yes
+ ;;
+ no)
+ INCLUDED_POPT=no
+ ;;
+ esac ],
+)
+if test x"$INCLUDED_POPT" != x"yes"; then
+ AC_CHECK_LIB(popt, poptGetContext,
+ INCLUDED_POPT=no, INCLUDED_POPT=yes)
+fi
+
+AC_MSG_CHECKING(whether to use included popt)
+if test x"$INCLUDED_POPT" = x"yes"; then
+ AC_MSG_RESULT(yes)
+ BUILD_POPT='$(POPT_OBJ)'
+ POPTLIBS='$(POPT_OBJ)'
+ FLAGS1="-I\$(srcdir)/popt"
+else
+ AC_MSG_RESULT(no)
+ BUILD_POPT=""
+ POPTLIBS="-lpopt"
+fi
+AC_SUBST(BUILD_POPT)
+AC_SUBST(POPTLIBS)
+AC_SUBST(FLAGS1)
+
+#################################################
+# Check if user wants DNS service discovery support
+
+AC_ARG_ENABLE(dnssd,
+[AS_HELP_STRING([--enable-dnssd], [Enable DNS service discovery support (default=auto)])])
+
+AC_SUBST(DNSSD_LIBS)
+if test x"$enable_dnssd" != x"no"; then
+ have_dnssd_support=yes
+
+ AC_CHECK_HEADERS(dns_sd.h)
+ if test x"$ac_cv_header_dns_sd_h" != x"yes"; then
+ have_dnssd_support=no
+ fi
+
+ # On Darwin the DNSSD API is in libc, but on other platforms it's
+ # probably in -ldns_sd
+ AC_CHECK_FUNCS(DNSServiceRegister)
+ AC_CHECK_LIB_EXT(dns_sd, DNSSD_LIBS, DNSServiceRegister)
+ if test x"$ac_cv_func_DNSServiceRegister" != x"yes" -a \
+ x"$ac_cv_lib_ext_DNSServiceRegister" != x"yes"; then
+ have_dnssd_support=no
+ fi
+
+ if test x"$have_dnssd_support" = x"yes"; then
+ AC_DEFINE(WITH_DNSSD_SUPPORT, 1,
+ [Whether to enable DNS service discovery support])
+ else
+ if test x"$enable_dnssd" = x"yes"; then
+ AC_MSG_ERROR(DNS service discovery support not available)
+ fi
+ fi
+
+fi
+
+#################################################
+# Check to see if we should use the included iniparser
+
+AC_ARG_WITH(included-iniparser,
+[AS_HELP_STRING([--with-included-iniparser], [use bundled iniparser library, not from system])],
+[
+ case "$withval" in
+ yes)
+ INCLUDED_INIPARSER=yes
+ ;;
+ no)
+ INCLUDED_INIPARSER=no
+ ;;
+ esac ],
+)
+if test x"$INCLUDED_INIPARSER" != x"yes"; then
+ AC_CHECK_LIB(iniparser, iniparser_load,
+ INCLUDED_INIPARSER=no, INCLUDED_INIPARSER=yes)
+fi
+
+AC_MSG_CHECKING(whether to use included iniparser)
+if test x"$INCLUDED_INIPARSER" = x"yes"; then
+ AC_MSG_RESULT(yes)
+ BUILD_INIPARSER='$(INIPARSER_OBJ)'
+ INIPARSERLIBS=""
+ FLAGS1="$FLAGS1 -I\$(srcdir)/iniparser/src"
+else
+ AC_MSG_RESULT(no)
+ BUILD_INIPARSER=""
+ INIPARSERLIBS="-liniparser"
+fi
+AC_SUBST(BUILD_INIPARSER)
+AC_SUBST(INIPARSERLIBS)
+AC_SUBST(FLAGS1)
+
+
+
+# Checks for the vfs_fileid module
+# Start
+AC_CHECK_FUNC(getmntent)
+
+AC_CHECK_HEADERS(sys/statfs.h)
+
+AC_MSG_CHECKING([vfs_fileid: checking for statfs() and struct statfs.f_fsid)])
+AC_CACHE_VAL(vfsfileid_cv_statfs,[
+ AC_TRY_RUN([
+ #include <sys/types.h>
+ #include <sys/statfs.h>
+ int main(void)
+ {
+ struct statfs fsd;
+ fsid_t fsid = fsd.f_fsid;
+ return statfs (".", &fsd);
+ }],
+ vfsfileid_cv_statfs=yes,
+ vfsfileid_cv_statfs=no,
+ vfsfileid_cv_statfs=cross)
+])
+AC_MSG_RESULT($vfsfileid_cv_statfs)
+
+if test x"$ac_cv_func_getmntent" = x"yes" -a \
+ x"$vfsfileid_cv_statfs" = x"yes"; then
+ default_shared_modules="$default_shared_modules vfs_fileid"
+fi
+# End
+# Checks for the vfs_fileid module
+
+
+for i in `echo $default_static_modules | sed -e 's/,/ /g'`
+do
+ eval MODULE_DEFAULT_$i=STATIC
+done
+
+for i in `echo $default_shared_modules | sed -e 's/,/ /g'`
+do
+ dnl Fall back to static if we cannot build shared libraries
+ eval MODULE_DEFAULT_$i=STATIC
+
+ if test $BLDSHARED = true; then
+ eval MODULE_DEFAULT_$i=SHARED
+ fi
+done
+
+dnl Always build these modules static
+MODULE_rpc_spoolss=STATIC
+MODULE_rpc_srvsvc=STATIC
+MODULE_idmap_tdb=STATIC
+MODULE_idmap_passdb=STATIC
+MODULE_idmap_nss=STATIC
+
+MODULE_nss_info_template=STATIC
+
+AC_ARG_WITH(static-modules,
+[AS_HELP_STRING([--with-static-modules=MODULES], [Comma-separated list of names of modules to statically link in])],
+[ if test $withval; then
+ for i in `echo $withval | sed -e 's/,/ /g'`
+ do
+ eval MODULE_$i=STATIC
+ done
+fi ])
+
+AC_ARG_WITH(shared-modules,
+[AS_HELP_STRING([--with-shared-modules=MODULES], [Comma-separated list of names of modules to build shared])],
+[ if test $withval; then
+ for i in `echo $withval | sed -e 's/,/ /g'`
+ do
+ eval MODULE_$i=SHARED
+ done
+fi ])
+
+SMB_MODULE(pdb_ldap, passdb/pdb_ldap.o passdb/pdb_nds.o, "bin/ldapsam.$SHLIBEXT", PDB,
+ [ PASSDB_LIBS="$PASSDB_LIBS $LDAP_LIBS" ] )
+SMB_MODULE(pdb_smbpasswd, passdb/pdb_smbpasswd.o, "bin/smbpasswd.$SHLIBEXT", PDB)
+SMB_MODULE(pdb_tdbsam, passdb/pdb_tdb.o, "bin/tdbsam.$SHLIBEXT", PDB)
+SMB_SUBSYSTEM(PDB,passdb/pdb_interface.o)
+
+
+SMB_MODULE(rpc_lsarpc, \$(RPC_LSA_OBJ), "bin/librpc_lsarpc.$SHLIBEXT", RPC)
+SMB_MODULE(rpc_winreg, \$(RPC_REG_OBJ), "bin/librpc_winreg.$SHLIBEXT", RPC)
+SMB_MODULE(rpc_initshutdown, \$(RPC_INITSHUTDOWN_OBJ), "bin/librpc_initshutdown.$SHLIBEXT", RPC)
+SMB_MODULE(rpc_dssetup, \$(RPC_DSSETUP_OBJ), "bin/librpc_dssetup.$SHLIBEXT", RPC)
+SMB_MODULE(rpc_wkssvc, \$(RPC_WKS_OBJ), "bin/librpc_wkssvc.$SHLIBEXT", RPC)
+SMB_MODULE(rpc_svcctl2, \$(RPC_SVCCTL_OBJ), "bin/librpc_svcctl2.$SHLIBEXT", RPC)
+SMB_MODULE(rpc_ntsvcs2, \$(RPC_NTSVCS_OBJ), "bin/librpc_ntsvcs2.$SHLIBEXT", RPC)
+SMB_MODULE(rpc_netlogon, \$(RPC_NETLOG_OBJ), "bin/librpc_NETLOGON.$SHLIBEXT", RPC)
+SMB_MODULE(rpc_netdfs, \$(RPC_DFS_OBJ), "bin/librpc_netdfs.$SHLIBEXT", RPC)
+SMB_MODULE(rpc_srvsvc, \$(RPC_SVC_OBJ), "bin/librpc_svcsvc.$SHLIBEXT", RPC)
+SMB_MODULE(rpc_spoolss, \$(RPC_SPOOLSS_OBJ), "bin/librpc_spoolss.$SHLIBEXT", RPC)
+SMB_MODULE(rpc_eventlog2, \$(RPC_EVENTLOG_OBJ), "bin/librpc_eventlog2.$SHLIBEXT", RPC)
+SMB_MODULE(rpc_samr, \$(RPC_SAMR_OBJ), "bin/librpc_samr.$SHLIBEXT", RPC)
+SMB_MODULE(rpc_rpcecho, \$(RPC_ECHO_OBJ), "bin/librpc_rpcecho.$SHLIBEXT", RPC)
+SMB_SUBSYSTEM(RPC,smbd/server.o)
+
+SMB_MODULE(idmap_ldap, winbindd/idmap_ldap.o, "bin/ldap.$SHLIBEXT", IDMAP)
+SMB_MODULE(idmap_tdb, winbindd/idmap_tdb.o, "bin/tdb.$SHLIBEXT", IDMAP)
+SMB_MODULE(idmap_tdb2, winbindd/idmap_tdb2.o, "bin/tdb2.$SHLIBEXT", IDMAP)
+SMB_MODULE(idmap_passdb, winbindd/idmap_passdb.o, "bin/passdb.$SHLIBEXT", IDMAP)
+SMB_MODULE(idmap_nss, winbindd/idmap_nss.o, "bin/nss.$SHLIBEXT", IDMAP)
+SMB_MODULE(idmap_rid, winbindd/idmap_rid.o, "bin/rid.$SHLIBEXT", IDMAP)
+SMB_MODULE(idmap_ad, winbindd/idmap_ad.o, "bin/ad.$SHLIBEXT", IDMAP)
+SMB_SUBSYSTEM(IDMAP, winbindd/idmap.o)
+
+SMB_MODULE(nss_info_template, winbindd/nss_info_template.o, "bin/template.$SHLIBEXT", NSS_INFO)
+SMB_SUBSYSTEM(NSS_INFO, winbindd/nss_info.o)
+
+SMB_MODULE(charset_weird, modules/weird.o, "bin/weird.$SHLIBEXT", CHARSET)
+SMB_MODULE(charset_CP850, modules/CP850.o, "bin/CP850.$SHLIBEXT", CHARSET)
+SMB_MODULE(charset_CP437, modules/CP437.o, "bin/CP437.$SHLIBEXT", CHARSET)
+SMB_MODULE(charset_macosxfs, modules/charset_macosxfs.o,"bin/macosxfs.$SHLIBEXT", CHARSET)
+SMB_SUBSYSTEM(CHARSET,lib/iconv.o)
+
+SMB_MODULE(auth_sam, \$(AUTH_SAM_OBJ), "bin/sam.$SHLIBEXT", AUTH)
+SMB_MODULE(auth_unix, \$(AUTH_UNIX_OBJ), "bin/unix.$SHLIBEXT", AUTH)
+SMB_MODULE(auth_winbind, \$(AUTH_WINBIND_OBJ), "bin/winbind.$SHLIBEXT", AUTH)
+SMB_MODULE(auth_server, \$(AUTH_SERVER_OBJ), "bin/smbserver.$SHLIBEXT", AUTH)
+SMB_MODULE(auth_domain, \$(AUTH_DOMAIN_OBJ), "bin/domain.$SHLIBEXT", AUTH)
+SMB_MODULE(auth_builtin, \$(AUTH_BUILTIN_OBJ), "bin/builtin.$SHLIBEXT", AUTH)
+SMB_MODULE(auth_script, \$(AUTH_SCRIPT_OBJ), "bin/script.$SHLIBEXT", AUTH)
+SMB_SUBSYSTEM(AUTH,auth/auth.o)
+
+SMB_MODULE(vfs_default, \$(VFS_DEFAULT_OBJ), "bin/default.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_recycle, \$(VFS_RECYCLE_OBJ), "bin/recycle.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_audit, \$(VFS_AUDIT_OBJ), "bin/audit.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_extd_audit, \$(VFS_EXTD_AUDIT_OBJ), "bin/extd_audit.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_full_audit, \$(VFS_FULL_AUDIT_OBJ), "bin/full_audit.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_netatalk, \$(VFS_NETATALK_OBJ), "bin/netatalk.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_fake_perms, \$(VFS_FAKE_PERMS_OBJ), "bin/fake_perms.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_default_quota, \$(VFS_DEFAULT_QUOTA_OBJ), "bin/default_quota.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_readonly, \$(VFS_READONLY_OBJ), "bin/readonly.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_cap, \$(VFS_CAP_OBJ), "bin/cap.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_expand_msdfs, \$(VFS_EXPAND_MSDFS_OBJ), "bin/expand_msdfs.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_shadow_copy, \$(VFS_SHADOW_COPY_OBJ), "bin/shadow_copy.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_shadow_copy2, \$(VFS_SHADOW_COPY2_OBJ), "bin/shadow_copy2.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_afsacl, \$(VFS_AFSACL_OBJ), "bin/afsacl.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_xattr_tdb, \$(VFS_XATTR_TDB_OBJ), "bin/xattr_tdb.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_posixacl, \$(VFS_POSIXACL_OBJ), "bin/posixacl.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_aixacl, \$(VFS_AIXACL_OBJ), "bin/aixacl.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_aixacl2, \$(VFS_AIXACL2_OBJ), "bin/aixacl2.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_solarisacl, \$(VFS_SOLARISACL_OBJ), "bin/solarisacl.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_irixacl, \$(VFS_IRIXACL_OBJ), "bin/irixacl.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_hpuxacl, \$(VFS_HPUXACL_OBJ), "bin/hpuxacl.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_tru64acl, \$(VFS_TRU64ACL_OBJ), "bin/tru64acl.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_catia, \$(VFS_CATIA_OBJ), "bin/catia.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_streams_xattr, \$(VFS_STREAMS_XATTR_OBJ), "bin/streams_xattr.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_streams_depot, \$(VFS_STREAMS_DEPOT_OBJ), "bin/streams_depot.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_cacheprime, \$(VFS_CACHEPRIME_OBJ), "bin/cacheprime.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_prealloc, \$(VFS_PREALLOC_OBJ), "bin/prealloc.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_commit, \$(VFS_COMMIT_OBJ), "bin/commit.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_gpfs, \$(VFS_GPFS_OBJ), "bin/gpfs.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_readahead, \$(VFS_READAHEAD_OBJ), "bin/readahead.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_tsmsm, \$(VFS_TSMSM_OBJ), "bin/tsmsm.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_fileid, \$(VFS_FILEID_OBJ), "bin/fileid.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_aio_fork, \$(VFS_AIO_FORK_OBJ), "bin/aio_fork.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_syncops, \$(VFS_SYNCOPS_OBJ), "bin/syncops.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_zfsacl, \$(VFS_ZFSACL_OBJ), "bin/zfsacl.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_notify_fam, \$(VFS_NOTIFY_FAM_OBJ), "bin/notify_fam.$SHLIBEXT", VFS)
+
+
+SMB_SUBSYSTEM(VFS,smbd/vfs.o)
+
+SMB_MODULE(gpext_registry, libgpo/gpext/registry.o, "bin/registry.$SHLIBEXT", GPEXT)
+SMB_MODULE(gpext_scripts, libgpo/gpext/scripts.o, "bin/scripts.$SHLIBEXT", GPEXT)
+SMB_SUBSYSTEM(GPEXT, libgpo/gpext/gpext.o)
+
+AC_DEFINE_UNQUOTED(STRING_STATIC_MODULES, "$string_static_modules", [String list of builtin modules])
+
+#################################################
+# do extra things if we are running insure
+
+if test "${ac_cv_prog_CC}" = "insure"; then
+ CPPFLAGS="$CPPFLAGS -D__INSURE__"
+fi
+
+#################################################
+# If run from the build farm, enable NASTY hacks
+#################################################
+AC_MSG_CHECKING(whether to enable build farm hacks)
+if test x"$RUN_FROM_BUILD_FARM" = x"yes"; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(ENABLE_BUILD_FARM_HACKS, 1, [Defined if running in the build farm])
+else
+ AC_MSG_RESULT(no)
+fi
+
+#################################################
+# check for bad librt/libpthread interactions
+
+if test x"$samba_cv_HAVE_KERNEL_OPLOCKS_LINUX" = x"yes" -o \
+ x"$samba_cv_HAVE_KERNEL_CHANGE_NOTIFY" = x"yes" -o \
+ x"$samba_cv_HAVE_AIO64" = x"yes" -o \
+ x"$samba_cv_HAVE_AIO" = x"yes" ; then
+
+SMB_IF_RTSIGNAL_BUG(
+ [
+ # Have RT_SIGNAL bug, need to check whether the problem will
+ # affect anything we have configured.
+
+ rt_do_error=no
+ if test x"$samba_cv_HAVE_KERNEL_OPLOCKS_LINUX" = x"yes"; then
+ if test x"$rt_signal_lease_ok" = x"no" ; then
+ rt_do_error=yes
+ fi
+ fi
+
+ if test x"$samba_cv_HAVE_KERNEL_CHANGE_NOTIFY" = x"yes"; then
+ if test x"$rt_signal_notify_ok" = x"no" ; then
+ rt_do_error=yes
+ fi
+ fi
+
+ if test x"$samba_cv_HAVE_AIO64" = x"yes" -o \
+ x"$samba_cv_HAVE_AIO" = x"yes" ; then
+ if test x"$rt_signal_aio_ok" = x"no" ; then
+ rt_do_error=yes
+ fi
+ fi
+
+ if test x"$rt_do_error" = x"yes" ; then
+ SMB_IS_LIBPTHREAD_LINKED(
+ [
+ cat<<MSG
+
+*** On this platforms, linking Samba against pthreads causes problems
+*** with the oplock and change notification mechanisms. You may be
+*** using pthreads as a side-effect of using the --with-aio-support
+*** or --with-profiling-data options. Please remove these and try again.
+
+MSG
+ ],
+ [
+ cat<<MSG
+
+*** On this platform, the oplock and change notification mechanisms do not
+*** appear to work. Please report this problem to samba-technical@samba.org
+*** and attach the config.log file from this directory.
+
+MSG
+ ])
+ AC_MSG_ERROR(unable to use realtime signals on this platform)
+ fi
+ ],
+ [
+ # no RT_SIGNAL bug, we are golden
+ SMB_IS_LIBPTHREAD_LINKED(
+ [
+ AC_MSG_WARN(using libpthreads - this may degrade performance)
+ ])
+
+ ],
+ [
+ # cross compiling, I hope you know what you are doing
+ true
+ ])
+
+fi
+
+dnl Remove -L/usr/lib/? from LDFLAGS and LIBS
+LIB_REMOVE_USR_LIB(LDFLAGS)
+LIB_REMOVE_USR_LIB(LIBS)
+LIB_REMOVE_USR_LIB(KRB5_LIBS)
+
+dnl Remove -I/usr/include/? from CFLAGS and CPPFLAGS
+CFLAGS_REMOVE_USR_INCLUDE(CFLAGS)
+CFLAGS_REMOVE_USR_INCLUDE(CPPFLAGS)
+
+#################################################
+# Display summary of libraries detected
+
+AC_MSG_RESULT([Using libraries:])
+AC_MSG_RESULT([ LIBS = $LIBS])
+if test x"$with_ads_support" != x"no"; then
+ AC_MSG_RESULT([ KRB5_LIBS = $KRB5_LIBS])
+fi
+if test x"$with_ldap_support" != x"no"; then
+ AC_MSG_RESULT([ LDAP_LIBS = $LDAP_LIBS])
+fi
+if test x"$with_dnsupdate_support" != x"no"; then
+ AC_MSG_RESULT([ UUID_LIBS = $UUID_LIBS])
+fi
+if test x"$have_dnssd_support" != x"no"; then
+ AC_MSG_RESULT([ DNSSD_LIBS = $DNSSD_LIBS])
+fi
+AC_MSG_RESULT([ AUTH_LIBS = $AUTH_LIBS])
+
+#################################################
+# final configure stuff
+
+AC_MSG_CHECKING([configure summary])
+AC_TRY_RUN([#include "${srcdir-.}/tests/summary.c"],
+ AC_MSG_RESULT(yes),
+ AC_MSG_ERROR([summary failure. Aborting config]); exit 1;,
+ AC_MSG_WARN([cannot run when cross-compiling]))
+
+dnl Merge in developer cflags from now on
+AC_SUBST(DEVELOPER_CFLAGS)
+if test x"$krb5_developer" = x"yes" -o x"$developer" = x"yes" -o x"$picky_developer" = x"yes"; then
+ CFLAGS="${CFLAGS} \$(DEVELOPER_CFLAGS)"
+fi
+
+# Stuff the smbd-only libraries at the end of the smbd link
+# path (if we have them).
+SMBD_LIBS="$samba_dmapi_libs"
+AC_SUBST(SMBD_LIBS)
+
+AC_OUTPUT(Makefile
+ script/findsmb smbadduser script/gen-8bit-gap.sh script/installbin.sh script/uninstallbin.sh
+ lib/netapi/examples/Makefile
+ lib/netapi/tests/Makefile
+ pkgconfig/smbclient.pc
+ pkgconfig/wbclient.pc
+ pkgconfig/netapi.pc
+ pkgconfig/smbsharemodes.pc
+ ../examples/libsmbclient/Makefile.internal
+ )
+
+#################################################
+# Print very concise instructions on building/use
+if test "x$enable_dmalloc" = xyes
+then
+ AC_MSG_RESULT([Note: The dmalloc debug library will be included. To turn it on use])
+ AC_MSG_RESULT([ \$ eval \`dmalloc samba\`.])
+fi
diff --git a/source3/dynconfig.c b/source3/dynconfig.c
new file mode 100644
index 0000000000..3a54507599
--- /dev/null
+++ b/source3/dynconfig.c
@@ -0,0 +1,104 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) 2001 by Martin Pool <mbp@samba.org>
+ Copyright (C) 2003 by Jim McDonough <jmcd@us.ibm.com>
+ Copyright (C) 2007 by Jeremy Allison <jra@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/**
+ * @file dynconfig.c
+ *
+ * @brief Global configurations, initialized to configured defaults.
+ *
+ * This file should be the only file that depends on path
+ * configuration (--prefix, etc), so that if ./configure is re-run,
+ * all programs will be appropriately updated. Everything else in
+ * Samba should import extern variables from here, rather than relying
+ * on preprocessor macros.
+ *
+ * Eventually some of these may become even more variable, so that
+ * they can for example consistently be set across the whole of Samba
+ * by command-line parameters, config file entries, or environment
+ * variables.
+ *
+ * @todo Perhaps eventually these should be merged into the parameter
+ * table? There's kind of a chicken-and-egg situation there...
+ **/
+
+#define DEFINE_DYN_CONFIG_PARAM(name) \
+static char *dyn_##name; \
+\
+ const char *get_dyn_##name(void) \
+{\
+ if (dyn_##name == NULL) {\
+ return name;\
+ }\
+ return dyn_##name;\
+}\
+\
+ const char *set_dyn_##name(const char *newpath) \
+{\
+ if (dyn_##name) {\
+ SAFE_FREE(dyn_##name);\
+ }\
+ dyn_##name = SMB_STRDUP(newpath);\
+ return dyn_##name;\
+}\
+\
+ bool is_default_dyn_##name(void) \
+{\
+ return (dyn_##name == NULL);\
+}
+
+DEFINE_DYN_CONFIG_PARAM(SBINDIR)
+DEFINE_DYN_CONFIG_PARAM(BINDIR)
+DEFINE_DYN_CONFIG_PARAM(SWATDIR)
+DEFINE_DYN_CONFIG_PARAM(CONFIGFILE) /**< Location of smb.conf file. **/
+DEFINE_DYN_CONFIG_PARAM(LOGFILEBASE) /** Log file directory. **/
+DEFINE_DYN_CONFIG_PARAM(LMHOSTSFILE) /** Statically configured LanMan hosts. **/
+DEFINE_DYN_CONFIG_PARAM(CODEPAGEDIR)
+DEFINE_DYN_CONFIG_PARAM(LIBDIR)
+DEFINE_DYN_CONFIG_PARAM(MODULESDIR)
+DEFINE_DYN_CONFIG_PARAM(SHLIBEXT)
+DEFINE_DYN_CONFIG_PARAM(LOCKDIR)
+DEFINE_DYN_CONFIG_PARAM(PIDDIR)
+DEFINE_DYN_CONFIG_PARAM(SMB_PASSWD_FILE)
+DEFINE_DYN_CONFIG_PARAM(PRIVATE_DIR)
+
+/* In non-FHS mode, these should be configurable using 'lock dir =';
+ but in FHS mode, they are their own directory. Implement as wrapper
+ functions so that everything can still be kept in dynconfig.c.
+ */
+
+const char *get_dyn_STATEDIR(void)
+{
+#ifdef FHS_COMPATIBLE
+ return STATEDIR;
+#else
+ return lp_lockdir();
+#endif
+}
+
+const char *get_dyn_CACHEDIR(void)
+{
+#ifdef FHS_COMPATIBLE
+ return CACHEDIR;
+#else
+ return lp_lockdir();
+#endif
+}
diff --git a/source3/exports/libaddns.syms b/source3/exports/libaddns.syms
new file mode 100644
index 0000000000..3e88ba739c
--- /dev/null
+++ b/source3/exports/libaddns.syms
@@ -0,0 +1,5 @@
+{
+ # no global exported symbols (yet) in libaddns ...
+
+ local: *;
+};
diff --git a/source3/exports/modules-darwin.syms b/source3/exports/modules-darwin.syms
new file mode 100644
index 0000000000..be457614d8
--- /dev/null
+++ b/source3/exports/modules-darwin.syms
@@ -0,0 +1 @@
+_init_samba_module
diff --git a/source3/groupdb/mapping.c b/source3/groupdb/mapping.c
new file mode 100644
index 0000000000..b952cda523
--- /dev/null
+++ b/source3/groupdb/mapping.c
@@ -0,0 +1,808 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Jean François Micouleau 1998-2001.
+ * Copyright (C) Volker Lendecke 2006.
+ * Copyright (C) Gerald Carter 2006.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "groupdb/mapping.h"
+
+static const struct mapping_backend *backend;
+
+/*
+ initialise a group mapping backend
+ */
+static bool init_group_mapping(void)
+{
+ const char *backend_string;
+
+ if (backend != NULL) {
+ /* already initialised */
+ return True;
+ }
+
+ /*
+ * default to using the ldb backend. This parameter should
+ * disappear in future versions of Samba3.
+ *
+ * But it's needed for cluster setups, because it's
+ * not yet possible to distribute a ldb inside a cluster.
+ */
+ backend_string = lp_parm_const_string(-1, "groupdb", "backend", "ldb");
+
+ if (strcmp(backend_string, "ldb") == 0) {
+ backend = groupdb_ldb_init();
+ } else if (strcmp(backend_string, "tdb") == 0) {
+ backend = groupdb_tdb_init();
+ } else {
+ DEBUG(0,("Unknown groupdb backend '%s'\n", backend_string));
+ smb_panic("Unknown groupdb backend");
+ }
+
+ return backend != NULL;
+}
+
+/****************************************************************************
+initialise first time the mapping list
+****************************************************************************/
+NTSTATUS add_initial_entry(gid_t gid, const char *sid, enum lsa_SidType sid_name_use, const char *nt_name, const char *comment)
+{
+ GROUP_MAP map;
+
+ if(!init_group_mapping()) {
+ DEBUG(0,("failed to initialize group mapping\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ map.gid=gid;
+ if (!string_to_sid(&map.sid, sid)) {
+ DEBUG(0, ("string_to_sid failed: %s", sid));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ map.sid_name_use=sid_name_use;
+ fstrcpy(map.nt_name, nt_name);
+ fstrcpy(map.comment, comment);
+
+ return pdb_add_group_mapping_entry(&map);
+}
+
+static NTSTATUS alias_memberships(const DOM_SID *members, size_t num_members,
+ DOM_SID **sids, size_t *num)
+{
+ size_t i;
+
+ *num = 0;
+ *sids = NULL;
+
+ for (i=0; i<num_members; i++) {
+ NTSTATUS status = backend->one_alias_membership(&members[i], sids, num);
+ if (!NT_STATUS_IS_OK(status))
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+struct aliasmem_closure {
+ const DOM_SID *alias;
+ DOM_SID **sids;
+ size_t *num;
+};
+
+
+
+/*
+ *
+ * High level functions
+ * better to use them than the lower ones.
+ *
+ * we are checking if the group is in the mapping file
+ * and if the group is an existing unix group
+ *
+ */
+
+/* get a domain group from it's SID */
+
+bool get_domain_group_from_sid(DOM_SID sid, GROUP_MAP *map)
+{
+ struct group *grp;
+ bool ret;
+
+ if(!init_group_mapping()) {
+ DEBUG(0,("failed to initialize group mapping\n"));
+ return(False);
+ }
+
+ DEBUG(10, ("get_domain_group_from_sid\n"));
+
+ /* if the group is NOT in the database, it CAN NOT be a domain group */
+
+ become_root();
+ ret = pdb_getgrsid(map, sid);
+ unbecome_root();
+
+ /* special case check for rid 513 */
+
+ if ( !ret ) {
+ uint32 rid;
+
+ sid_peek_rid( &sid, &rid );
+
+ if ( rid == DOMAIN_GROUP_RID_USERS ) {
+ fstrcpy( map->nt_name, "None" );
+ fstrcpy( map->comment, "Ordinary Users" );
+ sid_copy( &map->sid, &sid );
+ map->sid_name_use = SID_NAME_DOM_GRP;
+ map->gid = (gid_t)-1;
+
+ return True;
+ }
+
+ return False;
+ }
+
+ DEBUG(10, ("get_domain_group_from_sid: SID found in the TDB\n"));
+
+ /* if it's not a domain group, continue */
+ if (map->sid_name_use!=SID_NAME_DOM_GRP) {
+ return False;
+ }
+
+ DEBUG(10, ("get_domain_group_from_sid: SID is a domain group\n"));
+
+ if (map->gid==-1) {
+ return False;
+ }
+
+ DEBUG(10, ("get_domain_group_from_sid: SID is mapped to gid:%lu\n",(unsigned long)map->gid));
+
+ grp = getgrgid(map->gid);
+ if ( !grp ) {
+ DEBUG(10, ("get_domain_group_from_sid: gid DOESN'T exist in UNIX security\n"));
+ return False;
+ }
+
+ DEBUG(10, ("get_domain_group_from_sid: gid exists in UNIX security\n"));
+
+ return True;
+}
+
+/****************************************************************************
+ Create a UNIX group on demand.
+****************************************************************************/
+
+int smb_create_group(const char *unix_group, gid_t *new_gid)
+{
+ char *add_script = NULL;
+ int ret = -1;
+ int fd = 0;
+
+ *new_gid = 0;
+
+ /* defer to scripts */
+
+ if ( *lp_addgroup_script() ) {
+ TALLOC_CTX *ctx = talloc_tos();
+
+ add_script = talloc_strdup(ctx,
+ lp_addgroup_script());
+ if (!add_script) {
+ return -1;
+ }
+ add_script = talloc_string_sub(ctx,
+ add_script, "%g", unix_group);
+ if (!add_script) {
+ return -1;
+ }
+
+ ret = smbrun(add_script, &fd);
+ DEBUG(ret ? 0 : 3,("smb_create_group: Running the command `%s' gave %d\n",add_script,ret));
+ if (ret == 0) {
+ smb_nscd_flush_group_cache();
+ }
+ if (ret != 0)
+ return ret;
+
+ if (fd != 0) {
+ fstring output;
+
+ *new_gid = 0;
+ if (read(fd, output, sizeof(output)) > 0) {
+ *new_gid = (gid_t)strtoul(output, NULL, 10);
+ }
+
+ close(fd);
+ }
+
+ }
+
+ if (*new_gid == 0) {
+ struct group *grp = getgrnam(unix_group);
+
+ if (grp != NULL)
+ *new_gid = grp->gr_gid;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Delete a UNIX group on demand.
+****************************************************************************/
+
+int smb_delete_group(const char *unix_group)
+{
+ char *del_script = NULL;
+ int ret = -1;
+
+ /* defer to scripts */
+
+ if ( *lp_delgroup_script() ) {
+ TALLOC_CTX *ctx = talloc_tos();
+
+ del_script = talloc_strdup(ctx,
+ lp_delgroup_script());
+ if (!del_script) {
+ return -1;
+ }
+ del_script = talloc_string_sub(ctx,
+ del_script, "%g", unix_group);
+ if (!del_script) {
+ return -1;
+ }
+ ret = smbrun(del_script,NULL);
+ DEBUG(ret ? 0 : 3,("smb_delete_group: Running the command `%s' gave %d\n",del_script,ret));
+ if (ret == 0) {
+ smb_nscd_flush_group_cache();
+ }
+ return ret;
+ }
+
+ return -1;
+}
+
+/****************************************************************************
+ Set a user's primary UNIX group.
+****************************************************************************/
+
+int smb_set_primary_group(const char *unix_group, const char* unix_user)
+{
+ char *add_script = NULL;
+ int ret = -1;
+
+ /* defer to scripts */
+
+ if ( *lp_setprimarygroup_script() ) {
+ TALLOC_CTX *ctx = talloc_tos();
+
+ add_script = talloc_strdup(ctx,
+ lp_setprimarygroup_script());
+ if (!add_script) {
+ return -1;
+ }
+ add_script = talloc_all_string_sub(ctx,
+ add_script, "%g", unix_group);
+ if (!add_script) {
+ return -1;
+ }
+ add_script = talloc_string_sub(ctx,
+ add_script, "%u", unix_user);
+ if (!add_script) {
+ return -1;
+ }
+ ret = smbrun(add_script,NULL);
+ flush_pwnam_cache();
+ DEBUG(ret ? 0 : 3,("smb_set_primary_group: "
+ "Running the command `%s' gave %d\n",add_script,ret));
+ if (ret == 0) {
+ smb_nscd_flush_group_cache();
+ }
+ return ret;
+ }
+
+ return -1;
+}
+
+/****************************************************************************
+ Add a user to a UNIX group.
+****************************************************************************/
+
+int smb_add_user_group(const char *unix_group, const char *unix_user)
+{
+ char *add_script = NULL;
+ int ret = -1;
+
+ /* defer to scripts */
+
+ if ( *lp_addusertogroup_script() ) {
+ TALLOC_CTX *ctx = talloc_tos();
+
+ add_script = talloc_strdup(ctx,
+ lp_addusertogroup_script());
+ if (!add_script) {
+ return -1;
+ }
+ add_script = talloc_string_sub(ctx,
+ add_script, "%g", unix_group);
+ if (!add_script) {
+ return -1;
+ }
+ add_script = talloc_string_sub(ctx,
+ add_script, "%u", unix_user);
+ if (!add_script) {
+ return -1;
+ }
+ ret = smbrun(add_script,NULL);
+ DEBUG(ret ? 0 : 3,("smb_add_user_group: Running the command `%s' gave %d\n",add_script,ret));
+ if (ret == 0) {
+ smb_nscd_flush_group_cache();
+ }
+ return ret;
+ }
+
+ return -1;
+}
+
+/****************************************************************************
+ Delete a user from a UNIX group
+****************************************************************************/
+
+int smb_delete_user_group(const char *unix_group, const char *unix_user)
+{
+ char *del_script = NULL;
+ int ret = -1;
+
+ /* defer to scripts */
+
+ if ( *lp_deluserfromgroup_script() ) {
+ TALLOC_CTX *ctx = talloc_tos();
+
+ del_script = talloc_strdup(ctx,
+ lp_deluserfromgroup_script());
+ if (!del_script) {
+ return -1;
+ }
+ del_script = talloc_string_sub(ctx,
+ del_script, "%g", unix_group);
+ if (!del_script) {
+ return -1;
+ }
+ del_script = talloc_string_sub(ctx,
+ del_script, "%u", unix_user);
+ if (!del_script) {
+ return -1;
+ }
+ ret = smbrun(del_script,NULL);
+ DEBUG(ret ? 0 : 3,("smb_delete_user_group: Running the command `%s' gave %d\n",del_script,ret));
+ if (ret == 0) {
+ smb_nscd_flush_group_cache();
+ }
+ return ret;
+ }
+
+ return -1;
+}
+
+
+NTSTATUS pdb_default_getgrsid(struct pdb_methods *methods, GROUP_MAP *map,
+ DOM_SID sid)
+{
+ if (!init_group_mapping()) {
+ DEBUG(0,("failed to initialize group mapping\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return backend->get_group_map_from_sid(sid, map) ?
+ NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS pdb_default_getgrgid(struct pdb_methods *methods, GROUP_MAP *map,
+ gid_t gid)
+{
+ if (!init_group_mapping()) {
+ DEBUG(0,("failed to initialize group mapping\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return backend->get_group_map_from_gid(gid, map) ?
+ NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS pdb_default_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
+ const char *name)
+{
+ if (!init_group_mapping()) {
+ DEBUG(0,("failed to initialize group mapping\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return backend->get_group_map_from_ntname(name, map) ?
+ NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS pdb_default_add_group_mapping_entry(struct pdb_methods *methods,
+ GROUP_MAP *map)
+{
+ if (!init_group_mapping()) {
+ DEBUG(0,("failed to initialize group mapping\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return backend->add_mapping_entry(map, TDB_INSERT) ?
+ NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS pdb_default_update_group_mapping_entry(struct pdb_methods *methods,
+ GROUP_MAP *map)
+{
+ if (!init_group_mapping()) {
+ DEBUG(0,("failed to initialize group mapping\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return backend->add_mapping_entry(map, TDB_REPLACE) ?
+ NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS pdb_default_delete_group_mapping_entry(struct pdb_methods *methods,
+ DOM_SID sid)
+{
+ if (!init_group_mapping()) {
+ DEBUG(0,("failed to initialize group mapping\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return backend->group_map_remove(&sid) ?
+ NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS pdb_default_enum_group_mapping(struct pdb_methods *methods,
+ const DOM_SID *sid, enum lsa_SidType sid_name_use,
+ GROUP_MAP **pp_rmap, size_t *p_num_entries,
+ bool unix_only)
+{
+ if (!init_group_mapping()) {
+ DEBUG(0,("failed to initialize group mapping\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return backend->enum_group_mapping(sid, sid_name_use, pp_rmap, p_num_entries, unix_only) ?
+ NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS pdb_default_create_alias(struct pdb_methods *methods,
+ const char *name, uint32 *rid)
+{
+ DOM_SID sid;
+ enum lsa_SidType type;
+ uint32 new_rid;
+ gid_t gid;
+ bool exists;
+ GROUP_MAP map;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ DEBUG(10, ("Trying to create alias %s\n", name));
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ exists = lookup_name(mem_ctx, name, LOOKUP_NAME_LOCAL,
+ NULL, NULL, &sid, &type);
+ TALLOC_FREE(mem_ctx);
+
+ if (exists) {
+ return NT_STATUS_ALIAS_EXISTS;
+ }
+
+ if (!winbind_allocate_gid(&gid)) {
+ DEBUG(3, ("Could not get a gid out of winbind\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (!pdb_new_rid(&new_rid)) {
+ DEBUG(0, ("Could not allocate a RID -- wasted a gid :-(\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ DEBUG(10, ("Creating alias %s with gid %d and rid %d\n",
+ name, gid, new_rid));
+
+ sid_copy(&sid, get_global_sam_sid());
+ sid_append_rid(&sid, new_rid);
+
+ map.gid = gid;
+ sid_copy(&map.sid, &sid);
+ map.sid_name_use = SID_NAME_ALIAS;
+ fstrcpy(map.nt_name, name);
+ fstrcpy(map.comment, "");
+
+ status = pdb_add_group_mapping_entry(&map);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Could not add group mapping entry for alias %s "
+ "(%s)\n", name, nt_errstr(status)));
+ return status;
+ }
+
+ *rid = new_rid;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_default_delete_alias(struct pdb_methods *methods,
+ const DOM_SID *sid)
+{
+ return pdb_delete_group_mapping_entry(*sid);
+}
+
+NTSTATUS pdb_default_get_aliasinfo(struct pdb_methods *methods,
+ const DOM_SID *sid,
+ struct acct_info *info)
+{
+ GROUP_MAP map;
+
+ if (!pdb_getgrsid(&map, *sid))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ if ((map.sid_name_use != SID_NAME_ALIAS) &&
+ (map.sid_name_use != SID_NAME_WKN_GRP)) {
+ DEBUG(2, ("%s is a %s, expected an alias\n",
+ sid_string_dbg(sid),
+ sid_type_lookup(map.sid_name_use)));
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ fstrcpy(info->acct_name, map.nt_name);
+ fstrcpy(info->acct_desc, map.comment);
+ sid_peek_rid(&map.sid, &info->rid);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_default_set_aliasinfo(struct pdb_methods *methods,
+ const DOM_SID *sid,
+ struct acct_info *info)
+{
+ GROUP_MAP map;
+
+ if (!pdb_getgrsid(&map, *sid))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ fstrcpy(map.nt_name, info->acct_name);
+ fstrcpy(map.comment, info->acct_desc);
+
+ return pdb_update_group_mapping_entry(&map);
+}
+
+NTSTATUS pdb_default_add_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias, const DOM_SID *member)
+{
+ if (!init_group_mapping()) {
+ DEBUG(0,("failed to initialize group mapping\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return backend->add_aliasmem(alias, member);
+}
+
+NTSTATUS pdb_default_del_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias, const DOM_SID *member)
+{
+ if (!init_group_mapping()) {
+ DEBUG(0,("failed to initialize group mapping\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return backend->del_aliasmem(alias, member);
+}
+
+NTSTATUS pdb_default_enum_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias, DOM_SID **pp_members,
+ size_t *p_num_members)
+{
+ if (!init_group_mapping()) {
+ DEBUG(0,("failed to initialize group mapping\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return backend->enum_aliasmem(alias, pp_members, p_num_members);
+}
+
+NTSTATUS pdb_default_alias_memberships(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *domain_sid,
+ const DOM_SID *members,
+ size_t num_members,
+ uint32 **pp_alias_rids,
+ size_t *p_num_alias_rids)
+{
+ DOM_SID *alias_sids;
+ size_t i, num_alias_sids;
+ NTSTATUS result;
+
+ if (!init_group_mapping()) {
+ DEBUG(0,("failed to initialize group mapping\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ alias_sids = NULL;
+ num_alias_sids = 0;
+
+ result = alias_memberships(members, num_members,
+ &alias_sids, &num_alias_sids);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ *p_num_alias_rids = 0;
+
+ if (num_alias_sids == 0) {
+ TALLOC_FREE(alias_sids);
+ return NT_STATUS_OK;
+ }
+
+ *pp_alias_rids = TALLOC_ARRAY(mem_ctx, uint32, num_alias_sids);
+ if (*pp_alias_rids == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ for (i=0; i<num_alias_sids; i++) {
+ if (!sid_peek_check_rid(domain_sid, &alias_sids[i],
+ &(*pp_alias_rids)[*p_num_alias_rids]))
+ continue;
+ *p_num_alias_rids += 1;
+ }
+
+ TALLOC_FREE(alias_sids);
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ no ops for passdb backends that don't implement group mapping
+ *********************************************************************/
+
+NTSTATUS pdb_nop_getgrsid(struct pdb_methods *methods, GROUP_MAP *map,
+ DOM_SID sid)
+{
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS pdb_nop_getgrgid(struct pdb_methods *methods, GROUP_MAP *map,
+ gid_t gid)
+{
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS pdb_nop_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
+ const char *name)
+{
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS pdb_nop_add_group_mapping_entry(struct pdb_methods *methods,
+ GROUP_MAP *map)
+{
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS pdb_nop_update_group_mapping_entry(struct pdb_methods *methods,
+ GROUP_MAP *map)
+{
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS pdb_nop_delete_group_mapping_entry(struct pdb_methods *methods,
+ DOM_SID sid)
+{
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS pdb_nop_enum_group_mapping(struct pdb_methods *methods,
+ enum lsa_SidType sid_name_use,
+ GROUP_MAP **rmap, size_t *num_entries,
+ bool unix_only)
+{
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/****************************************************************************
+ These need to be redirected through pdb_interface.c
+****************************************************************************/
+bool pdb_get_dom_grp_info(const DOM_SID *sid, struct acct_info *info)
+{
+ GROUP_MAP map;
+ bool res;
+
+ become_root();
+ res = get_domain_group_from_sid(*sid, &map);
+ unbecome_root();
+
+ if (!res)
+ return False;
+
+ fstrcpy(info->acct_name, map.nt_name);
+ fstrcpy(info->acct_desc, map.comment);
+ sid_peek_rid(sid, &info->rid);
+ return True;
+}
+
+bool pdb_set_dom_grp_info(const DOM_SID *sid, const struct acct_info *info)
+{
+ GROUP_MAP map;
+
+ if (!get_domain_group_from_sid(*sid, &map))
+ return False;
+
+ fstrcpy(map.nt_name, info->acct_name);
+ fstrcpy(map.comment, info->acct_desc);
+
+ return NT_STATUS_IS_OK(pdb_update_group_mapping_entry(&map));
+}
+
+/********************************************************************
+ Really just intended to be called by smbd
+********************************************************************/
+
+NTSTATUS pdb_create_builtin_alias(uint32 rid)
+{
+ DOM_SID sid;
+ enum lsa_SidType type;
+ gid_t gid;
+ GROUP_MAP map;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ const char *name = NULL;
+ fstring groupname;
+
+ DEBUG(10, ("Trying to create builtin alias %d\n", rid));
+
+ if ( !sid_compose( &sid, &global_sid_Builtin, rid ) ) {
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ if ( (mem_ctx = talloc_new(NULL)) == NULL ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( !lookup_sid(mem_ctx, &sid, NULL, &name, &type) ) {
+ TALLOC_FREE( mem_ctx );
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ /* validate RID so copy the name and move on */
+
+ fstrcpy( groupname, name );
+ TALLOC_FREE( mem_ctx );
+
+ if (!winbind_allocate_gid(&gid)) {
+ DEBUG(3, ("pdb_create_builtin_alias: Could not get a gid out of winbind\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ DEBUG(10,("Creating alias %s with gid %d\n", groupname, gid));
+
+ map.gid = gid;
+ sid_copy(&map.sid, &sid);
+ map.sid_name_use = SID_NAME_ALIAS;
+ fstrcpy(map.nt_name, groupname);
+ fstrcpy(map.comment, "");
+
+ status = pdb_add_group_mapping_entry(&map);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("pdb_create_builtin_alias: Could not add group mapping entry for alias %d "
+ "(%s)\n", rid, nt_errstr(status)));
+ }
+
+ return status;
+}
+
+
diff --git a/source3/groupdb/mapping.h b/source3/groupdb/mapping.h
new file mode 100644
index 0000000000..c37ae84b87
--- /dev/null
+++ b/source3/groupdb/mapping.h
@@ -0,0 +1,33 @@
+#define DATABASE_VERSION_V1 1 /* native byte format. */
+#define DATABASE_VERSION_V2 2 /* le format. */
+
+#define GROUP_PREFIX "UNIXGROUP/"
+#define GROUP_PREFIX_LEN 10
+
+/* Alias memberships are stored reverse, as memberships. The performance
+ * critical operation is to determine the aliases a SID is member of, not
+ * listing alias members. So we store a list of alias SIDs a SID is member of
+ * hanging of the member as key.
+ */
+#define MEMBEROF_PREFIX "MEMBEROF/"
+#define MEMBEROF_PREFIX_LEN 9
+
+/*
+ groupdb mapping backend abstraction
+ */
+struct mapping_backend {
+ bool (*init_group_mapping)(void);
+ bool (*add_mapping_entry)(GROUP_MAP *map, int flag);
+ bool (*get_group_map_from_sid)(DOM_SID sid, GROUP_MAP *map);
+ bool (*get_group_map_from_gid)(gid_t gid, GROUP_MAP *map);
+ bool (*get_group_map_from_ntname)(const char *name, GROUP_MAP *map);
+ bool (*group_map_remove)(const DOM_SID *sid);
+ bool (*enum_group_mapping)(const DOM_SID *domsid, enum lsa_SidType sid_name_use,
+ GROUP_MAP **pp_rmap,
+ size_t *p_num_entries, bool unix_only);
+ NTSTATUS (*one_alias_membership)(const DOM_SID *member,
+ DOM_SID **sids, size_t *num);
+ NTSTATUS (*add_aliasmem)(const DOM_SID *alias, const DOM_SID *member);
+ NTSTATUS (*del_aliasmem)(const DOM_SID *alias, const DOM_SID *member);
+ NTSTATUS (*enum_aliasmem)(const DOM_SID *alias, DOM_SID **sids, size_t *num);
+};
diff --git a/source3/groupdb/mapping_ldb.c b/source3/groupdb/mapping_ldb.c
new file mode 100644
index 0000000000..7ce879fb6e
--- /dev/null
+++ b/source3/groupdb/mapping_ldb.c
@@ -0,0 +1,699 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * group mapping code on top of ldb
+ *
+ * Copyright (C) Andrew Tridgell 2006
+ *
+ * based on tdb group mapping code from groupdb/mapping.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "groupdb/mapping.h"
+#include "lib/ldb/include/includes.h"
+#include "lib/ldb/include/ldb_errors.h"
+
+static struct ldb_context *ldb;
+
+static bool mapping_upgrade(const char *tdb_path);
+
+/*
+ connect to the group mapping ldb
+*/
+static bool init_group_mapping(void)
+{
+ bool existed;
+ const char *init_ldif[] =
+ { "dn: @ATTRIBUTES\n" \
+ "ntName: CASE_INSENSITIVE\n" \
+ "\n",
+ "dn: @INDEXLIST\n" \
+ "@IDXATTR: gidNumber\n" \
+ "@IDXATTR: ntName\n" \
+ "@IDXATTR: member\n" };
+ const char *db_path, *tdb_path;
+ int ret;
+ int flags = 0;
+
+ if (ldb != NULL) {
+ return True;
+ }
+
+ /* this is needed as Samba3 doesn't have this globally yet */
+ ldb_global_init();
+
+ db_path = state_path("group_mapping.ldb");
+
+ ldb = ldb_init(NULL);
+ if (ldb == NULL) goto failed;
+
+ /* Ensure this db is created read/write for root only. */
+ ldb_set_create_perms(ldb, 0600);
+
+ existed = file_exist(db_path, NULL);
+
+ if (lp_parm_bool(-1, "groupmap", "nosync", False)) {
+ flags |= LDB_FLG_NOSYNC;
+ }
+
+ if (!lp_use_mmap()) {
+ flags |= LDB_FLG_NOMMAP;
+ }
+
+ ret = ldb_connect(ldb, db_path, flags, NULL);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ /* force the permissions on the ldb to 0600 - this will fix
+ existing databases as well as new ones */
+ if (chmod(db_path, 0600) != 0) {
+ goto failed;
+ }
+
+ if (!existed) {
+ /* initialise the ldb with an index */
+ struct ldb_ldif *ldif;
+ int i;
+ for (i=0;i<ARRAY_SIZE(init_ldif);i++) {
+ ldif = ldb_ldif_read_string(ldb, &init_ldif[i]);
+ if (ldif == NULL) goto failed;
+ ret = ldb_add(ldb, ldif->msg);
+ talloc_free(ldif);
+ if (ret == -1) goto failed;
+ }
+ }
+
+ /* possibly upgrade */
+ tdb_path = state_path("group_mapping.tdb");
+ if (file_exist(tdb_path, NULL) && !mapping_upgrade(tdb_path)) {
+ unlink(state_path("group_mapping.ldb"));
+ goto failed;
+ }
+
+ return True;
+
+failed:
+ DEBUG(0,("Failed to open group mapping ldb '%s' - '%s'\n",
+ db_path, ldb?ldb_errstring(ldb):strerror(errno)));
+ talloc_free(ldb);
+ ldb = NULL;
+ return False;
+}
+
+
+/*
+ form the DN for a mapping entry from a SID
+ */
+static struct ldb_dn *mapping_dn(TALLOC_CTX *mem_ctx, const DOM_SID *sid)
+{
+ fstring string_sid;
+ uint32_t rid;
+ DOM_SID domsid;
+
+ sid_copy(&domsid, sid);
+ if (!sid_split_rid(&domsid, &rid)) {
+ return NULL;
+ }
+ if (!sid_to_fstring(string_sid, &domsid)) {
+ return NULL;
+ }
+ /* we split by domain and rid so we can do a subtree search
+ when we only want one domain */
+ return ldb_dn_string_compose(mem_ctx, NULL, "rid=%u,domain=%s",
+ rid, string_sid);
+}
+
+/*
+ add a group mapping entry
+ */
+static bool add_mapping_entry(GROUP_MAP *map, int flag)
+{
+ struct ldb_message *msg;
+ int ret, i;
+ fstring string_sid;
+
+ msg = ldb_msg_new(ldb);
+ if (msg == NULL) {
+ return False;
+ }
+
+ msg->dn = mapping_dn(msg, &map->sid);
+ if (msg->dn == NULL) {
+ goto failed;
+ }
+
+ if (ldb_msg_add_string(msg, "objectClass", "groupMap") != LDB_SUCCESS ||
+ ldb_msg_add_string(msg, "sid",
+ sid_to_fstring(string_sid, &map->sid)) != LDB_SUCCESS ||
+ ldb_msg_add_fmt(msg, "gidNumber", "%u", (unsigned)map->gid) != LDB_SUCCESS ||
+ ldb_msg_add_fmt(msg, "sidNameUse", "%u", (unsigned)map->sid_name_use) != LDB_SUCCESS ||
+ ldb_msg_add_string(msg, "comment", map->comment) != LDB_SUCCESS ||
+ ldb_msg_add_string(msg, "ntName", map->nt_name) != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ ret = ldb_add(ldb, msg);
+
+ /* if it exists we update it. This is a hangover from the semantics the
+ tdb backend had */
+ if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+ for (i=0;i<msg->num_elements;i++) {
+ msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
+ }
+ ret = ldb_modify(ldb, msg);
+ }
+
+ talloc_free(msg);
+
+ return ret == LDB_SUCCESS;
+
+failed:
+ talloc_free(msg);
+ return False;
+}
+
+/*
+ unpack a ldb message into a GROUP_MAP structure
+*/
+static bool msg_to_group_map(struct ldb_message *msg, GROUP_MAP *map)
+{
+ const char *sidstr;
+
+ map->gid = ldb_msg_find_attr_as_int(msg, "gidNumber", -1);
+ map->sid_name_use = ldb_msg_find_attr_as_int(msg, "sidNameUse", -1);
+ fstrcpy(map->nt_name, ldb_msg_find_attr_as_string(msg, "ntName", NULL));
+ fstrcpy(map->comment, ldb_msg_find_attr_as_string(msg, "comment", NULL));
+ sidstr = ldb_msg_find_attr_as_string(msg, "sid", NULL);
+
+ if (!string_to_sid(&map->sid, sidstr) ||
+ map->gid == (gid_t)-1 ||
+ map->sid_name_use == (enum lsa_SidType)-1) {
+ DEBUG(0,("Unable to unpack group mapping\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*
+ return a group map entry for a given sid
+*/
+static bool get_group_map_from_sid(DOM_SID sid, GROUP_MAP *map)
+{
+ int ret;
+ struct ldb_dn *dn;
+ struct ldb_result *res=NULL;
+
+ dn = mapping_dn(ldb, &sid);
+ if (dn == NULL) goto failed;
+
+ ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, NULL, NULL, &res);
+ talloc_steal(dn, res);
+ if (ret != LDB_SUCCESS || res->count != 1) {
+ goto failed;
+ }
+
+ if (!msg_to_group_map(res->msgs[0], map)) goto failed;
+
+ talloc_free(dn);
+ return True;
+
+failed:
+ talloc_free(dn);
+ return False;
+}
+
+/*
+ return a group map entry for a given gid
+*/
+static bool get_group_map_from_gid(gid_t gid, GROUP_MAP *map)
+{
+ int ret;
+ char *expr;
+ struct ldb_result *res=NULL;
+
+ expr = talloc_asprintf(ldb, "(&(gidNumber=%u)(objectClass=groupMap))",
+ (unsigned)gid);
+ if (expr == NULL) goto failed;
+
+ ret = ldb_search(ldb, NULL, LDB_SCOPE_SUBTREE, expr, NULL, &res);
+ talloc_steal(expr, res);
+ if (ret != LDB_SUCCESS || res->count != 1) goto failed;
+
+ if (!msg_to_group_map(res->msgs[0], map)) goto failed;
+
+ talloc_free(expr);
+ return True;
+
+failed:
+ talloc_free(expr);
+ return False;
+}
+
+/*
+ Return the sid and the type of the unix group.
+*/
+static bool get_group_map_from_ntname(const char *name, GROUP_MAP *map)
+{
+ int ret;
+ char *expr;
+ struct ldb_result *res=NULL;
+
+ expr = talloc_asprintf(ldb, "(&(ntName=%s)(objectClass=groupMap))", name);
+ if (expr == NULL) goto failed;
+
+ ret = ldb_search(ldb, NULL, LDB_SCOPE_SUBTREE, expr, NULL, &res);
+ talloc_steal(expr, res);
+ if (ret != LDB_SUCCESS || res->count != 1) goto failed;
+
+ if (!msg_to_group_map(res->msgs[0], map)) goto failed;
+
+ talloc_free(expr);
+ return True;
+
+failed:
+ talloc_free(expr);
+ return False;
+}
+
+/*
+ Remove a group mapping entry.
+*/
+static bool group_map_remove(const DOM_SID *sid)
+{
+ struct ldb_dn *dn;
+ int ret;
+
+ dn = mapping_dn(ldb, sid);
+ if (dn == NULL) {
+ return False;
+ }
+ ret = ldb_delete(ldb, dn);
+ talloc_free(dn);
+
+ return ret == LDB_SUCCESS;
+}
+
+
+/*
+ Enumerate the group mappings for a domain
+*/
+static bool enum_group_mapping(const DOM_SID *domsid, enum lsa_SidType sid_name_use,
+ GROUP_MAP **pp_rmap,
+ size_t *p_num_entries, bool unix_only)
+{
+ int i, ret;
+ char *expr;
+ fstring name;
+ struct ldb_result *res = NULL;
+ struct ldb_dn *basedn=NULL;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(ldb);
+ if (tmp_ctx == NULL) goto failed;
+
+ if (sid_name_use == SID_NAME_UNKNOWN) {
+ expr = talloc_asprintf(tmp_ctx, "(&(objectClass=groupMap))");
+ } else {
+ expr = talloc_asprintf(tmp_ctx, "(&(sidNameUse=%u)(objectClass=groupMap))",
+ sid_name_use);
+ }
+ if (expr == NULL) goto failed;
+
+ /* we do a subtree search on the domain */
+ if (domsid != NULL) {
+ sid_to_fstring(name, domsid);
+ basedn = ldb_dn_string_compose(tmp_ctx, NULL, "domain=%s", name);
+ if (basedn == NULL) goto failed;
+ }
+
+ ret = ldb_search(ldb, basedn, LDB_SCOPE_SUBTREE, expr, NULL, &res);
+ talloc_steal(tmp_ctx, res);
+ if (ret != LDB_SUCCESS) goto failed;
+
+ (*pp_rmap) = NULL;
+ *p_num_entries = 0;
+
+ for (i=0;i<res->count;i++) {
+ (*pp_rmap) = SMB_REALLOC_ARRAY((*pp_rmap), GROUP_MAP,
+ (*p_num_entries)+1);
+ if (!(*pp_rmap)) goto failed;
+
+ if (!msg_to_group_map(res->msgs[i], &(*pp_rmap)[*p_num_entries])) {
+ goto failed;
+ }
+
+ (*p_num_entries)++;
+ }
+
+ talloc_free(tmp_ctx);
+ return True;
+
+failed:
+ talloc_free(tmp_ctx);
+ return False;
+}
+
+/*
+ This operation happens on session setup, so it should better be fast. We
+ store a list of aliases a SID is member of hanging off MEMBEROF/SID.
+*/
+static NTSTATUS one_alias_membership(const DOM_SID *member,
+ DOM_SID **sids, size_t *num)
+{
+ const char *attrs[] = {
+ "sid",
+ NULL
+ };
+ DOM_SID alias;
+ char *expr;
+ int ret, i;
+ struct ldb_result *res=NULL;
+ fstring string_sid;
+ NTSTATUS status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+
+ if (!sid_to_fstring(string_sid, member)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ expr = talloc_asprintf(ldb, "(&(member=%s)(objectClass=groupMap))",
+ string_sid);
+ if (expr == NULL) goto failed;
+
+ ret = ldb_search(ldb, NULL, LDB_SCOPE_SUBTREE, expr, attrs, &res);
+ talloc_steal(expr, res);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ for (i=0;i<res->count;i++) {
+ struct ldb_message_element *el;
+ el = ldb_msg_find_element(res->msgs[i], "sid");
+ if (el == NULL || el->num_values != 1) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto failed;
+ }
+ string_to_sid(&alias, (char *)el->values[0].data);
+ status = add_sid_to_array_unique(NULL, &alias, sids, num);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+ }
+
+ talloc_free(expr);
+ return NT_STATUS_OK;
+
+failed:
+ talloc_free(expr);
+ return status;
+}
+
+/*
+ add/remove a member field
+*/
+static NTSTATUS modify_aliasmem(const DOM_SID *alias, const DOM_SID *member,
+ int operation)
+{
+ fstring string_sid;
+ int ret;
+ struct ldb_message msg;
+ struct ldb_message_element el;
+ struct ldb_val val;
+ TALLOC_CTX *tmp_ctx;
+ GROUP_MAP map;
+
+ if (!get_group_map_from_sid(*alias, &map)) {
+ sid_to_fstring(string_sid, alias);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ if ((map.sid_name_use != SID_NAME_ALIAS) &&
+ (map.sid_name_use != SID_NAME_WKN_GRP)) {
+ DEBUG(0,("sid_name_use=%d\n", map.sid_name_use));
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ msg.dn = mapping_dn(tmp_ctx, alias);
+ if (msg.dn == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ msg.num_elements = 1;
+ msg.elements = &el;
+ el.flags = operation;
+ el.name = talloc_strdup(tmp_ctx, "member");
+ el.num_values = 1;
+ el.values = &val;
+ sid_to_fstring(string_sid, member);
+ val.data = (uint8_t *)string_sid;
+ val.length = strlen(string_sid);
+
+ ret = ldb_modify(ldb, &msg);
+ talloc_free(tmp_ctx);
+
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ if (operation == LDB_FLAG_MOD_ADD &&
+ ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
+ return NT_STATUS_MEMBER_IN_ALIAS;
+ }
+
+ return (ret == LDB_SUCCESS ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED);
+}
+
+static NTSTATUS add_aliasmem(const DOM_SID *alias, const DOM_SID *member)
+{
+ return modify_aliasmem(alias, member, LDB_FLAG_MOD_ADD);
+}
+
+static NTSTATUS del_aliasmem(const DOM_SID *alias, const DOM_SID *member)
+{
+ return modify_aliasmem(alias, member, LDB_FLAG_MOD_DELETE);
+}
+
+
+/*
+ enumerate sids that have the given alias set in member
+*/
+static NTSTATUS enum_aliasmem(const DOM_SID *alias, DOM_SID **sids, size_t *num)
+{
+ const char *attrs[] = {
+ "member",
+ NULL
+ };
+ int ret, i;
+ NTSTATUS status = NT_STATUS_OK;
+ struct ldb_result *res=NULL;
+ struct ldb_dn *dn;
+ struct ldb_message_element *el;
+
+ *sids = NULL;
+ *num = 0;
+
+ dn = mapping_dn(ldb, alias);
+ if (dn == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, NULL, attrs, &res);
+ talloc_steal(dn, res);
+ if (ret == LDB_SUCCESS && res->count == 0) {
+ talloc_free(dn);
+ return NT_STATUS_OK;
+ }
+ if (ret != LDB_SUCCESS) {
+ talloc_free(dn);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ el = ldb_msg_find_element(res->msgs[0], "member");
+ if (el == NULL) {
+ talloc_free(dn);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ for (i=0;i<el->num_values;i++) {
+ DOM_SID sid;
+ string_to_sid(&sid, (const char *)el->values[i].data);
+ status = add_sid_to_array_unique(NULL, &sid, sids, num);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ }
+
+done:
+ talloc_free(dn);
+ return status;
+}
+
+/*
+ upgrade one group mapping record from the old tdb format
+*/
+static int upgrade_map_record(TDB_CONTEXT *tdb_ctx, TDB_DATA key,
+ TDB_DATA data, void *state)
+{
+ int ret;
+ GROUP_MAP map;
+
+ if (strncmp((char *)key.dptr, GROUP_PREFIX,
+ MIN(key.dsize, strlen(GROUP_PREFIX))) != 0) {
+ return 0;
+ }
+
+ if (!string_to_sid(&map.sid, strlen(GROUP_PREFIX) + (const char *)key.dptr)) {
+ DEBUG(0,("Bad sid key '%s' during upgrade\n", (const char *)key.dptr));
+ *(int *)state = -1;
+ return -1;
+ }
+
+ ret = tdb_unpack(data.dptr, data.dsize, "ddff",
+ &map.gid, &map.sid_name_use, &map.nt_name, &map.comment);
+ if (ret == -1) {
+ DEBUG(0,("Failed to unpack group map record during upgrade\n"));
+ *(int *)state = -1;
+ return -1;
+ }
+
+ if (!add_mapping_entry(&map, 0)) {
+ DEBUG(0,("Failed to add mapping entry during upgrade\n"));
+ *(int *)state = -1;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ upgrade one alias record from the old tdb format
+*/
+static int upgrade_alias_record(TDB_CONTEXT *tdb_ctx, TDB_DATA key,
+ TDB_DATA data, void *state)
+{
+ const char *p = (const char *)data.dptr;
+ char *string_sid;
+ DOM_SID member;
+ TALLOC_CTX *frame;
+
+ if (strncmp((char *)key.dptr, MEMBEROF_PREFIX,
+ MIN(key.dsize, strlen(MEMBEROF_PREFIX))) != 0) {
+ return 0;
+ }
+
+ if (!string_to_sid(&member, strlen(MEMBEROF_PREFIX) + (const char *)key.dptr)) {
+ DEBUG(0,("Bad alias key %s during upgrade\n",
+ (const char *)key.dptr));
+ *(int *)state = -1;
+ }
+
+ frame = talloc_stackframe();
+ while (next_token_talloc(frame,&p, &string_sid, " ")) {
+ DOM_SID alias;
+ NTSTATUS status;
+ string_to_sid(&alias, string_sid);
+ status = add_aliasmem(&alias, &member);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_ALIAS)) {
+ DEBUG(0,("Ignoring orphaned alias record '%s'\n",
+ string_sid));
+ } else if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Failed to add alias member during upgrade - %s\n",
+ nt_errstr(status)));
+ *(int *)state = -1;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ }
+ TALLOC_FREE(frame);
+ return 0;
+}
+
+/*
+ upgrade from a old style tdb
+*/
+static bool mapping_upgrade(const char *tdb_path)
+{
+ static TDB_CONTEXT *tdb;
+ int ret, status=0;
+
+ tdb = tdb_open_log(tdb_path, 0, TDB_DEFAULT, O_RDWR, 0600);
+ if (tdb == NULL) goto failed;
+
+ /* we have to do the map records first, as alias records may
+ reference them */
+ ret = tdb_traverse(tdb, upgrade_map_record, &status);
+ if (ret == -1 || status == -1) goto failed;
+
+ ret = tdb_traverse(tdb, upgrade_alias_record, &status);
+ if (ret == -1 || status == -1) goto failed;
+
+ if (tdb) {
+ tdb_close(tdb);
+ tdb = NULL;
+ }
+
+ {
+ const char *old_path = tdb_path;
+ char *new_path = state_path("group_mapping.tdb.upgraded");
+
+ if (!new_path) {
+ goto failed;
+ }
+ if (rename(old_path, new_path) != 0) {
+ DEBUG(0,("Failed to rename old group mapping database\n"));
+ goto failed;
+ }
+ }
+ return True;
+
+failed:
+ DEBUG(0,("Failed to upgrade group mapping database\n"));
+ if (tdb) tdb_close(tdb);
+ return False;
+}
+
+
+
+static const struct mapping_backend ldb_backend = {
+ .add_mapping_entry = add_mapping_entry,
+ .get_group_map_from_sid = get_group_map_from_sid,
+ .get_group_map_from_gid = get_group_map_from_gid,
+ .get_group_map_from_ntname = get_group_map_from_ntname,
+ .group_map_remove = group_map_remove,
+ .enum_group_mapping = enum_group_mapping,
+ .one_alias_membership = one_alias_membership,
+ .add_aliasmem = add_aliasmem,
+ .del_aliasmem = del_aliasmem,
+ .enum_aliasmem = enum_aliasmem
+};
+
+/*
+ initialise the ldb mapping backend
+ */
+const struct mapping_backend *groupdb_ldb_init(void)
+{
+ if (!init_group_mapping()) {
+ DEBUG(0,("Failed to initialise ldb mapping backend\n"));
+ return NULL;
+ }
+
+ return &ldb_backend;
+}
diff --git a/source3/groupdb/mapping_tdb.c b/source3/groupdb/mapping_tdb.c
new file mode 100644
index 0000000000..7cee53a968
--- /dev/null
+++ b/source3/groupdb/mapping_tdb.c
@@ -0,0 +1,744 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2006,
+ * Copyright (C) Jean François Micouleau 1998-2001.
+ * Copyright (C) Volker Lendecke 2006.
+ * Copyright (C) Gerald Carter 2006.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "groupdb/mapping.h"
+
+static struct db_context *db; /* used for driver files */
+
+static bool enum_group_mapping(const DOM_SID *domsid, enum lsa_SidType sid_name_use, GROUP_MAP **pp_rmap,
+ size_t *p_num_entries, bool unix_only);
+static bool group_map_remove(const DOM_SID *sid);
+
+/****************************************************************************
+ Open the group mapping tdb.
+****************************************************************************/
+static bool init_group_mapping(void)
+{
+ if (db != NULL) {
+ return true;
+ }
+
+ db = db_open(NULL, state_path("group_mapping.tdb"), 0,
+ TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if (db == NULL) {
+ DEBUG(0, ("Failed to open group mapping database: %s\n",
+ strerror(errno)));
+ return false;
+ }
+
+#if 0
+ /*
+ * This code was designed to handle a group mapping version
+ * upgrade. mapping_tdb is not active by default anymore, so ignore
+ * this here.
+ */
+ {
+ const char *vstring = "INFO/version";
+ int32 vers_id;
+ GROUP_MAP *map_table = NULL;
+ size_t num_entries = 0;
+
+ /* handle a Samba upgrade */
+ tdb_lock_bystring(tdb, vstring);
+
+ /* Cope with byte-reversed older versions of the db. */
+ vers_id = tdb_fetch_int32(tdb, vstring);
+ if ((vers_id == DATABASE_VERSION_V1)
+ || (IREV(vers_id) == DATABASE_VERSION_V1)) {
+ /*
+ * Written on a bigendian machine with old fetch_int
+ * code. Save as le.
+ */
+ tdb_store_int32(tdb, vstring, DATABASE_VERSION_V2);
+ vers_id = DATABASE_VERSION_V2;
+ }
+
+ /* if its an unknown version we remove everthing in the db */
+
+ if (vers_id != DATABASE_VERSION_V2) {
+ tdb_wipe_all(tdb);
+ tdb_store_int32(tdb, vstring, DATABASE_VERSION_V2);
+ }
+
+ tdb_unlock_bystring(tdb, vstring);
+
+ /* cleanup any map entries with a gid == -1 */
+
+ if ( enum_group_mapping( NULL, SID_NAME_UNKNOWN, &map_table,
+ &num_entries, False ) ) {
+ int i;
+
+ for ( i=0; i<num_entries; i++ ) {
+ if ( map_table[i].gid == -1 ) {
+ group_map_remove( &map_table[i].sid );
+ }
+ }
+
+ SAFE_FREE( map_table );
+ }
+ }
+#endif
+
+ return true;
+}
+
+static char *group_mapping_key(TALLOC_CTX *mem_ctx, const DOM_SID *sid)
+{
+ char *sidstr, *result;
+
+ sidstr = sid_string_talloc(talloc_tos(), sid);
+ if (sidstr == NULL) {
+ return NULL;
+ }
+
+ result = talloc_asprintf(mem_ctx, "%s%s", GROUP_PREFIX, sidstr);
+
+ TALLOC_FREE(sidstr);
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+static bool add_mapping_entry(GROUP_MAP *map, int flag)
+{
+ char *key, *buf;
+ int len;
+ NTSTATUS status;
+
+ key = group_mapping_key(talloc_tos(), &map->sid);
+ if (key == NULL) {
+ return false;
+ }
+
+ len = tdb_pack(NULL, 0, "ddff",
+ map->gid, map->sid_name_use, map->nt_name, map->comment);
+
+ buf = TALLOC_ARRAY(key, char, len);
+ if (!buf) {
+ TALLOC_FREE(key);
+ return false;
+ }
+ len = tdb_pack((uint8 *)buf, len, "ddff", map->gid,
+ map->sid_name_use, map->nt_name, map->comment);
+
+ status = dbwrap_trans_store(
+ db, string_term_tdb_data(key),
+ make_tdb_data((uint8_t *)buf, len), TDB_REPLACE);
+
+ TALLOC_FREE(key);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Return the sid and the type of the unix group.
+****************************************************************************/
+
+static bool get_group_map_from_sid(DOM_SID sid, GROUP_MAP *map)
+{
+ TDB_DATA dbuf;
+ char *key;
+ int ret = 0;
+
+ /* the key is the SID, retrieving is direct */
+
+ key = group_mapping_key(talloc_tos(), &sid);
+ if (key == NULL) {
+ return false;
+ }
+
+ dbuf = dbwrap_fetch_bystring(db, key, key);
+ if (dbuf.dptr == NULL) {
+ TALLOC_FREE(key);
+ return false;
+ }
+
+ ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddff",
+ &map->gid, &map->sid_name_use,
+ &map->nt_name, &map->comment);
+
+ TALLOC_FREE(key);
+
+ if ( ret == -1 ) {
+ DEBUG(3,("get_group_map_from_sid: tdb_unpack failure\n"));
+ return false;
+ }
+
+ sid_copy(&map->sid, &sid);
+
+ return true;
+}
+
+static bool dbrec2map(const struct db_record *rec, GROUP_MAP *map)
+{
+ if ((rec->key.dsize < strlen(GROUP_PREFIX))
+ || (strncmp((char *)rec->key.dptr, GROUP_PREFIX,
+ GROUP_PREFIX_LEN) != 0)) {
+ return False;
+ }
+
+ if (!string_to_sid(&map->sid, (const char *)rec->key.dptr
+ + GROUP_PREFIX_LEN)) {
+ return False;
+ }
+
+ return tdb_unpack(rec->value.dptr, rec->value.dsize, "ddff",
+ &map->gid, &map->sid_name_use, &map->nt_name,
+ &map->comment) != -1;
+}
+
+struct find_map_state {
+ bool found;
+ const char *name; /* If != NULL, look for name */
+ gid_t gid; /* valid iff name == NULL */
+ GROUP_MAP *map;
+};
+
+static int find_map(struct db_record *rec, void *private_data)
+{
+ struct find_map_state *state = (struct find_map_state *)private_data;
+
+ if (!dbrec2map(rec, state->map)) {
+ DEBUG(10, ("failed to unpack map\n"));
+ return 0;
+ }
+
+ if (state->name != NULL) {
+ if (strequal(state->name, state->map->nt_name)) {
+ state->found = true;
+ return 1;
+ }
+ }
+ else {
+ if (state->map->gid == state->gid) {
+ state->found = true;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Return the sid and the type of the unix group.
+****************************************************************************/
+
+static bool get_group_map_from_gid(gid_t gid, GROUP_MAP *map)
+{
+ struct find_map_state state;
+
+ state.found = false;
+ state.name = NULL; /* Indicate we're looking for gid */
+ state.gid = gid;
+ state.map = map;
+
+ db->traverse_read(db, find_map, (void *)&state);
+
+ return state.found;
+}
+
+/****************************************************************************
+ Return the sid and the type of the unix group.
+****************************************************************************/
+
+static bool get_group_map_from_ntname(const char *name, GROUP_MAP *map)
+{
+ struct find_map_state state;
+
+ state.found = false;
+ state.name = name;
+ state.map = map;
+
+ db->traverse_read(db, find_map, (void *)&state);
+
+ return state.found;
+}
+
+/****************************************************************************
+ Remove a group mapping entry.
+****************************************************************************/
+
+static bool group_map_remove(const DOM_SID *sid)
+{
+ char *key;
+ NTSTATUS status;
+
+ key = group_mapping_key(talloc_tos(), sid);
+ if (key == NULL) {
+ return false;
+ }
+
+ status = dbwrap_trans_delete(db, string_term_tdb_data(key));
+
+ TALLOC_FREE(key);
+ return NT_STATUS_IS_OK(status);
+}
+
+/****************************************************************************
+ Enumerate the group mapping.
+****************************************************************************/
+
+struct enum_map_state {
+ const DOM_SID *domsid;
+ enum lsa_SidType sid_name_use;
+ bool unix_only;
+
+ size_t num_maps;
+ GROUP_MAP *maps;
+};
+
+static int collect_map(struct db_record *rec, void *private_data)
+{
+ struct enum_map_state *state = (struct enum_map_state *)private_data;
+ GROUP_MAP map;
+ GROUP_MAP *tmp;
+
+ if (!dbrec2map(rec, &map)) {
+ return 0;
+ }
+ /* list only the type or everything if UNKNOWN */
+ if (state->sid_name_use != SID_NAME_UNKNOWN
+ && state->sid_name_use != map.sid_name_use) {
+ DEBUG(11,("enum_group_mapping: group %s is not of the "
+ "requested type\n", map.nt_name));
+ return 0;
+ }
+
+ if ((state->unix_only == ENUM_ONLY_MAPPED) && (map.gid == -1)) {
+ DEBUG(11,("enum_group_mapping: group %s is non mapped\n",
+ map.nt_name));
+ return 0;
+ }
+
+ if ((state->domsid != NULL) &&
+ (sid_compare_domain(state->domsid, &map.sid) != 0)) {
+ DEBUG(11,("enum_group_mapping: group %s is not in domain\n",
+ sid_string_dbg(&map.sid)));
+ return 0;
+ }
+
+ if (!(tmp = SMB_REALLOC_ARRAY(state->maps, GROUP_MAP,
+ state->num_maps+1))) {
+ DEBUG(0,("enum_group_mapping: Unable to enlarge group "
+ "map!\n"));
+ return 1;
+ }
+
+ state->maps = tmp;
+ state->maps[state->num_maps] = map;
+ state->num_maps++;
+ return 0;
+}
+
+static bool enum_group_mapping(const DOM_SID *domsid,
+ enum lsa_SidType sid_name_use,
+ GROUP_MAP **pp_rmap,
+ size_t *p_num_entries, bool unix_only)
+{
+ struct enum_map_state state;
+
+ state.domsid = domsid;
+ state.sid_name_use = sid_name_use;
+ state.unix_only = unix_only;
+ state.num_maps = 0;
+ state.maps = NULL;
+
+ if (db->traverse_read(db, collect_map, (void *)&state) < 0) {
+ return false;
+ }
+
+ *pp_rmap = state.maps;
+ *p_num_entries = state.num_maps;
+
+ return true;
+}
+
+/* This operation happens on session setup, so it should better be fast. We
+ * store a list of aliases a SID is member of hanging off MEMBEROF/SID. */
+
+static NTSTATUS one_alias_membership(const DOM_SID *member,
+ DOM_SID **sids, size_t *num)
+{
+ fstring tmp;
+ fstring key;
+ char *string_sid;
+ TDB_DATA dbuf;
+ const char *p;
+ NTSTATUS status = NT_STATUS_OK;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ slprintf(key, sizeof(key), "%s%s", MEMBEROF_PREFIX,
+ sid_to_fstring(tmp, member));
+
+ dbuf = dbwrap_fetch_bystring(db, frame, key);
+ if (dbuf.dptr == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
+
+ p = (const char *)dbuf.dptr;
+
+ while (next_token_talloc(frame, &p, &string_sid, " ")) {
+ DOM_SID alias;
+
+ if (!string_to_sid(&alias, string_sid))
+ continue;
+
+ status= add_sid_to_array_unique(NULL, &alias, sids, num);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ }
+
+done:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+static NTSTATUS alias_memberships(const DOM_SID *members, size_t num_members,
+ DOM_SID **sids, size_t *num)
+{
+ size_t i;
+
+ *num = 0;
+ *sids = NULL;
+
+ for (i=0; i<num_members; i++) {
+ NTSTATUS status = one_alias_membership(&members[i], sids, num);
+ if (!NT_STATUS_IS_OK(status))
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+static bool is_aliasmem(const DOM_SID *alias, const DOM_SID *member)
+{
+ DOM_SID *sids;
+ size_t i, num;
+
+ /* This feels the wrong way round, but the on-disk data structure
+ * dictates it this way. */
+ if (!NT_STATUS_IS_OK(alias_memberships(member, 1, &sids, &num)))
+ return False;
+
+ for (i=0; i<num; i++) {
+ if (sid_compare(alias, &sids[i]) == 0) {
+ TALLOC_FREE(sids);
+ return True;
+ }
+ }
+ TALLOC_FREE(sids);
+ return False;
+}
+
+
+static NTSTATUS add_aliasmem(const DOM_SID *alias, const DOM_SID *member)
+{
+ GROUP_MAP map;
+ char *key;
+ fstring string_sid;
+ char *new_memberstring;
+ struct db_record *rec;
+ NTSTATUS status;
+
+ if (!get_group_map_from_sid(*alias, &map))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ if ( (map.sid_name_use != SID_NAME_ALIAS) &&
+ (map.sid_name_use != SID_NAME_WKN_GRP) )
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ if (is_aliasmem(alias, member))
+ return NT_STATUS_MEMBER_IN_ALIAS;
+
+ sid_to_fstring(string_sid, member);
+
+ key = talloc_asprintf(talloc_tos(), "%s%s", MEMBEROF_PREFIX,
+ string_sid);
+ if (key == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (db->transaction_start(db) != 0) {
+ DEBUG(0, ("transaction_start failed\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ rec = db->fetch_locked(db, key, string_term_tdb_data(key));
+
+ if (rec == NULL) {
+ DEBUG(10, ("fetch_lock failed\n"));
+ TALLOC_FREE(key);
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto cancel;
+ }
+
+ sid_to_fstring(string_sid, alias);
+
+ if (rec->value.dptr != NULL) {
+ new_memberstring = talloc_asprintf(
+ key, "%s %s", (char *)(rec->value.dptr), string_sid);
+ } else {
+ new_memberstring = talloc_strdup(key, string_sid);
+ }
+
+ if (new_memberstring == NULL) {
+ TALLOC_FREE(key);
+ status = NT_STATUS_NO_MEMORY;
+ goto cancel;
+ }
+
+ status = rec->store(rec, string_term_tdb_data(new_memberstring), 0);
+
+ TALLOC_FREE(key);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Could not store record: %s\n", nt_errstr(status)));
+ goto cancel;
+ }
+
+ if (db->transaction_commit(db) != 0) {
+ DEBUG(0, ("transaction_commit failed\n"));
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ return status;
+ }
+
+ return NT_STATUS_OK;
+
+ cancel:
+ if (db->transaction_cancel(db) != 0) {
+ smb_panic("transaction_cancel failed");
+ }
+
+ return status;
+}
+
+struct aliasmem_state {
+ const DOM_SID *alias;
+ DOM_SID **sids;
+ size_t *num;
+};
+
+static int collect_aliasmem(struct db_record *rec, void *priv)
+{
+ struct aliasmem_state *state = (struct aliasmem_state *)priv;
+ const char *p;
+ char *alias_string;
+ TALLOC_CTX *frame;
+
+ if (strncmp((const char *)rec->key.dptr, MEMBEROF_PREFIX,
+ MEMBEROF_PREFIX_LEN) != 0)
+ return 0;
+
+ p = (const char *)rec->value.dptr;
+
+ frame = talloc_stackframe();
+
+ while (next_token_talloc(frame, &p, &alias_string, " ")) {
+ DOM_SID alias, member;
+ const char *member_string;
+
+ if (!string_to_sid(&alias, alias_string))
+ continue;
+
+ if (sid_compare(state->alias, &alias) != 0)
+ continue;
+
+ /* Ok, we found the alias we're looking for in the membership
+ * list currently scanned. The key represents the alias
+ * member. Add that. */
+
+ member_string = strchr((const char *)rec->key.dptr, '/');
+
+ /* Above we tested for MEMBEROF_PREFIX which includes the
+ * slash. */
+
+ SMB_ASSERT(member_string != NULL);
+ member_string += 1;
+
+ if (!string_to_sid(&member, member_string))
+ continue;
+
+ if (!NT_STATUS_IS_OK(add_sid_to_array(NULL, &member,
+ state->sids,
+ state->num)))
+ {
+ /* talloc fail. */
+ break;
+ }
+ }
+
+ TALLOC_FREE(frame);
+ return 0;
+}
+
+static NTSTATUS enum_aliasmem(const DOM_SID *alias, DOM_SID **sids, size_t *num)
+{
+ GROUP_MAP map;
+ struct aliasmem_state state;
+
+ if (!get_group_map_from_sid(*alias, &map))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ if ( (map.sid_name_use != SID_NAME_ALIAS) &&
+ (map.sid_name_use != SID_NAME_WKN_GRP) )
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ *sids = NULL;
+ *num = 0;
+
+ state.alias = alias;
+ state.sids = sids;
+ state.num = num;
+
+ db->traverse_read(db, collect_aliasmem, &state);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS del_aliasmem(const DOM_SID *alias, const DOM_SID *member)
+{
+ NTSTATUS status;
+ DOM_SID *sids;
+ size_t i, num;
+ bool found = False;
+ char *member_string;
+ char *key;
+ fstring sid_string;
+
+ if (db->transaction_start(db) != 0) {
+ DEBUG(0, ("transaction_start failed\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ status = alias_memberships(member, 1, &sids, &num);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto cancel;
+ }
+
+ for (i=0; i<num; i++) {
+ if (sid_compare(&sids[i], alias) == 0) {
+ found = True;
+ break;
+ }
+ }
+
+ if (!found) {
+ TALLOC_FREE(sids);
+ status = NT_STATUS_MEMBER_NOT_IN_ALIAS;
+ goto cancel;
+ }
+
+ if (i < num)
+ sids[i] = sids[num-1];
+
+ num -= 1;
+
+ sid_to_fstring(sid_string, member);
+
+ key = talloc_asprintf(sids, "%s%s", MEMBEROF_PREFIX, sid_string);
+ if (key == NULL) {
+ TALLOC_FREE(sids);
+ status = NT_STATUS_NO_MEMORY;
+ goto cancel;
+ }
+
+ if (num == 0) {
+ status = dbwrap_delete_bystring(db, key);
+ TALLOC_FREE(sids);
+ goto cancel;
+ }
+
+ member_string = talloc_strdup(sids, "");
+ if (member_string == NULL) {
+ TALLOC_FREE(sids);
+ status = NT_STATUS_NO_MEMORY;
+ goto cancel;
+ }
+
+ for (i=0; i<num; i++) {
+
+ sid_to_fstring(sid_string, &sids[i]);
+
+ member_string = talloc_asprintf_append_buffer(
+ member_string, " %s", sid_string);
+
+ if (member_string == NULL) {
+ TALLOC_FREE(sids);
+ status = NT_STATUS_NO_MEMORY;
+ goto cancel;
+ }
+ }
+
+ status = dbwrap_store_bystring(
+ db, key, string_term_tdb_data(member_string), 0);
+
+ TALLOC_FREE(sids);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("dbwrap_store_bystring failed: %s\n",
+ nt_errstr(status)));
+ goto cancel;
+ }
+
+ if (db->transaction_commit(db) != 0) {
+ DEBUG(0, ("transaction_commit failed\n"));
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ return status;
+ }
+
+ return NT_STATUS_OK;
+
+ cancel:
+ if (db->transaction_cancel(db) != 0) {
+ smb_panic("transaction_cancel failed");
+ }
+ return status;
+}
+
+static const struct mapping_backend tdb_backend = {
+ .add_mapping_entry = add_mapping_entry,
+ .get_group_map_from_sid = get_group_map_from_sid,
+ .get_group_map_from_gid = get_group_map_from_gid,
+ .get_group_map_from_ntname = get_group_map_from_ntname,
+ .group_map_remove = group_map_remove,
+ .enum_group_mapping = enum_group_mapping,
+ .one_alias_membership = one_alias_membership,
+ .add_aliasmem = add_aliasmem,
+ .del_aliasmem = del_aliasmem,
+ .enum_aliasmem = enum_aliasmem
+};
+
+/*
+ initialise the tdb mapping backend
+ */
+const struct mapping_backend *groupdb_tdb_init(void)
+{
+ if (!init_group_mapping()) {
+ DEBUG(0,("Failed to initialise tdb mapping backend\n"));
+ return NULL;
+ }
+
+ return &tdb_backend;
+}
diff --git a/source3/include/MacExtensions.h b/source3/include/MacExtensions.h
new file mode 100644
index 0000000000..6e911feea2
--- /dev/null
+++ b/source3/include/MacExtensions.h
@@ -0,0 +1,245 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) John H Terpstra 1996-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Paul Ashton 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef _MAC_EXTENSIONS_H
+#define _MAC_EXTENSIONS_H
+
+/* Folder that holds the stream info */
+#define STREAM_FOLDER ".streams"
+#define STREAM_FOLDER_SLASH ".streams/"
+
+/* Common Streams Names*/
+#define DefaultStreamTestLen 6
+#define DefaultStreamTest ":$DATA"
+#define AFPDATA_STREAM "::$DATA"
+#define AFPINFO_STREAM ":AFP_AfpInfo:$DATA"
+#define AFPRESOURCE_STREAM ":AFP_Resource:$DATA"
+#define AFPCOMMENTS_STREAM ":Comments:$DATA"
+#define AFPDESKTOP_STREAM ":AFP_DeskTop:$DATA"
+#define AFPIDINDEX_STREAM ":AFP_IdIndex:$DATA"
+
+/*
+** NT's AFP_AfpInfo stream structure
+*/
+#define APF_INFO_SIZE 0x3c
+#define AFP_Signature 0x41465000
+#define AFP_Version 0x00000100
+#define AFP_BackupTime 0x00000080
+#define AFP_FinderSize 32
+/*
+** Orginal AFP_AfpInfo stream used by NT
+** We needed a way to store the create date so SAMBA
+** AFP_AfpInfo adds for bytes to this structrure
+** and call's it _SambaAfpInfo
+*/
+typedef struct _AfpInfo
+{
+ uint32 afpi_Signature; /* Must be *(PDWORD)"AFP" */
+ uint32 afpi_Version; /* Must be 0x00010000 */
+ uint32 afpi_Reserved1;
+ uint32 afpi_BackupTime; /* Backup time for the file/dir */
+ unsigned char afpi_FinderInfo[AFP_FinderSize]; /* Finder Info (32 bytes) */
+ unsigned char afpi_ProDosInfo[6]; /* ProDos Info (6 bytes) # */
+ unsigned char afpi_Reserved2[6];
+} AfpInfo;
+
+typedef struct _SambaAfpInfo
+{
+ AfpInfo afp;
+ unsigned long createtime;
+} SambaAfpInfo;
+
+/*
+** On SAMBA this structrue is followed by 4 bytes that store the create
+** date of the file or folder asociated with it.
+*/
+
+/*
+** These extentions are only supported with the NT LM 0.12 Dialect. These extentions
+** will be process on a share by share bases.
+*/
+
+/*
+** Trans2_Query_FS_Information Call is used by the MacCIFS extentions for three reasons.
+** First to see if the remote server share supports the basic Macintosh CIFS extentions.
+** Second to return some basic need information about the share to the Macintosh.
+** Third to see if this share support any other Macintosh extentions.
+**
+** We will be using infromation levels that are betwwen 0x300 and 0x399 for all Macintosh
+** extentions calls. The first of these will be the SMB_MAC_QUERY_FS_INFO level which
+** will allow the server to return the MacQueryFSInfo structure. All fields are Little
+** Endian unless other wise specified.
+*/
+#define SMB_MAC_QUERY_FS_INFO 0x301
+
+
+
+/*
+** The server will return folder access control in the Trans2_Find_First2
+** and Trans2_Find_Next2 message described later in this document.
+*/
+#define SUPPORT_MAC_ACCESS_CNTRL 0x0010
+/*
+** The server supports setting/getting comments using the mechanism in this
+** document instead of using the NTFS format described in the Introduction.
+*/
+#define SUPPORT_MAC_GETSETCOMMENTS 0x0020
+/*
+** The Server supports setting and getting Macintosh desktop database information
+** using the mechanism in this document.
+*/
+#define SUPPORT_MAC_DESKTOPDB_CALLS 0x0040
+/*
+** The server will return a unique id for files and directories in the
+** Trans2_Find_First2 and Trans2_Find_Next2 message described later in this document.
+*/
+#define SUPPORT_MAC_UNIQUE_IDS 0x0080
+/*
+** The server will return this flag telling the client that the server does
+** not support streams or the Macintosh extensions. The rest of this message
+** will be ignored by the client.
+*/
+#define NO_STREAMS_OR_MAC_SUPPORT 0x0100
+
+/*
+** We will be adding a new info level to the Trans2_Find_First2 and Trans2_Find_Next2.
+** This info level will be SMB_MAC_FIND_BOTH_HFS_INFO and will support the server
+** return additional information need by the Macintosh. All fields are Little
+** Endian unless other wise specified.
+*/
+
+#define SMB_MAC_FIND_BOTH_HFS_INFO 0x302
+
+enum {
+ ownerRead = 0x0400,
+ ownerWrite = 0x0200,
+ ownerSearch = 0x0100,
+ groupRead = 0x0040,
+ groupWrite = 0x0020,
+ groupSearch = 0x0010,
+ otherRead = 0x0004,
+ otherWrite = 0x0002,
+ otherSearch = 0x0001,
+ Owner = 0x0800
+};
+
+
+/*
+** We will be adding a new info level to the Trans2_Set_Path_Information.
+** This info level will be SMB_MAC_SET_FINDER_INFO and will support the client
+** setting information on the server need by the Macintosh. All fields are Little
+** Endian unless other wise specified.
+*/
+
+#define SMB_MAC_SET_FINDER_INFO 0x303
+
+enum {
+ SetCreateDate = 0x01, /* If this is set then set the create date of the file/folder */
+ SetModDate = 0x02, /* If this is set then set the modify date of the file/folder */
+ SetFLAttrib = 0x04, /* If this is set then set the Macintosh lock bit of the file/folder */
+ FndrInfo1 = 0x08, /* If this is set then set the first 16 bytes of finder info */
+ FndrInfo2 = 0x10, /* If this is set then set the second 16 bytes of finder info */
+ SetHidden = 0x20 /* We are either setting or unsetting the hidden bit */
+};
+
+
+/*
+** We will be adding some new info level to the Trans2_Set_Path_Information and Trans2_Query_Path_Information.
+** These info levels will allow the client to add, get, and remove desktop inforamtion from the
+** server. How the server stores this information is up to them.
+*/
+
+/*
+** We need to be able to store an application name and its creator in a database. We send a
+** Trans2_Set_Path_Information call with the full path of the application in the path field.
+** We will send an info level that represents adding an application name and creator to the database.
+** We will pass the File Creator in the data message.
+**
+** The server should just respond with no error or an error.
+*/
+#define SMB_MAC_DT_ADD_APPL 0x304
+
+/*
+** We need to be able to remove an application name and its creator from a database. We send a
+** Trans2_Set_Path_Information call with the full path of the application in the path field.
+** We will send an info level that represents removing an application name and creator from the database.
+** We will pass the File Creator in the data message.
+**
+** The server should just respond with no error or an error.
+*/
+#define SMB_MAC_DT_REMOVE_APPL 0x305
+
+
+/*
+** We need to be able to get an application name and its creator from a database. We send a
+** Trans2_Query_Path_Information call in which the name field is just ignore.
+** We will send an info level that represents getting an application name with a structure that
+** contains the File Creator and index. Were index has the following meaning.
+** Index = 0; Get the application path from the database with the most current date.
+** Index > 0; Use the index to find the application path from the database.
+** e.g. index of 5 means get the fifth entry of this application name in the database.
+** if not entry return an error.
+**
+** The server returns with a structure that contains the full path to the appication and
+** its creator's date.
+*/
+#define SMB_MAC_DT_GET_APPL 0x306
+
+
+/*
+** We need to be able to get an icon from a database. We send a Trans2_Query_Path_Information call in
+** which the path name is ignore. We will send an info level that represents getting an icon with a structure
+** that contains the Requested size of the icon, the Icon type, File Creator, and File Type.
+**
+** The server returns with a structure that contains the actual size of the icon
+** (must be less than requested length) and the icon bit map.
+*/
+#define SMB_MAC_DT_GET_ICON 0x307
+
+
+/*
+** We need to be able to get an icon from a database. We send a Trans2_Query_Path_Information call in
+** which the path name is ignore. We will send an info level that represents getting an icon with a structure
+** that contains the index and File Creator. The index allows the client to make repeated calls to the server
+** gathering all icon stored by this file creator.
+**
+**
+** The server returns with a structure that contains the actual size of the icon
+** (must be less than requested length) and the icon bit map, File Type, and Icon Type.
+*/
+#define SMB_MAC_DT_GET_ICON_INFO 0x308
+
+
+
+/*
+** We need to be able to add an icon to a database. We send a Trans2_Set_Path_Information call in
+** which the path name is ignore. We will send an info level that represents setting an icon with a structure
+** that contains the icon data, icon size, icon type, the file type, and file creator.
+**
+**
+** The server returns only that the call was successful or not.
+*/
+#define SMB_MAC_DT_ADD_ICON 0x309
+
+#endif /* _MAC_EXTENSIONS_H */
+
+/* _MAC_EXTENSIONS_H */
+
diff --git a/source3/include/ads.h b/source3/include/ads.h
new file mode 100644
index 0000000000..97faf0b6eb
--- /dev/null
+++ b/source3/include/ads.h
@@ -0,0 +1,425 @@
+#ifndef _INCLUDE_ADS_H_
+#define _INCLUDE_ADS_H_
+/*
+ header for ads (active directory) library routines
+
+ basically this is a wrapper around ldap
+*/
+
+enum wb_posix_mapping {
+ WB_POSIX_MAP_UNKNOWN = -1,
+ WB_POSIX_MAP_TEMPLATE = 0,
+ WB_POSIX_MAP_SFU = 1,
+ WB_POSIX_MAP_SFU20 = 2,
+ WB_POSIX_MAP_RFC2307 = 3,
+ WB_POSIX_MAP_UNIXINFO = 4
+};
+
+/* there are 5 possible types of errors the ads subsystem can produce */
+enum ads_error_type {ENUM_ADS_ERROR_KRB5, ENUM_ADS_ERROR_GSS,
+ ENUM_ADS_ERROR_LDAP, ENUM_ADS_ERROR_SYSTEM, ENUM_ADS_ERROR_NT};
+
+typedef struct {
+ enum ads_error_type error_type;
+ union err_state{
+ int rc;
+ NTSTATUS nt_status;
+ } err;
+ /* For error_type = ENUM_ADS_ERROR_GSS minor_status describe GSS API error */
+ /* Where rc represents major_status of GSS API error */
+ int minor_status;
+} ADS_STATUS;
+
+struct ads_struct;
+
+struct ads_saslwrap_ops {
+ const char *name;
+ ADS_STATUS (*wrap)(struct ads_struct *, uint8 *buf, uint32 len);
+ ADS_STATUS (*unwrap)(struct ads_struct *);
+ void (*disconnect)(struct ads_struct *);
+};
+
+enum ads_saslwrap_type {
+ ADS_SASLWRAP_TYPE_PLAIN = 1,
+ ADS_SASLWRAP_TYPE_SIGN = 2,
+ ADS_SASLWRAP_TYPE_SEAL = 4
+};
+
+typedef struct ads_struct {
+ int is_mine; /* do I own this structure's memory? */
+
+ /* info needed to find the server */
+ struct {
+ char *realm;
+ char *workgroup;
+ char *ldap_server;
+ int foreign; /* set to 1 if connecting to a foreign
+ * realm */
+ bool gc; /* Is this a global catalog server? */
+ } server;
+
+ /* info needed to authenticate */
+ struct {
+ char *realm;
+ char *password;
+ char *user_name;
+ char *kdc_server;
+ unsigned flags;
+ int time_offset;
+ time_t tgt_expire;
+ time_t tgs_expire;
+ time_t renewable;
+ } auth;
+
+ /* info derived from the servers config */
+ struct {
+ uint32 flags; /* cldap flags identifying the services. */
+ char *realm;
+ char *bind_path;
+ char *ldap_server_name;
+ char *server_site_name;
+ char *client_site_name;
+ time_t current_time;
+ int tried_closest_dc;
+ char *schema_path;
+ char *config_path;
+ } config;
+
+ /* info about the current LDAP connection */
+#ifdef HAVE_LDAP
+ struct {
+ LDAP *ld;
+ struct sockaddr_storage ss; /* the ip of the active connection, if any */
+ time_t last_attempt; /* last attempt to reconnect */
+ int port;
+
+ enum ads_saslwrap_type wrap_type;
+
+#ifdef HAVE_LDAP_SASL_WRAPPING
+ Sockbuf_IO_Desc *sbiod; /* lowlevel state for LDAP wrapping */
+#endif /* HAVE_LDAP_SASL_WRAPPING */
+ TALLOC_CTX *mem_ctx;
+ const struct ads_saslwrap_ops *wrap_ops;
+ void *wrap_private_data;
+ struct {
+ uint32 ofs;
+ uint32 needed;
+ uint32 left;
+#define ADS_SASL_WRAPPING_IN_MAX_WRAPPED 0x0FFFFFFF
+ uint32 max_wrapped;
+ uint32 min_wrapped;
+ uint32 size;
+ uint8 *buf;
+ } in;
+ struct {
+ uint32 ofs;
+ uint32 left;
+#define ADS_SASL_WRAPPING_OUT_MAX_WRAPPED 0x00A00000
+ uint32 max_unwrapped;
+ uint32 sig_size;
+ uint32 size;
+ uint8 *buf;
+ } out;
+ } ldap;
+#endif /* HAVE_LDAP */
+} ADS_STRUCT;
+
+/* used to remember the names of the posix attributes in AD */
+/* see the rfc2307 & sfu nss backends */
+
+struct posix_schema {
+ char *posix_homedir_attr;
+ char *posix_shell_attr;
+ char *posix_uidnumber_attr;
+ char *posix_gidnumber_attr;
+ char *posix_gecos_attr;
+};
+
+
+
+#ifdef HAVE_ADS
+typedef LDAPMod **ADS_MODLIST;
+#else
+typedef void **ADS_MODLIST;
+#endif
+
+/* macros to simplify error returning */
+#define ADS_ERROR(rc) ADS_ERROR_LDAP(rc)
+#define ADS_ERROR_LDAP(rc) ads_build_error(ENUM_ADS_ERROR_LDAP, rc, 0)
+#define ADS_ERROR_SYSTEM(rc) ads_build_error(ENUM_ADS_ERROR_SYSTEM, rc?rc:EINVAL, 0)
+#define ADS_ERROR_KRB5(rc) ads_build_error(ENUM_ADS_ERROR_KRB5, rc, 0)
+#define ADS_ERROR_GSS(rc, minor) ads_build_error(ENUM_ADS_ERROR_GSS, rc, minor)
+#define ADS_ERROR_NT(rc) ads_build_nt_error(ENUM_ADS_ERROR_NT,rc)
+
+#define ADS_ERR_OK(status) ((status.error_type == ENUM_ADS_ERROR_NT) ? NT_STATUS_IS_OK(status.err.nt_status):(status.err.rc == 0))
+#define ADS_SUCCESS ADS_ERROR(0)
+
+#define ADS_ERROR_HAVE_NO_MEMORY(x) do { \
+ if (!(x)) {\
+ return ADS_ERROR(LDAP_NO_MEMORY);\
+ }\
+} while (0)
+
+
+/* time between reconnect attempts */
+#define ADS_RECONNECT_TIME 5
+
+/* ldap control oids */
+#define ADS_PAGE_CTL_OID "1.2.840.113556.1.4.319"
+#define ADS_NO_REFERRALS_OID "1.2.840.113556.1.4.1339"
+#define ADS_SERVER_SORT_OID "1.2.840.113556.1.4.473"
+#define ADS_PERMIT_MODIFY_OID "1.2.840.113556.1.4.1413"
+#define ADS_ASQ_OID "1.2.840.113556.1.4.1504"
+#define ADS_EXTENDED_DN_OID "1.2.840.113556.1.4.529"
+#define ADS_SD_FLAGS_OID "1.2.840.113556.1.4.801"
+
+/* ldap attribute oids (Services for Unix 3.0, 3.5) */
+#define ADS_ATTR_SFU_UIDNUMBER_OID "1.2.840.113556.1.6.18.1.310"
+#define ADS_ATTR_SFU_GIDNUMBER_OID "1.2.840.113556.1.6.18.1.311"
+#define ADS_ATTR_SFU_HOMEDIR_OID "1.2.840.113556.1.6.18.1.344"
+#define ADS_ATTR_SFU_SHELL_OID "1.2.840.113556.1.6.18.1.312"
+#define ADS_ATTR_SFU_GECOS_OID "1.2.840.113556.1.6.18.1.337"
+
+/* ldap attribute oids (Services for Unix 2.0) */
+#define ADS_ATTR_SFU20_UIDNUMBER_OID "1.2.840.113556.1.4.7000.187.70"
+#define ADS_ATTR_SFU20_GIDNUMBER_OID "1.2.840.113556.1.4.7000.187.71"
+#define ADS_ATTR_SFU20_HOMEDIR_OID "1.2.840.113556.1.4.7000.187.106"
+#define ADS_ATTR_SFU20_SHELL_OID "1.2.840.113556.1.4.7000.187.72"
+#define ADS_ATTR_SFU20_GECOS_OID "1.2.840.113556.1.4.7000.187.97"
+
+/* ldap attribute oids (RFC2307) */
+#define ADS_ATTR_RFC2307_UIDNUMBER_OID "1.3.6.1.1.1.1.0"
+#define ADS_ATTR_RFC2307_GIDNUMBER_OID "1.3.6.1.1.1.1.1"
+#define ADS_ATTR_RFC2307_HOMEDIR_OID "1.3.6.1.1.1.1.3"
+#define ADS_ATTR_RFC2307_SHELL_OID "1.3.6.1.1.1.1.4"
+#define ADS_ATTR_RFC2307_GECOS_OID "1.3.6.1.1.1.1.2"
+
+/* ldap bitwise searches */
+#define ADS_LDAP_MATCHING_RULE_BIT_AND "1.2.840.113556.1.4.803"
+#define ADS_LDAP_MATCHING_RULE_BIT_OR "1.2.840.113556.1.4.804"
+
+/* UserFlags for userAccountControl */
+#define UF_SCRIPT 0x00000001
+#define UF_ACCOUNTDISABLE 0x00000002
+#define UF_UNUSED_1 0x00000004
+#define UF_HOMEDIR_REQUIRED 0x00000008
+
+#define UF_LOCKOUT 0x00000010
+#define UF_PASSWD_NOTREQD 0x00000020
+#define UF_PASSWD_CANT_CHANGE 0x00000040
+#define UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED 0x00000080
+
+#define UF_TEMP_DUPLICATE_ACCOUNT 0x00000100
+#define UF_NORMAL_ACCOUNT 0x00000200
+#define UF_UNUSED_2 0x00000400
+#define UF_INTERDOMAIN_TRUST_ACCOUNT 0x00000800
+
+#define UF_WORKSTATION_TRUST_ACCOUNT 0x00001000
+#define UF_SERVER_TRUST_ACCOUNT 0x00002000
+#define UF_UNUSED_3 0x00004000
+#define UF_UNUSED_4 0x00008000
+
+#define UF_DONT_EXPIRE_PASSWD 0x00010000
+#define UF_MNS_LOGON_ACCOUNT 0x00020000
+#define UF_SMARTCARD_REQUIRED 0x00040000
+#define UF_TRUSTED_FOR_DELEGATION 0x00080000
+
+#define UF_NOT_DELEGATED 0x00100000
+#define UF_USE_DES_KEY_ONLY 0x00200000
+#define UF_DONT_REQUIRE_PREAUTH 0x00400000
+#define UF_PASSWORD_EXPIRED 0x00800000
+
+#define UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION 0x01000000
+#define UF_NO_AUTH_DATA_REQUIRED 0x02000000
+#define UF_UNUSED_8 0x04000000
+#define UF_UNUSED_9 0x08000000
+
+#define UF_UNUSED_10 0x10000000
+#define UF_UNUSED_11 0x20000000
+#define UF_UNUSED_12 0x40000000
+#define UF_UNUSED_13 0x80000000
+
+#define UF_MACHINE_ACCOUNT_MASK (\
+ UF_INTERDOMAIN_TRUST_ACCOUNT |\
+ UF_WORKSTATION_TRUST_ACCOUNT |\
+ UF_SERVER_TRUST_ACCOUNT \
+ )
+
+#define UF_ACCOUNT_TYPE_MASK (\
+ UF_TEMP_DUPLICATE_ACCOUNT |\
+ UF_NORMAL_ACCOUNT |\
+ UF_INTERDOMAIN_TRUST_ACCOUNT |\
+ UF_WORKSTATION_TRUST_ACCOUNT |\
+ UF_SERVER_TRUST_ACCOUNT \
+ )
+
+#define UF_SETTABLE_BITS (\
+ UF_SCRIPT |\
+ UF_ACCOUNTDISABLE |\
+ UF_HOMEDIR_REQUIRED |\
+ UF_LOCKOUT |\
+ UF_PASSWD_NOTREQD |\
+ UF_PASSWD_CANT_CHANGE |\
+ UF_ACCOUNT_TYPE_MASK | \
+ UF_DONT_EXPIRE_PASSWD | \
+ UF_MNS_LOGON_ACCOUNT |\
+ UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED |\
+ UF_SMARTCARD_REQUIRED |\
+ UF_TRUSTED_FOR_DELEGATION |\
+ UF_NOT_DELEGATED |\
+ UF_USE_DES_KEY_ONLY |\
+ UF_DONT_REQUIRE_PREAUTH \
+ )
+
+/* sAMAccountType */
+#define ATYPE_NORMAL_ACCOUNT 0x30000000 /* 805306368 */
+#define ATYPE_WORKSTATION_TRUST 0x30000001 /* 805306369 */
+#define ATYPE_INTERDOMAIN_TRUST 0x30000002 /* 805306370 */
+#define ATYPE_SECURITY_GLOBAL_GROUP 0x10000000 /* 268435456 */
+#define ATYPE_DISTRIBUTION_GLOBAL_GROUP 0x10000001 /* 268435457 */
+#define ATYPE_DISTRIBUTION_UNIVERSAL_GROUP ATYPE_DISTRIBUTION_GLOBAL_GROUP
+#define ATYPE_SECURITY_LOCAL_GROUP 0x20000000 /* 536870912 */
+#define ATYPE_DISTRIBUTION_LOCAL_GROUP 0x20000001 /* 536870913 */
+
+#define ATYPE_ACCOUNT ATYPE_NORMAL_ACCOUNT /* 0x30000000 805306368 */
+#define ATYPE_GLOBAL_GROUP ATYPE_SECURITY_GLOBAL_GROUP /* 0x10000000 268435456 */
+#define ATYPE_LOCAL_GROUP ATYPE_SECURITY_LOCAL_GROUP /* 0x20000000 536870912 */
+
+/* groupType */
+#define GROUP_TYPE_BUILTIN_LOCAL_GROUP 0x00000001
+#define GROUP_TYPE_ACCOUNT_GROUP 0x00000002
+#define GROUP_TYPE_RESOURCE_GROUP 0x00000004
+#define GROUP_TYPE_UNIVERSAL_GROUP 0x00000008
+#define GROUP_TYPE_APP_BASIC_GROUP 0x00000010
+#define GROUP_TYPE_APP_QUERY_GROUP 0x00000020
+#define GROUP_TYPE_SECURITY_ENABLED 0x80000000
+
+#define GTYPE_SECURITY_BUILTIN_LOCAL_GROUP ( /* 0x80000005 -2147483643 */ \
+ GROUP_TYPE_BUILTIN_LOCAL_GROUP| \
+ GROUP_TYPE_RESOURCE_GROUP| \
+ GROUP_TYPE_SECURITY_ENABLED \
+ )
+#define GTYPE_SECURITY_DOMAIN_LOCAL_GROUP ( /* 0x80000004 -2147483644 */ \
+ GROUP_TYPE_RESOURCE_GROUP| \
+ GROUP_TYPE_SECURITY_ENABLED \
+ )
+#define GTYPE_SECURITY_GLOBAL_GROUP ( /* 0x80000002 -2147483646 */ \
+ GROUP_TYPE_ACCOUNT_GROUP| \
+ GROUP_TYPE_SECURITY_ENABLED \
+ )
+#define GTYPE_SECURITY_UNIVERSAL_GROUP ( /* 0x80000008 -2147483656 */ \
+ GROUP_TYPE_UNIVERSAL_GROUP| \
+ GROUP_TYPE_SECURITY_ENABLED \
+ )
+
+#define GTYPE_DISTRIBUTION_GLOBAL_GROUP 0x00000002 /* 2 */
+#define GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP 0x00000004 /* 4 */
+#define GTYPE_DISTRIBUTION_UNIVERSAL_GROUP 0x00000008 /* 8 */
+
+#define ADS_PINGS 0x0000FFFF /* Ping response */
+#define ADS_DNS_CONTROLLER 0x20000000 /* DomainControllerName is a DNS name*/
+#define ADS_DNS_DOMAIN 0x40000000 /* DomainName is a DNS name */
+#define ADS_DNS_FOREST 0x80000000 /* DnsForestName is a DNS name */
+
+/* ads auth control flags */
+#define ADS_AUTH_DISABLE_KERBEROS 0x0001
+#define ADS_AUTH_NO_BIND 0x0002
+#define ADS_AUTH_ANON_BIND 0x0004
+#define ADS_AUTH_SIMPLE_BIND 0x0008
+#define ADS_AUTH_ALLOW_NTLMSSP 0x0010
+#define ADS_AUTH_SASL_SIGN 0x0020
+#define ADS_AUTH_SASL_SEAL 0x0040
+#define ADS_AUTH_SASL_FORCE 0x0080
+#define ADS_AUTH_USER_CREDS 0x0100
+
+/* Kerberos environment variable names */
+#define KRB5_ENV_CCNAME "KRB5CCNAME"
+
+/* Heimdal uses a slightly different name */
+#if defined(HAVE_ENCTYPE_ARCFOUR_HMAC_MD5)
+#define ENCTYPE_ARCFOUR_HMAC ENCTYPE_ARCFOUR_HMAC_MD5
+#endif
+
+/* The older versions of heimdal that don't have this
+ define don't seem to use it anyway. I'm told they
+ always use a subkey */
+#ifndef HAVE_AP_OPTS_USE_SUBKEY
+#define AP_OPTS_USE_SUBKEY 0
+#endif
+
+#define WELL_KNOWN_GUID_COMPUTERS "AA312825768811D1ADED00C04FD8D5CD"
+#define WELL_KNOWN_GUID_USERS "A9D1CA15768811D1ADED00C04FD8D5CD"
+
+#ifndef KRB5_ADDR_NETBIOS
+#define KRB5_ADDR_NETBIOS 0x14
+#endif
+
+#ifndef KRB5KRB_ERR_RESPONSE_TOO_BIG
+#define KRB5KRB_ERR_RESPONSE_TOO_BIG (-1765328332L)
+#endif
+
+#ifdef HAVE_KRB5
+typedef struct {
+ NTSTATUS ntstatus;
+ uint32 unknown1;
+ uint32 unknown2; /* 0x00000001 */
+} KRB5_EDATA_NTSTATUS;
+
+typedef struct {
+#if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
+ krb5_address **addrs;
+#elif defined(HAVE_KRB5_ADDRESSES) /* Heimdal */
+ krb5_addresses *addrs;
+#else
+#error UNKNOWN_KRB5_ADDRESS_TYPE
+#endif /* defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) */
+} smb_krb5_addresses;
+
+#ifdef HAVE_KRB5_KEYBLOCK_KEYVALUE /* Heimdal */
+#define KRB5_KEY_TYPE(k) ((k)->keytype)
+#define KRB5_KEY_LENGTH(k) ((k)->keyvalue.length)
+#define KRB5_KEY_DATA(k) ((k)->keyvalue.data)
+#define KRB5_KEY_DATA_CAST void
+#else /* MIT */
+#define KRB5_KEY_TYPE(k) ((k)->enctype)
+#define KRB5_KEY_LENGTH(k) ((k)->length)
+#define KRB5_KEY_DATA(k) ((k)->contents)
+#define KRB5_KEY_DATA_CAST krb5_octet
+#endif /* HAVE_KRB5_KEYBLOCK_KEYVALUE */
+
+#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEY /* MIT */
+#define KRB5_KT_KEY(k) (&(k)->key)
+#elif HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */
+#define KRB5_KT_KEY(k) (&(k)->keyblock)
+#else
+#error krb5_keytab_entry has no key or keyblock member
+#endif /* HAVE_KRB5_KEYTAB_ENTRY_KEY */
+
+#endif /* HAVE_KRB5 */
+
+enum ads_extended_dn_flags {
+ ADS_EXTENDED_DN_HEX_STRING = 0,
+ ADS_EXTENDED_DN_STRING = 1 /* not supported on win2k */
+};
+
+/* this is probably not very well suited to pass other controls generically but
+ * is good enough for the extended dn control where it is only used for atm */
+
+typedef struct {
+ const char *control;
+ int val;
+ int critical;
+} ads_control;
+
+#define ADS_EXTENDED_RIGHT_APPLY_GROUP_POLICY "edacfd8f-ffb3-11d1-b41d-00a0c968f939"
+
+#define ADS_IGNORE_PRINCIPAL "not_defined_in_RFC4178@please_ignore"
+
+/* Settings for the domainFunctionality attribute in the rootDSE */
+
+#define DS_DOMAIN_FUNCTION_2000 0
+#define DS_DOMAIN_FUCNTION_2003_MIXED 1
+#define DS_DOMAIN_FUNCTION_2003 2
+#define DS_DOMAIN_FUNCTION_2008 3
+
+#endif /* _INCLUDE_ADS_H_ */
diff --git a/source3/include/ads_dns.h b/source3/include/ads_dns.h
new file mode 100644
index 0000000000..24805f85a3
--- /dev/null
+++ b/source3/include/ads_dns.h
@@ -0,0 +1,61 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Internal DNS query structures
+ * Copyright (C) Gerald Carter 2006.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _ADS_DNS_H
+#define _ADS_DNS_H
+
+/* DNS query section in replies */
+
+struct dns_query {
+ const char *hostname;
+ uint16 type;
+ uint16 in_class;
+};
+
+/* DNS RR record in reply */
+
+struct dns_rr {
+ const char *hostname;
+ uint16 type;
+ uint16 in_class;
+ uint32 ttl;
+ uint16 rdatalen;
+ uint8 *rdata;
+};
+
+/* SRV records */
+
+struct dns_rr_srv {
+ const char *hostname;
+ uint16 priority;
+ uint16 weight;
+ uint16 port;
+ size_t num_ips;
+ struct sockaddr_storage *ss_s; /* support multi-homed hosts */
+};
+
+/* NS records */
+
+struct dns_rr_ns {
+ const char *hostname;
+ struct sockaddr_storage ss;
+};
+
+
+#endif /* _ADS_DNS_H */
diff --git a/source3/include/ads_protos.h b/source3/include/ads_protos.h
new file mode 100644
index 0000000000..a372010b79
--- /dev/null
+++ b/source3/include/ads_protos.h
@@ -0,0 +1,122 @@
+/*
+ * Prototypes for ads
+ */
+
+void ads_msgfree(ADS_STRUCT *ads, LDAPMessage *msg);
+char *ads_get_dn(ADS_STRUCT *ads, LDAPMessage *msg);
+char *ads_get_dn_canonical(ADS_STRUCT *ads, LDAPMessage *msg);
+
+char *ads_pull_string(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, LDAPMessage *msg,
+ const char *field);
+char **ads_pull_strings(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ LDAPMessage *msg, const char *field,
+ size_t *num_values);
+char **ads_pull_strings_range(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ LDAPMessage *msg, const char *field,
+ char **current_strings,
+ const char **next_attribute,
+ size_t *num_strings,
+ bool *more_strings);
+bool ads_pull_uint32(ADS_STRUCT *ads, LDAPMessage *msg, const char *field,
+ uint32 *v);
+bool ads_pull_guid(ADS_STRUCT *ads, LDAPMessage *msg, struct GUID *guid);
+bool ads_pull_sid(ADS_STRUCT *ads, LDAPMessage *msg, const char *field,
+ DOM_SID *sid);
+int ads_pull_sids(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ LDAPMessage *msg, const char *field, DOM_SID **sids);
+bool ads_pull_sd(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ LDAPMessage *msg, const char *field, SEC_DESC **sd);
+char *ads_pull_username(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ LDAPMessage *msg);
+int ads_pull_sids_from_extendeddn(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ LDAPMessage *msg,
+ const char *field,
+ enum ads_extended_dn_flags flags,
+ DOM_SID **sids);
+
+ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, LDAPMessage **res,
+ const char *machine);
+ADS_STATUS ads_find_printer_on_server(ADS_STRUCT *ads, LDAPMessage **res,
+ const char *printer,
+ const char *servername);
+ADS_STATUS ads_find_printers(ADS_STRUCT *ads, LDAPMessage **res);
+ADS_STATUS ads_find_user_acct(ADS_STRUCT *ads, LDAPMessage **res,
+ const char *user);
+
+ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope,
+ const char *expr,
+ const char **attrs, LDAPMessage **res);
+ADS_STATUS ads_search(ADS_STRUCT *ads, LDAPMessage **res,
+ const char *expr, const char **attrs);
+ADS_STATUS ads_search_dn(ADS_STRUCT *ads, LDAPMessage **res,
+ const char *dn, const char **attrs);
+ADS_STATUS ads_do_search_all_args(ADS_STRUCT *ads, const char *bind_path,
+ int scope, const char *expr,
+ const char **attrs, void *args,
+ LDAPMessage **res);
+ADS_STATUS ads_do_search_all(ADS_STRUCT *ads, const char *bind_path,
+ int scope, const char *expr,
+ const char **attrs, LDAPMessage **res);
+ADS_STATUS ads_do_search_retry(ADS_STRUCT *ads, const char *bind_path,
+ int scope,
+ const char *expr,
+ const char **attrs, LDAPMessage **res);
+ADS_STATUS ads_do_search_retry_args(ADS_STRUCT *ads, const char *bind_path,
+ int scope, const char *expr,
+ const char **attrs, void *args,
+ LDAPMessage **res);
+ADS_STATUS ads_search_retry(ADS_STRUCT *ads, LDAPMessage **res,
+ const char *expr, const char **attrs);
+ADS_STATUS ads_search_retry_dn(ADS_STRUCT *ads, LDAPMessage **res,
+ const char *dn,
+ const char **attrs);
+ADS_STATUS ads_search_retry_extended_dn(ADS_STRUCT *ads, LDAPMessage **res,
+ const char *dn,
+ const char **attrs,
+ enum ads_extended_dn_flags flags);
+ADS_STATUS ads_search_retry_extended_dn_ranged(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ const char *dn,
+ const char **attrs,
+ enum ads_extended_dn_flags flags,
+ char ***strings,
+ size_t *num_strings);
+ADS_STATUS ads_search_retry_sid(ADS_STRUCT *ads, LDAPMessage **res,
+ const DOM_SID *sid,
+ const char **attrs);
+
+
+LDAPMessage *ads_first_entry(ADS_STRUCT *ads, LDAPMessage *res);
+LDAPMessage *ads_next_entry(ADS_STRUCT *ads, LDAPMessage *res);
+LDAPMessage *ads_first_message(ADS_STRUCT *ads, LDAPMessage *res);
+LDAPMessage *ads_next_message(ADS_STRUCT *ads, LDAPMessage *res);
+void ads_process_results(ADS_STRUCT *ads, LDAPMessage *res,
+ bool (*fn)(ADS_STRUCT *,char *, void **, void *),
+ void *data_area);
+void ads_dump(ADS_STRUCT *ads, LDAPMessage *res);
+
+ADS_STATUS ads_parse_gpo(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ LDAPMessage *res,
+ const char *gpo_dn,
+ struct GROUP_POLICY_OBJECT *gpo);
+ADS_STATUS ads_search_retry_dn_sd_flags(ADS_STRUCT *ads, LDAPMessage **res,
+ uint32 sd_flags,
+ const char *dn,
+ const char **attrs);
+ADS_STATUS ads_do_search_all_sd_flags(ADS_STRUCT *ads, const char *bind_path,
+ int scope, const char *expr,
+ const char **attrs, uint32 sd_flags,
+ LDAPMessage **res);
+ADS_STATUS ads_get_tokensids(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *dn,
+ DOM_SID *user_sid,
+ DOM_SID *primary_group_sid,
+ DOM_SID **sids,
+ size_t *num_sids);
+ADS_STATUS ads_get_joinable_ous(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ char ***ous,
+ size_t *num_ous);
diff --git a/source3/include/adt_tree.h b/source3/include/adt_tree.h
new file mode 100644
index 0000000000..3acda8edb8
--- /dev/null
+++ b/source3/include/adt_tree.h
@@ -0,0 +1,61 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Generic Abstract Data Types
+ * Copyright (C) Gerald Carter 2002-2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ADT_TREE_H
+#define ADT_TREE_H
+
+/* data structure used to build the tree */
+
+typedef struct _tree_node {
+ struct _tree_node *parent;
+ struct _tree_node **children;
+ int num_children;
+ char *key;
+ void *data_p;
+} TREE_NODE;
+
+typedef struct _tree_root {
+ TREE_NODE *root;
+
+ /* not used currently (is it needed?) */
+ int (*compare)(void* x, void *y);
+} SORTED_TREE;
+
+/*
+ * API
+ */
+
+/* create a new tree, talloc_free() to throw it away */
+
+SORTED_TREE* pathtree_init( void *data_p, int (cmp_fn)(void*, void*) );
+
+/* add a new path component */
+
+WERROR pathtree_add( SORTED_TREE *tree, const char *path, void *data_p );
+
+/* search path */
+
+void* pathtree_find( SORTED_TREE *tree, char *key );
+
+/* debug (print) functions */
+
+void pathtree_print_keys( SORTED_TREE *tree, int debug );
+
+
+#endif
diff --git a/source3/include/asn_1.h b/source3/include/asn_1.h
new file mode 100644
index 0000000000..dd345cd601
--- /dev/null
+++ b/source3/include/asn_1.h
@@ -0,0 +1,71 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple ASN1 code
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _ASN_1_H
+#define _ASN_1_H
+
+struct nesting {
+ off_t start;
+ size_t taglen; /* for parsing */
+ struct nesting *next;
+};
+
+typedef struct asn1_data {
+ uint8 *data;
+ size_t length;
+ off_t ofs;
+ struct nesting *nesting;
+ bool has_error;
+} ASN1_DATA;
+
+
+#define ASN1_APPLICATION(x) ((x)+0x60)
+#define ASN1_APPLICATION_SIMPLE(x) ((x)+0x40)
+#define ASN1_SEQUENCE(x) ((x)+0x30)
+#define ASN1_CONTEXT(x) ((x)+0xa0)
+#define ASN1_CONTEXT_SIMPLE(x) ((x)+0x80)
+#define ASN1_GENERAL_STRING 0x1b
+#define ASN1_OCTET_STRING 0x4
+#define ASN1_OID 0x6
+#define ASN1_BOOLEAN 0x1
+#define ASN1_INTEGER 0x2
+#define ASN1_BITFIELD 0x3
+#define ASN1_ENUMERATED 0xa
+#define ASN1_SET 0x31
+
+#define ASN1_MAX_OIDS 20
+
+/* some well known object IDs */
+#define OID_SPNEGO "1 3 6 1 5 5 2"
+#define OID_NTLMSSP "1 3 6 1 4 1 311 2 2 10"
+#define OID_KERBEROS5_OLD "1 2 840 48018 1 2 2"
+#define OID_KERBEROS5 "1 2 840 113554 1 2 2"
+
+#define SPNEGO_NEG_RESULT_ACCEPT 0
+#define SPNEGO_NEG_RESULT_INCOMPLETE 1
+#define SPNEGO_NEG_RESULT_REJECT 2
+
+/* not really ASN.1, but RFC 1964 */
+#define TOK_ID_KRB_AP_REQ (uchar*)"\x01\x00"
+#define TOK_ID_KRB_AP_REP (uchar*)"\x02\x00"
+#define TOK_ID_KRB_ERROR (uchar*)"\x03\x00"
+#define TOK_ID_GSS_GETMIC (uchar*)"\x01\x01"
+#define TOK_ID_GSS_WRAP (uchar*)"\x02\x01"
+
+#endif /* _ASN_1_H */
diff --git a/source3/include/async_req.h b/source3/include/async_req.h
new file mode 100644
index 0000000000..2d01b53814
--- /dev/null
+++ b/source3/include/async_req.h
@@ -0,0 +1,137 @@
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async requests
+ Copyright (C) Volker Lendecke 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ASYNC_REQ_H__
+#define __ASYNC_REQ_H__
+
+#include "includes.h"
+
+/**
+ * An async request moves between the following 4 states:
+ */
+
+enum async_req_state {
+ /**
+ * we are creating the request
+ */
+ ASYNC_REQ_INIT,
+ /**
+ * we are waiting the request to complete
+ */
+ ASYNC_REQ_IN_PROGRESS,
+ /**
+ * the request is finished
+ */
+ ASYNC_REQ_DONE,
+ /**
+ * an error has occured
+ */
+ ASYNC_REQ_ERROR
+};
+
+/**
+ * @brief An async request
+ *
+ * This represents an async request being processed by callbacks via an event
+ * context. A user can issue for example a write request to a socket, giving
+ * an implementation function the fd, the buffer and the number of bytes to
+ * transfer. The function issuing the request will immediately return without
+ * blocking most likely without having sent anything. The API user then fills
+ * in req->async.fn and req->async.priv, functions that are called when the
+ * request is finished.
+ *
+ * It is up to the user of the async request to talloc_free it after it has
+ * finished. This can happen while the completion function is called.
+ */
+
+struct async_req {
+ /**
+ * @brief The external state - will be queried by the caller
+ *
+ * While the async request is being processed, state will remain in
+ * ASYNC_REQ_IN_PROGRESS. A request is finished if
+ * req->state>=ASYNC_REQ_DONE.
+ */
+ enum async_req_state state;
+
+ /**
+ * @brief Private pointer for the actual implementation
+ *
+ * The implementation doing the work for the async request needs a
+ * current state like for example a fd event. The user of an async
+ * request should not touch this.
+ */
+ void *private_data;
+
+ /**
+ * @brief Print yourself, for debugging purposes
+ *
+ * Async requests are opaque data structures. The implementation of an
+ * async request can define a custom function to print more debug
+ * info.
+ */
+ char *(*print)(TALLOC_CTX *mem_ctx, struct async_req *);
+
+ /**
+ * @brief status code when finished
+ *
+ * This status can be queried in the async completion function. It
+ * will be set to NT_STATUS_OK when everything went fine.
+ **/
+ NTSTATUS status;
+
+ /**
+ * @brief The event context we are using
+ *
+ * The event context that this async request works on.
+ */
+ struct event_context *event_ctx;
+
+ /**
+ * @brief What to do on completion
+ *
+ * This is used for the user of an async request, fn is called when
+ * the request completes, either successfully or with an error.
+ */
+ struct {
+ /**
+ * @brief Completion function
+ * Completion function, to be filled by the API user
+ */
+ void (*fn)(struct async_req *);
+ /**
+ * @brief Private data for the completion function
+ */
+ void *priv;
+ } async;
+};
+
+struct async_req *async_req_new(TALLOC_CTX *mem_ctx, struct event_context *ev);
+
+char *async_req_print(TALLOC_CTX *mem_ctx, struct async_req *req);
+
+void async_req_done(struct async_req *req);
+
+void async_req_error(struct async_req *req, NTSTATUS status);
+
+bool async_post_status(struct async_req *req, NTSTATUS status);
+
+bool async_req_nomem(const void *p, struct async_req *req);
+
+#endif
diff --git a/source3/include/async_smb.h b/source3/include/async_smb.h
new file mode 100644
index 0000000000..4e2061813f
--- /dev/null
+++ b/source3/include/async_smb.h
@@ -0,0 +1,145 @@
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async SMB client requests
+ Copyright (C) Volker Lendecke 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ASYNC_SMB_H__
+#define __ASYNC_SMB_H__
+
+#include "includes.h"
+
+/**
+ * struct cli_request is the state holder for an async client request we sent
+ * to the server. It can consist of more than one struct async_req that we
+ * have to server if the application did a cli_chain_cork() and
+ * cli_chain_uncork()
+ */
+
+struct cli_request {
+ /**
+ * "prev" and "next" form the doubly linked list in
+ * cli_state->outstanding_requests
+ */
+ struct cli_request *prev, *next;
+
+ /**
+ * num_async: How many chained requests do we serve?
+ */
+ int num_async;
+
+ /**
+ * async: This is the list of chained requests that were queued up by
+ * cli_request_chain before we sent out this request
+ */
+ struct async_req **async;
+
+ /**
+ * The client connection for this request
+ */
+ struct cli_state *cli;
+
+ /**
+ * The enc_state to decrypt the reply
+ */
+ struct smb_trans_enc_state *enc_state;
+
+ /**
+ * The mid we used for this request. Mainly used to demultiplex on
+ * receiving replies.
+ */
+ uint16_t mid;
+
+ /**
+ * The bytes we have to ship to the server
+ */
+ char *outbuf;
+
+ /**
+ * How much from "outbuf" did we already send
+ */
+ size_t sent;
+
+ /**
+ * The reply comes in here. Its intended size is implicit by
+ * smb_len(), its current size can be read via talloc_get_size()
+ */
+ char *inbuf;
+
+ /**
+ * Specific requests might add stuff here. Maybe convert this to a
+ * private_pointer at some point.
+ */
+ union {
+ struct {
+ off_t ofs;
+ size_t size;
+ ssize_t received;
+ uint8_t *rcvbuf;
+ } read;
+ struct {
+ DATA_BLOB data;
+ uint16_t num_echos;
+ } echo;
+ } data;
+
+ /**
+ * For requests that don't follow the strict request/reply pattern
+ * such as the transaction request family and echo requests it is
+ * necessary to break the standard procedure in
+ * handle_incoming_pdu(). For a simple example look at
+ * cli_echo_recv_helper().
+ */
+ struct {
+ void (*fn)(struct async_req *req);
+ void *priv;
+ } recv_helper;
+};
+
+/*
+ * Ship a new smb request to the server
+ */
+
+struct async_req *cli_request_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ uint8_t smb_command,
+ uint8_t additional_flags,
+ uint8_t wct, const uint16_t *vwv,
+ uint16_t num_bytes, const uint8_t *bytes);
+
+bool cli_chain_cork(struct cli_state *cli, struct event_context *ev,
+ size_t size_hint);
+void cli_chain_uncork(struct cli_state *cli);
+bool cli_in_chain(struct cli_state *cli);
+
+NTSTATUS cli_pull_reply(struct async_req *req,
+ uint8_t *pwct, uint16_t **pvwv,
+ uint16_t *pnum_bytes, uint8_t **pbytes);
+
+/*
+ * Fetch an error out of a NBT packet
+ */
+
+NTSTATUS cli_pull_error(char *buf);
+
+/*
+ * Compatibility helper for the sync APIs: Fake NTSTATUS in cli->inbuf
+ */
+
+void cli_set_error(struct cli_state *cli, NTSTATUS status);
+
+#endif
diff --git a/source3/include/async_sock.h b/source3/include/async_sock.h
new file mode 100644
index 0000000000..3c90453601
--- /dev/null
+++ b/source3/include/async_sock.h
@@ -0,0 +1,45 @@
+/*
+ Unix SMB/CIFS implementation.
+ async socket operations
+ Copyright (C) Volker Lendecke 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ASYNC_SOCK_H__
+#define __ASYNC_SOCK_H__
+
+#include "includes.h"
+
+ssize_t async_syscall_result_ssize_t(struct async_req **req, int *perrno);
+size_t async_syscall_result_size_t (struct async_req **req, int *perrno);
+ssize_t async_syscall_result_int (struct async_req **req, int *perrno);
+
+struct async_req *async_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ int fd, const void *buffer, size_t length,
+ int flags);
+struct async_req *async_sendall(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ int fd, const void *buffer, size_t length,
+ int flags);
+struct async_req *async_recv(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ int fd, void *buffer, size_t length,
+ int flags);
+struct async_req *async_recvall(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ int fd, void *buffer, size_t length,
+ int flags);
+struct async_req *async_connect(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ int fd, const struct sockaddr *address,
+ socklen_t address_len);
+
+#endif
diff --git a/source3/include/auth.h b/source3/include/auth.h
new file mode 100644
index 0000000000..adcd6e943f
--- /dev/null
+++ b/source3/include/auth.h
@@ -0,0 +1,148 @@
+#ifndef _SMBAUTH_H_
+#define _SMBAUTH_H_
+/*
+ Unix SMB/CIFS implementation.
+ Standardised Authentication types
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+typedef struct auth_usersupplied_info {
+ DATA_BLOB lm_resp;
+ DATA_BLOB nt_resp;
+ DATA_BLOB lm_interactive_pwd;
+ DATA_BLOB nt_interactive_pwd;
+ DATA_BLOB plaintext_password;
+
+ bool encrypted;
+
+ bool was_mapped; /* Did the username map actually match? */
+ char *client_domain; /* domain name string */
+ char *domain; /* domain name after mapping */
+ char *internal_username; /* username after mapping */
+ char *smb_name; /* username before mapping */
+ char *wksta_name; /* workstation name (netbios calling
+ * name) unicode string */
+
+ uint32 logon_parameters;
+
+} auth_usersupplied_info;
+
+typedef struct auth_serversupplied_info {
+ bool guest;
+
+ DOM_SID *sids; /* These SIDs are preliminary between
+ check_ntlm_password and the token creation. */
+ size_t num_sids;
+
+ struct unix_user_token utok;
+
+ /* NT group information taken from the info3 structure */
+
+ NT_USER_TOKEN *ptok;
+
+ DATA_BLOB user_session_key;
+ DATA_BLOB lm_session_key;
+
+ char *login_server; /* which server authorized the login? */
+
+ struct samu *sam_account;
+
+ void *pam_handle;
+
+ /*
+ * This is a token from /etc/passwd and /etc/group
+ */
+ bool nss_token;
+
+ char *unix_name;
+
+ /*
+ * For performance reasons we keep an alpha_strcpy-sanitized version
+ * of the username around as long as the global variable current_user
+ * still exists. If we did not do keep this, we'd have to call
+ * alpha_strcpy whenever we do a become_user(), potentially on every
+ * smb request. See set_current_user_info.
+ */
+ char *sanitized_username;
+} auth_serversupplied_info;
+
+struct auth_context {
+ DATA_BLOB challenge;
+
+ /* Who set this up in the first place? */
+ const char *challenge_set_by;
+
+ bool challenge_may_be_modified;
+
+ struct auth_methods *challenge_set_method;
+ /* What order are the various methods in? Try to stop it changing under us */
+ struct auth_methods *auth_method_list;
+
+ TALLOC_CTX *mem_ctx;
+ const uint8 *(*get_ntlm_challenge)(struct auth_context *auth_context);
+ NTSTATUS (*check_ntlm_password)(const struct auth_context *auth_context,
+ const struct auth_usersupplied_info *user_info,
+ struct auth_serversupplied_info **server_info);
+ NTSTATUS (*nt_status_squash)(NTSTATUS nt_status);
+ void (*free)(struct auth_context **auth_context);
+};
+
+typedef struct auth_methods
+{
+ struct auth_methods *prev, *next;
+ const char *name; /* What name got this module */
+
+ NTSTATUS (*auth)(const struct auth_context *auth_context,
+ void *my_private_data,
+ TALLOC_CTX *mem_ctx,
+ const struct auth_usersupplied_info *user_info,
+ auth_serversupplied_info **server_info);
+
+ /* If you are using this interface, then you are probably
+ * getting something wrong. This interface is only for
+ * security=server, and makes a number of compromises to allow
+ * that. It is not compatible with being a PDC. */
+ DATA_BLOB (*get_chal)(const struct auth_context *auth_context,
+ void **my_private_data,
+ TALLOC_CTX *mem_ctx);
+
+ /* Used to keep tabs on things like the cli for SMB server authentication */
+ void *private_data;
+
+} auth_methods;
+
+typedef NTSTATUS (*auth_init_function)(struct auth_context *, const char *, struct auth_methods **);
+
+struct auth_init_function_entry {
+ const char *name;
+ /* Function to create a member of the authmethods list */
+
+ auth_init_function init;
+
+ struct auth_init_function_entry *prev, *next;
+};
+
+typedef struct auth_ntlmssp_state {
+ TALLOC_CTX *mem_ctx;
+ struct auth_context *auth_context;
+ struct auth_serversupplied_info *server_info;
+ struct ntlmssp_state *ntlmssp_state;
+} AUTH_NTLMSSP_STATE;
+
+/* Changed from 1 -> 2 to add the logon_parameters field. */
+#define AUTH_INTERFACE_VERSION 2
+
+#endif /* _SMBAUTH_H_ */
diff --git a/source3/include/authdata.h b/source3/include/authdata.h
new file mode 100644
index 0000000000..70f6d2da9a
--- /dev/null
+++ b/source3/include/authdata.h
@@ -0,0 +1,39 @@
+/*
+ Unix SMB/CIFS implementation.
+ Kerberos authorization data
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AUTHDATA_H
+#define _AUTHDATA_H
+
+#include "rpc_misc.h"
+
+#define PAC_TYPE_LOGON_INFO 1
+#define PAC_TYPE_SERVER_CHECKSUM 6
+#define PAC_TYPE_PRIVSVR_CHECKSUM 7
+#define PAC_TYPE_LOGON_NAME 10
+
+#ifndef KRB5_AUTHDATA_WIN2K_PAC
+#define KRB5_AUTHDATA_WIN2K_PAC 128
+#endif
+
+#ifndef KRB5_AUTHDATA_IF_RELEVANT
+#define KRB5_AUTHDATA_IF_RELEVANT 1
+#endif
+
+#endif
diff --git a/source3/include/byteorder.h b/source3/include/byteorder.h
new file mode 100644
index 0000000000..9ced9cea3a
--- /dev/null
+++ b/source3/include/byteorder.h
@@ -0,0 +1,176 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Byte 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _BYTEORDER_H
+#define _BYTEORDER_H
+
+/*
+ This file implements macros for machine independent short and
+ int manipulation
+
+Here is a description of this file that I emailed to the samba list once:
+
+> I am confused about the way that byteorder.h works in Samba. I have
+> looked at it, and I would have thought that you might make a distinction
+> between LE and BE machines, but you only seem to distinguish between 386
+> and all other architectures.
+>
+> Can you give me a clue?
+
+sure.
+
+The distinction between 386 and other architectures is only there as
+an optimisation. You can take it out completely and it will make no
+difference. The routines (macros) in byteorder.h are totally byteorder
+independent. The 386 optimsation just takes advantage of the fact that
+the x86 processors don't care about alignment, so we don't have to
+align ints on int boundaries etc. If there are other processors out
+there that aren't alignment sensitive then you could also define
+CAREFUL_ALIGNMENT=0 on those processors as well.
+
+Ok, now to the macros themselves. I'll take a simple example, say we
+want to extract a 2 byte integer from a SMB packet and put it into a
+type called uint16 that is in the local machines byte order, and you
+want to do it with only the assumption that uint16 is _at_least_ 16
+bits long (this last condition is very important for architectures
+that don't have any int types that are 2 bytes long)
+
+You do this:
+
+#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
+#define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
+#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
+
+then to extract a uint16 value at offset 25 in a buffer you do this:
+
+char *buffer = foo_bar();
+uint16 xx = SVAL(buffer,25);
+
+We are using the byteoder independence of the ANSI C bitshifts to do
+the work. A good optimising compiler should turn this into efficient
+code, especially if it happens to have the right byteorder :-)
+
+I know these macros can be made a bit tidier by removing some of the
+casts, but you need to look at byteorder.h as a whole to see the
+reasoning behind them. byteorder.h defines the following macros:
+
+SVAL(buf,pos) - extract a 2 byte SMB value
+IVAL(buf,pos) - extract a 4 byte SMB value
+SVALS(buf,pos) signed version of SVAL()
+IVALS(buf,pos) signed version of IVAL()
+
+SSVAL(buf,pos,val) - put a 2 byte SMB value into a buffer
+SIVAL(buf,pos,val) - put a 4 byte SMB value into a buffer
+SSVALS(buf,pos,val) - signed version of SSVAL()
+SIVALS(buf,pos,val) - signed version of SIVAL()
+
+RSVAL(buf,pos) - like SVAL() but for NMB byte ordering
+RSVALS(buf,pos) - like SVALS() but for NMB byte ordering
+RIVAL(buf,pos) - like IVAL() but for NMB byte ordering
+RIVALS(buf,pos) - like IVALS() but for NMB byte ordering
+RSSVAL(buf,pos,val) - like SSVAL() but for NMB ordering
+RSIVAL(buf,pos,val) - like SIVAL() but for NMB ordering
+RSIVALS(buf,pos,val) - like SIVALS() but for NMB ordering
+
+it also defines lots of intermediate macros, just ignore those :-)
+
+*/
+
+#undef CAREFUL_ALIGNMENT
+
+/* we know that the 386 can handle misalignment and has the "right"
+ byteorder */
+#ifdef __i386__
+#define CAREFUL_ALIGNMENT 0
+#endif
+
+#ifndef CAREFUL_ALIGNMENT
+#define CAREFUL_ALIGNMENT 1
+#endif
+
+#define CVAL(buf,pos) ((unsigned)(((const unsigned char *)(buf))[pos]))
+#define CVAL_NC(buf,pos) (((unsigned char *)(buf))[pos]) /* Non-const version of CVAL */
+#define PVAL(buf,pos) (CVAL(buf,pos))
+#define SCVAL(buf,pos,val) (CVAL_NC(buf,pos) = (val))
+
+
+#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_NC(buf,pos)=(unsigned char)((val)&0xFF),CVAL_NC(buf,pos+1)=(unsigned char)((val)>>8))
+#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
+#define SVALS(buf,pos) ((int16)SVAL(buf,pos))
+#define IVALS(buf,pos) ((int32)IVAL(buf,pos))
+#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((uint16)(val)))
+#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 /* CAREFUL_ALIGNMENT */
+
+/* this handles things for architectures like the 386 that can handle
+ alignment errors */
+/*
+ WARNING: This section is dependent on the length of int16 and int32
+ being correct
+*/
+
+/* get single value from an SMB buffer */
+#define SVAL(buf,pos) (*(const uint16 *)((const char *)(buf) + (pos)))
+#define SVAL_NC(buf,pos) (*(uint16 *)((char *)(buf) + (pos))) /* Non const version of above. */
+#define IVAL(buf,pos) (*(const uint32 *)((const char *)(buf) + (pos)))
+#define IVAL_NC(buf,pos) (*(uint32 *)((char *)(buf) + (pos))) /* Non const version of above. */
+#define SVALS(buf,pos) (*(const int16 *)((const char *)(buf) + (pos)))
+#define SVALS_NC(buf,pos) (*(int16 *)((char *)(buf) + (pos))) /* Non const version of above. */
+#define IVALS(buf,pos) (*(const int32 *)((const char *)(buf) + (pos)))
+#define IVALS_NC(buf,pos) (*(int32 *)((char *)(buf) + (pos))) /* Non const version of above. */
+
+/* store single value in an SMB buffer */
+#define SSVAL(buf,pos,val) SVAL_NC(buf,pos)=((uint16)(val))
+#define SIVAL(buf,pos,val) IVAL_NC(buf,pos)=((uint32)(val))
+#define SSVALS(buf,pos,val) SVALS_NC(buf,pos)=((int16)(val))
+#define SIVALS(buf,pos,val) IVALS_NC(buf,pos)=((int32)(val))
+
+#endif /* CAREFUL_ALIGNMENT */
+
+/* now the reverse routines - these are used in nmb packets (mostly) */
+#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
+#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
+
+#define RSVAL(buf,pos) SREV(SVAL(buf,pos))
+#define RSVALS(buf,pos) SREV(SVALS(buf,pos))
+#define RIVAL(buf,pos) IREV(IVAL(buf,pos))
+#define RIVALS(buf,pos) IREV(IVALS(buf,pos))
+#define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
+#define RSSVALS(buf,pos,val) SSVALS(buf,pos,SREV(val))
+#define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
+#define RSIVALS(buf,pos,val) SIVALS(buf,pos,IREV(val))
+
+/* Alignment macros. */
+#define ALIGN4(p,base) ((p) + ((4 - (PTR_DIFF((p), (base)) & 3)) & 3))
+#define ALIGN2(p,base) ((p) + ((2 - (PTR_DIFF((p), (base)) & 1)) & 1))
+
+/* 64 bit macros */
+#define BVAL(p, ofs) (IVAL(p,ofs) | (((uint64_t)IVAL(p,(ofs)+4)) << 32))
+#define BVALS(p, ofs) ((int64_t)BVAL(p,ofs))
+#define SBVAL(p, ofs, v) (SIVAL(p,ofs,(v)&0xFFFFFFFF), SIVAL(p,(ofs)+4,((uint64_t)(v))>>32))
+#define SBVALS(p, ofs, v) (SBVAL(p,ofs,(uint64_t)v))
+
+#endif /* _BYTEORDER_H */
diff --git a/source3/include/charset.h b/source3/include/charset.h
new file mode 100644
index 0000000000..4d04b5a1a6
--- /dev/null
+++ b/source3/include/charset.h
@@ -0,0 +1,126 @@
+/*
+ Unix SMB/CIFS implementation.
+ charset defines
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jelmer Vernooij 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* this defines the charset types used in samba */
+typedef enum {CH_UTF16LE=0, CH_UTF16=0, CH_UNIX=1, CH_DISPLAY=2, CH_DOS=3, CH_UTF8=4, CH_UTF16BE=5} charset_t;
+
+#define NUM_CHARSETS 6
+
+/*
+ * for each charset we have a function that pushes from that charset to a ucs2
+ * buffer, and a function that pulls from ucs2 buffer to that charset.
+ * */
+
+struct charset_functions {
+ const char *name;
+ size_t (*pull)(void *, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+ size_t (*push)(void *, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+ struct charset_functions *prev, *next;
+};
+
+/*
+ * This is auxiliary struct used by source/script/gen-8-bit-gap.sh script
+ * during generation of an encoding table for charset module
+ * */
+
+struct charset_gap_table {
+ uint16 start;
+ uint16 end;
+ int32 idx;
+};
+
+/*
+ * Define stub for charset module which implements 8-bit encoding with gaps.
+ * Encoding tables for such module should be produced from glibc's CHARMAPs
+ * using script source/script/gen-8bit-gap.sh
+ * CHARSETNAME is CAPITALIZED charset name
+ *
+ * */
+#define SMB_GENERATE_CHARSET_MODULE_8_BIT_GAP(CHARSETNAME) \
+static size_t CHARSETNAME ## _push(void *cd, const char **inbuf, size_t *inbytesleft, \
+ char **outbuf, size_t *outbytesleft) \
+{ \
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) { \
+ int i; \
+ int done = 0; \
+ \
+ uint16 ch = SVAL(*inbuf,0); \
+ \
+ for (i=0; from_idx[i].start != 0xffff; i++) { \
+ if ((from_idx[i].start <= ch) && (from_idx[i].end >= ch)) { \
+ ((unsigned char*)(*outbuf))[0] = from_ucs2[from_idx[i].idx+ch]; \
+ (*inbytesleft) -= 2; \
+ (*outbytesleft) -= 1; \
+ (*inbuf) += 2; \
+ (*outbuf) += 1; \
+ done = 1; \
+ break; \
+ } \
+ } \
+ if (!done) { \
+ errno = EINVAL; \
+ return -1; \
+ } \
+ \
+ } \
+ \
+ if (*inbytesleft == 1) { \
+ errno = EINVAL; \
+ return -1; \
+ } \
+ \
+ if (*inbytesleft > 1) { \
+ errno = E2BIG; \
+ return -1; \
+ } \
+ \
+ return 0; \
+} \
+ \
+static size_t CHARSETNAME ## _pull(void *cd, const char **inbuf, size_t *inbytesleft, \
+ char **outbuf, size_t *outbytesleft) \
+{ \
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) { \
+ *(uint16*)(*outbuf) = to_ucs2[((unsigned char*)(*inbuf))[0]]; \
+ (*inbytesleft) -= 1; \
+ (*outbytesleft) -= 2; \
+ (*inbuf) += 1; \
+ (*outbuf) += 2; \
+ } \
+ \
+ if (*inbytesleft > 0) { \
+ errno = E2BIG; \
+ return -1; \
+ } \
+ \
+ return 0; \
+} \
+ \
+struct charset_functions CHARSETNAME ## _functions = \
+ {#CHARSETNAME, CHARSETNAME ## _pull, CHARSETNAME ## _push}; \
+ \
+NTSTATUS charset_ ## CHARSETNAME ## _init(void); \
+NTSTATUS charset_ ## CHARSETNAME ## _init(void) \
+{ \
+ return smb_register_charset(& CHARSETNAME ## _functions); \
+} \
+
diff --git a/source3/include/client.h b/source3/include/client.h
new file mode 100644
index 0000000000..70b0421c6d
--- /dev/null
+++ b/source3/include/client.h
@@ -0,0 +1,252 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _CLIENT_H
+#define _CLIENT_H
+
+/* the client asks for a smaller buffer to save ram and also to get more
+ overlap on the wire. This size gives us a nice read/write size, which
+ will be a multiple of the page size on almost any system */
+#define CLI_BUFFER_SIZE (0xFFFF)
+#define CLI_SAMBA_MAX_LARGE_READX_SIZE (127*1024) /* Works for Samba servers */
+#define CLI_SAMBA_MAX_LARGE_WRITEX_SIZE (127*1024) /* Works for Samba servers */
+#define CLI_WINDOWS_MAX_LARGE_READX_SIZE ((64*1024)-2) /* Windows servers are broken.... */
+#define CLI_WINDOWS_MAX_LARGE_WRITEX_SIZE ((64*1024)-2) /* Windows servers are broken.... */
+#define CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE (0xFFFF00) /* 24-bit len. */
+#define CLI_SAMBA_MAX_POSIX_LARGE_WRITEX_SIZE (0xFFFF00) /* 24-bit len. */
+
+/*
+ * These definitions depend on smb.h
+ */
+
+struct print_job_info {
+ uint16 id;
+ uint16 priority;
+ size_t size;
+ fstring user;
+ fstring name;
+ time_t t;
+};
+
+struct cli_pipe_auth_data {
+ enum pipe_auth_type auth_type; /* switch for the union below. Defined in ntdomain.h */
+ enum pipe_auth_level auth_level; /* defined in ntdomain.h */
+
+ char *domain;
+ char *user_name;
+
+ union {
+ struct schannel_auth_struct *schannel_auth;
+ NTLMSSP_STATE *ntlmssp_state;
+ struct kerberos_auth_struct *kerberos_auth;
+ } a_u;
+};
+
+struct rpc_pipe_client {
+ struct rpc_pipe_client *prev, *next;
+
+ enum dcerpc_transport_t transport_type;
+
+ union {
+ struct {
+ struct cli_state *cli;
+ const char *pipe_name;
+ uint16 fnum;
+ } np;
+ struct {
+ int fd;
+ } sock;
+ } trans ;
+
+ struct ndr_syntax_id abstract_syntax;
+ struct ndr_syntax_id transfer_syntax;
+
+ char *desthost;
+ char *srv_name_slash;
+
+ uint16 max_xmit_frag;
+ uint16 max_recv_frag;
+
+ struct cli_pipe_auth_data *auth;
+
+ /* The following is only non-null on a netlogon pipe. */
+ struct dcinfo *dc;
+};
+
+/* Transport encryption state. */
+enum smb_trans_enc_type {
+ SMB_TRANS_ENC_NTLM
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+ , SMB_TRANS_ENC_GSS
+#endif
+};
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+struct smb_tran_enc_state_gss {
+ gss_ctx_id_t gss_ctx;
+ gss_cred_id_t creds;
+};
+#endif
+
+struct smb_trans_enc_state {
+ enum smb_trans_enc_type smb_enc_type;
+ uint16 enc_ctx_num;
+ bool enc_on;
+ union {
+ NTLMSSP_STATE *ntlmssp_state;
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+ struct smb_tran_enc_state_gss *gss_state;
+#endif
+ } s;
+};
+
+struct cli_state {
+ int port;
+ int fd;
+ /* Last read or write error. */
+ enum smb_read_errors smb_rw_error;
+ uint16 cnum;
+ uint16 pid;
+ uint16 mid;
+ uint16 vuid;
+ int protocol;
+ int sec_mode;
+ int rap_error;
+ int privileges;
+
+ fstring desthost;
+
+ /* The credentials used to open the cli_state connection. */
+ fstring domain;
+ fstring user_name;
+ struct pwd_info pwd;
+
+ /*
+ * The following strings are the
+ * ones returned by the server if
+ * the protocol > NT1.
+ */
+ fstring server_type;
+ fstring server_os;
+ fstring server_domain;
+
+ fstring share;
+ fstring dev;
+ struct nmb_name called;
+ struct nmb_name calling;
+ fstring full_dest_host_name;
+ struct sockaddr_storage dest_ss;
+
+ DATA_BLOB secblob; /* cryptkey or negTokenInit */
+ uint32 sesskey;
+ int serverzone;
+ uint32 servertime;
+ int readbraw_supported;
+ int writebraw_supported;
+ int timeout; /* in milliseconds. */
+ size_t max_xmit;
+ size_t max_mux;
+ char *outbuf;
+ char *inbuf;
+ unsigned int bufsize;
+ int initialised;
+ int win95;
+ bool is_samba;
+ uint32 capabilities;
+ uint32 posix_capabilities;
+ bool dfsroot;
+
+#if 0
+ TALLOC_CTX *longterm_mem_ctx;
+ TALLOC_CTX *call_mem_ctx;
+#endif
+
+ smb_sign_info sign_info;
+
+ struct smb_trans_enc_state *trans_enc_state; /* Setup if we're encrypting SMB's. */
+
+ /* the session key for this CLI, outside
+ any per-pipe authenticaion */
+ DATA_BLOB user_session_key;
+
+ /* The list of pipes currently open on this connection. */
+ struct rpc_pipe_client *pipe_list;
+
+ bool use_kerberos;
+ bool fallback_after_kerberos;
+ bool use_spnego;
+ bool got_kerberos_mechanism; /* Server supports krb5 in SPNEGO. */
+
+ bool use_oplocks; /* should we use oplocks? */
+ bool use_level_II_oplocks; /* should we use level II oplocks? */
+
+ /* a oplock break request handler */
+ bool (*oplock_handler)(struct cli_state *cli, int fnum, unsigned char level);
+
+ bool force_dos_errors;
+ bool case_sensitive; /* False by default. */
+
+ /**
+ * fd_event is around while we have async requests outstanding or are
+ * building a chained request.
+ *
+ * (fd_event!=NULL) &&
+ * ((outstanding_request!=NULL)||(chain_accumulator!=NULL))
+ *
+ * should always be true, as well as the reverse: If both cli_request
+ * pointers are NULL, no fd_event is around.
+ */
+ struct fd_event *fd_event;
+ char *evt_inbuf;
+
+ /**
+ * A linked list of requests that are waiting for a reply
+ */
+ struct cli_request *outstanding_requests;
+
+ /**
+ * The place to build up the list of chained requests. In CIFS, a
+ * single cli_request corresponds to a MID and can serve more than one
+ * chained async_req.
+ */
+ struct cli_request *chain_accumulator;
+};
+
+typedef struct file_info {
+ struct cli_state *cli;
+ SMB_BIG_UINT size;
+ uint16 mode;
+ uid_t uid;
+ gid_t gid;
+ /* these times are normally kept in GMT */
+ struct timespec mtime_ts;
+ struct timespec atime_ts;
+ struct timespec ctime_ts;
+ char *name;
+ char short_name[13*3]; /* the *3 is to cope with multi-byte */
+} file_info;
+
+#define CLI_FULL_CONNECTION_DONT_SPNEGO 0x0001
+#define CLI_FULL_CONNECTION_USE_KERBEROS 0x0002
+#define CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK 0x0004
+#define CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS 0x0008
+
+#endif /* _CLIENT_H */
diff --git a/source3/include/clitar.h b/source3/include/clitar.h
new file mode 100644
index 0000000000..69267fbb08
--- /dev/null
+++ b/source3/include/clitar.h
@@ -0,0 +1,40 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * clitar file format
+ * Copyright (C) Andrew Tridgell 2000
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CLITAR_H
+#define _CLITAR_H
+
+#define TBLOCK 512
+#define NAMSIZ 100
+union hblock {
+ char dummy[TBLOCK];
+ struct header {
+ char name[NAMSIZ];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char chksum[8];
+ char linkflag;
+ char linkname[NAMSIZ];
+ } dbuf;
+};
+
+#endif /* _CLITAR_H */
diff --git a/source3/include/core.h b/source3/include/core.h
new file mode 100644
index 0000000000..1f9ddb8b3c
--- /dev/null
+++ b/source3/include/core.h
@@ -0,0 +1,3 @@
+/* dummy file to deal with pidl autogenerated ndr files */
+
+#include "nterr.h"
diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h
new file mode 100644
index 0000000000..39f50c2cfc
--- /dev/null
+++ b/source3/include/ctdbd_conn.h
@@ -0,0 +1,77 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba3 ctdb connection handling
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _CTDBD_CONN_H
+#define _CTDBD_CONN_H
+
+struct ctdbd_connection;
+
+NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx,
+ struct ctdbd_connection **pconn);
+NTSTATUS ctdbd_messaging_connection(TALLOC_CTX *mem_ctx,
+ struct ctdbd_connection **pconn);
+
+uint32 ctdbd_vnn(const struct ctdbd_connection *conn);
+
+NTSTATUS ctdbd_register_msg_ctx(struct ctdbd_connection *conn,
+ struct messaging_context *msg_ctx);
+
+NTSTATUS ctdbd_messaging_send(struct ctdbd_connection *conn,
+ uint32 dst_vnn, uint64 dst_srvid,
+ struct messaging_rec *msg);
+
+bool ctdbd_process_exists(struct ctdbd_connection *conn, uint32 vnn,
+ pid_t pid);
+
+char *ctdbd_dbpath(struct ctdbd_connection *conn,
+ TALLOC_CTX *mem_ctx, uint32_t db_id);
+
+NTSTATUS ctdbd_db_attach(struct ctdbd_connection *conn, const char *name,
+ uint32_t *db_id, int tdb_flags);
+
+NTSTATUS ctdbd_migrate(struct ctdbd_connection *conn, uint32 db_id,
+ TDB_DATA key);
+
+NTSTATUS ctdbd_fetch(struct ctdbd_connection *conn, uint32 db_id,
+ TDB_DATA key, TALLOC_CTX *mem_ctx, TDB_DATA *data);
+
+NTSTATUS ctdbd_traverse(uint32 db_id,
+ void (*fn)(TDB_DATA key, TDB_DATA data,
+ void *private_data),
+ void *private_data);
+
+NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn,
+ const struct sockaddr_in *server,
+ const struct sockaddr_in *client,
+ void (*release_ip_handler)(const char *ip_addr,
+ void *private_data),
+ void *private_data);
+
+NTSTATUS ctdbd_register_reconfigure(struct ctdbd_connection *conn);
+
+NTSTATUS ctdbd_persistent_store(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key, TDB_DATA data);
+NTSTATUS ctdbd_start_persistent_update(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key, TDB_DATA data);
+NTSTATUS ctdbd_cancel_persistent_update(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key, TDB_DATA data);
+
+NTSTATUS ctdbd_control_local(struct ctdbd_connection *conn, uint32 opcode,
+ uint64_t srvid, uint32_t flags, TDB_DATA data,
+ TALLOC_CTX *mem_ctx, TDB_DATA *outdata,
+ int *cstatus);
+
+#endif /* _CTDBD_CONN_H */
diff --git a/source3/include/dbwrap.h b/source3/include/dbwrap.h
new file mode 100644
index 0000000000..46833fabdc
--- /dev/null
+++ b/source3/include/dbwrap.h
@@ -0,0 +1,91 @@
+/*
+ Unix SMB/CIFS implementation.
+ Database interface wrapper around tdb
+ Copyright (C) Volker Lendecke 2005-2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __DBWRAP_H__
+#define __DBWRAP_H__
+
+struct db_record {
+ TDB_DATA key, value;
+ NTSTATUS (*store)(struct db_record *rec, TDB_DATA data, int flag);
+ NTSTATUS (*delete_rec)(struct db_record *rec);
+ void *private_data;
+};
+
+struct db_context {
+ struct db_record *(*fetch_locked)(struct db_context *db,
+ TALLOC_CTX *mem_ctx,
+ TDB_DATA key);
+ int (*fetch)(struct db_context *db, TALLOC_CTX *mem_ctx,
+ TDB_DATA key, TDB_DATA *data);
+ int (*traverse)(struct db_context *db,
+ int (*f)(struct db_record *rec,
+ void *private_data),
+ void *private_data);
+ int (*traverse_read)(struct db_context *db,
+ int (*f)(struct db_record *rec,
+ void *private_data),
+ void *private_data);
+ int (*get_seqnum)(struct db_context *db);
+ int (*transaction_start)(struct db_context *db);
+ int (*transaction_commit)(struct db_context *db);
+ int (*transaction_cancel)(struct db_context *db);
+ void *private_data;
+ bool persistent;
+};
+
+struct db_context *db_open(TALLOC_CTX *mem_ctx,
+ const char *name,
+ int hash_size, int tdb_flags,
+ int open_flags, mode_t mode);
+
+struct db_context *db_open_rbt(TALLOC_CTX *mem_ctx);
+
+struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
+ const char *name,
+ int hash_size, int tdb_flags,
+ int open_flags, mode_t mode);
+
+struct db_context *db_open_tdb2(TALLOC_CTX *mem_ctx,
+ const char *name,
+ int hash_size, int tdb_flags,
+ int open_flags, mode_t mode);
+
+struct messaging_context;
+
+#ifdef CLUSTER_SUPPORT
+struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
+ const char *name,
+ int hash_size, int tdb_flags,
+ int open_flags, mode_t mode);
+#endif
+
+struct db_context *db_open_file(TALLOC_CTX *mem_ctx,
+ struct messaging_context *msg_ctx,
+ const char *name,
+ int hash_size, int tdb_flags,
+ int open_flags, mode_t mode);
+
+
+NTSTATUS dbwrap_delete_bystring(struct db_context *db, const char *key);
+NTSTATUS dbwrap_store_bystring(struct db_context *db, const char *key,
+ TDB_DATA data, int flags);
+TDB_DATA dbwrap_fetch_bystring(struct db_context *db, TALLOC_CTX *mem_ctx,
+ const char *key);
+
+#endif /* __DBWRAP_H__ */
diff --git a/source3/include/dcerpc.h b/source3/include/dcerpc.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/source3/include/dcerpc.h
diff --git a/source3/include/debug.h b/source3/include/debug.h
new file mode 100644
index 0000000000..d1716320b3
--- /dev/null
+++ b/source3/include/debug.h
@@ -0,0 +1,240 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB debug stuff
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) John H Terpstra 1996-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Paul Ashton 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+/* -------------------------------------------------------------------------- **
+ * Debugging code. See also debug.c
+ */
+
+/* mkproto.awk has trouble with ifdef'd function definitions (it ignores
+ * the #ifdef directive and will read both definitions, thus creating two
+ * diffferent prototype declarations), so we must do these by hand.
+ */
+/* I know the __attribute__ stuff is ugly, but it does ensure we get the
+ arguments to DEBUG() right. We have got them wrong too often in the
+ past.
+ The PRINTFLIKE comment does the equivalent for SGI MIPSPro.
+ */
+/* PRINTFLIKE1 */
+int Debug1( const char *, ... ) PRINTF_ATTRIBUTE(1,2);
+/* PRINTFLIKE1 */
+bool dbgtext( const char *, ... ) PRINTF_ATTRIBUTE(1,2);
+bool dbghdr( int level, int cls, const char *file, const char *func, int line );
+
+#if defined(sgi) && (_COMPILER_VERSION >= 730)
+#pragma mips_frequency_hint NEVER Debug1
+#pragma mips_frequency_hint NEVER dbgtext
+#pragma mips_frequency_hint NEVER dbghdr
+#endif
+
+extern XFILE *dbf;
+
+/* If we have these macros, we can add additional info to the header. */
+
+#ifdef HAVE_FUNCTION_MACRO
+#define FUNCTION_MACRO (__FUNCTION__)
+#else
+#define FUNCTION_MACRO ("")
+#endif
+
+/*
+ * Redefine DEBUGLEVEL because so we don't have to change every source file
+ * that *unnecessarily* references it. Source files neeed not extern reference
+ * DEBUGLEVEL, as it's extern in includes.h (which all source files include).
+ * Eventually, all these references should be removed, and all references to
+ * DEBUGLEVEL should be references to DEBUGLEVEL_CLASS[DBGC_ALL]. This could
+ * still be through a macro still called DEBUGLEVEL. This cannot be done now
+ * because some references would expand incorrectly.
+ */
+#define DEBUGLEVEL *debug_level
+extern int DEBUGLEVEL;
+
+/*
+ * Define all new debug classes here. A class is represented by an entry in
+ * the DEBUGLEVEL_CLASS array. Index zero of this arrray is equivalent to the
+ * old DEBUGLEVEL. Any source file that does NOT add the following lines:
+ *
+ * #undef DBGC_CLASS
+ * #define DBGC_CLASS DBGC_<your class name here>
+ *
+ * at the start of the file (after #include "includes.h") will default to
+ * using index zero, so it will behaive just like it always has.
+ */
+#define DBGC_ALL 0 /* index equivalent to DEBUGLEVEL */
+
+#define DBGC_TDB 1
+#define DBGC_PRINTDRIVERS 2
+#define DBGC_LANMAN 3
+#define DBGC_SMB 4
+#define DBGC_RPC_PARSE 5
+#define DBGC_RPC_SRV 6
+#define DBGC_RPC_CLI 7
+#define DBGC_PASSDB 8
+#define DBGC_SAM 9
+#define DBGC_AUTH 10
+#define DBGC_WINBIND 11
+#define DBGC_VFS 12
+#define DBGC_IDMAP 13
+#define DBGC_QUOTA 14
+#define DBGC_ACLS 15
+#define DBGC_LOCKING 16
+#define DBGC_MSDFS 17
+#define DBGC_DMAPI 18
+#define DBGC_REGISTRY 19
+
+/* So you can define DBGC_CLASS before including debug.h */
+#ifndef DBGC_CLASS
+#define DBGC_CLASS 0 /* override as shown above */
+#endif
+
+extern int *DEBUGLEVEL_CLASS;
+extern bool *DEBUGLEVEL_CLASS_ISSET;
+
+/* Debugging macros
+ *
+ * DEBUGLVL()
+ * If the 'file specific' debug class level >= level OR the system-wide
+ * DEBUGLEVEL (synomym for DEBUGLEVEL_CLASS[ DBGC_ALL ]) >= level then
+ * generate a header using the default macros for file, line, and
+ * function name. Returns True if the debug level was <= DEBUGLEVEL.
+ *
+ * Example: if( DEBUGLVL( 2 ) ) dbgtext( "Some text.\n" );
+ *
+ * DEBUGLVLC()
+ * If the 'macro specified' debug class level >= level OR the system-wide
+ * DEBUGLEVEL (synomym for DEBUGLEVEL_CLASS[ DBGC_ALL ]) >= level then
+ * generate a header using the default macros for file, line, and
+ * function name. Returns True if the debug level was <= DEBUGLEVEL.
+ *
+ * Example: if( DEBUGLVLC( DBGC_TDB, 2 ) ) dbgtext( "Some text.\n" );
+ *
+ * DEBUG()
+ * If the 'file specific' debug class level >= level OR the system-wide
+ * DEBUGLEVEL (synomym for DEBUGLEVEL_CLASS[ DBGC_ALL ]) >= level then
+ * generate a header using the default macros for file, line, and
+ * function name. Each call to DEBUG() generates a new header *unless* the
+ * previous debug output was unterminated (i.e. no '\n').
+ * See debug.c:dbghdr() for more info.
+ *
+ * Example: DEBUG( 2, ("Some text and a value %d.\n", value) );
+ *
+ * DEBUGC()
+ * If the 'macro specified' debug class level >= level OR the system-wide
+ * DEBUGLEVEL (synomym for DEBUGLEVEL_CLASS[ DBGC_ALL ]) >= level then
+ * generate a header using the default macros for file, line, and
+ * function name. Each call to DEBUG() generates a new header *unless* the
+ * previous debug output was unterminated (i.e. no '\n').
+ * See debug.c:dbghdr() for more info.
+ *
+ * Example: DEBUGC( DBGC_TDB, 2, ("Some text and a value %d.\n", value) );
+ *
+ * DEBUGADD(), DEBUGADDC()
+ * Same as DEBUG() and DEBUGC() except the text is appended to the previous
+ * DEBUG(), DEBUGC(), DEBUGADD(), DEBUGADDC() with out another interviening
+ * header.
+ *
+ * Example: DEBUGADD( 2, ("Some text and a value %d.\n", value) );
+ * DEBUGADDC( DBGC_TDB, 2, ("Some text and a value %d.\n", value) );
+ *
+ * Note: If the debug class has not be redeined (see above) then the optimizer
+ * will remove the extra conditional test.
+ */
+
+/*
+ * From talloc.c:
+ */
+
+/* these macros gain us a few percent of speed on gcc */
+#if (__GNUC__ >= 3)
+/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
+ as its first argument */
+#ifndef likely
+#define likely(x) __builtin_expect(!!(x), 1)
+#endif
+#ifndef unlikely
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#endif
+#else
+#ifndef likely
+#define likely(x) (x)
+#endif
+#ifndef unlikely
+#define unlikely(x) (x)
+#endif
+#endif
+
+#define CHECK_DEBUGLVL( level ) \
+ ( ((level) <= MAX_DEBUG_LEVEL) && \
+ unlikely((DEBUGLEVEL_CLASS[ DBGC_CLASS ] >= (level))|| \
+ (!DEBUGLEVEL_CLASS_ISSET[ DBGC_CLASS ] && \
+ DEBUGLEVEL_CLASS[ DBGC_ALL ] >= (level)) ) )
+
+#define DEBUGLVL( level ) \
+ ( CHECK_DEBUGLVL(level) \
+ && dbghdr( level, DBGC_CLASS, __FILE__, FUNCTION_MACRO, (__LINE__) ) )
+
+
+#define DEBUGLVLC( dbgc_class, level ) \
+ ( ((level) <= MAX_DEBUG_LEVEL) && \
+ unlikely((DEBUGLEVEL_CLASS[ dbgc_class ] >= (level))|| \
+ (!DEBUGLEVEL_CLASS_ISSET[ dbgc_class ] && \
+ DEBUGLEVEL_CLASS[ DBGC_ALL ] >= (level)) ) \
+ && dbghdr( level, DBGC_CLASS, __FILE__, FUNCTION_MACRO, (__LINE__) ) )
+
+
+#define DEBUG( level, body ) \
+ (void)( ((level) <= MAX_DEBUG_LEVEL) && \
+ unlikely((DEBUGLEVEL_CLASS[ DBGC_CLASS ] >= (level))|| \
+ (!DEBUGLEVEL_CLASS_ISSET[ DBGC_CLASS ] && \
+ DEBUGLEVEL_CLASS[ DBGC_ALL ] >= (level)) ) \
+ && (dbghdr( level, DBGC_CLASS, __FILE__, FUNCTION_MACRO, (__LINE__) )) \
+ && (dbgtext body) )
+
+#define DEBUGC( dbgc_class, level, body ) \
+ (void)( ((level) <= MAX_DEBUG_LEVEL) && \
+ unlikely((DEBUGLEVEL_CLASS[ dbgc_class ] >= (level))|| \
+ (!DEBUGLEVEL_CLASS_ISSET[ dbgc_class ] && \
+ DEBUGLEVEL_CLASS[ DBGC_ALL ] >= (level)) ) \
+ && (dbghdr( level, DBGC_CLASS, __FILE__, FUNCTION_MACRO, (__LINE__) )) \
+ && (dbgtext body) )
+
+#define DEBUGADD( level, body ) \
+ (void)( ((level) <= MAX_DEBUG_LEVEL) && \
+ unlikely((DEBUGLEVEL_CLASS[ DBGC_CLASS ] >= (level))|| \
+ (!DEBUGLEVEL_CLASS_ISSET[ DBGC_CLASS ] && \
+ DEBUGLEVEL_CLASS[ DBGC_ALL ] >= (level)) ) \
+ && (dbgtext body) )
+
+#define DEBUGADDC( dbgc_class, level, body ) \
+ (void)( ((level) <= MAX_DEBUG_LEVEL) && \
+ unlikely((DEBUGLEVEL_CLASS[ dbgc_class ] >= (level))|| \
+ (!DEBUGLEVEL_CLASS_ISSET[ dbgc_class ] && \
+ DEBUGLEVEL_CLASS[ DBGC_ALL ] >= (level)) ) \
+ && (dbgtext body) )
+
+/* Print a separator to the debug log. */
+#define DEBUGSEP(level)\
+ DEBUG((level),("===============================================================\n"))
+
+#endif
diff --git a/source3/include/debugparse.h b/source3/include/debugparse.h
new file mode 100644
index 0000000000..a66a82a8d8
--- /dev/null
+++ b/source3/include/debugparse.h
@@ -0,0 +1,126 @@
+#ifndef DEBUGPARSE_H
+#define DEBUGPARSE_H
+/* ========================================================================== **
+ * debugparse.c
+ *
+ * Copyright (C) 1998 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ *
+ * -------------------------------------------------------------------------- **
+ * This module is a very simple parser for Samba debug log files.
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 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 Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- **
+ * The important function in this module is dbg_char2token(). The rest is
+ * basically fluff. (Potentially useful fluff, but still fluff.)
+ * ========================================================================== **
+ */
+
+#include "includes.h"
+
+/* This module compiles quite nicely outside of the Samba environment.
+ * You'll need the following headers:
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+ */
+
+/* -------------------------------------------------------------------------- **
+ * These are the tokens returned by dbg_char2token().
+ */
+
+typedef enum
+ {
+ dbg_null = 0,
+ dbg_ignore,
+ dbg_header,
+ dbg_timestamp,
+ dbg_level,
+ dbg_sourcefile,
+ dbg_function,
+ dbg_lineno,
+ dbg_message,
+ dbg_eof
+ } dbg_Token;
+
+/* -------------------------------------------------------------------------- **
+ * Function prototypes...
+ */
+
+ const char *dbg_token2string( dbg_Token tok );
+ /* ------------------------------------------------------------------------ **
+ * Given a token, return a string describing the token.
+ *
+ * Input: tok - One of the set of dbg_Tokens defined in debugparse.h.
+ *
+ * Output: A string identifying the token. This is useful for debugging,
+ * etc.
+ *
+ * Note: If the token is not known, this function will return the
+ * string "<unknown>".
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ dbg_Token dbg_char2token( dbg_Token *state, int c );
+ /* ------------------------------------------------------------------------ **
+ * Parse input one character at a time.
+ *
+ * Input: state - A pointer to a token variable. This is used to
+ * maintain the parser state between calls. For
+ * each input stream, you should set up a separate
+ * state variable and initialize it to dbg_null.
+ * Pass a pointer to it into this function with each
+ * character in the input stream. See dbg_test()
+ * for an example.
+ * c - The "current" character in the input stream.
+ *
+ * Output: A token.
+ * The token value will change when delimiters are found,
+ * which indicate a transition between syntactical objects.
+ * Possible return values are:
+ *
+ * dbg_null - The input character was an end-of-line.
+ * This resets the parser to its initial state
+ * in preparation for parsing the next line.
+ * dbg_eof - Same as dbg_null, except that the character
+ * was an end-of-file.
+ * dbg_ignore - Returned for whitespace and delimiters.
+ * These lexical tokens are only of interest
+ * to the parser.
+ * dbg_header - Indicates the start of a header line. The
+ * input character was '[' and was the first on
+ * the line.
+ * dbg_timestamp - Indicates that the input character was part
+ * of a header timestamp.
+ * dbg_level - Indicates that the input character was part
+ * of the debug-level value in the header.
+ * dbg_sourcefile - Indicates that the input character was part
+ * of the sourcefile name in the header.
+ * dbg_function - Indicates that the input character was part
+ * of the function name in the header.
+ * dbg_lineno - Indicates that the input character was part
+ * of the DEBUG call line number in the header.
+ * dbg_message - Indicates that the input character was part
+ * of the DEBUG message text.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+
+/* -------------------------------------------------------------------------- */
+#endif /* DEBUGPARSE_H */
diff --git a/source3/include/dlinklist.h b/source3/include/dlinklist.h
new file mode 100644
index 0000000000..1a4ebb6fa0
--- /dev/null
+++ b/source3/include/dlinklist.h
@@ -0,0 +1,113 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* To use these macros you must have a structure containing a next and
+ prev pointer */
+
+#ifndef _DLINKLIST_H
+#define _DLINKLIST_H
+
+
+/* hook into the front of the list */
+#define DLIST_ADD(list, p) \
+do { \
+ if (!(list)) { \
+ (list) = (p); \
+ (p)->next = (p)->prev = NULL; \
+ } else { \
+ (list)->prev = (p); \
+ (p)->next = (list); \
+ (p)->prev = NULL; \
+ (list) = (p); \
+ }\
+} while (0)
+
+/* remove an element from a list - element doesn't have to be in list. */
+#define DLIST_REMOVE(list, p) \
+do { \
+ if ((p) == (list)) { \
+ (list) = (p)->next; \
+ if (list) (list)->prev = NULL; \
+ } else { \
+ if ((p)->prev) (p)->prev->next = (p)->next; \
+ if ((p)->next) (p)->next->prev = (p)->prev; \
+ } \
+ if ((p) != (list)) (p)->next = (p)->prev = NULL; \
+} while (0)
+
+/* promote an element to the top of the list */
+#define DLIST_PROMOTE(list, p) \
+do { \
+ DLIST_REMOVE(list, p); \
+ DLIST_ADD(list, p); \
+} while (0)
+
+/* hook into the end of the list - needs the entry type */
+#define DLIST_ADD_END(list, p, type) \
+do { \
+ if (!(list)) { \
+ (list) = (p); \
+ (p)->next = (p)->prev = NULL; \
+ } else { \
+ type tmp; \
+ for (tmp = (list); tmp->next; tmp = tmp->next) ; \
+ tmp->next = (p); \
+ (p)->next = NULL; \
+ (p)->prev = tmp; \
+ } \
+} while (0)
+
+/* insert 'p' after the given element 'el' in a list. If el is NULL then
+ this is the same as a DLIST_ADD() */
+#define DLIST_ADD_AFTER(list, p, el) \
+do { \
+ if (!(list) || !(el)) { \
+ DLIST_ADD(list, p); \
+ } else { \
+ p->prev = el; \
+ p->next = el->next; \
+ el->next = p; \
+ if (p->next) p->next->prev = p; \
+ }\
+} while (0)
+
+/* demote an element to the end of the list, needs a tmp pointer */
+#define DLIST_DEMOTE(list, p, tmp) \
+do { \
+ DLIST_REMOVE(list, p); \
+ DLIST_ADD_END(list, p, tmp); \
+} while (0)
+
+/* concatenate two lists - putting all elements of the 2nd list at the
+ end of the first list */
+#define DLIST_CONCATENATE(list1, list2, type) \
+do { \
+ if (!(list1)) { \
+ (list1) = (list2); \
+ } else { \
+ type tmp; \
+ for (tmp = (list1); tmp->next; tmp = tmp->next) ; \
+ tmp->next = (list2); \
+ if (list2) { \
+ (list2)->prev = tmp; \
+ } \
+ } \
+} while (0)
+
+#endif /* _DLINKLIST_H */
diff --git a/source3/include/doserr.h b/source3/include/doserr.h
new file mode 100644
index 0000000000..5d3b866d01
--- /dev/null
+++ b/source3/include/doserr.h
@@ -0,0 +1,303 @@
+/*
+ Unix SMB/CIFS implementation.
+ DOS error code constants
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) John H Terpstra 1996-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Paul Ashton 1998-2000
+ Copyright (C) Gerald (Jerry) Carter 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _DOSERR_H
+#define _DOSERR_H
+
+/* Error classes */
+
+#define ERRDOS 0x01 /* Error is from the core DOS operating system set. */
+#define ERRSRV 0x02 /* Error is generated by the server network file manager.*/
+#define ERRHRD 0x03 /* Error is an hardware error. */
+#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
+
+/* SMB X/Open error codes for the ERRDOS error class */
+#define ERRsuccess 0 /* No error */
+#define ERRbadfunc 1 /* Invalid function (or system call) */
+#define ERRbadfile 2 /* File not found (pathname error) */
+#define ERRbadpath 3 /* Directory not found */
+#define ERRnofids 4 /* Too many open files */
+#define ERRnoaccess 5 /* Access denied */
+#define ERRbadfid 6 /* Invalid fid */
+#define ERRbadmcb 7 /* Memory control blocks destroyed. */
+#define ERRnomem 8 /* Out of memory */
+#define ERRbadmem 9 /* Invalid memory block address */
+#define ERRbadenv 10 /* Invalid environment */
+#define ERRbadformat 11 /* Bad Format */
+#define ERRbadaccess 12 /* Invalid open mode */
+#define ERRbaddata 13 /* Invalid data (only from ioctl call) */
+#define ERRres 14 /* reserved */
+#define ERRbaddrive 15 /* Invalid drive */
+#define ERRremcd 16 /* Attempt to delete current directory */
+#define ERRdiffdevice 17 /* rename/move across different filesystems */
+#define ERRnofiles 18 /* no more files found in file search */
+#define ERRgeneral 31 /* General failure */
+#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 ERRnetnamedel 64 /* Network name deleted or not available */
+#define ERRnosuchshare 67 /* You specified an invalid share name */
+#define ERRfilexists 80 /* File in operation already exists */
+#define ERRinvalidparam 87
+#define ERRcannotopen 110 /* Cannot open the file specified */
+#define ERRbufferoverflow 111
+#define ERRinsufficientbuffer 122
+#define ERRinvalidname 123 /* Invalid name */
+#define ERRunknownlevel 124
+#define ERRnotlocked 158 /* This region is not locked by this locking context. */
+#define ERRinvalidpath 161
+#define ERRcancelviolation 173
+#define ERRnoatomiclocks 174
+#define ERRrename 183
+#define ERRbadpipe 230 /* Named pipe invalid */
+#define ERRpipebusy 231 /* All instances of pipe are busy */
+#define ERRpipeclosing 232 /* named pipe close in progress */
+#define ERRnotconnected 233 /* No process on other end of named pipe */
+#define ERRmoredata 234 /* More data to be returned */
+#define ERReainconsistent 255 /* from EMC */
+#define ERRnomoreitems 259
+#define ERRbaddirectory 267 /* Invalid directory name in a path. */
+#define ERReasnotsupported 282 /* Extended attributes */
+#define ERRlogonfailure 1326 /* Unknown username or bad password */
+#define ERRbuftoosmall 2123
+#define ERRunknownipc 2142
+#define ERRnosuchprintjob 2151
+#define ERRinvgroup 2455
+
+/* here's a special one from observing NT */
+#define ERRnoipc 66 /* don't support ipc */
+
+/* These errors seem to be only returned by the NT printer driver system */
+#define ERRdriveralreadyinstalled 1795 /* ERROR_PRINTER_DRIVER_ALREADY_INSTALLED */
+#define ERRunknownprinterport 1796 /* ERROR_UNKNOWN_PORT */
+#define ERRunknownprinterdriver 1797 /* ERROR_UNKNOWN_PRINTER_DRIVER */
+#define ERRunknownprintprocessor 1798 /* ERROR_UNKNOWN_PRINTPROCESSOR */
+#define ERRinvalidseparatorfile 1799 /* ERROR_INVALID_SEPARATOR_FILE */
+#define ERRinvalidjobpriority 1800 /* ERROR_INVALID_PRIORITY */
+#define ERRinvalidprintername 1801 /* ERROR_INVALID_PRINTER_NAME */
+#define ERRprinteralreadyexists 1802 /* ERROR_PRINTER_ALREADY_EXISTS */
+#define ERRinvalidprintercommand 1803 /* ERROR_INVALID_PRINTER_COMMAND */
+#define ERRinvaliddatatype 1804 /* ERROR_INVALID_DATATYPE */
+#define ERRinvalidenvironment 1805 /* ERROR_INVALID_ENVIRONMENT */
+
+#define ERRunknownprintmonitor 3000 /* ERROR_UNKNOWN_PRINT_MONITOR */
+#define ERRprinterdriverinuse 3001 /* ERROR_PRINTER_DRIVER_IN_USE */
+#define ERRspoolfilenotfound 3002 /* ERROR_SPOOL_FILE_NOT_FOUND */
+#define ERRnostartdoc 3003 /* ERROR_SPL_NO_STARTDOC */
+#define ERRnoaddjob 3004 /* ERROR_SPL_NO_ADDJOB */
+#define ERRprintprocessoralreadyinstalled 3005 /* ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED */
+#define ERRprintmonitoralreadyinstalled 3006 /* ERROR_PRINT_MONITOR_ALREADY_INSTALLED */
+#define ERRinvalidprintmonitor 3007 /* ERROR_INVALID_PRINT_MONITOR */
+#define ERRprintmonitorinuse 3008 /* ERROR_PRINT_MONITOR_IN_USE */
+#define ERRprinterhasjobsqueued 3009 /* ERROR_PRINTER_HAS_JOBS_QUEUED */
+
+/* Error codes for the ERRSRV class */
+
+#define ERRerror 1 /* Non specific error code */
+#define ERRbadpw 2 /* Bad password */
+#define ERRbadtype 3 /* reserved */
+#define ERRaccess 4 /* No permissions to do the requested operation */
+#define ERRinvnid 5 /* tid invalid */
+#define ERRinvnetname 6 /* Invalid servername */
+#define ERRinvdevice 7 /* Invalid device */
+#define ERRqfull 49 /* Print queue full */
+#define ERRqtoobig 50 /* Queued item too big */
+#define ERRinvpfid 52 /* Invalid print file in smb_fid */
+#define ERRsmbcmd 64 /* Unrecognised command */
+#define ERRsrverror 65 /* smb server internal error */
+#define ERRfilespecs 67 /* fid and pathname invalid combination */
+#define ERRbadlink 68 /* reserved */
+#define ERRbadpermits 69 /* Access specified for a file is not valid */
+#define ERRbadpid 70 /* reserved */
+#define ERRsetattrmode 71 /* attribute mode invalid */
+#define ERRpaused 81 /* Message server paused */
+#define ERRmsgoff 82 /* Not receiving messages */
+#define ERRnoroom 83 /* No room for message */
+#define ERRrmuns 87 /* too many remote usernames */
+#define ERRtimeout 88 /* operation timed out */
+#define ERRnoresource 89 /* No resources currently available for request. */
+#define ERRtoomanyuids 90 /* too many userids */
+#define ERRbaduid 91 /* bad userid */
+#define ERRuseMPX 250 /* temporarily unable to use raw mode, use MPX mode */
+#define ERRuseSTD 251 /* temporarily unable to use raw mode, use standard mode */
+#define ERRcontMPX 252 /* resume MPX mode */
+#define ERRbadPW /* reserved */
+#define ERRnosupport 0xFFFF
+#define ERRunknownsmb 22 /* from NT 3.5 response */
+
+/* Error codes for the ERRHRD class */
+
+#define ERRnowrite 19 /* read only media */
+#define ERRbadunit 20 /* Unknown device */
+#define ERRnotready 21 /* Drive not ready */
+#define ERRbadcmd 22 /* Unknown command */
+#define ERRdata 23 /* Data (CRC) error */
+#define ERRbadreq 24 /* Bad request structure length */
+#define ERRseek 25
+#define ERRbadmedia 26
+#define ERRbadsector 27
+#define ERRnopaper 28
+#define ERRwrite 29 /* write fault */
+#define ERRread 30 /* read fault */
+#define ERRgeneral 31 /* General hardware failure */
+#define ERRwrongdisk 34
+#define ERRFCBunavail 35
+#define ERRsharebufexc 36 /* share buffer exceeded */
+#define ERRdiskfull 39
+
+
+/* these are win32 error codes. There are only a few places where
+ these matter for Samba, primarily in the NT printing code */
+#define WERR_OK W_ERROR(0)
+#define WERR_BADFUNC W_ERROR(1)
+#define WERR_BADFILE W_ERROR(2)
+#define WERR_ACCESS_DENIED W_ERROR(5)
+#define WERR_BADFID W_ERROR(6)
+#define WERR_NOMEM W_ERROR(8)
+#define WERR_GENERAL_FAILURE W_ERROR(31)
+#define WERR_NOT_SUPPORTED W_ERROR(50)
+#define WERR_DEVICE_NOT_EXIST W_ERROR(55)
+#define WERR_PRINTQ_FULL W_ERROR(61)
+#define WERR_NO_SPOOL_SPACE W_ERROR(62)
+#define WERR_NO_SUCH_SHARE W_ERROR(67)
+#define WERR_ALREADY_EXISTS W_ERROR(80)
+#define WERR_BAD_PASSWORD W_ERROR(86)
+#define WERR_INVALID_PARAM W_ERROR(87)
+#define WERR_SEM_TIMEOUT W_ERROR(121)
+#define WERR_INSUFFICIENT_BUFFER W_ERROR(122)
+#define WERR_INVALID_NAME W_ERROR(123)
+#define WERR_UNKNOWN_LEVEL W_ERROR(124)
+#define WERR_OBJECT_PATH_INVALID W_ERROR(161)
+#define WERR_NO_MORE_ITEMS W_ERROR(259)
+#define WERR_MORE_DATA W_ERROR(234)
+#define WERR_INVALID_OWNER W_ERROR(1307)
+#define WERR_IO_PENDING W_ERROR(997)
+#define WERR_CAN_NOT_COMPLETE W_ERROR(1003)
+#define WERR_INVALID_FLAGS W_ERROR(1004)
+#define WERR_REG_CORRUPT W_ERROR(1015)
+#define WERR_REG_IO_FAILURE W_ERROR(1016)
+#define WERR_REG_FILE_INVALID W_ERROR(1017)
+#define WERR_NO_SUCH_SERVICE W_ERROR(1060)
+#define WERR_INVALID_SERVICE_CONTROL W_ERROR(1052)
+#define WERR_SERVICE_ALREADY_RUNNING W_ERROR(1056)
+#define WERR_SERVICE_DISABLED W_ERROR(1058)
+#define WERR_SERVICE_NEVER_STARTED W_ERROR(1077)
+#define WERR_NOT_FOUND W_ERROR(1168)
+#define WERR_INVALID_COMPUTER_NAME W_ERROR(1210)
+#define WERR_INVALID_DOMAINNAME W_ERROR(1212)
+#define WERR_MACHINE_LOCKED W_ERROR(1271)
+#define WERR_REVISION_MISMATCH W_ERROR(1306)
+#define WERR_NO_LOGON_SERVERS W_ERROR(1311)
+#define WERR_NO_SUCH_LOGON_SESSION W_ERROR(1312)
+#define WERR_USER_ALREADY_EXISTS W_ERROR(1316)
+#define WERR_NO_SUCH_USER W_ERROR(1317)
+#define WERR_GROUP_EXISTS W_ERROR(1318)
+#define WERR_MEMBER_IN_GROUP W_ERROR(1320)
+#define WERR_USER_NOT_IN_GROUP W_ERROR(1321)
+#define WERR_WRONG_PASSWORD W_ERROR(1323)
+#define WERR_PASSWORD_RESTRICTION W_ERROR(1325)
+#define WERR_LOGON_FAILURE W_ERROR(1326)
+#define WERR_NO_SUCH_DOMAIN W_ERROR(1355)
+#define WERR_NONE_MAPPED W_ERROR(1332)
+#define WERR_INVALID_SECURITY_DESCRIPTOR W_ERROR(1338)
+#define WERR_INVALID_DOMAIN_STATE W_ERROR(1353)
+#define WERR_INVALID_DOMAIN_ROLE W_ERROR(1354)
+#define WERR_SPECIAL_ACCOUNT W_ERROR(1371)
+#define WERR_NO_SUCH_ALIAS W_ERROR(1376)
+#define WERR_MEMBER_IN_ALIAS W_ERROR(1378)
+#define WERR_ALIAS_EXISTS W_ERROR(1379)
+#define WERR_TIME_SKEW W_ERROR(1398)
+#define WERR_EVENTLOG_FILE_CORRUPT W_ERROR(1500)
+#define WERR_SERVER_UNAVAILABLE W_ERROR(1722)
+#define WERR_INVALID_FORM_NAME W_ERROR(1902)
+#define WERR_INVALID_FORM_SIZE W_ERROR(1903)
+#define WERR_PASSWORD_MUST_CHANGE W_ERROR(1907)
+#define WERR_DOMAIN_CONTROLLER_NOT_FOUND W_ERROR(1908)
+#define WERR_ACCOUNT_LOCKED_OUT W_ERROR(1909)
+
+#define WERR_DEVICE_NOT_AVAILABLE W_ERROR(4319)
+#define WERR_STATUS_MORE_ENTRIES W_ERROR(0x0105)
+
+#define WERR_DS_DRA_BAD_DN W_ERROR(8439)
+#define WERR_DS_DRA_BAD_NC W_ERROR(8440)
+
+#define WERR_PRINTER_DRIVER_ALREADY_INSTALLED W_ERROR(ERRdriveralreadyinstalled)
+#define WERR_UNKNOWN_PORT W_ERROR(ERRunknownprinterport)
+#define WERR_UNKNOWN_PRINTER_DRIVER W_ERROR(ERRunknownprinterdriver)
+#define WERR_UNKNOWN_PRINTPROCESSOR W_ERROR(ERRunknownprintprocessor)
+#define WERR_INVALID_SEPARATOR_FILE W_ERROR(ERRinvalidseparatorfile)
+#define WERR_INVALID_PRIORITY W_ERROR(ERRinvalidjobpriority)
+#define WERR_INVALID_PRINTER_NAME W_ERROR(ERRinvalidprintername)
+#define WERR_PRINTER_ALREADY_EXISTS W_ERROR(ERRprinteralreadyexists)
+#define WERR_INVALID_PRINTER_COMMAND W_ERROR(ERRinvalidprintercommand)
+#define WERR_INVALID_DATATYPE W_ERROR(ERRinvaliddatatype)
+#define WERR_INVALID_ENVIRONMENT W_ERROR(ERRinvalidenvironment)
+
+#define WERR_UNKNOWN_PRINT_MONITOR W_ERROR(ERRunknownprintmonitor)
+#define WERR_PRINTER_DRIVER_IN_USE W_ERROR(ERRprinterdriverinuse)
+#define WERR_SPOOL_FILE_NOT_FOUND W_ERROR(ERRspoolfilenotfound)
+#define WERR_SPL_NO_STARTDOC W_ERROR(ERRnostartdoc)
+#define WERR_SPL_NO_ADDJOB W_ERROR(ERRnoaddjob)
+#define WERR_PRINT_PROCESSOR_ALREADY_INSTALLED W_ERROR(ERRprintprocessoralreadyinstalled)
+#define WERR_PRINT_MONITOR_ALREADY_INSTALLED W_ERROR(ERRprintmonitoralreadyinstalled)
+#define WERR_INVALID_PRINT_MONITOR W_ERROR(ERRinvalidprintmonitor)
+#define WERR_PRINT_MONITOR_IN_USE W_ERROR(ERRprintmonitorinuse)
+#define WERR_PRINTER_HAS_JOBS_QUEUED W_ERROR(ERRprinterhasjobsqueued)
+
+/* Configuration Manager Errors */
+/* Basically Win32 errors meanings are specific to the \ntsvcs pipe */
+
+#define WERR_CM_NO_MORE_HW_PROFILES W_ERROR(35)
+#define WERR_CM_NO_SUCH_VALUE W_ERROR(37)
+
+
+/* DFS errors */
+
+#ifndef NERR_BASE
+#define NERR_BASE (2100)
+#endif
+
+#ifndef MAX_NERR
+#define MAX_NERR (NERR_BASE+899)
+#endif
+
+#define WERR_BUF_TOO_SMALL W_ERROR(NERR_BASE+23)
+#define WERR_JOB_NOT_FOUND W_ERROR(NERR_BASE+51)
+#define WERR_DEST_NOT_FOUND W_ERROR(NERR_BASE+52)
+#define WERR_GROUP_NOT_FOUND W_ERROR(NERR_BASE+120)
+#define WERR_USER_NOT_FOUND W_ERROR(NERR_BASE+121)
+#define WERR_USER_EXISTS W_ERROR(NERR_BASE+124)
+#define WERR_NET_NAME_NOT_FOUND W_ERROR(NERR_BASE+210)
+#define WERR_NOT_LOCAL_DOMAIN W_ERROR(NERR_BASE+220)
+#define WERR_DC_NOT_FOUND W_ERROR(NERR_BASE+353)
+#define WERR_DFS_NO_SUCH_VOL W_ERROR(NERR_BASE+562)
+#define WERR_DFS_NO_SUCH_SHARE W_ERROR(NERR_BASE+565)
+#define WERR_DFS_NO_SUCH_SERVER W_ERROR(NERR_BASE+573)
+#define WERR_DFS_INTERNAL_ERROR W_ERROR(NERR_BASE+590)
+#define WERR_DFS_CANT_CREATE_JUNCT W_ERROR(NERR_BASE+569)
+#define WERR_SETUP_ALREADY_JOINED W_ERROR(NERR_BASE+591)
+#define WERR_SETUP_NOT_JOINED W_ERROR(NERR_BASE+592)
+#define WERR_SETUP_DOMAIN_CONTROLLER W_ERROR(NERR_BASE+593)
+#define WERR_DEFAULT_JOIN_REQUIRED W_ERROR(NERR_BASE+594)
+
+#endif /* _DOSERR_H */
diff --git a/source3/include/dynconfig.h b/source3/include/dynconfig.h
new file mode 100644
index 0000000000..758bde33cc
--- /dev/null
+++ b/source3/include/dynconfig.h
@@ -0,0 +1,89 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) 2001 by Martin Pool <mbp@samba.org>
+ Copyright (C) 2003 by Jim McDonough <jmcd@us.ibm.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file dynconfig.h
+ *
+ * @brief Exported global configurations.
+ **/
+
+const char *get_dyn_SBINDIR(void);
+const char *set_dyn_SBINDIR(const char *newpath);
+bool is_default_dyn_SBINDIR(void);
+
+const char *get_dyn_BINDIR(void);
+const char *set_dyn_BINDIR(const char *newpath);
+bool is_default_dyn_BINDIR(void);
+
+const char *get_dyn_SWATDIR(void);
+const char *set_dyn_SWATDIR(const char *newpath);
+bool is_default_dyn_SWATDIR(void);
+
+const char *get_dyn_CONFIGFILE(void);
+const char *set_dyn_CONFIGFILE(const char *newpath);
+bool is_default_dyn_CONFIGFILE(void);
+
+const char *get_dyn_LOGFILEBASE(void);
+const char *set_dyn_LOGFILEBASE(const char *newpath);
+bool is_default_dyn_LOGFILEBASE(void);
+
+const char *get_dyn_LMHOSTSFILE(void);
+const char *set_dyn_LMHOSTSFILE(const char *newpath);
+bool is_default_dyn_LMHOSTSFILE(void);
+
+const char *get_dyn_CODEPAGEDIR(void);
+const char *set_dyn_CODEPAGEDIR(const char *newpath);
+bool is_default_dyn_CODEPAGEDIR(void);
+
+const char *get_dyn_LIBDIR(void);
+const char *set_dyn_LIBDIR(const char *newpath);
+bool is_default_dyn_LIBDIR(void);
+
+const char *get_dyn_MODULESDIR(void);
+const char *set_dyn_MODULESDIR(const char *newpath);
+bool is_default_dyn_MODULESDIR(void);
+
+const char *get_dyn_SHLIBEXT(void);
+const char *set_dyn_SHLIBEXT(const char *newpath);
+bool is_default_dyn_SHLIBEXT(void);
+
+const char *get_dyn_LOCKDIR(void);
+const char *set_dyn_LOCKDIR(const char *newpath);
+bool is_default_dyn_LOCKDIR(void);
+
+const char *get_dyn_PIDDIR(void);
+const char *set_dyn_PIDDIR(const char *newpath);
+bool is_default_dyn_PIDDIR(void);
+
+const char *get_dyn_SMB_PASSWD_FILE(void);
+const char *set_dyn_SMB_PASSWD_FILE(const char *newpath);
+bool is_default_dyn_SMB_PASSWD_FILE(void);
+
+const char *get_dyn_PRIVATE_DIR(void);
+const char *set_dyn_PRIVATE_DIR(const char *newpath);
+bool is_default_dyn_PRIVATE_DIR(void);
+
+/*
+ * For STATEDIR and CACHEDIR, there are only getter functions.
+ * In non-FHS-mode, these are configurable via LOCKDIR.
+ * In FHS-mode, these are their own fixed directories.
+ */
+const char *get_dyn_STATEDIR(void);
+
+const char *get_dyn_CACHEDIR(void);
diff --git a/source3/include/event.h b/source3/include/event.h
new file mode 100644
index 0000000000..0465fae471
--- /dev/null
+++ b/source3/include/event.h
@@ -0,0 +1,24 @@
+/*
+ Unix SMB/CIFS implementation.
+ event handling
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* bits for file descriptor event flags */
+#define EVENT_FD_READ 1
+#define EVENT_FD_WRITE 2
+
diff --git a/source3/include/fake_file.h b/source3/include/fake_file.h
new file mode 100644
index 0000000000..93da106030
--- /dev/null
+++ b/source3/include/fake_file.h
@@ -0,0 +1,39 @@
+/*
+ Unix SMB/CIFS implementation.
+ FAKE FILE suppport, for faking up special files windows want access to
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _FAKE_FILE_H
+#define _FAKE_FILE_H
+
+enum FAKE_FILE_TYPE {
+ FAKE_FILE_TYPE_NONE = 0,
+ FAKE_FILE_TYPE_QUOTA
+};
+
+/*
+we now get the unix name --metze
+*/
+#define FAKE_FILE_NAME_QUOTA_WIN32 "\\$Extend\\$Quota:$Q:$INDEX_ALLOCATION"
+#define FAKE_FILE_NAME_QUOTA_UNIX "$Extend/$Quota:$Q:$INDEX_ALLOCATION"
+
+struct fake_file_handle {
+ enum FAKE_FILE_TYPE type;
+ void *private_data;
+};
+
+#endif /* _FAKE_FILE_H */
diff --git a/source3/include/gpo.h b/source3/include/gpo.h
new file mode 100644
index 0000000000..bf5ff6a598
--- /dev/null
+++ b/source3/include/gpo.h
@@ -0,0 +1,158 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Object Support
+ * Copyright (C) Guenther Deschner 2005-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+enum GPO_LINK_TYPE {
+ GP_LINK_UNKOWN = 0,
+ GP_LINK_MACHINE = 1,
+ GP_LINK_SITE = 2,
+ GP_LINK_DOMAIN = 3,
+ GP_LINK_OU = 4,
+ GP_LINK_LOCAL = 5 /* for convenience */
+};
+
+/* GPO_OPTIONS */
+#define GPO_FLAG_DISABLE 0x00000001
+#define GPO_FLAG_FORCE 0x00000002
+
+/* GPO_LIST_FLAGS */
+#define GPO_LIST_FLAG_MACHINE 0x00000001
+#define GPO_LIST_FLAG_SITEONLY 0x00000002
+
+/* following flags from http://support.microsoft.com/kb/312164/EN-US/ */
+#define GPO_INFO_FLAG_MACHINE 0x00000001
+#define GPO_INFO_FLAG_BACKGROUND 0x00000010
+#define GPO_INFO_FLAG_SLOWLINK 0x00000020
+#define GPO_INFO_FLAG_VERBOSE 0x00000040
+#define GPO_INFO_FLAG_NOCHANGES 0x00000080
+#define GPO_INFO_FLAG_LINKTRANSITION 0x00000100
+#define GPO_INFO_FLAG_LOGRSOP_TRANSITION 0x00000200
+#define GPO_INFO_FLAG_FORCED_REFRESH 0x00000400
+#define GPO_INFO_FLAG_SAFEMODE_BOOT 0x00000800
+
+#define GPO_VERSION_USER(x) (x >> 16)
+#define GPO_VERSION_MACHINE(x) (x & 0xffff)
+
+struct GROUP_POLICY_OBJECT {
+ uint32_t options; /* GPFLAGS_* */
+ uint32_t version;
+ const char *ds_path;
+ const char *file_sys_path;
+ const char *display_name;
+ const char *name;
+ const char *link;
+ enum GPO_LINK_TYPE link_type;
+ const char *user_extensions;
+ const char *machine_extensions;
+ SEC_DESC *security_descriptor;
+ struct GROUP_POLICY_OBJECT *next, *prev;
+};
+
+/* the following is seen on the DS (see adssearch.pl for details) */
+
+/* the type field in a 'gPLink', the same as GPO_FLAG ? */
+#define GPO_LINK_OPT_NONE 0x00000000
+#define GPO_LINK_OPT_DISABLED 0x00000001
+#define GPO_LINK_OPT_ENFORCED 0x00000002
+
+/* GPO_LINK_OPT_ENFORCED takes precedence over GPOPTIONS_BLOCK_INHERITANCE */
+
+/* 'gPOptions', maybe a bitmask as well */
+enum GPO_INHERIT {
+ GPOPTIONS_INHERIT = 0,
+ GPOPTIONS_BLOCK_INHERITANCE = 1
+};
+
+/* 'flags' in a 'groupPolicyContainer' object */
+#define GPFLAGS_ALL_ENABLED 0x00000000
+#define GPFLAGS_USER_SETTINGS_DISABLED 0x00000001
+#define GPFLAGS_MACHINE_SETTINGS_DISABLED 0x00000002
+#define GPFLAGS_ALL_DISABLED (GPFLAGS_USER_SETTINGS_DISABLED | \
+ GPFLAGS_MACHINE_SETTINGS_DISABLED)
+
+struct GP_LINK {
+ const char *gp_link; /* raw link name */
+ uint32_t gp_opts; /* inheritance options GPO_INHERIT */
+ uint32_t num_links; /* number of links */
+ char **link_names; /* array of parsed link names */
+ uint32_t *link_opts; /* array of parsed link opts GPO_LINK_OPT_* */
+};
+
+struct GP_EXT {
+ const char *gp_extension; /* raw extension name */
+ uint32_t num_exts;
+ char **extensions;
+ char **extensions_guid;
+ char **snapins;
+ char **snapins_guid;
+ struct GP_EXT *next, *prev;
+};
+
+#define GPO_CACHE_DIR "gpo_cache"
+#define GPT_INI "GPT.INI"
+#define GPO_REFRESH_INTERVAL 60*90
+
+#define GPO_REG_STATE_MACHINE "State\\Machine"
+
+enum gp_reg_action {
+ GP_REG_ACTION_NONE = 0,
+ GP_REG_ACTION_ADD_VALUE = 1,
+ GP_REG_ACTION_ADD_KEY = 2,
+ GP_REG_ACTION_DEL_VALUES = 3,
+ GP_REG_ACTION_DEL_VALUE = 4,
+ GP_REG_ACTION_DEL_ALL_VALUES = 5,
+ GP_REG_ACTION_DEL_KEYS = 6,
+ GP_REG_ACTION_SEC_KEY_SET = 7,
+ GP_REG_ACTION_SEC_KEY_RESET = 8
+};
+
+struct gp_registry_entry {
+ enum gp_reg_action action;
+ const char *key;
+ const char *value;
+ struct registry_value *data;
+};
+
+struct gp_registry_value {
+ const char *value;
+ struct registry_value *data;
+};
+
+struct gp_registry_entry2 {
+ enum gp_reg_action action;
+ const char *key;
+ size_t num_values;
+ struct gp_registry_value **values;
+};
+
+struct gp_registry_entries {
+ size_t num_entries;
+ struct gp_registry_entry **entries;
+};
+
+struct gp_registry_context {
+ const struct nt_user_token *token;
+ const char *path;
+ struct registry_key *curr_key;
+};
+
+#define GP_EXT_GUID_SECURITY "827D319E-6EAC-11D2-A4EA-00C04F79F83A"
+#define GP_EXT_GUID_REGISTRY "35378EAC-683F-11D2-A89A-00C04FBBCFA2"
+#define GP_EXT_GUID_SCRIPTS "42B5FAAE-6536-11D2-AE5A-0000F87571E3"
+
+#include "libgpo/gpext/gpext.h"
diff --git a/source3/include/hmacmd5.h b/source3/include/hmacmd5.h
new file mode 100644
index 0000000000..ae588fb889
--- /dev/null
+++ b/source3/include/hmacmd5.h
@@ -0,0 +1,29 @@
+/*
+ Unix SMB/CIFS implementation.
+ Interface header: Scheduler service
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1999
+ Copyright (C) Andrew Tridgell 1992-1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _HMAC_MD5_H
+
+typedef struct {
+ struct MD5Context ctx;
+ unsigned char k_ipad[65];
+ unsigned char k_opad[65];
+} HMACMD5Context;
+
+#endif /* _HMAC_MD5_H */
diff --git a/source3/include/idmap.h b/source3/include/idmap.h
new file mode 100644
index 0000000000..95c3e4c0c2
--- /dev/null
+++ b/source3/include/idmap.h
@@ -0,0 +1,81 @@
+#ifndef _IDMAP_H_
+#define _IDMAP_H_
+/*
+ Unix SMB/CIFS implementation.
+
+ Idmap headers
+
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+ Copyright (C) Simo Sorce 2003
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* idmap version determines auto-conversion - this is the database
+ structure version specifier. */
+
+#define IDMAP_VERSION 2
+
+/* The interface version specifier.
+ Updated to 3 for enum types by JRA. */
+
+/* Updated to 4, completely new interface, SSS */
+
+#define SMB_IDMAP_INTERFACE_VERSION 4
+
+struct idmap_domain {
+ const char *name;
+ struct idmap_methods *methods;
+ void *private_data;
+};
+
+/* Filled out by IDMAP backends */
+struct idmap_methods {
+
+ /* Called when backend is first loaded */
+ NTSTATUS (*init)(struct idmap_domain *dom, const char *params);
+
+ /* Map an array of uids/gids to SIDs. The caller specifies
+ the uid/gid and type. Gets back the SID. */
+ NTSTATUS (*unixids_to_sids)(struct idmap_domain *dom, struct id_map **ids);
+
+ /* Map an arry of SIDs to uids/gids. The caller sets the SID
+ and type and gets back a uid or gid. */
+ NTSTATUS (*sids_to_unixids)(struct idmap_domain *dom, struct id_map **ids);
+
+ NTSTATUS (*set_mapping)(struct idmap_domain *dom, const struct id_map *map);
+ NTSTATUS (*remove_mapping)(struct idmap_domain *dom, const struct id_map *map);
+
+ /* Called to dump backends data */
+ /* NOTE: caller must use talloc_free to free maps when done */
+ NTSTATUS (*dump_data)(struct idmap_domain *dom, struct id_map **maps, int *num_maps);
+
+ /* Called when backend is unloaded */
+ NTSTATUS (*close_fn)(struct idmap_domain *dom);
+};
+
+struct idmap_alloc_methods {
+
+ /* Called when backend is first loaded */
+ NTSTATUS (*init)(const char *compat_params);
+
+ NTSTATUS (*allocate_id)(struct unixid *id);
+ NTSTATUS (*get_id_hwm)(struct unixid *id);
+ NTSTATUS (*set_id_hwm)(struct unixid *id);
+
+ /* Called when backend is unloaded */
+ NTSTATUS (*close_fn)(void);
+};
+
+#endif /* _IDMAP_H_ */
diff --git a/source3/include/includes.h b/source3/include/includes.h
new file mode 100644
index 0000000000..9c5ea08f6d
--- /dev/null
+++ b/source3/include/includes.h
@@ -0,0 +1,1320 @@
+#ifndef _INCLUDES_H
+#define _INCLUDES_H
+/*
+ Unix SMB/CIFS implementation.
+ Machine customisation and include handling
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) 2002 by Martin Pool <mbp@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* work around broken krb5.h on sles9 */
+#ifdef SIZEOF_LONG
+#undef SIZEOF_LONG
+#endif
+
+#include "lib/replace/replace.h"
+
+/* make sure we have included the correct config.h */
+#ifndef NO_CONFIG_H /* for some tests */
+#ifndef CONFIG_H_IS_FROM_SAMBA
+#error "make sure you have removed all config.h files from standalone builds!"
+#error "the included config.h isn't from samba!"
+#endif
+#endif /* NO_CONFIG_H */
+
+/* only do the C++ reserved word check when we compile
+ to include --with-developer since too many systems
+ still have comflicts with their header files (e.g. IRIX 6.4) */
+
+#if !defined(__cplusplus) && defined(DEVELOPER)
+#define class #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#define private #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#define public #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#define protected #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#define template #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#define this #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#define new #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#define delete #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#define friend #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#endif
+
+#include "local.h"
+
+#ifdef AIX
+#define DEFAULT_PRINTING PRINT_AIX
+#define PRINTCAP_NAME "/etc/qconfig"
+#endif
+
+#ifdef HPUX
+#define DEFAULT_PRINTING PRINT_HPUX
+#endif
+
+#ifdef QNX
+#define DEFAULT_PRINTING PRINT_QNX
+#endif
+
+#ifdef SUNOS4
+/* on SUNOS4 termios.h conflicts with sys/ioctl.h */
+#undef HAVE_TERMIOS_H
+#endif
+
+#ifndef _PUBLIC_
+#ifdef HAVE_VISIBILITY_ATTR
+# define _PUBLIC_ __attribute__((visibility("default")))
+#else
+# define _PUBLIC_
+#endif
+#endif
+
+#if defined(__GNUC__) && !defined(__cplusplus)
+/** gcc attribute used on function parameters so that it does not emit
+ * warnings about them being unused. **/
+# define UNUSED(param) param __attribute__ ((unused))
+#else
+# define UNUSED(param) param
+/** Feel free to add definitions for other compilers here. */
+#endif
+
+#ifdef RELIANTUNIX
+/*
+ * <unistd.h> has to be included before any other to get
+ * large file support on Reliant UNIX. Yes, it's broken :-).
+ */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#endif /* RELIANTUNIX */
+
+#include "system/capability.h"
+#include "system/dir.h"
+#include "system/filesys.h"
+#include "system/glob.h"
+#include "system/iconv.h"
+#include "system/locale.h"
+#include "system/network.h"
+#include "system/passwd.h"
+#include "system/readline.h"
+#include "system/select.h"
+#include "system/shmem.h"
+#include "system/syslog.h"
+#include "system/terminal.h"
+#include "system/time.h"
+#include "system/wait.h"
+
+#if defined(HAVE_RPC_RPC_H)
+/*
+ * Check for AUTH_ERROR define conflict with rpc/rpc.h in prot.h.
+ */
+#if defined(HAVE_SYS_SECURITY_H) && defined(HAVE_RPC_AUTH_ERROR_CONFLICT)
+#undef AUTH_ERROR
+#endif
+/*
+ * HP-UX 11.X has TCP_NODELAY and TCP_MAXSEG defined in <netinet/tcp.h> which
+ * was included above. However <rpc/rpc.h> includes <sys/xti.h> which defines
+ * them again without checking if they already exsist. This generates
+ * two "Redefinition of macro" warnings for every single .c file that is
+ * compiled.
+ */
+#if defined(HPUX) && defined(TCP_NODELAY)
+#undef TCP_NODELAY
+#endif
+#if defined(HPUX) && defined(TCP_MAXSEG)
+#undef TCP_MAXSEG
+#endif
+#include <rpc/rpc.h>
+#endif
+
+#if defined(HAVE_YP_GET_DEFAULT_DOMAIN) && defined(HAVE_SETNETGRENT) && defined(HAVE_ENDNETGRENT) && defined(HAVE_GETNETGRENT)
+#define HAVE_NETGROUP 1
+#endif
+
+#if defined (HAVE_NETGROUP)
+#if defined(HAVE_RPCSVC_YP_PROT_H)
+/*
+ * HP-UX 11.X has TCP_NODELAY and TCP_MAXSEG defined in <netinet/tcp.h> which
+ * was included above. However <rpc/rpc.h> includes <sys/xti.h> which defines
+ * them again without checking if they already exsist. This generates
+ * two "Redefinition of macro" warnings for every single .c file that is
+ * compiled.
+ */
+#if defined(HPUX) && defined(TCP_NODELAY)
+#undef TCP_NODELAY
+#endif
+#if defined(HPUX) && defined(TCP_MAXSEG)
+#undef TCP_MAXSEG
+#endif
+#include <rpcsvc/yp_prot.h>
+#endif
+#if defined(HAVE_RPCSVC_YPCLNT_H)
+#include <rpcsvc/ypclnt.h>
+#endif
+#endif /* HAVE_NETGROUP */
+
+#if HAVE_KRB5_H
+#include <krb5.h>
+#else
+#undef HAVE_KRB5
+#endif
+
+#if HAVE_LBER_H
+#include <lber.h>
+#if defined(HPUX) && !defined(_LBER_TYPES_H)
+/* Define ber_tag_t and ber_int_t for using
+ * HP LDAP-UX Integration products' LDAP libraries.
+*/
+#ifndef ber_tag_t
+typedef unsigned long ber_tag_t;
+typedef int ber_int_t;
+#endif
+#endif /* defined(HPUX) && !defined(_LBER_TYPES_H) */
+#ifndef LBER_USE_DER
+#define LBER_USE_DER 0x01
+#endif
+#endif
+
+#if HAVE_LDAP_H
+#include <ldap.h>
+#ifndef LDAP_CONST
+#define LDAP_CONST const
+#endif
+#ifndef LDAP_OPT_SUCCESS
+#define LDAP_OPT_SUCCESS 0
+#endif
+/* Solaris 8 and maybe other LDAP implementations spell this "..._INPROGRESS": */
+#if defined(LDAP_SASL_BIND_INPROGRESS) && !defined(LDAP_SASL_BIND_IN_PROGRESS)
+#define LDAP_SASL_BIND_IN_PROGRESS LDAP_SASL_BIND_INPROGRESS
+#endif
+/* Solaris 8 defines SSL_LDAP_PORT, not LDAPS_PORT and it only does so if
+ LDAP_SSL is defined - but SSL is not working. We just want the
+ port number! Let's just define LDAPS_PORT correct. */
+#if !defined(LDAPS_PORT)
+#define LDAPS_PORT 636
+#endif
+#else
+#undef HAVE_LDAP
+#endif
+
+#if HAVE_GSSAPI_H
+#include <gssapi.h>
+#elif HAVE_GSSAPI_GSSAPI_H
+#include <gssapi/gssapi.h>
+#elif HAVE_GSSAPI_GSSAPI_GENERIC_H
+#include <gssapi/gssapi_generic.h>
+#endif
+
+#if HAVE_COM_ERR_H
+#include <com_err.h>
+#endif
+
+#if HAVE_SYS_ATTRIBUTES_H
+#include <sys/attributes.h>
+#endif
+
+#ifndef ENOATTR
+#define ENOATTR ENODATA
+#endif
+
+/* mutually exclusive (SuSE 8.2) */
+#if HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#elif HAVE_SYS_XATTR_H
+#include <sys/xattr.h>
+#endif
+
+#ifdef HAVE_SYS_EA_H
+#include <sys/ea.h>
+#endif
+
+#ifdef HAVE_SYS_EXTATTR_H
+#include <sys/extattr.h>
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#if HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
+
+#if HAVE_NETGROUP_H
+#include <netgroup.h>
+#endif
+
+#if defined(HAVE_AIO_H) && defined(WITH_AIO)
+#include <aio.h>
+#endif
+
+/* skip valgrind headers on 64bit AMD boxes */
+#ifndef HAVE_64BIT_LINUX
+/* Special macros that are no-ops except when run under Valgrind on
+ * x86. They've moved a little bit from valgrind 1.0.4 to 1.9.4 */
+#if HAVE_VALGRIND_MEMCHECK_H
+ /* memcheck.h includes valgrind.h */
+#include <valgrind/memcheck.h>
+#elif HAVE_VALGRIND_H
+#include <valgrind.h>
+#endif
+#endif
+
+/* If we have --enable-developer and the valgrind header is present,
+ * then we're OK to use it. Set a macro so this logic can be done only
+ * once. */
+#if defined(DEVELOPER) && !defined(HAVE_64BIT_LINUX)
+#if (HAVE_VALGRIND_H || HAVE_VALGRIND_VALGRIND_H)
+#define VALGRIND
+#endif
+#endif
+
+
+/* we support ADS if we want it and have krb5 and ldap libs */
+#if defined(WITH_ADS) && defined(HAVE_KRB5) && defined(HAVE_LDAP)
+#define HAVE_ADS
+#endif
+
+/*
+ * Define VOLATILE if needed.
+ */
+
+#if defined(HAVE_VOLATILE)
+#define VOLATILE volatile
+#else
+#define VOLATILE
+#endif
+
+/*
+ * Define additional missing types
+ */
+#if defined(HAVE_SIG_ATOMIC_T_TYPE) && defined(AIX)
+typedef sig_atomic_t SIG_ATOMIC_T;
+#elif defined(HAVE_SIG_ATOMIC_T_TYPE) && !defined(AIX)
+typedef sig_atomic_t VOLATILE SIG_ATOMIC_T;
+#else
+typedef int VOLATILE SIG_ATOMIC_T;
+#endif
+
+#ifndef uchar
+#define uchar unsigned char
+#endif
+
+#ifdef HAVE_UNSIGNED_CHAR
+#define schar signed char
+#else
+#define schar char
+#endif
+
+/*
+ Samba needs type definitions for int16, int32, uint16 and uint32.
+
+ Normally these are signed and unsigned 16 and 32 bit integers, but
+ they actually only need to be at least 16 and 32 bits
+ respectively. Thus if your word size is 8 bytes just defining them
+ as signed and unsigned int will work.
+*/
+
+#ifndef uint8
+#define uint8 unsigned char
+#endif
+
+#if !defined(int16) && !defined(HAVE_INT16_FROM_RPC_RPC_H)
+# if (SIZEOF_SHORT == 4)
+# define int16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16;
+# else /* SIZEOF_SHORT != 4 */
+# define int16 short
+# endif /* SIZEOF_SHORT != 4 */
+ /* needed to work around compile issue on HP-UX 11.x */
+# define _INT16 1
+#endif
+
+/*
+ * Note we duplicate the size tests in the unsigned
+ * case as int16 may be a typedef from rpc/rpc.h
+ */
+
+#if !defined(uint16) && !defined(HAVE_UINT16_FROM_RPC_RPC_H)
+#if (SIZEOF_SHORT == 4)
+#define uint16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16;
+#else /* SIZEOF_SHORT != 4 */
+#define uint16 unsigned short
+#endif /* SIZEOF_SHORT != 4 */
+#endif
+
+#if !defined(int32) && !defined(HAVE_INT32_FROM_RPC_RPC_H)
+# if (SIZEOF_INT == 4)
+# define int32 int
+# elif (SIZEOF_LONG == 4)
+# define int32 long
+# elif (SIZEOF_SHORT == 4)
+# define int32 short
+# else
+ /* uggh - no 32 bit type?? probably a CRAY. just hope this works ... */
+# define int32 int
+# endif
+ /* needed to work around compile issue on HP-UX 11.x */
+# define _INT32 1
+#endif
+
+/*
+ * Note we duplicate the size tests in the unsigned
+ * case as int32 may be a typedef from rpc/rpc.h
+ */
+
+#if !defined(uint32) && !defined(HAVE_UINT32_FROM_RPC_RPC_H)
+#if (SIZEOF_INT == 4)
+#define uint32 unsigned int
+#elif (SIZEOF_LONG == 4)
+#define uint32 unsigned long
+#elif (SIZEOF_SHORT == 4)
+#define uint32 unsigned short
+#else
+/* uggh - no 32 bit type?? probably a CRAY. just hope this works ... */
+#define uint32 unsigned
+#endif
+#endif
+
+/*
+ * check for 8 byte long long
+ */
+
+#if !defined(uint64)
+#if (SIZEOF_LONG == 8)
+#define uint64 unsigned long
+#elif (SIZEOF_LONG_LONG == 8)
+#define uint64 unsigned long long
+#endif /* don't lie. If we don't have it, then don't use it */
+#endif
+
+#if !defined(int64)
+#if (SIZEOF_LONG == 8)
+#define int64 long
+#elif (SIZEOF_LONG_LONG == 8)
+#define int64 long long
+#endif /* don't lie. If we don't have it, then don't use it */
+#endif
+
+
+/*
+ * Types for devices, inodes and offsets.
+ */
+
+#ifndef SMB_DEV_T
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_DEV64_T)
+# define SMB_DEV_T dev64_t
+# else
+# define SMB_DEV_T dev_t
+# endif
+#endif
+
+#ifndef LARGE_SMB_DEV_T
+# if (defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_DEV64_T)) || (defined(SIZEOF_DEV_T) && (SIZEOF_DEV_T == 8))
+# define LARGE_SMB_DEV_T 1
+# endif
+#endif
+
+#ifdef LARGE_SMB_DEV_T
+#define SDEV_T_VAL(p, ofs, v) (SIVAL((p),(ofs),(v)&0xFFFFFFFF), SIVAL((p),(ofs)+4,(v)>>32))
+#define DEV_T_VAL(p, ofs) ((SMB_DEV_T)(((SMB_BIG_UINT)(IVAL((p),(ofs))))| (((SMB_BIG_UINT)(IVAL((p),(ofs)+4))) << 32)))
+#else
+#define SDEV_T_VAL(p, ofs, v) (SIVAL((p),(ofs),v),SIVAL((p),(ofs)+4,0))
+#define DEV_T_VAL(p, ofs) ((SMB_DEV_T)(IVAL((p),(ofs))))
+#endif
+
+/*
+ * Setup the correctly sized inode type.
+ */
+
+#ifndef SMB_INO_T
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_INO64_T)
+# define SMB_INO_T ino64_t
+# else
+# define SMB_INO_T ino_t
+# endif
+#endif
+
+#ifndef LARGE_SMB_INO_T
+# if (defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_INO64_T)) || (defined(SIZEOF_INO_T) && (SIZEOF_INO_T == 8))
+# define LARGE_SMB_INO_T 1
+# endif
+#endif
+
+#ifdef LARGE_SMB_INO_T
+#define SINO_T_VAL(p, ofs, v) (SIVAL((p),(ofs),(v)&0xFFFFFFFF), SIVAL((p),(ofs)+4,(v)>>32))
+#define INO_T_VAL(p, ofs) ((SMB_INO_T)(((SMB_BIG_UINT)(IVAL(p,ofs)))| (((SMB_BIG_UINT)(IVAL(p,(ofs)+4))) << 32)))
+#else
+#define SINO_T_VAL(p, ofs, v) (SIVAL(p,ofs,v),SIVAL(p,(ofs)+4,0))
+#define INO_T_VAL(p, ofs) ((SMB_INO_T)(IVAL((p),(ofs))))
+#endif
+
+#ifndef SMB_OFF_T
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T)
+# define SMB_OFF_T off64_t
+# else
+# define SMB_OFF_T off_t
+# endif
+#endif
+
+#if defined(HAVE_LONGLONG)
+#define SMB_BIG_UINT unsigned long long
+#define SMB_BIG_INT long long
+#define SBIG_UINT(p, ofs, v) (SIVAL(p,ofs,(v)&0xFFFFFFFF), SIVAL(p,(ofs)+4,(v)>>32))
+#else
+#define SMB_BIG_UINT unsigned long
+#define SMB_BIG_INT long
+#define SBIG_UINT(p, ofs, v) (SIVAL(p,ofs,v),SIVAL(p,(ofs)+4,0))
+#endif
+
+#define SMB_BIG_UINT_BITS (sizeof(SMB_BIG_UINT)*8)
+
+/* this should really be a 64 bit type if possible */
+#define br_off SMB_BIG_UINT
+
+#define SMB_OFF_T_BITS (sizeof(SMB_OFF_T)*8)
+
+/*
+ * Set the define that tells us if we can do 64 bit
+ * NT SMB calls.
+ */
+
+#ifndef LARGE_SMB_OFF_T
+# if (defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T)) || (defined(SIZEOF_OFF_T) && (SIZEOF_OFF_T == 8))
+# define LARGE_SMB_OFF_T 1
+# endif
+#endif
+
+#ifdef LARGE_SMB_OFF_T
+#define SOFF_T(p, ofs, v) (SIVAL(p,ofs,(v)&0xFFFFFFFF), SIVAL(p,(ofs)+4,(v)>>32))
+#define SOFF_T_R(p, ofs, v) (SIVAL(p,(ofs)+4,(v)&0xFFFFFFFF), SIVAL(p,ofs,(v)>>32))
+#define IVAL_TO_SMB_OFF_T(buf,off) ((SMB_OFF_T)(( ((SMB_BIG_UINT)(IVAL((buf),(off)))) & ((SMB_BIG_UINT)0xFFFFFFFF) )))
+#define IVAL2_TO_SMB_BIG_UINT(buf,off) ( (((SMB_BIG_UINT)(IVAL((buf),(off)))) & ((SMB_BIG_UINT)0xFFFFFFFF)) | \
+ (( ((SMB_BIG_UINT)(IVAL((buf),(off+4)))) & ((SMB_BIG_UINT)0xFFFFFFFF) ) << 32 ) )
+#else
+#define SOFF_T(p, ofs, v) (SIVAL(p,ofs,v),SIVAL(p,(ofs)+4,0))
+#define SOFF_T_R(p, ofs, v) (SIVAL(p,(ofs)+4,v),SIVAL(p,ofs,0))
+#define IVAL_TO_SMB_OFF_T(buf,off) ((SMB_OFF_T)(( ((uint32)(IVAL((buf),(off)))) & 0xFFFFFFFF )))
+#define IVAL2_TO_SMB_BIG_UINT(buf,off) ( (((SMB_BIG_UINT)(IVAL((buf),(off)))) & ((SMB_BIG_UINT)0xFFFFFFFF)) | \
+ (( ((SMB_BIG_UINT)(IVAL((buf),(off+4)))) & ((SMB_BIG_UINT)0xFFFFFFFF) ) << 32 ) )
+#endif
+
+/*
+ * Type for stat structure.
+ */
+
+#ifndef SMB_STRUCT_STAT
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_STAT64) && defined(HAVE_OFF64_T)
+# define SMB_STRUCT_STAT struct stat64
+# else
+# define SMB_STRUCT_STAT struct stat
+# endif
+#endif
+
+/*
+ * Type for dirent structure.
+ */
+
+#ifndef SMB_STRUCT_DIRENT
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_STRUCT_DIRENT64)
+# define SMB_STRUCT_DIRENT struct dirent64
+# else
+# define SMB_STRUCT_DIRENT struct dirent
+# endif
+#endif
+
+/*
+ * Type for DIR structure.
+ */
+
+#ifndef SMB_STRUCT_DIR
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_STRUCT_DIR64)
+# define SMB_STRUCT_DIR DIR64
+# else
+# define SMB_STRUCT_DIR DIR
+# endif
+#endif
+
+/*
+ * Defines for 64 bit fcntl locks.
+ */
+
+#ifndef SMB_STRUCT_FLOCK
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_STRUCT_FLOCK64) && defined(HAVE_OFF64_T)
+# define SMB_STRUCT_FLOCK struct flock64
+# else
+# define SMB_STRUCT_FLOCK struct flock
+# endif
+#endif
+
+#ifndef SMB_F_SETLKW
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_STRUCT_FLOCK64) && defined(HAVE_OFF64_T)
+# define SMB_F_SETLKW F_SETLKW64
+# else
+# define SMB_F_SETLKW F_SETLKW
+# endif
+#endif
+
+#ifndef SMB_F_SETLK
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_STRUCT_FLOCK64) && defined(HAVE_OFF64_T)
+# define SMB_F_SETLK F_SETLK64
+# else
+# define SMB_F_SETLK F_SETLK
+# endif
+#endif
+
+#ifndef SMB_F_GETLK
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_STRUCT_FLOCK64) && defined(HAVE_OFF64_T)
+# define SMB_F_GETLK F_GETLK64
+# else
+# define SMB_F_GETLK F_GETLK
+# endif
+#endif
+
+/*
+ * Type for aiocb structure.
+ */
+
+#ifndef SMB_STRUCT_AIOCB
+# if defined(WITH_AIO)
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64)
+# define SMB_STRUCT_AIOCB struct aiocb64
+# else
+# define SMB_STRUCT_AIOCB struct aiocb
+# endif
+# else
+# define SMB_STRUCT_AIOCB int /* AIO not being used but we still need the define.... */
+# endif
+#endif
+
+#ifndef HAVE_STRUCT_TIMESPEC
+struct timespec {
+ time_t tv_sec; /* Seconds. */
+ long tv_nsec; /* Nanoseconds. */
+};
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+#ifdef HAVE_BROKEN_GETGROUPS
+#define GID_T int
+#else
+#define GID_T gid_t
+#endif
+
+#ifndef NGROUPS_MAX
+#define NGROUPS_MAX 32 /* Guess... */
+#endif
+
+/* Our own fstrings */
+
+/*
+ --------------
+ / \
+ / REST \
+ / IN \
+ / PEACE \
+ / \
+ | The infamous pstring |
+ | |
+ | |
+ | 7 December |
+ | |
+ | 2007 |
+ *| * * * | *
+ _________)/\\_//(\/(/\)/\//\/\///|_)_______
+*/
+
+#ifndef FSTRING_LEN
+#define FSTRING_LEN 256
+typedef char fstring[FSTRING_LEN];
+#endif
+
+/* Lists, trees, caching, database... */
+#include "xfile.h"
+#include "intl.h"
+#include "dlinklist.h"
+#include "tdb.h"
+#include "util_tdb.h"
+
+#include "lib/talloc/talloc.h"
+/* And a little extension. Abort on type mismatch */
+#define talloc_get_type_abort(ptr, type) \
+ (type *)talloc_check_name_abort(ptr, #type)
+
+#include "nt_status.h"
+#include "ads.h"
+#include "ads_dns.h"
+#include "interfaces.h"
+#include "trans2.h"
+#include "nterr.h"
+#include "ntioctl.h"
+#include "charset.h"
+#include "dynconfig.h"
+#include "util_getent.h"
+#include "debugparse.h"
+#include "version.h"
+#include "privileges.h"
+#include "messages.h"
+#include "locking.h"
+#include "smb.h"
+#include "nameserv.h"
+#include "secrets.h"
+#include "byteorder.h"
+#include "privileges.h"
+#include "rpc_misc.h"
+#include "rpc_dce.h"
+#include "mapping.h"
+#include "passdb.h"
+#include "rpc_secdes.h"
+#include "gpo.h"
+#include "authdata.h"
+#include "msdfs.h"
+#include "rap.h"
+#include "md5.h"
+#include "hmacmd5.h"
+#include "ntlmssp.h"
+#include "auth.h"
+#include "ntdomain.h"
+#include "rpc_svcctl.h"
+#include "rpc_ntsvcs.h"
+#include "rpc_lsa.h"
+#include "reg_objects.h"
+#include "reg_db.h"
+#include "rpc_spoolss.h"
+#include "rpc_eventlog.h"
+#include "rpc_perfcount.h"
+#include "rpc_perfcount_defs.h"
+#include "librpc/gen_ndr/notify.h"
+#include "librpc/gen_ndr/xattr.h"
+#include "librpc/gen_ndr/messaging.h"
+#include "librpc/rpc/dcerpc.h"
+#include "nt_printing.h"
+#include "idmap.h"
+#include "client.h"
+
+#include "session.h"
+#include "asn_1.h"
+#include "popt.h"
+#include "mangle.h"
+#include "module.h"
+#include "nsswitch/winbind_client.h"
+#include "spnego.h"
+#include "rpc_client.h"
+#include "event.h"
+#include "dbwrap.h"
+#include "packet.h"
+#include "ctdbd_conn.h"
+#include "talloc_stack.h"
+#include "memcache.h"
+#include "async_req.h"
+#include "async_smb.h"
+#include "async_sock.h"
+
+#include "lib/smbconf/smbconf.h"
+
+/* Defines for wisXXX functions. */
+#define UNI_UPPER 0x1
+#define UNI_LOWER 0x2
+#define UNI_DIGIT 0x4
+#define UNI_XDIGIT 0x8
+#define UNI_SPACE 0x10
+
+#include "nsswitch/winbind_nss.h"
+
+/* forward declaration from printing.h to get around
+ header file dependencies */
+
+struct printjob;
+
+/* forward declarations from smbldap.c */
+
+#include "smbldap.h"
+
+#include "smb_ldap.h"
+
+struct dns_reg_state;
+
+void dns_register_smbd(struct dns_reg_state ** dns_state_ptr,
+ unsigned port,
+ int *maxfd,
+ fd_set *listen_set,
+ struct timeval *timeout);
+
+void dns_register_close(struct dns_reg_state ** dns_state_ptr);
+
+
+bool dns_register_smbd_reply(struct dns_reg_state *dns_state,
+ fd_set *lfds, struct timeval *timeout);
+
+/*
+ * Reasons for cache flush.
+ */
+
+enum flush_reason_enum {
+ SEEK_FLUSH,
+ READ_FLUSH,
+ WRITE_FLUSH,
+ READRAW_FLUSH,
+ OPLOCK_RELEASE_FLUSH,
+ CLOSE_FLUSH,
+ SYNC_FLUSH,
+ SIZECHANGE_FLUSH,
+ /* NUM_FLUSH_REASONS must remain the last value in the enumeration. */
+ NUM_FLUSH_REASONS};
+
+#include "nss_info.h"
+#include "modules/nfs4_acls.h"
+#include "nsswitch/libwbclient/wbclient.h"
+
+/* generated rpc server implementation functions */
+#include "librpc/gen_ndr/srv_echo.h"
+#include "librpc/gen_ndr/srv_svcctl.h"
+#include "librpc/gen_ndr/srv_lsa.h"
+#include "librpc/gen_ndr/srv_eventlog.h"
+#include "librpc/gen_ndr/srv_winreg.h"
+#include "librpc/gen_ndr/srv_initshutdown.h"
+
+/***** automatically generated prototypes *****/
+#ifndef NO_PROTO_H
+#include "proto.h"
+#endif
+
+#if defined(HAVE_POSIX_ACLS)
+#include "modules/vfs_posixacl.h"
+#endif
+
+#if defined(HAVE_TRU64_ACLS)
+#include "modules/vfs_tru64acl.h"
+#endif
+
+#if defined(HAVE_SOLARIS_ACLS) || defined(HAVE_UNIXWARE_ACLS)
+#include "modules/vfs_solarisacl.h"
+#endif
+
+#if defined(HAVE_HPUX_ACLS)
+#include "modules/vfs_hpuxacl.h"
+#endif
+
+#if defined(HAVE_IRIX_ACLS)
+#include "modules/vfs_irixacl.h"
+#endif
+
+#ifdef HAVE_LDAP
+#include "ads_protos.h"
+#endif
+
+/* We need this after proto.h to reference GetTimeOfDay(). */
+#include "smbprofile.h"
+
+/* String routines */
+
+#include "srvstr.h"
+#include "safe_string.h"
+
+/* prototypes from lib/util_transfer_file.c */
+#include "transfer_file.h"
+
+#ifdef __COMPAR_FN_T
+#define QSORT_CAST (__compar_fn_t)
+#endif
+
+#ifndef QSORT_CAST
+#define QSORT_CAST (int (*)(const void *, const void *))
+#endif
+
+#ifndef DEFAULT_PRINTING
+#ifdef HAVE_CUPS
+#define DEFAULT_PRINTING PRINT_CUPS
+#define PRINTCAP_NAME "cups"
+#elif defined(SYSV)
+#define DEFAULT_PRINTING PRINT_SYSV
+#define PRINTCAP_NAME "lpstat"
+#else
+#define DEFAULT_PRINTING PRINT_BSD
+#define PRINTCAP_NAME "/etc/printcap"
+#endif
+#endif
+
+#ifndef PRINTCAP_NAME
+#define PRINTCAP_NAME "/etc/printcap"
+#endif
+
+#ifndef SIGCLD
+#define SIGCLD SIGCHLD
+#endif
+
+#ifndef SIGRTMIN
+#define SIGRTMIN 32
+#endif
+
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+#if defined(HAVE_PUTPRPWNAM) && defined(AUTH_CLEARTEXT_SEG_CHARS)
+#define OSF1_ENH_SEC 1
+#endif
+
+#ifndef ALLOW_CHANGE_PASSWORD
+#if (defined(HAVE_TERMIOS_H) && defined(HAVE_DUP2) && defined(HAVE_SETSID))
+#define ALLOW_CHANGE_PASSWORD 1
+#endif
+#endif
+
+/* 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 HAVE_PIPE
+#define SYNC_DNS 1
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+#ifndef HAVE_CRYPT
+#define crypt ufc_crypt
+#endif
+
+#ifndef O_ACCMODE
+#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
+#endif
+
+#if defined(HAVE_CRYPT16) && defined(HAVE_GETAUTHUID)
+#define ULTRIX_AUTH 1
+#endif
+
+#if (defined(USE_SETRESUID) && !defined(HAVE_SETRESUID_DECL))
+/* stupid glibc */
+int setresuid(uid_t ruid, uid_t euid, uid_t suid);
+#endif
+#if (defined(USE_SETRESUID) && !defined(HAVE_SETRESGID_DECL))
+int setresgid(gid_t rgid, gid_t egid, gid_t sgid);
+#endif
+
+/*
+ * Some older systems seem not to have MAXHOSTNAMELEN
+ * defined.
+ */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 255
+#endif
+
+/* yuck, I'd like a better way of doing this */
+#define DIRP_SIZE (256 + 32)
+
+/*
+ * glibc on linux doesn't seem to have MSG_WAITALL
+ * defined. I think the kernel has it though..
+ */
+
+#ifndef MSG_WAITALL
+#define MSG_WAITALL 0
+#endif
+
+/* default socket options. Dave Miller thinks we should default to TCP_NODELAY
+ given the socket IO pattern that Samba uses */
+#ifdef TCP_NODELAY
+#define DEFAULT_SOCKET_OPTIONS "TCP_NODELAY"
+#else
+#define DEFAULT_SOCKET_OPTIONS ""
+#endif
+
+/* dmalloc -- free heap debugger (dmalloc.org). This should be near
+ * the *bottom* of include files so as not to conflict. */
+#ifdef ENABLE_DMALLOC
+# include <dmalloc.h>
+#endif
+
+
+/* Some POSIX definitions for those without */
+
+#ifndef S_IFDIR
+#define S_IFDIR 0x4000
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(mode) ((mode & 0xF000) == S_IFDIR)
+#endif
+#ifndef S_IRWXU
+#define S_IRWXU 00700 /* read, write, execute: owner */
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR 00400 /* read permission: owner */
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR 00200 /* write permission: owner */
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR 00100 /* execute permission: owner */
+#endif
+#ifndef S_IRWXG
+#define S_IRWXG 00070 /* read, write, execute: group */
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP 00040 /* read permission: group */
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP 00020 /* write permission: group */
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 00010 /* execute permission: group */
+#endif
+#ifndef S_IRWXO
+#define S_IRWXO 00007 /* read, write, execute: other */
+#endif
+#ifndef S_IROTH
+#define S_IROTH 00004 /* read permission: other */
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 00002 /* write permission: other */
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 00001 /* execute permission: other */
+#endif
+
+/* For sys_adminlog(). */
+#ifndef LOG_EMERG
+#define LOG_EMERG 0 /* system is unusable */
+#endif
+
+#ifndef LOG_ALERT
+#define LOG_ALERT 1 /* action must be taken immediately */
+#endif
+
+#ifndef LOG_CRIT
+#define LOG_CRIT 2 /* critical conditions */
+#endif
+
+#ifndef LOG_ERR
+#define LOG_ERR 3 /* error conditions */
+#endif
+
+#ifndef LOG_WARNING
+#define LOG_WARNING 4 /* warning conditions */
+#endif
+
+#ifndef LOG_NOTICE
+#define LOG_NOTICE 5 /* normal but significant condition */
+#endif
+
+#ifndef LOG_INFO
+#define LOG_INFO 6 /* informational */
+#endif
+
+#ifndef LOG_DEBUG
+#define LOG_DEBUG 7 /* debug-level messages */
+#endif
+
+#if HAVE_KERNEL_SHARE_MODES
+#ifndef LOCK_MAND
+#define LOCK_MAND 32 /* This is a mandatory flock */
+#define LOCK_READ 64 /* ... Which allows concurrent read operations */
+#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
+#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
+#endif
+#endif
+
+extern int DEBUGLEVEL;
+
+#define MAX_SEC_CTX_DEPTH 8 /* Maximum number of security contexts */
+
+
+#ifdef GLIBC_HACK_FCNTL64
+/* this is a gross hack. 64 bit locking is completely screwed up on
+ i386 Linux in glibc 2.1.95 (which ships with RedHat 7.0). This hack
+ "fixes" the problem with the current 2.4.0test kernels
+*/
+#define fcntl fcntl64
+#undef F_SETLKW
+#undef F_SETLK
+#define F_SETLK 13
+#define F_SETLKW 14
+#endif
+
+
+/* Needed for sys_dlopen/sys_dlsym/sys_dlclose */
+#ifndef RTLD_GLOBAL
+#define RTLD_GLOBAL 0
+#endif
+
+#ifndef RTLD_LAZY
+#define RTLD_LAZY 0
+#endif
+
+#ifndef RTLD_NOW
+#define RTLD_NOW 0
+#endif
+
+/* needed for some systems without iconv. Doesn't really matter
+ what error code we use */
+#ifndef EILSEQ
+#define EILSEQ EIO
+#endif
+
+/* add varargs prototypes with printf checking */
+/*PRINTFLIKE2 */
+int fdprintf(int , const char *, ...) PRINTF_ATTRIBUTE(2,3);
+/*PRINTFLIKE1 */
+int d_printf(const char *, ...) PRINTF_ATTRIBUTE(1,2);
+/*PRINTFLIKE2 */
+int d_fprintf(FILE *f, const char *, ...) PRINTF_ATTRIBUTE(2,3);
+
+/* PRINTFLIKE2 */
+void sys_adminlog(int priority, const char *format_str, ...) PRINTF_ATTRIBUTE(2,3);
+
+/* PRINTFLIKE2 */
+int fstr_sprintf(fstring s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+int d_vfprintf(FILE *f, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+int smb_xvasprintf(char **ptr, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+int asprintf_strupper_m(char **strp, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+char *talloc_asprintf_strupper_m(TALLOC_CTX *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+/* we used to use these fns, but now we have good replacements
+ for snprintf and vsnprintf */
+#define slprintf snprintf
+#define vslprintf vsnprintf
+
+/* we need to use __va_copy() on some platforms */
+#ifdef HAVE_VA_COPY
+#define VA_COPY(dest, src) va_copy(dest, src)
+#else
+#ifdef HAVE___VA_COPY
+#define VA_COPY(dest, src) __va_copy(dest, src)
+#else
+#define VA_COPY(dest, src) (dest) = (src)
+#endif
+#endif
+
+/*
+ * Veritas File System. Often in addition to native.
+ * Quotas different.
+ */
+#if defined(HAVE_SYS_FS_VX_QUOTA_H)
+#define VXFS_QUOTA
+#endif
+
+#ifndef XATTR_CREATE
+#define XATTR_CREATE 0x1 /* set value, fail if attr already exists */
+#endif
+
+#ifndef XATTR_REPLACE
+#define XATTR_REPLACE 0x2 /* set value, fail if attr does not exist */
+#endif
+
+#if defined(HAVE_KRB5)
+
+krb5_error_code smb_krb5_parse_name(krb5_context context,
+ const char *name, /* in unix charset */
+ krb5_principal *principal);
+
+krb5_error_code smb_krb5_unparse_name(krb5_context context,
+ krb5_const_principal principal,
+ char **unix_name);
+
+#ifndef HAVE_KRB5_SET_REAL_TIME
+krb5_error_code krb5_set_real_time(krb5_context context, int32_t seconds, int32_t microseconds);
+#endif
+
+krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc);
+
+#if defined(HAVE_KRB5_AUTH_CON_SETKEY) && !defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY)
+krb5_error_code krb5_auth_con_setuseruserkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock *keyblock);
+#endif
+
+#ifndef HAVE_KRB5_FREE_UNPARSED_NAME
+void krb5_free_unparsed_name(krb5_context ctx, char *val);
+#endif
+
+/* Stub out initialize_krb5_error_table since it is not present in all
+ * Kerberos implementations. If it's not present, it's not necessary to
+ * call it.
+ */
+#ifndef HAVE_INITIALIZE_KRB5_ERROR_TABLE
+#define initialize_krb5_error_table()
+#endif
+
+/* Samba wrapper function for krb5 functionality. */
+bool setup_kaddr( krb5_address *pkaddr, struct sockaddr_storage *paddr);
+int create_kerberos_key_from_string(krb5_context context, krb5_principal host_princ, krb5_data *password, krb5_keyblock *key, krb5_enctype enctype, bool no_salt);
+bool get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, krb5_ticket *tkt);
+krb5_const_principal get_principal_from_tkt(krb5_ticket *tkt);
+krb5_error_code smb_krb5_locate_kdc(krb5_context ctx, const krb5_data *realm, struct sockaddr **addr_pp, int *naddrs, int get_masters);
+#if defined(HAVE_KRB5_LOCATE_KDC)
+krb5_error_code krb5_locate_kdc(krb5_context ctx, const krb5_data *realm, struct sockaddr **addr_pp, int *naddrs, int get_masters);
+#endif
+krb5_error_code get_kerberos_allowed_etypes(krb5_context context, krb5_enctype **enctypes);
+bool get_krb5_smb_session_key(krb5_context context, krb5_auth_context auth_context, DATA_BLOB *session_key, bool remote);
+krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry);
+krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context, krb5_principal host_princ, int enctype);
+void kerberos_set_creds_enctype(krb5_creds *pcreds, int enctype);
+bool kerberos_compatible_enctypes(krb5_context context, krb5_enctype enctype1, krb5_enctype enctype2);
+void kerberos_free_data_contents(krb5_context context, krb5_data *pdata);
+NTSTATUS decode_pac_data(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pac_data_blob,
+ krb5_context context,
+ krb5_keyblock *service_keyblock,
+ krb5_const_principal client_principal,
+ time_t tgs_authtime,
+ struct PAC_DATA **pac_data_out);
+void smb_krb5_checksum_from_pac_sig(krb5_checksum *cksum,
+ struct PAC_SIGNATURE_DATA *sig);
+krb5_error_code smb_krb5_verify_checksum(krb5_context context,
+ const krb5_keyblock *keyblock,
+ krb5_keyusage usage,
+ krb5_checksum *cksum,
+ uint8 *data,
+ size_t length);
+time_t get_authtime_from_tkt(krb5_ticket *tkt);
+void smb_krb5_free_ap_req(krb5_context context,
+ krb5_ap_req *ap_req);
+krb5_error_code smb_krb5_get_keyinfo_from_ap_req(krb5_context context,
+ const krb5_data *inbuf,
+ krb5_kvno *kvno,
+ krb5_enctype *enctype);
+krb5_error_code krb5_rd_req_return_keyblock_from_keytab(krb5_context context,
+ krb5_auth_context *auth_context,
+ const krb5_data *inbuf,
+ krb5_const_principal server,
+ krb5_keytab keytab,
+ krb5_flags *ap_req_options,
+ krb5_ticket **ticket,
+ krb5_keyblock **keyblock);
+krb5_error_code smb_krb5_parse_name_norealm(krb5_context context,
+ const char *name,
+ krb5_principal *principal);
+bool smb_krb5_principal_compare_any_realm(krb5_context context,
+ krb5_const_principal princ1,
+ krb5_const_principal princ2);
+int cli_krb5_get_ticket(const char *principal, time_t time_offset,
+ DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts, const char *ccname, time_t *tgs_expire);
+krb5_error_code smb_krb5_renew_ticket(const char *ccache_string, const char *client_string, const char *service_string, time_t *expire_time);
+krb5_error_code kpasswd_err_to_krb5_err(krb5_error_code res_code);
+krb5_error_code smb_krb5_gen_netbios_krb5_address(smb_krb5_addresses **kerb_addr);
+krb5_error_code smb_krb5_free_addresses(krb5_context context, smb_krb5_addresses *addr);
+NTSTATUS krb5_to_nt_status(krb5_error_code kerberos_error);
+krb5_error_code nt_status_to_krb5(NTSTATUS nt_status);
+void smb_krb5_free_error(krb5_context context, krb5_error *krberror);
+krb5_error_code handle_krberror_packet(krb5_context context,
+ krb5_data *packet);
+
+void smb_krb5_get_init_creds_opt_free(krb5_context context,
+ krb5_get_init_creds_opt *opt);
+krb5_error_code smb_krb5_get_init_creds_opt_alloc(krb5_context context,
+ krb5_get_init_creds_opt **opt);
+krb5_error_code smb_krb5_mk_error(krb5_context context,
+ krb5_error_code error_code,
+ const krb5_principal server,
+ krb5_data *reply);
+krb5_enctype smb_get_enctype_from_kt_entry(krb5_keytab_entry *kt_entry);
+krb5_error_code smb_krb5_enctype_to_string(krb5_context context,
+ krb5_enctype enctype,
+ char **etype_s);
+krb5_error_code smb_krb5_open_keytab(krb5_context context,
+ const char *keytab_name,
+ bool write_access,
+ krb5_keytab *keytab);
+krb5_error_code smb_krb5_keytab_name(TALLOC_CTX *mem_ctx,
+ krb5_context context,
+ krb5_keytab keytab,
+ const char **keytab_name);
+int smb_krb5_kt_add_entry_ext(krb5_context context,
+ krb5_keytab keytab,
+ krb5_kvno kvno,
+ const char *princ_s,
+ krb5_enctype *enctypes,
+ krb5_data password,
+ bool no_salt,
+ bool keep_old_entries);
+
+#endif /* HAVE_KRB5 */
+
+
+#ifdef HAVE_LDAP
+
+/* function declarations not included in proto.h */
+LDAP *ldap_open_with_timeout(const char *server, int port, unsigned int to);
+
+#endif /* HAVE_LDAP */
+
+#if defined(HAVE_LINUX_READAHEAD) && ! defined(HAVE_READAHEAD_DECL)
+ssize_t readahead(int fd, off64_t offset, size_t count);
+#endif
+
+/* TRUE and FALSE are part of the C99 standard and gcc, but
+ unfortunately many vendor compilers don't support them. Use True
+ and False instead. */
+
+#ifdef TRUE
+#undef TRUE
+#endif
+#define TRUE __ERROR__XX__DONT_USE_TRUE
+
+#ifdef FALSE
+#undef FALSE
+#endif
+#define FALSE __ERROR__XX__DONT_USE_FALSE
+
+/* If we have blacklisted mmap() try to avoid using it accidentally by
+ undefining the HAVE_MMAP symbol. */
+
+#ifdef MMAP_BLACKLIST
+#undef HAVE_MMAP
+#endif
+
+#define CONST_DISCARD(type, ptr) ((type) ((void *) (ptr)))
+#define CONST_ADD(type, ptr) ((type) ((const void *) (ptr)))
+
+#ifndef NORETURN_ATTRIBUTE
+#if (__GNUC__ >= 3)
+#define NORETURN_ATTRIBUTE __attribute__ ((noreturn))
+#else
+#define NORETURN_ATTRIBUTE
+#endif
+#endif
+
+void smb_panic( const char *why ) NORETURN_ATTRIBUTE ;
+void dump_core(void) NORETURN_ATTRIBUTE ;
+void exit_server(const char *const reason) NORETURN_ATTRIBUTE ;
+void exit_server_cleanly(const char *const reason) NORETURN_ATTRIBUTE ;
+void exit_server_fault(void) NORETURN_ATTRIBUTE ;
+
+#ifdef HAVE_LIBNSCD
+#include "libnscd.h"
+#endif
+
+#if defined(HAVE_IPV6)
+void in6_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
+ struct in6_addr ip);
+#endif
+
+#endif /* _INCLUDES_H */
diff --git a/source3/include/interfaces.h b/source3/include/interfaces.h
new file mode 100644
index 0000000000..84501cee41
--- /dev/null
+++ b/source3/include/interfaces.h
@@ -0,0 +1,51 @@
+/*
+ Unix SMB/CIFS implementation.
+ Machine customisation and include handling
+ Copyright (C) Jeremy Allison <jra@samba.org> 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ This structure is used by lib/interfaces.c to return the list of network
+ interfaces on the machine
+*/
+
+#ifndef _INTERFACES_H
+#define _INTERFACES_H
+
+#include "lib/replace/replace.h"
+#include "lib/replace/system/network.h"
+
+#define MAX_INTERFACES 128
+
+struct iface_struct {
+ char name[16];
+ int flags;
+ struct sockaddr_storage ip;
+ struct sockaddr_storage netmask;
+ struct sockaddr_storage bcast;
+};
+
+bool make_netmask(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ unsigned long masklen);
+void make_bcast(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ const struct sockaddr_storage *nmask);
+void make_net(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ const struct sockaddr_storage *nmask);
+int get_interfaces(struct iface_struct *ifaces, int max_interfaces);
+
+#endif
diff --git a/source3/include/intl.h b/source3/include/intl.h
new file mode 100644
index 0000000000..cb0dc346cc
--- /dev/null
+++ b/source3/include/intl.h
@@ -0,0 +1,23 @@
+/*
+ Unix SMB/CIFS implementation.
+ internationalisation headers
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/* ideally we would have a static mapping, but that precludes
+ dynamic loading. This is a reasonable compromise */
+#define N_(x) (x)
diff --git a/source3/include/libmsrpc.h b/source3/include/libmsrpc.h
new file mode 100644
index 0000000000..3f2a7260ca
--- /dev/null
+++ b/source3/include/libmsrpc.h
@@ -0,0 +1,3045 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * MS-RPC client library API definitions/prototypes
+ *
+ * Copyright (C) Chris Nicholls 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBMSRPC_H
+#define LIBMSRPC_H
+
+
+#include "includes.h"
+#include "libsmbclient.h"
+#include "libsmb_internal.h"
+
+/*server capability levels*/
+#define SRV_WIN_NT4 1
+#define SRV_WIN_2K 2
+#define SRV_WIN_2K_SP3 3
+#define SRV_WIN_2K3 4
+
+/**@defgroup handle Server Handle*/
+/**@defgroup Library_Functions Library/Utility Functions*/
+/**@defgroup lsa_defs LSA Definitions*/
+/**@defgroup LSA_Functions LSA Functions*/
+/**@defgroup reg_defs Registry Definitions*/
+/**@defgroup Reg_Functions Registry Functions*/
+/**@defgroup sam_defs SAM Definitions*/
+/**@defgroup SAM_Functions SAM Functions*/
+/**@defgroup svc_defs Service Control Definitions*/
+/**@defgroup SCM_Functions Service Control Functions*/
+
+/**Operation was unsuccessful*/
+#define CAC_FAILURE 0
+/**Operation was successful*/
+#define CAC_SUCCESS 1
+/**Operation was only partially successful
+ * an example of this is if you try to lookup a list of accounts to SIDs and not all accounts can be resolved*/
+#define CAC_PARTIAL_SUCCESS 2
+
+/**@ingroup CAC_errors Use this to see if the last operation failed - useful for enumeration functions that use multiple calls*/
+#define CAC_OP_FAILED(status) !NT_STATUS_IS_OK(status) && \
+ NT_STATUS_V(status) != NT_STATUS_V(STATUS_SOME_UNMAPPED) && \
+ NT_STATUS_V(status) != NT_STATUS_V(STATUS_NO_MORE_FILES) && \
+ NT_STATUS_V(status) != NT_STATUS_V(NT_STATUS_NO_MORE_ENTRIES) && \
+ NT_STATUS_V(status) != NT_STATUS_V(NT_STATUS_NONE_MAPPED) && \
+ NT_STATUS_V(status) != NT_STATUS_V(NT_STATUS_GUIDS_EXHAUSTED)
+
+
+/**Privilege string constants*/
+#define CAC_SE_CREATE_TOKEN "SeCreateTokenPrivilege"
+#define CAC_SE_ASSIGN_PRIMARY_TOKEN "SeAssignPrimaryTokenPrivilege"
+#define CAC_SE_LOCK_MEMORY "SeLockMemoryPrivilege"
+#define CAC_SE_INCREASE_QUOTA "SeIncreaseQuotaPrivilege"
+#define CAC_SE_MACHINE_ACCOUNT "SeMachineAccountPrivilege"
+#define CAC_SE_TCB "SeTcbPrivilege"
+#define CAC_SE_SECURITY "SeSecurityPrivilege"
+#define CAC_SE_TAKE_OWNERSHIP "SeTakeOwnershipPrivilege"
+#define CAC_SE_LOAD_DRIVER "SeLoadDriverPrivilege"
+#define CAC_SE_SYSTEM_PROFILE "SeSystemProfilePrivilege"
+#define CAC_SE_SYSTEM_TIME "SeSystemtimePrivilege"
+#define CAC_SE_PROFILE_SINGLE_PROC "SeProfileSingleProcessPrivilege"
+#define CAC_SE_INCREASE_BASE_PRIORITY "SeIncreaseBasePriorityPrivilege"
+#define CAC_SE_CREATE_PAGEFILE "SeCreatePagefilePrivilege"
+#define CAC_SE_CREATE_PERMANENT "SeCreatePermanentPrivilege"
+#define CAC_SE_BACKUP "SeBackupPrivilege"
+#define CAC_SE_RESTORE "SeRestorePrivilege"
+#define CAC_SE_SHUTDOWN "SeShutdownPrivilege"
+#define CAC_SE_DEBUG "SeDebugPrivilege"
+#define CAC_SE_AUDIT "SeAuditPrivilege"
+#define CAC_SE_SYSTEM_ENV "SeSystemEnvironmentPrivilege"
+#define CAC_SE_CHANGE_NOTIFY "SeChangeNotifyPrivilege"
+#define CAC_SE_REMOTE_SHUTDOWN "SeRemoteShutdownPrivilege"
+#define CAC_SE_UNDOCK "SeUndockPrivilege"
+#define CAC_SE_SYNC_AGENT "SeSyncAgentPrivilege"
+#define CAC_SE_ENABLE_DELEGATION "SeEnableDelegationPrivilege"
+#define CAC_SE_MANAGE_VOLUME "SeManageVolumePrivilege"
+#define CAC_SE_IMPERSONATE "SeImpersonatePrivilege"
+#define CAC_SE_CREATE_GLOBAL "SeCreateGlobalPrivilege"
+#define CAC_SE_PRINT_OPERATOR "SePrintOperatorPrivilege"
+#define CAC_SE_NETWORK_LOGON "SeNetworkLogonRight"
+#define CAC_SE_INTERACTIVE_LOGON "SeInteractiveLogonRight"
+#define CAC_SE_BATCH_LOGON "SeBatchLogonRight"
+#define CAC_SE_SERVICE_LOGON "SeServiceLogonRight"
+#define CAC_SE_ADD_USERS "SeAddUsersPrivilege"
+#define CAC_SE_DISK_OPERATOR "SeDiskOperatorPrivilege"
+
+/**
+ * @addtogroup lsa_defs
+ * @{
+ */
+/**used to specify what data to retrieve using cac_LsaQueryTrustedDomainInformation*/
+#define CAC_INFO_TRUSTED_DOMAIN_NAME 0x1
+#define CAC_INFO_TRUSTED_DOMAIN_POSIX_OFFSET 0x3
+#define CAC_INFO_TRUSTED_DOMAIN_PASSWORD 0x4
+
+/**Used when requesting machine domain information*/
+#define CAC_DOMAIN_INFO 0x0003
+
+/**Used when requesting machine local information*/
+#define CAC_LOCAL_INFO 0x0005
+
+/**Stores information about a SID*/
+typedef struct _CACSIDINFO {
+ /**The actual SID*/
+ DOM_SID sid;
+
+ /**The name of the object which maps to this SID*/
+ char *name;
+
+ /**The domain the SID belongs to*/
+ char *domain;
+} CacSidInfo;
+/* @} */
+
+/**
+ * @addtogroup reg_defs
+ * @{
+ */
+/**Null terminated string*/
+typedef char* REG_SZ_DATA;
+
+/**Null terminated string with windows environment variables that should be expanded*/
+typedef char* REG_EXPAND_SZ_DATA;
+
+/**Binary data of some kind*/
+typedef struct _REGBINARYDATA {
+ uint32 data_length;
+ uint8 * data;
+} REG_BINARY_DATA;
+
+/**32-bit (little endian) number*/
+typedef uint32 REG_DWORD_DATA;
+
+/**32-bit big endian number*/
+typedef uint32 REG_DWORD_BE_DATA;
+
+/**array of strings*/
+typedef struct _REGMULTISZDATA {
+ uint32 num_strings;
+
+ char **strings;
+} REG_MULTI_SZ_DATA;
+
+typedef union _REGVALUEDATA {
+ REG_SZ_DATA reg_sz;
+ REG_EXPAND_SZ_DATA reg_expand_sz;
+ REG_BINARY_DATA reg_binary;
+ REG_DWORD_DATA reg_dword;
+ REG_DWORD_BE_DATA reg_dword_be;
+ REG_MULTI_SZ_DATA reg_multi_sz;
+} REG_VALUE_DATA;
+/**@}*/
+
+/**
+ * @addtogroup sam_defs
+ * @{
+ */
+
+#define CAC_USER_RID 0x1
+#define CAC_GROUP_RID 0x2
+
+typedef struct _CACLOOKUPRIDSRECORD {
+ char *name;
+ uint32 rid;
+
+ /**If found, this will be one of:
+ * - CAC_USER_RID
+ * - CAC_GROUP_RID
+ */
+ uint32 type;
+
+ /*if the name or RID was looked up, then found = True*/
+ bool found;
+} CacLookupRidsRecord;
+
+typedef struct _CACUSERINFO {
+ /**Last logon time*/
+ time_t logon_time;
+
+ /**Last logoff time*/
+ time_t logoff_time;
+
+ /**Last kickoff time*/
+ time_t kickoff_time;
+
+ /**Last password set time*/
+ time_t pass_last_set_time;
+
+ /**Time password can change*/
+ time_t pass_can_change_time;
+
+ /**Time password must change*/
+ time_t pass_must_change_time;
+
+ /**LM user password*/
+ uint8 lm_password[8];
+
+ /**NT user password*/
+ uint8 nt_password[8];
+
+ /**User's RID*/
+ uint32 rid;
+
+ /**RID of primary group*/
+ uint32 group_rid;
+
+ /**User's ACB mask*/
+ uint32 acb_mask;
+
+ /**Bad password count*/
+ uint16 bad_passwd_count;
+
+ /**Number of logons*/
+ uint16 logon_count;
+
+ /**Change password at next logon?*/
+ bool pass_must_change;
+
+ /**Username*/
+ char *username;
+
+ /**User's full name*/
+ char *full_name;
+
+ /**User's home directory*/
+ char *home_dir;
+
+ /**Home directory drive*/
+ char *home_drive;
+
+ /**Logon script*/
+ char *logon_script;
+
+ /**Path to profile*/
+ char *profile_path;
+
+ /**Account description*/
+ char *description;
+
+ /**Login from workstations*/
+ char *workstations;
+
+ char *dial;
+
+ /**Possible logon hours*/
+ LOGON_HRS *logon_hours;
+
+} CacUserInfo;
+
+typedef struct _CACGROUPINFO {
+ /**Group name*/
+ char *name;
+
+ /**Description*/
+ char *description;
+
+ /**Number of members*/
+ uint32 num_members;
+} CacGroupInfo, CacAliasInfo;
+
+/**Represents a period (duration) of time*/
+typedef struct _CACTIME {
+ /**Number of days*/
+ uint32 days;
+
+ /**Number of hours*/
+ uint32 hours;
+
+ /**Number of minutes*/
+ uint32 minutes;
+
+ /**number of seconds*/
+ uint32 seconds;
+} CacTime;
+
+
+typedef struct _CACDOMINFO {
+ /**The server role. Should be one of:
+ * ROLE_STANDALONE
+ * ROLE_DOMAIN_MEMBER
+ * ROLE_DOMAIN_BDC
+ * ROLE_DOMAIN_PDC
+ * see include/smb.h
+ */
+ uint32 server_role;
+
+ /**Number of domain users*/
+ uint32 num_users;
+
+ /**Number of domain groups*/
+ uint32 num_domain_groups;
+
+ /**Number of local groups*/
+ uint32 num_local_groups;
+
+ /**Comment*/
+ char *comment;
+
+ /**Domain name*/
+ char *domain_name;
+
+ /**Server name*/
+ char *server_name;
+
+ /**Minimum password length*/
+ uint16 min_pass_length;
+
+ /**How many previous passwords to remember - ie, password cannot be the same as N previous passwords*/
+ uint16 pass_history;
+
+ /**How long (from now) before passwords expire*/
+ CacTime expire;
+
+ /**How long (from now) before passwords can be changed*/
+ CacTime min_pass_age;
+
+ /**How long users are locked out for too many bad password attempts*/
+ CacTime lockout_duration;
+
+ /**How long before lockouts are reset*/
+ CacTime lockout_reset;
+
+ /**How many bad password attempts before lockout occurs*/
+ uint16 num_bad_attempts;
+} CacDomainInfo;
+
+/**@}*/ /*sam_defs*/
+
+/**@addtogroup svc_defs
+ * @{
+ */
+typedef struct _CACSERVICE {
+ /**The service name*/
+ char *service_name;
+
+ /**The display name of the service*/
+ char *display_name;
+
+ /**Current status of the service - see include/rpc_svcctl.h for SERVICE_STATUS definition*/
+ SERVICE_STATUS status;
+} CacService;
+
+typedef struct __CACSERVICECONFIG {
+ /**The service type*/
+ uint32 type;
+
+ /**The start type. Should be one of:
+ * - SVCCTL_BOOT_START
+ * - SVCCTL_SYSTEM_START
+ * - SVCCTL_AUTO_START
+ * - SVCCTL_DEMAND_START
+ */
+ uint32 start_type;
+
+ uint32 error_control;
+
+ /**Path to executable*/
+ char *exe_path;
+
+ /***/
+ char *load_order_group;
+
+ uint32 tag_id;
+
+ /**Any dependencies for the service*/
+ char *dependencies;
+
+ /**Run as...*/
+ char *start_name;
+
+ /**Service display name*/
+ char *display_name;
+
+} CacServiceConfig;
+/**@}*/ /*svc_defs*/
+
+#include "libmsrpc_internal.h"
+
+/**
+ * @addtogroup handle
+ * @{
+ */
+
+/**
+ * Server handle used to keep track of client/server/pipe information. Use cac_NewServerHandle() to allocate.
+ * Initiliaze as many values as possible before calling cac_Connect().
+ *
+ * @note When allocating memory for the fields, use SMB_MALLOC() (or equivalent) instead of talloc() (or equivalent) -
+ * If memory is not allocated for a field, cac_Connect will allocate sizeof(fstring) bytes for it.
+ *
+ * @note It may be wise to allocate large buffers for these fields and strcpy data into them.
+ *
+ * @see cac_NewServerHandle()
+ * @see cac_FreeHandle()
+ */
+typedef struct _CACSERVERHANDLE {
+ /** debug level
+ */
+ int debug;
+
+ /** netbios name used to make connections
+ */
+ char *netbios_name;
+
+ /** domain name used to make connections
+ */
+ char *domain;
+
+ /** username used to make connections
+ */
+ char *username;
+
+ /** user's password plain text string
+ */
+ char *password;
+
+ /** name or IP address of server we are currently working with
+ */
+ char *server;
+
+ /**stores the latest NTSTATUS code
+ */
+ NTSTATUS status;
+
+ /** internal. do not modify!
+ */
+ struct CacServerHandleInternal _internal;
+
+} CacServerHandle;
+
+/*@}*/
+
+/**internal function. do not call this function*/
+SMBCSRV *cac_GetServer(CacServerHandle *hnd);
+
+
+/** @addtogroup Library_Functions
+ * @{
+ */
+/**
+ * Initializes the library - do not need to call this function. Open's smb.conf as well as initializes logging.
+ * @param debug Debug level for library to use
+ */
+
+void cac_Init(int debug);
+
+/**
+ * Creates an un-initialized CacServerHandle
+ * @param allocate_fields If True, the function will allocate sizeof(fstring) bytes for all char * fields in the handle
+ * @return - un-initialized server handle
+ * - NULL if no memory could be allocated
+ */
+CacServerHandle * cac_NewServerHandle(bool allocate_fields);
+
+/**
+ * Specifies the smbc_get_auth_data_fn to use if you do not want to use the default.
+ * @param hnd non-NULL server handle
+ * @param auth_fn auth_data_fn to set in server handle
+ */
+
+void cac_SetAuthDataFn(CacServerHandle *hnd, smbc_get_auth_data_fn auth_fn);
+
+/** Use your own libsmbclient context - not necessary.
+ * @note You must still call cac_Connect() after specifying your own libsmbclient context
+ * @param hnd Initialized, but not connected CacServerHandle
+ * @param ctx The libsmbclient context you would like to use.
+ */
+void cac_SetSmbcContext(CacServerHandle *hnd, SMBCCTX *ctx);
+
+/** Connects to a specified server. If there is already a connection to a different server,
+ * it will be cleaned up before connecting to the new server.
+ * @param hnd Pre-initialized CacServerHandle
+ * @param srv (Optional) Name or IP of the server to connect to. If NULL, server from the CacServerHandle will be used.
+ *
+ * @return CAC_FAILURE if the operation could not be completed successfully (hnd->status will also be set with a NTSTATUS code)
+ * @return CAC_SUCCESS if the operation succeeded
+ */
+int cac_Connect(CacServerHandle *hnd, const char *srv);
+
+
+/**
+ * Cleans up any data used by the CacServerHandle. If the libsmbclient context was set using cac_SetSmbcContext(), it will not be free'd.
+ * @param hnd the CacServerHandle to destroy
+ */
+void cac_FreeHandle(CacServerHandle * hnd);
+
+/**
+ * Initializes a CacTime structure based on an NTTIME structure
+ * If the function fails, then the CacTime structure will be zero'd out
+ */
+void cac_InitCacTime(CacTime *cactime, NTTIME nttime);
+
+/**
+ * Called by cac_NewServerHandle() if allocate_fields = True. You can call this if you want to, allocates sizeof(fstring) char's for every char * field
+ * @param hnd Uninitialized server handle
+ * @return CAC_FAILURE Memory could not be allocated
+ * @return CAC_SUCCESS Memory was allocated
+ */
+int cac_InitHandleMem(CacServerHandle *hnd);
+
+/**
+ * Default smbc_get_auth_data_fn for libmsrpc. This function is called when libmsrpc needs to get more information about the
+ * client (username/password, workgroup).
+ * This function provides simple prompts to the user to enter the information. This description his here so you know how to re-define this function.
+ * @see cac_SetAuthDataFn()
+ * @param pServer Name/IP of the server to connect to.
+ * @param pShare Share name to connect to
+ * @param pWorkgroup libmsrpc passes in the workgroup/domain name from hnd->domain. It can be modified in the function.
+ * @param maxLenWorkgroup The maximum length of a string pWogroup can hold.
+ * @param pUsername libmsrpc passes in the username from hnd->username. It can be modified in the function.
+ * @param maxLenUsername The maximum length of a string pUsername can hold.
+ * @param pPassword libmsrpc pass in the password from hnd->password. It can be modified in the function.
+ * @param maxLenPassword The maximum length of a string pPassword can hold.
+ */
+void cac_GetAuthDataFn(const char * pServer,
+ const char * pShare,
+ char * pWorkgroup,
+ int maxLenWorkgroup,
+ char * pUsername,
+ int maxLenUsername,
+ char * pPassword,
+ int maxLenPassword);
+
+
+/**@}*/
+
+/*****************
+ * LSA Functions *
+ *****************/
+
+/** @addtogroup LSA_Functions
+ * @{
+ */
+
+struct LsaOpenPolicy {
+ /**Inputs*/
+ struct {
+ /**Access Mask. Refer to Security Access Masks in include/rpc_secdes.h*/
+ uint32 access;
+
+ /**Use security quality of service? (True/False)*/
+ bool security_qos;
+ } in;
+
+ /**Outputs*/
+ struct {
+ /**Handle to the open policy (needed for all other operations)*/
+ POLICY_HND *pol;
+ } out;
+};
+
+/**
+ * Opens a policy handle on a remote machine.
+ * @param hnd fully initialized CacServerHandle for remote machine
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE if the policy could not be opened. hnd->status set with appropriate NTSTATUS
+ * @return CAC_SUCCESS if the policy could be opened, the policy handle can be found
+ */
+int cac_LsaOpenPolicy(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaOpenPolicy *op);
+
+
+/**
+ * Closes an LSA policy handle (Retrieved using cac_LsaOpenPolicy).
+ * If successful, the handle will be closed on the server, and memory for pol will be freed
+ * @param hnd - An initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param pol - the policy handle to close
+ * @return CAC_FAILURE could not close the policy handle, hnd->status is set to the appropriate NTSTATUS error code
+ * @return CAC_SUCCESS the policy handle was closed
+ */
+int cac_LsaClosePolicy(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *pol);
+
+
+struct LsaGetNamesFromSids {
+ struct {
+ /**handle to and open LSA policy*/
+ POLICY_HND *pol;
+
+ /**the number of SIDs to lookup*/
+ uint32 num_sids;
+
+ /**array of SIDs to lookup*/
+ DOM_SID *sids;
+ } in;
+
+ struct {
+ /**The number of names returned (in case of CAC_PARTIAL_SUCCESS)*/
+ uint32 num_found;
+
+ /**array of SID info each index is one sid */
+ CacSidInfo *sids;
+
+ /**in case of partial success, an array of SIDs that could not be looked up (NULL if all sids were looked up)*/
+ DOM_SID *unknown;
+ } out;
+};
+
+/**
+ * Looks up the names for a list of SIDS
+ * @param hnd initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op input and output parameters
+ * @return CAC_FAILURE none of the SIDs could be looked up hnd->status is set with appropriate NTSTATUS error code
+ * @return CAC_SUCCESS all of the SIDs were translated and a list of names has been output
+ * @return CAC_PARTIAL_SUCCESS not all of the SIDs were translated, as a result the number of returned names is less than the original list of SIDs
+ */
+int cac_LsaGetNamesFromSids(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaGetNamesFromSids *op);
+
+struct LsaGetSidsFromNames {
+ struct {
+ /**handle to an open LSA policy*/
+ POLICY_HND *pol;
+
+ /**number of SIDs to lookup*/
+ uint32 num_names;
+
+ /**array of strings listing the names*/
+ char **names;
+ } in;
+
+ struct {
+ /**The number of SIDs returned (in case of partial success*/
+ uint32 num_found;
+
+ /**array of SID info for the looked up names*/
+ CacSidInfo *sids;
+
+ /**in case of partial success, the names that were not looked up*/
+ char **unknown;
+ } out;
+};
+
+/**
+ * Looks up the SIDs for a list of names
+ * @param hnd initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op input and output parameters
+ * @return CAC_FAILURE none of the SIDs could be looked up hnd->status is set with appropriate NTSTATUS error code
+ * @return CAC_SUCCESS all of the SIDs were translated and a list of names has been output
+ * @return CAC_PARTIAL_SUCCESS not all of the SIDs were translated, as a result the number of returned names is less than the original list of SIDs
+ */
+int cac_LsaGetSidsFromNames(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaGetSidsFromNames *op);
+
+struct LsaFetchSid {
+ struct {
+ /**handle to an open LSA policy*/
+ POLICY_HND *pol;
+
+ /**can be CAC_LOCAL_INFO, CAC_DOMAIN_INFO, or (CAC_LOCAL_INFO | CAC_DOMAIN_INFO)*/
+ uint16 info_class;
+ } in;
+
+ struct {
+ /**the machine's local SID and domain name (NULL if not asked for)*/
+ CacSidInfo *local_sid;
+
+ /**the machine's domain SID and name (NULL if not asked for)*/
+ CacSidInfo *domain_sid;
+
+ } out;
+};
+
+/**
+ * Looks up the domain or local sid of a machine with an open LSA policy handle
+ * @param hnd initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op input and output parameters
+ * @return CAC_FAILURE if the SID could not be fetched
+ * @return CAC_SUCCESS if the SID was fetched
+ * @return CAC_PARTIAL_SUCCESS if you asked for both local and domain sids but only one was returned
+ */
+int cac_LsaFetchSid(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaFetchSid *op);
+
+struct LsaQueryInfoPolicy {
+ struct {
+ /**Open LSA policy handle on remote server*/
+ POLICY_HND *pol;
+ } in;
+
+ struct {
+ /**remote server's domain name*/
+ char *domain_name;
+
+ /**remote server's dns name*/
+ char *dns_name;
+
+ /**remote server's forest name*/
+ char *forest_name;
+
+ /**remote server's domain guid*/
+ struct GUID *domain_guid;
+
+ /**remote server's domain SID*/
+ DOM_SID *domain_sid;
+ } out;
+};
+
+/**
+ * Retrieves information about the LSA machine/domain
+ * @param hnd initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op input and output parameters
+ * Note: for pre-Windows 2000 machines, only op->out.SID and op->out.domain will be set. @see cac_LsaFetchSid
+ * @return - CAC_FAILURE if the operation was not successful. hnd->status will be set with an accurate NT_STATUS code
+ * @return CAC_SUCCESS the operation was successful.
+ */
+int cac_LsaQueryInfoPolicy(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaQueryInfoPolicy *op);
+
+struct LsaEnumSids {
+ struct {
+ /**Open LSA Policy handle*/
+ POLICY_HND *pol;
+
+ /**The prefered maximum number of SIDs returned per call*/
+ uint32 pref_max_sids;
+ } in;
+
+ struct {
+ /**used to keep track of how many sids have been retrieved over multiple calls
+ * should be set to zero via ZERO_STRUCT() befrore the first call. Use the same struct LsaEnumSids for multiple calls*/
+ uint32 resume_idx;
+
+ /**The number of sids returned this call*/
+ uint32 num_sids;
+
+ /**Array of sids returned*/
+ DOM_SID *sids;
+
+ } out;
+};
+
+/**
+ * Enumerates the SIDs in the LSA. Can be enumerated in blocks by calling the function multiple times.
+ * Example: while(cac_LsaEnumSids(hnd, mem_ctx, op) { ... }
+ * @param hnd - An initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE there was an error during operations OR there are no more results
+ * @return CAC_SUCCESS the operation completed and results were returned
+ */
+int cac_LsaEnumSids(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaEnumSids *op);
+
+struct LsaEnumAccountRights {
+ struct {
+ /**Open LSA Policy handle*/
+ POLICY_HND *pol;
+
+ /**(Optional) SID of the account - must supply either sid or name*/
+ DOM_SID *sid;
+
+ /**(Optional) name of the account - must supply either sid or name*/
+ char *name;
+ } in;
+
+ struct {
+ /**Count of rights for this account*/
+ uint32 num_privs;
+
+ /**array of privilege names*/
+ char **priv_names;
+ } out;
+};
+
+/**
+ * Enumerates rights assigned to a given account. Takes a SID instead of account handle as input
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE the rights could not be retrieved. hnd->status is set with NT_STATUS code
+ * @return CAC_SUCCESS the operation was successful.
+ */
+
+int cac_LsaEnumAccountRights(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaEnumAccountRights *op);
+
+struct LsaEnumTrustedDomains {
+ struct {
+ /**Open LSA policy handle*/
+ POLICY_HND *pol;
+ } in;
+
+ struct {
+ /**used to keep track of how many domains have been retrieved over multiple calls
+ * should be set to zero via ZERO_STRUCT() before the first call. Use the same struct LsaEnumSids for multiple calls*/
+ uint32 resume_idx;
+
+ /**The number of domains returned by the remote server this call*/
+ uint32 num_domains;
+
+ /**array of trusted domain names returned by the remote server*/
+ char **domain_names;
+
+ /**array of trusted domain sids returned by the remote server*/
+ DOM_SID *domain_sids;
+ } out;
+};
+
+/**
+ * Enumerates the trusted domains in the LSA.
+ * @param hnd - An initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op - initialized parameters
+ * @return CAC_FAILURE there was an error during operations OR there are no more results
+ * @return CAC_SUCCESS the operation completed and results were returned
+ */
+int cac_LsaEnumTrustedDomains(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaEnumTrustedDomains *op);
+
+struct LsaOpenTrustedDomain {
+ struct {
+ /**an open LSA policy handle*/
+ POLICY_HND *pol;
+
+ /**SID of the trusted domain to open*/
+ DOM_SID *domain_sid;
+
+ /**Desired access on the open domain*/
+ uint32 access;
+ } in;
+
+ struct {
+ /**A handle to the policy that is opened*/
+ POLICY_HND *domain_pol;
+ } out;
+};
+
+/**
+ * Opens a trusted domain by SID.
+ * @param hnd An initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op initialized I/O parameters
+ * @return CAC_FAILURE a handle to the domain could not be opened. hnd->status is set with approriate NT_STATUS code
+ * @return CAC_SUCCESS the domain was opened successfully
+ */
+int cac_LsaOpenTrustedDomain(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaOpenTrustedDomain *op);
+
+struct LsaQueryTrustedDomainInfo {
+ struct {
+ /**Open LSA policy handle*/
+ POLICY_HND *pol;
+
+ /**Info class of returned data*/
+ uint16 info_class;
+
+ /**(Optional)SID of trusted domain to query (must specify either SID or name of trusted domain)*/
+ DOM_SID *domain_sid;
+
+ /**(Optional)Name of trusted domain to query (must specify either SID or name of trusted domain)*/
+ char *domain_name;
+ } in;
+
+ struct {
+ /**information about the trusted domain*/
+ LSA_TRUSTED_DOMAIN_INFO *info;
+ } out;
+};
+
+/**
+ * Retrieves information a trusted domain.
+ * @param hnd An initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op initialized I/O parameters
+ * @return CAC_FAILURE a handle to the domain could not be opened. hnd->status is set with approriate NT_STATUS code
+ * @return CAC_SUCCESS the domain was opened successfully
+ */
+
+int cac_LsaQueryTrustedDomainInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaQueryTrustedDomainInfo *op);
+
+struct LsaEnumPrivileges {
+ struct {
+ /**An open LSA policy handle*/
+ POLICY_HND *pol;
+
+ /**The _preferred_ maxinum number of privileges returned per call*/
+ uint32 pref_max_privs;
+ } in;
+
+ struct {
+ /**Used to keep track of how many privileges have been retrieved over multiple calls. Do not modify this value between calls*/
+ uint32 resume_idx;
+
+ /**The number of privileges returned this call*/
+ uint32 num_privs;
+
+ /**Array of privilege names*/
+ char **priv_names;
+
+ /**Array of high bits for privilege LUID*/
+ uint32 *high_bits;
+
+ /**Array of low bits for privilege LUID*/
+ uint32 *low_bits;
+ } out;
+};
+
+/**
+ * Enumerates the Privileges supported by the LSA. Can be enumerated in blocks by calling the function multiple times.
+ * Example: while(cac_LsaEnumPrivileges(hnd, mem_ctx, op) { ... }
+ * @param hnd An initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE there was an error during operations OR there are no more results
+ * @return CAC_SUCCESS the operation completed and results were returned
+ * @see CAC_OP_FAILED()
+ */
+int cac_LsaEnumPrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaEnumPrivileges *op);
+
+struct LsaOpenAccount {
+ struct {
+ /**An open LSA policy handle*/
+ POLICY_HND *pol;
+
+ /**(Optional) account SID - must supply either sid or name*/
+ DOM_SID *sid;
+
+ /**(Optional) account name - must supply either sid or name*/
+ char *name;
+
+ /**desired access for the handle*/
+ uint32 access;
+ } in;
+
+ struct {
+ /**A handle to the opened user*/
+ POLICY_HND *user;
+ } out;
+};
+
+/**
+ * Opens a handle to an account in the LSA
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE the account could not be opened. hnd->status has appropriate NT_STATUS code
+ * @return CAC_SUCCESS the account was opened
+ */
+int cac_LsaOpenAccount(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaOpenAccount *op);
+
+struct LsaAddPrivileges {
+ struct {
+ /**An open LSA policy handle*/
+ POLICY_HND *pol;
+
+ /**(Optional) The user's SID (must specify at least sid or name)*/
+ DOM_SID *sid;
+
+ /**(Optional) The user's name (must specify at least sid or name)*/
+ char *name;
+
+ /**The privilege names of the privileges to add for the account*/
+ char **priv_names;
+
+ /**The number of privileges in the priv_names array*/
+ uint32 num_privs;
+
+ } in;
+};
+
+/**
+ * Adds Privileges an account.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE the privileges could not be set. hnd->status has appropriate NT_STATUS code
+ * @return CAC_SUCCESS the privileges were set.
+ */
+int cac_LsaAddPrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaAddPrivileges *op);
+
+struct LsaRemovePrivileges {
+ struct {
+ /**An open handle to the LSA*/
+ POLICY_HND *pol;
+
+ /**(Optional) The account SID (must specify at least sid or name)*/
+ DOM_SID *sid;
+
+ /**(Optional) The account name (must specify at least sid or name)*/
+ char *name;
+
+ /**The privilege names of the privileges to remove from the account*/
+ char **priv_names;
+
+ /**The number of privileges in the priv_names array*/
+ uint32 num_privs;
+
+ } in;
+
+};
+
+/**
+ * Removes a _specific_ set of privileges from an account
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE the privileges could not be removed. hnd->status is set with NT_STATUS code
+ * @return CAC_SUCCESS the privileges were removed
+ */
+int cac_LsaRemovePrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaRemovePrivileges *op);
+
+struct LsaClearPrivileges {
+ struct {
+ /**An open handle to the LSA*/
+ POLICY_HND *pol;
+
+ /**(Optional) The user's SID (must specify at least sid or name)*/
+ DOM_SID *sid;
+
+ /**(Optional) The user's name (must specify at least sid or name)*/
+ char *name;
+ } in;
+
+};
+
+/**
+ * Removes ALL privileges from an account
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE the operation was not successful, hnd->status set with NT_STATUS code
+ * @return CAC_SUCCESS the opeartion was successful.
+ */
+int cac_LsaClearPrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaClearPrivileges *op);
+
+/**
+ * Sets an accounts priviliges. Removes all privileges and then adds specified privileges.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE The operation could not complete successfully
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_LsaSetPrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaAddPrivileges *op);
+
+struct LsaGetSecurityObject {
+ struct {
+ /**Open LSA policy handle*/
+ POLICY_HND *pol;
+ } in;
+
+ struct {
+ /**Returned security descriptor information*/
+ SEC_DESC_BUF *sec;
+ } out;
+};
+
+/**
+ * Retrieves Security Descriptor information about the LSA
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE The operation could not complete successfully
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_LsaGetSecurityObject(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaGetSecurityObject *op);
+
+
+/**@}*/ /*LSA_Functions*/
+
+/**********************
+ * Registry Functions *
+ *********************/
+
+/**@addtogroup Reg_Functions
+ * @{
+ */
+
+struct RegConnect {
+ struct {
+ /** must be one of :
+ * HKEY_CLASSES_ROOT,
+ * HKEY_LOCAL_MACHINE,
+ * HKEY_USERS,
+ * HKEY_PERFORMANCE_DATA,
+ */
+ int root;
+
+ /**desired access on the root key
+ * combination of:
+ * REG_KEY_READ,
+ * REG_KEY_WRITE,
+ * REG_KEY_EXECUTE,
+ * REG_KEY_ALL,
+ * found in include/rpc_secdes.h*/
+ uint32 access;
+ } in;
+
+ struct {
+ POLICY_HND *key;
+ } out;
+};
+
+/**
+ * Opens a handle to the registry on the server
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegConnect(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegConnect *op);
+
+/**
+ * Closes an open registry handle
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param key The Key/Handle to close
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegClose(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *key);
+
+struct RegOpenKey {
+ struct {
+ /**(Optional)parent key.
+ * If this is NULL, then cac_RegOpenKey() will attempt to connect to the registry, name MUST start with something like:<br>
+ * HKEY_LOCAL_MACHINE\ or an abbreviation like HKCR\
+ *
+ * supported root names:
+ * - HKEY_LOCAL_MACHINE\ or HKLM\
+ * - HKEY_CLASSES_ROOT\ or HKCR\
+ * - HKEY_USERS\ or HKU\
+ * - HKEY_PERFORMANCE_DATA or HKPD\
+ */
+ POLICY_HND *parent_key;
+
+ /**name/path of key*/
+ char *name;
+
+ /**desired access on this key*/
+ uint32 access;
+ } in;
+
+ struct {
+ POLICY_HND *key;
+ } out;
+};
+
+/**
+ * Opens a registry key
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_RegOpenKey(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegOpenKey *op);
+
+struct RegEnumKeys {
+ struct {
+ /**enumerate subkeys of this key*/
+ POLICY_HND *key;
+
+ /**maximum number of keys to enumerate each call*/
+ uint32 max_keys;
+ } in;
+
+ struct {
+ /**keeps track of the index to resume enumerating*/
+ uint32 resume_idx;
+
+ /**the number of keys returned this call*/
+ uint32 num_keys;
+
+ /**array of key names*/
+ char **key_names;
+
+ /**class names of the keys*/
+ char **class_names;
+
+ /**last modification time of the key*/
+ time_t *mod_times;
+ } out;
+};
+
+/**
+ * Enumerates Subkeys of a given key. Can be run in a loop. Example: while(cac_RegEnumKeys(hnd, mem_ctx, op)) { ... }
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @see CAC_OP_FAILED()
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegEnumKeys(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegEnumKeys *op);
+
+
+struct RegCreateKey {
+ struct {
+ /**create a subkey of parent_key*/
+ POLICY_HND *parent_key;
+
+ /**name of the key to create*/
+ char *key_name;
+
+ /**class of the key*/
+ char *class_name;
+
+ /**Access mask to open the key with. See REG_KEY_* in include/rpc_secdes.h*/
+ uint32 access;
+ } in;
+
+ struct {
+ /**Open handle to the key*/
+ POLICY_HND *key;
+ } out;
+};
+
+/**
+ * Creates a registry key, if the key already exists, it will be opened __Creating keys is not currently working__.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parmeters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegCreateKey(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegCreateKey *op);
+
+struct RegDeleteKey {
+ struct {
+ /**handle to open registry key*/
+ POLICY_HND *parent_key;
+
+ /**name of the key to delete*/
+ char *name;
+
+ /**delete recursively. WARNING: this might not always work as planned*/
+ bool recursive;
+ } in;
+
+};
+
+/**
+ * Deletes a subkey of an open key. Note: if you run this with op->in.recursive == True, and the operation fails, it may leave the key in an inconsistent state.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_RegDeleteKey(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegDeleteKey *op);
+
+struct RegDeleteValue {
+ struct {
+ /**handle to open registry key*/
+ POLICY_HND *parent_key;
+
+ /**name of the value to delete*/
+ char *name;
+ } in;
+};
+
+/**
+ * Deletes a registry value.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegDeleteValue(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegDeleteValue *op);
+
+struct RegQueryKeyInfo {
+ struct {
+ /**Open handle to the key to query*/
+ POLICY_HND *key;
+ } in;
+
+ struct {
+ /**name of the key class*/
+ char *class_name;
+
+ /**number of subkeys of the key*/
+ uint32 num_subkeys;
+
+ /**length (in characters) of the longest subkey name*/
+ uint32 longest_subkey;
+
+ /**length (in characters) of the longest class name*/
+ uint32 longest_class;
+
+ /**number of values in this key*/
+ uint32 num_values;
+
+ /**length (in characters) of the longest value name*/
+ uint32 longest_value_name;
+
+ /**length (in bytes) of the biggest value data*/
+ uint32 longest_value_data;
+
+ /**size (in bytes) of the security descriptor*/
+ uint32 security_desc_size;
+
+ /**time of the last write*/
+ time_t last_write_time;
+ } out;
+};
+
+/**
+ * Retrieves information about an open key
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_RegQueryKeyInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegQueryKeyInfo *op);
+
+struct RegSaveKey {
+ struct {
+ /**Open key to be saved*/
+ POLICY_HND *key;
+
+ /**The path (on the remote computer) to save the file to*/
+ char *filename;
+ } in;
+};
+
+/**
+ * Saves a key to a file on the remote machine __Not currently working__.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_RegSaveKey(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegSaveKey *op);
+
+struct RegQueryValue {
+ struct {
+ /**handle to open registry key*/
+ POLICY_HND *key;
+
+ /**name of the value to query*/
+ char *val_name;
+ } in;
+
+ struct {
+ /**Value type.
+ * One of:
+ * - REG_DWORD (equivalent to REG_DWORD_LE)
+ * - REG_DWORD_BE
+ * - REG_SZ
+ * - REG_EXPAND_SZ
+ * - REG_MULTI_SZ
+ * - REG_BINARY
+ */
+ uint32 type;
+
+ /**The value*/
+ REG_VALUE_DATA *data;
+ } out;
+};
+
+/**
+ * Retrieves a value (type and data) _not currently working_.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_RegQueryValue(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegQueryValue *op);
+
+struct RegEnumValues {
+ struct {
+ /**handle to open key*/
+ POLICY_HND *key;
+
+ /**max number of values returned per call*/
+ uint32 max_values;
+
+ } in;
+
+ struct {
+ /**keeps track of the index to resume from - used over multiple calls*/
+ uint32 resume_idx;
+
+ /**the number of values that were returned this call*/
+ uint32 num_values;
+
+ /**Array of value types. A type can be one of:
+ * - REG_DWORD (equivalent to REG_DWORD_LE)
+ * - REG_DWORD_BE
+ * - REG_SZ
+ * - REG_EXPAND_SZ
+ * - REG_MULTI_SZ
+ * - REG_BINARY
+ */
+ uint32 *types;
+
+ /**array of strings storing the names of the values*/
+ char **value_names;
+
+ /**array of pointers to the value data returned*/
+ REG_VALUE_DATA **values;
+ } out;
+};
+
+/**
+ * Enumerates a number of Registry values in an open registry key.
+ * Can be run in a loop. Example: while(cac_RegEnumValues(hnd, mem_ctx, op)) { ... }
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @see CAC_OP_FAILED()
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegEnumValues(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegEnumValues *op);
+
+struct RegSetValue {
+ struct {
+ /**Handle to open registry key*/
+ POLICY_HND *key;
+
+ /**Name of the value*/
+ char *val_name;
+
+ /**Value type.
+ * One of:
+ * - REG_DWORD (equivalent to REG_DWORD_LE)
+ * - REG_DWORD_BE
+ * - REG_SZ
+ * - REG_EXPAND_SZ
+ * - REG_MULTI_SZ
+ * - REG_BINARY
+ */
+ uint32 type;
+
+ /**the value*/
+ REG_VALUE_DATA value;
+ } in;
+};
+
+/**
+ * Sets or creates value (type and data).
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegSetValue(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegSetValue *op);
+
+struct RegGetVersion {
+ struct {
+ /**open registry key*/
+ POLICY_HND *key;
+ } in;
+
+ struct {
+ /**version number*/
+ uint32 version;
+ } out;
+};
+
+/**
+ * Retrieves the registry version number
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegGetVersion(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegGetVersion *op);
+
+struct RegGetKeySecurity {
+ struct {
+ /**Handle to key to query*/
+ POLICY_HND *key;
+
+ /**Info that you want. Should be a combination of (1 or more or'd):
+ * - OWNER_SECURITY_INFORMATION
+ * - GROUP_SECURITY_INFORMATION
+ * - DACL_SECURITY_INFORMATION
+ * - SACL_SECURITY_INFORMATION
+ * - UNPROTECTED_SACL_SECURITY_INFORMATION
+ * - UNPROTECTED_DACL_SECURITY_INFORMATION
+ * - PROTECTED_SACL_SECURITY_INFORMATION
+ * - PROTECTED_DACL_SECURITY_INFORMATION
+ *
+ * or use:
+ * - ALL_SECURITY_INFORMATION
+ *
+ * all definitions from include/rpc_secdes.h
+ */
+ uint32 info_type;
+ } in;
+
+ struct {
+ /**size of the data returned*/
+ uint32 size;
+
+ /**Security descriptor*/
+ SEC_DESC *descriptor;
+ } out;
+};
+
+/**
+ * Retrieves a key security descriptor.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_RegGetKeySecurity(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegGetKeySecurity *op);
+
+struct RegSetKeySecurity {
+ struct {
+ /**Handle to key to query*/
+ POLICY_HND *key;
+
+ /**Info that you want. Should be a combination of (1 or more or'd):
+ * - OWNER_SECURITY_INFORMATION
+ * - GROUP_SECURITY_INFORMATION
+ * - DACL_SECURITY_INFORMATION
+ * - SACL_SECURITY_INFORMATION
+ * - UNPROTECTED_SACL_SECURITY_INFORMATION
+ * - UNPROTECTED_DACL_SECURITY_INFORMATION
+ * - PROTECTED_SACL_SECURITY_INFORMATION
+ * - PROTECTED_DACL_SECURITY_INFORMATION
+ *
+ * or use:
+ * - ALL_SECURITY_INFORMATION
+ *
+ * all definitions from include/rpc_secdes.h
+ */
+ uint32 info_type;
+
+ /**size of the descriptor*/
+ size_t size;
+
+ /**Security descriptor*/
+ SEC_DESC *descriptor;
+ } in;
+};
+
+/**
+ * Sets the key security descriptor.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegSetKeySecurity(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegSetKeySecurity *op);
+
+/**@}*/ /*Reg_Functions*/
+
+struct Shutdown {
+ struct {
+ /**the message to display (can be NULL)*/
+ char *message;
+
+ /**timeout in seconds*/
+ uint32 timeout;
+
+ /**False = shutdown, True = reboot*/
+ bool reboot;
+
+ /**force the*/
+ bool force;
+
+ /*FIXME: make this useful*/
+ uint32 reason;
+ } in;
+};
+
+
+/**
+ * Shutdown the server _not currently working_.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_Shutdown(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct Shutdown *op);
+
+/**
+ * Attempt to abort initiated shutdown on the server _not currently working_.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_AbortShutdown(CacServerHandle *hnd, TALLOC_CTX *mem_ctx);
+
+/*****************
+ * SAM Functions *
+ *****************/
+
+/**@addtogroup SAM_Functions
+ * @{
+ */
+struct SamConnect {
+ struct {
+ /**Access mask to open with
+ * see generic access masks in include/smb.h*/
+ uint32 access;
+ } in;
+
+ struct {
+ POLICY_HND *sam;
+ } out;
+};
+
+/**
+ * Connects to the SAM. This can be skipped by just calling cac_SamOpenDomain()
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_SamConnect(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamConnect *op);
+
+
+/**
+ * Closes any (SAM, domain, user, group, etc.) SAM handle.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param sam Handle to close
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_SamClose(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *sam);
+
+struct SamOpenDomain {
+ struct {
+ /**The desired access. See generic access masks - include/smb.h*/
+ uint32 access;
+
+ /**(Optional) An open handle to the SAM. If it is NULL, the function will connect to the SAM with the access mask above*/
+ POLICY_HND *sam;
+
+ /**(Optional) The SID of the domain to open.
+ * If this this is NULL, the function will attempt to open the domain specified in hnd->domain */
+ DOM_SID *sid;
+ } in;
+
+ struct {
+ /**handle to the open domain*/
+ POLICY_HND *dom_hnd;
+
+ /**Handle to the open SAM*/
+ POLICY_HND *sam;
+ } out;
+};
+
+/**
+ * Opens a handle to a domain. This must be called before any other SAM functions
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamOpenDomain(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamOpenDomain *op);
+
+struct SamCreateUser {
+ struct {
+ /**Open domain handle*/
+ POLICY_HND *dom_hnd;
+
+ /**Username*/
+ char *name;
+
+ /**See Allowable account control bits in include/smb.h*/
+ uint32 acb_mask;
+ } in;
+
+ struct {
+ /**handle to the user*/
+ POLICY_HND *user_hnd;
+
+ /**rid of the user*/
+ uint32 rid;
+ } out;
+};
+
+/**
+ * Creates a new domain user, if the account already exists it will _not_ be opened and hnd->status will be NT_STATUS_USER_EXISTS
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_SamCreateUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamCreateUser *op);
+
+struct SamOpenUser {
+ struct {
+ /**Handle to open SAM connection*/
+ POLICY_HND *dom_hnd;
+
+ /**desired access - see generic access masks in include/smb.h*/
+ uint32 access;
+
+ /**RID of the user*/
+ uint32 rid;
+
+ /**(Optional) name of the user - must supply either RID or user name*/
+ char *name;
+ } in;
+
+ struct {
+ /**Handle to the user*/
+ POLICY_HND *user_hnd;
+ } out;
+};
+
+/**
+ * Opens a domain user.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamOpenUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamOpenUser *op);
+
+/**
+ * Deletes a domain user.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param user_hnd Open handle to the user
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamDeleteUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *user_hnd);
+
+
+struct SamEnumUsers {
+ struct {
+ /**Open handle to a domain*/
+ POLICY_HND *dom_hnd;
+
+ /**Enumerate users with specific ACB. If 0, all users will be enumerated*/
+ uint32 acb_mask;
+ } in;
+
+ struct {
+ /**where to resume from. Used over multiple calls*/
+ uint32 resume_idx;
+
+ /**the number of users returned this call*/
+ uint32 num_users;
+
+ /**Array storing the rids of the returned users*/
+ uint32 *rids;
+
+ /**Array storing the names of all the users returned*/
+ char **names;
+
+ bool done;
+ } out;
+};
+
+/**
+ * Enumerates domain users. Can be used as a loop condition. Example: while(cac_SamEnumUsers(hnd, mem_ctx, op)) { ... }
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamEnumUsers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamEnumUsers *op);
+
+struct SamGetNamesFromRids {
+ struct {
+ /**An open handle to the domain SAM from cac_SamOpenDomain()*/
+ POLICY_HND *dom_hnd;
+
+ /**Number of RIDs to resolve*/
+ uint32 num_rids;
+
+ /**Array of RIDs to resolve*/
+ uint32 *rids;
+ } in;
+
+ struct {
+ /**the number of names returned - if this is 0, the map is NULL*/
+ uint32 num_names;
+
+ /**array contiaing the Names and RIDs*/
+ CacLookupRidsRecord *map;
+ } out;
+};
+
+/**
+ * Returns a list of names which map to a list of RIDs.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetNamesFromRids(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetNamesFromRids *op);
+
+struct SamGetRidsFromNames {
+ struct {
+ /**An open handle to the domain SAM from cac_SamOpenDomain()*/
+ POLICY_HND *dom_hnd;
+
+ /**Number of names to resolve*/
+ uint32 num_names;
+
+ /**Array of names to resolve*/
+ char **names;
+ } in;
+
+ struct {
+ /**the number of names returned - if this is 0, then map is NULL*/
+ uint32 num_rids;
+
+ /**array contiaing the Names and RIDs*/
+ CacLookupRidsRecord *map;
+ } out;
+};
+
+/**
+ * Returns a list of RIDs which map to a list of names.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetRidsFromNames(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetRidsFromNames *op);
+
+struct SamGetGroupsForUser {
+ struct {
+ /**An open handle to the user*/
+ POLICY_HND *user_hnd;
+ } in;
+
+ struct {
+ /**The number of groups the user is a member of*/
+ uint32 num_groups;
+
+ /**The RIDs of the groups*/
+ uint32 *rids;
+
+ /**The attributes of the groups*/
+ uint32 *attributes;
+ } out;
+};
+/**
+ * Retrieves a list of groups that a user is a member of.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetGroupsForUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetGroupsForUser *op);
+
+struct SamOpenGroup {
+ struct {
+ /**Open handle to the domain SAM*/
+ POLICY_HND *dom_hnd;
+
+ /**Desired access to open the group with. See Generic access masks in include/smb.h*/
+ uint32 access;
+
+ /**rid of the group*/
+ uint32 rid;
+ } in;
+
+ struct {
+ /**Handle to the group*/
+ POLICY_HND *group_hnd;
+ } out;
+};
+
+/**
+ * Opens a domain group.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamOpenGroup(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamOpenGroup *op);
+
+struct SamCreateGroup {
+ struct {
+ /**Open handle to the domain SAM*/
+ POLICY_HND *dom_hnd;
+
+ /**Desired access to open the group with. See Generic access masks in include/smb.h*/
+ uint32 access;
+
+ /**The name of the group*/
+ char *name;
+ } in;
+
+ struct {
+ /**Handle to the group*/
+ POLICY_HND *group_hnd;
+ } out;
+};
+
+/**
+ * Creates a group. If the group already exists it will not be opened.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamCreateGroup(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamCreateGroup *op);
+
+/**
+ * Deletes a domain group.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param group_hnd Open handle to the group.
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamDeleteGroup(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *group_hnd);
+
+struct SamGetGroupMembers {
+ struct {
+ /**Open handle to a group*/
+ POLICY_HND *group_hnd;
+ } in;
+
+ struct {
+ /**The number of members in the group*/
+ uint32 num_members;
+
+ /**An array storing the RIDs of the users*/
+ uint32 *rids;
+
+ /**The attributes*/
+ uint32 *attributes;
+ } out;
+};
+
+/**
+ * Retrives a list of users in a group.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetGroupMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetGroupMembers *op);
+
+struct SamAddGroupMember {
+ struct {
+ /**Open handle to a group*/
+ POLICY_HND *group_hnd;
+
+ /**RID of new member*/
+ uint32 rid;
+ } in;
+};
+
+/**
+ * Adds a user to a group.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamAddGroupMember(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamAddGroupMember *op);
+
+struct SamRemoveGroupMember {
+ struct {
+ /**Open handle to a group*/
+ POLICY_HND *group_hnd;
+
+ /**RID of member to remove*/
+ uint32 rid;
+ } in;
+};
+
+/**
+ * Removes a user from a group.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamRemoveGroupMember(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamRemoveGroupMember *op);
+
+/**
+ * Removes all the members of a group - warning: if this function fails is is possible that some but not all members were removed
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param group_hnd Open handle to the group to clear
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamClearGroupMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *group_hnd);
+
+struct SamSetGroupMembers {
+ struct {
+ /**Open handle to the group*/
+ POLICY_HND *group_hnd;
+
+ /**Number of members in the group - if this is 0, all members of the group will be removed*/
+ uint32 num_members;
+
+ /**The RIDs of the users to add*/
+ uint32 *rids;
+ } in;
+};
+
+/**
+ * Clears the members of a group and adds a list of members to the group
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamSetGroupMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetGroupMembers *op);
+
+struct SamEnumGroups {
+ struct {
+ /**Open handle to a domain*/
+ POLICY_HND *dom_hnd;
+ } in;
+
+ struct {
+ /**Where to resume from _do not_ modify this value. Used over multiple calls.*/
+ uint32 resume_idx;
+
+ /**the number of users returned this call*/
+ uint32 num_groups;
+
+ /**Array storing the rids of the returned groups*/
+ uint32 *rids;
+
+ /**Array storing the names of all the groups returned*/
+ char **names;
+
+ /**Array storing the descriptions of all the groups returned*/
+ char **descriptions;
+
+ bool done;
+ } out;
+};
+
+/**
+ * Enumerates domain groups. Can be used as a loop condition. Example: while(cac_SamEnumGroups(hnd, mem_ctx, op)) { ... }
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamEnumGroups(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamEnumGroups *op);
+
+struct SamEnumAliases {
+ struct {
+ /**Open handle to a domain*/
+ POLICY_HND *dom_hnd;
+ } in;
+
+ struct {
+ /**where to resume from. Used over multiple calls*/
+ uint32 resume_idx;
+
+ /**the number of users returned this call*/
+ uint32 num_aliases;
+
+ /**Array storing the rids of the returned groups*/
+ uint32 *rids;
+
+ /**Array storing the names of all the groups returned*/
+ char **names;
+
+ /**Array storing the descriptions of all the groups returned*/
+ char **descriptions;
+
+ bool done;
+ } out;
+};
+
+/**
+ * Enumerates domain aliases. Can be used as a loop condition. Example: while(cac_SamEnumAliases(hnd, mem_ctx, op)) { ... }
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamEnumAliases(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamEnumAliases *op);
+
+struct SamCreateAlias {
+ struct {
+ /**Open handle to the domain SAM*/
+ POLICY_HND *dom_hnd;
+
+ /**The name of the alias*/
+ char *name;
+ } in;
+
+ struct {
+ /**Handle to the group*/
+ POLICY_HND *alias_hnd;
+ } out;
+};
+
+/**
+ * Creates an alias. If the alias already exists it will not be opened.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_SamCreateAlias(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamCreateAlias *op);
+
+struct SamOpenAlias {
+ struct {
+ /**Open handle to the domain SAM*/
+ POLICY_HND *dom_hnd;
+
+ /**Desired access to open the group with. See Generic access masks in include/smb.h*/
+ uint32 access;
+
+ /**rid of the alias*/
+ uint32 rid;
+ } in;
+
+ struct {
+ /**Handle to the alias*/
+ POLICY_HND *alias_hnd;
+ } out;
+};
+
+/**
+ * Opens a handle to an alias.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamOpenAlias(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamOpenAlias *op);
+
+/**
+ * Deletes an alias.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param alias_hnd Open handle to the alias
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamDeleteAlias(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *alias_hnd);
+
+struct SamAddAliasMember {
+ struct {
+ /**Open handle to a alias*/
+ POLICY_HND *alias_hnd;
+
+ /**SID of new member*/
+ DOM_SID *sid;
+ } in;
+};
+
+/**
+ * Adds an account to an alias.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamAddAliasMember(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamAddAliasMember *op);
+
+struct SamRemoveAliasMember {
+ struct {
+ /**Open handle to the alias*/
+ POLICY_HND *alias_hnd;
+
+ /**The SID of the member*/
+ DOM_SID *sid;
+ } in;
+};
+
+/**
+ * Removes an account from an alias.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamRemoveAliasMember(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamRemoveAliasMember *op);
+
+struct SamGetAliasMembers {
+ struct {
+ /**Open handle to the alias*/
+ POLICY_HND *alias_hnd;
+ } in;
+
+ struct {
+ /**The number of members*/
+ uint32 num_members;
+
+ /**An array storing the SIDs of the accounts*/
+ DOM_SID *sids;
+ } out;
+};
+
+/**
+ * Retrieves a list of all accounts in an alias.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetAliasMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetAliasMembers *op);
+
+/**
+ * Removes all the members of an alias - warning: if this function fails is is possible that some but not all members were removed
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param alias_hnd Handle to the alias to clear
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_SamClearAliasMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *alias_hnd);
+
+struct SamSetAliasMembers {
+ struct {
+ /**Open handle to the group*/
+ POLICY_HND *alias_hnd;
+
+ /**Number of members in the group - if this is 0, all members of the group will be removed*/
+ uint32 num_members;
+
+ /**The SIDs of the accounts to add*/
+ DOM_SID *sids;
+ } in;
+};
+
+/**
+ * Clears the members of an alias and adds a list of members to the alias
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamSetAliasMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetAliasMembers *op);
+
+
+struct SamUserChangePasswd {
+ struct {
+ /**The username*/
+ char *username;
+
+ /**The current password*/
+ char *password;
+
+ /**The new password*/
+ char *new_password;
+ } in;
+};
+/**Used by a user to change their password*/
+int cac_SamUserChangePasswd(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamUserChangePasswd *op);
+
+/**
+ * Enables a user
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param user_hnd Open handle to the user to enable
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamEnableUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *user_hnd);
+
+/**
+ * Disables a user
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param user_hnd Open handle to the user to disables
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamDisableUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *user_hnd);
+
+struct SamSetPassword {
+ struct {
+ /**Open handle to a user*/
+ POLICY_HND *user_hnd;
+
+ /**The new password*/
+ char *password;
+ } in;
+};
+
+/**
+ * Sets a user's password
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_SamSetPassword(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetPassword *op);
+
+struct SamGetUserInfo {
+ struct {
+ /**Open Handle to a user*/
+ POLICY_HND *user_hnd;
+ } in;
+
+ struct {
+ CacUserInfo *info;
+ } out;
+};
+
+/**
+ * Retrieves user information using a CacUserInfo structure. If you would like to use a SAM_USERINFO_CTR directly, use cac_SamGetUserInfoCtr()
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @see cac_SamGetUserInfoCtr()
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetUserInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetUserInfo *op);
+
+struct SamSetUserInfo {
+ struct {
+ /**Open handle to a user*/
+ POLICY_HND *user_hnd;
+
+ /**Structure containing the data you would like to set*/
+ CacUserInfo *info;
+ } in;
+};
+
+/**
+ * Sets the user info using a CacUserInfo structure. If you would like to use a SAM_USERINFO_CTR directly use cac_SamSetUserInfoCtr().
+ * @note All fields in the CacUserInfo structure will be set. Best to call cac_GetUserInfo() modify fields that you want, and then call cac_SetUserInfo().
+ * @note When calling this, you _must_ set the user's password.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @see cac_SamSetUserInfoCtr()
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamSetUserInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetUserInfo *op);
+
+struct SamGetUserInfoCtr {
+ struct {
+ /**Open handle to a user*/
+ POLICY_HND *user_hnd;
+
+ /**What USER_INFO structure you want. See include/rpc_samr.h*/
+ uint16 info_class;
+ } in;
+
+ struct {
+ /**returned user info*/
+ SAM_USERINFO_CTR *ctr;
+ } out;
+};
+
+/**
+ * Retrieves user information using a SAM_USERINFO_CTR structure. If you don't want to use this structure, user SamGetUserInfo()
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @see cac_SamGetUserInfo()
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetUserInfoCtr(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetUserInfoCtr *op);
+
+struct SamSetUserInfoCtr {
+ struct {
+ /**Open handle to a user*/
+ POLICY_HND *user_hnd;
+
+ /**user info - make sure ctr->switch_value is set properly*/
+ SAM_USERINFO_CTR *ctr;
+ } in;
+};
+
+/**
+ * Sets the user info using a SAM_USERINFO_CTR structure. If you don't want to use this structure, use cac_SamSetUserInfo()
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @see cac_SamSetUserInfo()
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_SamSetUserInfoCtr(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetUserInfoCtr *op);
+
+struct SamRenameUser {
+ struct {
+ /**Open handle to user*/
+ POLICY_HND *user_hnd;
+
+ /**New user name*/
+ char *new_name;
+ } in;
+};
+
+/**
+ * Changes the name of a user.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamRenameUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamRenameUser *op);
+
+struct SamGetGroupInfo {
+ struct {
+ /**Open handle to a group*/
+ POLICY_HND *group_hnd;
+ } in;
+
+ struct {
+ /**Returned info about the group*/
+ CacGroupInfo *info;
+ } out;
+};
+
+/**
+ * Retrieves information about a group.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetGroupInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetGroupInfo *op);
+
+struct SamSetGroupInfo {
+ struct {
+ /**Open handle to a group*/
+ POLICY_HND *group_hnd;
+
+ /**group info*/
+ CacGroupInfo *info;
+ } in;
+};
+
+/**
+ * Sets information about a group.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamSetGroupInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetGroupInfo *op);
+
+struct SamRenameGroup {
+ struct {
+ /**Open handle to a group*/
+ POLICY_HND *group_hnd;
+
+ /**New name*/
+ char *new_name;
+ } in;
+};
+
+/**
+ * Changes the name of a group
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_SamRenameGroup(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamRenameGroup *op);
+
+struct SamGetAliasInfo {
+ struct {
+ /**Open handle to an alias*/
+ POLICY_HND *alias_hnd;
+ } in;
+
+ struct {
+ /**Returned alias info*/
+ CacAliasInfo *info;
+ } out;
+};
+
+/**
+ * Retrieves information about an alias.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetAliasInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetAliasInfo *op);
+
+struct SamSetAliasInfo {
+ struct {
+ /**Open handle to an alias*/
+ POLICY_HND *alias_hnd;
+
+ /**Returned alias info*/
+ CacAliasInfo *info;
+ } in;
+};
+
+/**
+ * Sets information about an alias.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamSetAliasInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetAliasInfo *op);
+
+struct SamGetDomainInfo {
+ struct {
+ /**Open handle to the domain SAM*/
+ POLICY_HND *dom_hnd;
+ } in;
+
+ struct {
+ /**Returned domain info*/
+ CacDomainInfo *info;
+ } out;
+};
+
+/**
+ * Gets domain information in the form of a CacDomainInfo structure.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @see SamGetDomainInfoCtr()
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ * @return CAC_PARTIAL_SUCCESS - This function makes 3 rpc calls, if one or two fail and the rest succeed,
+ * not all fields in the CacDomainInfo structure will be filled
+ */
+int cac_SamGetDomainInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetDomainInfo *op);
+
+struct SamGetDomainInfoCtr {
+ struct {
+ /**Open handle to domain*/
+ POLICY_HND *dom_hnd;
+
+ /**What info level you want*/
+ uint16 info_class;
+ } in;
+
+ struct {
+ SAM_UNK_CTR *info;
+ } out;
+};
+
+/**
+ * Gets domain information in the form of a SAM_UNK_CTR structure.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @see SamGetDomainInfo()
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SamGetDomainInfoCtr(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetDomainInfoCtr *op);
+
+struct SamGetDisplayInfo {
+ struct {
+ /**Open handle to domain*/
+ POLICY_HND *dom_hnd;
+
+ /**What type of data*/
+ uint16 info_class;
+
+ /**(Optional)If 0, max_entries and max_size will be filled in by the function*/
+ uint32 max_entries;
+
+ /**(Optional)If 0, max_entries and max_size will be filled in by the function*/
+ uint32 max_size;
+ } in;
+
+ struct {
+ /**Do not modify this value, use the same value between multiple calls (ie in while loop)*/
+ uint32 resume_idx;
+
+ /**Number of entries returned*/
+ uint32 num_entries;
+
+ /**Returned display info*/
+ SAM_DISPINFO_CTR ctr;
+
+ /**Internal value. Do not modify.*/
+ uint32 loop_count;
+
+ bool done;
+ } out;
+};
+
+/**
+ * Gets dislpay information using a SAM_DISPINFO_CTR.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SamGetDisplayInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetDisplayInfo *op);
+
+struct SamLookupDomain {
+ struct {
+ /**Open handle to the sam (opened with cac_SamConnect() or cac_SamOpenDomain()*/
+ POLICY_HND *sam;
+
+ /**Name of the domain to lookup*/
+ char *name;
+ } in;
+
+ struct {
+ /**SID of the domain*/
+ DOM_SID *sid;
+ } out;
+};
+
+/**
+ * Looks up a Domain SID given it's name.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SamLookupDomain(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamLookupDomain *op);
+
+struct SamGetSecurityObject {
+ struct {
+ /**An open handle (SAM, domain or user)*/
+ POLICY_HND *pol;
+ } in;
+
+ struct {
+ SEC_DESC_BUF *sec;
+ } out;
+};
+
+/**
+ * Retrievies Security descriptor information for a SAM/Domain/user
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SamGetSecurityObject(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetSecurityObject *op);
+
+struct SamFlush {
+ struct {
+ /**Open handle to the domain SAM*/
+ POLICY_HND *dom_hnd;
+
+ /**(Optional)Domain SID. If NULL, the domain in hnd->domain will be opened*/
+ DOM_SID *sid;
+
+ /**(Optional)Desired access to re-open the domain with. If 0, MAXIMUM_ALLOWED_ACCESS is used.*/
+ uint32 access;
+ } in;
+};
+
+/**
+ * Closes the domain handle, then re-opens it - effectively flushing any changes made.
+ * WARNING: if this fails you will no longer have an open handle to the domain SAM.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SamFlush(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamFlush *op);
+
+/**@}*/ /*SAM_Functions*/
+
+/**@addtogroup SCM_Functions
+ * @{
+ */
+
+struct SvcOpenScm {
+ struct {
+ /**Desired access to open the Handle with. See SC_RIGHT_MGR_* or SC_MANAGER_* in include/rpc_secdes.h*/
+ uint32 access;
+ } in;
+
+ struct {
+ /**Handle to the SCM*/
+ POLICY_HND *scm_hnd;
+ } out;
+};
+
+/**
+ * Opens a handle to the SCM on the remote machine.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcOpenScm(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcOpenScm *op);
+
+/**
+ * Closes an Svc handle (SCM or Service)
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param scm_hnd The handle to close
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcClose(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *scm_hnd);
+
+struct SvcEnumServices {
+ struct {
+ /**Open handle to the SCM*/
+ POLICY_HND *scm_hnd;
+
+ /**(Optional)Type of service to enumerate. Possible values:
+ * - SVCCTL_TYPE_WIN32
+ * - SVCCTL_TYPE_DRIVER
+ * If this is 0, (SVCCTL_TYPE_DRIVER | SVCCTL_TYPE_WIN32) is assumed.
+ */
+ uint32 type;
+
+ /**(Optional)State of service to enumerate. Possible values:
+ * - SVCCTL_STATE_ACTIVE
+ * - SVCCTL_STATE_INACTIVE
+ * - SVCCTL_STATE_ALL
+ * If this is 0, SVCCTL_STATE_ALL is assumed.
+ */
+ uint32 state;
+ } in;
+
+ struct {
+ /**Number of services returned*/
+ uint32 num_services;
+
+ /**Array of service structures*/
+ CacService *services;
+ } out;
+};
+
+/**
+ * Enumerates services on the remote machine.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcEnumServices(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcEnumServices *op);
+
+struct SvcOpenService {
+ struct {
+ /**Handle to the Service Control Manager*/
+ POLICY_HND *scm_hnd;
+
+ /**Access mask to open service with see SERVICE_* or SC_RIGHT_SVC_* in include/rpc_secdes.h*/
+ uint32 access;
+
+ /**The name of the service. _not_ the display name*/
+ char *name;
+ } in;
+
+ struct {
+ /**Handle to the open service*/
+ POLICY_HND *svc_hnd;
+ } out;
+};
+
+/**
+ * Opens a handle to a service.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+
+int cac_SvcOpenService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcOpenService *op);
+
+struct SvcGetStatus {
+ struct {
+ /**Open handle to the service to query*/
+ POLICY_HND *svc_hnd;
+ } in;
+
+ struct {
+ /**The status of the service. See include/rpc_svcctl.h for SERVICE_STATUS definition.*/
+ SERVICE_STATUS status;
+ } out;
+};
+
+/**
+ * Retrieves the status of a service.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcGetStatus(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcGetStatus *op);
+
+struct SvcStartService {
+ struct {
+ /**open handle to the service*/
+ POLICY_HND *svc_hnd;
+
+ /**Array of parameters to start the service with. Can be NULL if num_parms is 0*/
+ char **parms;
+
+ /**Number of parameters in the parms array*/
+ uint32 num_parms;
+
+ /**Number of seconds to wait for the service to actually start. If this is 0, then the status will not be checked after the initial call*/
+ uint32 timeout;
+ } in;
+};
+
+/**
+ * Attempts to start a service.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+
+int cac_SvcStartService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcStartService *op);
+
+struct SvcControlService {
+ struct {
+ /**Open handle to the service to control*/
+ POLICY_HND *svc_hnd;
+
+ /**The control operation to perform. Possible values (from include/rpc_svcctl.h):
+ * - SVCCTL_CONTROL_STOP
+ * - SVCCTL_CONTROL_PAUSE
+ * - SVCCTL_CONTROL_CONTINUE
+ * - SVCCTL_CONTROL_SHUTDOWN
+ */
+ uint32 control;
+ } in;
+
+ struct {
+ /**The returned status of the service, _immediately_ after the call*/
+ SERVICE_STATUS *status;
+ } out;
+};
+
+/**
+ * Performs a control operation on a service and _immediately_ returns.
+ * @see cac_SvcStopService()
+ * @see cac_SvcPauseService()
+ * @see cac_SvcContinueService()
+ * @see cac_SvcShutdownService()
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcControlService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcControlService *op);
+
+struct SvcStopService {
+ struct {
+ /**Open handle to the service*/
+ POLICY_HND *svc_hnd;
+
+ /**Number of seconds to wait for the service to actually start.
+ * If this is 0, then the status will not be checked after the initial call and CAC_SUCCESS might be returned if the status isn't actually started
+ */
+ uint32 timeout;
+ } in;
+
+ struct {
+ /**Status of the service after the operation*/
+ SERVICE_STATUS status;
+ } out;
+};
+
+/**
+ * Attempts to stop a service.
+ * @see cacSvcControlService()
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful. If hnd->status is NT_STATUS_OK, then a timeout occured.
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcStopService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcStopService *op);
+
+struct SvcPauseService {
+ struct {
+ /**Open handle to the service*/
+ POLICY_HND *svc_hnd;
+
+ /**Number of seconds to wait for the service to actually start.
+ * If this is 0, then the status will not be checked after the initial call and CAC_SUCCESS might be returned if the status isn't actually started
+ */
+ uint32 timeout;
+ } in;
+
+ struct {
+ /**Status of the service after the operation*/
+ SERVICE_STATUS status;
+ } out;
+};
+
+/**
+ * Attempts to pause a service.
+ * @see cacSvcControlService()
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful. If hnd->status is NT_STATUS_OK, then a timeout occured.
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcPauseService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcPauseService *op);
+
+struct SvcContinueService {
+ struct {
+ /**Open handle to the service*/
+ POLICY_HND *svc_hnd;
+
+ /**Number of seconds to wait for the service to actually start.
+ * If this is 0, then the status will not be checked after the initial call and CAC_SUCCESS might be returned if the status isn't actually started
+ */
+ uint32 timeout;
+ } in;
+
+ struct {
+ /**Status of the service after the operation*/
+ SERVICE_STATUS status;
+ } out;
+};
+
+/**
+ * Attempts to continue a paused service.
+ * @see cacSvcControlService()
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful. If hnd->status is NT_STATUS_OK, then a timeout occured.
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcContinueService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcContinueService *op);
+
+struct SvcGetDisplayName {
+ struct {
+ /**Open handle to the service*/
+ POLICY_HND *svc_hnd;
+ } in;
+
+ struct {
+ /**The returned display name of the service*/
+ char *display_name;
+ } out;
+};
+
+/**
+ * Retrieves the display name of a service _not currently working_
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcGetDisplayName(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcGetDisplayName *op);
+
+struct SvcGetServiceConfig {
+ struct {
+ /**Open handle to the service*/
+ POLICY_HND *svc_hnd;
+ } in;
+
+ struct {
+ /**Returned Configuration information*/
+ CacServiceConfig config;
+ } out;
+};
+
+/**
+ * Retrieves configuration information about a service.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcGetServiceConfig(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcGetServiceConfig *op);
+
+/**@}*/ /*SCM_Functions*/
+
+struct rpc_pipe_client *cac_GetPipe(CacServerHandle *hnd, int pi_idx);
+
+#endif /* LIBMSRPC_H */
+
+
diff --git a/source3/include/libmsrpc_internal.h b/source3/include/libmsrpc_internal.h
new file mode 100644
index 0000000000..623c43f9c3
--- /dev/null
+++ b/source3/include/libmsrpc_internal.h
@@ -0,0 +1,73 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * MS-RPC client internal definitions
+ * Copyright (C) Chris Nicholls 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBMSRPC_INTERNAL_H
+#define LIBMSRPC_INTERNAL_H
+
+#include "libmsrpc.h"
+
+/*definitions*/
+
+struct CacServerHandleInternal {
+ /*stores the os type of the server*/
+ uint16 srv_level;
+
+ /*stores the initialized/active pipes*/
+ bool pipes[PI_MAX_PIPES];
+
+ /*underlying smbc context*/
+ SMBCCTX *ctx;
+
+ /*did the user supply this SMBCCTX?*/
+ bool user_supplied_ctx;
+};
+
+/*used to get a struct rpc_pipe_client* to be passed into rpccli* calls*/
+
+/*nessecary prototypes*/
+bool rid_in_list(uint32 rid, uint32 *list, uint32 list_len);
+
+int cac_ParseRegPath(char *path, uint32 *reg_type, char **key_name);
+
+REG_VALUE_DATA *cac_MakeRegValueData(TALLOC_CTX *mem_ctx, uint32 data_type, REGVAL_BUFFER buf);
+
+RPC_DATA_BLOB *cac_MakeRpcDataBlob(TALLOC_CTX *mem_ctx, uint32 data_type, REG_VALUE_DATA data);
+
+SAM_USERINFO_CTR *cac_MakeUserInfoCtr(TALLOC_CTX *mem_ctx, CacUserInfo *info);
+
+CacUserInfo *cac_MakeUserInfo(TALLOC_CTX *mem_ctx, SAM_USERINFO_CTR *ctr);
+CacGroupInfo *cac_MakeGroupInfo(TALLOC_CTX *mem_ctx, GROUP_INFO_CTR *ctr);
+GROUP_INFO_CTR *cac_MakeGroupInfoCtr(TALLOC_CTX *mem_ctx, CacGroupInfo *info);
+CacAliasInfo *cac_MakeAliasInfo(TALLOC_CTX *mem_ctx, ALIAS_INFO_CTR ctr);
+ALIAS_INFO_CTR *cac_MakeAliasInfoCtr(TALLOC_CTX *mem_ctx, CacAliasInfo *info);
+CacDomainInfo *cac_MakeDomainInfo(TALLOC_CTX *mem_ctx, SAM_UNK_INFO_1 *info1, SAM_UNK_INFO_2 *info2, SAM_UNK_INFO_12 *info12);
+CacService *cac_MakeServiceArray(TALLOC_CTX *mem_ctx, ENUM_SERVICES_STATUS *svc, uint32 num_services);
+int cac_InitCacServiceConfig(TALLOC_CTX *mem_ctx, SERVICE_CONFIG *src, CacServiceConfig *dest);
+
+/*moved to libmsrpc.h*/
+/*struct rpc_pipe_client *cac_GetPipe(CacServerHandle *hnd, int pi_idx);*/
+
+SMBCSRV *smbc_attr_server(SMBCCTX *context,
+ const char *server, const char *share,
+ fstring workgroup,
+ fstring username, fstring password,
+ POLICY_HND *pol);
+
+
+#endif /* LIBMSRPC_INTERNAL_H */
diff --git a/source3/include/libsmb_internal.h b/source3/include/libsmb_internal.h
new file mode 100644
index 0000000000..3b909d13b9
--- /dev/null
+++ b/source3/include/libsmb_internal.h
@@ -0,0 +1,536 @@
+/*
+ Unix SMB/Netbios implementation.
+ SMB client library implementation
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000, 2002
+ Copyright (C) John Terpstra 2000
+ Copyright (C) Tom Jansen (Ninja ISD) 2002
+ Copyright (C) Derrell Lipman 2003-2008
+ Copyright (C) Jeremy Allison 2007, 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+
+#ifndef _LIBSMB_INTERNAL_H_
+#define _LIBSMB_INTERNAL_H_
+
+#include "../include/libsmbclient.h"
+
+#define SMBC_MAX_NAME 1023
+#define SMBC_FILE_MODE (S_IFREG | 0444)
+#define SMBC_DIR_MODE (S_IFDIR | 0555)
+
+/*
+ * DOS Attribute values (used internally)
+ */
+typedef struct DOS_ATTR_DESC {
+ int mode;
+ SMB_OFF_T size;
+ time_t create_time;
+ time_t access_time;
+ time_t write_time;
+ time_t change_time;
+ SMB_INO_T inode;
+} DOS_ATTR_DESC;
+
+
+/*
+ * Internal flags for extended attributes
+ */
+
+/* internal mode values */
+#define SMBC_XATTR_MODE_ADD 1
+#define SMBC_XATTR_MODE_REMOVE 2
+#define SMBC_XATTR_MODE_REMOVE_ALL 3
+#define SMBC_XATTR_MODE_SET 4
+#define SMBC_XATTR_MODE_CHOWN 5
+#define SMBC_XATTR_MODE_CHGRP 6
+
+#define CREATE_ACCESS_READ READ_CONTROL_ACCESS
+
+/*We should test for this in configure ... */
+#ifndef ENOTSUP
+#define ENOTSUP EOPNOTSUPP
+#endif
+
+
+struct _SMBCSRV {
+ struct cli_state *cli;
+ dev_t dev;
+ bool no_pathinfo;
+ bool no_pathinfo2;
+ bool no_nt_session;
+ POLICY_HND pol;
+
+ SMBCSRV *next, *prev;
+
+};
+
+/*
+ * Keep directory entries in a list
+ */
+struct smbc_dir_list {
+ struct smbc_dir_list *next;
+ struct smbc_dirent *dirent;
+};
+
+
+/*
+ * Structure for open file management
+ */
+struct _SMBCFILE {
+ int cli_fd;
+ char *fname;
+ SMB_OFF_T offset;
+ struct _SMBCSRV *srv;
+ bool file;
+ struct smbc_dir_list *dir_list, *dir_end, *dir_next;
+ int dir_type, dir_error;
+
+ SMBCFILE *next, *prev;
+};
+
+
+/*
+ * Context structure
+ */
+struct SMBC_internal_data {
+
+ /* True when this handle is initialized */
+ bool initialized;
+
+ /* dirent pointer location
+ *
+ * Leave room for any urlencoded filename and the comment field.
+ *
+ * We really should use sizeof(struct smbc_dirent) plus (NAME_MAX * 3)
+ * plus whatever the max length of a comment is, plus a couple of null
+ * terminators (one after the filename, one after the comment).
+ *
+ * According to <linux/limits.h>, NAME_MAX is 255. Is it longer
+ * anyplace else?
+ */
+ char dirent[1024];
+
+ /*
+ * server connection list
+ */
+ SMBCSRV * servers;
+
+ /*
+ * open file/dir list
+ */
+ SMBCFILE * files;
+
+ /*
+ * Log to standard error instead of the more typical standard output
+ */
+ bool debug_stderr;
+
+ /*
+ * Support "Create Time" in get/set with the *xattr() functions, if
+ * true. This replaces the dos attribute strings C_TIME, A_TIME and
+ * M_TIME with CHANGE_TIME, ACCESS_TIME and WRITE_TIME, and adds
+ * CREATE_TIME. Default is FALSE, i.e. to use the old-style shorter
+ * names and to not support CREATE time, for backward compatibility.
+ */
+ bool full_time_names;
+
+ /*
+ * The share mode of a file being opened. To match POSIX semantics
+ * (and maintain backward compatibility), DENY_NONE is the default.
+ */
+ smbc_share_mode share_mode;
+
+ /*
+ * Authentication function which includes the context. This will be
+ * used if set; otherwise context->callbacks.auth_fn() will be used.
+ */
+ smbc_get_auth_data_with_context_fn auth_fn_with_context;
+
+ /*
+ * An opaque (to this library) user data handle which can be set
+ * and retrieved with smbc_option_set() and smbc_option_get().
+ */
+ void * user_data;
+
+ /*
+ * Should we attempt UNIX smb encryption ?
+ * Set to 0 if we should never attempt, set to 1 if
+ * encryption requested, set to 2 if encryption required.
+ */
+ smbc_smb_encrypt_level smb_encryption_level;
+
+ struct smbc_server_cache * server_cache;
+
+ /* POSIX emulation functions */
+ struct
+ {
+#if 0 /* Left in libsmbclient.h for backward compatibility */
+ smbc_open_fn open_fn;
+ smbc_creat_fn creat_fn;
+ smbc_read_fn read_fn;
+ smbc_write_fn write_fn;
+ smbc_unlink_fn unlink_fn;
+ smbc_rename_fn rename_fn;
+ smbc_lseek_fn lseek_fn;
+ smbc_stat_fn stat_fn;
+ smbc_fstat_fn fstat_fn;
+#endif
+ smbc_ftruncate_fn ftruncate_fn;
+#if 0 /* Left in libsmbclient.h for backward compatibility */
+ smbc_close_fn close_fn;
+ smbc_opendir_fn opendir_fn;
+ smbc_closedir_fn closedir_fn;
+ smbc_readdir_fn readdir_fn;
+ smbc_getdents_fn getdents_fn;
+ smbc_mkdir_fn mkdir_fn;
+ smbc_rmdir_fn rmdir_fn;
+ smbc_telldir_fn telldir_fn;
+ smbc_lseekdir_fn lseekdir_fn;
+ smbc_fstatdir_fn fstatdir_fn;
+ smbc_chmod_fn chmod_fn;
+ smbc_utimes_fn utimes_fn;
+ smbc_setxattr_fn setxattr_fn;
+ smbc_getxattr_fn getxattr_fn;
+ smbc_removexattr_fn removexattr_fn;
+ smbc_listxattr_fn listxattr_fn;
+#endif
+ } posix_emu;
+
+#if 0 /* Left in libsmbclient.h for backward compatibility */
+ /* Printing-related functions */
+ struct
+ {
+ smbc_print_file_fn print_file_fn;
+ smbc_open_print_job_fn open_print_job_fn;
+ smbc_list_print_jobs_fn list_print_jobs_fn;
+ smbc_unlink_print_job_fn unlink_print_job_fn;
+ } printing;
+#endif
+
+#if 0 /* None available yet */
+ /* SMB high-level functions */
+ struct
+ {
+ } smb;
+
+#endif
+};
+
+/* Functions in libsmb_cache.c */
+int
+SMBC_add_cached_server(SMBCCTX * context,
+ SMBCSRV * newsrv,
+ const char * server,
+ const char * share,
+ const char * workgroup,
+ const char * username);
+
+SMBCSRV *
+SMBC_get_cached_server(SMBCCTX * context,
+ const char * server,
+ const char * share,
+ const char * workgroup,
+ const char * user);
+
+int
+SMBC_remove_cached_server(SMBCCTX * context,
+ SMBCSRV * server);
+
+int
+SMBC_purge_cached_servers(SMBCCTX * context);
+
+
+/* Functions in libsmb_dir.c */
+int
+SMBC_check_options(char *server,
+ char *share,
+ char *path,
+ char *options);
+
+SMBCFILE *
+SMBC_opendir_ctx(SMBCCTX *context,
+ const char *fname);
+
+int
+SMBC_closedir_ctx(SMBCCTX *context,
+ SMBCFILE *dir);
+
+struct smbc_dirent *
+SMBC_readdir_ctx(SMBCCTX *context,
+ SMBCFILE *dir);
+
+int
+SMBC_getdents_ctx(SMBCCTX *context,
+ SMBCFILE *dir,
+ struct smbc_dirent *dirp,
+ int count);
+
+int
+SMBC_mkdir_ctx(SMBCCTX *context,
+ const char *fname,
+ mode_t mode);
+
+int
+SMBC_rmdir_ctx(SMBCCTX *context,
+ const char *fname);
+
+off_t
+SMBC_telldir_ctx(SMBCCTX *context,
+ SMBCFILE *dir);
+
+int
+SMBC_lseekdir_ctx(SMBCCTX *context,
+ SMBCFILE *dir,
+ off_t offset);
+
+int
+SMBC_fstatdir_ctx(SMBCCTX *context,
+ SMBCFILE *dir,
+ struct stat *st);
+
+int
+SMBC_chmod_ctx(SMBCCTX *context,
+ const char *fname,
+ mode_t newmode);
+
+int
+SMBC_utimes_ctx(SMBCCTX *context,
+ const char *fname,
+ struct timeval *tbuf);
+
+int
+SMBC_unlink_ctx(SMBCCTX *context,
+ const char *fname);
+
+int
+SMBC_rename_ctx(SMBCCTX *ocontext,
+ const char *oname,
+ SMBCCTX *ncontext,
+ const char *nname);
+
+
+/* Functions in libsmb_file.c */
+SMBCFILE *
+SMBC_open_ctx(SMBCCTX *context,
+ const char *fname,
+ int flags,
+ mode_t mode);
+
+SMBCFILE *
+SMBC_creat_ctx(SMBCCTX *context,
+ const char *path,
+ mode_t mode);
+
+ssize_t
+SMBC_read_ctx(SMBCCTX *context,
+ SMBCFILE *file,
+ void *buf,
+ size_t count);
+
+ssize_t
+SMBC_write_ctx(SMBCCTX *context,
+ SMBCFILE *file,
+ const void *buf,
+ size_t count);
+
+int
+SMBC_close_ctx(SMBCCTX *context,
+ SMBCFILE *file);
+
+bool
+SMBC_getatr(SMBCCTX * context,
+ SMBCSRV *srv,
+ char *path,
+ uint16 *mode,
+ SMB_OFF_T *size,
+ struct timespec *create_time_ts,
+ struct timespec *access_time_ts,
+ struct timespec *write_time_ts,
+ struct timespec *change_time_ts,
+ SMB_INO_T *ino);
+
+bool
+SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path,
+ time_t create_time,
+ time_t access_time,
+ time_t write_time,
+ time_t change_time,
+ uint16 mode);
+
+off_t
+SMBC_lseek_ctx(SMBCCTX *context,
+ SMBCFILE *file,
+ off_t offset,
+ int whence);
+
+int
+SMBC_ftruncate_ctx(SMBCCTX *context,
+ SMBCFILE *file,
+ off_t length);
+
+
+/* Functions in libsmb_misc.c */
+int
+SMBC_dlist_contains(SMBCFILE * list, SMBCFILE *p);
+
+int
+SMBC_errno(SMBCCTX *context,
+ struct cli_state *c);
+
+
+/* Functions in libsmb_path.c */
+int
+SMBC_urldecode(char *dest,
+ char *src,
+ size_t max_dest_len);
+
+int
+SMBC_urlencode(char *dest,
+ char *src,
+ int max_dest_len);
+
+int
+SMBC_parse_path(TALLOC_CTX *ctx,
+ SMBCCTX *context,
+ const char *fname,
+ char **pp_workgroup,
+ char **pp_server,
+ char **pp_share,
+ char **pp_path,
+ char **pp_user,
+ char **pp_password,
+ char **pp_options);
+
+
+/* Functions in libsmb_printjob.c */
+SMBCFILE *
+SMBC_open_print_job_ctx(SMBCCTX *context,
+ const char *fname);
+
+int
+SMBC_print_file_ctx(SMBCCTX *c_file,
+ const char *fname,
+ SMBCCTX *c_print,
+ const char *printq);
+
+int
+SMBC_list_print_jobs_ctx(SMBCCTX *context,
+ const char *fname,
+ smbc_list_print_job_fn fn);
+
+int
+SMBC_unlink_print_job_ctx(SMBCCTX *context,
+ const char *fname,
+ int id);
+
+
+/* Functions in libsmb_server.c */
+int
+SMBC_check_server(SMBCCTX * context,
+ SMBCSRV * server);
+
+int
+SMBC_remove_unused_server(SMBCCTX * context,
+ SMBCSRV * srv);
+
+void
+SMBC_call_auth_fn(TALLOC_CTX *ctx,
+ SMBCCTX *context,
+ const char *server,
+ const char *share,
+ char **pp_workgroup,
+ char **pp_username,
+ char **pp_password);
+
+void
+SMBC_get_auth_data(const char *server, const char *share,
+ char *workgroup_buf, int workgroup_buf_len,
+ char *username_buf, int username_buf_len,
+ char *password_buf, int password_buf_len);
+
+SMBCSRV *
+SMBC_find_server(TALLOC_CTX *ctx,
+ SMBCCTX *context,
+ const char *server,
+ const char *share,
+ char **pp_workgroup,
+ char **pp_username,
+ char **pp_password);
+
+SMBCSRV *
+SMBC_server(TALLOC_CTX *ctx,
+ SMBCCTX *context,
+ bool connect_if_not_found,
+ const char *server,
+ const char *share,
+ char **pp_workgroup,
+ char **pp_username,
+ char **pp_password);
+
+SMBCSRV *
+SMBC_attr_server(TALLOC_CTX *ctx,
+ SMBCCTX *context,
+ const char *server,
+ const char *share,
+ char **pp_workgroup,
+ char **pp_username,
+ char **pp_password);
+
+
+/* Functions in libsmb_stat.c */
+int
+SMBC_stat_ctx(SMBCCTX *context,
+ const char *fname,
+ struct stat *st);
+
+int
+SMBC_fstat_ctx(SMBCCTX *context,
+ SMBCFILE *file,
+ struct stat *st);
+
+
+/* Functions in libsmb_xattr.c */
+int
+SMBC_setxattr_ctx(SMBCCTX *context,
+ const char *fname,
+ const char *name,
+ const void *value,
+ size_t size,
+ int flags);
+
+int
+SMBC_getxattr_ctx(SMBCCTX *context,
+ const char *fname,
+ const char *name,
+ const void *value,
+ size_t size);
+
+int
+SMBC_removexattr_ctx(SMBCCTX *context,
+ const char *fname,
+ const char *name);
+
+int
+SMBC_listxattr_ctx(SMBCCTX *context,
+ const char *fname,
+ char *list,
+ size_t size);
+
+
+#endif
diff --git a/source3/include/libsmbclient.h b/source3/include/libsmbclient.h
new file mode 100644
index 0000000000..a8b27b709e
--- /dev/null
+++ b/source3/include/libsmbclient.h
@@ -0,0 +1,2819 @@
+/*=====================================================================
+ Unix SMB/Netbios implementation.
+ SMB client library API definitions
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000
+ Copyright (C) John Terpsra 2000
+ Copyright (C) Tom Jansen (Ninja ISD) 2002
+ Copyright (C) Derrell Lipman 2003-2008
+
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+ =====================================================================*/
+
+#ifndef SMBCLIENT_H_INCLUDED
+#define SMBCLIENT_H_INCLUDED
+
+#undef DEPRECATED_SMBC_INTERFACE
+#if ! defined(__LIBSMBCLIENT_INTERNAL__) && defined(__GNUC__)
+# define DEPRECATED_SMBC_INTERFACE __attribute__ ((deprecated))
+#else
+# define DEPRECATED_SMBC_INTERFACE
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-------------------------------------------------------------------*/
+/* The following are special comments to instruct DOXYGEN (automated
+ * documentation tool:
+*/
+/** \defgroup libsmbclient
+*/
+/** \defgroup structure Data Structures Type and Constants
+* \ingroup libsmbclient
+* Data structures, types, and constants
+*/
+/** \defgroup callback Callback function types
+* \ingroup libsmbclient
+* Callback functions
+*/
+/** \defgroup file File Functions
+* \ingroup libsmbclient
+* Functions used to access individual file contents
+*/
+/** \defgroup directory Directory Functions
+* \ingroup libsmbclient
+* Functions used to access directory entries
+*/
+/** \defgroup attribute Attributes Functions
+* \ingroup libsmbclient
+* Functions used to view or change file and directory attributes
+*/
+/** \defgroup print Print Functions
+* \ingroup libsmbclient
+* Functions used to access printing functionality
+*/
+/** \defgroup misc Miscellaneous Functions
+* \ingroup libsmbclient
+* Functions that don't fit in to other categories
+*/
+/*-------------------------------------------------------------------*/
+
+/* Make sure we have the following includes for now ... */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <utime.h>
+
+#define SMBC_BASE_FD 10000 /* smallest file descriptor returned */
+
+#define SMBC_WORKGROUP 1
+#define SMBC_SERVER 2
+#define SMBC_FILE_SHARE 3
+#define SMBC_PRINTER_SHARE 4
+#define SMBC_COMMS_SHARE 5
+#define SMBC_IPC_SHARE 6
+#define SMBC_DIR 7
+#define SMBC_FILE 8
+#define SMBC_LINK 9
+
+/**@ingroup structure
+ * Structure that represents a directory entry.
+ *
+ */
+struct smbc_dirent
+{
+ /** Type of entity.
+ SMBC_WORKGROUP=1,
+ SMBC_SERVER=2,
+ SMBC_FILE_SHARE=3,
+ SMBC_PRINTER_SHARE=4,
+ SMBC_COMMS_SHARE=5,
+ SMBC_IPC_SHARE=6,
+ SMBC_DIR=7,
+ SMBC_FILE=8,
+ SMBC_LINK=9,*/
+ unsigned int smbc_type;
+
+ /** Length of this smbc_dirent in bytes
+ */
+ unsigned int dirlen;
+ /** The length of the comment string in bytes (does not include
+ * null terminator)
+ */
+ unsigned int commentlen;
+ /** Points to the null terminated comment string
+ */
+ char *comment;
+ /** The length of the name string in bytes (does not include
+ * null terminator)
+ */
+ unsigned int namelen;
+ /** Points to the null terminated name string
+ */
+ char name[1];
+};
+
+/*
+ * Flags for smbc_setxattr()
+ * Specify a bitwise OR of these, or 0 to add or replace as necessary
+ */
+#define SMBC_XATTR_FLAG_CREATE 0x1 /* fail if attr already exists */
+#define SMBC_XATTR_FLAG_REPLACE 0x2 /* fail if attr does not exist */
+
+
+/*
+ * Mappings of the DOS mode bits, as returned by smbc_getxattr() when the
+ * attribute name "system.dos_attr.mode" (or "system.dos_attr.*" or
+ * "system.*") is specified.
+ */
+#define SMBC_DOS_MODE_READONLY 0x01
+#define SMBC_DOS_MODE_HIDDEN 0x02
+#define SMBC_DOS_MODE_SYSTEM 0x04
+#define SMBC_DOS_MODE_VOLUME_ID 0x08
+#define SMBC_DOS_MODE_DIRECTORY 0x10
+#define SMBC_DOS_MODE_ARCHIVE 0x20
+
+/*
+ * Valid values for the option "open_share_mode", when calling
+ * smbc_setOptionOpenShareMode()
+ */
+typedef enum smbc_share_mode
+{
+ SMBC_SHAREMODE_DENY_DOS = 0,
+ SMBC_SHAREMODE_DENY_ALL = 1,
+ SMBC_SHAREMODE_DENY_WRITE = 2,
+ SMBC_SHAREMODE_DENY_READ = 3,
+ SMBC_SHAREMODE_DENY_NONE = 4,
+ SMBC_SHAREMODE_DENY_FCB = 7
+} smbc_share_mode;
+
+
+/**
+ * Values for option SMB Encryption Level, as set and retrieved with
+ * smbc_setOptionSmbEncryptionLevel() and smbc_getOptionSmbEncryptionLevel()
+ */
+typedef enum smbc_smb_encrypt_level
+{
+ SMBC_ENCRYPTLEVEL_NONE = 0,
+ SMBC_ENCRYPTLEVEL_REQUEST = 1,
+ SMBC_ENCRYPTLEVEL_REQUIRE = 2
+} smbc_smb_encrypt_level;
+
+
+typedef int smbc_bool;
+
+
+#ifndef ENOATTR
+# define ENOATTR ENOENT /* No such attribute */
+#endif
+
+
+
+
+/**@ingroup structure
+ * Structure that represents a print job.
+ *
+ */
+#ifndef _CLIENT_H
+struct print_job_info
+{
+ /** numeric ID of the print job
+ */
+ unsigned short id;
+
+ /** represents print job priority (lower numbers mean higher priority)
+ */
+ unsigned short priority;
+
+ /** Size of the print job
+ */
+ size_t size;
+
+ /** Name of the user that owns the print job
+ */
+ char user[128];
+
+ /** Name of the print job. This will have no name if an anonymous print
+ * file was opened. Ie smb://server/printer
+ */
+ char name[128];
+
+ /** Time the print job was spooled
+ */
+ time_t t;
+};
+#endif /* _CLIENT_H */
+
+
+/**@ingroup structure
+ * Server handle
+ */
+typedef struct _SMBCSRV SMBCSRV;
+
+/**@ingroup structure
+ * File or directory handle
+ */
+typedef struct _SMBCFILE SMBCFILE;
+
+/**@ingroup structure
+ * File or directory handle
+ */
+typedef struct _SMBCCTX SMBCCTX;
+
+
+/*
+ * Flags for SMBCCTX->flags
+ *
+ * NEW CODE SHOULD NOT DIRECTLY MANIPULATE THE CONTEXT STRUCTURE.
+ * Instead, use:
+ * smbc_setOptionUseKerberos()
+ * smbc_getOptionUseKerberos()
+ * smbc_setOptionFallbackAfterKerberos()
+ * smbc_getOptionFallbackAFterKerberos()
+ * smbc_setOptionNoAutoAnonymousLogin()
+ * smbc_getOptionNoAutoAnonymousLogin()
+ */
+# define SMB_CTX_FLAG_USE_KERBEROS (1 << 0)
+# define SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS (1 << 1)
+# define SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON (1 << 2)
+
+
+
+/**@ingroup callback
+ * Authentication callback function type (traditional method)
+ *
+ * Type for the the authentication function called by the library to
+ * obtain authentication credentals
+ *
+ * For kerberos support the function should just be called without
+ * prompting the user for credentials. Which means a simple 'return'
+ * should work. Take a look at examples/libsmbclient/get_auth_data_fn.h
+ * and examples/libsmbclient/testbrowse.c.
+ *
+ * @param srv Server being authenticated to
+ *
+ * @param shr Share being authenticated to
+ *
+ * @param wg Pointer to buffer containing a "hint" for the
+ * workgroup to be authenticated. Should be filled in
+ * with the correct workgroup if the hint is wrong.
+ *
+ * @param wglen The size of the workgroup buffer in bytes
+ *
+ * @param un Pointer to buffer containing a "hint" for the
+ * user name to be use for authentication. Should be
+ * filled in with the correct workgroup if the hint is
+ * wrong.
+ *
+ * @param unlen The size of the username buffer in bytes
+ *
+ * @param pw Pointer to buffer containing to which password
+ * copied
+ *
+ * @param pwlen The size of the password buffer in bytes
+ *
+ */
+typedef void (*smbc_get_auth_data_fn)(const char *srv,
+ const char *shr,
+ char *wg, int wglen,
+ char *un, int unlen,
+ char *pw, int pwlen);
+/**@ingroup callback
+ * Authentication callback function type (method that includes context)
+ *
+ * Type for the the authentication function called by the library to
+ * obtain authentication credentals
+ *
+ * For kerberos support the function should just be called without
+ * prompting the user for credentials. Which means a simple 'return'
+ * should work. Take a look at examples/libsmbclient/get_auth_data_fn.h
+ * and examples/libsmbclient/testbrowse.c.
+ *
+ * @param c Pointer to the smb context
+ *
+ * @param srv Server being authenticated to
+ *
+ * @param shr Share being authenticated to
+ *
+ * @param wg Pointer to buffer containing a "hint" for the
+ * workgroup to be authenticated. Should be filled in
+ * with the correct workgroup if the hint is wrong.
+ *
+ * @param wglen The size of the workgroup buffer in bytes
+ *
+ * @param un Pointer to buffer containing a "hint" for the
+ * user name to be use for authentication. Should be
+ * filled in with the correct workgroup if the hint is
+ * wrong.
+ *
+ * @param unlen The size of the username buffer in bytes
+ *
+ * @param pw Pointer to buffer containing to which password
+ * copied
+ *
+ * @param pwlen The size of the password buffer in bytes
+ *
+ */
+typedef void (*smbc_get_auth_data_with_context_fn)(SMBCCTX *c,
+ const char *srv,
+ const char *shr,
+ char *wg, int wglen,
+ char *un, int unlen,
+ char *pw, int pwlen);
+
+
+/**@ingroup callback
+ * Print job info callback function type.
+ *
+ * @param i pointer to print job information structure
+ *
+ */
+typedef void (*smbc_list_print_job_fn)(struct print_job_info *i);
+
+
+/**@ingroup callback
+ * Check if a server is still good
+ *
+ * @param c pointer to smb context
+ *
+ * @param srv pointer to server to check
+ *
+ * @return 0 when connection is good. 1 on error.
+ *
+ */
+typedef int (*smbc_check_server_fn)(SMBCCTX * c, SMBCSRV *srv);
+
+/**@ingroup callback
+ * Remove a server if unused
+ *
+ * @param c pointer to smb context
+ *
+ * @param srv pointer to server to remove
+ *
+ * @return 0 on success. 1 on failure.
+ *
+ */
+typedef int (*smbc_remove_unused_server_fn)(SMBCCTX * c, SMBCSRV *srv);
+
+
+/**@ingroup callback
+ * Add a server to the cache system
+ *
+ * @param c pointer to smb context
+ *
+ * @param srv pointer to server to add
+ *
+ * @param server server name
+ *
+ * @param share share name
+ *
+ * @param workgroup workgroup used to connect
+ *
+ * @param username username used to connect
+ *
+ * @return 0 on success. 1 on failure.
+ *
+ */
+typedef int (*smbc_add_cached_srv_fn) (SMBCCTX * c, SMBCSRV *srv,
+ const char * server, const char * share,
+ const char * workgroup, const char * username);
+
+/**@ingroup callback
+ * Look up a server in the cache system
+ *
+ * @param c pointer to smb context
+ *
+ * @param server server name to match
+ *
+ * @param share share name to match
+ *
+ * @param workgroup workgroup to match
+ *
+ * @param username username to match
+ *
+ * @return pointer to SMBCSRV on success. NULL on failure.
+ *
+ */
+typedef SMBCSRV * (*smbc_get_cached_srv_fn) (SMBCCTX * c, const char * server,
+ const char * share, const char * workgroup,
+ const char * username);
+
+/**@ingroup callback
+ * Check if a server is still good
+ *
+ * @param c pointer to smb context
+ *
+ * @param srv pointer to server to remove
+ *
+ * @return 0 when found and removed. 1 on failure.
+ *
+ */
+typedef int (*smbc_remove_cached_srv_fn)(SMBCCTX * c, SMBCSRV *srv);
+
+
+/**@ingroup callback
+ * Try to remove all servers from the cache system and disconnect
+ *
+ * @param c pointer to smb context
+ *
+ * @return 0 when found and removed. 1 on failure.
+ *
+ */
+typedef int (*smbc_purge_cached_fn) (SMBCCTX * c);
+
+
+
+/*****************************************
+ * Getters and setters for CONFIGURATION *
+ *****************************************/
+
+/** Get the debug level */
+int
+smbc_getDebug(SMBCCTX *c);
+
+/** Set the debug level */
+void
+smbc_setDebug(SMBCCTX *c, int debug);
+
+/** Get the netbios name used for making connections */
+char *
+smbc_getNetbiosName(SMBCCTX *c);
+
+/** Set the netbios name used for making connections */
+void
+smbc_setNetbiosName(SMBCCTX *c, char * netbios_name);
+
+/** Get the workgroup used for making connections */
+char *
+smbc_getWorkgroup(SMBCCTX *c);
+
+/** Set the workgroup used for making connections */
+void smbc_setWorkgroup(SMBCCTX *c, char * workgroup);
+
+/** Get the username used for making connections */
+char *
+smbc_getUser(SMBCCTX *c);
+
+/** Set the username used for making connections */
+void
+smbc_setUser(SMBCCTX *c, char * user);
+
+/**
+ * Get the timeout used for waiting on connections and response data
+ * (in milliseconds)
+ */
+int
+smbc_getTimeout(SMBCCTX *c);
+
+/**
+ * Set the timeout used for waiting on connections and response data
+ * (in milliseconds)
+ */
+void
+smbc_setTimeout(SMBCCTX *c, int timeout);
+
+
+
+/***********************************
+ * Getters and setters for OPTIONS *
+ ***********************************/
+
+/** Get whether to log to standard error instead of standard output */
+smbc_bool
+smbc_getOptionDebugToStderr(SMBCCTX *c);
+
+/** Set whether to log to standard error instead of standard output */
+void
+smbc_setOptionDebugToStderr(SMBCCTX *c, smbc_bool b);
+
+/**
+ * Get whether to use new-style time attribute names, e.g. WRITE_TIME rather
+ * than the old-style names such as M_TIME. This allows also setting/getting
+ * CREATE_TIME which was previously unimplemented. (Note that the old C_TIME
+ * was supposed to be CHANGE_TIME but was confused and sometimes referred to
+ * CREATE_TIME.)
+ */
+smbc_bool
+smbc_getOptionFullTimeNames(SMBCCTX *c);
+
+/**
+ * Set whether to use new-style time attribute names, e.g. WRITE_TIME rather
+ * than the old-style names such as M_TIME. This allows also setting/getting
+ * CREATE_TIME which was previously unimplemented. (Note that the old C_TIME
+ * was supposed to be CHANGE_TIME but was confused and sometimes referred to
+ * CREATE_TIME.)
+ */
+void
+smbc_setOptionFullTimeNames(SMBCCTX *c, smbc_bool b);
+
+/**
+ * Get the share mode to use for files opened with SMBC_open_ctx(). The
+ * default is SMBC_SHAREMODE_DENY_NONE.
+ */
+smbc_share_mode
+smbc_getOptionOpenShareMode(SMBCCTX *c);
+
+/**
+ * Set the share mode to use for files opened with SMBC_open_ctx(). The
+ * default is SMBC_SHAREMODE_DENY_NONE.
+ */
+void
+smbc_setOptionOpenShareMode(SMBCCTX *c, smbc_share_mode share_mode);
+
+/** Retrieve a previously saved user data handle */
+void *
+smbc_getOptionUserData(SMBCCTX *c);
+
+/** Save a user data handle */
+void
+smbc_setOptionUserData(SMBCCTX *c, void *user_data);
+
+/** Get the encoded value for encryption level. */
+smbc_smb_encrypt_level
+smbc_getOptionSmbEncryptionLevel(SMBCCTX *c);
+
+/** Set the encoded value for encryption level. */
+void
+smbc_setOptionSmbEncryptionLevel(SMBCCTX *c, smbc_smb_encrypt_level level);
+
+/**
+ * Get from how many local master browsers should the list of workgroups be
+ * retrieved. It can take up to 12 minutes or longer after a server becomes a
+ * local master browser, for it to have the entire browse list (the list of
+ * workgroups/domains) from an entire network. Since a client never knows
+ * which local master browser will be found first, the one which is found
+ * first and used to retrieve a browse list may have an incomplete or empty
+ * browse list. By requesting the browse list from multiple local master
+ * browsers, a more complete list can be generated. For small networks (few
+ * workgroups), it is recommended that this value be set to 0, causing the
+ * browse lists from all found local master browsers to be retrieved and
+ * merged. For networks with many workgroups, a suitable value for this
+ * variable is probably somewhere around 3. (Default: 3).
+ */
+int
+smbc_getOptionBrowseMaxLmbCount(SMBCCTX *c);
+
+/**
+ * Set from how many local master browsers should the list of workgroups be
+ * retrieved. It can take up to 12 minutes or longer after a server becomes a
+ * local master browser, for it to have the entire browse list (the list of
+ * workgroups/domains) from an entire network. Since a client never knows
+ * which local master browser will be found first, the one which is found
+ * first and used to retrieve a browse list may have an incomplete or empty
+ * browse list. By requesting the browse list from multiple local master
+ * browsers, a more complete list can be generated. For small networks (few
+ * workgroups), it is recommended that this value be set to 0, causing the
+ * browse lists from all found local master browsers to be retrieved and
+ * merged. For networks with many workgroups, a suitable value for this
+ * variable is probably somewhere around 3. (Default: 3).
+ */
+void
+smbc_setOptionBrowseMaxLmbCount(SMBCCTX *c, int count);
+
+/**
+ * Get whether to url-encode readdir entries.
+ *
+ * There is a difference in the desired return strings from
+ * smbc_readdir() depending upon whether the filenames are to
+ * be displayed to the user, or whether they are to be
+ * appended to the path name passed to smbc_opendir() to call
+ * a further smbc_ function (e.g. open the file with
+ * smbc_open()). In the former case, the filename should be
+ * in "human readable" form. In the latter case, the smbc_
+ * functions expect a URL which must be url-encoded. Those
+ * functions decode the URL. If, for example, smbc_readdir()
+ * returned a file name of "abc%20def.txt", passing a path
+ * with this file name attached to smbc_open() would cause
+ * smbc_open to attempt to open the file "abc def.txt" since
+ * the %20 is decoded into a space.
+ *
+ * Set this option to True if the names returned by
+ * smbc_readdir() should be url-encoded such that they can be
+ * passed back to another smbc_ call. Set it to False if the
+ * names returned by smbc_readdir() are to be presented to the
+ * user.
+ *
+ * For backwards compatibility, this option defaults to False.
+ */
+smbc_bool
+smbc_getOptionUrlEncodeReaddirEntries(SMBCCTX *c);
+
+/**
+ * Set whether to url-encode readdir entries.
+ *
+ * There is a difference in the desired return strings from
+ * smbc_readdir() depending upon whether the filenames are to
+ * be displayed to the user, or whether they are to be
+ * appended to the path name passed to smbc_opendir() to call
+ * a further smbc_ function (e.g. open the file with
+ * smbc_open()). In the former case, the filename should be
+ * in "human readable" form. In the latter case, the smbc_
+ * functions expect a URL which must be url-encoded. Those
+ * functions decode the URL. If, for example, smbc_readdir()
+ * returned a file name of "abc%20def.txt", passing a path
+ * with this file name attached to smbc_open() would cause
+ * smbc_open to attempt to open the file "abc def.txt" since
+ * the %20 is decoded into a space.
+ *
+ * Set this option to True if the names returned by
+ * smbc_readdir() should be url-encoded such that they can be
+ * passed back to another smbc_ call. Set it to False if the
+ * names returned by smbc_readdir() are to be presented to the
+ * user.
+ *
+ * For backwards compatibility, this option defaults to False.
+ */
+void
+smbc_setOptionUrlEncodeReaddirEntries(SMBCCTX *c, smbc_bool b);
+
+/**
+ * Get whether to use the same connection for all shares on a server.
+ *
+ * Some Windows versions appear to have a limit to the number
+ * of concurrent SESSIONs and/or TREE CONNECTions. In
+ * one-shot programs (i.e. the program runs and then quickly
+ * ends, thereby shutting down all connections), it is
+ * probably reasonable to establish a new connection for each
+ * share. In long-running applications, the limitation can be
+ * avoided by using only a single connection to each server,
+ * and issuing a new TREE CONNECT when the share is accessed.
+ */
+smbc_bool
+smbc_getOptionOneSharePerServer(SMBCCTX *c);
+
+/**
+ * Set whether to use the same connection for all shares on a server.
+ *
+ * Some Windows versions appear to have a limit to the number
+ * of concurrent SESSIONs and/or TREE CONNECTions. In
+ * one-shot programs (i.e. the program runs and then quickly
+ * ends, thereby shutting down all connections), it is
+ * probably reasonable to establish a new connection for each
+ * share. In long-running applications, the limitation can be
+ * avoided by using only a single connection to each server,
+ * and issuing a new TREE CONNECT when the share is accessed.
+ */
+void
+smbc_setOptionOneSharePerServer(SMBCCTX *c, smbc_bool b);
+
+/** Get whether to enable use of kerberos */
+smbc_bool
+smbc_getOptionUseKerberos(SMBCCTX *c);
+
+/** Set whether to enable use of kerberos */
+void
+smbc_setOptionUseKerberos(SMBCCTX *c, smbc_bool b);
+
+/** Get whether to fallback after kerberos */
+smbc_bool
+smbc_getOptionFallbackAfterKerberos(SMBCCTX *c);
+
+/** Set whether to fallback after kerberos */
+void
+smbc_setOptionFallbackAfterKerberos(SMBCCTX *c, smbc_bool b);
+
+/** Get whether to automatically select anonymous login */
+smbc_bool
+smbc_getOptionNoAutoAnonymousLogin(SMBCCTX *c);
+
+/** Set whether to automatically select anonymous login */
+void
+smbc_setOptionNoAutoAnonymousLogin(SMBCCTX *c, smbc_bool b);
+
+
+
+/*************************************
+ * Getters and setters for FUNCTIONS *
+ *************************************/
+
+/** Get the function for obtaining authentication data */
+smbc_get_auth_data_fn smbc_getFunctionAuthData(SMBCCTX *c);
+
+/** Set the function for obtaining authentication data */
+void smbc_setFunctionAuthData(SMBCCTX *c, smbc_get_auth_data_fn fn);
+
+/** Get the new-style authentication function which includes the context. */
+smbc_get_auth_data_with_context_fn
+smbc_getFunctionAuthDataWithContext(SMBCCTX *c);
+
+/** Set the new-style authentication function which includes the context. */
+void
+smbc_setFunctionAuthDataWithContext(SMBCCTX *c,
+ smbc_get_auth_data_with_context_fn fn);
+
+/** Get the function for checking if a server is still good */
+smbc_check_server_fn smbc_getFunctionCheckServer(SMBCCTX *c);
+
+/** Set the function for checking if a server is still good */
+void smbc_setFunctionCheckServer(SMBCCTX *c, smbc_check_server_fn fn);
+
+/** Get the function for removing a server if unused */
+smbc_remove_unused_server_fn smbc_getFunctionRemoveUnusedServer(SMBCCTX *c);
+
+/** Set the function for removing a server if unused */
+void smbc_setFunctionRemoveUnusedServer(SMBCCTX *c,
+ smbc_remove_unused_server_fn fn);
+
+/** Get the function for adding a cached server */
+smbc_add_cached_srv_fn smbc_getFunctionAddCachedServer(SMBCCTX *c);
+
+/** Set the function for adding a cached server */
+void smbc_setFunctionAddCachedServer(SMBCCTX *c, smbc_add_cached_srv_fn fn);
+
+/** Get the function for server cache lookup */
+smbc_get_cached_srv_fn smbc_getFunctionGetCachedServer(SMBCCTX *c);
+
+/** Set the function for server cache lookup */
+void smbc_setFunctionGetCachedServer(SMBCCTX *c, smbc_get_cached_srv_fn fn);
+
+/** Get the function for server cache removal */
+smbc_remove_cached_srv_fn smbc_getFunctionRemoveCachedServer(SMBCCTX *c);
+
+/** Set the function for server cache removal */
+void smbc_setFunctionRemoveCachedServer(SMBCCTX *c,
+ smbc_remove_cached_srv_fn fn);
+
+/**
+ * Get the function for server cache purging. This function tries to
+ * remove all cached servers (e.g. on disconnect)
+ */
+smbc_purge_cached_fn smbc_getFunctionPurgeCachedServers(SMBCCTX *c);
+
+/**
+ * Set the function for server cache purging. This function tries to
+ * remove all cached servers (e.g. on disconnect)
+ */
+void smbc_setFunctionPurgeCachedServers(SMBCCTX *c,
+ smbc_purge_cached_fn fn);
+
+/** Get the function to store private data of the server cache */
+struct smbc_server_cache * smbc_getServerCacheData(SMBCCTX *c);
+
+/** Set the function to store private data of the server cache */
+void smbc_setServerCacheData(SMBCCTX *c, struct smbc_server_cache * cache);
+
+
+
+/*****************************************************************
+ * Callable functions for files. *
+ * Each callable has a function signature typedef, a declaration *
+ * for the getter, and a declaration for the setter. *
+ *****************************************************************/
+
+typedef SMBCFILE * (*smbc_open_fn)(SMBCCTX *c,
+ const char *fname,
+ int flags,
+ mode_t mode);
+smbc_open_fn smbc_getFunctionOpen(SMBCCTX *c);
+void smbc_setFunctionOpen(SMBCCTX *c, smbc_open_fn fn);
+
+typedef SMBCFILE * (*smbc_creat_fn)(SMBCCTX *c,
+ const char *path,
+ mode_t mode);
+smbc_creat_fn smbc_getFunctionCreat(SMBCCTX *c);
+void smbc_setFunctionCreat(SMBCCTX *c, smbc_creat_fn);
+
+typedef ssize_t (*smbc_read_fn)(SMBCCTX *c,
+ SMBCFILE *file,
+ void *buf,
+ size_t count);
+smbc_read_fn smbc_getFunctionRead(SMBCCTX *c);
+void smbc_setFunctionRead(SMBCCTX *c, smbc_read_fn fn);
+
+typedef ssize_t (*smbc_write_fn)(SMBCCTX *c,
+ SMBCFILE *file,
+ const void *buf,
+ size_t count);
+smbc_write_fn smbc_getFunctionWrite(SMBCCTX *c);
+void smbc_setFunctionWrite(SMBCCTX *c, smbc_write_fn fn);
+
+typedef int (*smbc_unlink_fn)(SMBCCTX *c,
+ const char *fname);
+smbc_unlink_fn smbc_getFunctionUnlink(SMBCCTX *c);
+void smbc_setFunctionUnlink(SMBCCTX *c, smbc_unlink_fn fn);
+
+typedef int (*smbc_rename_fn)(SMBCCTX *ocontext,
+ const char *oname,
+ SMBCCTX *ncontext,
+ const char *nname);
+smbc_rename_fn smbc_getFunctionRename(SMBCCTX *c);
+void smbc_setFunctionRename(SMBCCTX *c, smbc_rename_fn fn);
+
+typedef off_t (*smbc_lseek_fn)(SMBCCTX *c,
+ SMBCFILE * file,
+ off_t offset,
+ int whence);
+smbc_lseek_fn smbc_getFunctionLseek(SMBCCTX *c);
+void smbc_setFunctionLseek(SMBCCTX *c, smbc_lseek_fn fn);
+
+typedef int (*smbc_stat_fn)(SMBCCTX *c,
+ const char *fname,
+ struct stat *st);
+smbc_stat_fn smbc_getFunctionStat(SMBCCTX *c);
+void smbc_setFunctionStat(SMBCCTX *c, smbc_stat_fn fn);
+
+typedef int (*smbc_fstat_fn)(SMBCCTX *c,
+ SMBCFILE *file,
+ struct stat *st);
+smbc_fstat_fn smbc_getFunctionFstat(SMBCCTX *c);
+void smbc_setFunctionFstat(SMBCCTX *c, smbc_fstat_fn fn);
+
+typedef int (*smbc_ftruncate_fn)(SMBCCTX *c,
+ SMBCFILE *f,
+ off_t size);
+smbc_ftruncate_fn smbc_getFunctionFtruncate(SMBCCTX *c);
+void smbc_setFunctionFtruncate(SMBCCTX *c, smbc_ftruncate_fn fn);
+
+typedef int (*smbc_close_fn)(SMBCCTX *c,
+ SMBCFILE *file);
+smbc_close_fn smbc_getFunctionClose(SMBCCTX *c);
+void smbc_setFunctionClose(SMBCCTX *c, smbc_close_fn fn);
+
+
+
+/*****************************************************************
+ * Callable functions for directories. *
+ * Each callable has a function signature typedef, a declaration *
+ * for the getter, and a declaration for the setter. *
+ *****************************************************************/
+
+typedef SMBCFILE * (*smbc_opendir_fn)(SMBCCTX *c,
+ const char *fname);
+smbc_opendir_fn smbc_getFunctionOpendir(SMBCCTX *c);
+void smbc_setFunctionOpendir(SMBCCTX *c, smbc_opendir_fn fn);
+
+typedef int (*smbc_closedir_fn)(SMBCCTX *c,
+ SMBCFILE *dir);
+smbc_closedir_fn smbc_getFunctionClosedir(SMBCCTX *c);
+void smbc_setFunctionClosedir(SMBCCTX *c, smbc_closedir_fn fn);
+
+typedef struct smbc_dirent * (*smbc_readdir_fn)(SMBCCTX *c,
+ SMBCFILE *dir);
+smbc_readdir_fn smbc_getFunctionReaddir(SMBCCTX *c);
+void smbc_setFunctionReaddir(SMBCCTX *c, smbc_readdir_fn fn);
+
+typedef int (*smbc_getdents_fn)(SMBCCTX *c,
+ SMBCFILE *dir,
+ struct smbc_dirent *dirp,
+ int count);
+smbc_getdents_fn smbc_getFunctionGetdents(SMBCCTX *c);
+void smbc_setFunctionGetdents(SMBCCTX *c, smbc_getdents_fn fn);
+
+typedef int (*smbc_mkdir_fn)(SMBCCTX *c,
+ const char *fname,
+ mode_t mode);
+smbc_mkdir_fn smbc_getFunctionMkdir(SMBCCTX *c);
+void smbc_setFunctionMkdir(SMBCCTX *c, smbc_mkdir_fn fn);
+
+typedef int (*smbc_rmdir_fn)(SMBCCTX *c,
+ const char *fname);
+smbc_rmdir_fn smbc_getFunctionRmdir(SMBCCTX *c);
+void smbc_setFunctionRmdir(SMBCCTX *c, smbc_rmdir_fn fn);
+
+typedef off_t (*smbc_telldir_fn)(SMBCCTX *c,
+ SMBCFILE *dir);
+smbc_telldir_fn smbc_getFunctionTelldir(SMBCCTX *c);
+void smbc_setFunctionTelldir(SMBCCTX *c, smbc_telldir_fn fn);
+
+typedef int (*smbc_lseekdir_fn)(SMBCCTX *c,
+ SMBCFILE *dir,
+ off_t offset);
+smbc_lseekdir_fn smbc_getFunctionLseekdir(SMBCCTX *c);
+void smbc_setFunctionLseekdir(SMBCCTX *c, smbc_lseekdir_fn fn);
+
+typedef int (*smbc_fstatdir_fn)(SMBCCTX *c,
+ SMBCFILE *dir,
+ struct stat *st);
+smbc_fstatdir_fn smbc_getFunctionFstatdir(SMBCCTX *c);
+void smbc_setFunctionFstatdir(SMBCCTX *c, smbc_fstatdir_fn fn);
+
+
+
+/*****************************************************************
+ * Callable functions applicable to both files and directories. *
+ * Each callable has a function signature typedef, a declaration *
+ * for the getter, and a declaration for the setter. *
+ *****************************************************************/
+
+typedef int (*smbc_chmod_fn)(SMBCCTX *c,
+ const char *fname,
+ mode_t mode);
+smbc_chmod_fn smbc_getFunctionChmod(SMBCCTX *c);
+void smbc_setFunctionChmod(SMBCCTX *c, smbc_chmod_fn fn);
+
+typedef int (*smbc_utimes_fn)(SMBCCTX *c,
+ const char *fname,
+ struct timeval *tbuf);
+smbc_utimes_fn smbc_getFunctionUtimes(SMBCCTX *c);
+void smbc_setFunctionUtimes(SMBCCTX *c, smbc_utimes_fn fn);
+
+typedef int (*smbc_setxattr_fn)(SMBCCTX *context,
+ const char *fname,
+ const char *name,
+ const void *value,
+ size_t size,
+ int flags);
+smbc_setxattr_fn smbc_getFunctionSetxattr(SMBCCTX *c);
+void smbc_setFunctionSetxattr(SMBCCTX *c, smbc_setxattr_fn fn);
+
+typedef int (*smbc_getxattr_fn)(SMBCCTX *context,
+ const char *fname,
+ const char *name,
+ const void *value,
+ size_t size);
+smbc_getxattr_fn smbc_getFunctionGetxattr(SMBCCTX *c);
+void smbc_setFunctionGetxattr(SMBCCTX *c, smbc_getxattr_fn fn);
+
+typedef int (*smbc_removexattr_fn)(SMBCCTX *context,
+ const char *fname,
+ const char *name);
+smbc_removexattr_fn smbc_getFunctionRemovexattr(SMBCCTX *c);
+void smbc_setFunctionRemovexattr(SMBCCTX *c, smbc_removexattr_fn fn);
+
+typedef int (*smbc_listxattr_fn)(SMBCCTX *context,
+ const char *fname,
+ char *list,
+ size_t size);
+smbc_listxattr_fn smbc_getFunctionListxattr(SMBCCTX *c);
+void smbc_setFunctionListxattr(SMBCCTX *c, smbc_listxattr_fn fn);
+
+
+
+/*****************************************************************
+ * Callable functions for printing. *
+ * Each callable has a function signature typedef, a declaration *
+ * for the getter, and a declaration for the setter. *
+ *****************************************************************/
+
+typedef int (*smbc_print_file_fn)(SMBCCTX *c_file,
+ const char *fname,
+ SMBCCTX *c_print,
+ const char *printq);
+smbc_print_file_fn smbc_getFunctionPrintFile(SMBCCTX *c);
+void smbc_setFunctionPrintFile(SMBCCTX *c, smbc_print_file_fn fn);
+
+typedef SMBCFILE * (*smbc_open_print_job_fn)(SMBCCTX *c,
+ const char *fname);
+smbc_open_print_job_fn smbc_getFunctionOpenPrintJob(SMBCCTX *c);
+void smbc_setFunctionOpenPrintJob(SMBCCTX *c,
+ smbc_open_print_job_fn fn);
+
+typedef int (*smbc_list_print_jobs_fn)(SMBCCTX *c,
+ const char *fname,
+ smbc_list_print_job_fn fn);
+smbc_list_print_jobs_fn smbc_getFunctionListPrintJobs(SMBCCTX *c);
+void smbc_setFunctionListPrintJobs(SMBCCTX *c,
+ smbc_list_print_jobs_fn fn);
+
+typedef int (*smbc_unlink_print_job_fn)(SMBCCTX *c,
+ const char *fname,
+ int id);
+smbc_unlink_print_job_fn smbc_getFunctionUnlinkPrintJob(SMBCCTX *c);
+void smbc_setFunctionUnlinkPrintJob(SMBCCTX *c,
+ smbc_unlink_print_job_fn fn);
+
+
+/**@ingroup misc
+ * Create a new SBMCCTX (a context).
+ *
+ * Must be called before the context is passed to smbc_context_init()
+ *
+ * @return The given SMBCCTX pointer on success, NULL on error with errno set:
+ * - ENOMEM Out of memory
+ *
+ * @see smbc_free_context(), smbc_init_context()
+ *
+ * @note Do not forget to smbc_init_context() the returned SMBCCTX pointer !
+ */
+SMBCCTX * smbc_new_context(void);
+
+/**@ingroup misc
+ * Delete a SBMCCTX (a context) acquired from smbc_new_context().
+ *
+ * The context will be deleted if possible.
+ *
+ * @param context A pointer to a SMBCCTX obtained from smbc_new_context()
+ *
+ * @param shutdown_ctx If 1, all connections and files will be closed even if they are busy.
+ *
+ *
+ * @return Returns 0 on succes. Returns 1 on failure with errno set:
+ * - EBUSY Server connections are still used, Files are open or cache
+ * could not be purged
+ * - EBADF context == NULL
+ *
+ * @see smbc_new_context()
+ *
+ * @note It is advised to clean up all the contexts with shutdown_ctx set to 1
+ * just before exit()'ing. When shutdown_ctx is 0, this function can be
+ * use in periodical cleanup functions for example.
+ */
+int smbc_free_context(SMBCCTX * context, int shutdown_ctx);
+
+
+/**@ingroup misc
+ *
+ * @deprecated. Use smbc_setOption*() functions instead.
+ */
+void
+smbc_option_set(SMBCCTX *context,
+ char *option_name,
+ ... /* option_value */);
+
+/*
+ * @deprecated. Use smbc_getOption*() functions instead.
+ */
+void *
+smbc_option_get(SMBCCTX *context,
+ char *option_name);
+
+/**@ingroup misc
+ * Initialize a SBMCCTX (a context).
+ *
+ * Must be called before using any SMBCCTX API function
+ *
+ * @param context A pointer to a SMBCCTX obtained from smbc_new_context()
+ *
+ * @return A pointer to the given SMBCCTX on success,
+ * NULL on error with errno set:
+ * - EBADF NULL context given
+ * - ENOMEM Out of memory
+ * - ENOENT The smb.conf file would not load
+ *
+ * @see smbc_new_context()
+ *
+ * @note my_context = smbc_init_context(smbc_new_context())
+ * is perfectly safe, but it might leak memory on
+ * smbc_context_init() failure. Avoid this.
+ * You'll have to call smbc_free_context() yourself
+ * on failure.
+ */
+
+SMBCCTX * smbc_init_context(SMBCCTX * context);
+
+/**@ingroup misc
+ * Initialize the samba client library.
+ *
+ * Must be called before using any of the smbclient API function
+ *
+ * @param fn The function that will be called to obtaion
+ * authentication credentials.
+ *
+ * @param debug Allows caller to set the debug level. Can be
+ * changed in smb.conf file. Allows caller to set
+ * debugging if no smb.conf.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - ENOMEM Out of memory
+ * - ENOENT The smb.conf file would not load
+ *
+ */
+
+int smbc_init(smbc_get_auth_data_fn fn, int debug);
+
+/**@ingroup misc
+ * Set or retrieve the compatibility library's context pointer
+ *
+ * @param context New context to use, or NULL. If a new context is provided,
+ * it must have allocated with smbc_new_context() and
+ * initialized with smbc_init_context(), followed, optionally,
+ * by some manual changes to some of the non-internal fields.
+ *
+ * @return The old context.
+ *
+ * @see smbc_new_context(), smbc_init_context(), smbc_init()
+ *
+ * @note This function may be called prior to smbc_init() to force
+ * use of the next context without any internal calls to
+ * smbc_new_context() or smbc_init_context(). It may also
+ * be called after smbc_init() has already called those two
+ * functions, to replace the existing context with a new one.
+ * Care should be taken, in this latter case, to ensure that
+ * the server cache and any data allocated by the
+ * authentication functions have been freed, if necessary.
+ */
+
+SMBCCTX * smbc_set_context(SMBCCTX * new_context);
+
+/**@ingroup file
+ * Open a file on an SMB server.
+ *
+ * @param furl The smb url of the file to be opened.
+ *
+ * @param flags Is one of O_RDONLY, O_WRONLY or O_RDWR which
+ * request opening the file read-only,write-only
+ * or read/write. flags may also be bitwise-or'd with
+ * one or more of the following:
+ * O_CREAT - If the file does not exist it will be
+ * created.
+ * O_EXCL - When used with O_CREAT, if the file
+ * already exists it is an error and the open will
+ * fail.
+ * O_TRUNC - If the file already exists it will be
+ * truncated.
+ * O_APPEND The file is opened in append mode
+ *
+ * @param mode mode specifies the permissions to use if a new
+ * file is created. It is modified by the
+ * process's umask in the usual way: the permissions
+ * of the created file are (mode & ~umask)
+ *
+ * Not currently use, but there for future use.
+ * We will map this to SYSTEM, HIDDEN, etc bits
+ * that reverses the mapping that smbc_fstat does.
+ *
+ * @return Valid file handle, < 0 on error with errno set:
+ * - ENOMEM Out of memory
+ * - EINVAL if an invalid parameter passed, like no
+ * file, or smbc_init not called.
+ * - EEXIST pathname already exists and O_CREAT and
+ * O_EXCL were used.
+ * - EISDIR pathname refers to a directory and
+ * the access requested involved writing.
+ * - EACCES The requested access to the file is not
+ * allowed
+ * - ENODEV The requested share does not exist
+ * - ENOTDIR A file on the path is not a directory
+ * - ENOENT A directory component in pathname does
+ * not exist.
+ *
+ * @see smbc_creat()
+ *
+ * @note This call uses an underlying routine that may create
+ * a new connection to the server specified in the URL.
+ * If the credentials supplied in the URL, or via the
+ * auth_fn in the smbc_init call, fail, this call will
+ * try again with an empty username and password. This
+ * often gets mapped to the guest account on some machines.
+ */
+
+int smbc_open(const char *furl, int flags, mode_t mode);
+
+/**@ingroup file
+ * Create a file on an SMB server.
+ *
+ * Same as calling smbc_open() with flags = O_CREAT|O_WRONLY|O_TRUNC
+ *
+ * @param furl The smb url of the file to be created
+ *
+ * @param mode mode specifies the permissions to use if a new
+ * file is created. It is modified by the
+ * process's umask in the usual way: the permissions
+ * of the created file are (mode & ~umask)
+ *
+ * NOTE, the above is not true. We are dealing with
+ * an SMB server, which has no concept of a umask!
+ *
+ * @return Valid file handle, < 0 on error with errno set:
+ * - ENOMEM Out of memory
+ * - EINVAL if an invalid parameter passed, like no
+ * file, or smbc_init not called.
+ * - EEXIST pathname already exists and O_CREAT and
+ * O_EXCL were used.
+ * - EISDIR pathname refers to a directory and
+ * the access requested involved writing.
+ * - EACCES The requested access to the file is not
+ * allowed
+ * - ENOENT A directory component in pathname does
+ * not exist.
+ * - ENODEV The requested share does not exist.
+ * @see smbc_open()
+ *
+ */
+
+int smbc_creat(const char *furl, mode_t mode);
+
+/**@ingroup file
+ * Read from a file using an opened file handle.
+ *
+ * @param fd Open file handle from smbc_open() or smbc_creat()
+ *
+ * @param buf Pointer to buffer to recieve read data
+ *
+ * @param bufsize Size of buf in bytes
+ *
+ * @return Number of bytes read, < 0 on error with errno set:
+ * - EISDIR fd refers to a directory
+ * - EBADF fd is not a valid file descriptor or
+ * is not open for reading.
+ * - EINVAL fd is attached to an object which is
+ * unsuitable for reading, or no buffer passed or
+ * smbc_init not called.
+ *
+ * @see smbc_open(), smbc_write()
+ *
+ */
+ssize_t smbc_read(int fd, void *buf, size_t bufsize);
+
+
+/**@ingroup file
+ * Write to a file using an opened file handle.
+ *
+ * @param fd Open file handle from smbc_open() or smbc_creat()
+ *
+ * @param buf Pointer to buffer to recieve read data
+ *
+ * @param bufsize Size of buf in bytes
+ *
+ * @return Number of bytes written, < 0 on error with errno set:
+ * - EISDIR fd refers to a directory.
+ * - EBADF fd is not a valid file descriptor or
+ * is not open for reading.
+ * - EINVAL fd is attached to an object which is
+ * unsuitable for reading, or no buffer passed or
+ * smbc_init not called.
+ *
+ * @see smbc_open(), smbc_read()
+ *
+ */
+ssize_t smbc_write(int fd, const void *buf, size_t bufsize);
+
+
+/**@ingroup file
+ * Seek to a specific location in a file.
+ *
+ * @param fd Open file handle from smbc_open() or smbc_creat()
+ *
+ * @param offset Offset in bytes from whence
+ *
+ * @param whence A location in the file:
+ * - SEEK_SET The offset is set to offset bytes from
+ * the beginning of the file
+ * - SEEK_CUR The offset is set to current location
+ * plus offset bytes.
+ * - SEEK_END The offset is set to the size of the
+ * file plus offset bytes.
+ *
+ * @return Upon successful completion, lseek returns the
+ * resulting offset location as measured in bytes
+ * from the beginning of the file. Otherwise, a value
+ * of (off_t)-1 is returned and errno is set to
+ * indicate the error:
+ * - EBADF Fildes is not an open file descriptor.
+ * - EINVAL Whence is not a proper value or smbc_init
+ * not called.
+ *
+ * @todo Are all the whence values really supported?
+ *
+ * @todo Are errno values complete and correct?
+ */
+off_t smbc_lseek(int fd, off_t offset, int whence);
+
+
+/**@ingroup file
+ * Close an open file handle.
+ *
+ * @param fd The file handle to close
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EBADF fd isn't a valid open file descriptor
+ * - EINVAL smbc_init() failed or has not been called
+ *
+ * @see smbc_open(), smbc_creat()
+ */
+int smbc_close(int fd);
+
+
+/**@ingroup directory
+ * Unlink (delete) a file or directory.
+ *
+ * @param furl The smb url of the file to delete
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EACCES or EPERM Write access to the directory
+ * containing pathname is not allowed or one
+ * of the directories in pathname did not allow
+ * search (execute) permission
+ * - ENOENT A directory component in pathname does
+ * not exist
+ * - EINVAL NULL was passed in the file param or
+ * smbc_init not called.
+ * - EACCES You do not have access to the file
+ * - ENOMEM Insufficient kernel memory was available
+ *
+ * @see smbc_rmdir()s
+ *
+ * @todo Are errno values complete and correct?
+ */
+int smbc_unlink(const char *furl);
+
+
+/**@ingroup directory
+ * Rename or move a file or directory.
+ *
+ * @param ourl The original smb url (source url) of file or
+ * directory to be moved
+ *
+ * @param nurl The new smb url (destination url) of the file
+ * or directory after the move. Currently nurl must
+ * be on the same share as ourl.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EISDIR nurl is an existing directory, but ourl is
+ * not a directory.
+ * - EEXIST nurl is a non-empty directory,
+ * i.e., contains entries other than "." and ".."
+ * - EINVAL The new url contained a path prefix
+ * of the old, or, more generally, an attempt was
+ * made to make a directory a subdirectory of itself
+ * or smbc_init not called.
+ * - ENOTDIR A component used as a directory in ourl
+ * or nurl path is not, in fact, a directory. Or,
+ * ourl is a directory, and newpath exists but is not
+ * a directory.
+ * - EACCES or EPERM Write access to the directory
+ * containing ourl or nurl is not allowed for the
+ * process's effective uid, or one of the
+ * directories in ourl or nurl did not allow search
+ * (execute) permission, or ourl was a directory
+ * and did not allow write permission.
+ * - ENOENT A directory component in ourl or nurl
+ * does not exist.
+ * - EXDEV Rename across shares not supported.
+ * - ENOMEM Insufficient kernel memory was available.
+ * - EEXIST The target file, nurl, already exists.
+ *
+ *
+ * @todo Are we going to support copying when urls are not on the same
+ * share? I say no... NOTE. I agree for the moment.
+ *
+ */
+int smbc_rename(const char *ourl, const char *nurl);
+
+
+/**@ingroup directory
+ * Open a directory used to obtain directory entries.
+ *
+ * @param durl The smb url of the directory to open
+ *
+ * @return Valid directory handle. < 0 on error with errno set:
+ * - EACCES Permission denied.
+ * - EINVAL A NULL file/URL was passed, or the URL would
+ * not parse, or was of incorrect form or smbc_init not
+ * called.
+ * - ENOENT durl does not exist, or name is an
+ * - ENOMEM Insufficient memory to complete the
+ * operation.
+ * - ENOTDIR name is not a directory.
+ * - EPERM the workgroup could not be found.
+ * - ENODEV the workgroup or server could not be found.
+ *
+ * @see smbc_getdents(), smbc_readdir(), smbc_closedir()
+ *
+ */
+int smbc_opendir(const char *durl);
+
+
+/**@ingroup directory
+ * Close a directory handle opened by smbc_opendir().
+ *
+ * @param dh Directory handle to close
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EBADF dh is an invalid directory handle
+ *
+ * @see smbc_opendir()
+ */
+int smbc_closedir(int dh);
+
+
+/**@ingroup directory
+ * Get multiple directory entries.
+ *
+ * smbc_getdents() reads as many dirent structures from the an open
+ * directory handle into a specified memory area as will fit.
+ *
+ * @param dh Valid directory as returned by smbc_opendir()
+ *
+ * @param dirp pointer to buffer that will receive the directory
+ * entries.
+ *
+ * @param count The size of the dirp buffer in bytes
+ *
+ * @returns If any dirents returned, return will indicate the
+ * total size. If there were no more dirents available,
+ * 0 is returned. < 0 indicates an error.
+ * - EBADF Invalid directory handle
+ * - EINVAL Result buffer is too small or smbc_init
+ * not called.
+ * - ENOENT No such directory.
+ * @see , smbc_dirent, smbc_readdir(), smbc_open()
+ *
+ * @todo Are errno values complete and correct?
+ *
+ * @todo Add example code so people know how to parse buffers.
+ */
+int smbc_getdents(unsigned int dh, struct smbc_dirent *dirp, int count);
+
+
+/**@ingroup directory
+ * Get a single directory entry.
+ *
+ * @param dh Valid directory as returned by smbc_opendir()
+ *
+ * @return A pointer to a smbc_dirent structure, or NULL if an
+ * error occurs or end-of-directory is reached:
+ * - EBADF Invalid directory handle
+ * - EINVAL smbc_init() failed or has not been called
+ *
+ * @see smbc_dirent, smbc_getdents(), smbc_open()
+ */
+struct smbc_dirent* smbc_readdir(unsigned int dh);
+
+
+/**@ingroup directory
+ * Get the current directory offset.
+ *
+ * smbc_telldir() may be used in conjunction with smbc_readdir() and
+ * smbc_lseekdir().
+ *
+ * @param dh Valid directory as returned by smbc_opendir()
+ *
+ * @return The current location in the directory stream or -1
+ * if an error occur. The current location is not
+ * an offset. Becuase of the implementation, it is a
+ * handle that allows the library to find the entry
+ * later.
+ * - EBADF dh is not a valid directory handle
+ * - EINVAL smbc_init() failed or has not been called
+ * - ENOTDIR if dh is not a directory
+ *
+ * @see smbc_readdir()
+ *
+ */
+off_t smbc_telldir(int dh);
+
+
+/**@ingroup directory
+ * lseek on directories.
+ *
+ * smbc_lseekdir() may be used in conjunction with smbc_readdir() and
+ * smbc_telldir(). (rewind by smbc_lseekdir(fd, NULL))
+ *
+ * @param fd Valid directory as returned by smbc_opendir()
+ *
+ * @param offset The offset (as returned by smbc_telldir). Can be
+ * NULL, in which case we will rewind
+ *
+ * @return 0 on success, -1 on failure
+ * - EBADF dh is not a valid directory handle
+ * - ENOTDIR if dh is not a directory
+ * - EINVAL offset did not refer to a valid dirent or
+ * smbc_init not called.
+ *
+ * @see smbc_telldir()
+ *
+ *
+ * @todo In what does the reture and errno values mean?
+ */
+int smbc_lseekdir(int fd, off_t offset);
+
+/**@ingroup directory
+ * Create a directory.
+ *
+ * @param durl The url of the directory to create
+ *
+ * @param mode Specifies the permissions to use. It is modified
+ * by the process's umask in the usual way: the
+ * permissions of the created file are (mode & ~umask).
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EEXIST directory url already exists
+ * - EACCES The parent directory does not allow write
+ * permission to the process, or one of the directories
+ * - ENOENT A directory component in pathname does not
+ * exist.
+ * - EINVAL NULL durl passed or smbc_init not called.
+ * - ENOMEM Insufficient memory was available.
+ *
+ * @see smbc_rmdir()
+ *
+ */
+int smbc_mkdir(const char *durl, mode_t mode);
+
+
+/**@ingroup directory
+ * Remove a directory.
+ *
+ * @param durl The smb url of the directory to remove
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EACCES or EPERM Write access to the directory
+ * containing pathname was not allowed.
+ * - EINVAL durl is NULL or smbc_init not called.
+ * - ENOENT A directory component in pathname does not
+ * exist.
+ * - ENOTEMPTY directory contains entries.
+ * - ENOMEM Insufficient kernel memory was available.
+ *
+ * @see smbc_mkdir(), smbc_unlink()
+ *
+ * @todo Are errno values complete and correct?
+ */
+int smbc_rmdir(const char *durl);
+
+
+/**@ingroup attribute
+ * Get information about a file or directory.
+ *
+ * @param url The smb url to get information for
+ *
+ * @param st pointer to a buffer that will be filled with
+ * standard Unix struct stat information.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - ENOENT A component of the path file_name does not
+ * exist.
+ * - EINVAL a NULL url was passed or smbc_init not called.
+ * - EACCES Permission denied.
+ * - ENOMEM Out of memory
+ * - ENOTDIR The target dir, url, is not a directory.
+ *
+ * @see Unix stat()
+ *
+ */
+int smbc_stat(const char *url, struct stat *st);
+
+
+/**@ingroup attribute
+ * Get file information via an file descriptor.
+ *
+ * @param fd Open file handle from smbc_open() or smbc_creat()
+ *
+ * @param st pointer to a buffer that will be filled with
+ * standard Unix struct stat information.
+ *
+ * @return EBADF filedes is bad.
+ * - EACCES Permission denied.
+ * - EBADF fd is not a valid file descriptor
+ * - EINVAL Problems occurred in the underlying routines
+ * or smbc_init not called.
+ * - ENOMEM Out of memory
+ *
+ * @see smbc_stat(), Unix stat()
+ *
+ */
+int smbc_fstat(int fd, struct stat *st);
+
+
+/**@ingroup attribute
+ * Truncate a file given a file descriptor
+ *
+ * @param fd Open file handle from smbc_open() or smbc_creat()
+ *
+ * @param size size to truncate the file to
+ *
+ * @return EBADF filedes is bad.
+ * - EACCES Permission denied.
+ * - EBADF fd is not a valid file descriptor
+ * - EINVAL Problems occurred in the underlying routines
+ * or smbc_init not called.
+ * - ENOMEM Out of memory
+ *
+ * @see , Unix ftruncate()
+ *
+ */
+int smbc_ftruncate(int fd, off_t size);
+
+
+/**@ingroup attribute
+ * Change the permissions of a file.
+ *
+ * @param url The smb url of the file or directory to change
+ * permissions of
+ *
+ * @param mode The permissions to set:
+ * - Put good explaination of permissions here!
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EPERM The effective UID does not match the owner
+ * of the file, and is not zero
+ * - ENOENT The file does not exist.
+ * - ENOMEM Insufficient was available.
+ * - ENOENT file or directory does not exist
+ *
+ * @todo Actually implement this fuction?
+ *
+ * @todo Are errno values complete and correct?
+ */
+int smbc_chmod(const char *url, mode_t mode);
+
+/**
+ * @ingroup attribute
+ * Change the last modification time on a file
+ *
+ * @param url The smb url of the file or directory to change
+ * the modification time of
+ *
+ * @param tbuf An array of two timeval structures which contains,
+ * respectively, the desired access and modification times.
+ * NOTE: Only the tv_sec field off each timeval structure is
+ * used. The tv_usec (microseconds) portion is ignored.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL The client library is not properly initialized
+ * - EPERM Permission was denied.
+ *
+ */
+int smbc_utimes(const char *url, struct timeval *tbuf);
+
+#ifdef HAVE_UTIME_H
+/**
+ * @ingroup attribute
+ * Change the last modification time on a file
+ *
+ * @param url The smb url of the file or directory to change
+ * the modification time of
+ *
+ * @param utbuf A pointer to a utimebuf structure which contains the
+ * desired access and modification times.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL The client library is not properly initialized
+ * - ENOMEM No memory was available for internal needs
+ * - EPERM Permission was denied.
+ *
+ */
+int smbc_utime(const char *fname, struct utimbuf *utbuf);
+#endif
+
+/**@ingroup attribute
+ * Set extended attributes for a file. This is used for modifying a file's
+ * security descriptor (i.e. owner, group, and access control list)
+ *
+ * @param url The smb url of the file or directory to set extended
+ * attributes for.
+ *
+ * @param name The name of an attribute to be changed. Names are of
+ * one of the following forms:
+ *
+ * system.nt_sec_desc.<attribute name>
+ * system.nt_sec_desc.*
+ * system.nt_sec_desc.*+
+ *
+ * where <attribute name> is one of:
+ *
+ * revision
+ * owner
+ * owner+
+ * group
+ * group+
+ * acl:<name or sid>
+ * acl+:<name or sid>
+ *
+ * In the forms "system.nt_sec_desc.*" and
+ * "system.nt_sec_desc.*+", the asterisk and plus signs are
+ * literal, i.e. the string is provided exactly as shown, and
+ * the value parameter should contain a complete security
+ * descriptor with name:value pairs separated by tabs,
+ * commas, or newlines (not spaces!).
+ *
+ * The plus sign ('+') indicates that SIDs should be mapped
+ * to names. Without the plus sign, SIDs are not mapped;
+ * rather they are simply converted to a string format.
+ *
+ * @param value The value to be assigned to the specified attribute name.
+ * This buffer should contain only the attribute value if the
+ * name was of the "system.nt_sec_desc.<attribute_name>"
+ * form. If the name was of the "system.nt_sec_desc.*" form
+ * then a complete security descriptor, with name:value pairs
+ * separated by tabs, commas, or newlines (not spaces!),
+ * should be provided in this value buffer. A complete
+ * security descriptor will contain one or more entries
+ * selected from the following:
+ *
+ * REVISION:<revision number>
+ * OWNER:<sid or name>
+ * GROUP:<sid or name>
+ * ACL:<sid or name>:<type>/<flags>/<mask>
+ *
+ * The revision of the ACL specifies the internal Windows NT
+ * ACL revision for the security descriptor. If not specified
+ * it defaults to 1. Using values other than 1 may cause
+ * strange behaviour.
+ *
+ * The owner and group specify the owner and group sids for
+ * the object. If the attribute name (either '*+' with a
+ * complete security descriptor, or individual 'owner+' or
+ * 'group+' attribute names) ended with a plus sign, the
+ * specified name is resolved to a SID value, using the
+ * server on which the file or directory resides. Otherwise,
+ * the value should be provided in SID-printable format as
+ * S-1-x-y-z, and is used directly. The <sid or name>
+ * associated with the ACL: attribute should be provided
+ * similarly.
+ *
+ * @param size The number of the bytes of data in the value buffer
+ *
+ * @param flags A bit-wise OR of zero or more of the following:
+ * SMBC_XATTR_FLAG_CREATE -
+ * fail if the named attribute already exists
+ * SMBC_XATTR_FLAG_REPLACE -
+ * fail if the attribute does not already exist
+ *
+ * If neither flag is specified, the specified attributes
+ * will be added or replace existing attributes of the same
+ * name, as necessary.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL The client library is not properly initialized
+ * or one of the parameters is not of a correct
+ * form
+ * - ENOMEM No memory was available for internal needs
+ * - EEXIST If the attribute already exists and the flag
+ * SMBC_XATTR_FLAG_CREAT was specified
+ * - ENOATTR If the attribute does not exist and the flag
+ * SMBC_XATTR_FLAG_REPLACE was specified
+ * - EPERM Permission was denied.
+ * - ENOTSUP The referenced file system does not support
+ * extended attributes
+ *
+ * @note Attribute names are compared in a case-insensitive
+ * fashion. All of the following are equivalent, although
+ * the all-lower-case name is the preferred format:
+ * system.nt_sec_desc.owner
+ * SYSTEM.NT_SEC_DESC.OWNER
+ * sYsTeM.nt_sEc_desc.owNER
+ *
+ */
+int smbc_setxattr(const char *url,
+ const char *name,
+ const void *value,
+ size_t size,
+ int flags);
+
+
+/**@ingroup attribute
+ * Set extended attributes for a file. This is used for modifying a file's
+ * security descriptor (i.e. owner, group, and access control list). The
+ * POSIX function which this maps to would act on a symbolic link rather than
+ * acting on what the symbolic link points to, but with no symbolic links in
+ * SMB file systems, this function is functionally identical to
+ * smbc_setxattr().
+ *
+ * @param url The smb url of the file or directory to set extended
+ * attributes for.
+ *
+ * @param name The name of an attribute to be changed. Names are of
+ * one of the following forms:
+ *
+ * system.nt_sec_desc.<attribute name>
+ * system.nt_sec_desc.*
+ * system.nt_sec_desc.*+
+ *
+ * where <attribute name> is one of:
+ *
+ * revision
+ * owner
+ * owner+
+ * group
+ * group+
+ * acl:<name or sid>
+ * acl+:<name or sid>
+ *
+ * In the forms "system.nt_sec_desc.*" and
+ * "system.nt_sec_desc.*+", the asterisk and plus signs are
+ * literal, i.e. the string is provided exactly as shown, and
+ * the value parameter should contain a complete security
+ * descriptor with name:value pairs separated by tabs,
+ * commas, or newlines (not spaces!).
+ *
+ * The plus sign ('+') indicates that SIDs should be mapped
+ * to names. Without the plus sign, SIDs are not mapped;
+ * rather they are simply converted to a string format.
+ *
+ * @param value The value to be assigned to the specified attribute name.
+ * This buffer should contain only the attribute value if the
+ * name was of the "system.nt_sec_desc.<attribute_name>"
+ * form. If the name was of the "system.nt_sec_desc.*" form
+ * then a complete security descriptor, with name:value pairs
+ * separated by tabs, commas, or newlines (not spaces!),
+ * should be provided in this value buffer. A complete
+ * security descriptor will contain one or more entries
+ * selected from the following:
+ *
+ * REVISION:<revision number>
+ * OWNER:<sid or name>
+ * GROUP:<sid or name>
+ * ACL:<sid or name>:<type>/<flags>/<mask>
+ *
+ * The revision of the ACL specifies the internal Windows NT
+ * ACL revision for the security descriptor. If not specified
+ * it defaults to 1. Using values other than 1 may cause
+ * strange behaviour.
+ *
+ * The owner and group specify the owner and group sids for
+ * the object. If the attribute name (either '*+' with a
+ * complete security descriptor, or individual 'owner+' or
+ * 'group+' attribute names) ended with a plus sign, the
+ * specified name is resolved to a SID value, using the
+ * server on which the file or directory resides. Otherwise,
+ * the value should be provided in SID-printable format as
+ * S-1-x-y-z, and is used directly. The <sid or name>
+ * associated with the ACL: attribute should be provided
+ * similarly.
+ *
+ * @param size The number of the bytes of data in the value buffer
+ *
+ * @param flags A bit-wise OR of zero or more of the following:
+ * SMBC_XATTR_FLAG_CREATE -
+ * fail if the named attribute already exists
+ * SMBC_XATTR_FLAG_REPLACE -
+ * fail if the attribute does not already exist
+ *
+ * If neither flag is specified, the specified attributes
+ * will be added or replace existing attributes of the same
+ * name, as necessary.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL The client library is not properly initialized
+ * or one of the parameters is not of a correct
+ * form
+ * - ENOMEM No memory was available for internal needs
+ * - EEXIST If the attribute already exists and the flag
+ * SMBC_XATTR_FLAG_CREAT was specified
+ * - ENOATTR If the attribute does not exist and the flag
+ * SMBC_XATTR_FLAG_REPLACE was specified
+ * - EPERM Permission was denied.
+ * - ENOTSUP The referenced file system does not support
+ * extended attributes
+ *
+ * @note Attribute names are compared in a case-insensitive
+ * fashion. All of the following are equivalent, although
+ * the all-lower-case name is the preferred format:
+ * system.nt_sec_desc.owner
+ * SYSTEM.NT_SEC_DESC.OWNER
+ * sYsTeM.nt_sEc_desc.owNER
+ *
+ */
+int smbc_lsetxattr(const char *url,
+ const char *name,
+ const void *value,
+ size_t size,
+ int flags);
+
+
+/**@ingroup attribute
+ * Set extended attributes for a file. This is used for modifying a file's
+ * security descriptor (i.e. owner, group, and access control list)
+ *
+ * @param fd A file descriptor associated with an open file (as
+ * previously returned by smbc_open(), to get extended
+ * attributes for.
+ *
+ * @param name The name of an attribute to be changed. Names are of
+ * one of the following forms:
+ *
+ * system.nt_sec_desc.<attribute name>
+ * system.nt_sec_desc.*
+ * system.nt_sec_desc.*+
+ *
+ * where <attribute name> is one of:
+ *
+ * revision
+ * owner
+ * owner+
+ * group
+ * group+
+ * acl:<name or sid>
+ * acl+:<name or sid>
+ *
+ * In the forms "system.nt_sec_desc.*" and
+ * "system.nt_sec_desc.*+", the asterisk and plus signs are
+ * literal, i.e. the string is provided exactly as shown, and
+ * the value parameter should contain a complete security
+ * descriptor with name:value pairs separated by tabs,
+ * commas, or newlines (not spaces!).
+ *
+ * The plus sign ('+') indicates that SIDs should be mapped
+ * to names. Without the plus sign, SIDs are not mapped;
+ * rather they are simply converted to a string format.
+ *
+ * @param value The value to be assigned to the specified attribute name.
+ * This buffer should contain only the attribute value if the
+ * name was of the "system.nt_sec_desc.<attribute_name>"
+ * form. If the name was of the "system.nt_sec_desc.*" form
+ * then a complete security descriptor, with name:value pairs
+ * separated by tabs, commas, or newlines (not spaces!),
+ * should be provided in this value buffer. A complete
+ * security descriptor will contain one or more entries
+ * selected from the following:
+ *
+ * REVISION:<revision number>
+ * OWNER:<sid or name>
+ * GROUP:<sid or name>
+ * ACL:<sid or name>:<type>/<flags>/<mask>
+ *
+ * The revision of the ACL specifies the internal Windows NT
+ * ACL revision for the security descriptor. If not specified
+ * it defaults to 1. Using values other than 1 may cause
+ * strange behaviour.
+ *
+ * The owner and group specify the owner and group sids for
+ * the object. If the attribute name (either '*+' with a
+ * complete security descriptor, or individual 'owner+' or
+ * 'group+' attribute names) ended with a plus sign, the
+ * specified name is resolved to a SID value, using the
+ * server on which the file or directory resides. Otherwise,
+ * the value should be provided in SID-printable format as
+ * S-1-x-y-z, and is used directly. The <sid or name>
+ * associated with the ACL: attribute should be provided
+ * similarly.
+ *
+ * @param size The number of the bytes of data in the value buffer
+ *
+ * @param flags A bit-wise OR of zero or more of the following:
+ * SMBC_XATTR_FLAG_CREATE -
+ * fail if the named attribute already exists
+ * SMBC_XATTR_FLAG_REPLACE -
+ * fail if the attribute does not already exist
+ *
+ * If neither flag is specified, the specified attributes
+ * will be added or replace existing attributes of the same
+ * name, as necessary.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL The client library is not properly initialized
+ * or one of the parameters is not of a correct
+ * form
+ * - ENOMEM No memory was available for internal needs
+ * - EEXIST If the attribute already exists and the flag
+ * SMBC_XATTR_FLAG_CREAT was specified
+ * - ENOATTR If the attribute does not exist and the flag
+ * SMBC_XATTR_FLAG_REPLACE was specified
+ * - EPERM Permission was denied.
+ * - ENOTSUP The referenced file system does not support
+ * extended attributes
+ *
+ * @note Attribute names are compared in a case-insensitive
+ * fashion. All of the following are equivalent, although
+ * the all-lower-case name is the preferred format:
+ * system.nt_sec_desc.owner
+ * SYSTEM.NT_SEC_DESC.OWNER
+ * sYsTeM.nt_sEc_desc.owNER
+ *
+ */
+int smbc_fsetxattr(int fd,
+ const char *name,
+ const void *value,
+ size_t size,
+ int flags);
+
+
+/**@ingroup attribute
+ * Get extended attributes for a file.
+ *
+ * @param url The smb url of the file or directory to get extended
+ * attributes for.
+ *
+ * @param name The name of an attribute to be retrieved. Names are of
+ * one of the following forms:
+ *
+ * system.nt_sec_desc.<attribute name>
+ * system.nt_sec_desc.*
+ * system.nt_sec_desc.*+
+ *
+ * where <attribute name> is one of:
+ *
+ * revision
+ * owner
+ * owner+
+ * group
+ * group+
+ * acl:<name or sid>
+ * acl+:<name or sid>
+ *
+ * In the forms "system.nt_sec_desc.*" and
+ * "system.nt_sec_desc.*+", the asterisk and plus signs are
+ * literal, i.e. the string is provided exactly as shown, and
+ * the value parameter will return a complete security
+ * descriptor with name:value pairs separated by tabs,
+ * commas, or newlines (not spaces!).
+ *
+ * The plus sign ('+') indicates that SIDs should be mapped
+ * to names. Without the plus sign, SIDs are not mapped;
+ * rather they are simply converted to a string format.
+ *
+ * @param value A pointer to a buffer in which the value of the specified
+ * attribute will be placed (unless size is zero).
+ *
+ * @param size The size of the buffer pointed to by value. This parameter
+ * may also be zero, in which case the size of the buffer
+ * required to hold the attribute value will be returned,
+ * but nothing will be placed into the value buffer.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL The client library is not properly initialized
+ * or one of the parameters is not of a correct
+ * form
+ * - ENOMEM No memory was available for internal needs
+ * - EEXIST If the attribute already exists and the flag
+ * SMBC_XATTR_FLAG_CREAT was specified
+ * - ENOATTR If the attribute does not exist and the flag
+ * SMBC_XATTR_FLAG_REPLACE was specified
+ * - EPERM Permission was denied.
+ * - ENOTSUP The referenced file system does not support
+ * extended attributes
+ *
+ */
+int smbc_getxattr(const char *url,
+ const char *name,
+ const void *value,
+ size_t size);
+
+
+/**@ingroup attribute
+ * Get extended attributes for a file. The POSIX function which this maps to
+ * would act on a symbolic link rather than acting on what the symbolic link
+ * points to, but with no symbolic links in SMB file systems, this function
+ * is functionally identical to smbc_getxattr().
+ *
+ * @param url The smb url of the file or directory to get extended
+ * attributes for.
+ *
+ * @param name The name of an attribute to be retrieved. Names are of
+ * one of the following forms:
+ *
+ * system.nt_sec_desc.<attribute name>
+ * system.nt_sec_desc.*
+ * system.nt_sec_desc.*+
+ *
+ * where <attribute name> is one of:
+ *
+ * revision
+ * owner
+ * owner+
+ * group
+ * group+
+ * acl:<name or sid>
+ * acl+:<name or sid>
+ *
+ * In the forms "system.nt_sec_desc.*" and
+ * "system.nt_sec_desc.*+", the asterisk and plus signs are
+ * literal, i.e. the string is provided exactly as shown, and
+ * the value parameter will return a complete security
+ * descriptor with name:value pairs separated by tabs,
+ * commas, or newlines (not spaces!).
+ *
+ * The plus sign ('+') indicates that SIDs should be mapped
+ * to names. Without the plus sign, SIDs are not mapped;
+ * rather they are simply converted to a string format.
+ *
+ * @param value A pointer to a buffer in which the value of the specified
+ * attribute will be placed (unless size is zero).
+ *
+ * @param size The size of the buffer pointed to by value. This parameter
+ * may also be zero, in which case the size of the buffer
+ * required to hold the attribute value will be returned,
+ * but nothing will be placed into the value buffer.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL The client library is not properly initialized
+ * or one of the parameters is not of a correct
+ * form
+ * - ENOMEM No memory was available for internal needs
+ * - EEXIST If the attribute already exists and the flag
+ * SMBC_XATTR_FLAG_CREAT was specified
+ * - ENOATTR If the attribute does not exist and the flag
+ * SMBC_XATTR_FLAG_REPLACE was specified
+ * - EPERM Permission was denied.
+ * - ENOTSUP The referenced file system does not support
+ * extended attributes
+ *
+ */
+int smbc_lgetxattr(const char *url,
+ const char *name,
+ const void *value,
+ size_t size);
+
+
+/**@ingroup attribute
+ * Get extended attributes for a file.
+ *
+ * @param fd A file descriptor associated with an open file (as
+ * previously returned by smbc_open(), to get extended
+ * attributes for.
+ *
+ * @param name The name of an attribute to be retrieved. Names are of
+ * one of the following forms:
+ *
+ * system.nt_sec_desc.<attribute name>
+ * system.nt_sec_desc.*
+ * system.nt_sec_desc.*+
+ *
+ * where <attribute name> is one of:
+ *
+ * revision
+ * owner
+ * owner+
+ * group
+ * group+
+ * acl:<name or sid>
+ * acl+:<name or sid>
+ *
+ * In the forms "system.nt_sec_desc.*" and
+ * "system.nt_sec_desc.*+", the asterisk and plus signs are
+ * literal, i.e. the string is provided exactly as shown, and
+ * the value parameter will return a complete security
+ * descriptor with name:value pairs separated by tabs,
+ * commas, or newlines (not spaces!).
+ *
+ * The plus sign ('+') indicates that SIDs should be mapped
+ * to names. Without the plus sign, SIDs are not mapped;
+ * rather they are simply converted to a string format.
+ *
+ * @param value A pointer to a buffer in which the value of the specified
+ * attribute will be placed (unless size is zero).
+ *
+ * @param size The size of the buffer pointed to by value. This parameter
+ * may also be zero, in which case the size of the buffer
+ * required to hold the attribute value will be returned,
+ * but nothing will be placed into the value buffer.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL The client library is not properly initialized
+ * or one of the parameters is not of a correct
+ * form
+ * - ENOMEM No memory was available for internal needs
+ * - EEXIST If the attribute already exists and the flag
+ * SMBC_XATTR_FLAG_CREAT was specified
+ * - ENOATTR If the attribute does not exist and the flag
+ * SMBC_XATTR_FLAG_REPLACE was specified
+ * - EPERM Permission was denied.
+ * - ENOTSUP The referenced file system does not support
+ * extended attributes
+ *
+ */
+int smbc_fgetxattr(int fd,
+ const char *name,
+ const void *value,
+ size_t size);
+
+
+/**@ingroup attribute
+ * Remove extended attributes for a file. This is used for modifying a file's
+ * security descriptor (i.e. owner, group, and access control list)
+ *
+ * @param url The smb url of the file or directory to remove the extended
+ * attributes for.
+ *
+ * @param name The name of an attribute to be removed. Names are of
+ * one of the following forms:
+ *
+ * system.nt_sec_desc.<attribute name>
+ * system.nt_sec_desc.*
+ * system.nt_sec_desc.*+
+ *
+ * where <attribute name> is one of:
+ *
+ * revision
+ * owner
+ * owner+
+ * group
+ * group+
+ * acl:<name or sid>
+ * acl+:<name or sid>
+ *
+ * In the forms "system.nt_sec_desc.*" and
+ * "system.nt_sec_desc.*+", the asterisk and plus signs are
+ * literal, i.e. the string is provided exactly as shown, and
+ * the value parameter will return a complete security
+ * descriptor with name:value pairs separated by tabs,
+ * commas, or newlines (not spaces!).
+ *
+ * The plus sign ('+') indicates that SIDs should be mapped
+ * to names. Without the plus sign, SIDs are not mapped;
+ * rather they are simply converted to a string format.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL The client library is not properly initialized
+ * - ENOMEM No memory was available for internal needs
+ * - EPERM Permission was denied.
+ * - ENOTSUP The referenced file system does not support
+ * extended attributes
+ *
+ */
+int smbc_removexattr(const char *url,
+ const char *name);
+
+
+/**@ingroup attribute
+ * Remove extended attributes for a file. This is used for modifying a file's
+ * security descriptor (i.e. owner, group, and access control list) The POSIX
+ * function which this maps to would act on a symbolic link rather than acting
+ * on what the symbolic link points to, but with no symbolic links in SMB file
+ * systems, this function is functionally identical to smbc_removexattr().
+ *
+ * @param url The smb url of the file or directory to remove the extended
+ * attributes for.
+ *
+ * @param name The name of an attribute to be removed. Names are of
+ * one of the following forms:
+ *
+ * system.nt_sec_desc.<attribute name>
+ * system.nt_sec_desc.*
+ * system.nt_sec_desc.*+
+ *
+ * where <attribute name> is one of:
+ *
+ * revision
+ * owner
+ * owner+
+ * group
+ * group+
+ * acl:<name or sid>
+ * acl+:<name or sid>
+ *
+ * In the forms "system.nt_sec_desc.*" and
+ * "system.nt_sec_desc.*+", the asterisk and plus signs are
+ * literal, i.e. the string is provided exactly as shown, and
+ * the value parameter will return a complete security
+ * descriptor with name:value pairs separated by tabs,
+ * commas, or newlines (not spaces!).
+ *
+ * The plus sign ('+') indicates that SIDs should be mapped
+ * to names. Without the plus sign, SIDs are not mapped;
+ * rather they are simply converted to a string format.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL The client library is not properly initialized
+ * - ENOMEM No memory was available for internal needs
+ * - EPERM Permission was denied.
+ * - ENOTSUP The referenced file system does not support
+ * extended attributes
+ *
+ */
+int smbc_lremovexattr(const char *url,
+ const char *name);
+
+
+/**@ingroup attribute
+ * Remove extended attributes for a file. This is used for modifying a file's
+ * security descriptor (i.e. owner, group, and access control list)
+ *
+ * @param fd A file descriptor associated with an open file (as
+ * previously returned by smbc_open(), to get extended
+ * attributes for.
+ *
+ * @param name The name of an attribute to be removed. Names are of
+ * one of the following forms:
+ *
+ * system.nt_sec_desc.<attribute name>
+ * system.nt_sec_desc.*
+ * system.nt_sec_desc.*+
+ *
+ * where <attribute name> is one of:
+ *
+ * revision
+ * owner
+ * owner+
+ * group
+ * group+
+ * acl:<name or sid>
+ * acl+:<name or sid>
+ *
+ * In the forms "system.nt_sec_desc.*" and
+ * "system.nt_sec_desc.*+", the asterisk and plus signs are
+ * literal, i.e. the string is provided exactly as shown, and
+ * the value parameter will return a complete security
+ * descriptor with name:value pairs separated by tabs,
+ * commas, or newlines (not spaces!).
+ *
+ * The plus sign ('+') indicates that SIDs should be mapped
+ * to names. Without the plus sign, SIDs are not mapped;
+ * rather they are simply converted to a string format.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL The client library is not properly initialized
+ * - ENOMEM No memory was available for internal needs
+ * - EPERM Permission was denied.
+ * - ENOTSUP The referenced file system does not support
+ * extended attributes
+ *
+ */
+int smbc_fremovexattr(int fd,
+ const char *name);
+
+
+/**@ingroup attribute
+ * List the supported extended attribute names associated with a file
+ *
+ * @param url The smb url of the file or directory to list the extended
+ * attributes for.
+ *
+ * @param list A pointer to a buffer in which the list of attributes for
+ * the specified file or directory will be placed (unless
+ * size is zero).
+ *
+ * @param size The size of the buffer pointed to by list. This parameter
+ * may also be zero, in which case the size of the buffer
+ * required to hold all of the attribute names will be
+ * returned, but nothing will be placed into the list buffer.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL The client library is not properly initialized
+ * - ENOMEM No memory was available for internal needs
+ * - EPERM Permission was denied.
+ * - ENOTSUP The referenced file system does not support
+ * extended attributes
+ *
+ * @note This function always returns all attribute names supported
+ * by NT file systems, regardless of whether the referenced
+ * file system supports extended attributes (e.g. a Windows
+ * 2000 machine supports extended attributes if NTFS is used,
+ * but not if FAT is used, and Windows 98 doesn't support
+ * extended attributes at all. Whether this is a feature or
+ * a bug is yet to be decided.
+ */
+int smbc_listxattr(const char *url,
+ char *list,
+ size_t size);
+
+/**@ingroup attribute
+ * List the supported extended attribute names associated with a file The
+ * POSIX function which this maps to would act on a symbolic link rather than
+ * acting on what the symbolic link points to, but with no symbolic links in
+ * SMB file systems, this function is functionally identical to
+ * smbc_listxattr().
+ *
+ * @param url The smb url of the file or directory to list the extended
+ * attributes for.
+ *
+ * @param list A pointer to a buffer in which the list of attributes for
+ * the specified file or directory will be placed (unless
+ * size is zero).
+ *
+ * @param size The size of the buffer pointed to by list. This parameter
+ * may also be zero, in which case the size of the buffer
+ * required to hold all of the attribute names will be
+ * returned, but nothing will be placed into the list buffer.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL The client library is not properly initialized
+ * - ENOMEM No memory was available for internal needs
+ * - EPERM Permission was denied.
+ * - ENOTSUP The referenced file system does not support
+ * extended attributes
+ *
+ * @note This function always returns all attribute names supported
+ * by NT file systems, regardless of wether the referenced
+ * file system supports extended attributes (e.g. a Windows
+ * 2000 machine supports extended attributes if NTFS is used,
+ * but not if FAT is used, and Windows 98 doesn't support
+ * extended attributes at all. Whether this is a feature or
+ * a bug is yet to be decided.
+ */
+int smbc_llistxattr(const char *url,
+ char *list,
+ size_t size);
+
+/**@ingroup attribute
+ * List the supported extended attribute names associated with a file
+ *
+ * @param fd A file descriptor associated with an open file (as
+ * previously returned by smbc_open(), to get extended
+ * attributes for.
+ *
+ * @param list A pointer to a buffer in which the list of attributes for
+ * the specified file or directory will be placed (unless
+ * size is zero).
+ *
+ * @param size The size of the buffer pointed to by list. This parameter
+ * may also be zero, in which case the size of the buffer
+ * required to hold all of the attribute names will be
+ * returned, but nothing will be placed into the list buffer.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL The client library is not properly initialized
+ * - ENOMEM No memory was available for internal needs
+ * - EPERM Permission was denied.
+ * - ENOTSUP The referenced file system does not support
+ * extended attributes
+ *
+ * @note This function always returns all attribute names supported
+ * by NT file systems, regardless of wether the referenced
+ * file system supports extended attributes (e.g. a Windows
+ * 2000 machine supports extended attributes if NTFS is used,
+ * but not if FAT is used, and Windows 98 doesn't support
+ * extended attributes at all. Whether this is a feature or
+ * a bug is yet to be decided.
+ */
+int smbc_flistxattr(int fd,
+ char *list,
+ size_t size);
+
+/**@ingroup print
+ * Print a file given the name in fname. It would be a URL ...
+ *
+ * @param fname The URL of a file on a remote SMB server that the
+ * caller wants printed
+ *
+ * @param printq The URL of the print share to print the file to.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ *
+ * - EINVAL fname or printq was NULL or smbc_init not
+ * not called.
+ * and errors returned by smbc_open
+ *
+ */
+int smbc_print_file(const char *fname, const char *printq);
+
+/**@ingroup print
+ * Open a print file that can be written to by other calls. This simply
+ * does an smbc_open call after checking if there is a file name on the
+ * URI. If not, a temporary name is added ...
+ *
+ * @param fname The URL of the print share to print to?
+ *
+ * @returns A file handle for the print file if successful.
+ * Returns -1 if an error ocurred and errno has the values
+ * - EINVAL fname was NULL or smbc_init not called.
+ * - all errors returned by smbc_open
+ *
+ */
+int smbc_open_print_job(const char *fname);
+
+/**@ingroup print
+ * List the print jobs on a print share, for the moment, pass a callback
+ *
+ * @param purl The url of the print share to list the jobs of
+ *
+ * @param fn Callback function the receives printjob info
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL fname was NULL or smbc_init not called
+ * - EACCES ???
+ */
+int smbc_list_print_jobs(const char *purl, smbc_list_print_job_fn fn);
+
+/**@ingroup print
+ * Delete a print job
+ *
+ * @param purl Url of the print share
+ *
+ * @param id The id of the job to delete
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL fname was NULL or smbc_init not called
+ *
+ * @todo what errno values are possible here?
+ */
+int smbc_unlink_print_job(const char *purl, int id);
+
+/**@ingroup callback
+ * Remove a server from the cached server list it's unused.
+ *
+ * @param context pointer to smb context
+ *
+ * @param srv pointer to server to remove
+ *
+ * @return On success, 0 is returned. 1 is returned if the server could not
+ * be removed. Also useable outside libsmbclient.
+ */
+int smbc_remove_unused_server(SMBCCTX * context, SMBCSRV * srv);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**@ingroup directory
+ * Convert strings of %xx to their single character equivalent.
+ *
+ * @param dest A pointer to a buffer in which the resulting decoded
+ * string should be placed. This may be a pointer to the
+ * same buffer as src_segment.
+ *
+ * @param src A pointer to the buffer containing the URL to be decoded.
+ * Any %xx sequences herein are converted to their single
+ * character equivalent. Each 'x' must be a valid hexadecimal
+ * digit, or that % sequence is left undecoded.
+ *
+ * @param max_dest_len
+ * The size of the buffer pointed to by dest_segment.
+ *
+ * @return The number of % sequences which could not be converted
+ * due to lack of two following hexadecimal digits.
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+int
+smbc_urldecode(char *dest, char * src, size_t max_dest_len);
+#ifdef __cplusplus
+}
+#endif
+
+
+/*
+ * Convert any characters not specifically allowed in a URL into their %xx
+ * equivalent.
+ *
+ * @param dest A pointer to a buffer in which the resulting encoded
+ * string should be placed. Unlike smbc_urldecode(), this
+ * must be a buffer unique from src.
+ *
+ * @param src A pointer to the buffer containing the string to be encoded.
+ * Any character not specifically allowed in a URL is converted
+ * into its hexadecimal value and encoded as %xx.
+ *
+ * @param max_dest_len
+ * The size of the buffer pointed to by dest_segment.
+ *
+ * @returns The remaining buffer length.
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+int
+smbc_urlencode(char * dest, char * src, int max_dest_len);
+#ifdef __cplusplus
+}
+#endif
+
+
+/**@ingroup directory
+ * Return the version of the linked Samba code, and thus the version of the
+ * libsmbclient code.
+ *
+ * @return The version string.
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+const char *
+smbc_version(void);
+#ifdef __cplusplus
+}
+#endif
+
+/**@ingroup misc
+ * Set the users credentials globally so they can be used for DFS
+ * referrals. Probably best to use this function in the smbc_get_auth_data_fn
+ * callback.
+ *
+ * @param workgroup Workgroup of the user.
+ *
+ * @param user Username of user.
+ *
+ * @param password Password of user.
+ *
+ * @param use_kerberos Whether to use Kerberos
+ *
+ * @param signing_state One of these strings (all equivalents on same line):
+ * "off", "no", "false"
+ * "on", "yes", "true", "auto"
+ * "force", "required", "forced"
+ */
+
+void
+smbc_set_credentials(char *workgroup,
+ char *user,
+ char *password,
+ smbc_bool use_kerberos,
+ char *signing_state);
+
+
+/**
+ * @ingroup structure
+ * Structure that contains a client context information
+ * This structure is known as SMBCCTX
+ *
+ * DO NOT DIRECTLY MANIPULATE THE CONTEXT STRUCTURE! The data in the context
+ * structure should all be considered private to the library. It remains here
+ * only for backward compatibility.
+ *
+ * See the comments herein for use of the setter and getter functions which
+ * should now be used for manipulating these values. New features, functions,
+ * etc., are not added here but rather in _internal where they are not
+ * directly visible to applications. This makes it much easier to maintain
+ * ABI compatibility.
+ */
+struct _SMBCCTX
+{
+ /**
+ * debug level
+ *
+ * DEPRECATED:
+ * Use smbc_getDebug() and smbc_setDebug()
+ */
+ int debug DEPRECATED_SMBC_INTERFACE;
+
+ /**
+ * netbios name used for making connections
+ *
+ * DEPRECATED:
+ * Use smbc_getNetbiosName() and smbc_setNetbiosName()
+ */
+ char * netbios_name DEPRECATED_SMBC_INTERFACE;
+
+ /**
+ * workgroup name used for making connections
+ *
+ * DEPRECATED:
+ * Use smbc_getWorkgroup() and smbc_setWorkgroup()
+ */
+ char * workgroup DEPRECATED_SMBC_INTERFACE;
+
+ /**
+ * username used for making connections
+ *
+ * DEPRECATED:
+ * Use smbc_getUser() and smbc_setUser()
+ */
+ char * user DEPRECATED_SMBC_INTERFACE;
+
+ /**
+ * timeout used for waiting on connections / response data (in
+ * milliseconds)
+ *
+ * DEPRECATED:
+ * Use smbc_getTimeout() and smbc_setTimeout()
+ */
+ int timeout DEPRECATED_SMBC_INTERFACE;
+
+ /**
+ * callable functions for files:
+ * For usage and return values see the SMBC_* functions
+ *
+ * DEPRECATED:
+ *
+ * Use smbc_getFunction*() and smbc_setFunction*(), e.g.
+ * smbc_getFunctionOpen(), smbc_setFunctionUnlink(), etc.
+ */
+ smbc_open_fn open DEPRECATED_SMBC_INTERFACE;
+ smbc_creat_fn creat DEPRECATED_SMBC_INTERFACE;
+ smbc_read_fn read DEPRECATED_SMBC_INTERFACE;
+ smbc_write_fn write DEPRECATED_SMBC_INTERFACE;
+ smbc_unlink_fn unlink DEPRECATED_SMBC_INTERFACE;
+ smbc_rename_fn rename DEPRECATED_SMBC_INTERFACE;
+ smbc_lseek_fn lseek DEPRECATED_SMBC_INTERFACE;
+ smbc_stat_fn stat DEPRECATED_SMBC_INTERFACE;
+ smbc_fstat_fn fstat DEPRECATED_SMBC_INTERFACE;
+#if 0 /* internal */
+ smbc_ftruncate_fn ftruncate_fn;
+#endif
+ smbc_close_fn close_fn DEPRECATED_SMBC_INTERFACE;
+ smbc_opendir_fn opendir DEPRECATED_SMBC_INTERFACE;
+ smbc_closedir_fn closedir DEPRECATED_SMBC_INTERFACE;
+ smbc_readdir_fn readdir DEPRECATED_SMBC_INTERFACE;
+ smbc_getdents_fn getdents DEPRECATED_SMBC_INTERFACE;
+ smbc_mkdir_fn mkdir DEPRECATED_SMBC_INTERFACE;
+ smbc_rmdir_fn rmdir DEPRECATED_SMBC_INTERFACE;
+ smbc_telldir_fn telldir DEPRECATED_SMBC_INTERFACE;
+ smbc_lseekdir_fn lseekdir DEPRECATED_SMBC_INTERFACE;
+ smbc_fstatdir_fn fstatdir DEPRECATED_SMBC_INTERFACE;
+ smbc_chmod_fn chmod DEPRECATED_SMBC_INTERFACE;
+ smbc_utimes_fn utimes DEPRECATED_SMBC_INTERFACE;
+ smbc_setxattr_fn setxattr DEPRECATED_SMBC_INTERFACE;
+ smbc_getxattr_fn getxattr DEPRECATED_SMBC_INTERFACE;
+ smbc_removexattr_fn removexattr DEPRECATED_SMBC_INTERFACE;
+ smbc_listxattr_fn listxattr DEPRECATED_SMBC_INTERFACE;
+
+ /* Printing-related functions */
+ smbc_print_file_fn print_file DEPRECATED_SMBC_INTERFACE;
+ smbc_open_print_job_fn open_print_job DEPRECATED_SMBC_INTERFACE;
+ smbc_list_print_jobs_fn list_print_jobs DEPRECATED_SMBC_INTERFACE;
+ smbc_unlink_print_job_fn unlink_print_job DEPRECATED_SMBC_INTERFACE;
+
+ /*
+ ** Callbacks
+ *
+ * DEPRECATED:
+ *
+ * See the comment above each field, for the getter and setter
+ * functions that should now be used.
+ */
+ struct _smbc_callbacks
+ {
+ /**
+ * authentication function callback: called upon auth requests
+ *
+ * DEPRECATED:
+ * Use smbc_getFunctionAuthData(), smbc_setFunctionAuthData()
+ */
+ smbc_get_auth_data_fn auth_fn DEPRECATED_SMBC_INTERFACE;
+
+ /**
+ * check if a server is still good
+ *
+ * DEPRECATED:
+ * Use smbc_getFunctionCheckServer(),
+ * smbc_setFunctionCheckServer()
+ */
+ smbc_check_server_fn check_server_fn DEPRECATED_SMBC_INTERFACE;
+
+ /**
+ * remove a server if unused
+ *
+ * DEPRECATED:
+ * Use smbc_getFunctionRemoveUnusedServer(),
+ * smbc_setFunctionCheckServer()
+ */
+ smbc_remove_unused_server_fn remove_unused_server_fn DEPRECATED_SMBC_INTERFACE;
+
+ /** Cache subsystem
+ *
+ * For an example cache system see
+ * samba/source/libsmb/libsmb_cache.c
+ *
+ * Cache subsystem * functions follow.
+ */
+
+ /**
+ * server cache addition
+ *
+ * DEPRECATED:
+ * Use smbc_getFunctionAddCachedServer(),
+ * smbc_setFunctionAddCachedServer()
+ */
+ smbc_add_cached_srv_fn add_cached_srv_fn DEPRECATED_SMBC_INTERFACE;
+
+ /**
+ * server cache lookup
+ *
+ * DEPRECATED:
+ * Use smbc_getFunctionGetCachedServer(),
+ * smbc_setFunctionGetCachedServer()
+ */
+ smbc_get_cached_srv_fn get_cached_srv_fn DEPRECATED_SMBC_INTERFACE;
+
+ /**
+ * server cache removal
+ *
+ * DEPRECATED:
+ * Use smbc_getFunctionRemoveCachedServer(),
+ * smbc_setFunctionRemoveCachedServer()
+ */
+ smbc_remove_cached_srv_fn remove_cached_srv_fn DEPRECATED_SMBC_INTERFACE;
+
+ /**
+ * server cache purging, try to remove all cached servers
+ * (disconnect)
+ *
+ * DEPRECATED:
+ * Use smbc_getFunctionPurgeCachedServers(),
+ * smbc_setFunctionPurgeCachedServers()
+ */
+ smbc_purge_cached_fn purge_cached_fn DEPRECATED_SMBC_INTERFACE;
+ } callbacks;
+
+ /**
+ * Space where the private data of the server cache used to be
+ *
+ * DEPRECATED:
+ * Use smbc_getServerCacheData(), smbc_setServerCacheData()
+ */
+ void * reserved DEPRECATED_SMBC_INTERFACE;
+
+ /*
+ * Very old configuration options.
+ *
+ * DEPRECATED:
+ * Use one of the following functions instead:
+ * smbc_setOptionUseKerberos()
+ * smbc_getOptionUseKerberos()
+ * smbc_setOptionFallbackAfterKerberos()
+ * smbc_getOptionFallbackAfterKerberos()
+ * smbc_setOptionNoAutoAnonymousLogin()
+ * smbc_getOptionNoAutoAnonymousLogin()
+ */
+ int flags DEPRECATED_SMBC_INTERFACE;
+
+ /**
+ * user options selections that apply to this session
+ *
+ * NEW OPTIONS ARE NOT ADDED HERE!
+ *
+ * DEPRECATED:
+ * To set and retrieve options, use the smbc_setOption*() and
+ * smbc_getOption*() functions.
+ */
+ struct _smbc_options {
+ int browse_max_lmb_count DEPRECATED_SMBC_INTERFACE;
+ int urlencode_readdir_entries DEPRECATED_SMBC_INTERFACE;
+ int one_share_per_server DEPRECATED_SMBC_INTERFACE;
+ } options DEPRECATED_SMBC_INTERFACE;
+
+ /** INTERNAL DATA
+ * do _NOT_ touch this from your program !
+ */
+ struct SMBC_internal_data * internal;
+};
+
+
+#endif /* SMBCLIENT_H_INCLUDED */
diff --git a/source3/include/local.h b/source3/include/local.h
new file mode 100644
index 0000000000..c125ded371
--- /dev/null
+++ b/source3/include/local.h
@@ -0,0 +1,256 @@
+/* Copyright (C) 1995-1998 Samba-Team */
+/* Copyright (C) 1998 John H Terpstra <jht@aquasoft.com.au> */
+
+/* local definitions for file server */
+#ifndef _LOCAL_H
+#define _LOCAL_H
+
+/* The default workgroup - usually overridden in smb.conf */
+#ifndef WORKGROUP
+#define WORKGROUP "WORKGROUP"
+#endif
+
+/* the maximum debug level to compile into the code. This assumes a good
+ optimising compiler that can remove unused code
+ for embedded or low-memory systems set this to a value like 2 to get
+ only important messages. This gives *much* smaller binaries
+*/
+#ifndef MAX_DEBUG_LEVEL
+#define MAX_DEBUG_LEVEL 1000
+#endif
+
+/* This defines the section name in the configuration file that will contain */
+/* global parameters - that is, parameters relating to the whole server, not */
+/* just services. This name is then reserved, and may not be used as a */
+/* a service name. It will default to "global" if not defined here. */
+#define GLOBAL_NAME "global"
+#define GLOBAL_NAME2 "globals"
+
+/* This defines the section name in the configuration file that will
+ refer to the special "homes" service */
+#define HOMES_NAME "homes"
+
+/* This defines the section name in the configuration file that will
+ refer to the special "printers" service */
+#define PRINTERS_NAME "printers"
+
+/* 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 MAX_OPEN_DIRECTORIES 256
+
+/* max number of directory handles */
+/* As this now uses the bitmap code this can be
+ quite large. */
+#define MAX_DIRECTORY_HANDLES 2048
+
+/* maximum number of file caches per smbd */
+#define MAX_WRITE_CACHES 10
+
+/* define what facility to use for syslog */
+#ifndef SYSLOG_FACILITY
+#define SYSLOG_FACILITY LOG_DAEMON
+#endif
+
+/*
+ * Default number of maximum open files per smbd. This is
+ * also limited by the maximum available file descriptors
+ * per process and can also be set in smb.conf as "max open files"
+ * in the [global] section.
+ */
+
+#ifndef MAX_OPEN_FILES
+#define MAX_OPEN_FILES 10000
+#endif
+
+#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"
+
+/* wchar separators for lists */
+#define LIST_SEP_W wchar_list_sep
+
+/* this is where browse lists are kept in the lock dir */
+#define SERVER_LIST "browse.dat"
+
+/* shall filenames with illegal chars in them get mangled in long
+ filename listings? */
+#define MANGLE_LONG_FILENAMES
+
+/* define this if you want to stop spoofing with .. and soft links
+ NOTE: This also slows down the server considerably */
+#define REDUCE_PATHS
+
+/* the size of the directory cache */
+#define DIRCACHESIZE 20
+
+/* what default type of filesystem do we want this to show up as in a
+ NT file manager window? */
+#define FSTYPE_STRING "NTFS"
+
+/* the default guest account - normally set in the Makefile or smb.conf */
+#ifndef GUEST_ACCOUNT
+#define GUEST_ACCOUNT "nobody"
+#endif
+
+/* user to test password server with as invalid in security=server mode. */
+#ifndef INVALID_USER_PREFIX
+#define INVALID_USER_PREFIX "sambatest"
+#endif
+
+/* the default pager to use for the client "more" command. Users can
+ override this with the PAGER environment variable */
+#ifndef PAGER
+#define PAGER "more"
+#endif
+
+/* the size of the uid cache used to reduce valid user checks */
+#define VUID_CACHE_SIZE 32
+
+/* 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 (180)
+#define IDLE_CLOSED_TIMEOUT (60)
+#define DPTR_IDLE_TIMEOUT (120)
+#define SMBD_SELECT_TIMEOUT (60)
+#define NMBD_SELECT_LOOP (10)
+#define BROWSE_INTERVAL (60)
+#define REGISTRATION_INTERVAL (10*60)
+#define NMBD_INETD_TIMEOUT (120)
+#define NMBD_MAX_TTL (24*60*60)
+#define LPQ_LOCK_TIMEOUT (5)
+#define NMBD_INTERFACES_RELOAD (120)
+#define NMBD_UNEXPECTED_TIMEOUT (15)
+
+/* the following are in milliseconds */
+#define LOCK_RETRY_TIMEOUT (100)
+
+/* do you want to dump core (carefully!) when an internal error is
+ encountered? Samba will be careful to make the core file only
+ accessible to root */
+#define DUMP_CORE 1
+
+/* shall we support browse requests via a FIFO to nmbd? */
+#define ENABLE_FIFO 1
+
+/* how long (in miliseconds) to wait for a socket connect to happen */
+#define LONG_CONNECT_TIMEOUT 30000
+#define SHORT_CONNECT_TIMEOUT 5000
+
+/* the default netbios keepalive timeout */
+#define DEFAULT_KEEPALIVE 300
+
+/* 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
+
+/*
+ * Default passwd chat script.
+ */
+
+#define DEFAULT_PASSWD_CHAT "*new*password* %n\\n *new*password* %n\\n *changed*"
+
+/* Minimum length of allowed password when changing UNIX password. */
+#define MINPASSWDLENGTH 5
+
+/* maximum ID number used for session control. This cannot be larger
+ than 62*62 for the current code */
+#define MAX_SESSION_ID 3000
+
+/* For the benifit of PAM and the 'session exec' scripts, we fake up a terminal
+ name. This can be in one of two forms: The first for systems not using
+ utmp (and therefore not constrained as to length or the need for a number
+ < 3000 or so) and the second for systems with this 'well behaved terminal
+ like name' constraint.
+*/
+
+#ifndef SESSION_TEMPLATE
+/* Paramaters are 'pid' and 'vuid' */
+#define SESSION_TEMPLATE "smb/%lu/%d"
+#endif
+
+#ifndef SESSION_UTMP_TEMPLATE
+#define SESSION_UTMP_TEMPLATE "smb/%d"
+#endif
+
+/* the maximum age in seconds of a password. Should be a lp_ parameter */
+#define MAX_PASSWORD_AGE (21*24*60*60)
+
+/* Default allocation roundup. */
+#define SMB_ROUNDUP_ALLOCATION_SIZE 0x100000
+
+/* shall we deny oplocks to clients that get timeouts? */
+#define FASCIST_OPLOCK_BACKOFF 1
+
+/* this enables the "rabbit pellet" fix for SMBwritebraw */
+#define RABBIT_PELLET_FIX 1
+
+/* Max number of jobs per print queue. */
+#define PRINT_MAX_JOBID 10000
+
+/* Max number of open RPC pipes. */
+#define MAX_OPEN_PIPES 2048
+
+/* Tuning for server auth mutex. */
+#define CLI_AUTH_TIMEOUT 5000 /* In milli-seconds. */
+#define NUM_CLI_AUTH_CONNECT_RETRIES 3
+/* Number in seconds to wait for the mutex. This must be less than 30 seconds. */
+#define SERVER_MUTEX_WAIT_TIME ( ((NUM_CLI_AUTH_CONNECT_RETRIES) * ((CLI_AUTH_TIMEOUT)/1000)) + 5)
+/* Number in seconds for winbindd to wait for the mutex. Make this 2 * smbd wait time. */
+#define WINBIND_SERVER_MUTEX_WAIT_TIME (( ((NUM_CLI_AUTH_CONNECT_RETRIES) * ((CLI_AUTH_TIMEOUT)/1000)) + 5)*2)
+
+/* Max number of simultaneous winbindd socket connections. */
+#define WINBINDD_MAX_SIMULTANEOUS_CLIENTS 200
+
+/* Buffer size to use when printing backtraces */
+#define BACKTRACE_STACK_SIZE 64
+
+/* size of listen() backlog in smbd */
+#define SMBD_LISTEN_BACKLOG 50
+
+/* Number of microseconds to wait before a sharing violation. */
+#define SHARING_VIOLATION_USEC_WAIT 950000
+
+/* Number of microseconds to wait before a updating the write time (2 secs). */
+#define WRITE_TIME_UPDATE_USEC_DELAY 2000000
+
+#define MAX_LDAP_REPLICATION_SLEEP_TIME 5000 /* In milliseconds. */
+
+/* tdb hash size for the open database. */
+#define SMB_OPEN_DATABASE_TDB_HASH_SIZE 10007
+
+/* Characters we disallow in sharenames. */
+#define INVALID_SHARENAME_CHARS "%<>*?|/\\+=;:\","
+
+/* Seconds between connection attempts to a remote server. */
+#define FAILED_CONNECTION_CACHE_TIMEOUT 30
+
+/* Default hash size for the winbindd cache. */
+#define WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE 5000
+
+/* Windows minimum lock resolution timeout in ms */
+#define WINDOWS_MINIMUM_LOCK_TIMEOUT_MS 200
+
+#endif
diff --git a/source3/include/locking.h b/source3/include/locking.h
new file mode 100644
index 0000000000..b2b7236721
--- /dev/null
+++ b/source3/include/locking.h
@@ -0,0 +1,78 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup, plus a whole lot more.
+
+ Copyright (C) Jeremy Allison 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _LOCKING_H
+#define _LOCKING_H
+
+/* passed to br lock code - the UNLOCK_LOCK should never be stored into the tdb
+ and is used in calculating POSIX unlock ranges only. We differentiate between
+ PENDING read and write locks to allow posix lock downgrades to trigger a lock
+ re-evaluation. */
+
+enum brl_type {READ_LOCK, WRITE_LOCK, PENDING_READ_LOCK, PENDING_WRITE_LOCK, UNLOCK_LOCK};
+enum brl_flavour {WINDOWS_LOCK = 0, POSIX_LOCK = 1};
+
+#define IS_PENDING_LOCK(type) ((type) == PENDING_READ_LOCK || (type) == PENDING_WRITE_LOCK)
+
+/* This contains elements that differentiate locks. The smbpid is a
+ client supplied pid, and is essentially the locking context for
+ this client */
+
+struct lock_context {
+ uint32 smbpid;
+ uint16 tid;
+ struct server_id pid;
+};
+
+struct files_struct;
+
+struct file_id {
+ /* we don't use SMB_DEV_T and SMB_INO_T as we want a fixed size here,
+ and we may be using file system specific code to fill in something
+ other than a dev_t for the device */
+ uint64_t devid;
+ uint64_t inode;
+};
+
+struct byte_range_lock {
+ struct files_struct *fsp;
+ unsigned int num_locks;
+ bool modified;
+ bool read_only;
+ struct file_id key;
+ struct lock_struct *lock_data;
+ struct db_record *record;
+};
+
+/* Internal structure in brlock.tdb.
+ The data in brlock records is an unsorted linear array of these
+ records. It is unnecessary to store the count as tdb provides the
+ size of the record */
+
+struct lock_struct {
+ struct lock_context context;
+ br_off start;
+ br_off size;
+ uint16 fnum;
+ enum brl_type lock_type;
+ enum brl_flavour lock_flav;
+};
+
+#endif /* _LOCKING_H_ */
diff --git a/source3/include/mangle.h b/source3/include/mangle.h
new file mode 100644
index 0000000000..c07b852453
--- /dev/null
+++ b/source3/include/mangle.h
@@ -0,0 +1,23 @@
+#ifndef _MANGLE_H_
+#define _MANGLE_H_
+/*
+ header for 8.3 name mangling interface
+*/
+
+struct mangle_fns {
+ void (*reset)(void);
+ bool (*is_mangled)(const char *s, const struct share_params *p);
+ bool (*must_mangle)(const char *s, const struct share_params *p);
+ bool (*is_8_3)(const char *fname, bool check_case, bool allow_wildcards,
+ const struct share_params *p);
+ bool (*lookup_name_from_8_3)(TALLOC_CTX *ctx,
+ const char *in,
+ char **out, /* talloced on the given context. */
+ const struct share_params *p);
+ bool (*name_to_8_3)(const char *in,
+ char out[13],
+ bool cache83,
+ int default_case,
+ const struct share_params *p);
+};
+#endif /* _MANGLE_H_ */
diff --git a/source3/include/mapping.h b/source3/include/mapping.h
new file mode 100644
index 0000000000..75459fcebd
--- /dev/null
+++ b/source3/include/mapping.h
@@ -0,0 +1,32 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Jean François Micouleau 1998-2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define ENUM_ONLY_MAPPED True
+#define ENUM_ALL_MAPPED False
+
+typedef struct _GROUP_MAP {
+ struct pdb_methods *methods;
+ gid_t gid;
+ DOM_SID sid;
+ enum lsa_SidType sid_name_use;
+ fstring nt_name;
+ fstring comment;
+} GROUP_MAP;
+
diff --git a/source3/include/md5.h b/source3/include/md5.h
new file mode 100644
index 0000000000..e4cd08ed5e
--- /dev/null
+++ b/source3/include/md5.h
@@ -0,0 +1,19 @@
+#ifndef MD5_H
+#define MD5_H
+#ifndef HEADER_MD5_H
+/* Try to avoid clashes with OpenSSL */
+#define HEADER_MD5_H
+#endif
+
+struct MD5Context {
+ uint32 buf[4];
+ uint32 bits[2];
+ unsigned char in[64];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+ unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+
+#endif /* !MD5_H */
diff --git a/source3/include/memcache.h b/source3/include/memcache.h
new file mode 100644
index 0000000000..0a596b91a5
--- /dev/null
+++ b/source3/include/memcache.h
@@ -0,0 +1,115 @@
+/*
+ Unix SMB/CIFS implementation.
+ In-memory cache
+ Copyright (C) Volker Lendecke 2007-2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __MEMCACHE_H__
+#define __MEMCACHE_H__
+
+#include "includes.h"
+
+struct memcache;
+
+/*
+ * A memcache can store different subkeys with overlapping keys, the
+ * memcache_number becomes part of the key. Feel free to add caches of your
+ * own here.
+ *
+ * If you add talloc type caches, also note this in the switch statement in
+ * memcache_is_talloc().
+ */
+
+enum memcache_number {
+ STAT_CACHE,
+ UID_SID_CACHE,
+ SID_UID_CACHE,
+ GID_SID_CACHE,
+ SID_GID_CACHE,
+ GETWD_CACHE,
+ GETPWNAM_CACHE, /* talloc */
+ MANGLE_HASH2_CACHE,
+ PDB_GETPWSID_CACHE, /* talloc */
+ SINGLETON_CACHE_TALLOC, /* talloc */
+ SINGLETON_CACHE
+};
+
+/*
+ * Create a memcache structure. max_size is in bytes, if you set it 0 it will
+ * not forget anything.
+ */
+
+struct memcache *memcache_init(TALLOC_CTX *mem_ctx, size_t max_size);
+
+/*
+ * If you set this global memcache, use it as the default cache when NULL is
+ * passed to the memcache functions below. This is a workaround for many
+ * situations where passing the cache everywhere would be a big hassle.
+ */
+
+void memcache_set_global(struct memcache *cache);
+
+/*
+ * Add a data blob to the cache
+ */
+
+void memcache_add(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key, DATA_BLOB value);
+
+/*
+ * Add a talloc object to the cache. The difference to memcache_add() is that
+ * when the objects is to be discared, talloc_free is called for it. Also
+ * talloc_move() ownership of the object to the cache.
+ *
+ * Please note that the current implementation has a fixed relationship
+ * between what cache subtypes store talloc objects and which ones store plain
+ * blobs. We can fix this, but for now we don't have a mixed use of blobs vs
+ * talloc objects in the cache types.
+ */
+
+void memcache_add_talloc(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key, void *ptr);
+
+/*
+ * Delete an object from the cache
+ */
+
+void memcache_delete(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key);
+
+/*
+ * Look up an object from the cache. Memory still belongs to the cache, so
+ * make a copy of it if needed.
+ */
+
+bool memcache_lookup(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key, DATA_BLOB *value);
+
+/*
+ * Look up an object from the cache. Memory still belongs to the cache, so
+ * make a copy of it if needed.
+ */
+
+void *memcache_lookup_talloc(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key);
+
+/*
+ * Flush a complete cache subset.
+ */
+
+void memcache_flush(struct memcache *cache, enum memcache_number n);
+
+#endif
diff --git a/source3/include/messages.h b/source3/include/messages.h
new file mode 100644
index 0000000000..db805a2093
--- /dev/null
+++ b/source3/include/messages.h
@@ -0,0 +1,153 @@
+/*
+ Unix SMB/CIFS implementation.
+ messages.c header
+ Copyright (C) Andrew Tridgell 2000
+ Copyright (C) 2001, 2002 by Martin Pool
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _MESSAGES_H_
+#define _MESSAGES_H_
+
+/* change the message version with any incompatible changes in the protocol */
+#define MESSAGE_VERSION 2
+
+/*
+ * Special flags passed to message_send. Allocated from the top, lets see when
+ * it collides with the message types in the lower 16 bits :-)
+ */
+
+/*
+ * Under high load, this message can be dropped. Use for notify-style
+ * messages that are not critical for correct operation.
+ */
+#define MSG_FLAG_LOWPRIORITY 0x80000000
+
+
+/* Flags to classify messages - used in message_send_all() */
+/* Sender will filter by flag. */
+
+#define FLAG_MSG_GENERAL 0x0001
+#define FLAG_MSG_SMBD 0x0002
+#define FLAG_MSG_NMBD 0x0004
+#define FLAG_MSG_PRINT_NOTIFY 0x0008
+#define FLAG_MSG_PRINT_GENERAL 0x0010
+/* dbwrap messages 4001-4999 */
+#define FLAG_MSG_DBWRAP 0x0020
+
+
+/*
+ * Virtual Node Numbers are identifying a node within a cluster. Ctdbd sets
+ * this, we retrieve our vnn from it.
+ */
+
+#define NONCLUSTER_VNN (0xFFFFFFFF)
+
+/*
+ * ctdb gives us 64-bit server ids for messaging_send. This is done to avoid
+ * pid clashes and to be able to register for special messages like "all
+ * smbds".
+ *
+ * Normal individual server id's have the upper 32 bits to 0, I picked "1" for
+ * Samba, other subsystems might use something else.
+ */
+
+#define MSG_SRVID_SAMBA 0x0000000100000000LL
+
+
+struct server_id {
+ pid_t pid;
+#ifdef CLUSTER_SUPPORT
+ uint32 vnn;
+#endif
+};
+
+#ifdef CLUSTER_SUPPORT
+#define MSG_BROADCAST_PID_STR "0:0"
+#else
+#define MSG_BROADCAST_PID_STR "0"
+#endif
+
+struct messaging_context;
+struct messaging_rec;
+struct data_blob;
+
+/*
+ * struct messaging_context belongs to messages.c, but because we still have
+ * messaging_dispatch, we need it here. Once we get rid of signals for
+ * notifying processes, this will go.
+ */
+
+struct messaging_context {
+ struct server_id id;
+ struct event_context *event_ctx;
+ struct messaging_callback *callbacks;
+
+ struct messaging_backend *local;
+ struct messaging_backend *remote;
+};
+
+struct messaging_backend {
+ NTSTATUS (*send_fn)(struct messaging_context *msg_ctx,
+ struct server_id pid, int msg_type,
+ const struct data_blob *data,
+ struct messaging_backend *backend);
+ void *private_data;
+};
+
+NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct messaging_backend **presult);
+void message_dispatch(struct messaging_context *msg_ctx);
+
+NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct messaging_backend **presult);
+struct ctdbd_connection *messaging_ctdbd_connection(void);
+
+bool message_send_all(struct messaging_context *msg_ctx,
+ int msg_type,
+ const void *buf, size_t len,
+ int *n_sent);
+struct event_context *messaging_event_context(struct messaging_context *msg_ctx);
+struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx,
+ struct server_id server_id,
+ struct event_context *ev);
+
+/*
+ * re-init after a fork
+ */
+NTSTATUS messaging_reinit(struct messaging_context *msg_ctx);
+
+NTSTATUS messaging_register(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ void (*fn)(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ struct data_blob *data));
+void messaging_deregister(struct messaging_context *ctx, uint32_t msg_type,
+ void *private_data);
+NTSTATUS messaging_send(struct messaging_context *msg_ctx,
+ struct server_id server,
+ uint32_t msg_type, const struct data_blob *data);
+NTSTATUS messaging_send_buf(struct messaging_context *msg_ctx,
+ struct server_id server, uint32_t msg_type,
+ const uint8 *buf, size_t len);
+void messaging_dispatch_rec(struct messaging_context *msg_ctx,
+ struct messaging_rec *rec);
+
+#endif
diff --git a/source3/include/module.h b/source3/include/module.h
new file mode 100644
index 0000000000..20dbaba6b4
--- /dev/null
+++ b/source3/include/module.h
@@ -0,0 +1,35 @@
+/*
+ Unix SMB/CIFS implementation.
+ Handling of idle/exit events
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _MODULE_H
+#define _MODULE_H
+
+/* Module support */
+typedef NTSTATUS (init_module_function) (void);
+
+
+typedef int smb_event_id_t;
+#define SMB_EVENT_ID_INVALID (-1)
+
+#define SMB_IDLE_EVENT_DEFAULT_INTERVAL 180
+#define SMB_IDLE_EVENT_MIN_INTERVAL 30
+
+typedef void (smb_idle_event_fn)(void **data,time_t *interval,time_t now);
+
+#endif /* _MODULE_H */
diff --git a/source3/include/msdfs.h b/source3/include/msdfs.h
new file mode 100644
index 0000000000..4551325843
--- /dev/null
+++ b/source3/include/msdfs.h
@@ -0,0 +1,75 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ MSDfs services for Samba
+ Copyright (C) Shirish Kalele 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _MSDFS_H
+#define _MSDFS_H
+
+#define REFERRAL_TTL 600
+
+/* Flags used in trans2 Get Referral reply */
+#define DFSREF_REFERRAL_SERVER 0x1
+#define DFSREF_STORAGE_SERVER 0x2
+
+/* Referral sizes */
+#define VERSION2_REFERRAL_SIZE 0x16
+#define VERSION3_REFERRAL_SIZE 0x22
+#define REFERRAL_HEADER_SIZE 0x08
+
+/* Maximum number of referrals for each Dfs volume */
+#define MAX_REFERRAL_COUNT 256
+#define MAX_MSDFS_JUNCTIONS 256
+
+typedef struct _client_referral {
+ uint32 proximity;
+ uint32 ttl;
+ char *dfspath;
+} CLIENT_DFS_REFERRAL;
+
+struct referral {
+ char *alternate_path; /* contains the path referred */
+ uint32 proximity;
+ uint32 ttl; /* how long should client cache referral */
+};
+
+struct junction_map {
+ char *service_name;
+ char *volume_name;
+ const char *comment;
+ int referral_count;
+ struct referral* referral_list;
+};
+
+struct dfs_path {
+ char *hostname;
+ char *servicename;
+ char *reqpath;
+ bool posix_path;
+};
+
+#define init_dfsroot(conn, inbuf, outbuf) \
+{ if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) { \
+ DEBUG(2,("Serving %s as a Dfs root\n", \
+ lp_servicename(SNUM(conn)) )); \
+ SSVAL(outbuf, smb_vwv2, SMB_SHARE_IN_DFS \
+ | SVAL(outbuf, smb_vwv2)); \
+} }
+
+#endif /* _MSDFS_H */
diff --git a/source3/include/nameserv.h b/source3/include/nameserv.h
new file mode 100644
index 0000000000..4377e3330a
--- /dev/null
+++ b/source3/include/nameserv.h
@@ -0,0 +1,628 @@
+#ifndef _NAMESERV_H_
+#define _NAMESERV_H_
+/*
+ Unix SMB/CIFS implementation.
+ NBT netbios header - 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#define INFO_VERSION "INFO/version"
+#define INFO_COUNT "INFO/num_entries"
+#define INFO_ID_HIGH "INFO/id_high"
+#define INFO_ID_LOW "INFO/id_low"
+#define ENTRY_PREFIX "ENTRY/"
+
+#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
+
+/*********************************************************
+ 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
+
+/* The wins flags. Looks like the nbflags ! */
+#define WINS_UNIQUE 0x00 /* Unique record */
+#define WINS_NGROUP 0x01 /* Normal Group eg: 1B */
+#define WINS_SGROUP 0x02 /* Special Group eg: 1C */
+#define WINS_MHOMED 0x03 /* MultiHomed */
+
+#define WINS_ACTIVE 0x00 /* active record */
+#define WINS_RELEASED 0x04 /* released record */
+#define WINS_TOMBSTONED 0x08 /* tombstoned record */
+#define WINS_DELETED 0x0C /* deleted record */
+
+#define WINS_STATE_MASK 0x0C
+
+#define WINS_LOCAL 0x00 /* local record */
+#define WINS_REMOTE 0x10 /* remote record */
+
+#define WINS_BNODE 0x00 /* Broadcast node */
+#define WINS_PNODE 0x20 /* PtP node */
+#define WINS_MNODE 0x40 /* Mixed node */
+#define WINS_HNODE 0x60 /* Hybrid node */
+
+#define WINS_NONSTATIC 0x00 /* dynamic record */
+#define WINS_STATIC 0x80 /* static record */
+
+#define WINS_STATE_ACTIVE(p) (((p)->data.wins_flags & WINS_STATE_MASK) == WINS_ACTIVE)
+
+
+/* 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)
+
+/* 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};
+
+enum master_state {
+ MST_NONE,
+ MST_POTENTIAL,
+ MST_BACKUP,
+ MST_MSB,
+ MST_BROWSER,
+ MST_UNBECOMING_MASTER
+};
+
+enum domain_state {
+ DOMAIN_NONE,
+ DOMAIN_WAIT,
+ DOMAIN_MST
+};
+
+enum logon_state {
+ LOGON_NONE,
+ LOGON_WAIT,
+ LOGON_SRV
+};
+
+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. */
+
+ SMB_BIG_UINT id; /* unique id */
+ struct in_addr wins_ip; /* the adress of the wins server this record comes from */
+
+ int wins_flags; /* similar to the netbios flags but different ! */
+};
+
+/* This structure represents an entry in a local netbios name list. */
+struct name_record {
+ struct name_record *prev, *next;
+ 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 {
+ struct browse_cache_record *prev, *next;
+ unstring lmb_name;
+ unstring 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;
+
+ 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. */
+ unstring work_group;
+ int token; /* Used when communicating with backup browsers. */
+ unstring 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;
+
+ /* Recursion protection. */
+ bool in_expiration_processing;
+};
+
+/* A subnet structure. It contains a list of workgroups and netbios names. */
+
+/*
+ B nodes will have their own, totally separate subnet record, with their
+ own netbios name set. These do NOT interact with other subnet records'
+ netbios names.
+*/
+
+enum subnet_type {
+ NORMAL_SUBNET = 0, /* Subnet listed in interfaces list. */
+ UNICAST_SUBNET = 1, /* Subnet for unicast packets. */
+ REMOTE_BROADCAST_SUBNET = 2, /* Subnet for remote broadcasts. */
+ WINS_SERVER_SUBNET = 3 /* Only created if we are a WINS server. */
+};
+
+struct subnet_record {
+ struct subnet_record *next;
+ struct subnet_record *prev;
+
+ char *subnet_name; /* For Debug identification. */
+ enum subnet_type type; /* To catagorize the subnet. */
+
+ struct work_record *workgrouplist; /* List of workgroups. */
+ struct name_record *namelist; /* 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;
+ int rr_class;
+ int ttl;
+ int rdlength;
+ char rdata[MAX_DGRAM_SIZE];
+};
+
+/* Define these so we can pass info back to caller of name_query */
+#define NM_FLAGS_RS 0x80 /* Response. Cheat */
+#define NM_FLAGS_AA 0x40 /* Authoritative */
+#define NM_FLAGS_TC 0x20 /* Truncated */
+#define NM_FLAGS_RD 0x10 /* Recursion Desired */
+#define NM_FLAGS_RA 0x08 /* Recursion Available */
+#define NM_FLAGS_B 0x01 /* Broadcast */
+
+/* An nmb packet. */
+struct nmb_packet {
+ struct {
+ int name_trn_id;
+ int opcode;
+ bool response;
+ struct {
+ bool bcast;
+ bool recursion_available;
+ bool recursion_desired;
+ bool trunc;
+ bool authoritative;
+ } nm_flags;
+ int rcode;
+ int qdcount;
+ int ancount;
+ int nscount;
+ int arcount;
+ } header;
+
+ struct {
+ struct nmb_name question_name;
+ int question_type;
+ int question_class;
+ } question;
+
+ struct res_rec *answers;
+ struct res_rec *nsrecs;
+ struct res_rec *additional;
+};
+
+/* msg_type field options - from rfc1002. */
+
+#define DGRAM_UNIQUE 0x10
+#define DGRAM_GROUP 0x11
+#define DGRAM_BROADCAST 0x12
+/* defined in IDL
+#define DGRAM_ERROR 0x13
+*/
+#define DGRAM_QUERY_REQUEST 0x14
+#define DGRAM_POSITIVE_QUERY_RESPONSE 0x15
+#define DGRAM_NEGATIVE_QUERT_RESPONSE 0x16
+
+/* A datagram - this normally contains SMB data in the data[] array. */
+
+struct dgram_packet {
+ struct {
+ int msg_type;
+ struct {
+ enum node_type node_type;
+ bool first;
+ bool more;
+ } flags;
+ int dgm_id;
+ struct in_addr source_ip;
+ int source_port;
+ int dgm_length;
+ int packet_offset;
+ } header;
+ struct nmb_name source_name;
+ struct nmb_name dest_name;
+ int datasize;
+ char data[MAX_DGRAM_SIZE];
+};
+
+/* 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;
+ time_t timestamp;
+ enum packet_type packet_type;
+ union {
+ struct nmb_packet nmb;
+ struct dgram_packet dgram;
+ } packet;
+};
+
+/* NETLOGON opcodes */
+
+#define QUERYFORPDC 7 /* Query for PDC. */
+#define SAM_UAS_CHANGE 10 /* Announce change to UAS or SAM. */
+#define QUERYFORPDC_R 12 /* Response to Query for PDC. */
+#define SAMLOGON 18
+#define SAMLOGON_R 19
+#define SAMLOGON_UNK_R 21
+#define SAMLOGON_AD_UNK_R 23
+#define SAMLOGON_AD_R 25
+
+/* 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)
+
+/* The Extinction interval: 4 days, time a node will stay in released state */
+#define EXTINCTION_INTERVAL (4*24*60*60)
+
+/* The Extinction time-out: 1 day, time a node will stay in deleted state */
+#define EXTINCTION_TIMEOUT (24*60*60)
+
+/* 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)))
+
+/* wins replication record used between nmbd and wrepld */
+typedef struct _WINS_RECORD {
+ char name[17];
+ char type;
+ int nb_flags;
+ int wins_flags;
+ SMB_BIG_UINT id;
+ int num_ips;
+ struct in_addr ip[25];
+ struct in_addr wins_ip;
+} WINS_RECORD;
+
+/* To be removed. */
+enum state_type { TEST };
+#endif /* _NAMESERV_H_ */
diff --git a/source3/include/ndr.h b/source3/include/ndr.h
new file mode 100644
index 0000000000..a416866ef2
--- /dev/null
+++ b/source3/include/ndr.h
@@ -0,0 +1 @@
+/* dummy file to deal with pidl autogenerated ndr files */
diff --git a/source3/include/nss_info.h b/source3/include/nss_info.h
new file mode 100644
index 0000000000..1ff9ebcd55
--- /dev/null
+++ b/source3/include/nss_info.h
@@ -0,0 +1,90 @@
+/*
+ Unix SMB/CIFS implementation.
+ Idmap NSS headers
+
+ Copyright (C) Gerald Carter 2006
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _IDMAP_NSS_H
+#define _IDMAP_NSS_H
+
+#ifndef HAVE_LDAP
+# ifndef LDAPMessage
+# define LDAPMessage void
+# endif
+#endif
+
+/* The interface version specifier */
+
+#define SMB_NSS_INFO_INTERFACE_VERSION 1
+
+/* List of available backends. All backends must
+ register themselves */
+
+struct nss_function_entry {
+ struct nss_function_entry *prev, *next;
+
+ const char *name;
+ struct nss_info_methods *methods;
+};
+
+/* List of configured domains. Each domain points
+ back to its configured backend. */
+
+struct nss_domain_entry {
+ struct nss_domain_entry *prev, *next;
+
+ const char *domain;
+
+ NTSTATUS init_status;
+ struct nss_function_entry *backend;
+
+ /* hold state on a per domain basis */
+
+ void *state;
+};
+
+/* API */
+
+struct nss_info_methods {
+ NTSTATUS (*init)( struct nss_domain_entry *e );
+ NTSTATUS (*get_nss_info)( struct nss_domain_entry *e,
+ const DOM_SID *sid,
+ TALLOC_CTX *ctx,
+ ADS_STRUCT *ads, LDAPMessage *msg,
+ char **homedir, char **shell, char **gecos, gid_t *p_gid);
+ NTSTATUS (*close_fn)( void );
+};
+
+
+/* The following definitions come from nsswitch/nss_info.c */
+
+NTSTATUS smb_register_idmap_nss(int version,
+ const char *name,
+ struct nss_info_methods *methods);
+
+NTSTATUS nss_init( const char **nss_list );
+
+NTSTATUS nss_get_info( const char *domain, const DOM_SID *user_sid,
+ TALLOC_CTX *ctx,
+ ADS_STRUCT *ads, LDAPMessage *msg,
+ char **homedir, char **shell, char **gecos,
+ gid_t *p_gid);
+
+NTSTATUS nss_close( const char *parameters );
+
+#endif /* _IDMAP_NSS_H_ */
+
diff --git a/source3/include/nt_printing.h b/source3/include/nt_printing.h
new file mode 100644
index 0000000000..479404d6fd
--- /dev/null
+++ b/source3/include/nt_printing.h
@@ -0,0 +1,485 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-2000,
+ Copyright (C) Jean Francois Micouleau 1998-2000.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef NT_PRINTING_H_
+#define NT_PRINTING_H_
+
+#define ORIENTATION 0x00000001L
+#define PAPERSIZE 0x00000002L
+#define PAPERLENGTH 0x00000004L
+#define PAPERWIDTH 0x00000008L
+#define SCALE 0x00000010L
+#define COPIES 0x00000100L
+#define DEFAULTSOURCE 0x00000200L
+#define PRINTQUALITY 0x00000400L
+#define COLOR 0x00000800L
+#define DUPLEX 0x00001000L
+#define YRESOLUTION 0x00002000L
+#define TTOPTION 0x00004000L
+#define COLLATE 0x00008000L
+#define FORMNAME 0x00010000L
+#define LOGPIXELS 0x00020000L
+#define BITSPERPEL 0x00040000L
+#define PELSWIDTH 0x00080000L
+#define PELSHEIGHT 0x00100000L
+#define DISPLAYFLAGS 0x00200000L
+#define DISPLAYFREQUENCY 0x00400000L
+#define PANNINGWIDTH 0x00800000L
+#define PANNINGHEIGHT 0x01000000L
+
+#define ORIENT_PORTRAIT 1
+#define ORIENT_LANDSCAPE 2
+
+#define PAPER_FIRST PAPER_LETTER
+#define PAPER_LETTER 1 /* Letter 8 1/2 x 11 in */
+#define PAPER_LETTERSMALL 2 /* Letter Small 8 1/2 x 11 in */
+#define PAPER_TABLOID 3 /* Tabloid 11 x 17 in */
+#define PAPER_LEDGER 4 /* Ledger 17 x 11 in */
+#define PAPER_LEGAL 5 /* Legal 8 1/2 x 14 in */
+#define PAPER_STATEMENT 6 /* Statement 5 1/2 x 8 1/2 in */
+#define PAPER_EXECUTIVE 7 /* Executive 7 1/4 x 10 1/2 in */
+#define PAPER_A3 8 /* A3 297 x 420 mm */
+#define PAPER_A4 9 /* A4 210 x 297 mm */
+#define PAPER_A4SMALL 10 /* A4 Small 210 x 297 mm */
+#define PAPER_A5 11 /* A5 148 x 210 mm */
+#define PAPER_B4 12 /* B4 (JIS) 250 x 354 */
+#define PAPER_B5 13 /* B5 (JIS) 182 x 257 mm */
+#define PAPER_FOLIO 14 /* Folio 8 1/2 x 13 in */
+#define PAPER_QUARTO 15 /* Quarto 215 x 275 mm */
+#define PAPER_10X14 16 /* 10x14 in */
+#define PAPER_11X17 17 /* 11x17 in */
+#define PAPER_NOTE 18 /* Note 8 1/2 x 11 in */
+#define PAPER_ENV_9 19 /* Envelope #9 3 7/8 x 8 7/8 */
+#define PAPER_ENV_10 20 /* Envelope #10 4 1/8 x 9 1/2 */
+#define PAPER_ENV_11 21 /* Envelope #11 4 1/2 x 10 3/8 */
+#define PAPER_ENV_12 22 /* Envelope #12 4 \276 x 11 */
+#define PAPER_ENV_14 23 /* Envelope #14 5 x 11 1/2 */
+#define PAPER_CSHEET 24 /* C size sheet */
+#define PAPER_DSHEET 25 /* D size sheet */
+#define PAPER_ESHEET 26 /* E size sheet */
+#define PAPER_ENV_DL 27 /* Envelope DL 110 x 220mm */
+#define PAPER_ENV_C5 28 /* Envelope C5 162 x 229 mm */
+#define PAPER_ENV_C3 29 /* Envelope C3 324 x 458 mm */
+#define PAPER_ENV_C4 30 /* Envelope C4 229 x 324 mm */
+#define PAPER_ENV_C6 31 /* Envelope C6 114 x 162 mm */
+#define PAPER_ENV_C65 32 /* Envelope C65 114 x 229 mm */
+#define PAPER_ENV_B4 33 /* Envelope B4 250 x 353 mm */
+#define PAPER_ENV_B5 34 /* Envelope B5 176 x 250 mm */
+#define PAPER_ENV_B6 35 /* Envelope B6 176 x 125 mm */
+#define PAPER_ENV_ITALY 36 /* Envelope 110 x 230 mm */
+#define PAPER_ENV_MONARCH 37 /* Envelope Monarch 3.875 x 7.5 in */
+#define PAPER_ENV_PERSONAL 38 /* 6 3/4 Envelope 3 5/8 x 6 1/2 in */
+#define PAPER_FANFOLD_US 39 /* US Std Fanfold 14 7/8 x 11 in */
+#define PAPER_FANFOLD_STD_GERMAN 40 /* German Std Fanfold 8 1/2 x 12 in */
+#define PAPER_FANFOLD_LGL_GERMAN 41 /* German Legal Fanfold 8 1/2 x 13 in */
+
+#define PAPER_LAST PAPER_FANFOLD_LGL_GERMAN
+#define PAPER_USER 256
+
+#define BIN_FIRST BIN_UPPER
+#define BIN_UPPER 1
+#define BIN_ONLYONE 1
+#define BIN_LOWER 2
+#define BIN_MIDDLE 3
+#define BIN_MANUAL 4
+#define BIN_ENVELOPE 5
+#define BIN_ENVMANUAL 6
+#define BIN_AUTO 7
+#define BIN_TRACTOR 8
+#define BIN_SMALLFMT 9
+#define BIN_LARGEFMT 10
+#define BIN_LARGECAPACITY 11
+#define BIN_CASSETTE 14
+#define BIN_FORMSOURCE 15
+#define BIN_LAST BIN_FORMSOURCE
+
+#define BIN_USER 256 /* device specific bins start here */
+
+#define RES_DRAFT (-1)
+#define RES_LOW (-2)
+#define RES_MEDIUM (-3)
+#define RES_HIGH (-4)
+
+#define COLOR_MONOCHROME 1
+#define COLOR_COLOR 2
+
+#define DUP_SIMPLEX 1
+#define DUP_VERTICAL 2
+#define DUP_HORIZONTAL 3
+
+#define TT_BITMAP 1 /* print TT fonts as graphics */
+#define TT_DOWNLOAD 2 /* download TT fonts as soft fonts */
+#define TT_SUBDEV 3 /* substitute device fonts for TT fonts */
+
+#define COLLATE_FALSE 0
+#define COLLATE_TRUE 1
+
+typedef struct nt_printer_driver_info_level_3
+{
+ uint32 cversion;
+
+ fstring name;
+ fstring environment;
+ fstring driverpath;
+ fstring datafile;
+ fstring configfile;
+ fstring helpfile;
+ fstring monitorname;
+ fstring defaultdatatype;
+ fstring *dependentfiles;
+} NT_PRINTER_DRIVER_INFO_LEVEL_3;
+
+/* SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 structure */
+typedef struct {
+ uint32 version;
+ fstring name;
+ fstring environment;
+ fstring driverpath;
+ fstring datafile;
+ fstring configfile;
+ fstring helpfile;
+ fstring monitorname;
+ fstring defaultdatatype;
+ fstring mfgname;
+ fstring oemurl;
+ fstring hardwareid;
+ fstring provider;
+ fstring *dependentfiles;
+ fstring *previousnames;
+} NT_PRINTER_DRIVER_INFO_LEVEL_6;
+
+
+typedef struct nt_printer_driver_info_level
+{
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3;
+ NT_PRINTER_DRIVER_INFO_LEVEL_6 *info_6;
+} NT_PRINTER_DRIVER_INFO_LEVEL;
+
+/* predefined registry key names for printer data */
+
+#define SPOOL_PRINTERDATA_KEY "PrinterDriverData"
+#define SPOOL_DSSPOOLER_KEY "DsSpooler"
+#define SPOOL_DSDRIVER_KEY "DsDriver"
+#define SPOOL_DSUSER_KEY "DsUser"
+#define SPOOL_PNPDATA_KEY "PnPData"
+#define SPOOL_OID_KEY "OID"
+
+/* predefined value names for printer data */
+#define SPOOL_REG_ASSETNUMBER "assetNumber"
+#define SPOOL_REG_BYTESPERMINUTE "bytesPerMinute"
+#define SPOOL_REG_DEFAULTPRIORITY "defaultPriority"
+#define SPOOL_REG_DESCRIPTION "description"
+#define SPOOL_REG_DRIVERNAME "driverName"
+#define SPOOL_REG_DRIVERVERSION "driverVersion"
+#define SPOOL_REG_FLAGS "flags"
+#define SPOOL_REG_LOCATION "location"
+#define SPOOL_REG_OPERATINGSYSTEM "operatingSystem"
+#define SPOOL_REG_OPERATINGSYSTEMHOTFIX "operatingSystemHotfix"
+#define SPOOL_REG_OPERATINGSYSTEMSERVICEPACK "operatingSystemServicePack"
+#define SPOOL_REG_OPERATINGSYSTEMVERSION "operatingSystemVersion"
+#define SPOOL_REG_PORTNAME "portName"
+#define SPOOL_REG_PRINTATTRIBUTES "printAttributes"
+#define SPOOL_REG_PRINTBINNAMES "printBinNames"
+#define SPOOL_REG_PRINTCOLLATE "printCollate"
+#define SPOOL_REG_PRINTCOLOR "printColor"
+#define SPOOL_REG_PRINTDUPLEXSUPPORTED "printDuplexSupported"
+#define SPOOL_REG_PRINTENDTIME "printEndTime"
+#define SPOOL_REG_PRINTERNAME "printerName"
+#define SPOOL_REG_PRINTFORMNAME "printFormName"
+#define SPOOL_REG_PRINTKEEPPRINTEDJOBS "printKeepPrintedJobs"
+#define SPOOL_REG_PRINTLANGUAGE "printLanguage"
+#define SPOOL_REG_PRINTMACADDRESS "printMACAddress"
+#define SPOOL_REG_PRINTMAXCOPIES "printMaxCopies"
+#define SPOOL_REG_PRINTMAXRESOLUTIONSUPPORTED "printMaxResolutionSupported"
+#define SPOOL_REG_PRINTMAXXEXTENT "printMaxXExtent"
+#define SPOOL_REG_PRINTMAXYEXTENT "printMaxYExtent"
+#define SPOOL_REG_PRINTMEDIAREADY "printMediaReady"
+#define SPOOL_REG_PRINTMEDIASUPPORTED "printMediaSupported"
+#define SPOOL_REG_PRINTMEMORY "printMemory"
+#define SPOOL_REG_PRINTMINXEXTENT "printMinXExtent"
+#define SPOOL_REG_PRINTMINYEXTENT "printMinYExtent"
+#define SPOOL_REG_PRINTNETWORKADDRESS "printNetworkAddress"
+#define SPOOL_REG_PRINTNOTIFY "printNotify"
+#define SPOOL_REG_PRINTNUMBERUP "printNumberUp"
+#define SPOOL_REG_PRINTORIENTATIONSSUPPORTED "printOrientationsSupported"
+#define SPOOL_REG_PRINTOWNER "printOwner"
+#define SPOOL_REG_PRINTPAGESPERMINUTE "printPagesPerMinute"
+#define SPOOL_REG_PRINTRATE "printRate"
+#define SPOOL_REG_PRINTRATEUNIT "printRateUnit"
+#define SPOOL_REG_PRINTSEPARATORFILE "printSeparatorFile"
+#define SPOOL_REG_PRINTSHARENAME "printShareName"
+#define SPOOL_REG_PRINTSPOOLING "printSpooling"
+#define SPOOL_REGVAL_PRINTWHILESPOOLING "PrintWhileSpooling"
+#define SPOOL_REGVAL_PRINTAFTERSPOOLED "PrintAfterSpooled"
+#define SPOOL_REGVAL_PRINTDIRECT "PrintDirect"
+#define SPOOL_REG_PRINTSTAPLINGSUPPORTED "printStaplingSupported"
+#define SPOOL_REG_PRINTSTARTTIME "printStartTime"
+#define SPOOL_REG_PRINTSTATUS "printStatus"
+#define SPOOL_REG_PRIORITY "priority"
+#define SPOOL_REG_SERVERNAME "serverName"
+#define SPOOL_REG_SHORTSERVERNAME "shortServerName"
+#define SPOOL_REG_UNCNAME "uNCName"
+#define SPOOL_REG_URL "url"
+#define SPOOL_REG_VERSIONNUMBER "versionNumber"
+
+/* container for a single registry key */
+
+typedef struct {
+ char *name;
+ REGVAL_CTR *values;
+} NT_PRINTER_KEY;
+
+/* container for all printer data */
+
+typedef struct {
+ int num_keys;
+ NT_PRINTER_KEY *keys;
+} NT_PRINTER_DATA;
+
+#define MAXDEVICENAME 32
+
+typedef struct ntdevicemode
+{
+ fstring devicename;
+ fstring formname;
+
+ uint16 specversion;
+ uint16 driverversion;
+ uint16 size;
+ uint16 driverextra;
+ uint16 orientation;
+ uint16 papersize;
+ uint16 paperlength;
+ uint16 paperwidth;
+ uint16 scale;
+ uint16 copies;
+ uint16 defaultsource;
+ uint16 printquality;
+ uint16 color;
+ uint16 duplex;
+ uint16 yresolution;
+ uint16 ttoption;
+ uint16 collate;
+ uint16 logpixels;
+
+ uint32 fields;
+ uint32 bitsperpel;
+ uint32 pelswidth;
+ uint32 pelsheight;
+ uint32 displayflags;
+ uint32 displayfrequency;
+ uint32 icmmethod;
+ uint32 icmintent;
+ uint32 mediatype;
+ uint32 dithertype;
+ uint32 reserved1;
+ uint32 reserved2;
+ uint32 panningwidth;
+ uint32 panningheight;
+ uint8 *nt_dev_private;
+} NT_DEVICEMODE;
+
+typedef struct nt_printer_info_level_2
+{
+ uint32 attributes;
+ uint32 priority;
+ uint32 default_priority;
+ uint32 starttime;
+ uint32 untiltime;
+ uint32 status;
+ uint32 cjobs;
+ uint32 averageppm;
+ fstring servername;
+ fstring printername;
+ fstring sharename;
+ fstring portname;
+ fstring drivername;
+ char comment[1024];
+ fstring location;
+ NT_DEVICEMODE *devmode;
+ fstring sepfile;
+ fstring printprocessor;
+ fstring datatype;
+ fstring parameters;
+ NT_PRINTER_DATA *data;
+ SEC_DESC_BUF *secdesc_buf;
+ uint32 changeid;
+ uint32 c_setprinter;
+ uint32 setuptime;
+} NT_PRINTER_INFO_LEVEL_2;
+
+typedef struct nt_printer_info_level
+{
+ NT_PRINTER_INFO_LEVEL_2 *info_2;
+} NT_PRINTER_INFO_LEVEL;
+
+typedef struct
+{
+ fstring name;
+ uint32 flag;
+ uint32 width;
+ uint32 length;
+ uint32 left;
+ uint32 top;
+ uint32 right;
+ uint32 bottom;
+} nt_forms_struct;
+
+#ifndef SAMBA_PRINTER_PORT_NAME
+#define SAMBA_PRINTER_PORT_NAME "Samba Printer Port"
+#endif
+
+
+/*
+ * Structures for the XcvDataPort() calls
+ */
+
+#define PORT_PROTOCOL_DIRECT 1
+#define PORT_PROTOCOL_LPR 2
+
+typedef struct {
+ fstring name;
+ uint32 version;
+ uint32 protocol;
+ fstring hostaddr;
+ fstring snmpcommunity;
+ fstring queue;
+ uint32 dblspool;
+ fstring ipaddr;
+ uint32 port;
+ bool enable_snmp;
+ uint32 snmp_index;
+} NT_PORT_DATA_1;
+
+/* DOS header format */
+#define DOS_HEADER_SIZE 64
+#define DOS_HEADER_MAGIC_OFFSET 0
+#define DOS_HEADER_MAGIC 0x5A4D
+#define DOS_HEADER_LFANEW_OFFSET 60
+
+/* New Executable format (Win or OS/2 1.x segmented) */
+#define NE_HEADER_SIZE 64
+#define NE_HEADER_SIGNATURE_OFFSET 0
+#define NE_HEADER_SIGNATURE 0x454E
+#define NE_HEADER_TARGET_OS_OFFSET 54
+#define NE_HEADER_TARGOS_WIN 0x02
+#define NE_HEADER_MINOR_VER_OFFSET 62
+#define NE_HEADER_MAJOR_VER_OFFSET 63
+
+/* Portable Executable format */
+#define PE_HEADER_SIZE 24
+#define PE_HEADER_SIGNATURE_OFFSET 0
+#define PE_HEADER_SIGNATURE 0x00004550
+#define PE_HEADER_MACHINE_OFFSET 4
+#define PE_HEADER_MACHINE_I386 0x14c
+#define PE_HEADER_NUMBER_OF_SECTIONS 6
+#define PE_HEADER_OPTIONAL_HEADER_SIZE 20
+#define PE_HEADER_SECT_HEADER_SIZE 40
+#define PE_HEADER_SECT_NAME_OFFSET 0
+#define PE_HEADER_SECT_SIZE_DATA_OFFSET 16
+#define PE_HEADER_SECT_PTR_DATA_OFFSET 20
+
+/* Microsoft file version format */
+#define VS_SIGNATURE "VS_VERSION_INFO"
+#define VS_MAGIC_VALUE 0xfeef04bd
+#define VS_MAJOR_OFFSET 8
+#define VS_MINOR_OFFSET 12
+#define VS_VERSION_INFO_UNICODE_SIZE (sizeof(VS_SIGNATURE)*2+4+VS_MINOR_OFFSET+4) /* not true size! */
+#define VS_VERSION_INFO_SIZE (sizeof(VS_SIGNATURE)+4+VS_MINOR_OFFSET+4) /* not true size! */
+#define VS_NE_BUF_SIZE 4096 /* Must be > 2*VS_VERSION_INFO_SIZE */
+
+/* Notify spoolss clients that something has changed. The
+ notification data is either stored in two uint32 values or a
+ variable length array. */
+
+#define SPOOLSS_NOTIFY_MSG_UNIX_JOBID 0x0001 /* Job id is unix */
+
+typedef struct spoolss_notify_msg {
+ fstring printer; /* Name of printer notified */
+ uint32 type; /* Printer or job notify */
+ uint32 field; /* Notify field changed */
+ uint32 id; /* Job id */
+ uint32 len; /* Length of data, 0 for two uint32 value */
+ uint32 flags;
+ union {
+ uint32 value[2];
+ char *data;
+ } notify;
+} SPOOLSS_NOTIFY_MSG;
+
+typedef struct {
+ fstring printername;
+ uint32 num_msgs;
+ SPOOLSS_NOTIFY_MSG *msgs;
+} SPOOLSS_NOTIFY_MSG_GROUP;
+
+typedef struct {
+ TALLOC_CTX *ctx;
+ uint32 num_groups;
+ SPOOLSS_NOTIFY_MSG_GROUP *msg_groups;
+} SPOOLSS_NOTIFY_MSG_CTR;
+
+#define SPLHND_PRINTER 1
+#define SPLHND_SERVER 2
+#define SPLHND_PORTMON_TCP 3
+#define SPLHND_PORTMON_LOCAL 4
+
+/* structure to store the printer handles */
+/* and a reference to what it's pointing to */
+/* and the notify info asked about */
+/* that's the central struct */
+typedef struct _Printer{
+ struct _Printer *prev, *next;
+ bool document_started;
+ bool page_started;
+ uint32 jobid; /* jobid in printing backend */
+ int printer_type;
+ TALLOC_CTX *ctx;
+ fstring servername;
+ fstring sharename;
+ uint32 type;
+ uint32 access_granted;
+ struct {
+ uint32 flags;
+ uint32 options;
+ fstring localmachine;
+ uint32 printerlocal;
+ SPOOL_NOTIFY_OPTION *option;
+ POLICY_HND client_hnd;
+ bool client_connected;
+ uint32 change;
+ /* are we in a FindNextPrinterChangeNotify() call? */
+ bool fnpcn;
+ } notify;
+ struct {
+ fstring machine;
+ fstring user;
+ } client;
+
+ /* devmode sent in the OpenPrinter() call */
+ NT_DEVICEMODE *nt_devmode;
+
+ /* cache the printer info */
+ NT_PRINTER_INFO_LEVEL *printer_info;
+
+} Printer_entry;
+
+#endif /* NT_PRINTING_H_ */
diff --git a/source3/include/nt_status.h b/source3/include/nt_status.h
new file mode 100644
index 0000000000..30174e4b51
--- /dev/null
+++ b/source3/include/nt_status.h
@@ -0,0 +1,115 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup, plus a whole lot more.
+
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NT_STATUS_H
+#define _NT_STATUS_H
+
+/* The Splint code analysis tool doesn't like immediate structures. */
+
+#ifdef _SPLINT_ /* http://www.splint.org */
+#undef HAVE_IMMEDIATE_STRUCTURES
+#endif
+
+/* The following rather strange looking definitions of NTSTATUS and WERROR
+ are there in order to catch common coding errors where different error types
+ are mixed up. This is especially important as we slowly convert Samba
+ from using bool for internal functions.
+*/
+
+#if defined(HAVE_IMMEDIATE_STRUCTURES)
+typedef struct {uint32 v;} NTSTATUS;
+#define NT_STATUS(x) ((NTSTATUS) { x })
+#define NT_STATUS_V(x) ((x).v)
+#else
+typedef uint32 NTSTATUS;
+#define NT_STATUS(x) (x)
+#define NT_STATUS_V(x) (x)
+#endif
+
+#if defined(HAVE_IMMEDIATE_STRUCTURES)
+typedef struct {uint32 w;} WERROR;
+#define W_ERROR(x) ((WERROR) { x })
+#define W_ERROR_V(x) ((x).w)
+#else
+typedef uint32 WERROR;
+#define W_ERROR(x) (x)
+#define W_ERROR_V(x) (x)
+#endif
+
+#define NT_STATUS_IS_OK(x) (NT_STATUS_V(x) == 0)
+#define NT_STATUS_IS_ERR(x) ((NT_STATUS_V(x) & 0xc0000000) == 0xc0000000)
+#define NT_STATUS_EQUAL(x,y) (NT_STATUS_V(x) == NT_STATUS_V(y))
+#define W_ERROR_IS_OK(x) (W_ERROR_V(x) == 0)
+#define W_ERROR_EQUAL(x,y) (W_ERROR_V(x) == W_ERROR_V(y))
+
+#define NT_STATUS_HAVE_NO_MEMORY(x) do { \
+ if (!(x)) {\
+ return NT_STATUS_NO_MEMORY;\
+ }\
+} while (0)
+
+#define NT_STATUS_NOT_OK_RETURN(x) do { \
+ if (!NT_STATUS_IS_OK(x)) {\
+ return x;\
+ }\
+} while (0)
+
+#define W_ERROR_HAVE_NO_MEMORY(x) do { \
+ if (!(x)) {\
+ return WERR_NOMEM;\
+ }\
+} while (0)
+
+#define W_ERROR_NOT_OK_RETURN(x) do { \
+ if (!W_ERROR_IS_OK(x)) {\
+ return x;\
+ }\
+} while (0)
+
+/* The top byte in an NTSTATUS code is used as a type field.
+ * Windows only uses value 0xC0 as an indicator for an NT error
+ * and 0x00 for success.
+ * So we can use the type field to store other types of error codes
+ * inside the three lower bytes.
+ * NB: The system error codes (errno) are not integrated via a type of
+ * their own but are mapped to genuine NT error codes via
+ * map_nt_error_from_unix() */
+
+#define NT_STATUS_TYPE(status) ((NT_STATUS_V(status) & 0xFF000000) >> 24)
+
+#define NT_STATUS_TYPE_DOS 0xF1
+#define NT_STATUS_TYPE_LDAP 0xF2
+
+/* this defines special NTSTATUS codes to represent DOS errors. I
+ have chosen this macro to produce status codes in the invalid
+ NTSTATUS range */
+#define NT_STATUS_DOS_MASK (NT_STATUS_TYPE_DOS << 24)
+#define NT_STATUS_DOS(class, code) NT_STATUS(NT_STATUS_DOS_MASK | ((class)<<16) | code)
+#define NT_STATUS_IS_DOS(status) ((NT_STATUS_V(status) & 0xFF000000) == NT_STATUS_DOS_MASK)
+#define NT_STATUS_DOS_CLASS(status) ((NT_STATUS_V(status) >> 16) & 0xFF)
+#define NT_STATUS_DOS_CODE(status) (NT_STATUS_V(status) & 0xFFFF)
+
+/* define ldap error codes as NTSTATUS codes */
+#define NT_STATUS_LDAP_MASK (NT_STATUS_TYPE_LDAP << 24)
+#define NT_STATUS_LDAP(code) NT_STATUS(NT_STATUS_LDAP_MASK | code)
+#define NT_STATUS_IS_LDAP(status) ((NT_STATUS_V(status) & 0xFF000000) == NT_STATUS_LDAP_MASK)
+#define NT_STATUS_LDAP_CODE(status) (NT_STATUS_V(status) & ~0xFF000000)
+
+#endif
diff --git a/source3/include/ntdomain.h b/source3/include/ntdomain.h
new file mode 100644
index 0000000000..de0a313609
--- /dev/null
+++ b/source3/include/ntdomain.h
@@ -0,0 +1,376 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Paul Ashton 1997
+ Copyright (C) Jeremy Allison 2000-2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NT_DOMAIN_H /* _NT_DOMAIN_H */
+#define _NT_DOMAIN_H
+
+/*
+ * A bunch of stuff that was put into smb.h
+ * in the NTDOM branch - it didn't belong there.
+ */
+
+typedef struct _prs_struct {
+ bool io; /* parsing in or out of data stream */
+ /*
+ * If the (incoming) data is big-endian. On output we are
+ * always little-endian.
+ */
+ bool bigendian_data;
+ uint8 align; /* data alignment */
+ bool is_dynamic; /* Do we own this memory or not ? */
+ uint32 data_offset; /* Current working offset into data. */
+ uint32 buffer_size; /* Current allocated size of the buffer. */
+ uint32 grow_size; /* size requested via prs_grow() calls */
+ char *data_p; /* The buffer itself. */
+ TALLOC_CTX *mem_ctx; /* When unmarshalling, use this.... */
+ const char *sess_key; /* If we have to do encrypt/decrypt on the fly. */
+} prs_struct;
+
+/*
+ * Defines for io member of prs_struct.
+ */
+
+#define MARSHALL 0
+#define UNMARSHALL 1
+
+#define MARSHALLING(ps) (!(ps)->io)
+#define UNMARSHALLING(ps) ((ps)->io)
+
+#define RPC_BIG_ENDIAN 1
+#define RPC_LITTLE_ENDIAN 0
+
+#define RPC_PARSE_ALIGN 4
+
+typedef struct _output_data {
+ /*
+ * Raw RPC output data. This does not include RPC headers or footers.
+ */
+ prs_struct rdata;
+
+ /* The amount of data sent from the current rdata struct. */
+ uint32 data_sent_length;
+
+ /*
+ * The current PDU being returned. This inclues
+ * headers, data and authentication footer.
+ */
+ unsigned char current_pdu[RPC_MAX_PDU_FRAG_LEN];
+
+ /* The amount of data in the current_pdu buffer. */
+ uint32 current_pdu_len;
+
+ /* The amount of data sent from the current PDU. */
+ uint32 current_pdu_sent;
+} output_data;
+
+typedef struct _input_data {
+ /*
+ * This is the current incoming pdu. The data here
+ * is collected via multiple writes until a complete
+ * pdu is seen, then the data is copied into the in_data
+ * structure. The maximum size of this is 0x1630 (RPC_MAX_PDU_FRAG_LEN).
+ */
+ unsigned char current_in_pdu[RPC_MAX_PDU_FRAG_LEN];
+
+ /*
+ * The amount of data needed to complete the in_pdu.
+ * If this is zero, then we are at the start of a new
+ * pdu.
+ */
+ uint32 pdu_needed_len;
+
+ /*
+ * The amount of data received so far in the in_pdu.
+ * If this is zero, then we are at the start of a new
+ * pdu.
+ */
+ uint32 pdu_received_len;
+
+ /*
+ * This is the collection of input data with all
+ * the rpc headers and auth footers removed.
+ * The maximum length of this (1Mb) is strictly enforced.
+ */
+ prs_struct data;
+} input_data;
+
+/*
+ * Handle database - stored per pipe.
+ */
+
+struct policy {
+ struct policy *next, *prev;
+
+ POLICY_HND pol_hnd;
+
+ void *data_ptr;
+ void (*free_fn)(void *);
+};
+
+struct handle_list {
+ struct policy *Policy; /* List of policies. */
+ size_t count; /* Current number of handles. */
+ size_t pipe_ref_count; /* Number of pipe handles referring to this list. */
+};
+
+/* Domain controller authentication protocol info */
+struct dcinfo {
+ uint32 sequence; /* "timestamp" from client. */
+ struct netr_Credential seed_chal;
+ struct netr_Credential clnt_chal; /* Client credential */
+ struct netr_Credential srv_chal; /* Server credential */
+
+ unsigned char sess_key[16]; /* Session key - 8 bytes followed by 8 zero bytes */
+ unsigned char mach_pw[16]; /* md4(machine password) */
+
+ fstring mach_acct; /* Machine name we've authenticated. */
+
+ fstring remote_machine; /* Machine name we've authenticated. */
+ fstring domain;
+
+ bool challenge_sent;
+ bool authenticated;
+};
+
+typedef struct pipe_rpc_fns {
+
+ struct pipe_rpc_fns *next, *prev;
+
+ /* RPC function table associated with the current rpc_bind (associated by context) */
+
+ const struct api_struct *cmds;
+ int n_cmds;
+ uint32 context_id;
+
+} PIPE_RPC_FNS;
+
+/*
+ * Different auth types we support.
+ * Can't keep in sync with wire values as spnego wraps different auth methods.
+ */
+
+enum pipe_auth_type { PIPE_AUTH_TYPE_NONE = 0, PIPE_AUTH_TYPE_NTLMSSP, PIPE_AUTH_TYPE_SCHANNEL,
+ PIPE_AUTH_TYPE_SPNEGO_NTLMSSP, PIPE_AUTH_TYPE_KRB5, PIPE_AUTH_TYPE_SPNEGO_KRB5 };
+
+/* Possible auth levels - keep these in sync with the wire values. */
+enum pipe_auth_level { PIPE_AUTH_LEVEL_NONE = 0,
+ PIPE_AUTH_LEVEL_CONNECT = 1, /* We treat as NONE. */
+ PIPE_AUTH_LEVEL_INTEGRITY = 5, /* Sign. */
+ PIPE_AUTH_LEVEL_PRIVACY = 6 /* Seal. */
+};
+
+/* auth state for krb5. */
+struct kerberos_auth_struct {
+ const char *service_principal;
+ DATA_BLOB session_key;
+};
+
+/* auth state for schannel. */
+struct schannel_auth_struct {
+ unsigned char sess_key[16];
+ uint32 seq_num;
+};
+
+/* auth state for all bind types. */
+
+struct pipe_auth_data {
+ enum pipe_auth_type auth_type; /* switch for union below. */
+ enum pipe_auth_level auth_level;
+ union {
+ struct schannel_auth_struct *schannel_auth;
+ AUTH_NTLMSSP_STATE *auth_ntlmssp_state;
+/* struct kerberos_auth_struct *kerberos_auth; TO BE ADDED... */
+ } a_u;
+ void (*auth_data_free_func)(struct pipe_auth_data *);
+};
+
+/*
+ * DCE/RPC-specific samba-internal-specific handling of data on
+ * NamedPipes.
+ */
+
+typedef struct pipes_struct {
+ struct pipes_struct *next, *prev;
+
+ char client_address[INET6_ADDRSTRLEN];
+
+ struct auth_serversupplied_info *server_info;
+
+ fstring name;
+ fstring pipe_srv_name;
+
+ /* linked list of rpc dispatch tables associated
+ with the open rpc contexts */
+
+ PIPE_RPC_FNS *contexts;
+
+ RPC_HDR hdr; /* Incoming RPC header. */
+ RPC_HDR_REQ hdr_req; /* Incoming request header. */
+
+ struct pipe_auth_data auth;
+
+ struct dcinfo *dc; /* Keeps the creds data from netlogon. */
+
+ /*
+ * Unix user name and credentials used when a pipe is authenticated.
+ */
+
+ struct current_user pipe_user;
+
+ /*
+ * Set to true when an RPC bind has been done on this pipe.
+ */
+
+ bool pipe_bound;
+
+ /*
+ * Set to true when we should return fault PDU's for everything.
+ */
+
+ bool fault_state;
+
+ /*
+ * Set to true when we should return fault PDU's for a bad handle.
+ */
+
+ bool bad_handle_fault_state;
+
+ /*
+ * Set to true when the backend does not support a call.
+ */
+
+ bool rng_fault_state;
+
+ /*
+ * Set to RPC_BIG_ENDIAN when dealing with big-endian PDU's
+ */
+
+ bool endian;
+
+ /*
+ * Struct to deal with multiple pdu inputs.
+ */
+
+ input_data in_data;
+
+ /*
+ * Struct to deal with multiple pdu outputs.
+ */
+
+ output_data out_data;
+
+ /* This context is used for PDU data and is freed between each pdu.
+ Don't use for pipe state storage. */
+ TALLOC_CTX *mem_ctx;
+
+ /* handle database to use on this pipe. */
+ struct handle_list *pipe_handles;
+
+} pipes_struct;
+
+typedef struct smb_np_struct {
+ struct smb_np_struct *next, *prev;
+ int pnum;
+ connection_struct *conn;
+ uint16 vuid; /* points to the unauthenticated user that opened this pipe. */
+ bool open; /* open connection */
+ uint16 device_state;
+ uint16 priority;
+ char *name;
+
+ /* When replying to an SMBtrans, this is the maximum amount of
+ data that can be sent in the initial reply. */
+ int max_trans_reply;
+
+ /*
+ * NamedPipe state information.
+ */
+ struct pipes_struct *np_state;
+
+ /*
+ * NamedPipe functions, to be called to perform
+ * Named Pipe transactions on request from an
+ * SMB client.
+ */
+
+ /* call to create a named pipe connection.
+ * returns: state information representing the connection.
+ * is stored in np_state, above.
+ */
+ struct pipes_struct *(*namedpipe_create)(
+ const char *pipe_name,
+ const char *client_address,
+ struct auth_serversupplied_info *server_info,
+ uint16_t vuid);
+
+ /* call to perform a write namedpipe operation
+ */
+ ssize_t (*namedpipe_write)(struct pipes_struct *p,
+ char *data, size_t n);
+
+ /* call to perform a read namedpipe operation.
+ *
+ * NOTE: the only reason that the pipe_outstanding
+ * argument is here is because samba does not use
+ * the namedpipe_transact function yet: instead,
+ * it performs the same as what namedpipe_transact
+ * does - a write, followed by a read.
+ *
+ * when samba is modified to use namedpipe_transact,
+ * the pipe_outstanding argument may be removed.
+ */
+ ssize_t (*namedpipe_read)(struct pipes_struct *p,
+ char *data, size_t max_len,
+ bool *pipe_outstanding);
+
+} smb_np_struct;
+
+struct api_struct {
+ const char *name;
+ uint8 opnum;
+ bool (*fn) (pipes_struct *);
+};
+
+typedef struct {
+ uint32 rid;
+ const char *name;
+} rid_name;
+
+/*
+ * higher order functions for use with msrpc client code
+ */
+
+#define PRINT_INFO_FN(fn)\
+ void (*fn)(const char*, uint32, uint32, void *const *const)
+#define JOB_INFO_FN(fn)\
+ void (*fn)(const char*, const char*, uint32, uint32, void *const *const)
+
+/* end higher order functions */
+
+typedef struct {
+ uint32 size;
+ prs_struct prs;
+ uint32 struct_start;
+ uint32 string_at_end;
+} RPC_BUFFER;
+
+#endif /* _NT_DOMAIN_H */
diff --git a/source3/include/nterr.h b/source3/include/nterr.h
new file mode 100644
index 0000000000..612cf6ea1b
--- /dev/null
+++ b/source3/include/nterr.h
@@ -0,0 +1,571 @@
+/*
+ Unix SMB/CIFS implementation.
+ NT error code constants
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) John H Terpstra 1996-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Paul Ashton 1998-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NTERR_H
+#define _NTERR_H
+
+/* Win32 Status codes. */
+
+#define STATUS_BUFFER_OVERFLOW NT_STATUS(0x80000005)
+#define STATUS_NO_MORE_FILES NT_STATUS(0x80000006)
+#define NT_STATUS_NO_MORE_ENTRIES NT_STATUS(0x8000001a)
+
+/* Vista Status codes. */
+#define NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT NT_STATUS(0x8000002d)
+
+#define STATUS_MORE_ENTRIES NT_STATUS(0x0105)
+#define STATUS_SOME_UNMAPPED NT_STATUS(0x0107)
+#define ERROR_INVALID_PARAMETER NT_STATUS(0x0057)
+#define ERROR_INSUFFICIENT_BUFFER NT_STATUS(0x007a)
+#define STATUS_NOTIFY_ENUM_DIR NT_STATUS(0x010c)
+#define ERROR_INVALID_DATATYPE NT_STATUS(0x070c)
+
+/* Win32 Error codes extracted using a loop in smbclient then printing a
+ netmon sniff to a file. */
+
+/*
+ --------------
+ / \
+ / REST \
+ / IN \
+ / PEACE \
+ / \
+ | NT_STATUS_NOPROBLEMO |
+ | |
+ | |
+ | 4 September |
+ | |
+ | 2001 |
+ *| * * * | *
+ _________)/\\_//(\/(/\)/\//\/\///|_)_______
+*/
+
+#define NT_STATUS_OK NT_STATUS(0x0000)
+#define NT_STATUS_UNSUCCESSFUL NT_STATUS(0xC0000000 | 0x0001)
+#define NT_STATUS_NOT_IMPLEMENTED NT_STATUS(0xC0000000 | 0x0002)
+#define NT_STATUS_INVALID_INFO_CLASS NT_STATUS(0xC0000000 | 0x0003)
+#define NT_STATUS_INFO_LENGTH_MISMATCH NT_STATUS(0xC0000000 | 0x0004)
+#define NT_STATUS_ACCESS_VIOLATION NT_STATUS(0xC0000000 | 0x0005)
+#define NT_STATUS_IN_PAGE_ERROR NT_STATUS(0xC0000000 | 0x0006)
+#define NT_STATUS_PAGEFILE_QUOTA NT_STATUS(0xC0000000 | 0x0007)
+#define NT_STATUS_INVALID_HANDLE NT_STATUS(0xC0000000 | 0x0008)
+#define NT_STATUS_BAD_INITIAL_STACK NT_STATUS(0xC0000000 | 0x0009)
+#define NT_STATUS_BAD_INITIAL_PC NT_STATUS(0xC0000000 | 0x000a)
+#define NT_STATUS_INVALID_CID NT_STATUS(0xC0000000 | 0x000b)
+#define NT_STATUS_TIMER_NOT_CANCELED NT_STATUS(0xC0000000 | 0x000c)
+#define NT_STATUS_INVALID_PARAMETER NT_STATUS(0xC0000000 | 0x000d)
+#define NT_STATUS_NO_SUCH_DEVICE NT_STATUS(0xC0000000 | 0x000e)
+#define NT_STATUS_NO_SUCH_FILE NT_STATUS(0xC0000000 | 0x000f)
+#define NT_STATUS_INVALID_DEVICE_REQUEST NT_STATUS(0xC0000000 | 0x0010)
+#define NT_STATUS_END_OF_FILE NT_STATUS(0xC0000000 | 0x0011)
+#define NT_STATUS_WRONG_VOLUME NT_STATUS(0xC0000000 | 0x0012)
+#define NT_STATUS_NO_MEDIA_IN_DEVICE NT_STATUS(0xC0000000 | 0x0013)
+#define NT_STATUS_UNRECOGNIZED_MEDIA NT_STATUS(0xC0000000 | 0x0014)
+#define NT_STATUS_NONEXISTENT_SECTOR NT_STATUS(0xC0000000 | 0x0015)
+#define NT_STATUS_MORE_PROCESSING_REQUIRED NT_STATUS(0xC0000000 | 0x0016)
+#define NT_STATUS_NO_MEMORY NT_STATUS(0xC0000000 | 0x0017)
+#define NT_STATUS_CONFLICTING_ADDRESSES NT_STATUS(0xC0000000 | 0x0018)
+#define NT_STATUS_NOT_MAPPED_VIEW NT_STATUS(0xC0000000 | 0x0019)
+#define NT_STATUS_UNABLE_TO_FREE_VM NT_STATUS(0xC0000000 | 0x001a)
+#define NT_STATUS_UNABLE_TO_DELETE_SECTION NT_STATUS(0xC0000000 | 0x001b)
+#define NT_STATUS_INVALID_SYSTEM_SERVICE NT_STATUS(0xC0000000 | 0x001c)
+#define NT_STATUS_ILLEGAL_INSTRUCTION NT_STATUS(0xC0000000 | 0x001d)
+#define NT_STATUS_INVALID_LOCK_SEQUENCE NT_STATUS(0xC0000000 | 0x001e)
+#define NT_STATUS_INVALID_VIEW_SIZE NT_STATUS(0xC0000000 | 0x001f)
+#define NT_STATUS_INVALID_FILE_FOR_SECTION NT_STATUS(0xC0000000 | 0x0020)
+#define NT_STATUS_ALREADY_COMMITTED NT_STATUS(0xC0000000 | 0x0021)
+#define NT_STATUS_ACCESS_DENIED NT_STATUS(0xC0000000 | 0x0022)
+#define NT_STATUS_BUFFER_TOO_SMALL NT_STATUS(0xC0000000 | 0x0023)
+#define NT_STATUS_OBJECT_TYPE_MISMATCH NT_STATUS(0xC0000000 | 0x0024)
+#define NT_STATUS_NONCONTINUABLE_EXCEPTION NT_STATUS(0xC0000000 | 0x0025)
+#define NT_STATUS_INVALID_DISPOSITION NT_STATUS(0xC0000000 | 0x0026)
+#define NT_STATUS_UNWIND NT_STATUS(0xC0000000 | 0x0027)
+#define NT_STATUS_BAD_STACK NT_STATUS(0xC0000000 | 0x0028)
+#define NT_STATUS_INVALID_UNWIND_TARGET NT_STATUS(0xC0000000 | 0x0029)
+#define NT_STATUS_NOT_LOCKED NT_STATUS(0xC0000000 | 0x002a)
+#define NT_STATUS_PARITY_ERROR NT_STATUS(0xC0000000 | 0x002b)
+#define NT_STATUS_UNABLE_TO_DECOMMIT_VM NT_STATUS(0xC0000000 | 0x002c)
+#define NT_STATUS_NOT_COMMITTED NT_STATUS(0xC0000000 | 0x002d)
+#define NT_STATUS_INVALID_PORT_ATTRIBUTES NT_STATUS(0xC0000000 | 0x002e)
+#define NT_STATUS_PORT_MESSAGE_TOO_LONG NT_STATUS(0xC0000000 | 0x002f)
+#define NT_STATUS_INVALID_PARAMETER_MIX NT_STATUS(0xC0000000 | 0x0030)
+#define NT_STATUS_INVALID_QUOTA_LOWER NT_STATUS(0xC0000000 | 0x0031)
+#define NT_STATUS_DISK_CORRUPT_ERROR NT_STATUS(0xC0000000 | 0x0032)
+#define NT_STATUS_OBJECT_NAME_INVALID NT_STATUS(0xC0000000 | 0x0033)
+#define NT_STATUS_OBJECT_NAME_NOT_FOUND NT_STATUS(0xC0000000 | 0x0034)
+#define NT_STATUS_OBJECT_NAME_COLLISION NT_STATUS(0xC0000000 | 0x0035)
+#define NT_STATUS_HANDLE_NOT_WAITABLE NT_STATUS(0xC0000000 | 0x0036)
+#define NT_STATUS_PORT_DISCONNECTED NT_STATUS(0xC0000000 | 0x0037)
+#define NT_STATUS_DEVICE_ALREADY_ATTACHED NT_STATUS(0xC0000000 | 0x0038)
+#define NT_STATUS_OBJECT_PATH_INVALID NT_STATUS(0xC0000000 | 0x0039)
+#define NT_STATUS_OBJECT_PATH_NOT_FOUND NT_STATUS(0xC0000000 | 0x003a)
+#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD NT_STATUS(0xC0000000 | 0x003b)
+#define NT_STATUS_DATA_OVERRUN NT_STATUS(0xC0000000 | 0x003c)
+#define NT_STATUS_DATA_LATE_ERROR NT_STATUS(0xC0000000 | 0x003d)
+#define NT_STATUS_DATA_ERROR NT_STATUS(0xC0000000 | 0x003e)
+#define NT_STATUS_CRC_ERROR NT_STATUS(0xC0000000 | 0x003f)
+#define NT_STATUS_SECTION_TOO_BIG NT_STATUS(0xC0000000 | 0x0040)
+#define NT_STATUS_PORT_CONNECTION_REFUSED NT_STATUS(0xC0000000 | 0x0041)
+#define NT_STATUS_INVALID_PORT_HANDLE NT_STATUS(0xC0000000 | 0x0042)
+#define NT_STATUS_SHARING_VIOLATION NT_STATUS(0xC0000000 | 0x0043)
+#define NT_STATUS_QUOTA_EXCEEDED NT_STATUS(0xC0000000 | 0x0044)
+#define NT_STATUS_INVALID_PAGE_PROTECTION NT_STATUS(0xC0000000 | 0x0045)
+#define NT_STATUS_MUTANT_NOT_OWNED NT_STATUS(0xC0000000 | 0x0046)
+#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED NT_STATUS(0xC0000000 | 0x0047)
+#define NT_STATUS_PORT_ALREADY_SET NT_STATUS(0xC0000000 | 0x0048)
+#define NT_STATUS_SECTION_NOT_IMAGE NT_STATUS(0xC0000000 | 0x0049)
+#define NT_STATUS_SUSPEND_COUNT_EXCEEDED NT_STATUS(0xC0000000 | 0x004a)
+#define NT_STATUS_THREAD_IS_TERMINATING NT_STATUS(0xC0000000 | 0x004b)
+#define NT_STATUS_BAD_WORKING_SET_LIMIT NT_STATUS(0xC0000000 | 0x004c)
+#define NT_STATUS_INCOMPATIBLE_FILE_MAP NT_STATUS(0xC0000000 | 0x004d)
+#define NT_STATUS_SECTION_PROTECTION NT_STATUS(0xC0000000 | 0x004e)
+#define NT_STATUS_EAS_NOT_SUPPORTED NT_STATUS(0xC0000000 | 0x004f)
+#define NT_STATUS_EA_TOO_LARGE NT_STATUS(0xC0000000 | 0x0050)
+#define NT_STATUS_NONEXISTENT_EA_ENTRY NT_STATUS(0xC0000000 | 0x0051)
+#define NT_STATUS_NO_EAS_ON_FILE NT_STATUS(0xC0000000 | 0x0052)
+#define NT_STATUS_EA_CORRUPT_ERROR NT_STATUS(0xC0000000 | 0x0053)
+#define NT_STATUS_FILE_LOCK_CONFLICT NT_STATUS(0xC0000000 | 0x0054)
+#define NT_STATUS_LOCK_NOT_GRANTED NT_STATUS(0xC0000000 | 0x0055)
+#define NT_STATUS_DELETE_PENDING NT_STATUS(0xC0000000 | 0x0056)
+#define NT_STATUS_CTL_FILE_NOT_SUPPORTED NT_STATUS(0xC0000000 | 0x0057)
+#define NT_STATUS_UNKNOWN_REVISION NT_STATUS(0xC0000000 | 0x0058)
+#define NT_STATUS_REVISION_MISMATCH NT_STATUS(0xC0000000 | 0x0059)
+#define NT_STATUS_INVALID_OWNER NT_STATUS(0xC0000000 | 0x005a)
+#define NT_STATUS_INVALID_PRIMARY_GROUP NT_STATUS(0xC0000000 | 0x005b)
+#define NT_STATUS_NO_IMPERSONATION_TOKEN NT_STATUS(0xC0000000 | 0x005c)
+#define NT_STATUS_CANT_DISABLE_MANDATORY NT_STATUS(0xC0000000 | 0x005d)
+#define NT_STATUS_NO_LOGON_SERVERS NT_STATUS(0xC0000000 | 0x005e)
+#define NT_STATUS_NO_SUCH_LOGON_SESSION NT_STATUS(0xC0000000 | 0x005f)
+#define NT_STATUS_NO_SUCH_PRIVILEGE NT_STATUS(0xC0000000 | 0x0060)
+#define NT_STATUS_PRIVILEGE_NOT_HELD NT_STATUS(0xC0000000 | 0x0061)
+#define NT_STATUS_INVALID_ACCOUNT_NAME NT_STATUS(0xC0000000 | 0x0062)
+#define NT_STATUS_USER_EXISTS NT_STATUS(0xC0000000 | 0x0063)
+#define NT_STATUS_NO_SUCH_USER NT_STATUS(0xC0000000 | 0x0064)
+#define NT_STATUS_GROUP_EXISTS NT_STATUS(0xC0000000 | 0x0065)
+#define NT_STATUS_NO_SUCH_GROUP NT_STATUS(0xC0000000 | 0x0066)
+#define NT_STATUS_MEMBER_IN_GROUP NT_STATUS(0xC0000000 | 0x0067)
+#define NT_STATUS_MEMBER_NOT_IN_GROUP NT_STATUS(0xC0000000 | 0x0068)
+#define NT_STATUS_LAST_ADMIN NT_STATUS(0xC0000000 | 0x0069)
+#define NT_STATUS_WRONG_PASSWORD NT_STATUS(0xC0000000 | 0x006a)
+#define NT_STATUS_ILL_FORMED_PASSWORD NT_STATUS(0xC0000000 | 0x006b)
+#define NT_STATUS_PASSWORD_RESTRICTION NT_STATUS(0xC0000000 | 0x006c)
+#define NT_STATUS_LOGON_FAILURE NT_STATUS(0xC0000000 | 0x006d)
+#define NT_STATUS_ACCOUNT_RESTRICTION NT_STATUS(0xC0000000 | 0x006e)
+#define NT_STATUS_INVALID_LOGON_HOURS NT_STATUS(0xC0000000 | 0x006f)
+#define NT_STATUS_INVALID_WORKSTATION NT_STATUS(0xC0000000 | 0x0070)
+#define NT_STATUS_PASSWORD_EXPIRED NT_STATUS(0xC0000000 | 0x0071)
+#define NT_STATUS_ACCOUNT_DISABLED NT_STATUS(0xC0000000 | 0x0072)
+#define NT_STATUS_NONE_MAPPED NT_STATUS(0xC0000000 | 0x0073)
+#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED NT_STATUS(0xC0000000 | 0x0074)
+#define NT_STATUS_LUIDS_EXHAUSTED NT_STATUS(0xC0000000 | 0x0075)
+#define NT_STATUS_INVALID_SUB_AUTHORITY NT_STATUS(0xC0000000 | 0x0076)
+#define NT_STATUS_INVALID_ACL NT_STATUS(0xC0000000 | 0x0077)
+#define NT_STATUS_INVALID_SID NT_STATUS(0xC0000000 | 0x0078)
+#define NT_STATUS_INVALID_SECURITY_DESCR NT_STATUS(0xC0000000 | 0x0079)
+#define NT_STATUS_PROCEDURE_NOT_FOUND NT_STATUS(0xC0000000 | 0x007a)
+#define NT_STATUS_INVALID_IMAGE_FORMAT NT_STATUS(0xC0000000 | 0x007b)
+#define NT_STATUS_NO_TOKEN NT_STATUS(0xC0000000 | 0x007c)
+#define NT_STATUS_BAD_INHERITANCE_ACL NT_STATUS(0xC0000000 | 0x007d)
+#define NT_STATUS_RANGE_NOT_LOCKED NT_STATUS(0xC0000000 | 0x007e)
+#define NT_STATUS_DISK_FULL NT_STATUS(0xC0000000 | 0x007f)
+#define NT_STATUS_SERVER_DISABLED NT_STATUS(0xC0000000 | 0x0080)
+#define NT_STATUS_SERVER_NOT_DISABLED NT_STATUS(0xC0000000 | 0x0081)
+#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED NT_STATUS(0xC0000000 | 0x0082)
+#define NT_STATUS_GUIDS_EXHAUSTED NT_STATUS(0xC0000000 | 0x0083)
+#define NT_STATUS_INVALID_ID_AUTHORITY NT_STATUS(0xC0000000 | 0x0084)
+#define NT_STATUS_AGENTS_EXHAUSTED NT_STATUS(0xC0000000 | 0x0085)
+#define NT_STATUS_INVALID_VOLUME_LABEL NT_STATUS(0xC0000000 | 0x0086)
+#define NT_STATUS_SECTION_NOT_EXTENDED NT_STATUS(0xC0000000 | 0x0087)
+#define NT_STATUS_NOT_MAPPED_DATA NT_STATUS(0xC0000000 | 0x0088)
+#define NT_STATUS_RESOURCE_DATA_NOT_FOUND NT_STATUS(0xC0000000 | 0x0089)
+#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND NT_STATUS(0xC0000000 | 0x008a)
+#define NT_STATUS_RESOURCE_NAME_NOT_FOUND NT_STATUS(0xC0000000 | 0x008b)
+#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED NT_STATUS(0xC0000000 | 0x008c)
+#define NT_STATUS_FLOAT_DENORMAL_OPERAND NT_STATUS(0xC0000000 | 0x008d)
+#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO NT_STATUS(0xC0000000 | 0x008e)
+#define NT_STATUS_FLOAT_INEXACT_RESULT NT_STATUS(0xC0000000 | 0x008f)
+#define NT_STATUS_FLOAT_INVALID_OPERATION NT_STATUS(0xC0000000 | 0x0090)
+#define NT_STATUS_FLOAT_OVERFLOW NT_STATUS(0xC0000000 | 0x0091)
+#define NT_STATUS_FLOAT_STACK_CHECK NT_STATUS(0xC0000000 | 0x0092)
+#define NT_STATUS_FLOAT_UNDERFLOW NT_STATUS(0xC0000000 | 0x0093)
+#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO NT_STATUS(0xC0000000 | 0x0094)
+#define NT_STATUS_INTEGER_OVERFLOW NT_STATUS(0xC0000000 | 0x0095)
+#define NT_STATUS_PRIVILEGED_INSTRUCTION NT_STATUS(0xC0000000 | 0x0096)
+#define NT_STATUS_TOO_MANY_PAGING_FILES NT_STATUS(0xC0000000 | 0x0097)
+#define NT_STATUS_FILE_INVALID NT_STATUS(0xC0000000 | 0x0098)
+#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED NT_STATUS(0xC0000000 | 0x0099)
+#define NT_STATUS_INSUFFICIENT_RESOURCES NT_STATUS(0xC0000000 | 0x009a)
+#define NT_STATUS_DFS_EXIT_PATH_FOUND NT_STATUS(0xC0000000 | 0x009b)
+#define NT_STATUS_DEVICE_DATA_ERROR NT_STATUS(0xC0000000 | 0x009c)
+#define NT_STATUS_DEVICE_NOT_CONNECTED NT_STATUS(0xC0000000 | 0x009d)
+#define NT_STATUS_DEVICE_POWER_FAILURE NT_STATUS(0xC0000000 | 0x009e)
+#define NT_STATUS_FREE_VM_NOT_AT_BASE NT_STATUS(0xC0000000 | 0x009f)
+#define NT_STATUS_MEMORY_NOT_ALLOCATED NT_STATUS(0xC0000000 | 0x00a0)
+#define NT_STATUS_WORKING_SET_QUOTA NT_STATUS(0xC0000000 | 0x00a1)
+#define NT_STATUS_MEDIA_WRITE_PROTECTED NT_STATUS(0xC0000000 | 0x00a2)
+#define NT_STATUS_DEVICE_NOT_READY NT_STATUS(0xC0000000 | 0x00a3)
+#define NT_STATUS_INVALID_GROUP_ATTRIBUTES NT_STATUS(0xC0000000 | 0x00a4)
+#define NT_STATUS_BAD_IMPERSONATION_LEVEL NT_STATUS(0xC0000000 | 0x00a5)
+#define NT_STATUS_CANT_OPEN_ANONYMOUS NT_STATUS(0xC0000000 | 0x00a6)
+#define NT_STATUS_BAD_VALIDATION_CLASS NT_STATUS(0xC0000000 | 0x00a7)
+#define NT_STATUS_BAD_TOKEN_TYPE NT_STATUS(0xC0000000 | 0x00a8)
+#define NT_STATUS_BAD_MASTER_BOOT_RECORD NT_STATUS(0xC0000000 | 0x00a9)
+#define NT_STATUS_INSTRUCTION_MISALIGNMENT NT_STATUS(0xC0000000 | 0x00aa)
+#define NT_STATUS_INSTANCE_NOT_AVAILABLE NT_STATUS(0xC0000000 | 0x00ab)
+#define NT_STATUS_PIPE_NOT_AVAILABLE NT_STATUS(0xC0000000 | 0x00ac)
+#define NT_STATUS_INVALID_PIPE_STATE NT_STATUS(0xC0000000 | 0x00ad)
+#define NT_STATUS_PIPE_BUSY NT_STATUS(0xC0000000 | 0x00ae)
+#define NT_STATUS_ILLEGAL_FUNCTION NT_STATUS(0xC0000000 | 0x00af)
+#define NT_STATUS_PIPE_DISCONNECTED NT_STATUS(0xC0000000 | 0x00b0)
+#define NT_STATUS_PIPE_CLOSING NT_STATUS(0xC0000000 | 0x00b1)
+#define NT_STATUS_PIPE_CONNECTED NT_STATUS(0xC0000000 | 0x00b2)
+#define NT_STATUS_PIPE_LISTENING NT_STATUS(0xC0000000 | 0x00b3)
+#define NT_STATUS_INVALID_READ_MODE NT_STATUS(0xC0000000 | 0x00b4)
+#define NT_STATUS_IO_TIMEOUT NT_STATUS(0xC0000000 | 0x00b5)
+#define NT_STATUS_FILE_FORCED_CLOSED NT_STATUS(0xC0000000 | 0x00b6)
+#define NT_STATUS_PROFILING_NOT_STARTED NT_STATUS(0xC0000000 | 0x00b7)
+#define NT_STATUS_PROFILING_NOT_STOPPED NT_STATUS(0xC0000000 | 0x00b8)
+#define NT_STATUS_COULD_NOT_INTERPRET NT_STATUS(0xC0000000 | 0x00b9)
+#define NT_STATUS_FILE_IS_A_DIRECTORY NT_STATUS(0xC0000000 | 0x00ba)
+#define NT_STATUS_NOT_SUPPORTED NT_STATUS(0xC0000000 | 0x00bb)
+#define NT_STATUS_REMOTE_NOT_LISTENING NT_STATUS(0xC0000000 | 0x00bc)
+#define NT_STATUS_DUPLICATE_NAME NT_STATUS(0xC0000000 | 0x00bd)
+#define NT_STATUS_BAD_NETWORK_PATH NT_STATUS(0xC0000000 | 0x00be)
+#define NT_STATUS_NETWORK_BUSY NT_STATUS(0xC0000000 | 0x00bf)
+#define NT_STATUS_DEVICE_DOES_NOT_EXIST NT_STATUS(0xC0000000 | 0x00c0)
+#define NT_STATUS_TOO_MANY_COMMANDS NT_STATUS(0xC0000000 | 0x00c1)
+#define NT_STATUS_ADAPTER_HARDWARE_ERROR NT_STATUS(0xC0000000 | 0x00c2)
+#define NT_STATUS_INVALID_NETWORK_RESPONSE NT_STATUS(0xC0000000 | 0x00c3)
+#define NT_STATUS_UNEXPECTED_NETWORK_ERROR NT_STATUS(0xC0000000 | 0x00c4)
+#define NT_STATUS_BAD_REMOTE_ADAPTER NT_STATUS(0xC0000000 | 0x00c5)
+#define NT_STATUS_PRINT_QUEUE_FULL NT_STATUS(0xC0000000 | 0x00c6)
+#define NT_STATUS_NO_SPOOL_SPACE NT_STATUS(0xC0000000 | 0x00c7)
+#define NT_STATUS_PRINT_CANCELLED NT_STATUS(0xC0000000 | 0x00c8)
+#define NT_STATUS_NETWORK_NAME_DELETED NT_STATUS(0xC0000000 | 0x00c9)
+#define NT_STATUS_NETWORK_ACCESS_DENIED NT_STATUS(0xC0000000 | 0x00ca)
+#define NT_STATUS_BAD_DEVICE_TYPE NT_STATUS(0xC0000000 | 0x00cb)
+#define NT_STATUS_BAD_NETWORK_NAME NT_STATUS(0xC0000000 | 0x00cc)
+#define NT_STATUS_TOO_MANY_NAMES NT_STATUS(0xC0000000 | 0x00cd)
+#define NT_STATUS_TOO_MANY_SESSIONS NT_STATUS(0xC0000000 | 0x00ce)
+#define NT_STATUS_SHARING_PAUSED NT_STATUS(0xC0000000 | 0x00cf)
+#define NT_STATUS_REQUEST_NOT_ACCEPTED NT_STATUS(0xC0000000 | 0x00d0)
+#define NT_STATUS_REDIRECTOR_PAUSED NT_STATUS(0xC0000000 | 0x00d1)
+#define NT_STATUS_NET_WRITE_FAULT NT_STATUS(0xC0000000 | 0x00d2)
+#define NT_STATUS_PROFILING_AT_LIMIT NT_STATUS(0xC0000000 | 0x00d3)
+#define NT_STATUS_NOT_SAME_DEVICE NT_STATUS(0xC0000000 | 0x00d4)
+#define NT_STATUS_FILE_RENAMED NT_STATUS(0xC0000000 | 0x00d5)
+#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED NT_STATUS(0xC0000000 | 0x00d6)
+#define NT_STATUS_NO_SECURITY_ON_OBJECT NT_STATUS(0xC0000000 | 0x00d7)
+#define NT_STATUS_CANT_WAIT NT_STATUS(0xC0000000 | 0x00d8)
+#define NT_STATUS_PIPE_EMPTY NT_STATUS(0xC0000000 | 0x00d9)
+#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO NT_STATUS(0xC0000000 | 0x00da)
+#define NT_STATUS_CANT_TERMINATE_SELF NT_STATUS(0xC0000000 | 0x00db)
+#define NT_STATUS_INVALID_SERVER_STATE NT_STATUS(0xC0000000 | 0x00dc)
+#define NT_STATUS_INVALID_DOMAIN_STATE NT_STATUS(0xC0000000 | 0x00dd)
+#define NT_STATUS_INVALID_DOMAIN_ROLE NT_STATUS(0xC0000000 | 0x00de)
+#define NT_STATUS_NO_SUCH_DOMAIN NT_STATUS(0xC0000000 | 0x00df)
+#define NT_STATUS_DOMAIN_EXISTS NT_STATUS(0xC0000000 | 0x00e0)
+#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED NT_STATUS(0xC0000000 | 0x00e1)
+#define NT_STATUS_OPLOCK_NOT_GRANTED NT_STATUS(0xC0000000 | 0x00e2)
+#define NT_STATUS_INVALID_OPLOCK_PROTOCOL NT_STATUS(0xC0000000 | 0x00e3)
+#define NT_STATUS_INTERNAL_DB_CORRUPTION NT_STATUS(0xC0000000 | 0x00e4)
+#define NT_STATUS_INTERNAL_ERROR NT_STATUS(0xC0000000 | 0x00e5)
+#define NT_STATUS_GENERIC_NOT_MAPPED NT_STATUS(0xC0000000 | 0x00e6)
+#define NT_STATUS_BAD_DESCRIPTOR_FORMAT NT_STATUS(0xC0000000 | 0x00e7)
+#define NT_STATUS_INVALID_USER_BUFFER NT_STATUS(0xC0000000 | 0x00e8)
+#define NT_STATUS_UNEXPECTED_IO_ERROR NT_STATUS(0xC0000000 | 0x00e9)
+#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR NT_STATUS(0xC0000000 | 0x00ea)
+#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR NT_STATUS(0xC0000000 | 0x00eb)
+#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR NT_STATUS(0xC0000000 | 0x00ec)
+#define NT_STATUS_NOT_LOGON_PROCESS NT_STATUS(0xC0000000 | 0x00ed)
+#define NT_STATUS_LOGON_SESSION_EXISTS NT_STATUS(0xC0000000 | 0x00ee)
+#define NT_STATUS_INVALID_PARAMETER_1 NT_STATUS(0xC0000000 | 0x00ef)
+#define NT_STATUS_INVALID_PARAMETER_2 NT_STATUS(0xC0000000 | 0x00f0)
+#define NT_STATUS_INVALID_PARAMETER_3 NT_STATUS(0xC0000000 | 0x00f1)
+#define NT_STATUS_INVALID_PARAMETER_4 NT_STATUS(0xC0000000 | 0x00f2)
+#define NT_STATUS_INVALID_PARAMETER_5 NT_STATUS(0xC0000000 | 0x00f3)
+#define NT_STATUS_INVALID_PARAMETER_6 NT_STATUS(0xC0000000 | 0x00f4)
+#define NT_STATUS_INVALID_PARAMETER_7 NT_STATUS(0xC0000000 | 0x00f5)
+#define NT_STATUS_INVALID_PARAMETER_8 NT_STATUS(0xC0000000 | 0x00f6)
+#define NT_STATUS_INVALID_PARAMETER_9 NT_STATUS(0xC0000000 | 0x00f7)
+#define NT_STATUS_INVALID_PARAMETER_10 NT_STATUS(0xC0000000 | 0x00f8)
+#define NT_STATUS_INVALID_PARAMETER_11 NT_STATUS(0xC0000000 | 0x00f9)
+#define NT_STATUS_INVALID_PARAMETER_12 NT_STATUS(0xC0000000 | 0x00fa)
+#define NT_STATUS_REDIRECTOR_NOT_STARTED NT_STATUS(0xC0000000 | 0x00fb)
+#define NT_STATUS_REDIRECTOR_STARTED NT_STATUS(0xC0000000 | 0x00fc)
+#define NT_STATUS_STACK_OVERFLOW NT_STATUS(0xC0000000 | 0x00fd)
+#define NT_STATUS_NO_SUCH_PACKAGE NT_STATUS(0xC0000000 | 0x00fe)
+#define NT_STATUS_BAD_FUNCTION_TABLE NT_STATUS(0xC0000000 | 0x00ff)
+#define NT_STATUS_DIRECTORY_NOT_EMPTY NT_STATUS(0xC0000000 | 0x0101)
+#define NT_STATUS_FILE_CORRUPT_ERROR NT_STATUS(0xC0000000 | 0x0102)
+#define NT_STATUS_NOT_A_DIRECTORY NT_STATUS(0xC0000000 | 0x0103)
+#define NT_STATUS_BAD_LOGON_SESSION_STATE NT_STATUS(0xC0000000 | 0x0104)
+#define NT_STATUS_LOGON_SESSION_COLLISION NT_STATUS(0xC0000000 | 0x0105)
+#define NT_STATUS_NAME_TOO_LONG NT_STATUS(0xC0000000 | 0x0106)
+#define NT_STATUS_FILES_OPEN NT_STATUS(0xC0000000 | 0x0107)
+#define NT_STATUS_CONNECTION_IN_USE NT_STATUS(0xC0000000 | 0x0108)
+#define NT_STATUS_MESSAGE_NOT_FOUND NT_STATUS(0xC0000000 | 0x0109)
+#define NT_STATUS_PROCESS_IS_TERMINATING NT_STATUS(0xC0000000 | 0x010a)
+#define NT_STATUS_INVALID_LOGON_TYPE NT_STATUS(0xC0000000 | 0x010b)
+#define NT_STATUS_NO_GUID_TRANSLATION NT_STATUS(0xC0000000 | 0x010c)
+#define NT_STATUS_CANNOT_IMPERSONATE NT_STATUS(0xC0000000 | 0x010d)
+#define NT_STATUS_IMAGE_ALREADY_LOADED NT_STATUS(0xC0000000 | 0x010e)
+#define NT_STATUS_ABIOS_NOT_PRESENT NT_STATUS(0xC0000000 | 0x010f)
+#define NT_STATUS_ABIOS_LID_NOT_EXIST NT_STATUS(0xC0000000 | 0x0110)
+#define NT_STATUS_ABIOS_LID_ALREADY_OWNED NT_STATUS(0xC0000000 | 0x0111)
+#define NT_STATUS_ABIOS_NOT_LID_OWNER NT_STATUS(0xC0000000 | 0x0112)
+#define NT_STATUS_ABIOS_INVALID_COMMAND NT_STATUS(0xC0000000 | 0x0113)
+#define NT_STATUS_ABIOS_INVALID_LID NT_STATUS(0xC0000000 | 0x0114)
+#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE NT_STATUS(0xC0000000 | 0x0115)
+#define NT_STATUS_ABIOS_INVALID_SELECTOR NT_STATUS(0xC0000000 | 0x0116)
+#define NT_STATUS_NO_LDT NT_STATUS(0xC0000000 | 0x0117)
+#define NT_STATUS_INVALID_LDT_SIZE NT_STATUS(0xC0000000 | 0x0118)
+#define NT_STATUS_INVALID_LDT_OFFSET NT_STATUS(0xC0000000 | 0x0119)
+#define NT_STATUS_INVALID_LDT_DESCRIPTOR NT_STATUS(0xC0000000 | 0x011a)
+#define NT_STATUS_INVALID_IMAGE_NE_FORMAT NT_STATUS(0xC0000000 | 0x011b)
+#define NT_STATUS_RXACT_INVALID_STATE NT_STATUS(0xC0000000 | 0x011c)
+#define NT_STATUS_RXACT_COMMIT_FAILURE NT_STATUS(0xC0000000 | 0x011d)
+#define NT_STATUS_MAPPED_FILE_SIZE_ZERO NT_STATUS(0xC0000000 | 0x011e)
+#define NT_STATUS_TOO_MANY_OPENED_FILES NT_STATUS(0xC0000000 | 0x011f)
+#define NT_STATUS_CANCELLED NT_STATUS(0xC0000000 | 0x0120)
+#define NT_STATUS_CANNOT_DELETE NT_STATUS(0xC0000000 | 0x0121)
+#define NT_STATUS_INVALID_COMPUTER_NAME NT_STATUS(0xC0000000 | 0x0122)
+#define NT_STATUS_FILE_DELETED NT_STATUS(0xC0000000 | 0x0123)
+#define NT_STATUS_SPECIAL_ACCOUNT NT_STATUS(0xC0000000 | 0x0124)
+#define NT_STATUS_SPECIAL_GROUP NT_STATUS(0xC0000000 | 0x0125)
+#define NT_STATUS_SPECIAL_USER NT_STATUS(0xC0000000 | 0x0126)
+#define NT_STATUS_MEMBERS_PRIMARY_GROUP NT_STATUS(0xC0000000 | 0x0127)
+#define NT_STATUS_FILE_CLOSED NT_STATUS(0xC0000000 | 0x0128)
+#define NT_STATUS_TOO_MANY_THREADS NT_STATUS(0xC0000000 | 0x0129)
+#define NT_STATUS_THREAD_NOT_IN_PROCESS NT_STATUS(0xC0000000 | 0x012a)
+#define NT_STATUS_TOKEN_ALREADY_IN_USE NT_STATUS(0xC0000000 | 0x012b)
+#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED NT_STATUS(0xC0000000 | 0x012c)
+#define NT_STATUS_COMMITMENT_LIMIT NT_STATUS(0xC0000000 | 0x012d)
+#define NT_STATUS_INVALID_IMAGE_LE_FORMAT NT_STATUS(0xC0000000 | 0x012e)
+#define NT_STATUS_INVALID_IMAGE_NOT_MZ NT_STATUS(0xC0000000 | 0x012f)
+#define NT_STATUS_INVALID_IMAGE_PROTECT NT_STATUS(0xC0000000 | 0x0130)
+#define NT_STATUS_INVALID_IMAGE_WIN_16 NT_STATUS(0xC0000000 | 0x0131)
+#define NT_STATUS_LOGON_SERVER_CONFLICT NT_STATUS(0xC0000000 | 0x0132)
+#define NT_STATUS_TIME_DIFFERENCE_AT_DC NT_STATUS(0xC0000000 | 0x0133)
+#define NT_STATUS_SYNCHRONIZATION_REQUIRED NT_STATUS(0xC0000000 | 0x0134)
+#define NT_STATUS_DLL_NOT_FOUND NT_STATUS(0xC0000000 | 0x0135)
+#define NT_STATUS_OPEN_FAILED NT_STATUS(0xC0000000 | 0x0136)
+#define NT_STATUS_IO_PRIVILEGE_FAILED NT_STATUS(0xC0000000 | 0x0137)
+#define NT_STATUS_ORDINAL_NOT_FOUND NT_STATUS(0xC0000000 | 0x0138)
+#define NT_STATUS_ENTRYPOINT_NOT_FOUND NT_STATUS(0xC0000000 | 0x0139)
+#define NT_STATUS_CONTROL_C_EXIT NT_STATUS(0xC0000000 | 0x013a)
+#define NT_STATUS_LOCAL_DISCONNECT NT_STATUS(0xC0000000 | 0x013b)
+#define NT_STATUS_REMOTE_DISCONNECT NT_STATUS(0xC0000000 | 0x013c)
+#define NT_STATUS_REMOTE_RESOURCES NT_STATUS(0xC0000000 | 0x013d)
+#define NT_STATUS_LINK_FAILED NT_STATUS(0xC0000000 | 0x013e)
+#define NT_STATUS_LINK_TIMEOUT NT_STATUS(0xC0000000 | 0x013f)
+#define NT_STATUS_INVALID_CONNECTION NT_STATUS(0xC0000000 | 0x0140)
+#define NT_STATUS_INVALID_ADDRESS NT_STATUS(0xC0000000 | 0x0141)
+#define NT_STATUS_DLL_INIT_FAILED NT_STATUS(0xC0000000 | 0x0142)
+#define NT_STATUS_MISSING_SYSTEMFILE NT_STATUS(0xC0000000 | 0x0143)
+#define NT_STATUS_UNHANDLED_EXCEPTION NT_STATUS(0xC0000000 | 0x0144)
+#define NT_STATUS_APP_INIT_FAILURE NT_STATUS(0xC0000000 | 0x0145)
+#define NT_STATUS_PAGEFILE_CREATE_FAILED NT_STATUS(0xC0000000 | 0x0146)
+#define NT_STATUS_NO_PAGEFILE NT_STATUS(0xC0000000 | 0x0147)
+#define NT_STATUS_INVALID_LEVEL NT_STATUS(0xC0000000 | 0x0148)
+#define NT_STATUS_WRONG_PASSWORD_CORE NT_STATUS(0xC0000000 | 0x0149)
+#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT NT_STATUS(0xC0000000 | 0x014a)
+#define NT_STATUS_PIPE_BROKEN NT_STATUS(0xC0000000 | 0x014b)
+#define NT_STATUS_REGISTRY_CORRUPT NT_STATUS(0xC0000000 | 0x014c)
+#define NT_STATUS_REGISTRY_IO_FAILED NT_STATUS(0xC0000000 | 0x014d)
+#define NT_STATUS_NO_EVENT_PAIR NT_STATUS(0xC0000000 | 0x014e)
+#define NT_STATUS_UNRECOGNIZED_VOLUME NT_STATUS(0xC0000000 | 0x014f)
+#define NT_STATUS_SERIAL_NO_DEVICE_INITED NT_STATUS(0xC0000000 | 0x0150)
+#define NT_STATUS_NO_SUCH_ALIAS NT_STATUS(0xC0000000 | 0x0151)
+#define NT_STATUS_MEMBER_NOT_IN_ALIAS NT_STATUS(0xC0000000 | 0x0152)
+#define NT_STATUS_MEMBER_IN_ALIAS NT_STATUS(0xC0000000 | 0x0153)
+#define NT_STATUS_ALIAS_EXISTS NT_STATUS(0xC0000000 | 0x0154)
+#define NT_STATUS_LOGON_NOT_GRANTED NT_STATUS(0xC0000000 | 0x0155)
+#define NT_STATUS_TOO_MANY_SECRETS NT_STATUS(0xC0000000 | 0x0156)
+#define NT_STATUS_SECRET_TOO_LONG NT_STATUS(0xC0000000 | 0x0157)
+#define NT_STATUS_INTERNAL_DB_ERROR NT_STATUS(0xC0000000 | 0x0158)
+#define NT_STATUS_FULLSCREEN_MODE NT_STATUS(0xC0000000 | 0x0159)
+#define NT_STATUS_TOO_MANY_CONTEXT_IDS NT_STATUS(0xC0000000 | 0x015a)
+#define NT_STATUS_LOGON_TYPE_NOT_GRANTED NT_STATUS(0xC0000000 | 0x015b)
+#define NT_STATUS_NOT_REGISTRY_FILE NT_STATUS(0xC0000000 | 0x015c)
+#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED NT_STATUS(0xC0000000 | 0x015d)
+#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR NT_STATUS(0xC0000000 | 0x015e)
+#define NT_STATUS_FT_MISSING_MEMBER NT_STATUS(0xC0000000 | 0x015f)
+#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY NT_STATUS(0xC0000000 | 0x0160)
+#define NT_STATUS_ILLEGAL_CHARACTER NT_STATUS(0xC0000000 | 0x0161)
+#define NT_STATUS_UNMAPPABLE_CHARACTER NT_STATUS(0xC0000000 | 0x0162)
+#define NT_STATUS_UNDEFINED_CHARACTER NT_STATUS(0xC0000000 | 0x0163)
+#define NT_STATUS_FLOPPY_VOLUME NT_STATUS(0xC0000000 | 0x0164)
+#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND NT_STATUS(0xC0000000 | 0x0165)
+#define NT_STATUS_FLOPPY_WRONG_CYLINDER NT_STATUS(0xC0000000 | 0x0166)
+#define NT_STATUS_FLOPPY_UNKNOWN_ERROR NT_STATUS(0xC0000000 | 0x0167)
+#define NT_STATUS_FLOPPY_BAD_REGISTERS NT_STATUS(0xC0000000 | 0x0168)
+#define NT_STATUS_DISK_RECALIBRATE_FAILED NT_STATUS(0xC0000000 | 0x0169)
+#define NT_STATUS_DISK_OPERATION_FAILED NT_STATUS(0xC0000000 | 0x016a)
+#define NT_STATUS_DISK_RESET_FAILED NT_STATUS(0xC0000000 | 0x016b)
+#define NT_STATUS_SHARED_IRQ_BUSY NT_STATUS(0xC0000000 | 0x016c)
+#define NT_STATUS_FT_ORPHANING NT_STATUS(0xC0000000 | 0x016d)
+#define NT_STATUS_PARTITION_FAILURE NT_STATUS(0xC0000000 | 0x0172)
+#define NT_STATUS_INVALID_BLOCK_LENGTH NT_STATUS(0xC0000000 | 0x0173)
+#define NT_STATUS_DEVICE_NOT_PARTITIONED NT_STATUS(0xC0000000 | 0x0174)
+#define NT_STATUS_UNABLE_TO_LOCK_MEDIA NT_STATUS(0xC0000000 | 0x0175)
+#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA NT_STATUS(0xC0000000 | 0x0176)
+#define NT_STATUS_EOM_OVERFLOW NT_STATUS(0xC0000000 | 0x0177)
+#define NT_STATUS_NO_MEDIA NT_STATUS(0xC0000000 | 0x0178)
+#define NT_STATUS_NO_SUCH_MEMBER NT_STATUS(0xC0000000 | 0x017a)
+#define NT_STATUS_INVALID_MEMBER NT_STATUS(0xC0000000 | 0x017b)
+#define NT_STATUS_KEY_DELETED NT_STATUS(0xC0000000 | 0x017c)
+#define NT_STATUS_NO_LOG_SPACE NT_STATUS(0xC0000000 | 0x017d)
+#define NT_STATUS_TOO_MANY_SIDS NT_STATUS(0xC0000000 | 0x017e)
+#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED NT_STATUS(0xC0000000 | 0x017f)
+#define NT_STATUS_KEY_HAS_CHILDREN NT_STATUS(0xC0000000 | 0x0180)
+#define NT_STATUS_CHILD_MUST_BE_VOLATILE NT_STATUS(0xC0000000 | 0x0181)
+#define NT_STATUS_DEVICE_CONFIGURATION_ERROR NT_STATUS(0xC0000000 | 0x0182)
+#define NT_STATUS_DRIVER_INTERNAL_ERROR NT_STATUS(0xC0000000 | 0x0183)
+#define NT_STATUS_INVALID_DEVICE_STATE NT_STATUS(0xC0000000 | 0x0184)
+#define NT_STATUS_IO_DEVICE_ERROR NT_STATUS(0xC0000000 | 0x0185)
+#define NT_STATUS_DEVICE_PROTOCOL_ERROR NT_STATUS(0xC0000000 | 0x0186)
+#define NT_STATUS_BACKUP_CONTROLLER NT_STATUS(0xC0000000 | 0x0187)
+#define NT_STATUS_LOG_FILE_FULL NT_STATUS(0xC0000000 | 0x0188)
+#define NT_STATUS_TOO_LATE NT_STATUS(0xC0000000 | 0x0189)
+#define NT_STATUS_NO_TRUST_LSA_SECRET NT_STATUS(0xC0000000 | 0x018a)
+#define NT_STATUS_NO_TRUST_SAM_ACCOUNT NT_STATUS(0xC0000000 | 0x018b)
+#define NT_STATUS_TRUSTED_DOMAIN_FAILURE NT_STATUS(0xC0000000 | 0x018c)
+#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE NT_STATUS(0xC0000000 | 0x018d)
+#define NT_STATUS_EVENTLOG_FILE_CORRUPT NT_STATUS(0xC0000000 | 0x018e)
+#define NT_STATUS_EVENTLOG_CANT_START NT_STATUS(0xC0000000 | 0x018f)
+#define NT_STATUS_TRUST_FAILURE NT_STATUS(0xC0000000 | 0x0190)
+#define NT_STATUS_MUTANT_LIMIT_EXCEEDED NT_STATUS(0xC0000000 | 0x0191)
+#define NT_STATUS_NETLOGON_NOT_STARTED NT_STATUS(0xC0000000 | 0x0192)
+#define NT_STATUS_ACCOUNT_EXPIRED NT_STATUS(0xC0000000 | 0x0193)
+#define NT_STATUS_POSSIBLE_DEADLOCK NT_STATUS(0xC0000000 | 0x0194)
+#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT NT_STATUS(0xC0000000 | 0x0195)
+#define NT_STATUS_REMOTE_SESSION_LIMIT NT_STATUS(0xC0000000 | 0x0196)
+#define NT_STATUS_EVENTLOG_FILE_CHANGED NT_STATUS(0xC0000000 | 0x0197)
+#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT NT_STATUS(0xC0000000 | 0x0198)
+#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT NT_STATUS(0xC0000000 | 0x0199)
+#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT NT_STATUS(0xC0000000 | 0x019a)
+#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT NT_STATUS(0xC0000000 | 0x019b)
+#define NT_STATUS_FS_DRIVER_REQUIRED NT_STATUS(0xC0000000 | 0x019c)
+#define NT_STATUS_NO_USER_SESSION_KEY NT_STATUS(0xC0000000 | 0x0202)
+#define NT_STATUS_USER_SESSION_DELETED NT_STATUS(0xC0000000 | 0x0203)
+#define NT_STATUS_RESOURCE_LANG_NOT_FOUND NT_STATUS(0xC0000000 | 0x0204)
+#define NT_STATUS_INSUFF_SERVER_RESOURCES NT_STATUS(0xC0000000 | 0x0205)
+#define NT_STATUS_INVALID_BUFFER_SIZE NT_STATUS(0xC0000000 | 0x0206)
+#define NT_STATUS_INVALID_ADDRESS_COMPONENT NT_STATUS(0xC0000000 | 0x0207)
+#define NT_STATUS_INVALID_ADDRESS_WILDCARD NT_STATUS(0xC0000000 | 0x0208)
+#define NT_STATUS_TOO_MANY_ADDRESSES NT_STATUS(0xC0000000 | 0x0209)
+#define NT_STATUS_ADDRESS_ALREADY_EXISTS NT_STATUS(0xC0000000 | 0x020a)
+#define NT_STATUS_ADDRESS_CLOSED NT_STATUS(0xC0000000 | 0x020b)
+#define NT_STATUS_CONNECTION_DISCONNECTED NT_STATUS(0xC0000000 | 0x020c)
+#define NT_STATUS_CONNECTION_RESET NT_STATUS(0xC0000000 | 0x020d)
+#define NT_STATUS_TOO_MANY_NODES NT_STATUS(0xC0000000 | 0x020e)
+#define NT_STATUS_TRANSACTION_ABORTED NT_STATUS(0xC0000000 | 0x020f)
+#define NT_STATUS_TRANSACTION_TIMED_OUT NT_STATUS(0xC0000000 | 0x0210)
+#define NT_STATUS_TRANSACTION_NO_RELEASE NT_STATUS(0xC0000000 | 0x0211)
+#define NT_STATUS_TRANSACTION_NO_MATCH NT_STATUS(0xC0000000 | 0x0212)
+#define NT_STATUS_TRANSACTION_RESPONDED NT_STATUS(0xC0000000 | 0x0213)
+#define NT_STATUS_TRANSACTION_INVALID_ID NT_STATUS(0xC0000000 | 0x0214)
+#define NT_STATUS_TRANSACTION_INVALID_TYPE NT_STATUS(0xC0000000 | 0x0215)
+#define NT_STATUS_NOT_SERVER_SESSION NT_STATUS(0xC0000000 | 0x0216)
+#define NT_STATUS_NOT_CLIENT_SESSION NT_STATUS(0xC0000000 | 0x0217)
+#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE NT_STATUS(0xC0000000 | 0x0218)
+#define NT_STATUS_DEBUG_ATTACH_FAILED NT_STATUS(0xC0000000 | 0x0219)
+#define NT_STATUS_SYSTEM_PROCESS_TERMINATED NT_STATUS(0xC0000000 | 0x021a)
+#define NT_STATUS_DATA_NOT_ACCEPTED NT_STATUS(0xC0000000 | 0x021b)
+#define NT_STATUS_NO_BROWSER_SERVERS_FOUND NT_STATUS(0xC0000000 | 0x021c)
+#define NT_STATUS_VDM_HARD_ERROR NT_STATUS(0xC0000000 | 0x021d)
+#define NT_STATUS_DRIVER_CANCEL_TIMEOUT NT_STATUS(0xC0000000 | 0x021e)
+#define NT_STATUS_REPLY_MESSAGE_MISMATCH NT_STATUS(0xC0000000 | 0x021f)
+#define NT_STATUS_MAPPED_ALIGNMENT NT_STATUS(0xC0000000 | 0x0220)
+#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH NT_STATUS(0xC0000000 | 0x0221)
+#define NT_STATUS_LOST_WRITEBEHIND_DATA NT_STATUS(0xC0000000 | 0x0222)
+#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID NT_STATUS(0xC0000000 | 0x0223)
+#define NT_STATUS_PASSWORD_MUST_CHANGE NT_STATUS(0xC0000000 | 0x0224)
+#define NT_STATUS_NOT_FOUND NT_STATUS(0xC0000000 | 0x0225)
+#define NT_STATUS_NOT_TINY_STREAM NT_STATUS(0xC0000000 | 0x0226)
+#define NT_STATUS_RECOVERY_FAILURE NT_STATUS(0xC0000000 | 0x0227)
+#define NT_STATUS_STACK_OVERFLOW_READ NT_STATUS(0xC0000000 | 0x0228)
+#define NT_STATUS_FAIL_CHECK NT_STATUS(0xC0000000 | 0x0229)
+#define NT_STATUS_DUPLICATE_OBJECTID NT_STATUS(0xC0000000 | 0x022a)
+#define NT_STATUS_OBJECTID_EXISTS NT_STATUS(0xC0000000 | 0x022b)
+#define NT_STATUS_CONVERT_TO_LARGE NT_STATUS(0xC0000000 | 0x022c)
+#define NT_STATUS_RETRY NT_STATUS(0xC0000000 | 0x022d)
+#define NT_STATUS_FOUND_OUT_OF_SCOPE NT_STATUS(0xC0000000 | 0x022e)
+#define NT_STATUS_ALLOCATE_BUCKET NT_STATUS(0xC0000000 | 0x022f)
+#define NT_STATUS_PROPSET_NOT_FOUND NT_STATUS(0xC0000000 | 0x0230)
+#define NT_STATUS_MARSHALL_OVERFLOW NT_STATUS(0xC0000000 | 0x0231)
+#define NT_STATUS_INVALID_VARIANT NT_STATUS(0xC0000000 | 0x0232)
+#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND NT_STATUS(0xC0000000 | 0x0233)
+#define NT_STATUS_ACCOUNT_LOCKED_OUT NT_STATUS(0xC0000000 | 0x0234)
+#define NT_STATUS_HANDLE_NOT_CLOSABLE NT_STATUS(0xC0000000 | 0x0235)
+#define NT_STATUS_CONNECTION_REFUSED NT_STATUS(0xC0000000 | 0x0236)
+#define NT_STATUS_GRACEFUL_DISCONNECT NT_STATUS(0xC0000000 | 0x0237)
+#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED NT_STATUS(0xC0000000 | 0x0238)
+#define NT_STATUS_ADDRESS_NOT_ASSOCIATED NT_STATUS(0xC0000000 | 0x0239)
+#define NT_STATUS_CONNECTION_INVALID NT_STATUS(0xC0000000 | 0x023a)
+#define NT_STATUS_CONNECTION_ACTIVE NT_STATUS(0xC0000000 | 0x023b)
+#define NT_STATUS_NETWORK_UNREACHABLE NT_STATUS(0xC0000000 | 0x023c)
+#define NT_STATUS_HOST_UNREACHABLE NT_STATUS(0xC0000000 | 0x023d)
+#define NT_STATUS_PROTOCOL_UNREACHABLE NT_STATUS(0xC0000000 | 0x023e)
+#define NT_STATUS_PORT_UNREACHABLE NT_STATUS(0xC0000000 | 0x023f)
+#define NT_STATUS_REQUEST_ABORTED NT_STATUS(0xC0000000 | 0x0240)
+#define NT_STATUS_CONNECTION_ABORTED NT_STATUS(0xC0000000 | 0x0241)
+#define NT_STATUS_BAD_COMPRESSION_BUFFER NT_STATUS(0xC0000000 | 0x0242)
+#define NT_STATUS_USER_MAPPED_FILE NT_STATUS(0xC0000000 | 0x0243)
+#define NT_STATUS_AUDIT_FAILED NT_STATUS(0xC0000000 | 0x0244)
+#define NT_STATUS_TIMER_RESOLUTION_NOT_SET NT_STATUS(0xC0000000 | 0x0245)
+#define NT_STATUS_CONNECTION_COUNT_LIMIT NT_STATUS(0xC0000000 | 0x0246)
+#define NT_STATUS_LOGIN_TIME_RESTRICTION NT_STATUS(0xC0000000 | 0x0247)
+#define NT_STATUS_LOGIN_WKSTA_RESTRICTION NT_STATUS(0xC0000000 | 0x0248)
+#define NT_STATUS_IMAGE_MP_UP_MISMATCH NT_STATUS(0xC0000000 | 0x0249)
+#define NT_STATUS_INSUFFICIENT_LOGON_INFO NT_STATUS(0xC0000000 | 0x0250)
+#define NT_STATUS_BAD_DLL_ENTRYPOINT NT_STATUS(0xC0000000 | 0x0251)
+#define NT_STATUS_BAD_SERVICE_ENTRYPOINT NT_STATUS(0xC0000000 | 0x0252)
+#define NT_STATUS_LPC_REPLY_LOST NT_STATUS(0xC0000000 | 0x0253)
+#define NT_STATUS_IP_ADDRESS_CONFLICT1 NT_STATUS(0xC0000000 | 0x0254)
+#define NT_STATUS_IP_ADDRESS_CONFLICT2 NT_STATUS(0xC0000000 | 0x0255)
+#define NT_STATUS_REGISTRY_QUOTA_LIMIT NT_STATUS(0xC0000000 | 0x0256)
+#define NT_STATUS_PATH_NOT_COVERED NT_STATUS(0xC0000000 | 0x0257)
+#define NT_STATUS_NO_CALLBACK_ACTIVE NT_STATUS(0xC0000000 | 0x0258)
+#define NT_STATUS_LICENSE_QUOTA_EXCEEDED NT_STATUS(0xC0000000 | 0x0259)
+#define NT_STATUS_PWD_TOO_SHORT NT_STATUS(0xC0000000 | 0x025a)
+#define NT_STATUS_PWD_TOO_RECENT NT_STATUS(0xC0000000 | 0x025b)
+#define NT_STATUS_PWD_HISTORY_CONFLICT NT_STATUS(0xC0000000 | 0x025c)
+#define NT_STATUS_PLUGPLAY_NO_DEVICE NT_STATUS(0xC0000000 | 0x025e)
+#define NT_STATUS_UNSUPPORTED_COMPRESSION NT_STATUS(0xC0000000 | 0x025f)
+#define NT_STATUS_INVALID_HW_PROFILE NT_STATUS(0xC0000000 | 0x0260)
+#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH NT_STATUS(0xC0000000 | 0x0261)
+#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND NT_STATUS(0xC0000000 | 0x0262)
+#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND NT_STATUS(0xC0000000 | 0x0263)
+#define NT_STATUS_RESOURCE_NOT_OWNED NT_STATUS(0xC0000000 | 0x0264)
+#define NT_STATUS_TOO_MANY_LINKS NT_STATUS(0xC0000000 | 0x0265)
+#define NT_STATUS_QUOTA_LIST_INCONSISTENT NT_STATUS(0xC0000000 | 0x0266)
+#define NT_STATUS_FILE_IS_OFFLINE NT_STATUS(0xC0000000 | 0x0267)
+#define NT_STATUS_DS_NO_MORE_RIDS NT_STATUS(0xC0000000 | 0x02a8)
+#define NT_STATUS_NOT_A_REPARSE_POINT NT_STATUS(0xC0000000 | 0x0275)
+#define NT_STATUS_DOWNGRADE_DETECTED NT_STATUS(0xC0000000 | 0x0388)
+#define NT_STATUS_NO_SUCH_JOB NT_STATUS(0xC0000000 | 0xEDE) /* scheduler */
+#define NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED NT_STATUS(0xC0000000 | 0x20004)
+#define NT_STATUS_RPC_CANNOT_SUPPORT NT_STATUS(0xC0000000 | 0x20041)
+
+#endif /* _NTERR_H */
diff --git a/source3/include/ntioctl.h b/source3/include/ntioctl.h
new file mode 100644
index 0000000000..c565b8f9a4
--- /dev/null
+++ b/source3/include/ntioctl.h
@@ -0,0 +1,88 @@
+/*
+ Unix SMB/CIFS implementation.
+ NT ioctl code constants
+ Copyright (C) Andrew Tridgell 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ I'm guessing we will need to support a bunch of these eventually. For now
+ we only need the sparse flag
+*/
+
+#ifndef _NTIOCTL_H
+#define _NTIOCTL_H
+
+/* IOCTL information */
+/* List of ioctl function codes that look to be of interest to remote clients like this. */
+/* Need to do some experimentation to make sure they all work remotely. */
+/* Some of the following such as the encryption/compression ones would be */
+/* invoked from tools via a specialized hook into the VFS rather than via the */
+/* standard vfs entry points */
+#define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000
+#define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004
+#define FSCTL_REQUEST_BATCH_OPLOCK 0x00090008
+#define FSCTL_LOCK_VOLUME 0x00090018
+#define FSCTL_UNLOCK_VOLUME 0x0009001C
+#define FSCTL_GET_COMPRESSION 0x0009003C
+#define FSCTL_SET_COMPRESSION 0x0009C040
+#define FSCTL_REQUEST_FILTER_OPLOCK 0x0009008C
+#define FSCTL_FIND_FILES_BY_SID 0x0009008F
+#define FSCTL_FILESYS_GET_STATISTICS 0x00090090
+#define FSCTL_SET_OBJECT_ID 0x00090098
+#define FSCTL_GET_OBJECT_ID 0x0009009C
+#define FSCTL_SET_REPARSE_POINT 0x000900A4
+#define FSCTL_GET_REPARSE_POINT 0x000900A8
+#define FSCTL_DELETE_REPARSE_POINT 0x000900AC
+#define FSCTL_CREATE_OR_GET_OBJECT_ID 0x000900C0
+#define FSCTL_SET_SPARSE 0x000900C4
+#define FSCTL_SET_ZERO_DATA 0x000900C8
+#define FSCTL_SET_ENCRYPTION 0x000900D7
+#define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB
+#define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF
+#define FSCTL_READ_RAW_ENCRYPTED 0x000900E3
+#define FSCTL_SIS_COPYFILE 0x00090100
+#define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF
+#define FSCTL_SIS_LINK_FILES 0x0009C104
+
+#define FSCTL_GET_SHADOW_COPY_DATA 0x00144064 /* KJC -- Shadow Copy information */
+
+#if 0
+#define FSCTL_SECURITY_ID_CHECK
+#define FSCTL_DISMOUNT_VOLUME
+#define FSCTL_GET_NTFS_FILE_RECORD
+#define FSCTL_ALLOW_EXTENDED_DASD_IO
+#define FSCTL_RECALL_FILE
+
+#endif
+
+#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
+#define IO_REPARSE_TAG_HSM 0xC0000004
+#define IO_REPARSE_TAG_SIS 0x80000007
+
+
+/* For FSCTL_GET_SHADOW_COPY_DATA ...*/
+typedef char SHADOW_COPY_LABEL[25];
+
+typedef struct shadow_copy_data {
+ TALLOC_CTX *mem_ctx;
+ /* Total number of shadow volumes currently mounted */
+ uint32 num_volumes;
+ /* Concatenated list of labels */
+ SHADOW_COPY_LABEL *labels;
+} SHADOW_COPY_DATA;
+
+
+#endif /* _NTIOCTL_H */
diff --git a/source3/include/ntlmssp.h b/source3/include/ntlmssp.h
new file mode 100644
index 0000000000..3fb41c5613
--- /dev/null
+++ b/source3/include/ntlmssp.h
@@ -0,0 +1,175 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* NTLMSSP mode */
+enum NTLMSSP_ROLE
+{
+ NTLMSSP_SERVER,
+ NTLMSSP_CLIENT
+};
+
+/* NTLMSSP message types */
+enum NTLM_MESSAGE_TYPE
+{
+ NTLMSSP_INITIAL = 0 /* samba internal state */,
+ NTLMSSP_NEGOTIATE = 1,
+ NTLMSSP_CHALLENGE = 2,
+ NTLMSSP_AUTH = 3,
+ NTLMSSP_UNKNOWN = 4,
+ NTLMSSP_DONE = 5 /* samba final state */
+};
+
+/* NTLMSSP negotiation flags */
+#define NTLMSSP_NEGOTIATE_UNICODE 0x00000001
+#define NTLMSSP_NEGOTIATE_OEM 0x00000002
+#define NTLMSSP_REQUEST_TARGET 0x00000004
+#define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* Message integrity */
+#define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* Message confidentiality */
+#define NTLMSSP_NEGOTIATE_DATAGRAM_STYLE 0x00000040
+#define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080
+#define NTLMSSP_NEGOTIATE_NETWARE 0x00000100
+#define NTLMSSP_NEGOTIATE_NTLM 0x00000200
+#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x00001000
+#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x00002000
+#define NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL 0x00004000
+#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000
+#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000
+#define NTLMSSP_TARGET_TYPE_SERVER 0x20000
+#define NTLMSSP_CHAL_INIT_RESPONSE 0x00010000
+
+#define NTLMSSP_CHAL_ACCEPT_RESPONSE 0x00020000
+#define NTLMSSP_CHAL_NON_NT_SESSION_KEY 0x00040000
+#define NTLMSSP_NEGOTIATE_NTLM2 0x00080000
+#define NTLMSSP_CHAL_TARGET_INFO 0x00800000
+#define NTLMSSP_NEGOTIATE_VERSION 0x02000000
+#define NTLMSSP_NEGOTIATE_128 0x20000000 /* 128-bit encryption */
+#define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000
+#define NTLMSSP_NEGOTIATE_56 0x80000000
+
+#define NTLMSSP_FEATURE_SESSION_KEY 0x00000001
+#define NTLMSSP_FEATURE_SIGN 0x00000002
+#define NTLMSSP_FEATURE_SEAL 0x00000004
+
+#define NTLMSSP_NAME_TYPE_SERVER 0x01
+#define NTLMSSP_NAME_TYPE_DOMAIN 0x02
+#define NTLMSSP_NAME_TYPE_SERVER_DNS 0x03
+#define NTLMSSP_NAME_TYPE_DOMAIN_DNS 0x04
+
+#define NTLMSSP_SIG_SIZE 16
+
+typedef struct ntlmssp_state
+{
+ TALLOC_CTX *mem_ctx;
+ unsigned int ref_count;
+ enum NTLMSSP_ROLE role;
+ enum server_types server_role;
+ uint32 expected_state;
+
+ bool unicode;
+ bool use_ntlmv2;
+ char *user;
+ char *domain;
+ char *workstation;
+ unsigned char *nt_hash;
+ unsigned char *lm_hash;
+ char *server_domain;
+
+ DATA_BLOB internal_chal; /* Random challenge as supplied to the client for NTLM authentication */
+
+ DATA_BLOB chal; /* Random challenge as input into the actual NTLM (or NTLM2) authentication */
+ DATA_BLOB lm_resp;
+ DATA_BLOB nt_resp;
+ DATA_BLOB session_key;
+
+ uint32 neg_flags; /* the current state of negotiation with the NTLMSSP partner */
+
+ void *auth_context;
+
+ /**
+ * Callback to get the 'challenge' used for NTLM authentication.
+ *
+ * @param ntlmssp_state This structure
+ * @return 8 bytes of challnege data, determined by the server to be the challenge for NTLM authentication
+ *
+ */
+ const uint8 *(*get_challenge)(const struct ntlmssp_state *ntlmssp_state);
+
+ /**
+ * Callback to find if the challenge used by NTLM authentication may be modified
+ *
+ * The NTLM2 authentication scheme modifies the effective challenge, but this is not compatiable with the
+ * current 'security=server' implementation..
+ *
+ * @param ntlmssp_state This structure
+ * @return Can the challenge be set to arbitary values?
+ *
+ */
+ bool (*may_set_challenge)(const struct ntlmssp_state *ntlmssp_state);
+
+ /**
+ * Callback to set the 'challenge' used for NTLM authentication.
+ *
+ * The callback may use the void *auth_context to store state information, but the same value is always available
+ * from the DATA_BLOB chal on this structure.
+ *
+ * @param ntlmssp_state This structure
+ * @param challenge 8 bytes of data, agreed by the client and server to be the effective challenge for NTLM2 authentication
+ *
+ */
+ NTSTATUS (*set_challenge)(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge);
+
+ /**
+ * Callback to check the user's password.
+ *
+ * The callback must reads the feilds of this structure for the information it needs on the user
+ * @param ntlmssp_state This structure
+ * @param nt_session_key If an NT session key is returned by the authentication process, return it here
+ * @param lm_session_key If an LM session key is returned by the authentication process, return it here
+ *
+ */
+ NTSTATUS (*check_password)(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *nt_session_key, DATA_BLOB *lm_session_key);
+
+ const char *(*get_global_myname)(void);
+ const char *(*get_domain)(void);
+
+ /* ntlmv2 */
+
+ unsigned char send_sign_key[16];
+ unsigned char send_seal_key[16];
+ unsigned char recv_sign_key[16];
+ unsigned char recv_seal_key[16];
+
+ unsigned char send_seal_arc4_state[258];
+ unsigned char recv_seal_arc4_state[258];
+
+ uint32 ntlm2_send_seq_num;
+ uint32 ntlm2_recv_seq_num;
+
+ /* ntlmv1 */
+ unsigned char ntlmv1_arc4_state[258];
+ uint32 ntlmv1_seq_num;
+
+ /* it turns out that we don't always get the
+ response in at the time we want to process it.
+ Store it here, until we need it */
+ DATA_BLOB stored_response;
+
+} NTLMSSP_STATE;
diff --git a/source3/include/ntquotas.h b/source3/include/ntquotas.h
new file mode 100644
index 0000000000..ed503b3854
--- /dev/null
+++ b/source3/include/ntquotas.h
@@ -0,0 +1,91 @@
+/*
+ Unix SMB/CIFS implementation.
+ NT QUOTA code constants
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NTQUOTAS_H
+#define _NTQUOTAS_H
+
+/*
+ * details for Quota Flags:
+ *
+ * 0x20 Log Limit: log if the user exceeds his Hard Quota
+ * 0x10 Log Warn: log if the user exceeds his Soft Quota
+ * 0x02 Deny Disk: deny disk access when the user exceeds his Hard Quota
+ * 0x01 Enable Quotas: enable quota for this fs
+ *
+ */
+
+#define QUOTAS_ENABLED 0x0001
+#define QUOTAS_DENY_DISK 0x0002
+#define QUOTAS_LOG_VIOLATIONS 0x0004
+#define CONTENT_INDEX_DISABLED 0x0008
+#define QUOTAS_LOG_THRESHOLD 0x0010
+#define QUOTAS_LOG_LIMIT 0x0020
+#define LOG_VOLUME_THRESHOLD 0x0040
+#define LOG_VOLUME_LIMIT 0x0080
+#define QUOTAS_INCOMPLETE 0x0100
+#define QUOTAS_REBUILDING 0x0200
+#define QUOTAS_0400 0x0400
+#define QUOTAS_0800 0x0800
+#define QUOTAS_1000 0x1000
+#define QUOTAS_2000 0x2000
+#define QUOTAS_4000 0x4000
+#define QUOTAS_8000 0x8000
+
+#define SMB_NTQUOTAS_NO_LIMIT ((SMB_BIG_UINT)(-1))
+#define SMB_NTQUOTAS_NO_ENTRY ((SMB_BIG_UINT)(-2))
+#define SMB_NTQUOTAS_NO_SPACE ((SMB_BIG_UINT)(0))
+#define SMB_NTQUOTAS_1_B (SMB_BIG_UINT)0x0000000000000001
+#define SMB_NTQUOTAS_1KB (SMB_BIG_UINT)0x0000000000000400
+#define SMB_NTQUOTAS_1MB (SMB_BIG_UINT)0x0000000000100000
+#define SMB_NTQUOTAS_1GB (SMB_BIG_UINT)0x0000000040000000
+#define SMB_NTQUOTAS_1TB (SMB_BIG_UINT)0x0000010000000000
+#define SMB_NTQUOTAS_1PB (SMB_BIG_UINT)0x0004000000000000
+#define SMB_NTQUOTAS_1EB (SMB_BIG_UINT)0x1000000000000000
+
+enum SMB_QUOTA_TYPE {
+ SMB_INVALID_QUOTA_TYPE = -1,
+ SMB_USER_FS_QUOTA_TYPE = 1,
+ SMB_USER_QUOTA_TYPE = 2,
+ SMB_GROUP_FS_QUOTA_TYPE = 3,/* not used yet */
+ SMB_GROUP_QUOTA_TYPE = 4 /* not in use yet, maybe for disk_free queries */
+};
+
+typedef struct _SMB_NTQUOTA_STRUCT {
+ enum SMB_QUOTA_TYPE qtype;
+ SMB_BIG_UINT usedspace;
+ SMB_BIG_UINT softlim;
+ SMB_BIG_UINT hardlim;
+ uint32 qflags;
+ DOM_SID sid;
+} SMB_NTQUOTA_STRUCT;
+
+typedef struct _SMB_NTQUOTA_LIST {
+ struct _SMB_NTQUOTA_LIST *prev,*next;
+ TALLOC_CTX *mem_ctx;
+ uid_t uid;
+ SMB_NTQUOTA_STRUCT *quotas;
+} SMB_NTQUOTA_LIST;
+
+typedef struct _SMB_NTQUOTA_HANDLE {
+ bool valid;
+ SMB_NTQUOTA_LIST *quota_list;
+ SMB_NTQUOTA_LIST *tmp_list;
+} SMB_NTQUOTA_HANDLE;
+
+#endif /*_NTQUOTAS_H */
diff --git a/source3/include/packet.h b/source3/include/packet.h
new file mode 100644
index 0000000000..d5174229ca
--- /dev/null
+++ b/source3/include/packet.h
@@ -0,0 +1,83 @@
+/*
+ Unix SMB/CIFS implementation.
+ Packet handling
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * A packet context is a wrapper around a bidirectional file descriptor,
+ * hiding the handling of individual requests.
+ */
+
+struct packet_context;
+
+/*
+ * Initialize a packet context. The fd is given to the packet context, meaning
+ * that it is automatically closed when the packet context is freed.
+ */
+struct packet_context *packet_init(TALLOC_CTX *mem_ctx, int fd);
+
+/*
+ * Pull data from the fd
+ */
+NTSTATUS packet_fd_read(struct packet_context *ctx);
+
+/*
+ * Sync read, wait for the next chunk
+ */
+NTSTATUS packet_fd_read_sync(struct packet_context *ctx);
+
+/*
+ * Handle an incoming packet:
+ * Return False if none is available
+ * Otherwise return True and store the callback result in *status
+ */
+bool packet_handler(struct packet_context *ctx,
+ bool (*full_req)(const struct data_blob *data,
+ size_t *length,
+ void *private_data),
+ NTSTATUS (*callback)(const struct data_blob *data,
+ void *private_data),
+ void *private_data,
+ NTSTATUS *status);
+
+/*
+ * How many bytes of outgoing data do we have pending?
+ */
+size_t packet_outgoing_bytes(struct packet_context *ctx);
+
+/*
+ * Push data to the fd
+ */
+NTSTATUS packet_fd_write(struct packet_context *ctx);
+
+/*
+ * Sync flush all outgoing bytes
+ */
+NTSTATUS packet_flush(struct packet_context *ctx);
+
+/*
+ * Send a list of DATA_BLOBs
+ *
+ * Example: packet_send(ctx, 2, data_blob_const(&size, sizeof(size)),
+ * data_blob_const(buf, size));
+ */
+NTSTATUS packet_send(struct packet_context *ctx, int num_blobs, ...);
+
+/*
+ * Get the packet context's file descriptor
+ */
+int packet_get_fd(struct packet_context *ctx);
diff --git a/source3/include/passdb.h b/source3/include/passdb.h
new file mode 100644
index 0000000000..360a0d0444
--- /dev/null
+++ b/source3/include/passdb.h
@@ -0,0 +1,399 @@
+/*
+ Unix SMB/CIFS implementation.
+ passdb structures and parameters
+ Copyright (C) Gerald Carter 2001
+ Copyright (C) Luke Kenneth Casson Leighton 1998 - 2000
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Simo Sorce 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _PASSDB_H
+#define _PASSDB_H
+
+
+/*
+ * in samba4 idl
+ * ACCT_NT_PWD_SET == SAMR_FIELD_PASSWORD and
+ * ACCT_LM_PWD_SET == SAMR_FIELD_PASSWORD2
+ */
+
+#define ACCT_NT_PWD_SET 0x01000000
+#define ACCT_LM_PWD_SET 0x02000000
+
+/*
+ * bit flags representing initialized fields in struct samu
+ */
+enum pdb_elements {
+ PDB_UNINIT,
+ PDB_SMBHOME,
+ PDB_PROFILE,
+ PDB_DRIVE,
+ PDB_LOGONSCRIPT,
+ PDB_LOGONTIME,
+ PDB_LOGOFFTIME,
+ PDB_KICKOFFTIME,
+ PDB_BAD_PASSWORD_TIME,
+ PDB_CANCHANGETIME,
+ PDB_MUSTCHANGETIME,
+ PDB_PLAINTEXT_PW,
+ PDB_USERNAME,
+ PDB_FULLNAME,
+ PDB_DOMAIN,
+ PDB_NTUSERNAME,
+ PDB_HOURSLEN,
+ PDB_LOGONDIVS,
+ PDB_USERSID,
+ PDB_GROUPSID,
+ PDB_ACCTCTRL,
+ PDB_PASSLASTSET,
+ PDB_ACCTDESC,
+ PDB_WORKSTATIONS,
+ PDB_COMMENT,
+ PDB_MUNGEDDIAL,
+ PDB_HOURS,
+ PDB_FIELDS_PRESENT,
+ PDB_BAD_PASSWORD_COUNT,
+ PDB_LOGON_COUNT,
+ PDB_UNKNOWN6,
+ PDB_LMPASSWD,
+ PDB_NTPASSWD,
+ PDB_PWHISTORY,
+ PDB_BACKEND_PRIVATE_DATA,
+
+ /* this must be the last element */
+ PDB_COUNT
+};
+
+enum pdb_group_elements {
+ PDB_GROUP_NAME,
+ PDB_GROUP_SID,
+ PDB_GROUP_SID_NAME_USE,
+ PDB_GROUP_MEMBERS,
+
+ /* this must be the last element */
+ PDB_GROUP_COUNT
+};
+
+
+enum pdb_value_state {
+ PDB_DEFAULT=0,
+ PDB_SET,
+ PDB_CHANGED
+};
+
+#define IS_SAM_SET(x, flag) (pdb_get_init_flags(x, flag) == PDB_SET)
+#define IS_SAM_CHANGED(x, flag) (pdb_get_init_flags(x, flag) == PDB_CHANGED)
+#define IS_SAM_DEFAULT(x, flag) (pdb_get_init_flags(x, flag) == PDB_DEFAULT)
+
+/* cache for bad password lockout data, to be used on replicated SAMs */
+typedef struct logon_cache_struct {
+ time_t entry_timestamp;
+ uint32 acct_ctrl;
+ uint16 bad_password_count;
+ time_t bad_password_time;
+} LOGIN_CACHE;
+
+struct samu {
+ struct pdb_methods *methods;
+
+ /* initialization flags */
+ struct bitmap *change_flags;
+ struct bitmap *set_flags;
+
+ time_t logon_time; /* logon time */
+ time_t logoff_time; /* logoff time */
+ time_t kickoff_time; /* kickoff time */
+ time_t bad_password_time; /* last bad password entered */
+ 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 */
+
+ const char *username; /* UNIX username string */
+ const char *domain; /* Windows Domain name */
+ const char *nt_username; /* Windows username string */
+ const char *full_name; /* user's full name string */
+ const char *home_dir; /* home directory string */
+ const char *dir_drive; /* home directory drive string */
+ const char *logon_script; /* logon script string */
+ const char *profile_path; /* profile path string */
+ const char *acct_desc; /* user description string */
+ const char *workstations; /* login from workstations string */
+ const char *comment;
+ const char *munged_dial; /* munged path name and dial-back tel number */
+
+ DOM_SID user_sid;
+ DOM_SID *group_sid;
+
+ DATA_BLOB lm_pw; /* .data is Null if no password */
+ DATA_BLOB nt_pw; /* .data is Null if no password */
+ DATA_BLOB nt_pw_his; /* nt hashed password history .data is Null if not available */
+ char* plaintext_pw; /* is Null if not available */
+
+ uint32 acct_ctrl; /* account info (ACB_xxxx bit-mask) */
+ uint32 fields_present; /* 0x00ff ffff */
+
+ uint16 logon_divs; /* 168 - number of hours in a week */
+ uint32 hours_len; /* normally 21 bytes */
+ uint8 hours[MAX_HOURS_LEN];
+
+ /* Was unknown_5. */
+ uint16 bad_password_count;
+ uint16 logon_count;
+
+ uint32 unknown_6; /* 0x0000 04ec */
+
+ /* a tag for who added the private methods */
+
+ const struct pdb_methods *backend_private_methods;
+ void *backend_private_data;
+ void (*backend_private_data_free_fn)(void **);
+
+ /* maintain a copy of the user's struct passwd */
+
+ struct passwd *unix_pw;
+};
+
+struct acct_info {
+ fstring acct_name; /* account name */
+ fstring acct_desc; /* account name */
+ uint32 rid; /* domain-relative RID */
+};
+
+struct samr_displayentry {
+ uint32 idx;
+ uint32 rid;
+ uint32 acct_flags;
+ const char *account_name;
+ const char *fullname;
+ const char *description;
+};
+
+enum pdb_search_type {
+ PDB_USER_SEARCH,
+ PDB_GROUP_SEARCH,
+ PDB_ALIAS_SEARCH
+};
+
+struct pdb_search {
+ TALLOC_CTX *mem_ctx;
+ enum pdb_search_type type;
+ struct samr_displayentry *cache;
+ uint32 num_entries;
+ ssize_t cache_size;
+ bool search_ended;
+ void *private_data;
+ bool (*next_entry)(struct pdb_search *search,
+ struct samr_displayentry *entry);
+ void (*search_end)(struct pdb_search *search);
+};
+
+/*****************************************************************
+ Functions to be implemented by the new (v2) passdb API
+****************************************************************/
+
+/*
+ * This next constant specifies the version number of the PASSDB interface
+ * this SAMBA will load. Increment this if *ANY* changes are made to the interface.
+ * Changed interface to fix int -> size_t problems. JRA.
+ * There's no point in allocating arrays in
+ * samr_lookup_rids twice. It was done in the srv_samr_nt.c code as well as in
+ * the pdb module. Remove the latter, this might happen more often. VL.
+ * changed to version 14 to move lookup_rids and lookup_names to return
+ * enum lsa_SidType rather than uint32.
+ * Changed to 16 for access to the trusted domain passwords (obnox).
+ * Changed to 17, the sampwent interface is gone.
+ */
+
+#define PASSDB_INTERFACE_VERSION 17
+
+struct pdb_methods
+{
+ const char *name; /* What name got this module */
+
+ NTSTATUS (*getsampwnam)(struct pdb_methods *, struct samu *sam_acct, const char *username);
+
+ NTSTATUS (*getsampwsid)(struct pdb_methods *, struct samu *sam_acct, const DOM_SID *sid);
+
+ NTSTATUS (*create_user)(struct pdb_methods *, TALLOC_CTX *tmp_ctx,
+ const char *name, uint32 acct_flags,
+ uint32 *rid);
+
+ NTSTATUS (*delete_user)(struct pdb_methods *, TALLOC_CTX *tmp_ctx,
+ struct samu *sam_acct);
+
+ NTSTATUS (*add_sam_account)(struct pdb_methods *, struct samu *sampass);
+
+ NTSTATUS (*update_sam_account)(struct pdb_methods *, struct samu *sampass);
+
+ NTSTATUS (*delete_sam_account)(struct pdb_methods *, struct samu *username);
+
+ NTSTATUS (*rename_sam_account)(struct pdb_methods *, struct samu *oldname, const char *newname);
+
+ NTSTATUS (*update_login_attempts)(struct pdb_methods *methods, struct samu *sam_acct, bool success);
+
+ NTSTATUS (*getgrsid)(struct pdb_methods *methods, GROUP_MAP *map, DOM_SID sid);
+
+ NTSTATUS (*getgrgid)(struct pdb_methods *methods, GROUP_MAP *map, gid_t gid);
+
+ NTSTATUS (*getgrnam)(struct pdb_methods *methods, GROUP_MAP *map, const char *name);
+
+ NTSTATUS (*create_dom_group)(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx, const char *name,
+ uint32 *rid);
+
+ NTSTATUS (*delete_dom_group)(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx, uint32 rid);
+
+ NTSTATUS (*add_group_mapping_entry)(struct pdb_methods *methods,
+ GROUP_MAP *map);
+
+ NTSTATUS (*update_group_mapping_entry)(struct pdb_methods *methods,
+ GROUP_MAP *map);
+
+ NTSTATUS (*delete_group_mapping_entry)(struct pdb_methods *methods,
+ DOM_SID sid);
+
+ NTSTATUS (*enum_group_mapping)(struct pdb_methods *methods,
+ const DOM_SID *sid, enum lsa_SidType sid_name_use,
+ GROUP_MAP **pp_rmap, size_t *p_num_entries,
+ bool unix_only);
+
+ NTSTATUS (*enum_group_members)(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group,
+ uint32 **pp_member_rids,
+ size_t *p_num_members);
+
+ NTSTATUS (*enum_group_memberships)(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ struct samu *user,
+ DOM_SID **pp_sids, gid_t **pp_gids,
+ size_t *p_num_groups);
+
+ NTSTATUS (*set_unix_primary_group)(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ struct samu *user);
+
+ NTSTATUS (*add_groupmem)(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ uint32 group_rid, uint32 member_rid);
+
+ NTSTATUS (*del_groupmem)(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ uint32 group_rid, uint32 member_rid);
+
+ NTSTATUS (*create_alias)(struct pdb_methods *methods,
+ const char *name, uint32 *rid);
+
+ NTSTATUS (*delete_alias)(struct pdb_methods *methods,
+ const DOM_SID *sid);
+
+ NTSTATUS (*get_aliasinfo)(struct pdb_methods *methods,
+ const DOM_SID *sid,
+ struct acct_info *info);
+
+ NTSTATUS (*set_aliasinfo)(struct pdb_methods *methods,
+ const DOM_SID *sid,
+ struct acct_info *info);
+
+ NTSTATUS (*add_aliasmem)(struct pdb_methods *methods,
+ const DOM_SID *alias, const DOM_SID *member);
+ NTSTATUS (*del_aliasmem)(struct pdb_methods *methods,
+ const DOM_SID *alias, const DOM_SID *member);
+ NTSTATUS (*enum_aliasmem)(struct pdb_methods *methods,
+ const DOM_SID *alias, DOM_SID **members,
+ size_t *p_num_members);
+ NTSTATUS (*enum_alias_memberships)(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *domain_sid,
+ const DOM_SID *members,
+ size_t num_members,
+ uint32 **pp_alias_rids,
+ size_t *p_num_alias_rids);
+
+ NTSTATUS (*lookup_rids)(struct pdb_methods *methods,
+ const DOM_SID *domain_sid,
+ int num_rids,
+ uint32 *rids,
+ const char **pp_names,
+ enum lsa_SidType *attrs);
+
+ NTSTATUS (*lookup_names)(struct pdb_methods *methods,
+ const DOM_SID *domain_sid,
+ int num_names,
+ const char **pp_names,
+ uint32 *rids,
+ enum lsa_SidType *attrs);
+
+ NTSTATUS (*get_account_policy)(struct pdb_methods *methods,
+ int policy_index, uint32 *value);
+
+ NTSTATUS (*set_account_policy)(struct pdb_methods *methods,
+ int policy_index, uint32 value);
+
+ NTSTATUS (*get_seq_num)(struct pdb_methods *methods, time_t *seq_num);
+
+ bool (*search_users)(struct pdb_methods *methods,
+ struct pdb_search *search,
+ uint32 acct_flags);
+ bool (*search_groups)(struct pdb_methods *methods,
+ struct pdb_search *search);
+ bool (*search_aliases)(struct pdb_methods *methods,
+ struct pdb_search *search,
+ const DOM_SID *sid);
+
+ bool (*uid_to_rid)(struct pdb_methods *methods, uid_t uid,
+ uint32 *rid);
+ bool (*uid_to_sid)(struct pdb_methods *methods, uid_t uid,
+ DOM_SID *sid);
+ bool (*gid_to_sid)(struct pdb_methods *methods, gid_t gid,
+ DOM_SID *sid);
+ bool (*sid_to_id)(struct pdb_methods *methods, const DOM_SID *sid,
+ union unid_t *id, enum lsa_SidType *type);
+
+ bool (*rid_algorithm)(struct pdb_methods *methods);
+ bool (*new_rid)(struct pdb_methods *methods, uint32 *rid);
+
+
+ bool (*get_trusteddom_pw)(struct pdb_methods *methods,
+ const char *domain, char** pwd,
+ DOM_SID *sid, time_t *pass_last_set_time);
+ bool (*set_trusteddom_pw)(struct pdb_methods *methods,
+ const char* domain, const char* pwd,
+ const DOM_SID *sid);
+ bool (*del_trusteddom_pw)(struct pdb_methods *methods,
+ const char *domain);
+ NTSTATUS (*enum_trusteddoms)(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx, uint32 *num_domains,
+ struct trustdom_info ***domains);
+
+ void *private_data; /* Private data of some kind */
+
+ void (*free_private_data)(void **);
+};
+
+typedef NTSTATUS (*pdb_init_function)(struct pdb_methods **, const char *);
+
+struct pdb_init_function_entry {
+ const char *name;
+
+ /* Function to create a member of the pdb_methods list */
+ pdb_init_function init;
+
+ struct pdb_init_function_entry *prev, *next;
+};
+
+#endif /* _PASSDB_H */
diff --git a/source3/include/popt_common.h b/source3/include/popt_common.h
new file mode 100644
index 0000000000..bbd013a18f
--- /dev/null
+++ b/source3/include/popt_common.h
@@ -0,0 +1,58 @@
+/*
+ Unix SMB/CIFS implementation.
+ Common popt arguments
+ Copyright (C) Jelmer Vernooij 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _POPT_COMMON_H
+#define _POPT_COMMON_H
+
+#include <popt.h>
+
+/* Common popt structures */
+extern struct poptOption popt_common_samba[];
+extern struct poptOption popt_common_connection[];
+extern struct poptOption popt_common_configfile[];
+extern struct poptOption popt_common_version[];
+extern struct poptOption popt_common_credentials[];
+extern struct poptOption popt_common_debuglevel[];
+extern const struct poptOption popt_common_dynconfig[];
+
+#ifndef POPT_TABLEEND
+#define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
+#endif
+
+#define POPT_COMMON_SAMBA { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_samba, 0, "Common samba options:", NULL },
+#define POPT_COMMON_CONNECTION { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_connection, 0, "Connection options:", NULL },
+#define POPT_COMMON_VERSION { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_version, 0, "Common samba options:", NULL },
+#define POPT_COMMON_CONFIGFILE { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_configfile, 0, "Common samba config:", NULL },
+#define POPT_COMMON_CREDENTIALS { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_credentials, 0, "Authentication options:", NULL },
+#define POPT_COMMON_DYNCONFIG { NULL, 0, POPT_ARG_INCLUDE_TABLE, \
+ CONST_DISCARD(poptOption *, popt_common_dynconfig), 0, \
+ "Build-time configuration overrides:", NULL },
+#define POPT_COMMON_DEBUGLEVEL { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_debuglevel, 0, "Common samba debugging:", NULL },
+
+struct user_auth_info {
+ char *username;
+ char *password;
+ bool got_pass;
+ bool use_kerberos;
+ int signing_state;
+ bool smb_encrypt;
+ bool use_machine_account;
+};
+
+#endif /* _POPT_COMMON_H */
diff --git a/source3/include/printing.h b/source3/include/printing.h
new file mode 100644
index 0000000000..2788143cc5
--- /dev/null
+++ b/source3/include/printing.h
@@ -0,0 +1,102 @@
+#ifndef PRINTING_H_
+#define PRINTING_H_
+
+/*
+ Unix SMB/CIFS implementation.
+ printing definitions
+ Copyright (C) Andrew Tridgell 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ This file defines the low-level printing system interfaces used by the
+ SAMBA printing subsystem.
+*/
+
+/* Information for print jobs */
+struct printjob {
+ pid_t pid; /* which process launched the job */
+ int sysjob; /* the system (lp) job number */
+ int fd; /* file descriptor of open file if open */
+ time_t starttime; /* when the job started spooling */
+ int status; /* the status of this job */
+ size_t size; /* the size of the job so far */
+ int page_count; /* then number of pages so far */
+ bool spooled; /* has it been sent to the spooler yet? */
+ bool smbjob; /* set if the job is a SMB job */
+ fstring filename; /* the filename used to spool the file */
+ fstring jobname; /* the job name given to us by the client */
+ fstring user; /* the user who started the job */
+ fstring queuename; /* service number of printer for this job */
+ NT_DEVICEMODE *nt_devmode;
+};
+
+/* Information for print interfaces */
+struct printif
+{
+ /* value of the 'printing' option for this service */
+ enum printing_types type;
+
+ int (*queue_get)(const char *printer_name,
+ enum printing_types printing_type,
+ char *lpq_command,
+ print_queue_struct **q,
+ print_status_struct *status);
+ int (*queue_pause)(int snum);
+ int (*queue_resume)(int snum);
+ int (*job_delete)(const char *sharename, const char *lprm_command, struct printjob *pjob);
+ int (*job_pause)(int snum, struct printjob *pjob);
+ int (*job_resume)(int snum, struct printjob *pjob);
+ int (*job_submit)(int snum, struct printjob *pjob);
+};
+
+extern struct printif generic_printif;
+
+#ifdef HAVE_CUPS
+extern struct printif cups_printif;
+#endif /* HAVE_CUPS */
+
+#ifdef HAVE_IPRINT
+extern struct printif iprint_printif;
+#endif /* HAVE_IPRINT */
+
+/* PRINT_MAX_JOBID is now defined in local.h */
+#define UNIX_JOB_START PRINT_MAX_JOBID
+#define NEXT_JOBID(j) ((j+1) % PRINT_MAX_JOBID > 0 ? (j+1) % PRINT_MAX_JOBID : 1)
+
+#define MAX_CACHE_VALID_TIME 3600
+
+#ifndef PRINT_SPOOL_PREFIX
+#define PRINT_SPOOL_PREFIX "smbprn."
+#endif
+#define PRINT_DATABASE_VERSION 5
+
+/* There can be this many printing tdb's open, plus any locked ones. */
+#define MAX_PRINT_DBS_OPEN 1
+
+struct tdb_print_db {
+ struct tdb_print_db *next, *prev;
+ TDB_CONTEXT *tdb;
+ int ref_count;
+ fstring printer_name;
+};
+
+/*
+ * Used for print notify
+ */
+
+#define NOTIFY_PID_LIST_KEY "NOTIFY_PID_LIST"
+
+#endif /* PRINTING_H_ */
diff --git a/source3/include/privileges.h b/source3/include/privileges.h
new file mode 100644
index 0000000000..9a5d928da0
--- /dev/null
+++ b/source3/include/privileges.h
@@ -0,0 +1,112 @@
+
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Paul Ashton 1997
+ Copyright (C) Simo Sorce 2003
+ Copyright (C) Gerald (Jerry) Carter 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PRIVILEGES_H
+#define PRIVILEGES_H
+
+/* privilege bitmask */
+
+#define SE_PRIV_MASKSIZE 4
+
+typedef struct {
+ uint32 mask[SE_PRIV_MASKSIZE];
+} SE_PRIV;
+
+
+/* common privilege defines */
+
+#define SE_END { { 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }
+#define SE_NONE { { 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }
+#define SE_ALL_PRIVS { { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF } }
+
+
+/*
+ * We will use our own set of privileges since it makes no sense
+ * to implement all of the Windows set when only a portion will
+ * be used. Use 128-bit mask to give room to grow.
+ */
+
+#define SE_NETWORK_LOGON { { 0x00000001, 0x00000000, 0x00000000, 0x00000000 } }
+#define SE_INTERACTIVE_LOGON { { 0x00000002, 0x00000000, 0x00000000, 0x00000000 } }
+#define SE_BATCH_LOGON { { 0x00000004, 0x00000000, 0x00000000, 0x00000000 } }
+#define SE_SERVICE_LOGON { { 0x00000008, 0x00000000, 0x00000000, 0x00000000 } }
+#define SE_MACHINE_ACCOUNT { { 0x00000010, 0x00000000, 0x00000000, 0x00000000 } }
+#define SE_PRINT_OPERATOR { { 0x00000020, 0x00000000, 0x00000000, 0x00000000 } }
+#define SE_ADD_USERS { { 0x00000040, 0x00000000, 0x00000000, 0x00000000 } }
+#define SE_DISK_OPERATOR { { 0x00000080, 0x00000000, 0x00000000, 0x00000000 } }
+#define SE_REMOTE_SHUTDOWN { { 0x00000100, 0x00000000, 0x00000000, 0x00000000 } }
+#define SE_BACKUP { { 0x00000200, 0x00000000, 0x00000000, 0x00000000 } }
+#define SE_RESTORE { { 0x00000400, 0x00000000, 0x00000000, 0x00000000 } }
+#define SE_TAKE_OWNERSHIP { { 0x00000800, 0x00000000, 0x00000000, 0x00000000 } }
+
+/* defined in lib/privilegs_basic.c */
+
+extern const SE_PRIV se_priv_all;
+
+extern const SE_PRIV se_priv_none;
+extern const SE_PRIV se_machine_account;
+extern const SE_PRIV se_print_operator;
+extern const SE_PRIV se_add_users;
+extern const SE_PRIV se_disk_operators;
+extern const SE_PRIV se_remote_shutdown;
+extern const SE_PRIV se_restore;
+extern const SE_PRIV se_take_ownership;
+
+
+/*
+ * These are used in Lsa replies (srv_lsa_nt.c)
+ */
+#define PR_NONE 0x0000
+#define PR_LOG_ON_LOCALLY 0x0001
+#define PR_ACCESS_FROM_NETWORK 0x0002
+#define PR_LOG_ON_BATCH_JOB 0x0004
+#define PR_LOG_ON_SERVICE 0x0010
+
+
+typedef struct {
+ uint32 high;
+ uint32 low;
+} LUID;
+
+typedef struct {
+ LUID luid;
+ uint32 attr;
+} LUID_ATTR;
+
+typedef struct {
+ TALLOC_CTX *mem_ctx;
+ bool ext_ctx;
+ uint32 count;
+ uint32 control;
+ LUID_ATTR *set;
+} PRIVILEGE_SET;
+
+typedef struct {
+ SE_PRIV se_priv;
+ const char *name;
+ const char *description;
+ LUID luid;
+} PRIVS;
+
+#endif /* PRIVILEGES_H */
diff --git a/source3/include/proto.h b/source3/include/proto.h
new file mode 100644
index 0000000000..2901911c70
--- /dev/null
+++ b/source3/include/proto.h
@@ -0,0 +1,10554 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * collected prototypes header
+ *
+ * frozen from "make proto" in May 2008
+ *
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _PROTO_H_
+#define _PROTO_H_
+
+
+/* The following definitions come from auth/auth.c */
+
+NTSTATUS smb_register_auth(int version, const char *name, auth_init_function init);
+bool load_auth_module(struct auth_context *auth_context,
+ const char *module, auth_methods **ret) ;
+NTSTATUS make_auth_context_subsystem(struct auth_context **auth_context) ;
+NTSTATUS make_auth_context_fixed(struct auth_context **auth_context, uchar chal[8]) ;
+
+/* The following definitions come from auth/auth_builtin.c */
+
+NTSTATUS auth_builtin_init(void);
+
+/* The following definitions come from auth/auth_compat.c */
+
+NTSTATUS check_plaintext_password(const char *smb_name, DATA_BLOB plaintext_password, auth_serversupplied_info **server_info);
+bool password_ok(const char *smb_name, DATA_BLOB password_blob);
+
+/* The following definitions come from auth/auth_domain.c */
+
+NTSTATUS auth_domain_init(void) ;
+
+/* The following definitions come from auth/auth_ntlmssp.c */
+
+NTSTATUS auth_ntlmssp_start(AUTH_NTLMSSP_STATE **auth_ntlmssp_state);
+void auth_ntlmssp_end(AUTH_NTLMSSP_STATE **auth_ntlmssp_state);
+NTSTATUS auth_ntlmssp_update(AUTH_NTLMSSP_STATE *auth_ntlmssp_state,
+ const DATA_BLOB request, DATA_BLOB *reply) ;
+
+/* The following definitions come from auth/auth_sam.c */
+
+NTSTATUS auth_sam_init(void);
+
+/* The following definitions come from auth/auth_server.c */
+
+NTSTATUS auth_server_init(void);
+
+/* The following definitions come from auth/auth_unix.c */
+
+NTSTATUS auth_unix_init(void);
+
+/* The following definitions come from auth/auth_util.c */
+
+NTSTATUS make_user_info_map(auth_usersupplied_info **user_info,
+ const char *smb_name,
+ const char *client_domain,
+ const char *wksta_name,
+ DATA_BLOB *lm_pwd, DATA_BLOB *nt_pwd,
+ DATA_BLOB *lm_interactive_pwd, DATA_BLOB *nt_interactive_pwd,
+ DATA_BLOB *plaintext,
+ bool encrypted);
+bool make_user_info_netlogon_network(auth_usersupplied_info **user_info,
+ const char *smb_name,
+ const char *client_domain,
+ const char *wksta_name,
+ uint32 logon_parameters,
+ const uchar *lm_network_pwd,
+ int lm_pwd_len,
+ const uchar *nt_network_pwd,
+ int nt_pwd_len);
+bool make_user_info_netlogon_interactive(auth_usersupplied_info **user_info,
+ const char *smb_name,
+ const char *client_domain,
+ const char *wksta_name,
+ uint32 logon_parameters,
+ const uchar chal[8],
+ const uchar lm_interactive_pwd[16],
+ const uchar nt_interactive_pwd[16],
+ const uchar *dc_sess_key);
+bool make_user_info_for_reply(auth_usersupplied_info **user_info,
+ const char *smb_name,
+ const char *client_domain,
+ const uint8 chal[8],
+ DATA_BLOB plaintext_password);
+NTSTATUS make_user_info_for_reply_enc(auth_usersupplied_info **user_info,
+ const char *smb_name,
+ const char *client_domain,
+ DATA_BLOB lm_resp, DATA_BLOB nt_resp);
+bool make_user_info_guest(auth_usersupplied_info **user_info) ;
+NTSTATUS make_server_info_sam(auth_serversupplied_info **server_info,
+ struct samu *sampass);
+NTSTATUS create_local_token(auth_serversupplied_info *server_info);
+NTSTATUS create_token_from_username(TALLOC_CTX *mem_ctx, const char *username,
+ bool is_guest,
+ uid_t *uid, gid_t *gid,
+ char **found_username,
+ struct nt_user_token **token);
+bool user_in_group_sid(const char *username, const DOM_SID *group_sid);
+bool user_in_group(const char *username, const char *groupname);
+NTSTATUS make_server_info_pw(auth_serversupplied_info **server_info,
+ char *unix_username,
+ struct passwd *pwd);
+NTSTATUS make_serverinfo_from_username(TALLOC_CTX *mem_ctx,
+ const char *username,
+ bool is_guest,
+ struct auth_serversupplied_info **presult);
+struct auth_serversupplied_info *copy_serverinfo(TALLOC_CTX *mem_ctx,
+ auth_serversupplied_info *src);
+bool init_guest_info(void);
+bool server_info_set_session_key(struct auth_serversupplied_info *info,
+ DATA_BLOB session_key);
+NTSTATUS make_server_info_guest(TALLOC_CTX *mem_ctx,
+ auth_serversupplied_info **server_info);
+bool copy_current_user(struct current_user *dst, struct current_user *src);
+struct passwd *smb_getpwnam( TALLOC_CTX *mem_ctx, char *domuser,
+ fstring save_username, bool create );
+NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
+ const char *sent_nt_username,
+ const char *domain,
+ auth_serversupplied_info **server_info,
+ struct netr_SamInfo3 *info3);
+NTSTATUS make_server_info_wbcAuthUserInfo(TALLOC_CTX *mem_ctx,
+ const char *sent_nt_username,
+ const char *domain,
+ const struct wbcAuthUserInfo *info,
+ auth_serversupplied_info **server_info);
+void free_user_info(auth_usersupplied_info **user_info);
+bool make_auth_methods(struct auth_context *auth_context, auth_methods **auth_method) ;
+bool is_trusted_domain(const char* dom_name);
+
+/* The following definitions come from auth/auth_winbind.c */
+
+NTSTATUS auth_winbind_init(void);
+
+/* The following definitions come from auth/pampass.c */
+
+bool smb_pam_claim_session(char *user, char *tty, char *rhost);
+bool smb_pam_close_session(char *user, char *tty, char *rhost);
+NTSTATUS smb_pam_accountcheck(const char * user);
+NTSTATUS smb_pam_passcheck(const char * user, const char * password);
+bool smb_pam_passchange(const char * user, const char * oldpassword, const char * newpassword);
+NTSTATUS smb_pam_accountcheck(const char * user);
+bool smb_pam_claim_session(char *user, char *tty, char *rhost);
+bool smb_pam_close_session(char *in_user, char *tty, char *rhost);
+
+/* The following definitions come from auth/pass_check.c */
+
+void dfs_unlogin(void);
+NTSTATUS pass_check(const struct passwd *pass, const char *user, const char *password,
+ int pwlen, bool (*fn) (const char *, const char *), bool run_cracker);
+
+/* The following definitions come from auth/token_util.c */
+
+bool nt_token_check_sid ( const DOM_SID *sid, const NT_USER_TOKEN *token );
+bool nt_token_check_domain_rid( NT_USER_TOKEN *token, uint32 rid );
+NT_USER_TOKEN *get_root_nt_token( void );
+NTSTATUS add_aliases(const DOM_SID *domain_sid,
+ struct nt_user_token *token);
+NTSTATUS create_builtin_users(const DOM_SID *sid);
+NTSTATUS create_builtin_administrators(const DOM_SID *sid);
+struct nt_user_token *create_local_nt_token(TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ bool is_guest,
+ int num_groupsids,
+ const DOM_SID *groupsids);
+void debug_nt_user_token(int dbg_class, int dbg_lev, NT_USER_TOKEN *token);
+void debug_unix_user_token(int dbg_class, int dbg_lev, uid_t uid, gid_t gid,
+ int n_groups, gid_t *groups);
+
+/* The following definitions come from groupdb/mapping.c */
+
+NTSTATUS add_initial_entry(gid_t gid, const char *sid, enum lsa_SidType sid_name_use, const char *nt_name, const char *comment);
+bool get_domain_group_from_sid(DOM_SID sid, GROUP_MAP *map);
+int smb_create_group(const char *unix_group, gid_t *new_gid);
+int smb_delete_group(const char *unix_group);
+int smb_set_primary_group(const char *unix_group, const char* unix_user);
+int smb_add_user_group(const char *unix_group, const char *unix_user);
+int smb_delete_user_group(const char *unix_group, const char *unix_user);
+NTSTATUS pdb_default_getgrsid(struct pdb_methods *methods, GROUP_MAP *map,
+ DOM_SID sid);
+NTSTATUS pdb_default_getgrgid(struct pdb_methods *methods, GROUP_MAP *map,
+ gid_t gid);
+NTSTATUS pdb_default_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
+ const char *name);
+NTSTATUS pdb_default_add_group_mapping_entry(struct pdb_methods *methods,
+ GROUP_MAP *map);
+NTSTATUS pdb_default_update_group_mapping_entry(struct pdb_methods *methods,
+ GROUP_MAP *map);
+NTSTATUS pdb_default_delete_group_mapping_entry(struct pdb_methods *methods,
+ DOM_SID sid);
+NTSTATUS pdb_default_enum_group_mapping(struct pdb_methods *methods,
+ const DOM_SID *sid, enum lsa_SidType sid_name_use,
+ GROUP_MAP **pp_rmap, size_t *p_num_entries,
+ bool unix_only);
+NTSTATUS pdb_default_create_alias(struct pdb_methods *methods,
+ const char *name, uint32 *rid);
+NTSTATUS pdb_default_delete_alias(struct pdb_methods *methods,
+ const DOM_SID *sid);
+NTSTATUS pdb_default_get_aliasinfo(struct pdb_methods *methods,
+ const DOM_SID *sid,
+ struct acct_info *info);
+NTSTATUS pdb_default_set_aliasinfo(struct pdb_methods *methods,
+ const DOM_SID *sid,
+ struct acct_info *info);
+NTSTATUS pdb_default_add_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias, const DOM_SID *member);
+NTSTATUS pdb_default_del_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias, const DOM_SID *member);
+NTSTATUS pdb_default_enum_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias, DOM_SID **pp_members,
+ size_t *p_num_members);
+NTSTATUS pdb_default_alias_memberships(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *domain_sid,
+ const DOM_SID *members,
+ size_t num_members,
+ uint32 **pp_alias_rids,
+ size_t *p_num_alias_rids);
+NTSTATUS pdb_nop_getgrsid(struct pdb_methods *methods, GROUP_MAP *map,
+ DOM_SID sid);
+NTSTATUS pdb_nop_getgrgid(struct pdb_methods *methods, GROUP_MAP *map,
+ gid_t gid);
+NTSTATUS pdb_nop_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
+ const char *name);
+NTSTATUS pdb_nop_add_group_mapping_entry(struct pdb_methods *methods,
+ GROUP_MAP *map);
+NTSTATUS pdb_nop_update_group_mapping_entry(struct pdb_methods *methods,
+ GROUP_MAP *map);
+NTSTATUS pdb_nop_delete_group_mapping_entry(struct pdb_methods *methods,
+ DOM_SID sid);
+NTSTATUS pdb_nop_enum_group_mapping(struct pdb_methods *methods,
+ enum lsa_SidType sid_name_use,
+ GROUP_MAP **rmap, size_t *num_entries,
+ bool unix_only);
+bool pdb_get_dom_grp_info(const DOM_SID *sid, struct acct_info *info);
+bool pdb_set_dom_grp_info(const DOM_SID *sid, const struct acct_info *info);
+NTSTATUS pdb_create_builtin_alias(uint32 rid);
+
+/* The following definitions come from groupdb/mapping_ldb.c */
+
+const struct mapping_backend *groupdb_ldb_init(void);
+
+/* The following definitions come from groupdb/mapping_tdb.c */
+
+const struct mapping_backend *groupdb_tdb_init(void);
+
+/* The following definitions come from intl/lang_tdb.c */
+
+bool lang_tdb_init(const char *lang);
+const char *lang_msg(const char *msgid);
+void lang_msg_free(const char *msgstr);
+char *lang_tdb_current(void);
+
+/* The following definitions come from lib/access.c */
+
+bool client_match(const char *tok, const void *item);
+bool list_match(const char **list,const void *item,
+ bool (*match_fn)(const char *, const void *));
+bool allow_access(const char **deny_list,
+ const char **allow_list,
+ const char *cname,
+ const char *caddr);
+bool check_access(int sock, const char **allow_list, const char **deny_list);
+
+/* The following definitions come from lib/account_pol.c */
+
+void account_policy_names_list(const char ***names, int *num_names);
+const char *decode_account_policy_name(int field);
+const char *get_account_policy_attr(int field);
+const char *account_policy_get_desc(int field);
+int account_policy_name_to_fieldnum(const char *name);
+bool account_policy_get_default(int account_policy, uint32 *val);
+bool init_account_policy(void);
+bool account_policy_get(int field, uint32 *value);
+bool account_policy_set(int field, uint32 value);
+bool cache_account_policy_set(int field, uint32 value);
+bool cache_account_policy_get(int field, uint32 *value);
+struct db_context *get_account_pol_db( void );
+
+/* The following definitions come from lib/adt_tree.c */
+
+
+/* The following definitions come from lib/afs.c */
+
+char *afs_createtoken_str(const char *username, const char *cell);
+bool afs_login(connection_struct *conn);
+bool afs_login(connection_struct *conn);
+char *afs_createtoken_str(const char *username, const char *cell);
+
+/* The following definitions come from lib/afs_settoken.c */
+
+int afs_syscall( int subcall,
+ char * path,
+ int cmd,
+ char * cmarg,
+ int follow);
+bool afs_settoken_str(const char *token_string);
+bool afs_settoken_str(const char *token_string);
+
+/* The following definitions come from lib/arc4.c */
+
+void smb_arc4_init(unsigned char arc4_state_out[258], const unsigned char *key, size_t keylen);
+void smb_arc4_crypt(unsigned char arc4_state_inout[258], unsigned char *data, size_t len);
+
+/* The following definitions come from lib/audit.c */
+
+const char *audit_category_str(uint32 category);
+const char *audit_param_str(uint32 category);
+const char *audit_description_str(uint32 category);
+bool get_audit_category_from_param(const char *param, uint32 *audit_category);
+const char *audit_policy_str(TALLOC_CTX *mem_ctx, uint32 policy);
+
+/* The following definitions come from lib/bitmap.c */
+
+struct bitmap *bitmap_allocate(int n);
+void bitmap_free(struct bitmap *bm);
+struct bitmap *bitmap_talloc(TALLOC_CTX *mem_ctx, int n);
+int bitmap_copy(struct bitmap * const dst, const struct bitmap * const src);
+bool bitmap_set(struct bitmap *bm, unsigned i);
+bool bitmap_clear(struct bitmap *bm, unsigned i);
+bool bitmap_query(struct bitmap *bm, unsigned i);
+int bitmap_find(struct bitmap *bm, unsigned ofs);
+
+/* The following definitions come from lib/charcnv.c */
+
+char lp_failed_convert_char(void);
+void lazy_initialize_conv(void);
+void gfree_charcnv(void);
+void init_iconv(void);
+size_t convert_string(charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t destlen, bool allow_bad_conv);
+bool convert_string_allocate(TALLOC_CTX *ctx, charset_t from, charset_t to,
+ void const *src, size_t srclen, void *dst,
+ size_t *converted_size, bool allow_bad_conv);
+bool convert_string_talloc(TALLOC_CTX *ctx, charset_t from, charset_t to,
+ void const *src, size_t srclen, void *dst,
+ size_t *converted_size, bool allow_bad_conv);
+size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen);
+char *strdup_upper(const char *s);
+char *talloc_strdup_upper(TALLOC_CTX *ctx, const char *s);
+size_t unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen);
+char *strdup_lower(const char *s);
+char *talloc_strdup_lower(TALLOC_CTX *ctx, const char *s);
+size_t ucs2_align(const void *base_ptr, const void *p, int flags);
+size_t push_ascii(void *dest, const char *src, size_t dest_len, int flags);
+size_t push_ascii_fstring(void *dest, const char *src);
+size_t push_ascii_nstring(void *dest, const char *src);
+bool push_ascii_allocate(char **dest, const char *src, size_t *converted_size);
+size_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len, int flags);
+size_t pull_ascii_fstring(char *dest, const void *src);
+size_t pull_ascii_nstring(char *dest, size_t dest_len, const void *src);
+size_t push_ucs2(const void *base_ptr, void *dest, const char *src, size_t dest_len, int flags);
+bool push_ucs2_allocate(smb_ucs2_t **dest, const char *src,
+ size_t *converted_size);
+size_t push_utf8_fstring(void *dest, const char *src);
+bool push_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src,
+ size_t *converted_size);
+bool push_utf8_allocate(char **dest, const char *src, size_t *converted_size);
+size_t pull_ucs2(const void *base_ptr, char *dest, const void *src, size_t dest_len, size_t src_len, int flags);
+size_t pull_ucs2_base_talloc(TALLOC_CTX *ctx,
+ const void *base_ptr,
+ char **ppdest,
+ const void *src,
+ size_t src_len,
+ int flags);
+size_t pull_ucs2_fstring(char *dest, const void *src);
+bool push_ucs2_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src,
+ size_t *converted_size);
+bool pull_ucs2_allocate(char **dest, const smb_ucs2_t *src,
+ size_t *converted_size);
+bool pull_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src,
+ size_t *converted_size);
+bool pull_utf8_allocate(char **dest, const char *src, size_t *converted_size);
+bool pull_ucs2_talloc(TALLOC_CTX *ctx, char **dest, const smb_ucs2_t *src,
+ size_t *converted_size);
+bool pull_ascii_talloc(TALLOC_CTX *ctx, char **dest, const char *src,
+ size_t *converted_size);
+size_t push_string_fn(const char *function, unsigned int line,
+ const void *base_ptr, uint16 flags2,
+ void *dest, const char *src,
+ size_t dest_len, int flags);
+size_t pull_string_fn(const char *function,
+ unsigned int line,
+ const void *base_ptr,
+ uint16 smb_flags2,
+ char *dest,
+ const void *src,
+ size_t dest_len,
+ size_t src_len,
+ int flags);
+size_t pull_string_talloc_fn(const char *function,
+ unsigned int line,
+ TALLOC_CTX *ctx,
+ const void *base_ptr,
+ uint16 smb_flags2,
+ char **ppdest,
+ const void *src,
+ size_t src_len,
+ int flags);
+size_t align_string(const void *base_ptr, const char *p, int flags);
+codepoint_t next_codepoint(const char *str, size_t *size);
+
+/* The following definitions come from lib/clobber.c */
+
+void clobber_region(const char *fn, unsigned int line, char *dest, size_t len);
+
+/* The following definitions come from lib/conn_tdb.c */
+
+struct db_record *connections_fetch_record(TALLOC_CTX *mem_ctx,
+ TDB_DATA key);
+struct db_record *connections_fetch_entry(TALLOC_CTX *mem_ctx,
+ connection_struct *conn,
+ const char *name);
+int connections_traverse(int (*fn)(struct db_record *rec,
+ void *private_data),
+ void *private_data);
+int connections_forall(int (*fn)(struct db_record *rec,
+ const struct connections_key *key,
+ const struct connections_data *data,
+ void *private_data),
+ void *private_data);
+bool connections_init(bool rw);
+
+/* The following definitions come from lib/crc32.c */
+
+uint32 crc32_calc_buffer(const char *buf, size_t size);
+
+/* The following definitions come from lib/data_blob.c */
+
+DATA_BLOB data_blob(const void *p, size_t length);
+DATA_BLOB data_blob_talloc(TALLOC_CTX *mem_ctx, const void *p, size_t length);
+void data_blob_free(DATA_BLOB *d);
+void data_blob_clear(DATA_BLOB *d);
+void data_blob_clear_free(DATA_BLOB *d);
+DATA_BLOB data_blob_string_const(const char *str);
+DATA_BLOB data_blob_const(const void *p, size_t length);
+DATA_BLOB data_blob_talloc_zero(TALLOC_CTX *mem_ctx, size_t length);
+_PUBLIC_ char *data_blob_hex_string(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob);
+
+/* The following definitions come from lib/dbwrap_util.c */
+
+int32_t dbwrap_fetch_int32(struct db_context *db, const char *keystr);
+int dbwrap_store_int32(struct db_context *db, const char *keystr, int32_t v);
+bool dbwrap_fetch_uint32(struct db_context *db, const char *keystr,
+ uint32_t *val);
+bool dbwrap_store_uint32(struct db_context *db, const char *keystr, uint32_t v);
+uint32_t dbwrap_change_uint32_atomic(struct db_context *db, const char *keystr,
+ uint32_t *oldval, uint32_t change_val);
+int32 dbwrap_change_int32_atomic(struct db_context *db, const char *keystr,
+ int32 *oldval, int32 change_val);
+NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
+ int flag);
+NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key);
+NTSTATUS dbwrap_trans_store_int32(struct db_context *db, const char *keystr,
+ int32_t v);
+NTSTATUS dbwrap_trans_store_uint32(struct db_context *db, const char *keystr,
+ uint32_t v);
+NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
+ TDB_DATA data, int flags);
+NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key);
+
+/* The following definitions come from lib/debug.c */
+
+void gfree_debugsyms(void);
+const char *debug_classname_from_index(int ndx);
+int debug_add_class(const char *classname);
+int debug_lookup_classname(const char *classname);
+bool debug_parse_levels(const char *params_str);
+void debug_message(struct messaging_context *msg_ctx, void *private_data, uint32_t msg_type, struct server_id src, DATA_BLOB *data);
+void debug_init(void);
+void debug_register_msgs(struct messaging_context *msg_ctx);
+void setup_logging(const char *pname, bool interactive);
+void debug_set_logfile(const char *name);
+bool reopen_logs( void );
+void force_check_log_size( void );
+bool need_to_check_log_size( void );
+void check_log_size( void );
+void dbgflush( void );
+bool dbghdr(int level, int cls, const char *file, const char *func, int line);
+TALLOC_CTX *debug_ctx(void);
+
+/* The following definitions come from lib/display_sec.c */
+
+char *get_sec_mask_str(TALLOC_CTX *ctx, uint32 type);
+void display_sec_access(SEC_ACCESS *info);
+void display_sec_ace_flags(uint8_t flags);
+void display_sec_ace(SEC_ACE *ace);
+void display_sec_acl(SEC_ACL *sec_acl);
+void display_acl_type(uint16 type);
+void display_sec_desc(SEC_DESC *sec);
+
+/* The following definitions come from lib/dmallocmsg.c */
+
+void register_dmalloc_msgs(struct messaging_context *msg_ctx);
+
+/* The following definitions come from lib/dprintf.c */
+
+void display_set_stderr(void);
+
+/* The following definitions come from lib/errmap_unix.c */
+
+NTSTATUS map_nt_error_from_unix(int unix_error);
+
+/* The following definitions come from lib/events.c */
+
+struct timed_event *event_add_timed(struct event_context *event_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct timeval when,
+ const char *event_name,
+ void (*handler)(struct event_context *event_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data),
+ void *private_data);
+struct fd_event *event_add_fd(struct event_context *event_ctx,
+ TALLOC_CTX *mem_ctx,
+ int fd, uint16_t flags,
+ void (*handler)(struct event_context *event_ctx,
+ struct fd_event *event,
+ uint16 flags,
+ void *private_data),
+ void *private_data);
+void event_fd_set_writeable(struct fd_event *fde);
+void event_fd_set_not_writeable(struct fd_event *fde);
+void event_fd_set_readable(struct fd_event *fde);
+void event_fd_set_not_readable(struct fd_event *fde);
+bool event_add_to_select_args(struct event_context *event_ctx,
+ const struct timeval *now,
+ fd_set *read_fds, fd_set *write_fds,
+ struct timeval *timeout, int *maxfd);
+bool events_pending(struct event_context *event_ctx);
+bool run_events(struct event_context *event_ctx,
+ int selrtn, fd_set *read_fds, fd_set *write_fds);
+struct timeval *get_timed_events_timeout(struct event_context *event_ctx,
+ struct timeval *to_ret);
+int event_loop_once(struct event_context *ev);
+struct event_context *event_context_init(TALLOC_CTX *mem_ctx);
+int set_event_dispatch_time(struct event_context *event_ctx,
+ const char *event_name, struct timeval when);
+int cancel_named_event(struct event_context *event_ctx,
+ const char *event_name);
+void dump_event_list(struct event_context *event_ctx);
+
+/* The following definitions come from lib/fault.c */
+
+void fault_setup(void (*fn)(void *));
+void dump_core_setup(const char *progname);
+
+/* The following definitions come from lib/file_id.c */
+
+struct file_id file_id_create_dev(SMB_DEV_T dev, SMB_INO_T inode);
+struct file_id vfs_file_id_from_sbuf(connection_struct *conn, const SMB_STRUCT_STAT *sbuf);
+bool file_id_equal(const struct file_id *id1, const struct file_id *id2);
+const char *file_id_string_tos(const struct file_id *id);
+void push_file_id_16(char *buf, const struct file_id *id);
+void pull_file_id_16(char *buf, struct file_id *id);
+
+/* The following definitions come from lib/fsusage.c */
+
+int sys_fsusage(const char *path, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
+
+/* The following definitions come from lib/gencache.c */
+
+bool gencache_init(void);
+bool gencache_shutdown(void);
+bool gencache_set(const char *keystr, const char *value, time_t timeout);
+bool gencache_del(const char *keystr);
+bool gencache_get(const char *keystr, char **valstr, time_t *timeout);
+bool gencache_get_data_blob(const char *keystr, DATA_BLOB *blob, bool *expired);
+bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob, time_t timeout);
+void gencache_iterate(void (*fn)(const char* key, const char *value, time_t timeout, void* dptr),
+ void* data, const char* keystr_pattern);
+int gencache_lock_entry( const char *key );
+void gencache_unlock_entry( const char *key );
+
+/* The following definitions come from lib/genrand.c */
+
+void set_rand_reseed_callback(void (*fn)(int *));
+void set_need_random_reseed(void);
+void generate_random_buffer( unsigned char *out, int len);
+char *generate_random_str(size_t len);
+
+/* The following definitions come from lib/hmacmd5.c */
+
+void hmac_md5_init_rfc2104(const unsigned char *key, int key_len, HMACMD5Context *ctx);
+void hmac_md5_init_limK_to_64(const unsigned char* key, int key_len,
+ HMACMD5Context *ctx);
+void hmac_md5_update(const unsigned char *text, int text_len, HMACMD5Context *ctx);
+void hmac_md5_final(unsigned char *digest, HMACMD5Context *ctx);
+void hmac_md5( unsigned char key[16], const unsigned char *data, int data_len,
+ unsigned char *digest);
+
+/* The following definitions come from lib/iconv.c */
+
+NTSTATUS smb_register_charset(struct charset_functions *funcs) ;
+size_t smb_iconv(smb_iconv_t cd,
+ const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode);
+int smb_iconv_close (smb_iconv_t cd);
+
+/* The following definitions come from lib/interface.c */
+
+bool ismyaddr(const struct sockaddr_storage *ip);
+bool ismyip_v4(struct in_addr ip);
+bool is_local_net(const struct sockaddr_storage *from);
+void setup_linklocal_scope_id(struct sockaddr_storage *pss);
+bool is_local_net_v4(struct in_addr from);
+int iface_count(void);
+int iface_count_v4_nl(void);
+const struct in_addr *first_ipv4_iface(void);
+struct interface *get_interface(int n);
+const struct sockaddr_storage *iface_n_sockaddr_storage(int n);
+const struct in_addr *iface_n_ip_v4(int n);
+const struct in_addr *iface_n_bcast_v4(int n);
+const struct sockaddr_storage *iface_n_bcast(int n);
+const struct sockaddr_storage *iface_ip(const struct sockaddr_storage *ip);
+bool iface_local(const struct sockaddr_storage *ip);
+void load_interfaces(void);
+void gfree_interfaces(void);
+bool interfaces_changed(void);
+
+/* The following definitions come from lib/ldap_debug_handler.c */
+
+void init_ldap_debugging(void);
+
+/* The following definitions come from lib/ldap_escape.c */
+
+char *escape_ldap_string_alloc(const char *s);
+char *escape_rdn_val_string_alloc(const char *s);
+
+/* The following definitions come from lib/md4.c */
+
+void mdfour(unsigned char *out, const unsigned char *in, int n);
+
+/* The following definitions come from lib/md5.c */
+
+void MD5Init(struct MD5Context *ctx);
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
+
+/* The following definitions come from lib/module.c */
+
+NTSTATUS smb_load_module(const char *module_name);
+int smb_load_modules(const char **modules);
+NTSTATUS smb_probe_module(const char *subsystem, const char *module);
+NTSTATUS smb_load_module(const char *module_name);
+int smb_load_modules(const char **modules);
+NTSTATUS smb_probe_module(const char *subsystem, const char *module);
+void init_modules(void);
+
+/* The following definitions come from lib/ms_fnmatch.c */
+
+int ms_fnmatch(const char *pattern, const char *string, bool translate_pattern,
+ bool is_case_sensitive);
+int gen_fnmatch(const char *pattern, const char *string);
+
+/* The following definitions come from lib/pam_errors.c */
+
+NTSTATUS pam_to_nt_status(int pam_error);
+int nt_status_to_pam(NTSTATUS nt_status);
+NTSTATUS pam_to_nt_status(int pam_error);
+int nt_status_to_pam(NTSTATUS nt_status);
+
+/* The following definitions come from lib/pidfile.c */
+
+pid_t pidfile_pid(const char *name);
+void pidfile_create(const char *program_name);
+
+/* The following definitions come from lib/popt_common.c */
+
+
+/* The following definitions come from lib/privileges.c */
+
+bool get_privileges_for_sids(SE_PRIV *privileges, DOM_SID *slist, int scount);
+NTSTATUS privilege_enumerate_accounts(DOM_SID **sids, int *num_sids);
+NTSTATUS privilege_enum_sids(const SE_PRIV *mask, TALLOC_CTX *mem_ctx,
+ DOM_SID **sids, int *num_sids);
+bool grant_privilege(const DOM_SID *sid, const SE_PRIV *priv_mask);
+bool grant_privilege_by_name(DOM_SID *sid, const char *name);
+bool revoke_privilege(const DOM_SID *sid, const SE_PRIV *priv_mask);
+bool revoke_all_privileges( DOM_SID *sid );
+bool revoke_privilege_by_name(DOM_SID *sid, const char *name);
+NTSTATUS privilege_create_account(const DOM_SID *sid );
+NTSTATUS privilege_set_init(PRIVILEGE_SET *priv_set);
+NTSTATUS privilege_set_init_by_ctx(TALLOC_CTX *mem_ctx, PRIVILEGE_SET *priv_set);
+void privilege_set_free(PRIVILEGE_SET *priv_set);
+NTSTATUS dup_luid_attr(TALLOC_CTX *mem_ctx, LUID_ATTR **new_la, LUID_ATTR *old_la, int count);
+bool is_privileged_sid( const DOM_SID *sid );
+bool grant_all_privileges( const DOM_SID *sid );
+
+/* The following definitions come from lib/privileges_basic.c */
+
+bool se_priv_copy( SE_PRIV *dst, const SE_PRIV *src );
+bool se_priv_put_all_privileges(SE_PRIV *mask);
+void se_priv_add( SE_PRIV *mask, const SE_PRIV *addpriv );
+void se_priv_remove( SE_PRIV *mask, const SE_PRIV *removepriv );
+bool se_priv_equal( const SE_PRIV *mask1, const SE_PRIV *mask2 );
+bool se_priv_from_name( const char *name, SE_PRIV *mask );
+void dump_se_priv( int dbg_cl, int dbg_lvl, const SE_PRIV *mask );
+bool is_privilege_assigned(const SE_PRIV *privileges,
+ const SE_PRIV *check);
+const char* get_privilege_dispname( const char *name );
+bool user_has_privileges(const NT_USER_TOKEN *token, const SE_PRIV *privilege);
+bool user_has_any_privilege(NT_USER_TOKEN *token, const SE_PRIV *privilege);
+int count_all_privileges( void );
+LUID_ATTR get_privilege_luid( SE_PRIV *mask );
+const char *luid_to_privilege_name(const LUID *set);
+bool se_priv_to_privilege_set( PRIVILEGE_SET *set, SE_PRIV *mask );
+bool privilege_set_to_se_priv( SE_PRIV *mask, struct lsa_PrivilegeSet *privset );
+
+/* The following definitions come from lib/readline.c */
+
+char *smb_readline(const char *prompt, void (*callback)(void),
+ char **(completion_fn)(const char *text, int start, int end));
+const char *smb_readline_get_line_buffer(void);
+void smb_readline_ca_char(char c);
+int cmd_history(void);
+
+/* The following definitions come from lib/recvfile.c */
+
+ssize_t sys_recvfile(int fromfd,
+ int tofd,
+ SMB_OFF_T offset,
+ size_t count);
+ssize_t sys_recvfile(int fromfd,
+ int tofd,
+ SMB_OFF_T offset,
+ size_t count);
+ssize_t drain_socket(int sockfd, size_t count);
+
+/* The following definitions come from lib/secace.c */
+
+bool sec_ace_object(uint8 type);
+void sec_ace_copy(SEC_ACE *ace_dest, SEC_ACE *ace_src);
+void init_sec_ace(SEC_ACE *t, const DOM_SID *sid, enum security_ace_type type,
+ uint32 mask, uint8 flag);
+NTSTATUS sec_ace_add_sid(TALLOC_CTX *ctx, SEC_ACE **pp_new, SEC_ACE *old, unsigned *num, DOM_SID *sid, uint32 mask);
+NTSTATUS sec_ace_mod_sid(SEC_ACE *ace, size_t num, DOM_SID *sid, uint32 mask);
+NTSTATUS sec_ace_del_sid(TALLOC_CTX *ctx, SEC_ACE **pp_new, SEC_ACE *old, uint32 *num, DOM_SID *sid);
+bool sec_ace_equal(SEC_ACE *s1, SEC_ACE *s2);
+int nt_ace_inherit_comp( SEC_ACE *a1, SEC_ACE *a2);
+int nt_ace_canon_comp( SEC_ACE *a1, SEC_ACE *a2);
+void dacl_sort_into_canonical_order(SEC_ACE *srclist, unsigned int num_aces);
+bool token_sid_in_ace(const NT_USER_TOKEN *token, const SEC_ACE *ace);
+
+/* The following definitions come from lib/secacl.c */
+
+SEC_ACL *make_sec_acl(TALLOC_CTX *ctx, enum security_acl_revision revision,
+ int num_aces, SEC_ACE *ace_list);
+SEC_ACL *dup_sec_acl(TALLOC_CTX *ctx, SEC_ACL *src);
+bool sec_acl_equal(SEC_ACL *s1, SEC_ACL *s2);
+
+/* The following definitions come from lib/secdesc.c */
+
+bool sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2);
+SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb);
+SEC_DESC *make_sec_desc(TALLOC_CTX *ctx,
+ enum security_descriptor_revision revision,
+ uint16 type,
+ const DOM_SID *owner_sid, const DOM_SID *grp_sid,
+ SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size);
+SEC_DESC *dup_sec_desc(TALLOC_CTX *ctx, const SEC_DESC *src);
+NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx,
+ struct security_descriptor *secdesc,
+ uint8 **data, size_t *len);
+NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8 *data, size_t len,
+ struct security_descriptor **psecdesc);
+SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, const DOM_SID *owner_sid, const DOM_SID *grp_sid,
+ SEC_ACL *dacl, size_t *sd_size);
+SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc);
+SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src);
+NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size);
+NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask);
+NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size);
+SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr,
+ bool child_container);
+void init_sec_access(uint32 *t, uint32 mask);
+
+/* The following definitions come from lib/select.c */
+
+void sys_select_signal(char c);
+int sys_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval);
+int sys_select_intr(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval);
+
+/* The following definitions come from lib/sendfile.c */
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count);
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count);
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count);
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count);
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count);
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count);
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count);
+
+/* The following definitions come from lib/server_mutex.c */
+
+struct named_mutex *grab_named_mutex(TALLOC_CTX *mem_ctx, const char *name,
+ int timeout);
+
+/* The following definitions come from lib/sharesec.c */
+
+SEC_DESC *get_share_security_default( TALLOC_CTX *ctx, size_t *psize, uint32 def_access);
+SEC_DESC *get_share_security( TALLOC_CTX *ctx, const char *servicename,
+ size_t *psize);
+bool set_share_security(const char *share_name, SEC_DESC *psd);
+bool delete_share_security(const char *servicename);
+bool share_access_check(const NT_USER_TOKEN *token, const char *sharename,
+ uint32 desired_access);
+bool parse_usershare_acl(TALLOC_CTX *ctx, const char *acl_str, SEC_DESC **ppsd);
+
+/* The following definitions come from lib/signal.c */
+
+void BlockSignals(bool block,int signum);
+void (*CatchSignal(int signum,void (*handler)(int )))(int);
+void CatchChild(void);
+void CatchChildLeaveStatus(void);
+
+/* The following definitions come from lib/smbldap.c */
+
+int smb_ldap_start_tls(LDAP *ldap_struct, int version);
+int smb_ldap_setup_conn(LDAP **ldap_struct, const char *uri);
+int smb_ldap_upgrade_conn(LDAP *ldap_struct, int *new_version) ;
+int smb_ldap_setup_full_conn(LDAP **ldap_struct, const char *uri);
+int smbldap_search(struct smbldap_state *ldap_state,
+ const char *base, int scope, const char *filter,
+ const char *attrs[], int attrsonly,
+ LDAPMessage **res);
+int smbldap_search_paged(struct smbldap_state *ldap_state,
+ const char *base, int scope, const char *filter,
+ const char **attrs, int attrsonly, int pagesize,
+ LDAPMessage **res, void **cookie);
+int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[]);
+int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[]);
+int smbldap_delete(struct smbldap_state *ldap_state, const char *dn);
+int smbldap_extended_operation(struct smbldap_state *ldap_state,
+ LDAP_CONST char *reqoid, struct berval *reqdata,
+ LDAPControl **serverctrls, LDAPControl **clientctrls,
+ char **retoidp, struct berval **retdatap);
+int smbldap_search_suffix (struct smbldap_state *ldap_state,
+ const char *filter, const char **search_attr,
+ LDAPMessage ** result);
+void smbldap_free_struct(struct smbldap_state **ldap_state) ;
+NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, struct event_context *event_ctx,
+ const char *location,
+ struct smbldap_state **smbldap_state);
+char *smbldap_get_dn(LDAP *ld, LDAPMessage *entry);
+bool smbldap_has_control(LDAP *ld, const char *control);
+bool smbldap_has_extension(LDAP *ld, const char *extension);
+bool smbldap_has_naming_context(LDAP *ld, const char *naming_context);
+bool smbldap_set_creds(struct smbldap_state *ldap_state, bool anon, const char *dn, const char *secret);
+
+/* The following definitions come from lib/smbldap_util.c */
+
+NTSTATUS smbldap_search_domain_info(struct smbldap_state *ldap_state,
+ LDAPMessage ** result, const char *domain_name,
+ bool try_add);
+
+/* The following definitions come from lib/smbrun.c */
+
+int smbrun_no_sanitize(const char *cmd, int *outfd);
+int smbrun(const char *cmd, int *outfd);
+int smbrunsecret(const char *cmd, const char *secret);
+
+/* The following definitions come from lib/sock_exec.c */
+
+int sock_exec(const char *prog);
+
+/* The following definitions come from lib/substitute.c */
+
+void free_local_machine_name(void);
+bool set_local_machine_name(const char *local_name, bool perm);
+const char *get_local_machine_name(void);
+bool set_remote_machine_name(const char *remote_name, bool perm);
+const char *get_remote_machine_name(void);
+void sub_set_smb_name(const char *name);
+void set_current_user_info(const char *smb_name, const char *unix_name,
+ const char *full_name, const char *domain);
+const char *get_current_username(void);
+void standard_sub_basic(const char *smb_name, const char *domain_name,
+ char *str, size_t len);
+char *talloc_sub_basic(TALLOC_CTX *mem_ctx, const char *smb_name,
+ const char *domain_name, const char *str);
+char *alloc_sub_basic(const char *smb_name, const char *domain_name,
+ const char *str);
+char *talloc_sub_specified(TALLOC_CTX *mem_ctx,
+ const char *input_string,
+ const char *username,
+ const char *domain,
+ uid_t uid,
+ gid_t gid);
+char *talloc_sub_advanced(TALLOC_CTX *mem_ctx,
+ const char *servicename, const char *user,
+ const char *connectpath, gid_t gid,
+ const char *smb_name, const char *domain_name,
+ const char *str);
+void standard_sub_advanced(const char *servicename, const char *user,
+ const char *connectpath, gid_t gid,
+ const char *smb_name, const char *domain_name,
+ char *str, size_t len);
+char *standard_sub_conn(TALLOC_CTX *ctx, connection_struct *conn, const char *str);
+
+/* The following definitions come from lib/sysacls.c */
+
+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p);
+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p);
+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p);
+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d);
+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d);
+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm);
+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm);
+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p);
+SMB_ACL_T sys_acl_init(int count);
+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p);
+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type);
+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p);
+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d);
+int sys_acl_free_text(char *text);
+int sys_acl_free_acl(SMB_ACL_T acl_d) ;
+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype);
+int sys_acl_valid(SMB_ACL_T acl_d);
+SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p, SMB_ACL_TYPE_T type);
+SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp);
+int sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d);
+int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_ACL_T acl_d);
+int sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path);
+SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p, SMB_ACL_TYPE_T type);
+SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp);
+int sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d);
+int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_ACL_T acl_d);
+int sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path);
+SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p, SMB_ACL_TYPE_T type);
+SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp);
+int sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d);
+int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_ACL_T acl_d);
+int sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path);
+SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p, SMB_ACL_TYPE_T type);
+SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp);
+int sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d);
+int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_ACL_T acl_d);
+int sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path);
+SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p, SMB_ACL_TYPE_T type);
+SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp);
+int sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d);
+int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_ACL_T acl_d);
+int sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path);
+SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p, SMB_ACL_TYPE_T type);
+SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp);
+int sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d);
+int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_ACL_T acl_d);
+int sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path);
+SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p, SMB_ACL_TYPE_T type);
+SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp);
+int sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d);
+int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_ACL_T acl_d);
+int sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path);
+int no_acl_syscall_error(int err);
+
+/* The following definitions come from lib/sysquotas.c */
+
+int sys_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
+int sys_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
+
+/* The following definitions come from lib/sysquotas_4A.c */
+
+int sys_get_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
+int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
+
+/* The following definitions come from lib/sysquotas_linux.c */
+
+int sys_get_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
+int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
+
+/* The following definitions come from lib/sysquotas_xfs.c */
+
+int sys_get_xfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
+int sys_set_xfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
+
+/* The following definitions come from lib/system.c */
+
+void *sys_memalign( size_t align, size_t size );
+int sys_usleep(long usecs);
+ssize_t sys_read(int fd, void *buf, size_t count);
+ssize_t sys_write(int fd, const void *buf, size_t count);
+ssize_t sys_pread(int fd, void *buf, size_t count, SMB_OFF_T off);
+ssize_t sys_pwrite(int fd, const void *buf, size_t count, SMB_OFF_T off);
+ssize_t sys_send(int s, const void *msg, size_t len, int flags);
+ssize_t sys_sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);
+ssize_t sys_recv(int fd, void *buf, size_t count, int flags);
+ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
+int sys_fcntl_ptr(int fd, int cmd, void *arg);
+int sys_fcntl_long(int fd, int cmd, long arg);
+int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf);
+int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf);
+int sys_lstat(const 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 sys_creat(const char *path, mode_t mode);
+int sys_open(const char *path, int oflag, mode_t mode);
+FILE *sys_fopen(const char *path, const char *type);
+void kernel_flock(int fd, uint32 share_mode);
+SMB_STRUCT_DIR *sys_opendir(const char *name);
+SMB_STRUCT_DIRENT *sys_readdir(SMB_STRUCT_DIR *dirp);
+void sys_seekdir(SMB_STRUCT_DIR *dirp, long offset);
+long sys_telldir(SMB_STRUCT_DIR *dirp);
+void sys_rewinddir(SMB_STRUCT_DIR *dirp);
+int sys_closedir(SMB_STRUCT_DIR *dirp);
+int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev);
+char *sys_realpath(const char *path, char *resolved_path);
+int sys_waitpid(pid_t pid,int *status,int options);
+char *sys_getwd(char *s);
+int sys_symlink(const char *oldpath, const char *newpath);
+int sys_readlink(const char *path, char *buf, size_t bufsiz);
+int sys_link(const char *oldpath, const char *newpath);
+int sys_chown(const char *fname,uid_t uid,gid_t gid);
+int sys_lchown(const char *fname,uid_t uid,gid_t gid);
+int sys_chroot(const char *dname);
+void set_effective_capability(enum smbd_capability capability);
+void drop_effective_capability(enum smbd_capability capability);
+long sys_random(void);
+void sys_srandom(unsigned int seed);
+int groups_max(void);
+int sys_getgroups(int setlen, gid_t *gidset);
+int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset);
+void sys_setpwent(void);
+struct passwd *sys_getpwent(void);
+void sys_endpwent(void);
+struct passwd *sys_getpwnam(const char *name);
+struct passwd *sys_getpwuid(uid_t uid);
+struct group *sys_getgrnam(const char *name);
+struct group *sys_getgrgid(gid_t gid);
+pid_t sys_fork(void);
+pid_t sys_getpid(void);
+int sys_popen(const char *command);
+int sys_pclose(int fd);
+void *sys_dlopen(const char *name, int flags);
+void *sys_dlsym(void *handle, const char *symbol);
+int sys_dlclose (void *handle);
+const char *sys_dlerror(void);
+int sys_dup2(int oldfd, int newfd) ;
+ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size);
+ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size);
+ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size);
+ssize_t sys_listxattr (const char *path, char *list, size_t size);
+ssize_t sys_llistxattr (const char *path, char *list, size_t size);
+ssize_t sys_flistxattr (int filedes, char *list, size_t size);
+int sys_removexattr (const char *path, const char *name);
+int sys_lremovexattr (const char *path, const char *name);
+int sys_fremovexattr (int filedes, const char *name);
+int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags);
+int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags);
+int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags);
+uint32 unix_dev_major(SMB_DEV_T dev);
+uint32 unix_dev_minor(SMB_DEV_T dev);
+int sys_aio_read(SMB_STRUCT_AIOCB *aiocb);
+int sys_aio_write(SMB_STRUCT_AIOCB *aiocb);
+ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb);
+int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb);
+int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb);
+int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb);
+int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout);
+int sys_aio_read(SMB_STRUCT_AIOCB *aiocb);
+int sys_aio_write(SMB_STRUCT_AIOCB *aiocb);
+ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb);
+int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb);
+int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb);
+int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb);
+int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout);
+int sys_getpeereid( int s, uid_t *uid);
+int sys_getnameinfo(const struct sockaddr *psa,
+ socklen_t salen,
+ char *host,
+ size_t hostlen,
+ char *service,
+ size_t servlen,
+ int flags);
+int sys_connect(int fd, const struct sockaddr * addr);
+
+/* The following definitions come from lib/system_smbd.c */
+
+bool getgroups_unix_user(TALLOC_CTX *mem_ctx, const char *user,
+ gid_t primary_gid,
+ gid_t **ret_groups, size_t *p_ngroups);
+
+/* The following definitions come from lib/tallocmsg.c */
+
+void register_msg_pool_usage(struct messaging_context *msg_ctx);
+
+/* The following definitions come from lib/time.c */
+
+time_t get_time_t_max(void);
+void GetTimeOfDay(struct timeval *tval);
+time_t nt_time_to_unix(NTTIME nt);
+void unix_to_nt_time(NTTIME *nt, time_t t);
+bool null_time(time_t t);
+bool null_nttime(NTTIME t);
+bool null_timespec(struct timespec ts);
+void push_dos_date(uint8_t *buf, int offset, time_t unixdate, int zone_offset);
+void push_dos_date2(uint8_t *buf,int offset,time_t unixdate, int zone_offset);
+void push_dos_date3(uint8_t *buf,int offset,time_t unixdate, int zone_offset);
+time_t pull_dos_date(const uint8_t *date_ptr, int zone_offset);
+time_t pull_dos_date2(const uint8_t *date_ptr, int zone_offset);
+time_t pull_dos_date3(const uint8_t *date_ptr, int zone_offset);
+char *http_timestring(time_t t);
+char *timestring(TALLOC_CTX *mem_ctx, time_t t);
+const char *nt_time_string(TALLOC_CTX *mem_ctx, NTTIME nt);
+NTTIME nttime_from_string(const char *s);
+int64_t usec_time_diff(struct timeval *tv1, struct timeval *tv2);
+struct timeval timeval_zero(void);
+bool timeval_is_zero(const struct timeval *tv);
+struct timeval timeval_current(void);
+struct timeval timeval_set(uint32_t secs, uint32_t usecs);
+struct timeval timeval_add(const struct timeval *tv,
+ uint32_t secs, uint32_t usecs);
+struct timeval timeval_sum(const struct timeval *tv1,
+ const struct timeval *tv2);
+struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs);
+int timeval_compare(const struct timeval *tv1, const struct timeval *tv2);
+bool timeval_expired(const struct timeval *tv);
+double timeval_elapsed2(const struct timeval *tv1, const struct timeval *tv2);
+double timeval_elapsed(const struct timeval *tv);
+struct timeval timeval_min(const struct timeval *tv1,
+ const struct timeval *tv2);
+struct timeval timeval_max(const struct timeval *tv1,
+ const struct timeval *tv2);
+struct timeval timeval_until(const struct timeval *tv1,
+ const struct timeval *tv2);
+NTTIME timeval_to_nttime(const struct timeval *tv);
+uint32 convert_time_t_to_uint32(time_t t);
+time_t convert_uint32_to_time_t(uint32 u);
+int get_time_zone(time_t t);
+bool nt_time_is_zero(const NTTIME *nt);
+time_t generalized_to_unix_time(const char *str);
+int get_server_zone_offset(void);
+int set_server_zone_offset(time_t t);
+char *current_timestring(TALLOC_CTX *ctx, bool hires);
+void srv_put_dos_date(char *buf,int offset,time_t unixdate);
+void srv_put_dos_date2(char *buf,int offset, time_t unixdate);
+void srv_put_dos_date3(char *buf,int offset,time_t unixdate);
+void put_long_date_timespec(char *p, struct timespec ts);
+void put_long_date(char *p, time_t t);
+struct timespec get_create_timespec(const SMB_STRUCT_STAT *st,bool fake_dirs);
+struct timespec get_atimespec(const SMB_STRUCT_STAT *pst);
+void set_atimespec(SMB_STRUCT_STAT *pst, struct timespec ts);
+struct timespec get_mtimespec(const SMB_STRUCT_STAT *pst);
+void set_mtimespec(SMB_STRUCT_STAT *pst, struct timespec ts);
+struct timespec get_ctimespec(const SMB_STRUCT_STAT *pst);
+void set_ctimespec(SMB_STRUCT_STAT *pst, struct timespec ts);
+void dos_filetime_timespec(struct timespec *tsp);
+time_t srv_make_unix_date(const void *date_ptr);
+time_t srv_make_unix_date2(const void *date_ptr);
+time_t srv_make_unix_date3(const void *date_ptr);
+time_t convert_timespec_to_time_t(struct timespec ts);
+struct timespec convert_time_t_to_timespec(time_t t);
+struct timespec convert_timeval_to_timespec(const struct timeval tv);
+struct timeval convert_timespec_to_timeval(const struct timespec ts);
+struct timespec timespec_current(void);
+struct timespec timespec_min(const struct timespec *ts1,
+ const struct timespec *ts2);
+int timespec_compare(const struct timespec *ts1, const struct timespec *ts2);
+struct timespec interpret_long_date(const char *p);
+void cli_put_dos_date(struct cli_state *cli, char *buf, int offset, time_t unixdate);
+void cli_put_dos_date2(struct cli_state *cli, char *buf, int offset, time_t unixdate);
+void cli_put_dos_date3(struct cli_state *cli, char *buf, int offset, time_t unixdate);
+time_t cli_make_unix_date(struct cli_state *cli, const void *date_ptr);
+time_t cli_make_unix_date2(struct cli_state *cli, const void *date_ptr);
+time_t cli_make_unix_date3(struct cli_state *cli, const void *date_ptr);
+struct timespec nt_time_to_unix_timespec(NTTIME *nt);
+bool nt_time_equals(const NTTIME *nt1, const NTTIME *nt2);
+void TimeInit(void);
+void get_process_uptime(struct timeval *ret_time);
+time_t nt_time_to_unix_abs(const NTTIME *nt);
+time_t uint64s_nt_time_to_unix_abs(const uint64_t *src);
+void unix_timespec_to_nt_time(NTTIME *nt, struct timespec ts);
+void unix_to_nt_time_abs(NTTIME *nt, time_t t);
+bool null_mtime(time_t mtime);
+const char *time_to_asc(const time_t t);
+const char *display_time(NTTIME nttime);
+bool nt_time_is_set(const NTTIME *nt);
+
+/* The following definitions come from lib/ufc.c */
+
+char *ufc_crypt(const char *key,const char *salt);
+
+/* The following definitions come from lib/username.c */
+
+char *get_user_home_dir(TALLOC_CTX *mem_ctx, const char *user);
+struct passwd *Get_Pwnam_alloc(TALLOC_CTX *mem_ctx, const char *user);
+
+/* The following definitions come from lib/util.c */
+
+bool set_global_myname(const char *myname);
+const char *global_myname(void);
+bool set_global_myworkgroup(const char *myworkgroup);
+const char *lp_workgroup(void);
+bool set_global_scope(const char *scope);
+const char *global_scope(void);
+void gfree_names(void);
+void gfree_all( void );
+const char *my_netbios_names(int i);
+bool set_netbios_aliases(const char **str_array);
+bool init_names(void);
+const char *get_cmdline_auth_info_username(void);
+void set_cmdline_auth_info_username(const char *username);
+const char *get_cmdline_auth_info_password(void);
+void set_cmdline_auth_info_password(const char *password);
+bool set_cmdline_auth_info_signing_state(const char *arg);
+int get_cmdline_auth_info_signing_state(void);
+void set_cmdline_auth_info_use_kerberos(bool b);
+bool get_cmdline_auth_info_use_kerberos(void);
+void set_cmdline_auth_info_use_krb5_ticket(void);
+void set_cmdline_auth_info_smb_encrypt(void);
+void set_cmdline_auth_info_use_machine_account(void);
+bool get_cmdline_auth_info_got_pass(void);
+bool get_cmdline_auth_info_smb_encrypt(void);
+bool get_cmdline_auth_info_use_machine_account(void);
+bool get_cmdline_auth_info_copy(struct user_auth_info *info);
+bool set_cmdline_auth_info_machine_account_creds(void);
+const char *tmpdir(void);
+bool add_gid_to_array_unique(TALLOC_CTX *mem_ctx, gid_t gid,
+ gid_t **gids, size_t *num_gids);
+const char *get_numlist(const char *p, uint32 **num, int *count);
+bool file_exist(const char *fname,SMB_STRUCT_STAT *sbuf);
+bool socket_exist(const char *fname);
+time_t file_modtime(const char *fname);
+bool directory_exist(char *dname,SMB_STRUCT_STAT *st);
+SMB_OFF_T get_file_size(char *file_name);
+char *attrib_string(uint16 mode);
+void show_msg(char *buf);
+void smb_set_enclen(char *buf,int len,uint16 enc_ctx_num);
+void smb_setlen(char *buf,int len);
+int set_message_bcc(char *buf,int num_bytes);
+ssize_t message_push_blob(uint8 **outbuf, DATA_BLOB blob);
+char *unix_clean_name(TALLOC_CTX *ctx, const char *s);
+char *clean_name(TALLOC_CTX *ctx, const char *s);
+void close_low_fds(bool stderr_too);
+ssize_t write_data_at_offset(int fd, const char *buffer, size_t N, SMB_OFF_T pos);
+int set_blocking(int fd, bool set);
+void smb_msleep(unsigned int t);
+void become_daemon(bool Fork, bool no_process_group);
+bool reinit_after_fork(struct messaging_context *msg_ctx,
+ bool parent_longlived);
+bool yesno(const char *p);
+void *malloc_(size_t size);
+void *malloc_array(size_t el_size, unsigned int count);
+void *memalign_array(size_t el_size, size_t align, unsigned int count);
+void *calloc_array(size_t size, size_t nmemb);
+void *Realloc(void *p, size_t size, bool free_old_on_error);
+void *realloc_array(void *p, size_t el_size, unsigned int count, bool free_old_on_error);
+void add_to_large_array(TALLOC_CTX *mem_ctx, size_t element_size,
+ void *element, void *_array, uint32 *num_elements,
+ ssize_t *array_size);
+void safe_free(void *p);
+char *get_myname(TALLOC_CTX *ctx);
+char *get_mydnsdomname(TALLOC_CTX *ctx);
+int interpret_protocol(const char *str,int def);
+char *automount_lookup(TALLOC_CTX *ctx, const char *user_name);
+char *automount_lookup(TALLOC_CTX *ctx, const char *user_name);
+bool process_exists(const struct server_id pid);
+bool process_exists_by_pid(pid_t pid);
+const char *uidtoname(uid_t uid);
+char *gidtoname(gid_t gid);
+uid_t nametouid(const char *name);
+gid_t nametogid(const char *name);
+void smb_panic(const char *const why);
+void log_stack_trace(void);
+const char *readdirname(SMB_STRUCT_DIR *p);
+bool is_in_path(const char *name, name_compare_entry *namelist, bool case_sensitive);
+void set_namearray(name_compare_entry **ppname_array, const 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 fcntl_getlock(int fd, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid);
+bool is_myname(const char *s);
+bool is_myworkgroup(const char *s);
+void ra_lanman_string( const char *native_lanman );
+const char *get_remote_arch_str(void);
+void set_remote_arch(enum remote_arch_types type);
+enum remote_arch_types get_remote_arch(void);
+void print_asc(int level, const unsigned char *buf,int len);
+void dump_data(int level, const unsigned char *buf1,int len);
+void dump_data_pw(const char *msg, const uchar * data, size_t len);
+const char *tab_depth(int level, int depth);
+int str_checksum(const char *s);
+void zero_free(void *p, size_t size);
+int set_maxfiles(int requested_max);
+int smb_mkstemp(char *name_template);
+void *smb_xmalloc_array(size_t size, unsigned int count);
+void *smb_xmemdup(const void *p, size_t size);
+char *smb_xstrdup(const char *s);
+char *smb_xstrndup(const char *s, size_t n);
+void *memdup(const void *p, size_t size);
+char *myhostname(void);
+char *lock_path(const char *name);
+char *pid_path(const char *name);
+char *lib_path(const char *name);
+char *modules_path(const char *name);
+char *data_path(const char *name);
+char *state_path(const char *name);
+const char *shlib_ext(void);
+char *parent_dirname(const char *path);
+bool parent_dirname_talloc(TALLOC_CTX *mem_ctx, const char *dir,
+ char **parent, const char **name);
+bool ms_has_wild(const char *s);
+bool ms_has_wild_w(const smb_ucs2_t *s);
+bool mask_match(const char *string, const char *pattern, bool is_case_sensitive);
+bool mask_match_search(const char *string, const char *pattern, bool is_case_sensitive);
+bool mask_match_list(const char *string, char **list, int listLen, bool is_case_sensitive);
+bool unix_wild_match(const char *pattern, const char *string);
+bool name_to_fqdn(fstring fqdn, const char *name);
+void *talloc_check_name_abort(const void *ptr, const char *name);
+void *talloc_append_blob(TALLOC_CTX *mem_ctx, void *buf, DATA_BLOB blob);
+uint32 map_share_mode_to_deny_mode(uint32 share_access, uint32 private_options);
+pid_t procid_to_pid(const struct server_id *proc);
+void set_my_vnn(uint32 vnn);
+uint32 get_my_vnn(void);
+struct server_id pid_to_procid(pid_t pid);
+struct server_id procid_self(void);
+struct server_id server_id_self(void);
+bool procid_equal(const struct server_id *p1, const struct server_id *p2);
+bool cluster_id_equal(const struct server_id *id1,
+ const struct server_id *id2);
+bool procid_is_me(const struct server_id *pid);
+struct server_id interpret_pid(const char *pid_string);
+char *procid_str(TALLOC_CTX *mem_ctx, const struct server_id *pid);
+char *procid_str_static(const struct server_id *pid);
+bool procid_valid(const struct server_id *pid);
+bool procid_is_local(const struct server_id *pid);
+int this_is_smp(void);
+bool is_offset_safe(const char *buf_base, size_t buf_len, char *ptr, size_t off);
+char *get_safe_ptr(const char *buf_base, size_t buf_len, char *ptr, size_t off);
+char *get_safe_str_ptr(const char *buf_base, size_t buf_len, char *ptr, size_t off);
+int get_safe_SVAL(const char *buf_base, size_t buf_len, char *ptr, size_t off, int failval);
+int get_safe_IVAL(const char *buf_base, size_t buf_len, char *ptr, size_t off, int failval);
+void split_domain_user(TALLOC_CTX *mem_ctx,
+ const char *full_name,
+ char **domain,
+ char **user);
+void *_talloc_zero_zeronull(const void *ctx, size_t size, const char *name);
+void *_talloc_memdup_zeronull(const void *t, const void *p, size_t size, const char *name);
+void *_talloc_array_zeronull(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *_talloc_zero_array_zeronull(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *talloc_zeronull(const void *context, size_t size, const char *name);
+NTSTATUS split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname,
+ char **pbase, char **pstream);
+bool is_valid_policy_hnd(const POLICY_HND *hnd);
+bool policy_hnd_equal(const struct policy_handle *hnd1,
+ const struct policy_handle *hnd2);
+const char *strip_hostname(const char *s);
+
+/* The following definitions come from lib/util_file.c */
+
+char *fgets_slash(char *s2,int maxlen,XFILE *f);
+char *fd_load(int fd, size_t *psize, size_t maxsize);
+char *file_load(const char *fname, size_t *size, size_t maxsize);
+bool unmap_file(void* start, size_t size);
+void *map_file(char *fname, size_t size);
+char **file_lines_load(const char *fname, int *numlines, size_t maxsize);
+char **fd_lines_load(int fd, int *numlines, size_t maxsize);
+char **file_lines_pload(char *syscmd, int *numlines);
+void file_lines_free(char **lines);
+void file_lines_slashcont(char **lines);
+bool file_save(const char *fname, void *packet, size_t length);
+
+/* The following definitions come from lib/util_nscd.c */
+
+void smb_nscd_flush_user_cache(void);
+void smb_nscd_flush_group_cache(void);
+
+/* The following definitions come from lib/util_nttoken.c */
+
+NT_USER_TOKEN *dup_nt_token(TALLOC_CTX *mem_ctx, const NT_USER_TOKEN *ptoken);
+NTSTATUS merge_nt_token(TALLOC_CTX *mem_ctx,
+ const struct nt_user_token *token_1,
+ const struct nt_user_token *token_2,
+ struct nt_user_token **token_out);
+
+/* The following definitions come from lib/util_pw.c */
+
+struct passwd *tcopy_passwd(TALLOC_CTX *mem_ctx, const struct passwd *from) ;
+void flush_pwnam_cache(void);
+struct passwd *getpwnam_alloc(TALLOC_CTX *mem_ctx, const char *name);
+struct passwd *getpwuid_alloc(TALLOC_CTX *mem_ctx, uid_t uid) ;
+
+/* The following definitions come from lib/util_reg.c */
+
+const char *reg_type_lookup(enum winreg_Type type);
+WERROR reg_pull_multi_sz(TALLOC_CTX *mem_ctx, const void *buf, size_t len,
+ uint32 *num_values, char ***values);
+
+/* The following definitions come from lib/util_reg_api.c */
+
+WERROR registry_pull_value(TALLOC_CTX *mem_ctx,
+ struct registry_value **pvalue,
+ enum winreg_Type type, uint8 *data,
+ uint32 size, uint32 length);
+WERROR registry_push_value(TALLOC_CTX *mem_ctx,
+ const struct registry_value *value,
+ DATA_BLOB *presult);
+
+/* The following definitions come from lib/util_seaccess.c */
+
+void se_map_generic(uint32 *access_mask, const struct generic_mapping *mapping);
+void se_map_standard(uint32 *access_mask, struct standard_mapping *mapping);
+bool se_access_check(const SEC_DESC *sd, const NT_USER_TOKEN *token,
+ uint32 acc_desired, uint32 *acc_granted,
+ NTSTATUS *status);
+NTSTATUS samr_make_sam_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd_size);
+
+/* The following definitions come from lib/util_sec.c */
+
+void sec_init(void);
+uid_t sec_initial_uid(void);
+gid_t sec_initial_gid(void);
+bool non_root_mode(void);
+void gain_root_privilege(void);
+void gain_root_group_privilege(void);
+void set_effective_uid(uid_t uid);
+void set_effective_gid(gid_t gid);
+void save_re_uid(void);
+void restore_re_uid_fromroot(void);
+void restore_re_uid(void);
+void save_re_gid(void);
+void restore_re_gid(void);
+int set_re_uid(void);
+void become_user_permanently(uid_t uid, gid_t gid);
+bool is_setuid_root(void) ;
+
+/* The following definitions come from lib/util_sid.c */
+
+const char *sid_type_lookup(uint32 sid_type) ;
+NT_USER_TOKEN *get_system_token(void) ;
+const char *get_global_sam_name(void) ;
+char *sid_to_fstring(fstring sidstr_out, const DOM_SID *sid);
+char *sid_string_talloc(TALLOC_CTX *mem_ctx, const DOM_SID *sid);
+char *sid_string_dbg(const DOM_SID *sid);
+char *sid_string_tos(const DOM_SID *sid);
+bool string_to_sid(DOM_SID *sidout, const char *sidstr);
+DOM_SID *string_sid_talloc(TALLOC_CTX *mem_ctx, const char *sidstr);
+bool sid_append_rid(DOM_SID *sid, uint32 rid);
+bool sid_compose(DOM_SID *dst, const DOM_SID *domain_sid, uint32 rid);
+bool sid_split_rid(DOM_SID *sid, uint32 *rid);
+bool sid_peek_rid(const DOM_SID *sid, uint32 *rid);
+bool sid_peek_check_rid(const DOM_SID *exp_dom_sid, const DOM_SID *sid, uint32 *rid);
+void sid_copy(DOM_SID *dst, const DOM_SID *src);
+bool sid_linearize(char *outbuf, size_t len, const DOM_SID *sid);
+bool sid_parse(const char *inbuf, size_t len, DOM_SID *sid);
+int sid_compare(const DOM_SID *sid1, const DOM_SID *sid2);
+int sid_compare_domain(const DOM_SID *sid1, const DOM_SID *sid2);
+bool sid_equal(const DOM_SID *sid1, const DOM_SID *sid2);
+bool non_mappable_sid(DOM_SID *sid);
+char *sid_binstring(const DOM_SID *sid);
+char *sid_binstring_hex(const DOM_SID *sid);
+DOM_SID *sid_dup_talloc(TALLOC_CTX *ctx, const DOM_SID *src);
+NTSTATUS add_sid_to_array(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ DOM_SID **sids, size_t *num);
+NTSTATUS add_sid_to_array_unique(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ DOM_SID **sids, size_t *num_sids);
+void del_sid_from_array(const DOM_SID *sid, DOM_SID **sids, size_t *num);
+bool add_rid_to_array_unique(TALLOC_CTX *mem_ctx,
+ uint32 rid, uint32 **pp_rids, size_t *p_num);
+bool is_null_sid(const DOM_SID *sid);
+NTSTATUS sid_array_from_info3(TALLOC_CTX *mem_ctx,
+ const struct netr_SamInfo3 *info3,
+ DOM_SID **user_sids,
+ size_t *num_user_sids,
+ bool include_user_group_rid,
+ bool skip_ressource_groups);
+
+/* The following definitions come from lib/util_sock.c */
+
+bool is_ipaddress_v4(const char *str);
+bool is_ipaddress(const char *str);
+bool is_broadcast_addr(const struct sockaddr_storage *pss);
+uint32 interpret_addr(const char *str);
+struct in_addr *interpret_addr2(struct in_addr *ip, const char *str);
+bool interpret_string_addr(struct sockaddr_storage *pss,
+ const char *str,
+ int flags);
+bool is_loopback_ip_v4(struct in_addr ip);
+bool is_loopback_addr(const struct sockaddr_storage *pss);
+bool is_zero_ip_v4(struct in_addr ip);
+bool is_zero_addr(const struct sockaddr_storage *pss);
+void zero_ip_v4(struct in_addr *ip);
+void zero_addr(struct sockaddr_storage *pss);
+bool same_net_v4(struct in_addr ip1,struct in_addr ip2,struct in_addr mask);
+void in_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
+ struct in_addr ip);
+bool same_net(const struct sockaddr_storage *ip1,
+ const struct sockaddr_storage *ip2,
+ const struct sockaddr_storage *mask);
+bool addr_equal(const struct sockaddr_storage *ip1,
+ const struct sockaddr_storage *ip2);
+bool is_address_any(const struct sockaddr_storage *psa);
+uint16_t get_sockaddr_port(const struct sockaddr_storage *pss);
+char *print_sockaddr(char *dest,
+ size_t destlen,
+ const struct sockaddr_storage *psa);
+char *print_canonical_sockaddr(TALLOC_CTX *ctx,
+ const struct sockaddr_storage *pss);
+void set_sockaddr_port(struct sockaddr_storage *psa, uint16 port);
+const char *client_name(int fd);
+const char *client_addr(int fd, char *addr, size_t addrlen);
+const char *client_socket_addr(int fd, char *addr, size_t addr_len);
+int client_socket_port(int fd);
+void set_smb_read_error(enum smb_read_errors *pre,
+ enum smb_read_errors newerr);
+void cond_set_smb_read_error(enum smb_read_errors *pre,
+ enum smb_read_errors newerr);
+bool is_a_socket(int fd);
+void set_socket_options(int fd, const char *options);
+ssize_t read_udp_v4_socket(int fd,
+ char *buf,
+ size_t len,
+ struct sockaddr_storage *psa);
+NTSTATUS read_socket_with_timeout(int fd, char *buf,
+ size_t mincnt, size_t maxcnt,
+ unsigned int time_out,
+ size_t *size_ret);
+NTSTATUS read_data(int fd, char *buffer, size_t N);
+ssize_t write_data(int fd, const char *buffer, size_t N);
+bool send_keepalive(int client);
+NTSTATUS read_smb_length_return_keepalive(int fd, char *inbuf,
+ unsigned int timeout,
+ size_t *len);
+NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
+ size_t *len);
+NTSTATUS receive_smb_raw(int fd,
+ char *buffer,
+ size_t buflen,
+ unsigned int timeout,
+ size_t maxlen,
+ size_t *p_len);
+int open_socket_in(int type,
+ uint16_t port,
+ int dlevel,
+ const struct sockaddr_storage *psock,
+ bool rebind);
+int open_socket_out(int type,
+ const struct sockaddr_storage *pss,
+ uint16_t port,
+ int timeout);
+bool open_any_socket_out(struct sockaddr_storage *addrs, int num_addrs,
+ int timeout, int *fd_index, int *fd);
+int open_udp_socket(const char *host, int port);
+const char *get_peer_name(int fd, bool force_lookup);
+const char *get_peer_addr(int fd, char *addr, size_t addr_len);
+int create_pipe_sock(const char *socket_dir,
+ const char *socket_name,
+ mode_t dir_perms);
+const char *get_mydnsfullname(void);
+bool is_myname_or_ipaddr(const char *s);
+
+/* The following definitions come from lib/util_str.c */
+
+bool next_token(const char **ptr, char *buff, const char *sep, size_t bufsize);
+bool next_token_talloc(TALLOC_CTX *ctx,
+ const char **ptr,
+ char **pp_buff,
+ const char *sep);
+bool next_token_no_ltrim_talloc(TALLOC_CTX *ctx,
+ const char **ptr,
+ char **pp_buff,
+ const char *sep);
+int StrCaseCmp(const char *s, const char *t);
+int StrnCaseCmp(const char *s, const char *t, size_t len);
+bool strequal(const char *s1, const char *s2);
+bool strnequal(const char *s1,const char *s2,size_t n);
+bool strcsequal(const char *s1,const char *s2);
+int strwicmp(const char *psz1, const char *psz2);
+void strnorm(char *s, int case_default);
+bool strisnormal(const char *s, int case_default);
+void string_replace( char *s, char oldc, char newc );
+char *push_skip_string(char *buf);
+char *skip_string(const char *base, size_t len, char *buf);
+size_t str_charnum(const char *s);
+size_t str_ascii_charnum(const char *s);
+bool trim_char(char *s,char cfront,char cback);
+bool trim_string(char *s,const char *front,const char *back);
+bool strhasupper(const char *s);
+bool strhaslower(const char *s);
+size_t count_chars(const char *s,char c);
+char *safe_strcpy_fn(const char *fn,
+ int line,
+ char *dest,
+ const char *src,
+ size_t maxlength);
+char *safe_strcat_fn(const char *fn,
+ int line,
+ char *dest,
+ const char *src,
+ size_t maxlength);
+char *alpha_strcpy_fn(const char *fn,
+ int line,
+ char *dest,
+ const char *src,
+ const char *other_safe_chars,
+ size_t maxlength);
+char *StrnCpy_fn(const char *fn, int line,char *dest,const char *src,size_t n);
+size_t strhex_to_str(char *buf, size_t buf_len, const char *strhex, size_t strhex_len);
+DATA_BLOB strhex_to_data_blob(TALLOC_CTX *mem_ctx, const char *strhex);
+char *hex_encode(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len);
+bool in_list(const char *s, const char *list, bool casesensitive);
+void string_free(char **s);
+bool string_set(char **dest,const char *src);
+void string_sub2(char *s,const char *pattern, const char *insert, size_t len,
+ bool remove_unsafe_characters, bool replace_once,
+ bool allow_trailing_dollar);
+void string_sub_once(char *s, const char *pattern,
+ const char *insert, size_t len);
+void string_sub(char *s,const char *pattern, const char *insert, size_t len);
+void fstring_sub(char *s,const char *pattern,const char *insert);
+char *realloc_string_sub2(char *string,
+ const char *pattern,
+ const char *insert,
+ bool remove_unsafe_characters,
+ bool allow_trailing_dollar);
+char *realloc_string_sub(char *string,
+ const char *pattern,
+ const char *insert);
+char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
+ const char *pattern,
+ const char *insert,
+ bool remove_unsafe_characters,
+ bool replace_once,
+ bool allow_trailing_dollar);
+char *talloc_string_sub(TALLOC_CTX *mem_ctx,
+ const char *src,
+ const char *pattern,
+ const char *insert);
+void all_string_sub(char *s,const char *pattern,const char *insert, size_t len);
+char *talloc_all_string_sub(TALLOC_CTX *ctx,
+ const char *src,
+ const char *pattern,
+ const char *insert);
+char *octal_string(int i);
+char *string_truncate(char *s, unsigned int length);
+char *strchr_m(const char *src, char c);
+char *strrchr_m(const char *s, char c);
+char *strnrchr_m(const char *s, char c, unsigned int n);
+char *strstr_m(const char *src, const char *findstr);
+void strlower_m(char *s);
+void strupper_m(char *s);
+size_t strlen_m(const char *s);
+size_t strlen_m_term(const char *s);
+size_t strlen_m_term_null(const char *s);
+char *binary_string_rfc2254(char *buf, int len);
+char *binary_string(char *buf, int len);
+int fstr_sprintf(fstring s, const char *fmt, ...);
+char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const char *sep);
+bool str_list_copy(TALLOC_CTX *mem_ctx, char ***dest, const char **src);
+bool str_list_compare(char **list1, char **list2);
+int str_list_count( const char **list );
+bool str_list_sub_basic( char **list, const char *smb_name,
+ const char *domain_name );
+bool str_list_substitute(char **list, const char *pattern, const char *insert);
+char *ipstr_list_make(char **ipstr_list,
+ const struct ip_service *ip_list,
+ int ip_count);
+int ipstr_list_parse(const char *ipstr_list, struct ip_service **ip_list);
+void ipstr_list_free(char* ipstr_list);
+void rfc1738_unescape(char *buf);
+DATA_BLOB base64_decode_data_blob(const char *s);
+void base64_decode_inplace(char *s);
+char *base64_encode_data_blob(TALLOC_CTX *mem_ctx, DATA_BLOB data);
+SMB_BIG_UINT STR_TO_SMB_BIG_UINT(const char *nptr, const char **entptr);
+SMB_OFF_T conv_str_size(const char * str);
+void string_append(char **left, const char *right);
+bool add_string_to_array(TALLOC_CTX *mem_ctx,
+ const char *str, const char ***strings,
+ int *num);
+void sprintf_append(TALLOC_CTX *mem_ctx, char **string, ssize_t *len,
+ size_t *bufsize, const char *fmt, ...);
+int asprintf_strupper_m(char **strp, const char *fmt, ...);
+char *talloc_asprintf_strupper_m(TALLOC_CTX *t, const char *fmt, ...);
+char *talloc_asprintf_strlower_m(TALLOC_CTX *t, const char *fmt, ...);
+char *sstring_sub(const char *src, char front, char back);
+bool validate_net_name( const char *name,
+ const char *invalid_chars,
+ int max_len);
+size_t ascii_len_n(const char *src, size_t n);
+size_t utf16_len(const void *buf);
+size_t utf16_len_n(const void *src, size_t n);
+char *escape_shell_string(const char *src);
+
+/* The following definitions come from lib/util_unistr.c */
+
+void gfree_case_tables(void);
+void load_case_tables(void);
+void init_valid_table(void);
+size_t dos_PutUniCode(char *dst,const char *src, size_t len, bool null_terminate);
+char *skip_unibuf(char *src, size_t len);
+int rpcstr_pull(char* dest, void *src, int dest_len, int src_len, int flags);
+int rpcstr_pull_talloc(TALLOC_CTX *ctx,
+ char **dest,
+ void *src,
+ int src_len,
+ int flags);
+int rpcstr_pull_unistr2_fstring(char *dest, UNISTR2 *src);
+char *rpcstr_pull_unistr2_talloc(TALLOC_CTX *ctx, const UNISTR2 *src);
+int rpcstr_push(void *dest, const char *src, size_t dest_len, int flags);
+int rpcstr_push_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src);
+void unistr2_to_ascii(char *dest, const UNISTR2 *str, size_t maxlen);
+void unistr3_to_ascii(char *dest, const UNISTR3 *str, size_t maxlen);
+char *unistr2_to_ascii_talloc(TALLOC_CTX *ctx, const UNISTR2 *str);
+const char *unistr2_static(const UNISTR2 *str);
+smb_ucs2_t toupper_w(smb_ucs2_t val);
+smb_ucs2_t tolower_w( smb_ucs2_t val );
+bool islower_w(smb_ucs2_t c);
+bool isupper_w(smb_ucs2_t c);
+bool isvalid83_w(smb_ucs2_t c);
+size_t strlen_w(const smb_ucs2_t *src);
+size_t strnlen_w(const smb_ucs2_t *src, size_t max);
+smb_ucs2_t *strchr_w(const smb_ucs2_t *s, smb_ucs2_t c);
+smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c);
+smb_ucs2_t *strrchr_w(const smb_ucs2_t *s, smb_ucs2_t c);
+smb_ucs2_t *strnrchr_w(const smb_ucs2_t *s, smb_ucs2_t c, unsigned int n);
+smb_ucs2_t *strstr_w(const smb_ucs2_t *s, const smb_ucs2_t *ins);
+bool strlower_w(smb_ucs2_t *s);
+bool strupper_w(smb_ucs2_t *s);
+void strnorm_w(smb_ucs2_t *s, int case_default);
+int strcmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b);
+int strncmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len);
+int strcasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b);
+int strncasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len);
+bool strequal_w(const smb_ucs2_t *s1, const smb_ucs2_t *s2);
+bool strnequal_w(const smb_ucs2_t *s1,const smb_ucs2_t *s2,size_t n);
+smb_ucs2_t *strdup_w(const smb_ucs2_t *src);
+smb_ucs2_t *strndup_w(const smb_ucs2_t *src, size_t len);
+smb_ucs2_t *strncpy_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max);
+smb_ucs2_t *strncat_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max);
+smb_ucs2_t *strcat_w(smb_ucs2_t *dest, const smb_ucs2_t *src);
+void string_replace_w(smb_ucs2_t *s, smb_ucs2_t oldc, smb_ucs2_t newc);
+bool trim_string_w(smb_ucs2_t *s, const smb_ucs2_t *front,
+ const smb_ucs2_t *back);
+int strcmp_wa(const smb_ucs2_t *a, const char *b);
+int strncmp_wa(const smb_ucs2_t *a, const char *b, size_t len);
+smb_ucs2_t *strpbrk_wa(const smb_ucs2_t *s, const char *p);
+smb_ucs2_t *strstr_wa(const smb_ucs2_t *s, const char *ins);
+int unistrlen(uint16 *s);
+int unistrcpy(uint16 *dst, uint16 *src);
+UNISTR2* ucs2_to_unistr2(TALLOC_CTX *ctx, UNISTR2* dst, smb_ucs2_t* src);
+int toupper_ascii(int c);
+int tolower_ascii(int c);
+int isupper_ascii(int c);
+int islower_ascii(int c);
+
+/* The following definitions come from lib/util_uuid.c */
+
+void smb_uuid_pack(const struct GUID uu, UUID_FLAT *ptr);
+void smb_uuid_unpack(const UUID_FLAT in, struct GUID *uu);
+void smb_uuid_generate_random(struct GUID *uu);
+const char *smb_uuid_string(TALLOC_CTX *mem_ctx, const struct GUID uu);
+bool smb_string_to_uuid(const char *in, struct GUID* uu);
+char *guid_binstring(const struct GUID *guid);
+
+/* The following definitions come from lib/version.c */
+
+const char *samba_version_string(void);
+
+/* The following definitions come from lib/winbind_util.c */
+
+bool winbind_lookup_name(const char *dom_name, const char *name, DOM_SID *sid,
+ enum lsa_SidType *name_type);
+bool winbind_lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ const char **domain, const char **name,
+ enum lsa_SidType *name_type);
+bool winbind_ping(void);
+bool winbind_sid_to_uid(uid_t *puid, const DOM_SID *sid);
+bool winbind_uid_to_sid(DOM_SID *sid, uid_t uid);
+bool winbind_sid_to_gid(gid_t *pgid, const DOM_SID *sid);
+bool winbind_gid_to_sid(DOM_SID *sid, gid_t gid);
+wbcErr wb_is_trusted_domain(const char *domain);
+bool winbind_lookup_rids(TALLOC_CTX *mem_ctx,
+ const DOM_SID *domain_sid,
+ int num_rids, uint32 *rids,
+ const char **domain_name,
+ const char ***names, enum lsa_SidType **types);
+bool winbind_allocate_uid(uid_t *uid);
+bool winbind_allocate_gid(gid_t *gid);
+bool winbind_lookup_name(const char *dom_name, const char *name, DOM_SID *sid,
+ enum lsa_SidType *name_type);
+bool winbind_lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ const char **domain, const char **name,
+ enum lsa_SidType *name_type);
+bool winbind_ping(void);
+bool winbind_sid_to_uid(uid_t *puid, const DOM_SID *sid);
+bool winbind_uid_to_sid(DOM_SID *sid, uid_t uid);
+bool winbind_sid_to_gid(gid_t *pgid, const DOM_SID *sid);
+bool winbind_gid_to_sid(DOM_SID *sid, gid_t gid);
+wbcErr wb_is_trusted_domain(const char *domain);
+bool winbind_lookup_rids(TALLOC_CTX *mem_ctx,
+ const DOM_SID *domain_sid,
+ int num_rids, uint32 *rids,
+ const char **domain_name,
+ const char ***names, enum lsa_SidType **types);
+bool winbind_allocate_uid(uid_t *uid);
+bool winbind_allocate_gid(gid_t *gid);
+
+/* The following definitions come from lib/wins_srv.c */
+
+bool wins_srv_is_dead(struct in_addr wins_ip, struct in_addr src_ip);
+void wins_srv_alive(struct in_addr wins_ip, struct in_addr src_ip);
+void wins_srv_died(struct in_addr wins_ip, struct in_addr src_ip);
+unsigned wins_srv_count(void);
+char **wins_srv_tags(void);
+void wins_srv_tags_free(char **list);
+struct in_addr wins_srv_ip_tag(const char *tag, struct in_addr src_ip);
+unsigned wins_srv_count_tag(const char *tag);
+
+/* The following definitions come from lib/xfile.c */
+
+int x_setvbuf(XFILE *f, char *buf, int mode, size_t size);
+XFILE *x_fopen(const char *fname, int flags, mode_t mode);
+XFILE *x_fdup(const XFILE *f);
+int x_fclose(XFILE *f);
+size_t x_fwrite(const void *p, size_t size, size_t nmemb, XFILE *f);
+int x_fileno(const XFILE *f);
+int x_fflush(XFILE *f);
+void x_setbuffer(XFILE *f, char *buf, size_t size);
+void x_setbuf(XFILE *f, char *buf);
+void x_setlinebuf(XFILE *f);
+int x_feof(XFILE *f);
+int x_ferror(XFILE *f);
+int x_fgetc(XFILE *f);
+size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f);
+char *x_fgets(char *s, int size, XFILE *stream) ;
+off_t x_tseek(XFILE *f, off_t offset, int whence);
+
+/* The following definitions come from libads/ads_status.c */
+
+ADS_STATUS ads_build_error(enum ads_error_type etype,
+ int rc, int minor_status);
+ADS_STATUS ads_build_nt_error(enum ads_error_type etype,
+ NTSTATUS nt_status);
+NTSTATUS ads_ntstatus(ADS_STATUS status);
+const char *ads_errstr(ADS_STATUS status);
+NTSTATUS gss_err_to_ntstatus(uint32 maj, uint32 min);
+
+/* The following definitions come from libads/ads_struct.c */
+
+char *ads_build_path(const char *realm, const char *sep, const char *field, int reverse);
+char *ads_build_dn(const char *realm);
+char *ads_build_domain(const char *dn);
+ADS_STRUCT *ads_init(const char *realm,
+ const char *workgroup,
+ const char *ldap_server);
+void ads_destroy(ADS_STRUCT **ads);
+
+/* The following definitions come from libads/ads_utils.c */
+
+uint32 ads_acb2uf(uint32 acb);
+uint32 ads_uf2acb(uint32 uf);
+uint32 ads_uf2atype(uint32 uf);
+uint32 ads_gtype2atype(uint32 gtype);
+enum lsa_SidType ads_atype_map(uint32 atype);
+
+/* The following definitions come from libads/authdata.c */
+
+struct PAC_LOGON_INFO *get_logon_info_from_pac(struct PAC_DATA *pac_data);
+NTSTATUS kerberos_return_pac(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const char *pass,
+ time_t time_offset,
+ time_t *expire_time,
+ time_t *renew_till_time,
+ const char *cache_name,
+ bool request_pac,
+ bool add_netbios_addr,
+ time_t renewable_time,
+ struct PAC_DATA **pac_ret);
+NTSTATUS kerberos_return_info3_from_pac(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const char *pass,
+ time_t time_offset,
+ time_t *expire_time,
+ time_t *renew_till_time,
+ const char *cache_name,
+ bool request_pac,
+ bool add_netbios_addr,
+ time_t renewable_time,
+ struct netr_SamInfo3 **info3);
+
+/* The following definitions come from libads/cldap.c */
+
+bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
+ const char *server,
+ const char *realm,
+ uint32_t *nt_version,
+ union nbt_cldap_netlogon **reply);
+bool ads_cldap_netlogon_5(TALLOC_CTX *mem_ctx,
+ const char *server,
+ const char *realm,
+ struct nbt_cldap_netlogon_5 *reply5);
+bool pull_mailslot_cldap_reply(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob,
+ union nbt_cldap_netlogon *r,
+ uint32_t *nt_version);
+
+/* The following definitions come from libads/disp_sec.c */
+
+void ads_disp_sd(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, SEC_DESC *sd);
+
+/* The following definitions come from libads/dns.c */
+
+NTSTATUS ads_dns_lookup_ns(TALLOC_CTX *ctx,
+ const char *dnsdomain,
+ struct dns_rr_ns **nslist,
+ int *numns);
+bool sitename_store(const char *realm, const char *sitename);
+char *sitename_fetch(const char *realm);
+bool stored_sitename_changed(const char *realm, const char *sitename);
+NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx,
+ const char *realm,
+ const char *sitename,
+ struct dns_rr_srv **dclist,
+ int *numdcs );
+NTSTATUS ads_dns_query_gcs(TALLOC_CTX *ctx,
+ const char *realm,
+ const char *sitename,
+ struct dns_rr_srv **dclist,
+ int *numdcs );
+NTSTATUS ads_dns_query_kdcs(TALLOC_CTX *ctx,
+ const char *dns_forest_name,
+ const char *sitename,
+ struct dns_rr_srv **dclist,
+ int *numdcs );
+NTSTATUS ads_dns_query_pdc(TALLOC_CTX *ctx,
+ const char *dns_domain_name,
+ struct dns_rr_srv **dclist,
+ int *numdcs );
+NTSTATUS ads_dns_query_dcs_guid(TALLOC_CTX *ctx,
+ const char *dns_forest_name,
+ const struct GUID *domain_guid,
+ struct dns_rr_srv **dclist,
+ int *numdcs );
+
+/* The following definitions come from libads/kerberos.c */
+
+int kerberos_kinit_password_ext(const char *principal,
+ const char *password,
+ int time_offset,
+ time_t *expire_time,
+ time_t *renew_till_time,
+ const char *cache_name,
+ bool request_pac,
+ bool add_netbios_addr,
+ time_t renewable_time,
+ NTSTATUS *ntstatus);
+int ads_kinit_password(ADS_STRUCT *ads);
+int ads_kdestroy(const char *cc_name);
+char* kerberos_standard_des_salt( void );
+bool kerberos_secrets_store_des_salt( const char* salt );
+char* kerberos_secrets_fetch_des_salt( void );
+char *kerberos_get_default_realm_from_ccache( void );
+bool kerberos_secrets_store_salting_principal(const char *service,
+ int enctype,
+ const char *principal);
+int kerberos_kinit_password(const char *principal,
+ const char *password,
+ int time_offset,
+ const char *cache_name);
+bool create_local_private_krb5_conf_for_domain(const char *realm,
+ const char *domain,
+ const char *sitename,
+ struct sockaddr_storage *pss);
+
+/* The following definitions come from libads/kerberos_keytab.c */
+
+int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc);
+int ads_keytab_flush(ADS_STRUCT *ads);
+int ads_keytab_create_default(ADS_STRUCT *ads);
+int ads_keytab_list(const char *keytab_name);
+
+/* The following definitions come from libads/kerberos_verify.c */
+
+NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
+ const char *realm,
+ time_t time_offset,
+ const DATA_BLOB *ticket,
+ char **principal,
+ struct PAC_DATA **pac_data,
+ DATA_BLOB *ap_rep,
+ DATA_BLOB *session_key,
+ bool use_replay_cache);
+
+/* The following definitions come from libads/krb5_errs.c */
+
+
+/* The following definitions come from libads/krb5_setpw.c */
+
+ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ,
+ const char *newpw, int time_offset);
+ADS_STATUS kerberos_set_password(const char *kpasswd_server,
+ const char *auth_principal, const char *auth_password,
+ const char *target_principal, const char *new_password,
+ int time_offset);
+ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
+ const char *machine_account,
+ const char *password);
+
+/* The following definitions come from libads/ldap.c */
+
+bool ads_sitename_match(ADS_STRUCT *ads);
+bool ads_closest_dc(ADS_STRUCT *ads);
+ADS_STATUS ads_connect(ADS_STRUCT *ads);
+ADS_STATUS ads_connect_user_creds(ADS_STRUCT *ads);
+ADS_STATUS ads_connect_gc(ADS_STRUCT *ads);
+void ads_disconnect(ADS_STRUCT *ads);
+ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path,
+ int scope, const char *expr, const char **attrs,
+ bool (*fn)(ADS_STRUCT *, char *, void **, void *),
+ void *data_area);
+void ads_memfree(ADS_STRUCT *ads, void *mem);
+char *ads_parent_dn(const char *dn);
+ADS_MODLIST ads_init_mods(TALLOC_CTX *ctx);
+ADS_STATUS ads_mod_str(TALLOC_CTX *ctx, ADS_MODLIST *mods,
+ const char *name, const char *val);
+ADS_STATUS ads_mod_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
+ const char *name, const char **vals);
+ADS_STATUS ads_gen_mod(ADS_STRUCT *ads, const char *mod_dn, ADS_MODLIST mods);
+ADS_STATUS ads_gen_add(ADS_STRUCT *ads, const char *new_dn, ADS_MODLIST mods);
+ADS_STATUS ads_del_dn(ADS_STRUCT *ads, char *del_dn);
+char *ads_ou_string(ADS_STRUCT *ads, const char *org_unit);
+char *ads_default_ou_string(ADS_STRUCT *ads, const char *wknguid);
+ADS_STATUS ads_add_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
+ const char *name, const char **vals);
+uint32 ads_get_kvno(ADS_STRUCT *ads, const char *account_name);
+uint32_t ads_get_machine_kvno(ADS_STRUCT *ads, const char *machine_name);
+ADS_STATUS ads_clear_service_principal_names(ADS_STRUCT *ads, const char *machine_name);
+ADS_STATUS ads_add_service_principal_name(ADS_STRUCT *ads, const char *machine_name,
+ const char *my_fqdn, const char *spn);
+ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name,
+ const char *org_unit);
+ADS_STATUS ads_move_machine_acct(ADS_STRUCT *ads, const char *machine_name,
+ const char *org_unit, bool *moved);
+int ads_count_replies(ADS_STRUCT *ads, void *res);
+ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32 *usn);
+ADS_STATUS ads_current_time(ADS_STRUCT *ads);
+ADS_STATUS ads_domain_func_level(ADS_STRUCT *ads, uint32 *val);
+ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, DOM_SID *sid);
+ADS_STATUS ads_site_dn(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char **site_name);
+ADS_STATUS ads_site_dn_for_machine(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char *computer_name, const char **site_dn);
+ADS_STATUS ads_upn_suffixes(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char ***suffixes, size_t *num_suffixes);
+ADS_STATUS ads_get_joinable_ous(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ char ***ous,
+ size_t *num_ous);
+bool ads_get_sid_from_extended_dn(TALLOC_CTX *mem_ctx,
+ const char *extended_dn,
+ enum ads_extended_dn_flags flags,
+ DOM_SID *sid);
+char* ads_get_dnshostname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name );
+char* ads_get_upn( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name );
+char* ads_get_samaccountname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name );
+ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *machine_name,
+ uint32 account_type, const char *org_unit);
+ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname);
+ADS_STATUS ads_find_samaccount(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *samaccountname,
+ uint32 *uac_ret,
+ const char **dn_ret);
+ADS_STATUS ads_config_path(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ char **config_path);
+const char *ads_get_extended_right_name_by_guid(ADS_STRUCT *ads,
+ const char *config_path,
+ TALLOC_CTX *mem_ctx,
+ const struct GUID *rights_guid);
+ADS_STATUS ads_check_ou_dn(TALLOC_CTX *mem_ctx,
+ ADS_STRUCT *ads,
+ const char **account_ou);
+
+/* The following definitions come from libads/ldap_printer.c */
+
+ADS_STATUS ads_mod_printer_entry(ADS_STRUCT *ads, char *prt_dn,
+ TALLOC_CTX *ctx, const ADS_MODLIST *mods);
+ADS_STATUS ads_add_printer_entry(ADS_STRUCT *ads, char *prt_dn,
+ TALLOC_CTX *ctx, ADS_MODLIST *mods);
+WERROR get_remote_printer_publishing_data(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ ADS_MODLIST *mods,
+ const char *printer);
+bool get_local_printer_publishing_data(TALLOC_CTX *mem_ctx,
+ ADS_MODLIST *mods,
+ NT_PRINTER_DATA *data);
+
+/* The following definitions come from libads/ldap_schema.c */
+
+ADS_STATUS ads_get_attrnames_by_oids(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ const char *schema_path,
+ const char **OIDs, size_t num_OIDs,
+ char ***OIDs_out, char ***names, size_t *count);
+const char *ads_get_attrname_by_guid(ADS_STRUCT *ads,
+ const char *schema_path,
+ TALLOC_CTX *mem_ctx,
+ const struct GUID *schema_guid);
+const char *ads_get_attrname_by_oid(ADS_STRUCT *ads, const char *schema_path, TALLOC_CTX *mem_ctx, const char * OID);
+ADS_STATUS ads_schema_path(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char **schema_path);
+ADS_STATUS ads_check_posix_schema_mapping(TALLOC_CTX *mem_ctx,
+ ADS_STRUCT *ads,
+ enum wb_posix_mapping map_type,
+ struct posix_schema **s ) ;
+
+/* The following definitions come from libads/ldap_user.c */
+
+ADS_STATUS ads_add_user_acct(ADS_STRUCT *ads, const char *user,
+ const char *container, const char *fullname);
+ADS_STATUS ads_add_group_acct(ADS_STRUCT *ads, const char *group,
+ const char *container, const char *comment);
+
+/* The following definitions come from libads/ldap_utils.c */
+
+ADS_STATUS ads_ranged_search(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ int scope,
+ const char *base,
+ const char *filter,
+ void *args,
+ const char *range_attr,
+ char ***strings,
+ size_t *num_strings);
+ADS_STATUS ads_ranged_search_internal(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ int scope,
+ const char *base,
+ const char *filter,
+ const char **attrs,
+ void *args,
+ const char *range_attr,
+ char ***strings,
+ size_t *num_strings,
+ uint32 *first_usn,
+ int *num_retries,
+ bool *more_values);
+
+/* The following definitions come from libads/ndr.c */
+
+void ndr_print_ads_auth_flags(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_ads_struct(struct ndr_print *ndr, const char *name, const struct ads_struct *r);
+
+/* The following definitions come from libads/sasl.c */
+
+ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads);
+
+/* The following definitions come from libads/sasl_wrapping.c */
+
+ADS_STATUS ads_setup_sasl_wrapping(ADS_STRUCT *ads,
+ const struct ads_saslwrap_ops *ops,
+ void *private_data);
+ADS_STATUS ads_setup_sasl_wrapping(ADS_STRUCT *ads,
+ const struct ads_saslwrap_ops *ops,
+ void *private_data);
+
+/* The following definitions come from libads/util.c */
+
+ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_principal);
+ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
+ char **returned_principal);
+
+/* The following definitions come from libcli/nbt/nbtname.c */
+
+_PUBLIC_ void ndr_print_nbt_string(struct ndr_print *ndr, const char *name, const char *s);
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_string(struct ndr_pull *ndr, int ndr_flags, const char **s);
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_string(struct ndr_push *ndr, int ndr_flags, const char *s);
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_name(struct ndr_pull *ndr, int ndr_flags, struct nbt_name *r);
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_name(struct ndr_push *ndr, int ndr_flags, const struct nbt_name *r);
+_PUBLIC_ NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx, struct nbt_name *name, struct nbt_name *newname);
+_PUBLIC_ NTSTATUS nbt_name_to_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct nbt_name *name);
+_PUBLIC_ NTSTATUS nbt_name_from_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, struct nbt_name *name);
+_PUBLIC_ void nbt_choose_called_name(TALLOC_CTX *mem_ctx,
+ struct nbt_name *n, const char *name, int type);
+_PUBLIC_ char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name);
+_PUBLIC_ enum ndr_err_code ndr_pull_wrepl_nbt_name(struct ndr_pull *ndr, int ndr_flags, const struct nbt_name **_r);
+_PUBLIC_ enum ndr_err_code ndr_push_wrepl_nbt_name(struct ndr_push *ndr, int ndr_flags, const struct nbt_name *r);
+_PUBLIC_ void ndr_print_wrepl_nbt_name(struct ndr_print *ndr, const char *name, const struct nbt_name *r);
+
+/* The following definitions come from libgpo/gpext/gpext.c */
+
+struct gp_extension *get_gp_extension_list(void);
+NTSTATUS unregister_gp_extension(const char *name);
+NTSTATUS register_gp_extension(TALLOC_CTX *gpext_ctx,
+ int version,
+ const char *name,
+ const char *guid,
+ struct gp_extension_methods *methods);
+NTSTATUS gp_ext_info_add_entry(TALLOC_CTX *mem_ctx,
+ const char *module,
+ const char *ext_guid,
+ struct gp_extension_reg_table *table,
+ struct gp_extension_reg_info *info);
+NTSTATUS shutdown_gp_extensions(void);
+NTSTATUS init_gp_extensions(TALLOC_CTX *mem_ctx);
+NTSTATUS free_gp_extensions(void);
+void debug_gpext_header(int lvl,
+ const char *name,
+ uint32_t flags,
+ struct GROUP_POLICY_OBJECT *gpo,
+ const char *extension_guid,
+ const char *snapin_guid);
+NTSTATUS process_gpo_list_with_extension(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const struct nt_user_token *token,
+ struct GROUP_POLICY_OBJECT *gpo_list,
+ const char *extension_guid,
+ const char *snapin_guid);
+NTSTATUS gpext_process_extension(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const struct nt_user_token *token,
+ struct registry_key *root_key,
+ struct GROUP_POLICY_OBJECT *gpo,
+ const char *extension_guid,
+ const char *snapin_guid);
+
+/* The following definitions come from libgpo/gpo_fetch.c */
+
+NTSTATUS gpo_explode_filesyspath(TALLOC_CTX *mem_ctx,
+ const char *file_sys_path,
+ char **server,
+ char **service,
+ char **nt_path,
+ char **unix_path);
+NTSTATUS gpo_fetch_files(TALLOC_CTX *mem_ctx,
+ struct cli_state *cli,
+ struct GROUP_POLICY_OBJECT *gpo);
+NTSTATUS gpo_get_sysvol_gpt_version(TALLOC_CTX *mem_ctx,
+ const char *unix_path,
+ uint32_t *sysvol_version,
+ char **display_name);
+
+/* The following definitions come from libgpo/gpo_filesync.c */
+
+NTSTATUS gpo_copy_file(TALLOC_CTX *mem_ctx,
+ struct cli_state *cli,
+ const char *nt_path,
+ const char *unix_path);
+NTSTATUS gpo_sync_directories(TALLOC_CTX *mem_ctx,
+ struct cli_state *cli,
+ const char *nt_path,
+ const char *local_path);
+
+/* The following definitions come from libgpo/gpo_ini.c */
+
+NTSTATUS parse_gpt_ini(TALLOC_CTX *mem_ctx,
+ const char *filename,
+ uint32_t *version,
+ char **display_name);
+
+/* The following definitions come from libgpo/gpo_ldap.c */
+
+bool ads_parse_gp_ext(TALLOC_CTX *mem_ctx,
+ const char *extension_raw,
+ struct GP_EXT **gp_ext);
+ADS_STATUS ads_get_gpo_link(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *link_dn,
+ struct GP_LINK *gp_link_struct);
+ADS_STATUS ads_add_gpo_link(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *link_dn,
+ const char *gpo_dn,
+ uint32_t gpo_opt);
+ADS_STATUS ads_delete_gpo_link(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *link_dn,
+ const char *gpo_dn);
+ADS_STATUS ads_get_gpo(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *gpo_dn,
+ const char *display_name,
+ const char *guid_name,
+ struct GROUP_POLICY_OBJECT *gpo);
+ADS_STATUS ads_get_sid_token(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *dn,
+ struct nt_user_token **token);
+ADS_STATUS ads_get_gpo_list(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *dn,
+ uint32_t flags,
+ const struct nt_user_token *token,
+ struct GROUP_POLICY_OBJECT **gpo_list);
+
+/* The following definitions come from libgpo/gpo_reg.c */
+
+struct nt_user_token *registry_create_system_token(TALLOC_CTX *mem_ctx);
+WERROR gp_init_reg_ctx(TALLOC_CTX *mem_ctx,
+ const char *initial_path,
+ uint32_t desired_access,
+ const struct nt_user_token *token,
+ struct gp_registry_context **reg_ctx);
+void gp_free_reg_ctx(struct gp_registry_context *reg_ctx);
+WERROR gp_store_reg_subkey(TALLOC_CTX *mem_ctx,
+ const char *subkeyname,
+ struct registry_key *curr_key,
+ struct registry_key **new_key);
+WERROR gp_read_reg_subkey(TALLOC_CTX *mem_ctx,
+ struct gp_registry_context *reg_ctx,
+ const char *subkeyname,
+ struct registry_key **key);
+WERROR gp_store_reg_val_sz(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ const char *val_name,
+ const char *val);
+WERROR gp_read_reg_val_sz(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ const char *val_name,
+ const char **val);
+WERROR gp_reg_state_store(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const char *dn,
+ const struct nt_user_token *token,
+ struct GROUP_POLICY_OBJECT *gpo_list);
+WERROR gp_reg_state_read(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const DOM_SID *sid,
+ struct GROUP_POLICY_OBJECT **gpo_list);
+WERROR gp_secure_key(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct registry_key *key,
+ const DOM_SID *sid);
+void dump_reg_val(int lvl, const char *direction,
+ const char *key, const char *subkey,
+ struct registry_value *val);
+void dump_reg_entry(uint32_t flags,
+ const char *dir,
+ struct gp_registry_entry *entry);
+void dump_reg_entries(uint32_t flags,
+ const char *dir,
+ struct gp_registry_entry *entries,
+ size_t num_entries);
+bool add_gp_registry_entry_to_array(TALLOC_CTX *mem_ctx,
+ struct gp_registry_entry *entry,
+ struct gp_registry_entry **entries,
+ size_t *num);
+WERROR reg_apply_registry_entry(TALLOC_CTX *mem_ctx,
+ struct registry_key *root_key,
+ struct gp_registry_context *reg_ctx,
+ struct gp_registry_entry *entry,
+ const struct nt_user_token *token,
+ uint32_t flags);
+
+/* The following definitions come from libgpo/gpo_sec.c */
+
+NTSTATUS gpo_apply_security_filtering(const struct GROUP_POLICY_OBJECT *gpo,
+ const struct nt_user_token *token);
+
+/* The following definitions come from libgpo/gpo_util.c */
+
+const char *cse_gpo_guid_string_to_name(const char *guid);
+const char *cse_gpo_name_to_guid_string(const char *name);
+const char *cse_snapin_gpo_guid_string_to_name(const char *guid);
+void dump_gp_ext(struct GP_EXT *gp_ext, int debuglevel);
+void dump_gpo(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ struct GROUP_POLICY_OBJECT *gpo,
+ int debuglevel);
+void dump_gpo_list(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ struct GROUP_POLICY_OBJECT *gpo_list,
+ int debuglevel);
+void dump_gplink(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, struct GP_LINK *gp_link);
+ADS_STATUS gpo_process_a_gpo(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const struct nt_user_token *token,
+ struct registry_key *root_key,
+ struct GROUP_POLICY_OBJECT *gpo,
+ const char *extension_guid_filter,
+ uint32_t flags);
+ADS_STATUS gpo_process_gpo_list(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const struct nt_user_token *token,
+ struct GROUP_POLICY_OBJECT *gpo_list,
+ const char *extensions_guid_filter,
+ uint32_t flags);
+NTSTATUS check_refresh_gpo(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct GROUP_POLICY_OBJECT *gpo,
+ struct cli_state **cli_out);
+NTSTATUS check_refresh_gpo_list(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct GROUP_POLICY_OBJECT *gpo_list);
+NTSTATUS gpo_get_unix_path(TALLOC_CTX *mem_ctx,
+ struct GROUP_POLICY_OBJECT *gpo,
+ char **unix_path);
+char *gpo_flag_str(uint32_t flags);
+NTSTATUS gp_find_file(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const char *filename,
+ const char *suffix,
+ const char **filename_out);
+ADS_STATUS gp_get_machine_token(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *dn,
+ struct nt_user_token **token);
+
+/* The following definitions come from librpc/gen_ndr/ndr_dfs.c */
+
+_PUBLIC_ void ndr_print_dfs_ManagerVersion(struct ndr_print *ndr, const char *name, enum dfs_ManagerVersion r);
+_PUBLIC_ void ndr_print_dfs_Info0(struct ndr_print *ndr, const char *name, const struct dfs_Info0 *r);
+_PUBLIC_ void ndr_print_dfs_Info1(struct ndr_print *ndr, const char *name, const struct dfs_Info1 *r);
+_PUBLIC_ enum ndr_err_code ndr_push_dfs_VolumeState(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+_PUBLIC_ enum ndr_err_code ndr_pull_dfs_VolumeState(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+_PUBLIC_ void ndr_print_dfs_VolumeState(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_dfs_Info2(struct ndr_print *ndr, const char *name, const struct dfs_Info2 *r);
+_PUBLIC_ enum ndr_err_code ndr_push_dfs_StorageState(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+_PUBLIC_ enum ndr_err_code ndr_pull_dfs_StorageState(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+_PUBLIC_ void ndr_print_dfs_StorageState(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_dfs_StorageInfo(struct ndr_print *ndr, const char *name, const struct dfs_StorageInfo *r);
+_PUBLIC_ void ndr_print_dfs_Info3(struct ndr_print *ndr, const char *name, const struct dfs_Info3 *r);
+_PUBLIC_ void ndr_print_dfs_Info4(struct ndr_print *ndr, const char *name, const struct dfs_Info4 *r);
+_PUBLIC_ enum ndr_err_code ndr_push_dfs_PropertyFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+_PUBLIC_ enum ndr_err_code ndr_pull_dfs_PropertyFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+_PUBLIC_ void ndr_print_dfs_PropertyFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_dfs_Info5(struct ndr_print *ndr, const char *name, const struct dfs_Info5 *r);
+_PUBLIC_ void ndr_print_dfs_Target_PriorityClass(struct ndr_print *ndr, const char *name, enum dfs_Target_PriorityClass r);
+_PUBLIC_ void ndr_print_dfs_Target_Priority(struct ndr_print *ndr, const char *name, const struct dfs_Target_Priority *r);
+_PUBLIC_ void ndr_print_dfs_StorageInfo2(struct ndr_print *ndr, const char *name, const struct dfs_StorageInfo2 *r);
+_PUBLIC_ void ndr_print_dfs_Info6(struct ndr_print *ndr, const char *name, const struct dfs_Info6 *r);
+_PUBLIC_ void ndr_print_dfs_Info7(struct ndr_print *ndr, const char *name, const struct dfs_Info7 *r);
+_PUBLIC_ void ndr_print_dfs_Info100(struct ndr_print *ndr, const char *name, const struct dfs_Info100 *r);
+_PUBLIC_ void ndr_print_dfs_Info101(struct ndr_print *ndr, const char *name, const struct dfs_Info101 *r);
+_PUBLIC_ void ndr_print_dfs_Info102(struct ndr_print *ndr, const char *name, const struct dfs_Info102 *r);
+_PUBLIC_ void ndr_print_dfs_Info103(struct ndr_print *ndr, const char *name, const struct dfs_Info103 *r);
+_PUBLIC_ void ndr_print_dfs_Info104(struct ndr_print *ndr, const char *name, const struct dfs_Info104 *r);
+_PUBLIC_ void ndr_print_dfs_Info105(struct ndr_print *ndr, const char *name, const struct dfs_Info105 *r);
+_PUBLIC_ void ndr_print_dfs_Info106(struct ndr_print *ndr, const char *name, const struct dfs_Info106 *r);
+_PUBLIC_ void ndr_print_dfs_Info200(struct ndr_print *ndr, const char *name, const struct dfs_Info200 *r);
+_PUBLIC_ void ndr_print_dfs_VolumeFlavor(struct ndr_print *ndr, const char *name, enum dfs_VolumeFlavor r);
+_PUBLIC_ void ndr_print_dfs_Info300(struct ndr_print *ndr, const char *name, const struct dfs_Info300 *r);
+_PUBLIC_ void ndr_print_dfs_Info(struct ndr_print *ndr, const char *name, const union dfs_Info *r);
+_PUBLIC_ void ndr_print_dfs_EnumArray1(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray1 *r);
+_PUBLIC_ void ndr_print_dfs_EnumArray2(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray2 *r);
+_PUBLIC_ void ndr_print_dfs_EnumArray3(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray3 *r);
+_PUBLIC_ void ndr_print_dfs_EnumArray4(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray4 *r);
+_PUBLIC_ void ndr_print_dfs_EnumArray5(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray5 *r);
+_PUBLIC_ void ndr_print_dfs_EnumArray6(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray6 *r);
+_PUBLIC_ void ndr_print_dfs_EnumArray200(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray200 *r);
+_PUBLIC_ void ndr_print_dfs_EnumArray300(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray300 *r);
+_PUBLIC_ void ndr_print_dfs_EnumInfo(struct ndr_print *ndr, const char *name, const union dfs_EnumInfo *r);
+_PUBLIC_ void ndr_print_dfs_EnumStruct(struct ndr_print *ndr, const char *name, const struct dfs_EnumStruct *r);
+_PUBLIC_ void ndr_print_dfs_UnknownStruct(struct ndr_print *ndr, const char *name, const struct dfs_UnknownStruct *r);
+_PUBLIC_ enum ndr_err_code ndr_push_dfs_GetManagerVersion(struct ndr_push *ndr, int flags, const struct dfs_GetManagerVersion *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_dfs_GetManagerVersion(struct ndr_pull *ndr, int flags, struct dfs_GetManagerVersion *r);
+_PUBLIC_ void ndr_print_dfs_GetManagerVersion(struct ndr_print *ndr, const char *name, int flags, const struct dfs_GetManagerVersion *r);
+_PUBLIC_ void ndr_print_dfs_Add(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Add *r);
+_PUBLIC_ void ndr_print_dfs_Remove(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Remove *r);
+_PUBLIC_ void ndr_print_dfs_SetInfo(struct ndr_print *ndr, const char *name, int flags, const struct dfs_SetInfo *r);
+_PUBLIC_ void ndr_print_dfs_GetInfo(struct ndr_print *ndr, const char *name, int flags, const struct dfs_GetInfo *r);
+_PUBLIC_ void ndr_print_dfs_Enum(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Enum *r);
+_PUBLIC_ void ndr_print_dfs_Rename(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Rename *r);
+_PUBLIC_ void ndr_print_dfs_Move(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Move *r);
+_PUBLIC_ void ndr_print_dfs_ManagerGetConfigInfo(struct ndr_print *ndr, const char *name, int flags, const struct dfs_ManagerGetConfigInfo *r);
+_PUBLIC_ void ndr_print_dfs_ManagerSendSiteInfo(struct ndr_print *ndr, const char *name, int flags, const struct dfs_ManagerSendSiteInfo *r);
+_PUBLIC_ void ndr_print_dfs_AddFtRoot(struct ndr_print *ndr, const char *name, int flags, const struct dfs_AddFtRoot *r);
+_PUBLIC_ void ndr_print_dfs_RemoveFtRoot(struct ndr_print *ndr, const char *name, int flags, const struct dfs_RemoveFtRoot *r);
+_PUBLIC_ void ndr_print_dfs_AddStdRoot(struct ndr_print *ndr, const char *name, int flags, const struct dfs_AddStdRoot *r);
+_PUBLIC_ void ndr_print_dfs_RemoveStdRoot(struct ndr_print *ndr, const char *name, int flags, const struct dfs_RemoveStdRoot *r);
+_PUBLIC_ void ndr_print_dfs_ManagerInitialize(struct ndr_print *ndr, const char *name, int flags, const struct dfs_ManagerInitialize *r);
+_PUBLIC_ void ndr_print_dfs_AddStdRootForced(struct ndr_print *ndr, const char *name, int flags, const struct dfs_AddStdRootForced *r);
+_PUBLIC_ void ndr_print_dfs_GetDcAddress(struct ndr_print *ndr, const char *name, int flags, const struct dfs_GetDcAddress *r);
+_PUBLIC_ void ndr_print_dfs_SetDcAddress(struct ndr_print *ndr, const char *name, int flags, const struct dfs_SetDcAddress *r);
+_PUBLIC_ void ndr_print_dfs_FlushFtTable(struct ndr_print *ndr, const char *name, int flags, const struct dfs_FlushFtTable *r);
+_PUBLIC_ void ndr_print_dfs_Add2(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Add2 *r);
+_PUBLIC_ void ndr_print_dfs_Remove2(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Remove2 *r);
+_PUBLIC_ enum ndr_err_code ndr_push_dfs_EnumEx(struct ndr_push *ndr, int flags, const struct dfs_EnumEx *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_dfs_EnumEx(struct ndr_pull *ndr, int flags, struct dfs_EnumEx *r);
+_PUBLIC_ void ndr_print_dfs_EnumEx(struct ndr_print *ndr, const char *name, int flags, const struct dfs_EnumEx *r);
+_PUBLIC_ void ndr_print_dfs_SetInfo2(struct ndr_print *ndr, const char *name, int flags, const struct dfs_SetInfo2 *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_dssetup.c */
+
+_PUBLIC_ void ndr_print_dssetup_DsRole(struct ndr_print *ndr, const char *name, enum dssetup_DsRole r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_dssetup_DsRolePrimaryDomInfoBasic(struct ndr_print *ndr, const char *name, const struct dssetup_DsRolePrimaryDomInfoBasic *r);
+_PUBLIC_ void ndr_print_dssetup_DsUpgrade(struct ndr_print *ndr, const char *name, enum dssetup_DsUpgrade r);
+_PUBLIC_ void ndr_print_dssetup_DsPrevious(struct ndr_print *ndr, const char *name, enum dssetup_DsPrevious r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleUpgradeStatus(struct ndr_print *ndr, const char *name, const struct dssetup_DsRoleUpgradeStatus *r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleOp(struct ndr_print *ndr, const char *name, enum dssetup_DsRoleOp r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleOpStatus(struct ndr_print *ndr, const char *name, const struct dssetup_DsRoleOpStatus *r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleInfoLevel(struct ndr_print *ndr, const char *name, enum dssetup_DsRoleInfoLevel r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleInfo(struct ndr_print *ndr, const char *name, const union dssetup_DsRoleInfo *r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleGetPrimaryDomainInformation(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleGetPrimaryDomainInformation *r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleDnsNameToFlatName(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleDnsNameToFlatName *r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleDcAsDc(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleDcAsDc *r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleDcAsReplica(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleDcAsReplica *r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleDemoteDc(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleDemoteDc *r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleGetDcOperationProgress(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleGetDcOperationProgress *r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleGetDcOperationResults(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleGetDcOperationResults *r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleCancel(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleCancel *r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleServerSaveStateForUpgrade(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleServerSaveStateForUpgrade *r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleUpgradeDownlevelServer(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleUpgradeDownlevelServer *r);
+_PUBLIC_ void ndr_print_dssetup_DsRoleAbortDownlevelServerUpgrade(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleAbortDownlevelServerUpgrade *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_echo.c */
+
+_PUBLIC_ void ndr_print_echo_info1(struct ndr_print *ndr, const char *name, const struct echo_info1 *r);
+_PUBLIC_ void ndr_print_echo_info2(struct ndr_print *ndr, const char *name, const struct echo_info2 *r);
+_PUBLIC_ void ndr_print_echo_info3(struct ndr_print *ndr, const char *name, const struct echo_info3 *r);
+_PUBLIC_ void ndr_print_STRUCT_echo_info4(struct ndr_print *ndr, const char *name, const struct echo_info4 *r);
+_PUBLIC_ void ndr_print_echo_info5(struct ndr_print *ndr, const char *name, const struct echo_info5 *r);
+_PUBLIC_ void ndr_print_echo_info6(struct ndr_print *ndr, const char *name, const struct echo_info6 *r);
+_PUBLIC_ void ndr_print_echo_info7(struct ndr_print *ndr, const char *name, const struct echo_info7 *r);
+_PUBLIC_ void ndr_print_echo_Info(struct ndr_print *ndr, const char *name, const union echo_Info *r);
+_PUBLIC_ void ndr_print_echo_Enum1(struct ndr_print *ndr, const char *name, enum echo_Enum1 r);
+_PUBLIC_ void ndr_print_echo_Enum1_32(struct ndr_print *ndr, const char *name, enum echo_Enum1_32 r);
+_PUBLIC_ void ndr_print_echo_Enum2(struct ndr_print *ndr, const char *name, const struct echo_Enum2 *r);
+_PUBLIC_ void ndr_print_echo_Enum3(struct ndr_print *ndr, const char *name, const union echo_Enum3 *r);
+_PUBLIC_ void ndr_print_echo_Surrounding(struct ndr_print *ndr, const char *name, const struct echo_Surrounding *r);
+_PUBLIC_ void ndr_print_echo_AddOne(struct ndr_print *ndr, const char *name, int flags, const struct echo_AddOne *r);
+_PUBLIC_ void ndr_print_echo_EchoData(struct ndr_print *ndr, const char *name, int flags, const struct echo_EchoData *r);
+_PUBLIC_ void ndr_print_echo_SinkData(struct ndr_print *ndr, const char *name, int flags, const struct echo_SinkData *r);
+_PUBLIC_ void ndr_print_echo_SourceData(struct ndr_print *ndr, const char *name, int flags, const struct echo_SourceData *r);
+_PUBLIC_ void ndr_print_echo_TestCall(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestCall *r);
+_PUBLIC_ void ndr_print_echo_TestCall2(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestCall2 *r);
+_PUBLIC_ void ndr_print_echo_TestSleep(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestSleep *r);
+_PUBLIC_ void ndr_print_echo_TestEnum(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestEnum *r);
+_PUBLIC_ void ndr_print_echo_TestSurrounding(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestSurrounding *r);
+_PUBLIC_ void ndr_print_echo_TestDoublePointer(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestDoublePointer *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_eventlog.c */
+
+_PUBLIC_ void ndr_print_eventlog_OpenUnknown0(struct ndr_print *ndr, const char *name, const struct eventlog_OpenUnknown0 *r);
+_PUBLIC_ enum ndr_err_code ndr_push_eventlog_Record(struct ndr_push *ndr, int ndr_flags, const struct eventlog_Record *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_eventlog_Record(struct ndr_pull *ndr, int ndr_flags, struct eventlog_Record *r);
+_PUBLIC_ void ndr_print_eventlog_Record(struct ndr_print *ndr, const char *name, const struct eventlog_Record *r);
+_PUBLIC_ void ndr_print_eventlog_ClearEventLogW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ClearEventLogW *r);
+_PUBLIC_ void ndr_print_eventlog_BackupEventLogW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_BackupEventLogW *r);
+_PUBLIC_ void ndr_print_eventlog_CloseEventLog(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_CloseEventLog *r);
+_PUBLIC_ void ndr_print_eventlog_DeregisterEventSource(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_DeregisterEventSource *r);
+_PUBLIC_ void ndr_print_eventlog_GetNumRecords(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_GetNumRecords *r);
+_PUBLIC_ void ndr_print_eventlog_GetOldestRecord(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_GetOldestRecord *r);
+_PUBLIC_ void ndr_print_eventlog_ChangeNotify(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ChangeNotify *r);
+_PUBLIC_ void ndr_print_eventlog_OpenEventLogW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_OpenEventLogW *r);
+_PUBLIC_ void ndr_print_eventlog_RegisterEventSourceW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_RegisterEventSourceW *r);
+_PUBLIC_ void ndr_print_eventlog_OpenBackupEventLogW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_OpenBackupEventLogW *r);
+_PUBLIC_ void ndr_print_eventlog_ReadEventLogW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ReadEventLogW *r);
+_PUBLIC_ void ndr_print_eventlog_ReportEventW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ReportEventW *r);
+_PUBLIC_ void ndr_print_eventlog_ClearEventLogA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ClearEventLogA *r);
+_PUBLIC_ void ndr_print_eventlog_BackupEventLogA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_BackupEventLogA *r);
+_PUBLIC_ void ndr_print_eventlog_OpenEventLogA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_OpenEventLogA *r);
+_PUBLIC_ void ndr_print_eventlog_RegisterEventSourceA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_RegisterEventSourceA *r);
+_PUBLIC_ void ndr_print_eventlog_OpenBackupEventLogA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_OpenBackupEventLogA *r);
+_PUBLIC_ void ndr_print_eventlog_ReadEventLogA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ReadEventLogA *r);
+_PUBLIC_ void ndr_print_eventlog_ReportEventA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ReportEventA *r);
+_PUBLIC_ void ndr_print_eventlog_RegisterClusterSvc(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_RegisterClusterSvc *r);
+_PUBLIC_ void ndr_print_eventlog_DeregisterClusterSvc(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_DeregisterClusterSvc *r);
+_PUBLIC_ void ndr_print_eventlog_WriteClusterEvents(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_WriteClusterEvents *r);
+_PUBLIC_ void ndr_print_eventlog_GetLogIntormation(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_GetLogIntormation *r);
+_PUBLIC_ void ndr_print_eventlog_FlushEventLog(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_FlushEventLog *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_initshutdown.c */
+
+_PUBLIC_ void ndr_print_initshutdown_String_sub(struct ndr_print *ndr, const char *name, const struct initshutdown_String_sub *r);
+_PUBLIC_ enum ndr_err_code ndr_push_initshutdown_String(struct ndr_push *ndr, int ndr_flags, const struct initshutdown_String *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_initshutdown_String(struct ndr_pull *ndr, int ndr_flags, struct initshutdown_String *r);
+_PUBLIC_ void ndr_print_initshutdown_String(struct ndr_print *ndr, const char *name, const struct initshutdown_String *r);
+_PUBLIC_ void ndr_print_initshutdown_Init(struct ndr_print *ndr, const char *name, int flags, const struct initshutdown_Init *r);
+_PUBLIC_ void ndr_print_initshutdown_Abort(struct ndr_print *ndr, const char *name, int flags, const struct initshutdown_Abort *r);
+_PUBLIC_ void ndr_print_initshutdown_InitEx(struct ndr_print *ndr, const char *name, int flags, const struct initshutdown_InitEx *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_krb5pac.c */
+
+_PUBLIC_ void ndr_print_PAC_LOGON_NAME(struct ndr_print *ndr, const char *name, const struct PAC_LOGON_NAME *r);
+_PUBLIC_ enum ndr_err_code ndr_push_PAC_SIGNATURE_DATA(struct ndr_push *ndr, int ndr_flags, const struct PAC_SIGNATURE_DATA *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_PAC_SIGNATURE_DATA(struct ndr_pull *ndr, int ndr_flags, struct PAC_SIGNATURE_DATA *r);
+_PUBLIC_ void ndr_print_PAC_SIGNATURE_DATA(struct ndr_print *ndr, const char *name, const struct PAC_SIGNATURE_DATA *r);
+_PUBLIC_ void ndr_print_PAC_LOGON_INFO(struct ndr_print *ndr, const char *name, const struct PAC_LOGON_INFO *r);
+_PUBLIC_ enum ndr_err_code ndr_push_PAC_LOGON_INFO_CTR(struct ndr_push *ndr, int ndr_flags, const struct PAC_LOGON_INFO_CTR *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_PAC_LOGON_INFO_CTR(struct ndr_pull *ndr, int ndr_flags, struct PAC_LOGON_INFO_CTR *r);
+_PUBLIC_ void ndr_print_PAC_LOGON_INFO_CTR(struct ndr_print *ndr, const char *name, const struct PAC_LOGON_INFO_CTR *r);
+_PUBLIC_ enum ndr_err_code ndr_push_PAC_TYPE(struct ndr_push *ndr, int ndr_flags, enum PAC_TYPE r);
+_PUBLIC_ enum ndr_err_code ndr_pull_PAC_TYPE(struct ndr_pull *ndr, int ndr_flags, enum PAC_TYPE *r);
+_PUBLIC_ void ndr_print_PAC_TYPE(struct ndr_print *ndr, const char *name, enum PAC_TYPE r);
+_PUBLIC_ void ndr_print_DATA_BLOB_REM(struct ndr_print *ndr, const char *name, const struct DATA_BLOB_REM *r);
+_PUBLIC_ enum ndr_err_code ndr_push_PAC_INFO(struct ndr_push *ndr, int ndr_flags, const union PAC_INFO *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_PAC_INFO(struct ndr_pull *ndr, int ndr_flags, union PAC_INFO *r);
+_PUBLIC_ void ndr_print_PAC_INFO(struct ndr_print *ndr, const char *name, const union PAC_INFO *r);
+_PUBLIC_ size_t ndr_size_PAC_INFO(const union PAC_INFO *r, uint32_t level, int flags);
+_PUBLIC_ enum ndr_err_code ndr_push_PAC_DATA(struct ndr_push *ndr, int ndr_flags, const struct PAC_DATA *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_PAC_DATA(struct ndr_pull *ndr, int ndr_flags, struct PAC_DATA *r);
+_PUBLIC_ void ndr_print_PAC_DATA(struct ndr_print *ndr, const char *name, const struct PAC_DATA *r);
+_PUBLIC_ enum ndr_err_code ndr_push_PAC_BUFFER_RAW(struct ndr_push *ndr, int ndr_flags, const struct PAC_BUFFER_RAW *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_PAC_BUFFER_RAW(struct ndr_pull *ndr, int ndr_flags, struct PAC_BUFFER_RAW *r);
+_PUBLIC_ void ndr_print_PAC_BUFFER_RAW(struct ndr_print *ndr, const char *name, const struct PAC_BUFFER_RAW *r);
+_PUBLIC_ enum ndr_err_code ndr_push_PAC_DATA_RAW(struct ndr_push *ndr, int ndr_flags, const struct PAC_DATA_RAW *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_PAC_DATA_RAW(struct ndr_pull *ndr, int ndr_flags, struct PAC_DATA_RAW *r);
+_PUBLIC_ void ndr_print_PAC_DATA_RAW(struct ndr_print *ndr, const char *name, const struct PAC_DATA_RAW *r);
+_PUBLIC_ enum ndr_err_code ndr_push_netsamlogoncache_entry(struct ndr_push *ndr, int ndr_flags, const struct netsamlogoncache_entry *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netsamlogoncache_entry(struct ndr_pull *ndr, int ndr_flags, struct netsamlogoncache_entry *r);
+_PUBLIC_ void ndr_print_netsamlogoncache_entry(struct ndr_print *ndr, const char *name, const struct netsamlogoncache_entry *r);
+_PUBLIC_ void ndr_print_decode_pac(struct ndr_print *ndr, const char *name, int flags, const struct decode_pac *r);
+_PUBLIC_ void ndr_print_decode_pac_raw(struct ndr_print *ndr, const char *name, int flags, const struct decode_pac_raw *r);
+_PUBLIC_ void ndr_print_decode_login_info(struct ndr_print *ndr, const char *name, int flags, const struct decode_login_info *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_lsa.c */
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_String(struct ndr_push *ndr, int ndr_flags, const struct lsa_String *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_String(struct ndr_pull *ndr, int ndr_flags, struct lsa_String *r);
+_PUBLIC_ void ndr_print_lsa_String(struct ndr_print *ndr, const char *name, const struct lsa_String *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_StringLarge(struct ndr_push *ndr, int ndr_flags, const struct lsa_StringLarge *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_StringLarge(struct ndr_pull *ndr, int ndr_flags, struct lsa_StringLarge *r);
+_PUBLIC_ void ndr_print_lsa_StringLarge(struct ndr_print *ndr, const char *name, const struct lsa_StringLarge *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_Strings(struct ndr_push *ndr, int ndr_flags, const struct lsa_Strings *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_Strings(struct ndr_pull *ndr, int ndr_flags, struct lsa_Strings *r);
+_PUBLIC_ void ndr_print_lsa_Strings(struct ndr_print *ndr, const char *name, const struct lsa_Strings *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_AsciiString(struct ndr_push *ndr, int ndr_flags, const struct lsa_AsciiString *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_AsciiString(struct ndr_pull *ndr, int ndr_flags, struct lsa_AsciiString *r);
+_PUBLIC_ void ndr_print_lsa_AsciiString(struct ndr_print *ndr, const char *name, const struct lsa_AsciiString *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_AsciiStringLarge(struct ndr_push *ndr, int ndr_flags, const struct lsa_AsciiStringLarge *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_AsciiStringLarge(struct ndr_pull *ndr, int ndr_flags, struct lsa_AsciiStringLarge *r);
+_PUBLIC_ void ndr_print_lsa_AsciiStringLarge(struct ndr_print *ndr, const char *name, const struct lsa_AsciiStringLarge *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_BinaryString(struct ndr_push *ndr, int ndr_flags, const struct lsa_BinaryString *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_BinaryString(struct ndr_pull *ndr, int ndr_flags, struct lsa_BinaryString *r);
+_PUBLIC_ void ndr_print_lsa_BinaryString(struct ndr_print *ndr, const char *name, const struct lsa_BinaryString *r);
+_PUBLIC_ void ndr_print_lsa_LUID(struct ndr_print *ndr, const char *name, const struct lsa_LUID *r);
+_PUBLIC_ void ndr_print_lsa_PrivEntry(struct ndr_print *ndr, const char *name, const struct lsa_PrivEntry *r);
+_PUBLIC_ void ndr_print_lsa_PrivArray(struct ndr_print *ndr, const char *name, const struct lsa_PrivArray *r);
+_PUBLIC_ void ndr_print_lsa_QosInfo(struct ndr_print *ndr, const char *name, const struct lsa_QosInfo *r);
+_PUBLIC_ void ndr_print_lsa_ObjectAttribute(struct ndr_print *ndr, const char *name, const struct lsa_ObjectAttribute *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_PolicyAccessMask(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_PolicyAccessMask(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+_PUBLIC_ void ndr_print_lsa_PolicyAccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_lsa_AuditLogInfo(struct ndr_print *ndr, const char *name, const struct lsa_AuditLogInfo *r);
+_PUBLIC_ void ndr_print_lsa_PolicyAuditPolicy(struct ndr_print *ndr, const char *name, enum lsa_PolicyAuditPolicy r);
+_PUBLIC_ void ndr_print_lsa_AuditEventsInfo(struct ndr_print *ndr, const char *name, const struct lsa_AuditEventsInfo *r);
+_PUBLIC_ void ndr_print_lsa_DomainInfo(struct ndr_print *ndr, const char *name, const struct lsa_DomainInfo *r);
+_PUBLIC_ void ndr_print_lsa_PDAccountInfo(struct ndr_print *ndr, const char *name, const struct lsa_PDAccountInfo *r);
+_PUBLIC_ void ndr_print_lsa_ServerRole(struct ndr_print *ndr, const char *name, const struct lsa_ServerRole *r);
+_PUBLIC_ void ndr_print_lsa_ReplicaSourceInfo(struct ndr_print *ndr, const char *name, const struct lsa_ReplicaSourceInfo *r);
+_PUBLIC_ void ndr_print_lsa_DefaultQuotaInfo(struct ndr_print *ndr, const char *name, const struct lsa_DefaultQuotaInfo *r);
+_PUBLIC_ void ndr_print_lsa_ModificationInfo(struct ndr_print *ndr, const char *name, const struct lsa_ModificationInfo *r);
+_PUBLIC_ void ndr_print_lsa_AuditFullSetInfo(struct ndr_print *ndr, const char *name, const struct lsa_AuditFullSetInfo *r);
+_PUBLIC_ void ndr_print_lsa_AuditFullQueryInfo(struct ndr_print *ndr, const char *name, const struct lsa_AuditFullQueryInfo *r);
+_PUBLIC_ void ndr_print_lsa_DnsDomainInfo(struct ndr_print *ndr, const char *name, const struct lsa_DnsDomainInfo *r);
+_PUBLIC_ void ndr_print_lsa_PolicyInfo(struct ndr_print *ndr, const char *name, enum lsa_PolicyInfo r);
+_PUBLIC_ void ndr_print_lsa_PolicyInformation(struct ndr_print *ndr, const char *name, const union lsa_PolicyInformation *r);
+_PUBLIC_ void ndr_print_lsa_SidPtr(struct ndr_print *ndr, const char *name, const struct lsa_SidPtr *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_SidArray(struct ndr_push *ndr, int ndr_flags, const struct lsa_SidArray *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_SidArray(struct ndr_pull *ndr, int ndr_flags, struct lsa_SidArray *r);
+_PUBLIC_ void ndr_print_lsa_SidArray(struct ndr_print *ndr, const char *name, const struct lsa_SidArray *r);
+_PUBLIC_ void ndr_print_lsa_DomainList(struct ndr_print *ndr, const char *name, const struct lsa_DomainList *r);
+_PUBLIC_ void ndr_print_lsa_SidType(struct ndr_print *ndr, const char *name, enum lsa_SidType r);
+_PUBLIC_ void ndr_print_lsa_TranslatedSid(struct ndr_print *ndr, const char *name, const struct lsa_TranslatedSid *r);
+_PUBLIC_ void ndr_print_lsa_TransSidArray(struct ndr_print *ndr, const char *name, const struct lsa_TransSidArray *r);
+_PUBLIC_ void ndr_print_lsa_RefDomainList(struct ndr_print *ndr, const char *name, const struct lsa_RefDomainList *r);
+_PUBLIC_ void ndr_print_lsa_LookupNamesLevel(struct ndr_print *ndr, const char *name, enum lsa_LookupNamesLevel r);
+_PUBLIC_ void ndr_print_lsa_TranslatedName(struct ndr_print *ndr, const char *name, const struct lsa_TranslatedName *r);
+_PUBLIC_ void ndr_print_lsa_TransNameArray(struct ndr_print *ndr, const char *name, const struct lsa_TransNameArray *r);
+_PUBLIC_ void ndr_print_lsa_LUIDAttribute(struct ndr_print *ndr, const char *name, const struct lsa_LUIDAttribute *r);
+_PUBLIC_ void ndr_print_lsa_PrivilegeSet(struct ndr_print *ndr, const char *name, const struct lsa_PrivilegeSet *r);
+_PUBLIC_ void ndr_print_lsa_DATA_BUF(struct ndr_print *ndr, const char *name, const struct lsa_DATA_BUF *r);
+_PUBLIC_ void ndr_print_lsa_DATA_BUF2(struct ndr_print *ndr, const char *name, const struct lsa_DATA_BUF2 *r);
+_PUBLIC_ void ndr_print_lsa_TrustDomInfoEnum(struct ndr_print *ndr, const char *name, enum lsa_TrustDomInfoEnum r);
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoName(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoName *r);
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoPosixOffset(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoPosixOffset *r);
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoPassword(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoPassword *r);
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoBasic(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoBasic *r);
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoInfoEx(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoInfoEx *r);
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoBuffer(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoBuffer *r);
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoAuthInfo(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoAuthInfo *r);
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoFullInfo(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoFullInfo *r);
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfo11(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfo11 *r);
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoInfoAll(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoInfoAll *r);
+_PUBLIC_ void ndr_print_lsa_TrustedDomainInfo(struct ndr_print *ndr, const char *name, const union lsa_TrustedDomainInfo *r);
+_PUBLIC_ void ndr_print_lsa_DATA_BUF_PTR(struct ndr_print *ndr, const char *name, const struct lsa_DATA_BUF_PTR *r);
+_PUBLIC_ void ndr_print_lsa_RightSet(struct ndr_print *ndr, const char *name, const struct lsa_RightSet *r);
+_PUBLIC_ void ndr_print_lsa_DomainListEx(struct ndr_print *ndr, const char *name, const struct lsa_DomainListEx *r);
+_PUBLIC_ void ndr_print_lsa_DomainInfoKerberos(struct ndr_print *ndr, const char *name, const struct lsa_DomainInfoKerberos *r);
+_PUBLIC_ void ndr_print_lsa_DomainInfoEfs(struct ndr_print *ndr, const char *name, const struct lsa_DomainInfoEfs *r);
+_PUBLIC_ void ndr_print_lsa_DomainInformationPolicy(struct ndr_print *ndr, const char *name, const union lsa_DomainInformationPolicy *r);
+_PUBLIC_ void ndr_print_lsa_TranslatedName2(struct ndr_print *ndr, const char *name, const struct lsa_TranslatedName2 *r);
+_PUBLIC_ void ndr_print_lsa_TransNameArray2(struct ndr_print *ndr, const char *name, const struct lsa_TransNameArray2 *r);
+_PUBLIC_ void ndr_print_lsa_TranslatedSid2(struct ndr_print *ndr, const char *name, const struct lsa_TranslatedSid2 *r);
+_PUBLIC_ void ndr_print_lsa_TransSidArray2(struct ndr_print *ndr, const char *name, const struct lsa_TransSidArray2 *r);
+_PUBLIC_ void ndr_print_lsa_TranslatedSid3(struct ndr_print *ndr, const char *name, const struct lsa_TranslatedSid3 *r);
+_PUBLIC_ void ndr_print_lsa_TransSidArray3(struct ndr_print *ndr, const char *name, const struct lsa_TransSidArray3 *r);
+_PUBLIC_ void ndr_print_lsa_ForestTrustBinaryData(struct ndr_print *ndr, const char *name, const struct lsa_ForestTrustBinaryData *r);
+_PUBLIC_ void ndr_print_lsa_ForestTrustDomainInfo(struct ndr_print *ndr, const char *name, const struct lsa_ForestTrustDomainInfo *r);
+_PUBLIC_ void ndr_print_lsa_ForestTrustData(struct ndr_print *ndr, const char *name, const union lsa_ForestTrustData *r);
+_PUBLIC_ void ndr_print_lsa_ForestTrustRecordType(struct ndr_print *ndr, const char *name, enum lsa_ForestTrustRecordType r);
+_PUBLIC_ void ndr_print_lsa_ForestTrustRecord(struct ndr_print *ndr, const char *name, const struct lsa_ForestTrustRecord *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_ForestTrustInformation(struct ndr_push *ndr, int ndr_flags, const struct lsa_ForestTrustInformation *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_ForestTrustInformation(struct ndr_pull *ndr, int ndr_flags, struct lsa_ForestTrustInformation *r);
+_PUBLIC_ void ndr_print_lsa_ForestTrustInformation(struct ndr_print *ndr, const char *name, const struct lsa_ForestTrustInformation *r);
+_PUBLIC_ void ndr_print_lsa_Close(struct ndr_print *ndr, const char *name, int flags, const struct lsa_Close *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_Delete(struct ndr_push *ndr, int flags, const struct lsa_Delete *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_Delete(struct ndr_pull *ndr, int flags, struct lsa_Delete *r);
+_PUBLIC_ void ndr_print_lsa_Delete(struct ndr_print *ndr, const char *name, int flags, const struct lsa_Delete *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_EnumPrivs(struct ndr_push *ndr, int flags, const struct lsa_EnumPrivs *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_EnumPrivs(struct ndr_pull *ndr, int flags, struct lsa_EnumPrivs *r);
+_PUBLIC_ void ndr_print_lsa_EnumPrivs(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumPrivs *r);
+_PUBLIC_ void ndr_print_lsa_QuerySecurity(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QuerySecurity *r);
+_PUBLIC_ void ndr_print_lsa_SetSecObj(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetSecObj *r);
+_PUBLIC_ void ndr_print_lsa_ChangePassword(struct ndr_print *ndr, const char *name, int flags, const struct lsa_ChangePassword *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_OpenPolicy(struct ndr_push *ndr, int flags, const struct lsa_OpenPolicy *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_OpenPolicy(struct ndr_pull *ndr, int flags, struct lsa_OpenPolicy *r);
+_PUBLIC_ void ndr_print_lsa_OpenPolicy(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenPolicy *r);
+_PUBLIC_ void ndr_print_lsa_QueryInfoPolicy(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryInfoPolicy *r);
+_PUBLIC_ void ndr_print_lsa_SetInfoPolicy(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetInfoPolicy *r);
+_PUBLIC_ void ndr_print_lsa_ClearAuditLog(struct ndr_print *ndr, const char *name, int flags, const struct lsa_ClearAuditLog *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_CreateAccount(struct ndr_push *ndr, int flags, const struct lsa_CreateAccount *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_CreateAccount(struct ndr_pull *ndr, int flags, struct lsa_CreateAccount *r);
+_PUBLIC_ void ndr_print_lsa_CreateAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CreateAccount *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_EnumAccounts(struct ndr_push *ndr, int flags, const struct lsa_EnumAccounts *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_EnumAccounts(struct ndr_pull *ndr, int flags, struct lsa_EnumAccounts *r);
+_PUBLIC_ void ndr_print_lsa_EnumAccounts(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumAccounts *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_CreateTrustedDomain(struct ndr_push *ndr, int flags, const struct lsa_CreateTrustedDomain *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_CreateTrustedDomain(struct ndr_pull *ndr, int flags, struct lsa_CreateTrustedDomain *r);
+_PUBLIC_ void ndr_print_lsa_CreateTrustedDomain(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CreateTrustedDomain *r);
+_PUBLIC_ void ndr_print_lsa_EnumTrustDom(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumTrustDom *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_LookupNames(struct ndr_push *ndr, int flags, const struct lsa_LookupNames *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_LookupNames(struct ndr_pull *ndr, int flags, struct lsa_LookupNames *r);
+_PUBLIC_ void ndr_print_lsa_LookupNames(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupNames *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_LookupSids(struct ndr_push *ndr, int flags, const struct lsa_LookupSids *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_LookupSids(struct ndr_pull *ndr, int flags, struct lsa_LookupSids *r);
+_PUBLIC_ void ndr_print_lsa_LookupSids(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupSids *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_CreateSecret(struct ndr_push *ndr, int flags, const struct lsa_CreateSecret *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_CreateSecret(struct ndr_pull *ndr, int flags, struct lsa_CreateSecret *r);
+_PUBLIC_ void ndr_print_lsa_CreateSecret(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CreateSecret *r);
+_PUBLIC_ void ndr_print_lsa_OpenAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenAccount *r);
+_PUBLIC_ void ndr_print_lsa_EnumPrivsAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumPrivsAccount *r);
+_PUBLIC_ void ndr_print_lsa_AddPrivilegesToAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_AddPrivilegesToAccount *r);
+_PUBLIC_ void ndr_print_lsa_RemovePrivilegesFromAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_RemovePrivilegesFromAccount *r);
+_PUBLIC_ void ndr_print_lsa_GetQuotasForAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_GetQuotasForAccount *r);
+_PUBLIC_ void ndr_print_lsa_SetQuotasForAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetQuotasForAccount *r);
+_PUBLIC_ void ndr_print_lsa_GetSystemAccessAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_GetSystemAccessAccount *r);
+_PUBLIC_ void ndr_print_lsa_SetSystemAccessAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetSystemAccessAccount *r);
+_PUBLIC_ void ndr_print_lsa_OpenTrustedDomain(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenTrustedDomain *r);
+_PUBLIC_ void ndr_print_lsa_QueryTrustedDomainInfo(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryTrustedDomainInfo *r);
+_PUBLIC_ void ndr_print_lsa_SetInformationTrustedDomain(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetInformationTrustedDomain *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_OpenSecret(struct ndr_push *ndr, int flags, const struct lsa_OpenSecret *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_OpenSecret(struct ndr_pull *ndr, int flags, struct lsa_OpenSecret *r);
+_PUBLIC_ void ndr_print_lsa_OpenSecret(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenSecret *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_SetSecret(struct ndr_push *ndr, int flags, const struct lsa_SetSecret *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_SetSecret(struct ndr_pull *ndr, int flags, struct lsa_SetSecret *r);
+_PUBLIC_ void ndr_print_lsa_SetSecret(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetSecret *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_QuerySecret(struct ndr_push *ndr, int flags, const struct lsa_QuerySecret *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_QuerySecret(struct ndr_pull *ndr, int flags, struct lsa_QuerySecret *r);
+_PUBLIC_ void ndr_print_lsa_QuerySecret(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QuerySecret *r);
+_PUBLIC_ void ndr_print_lsa_LookupPrivValue(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupPrivValue *r);
+_PUBLIC_ void ndr_print_lsa_LookupPrivName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupPrivName *r);
+_PUBLIC_ void ndr_print_lsa_LookupPrivDisplayName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupPrivDisplayName *r);
+_PUBLIC_ void ndr_print_lsa_DeleteObject(struct ndr_print *ndr, const char *name, int flags, const struct lsa_DeleteObject *r);
+_PUBLIC_ void ndr_print_lsa_EnumAccountsWithUserRight(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumAccountsWithUserRight *r);
+_PUBLIC_ void ndr_print_lsa_EnumAccountRights(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumAccountRights *r);
+_PUBLIC_ void ndr_print_lsa_AddAccountRights(struct ndr_print *ndr, const char *name, int flags, const struct lsa_AddAccountRights *r);
+_PUBLIC_ void ndr_print_lsa_RemoveAccountRights(struct ndr_print *ndr, const char *name, int flags, const struct lsa_RemoveAccountRights *r);
+_PUBLIC_ void ndr_print_lsa_QueryTrustedDomainInfoBySid(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryTrustedDomainInfoBySid *r);
+_PUBLIC_ void ndr_print_lsa_SetTrustedDomainInfo(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetTrustedDomainInfo *r);
+_PUBLIC_ void ndr_print_lsa_DeleteTrustedDomain(struct ndr_print *ndr, const char *name, int flags, const struct lsa_DeleteTrustedDomain *r);
+_PUBLIC_ void ndr_print_lsa_StorePrivateData(struct ndr_print *ndr, const char *name, int flags, const struct lsa_StorePrivateData *r);
+_PUBLIC_ void ndr_print_lsa_RetrievePrivateData(struct ndr_print *ndr, const char *name, int flags, const struct lsa_RetrievePrivateData *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_OpenPolicy2(struct ndr_push *ndr, int flags, const struct lsa_OpenPolicy2 *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_OpenPolicy2(struct ndr_pull *ndr, int flags, struct lsa_OpenPolicy2 *r);
+_PUBLIC_ void ndr_print_lsa_OpenPolicy2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenPolicy2 *r);
+_PUBLIC_ void ndr_print_lsa_GetUserName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_GetUserName *r);
+_PUBLIC_ void ndr_print_lsa_QueryInfoPolicy2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryInfoPolicy2 *r);
+_PUBLIC_ void ndr_print_lsa_SetInfoPolicy2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetInfoPolicy2 *r);
+_PUBLIC_ void ndr_print_lsa_QueryTrustedDomainInfoByName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryTrustedDomainInfoByName *r);
+_PUBLIC_ void ndr_print_lsa_SetTrustedDomainInfoByName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetTrustedDomainInfoByName *r);
+_PUBLIC_ void ndr_print_lsa_EnumTrustedDomainsEx(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumTrustedDomainsEx *r);
+_PUBLIC_ void ndr_print_lsa_CreateTrustedDomainEx(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CreateTrustedDomainEx *r);
+_PUBLIC_ void ndr_print_lsa_CloseTrustedDomainEx(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CloseTrustedDomainEx *r);
+_PUBLIC_ void ndr_print_lsa_QueryDomainInformationPolicy(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryDomainInformationPolicy *r);
+_PUBLIC_ void ndr_print_lsa_SetDomainInformationPolicy(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetDomainInformationPolicy *r);
+_PUBLIC_ void ndr_print_lsa_OpenTrustedDomainByName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenTrustedDomainByName *r);
+_PUBLIC_ void ndr_print_lsa_TestCall(struct ndr_print *ndr, const char *name, int flags, const struct lsa_TestCall *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_LookupSids2(struct ndr_push *ndr, int flags, const struct lsa_LookupSids2 *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_LookupSids2(struct ndr_pull *ndr, int flags, struct lsa_LookupSids2 *r);
+_PUBLIC_ void ndr_print_lsa_LookupSids2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupSids2 *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_LookupNames2(struct ndr_push *ndr, int flags, const struct lsa_LookupNames2 *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_LookupNames2(struct ndr_pull *ndr, int flags, struct lsa_LookupNames2 *r);
+_PUBLIC_ void ndr_print_lsa_LookupNames2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupNames2 *r);
+_PUBLIC_ void ndr_print_lsa_CreateTrustedDomainEx2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CreateTrustedDomainEx2 *r);
+_PUBLIC_ void ndr_print_lsa_CREDRWRITE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRWRITE *r);
+_PUBLIC_ void ndr_print_lsa_CREDRREAD(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRREAD *r);
+_PUBLIC_ void ndr_print_lsa_CREDRENUMERATE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRENUMERATE *r);
+_PUBLIC_ void ndr_print_lsa_CREDRWRITEDOMAINCREDENTIALS(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRWRITEDOMAINCREDENTIALS *r);
+_PUBLIC_ void ndr_print_lsa_CREDRREADDOMAINCREDENTIALS(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRREADDOMAINCREDENTIALS *r);
+_PUBLIC_ void ndr_print_lsa_CREDRDELETE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRDELETE *r);
+_PUBLIC_ void ndr_print_lsa_CREDRGETTARGETINFO(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRGETTARGETINFO *r);
+_PUBLIC_ void ndr_print_lsa_CREDRPROFILELOADED(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRPROFILELOADED *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_LookupNames3(struct ndr_push *ndr, int flags, const struct lsa_LookupNames3 *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_LookupNames3(struct ndr_pull *ndr, int flags, struct lsa_LookupNames3 *r);
+_PUBLIC_ void ndr_print_lsa_LookupNames3(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupNames3 *r);
+_PUBLIC_ void ndr_print_lsa_CREDRGETSESSIONTYPES(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRGETSESSIONTYPES *r);
+_PUBLIC_ void ndr_print_lsa_LSARREGISTERAUDITEVENT(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARREGISTERAUDITEVENT *r);
+_PUBLIC_ void ndr_print_lsa_LSARGENAUDITEVENT(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARGENAUDITEVENT *r);
+_PUBLIC_ void ndr_print_lsa_LSARUNREGISTERAUDITEVENT(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARUNREGISTERAUDITEVENT *r);
+_PUBLIC_ void ndr_print_lsa_lsaRQueryForestTrustInformation(struct ndr_print *ndr, const char *name, int flags, const struct lsa_lsaRQueryForestTrustInformation *r);
+_PUBLIC_ void ndr_print_lsa_LSARSETFORESTTRUSTINFORMATION(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARSETFORESTTRUSTINFORMATION *r);
+_PUBLIC_ void ndr_print_lsa_CREDRRENAME(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRRENAME *r);
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_LookupSids3(struct ndr_push *ndr, int flags, const struct lsa_LookupSids3 *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_LookupSids3(struct ndr_pull *ndr, int flags, struct lsa_LookupSids3 *r);
+_PUBLIC_ void ndr_print_lsa_LookupSids3(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupSids3 *r);
+_PUBLIC_ void ndr_print_lsa_LookupNames4(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupNames4 *r);
+_PUBLIC_ void ndr_print_lsa_LSAROPENPOLICYSCE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSAROPENPOLICYSCE *r);
+_PUBLIC_ void ndr_print_lsa_LSARADTREGISTERSECURITYEVENTSOURCE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE *r);
+_PUBLIC_ void ndr_print_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE *r);
+_PUBLIC_ void ndr_print_lsa_LSARADTREPORTSECURITYEVENT(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARADTREPORTSECURITYEVENT *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_misc.c */
+
+_PUBLIC_ enum ndr_err_code ndr_push_GUID(struct ndr_push *ndr, int ndr_flags, const struct GUID *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_GUID(struct ndr_pull *ndr, int ndr_flags, struct GUID *r);
+_PUBLIC_ size_t ndr_size_GUID(const struct GUID *r, int flags);
+_PUBLIC_ enum ndr_err_code ndr_push_ndr_syntax_id(struct ndr_push *ndr, int ndr_flags, const struct ndr_syntax_id *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_ndr_syntax_id(struct ndr_pull *ndr, int ndr_flags, struct ndr_syntax_id *r);
+_PUBLIC_ void ndr_print_ndr_syntax_id(struct ndr_print *ndr, const char *name, const struct ndr_syntax_id *r);
+_PUBLIC_ enum ndr_err_code ndr_push_policy_handle(struct ndr_push *ndr, int ndr_flags, const struct policy_handle *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_policy_handle(struct ndr_pull *ndr, int ndr_flags, struct policy_handle *r);
+_PUBLIC_ void ndr_print_policy_handle(struct ndr_print *ndr, const char *name, const struct policy_handle *r);
+_PUBLIC_ enum ndr_err_code ndr_push_netr_SchannelType(struct ndr_push *ndr, int ndr_flags, enum netr_SchannelType r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_SchannelType(struct ndr_pull *ndr, int ndr_flags, enum netr_SchannelType *r);
+_PUBLIC_ void ndr_print_netr_SchannelType(struct ndr_print *ndr, const char *name, enum netr_SchannelType r);
+_PUBLIC_ enum ndr_err_code ndr_push_netr_SamDatabaseID(struct ndr_push *ndr, int ndr_flags, enum netr_SamDatabaseID r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_SamDatabaseID(struct ndr_pull *ndr, int ndr_flags, enum netr_SamDatabaseID *r);
+_PUBLIC_ void ndr_print_netr_SamDatabaseID(struct ndr_print *ndr, const char *name, enum netr_SamDatabaseID r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_RejectReason(struct ndr_push *ndr, int ndr_flags, enum samr_RejectReason r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_RejectReason(struct ndr_pull *ndr, int ndr_flags, enum samr_RejectReason *r);
+_PUBLIC_ void ndr_print_samr_RejectReason(struct ndr_print *ndr, const char *name, enum samr_RejectReason r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_nbt.c */
+
+_PUBLIC_ void ndr_print_nbt_operation(struct ndr_print *ndr, const char *name, uint16_t r);
+_PUBLIC_ void ndr_print_nbt_name_type(struct ndr_print *ndr, const char *name, enum nbt_name_type r);
+_PUBLIC_ void ndr_print_nbt_name(struct ndr_print *ndr, const char *name, const struct nbt_name *r);
+_PUBLIC_ void ndr_print_nbt_qclass(struct ndr_print *ndr, const char *name, enum nbt_qclass r);
+_PUBLIC_ void ndr_print_nbt_qtype(struct ndr_print *ndr, const char *name, enum nbt_qtype r);
+_PUBLIC_ void ndr_print_nbt_name_question(struct ndr_print *ndr, const char *name, const struct nbt_name_question *r);
+_PUBLIC_ void ndr_print_nb_flags(struct ndr_print *ndr, const char *name, uint16_t r);
+_PUBLIC_ void ndr_print_nbt_rdata_address(struct ndr_print *ndr, const char *name, const struct nbt_rdata_address *r);
+_PUBLIC_ void ndr_print_nbt_rdata_netbios(struct ndr_print *ndr, const char *name, const struct nbt_rdata_netbios *r);
+_PUBLIC_ void ndr_print_nbt_statistics(struct ndr_print *ndr, const char *name, const struct nbt_statistics *r);
+_PUBLIC_ void ndr_print_nbt_status_name(struct ndr_print *ndr, const char *name, const struct nbt_status_name *r);
+_PUBLIC_ void ndr_print_nbt_rdata_status(struct ndr_print *ndr, const char *name, const struct nbt_rdata_status *r);
+_PUBLIC_ void ndr_print_nbt_rdata_data(struct ndr_print *ndr, const char *name, const struct nbt_rdata_data *r);
+_PUBLIC_ void ndr_print_nbt_rdata(struct ndr_print *ndr, const char *name, const union nbt_rdata *r);
+_PUBLIC_ void ndr_print_nbt_res_rec(struct ndr_print *ndr, const char *name, const struct nbt_res_rec *r);
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_name_packet(struct ndr_push *ndr, int ndr_flags, const struct nbt_name_packet *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_name_packet(struct ndr_pull *ndr, int ndr_flags, struct nbt_name_packet *r);
+_PUBLIC_ void ndr_print_nbt_name_packet(struct ndr_print *ndr, const char *name, const struct nbt_name_packet *r);
+_PUBLIC_ void ndr_print_dgram_msg_type(struct ndr_print *ndr, const char *name, enum dgram_msg_type r);
+_PUBLIC_ void ndr_print_dgram_flags(struct ndr_print *ndr, const char *name, uint8_t r);
+_PUBLIC_ void ndr_print_smb_command(struct ndr_print *ndr, const char *name, enum smb_command r);
+_PUBLIC_ void ndr_print_smb_trans_body(struct ndr_print *ndr, const char *name, const struct smb_trans_body *r);
+_PUBLIC_ void ndr_print_smb_body(struct ndr_print *ndr, const char *name, const union smb_body *r);
+_PUBLIC_ enum ndr_err_code ndr_push_dgram_smb_packet(struct ndr_push *ndr, int ndr_flags, const struct dgram_smb_packet *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_dgram_smb_packet(struct ndr_pull *ndr, int ndr_flags, struct dgram_smb_packet *r);
+_PUBLIC_ void ndr_print_dgram_smb_packet(struct ndr_print *ndr, const char *name, const struct dgram_smb_packet *r);
+_PUBLIC_ void ndr_print_dgram_message_body(struct ndr_print *ndr, const char *name, const union dgram_message_body *r);
+_PUBLIC_ void ndr_print_dgram_message(struct ndr_print *ndr, const char *name, const struct dgram_message *r);
+_PUBLIC_ void ndr_print_dgram_err_code(struct ndr_print *ndr, const char *name, enum dgram_err_code r);
+_PUBLIC_ void ndr_print_dgram_data(struct ndr_print *ndr, const char *name, const union dgram_data *r);
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_dgram_packet(struct ndr_push *ndr, int ndr_flags, const struct nbt_dgram_packet *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_dgram_packet(struct ndr_pull *ndr, int ndr_flags, struct nbt_dgram_packet *r);
+_PUBLIC_ void ndr_print_nbt_dgram_packet(struct ndr_print *ndr, const char *name, const struct nbt_dgram_packet *r);
+_PUBLIC_ void ndr_print_nbt_netlogon_command(struct ndr_print *ndr, const char *name, enum nbt_netlogon_command r);
+_PUBLIC_ void ndr_print_nbt_netlogon_version(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_nbt_netlogon_query_for_pdc(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_query_for_pdc *r);
+_PUBLIC_ void ndr_print_nbt_netlogon_query_for_pdc2(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_query_for_pdc2 *r);
+_PUBLIC_ void ndr_print_nbt_netlogon_response_from_pdc(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_response_from_pdc *r);
+_PUBLIC_ void ndr_print_nbt_server_type(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_nbt_dc_sock_addr(struct ndr_print *ndr, const char *name, const struct nbt_dc_sock_addr *r);
+_PUBLIC_ void ndr_print_nbt_netlogon_response_from_pdc2(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_response_from_pdc2 *r);
+_PUBLIC_ void ndr_print_nbt_db_change(struct ndr_print *ndr, const char *name, const struct nbt_db_change *r);
+_PUBLIC_ void ndr_print_nbt_netlogon_announce_uas(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_announce_uas *r);
+_PUBLIC_ void ndr_print_nbt_netlogon_request(struct ndr_print *ndr, const char *name, const union nbt_netlogon_request *r);
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_netlogon_packet(struct ndr_push *ndr, int ndr_flags, const struct nbt_netlogon_packet *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_netlogon_packet(struct ndr_pull *ndr, int ndr_flags, struct nbt_netlogon_packet *r);
+_PUBLIC_ void ndr_print_nbt_netlogon_packet(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_packet *r);
+_PUBLIC_ void ndr_print_nbt_cldap_netlogon_1(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_1 *r);
+_PUBLIC_ void ndr_print_nbt_cldap_netlogon_3(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_3 *r);
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_cldap_netlogon_5(struct ndr_push *ndr, int ndr_flags, const struct nbt_cldap_netlogon_5 *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_cldap_netlogon_5(struct ndr_pull *ndr, int ndr_flags, struct nbt_cldap_netlogon_5 *r);
+_PUBLIC_ void ndr_print_nbt_cldap_netlogon_5(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_5 *r);
+_PUBLIC_ void ndr_print_nbt_cldap_netlogon_13(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_13 *r);
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_cldap_netlogon_15(struct ndr_push *ndr, int ndr_flags, const struct nbt_cldap_netlogon_15 *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_cldap_netlogon_15(struct ndr_pull *ndr, int ndr_flags, struct nbt_cldap_netlogon_15 *r);
+_PUBLIC_ void ndr_print_nbt_cldap_netlogon_15(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_15 *r);
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_cldap_netlogon_29(struct ndr_push *ndr, int ndr_flags, const struct nbt_cldap_netlogon_29 *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_cldap_netlogon_29(struct ndr_pull *ndr, int ndr_flags, struct nbt_cldap_netlogon_29 *r);
+_PUBLIC_ void ndr_print_nbt_cldap_netlogon_29(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_29 *r);
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_cldap_netlogon(struct ndr_push *ndr, int ndr_flags, const union nbt_cldap_netlogon *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_cldap_netlogon(struct ndr_pull *ndr, int ndr_flags, union nbt_cldap_netlogon *r);
+_PUBLIC_ void ndr_print_nbt_cldap_netlogon(struct ndr_print *ndr, const char *name, const union nbt_cldap_netlogon *r);
+_PUBLIC_ void ndr_print_nbt_ntlogon_command(struct ndr_print *ndr, const char *name, enum nbt_ntlogon_command r);
+_PUBLIC_ void ndr_print_nbt_ntlogon_sam_logon(struct ndr_print *ndr, const char *name, const struct nbt_ntlogon_sam_logon *r);
+_PUBLIC_ void ndr_print_nbt_ntlogon_sam_logon_reply(struct ndr_print *ndr, const char *name, const struct nbt_ntlogon_sam_logon_reply *r);
+_PUBLIC_ void ndr_print_nbt_ntlogon_request(struct ndr_print *ndr, const char *name, const union nbt_ntlogon_request *r);
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_ntlogon_packet(struct ndr_push *ndr, int ndr_flags, const struct nbt_ntlogon_packet *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_ntlogon_packet(struct ndr_pull *ndr, int ndr_flags, struct nbt_ntlogon_packet *r);
+_PUBLIC_ void ndr_print_nbt_ntlogon_packet(struct ndr_print *ndr, const char *name, const struct nbt_ntlogon_packet *r);
+_PUBLIC_ void ndr_print_nbt_browse_opcode(struct ndr_print *ndr, const char *name, enum nbt_browse_opcode r);
+_PUBLIC_ void ndr_print_nbt_browse_host_announcement(struct ndr_print *ndr, const char *name, const struct nbt_browse_host_announcement *r);
+_PUBLIC_ void ndr_print_nbt_browse_announcement_request(struct ndr_print *ndr, const char *name, const struct nbt_browse_announcement_request *r);
+_PUBLIC_ void ndr_print_nbt_browse_election_request(struct ndr_print *ndr, const char *name, const struct nbt_browse_election_request *r);
+_PUBLIC_ void ndr_print_nbt_browse_backup_list_request(struct ndr_print *ndr, const char *name, const struct nbt_browse_backup_list_request *r);
+_PUBLIC_ void ndr_print_nbt_browse_backup_list_response(struct ndr_print *ndr, const char *name, const struct nbt_browse_backup_list_response *r);
+_PUBLIC_ void ndr_print_nbt_browse_become_backup(struct ndr_print *ndr, const char *name, const struct nbt_browse_become_backup *r);
+_PUBLIC_ void ndr_print_nbt_browse_domain_announcement(struct ndr_print *ndr, const char *name, const struct nbt_browse_domain_announcement *r);
+_PUBLIC_ void ndr_print_nbt_browse_master_announcement(struct ndr_print *ndr, const char *name, const struct nbt_browse_master_announcement *r);
+_PUBLIC_ void ndr_print_nbt_browse_reset_state(struct ndr_print *ndr, const char *name, const struct nbt_browse_reset_state *r);
+_PUBLIC_ void ndr_print_nbt_browse_local_master_announcement(struct ndr_print *ndr, const char *name, const struct nbt_browse_local_master_announcement *r);
+_PUBLIC_ void ndr_print_nbt_browse_payload(struct ndr_print *ndr, const char *name, const union nbt_browse_payload *r);
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_browse_packet(struct ndr_push *ndr, int ndr_flags, const struct nbt_browse_packet *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_browse_packet(struct ndr_pull *ndr, int ndr_flags, struct nbt_browse_packet *r);
+_PUBLIC_ void ndr_print_nbt_browse_packet(struct ndr_print *ndr, const char *name, const struct nbt_browse_packet *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_netlogon.c */
+
+_PUBLIC_ void ndr_print_netr_UasInfo(struct ndr_print *ndr, const char *name, const struct netr_UasInfo *r);
+_PUBLIC_ void ndr_print_netr_UasLogoffInfo(struct ndr_print *ndr, const char *name, const struct netr_UasLogoffInfo *r);
+_PUBLIC_ enum ndr_err_code ndr_push_netr_AcctLockStr(struct ndr_push *ndr, int ndr_flags, const struct netr_AcctLockStr *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_AcctLockStr(struct ndr_pull *ndr, int ndr_flags, struct netr_AcctLockStr *r);
+_PUBLIC_ void ndr_print_netr_AcctLockStr(struct ndr_print *ndr, const char *name, const struct netr_AcctLockStr *r);
+_PUBLIC_ enum ndr_err_code ndr_push_netr_LogonParameterControl(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_LogonParameterControl(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+_PUBLIC_ void ndr_print_netr_LogonParameterControl(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_netr_IdentityInfo(struct ndr_print *ndr, const char *name, const struct netr_IdentityInfo *r);
+_PUBLIC_ void ndr_print_netr_PasswordInfo(struct ndr_print *ndr, const char *name, const struct netr_PasswordInfo *r);
+_PUBLIC_ void ndr_print_netr_ChallengeResponse(struct ndr_print *ndr, const char *name, const struct netr_ChallengeResponse *r);
+_PUBLIC_ void ndr_print_netr_NetworkInfo(struct ndr_print *ndr, const char *name, const struct netr_NetworkInfo *r);
+_PUBLIC_ enum ndr_err_code ndr_push_netr_LogonInfo(struct ndr_push *ndr, int ndr_flags, const union netr_LogonInfo *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_LogonInfo(struct ndr_pull *ndr, int ndr_flags, union netr_LogonInfo *r);
+_PUBLIC_ void ndr_print_netr_LogonInfo(struct ndr_print *ndr, const char *name, const union netr_LogonInfo *r);
+_PUBLIC_ enum ndr_err_code ndr_push_netr_UserSessionKey(struct ndr_push *ndr, int ndr_flags, const struct netr_UserSessionKey *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_UserSessionKey(struct ndr_pull *ndr, int ndr_flags, struct netr_UserSessionKey *r);
+_PUBLIC_ void ndr_print_netr_UserSessionKey(struct ndr_print *ndr, const char *name, const struct netr_UserSessionKey *r);
+_PUBLIC_ enum ndr_err_code ndr_push_netr_LMSessionKey(struct ndr_push *ndr, int ndr_flags, const struct netr_LMSessionKey *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_LMSessionKey(struct ndr_pull *ndr, int ndr_flags, struct netr_LMSessionKey *r);
+_PUBLIC_ void ndr_print_netr_LMSessionKey(struct ndr_print *ndr, const char *name, const struct netr_LMSessionKey *r);
+_PUBLIC_ enum ndr_err_code ndr_push_netr_UserFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_UserFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+_PUBLIC_ void ndr_print_netr_UserFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_netr_SamBaseInfo(struct ndr_print *ndr, const char *name, const struct netr_SamBaseInfo *r);
+_PUBLIC_ void ndr_print_netr_SamInfo2(struct ndr_print *ndr, const char *name, const struct netr_SamInfo2 *r);
+_PUBLIC_ void ndr_print_netr_SidAttr(struct ndr_print *ndr, const char *name, const struct netr_SidAttr *r);
+_PUBLIC_ enum ndr_err_code ndr_push_netr_SamInfo3(struct ndr_push *ndr, int ndr_flags, const struct netr_SamInfo3 *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_SamInfo3(struct ndr_pull *ndr, int ndr_flags, struct netr_SamInfo3 *r);
+_PUBLIC_ void ndr_print_netr_SamInfo3(struct ndr_print *ndr, const char *name, const struct netr_SamInfo3 *r);
+_PUBLIC_ void ndr_print_netr_SamInfo6(struct ndr_print *ndr, const char *name, const struct netr_SamInfo6 *r);
+_PUBLIC_ void ndr_print_netr_PacInfo(struct ndr_print *ndr, const char *name, const struct netr_PacInfo *r);
+_PUBLIC_ enum ndr_err_code ndr_push_netr_Validation(struct ndr_push *ndr, int ndr_flags, const union netr_Validation *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_Validation(struct ndr_pull *ndr, int ndr_flags, union netr_Validation *r);
+_PUBLIC_ void ndr_print_netr_Validation(struct ndr_print *ndr, const char *name, const union netr_Validation *r);
+_PUBLIC_ enum ndr_err_code ndr_push_netr_Credential(struct ndr_push *ndr, int ndr_flags, const struct netr_Credential *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_Credential(struct ndr_pull *ndr, int ndr_flags, struct netr_Credential *r);
+_PUBLIC_ void ndr_print_netr_Credential(struct ndr_print *ndr, const char *name, const struct netr_Credential *r);
+_PUBLIC_ enum ndr_err_code ndr_push_netr_Authenticator(struct ndr_push *ndr, int ndr_flags, const struct netr_Authenticator *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_Authenticator(struct ndr_pull *ndr, int ndr_flags, struct netr_Authenticator *r);
+_PUBLIC_ void ndr_print_netr_Authenticator(struct ndr_print *ndr, const char *name, const struct netr_Authenticator *r);
+_PUBLIC_ void ndr_print_netr_LogonLevel(struct ndr_print *ndr, const char *name, enum netr_LogonLevel r);
+_PUBLIC_ void ndr_print_netr_DELTA_DELETE_USER(struct ndr_print *ndr, const char *name, const struct netr_DELTA_DELETE_USER *r);
+_PUBLIC_ void ndr_print_netr_USER_KEY16(struct ndr_print *ndr, const char *name, const struct netr_USER_KEY16 *r);
+_PUBLIC_ void ndr_print_netr_PasswordHistory(struct ndr_print *ndr, const char *name, const struct netr_PasswordHistory *r);
+_PUBLIC_ void ndr_print_netr_USER_KEYS2(struct ndr_print *ndr, const char *name, const struct netr_USER_KEYS2 *r);
+_PUBLIC_ void ndr_print_netr_USER_KEY_UNION(struct ndr_print *ndr, const char *name, const struct netr_USER_KEY_UNION *r);
+_PUBLIC_ enum ndr_err_code ndr_push_netr_USER_KEYS(struct ndr_push *ndr, int ndr_flags, const struct netr_USER_KEYS *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_USER_KEYS(struct ndr_pull *ndr, int ndr_flags, struct netr_USER_KEYS *r);
+_PUBLIC_ void ndr_print_netr_USER_KEYS(struct ndr_print *ndr, const char *name, const struct netr_USER_KEYS *r);
+_PUBLIC_ void ndr_print_netr_USER_PRIVATE_INFO(struct ndr_print *ndr, const char *name, const struct netr_USER_PRIVATE_INFO *r);
+_PUBLIC_ void ndr_print_netr_DELTA_USER(struct ndr_print *ndr, const char *name, const struct netr_DELTA_USER *r);
+_PUBLIC_ void ndr_print_netr_DELTA_DOMAIN(struct ndr_print *ndr, const char *name, const struct netr_DELTA_DOMAIN *r);
+_PUBLIC_ void ndr_print_netr_DELTA_GROUP(struct ndr_print *ndr, const char *name, const struct netr_DELTA_GROUP *r);
+_PUBLIC_ void ndr_print_netr_DELTA_RENAME(struct ndr_print *ndr, const char *name, const struct netr_DELTA_RENAME *r);
+_PUBLIC_ void ndr_print_netr_DELTA_GROUP_MEMBER(struct ndr_print *ndr, const char *name, const struct netr_DELTA_GROUP_MEMBER *r);
+_PUBLIC_ void ndr_print_netr_DELTA_ALIAS(struct ndr_print *ndr, const char *name, const struct netr_DELTA_ALIAS *r);
+_PUBLIC_ void ndr_print_netr_DELTA_ALIAS_MEMBER(struct ndr_print *ndr, const char *name, const struct netr_DELTA_ALIAS_MEMBER *r);
+_PUBLIC_ void ndr_print_netr_QUOTA_LIMITS(struct ndr_print *ndr, const char *name, const struct netr_QUOTA_LIMITS *r);
+_PUBLIC_ void ndr_print_netr_DELTA_POLICY(struct ndr_print *ndr, const char *name, const struct netr_DELTA_POLICY *r);
+_PUBLIC_ void ndr_print_netr_DELTA_TRUSTED_DOMAIN(struct ndr_print *ndr, const char *name, const struct netr_DELTA_TRUSTED_DOMAIN *r);
+_PUBLIC_ void ndr_print_netr_DELTA_DELETE_TRUST(struct ndr_print *ndr, const char *name, const struct netr_DELTA_DELETE_TRUST *r);
+_PUBLIC_ void ndr_print_netr_DELTA_ACCOUNT(struct ndr_print *ndr, const char *name, const struct netr_DELTA_ACCOUNT *r);
+_PUBLIC_ void ndr_print_netr_DELTA_DELETE_ACCOUNT(struct ndr_print *ndr, const char *name, const struct netr_DELTA_DELETE_ACCOUNT *r);
+_PUBLIC_ void ndr_print_netr_DELTA_DELETE_SECRET(struct ndr_print *ndr, const char *name, const struct netr_DELTA_DELETE_SECRET *r);
+_PUBLIC_ void ndr_print_netr_CIPHER_VALUE(struct ndr_print *ndr, const char *name, const struct netr_CIPHER_VALUE *r);
+_PUBLIC_ void ndr_print_netr_DELTA_SECRET(struct ndr_print *ndr, const char *name, const struct netr_DELTA_SECRET *r);
+_PUBLIC_ void ndr_print_netr_DeltaEnum(struct ndr_print *ndr, const char *name, enum netr_DeltaEnum r);
+_PUBLIC_ void ndr_print_netr_DELTA_UNION(struct ndr_print *ndr, const char *name, const union netr_DELTA_UNION *r);
+_PUBLIC_ void ndr_print_netr_DELTA_ID_UNION(struct ndr_print *ndr, const char *name, const union netr_DELTA_ID_UNION *r);
+_PUBLIC_ void ndr_print_netr_DELTA_ENUM(struct ndr_print *ndr, const char *name, const struct netr_DELTA_ENUM *r);
+_PUBLIC_ void ndr_print_netr_DELTA_ENUM_ARRAY(struct ndr_print *ndr, const char *name, const struct netr_DELTA_ENUM_ARRAY *r);
+_PUBLIC_ void ndr_print_netr_UAS_INFO_0(struct ndr_print *ndr, const char *name, const struct netr_UAS_INFO_0 *r);
+_PUBLIC_ void ndr_print_netr_AccountBuffer(struct ndr_print *ndr, const char *name, const struct netr_AccountBuffer *r);
+_PUBLIC_ void ndr_print_netr_InfoFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_netr_NETLOGON_INFO_1(struct ndr_print *ndr, const char *name, const struct netr_NETLOGON_INFO_1 *r);
+_PUBLIC_ void ndr_print_netr_NETLOGON_INFO_2(struct ndr_print *ndr, const char *name, const struct netr_NETLOGON_INFO_2 *r);
+_PUBLIC_ void ndr_print_netr_NETLOGON_INFO_3(struct ndr_print *ndr, const char *name, const struct netr_NETLOGON_INFO_3 *r);
+_PUBLIC_ void ndr_print_netr_CONTROL_QUERY_INFORMATION(struct ndr_print *ndr, const char *name, const union netr_CONTROL_QUERY_INFORMATION *r);
+_PUBLIC_ void ndr_print_netr_LogonControlCode(struct ndr_print *ndr, const char *name, enum netr_LogonControlCode r);
+_PUBLIC_ void ndr_print_netr_CONTROL_DATA_INFORMATION(struct ndr_print *ndr, const char *name, const union netr_CONTROL_DATA_INFORMATION *r);
+_PUBLIC_ void ndr_print_netr_NegotiateFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_netr_Blob(struct ndr_print *ndr, const char *name, const struct netr_Blob *r);
+_PUBLIC_ void ndr_print_netr_DsRGetDCName_flags(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_netr_DsRGetDCNameInfo_AddressType(struct ndr_print *ndr, const char *name, enum netr_DsRGetDCNameInfo_AddressType r);
+_PUBLIC_ void ndr_print_netr_DsR_DcFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ enum ndr_err_code ndr_push_netr_DsRGetDCNameInfo(struct ndr_push *ndr, int ndr_flags, const struct netr_DsRGetDCNameInfo *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_DsRGetDCNameInfo(struct ndr_pull *ndr, int ndr_flags, struct netr_DsRGetDCNameInfo *r);
+_PUBLIC_ void ndr_print_netr_DsRGetDCNameInfo(struct ndr_print *ndr, const char *name, const struct netr_DsRGetDCNameInfo *r);
+_PUBLIC_ void ndr_print_netr_BinaryString(struct ndr_print *ndr, const char *name, const struct netr_BinaryString *r);
+_PUBLIC_ void ndr_print_netr_DomainQuery1(struct ndr_print *ndr, const char *name, const struct netr_DomainQuery1 *r);
+_PUBLIC_ void ndr_print_netr_DomainQuery(struct ndr_print *ndr, const char *name, const union netr_DomainQuery *r);
+_PUBLIC_ void ndr_print_netr_DomainTrustInfo(struct ndr_print *ndr, const char *name, const struct netr_DomainTrustInfo *r);
+_PUBLIC_ void ndr_print_netr_DomainInfo1(struct ndr_print *ndr, const char *name, const struct netr_DomainInfo1 *r);
+_PUBLIC_ void ndr_print_netr_DomainInfo(struct ndr_print *ndr, const char *name, const union netr_DomainInfo *r);
+_PUBLIC_ void ndr_print_netr_CryptPassword(struct ndr_print *ndr, const char *name, const struct netr_CryptPassword *r);
+_PUBLIC_ void ndr_print_netr_DsRAddressToSitenamesWCtr(struct ndr_print *ndr, const char *name, const struct netr_DsRAddressToSitenamesWCtr *r);
+_PUBLIC_ void ndr_print_netr_DsRAddress(struct ndr_print *ndr, const char *name, const struct netr_DsRAddress *r);
+_PUBLIC_ void ndr_print_netr_TrustFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_netr_TrustType(struct ndr_print *ndr, const char *name, enum netr_TrustType r);
+_PUBLIC_ void ndr_print_netr_TrustAttributes(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_netr_DomainTrust(struct ndr_print *ndr, const char *name, const struct netr_DomainTrust *r);
+_PUBLIC_ void ndr_print_netr_DomainTrustList(struct ndr_print *ndr, const char *name, const struct netr_DomainTrustList *r);
+_PUBLIC_ void ndr_print_netr_DsRAddressToSitenamesExWCtr(struct ndr_print *ndr, const char *name, const struct netr_DsRAddressToSitenamesExWCtr *r);
+_PUBLIC_ void ndr_print_DcSitesCtr(struct ndr_print *ndr, const char *name, const struct DcSitesCtr *r);
+_PUBLIC_ void ndr_print_netr_LogonUasLogon(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonUasLogon *r);
+_PUBLIC_ void ndr_print_netr_LogonUasLogoff(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonUasLogoff *r);
+_PUBLIC_ void ndr_print_netr_LogonSamLogon(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonSamLogon *r);
+_PUBLIC_ void ndr_print_netr_LogonSamLogoff(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonSamLogoff *r);
+_PUBLIC_ void ndr_print_netr_ServerReqChallenge(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerReqChallenge *r);
+_PUBLIC_ void ndr_print_netr_ServerAuthenticate(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerAuthenticate *r);
+_PUBLIC_ void ndr_print_netr_ServerPasswordSet(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerPasswordSet *r);
+_PUBLIC_ void ndr_print_netr_DatabaseDeltas(struct ndr_print *ndr, const char *name, int flags, const struct netr_DatabaseDeltas *r);
+_PUBLIC_ void ndr_print_netr_DatabaseSync(struct ndr_print *ndr, const char *name, int flags, const struct netr_DatabaseSync *r);
+_PUBLIC_ void ndr_print_netr_AccountDeltas(struct ndr_print *ndr, const char *name, int flags, const struct netr_AccountDeltas *r);
+_PUBLIC_ void ndr_print_netr_AccountSync(struct ndr_print *ndr, const char *name, int flags, const struct netr_AccountSync *r);
+_PUBLIC_ void ndr_print_netr_GetDcName(struct ndr_print *ndr, const char *name, int flags, const struct netr_GetDcName *r);
+_PUBLIC_ void ndr_print_netr_LogonControl(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonControl *r);
+_PUBLIC_ void ndr_print_netr_GetAnyDCName(struct ndr_print *ndr, const char *name, int flags, const struct netr_GetAnyDCName *r);
+_PUBLIC_ void ndr_print_netr_LogonControl2(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonControl2 *r);
+_PUBLIC_ void ndr_print_netr_ServerAuthenticate2(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerAuthenticate2 *r);
+_PUBLIC_ void ndr_print_netr_DatabaseSync2(struct ndr_print *ndr, const char *name, int flags, const struct netr_DatabaseSync2 *r);
+_PUBLIC_ void ndr_print_netr_DatabaseRedo(struct ndr_print *ndr, const char *name, int flags, const struct netr_DatabaseRedo *r);
+_PUBLIC_ void ndr_print_netr_LogonControl2Ex(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonControl2Ex *r);
+_PUBLIC_ void ndr_print_netr_NetrEnumerateTrustedDomains(struct ndr_print *ndr, const char *name, int flags, const struct netr_NetrEnumerateTrustedDomains *r);
+_PUBLIC_ void ndr_print_netr_DsRGetDCName(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRGetDCName *r);
+_PUBLIC_ void ndr_print_netr_NETRLOGONDUMMYROUTINE1(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONDUMMYROUTINE1 *r);
+_PUBLIC_ void ndr_print_netr_NETRLOGONSETSERVICEBITS(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONSETSERVICEBITS *r);
+_PUBLIC_ void ndr_print_netr_LogonGetTrustRid(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonGetTrustRid *r);
+_PUBLIC_ void ndr_print_netr_NETRLOGONCOMPUTESERVERDIGEST(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONCOMPUTESERVERDIGEST *r);
+_PUBLIC_ void ndr_print_netr_NETRLOGONCOMPUTECLIENTDIGEST(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONCOMPUTECLIENTDIGEST *r);
+_PUBLIC_ void ndr_print_netr_ServerAuthenticate3(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerAuthenticate3 *r);
+_PUBLIC_ void ndr_print_netr_DsRGetDCNameEx(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRGetDCNameEx *r);
+_PUBLIC_ void ndr_print_netr_DsRGetSiteName(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRGetSiteName *r);
+_PUBLIC_ void ndr_print_netr_LogonGetDomainInfo(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonGetDomainInfo *r);
+_PUBLIC_ void ndr_print_netr_ServerPasswordSet2(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerPasswordSet2 *r);
+_PUBLIC_ void ndr_print_netr_ServerPasswordGet(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerPasswordGet *r);
+_PUBLIC_ void ndr_print_netr_NETRLOGONSENDTOSAM(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONSENDTOSAM *r);
+_PUBLIC_ void ndr_print_netr_DsRAddressToSitenamesW(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRAddressToSitenamesW *r);
+_PUBLIC_ void ndr_print_netr_DsRGetDCNameEx2(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRGetDCNameEx2 *r);
+_PUBLIC_ void ndr_print_netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN *r);
+_PUBLIC_ void ndr_print_netr_NetrEnumerateTrustedDomainsEx(struct ndr_print *ndr, const char *name, int flags, const struct netr_NetrEnumerateTrustedDomainsEx *r);
+_PUBLIC_ void ndr_print_netr_DsRAddressToSitenamesExW(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRAddressToSitenamesExW *r);
+_PUBLIC_ void ndr_print_netr_DsrGetDcSiteCoverageW(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsrGetDcSiteCoverageW *r);
+_PUBLIC_ void ndr_print_netr_LogonSamLogonEx(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonSamLogonEx *r);
+_PUBLIC_ void ndr_print_netr_DsrEnumerateDomainTrusts(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsrEnumerateDomainTrusts *r);
+_PUBLIC_ void ndr_print_netr_DsrDeregisterDNSHostRecords(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsrDeregisterDNSHostRecords *r);
+_PUBLIC_ void ndr_print_netr_ServerTrustPasswordsGet(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerTrustPasswordsGet *r);
+_PUBLIC_ void ndr_print_netr_DsRGetForestTrustInformation(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRGetForestTrustInformation *r);
+_PUBLIC_ void ndr_print_netr_GetForestTrustInformation(struct ndr_print *ndr, const char *name, int flags, const struct netr_GetForestTrustInformation *r);
+_PUBLIC_ void ndr_print_netr_LogonSamLogonWithFlags(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonSamLogonWithFlags *r);
+_PUBLIC_ void ndr_print_netr_NETRSERVERGETTRUSTINFO(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRSERVERGETTRUSTINFO *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_notify.c */
+
+_PUBLIC_ enum ndr_err_code ndr_push_notify_entry(struct ndr_push *ndr, int ndr_flags, const struct notify_entry *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_notify_entry(struct ndr_pull *ndr, int ndr_flags, struct notify_entry *r);
+_PUBLIC_ void ndr_print_notify_entry(struct ndr_print *ndr, const char *name, const struct notify_entry *r);
+_PUBLIC_ void ndr_print_notify_depth(struct ndr_print *ndr, const char *name, const struct notify_depth *r);
+_PUBLIC_ enum ndr_err_code ndr_push_notify_array(struct ndr_push *ndr, int ndr_flags, const struct notify_array *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_notify_array(struct ndr_pull *ndr, int ndr_flags, struct notify_array *r);
+_PUBLIC_ void ndr_print_notify_array(struct ndr_print *ndr, const char *name, const struct notify_array *r);
+_PUBLIC_ enum ndr_err_code ndr_push_notify_event(struct ndr_push *ndr, int ndr_flags, const struct notify_event *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_notify_event(struct ndr_pull *ndr, int ndr_flags, struct notify_event *r);
+_PUBLIC_ void ndr_print_notify_event(struct ndr_print *ndr, const char *name, const struct notify_event *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_ntsvcs.c */
+
+_PUBLIC_ void ndr_print_PNP_HwProfInfo(struct ndr_print *ndr, const char *name, const struct PNP_HwProfInfo *r);
+_PUBLIC_ void ndr_print_PNP_Disconnect(struct ndr_print *ndr, const char *name, int flags, const struct PNP_Disconnect *r);
+_PUBLIC_ void ndr_print_PNP_Connect(struct ndr_print *ndr, const char *name, int flags, const struct PNP_Connect *r);
+_PUBLIC_ void ndr_print_PNP_GetVersion(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetVersion *r);
+_PUBLIC_ void ndr_print_PNP_GetGlobalState(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetGlobalState *r);
+_PUBLIC_ void ndr_print_PNP_InitDetection(struct ndr_print *ndr, const char *name, int flags, const struct PNP_InitDetection *r);
+_PUBLIC_ void ndr_print_PNP_ReportLogOn(struct ndr_print *ndr, const char *name, int flags, const struct PNP_ReportLogOn *r);
+_PUBLIC_ void ndr_print_PNP_ValidateDeviceInstance(struct ndr_print *ndr, const char *name, int flags, const struct PNP_ValidateDeviceInstance *r);
+_PUBLIC_ void ndr_print_PNP_GetRootDeviceInstance(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetRootDeviceInstance *r);
+_PUBLIC_ void ndr_print_PNP_GetRelatedDeviceInstance(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetRelatedDeviceInstance *r);
+_PUBLIC_ void ndr_print_PNP_EnumerateSubKeys(struct ndr_print *ndr, const char *name, int flags, const struct PNP_EnumerateSubKeys *r);
+_PUBLIC_ void ndr_print_PNP_GetDeviceList(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetDeviceList *r);
+_PUBLIC_ void ndr_print_PNP_GetDeviceListSize(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetDeviceListSize *r);
+_PUBLIC_ void ndr_print_PNP_GetDepth(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetDepth *r);
+_PUBLIC_ void ndr_print_PNP_GetDeviceRegProp(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetDeviceRegProp *r);
+_PUBLIC_ void ndr_print_PNP_SetDeviceRegProp(struct ndr_print *ndr, const char *name, int flags, const struct PNP_SetDeviceRegProp *r);
+_PUBLIC_ void ndr_print_PNP_GetClassInstance(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetClassInstance *r);
+_PUBLIC_ void ndr_print_PNP_CreateKey(struct ndr_print *ndr, const char *name, int flags, const struct PNP_CreateKey *r);
+_PUBLIC_ void ndr_print_PNP_DeleteRegistryKey(struct ndr_print *ndr, const char *name, int flags, const struct PNP_DeleteRegistryKey *r);
+_PUBLIC_ void ndr_print_PNP_GetClassCount(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetClassCount *r);
+_PUBLIC_ void ndr_print_PNP_GetClassName(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetClassName *r);
+_PUBLIC_ void ndr_print_PNP_DeleteClassKey(struct ndr_print *ndr, const char *name, int flags, const struct PNP_DeleteClassKey *r);
+_PUBLIC_ void ndr_print_PNP_GetInterfaceDeviceAlias(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetInterfaceDeviceAlias *r);
+_PUBLIC_ void ndr_print_PNP_GetInterfaceDeviceList(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetInterfaceDeviceList *r);
+_PUBLIC_ void ndr_print_PNP_GetInterfaceDeviceListSize(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetInterfaceDeviceListSize *r);
+_PUBLIC_ void ndr_print_PNP_RegisterDeviceClassAssociation(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RegisterDeviceClassAssociation *r);
+_PUBLIC_ void ndr_print_PNP_UnregisterDeviceClassAssociation(struct ndr_print *ndr, const char *name, int flags, const struct PNP_UnregisterDeviceClassAssociation *r);
+_PUBLIC_ void ndr_print_PNP_GetClassRegProp(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetClassRegProp *r);
+_PUBLIC_ void ndr_print_PNP_SetClassRegProp(struct ndr_print *ndr, const char *name, int flags, const struct PNP_SetClassRegProp *r);
+_PUBLIC_ void ndr_print_PNP_CreateDevInst(struct ndr_print *ndr, const char *name, int flags, const struct PNP_CreateDevInst *r);
+_PUBLIC_ void ndr_print_PNP_DeviceInstanceAction(struct ndr_print *ndr, const char *name, int flags, const struct PNP_DeviceInstanceAction *r);
+_PUBLIC_ void ndr_print_PNP_GetDeviceStatus(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetDeviceStatus *r);
+_PUBLIC_ void ndr_print_PNP_SetDeviceProblem(struct ndr_print *ndr, const char *name, int flags, const struct PNP_SetDeviceProblem *r);
+_PUBLIC_ void ndr_print_PNP_DisableDevInst(struct ndr_print *ndr, const char *name, int flags, const struct PNP_DisableDevInst *r);
+_PUBLIC_ void ndr_print_PNP_UninstallDevInst(struct ndr_print *ndr, const char *name, int flags, const struct PNP_UninstallDevInst *r);
+_PUBLIC_ void ndr_print_PNP_AddID(struct ndr_print *ndr, const char *name, int flags, const struct PNP_AddID *r);
+_PUBLIC_ void ndr_print_PNP_RegisterDriver(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RegisterDriver *r);
+_PUBLIC_ void ndr_print_PNP_QueryRemove(struct ndr_print *ndr, const char *name, int flags, const struct PNP_QueryRemove *r);
+_PUBLIC_ void ndr_print_PNP_RequestDeviceEject(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RequestDeviceEject *r);
+_PUBLIC_ void ndr_print_PNP_IsDockStationPresent(struct ndr_print *ndr, const char *name, int flags, const struct PNP_IsDockStationPresent *r);
+_PUBLIC_ void ndr_print_PNP_RequestEjectPC(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RequestEjectPC *r);
+_PUBLIC_ void ndr_print_PNP_HwProfFlags(struct ndr_print *ndr, const char *name, int flags, const struct PNP_HwProfFlags *r);
+_PUBLIC_ void ndr_print_PNP_GetHwProfInfo(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetHwProfInfo *r);
+_PUBLIC_ void ndr_print_PNP_AddEmptyLogConf(struct ndr_print *ndr, const char *name, int flags, const struct PNP_AddEmptyLogConf *r);
+_PUBLIC_ void ndr_print_PNP_FreeLogConf(struct ndr_print *ndr, const char *name, int flags, const struct PNP_FreeLogConf *r);
+_PUBLIC_ void ndr_print_PNP_GetFirstLogConf(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetFirstLogConf *r);
+_PUBLIC_ void ndr_print_PNP_GetNextLogConf(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetNextLogConf *r);
+_PUBLIC_ void ndr_print_PNP_GetLogConfPriority(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetLogConfPriority *r);
+_PUBLIC_ void ndr_print_PNP_AddResDes(struct ndr_print *ndr, const char *name, int flags, const struct PNP_AddResDes *r);
+_PUBLIC_ void ndr_print_PNP_FreeResDes(struct ndr_print *ndr, const char *name, int flags, const struct PNP_FreeResDes *r);
+_PUBLIC_ void ndr_print_PNP_GetNextResDes(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetNextResDes *r);
+_PUBLIC_ void ndr_print_PNP_GetResDesData(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetResDesData *r);
+_PUBLIC_ void ndr_print_PNP_GetResDesDataSize(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetResDesDataSize *r);
+_PUBLIC_ void ndr_print_PNP_ModifyResDes(struct ndr_print *ndr, const char *name, int flags, const struct PNP_ModifyResDes *r);
+_PUBLIC_ void ndr_print_PNP_DetectResourceLimit(struct ndr_print *ndr, const char *name, int flags, const struct PNP_DetectResourceLimit *r);
+_PUBLIC_ void ndr_print_PNP_QueryResConfList(struct ndr_print *ndr, const char *name, int flags, const struct PNP_QueryResConfList *r);
+_PUBLIC_ void ndr_print_PNP_SetHwProf(struct ndr_print *ndr, const char *name, int flags, const struct PNP_SetHwProf *r);
+_PUBLIC_ void ndr_print_PNP_QueryArbitratorFreeData(struct ndr_print *ndr, const char *name, int flags, const struct PNP_QueryArbitratorFreeData *r);
+_PUBLIC_ void ndr_print_PNP_QueryArbitratorFreeSize(struct ndr_print *ndr, const char *name, int flags, const struct PNP_QueryArbitratorFreeSize *r);
+_PUBLIC_ void ndr_print_PNP_RunDetection(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RunDetection *r);
+_PUBLIC_ void ndr_print_PNP_RegisterNotification(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RegisterNotification *r);
+_PUBLIC_ void ndr_print_PNP_UnregisterNotification(struct ndr_print *ndr, const char *name, int flags, const struct PNP_UnregisterNotification *r);
+_PUBLIC_ void ndr_print_PNP_GetCustomDevProp(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetCustomDevProp *r);
+_PUBLIC_ void ndr_print_PNP_GetVersionInternal(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetVersionInternal *r);
+_PUBLIC_ void ndr_print_PNP_GetBlockedDriverInfo(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetBlockedDriverInfo *r);
+_PUBLIC_ void ndr_print_PNP_GetServerSideDeviceInstallFlags(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetServerSideDeviceInstallFlags *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_samr.c */
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_AcctFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_AcctFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+_PUBLIC_ void ndr_print_samr_AcctFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_samr_ConnectAccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_samr_UserAccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_samr_DomainAccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_samr_GroupAccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_samr_AliasAccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_samr_SamEntry(struct ndr_print *ndr, const char *name, const struct samr_SamEntry *r);
+_PUBLIC_ void ndr_print_samr_SamArray(struct ndr_print *ndr, const char *name, const struct samr_SamArray *r);
+_PUBLIC_ void ndr_print_samr_Role(struct ndr_print *ndr, const char *name, enum samr_Role r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_PasswordProperties(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_PasswordProperties(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+_PUBLIC_ void ndr_print_samr_PasswordProperties(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_samr_DomInfo1(struct ndr_print *ndr, const char *name, const struct samr_DomInfo1 *r);
+_PUBLIC_ void ndr_print_samr_DomInfo2(struct ndr_print *ndr, const char *name, const struct samr_DomInfo2 *r);
+_PUBLIC_ void ndr_print_samr_DomInfo3(struct ndr_print *ndr, const char *name, const struct samr_DomInfo3 *r);
+_PUBLIC_ void ndr_print_samr_DomInfo4(struct ndr_print *ndr, const char *name, const struct samr_DomInfo4 *r);
+_PUBLIC_ void ndr_print_samr_DomInfo5(struct ndr_print *ndr, const char *name, const struct samr_DomInfo5 *r);
+_PUBLIC_ void ndr_print_samr_DomInfo6(struct ndr_print *ndr, const char *name, const struct samr_DomInfo6 *r);
+_PUBLIC_ void ndr_print_samr_DomInfo7(struct ndr_print *ndr, const char *name, const struct samr_DomInfo7 *r);
+_PUBLIC_ void ndr_print_samr_DomInfo8(struct ndr_print *ndr, const char *name, const struct samr_DomInfo8 *r);
+_PUBLIC_ void ndr_print_samr_DomInfo9(struct ndr_print *ndr, const char *name, const struct samr_DomInfo9 *r);
+_PUBLIC_ void ndr_print_samr_DomInfo11(struct ndr_print *ndr, const char *name, const struct samr_DomInfo11 *r);
+_PUBLIC_ void ndr_print_samr_DomInfo12(struct ndr_print *ndr, const char *name, const struct samr_DomInfo12 *r);
+_PUBLIC_ void ndr_print_samr_DomInfo13(struct ndr_print *ndr, const char *name, const struct samr_DomInfo13 *r);
+_PUBLIC_ void ndr_print_samr_DomainInfo(struct ndr_print *ndr, const char *name, const union samr_DomainInfo *r);
+_PUBLIC_ void ndr_print_samr_Ids(struct ndr_print *ndr, const char *name, const struct samr_Ids *r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_GroupAttrs(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_GroupAttrs(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+_PUBLIC_ void ndr_print_samr_GroupAttrs(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_samr_GroupInfoAll(struct ndr_print *ndr, const char *name, const struct samr_GroupInfoAll *r);
+_PUBLIC_ void ndr_print_samr_GroupInfoAttributes(struct ndr_print *ndr, const char *name, const struct samr_GroupInfoAttributes *r);
+_PUBLIC_ void ndr_print_samr_GroupInfoEnum(struct ndr_print *ndr, const char *name, enum samr_GroupInfoEnum r);
+_PUBLIC_ void ndr_print_samr_GroupInfo(struct ndr_print *ndr, const char *name, const union samr_GroupInfo *r);
+_PUBLIC_ void ndr_print_samr_RidTypeArray(struct ndr_print *ndr, const char *name, const struct samr_RidTypeArray *r);
+_PUBLIC_ void ndr_print_samr_AliasInfoAll(struct ndr_print *ndr, const char *name, const struct samr_AliasInfoAll *r);
+_PUBLIC_ void ndr_print_samr_AliasInfoEnum(struct ndr_print *ndr, const char *name, enum samr_AliasInfoEnum r);
+_PUBLIC_ void ndr_print_samr_AliasInfo(struct ndr_print *ndr, const char *name, const union samr_AliasInfo *r);
+_PUBLIC_ void ndr_print_samr_UserInfo1(struct ndr_print *ndr, const char *name, const struct samr_UserInfo1 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo2(struct ndr_print *ndr, const char *name, const struct samr_UserInfo2 *r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_LogonHours(struct ndr_push *ndr, int ndr_flags, const struct samr_LogonHours *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_LogonHours(struct ndr_pull *ndr, int ndr_flags, struct samr_LogonHours *r);
+_PUBLIC_ void ndr_print_samr_LogonHours(struct ndr_print *ndr, const char *name, const struct samr_LogonHours *r);
+_PUBLIC_ void ndr_print_samr_UserInfo3(struct ndr_print *ndr, const char *name, const struct samr_UserInfo3 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo4(struct ndr_print *ndr, const char *name, const struct samr_UserInfo4 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo5(struct ndr_print *ndr, const char *name, const struct samr_UserInfo5 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo6(struct ndr_print *ndr, const char *name, const struct samr_UserInfo6 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo7(struct ndr_print *ndr, const char *name, const struct samr_UserInfo7 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo8(struct ndr_print *ndr, const char *name, const struct samr_UserInfo8 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo9(struct ndr_print *ndr, const char *name, const struct samr_UserInfo9 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo10(struct ndr_print *ndr, const char *name, const struct samr_UserInfo10 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo11(struct ndr_print *ndr, const char *name, const struct samr_UserInfo11 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo12(struct ndr_print *ndr, const char *name, const struct samr_UserInfo12 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo13(struct ndr_print *ndr, const char *name, const struct samr_UserInfo13 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo14(struct ndr_print *ndr, const char *name, const struct samr_UserInfo14 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo16(struct ndr_print *ndr, const char *name, const struct samr_UserInfo16 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo17(struct ndr_print *ndr, const char *name, const struct samr_UserInfo17 *r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_Password(struct ndr_push *ndr, int ndr_flags, const struct samr_Password *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_Password(struct ndr_pull *ndr, int ndr_flags, struct samr_Password *r);
+_PUBLIC_ void ndr_print_samr_Password(struct ndr_print *ndr, const char *name, const struct samr_Password *r);
+_PUBLIC_ void ndr_print_samr_UserInfo18(struct ndr_print *ndr, const char *name, const struct samr_UserInfo18 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo20(struct ndr_print *ndr, const char *name, const struct samr_UserInfo20 *r);
+_PUBLIC_ void ndr_print_samr_FieldsPresent(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_samr_UserInfo21(struct ndr_print *ndr, const char *name, const struct samr_UserInfo21 *r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_CryptPassword(struct ndr_push *ndr, int ndr_flags, const struct samr_CryptPassword *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_CryptPassword(struct ndr_pull *ndr, int ndr_flags, struct samr_CryptPassword *r);
+_PUBLIC_ void ndr_print_samr_CryptPassword(struct ndr_print *ndr, const char *name, const struct samr_CryptPassword *r);
+_PUBLIC_ void ndr_print_samr_UserInfo23(struct ndr_print *ndr, const char *name, const struct samr_UserInfo23 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo24(struct ndr_print *ndr, const char *name, const struct samr_UserInfo24 *r);
+_PUBLIC_ void ndr_print_samr_CryptPasswordEx(struct ndr_print *ndr, const char *name, const struct samr_CryptPasswordEx *r);
+_PUBLIC_ void ndr_print_samr_UserInfo25(struct ndr_print *ndr, const char *name, const struct samr_UserInfo25 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo26(struct ndr_print *ndr, const char *name, const struct samr_UserInfo26 *r);
+_PUBLIC_ void ndr_print_samr_UserInfo(struct ndr_print *ndr, const char *name, const union samr_UserInfo *r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_RidWithAttribute(struct ndr_push *ndr, int ndr_flags, const struct samr_RidWithAttribute *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_RidWithAttribute(struct ndr_pull *ndr, int ndr_flags, struct samr_RidWithAttribute *r);
+_PUBLIC_ void ndr_print_samr_RidWithAttribute(struct ndr_print *ndr, const char *name, const struct samr_RidWithAttribute *r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_RidWithAttributeArray(struct ndr_push *ndr, int ndr_flags, const struct samr_RidWithAttributeArray *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_RidWithAttributeArray(struct ndr_pull *ndr, int ndr_flags, struct samr_RidWithAttributeArray *r);
+_PUBLIC_ void ndr_print_samr_RidWithAttributeArray(struct ndr_print *ndr, const char *name, const struct samr_RidWithAttributeArray *r);
+_PUBLIC_ void ndr_print_samr_DispEntryGeneral(struct ndr_print *ndr, const char *name, const struct samr_DispEntryGeneral *r);
+_PUBLIC_ void ndr_print_samr_DispInfoGeneral(struct ndr_print *ndr, const char *name, const struct samr_DispInfoGeneral *r);
+_PUBLIC_ void ndr_print_samr_DispEntryFull(struct ndr_print *ndr, const char *name, const struct samr_DispEntryFull *r);
+_PUBLIC_ void ndr_print_samr_DispInfoFull(struct ndr_print *ndr, const char *name, const struct samr_DispInfoFull *r);
+_PUBLIC_ void ndr_print_samr_DispEntryFullGroup(struct ndr_print *ndr, const char *name, const struct samr_DispEntryFullGroup *r);
+_PUBLIC_ void ndr_print_samr_DispInfoFullGroups(struct ndr_print *ndr, const char *name, const struct samr_DispInfoFullGroups *r);
+_PUBLIC_ void ndr_print_samr_DispEntryAscii(struct ndr_print *ndr, const char *name, const struct samr_DispEntryAscii *r);
+_PUBLIC_ void ndr_print_samr_DispInfoAscii(struct ndr_print *ndr, const char *name, const struct samr_DispInfoAscii *r);
+_PUBLIC_ void ndr_print_samr_DispInfo(struct ndr_print *ndr, const char *name, const union samr_DispInfo *r);
+_PUBLIC_ void ndr_print_samr_PwInfo(struct ndr_print *ndr, const char *name, const struct samr_PwInfo *r);
+_PUBLIC_ void ndr_print_samr_ConnectVersion(struct ndr_print *ndr, const char *name, enum samr_ConnectVersion r);
+_PUBLIC_ void ndr_print_samr_ChangeReject(struct ndr_print *ndr, const char *name, const struct samr_ChangeReject *r);
+_PUBLIC_ void ndr_print_samr_ConnectInfo1(struct ndr_print *ndr, const char *name, const struct samr_ConnectInfo1 *r);
+_PUBLIC_ void ndr_print_samr_ConnectInfo(struct ndr_print *ndr, const char *name, const union samr_ConnectInfo *r);
+_PUBLIC_ void ndr_print_samr_ValidateFieldsPresent(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_samr_ValidatePasswordLevel(struct ndr_print *ndr, const char *name, enum samr_ValidatePasswordLevel r);
+_PUBLIC_ void ndr_print_samr_ValidationStatus(struct ndr_print *ndr, const char *name, enum samr_ValidationStatus r);
+_PUBLIC_ void ndr_print_samr_ValidationBlob(struct ndr_print *ndr, const char *name, const struct samr_ValidationBlob *r);
+_PUBLIC_ void ndr_print_samr_ValidatePasswordInfo(struct ndr_print *ndr, const char *name, const struct samr_ValidatePasswordInfo *r);
+_PUBLIC_ void ndr_print_samr_ValidatePasswordRepCtr(struct ndr_print *ndr, const char *name, const struct samr_ValidatePasswordRepCtr *r);
+_PUBLIC_ void ndr_print_samr_ValidatePasswordRep(struct ndr_print *ndr, const char *name, const union samr_ValidatePasswordRep *r);
+_PUBLIC_ void ndr_print_samr_ValidatePasswordReq3(struct ndr_print *ndr, const char *name, const struct samr_ValidatePasswordReq3 *r);
+_PUBLIC_ void ndr_print_samr_ValidatePasswordReq2(struct ndr_print *ndr, const char *name, const struct samr_ValidatePasswordReq2 *r);
+_PUBLIC_ void ndr_print_samr_ValidatePasswordReq1(struct ndr_print *ndr, const char *name, const struct samr_ValidatePasswordReq1 *r);
+_PUBLIC_ void ndr_print_samr_ValidatePasswordReq(struct ndr_print *ndr, const char *name, const union samr_ValidatePasswordReq *r);
+_PUBLIC_ void ndr_print_samr_Connect(struct ndr_print *ndr, const char *name, int flags, const struct samr_Connect *r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_Close(struct ndr_push *ndr, int flags, const struct samr_Close *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_Close(struct ndr_pull *ndr, int flags, struct samr_Close *r);
+_PUBLIC_ void ndr_print_samr_Close(struct ndr_print *ndr, const char *name, int flags, const struct samr_Close *r);
+_PUBLIC_ void ndr_print_samr_SetSecurity(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetSecurity *r);
+_PUBLIC_ void ndr_print_samr_QuerySecurity(struct ndr_print *ndr, const char *name, int flags, const struct samr_QuerySecurity *r);
+_PUBLIC_ void ndr_print_samr_Shutdown(struct ndr_print *ndr, const char *name, int flags, const struct samr_Shutdown *r);
+_PUBLIC_ void ndr_print_samr_LookupDomain(struct ndr_print *ndr, const char *name, int flags, const struct samr_LookupDomain *r);
+_PUBLIC_ void ndr_print_samr_EnumDomains(struct ndr_print *ndr, const char *name, int flags, const struct samr_EnumDomains *r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_OpenDomain(struct ndr_push *ndr, int flags, const struct samr_OpenDomain *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_OpenDomain(struct ndr_pull *ndr, int flags, struct samr_OpenDomain *r);
+_PUBLIC_ void ndr_print_samr_OpenDomain(struct ndr_print *ndr, const char *name, int flags, const struct samr_OpenDomain *r);
+_PUBLIC_ void ndr_print_samr_QueryDomainInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryDomainInfo *r);
+_PUBLIC_ void ndr_print_samr_SetDomainInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetDomainInfo *r);
+_PUBLIC_ void ndr_print_samr_CreateDomainGroup(struct ndr_print *ndr, const char *name, int flags, const struct samr_CreateDomainGroup *r);
+_PUBLIC_ void ndr_print_samr_EnumDomainGroups(struct ndr_print *ndr, const char *name, int flags, const struct samr_EnumDomainGroups *r);
+_PUBLIC_ void ndr_print_samr_CreateUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_CreateUser *r);
+_PUBLIC_ void ndr_print_samr_EnumDomainUsers(struct ndr_print *ndr, const char *name, int flags, const struct samr_EnumDomainUsers *r);
+_PUBLIC_ void ndr_print_samr_CreateDomAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_CreateDomAlias *r);
+_PUBLIC_ void ndr_print_samr_EnumDomainAliases(struct ndr_print *ndr, const char *name, int flags, const struct samr_EnumDomainAliases *r);
+_PUBLIC_ void ndr_print_samr_GetAliasMembership(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetAliasMembership *r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_LookupNames(struct ndr_push *ndr, int flags, const struct samr_LookupNames *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_LookupNames(struct ndr_pull *ndr, int flags, struct samr_LookupNames *r);
+_PUBLIC_ void ndr_print_samr_LookupNames(struct ndr_print *ndr, const char *name, int flags, const struct samr_LookupNames *r);
+_PUBLIC_ void ndr_print_samr_LookupRids(struct ndr_print *ndr, const char *name, int flags, const struct samr_LookupRids *r);
+_PUBLIC_ void ndr_print_samr_OpenGroup(struct ndr_print *ndr, const char *name, int flags, const struct samr_OpenGroup *r);
+_PUBLIC_ void ndr_print_samr_QueryGroupInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryGroupInfo *r);
+_PUBLIC_ void ndr_print_samr_SetGroupInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetGroupInfo *r);
+_PUBLIC_ void ndr_print_samr_AddGroupMember(struct ndr_print *ndr, const char *name, int flags, const struct samr_AddGroupMember *r);
+_PUBLIC_ void ndr_print_samr_DeleteDomainGroup(struct ndr_print *ndr, const char *name, int flags, const struct samr_DeleteDomainGroup *r);
+_PUBLIC_ void ndr_print_samr_DeleteGroupMember(struct ndr_print *ndr, const char *name, int flags, const struct samr_DeleteGroupMember *r);
+_PUBLIC_ void ndr_print_samr_QueryGroupMember(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryGroupMember *r);
+_PUBLIC_ void ndr_print_samr_SetMemberAttributesOfGroup(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetMemberAttributesOfGroup *r);
+_PUBLIC_ void ndr_print_samr_OpenAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_OpenAlias *r);
+_PUBLIC_ void ndr_print_samr_QueryAliasInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryAliasInfo *r);
+_PUBLIC_ void ndr_print_samr_SetAliasInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetAliasInfo *r);
+_PUBLIC_ void ndr_print_samr_DeleteDomAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_DeleteDomAlias *r);
+_PUBLIC_ void ndr_print_samr_AddAliasMember(struct ndr_print *ndr, const char *name, int flags, const struct samr_AddAliasMember *r);
+_PUBLIC_ void ndr_print_samr_DeleteAliasMember(struct ndr_print *ndr, const char *name, int flags, const struct samr_DeleteAliasMember *r);
+_PUBLIC_ void ndr_print_samr_GetMembersInAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetMembersInAlias *r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_OpenUser(struct ndr_push *ndr, int flags, const struct samr_OpenUser *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_OpenUser(struct ndr_pull *ndr, int flags, struct samr_OpenUser *r);
+_PUBLIC_ void ndr_print_samr_OpenUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_OpenUser *r);
+_PUBLIC_ void ndr_print_samr_DeleteUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_DeleteUser *r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_QueryUserInfo(struct ndr_push *ndr, int flags, const struct samr_QueryUserInfo *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_QueryUserInfo(struct ndr_pull *ndr, int flags, struct samr_QueryUserInfo *r);
+_PUBLIC_ void ndr_print_samr_QueryUserInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryUserInfo *r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_SetUserInfo(struct ndr_push *ndr, int flags, const struct samr_SetUserInfo *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_SetUserInfo(struct ndr_pull *ndr, int flags, struct samr_SetUserInfo *r);
+_PUBLIC_ void ndr_print_samr_SetUserInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetUserInfo *r);
+_PUBLIC_ void ndr_print_samr_ChangePasswordUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_ChangePasswordUser *r);
+_PUBLIC_ void ndr_print_samr_GetGroupsForUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetGroupsForUser *r);
+_PUBLIC_ void ndr_print_samr_QueryDisplayInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryDisplayInfo *r);
+_PUBLIC_ void ndr_print_samr_GetDisplayEnumerationIndex(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetDisplayEnumerationIndex *r);
+_PUBLIC_ void ndr_print_samr_TestPrivateFunctionsDomain(struct ndr_print *ndr, const char *name, int flags, const struct samr_TestPrivateFunctionsDomain *r);
+_PUBLIC_ void ndr_print_samr_TestPrivateFunctionsUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_TestPrivateFunctionsUser *r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_GetUserPwInfo(struct ndr_push *ndr, int flags, const struct samr_GetUserPwInfo *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_GetUserPwInfo(struct ndr_pull *ndr, int flags, struct samr_GetUserPwInfo *r);
+_PUBLIC_ void ndr_print_samr_GetUserPwInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetUserPwInfo *r);
+_PUBLIC_ void ndr_print_samr_RemoveMemberFromForeignDomain(struct ndr_print *ndr, const char *name, int flags, const struct samr_RemoveMemberFromForeignDomain *r);
+_PUBLIC_ void ndr_print_samr_QueryDomainInfo2(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryDomainInfo2 *r);
+_PUBLIC_ void ndr_print_samr_QueryUserInfo2(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryUserInfo2 *r);
+_PUBLIC_ void ndr_print_samr_QueryDisplayInfo2(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryDisplayInfo2 *r);
+_PUBLIC_ void ndr_print_samr_GetDisplayEnumerationIndex2(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetDisplayEnumerationIndex2 *r);
+_PUBLIC_ void ndr_print_samr_CreateUser2(struct ndr_print *ndr, const char *name, int flags, const struct samr_CreateUser2 *r);
+_PUBLIC_ void ndr_print_samr_QueryDisplayInfo3(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryDisplayInfo3 *r);
+_PUBLIC_ void ndr_print_samr_AddMultipleMembersToAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_AddMultipleMembersToAlias *r);
+_PUBLIC_ void ndr_print_samr_RemoveMultipleMembersFromAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_RemoveMultipleMembersFromAlias *r);
+_PUBLIC_ void ndr_print_samr_OemChangePasswordUser2(struct ndr_print *ndr, const char *name, int flags, const struct samr_OemChangePasswordUser2 *r);
+_PUBLIC_ void ndr_print_samr_ChangePasswordUser2(struct ndr_print *ndr, const char *name, int flags, const struct samr_ChangePasswordUser2 *r);
+_PUBLIC_ void ndr_print_samr_GetDomPwInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetDomPwInfo *r);
+_PUBLIC_ void ndr_print_samr_Connect2(struct ndr_print *ndr, const char *name, int flags, const struct samr_Connect2 *r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_SetUserInfo2(struct ndr_push *ndr, int flags, const struct samr_SetUserInfo2 *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_SetUserInfo2(struct ndr_pull *ndr, int flags, struct samr_SetUserInfo2 *r);
+_PUBLIC_ void ndr_print_samr_SetUserInfo2(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetUserInfo2 *r);
+_PUBLIC_ void ndr_print_samr_SetBootKeyInformation(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetBootKeyInformation *r);
+_PUBLIC_ void ndr_print_samr_GetBootKeyInformation(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetBootKeyInformation *r);
+_PUBLIC_ void ndr_print_samr_Connect3(struct ndr_print *ndr, const char *name, int flags, const struct samr_Connect3 *r);
+_PUBLIC_ void ndr_print_samr_Connect4(struct ndr_print *ndr, const char *name, int flags, const struct samr_Connect4 *r);
+_PUBLIC_ void ndr_print_samr_ChangePasswordUser3(struct ndr_print *ndr, const char *name, int flags, const struct samr_ChangePasswordUser3 *r);
+_PUBLIC_ enum ndr_err_code ndr_push_samr_Connect5(struct ndr_push *ndr, int flags, const struct samr_Connect5 *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_Connect5(struct ndr_pull *ndr, int flags, struct samr_Connect5 *r);
+_PUBLIC_ void ndr_print_samr_Connect5(struct ndr_print *ndr, const char *name, int flags, const struct samr_Connect5 *r);
+_PUBLIC_ void ndr_print_samr_RidToSid(struct ndr_print *ndr, const char *name, int flags, const struct samr_RidToSid *r);
+_PUBLIC_ void ndr_print_samr_SetDsrmPassword(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetDsrmPassword *r);
+_PUBLIC_ void ndr_print_samr_ValidatePassword(struct ndr_print *ndr, const char *name, int flags, const struct samr_ValidatePassword *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_security.c */
+
+_PUBLIC_ void ndr_print_security_ace_flags(struct ndr_print *ndr, const char *name, uint8_t r);
+_PUBLIC_ void ndr_print_security_ace_type(struct ndr_print *ndr, const char *name, enum security_ace_type r);
+_PUBLIC_ void ndr_print_security_ace_object_flags(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_security_ace_object_type(struct ndr_print *ndr, const char *name, const union security_ace_object_type *r);
+_PUBLIC_ void ndr_print_security_ace_object_inherited_type(struct ndr_print *ndr, const char *name, const union security_ace_object_inherited_type *r);
+_PUBLIC_ void ndr_print_security_ace_object(struct ndr_print *ndr, const char *name, const struct security_ace_object *r);
+_PUBLIC_ void ndr_print_security_ace_object_ctr(struct ndr_print *ndr, const char *name, const union security_ace_object_ctr *r);
+_PUBLIC_ enum ndr_err_code ndr_push_security_ace(struct ndr_push *ndr, int ndr_flags, const struct security_ace *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_security_ace(struct ndr_pull *ndr, int ndr_flags, struct security_ace *r);
+_PUBLIC_ void ndr_print_security_ace(struct ndr_print *ndr, const char *name, const struct security_ace *r);
+_PUBLIC_ void ndr_print_security_acl_revision(struct ndr_print *ndr, const char *name, enum security_acl_revision r);
+_PUBLIC_ enum ndr_err_code ndr_push_security_acl(struct ndr_push *ndr, int ndr_flags, const struct security_acl *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_security_acl(struct ndr_pull *ndr, int ndr_flags, struct security_acl *r);
+_PUBLIC_ void ndr_print_security_acl(struct ndr_print *ndr, const char *name, const struct security_acl *r);
+_PUBLIC_ void ndr_print_security_descriptor_revision(struct ndr_print *ndr, const char *name, enum security_descriptor_revision r);
+_PUBLIC_ void ndr_print_security_descriptor_type(struct ndr_print *ndr, const char *name, uint16_t r);
+_PUBLIC_ enum ndr_err_code ndr_push_security_descriptor(struct ndr_push *ndr, int ndr_flags, const struct security_descriptor *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_security_descriptor(struct ndr_pull *ndr, int ndr_flags, struct security_descriptor *r);
+_PUBLIC_ void ndr_print_security_descriptor(struct ndr_print *ndr, const char *name, const struct security_descriptor *r);
+_PUBLIC_ enum ndr_err_code ndr_push_sec_desc_buf(struct ndr_push *ndr, int ndr_flags, const struct sec_desc_buf *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_sec_desc_buf(struct ndr_pull *ndr, int ndr_flags, struct sec_desc_buf *r);
+_PUBLIC_ void ndr_print_sec_desc_buf(struct ndr_print *ndr, const char *name, const struct sec_desc_buf *r);
+_PUBLIC_ enum ndr_err_code ndr_push_security_token(struct ndr_push *ndr, int ndr_flags, const struct security_token *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_security_token(struct ndr_pull *ndr, int ndr_flags, struct security_token *r);
+_PUBLIC_ void ndr_print_security_token(struct ndr_print *ndr, const char *name, const struct security_token *r);
+_PUBLIC_ enum ndr_err_code ndr_push_security_secinfo(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+_PUBLIC_ enum ndr_err_code ndr_pull_security_secinfo(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+_PUBLIC_ void ndr_print_security_secinfo(struct ndr_print *ndr, const char *name, uint32_t r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_srvsvc.c */
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevInfo0 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevCtr0 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevInfo1 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevCtr1 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetCharDevInfo *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetCharDevCtr *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevQInfo0 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevQCtr0 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevQInfo1 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevQCtr1 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetCharDevQInfo *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetCharDevQCtr *r);
+_PUBLIC_ void ndr_print_srvsvc_NetConnInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetConnInfo0 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetConnCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetConnCtr0 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetConnInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetConnInfo1 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetConnCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetConnCtr1 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetConnCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetConnCtr *r);
+_PUBLIC_ void ndr_print_srvsvc_NetConnInfoCtr(struct ndr_print *ndr, const char *name, const struct srvsvc_NetConnInfoCtr *r);
+_PUBLIC_ void ndr_print_srvsvc_NetFileInfo2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetFileInfo2 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetFileCtr2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetFileCtr2 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetFileInfo3(struct ndr_print *ndr, const char *name, const struct srvsvc_NetFileInfo3 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetFileCtr3(struct ndr_print *ndr, const char *name, const struct srvsvc_NetFileCtr3 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetFileInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetFileInfo *r);
+_PUBLIC_ void ndr_print_srvsvc_NetFileCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetFileCtr *r);
+_PUBLIC_ void ndr_print_srvsvc_NetFileInfoCtr(struct ndr_print *ndr, const char *name, const struct srvsvc_NetFileInfoCtr *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSessInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfo0 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSessCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessCtr0 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSessInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfo1 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSessCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessCtr1 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSessInfo2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfo2 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSessCtr2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessCtr2 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSessInfo10(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfo10 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSessCtr10(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessCtr10 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSessInfo502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfo502 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSessCtr502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessCtr502 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSessCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetSessCtr *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSessInfoCtr(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfoCtr *r);
+_PUBLIC_ void ndr_print_srvsvc_ShareType(struct ndr_print *ndr, const char *name, enum srvsvc_ShareType r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo0 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr0 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo1 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo2 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr2 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo501(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo501 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr501(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr501 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo502 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr502 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo1004(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo1004 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr1004(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1004 *r);
+_PUBLIC_ void ndr_print_NetShareInfo1005Flags(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo1005(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo1005 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr1005(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1005 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo1006(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo1006 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr1006(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1006 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo1007(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo1007 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr1007(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1007 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr1501(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1501 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetShareInfo *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetShareCtr *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfoCtr(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfoCtr *r);
+_PUBLIC_ enum ndr_err_code ndr_push_srvsvc_PlatformId(struct ndr_push *ndr, int ndr_flags, enum srvsvc_PlatformId r);
+_PUBLIC_ enum ndr_err_code ndr_pull_srvsvc_PlatformId(struct ndr_pull *ndr, int ndr_flags, enum srvsvc_PlatformId *r);
+_PUBLIC_ void ndr_print_srvsvc_PlatformId(struct ndr_print *ndr, const char *name, enum srvsvc_PlatformId r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo100(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo100 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo101(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo101 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo102(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo102 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo402(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo402 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo403(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo403 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo502 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo503(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo503 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo599(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo599 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1005(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1005 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1010(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1010 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1016(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1016 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1017(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1017 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1018(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1018 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1107(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1107 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1501(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1501 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1502 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1503(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1503 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1506(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1506 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1509(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1509 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1510(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1510 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1511(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1511 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1512(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1512 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1513(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1513 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1514(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1514 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1515(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1515 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1516(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1516 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1518(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1518 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1520(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1520 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1521(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1521 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1522(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1522 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1523(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1523 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1524(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1524 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1525(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1525 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1528(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1528 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1529(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1529 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1530(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1530 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1533(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1533 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1534(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1534 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1535(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1535 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1536(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1536 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1537(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1537 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1538(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1538 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1539(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1539 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1540(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1540 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1541(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1541 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1542(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1542 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1543(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1543 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1544(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1544 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1545(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1545 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1546(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1546 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1547(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1547 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1548(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1548 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1549(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1549 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1550(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1550 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1552(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1552 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1553(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1553 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1554(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1554 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1555(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1555 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1556(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1556 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetSrvInfo *r);
+_PUBLIC_ void ndr_print_srvsvc_NetDiskInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetDiskInfo0 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetDiskInfo(struct ndr_print *ndr, const char *name, const struct srvsvc_NetDiskInfo *r);
+_PUBLIC_ void ndr_print_srvsvc_Statistics(struct ndr_print *ndr, const char *name, const struct srvsvc_Statistics *r);
+_PUBLIC_ void ndr_print_srvsvc_NetTransportInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportInfo0 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetTransportCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportCtr0 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetTransportInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportInfo1 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetTransportCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportCtr1 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetTransportInfo2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportInfo2 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetTransportCtr2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportCtr2 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetTransportInfo3(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportInfo3 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetTransportCtr3(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportCtr3 *r);
+_PUBLIC_ void ndr_print_srvsvc_NetTransportCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetTransportCtr *r);
+_PUBLIC_ void ndr_print_srvsvc_NetRemoteTODInfo(struct ndr_print *ndr, const char *name, const struct srvsvc_NetRemoteTODInfo *r);
+_PUBLIC_ void ndr_print_srvsvc_NetTransportInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetTransportInfo *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevEnum *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevGetInfo *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevControl(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevControl *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevQEnum *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevQGetInfo *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevQSetInfo *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQPurge(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevQPurge *r);
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQPurgeSelf(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevQPurgeSelf *r);
+_PUBLIC_ void ndr_print_srvsvc_NetConnEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetConnEnum *r);
+_PUBLIC_ void ndr_print_srvsvc_NetFileEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetFileEnum *r);
+_PUBLIC_ void ndr_print_srvsvc_NetFileGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetFileGetInfo *r);
+_PUBLIC_ void ndr_print_srvsvc_NetFileClose(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetFileClose *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSessEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSessEnum *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSessDel(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSessDel *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareAdd(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareAdd *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareEnumAll(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareEnumAll *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareGetInfo *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareSetInfo *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareDel(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareDel *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareDelSticky(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareDelSticky *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareCheck(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareCheck *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSrvGetInfo *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSrvSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSrvSetInfo *r);
+_PUBLIC_ void ndr_print_srvsvc_NetDiskEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetDiskEnum *r);
+_PUBLIC_ void ndr_print_srvsvc_NetServerStatisticsGet(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetServerStatisticsGet *r);
+_PUBLIC_ void ndr_print_srvsvc_NetTransportAdd(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetTransportAdd *r);
+_PUBLIC_ void ndr_print_srvsvc_NetTransportEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetTransportEnum *r);
+_PUBLIC_ void ndr_print_srvsvc_NetTransportDel(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetTransportDel *r);
+_PUBLIC_ void ndr_print_srvsvc_NetRemoteTOD(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetRemoteTOD *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSetServiceBits(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSetServiceBits *r);
+_PUBLIC_ void ndr_print_srvsvc_NetPathType(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetPathType *r);
+_PUBLIC_ void ndr_print_srvsvc_NetPathCanonicalize(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetPathCanonicalize *r);
+_PUBLIC_ void ndr_print_srvsvc_NetPathCompare(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetPathCompare *r);
+_PUBLIC_ void ndr_print_srvsvc_NetNameValidate(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetNameValidate *r);
+_PUBLIC_ void ndr_print_srvsvc_NETRPRNAMECANONICALIZE(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRPRNAMECANONICALIZE *r);
+_PUBLIC_ void ndr_print_srvsvc_NetPRNameCompare(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetPRNameCompare *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareEnum *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareDelStart(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareDelStart *r);
+_PUBLIC_ void ndr_print_srvsvc_NetShareDelCommit(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareDelCommit *r);
+_PUBLIC_ void ndr_print_srvsvc_NetGetFileSecurity(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetGetFileSecurity *r);
+_PUBLIC_ void ndr_print_srvsvc_NetSetFileSecurity(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSetFileSecurity *r);
+_PUBLIC_ void ndr_print_srvsvc_NetServerTransportAddEx(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetServerTransportAddEx *r);
+_PUBLIC_ void ndr_print_srvsvc_NetServerSetServiceBitsEx(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetServerSetServiceBitsEx *r);
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSGETVERSION(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSGETVERSION *r);
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSCREATELOCALPARTITION(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSCREATELOCALPARTITION *r);
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSDELETELOCALPARTITION(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSDELETELOCALPARTITION *r);
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSSETLOCALVOLUMESTATE(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSSETLOCALVOLUMESTATE *r);
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSSETSERVERINFO(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSSETSERVERINFO *r);
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSCREATEEXITPOINT(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSCREATEEXITPOINT *r);
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSDELETEEXITPOINT(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSDELETEEXITPOINT *r);
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSMODIFYPREFIX(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSMODIFYPREFIX *r);
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSFIXLOCALVOLUME(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSFIXLOCALVOLUME *r);
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSMANAGERREPORTSITEINFO(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSMANAGERREPORTSITEINFO *r);
+_PUBLIC_ void ndr_print_srvsvc_NETRSERVERTRANSPORTDELEX(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRSERVERTRANSPORTDELEX *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_svcctl.c */
+
+_PUBLIC_ void ndr_print_SERVICE_LOCK_STATUS(struct ndr_print *ndr, const char *name, const struct SERVICE_LOCK_STATUS *r);
+_PUBLIC_ void ndr_print_SERVICE_STATUS(struct ndr_print *ndr, const char *name, const struct SERVICE_STATUS *r);
+_PUBLIC_ void ndr_print_ENUM_SERVICE_STATUS(struct ndr_print *ndr, const char *name, const struct ENUM_SERVICE_STATUS *r);
+_PUBLIC_ enum ndr_err_code ndr_push_svcctl_ServerType(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+_PUBLIC_ enum ndr_err_code ndr_pull_svcctl_ServerType(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+_PUBLIC_ void ndr_print_svcctl_ServerType(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_svcctl_MgrAccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_svcctl_ServiceAccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_svcctl_CloseServiceHandle(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_CloseServiceHandle *r);
+_PUBLIC_ void ndr_print_svcctl_ControlService(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_ControlService *r);
+_PUBLIC_ void ndr_print_svcctl_DeleteService(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_DeleteService *r);
+_PUBLIC_ void ndr_print_svcctl_LockServiceDatabase(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_LockServiceDatabase *r);
+_PUBLIC_ void ndr_print_svcctl_QueryServiceObjectSecurity(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceObjectSecurity *r);
+_PUBLIC_ void ndr_print_svcctl_SetServiceObjectSecurity(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_SetServiceObjectSecurity *r);
+_PUBLIC_ void ndr_print_svcctl_QueryServiceStatus(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceStatus *r);
+_PUBLIC_ void ndr_print_svcctl_SetServiceStatus(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_SetServiceStatus *r);
+_PUBLIC_ void ndr_print_svcctl_UnlockServiceDatabase(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_UnlockServiceDatabase *r);
+_PUBLIC_ void ndr_print_svcctl_NotifyBootConfigStatus(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_NotifyBootConfigStatus *r);
+_PUBLIC_ void ndr_print_svcctl_SCSetServiceBitsW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_SCSetServiceBitsW *r);
+_PUBLIC_ void ndr_print_svcctl_ChangeServiceConfigW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_ChangeServiceConfigW *r);
+_PUBLIC_ void ndr_print_svcctl_CreateServiceW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_CreateServiceW *r);
+_PUBLIC_ void ndr_print_svcctl_EnumDependentServicesW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_EnumDependentServicesW *r);
+_PUBLIC_ void ndr_print_svcctl_EnumServicesStatusW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_EnumServicesStatusW *r);
+_PUBLIC_ void ndr_print_svcctl_OpenSCManagerW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_OpenSCManagerW *r);
+_PUBLIC_ void ndr_print_svcctl_OpenServiceW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_OpenServiceW *r);
+_PUBLIC_ void ndr_print_svcctl_QueryServiceConfigW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceConfigW *r);
+_PUBLIC_ void ndr_print_svcctl_QueryServiceLockStatusW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceLockStatusW *r);
+_PUBLIC_ void ndr_print_svcctl_StartServiceW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_StartServiceW *r);
+_PUBLIC_ void ndr_print_svcctl_GetServiceDisplayNameW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_GetServiceDisplayNameW *r);
+_PUBLIC_ void ndr_print_svcctl_GetServiceKeyNameW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_GetServiceKeyNameW *r);
+_PUBLIC_ void ndr_print_svcctl_SCSetServiceBitsA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_SCSetServiceBitsA *r);
+_PUBLIC_ void ndr_print_svcctl_ChangeServiceConfigA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_ChangeServiceConfigA *r);
+_PUBLIC_ void ndr_print_svcctl_CreateServiceA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_CreateServiceA *r);
+_PUBLIC_ void ndr_print_svcctl_EnumDependentServicesA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_EnumDependentServicesA *r);
+_PUBLIC_ void ndr_print_svcctl_EnumServicesStatusA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_EnumServicesStatusA *r);
+_PUBLIC_ void ndr_print_svcctl_OpenSCManagerA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_OpenSCManagerA *r);
+_PUBLIC_ void ndr_print_svcctl_OpenServiceA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_OpenServiceA *r);
+_PUBLIC_ void ndr_print_svcctl_QueryServiceConfigA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceConfigA *r);
+_PUBLIC_ void ndr_print_svcctl_QueryServiceLockStatusA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceLockStatusA *r);
+_PUBLIC_ void ndr_print_svcctl_StartServiceA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_StartServiceA *r);
+_PUBLIC_ void ndr_print_svcctl_GetServiceDisplayNameA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_GetServiceDisplayNameA *r);
+_PUBLIC_ void ndr_print_svcctl_GetServiceKeyNameA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_GetServiceKeyNameA *r);
+_PUBLIC_ void ndr_print_svcctl_GetCurrentGroupeStateW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_GetCurrentGroupeStateW *r);
+_PUBLIC_ void ndr_print_svcctl_EnumServiceGroupW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_EnumServiceGroupW *r);
+_PUBLIC_ void ndr_print_svcctl_ChangeServiceConfig2A(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_ChangeServiceConfig2A *r);
+_PUBLIC_ void ndr_print_svcctl_ChangeServiceConfig2W(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_ChangeServiceConfig2W *r);
+_PUBLIC_ void ndr_print_svcctl_QueryServiceConfig2A(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceConfig2A *r);
+_PUBLIC_ void ndr_print_svcctl_QueryServiceConfig2W(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceConfig2W *r);
+_PUBLIC_ void ndr_print_svcctl_QueryServiceStatusEx(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceStatusEx *r);
+_PUBLIC_ void ndr_print_EnumServicesStatusExA(struct ndr_print *ndr, const char *name, int flags, const struct EnumServicesStatusExA *r);
+_PUBLIC_ void ndr_print_EnumServicesStatusExW(struct ndr_print *ndr, const char *name, int flags, const struct EnumServicesStatusExW *r);
+_PUBLIC_ void ndr_print_svcctl_SCSendTSMessage(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_SCSendTSMessage *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_winreg.c */
+
+_PUBLIC_ void ndr_print_winreg_AccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_winreg_Type(struct ndr_print *ndr, const char *name, enum winreg_Type r);
+_PUBLIC_ enum ndr_err_code ndr_push_winreg_String(struct ndr_push *ndr, int ndr_flags, const struct winreg_String *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_winreg_String(struct ndr_pull *ndr, int ndr_flags, struct winreg_String *r);
+_PUBLIC_ void ndr_print_winreg_String(struct ndr_print *ndr, const char *name, const struct winreg_String *r);
+_PUBLIC_ void ndr_print_KeySecurityData(struct ndr_print *ndr, const char *name, const struct KeySecurityData *r);
+_PUBLIC_ void ndr_print_winreg_SecBuf(struct ndr_print *ndr, const char *name, const struct winreg_SecBuf *r);
+_PUBLIC_ void ndr_print_winreg_CreateAction(struct ndr_print *ndr, const char *name, enum winreg_CreateAction r);
+_PUBLIC_ void ndr_print_winreg_StringBuf(struct ndr_print *ndr, const char *name, const struct winreg_StringBuf *r);
+_PUBLIC_ void ndr_print_winreg_ValNameBuf(struct ndr_print *ndr, const char *name, const struct winreg_ValNameBuf *r);
+_PUBLIC_ void ndr_print_KeySecurityAttribute(struct ndr_print *ndr, const char *name, const struct KeySecurityAttribute *r);
+_PUBLIC_ void ndr_print_QueryMultipleValue(struct ndr_print *ndr, const char *name, const struct QueryMultipleValue *r);
+_PUBLIC_ void ndr_print_winreg_OpenHKCR(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKCR *r);
+_PUBLIC_ void ndr_print_winreg_OpenHKCU(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKCU *r);
+_PUBLIC_ void ndr_print_winreg_OpenHKLM(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKLM *r);
+_PUBLIC_ void ndr_print_winreg_OpenHKPD(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKPD *r);
+_PUBLIC_ void ndr_print_winreg_OpenHKU(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKU *r);
+_PUBLIC_ void ndr_print_winreg_CloseKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_CloseKey *r);
+_PUBLIC_ void ndr_print_winreg_CreateKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_CreateKey *r);
+_PUBLIC_ void ndr_print_winreg_DeleteKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_DeleteKey *r);
+_PUBLIC_ void ndr_print_winreg_DeleteValue(struct ndr_print *ndr, const char *name, int flags, const struct winreg_DeleteValue *r);
+_PUBLIC_ void ndr_print_winreg_EnumKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_EnumKey *r);
+_PUBLIC_ void ndr_print_winreg_EnumValue(struct ndr_print *ndr, const char *name, int flags, const struct winreg_EnumValue *r);
+_PUBLIC_ void ndr_print_winreg_FlushKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_FlushKey *r);
+_PUBLIC_ void ndr_print_winreg_GetKeySecurity(struct ndr_print *ndr, const char *name, int flags, const struct winreg_GetKeySecurity *r);
+_PUBLIC_ void ndr_print_winreg_LoadKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_LoadKey *r);
+_PUBLIC_ void ndr_print_winreg_NotifyChangeKeyValue(struct ndr_print *ndr, const char *name, int flags, const struct winreg_NotifyChangeKeyValue *r);
+_PUBLIC_ void ndr_print_winreg_OpenKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenKey *r);
+_PUBLIC_ void ndr_print_winreg_QueryInfoKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_QueryInfoKey *r);
+_PUBLIC_ void ndr_print_winreg_QueryValue(struct ndr_print *ndr, const char *name, int flags, const struct winreg_QueryValue *r);
+_PUBLIC_ void ndr_print_winreg_ReplaceKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_ReplaceKey *r);
+_PUBLIC_ void ndr_print_winreg_RestoreKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_RestoreKey *r);
+_PUBLIC_ void ndr_print_winreg_SaveKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_SaveKey *r);
+_PUBLIC_ void ndr_print_winreg_SetKeySecurity(struct ndr_print *ndr, const char *name, int flags, const struct winreg_SetKeySecurity *r);
+_PUBLIC_ void ndr_print_winreg_SetValue(struct ndr_print *ndr, const char *name, int flags, const struct winreg_SetValue *r);
+_PUBLIC_ void ndr_print_winreg_UnLoadKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_UnLoadKey *r);
+_PUBLIC_ void ndr_print_winreg_InitiateSystemShutdown(struct ndr_print *ndr, const char *name, int flags, const struct winreg_InitiateSystemShutdown *r);
+_PUBLIC_ void ndr_print_winreg_AbortSystemShutdown(struct ndr_print *ndr, const char *name, int flags, const struct winreg_AbortSystemShutdown *r);
+_PUBLIC_ void ndr_print_winreg_GetVersion(struct ndr_print *ndr, const char *name, int flags, const struct winreg_GetVersion *r);
+_PUBLIC_ void ndr_print_winreg_OpenHKCC(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKCC *r);
+_PUBLIC_ void ndr_print_winreg_OpenHKDD(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKDD *r);
+_PUBLIC_ void ndr_print_winreg_QueryMultipleValues(struct ndr_print *ndr, const char *name, int flags, const struct winreg_QueryMultipleValues *r);
+_PUBLIC_ void ndr_print_winreg_InitiateSystemShutdownEx(struct ndr_print *ndr, const char *name, int flags, const struct winreg_InitiateSystemShutdownEx *r);
+_PUBLIC_ void ndr_print_winreg_SaveKeyEx(struct ndr_print *ndr, const char *name, int flags, const struct winreg_SaveKeyEx *r);
+_PUBLIC_ void ndr_print_winreg_OpenHKPT(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKPT *r);
+_PUBLIC_ void ndr_print_winreg_OpenHKPN(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKPN *r);
+_PUBLIC_ void ndr_print_winreg_QueryMultipleValues2(struct ndr_print *ndr, const char *name, int flags, const struct winreg_QueryMultipleValues2 *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_wkssvc.c */
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo100(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo100 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo101(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo101 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo102(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo102 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo502(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo502 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1010(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1010 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1011(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1011 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1012(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1012 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1013(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1013 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1018(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1018 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1023(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1023 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1027(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1027 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1028(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1028 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1032(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1032 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1033(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1033 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1041(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1041 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1042(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1042 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1043(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1043 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1044(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1044 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1045(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1045 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1046(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1046 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1047(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1047 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1048(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1048 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1049(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1049 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1050(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1050 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1051(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1051 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1052(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1052 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1053(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1053 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1054(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1054 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1055(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1055 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1056(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1056 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1057(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1057 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1058(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1058 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1059(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1059 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1060(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1060 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1061(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1061 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1062(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1062 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo(struct ndr_print *ndr, const char *name, const union wkssvc_NetWkstaInfo *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrWkstaUserInfo0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrWkstaUserInfo0 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaEnumUsersCtr0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaEnumUsersCtr0 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrWkstaUserInfo1(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrWkstaUserInfo1 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaEnumUsersCtr1(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaEnumUsersCtr1 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaEnumUsersCtr(struct ndr_print *ndr, const char *name, const union wkssvc_NetWkstaEnumUsersCtr *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaEnumUsersInfo(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaEnumUsersInfo *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrWkstaUserInfo1101(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrWkstaUserInfo1101 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrWkstaUserInfo(struct ndr_print *ndr, const char *name, const union wkssvc_NetrWkstaUserInfo *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaTransportInfo0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaTransportInfo0 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaTransportCtr0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaTransportCtr0 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaTransportCtr(struct ndr_print *ndr, const char *name, const union wkssvc_NetWkstaTransportCtr *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaTransportInfo(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaTransportInfo *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrUseInfo3(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseInfo3 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrUseInfo2(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseInfo2 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrUseInfo1(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseInfo1 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrUseInfo0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseInfo0 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrUseGetInfoCtr(struct ndr_print *ndr, const char *name, const union wkssvc_NetrUseGetInfoCtr *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrUseEnumCtr2(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseEnumCtr2 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrUseEnumCtr1(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseEnumCtr1 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrUseEnumCtr0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseEnumCtr0 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrUseEnumCtr(struct ndr_print *ndr, const char *name, const union wkssvc_NetrUseEnumCtr *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrUseEnumInfo(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseEnumInfo *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrWorkstationStatistics(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrWorkstationStatistics *r);
+_PUBLIC_ void ndr_print_wkssvc_renameflags(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_wkssvc_NetValidateNameType(struct ndr_print *ndr, const char *name, enum wkssvc_NetValidateNameType r);
+_PUBLIC_ void ndr_print_wkssvc_NetJoinStatus(struct ndr_print *ndr, const char *name, enum wkssvc_NetJoinStatus r);
+_PUBLIC_ void ndr_print_wkssvc_PasswordBuffer(struct ndr_print *ndr, const char *name, const struct wkssvc_PasswordBuffer *r);
+_PUBLIC_ void ndr_print_wkssvc_joinflags(struct ndr_print *ndr, const char *name, uint32_t r);
+_PUBLIC_ void ndr_print_wkssvc_ComputerNameType(struct ndr_print *ndr, const char *name, enum wkssvc_ComputerNameType r);
+_PUBLIC_ void ndr_print_wkssvc_ComputerNamesCtr(struct ndr_print *ndr, const char *name, const struct wkssvc_ComputerNamesCtr *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetWkstaGetInfo *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetWkstaSetInfo *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaEnumUsers(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetWkstaEnumUsers *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrWkstaUserGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrWkstaUserGetInfo *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrWkstaUserSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrWkstaUserSetInfo *r);
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaTransportEnum(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetWkstaTransportEnum *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrWkstaTransportAdd(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrWkstaTransportAdd *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrWkstaTransportDel(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrWkstaTransportDel *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrUseAdd(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUseAdd *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrUseGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUseGetInfo *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrUseDel(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUseDel *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrUseEnum(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUseEnum *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrMessageBufferSend(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrMessageBufferSend *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrWorkstationStatisticsGet(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrWorkstationStatisticsGet *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrLogonDomainNameAdd(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrLogonDomainNameAdd *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrLogonDomainNameDel(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrLogonDomainNameDel *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrJoinDomain(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrJoinDomain *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrUnjoinDomain(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUnjoinDomain *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrRenameMachineInDomain(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrRenameMachineInDomain *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrValidateName(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrValidateName *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrGetJoinInformation(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrGetJoinInformation *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrGetJoinableOus(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrGetJoinableOus *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrJoinDomain2(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrJoinDomain2 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrUnjoinDomain2(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUnjoinDomain2 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrRenameMachineInDomain2(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrRenameMachineInDomain2 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrValidateName2(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrValidateName2 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrGetJoinableOus2(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrGetJoinableOus2 *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrAddAlternateComputerName(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrAddAlternateComputerName *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrRemoveAlternateComputerName(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrRemoveAlternateComputerName *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrSetPrimaryComputername(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrSetPrimaryComputername *r);
+_PUBLIC_ void ndr_print_wkssvc_NetrEnumerateComputerNames(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrEnumerateComputerNames *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_xattr.c */
+
+_PUBLIC_ enum ndr_err_code ndr_push_tdb_xattr(struct ndr_push *ndr, int ndr_flags, const struct tdb_xattr *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_tdb_xattr(struct ndr_pull *ndr, int ndr_flags, struct tdb_xattr *r);
+_PUBLIC_ void ndr_print_tdb_xattr(struct ndr_print *ndr, const char *name, const struct tdb_xattr *r);
+_PUBLIC_ enum ndr_err_code ndr_push_tdb_xattrs(struct ndr_push *ndr, int ndr_flags, const struct tdb_xattrs *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_tdb_xattrs(struct ndr_pull *ndr, int ndr_flags, struct tdb_xattrs *r);
+_PUBLIC_ void ndr_print_tdb_xattrs(struct ndr_print *ndr, const char *name, const struct tdb_xattrs *r);
+
+/* The following definitions come from librpc/gen_ndr/srv_dfs.c */
+
+void netdfs_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_netdfs_init(void);
+
+/* The following definitions come from librpc/gen_ndr/srv_dssetup.c */
+
+void dssetup_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_dssetup_init(void);
+
+/* The following definitions come from librpc/gen_ndr/srv_echo.c */
+
+void rpcecho_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_rpcecho_init(void);
+
+/* The following definitions come from librpc/gen_ndr/srv_eventlog.c */
+
+void eventlog_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_eventlog_init(void);
+
+/* The following definitions come from librpc/gen_ndr/srv_initshutdown.c */
+
+void initshutdown_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_initshutdown_init(void);
+
+/* The following definitions come from librpc/gen_ndr/srv_lsa.c */
+
+void lsarpc_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_lsarpc_init(void);
+
+/* The following definitions come from librpc/gen_ndr/srv_netlogon.c */
+
+void netlogon_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_netlogon_init(void);
+
+/* The following definitions come from librpc/gen_ndr/srv_ntsvcs.c */
+
+void ntsvcs_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_ntsvcs_init(void);
+
+/* The following definitions come from librpc/gen_ndr/srv_samr.c */
+
+void samr_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_samr_init(void);
+
+/* The following definitions come from librpc/gen_ndr/srv_srvsvc.c */
+
+void srvsvc_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_srvsvc_init(void);
+
+/* The following definitions come from librpc/gen_ndr/srv_svcctl.c */
+
+void svcctl_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_svcctl_init(void);
+
+/* The following definitions come from librpc/gen_ndr/srv_winreg.c */
+
+void winreg_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_winreg_init(void);
+
+/* The following definitions come from librpc/gen_ndr/srv_wkssvc.c */
+
+void wkssvc_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_wkssvc_init(void);
+
+/* The following definitions come from librpc/ndr/ndr.c */
+
+_PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n);
+_PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx);
+_PUBLIC_ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size);
+_PUBLIC_ void ndr_pull_save(struct ndr_pull *ndr, struct ndr_pull_save *save);
+_PUBLIC_ void ndr_pull_restore(struct ndr_pull *ndr, struct ndr_pull_save *save);
+_PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx);
+_PUBLIC_ DATA_BLOB ndr_push_blob(struct ndr_push *ndr);
+_PUBLIC_ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size);
+_PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...) _PRINTF_ATTRIBUTE(2,3);
+_PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...) _PRINTF_ATTRIBUTE(2,3);
+_PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr);
+_PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr);
+_PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr);
+_PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr);
+_PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr);
+_PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
+ ndr_print_function_t fn, const char *name,
+ int flags, void *ptr);
+_PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags);
+NTSTATUS ndr_map_error2ntstatus(enum ndr_err_code ndr_err);
+const char *ndr_errstr(enum ndr_err_code err);
+_PUBLIC_ enum ndr_err_code ndr_pull_error(struct ndr_pull *ndr,
+ enum ndr_err_code ndr_err,
+ const char *format, ...) _PRINTF_ATTRIBUTE(3,4);
+_PUBLIC_ enum ndr_err_code ndr_push_error(struct ndr_push *ndr,
+ enum ndr_err_code ndr_err,
+ const char *format, ...) _PRINTF_ATTRIBUTE(3,4);
+_PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
+ struct ndr_pull **_subndr,
+ size_t header_size,
+ ssize_t size_is);
+_PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr,
+ struct ndr_pull *subndr,
+ size_t header_size,
+ ssize_t size_is);
+_PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
+ struct ndr_push **_subndr,
+ size_t header_size,
+ ssize_t size_is);
+_PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
+ struct ndr_push *subndr,
+ size_t header_size,
+ ssize_t size_is);
+_PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx,
+ struct ndr_token_list **list,
+ const void *key,
+ uint32_t value);
+_PUBLIC_ enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list **list, const void *key, uint32_t *v,
+ comparison_fn_t _cmp_fn, bool _remove_tok);
+_PUBLIC_ enum ndr_err_code ndr_token_retrieve(struct ndr_token_list **list, const void *key, uint32_t *v);
+_PUBLIC_ uint32_t ndr_token_peek(struct ndr_token_list **list, const void *key);
+_PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p);
+_PUBLIC_ uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p);
+_PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size);
+_PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p);
+_PUBLIC_ uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p);
+_PUBLIC_ enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length);
+_PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val);
+_PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val);
+_PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val);
+_PUBLIC_ uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, const void *p);
+_PUBLIC_ uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, const void *p);
+_PUBLIC_ uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void *p);
+_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
+ ndr_pull_flags_fn_t fn);
+_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
+ ndr_pull_flags_fn_t fn);
+_PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
+ uint32_t level, ndr_pull_flags_fn_t fn);
+_PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
+ uint32_t level, ndr_pull_flags_fn_t fn);
+_PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, const void *p,
+ ndr_push_flags_fn_t fn);
+_PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
+ uint32_t level, ndr_push_flags_fn_t fn);
+_PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push);
+_PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push);
+_PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr);
+_PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset);
+_PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset);
+_PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p);
+_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p);
+_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p);
+_PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr);
+_PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset);
+_PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset);
+_PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p);
+_PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset);
+_PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p);
+
+/* The following definitions come from librpc/ndr/ndr_basic.c */
+
+_PUBLIC_ void ndr_check_padding(struct ndr_pull *ndr, size_t n);
+_PUBLIC_ enum ndr_err_code ndr_pull_int8(struct ndr_pull *ndr, int ndr_flags, int8_t *v);
+_PUBLIC_ enum ndr_err_code ndr_pull_uint8(struct ndr_pull *ndr, int ndr_flags, uint8_t *v);
+_PUBLIC_ enum ndr_err_code ndr_pull_int16(struct ndr_pull *ndr, int ndr_flags, int16_t *v);
+_PUBLIC_ enum ndr_err_code ndr_pull_uint16(struct ndr_pull *ndr, int ndr_flags, uint16_t *v);
+_PUBLIC_ enum ndr_err_code ndr_pull_int32(struct ndr_pull *ndr, int ndr_flags, int32_t *v);
+_PUBLIC_ enum ndr_err_code ndr_pull_uint32(struct ndr_pull *ndr, int ndr_flags, uint32_t *v);
+_PUBLIC_ enum ndr_err_code ndr_pull_generic_ptr(struct ndr_pull *ndr, uint32_t *v);
+_PUBLIC_ enum ndr_err_code ndr_pull_ref_ptr(struct ndr_pull *ndr, uint32_t *v);
+_PUBLIC_ enum ndr_err_code ndr_pull_udlong(struct ndr_pull *ndr, int ndr_flags, uint64_t *v);
+_PUBLIC_ enum ndr_err_code ndr_pull_udlongr(struct ndr_pull *ndr, int ndr_flags, uint64_t *v);
+_PUBLIC_ enum ndr_err_code ndr_pull_dlong(struct ndr_pull *ndr, int ndr_flags, int64_t *v);
+_PUBLIC_ enum ndr_err_code ndr_pull_hyper(struct ndr_pull *ndr, int ndr_flags, uint64_t *v);
+_PUBLIC_ enum ndr_err_code ndr_pull_pointer(struct ndr_pull *ndr, int ndr_flags, void* *v);
+_PUBLIC_ enum ndr_err_code ndr_pull_NTSTATUS(struct ndr_pull *ndr, int ndr_flags, NTSTATUS *status);
+_PUBLIC_ enum ndr_err_code ndr_push_NTSTATUS(struct ndr_push *ndr, int ndr_flags, NTSTATUS status);
+_PUBLIC_ void ndr_print_NTSTATUS(struct ndr_print *ndr, const char *name, NTSTATUS r);
+_PUBLIC_ enum ndr_err_code ndr_pull_WERROR(struct ndr_pull *ndr, int ndr_flags, WERROR *status);
+_PUBLIC_ enum ndr_err_code ndr_push_WERROR(struct ndr_push *ndr, int ndr_flags, WERROR status);
+_PUBLIC_ void ndr_print_WERROR(struct ndr_print *ndr, const char *name, WERROR r);
+_PUBLIC_ enum ndr_err_code ndr_pull_bytes(struct ndr_pull *ndr, uint8_t *data, uint32_t n);
+_PUBLIC_ enum ndr_err_code ndr_pull_array_uint8(struct ndr_pull *ndr, int ndr_flags, uint8_t *data, uint32_t n);
+_PUBLIC_ enum ndr_err_code ndr_push_int8(struct ndr_push *ndr, int ndr_flags, int8_t v);
+_PUBLIC_ enum ndr_err_code ndr_push_uint8(struct ndr_push *ndr, int ndr_flags, uint8_t v);
+_PUBLIC_ enum ndr_err_code ndr_push_int16(struct ndr_push *ndr, int ndr_flags, int16_t v);
+_PUBLIC_ enum ndr_err_code ndr_push_uint16(struct ndr_push *ndr, int ndr_flags, uint16_t v);
+_PUBLIC_ enum ndr_err_code ndr_push_int32(struct ndr_push *ndr, int ndr_flags, int32_t v);
+_PUBLIC_ enum ndr_err_code ndr_push_uint32(struct ndr_push *ndr, int ndr_flags, uint32_t v);
+_PUBLIC_ enum ndr_err_code ndr_push_udlong(struct ndr_push *ndr, int ndr_flags, uint64_t v);
+_PUBLIC_ enum ndr_err_code ndr_push_udlongr(struct ndr_push *ndr, int ndr_flags, uint64_t v);
+_PUBLIC_ enum ndr_err_code ndr_push_dlong(struct ndr_push *ndr, int ndr_flags, int64_t v);
+_PUBLIC_ enum ndr_err_code ndr_push_hyper(struct ndr_push *ndr, int ndr_flags, uint64_t v);
+_PUBLIC_ enum ndr_err_code ndr_push_pointer(struct ndr_push *ndr, int ndr_flags, void* v);
+_PUBLIC_ enum ndr_err_code ndr_push_align(struct ndr_push *ndr, size_t size);
+_PUBLIC_ enum ndr_err_code ndr_pull_align(struct ndr_pull *ndr, size_t size);
+_PUBLIC_ enum ndr_err_code ndr_push_bytes(struct ndr_push *ndr, const uint8_t *data, uint32_t n);
+_PUBLIC_ enum ndr_err_code ndr_push_zero(struct ndr_push *ndr, uint32_t n);
+_PUBLIC_ enum ndr_err_code ndr_push_array_uint8(struct ndr_push *ndr, int ndr_flags, const uint8_t *data, uint32_t n);
+_PUBLIC_ void ndr_push_save(struct ndr_push *ndr, struct ndr_push_save *save);
+_PUBLIC_ void ndr_push_restore(struct ndr_push *ndr, struct ndr_push_save *save);
+_PUBLIC_ enum ndr_err_code ndr_push_unique_ptr(struct ndr_push *ndr, const void *p);
+_PUBLIC_ enum ndr_err_code ndr_push_full_ptr(struct ndr_push *ndr, const void *p);
+_PUBLIC_ enum ndr_err_code ndr_push_ref_ptr(struct ndr_push *ndr);
+_PUBLIC_ enum ndr_err_code ndr_push_NTTIME(struct ndr_push *ndr, int ndr_flags, NTTIME t);
+_PUBLIC_ enum ndr_err_code ndr_pull_NTTIME(struct ndr_pull *ndr, int ndr_flags, NTTIME *t);
+_PUBLIC_ enum ndr_err_code ndr_push_NTTIME_1sec(struct ndr_push *ndr, int ndr_flags, NTTIME t);
+_PUBLIC_ enum ndr_err_code ndr_pull_NTTIME_1sec(struct ndr_pull *ndr, int ndr_flags, NTTIME *t);
+_PUBLIC_ enum ndr_err_code ndr_pull_NTTIME_hyper(struct ndr_pull *ndr, int ndr_flags, NTTIME *t);
+_PUBLIC_ enum ndr_err_code ndr_push_NTTIME_hyper(struct ndr_push *ndr, int ndr_flags, NTTIME t);
+_PUBLIC_ enum ndr_err_code ndr_push_time_t(struct ndr_push *ndr, int ndr_flags, time_t t);
+_PUBLIC_ enum ndr_err_code ndr_pull_time_t(struct ndr_pull *ndr, int ndr_flags, time_t *t);
+_PUBLIC_ enum ndr_err_code ndr_pull_ipv4address(struct ndr_pull *ndr, int ndr_flags, const char **address);
+_PUBLIC_ enum ndr_err_code ndr_push_ipv4address(struct ndr_push *ndr, int ndr_flags, const char *address);
+_PUBLIC_ void ndr_print_ipv4address(struct ndr_print *ndr, const char *name,
+ const char *address);
+_PUBLIC_ void ndr_print_struct(struct ndr_print *ndr, const char *name, const char *type);
+_PUBLIC_ void ndr_print_enum(struct ndr_print *ndr, const char *name, const char *type,
+ const char *val, uint32_t value);
+_PUBLIC_ void ndr_print_bitmap_flag(struct ndr_print *ndr, size_t size, const char *flag_name, uint32_t flag, uint32_t value);
+_PUBLIC_ void ndr_print_int8(struct ndr_print *ndr, const char *name, int8_t v);
+_PUBLIC_ void ndr_print_uint8(struct ndr_print *ndr, const char *name, uint8_t v);
+_PUBLIC_ void ndr_print_int16(struct ndr_print *ndr, const char *name, int16_t v);
+_PUBLIC_ void ndr_print_uint16(struct ndr_print *ndr, const char *name, uint16_t v);
+_PUBLIC_ void ndr_print_int32(struct ndr_print *ndr, const char *name, int32_t v);
+_PUBLIC_ void ndr_print_uint32(struct ndr_print *ndr, const char *name, uint32_t v);
+_PUBLIC_ void ndr_print_udlong(struct ndr_print *ndr, const char *name, uint64_t v);
+_PUBLIC_ void ndr_print_udlongr(struct ndr_print *ndr, const char *name, uint64_t v);
+_PUBLIC_ void ndr_print_dlong(struct ndr_print *ndr, const char *name, int64_t v);
+_PUBLIC_ void ndr_print_hyper(struct ndr_print *ndr, const char *name, uint64_t v);
+_PUBLIC_ void ndr_print_pointer(struct ndr_print *ndr, const char *name, void *v);
+_PUBLIC_ void ndr_print_ptr(struct ndr_print *ndr, const char *name, const void *p);
+_PUBLIC_ void ndr_print_NTTIME(struct ndr_print *ndr, const char *name, NTTIME t);
+_PUBLIC_ void ndr_print_NTTIME_1sec(struct ndr_print *ndr, const char *name, NTTIME t);
+_PUBLIC_ void ndr_print_NTTIME_hyper(struct ndr_print *ndr, const char *name, NTTIME t);
+_PUBLIC_ void ndr_print_time_t(struct ndr_print *ndr, const char *name, time_t t);
+_PUBLIC_ void ndr_print_union(struct ndr_print *ndr, const char *name, int level, const char *type);
+_PUBLIC_ void ndr_print_bad_level(struct ndr_print *ndr, const char *name, uint16_t level);
+_PUBLIC_ void ndr_print_array_uint8(struct ndr_print *ndr, const char *name,
+ const uint8_t *data, uint32_t count);
+_PUBLIC_ void ndr_print_DATA_BLOB(struct ndr_print *ndr, const char *name, DATA_BLOB r);
+_PUBLIC_ enum ndr_err_code ndr_push_DATA_BLOB(struct ndr_push *ndr, int ndr_flags, DATA_BLOB blob);
+_PUBLIC_ enum ndr_err_code ndr_pull_DATA_BLOB(struct ndr_pull *ndr, int ndr_flags, DATA_BLOB *blob);
+_PUBLIC_ uint32_t ndr_size_DATA_BLOB(int ret, const DATA_BLOB *data, int flags);
+_PUBLIC_ void ndr_print_bool(struct ndr_print *ndr, const char *name, const bool b);
+_PUBLIC_ void ndr_print_sockaddr_storage(struct ndr_print *ndr, const char *name, const struct sockaddr_storage *ss);
+
+/* The following definitions come from librpc/ndr/ndr_krb5pac.c */
+
+enum ndr_err_code ndr_push_PAC_BUFFER(struct ndr_push *ndr, int ndr_flags, const struct PAC_BUFFER *r);
+enum ndr_err_code ndr_pull_PAC_BUFFER(struct ndr_pull *ndr, int ndr_flags, struct PAC_BUFFER *r);
+void ndr_print_PAC_BUFFER(struct ndr_print *ndr, const char *name, const struct PAC_BUFFER *r);
+
+/* The following definitions come from librpc/ndr/ndr_misc.c */
+
+bool all_zero(const uint8_t *ptr, size_t size);
+void ndr_print_GUID(struct ndr_print *ndr, const char *name, const struct GUID *guid);
+bool ndr_syntax_id_equal(const struct ndr_syntax_id *i1,
+ const struct ndr_syntax_id *i2);
+enum ndr_err_code ndr_push_server_id(struct ndr_push *ndr, int ndr_flags, const struct server_id *r);
+enum ndr_err_code ndr_pull_server_id(struct ndr_pull *ndr, int ndr_flags, struct server_id *r);
+void ndr_print_server_id(struct ndr_print *ndr, const char *name, const struct server_id *r);
+
+/* The following definitions come from librpc/ndr/ndr_sec_helper.c */
+
+size_t ndr_size_dom_sid(const struct dom_sid *sid, int flags);
+size_t ndr_size_dom_sid28(const struct dom_sid *sid, int flags);
+size_t ndr_size_dom_sid0(const struct dom_sid *sid, int flags);
+size_t ndr_size_security_ace(const struct security_ace *ace, int flags);
+size_t ndr_size_security_acl(const struct security_acl *acl, int flags);
+size_t ndr_size_security_descriptor(const struct security_descriptor *sd, int flags);
+void ndr_print_dom_sid(struct ndr_print *ndr, const char *name, const struct dom_sid *sid);
+void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, const struct dom_sid *sid);
+void ndr_print_dom_sid28(struct ndr_print *ndr, const char *name, const struct dom_sid *sid);
+void ndr_print_dom_sid0(struct ndr_print *ndr, const char *name, const struct dom_sid *sid);
+
+/* The following definitions come from librpc/ndr/ndr_string.c */
+
+_PUBLIC_ enum ndr_err_code ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s);
+_PUBLIC_ enum ndr_err_code ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s);
+_PUBLIC_ size_t ndr_string_array_size(struct ndr_push *ndr, const char *s);
+_PUBLIC_ void ndr_print_string(struct ndr_print *ndr, const char *name, const char *s);
+_PUBLIC_ uint32_t ndr_size_string(int ret, const char * const* string, int flags) ;
+_PUBLIC_ enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, int ndr_flags, const char ***_a);
+_PUBLIC_ enum ndr_err_code ndr_push_string_array(struct ndr_push *ndr, int ndr_flags, const char **a);
+_PUBLIC_ void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a);
+_PUBLIC_ uint32_t ndr_string_length(const void *_var, uint32_t element_size);
+_PUBLIC_ enum ndr_err_code ndr_check_string_terminator(struct ndr_pull *ndr, uint32_t count, uint32_t element_size);
+_PUBLIC_ enum ndr_err_code ndr_pull_charset(struct ndr_pull *ndr, int ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset);
+_PUBLIC_ enum ndr_err_code ndr_push_charset(struct ndr_push *ndr, int ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset);
+_PUBLIC_ uint32_t ndr_charset_length(const void *var, charset_t chset);
+
+/* The following definitions come from librpc/ndr/sid.c */
+
+enum ndr_err_code ndr_push_dom_sid(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *r);
+enum ndr_err_code ndr_pull_dom_sid(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *r);
+char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid);
+enum ndr_err_code ndr_pull_dom_sid2(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid);
+enum ndr_err_code ndr_push_dom_sid2(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid);
+enum ndr_err_code ndr_pull_dom_sid28(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid);
+enum ndr_err_code ndr_push_dom_sid28(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid);
+enum ndr_err_code ndr_pull_dom_sid0(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid);
+enum ndr_err_code ndr_push_dom_sid0(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid);
+
+/* The following definitions come from librpc/ndr/uuid.c */
+
+_PUBLIC_ NTSTATUS GUID_from_string(const char *s, struct GUID *guid);
+_PUBLIC_ NTSTATUS NS_GUID_from_string(const char *s, struct GUID *guid);
+struct GUID GUID_random(void);
+_PUBLIC_ struct GUID GUID_zero(void);
+_PUBLIC_ bool GUID_all_zero(const struct GUID *u);
+_PUBLIC_ bool GUID_equal(const struct GUID *u1, const struct GUID *u2);
+_PUBLIC_ int GUID_compare(const struct GUID *u1, const struct GUID *u2);
+_PUBLIC_ char *GUID_string(TALLOC_CTX *mem_ctx, const struct GUID *guid);
+_PUBLIC_ char *GUID_string2(TALLOC_CTX *mem_ctx, const struct GUID *guid);
+_PUBLIC_ char *NS_GUID_string(TALLOC_CTX *mem_ctx, const struct GUID *guid);
+_PUBLIC_ bool policy_handle_empty(struct policy_handle *h) ;
+
+/* The following definitions come from librpc/rpc/binding.c */
+
+const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor);
+_PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b);
+_PUBLIC_ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_binding **b_out);
+_PUBLIC_ NTSTATUS dcerpc_floor_get_lhs_data(struct epm_floor *epm_floor, struct ndr_syntax_id *syntax);
+const char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor);
+enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot);
+_PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_tower(struct epm_tower *tower);
+_PUBLIC_ NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
+ struct epm_tower *tower,
+ struct dcerpc_binding **b_out);
+_PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding, struct epm_tower *tower);
+
+/* The following definitions come from librpc/rpc/dcerpc.c */
+
+struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p, const struct GUID *object,
+ const struct ndr_interface_table *table, uint32_t opnum,
+ TALLOC_CTX *mem_ctx, void *r);
+NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req);
+_PUBLIC_ NTSTATUS dcerpc_pipe_connect(TALLOC_CTX *parent_ctx, struct dcerpc_pipe **pp,
+ const char *binding_string, const struct ndr_interface_table *table,
+ struct cli_credentials *credentials, struct event_context *ev,
+ struct loadparm_context *lp_ctx);
+
+/* The following definitions come from libsmb/asn1.c */
+
+void asn1_free(ASN1_DATA *data);
+bool asn1_write(ASN1_DATA *data, const void *p, int len);
+bool asn1_write_uint8(ASN1_DATA *data, uint8 v);
+bool asn1_push_tag(ASN1_DATA *data, uint8 tag);
+bool asn1_pop_tag(ASN1_DATA *data);
+bool asn1_write_Integer(ASN1_DATA *data, int i);
+bool asn1_write_OID(ASN1_DATA *data, const char *OID);
+bool asn1_write_OctetString(ASN1_DATA *data, const void *p, size_t length);
+bool asn1_write_GeneralString(ASN1_DATA *data, const char *s);
+bool asn1_write_BOOLEAN(ASN1_DATA *data, bool v);
+bool asn1_write_BOOLEAN2(ASN1_DATA *data, bool v);
+bool asn1_check_BOOLEAN(ASN1_DATA *data, bool v);
+bool asn1_load(ASN1_DATA *data, DATA_BLOB blob);
+bool asn1_read(ASN1_DATA *data, void *p, int len);
+bool asn1_read_uint8(ASN1_DATA *data, uint8 *v);
+bool asn1_check_tag(ASN1_DATA *data, uint8 tag);
+bool asn1_start_tag(ASN1_DATA *data, uint8 tag);
+bool asn1_end_tag(ASN1_DATA *data);
+int asn1_tag_remaining(ASN1_DATA *data);
+bool asn1_read_OID(ASN1_DATA *data, char **OID);
+bool asn1_check_OID(ASN1_DATA *data, const char *OID);
+bool asn1_read_GeneralString(ASN1_DATA *data, char **s);
+bool asn1_read_OctetString(ASN1_DATA *data, DATA_BLOB *blob);
+bool asn1_read_Integer(ASN1_DATA *data, int *i);
+bool asn1_check_enumerated(ASN1_DATA *data, int v);
+bool asn1_write_enumerated(ASN1_DATA *data, uint8 v);
+bool ber_write_OID_String(DATA_BLOB *blob, const char *OID);
+bool ber_read_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB blob, const char **OID);
+
+/* The following definitions come from libsmb/cliconnect.c */
+
+ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user,
+ const char *pass, const char *user_domain,
+ const char * dest_realm);
+
+NTSTATUS cli_session_setup(struct cli_state *cli,
+ const char *user,
+ const char *pass, int passlen,
+ const char *ntpass, int ntpasslen,
+ const char *workgroup);
+bool cli_ulogoff(struct cli_state *cli);
+bool cli_send_tconX(struct cli_state *cli,
+ const char *share, const char *dev, const char *pass, int passlen);
+bool cli_tdis(struct cli_state *cli);
+void cli_negprot_send(struct cli_state *cli);
+bool cli_negprot(struct cli_state *cli);
+bool cli_session_request(struct cli_state *cli,
+ struct nmb_name *calling, struct nmb_name *called);
+NTSTATUS cli_connect(struct cli_state *cli,
+ const char *host,
+ struct sockaddr_storage *dest_ss);
+NTSTATUS cli_start_connection(struct cli_state **output_cli,
+ const char *my_name,
+ const char *dest_host,
+ struct sockaddr_storage *dest_ss, int port,
+ int signing_state, int flags,
+ bool *retry) ;
+NTSTATUS cli_full_connection(struct cli_state **output_cli,
+ const char *my_name,
+ const char *dest_host,
+ struct sockaddr_storage *dest_ss, int port,
+ const char *service, const char *service_type,
+ const char *user, const char *domain,
+ const char *password, int flags,
+ int signing_state,
+ bool *retry) ;
+bool attempt_netbios_session_request(struct cli_state **ppcli, const char *srchost, const char *desthost,
+ struct sockaddr_storage *pdest_ss);
+NTSTATUS cli_raw_tcon(struct cli_state *cli,
+ const char *service, const char *pass, const char *dev,
+ uint16 *max_xmit, uint16 *tid);
+struct cli_state *get_ipc_connect(char *server,
+ struct sockaddr_storage *server_ss,
+ const struct user_auth_info *user_info);
+struct cli_state *get_ipc_connect_master_ip(TALLOC_CTX *ctx,
+ struct ip_service *mb_ip,
+ const struct user_auth_info *user_info,
+ char **pp_workgroup_out);
+struct cli_state *get_ipc_connect_master_ip_bcast(TALLOC_CTX *ctx,
+ const struct user_auth_info *user_info,
+ char **pp_workgroup_out);
+
+/* The following definitions come from libsmb/clidfs.c */
+
+NTSTATUS cli_cm_force_encryption(struct cli_state *c,
+ const char *username,
+ const char *password,
+ const char *domain,
+ const char *sharename);
+const char *cli_cm_get_mntpoint(struct cli_state *c);
+struct cli_state *cli_cm_open(TALLOC_CTX *ctx,
+ struct cli_state *referring_cli,
+ const char *server,
+ const char *share,
+ bool show_hdr,
+ bool force_encrypt);
+void cli_cm_shutdown(void);
+void cli_cm_display(void);
+void cli_cm_set_credentials(void);
+void cli_cm_set_port(int port_number);
+void cli_cm_set_dest_name_type(int type);
+void cli_cm_set_signing_state(int state);
+void cli_cm_set_username(const char *username);
+void cli_cm_set_password(const char *newpass);
+void cli_cm_set_use_kerberos(void);
+void cli_cm_set_fallback_after_kerberos(void);
+void cli_cm_set_dest_ss(struct sockaddr_storage *pss);
+bool cli_dfs_get_referral(TALLOC_CTX *ctx,
+ struct cli_state *cli,
+ const char *path,
+ CLIENT_DFS_REFERRAL**refs,
+ size_t *num_refs,
+ uint16 *consumed);
+bool cli_resolve_path(TALLOC_CTX *ctx,
+ const char *mountpt,
+ struct cli_state *rootcli,
+ const char *path,
+ struct cli_state **targetcli,
+ char **pp_targetpath);
+
+/* The following definitions come from libsmb/clidgram.c */
+
+bool cli_send_mailslot(struct messaging_context *msg_ctx,
+ bool unique, const char *mailslot,
+ uint16 priority,
+ char *buf, int len,
+ const char *srcname, int src_type,
+ const char *dstname, int dest_type,
+ const struct sockaddr_storage *dest_ss);
+bool send_getdc_request(TALLOC_CTX *mem_ctx,
+ struct messaging_context *msg_ctx,
+ struct sockaddr_storage *dc_ss,
+ const char *domain_name,
+ const DOM_SID *sid,
+ uint32_t nt_version);
+bool receive_getdc_response(TALLOC_CTX *mem_ctx,
+ struct sockaddr_storage *dc_ss,
+ const char *domain_name,
+ uint32_t *nt_version,
+ const char **dc_name,
+ union nbt_cldap_netlogon **reply);
+
+/* The following definitions come from libsmb/clientgen.c */
+
+int cli_set_message(char *buf,int num_words,int num_bytes,bool zero);
+unsigned int cli_set_timeout(struct cli_state *cli, unsigned int timeout);
+int cli_set_port(struct cli_state *cli, int port);
+bool cli_receive_smb(struct cli_state *cli);
+ssize_t cli_receive_smb_data(struct cli_state *cli, char *buffer, size_t len);
+bool cli_receive_smb_readX_header(struct cli_state *cli);
+bool cli_send_smb(struct cli_state *cli);
+bool cli_send_smb_direct_writeX(struct cli_state *cli,
+ const char *p,
+ size_t extradata);
+void cli_setup_packet_buf(struct cli_state *cli, char *buf);
+void cli_setup_packet(struct cli_state *cli);
+void cli_setup_bcc(struct cli_state *cli, void *p);
+void cli_init_creds(struct cli_state *cli, const char *username, const char *domain, const char *password);
+void cli_setup_signing_state(struct cli_state *cli, int signing_state);
+struct cli_state *cli_initialise(void);
+void cli_nt_pipes_close(struct cli_state *cli);
+void cli_shutdown(struct cli_state *cli);
+void cli_sockopt(struct cli_state *cli, const char *options);
+uint16 cli_setpid(struct cli_state *cli, uint16 pid);
+bool cli_set_case_sensitive(struct cli_state *cli, bool case_sensitive);
+bool cli_send_keepalive(struct cli_state *cli);
+struct async_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ struct cli_state *cli, uint16_t num_echos,
+ DATA_BLOB data);
+NTSTATUS cli_echo_recv(struct async_req *req);
+NTSTATUS cli_echo(struct cli_state *cli, uint16_t num_echos, DATA_BLOB data);
+
+/* The following definitions come from libsmb/clierror.c */
+
+const char *cli_errstr(struct cli_state *cli);
+NTSTATUS cli_nt_error(struct cli_state *cli);
+void cli_dos_error(struct cli_state *cli, uint8 *eclass, uint32 *ecode);
+int cli_errno(struct cli_state *cli);
+bool cli_is_error(struct cli_state *cli);
+bool cli_is_nt_error(struct cli_state *cli);
+bool cli_is_dos_error(struct cli_state *cli);
+NTSTATUS cli_get_nt_error(struct cli_state *cli);
+void cli_set_nt_error(struct cli_state *cli, NTSTATUS status);
+void cli_reset_error(struct cli_state *cli);
+
+/* The following definitions come from libsmb/clifile.c */
+
+uint32 unix_perms_to_wire(mode_t perms);
+mode_t wire_perms_to_unix(uint32 perms);
+bool cli_unix_getfacl(struct cli_state *cli, const char *name, size_t *prb_size, char **retbuf);
+bool cli_unix_stat(struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbuf);
+bool cli_unix_symlink(struct cli_state *cli, const char *oldname, const char *newname);
+bool cli_unix_hardlink(struct cli_state *cli, const char *oldname, const char *newname);
+bool cli_unix_chmod(struct cli_state *cli, const char *fname, mode_t mode);
+bool cli_unix_chown(struct cli_state *cli, const char *fname, uid_t uid, gid_t gid);
+bool cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst);
+bool cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst);
+bool cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst);
+bool cli_unlink_full(struct cli_state *cli, const char *fname, uint16 attrs);
+bool cli_unlink(struct cli_state *cli, const char *fname);
+bool cli_mkdir(struct cli_state *cli, const char *dname);
+bool cli_rmdir(struct cli_state *cli, const char *dname);
+int cli_nt_delete_on_close(struct cli_state *cli, int fnum, bool flag);
+int cli_nt_create_full(struct cli_state *cli, const char *fname,
+ uint32 CreatFlags, uint32 DesiredAccess,
+ uint32 FileAttributes, uint32 ShareAccess,
+ uint32 CreateDisposition, uint32 CreateOptions,
+ uint8 SecuityFlags);
+int cli_nt_create(struct cli_state *cli, const char *fname, uint32 DesiredAccess);
+uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2, const char *str);
+struct async_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ struct cli_state *cli,
+ const char *fname, int flags, int share_mode);
+NTSTATUS cli_open_recv(struct async_req *req, int *fnum);
+int cli_open(struct cli_state *cli, const char *fname, int flags, int share_mode);
+struct async_req *cli_close_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ struct cli_state *cli, int fnum);
+NTSTATUS cli_close_recv(struct async_req *req);
+bool cli_close(struct cli_state *cli, int fnum);
+bool cli_ftruncate(struct cli_state *cli, int fnum, uint64_t size);
+NTSTATUS cli_locktype(struct cli_state *cli, int fnum,
+ uint32 offset, uint32 len,
+ int timeout, unsigned char locktype);
+bool cli_lock(struct cli_state *cli, int fnum,
+ uint32 offset, uint32 len, int timeout, enum brl_type lock_type);
+bool cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len);
+bool cli_lock64(struct cli_state *cli, int fnum,
+ SMB_BIG_UINT offset, SMB_BIG_UINT len, int timeout, enum brl_type lock_type);
+bool cli_unlock64(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_UINT len);
+bool cli_posix_lock(struct cli_state *cli, int fnum,
+ SMB_BIG_UINT offset, SMB_BIG_UINT len,
+ bool wait_lock, enum brl_type lock_type);
+bool cli_posix_unlock(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_UINT len);
+bool cli_posix_getlock(struct cli_state *cli, int fnum, SMB_BIG_UINT *poffset, SMB_BIG_UINT *plen);
+bool cli_getattrE(struct cli_state *cli, int fd,
+ uint16 *attr, SMB_OFF_T *size,
+ time_t *change_time,
+ time_t *access_time,
+ time_t *write_time);
+bool cli_getatr(struct cli_state *cli, const char *fname,
+ uint16 *attr, SMB_OFF_T *size, time_t *write_time);
+bool cli_setattrE(struct cli_state *cli, int fd,
+ time_t change_time,
+ time_t access_time,
+ time_t write_time);
+bool cli_setatr(struct cli_state *cli, const char *fname, uint16 attr, time_t t);
+bool cli_chkpath(struct cli_state *cli, const char *path);
+bool cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail);
+int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path);
+NTSTATUS cli_raw_ioctl(struct cli_state *cli, int fnum, uint32 code, DATA_BLOB *blob);
+bool cli_set_ea_path(struct cli_state *cli, const char *path, const char *ea_name, const char *ea_val, size_t ea_len);
+bool cli_set_ea_fnum(struct cli_state *cli, int fnum, const char *ea_name, const char *ea_val, size_t ea_len);
+bool cli_get_ea_list_path(struct cli_state *cli, const char *path,
+ TALLOC_CTX *ctx,
+ size_t *pnum_eas,
+ struct ea_struct **pea_list);
+bool cli_get_ea_list_fnum(struct cli_state *cli, int fnum,
+ TALLOC_CTX *ctx,
+ size_t *pnum_eas,
+ struct ea_struct **pea_list);
+int cli_posix_open(struct cli_state *cli, const char *fname, int flags, mode_t mode);
+int cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode);
+bool cli_posix_unlink(struct cli_state *cli, const char *fname);
+int cli_posix_rmdir(struct cli_state *cli, const char *fname);
+
+/* The following definitions come from libsmb/clifsinfo.c */
+
+bool cli_unix_extensions_version(struct cli_state *cli, uint16 *pmajor, uint16 *pminor,
+ uint32 *pcaplow, uint32 *pcaphigh);
+bool cli_set_unix_extensions_capabilities(struct cli_state *cli, uint16 major, uint16 minor,
+ uint32 caplow, uint32 caphigh);
+bool cli_get_fs_attr_info(struct cli_state *cli, uint32 *fs_attr);
+bool cli_get_fs_volume_info_old(struct cli_state *cli, fstring volume_name, uint32 *pserial_number);
+bool cli_get_fs_volume_info(struct cli_state *cli, fstring volume_name, uint32 *pserial_number, time_t *pdate);
+NTSTATUS cli_raw_ntlm_smb_encryption_start(struct cli_state *cli,
+ const char *user,
+ const char *pass,
+ const char *domain);
+NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli);
+NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli);
+NTSTATUS cli_force_encryption(struct cli_state *c,
+ const char *username,
+ const char *password,
+ const char *domain);
+
+/* The following definitions come from libsmb/clikrb5.c */
+
+bool unwrap_edata_ntstatus(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *edata,
+ DATA_BLOB *edata_out);
+bool unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, DATA_BLOB *unwrapped_pac_data);
+int cli_krb5_get_ticket(const char *principal, time_t time_offset,
+ DATA_BLOB *ticket, DATA_BLOB *session_key_krb5,
+ uint32 extra_ap_opts, const char *ccname,
+ time_t *tgs_expire);
+
+/* The following definitions come from libsmb/clilist.c */
+
+int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
+ void (*fn)(const char *, file_info *, const char *, void *), void *state);
+int cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute,
+ void (*fn)(const char *, file_info *, const char *, void *), void *state);
+int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute,
+ void (*fn)(const char *, file_info *, const char *, void *), void *state);
+
+/* The following definitions come from libsmb/climessage.c */
+
+int cli_message_start_build(struct cli_state *cli, const char *host, const char *username);
+bool cli_message_start(struct cli_state *cli, const char *host, const char *username,
+ int *grp);
+int cli_message_text_build(struct cli_state *cli, const char *msg, int len, int grp);
+bool cli_message_text(struct cli_state *cli, const char *msg, int len, int grp);
+int cli_message_end_build(struct cli_state *cli, int grp);
+bool cli_message_end(struct cli_state *cli, int grp);
+
+/* The following definitions come from libsmb/clioplock.c */
+
+bool cli_oplock_ack(struct cli_state *cli, int fnum, unsigned char level);
+void cli_oplock_handler(struct cli_state *cli,
+ bool (*handler)(struct cli_state *, int, unsigned char));
+
+/* The following definitions come from libsmb/cliprint.c */
+
+int cli_print_queue(struct cli_state *cli,
+ void (*fn)(struct print_job_info *));
+int cli_printjob_del(struct cli_state *cli, int job);
+int cli_spl_open(struct cli_state *cli, const char *fname, int flags, int share_mode);
+bool cli_spl_close(struct cli_state *cli, int fnum);
+
+/* The following definitions come from libsmb/cliquota.c */
+
+bool cli_get_quota_handle(struct cli_state *cli, int *quota_fnum);
+void free_ntquota_list(SMB_NTQUOTA_LIST **qt_list);
+bool cli_get_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt);
+bool cli_set_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt);
+bool cli_list_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_LIST **pqt_list);
+bool cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt);
+bool cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt);
+void dump_ntquota(SMB_NTQUOTA_STRUCT *qt, bool _verbose, bool _numeric, void (*_sidtostring)(fstring str, DOM_SID *sid, bool _numeric));
+void dump_ntquota_list(SMB_NTQUOTA_LIST **qtl, bool _verbose, bool _numeric, void (*_sidtostring)(fstring str, DOM_SID *sid, bool _numeric));
+
+/* The following definitions come from libsmb/clirap.c */
+
+bool cli_api_pipe(struct cli_state *cli, const char *pipe_name,
+ uint16 *setup, uint32 setup_count, uint32 max_setup_count,
+ char *params, uint32 param_count, uint32 max_param_count,
+ char *data, uint32 data_count, uint32 max_data_count,
+ char **rparam, uint32 *rparam_count,
+ char **rdata, uint32 *rdata_count);
+bool cli_api(struct cli_state *cli,
+ char *param, int prcnt, int mprcnt,
+ char *data, int drcnt, int mdrcnt,
+ char **rparam, unsigned int *rprcnt,
+ char **rdata, unsigned int *rdrcnt);
+bool cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation);
+int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state);
+bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
+ void (*fn)(const char *, uint32, const char *, void *),
+ void *state);
+bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
+ const char *old_password);
+bool cli_qpathinfo(struct cli_state *cli,
+ const char *fname,
+ time_t *change_time,
+ time_t *access_time,
+ time_t *write_time,
+ SMB_OFF_T *size,
+ uint16 *mode);
+bool cli_setpathinfo(struct cli_state *cli, const char *fname,
+ time_t create_time,
+ time_t access_time,
+ time_t write_time,
+ time_t change_time,
+ uint16 mode);
+bool cli_qpathinfo2(struct cli_state *cli, const char *fname,
+ struct timespec *create_time,
+ struct timespec *access_time,
+ struct timespec *write_time,
+ struct timespec *change_time,
+ SMB_OFF_T *size, uint16 *mode,
+ SMB_INO_T *ino);
+bool cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *pnum_streams,
+ struct stream_struct **pstreams);
+bool cli_qfilename(struct cli_state *cli, int fnum, char *name, size_t namelen);
+bool cli_qfileinfo(struct cli_state *cli, int fnum,
+ uint16 *mode, SMB_OFF_T *size,
+ struct timespec *create_time,
+ struct timespec *access_time,
+ struct timespec *write_time,
+ struct timespec *change_time,
+ SMB_INO_T *ino);
+bool cli_qpathinfo_basic( struct cli_state *cli, const char *name,
+ SMB_STRUCT_STAT *sbuf, uint32 *attributes );
+bool cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutdata, uint32 *poutlen);
+NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name);
+
+/* The following definitions come from libsmb/clirap2.c */
+
+int cli_NetGroupDelete(struct cli_state *cli, const char *group_name);
+int cli_NetGroupAdd(struct cli_state *cli, RAP_GROUP_INFO_1 *grinfo);
+int cli_RNetGroupEnum(struct cli_state *cli, void (*fn)(const char *, const char *, void *), void *state);
+int cli_RNetGroupEnum0(struct cli_state *cli,
+ void (*fn)(const char *, void *),
+ void *state);
+int cli_NetGroupDelUser(struct cli_state * cli, const char *group_name, const char *user_name);
+int cli_NetGroupAddUser(struct cli_state * cli, const char *group_name, const char *user_name);
+int cli_NetGroupGetUsers(struct cli_state * cli, const char *group_name, void (*fn)(const char *, void *), void *state );
+int cli_NetUserGetGroups(struct cli_state * cli, const char *user_name, void (*fn)(const char *, void *), void *state );
+int cli_NetUserDelete(struct cli_state *cli, const char * user_name );
+int cli_NetUserAdd(struct cli_state *cli, RAP_USER_INFO_1 * userinfo );
+int cli_RNetUserEnum(struct cli_state *cli, void (*fn)(const char *, const char *, const char *, const char *, void *), void *state);
+int cli_RNetUserEnum0(struct cli_state *cli,
+ void (*fn)(const char *, void *),
+ void *state);
+int cli_NetFileClose(struct cli_state *cli, uint32 file_id );
+int cli_NetFileGetInfo(struct cli_state *cli, uint32 file_id, void (*fn)(const char *, const char *, uint16, uint16, uint32));
+int cli_NetFileEnum(struct cli_state *cli, const char * user,
+ const char * base_path,
+ void (*fn)(const char *, const char *, uint16, uint16,
+ uint32));
+int cli_NetShareAdd(struct cli_state *cli, RAP_SHARE_INFO_2 * sinfo );
+int cli_NetShareDelete(struct cli_state *cli, const char * share_name );
+bool cli_get_pdc_name(struct cli_state *cli, const char *workgroup, char **pdc_name);
+bool cli_get_server_domain(struct cli_state *cli);
+bool cli_get_server_type(struct cli_state *cli, uint32 *pstype);
+bool cli_get_server_name(TALLOC_CTX *mem_ctx, struct cli_state *cli,
+ char **servername);
+bool cli_ns_check_server_type(struct cli_state *cli, char *workgroup, uint32 stype);
+bool cli_NetWkstaUserLogoff(struct cli_state *cli, const char *user, const char *workstation);
+int cli_NetPrintQEnum(struct cli_state *cli,
+ void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
+ void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,uint,uint,const char*));
+int cli_NetPrintQGetInfo(struct cli_state *cli, const char *printer,
+ void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
+ void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,uint,uint,const char*));
+int cli_RNetServiceEnum(struct cli_state *cli, void (*fn)(const char *, const char *, void *), void *state);
+int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16, uint16, uint16, uint, uint, uint, char *));
+int cli_NetSessionGetInfo(struct cli_state *cli, const char *workstation,
+ void (*fn)(const char *, const char *, uint16, uint16, uint16, uint, uint, uint, const char *));
+int cli_NetSessionDel(struct cli_state *cli, const char *workstation);
+int cli_NetConnectionEnum(struct cli_state *cli, const char *qualifier,
+ void (*fn)(uint16_t conid, uint16_t contype,
+ uint16_t numopens, uint16_t numusers,
+ uint32_t contime, const char *username,
+ const char *netname));
+
+/* The following definitions come from libsmb/clireadwrite.c */
+
+struct async_req *cli_read_andx_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli, int fnum,
+ off_t offset, size_t size);
+NTSTATUS cli_read_andx_recv(struct async_req *req, ssize_t *received,
+ uint8_t **rcvbuf);
+struct async_req *cli_pull_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ uint16_t fnum, off_t start_offset,
+ SMB_OFF_T size, size_t window_size,
+ NTSTATUS (*sink)(char *buf, size_t n,
+ void *priv),
+ void *priv);
+NTSTATUS cli_pull_recv(struct async_req *req, SMB_OFF_T *received);
+NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum,
+ off_t start_offset, SMB_OFF_T size, size_t window_size,
+ NTSTATUS (*sink)(char *buf, size_t n, void *priv),
+ void *priv, SMB_OFF_T *received);
+ssize_t cli_read(struct cli_state *cli, int fnum, char *buf,
+ off_t offset, size_t size);
+ssize_t cli_readraw(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size);
+ssize_t cli_write(struct cli_state *cli,
+ int fnum, uint16 write_mode,
+ const char *buf, off_t offset, size_t size);
+ssize_t cli_smbwrite(struct cli_state *cli,
+ int fnum, char *buf, off_t offset, size_t size1);
+
+/* The following definitions come from libsmb/clisecdesc.c */
+
+SEC_DESC *cli_query_secdesc(struct cli_state *cli, int fnum,
+ TALLOC_CTX *mem_ctx);
+bool cli_set_secdesc(struct cli_state *cli, int fnum, SEC_DESC *sd);
+
+/* The following definitions come from libsmb/clispnego.c */
+
+DATA_BLOB spnego_gen_negTokenInit(char guid[16],
+ const char *OIDs[],
+ const char *principal);
+DATA_BLOB gen_negTokenInit(const char *OID, DATA_BLOB blob);
+bool spnego_parse_negTokenInit(DATA_BLOB blob,
+ char *OIDs[ASN1_MAX_OIDS],
+ char **principal);
+DATA_BLOB gen_negTokenTarg(const char *OIDs[], DATA_BLOB blob);
+bool parse_negTokenTarg(DATA_BLOB blob, char *OIDs[ASN1_MAX_OIDS], DATA_BLOB *secblob);
+DATA_BLOB spnego_gen_krb5_wrap(const DATA_BLOB ticket, const uint8 tok_id[2]);
+bool spnego_parse_krb5_wrap(DATA_BLOB blob, DATA_BLOB *ticket, uint8 tok_id[2]);
+int spnego_gen_negTokenTarg(const char *principal, int time_offset,
+ DATA_BLOB *targ,
+ DATA_BLOB *session_key_krb5, uint32 extra_ap_opts,
+ time_t *expire_time);
+bool spnego_parse_challenge(const DATA_BLOB blob,
+ DATA_BLOB *chal1, DATA_BLOB *chal2);
+DATA_BLOB spnego_gen_auth(DATA_BLOB blob);
+bool spnego_parse_auth(DATA_BLOB blob, DATA_BLOB *auth);
+DATA_BLOB spnego_gen_auth_response(DATA_BLOB *reply, NTSTATUS nt_status,
+ const char *mechOID);
+bool spnego_parse_auth_response(DATA_BLOB blob, NTSTATUS nt_status,
+ const char *mechOID,
+ DATA_BLOB *auth);
+
+/* The following definitions come from libsmb/clistr.c */
+
+size_t clistr_push_fn(const char *function,
+ unsigned int line,
+ struct cli_state *cli,
+ void *dest,
+ const char *src,
+ int dest_len,
+ int flags);
+size_t clistr_pull_fn(const char *function,
+ unsigned int line,
+ struct cli_state *cli,
+ char *dest,
+ const void *src,
+ int dest_len,
+ int src_len,
+ int flags);
+size_t clistr_pull_talloc_fn(const char *function,
+ unsigned int line,
+ TALLOC_CTX *ctx,
+ struct cli_state *cli,
+ char **pp_dest,
+ const void *src,
+ int src_len,
+ int flags);
+size_t clistr_align_out(struct cli_state *cli, const void *p, int flags);
+size_t clistr_align_in(struct cli_state *cli, const void *p, int flags);
+
+/* The following definitions come from libsmb/clitrans.c */
+
+bool cli_send_trans(struct cli_state *cli, int trans,
+ const char *pipe_name,
+ int fid, int flags,
+ uint16 *setup, unsigned int lsetup, unsigned int msetup,
+ const char *param, unsigned int lparam, unsigned int mparam,
+ const char *data, unsigned int ldata, unsigned int mdata);
+bool cli_receive_trans(struct cli_state *cli,int trans,
+ char **param, unsigned int *param_len,
+ char **data, unsigned int *data_len);
+bool cli_send_nt_trans(struct cli_state *cli,
+ int function,
+ int flags,
+ uint16 *setup, unsigned int lsetup, unsigned int msetup,
+ char *param, unsigned int lparam, unsigned int mparam,
+ char *data, unsigned int ldata, unsigned int mdata);
+bool cli_receive_nt_trans(struct cli_state *cli,
+ char **param, unsigned int *param_len,
+ char **data, unsigned int *data_len);
+struct async_req *cli_trans_send(
+ TALLOC_CTX *mem_ctx, struct event_context *ev,
+ struct cli_state *cli, uint8_t trans_cmd,
+ const char *pipe_name, uint16_t fid, uint16_t function, int flags,
+ uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
+ uint8_t *param, uint32_t num_param, uint32_t max_param,
+ uint8_t *data, uint32_t num_data, uint32_t max_data);
+NTSTATUS cli_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
+ uint16_t **setup, uint8_t *num_setup,
+ uint8_t **param, uint32_t *num_param,
+ uint8_t **data, uint32_t *num_data);
+NTSTATUS cli_trans(TALLOC_CTX *mem_ctx, struct cli_state *cli,
+ uint8_t trans_cmd,
+ const char *pipe_name, uint16_t fid, uint16_t function,
+ int flags,
+ uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
+ uint8_t *param, uint32_t num_param, uint32_t max_param,
+ uint8_t *data, uint32_t num_data, uint32_t max_data,
+ uint16_t **rsetup, uint8_t *num_rsetup,
+ uint8_t **rparam, uint32_t *num_rparam,
+ uint8_t **rdata, uint32_t *num_rdata);
+
+/* The following definitions come from libsmb/conncache.c */
+
+NTSTATUS check_negative_conn_cache_timeout( const char *domain, const char *server, unsigned int failed_cache_timeout );
+NTSTATUS check_negative_conn_cache( const char *domain, const char *server);
+void add_failed_connection_entry(const char *domain, const char *server, NTSTATUS result) ;
+void delete_negative_conn_cache(const char *domain, const char *server);
+void flush_negative_conn_cache( void );
+void flush_negative_conn_cache_for_domain(const char *domain);
+
+/* The following definitions come from libsmb/credentials.c */
+
+char *credstr(const unsigned char *cred);
+void creds_server_init(uint32 neg_flags,
+ struct dcinfo *dc,
+ struct netr_Credential *clnt_chal,
+ struct netr_Credential *srv_chal,
+ const unsigned char mach_pw[16],
+ struct netr_Credential *init_chal_out);
+bool netlogon_creds_server_check(const struct dcinfo *dc,
+ const struct netr_Credential *rcv_cli_chal_in);
+bool netlogon_creds_server_step(struct dcinfo *dc,
+ const struct netr_Authenticator *received_cred,
+ struct netr_Authenticator *cred_out);
+void creds_client_init(uint32 neg_flags,
+ struct dcinfo *dc,
+ struct netr_Credential *clnt_chal,
+ struct netr_Credential *srv_chal,
+ const unsigned char mach_pw[16],
+ struct netr_Credential *init_chal_out);
+bool netlogon_creds_client_check(const struct dcinfo *dc,
+ const struct netr_Credential *rcv_srv_chal_in);
+void netlogon_creds_client_step(struct dcinfo *dc,
+ struct netr_Authenticator *next_cred_out);
+
+/* The following definitions come from libsmb/dcerpc_err.c */
+
+const char *dcerpc_errstr(uint32 fault_code);
+
+/* The following definitions come from libsmb/doserr.c */
+
+const char *dos_errstr(WERROR werror);
+const char *get_friendly_werror_msg(WERROR werror);
+const char *win_errstr(WERROR werror);
+
+/* The following definitions come from libsmb/dsgetdcname.c */
+
+void debug_dsdcinfo_flags(int lvl, uint32_t flags);
+NTSTATUS dsgetdcname(TALLOC_CTX *mem_ctx,
+ struct messaging_context *msg_ctx,
+ const char *domain_name,
+ struct GUID *domain_guid,
+ const char *site_name,
+ uint32_t flags,
+ struct netr_DsRGetDCNameInfo **info);
+
+/* The following definitions come from libsmb/errormap.c */
+
+NTSTATUS dos_to_ntstatus(uint8 eclass, uint32 ecode);
+void ntstatus_to_dos(NTSTATUS ntstatus, uint8 *eclass, uint32 *ecode);
+NTSTATUS werror_to_ntstatus(WERROR error);
+WERROR ntstatus_to_werror(NTSTATUS error);
+NTSTATUS map_nt_error_from_gss(uint32 gss_maj, uint32 minor);
+
+/* The following definitions come from libsmb/namecache.c */
+
+bool namecache_enable(void);
+bool namecache_shutdown(void);
+bool namecache_store(const char *name,
+ int name_type,
+ int num_names,
+ struct ip_service *ip_list);
+bool namecache_fetch(const char *name,
+ int name_type,
+ struct ip_service **ip_list,
+ int *num_names);
+bool namecache_delete(const char *name, int name_type);
+void namecache_flush(void);
+bool namecache_status_store(const char *keyname, int keyname_type,
+ int name_type, const struct sockaddr_storage *keyip,
+ const char *srvname);
+bool namecache_status_fetch(const char *keyname,
+ int keyname_type,
+ int name_type,
+ const struct sockaddr_storage *keyip,
+ char *srvname_out);
+
+/* The following definitions come from libsmb/namequery.c */
+
+bool saf_store( const char *domain, const char *servername );
+bool saf_delete( const char *domain );
+char *saf_fetch( const char *domain );
+NODE_STATUS_STRUCT *node_status_query(int fd,
+ struct nmb_name *name,
+ const struct sockaddr_storage *to_ss,
+ int *num_names,
+ struct node_status_extra *extra);
+bool name_status_find(const char *q_name,
+ int q_type,
+ int type,
+ const struct sockaddr_storage *to_ss,
+ fstring name);
+int ip_service_compare(struct ip_service *ss1, struct ip_service *ss2);
+struct sockaddr_storage *name_query(int fd,
+ const char *name,
+ int name_type,
+ bool bcast,
+ bool recurse,
+ const struct sockaddr_storage *to_ss,
+ int *count,
+ int *flags,
+ bool *timed_out);
+XFILE *startlmhosts(const char *fname);
+bool getlmhostsent(TALLOC_CTX *ctx, XFILE *fp, char **pp_name, int *name_type,
+ struct sockaddr_storage *pss);
+void endlmhosts(XFILE *fp);
+NTSTATUS name_resolve_bcast(const char *name,
+ int name_type,
+ struct ip_service **return_iplist,
+ int *return_count);
+NTSTATUS resolve_wins(const char *name,
+ int name_type,
+ struct ip_service **return_iplist,
+ int *return_count);
+NTSTATUS internal_resolve_name(const char *name,
+ int name_type,
+ const char *sitename,
+ struct ip_service **return_iplist,
+ int *return_count,
+ const char *resolve_order);
+bool resolve_name(const char *name,
+ struct sockaddr_storage *return_ss,
+ int name_type);
+NTSTATUS resolve_name_list(TALLOC_CTX *ctx,
+ const char *name,
+ int name_type,
+ struct sockaddr_storage **return_ss_arr,
+ unsigned int *p_num_entries);
+bool find_master_ip(const char *group, struct sockaddr_storage *master_ss);
+bool get_pdc_ip(const char *domain, struct sockaddr_storage *pss);
+NTSTATUS get_sorted_dc_list( const char *domain,
+ const char *sitename,
+ struct ip_service **ip_list,
+ int *count,
+ bool ads_only );
+NTSTATUS get_kdc_list( const char *realm,
+ const char *sitename,
+ struct ip_service **ip_list,
+ int *count);
+
+/* The following definitions come from libsmb/namequery_dc.c */
+
+bool get_dc_name(const char *domain,
+ const char *realm,
+ fstring srv_name,
+ struct sockaddr_storage *ss_out);
+
+/* The following definitions come from libsmb/nmblib.c */
+
+void debug_nmb_packet(struct packet_struct *p);
+void put_name(char *dest, const char *name, int pad, unsigned int name_type);
+char *nmb_namestr(const struct nmb_name *n);
+struct packet_struct *copy_packet(struct packet_struct *packet);
+void free_packet(struct packet_struct *packet);
+struct packet_struct *parse_packet(char *buf,int length,
+ enum packet_type packet_type,
+ struct in_addr ip,
+ int port);
+struct packet_struct *read_packet(int fd,enum packet_type packet_type);
+void make_nmb_name( struct nmb_name *n, const char *name, int type);
+bool nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2);
+int build_packet(char *buf, size_t buflen, struct packet_struct *p);
+bool send_packet(struct packet_struct *p);
+struct packet_struct *receive_packet(int fd,enum packet_type type,int t);
+struct packet_struct *receive_nmb_packet(int fd, int t, int trn_id);
+struct packet_struct *receive_dgram_packet(int fd, int t,
+ const char *mailslot_name);
+bool match_mailslot_name(struct packet_struct *p, const char *mailslot_name);
+int matching_len_bits(unsigned char *p1, unsigned char *p2, size_t len);
+void sort_query_replies(char *data, int n, struct in_addr ip);
+int name_mangle( char *In, char *Out, char name_type );
+int name_extract(char *buf,int ofs, fstring name);
+int name_len(char *s1);
+
+/* The following definitions come from libsmb/nterr.c */
+
+const char *nt_errstr(NTSTATUS nt_code);
+const char *get_friendly_nt_error_msg(NTSTATUS nt_code);
+const char *get_nt_error_c_code(NTSTATUS nt_code);
+NTSTATUS nt_status_string_to_code(char *nt_status_str);
+NTSTATUS nt_status_squash(NTSTATUS nt_status);
+
+/* The following definitions come from libsmb/ntlm_check.c */
+
+NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *challenge,
+ const DATA_BLOB *lm_response,
+ const DATA_BLOB *nt_response,
+ const DATA_BLOB *lm_interactive_pwd,
+ const DATA_BLOB *nt_interactive_pwd,
+ const char *username,
+ const char *client_username,
+ const char *client_domain,
+ const uint8 *lm_pw, const uint8 *nt_pw,
+ DATA_BLOB *user_sess_key,
+ DATA_BLOB *lm_sess_key);
+
+/* The following definitions come from libsmb/ntlmssp.c */
+
+void debug_ntlmssp_flags(uint32 neg_flags);
+NTSTATUS ntlmssp_set_username(NTLMSSP_STATE *ntlmssp_state, const char *user) ;
+NTSTATUS ntlmssp_set_hashes(NTLMSSP_STATE *ntlmssp_state,
+ const unsigned char lm_hash[16],
+ const unsigned char nt_hash[16]) ;
+NTSTATUS ntlmssp_set_password(NTLMSSP_STATE *ntlmssp_state, const char *password) ;
+NTSTATUS ntlmssp_set_domain(NTLMSSP_STATE *ntlmssp_state, const char *domain) ;
+NTSTATUS ntlmssp_set_workstation(NTLMSSP_STATE *ntlmssp_state, const char *workstation) ;
+NTSTATUS ntlmssp_store_response(NTLMSSP_STATE *ntlmssp_state,
+ DATA_BLOB response) ;
+void ntlmssp_want_feature_list(NTLMSSP_STATE *ntlmssp_state, char *feature_list);
+void ntlmssp_want_feature(NTLMSSP_STATE *ntlmssp_state, uint32 feature);
+NTSTATUS ntlmssp_update(NTLMSSP_STATE *ntlmssp_state,
+ const DATA_BLOB in, DATA_BLOB *out) ;
+void ntlmssp_end(NTLMSSP_STATE **ntlmssp_state);
+DATA_BLOB ntlmssp_weaken_keys(NTLMSSP_STATE *ntlmssp_state, TALLOC_CTX *mem_ctx);
+NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state);
+NTSTATUS ntlmssp_client_start(NTLMSSP_STATE **ntlmssp_state);
+
+/* The following definitions come from libsmb/ntlmssp_parse.c */
+
+bool msrpc_gen(DATA_BLOB *blob,
+ const char *format, ...);
+bool msrpc_parse(const DATA_BLOB *blob,
+ const char *format, ...);
+
+/* The following definitions come from libsmb/ntlmssp_sign.c */
+
+NTSTATUS ntlmssp_sign_packet(NTLMSSP_STATE *ntlmssp_state,
+ const uchar *data, size_t length,
+ const uchar *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig) ;
+NTSTATUS ntlmssp_check_packet(NTLMSSP_STATE *ntlmssp_state,
+ const uchar *data, size_t length,
+ const uchar *whole_pdu, size_t pdu_length,
+ const DATA_BLOB *sig) ;
+NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state,
+ uchar *data, size_t length,
+ uchar *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig);
+NTSTATUS ntlmssp_unseal_packet(NTLMSSP_STATE *ntlmssp_state,
+ uchar *data, size_t length,
+ uchar *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig);
+NTSTATUS ntlmssp_sign_init(NTLMSSP_STATE *ntlmssp_state);
+
+/* The following definitions come from libsmb/passchange.c */
+
+NTSTATUS remote_password_change(const char *remote_machine, const char *user_name,
+ const char *old_passwd, const char *new_passwd,
+ char **err_str);
+
+/* The following definitions come from libsmb/pwd_cache.c */
+
+void pwd_set_cleartext(struct pwd_info *pwd, const char *clr);
+void pwd_get_cleartext(struct pwd_info *pwd, fstring clr);
+
+/* The following definitions come from libsmb/samlogon_cache.c */
+
+bool netsamlogon_cache_init(void);
+bool netsamlogon_cache_shutdown(void);
+void netsamlogon_clear_cached_user(struct netr_SamInfo3 *info3);
+bool netsamlogon_cache_store(const char *username, struct netr_SamInfo3 *info3);
+struct netr_SamInfo3 *netsamlogon_cache_get(TALLOC_CTX *mem_ctx, const DOM_SID *user_sid);
+bool netsamlogon_cache_have(const DOM_SID *user_sid);
+
+/* The following definitions come from libsmb/smb_seal.c */
+
+NTSTATUS get_enc_ctx_num(const uint8_t *buf, uint16 *p_enc_ctx_num);
+bool common_encryption_on(struct smb_trans_enc_state *es);
+NTSTATUS common_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf);
+NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state,
+ uint16 enc_ctx_num,
+ char *buf,
+ char **ppbuf_out);
+NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out);
+NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf);
+void common_free_encryption_state(struct smb_trans_enc_state **pp_es);
+void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf);
+bool cli_encryption_on(struct cli_state *cli);
+void cli_free_encryption_context(struct cli_state *cli);
+void cli_free_enc_buffer(struct cli_state *cli, char *buf);
+NTSTATUS cli_decrypt_message(struct cli_state *cli);
+NTSTATUS cli_encrypt_message(struct cli_state *cli, char *buf, char **buf_out);
+
+/* The following definitions come from libsmb/smb_signing.c */
+
+bool cli_simple_set_signing(struct cli_state *cli,
+ const DATA_BLOB user_session_key,
+ const DATA_BLOB response);
+bool cli_null_set_signing(struct cli_state *cli);
+bool cli_temp_set_signing(struct cli_state *cli);
+void cli_free_signing_context(struct cli_state *cli);
+void cli_calculate_sign_mac(struct cli_state *cli, char *buf);
+bool cli_check_sign_mac(struct cli_state *cli, char *buf);
+bool client_set_trans_sign_state_on(struct cli_state *cli, uint16 mid);
+bool client_set_trans_sign_state_off(struct cli_state *cli, uint16 mid);
+bool client_is_signing_on(struct cli_state *cli);
+bool srv_oplock_set_signing(bool onoff);
+bool srv_check_sign_mac(const char *inbuf, bool must_be_ok);
+void srv_calculate_sign_mac(char *outbuf);
+void srv_defer_sign_response(uint16 mid);
+void srv_cancel_sign_response(uint16 mid);
+void srv_set_signing_negotiated(void);
+bool srv_is_signing_active(void);
+bool srv_is_signing_negotiated(void);
+bool srv_signing_started(void);
+void srv_set_signing(const DATA_BLOB user_session_key, const DATA_BLOB response);
+
+/* The following definitions come from libsmb/smbdes.c */
+
+void des_crypt56(unsigned char *out, const unsigned char *in, const unsigned char *key, int forw);
+void E_P16(const unsigned char *p14,unsigned char *p16);
+void E_P24(const unsigned char *p21, const unsigned char *c8, unsigned char *p24);
+void D_P16(const unsigned char *p14, const unsigned char *in, unsigned char *out);
+void E_old_pw_hash( unsigned char *p14, const unsigned char *in, unsigned char *out);
+void des_crypt128(unsigned char out[8], const unsigned char in[8], const unsigned char key[16]);
+void des_crypt64(unsigned char out[8], const unsigned char in[8], const unsigned char key[8]);
+void des_crypt112(unsigned char out[8], const unsigned char in[8], const unsigned char key[14], int forw);
+void cred_hash3(unsigned char *out, const unsigned char *in, const unsigned char *key, int forw);
+void des_crypt112_16(unsigned char out[16], unsigned char in[16], const unsigned char key[14], int forw);
+void SamOEMhash( unsigned char *data, const unsigned char key[16], size_t len);
+void SamOEMhashBlob( unsigned char *data, size_t len, DATA_BLOB *key);
+void sam_pwd_hash(unsigned int rid, const uchar *in, uchar *out, int forw);
+
+/* The following definitions come from libsmb/smbencrypt.c */
+
+void SMBencrypt_hash(const uchar lm_hash[16], const uchar *c8, uchar p24[24]);
+bool SMBencrypt(const char *passwd, const uchar *c8, uchar p24[24]);
+void E_md4hash(const char *passwd, uchar p16[16]);
+void E_md5hash(const uchar salt[16], const uchar nthash[16], uchar hash_out[16]);
+bool E_deshash(const char *passwd, uchar p16[16]);
+void nt_lm_owf_gen(const char *pwd, uchar nt_p16[16], uchar p16[16]);
+bool ntv2_owf_gen(const uchar owf[16],
+ const char *user_in, const char *domain_in,
+ bool upper_case_domain, /* Transform the domain into UPPER case */
+ uchar kr_buf[16]);
+void SMBOWFencrypt(const uchar passwd[16], const uchar *c8, uchar p24[24]);
+void NTLMSSPOWFencrypt(const uchar passwd[8], const uchar *ntlmchalresp, uchar p24[24]);
+void SMBNTencrypt_hash(const uchar nt_hash[16], uchar *c8, uchar *p24);
+void SMBNTencrypt(const char *passwd, uchar *c8, uchar *p24);
+void SMBOWFencrypt_ntv2(const uchar kr[16],
+ const DATA_BLOB *srv_chal,
+ const DATA_BLOB *cli_chal,
+ uchar resp_buf[16]);
+void SMBsesskeygen_ntv2(const uchar kr[16],
+ const uchar * nt_resp, uint8 sess_key[16]);
+void SMBsesskeygen_ntv1(const uchar kr[16],
+ const uchar * nt_resp, uint8 sess_key[16]);
+void SMBsesskeygen_lm_sess_key(const uchar lm_hash[16],
+ const uchar lm_resp[24], /* only uses 8 */
+ uint8 sess_key[16]);
+DATA_BLOB NTLMv2_generate_names_blob(const char *hostname,
+ const char *domain);
+bool SMBNTLMv2encrypt_hash(const char *user, const char *domain, const uchar nt_hash[16],
+ const DATA_BLOB *server_chal,
+ const DATA_BLOB *names_blob,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *user_session_key) ;
+bool SMBNTLMv2encrypt(const char *user, const char *domain, const char *password,
+ const DATA_BLOB *server_chal,
+ const DATA_BLOB *names_blob,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *user_session_key) ;
+bool encode_pw_buffer(uint8 buffer[516], const char *password, int string_flags);
+bool decode_pw_buffer(TALLOC_CTX *ctx,
+ uint8 in_buffer[516],
+ char **pp_new_pwrd,
+ uint32 *new_pw_len,
+ int string_flags);
+void encode_or_decode_arc4_passwd_buffer(unsigned char pw_buf[532], const DATA_BLOB *psession_key);
+void sess_crypt_blob(DATA_BLOB *out, const DATA_BLOB *in, const DATA_BLOB *session_key, int forward);
+char *decrypt_trustdom_secret(uint8_t nt_hash[16], DATA_BLOB *data_in);
+void encode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx,
+ const char *pwd,
+ DATA_BLOB *session_key,
+ struct wkssvc_PasswordBuffer **pwd_buf);
+WERROR decode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx,
+ struct wkssvc_PasswordBuffer *pwd_buf,
+ DATA_BLOB *session_key,
+ char **pwd);
+DATA_BLOB decrypt_drsuapi_blob(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *session_key,
+ bool rcrypt,
+ uint32_t rid,
+ const DATA_BLOB *buffer);
+
+/* The following definitions come from libsmb/smberr.c */
+
+const char *smb_dos_err_name(uint8 e_class, uint16 num);
+const char *get_dos_error_msg(WERROR result);
+const char *smb_dos_err_class(uint8 e_class);
+char *smb_dos_errstr(char *inbuf);
+WERROR map_werror_from_unix(int error);
+
+/* The following definitions come from libsmb/spnego.c */
+
+ssize_t read_spnego_data(DATA_BLOB data, SPNEGO_DATA *token);
+ssize_t write_spnego_data(DATA_BLOB *blob, SPNEGO_DATA *spnego);
+bool free_spnego_data(SPNEGO_DATA *spnego);
+
+/* The following definitions come from libsmb/trustdom_cache.c */
+
+bool trustdom_cache_enable(void);
+bool trustdom_cache_shutdown(void);
+bool trustdom_cache_store(char* name, char* alt_name, const DOM_SID *sid,
+ time_t timeout);
+bool trustdom_cache_fetch(const char* name, DOM_SID* sid);
+uint32 trustdom_cache_fetch_timestamp( void );
+bool trustdom_cache_store_timestamp( uint32 t, time_t timeout );
+void trustdom_cache_flush(void);
+void update_trustdom_cache( void );
+
+/* The following definitions come from libsmb/trusts_util.c */
+
+NTSTATUS trust_pw_change_and_store_it(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ const char *domain,
+ unsigned char orig_trust_passwd_hash[16],
+ uint32 sec_channel_type);
+NTSTATUS trust_pw_find_change_and_store_it(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *domain) ;
+bool enumerate_domain_trusts( TALLOC_CTX *mem_ctx, const char *domain,
+ char ***domain_names, uint32 *num_domains,
+ DOM_SID **sids );
+
+/* The following definitions come from libsmb/unexpected.c */
+
+void unexpected_packet(struct packet_struct *p);
+void clear_unexpected(time_t t);
+struct packet_struct *receive_unexpected(enum packet_type packet_type, int id,
+ const char *mailslot_name);
+
+/* The following definitions come from locking/brlock.c */
+
+bool brl_same_context(const struct lock_context *ctx1,
+ const struct lock_context *ctx2);
+void brl_init(bool read_only);
+void brl_shutdown(void);
+NTSTATUS brl_lock(struct messaging_context *msg_ctx,
+ struct byte_range_lock *br_lck,
+ uint32 smbpid,
+ struct server_id pid,
+ br_off start,
+ br_off size,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ bool blocking_lock,
+ uint32 *psmbpid);
+bool brl_unlock(struct messaging_context *msg_ctx,
+ struct byte_range_lock *br_lck,
+ uint32 smbpid,
+ struct server_id pid,
+ br_off start,
+ br_off size,
+ enum brl_flavour lock_flav);
+bool brl_locktest(struct byte_range_lock *br_lck,
+ uint32 smbpid,
+ struct server_id pid,
+ br_off start,
+ br_off size,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav);
+NTSTATUS brl_lockquery(struct byte_range_lock *br_lck,
+ uint32 *psmbpid,
+ struct server_id pid,
+ br_off *pstart,
+ br_off *psize,
+ enum brl_type *plock_type,
+ enum brl_flavour lock_flav);
+bool brl_lock_cancel(struct byte_range_lock *br_lck,
+ uint32 smbpid,
+ struct server_id pid,
+ br_off start,
+ br_off size,
+ enum brl_flavour lock_flav);
+void brl_close_fnum(struct messaging_context *msg_ctx,
+ struct byte_range_lock *br_lck);
+int brl_forall(void (*fn)(struct file_id id, struct server_id pid,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ br_off start, br_off size,
+ void *private_data),
+ void *private_data);
+struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx,
+ files_struct *fsp);
+struct byte_range_lock *brl_get_locks_readonly(TALLOC_CTX *mem_ctx,
+ files_struct *fsp);
+void brl_register_msgs(struct messaging_context *msg_ctx);
+
+/* The following definitions come from locking/locking.c */
+
+const char *lock_type_name(enum brl_type lock_type);
+const char *lock_flav_name(enum brl_flavour lock_flav);
+bool is_locked(files_struct *fsp,
+ uint32 smbpid,
+ SMB_BIG_UINT count,
+ SMB_BIG_UINT offset,
+ enum brl_type lock_type);
+NTSTATUS query_lock(files_struct *fsp,
+ uint32 *psmbpid,
+ SMB_BIG_UINT *pcount,
+ SMB_BIG_UINT *poffset,
+ enum brl_type *plock_type,
+ enum brl_flavour lock_flav);
+struct byte_range_lock *do_lock(struct messaging_context *msg_ctx,
+ files_struct *fsp,
+ uint32 lock_pid,
+ SMB_BIG_UINT count,
+ SMB_BIG_UINT offset,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ bool blocking_lock,
+ NTSTATUS *perr,
+ uint32 *plock_pid);
+NTSTATUS do_unlock(struct messaging_context *msg_ctx,
+ files_struct *fsp,
+ uint32 lock_pid,
+ SMB_BIG_UINT count,
+ SMB_BIG_UINT offset,
+ enum brl_flavour lock_flav);
+NTSTATUS do_lock_cancel(files_struct *fsp,
+ uint32 lock_pid,
+ SMB_BIG_UINT count,
+ SMB_BIG_UINT offset,
+ enum brl_flavour lock_flav);
+void locking_close_file(struct messaging_context *msg_ctx,
+ files_struct *fsp);
+bool locking_init(void);
+bool locking_init_readonly(void);
+bool locking_end(void);
+char *share_mode_str(TALLOC_CTX *ctx, int num, const struct share_mode_entry *e);
+struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx,
+ const struct file_id id,
+ const char *servicepath,
+ const char *fname,
+ const struct timespec *old_write_time);
+struct share_mode_lock *fetch_share_mode_unlocked(TALLOC_CTX *mem_ctx,
+ const struct file_id id,
+ const char *servicepath,
+ const char *fname);
+bool rename_share_filename(struct messaging_context *msg_ctx,
+ struct share_mode_lock *lck,
+ const char *servicepath,
+ const char *newname);
+void get_file_infos(struct file_id id,
+ bool *delete_on_close,
+ struct timespec *write_time);
+bool is_valid_share_mode_entry(const struct share_mode_entry *e);
+bool is_deferred_open_entry(const struct share_mode_entry *e);
+bool is_unused_share_mode_entry(const struct share_mode_entry *e);
+void set_share_mode(struct share_mode_lock *lck, files_struct *fsp,
+ uid_t uid, uint16 mid, uint16 op_type, bool initial_delete_on_close_allowed);
+void add_deferred_open(struct share_mode_lock *lck, uint16 mid,
+ struct timeval request_time,
+ struct file_id id);
+bool del_share_mode(struct share_mode_lock *lck, files_struct *fsp);
+void del_deferred_open_entry(struct share_mode_lock *lck, uint16 mid);
+bool remove_share_oplock(struct share_mode_lock *lck, files_struct *fsp);
+bool downgrade_share_oplock(struct share_mode_lock *lck, files_struct *fsp);
+NTSTATUS can_set_delete_on_close(files_struct *fsp, bool delete_on_close,
+ uint32 dosmode);
+bool can_set_initial_delete_on_close(const struct share_mode_lock *lck);
+void set_delete_on_close_token(struct share_mode_lock *lck, UNIX_USER_TOKEN *tok);
+void set_delete_on_close_lck(struct share_mode_lock *lck, bool delete_on_close, UNIX_USER_TOKEN *tok);
+bool set_delete_on_close(files_struct *fsp, bool delete_on_close, UNIX_USER_TOKEN *tok);
+bool set_allow_initial_delete_on_close(struct share_mode_lock *lck, files_struct *fsp, bool delete_on_close);
+bool set_sticky_write_time(struct file_id fileid, struct timespec write_time);
+bool set_write_time(struct file_id fileid, struct timespec write_time);
+int share_mode_forall(void (*fn)(const struct share_mode_entry *, const char *,
+ const char *, void *),
+ void *private_data);
+
+/* The following definitions come from locking/posix.c */
+
+bool is_posix_locked(files_struct *fsp,
+ SMB_BIG_UINT *pu_offset,
+ SMB_BIG_UINT *pu_count,
+ enum brl_type *plock_type,
+ enum brl_flavour lock_flav);
+bool posix_locking_init(bool read_only);
+bool posix_locking_end(void);
+void reduce_windows_lock_ref_count(files_struct *fsp, unsigned int dcount);
+int fd_close_posix(struct files_struct *fsp);
+bool set_posix_lock_windows_flavour(files_struct *fsp,
+ SMB_BIG_UINT u_offset,
+ SMB_BIG_UINT u_count,
+ enum brl_type lock_type,
+ const struct lock_context *lock_ctx,
+ const struct lock_struct *plocks,
+ int num_locks,
+ int *errno_ret);
+bool release_posix_lock_windows_flavour(files_struct *fsp,
+ SMB_BIG_UINT u_offset,
+ SMB_BIG_UINT u_count,
+ enum brl_type deleted_lock_type,
+ const struct lock_context *lock_ctx,
+ const struct lock_struct *plocks,
+ int num_locks);
+bool set_posix_lock_posix_flavour(files_struct *fsp,
+ SMB_BIG_UINT u_offset,
+ SMB_BIG_UINT u_count,
+ enum brl_type lock_type,
+ int *errno_ret);
+bool release_posix_lock_posix_flavour(files_struct *fsp,
+ SMB_BIG_UINT u_offset,
+ SMB_BIG_UINT u_count,
+ const struct lock_context *lock_ctx,
+ const struct lock_struct *plocks,
+ int num_locks);
+
+/* The following definitions come from modules/vfs_default.c */
+
+int vfswrap_lstat(vfs_handle_struct *handle, const char *path, SMB_STRUCT_STAT *sbuf);
+ssize_t vfswrap_llistxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size);
+ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size);
+NTSTATUS vfs_default_init(void);
+
+/* 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);
+bool queue_dns_query(struct packet_struct *p,struct nmb_name *question);
+void kill_async_dns_child(void);
+
+/* The following definitions come from nmbd/nmbd.c */
+
+struct event_context *nmbd_event_context(void);
+struct messaging_context *nmbd_messaging_context(void);
+
+/* 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, const 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( const char *work_name,
+ const char *browser_name,
+ struct in_addr ip );
+struct browse_cache_record *find_browser_in_lmb_cache( const 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);
+void nmbd_message_election(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data);
+
+/* 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, int len);
+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, int len);
+
+/* 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(const 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 */
+
+void register_my_workgroup_one_subnet(struct subnet_record *subrec);
+bool register_my_workgroup_and_names(void);
+void release_wins_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,
+ const 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 );
+bool add_name_to_subnet( struct subnet_record *subrec,
+ const 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 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(time_t t);
+void add_samba_names_to_subnet( struct subnet_record *subrec );
+void dump_name_record( struct name_record *namerec, XFILE *fp);
+void dump_all_namelists(void);
+
+/* The following definitions come from nmbd/nmbd_namequery.c */
+
+bool query_name(struct subnet_record *subrec, const 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,
+ const 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 */
+
+void register_name(struct subnet_record *subrec,
+ const char *name, int type, uint16 nb_flags,
+ register_name_success_function success_fn,
+ register_name_fail_function fail_fn,
+ struct userdata_struct *userdata);
+void wins_refresh_name(struct name_record *namerec);
+
+/* The following definitions come from nmbd/nmbd_namerelease.c */
+
+void 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);
+void queue_wins_refresh(struct nmb_name *nmbname,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ uint16 nb_flags,
+ struct in_addr refresh_ip,
+ const char *tag);
+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 in_addr wins_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 in_addr dest_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 queue_packet(struct packet_struct *packet);
+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, const char *mailslot,char *buf, size_t len,
+ const char *srcname, int src_type,
+ const char *dstname, int dest_type,
+ struct in_addr dest_ip,struct in_addr src_ip,
+ int dest_port);
+
+/* The following definitions come from nmbd/nmbd_processlogon.c */
+
+void process_logon_packet(struct packet_struct *p, char *buf,int len,
+ const 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, const 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, const 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,
+ const char *name,int servertype,
+ int ttl, const 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_entry(XFILE *fp, const char *name, uint32 rec_type,
+ const char *local_master_browser_name, const char *description);
+void write_browse_list(time_t t, bool force_write);
+
+/* The following definitions come from nmbd/nmbd_subnetdb.c */
+
+void close_subnet(struct subnet_record *subrec);
+struct subnet_record *make_normal_subnet(const struct interface *iface);
+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 */
+
+struct name_record *find_name_on_wins_subnet(const struct nmb_name *nmbname, bool self_only);
+bool wins_store_changed_namerec(const struct name_record *namerec);
+bool add_name_to_wins_subnet(const struct name_record *namerec);
+bool remove_name_from_wins_namelist(struct name_record *namerec);
+void dump_wins_subnet_namelist(XFILE *fp);
+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 fetch_all_active_wins_1b_names(void);
+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_name_record(struct name_record *namerec, XFILE *fp);
+void wins_write_database(time_t t, bool background);
+void nmbd_wins_new_entry(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data);
+
+/* The following definitions come from nmbd/nmbd_workgroupdb.c */
+
+struct work_record *find_workgroup_on_subnet(struct subnet_record *subrec,
+ const char *name);
+struct work_record *create_workgroup_on_subnet(struct subnet_record *subrec,
+ const char *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_smb_ports(void);
+char *lp_dos_charset(void);
+char *lp_unix_charset(void);
+char *lp_display_charset(void);
+char *lp_logfile(void);
+char *lp_configfile(void);
+char *lp_smb_passwd_file(void);
+char *lp_private_dir(void);
+char *lp_serverstring(void);
+int lp_printcap_cache_time(void);
+char *lp_addport_cmd(void);
+char *lp_enumports_cmd(void);
+char *lp_addprinter_cmd(void);
+char *lp_deleteprinter_cmd(void);
+char *lp_os2_driver_map(void);
+char *lp_lockdir(void);
+char *lp_piddir(void);
+char *lp_mangling_method(void);
+int lp_mangle_prefix(void);
+char *lp_utmpdir(void);
+char *lp_wtmpdir(void);
+bool lp_utmp(void);
+char *lp_rootdir(void);
+char *lp_defaultservice(void);
+char *lp_msg_command(void);
+char *lp_get_quota_command(void);
+char *lp_set_quota_command(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_realm(void);
+const char *lp_afs_username_map(void);
+int lp_afs_token_lifetime(void);
+char *lp_log_nt_token_command(void);
+char *lp_username_map(void);
+const char *lp_logon_script(void);
+const char *lp_logon_path(void);
+const char *lp_logon_drive(void);
+const char *lp_logon_home(void);
+char *lp_remote_announce(void);
+char *lp_remote_browse_sync(void);
+const char **lp_wins_server_list(void);
+const char **lp_interfaces(void);
+char *lp_socket_address(void);
+char *lp_nis_home_map_name(void);
+const char **lp_netbios_aliases(void);
+const char *lp_passdb_backend(void);
+const char **lp_preload_modules(void);
+char *lp_panic_action(void);
+char *lp_adduser_script(void);
+char *lp_renameuser_script(void);
+char *lp_deluser_script(void);
+const char *lp_guestaccount(void);
+char *lp_addgroup_script(void);
+char *lp_delgroup_script(void);
+char *lp_addusertogroup_script(void);
+char *lp_deluserfromgroup_script(void);
+char *lp_setprimarygroup_script(void);
+char *lp_addmachine_script(void);
+char *lp_shutdown_script(void);
+char *lp_abort_shutdown_script(void);
+char *lp_username_map_script(void);
+char *lp_check_password_script(void);
+char *lp_wins_hook(void);
+const char *lp_template_homedir(void);
+const char *lp_template_shell(void);
+const char *lp_winbind_separator(void);
+int lp_acl_compatibility(void);
+bool lp_winbind_enum_users(void);
+bool lp_winbind_enum_groups(void);
+bool lp_winbind_use_default_domain(void);
+bool lp_winbind_trusted_domains_only(void);
+bool lp_winbind_nested_groups(void);
+int lp_winbind_expand_groups(void);
+bool lp_winbind_refresh_tickets(void);
+bool lp_winbind_offline_logon(void);
+bool lp_winbind_normalize_names(void);
+bool lp_winbind_rpc_only(void);
+const char **lp_idmap_domains(void);
+const char *lp_idmap_backend(void);
+char *lp_idmap_alloc_backend(void);
+int lp_idmap_cache_time(void);
+int lp_idmap_negative_cache_time(void);
+int lp_keepalive(void);
+bool lp_passdb_expand_explicit(void);
+char *lp_ldap_suffix(void);
+char *lp_ldap_admin_dn(void);
+int lp_ldap_ssl(void);
+int lp_ldap_passwd_sync(void);
+bool lp_ldap_delete_dn(void);
+int lp_ldap_replication_sleep(void);
+int lp_ldap_timeout(void);
+int lp_ldap_connection_timeout(void);
+int lp_ldap_page_size(void);
+int lp_ldap_debug_level(void);
+int lp_ldap_debug_threshold(void);
+char *lp_add_share_cmd(void);
+char *lp_change_share_cmd(void);
+char *lp_delete_share_cmd(void);
+char *lp_usershare_path(void);
+const char **lp_usershare_prefix_allow_list(void);
+const char **lp_usershare_prefix_deny_list(void);
+const char **lp_eventlog_list(void);
+bool lp_registry_shares(void);
+bool lp_usershare_allow_guests(void);
+bool lp_usershare_owner_only(void);
+bool lp_disable_netbios(void);
+bool lp_reset_on_zero_vc(void);
+bool lp_ms_add_printer_wizard(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_logons(void);
+const char **lp_init_logon_delayed_hosts(void);
+int lp_init_logon_delay(void);
+bool lp_load_printers(void);
+bool lp_readraw(void);
+bool lp_large_readwrite(void);
+bool lp_writeraw(void);
+bool lp_null_passwords(void);
+bool lp_obey_pam_restrictions(void);
+bool lp_encrypted_passwords(void);
+bool lp_update_encrypted(void);
+int lp_client_schannel(void);
+int lp_server_schannel(void);
+bool lp_syslog_only(void);
+bool lp_timestamp_logs(void);
+bool lp_debug_prefix_timestamp(void);
+bool lp_debug_hires_timestamp(void);
+bool lp_debug_pid(void);
+bool lp_debug_uid(void);
+bool lp_debug_class(void);
+bool lp_enable_core_files(void);
+bool lp_browse_list(void);
+bool lp_nis_home_map(void);
+bool lp_bind_interfaces_only(void);
+bool lp_pam_password_change(void);
+bool lp_unix_password_sync(void);
+bool lp_passwd_chat_debug(void);
+int lp_passwd_chat_timeout(void);
+bool lp_nt_pipe_support(void);
+bool lp_nt_status_support(void);
+bool lp_stat_cache(void);
+int lp_max_stat_cache_size(void);
+bool lp_allow_trusted_domains(void);
+int lp_restrict_anonymous(void);
+bool lp_lanman_auth(void);
+bool lp_ntlm_auth(void);
+bool lp_client_plaintext_auth(void);
+bool lp_client_lanman_auth(void);
+bool lp_client_ntlmv2_auth(void);
+bool lp_host_msdfs(void);
+bool lp_kernel_oplocks(void);
+bool lp_enhanced_browsing(void);
+bool lp_use_mmap(void);
+bool lp_unix_extensions(void);
+bool lp_use_spnego(void);
+bool lp_client_use_spnego(void);
+bool lp_hostname_lookups(void);
+bool lp_change_notify(const struct share_params *p );
+bool lp_kernel_change_notify(const struct share_params *p );
+bool lp_use_kerberos_keytab(void);
+bool lp_defer_sharing_violations(void);
+bool lp_enable_privileges(void);
+bool lp_enable_asu_support(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_max_open_files(void);
+int lp_open_files_db_hash_size(void);
+int lp_maxxmit(void);
+int lp_maxmux(void);
+int lp_passwordlevel(void);
+int lp_usernamelevel(void);
+int lp_deadtime(void);
+bool lp_getwd_cache(void);
+int lp_maxprotocol(void);
+int lp_minprotocol(void);
+int lp_security(void);
+const char **lp_auth_methods(void);
+bool lp_paranoid_server_security(void);
+int lp_maxdisksize(void);
+int lp_lpqcachetime(void);
+int lp_max_smbd_processes(void);
+bool _lp_disable_spoolss(void);
+int lp_syslog(void);
+int lp_lm_announce(void);
+int lp_lm_interval(void);
+int lp_machine_password_timeout(void);
+int lp_map_to_guest(void);
+int lp_oplock_break_wait_time(void);
+int lp_lock_spin_time(void);
+int lp_usershare_max_shares(void);
+const char *lp_socket_options(void);
+int lp_config_backend(void);
+char *lp_preexec(int );
+char *lp_postexec(int );
+char *lp_rootpreexec(int );
+char *lp_rootpostexec(int );
+char *lp_servicename(int );
+const char *lp_const_servicename(int );
+char *lp_pathname(int );
+char *lp_dontdescend(int );
+char *lp_username(int );
+const char **lp_invalid_users(int );
+const char **lp_valid_users(int );
+const char **lp_admin_users(int );
+const char **lp_svcctl_list(void);
+char *lp_cups_options(int );
+char *lp_cups_server(void);
+char *lp_iprint_server(void);
+const char *lp_ctdbd_socket(void);
+const char **lp_cluster_addresses(void);
+bool lp_clustering(void);
+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 );
+const char *lp_printjob_username(int );
+const char **lp_hostsallow(int );
+const 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 );
+const char **lp_readlist(int );
+const char **lp_writelist(int );
+const char **lp_printer_admin(int );
+char *lp_fstype(int );
+const char **lp_vfs_objects(int );
+char *lp_msdfs_proxy(int );
+char *lp_veto_files(int );
+char *lp_hide_files(int );
+char *lp_veto_oplocks(int );
+bool lp_msdfs_root(int );
+char *lp_aio_write_behind(int );
+char *lp_dfree_command(int );
+bool lp_autoloaded(int );
+bool lp_preexec_close(int );
+bool lp_rootpreexec_close(int );
+int lp_casesensitive(int );
+bool lp_preservecase(int );
+bool lp_shortpreservecase(int );
+bool lp_hide_dot_files(int );
+bool lp_hide_special_files(int );
+bool lp_hideunreadable(int );
+bool lp_hideunwriteable_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_administrative_share(int );
+bool lp_print_ok(int );
+bool lp_map_hidden(int );
+bool lp_map_archive(int );
+bool lp_store_dos_attributes(int );
+bool lp_dmapi_support(int );
+bool lp_locking(const struct share_params *p );
+int lp_strict_locking(const struct share_params *p );
+bool lp_posix_locking(const struct share_params *p );
+bool lp_share_modes(int );
+bool lp_oplocks(int );
+bool lp_level2_oplocks(int );
+bool lp_onlyuser(int );
+bool lp_manglednames(const struct share_params *p );
+bool lp_widelinks(int );
+bool lp_symlinks(int );
+bool lp_syncalways(int );
+bool lp_strict_allocate(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_filemode(int );
+bool lp_dos_filetimes(int );
+bool lp_dos_filetime_resolution(int );
+bool lp_fake_dir_create_times(int );
+bool lp_blocking_locks(int );
+bool lp_inherit_perms(int );
+bool lp_inherit_acls(int );
+bool lp_inherit_owner(int );
+bool lp_use_client_driver(int );
+bool lp_default_devmode(int );
+bool lp_force_printername(int );
+bool lp_nt_acl_support(int );
+bool lp_force_unknown_acl_user(int );
+bool lp_ea_support(int );
+bool _lp_use_sendfile(int );
+bool lp_profile_acls(int );
+bool lp_map_acl_inherit(int );
+bool lp_afs_share(int );
+bool lp_acl_check_permissions(int );
+bool lp_acl_group_control(int );
+bool lp_acl_map_full_control(int );
+int lp_create_mask(int );
+int lp_force_create_mode(int );
+int lp_security_mask(int );
+int lp_force_security_mode(int );
+int lp_dir_mask(int );
+int lp_force_dir_mode(int );
+int lp_dir_security_mask(int );
+int lp_force_dir_security_mode(int );
+int lp_max_connections(int );
+int lp_defaultcase(int );
+int lp_minprintspace(int );
+int lp_printing(int );
+int lp_max_reported_jobs(int );
+int lp_oplock_contention_limit(int );
+int lp_csc_policy(int );
+int lp_write_cache_size(int );
+int lp_block_size(int );
+int lp_dfree_cache_time(int );
+int lp_allocation_roundup_size(int );
+int lp_aio_read_size(int );
+int lp_aio_write_size(int );
+int lp_map_readonly(int );
+int lp_directory_name_cache_size(int );
+int lp_smb_encrypt(int );
+char lp_magicchar(const struct share_params *p );
+int lp_winbind_cache_time(void);
+int lp_winbind_reconnect_delay(void);
+const char **lp_winbind_nss_info(void);
+int lp_algorithmic_rid_base(void);
+int lp_name_cache_timeout(void);
+int lp_client_signing(void);
+int lp_server_signing(void);
+int lp_client_ldap_sasl_wrapping(void);
+char *lp_parm_talloc_string(int snum, const char *type, const char *option, const char *def);
+const char *lp_parm_const_string(int snum, const char *type, const char *option, const char *def);
+const char **lp_parm_string_list(int snum, const char *type, const char *option, const char **def);
+int lp_parm_int(int snum, const char *type, const char *option, int def);
+unsigned long lp_parm_ulong(int snum, const char *type, const char *option, unsigned long def);
+bool lp_parm_bool(int snum, const char *type, const char *option, bool def);
+int lp_parm_enum(int snum, const char *type, const char *option,
+ const struct enum_list *_enum, int def);
+bool lp_add_home(const char *pszHomename, int iDefaultService,
+ const char *user, const char *pszHomedir);
+int lp_add_service(const char *pszService, int iDefaultService);
+bool lp_add_printer(const char *pszPrintername, int iDefaultService);
+bool lp_parameter_is_valid(const char *pszParmName);
+bool lp_parameter_is_global(const char *pszParmName);
+bool lp_parameter_is_canonical(const char *parm_name);
+bool lp_canonicalize_parameter(const char *parm_name, const char **canon_parm,
+ bool *inverse);
+bool lp_canonicalize_parameter_with_value(const char *parm_name,
+ const char *val,
+ const char **canon_parm,
+ const char **canon_val);
+void show_parameter_list(void);
+bool lp_string_is_valid_boolean(const char *parm_value);
+bool lp_invert_boolean(const char *str, const char **inverse_str);
+bool lp_canonicalize_boolean(const char *str, const char**canon_str);
+bool service_ok(int iService);
+bool lp_config_backend_is_registry(void);
+bool lp_config_backend_is_file(void);
+bool lp_file_list_changed(void);
+bool lp_idmap_uid(uid_t *low, uid_t *high);
+bool lp_idmap_gid(gid_t *low, gid_t *high);
+const char *lp_ldap_machine_suffix(void);
+const char *lp_ldap_user_suffix(void);
+const char *lp_ldap_group_suffix(void);
+const char *lp_ldap_idmap_suffix(void);
+void *lp_local_ptr(int snum, void *ptr);
+bool lp_do_parameter(int snum, const char *pszParmName, const char *pszParmValue);
+void init_locals(void);
+bool lp_is_default(int snum, struct parm_struct *parm);
+bool dump_a_parameter(int snum, char *parm_name, FILE * f, bool isGlobal);
+struct parm_struct *lp_get_parameter(const char *param_name);
+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));
+void lp_kill_all_services(void);
+void lp_killservice(int iServiceIn);
+const char* server_role_str(uint32 role);
+enum usershare_err parse_usershare_file(TALLOC_CTX *ctx,
+ SMB_STRUCT_STAT *psbuf,
+ const char *servicename,
+ int snum,
+ char **lines,
+ int numlines,
+ char **pp_sharepath,
+ char **pp_comment,
+ SEC_DESC **ppsd,
+ bool *pallow_guest);
+int load_usershare_service(const char *servicename);
+int load_usershare_shares(void);
+void gfree_loadparm(void);
+void lp_set_in_client(bool b);
+bool lp_is_in_client(void);
+bool lp_load_ex(const char *pszFname,
+ bool global_only,
+ bool save_defaults,
+ bool add_ipc,
+ bool initialize_globals,
+ bool allow_include_registry,
+ bool allow_registry_shares);
+bool lp_load(const char *pszFname,
+ bool global_only,
+ bool save_defaults,
+ bool add_ipc,
+ bool initialize_globals);
+bool lp_load_initial_only(const char *pszFname);
+bool lp_load_with_registry_shares(const char *pszFname,
+ bool global_only,
+ bool save_defaults,
+ bool add_ipc,
+ bool initialize_globals);
+int lp_numservices(void);
+void lp_dump(FILE *f, bool show_defaults, int maxtoprint);
+void lp_dump_one(FILE * f, bool show_defaults, int snum);
+int lp_servicenumber(const char *pszServiceName);
+bool share_defined(const char *service_name);
+struct share_params *get_share_params(TALLOC_CTX *mem_ctx,
+ const char *sharename);
+struct share_iterator *share_list_all(TALLOC_CTX *mem_ctx);
+struct share_params *next_share(struct share_iterator *list);
+struct share_params *next_printer(struct share_iterator *list);
+struct share_params *snum2params_static(int snum);
+const char *volume_label(int snum);
+int lp_server_role(void);
+bool lp_domain_master(void);
+bool lp_preferred_master(void);
+void lp_remove_service(int snum);
+void lp_copy_service(int snum, const 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(const char *new_order);
+const char *lp_printername(int snum);
+void lp_set_logfile(const char *name);
+int lp_maxprintjobs(int snum);
+const char *lp_printcapname(void);
+bool lp_disable_spoolss( void );
+void lp_set_spoolss_state( uint32 state );
+uint32 lp_get_spoolss_state( void );
+bool lp_use_sendfile(int snum);
+void set_use_sendfile(int snum, bool val);
+void set_store_dos_attributes(int snum, bool val);
+void lp_set_mangling_method(const char *new_method);
+bool lp_posix_pathnames(void);
+void lp_set_posix_pathnames(void);
+enum brl_flavour lp_posix_cifsu_locktype(files_struct *fsp);
+void lp_set_posix_default_cifsx_readwrite_locktype(enum brl_flavour val);
+int lp_min_receive_file_size(void);
+
+/* The following definitions come from param/params.c */
+
+bool pm_process( const char *FileName,
+ bool (*sfunc)(const char *, void *),
+ bool (*pfunc)(const char *, const char *, void *),
+ void *userdata);
+
+/* The following definitions come from param/util.c */
+
+uint32 get_int_param( const char* param );
+char* get_string_param( const char* param );
+
+/* The following definitions come from passdb/login_cache.c */
+
+bool login_cache_init(void);
+bool login_cache_shutdown(void);
+LOGIN_CACHE * login_cache_read(struct samu *sampass);
+bool login_cache_write(const struct samu *sampass, LOGIN_CACHE entry);
+bool login_cache_delentry(const struct samu *sampass);
+
+/* The following definitions come from passdb/lookup_sid.c */
+
+bool lookup_name(TALLOC_CTX *mem_ctx,
+ const char *full_name, int flags,
+ const char **ret_domain, const char **ret_name,
+ DOM_SID *ret_sid, enum lsa_SidType *ret_type);
+bool lookup_name_smbconf(TALLOC_CTX *mem_ctx,
+ const char *full_name, int flags,
+ const char **ret_domain, const char **ret_name,
+ DOM_SID *ret_sid, enum lsa_SidType *ret_type);
+NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
+ const DOM_SID **sids, int level,
+ struct lsa_dom_info **ret_domains,
+ struct lsa_name_info **ret_names);
+bool lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ const char **ret_domain, const char **ret_name,
+ enum lsa_SidType *ret_type);
+void store_uid_sid_cache(const DOM_SID *psid, uid_t uid);
+void store_gid_sid_cache(const DOM_SID *psid, gid_t gid);
+void uid_to_sid(DOM_SID *psid, uid_t uid);
+void gid_to_sid(DOM_SID *psid, gid_t gid);
+bool sid_to_uid(const DOM_SID *psid, uid_t *puid);
+bool sid_to_gid(const DOM_SID *psid, gid_t *pgid);
+
+/* The following definitions come from passdb/machine_sid.c */
+
+DOM_SID *get_global_sam_sid(void);
+void reset_global_sam_sid(void) ;
+bool sid_check_is_domain(const DOM_SID *sid);
+bool sid_check_is_in_our_domain(const DOM_SID *sid);
+
+/* The following definitions come from passdb/passdb.c */
+
+const char *my_sam_name(void);
+struct samu *samu_new( TALLOC_CTX *ctx );
+NTSTATUS samu_set_unix(struct samu *user, const struct passwd *pwd);
+NTSTATUS samu_alloc_rid_unix(struct samu *user, const struct passwd *pwd);
+char *pdb_encode_acct_ctrl(uint32 acct_ctrl, size_t length);
+uint32 pdb_decode_acct_ctrl(const char *p);
+void pdb_sethexpwd(char p[33], const unsigned char *pwd, uint32 acct_ctrl);
+bool pdb_gethexpwd(const char *p, unsigned char *pwd);
+void pdb_sethexhours(char *p, const unsigned char *hours);
+bool pdb_gethexhours(const char *p, unsigned char *hours);
+int algorithmic_rid_base(void);
+uid_t algorithmic_pdb_user_rid_to_uid(uint32 user_rid);
+uid_t max_algorithmic_uid(void);
+uint32 algorithmic_pdb_uid_to_user_rid(uid_t uid);
+gid_t pdb_group_rid_to_gid(uint32 group_rid);
+gid_t max_algorithmic_gid(void);
+uint32 algorithmic_pdb_gid_to_group_rid(gid_t gid);
+bool algorithmic_pdb_rid_is_user(uint32 rid);
+bool lookup_global_sam_name(const char *name, int flags, uint32_t *rid,
+ enum lsa_SidType *type);
+NTSTATUS local_password_change(const char *user_name,
+ int local_flags,
+ const char *new_passwd,
+ char **pp_err_str,
+ char **pp_msg_str);
+bool init_sam_from_buffer_v3(struct samu *sampass, uint8 *buf, uint32 buflen);
+uint32 init_buffer_from_sam_v3 (uint8 **buf, struct samu *sampass, bool size_only);
+bool pdb_copy_sam_account(struct samu *dst, struct samu *src );
+bool pdb_update_bad_password_count(struct samu *sampass, bool *updated);
+bool pdb_update_autolock_flag(struct samu *sampass, bool *updated);
+bool pdb_increment_bad_password_count(struct samu *sampass);
+bool is_dc_trusted_domain_situation(const char *domain_name);
+bool get_trust_pw_clear(const char *domain, char **ret_pwd,
+ const char **account_name, uint32 *channel);
+bool get_trust_pw_hash(const char *domain, uint8 ret_pwd[16],
+ const char **account_name, uint32 *channel);
+struct samr_LogonHours get_logon_hours_from_pdb(TALLOC_CTX *mem_ctx,
+ struct samu *pw);
+
+/* The following definitions come from passdb/pdb_compat.c */
+
+uint32 pdb_get_user_rid (const struct samu *sampass);
+uint32 pdb_get_group_rid (struct samu *sampass);
+bool pdb_set_user_sid_from_rid (struct samu *sampass, uint32 rid, enum pdb_value_state flag);
+bool pdb_set_group_sid_from_rid (struct samu *sampass, uint32 grid, enum pdb_value_state flag);
+
+/* The following definitions come from passdb/pdb_get_set.c */
+
+uint32 pdb_get_acct_ctrl(const struct samu *sampass);
+time_t pdb_get_logon_time(const struct samu *sampass);
+time_t pdb_get_logoff_time(const struct samu *sampass);
+time_t pdb_get_kickoff_time(const struct samu *sampass);
+time_t pdb_get_bad_password_time(const struct samu *sampass);
+time_t pdb_get_pass_last_set_time(const struct samu *sampass);
+time_t pdb_get_pass_can_change_time(const struct samu *sampass);
+time_t pdb_get_pass_can_change_time_noncalc(const struct samu *sampass);
+time_t pdb_get_pass_must_change_time(const struct samu *sampass);
+bool pdb_get_pass_can_change(const struct samu *sampass);
+uint16 pdb_get_logon_divs(const struct samu *sampass);
+uint32 pdb_get_hours_len(const struct samu *sampass);
+const uint8 *pdb_get_hours(const struct samu *sampass);
+const uint8 *pdb_get_nt_passwd(const struct samu *sampass);
+const uint8 *pdb_get_lanman_passwd(const struct samu *sampass);
+const uint8 *pdb_get_pw_history(const struct samu *sampass, uint32 *current_hist_len);
+const char *pdb_get_plaintext_passwd(const struct samu *sampass);
+const DOM_SID *pdb_get_user_sid(const struct samu *sampass);
+const DOM_SID *pdb_get_group_sid(struct samu *sampass);
+enum pdb_value_state pdb_get_init_flags(const struct samu *sampass, enum pdb_elements element);
+const char *pdb_get_username(const struct samu *sampass);
+const char *pdb_get_domain(const struct samu *sampass);
+const char *pdb_get_nt_username(const struct samu *sampass);
+const char *pdb_get_fullname(const struct samu *sampass);
+const char *pdb_get_homedir(const struct samu *sampass);
+const char *pdb_get_dir_drive(const struct samu *sampass);
+const char *pdb_get_logon_script(const struct samu *sampass);
+const char *pdb_get_profile_path(const struct samu *sampass);
+const char *pdb_get_acct_desc(const struct samu *sampass);
+const char *pdb_get_workstations(const struct samu *sampass);
+const char *pdb_get_comment(const struct samu *sampass);
+const char *pdb_get_munged_dial(const struct samu *sampass);
+uint16 pdb_get_bad_password_count(const struct samu *sampass);
+uint16 pdb_get_logon_count(const struct samu *sampass);
+uint32 pdb_get_unknown_6(const struct samu *sampass);
+void *pdb_get_backend_private_data(const struct samu *sampass, const struct pdb_methods *my_methods);
+bool pdb_set_acct_ctrl(struct samu *sampass, uint32 acct_ctrl, enum pdb_value_state flag);
+bool pdb_set_logon_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag);
+bool pdb_set_logoff_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag);
+bool pdb_set_kickoff_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag);
+bool pdb_set_bad_password_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag);
+bool pdb_set_pass_can_change_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag);
+bool pdb_set_pass_must_change_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag);
+bool pdb_set_pass_last_set_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag);
+bool pdb_set_hours_len(struct samu *sampass, uint32 len, enum pdb_value_state flag);
+bool pdb_set_logon_divs(struct samu *sampass, uint16 hours, enum pdb_value_state flag);
+bool pdb_set_init_flags(struct samu *sampass, enum pdb_elements element, enum pdb_value_state value_flag);
+bool pdb_set_user_sid(struct samu *sampass, const DOM_SID *u_sid, enum pdb_value_state flag);
+bool pdb_set_user_sid_from_string(struct samu *sampass, fstring u_sid, enum pdb_value_state flag);
+bool pdb_set_group_sid(struct samu *sampass, const DOM_SID *g_sid, enum pdb_value_state flag);
+bool pdb_set_username(struct samu *sampass, const char *username, enum pdb_value_state flag);
+bool pdb_set_domain(struct samu *sampass, const char *domain, enum pdb_value_state flag);
+bool pdb_set_nt_username(struct samu *sampass, const char *nt_username, enum pdb_value_state flag);
+bool pdb_set_fullname(struct samu *sampass, const char *full_name, enum pdb_value_state flag);
+bool pdb_set_logon_script(struct samu *sampass, const char *logon_script, enum pdb_value_state flag);
+bool pdb_set_profile_path(struct samu *sampass, const char *profile_path, enum pdb_value_state flag);
+bool pdb_set_dir_drive(struct samu *sampass, const char *dir_drive, enum pdb_value_state flag);
+bool pdb_set_homedir(struct samu *sampass, const char *home_dir, enum pdb_value_state flag);
+bool pdb_set_acct_desc(struct samu *sampass, const char *acct_desc, enum pdb_value_state flag);
+bool pdb_set_workstations(struct samu *sampass, const char *workstations, enum pdb_value_state flag);
+bool pdb_set_comment(struct samu *sampass, const char *comment, enum pdb_value_state flag);
+bool pdb_set_munged_dial(struct samu *sampass, const char *munged_dial, enum pdb_value_state flag);
+bool pdb_set_nt_passwd(struct samu *sampass, const uint8 pwd[NT_HASH_LEN], enum pdb_value_state flag);
+bool pdb_set_lanman_passwd(struct samu *sampass, const uint8 pwd[LM_HASH_LEN], enum pdb_value_state flag);
+bool pdb_set_pw_history(struct samu *sampass, const uint8 *pwd, uint32 historyLen, enum pdb_value_state flag);
+bool pdb_set_plaintext_pw_only(struct samu *sampass, const char *password, enum pdb_value_state flag);
+bool pdb_set_bad_password_count(struct samu *sampass, uint16 bad_password_count, enum pdb_value_state flag);
+bool pdb_set_logon_count(struct samu *sampass, uint16 logon_count, enum pdb_value_state flag);
+bool pdb_set_unknown_6(struct samu *sampass, uint32 unkn, enum pdb_value_state flag);
+bool pdb_set_hours(struct samu *sampass, const uint8 *hours, enum pdb_value_state flag);
+bool pdb_set_backend_private_data(struct samu *sampass, void *private_data,
+ void (*free_fn)(void **),
+ const struct pdb_methods *my_methods,
+ enum pdb_value_state flag);
+bool pdb_set_pass_can_change(struct samu *sampass, bool canchange);
+bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext);
+uint32 pdb_build_fields_present(struct samu *sampass);
+
+/* The following definitions come from passdb/pdb_interface.c */
+
+NTSTATUS smb_register_passdb(int version, const char *name, pdb_init_function init) ;
+struct pdb_init_function_entry *pdb_find_backend_entry(const char *name);
+struct event_context *pdb_get_event_context(void);
+NTSTATUS make_pdb_method_name(struct pdb_methods **methods, const char *selected);
+bool pdb_getsampwnam(struct samu *sam_acct, const char *username) ;
+bool guest_user_info( struct samu *user );
+bool pdb_getsampwsid(struct samu *sam_acct, const DOM_SID *sid) ;
+NTSTATUS pdb_create_user(TALLOC_CTX *mem_ctx, const char *name, uint32 flags,
+ uint32 *rid);
+NTSTATUS pdb_delete_user(TALLOC_CTX *mem_ctx, struct samu *sam_acct);
+NTSTATUS pdb_add_sam_account(struct samu *sam_acct) ;
+NTSTATUS pdb_update_sam_account(struct samu *sam_acct) ;
+NTSTATUS pdb_delete_sam_account(struct samu *sam_acct) ;
+NTSTATUS pdb_rename_sam_account(struct samu *oldname, const char *newname);
+NTSTATUS pdb_update_login_attempts(struct samu *sam_acct, bool success);
+bool pdb_getgrsid(GROUP_MAP *map, DOM_SID sid);
+bool pdb_getgrgid(GROUP_MAP *map, gid_t gid);
+bool pdb_getgrnam(GROUP_MAP *map, const char *name);
+NTSTATUS pdb_create_dom_group(TALLOC_CTX *mem_ctx, const char *name,
+ uint32 *rid);
+NTSTATUS pdb_delete_dom_group(TALLOC_CTX *mem_ctx, uint32 rid);
+NTSTATUS pdb_add_group_mapping_entry(GROUP_MAP *map);
+NTSTATUS pdb_update_group_mapping_entry(GROUP_MAP *map);
+NTSTATUS pdb_delete_group_mapping_entry(DOM_SID sid);
+bool pdb_enum_group_mapping(const DOM_SID *sid, enum lsa_SidType sid_name_use, GROUP_MAP **pp_rmap,
+ size_t *p_num_entries, bool unix_only);
+NTSTATUS pdb_enum_group_members(TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ uint32 **pp_member_rids,
+ size_t *p_num_members);
+NTSTATUS pdb_enum_group_memberships(TALLOC_CTX *mem_ctx, struct samu *user,
+ DOM_SID **pp_sids, gid_t **pp_gids,
+ size_t *p_num_groups);
+NTSTATUS pdb_set_unix_primary_group(TALLOC_CTX *mem_ctx, struct samu *user);
+NTSTATUS pdb_add_groupmem(TALLOC_CTX *mem_ctx, uint32 group_rid,
+ uint32 member_rid);
+NTSTATUS pdb_del_groupmem(TALLOC_CTX *mem_ctx, uint32 group_rid,
+ uint32 member_rid);
+NTSTATUS pdb_create_alias(const char *name, uint32 *rid);
+NTSTATUS pdb_delete_alias(const DOM_SID *sid);
+NTSTATUS pdb_get_aliasinfo(const DOM_SID *sid, struct acct_info *info);
+NTSTATUS pdb_set_aliasinfo(const DOM_SID *sid, struct acct_info *info);
+NTSTATUS pdb_add_aliasmem(const DOM_SID *alias, const DOM_SID *member);
+NTSTATUS pdb_del_aliasmem(const DOM_SID *alias, const DOM_SID *member);
+NTSTATUS pdb_enum_aliasmem(const DOM_SID *alias,
+ DOM_SID **pp_members, size_t *p_num_members);
+NTSTATUS pdb_enum_alias_memberships(TALLOC_CTX *mem_ctx,
+ const DOM_SID *domain_sid,
+ const DOM_SID *members, size_t num_members,
+ uint32 **pp_alias_rids,
+ size_t *p_num_alias_rids);
+NTSTATUS pdb_lookup_rids(const DOM_SID *domain_sid,
+ int num_rids,
+ uint32 *rids,
+ const char **names,
+ enum lsa_SidType *attrs);
+NTSTATUS pdb_lookup_names(const DOM_SID *domain_sid,
+ int num_names,
+ const char **names,
+ uint32 *rids,
+ enum lsa_SidType *attrs);
+bool pdb_get_account_policy(int policy_index, uint32 *value);
+bool pdb_set_account_policy(int policy_index, uint32 value);
+bool pdb_get_seq_num(time_t *seq_num);
+bool pdb_uid_to_rid(uid_t uid, uint32 *rid);
+bool pdb_uid_to_sid(uid_t uid, DOM_SID *sid);
+bool pdb_gid_to_sid(gid_t gid, DOM_SID *sid);
+bool pdb_sid_to_id(const DOM_SID *sid, union unid_t *id,
+ enum lsa_SidType *type);
+bool pdb_rid_algorithm(void);
+bool pdb_new_rid(uint32 *rid);
+bool initialize_password_db(bool reload, struct event_context *event_ctx);
+struct pdb_search *pdb_search_init(enum pdb_search_type type);
+struct pdb_search *pdb_search_users(uint32 acct_flags);
+struct pdb_search *pdb_search_groups(void);
+struct pdb_search *pdb_search_aliases(const DOM_SID *sid);
+uint32 pdb_search_entries(struct pdb_search *search,
+ uint32 start_idx, uint32 max_entries,
+ struct samr_displayentry **result);
+void pdb_search_destroy(struct pdb_search *search);
+bool pdb_get_trusteddom_pw(const char *domain, char** pwd, DOM_SID *sid,
+ time_t *pass_last_set_time);
+bool pdb_set_trusteddom_pw(const char* domain, const char* pwd,
+ const DOM_SID *sid);
+bool pdb_del_trusteddom_pw(const char *domain);
+NTSTATUS pdb_enum_trusteddoms(TALLOC_CTX *mem_ctx, uint32 *num_domains,
+ struct trustdom_info ***domains);
+NTSTATUS make_pdb_method( struct pdb_methods **methods ) ;
+
+/* The following definitions come from passdb/pdb_ldap.c */
+
+const char** get_userattr_list( TALLOC_CTX *mem_ctx, int schema_ver );
+int ldapsam_search_suffix_by_name(struct ldapsam_privates *ldap_state,
+ const char *user,
+ LDAPMessage ** result,
+ const char **attr);
+const char **talloc_attrs(TALLOC_CTX *mem_ctx, ...);
+NTSTATUS pdb_init_ldapsam_compat(struct pdb_methods **pdb_method, const char *location);
+NTSTATUS pdb_init_ldapsam(struct pdb_methods **pdb_method, const char *location);
+NTSTATUS pdb_ldap_init(void);
+
+/* The following definitions come from passdb/pdb_nds.c */
+
+int pdb_nds_get_password(
+ struct smbldap_state *ldap_state,
+ char *object_dn,
+ size_t *pwd_len,
+ char *pwd );
+int pdb_nds_set_password(
+ struct smbldap_state *ldap_state,
+ char *object_dn,
+ const char *pwd );
+NTSTATUS pdb_nds_init(void);
+
+/* The following definitions come from passdb/pdb_smbpasswd.c */
+
+NTSTATUS pdb_smbpasswd_init(void) ;
+
+/* The following definitions come from passdb/pdb_tdb.c */
+
+bool init_sam_from_buffer_v2(struct samu *sampass, uint8 *buf, uint32 buflen);
+NTSTATUS pdb_tdbsam_init(void);
+
+/* The following definitions come from passdb/secrets.c */
+
+bool secrets_init(void);
+struct db_context *secrets_db_ctx(void);
+void secrets_shutdown(void);
+void *secrets_fetch(const char *key, size_t *size);
+bool secrets_store(const char *key, const void *data, size_t size);
+bool secrets_delete(const char *key);
+bool secrets_store_domain_sid(const char *domain, const DOM_SID *sid);
+bool secrets_fetch_domain_sid(const char *domain, DOM_SID *sid);
+bool secrets_store_domain_guid(const char *domain, struct GUID *guid);
+bool secrets_fetch_domain_guid(const char *domain, struct GUID *guid);
+void *secrets_get_trust_account_lock(TALLOC_CTX *mem_ctx, const char *domain);
+uint32 get_default_sec_channel(void);
+bool secrets_fetch_trust_account_password_legacy(const char *domain,
+ uint8 ret_pwd[16],
+ time_t *pass_last_set_time,
+ uint32 *channel);
+bool secrets_fetch_trust_account_password(const char *domain, uint8 ret_pwd[16],
+ time_t *pass_last_set_time,
+ uint32 *channel);
+bool secrets_fetch_trusted_domain_password(const char *domain, char** pwd,
+ DOM_SID *sid, time_t *pass_last_set_time);
+bool secrets_store_trusted_domain_password(const char* domain, const char* pwd,
+ const DOM_SID *sid);
+bool secrets_delete_machine_password(const char *domain);
+bool secrets_delete_machine_password_ex(const char *domain);
+bool secrets_delete_domain_sid(const char *domain);
+bool secrets_store_machine_password(const char *pass, const char *domain, uint32 sec_channel);
+char *secrets_fetch_machine_password(const char *domain,
+ time_t *pass_last_set_time,
+ uint32 *channel);
+bool trusted_domain_password_delete(const char *domain);
+bool secrets_store_ldap_pw(const char* dn, char* pw);
+bool fetch_ldap_pw(char **dn, char** pw);
+NTSTATUS secrets_trusted_domains(TALLOC_CTX *mem_ctx, uint32 *num_domains,
+ struct trustdom_info ***domains);
+bool secrets_store_afs_keyfile(const char *cell, const struct afs_keyfile *keyfile);
+bool secrets_fetch_afs_key(const char *cell, struct afs_key *result);
+void secrets_fetch_ipc_userpass(char **username, char **domain, char **password);
+bool secrets_store_schannel_session_info(TALLOC_CTX *mem_ctx,
+ const char *remote_machine,
+ const struct dcinfo *pdc);
+bool secrets_restore_schannel_session_info(TALLOC_CTX *mem_ctx,
+ const char *remote_machine,
+ struct dcinfo **ppdc);
+bool secrets_store_generic(const char *owner, const char *key, const char *secret);
+char *secrets_fetch_generic(const char *owner, const char *key);
+
+/* The following definitions come from passdb/util_builtin.c */
+
+bool lookup_builtin_rid(TALLOC_CTX *mem_ctx, uint32 rid, const char **name);
+bool lookup_builtin_name(const char *name, uint32 *rid);
+const char *builtin_domain_name(void);
+bool sid_check_is_builtin(const DOM_SID *sid);
+bool sid_check_is_in_builtin(const DOM_SID *sid);
+
+/* The following definitions come from passdb/util_unixsids.c */
+
+bool sid_check_is_unix_users(const DOM_SID *sid);
+bool sid_check_is_in_unix_users(const DOM_SID *sid);
+bool uid_to_unix_users_sid(uid_t uid, DOM_SID *sid);
+bool gid_to_unix_groups_sid(gid_t gid, DOM_SID *sid);
+const char *unix_users_domain_name(void);
+bool lookup_unix_user_name(const char *name, DOM_SID *sid);
+bool sid_check_is_unix_groups(const DOM_SID *sid);
+bool sid_check_is_in_unix_groups(const DOM_SID *sid);
+const char *unix_groups_domain_name(void);
+bool lookup_unix_group_name(const char *name, DOM_SID *sid);
+
+/* The following definitions come from passdb/util_wellknown.c */
+
+bool sid_check_is_wellknown_domain(const DOM_SID *sid, const char **name);
+bool sid_check_is_in_wellknown_domain(const DOM_SID *sid);
+bool lookup_wellknown_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ const char **domain, const char **name);
+bool lookup_wellknown_name(TALLOC_CTX *mem_ctx, const char *name,
+ DOM_SID *sid, const char **domain);
+
+/* The following definitions come from printing/load.c */
+
+void load_printers(void);
+
+/* The following definitions come from printing/lpq_parse.c */
+
+bool parse_lpq_entry(enum printing_types printing_type,char *line,
+ print_queue_struct *buf,
+ print_status_struct *status,bool first);
+
+/* The following definitions come from printing/notify.c */
+
+int print_queue_snum(const char *qname);
+bool print_notify_messages_pending(void);
+void print_notify_send_messages(struct messaging_context *msg_ctx,
+ unsigned int timeout);
+void notify_printer_status_byname(const char *sharename, uint32 status);
+void notify_printer_status(int snum, uint32 status);
+void notify_job_status_byname(const char *sharename, uint32 jobid, uint32 status,
+ uint32 flags);
+void notify_job_status(const char *sharename, uint32 jobid, uint32 status);
+void notify_job_total_bytes(const char *sharename, uint32 jobid,
+ uint32 size);
+void notify_job_total_pages(const char *sharename, uint32 jobid,
+ uint32 pages);
+void notify_job_username(const char *sharename, uint32 jobid, char *name);
+void notify_job_name(const char *sharename, uint32 jobid, char *name);
+void notify_job_submitted(const char *sharename, uint32 jobid,
+ time_t submitted);
+void notify_printer_driver(int snum, char *driver_name);
+void notify_printer_comment(int snum, char *comment);
+void notify_printer_sharename(int snum, char *share_name);
+void notify_printer_printername(int snum, char *printername);
+void notify_printer_port(int snum, char *port_name);
+void notify_printer_location(int snum, char *location);
+void notify_printer_byname( const char *printername, uint32 change, const char *value );
+bool print_notify_pid_list(const char *printername, TALLOC_CTX *mem_ctx, size_t *p_num_pids, pid_t **pp_pid_list);
+
+/* The following definitions come from printing/nt_printing.c */
+
+bool nt_printing_init(struct messaging_context *msg_ctx);
+uint32 update_c_setprinter(bool initialize);
+uint32 get_c_setprinter(void);
+int get_builtin_ntforms(nt_forms_struct **list);
+bool get_a_builtin_ntform(UNISTR2 *uni_formname,nt_forms_struct *form);
+int get_ntforms(nt_forms_struct **list);
+int write_ntforms(nt_forms_struct **list, int number);
+bool add_a_form(nt_forms_struct **list, const FORM *form, int *count);
+bool delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, WERROR *ret);
+void update_a_form(nt_forms_struct **list, const FORM *form, int count);
+int get_ntdrivers(fstring **list, const char *architecture, uint32 version);
+const char *get_short_archi(const char *long_archi);
+WERROR clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
+ uint32 level, struct current_user *user);
+WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level,
+ struct current_user *user, WERROR *perr);
+int pack_devicemode(NT_DEVICEMODE *nt_devmode, uint8 *buf, int buflen);
+uint32 del_a_printer(const char *sharename);
+NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename);
+NT_DEVICEMODE *dup_nt_devicemode(NT_DEVICEMODE *nt_devicemode);
+void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr);
+int unpack_devicemode(NT_DEVICEMODE **nt_devmode, const uint8 *buf, int buflen);
+int add_new_printer_key( NT_PRINTER_DATA *data, const char *name );
+int delete_printer_key( NT_PRINTER_DATA *data, const char *name );
+int lookup_printerkey( NT_PRINTER_DATA *data, const char *name );
+int get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **subkeys );
+WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action);
+WERROR check_published_printers(void);
+bool is_printer_published(Printer_entry *print_hnd, int snum,
+ struct GUID *guid);
+WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action);
+WERROR check_published_printers(void);
+bool is_printer_published(Printer_entry *print_hnd, int snum,
+ struct GUID *guid);
+WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key );
+WERROR delete_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value );
+WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value,
+ uint32 type, uint8 *data, int real_len );
+REGISTRY_VALUE* get_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value );
+WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level);
+bool set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level);
+bool del_driver_init(char *drivername);
+WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, uint8 *data, uint32 data_len);
+WERROR get_a_printer( Printer_entry *print_hnd,
+ NT_PRINTER_INFO_LEVEL **pp_printer,
+ uint32 level,
+ const char *sharename);
+WERROR get_a_printer_search( Printer_entry *print_hnd,
+ NT_PRINTER_INFO_LEVEL **pp_printer,
+ uint32 level,
+ const char *sharename);
+uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level);
+uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level);
+WERROR get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
+ fstring drivername, const char *architecture, uint32 version);
+uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level);
+bool printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 );
+bool printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info );
+WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user,
+ uint32 version, bool delete_files );
+WERROR nt_printing_setsec(const char *sharename, SEC_DESC_BUF *secdesc_ctr);
+bool nt_printing_getsec(TALLOC_CTX *ctx, const char *sharename, SEC_DESC_BUF **secdesc_ctr);
+void map_printer_permissions(SEC_DESC *sd);
+void map_job_permissions(SEC_DESC *sd);
+bool print_access_check(struct auth_serversupplied_info *server_info, int snum,
+ int access_type);
+bool print_time_access_check(const char *servicename);
+char* get_server_name( Printer_entry *printer );
+
+/* The following definitions come from printing/pcap.c */
+
+bool pcap_cache_add(const char *name, const char *comment);
+bool pcap_cache_loaded(void);
+void pcap_cache_reload(void);
+bool pcap_printername_ok(const char *printername);
+void pcap_printer_fn(void (*fn)(char *, char *));
+
+/* The following definitions come from printing/print_aix.c */
+
+bool aix_cache_reload(void);
+
+/* The following definitions come from printing/print_cups.c */
+
+bool cups_cache_reload(void);
+bool cups_pull_comment_location(NT_PRINTER_INFO_LEVEL_2 *printer);
+
+/* The following definitions come from printing/print_generic.c */
+
+
+/* The following definitions come from printing/print_iprint.c */
+
+bool iprint_cache_reload(void);
+
+/* The following definitions come from printing/print_svid.c */
+
+bool sysv_cache_reload(void);
+
+/* The following definitions come from printing/printfsp.c */
+
+NTSTATUS print_fsp_open(connection_struct *conn, const char *fname,
+ uint16_t current_vuid, files_struct **result);
+void print_fsp_end(files_struct *fsp, enum file_close_type close_type);
+
+/* The following definitions come from printing/printing.c */
+
+uint16 pjobid_to_rap(const char* sharename, uint32 jobid);
+bool rap_to_pjobid(uint16 rap_jobid, fstring sharename, uint32 *pjobid);
+bool print_backend_init(struct messaging_context *msg_ctx);
+void printing_end(void);
+int unpack_pjob( uint8 *buf, int buflen, struct printjob *pjob );
+uint32 sysjob_to_jobid(int unix_jobid);
+void pjob_delete(const char* sharename, uint32 jobid);
+void start_background_queue(void);
+bool print_notify_register_pid(int snum);
+bool print_notify_deregister_pid(int snum);
+bool print_job_exists(const char* sharename, uint32 jobid);
+int print_job_fd(const char* sharename, uint32 jobid);
+char *print_job_fname(const char* sharename, uint32 jobid);
+NT_DEVICEMODE *print_job_devmode(const char* sharename, uint32 jobid);
+bool print_job_set_place(const char *sharename, uint32 jobid, int place);
+bool print_job_set_name(const char *sharename, uint32 jobid, char *name);
+bool print_job_delete(struct auth_serversupplied_info *server_info, int snum,
+ uint32 jobid, WERROR *errcode);
+bool print_job_pause(struct auth_serversupplied_info *server_info, int snum,
+ uint32 jobid, WERROR *errcode);
+bool print_job_resume(struct auth_serversupplied_info *server_info, int snum,
+ uint32 jobid, WERROR *errcode);
+ssize_t print_job_write(int snum, uint32 jobid, const char *buf, SMB_OFF_T pos, size_t size);
+int print_queue_length(int snum, print_status_struct *pstatus);
+uint32 print_job_start(struct auth_serversupplied_info *server_info, int snum,
+ char *jobname, NT_DEVICEMODE *nt_devmode );
+void print_job_endpage(int snum, uint32 jobid);
+bool print_job_end(int snum, uint32 jobid, enum file_close_type close_type);
+int print_queue_status(int snum,
+ print_queue_struct **ppqueue,
+ print_status_struct *status);
+bool print_queue_pause(struct auth_serversupplied_info *server_info, int snum,
+ WERROR *errcode);
+bool print_queue_resume(struct auth_serversupplied_info *server_info, int snum,
+ WERROR *errcode);
+bool print_queue_purge(struct auth_serversupplied_info *server_info, int snum,
+ WERROR *errcode);
+
+/* The following definitions come from printing/printing_db.c */
+
+struct tdb_print_db *get_print_db_byname(const char *printername);
+void release_print_db( struct tdb_print_db *pdb);
+void close_all_print_db(void);
+TDB_DATA get_printer_notify_pid_list(TDB_CONTEXT *tdb, const char *printer_name, bool cleanlist);
+
+/* The following definitions come from profile/profile.c */
+
+void set_profile_level(int level, struct server_id src);
+bool profile_setup(struct messaging_context *msg_ctx, bool rdonly);
+
+/* The following definitions come from registry/reg_api.c */
+
+WERROR reg_openhive(TALLOC_CTX *mem_ctx, const char *hive,
+ uint32 desired_access,
+ const struct nt_user_token *token,
+ struct registry_key **pkey);
+WERROR reg_openkey(TALLOC_CTX *mem_ctx, struct registry_key *parent,
+ const char *name, uint32 desired_access,
+ struct registry_key **pkey);
+WERROR reg_enumkey(TALLOC_CTX *mem_ctx, struct registry_key *key,
+ uint32 idx, char **name, NTTIME *last_write_time);
+WERROR reg_enumvalue(TALLOC_CTX *mem_ctx, struct registry_key *key,
+ uint32 idx, char **pname, struct registry_value **pval);
+WERROR reg_queryvalue(TALLOC_CTX *mem_ctx, struct registry_key *key,
+ const char *name, struct registry_value **pval);
+WERROR reg_queryinfokey(struct registry_key *key, uint32_t *num_subkeys,
+ uint32_t *max_subkeylen, uint32_t *max_subkeysize,
+ uint32_t *num_values, uint32_t *max_valnamelen,
+ uint32_t *max_valbufsize, uint32_t *secdescsize,
+ NTTIME *last_changed_time);
+WERROR reg_createkey(TALLOC_CTX *ctx, struct registry_key *parent,
+ const char *subkeypath, uint32 desired_access,
+ struct registry_key **pkey,
+ enum winreg_CreateAction *paction);
+WERROR reg_deletekey(struct registry_key *parent, const char *path);
+WERROR reg_setvalue(struct registry_key *key, const char *name,
+ const struct registry_value *val);
+WERROR reg_deletevalue(struct registry_key *key, const char *name);
+WERROR reg_getkeysecurity(TALLOC_CTX *mem_ctx, struct registry_key *key,
+ struct security_descriptor **psecdesc);
+WERROR reg_setkeysecurity(struct registry_key *key,
+ struct security_descriptor *psecdesc);
+WERROR reg_getversion(uint32_t *version);
+WERROR reg_restorekey(struct registry_key *key, const char *fname);
+WERROR reg_savekey(struct registry_key *key, const char *fname);
+WERROR reg_deleteallvalues(struct registry_key *key);
+WERROR reg_open_path(TALLOC_CTX *mem_ctx, const char *orig_path,
+ uint32 desired_access, const struct nt_user_token *token,
+ struct registry_key **pkey);
+WERROR reg_deletekey_recursive(TALLOC_CTX *ctx,
+ struct registry_key *parent,
+ const char *path);
+WERROR reg_deletesubkeys_recursive(TALLOC_CTX *ctx,
+ struct registry_key *parent,
+ const char *path);
+WERROR reg_create_path(TALLOC_CTX *mem_ctx, const char *orig_path,
+ uint32 desired_access,
+ const struct nt_user_token *token,
+ enum winreg_CreateAction *paction,
+ struct registry_key **pkey);
+WERROR reg_delete_path(const struct nt_user_token *token,
+ const char *orig_path);
+
+/* The following definitions come from registry/reg_backend_current_version.c */
+
+
+/* The following definitions come from registry/reg_backend_db.c */
+
+WERROR init_registry_key(const char *add_path);
+WERROR init_registry_data(void);
+WERROR regdb_init(void);
+WERROR regdb_open( void );
+int regdb_close( void );
+int regdb_get_seqnum(void);
+bool regdb_store_keys(const char *key, REGSUBKEY_CTR *ctr);
+int regdb_fetch_keys(const char *key, REGSUBKEY_CTR *ctr);
+int regdb_fetch_values( const char* key, REGVAL_CTR *values );
+bool regdb_store_values( const char *key, REGVAL_CTR *values );
+bool regdb_subkeys_need_update(REGSUBKEY_CTR *subkeys);
+bool regdb_values_need_update(REGVAL_CTR *values);
+
+/* The following definitions come from registry/reg_backend_hkpt_params.c */
+
+
+/* The following definitions come from registry/reg_backend_netlogon_params.c */
+
+
+/* The following definitions come from registry/reg_backend_perflib.c */
+
+
+/* The following definitions come from registry/reg_backend_printing.c */
+
+
+/* The following definitions come from registry/reg_backend_prod_options.c */
+
+
+/* The following definitions come from registry/reg_backend_shares.c */
+
+
+/* The following definitions come from registry/reg_backend_smbconf.c */
+
+
+/* The following definitions come from registry/reg_backend_tcpip_params.c */
+
+
+/* The following definitions come from registry/reg_cachehook.c */
+
+WERROR reghook_cache_init(void);
+WERROR reghook_cache_add(const char *keyname, REGISTRY_OPS *ops);
+REGISTRY_OPS *reghook_cache_find(const char *keyname);
+void reghook_dump_cache( int debuglevel );
+
+/* The following definitions come from registry/reg_dispatcher.c */
+
+bool store_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkeys );
+bool store_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val );
+int fetch_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkey_ctr );
+int fetch_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val );
+bool regkey_access_check( REGISTRY_KEY *key, uint32 requested, uint32 *granted,
+ const struct nt_user_token *token );
+WERROR regkey_get_secdesc(TALLOC_CTX *mem_ctx, REGISTRY_KEY *key,
+ struct security_descriptor **psecdesc);
+WERROR regkey_set_secdesc(REGISTRY_KEY *key,
+ struct security_descriptor *psecdesc);
+bool reg_subkeys_need_update(REGISTRY_KEY *key, REGSUBKEY_CTR *subkeys);
+bool reg_values_need_update(REGISTRY_KEY *key, REGVAL_CTR *values);
+
+/* The following definitions come from registry/reg_eventlog.c */
+
+bool eventlog_init_keys(void);
+bool eventlog_add_source( const char *eventlog, const char *sourcename,
+ const char *messagefile );
+
+/* The following definitions come from registry/reg_init_basic.c */
+
+WERROR registry_init_common(void);
+WERROR registry_init_basic(void);
+
+/* The following definitions come from registry/reg_init_full.c */
+
+WERROR registry_init_full(void);
+
+/* The following definitions come from registry/reg_init_smbconf.c */
+
+NTSTATUS registry_create_admin_token(TALLOC_CTX *mem_ctx,
+ NT_USER_TOKEN **ptoken);
+WERROR registry_init_smbconf(const char *keyname);
+
+/* The following definitions come from registry/reg_objects.c */
+
+WERROR regsubkey_ctr_addkey( REGSUBKEY_CTR *ctr, const char *keyname );
+int regsubkey_ctr_delkey( REGSUBKEY_CTR *ctr, const char *keyname );
+bool regsubkey_ctr_key_exists( REGSUBKEY_CTR *ctr, const char *keyname );
+int regsubkey_ctr_numkeys( REGSUBKEY_CTR *ctr );
+char* regsubkey_ctr_specific_key( REGSUBKEY_CTR *ctr, uint32 key_index );
+int regval_ctr_numvals( REGVAL_CTR *ctr );
+REGISTRY_VALUE* dup_registry_value( REGISTRY_VALUE *val );
+void free_registry_value( REGISTRY_VALUE *val );
+uint8* regval_data_p( REGISTRY_VALUE *val );
+uint32 regval_size( REGISTRY_VALUE *val );
+char* regval_name( REGISTRY_VALUE *val );
+uint32 regval_type( REGISTRY_VALUE *val );
+REGISTRY_VALUE* regval_ctr_specific_value( REGVAL_CTR *ctr, uint32 idx );
+bool regval_ctr_key_exists( REGVAL_CTR *ctr, const char *value );
+REGISTRY_VALUE *regval_compose(TALLOC_CTX *ctx, const char *name, uint16 type,
+ const char *data_p, size_t size);
+int regval_ctr_addvalue( REGVAL_CTR *ctr, const char *name, uint16 type,
+ const char *data_p, size_t size );
+int regval_ctr_copyvalue( REGVAL_CTR *ctr, REGISTRY_VALUE *val );
+int regval_ctr_delvalue( REGVAL_CTR *ctr, const char *name );
+REGISTRY_VALUE* regval_ctr_getvalue( REGVAL_CTR *ctr, const char *name );
+uint32 regval_dword( REGISTRY_VALUE *val );
+char *regval_sz(REGISTRY_VALUE *val);
+
+/* The following definitions come from registry/reg_perfcount.c */
+
+void perfcount_init_keys( void );
+uint32 reg_perfcount_get_base_index(void);
+uint32 reg_perfcount_get_last_counter(uint32 base_index);
+uint32 reg_perfcount_get_last_help(uint32 last_counter);
+uint32 reg_perfcount_get_counter_help(uint32 base_index, char **retbuf);
+uint32 reg_perfcount_get_counter_names(uint32 base_index, char **retbuf);
+bool _reg_perfcount_get_counter_data(TDB_DATA key, TDB_DATA *data);
+bool _reg_perfcount_get_instance_info(PERF_INSTANCE_DEFINITION *inst,
+ prs_struct *ps,
+ int instId,
+ PERF_OBJECT_TYPE *obj,
+ TDB_CONTEXT *names);
+bool _reg_perfcount_add_instance(PERF_OBJECT_TYPE *obj,
+ prs_struct *ps,
+ int instInd,
+ TDB_CONTEXT *names);
+uint32 reg_perfcount_get_perf_data_block(uint32 base_index,
+ prs_struct *ps,
+ PERF_DATA_BLOCK *block,
+ const char *object_ids);
+WERROR reg_perfcount_get_hkpd(prs_struct *ps, uint32 max_buf_size, uint32 *outbuf_len, const char *object_ids);
+
+/* The following definitions come from registry/reg_util.c */
+
+bool reg_split_path(char *path, char **base, char **new_path);
+bool reg_split_key(char *path, char **base, char **key);
+char *normalize_reg_path(TALLOC_CTX *ctx, const char *keyname );
+void normalize_dbkey(char *key);
+char *reg_remaining_path(TALLOC_CTX *ctx, const char *key);
+int regval_convert_multi_sz( uint16 *multi_string, size_t byte_len, char ***values );
+size_t regval_build_multi_sz( char **values, uint16 **buffer );
+
+/* The following definitions come from registry/reg_util_legacy.c */
+
+WERROR regkey_open_internal( TALLOC_CTX *ctx, REGISTRY_KEY **regkey,
+ const char *path,
+ const struct nt_user_token *token,
+ uint32 access_desired );
+
+/* The following definitions come from registry/regfio.c */
+
+
+/* The following definitions come from rpc_client/cli_lsarpc.c */
+
+NTSTATUS rpccli_lsa_open_policy(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ bool sec_qos, uint32 des_access,
+ POLICY_HND *pol);
+NTSTATUS rpccli_lsa_open_policy2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, bool sec_qos,
+ uint32 des_access, POLICY_HND *pol);
+NTSTATUS rpccli_lsa_lookup_sids(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol,
+ int num_sids,
+ const DOM_SID *sids,
+ char ***pdomains,
+ char ***pnames,
+ enum lsa_SidType **ptypes);
+NTSTATUS rpccli_lsa_lookup_names(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, int num_names,
+ const char **names,
+ const char ***dom_names,
+ int level,
+ DOM_SID **sids,
+ enum lsa_SidType **types);
+bool fetch_domain_sid( char *domain, char *remote_machine, DOM_SID *psid);
+
+/* The following definitions come from rpc_client/cli_netlogon.c */
+
+NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
+ const char *server_name,
+ const char *domain,
+ const char *clnt_name,
+ const char *machine_account,
+ const unsigned char machine_pwd[16],
+ enum netr_SchannelType sec_chan_type,
+ uint32_t *neg_flags_inout);
+NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 logon_parameters,
+ const char *domain,
+ const char *username,
+ const char *password,
+ const char *workstation,
+ int logon_type);
+NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 logon_parameters,
+ const char *server,
+ const char *username,
+ const char *domain,
+ const char *workstation,
+ const uint8 chal[8],
+ DATA_BLOB lm_response,
+ DATA_BLOB nt_response,
+ struct netr_SamInfo3 **info3);
+NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 logon_parameters,
+ const char *server,
+ const char *username,
+ const char *domain,
+ const char *workstation,
+ const uint8 chal[8],
+ DATA_BLOB lm_response,
+ DATA_BLOB nt_response,
+ struct netr_SamInfo3 **info3);
+
+/* The following definitions come from rpc_client/cli_pipe.c */
+
+NTSTATUS rpc_api_pipe_req(struct rpc_pipe_client *cli,
+ uint8 op_num,
+ prs_struct *in_data,
+ prs_struct *out_data);
+NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
+ struct cli_pipe_auth_data *auth);
+unsigned int rpccli_set_timeout(struct rpc_pipe_client *cli,
+ unsigned int timeout);
+bool rpccli_get_pwd_hash(struct rpc_pipe_client *cli, uint8_t nt_hash[16]);
+struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p);
+NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx,
+ struct cli_pipe_auth_data **presult);
+NTSTATUS rpccli_ntlmssp_bind_data(TALLOC_CTX *mem_ctx,
+ enum pipe_auth_type auth_type,
+ enum pipe_auth_level auth_level,
+ const char *domain,
+ const char *username,
+ const char *password,
+ struct cli_pipe_auth_data **presult);
+NTSTATUS rpccli_schannel_bind_data(TALLOC_CTX *mem_ctx, const char *domain,
+ enum pipe_auth_level auth_level,
+ const uint8_t sess_key[16],
+ struct cli_pipe_auth_data **presult);
+NTSTATUS rpccli_kerberos_bind_data(TALLOC_CTX *mem_ctx,
+ enum pipe_auth_level auth_level,
+ const char *service_princ,
+ const char *username,
+ const char *password,
+ struct cli_pipe_auth_data **presult);
+NTSTATUS rpc_pipe_open_tcp(TALLOC_CTX *mem_ctx, const char *host,
+ const struct ndr_syntax_id *abstract_syntax,
+ struct rpc_pipe_client **presult);
+NTSTATUS rpc_pipe_open_ncalrpc(TALLOC_CTX *mem_ctx, const char *socket_path,
+ const struct ndr_syntax_id *abstract_syntax,
+ struct rpc_pipe_client **presult);
+NTSTATUS cli_rpc_pipe_open_noauth(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ struct rpc_pipe_client **presult);
+NTSTATUS cli_rpc_pipe_open_ntlmssp(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ enum pipe_auth_level auth_level,
+ const char *domain,
+ const char *username,
+ const char *password,
+ struct rpc_pipe_client **presult);
+NTSTATUS cli_rpc_pipe_open_spnego_ntlmssp(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ enum pipe_auth_level auth_level,
+ const char *domain,
+ const char *username,
+ const char *password,
+ struct rpc_pipe_client **presult);
+NTSTATUS get_schannel_session_key(struct cli_state *cli,
+ const char *domain,
+ uint32 *pneg_flags,
+ struct rpc_pipe_client **presult);
+NTSTATUS cli_rpc_pipe_open_schannel_with_key(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ enum pipe_auth_level auth_level,
+ const char *domain,
+ const struct dcinfo *pdc,
+ struct rpc_pipe_client **presult);
+NTSTATUS cli_rpc_pipe_open_ntlmssp_auth_schannel(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ enum pipe_auth_level auth_level,
+ const char *domain,
+ const char *username,
+ const char *password,
+ struct rpc_pipe_client **presult);
+NTSTATUS cli_rpc_pipe_open_schannel(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ enum pipe_auth_level auth_level,
+ const char *domain,
+ struct rpc_pipe_client **presult);
+NTSTATUS cli_rpc_pipe_open_krb5(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ enum pipe_auth_level auth_level,
+ const char *service_princ,
+ const char *username,
+ const char *password,
+ struct rpc_pipe_client **presult);
+NTSTATUS cli_get_session_key(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *cli,
+ DATA_BLOB *session_key);
+
+
+/* The following definitions come from rpc_client/cli_reg.c */
+
+NTSTATUS rpccli_winreg_Connect(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ uint32 reg_type, uint32 access_mask,
+ POLICY_HND *reg_hnd);
+uint32 reg_init_regval_buffer( REGVAL_BUFFER *buf2, REGISTRY_VALUE *val );
+
+/* The following definitions come from rpc_client/cli_samr.c */
+
+NTSTATUS rpccli_samr_chgpasswd_user(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle,
+ const char *newpassword,
+ const char *oldpassword);
+NTSTATUS rpccli_samr_chgpasswd_user2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *username,
+ const char *newpassword,
+ const char *oldpassword);
+NTSTATUS rpccli_samr_chng_pswd_auth_crap(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *username,
+ DATA_BLOB new_nt_password_blob,
+ DATA_BLOB old_nt_hash_enc_blob,
+ DATA_BLOB new_lm_password_blob,
+ DATA_BLOB old_lm_hash_enc_blob);
+NTSTATUS rpccli_samr_chgpasswd_user3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *username,
+ const char *newpassword,
+ const char *oldpassword,
+ struct samr_DomInfo1 **dominfo1,
+ struct samr_ChangeReject **reject);
+void get_query_dispinfo_params(int loop_count, uint32 *max_entries,
+ uint32 *max_size);
+NTSTATUS rpccli_try_samr_connects(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t access_mask,
+ POLICY_HND *connect_pol);
+
+/* The following definitions come from rpc_client/cli_spoolss.c */
+
+WERROR rpccli_spoolss_open_printer_ex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ const char *printername, const char *datatype, uint32 access_required,
+ const char *station, const char *username, POLICY_HND *pol);
+WERROR rpccli_spoolss_close_printer(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol);
+WERROR rpccli_spoolss_enum_printers(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ char *name, uint32 flags, uint32 level,
+ uint32 *num_printers, PRINTER_INFO_CTR *ctr);
+WERROR rpccli_spoolss_enum_ports(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ uint32 level, uint32 *num_ports, PORT_INFO_CTR *ctr);
+WERROR rpccli_spoolss_getprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 level,
+ PRINTER_INFO_CTR *ctr);
+WERROR rpccli_spoolss_setprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 level,
+ PRINTER_INFO_CTR *ctr, uint32 command);
+WERROR rpccli_spoolss_getprinterdriver(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 level,
+ const char *env, int version, PRINTER_DRIVER_CTR *ctr);
+WERROR rpccli_spoolss_enumprinterdrivers (struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 level, const char *env,
+ uint32 *num_drivers,
+ PRINTER_DRIVER_CTR *ctr);
+WERROR rpccli_spoolss_getprinterdriverdir (struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 level, char *env,
+ DRIVER_DIRECTORY_CTR *ctr);
+WERROR rpccli_spoolss_addprinterdriver (struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, uint32 level,
+ PRINTER_DRIVER_CTR *ctr);
+WERROR rpccli_spoolss_addprinterex (struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ uint32 level, PRINTER_INFO_CTR*ctr);
+WERROR rpccli_spoolss_deleteprinterdriverex(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, const char *arch,
+ const char *driver, int version);
+WERROR rpccli_spoolss_deleteprinterdriver (struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, const char *arch,
+ const char *driver);
+WERROR rpccli_spoolss_getprintprocessordirectory(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ char *name, char *environment,
+ fstring procdir);
+WERROR rpccli_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *handle, uint32 level, FORM *form);
+WERROR rpccli_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *handle, uint32 level,
+ const char *form_name, FORM *form);
+WERROR rpccli_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *handle, const char *formname,
+ uint32 level, FORM_1 *form);
+WERROR rpccli_spoolss_deleteform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *handle, const char *form_name);
+WERROR rpccli_spoolss_enumforms(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *handle, int level, uint32 *num_forms,
+ FORM_1 **forms);
+WERROR rpccli_spoolss_enumjobs(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, uint32 level, uint32 firstjob,
+ uint32 num_jobs, uint32 *returned, JOB_INFO_CTR *ctr);
+WERROR rpccli_spoolss_setjob(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, uint32 jobid, uint32 level,
+ uint32 command);
+WERROR rpccli_spoolss_getjob(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, uint32 jobid, uint32 level,
+ JOB_INFO_CTR *ctr);
+WERROR rpccli_spoolss_startpageprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd);
+WERROR rpccli_spoolss_endpageprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd);
+WERROR rpccli_spoolss_startdocprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, char *docname,
+ char *outputfile, char *datatype,
+ uint32 *jobid);
+WERROR rpccli_spoolss_enddocprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd);
+WERROR rpccli_spoolss_getprinterdata(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, const char *valuename,
+ REGISTRY_VALUE *value);
+WERROR rpccli_spoolss_getprinterdataex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, const char *keyname,
+ const char *valuename,
+ REGISTRY_VALUE *value);
+WERROR rpccli_spoolss_setprinterdata(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, REGISTRY_VALUE *value);
+WERROR rpccli_spoolss_setprinterdataex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, char *keyname,
+ REGISTRY_VALUE *value);
+WERROR rpccli_spoolss_enumprinterdata(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, uint32 ndx,
+ uint32 value_offered, uint32 data_offered,
+ uint32 *value_needed, uint32 *data_needed,
+ REGISTRY_VALUE *value);
+WERROR rpccli_spoolss_enumprinterdataex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, const char *keyname,
+ REGVAL_CTR *ctr);
+WERROR rpccli_spoolss_writeprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, uint32 data_size, char *data,
+ uint32 *num_written);
+WERROR rpccli_spoolss_deleteprinterdata(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, char *valuename);
+WERROR rpccli_spoolss_deleteprinterdataex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, char *keyname,
+ char *valuename);
+WERROR rpccli_spoolss_enumprinterkey(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, const char *keyname,
+ uint16 **keylist, uint32 *len);
+WERROR rpccli_spoolss_deleteprinterkey(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, char *keyname);
+
+/* The following definitions come from rpc_client/cli_spoolss_notify.c */
+
+WERROR rpccli_spoolss_reply_open_printer(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ const char *printer, uint32 printerlocal, uint32 type,
+ POLICY_HND *handle);
+WERROR rpccli_spoolss_reply_close_printer(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *handle);
+WERROR rpccli_spoolss_routerreplyprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 condition, uint32 change_id);
+WERROR rpccli_spoolss_rrpcn(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 notify_data_len,
+ SPOOL_NOTIFY_INFO_DATA *notify_data,
+ uint32 change_low, uint32 change_high);
+WERROR rpccli_spoolss_rffpcnex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 flags, uint32 options,
+ const char *localmachine, uint32 printerlocal,
+ SPOOL_NOTIFY_OPTION *option);
+
+/* The following definitions come from rpc_client/cli_svcctl.c */
+
+WERROR rpccli_svcctl_enumerate_services( struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hSCM, uint32 type, uint32 state,
+ uint32 *returned, ENUM_SERVICES_STATUS **service_array );
+WERROR rpccli_svcctl_query_config(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hService, SERVICE_CONFIG *config );
+
+/* The following definitions come from rpc_client/init_lsa.c */
+
+void init_lsa_String(struct lsa_String *name, const char *s);
+void init_lsa_StringLarge(struct lsa_StringLarge *name, const char *s);
+void init_lsa_AsciiString(struct lsa_AsciiString *name, const char *s);
+void init_lsa_AsciiStringLarge(struct lsa_AsciiStringLarge *name, const char *s);
+void init_lsa_sec_qos(struct lsa_QosInfo *r,
+ uint32_t len,
+ uint16_t impersonation_level,
+ uint8_t context_mode,
+ uint8_t effective_only);
+void init_lsa_obj_attr(struct lsa_ObjectAttribute *r,
+ uint32_t len,
+ uint8_t *root_dir,
+ const char *object_name,
+ uint32_t attributes,
+ struct security_descriptor *sec_desc,
+ struct lsa_QosInfo *sec_qos);
+void init_lsa_translated_sid(struct lsa_TranslatedSid *r,
+ enum lsa_SidType sid_type,
+ uint32_t rid,
+ uint32_t sid_index);
+void init_lsa_translated_name2(struct lsa_TranslatedName2 *r,
+ enum lsa_SidType sid_type,
+ const char *name,
+ uint32_t sid_index,
+ uint32_t unknown);
+
+/* The following definitions come from rpc_client/init_netlogon.c */
+
+void init_netr_SamBaseInfo(struct netr_SamBaseInfo *r,
+ NTTIME last_logon,
+ NTTIME last_logoff,
+ NTTIME acct_expiry,
+ NTTIME last_password_change,
+ NTTIME allow_password_change,
+ NTTIME force_password_change,
+ const char *account_name,
+ const char *full_name,
+ const char *logon_script,
+ const char *profile_path,
+ const char *home_directory,
+ const char *home_drive,
+ uint16_t logon_count,
+ uint16_t bad_password_count,
+ uint32_t rid,
+ uint32_t primary_gid,
+ struct samr_RidWithAttributeArray groups,
+ uint32_t user_flags,
+ struct netr_UserSessionKey key,
+ const char *logon_server,
+ const char *domain,
+ struct dom_sid2 *domain_sid,
+ struct netr_LMSessionKey LMSessKey,
+ uint32_t acct_flags);
+void init_netr_SamInfo3(struct netr_SamInfo3 *r,
+ NTTIME last_logon,
+ NTTIME last_logoff,
+ NTTIME acct_expiry,
+ NTTIME last_password_change,
+ NTTIME allow_password_change,
+ NTTIME force_password_change,
+ const char *account_name,
+ const char *full_name,
+ const char *logon_script,
+ const char *profile_path,
+ const char *home_directory,
+ const char *home_drive,
+ uint16_t logon_count,
+ uint16_t bad_password_count,
+ uint32_t rid,
+ uint32_t primary_gid,
+ struct samr_RidWithAttributeArray groups,
+ uint32_t user_flags,
+ struct netr_UserSessionKey key,
+ const char *logon_server,
+ const char *domain,
+ struct dom_sid2 *domain_sid,
+ struct netr_LMSessionKey LMSessKey,
+ uint32_t acct_flags,
+ uint32_t sidcount,
+ struct netr_SidAttr *sids);
+NTSTATUS serverinfo_to_SamInfo3(struct auth_serversupplied_info *server_info,
+ uint8_t pipe_session_key[16],
+ struct netr_SamInfo3 *sam3);
+void init_netr_IdentityInfo(struct netr_IdentityInfo *r,
+ const char *domain_name,
+ uint32_t parameter_control,
+ uint32_t logon_id_low,
+ uint32_t logon_id_high,
+ const char *account_name,
+ const char *workstation);
+void init_netr_NetworkInfo(struct netr_NetworkInfo *r,
+ const char *domain_name,
+ uint32_t parameter_control,
+ uint32_t logon_id_low,
+ uint32_t logon_id_high,
+ const char *account_name,
+ const char *workstation,
+ uint8_t challenge[8],
+ struct netr_ChallengeResponse nt,
+ struct netr_ChallengeResponse lm);
+void init_netr_PasswordInfo(struct netr_PasswordInfo *r,
+ const char *domain_name,
+ uint32_t parameter_control,
+ uint32_t logon_id_low,
+ uint32_t logon_id_high,
+ const char *account_name,
+ const char *workstation,
+ struct samr_Password lmpassword,
+ struct samr_Password ntpassword);
+
+/* The following definitions come from rpc_client/init_samr.c */
+
+void init_samr_DomInfo1(struct samr_DomInfo1 *r,
+ uint16_t min_password_length,
+ uint16_t password_history_length,
+ uint32_t password_properties,
+ int64_t max_password_age,
+ int64_t min_password_age);
+void init_samr_DomInfo2(struct samr_DomInfo2 *r,
+ NTTIME force_logoff_time,
+ const char *comment,
+ const char *domain_name,
+ const char *primary,
+ uint64_t sequence_num,
+ uint32_t unknown2,
+ enum samr_Role role,
+ uint32_t unknown3,
+ uint32_t num_users,
+ uint32_t num_groups,
+ uint32_t num_aliases);
+void init_samr_DomInfo3(struct samr_DomInfo3 *r,
+ NTTIME force_logoff_time);
+void init_samr_DomInfo4(struct samr_DomInfo4 *r,
+ const char *comment);
+void init_samr_DomInfo5(struct samr_DomInfo5 *r,
+ const char *domain_name);
+void init_samr_DomInfo6(struct samr_DomInfo6 *r,
+ const char *primary);
+void init_samr_DomInfo7(struct samr_DomInfo7 *r,
+ enum samr_Role role);
+void init_samr_DomInfo8(struct samr_DomInfo8 *r,
+ uint64_t sequence_num,
+ NTTIME domain_create_time);
+void init_samr_DomInfo9(struct samr_DomInfo9 *r,
+ uint32_t unknown);
+void init_samr_DomInfo12(struct samr_DomInfo12 *r,
+ uint64_t lockout_duration,
+ uint64_t lockout_window,
+ uint16_t lockout_threshold);
+void init_samr_group_info1(struct samr_GroupInfoAll *r,
+ const char *name,
+ uint32_t attributes,
+ uint32_t num_members,
+ const char *description);
+void init_samr_group_info2(struct lsa_String *r, const char *group_name);
+void init_samr_group_info3(struct samr_GroupInfoAttributes *r,
+ uint32_t attributes);
+void init_samr_group_info4(struct lsa_String *r, const char *description);
+void init_samr_group_info5(struct samr_GroupInfoAll *r,
+ const char *name,
+ uint32_t attributes,
+ uint32_t num_members,
+ const char *description);
+void init_samr_alias_info1(struct samr_AliasInfoAll *r,
+ const char *name,
+ uint32_t num_members,
+ const char *description);
+void init_samr_alias_info3(struct lsa_String *r,
+ const char *description);
+void init_samr_user_info7(struct samr_UserInfo7 *r,
+ const char *account_name);
+void init_samr_user_info9(struct samr_UserInfo9 *r,
+ uint32_t primary_gid);
+void init_samr_user_info16(struct samr_UserInfo16 *r,
+ uint32_t acct_flags);
+void init_samr_user_info18(struct samr_UserInfo18 *r,
+ const uint8 lm_pwd[16],
+ const uint8 nt_pwd[16]);
+void init_samr_user_info20(struct samr_UserInfo20 *r,
+ struct lsa_BinaryString *parameters);
+void init_samr_user_info21(struct samr_UserInfo21 *r,
+ NTTIME last_logon,
+ NTTIME last_logoff,
+ NTTIME last_password_change,
+ NTTIME acct_expiry,
+ NTTIME allow_password_change,
+ NTTIME force_password_change,
+ const char *account_name,
+ const char *full_name,
+ const char *home_directory,
+ const char *home_drive,
+ const char *logon_script,
+ const char *profile_path,
+ const char *description,
+ const char *workstations,
+ const char *comment,
+ struct lsa_BinaryString *parameters,
+ uint32_t rid,
+ uint32_t primary_gid,
+ uint32_t acct_flags,
+ uint32_t fields_present,
+ struct samr_LogonHours logon_hours,
+ uint16_t bad_password_count,
+ uint16_t logon_count,
+ uint16_t country_code,
+ uint16_t code_page,
+ uint8_t nt_password_set,
+ uint8_t lm_password_set,
+ uint8_t password_expired);
+void init_samr_user_info23(struct samr_UserInfo23 *r,
+ NTTIME last_logon,
+ NTTIME last_logoff,
+ NTTIME last_password_change,
+ NTTIME acct_expiry,
+ NTTIME allow_password_change,
+ NTTIME force_password_change,
+ const char *account_name,
+ const char *full_name,
+ const char *home_directory,
+ const char *home_drive,
+ const char *logon_script,
+ const char *profile_path,
+ const char *description,
+ const char *workstations,
+ const char *comment,
+ struct lsa_BinaryString *parameters,
+ uint32_t rid,
+ uint32_t primary_gid,
+ uint32_t acct_flags,
+ uint32_t fields_present,
+ struct samr_LogonHours logon_hours,
+ uint16_t bad_password_count,
+ uint16_t logon_count,
+ uint16_t country_code,
+ uint16_t code_page,
+ uint8_t nt_password_set,
+ uint8_t lm_password_set,
+ uint8_t password_expired,
+ uint8_t data[516],
+ uint8_t pw_len);
+void init_samr_user_info24(struct samr_UserInfo24 *r,
+ uint8_t data[516],
+ uint8_t pw_len);
+void init_samr_CryptPasswordEx(const char *pwd,
+ DATA_BLOB *session_key,
+ struct samr_CryptPasswordEx *pwd_buf);
+void init_samr_CryptPassword(const char *pwd,
+ DATA_BLOB *session_key,
+ struct samr_CryptPassword *pwd_buf);
+
+/* The following definitions come from rpc_client/init_srvsvc.c */
+
+void init_srvsvc_NetSrvInfo102(struct srvsvc_NetSrvInfo102 *r,
+ enum srvsvc_PlatformId platform_id,
+ const char *server_name,
+ uint32_t version_major,
+ uint32_t version_minor,
+ uint32_t server_type,
+ const char *comment,
+ uint32_t users,
+ uint32_t disc,
+ uint32_t hidden,
+ uint32_t announce,
+ uint32_t anndelta,
+ uint32_t licenses,
+ const char *userpath);
+void init_srvsvc_NetSrvInfo101(struct srvsvc_NetSrvInfo101 *r,
+ enum srvsvc_PlatformId platform_id,
+ const char *server_name,
+ uint32_t version_major,
+ uint32_t version_minor,
+ uint32_t server_type,
+ const char *comment);
+void init_srvsvc_NetSrvInfo100(struct srvsvc_NetSrvInfo100 *r,
+ enum srvsvc_PlatformId platform_id,
+ const char *server_name);
+void init_srvsvc_NetShareInfo0(struct srvsvc_NetShareInfo0 *r,
+ const char *name);
+void init_srvsvc_NetShareInfo1(struct srvsvc_NetShareInfo1 *r,
+ const char *name,
+ enum srvsvc_ShareType type,
+ const char *comment);
+void init_srvsvc_NetShareInfo2(struct srvsvc_NetShareInfo2 *r,
+ const char *name,
+ enum srvsvc_ShareType type,
+ const char *comment,
+ uint32_t permissions,
+ uint32_t max_users,
+ uint32_t current_users,
+ const char *path,
+ const char *password);
+void init_srvsvc_NetShareInfo501(struct srvsvc_NetShareInfo501 *r,
+ const char *name,
+ enum srvsvc_ShareType type,
+ const char *comment,
+ uint32_t csc_policy);
+void init_srvsvc_NetShareInfo502(struct srvsvc_NetShareInfo502 *r,
+ const char *name,
+ enum srvsvc_ShareType type,
+ const char *comment,
+ uint32_t permissions,
+ uint32_t max_users,
+ uint32_t current_users,
+ const char *path,
+ const char *password,
+ struct sec_desc_buf *sd_buf);
+void init_srvsvc_NetShareInfo1004(struct srvsvc_NetShareInfo1004 *r,
+ const char *comment);
+void init_srvsvc_NetShareInfo1005(struct srvsvc_NetShareInfo1005 *r,
+ uint32_t dfs_flags);
+void init_srvsvc_NetShareInfo1006(struct srvsvc_NetShareInfo1006 *r,
+ uint32_t max_users);
+void init_srvsvc_NetShareInfo1007(struct srvsvc_NetShareInfo1007 *r,
+ uint32_t flags,
+ const char *alternate_directory_name);
+void init_srvsvc_NetRemoteTODInfo(struct srvsvc_NetRemoteTODInfo *r,
+ uint32_t elapsed,
+ uint32_t msecs,
+ uint32_t hours,
+ uint32_t mins,
+ uint32_t secs,
+ uint32_t hunds,
+ int32_t ttimezone,
+ uint32_t tinterval,
+ uint32_t day,
+ uint32_t month,
+ uint32_t year,
+ uint32_t weekday);
+void init_srvsvc_NetSessInfo0(struct srvsvc_NetSessInfo0 *r,
+ const char *client);
+void init_srvsvc_NetSessInfo1(struct srvsvc_NetSessInfo1 *r,
+ const char *client,
+ const char *user,
+ uint32_t num_open,
+ uint32_t _time,
+ uint32_t idle_time,
+ uint32_t user_flags);
+void init_srvsvc_NetSessInfo2(struct srvsvc_NetSessInfo2 *r,
+ const char *client,
+ const char *user,
+ uint32_t num_open,
+ uint32_t _time,
+ uint32_t idle_time,
+ uint32_t user_flags,
+ const char *client_type);
+void init_srvsvc_NetSessInfo10(struct srvsvc_NetSessInfo10 *r,
+ const char *client,
+ const char *user,
+ uint32_t _time,
+ uint32_t idle_time);
+void init_srvsvc_NetSessInfo502(struct srvsvc_NetSessInfo502 *r,
+ const char *client,
+ const char *user,
+ uint32_t num_open,
+ uint32_t _time,
+ uint32_t idle_time,
+ uint32_t user_flags,
+ const char *client_type,
+ const char *transport);
+void init_srvsvc_NetFileInfo2(struct srvsvc_NetFileInfo2 *r,
+ uint32_t fid);
+void init_srvsvc_NetFileInfo3(struct srvsvc_NetFileInfo3 *r,
+ uint32_t fid,
+ uint32_t permissions,
+ uint32_t num_locks,
+ const char *path,
+ const char *user);
+void init_srvsvc_NetConnInfo0(struct srvsvc_NetConnInfo0 *r,
+ uint32_t conn_id);
+void init_srvsvc_NetConnInfo1(struct srvsvc_NetConnInfo1 *r,
+ uint32_t conn_id,
+ uint32_t conn_type,
+ uint32_t num_open,
+ uint32_t num_users,
+ uint32_t conn_time,
+ const char *user,
+ const char *share);
+
+/* The following definitions come from rpc_client/ndr.c */
+
+NTSTATUS cli_do_rpc_ndr(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const struct ndr_interface_table *table,
+ uint32 opnum, void *r);
+
+/* The following definitions come from rpc_parse/parse_buffer.c */
+
+void rpcbuf_init(RPC_BUFFER *buffer, uint32 size, TALLOC_CTX *ctx);
+bool prs_rpcbuffer(const char *desc, prs_struct *ps, int depth, RPC_BUFFER *buffer);
+bool prs_rpcbuffer_p(const char *desc, prs_struct *ps, int depth, RPC_BUFFER **buffer);
+bool rpcbuf_alloc_size(RPC_BUFFER *buffer, uint32 buffer_size);
+void rpcbuf_move(RPC_BUFFER *src, RPC_BUFFER **dest);
+uint32 rpcbuf_get_size(RPC_BUFFER *buffer);
+bool smb_io_relstr(const char *desc, RPC_BUFFER *buffer, int depth, UNISTR *string);
+bool smb_io_relarraystr(const char *desc, RPC_BUFFER *buffer, int depth, uint16 **string);
+bool smb_io_relsecdesc(const char *desc, RPC_BUFFER *buffer, int depth, SEC_DESC **secdesc);
+uint32 size_of_relative_string(UNISTR *string);
+
+/* The following definitions come from rpc_parse/parse_eventlog.c */
+
+bool eventlog_io_q_read_eventlog(const char *desc, EVENTLOG_Q_READ_EVENTLOG *q_u,
+ prs_struct *ps, int depth);
+bool eventlog_io_r_read_eventlog(const char *desc,
+ EVENTLOG_Q_READ_EVENTLOG *q_u,
+ EVENTLOG_R_READ_EVENTLOG *r_u,
+ prs_struct *ps,
+ int depth);
+
+/* The following definitions come from rpc_parse/parse_misc.c */
+
+bool smb_io_time(const char *desc, NTTIME *nttime, prs_struct *ps, int depth);
+bool smb_io_nttime(const char *desc, prs_struct *ps, int depth, NTTIME *nttime);
+uint32 get_enum_hnd(ENUM_HND *enh);
+void init_enum_hnd(ENUM_HND *enh, uint32 hnd);
+bool smb_io_enum_hnd(const char *desc, ENUM_HND *hnd, prs_struct *ps, int depth);
+bool smb_io_dom_sid(const char *desc, DOM_SID *sid, prs_struct *ps, int depth);
+void init_dom_sid2(DOM_SID2 *sid2, const DOM_SID *sid);
+bool smb_io_dom_sid2_p(const char *desc, prs_struct *ps, int depth, DOM_SID2 **sid2);
+bool smb_io_dom_sid2(const char *desc, DOM_SID2 *sid, prs_struct *ps, int depth);
+bool smb_io_uuid(const char *desc, struct GUID *uuid,
+ prs_struct *ps, int depth);
+void init_str_hdr(STRHDR *hdr, int max_len, int len, uint32 buffer);
+bool smb_io_strhdr(const char *desc, STRHDR *hdr, prs_struct *ps, int depth);
+void init_uni_hdr(UNIHDR *hdr, UNISTR2 *str2);
+bool smb_io_unihdr(const char *desc, UNIHDR *hdr, prs_struct *ps, int depth);
+void init_buf_hdr(BUFHDR *hdr, int max_len, int len);
+bool smb_io_hdrbuf_pre(const char *desc, BUFHDR *hdr, prs_struct *ps, int depth, uint32 *offset);
+bool smb_io_hdrbuf_post(const char *desc, BUFHDR *hdr, prs_struct *ps, int depth,
+ uint32 ptr_hdrbuf, uint32 max_len, uint32 len);
+bool smb_io_hdrbuf(const char *desc, BUFHDR *hdr, prs_struct *ps, int depth);
+void init_unistr(UNISTR *str, const char *buf);
+bool smb_io_unistr(const char *desc, UNISTR *uni, prs_struct *ps, int depth);
+void init_rpc_blob_uint32(RPC_DATA_BLOB *str, uint32 val);
+void init_rpc_blob_str(RPC_DATA_BLOB *str, const char *buf, int len);
+void init_rpc_blob_hex(RPC_DATA_BLOB *str, const char *buf);
+void init_rpc_blob_bytes(RPC_DATA_BLOB *str, uint8 *buf, size_t len);
+bool smb_io_buffer5(const char *desc, BUFFER5 *buf5, prs_struct *ps, int depth);
+void init_regval_buffer(REGVAL_BUFFER *str, const uint8 *buf, size_t len);
+bool smb_io_regval_buffer(const char *desc, prs_struct *ps, int depth, REGVAL_BUFFER *buf2);
+void init_buf_unistr2(UNISTR2 *str, uint32 *ptr, const char *buf);
+void copy_unistr2(UNISTR2 *str, const UNISTR2 *from);
+void init_string2(STRING2 *str, const char *buf, size_t max_len, size_t str_len);
+bool smb_io_string2(const char *desc, STRING2 *str2, uint32 buffer, prs_struct *ps, int depth);
+void init_unistr2(UNISTR2 *str, const char *buf, enum unistr2_term_codes flags);
+void init_unistr4(UNISTR4 *uni4, const char *buf, enum unistr2_term_codes flags);
+void init_unistr4_w( TALLOC_CTX *ctx, UNISTR4 *uni4, const smb_ucs2_t *buf );
+void init_unistr2_w(TALLOC_CTX *ctx, UNISTR2 *str, const smb_ucs2_t *buf);
+void init_unistr2_from_unistr(TALLOC_CTX *ctx, UNISTR2 *to, const UNISTR *from);
+void init_unistr2_from_datablob(UNISTR2 *str, DATA_BLOB *blob) ;
+bool prs_io_unistr2_p(const char *desc, prs_struct *ps, int depth, UNISTR2 **uni2);
+bool prs_io_unistr2(const char *desc, prs_struct *ps, int depth, UNISTR2 *uni2 );
+bool smb_io_unistr2(const char *desc, UNISTR2 *uni2, uint32 buffer, prs_struct *ps, int depth);
+bool prs_unistr4(const char *desc, prs_struct *ps, int depth, UNISTR4 *uni4);
+bool prs_unistr4_hdr(const char *desc, prs_struct *ps, int depth, UNISTR4 *uni4);
+bool prs_unistr4_str(const char *desc, prs_struct *ps, int depth, UNISTR4 *uni4);
+bool prs_unistr4_array(const char *desc, prs_struct *ps, int depth, UNISTR4_ARRAY *array );
+bool init_unistr4_array( UNISTR4_ARRAY *array, uint32 count, const char **strings );
+void init_dom_rid(DOM_RID *prid, uint32 rid, uint16 type, uint32 idx);
+bool smb_io_dom_rid(const char *desc, DOM_RID *rid, prs_struct *ps, int depth);
+bool smb_io_dom_rid2(const char *desc, DOM_RID2 *rid, prs_struct *ps, int depth);
+void init_dom_rid3(DOM_RID3 *rid3, uint32 rid, uint8 type);
+bool smb_io_dom_rid3(const char *desc, DOM_RID3 *rid3, prs_struct *ps, int depth);
+void init_dom_rid4(DOM_RID4 *rid4, uint16 unknown, uint16 attr, uint32 rid);
+void init_clnt_srv(DOM_CLNT_SRV *logcln, const char *logon_srv,
+ const char *comp_name);
+bool smb_io_clnt_srv(const char *desc, DOM_CLNT_SRV *logcln, prs_struct *ps, int depth);
+void init_log_info(DOM_LOG_INFO *loginfo, const char *logon_srv, const char *acct_name,
+ uint16 sec_chan, const char *comp_name);
+bool smb_io_log_info(const char *desc, DOM_LOG_INFO *loginfo, prs_struct *ps, int depth);
+bool smb_io_chal(const char *desc, DOM_CHAL *chal, prs_struct *ps, int depth);
+bool smb_io_cred(const char *desc, DOM_CRED *cred, prs_struct *ps, int depth);
+void init_clnt_info2(DOM_CLNT_INFO2 *clnt,
+ const char *logon_srv, const char *comp_name,
+ const DOM_CRED *clnt_cred);
+bool smb_io_clnt_info2(const char *desc, DOM_CLNT_INFO2 *clnt, prs_struct *ps, int depth);
+void init_clnt_info(DOM_CLNT_INFO *clnt,
+ const char *logon_srv, const char *acct_name,
+ uint16 sec_chan, const char *comp_name,
+ const DOM_CRED *cred);
+bool smb_io_clnt_info(const char *desc, DOM_CLNT_INFO *clnt, prs_struct *ps, int depth);
+void init_logon_id(DOM_LOGON_ID *logonid, uint32 log_id_low, uint32 log_id_high);
+bool smb_io_logon_id(const char *desc, DOM_LOGON_ID *logonid, prs_struct *ps, int depth);
+void init_owf_info(OWF_INFO *hash, const uint8 data[16]);
+bool smb_io_owf_info(const char *desc, OWF_INFO *hash, prs_struct *ps, int depth);
+bool smb_io_gid(const char *desc, DOM_GID *gid, prs_struct *ps, int depth);
+bool smb_io_pol_hnd(const char *desc, POLICY_HND *pol, prs_struct *ps, int depth);
+void init_unistr3(UNISTR3 *str, const char *buf);
+bool smb_io_unistr3(const char *desc, UNISTR3 *name, prs_struct *ps, int depth);
+bool prs_uint64(const char *name, prs_struct *ps, int depth, uint64 *data64);
+bool smb_io_bufhdr2(const char *desc, BUFHDR2 *hdr, prs_struct *ps, int depth);
+bool smb_io_bufhdr4(const char *desc, BUFHDR4 *hdr, prs_struct *ps, int depth);
+bool smb_io_rpc_blob(const char *desc, RPC_DATA_BLOB *blob, prs_struct *ps, int depth);
+bool make_uni_hdr(UNIHDR *hdr, int len);
+bool make_bufhdr2(BUFHDR2 *hdr, uint32 info_level, uint32 length, uint32 buffer);
+uint32 str_len_uni(UNISTR *source);
+bool policy_handle_is_valid(const POLICY_HND *hnd);
+
+/* The following definitions come from rpc_parse/parse_ntsvcs.c */
+
+bool ntsvcs_io_q_get_device_list(const char *desc, NTSVCS_Q_GET_DEVICE_LIST *q_u, prs_struct *ps, int depth);
+bool ntsvcs_io_r_get_device_list(const char *desc, NTSVCS_R_GET_DEVICE_LIST *r_u, prs_struct *ps, int depth);
+bool ntsvcs_io_q_get_device_reg_property(const char *desc, NTSVCS_Q_GET_DEVICE_REG_PROPERTY *q_u, prs_struct *ps, int depth);
+bool ntsvcs_io_r_get_device_reg_property(const char *desc, NTSVCS_R_GET_DEVICE_REG_PROPERTY *r_u, prs_struct *ps, int depth);
+
+/* The following definitions come from rpc_parse/parse_prs.c */
+
+void prs_dump(const char *name, int v, prs_struct *ps);
+void prs_dump_before(const char *name, int v, prs_struct *ps);
+void prs_dump_region(const char *name, int v, prs_struct *ps,
+ int from_off, int to_off);
+void prs_debug(prs_struct *ps, int depth, const char *desc, const char *fn_name);
+bool prs_init(prs_struct *ps, uint32 size, TALLOC_CTX *ctx, bool io);
+void prs_mem_free(prs_struct *ps);
+void prs_mem_clear(prs_struct *ps);
+char *prs_alloc_mem_(prs_struct *ps, size_t size, unsigned int count);
+char *prs_alloc_mem(prs_struct *ps, size_t size, unsigned int count);
+TALLOC_CTX *prs_get_mem_context(prs_struct *ps);
+void prs_give_memory(prs_struct *ps, char *buf, uint32 size, bool is_dynamic);
+char *prs_take_memory(prs_struct *ps, uint32 *psize);
+bool prs_set_buffer_size(prs_struct *ps, uint32 newsize);
+bool prs_grow(prs_struct *ps, uint32 extra_space);
+bool prs_force_grow(prs_struct *ps, uint32 extra_space);
+char *prs_data_p(prs_struct *ps);
+uint32 prs_data_size(prs_struct *ps);
+uint32 prs_offset(prs_struct *ps);
+bool prs_set_offset(prs_struct *ps, uint32 offset);
+bool prs_append_prs_data(prs_struct *dst, prs_struct *src);
+bool prs_append_some_data(prs_struct *dst, void *src_base, uint32_t start,
+ uint32_t len);
+bool prs_append_some_prs_data(prs_struct *dst, prs_struct *src, int32 start, uint32 len);
+bool prs_copy_data_in(prs_struct *dst, const char *src, uint32 len);
+bool prs_copy_data_out(char *dst, prs_struct *src, uint32 len);
+bool prs_copy_all_data_out(char *dst, prs_struct *src);
+void prs_set_endian_data(prs_struct *ps, bool endian);
+bool prs_align(prs_struct *ps);
+bool prs_align_uint16(prs_struct *ps);
+bool prs_align_uint64(prs_struct *ps);
+bool prs_align_custom(prs_struct *ps, uint8 boundary);
+bool prs_align_needed(prs_struct *ps, uint32 needed);
+char *prs_mem_get(prs_struct *ps, uint32 extra_size);
+void prs_switch_type(prs_struct *ps, bool io);
+void prs_force_dynamic(prs_struct *ps);
+void prs_set_session_key(prs_struct *ps, const char sess_key[16]);
+bool prs_uint8(const char *name, prs_struct *ps, int depth, uint8 *data8);
+bool prs_pointer( const char *name, prs_struct *ps, int depth,
+ void *dta, size_t data_size,
+ bool (*prs_fn)(const char*, prs_struct*, int, void*) );
+bool prs_uint16(const char *name, prs_struct *ps, int depth, uint16 *data16);
+bool prs_uint32(const char *name, prs_struct *ps, int depth, uint32 *data32);
+bool prs_int32(const char *name, prs_struct *ps, int depth, int32 *data32);
+bool prs_ntstatus(const char *name, prs_struct *ps, int depth, NTSTATUS *status);
+bool prs_dcerpc_status(const char *name, prs_struct *ps, int depth, NTSTATUS *status);
+bool prs_werror(const char *name, prs_struct *ps, int depth, WERROR *status);
+bool prs_uint8s(bool charmode, const char *name, prs_struct *ps, int depth, uint8 *data8s, int len);
+bool prs_uint16s(bool charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len);
+bool prs_uint16uni(bool charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len);
+bool prs_uint32s(bool charmode, const char *name, prs_struct *ps, int depth, uint32 *data32s, int len);
+bool prs_buffer5(bool charmode, const char *name, prs_struct *ps, int depth, BUFFER5 *str);
+bool prs_regval_buffer(bool charmode, const char *name, prs_struct *ps, int depth, REGVAL_BUFFER *buf);
+bool prs_string2(bool charmode, const char *name, prs_struct *ps, int depth, STRING2 *str);
+bool prs_unistr2(bool charmode, const char *name, prs_struct *ps, int depth, UNISTR2 *str);
+bool prs_unistr3(bool charmode, const char *name, UNISTR3 *str, prs_struct *ps, int depth);
+bool prs_unistr(const char *name, prs_struct *ps, int depth, UNISTR *str);
+bool prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_buf_size);
+bool prs_string_alloc(const char *name, prs_struct *ps, int depth, const char **str);
+bool prs_uint16_pre(const char *name, prs_struct *ps, int depth, uint16 *data16, uint32 *offset);
+bool prs_uint16_post(const char *name, prs_struct *ps, int depth, uint16 *data16,
+ uint32 ptr_uint16, uint32 start_offset);
+bool prs_uint32_pre(const char *name, prs_struct *ps, int depth, uint32 *data32, uint32 *offset);
+bool prs_uint32_post(const char *name, prs_struct *ps, int depth, uint32 *data32,
+ uint32 ptr_uint32, uint32 data_size);
+int tdb_prs_store(TDB_CONTEXT *tdb, TDB_DATA kbuf, prs_struct *ps);
+int tdb_prs_fetch(TDB_CONTEXT *tdb, TDB_DATA kbuf, prs_struct *ps, TALLOC_CTX *mem_ctx);
+bool prs_hash1(prs_struct *ps, uint32 offset, int len);
+void schannel_encode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level,
+ enum schannel_direction direction,
+ RPC_AUTH_SCHANNEL_CHK * verf,
+ char *data, size_t data_len);
+bool schannel_decode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level,
+ enum schannel_direction direction,
+ RPC_AUTH_SCHANNEL_CHK * verf, char *data, size_t data_len);
+bool prs_init_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx);
+bool prs_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx);
+
+/* The following definitions come from rpc_parse/parse_rpc.c */
+
+const char *cli_get_pipe_name_from_iface(TALLOC_CTX *mem_ctx,
+ struct cli_state *cli,
+ const struct ndr_syntax_id *interface);
+void init_rpc_hdr(RPC_HDR *hdr, enum RPC_PKT_TYPE pkt_type, uint8 flags,
+ uint32 call_id, int data_len, int auth_len);
+bool smb_io_rpc_hdr(const char *desc, RPC_HDR *rpc, prs_struct *ps, int depth);
+void init_rpc_context(RPC_CONTEXT *rpc_ctx, uint16 context_id,
+ const RPC_IFACE *abstract, const RPC_IFACE *transfer);
+void init_rpc_hdr_rb(RPC_HDR_RB *rpc,
+ uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid,
+ RPC_CONTEXT *context);
+bool smb_io_rpc_context(const char *desc, RPC_CONTEXT *rpc_ctx, prs_struct *ps, int depth);
+bool smb_io_rpc_hdr_rb(const char *desc, RPC_HDR_RB *rpc, prs_struct *ps, int depth);
+void init_rpc_hdr_ba(RPC_HDR_BA *rpc,
+ uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid,
+ const char *pipe_addr,
+ uint8 num_results, uint16 result, uint16 reason,
+ RPC_IFACE *transfer);
+bool smb_io_rpc_hdr_ba(const char *desc, RPC_HDR_BA *rpc, prs_struct *ps, int depth);
+void init_rpc_hdr_req(RPC_HDR_REQ *hdr, uint32 alloc_hint, uint16 opnum);
+bool smb_io_rpc_hdr_req(const char *desc, RPC_HDR_REQ *rpc, prs_struct *ps, int depth);
+bool smb_io_rpc_hdr_resp(const char *desc, RPC_HDR_RESP *rpc, prs_struct *ps, int depth);
+bool smb_io_rpc_hdr_fault(const char *desc, RPC_HDR_FAULT *rpc, prs_struct *ps, int depth);
+void init_rpc_hdr_auth(RPC_HDR_AUTH *rai,
+ uint8 auth_type, uint8 auth_level,
+ uint8 auth_pad_len,
+ uint32 auth_context_id);
+bool smb_io_rpc_hdr_auth(const char *desc, RPC_HDR_AUTH *rai, prs_struct *ps, int depth);
+bool rpc_auth_verifier_chk(RPC_AUTH_VERIFIER *rav,
+ const char *signature, uint32 msg_type);
+void init_rpc_auth_verifier(RPC_AUTH_VERIFIER *rav,
+ const char *signature, uint32 msg_type);
+bool smb_io_rpc_auth_verifier(const char *desc, RPC_AUTH_VERIFIER *rav, prs_struct *ps, int depth);
+bool smb_io_rpc_schannel_verifier(const char *desc, RPC_AUTH_VERIFIER *rav, prs_struct *ps, int depth);
+void init_rpc_auth_schannel_neg(RPC_AUTH_SCHANNEL_NEG *neg,
+ const char *domain, const char *myname);
+bool smb_io_rpc_auth_schannel_neg(const char *desc, RPC_AUTH_SCHANNEL_NEG *neg,
+ prs_struct *ps, int depth);
+bool smb_io_rpc_auth_schannel_chk(const char *desc, int auth_len,
+ RPC_AUTH_SCHANNEL_CHK * chk,
+ prs_struct *ps, int depth);
+
+/* The following definitions come from rpc_parse/parse_sec.c */
+
+bool sec_io_desc(const char *desc, SEC_DESC **ppsd, prs_struct *ps, int depth);
+bool sec_io_desc_buf(const char *desc, SEC_DESC_BUF **ppsdb, prs_struct *ps, int depth);
+
+/* The following definitions come from rpc_parse/parse_spoolss.c */
+
+bool spoolss_io_system_time(const char *desc, prs_struct *ps, int depth, SYSTEMTIME *systime);
+bool make_systemtime(SYSTEMTIME *systime, struct tm *unixtime);
+bool smb_io_notify_info_data_strings(const char *desc,SPOOL_NOTIFY_INFO_DATA *data,
+ prs_struct *ps, int depth);
+bool spool_io_user_level_1( const char *desc, prs_struct *ps, int depth, SPOOL_USER_1 *q_u );
+bool spoolss_io_devmode(const char *desc, prs_struct *ps, int depth, DEVICEMODE *devmode);
+bool make_spoolss_q_open_printer_ex(SPOOL_Q_OPEN_PRINTER_EX *q_u,
+ const fstring printername,
+ const fstring datatype,
+ uint32 access_required,
+ const fstring clientname,
+ const fstring user_name);
+bool make_spoolss_q_addprinterex( TALLOC_CTX *mem_ctx, SPOOL_Q_ADDPRINTEREX *q_u,
+ const char *srv_name, const char* clientname, const char* user_name,
+ uint32 level, PRINTER_INFO_CTR *ctr);
+bool make_spoolss_printer_info_2(TALLOC_CTX *ctx, SPOOL_PRINTER_INFO_LEVEL_2 **spool_info2,
+ PRINTER_INFO_2 *info);
+bool make_spoolss_printer_info_3(TALLOC_CTX *mem_ctx, SPOOL_PRINTER_INFO_LEVEL_3 **spool_info3,
+ PRINTER_INFO_3 *info);
+bool make_spoolss_printer_info_7(TALLOC_CTX *mem_ctx, SPOOL_PRINTER_INFO_LEVEL_7 **spool_info7,
+ PRINTER_INFO_7 *info);
+bool spoolss_io_q_open_printer(const char *desc, SPOOL_Q_OPEN_PRINTER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_open_printer(const char *desc, SPOOL_R_OPEN_PRINTER *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_open_printer_ex(const char *desc, SPOOL_Q_OPEN_PRINTER_EX *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_open_printer_ex(const char *desc, SPOOL_R_OPEN_PRINTER_EX *r_u, prs_struct *ps, int depth);
+bool make_spoolss_q_deleteprinterdriverex( TALLOC_CTX *mem_ctx,
+ SPOOL_Q_DELETEPRINTERDRIVEREX *q_u,
+ const char *server,
+ const char* arch,
+ const char* driver,
+ int version);
+bool make_spoolss_q_deleteprinterdriver(
+ TALLOC_CTX *mem_ctx,
+ SPOOL_Q_DELETEPRINTERDRIVER *q_u,
+ const char *server,
+ const char* arch,
+ const char* driver
+);
+bool make_spoolss_q_getprinterdata(SPOOL_Q_GETPRINTERDATA *q_u,
+ const POLICY_HND *handle,
+ const char *valuename, uint32 size);
+bool make_spoolss_q_getprinterdataex(SPOOL_Q_GETPRINTERDATAEX *q_u,
+ const POLICY_HND *handle,
+ const char *keyname,
+ const char *valuename, uint32 size);
+bool spoolss_io_q_getprinterdata(const char *desc, SPOOL_Q_GETPRINTERDATA *q_u, prs_struct *ps, int depth);
+bool spoolss_io_q_deleteprinterdata(const char *desc, SPOOL_Q_DELETEPRINTERDATA *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_deleteprinterdata(const char *desc, SPOOL_R_DELETEPRINTERDATA *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_deleteprinterdataex(const char *desc, SPOOL_Q_DELETEPRINTERDATAEX *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_deleteprinterdataex(const char *desc, SPOOL_R_DELETEPRINTERDATAEX *r_u, prs_struct *ps, int depth);
+bool spoolss_io_r_getprinterdata(const char *desc, SPOOL_R_GETPRINTERDATA *r_u, prs_struct *ps, int depth);
+bool make_spoolss_q_closeprinter(SPOOL_Q_CLOSEPRINTER *q_u, POLICY_HND *hnd);
+bool spoolss_io_q_abortprinter(const char *desc, SPOOL_Q_ABORTPRINTER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_abortprinter(const char *desc, SPOOL_R_ABORTPRINTER *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_deleteprinter(const char *desc, SPOOL_Q_DELETEPRINTER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_deleteprinter(const char *desc, SPOOL_R_DELETEPRINTER *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_deleteprinterdriver(const char *desc, SPOOL_Q_DELETEPRINTERDRIVER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_deleteprinterdriver(const char *desc, SPOOL_R_DELETEPRINTERDRIVER *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_deleteprinterdriverex(const char *desc, SPOOL_Q_DELETEPRINTERDRIVEREX *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_deleteprinterdriverex(const char *desc, SPOOL_R_DELETEPRINTERDRIVEREX *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_closeprinter(const char *desc, SPOOL_Q_CLOSEPRINTER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_closeprinter(const char *desc, SPOOL_R_CLOSEPRINTER *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_startdocprinter(const char *desc, SPOOL_Q_STARTDOCPRINTER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_startdocprinter(const char *desc, SPOOL_R_STARTDOCPRINTER *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_enddocprinter(const char *desc, SPOOL_Q_ENDDOCPRINTER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_enddocprinter(const char *desc, SPOOL_R_ENDDOCPRINTER *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_startpageprinter(const char *desc, SPOOL_Q_STARTPAGEPRINTER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_startpageprinter(const char *desc, SPOOL_R_STARTPAGEPRINTER *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_endpageprinter(const char *desc, SPOOL_Q_ENDPAGEPRINTER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_endpageprinter(const char *desc, SPOOL_R_ENDPAGEPRINTER *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_writeprinter(const char *desc, SPOOL_Q_WRITEPRINTER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_writeprinter(const char *desc, SPOOL_R_WRITEPRINTER *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_rffpcnex(const char *desc, SPOOL_Q_RFFPCNEX *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_rffpcnex(const char *desc, SPOOL_R_RFFPCNEX *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_rfnpcnex(const char *desc, SPOOL_Q_RFNPCNEX *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_rfnpcnex(const char *desc, SPOOL_R_RFNPCNEX *r_u, prs_struct *ps, int depth);
+bool smb_io_printer_info_0(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_0 *info, int depth);
+bool smb_io_printer_info_1(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_1 *info, int depth);
+bool smb_io_printer_info_2(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_2 *info, int depth);
+bool smb_io_printer_info_3(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_3 *info, int depth);
+bool smb_io_printer_info_4(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_4 *info, int depth);
+bool smb_io_printer_info_5(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_5 *info, int depth);
+bool smb_io_printer_info_6(const char *desc, RPC_BUFFER *buffer,
+ PRINTER_INFO_6 *info, int depth);
+bool smb_io_printer_info_7(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_7 *info, int depth);
+bool smb_io_port_info_1(const char *desc, RPC_BUFFER *buffer, PORT_INFO_1 *info, int depth);
+bool smb_io_port_info_2(const char *desc, RPC_BUFFER *buffer, PORT_INFO_2 *info, int depth);
+bool smb_io_printer_driver_info_1(const char *desc, RPC_BUFFER *buffer, DRIVER_INFO_1 *info, int depth) ;
+bool smb_io_printer_driver_info_2(const char *desc, RPC_BUFFER *buffer, DRIVER_INFO_2 *info, int depth) ;
+bool smb_io_printer_driver_info_3(const char *desc, RPC_BUFFER *buffer, DRIVER_INFO_3 *info, int depth);
+bool smb_io_printer_driver_info_6(const char *desc, RPC_BUFFER *buffer, DRIVER_INFO_6 *info, int depth);
+bool smb_io_job_info_1(const char *desc, RPC_BUFFER *buffer, JOB_INFO_1 *info, int depth);
+bool smb_io_job_info_2(const char *desc, RPC_BUFFER *buffer, JOB_INFO_2 *info, int depth);
+bool smb_io_form_1(const char *desc, RPC_BUFFER *buffer, FORM_1 *info, int depth);
+bool smb_io_driverdir_1(const char *desc, RPC_BUFFER *buffer, DRIVER_DIRECTORY_1 *info, int depth);
+bool smb_io_port_1(const char *desc, RPC_BUFFER *buffer, PORT_INFO_1 *info, int depth);
+bool smb_io_port_2(const char *desc, RPC_BUFFER *buffer, PORT_INFO_2 *info, int depth);
+bool smb_io_printprocessor_info_1(const char *desc, RPC_BUFFER *buffer, PRINTPROCESSOR_1 *info, int depth);
+bool smb_io_printprocdatatype_info_1(const char *desc, RPC_BUFFER *buffer, PRINTPROCDATATYPE_1 *info, int depth);
+bool smb_io_printmonitor_info_1(const char *desc, RPC_BUFFER *buffer, PRINTMONITOR_1 *info, int depth);
+bool smb_io_printmonitor_info_2(const char *desc, RPC_BUFFER *buffer, PRINTMONITOR_2 *info, int depth);
+uint32 spoolss_size_printer_info_0(PRINTER_INFO_0 *info);
+uint32 spoolss_size_printer_info_1(PRINTER_INFO_1 *info);
+uint32 spoolss_size_printer_info_2(PRINTER_INFO_2 *info);
+uint32 spoolss_size_printer_info_4(PRINTER_INFO_4 *info);
+uint32 spoolss_size_printer_info_5(PRINTER_INFO_5 *info);
+uint32 spoolss_size_printer_info_6(PRINTER_INFO_6 *info);
+uint32 spoolss_size_printer_info_3(PRINTER_INFO_3 *info);
+uint32 spoolss_size_printer_info_7(PRINTER_INFO_7 *info);
+uint32 spoolss_size_printer_driver_info_1(DRIVER_INFO_1 *info);
+uint32 spoolss_size_printer_driver_info_2(DRIVER_INFO_2 *info);
+uint32 spoolss_size_string_array(uint16 *string);
+uint32 spoolss_size_printer_driver_info_3(DRIVER_INFO_3 *info);
+uint32 spoolss_size_printer_driver_info_6(DRIVER_INFO_6 *info);
+uint32 spoolss_size_job_info_1(JOB_INFO_1 *info);
+uint32 spoolss_size_job_info_2(JOB_INFO_2 *info);
+uint32 spoolss_size_form_1(FORM_1 *info);
+uint32 spoolss_size_port_info_1(PORT_INFO_1 *info);
+uint32 spoolss_size_driverdir_info_1(DRIVER_DIRECTORY_1 *info);
+uint32 spoolss_size_printprocessordirectory_info_1(PRINTPROCESSOR_DIRECTORY_1 *info);
+uint32 spoolss_size_port_info_2(PORT_INFO_2 *info);
+uint32 spoolss_size_printprocessor_info_1(PRINTPROCESSOR_1 *info);
+uint32 spoolss_size_printprocdatatype_info_1(PRINTPROCDATATYPE_1 *info);
+uint32 spoolss_size_printer_enum_values(PRINTER_ENUM_VALUES *p);
+uint32 spoolss_size_printmonitor_info_1(PRINTMONITOR_1 *info);
+uint32 spoolss_size_printmonitor_info_2(PRINTMONITOR_2 *info);
+bool make_spoolss_q_getprinterdriver2(SPOOL_Q_GETPRINTERDRIVER2 *q_u,
+ const POLICY_HND *hnd,
+ const fstring architecture,
+ uint32 level, uint32 clientmajor, uint32 clientminor,
+ RPC_BUFFER *buffer, uint32 offered);
+bool spoolss_io_q_getprinterdriver2(const char *desc, SPOOL_Q_GETPRINTERDRIVER2 *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_getprinterdriver2(const char *desc, SPOOL_R_GETPRINTERDRIVER2 *r_u, prs_struct *ps, int depth);
+bool make_spoolss_q_enumprinters(
+ SPOOL_Q_ENUMPRINTERS *q_u,
+ uint32 flags,
+ char *servername,
+ uint32 level,
+ RPC_BUFFER *buffer,
+ uint32 offered
+);
+bool make_spoolss_q_enumports(SPOOL_Q_ENUMPORTS *q_u,
+ fstring servername, uint32 level,
+ RPC_BUFFER *buffer, uint32 offered);
+bool spoolss_io_q_enumprinters(const char *desc, SPOOL_Q_ENUMPRINTERS *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_enumprinters(const char *desc, SPOOL_R_ENUMPRINTERS *r_u, prs_struct *ps, int depth);
+bool spoolss_io_r_getprinter(const char *desc, SPOOL_R_GETPRINTER *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_getprinter(const char *desc, SPOOL_Q_GETPRINTER *q_u, prs_struct *ps, int depth);
+bool make_spoolss_q_getprinter(
+ TALLOC_CTX *mem_ctx,
+ SPOOL_Q_GETPRINTER *q_u,
+ const POLICY_HND *hnd,
+ uint32 level,
+ RPC_BUFFER *buffer,
+ uint32 offered
+);
+bool make_spoolss_q_setprinter(TALLOC_CTX *mem_ctx, SPOOL_Q_SETPRINTER *q_u,
+ const POLICY_HND *hnd, uint32 level, PRINTER_INFO_CTR *info,
+ uint32 command);
+bool spoolss_io_r_setprinter(const char *desc, SPOOL_R_SETPRINTER *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_setprinter(const char *desc, SPOOL_Q_SETPRINTER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_fcpn(const char *desc, SPOOL_R_FCPN *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_fcpn(const char *desc, SPOOL_Q_FCPN *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_addjob(const char *desc, SPOOL_R_ADDJOB *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_addjob(const char *desc, SPOOL_Q_ADDJOB *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_enumjobs(const char *desc, SPOOL_R_ENUMJOBS *r_u, prs_struct *ps, int depth);
+bool make_spoolss_q_enumjobs(SPOOL_Q_ENUMJOBS *q_u, const POLICY_HND *hnd,
+ uint32 firstjob,
+ uint32 numofjobs,
+ uint32 level,
+ RPC_BUFFER *buffer,
+ uint32 offered);
+bool spoolss_io_q_enumjobs(const char *desc, SPOOL_Q_ENUMJOBS *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_schedulejob(const char *desc, SPOOL_R_SCHEDULEJOB *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_schedulejob(const char *desc, SPOOL_Q_SCHEDULEJOB *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_setjob(const char *desc, SPOOL_R_SETJOB *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_setjob(const char *desc, SPOOL_Q_SETJOB *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_enumprinterdrivers(const char *desc, SPOOL_R_ENUMPRINTERDRIVERS *r_u, prs_struct *ps, int depth);
+bool make_spoolss_q_enumprinterdrivers(SPOOL_Q_ENUMPRINTERDRIVERS *q_u,
+ const char *name,
+ const char *environment,
+ uint32 level,
+ RPC_BUFFER *buffer, uint32 offered);
+bool spoolss_io_q_enumprinterdrivers(const char *desc, SPOOL_Q_ENUMPRINTERDRIVERS *q_u, prs_struct *ps, int depth);
+bool spoolss_io_q_enumforms(const char *desc, SPOOL_Q_ENUMFORMS *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_enumforms(const char *desc, SPOOL_R_ENUMFORMS *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_getform(const char *desc, SPOOL_Q_GETFORM *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_getform(const char *desc, SPOOL_R_GETFORM *r_u, prs_struct *ps, int depth);
+bool spoolss_io_r_enumports(const char *desc, SPOOL_R_ENUMPORTS *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_enumports(const char *desc, SPOOL_Q_ENUMPORTS *q_u, prs_struct *ps, int depth);
+bool spool_io_printer_info_level_1(const char *desc, SPOOL_PRINTER_INFO_LEVEL_1 *il, prs_struct *ps, int depth);
+bool spool_io_printer_info_level_3(const char *desc, SPOOL_PRINTER_INFO_LEVEL_3 *il, prs_struct *ps, int depth);
+bool spool_io_printer_info_level_2(const char *desc, SPOOL_PRINTER_INFO_LEVEL_2 *il, prs_struct *ps, int depth);
+bool spool_io_printer_info_level_7(const char *desc, SPOOL_PRINTER_INFO_LEVEL_7 *il, prs_struct *ps, int depth);
+bool spool_io_printer_info_level(const char *desc, SPOOL_PRINTER_INFO_LEVEL *il, prs_struct *ps, int depth);
+bool spoolss_io_q_addprinterex(const char *desc, SPOOL_Q_ADDPRINTEREX *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_addprinterex(const char *desc, SPOOL_R_ADDPRINTEREX *r_u,
+ prs_struct *ps, int depth);
+bool spool_io_printer_driver_info_level_3(const char *desc, SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 **q_u,
+ prs_struct *ps, int depth);
+bool spool_io_printer_driver_info_level_6(const char *desc, SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 **q_u,
+ prs_struct *ps, int depth);
+bool smb_io_unibuffer(const char *desc, UNISTR2 *buffer, prs_struct *ps, int depth);
+bool spool_io_printer_driver_info_level(const char *desc, SPOOL_PRINTER_DRIVER_INFO_LEVEL *il, prs_struct *ps, int depth);
+bool make_spoolss_q_addprinterdriver(TALLOC_CTX *mem_ctx,
+ SPOOL_Q_ADDPRINTERDRIVER *q_u, const char* srv_name,
+ uint32 level, PRINTER_DRIVER_CTR *info);
+bool make_spoolss_driver_info_3(TALLOC_CTX *mem_ctx,
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 **spool_drv_info,
+ DRIVER_INFO_3 *info3);
+bool make_spoolss_buffer5(TALLOC_CTX *mem_ctx, BUFFER5 *buf5, uint32 len, uint16 *src);
+bool spoolss_io_q_addprinterdriver(const char *desc, SPOOL_Q_ADDPRINTERDRIVER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_addprinterdriver(const char *desc, SPOOL_R_ADDPRINTERDRIVER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_q_addprinterdriverex(const char *desc, SPOOL_Q_ADDPRINTERDRIVEREX *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_addprinterdriverex(const char *desc, SPOOL_R_ADDPRINTERDRIVEREX *q_u, prs_struct *ps, int depth);
+bool uni_2_asc_printer_driver_3(SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 *uni,
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 **asc);
+bool uni_2_asc_printer_driver_6(SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 *uni,
+ NT_PRINTER_DRIVER_INFO_LEVEL_6 **asc);
+bool uni_2_asc_printer_info_2(const SPOOL_PRINTER_INFO_LEVEL_2 *uni,
+ NT_PRINTER_INFO_LEVEL_2 *d);
+bool make_spoolss_q_getprinterdriverdir(SPOOL_Q_GETPRINTERDRIVERDIR *q_u,
+ fstring servername, fstring env_name, uint32 level,
+ RPC_BUFFER *buffer, uint32 offered);
+bool spoolss_io_q_getprinterdriverdir(const char *desc, SPOOL_Q_GETPRINTERDRIVERDIR *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_getprinterdriverdir(const char *desc, SPOOL_R_GETPRINTERDRIVERDIR *r_u, prs_struct *ps, int depth);
+bool spoolss_io_r_enumprintprocessors(const char *desc, SPOOL_R_ENUMPRINTPROCESSORS *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_enumprintprocessors(const char *desc, SPOOL_Q_ENUMPRINTPROCESSORS *q_u, prs_struct *ps, int depth);
+bool spoolss_io_q_addprintprocessor(const char *desc, SPOOL_Q_ADDPRINTPROCESSOR *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_addprintprocessor(const char *desc, SPOOL_R_ADDPRINTPROCESSOR *r_u, prs_struct *ps, int depth);
+bool spoolss_io_r_enumprintprocdatatypes(const char *desc, SPOOL_R_ENUMPRINTPROCDATATYPES *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_enumprintprocdatatypes(const char *desc, SPOOL_Q_ENUMPRINTPROCDATATYPES *q_u, prs_struct *ps, int depth);
+bool spoolss_io_q_enumprintmonitors(const char *desc, SPOOL_Q_ENUMPRINTMONITORS *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_enumprintmonitors(const char *desc, SPOOL_R_ENUMPRINTMONITORS *r_u, prs_struct *ps, int depth);
+bool spoolss_io_r_enumprinterdata(const char *desc, SPOOL_R_ENUMPRINTERDATA *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_enumprinterdata(const char *desc, SPOOL_Q_ENUMPRINTERDATA *q_u, prs_struct *ps, int depth);
+bool make_spoolss_q_enumprinterdata(SPOOL_Q_ENUMPRINTERDATA *q_u,
+ const POLICY_HND *hnd,
+ uint32 idx, uint32 valuelen, uint32 datalen);
+bool make_spoolss_q_enumprinterdataex(SPOOL_Q_ENUMPRINTERDATAEX *q_u,
+ const POLICY_HND *hnd, const char *key,
+ uint32 size);
+bool make_spoolss_q_setprinterdata(SPOOL_Q_SETPRINTERDATA *q_u, const POLICY_HND *hnd,
+ char* value, uint32 data_type, char* data, uint32 data_size);
+bool make_spoolss_q_setprinterdataex(SPOOL_Q_SETPRINTERDATAEX *q_u, const POLICY_HND *hnd,
+ char *key, char* value, uint32 data_type, char* data,
+ uint32 data_size);
+bool spoolss_io_q_setprinterdata(const char *desc, SPOOL_Q_SETPRINTERDATA *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_setprinterdata(const char *desc, SPOOL_R_SETPRINTERDATA *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_resetprinter(const char *desc, SPOOL_Q_RESETPRINTER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_resetprinter(const char *desc, SPOOL_R_RESETPRINTER *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_deleteform(const char *desc, SPOOL_Q_DELETEFORM *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_deleteform(const char *desc, SPOOL_R_DELETEFORM *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_addform(const char *desc, SPOOL_Q_ADDFORM *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_addform(const char *desc, SPOOL_R_ADDFORM *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_setform(const char *desc, SPOOL_Q_SETFORM *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_setform(const char *desc, SPOOL_R_SETFORM *r_u, prs_struct *ps, int depth);
+bool spoolss_io_r_getjob(const char *desc, SPOOL_R_GETJOB *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_getjob(const char *desc, SPOOL_Q_GETJOB *q_u, prs_struct *ps, int depth);
+void free_devmode(DEVICEMODE *devmode);
+void free_printer_info_1(PRINTER_INFO_1 *printer);
+void free_printer_info_2(PRINTER_INFO_2 *printer);
+void free_printer_info_3(PRINTER_INFO_3 *printer);
+void free_printer_info_4(PRINTER_INFO_4 *printer);
+void free_printer_info_5(PRINTER_INFO_5 *printer);
+void free_printer_info_6(PRINTER_INFO_6 *printer);
+void free_printer_info_7(PRINTER_INFO_7 *printer);
+void free_job_info_2(JOB_INFO_2 *job);
+bool make_spoolss_q_replyopenprinter(SPOOL_Q_REPLYOPENPRINTER *q_u,
+ const fstring string, uint32 printer, uint32 type);
+bool spoolss_io_q_replyopenprinter(const char *desc, SPOOL_Q_REPLYOPENPRINTER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_replyopenprinter(const char *desc, SPOOL_R_REPLYOPENPRINTER *r_u, prs_struct *ps, int depth);
+bool make_spoolss_q_routerreplyprinter(SPOOL_Q_ROUTERREPLYPRINTER *q_u, POLICY_HND *hnd,
+ uint32 condition, uint32 change_id);
+bool spoolss_io_q_routerreplyprinter (const char *desc, SPOOL_Q_ROUTERREPLYPRINTER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_routerreplyprinter (const char *desc, SPOOL_R_ROUTERREPLYPRINTER *r_u, prs_struct *ps, int depth);
+bool make_spoolss_q_reply_closeprinter(SPOOL_Q_REPLYCLOSEPRINTER *q_u, POLICY_HND *hnd);
+bool spoolss_io_q_replycloseprinter(const char *desc, SPOOL_Q_REPLYCLOSEPRINTER *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_replycloseprinter(const char *desc, SPOOL_R_REPLYCLOSEPRINTER *r_u, prs_struct *ps, int depth);
+bool make_spoolss_q_reply_rrpcn(SPOOL_Q_REPLY_RRPCN *q_u, POLICY_HND *hnd,
+ uint32 change_low, uint32 change_high,
+ SPOOL_NOTIFY_INFO *info);
+bool spoolss_io_q_reply_rrpcn(const char *desc, SPOOL_Q_REPLY_RRPCN *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_reply_rrpcn(const char *desc, SPOOL_R_REPLY_RRPCN *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_getprinterdataex(const char *desc, SPOOL_Q_GETPRINTERDATAEX *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_getprinterdataex(const char *desc, SPOOL_R_GETPRINTERDATAEX *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_setprinterdataex(const char *desc, SPOOL_Q_SETPRINTERDATAEX *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_setprinterdataex(const char *desc, SPOOL_R_SETPRINTERDATAEX *r_u, prs_struct *ps, int depth);
+bool make_spoolss_q_enumprinterkey(SPOOL_Q_ENUMPRINTERKEY *q_u,
+ POLICY_HND *hnd, const char *key,
+ uint32 size);
+bool spoolss_io_q_enumprinterkey(const char *desc, SPOOL_Q_ENUMPRINTERKEY *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_enumprinterkey(const char *desc, SPOOL_R_ENUMPRINTERKEY *r_u, prs_struct *ps, int depth);
+bool make_spoolss_q_deleteprinterkey(SPOOL_Q_DELETEPRINTERKEY *q_u,
+ POLICY_HND *hnd, char *keyname);
+bool spoolss_io_q_deleteprinterkey(const char *desc, SPOOL_Q_DELETEPRINTERKEY *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_deleteprinterkey(const char *desc, SPOOL_R_DELETEPRINTERKEY *r_u, prs_struct *ps, int depth);
+bool spoolss_io_q_enumprinterdataex(const char *desc, SPOOL_Q_ENUMPRINTERDATAEX *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_enumprinterdataex(const char *desc, SPOOL_R_ENUMPRINTERDATAEX *r_u, prs_struct *ps, int depth);
+bool make_spoolss_q_getprintprocessordirectory(SPOOL_Q_GETPRINTPROCESSORDIRECTORY *q_u, const char *name, char *environment, int level, RPC_BUFFER *buffer, uint32 offered);
+bool spoolss_io_q_getprintprocessordirectory(const char *desc, SPOOL_Q_GETPRINTPROCESSORDIRECTORY *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_getprintprocessordirectory(const char *desc, SPOOL_R_GETPRINTPROCESSORDIRECTORY *r_u, prs_struct *ps, int depth);
+bool smb_io_printprocessordirectory_1(const char *desc, RPC_BUFFER *buffer, PRINTPROCESSOR_DIRECTORY_1 *info, int depth);
+bool make_spoolss_q_addform(SPOOL_Q_ADDFORM *q_u, POLICY_HND *handle,
+ int level, FORM *form);
+bool make_spoolss_q_setform(SPOOL_Q_SETFORM *q_u, POLICY_HND *handle,
+ int level, const char *form_name, FORM *form);
+bool make_spoolss_q_deleteform(SPOOL_Q_DELETEFORM *q_u, POLICY_HND *handle,
+ const char *form);
+bool make_spoolss_q_getform(SPOOL_Q_GETFORM *q_u, POLICY_HND *handle,
+ const char *formname, uint32 level,
+ RPC_BUFFER *buffer, uint32 offered);
+bool make_spoolss_q_enumforms(SPOOL_Q_ENUMFORMS *q_u, POLICY_HND *handle,
+ uint32 level, RPC_BUFFER *buffer,
+ uint32 offered);
+bool make_spoolss_q_setjob(SPOOL_Q_SETJOB *q_u, POLICY_HND *handle,
+ uint32 jobid, uint32 level, uint32 command);
+bool make_spoolss_q_getjob(SPOOL_Q_GETJOB *q_u, POLICY_HND *handle,
+ uint32 jobid, uint32 level, RPC_BUFFER *buffer,
+ uint32 offered);
+bool make_spoolss_q_startpageprinter(SPOOL_Q_STARTPAGEPRINTER *q_u,
+ POLICY_HND *handle);
+bool make_spoolss_q_endpageprinter(SPOOL_Q_ENDPAGEPRINTER *q_u,
+ POLICY_HND *handle);
+bool make_spoolss_q_startdocprinter(SPOOL_Q_STARTDOCPRINTER *q_u,
+ POLICY_HND *handle, uint32 level,
+ char *docname, char *outputfile,
+ char *datatype);
+bool make_spoolss_q_enddocprinter(SPOOL_Q_ENDDOCPRINTER *q_u,
+ POLICY_HND *handle);
+bool make_spoolss_q_writeprinter(SPOOL_Q_WRITEPRINTER *q_u,
+ POLICY_HND *handle, uint32 data_size,
+ char *data);
+bool make_spoolss_q_deleteprinterdata(SPOOL_Q_DELETEPRINTERDATA *q_u,
+ POLICY_HND *handle, char *valuename);
+bool make_spoolss_q_deleteprinterdataex(SPOOL_Q_DELETEPRINTERDATAEX *q_u,
+ POLICY_HND *handle, char *key,
+ char *value);
+bool make_spoolss_q_rffpcnex(SPOOL_Q_RFFPCNEX *q_u, POLICY_HND *handle,
+ uint32 flags, uint32 options, const char *localmachine,
+ uint32 printerlocal, SPOOL_NOTIFY_OPTION *option);
+bool spoolss_io_q_xcvdataport(const char *desc, SPOOL_Q_XCVDATAPORT *q_u, prs_struct *ps, int depth);
+bool spoolss_io_r_xcvdataport(const char *desc, SPOOL_R_XCVDATAPORT *r_u, prs_struct *ps, int depth);
+bool make_monitorui_buf( RPC_BUFFER *buf, const char *dllname );
+bool convert_port_data_1( NT_PORT_DATA_1 *port1, RPC_BUFFER *buf ) ;
+
+/* The following definitions come from rpc_parse/parse_svcctl.c */
+
+bool svcctl_io_enum_services_status( const char *desc, ENUM_SERVICES_STATUS *enum_status, RPC_BUFFER *buffer, int depth );
+bool svcctl_io_service_status_process( const char *desc, SERVICE_STATUS_PROCESS *status, RPC_BUFFER *buffer, int depth );
+uint32 svcctl_sizeof_enum_services_status( ENUM_SERVICES_STATUS *status );
+uint32 svcctl_sizeof_service_config( SERVICE_CONFIG *config );
+bool svcctl_io_q_enum_services_status(const char *desc, SVCCTL_Q_ENUM_SERVICES_STATUS *q_u, prs_struct *ps, int depth);
+bool svcctl_io_r_enum_services_status(const char *desc, SVCCTL_R_ENUM_SERVICES_STATUS *r_u, prs_struct *ps, int depth);
+bool svcctl_io_q_query_service_config(const char *desc, SVCCTL_Q_QUERY_SERVICE_CONFIG *q_u, prs_struct *ps, int depth);
+bool svcctl_io_r_query_service_config(const char *desc, SVCCTL_R_QUERY_SERVICE_CONFIG *r_u, prs_struct *ps, int depth);
+bool svcctl_io_q_query_service_config2(const char *desc, SVCCTL_Q_QUERY_SERVICE_CONFIG2 *q_u, prs_struct *ps, int depth);
+void init_service_description_buffer(SERVICE_DESCRIPTION *desc, const char *service_desc );
+bool svcctl_io_service_description( const char *desc, SERVICE_DESCRIPTION *description, RPC_BUFFER *buffer, int depth );
+uint32 svcctl_sizeof_service_description( SERVICE_DESCRIPTION *desc );
+bool svcctl_io_service_fa( const char *desc, SERVICE_FAILURE_ACTIONS *fa, RPC_BUFFER *buffer, int depth );
+uint32 svcctl_sizeof_service_fa( SERVICE_FAILURE_ACTIONS *fa);
+bool svcctl_io_r_query_service_config2(const char *desc, SVCCTL_R_QUERY_SERVICE_CONFIG2 *r_u, prs_struct *ps, int depth);
+bool svcctl_io_q_query_service_status_ex(const char *desc, SVCCTL_Q_QUERY_SERVICE_STATUSEX *q_u, prs_struct *ps, int depth);
+bool svcctl_io_r_query_service_status_ex(const char *desc, SVCCTL_R_QUERY_SERVICE_STATUSEX *r_u, prs_struct *ps, int depth);
+
+/* The following definitions come from rpc_server/srv_dfs_nt.c */
+
+void _dfs_GetManagerVersion(pipes_struct *p, struct dfs_GetManagerVersion *r);
+WERROR _dfs_Add(pipes_struct *p, struct dfs_Add *r);
+WERROR _dfs_Remove(pipes_struct *p, struct dfs_Remove *r);
+WERROR _dfs_Enum(pipes_struct *p, struct dfs_Enum *r);
+WERROR _dfs_GetInfo(pipes_struct *p, struct dfs_GetInfo *r);
+WERROR _dfs_SetInfo(pipes_struct *p, struct dfs_SetInfo *r);
+WERROR _dfs_Rename(pipes_struct *p, struct dfs_Rename *r);
+WERROR _dfs_Move(pipes_struct *p, struct dfs_Move *r);
+WERROR _dfs_ManagerGetConfigInfo(pipes_struct *p, struct dfs_ManagerGetConfigInfo *r);
+WERROR _dfs_ManagerSendSiteInfo(pipes_struct *p, struct dfs_ManagerSendSiteInfo *r);
+WERROR _dfs_AddFtRoot(pipes_struct *p, struct dfs_AddFtRoot *r);
+WERROR _dfs_RemoveFtRoot(pipes_struct *p, struct dfs_RemoveFtRoot *r);
+WERROR _dfs_AddStdRoot(pipes_struct *p, struct dfs_AddStdRoot *r);
+WERROR _dfs_RemoveStdRoot(pipes_struct *p, struct dfs_RemoveStdRoot *r);
+WERROR _dfs_ManagerInitialize(pipes_struct *p, struct dfs_ManagerInitialize *r);
+WERROR _dfs_AddStdRootForced(pipes_struct *p, struct dfs_AddStdRootForced *r);
+WERROR _dfs_GetDcAddress(pipes_struct *p, struct dfs_GetDcAddress *r);
+WERROR _dfs_SetDcAddress(pipes_struct *p, struct dfs_SetDcAddress *r);
+WERROR _dfs_FlushFtTable(pipes_struct *p, struct dfs_FlushFtTable *r);
+WERROR _dfs_Add2(pipes_struct *p, struct dfs_Add2 *r);
+WERROR _dfs_Remove2(pipes_struct *p, struct dfs_Remove2 *r);
+WERROR _dfs_EnumEx(pipes_struct *p, struct dfs_EnumEx *r);
+WERROR _dfs_SetInfo2(pipes_struct *p, struct dfs_SetInfo2 *r);
+
+/* The following definitions come from rpc_server/srv_dssetup_nt.c */
+
+WERROR _dssetup_DsRoleGetPrimaryDomainInformation(pipes_struct *p,
+ struct dssetup_DsRoleGetPrimaryDomainInformation *r);
+WERROR _dssetup_DsRoleDnsNameToFlatName(pipes_struct *p,
+ struct dssetup_DsRoleDnsNameToFlatName *r);
+WERROR _dssetup_DsRoleDcAsDc(pipes_struct *p,
+ struct dssetup_DsRoleDcAsDc *r);
+WERROR _dssetup_DsRoleDcAsReplica(pipes_struct *p,
+ struct dssetup_DsRoleDcAsReplica *r);
+WERROR _dssetup_DsRoleDemoteDc(pipes_struct *p,
+ struct dssetup_DsRoleDemoteDc *r);
+WERROR _dssetup_DsRoleGetDcOperationProgress(pipes_struct *p,
+ struct dssetup_DsRoleGetDcOperationProgress *r);
+WERROR _dssetup_DsRoleGetDcOperationResults(pipes_struct *p,
+ struct dssetup_DsRoleGetDcOperationResults *r);
+WERROR _dssetup_DsRoleCancel(pipes_struct *p,
+ struct dssetup_DsRoleCancel *r);
+WERROR _dssetup_DsRoleServerSaveStateForUpgrade(pipes_struct *p,
+ struct dssetup_DsRoleServerSaveStateForUpgrade *r);
+WERROR _dssetup_DsRoleUpgradeDownlevelServer(pipes_struct *p,
+ struct dssetup_DsRoleUpgradeDownlevelServer *r);
+WERROR _dssetup_DsRoleAbortDownlevelServerUpgrade(pipes_struct *p,
+ struct dssetup_DsRoleAbortDownlevelServerUpgrade *r);
+
+/* The following definitions come from rpc_server/srv_echo_nt.c */
+
+void _echo_AddOne(pipes_struct *p, struct echo_AddOne *r );
+void _echo_EchoData(pipes_struct *p, struct echo_EchoData *r);
+void _echo_SinkData(pipes_struct *p, struct echo_SinkData *r);
+void _echo_SourceData(pipes_struct *p, struct echo_SourceData *r);
+void _echo_TestCall(pipes_struct *p, struct echo_TestCall *r);
+NTSTATUS _echo_TestCall2(pipes_struct *p, struct echo_TestCall2 *r);
+uint32 _echo_TestSleep(pipes_struct *p, struct echo_TestSleep *r);
+void _echo_TestEnum(pipes_struct *p, struct echo_TestEnum *r);
+void _echo_TestSurrounding(pipes_struct *p, struct echo_TestSurrounding *r);
+uint16 _echo_TestDoublePointer(pipes_struct *p, struct echo_TestDoublePointer *r);
+
+/* The following definitions come from rpc_server/srv_eventlog.c */
+
+NTSTATUS rpc_eventlog2_init(void);
+void eventlog2_get_pipe_fns(struct api_struct **fns, int *n_fns);
+
+/* The following definitions come from rpc_server/srv_eventlog_lib.c */
+
+TDB_CONTEXT *elog_init_tdb( char *tdbfilename );
+char *elog_tdbname(TALLOC_CTX *ctx, const char *name );
+int elog_tdb_size( TDB_CONTEXT * tdb, int *MaxSize, int *Retention );
+bool prune_eventlog( TDB_CONTEXT * tdb );
+bool can_write_to_eventlog( TDB_CONTEXT * tdb, int32 needed );
+ELOG_TDB *elog_open_tdb( char *logname, bool force_clear );
+int elog_close_tdb( ELOG_TDB *etdb, bool force_close );
+int write_eventlog_tdb( TDB_CONTEXT * the_tdb, Eventlog_entry * ee );
+void fixup_eventlog_entry( Eventlog_entry * ee );
+bool parse_logentry( char *line, Eventlog_entry * entry, bool * eor );
+
+/* The following definitions come from rpc_server/srv_eventlog_nt.c */
+
+NTSTATUS _eventlog_OpenEventLogW(pipes_struct *p,
+ struct eventlog_OpenEventLogW *r);
+NTSTATUS _eventlog_ClearEventLogW(pipes_struct *p,
+ struct eventlog_ClearEventLogW *r);
+NTSTATUS _eventlog_CloseEventLog( pipes_struct * p, struct eventlog_CloseEventLog *r );
+NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
+ EVENTLOG_Q_READ_EVENTLOG * q_u,
+ EVENTLOG_R_READ_EVENTLOG * r_u );
+NTSTATUS _eventlog_GetOldestRecord(pipes_struct *p,
+ struct eventlog_GetOldestRecord *r);
+NTSTATUS _eventlog_GetNumRecords(pipes_struct *p,
+ struct eventlog_GetNumRecords *r);
+NTSTATUS _eventlog_BackupEventLogW(pipes_struct *p, struct eventlog_BackupEventLogW *r);
+NTSTATUS _eventlog_DeregisterEventSource(pipes_struct *p, struct eventlog_DeregisterEventSource *r);
+NTSTATUS _eventlog_ChangeNotify(pipes_struct *p, struct eventlog_ChangeNotify *r);
+NTSTATUS _eventlog_RegisterEventSourceW(pipes_struct *p, struct eventlog_RegisterEventSourceW *r);
+NTSTATUS _eventlog_OpenBackupEventLogW(pipes_struct *p, struct eventlog_OpenBackupEventLogW *r);
+NTSTATUS _eventlog_ReadEventLogW(pipes_struct *p, struct eventlog_ReadEventLogW *r);
+NTSTATUS _eventlog_ReportEventW(pipes_struct *p, struct eventlog_ReportEventW *r);
+NTSTATUS _eventlog_ClearEventLogA(pipes_struct *p, struct eventlog_ClearEventLogA *r);
+NTSTATUS _eventlog_BackupEventLogA(pipes_struct *p, struct eventlog_BackupEventLogA *r);
+NTSTATUS _eventlog_OpenEventLogA(pipes_struct *p, struct eventlog_OpenEventLogA *r);
+NTSTATUS _eventlog_RegisterEventSourceA(pipes_struct *p, struct eventlog_RegisterEventSourceA *r);
+NTSTATUS _eventlog_OpenBackupEventLogA(pipes_struct *p, struct eventlog_OpenBackupEventLogA *r);
+NTSTATUS _eventlog_ReadEventLogA(pipes_struct *p, struct eventlog_ReadEventLogA *r);
+NTSTATUS _eventlog_ReportEventA(pipes_struct *p, struct eventlog_ReportEventA *r);
+NTSTATUS _eventlog_RegisterClusterSvc(pipes_struct *p, struct eventlog_RegisterClusterSvc *r);
+NTSTATUS _eventlog_DeregisterClusterSvc(pipes_struct *p, struct eventlog_DeregisterClusterSvc *r);
+NTSTATUS _eventlog_WriteClusterEvents(pipes_struct *p, struct eventlog_WriteClusterEvents *r);
+NTSTATUS _eventlog_GetLogIntormation(pipes_struct *p, struct eventlog_GetLogIntormation *r);
+NTSTATUS _eventlog_FlushEventLog(pipes_struct *p, struct eventlog_FlushEventLog *r);
+
+/* The following definitions come from rpc_server/srv_initshutdown_nt.c */
+
+WERROR _initshutdown_Init(pipes_struct *p, struct initshutdown_Init *r);
+WERROR _initshutdown_InitEx(pipes_struct *p, struct initshutdown_InitEx *r);
+WERROR _initshutdown_Abort(pipes_struct *p, struct initshutdown_Abort *r);
+
+/* The following definitions come from rpc_server/srv_lsa_hnd.c */
+
+bool init_pipe_handle_list(pipes_struct *p, const char *pipe_name);
+bool create_policy_hnd(pipes_struct *p, POLICY_HND *hnd, void (*free_fn)(void *), void *data_ptr);
+bool find_policy_by_hnd(pipes_struct *p, POLICY_HND *hnd, void **data_p);
+bool close_policy_hnd(pipes_struct *p, POLICY_HND *hnd);
+void close_policy_by_pipe(pipes_struct *p);
+bool pipe_access_check(pipes_struct *p);
+
+/* The following definitions come from rpc_server/srv_lsa_nt.c */
+
+NTSTATUS _lsa_OpenPolicy2(pipes_struct *p,
+ struct lsa_OpenPolicy2 *r);
+NTSTATUS _lsa_OpenPolicy(pipes_struct *p,
+ struct lsa_OpenPolicy *r);
+NTSTATUS _lsa_EnumTrustDom(pipes_struct *p,
+ struct lsa_EnumTrustDom *r);
+NTSTATUS _lsa_QueryInfoPolicy(pipes_struct *p,
+ struct lsa_QueryInfoPolicy *r);
+NTSTATUS _lsa_LookupSids(pipes_struct *p,
+ struct lsa_LookupSids *r);
+NTSTATUS _lsa_LookupSids2(pipes_struct *p,
+ struct lsa_LookupSids2 *r);
+NTSTATUS _lsa_LookupSids3(pipes_struct *p,
+ struct lsa_LookupSids3 *r);
+NTSTATUS _lsa_LookupNames(pipes_struct *p,
+ struct lsa_LookupNames *r);
+NTSTATUS _lsa_LookupNames2(pipes_struct *p,
+ struct lsa_LookupNames2 *r);
+NTSTATUS _lsa_LookupNames3(pipes_struct *p,
+ struct lsa_LookupNames3 *r);
+NTSTATUS _lsa_LookupNames4(pipes_struct *p,
+ struct lsa_LookupNames4 *r);
+NTSTATUS _lsa_Close(pipes_struct *p, struct lsa_Close *r);
+NTSTATUS _lsa_OpenSecret(pipes_struct *p, struct lsa_OpenSecret *r);
+NTSTATUS _lsa_OpenTrustedDomain(pipes_struct *p, struct lsa_OpenTrustedDomain *r);
+NTSTATUS _lsa_CreateTrustedDomain(pipes_struct *p, struct lsa_CreateTrustedDomain *r);
+NTSTATUS _lsa_CreateSecret(pipes_struct *p, struct lsa_CreateSecret *r);
+NTSTATUS _lsa_SetSecret(pipes_struct *p, struct lsa_SetSecret *r);
+NTSTATUS _lsa_DeleteObject(pipes_struct *p,
+ struct lsa_DeleteObject *r);
+NTSTATUS _lsa_EnumPrivs(pipes_struct *p,
+ struct lsa_EnumPrivs *r);
+NTSTATUS _lsa_LookupPrivDisplayName(pipes_struct *p,
+ struct lsa_LookupPrivDisplayName *r);
+NTSTATUS _lsa_EnumAccounts(pipes_struct *p,
+ struct lsa_EnumAccounts *r);
+NTSTATUS _lsa_GetUserName(pipes_struct *p,
+ struct lsa_GetUserName *r);
+NTSTATUS _lsa_CreateAccount(pipes_struct *p,
+ struct lsa_CreateAccount *r);
+NTSTATUS _lsa_OpenAccount(pipes_struct *p,
+ struct lsa_OpenAccount *r);
+NTSTATUS _lsa_EnumPrivsAccount(pipes_struct *p,
+ struct lsa_EnumPrivsAccount *r);
+NTSTATUS _lsa_GetSystemAccessAccount(pipes_struct *p,
+ struct lsa_GetSystemAccessAccount *r);
+NTSTATUS _lsa_SetSystemAccessAccount(pipes_struct *p,
+ struct lsa_SetSystemAccessAccount *r);
+NTSTATUS _lsa_AddPrivilegesToAccount(pipes_struct *p,
+ struct lsa_AddPrivilegesToAccount *r);
+NTSTATUS _lsa_RemovePrivilegesFromAccount(pipes_struct *p,
+ struct lsa_RemovePrivilegesFromAccount *r);
+NTSTATUS _lsa_QuerySecurity(pipes_struct *p,
+ struct lsa_QuerySecurity *r);
+NTSTATUS _lsa_AddAccountRights(pipes_struct *p,
+ struct lsa_AddAccountRights *r);
+NTSTATUS _lsa_RemoveAccountRights(pipes_struct *p,
+ struct lsa_RemoveAccountRights *r);
+NTSTATUS _lsa_EnumAccountRights(pipes_struct *p,
+ struct lsa_EnumAccountRights *r);
+NTSTATUS _lsa_LookupPrivValue(pipes_struct *p,
+ struct lsa_LookupPrivValue *r);
+NTSTATUS _lsa_Delete(pipes_struct *p, struct lsa_Delete *r);
+NTSTATUS _lsa_SetSecObj(pipes_struct *p, struct lsa_SetSecObj *r);
+NTSTATUS _lsa_ChangePassword(pipes_struct *p, struct lsa_ChangePassword *r);
+NTSTATUS _lsa_SetInfoPolicy(pipes_struct *p, struct lsa_SetInfoPolicy *r);
+NTSTATUS _lsa_ClearAuditLog(pipes_struct *p, struct lsa_ClearAuditLog *r);
+NTSTATUS _lsa_GetQuotasForAccount(pipes_struct *p, struct lsa_GetQuotasForAccount *r);
+NTSTATUS _lsa_SetQuotasForAccount(pipes_struct *p, struct lsa_SetQuotasForAccount *r);
+NTSTATUS _lsa_QueryTrustedDomainInfo(pipes_struct *p, struct lsa_QueryTrustedDomainInfo *r);
+NTSTATUS _lsa_SetInformationTrustedDomain(pipes_struct *p, struct lsa_SetInformationTrustedDomain *r);
+NTSTATUS _lsa_QuerySecret(pipes_struct *p, struct lsa_QuerySecret *r);
+NTSTATUS _lsa_LookupPrivName(pipes_struct *p, struct lsa_LookupPrivName *r);
+NTSTATUS _lsa_EnumAccountsWithUserRight(pipes_struct *p, struct lsa_EnumAccountsWithUserRight *r);
+NTSTATUS _lsa_QueryTrustedDomainInfoBySid(pipes_struct *p, struct lsa_QueryTrustedDomainInfoBySid *r);
+NTSTATUS _lsa_SetTrustedDomainInfo(pipes_struct *p, struct lsa_SetTrustedDomainInfo *r);
+NTSTATUS _lsa_DeleteTrustedDomain(pipes_struct *p, struct lsa_DeleteTrustedDomain *r);
+NTSTATUS _lsa_StorePrivateData(pipes_struct *p, struct lsa_StorePrivateData *r);
+NTSTATUS _lsa_RetrievePrivateData(pipes_struct *p, struct lsa_RetrievePrivateData *r);
+NTSTATUS _lsa_QueryInfoPolicy2(pipes_struct *p, struct lsa_QueryInfoPolicy2 *r);
+NTSTATUS _lsa_SetInfoPolicy2(pipes_struct *p, struct lsa_SetInfoPolicy2 *r);
+NTSTATUS _lsa_QueryTrustedDomainInfoByName(pipes_struct *p, struct lsa_QueryTrustedDomainInfoByName *r);
+NTSTATUS _lsa_SetTrustedDomainInfoByName(pipes_struct *p, struct lsa_SetTrustedDomainInfoByName *r);
+NTSTATUS _lsa_EnumTrustedDomainsEx(pipes_struct *p, struct lsa_EnumTrustedDomainsEx *r);
+NTSTATUS _lsa_CreateTrustedDomainEx(pipes_struct *p, struct lsa_CreateTrustedDomainEx *r);
+NTSTATUS _lsa_CloseTrustedDomainEx(pipes_struct *p, struct lsa_CloseTrustedDomainEx *r);
+NTSTATUS _lsa_QueryDomainInformationPolicy(pipes_struct *p, struct lsa_QueryDomainInformationPolicy *r);
+NTSTATUS _lsa_SetDomainInformationPolicy(pipes_struct *p, struct lsa_SetDomainInformationPolicy *r);
+NTSTATUS _lsa_OpenTrustedDomainByName(pipes_struct *p, struct lsa_OpenTrustedDomainByName *r);
+NTSTATUS _lsa_TestCall(pipes_struct *p, struct lsa_TestCall *r);
+NTSTATUS _lsa_CreateTrustedDomainEx2(pipes_struct *p, struct lsa_CreateTrustedDomainEx2 *r);
+NTSTATUS _lsa_CREDRWRITE(pipes_struct *p, struct lsa_CREDRWRITE *r);
+NTSTATUS _lsa_CREDRREAD(pipes_struct *p, struct lsa_CREDRREAD *r);
+NTSTATUS _lsa_CREDRENUMERATE(pipes_struct *p, struct lsa_CREDRENUMERATE *r);
+NTSTATUS _lsa_CREDRWRITEDOMAINCREDENTIALS(pipes_struct *p, struct lsa_CREDRWRITEDOMAINCREDENTIALS *r);
+NTSTATUS _lsa_CREDRREADDOMAINCREDENTIALS(pipes_struct *p, struct lsa_CREDRREADDOMAINCREDENTIALS *r);
+NTSTATUS _lsa_CREDRDELETE(pipes_struct *p, struct lsa_CREDRDELETE *r);
+NTSTATUS _lsa_CREDRGETTARGETINFO(pipes_struct *p, struct lsa_CREDRGETTARGETINFO *r);
+NTSTATUS _lsa_CREDRPROFILELOADED(pipes_struct *p, struct lsa_CREDRPROFILELOADED *r);
+NTSTATUS _lsa_CREDRGETSESSIONTYPES(pipes_struct *p, struct lsa_CREDRGETSESSIONTYPES *r);
+NTSTATUS _lsa_LSARREGISTERAUDITEVENT(pipes_struct *p, struct lsa_LSARREGISTERAUDITEVENT *r);
+NTSTATUS _lsa_LSARGENAUDITEVENT(pipes_struct *p, struct lsa_LSARGENAUDITEVENT *r);
+NTSTATUS _lsa_LSARUNREGISTERAUDITEVENT(pipes_struct *p, struct lsa_LSARUNREGISTERAUDITEVENT *r);
+NTSTATUS _lsa_lsaRQueryForestTrustInformation(pipes_struct *p, struct lsa_lsaRQueryForestTrustInformation *r);
+NTSTATUS _lsa_LSARSETFORESTTRUSTINFORMATION(pipes_struct *p, struct lsa_LSARSETFORESTTRUSTINFORMATION *r);
+NTSTATUS _lsa_CREDRRENAME(pipes_struct *p, struct lsa_CREDRRENAME *r);
+NTSTATUS _lsa_LSAROPENPOLICYSCE(pipes_struct *p, struct lsa_LSAROPENPOLICYSCE *r);
+NTSTATUS _lsa_LSARADTREGISTERSECURITYEVENTSOURCE(pipes_struct *p, struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE *r);
+NTSTATUS _lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(pipes_struct *p, struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE *r);
+NTSTATUS _lsa_LSARADTREPORTSECURITYEVENT(pipes_struct *p, struct lsa_LSARADTREPORTSECURITYEVENT *r);
+
+/* The following definitions come from rpc_server/srv_netlog_nt.c */
+
+WERROR _netr_LogonControl(pipes_struct *p,
+ struct netr_LogonControl *r);
+WERROR _netr_LogonControl2(pipes_struct *p,
+ struct netr_LogonControl2 *r);
+WERROR _netr_NetrEnumerateTrustedDomains(pipes_struct *p,
+ struct netr_NetrEnumerateTrustedDomains *r);
+NTSTATUS _netr_ServerReqChallenge(pipes_struct *p,
+ struct netr_ServerReqChallenge *r);
+NTSTATUS _netr_ServerAuthenticate(pipes_struct *p,
+ struct netr_ServerAuthenticate *r);
+NTSTATUS _netr_ServerAuthenticate2(pipes_struct *p,
+ struct netr_ServerAuthenticate2 *r);
+NTSTATUS _netr_ServerPasswordSet(pipes_struct *p,
+ struct netr_ServerPasswordSet *r);
+NTSTATUS _netr_LogonSamLogoff(pipes_struct *p,
+ struct netr_LogonSamLogoff *r);
+NTSTATUS _netr_LogonSamLogon(pipes_struct *p,
+ struct netr_LogonSamLogon *r);
+NTSTATUS _netr_LogonSamLogonEx(pipes_struct *p,
+ struct netr_LogonSamLogonEx *r);
+WERROR _netr_LogonUasLogon(pipes_struct *p,
+ struct netr_LogonUasLogon *r);
+WERROR _netr_LogonUasLogoff(pipes_struct *p,
+ struct netr_LogonUasLogoff *r);
+NTSTATUS _netr_DatabaseDeltas(pipes_struct *p,
+ struct netr_DatabaseDeltas *r);
+NTSTATUS _netr_DatabaseSync(pipes_struct *p,
+ struct netr_DatabaseSync *r);
+NTSTATUS _netr_AccountDeltas(pipes_struct *p,
+ struct netr_AccountDeltas *r);
+NTSTATUS _netr_AccountSync(pipes_struct *p,
+ struct netr_AccountSync *r);
+WERROR _netr_GetDcName(pipes_struct *p,
+ struct netr_GetDcName *r);
+WERROR _netr_GetAnyDCName(pipes_struct *p,
+ struct netr_GetAnyDCName *r);
+NTSTATUS _netr_DatabaseSync2(pipes_struct *p,
+ struct netr_DatabaseSync2 *r);
+NTSTATUS _netr_DatabaseRedo(pipes_struct *p,
+ struct netr_DatabaseRedo *r);
+WERROR _netr_LogonControl2Ex(pipes_struct *p,
+ struct netr_LogonControl2Ex *r);
+WERROR _netr_DsRGetDCName(pipes_struct *p,
+ struct netr_DsRGetDCName *r);
+WERROR _netr_NETRLOGONDUMMYROUTINE1(pipes_struct *p,
+ struct netr_NETRLOGONDUMMYROUTINE1 *r);
+WERROR _netr_NETRLOGONSETSERVICEBITS(pipes_struct *p,
+ struct netr_NETRLOGONSETSERVICEBITS *r);
+WERROR _netr_LogonGetTrustRid(pipes_struct *p,
+ struct netr_LogonGetTrustRid *r);
+WERROR _netr_NETRLOGONCOMPUTESERVERDIGEST(pipes_struct *p,
+ struct netr_NETRLOGONCOMPUTESERVERDIGEST *r);
+WERROR _netr_NETRLOGONCOMPUTECLIENTDIGEST(pipes_struct *p,
+ struct netr_NETRLOGONCOMPUTECLIENTDIGEST *r);
+NTSTATUS _netr_ServerAuthenticate3(pipes_struct *p,
+ struct netr_ServerAuthenticate3 *r);
+WERROR _netr_DsRGetDCNameEx(pipes_struct *p,
+ struct netr_DsRGetDCNameEx *r);
+WERROR _netr_DsRGetSiteName(pipes_struct *p,
+ struct netr_DsRGetSiteName *r);
+NTSTATUS _netr_LogonGetDomainInfo(pipes_struct *p,
+ struct netr_LogonGetDomainInfo *r);
+NTSTATUS _netr_ServerPasswordSet2(pipes_struct *p,
+ struct netr_ServerPasswordSet2 *r);
+WERROR _netr_ServerPasswordGet(pipes_struct *p,
+ struct netr_ServerPasswordGet *r);
+WERROR _netr_NETRLOGONSENDTOSAM(pipes_struct *p,
+ struct netr_NETRLOGONSENDTOSAM *r);
+WERROR _netr_DsRAddressToSitenamesW(pipes_struct *p,
+ struct netr_DsRAddressToSitenamesW *r);
+WERROR _netr_DsRGetDCNameEx2(pipes_struct *p,
+ struct netr_DsRGetDCNameEx2 *r);
+WERROR _netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(pipes_struct *p,
+ struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN *r);
+WERROR _netr_NetrEnumerateTrustedDomainsEx(pipes_struct *p,
+ struct netr_NetrEnumerateTrustedDomainsEx *r);
+WERROR _netr_DsRAddressToSitenamesExW(pipes_struct *p,
+ struct netr_DsRAddressToSitenamesExW *r);
+WERROR _netr_DsrGetDcSiteCoverageW(pipes_struct *p,
+ struct netr_DsrGetDcSiteCoverageW *r);
+WERROR _netr_DsrEnumerateDomainTrusts(pipes_struct *p,
+ struct netr_DsrEnumerateDomainTrusts *r);
+WERROR _netr_DsrDeregisterDNSHostRecords(pipes_struct *p,
+ struct netr_DsrDeregisterDNSHostRecords *r);
+NTSTATUS _netr_ServerTrustPasswordsGet(pipes_struct *p,
+ struct netr_ServerTrustPasswordsGet *r);
+WERROR _netr_DsRGetForestTrustInformation(pipes_struct *p,
+ struct netr_DsRGetForestTrustInformation *r);
+WERROR _netr_GetForestTrustInformation(pipes_struct *p,
+ struct netr_GetForestTrustInformation *r);
+NTSTATUS _netr_LogonSamLogonWithFlags(pipes_struct *p,
+ struct netr_LogonSamLogonWithFlags *r);
+WERROR _netr_NETRSERVERGETTRUSTINFO(pipes_struct *p,
+ struct netr_NETRSERVERGETTRUSTINFO *r);
+
+/* The following definitions come from rpc_server/srv_ntsvcs.c */
+
+void ntsvcs2_get_pipe_fns( struct api_struct **fns, int *n_fns );
+NTSTATUS rpc_ntsvcs2_init(void);
+
+/* The following definitions come from rpc_server/srv_ntsvcs_nt.c */
+
+WERROR _PNP_GetVersion(pipes_struct *p,
+ struct PNP_GetVersion *r);
+WERROR _PNP_GetDeviceListSize(pipes_struct *p,
+ struct PNP_GetDeviceListSize *r);
+WERROR _ntsvcs_get_device_list( pipes_struct *p, NTSVCS_Q_GET_DEVICE_LIST *q_u, NTSVCS_R_GET_DEVICE_LIST *r_u );
+WERROR _ntsvcs_get_device_reg_property( pipes_struct *p, NTSVCS_Q_GET_DEVICE_REG_PROPERTY *q_u, NTSVCS_R_GET_DEVICE_REG_PROPERTY *r_u );
+WERROR _PNP_ValidateDeviceInstance(pipes_struct *p,
+ struct PNP_ValidateDeviceInstance *r);
+WERROR _PNP_GetHwProfInfo(pipes_struct *p,
+ struct PNP_GetHwProfInfo *r);
+WERROR _PNP_HwProfFlags(pipes_struct *p,
+ struct PNP_HwProfFlags *r);
+WERROR _PNP_Disconnect(pipes_struct *p,
+ struct PNP_Disconnect *r);
+WERROR _PNP_Connect(pipes_struct *p,
+ struct PNP_Connect *r);
+WERROR _PNP_GetGlobalState(pipes_struct *p,
+ struct PNP_GetGlobalState *r);
+WERROR _PNP_InitDetection(pipes_struct *p,
+ struct PNP_InitDetection *r);
+WERROR _PNP_ReportLogOn(pipes_struct *p,
+ struct PNP_ReportLogOn *r);
+WERROR _PNP_GetRootDeviceInstance(pipes_struct *p,
+ struct PNP_GetRootDeviceInstance *r);
+WERROR _PNP_GetRelatedDeviceInstance(pipes_struct *p,
+ struct PNP_GetRelatedDeviceInstance *r);
+WERROR _PNP_EnumerateSubKeys(pipes_struct *p,
+ struct PNP_EnumerateSubKeys *r);
+WERROR _PNP_GetDeviceList(pipes_struct *p,
+ struct PNP_GetDeviceList *r);
+WERROR _PNP_GetDepth(pipes_struct *p,
+ struct PNP_GetDepth *r);
+WERROR _PNP_GetDeviceRegProp(pipes_struct *p,
+ struct PNP_GetDeviceRegProp *r);
+WERROR _PNP_SetDeviceRegProp(pipes_struct *p,
+ struct PNP_SetDeviceRegProp *r);
+WERROR _PNP_GetClassInstance(pipes_struct *p,
+ struct PNP_GetClassInstance *r);
+WERROR _PNP_CreateKey(pipes_struct *p,
+ struct PNP_CreateKey *r);
+WERROR _PNP_DeleteRegistryKey(pipes_struct *p,
+ struct PNP_DeleteRegistryKey *r);
+WERROR _PNP_GetClassCount(pipes_struct *p,
+ struct PNP_GetClassCount *r);
+WERROR _PNP_GetClassName(pipes_struct *p,
+ struct PNP_GetClassName *r);
+WERROR _PNP_DeleteClassKey(pipes_struct *p,
+ struct PNP_DeleteClassKey *r);
+WERROR _PNP_GetInterfaceDeviceAlias(pipes_struct *p,
+ struct PNP_GetInterfaceDeviceAlias *r);
+WERROR _PNP_GetInterfaceDeviceList(pipes_struct *p,
+ struct PNP_GetInterfaceDeviceList *r);
+WERROR _PNP_GetInterfaceDeviceListSize(pipes_struct *p,
+ struct PNP_GetInterfaceDeviceListSize *r);
+WERROR _PNP_RegisterDeviceClassAssociation(pipes_struct *p,
+ struct PNP_RegisterDeviceClassAssociation *r);
+WERROR _PNP_UnregisterDeviceClassAssociation(pipes_struct *p,
+ struct PNP_UnregisterDeviceClassAssociation *r);
+WERROR _PNP_GetClassRegProp(pipes_struct *p,
+ struct PNP_GetClassRegProp *r);
+WERROR _PNP_SetClassRegProp(pipes_struct *p,
+ struct PNP_SetClassRegProp *r);
+WERROR _PNP_CreateDevInst(pipes_struct *p,
+ struct PNP_CreateDevInst *r);
+WERROR _PNP_DeviceInstanceAction(pipes_struct *p,
+ struct PNP_DeviceInstanceAction *r);
+WERROR _PNP_GetDeviceStatus(pipes_struct *p,
+ struct PNP_GetDeviceStatus *r);
+WERROR _PNP_SetDeviceProblem(pipes_struct *p,
+ struct PNP_SetDeviceProblem *r);
+WERROR _PNP_DisableDevInst(pipes_struct *p,
+ struct PNP_DisableDevInst *r);
+WERROR _PNP_UninstallDevInst(pipes_struct *p,
+ struct PNP_UninstallDevInst *r);
+WERROR _PNP_AddID(pipes_struct *p,
+ struct PNP_AddID *r);
+WERROR _PNP_RegisterDriver(pipes_struct *p,
+ struct PNP_RegisterDriver *r);
+WERROR _PNP_QueryRemove(pipes_struct *p,
+ struct PNP_QueryRemove *r);
+WERROR _PNP_RequestDeviceEject(pipes_struct *p,
+ struct PNP_RequestDeviceEject *r);
+WERROR _PNP_IsDockStationPresent(pipes_struct *p,
+ struct PNP_IsDockStationPresent *r);
+WERROR _PNP_RequestEjectPC(pipes_struct *p,
+ struct PNP_RequestEjectPC *r);
+WERROR _PNP_AddEmptyLogConf(pipes_struct *p,
+ struct PNP_AddEmptyLogConf *r);
+WERROR _PNP_FreeLogConf(pipes_struct *p,
+ struct PNP_FreeLogConf *r);
+WERROR _PNP_GetFirstLogConf(pipes_struct *p,
+ struct PNP_GetFirstLogConf *r);
+WERROR _PNP_GetNextLogConf(pipes_struct *p,
+ struct PNP_GetNextLogConf *r);
+WERROR _PNP_GetLogConfPriority(pipes_struct *p,
+ struct PNP_GetLogConfPriority *r);
+WERROR _PNP_AddResDes(pipes_struct *p,
+ struct PNP_AddResDes *r);
+WERROR _PNP_FreeResDes(pipes_struct *p,
+ struct PNP_FreeResDes *r);
+WERROR _PNP_GetNextResDes(pipes_struct *p,
+ struct PNP_GetNextResDes *r);
+WERROR _PNP_GetResDesData(pipes_struct *p,
+ struct PNP_GetResDesData *r);
+WERROR _PNP_GetResDesDataSize(pipes_struct *p,
+ struct PNP_GetResDesDataSize *r);
+WERROR _PNP_ModifyResDes(pipes_struct *p,
+ struct PNP_ModifyResDes *r);
+WERROR _PNP_DetectResourceLimit(pipes_struct *p,
+ struct PNP_DetectResourceLimit *r);
+WERROR _PNP_QueryResConfList(pipes_struct *p,
+ struct PNP_QueryResConfList *r);
+WERROR _PNP_SetHwProf(pipes_struct *p,
+ struct PNP_SetHwProf *r);
+WERROR _PNP_QueryArbitratorFreeData(pipes_struct *p,
+ struct PNP_QueryArbitratorFreeData *r);
+WERROR _PNP_QueryArbitratorFreeSize(pipes_struct *p,
+ struct PNP_QueryArbitratorFreeSize *r);
+WERROR _PNP_RunDetection(pipes_struct *p,
+ struct PNP_RunDetection *r);
+WERROR _PNP_RegisterNotification(pipes_struct *p,
+ struct PNP_RegisterNotification *r);
+WERROR _PNP_UnregisterNotification(pipes_struct *p,
+ struct PNP_UnregisterNotification *r);
+WERROR _PNP_GetCustomDevProp(pipes_struct *p,
+ struct PNP_GetCustomDevProp *r);
+WERROR _PNP_GetVersionInternal(pipes_struct *p,
+ struct PNP_GetVersionInternal *r);
+WERROR _PNP_GetBlockedDriverInfo(pipes_struct *p,
+ struct PNP_GetBlockedDriverInfo *r);
+WERROR _PNP_GetServerSideDeviceInstallFlags(pipes_struct *p,
+ struct PNP_GetServerSideDeviceInstallFlags *r);
+
+/* The following definitions come from rpc_server/srv_pipe.c */
+
+bool create_next_pdu(pipes_struct *p);
+bool api_pipe_bind_auth3(pipes_struct *p, prs_struct *rpc_in_p);
+bool setup_fault_pdu(pipes_struct *p, NTSTATUS status);
+bool setup_cancel_ack_reply(pipes_struct *p, prs_struct *rpc_in_p);
+bool check_bind_req(struct pipes_struct *p, RPC_IFACE* abstract,
+ RPC_IFACE* transfer, uint32 context_id);
+NTSTATUS rpc_pipe_register_commands(int version, const char *clnt,
+ const char *srv,
+ const struct ndr_syntax_id *interface,
+ const struct api_struct *cmds, int size);
+bool is_known_pipename(const char *cli_filename);
+bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p);
+bool api_pipe_alter_context(pipes_struct *p, prs_struct *rpc_in_p);
+bool api_pipe_ntlmssp_auth_process(pipes_struct *p, prs_struct *rpc_in,
+ uint32 *p_ss_padding_len, NTSTATUS *pstatus);
+bool api_pipe_schannel_process(pipes_struct *p, prs_struct *rpc_in, uint32 *p_ss_padding_len);
+struct current_user *get_current_user(struct current_user *user, pipes_struct *p);
+void free_pipe_rpc_context( PIPE_RPC_FNS *list );
+bool api_pipe_request(pipes_struct *p);
+
+/* The following definitions come from rpc_server/srv_pipe_hnd.c */
+
+pipes_struct *get_first_internal_pipe(void);
+pipes_struct *get_next_internal_pipe(pipes_struct *p);
+void set_pipe_handle_offset(int max_open_files);
+void reset_chain_p(void);
+void init_rpc_pipe_hnd(void);
+smb_np_struct *open_rpc_pipe_p(const char *pipe_name,
+ connection_struct *conn, uint16 vuid);
+ssize_t write_to_pipe(smb_np_struct *p, char *data, size_t n);
+ssize_t read_from_pipe(smb_np_struct *p, char *data, size_t n,
+ bool *is_data_outstanding);
+bool wait_rpc_pipe_hnd_state(smb_np_struct *p, uint16 priority);
+bool set_rpc_pipe_hnd_state(smb_np_struct *p, uint16 device_state);
+bool close_rpc_pipe_hnd(smb_np_struct *p);
+void pipe_close_conn(connection_struct *conn);
+smb_np_struct *get_rpc_pipe_p(uint16 pnum);
+smb_np_struct *get_rpc_pipe(int pnum);
+struct pipes_struct *make_internal_rpc_pipe_p(const char *pipe_name,
+ const char *client_address,
+ struct auth_serversupplied_info *server_info,
+ uint16_t vuid);
+ssize_t read_from_internal_pipe(struct pipes_struct *p, char *data, size_t n,
+ bool *is_data_outstanding);
+ssize_t write_to_internal_pipe(struct pipes_struct *p, char *data, size_t n);
+
+/* The following definitions come from rpc_server/srv_samr_nt.c */
+
+NTSTATUS _samr_Close(pipes_struct *p, struct samr_Close *r);
+NTSTATUS _samr_OpenDomain(pipes_struct *p,
+ struct samr_OpenDomain *r);
+NTSTATUS _samr_GetUserPwInfo(pipes_struct *p,
+ struct samr_GetUserPwInfo *r);
+NTSTATUS _samr_SetSecurity(pipes_struct *p,
+ struct samr_SetSecurity *r);
+NTSTATUS _samr_QuerySecurity(pipes_struct *p,
+ struct samr_QuerySecurity *r);
+NTSTATUS _samr_EnumDomainUsers(pipes_struct *p,
+ struct samr_EnumDomainUsers *r);
+NTSTATUS _samr_EnumDomainGroups(pipes_struct *p,
+ struct samr_EnumDomainGroups *r);
+NTSTATUS _samr_EnumDomainAliases(pipes_struct *p,
+ struct samr_EnumDomainAliases *r);
+NTSTATUS _samr_QueryDisplayInfo(pipes_struct *p,
+ struct samr_QueryDisplayInfo *r);
+NTSTATUS _samr_QueryDisplayInfo2(pipes_struct *p,
+ struct samr_QueryDisplayInfo2 *r);
+NTSTATUS _samr_QueryDisplayInfo3(pipes_struct *p,
+ struct samr_QueryDisplayInfo3 *r);
+NTSTATUS _samr_QueryAliasInfo(pipes_struct *p,
+ struct samr_QueryAliasInfo *r);
+NTSTATUS _samr_LookupNames(pipes_struct *p,
+ struct samr_LookupNames *r);
+NTSTATUS _samr_ChangePasswordUser2(pipes_struct *p,
+ struct samr_ChangePasswordUser2 *r);
+NTSTATUS _samr_ChangePasswordUser3(pipes_struct *p,
+ struct samr_ChangePasswordUser3 *r);
+NTSTATUS _samr_LookupRids(pipes_struct *p,
+ struct samr_LookupRids *r);
+NTSTATUS _samr_OpenUser(pipes_struct *p,
+ struct samr_OpenUser *r);
+NTSTATUS _samr_QueryUserInfo(pipes_struct *p,
+ struct samr_QueryUserInfo *r);
+NTSTATUS _samr_GetGroupsForUser(pipes_struct *p,
+ struct samr_GetGroupsForUser *r);
+NTSTATUS _samr_QueryDomainInfo(pipes_struct *p,
+ struct samr_QueryDomainInfo *r);
+NTSTATUS _samr_CreateUser2(pipes_struct *p,
+ struct samr_CreateUser2 *r);
+NTSTATUS _samr_Connect(pipes_struct *p,
+ struct samr_Connect *r);
+NTSTATUS _samr_Connect2(pipes_struct *p,
+ struct samr_Connect2 *r);
+NTSTATUS _samr_Connect4(pipes_struct *p,
+ struct samr_Connect4 *r);
+NTSTATUS _samr_Connect5(pipes_struct *p,
+ struct samr_Connect5 *r);
+NTSTATUS _samr_LookupDomain(pipes_struct *p,
+ struct samr_LookupDomain *r);
+NTSTATUS _samr_EnumDomains(pipes_struct *p,
+ struct samr_EnumDomains *r);
+NTSTATUS _samr_OpenAlias(pipes_struct *p,
+ struct samr_OpenAlias *r);
+NTSTATUS _samr_SetUserInfo(pipes_struct *p,
+ struct samr_SetUserInfo *r);
+NTSTATUS _samr_SetUserInfo2(pipes_struct *p,
+ struct samr_SetUserInfo2 *r);
+NTSTATUS _samr_GetAliasMembership(pipes_struct *p,
+ struct samr_GetAliasMembership *r);
+NTSTATUS _samr_GetMembersInAlias(pipes_struct *p,
+ struct samr_GetMembersInAlias *r);
+NTSTATUS _samr_QueryGroupMember(pipes_struct *p,
+ struct samr_QueryGroupMember *r);
+NTSTATUS _samr_AddAliasMember(pipes_struct *p,
+ struct samr_AddAliasMember *r);
+NTSTATUS _samr_DeleteAliasMember(pipes_struct *p,
+ struct samr_DeleteAliasMember *r);
+NTSTATUS _samr_AddGroupMember(pipes_struct *p,
+ struct samr_AddGroupMember *r);
+NTSTATUS _samr_DeleteGroupMember(pipes_struct *p,
+ struct samr_DeleteGroupMember *r);
+NTSTATUS _samr_DeleteUser(pipes_struct *p,
+ struct samr_DeleteUser *r);
+NTSTATUS _samr_DeleteDomainGroup(pipes_struct *p,
+ struct samr_DeleteDomainGroup *r);
+NTSTATUS _samr_DeleteDomAlias(pipes_struct *p,
+ struct samr_DeleteDomAlias *r);
+NTSTATUS _samr_CreateDomainGroup(pipes_struct *p,
+ struct samr_CreateDomainGroup *r);
+NTSTATUS _samr_CreateDomAlias(pipes_struct *p,
+ struct samr_CreateDomAlias *r);
+NTSTATUS _samr_QueryGroupInfo(pipes_struct *p,
+ struct samr_QueryGroupInfo *r);
+NTSTATUS _samr_SetGroupInfo(pipes_struct *p,
+ struct samr_SetGroupInfo *r);
+NTSTATUS _samr_SetAliasInfo(pipes_struct *p,
+ struct samr_SetAliasInfo *r);
+NTSTATUS _samr_GetDomPwInfo(pipes_struct *p,
+ struct samr_GetDomPwInfo *r);
+NTSTATUS _samr_OpenGroup(pipes_struct *p,
+ struct samr_OpenGroup *r);
+NTSTATUS _samr_RemoveMemberFromForeignDomain(pipes_struct *p,
+ struct samr_RemoveMemberFromForeignDomain *r);
+NTSTATUS _samr_QueryDomainInfo2(pipes_struct *p,
+ struct samr_QueryDomainInfo2 *r);
+NTSTATUS _samr_SetDomainInfo(pipes_struct *p,
+ struct samr_SetDomainInfo *r);
+NTSTATUS _samr_GetDisplayEnumerationIndex(pipes_struct *p,
+ struct samr_GetDisplayEnumerationIndex *r);
+NTSTATUS _samr_GetDisplayEnumerationIndex2(pipes_struct *p,
+ struct samr_GetDisplayEnumerationIndex2 *r);
+NTSTATUS _samr_Shutdown(pipes_struct *p,
+ struct samr_Shutdown *r);
+NTSTATUS _samr_CreateUser(pipes_struct *p,
+ struct samr_CreateUser *r);
+NTSTATUS _samr_SetMemberAttributesOfGroup(pipes_struct *p,
+ struct samr_SetMemberAttributesOfGroup *r);
+NTSTATUS _samr_ChangePasswordUser(pipes_struct *p,
+ struct samr_ChangePasswordUser *r);
+NTSTATUS _samr_TestPrivateFunctionsDomain(pipes_struct *p,
+ struct samr_TestPrivateFunctionsDomain *r);
+NTSTATUS _samr_TestPrivateFunctionsUser(pipes_struct *p,
+ struct samr_TestPrivateFunctionsUser *r);
+NTSTATUS _samr_QueryUserInfo2(pipes_struct *p,
+ struct samr_QueryUserInfo2 *r);
+NTSTATUS _samr_AddMultipleMembersToAlias(pipes_struct *p,
+ struct samr_AddMultipleMembersToAlias *r);
+NTSTATUS _samr_RemoveMultipleMembersFromAlias(pipes_struct *p,
+ struct samr_RemoveMultipleMembersFromAlias *r);
+NTSTATUS _samr_OemChangePasswordUser2(pipes_struct *p,
+ struct samr_OemChangePasswordUser2 *r);
+NTSTATUS _samr_SetBootKeyInformation(pipes_struct *p,
+ struct samr_SetBootKeyInformation *r);
+NTSTATUS _samr_GetBootKeyInformation(pipes_struct *p,
+ struct samr_GetBootKeyInformation *r);
+NTSTATUS _samr_Connect3(pipes_struct *p,
+ struct samr_Connect3 *r);
+NTSTATUS _samr_RidToSid(pipes_struct *p,
+ struct samr_RidToSid *r);
+NTSTATUS _samr_SetDsrmPassword(pipes_struct *p,
+ struct samr_SetDsrmPassword *r);
+NTSTATUS _samr_ValidatePassword(pipes_struct *p,
+ struct samr_ValidatePassword *r);
+
+/* The following definitions come from rpc_server/srv_samr_util.c */
+
+void copy_id20_to_sam_passwd(struct samu *to,
+ struct samr_UserInfo20 *from);
+void copy_id21_to_sam_passwd(const char *log_prefix,
+ struct samu *to,
+ struct samr_UserInfo21 *from);
+void copy_id23_to_sam_passwd(struct samu *to,
+ struct samr_UserInfo23 *from);
+void copy_id25_to_sam_passwd(struct samu *to,
+ struct samr_UserInfo25 *from);
+
+/* The following definitions come from rpc_server/srv_spoolss.c */
+
+void spoolss_get_pipe_fns( struct api_struct **fns, int *n_fns );
+NTSTATUS rpc_spoolss_init(void);
+
+/* The following definitions come from rpc_server/srv_spoolss_nt.c */
+
+WERROR delete_printer_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, const char *sharename );
+void do_drv_upgrade_printer(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data);
+void update_monitored_printq_cache( void );
+void reset_all_printerdata(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data);
+WERROR _spoolss_open_printer(pipes_struct *p, SPOOL_Q_OPEN_PRINTER *q_u, SPOOL_R_OPEN_PRINTER *r_u);
+WERROR _spoolss_open_printer_ex( pipes_struct *p, SPOOL_Q_OPEN_PRINTER_EX *q_u, SPOOL_R_OPEN_PRINTER_EX *r_u);
+bool convert_devicemode(const char *printername, const DEVICEMODE *devmode,
+ NT_DEVICEMODE **pp_nt_devmode);
+WERROR _spoolss_closeprinter(pipes_struct *p, SPOOL_Q_CLOSEPRINTER *q_u, SPOOL_R_CLOSEPRINTER *r_u);
+WERROR _spoolss_deleteprinter(pipes_struct *p, SPOOL_Q_DELETEPRINTER *q_u, SPOOL_R_DELETEPRINTER *r_u);
+WERROR _spoolss_deleteprinterdriver(pipes_struct *p, SPOOL_Q_DELETEPRINTERDRIVER *q_u, SPOOL_R_DELETEPRINTERDRIVER *r_u);
+WERROR _spoolss_deleteprinterdriverex(pipes_struct *p, SPOOL_Q_DELETEPRINTERDRIVEREX *q_u, SPOOL_R_DELETEPRINTERDRIVEREX *r_u);
+WERROR set_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, const char *key, const char *value,
+ uint32 type, uint8 *data, int real_len );
+WERROR _spoolss_getprinterdata(pipes_struct *p, SPOOL_Q_GETPRINTERDATA *q_u, SPOOL_R_GETPRINTERDATA *r_u);
+WERROR _spoolss_rffpcnex(pipes_struct *p, SPOOL_Q_RFFPCNEX *q_u, SPOOL_R_RFFPCNEX *r_u);
+void spoolss_notify_server_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx);
+void spoolss_notify_printer_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx);
+void spoolss_notify_share_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx);
+void spoolss_notify_port_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx);
+void spoolss_notify_driver_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx);
+void spoolss_notify_comment(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx);
+void spoolss_notify_location(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx);
+void spoolss_notify_sepfile(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx);
+void spoolss_notify_print_processor(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx);
+void spoolss_notify_parameters(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx);
+void spoolss_notify_datatype(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx);
+void spoolss_notify_attributes(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx);
+void spoolss_notify_cjobs(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx);
+void construct_info_data(SPOOL_NOTIFY_INFO_DATA *info_data, uint16 type, uint16 field, int id);
+WERROR _spoolss_rfnpcnex( pipes_struct *p, SPOOL_Q_RFNPCNEX *q_u, SPOOL_R_RFNPCNEX *r_u);
+DEVICEMODE *construct_dev_mode(const char *servicename);
+WERROR _spoolss_enumprinters( pipes_struct *p, SPOOL_Q_ENUMPRINTERS *q_u, SPOOL_R_ENUMPRINTERS *r_u);
+WERROR _spoolss_getprinter(pipes_struct *p, SPOOL_Q_GETPRINTER *q_u, SPOOL_R_GETPRINTER *r_u);
+WERROR _spoolss_getprinterdriver2(pipes_struct *p, SPOOL_Q_GETPRINTERDRIVER2 *q_u, SPOOL_R_GETPRINTERDRIVER2 *r_u);
+WERROR _spoolss_startpageprinter(pipes_struct *p, SPOOL_Q_STARTPAGEPRINTER *q_u, SPOOL_R_STARTPAGEPRINTER *r_u);
+WERROR _spoolss_endpageprinter(pipes_struct *p, SPOOL_Q_ENDPAGEPRINTER *q_u, SPOOL_R_ENDPAGEPRINTER *r_u);
+WERROR _spoolss_startdocprinter(pipes_struct *p, SPOOL_Q_STARTDOCPRINTER *q_u, SPOOL_R_STARTDOCPRINTER *r_u);
+WERROR _spoolss_enddocprinter(pipes_struct *p, SPOOL_Q_ENDDOCPRINTER *q_u, SPOOL_R_ENDDOCPRINTER *r_u);
+WERROR _spoolss_writeprinter(pipes_struct *p, SPOOL_Q_WRITEPRINTER *q_u, SPOOL_R_WRITEPRINTER *r_u);
+WERROR _spoolss_abortprinter(pipes_struct *p, SPOOL_Q_ABORTPRINTER *q_u, SPOOL_R_ABORTPRINTER *r_u);
+WERROR add_port_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, const char *portname, const char *uri );
+bool add_printer_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, NT_PRINTER_INFO_LEVEL *printer);
+WERROR _spoolss_setprinter(pipes_struct *p, SPOOL_Q_SETPRINTER *q_u, SPOOL_R_SETPRINTER *r_u);
+WERROR _spoolss_fcpn(pipes_struct *p, SPOOL_Q_FCPN *q_u, SPOOL_R_FCPN *r_u);
+WERROR _spoolss_addjob(pipes_struct *p, SPOOL_Q_ADDJOB *q_u, SPOOL_R_ADDJOB *r_u);
+WERROR _spoolss_enumjobs( pipes_struct *p, SPOOL_Q_ENUMJOBS *q_u, SPOOL_R_ENUMJOBS *r_u);
+WERROR _spoolss_schedulejob( pipes_struct *p, SPOOL_Q_SCHEDULEJOB *q_u, SPOOL_R_SCHEDULEJOB *r_u);
+WERROR _spoolss_setjob(pipes_struct *p, SPOOL_Q_SETJOB *q_u, SPOOL_R_SETJOB *r_u);
+WERROR _spoolss_enumprinterdrivers( pipes_struct *p, SPOOL_Q_ENUMPRINTERDRIVERS *q_u, SPOOL_R_ENUMPRINTERDRIVERS *r_u);
+WERROR _spoolss_enumforms(pipes_struct *p, SPOOL_Q_ENUMFORMS *q_u, SPOOL_R_ENUMFORMS *r_u);
+WERROR _spoolss_getform(pipes_struct *p, SPOOL_Q_GETFORM *q_u, SPOOL_R_GETFORM *r_u);
+WERROR enumports_hook(TALLOC_CTX *ctx, int *count, char ***lines );
+WERROR _spoolss_enumports( pipes_struct *p, SPOOL_Q_ENUMPORTS *q_u, SPOOL_R_ENUMPORTS *r_u);
+WERROR _spoolss_addprinterex( pipes_struct *p, SPOOL_Q_ADDPRINTEREX *q_u, SPOOL_R_ADDPRINTEREX *r_u);
+WERROR _spoolss_addprinterdriver(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVER *q_u, SPOOL_R_ADDPRINTERDRIVER *r_u);
+WERROR _spoolss_addprinterdriverex(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVEREX *q_u, SPOOL_R_ADDPRINTERDRIVEREX *r_u);
+WERROR _spoolss_getprinterdriverdirectory(pipes_struct *p, SPOOL_Q_GETPRINTERDRIVERDIR *q_u, SPOOL_R_GETPRINTERDRIVERDIR *r_u);
+WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, SPOOL_R_ENUMPRINTERDATA *r_u);
+WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SPOOL_R_SETPRINTERDATA *r_u);
+WERROR _spoolss_resetprinter(pipes_struct *p, SPOOL_Q_RESETPRINTER *q_u, SPOOL_R_RESETPRINTER *r_u);
+WERROR _spoolss_deleteprinterdata(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATA *q_u, SPOOL_R_DELETEPRINTERDATA *r_u);
+WERROR _spoolss_addform( pipes_struct *p, SPOOL_Q_ADDFORM *q_u, SPOOL_R_ADDFORM *r_u);
+WERROR _spoolss_deleteform( pipes_struct *p, SPOOL_Q_DELETEFORM *q_u, SPOOL_R_DELETEFORM *r_u);
+WERROR _spoolss_setform(pipes_struct *p, SPOOL_Q_SETFORM *q_u, SPOOL_R_SETFORM *r_u);
+WERROR _spoolss_enumprintprocessors(pipes_struct *p, SPOOL_Q_ENUMPRINTPROCESSORS *q_u, SPOOL_R_ENUMPRINTPROCESSORS *r_u);
+WERROR _spoolss_enumprintprocdatatypes(pipes_struct *p, SPOOL_Q_ENUMPRINTPROCDATATYPES *q_u, SPOOL_R_ENUMPRINTPROCDATATYPES *r_u);
+WERROR _spoolss_enumprintmonitors(pipes_struct *p, SPOOL_Q_ENUMPRINTMONITORS *q_u, SPOOL_R_ENUMPRINTMONITORS *r_u);
+WERROR _spoolss_getjob( pipes_struct *p, SPOOL_Q_GETJOB *q_u, SPOOL_R_GETJOB *r_u);
+WERROR _spoolss_getprinterdataex(pipes_struct *p, SPOOL_Q_GETPRINTERDATAEX *q_u, SPOOL_R_GETPRINTERDATAEX *r_u);
+WERROR _spoolss_setprinterdataex(pipes_struct *p, SPOOL_Q_SETPRINTERDATAEX *q_u, SPOOL_R_SETPRINTERDATAEX *r_u);
+WERROR _spoolss_deleteprinterdataex(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATAEX *q_u, SPOOL_R_DELETEPRINTERDATAEX *r_u);
+WERROR _spoolss_enumprinterkey(pipes_struct *p, SPOOL_Q_ENUMPRINTERKEY *q_u, SPOOL_R_ENUMPRINTERKEY *r_u);
+WERROR _spoolss_deleteprinterkey(pipes_struct *p, SPOOL_Q_DELETEPRINTERKEY *q_u, SPOOL_R_DELETEPRINTERKEY *r_u);
+WERROR _spoolss_enumprinterdataex(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATAEX *q_u, SPOOL_R_ENUMPRINTERDATAEX *r_u);
+WERROR _spoolss_getprintprocessordirectory(pipes_struct *p, SPOOL_Q_GETPRINTPROCESSORDIRECTORY *q_u, SPOOL_R_GETPRINTPROCESSORDIRECTORY *r_u);
+WERROR _spoolss_xcvdataport(pipes_struct *p, SPOOL_Q_XCVDATAPORT *q_u, SPOOL_R_XCVDATAPORT *r_u);
+
+/* The following definitions come from rpc_server/srv_srvsvc_nt.c */
+
+WERROR _srvsvc_NetFileEnum(pipes_struct *p,
+ struct srvsvc_NetFileEnum *r);
+WERROR _srvsvc_NetSrvGetInfo(pipes_struct *p,
+ struct srvsvc_NetSrvGetInfo *r);
+WERROR _srvsvc_NetSrvSetInfo(pipes_struct *p,
+ struct srvsvc_NetSrvSetInfo *r);
+WERROR _srvsvc_NetConnEnum(pipes_struct *p,
+ struct srvsvc_NetConnEnum *r);
+WERROR _srvsvc_NetSessEnum(pipes_struct *p,
+ struct srvsvc_NetSessEnum *r);
+WERROR _srvsvc_NetSessDel(pipes_struct *p,
+ struct srvsvc_NetSessDel *r);
+WERROR _srvsvc_NetShareEnumAll(pipes_struct *p,
+ struct srvsvc_NetShareEnumAll *r);
+WERROR _srvsvc_NetShareEnum(pipes_struct *p,
+ struct srvsvc_NetShareEnum *r);
+WERROR _srvsvc_NetShareGetInfo(pipes_struct *p,
+ struct srvsvc_NetShareGetInfo *r);
+char *valid_share_pathname(TALLOC_CTX *ctx, const char *dos_pathname);
+WERROR _srvsvc_NetShareSetInfo(pipes_struct *p,
+ struct srvsvc_NetShareSetInfo *r);
+WERROR _srvsvc_NetShareAdd(pipes_struct *p,
+ struct srvsvc_NetShareAdd *r);
+WERROR _srvsvc_NetShareDel(pipes_struct *p,
+ struct srvsvc_NetShareDel *r);
+WERROR _srvsvc_NetShareDelSticky(pipes_struct *p,
+ struct srvsvc_NetShareDelSticky *r);
+WERROR _srvsvc_NetRemoteTOD(pipes_struct *p,
+ struct srvsvc_NetRemoteTOD *r);
+WERROR _srvsvc_NetGetFileSecurity(pipes_struct *p,
+ struct srvsvc_NetGetFileSecurity *r);
+WERROR _srvsvc_NetSetFileSecurity(pipes_struct *p,
+ struct srvsvc_NetSetFileSecurity *r);
+WERROR _srvsvc_NetDiskEnum(pipes_struct *p,
+ struct srvsvc_NetDiskEnum *r);
+WERROR _srvsvc_NetNameValidate(pipes_struct *p,
+ struct srvsvc_NetNameValidate *r);
+WERROR _srvsvc_NetFileClose(pipes_struct *p, struct srvsvc_NetFileClose *r);
+WERROR _srvsvc_NetCharDevEnum(pipes_struct *p, struct srvsvc_NetCharDevEnum *r);
+WERROR _srvsvc_NetCharDevGetInfo(pipes_struct *p, struct srvsvc_NetCharDevGetInfo *r);
+WERROR _srvsvc_NetCharDevControl(pipes_struct *p, struct srvsvc_NetCharDevControl *r);
+WERROR _srvsvc_NetCharDevQEnum(pipes_struct *p, struct srvsvc_NetCharDevQEnum *r);
+WERROR _srvsvc_NetCharDevQGetInfo(pipes_struct *p, struct srvsvc_NetCharDevQGetInfo *r);
+WERROR _srvsvc_NetCharDevQSetInfo(pipes_struct *p, struct srvsvc_NetCharDevQSetInfo *r);
+WERROR _srvsvc_NetCharDevQPurge(pipes_struct *p, struct srvsvc_NetCharDevQPurge *r);
+WERROR _srvsvc_NetCharDevQPurgeSelf(pipes_struct *p, struct srvsvc_NetCharDevQPurgeSelf *r);
+WERROR _srvsvc_NetFileGetInfo(pipes_struct *p, struct srvsvc_NetFileGetInfo *r);
+WERROR _srvsvc_NetShareCheck(pipes_struct *p, struct srvsvc_NetShareCheck *r);
+WERROR _srvsvc_NetServerStatisticsGet(pipes_struct *p, struct srvsvc_NetServerStatisticsGet *r);
+WERROR _srvsvc_NetTransportAdd(pipes_struct *p, struct srvsvc_NetTransportAdd *r);
+WERROR _srvsvc_NetTransportEnum(pipes_struct *p, struct srvsvc_NetTransportEnum *r);
+WERROR _srvsvc_NetTransportDel(pipes_struct *p, struct srvsvc_NetTransportDel *r);
+WERROR _srvsvc_NetSetServiceBits(pipes_struct *p, struct srvsvc_NetSetServiceBits *r);
+WERROR _srvsvc_NetPathType(pipes_struct *p, struct srvsvc_NetPathType *r);
+WERROR _srvsvc_NetPathCanonicalize(pipes_struct *p, struct srvsvc_NetPathCanonicalize *r);
+WERROR _srvsvc_NetPathCompare(pipes_struct *p, struct srvsvc_NetPathCompare *r);
+WERROR _srvsvc_NETRPRNAMECANONICALIZE(pipes_struct *p, struct srvsvc_NETRPRNAMECANONICALIZE *r);
+WERROR _srvsvc_NetPRNameCompare(pipes_struct *p, struct srvsvc_NetPRNameCompare *r);
+WERROR _srvsvc_NetShareDelStart(pipes_struct *p, struct srvsvc_NetShareDelStart *r);
+WERROR _srvsvc_NetShareDelCommit(pipes_struct *p, struct srvsvc_NetShareDelCommit *r);
+WERROR _srvsvc_NetServerTransportAddEx(pipes_struct *p, struct srvsvc_NetServerTransportAddEx *r);
+WERROR _srvsvc_NetServerSetServiceBitsEx(pipes_struct *p, struct srvsvc_NetServerSetServiceBitsEx *r);
+WERROR _srvsvc_NETRDFSGETVERSION(pipes_struct *p, struct srvsvc_NETRDFSGETVERSION *r);
+WERROR _srvsvc_NETRDFSCREATELOCALPARTITION(pipes_struct *p, struct srvsvc_NETRDFSCREATELOCALPARTITION *r);
+WERROR _srvsvc_NETRDFSDELETELOCALPARTITION(pipes_struct *p, struct srvsvc_NETRDFSDELETELOCALPARTITION *r);
+WERROR _srvsvc_NETRDFSSETLOCALVOLUMESTATE(pipes_struct *p, struct srvsvc_NETRDFSSETLOCALVOLUMESTATE *r);
+WERROR _srvsvc_NETRDFSSETSERVERINFO(pipes_struct *p, struct srvsvc_NETRDFSSETSERVERINFO *r);
+WERROR _srvsvc_NETRDFSCREATEEXITPOINT(pipes_struct *p, struct srvsvc_NETRDFSCREATEEXITPOINT *r);
+WERROR _srvsvc_NETRDFSDELETEEXITPOINT(pipes_struct *p, struct srvsvc_NETRDFSDELETEEXITPOINT *r);
+WERROR _srvsvc_NETRDFSMODIFYPREFIX(pipes_struct *p, struct srvsvc_NETRDFSMODIFYPREFIX *r);
+WERROR _srvsvc_NETRDFSFIXLOCALVOLUME(pipes_struct *p, struct srvsvc_NETRDFSFIXLOCALVOLUME *r);
+WERROR _srvsvc_NETRDFSMANAGERREPORTSITEINFO(pipes_struct *p, struct srvsvc_NETRDFSMANAGERREPORTSITEINFO *r);
+WERROR _srvsvc_NETRSERVERTRANSPORTDELEX(pipes_struct *p, struct srvsvc_NETRSERVERTRANSPORTDELEX *r);
+
+/* The following definitions come from rpc_server/srv_svcctl.c */
+
+void svcctl2_get_pipe_fns( struct api_struct **fns, int *n_fns );
+NTSTATUS rpc_svcctl2_init(void);
+
+/* The following definitions come from rpc_server/srv_svcctl_nt.c */
+
+bool init_service_op_table( void );
+WERROR _svcctl_OpenSCManagerW(pipes_struct *p,
+ struct svcctl_OpenSCManagerW *r);
+WERROR _svcctl_OpenServiceW(pipes_struct *p,
+ struct svcctl_OpenServiceW *r);
+WERROR _svcctl_CloseServiceHandle(pipes_struct *p, struct svcctl_CloseServiceHandle *r);
+WERROR _svcctl_GetServiceDisplayNameW(pipes_struct *p,
+ struct svcctl_GetServiceDisplayNameW *r);
+WERROR _svcctl_QueryServiceStatus(pipes_struct *p,
+ struct svcctl_QueryServiceStatus *r);
+WERROR _svcctl_enum_services_status(pipes_struct *p, SVCCTL_Q_ENUM_SERVICES_STATUS *q_u, SVCCTL_R_ENUM_SERVICES_STATUS *r_u);
+WERROR _svcctl_StartServiceW(pipes_struct *p,
+ struct svcctl_StartServiceW *r);
+WERROR _svcctl_ControlService(pipes_struct *p,
+ struct svcctl_ControlService *r);
+WERROR _svcctl_EnumDependentServicesW(pipes_struct *p,
+ struct svcctl_EnumDependentServicesW *r);
+WERROR _svcctl_query_service_status_ex( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_STATUSEX *q_u, SVCCTL_R_QUERY_SERVICE_STATUSEX *r_u );
+WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG *r_u );
+WERROR _svcctl_query_service_config2( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG2 *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG2 *r_u );
+WERROR _svcctl_LockServiceDatabase(pipes_struct *p,
+ struct svcctl_LockServiceDatabase *r);
+WERROR _svcctl_UnlockServiceDatabase(pipes_struct *p,
+ struct svcctl_UnlockServiceDatabase *r);
+WERROR _svcctl_QueryServiceObjectSecurity(pipes_struct *p,
+ struct svcctl_QueryServiceObjectSecurity *r);
+WERROR _svcctl_SetServiceObjectSecurity(pipes_struct *p,
+ struct svcctl_SetServiceObjectSecurity *r);
+WERROR _svcctl_DeleteService(pipes_struct *p, struct svcctl_DeleteService *r);
+WERROR _svcctl_SetServiceStatus(pipes_struct *p, struct svcctl_SetServiceStatus *r);
+WERROR _svcctl_NotifyBootConfigStatus(pipes_struct *p, struct svcctl_NotifyBootConfigStatus *r);
+WERROR _svcctl_SCSetServiceBitsW(pipes_struct *p, struct svcctl_SCSetServiceBitsW *r);
+WERROR _svcctl_ChangeServiceConfigW(pipes_struct *p, struct svcctl_ChangeServiceConfigW *r);
+WERROR _svcctl_CreateServiceW(pipes_struct *p, struct svcctl_CreateServiceW *r);
+WERROR _svcctl_EnumServicesStatusW(pipes_struct *p, struct svcctl_EnumServicesStatusW *r);
+WERROR _svcctl_QueryServiceConfigW(pipes_struct *p, struct svcctl_QueryServiceConfigW *r);
+WERROR _svcctl_QueryServiceLockStatusW(pipes_struct *p, struct svcctl_QueryServiceLockStatusW *r);
+WERROR _svcctl_GetServiceKeyNameW(pipes_struct *p, struct svcctl_GetServiceKeyNameW *r);
+WERROR _svcctl_SCSetServiceBitsA(pipes_struct *p, struct svcctl_SCSetServiceBitsA *r);
+WERROR _svcctl_ChangeServiceConfigA(pipes_struct *p, struct svcctl_ChangeServiceConfigA *r);
+WERROR _svcctl_CreateServiceA(pipes_struct *p, struct svcctl_CreateServiceA *r);
+WERROR _svcctl_EnumDependentServicesA(pipes_struct *p, struct svcctl_EnumDependentServicesA *r);
+WERROR _svcctl_EnumServicesStatusA(pipes_struct *p, struct svcctl_EnumServicesStatusA *r);
+WERROR _svcctl_OpenSCManagerA(pipes_struct *p, struct svcctl_OpenSCManagerA *r);
+WERROR _svcctl_OpenServiceA(pipes_struct *p, struct svcctl_OpenServiceA *r);
+WERROR _svcctl_QueryServiceConfigA(pipes_struct *p, struct svcctl_QueryServiceConfigA *r);
+WERROR _svcctl_QueryServiceLockStatusA(pipes_struct *p, struct svcctl_QueryServiceLockStatusA *r);
+WERROR _svcctl_StartServiceA(pipes_struct *p, struct svcctl_StartServiceA *r);
+WERROR _svcctl_GetServiceDisplayNameA(pipes_struct *p, struct svcctl_GetServiceDisplayNameA *r);
+WERROR _svcctl_GetServiceKeyNameA(pipes_struct *p, struct svcctl_GetServiceKeyNameA *r);
+WERROR _svcctl_GetCurrentGroupeStateW(pipes_struct *p, struct svcctl_GetCurrentGroupeStateW *r);
+WERROR _svcctl_EnumServiceGroupW(pipes_struct *p, struct svcctl_EnumServiceGroupW *r);
+WERROR _svcctl_ChangeServiceConfig2A(pipes_struct *p, struct svcctl_ChangeServiceConfig2A *r);
+WERROR _svcctl_ChangeServiceConfig2W(pipes_struct *p, struct svcctl_ChangeServiceConfig2W *r);
+WERROR _svcctl_QueryServiceConfig2A(pipes_struct *p, struct svcctl_QueryServiceConfig2A *r);
+WERROR _svcctl_QueryServiceConfig2W(pipes_struct *p, struct svcctl_QueryServiceConfig2W *r);
+WERROR _svcctl_QueryServiceStatusEx(pipes_struct *p, struct svcctl_QueryServiceStatusEx *r);
+WERROR _EnumServicesStatusExA(pipes_struct *p, struct EnumServicesStatusExA *r);
+WERROR _EnumServicesStatusExW(pipes_struct *p, struct EnumServicesStatusExW *r);
+WERROR _svcctl_SCSendTSMessage(pipes_struct *p, struct svcctl_SCSendTSMessage *r);
+
+/* The following definitions come from rpc_server/srv_winreg_nt.c */
+
+WERROR _winreg_CloseKey(pipes_struct *p, struct winreg_CloseKey *r);
+WERROR _winreg_OpenHKLM(pipes_struct *p, struct winreg_OpenHKLM *r);
+WERROR _winreg_OpenHKPD(pipes_struct *p, struct winreg_OpenHKPD *r);
+WERROR _winreg_OpenHKPT(pipes_struct *p, struct winreg_OpenHKPT *r);
+WERROR _winreg_OpenHKCR(pipes_struct *p, struct winreg_OpenHKCR *r);
+WERROR _winreg_OpenHKU(pipes_struct *p, struct winreg_OpenHKU *r);
+WERROR _winreg_OpenHKCU(pipes_struct *p, struct winreg_OpenHKCU *r);
+WERROR _winreg_OpenHKCC(pipes_struct *p, struct winreg_OpenHKCC *r);
+WERROR _winreg_OpenHKDD(pipes_struct *p, struct winreg_OpenHKDD *r);
+WERROR _winreg_OpenHKPN(pipes_struct *p, struct winreg_OpenHKPN *r);
+WERROR _winreg_OpenKey(pipes_struct *p, struct winreg_OpenKey *r);
+WERROR _winreg_QueryValue(pipes_struct *p, struct winreg_QueryValue *r);
+WERROR _winreg_QueryInfoKey(pipes_struct *p, struct winreg_QueryInfoKey *r);
+WERROR _winreg_GetVersion(pipes_struct *p, struct winreg_GetVersion *r);
+WERROR _winreg_EnumKey(pipes_struct *p, struct winreg_EnumKey *r);
+WERROR _winreg_EnumValue(pipes_struct *p, struct winreg_EnumValue *r);
+WERROR _winreg_InitiateSystemShutdown(pipes_struct *p, struct winreg_InitiateSystemShutdown *r);
+WERROR _winreg_InitiateSystemShutdownEx(pipes_struct *p, struct winreg_InitiateSystemShutdownEx *r);
+WERROR _winreg_AbortSystemShutdown(pipes_struct *p, struct winreg_AbortSystemShutdown *r);
+WERROR _winreg_RestoreKey(pipes_struct *p, struct winreg_RestoreKey *r);
+WERROR _winreg_SaveKey(pipes_struct *p, struct winreg_SaveKey *r);
+WERROR _winreg_SaveKeyEx(pipes_struct *p, struct winreg_SaveKeyEx *r);
+WERROR _winreg_CreateKey( pipes_struct *p, struct winreg_CreateKey *r);
+WERROR _winreg_SetValue(pipes_struct *p, struct winreg_SetValue *r);
+WERROR _winreg_DeleteKey(pipes_struct *p, struct winreg_DeleteKey *r);
+WERROR _winreg_DeleteValue(pipes_struct *p, struct winreg_DeleteValue *r);
+WERROR _winreg_GetKeySecurity(pipes_struct *p, struct winreg_GetKeySecurity *r);
+WERROR _winreg_SetKeySecurity(pipes_struct *p, struct winreg_SetKeySecurity *r);
+WERROR _winreg_FlushKey(pipes_struct *p, struct winreg_FlushKey *r);
+WERROR _winreg_UnLoadKey(pipes_struct *p, struct winreg_UnLoadKey *r);
+WERROR _winreg_ReplaceKey(pipes_struct *p, struct winreg_ReplaceKey *r);
+WERROR _winreg_LoadKey(pipes_struct *p, struct winreg_LoadKey *r);
+WERROR _winreg_NotifyChangeKeyValue(pipes_struct *p, struct winreg_NotifyChangeKeyValue *r);
+WERROR _winreg_QueryMultipleValues(pipes_struct *p, struct winreg_QueryMultipleValues *r);
+WERROR _winreg_QueryMultipleValues2(pipes_struct *p, struct winreg_QueryMultipleValues2 *r);
+
+/* The following definitions come from rpc_server/srv_wkssvc_nt.c */
+
+WERROR _wkssvc_NetWkstaGetInfo(pipes_struct *p, struct wkssvc_NetWkstaGetInfo *r);
+WERROR _wkssvc_NetWkstaSetInfo(pipes_struct *p, struct wkssvc_NetWkstaSetInfo *r);
+WERROR _wkssvc_NetWkstaEnumUsers(pipes_struct *p, struct wkssvc_NetWkstaEnumUsers *r);
+WERROR _wkssvc_NetrWkstaUserGetInfo(pipes_struct *p, struct wkssvc_NetrWkstaUserGetInfo *r);
+WERROR _wkssvc_NetrWkstaUserSetInfo(pipes_struct *p, struct wkssvc_NetrWkstaUserSetInfo *r);
+WERROR _wkssvc_NetWkstaTransportEnum(pipes_struct *p, struct wkssvc_NetWkstaTransportEnum *r);
+WERROR _wkssvc_NetrWkstaTransportAdd(pipes_struct *p, struct wkssvc_NetrWkstaTransportAdd *r);
+WERROR _wkssvc_NetrWkstaTransportDel(pipes_struct *p, struct wkssvc_NetrWkstaTransportDel *r);
+WERROR _wkssvc_NetrUseAdd(pipes_struct *p, struct wkssvc_NetrUseAdd *r);
+WERROR _wkssvc_NetrUseGetInfo(pipes_struct *p, struct wkssvc_NetrUseGetInfo *r);
+WERROR _wkssvc_NetrUseDel(pipes_struct *p, struct wkssvc_NetrUseDel *r);
+WERROR _wkssvc_NetrUseEnum(pipes_struct *p, struct wkssvc_NetrUseEnum *r);
+WERROR _wkssvc_NetrMessageBufferSend(pipes_struct *p, struct wkssvc_NetrMessageBufferSend *r);
+WERROR _wkssvc_NetrWorkstationStatisticsGet(pipes_struct *p, struct wkssvc_NetrWorkstationStatisticsGet *r) ;
+WERROR _wkssvc_NetrLogonDomainNameAdd(pipes_struct *p, struct wkssvc_NetrLogonDomainNameAdd *r);
+WERROR _wkssvc_NetrLogonDomainNameDel(pipes_struct *p, struct wkssvc_NetrLogonDomainNameDel *r);
+WERROR _wkssvc_NetrJoinDomain(pipes_struct *p, struct wkssvc_NetrJoinDomain *r);
+WERROR _wkssvc_NetrUnjoinDomain(pipes_struct *p, struct wkssvc_NetrUnjoinDomain *r);
+WERROR _wkssvc_NetrRenameMachineInDomain(pipes_struct *p, struct wkssvc_NetrRenameMachineInDomain *r);
+WERROR _wkssvc_NetrValidateName(pipes_struct *p, struct wkssvc_NetrValidateName *r);
+WERROR _wkssvc_NetrGetJoinInformation(pipes_struct *p, struct wkssvc_NetrGetJoinInformation *r);
+WERROR _wkssvc_NetrGetJoinableOus(pipes_struct *p, struct wkssvc_NetrGetJoinableOus *r);
+WERROR _wkssvc_NetrJoinDomain2(pipes_struct *p,
+ struct wkssvc_NetrJoinDomain2 *r);
+WERROR _wkssvc_NetrUnjoinDomain2(pipes_struct *p,
+ struct wkssvc_NetrUnjoinDomain2 *r);
+WERROR _wkssvc_NetrRenameMachineInDomain2(pipes_struct *p, struct wkssvc_NetrRenameMachineInDomain2 *r);
+WERROR _wkssvc_NetrValidateName2(pipes_struct *p, struct wkssvc_NetrValidateName2 *r);
+WERROR _wkssvc_NetrGetJoinableOus2(pipes_struct *p, struct wkssvc_NetrGetJoinableOus2 *r);
+WERROR _wkssvc_NetrAddAlternateComputerName(pipes_struct *p, struct wkssvc_NetrAddAlternateComputerName *r);
+WERROR _wkssvc_NetrRemoveAlternateComputerName(pipes_struct *p, struct wkssvc_NetrRemoveAlternateComputerName *r);
+WERROR _wkssvc_NetrSetPrimaryComputername(pipes_struct *p, struct wkssvc_NetrSetPrimaryComputername *r);
+WERROR _wkssvc_NetrEnumerateComputerNames(pipes_struct *p, struct wkssvc_NetrEnumerateComputerNames *r);
+
+/* The following definitions come from rpcclient/cmd_dfs.c */
+
+
+/* The following definitions come from rpcclient/cmd_dssetup.c */
+
+
+/* The following definitions come from rpcclient/cmd_echo.c */
+
+
+/* The following definitions come from rpcclient/cmd_lsarpc.c */
+
+
+/* The following definitions come from rpcclient/cmd_netlogon.c */
+
+
+/* The following definitions come from rpcclient/cmd_ntsvcs.c */
+
+
+/* The following definitions come from rpcclient/cmd_samr.c */
+
+
+/* The following definitions come from rpcclient/cmd_shutdown.c */
+
+
+/* The following definitions come from rpcclient/cmd_spoolss.c */
+
+void set_drv_info_3_env (DRIVER_INFO_3 *info, const char *arch);
+
+/* The following definitions come from rpcclient/cmd_srvsvc.c */
+
+
+/* The following definitions come from rpcclient/cmd_test.c */
+
+
+/* The following definitions come from rpcclient/cmd_wkssvc.c */
+
+
+/* The following definitions come from rpcclient/rpcclient.c */
+
+
+/* The following definitions come from services/services_db.c */
+
+void svcctl_init_keys( void );
+SEC_DESC *svcctl_get_secdesc( TALLOC_CTX *ctx, const char *name, NT_USER_TOKEN *token );
+bool svcctl_set_secdesc( TALLOC_CTX *ctx, const char *name, SEC_DESC *sec_desc, NT_USER_TOKEN *token );
+const char *svcctl_lookup_dispname(TALLOC_CTX *ctx, const char *name, NT_USER_TOKEN *token );
+const char *svcctl_lookup_description(TALLOC_CTX *ctx, const char *name, NT_USER_TOKEN *token );
+REGVAL_CTR *svcctl_fetch_regvalues( const char *name, NT_USER_TOKEN *token );
+
+/* The following definitions come from services/svc_netlogon.c */
+
+
+/* The following definitions come from services/svc_rcinit.c */
+
+
+/* The following definitions come from services/svc_spoolss.c */
+
+
+/* The following definitions come from services/svc_winreg.c */
+
+
+/* The following definitions come from services/svc_wins.c */
+
+
+/* The following definitions come from smbd/aio.c */
+
+void aio_request_done(uint16_t mid);
+bool aio_finished(void);
+void initialize_async_io_handler(void);
+bool schedule_aio_read_and_X(connection_struct *conn,
+ struct smb_request *req,
+ files_struct *fsp, SMB_OFF_T startpos,
+ size_t smb_maxcnt);
+bool schedule_aio_write_and_X(connection_struct *conn,
+ struct smb_request *req,
+ files_struct *fsp, char *data,
+ SMB_OFF_T startpos,
+ size_t numtowrite);
+int process_aio_queue(void);
+int wait_for_aio_completion(files_struct *fsp);
+void cancel_aio_by_fsp(files_struct *fsp);
+bool aio_finished(void);
+void initialize_async_io_handler(void);
+int process_aio_queue(void);
+bool schedule_aio_read_and_X(connection_struct *conn,
+ struct smb_request *req,
+ files_struct *fsp, SMB_OFF_T startpos,
+ size_t smb_maxcnt);
+bool schedule_aio_write_and_X(connection_struct *conn,
+ struct smb_request *req,
+ files_struct *fsp, char *data,
+ SMB_OFF_T startpos,
+ size_t numtowrite);
+void cancel_aio_by_fsp(files_struct *fsp);
+int wait_for_aio_completion(files_struct *fsp);
+
+/* The following definitions come from smbd/blocking.c */
+
+bool push_blocking_lock_request( struct byte_range_lock *br_lck,
+ const struct smb_request *req,
+ files_struct *fsp,
+ int lock_timeout,
+ int lock_num,
+ uint32 lock_pid,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ SMB_BIG_UINT offset,
+ SMB_BIG_UINT count,
+ uint32 blocking_pid);
+void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck);
+void remove_pending_lock_requests_by_mid(int mid);
+bool blocking_lock_was_deferred(int mid);
+bool blocking_lock_cancel(files_struct *fsp,
+ uint32 lock_pid,
+ SMB_BIG_UINT offset,
+ SMB_BIG_UINT count,
+ enum brl_flavour lock_flav,
+ unsigned char locktype,
+ NTSTATUS err);
+
+/* The following definitions come from smbd/change_trust_pw.c */
+
+NTSTATUS change_trust_account_password( const char *domain, const char *remote_machine);
+
+/* The following definitions come from smbd/chgpasswd.c */
+
+bool chgpasswd(const char *name, const struct passwd *pass,
+ const char *oldpass, const char *newpass, bool as_root);
+bool chgpasswd(const char *name, const struct passwd *pass,
+ const char *oldpass, const char *newpass, bool as_root);
+bool check_lanman_password(char *user, uchar * pass1,
+ uchar * pass2, struct samu **hnd);
+bool change_lanman_password(struct samu *sampass, uchar *pass2);
+NTSTATUS pass_oem_change(char *user,
+ uchar password_encrypted_with_lm_hash[516],
+ const uchar old_lm_hash_encrypted[16],
+ uchar password_encrypted_with_nt_hash[516],
+ const uchar old_nt_hash_encrypted[16],
+ uint32 *reject_reason);
+NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passwd, bool as_root, uint32 *samr_reject_reason);
+
+/* The following definitions come from smbd/close.c */
+
+void set_close_write_time(struct files_struct *fsp, struct timespec ts);
+NTSTATUS close_file(files_struct *fsp, enum file_close_type close_type);
+void msg_close_file(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data);
+
+/* 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(unsigned cnum);
+connection_struct *conn_new(void);
+bool conn_close_all(void);
+bool conn_idle_all(time_t t);
+void conn_clear_vuid_caches(uint16 vuid);
+void conn_free_internal(connection_struct *conn);
+void conn_free(connection_struct *conn);
+void msg_force_tdis(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data);
+
+/* The following definitions come from smbd/connection.c */
+
+bool yield_connection(connection_struct *conn, const char *name);
+int count_current_connections( const char *sharename, bool clear );
+int count_all_current_connections(void);
+bool claim_connection(connection_struct *conn, const char *name,
+ uint32 msg_flags);
+bool register_message_flags(bool doreg, uint32 msg_flags);
+bool store_pipe_opendb( smb_np_struct *p );
+bool delete_pipe_opendb( smb_np_struct *p );
+
+/* The following definitions come from smbd/dfree.c */
+
+SMB_BIG_UINT sys_disk_free(connection_struct *conn, const char *path, bool small_query,
+ SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize);
+SMB_BIG_UINT get_dfree_info(connection_struct *conn,
+ const char *path,
+ bool small_query,
+ SMB_BIG_UINT *bsize,
+ SMB_BIG_UINT *dfree,
+ SMB_BIG_UINT *dsize);
+
+/* The following definitions come from smbd/dir.c */
+
+bool make_dir_struct(TALLOC_CTX *ctx,
+ char *buf,
+ const char *mask,
+ const char *fname,
+ SMB_OFF_T size,
+ uint32 mode,
+ time_t date,
+ bool uc);
+void init_dptrs(void);
+char *dptr_path(int key);
+char *dptr_wcard(int key);
+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,uint16 spid);
+NTSTATUS dptr_create(connection_struct *conn, const char *path, bool old_handle, bool expect_close,uint16 spid,
+ const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret);
+int dptr_CloseDir(struct dptr_struct *dptr);
+void dptr_SeekDir(struct dptr_struct *dptr, long offset);
+long dptr_TellDir(struct dptr_struct *dptr);
+bool dptr_has_wild(struct dptr_struct *dptr);
+int dptr_dnum(struct dptr_struct *dptr);
+const char *dptr_ReadDirName(TALLOC_CTX *ctx,
+ struct dptr_struct *dptr,
+ long *poffset,
+ SMB_STRUCT_STAT *pst);
+bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst);
+void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset);
+bool dptr_fill(char *buf1,unsigned int key);
+struct dptr_struct *dptr_fetch(char *buf,int *num);
+struct dptr_struct *dptr_fetch_lanman2(int dptr_num);
+bool dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype);
+bool get_dir_entry(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ const char *mask,
+ uint32 dirtype,
+ char **pp_fname_out,
+ SMB_OFF_T *size,
+ uint32 *mode,
+ time_t *date,
+ bool check_descend,
+ bool ask_sharemode);
+bool is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, bool use_veto);
+struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
+ const char *name, const char *mask, uint32 attr);
+const char *ReadDirName(struct smb_Dir *dirp, long *poffset);
+void RewindDir(struct smb_Dir *dirp, long *poffset);
+void SeekDir(struct smb_Dir *dirp, long offset);
+long TellDir(struct smb_Dir *dirp);
+void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset);
+bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset);
+NTSTATUS can_delete_directory(struct connection_struct *conn,
+ const char *dirname);
+
+/* The following definitions come from smbd/dmapi.c */
+
+const void *dmapi_get_current_session(void);
+bool dmapi_have_session(void);
+bool dmapi_new_session(void);
+bool dmapi_destroy_session(void);
+uint32 dmapi_file_flags(const char * const path);
+
+/* The following definitions come from smbd/dnsregister.c */
+
+void dns_register_close(struct dns_reg_state **dns_state_ptr);
+void dns_register_smbd(struct dns_reg_state ** dns_state_ptr,
+ unsigned port,
+ int *maxfd,
+ fd_set *listen_set,
+ struct timeval *timeout);
+bool dns_register_smbd_reply(struct dns_reg_state *dns_state,
+ fd_set *lfds, struct timeval *timeout);
+
+/* The following definitions come from smbd/dosmode.c */
+
+mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname,
+ const char *inherit_from_dir);
+uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf);
+uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf);
+int file_set_dosmode(connection_struct *conn, const char *fname,
+ uint32 dosmode, SMB_STRUCT_STAT *st,
+ const char *parent_dir,
+ bool newfile);
+int file_ntimes(connection_struct *conn, const char *fname, const struct timespec ts[2]);
+bool set_sticky_write_time_path(connection_struct *conn, const char *fname,
+ struct file_id fileid, const struct timespec mtime);
+bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime);
+bool update_write_time(struct files_struct *fsp);
+
+/* The following definitions come from smbd/error.c */
+
+bool use_nt_status(void);
+void error_packet_set(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file);
+int error_packet(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file);
+void reply_nt_error(struct smb_request *req, NTSTATUS ntstatus,
+ int line, const char *file);
+void reply_force_nt_error(struct smb_request *req, NTSTATUS ntstatus,
+ int line, const char *file);
+void reply_dos_error(struct smb_request *req, uint8 eclass, uint32 ecode,
+ int line, const char *file);
+void reply_both_error(struct smb_request *req, uint8 eclass, uint32 ecode,
+ NTSTATUS status, int line, const char *file);
+void reply_openerror(struct smb_request *req, NTSTATUS status);
+void reply_unix_error(struct smb_request *req, uint8 defclass, uint32 defcode,
+ NTSTATUS defstatus, int line, const char *file);
+
+/* The following definitions come from smbd/fake_file.c */
+
+enum FAKE_FILE_TYPE is_fake_file(const char *fname);
+NTSTATUS open_fake_file(connection_struct *conn,
+ uint16_t current_vuid,
+ enum FAKE_FILE_TYPE fake_file_type,
+ const char *fname,
+ uint32 access_mask,
+ files_struct **result);
+void destroy_fake_file_handle(struct fake_file_handle **fh);
+NTSTATUS close_fake_file(files_struct *fsp);
+
+/* The following definitions come from smbd/file_access.c */
+
+bool can_access_file_acl(struct connection_struct *conn,
+ const char * fname,
+ uint32_t access_mask);
+bool can_delete_file_in_directory(connection_struct *conn, const char *fname);
+bool can_access_file_data(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask);
+bool can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf);
+bool directory_has_default_acl(connection_struct *conn, const char *fname);
+
+/* The following definitions come from smbd/fileio.c */
+
+ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n);
+void trigger_write_time_update(struct files_struct *fsp);
+void trigger_write_time_update_immediate(struct files_struct *fsp);
+ssize_t write_file(struct smb_request *req,
+ files_struct *fsp,
+ const char *data,
+ SMB_OFF_T pos,
+ size_t n);
+void delete_write_cache(files_struct *fsp);
+void set_filelen_write_cache(files_struct *fsp, SMB_OFF_T file_size);
+ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason);
+NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, bool write_through);
+int fsp_stat(files_struct *fsp, SMB_STRUCT_STAT *pst);
+
+/* The following definitions come from smbd/filename.c */
+
+NTSTATUS unix_convert(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ const char *orig_path,
+ bool allow_wcard_last_component,
+ char **pp_conv_path,
+ char **pp_saved_last_component,
+ SMB_STRUCT_STAT *pst);
+NTSTATUS check_name(connection_struct *conn, const char *name);
+
+/* The following definitions come from smbd/files.c */
+
+NTSTATUS file_new(connection_struct *conn, files_struct **result);
+void file_close_conn(connection_struct *conn);
+void file_close_pid(uint16 smbpid, int vuid);
+void file_init(void);
+void file_close_user(int vuid);
+void file_dump_open_table(void);
+files_struct *file_find_fd(int fd);
+files_struct *file_find_dif(struct file_id id, unsigned long gen_id);
+files_struct *file_find_fsp(files_struct *orig_fsp);
+files_struct *file_find_di_first(struct file_id id);
+files_struct *file_find_di_next(files_struct *start_fsp);
+files_struct *file_find_print(void);
+void file_sync_all(connection_struct *conn);
+void file_free(files_struct *fsp);
+files_struct *file_fnum(uint16 fnum);
+files_struct *file_fsp(uint16 fid);
+void file_chain_reset(void);
+NTSTATUS dup_file_fsp(files_struct *fsp,
+ uint32 access_mask,
+ uint32 share_access,
+ uint32 create_options,
+ files_struct **result);
+
+/* The following definitions come from smbd/ipc.c */
+
+void send_trans_reply(connection_struct *conn,
+ const uint8_t *inbuf,
+ char *rparam, int rparam_len,
+ char *rdata, int rdata_len,
+ bool buffer_too_large);
+void reply_trans(struct smb_request *req);
+void reply_transs(struct smb_request *req);
+
+/* The following definitions come from smbd/lanman.c */
+
+void api_reply(connection_struct *conn, uint16 vuid,
+ struct smb_request *req,
+ char *data, char *params,
+ int tdscnt, int tpscnt,
+ int mdrcnt, int mprcnt);
+
+/* The following definitions come from smbd/mangle.c */
+
+void mangle_reset_cache(void);
+void mangle_change_to_posix(void);
+bool mangle_is_mangled(const char *s, const struct share_params *p);
+bool mangle_is_8_3(const char *fname, bool check_case,
+ const struct share_params *p);
+bool mangle_is_8_3_wildcards(const char *fname, bool check_case,
+ const struct share_params *p);
+bool mangle_must_mangle(const char *fname,
+ const struct share_params *p);
+bool mangle_lookup_name_from_8_3(TALLOC_CTX *ctx,
+ const char *in,
+ char **out, /* talloced on the given context. */
+ const struct share_params *p);
+bool name_to_8_3(const char *in,
+ char out[13],
+ bool cache83,
+ const struct share_params *p);
+
+/* The following definitions come from smbd/mangle_hash.c */
+
+struct mangle_fns *mangle_hash_init(void);
+
+/* The following definitions come from smbd/mangle_hash2.c */
+
+struct mangle_fns *mangle_hash2_init(void);
+struct mangle_fns *posix_mangle_init(void);
+
+/* The following definitions come from smbd/map_username.c */
+
+bool map_username(fstring user);
+
+/* The following definitions come from smbd/message.c */
+
+void reply_sends(struct smb_request *req);
+void reply_sendstrt(struct smb_request *req);
+void reply_sendtxt(struct smb_request *req);
+void reply_sendend(struct smb_request *req);
+
+/* The following definitions come from smbd/msdfs.c */
+
+bool is_msdfs_link(connection_struct *conn,
+ const char *path,
+ SMB_STRUCT_STAT *sbufp);
+NTSTATUS get_referred_path(TALLOC_CTX *ctx,
+ const char *dfs_path,
+ struct junction_map *jucn,
+ int *consumedcntp,
+ bool *self_referralp);
+int setup_dfs_referral(connection_struct *orig_conn,
+ const char *dfs_path,
+ int max_referral_level,
+ char **ppdata, NTSTATUS *pstatus);
+bool create_junction(TALLOC_CTX *ctx,
+ const char *dfs_path,
+ struct junction_map *jucn);
+bool create_msdfs_link(const struct junction_map *jucn);
+bool remove_msdfs_link(const struct junction_map *jucn);
+struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn);
+NTSTATUS resolve_dfspath(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ bool dfs_pathnames,
+ const char *name_in,
+ char **pp_name_out);
+NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ bool dfs_pathnames,
+ const char *name_in,
+ char **pp_name_out,
+ bool *ppath_contains_wcard);
+NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
+ connection_struct **pconn,
+ int snum,
+ const char *path,
+ char **poldcwd);
+
+/* The following definitions come from smbd/negprot.c */
+
+void reply_negprot(struct smb_request *req);
+
+/* The following definitions come from smbd/notify.c */
+
+void change_notify_reply(connection_struct *conn,
+ const uint8 *request_buf, uint32 max_param,
+ struct notify_change_buf *notify_buf);
+NTSTATUS change_notify_create(struct files_struct *fsp, uint32 filter,
+ bool recursive);
+NTSTATUS change_notify_add_request(const struct smb_request *req,
+ uint32 max_param,
+ uint32 filter, bool recursive,
+ struct files_struct *fsp);
+void remove_pending_change_notify_requests_by_mid(uint16 mid);
+void remove_pending_change_notify_requests_by_fid(files_struct *fsp,
+ NTSTATUS status);
+void notify_fname(connection_struct *conn, uint32 action, uint32 filter,
+ const char *path);
+char *notify_filter_string(TALLOC_CTX *mem_ctx, uint32 filter);
+struct sys_notify_context *sys_notify_context_create(connection_struct *conn,
+ TALLOC_CTX *mem_ctx,
+ struct event_context *ev);
+NTSTATUS sys_notify_watch(struct sys_notify_context *ctx,
+ struct notify_entry *e,
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev),
+ void *private_data, void *handle);
+
+/* The following definitions come from smbd/notify_inotify.c */
+
+NTSTATUS inotify_watch(struct sys_notify_context *ctx,
+ struct notify_entry *e,
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev),
+ void *private_data,
+ void *handle_p);
+
+/* The following definitions come from smbd/notify_internal.c */
+
+struct notify_context *notify_init(TALLOC_CTX *mem_ctx, struct server_id server,
+ struct messaging_context *messaging_ctx,
+ struct event_context *ev,
+ connection_struct *conn);
+NTSTATUS notify_add(struct notify_context *notify, struct notify_entry *e0,
+ void (*callback)(void *, const struct notify_event *),
+ void *private_data);
+NTSTATUS notify_remove(struct notify_context *notify, void *private_data);
+void notify_trigger(struct notify_context *notify,
+ uint32_t action, uint32_t filter, const char *path);
+
+/* The following definitions come from smbd/ntquotas.c */
+
+int vfs_get_ntquota(files_struct *fsp, enum SMB_QUOTA_TYPE qtype, DOM_SID *psid, SMB_NTQUOTA_STRUCT *qt);
+int vfs_set_ntquota(files_struct *fsp, enum SMB_QUOTA_TYPE qtype, DOM_SID *psid, SMB_NTQUOTA_STRUCT *qt);
+int vfs_get_user_ntquota_list(files_struct *fsp, SMB_NTQUOTA_LIST **qt_list);
+void *init_quota_handle(TALLOC_CTX *mem_ctx);
+
+/* The following definitions come from smbd/nttrans.c */
+
+void send_nt_replies(connection_struct *conn,
+ struct smb_request *req, NTSTATUS nt_error,
+ char *params, int paramsize,
+ char *pdata, int datasize);
+bool is_ntfs_stream_name(const char *fname);
+void reply_ntcreate_and_X(struct smb_request *req);
+void reply_ntcancel(struct smb_request *req);
+void reply_ntrename(struct smb_request *req);
+void reply_nttrans(struct smb_request *req);
+void reply_nttranss(struct smb_request *req);
+
+/* The following definitions come from smbd/open.c */
+
+NTSTATUS fd_close(files_struct *fsp);
+bool map_open_params_to_ntcreate(const char *fname, int deny_mode, int open_func,
+ uint32 *paccess_mask,
+ uint32 *pshare_mode,
+ uint32 *pcreate_disposition,
+ uint32 *pcreate_options);
+NTSTATUS open_file_ntcreate(connection_struct *conn,
+ struct smb_request *req,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf,
+ uint32 access_mask, /* access bits (FILE_READ_DATA etc.) */
+ uint32 share_access, /* share constants (FILE_SHARE_READ etc) */
+ uint32 create_disposition, /* FILE_OPEN_IF etc. */
+ uint32 create_options, /* options such as delete on close. */
+ uint32 new_dos_attributes, /* attributes used for new file. */
+ int oplock_request, /* internal Samba oplock codes. */
+ /* Information (FILE_EXISTS etc.) */
+ int *pinfo,
+ files_struct **result);
+NTSTATUS open_file_fchmod(connection_struct *conn, const char *fname,
+ SMB_STRUCT_STAT *psbuf, files_struct **result);
+NTSTATUS close_file_fchmod(files_struct *fsp);
+NTSTATUS open_directory(connection_struct *conn,
+ struct smb_request *req,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf,
+ uint32 access_mask,
+ uint32 share_access,
+ uint32 create_disposition,
+ uint32 create_options,
+ uint32 file_attributes,
+ int *pinfo,
+ files_struct **result);
+NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, const char *directory);
+void msg_file_was_renamed(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data);
+NTSTATUS create_file_unixpath(connection_struct *conn,
+ struct smb_request *req,
+ const char *fname,
+ uint32_t access_mask,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ uint32_t file_attributes,
+ uint32_t oplock_request,
+ SMB_BIG_UINT allocation_size,
+ struct security_descriptor *sd,
+ struct ea_list *ea_list,
+
+ files_struct **result,
+ int *pinfo,
+ SMB_STRUCT_STAT *psbuf);
+NTSTATUS create_file(connection_struct *conn,
+ struct smb_request *req,
+ uint16_t root_dir_fid,
+ const char *fname,
+ uint32_t access_mask,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ uint32_t file_attributes,
+ uint32_t oplock_request,
+ SMB_BIG_UINT allocation_size,
+ struct security_descriptor *sd,
+ struct ea_list *ea_list,
+
+ files_struct **result,
+ int *pinfo,
+ SMB_STRUCT_STAT *psbuf);
+
+/* The following definitions come from smbd/oplock.c */
+
+int32 get_number_of_exclusive_open_oplocks(void);
+bool oplock_message_waiting(fd_set *fds);
+void process_kernel_oplocks(struct messaging_context *msg_ctx, fd_set *pfds);
+bool set_file_oplock(files_struct *fsp, int oplock_type);
+void release_file_oplock(files_struct *fsp);
+bool remove_oplock(files_struct *fsp);
+bool downgrade_oplock(files_struct *fsp);
+int oplock_notify_fd(void);
+void reply_to_oplock_break_requests(files_struct *fsp);
+void release_level_2_oplocks_on_change(files_struct *fsp);
+void share_mode_entry_to_message(char *msg, const struct share_mode_entry *e);
+void message_to_share_mode_entry(struct share_mode_entry *e, char *msg);
+bool init_oplocks(struct messaging_context *msg_ctx);
+
+/* The following definitions come from smbd/oplock_irix.c */
+
+struct kernel_oplocks *irix_init_kernel_oplocks(void) ;
+
+/* The following definitions come from smbd/oplock_linux.c */
+
+void linux_set_lease_capability(void);
+int linux_set_lease_sighandler(int fd);
+int linux_setlease(int fd, int leasetype);
+struct kernel_oplocks *linux_init_kernel_oplocks(void) ;
+
+/* The following definitions come from smbd/password.c */
+
+user_struct *get_valid_user_struct(uint16 vuid);
+bool is_partial_auth_vuid(uint16 vuid);
+user_struct *get_partial_auth_user_struct(uint16 vuid);
+void invalidate_vuid(uint16 vuid);
+void invalidate_all_vuids(void);
+int register_initial_vuid(void);
+int register_existing_vuid(uint16 vuid,
+ auth_serversupplied_info *server_info,
+ DATA_BLOB response_blob,
+ const char *smb_name);
+void add_session_user(const char *user);
+void add_session_workgroup(const char *workgroup);
+const char *get_session_workgroup(void);
+bool user_in_netgroup(const char *user, const char *ngname);
+bool user_in_list(const char *user,const char **list);
+bool authorise_login(int snum, fstring user, DATA_BLOB password,
+ bool *guest);
+
+/* The following definitions come from smbd/pipes.c */
+
+void reply_open_pipe_and_X(connection_struct *conn, struct smb_request *req);
+void reply_pipe_write(struct smb_request *req);
+void reply_pipe_write_and_X(struct smb_request *req);
+void reply_pipe_read_and_X(struct smb_request *req);
+void reply_pipe_close(connection_struct *conn, struct smb_request *req);
+
+/* The following definitions come from smbd/posix_acls.c */
+
+NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd);
+SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl);
+NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info,
+ SEC_DESC **ppdesc);
+NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name,
+ uint32_t security_info, SEC_DESC **ppdesc);
+int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid);
+NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd);
+int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode );
+int chmod_acl(connection_struct *conn, const char *name, mode_t mode);
+int inherit_access_posix_acl(connection_struct *conn, const char *inherit_from_dir,
+ const char *name, mode_t mode);
+int fchmod_acl(files_struct *fsp, mode_t mode);
+bool set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf,
+ uint16 num_def_acls, const char *pdata);
+bool set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname, uint16 num_acls, const char *pdata);
+SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname);
+
+/* The following definitions come from smbd/process.c */
+
+bool srv_send_smb(int fd, char *buffer, bool do_encrypt);
+int srv_set_message(char *buf,
+ int num_words,
+ int num_bytes,
+ bool zero);
+void init_smb_request(struct smb_request *req,
+ const uint8 *inbuf,
+ size_t unread_bytes,
+ bool encrypted);
+void remove_deferred_open_smb_message(uint16 mid);
+void schedule_deferred_open_smb_message(uint16 mid);
+bool open_was_deferred(uint16 mid);
+struct pending_message_list *get_open_deferred_message(uint16 mid);
+bool push_deferred_smb_message(struct smb_request *req,
+ struct timeval request_time,
+ struct timeval timeout,
+ char *private_data, size_t priv_len);
+struct idle_event *event_add_idle(struct event_context *event_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct timeval interval,
+ const char *name,
+ bool (*handler)(const struct timeval *now,
+ void *private_data),
+ void *private_data);
+NTSTATUS allow_new_trans(struct trans_state *list, int mid);
+void respond_to_all_remaining_local_messages(void);
+bool create_outbuf(TALLOC_CTX *mem_ctx, const char *inbuf, char **outbuf,
+ uint8_t num_words, uint32_t num_bytes);
+void reply_outbuf(struct smb_request *req, uint8 num_words, uint32 num_bytes);
+const char *smb_fn_name(int type);
+void add_to_common_flags2(uint32 v);
+void remove_from_common_flags2(uint32 v);
+void construct_reply_common(const char *inbuf, char *outbuf);
+void chain_reply(struct smb_request *req);
+void check_reload(time_t t);
+void smbd_process(void);
+
+/* The following definitions come from smbd/quotas.c */
+
+bool disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
+bool disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
+bool disk_quotas(const char *path,
+ SMB_BIG_UINT *bsize,
+ SMB_BIG_UINT *dfree,
+ SMB_BIG_UINT *dsize);
+bool disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
+bool disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
+bool disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
+bool disk_quotas_vxfs(const char *name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
+bool disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize);
+bool disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize);
+
+/* The following definitions come from smbd/reply.c */
+
+NTSTATUS check_path_syntax(char *path);
+NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard);
+NTSTATUS check_path_syntax_posix(char *path);
+size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
+ const char *inbuf,
+ uint16 smb_flags2,
+ char **pp_dest,
+ const char *src,
+ size_t src_len,
+ int flags,
+ NTSTATUS *err,
+ bool *contains_wcard);
+size_t srvstr_get_path(TALLOC_CTX *ctx,
+ const char *inbuf,
+ uint16 smb_flags2,
+ char **pp_dest,
+ const char *src,
+ size_t src_len,
+ int flags,
+ NTSTATUS *err);
+bool check_fsp_open(connection_struct *conn, struct smb_request *req,
+ files_struct *fsp);
+bool check_fsp(connection_struct *conn, struct smb_request *req,
+ files_struct *fsp);
+bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
+ files_struct *fsp);
+bool fsp_belongs_conn(connection_struct *conn, struct smb_request *req,
+ files_struct *fsp);
+void reply_special(char *inbuf);
+void reply_tcon(struct smb_request *req);
+void reply_tcon_and_X(struct smb_request *req);
+void reply_unknown_new(struct smb_request *req, uint8 type);
+void reply_ioctl(struct smb_request *req);
+void reply_checkpath(struct smb_request *req);
+void reply_getatr(struct smb_request *req);
+void reply_setatr(struct smb_request *req);
+void reply_dskattr(struct smb_request *req);
+void reply_search(struct smb_request *req);
+void reply_fclose(struct smb_request *req);
+void reply_open(struct smb_request *req);
+void reply_open_and_X(struct smb_request *req);
+void reply_ulogoffX(struct smb_request *req);
+void reply_mknew(struct smb_request *req);
+void reply_ctemp(struct smb_request *req);
+NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
+ uint32 dirtype, const char *name_in, bool has_wild);
+void reply_unlink(struct smb_request *req);
+void send_file_readbraw(connection_struct *conn,
+ files_struct *fsp,
+ SMB_OFF_T startpos,
+ size_t nread,
+ ssize_t mincount);
+void reply_readbraw(struct smb_request *req);
+void reply_lockread(struct smb_request *req);
+void reply_read(struct smb_request *req);
+void reply_read_and_X(struct smb_request *req);
+void error_to_writebrawerr(struct smb_request *req);
+void reply_writebraw(struct smb_request *req);
+void reply_writeunlock(struct smb_request *req);
+void reply_write(struct smb_request *req);
+bool is_valid_writeX_buffer(const uint8_t *inbuf);
+void reply_write_and_X(struct smb_request *req);
+void reply_lseek(struct smb_request *req);
+void reply_flush(struct smb_request *req);
+void reply_exit(struct smb_request *req);
+void reply_close(struct smb_request *req);
+void reply_writeclose(struct smb_request *req);
+void reply_lock(struct smb_request *req);
+void reply_unlock(struct smb_request *req);
+void reply_tdis(struct smb_request *req);
+void reply_echo(struct smb_request *req);
+void reply_printopen(struct smb_request *req);
+void reply_printclose(struct smb_request *req);
+void reply_printqueue(struct smb_request *req);
+void reply_printwrite(struct smb_request *req);
+void reply_mkdir(struct smb_request *req);
+NTSTATUS rmdir_internals(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ const char *directory);
+void reply_rmdir(struct smb_request *req);
+NTSTATUS rename_internals_fsp(connection_struct *conn,
+ files_struct *fsp,
+ char *newname,
+ const char *newname_last_component,
+ uint32 attrs,
+ bool replace_if_exists);
+NTSTATUS rename_internals(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ struct smb_request *req,
+ const char *name_in,
+ const char *newname_in,
+ uint32 attrs,
+ bool replace_if_exists,
+ bool src_has_wild,
+ bool dest_has_wild,
+ uint32_t access_mask);
+void reply_mv(struct smb_request *req);
+NTSTATUS copy_file(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ const char *src,
+ const char *dest1,
+ int ofun,
+ int count,
+ bool target_is_directory);
+void reply_copy(struct smb_request *req);
+uint32 get_lock_pid( char *data, int data_offset, bool large_file_format);
+SMB_BIG_UINT get_lock_count( char *data, int data_offset, bool large_file_format);
+SMB_BIG_UINT get_lock_offset( char *data, int data_offset, bool large_file_format, bool *err);
+void reply_lockingX(struct smb_request *req);
+void reply_readbmpx(struct smb_request *req);
+void reply_readbs(struct smb_request *req);
+void reply_setattrE(struct smb_request *req);
+void reply_writebmpx(struct smb_request *req);
+void reply_writebs(struct smb_request *req);
+void reply_getattrE(struct smb_request *req);
+
+/* The following definitions come from smbd/seal.c */
+
+uint16_t srv_enc_ctx(void);
+bool is_encrypted_packet(const uint8_t *inbuf);
+void srv_free_enc_buffer(char *buf);
+NTSTATUS srv_decrypt_buffer(char *buf);
+NTSTATUS srv_encrypt_buffer(char *buf, char **buf_out);
+NTSTATUS srv_request_encryption_setup(connection_struct *conn,
+ unsigned char **ppdata,
+ size_t *p_data_size,
+ unsigned char **pparam,
+ size_t *p_param_size);
+NTSTATUS srv_encryption_start(connection_struct *conn);
+void server_encryption_shutdown(void);
+
+/* The following definitions come from smbd/sec_ctx.c */
+
+bool unix_token_equal(const UNIX_USER_TOKEN *t1, const UNIX_USER_TOKEN *t2);
+bool push_sec_ctx(void);
+void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN *token);
+void set_root_sec_ctx(void);
+bool pop_sec_ctx(void);
+void init_sec_ctx(void);
+
+/* The following definitions come from smbd/server.c */
+
+int smbd_server_fd(void);
+int get_client_fd(void);
+int client_get_tcp_info(struct sockaddr_in *server, struct sockaddr_in *client);
+struct event_context *smbd_event_context(void);
+struct messaging_context *smbd_messaging_context(void);
+struct memcache *smbd_memcache(void);
+void reload_printers(void);
+bool reload_services(bool test);
+void exit_server(const char *const explanation);
+void exit_server_cleanly(const char *const explanation);
+void exit_server_fault(void);
+
+/* The following definitions come from smbd/service.c */
+
+bool set_conn_connectpath(connection_struct *conn, const char *connectpath);
+bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir);
+void load_registry_shares(void);
+int add_home_service(const char *service, const char *username, const char *homedir);
+int find_service(fstring service);
+connection_struct *make_connection_with_chdir(const char *service_in,
+ DATA_BLOB password,
+ const char *dev, uint16 vuid,
+ NTSTATUS *status);
+connection_struct *make_connection(const char *service_in, DATA_BLOB password,
+ const char *pdev, uint16 vuid,
+ NTSTATUS *status);
+void close_cnum(connection_struct *conn, uint16 vuid);
+
+/* The following definitions come from smbd/session.c */
+
+bool session_init(void);
+bool session_claim(user_struct *vuser);
+void session_yield(user_struct *vuser);
+int list_sessions(TALLOC_CTX *mem_ctx, struct sessionid **session_list);
+
+/* The following definitions come from smbd/sesssetup.c */
+
+NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
+ DATA_BLOB *pblob_out,
+ char **kerb_mechOID);
+void reply_sesssetup_and_X(struct smb_request *req);
+
+/* The following definitions come from smbd/share_access.c */
+
+bool token_contains_name_in_list(const char *username,
+ const char *domain,
+ const char *sharename,
+ const struct nt_user_token *token,
+ const char **list);
+bool user_ok_token(const char *username, const char *domain,
+ struct nt_user_token *token, int snum);
+bool is_share_read_only_for_token(const char *username,
+ const char *domain,
+ struct nt_user_token *token, int snum);
+
+/* The following definitions come from smbd/srvstr.c */
+
+size_t srvstr_push_fn(const char *function, unsigned int line,
+ const char *base_ptr, uint16 smb_flags2, void *dest,
+ const char *src, int dest_len, int flags);
+ssize_t message_push_string(uint8 **outbuf, const char *str, int flags);
+
+/* The following definitions come from smbd/statcache.c */
+
+void stat_cache_add( const char *full_orig_name,
+ char *translated_path,
+ bool case_sensitive);
+bool stat_cache_lookup(connection_struct *conn,
+ char **pp_name,
+ char **pp_dirpath,
+ char **pp_start,
+ SMB_STRUCT_STAT *pst);
+void send_stat_cache_delete_message(const char *name);
+void stat_cache_delete(const char *name);
+unsigned int fast_string_hash(TDB_DATA *key);
+bool reset_stat_cache( void );
+
+/* The following definitions come from smbd/statvfs.c */
+
+int sys_statvfs(const char *path, vfs_statvfs_struct *statbuf);
+
+/* The following definitions come from smbd/trans2.c */
+
+SMB_BIG_UINT smb_roundup(connection_struct *conn, SMB_BIG_UINT val);
+SMB_BIG_UINT get_allocation_size(connection_struct *conn, files_struct *fsp, const SMB_STRUCT_STAT *sbuf);
+NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn,
+ files_struct *fsp, const char *fname,
+ const char *ea_name, struct ea_struct *pea);
+NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
+ files_struct *fsp, const char *fname,
+ char ***pnames, size_t *pnum_names);
+NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, const char *fname, struct ea_list *ea_list);
+struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used);
+void send_trans2_replies(connection_struct *conn,
+ struct smb_request *req,
+ const char *params,
+ int paramsize,
+ const char *pdata,
+ int datasize,
+ int max_data_bytes);
+unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16]);
+NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ const char *oldname_in,
+ const char *newname_in);
+NTSTATUS smb_set_file_time(connection_struct *conn,
+ files_struct *fsp,
+ const char *fname,
+ const SMB_STRUCT_STAT *psbuf,
+ struct timespec ts[2],
+ bool setting_write_time);
+void reply_findclose(struct smb_request *req);
+void reply_findnclose(struct smb_request *req);
+void reply_trans2(struct smb_request *req);
+void reply_transs2(struct smb_request *req);
+
+/* The following definitions come from smbd/uid.c */
+
+bool change_to_guest(void);
+void conn_clear_vuid_cache(connection_struct *conn, uint16_t vuid);
+bool change_to_user(connection_struct *conn, uint16 vuid);
+bool change_to_root_user(void);
+bool become_authenticated_pipe_user(pipes_struct *p);
+bool unbecome_authenticated_pipe_user(void);
+void become_root(void);
+void unbecome_root(void);
+bool become_user(connection_struct *conn, uint16 vuid);
+bool unbecome_user(void);
+
+/* The following definitions come from smbd/utmp.c */
+
+void sys_utmp_claim(const char *username, const char *hostname,
+ const char *ip_addr_str,
+ const char *id_str, int id_num);
+void sys_utmp_yield(const char *username, const char *hostname,
+ const char *ip_addr_str,
+ const char *id_str, int id_num);
+void sys_utmp_yield(const char *username, const char *hostname,
+ const char *ip_addr_str,
+ const char *id_str, int id_num);
+void sys_utmp_claim(const char *username, const char *hostname,
+ const char *ip_addr_str,
+ const char *id_str, int id_num);
+
+/* The following definitions come from smbd/vfs.c */
+
+NTSTATUS smb_register_vfs(int version, const char *name, const vfs_op_tuple *vfs_op_tuples);
+bool vfs_init_custom(connection_struct *conn, const char *vfs_object);
+void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp, size_t ext_size);
+void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp);
+void *vfs_memctx_fsp_extension(vfs_handle_struct *handle, files_struct *fsp);
+void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp);
+bool smbd_vfs_init(connection_struct *conn);
+bool vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st);
+bool vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf);
+bool vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf);
+ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count);
+ssize_t vfs_pread_data(files_struct *fsp, char *buf,
+ size_t byte_count, SMB_OFF_T offset);
+ssize_t vfs_write_data(struct smb_request *req,
+ files_struct *fsp,
+ const char *buffer,
+ size_t N);
+ssize_t vfs_pwrite_data(struct smb_request *req,
+ files_struct *fsp,
+ const char *buffer,
+ size_t N,
+ SMB_OFF_T offset);
+int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len);
+int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len);
+int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len);
+SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n);
+char *vfs_readdirname(connection_struct *conn, void *p);
+int vfs_ChDir(connection_struct *conn, const char *path);
+char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn);
+NTSTATUS check_reduced_name(connection_struct *conn, const char *fname);
+
+/* The following definitions come from torture/denytest.c */
+
+bool torture_denytest1(int dummy);
+bool torture_denytest2(int dummy);
+
+/* The following definitions come from torture/mangle_test.c */
+
+bool torture_mangle(int dummy);
+
+/* The following definitions come from torture/nbio.c */
+
+double nbio_total(void);
+void nb_alarm(int ignore);
+void nbio_shmem(int n);
+void nb_setup(struct cli_state *cli);
+void nb_unlink(const char *fname);
+void nb_createx(const char *fname,
+ unsigned create_options, unsigned create_disposition, int handle);
+void nb_writex(int handle, int offset, int size, int ret_size);
+void nb_readx(int handle, int offset, int size, int ret_size);
+void nb_close(int handle);
+void nb_rmdir(const char *fname);
+void nb_rename(const char *oldname, const char *newname);
+void nb_qpathinfo(const char *fname);
+void nb_qfileinfo(int fnum);
+void nb_qfsinfo(int level);
+void nb_findfirst(const char *mask);
+void nb_flush(int fnum);
+void nb_deltree(const char *dname);
+void nb_cleanup(void);
+
+/* The following definitions come from torture/scanner.c */
+
+bool torture_trans2_scan(int dummy);
+bool torture_nttrans_scan(int dummy);
+
+/* The following definitions come from torture/torture.c */
+
+void start_timer(void);
+double end_timer(void);
+void *shm_setup(int size);
+bool smbcli_parse_unc(const char *unc_name, TALLOC_CTX *mem_ctx,
+ char **hostname, char **sharename);
+void torture_open_connection_free_unclist(char **unc_list);
+bool torture_open_connection(struct cli_state **c, int conn_index);
+bool torture_cli_session_setup2(struct cli_state *cli, uint16 *new_vuid);
+bool torture_close_connection(struct cli_state *c);
+bool torture_ioctl_test(int dummy);
+bool torture_chkpath_test(int dummy);
+
+/* The following definitions come from torture/utable.c */
+
+bool torture_utable(int dummy);
+bool torture_casetable(int dummy);
+
+/* The following definitions come from utils/passwd_util.c */
+
+char *stdin_new_passwd( void);
+char *get_pass( const char *prompt, bool stdin_get);
+
+/* The following definitions come from winbindd/idmap.c */
+
+bool idmap_is_offline(void);
+bool idmap_is_online(void);
+NTSTATUS smb_register_idmap(int version, const char *name,
+ struct idmap_methods *methods);
+NTSTATUS smb_register_idmap_alloc(int version, const char *name,
+ struct idmap_alloc_methods *methods);
+void idmap_close(void);
+NTSTATUS idmap_init_cache(void);
+NTSTATUS idmap_allocate_uid(struct unixid *id);
+NTSTATUS idmap_allocate_gid(struct unixid *id);
+NTSTATUS idmap_set_uid_hwm(struct unixid *id);
+NTSTATUS idmap_set_gid_hwm(struct unixid *id);
+NTSTATUS idmap_backends_unixid_to_sid(const char *domname,
+ struct id_map *id);
+NTSTATUS idmap_backends_sid_to_unixid(const char *domname,
+ struct id_map *id);
+NTSTATUS idmap_new_mapping(const struct dom_sid *psid, enum id_type type,
+ struct unixid *pxid);
+NTSTATUS idmap_set_mapping(const struct id_map *map);
+
+/* The following definitions come from winbindd/idmap_cache.c */
+
+bool idmap_cache_find_sid2uid(const struct dom_sid *sid, uid_t *puid,
+ bool *expired);
+bool idmap_cache_find_uid2sid(uid_t uid, struct dom_sid *sid, bool *expired);
+void idmap_cache_set_sid2uid(const struct dom_sid *sid, uid_t uid);
+bool idmap_cache_find_sid2gid(const struct dom_sid *sid, gid_t *pgid,
+ bool *expired);
+bool idmap_cache_find_gid2sid(gid_t gid, struct dom_sid *sid, bool *expired);
+void idmap_cache_set_sid2gid(const struct dom_sid *sid, gid_t gid);
+
+
+/* The following definitions come from winbindd/idmap_nss.c */
+
+NTSTATUS idmap_nss_init(void);
+
+/* The following definitions come from winbindd/idmap_passdb.c */
+
+NTSTATUS idmap_passdb_init(void);
+
+/* The following definitions come from winbindd/idmap_tdb.c */
+
+bool idmap_tdb_tdb_close(TDB_CONTEXT *tdbctx);
+NTSTATUS idmap_alloc_tdb_init(void);
+NTSTATUS idmap_tdb_init(void);
+
+/* The following definitions come from winbindd/idmap_util.c */
+
+NTSTATUS idmap_uid_to_sid(const char *domname, DOM_SID *sid, uid_t uid);
+NTSTATUS idmap_gid_to_sid(const char *domname, DOM_SID *sid, gid_t gid);
+NTSTATUS idmap_sid_to_uid(const char *dom_name, DOM_SID *sid, uid_t *uid);
+NTSTATUS idmap_sid_to_gid(const char *domname, DOM_SID *sid, gid_t *gid);
+
+/* The following definitions come from winbindd/nss_info.c */
+
+
+/* The following definitions come from winbindd/nss_info_template.c */
+
+NTSTATUS nss_info_template_init( void );
+
+#endif /* _PROTO_H_ */
diff --git a/source3/include/rap.h b/source3/include/rap.h
new file mode 100644
index 0000000000..a7efb67d60
--- /dev/null
+++ b/source3/include/rap.h
@@ -0,0 +1,506 @@
+/*
+ Samba Unix/Linux SMB client library
+ RAP (SMB Remote Procedure Calls) defines and structures
+ Copyright (C) Steve French 2001 (sfrench@us.ibm.com)
+ Copyright (C) Jim McDonough 2001 (jmcd@us.ibm.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _RAP_H_
+#define _RAP_H_
+
+/*****************************************************/
+/* */
+/* Additional RAP functionality */
+/* */
+/* RAP is the original SMB RPC, documented */
+/* by Microsoft and X/Open in the 1990s and */
+/* supported by most SMB/CIFS servers although */
+/* it is unlikely that any one implementation */
+/* supports all RAP command codes since some */
+/* are quite obsolete and a few are specific */
+/* to a particular network operating system */
+/* */
+/* Although it has largely been replaced */
+/* for complex remote admistration and management */
+/* (of servers) by the relatively newer */
+/* DCE/RPC based remote API (which better handles */
+/* large >64K data structures), there are many */
+/* important administrative and resource location */
+/* tasks and user tasks (e.g. password change) */
+/* that are performed via RAP. */
+/* */
+/* Although a few of the RAP calls are implemented */
+/* in the Samba client library already (clirap.c) */
+/* the new ones are in clirap2.c for easy patching */
+/* and integration and a corresponding header */
+/* file, rap.h, has been created. */
+/* */
+/* This is based on data from the CIFS spec */
+/* and the LAN Server and LAN Manager */
+/* Programming Reference books and published */
+/* RAP document and CIFS forum postings and */
+/* lots of trial and error. Additional */
+/* background information is available from the */
+/* X/Open reference book in their PC Interworking */
+/* series "IPC for SMB" and also from the */
+/* interoperability documentation in */
+/* ftp://ftp.microsoft.com/developr/drg/cifs */
+/* */
+/* Function names changed from API_ (as they are */
+/* in the CIFS specification to RAP_ in order */
+/* to avoid confusion with other API calls */
+/* sent via DCE RPC */
+/* */
+/*****************************************************/
+
+/*****************************************************/
+/* */
+/* Although without pound defines (of this header) */
+/* cifsrap.c already includes support for: */
+/* */
+/* WshareEnum (API number 0, level 1) */
+/* NetServerEnum2 (API num 104, level 1) */
+/* WWkstaUserLogon (132) */
+/* SamOEMchgPasswordUser2_P (214) */
+/* */
+/* and cifsprint.c already includes support for: */
+/* */
+/* WPrintJobEnum (API num 76, level 2) */
+/* WPrintJobDel (API num 81) */
+/* */
+/*****************************************************/
+
+#define RAP_WshareEnum 0
+#define RAP_WshareGetInfo 1
+#define RAP_WshareSetInfo 2
+#define RAP_WshareAdd 3
+#define RAP_WshareDel 4
+#define RAP_NetShareCheck 5
+#define RAP_WsessionEnum 6
+#define RAP_WsessionGetInfo 7
+#define RAP_WsessionDel 8
+#define RAP_WconnectionEnum 9
+#define RAP_WfileEnum 10
+#define RAP_WfileGetInfo 11
+#define RAP_WfileClose 12
+#define RAP_WserverGetInfo 13
+#define RAP_WserverSetInfo 14
+#define RAP_WserverDiskEnum 15
+#define RAP_WserverAdminCommand 16
+#define RAP_NetAuditOpen 17
+#define RAP_WauditClear 18
+#define RAP_NetErrorLogOpen 19
+#define RAP_WerrorLogClear 20
+#define RAP_NetCharDevEnum 21
+#define RAP_NetCharDevGetInfo 22
+#define RAP_WCharDevControl 23
+#define RAP_NetCharDevQEnum 24
+#define RAP_NetCharDevQGetInfo 25
+#define RAP_WCharDevQSetInfo 26
+#define RAP_WCharDevQPurge 27
+#define RAP_WCharDevQPurgeSelf 28
+#define RAP_WMessageNameEnum 29
+#define RAP_WMessageNameGetInfo 30
+#define RAP_WMessageNameAdd 31
+#define RAP_WMessageNameDel 32
+#define RAP_WMessageNameFwd 33
+#define RAP_WMessageNameUnFwd 34
+#define RAP_WMessageBufferSend 35
+#define RAP_WMessageFileSend 36
+#define RAP_WMessageLogFileSet 37
+#define RAP_WMessageLogFileGet 38
+#define RAP_WServiceEnum 39
+#define RAP_WServiceInstall 40
+#define RAP_WServiceControl 41
+#define RAP_WAccessEnum 42
+#define RAP_WAccessGetInfo 43
+#define RAP_WAccessSetInfo 44
+#define RAP_WAccessAdd 45
+#define RAP_WAccessDel 46
+#define RAP_WGroupEnum 47
+#define RAP_WGroupAdd 48
+#define RAP_WGroupDel 49
+#define RAP_WGroupAddUser 50
+#define RAP_WGroupDelUser 51
+#define RAP_WGroupGetUsers 52
+#define RAP_WUserEnum 53
+#define RAP_WUserAdd 54
+#define RAP_WUserDel 55
+#define RAP_WUserGetInfo 56
+#define RAP_WUserSetInfo 57
+#define RAP_WUserPasswordSet 58
+#define RAP_WUserGetGroups 59
+#define RAP_WWkstaSetUID 62
+#define RAP_WWkstaGetInfo 63
+#define RAP_WWkstaSetInfo 64
+#define RAP_WUseEnum 65
+#define RAP_WUseAdd 66
+#define RAP_WUseDel 67
+#define RAP_WUseGetInfo 68
+#define RAP_WPrintQEnum 69
+#define RAP_WPrintQGetInfo 70
+#define RAP_WPrintQSetInfo 71
+#define RAP_WPrintQAdd 72
+#define RAP_WPrintQDel 73
+#define RAP_WPrintQPause 74
+#define RAP_WPrintQContinue 75
+#define RAP_WPrintJobEnum 76
+#define RAP_WPrintJobGetInfo 77
+#define RAP_WPrintJobSetInfo_OLD 78
+#define RAP_WPrintJobDel 81
+#define RAP_WPrintJobPause 82
+#define RAP_WPrintJobContinue 83
+#define RAP_WPrintDestEnum 84
+#define RAP_WPrintDestGetInfo 85
+#define RAP_WPrintDestControl 86
+#define RAP_WProfileSave 87
+#define RAP_WProfileLoad 88
+#define RAP_WStatisticsGet 89
+#define RAP_WStatisticsClear 90
+#define RAP_NetRemoteTOD 91
+#define RAP_WNetBiosEnum 92
+#define RAP_WNetBiosGetInfo 93
+#define RAP_NetServerEnum 94
+#define RAP_I_NetServerEnum 95
+#define RAP_WServiceGetInfo 96
+#define RAP_WPrintQPurge 103
+#define RAP_NetServerEnum2 104
+#define RAP_WAccessGetUserPerms 105
+#define RAP_WGroupGetInfo 106
+#define RAP_WGroupSetInfo 107
+#define RAP_WGroupSetUsers 108
+#define RAP_WUserSetGroups 109
+#define RAP_WUserModalsGet 110
+#define RAP_WUserModalsSet 111
+#define RAP_WFileEnum2 112
+#define RAP_WUserAdd2 113
+#define RAP_WUserSetInfo2 114
+#define RAP_WUserPasswordSet2 115
+#define RAP_I_NetServerEnum2 116
+#define RAP_WConfigGet2 117
+#define RAP_WConfigGetAll2 118
+#define RAP_WGetDCName 119
+#define RAP_NetHandleGetInfo 120
+#define RAP_NetHandleSetInfo 121
+#define RAP_WStatisticsGet2 122
+#define RAP_WBuildGetInfo 123
+#define RAP_WFileGetInfo2 124
+#define RAP_WFileClose2 125
+#define RAP_WNetServerReqChallenge 126
+#define RAP_WNetServerAuthenticate 127
+#define RAP_WNetServerPasswordSet 128
+#define RAP_WNetAccountDeltas 129
+#define RAP_WNetAccountSync 130
+#define RAP_WUserEnum2 131
+#define RAP_WWkstaUserLogon 132
+#define RAP_WWkstaUserLogoff 133
+#define RAP_WLogonEnum 134
+#define RAP_WErrorLogRead 135
+#define RAP_NetPathType 136
+#define RAP_NetPathCanonicalize 137
+#define RAP_NetPathCompare 138
+#define RAP_NetNameValidate 139
+#define RAP_NetNameCanonicalize 140
+#define RAP_NetNameCompare 141
+#define RAP_WAuditRead 142
+#define RAP_WPrintDestAdd 143
+#define RAP_WPrintDestSetInfo 144
+#define RAP_WPrintDestDel 145
+#define RAP_WUserValidate2 146
+#define RAP_WPrintJobSetInfo 147
+#define RAP_TI_NetServerDiskEnum 148
+#define RAP_TI_NetServerDiskGetInfo 149
+#define RAP_TI_FTVerifyMirror 150
+#define RAP_TI_FTAbortVerify 151
+#define RAP_TI_FTGetInfo 152
+#define RAP_TI_FTSetInfo 153
+#define RAP_TI_FTLockDisk 154
+#define RAP_TI_FTFixError 155
+#define RAP_TI_FTAbortFix 156
+#define RAP_TI_FTDiagnoseError 157
+#define RAP_TI_FTGetDriveStats 158
+#define RAP_TI_FTErrorGetInfo 160
+#define RAP_NetAccessCheck 163
+#define RAP_NetAlertRaise 164
+#define RAP_NetAlertStart 165
+#define RAP_NetAlertStop 166
+#define RAP_NetAuditWrite 167
+#define RAP_NetIRemoteAPI 168
+#define RAP_NetServiceStatus 169
+#define RAP_NetServerRegister 170
+#define RAP_NetServerDeregister 171
+#define RAP_NetSessionEntryMake 172
+#define RAP_NetSessionEntryClear 173
+#define RAP_NetSessionEntryGetInfo 174
+#define RAP_NetSessionEntrySetInfo 175
+#define RAP_NetConnectionEntryMake 176
+#define RAP_NetConnectionEntryClear 177
+#define RAP_NetConnectionEntrySetInfo 178
+#define RAP_NetConnectionEntryGetInfo 179
+#define RAP_NetFileEntryMake 180
+#define RAP_NetFileEntryClear 181
+#define RAP_NetFileEntrySetInfo 182
+#define RAP_NetFileEntryGetInfo 183
+#define RAP_AltSrvMessageBufferSend 184
+#define RAP_AltSrvMessageFileSend 185
+#define RAP_wI_NetRplWkstaEnum 186
+#define RAP_wI_NetRplWkstaGetInfo 187
+#define RAP_wI_NetRplWkstaSetInfo 188
+#define RAP_wI_NetRplWkstaAdd 189
+#define RAP_wI_NetRplWkstaDel 190
+#define RAP_wI_NetRplProfileEnum 191
+#define RAP_wI_NetRplProfileGetInfo 192
+#define RAP_wI_NetRplProfileSetInfo 193
+#define RAP_wI_NetRplProfileAdd 194
+#define RAP_wI_NetRplProfileDel 195
+#define RAP_wI_NetRplProfileClone 196
+#define RAP_wI_NetRplBaseProfileEnum 197
+#define RAP_WIServerSetInfo 201
+#define RAP_WPrintDriverEnum 205
+#define RAP_WPrintQProcessorEnum 206
+#define RAP_WPrintPortEnum 207
+#define RAP_WNetWriteUpdateLog 208
+#define RAP_WNetAccountUpdate 209
+#define RAP_WNetAccountConfirmUpdate 210
+#define RAP_WConfigSet 211
+#define RAP_WAccountsReplicate 212
+#define RAP_SamOEMChgPasswordUser2_P 214
+#define RAP_NetServerEnum3 215
+#define RAP_WprintDriverGetInfo 250
+#define RAP_WprintDriverSetInfo 251
+#define RAP_WaliasAdd 252
+#define RAP_WaliasDel 253
+#define RAP_WaliasGetInfo 254
+#define RAP_WaliasSetInfo 255
+#define RAP_WaliasEnum 256
+#define RAP_WuserGetLogonAsn 257
+#define RAP_WuserSetLogonAsn 258
+#define RAP_WuserGetAppSel 259
+#define RAP_WuserSetAppSel 260
+#define RAP_WappAdd 261
+#define RAP_WappDel 262
+#define RAP_WappGetInfo 263
+#define RAP_WappSetInfo 264
+#define RAP_WappEnum 265
+#define RAP_WUserDCDBInit 266
+#define RAP_WDASDAdd 267
+#define RAP_WDASDDel 268
+#define RAP_WDASDGetInfo 269
+#define RAP_WDASDSetInfo 270
+#define RAP_WDASDEnum 271
+#define RAP_WDASDCheck 272
+#define RAP_WDASDCtl 273
+#define RAP_WuserRemoteLogonCheck 274
+#define RAP_WUserPasswordSet3 275
+#define RAP_WCreateRIPLMachine 276
+#define RAP_WDeleteRIPLMachine 277
+#define RAP_WGetRIPLMachineInfo 278
+#define RAP_WSetRIPLMachineInfo 279
+#define RAP_WEnumRIPLMachine 280
+#define RAP_I_ShareAdd 281
+#define RAP_AliasEnum 282
+#define RAP_WaccessApply 283
+#define RAP_WPrt16Query 284
+#define RAP_WPrt16Set 285
+#define RAP_WUserDel100 286
+#define RAP_WUserRemoteLogonCheck2 287
+#define RAP_WRemoteTODSet 294
+#define RAP_WprintJobMoveAll 295
+#define RAP_W16AppParmAdd 296
+#define RAP_W16AppParmDel 297
+#define RAP_W16AppParmGet 298
+#define RAP_W16AppParmSet 299
+#define RAP_W16RIPLMachineCreate 300
+#define RAP_W16RIPLMachineGetInfo 301
+#define RAP_W16RIPLMachineSetInfo 302
+#define RAP_W16RIPLMachineEnum 303
+#define RAP_W16RIPLMachineListParmEnum 304
+#define RAP_W16RIPLMachClassGetInfo 305
+#define RAP_W16RIPLMachClassEnum 306
+#define RAP_W16RIPLMachClassCreate 307
+#define RAP_W16RIPLMachClassSetInfo 308
+#define RAP_W16RIPLMachClassDelete 309
+#define RAP_W16RIPLMachClassLPEnum 310
+#define RAP_W16RIPLMachineDelete 311
+#define RAP_W16WSLevelGetInfo 312
+#define RAP_WserverNameAdd 313
+#define RAP_WserverNameDel 314
+#define RAP_WserverNameEnum 315
+#define RAP_I_WDASDEnum 316
+#define RAP_WDASDEnumTerminate 317
+#define RAP_WDASDSetInfo2 318
+#define MAX_API 318
+
+
+/* Parameter description strings for RAP calls */
+/* Names are defined name for RAP call with _REQ */
+/* appended to end. */
+
+#define RAP_WFileEnum2_REQ "zzWrLehb8g8"
+#define RAP_WFileGetInfo2_REQ "DWrLh"
+#define RAP_WFileClose2_REQ "D"
+
+#define RAP_NetGroupEnum_REQ "WrLeh"
+#define RAP_NetGroupAdd_REQ "WsT"
+#define RAP_NetGroupDel_REQ "z"
+#define RAP_NetGroupAddUser_REQ "zz"
+#define RAP_NetGroupDelUser_REQ "zz"
+#define RAP_NetGroupGetUsers_REQ "zWrLeh"
+#define RAP_NetGroupSetUsers_REQ "zWsTW"
+
+#define RAP_NetUserAdd2_REQ "WsTWW"
+#define RAP_NetUserEnum_REQ "WrLeh"
+#define RAP_NetUserEnum2_REQ "WrLDieh"
+#define RAP_NetUserGetGroups_REQ "zWrLeh"
+#define RAP_NetUserSetGroups_REQ "zWsTW"
+#define RAP_NetUserPasswordSet_REQ "zb16b16w"
+#define RAP_NetUserPasswordSet2_REQ "zb16b16WW"
+#define RAP_SAMOEMChgPasswordUser2_REQ "B516B16"
+#define RAP_NetUserValidate2_REQ "Wb62WWrLhWW"
+
+#define RAP_NetServerEnum2_REQ "WrLehDz"
+#define RAP_WserverGetInfo_REQ "WrLh"
+#define RAP_NetWkstatGetInfo "WrLh"
+
+#define RAP_WShareAdd_REQ "WsT"
+#define RAP_WShareEnum_REQ "WrLeh"
+#define RAP_WShareDel_REQ "zW"
+#define RAP_WWkstaGetInfo_REQ "WrLh"
+
+#define RAP_NetPrintQEnum_REQ "WrLeh"
+#define RAP_NetPrintQGetInfo_REQ "zWrLh"
+
+#define RAP_NetServerAdminCommand_REQ "zhrLeh"
+#define RAP_NetServiceEnum_REQ "WrLeh"
+#define RAP_NetServiceControl_REQ "zWWrL"
+#define RAP_NetServiceInstall_REQ "zF88sg88T"
+#define RAP_NetServiceGetInfo_REQ "zWrLh"
+#define RAP_NetSessionEnum_REQ "WrLeh"
+#define RAP_NetSessionGetInfo_REQ "zWrLh"
+#define RAP_NetSessionDel_REQ "zW"
+
+#define RAP_NetConnectionEnum_REQ "zWrLeh"
+
+#define RAP_NetWkstaUserLogoff_REQ "zzWb38WrLh"
+
+/* Description strings for returned data in RAP calls */
+/* I use all caps here in part to avoid accidental */
+/* name collisions */
+
+#define RAP_FILE_INFO_L2 "D"
+#define RAP_FILE_INFO_L3 "DWWzz"
+
+#define RAP_GROUP_INFO_L0 "B21"
+#define RAP_GROUP_INFO_L1 "B21Bz"
+#define RAP_GROUP_USERS_INFO_0 "B21"
+#define RAP_GROUP_USERS_INFO_1 "B21BN"
+
+#define RAP_USER_INFO_L0 "B21"
+#define RAP_USER_INFO_L1 "B21BB16DWzzWz"
+
+#define RAP_SERVER_INFO_L0 "B16"
+#define RAP_SERVER_INFO_L1 "B16BBDz"
+#define RAP_SERVER_INFO_L2 "B16BBDzDDDWWzWWWWWWWB21BzWWWWWWWWWWWWWWWWWWWWWWz"
+#define RAP_SERVER_INFO_L3 "B16BBDzDDDWWzWWWWWWWB21BzWWWWWWWWWWWWWWWWWWWWWWzDWz"
+#define RAP_SERVICE_INFO_L0 "B16"
+#define RAP_SERVICE_INFO_L2 "B16WDWB64"
+#define RAP_SHARE_INFO_L0 "B13"
+#define RAP_SHARE_INFO_L1 "B13BWz"
+#define RAP_SHARE_INFO_L2 "B13BWzWWWzB9B"
+
+#define RAP_PRINTQ_INFO_L2 "B13BWWWzzzzzWN"
+#define RAP_SMB_PRINT_JOB_L1 "WB21BB16B10zWWzDDz"
+
+#define RAP_SESSION_INFO_L2 "zzWWWDDDz"
+#define RAP_CONNECTION_INFO_L1 "WWWWDzz"
+
+#define RAP_USER_LOGOFF_INFO_L1 "WDW"
+
+#define RAP_WKSTA_INFO_L1 "WDzzzzBBDWDWWWWWWWWWWWWWWWWWWWzzWzzW"
+#define RAP_WKSTA_INFO_L10 "zzzBBzz"
+
+/* BB explicit packing would help in structs below */
+
+/* sizes of fixed-length fields, including null terminator */
+#define RAP_GROUPNAME_LEN 21
+#define RAP_USERNAME_LEN 21
+#define RAP_SHARENAME_LEN 13
+#define RAP_UPASSWD_LEN 16 /* user password */
+#define RAP_SPASSWD_LEN 9 /* share password */
+#define RAP_MACHNAME_LEN 16
+#define RAP_SRVCNAME_LEN 16
+#define RAP_SRVCCMNT_LEN 64
+#define RAP_DATATYPE_LEN 10
+
+
+typedef struct rap_group_info_1
+{
+ char group_name[RAP_GROUPNAME_LEN];
+ char reserved1;
+ char * comment;
+} RAP_GROUP_INFO_1;
+
+typedef struct rap_user_info_1
+{
+ char user_name[RAP_USERNAME_LEN];
+ char reserved1;
+ char passwrd[RAP_UPASSWD_LEN];
+ uint32 pwage;
+ uint16 priv;
+ char * home_dir;
+ char * comment;
+ uint16 userflags;
+ char * logon_script;
+} RAP_USER_INFO_1;
+
+typedef struct rap_service_info_2
+{
+ char service_name[RAP_SRVCNAME_LEN];
+ uint16 status;
+ uint32 installcode;
+ uint16 process_num;
+ char * comment;
+} RAP_SERVICE_INFO_2;
+
+
+typedef struct rap_share_info_0
+{
+ char share_name[RAP_SHARENAME_LEN];
+} RAP_SHARE_INFO_0;
+
+typedef struct rap_share_info_1
+{
+ char share_name[RAP_SHARENAME_LEN];
+ char reserved1;
+ uint16 share_type;
+ char * comment;
+} RAP_SHARE_INFO_1;
+
+typedef struct rap_share_info_2
+{
+ char share_name[RAP_SHARENAME_LEN];
+ char reserved1;
+ uint16 share_type;
+ char * comment;
+ uint16 perms;
+ uint16 maximum_users;
+ uint16 active_users;
+ char * path;
+ char password[RAP_SPASSWD_LEN];
+ char reserved2;
+} RAP_SHARE_INFO_2;
+
+#endif /* _RAP_H_ */
diff --git a/source3/include/rbtree.h b/source3/include/rbtree.h
new file mode 100644
index 0000000000..1cfd3463a0
--- /dev/null
+++ b/source3/include/rbtree.h
@@ -0,0 +1,132 @@
+/*
+ Red Black Trees
+ (C) 1999 Andrea Arcangeli <andrea@suse.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You 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
+
+ linux/include/linux/rbtree.h
+
+ To use rbtrees you'll have to implement your own insert and search cores.
+ This will avoid us to use callbacks and to drop drammatically performances.
+ I know it's not the cleaner way, but in C (not in C++) to get
+ performances and genericity...
+
+ Some example of insert and search follows here. The search is a plain
+ normal search over an ordered tree. The insert instead must be implemented
+ int two steps: as first thing the code must insert the element in
+ order as a red leaf in the tree, then the support library function
+ rb_insert_color() must be called. Such function will do the
+ not trivial work to rebalance the rbtree if necessary.
+
+-----------------------------------------------------------------------
+static inline struct page * rb_search_page_cache(struct inode * inode,
+ unsigned long offset)
+{
+ struct rb_node * n = inode->i_rb_page_cache.rb_node;
+ struct page * page;
+
+ while (n)
+ {
+ page = rb_entry(n, struct page, rb_page_cache);
+
+ if (offset < page->offset)
+ n = n->rb_left;
+ else if (offset > page->offset)
+ n = n->rb_right;
+ else
+ return page;
+ }
+ return NULL;
+}
+
+static inline struct page * __rb_insert_page_cache(struct inode * inode,
+ unsigned long offset,
+ struct rb_node * node)
+{
+ struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
+ struct rb_node * parent = NULL;
+ struct page * page;
+
+ while (*p)
+ {
+ parent = *p;
+ page = rb_entry(parent, struct page, rb_page_cache);
+
+ if (offset < page->offset)
+ p = &(*p)->rb_left;
+ else if (offset > page->offset)
+ p = &(*p)->rb_right;
+ else
+ return page;
+ }
+
+ rb_link_node(node, parent, p);
+
+ return NULL;
+}
+
+static inline struct page * rb_insert_page_cache(struct inode * inode,
+ unsigned long offset,
+ struct rb_node * node)
+{
+ struct page * ret;
+ if ((ret = __rb_insert_page_cache(inode, offset, node)))
+ goto out;
+ rb_insert_color(node, &inode->i_rb_page_cache);
+ out:
+ return ret;
+}
+-----------------------------------------------------------------------
+*/
+
+#ifndef _LINUX_RBTREE_H
+#define _LINUX_RBTREE_H
+
+struct rb_node
+{
+ unsigned long rb_parent_color;
+ struct rb_node *rb_right;
+ struct rb_node *rb_left;
+};
+
+struct rb_root
+{
+ struct rb_node *rb_node;
+};
+
+
+#define RB_ROOT (struct rb_root) { NULL, }
+
+#if 0
+#define rb_entry(ptr, type, member) container_of(ptr, type, member)
+#endif
+
+void rb_insert_color(struct rb_node *, struct rb_root *);
+void rb_erase(struct rb_node *, struct rb_root *);
+
+/* Find logical next and previous nodes in a tree */
+struct rb_node *rb_next(struct rb_node *);
+struct rb_node *rb_prev(struct rb_node *);
+struct rb_node *rb_first(struct rb_root *);
+struct rb_node *rb_last(struct rb_root *);
+
+/* Fast replacement of a single node without remove/rebalance/add/rebalance */
+extern void rb_replace_node(struct rb_node *victim, struct rb_node *new_node,
+ struct rb_root *root);
+
+void rb_link_node(struct rb_node * node, struct rb_node * parent,
+ struct rb_node ** rb_link);
+
+#endif /* _LINUX_RBTREE_H */
diff --git a/source3/include/reg_db.h b/source3/include/reg_db.h
new file mode 100644
index 0000000000..92448ae543
--- /dev/null
+++ b/source3/include/reg_db.h
@@ -0,0 +1,30 @@
+/*
+ Parameters for Samba's Internal Registry Database
+
+ Copyright (C) Michael Adam 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _REG_DB_H
+#define _REG_DB_H
+
+#define REG_TDB_FLAGS TDB_SEQNUM
+
+#define REGVER_V1 1 /* first db version with write support */
+
+#define REG_VALUE_PREFIX "SAMBA_REGVAL"
+#define REG_SECDESC_PREFIX "SAMBA_SECDESC"
+
+#endif /* _REG_DB_H */
diff --git a/source3/include/reg_objects.h b/source3/include/reg_objects.h
new file mode 100644
index 0000000000..d9159dd464
--- /dev/null
+++ b/source3/include/reg_objects.h
@@ -0,0 +1,172 @@
+/*
+ Samba's Internal Registry objects
+
+ SMB parameters and setup
+ Copyright (C) Gerald Carter 2002-2006.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _REG_OBJECTS_H /* _REG_OBJECTS_H */
+#define _REG_OBJECTS_H
+
+/* structure to contain registry values */
+
+typedef struct {
+ fstring valuename;
+ uint16 type;
+ /* this should be encapsulated in an RPC_DATA_BLOB */
+ uint32 size; /* in bytes */
+ uint8 *data_p;
+} REGISTRY_VALUE;
+
+/*
+ * A REG_SZ string is not necessarily NULL terminated. When retrieving it from
+ * the net, we guarantee this however. A server might want to push it without
+ * the terminator though.
+ */
+
+struct registry_string {
+ size_t len;
+ char *str;
+};
+
+struct registry_value {
+ enum winreg_Type type;
+ union {
+ uint32 dword;
+ uint64 qword;
+ struct registry_string sz;
+ struct {
+ uint32 num_strings;
+ char **strings;
+ } multi_sz;
+ DATA_BLOB binary;
+ } v;
+};
+
+/* container for registry values */
+
+typedef struct {
+ uint32 num_values;
+ REGISTRY_VALUE **values;
+ int seqnum;
+} REGVAL_CTR;
+
+/* container for registry subkey names */
+
+typedef struct {
+ uint32 num_subkeys;
+ char **subkeys;
+ int seqnum;
+} REGSUBKEY_CTR;
+
+/*
+ *
+ * Macros that used to reside in rpc_reg.h
+ *
+ */
+
+#define HKEY_CLASSES_ROOT 0x80000000
+#define HKEY_CURRENT_USER 0x80000001
+#define HKEY_LOCAL_MACHINE 0x80000002
+#define HKEY_USERS 0x80000003
+#define HKEY_PERFORMANCE_DATA 0x80000004
+
+#define KEY_HKLM "HKLM"
+#define KEY_HKU "HKU"
+#define KEY_HKCC "HKCC"
+#define KEY_HKCR "HKCR"
+#define KEY_HKPD "HKPD"
+#define KEY_HKPT "HKPT"
+#define KEY_HKPN "HKPN"
+#define KEY_HKCU "HKCU"
+#define KEY_HKDD "HKDD"
+#define KEY_SERVICES "HKLM\\SYSTEM\\CurrentControlSet\\Services"
+#define KEY_EVENTLOG "HKLM\\SYSTEM\\CurrentControlSet\\Services\\Eventlog"
+#define KEY_SHARES "HKLM\\SYSTEM\\CurrentControlSet\\Services\\LanmanServer\\Shares"
+#define KEY_NETLOGON_PARAMS "HKLM\\SYSTEM\\CurrentControlSet\\Services\\Netlogon\\Parameters"
+#define KEY_TCPIP_PARAMS "HKLM\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
+#define KEY_PROD_OPTIONS "HKLM\\SYSTEM\\CurrentControlSet\\Control\\ProductOptions"
+#define KEY_PRINTING "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Print"
+#define KEY_PRINTING_2K "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers"
+#define KEY_PRINTING_PORTS "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Ports"
+#define KEY_CURRENT_VERSION "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
+#define KEY_PERFLIB "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib"
+#define KEY_PERFLIB_009 "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009"
+#define KEY_GROUP_POLICY "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Group Policy"
+#define KEY_WINLOGON "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"
+#define KEY_SMBCONF "HKLM\\SOFTWARE\\Samba\\smbconf"
+#define KEY_SAMBA_GROUP_POLICY "HKLM\\SOFTWARE\\Samba\\Group Policy"
+#define KEY_TREE_ROOT ""
+
+#define KEY_GP_MACHINE_POLICY "HKLM\\Software\\Policies"
+#define KEY_GP_MACHINE_WIN_POLICY "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies"
+#define KEY_GP_USER_POLICY "HKCU\\Software\\Policies"
+#define KEY_GP_USER_WIN_POLICY "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies"
+/*
+ * Registry key types
+ * Most keys are going to be GENERIC -- may need a better name?
+ * HKPD and HKPT are used by reg_perfcount.c
+ * they are special keys that contain performance data
+ */
+#define REG_KEY_GENERIC 0
+#define REG_KEY_HKPD 1
+#define REG_KEY_HKPT 2
+
+/*
+ * container for function pointers to enumeration routines
+ * for virtual registry view
+ */
+
+typedef struct {
+ /* functions for enumerating subkeys and values */
+ int (*fetch_subkeys)( const char *key, REGSUBKEY_CTR *subkeys);
+ int (*fetch_values) ( const char *key, REGVAL_CTR *val );
+ bool (*store_subkeys)( const char *key, REGSUBKEY_CTR *subkeys );
+ bool (*store_values)( const char *key, REGVAL_CTR *val );
+ bool (*reg_access_check)( const char *keyname, uint32 requested,
+ uint32 *granted,
+ const NT_USER_TOKEN *token );
+ WERROR (*get_secdesc)(TALLOC_CTX *mem_ctx, const char *key,
+ struct security_descriptor **psecdesc);
+ WERROR (*set_secdesc)(const char *key,
+ struct security_descriptor *sec_desc);
+ bool (*subkeys_need_update)(REGSUBKEY_CTR *subkeys);
+ bool (*values_need_update)(REGVAL_CTR *values);
+} REGISTRY_OPS;
+
+typedef struct {
+ const char *keyname; /* full path to name of key */
+ REGISTRY_OPS *ops; /* registry function hooks */
+} REGISTRY_HOOK;
+
+
+/* structure to store the registry handles */
+
+typedef struct _RegistryKey {
+ uint32 type;
+ char *name; /* full name of registry key */
+ uint32 access_granted;
+ REGISTRY_OPS *ops;
+} REGISTRY_KEY;
+
+struct registry_key {
+ REGISTRY_KEY *key;
+ REGSUBKEY_CTR *subkeys;
+ REGVAL_CTR *values;
+ struct nt_user_token *token;
+};
+
+#endif /* _REG_OBJECTS_H */
diff --git a/source3/include/regfio.h b/source3/include/regfio.h
new file mode 100644
index 0000000000..63516a358d
--- /dev/null
+++ b/source3/include/regfio.h
@@ -0,0 +1,222 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Windows NT registry I/O library
+ * Copyright (c) Gerald (Jerry) Carter 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/************************************************************
+ * Most of this information was obtained from
+ * http://www.wednesday.demon.co.uk/dosreg.html
+ * Thanks Nigel!
+ ***********************************************************/
+
+
+#ifndef _REGFIO_H
+#define _REGFIO_H
+
+/* Macros */
+
+#define REGF_BLOCKSIZE 0x1000
+#define REGF_ALLOC_BLOCK 0x1000
+
+/* header sizes for various records */
+
+#define REGF_HDR_SIZE 4
+#define HBIN_HDR_SIZE 4
+#define HBIN_HEADER_REC_SIZE 0x24
+#define REC_HDR_SIZE 2
+
+#define REGF_OFFSET_NONE 0xffffffff
+
+/* Flags for the vk records */
+
+#define VK_FLAG_NAME_PRESENT 0x0001
+#define VK_DATA_IN_OFFSET 0x80000000
+
+/* NK record macros */
+
+#define NK_TYPE_LINKKEY 0x0010
+#define NK_TYPE_NORMALKEY 0x0020
+#define NK_TYPE_ROOTKEY 0x002c
+
+#define HBIN_STORE_REF(x, y) { x->hbin = y; y->ref_count++ };
+#define HBIN_REMOVE_REF(x, y) { x->hbin = NULL; y->ref_count-- /* if the count == 0; we can clean up */ };
+
+
+/* HBIN block */
+struct regf_hbin;
+typedef struct regf_hbin {
+ struct regf_hbin *prev, *next;
+ uint32 file_off; /* my offset in the registry file */
+ uint32 free_off; /* offset to free space within the hbin record */
+ uint32 free_size; /* amount of data left in the block */
+ int ref_count; /* how many active records are pointing to this block (not used currently) */
+
+ char header[HBIN_HDR_SIZE]; /* "hbin" */
+ uint32 first_hbin_off; /* offset from first hbin block */
+ uint32 block_size; /* block size of this blockually a multiple of 4096Kb) */
+
+ prs_struct ps; /* data */
+
+ bool dirty; /* has this hbin block been modified? */
+} REGF_HBIN;
+
+/* ??? List -- list of key offsets and hashed names for consistency */
+
+typedef struct {
+ uint32 nk_off;
+ uint8 keycheck[sizeof(uint32)];
+ char *fullname;
+} REGF_HASH_REC;
+
+typedef struct {
+ REGF_HBIN *hbin; /* pointer to HBIN record (in memory) containing this nk record */
+ uint32 hbin_off; /* offset from beginning of this hbin block */
+ uint32 rec_size; /* ((start_offset - end_offset) & 0xfffffff8) */
+
+ char header[REC_HDR_SIZE];
+ uint16 num_keys;
+ REGF_HASH_REC *hashes;
+} REGF_LF_REC;
+
+/* Key Value */
+
+typedef struct {
+ REGF_HBIN *hbin; /* pointer to HBIN record (in memory) containing this nk record */
+ uint32 hbin_off; /* offset from beginning of this hbin block */
+ uint32 rec_size; /* ((start_offset - end_offset) & 0xfffffff8) */
+ uint32 rec_off; /* offset stored in the value list */
+
+ char header[REC_HDR_SIZE];
+ char *valuename;
+ uint32 data_size;
+ uint32 data_off;
+ uint8 *data;
+ uint32 type;
+ uint16 flag;
+} REGF_VK_REC;
+
+
+/* Key Security */
+struct _regf_sk_rec;
+
+typedef struct _regf_sk_rec {
+ struct _regf_sk_rec *next, *prev;
+ REGF_HBIN *hbin; /* pointer to HBIN record (in memory) containing this nk record */
+ uint32 hbin_off; /* offset from beginning of this hbin block */
+ uint32 rec_size; /* ((start_offset - end_offset) & 0xfffffff8) */
+
+ uint32 sk_off; /* offset parsed from NK record used as a key
+ to lookup reference to this SK record */
+
+ char header[REC_HDR_SIZE];
+ uint32 prev_sk_off;
+ uint32 next_sk_off;
+ uint32 ref_count;
+ uint32 size;
+ SEC_DESC *sec_desc;
+} REGF_SK_REC;
+
+/* Key Name */
+
+typedef struct {
+ REGF_HBIN *hbin; /* pointer to HBIN record (in memory) containing this nk record */
+ uint32 hbin_off; /* offset from beginning of this hbin block */
+ uint32 subkey_index; /* index to next subkey record to return */
+ uint32 rec_size; /* ((start_offset - end_offset) & 0xfffffff8) */
+
+ /* header information */
+
+ char header[REC_HDR_SIZE];
+ uint16 key_type;
+ NTTIME mtime;
+ uint32 parent_off; /* back pointer in registry hive */
+ uint32 classname_off;
+ char *classname;
+ char *keyname;
+
+ /* max lengths */
+
+ uint32 max_bytes_subkeyname; /* max subkey name * 2 */
+ uint32 max_bytes_subkeyclassname; /* max subkey classname length (as if) */
+ uint32 max_bytes_valuename; /* max valuename * 2 */
+ uint32 max_bytes_value; /* max value data size */
+
+ /* unknowns */
+
+ uint32 unk_index; /* nigel says run time index ? */
+
+ /* children */
+
+ uint32 num_subkeys;
+ uint32 subkeys_off; /* hash records that point to NK records */
+ uint32 num_values;
+ uint32 values_off; /* value lists which point to VK records */
+ uint32 sk_off; /* offset to SK record */
+
+ /* link in the other records here */
+
+ REGF_LF_REC subkeys;
+ REGF_VK_REC *values;
+ REGF_SK_REC *sec_desc;
+
+} REGF_NK_REC;
+
+/* REGF block */
+
+typedef struct {
+ /* run time information */
+
+ int fd; /* file descriptor */
+ int open_flags; /* flags passed to the open() call */
+ TALLOC_CTX *mem_ctx; /* memory context for run-time file access information */
+ REGF_HBIN *block_list; /* list of open hbin blocks */
+
+ /* file format information */
+
+ char header[REGF_HDR_SIZE]; /* "regf" */
+ uint32 data_offset; /* offset to record in the first (or any?) hbin block */
+ uint32 last_block; /* offset to last hbin block in file */
+ uint32 checksum; /* XOR of bytes 0x0000 - 0x01FB */
+ NTTIME mtime;
+
+ REGF_SK_REC *sec_desc_list; /* list of security descriptors referenced by NK records */
+
+ /* unknowns used to simply writing */
+
+ uint32 unknown1;
+ uint32 unknown2;
+ uint32 unknown3;
+ uint32 unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+
+} REGF_FILE;
+
+/* Function Declarations */
+
+REGF_FILE* regfio_open( const char *filename, int flags, int mode );
+int regfio_close( REGF_FILE *r );
+
+REGF_NK_REC* regfio_rootkey( REGF_FILE *file );
+REGF_NK_REC* regfio_fetch_subkey( REGF_FILE *file, REGF_NK_REC *nk );
+REGF_NK_REC* regfio_write_key ( REGF_FILE *file, const char *name,
+ REGVAL_CTR *values, REGSUBKEY_CTR *subkeys,
+ SEC_DESC *sec_desc, REGF_NK_REC *parent );
+
+
+#endif /* _REGFIO_H */
+
diff --git a/source3/include/rpc_client.h b/source3/include/rpc_client.h
new file mode 100644
index 0000000000..684044b871
--- /dev/null
+++ b/source3/include/rpc_client.h
@@ -0,0 +1,74 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup
+ Copyright (C) Gerald (Jerry) Carter 2005.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _RPC_CLIENT_H
+#define _RPC_CLIENT_H
+
+/* autogenerated client stubs */
+
+#include "librpc/gen_ndr/cli_echo.h"
+#include "librpc/gen_ndr/cli_lsa.h"
+#include "librpc/gen_ndr/cli_svcctl.h"
+#include "librpc/gen_ndr/cli_wkssvc.h"
+#include "librpc/gen_ndr/cli_eventlog.h"
+#include "librpc/gen_ndr/cli_dfs.h"
+#include "librpc/gen_ndr/cli_initshutdown.h"
+#include "librpc/gen_ndr/cli_winreg.h"
+#include "librpc/gen_ndr/cli_srvsvc.h"
+#include "librpc/gen_ndr/cli_samr.h"
+#include "librpc/gen_ndr/cli_netlogon.h"
+#include "librpc/gen_ndr/cli_dssetup.h"
+#include "librpc/gen_ndr/cli_ntsvcs.h"
+#include "librpc/gen_ndr/cli_epmapper.h"
+#include "librpc/gen_ndr/cli_drsuapi.h"
+
+#define prs_init_empty( _ps_, _ctx_, _io_ ) (void) prs_init((_ps_), 0, (_ctx_), (_io_))
+
+/* macro to expand cookie-cutter code in cli_xxx() using rpc_api_pipe_req() */
+
+#define CLI_DO_RPC_WERR( pcli, ctx, interface, opnum, q_in, r_out, \
+ q_ps, r_ps, q_io_fn, r_io_fn, default_error ) \
+{\
+ SMB_ASSERT(ndr_syntax_id_equal(&pcli->abstract_syntax, interface)); \
+ if (!prs_init( &q_ps, RPC_MAX_PDU_FRAG_LEN, ctx, MARSHALL )) { \
+ return WERR_NOMEM;\
+ }\
+ prs_init_empty( &r_ps, ctx, UNMARSHALL );\
+ if ( q_io_fn("", &q_in, &q_ps, 0) ) {\
+ NTSTATUS _smb_pipe_stat_ = rpc_api_pipe_req(pcli, opnum, &q_ps, &r_ps); \
+ if (!NT_STATUS_IS_OK(_smb_pipe_stat_)) {\
+ prs_mem_free( &q_ps );\
+ prs_mem_free( &r_ps );\
+ return ntstatus_to_werror(_smb_pipe_stat_);\
+ }\
+ if (!r_io_fn("", &r_out, &r_ps, 0)) {\
+ prs_mem_free( &q_ps );\
+ prs_mem_free( &r_ps );\
+ return default_error;\
+ }\
+ } else {\
+ prs_mem_free( &q_ps );\
+ prs_mem_free( &r_ps );\
+ return default_error;\
+ }\
+ prs_mem_free( &q_ps );\
+ prs_mem_free( &r_ps );\
+}
+
+#endif /* _RPC_CLIENT_H */
diff --git a/source3/include/rpc_dce.h b/source3/include/rpc_dce.h
new file mode 100644
index 0000000000..b63f0eac5e
--- /dev/null
+++ b/source3/include/rpc_dce.h
@@ -0,0 +1,310 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _DCE_RPC_H /* _DCE_RPC_H */
+#define _DCE_RPC_H
+
+/* DCE/RPC packet types */
+
+enum RPC_PKT_TYPE {
+ RPC_REQUEST = 0x00, /* Ordinary request. */
+ RPC_PING = 0x01, /* Connectionless is server alive ? */
+ RPC_RESPONSE = 0x02, /* Ordinary reply. */
+ RPC_FAULT = 0x03, /* Fault in processing of call. */
+ RPC_WORKING = 0x04, /* Connectionless reply to a ping when server busy. */
+ RPC_NOCALL = 0x05, /* Connectionless reply to a ping when server has lost part of clients call. */
+ RPC_REJECT = 0x06, /* Refuse a request with a code. */
+ RPC_ACK = 0x07, /* Connectionless client to server code. */
+ RPC_CL_CANCEL= 0x08, /* Connectionless cancel. */
+ RPC_FACK = 0x09, /* Connectionless fragment ack. Both client and server send. */
+ RPC_CANCEL_ACK = 0x0A, /* Server ACK to client cancel request. */
+ RPC_BIND = 0x0B, /* Bind to interface. */
+ RPC_BINDACK = 0x0C, /* Server ack of bind. */
+ RPC_BINDNACK = 0x0D, /* Server nack of bind. */
+ RPC_ALTCONT = 0x0E, /* Alter auth. */
+ RPC_ALTCONTRESP = 0x0F, /* Reply to alter auth. */
+ RPC_AUTH3 = 0x10, /* not the real name! this is undocumented! */
+ RPC_SHUTDOWN = 0x11, /* Server to client request to shutdown. */
+ RPC_CO_CANCEL= 0x12, /* Connection-oriented cancel request. */
+ RPC_ORPHANED = 0x13 /* Client telling server it's aborting a partially sent request or telling
+ server to stop sending replies. */
+};
+
+/* DCE/RPC flags */
+#define RPC_FLG_FIRST 0x01
+#define RPC_FLG_LAST 0x02
+#define RPC_FLG_NOCALL 0x20
+
+
+#define SMBD_NTLMSSP_NEG_FLAGS 0x000082b1 /* ALWAYS_SIGN|NEG_NTLM|NEG_LM|NEG_SEAL|NEG_SIGN|NEG_UNICODE */
+
+/* NTLMSSP signature version */
+#define NTLMSSP_SIGN_VERSION 0x01
+
+/* DCE RPC auth types - extended by Microsoft. */
+#define RPC_ANONYMOUS_AUTH_TYPE 0
+#define RPC_AUTH_TYPE_KRB5_1 1
+#define RPC_SPNEGO_AUTH_TYPE 9
+#define RPC_NTLMSSP_AUTH_TYPE 10
+#define RPC_KRB5_AUTH_TYPE 16 /* Not yet implemented. */
+#define RPC_SCHANNEL_AUTH_TYPE 68 /* 0x44 */
+
+/* DCE-RPC standard identifiers to indicate
+ signing or sealing of an RPC pipe */
+#define RPC_AUTH_LEVEL_NONE 1
+#define RPC_AUTH_LEVEL_CONNECT 2
+#define RPC_AUTH_LEVEL_CALL 3
+#define RPC_AUTH_LEVEL_PACKET 4
+#define RPC_AUTH_LEVEL_INTEGRITY 5
+#define RPC_AUTH_LEVEL_PRIVACY 6
+
+#if 0
+#define RPC_PIPE_AUTH_SIGN_LEVEL 0x5
+#define RPC_PIPE_AUTH_SEAL_LEVEL 0x6
+#endif
+
+#define DCERPC_FAULT_OP_RNG_ERROR 0x1c010002
+#define DCERPC_FAULT_UNK_IF 0x1c010003
+#define DCERPC_FAULT_INVALID_TAG 0x1c000006
+#define DCERPC_FAULT_CONTEXT_MISMATCH 0x1c00001a
+#define DCERPC_FAULT_OTHER 0x00000001
+#define DCERPC_FAULT_ACCESS_DENIED 0x00000005
+#define DCERPC_FAULT_CANT_PERFORM 0x000006d8
+#define DCERPC_FAULT_NDR 0x000006f7
+
+
+/* Netlogon schannel auth type and level */
+#define SCHANNEL_SIGN_SIGNATURE { 0x77, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 }
+#define SCHANNEL_SEAL_SIGNATURE { 0x77, 0x00, 0x7a, 0x00, 0xff, 0xff, 0x00, 0x00 }
+
+#define RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN 0x20
+#define RPC_AUTH_SCHANNEL_SIGN_ONLY_CHK_LEN 0x18
+
+/* The 7 here seems to be required to get Win2k not to downgrade us
+ to NT4. Actually, anything other than 1ff would seem to do... */
+#define NETLOGON_NEG_AUTH2_FLAGS 0x000701ff
+/*
+ (NETLOGON_NEG_ACCOUNT_LOCKOUT |
+ NETLOGON_NEG_PERSISTENT_SAMREPL |
+ NETLOGON_NEG_ARCFOUR |
+ NETLOGON_NEG_PROMOTION_COUNT |
+ NETLOGON_NEG_CHANGELOG_BDC |
+ NETLOGON_NEG_FULL_SYNC_REPL |
+ NETLOGON_NEG_MULTIPLE_SIDS |
+ NETLOGON_NEG_REDO |
+ NETLOGON_NEG_PASSWORD_CHANGE_REFUSAL |
+ NETLOGON_NEG_DNS_DOMAIN_TRUSTS |
+ NETLOGON_NEG_PASSWORD_SET2 |
+ NETLOGON_NEG_GETDOMAININFO)
+*/
+#define NETLOGON_NEG_DOMAIN_TRUST_ACCOUNT 0x2010b000
+
+/* these are the flags that ADS clients use */
+#define NETLOGON_NEG_AUTH2_ADS_FLAGS 0x600fffff
+/*
+ (NETLOGON_NEG_ACCOUNT_LOCKOUT |
+ NETLOGON_NEG_PERSISTENT_SAMREPL |
+ NETLOGON_NEG_ARCFOUR |
+ NETLOGON_NEG_PROMOTION_COUNT |
+ NETLOGON_NEG_CHANGELOG_BDC |
+ NETLOGON_NEG_FULL_SYNC_REPL |
+ NETLOGON_NEG_MULTIPLE_SIDS |
+ NETLOGON_NEG_REDO |
+ NETLOGON_NEG_PASSWORD_CHANGE_REFUSAL |
+ NETLOGON_NEG_SEND_PASSWORD_INFO_PDC |
+ NETLOGON_NEG_GENERIC_PASSTHROUGH |
+ NETLOGON_NEG_CONCURRENT_RPC |
+ NETLOGON_NEG_AVOID_ACCOUNT_DB_REPL |
+ NETLOGON_NEG_AVOID_SECURITYAUTH_DB_REPL |
+ NETLOGON_NEG_128BIT |
+ NETLOGON_NEG_TRANSITIVE_TRUSTS |
+ NETLOGON_NEG_DNS_DOMAIN_TRUSTS |
+ NETLOGON_NEG_PASSWORD_SET2 |
+ NETLOGON_NEG_GETDOMAININFO |
+ NETLOGON_NEG_CROSS_FOREST_TRUSTS |
+ NETLOGON_NEG_AUTHENTICATED_RPC_LSASS |
+ NETLOGON_NEG_SCHANNEL)
+*/
+
+enum schannel_direction {
+ SENDER_IS_INITIATOR,
+ SENDER_IS_ACCEPTOR
+};
+
+/* Maximum size of the signing data in a fragment. */
+#define RPC_MAX_SIGN_SIZE 0x20 /* 32 */
+
+/* Maximum PDU fragment size. */
+/* #define MAX_PDU_FRAG_LEN 0x1630 this is what wnt sets */
+#define RPC_MAX_PDU_FRAG_LEN 0x10b8 /* this is what w2k sets */
+
+/* RPC_IFACE */
+typedef struct ndr_syntax_id RPC_IFACE;
+
+extern const struct ndr_syntax_id syntax_spoolss;
+
+#define RPC_IFACE_LEN (UUID_SIZE + 4)
+
+/* RPC_HDR - dce rpc header */
+typedef struct rpc_hdr_info {
+ uint8 major; /* 5 - RPC major version */
+ uint8 minor; /* 0 - RPC minor version */
+ uint8 pkt_type; /* RPC_PKT_TYPE - RPC response packet */
+ uint8 flags; /* DCE/RPC flags */
+ uint8 pack_type[4]; /* 0x1000 0000 - little-endian packed data representation */
+ uint16 frag_len; /* fragment length - data size (bytes) inc header and tail. */
+ uint16 auth_len; /* 0 - authentication length */
+ uint32 call_id; /* call identifier. matches 12th uint32 of incoming RPC data. */
+} RPC_HDR;
+
+#define RPC_HEADER_LEN 16
+
+/* RPC_HDR_REQ - ms request rpc header */
+typedef struct rpc_hdr_req_info {
+ uint32 alloc_hint; /* allocation hint - data size (bytes) minus header and tail. */
+ uint16 context_id; /* presentation context identifier */
+ uint16 opnum; /* opnum */
+} RPC_HDR_REQ;
+
+#define RPC_HDR_REQ_LEN 8
+
+/* RPC_HDR_RESP - ms response rpc header */
+typedef struct rpc_hdr_resp_info {
+ uint32 alloc_hint; /* allocation hint - data size (bytes) minus header and tail. */
+ uint16 context_id; /* 0 - presentation context identifier */
+ uint8 cancel_count; /* 0 - cancel count */
+ uint8 reserved; /* 0 - reserved. */
+} RPC_HDR_RESP;
+
+#define RPC_HDR_RESP_LEN 8
+
+/* RPC_HDR_FAULT - fault rpc header */
+typedef struct rpc_hdr_fault_info {
+ NTSTATUS status;
+ uint32 reserved; /* 0x0000 0000 */
+} RPC_HDR_FAULT;
+
+#define RPC_HDR_FAULT_LEN 8
+
+/* this seems to be the same string name depending on the name of the pipe,
+ * but is more likely to be linked to the interface name
+ * "srvsvc", "\\PIPE\\ntsvcs"
+ * "samr", "\\PIPE\\lsass"
+ * "wkssvc", "\\PIPE\\wksvcs"
+ * "NETLOGON", "\\PIPE\\NETLOGON"
+ */
+/* RPC_ADDR_STR */
+typedef struct rpc_addr_info {
+ uint16 len; /* length of the string including null terminator */
+ fstring str; /* the string above in single byte, null terminated form */
+} RPC_ADDR_STR;
+
+/* RPC_HDR_BBA - bind acknowledge, and alter context response. */
+typedef struct rpc_hdr_bba_info {
+ uint16 max_tsize; /* maximum transmission fragment size (0x1630) */
+ uint16 max_rsize; /* max receive fragment size (0x1630) */
+ uint32 assoc_gid; /* associated group id (0x0) */
+} RPC_HDR_BBA;
+
+#define RPC_HDR_BBA_LEN 8
+
+/* RPC_HDR_AUTH */
+typedef struct rpc_hdr_auth_info {
+ uint8 auth_type; /* See XXX_AUTH_TYPE above. */
+ uint8 auth_level; /* See RPC_PIPE_AUTH_XXX_LEVEL above. */
+ uint8 auth_pad_len;
+ uint8 auth_reserved;
+ uint32 auth_context_id;
+} RPC_HDR_AUTH;
+
+#define RPC_HDR_AUTH_LEN 8
+
+/* this is TEMPORARILY coded up as a specific structure */
+/* this structure comes after the bind request */
+/* RPC_AUTH_SCHANNEL_NEG */
+typedef struct rpc_auth_schannel_neg_info {
+ uint32 type1; /* Always zero ? */
+ uint32 type2; /* Types 0x3 and 0x13 seen. Check AcquireSecurityContext() docs.... */
+ fstring domain; /* calling workstations's domain */
+ fstring myname; /* calling workstation's name */
+} RPC_AUTH_SCHANNEL_NEG;
+
+/* attached to the end of encrypted rpc requests and responses */
+/* RPC_AUTH_SCHANNEL_CHK */
+typedef struct rpc_auth_schannel_chk_info {
+ uint8 sig [8]; /* 77 00 7a 00 ff ff 00 00 */
+ uint8 packet_digest[8]; /* checksum over the packet, MD5'ed with session key */
+ uint8 seq_num[8]; /* verifier, seq num */
+ uint8 confounder[8]; /* random 8-byte nonce */
+} RPC_AUTH_SCHANNEL_CHK;
+
+typedef struct rpc_context {
+ uint16 context_id; /* presentation context identifier. */
+ uint8 num_transfer_syntaxes; /* the number of syntaxes */
+ RPC_IFACE abstract; /* num and vers. of interface client is using */
+ RPC_IFACE *transfer; /* Array of transfer interfaces. */
+} RPC_CONTEXT;
+
+/* RPC_BIND_REQ - ms req bind */
+typedef struct rpc_bind_req_info {
+ RPC_HDR_BBA bba;
+ uint8 num_contexts; /* the number of contexts */
+ RPC_CONTEXT *rpc_context;
+} RPC_HDR_RB;
+
+/*
+ * The following length is 8 bytes RPC_HDR_BBA_LEN +
+ * 4 bytes size of context count +
+ * (context_count * (4 bytes of context_id, size of transfer syntax count + RPC_IFACE_LEN bytes +
+ * (transfer_syntax_count * RPC_IFACE_LEN bytes)))
+ */
+
+#define RPC_HDR_RB_LEN(rpc_hdr_rb) (RPC_HDR_BBA_LEN + 4 + \
+ ((rpc_hdr_rb)->num_contexts) * (4 + RPC_IFACE_LEN + (((rpc_hdr_rb)->rpc_context->num_transfer_syntaxes)*RPC_IFACE_LEN)))
+
+/* RPC_RESULTS - can only cope with one reason, right now... */
+typedef struct rpc_results_info {
+ /* uint8[] # 4-byte alignment padding, against SMB header */
+
+ uint8 num_results; /* the number of results (0x01) */
+
+ /* uint8[] # 4-byte alignment padding, against SMB header */
+
+ uint16 result; /* result (0x00 = accept) */
+ uint16 reason; /* reason (0x00 = no reason specified) */
+} RPC_RESULTS;
+
+/* RPC_HDR_BA */
+typedef struct rpc_hdr_ba_info {
+ RPC_HDR_BBA bba;
+
+ RPC_ADDR_STR addr ; /* the secondary address string, as described earlier */
+ RPC_RESULTS res ; /* results and reasons */
+ RPC_IFACE transfer; /* the transfer syntax from the request */
+} RPC_HDR_BA;
+
+/* RPC_AUTH_VERIFIER */
+typedef struct rpc_auth_verif_info {
+ fstring signature; /* "NTLMSSP".. Ok, not quite anymore */
+ uint32 msg_type; /* NTLMSSP_MESSAGE_TYPE (1,2,3) and 5 for schannel */
+} RPC_AUTH_VERIFIER;
+
+#endif /* _DCE_RPC_H */
diff --git a/source3/include/rpc_eventlog.h b/source3/include/rpc_eventlog.h
new file mode 100644
index 0000000000..3f5d03ed63
--- /dev/null
+++ b/source3/include/rpc_eventlog.h
@@ -0,0 +1,123 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Marcin Krzysztof Porwit 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _RPC_EVENTLOG_H /* _RPC_EVENTLOG_H */
+#define _RPC_EVENTLOG_H
+
+/* opcodes */
+
+#define EVENTLOG_CLEAREVENTLOG 0x00
+#define EVENTLOG_CLOSEEVENTLOG 0x02
+#define EVENTLOG_GETNUMRECORDS 0x04
+#define EVENTLOG_GETOLDESTENTRY 0x05
+#define EVENTLOG_OPENEVENTLOG 0x07
+#define EVENTLOG_READEVENTLOG 0x0a
+
+/* Eventlog read flags */
+/* defined in librpc/gen_ndr/eventlog.h */
+
+/* Event types */
+/* defined in librpc/gen_ndr/eventlog.h */
+
+/* Defines for TDB keys */
+#define EVT_OLDEST_ENTRY "INFO/oldest_entry"
+#define EVT_NEXT_RECORD "INFO/next_record"
+#define EVT_VERSION "INFO/version"
+#define EVT_MAXSIZE "INFO/maxsize"
+#define EVT_RETENTION "INFO/retention"
+
+#define ELOG_APPL "Application"
+#define ELOG_SYS "System"
+#define ELOG_SEC "Security"
+
+typedef struct elog_tdb {
+ struct elog_tdb *prev, *next;
+ char *name;
+ TDB_CONTEXT *tdb;
+ int ref_count;
+} ELOG_TDB;
+
+#define ELOG_TDB_CTX(x) ((x)->tdb)
+
+
+#define EVENTLOG_DATABASE_VERSION_V1 1
+
+/***********************************/
+
+typedef struct
+{
+ POLICY_HND handle;
+ uint32 flags;
+ uint32 offset;
+ uint32 max_read_size;
+} EVENTLOG_Q_READ_EVENTLOG;
+
+typedef struct {
+ uint32 length;
+ uint32 reserved1;
+ uint32 record_number;
+ uint32 time_generated;
+ uint32 time_written;
+ uint32 event_id;
+ uint16 event_type;
+ uint16 num_strings;
+ uint16 event_category;
+ uint16 reserved2;
+ uint32 closing_record_number;
+ uint32 string_offset;
+ uint32 user_sid_length;
+ uint32 user_sid_offset;
+ uint32 data_length;
+ uint32 data_offset;
+} Eventlog_record;
+
+typedef struct {
+ uint32 source_name_len;
+ smb_ucs2_t *source_name;
+ uint32 computer_name_len;
+ smb_ucs2_t *computer_name;
+ uint32 sid_padding;
+ smb_ucs2_t *sid;
+ uint32 strings_len;
+ smb_ucs2_t *strings;
+ uint32 user_data_len;
+ char *user_data;
+ uint32 data_padding;
+} Eventlog_data_record;
+
+typedef struct eventlog_entry {
+ Eventlog_record record;
+ Eventlog_data_record data_record;
+ uint8 *data;
+ uint8 *end_of_data_padding;
+ struct eventlog_entry *next;
+} Eventlog_entry;
+
+typedef struct {
+ uint32 num_bytes_in_resp;
+ uint32 bytes_in_next_record;
+ uint32 num_records;
+ Eventlog_entry *entry;
+ uint8 *end_of_entries_padding;
+ uint32 sent_size;
+ uint32 real_size;
+ NTSTATUS status;
+} EVENTLOG_R_READ_EVENTLOG;
+
+#endif /* _RPC_EVENTLOG_H */
diff --git a/source3/include/rpc_lsa.h b/source3/include/rpc_lsa.h
new file mode 100644
index 0000000000..b4021afd0a
--- /dev/null
+++ b/source3/include/rpc_lsa.h
@@ -0,0 +1,59 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Paul Ashton 1997
+ Copyright (C) Gerald (Jerry) Carter 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _RPC_LSA_H /* _RPC_LSA_H */
+#define _RPC_LSA_H
+
+#define LSA_POLICY_ALL_ACCESS ( STANDARD_RIGHTS_REQUIRED_ACCESS |\
+ LSA_POLICY_VIEW_LOCAL_INFORMATION |\
+ LSA_POLICY_VIEW_AUDIT_INFORMATION |\
+ LSA_POLICY_GET_PRIVATE_INFORMATION |\
+ LSA_POLICY_TRUST_ADMIN |\
+ LSA_POLICY_CREATE_ACCOUNT |\
+ LSA_POLICY_CREATE_SECRET |\
+ LSA_POLICY_CREATE_PRIVILEGE |\
+ LSA_POLICY_SET_DEFAULT_QUOTA_LIMITS |\
+ LSA_POLICY_SET_AUDIT_REQUIREMENTS |\
+ LSA_POLICY_AUDIT_LOG_ADMIN |\
+ LSA_POLICY_SERVER_ADMIN |\
+ LSA_POLICY_LOOKUP_NAMES )
+
+
+#define LSA_POLICY_READ ( STANDARD_RIGHTS_READ_ACCESS |\
+ LSA_POLICY_VIEW_AUDIT_INFORMATION |\
+ LSA_POLICY_GET_PRIVATE_INFORMATION)
+
+#define LSA_POLICY_WRITE ( STD_RIGHT_READ_CONTROL_ACCESS |\
+ LSA_POLICY_TRUST_ADMIN |\
+ LSA_POLICY_CREATE_ACCOUNT |\
+ LSA_POLICY_CREATE_SECRET |\
+ LSA_POLICY_CREATE_PRIVILEGE |\
+ LSA_POLICY_SET_DEFAULT_QUOTA_LIMITS |\
+ LSA_POLICY_SET_AUDIT_REQUIREMENTS |\
+ LSA_POLICY_AUDIT_LOG_ADMIN |\
+ LSA_POLICY_SERVER_ADMIN)
+
+#define LSA_POLICY_EXECUTE ( STANDARD_RIGHTS_EXECUTE_ACCESS |\
+ LSA_POLICY_VIEW_LOCAL_INFORMATION |\
+ LSA_POLICY_LOOKUP_NAMES )
+
+#endif /* _RPC_LSA_H */
diff --git a/source3/include/rpc_misc.h b/source3/include/rpc_misc.h
new file mode 100644
index 0000000000..3a3c61ecec
--- /dev/null
+++ b/source3/include/rpc_misc.h
@@ -0,0 +1,342 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Paul Ashton 1997
+ Copyright (C) Gerald (Jerry) Carter 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _RPC_MISC_H /* _RPC_MISC_H */
+#define _RPC_MISC_H
+
+#define SMB_RPC_INTERFACE_VERSION 1
+#define PRS_POINTER_CAST bool (*)(const char*, prs_struct*, int, void*)
+
+enum unistr2_term_codes { UNI_FLAGS_NONE = 0, UNI_STR_TERMINATE = 1, UNI_MAXLEN_TERMINATE = 2, UNI_BROKEN_NON_NULL = 3, UNI_STR_DBLTERMINATE = 4 };
+
+
+
+/**********************************************************************
+ * well-known RIDs - Relative IDs
+ **********************************************************************/
+
+/* RIDs - Well-known users ... */
+#define DOMAIN_USER_RID_ADMIN (0x000001F4L)
+#define DOMAIN_USER_RID_GUEST (0x000001F5L)
+#define DOMAIN_USER_RID_KRBTGT (0x000001F6L)
+
+/* RIDs - well-known groups ... */
+#define DOMAIN_GROUP_RID_ADMINS (0x00000200L)
+#define DOMAIN_GROUP_RID_USERS (0x00000201L)
+#define DOMAIN_GROUP_RID_GUESTS (0x00000202L)
+#define DOMAIN_GROUP_RID_COMPUTERS (0x00000203L)
+
+#define DOMAIN_GROUP_RID_CONTROLLERS (0x00000204L)
+#define DOMAIN_GROUP_RID_CERT_ADMINS (0x00000205L)
+#define DOMAIN_GROUP_RID_SCHEMA_ADMINS (0x00000206L)
+#define DOMAIN_GROUP_RID_ENTERPRISE_ADMINS (0x00000207L)
+
+/* is the following the right number? I bet it is --simo
+#define DOMAIN_GROUP_RID_POLICY_ADMINS (0x00000208L)
+*/
+
+/* 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)
+#define BUILTIN_ALIAS_RID_RAS_SERVERS (0x00000229L)
+#define BUILTIN_ALIAS_RID_PRE_2K_ACCESS (0x0000022aL)
+
+
+/**********************************************************************
+ * Masks for mappings between unix uid and gid types and
+ * NT RIDS.
+ **********************************************************************/
+
+#define BASE_RID (0x000003E8L)
+
+/* 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
+
+
+
+/**********************************************************************
+ * RPC policy handle used pretty much everywhere
+ **********************************************************************/
+
+typedef struct policy_handle POLICY_HND;
+typedef struct {
+ uint32 ptr_hnd; /* pointer to enumeration handle */
+ uint32 handle; /* enumeration handle */
+} ENUM_HND;
+
+#define OUR_HANDLE(hnd) (((hnd)==NULL) ? "NULL" :\
+ ( IVAL((hnd)->uuid.node,2) == (uint32)sys_getpid() ? "OURS" : \
+ "OTHER")), ((unsigned int)IVAL((hnd)->uuid.node,2)),\
+ ((unsigned int)sys_getpid() )
+
+
+/**********************************************************************
+ * Buffer Headers -- use by SEC_DESC_BUF in winreg and netlogon code
+ **********************************************************************/
+
+/* TODO: replace this with an encompassing buffer structure */
+typedef struct {
+ uint32 buf_max_len;
+ uint32 buf_len;
+} BUFHDR;
+
+/* this is a BUFHDR + a pointer to a buffer */
+typedef struct {
+ uint32 info_level;
+ uint32 length; /* uint8 chars */
+ uint32 buffer;
+} BUFHDR2;
+
+/* generic buffer ? wrapped around void*? */
+typedef struct {
+ uint32 size;
+ uint32 buffer;
+} BUFHDR4;
+
+
+/**********************************************************************
+ * Buffers
+ **********************************************************************/
+
+/* buffer used by \winreg\ calls to fill in arbitrary REG_XXX values.
+ It *may* look like a UNISTR2 but it is *not*. This is not a goof
+ by the winreg developers. It is a generic buffer. buffer length
+ is stored in bytes (not # of uint16's) */
+
+typedef struct {
+ uint32 buf_max_len;
+ uint32 offset;
+ uint32 buf_len;
+ uint16 *buffer;
+} REGVAL_BUFFER;
+
+/* generic rpc version of the DATA_BLOB. Just a length and uint8 array */
+
+typedef struct {
+ uint32 buf_len;
+ uint8 *buffer;
+} RPC_DATA_BLOB;
+
+/**********************************************************************
+ * Buffers use by spoolss (i might be able to replace it with
+ * an RPC_DATA_BLOB)
+ **********************************************************************/
+
+typedef struct {
+ uint32 buf_len;
+ uint16 *buffer; /* data */
+} BUFFER5;
+
+
+/**********************************************************************
+ * Unicode and basic string headers
+ **********************************************************************/
+
+typedef struct {
+ uint16 str_str_len;
+ uint16 str_max_len;
+ uint32 buffer; /* non-zero */
+} STRHDR;
+
+typedef struct {
+ uint16 uni_str_len;
+ uint16 uni_max_len;
+ uint32 buffer;
+} UNIHDR;
+
+/**********************************************************************
+ * UNICODE string variations
+ **********************************************************************/
+
+
+typedef struct { /* UNISTR - unicode string size and buffer */
+ uint16 *buffer; /* unicode characters. ***MUST*** be
+ little-endian. ***MUST*** be null-terminated */
+} UNISTR;
+
+typedef struct { /* UNISTR2 - unicode string size (in
+ uint16 unicode chars) and buffer */
+ uint32 uni_max_len;
+ uint32 offset;
+ uint32 uni_str_len;
+ uint16 *buffer; /* unicode characters. ***MUST*** be little-endian.
+ **must** be null-terminated and the uni_str_len
+ should include the NULL character */
+} UNISTR2;
+
+/* i think this is the same as a BUFFER5 used in the spoolss code --jerry */
+/* not sure about how the termination matches between the uint16 buffers thought */
+
+typedef struct { /* UNISTR3 - XXXX not sure about this structure */
+ uint32 uni_str_len;
+ UNISTR str;
+} UNISTR3;
+
+typedef struct { /* Buffer wrapped around a UNISTR2 */
+ uint16 length; /* number of bytes not counting NULL terminatation */
+ uint16 size; /* number of bytes including NULL terminatation */
+ UNISTR2 *string;
+} UNISTR4;
+
+typedef struct {
+ uint32 count;
+ UNISTR4 *strings;
+} UNISTR4_ARRAY;
+
+
+/**********************************************************************
+ * String variations
+ **********************************************************************/
+
+typedef struct { /* STRING2 - string size (in uint8 chars) and buffer */
+ uint32 str_max_len;
+ uint32 offset;
+ uint32 str_str_len;
+ uint8 *buffer; /* uint8 characters. **NOT** necessarily null-terminated */
+} STRING2;
+
+
+
+
+/**********************************************************************
+ * Domain SID structures
+ **********************************************************************/
+
+typedef struct {
+ uint32 num_auths; /* length, bytes, including length of len :-) */
+ DOM_SID sid;
+} DOM_SID2;
+
+
+/**********************************************************************
+ * Domain SID structures
+ **********************************************************************/
+
+/* DOM_RID - domain RID structure for ntlsa pipe */
+typedef struct {
+ uint16 type; /* value is SID_NAME_USE enum */
+ uint32 rid;
+ uint32 rid_idx; /* referenced domain index */
+} DOM_RID;
+
+/* DOM_RID2 - second domain RID structure for ntlsa pipe */
+typedef struct {
+ uint16 type; /* value is SID_NAME_USE enum */
+ uint32 rid;
+ uint32 rid_idx; /* referenced domain index */
+ uint32 unknown;
+} DOM_RID2;
+
+typedef struct { /* DOM_RID3 - domain RID structure for samr pipe */
+ uint32 rid; /* domain-relative (to a SID) id */
+ uint32 type1; /* value is 0x1 */
+ uint32 ptr_type; /* undocumented pointer */
+ uint32 type2; /* value is 0x1 */
+ uint32 unk; /* value is 0x2 */
+} DOM_RID3;
+
+/* DOM_RID4 - rid + user attributes */
+typedef struct domrid4_info
+{
+ uint32 unknown;
+ uint16 attr;
+ uint32 rid; /* user RID */
+} DOM_RID4;
+
+/* DOM_GID - group id + user attributes */
+typedef struct {
+ uint32 g_rid; /* a group RID */
+ uint32 attr;
+} DOM_GID;
+
+/**********************************************************************
+ * ????
+ **********************************************************************/
+
+/* DOM_CLNT_SRV - client / server names */
+typedef struct clnt_srv_info {
+ uint32 undoc_buffer; /* undocumented 32 bit buffer pointer */
+ UNISTR2 uni_logon_srv; /* logon server name */
+ uint32 undoc_buffer2; /* undocumented 32 bit buffer pointer */
+ UNISTR2 uni_comp_name; /* client machine name */
+} DOM_CLNT_SRV;
+
+/* DOM_LOG_INFO - login info */
+typedef struct log_info {
+ uint32 undoc_buffer; /* undocumented 32 bit buffer pointer */
+ UNISTR2 uni_logon_srv; /* logon server name */
+ UNISTR2 uni_acct_name; /* account name */
+ uint16 sec_chan; /* secure channel type */
+ UNISTR2 uni_comp_name; /* client machine name */
+} DOM_LOG_INFO;
+
+/* DOM_CHAL - challenge info */
+typedef struct chal_info {
+ unsigned char data[8]; /* credentials */
+} DOM_CHAL;
+
+/* DOM_CREDs - timestamped client or server credentials */
+typedef struct cred_info {
+ DOM_CHAL challenge; /* credentials */
+ UTIME timestamp; /* credential time-stamp */
+} DOM_CRED;
+
+/* DOM_CLNT_INFO - client info */
+typedef struct clnt_info {
+ DOM_LOG_INFO login;
+ DOM_CRED cred;
+} DOM_CLNT_INFO;
+
+/* DOM_CLNT_INFO2 - client info */
+typedef struct clnt_info2 {
+ DOM_CLNT_SRV login;
+ uint32 ptr_cred;
+ DOM_CRED cred;
+} DOM_CLNT_INFO2;
+
+/* DOM_LOGON_ID - logon id */
+typedef struct logon_info {
+ uint32 low;
+ uint32 high;
+} DOM_LOGON_ID;
+
+/* OWF INFO */
+typedef struct owf_info {
+ uint8 data[16];
+} OWF_INFO;
+
+
+#endif /* _RPC_MISC_H */
diff --git a/source3/include/rpc_ntsvcs.h b/source3/include/rpc_ntsvcs.h
new file mode 100644
index 0000000000..0056d16eb9
--- /dev/null
+++ b/source3/include/rpc_ntsvcs.h
@@ -0,0 +1,69 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup
+ Copyright (C) Gerald (Jerry) Carter 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _RPC_NTSVCS_H /* _RPC_NTSVCS_H */
+#define _RPC_NTSVCS_H
+
+/* ntsvcs pipe */
+
+#define NTSVCS_GET_VERSION 0x02
+#define NTSVCS_VALIDATE_DEVICE_INSTANCE 0x06
+#define NTSVCS_GET_ROOT_DEVICE_INSTANCE 0x07
+#define NTSVCS_GET_DEVICE_LIST 0x0a
+#define NTSVCS_GET_DEVICE_LIST_SIZE 0x0b
+#define NTSVCS_GET_DEVICE_REG_PROPERTY 0x0d
+#define NTSVCS_HW_PROFILE_FLAGS 0x28
+#define NTSVCS_GET_HW_PROFILE_INFO 0x29
+#define NTSVCS_GET_VERSION_INTERNAL 0x3e
+
+
+/**************************/
+
+typedef struct {
+ UNISTR2 *devicename;
+ uint32 buffer_size;
+ uint32 flags;
+} NTSVCS_Q_GET_DEVICE_LIST;
+
+typedef struct {
+ UNISTR2 devicepath;
+ uint32 needed;
+ WERROR status;
+} NTSVCS_R_GET_DEVICE_LIST;
+
+/**************************/
+
+typedef struct {
+ UNISTR2 devicepath;
+ uint32 property;
+ uint32 unknown2;
+ uint32 buffer_size1;
+ uint32 buffer_size2;
+ uint32 unknown5;
+} NTSVCS_Q_GET_DEVICE_REG_PROPERTY;
+
+typedef struct {
+ uint32 unknown1;
+ REGVAL_BUFFER value;
+ uint32 size;
+ uint32 needed;
+ WERROR status;
+} NTSVCS_R_GET_DEVICE_REG_PROPERTY;
+
+#endif /* _RPC_NTSVCS_H */
diff --git a/source3/include/rpc_perfcount.h b/source3/include/rpc_perfcount.h
new file mode 100644
index 0000000000..0cb2fdc212
--- /dev/null
+++ b/source3/include/rpc_perfcount.h
@@ -0,0 +1,126 @@
+#ifndef _RPC_PERFCOUNT_H
+#define _RPC_PERFCOUNT_H
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005,
+ * Copyright (C) Gerald (Jerry) Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+typedef struct perf_counter_definition
+{
+ /* sizeof(PERF_COUNTER_DEFINITION) */
+ uint32 ByteLength;
+ uint32 CounterNameTitleIndex;
+ uint32 CounterNameTitlePointer;
+ uint32 CounterHelpTitleIndex;
+ uint32 CounterHelpTitlePointer;
+ uint32 DefaultScale;
+ uint32 DetailLevel;
+ uint32 CounterType;
+ uint32 CounterSize;
+ uint32 CounterOffset;
+}
+PERF_COUNTER_DEFINITION;
+
+typedef struct perf_counter_block
+{
+ /* Total size of the data block, including all data plus this header */
+ uint32 ByteLength;
+ uint8 *data;
+}
+PERF_COUNTER_BLOCK;
+
+typedef struct perf_instance_definition
+{
+ /* Total size of the instance definition, including the length of the terminated Name string */
+ uint32 ByteLength;
+ uint32 ParentObjectTitleIndex;
+ uint32 ParentObjectTitlePointer;
+ uint32 UniqueID;
+ /* From the start of the PERF_INSTANCE_DEFINITION, the byte offset to the start of the Name string */
+ uint32 NameOffset;
+ uint32 NameLength;
+ /* Unicode string containing the name for the instance */
+ uint8 *data;
+ PERF_COUNTER_BLOCK counter_data;
+}
+PERF_INSTANCE_DEFINITION;
+
+typedef struct perf_object_type
+{
+ /* Total size of the object block, including all PERF_INSTANCE_DEFINITIONs,
+ PERF_COUNTER_DEFINITIONs and PERF_COUNTER_BLOCKs in bytes */
+ uint32 TotalByteLength;
+ /* Size of this PERF_OBJECT_TYPE plus all PERF_COUNTER_DEFINITIONs in bytes */
+ uint32 DefinitionLength;
+ /* Size of this PERF_OBJECT_TYPE */
+ uint32 HeaderLength;
+ uint32 ObjectNameTitleIndex;
+ uint32 ObjectNameTitlePointer;
+ uint32 ObjectHelpTitleIndex;
+ uint32 ObjectHelpTitlePointer;
+ uint32 DetailLevel;
+ uint32 NumCounters;
+ uint32 DefaultCounter;
+ uint32 NumInstances;
+ uint32 CodePage;
+ uint64 PerfTime;
+ uint64 PerfFreq;
+ PERF_COUNTER_DEFINITION *counters;
+ PERF_INSTANCE_DEFINITION *instances;
+ PERF_COUNTER_BLOCK counter_data;
+}
+PERF_OBJECT_TYPE;
+
+/* PerfCounter Inner Buffer structs */
+typedef struct perf_data_block
+{
+ /* hardcoded to read "P.E.R.F" */
+ uint16 Signature[4];
+ uint32 LittleEndian;
+ /* both currently hardcoded to 1 */
+ uint32 Version;
+ uint32 Revision;
+ /* bytes of PERF_OBJECT_TYPE data, does NOT include the PERF_DATA_BLOCK */
+ uint32 TotalByteLength;
+ /* size of PERF_DATA_BLOCK including the uint8 *data */
+ uint32 HeaderLength;
+ /* number of PERF_OBJECT_TYPE structures encoded */
+ uint32 NumObjectTypes;
+ uint32 DefaultObject;
+ SYSTEMTIME SystemTime;
+ /* This will guarantee that we're on a 64-bit boundary before we encode
+ PerfTime, and having it there will make my offset math much easier. */
+ uint32 Padding;
+ /* Now when I'm marshalling this, I'll need to call prs_align_uint64()
+ before I start encodint the uint64 structs */
+ /* clock rate * seconds uptime */
+ uint64 PerfTime;
+ /* The clock rate of the CPU */
+ uint64 PerfFreq;
+ /* used for high-res timers -- for now PerfTime * 10e7 */
+ uint64 PerfTime100nSec;
+ uint32 SystemNameLength;
+ uint32 SystemNameOffset;
+ /* The SystemName, in unicode, terminated */
+ uint8* data;
+ PERF_OBJECT_TYPE *objects;
+}
+PERF_DATA_BLOCK;
+
+#endif /* _RPC_PERFCOUNT_H */
diff --git a/source3/include/rpc_perfcount_defs.h b/source3/include/rpc_perfcount_defs.h
new file mode 100644
index 0000000000..6c84c270e5
--- /dev/null
+++ b/source3/include/rpc_perfcount_defs.h
@@ -0,0 +1,93 @@
+#ifndef _RPC_PERFCOUNT_DEFS_H
+#define _RPC_PERFCOUNT_DEFS_H
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005,
+ * Copyright (C) Gerald (Jerry) Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * The following #defines match what is in winperf.h.
+ * See that include file for more details, or look up
+ * "Performance Data Format" on MSDN
+ *
+ * Rather than including them in rpc_perfcount.h, they
+ * were broken out into a separate .h file so that they
+ * can be included by other programs that need this info
+ * without pulling in everything else samba-related.
+ */
+
+#define PERF_NO_INSTANCES -1
+#define PERF_NO_UNIQUE_ID -1
+
+/* These determine the data size */
+#define PERF_SIZE_DWORD 0x00000000
+#define PERF_SIZE_LARGE 0x00000100
+#define PERF_SIZE_ZERO 0x00000200
+#define PERF_SIZE_VARIABLE_LEN 0x00000300
+
+/* These determine the usage of the counter */
+#define PERF_TYPE_NUMBER 0x00000000
+#define PERF_TYPE_COUNTER 0x00000400
+#define PERF_TYPE_TEXT 0x00000800
+#define PERF_TYPE_ZERO 0x00000C00
+
+/* If PERF_TYPE_NUMBER was selected, these provide display information */
+#define PERF_NUMBER_HEX 0x00000000
+#define PERF_NUMBER_DECIMAL 0x00010000
+#define PERF_NUMBER_DEC_1000 0x00020000
+
+/* If PERF_TYPE_COUNTER was selected, these provide display information */
+#define PERF_COUNTER_VALUE 0x00000000
+#define PERF_COUNTER_RATE 0x00010000
+#define PERF_COUNTER_FRACTION 0x00020000
+#define PERF_COUNTER_BASE 0x00030000
+#define PERF_COUNTER_ELAPSED 0x00040000
+#define PERF_COUNTER_QUEUELEN 0x00050000
+#define PERF_COUNTER_HISTOGRAM 0x00060000
+#define PERF_COUNTER_PRECISION 0x00070000
+
+/* If PERF_TYPE_TEXT was selected, these provide display information */
+#define PERF_TEXT_UNICODE 0x00000000
+#define PERF_TEXT_ASCII 0x00010000
+
+/* These provide information for which tick count to use when computing elapsed interval */
+#define PERF_TIMER_TICK 0x00000000
+#define PERF_TIMER_100NS 0x00100000
+#define PERF_OBJECT_TIMER 0x00200000
+
+/* These affect how the data is manipulated prior to being displayed */
+#define PERF_DELTA_COUNTER 0x00400000
+#define PERF_DELTA_BASE 0x00800000
+#define PERF_INVERSE_COUNTER 0x01000000
+#define PERF_MULTI_COUNTER 0x02000000
+
+/* These determine if any text gets added when the value is displayed */
+#define PERF_DISPLAY_NO_SUFFIX 0x00000000
+#define PERF_DISPLAY_PER_SEC 0x10000000
+#define PERF_DISPLAY_PERCENT 0x20000000
+#define PERF_DISPLAY_SECONDS 0x30000000
+#define PERF_DISPLAY_NOSHOW 0x40000000
+
+/* These determine the DetailLevel of the counter */
+#define PERF_DETAIL_NOVICE 100
+#define PERF_DETAIL_ADVANCED 200
+#define PERF_DETAIL_EXPERT 300
+#define PERF_DETAIL_WIZARD 400
+
+#endif /* _RPC_PERFCOUNT_DEFS_H */
diff --git a/source3/include/rpc_secdes.h b/source3/include/rpc_secdes.h
new file mode 100644
index 0000000000..83103b7386
--- /dev/null
+++ b/source3/include/rpc_secdes.h
@@ -0,0 +1,496 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _RPC_SECDES_H /* _RPC_SECDES_H */
+#define _RPC_SECDES_H
+
+/* for ADS */
+#define SEC_RIGHTS_LIST_CONTENTS 0x4
+#define SEC_RIGHTS_LIST_OBJECT 0x80
+#define SEC_RIGHTS_READ_ALL_PROP 0x10
+#define SEC_RIGHTS_READ_PERMS 0x20000
+#define SEC_RIGHTS_WRITE_ALL_VALID 0x8
+#define SEC_RIGHTS_WRITE_ALL_PROP 0x20
+#define SEC_RIGHTS_MODIFY_OWNER 0x80000
+#define SEC_RIGHTS_MODIFY_PERMS 0x40000
+#define SEC_RIGHTS_CREATE_CHILD 0x1
+#define SEC_RIGHTS_DELETE_CHILD 0x2
+#define SEC_RIGHTS_DELETE_SUBTREE 0x40
+#define SEC_RIGHTS_DELETE 0x10000 /* advanced/special/object/delete */
+#define SEC_RIGHTS_EXTENDED 0x100 /* change/reset password, receive/send as*/
+#define SEC_RIGHTS_CHANGE_PASSWD SEC_RIGHTS_EXTENDED
+#define SEC_RIGHTS_RESET_PASSWD SEC_RIGHTS_EXTENDED
+#define SEC_RIGHTS_FULL_CTRL 0xf01ff
+
+#define SEC_ACE_OBJECT_PRESENT 0x00000001 /* thanks for Jim McDonough <jmcd@us.ibm.com> */
+#define SEC_ACE_OBJECT_INHERITED_PRESENT 0x00000002
+
+/*
+ * New Windows 2000 bits.
+ */
+#define SE_DESC_DACL_AUTO_INHERIT_REQ 0x0100
+#define SE_DESC_SACL_AUTO_INHERIT_REQ 0x0200
+#define SE_DESC_DACL_AUTO_INHERITED 0x0400
+#define SE_DESC_SACL_AUTO_INHERITED 0x0800
+#define SE_DESC_DACL_PROTECTED 0x1000
+#define SE_DESC_SACL_PROTECTED 0x2000
+
+/* security information */
+#define OWNER_SECURITY_INFORMATION 0x00000001
+#define GROUP_SECURITY_INFORMATION 0x00000002
+#define DACL_SECURITY_INFORMATION 0x00000004
+#define SACL_SECURITY_INFORMATION 0x00000008
+/* Extra W2K flags. */
+#define UNPROTECTED_SACL_SECURITY_INFORMATION 0x10000000
+#define UNPROTECTED_DACL_SECURITY_INFORMATION 0x20000000
+#define PROTECTED_SACL_SECURITY_INFORMATION 0x40000000
+#define PROTECTED_DACL_SECURITY_INFORMATION 0x80000000
+
+#define ALL_SECURITY_INFORMATION (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|\
+ DACL_SECURITY_INFORMATION|SACL_SECURITY_INFORMATION|\
+ UNPROTECTED_SACL_SECURITY_INFORMATION|\
+ UNPROTECTED_DACL_SECURITY_INFORMATION|\
+ PROTECTED_SACL_SECURITY_INFORMATION|\
+ PROTECTED_DACL_SECURITY_INFORMATION)
+
+/* SEC_ACCESS */
+typedef uint32 SEC_ACCESS;
+
+/* SEC_ACE */
+typedef struct security_ace SEC_ACE;
+#define SEC_ACE_HEADER_SIZE (2 * sizeof(uint8) + sizeof(uint16) + sizeof(uint32))
+
+#ifndef ACL_REVISION
+#define ACL_REVISION 0x3
+#endif
+
+#ifndef _SEC_ACL
+/* SEC_ACL */
+typedef struct security_acl SEC_ACL;
+#define SEC_ACL_HEADER_SIZE (2 * sizeof(uint16) + sizeof(uint32))
+#define _SEC_ACL
+#endif
+
+#ifndef SEC_DESC_REVISION
+#define SEC_DESC_REVISION 0x1
+#endif
+
+#ifndef _SEC_DESC
+/* SEC_DESC */
+typedef struct security_descriptor SEC_DESC;
+#define SEC_DESC_HEADER_SIZE (2 * sizeof(uint16) + 4 * sizeof(uint32))
+#define _SEC_DESC
+#endif
+
+#ifndef _SEC_DESC_BUF
+/* SEC_DESC_BUF */
+typedef struct sec_desc_buf SEC_DESC_BUF;
+#define _SEC_DESC_BUF
+#endif
+
+/* A type to describe the mapping of generic access rights to object
+ specific access rights. */
+
+struct generic_mapping {
+ uint32 generic_read;
+ uint32 generic_write;
+ uint32 generic_execute;
+ uint32 generic_all;
+};
+
+struct standard_mapping {
+ uint32 std_read;
+ uint32 std_write;
+ uint32 std_execute;
+ uint32 std_all;
+};
+
+
+/* Security Access Masks Rights */
+
+#define SPECIFIC_RIGHTS_MASK 0x0000FFFF
+#define STANDARD_RIGHTS_MASK 0x00FF0000
+#define GENERIC_RIGHTS_MASK 0xF0000000
+
+#define SEC_RIGHT_SYSTEM_SECURITY 0x01000000
+#define SEC_RIGHT_MAXIMUM_ALLOWED 0x02000000
+
+/* Generic access rights */
+
+#define GENERIC_RIGHT_ALL_ACCESS 0x10000000
+#define GENERIC_RIGHT_EXECUTE_ACCESS 0x20000000
+#define GENERIC_RIGHT_WRITE_ACCESS 0x40000000
+#define GENERIC_RIGHT_READ_ACCESS 0x80000000
+
+/* Standard access rights. */
+
+#define STD_RIGHT_DELETE_ACCESS 0x00010000
+#define STD_RIGHT_READ_CONTROL_ACCESS 0x00020000
+#define STD_RIGHT_WRITE_DAC_ACCESS 0x00040000
+#define STD_RIGHT_WRITE_OWNER_ACCESS 0x00080000
+#define STD_RIGHT_SYNCHRONIZE_ACCESS 0x00100000
+
+#define STD_RIGHT_ALL_ACCESS 0x001F0000
+
+/* Combinations of standard masks. */
+#define STANDARD_RIGHTS_ALL_ACCESS STD_RIGHT_ALL_ACCESS /* 0x001f0000 */
+#define STANDARD_RIGHTS_MODIFY_ACCESS STD_RIGHT_READ_CONTROL_ACCESS /* 0x00020000 */
+#define STANDARD_RIGHTS_EXECUTE_ACCESS STD_RIGHT_READ_CONTROL_ACCESS /* 0x00020000 */
+#define STANDARD_RIGHTS_READ_ACCESS STD_RIGHT_READ_CONTROL_ACCESS /* 0x00020000 */
+#define STANDARD_RIGHTS_WRITE_ACCESS \
+ (STD_RIGHT_WRITE_OWNER_ACCESS | \
+ STD_RIGHT_WRITE_DAC_ACCESS | \
+ STD_RIGHT_DELETE_ACCESS) /* 0x000d0000 */
+#define STANDARD_RIGHTS_REQUIRED_ACCESS \
+ (STD_RIGHT_DELETE_ACCESS | \
+ STD_RIGHT_READ_CONTROL_ACCESS | \
+ STD_RIGHT_WRITE_DAC_ACCESS | \
+ STD_RIGHT_WRITE_OWNER_ACCESS) /* 0x000f0000 */
+
+/* File Object specific access rights */
+
+#define SA_RIGHT_FILE_READ_DATA 0x00000001
+#define SA_RIGHT_FILE_WRITE_DATA 0x00000002
+#define SA_RIGHT_FILE_APPEND_DATA 0x00000004
+#define SA_RIGHT_FILE_READ_EA 0x00000008
+#define SA_RIGHT_FILE_WRITE_EA 0x00000010
+#define SA_RIGHT_FILE_EXECUTE 0x00000020
+#define SA_RIGHT_FILE_DELETE_CHILD 0x00000040
+#define SA_RIGHT_FILE_READ_ATTRIBUTES 0x00000080
+#define SA_RIGHT_FILE_WRITE_ATTRIBUTES 0x00000100
+
+#define SA_RIGHT_FILE_ALL_ACCESS 0x000001FF
+
+#define GENERIC_RIGHTS_FILE_ALL_ACCESS \
+ (STANDARD_RIGHTS_REQUIRED_ACCESS| \
+ STD_RIGHT_SYNCHRONIZE_ACCESS | \
+ SA_RIGHT_FILE_ALL_ACCESS)
+
+#define GENERIC_RIGHTS_FILE_READ \
+ (STANDARD_RIGHTS_READ_ACCESS | \
+ STD_RIGHT_SYNCHRONIZE_ACCESS | \
+ SA_RIGHT_FILE_READ_DATA | \
+ SA_RIGHT_FILE_READ_ATTRIBUTES | \
+ SA_RIGHT_FILE_READ_EA)
+
+#define GENERIC_RIGHTS_FILE_WRITE \
+ (STANDARD_RIGHTS_WRITE_ACCESS | \
+ STD_RIGHT_SYNCHRONIZE_ACCESS | \
+ SA_RIGHT_FILE_WRITE_DATA | \
+ SA_RIGHT_FILE_WRITE_ATTRIBUTES | \
+ SA_RIGHT_FILE_WRITE_EA | \
+ SA_RIGHT_FILE_APPEND_DATA)
+
+#define GENERIC_RIGHTS_FILE_EXECUTE \
+ (STANDARD_RIGHTS_EXECUTE_ACCESS | \
+ STD_RIGHT_SYNCHRONIZE_ACCESS | \
+ SA_RIGHT_FILE_READ_ATTRIBUTES | \
+ SA_RIGHT_FILE_EXECUTE)
+
+#define GENERIC_RIGHTS_FILE_MODIFY \
+ (STANDARD_RIGHTS_MODIFY_ACCESS | \
+ STD_RIGHT_SYNCHRONIZE_ACCESS | \
+ STD_RIGHT_DELETE_ACCESS | \
+ SA_RIGHT_FILE_WRITE_ATTRIBUTES | \
+ SA_RIGHT_FILE_READ_ATTRIBUTES | \
+ SA_RIGHT_FILE_EXECUTE | \
+ SA_RIGHT_FILE_WRITE_EA | \
+ SA_RIGHT_FILE_READ_EA | \
+ SA_RIGHT_FILE_APPEND_DATA | \
+ SA_RIGHT_FILE_WRITE_DATA | \
+ SA_RIGHT_FILE_READ_DATA)
+
+/* SAM server specific access rights */
+
+#define SA_RIGHT_SAM_CONNECT_SERVER 0x00000001
+#define SA_RIGHT_SAM_SHUTDOWN_SERVER 0x00000002
+#define SA_RIGHT_SAM_INITIALISE_SERVER 0x00000004
+#define SA_RIGHT_SAM_CREATE_DOMAIN 0x00000008
+#define SA_RIGHT_SAM_ENUM_DOMAINS 0x00000010
+#define SA_RIGHT_SAM_OPEN_DOMAIN 0x00000020
+
+#define SA_RIGHT_SAM_ALL_ACCESS 0x0000003F
+
+#define GENERIC_RIGHTS_SAM_ALL_ACCESS \
+ (STANDARD_RIGHTS_REQUIRED_ACCESS| \
+ SA_RIGHT_SAM_ALL_ACCESS)
+
+#define GENERIC_RIGHTS_SAM_READ \
+ (STANDARD_RIGHTS_READ_ACCESS | \
+ SA_RIGHT_SAM_ENUM_DOMAINS)
+
+#define GENERIC_RIGHTS_SAM_WRITE \
+ (STANDARD_RIGHTS_WRITE_ACCESS | \
+ SA_RIGHT_SAM_CREATE_DOMAIN | \
+ SA_RIGHT_SAM_INITIALISE_SERVER | \
+ SA_RIGHT_SAM_SHUTDOWN_SERVER)
+
+#define GENERIC_RIGHTS_SAM_EXECUTE \
+ (STANDARD_RIGHTS_EXECUTE_ACCESS | \
+ SA_RIGHT_SAM_OPEN_DOMAIN | \
+ SA_RIGHT_SAM_CONNECT_SERVER)
+
+
+/* Domain Object specific access rights */
+
+#define SA_RIGHT_DOMAIN_LOOKUP_INFO_1 0x00000001
+#define SA_RIGHT_DOMAIN_SET_INFO_1 0x00000002
+#define SA_RIGHT_DOMAIN_LOOKUP_INFO_2 0x00000004
+#define SA_RIGHT_DOMAIN_SET_INFO_2 0x00000008
+#define SA_RIGHT_DOMAIN_CREATE_USER 0x00000010
+#define SA_RIGHT_DOMAIN_CREATE_GROUP 0x00000020
+#define SA_RIGHT_DOMAIN_CREATE_ALIAS 0x00000040
+#define SA_RIGHT_DOMAIN_LOOKUP_ALIAS_BY_MEM 0x00000080
+#define SA_RIGHT_DOMAIN_ENUM_ACCOUNTS 0x00000100
+#define SA_RIGHT_DOMAIN_OPEN_ACCOUNT 0x00000200
+#define SA_RIGHT_DOMAIN_SET_INFO_3 0x00000400
+
+#define SA_RIGHT_DOMAIN_ALL_ACCESS 0x000007FF
+
+#define GENERIC_RIGHTS_DOMAIN_ALL_ACCESS \
+ (STANDARD_RIGHTS_REQUIRED_ACCESS| \
+ SA_RIGHT_DOMAIN_ALL_ACCESS)
+
+#define GENERIC_RIGHTS_DOMAIN_READ \
+ (STANDARD_RIGHTS_READ_ACCESS | \
+ SA_RIGHT_DOMAIN_LOOKUP_ALIAS_BY_MEM | \
+ SA_RIGHT_DOMAIN_LOOKUP_INFO_2)
+
+#define GENERIC_RIGHTS_DOMAIN_WRITE \
+ (STANDARD_RIGHTS_WRITE_ACCESS | \
+ SA_RIGHT_DOMAIN_SET_INFO_3 | \
+ SA_RIGHT_DOMAIN_CREATE_ALIAS | \
+ SA_RIGHT_DOMAIN_CREATE_GROUP | \
+ SA_RIGHT_DOMAIN_CREATE_USER | \
+ SA_RIGHT_DOMAIN_SET_INFO_2 | \
+ SA_RIGHT_DOMAIN_SET_INFO_1)
+
+#define GENERIC_RIGHTS_DOMAIN_EXECUTE \
+ (STANDARD_RIGHTS_EXECUTE_ACCESS | \
+ SA_RIGHT_DOMAIN_OPEN_ACCOUNT | \
+ SA_RIGHT_DOMAIN_ENUM_ACCOUNTS | \
+ SA_RIGHT_DOMAIN_LOOKUP_INFO_1)
+
+
+/* User Object specific access rights */
+
+#define SA_RIGHT_USER_GET_NAME_ETC 0x00000001
+#define SA_RIGHT_USER_GET_LOCALE 0x00000002
+#define SA_RIGHT_USER_SET_LOC_COM 0x00000004
+#define SA_RIGHT_USER_GET_LOGONINFO 0x00000008
+#define SA_RIGHT_USER_ACCT_FLAGS_EXPIRY 0x00000010
+#define SA_RIGHT_USER_SET_ATTRIBUTES 0x00000020
+#define SA_RIGHT_USER_CHANGE_PASSWORD 0x00000040
+#define SA_RIGHT_USER_SET_PASSWORD 0x00000080
+#define SA_RIGHT_USER_GET_GROUPS 0x00000100
+#define SA_RIGHT_USER_READ_GROUP_MEM 0x00000200
+#define SA_RIGHT_USER_CHANGE_GROUP_MEM 0x00000400
+
+#define SA_RIGHT_USER_ALL_ACCESS 0x000007FF
+
+#define GENERIC_RIGHTS_USER_ALL_ACCESS \
+ (STANDARD_RIGHTS_REQUIRED_ACCESS| \
+ SA_RIGHT_USER_ALL_ACCESS) /* 0x000f07ff */
+
+#define GENERIC_RIGHTS_USER_READ \
+ (STANDARD_RIGHTS_READ_ACCESS | \
+ SA_RIGHT_USER_READ_GROUP_MEM | \
+ SA_RIGHT_USER_GET_GROUPS | \
+ SA_RIGHT_USER_ACCT_FLAGS_EXPIRY | \
+ SA_RIGHT_USER_GET_LOGONINFO | \
+ SA_RIGHT_USER_GET_LOCALE) /* 0x0002031a */
+
+#define GENERIC_RIGHTS_USER_WRITE \
+ (STANDARD_RIGHTS_WRITE_ACCESS | \
+ SA_RIGHT_USER_CHANGE_PASSWORD | \
+ SA_RIGHT_USER_SET_LOC_COM | \
+ SA_RIGHT_USER_SET_ATTRIBUTES | \
+ SA_RIGHT_USER_SET_PASSWORD | \
+ SA_RIGHT_USER_CHANGE_GROUP_MEM) /* 0x000204e4 */
+
+#define GENERIC_RIGHTS_USER_EXECUTE \
+ (STANDARD_RIGHTS_EXECUTE_ACCESS | \
+ SA_RIGHT_USER_CHANGE_PASSWORD | \
+ SA_RIGHT_USER_GET_NAME_ETC ) /* 0x00020041 */
+
+
+/* Group Object specific access rights */
+
+#define SA_RIGHT_GROUP_LOOKUP_INFO 0x00000001
+#define SA_RIGHT_GROUP_SET_INFO 0x00000002
+#define SA_RIGHT_GROUP_ADD_MEMBER 0x00000004
+#define SA_RIGHT_GROUP_REMOVE_MEMBER 0x00000008
+#define SA_RIGHT_GROUP_GET_MEMBERS 0x00000010
+
+#define SA_RIGHT_GROUP_ALL_ACCESS 0x0000001F
+
+#define GENERIC_RIGHTS_GROUP_ALL_ACCESS \
+ (STANDARD_RIGHTS_REQUIRED_ACCESS| \
+ SA_RIGHT_GROUP_ALL_ACCESS) /* 0x000f001f */
+
+#define GENERIC_RIGHTS_GROUP_READ \
+ (STANDARD_RIGHTS_READ_ACCESS | \
+ SA_RIGHT_GROUP_GET_MEMBERS) /* 0x00020010 */
+
+#define GENERIC_RIGHTS_GROUP_WRITE \
+ (STANDARD_RIGHTS_WRITE_ACCESS | \
+ SA_RIGHT_GROUP_REMOVE_MEMBER | \
+ SA_RIGHT_GROUP_ADD_MEMBER | \
+ SA_RIGHT_GROUP_SET_INFO ) /* 0x0002000e */
+
+#define GENERIC_RIGHTS_GROUP_EXECUTE \
+ (STANDARD_RIGHTS_EXECUTE_ACCESS | \
+ SA_RIGHT_GROUP_LOOKUP_INFO) /* 0x00020001 */
+
+
+/* Alias Object specific access rights */
+
+#define SA_RIGHT_ALIAS_ADD_MEMBER 0x00000001
+#define SA_RIGHT_ALIAS_REMOVE_MEMBER 0x00000002
+#define SA_RIGHT_ALIAS_GET_MEMBERS 0x00000004
+#define SA_RIGHT_ALIAS_LOOKUP_INFO 0x00000008
+#define SA_RIGHT_ALIAS_SET_INFO 0x00000010
+
+#define SA_RIGHT_ALIAS_ALL_ACCESS 0x0000001F
+
+#define GENERIC_RIGHTS_ALIAS_ALL_ACCESS \
+ (STANDARD_RIGHTS_REQUIRED_ACCESS| \
+ SA_RIGHT_ALIAS_ALL_ACCESS) /* 0x000f001f */
+
+#define GENERIC_RIGHTS_ALIAS_READ \
+ (STANDARD_RIGHTS_READ_ACCESS | \
+ SA_RIGHT_ALIAS_GET_MEMBERS ) /* 0x00020004 */
+
+#define GENERIC_RIGHTS_ALIAS_WRITE \
+ (STANDARD_RIGHTS_WRITE_ACCESS | \
+ SA_RIGHT_ALIAS_REMOVE_MEMBER | \
+ SA_RIGHT_ALIAS_ADD_MEMBER | \
+ SA_RIGHT_ALIAS_SET_INFO ) /* 0x00020013 */
+
+#define GENERIC_RIGHTS_ALIAS_EXECUTE \
+ (STANDARD_RIGHTS_EXECUTE_ACCESS | \
+ SA_RIGHT_ALIAS_LOOKUP_INFO ) /* 0x00020008 */
+
+/*
+ * Acces bits for the svcctl objects
+ */
+
+/* Service Control Manager Bits */
+
+#if 0
+#define SC_RIGHT_MGR_CONNECT 0x0001
+#define SC_RIGHT_MGR_CREATE_SERVICE 0x0002
+#define SC_RIGHT_MGR_ENUMERATE_SERVICE 0x0004
+#define SC_RIGHT_MGR_LOCK 0x0008
+#define SC_RIGHT_MGR_QUERY_LOCK_STATUS 0x0010
+#define SC_RIGHT_MGR_MODIFY_BOOT_CONFIG 0x0020
+
+#endif
+
+#define SC_MANAGER_READ_ACCESS \
+ ( STANDARD_RIGHTS_READ_ACCESS | \
+ SC_RIGHT_MGR_CONNECT | \
+ SC_RIGHT_MGR_ENUMERATE_SERVICE | \
+ SC_RIGHT_MGR_QUERY_LOCK_STATUS )
+
+#define SC_MANAGER_EXECUTE_ACCESS SC_MANAGER_READ_ACCESS
+
+#define SC_MANAGER_WRITE_ACCESS \
+ ( STANDARD_RIGHTS_REQUIRED_ACCESS | \
+ SC_MANAGER_READ_ACCESS | \
+ SC_RIGHT_MGR_CREATE_SERVICE | \
+ SC_RIGHT_MGR_LOCK | \
+ SC_RIGHT_MGR_MODIFY_BOOT_CONFIG )
+
+#define SC_MANAGER_ALL_ACCESS SC_MANAGER_WRITE_ACCESS
+
+/* Service Object Bits */
+
+#if 0
+#define SC_RIGHT_SVC_QUERY_CONFIG 0x0001
+#define SC_RIGHT_SVC_CHANGE_CONFIG 0x0002
+#define SC_RIGHT_SVC_QUERY_STATUS 0x0004
+#define SC_RIGHT_SVC_ENUMERATE_DEPENDENTS 0x0008
+#define SC_RIGHT_SVC_START 0x0010
+#define SC_RIGHT_SVC_STOP 0x0020
+#define SC_RIGHT_SVC_PAUSE_CONTINUE 0x0040
+#define SC_RIGHT_SVC_INTERROGATE 0x0080
+#define SC_RIGHT_SVC_USER_DEFINED_CONTROL 0x0100
+
+#endif
+
+#define SERVICE_READ_ACCESS \
+ ( STANDARD_RIGHTS_READ_ACCESS | \
+ SC_RIGHT_SVC_ENUMERATE_DEPENDENTS | \
+ SC_RIGHT_SVC_INTERROGATE | \
+ SC_RIGHT_SVC_QUERY_CONFIG | \
+ SC_RIGHT_SVC_QUERY_STATUS | \
+ SC_RIGHT_SVC_USER_DEFINED_CONTROL )
+
+#define SERVICE_EXECUTE_ACCESS \
+ ( SERVICE_READ_ACCESS | \
+ SC_RIGHT_SVC_START | \
+ SC_RIGHT_SVC_STOP | \
+ SC_RIGHT_SVC_PAUSE_CONTINUE )
+
+#define SERVICE_WRITE_ACCESS \
+ ( STANDARD_RIGHTS_REQUIRED_ACCESS | \
+ SERVICE_READ_ACCESS | \
+ SERVICE_EXECUTE_ACCESS | \
+ SC_RIGHT_SVC_CHANGE_CONFIG )
+
+#define SERVICE_ALL_ACCESS SERVICE_WRITE_ACCESS
+
+/*
+ * Access Bits for registry ACLS
+ */
+
+/* used by registry ACLs */
+
+#define SEC_RIGHTS_QUERY_VALUE 0x00000001
+#define SEC_RIGHTS_SET_VALUE 0x00000002
+#define SEC_RIGHTS_CREATE_SUBKEY 0x00000004
+#define SEC_RIGHTS_ENUM_SUBKEYS 0x00000008
+#define SEC_RIGHTS_NOTIFY 0x00000010
+#define SEC_RIGHTS_CREATE_LINK 0x00000020
+#define SEC_RIGHTS_MAXIMUM_ALLOWED 0x02000000
+
+
+#define REG_KEY_READ \
+ ( STANDARD_RIGHTS_READ_ACCESS |\
+ SEC_RIGHTS_QUERY_VALUE |\
+ SEC_RIGHTS_ENUM_SUBKEYS |\
+ SEC_RIGHTS_NOTIFY )
+
+#define REG_KEY_EXECUTE REG_KEY_READ
+
+#define REG_KEY_WRITE \
+ ( STANDARD_RIGHTS_WRITE_ACCESS |\
+ SEC_RIGHTS_SET_VALUE |\
+ SEC_RIGHTS_CREATE_SUBKEY )
+
+#define REG_KEY_ALL \
+ ( STANDARD_RIGHTS_REQUIRED_ACCESS |\
+ REG_KEY_READ |\
+ REG_KEY_WRITE |\
+ SEC_RIGHTS_CREATE_LINK )
+
+
+#endif /* _RPC_SECDES_H */
diff --git a/source3/include/rpc_spoolss.h b/source3/include/rpc_spoolss.h
new file mode 100644
index 0000000000..98f6110f7a
--- /dev/null
+++ b/source3/include/rpc_spoolss.h
@@ -0,0 +1,2224 @@
+/*
+ Unix SMB/Netbios implementation.
+
+ Copyright (C) Andrew Tridgell 1992-2000,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ Copyright (C) Jean Francois Micouleau 1998-2000.
+ Copyright (C) Gerald Carter 2001-2006.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _RPC_SPOOLSS_H /* _RPC_SPOOLSS_H */
+#define _RPC_SPOOLSS_H
+
+/* spoolss pipe: this are the calls which are not implemented ...
+#define SPOOLSS_GETPRINTERDRIVER 0x0b
+#define SPOOLSS_READPRINTER 0x16
+#define SPOOLSS_WAITFORPRINTERCHANGE 0x1c
+#define SPOOLSS_ADDPORT 0x25
+#define SPOOLSS_CONFIGUREPORT 0x26
+#define SPOOLSS_DELETEPORT 0x27
+#define SPOOLSS_CREATEPRINTERIC 0x28
+#define SPOOLSS_PLAYGDISCRIPTONPRINTERIC 0x29
+#define SPOOLSS_DELETEPRINTERIC 0x2a
+#define SPOOLSS_ADDPRINTERCONNECTION 0x2b
+#define SPOOLSS_DELETEPRINTERCONNECTION 0x2c
+#define SPOOLSS_PRINTERMESSAGEBOX 0x2d
+#define SPOOLSS_ADDMONITOR 0x2e
+#define SPOOLSS_DELETEMONITOR 0x2f
+#define SPOOLSS_DELETEPRINTPROCESSOR 0x30
+#define SPOOLSS_ADDPRINTPROVIDOR 0x31
+#define SPOOLSS_DELETEPRINTPROVIDOR 0x32
+#define SPOOLSS_FINDFIRSTPRINTERCHANGENOTIFICATION 0x36
+#define SPOOLSS_FINDNEXTPRINTERCHANGENOTIFICATION 0x37
+#define SPOOLSS_ROUTERFINDFIRSTPRINTERNOTIFICATIONOLD 0x39
+#define SPOOLSS_ADDPORTEX 0x3d
+#define SPOOLSS_REMOTEFINDFIRSTPRINTERCHANGENOTIFICATION0x3e
+#define SPOOLSS_SPOOLERINIT 0x3f
+#define SPOOLSS_RESETPRINTEREX 0x40
+*/
+
+/* those are implemented */
+#define SPOOLSS_ENUMPRINTERS 0x00
+#define SPOOLSS_OPENPRINTER 0x01
+#define SPOOLSS_SETJOB 0x02
+#define SPOOLSS_GETJOB 0x03
+#define SPOOLSS_ENUMJOBS 0x04
+#define SPOOLSS_ADDPRINTER 0x05
+#define SPOOLSS_DELETEPRINTER 0x06
+#define SPOOLSS_SETPRINTER 0x07
+#define SPOOLSS_GETPRINTER 0x08
+#define SPOOLSS_ADDPRINTERDRIVER 0x09
+#define SPOOLSS_ENUMPRINTERDRIVERS 0x0a
+#define SPOOLSS_GETPRINTERDRIVERDIRECTORY 0x0c
+#define SPOOLSS_DELETEPRINTERDRIVER 0x0d
+#define SPOOLSS_ADDPRINTPROCESSOR 0x0e
+#define SPOOLSS_ENUMPRINTPROCESSORS 0x0f
+#define SPOOLSS_GETPRINTPROCESSORDIRECTORY 0x10
+#define SPOOLSS_STARTDOCPRINTER 0x11
+#define SPOOLSS_STARTPAGEPRINTER 0x12
+#define SPOOLSS_WRITEPRINTER 0x13
+#define SPOOLSS_ENDPAGEPRINTER 0x14
+#define SPOOLSS_ABORTPRINTER 0x15
+#define SPOOLSS_ENDDOCPRINTER 0x17
+#define SPOOLSS_ADDJOB 0x18
+#define SPOOLSS_SCHEDULEJOB 0x19
+#define SPOOLSS_GETPRINTERDATA 0x1a
+#define SPOOLSS_SETPRINTERDATA 0x1b
+#define SPOOLSS_CLOSEPRINTER 0x1d
+#define SPOOLSS_ADDFORM 0x1e
+#define SPOOLSS_DELETEFORM 0x1f
+#define SPOOLSS_GETFORM 0x20
+#define SPOOLSS_SETFORM 0x21
+#define SPOOLSS_ENUMFORMS 0x22
+#define SPOOLSS_ENUMPORTS 0x23
+#define SPOOLSS_ENUMMONITORS 0x24
+#define SPOOLSS_ENUMPRINTPROCDATATYPES 0x33
+#define SPOOLSS_RESETPRINTER 0x34
+#define SPOOLSS_GETPRINTERDRIVER2 0x35
+#define SPOOLSS_FCPN 0x38 /* FindClosePrinterNotify */
+#define SPOOLSS_REPLYOPENPRINTER 0x3a
+#define SPOOLSS_ROUTERREPLYPRINTER 0x3b
+#define SPOOLSS_REPLYCLOSEPRINTER 0x3c
+#define SPOOLSS_RFFPCNEX 0x41 /* RemoteFindFirstPrinterChangeNotifyEx */
+#define SPOOLSS_RRPCN 0x42 /* RouteRefreshPrinterChangeNotification */
+#define SPOOLSS_RFNPCNEX 0x43 /* RemoteFindNextPrinterChangeNotifyEx */
+#define SPOOLSS_OPENPRINTEREX 0x45
+#define SPOOLSS_ADDPRINTEREX 0x46
+#define SPOOLSS_ENUMPRINTERDATA 0x48
+#define SPOOLSS_DELETEPRINTERDATA 0x49
+#define SPOOLSS_SETPRINTERDATAEX 0x4d
+#define SPOOLSS_GETPRINTERDATAEX 0x4e
+#define SPOOLSS_ENUMPRINTERDATAEX 0x4f
+#define SPOOLSS_ENUMPRINTERKEY 0x50
+#define SPOOLSS_DELETEPRINTERDATAEX 0x51
+#define SPOOLSS_DELETEPRINTERKEY 0x52
+#define SPOOLSS_DELETEPRINTERDRIVEREX 0x54
+#define SPOOLSS_XCVDATAPORT 0x58
+#define SPOOLSS_ADDPRINTERDRIVEREX 0x59
+
+/*
+ * Special strings for the OpenPrinter() call. See the MSDN DDK
+ * docs on the XcvDataPort() for more details.
+ */
+
+#define SPL_LOCAL_PORT "Local Port"
+#define SPL_TCPIP_PORT "Standard TCP/IP Port"
+#define SPL_XCV_MONITOR_LOCALMON ",XcvMonitor Local Port"
+#define SPL_XCV_MONITOR_TCPMON ",XcvMonitor Standard TCP/IP Port"
+
+
+#define PRINTER_CONTROL_UNPAUSE 0x00000000
+#define PRINTER_CONTROL_PAUSE 0x00000001
+#define PRINTER_CONTROL_RESUME 0x00000002
+#define PRINTER_CONTROL_PURGE 0x00000003
+#define PRINTER_CONTROL_SET_STATUS 0x00000004
+
+#define PRINTER_STATUS_OK 0x00000000
+#define PRINTER_STATUS_PAUSED 0x00000001
+#define PRINTER_STATUS_ERROR 0x00000002
+#define PRINTER_STATUS_PENDING_DELETION 0x00000004
+#define PRINTER_STATUS_PAPER_JAM 0x00000008
+
+#define PRINTER_STATUS_PAPER_OUT 0x00000010
+#define PRINTER_STATUS_MANUAL_FEED 0x00000020
+#define PRINTER_STATUS_PAPER_PROBLEM 0x00000040
+#define PRINTER_STATUS_OFFLINE 0x00000080
+
+#define PRINTER_STATUS_IO_ACTIVE 0x00000100
+#define PRINTER_STATUS_BUSY 0x00000200
+#define PRINTER_STATUS_PRINTING 0x00000400
+#define PRINTER_STATUS_OUTPUT_BIN_FULL 0x00000800
+
+#define PRINTER_STATUS_NOT_AVAILABLE 0x00001000
+#define PRINTER_STATUS_WAITING 0x00002000
+#define PRINTER_STATUS_PROCESSING 0x00004000
+#define PRINTER_STATUS_INITIALIZING 0x00008000
+
+#define PRINTER_STATUS_WARMING_UP 0x00010000
+#define PRINTER_STATUS_TONER_LOW 0x00020000
+#define PRINTER_STATUS_NO_TONER 0x00040000
+#define PRINTER_STATUS_PAGE_PUNT 0x00080000
+
+#define PRINTER_STATUS_USER_INTERVENTION 0x00100000
+#define PRINTER_STATUS_OUT_OF_MEMORY 0x00200000
+#define PRINTER_STATUS_DOOR_OPEN 0x00400000
+#define PRINTER_STATUS_SERVER_UNKNOWN 0x00800000
+
+#define PRINTER_STATUS_POWER_SAVE 0x01000000
+
+#define SERVER_ACCESS_ADMINISTER 0x00000001
+#define SERVER_ACCESS_ENUMERATE 0x00000002
+#define PRINTER_ACCESS_ADMINISTER 0x00000004
+#define PRINTER_ACCESS_USE 0x00000008
+#define JOB_ACCESS_ADMINISTER 0x00000010
+#define JOB_ACCESS_READ 0x00000020
+
+/* JOB status codes. */
+
+#define JOB_STATUS_QUEUED 0x0000
+#define JOB_STATUS_PAUSED 0x0001
+#define JOB_STATUS_ERROR 0x0002
+#define JOB_STATUS_DELETING 0x0004
+#define JOB_STATUS_SPOOLING 0x0008
+#define JOB_STATUS_PRINTING 0x0010
+#define JOB_STATUS_OFFLINE 0x0020
+#define JOB_STATUS_PAPEROUT 0x0040
+#define JOB_STATUS_PRINTED 0x0080
+#define JOB_STATUS_DELETED 0x0100
+#define JOB_STATUS_BLOCKED 0x0200
+#define JOB_STATUS_USER_INTERVENTION 0x0400
+
+/* Access rights for print servers */
+#define SERVER_ALL_ACCESS STANDARD_RIGHTS_REQUIRED_ACCESS|SERVER_ACCESS_ADMINISTER|SERVER_ACCESS_ENUMERATE
+#define SERVER_READ STANDARD_RIGHTS_READ_ACCESS|SERVER_ACCESS_ENUMERATE
+#define SERVER_WRITE STANDARD_RIGHTS_WRITE_ACCESS|SERVER_ACCESS_ADMINISTER|SERVER_ACCESS_ENUMERATE
+#define SERVER_EXECUTE STANDARD_RIGHTS_EXECUTE_ACCESS|SERVER_ACCESS_ENUMERATE
+
+/* Access rights for printers */
+#define PRINTER_ALL_ACCESS STANDARD_RIGHTS_REQUIRED_ACCESS|PRINTER_ACCESS_ADMINISTER|PRINTER_ACCESS_USE
+#define PRINTER_READ STANDARD_RIGHTS_READ_ACCESS|PRINTER_ACCESS_USE
+#define PRINTER_WRITE STANDARD_RIGHTS_WRITE_ACCESS|PRINTER_ACCESS_USE
+#define PRINTER_EXECUTE STANDARD_RIGHTS_EXECUTE_ACCESS|PRINTER_ACCESS_USE
+
+/* Access rights for jobs */
+#define JOB_ALL_ACCESS STANDARD_RIGHTS_REQUIRED_ACCESS|JOB_ACCESS_ADMINISTER|JOB_ACCESS_READ|PRINTER_ACCESS_USE
+#define JOB_READ STANDARD_RIGHTS_READ_ACCESS|JOB_ACCESS_ADMINISTER|JOB_ACCESS_READ
+#define JOB_WRITE STANDARD_RIGHTS_WRITE_ACCESS|JOB_ACCESS_ADMINISTER|PRINTER_ACCESS_USE
+#define JOB_EXECUTE STANDARD_RIGHTS_EXECUTE_ACCESS|JOB_ACCESS_ADMINISTER|PRINTER_ACCESS_USE
+
+/* ACE masks for the various print permissions */
+
+#define PRINTER_ACE_FULL_CONTROL (GENERIC_ALL_ACCESS|PRINTER_ALL_ACCESS)
+#define PRINTER_ACE_MANAGE_DOCUMENTS (GENERIC_ALL_ACCESS|READ_CONTROL_ACCESS)
+#define PRINTER_ACE_PRINT (GENERIC_EXECUTE_ACCESS|READ_CONTROL_ACCESS|PRINTER_ACCESS_USE)
+
+
+/* Notify field types */
+
+#define NOTIFY_ONE_VALUE 1 /* Notify data is stored in value1 */
+#define NOTIFY_TWO_VALUE 2 /* Notify data is stored in value2 */
+#define NOTIFY_POINTER 3 /* Data is a pointer to a buffer */
+#define NOTIFY_STRING 4 /* Data is a pointer to a buffer w/length */
+#define NOTIFY_SECDESC 5 /* Data is a security descriptor */
+
+#define PRINTER_NOTIFY_TYPE 0x00
+#define JOB_NOTIFY_TYPE 0x01
+#define PRINT_TABLE_END 0xFF
+
+#define MAX_PRINTER_NOTIFY 26
+#define MAX_JOB_NOTIFY 24
+
+#define MAX_NOTIFY_TYPE_FOR_NOW 26
+
+#define PRINTER_NOTIFY_SERVER_NAME 0x00
+#define PRINTER_NOTIFY_PRINTER_NAME 0x01
+#define PRINTER_NOTIFY_SHARE_NAME 0x02
+#define PRINTER_NOTIFY_PORT_NAME 0x03
+#define PRINTER_NOTIFY_DRIVER_NAME 0x04
+#define PRINTER_NOTIFY_COMMENT 0x05
+#define PRINTER_NOTIFY_LOCATION 0x06
+#define PRINTER_NOTIFY_DEVMODE 0x07
+#define PRINTER_NOTIFY_SEPFILE 0x08
+#define PRINTER_NOTIFY_PRINT_PROCESSOR 0x09
+#define PRINTER_NOTIFY_PARAMETERS 0x0A
+#define PRINTER_NOTIFY_DATATYPE 0x0B
+#define PRINTER_NOTIFY_SECURITY_DESCRIPTOR 0x0C
+#define PRINTER_NOTIFY_ATTRIBUTES 0x0D
+#define PRINTER_NOTIFY_PRIORITY 0x0E
+#define PRINTER_NOTIFY_DEFAULT_PRIORITY 0x0F
+#define PRINTER_NOTIFY_START_TIME 0x10
+#define PRINTER_NOTIFY_UNTIL_TIME 0x11
+#define PRINTER_NOTIFY_STATUS 0x12
+#define PRINTER_NOTIFY_STATUS_STRING 0x13
+#define PRINTER_NOTIFY_CJOBS 0x14
+#define PRINTER_NOTIFY_AVERAGE_PPM 0x15
+#define PRINTER_NOTIFY_TOTAL_PAGES 0x16
+#define PRINTER_NOTIFY_PAGES_PRINTED 0x17
+#define PRINTER_NOTIFY_TOTAL_BYTES 0x18
+#define PRINTER_NOTIFY_BYTES_PRINTED 0x19
+
+#define JOB_NOTIFY_PRINTER_NAME 0x00
+#define JOB_NOTIFY_MACHINE_NAME 0x01
+#define JOB_NOTIFY_PORT_NAME 0x02
+#define JOB_NOTIFY_USER_NAME 0x03
+#define JOB_NOTIFY_NOTIFY_NAME 0x04
+#define JOB_NOTIFY_DATATYPE 0x05
+#define JOB_NOTIFY_PRINT_PROCESSOR 0x06
+#define JOB_NOTIFY_PARAMETERS 0x07
+#define JOB_NOTIFY_DRIVER_NAME 0x08
+#define JOB_NOTIFY_DEVMODE 0x09
+#define JOB_NOTIFY_STATUS 0x0A
+#define JOB_NOTIFY_STATUS_STRING 0x0B
+#define JOB_NOTIFY_SECURITY_DESCRIPTOR 0x0C
+#define JOB_NOTIFY_DOCUMENT 0x0D
+#define JOB_NOTIFY_PRIORITY 0x0E
+#define JOB_NOTIFY_POSITION 0x0F
+#define JOB_NOTIFY_SUBMITTED 0x10
+#define JOB_NOTIFY_START_TIME 0x11
+#define JOB_NOTIFY_UNTIL_TIME 0x12
+#define JOB_NOTIFY_TIME 0x13
+#define JOB_NOTIFY_TOTAL_PAGES 0x14
+#define JOB_NOTIFY_PAGES_PRINTED 0x15
+#define JOB_NOTIFY_TOTAL_BYTES 0x16
+#define JOB_NOTIFY_BYTES_PRINTED 0x17
+
+#define PRINTER_NOTIFY_OPTIONS_REFRESH 0x01
+
+#define PRINTER_CHANGE_ADD_PRINTER 0x00000001
+#define PRINTER_CHANGE_SET_PRINTER 0x00000002
+#define PRINTER_CHANGE_DELETE_PRINTER 0x00000004
+#define PRINTER_CHANGE_FAILED_CONNECTION_PRINTER 0x00000008
+#define PRINTER_CHANGE_PRINTER (PRINTER_CHANGE_ADD_PRINTER | \
+ PRINTER_CHANGE_SET_PRINTER | \
+ PRINTER_CHANGE_DELETE_PRINTER | \
+ PRINTER_CHANGE_FAILED_CONNECTION_PRINTER )
+
+#define PRINTER_CHANGE_ADD_JOB 0x00000100
+#define PRINTER_CHANGE_SET_JOB 0x00000200
+#define PRINTER_CHANGE_DELETE_JOB 0x00000400
+#define PRINTER_CHANGE_WRITE_JOB 0x00000800
+#define PRINTER_CHANGE_JOB (PRINTER_CHANGE_ADD_JOB | \
+ PRINTER_CHANGE_SET_JOB | \
+ PRINTER_CHANGE_DELETE_JOB | \
+ PRINTER_CHANGE_WRITE_JOB )
+
+#define PRINTER_CHANGE_ADD_FORM 0x00010000
+#define PRINTER_CHANGE_SET_FORM 0x00020000
+#define PRINTER_CHANGE_DELETE_FORM 0x00040000
+#define PRINTER_CHANGE_FORM (PRINTER_CHANGE_ADD_FORM | \
+ PRINTER_CHANGE_SET_FORM | \
+ PRINTER_CHANGE_DELETE_FORM )
+
+#define PRINTER_CHANGE_ADD_PORT 0x00100000
+#define PRINTER_CHANGE_CONFIGURE_PORT 0x00200000
+#define PRINTER_CHANGE_DELETE_PORT 0x00400000
+#define PRINTER_CHANGE_PORT (PRINTER_CHANGE_ADD_PORT | \
+ PRINTER_CHANGE_CONFIGURE_PORT | \
+ PRINTER_CHANGE_DELETE_PORT )
+
+#define PRINTER_CHANGE_ADD_PRINT_PROCESSOR 0x01000000
+#define PRINTER_CHANGE_DELETE_PRINT_PROCESSOR 0x04000000
+#define PRINTER_CHANGE_PRINT_PROCESSOR (PRINTER_CHANGE_ADD_PRINT_PROCESSOR | \
+ PRINTER_CHANGE_DELETE_PRINT_PROCESSOR )
+
+#define PRINTER_CHANGE_ADD_PRINTER_DRIVER 0x10000000
+#define PRINTER_CHANGE_SET_PRINTER_DRIVER 0x20000000
+#define PRINTER_CHANGE_DELETE_PRINTER_DRIVER 0x40000000
+#define PRINTER_CHANGE_PRINTER_DRIVER (PRINTER_CHANGE_ADD_PRINTER_DRIVER | \
+ PRINTER_CHANGE_SET_PRINTER_DRIVER | \
+ PRINTER_CHANGE_DELETE_PRINTER_DRIVER )
+
+#define PRINTER_CHANGE_TIMEOUT 0x80000000
+#define PRINTER_CHANGE_ALL (PRINTER_CHANGE_JOB | \
+ PRINTER_CHANGE_FORM | \
+ PRINTER_CHANGE_PORT | \
+ PRINTER_CHANGE_PRINT_PROCESSOR | \
+ PRINTER_CHANGE_PRINTER_DRIVER )
+
+#define PRINTER_NOTIFY_INFO_DISCARDED 0x1
+
+/*
+ * Set of macros for flagging what changed in the PRINTER_INFO_2 struct
+ * when sending messages to other smbd's
+ */
+#define PRINTER_MESSAGE_NULL 0x00000000
+#define PRINTER_MESSAGE_DRIVER 0x00000001
+#define PRINTER_MESSAGE_COMMENT 0x00000002
+#define PRINTER_MESSAGE_PRINTERNAME 0x00000004
+#define PRINTER_MESSAGE_LOCATION 0x00000008
+#define PRINTER_MESSAGE_DEVMODE 0x00000010 /* not curently supported */
+#define PRINTER_MESSAGE_SEPFILE 0x00000020
+#define PRINTER_MESSAGE_PRINTPROC 0x00000040
+#define PRINTER_MESSAGE_PARAMS 0x00000080
+#define PRINTER_MESSAGE_DATATYPE 0x00000100
+#define PRINTER_MESSAGE_SECDESC 0x00000200
+#define PRINTER_MESSAGE_CJOBS 0x00000400
+#define PRINTER_MESSAGE_PORT 0x00000800
+#define PRINTER_MESSAGE_SHARENAME 0x00001000
+#define PRINTER_MESSAGE_ATTRIBUTES 0x00002000
+
+typedef struct printer_message_info {
+ uint32 low; /* PRINTER_CHANGE_XXX */
+ uint32 high; /* PRINTER_CHANGE_XXX */
+ fstring printer_name;
+ uint32 flags; /* PRINTER_MESSAGE_XXX */
+}
+PRINTER_MESSAGE_INFO;
+
+/*
+ * The printer attributes.
+ * I #defined all of them (grabbed form MSDN)
+ * I'm only using:
+ * ( SHARED | NETWORK | RAW_ONLY )
+ * RAW_ONLY _MUST_ be present otherwise NT will send an EMF file
+ */
+
+#define PRINTER_ATTRIBUTE_QUEUED 0x00000001
+#define PRINTER_ATTRIBUTE_DIRECT 0x00000002
+#define PRINTER_ATTRIBUTE_DEFAULT 0x00000004
+#define PRINTER_ATTRIBUTE_SHARED 0x00000008
+
+#define PRINTER_ATTRIBUTE_NETWORK 0x00000010
+#define PRINTER_ATTRIBUTE_HIDDEN 0x00000020
+#define PRINTER_ATTRIBUTE_LOCAL 0x00000040
+#define PRINTER_ATTRIBUTE_ENABLE_DEVQ 0x00000080
+
+#define PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS 0x00000100
+#define PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST 0x00000200
+#define PRINTER_ATTRIBUTE_WORK_OFFLINE 0x00000400
+#define PRINTER_ATTRIBUTE_ENABLE_BIDI 0x00000800
+
+#define PRINTER_ATTRIBUTE_RAW_ONLY 0x00001000
+#define PRINTER_ATTRIBUTE_PUBLISHED 0x00002000
+
+#define PRINTER_ATTRIBUTE_SAMBA (PRINTER_ATTRIBUTE_RAW_ONLY|\
+ PRINTER_ATTRIBUTE_SHARED|\
+ PRINTER_ATTRIBUTE_LOCAL)
+#define PRINTER_ATTRIBUTE_NOT_SAMBA (PRINTER_ATTRIBUTE_NETWORK)
+
+#define NO_PRIORITY 0
+#define MAX_PRIORITY 99
+#define MIN_PRIORITY 1
+#define DEF_PRIORITY 1
+
+/* the flags of the query */
+#define PRINTER_ENUM_DEFAULT 0x00000001
+#define PRINTER_ENUM_LOCAL 0x00000002
+#define PRINTER_ENUM_CONNECTIONS 0x00000004
+#define PRINTER_ENUM_FAVORITE 0x00000004
+#define PRINTER_ENUM_NAME 0x00000008
+#define PRINTER_ENUM_REMOTE 0x00000010
+#define PRINTER_ENUM_SHARED 0x00000020
+#define PRINTER_ENUM_NETWORK 0x00000040
+
+/* the flags of each printers */
+#define PRINTER_ENUM_UNKNOWN_8 0x00000008
+#define PRINTER_ENUM_EXPAND 0x00004000
+#define PRINTER_ENUM_CONTAINER 0x00008000
+#define PRINTER_ENUM_ICONMASK 0x00ff0000
+#define PRINTER_ENUM_ICON1 0x00010000
+#define PRINTER_ENUM_ICON2 0x00020000
+#define PRINTER_ENUM_ICON3 0x00040000
+#define PRINTER_ENUM_ICON4 0x00080000
+#define PRINTER_ENUM_ICON5 0x00100000
+#define PRINTER_ENUM_ICON6 0x00200000
+#define PRINTER_ENUM_ICON7 0x00400000
+#define PRINTER_ENUM_ICON8 0x00800000
+
+/* FLAGS for SPOOLSS_DELETEPRINTERDRIVEREX */
+
+#define DPD_DELETE_UNUSED_FILES 0x00000001
+#define DPD_DELETE_SPECIFIC_VERSION 0x00000002
+#define DPD_DELETE_ALL_FILES 0x00000004
+
+#define DRIVER_ANY_VERSION 0xffffffff
+#define DRIVER_MAX_VERSION 4
+
+/* FLAGS for SPOOLSS_ADDPRINTERDRIVEREX */
+
+#define APD_STRICT_UPGRADE 0x00000001
+#define APD_STRICT_DOWNGRADE 0x00000002
+#define APD_COPY_ALL_FILES 0x00000004
+#define APD_COPY_NEW_FILES 0x00000008
+
+
+/* this struct is undocumented */
+/* thanks to the ddk ... */
+typedef struct {
+ uint32 size; /* length of user_name & client_name + 2? */
+ UNISTR2 *client_name;
+ UNISTR2 *user_name;
+ uint32 build;
+ uint32 major;
+ uint32 minor;
+ uint32 processor;
+} SPOOL_USER_1;
+
+typedef struct {
+ uint32 level;
+ union {
+ SPOOL_USER_1 *user1;
+ } user;
+} SPOOL_USER_CTR;
+
+/*
+ * various bits in the DEVICEMODE.fields member
+ */
+
+#define DEVMODE_ORIENTATION 0x00000001
+#define DEVMODE_PAPERSIZE 0x00000002
+#define DEVMODE_PAPERLENGTH 0x00000004
+#define DEVMODE_PAPERWIDTH 0x00000008
+#define DEVMODE_SCALE 0x00000010
+#define DEVMODE_POSITION 0x00000020
+#define DEVMODE_NUP 0x00000040
+#define DEVMODE_COPIES 0x00000100
+#define DEVMODE_DEFAULTSOURCE 0x00000200
+#define DEVMODE_PRINTQUALITY 0x00000400
+#define DEVMODE_COLOR 0x00000800
+#define DEVMODE_DUPLEX 0x00001000
+#define DEVMODE_YRESOLUTION 0x00002000
+#define DEVMODE_TTOPTION 0x00004000
+#define DEVMODE_COLLATE 0x00008000
+#define DEVMODE_FORMNAME 0x00010000
+#define DEVMODE_LOGPIXELS 0x00020000
+#define DEVMODE_BITSPERPEL 0x00040000
+#define DEVMODE_PELSWIDTH 0x00080000
+#define DEVMODE_PELSHEIGHT 0x00100000
+#define DEVMODE_DISPLAYFLAGS 0x00200000
+#define DEVMODE_DISPLAYFREQUENCY 0x00400000
+#define DEVMODE_ICMMETHOD 0x00800000
+#define DEVMODE_ICMINTENT 0x01000000
+#define DEVMODE_MEDIATYPE 0x02000000
+#define DEVMODE_DITHERTYPE 0x04000000
+#define DEVMODE_PANNINGWIDTH 0x08000000
+#define DEVMODE_PANNINGHEIGHT 0x10000000
+
+
+/*
+ * Devicemode structure
+ */
+
+typedef struct devicemode
+{
+ UNISTR devicename;
+ uint16 specversion;
+ uint16 driverversion;
+ uint16 size;
+ uint16 driverextra;
+ uint32 fields;
+ uint16 orientation;
+ uint16 papersize;
+ uint16 paperlength;
+ uint16 paperwidth;
+ uint16 scale;
+ uint16 copies;
+ uint16 defaultsource;
+ uint16 printquality;
+ uint16 color;
+ uint16 duplex;
+ uint16 yresolution;
+ uint16 ttoption;
+ uint16 collate;
+ UNISTR formname;
+ uint16 logpixels;
+ uint32 bitsperpel;
+ uint32 pelswidth;
+ uint32 pelsheight;
+ uint32 displayflags;
+ uint32 displayfrequency;
+ uint32 icmmethod;
+ uint32 icmintent;
+ uint32 mediatype;
+ uint32 dithertype;
+ uint32 reserved1;
+ uint32 reserved2;
+ uint32 panningwidth;
+ uint32 panningheight;
+ uint8 *dev_private;
+}
+DEVICEMODE;
+
+typedef struct _devmode_cont
+{
+ uint32 size;
+ uint32 devmode_ptr;
+ DEVICEMODE *devmode;
+}
+DEVMODE_CTR;
+
+typedef struct _printer_default
+{
+ uint32 datatype_ptr;
+ UNISTR2 datatype;
+ DEVMODE_CTR devmode_cont;
+ uint32 access_required;
+}
+PRINTER_DEFAULT;
+
+/********************************************/
+
+typedef struct {
+ UNISTR2 *printername;
+ PRINTER_DEFAULT printer_default;
+} SPOOL_Q_OPEN_PRINTER;
+
+typedef struct {
+ POLICY_HND handle; /* handle used along all transactions (20*uint8) */
+ WERROR status;
+} SPOOL_R_OPEN_PRINTER;
+
+/********************************************/
+
+typedef struct {
+ UNISTR2 *printername;
+ PRINTER_DEFAULT printer_default;
+ uint32 user_switch;
+ SPOOL_USER_CTR user_ctr;
+} SPOOL_Q_OPEN_PRINTER_EX;
+
+typedef struct {
+ POLICY_HND handle; /* handle used along all transactions (20*uint8) */
+ WERROR status;
+} SPOOL_R_OPEN_PRINTER_EX;
+
+/********************************************/
+
+typedef struct spool_notify_option_type
+{
+ uint16 type;
+ uint16 reserved0;
+ uint32 reserved1;
+ uint32 reserved2;
+ uint32 count;
+ uint32 fields_ptr;
+ uint32 count2;
+ uint16 fields[MAX_NOTIFY_TYPE_FOR_NOW];
+}
+SPOOL_NOTIFY_OPTION_TYPE;
+
+typedef struct spool_notify_option_type_ctr
+{
+ uint32 count;
+ SPOOL_NOTIFY_OPTION_TYPE *type;
+}
+SPOOL_NOTIFY_OPTION_TYPE_CTR;
+
+
+
+typedef struct s_header_type
+{
+ uint32 type;
+ union
+ {
+ uint32 value;
+ UNISTR string;
+ }
+ data;
+}
+HEADER_TYPE;
+
+
+typedef struct spool_q_getprinterdata
+{
+ POLICY_HND handle;
+ UNISTR2 valuename;
+ uint32 size;
+}
+SPOOL_Q_GETPRINTERDATA;
+
+typedef struct spool_r_getprinterdata
+{
+ uint32 type;
+ uint32 size;
+ uint8 *data;
+ uint32 needed;
+ WERROR status;
+}
+SPOOL_R_GETPRINTERDATA;
+
+typedef struct spool_q_deleteprinterdata
+{
+ POLICY_HND handle;
+ UNISTR2 valuename;
+}
+SPOOL_Q_DELETEPRINTERDATA;
+
+typedef struct spool_r_deleteprinterdata
+{
+ WERROR status;
+}
+SPOOL_R_DELETEPRINTERDATA;
+
+typedef struct spool_q_closeprinter
+{
+ POLICY_HND handle;
+}
+SPOOL_Q_CLOSEPRINTER;
+
+typedef struct spool_r_closeprinter
+{
+ POLICY_HND handle;
+ WERROR status;
+}
+SPOOL_R_CLOSEPRINTER;
+
+typedef struct spool_q_startpageprinter
+{
+ POLICY_HND handle;
+}
+SPOOL_Q_STARTPAGEPRINTER;
+
+typedef struct spool_r_startpageprinter
+{
+ WERROR status;
+}
+SPOOL_R_STARTPAGEPRINTER;
+
+typedef struct spool_q_endpageprinter
+{
+ POLICY_HND handle;
+}
+SPOOL_Q_ENDPAGEPRINTER;
+
+typedef struct spool_r_endpageprinter
+{
+ WERROR status;
+}
+SPOOL_R_ENDPAGEPRINTER;
+
+
+typedef struct spool_q_deleteprinterdriver
+{
+ uint32 server_ptr;
+ UNISTR2 server;
+ UNISTR2 arch;
+ UNISTR2 driver;
+}
+SPOOL_Q_DELETEPRINTERDRIVER;
+
+typedef struct spool_r_deleteprinterdriver
+{
+ WERROR status;
+}
+SPOOL_R_DELETEPRINTERDRIVER;
+
+typedef struct spool_q_deleteprinterdriverex
+{
+ uint32 server_ptr;
+ UNISTR2 server;
+ UNISTR2 arch;
+ UNISTR2 driver;
+ uint32 delete_flags;
+ uint32 version;
+}
+SPOOL_Q_DELETEPRINTERDRIVEREX;
+
+typedef struct spool_r_deleteprinterdriverex
+{
+ WERROR status;
+}
+SPOOL_R_DELETEPRINTERDRIVEREX;
+
+
+typedef struct spool_doc_info_1
+{
+ uint32 p_docname;
+ uint32 p_outputfile;
+ uint32 p_datatype;
+ UNISTR2 docname;
+ UNISTR2 outputfile;
+ UNISTR2 datatype;
+}
+DOC_INFO_1;
+
+typedef struct spool_doc_info
+{
+ uint32 switch_value;
+ DOC_INFO_1 doc_info_1;
+}
+DOC_INFO;
+
+typedef struct spool_doc_info_container
+{
+ uint32 level;
+ DOC_INFO docinfo;
+}
+DOC_INFO_CONTAINER;
+
+typedef struct spool_q_startdocprinter
+{
+ POLICY_HND handle;
+ DOC_INFO_CONTAINER doc_info_container;
+}
+SPOOL_Q_STARTDOCPRINTER;
+
+typedef struct spool_r_startdocprinter
+{
+ uint32 jobid;
+ WERROR status;
+}
+SPOOL_R_STARTDOCPRINTER;
+
+typedef struct spool_q_enddocprinter
+{
+ POLICY_HND handle;
+}
+SPOOL_Q_ENDDOCPRINTER;
+
+typedef struct spool_r_enddocprinter
+{
+ WERROR status;
+}
+SPOOL_R_ENDDOCPRINTER;
+
+typedef struct spool_q_writeprinter
+{
+ POLICY_HND handle;
+ uint32 buffer_size;
+ uint8 *buffer;
+ uint32 buffer_size2;
+}
+SPOOL_Q_WRITEPRINTER;
+
+typedef struct spool_r_writeprinter
+{
+ uint32 buffer_written;
+ WERROR status;
+}
+SPOOL_R_WRITEPRINTER;
+
+typedef struct spool_notify_option
+{
+ uint32 version;
+ uint32 flags;
+ uint32 count;
+ uint32 option_type_ptr;
+ SPOOL_NOTIFY_OPTION_TYPE_CTR ctr;
+}
+SPOOL_NOTIFY_OPTION;
+
+typedef struct spool_notify_info_data
+{
+ uint16 type;
+ uint16 field;
+ uint32 reserved;
+ uint32 id;
+ union {
+ uint32 value[2];
+ struct {
+ uint32 length;
+ uint16 *string;
+ } data;
+ struct {
+ uint32 size;
+ SEC_DESC *desc;
+ } sd;
+ }
+ notify_data;
+ uint32 size;
+ uint32 enc_type;
+} SPOOL_NOTIFY_INFO_DATA;
+
+typedef struct spool_notify_info
+{
+ uint32 version;
+ uint32 flags;
+ uint32 count;
+ SPOOL_NOTIFY_INFO_DATA *data;
+}
+SPOOL_NOTIFY_INFO;
+
+/* If the struct name looks obscure, yes it is ! */
+/* RemoteFindFirstPrinterChangeNotificationEx query struct */
+typedef struct spoolss_q_rffpcnex
+{
+ POLICY_HND handle;
+ uint32 flags;
+ uint32 options;
+ uint32 localmachine_ptr;
+ UNISTR2 localmachine;
+ uint32 printerlocal;
+ uint32 option_ptr;
+ SPOOL_NOTIFY_OPTION *option;
+}
+SPOOL_Q_RFFPCNEX;
+
+typedef struct spool_r_rffpcnex
+{
+ WERROR status;
+}
+SPOOL_R_RFFPCNEX;
+
+/* Remote Find Next Printer Change Notify Ex */
+typedef struct spool_q_rfnpcnex
+{
+ POLICY_HND handle;
+ uint32 change;
+ uint32 option_ptr;
+ SPOOL_NOTIFY_OPTION *option;
+}
+SPOOL_Q_RFNPCNEX;
+
+typedef struct spool_r_rfnpcnex
+{
+ uint32 info_ptr;
+ SPOOL_NOTIFY_INFO info;
+ WERROR status;
+}
+SPOOL_R_RFNPCNEX;
+
+/* Find Close Printer Notify */
+typedef struct spool_q_fcpn
+{
+ POLICY_HND handle;
+}
+SPOOL_Q_FCPN;
+
+typedef struct spool_r_fcpn
+{
+ WERROR status;
+}
+SPOOL_R_FCPN;
+
+
+typedef struct printer_info_0
+{
+ UNISTR printername;
+ UNISTR servername;
+ uint32 cjobs;
+ uint32 total_jobs;
+ uint32 total_bytes;
+
+ uint16 year;
+ uint16 month;
+ uint16 dayofweek;
+ uint16 day;
+ uint16 hour;
+ uint16 minute;
+ uint16 second;
+ uint16 milliseconds;
+
+ uint32 global_counter;
+ uint32 total_pages;
+
+ uint16 major_version;
+ uint16 build_version;
+
+ uint32 unknown7;
+ uint32 unknown8;
+ uint32 unknown9;
+ uint32 session_counter;
+ uint32 unknown11;
+ uint32 printer_errors;
+ uint32 unknown13;
+ uint32 unknown14;
+ uint32 unknown15;
+ uint32 unknown16;
+ uint32 change_id;
+ uint32 unknown18;
+ uint32 status;
+ uint32 unknown20;
+ uint32 c_setprinter;
+
+ uint16 unknown22;
+ uint16 unknown23;
+ uint16 unknown24;
+ uint16 unknown25;
+ uint16 unknown26;
+ uint16 unknown27;
+ uint16 unknown28;
+ uint16 unknown29;
+} PRINTER_INFO_0;
+
+typedef struct printer_info_1
+{
+ uint32 flags;
+ UNISTR description;
+ UNISTR name;
+ UNISTR comment;
+}
+PRINTER_INFO_1;
+
+typedef struct printer_info_2
+{
+ UNISTR servername;
+ UNISTR printername;
+ UNISTR sharename;
+ UNISTR portname;
+ UNISTR drivername;
+ UNISTR comment;
+ UNISTR location;
+ DEVICEMODE *devmode;
+ UNISTR sepfile;
+ UNISTR printprocessor;
+ UNISTR datatype;
+ UNISTR parameters;
+ SEC_DESC *secdesc;
+ uint32 attributes;
+ uint32 priority;
+ uint32 defaultpriority;
+ uint32 starttime;
+ uint32 untiltime;
+ uint32 status;
+ uint32 cjobs;
+ uint32 averageppm;
+}
+PRINTER_INFO_2;
+
+typedef struct printer_info_3
+{
+ SEC_DESC *secdesc;
+}
+PRINTER_INFO_3;
+
+typedef struct printer_info_4
+{
+ UNISTR printername;
+ UNISTR servername;
+ uint32 attributes;
+}
+PRINTER_INFO_4;
+
+typedef struct printer_info_5
+{
+ UNISTR printername;
+ UNISTR portname;
+ uint32 attributes;
+ uint32 device_not_selected_timeout;
+ uint32 transmission_retry_timeout;
+}
+PRINTER_INFO_5;
+
+typedef struct printer_info_6
+{
+ uint32 status;
+}
+PRINTER_INFO_6;
+
+#define SPOOL_DS_PUBLISH 1
+#define SPOOL_DS_UPDATE 2
+#define SPOOL_DS_UNPUBLISH 4
+#define SPOOL_DS_PENDING 0x80000000
+
+typedef struct printer_info_7
+{
+ UNISTR guid; /* text form of printer guid */
+ uint32 action;
+}
+PRINTER_INFO_7;
+
+typedef struct spool_q_enumprinters
+{
+ uint32 flags;
+ uint32 servername_ptr;
+ UNISTR2 servername;
+ uint32 level;
+ RPC_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ENUMPRINTERS;
+
+typedef struct printer_info_ctr_info
+{
+ PRINTER_INFO_0 *printers_0;
+ PRINTER_INFO_1 *printers_1;
+ PRINTER_INFO_2 *printers_2;
+ PRINTER_INFO_3 *printers_3;
+ PRINTER_INFO_4 *printers_4;
+ PRINTER_INFO_5 *printers_5;
+ PRINTER_INFO_7 *printers_7;
+}
+PRINTER_INFO_CTR;
+
+typedef struct spool_r_enumprinters
+{
+ RPC_BUFFER *buffer;
+ uint32 needed; /* bytes needed */
+ uint32 returned; /* number of printers */
+ WERROR status;
+}
+SPOOL_R_ENUMPRINTERS;
+
+
+typedef struct spool_q_getprinter
+{
+ POLICY_HND handle;
+ uint32 level;
+ RPC_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_GETPRINTER;
+
+typedef struct printer_info_info
+{
+ union
+ {
+ PRINTER_INFO_0 *info0;
+ PRINTER_INFO_1 *info1;
+ PRINTER_INFO_2 *info2;
+ void *info;
+ } printer;
+} PRINTER_INFO;
+
+typedef struct spool_r_getprinter
+{
+ RPC_BUFFER *buffer;
+ uint32 needed;
+ WERROR status;
+} SPOOL_R_GETPRINTER;
+
+typedef struct driver_info_1
+{
+ UNISTR name;
+} DRIVER_INFO_1;
+
+typedef struct driver_info_2
+{
+ uint32 version;
+ UNISTR name;
+ UNISTR architecture;
+ UNISTR driverpath;
+ UNISTR datafile;
+ UNISTR configfile;
+} DRIVER_INFO_2;
+
+typedef struct driver_info_3
+{
+ uint32 version;
+ UNISTR name;
+ UNISTR architecture;
+ UNISTR driverpath;
+ UNISTR datafile;
+ UNISTR configfile;
+ UNISTR helpfile;
+ uint16 *dependentfiles;
+ UNISTR monitorname;
+ UNISTR defaultdatatype;
+}
+DRIVER_INFO_3;
+
+typedef struct driver_info_6
+{
+ uint32 version;
+ UNISTR name;
+ UNISTR architecture;
+ UNISTR driverpath;
+ UNISTR datafile;
+ UNISTR configfile;
+ UNISTR helpfile;
+ uint16 *dependentfiles;
+ UNISTR monitorname;
+ UNISTR defaultdatatype;
+ uint16* previousdrivernames;
+ NTTIME driver_date;
+ uint32 padding;
+ uint32 driver_version_low;
+ uint32 driver_version_high;
+ UNISTR mfgname;
+ UNISTR oem_url;
+ UNISTR hardware_id;
+ UNISTR provider;
+}
+DRIVER_INFO_6;
+
+typedef struct driver_info_info
+{
+ DRIVER_INFO_1 *info1;
+ DRIVER_INFO_2 *info2;
+ DRIVER_INFO_3 *info3;
+ DRIVER_INFO_6 *info6;
+}
+PRINTER_DRIVER_CTR;
+
+typedef struct spool_q_getprinterdriver2
+{
+ POLICY_HND handle;
+ uint32 architecture_ptr;
+ UNISTR2 architecture;
+ uint32 level;
+ RPC_BUFFER *buffer;
+ uint32 offered;
+ uint32 clientmajorversion;
+ uint32 clientminorversion;
+}
+SPOOL_Q_GETPRINTERDRIVER2;
+
+typedef struct spool_r_getprinterdriver2
+{
+ RPC_BUFFER *buffer;
+ uint32 needed;
+ uint32 servermajorversion;
+ uint32 serverminorversion;
+ WERROR status;
+}
+SPOOL_R_GETPRINTERDRIVER2;
+
+
+typedef struct add_jobinfo_1
+{
+ UNISTR path;
+ uint32 job_number;
+}
+ADD_JOBINFO_1;
+
+
+typedef struct spool_q_addjob
+{
+ POLICY_HND handle;
+ uint32 level;
+ RPC_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ADDJOB;
+
+typedef struct spool_r_addjob
+{
+ RPC_BUFFER *buffer;
+ uint32 needed;
+ WERROR status;
+}
+SPOOL_R_ADDJOB;
+
+/*
+ * I'm really wondering how many different time formats
+ * I will have to cope with
+ *
+ * JFM, 09/13/98 In a mad mood ;-(
+*/
+typedef struct systemtime
+{
+ uint16 year;
+ uint16 month;
+ uint16 dayofweek;
+ uint16 day;
+ uint16 hour;
+ uint16 minute;
+ uint16 second;
+ uint16 milliseconds;
+}
+SYSTEMTIME;
+
+typedef struct s_job_info_1
+{
+ uint32 jobid;
+ UNISTR printername;
+ UNISTR machinename;
+ UNISTR username;
+ UNISTR document;
+ UNISTR datatype;
+ UNISTR text_status;
+ uint32 status;
+ uint32 priority;
+ uint32 position;
+ uint32 totalpages;
+ uint32 pagesprinted;
+ SYSTEMTIME submitted;
+}
+JOB_INFO_1;
+
+typedef struct s_job_info_2
+{
+ uint32 jobid;
+ UNISTR printername;
+ UNISTR machinename;
+ UNISTR username;
+ UNISTR document;
+ UNISTR notifyname;
+ UNISTR datatype;
+ UNISTR printprocessor;
+ UNISTR parameters;
+ UNISTR drivername;
+ DEVICEMODE *devmode;
+ UNISTR text_status;
+/* SEC_DESC sec_desc;*/
+ uint32 status;
+ uint32 priority;
+ uint32 position;
+ uint32 starttime;
+ uint32 untiltime;
+ uint32 totalpages;
+ uint32 size;
+ SYSTEMTIME submitted;
+ uint32 timeelapsed;
+ uint32 pagesprinted;
+}
+JOB_INFO_2;
+
+typedef struct spool_q_enumjobs
+{
+ POLICY_HND handle;
+ uint32 firstjob;
+ uint32 numofjobs;
+ uint32 level;
+ RPC_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ENUMJOBS;
+
+typedef struct job_info_ctr_info
+{
+ union
+ {
+ JOB_INFO_1 *job_info_1;
+ JOB_INFO_2 *job_info_2;
+ void *info;
+ } job;
+
+} JOB_INFO_CTR;
+
+typedef struct spool_r_enumjobs
+{
+ RPC_BUFFER *buffer;
+ uint32 needed;
+ uint32 returned;
+ WERROR status;
+}
+SPOOL_R_ENUMJOBS;
+
+typedef struct spool_q_schedulejob
+{
+ POLICY_HND handle;
+ uint32 jobid;
+}
+SPOOL_Q_SCHEDULEJOB;
+
+typedef struct spool_r_schedulejob
+{
+ WERROR status;
+}
+SPOOL_R_SCHEDULEJOB;
+
+typedef struct s_port_info_1
+{
+ UNISTR port_name;
+}
+PORT_INFO_1;
+
+typedef struct s_port_info_2
+{
+ UNISTR port_name;
+ UNISTR monitor_name;
+ UNISTR description;
+ uint32 port_type;
+ uint32 reserved;
+}
+PORT_INFO_2;
+
+/* Port Type bits */
+#define PORT_TYPE_WRITE 0x0001
+#define PORT_TYPE_READ 0x0002
+#define PORT_TYPE_REDIRECTED 0x0004
+#define PORT_TYPE_NET_ATTACHED 0x0008
+
+typedef struct spool_q_enumports
+{
+ uint32 name_ptr;
+ UNISTR2 name;
+ uint32 level;
+ RPC_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ENUMPORTS;
+
+typedef struct port_info_ctr_info
+{
+ union
+ {
+ PORT_INFO_1 *info_1;
+ PORT_INFO_2 *info_2;
+ }
+ port;
+
+}
+PORT_INFO_CTR;
+
+typedef struct spool_r_enumports
+{
+ RPC_BUFFER *buffer;
+ uint32 needed; /* bytes needed */
+ uint32 returned; /* number of printers */
+ WERROR status;
+}
+SPOOL_R_ENUMPORTS;
+
+#define JOB_CONTROL_PAUSE 1
+#define JOB_CONTROL_RESUME 2
+#define JOB_CONTROL_CANCEL 3
+#define JOB_CONTROL_RESTART 4
+#define JOB_CONTROL_DELETE 5
+
+typedef struct job_info_info
+{
+ union
+ {
+ JOB_INFO_1 job_info_1;
+ JOB_INFO_2 job_info_2;
+ }
+ job;
+
+}
+JOB_INFO;
+
+typedef struct spool_q_setjob
+{
+ POLICY_HND handle;
+ uint32 jobid;
+ uint32 level;
+ JOB_INFO ctr;
+ uint32 command;
+
+}
+SPOOL_Q_SETJOB;
+
+typedef struct spool_r_setjob
+{
+ WERROR status;
+
+}
+SPOOL_R_SETJOB;
+
+typedef struct spool_q_enumprinterdrivers
+{
+ uint32 name_ptr;
+ UNISTR2 name;
+ uint32 environment_ptr;
+ UNISTR2 environment;
+ uint32 level;
+ RPC_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ENUMPRINTERDRIVERS;
+
+typedef struct spool_r_enumprinterdrivers
+{
+ RPC_BUFFER *buffer;
+ uint32 needed;
+ uint32 returned;
+ WERROR status;
+}
+SPOOL_R_ENUMPRINTERDRIVERS;
+
+#define FORM_USER 0
+#define FORM_BUILTIN 1
+#define FORM_PRINTER 2
+
+typedef struct spool_form_1
+{
+ uint32 flag;
+ UNISTR name;
+ uint32 width;
+ uint32 length;
+ uint32 left;
+ uint32 top;
+ uint32 right;
+ uint32 bottom;
+}
+FORM_1;
+
+typedef struct spool_q_enumforms
+{
+ POLICY_HND handle;
+ uint32 level;
+ RPC_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ENUMFORMS;
+
+typedef struct spool_r_enumforms
+{
+ RPC_BUFFER *buffer;
+ uint32 needed;
+ uint32 numofforms;
+ WERROR status;
+}
+SPOOL_R_ENUMFORMS;
+
+typedef struct spool_q_getform
+{
+ POLICY_HND handle;
+ UNISTR2 formname;
+ uint32 level;
+ RPC_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_GETFORM;
+
+typedef struct spool_r_getform
+{
+ RPC_BUFFER *buffer;
+ uint32 needed;
+ WERROR status;
+}
+SPOOL_R_GETFORM;
+
+typedef struct spool_printer_info_level_1
+{
+ uint32 flags;
+ uint32 description_ptr;
+ uint32 name_ptr;
+ uint32 comment_ptr;
+ UNISTR2 description;
+ UNISTR2 name;
+ UNISTR2 comment;
+} SPOOL_PRINTER_INFO_LEVEL_1;
+
+typedef struct spool_printer_info_level_2
+{
+ uint32 servername_ptr;
+ uint32 printername_ptr;
+ uint32 sharename_ptr;
+ uint32 portname_ptr;
+ uint32 drivername_ptr;
+ uint32 comment_ptr;
+ uint32 location_ptr;
+ uint32 devmode_ptr;
+ uint32 sepfile_ptr;
+ uint32 printprocessor_ptr;
+ uint32 datatype_ptr;
+ uint32 parameters_ptr;
+ uint32 secdesc_ptr;
+ uint32 attributes;
+ uint32 priority;
+ uint32 default_priority;
+ uint32 starttime;
+ uint32 untiltime;
+ uint32 status;
+ uint32 cjobs;
+ uint32 averageppm;
+ UNISTR2 servername;
+ UNISTR2 printername;
+ UNISTR2 sharename;
+ UNISTR2 portname;
+ UNISTR2 drivername;
+ UNISTR2 comment;
+ UNISTR2 location;
+ UNISTR2 sepfile;
+ UNISTR2 printprocessor;
+ UNISTR2 datatype;
+ UNISTR2 parameters;
+}
+SPOOL_PRINTER_INFO_LEVEL_2;
+
+typedef struct spool_printer_info_level_3
+{
+ uint32 secdesc_ptr;
+}
+SPOOL_PRINTER_INFO_LEVEL_3;
+
+typedef struct spool_printer_info_level_7
+{
+ uint32 guid_ptr;
+ uint32 action;
+ UNISTR2 guid;
+}
+SPOOL_PRINTER_INFO_LEVEL_7;
+
+typedef struct spool_printer_info_level
+{
+ uint32 level;
+ uint32 info_ptr;
+ SPOOL_PRINTER_INFO_LEVEL_1 *info_1;
+ SPOOL_PRINTER_INFO_LEVEL_2 *info_2;
+ SPOOL_PRINTER_INFO_LEVEL_3 *info_3;
+ SPOOL_PRINTER_INFO_LEVEL_7 *info_7;
+}
+SPOOL_PRINTER_INFO_LEVEL;
+
+typedef struct spool_printer_driver_info_level_3
+{
+ uint32 cversion;
+ uint32 name_ptr;
+ uint32 environment_ptr;
+ uint32 driverpath_ptr;
+ uint32 datafile_ptr;
+ uint32 configfile_ptr;
+ uint32 helpfile_ptr;
+ uint32 monitorname_ptr;
+ uint32 defaultdatatype_ptr;
+ uint32 dependentfilessize;
+ uint32 dependentfiles_ptr;
+
+ UNISTR2 name;
+ UNISTR2 environment;
+ UNISTR2 driverpath;
+ UNISTR2 datafile;
+ UNISTR2 configfile;
+ UNISTR2 helpfile;
+ UNISTR2 monitorname;
+ UNISTR2 defaultdatatype;
+ BUFFER5 dependentfiles;
+
+}
+SPOOL_PRINTER_DRIVER_INFO_LEVEL_3;
+
+/* SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 structure */
+typedef struct {
+ uint32 version;
+ uint32 name_ptr;
+ uint32 environment_ptr;
+ uint32 driverpath_ptr;
+ uint32 datafile_ptr;
+ uint32 configfile_ptr;
+ uint32 helpfile_ptr;
+ uint32 monitorname_ptr;
+ uint32 defaultdatatype_ptr;
+ uint32 dependentfiles_len;
+ uint32 dependentfiles_ptr;
+ uint32 previousnames_len;
+ uint32 previousnames_ptr;
+ NTTIME driverdate;
+ uint64 driverversion;
+ uint32 dummy4;
+ uint32 mfgname_ptr;
+ uint32 oemurl_ptr;
+ uint32 hardwareid_ptr;
+ uint32 provider_ptr;
+ UNISTR2 name;
+ UNISTR2 environment;
+ UNISTR2 driverpath;
+ UNISTR2 datafile;
+ UNISTR2 configfile;
+ UNISTR2 helpfile;
+ UNISTR2 monitorname;
+ UNISTR2 defaultdatatype;
+ BUFFER5 dependentfiles;
+ BUFFER5 previousnames;
+ UNISTR2 mfgname;
+ UNISTR2 oemurl;
+ UNISTR2 hardwareid;
+ UNISTR2 provider;
+} SPOOL_PRINTER_DRIVER_INFO_LEVEL_6;
+
+
+typedef struct spool_printer_driver_info_level
+{
+ uint32 level;
+ uint32 ptr;
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 *info_3;
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 *info_6;
+}
+SPOOL_PRINTER_DRIVER_INFO_LEVEL;
+
+
+typedef struct spool_q_setprinter
+{
+ POLICY_HND handle;
+ uint32 level;
+ SPOOL_PRINTER_INFO_LEVEL info;
+ SEC_DESC_BUF *secdesc_ctr;
+ DEVMODE_CTR devmode_ctr;
+
+ uint32 command;
+
+}
+SPOOL_Q_SETPRINTER;
+
+typedef struct spool_r_setprinter
+{
+ WERROR status;
+}
+SPOOL_R_SETPRINTER;
+
+/********************************************/
+
+typedef struct {
+ POLICY_HND handle;
+} SPOOL_Q_DELETEPRINTER;
+
+typedef struct {
+ POLICY_HND handle;
+ WERROR status;
+} SPOOL_R_DELETEPRINTER;
+
+/********************************************/
+
+typedef struct {
+ POLICY_HND handle;
+} SPOOL_Q_ABORTPRINTER;
+
+typedef struct {
+ WERROR status;
+} SPOOL_R_ABORTPRINTER;
+
+
+/********************************************/
+
+typedef struct {
+ UNISTR2 *server_name;
+ uint32 level;
+ SPOOL_PRINTER_INFO_LEVEL info;
+ DEVMODE_CTR devmode_ctr;
+ SEC_DESC_BUF *secdesc_ctr;
+ uint32 user_switch;
+ SPOOL_USER_CTR user_ctr;
+} SPOOL_Q_ADDPRINTEREX;
+
+typedef struct {
+ POLICY_HND handle;
+ WERROR status;
+} SPOOL_R_ADDPRINTEREX;
+
+/********************************************/
+
+typedef struct spool_q_addprinterdriver
+{
+ uint32 server_name_ptr;
+ UNISTR2 server_name;
+ uint32 level;
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL info;
+}
+SPOOL_Q_ADDPRINTERDRIVER;
+
+typedef struct spool_r_addprinterdriver
+{
+ WERROR status;
+}
+SPOOL_R_ADDPRINTERDRIVER;
+
+typedef struct spool_q_addprinterdriverex
+{
+ uint32 server_name_ptr;
+ UNISTR2 server_name;
+ uint32 level;
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL info;
+ uint32 copy_flags;
+}
+SPOOL_Q_ADDPRINTERDRIVEREX;
+
+typedef struct spool_r_addprinterdriverex
+{
+ WERROR status;
+}
+SPOOL_R_ADDPRINTERDRIVEREX;
+
+
+typedef struct driver_directory_1
+{
+ UNISTR name;
+}
+DRIVER_DIRECTORY_1;
+
+typedef struct driver_info_ctr_info
+{
+ DRIVER_DIRECTORY_1 *info1;
+}
+DRIVER_DIRECTORY_CTR;
+
+typedef struct spool_q_getprinterdriverdirectory
+{
+ uint32 name_ptr;
+ UNISTR2 name;
+ uint32 environment_ptr;
+ UNISTR2 environment;
+ uint32 level;
+ RPC_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_GETPRINTERDRIVERDIR;
+
+typedef struct spool_r_getprinterdriverdirectory
+{
+ RPC_BUFFER *buffer;
+ uint32 needed;
+ WERROR status;
+}
+SPOOL_R_GETPRINTERDRIVERDIR;
+
+typedef struct spool_q_addprintprocessor
+{
+ uint32 server_ptr;
+ UNISTR2 server;
+ UNISTR2 environment;
+ UNISTR2 path;
+ UNISTR2 name;
+}
+SPOOL_Q_ADDPRINTPROCESSOR;
+
+typedef struct spool_r_addprintprocessor
+{
+ WERROR status;
+}
+SPOOL_R_ADDPRINTPROCESSOR;
+
+
+typedef struct spool_q_enumprintprocessors
+{
+ uint32 name_ptr;
+ UNISTR2 name;
+ uint32 environment_ptr;
+ UNISTR2 environment;
+ uint32 level;
+ RPC_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ENUMPRINTPROCESSORS;
+
+typedef struct printprocessor_1
+{
+ UNISTR name;
+}
+PRINTPROCESSOR_1;
+
+typedef struct spool_r_enumprintprocessors
+{
+ RPC_BUFFER *buffer;
+ uint32 needed;
+ uint32 returned;
+ WERROR status;
+}
+SPOOL_R_ENUMPRINTPROCESSORS;
+
+typedef struct spool_q_enumprintprocdatatypes
+{
+ uint32 name_ptr;
+ UNISTR2 name;
+ uint32 processor_ptr;
+ UNISTR2 processor;
+ uint32 level;
+ RPC_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ENUMPRINTPROCDATATYPES;
+
+typedef struct ppdatatype_1
+{
+ UNISTR name;
+}
+PRINTPROCDATATYPE_1;
+
+typedef struct spool_r_enumprintprocdatatypes
+{
+ RPC_BUFFER *buffer;
+ uint32 needed;
+ uint32 returned;
+ WERROR status;
+}
+SPOOL_R_ENUMPRINTPROCDATATYPES;
+
+typedef struct printmonitor_1
+{
+ UNISTR name;
+}
+PRINTMONITOR_1;
+
+typedef struct printmonitor_2
+{
+ UNISTR name;
+ UNISTR environment;
+ UNISTR dll_name;
+}
+PRINTMONITOR_2;
+
+typedef struct spool_q_enumprintmonitors
+{
+ uint32 name_ptr;
+ UNISTR2 name;
+ uint32 level;
+ RPC_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ENUMPRINTMONITORS;
+
+typedef struct spool_r_enumprintmonitors
+{
+ RPC_BUFFER *buffer;
+ uint32 needed;
+ uint32 returned;
+ WERROR status;
+}
+SPOOL_R_ENUMPRINTMONITORS;
+
+
+typedef struct spool_q_enumprinterdata
+{
+ POLICY_HND handle;
+ uint32 index;
+ uint32 valuesize;
+ uint32 datasize;
+}
+SPOOL_Q_ENUMPRINTERDATA;
+
+typedef struct spool_r_enumprinterdata
+{
+ uint32 valuesize;
+ uint16 *value;
+ uint32 realvaluesize;
+ uint32 type;
+ uint32 datasize;
+ uint8 *data;
+ uint32 realdatasize;
+ WERROR status;
+}
+SPOOL_R_ENUMPRINTERDATA;
+
+typedef struct spool_q_setprinterdata
+{
+ POLICY_HND handle;
+ UNISTR2 value;
+ uint32 type;
+ uint32 max_len;
+ uint8 *data;
+ uint32 real_len;
+ uint32 numeric_data;
+}
+SPOOL_Q_SETPRINTERDATA;
+
+typedef struct spool_r_setprinterdata
+{
+ WERROR status;
+}
+SPOOL_R_SETPRINTERDATA;
+
+typedef struct spool_q_resetprinter
+{
+ POLICY_HND handle;
+ uint32 datatype_ptr;
+ UNISTR2 datatype;
+ DEVMODE_CTR devmode_ctr;
+
+} SPOOL_Q_RESETPRINTER;
+
+typedef struct spool_r_resetprinter
+{
+ WERROR status;
+}
+SPOOL_R_RESETPRINTER;
+
+
+
+typedef struct _form
+{
+ uint32 flags;
+ uint32 name_ptr;
+ uint32 size_x;
+ uint32 size_y;
+ uint32 left;
+ uint32 top;
+ uint32 right;
+ uint32 bottom;
+ UNISTR2 name;
+}
+FORM;
+
+typedef struct spool_q_addform
+{
+ POLICY_HND handle;
+ uint32 level;
+ uint32 level2; /* This should really be part of the FORM structure */
+ FORM form;
+}
+SPOOL_Q_ADDFORM;
+
+typedef struct spool_r_addform
+{
+ WERROR status;
+}
+SPOOL_R_ADDFORM;
+
+typedef struct spool_q_setform
+{
+ POLICY_HND handle;
+ UNISTR2 name;
+ uint32 level;
+ uint32 level2;
+ FORM form;
+}
+SPOOL_Q_SETFORM;
+
+typedef struct spool_r_setform
+{
+ WERROR status;
+}
+SPOOL_R_SETFORM;
+
+typedef struct spool_q_deleteform
+{
+ POLICY_HND handle;
+ UNISTR2 name;
+}
+SPOOL_Q_DELETEFORM;
+
+typedef struct spool_r_deleteform
+{
+ WERROR status;
+}
+SPOOL_R_DELETEFORM;
+
+typedef struct spool_q_getjob
+{
+ POLICY_HND handle;
+ uint32 jobid;
+ uint32 level;
+ RPC_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_GETJOB;
+
+typedef struct pjob_info_info
+{
+ union
+ {
+ JOB_INFO_1 *job_info_1;
+ JOB_INFO_2 *job_info_2;
+ void *info;
+ }
+ job;
+
+}
+PJOB_INFO;
+
+typedef struct spool_r_getjob
+{
+ RPC_BUFFER *buffer;
+ uint32 needed;
+ WERROR status;
+}
+SPOOL_R_GETJOB;
+
+typedef struct spool_q_replyopenprinter
+{
+ UNISTR2 string;
+ uint32 printer;
+ uint32 type;
+ uint32 unknown0;
+ uint32 unknown1;
+}
+SPOOL_Q_REPLYOPENPRINTER;
+
+typedef struct spool_r_replyopenprinter
+{
+ POLICY_HND handle;
+ WERROR status;
+}
+SPOOL_R_REPLYOPENPRINTER;
+
+typedef struct spool_q_routerreplyprinter
+{
+ POLICY_HND handle;
+ uint32 condition;
+ uint32 unknown1; /* 0x00000001 */
+ uint32 change_id;
+ uint8 unknown2[5]; /* 0x0000000001 */
+}
+SPOOL_Q_ROUTERREPLYPRINTER;
+
+typedef struct spool_r_routerreplyprinter
+{
+ WERROR status;
+}
+SPOOL_R_ROUTERREPLYPRINTER;
+
+typedef struct spool_q_replycloseprinter
+{
+ POLICY_HND handle;
+}
+SPOOL_Q_REPLYCLOSEPRINTER;
+
+typedef struct spool_r_replycloseprinter
+{
+ POLICY_HND handle;
+ WERROR status;
+}
+SPOOL_R_REPLYCLOSEPRINTER;
+
+typedef struct spool_q_rrpcn
+{
+ POLICY_HND handle;
+ uint32 change_low;
+ uint32 change_high;
+ uint32 unknown0;
+ uint32 unknown1;
+ uint32 info_ptr;
+ SPOOL_NOTIFY_INFO info;
+}
+SPOOL_Q_REPLY_RRPCN;
+
+typedef struct spool_r_rrpcn
+{
+ uint32 unknown0;
+ WERROR status;
+}
+SPOOL_R_REPLY_RRPCN;
+
+typedef struct spool_q_getprinterdataex
+{
+ POLICY_HND handle;
+ UNISTR2 keyname;
+ UNISTR2 valuename;
+ uint32 size;
+}
+SPOOL_Q_GETPRINTERDATAEX;
+
+typedef struct spool_r_getprinterdataex
+{
+ uint32 type;
+ uint32 size;
+ uint8 *data;
+ uint32 needed;
+ WERROR status;
+}
+SPOOL_R_GETPRINTERDATAEX;
+
+typedef struct spool_q_setprinterdataex
+{
+ POLICY_HND handle;
+ UNISTR2 key;
+ UNISTR2 value;
+ uint32 type;
+ uint32 max_len;
+ uint8 *data;
+ uint32 real_len;
+ uint32 numeric_data;
+}
+SPOOL_Q_SETPRINTERDATAEX;
+
+typedef struct spool_r_setprinterdataex
+{
+ WERROR status;
+}
+SPOOL_R_SETPRINTERDATAEX;
+
+
+typedef struct spool_q_deleteprinterdataex
+{
+ POLICY_HND handle;
+ UNISTR2 keyname;
+ UNISTR2 valuename;
+}
+SPOOL_Q_DELETEPRINTERDATAEX;
+
+typedef struct spool_r_deleteprinterdataex
+{
+ WERROR status;
+}
+SPOOL_R_DELETEPRINTERDATAEX;
+
+
+typedef struct spool_q_enumprinterkey
+{
+ POLICY_HND handle;
+ UNISTR2 key;
+ uint32 size;
+}
+SPOOL_Q_ENUMPRINTERKEY;
+
+typedef struct spool_r_enumprinterkey
+{
+ BUFFER5 keys;
+ uint32 needed; /* in bytes */
+ WERROR status;
+}
+SPOOL_R_ENUMPRINTERKEY;
+
+typedef struct spool_q_deleteprinterkey
+{
+ POLICY_HND handle;
+ UNISTR2 keyname;
+}
+SPOOL_Q_DELETEPRINTERKEY;
+
+typedef struct spool_r_deleteprinterkey
+{
+ WERROR status;
+}
+SPOOL_R_DELETEPRINTERKEY;
+
+typedef struct printer_enum_values
+{
+ UNISTR valuename;
+ uint32 value_len;
+ uint32 type;
+ uint8 *data;
+ uint32 data_len;
+
+}
+PRINTER_ENUM_VALUES;
+
+typedef struct printer_enum_values_ctr
+{
+ uint32 size;
+ uint32 size_of_array;
+ PRINTER_ENUM_VALUES *values;
+}
+PRINTER_ENUM_VALUES_CTR;
+
+typedef struct spool_q_enumprinterdataex
+{
+ POLICY_HND handle;
+ UNISTR2 key;
+ uint32 size;
+}
+SPOOL_Q_ENUMPRINTERDATAEX;
+
+typedef struct spool_r_enumprinterdataex
+{
+ PRINTER_ENUM_VALUES_CTR ctr;
+ uint32 needed;
+ uint32 returned;
+ WERROR status;
+}
+SPOOL_R_ENUMPRINTERDATAEX;
+
+typedef struct printprocessor_directory_1
+{
+ UNISTR name;
+}
+PRINTPROCESSOR_DIRECTORY_1;
+
+typedef struct spool_q_getprintprocessordirectory
+{
+ UNISTR2 name;
+ UNISTR2 environment;
+ uint32 level;
+ RPC_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_GETPRINTPROCESSORDIRECTORY;
+
+typedef struct spool_r_getprintprocessordirectory
+{
+ RPC_BUFFER *buffer;
+ uint32 needed;
+ WERROR status;
+}
+SPOOL_R_GETPRINTPROCESSORDIRECTORY;
+
+/**************************************/
+
+#define MAX_PORTNAME 64
+#define MAX_NETWORK_NAME 49
+#define MAX_SNMP_COMM_NAME 33
+#define MAX_QUEUE_NAME 33
+#define MAX_IPADDR_STRING 17
+
+typedef struct {
+ uint16 portname[MAX_PORTNAME];
+ uint32 version;
+ uint32 protocol;
+ uint32 size;
+ uint32 reserved;
+ uint16 hostaddress[MAX_NETWORK_NAME];
+ uint16 snmpcommunity[MAX_SNMP_COMM_NAME];
+ uint32 dblspool;
+ uint16 queue[MAX_QUEUE_NAME];
+ uint16 ipaddress[MAX_IPADDR_STRING];
+ uint32 port;
+ uint32 snmpenabled;
+ uint32 snmpdevindex;
+} SPOOL_PORT_DATA_1;
+
+typedef struct {
+ POLICY_HND handle;
+ UNISTR2 dataname;
+ RPC_BUFFER indata;
+ uint32 indata_len;
+ uint32 offered;
+ uint32 unknown;
+} SPOOL_Q_XCVDATAPORT;
+
+typedef struct {
+ RPC_BUFFER outdata;
+ uint32 needed;
+ uint32 unknown;
+ WERROR status;
+} SPOOL_R_XCVDATAPORT;
+
+#define PRINTER_DRIVER_VERSION 2
+#define PRINTER_DRIVER_ARCHITECTURE "Windows NT x86"
+
+#endif /* _RPC_SPOOLSS_H */
+
diff --git a/source3/include/rpc_svcctl.h b/source3/include/rpc_svcctl.h
new file mode 100644
index 0000000000..aa1d1662c8
--- /dev/null
+++ b/source3/include/rpc_svcctl.h
@@ -0,0 +1,259 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1997,
+ Copyright (C) Gerald (Jerry) Carter 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _RPC_SVCCTL_H /* _RPC_SVCCTL_H */
+#define _RPC_SVCCTL_H
+
+/* svcctl pipe */
+
+#define SVCCTL_CLOSE_SERVICE 0x00
+#define SVCCTL_CONTROL_SERVICE 0x01
+#define SVCCTL_LOCK_SERVICE_DB 0x03
+#define SVCCTL_QUERY_SERVICE_SEC 0x04
+#define SVCCTL_SET_SERVICE_SEC 0x05
+#define SVCCTL_QUERY_STATUS 0x06
+#define SVCCTL_UNLOCK_SERVICE_DB 0x08
+#define SVCCTL_ENUM_DEPENDENT_SERVICES_W 0x0d
+#define SVCCTL_ENUM_SERVICES_STATUS_W 0x0e
+#define SVCCTL_OPEN_SCMANAGER_W 0x0f
+#define SVCCTL_OPEN_SERVICE_W 0x10
+#define SVCCTL_QUERY_SERVICE_CONFIG_W 0x11
+#define SVCCTL_START_SERVICE_W 0x13
+#define SVCCTL_GET_DISPLAY_NAME 0x14
+#define SVCCTL_QUERY_SERVICE_CONFIG2_W 0x27
+#define SVCCTL_QUERY_SERVICE_STATUSEX_W 0x28
+
+/* ANSI versions not implemented currently
+#define SVCCTL_ENUM_SERVICES_STATUS_A 0x0e
+#define SVCCTL_OPEN_SCMANAGER_A 0x1b
+*/
+
+/* SERVER_STATUS - type */
+
+#define SVCCTL_TYPE_WIN32 0x00000030
+#define SVCCTL_TYPE_DRIVER 0x0000000f
+
+/* SERVER_STATUS - state */
+#define SVCCTL_STATE_ACTIVE 0x00000001
+#define SVCCTL_STATE_INACTIVE 0x00000002
+#define SVCCTL_STATE_ALL ( SVCCTL_STATE_ACTIVE | SVCCTL_STATE_INACTIVE )
+
+/* SERVER_STATUS - CurrentState */
+
+#define SVCCTL_STATE_UNKNOWN 0x00000000 /* only used internally to smbd */
+#define SVCCTL_STOPPED 0x00000001
+#define SVCCTL_START_PENDING 0x00000002
+#define SVCCTL_STOP_PENDING 0x00000003
+#define SVCCTL_RUNNING 0x00000004
+#define SVCCTL_CONTINUE_PENDING 0x00000005
+#define SVCCTL_PAUSE_PENDING 0x00000006
+#define SVCCTL_PAUSED 0x00000007
+
+/* SERVER_STATUS - ControlAccepted */
+
+#define SVCCTL_ACCEPT_NONE 0x00000000
+#define SVCCTL_ACCEPT_STOP 0x00000001
+#define SVCCTL_ACCEPT_PAUSE_CONTINUE 0x00000002
+#define SVCCTL_ACCEPT_SHUTDOWN 0x00000004
+#define SVCCTL_ACCEPT_PARAMCHANGE 0x00000008
+#define SVCCTL_ACCEPT_NETBINDCHANGE 0x00000010
+#define SVCCTL_ACCEPT_HARDWAREPROFILECHANGE 0x00000020
+#define SVCCTL_ACCEPT_POWEREVENT 0x00000040
+
+/* SERVER_STATUS - ControlAccepted */
+#define SVCCTL_SVC_ERROR_IGNORE 0x00000000
+#define SVCCTL_SVC_ERROR_NORMAL 0x00000001
+#define SVCCTL_SVC_ERROR_CRITICAL 0x00000002
+#define SVCCTL_SVC_ERROR_SEVERE 0x00000003
+
+/* QueryServiceConfig2 options */
+#define SERVICE_CONFIG_DESCRIPTION 0x00000001
+#define SERVICE_CONFIG_FAILURE_ACTIONS 0x00000002
+
+
+/* Service Config - values for ServiceType field*/
+
+#define SVCCTL_KERNEL_DRVR 0x00000001 /* doubtful we'll have these */
+#define SVCCTL_FILE_SYSTEM_DRVR 0x00000002
+#define SVCCTL_WIN32_OWN_PROC 0x00000010
+#define SVCCTL_WIN32_SHARED_PROC 0x00000020
+#define SVCCTL_WIN32_INTERACTIVE 0x00000100
+
+/* Service Config - values for StartType field */
+#define SVCCTL_BOOT_START 0x00000000
+#define SVCCTL_SYSTEM_START 0x00000001
+#define SVCCTL_AUTO_START 0x00000002
+#define SVCCTL_DEMAND_START 0x00000003
+#define SVCCTL_DISABLED 0x00000004
+
+/* Service Controls */
+
+#define SVCCTL_CONTROL_STOP 0x00000001
+#define SVCCTL_CONTROL_PAUSE 0x00000002
+#define SVCCTL_CONTROL_CONTINUE 0x00000003
+#define SVCCTL_CONTROL_INTERROGATE 0x00000004
+#define SVCCTL_CONTROL_SHUTDOWN 0x00000005
+
+#define SVC_HANDLE_IS_SCM 0x0000001
+#define SVC_HANDLE_IS_SERVICE 0x0000002
+#define SVC_HANDLE_IS_DBLOCK 0x0000003
+
+#define SVC_STATUS_PROCESS_INFO 0x00000000
+
+/* where we assume the location of the service control scripts */
+#define SVCCTL_SCRIPT_DIR "svcctl"
+
+/* utility structures for RPCs */
+
+/*
+ * "struct SERVICE_STATUS" comes from librpc/gen_ndr/svcctl.h
+ */
+
+typedef struct SERVICE_STATUS SERVICE_STATUS;
+
+typedef struct {
+ SERVICE_STATUS status;
+ uint32 process_id;
+ uint32 service_flags;
+} SERVICE_STATUS_PROCESS;
+
+
+typedef struct {
+ UNISTR servicename;
+ UNISTR displayname;
+ SERVICE_STATUS status;
+} ENUM_SERVICES_STATUS;
+
+typedef struct {
+ uint32 service_type;
+ uint32 start_type;
+ uint32 error_control;
+ UNISTR2 *executablepath;
+ UNISTR2 *loadordergroup;
+ uint32 tag_id;
+ UNISTR2 *dependencies;
+ UNISTR2 *startname;
+ UNISTR2 *displayname;
+} SERVICE_CONFIG;
+
+typedef struct {
+ uint32 unknown;
+ UNISTR description;
+} SERVICE_DESCRIPTION;
+
+typedef struct {
+ uint32 type;
+ uint32 delay;
+} SC_ACTION;
+
+typedef struct {
+ uint32 reset_period;
+ UNISTR2 *rebootmsg; /* i have no idea if these are UNISTR2's. I can't get a good trace */
+ UNISTR2 *command;
+ uint32 num_actions;
+ SC_ACTION *actions;
+} SERVICE_FAILURE_ACTIONS;
+
+/*
+ * dispatch table of functions to handle the =ServiceControl API
+ */
+
+typedef struct {
+ /* functions for enumerating subkeys and values */
+ WERROR (*stop_service)( const char *service, SERVICE_STATUS *status );
+ WERROR (*start_service) ( const char *service );
+ WERROR (*service_status)( const char *service, SERVICE_STATUS *status );
+} SERVICE_CONTROL_OPS;
+
+/* structure to store the service handle information */
+
+typedef struct _ServiceInfo {
+ uint8 type;
+ char *name;
+ uint32 access_granted;
+ SERVICE_CONTROL_OPS *ops;
+} SERVICE_INFO;
+
+
+/* rpc structures */
+
+/**************************/
+
+typedef struct {
+ POLICY_HND handle;
+ uint32 type;
+ uint32 state;
+ uint32 buffer_size;
+ uint32 *resume;
+} SVCCTL_Q_ENUM_SERVICES_STATUS;
+
+typedef struct {
+ RPC_BUFFER buffer;
+ uint32 needed;
+ uint32 returned;
+ uint32 *resume;
+ WERROR status;
+} SVCCTL_R_ENUM_SERVICES_STATUS;
+
+/**************************/
+
+typedef struct {
+ POLICY_HND handle;
+ uint32 buffer_size;
+} SVCCTL_Q_QUERY_SERVICE_CONFIG;
+
+typedef struct {
+ SERVICE_CONFIG config;
+ uint32 needed;
+ WERROR status;
+} SVCCTL_R_QUERY_SERVICE_CONFIG;
+
+
+/**************************/
+
+typedef struct {
+ POLICY_HND handle;
+ uint32 level;
+ uint32 buffer_size;
+} SVCCTL_Q_QUERY_SERVICE_CONFIG2;
+
+typedef struct {
+ RPC_BUFFER buffer;
+ uint32 needed;
+ WERROR status;
+} SVCCTL_R_QUERY_SERVICE_CONFIG2;
+
+
+/**************************/
+
+typedef struct {
+ POLICY_HND handle;
+ uint32 level;
+ uint32 buffer_size;
+} SVCCTL_Q_QUERY_SERVICE_STATUSEX;
+
+typedef struct {
+ RPC_BUFFER buffer;
+ uint32 needed;
+ WERROR status;
+} SVCCTL_R_QUERY_SERVICE_STATUSEX;
+
+#endif /* _RPC_SVCCTL_H */
+
diff --git a/source3/include/safe_string.h b/source3/include/safe_string.h
new file mode 100644
index 0000000000..c030acf8fd
--- /dev/null
+++ b/source3/include/safe_string.h
@@ -0,0 +1,226 @@
+/*
+ Unix SMB/CIFS implementation.
+ Safe string handling routines.
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAFE_STRING_H
+#define _SAFE_STRING_H
+
+#ifndef _SPLINT_ /* http://www.splint.org */
+
+/* Some macros to ensure people don't use buffer overflow vulnerable string
+ functions. */
+
+#ifdef bcopy
+#undef bcopy
+#endif /* bcopy */
+#define bcopy(src,dest,size) __ERROR__XX__NEVER_USE_BCOPY___;
+
+#ifdef strcpy
+#undef strcpy
+#endif /* strcpy */
+#define strcpy(dest,src) __ERROR__XX__NEVER_USE_STRCPY___;
+
+#ifdef strcat
+#undef strcat
+#endif /* strcat */
+#define strcat(dest,src) __ERROR__XX__NEVER_USE_STRCAT___;
+
+#ifdef sprintf
+#undef sprintf
+#endif /* sprintf */
+#define sprintf __ERROR__XX__NEVER_USE_SPRINTF__;
+
+/*
+ * strcasecmp/strncasecmp aren't an error, but it means you're not thinking about
+ * multibyte. Don't use them. JRA.
+ */
+#ifdef strcasecmp
+#undef strcasecmp
+#endif
+#define strcasecmp __ERROR__XX__NEVER_USE_STRCASECMP__;
+
+#ifdef strncasecmp
+#undef strncasecmp
+#endif
+#define strncasecmp __ERROR__XX__NEVER_USE_STRNCASECMP__;
+
+#endif /* !_SPLINT_ */
+
+#ifdef DEVELOPER
+#define SAFE_STRING_FUNCTION_NAME FUNCTION_MACRO
+#define SAFE_STRING_LINE __LINE__
+#else
+#define SAFE_STRING_FUNCTION_NAME ("")
+#define SAFE_STRING_LINE (0)
+#endif
+
+/* We need a number of different prototypes for our
+ non-existant fuctions */
+char * __unsafe_string_function_usage_here__(void);
+
+size_t __unsafe_string_function_usage_here_size_t__(void);
+
+size_t __unsafe_string_function_usage_here_char__(void);
+
+#ifdef HAVE_COMPILER_WILL_OPTIMIZE_OUT_FNS
+
+/* if the compiler will optimize out function calls, then use this to tell if we are
+ have the correct types (this works only where sizeof() returns the size of the buffer, not
+ the size of the pointer). */
+
+#define CHECK_STRING_SIZE(d, len) (sizeof(d) != (len) && sizeof(d) != sizeof(char *))
+
+#else /* HAVE_COMPILER_WILL_OPTIMIZE_OUT_FNS */
+
+#endif /* HAVE_COMPILER_WILL_OPTIMIZE_OUT_FNS */
+
+#define safe_strcpy_base(dest, src, base, size) \
+ safe_strcpy(dest, src, size-PTR_DIFF(dest,base)-1)
+
+/* String copy functions - macro hell below adds 'type checking' (limited,
+ but the best we can do in C) and may tag with function name/number to
+ record the last 'clobber region' on that string */
+
+#define fstrcpy(d,s) safe_strcpy((d),(s),sizeof(fstring)-1)
+#define fstrcat(d,s) safe_strcat((d),(s),sizeof(fstring)-1)
+#define nstrcpy(d,s) safe_strcpy((d), (s),sizeof(nstring)-1)
+#define unstrcpy(d,s) safe_strcpy((d), (s),sizeof(unstring)-1)
+
+/* the addition of the DEVELOPER checks in safe_strcpy means we must
+ * update a lot of code. To make this a little easier here are some
+ * functions that provide the lengths with less pain */
+
+/* Inside the _fn variants of these is a call to clobber_region(), -
+ * which might destroy the stack on a buggy function. We help the
+ * debugging process by putting the function and line who last caused
+ * a clobbering into a static buffer. If the program crashes at
+ * address 0xf1f1f1f1 then this function is probably, but not
+ * necessarily, to blame. */
+
+/* overmalloc_safe_strcpy: DEPRECATED! Used when you know the
+ * destination buffer is longer than maxlength, but you don't know how
+ * long. This is not a good situation, because we can't do the normal
+ * sanity checks. Don't use in new code! */
+
+#define overmalloc_safe_strcpy(dest,src,maxlength) \
+ safe_strcpy_fn(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, \
+ dest,src,maxlength)
+
+#define safe_strcpy(dest,src,maxlength) \
+ safe_strcpy_fn2(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, \
+ dest,src,maxlength)
+
+#define safe_strcat(dest,src,maxlength) \
+ safe_strcat_fn2(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, \
+ dest,src,maxlength)
+
+#define push_string(base_ptr, dest, src, dest_len, flags) \
+ push_string_fn2(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, \
+ base_ptr, 0, dest, src, dest_len, flags)
+
+#define pull_string(base_ptr, smb_flags2, dest, src, dest_len, src_len, flags) \
+ pull_string_fn2(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, \
+ base_ptr, smb_flags2, dest, src, dest_len, src_len, flags)
+
+#define pull_string_talloc(ctx, base_ptr, smb_flags2, dest, src, src_len, flags) \
+ pull_string_talloc_fn2(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, \
+ ctx, base_ptr, smb_flags2, dest, src, src_len, flags)
+
+#define clistr_push(cli, dest, src, dest_len, flags) \
+ clistr_push_fn2(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, \
+ cli, dest, src, dest_len, flags)
+
+#define clistr_pull(cli, dest, src, dest_len, src_len, flags) \
+ clistr_pull_fn2(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, \
+ cli, dest, src, dest_len, src_len, flags)
+
+#define clistr_pull_talloc(ctx, cli, pp_dest, src, src_len, flags) \
+ clistr_pull_talloc_fn(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, \
+ ctx, cli, pp_dest, src, src_len, flags)
+
+#define srvstr_push(base_ptr, smb_flags2, dest, src, dest_len, flags) \
+ srvstr_push_fn2(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, \
+ base_ptr, smb_flags2, dest, src, dest_len, flags)
+
+#define alpha_strcpy(dest,src,other_safe_chars,maxlength) \
+ alpha_strcpy_fn(SAFE_STRING_FUNCTION_NAME,SAFE_STRING_LINE, \
+ dest,src,other_safe_chars,maxlength)
+
+#define StrnCpy(dest,src,n) \
+ StrnCpy_fn(SAFE_STRING_FUNCTION_NAME,SAFE_STRING_LINE, \
+ dest,src,n)
+
+#ifdef HAVE_COMPILER_WILL_OPTIMIZE_OUT_FNS
+
+/* if the compiler will optimize out function calls, then use this to tell if we are
+ have the correct types (this works only where sizeof() returns the size of the buffer, not
+ the size of the pointer). */
+
+#define safe_strcpy_fn2(fn_name, fn_line, d, s, max_len) \
+ (CHECK_STRING_SIZE(d, max_len+1) \
+ ? __unsafe_string_function_usage_here__() \
+ : safe_strcpy_fn(fn_name, fn_line, (d), (s), (max_len)))
+
+#define safe_strcat_fn2(fn_name, fn_line, d, s, max_len) \
+ (CHECK_STRING_SIZE(d, max_len+1) \
+ ? __unsafe_string_function_usage_here__() \
+ : safe_strcat_fn(fn_name, fn_line, (d), (s), (max_len)))
+
+#define push_string_fn2(fn_name, fn_line, base_ptr, flags2, dest, src, dest_len, flags) \
+ (CHECK_STRING_SIZE(dest, dest_len) \
+ ? __unsafe_string_function_usage_here_size_t__() \
+ : push_string_fn(fn_name, fn_line, base_ptr, flags2, dest, src, dest_len, flags))
+
+#define pull_string_fn2(fn_name, fn_line, base_ptr, smb_flags2, dest, src, dest_len, src_len, flags) \
+ (CHECK_STRING_SIZE(dest, dest_len) \
+ ? __unsafe_string_function_usage_here_size_t__() \
+ : pull_string_fn(fn_name, fn_line, base_ptr, smb_flags2, dest, src, dest_len, src_len, flags))
+
+#define pull_string_talloc_fn2(fn_name, fn_line, ctx, base_ptr, smb_flags2, dest, src, src_len, flags) \
+ pull_string_talloc_fn(fn_name, fn_line, ctx, base_ptr, smb_flags2, dest, src, src_len, flags)
+
+#define clistr_push_fn2(fn_name, fn_line, cli, dest, src, dest_len, flags) \
+ (CHECK_STRING_SIZE(dest, dest_len) \
+ ? __unsafe_string_function_usage_here_size_t__() \
+ : clistr_push_fn(fn_name, fn_line, cli, dest, src, dest_len, flags))
+
+#define clistr_pull_fn2(fn_name, fn_line, cli, dest, src, dest_len, srclen, flags) \
+ (CHECK_STRING_SIZE(dest, dest_len) \
+ ? __unsafe_string_function_usage_here_size_t__() \
+ : clistr_pull_fn(fn_name, fn_line, cli, dest, src, dest_len, srclen, flags))
+
+#define srvstr_push_fn2(fn_name, fn_line, base_ptr, smb_flags2, dest, src, dest_len, flags) \
+ (CHECK_STRING_SIZE(dest, dest_len) \
+ ? __unsafe_string_function_usage_here_size_t__() \
+ : srvstr_push_fn(fn_name, fn_line, base_ptr, smb_flags2, dest, src, dest_len, flags))
+
+#else
+
+#define safe_strcpy_fn2 safe_strcpy_fn
+#define safe_strcat_fn2 safe_strcat_fn
+#define push_string_fn2 push_string_fn
+#define pull_string_fn2 pull_string_fn
+#define pull_string_talloc_fn2 pull_string_talloc_fn
+#define clistr_push_fn2 clistr_push_fn
+#define clistr_pull_fn2 clistr_pull_fn
+#define srvstr_push_fn2 srvstr_push_fn
+
+#endif
+
+#endif
diff --git a/source3/include/samba_linux_quota.h b/source3/include/samba_linux_quota.h
new file mode 100644
index 0000000000..8dbbec237f
--- /dev/null
+++ b/source3/include/samba_linux_quota.h
@@ -0,0 +1,335 @@
+#ifndef _SAMBA_LINUX_QUOTA_H_
+#define _SAMBA_LINUX_QUOTA_H_
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Andrew Tridgell 1994-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ This file is needed because Quota support on Linux has
+ been broken since Linus kernel 2.4.x. It will only get
+ better (and this file be removed) when all the distributions
+ ship a glibc with a working quota.h file. This is very
+ bad. JRA.
+
+ Original file came from Christoph Hellwig <hch@infradead.org>.
+ Massaged into one nasty include file (to stop us having to
+ add multiple files into Samba just for Linux braindamage)
+ by JRA.
+*/
+
+#undef QUOTABLOCK_SIZE
+
+#ifndef _QUOTAIO_LINUX_V1
+#define _QUOTAIO_LINUX_V1
+
+/*
+ * Headerfile for old quotafile format
+ */
+
+#include <sys/types.h>
+
+#define V1_DQBLK_SIZE_BITS 10
+#define V1_DQBLK_SIZE (1 << V1_DQBLK_SIZE_BITS) /* Size of one quota block in bytes in old format */
+
+#define V1_DQOFF(__id) ((loff_t) ((__id) * sizeof(struct v1_disk_dqblk)))
+
+/* Structure of quota on disk */
+struct v1_disk_dqblk {
+ u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */
+ u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */
+ u_int32_t dqb_curblocks; /* current block count */
+ u_int32_t dqb_ihardlimit; /* maximum # allocated inodes */
+ u_int32_t dqb_isoftlimit; /* preferred limit on inodes */
+ u_int32_t dqb_curinodes; /* current # allocated inodes */
+ time_t dqb_btime; /* time limit for excessive disk use */
+ time_t dqb_itime; /* time limit for excessive files */
+} __attribute__ ((packed));
+
+/* Structure used for communication with kernel */
+struct v1_kern_dqblk {
+ u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */
+ u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */
+ u_int32_t dqb_curblocks; /* current block count */
+ u_int32_t dqb_ihardlimit; /* maximum # allocated inodes */
+ u_int32_t dqb_isoftlimit; /* preferred inode limit */
+ u_int32_t dqb_curinodes; /* current # allocated inodes */
+ time_t dqb_btime; /* time limit for excessive disk use */
+ time_t dqb_itime; /* time limit for excessive files */
+};
+
+struct v1_dqstats {
+ u_int32_t lookups;
+ u_int32_t drops;
+ u_int32_t reads;
+ u_int32_t writes;
+ u_int32_t cache_hits;
+ u_int32_t allocated_dquots;
+ u_int32_t free_dquots;
+ u_int32_t syncs;
+};
+
+#ifndef Q_V1_GETQUOTA
+#define Q_V1_GETQUOTA 0x300
+#endif
+#ifndef Q_V1_SETQUOTA
+#define Q_V1_SETQUOTA 0x400
+#endif
+
+#endif /* _QUOTAIO_LINUX_V1 */
+
+/*
+ *
+ * Header file for disk format of new quotafile format
+ *
+ */
+
+#ifndef _QUOTAIO_LINUX_V2
+#define _QUOTAIO_LINUX_V2
+
+#include <sys/types.h>
+
+#ifndef _QUOTA_LINUX
+#define _QUOTA_LINUX
+
+#include <sys/types.h>
+
+typedef u_int32_t qid_t; /* Type in which we store ids in memory */
+typedef u_int64_t qsize_t; /* Type in which we store size limitations */
+
+#define MAXQUOTAS 2
+#define USRQUOTA 0 /* element used for user quotas */
+#define GRPQUOTA 1 /* element used for group quotas */
+
+/*
+ * Definitions for the default names of the quotas files.
+ */
+#define INITQFNAMES { \
+ "user", /* USRQUOTA */ \
+ "group", /* GRPQUOTA */ \
+ "undefined", \
+}
+
+/*
+ * Definitions of magics and versions of current quota files
+ */
+#define INITQMAGICS {\
+ 0xd9c01f11, /* USRQUOTA */\
+ 0xd9c01927 /* GRPQUOTA */\
+}
+
+/* Size of blocks in which are counted size limits in generic utility parts */
+#define QUOTABLOCK_BITS 10
+#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
+
+/* Conversion routines from and to quota blocks */
+#define qb2kb(x) ((x) << (QUOTABLOCK_BITS-10))
+#define kb2qb(x) ((x) >> (QUOTABLOCK_BITS-10))
+#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS)
+
+/*
+ * Command definitions for the 'quotactl' system call.
+ * The commands are broken into a main command defined below
+ * and a subcommand that is used to convey the type of
+ * quota that is being manipulated (see above).
+ */
+#define SUBCMDMASK 0x00ff
+#define SUBCMDSHIFT 8
+#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
+
+#define Q_6_5_QUOTAON 0x0100 /* enable quotas */
+#define Q_6_5_QUOTAOFF 0x0200 /* disable quotas */
+#define Q_6_5_SYNC 0x0600 /* sync disk copy of a filesystems quotas */
+
+#define Q_SYNC 0x800001 /* sync disk copy of a filesystems quotas */
+#define Q_QUOTAON 0x800002 /* turn quotas on */
+#define Q_QUOTAOFF 0x800003 /* turn quotas off */
+#define Q_GETFMT 0x800004 /* get quota format used on given filesystem */
+#define Q_GETINFO 0x800005 /* get information about quota files */
+#define Q_SETINFO 0x800006 /* set information about quota files */
+#define Q_GETQUOTA 0x800007 /* get user quota structure */
+#define Q_SETQUOTA 0x800008 /* set user quota structure */
+
+/*
+ * Quota structure used for communication with userspace via quotactl
+ * Following flags are used to specify which fields are valid
+ */
+#define QIF_BLIMITS 1
+#define QIF_SPACE 2
+#define QIF_ILIMITS 4
+#define QIF_INODES 8
+#define QIF_BTIME 16
+#define QIF_ITIME 32
+#define QIF_LIMITS (QIF_BLIMITS | QIF_ILIMITS)
+#define QIF_USAGE (QIF_SPACE | QIF_INODES)
+#define QIF_TIMES (QIF_BTIME | QIF_ITIME)
+#define QIF_ALL (QIF_LIMITS | QIF_USAGE | QIF_TIMES)
+
+struct if_dqblk {
+ u_int64_t dqb_bhardlimit;
+ u_int64_t dqb_bsoftlimit;
+ u_int64_t dqb_curspace;
+ u_int64_t dqb_ihardlimit;
+ u_int64_t dqb_isoftlimit;
+ u_int64_t dqb_curinodes;
+ u_int64_t dqb_btime;
+ u_int64_t dqb_itime;
+ u_int32_t dqb_valid;
+};
+
+/*
+ * Structure used for setting quota information about file via quotactl
+ * Following flags are used to specify which fields are valid
+ */
+#define IIF_BGRACE 1
+#define IIF_IGRACE 2
+#define IIF_FLAGS 4
+#define IIF_ALL (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS)
+
+struct if_dqinfo {
+ u_int64_t dqi_bgrace;
+ u_int64_t dqi_igrace;
+ u_int32_t dqi_flags;
+ u_int32_t dqi_valid;
+};
+
+/* Quota format identifiers */
+#define QFMT_VFS_OLD 1
+#define QFMT_VFS_V0 2
+
+/* Flags supported by kernel */
+#define V1_DQF_RSQUASH 1
+
+/* Ioctl for getting quota size */
+#include <sys/ioctl.h>
+#ifndef FIOQSIZE
+ #if defined(__alpha__) || defined(__powerpc__) || defined(__sh__) || defined(__sparc__) || defined(__sparc64__)
+ #define FIOQSIZE _IOR('f', 128, loff_t)
+ #elif defined(__arm__) || defined(__mc68000__) || defined(__s390__)
+ #define FIOQSIZE 0x545E
+ #elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__ia64__) || defined(__parisc__) || defined(__cris__) || defined(__hppa__)
+ #define FIOQSIZE 0x5460
+ #elif defined(__mips__) || defined(__mips64__)
+ #define FIOQSIZE 0x6667
+ #endif
+#endif
+
+long quotactl __P((int, const char *, qid_t, caddr_t));
+
+#endif /* _QUOTA_LINUX */
+
+#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) /* Offset of info header in file */
+#define V2_DQBLKSIZE_BITS 10
+#define V2_DQBLKSIZE (1 << V2_DQBLKSIZE_BITS) /* Size of block with quota structures */
+#define V2_DQTREEOFF 1 /* Offset of tree in file in blOcks */
+#define V2_DQTREEDEPTH 4 /* Depth of quota tree */
+#define V2_DQSTRINBLK ((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk)) /* Number of entries in one blocks */
+#define V2_GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
+#define V2_GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)(buf)) + sizeof(struct v2_disk_dqdbheader)))
+#define INIT_V2_VERSIONS { 0, 0}
+
+struct v2_disk_dqheader {
+ u_int32_t dqh_magic; /* Magic number identifying file */
+ u_int32_t dqh_version; /* File version */
+} __attribute__ ((packed));
+
+/* Flags for version specific files */
+#define V2_DQF_MASK 0x0000 /* Mask for all valid ondisk flags */
+
+/* Header with type and version specific information */
+struct v2_disk_dqinfo {
+ u_int32_t dqi_bgrace; /* Time before block soft limit becomes hard limit */
+ u_int32_t dqi_igrace; /* Time before inode soft limit becomes hard limit */
+ u_int32_t dqi_flags; /* Flags for quotafile (DQF_*) */
+ u_int32_t dqi_blocks; /* Number of blocks in file */
+ u_int32_t dqi_free_blk; /* Number of first free block in the list */
+ u_int32_t dqi_free_entry; /* Number of block with at least one free entry */
+} __attribute__ ((packed));
+
+/*
+ * Structure of header of block with quota structures. It is padded to 16 bytes so
+ * there will be space for exactly 18 quota-entries in a block
+ */
+struct v2_disk_dqdbheader {
+ u_int32_t dqdh_next_free; /* Number of next block with free entry */
+ u_int32_t dqdh_prev_free; /* Number of previous block with free entry */
+ u_int16_t dqdh_entries; /* Number of valid entries in block */
+ u_int16_t dqdh_pad1;
+ u_int32_t dqdh_pad2;
+} __attribute__ ((packed));
+
+/* Structure of quota for one user on disk */
+struct v2_disk_dqblk {
+ u_int32_t dqb_id; /* id this quota applies to */
+ u_int32_t dqb_ihardlimit; /* absolute limit on allocated inodes */
+ u_int32_t dqb_isoftlimit; /* preferred inode limit */
+ u_int32_t dqb_curinodes; /* current # allocated inodes */
+ u_int32_t dqb_bhardlimit; /* absolute limit on disk space (in QUOTABLOCK_SIZE) */
+ u_int32_t dqb_bsoftlimit; /* preferred limit on disk space (in QUOTABLOCK_SIZE) */
+ u_int64_t dqb_curspace; /* current space occupied (in bytes) */
+ u_int64_t dqb_btime; /* time limit for excessive disk use */
+ u_int64_t dqb_itime; /* time limit for excessive inode use */
+} __attribute__ ((packed));
+
+/* Structure of quota for communication with kernel */
+struct v2_kern_dqblk {
+ unsigned int dqb_ihardlimit;
+ unsigned int dqb_isoftlimit;
+ unsigned int dqb_curinodes;
+ unsigned int dqb_bhardlimit;
+ unsigned int dqb_bsoftlimit;
+ qsize_t dqb_curspace;
+ time_t dqb_btime;
+ time_t dqb_itime;
+};
+
+/* Structure of quotafile info for communication with kernel */
+struct v2_kern_dqinfo {
+ unsigned int dqi_bgrace;
+ unsigned int dqi_igrace;
+ unsigned int dqi_flags;
+ unsigned int dqi_blocks;
+ unsigned int dqi_free_blk;
+ unsigned int dqi_free_entry;
+};
+
+/* Structure with gathered statistics from kernel */
+struct v2_dqstats {
+ u_int32_t lookups;
+ u_int32_t drops;
+ u_int32_t reads;
+ u_int32_t writes;
+ u_int32_t cache_hits;
+ u_int32_t allocated_dquots;
+ u_int32_t free_dquots;
+ u_int32_t syncs;
+ u_int32_t version;
+};
+
+#ifndef Q_V2_GETQUOTA
+#define Q_V2_GETQUOTA 0x0D00
+#endif
+#ifndef Q_V2_SETQUOTA
+#define Q_V2_SETQUOTA 0x0E00
+#endif
+
+#endif /* _QUOTAIO_LINUX_V2 */
+
+#ifndef QUOTABLOCK_SIZE
+#define QUOTABLOCK_SIZE 1024
+#endif
+
+#endif /* _SAMBA_LINUX_QUOTA_H_ */
diff --git a/source3/include/secrets.h b/source3/include/secrets.h
new file mode 100644
index 0000000000..d9f457558b
--- /dev/null
+++ b/source3/include/secrets.h
@@ -0,0 +1,102 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * secrets.tdb file format info
+ * Copyright (C) Andrew Tridgell 2000
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SECRETS_H
+#define _SECRETS_H
+
+/* the first one is for the hashed password (NT4 style) the latter
+ for plaintext (ADS)
+*/
+#define SECRETS_MACHINE_ACCT_PASS "SECRETS/$MACHINE.ACC"
+#define SECRETS_MACHINE_PASSWORD "SECRETS/MACHINE_PASSWORD"
+#define SECRETS_MACHINE_LAST_CHANGE_TIME "SECRETS/MACHINE_LAST_CHANGE_TIME"
+#define SECRETS_MACHINE_SEC_CHANNEL_TYPE "SECRETS/MACHINE_SEC_CHANNEL_TYPE"
+#define SECRETS_MACHINE_TRUST_ACCOUNT_NAME "SECRETS/SECRETS_MACHINE_TRUST_ACCOUNT_NAME"
+/* this one is for storing trusted domain account password */
+#define SECRETS_DOMTRUST_ACCT_PASS "SECRETS/$DOMTRUST.ACC"
+
+/* Store the principal name used for Kerberos DES key salt under this key name. */
+#define SECRETS_SALTING_PRINCIPAL "SECRETS/SALTING_PRINCIPAL"
+
+/* The domain sid and our sid are stored here even though they aren't
+ really secret. */
+#define SECRETS_DOMAIN_SID "SECRETS/SID"
+#define SECRETS_SAM_SID "SAM/SID"
+
+/* The domain GUID and server GUID (NOT the same) are also not secret */
+#define SECRETS_DOMAIN_GUID "SECRETS/DOMGUID"
+#define SECRETS_SERVER_GUID "SECRETS/GUID"
+
+#define SECRETS_LDAP_BIND_PW "SECRETS/LDAP_BIND_PW"
+
+/* Authenticated user info is stored in secrets.tdb under these keys */
+
+#define SECRETS_AUTH_USER "SECRETS/AUTH_USER"
+#define SECRETS_AUTH_DOMAIN "SECRETS/AUTH_DOMAIN"
+#define SECRETS_AUTH_PASSWORD "SECRETS/AUTH_PASSWORD"
+
+/* structure for storing machine account password
+ (ie. when samba server is member of a domain */
+struct machine_acct_pass {
+ uint8 hash[16];
+ time_t mod_time;
+};
+
+/*
+ * storage structure for trusted domain
+ */
+typedef struct trusted_dom_pass {
+ size_t uni_name_len;
+ smb_ucs2_t uni_name[32]; /* unicode domain name */
+ size_t pass_len;
+ fstring pass; /* trust relationship's password */
+ time_t mod_time;
+ DOM_SID domain_sid; /* remote domain's sid */
+} TRUSTED_DOM_PASS;
+
+/*
+ * trusted domain entry/entries returned by secrets_get_trusted_domains
+ * (used in _lsa_enum_trust_dom call)
+ */
+struct trustdom_info {
+ char *name;
+ DOM_SID sid;
+};
+
+/*
+ * Format of an OpenAFS keyfile
+ */
+
+#define SECRETS_AFS_MAXKEYS 8
+
+struct afs_key {
+ uint32 kvno;
+ char key[8];
+};
+
+struct afs_keyfile {
+ uint32 nkeys;
+ struct afs_key entry[SECRETS_AFS_MAXKEYS];
+};
+
+#define SECRETS_AFS_KEYFILE "SECRETS/AFS_KEYFILE"
+
+#define SECRETS_SCHANNEL_STATE "SECRETS/SCHANNEL"
+
+#endif /* _SECRETS_H */
diff --git a/source3/include/session.h b/source3/include/session.h
new file mode 100644
index 0000000000..2aca1df94d
--- /dev/null
+++ b/source3/include/session.h
@@ -0,0 +1,42 @@
+/*
+ Unix SMB/CIFS implementation.
+ session handling for recording currently vailid vuids
+
+ Copyright (C) tridge@samba.org 2001
+ Copyright (C) Andew Bartlett <abartlet@samba.org> 2001
+ Copyright (C) Gerald (Jerry) Carter 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* a "session" is claimed when we do a SessionSetupX operation
+ and is yielded when the corresponding vuid is destroyed.
+
+ sessions are used to populate utmp and PAM session structures
+*/
+
+struct sessionid {
+ uid_t uid;
+ gid_t gid;
+ fstring username;
+ fstring hostname;
+ fstring netbios_name;
+ fstring remote_machine;
+ fstring id_str;
+ uint32 id_num;
+ struct server_id pid;
+ fstring ip_addr_str;
+ time_t connect_start;
+};
+
diff --git a/source3/include/smb.h b/source3/include/smb.h
new file mode 100644
index 0000000000..c8c4f8c3cc
--- /dev/null
+++ b/source3/include/smb.h
@@ -0,0 +1,1904 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup, plus a whole lot more.
+
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) John H Terpstra 1996-2002
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Paul Ashton 1998-2000
+ Copyright (C) Simo Sorce 2001-2002
+ Copyright (C) Martin Pool 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SMB_H
+#define _SMB_H
+
+/* logged when starting the various Samba daemons */
+#define COPYRIGHT_STARTUP_MESSAGE "Copyright Andrew Tridgell and the Samba Team 1992-2008"
+
+
+#if defined(LARGE_SMB_OFF_T)
+#define BUFFER_SIZE (128*1024)
+#else /* no large readwrite possible */
+#define BUFFER_SIZE (0xFFFF)
+#endif
+
+#define SAFETY_MARGIN 1024
+#define LARGE_WRITEX_HDR_SIZE 65
+
+#define NMB_PORT 137
+#define DGRAM_PORT 138
+#define SMB_PORT1 445
+#define SMB_PORT2 139
+#define SMB_PORTS "445 139"
+
+#define Undefined (-1)
+#define False false
+#define True true
+#define Auto (2)
+#define Required (3)
+
+#define SIZEOFWORD 2
+
+#ifndef DEF_CREATE_MASK
+#define DEF_CREATE_MASK (0755)
+#endif
+
+/* string manipulation flags - see clistr.c and srvstr.c */
+#define STR_TERMINATE 1
+#define STR_UPPER 2
+#define STR_ASCII 4
+#define STR_UNICODE 8
+#define STR_NOALIGN 16
+#define STR_TERMINATE_ASCII 128
+
+/* how long to wait for secondary SMB packets (milli-seconds) */
+#define SMB_SECONDARY_WAIT (60*1000)
+
+/* Debugging stuff */
+#include "debug.h"
+
+/* this defines the error codes that receive_smb can put in smb_read_error */
+enum smb_read_errors {
+ SMB_READ_OK = 0,
+ SMB_READ_TIMEOUT,
+ SMB_READ_EOF,
+ SMB_READ_ERROR,
+ SMB_WRITE_ERROR, /* This error code can go into the client smb_rw_error. */
+ SMB_READ_BAD_SIG,
+ SMB_NO_MEMORY,
+ SMB_DO_NOT_DO_TDIS, /* cli_close_connection() check for this when smbfs wants to keep tree connected */
+ SMB_READ_BAD_DECRYPT
+};
+
+#define DIR_STRUCT_SIZE 43
+
+/* these define the attribute byte as seen by DOS */
+#define aRONLY (1L<<0) /* 0x01 */
+#define aHIDDEN (1L<<1) /* 0x02 */
+#define aSYSTEM (1L<<2) /* 0x04 */
+#define aVOLID (1L<<3) /* 0x08 */
+#define aDIR (1L<<4) /* 0x10 */
+#define aARCH (1L<<5) /* 0x20 */
+
+/* deny modes */
+#define DENY_DOS 0
+#define DENY_ALL 1
+#define DENY_WRITE 2
+#define DENY_READ 3
+#define DENY_NONE 4
+#define DENY_FCB 7
+
+/* open modes */
+#define DOS_OPEN_RDONLY 0
+#define DOS_OPEN_WRONLY 1
+#define DOS_OPEN_RDWR 2
+#define DOS_OPEN_EXEC 3
+#define DOS_OPEN_FCB 0xF
+
+/* define shifts and masks for share and open modes. */
+#define OPENX_MODE_MASK 0xF
+#define DENY_MODE_SHIFT 4
+#define DENY_MODE_MASK 0x7
+#define GET_OPENX_MODE(x) ((x) & OPENX_MODE_MASK)
+#define SET_OPENX_MODE(x) ((x) & OPENX_MODE_MASK)
+#define GET_DENY_MODE(x) (((x)>>DENY_MODE_SHIFT) & DENY_MODE_MASK)
+#define SET_DENY_MODE(x) (((x) & DENY_MODE_MASK) <<DENY_MODE_SHIFT)
+
+/* Sync on open file (not sure if used anymore... ?) */
+#define FILE_SYNC_OPENMODE (1<<14)
+#define GET_FILE_SYNC_OPENMODE(x) (((x) & FILE_SYNC_OPENMODE) ? True : False)
+
+/* open disposition values */
+#define OPENX_FILE_EXISTS_FAIL 0
+#define OPENX_FILE_EXISTS_OPEN 1
+#define OPENX_FILE_EXISTS_TRUNCATE 2
+
+/* mask for open disposition. */
+#define OPENX_FILE_OPEN_MASK 0x3
+
+#define GET_FILE_OPENX_DISPOSITION(x) ((x) & FILE_OPEN_MASK)
+#define SET_FILE_OPENX_DISPOSITION(x) ((x) & FILE_OPEN_MASK)
+
+/* The above can be OR'ed with... */
+#define OPENX_FILE_CREATE_IF_NOT_EXIST 0x10
+#define OPENX_FILE_FAIL_IF_NOT_EXIST 0
+
+#include "doserr.h"
+
+typedef union unid_t {
+ uid_t uid;
+ gid_t gid;
+} unid_t;
+
+/*
+ * SMB UCS2 (16-bit unicode) internal type.
+ * smb_ucs2_t is *always* in little endian format.
+ */
+
+typedef uint16 smb_ucs2_t;
+
+#ifdef WORDS_BIGENDIAN
+#define UCS2_SHIFT 8
+#else
+#define UCS2_SHIFT 0
+#endif
+
+/* turn a 7 bit character into a ucs2 character */
+#define UCS2_CHAR(c) ((c) << UCS2_SHIFT)
+
+/* return an ascii version of a ucs2 character */
+#define UCS2_TO_CHAR(c) (((c) >> UCS2_SHIFT) & 0xff)
+
+/* Copy into a smb_ucs2_t from a possibly unaligned buffer. Return the copied smb_ucs2_t */
+#define COPY_UCS2_CHAR(dest,src) (((unsigned char *)(dest))[0] = ((unsigned char *)(src))[0],\
+ ((unsigned char *)(dest))[1] = ((unsigned char *)(src))[1], (dest))
+
+/* Large data type for manipulating uint32 unicode codepoints */
+typedef uint32 codepoint_t;
+#define INVALID_CODEPOINT ((codepoint_t)-1)
+
+/* pipe string names */
+#define PIPE_LANMAN "\\PIPE\\LANMAN"
+
+/* 64 bit time (100usec) since ????? - cifs6.txt, section 3.5, page 30 */
+typedef uint64_t NTTIME;
+
+#define MAX_HOURS_LEN 32
+
+#ifndef MAXSUBAUTHS
+#define MAXSUBAUTHS 15 /* max sub authorities in a SID */
+#endif
+
+#define SID_MAX_SIZE ((size_t)(8+(MAXSUBAUTHS*4)))
+
+#define LOOKUP_NAME_NONE 0x00000000
+#define LOOKUP_NAME_ISOLATED 0x00000001 /* Look up unqualified names */
+#define LOOKUP_NAME_REMOTE 0x00000002 /* Ask others */
+#define LOOKUP_NAME_GROUP 0x00000004 /* (unused) This is a NASTY hack for
+ valid users = @foo where foo also
+ exists in as user. */
+#define LOOKUP_NAME_EXPLICIT 0x00000008 /* Only include
+ explicitly mapped names and not
+ the Unix {User,Group} domain */
+#define LOOKUP_NAME_BUILTIN 0x00000010 /* builtin names */
+#define LOOKUP_NAME_WKN 0x00000020 /* well known names */
+#define LOOKUP_NAME_DOMAIN 0x00000040 /* only lookup own domain */
+#define LOOKUP_NAME_LOCAL (LOOKUP_NAME_ISOLATED\
+ |LOOKUP_NAME_BUILTIN\
+ |LOOKUP_NAME_WKN\
+ |LOOKUP_NAME_DOMAIN)
+#define LOOKUP_NAME_ALL (LOOKUP_NAME_ISOLATED\
+ |LOOKUP_NAME_REMOTE\
+ |LOOKUP_NAME_BUILTIN\
+ |LOOKUP_NAME_WKN\
+ |LOOKUP_NAME_DOMAIN)
+
+/**
+ * @brief Security Identifier
+ *
+ * @sa http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/accctrl_38yn.asp
+ **/
+typedef struct dom_sid {
+ uint8 sid_rev_num; /**< SID revision number */
+ uint8 num_auths; /**< Number of sub-authorities */
+ uint8 id_auth[6]; /**< Identifier Authority */
+ /*
+ * Pointer to sub-authorities.
+ *
+ * @note The values in these uint32's are in *native* byteorder, not
+ * neccessarily little-endian...... JRA.
+ */
+ uint32 sub_auths[MAXSUBAUTHS];
+} DOM_SID;
+
+enum id_mapping {
+ ID_UNKNOWN = 0,
+ ID_MAPPED,
+ ID_UNMAPPED,
+ ID_EXPIRED
+};
+
+enum id_type {
+ ID_TYPE_NOT_SPECIFIED = 0,
+ ID_TYPE_UID,
+ ID_TYPE_GID
+};
+
+struct unixid {
+ uint32_t id;
+ enum id_type type;
+};
+
+struct id_map {
+ DOM_SID *sid;
+ struct unixid xid;
+ enum id_mapping status;
+};
+
+/* used to hold an arbitrary blob of data */
+typedef struct data_blob {
+ uint8 *data;
+ size_t length;
+ void (*free)(struct data_blob *data_blob);
+} DATA_BLOB;
+
+extern const DATA_BLOB data_blob_null;
+
+#include "librpc/gen_ndr/misc.h"
+#include "librpc/gen_ndr/security.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/lsa.h"
+#include "librpc/gen_ndr/dfs.h"
+#include "librpc/gen_ndr/winreg.h"
+#include "librpc/gen_ndr/initshutdown.h"
+#include "librpc/gen_ndr/eventlog.h"
+#include "librpc/gen_ndr/srvsvc.h"
+#include "librpc/gen_ndr/wkssvc.h"
+#include "librpc/gen_ndr/echo.h"
+#include "librpc/gen_ndr/svcctl.h"
+#include "librpc/gen_ndr/netlogon.h"
+#include "librpc/gen_ndr/samr.h"
+#include "librpc/gen_ndr/dssetup.h"
+#include "librpc/gen_ndr/epmapper.h"
+#include "librpc/gen_ndr/libnet_join.h"
+#include "librpc/gen_ndr/krb5pac.h"
+#include "librpc/gen_ndr/ntsvcs.h"
+#include "librpc/gen_ndr/nbt.h"
+#include "librpc/gen_ndr/drsuapi.h"
+#include "librpc/gen_ndr/drsblobs.h"
+
+struct lsa_dom_info {
+ bool valid;
+ DOM_SID sid;
+ const char *name;
+ int num_idxs;
+ int *idxs;
+};
+
+struct lsa_name_info {
+ uint32 rid;
+ enum lsa_SidType type;
+ const char *name;
+ int dom_idx;
+};
+
+/* Some well-known SIDs */
+extern const DOM_SID global_sid_World_Domain;
+extern const DOM_SID global_sid_World;
+extern const DOM_SID global_sid_Creator_Owner_Domain;
+extern const DOM_SID global_sid_NT_Authority;
+extern const DOM_SID global_sid_System;
+extern const DOM_SID global_sid_NULL;
+extern const DOM_SID global_sid_Authenticated_Users;
+extern const DOM_SID global_sid_Network;
+extern const DOM_SID global_sid_Creator_Owner;
+extern const DOM_SID global_sid_Creator_Group;
+extern const DOM_SID global_sid_Anonymous;
+extern const DOM_SID global_sid_Builtin;
+extern const DOM_SID global_sid_Builtin_Administrators;
+extern const DOM_SID global_sid_Builtin_Users;
+extern const DOM_SID global_sid_Builtin_Guests;
+extern const DOM_SID global_sid_Builtin_Power_Users;
+extern const DOM_SID global_sid_Builtin_Account_Operators;
+extern const DOM_SID global_sid_Builtin_Server_Operators;
+extern const DOM_SID global_sid_Builtin_Print_Operators;
+extern const DOM_SID global_sid_Builtin_Backup_Operators;
+extern const DOM_SID global_sid_Builtin_Replicator;
+extern const DOM_SID global_sid_Builtin_PreWin2kAccess;
+extern const DOM_SID global_sid_Unix_Users;
+extern const DOM_SID global_sid_Unix_Groups;
+
+/*
+ * The complete list of SIDS belonging to this user.
+ * Created when a vuid is registered.
+ * The definition of the user_sids array is as follows :
+ *
+ * token->user_sids[0] = primary user SID.
+ * token->user_sids[1] = primary group SID.
+ * token->user_sids[2..num_sids] = supplementary group SIDS.
+ */
+
+#define PRIMARY_USER_SID_INDEX 0
+#define PRIMARY_GROUP_SID_INDEX 1
+
+typedef struct nt_user_token {
+ size_t num_sids;
+ DOM_SID *user_sids;
+ SE_PRIV privileges;
+} NT_USER_TOKEN;
+
+typedef struct unix_user_token {
+ uid_t uid;
+ gid_t gid;
+ size_t ngroups;
+ gid_t *groups;
+} UNIX_USER_TOKEN;
+
+/* 32 bit time (sec) since 01jan1970 - cifs6.txt, section 3.5, page 30 */
+typedef struct time_info {
+ uint32 time;
+} UTIME;
+
+typedef struct write_cache {
+ SMB_OFF_T file_size;
+ SMB_OFF_T offset;
+ size_t alloc_size;
+ size_t data_size;
+ char *data;
+} write_cache;
+
+typedef struct {
+ smb_ucs2_t *origname;
+ smb_ucs2_t *filename;
+ SMB_STRUCT_STAT *statinfo;
+} smb_filename;
+
+#include "fake_file.h"
+
+struct fd_handle {
+ size_t ref_count;
+ int fd;
+ SMB_BIG_UINT position_information;
+ SMB_OFF_T pos;
+ uint32 private_options; /* NT Create options, but we only look at
+ * NTCREATEX_OPTIONS_PRIVATE_DENY_DOS and
+ * NTCREATEX_OPTIONS_PRIVATE_DENY_FCB (Except
+ * for print files *only*, where
+ * DELETE_ON_CLOSE is not stored in the share
+ * mode database.
+ */
+ unsigned long gen_id;
+};
+
+struct event_context;
+struct fd_event;
+struct timed_event;
+struct idle_event;
+struct share_mode_entry;
+struct uuid;
+struct named_mutex;
+
+struct vfs_fsp_data {
+ struct vfs_fsp_data *next;
+ struct vfs_handle_struct *owner;
+ /* NOTE: This structure contains two pointers so that we can guarantee
+ * that the end of the structure is always both 4-byte and 8-byte aligned.
+ */
+};
+
+/* the basic packet size, assuming no words or bytes */
+#define smb_size 39
+
+struct notify_change {
+ uint32_t action;
+ const char *name;
+};
+
+struct notify_mid_map;
+struct notify_entry;
+struct notify_event;
+struct notify_change_request;
+struct sys_notify_backend;
+struct sys_notify_context {
+ struct event_context *ev;
+ struct connection_struct *conn;
+ void *private_data; /* For use by the system backend */
+};
+
+struct notify_change_buf {
+ /*
+ * If no requests are pending, changes are queued here. Simple array,
+ * we only append.
+ */
+
+ /*
+ * num_changes == -1 means that we have got a catch-all change, when
+ * asked we just return NT_STATUS_OK without specific changes.
+ */
+ int num_changes;
+ struct notify_change *changes;
+
+ /*
+ * If no changes are around requests are queued here. Using a linked
+ * list, because we have to append at the end and delete from the top.
+ */
+ struct notify_change_request *requests;
+};
+
+typedef struct files_struct {
+ struct files_struct *next, *prev;
+ int fnum;
+ struct connection_struct *conn;
+ struct fd_handle *fh;
+ unsigned int num_smb_operations;
+ uint16 rap_print_jobid;
+ struct file_id file_id;
+ SMB_BIG_UINT initial_allocation_size; /* Faked up initial allocation on disk. */
+ mode_t mode;
+ uint16 file_pid;
+ uint16 vuid;
+ write_cache *wcp;
+ struct timeval open_time;
+ uint32 access_mask; /* NTCreateX access bits (FILE_READ_DATA etc.) */
+ uint32 share_access; /* NTCreateX share constants (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE). */
+
+ bool update_write_time_triggered;
+ struct timed_event *update_write_time_event;
+ bool update_write_time_on_close;
+ struct timespec close_write_time;
+ bool write_time_forced;
+
+ int oplock_type;
+ int sent_oplock_break;
+ struct timed_event *oplock_timeout;
+ struct lock_struct last_lock_failure;
+ int current_lock_count; /* Count the number of outstanding locks and pending locks. */
+
+ struct share_mode_entry *pending_break_messages;
+ int num_pending_break_messages;
+
+ bool can_lock;
+ bool can_read;
+ bool can_write;
+ bool print_file;
+ bool modified;
+ bool is_directory;
+ bool aio_write_behind;
+ bool lockdb_clean;
+ bool initial_delete_on_close; /* Only set at NTCreateX if file was created. */
+ bool posix_open;
+ char *fsp_name;
+
+ struct vfs_fsp_data *vfs_extension;
+ struct fake_file_handle *fake_file_handle;
+
+ struct notify_change_buf *notify;
+
+ struct files_struct *base_fsp; /* placeholder for delete on close */
+} files_struct;
+
+#include "ntquotas.h"
+#include "sysquotas.h"
+
+struct vuid_cache_entry {
+ struct auth_serversupplied_info *server_info;
+ uint16_t vuid;
+ bool read_only;
+ bool admin_user;
+};
+
+struct vuid_cache {
+ unsigned int next_entry;
+ struct vuid_cache_entry array[VUID_CACHE_SIZE];
+};
+
+typedef struct {
+ char *name;
+ bool is_wild;
+} name_compare_entry;
+
+struct trans_state {
+ struct trans_state *next, *prev;
+ uint16 vuid;
+ uint16 mid;
+
+ uint32 max_param_return;
+ uint32 max_data_return;
+ uint32 max_setup_return;
+
+ uint8 cmd; /* SMBtrans or SMBtrans2 */
+
+ char *name; /* for trans requests */
+ uint16 call; /* for trans2 and nttrans requests */
+
+ bool close_on_completion;
+ bool one_way;
+
+ unsigned int setup_count;
+ uint16 *setup;
+
+ size_t received_data;
+ size_t received_param;
+
+ size_t total_param;
+ char *param;
+
+ size_t total_data;
+ char *data;
+};
+
+/*
+ * Info about an alternate data stream
+ */
+
+struct stream_struct {
+ SMB_OFF_T size;
+ SMB_OFF_T alloc_size;
+ char *name;
+};
+
+/* Include VFS stuff */
+
+#include "smb_acls.h"
+#include "vfs.h"
+
+struct dfree_cached_info {
+ time_t last_dfree_time;
+ SMB_BIG_UINT dfree_ret;
+ SMB_BIG_UINT bsize;
+ SMB_BIG_UINT dfree;
+ SMB_BIG_UINT dsize;
+};
+
+struct dptr_struct;
+
+struct share_params {
+ int service;
+};
+
+struct share_iterator {
+ int next_id;
+};
+
+typedef struct connection_struct {
+ struct connection_struct *next, *prev;
+ unsigned cnum; /* an index passed over the wire */
+ struct share_params *params;
+ bool force_user;
+ struct vuid_cache vuid_cache;
+ struct dptr_struct *dirptr;
+ bool printer;
+ bool ipc;
+ bool read_only; /* Attributes for the current user of the share. */
+ bool admin_user; /* Attributes for the current user of the share. */
+ char *dirpath;
+ char *connectpath;
+ char *origpath;
+
+ struct vfs_ops vfs; /* Filesystem operations */
+ struct vfs_ops vfs_opaque; /* OPAQUE Filesystem operations */
+ struct vfs_handle_struct *vfs_handles; /* for the new plugins */
+
+ /*
+ * This represents the user information on this connection. Depending
+ * on the vuid using this tid, this might change per SMB request.
+ */
+ struct auth_serversupplied_info *server_info;
+
+ char client_address[INET6_ADDRSTRLEN]; /* String version of client IP address. */
+
+ uint16 vuid; /* vuid of user who *opened* this connection, or UID_FIELD_INVALID */
+
+ time_t lastused;
+ time_t lastused_count;
+ bool used;
+ int num_files_open;
+ unsigned int num_smb_operations; /* Count of smb operations on this tree. */
+ int encrypt_level;
+ bool encrypted_tid;
+
+ /* Semantics requested by the client or forced by the server config. */
+ bool case_sensitive;
+ bool case_preserve;
+ bool short_case_preserve;
+
+ /* Semantics provided by the underlying filesystem. */
+ int fs_capabilities;
+
+ 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. */
+ name_compare_entry *aio_write_behind_list; /* Per-share list of files to use aio write behind on. */
+ struct dfree_cached_info *dfree_info;
+ struct trans_state *pending_trans;
+ struct notify_context *notify_ctx;
+} connection_struct;
+
+struct current_user {
+ connection_struct *conn;
+ uint16 vuid;
+ UNIX_USER_TOKEN ut;
+ NT_USER_TOKEN *nt_user_token;
+};
+
+struct smb_request {
+ uint16 flags2;
+ uint16 smbpid;
+ uint16 mid;
+ uint16 vuid;
+ uint16 tid;
+ uint8 wct;
+ const uint8 *inbuf;
+ uint8 *outbuf;
+ size_t unread_bytes;
+ bool encrypted;
+ connection_struct *conn;
+};
+
+/* Defines for the sent_oplock_break field above. */
+#define NO_BREAK_SENT 0
+#define BREAK_TO_NONE_SENT 1
+#define LEVEL_II_BREAK_SENT 2
+
+typedef struct {
+ fstring smb_name; /* user name from the client */
+ fstring unix_name; /* unix user name of a validated user */
+ fstring full_name; /* to store full name (such as "Joe Bloggs") from gecos field of password file */
+ fstring domain; /* domain that the client specified */
+} userdom_struct;
+
+/* Extra fields above "LPQ_PRINTING" are used to map extra NT status codes. */
+
+enum {LPQ_QUEUED=0,LPQ_PAUSED,LPQ_SPOOLING,LPQ_PRINTING,LPQ_ERROR,LPQ_DELETING,
+ LPQ_OFFLINE,LPQ_PAPEROUT,LPQ_PRINTED,LPQ_DELETED,LPQ_BLOCKED,LPQ_USER_INTERVENTION};
+
+typedef struct _print_queue_struct {
+ int job; /* normally the UNIX jobid -- see note in
+ printing.c:traverse_fn_delete() */
+ int size;
+ int page_count;
+ int status;
+ int priority;
+ time_t time;
+ fstring fs_user;
+ fstring fs_file;
+} print_queue_struct;
+
+enum {LPSTAT_OK, LPSTAT_STOPPED, LPSTAT_ERROR};
+
+typedef struct {
+ fstring message;
+ int qcount;
+ int status;
+} print_status_struct;
+
+/* used for server information: client, nameserv and ipc */
+struct server_info_struct {
+ fstring name;
+ uint32 type;
+ fstring comment;
+ fstring domain; /* used ONLY in ipc.c NOT namework.c */
+ bool server_added; /* used ONLY in ipc.c NOT namework.c */
+};
+
+/* used for network interfaces */
+struct interface {
+ struct interface *next, *prev;
+ char *name;
+ int flags;
+ struct sockaddr_storage ip;
+ struct sockaddr_storage netmask;
+ struct sockaddr_storage bcast;
+};
+
+/* Internal message queue for deferred opens. */
+struct pending_message_list {
+ struct pending_message_list *next, *prev;
+ struct timeval request_time; /* When was this first issued? */
+ struct timeval end_time; /* When does this time out? */
+ bool encrypted;
+ DATA_BLOB buf;
+ DATA_BLOB private_data;
+};
+
+#define SHARE_MODE_FLAG_POSIX_OPEN 0x1
+#define SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE 0x2
+
+/* struct returned by get_share_modes */
+struct share_mode_entry {
+ struct server_id pid;
+ uint16 op_mid;
+ uint16 op_type;
+ uint32 access_mask; /* NTCreateX access bits (FILE_READ_DATA etc.) */
+ uint32 share_access; /* NTCreateX share constants (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE). */
+ uint32 private_options; /* NT Create options, but we only look at
+ * NTCREATEX_OPTIONS_PRIVATE_DENY_DOS and
+ * NTCREATEX_OPTIONS_PRIVATE_DENY_FCB for
+ * smbstatus and swat */
+ struct timeval time;
+ struct file_id id;
+ unsigned long share_file_id;
+ uint32 uid; /* uid of file opener. */
+ uint16 flags; /* See SHARE_MODE_XX above. */
+};
+
+/* oplock break message definition - linearization of share_mode_entry.
+
+Offset Data length.
+0 struct server_id pid 4
+4 uint16 op_mid 2
+6 uint16 op_type 2
+8 uint32 access_mask 4
+12 uint32 share_access 4
+16 uint32 private_options 4
+20 uint32 time sec 4
+24 uint32 time usec 4
+28 SMB_DEV_T dev 8 bytes.
+36 SMB_INO_T inode 8 bytes
+44 unsigned long file_id 4 bytes
+48 uint32 uid 4 bytes
+52 uint16 flags 2 bytes
+54
+
+*/
+#ifdef CLUSTER_SUPPORT
+#define MSG_SMB_SHARE_MODE_ENTRY_SIZE 58
+#else
+#define MSG_SMB_SHARE_MODE_ENTRY_SIZE 54
+#endif
+
+struct share_mode_lock {
+ const char *servicepath; /* canonicalized. */
+ const char *filename;
+ struct file_id id;
+ int num_share_modes;
+ struct share_mode_entry *share_modes;
+ UNIX_USER_TOKEN *delete_token;
+ bool delete_on_close;
+ struct timespec old_write_time;
+ struct timespec changed_write_time;
+ bool fresh;
+ bool modified;
+ struct db_record *record;
+};
+
+/*
+ * Internal structure of locking.tdb share mode db.
+ * Used by locking.c and libsmbsharemodes.c
+ */
+
+struct locking_data {
+ union {
+ struct {
+ int num_share_mode_entries;
+ bool delete_on_close;
+ struct timespec old_write_time;
+ struct timespec changed_write_time;
+ uint32 delete_token_size; /* Only valid if either of
+ the two previous fields
+ are True. */
+ } s;
+ struct share_mode_entry dummy; /* Needed for alignment. */
+ } u;
+ /* The following four entries are implicit
+ struct share_mode_entry modes[num_share_mode_entries];
+ char unix_token[delete_token_size] (divisible by 4).
+ char share_name[];
+ char file_name[];
+ */
+};
+
+/* Used to store pipe open records for NetFileEnum() */
+
+struct pipe_open_rec {
+ struct server_id pid;
+ uid_t uid;
+ int pnum;
+ fstring name;
+};
+
+
+#define NT_HASH_LEN 16
+#define LM_HASH_LEN 16
+
+/* Password history contants. */
+#define PW_HISTORY_SALT_LEN 16
+#define SALTED_MD5_HASH_LEN 16
+#define PW_HISTORY_ENTRY_LEN (PW_HISTORY_SALT_LEN+SALTED_MD5_HASH_LEN)
+#define MAX_PW_HISTORY_LEN 24
+
+/*
+ * Flags for account policy.
+ */
+#define AP_MIN_PASSWORD_LEN 1
+#define AP_PASSWORD_HISTORY 2
+#define AP_USER_MUST_LOGON_TO_CHG_PASS 3
+#define AP_MAX_PASSWORD_AGE 4
+#define AP_MIN_PASSWORD_AGE 5
+#define AP_LOCK_ACCOUNT_DURATION 6
+#define AP_RESET_COUNT_TIME 7
+#define AP_BAD_ATTEMPT_LOCKOUT 8
+#define AP_TIME_TO_LOGOUT 9
+#define AP_REFUSE_MACHINE_PW_CHANGE 10
+
+/*
+ * Flags for local user manipulation.
+ */
+
+#define LOCAL_ADD_USER 0x1
+#define LOCAL_DELETE_USER 0x2
+#define LOCAL_DISABLE_USER 0x4
+#define LOCAL_ENABLE_USER 0x8
+#define LOCAL_TRUST_ACCOUNT 0x10
+#define LOCAL_SET_NO_PASSWORD 0x20
+#define LOCAL_SET_PASSWORD 0x40
+#define LOCAL_SET_LDAP_ADMIN_PW 0x80
+#define LOCAL_INTERDOM_ACCOUNT 0x100
+#define LOCAL_AM_ROOT 0x200 /* Act as root */
+
+/* key and data in the connections database - used in smbstatus and smbd */
+struct connections_key {
+ struct server_id pid;
+ int cnum;
+ fstring name;
+};
+
+struct connections_data {
+ int magic;
+ struct server_id pid;
+ int cnum;
+ uid_t uid;
+ gid_t gid;
+ char servicename[FSTRING_LEN];
+ char addr[24];
+ char machine[FSTRING_LEN];
+ time_t start;
+ uint32 bcast_msg_flags;
+};
+
+
+/* the following are used by loadparm for option lists */
+typedef enum {
+ P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,P_LIST,
+ P_STRING,P_USTRING,P_ENUM,P_SEP
+} parm_type;
+
+typedef enum {
+ P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
+} parm_class;
+
+struct enum_list {
+ int value;
+ const char *name;
+};
+
+struct parm_struct {
+ const char *label;
+ parm_type type;
+ parm_class p_class;
+ void *ptr;
+ bool (*special)(int snum, const char *, char **);
+ const struct enum_list *enum_list;
+ unsigned flags;
+ union {
+ bool bvalue;
+ int ivalue;
+ char *svalue;
+ char cvalue;
+ char **lvalue;
+ } def;
+};
+
+/* The following flags are used in SWAT */
+#define FLAG_BASIC 0x0001 /* Display only in BASIC view */
+#define FLAG_SHARE 0x0002 /* file sharing options */
+#define FLAG_PRINT 0x0004 /* printing options */
+#define FLAG_GLOBAL 0x0008 /* local options that should be globally settable in SWAT */
+#define FLAG_WIZARD 0x0010 /* Parameters that the wizard will operate on */
+#define FLAG_ADVANCED 0x0020 /* Parameters that will be visible in advanced view */
+#define FLAG_DEVELOPER 0x0040 /* No longer used */
+#define FLAG_DEPRECATED 0x1000 /* options that should no longer be used */
+#define FLAG_HIDE 0x2000 /* options that should be hidden in SWAT */
+#define FLAG_DOS_STRING 0x4000 /* convert from UNIX to DOS codepage when reading this string. */
+
+struct bitmap {
+ uint32 *b;
+ unsigned int n;
+};
+
+/* offsets into message for common items */
+#define smb_com 8
+#define smb_rcls 9
+#define smb_reh 10
+#define smb_err 11
+#define smb_flg 13
+#define smb_flg2 14
+#define smb_pidhigh 16
+#define smb_ss_field 18
+#define smb_tid 28
+#define smb_pid 30
+#define smb_uid 32
+#define smb_mid 34
+#define smb_wct 36
+#define smb_vwv 37
+#define smb_vwv0 37
+#define smb_vwv1 39
+#define smb_vwv2 41
+#define smb_vwv3 43
+#define smb_vwv4 45
+#define smb_vwv5 47
+#define smb_vwv6 49
+#define smb_vwv7 51
+#define smb_vwv8 53
+#define smb_vwv9 55
+#define smb_vwv10 57
+#define smb_vwv11 59
+#define smb_vwv12 61
+#define smb_vwv13 63
+#define smb_vwv14 65
+#define smb_vwv15 67
+#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 */
+#define SMBrmdir 0x01 /* delete directory */
+#define SMBopen 0x02 /* open file */
+#define SMBcreate 0x03 /* create file */
+#define SMBclose 0x04 /* close file */
+#define SMBflush 0x05 /* flush file */
+#define SMBunlink 0x06 /* delete file */
+#define SMBmv 0x07 /* rename file */
+#define SMBgetatr 0x08 /* get file attributes */
+#define SMBsetatr 0x09 /* set file attributes */
+#define SMBread 0x0A /* read from file */
+#define SMBwrite 0x0B /* write to file */
+#define SMBlock 0x0C /* lock byte range */
+#define SMBunlock 0x0D /* unlock byte range */
+#define SMBctemp 0x0E /* create temporary file */
+#define SMBmknew 0x0F /* make new file */
+#define SMBcheckpath 0x10 /* check directory path */
+#define SMBexit 0x11 /* process exit */
+#define SMBlseek 0x12 /* seek */
+#define SMBtcon 0x70 /* tree connect */
+#define SMBtconX 0x75 /* tree connect and X*/
+#define SMBtdis 0x71 /* tree disconnect */
+#define SMBnegprot 0x72 /* negotiate protocol */
+#define SMBdskattr 0x80 /* get disk attributes */
+#define SMBsearch 0x81 /* search directory */
+#define SMBsplopen 0xC0 /* open print spool file */
+#define SMBsplwr 0xC1 /* write to print spool file */
+#define SMBsplclose 0xC2 /* close print spool file */
+#define SMBsplretq 0xC3 /* return print queue */
+#define SMBsends 0xD0 /* send single block message */
+#define SMBsendb 0xD1 /* send broadcast message */
+#define SMBfwdname 0xD2 /* forward user name */
+#define SMBcancelf 0xD3 /* cancel forward */
+#define SMBgetmac 0xD4 /* get machine name */
+#define SMBsendstrt 0xD5 /* send start of multi-block message */
+#define SMBsendend 0xD6 /* send end of multi-block message */
+#define SMBsendtxt 0xD7 /* send text of multi-block message */
+
+/* Core+ protocol */
+#define SMBlockread 0x13 /* Lock a range and read */
+#define SMBwriteunlock 0x14 /* Unlock a range then write */
+#define SMBreadbraw 0x1a /* read a block of data with no smb header */
+#define SMBwritebraw 0x1d /* write a block of data with no smb header */
+#define SMBwritec 0x20 /* secondary write request */
+#define SMBwriteclose 0x2c /* write a file then close it */
+
+/* dos extended protocol */
+#define SMBreadBraw 0x1A /* read block raw */
+#define SMBreadBmpx 0x1B /* read block multiplexed */
+#define SMBreadBs 0x1C /* read block (secondary response) */
+#define SMBwriteBraw 0x1D /* write block raw */
+#define SMBwriteBmpx 0x1E /* write block multiplexed */
+#define SMBwriteBs 0x1F /* write block (secondary request) */
+#define SMBwriteC 0x20 /* write complete response */
+#define SMBsetattrE 0x22 /* set file attributes expanded */
+#define SMBgetattrE 0x23 /* get file attributes expanded */
+#define SMBlockingX 0x24 /* lock/unlock byte ranges and X */
+#define SMBtrans 0x25 /* transaction - name, bytes in/out */
+#define SMBtranss 0x26 /* transaction (secondary request/response) */
+#define SMBioctl 0x27 /* IOCTL */
+#define SMBioctls 0x28 /* IOCTL (secondary request/response) */
+#define SMBcopy 0x29 /* copy */
+#define SMBmove 0x2A /* move */
+#define SMBecho 0x2B /* echo */
+#define SMBopenX 0x2D /* open and X */
+#define SMBreadX 0x2E /* read and X */
+#define SMBwriteX 0x2F /* write and X */
+#define SMBsesssetupX 0x73 /* Session Set Up & X (including User Logon) */
+#define SMBffirst 0x82 /* find first */
+#define SMBfunique 0x83 /* find unique */
+#define SMBfclose 0x84 /* find close */
+#define SMBkeepalive 0x85 /* keepalive */
+#define SMBinvalid 0xFE /* invalid command */
+
+/* Extended 2.0 protocol */
+#define SMBtrans2 0x32 /* TRANS2 protocol set */
+#define SMBtranss2 0x33 /* TRANS2 protocol set, secondary command */
+#define SMBfindclose 0x34 /* Terminate a TRANSACT2_FINDFIRST */
+#define SMBfindnclose 0x35 /* Terminate a TRANSACT2_FINDNOTIFYFIRST */
+#define SMBulogoffX 0x74 /* user logoff */
+
+/* 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 */
+#define SMBntrename 0xA5 /* NT rename */
+
+/* These are the trans subcommands */
+#define TRANSACT_SETNAMEDPIPEHANDLESTATE 0x01
+#define TRANSACT_DCERPCCMD 0x26
+#define TRANSACT_WAITNAMEDPIPEHANDLESTATE 0x53
+
+/* These are the TRANS2 sub commands */
+#define TRANSACT2_OPEN 0x00
+#define TRANSACT2_FINDFIRST 0x01
+#define TRANSACT2_FINDNEXT 0x02
+#define TRANSACT2_QFSINFO 0x03
+#define TRANSACT2_SETFSINFO 0x04
+#define TRANSACT2_QPATHINFO 0x05
+#define TRANSACT2_SETPATHINFO 0x06
+#define TRANSACT2_QFILEINFO 0x07
+#define TRANSACT2_SETFILEINFO 0x08
+#define TRANSACT2_FSCTL 0x09
+#define TRANSACT2_IOCTL 0x0A
+#define TRANSACT2_FINDNOTIFYFIRST 0x0B
+#define TRANSACT2_FINDNOTIFYNEXT 0x0C
+#define TRANSACT2_MKDIR 0x0D
+#define TRANSACT2_SESSION_SETUP 0x0E
+#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
+#define NT_TRANSACT_GET_USER_QUOTA 7
+#define NT_TRANSACT_SET_USER_QUOTA 8
+
+/* These are the NT transact_get_user_quota sub commands */
+#define TRANSACT_GET_USER_QUOTA_LIST_CONTINUE 0x0000
+#define TRANSACT_GET_USER_QUOTA_LIST_START 0x0100
+#define TRANSACT_GET_USER_QUOTA_FOR_SID 0x0101
+
+/* Relevant IOCTL codes */
+#define IOCTL_QUERY_JOB_INFO 0x530060
+
+/* these are the trans2 sub fields for primary requests */
+#define smb_tpscnt smb_vwv0
+#define smb_tdscnt smb_vwv1
+#define smb_mprcnt smb_vwv2
+#define smb_mdrcnt smb_vwv3
+#define smb_msrcnt smb_vwv4
+#define smb_flags smb_vwv5
+#define smb_timeout smb_vwv6
+#define smb_pscnt smb_vwv9
+#define smb_psoff smb_vwv10
+#define smb_dscnt smb_vwv11
+#define smb_dsoff smb_vwv12
+#define smb_suwcnt smb_vwv13
+#define smb_setup smb_vwv14
+#define smb_setup0 smb_setup
+#define smb_setup1 (smb_setup+2)
+#define smb_setup2 (smb_setup+4)
+
+/* these are for the secondary requests */
+#define smb_spscnt smb_vwv2
+#define smb_spsoff smb_vwv3
+#define smb_spsdisp smb_vwv4
+#define smb_sdscnt smb_vwv5
+#define smb_sdsoff smb_vwv6
+#define smb_sdsdisp smb_vwv7
+#define smb_sfid smb_vwv8
+
+/* and these for responses */
+#define smb_tprcnt smb_vwv0
+#define smb_tdrcnt smb_vwv1
+#define smb_prcnt smb_vwv3
+#define smb_proff smb_vwv4
+#define smb_prdisp smb_vwv5
+#define smb_drcnt smb_vwv6
+#define smb_droff smb_vwv7
+#define smb_drdisp smb_vwv8
+
+/* these are for the NT trans primary request. */
+#define smb_nt_MaxSetupCount smb_vwv0
+#define smb_nt_Flags (smb_vwv0 + 1)
+#define smb_nt_TotalParameterCount (smb_vwv0 + 3)
+#define smb_nt_TotalDataCount (smb_vwv0 + 7)
+#define smb_nt_MaxParameterCount (smb_vwv0 + 11)
+#define smb_nt_MaxDataCount (smb_vwv0 + 15)
+#define smb_nt_ParameterCount (smb_vwv0 + 19)
+#define smb_nt_ParameterOffset (smb_vwv0 + 23)
+#define smb_nt_DataCount (smb_vwv0 + 27)
+#define smb_nt_DataOffset (smb_vwv0 + 31)
+#define smb_nt_SetupCount (smb_vwv0 + 35)
+#define smb_nt_Function (smb_vwv0 + 36)
+#define smb_nt_SetupStart (smb_vwv0 + 38)
+
+/* these are for the NT trans secondary request. */
+#define smb_nts_TotalParameterCount (smb_vwv0 + 3)
+#define smb_nts_TotalDataCount (smb_vwv0 + 7)
+#define smb_nts_ParameterCount (smb_vwv0 + 11)
+#define smb_nts_ParameterOffset (smb_vwv0 + 15)
+#define smb_nts_ParameterDisplacement (smb_vwv0 + 19)
+#define smb_nts_DataCount (smb_vwv0 + 23)
+#define smb_nts_DataOffset (smb_vwv0 + 27)
+#define smb_nts_DataDisplacement (smb_vwv0 + 31)
+
+/* these are for the NT trans reply. */
+#define smb_ntr_TotalParameterCount (smb_vwv0 + 3)
+#define smb_ntr_TotalDataCount (smb_vwv0 + 7)
+#define smb_ntr_ParameterCount (smb_vwv0 + 11)
+#define smb_ntr_ParameterOffset (smb_vwv0 + 15)
+#define smb_ntr_ParameterDisplacement (smb_vwv0 + 19)
+#define smb_ntr_DataCount (smb_vwv0 + 23)
+#define smb_ntr_DataOffset (smb_vwv0 + 27)
+#define smb_ntr_DataDisplacement (smb_vwv0 + 31)
+
+/* these are for the NT create_and_X */
+#define smb_ntcreate_NameLength (smb_vwv0 + 5)
+#define smb_ntcreate_Flags (smb_vwv0 + 7)
+#define smb_ntcreate_RootDirectoryFid (smb_vwv0 + 11)
+#define smb_ntcreate_DesiredAccess (smb_vwv0 + 15)
+#define smb_ntcreate_AllocationSize (smb_vwv0 + 19)
+#define smb_ntcreate_FileAttributes (smb_vwv0 + 27)
+#define smb_ntcreate_ShareAccess (smb_vwv0 + 31)
+#define smb_ntcreate_CreateDisposition (smb_vwv0 + 35)
+#define smb_ntcreate_CreateOptions (smb_vwv0 + 39)
+#define smb_ntcreate_ImpersonationLevel (smb_vwv0 + 43)
+#define smb_ntcreate_SecurityFlags (smb_vwv0 + 47)
+
+/* this is used on a TConX. I'm not sure the name is very helpful though */
+#define SMB_SUPPORT_SEARCH_BITS 0x0001
+#define SMB_SHARE_IN_DFS 0x0002
+
+/* Named pipe write mode flags. Used in writeX calls. */
+#define PIPE_RAW_MODE 0x4
+#define PIPE_START_MESSAGE 0x8
+
+/* File Specific access rights */
+#define FILE_READ_DATA 0x00000001
+#define FILE_WRITE_DATA 0x00000002
+#define FILE_APPEND_DATA 0x00000004
+#define FILE_READ_EA 0x00000008 /* File and directory */
+#define FILE_WRITE_EA 0x00000010 /* File and directory */
+#define FILE_EXECUTE 0x00000020
+#define FILE_DELETE_CHILD 0x00000040
+#define FILE_READ_ATTRIBUTES 0x00000080
+#define FILE_WRITE_ATTRIBUTES 0x00000100
+
+#define FILE_ALL_ACCESS 0x000001FF
+
+/* Directory specific access rights */
+#define FILE_LIST_DIRECTORY 0x00000001
+#define FILE_ADD_FILE 0x00000002
+#define FILE_ADD_SUBDIRECTORY 0x00000004
+#define FILE_TRAVERSE 0x00000020
+#define FILE_DELETE_CHILD 0x00000040
+
+/* the desired access to use when opening a pipe */
+#define DESIRED_ACCESS_PIPE 0x2019f
+
+/* Generic access masks & rights. */
+#define DELETE_ACCESS 0x00010000 /* (1L<<16) */
+#define READ_CONTROL_ACCESS 0x00020000 /* (1L<<17) */
+#define WRITE_DAC_ACCESS 0x00040000 /* (1L<<18) */
+#define WRITE_OWNER_ACCESS 0x00080000 /* (1L<<19) */
+#define SYNCHRONIZE_ACCESS 0x00100000 /* (1L<<20) */
+
+#define SYSTEM_SECURITY_ACCESS 0x01000000 /* (1L<<24) */
+#define MAXIMUM_ALLOWED_ACCESS 0x02000000 /* (1L<<25) */
+#define GENERIC_ALL_ACCESS 0x10000000 /* (1<<28) */
+#define GENERIC_EXECUTE_ACCESS 0x20000000 /* (1<<29) */
+#define GENERIC_WRITE_ACCESS 0x40000000 /* (1<<30) */
+#define GENERIC_READ_ACCESS ((unsigned)0x80000000) /* (((unsigned)1)<<31) */
+
+/* Mapping of generic access rights for files to specific rights. */
+
+/* This maps to 0x1F01FF */
+#define FILE_GENERIC_ALL (STANDARD_RIGHTS_REQUIRED_ACCESS| SYNCHRONIZE_ACCESS|FILE_ALL_ACCESS)
+
+/* This maps to 0x120089 */
+#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ_ACCESS|FILE_READ_DATA|FILE_READ_ATTRIBUTES|\
+ FILE_READ_EA|SYNCHRONIZE_ACCESS)
+
+/* This maps to 0x120116 */
+#define FILE_GENERIC_WRITE (STD_RIGHT_READ_CONTROL_ACCESS|FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|\
+ FILE_WRITE_EA|FILE_APPEND_DATA|SYNCHRONIZE_ACCESS)
+
+#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE_ACCESS|\
+ FILE_EXECUTE|SYNCHRONIZE_ACCESS)
+
+/* Share specific rights. */
+#define SHARE_ALL_ACCESS FILE_GENERIC_ALL
+#define SHARE_READ_ONLY (FILE_GENERIC_READ|FILE_EXECUTE)
+
+/* Mapping of access rights to UNIX perms. */
+#define UNIX_ACCESS_RWX FILE_GENERIC_ALL
+#define UNIX_ACCESS_R FILE_GENERIC_READ
+#define UNIX_ACCESS_W FILE_GENERIC_WRITE
+#define UNIX_ACCESS_X FILE_GENERIC_EXECUTE
+
+/* Mapping of access rights to UNIX perms. for a UNIX directory. */
+#define UNIX_DIRECTORY_ACCESS_RWX FILE_GENERIC_ALL
+#define UNIX_DIRECTORY_ACCESS_R FILE_GENERIC_READ
+#define UNIX_DIRECTORY_ACCESS_W FILE_GENERIC_WRITE
+#define UNIX_DIRECTORY_ACCESS_X FILE_GENERIC_EXECUTE
+
+#if 0
+/*
+ * This is the old mapping we used to use. To get W2KSP2 profiles
+ * working we need to map to the canonical file perms.
+ */
+#define UNIX_ACCESS_RWX (UNIX_ACCESS_R|UNIX_ACCESS_W|UNIX_ACCESS_X)
+#define UNIX_ACCESS_R (READ_CONTROL_ACCESS|SYNCHRONIZE_ACCESS|\
+ FILE_READ_ATTRIBUTES|FILE_READ_EA|FILE_READ_DATA)
+#define UNIX_ACCESS_W (READ_CONTROL_ACCESS|SYNCHRONIZE_ACCESS|\
+ FILE_WRITE_ATTRIBUTES|FILE_WRITE_EA|\
+ FILE_APPEND_DATA|FILE_WRITE_DATA)
+#define UNIX_ACCESS_X (READ_CONTROL_ACCESS|SYNCHRONIZE_ACCESS|\
+ FILE_EXECUTE|FILE_READ_ATTRIBUTES)
+#endif
+
+#define UNIX_ACCESS_NONE (WRITE_OWNER_ACCESS)
+
+/* Flags field. */
+#define REQUEST_OPLOCK 2
+#define REQUEST_BATCH_OPLOCK 4
+#define OPEN_DIRECTORY 8
+#define EXTENDED_RESPONSE_REQUIRED 0x10
+
+/* 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 0x001L
+#define FILE_ATTRIBUTE_HIDDEN 0x002L
+#define FILE_ATTRIBUTE_SYSTEM 0x004L
+#define FILE_ATTRIBUTE_DIRECTORY 0x010L
+#define FILE_ATTRIBUTE_ARCHIVE 0x020L
+#define FILE_ATTRIBUTE_NORMAL 0x080L
+#define FILE_ATTRIBUTE_TEMPORARY 0x100L
+#define FILE_ATTRIBUTE_SPARSE 0x200L
+#define FILE_ATTRIBUTE_REPARSE_POINT 0x400L
+#define FILE_ATTRIBUTE_COMPRESSED 0x800L
+#define FILE_ATTRIBUTE_OFFLINE 0x1000L
+#define FILE_ATTRIBUTE_NONINDEXED 0x2000L
+#define FILE_ATTRIBUTE_ENCRYPTED 0x4000L
+#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 /* File exists overwrite/supersede. File not exist create. */
+#define FILE_OPEN 1 /* File exists open. File not exist fail. */
+#define FILE_CREATE 2 /* File exists fail. File not exist create. */
+#define FILE_OPEN_IF 3 /* File exists open. File not exist create. */
+#define FILE_OVERWRITE 4 /* File exists overwrite. File not exist fail. */
+#define FILE_OVERWRITE_IF 5 /* File exists overwrite. File not exist create. */
+
+/* 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
+#define FILE_OPEN_BY_FILE_ID 0x2000
+
+#define NTCREATEX_OPTIONS_MUST_IGNORE_MASK (0x008F0480)
+
+#define NTCREATEX_OPTIONS_INVALID_PARAM_MASK (0xFF100030)
+
+/*
+ * Private create options used by the ntcreatex processing code. From Samba4.
+ * We reuse some ignored flags for private use.
+ */
+#define NTCREATEX_OPTIONS_PRIVATE_DENY_DOS 0x00010000
+#define NTCREATEX_OPTIONS_PRIVATE_DENY_FCB 0x00020000
+
+/* Private options for streams support */
+#define NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE 0x00040000
+
+/* Responses when opening a file. */
+#define FILE_WAS_SUPERSEDED 0
+#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
+
+/* flags for SMBntrename call (from Samba4) */
+#define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102 /* ???? */
+#define RENAME_FLAG_HARD_LINK 0x103
+#define RENAME_FLAG_RENAME 0x104
+#define RENAME_FLAG_COPY 0x105
+
+/* Filesystem Attributes. */
+#define FILE_CASE_SENSITIVE_SEARCH 0x00000001
+#define FILE_CASE_PRESERVED_NAMES 0x00000002
+#define FILE_UNICODE_ON_DISK 0x00000004
+/* According to cifs9f, this is 4, not 8 */
+/* Acconding to testing, this actually sets the security attribute! */
+#define FILE_PERSISTENT_ACLS 0x00000008
+#define FILE_FILE_COMPRESSION 0x00000010
+#define FILE_VOLUME_QUOTAS 0x00000020
+#define FILE_SUPPORTS_SPARSE_FILES 0x00000040
+#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080
+#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100
+#define FS_LFN_APIS 0x00004000
+#define FILE_VOLUME_IS_COMPRESSED 0x00008000
+#define FILE_SUPPORTS_OBJECT_IDS 0x00010000
+#define FILE_SUPPORTS_ENCRYPTION 0x00020000
+#define FILE_NAMED_STREAMS 0x00040000
+#define FILE_READ_ONLY_VOLUME 0x00080000
+
+/* 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
+#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200
+#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400
+#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800
+
+#define FILE_NOTIFY_CHANGE_NAME \
+ (FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME)
+
+/* change notify action results */
+#define NOTIFY_ACTION_ADDED 1
+#define NOTIFY_ACTION_REMOVED 2
+#define NOTIFY_ACTION_MODIFIED 3
+#define NOTIFY_ACTION_OLD_NAME 4
+#define NOTIFY_ACTION_NEW_NAME 5
+#define NOTIFY_ACTION_ADDED_STREAM 6
+#define NOTIFY_ACTION_REMOVED_STREAM 7
+#define NOTIFY_ACTION_MODIFIED_STREAM 8
+
+
+/* where to find the base of the SMB packet proper */
+#define smb_base(buf) (((char *)(buf))+4)
+
+/* we don't allow server strings to be longer than 48 characters as
+ otherwise NT will not honour the announce packets */
+#define MAX_SERVER_STRING_LENGTH 48
+
+
+#define SMB_SUCCESS 0 /* The request was successful. */
+
+#ifdef WITH_DFS
+void dfs_unlogin(void);
+extern int dcelogin_atmost_once;
+#endif
+
+#ifdef NOSTRDUP
+char *strdup(char *s);
+#endif
+
+#ifndef SIGNAL_CAST
+#define SIGNAL_CAST (RETSIGTYPE (*)(int))
+#endif
+
+#ifndef SELECT_CAST
+#define SELECT_CAST
+#endif
+
+/* This was set by JHT in liaison with Jeremy Allison early 1997
+ * History:
+ * Version 4.0 - never made public
+ * Version 4.10 - New to 1.9.16p2, lost in space 1.9.16p3 to 1.9.16p9
+ * - Reappeared in 1.9.16p11 with fixed smbd services
+ * Version 4.20 - To indicate that nmbd and browsing now works better
+ * Version 4.50 - Set at release of samba-2.2.0 by JHT
+ *
+ * Note: In the presence of NT4.X do not set above 4.9
+ * Setting this above 4.9 can have undesired side-effects.
+ * This may change again in Samba-3.0 after further testing. JHT
+ */
+
+#define DEFAULT_MAJOR_VERSION 0x04
+#define DEFAULT_MINOR_VERSION 0x09
+
+/* Browser Election Values */
+#define BROWSER_ELECTION_VERSION 0x010f
+#define BROWSER_CONSTANT 0xaa55
+
+/* Sercurity mode bits. */
+#define NEGOTIATE_SECURITY_USER_LEVEL 0x01
+#define NEGOTIATE_SECURITY_CHALLENGE_RESPONSE 0x02
+#define NEGOTIATE_SECURITY_SIGNATURES_ENABLED 0x04
+#define NEGOTIATE_SECURITY_SIGNATURES_REQUIRED 0x08
+
+/* NT Flags2 bits - cifs6.txt section 3.1.2 */
+
+#define FLAGS2_LONG_PATH_COMPONENTS 0x0001
+#define FLAGS2_EXTENDED_ATTRIBUTES 0x0002
+#define FLAGS2_SMB_SECURITY_SIGNATURES 0x0004
+#define FLAGS2_UNKNOWN_BIT4 0x0010
+#define FLAGS2_IS_LONG_NAME 0x0040
+#define FLAGS2_EXTENDED_SECURITY 0x0800
+#define FLAGS2_DFS_PATHNAMES 0x1000
+#define FLAGS2_READ_PERMIT_EXECUTE 0x2000
+#define FLAGS2_32_BIT_ERROR_CODES 0x4000
+#define FLAGS2_UNICODE_STRINGS 0x8000
+
+#define FLAGS2_WIN2K_SIGNATURE 0xC852 /* Hack alert ! For now... JRA. */
+
+/* TCONX Flag (smb_vwv2). */
+#define TCONX_FLAG_EXTENDED_RESPONSE 0x8
+
+/* Capabilities. see ftp.microsoft.com/developr/drg/cifs/cifs/cifs4.txt */
+
+#define CAP_RAW_MODE 0x0001
+#define CAP_MPX_MODE 0x0002
+#define CAP_UNICODE 0x0004
+#define CAP_LARGE_FILES 0x0008
+#define CAP_NT_SMBS 0x0010
+#define CAP_RPC_REMOTE_APIS 0x0020
+#define CAP_STATUS32 0x0040
+#define CAP_LEVEL_II_OPLOCKS 0x0080
+#define CAP_LOCK_AND_READ 0x0100
+#define CAP_NT_FIND 0x0200
+#define CAP_DFS 0x1000
+#define CAP_W2K_SMBS 0x2000
+#define CAP_LARGE_READX 0x4000
+#define CAP_LARGE_WRITEX 0x8000
+#define CAP_UNIX 0x800000 /* Capabilities for UNIX extensions. Created by HP. */
+#define CAP_EXTENDED_SECURITY 0x80000000
+
+/* protocol types. It assumes that higher protocols include lower protocols
+ as subsets */
+enum protocol_types {PROTOCOL_NONE,PROTOCOL_CORE,PROTOCOL_COREPLUS,PROTOCOL_LANMAN1,PROTOCOL_LANMAN2,PROTOCOL_NT1};
+
+/* security levels */
+enum security_types {SEC_SHARE,SEC_USER,SEC_SERVER,SEC_DOMAIN,SEC_ADS};
+
+/* server roles */
+enum server_types {
+ ROLE_STANDALONE,
+ ROLE_DOMAIN_MEMBER,
+ ROLE_DOMAIN_BDC,
+ ROLE_DOMAIN_PDC
+};
+
+/* printing types */
+enum printing_types {PRINT_BSD,PRINT_SYSV,PRINT_AIX,PRINT_HPUX,
+ PRINT_QNX,PRINT_PLP,PRINT_LPRNG,PRINT_SOFTQ,
+ PRINT_CUPS,PRINT_LPRNT,PRINT_LPROS2,PRINT_IPRINT
+#if defined(DEVELOPER) || defined(ENABLE_BUILD_FARM_HACKS)
+,PRINT_TEST,PRINT_VLP
+#endif /* DEVELOPER */
+};
+
+/* LDAP schema types */
+enum schema_types {SCHEMA_COMPAT, SCHEMA_AD, SCHEMA_SAMBA};
+
+/* LDAP SSL options */
+enum ldap_ssl_types {LDAP_SSL_ON, LDAP_SSL_OFF, LDAP_SSL_START_TLS};
+
+/* LDAP PASSWD SYNC methods */
+enum ldap_passwd_sync_types {LDAP_PASSWD_SYNC_ON, LDAP_PASSWD_SYNC_OFF, LDAP_PASSWD_SYNC_ONLY};
+
+/* Remote architectures we know about. */
+enum remote_arch_types {RA_UNKNOWN, RA_WFWG, RA_OS2, RA_WIN95, RA_WINNT,
+ RA_WIN2K, RA_WINXP, RA_WIN2K3, RA_VISTA,
+ RA_SAMBA, RA_CIFSFS, RA_WINXP64};
+
+/* case handling */
+enum case_handling {CASE_LOWER,CASE_UPPER};
+
+/* ACL compatibility */
+enum acl_compatibility {ACL_COMPAT_AUTO, ACL_COMPAT_WINNT, ACL_COMPAT_WIN2K};
+/*
+ * 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 */
+
+/*
+ * Size of buffer to use when moving files across filesystems.
+ */
+#define COPYBUF_SIZE (8*1024)
+
+/*
+ * Used in chaining code.
+ */
+extern int chain_size;
+
+/*
+ * Map the Core and Extended Oplock requesst bits down
+ * to common bits (EXCLUSIVE_OPLOCK & BATCH_OPLOCK).
+ */
+
+/*
+ * Core protocol.
+ */
+#define CORE_OPLOCK_REQUEST(inbuf) \
+ ((CVAL(inbuf,smb_flg)&(FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK))>>5)
+
+/*
+ * Extended protocol.
+ */
+#define EXTENDED_OPLOCK_REQUEST(inbuf) ((SVAL(inbuf,smb_vwv2)&((1<<1)|(1<<2)))>>1)
+
+/* Lock types. */
+#define LOCKING_ANDX_SHARED_LOCK 0x1
+#define LOCKING_ANDX_OPLOCK_RELEASE 0x2
+#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x4
+#define LOCKING_ANDX_CANCEL_LOCK 0x8
+#define LOCKING_ANDX_LARGE_FILES 0x10
+
+/*
+ * Bits we test with.
+ * Note these must fit into 16-bits.
+ */
+
+#define NO_OPLOCK 0x0
+#define EXCLUSIVE_OPLOCK 0x1
+#define BATCH_OPLOCK 0x2
+#define LEVEL_II_OPLOCK 0x4
+
+/* The following are Samba-private. */
+#define INTERNAL_OPEN_ONLY 0x8
+#define FAKE_LEVEL_II_OPLOCK 0x10 /* Client requested no_oplock, but we have to
+ * inform potential level2 holders on
+ * write. */
+#define DEFERRED_OPEN_ENTRY 0x20
+#define UNUSED_SHARE_MODE_ENTRY 0x40
+#define FORCE_OPLOCK_BREAK_TO_NONE 0x80
+
+/* None of the following should ever appear in fsp->oplock_request. */
+#define SAMBA_PRIVATE_OPLOCK_MASK (INTERNAL_OPEN_ONLY|DEFERRED_OPEN_ENTRY|UNUSED_SHARE_MODE_ENTRY|FORCE_OPLOCK_BREAK_TO_NONE)
+
+#define EXCLUSIVE_OPLOCK_TYPE(lck) ((lck) & ((unsigned int)EXCLUSIVE_OPLOCK|(unsigned int)BATCH_OPLOCK))
+#define BATCH_OPLOCK_TYPE(lck) ((lck) & (unsigned int)BATCH_OPLOCK)
+#define LEVEL_II_OPLOCK_TYPE(lck) ((lck) & ((unsigned int)LEVEL_II_OPLOCK|(unsigned int)FAKE_LEVEL_II_OPLOCK))
+
+struct inform_level2_message {
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ uint16 mid;
+ unsigned long target_file_id;
+ unsigned long source_file_id;
+};
+
+/* kernel_oplock_message definition.
+
+struct kernel_oplock_message {
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ unsigned long file_id;
+};
+
+Offset Data length.
+0 SMB_DEV_T dev 8 bytes.
+8 SMB_INO_T inode 8 bytes
+16 unsigned long file_id 4 bytes
+20
+
+*/
+#define MSG_SMB_KERNEL_BREAK_SIZE 20
+
+/* file_renamed_message definition.
+
+struct file_renamed_message {
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ char names[1]; A variable area containing sharepath and filename.
+};
+
+Offset Data length.
+0 SMB_DEV_T dev 8 bytes.
+8 SMB_INO_T inode 8 bytes
+16 char [] name zero terminated namelen bytes
+minimum length == 18.
+
+*/
+
+#define MSG_FILE_RENAMED_MIN_SIZE 16
+
+/*
+ * On the wire return values for oplock types.
+ */
+
+#define CORE_OPLOCK_GRANTED (1<<5)
+#define EXTENDED_OPLOCK_GRANTED (1<<15)
+
+#define NO_OPLOCK_RETURN 0
+#define EXCLUSIVE_OPLOCK_RETURN 1
+#define BATCH_OPLOCK_RETURN 2
+#define LEVEL_II_OPLOCK_RETURN 3
+
+/* Oplock levels */
+#define OPLOCKLEVEL_NONE 0
+#define OPLOCKLEVEL_II 1
+
+/*
+ * Capabilities abstracted for different systems.
+ */
+
+enum smbd_capability {
+ KERNEL_OPLOCK_CAPABILITY,
+ DMAPI_ACCESS_CAPABILITY,
+ LEASE_CAPABILITY
+};
+
+/* if a kernel does support oplocks then a structure of the following
+ typee is used to describe how to interact with the kernel */
+struct kernel_oplocks {
+ files_struct * (*receive_message)(fd_set *fds);
+ bool (*set_oplock)(files_struct *fsp, int oplock_type);
+ void (*release_oplock)(files_struct *fsp);
+ bool (*msg_waiting)(fd_set *fds);
+ int notification_fd;
+};
+
+#include "smb_macros.h"
+
+#define MAX_NETBIOSNAME_LEN 16
+/* DOS character, NetBIOS namestring. Type used on the wire. */
+typedef char nstring[MAX_NETBIOSNAME_LEN];
+/* Unix character, NetBIOS namestring. Type used to manipulate name in nmbd. */
+typedef char unstring[MAX_NETBIOSNAME_LEN*4];
+
+/* A netbios name structure. */
+struct nmb_name {
+ nstring name;
+ char scope[64];
+ unsigned int name_type;
+};
+
+/* A netbios node status array element. */
+typedef struct node_status_ {
+ nstring name;
+ unsigned char type;
+ unsigned char flags;
+} NODE_STATUS_STRUCT;
+
+/* The extra info from a NetBIOS node status query */
+struct node_status_extra {
+ unsigned char mac_addr[6];
+ /* There really is more here ... */
+};
+
+struct pwd_info {
+ bool null_pwd;
+ bool cleartext;
+
+ fstring password;
+};
+
+/* For split krb5 SPNEGO blobs. */
+struct pending_auth_data {
+ struct pending_auth_data *prev, *next;
+ uint16 vuid; /* Tag for this entry. */
+ uint16 smbpid; /* Alternate tag for this entry. */
+ size_t needed_len;
+ DATA_BLOB partial_data;
+};
+
+typedef struct user_struct {
+ struct user_struct *next, *prev;
+ uint16 vuid; /* Tag for this entry. */
+
+ char *session_keystr; /* used by utmp and pam session code.
+ TDB key string */
+ int homes_snum;
+
+ struct auth_serversupplied_info *server_info;
+
+ struct auth_ntlmssp_state *auth_ntlmssp_state;
+} user_struct;
+
+struct unix_error_map {
+ int unix_error;
+ int dos_class;
+ int dos_code;
+ NTSTATUS nt_error;
+};
+
+/*
+ * Size of new password account encoding string. This is enough space to
+ * hold 11 ACB characters, plus the surrounding [] and a terminating null.
+ * Do not change unless you are adding new ACB bits!
+ */
+
+#define NEW_PW_FORMAT_SPACE_PADDED_LEN 14
+
+/*
+ Do you want session setups at user level security with a invalid
+ password to be rejected or allowed in as guest? WinNT rejects them
+ but it can be a pain as it means "net view" needs to use a password
+
+ You have 3 choices in the setting of map_to_guest:
+
+ "NEVER_MAP_TO_GUEST" means session setups with an invalid password
+ are rejected. This is the default.
+
+ "MAP_TO_GUEST_ON_BAD_USER" means session setups with an invalid password
+ are rejected, unless the username does not exist, in which case it
+ is treated as a guest login
+
+ "MAP_TO_GUEST_ON_BAD_PASSWORD" means session setups with an invalid password
+ are treated as a guest login
+
+ Note that map_to_guest only has an effect in user or server
+ level security.
+*/
+
+#define NEVER_MAP_TO_GUEST 0
+#define MAP_TO_GUEST_ON_BAD_USER 1
+#define MAP_TO_GUEST_ON_BAD_PASSWORD 2
+#define MAP_TO_GUEST_ON_BAD_UID 3
+
+#define SAFE_NETBIOS_CHARS ". -_"
+
+/* generic iconv conversion structure */
+typedef struct _smb_iconv_t {
+ size_t (*direct)(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+ size_t (*pull)(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+ size_t (*push)(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+ void *cd_direct, *cd_pull, *cd_push;
+ char *from_name, *to_name;
+} *smb_iconv_t;
+
+/* The maximum length of a trust account password.
+ Used when we randomly create it, 15 char passwords
+ exceed NT4's max password length */
+
+#define DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH 14
+
+#include "popt_common.h"
+
+#define PORT_NONE 0
+#ifndef LDAP_PORT
+#define LDAP_PORT 389
+#endif
+#define LDAP_GC_PORT 3268
+
+/* used by the IP comparison function */
+struct ip_service {
+ struct sockaddr_storage ss;
+ unsigned port;
+};
+
+/* Special name type used to cause a _kerberos DNS lookup. */
+#define KDC_NAME_TYPE 0xDCDC
+
+/* Used by the SMB signing functions. */
+
+typedef struct smb_sign_info {
+ void (*sign_outgoing_message)(char *outbuf, struct smb_sign_info *si);
+ bool (*check_incoming_message)(const char *inbuf, struct smb_sign_info *si, bool must_be_ok);
+ void (*free_signing_context)(struct smb_sign_info *si);
+ void *signing_context;
+
+ bool negotiated_smb_signing;
+ bool allow_smb_signing;
+ bool doing_signing;
+ bool mandatory_signing;
+ bool seen_valid; /* Have I ever seen a validly signed packet? */
+} smb_sign_info;
+
+struct ea_struct {
+ uint8 flags;
+ char *name;
+ DATA_BLOB value;
+};
+
+struct ea_list {
+ struct ea_list *next, *prev;
+ struct ea_struct ea;
+};
+
+/* EA names used internally in Samba. KEEP UP TO DATE with prohibited_ea_names in trans2.c !. */
+#define SAMBA_POSIX_INHERITANCE_EA_NAME "user.SAMBA_PAI"
+/* EA to use for DOS attributes */
+#define SAMBA_XATTR_DOS_ATTRIB "user.DOSATTRIB"
+/* Prefix for DosStreams in the vfs_streams_xattr module */
+#define SAMBA_XATTR_DOSSTREAM_PREFIX "user.DosStream."
+
+#define UUID_SIZE 16
+
+#define UUID_FLAT_SIZE 16
+typedef struct uuid_flat {
+ uint8 info[UUID_FLAT_SIZE];
+} UUID_FLAT;
+
+/* map readonly options */
+enum mapreadonly_options {MAP_READONLY_NO, MAP_READONLY_YES, MAP_READONLY_PERMISSIONS};
+
+/* usershare error codes. */
+enum usershare_err {
+ USERSHARE_OK=0,
+ USERSHARE_MALFORMED_FILE,
+ USERSHARE_BAD_VERSION,
+ USERSHARE_MALFORMED_PATH,
+ USERSHARE_MALFORMED_COMMENT_DEF,
+ USERSHARE_MALFORMED_ACL_DEF,
+ USERSHARE_ACL_ERR,
+ USERSHARE_PATH_NOT_ABSOLUTE,
+ USERSHARE_PATH_IS_DENIED,
+ USERSHARE_PATH_NOT_ALLOWED,
+ USERSHARE_PATH_NOT_DIRECTORY,
+ USERSHARE_POSIX_ERR
+};
+
+/* Different reasons for closing a file. */
+enum file_close_type {NORMAL_CLOSE=0,SHUTDOWN_CLOSE,ERROR_CLOSE};
+
+/* Used in SMB_FS_OBJECTID_INFORMATION requests. Must be exactly 48 bytes. */
+#define SAMBA_EXTENDED_INFO_MAGIC 0x536d4261 /* "SmBa" */
+#define SAMBA_EXTENDED_INFO_VERSION_STRING_LENGTH 28
+struct smb_extended_info {
+ uint32 samba_magic; /* Always SAMBA_EXTRA_INFO_MAGIC */
+ uint32 samba_version; /* Major/Minor/Release/Revision */
+ uint32 samba_subversion; /* Prerelease/RC/Vendor patch */
+ NTTIME samba_gitcommitdate;
+ char samba_version_string[SAMBA_EXTENDED_INFO_VERSION_STRING_LENGTH];
+};
+
+#endif /* _SMB_H */
diff --git a/source3/include/smb_acls.h b/source3/include/smb_acls.h
new file mode 100644
index 0000000000..3d9cfbf5d2
--- /dev/null
+++ b/source3/include/smb_acls.h
@@ -0,0 +1,65 @@
+/*
+ Unix SMB/CIFS implementation.
+ Portable SMB ACL interface
+ Copyright (C) Jeremy Allison 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SMB_ACLS_H
+#define _SMB_ACLS_H
+
+typedef int SMB_ACL_TYPE_T;
+typedef mode_t *SMB_ACL_PERMSET_T;
+typedef mode_t SMB_ACL_PERM_T;
+#define SMB_ACL_READ 4
+#define SMB_ACL_WRITE 2
+#define SMB_ACL_EXECUTE 1
+
+/* Types of ACLs. */
+enum smb_acl_tag_t {
+ SMB_ACL_TAG_INVALID=0,
+ SMB_ACL_USER=1,
+ SMB_ACL_USER_OBJ,
+ SMB_ACL_GROUP,
+ SMB_ACL_GROUP_OBJ,
+ SMB_ACL_OTHER,
+ SMB_ACL_MASK
+};
+
+typedef enum smb_acl_tag_t SMB_ACL_TAG_T;
+
+struct smb_acl_entry {
+ enum smb_acl_tag_t a_type;
+ SMB_ACL_PERM_T a_perm;
+ uid_t uid;
+ gid_t gid;
+};
+
+typedef struct smb_acl_t {
+ int size;
+ int count;
+ int next;
+ struct smb_acl_entry acl[1];
+} *SMB_ACL_T;
+
+typedef struct smb_acl_entry *SMB_ACL_ENTRY_T;
+
+#define SMB_ACL_FIRST_ENTRY 0
+#define SMB_ACL_NEXT_ENTRY 1
+
+#define SMB_ACL_TYPE_ACCESS 0
+#define SMB_ACL_TYPE_DEFAULT 1
+
+#endif /* _SMB_ACLS_H */
diff --git a/source3/include/smb_ldap.h b/source3/include/smb_ldap.h
new file mode 100644
index 0000000000..a3c270d95c
--- /dev/null
+++ b/source3/include/smb_ldap.h
@@ -0,0 +1,255 @@
+/*
+ Unix SMB/CIFS Implementation.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Volker Lendecke 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _SMB_LDAP_H
+#define _SMB_LDAP_H
+
+enum ldap_request_tag {
+ LDAP_TAG_BindRequest = 0,
+ LDAP_TAG_BindResponse = 1,
+ LDAP_TAG_UnbindRequest = 2,
+ LDAP_TAG_SearchRequest = 3,
+ LDAP_TAG_SearchResultEntry = 4,
+ LDAP_TAG_SearchResultDone = 5,
+ LDAP_TAG_ModifyRequest = 6,
+ LDAP_TAG_ModifyResponse = 7,
+ LDAP_TAG_AddRequest = 8,
+ LDAP_TAG_AddResponse = 9,
+ LDAP_TAG_DelRequest = 10,
+ LDAP_TAG_DelResponse = 11,
+ LDAP_TAG_ModifyDNRequest = 12,
+ LDAP_TAG_ModifyDNResponse = 13,
+ LDAP_TAG_CompareRequest = 14,
+ LDAP_TAG_CompareResponse = 15,
+ LDAP_TAG_AbandonRequest = 16,
+ LDAP_TAG_SearchResultReference = 19,
+ LDAP_TAG_ExtendedRequest = 23,
+ LDAP_TAG_ExtendedResponse = 24
+};
+
+enum ldap_auth_mechanism {
+ LDAP_AUTH_MECH_SIMPLE = 0,
+ LDAP_AUTH_MECH_SASL = 3
+};
+
+#ifndef LDAP_SUCCESS
+enum ldap_result_code {
+ LDAP_SUCCESS = 0,
+ LDAP_SASL_BIND_IN_PROGRESS = 0x0e,
+ LDAP_INVALID_CREDENTIALS = 0x31,
+ LDAP_OTHER = 0x50
+};
+#endif /* LDAP_SUCCESS */
+
+struct ldap_Result {
+ int resultcode;
+ const char *dn;
+ const char *errormessage;
+ const char *referral;
+};
+
+struct ldap_attribute {
+ const char *name;
+ int num_values;
+ DATA_BLOB *values;
+};
+
+struct ldap_BindRequest {
+ int version;
+ const char *dn;
+ enum ldap_auth_mechanism mechanism;
+ union {
+ const char *password;
+ struct {
+ const char *mechanism;
+ DATA_BLOB secblob;
+ } SASL;
+ } creds;
+};
+
+struct ldap_BindResponse {
+ struct ldap_Result response;
+ union {
+ DATA_BLOB secblob;
+ } SASL;
+};
+
+struct ldap_UnbindRequest {
+ uint8 __dummy;
+};
+
+enum ldap_scope {
+ LDAP_SEARCH_SCOPE_BASE = 0,
+ LDAP_SEARCH_SCOPE_SINGLE = 1,
+ LDAP_SEARCH_SCOPE_SUB = 2
+};
+
+enum ldap_deref {
+ LDAP_DEREFERENCE_NEVER = 0,
+ LDAP_DEREFERENCE_IN_SEARCHING = 1,
+ LDAP_DEREFERENCE_FINDING_BASE = 2,
+ LDAP_DEREFERENCE_ALWAYS
+};
+
+struct ldap_SearchRequest {
+ const char *basedn;
+ enum ldap_scope scope;
+ enum ldap_deref deref;
+ uint32 timelimit;
+ uint32 sizelimit;
+ bool attributesonly;
+ char *filter;
+ int num_attributes;
+ const char **attributes;
+};
+
+struct ldap_SearchResEntry {
+ const char *dn;
+ int num_attributes;
+ struct ldap_attribute *attributes;
+};
+
+struct ldap_SearchResRef {
+ int num_referrals;
+ const char **referrals;
+};
+
+enum ldap_modify_type {
+ LDAP_MODIFY_NONE = -1,
+ LDAP_MODIFY_ADD = 0,
+ LDAP_MODIFY_DELETE = 1,
+ LDAP_MODIFY_REPLACE = 2
+};
+
+struct ldap_mod {
+ enum ldap_modify_type type;
+ struct ldap_attribute attrib;
+};
+
+struct ldap_ModifyRequest {
+ const char *dn;
+ int num_mods;
+ struct ldap_mod *mods;
+};
+
+struct ldap_AddRequest {
+ const char *dn;
+ int num_attributes;
+ struct ldap_attribute *attributes;
+};
+
+struct ldap_DelRequest {
+ const char *dn;
+};
+
+struct ldap_ModifyDNRequest {
+ const char *dn;
+ const char *newrdn;
+ bool deleteolddn;
+ const char *newsuperior;
+};
+
+struct ldap_CompareRequest {
+ const char *dn;
+ const char *attribute;
+ const char *value;
+};
+
+struct ldap_AbandonRequest {
+ uint32 messageid;
+};
+
+struct ldap_ExtendedRequest {
+ const char *oid;
+ DATA_BLOB value;
+};
+
+struct ldap_ExtendedResponse {
+ struct ldap_Result response;
+ const char *name;
+ DATA_BLOB value;
+};
+
+union ldap_Request {
+ struct ldap_BindRequest BindRequest;
+ struct ldap_BindResponse BindResponse;
+ struct ldap_UnbindRequest UnbindRequest;
+ struct ldap_SearchRequest SearchRequest;
+ struct ldap_SearchResEntry SearchResultEntry;
+ struct ldap_Result SearchResultDone;
+ struct ldap_SearchResRef SearchResultReference;
+ struct ldap_ModifyRequest ModifyRequest;
+ struct ldap_Result ModifyResponse;
+ struct ldap_AddRequest AddRequest;
+ struct ldap_Result AddResponse;
+ struct ldap_DelRequest DelRequest;
+ struct ldap_Result DelResponse;
+ struct ldap_ModifyDNRequest ModifyDNRequest;
+ struct ldap_Result ModifyDNResponse;
+ struct ldap_CompareRequest CompareRequest;
+ struct ldap_Result CompareResponse;
+ struct ldap_AbandonRequest AbandonRequest;
+ struct ldap_ExtendedRequest ExtendedRequest;
+ struct ldap_ExtendedResponse ExtendedResponse;
+};
+
+struct ldap_Control {
+ const char *oid;
+ bool critical;
+ DATA_BLOB value;
+};
+
+struct ldap_message {
+ TALLOC_CTX *mem_ctx;
+ uint32 messageid;
+ uint8 type;
+ union ldap_Request r;
+ int num_controls;
+ struct ldap_Control *controls;
+};
+
+struct ldap_queue_entry {
+ struct ldap_queue_entry *next, *prev;
+ int msgid;
+ struct ldap_message *msg;
+};
+
+struct ldap_connection {
+ TALLOC_CTX *mem_ctx;
+ int sock;
+ int next_msgid;
+ char *host;
+ uint16 port;
+ bool ldaps;
+
+ const char *auth_dn;
+ const char *simple_pw;
+
+ /* Current outstanding search entry */
+ int searchid;
+
+ /* List for incoming search entries */
+ struct ldap_queue_entry *search_entries;
+
+ /* Outstanding LDAP requests that have not yet been replied to */
+ struct ldap_queue_entry *outstanding;
+};
+
+#endif
diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h
new file mode 100644
index 0000000000..20e2a9a443
--- /dev/null
+++ b/source3/include/smb_macros.h
@@ -0,0 +1,396 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) John H Terpstra 1996-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1999
+ Copyright (C) Paul Ashton 1998 - 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SMB_MACROS_H
+#define _SMB_MACROS_H
+
+/* Misc bit macros */
+#define BOOLSTR(b) ((b) ? "Yes" : "No")
+#define BITSETW(ptr,bit) ((SVAL(ptr,0) & (1<<(bit)))!=0)
+
+/* for readability... */
+#define IS_DOS_READONLY(test_mode) (((test_mode) & aRONLY) != 0)
+#define IS_DOS_DIR(test_mode) (((test_mode) & aDIR) != 0)
+#define IS_DOS_ARCHIVE(test_mode) (((test_mode) & aARCH) != 0)
+#define IS_DOS_SYSTEM(test_mode) (((test_mode) & aSYSTEM) != 0)
+#define IS_DOS_HIDDEN(test_mode) (((test_mode) & aHIDDEN) != 0)
+
+#ifndef SAFE_FREE /* Oh no this is also defined in tdb.h */
+
+/**
+ * Free memory if the pointer and zero the pointer.
+ *
+ * @note You are explicitly allowed to pass NULL pointers -- they will
+ * always be ignored.
+ **/
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
+#endif
+
+/* assert macros */
+#ifdef DEVELOPER
+#define SMB_ASSERT(b) ( (b) ? (void)0 : \
+ (DEBUG(0,("PANIC: assert failed at %s(%d): %s\n", \
+ __FILE__, __LINE__, #b)), smb_panic("assert failed: " #b)))
+#else
+/* redefine the assert macro for non-developer builds */
+#define SMB_ASSERT(b) ( (b) ? (void)0 : \
+ (DEBUG(0,("PANIC: assert failed at %s(%d): %s\n", \
+ __FILE__, __LINE__, #b))))
+#endif
+
+#define SMB_WARN(condition, message) \
+ ((condition) ? (void)0 : \
+ DEBUG(0, ("WARNING: %s: %s\n", #condition, message)))
+
+#define SMB_ASSERT_ARRAY(a,n) SMB_ASSERT((sizeof(a)/sizeof((a)[0])) >= (n))
+
+/* these are useful macros for checking validity of handles */
+#define IS_IPC(conn) ((conn) && (conn)->ipc)
+#define IS_PRINT(conn) ((conn) && (conn)->printer)
+/* you must add the following extern declaration to files using this macro
+ * (do not add it to the macro as that causes nested extern declaration warnings)
+ * extern struct current_user current_user;
+ */
+#define FSP_BELONGS_CONN(fsp,conn) do {\
+ if (!((fsp) && (conn) && ((conn)==(fsp)->conn) && (current_user.vuid==(fsp)->vuid))) \
+ return ERROR_NT(NT_STATUS_INVALID_HANDLE); \
+ } while(0)
+
+/* you must add the following extern declaration to files using this macro
+ * (do not add it to the macro as that causes nested extern declaration warnings)
+ * extern struct current_user current_user;
+ */
+#define CHECK_FSP(fsp,conn) do {\
+ if (!(fsp) || !(conn)) \
+ return ERROR_NT(NT_STATUS_INVALID_HANDLE); \
+ else if (((conn) != (fsp)->conn) || current_user.vuid != (fsp)->vuid) \
+ return ERROR_NT(NT_STATUS_INVALID_HANDLE); \
+ else if ((fsp)->is_directory) \
+ return ERROR_NT(NT_STATUS_INVALID_DEVICE_REQUEST); \
+ else if ((fsp)->fh->fd == -1) \
+ return ERROR_NT(NT_STATUS_ACCESS_DENIED); \
+ (fsp)->num_smb_operations++;\
+ } while(0)
+
+#define CHECK_READ(fsp,inbuf) (((fsp)->fh->fd != -1) && ((fsp)->can_read || \
+ ((SVAL((inbuf),smb_flg2) & FLAGS2_READ_PERMIT_EXECUTE) && \
+ (fsp->access_mask & FILE_EXECUTE))))
+
+#define CHECK_WRITE(fsp) ((fsp)->can_write && ((fsp)->fh->fd != -1))
+
+#define ERROR_WAS_LOCK_DENIED(status) (NT_STATUS_EQUAL((status), NT_STATUS_LOCK_NOT_GRANTED) || \
+ NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT) )
+
+/* the service number for the [globals] defaults */
+#define GLOBAL_SECTION_SNUM (-1)
+/* translates a connection number into a service number */
+#define SNUM(conn) ((conn)?(conn)->params->service:GLOBAL_SECTION_SNUM)
+
+
+/* access various service details */
+#define SERVICE(snum) (lp_servicename(snum))
+#define PRINTERNAME(snum) (lp_printername(snum))
+#define CAN_WRITE(conn) (!conn->read_only)
+#define VALID_SNUM(snum) (lp_snum_ok(snum))
+#define GUEST_OK(snum) (VALID_SNUM(snum) && lp_guest_ok(snum))
+#define GUEST_ONLY(snum) (VALID_SNUM(snum) && lp_guest_only(snum))
+#define CAN_SETDIR(snum) (!lp_no_set_dir(snum))
+#define CAN_PRINT(conn) ((conn) && lp_print_ok(SNUM(conn)))
+#define MAP_HIDDEN(conn) ((conn) && lp_map_hidden(SNUM(conn)))
+#define MAP_SYSTEM(conn) ((conn) && lp_map_system(SNUM(conn)))
+#define MAP_ARCHIVE(conn) ((conn) && lp_map_archive(SNUM(conn)))
+#define IS_HIDDEN_PATH(conn,path) ((conn) && is_in_path((path),(conn)->hide_list,(conn)->case_sensitive))
+#define IS_VETO_PATH(conn,path) ((conn) && is_in_path((path),(conn)->veto_list,(conn)->case_sensitive))
+#define IS_VETO_OPLOCK_PATH(conn,path) ((conn) && is_in_path((path),(conn)->veto_oplock_list,(conn)->case_sensitive))
+
+/*
+ * 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 SET_STAT_INVALID(st) ((st).st_nlink = 0)
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+#ifndef ABS
+#define ABS(a) ((a)>0?(a):(-(a)))
+#endif
+
+/* Macros to get at offsets within smb_lkrng and smb_unlkrng
+ structures. We cannot define these as actual structures
+ due to possible differences in structure packing
+ on different machines/compilers. */
+
+#define SMB_LPID_OFFSET(indx) (10 * (indx))
+#define SMB_LKOFF_OFFSET(indx) ( 2 + (10 * (indx)))
+#define SMB_LKLEN_OFFSET(indx) ( 6 + (10 * (indx)))
+#define SMB_LARGE_LPID_OFFSET(indx) (20 * (indx))
+#define SMB_LARGE_LKOFF_OFFSET_HIGH(indx) (4 + (20 * (indx)))
+#define SMB_LARGE_LKOFF_OFFSET_LOW(indx) (8 + (20 * (indx)))
+#define SMB_LARGE_LKLEN_OFFSET_HIGH(indx) (12 + (20 * (indx)))
+#define SMB_LARGE_LKLEN_OFFSET_LOW(indx) (16 + (20 * (indx)))
+
+#define ERROR_DOS(class,code) error_packet(outbuf,class,code,NT_STATUS_OK,__LINE__,__FILE__)
+#define ERROR_NT(status) error_packet(outbuf,0,0,status,__LINE__,__FILE__)
+#define ERROR_FORCE_NT(status) error_packet(outbuf,-1,-1,status,__LINE__,__FILE__)
+#define ERROR_BOTH(status,class,code) error_packet(outbuf,class,code,status,__LINE__,__FILE__)
+
+#define reply_nterror(req,status) reply_nt_error(req,status,__LINE__,__FILE__)
+#define reply_force_nterror(req,status) reply_force_nt_error(req,status,__LINE__,__FILE__)
+#define reply_doserror(req,eclass,ecode) reply_dos_error(req,eclass,ecode,__LINE__,__FILE__)
+#define reply_botherror(req,status,eclass,ecode) reply_both_error(req,eclass,ecode,status,__LINE__,__FILE__)
+#define reply_unixerror(req,defclass,deferror) reply_unix_error(req,defclass,deferror,NT_STATUS_OK,__LINE__,__FILE__)
+
+#if 0
+/* defined in IDL */
+/* these are the datagram types */
+#define DGRAM_DIRECT_UNIQUE 0x10
+#endif
+
+#define SMB_ROUNDUP(x,r) ( ((x)%(r)) ? ( (((x)+(r))/(r))*(r) ) : (x))
+
+/* Extra macros added by Ying Chen at IBM - speed increase by inlining. */
+#define smb_buf(buf) (((char *)(buf)) + smb_size + CVAL(buf,smb_wct)*2)
+#define smb_buflen(buf) (SVAL(buf,smb_vwv0 + (int)CVAL(buf, smb_wct)*2))
+
+/* the remaining number of bytes in smb buffer 'buf' from pointer 'p'. */
+#define smb_bufrem(buf, p) (smb_buflen(buf)-PTR_DIFF(p, smb_buf(buf)))
+
+/* Note that chain_size must be available as an extern int to this macro. */
+#define smb_offset(p,buf) (PTR_DIFF(p,buf+4) + chain_size)
+
+#define smb_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|((PVAL(buf,1)&1)<<16))
+#define _smb_setlen(buf,len) do { buf[0] = 0; buf[1] = ((len)&0x10000)>>16; \
+ buf[2] = ((len)&0xFF00)>>8; buf[3] = (len)&0xFF; } while (0)
+
+#define smb_len_large(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
+#define _smb_setlen_large(buf,len) do { buf[0] = 0; buf[1] = ((len)&0xFF0000)>>16; \
+ buf[2] = ((len)&0xFF00)>>8; buf[3] = (len)&0xFF; } while (0)
+
+#define ENCRYPTION_REQUIRED(conn) ((conn) ? ((conn)->encrypt_level == Required) : false)
+#define IS_CONN_ENCRYPTED(conn) ((conn) ? (conn)->encrypted_tid : false)
+
+/*******************************************************************
+find the difference in milliseconds between two struct timeval
+values
+********************************************************************/
+
+#define TvalDiff(tvalold,tvalnew) \
+ (((tvalnew)->tv_sec - (tvalold)->tv_sec)*1000 + \
+ ((int)(tvalnew)->tv_usec - (int)(tvalold)->tv_usec)/1000)
+
+/****************************************************************************
+true if two IPv4 addresses are equal
+****************************************************************************/
+
+#define ip_equal_v4(ip1,ip2) ((ip1).s_addr == (ip2).s_addr)
+
+/*****************************************************************
+ splits out the last subkey of a key
+ *****************************************************************/
+
+#define reg_get_subkey(full_keyname, key_name, subkey_name) \
+ split_at_last_component(full_keyname, key_name, '\\', subkey_name)
+
+/****************************************************************************
+ Return True if the offset is at zero.
+****************************************************************************/
+
+#define dptr_zero(buf) (IVAL(buf,1) == 0)
+
+/*******************************************************************
+copy an IP address from one buffer to another
+********************************************************************/
+
+#define putip(dest,src) memcpy(dest,src,4)
+
+/*******************************************************************
+ Return True if a server has CIFS UNIX capabilities.
+********************************************************************/
+
+#define SERVER_HAS_UNIX_CIFS(c) ((c)->capabilities & CAP_UNIX)
+
+/****************************************************************************
+ Make a filename into unix format.
+****************************************************************************/
+
+#define IS_DIRECTORY_SEP(c) ((c) == '\\' || (c) == '/')
+#define unix_format(fname) string_replace(fname,'\\','/')
+#define unix_format_w(fname) string_replace_w(fname, UCS2_CHAR('\\'), UCS2_CHAR('/'))
+
+/****************************************************************************
+ Make a file into DOS format.
+****************************************************************************/
+
+#define dos_format(fname) string_replace(fname,'/','\\')
+
+/*****************************************************************************
+ Check to see if we are a DC for this domain
+*****************************************************************************/
+
+#define IS_DC (lp_server_role()==ROLE_DOMAIN_PDC || lp_server_role()==ROLE_DOMAIN_BDC)
+
+/*****************************************************************************
+ Safe allocation macros.
+*****************************************************************************/
+
+#define SMB_MALLOC_ARRAY(type,count) (type *)malloc_array(sizeof(type),(count))
+#define SMB_MEMALIGN_ARRAY(type,align,count) (type *)memalign_array(sizeof(type),align,(count))
+#define SMB_REALLOC(p,s) Realloc((p),(s),True) /* Always frees p on error or s == 0 */
+#define SMB_REALLOC_KEEP_OLD_ON_ERROR(p,s) Realloc((p),(s),False) /* Never frees p on error or s == 0 */
+#define SMB_REALLOC_ARRAY(p,type,count) (type *)realloc_array((p),sizeof(type),(count),True) /* Always frees p on error or s == 0 */
+#define SMB_REALLOC_ARRAY_KEEP_OLD_ON_ERROR(p,type,count) (type *)realloc_array((p),sizeof(type),(count),False) /* Never frees p on error or s == 0 */
+#define SMB_CALLOC_ARRAY(type,count) (type *)calloc_array(sizeof(type),(count))
+#define SMB_XMALLOC_P(type) (type *)smb_xmalloc_array(sizeof(type),1)
+#define SMB_XMALLOC_ARRAY(type,count) (type *)smb_xmalloc_array(sizeof(type),(count))
+
+/* The new talloc is paranoid malloc checker safe. */
+
+#if 0
+
+Disable these now we have checked all code paths and ensured
+NULL returns on zero request. JRA.
+
+#define TALLOC(ctx, size) talloc_zeronull(ctx, size, __location__)
+#define TALLOC_P(ctx, type) (type *)talloc_zeronull(ctx, sizeof(type), #type)
+#define TALLOC_ARRAY(ctx, type, count) (type *)_talloc_array_zeronull(ctx, sizeof(type), count, #type)
+#define TALLOC_MEMDUP(ctx, ptr, size) _talloc_memdup_zeronull(ctx, ptr, size, __location__)
+#define TALLOC_ZERO(ctx, size) _talloc_zero_zeronull(ctx, size, __location__)
+#define TALLOC_ZERO_P(ctx, type) (type *)_talloc_zero_zeronull(ctx, sizeof(type), #type)
+#define TALLOC_ZERO_ARRAY(ctx, type, count) (type *)_talloc_zero_array_zeronull(ctx, sizeof(type), count, #type)
+#define TALLOC_SIZE(ctx, size) talloc_zeronull(ctx, size, __location__)
+#define TALLOC_ZERO_SIZE(ctx, size) _talloc_zero_zeronull(ctx, size, __location__)
+
+#else
+
+#define TALLOC(ctx, size) talloc_named_const(ctx, size, __location__)
+#define TALLOC_P(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
+#define TALLOC_ARRAY(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
+#define TALLOC_MEMDUP(ctx, ptr, size) _talloc_memdup(ctx, ptr, size, __location__)
+#define TALLOC_ZERO(ctx, size) _talloc_zero(ctx, size, __location__)
+#define TALLOC_ZERO_P(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
+#define TALLOC_ZERO_ARRAY(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type)
+#define TALLOC_SIZE(ctx, size) talloc_named_const(ctx, size, __location__)
+#define TALLOC_ZERO_SIZE(ctx, size) _talloc_zero(ctx, size, __location__)
+
+#endif
+
+#define TALLOC_REALLOC(ctx, ptr, count) _talloc_realloc(ctx, ptr, count, __location__)
+#define TALLOC_REALLOC_ARRAY(ctx, ptr, type, count) (type *)_talloc_realloc_array(ctx, ptr, sizeof(type), count, #type)
+#define talloc_destroy(ctx) talloc_free(ctx)
+#define TALLOC_FREE(ctx) do { if ((ctx) != NULL) {talloc_free(ctx); ctx=NULL;} } while(0)
+
+/* only define PARANOID_MALLOC_CHECKER with --enable-developer */
+
+#if defined(DEVELOPER)
+# define PARANOID_MALLOC_CHECKER 1
+#endif
+
+#if defined(PARANOID_MALLOC_CHECKER)
+
+#define PRS_ALLOC_MEM(ps, type, count) (type *)prs_alloc_mem_((ps),sizeof(type),(count))
+
+/* Get medieval on our ass about malloc.... */
+
+/* Restrictions on malloc/realloc/calloc. */
+#ifdef malloc
+#undef malloc
+#endif
+#define malloc(s) __ERROR_DONT_USE_MALLOC_DIRECTLY
+
+#ifdef realloc
+#undef realloc
+#endif
+#define realloc(p,s) __ERROR_DONT_USE_REALLOC_DIRECTLY
+
+#ifdef calloc
+#undef calloc
+#endif
+#define calloc(n,s) __ERROR_DONT_USE_CALLOC_DIRECTLY
+
+#ifdef strndup
+#undef strndup
+#endif
+#define strndup(s,n) __ERROR_DONT_USE_STRNDUP_DIRECTLY
+
+#ifdef strdup
+#undef strdup
+#endif
+#define strdup(s) __ERROR_DONT_USE_STRDUP_DIRECTLY
+
+#define SMB_MALLOC(s) malloc_(s)
+#define SMB_MALLOC_P(type) (type *)malloc_(sizeof(type))
+
+#define SMB_STRDUP(s) smb_xstrdup(s)
+#define SMB_STRNDUP(s,n) smb_xstrndup(s,n)
+
+#else
+
+#define PRS_ALLOC_MEM(ps, type, count) (type *)prs_alloc_mem((ps),sizeof(type),(count))
+
+/* Regular malloc code. */
+
+#define SMB_MALLOC(s) malloc(s)
+#define SMB_MALLOC_P(type) (type *)malloc(sizeof(type))
+
+#define SMB_STRDUP(s) strdup(s)
+#define SMB_STRNDUP(s,n) strndup(s,n)
+
+#endif
+
+#define ADD_TO_ARRAY(mem_ctx, type, elem, array, num) \
+do { \
+ *(array) = ((mem_ctx) != NULL) ? \
+ TALLOC_REALLOC_ARRAY(mem_ctx, (*(array)), type, (*(num))+1) : \
+ SMB_REALLOC_ARRAY((*(array)), type, (*(num))+1); \
+ SMB_ASSERT((*(array)) != NULL); \
+ (*(array))[*(num)] = (elem); \
+ (*(num)) += 1; \
+} while (0)
+
+#define ADD_TO_LARGE_ARRAY(mem_ctx, type, elem, array, num, size) \
+ add_to_large_array((mem_ctx), sizeof(type), &(elem), (void *)(array), (num), (size));
+
+#ifndef ISDOT
+#define ISDOT(p) (*(p) == '.' && *((p) + 1) == '\0')
+#endif /* ISDOT */
+
+#ifndef ISDOTDOT
+#define ISDOTDOT(p) (*(p) == '.' && *((p) + 1) == '.' && *((p) + 2) == '\0')
+#endif /* ISDOTDOT */
+
+#ifndef toupper_ascii_fast
+/* Warning - this must only be called with 0 <= c < 128. IT WILL
+ * GIVE GARBAGE if c > 128 or c < 0. JRA.
+ */
+extern char toupper_ascii_fast_table[];
+#define toupper_ascii_fast(c) toupper_ascii_fast_table[(unsigned int)(c)];
+#endif
+
+#endif /* _SMB_MACROS_H */
diff --git a/source3/include/smb_share_modes.h b/source3/include/smb_share_modes.h
new file mode 100644
index 0000000000..101bec8245
--- /dev/null
+++ b/source3/include/smb_share_modes.h
@@ -0,0 +1,105 @@
+/*
+ Samba share mode database library.
+
+ Copyright (C) Jeremy Allison 2005.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SMB_SHARE_MODES_H_
+#define _SMB_STATE_MODES_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+
+/* Opaque database context handle. */
+struct smbdb_ctx;
+
+/* Share mode entry. */
+/*
+ We use 64 bit types for device and inode as
+ we don't know what size mode Samba has been
+ compiled in - dev/ino may be 32, may be 64
+ bits. This interface copes with either.
+*/
+
+struct smb_share_mode_entry {
+ uint64_t dev;
+ uint64_t ino;
+ uint32_t share_access;
+ uint32_t access_mask;
+ struct timeval open_time;
+ uint32_t file_id;
+ struct server_id pid;
+};
+
+/*
+ * open/close sharemode database.
+ */
+
+struct smbdb_ctx *smb_share_mode_db_open(const char *db_path);
+int smb_share_mode_db_close(struct smbdb_ctx *db_ctx);
+
+/*
+ * lock/unlock entry in sharemode database.
+ */
+
+int smb_lock_share_mode_entry(struct smbdb_ctx *db_ctx,
+ uint64_t dev,
+ uint64_t ino);
+
+int smb_unlock_share_mode_entry(struct smbdb_ctx *db_ctx,
+ uint64_t dev,
+ uint64_t ino);
+
+/*
+ * Share mode database accessor functions.
+ */
+
+int smb_get_share_mode_entries(struct smbdb_ctx *db_ctx,
+ uint64_t dev,
+ uint64_t ino,
+ struct smb_share_mode_entry **pp_list,
+ unsigned char *p_delete_on_close);
+
+int smb_create_share_mode_entry(struct smbdb_ctx *db_ctx,
+ uint64_t dev,
+ uint64_t ino,
+ const struct smb_share_mode_entry *set_entry,
+ const char *path);
+
+int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx,
+ uint64_t dev,
+ uint64_t ino,
+ const struct smb_share_mode_entry *set_entry);
+
+int smb_change_share_mode_entry(struct smbdb_ctx *db_ctx,
+ uint64_t dev,
+ uint64_t ino,
+ const struct smb_share_mode_entry *set_entry,
+ const struct smb_share_mode_entry *new_entry);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/source3/include/smbldap.h b/source3/include/smbldap.h
new file mode 100644
index 0000000000..a2cb8c5eea
--- /dev/null
+++ b/source3/include/smbldap.h
@@ -0,0 +1,234 @@
+/*
+ Unix SMB/CIFS mplementation.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Gerald Carter 2001-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _SMBLDAP_H
+#define _SMBLDAP_H
+
+struct smbldap_state;
+
+#ifdef HAVE_LDAP
+
+/* specify schema versions between 2.2. and 3.0 */
+
+#define SCHEMAVER_SAMBAACCOUNT 1
+#define SCHEMAVER_SAMBASAMACCOUNT 2
+
+/* objectclass names */
+
+#define LDAP_OBJ_SAMBASAMACCOUNT "sambaSamAccount"
+#define LDAP_OBJ_SAMBAACCOUNT "sambaAccount"
+#define LDAP_OBJ_GROUPMAP "sambaGroupMapping"
+#define LDAP_OBJ_DOMINFO "sambaDomain"
+#define LDAP_OBJ_IDPOOL "sambaUnixIdPool"
+#define LDAP_OBJ_IDMAP_ENTRY "sambaIdmapEntry"
+#define LDAP_OBJ_SID_ENTRY "sambaSidEntry"
+#define LDAP_OBJ_TRUST_PASSWORD "sambaTrustPassword"
+#define LDAP_OBJ_TRUSTDOM_PASSWORD "sambaTrustedDomainPassword"
+
+#define LDAP_OBJ_ACCOUNT "account"
+#define LDAP_OBJ_POSIXACCOUNT "posixAccount"
+#define LDAP_OBJ_POSIXGROUP "posixGroup"
+#define LDAP_OBJ_OU "organizationalUnit"
+
+/* some generic attributes that get reused a lot */
+
+#define LDAP_ATTRIBUTE_SID "sambaSID"
+#define LDAP_ATTRIBUTE_UIDNUMBER "uidNumber"
+#define LDAP_ATTRIBUTE_GIDNUMBER "gidNumber"
+#define LDAP_ATTRIBUTE_SID_LIST "sambaSIDList"
+
+/* attribute map table indexes */
+
+#define LDAP_ATTR_LIST_END 0
+#define LDAP_ATTR_UID 1
+#define LDAP_ATTR_UIDNUMBER 2
+#define LDAP_ATTR_GIDNUMBER 3
+#define LDAP_ATTR_UNIX_HOME 4
+#define LDAP_ATTR_PWD_LAST_SET 5
+#define LDAP_ATTR_PWD_CAN_CHANGE 6
+#define LDAP_ATTR_PWD_MUST_CHANGE 7
+#define LDAP_ATTR_LOGON_TIME 8
+#define LDAP_ATTR_LOGOFF_TIME 9
+#define LDAP_ATTR_KICKOFF_TIME 10
+#define LDAP_ATTR_CN 11
+#define LDAP_ATTR_DISPLAY_NAME 12
+#define LDAP_ATTR_HOME_PATH 13
+#define LDAP_ATTR_LOGON_SCRIPT 14
+#define LDAP_ATTR_PROFILE_PATH 15
+#define LDAP_ATTR_DESC 16
+#define LDAP_ATTR_USER_WKS 17
+#define LDAP_ATTR_USER_SID 18
+#define LDAP_ATTR_USER_RID 18
+#define LDAP_ATTR_PRIMARY_GROUP_SID 19
+#define LDAP_ATTR_PRIMARY_GROUP_RID 20
+#define LDAP_ATTR_LMPW 21
+#define LDAP_ATTR_NTPW 22
+#define LDAP_ATTR_DOMAIN 23
+#define LDAP_ATTR_OBJCLASS 24
+#define LDAP_ATTR_ACB_INFO 25
+#define LDAP_ATTR_NEXT_USERRID 26
+#define LDAP_ATTR_NEXT_GROUPRID 27
+#define LDAP_ATTR_DOM_SID 28
+#define LDAP_ATTR_HOME_DRIVE 29
+#define LDAP_ATTR_GROUP_SID 30
+#define LDAP_ATTR_GROUP_TYPE 31
+#define LDAP_ATTR_SID 32
+#define LDAP_ATTR_ALGORITHMIC_RID_BASE 33
+#define LDAP_ATTR_NEXT_RID 34
+#define LDAP_ATTR_BAD_PASSWORD_COUNT 35
+#define LDAP_ATTR_LOGON_COUNT 36
+#define LDAP_ATTR_MUNGED_DIAL 37
+#define LDAP_ATTR_BAD_PASSWORD_TIME 38
+#define LDAP_ATTR_PWD_HISTORY 39
+#define LDAP_ATTR_SID_LIST 40
+#define LDAP_ATTR_MOD_TIMESTAMP 41
+#define LDAP_ATTR_LOGON_HOURS 42
+#define LDAP_ATTR_TRUST_PASSWD_FLAGS 43
+#define LDAP_ATTR_SN 44
+
+
+typedef struct _attrib_map_entry {
+ int attrib;
+ const char *name;
+} ATTRIB_MAP_ENTRY;
+
+
+/* structures */
+
+extern ATTRIB_MAP_ENTRY attrib_map_v22[];
+extern ATTRIB_MAP_ENTRY attrib_map_to_delete_v22[];
+extern ATTRIB_MAP_ENTRY attrib_map_v30[];
+extern ATTRIB_MAP_ENTRY attrib_map_to_delete_v30[];
+extern ATTRIB_MAP_ENTRY dominfo_attr_list[];
+extern ATTRIB_MAP_ENTRY groupmap_attr_list[];
+extern ATTRIB_MAP_ENTRY groupmap_attr_list_to_delete[];
+extern ATTRIB_MAP_ENTRY idpool_attr_list[];
+extern ATTRIB_MAP_ENTRY sidmap_attr_list[];
+extern ATTRIB_MAP_ENTRY trustpw_attr_list[];
+
+
+/* Function declarations -- not included in proto.h so we don't
+ have to worry about LDAP structure types */
+
+NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx,
+ struct event_context *event_ctx,
+ const char *location,
+ struct smbldap_state **smbldap_state);
+
+const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key );
+const char** get_attr_list( TALLOC_CTX *mem_ctx, ATTRIB_MAP_ENTRY table[] );
+void smbldap_set_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value);
+void smbldap_make_mod(LDAP *ldap_struct, LDAPMessage *existing,
+ LDAPMod ***mods,
+ const char *attribute, const char *newval);
+bool smbldap_get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
+ const char *attribute, char *value,
+ int max_len);
+char *smbldap_get_dn(LDAP *ld, LDAPMessage *entry);
+int smbldap_modify(struct smbldap_state *ldap_state,
+ const char *dn,
+ LDAPMod *attrs[]);
+
+/**
+ * Struct to keep the state for all the ldap stuff
+ *
+ */
+
+struct smbldap_state {
+ LDAP *ldap_struct;
+ pid_t pid;
+ time_t last_ping;
+ /* retrive-once info */
+ const char *uri;
+
+ /* credentials */
+ bool anonymous;
+ char *bind_dn;
+ char *bind_secret;
+
+ bool paged_results;
+
+ unsigned int num_failures;
+
+ time_t last_use;
+ struct event_context *event_context;
+ struct timed_event *idle_event;
+
+ struct timeval last_rebind;
+};
+
+/* struct used by both pdb_ldap.c and pdb_nds.c */
+
+struct ldapsam_privates {
+ struct smbldap_state *smbldap_state;
+
+ /* Former statics */
+ LDAPMessage *result;
+ LDAPMessage *entry;
+ int index;
+
+ const char *domain_name;
+ DOM_SID domain_sid;
+
+ /* configuration items */
+ int schema_ver;
+
+ char *domain_dn;
+
+ /* Is this NDS ldap? */
+ int is_nds_ldap;
+
+ /* ldap server location parameter */
+ char *location;
+};
+
+/* Functions shared between pdb_ldap.c and pdb_nds.c. */
+NTSTATUS pdb_init_ldapsam_compat( struct pdb_methods **pdb_method, const char *location);
+void private_data_free_fn(void **result);
+int ldapsam_search_suffix_by_name(struct ldapsam_privates *ldap_state,
+ const char *user,
+ LDAPMessage ** result,
+ const char **attr);
+NTSTATUS pdb_init_ldapsam( struct pdb_methods **pdb_method, const char *location);
+const char** get_userattr_list( TALLOC_CTX *mem_ctx, int schema_ver );
+
+char * smbldap_talloc_single_attribute(LDAP *ldap_struct, LDAPMessage *entry,
+ const char *attribute,
+ TALLOC_CTX *mem_ctx);
+void talloc_autofree_ldapmsg(TALLOC_CTX *mem_ctx, LDAPMessage *result);
+void talloc_autofree_ldapmod(TALLOC_CTX *mem_ctx, LDAPMod **mod);
+const char *smbldap_talloc_dn(TALLOC_CTX *mem_ctx, LDAP *ld,
+ LDAPMessage *entry);
+
+
+#else
+#define LDAP void
+#define LDAPMod void
+#define LDAP_CONST const
+#define LDAPControl void
+struct berval;
+struct ldapsam_privates;
+#endif /* HAVE_LDAP */
+
+#define LDAP_DEFAULT_TIMEOUT 15
+#define LDAP_CONNECTION_DEFAULT_TIMEOUT 2
+#define LDAP_PAGE_SIZE 1024
+
+#endif /* _SMBLDAP_H */
diff --git a/source3/include/smbprofile.h b/source3/include/smbprofile.h
new file mode 100644
index 0000000000..f58a6452bf
--- /dev/null
+++ b/source3/include/smbprofile.h
@@ -0,0 +1,866 @@
+#ifndef _PROFILE_H_
+#define _PROFILE_H_
+/*
+ Unix SMB/CIFS implementation.
+ store smbd profiling information in shared memory
+ Copyright (C) Andrew Tridgell 1999
+ Copyright (C) James Peach 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/* this file defines the profile structure in the profile shared
+ memory area */
+
+#define PROF_SHMEM_KEY ((key_t)0x07021999)
+#define PROF_SHM_MAGIC 0x6349985
+#define PROF_SHM_VERSION 11
+
+/* time values in the following structure are in microseconds */
+
+#define __profile_stats_value(which, domain) domain[which]
+
+enum profile_stats_values
+{
+ PR_VALUE_SMBD_IDLE = 0,
+#define smbd_idle_count __profile_stats_value(PR_VALUE_SMBD_IDLE, count)
+#define smbd_idle_time __profile_stats_value(PR_VALUE_SMBD_IDLE, time)
+
+/* system call counters */
+ PR_VALUE_SYSCALL_OPENDIR,
+#define syscall_opendir_count __profile_stats_value(PR_VALUE_SYSCALL_OPENDIR, count)
+#define syscall_opendir_time __profile_stats_value(PR_VALUE_SYSCALL_OPENDIR, time)
+
+ PR_VALUE_SYSCALL_READDIR,
+#define syscall_readdir_count __profile_stats_value(PR_VALUE_SYSCALL_READDIR, count)
+#define syscall_readdir_time __profile_stats_value(PR_VALUE_SYSCALL_READDIR, time)
+
+ PR_VALUE_SYSCALL_SEEKDIR,
+#define syscall_seekdir_count __profile_stats_value(PR_VALUE_SYSCALL_SEEKDIR, count)
+#define syscall_seekdir_time __profile_stats_value(PR_VALUE_SYSCALL_SEEKDIR, time)
+
+ PR_VALUE_SYSCALL_TELLDIR,
+#define syscall_telldir_count __profile_stats_value(PR_VALUE_SYSCALL_TELLDIR, count)
+#define syscall_telldir_time __profile_stats_value(PR_VALUE_SYSCALL_TELLDIR, time)
+
+ PR_VALUE_SYSCALL_REWINDDIR,
+#define syscall_rewinddir_count __profile_stats_value(PR_VALUE_SYSCALL_REWINDDIR, count)
+#define syscall_rewinddir_time __profile_stats_value(PR_VALUE_SYSCALL_REWINDDIR, time)
+
+ PR_VALUE_SYSCALL_MKDIR,
+#define syscall_mkdir_count __profile_stats_value(PR_VALUE_SYSCALL_MKDIR, count)
+#define syscall_mkdir_time __profile_stats_value(PR_VALUE_SYSCALL_MKDIR, time)
+
+ PR_VALUE_SYSCALL_RMDIR,
+#define syscall_rmdir_count __profile_stats_value(PR_VALUE_SYSCALL_RMDIR, count)
+#define syscall_rmdir_time __profile_stats_value(PR_VALUE_SYSCALL_RMDIR, time)
+
+ PR_VALUE_SYSCALL_CLOSEDIR,
+#define syscall_closedir_count __profile_stats_value(PR_VALUE_SYSCALL_CLOSEDIR, count)
+#define syscall_closedir_time __profile_stats_value(PR_VALUE_SYSCALL_CLOSEDIR, time)
+
+ PR_VALUE_SYSCALL_OPEN,
+#define syscall_open_count __profile_stats_value(PR_VALUE_SYSCALL_OPEN, count)
+#define syscall_open_time __profile_stats_value(PR_VALUE_SYSCALL_OPEN, time)
+
+ PR_VALUE_SYSCALL_CLOSE,
+#define syscall_close_count __profile_stats_value(PR_VALUE_SYSCALL_CLOSE, count)
+#define syscall_close_time __profile_stats_value(PR_VALUE_SYSCALL_CLOSE, time)
+
+ PR_VALUE_SYSCALL_READ,
+#define syscall_read_count __profile_stats_value(PR_VALUE_SYSCALL_READ, count)
+#define syscall_read_time __profile_stats_value(PR_VALUE_SYSCALL_READ, time)
+
+ PR_VALUE_SYSCALL_PREAD,
+#define syscall_pread_count __profile_stats_value(PR_VALUE_SYSCALL_PREAD, count)
+#define syscall_pread_time __profile_stats_value(PR_VALUE_SYSCALL_PREAD, time)
+
+ PR_VALUE_SYSCALL_WRITE,
+#define syscall_write_count __profile_stats_value(PR_VALUE_SYSCALL_WRITE, count)
+#define syscall_write_time __profile_stats_value(PR_VALUE_SYSCALL_WRITE, time)
+
+ PR_VALUE_SYSCALL_PWRITE,
+#define syscall_pwrite_count __profile_stats_value(PR_VALUE_SYSCALL_PWRITE, count)
+#define syscall_pwrite_time __profile_stats_value(PR_VALUE_SYSCALL_PWRITE, time)
+
+ PR_VALUE_SYSCALL_LSEEK,
+#define syscall_lseek_count __profile_stats_value(PR_VALUE_SYSCALL_LSEEK, count)
+#define syscall_lseek_time __profile_stats_value(PR_VALUE_SYSCALL_LSEEK, time)
+
+ PR_VALUE_SYSCALL_SENDFILE,
+#define syscall_sendfile_count __profile_stats_value(PR_VALUE_SYSCALL_SENDFILE, count)
+#define syscall_sendfile_time __profile_stats_value(PR_VALUE_SYSCALL_SENDFILE, time)
+
+ PR_VALUE_SYSCALL_RECVFILE,
+#define syscall_recvfile_count __profile_stats_value(PR_VALUE_SYSCALL_RECVFILE, count)
+#define syscall_recvfile_time __profile_stats_value(PR_VALUE_SYSCALL_RECVFILE, time)
+
+ PR_VALUE_SYSCALL_RENAME,
+#define syscall_rename_count __profile_stats_value(PR_VALUE_SYSCALL_RENAME, count)
+#define syscall_rename_time __profile_stats_value(PR_VALUE_SYSCALL_RENAME, time)
+
+ PR_VALUE_SYSCALL_FSYNC,
+#define syscall_fsync_count __profile_stats_value(PR_VALUE_SYSCALL_FSYNC, count)
+#define syscall_fsync_time __profile_stats_value(PR_VALUE_SYSCALL_FSYNC, time)
+
+ PR_VALUE_SYSCALL_STAT,
+#define syscall_stat_count __profile_stats_value(PR_VALUE_SYSCALL_STAT, count)
+#define syscall_stat_time __profile_stats_value(PR_VALUE_SYSCALL_STAT, time)
+
+ PR_VALUE_SYSCALL_FSTAT,
+#define syscall_fstat_count __profile_stats_value(PR_VALUE_SYSCALL_FSTAT, count)
+#define syscall_fstat_time __profile_stats_value(PR_VALUE_SYSCALL_FSTAT, time)
+
+ PR_VALUE_SYSCALL_LSTAT,
+#define syscall_lstat_count __profile_stats_value(PR_VALUE_SYSCALL_LSTAT, count)
+#define syscall_lstat_time __profile_stats_value(PR_VALUE_SYSCALL_LSTAT, time)
+
+ PR_VALUE_SYSCALL_UNLINK,
+#define syscall_unlink_count __profile_stats_value(PR_VALUE_SYSCALL_UNLINK, count)
+#define syscall_unlink_time __profile_stats_value(PR_VALUE_SYSCALL_UNLINK, time)
+
+ PR_VALUE_SYSCALL_CHMOD,
+#define syscall_chmod_count __profile_stats_value(PR_VALUE_SYSCALL_CHMOD, count)
+#define syscall_chmod_time __profile_stats_value(PR_VALUE_SYSCALL_CHMOD, time)
+
+ PR_VALUE_SYSCALL_FCHMOD,
+#define syscall_fchmod_count __profile_stats_value(PR_VALUE_SYSCALL_FCHMOD, count)
+#define syscall_fchmod_time __profile_stats_value(PR_VALUE_SYSCALL_FCHMOD, time)
+
+ PR_VALUE_SYSCALL_CHOWN,
+#define syscall_chown_count __profile_stats_value(PR_VALUE_SYSCALL_CHOWN, count)
+#define syscall_chown_time __profile_stats_value(PR_VALUE_SYSCALL_CHOWN, time)
+
+ PR_VALUE_SYSCALL_FCHOWN,
+#define syscall_fchown_count __profile_stats_value(PR_VALUE_SYSCALL_FCHOWN, count)
+#define syscall_fchown_time __profile_stats_value(PR_VALUE_SYSCALL_FCHOWN, time)
+
+ PR_VALUE_SYSCALL_LCHOWN,
+#define syscall_lchown_count __profile_stats_value(PR_VALUE_SYSCALL_LCHOWN, count)
+#define syscall_lchown_time __profile_stats_value(PR_VALUE_SYSCALL_LCHOWN, time)
+
+ PR_VALUE_SYSCALL_CHDIR,
+#define syscall_chdir_count __profile_stats_value(PR_VALUE_SYSCALL_CHDIR, count)
+#define syscall_chdir_time __profile_stats_value(PR_VALUE_SYSCALL_CHDIR, time)
+
+ PR_VALUE_SYSCALL_GETWD,
+#define syscall_getwd_count __profile_stats_value(PR_VALUE_SYSCALL_GETWD, count)
+#define syscall_getwd_time __profile_stats_value(PR_VALUE_SYSCALL_GETWD, time)
+
+ PR_VALUE_SYSCALL_NTIMES,
+#define syscall_ntimes_count __profile_stats_value(PR_VALUE_SYSCALL_NTIMES, count)
+#define syscall_ntimes_time __profile_stats_value(PR_VALUE_SYSCALL_NTIMES, time)
+
+ PR_VALUE_SYSCALL_FTRUNCATE,
+#define syscall_ftruncate_count __profile_stats_value(PR_VALUE_SYSCALL_FTRUNCATE, count)
+#define syscall_ftruncate_time __profile_stats_value(PR_VALUE_SYSCALL_FTRUNCATE, time)
+
+ PR_VALUE_SYSCALL_FCNTL_LOCK,
+#define syscall_fcntl_lock_count __profile_stats_value(PR_VALUE_SYSCALL_FCNTL_LOCK, count)
+#define syscall_fcntl_lock_time __profile_stats_value(PR_VALUE_SYSCALL_FCNTL_LOCK, time)
+
+ PR_VALUE_SYSCALL_KERNEL_FLOCK,
+#define syscall_kernel_flock_count __profile_stats_value(PR_VALUE_SYSCALL_KERNEL_FLOCK, count)
+#define syscall_kernel_flock_time __profile_stats_value(PR_VALUE_SYSCALL_KERNEL_FLOCK, time)
+
+ PR_VALUE_SYSCALL_LINUX_SETLEASE,
+#define syscall_linux_setlease_count __profile_stats_value(PR_VALUE_SYSCALL_LINUX_SETLEASE, count)
+#define syscall_linux_setlease_time __profile_stats_value(PR_VALUE_SYSCALL_LINUX_SETLEASE, time)
+
+ PR_VALUE_SYSCALL_FCNTL_GETLOCK,
+#define syscall_fcntl_getlock_count __profile_stats_value(PR_VALUE_SYSCALL_FCNTL_GETLOCK, count)
+#define syscall_fcntl_getlock_time __profile_stats_value(PR_VALUE_SYSCALL_FCNTL_GETLOCK, time)
+
+ PR_VALUE_SYSCALL_READLINK,
+#define syscall_readlink_count __profile_stats_value(PR_VALUE_SYSCALL_READLINK, count)
+#define syscall_readlink_time __profile_stats_value(PR_VALUE_SYSCALL_READLINK, time)
+
+ PR_VALUE_SYSCALL_SYMLINK,
+#define syscall_symlink_count __profile_stats_value(PR_VALUE_SYSCALL_SYMLINK, count)
+#define syscall_symlink_time __profile_stats_value(PR_VALUE_SYSCALL_SYMLINK, time)
+
+ PR_VALUE_SYSCALL_LINK,
+#define syscall_link_count __profile_stats_value(PR_VALUE_SYSCALL_LINK, count)
+#define syscall_link_time __profile_stats_value(PR_VALUE_SYSCALL_LINK, time)
+
+ PR_VALUE_SYSCALL_MKNOD,
+#define syscall_mknod_count __profile_stats_value(PR_VALUE_SYSCALL_MKNOD, count)
+#define syscall_mknod_time __profile_stats_value(PR_VALUE_SYSCALL_MKNOD, time)
+
+ PR_VALUE_SYSCALL_REALPATH,
+#define syscall_realpath_count __profile_stats_value(PR_VALUE_SYSCALL_REALPATH, count)
+#define syscall_realpath_time __profile_stats_value(PR_VALUE_SYSCALL_REALPATH, time)
+
+ PR_VALUE_SYSCALL_GET_QUOTA,
+#define syscall_get_quota_count __profile_stats_value(PR_VALUE_SYSCALL_GET_QUOTA, count)
+#define syscall_get_quota_time __profile_stats_value(PR_VALUE_SYSCALL_GET_QUOTA, time)
+
+ PR_VALUE_SYSCALL_SET_QUOTA,
+#define syscall_set_quota_count __profile_stats_value(PR_VALUE_SYSCALL_SET_QUOTA, count)
+#define syscall_set_quota_time __profile_stats_value(PR_VALUE_SYSCALL_SET_QUOTA, time)
+
+/* counters for individual SMB types */
+ PR_VALUE_SMBMKDIR,
+#define SMBmkdir_count __profile_stats_value(PR_VALUE_SMBMKDIR, count)
+#define SMBmkdir_time __profile_stats_value(PR_VALUE_SMBMKDIR, time)
+
+ PR_VALUE_SMBRMDIR,
+#define SMBrmdir_count __profile_stats_value(PR_VALUE_SMBRMDIR, count)
+#define SMBrmdir_time __profile_stats_value(PR_VALUE_SMBRMDIR, time)
+
+ PR_VALUE_SMBOPEN,
+#define SMBopen_count __profile_stats_value(PR_VALUE_SMBOPEN, count)
+#define SMBopen_time __profile_stats_value(PR_VALUE_SMBOPEN, time)
+
+ PR_VALUE_SMBCREATE,
+#define SMBcreate_count __profile_stats_value(PR_VALUE_SMBCREATE, count)
+#define SMBcreate_time __profile_stats_value(PR_VALUE_SMBCREATE, time)
+
+ PR_VALUE_SMBCLOSE,
+#define SMBclose_count __profile_stats_value(PR_VALUE_SMBCLOSE, count)
+#define SMBclose_time __profile_stats_value(PR_VALUE_SMBCLOSE, time)
+
+ PR_VALUE_SMBFLUSH,
+#define SMBflush_count __profile_stats_value(PR_VALUE_SMBFLUSH, count)
+#define SMBflush_time __profile_stats_value(PR_VALUE_SMBFLUSH, time)
+
+ PR_VALUE_SMBUNLINK,
+#define SMBunlink_count __profile_stats_value(PR_VALUE_SMBUNLINK, count)
+#define SMBunlink_time __profile_stats_value(PR_VALUE_SMBUNLINK, time)
+
+ PR_VALUE_SMBMV,
+#define SMBmv_count __profile_stats_value(PR_VALUE_SMBMV, count)
+#define SMBmv_time __profile_stats_value(PR_VALUE_SMBMV, time)
+
+ PR_VALUE_SMBGETATR,
+#define SMBgetatr_count __profile_stats_value(PR_VALUE_SMBGETATR, count)
+#define SMBgetatr_time __profile_stats_value(PR_VALUE_SMBGETATR, time)
+
+ PR_VALUE_SMBSETATR,
+#define SMBsetatr_count __profile_stats_value(PR_VALUE_SMBSETATR, count)
+#define SMBsetatr_time __profile_stats_value(PR_VALUE_SMBSETATR, time)
+
+ PR_VALUE_SMBREAD,
+#define SMBread_count __profile_stats_value(PR_VALUE_SMBREAD, count)
+#define SMBread_time __profile_stats_value(PR_VALUE_SMBREAD, time)
+
+ PR_VALUE_SMBWRITE,
+#define SMBwrite_count __profile_stats_value(PR_VALUE_SMBWRITE, count)
+#define SMBwrite_time __profile_stats_value(PR_VALUE_SMBWRITE, time)
+
+ PR_VALUE_SMBLOCK,
+#define SMBlock_count __profile_stats_value(PR_VALUE_SMBLOCK, count)
+#define SMBlock_time __profile_stats_value(PR_VALUE_SMBLOCK, time)
+
+ PR_VALUE_SMBUNLOCK,
+#define SMBunlock_count __profile_stats_value(PR_VALUE_SMBUNLOCK, count)
+#define SMBunlock_time __profile_stats_value(PR_VALUE_SMBUNLOCK, time)
+
+ PR_VALUE_SMBCTEMP,
+#define SMBctemp_count __profile_stats_value(PR_VALUE_SMBCTEMP, count)
+#define SMBctemp_time __profile_stats_value(PR_VALUE_SMBCTEMP, time)
+
+ /* SMBmknew stats are currently combined with SMBcreate */
+ PR_VALUE_SMBMKNEW,
+#define SMBmknew_count __profile_stats_value(PR_VALUE_SMBMKNEW, count)
+#define SMBmknew_time __profile_stats_value(PR_VALUE_SMBMKNEW, time)
+
+ PR_VALUE_SMBCHECKPATH,
+#define SMBcheckpath_count __profile_stats_value(PR_VALUE_SMBCHECKPATH, count)
+#define SMBcheckpath_time __profile_stats_value(PR_VALUE_SMBCHECKPATH, time)
+
+ PR_VALUE_SMBEXIT,
+#define SMBexit_count __profile_stats_value(PR_VALUE_SMBEXIT, count)
+#define SMBexit_time __profile_stats_value(PR_VALUE_SMBEXIT, time)
+
+ PR_VALUE_SMBLSEEK,
+#define SMBlseek_count __profile_stats_value(PR_VALUE_SMBLSEEK, count)
+#define SMBlseek_time __profile_stats_value(PR_VALUE_SMBLSEEK, time)
+
+ PR_VALUE_SMBLOCKREAD,
+#define SMBlockread_count __profile_stats_value(PR_VALUE_SMBLOCKREAD, count)
+#define SMBlockread_time __profile_stats_value(PR_VALUE_SMBLOCKREAD, time)
+
+ PR_VALUE_SMBWRITEUNLOCK,
+#define SMBwriteunlock_count __profile_stats_value(PR_VALUE_SMBWRITEUNLOCK, count)
+#define SMBwriteunlock_time __profile_stats_value(PR_VALUE_SMBWRITEUNLOCK, time)
+
+ PR_VALUE_SMBREADBRAW,
+#define SMBreadbraw_count __profile_stats_value(PR_VALUE_SMBREADBRAW, count)
+#define SMBreadbraw_time __profile_stats_value(PR_VALUE_SMBREADBRAW, time)
+
+ PR_VALUE_SMBREADBMPX,
+#define SMBreadBmpx_count __profile_stats_value(PR_VALUE_SMBREADBMPX, count)
+#define SMBreadBmpx_time __profile_stats_value(PR_VALUE_SMBREADBMPX, time)
+
+ PR_VALUE_SMBREADBS,
+#define SMBreadBs_count __profile_stats_value(PR_VALUE_SMBREADBS, count)
+#define SMBreadBs_time __profile_stats_value(PR_VALUE_SMBREADBS, time)
+
+ PR_VALUE_SMBWRITEBRAW,
+#define SMBwritebraw_count __profile_stats_value(PR_VALUE_SMBWRITEBRAW, count)
+#define SMBwritebraw_time __profile_stats_value(PR_VALUE_SMBWRITEBRAW, time)
+
+ PR_VALUE_SMBWRITEBMPX,
+#define SMBwriteBmpx_count __profile_stats_value(PR_VALUE_SMBWRITEBMPX, count)
+#define SMBwriteBmpx_time __profile_stats_value(PR_VALUE_SMBWRITEBMPX, time)
+
+ PR_VALUE_SMBWRITEBS,
+#define SMBwriteBs_count __profile_stats_value(PR_VALUE_SMBWRITEBS, count)
+#define SMBwriteBs_time __profile_stats_value(PR_VALUE_SMBWRITEBS, time)
+
+ PR_VALUE_SMBWRITEC,
+#define SMBwritec_count __profile_stats_value(PR_VALUE_SMBWRITEC, count)
+#define SMBwritec_time __profile_stats_value(PR_VALUE_SMBWRITEC, time)
+
+ PR_VALUE_SMBSETATTRE,
+#define SMBsetattrE_count __profile_stats_value(PR_VALUE_SMBSETATTRE, count)
+#define SMBsetattrE_time __profile_stats_value(PR_VALUE_SMBSETATTRE, time)
+
+ PR_VALUE_SMBGETATTRE,
+#define SMBgetattrE_count __profile_stats_value(PR_VALUE_SMBGETATTRE, count)
+#define SMBgetattrE_time __profile_stats_value(PR_VALUE_SMBGETATTRE, time)
+
+ PR_VALUE_SMBLOCKINGX,
+#define SMBlockingX_count __profile_stats_value(PR_VALUE_SMBLOCKINGX, count)
+#define SMBlockingX_time __profile_stats_value(PR_VALUE_SMBLOCKINGX, time)
+
+ PR_VALUE_SMBTRANS,
+#define SMBtrans_count __profile_stats_value(PR_VALUE_SMBTRANS, count)
+#define SMBtrans_time __profile_stats_value(PR_VALUE_SMBTRANS, time)
+
+ PR_VALUE_SMBTRANSS,
+#define SMBtranss_count __profile_stats_value(PR_VALUE_SMBTRANSS, count)
+#define SMBtranss_time __profile_stats_value(PR_VALUE_SMBTRANSS, time)
+
+ PR_VALUE_SMBIOCTL,
+#define SMBioctl_count __profile_stats_value(PR_VALUE_SMBIOCTL, count)
+#define SMBioctl_time __profile_stats_value(PR_VALUE_SMBIOCTL, time)
+
+ PR_VALUE_SMBIOCTLS,
+#define SMBioctls_count __profile_stats_value(PR_VALUE_SMBIOCTLS, count)
+#define SMBioctls_time __profile_stats_value(PR_VALUE_SMBIOCTLS, time)
+
+ PR_VALUE_SMBCOPY,
+#define SMBcopy_count __profile_stats_value(PR_VALUE_SMBCOPY, count)
+#define SMBcopy_time __profile_stats_value(PR_VALUE_SMBCOPY, time)
+
+ PR_VALUE_SMBMOVE,
+#define SMBmove_count __profile_stats_value(PR_VALUE_SMBMOVE, count)
+#define SMBmove_time __profile_stats_value(PR_VALUE_SMBMOVE, time)
+
+ PR_VALUE_SMBECHO,
+#define SMBecho_count __profile_stats_value(PR_VALUE_SMBECHO, count)
+#define SMBecho_time __profile_stats_value(PR_VALUE_SMBECHO, time)
+
+ PR_VALUE_SMBWRITECLOSE,
+#define SMBwriteclose_count __profile_stats_value(PR_VALUE_SMBWRITECLOSE, count)
+#define SMBwriteclose_time __profile_stats_value(PR_VALUE_SMBWRITECLOSE, time)
+
+ PR_VALUE_SMBOPENX,
+#define SMBopenX_count __profile_stats_value(PR_VALUE_SMBOPENX, count)
+#define SMBopenX_time __profile_stats_value(PR_VALUE_SMBOPENX, time)
+
+ PR_VALUE_SMBREADX,
+#define SMBreadX_count __profile_stats_value(PR_VALUE_SMBREADX, count)
+#define SMBreadX_time __profile_stats_value(PR_VALUE_SMBREADX, time)
+
+ PR_VALUE_SMBWRITEX,
+#define SMBwriteX_count __profile_stats_value(PR_VALUE_SMBWRITEX, count)
+#define SMBwriteX_time __profile_stats_value(PR_VALUE_SMBWRITEX, time)
+
+ PR_VALUE_SMBTRANS2,
+#define SMBtrans2_count __profile_stats_value(PR_VALUE_SMBTRANS2, count)
+#define SMBtrans2_time __profile_stats_value(PR_VALUE_SMBTRANS2, time)
+
+ PR_VALUE_SMBTRANSS2,
+#define SMBtranss2_count __profile_stats_value(PR_VALUE_SMBTRANSS2, count)
+#define SMBtranss2_time __profile_stats_value(PR_VALUE_SMBTRANSS2, time)
+
+ PR_VALUE_SMBFINDCLOSE,
+#define SMBfindclose_count __profile_stats_value(PR_VALUE_SMBFINDCLOSE, count)
+#define SMBfindclose_time __profile_stats_value(PR_VALUE_SMBFINDCLOSE, time)
+
+ PR_VALUE_SMBFINDNCLOSE,
+#define SMBfindnclose_count __profile_stats_value(PR_VALUE_SMBFINDNCLOSE, count)
+#define SMBfindnclose_time __profile_stats_value(PR_VALUE_SMBFINDNCLOSE, time)
+
+ PR_VALUE_SMBTCON,
+#define SMBtcon_count __profile_stats_value(PR_VALUE_SMBTCON, count)
+#define SMBtcon_time __profile_stats_value(PR_VALUE_SMBTCON, time)
+
+ PR_VALUE_SMBTDIS,
+#define SMBtdis_count __profile_stats_value(PR_VALUE_SMBTDIS, count)
+#define SMBtdis_time __profile_stats_value(PR_VALUE_SMBTDIS, time)
+
+ PR_VALUE_SMBNEGPROT,
+#define SMBnegprot_count __profile_stats_value(PR_VALUE_SMBNEGPROT, count)
+#define SMBnegprot_time __profile_stats_value(PR_VALUE_SMBNEGPROT, time)
+
+ PR_VALUE_SMBSESSSETUPX,
+#define SMBsesssetupX_count __profile_stats_value(PR_VALUE_SMBSESSSETUPX, count)
+#define SMBsesssetupX_time __profile_stats_value(PR_VALUE_SMBSESSSETUPX, time)
+
+ PR_VALUE_SMBULOGOFFX,
+#define SMBulogoffX_count __profile_stats_value(PR_VALUE_SMBULOGOFFX, count)
+#define SMBulogoffX_time __profile_stats_value(PR_VALUE_SMBULOGOFFX, time)
+
+ PR_VALUE_SMBTCONX,
+#define SMBtconX_count __profile_stats_value(PR_VALUE_SMBTCONX, count)
+#define SMBtconX_time __profile_stats_value(PR_VALUE_SMBTCONX, time)
+
+ PR_VALUE_SMBDSKATTR,
+#define SMBdskattr_count __profile_stats_value(PR_VALUE_SMBDSKATTR, count)
+#define SMBdskattr_time __profile_stats_value(PR_VALUE_SMBDSKATTR, time)
+
+ PR_VALUE_SMBSEARCH,
+#define SMBsearch_count __profile_stats_value(PR_VALUE_SMBSEARCH, count)
+#define SMBsearch_time __profile_stats_value(PR_VALUE_SMBSEARCH, time)
+
+ /* SBMffirst stats combined with SMBsearch */
+ PR_VALUE_SMBFFIRST,
+#define SMBffirst_count __profile_stats_value(PR_VALUE_SMBFFIRST, count)
+#define SMBffirst_time __profile_stats_value(PR_VALUE_SMBFFIRST, time)
+
+ /* SBMfunique stats combined with SMBsearch */
+ PR_VALUE_SMBFUNIQUE,
+#define SMBfunique_count __profile_stats_value(PR_VALUE_SMBFUNIQUE, count)
+#define SMBfunique_time __profile_stats_value(PR_VALUE_SMBFUNIQUE, time)
+
+ PR_VALUE_SMBFCLOSE,
+#define SMBfclose_count __profile_stats_value(PR_VALUE_SMBFCLOSE, count)
+#define SMBfclose_time __profile_stats_value(PR_VALUE_SMBFCLOSE, time)
+
+ PR_VALUE_SMBNTTRANS,
+#define SMBnttrans_count __profile_stats_value(PR_VALUE_SMBNTTRANS, count)
+#define SMBnttrans_time __profile_stats_value(PR_VALUE_SMBNTTRANS, time)
+
+ PR_VALUE_SMBNTTRANSS,
+#define SMBnttranss_count __profile_stats_value(PR_VALUE_SMBNTTRANSS, count)
+#define SMBnttranss_time __profile_stats_value(PR_VALUE_SMBNTTRANSS, time)
+
+ PR_VALUE_SMBNTCREATEX,
+#define SMBntcreateX_count __profile_stats_value(PR_VALUE_SMBNTCREATEX, count)
+#define SMBntcreateX_time __profile_stats_value(PR_VALUE_SMBNTCREATEX, time)
+
+ PR_VALUE_SMBNTCANCEL,
+#define SMBntcancel_count __profile_stats_value(PR_VALUE_SMBNTCANCEL, count)
+#define SMBntcancel_time __profile_stats_value(PR_VALUE_SMBNTCANCEL, time)
+
+ PR_VALUE_SMBNTRENAME,
+#define SMBntrename_count __profile_stats_value(PR_VALUE_SMBNTRENAME, count)
+#define SMBntrename_time __profile_stats_value(PR_VALUE_SMBNTRENAME, time)
+
+ PR_VALUE_SMBSPLOPEN,
+#define SMBsplopen_count __profile_stats_value(PR_VALUE_SMBSPLOPEN, count)
+#define SMBsplopen_time __profile_stats_value(PR_VALUE_SMBSPLOPEN, time)
+
+ PR_VALUE_SMBSPLWR,
+#define SMBsplwr_count __profile_stats_value(PR_VALUE_SMBSPLWR, count)
+#define SMBsplwr_time __profile_stats_value(PR_VALUE_SMBSPLWR, time)
+
+ PR_VALUE_SMBSPLCLOSE,
+#define SMBsplclose_count __profile_stats_value(PR_VALUE_SMBSPLCLOSE, count)
+#define SMBsplclose_time __profile_stats_value(PR_VALUE_SMBSPLCLOSE, time)
+
+ PR_VALUE_SMBSPLRETQ,
+#define SMBsplretq_count __profile_stats_value(PR_VALUE_SMBSPLRETQ, count)
+#define SMBsplretq_time __profile_stats_value(PR_VALUE_SMBSPLRETQ, time)
+
+ PR_VALUE_SMBSENDS,
+#define SMBsends_count __profile_stats_value(PR_VALUE_SMBSENDS, count)
+#define SMBsends_time __profile_stats_value(PR_VALUE_SMBSENDS, time)
+
+ PR_VALUE_SMBSENDB,
+#define SMBsendb_count __profile_stats_value(PR_VALUE_SMBSENDB, count)
+#define SMBsendb_time __profile_stats_value(PR_VALUE_SMBSENDB, time)
+
+ PR_VALUE_SMBFWDNAME,
+#define SMBfwdname_count __profile_stats_value(PR_VALUE_SMBFWDNAME, count)
+#define SMBfwdname_time __profile_stats_value(PR_VALUE_SMBFWDNAME, time)
+
+ PR_VALUE_SMBCANCELF,
+#define SMBcancelf_count __profile_stats_value(PR_VALUE_SMBCANCELF, count)
+#define SMBcancelf_time __profile_stats_value(PR_VALUE_SMBCANCELF, time)
+
+ PR_VALUE_SMBGETMAC,
+#define SMBgetmac_count __profile_stats_value(PR_VALUE_SMBGETMAC, count)
+#define SMBgetmac_time __profile_stats_value(PR_VALUE_SMBGETMAC, time)
+
+ PR_VALUE_SMBSENDSTRT,
+#define SMBsendstrt_count __profile_stats_value(PR_VALUE_SMBSENDSTRT, count)
+#define SMBsendstrt_time __profile_stats_value(PR_VALUE_SMBSENDSTRT, time)
+
+ PR_VALUE_SMBSENDEND,
+#define SMBsendend_count __profile_stats_value(PR_VALUE_SMBSENDEND, count)
+#define SMBsendend_time __profile_stats_value(PR_VALUE_SMBSENDEND, time)
+
+ PR_VALUE_SMBSENDTXT,
+#define SMBsendtxt_count __profile_stats_value(PR_VALUE_SMBSENDTXT, count)
+#define SMBsendtxt_time __profile_stats_value(PR_VALUE_SMBSENDTXT, time)
+
+ PR_VALUE_SMBINVALID,
+#define SMBinvalid_count __profile_stats_value(PR_VALUE_SMBINVALID, count)
+#define SMBinvalid_time __profile_stats_value(PR_VALUE_SMBINVALID, time)
+
+/* Pathworks setdir command */
+ PR_VALUE_PATHWORKS_SETDIR,
+#define pathworks_setdir_count __profile_stats_value(PR_VALUE_PATHWORKS_SETDIR, count)
+#define pathworks_setdir_time __profile_stats_value(PR_VALUE_PATHWORKS_SETDIR, time)
+
+/* These are the TRANS2 sub commands */
+ PR_VALUE_TRANS2_OPEN,
+#define Trans2_open_count __profile_stats_value(PR_VALUE_TRANS2_OPEN, count)
+#define Trans2_open_time __profile_stats_value(PR_VALUE_TRANS2_OPEN, time)
+
+ PR_VALUE_TRANS2_FINDFIRST,
+#define Trans2_findfirst_count __profile_stats_value(PR_VALUE_TRANS2_FINDFIRST, count)
+#define Trans2_findfirst_time __profile_stats_value(PR_VALUE_TRANS2_FINDFIRST, time)
+
+ PR_VALUE_TRANS2_FINDNEXT,
+#define Trans2_findnext_count __profile_stats_value(PR_VALUE_TRANS2_FINDNEXT, count)
+#define Trans2_findnext_time __profile_stats_value(PR_VALUE_TRANS2_FINDNEXT, time)
+
+ PR_VALUE_TRANS2_QFSINFO,
+#define Trans2_qfsinfo_count __profile_stats_value(PR_VALUE_TRANS2_QFSINFO, count)
+#define Trans2_qfsinfo_time __profile_stats_value(PR_VALUE_TRANS2_QFSINFO, time)
+
+ PR_VALUE_TRANS2_SETFSINFO,
+#define Trans2_setfsinfo_count __profile_stats_value(PR_VALUE_TRANS2_SETFSINFO, count)
+#define Trans2_setfsinfo_time __profile_stats_value(PR_VALUE_TRANS2_SETFSINFO, time)
+
+ PR_VALUE_TRANS2_QPATHINFO,
+#define Trans2_qpathinfo_count __profile_stats_value(PR_VALUE_TRANS2_QPATHINFO, count)
+#define Trans2_qpathinfo_time __profile_stats_value(PR_VALUE_TRANS2_QPATHINFO, time)
+
+ PR_VALUE_TRANS2_SETPATHINFO,
+#define Trans2_setpathinfo_count __profile_stats_value(PR_VALUE_TRANS2_SETPATHINFO, count)
+#define Trans2_setpathinfo_time __profile_stats_value(PR_VALUE_TRANS2_SETPATHINFO, time)
+
+ PR_VALUE_TRANS2_QFILEINFO,
+#define Trans2_qfileinfo_count __profile_stats_value(PR_VALUE_TRANS2_QFILEINFO, count)
+#define Trans2_qfileinfo_time __profile_stats_value(PR_VALUE_TRANS2_QFILEINFO, time)
+
+ PR_VALUE_TRANS2_SETFILEINFO,
+#define Trans2_setfileinfo_count __profile_stats_value(PR_VALUE_TRANS2_SETFILEINFO, count)
+#define Trans2_setfileinfo_time __profile_stats_value(PR_VALUE_TRANS2_SETFILEINFO, time)
+
+ PR_VALUE_TRANS2_FSCTL,
+#define Trans2_fsctl_count __profile_stats_value(PR_VALUE_TRANS2_FSCTL, count)
+#define Trans2_fsctl_time __profile_stats_value(PR_VALUE_TRANS2_FSCTL, time)
+
+ PR_VALUE_TRANS2_IOCTL,
+#define Trans2_ioctl_count __profile_stats_value(PR_VALUE_TRANS2_IOCTL, count)
+#define Trans2_ioctl_time __profile_stats_value(PR_VALUE_TRANS2_IOCTL, time)
+
+ PR_VALUE_TRANS2_FINDNOTIFYFIRST,
+#define Trans2_findnotifyfirst_count __profile_stats_value(PR_VALUE_TRANS2_FINDNOTIFYFIRST, count)
+#define Trans2_findnotifyfirst_time __profile_stats_value(PR_VALUE_TRANS2_FINDNOTIFYFIRST, time)
+
+ PR_VALUE_TRANS2_FINDNOTIFYNEXT,
+#define Trans2_findnotifynext_count __profile_stats_value(PR_VALUE_TRANS2_FINDNOTIFYNEXT, count)
+#define Trans2_findnotifynext_time __profile_stats_value(PR_VALUE_TRANS2_FINDNOTIFYNEXT, time)
+
+ PR_VALUE_TRANS2_MKDIR,
+#define Trans2_mkdir_count __profile_stats_value(PR_VALUE_TRANS2_MKDIR, count)
+#define Trans2_mkdir_time __profile_stats_value(PR_VALUE_TRANS2_MKDIR, time)
+
+ PR_VALUE_TRANS2_SESSION_SETUP,
+#define Trans2_session_setup_count __profile_stats_value(PR_VALUE_TRANS2_SESSION_SETUP, count)
+#define Trans2_session_setup_time __profile_stats_value(PR_VALUE_TRANS2_SESSION_SETUP, time)
+
+ PR_VALUE_TRANS2_GET_DFS_REFERRAL,
+#define Trans2_get_dfs_referral_count __profile_stats_value(PR_VALUE_TRANS2_GET_DFS_REFERRAL, count)
+#define Trans2_get_dfs_referral_time __profile_stats_value(PR_VALUE_TRANS2_GET_DFS_REFERRAL, time)
+
+ PR_VALUE_TRANS2_REPORT_DFS_INCONSISTANCY,
+#define Trans2_report_dfs_inconsistancy_count __profile_stats_value(PR_VALUE_TRANS2_REPORT_DFS_INCONSISTANCY, count)
+#define Trans2_report_dfs_inconsistancy_time __profile_stats_value(PR_VALUE_TRANS2_REPORT_DFS_INCONSISTANCY, time)
+
+/* These are the NT transact sub commands. */
+ PR_VALUE_NT_TRANSACT_CREATE,
+#define NT_transact_create_count __profile_stats_value(PR_VALUE_NT_TRANSACT_CREATE, count)
+#define NT_transact_create_time __profile_stats_value(PR_VALUE_NT_TRANSACT_CREATE, time)
+
+ PR_VALUE_NT_TRANSACT_IOCTL,
+#define NT_transact_ioctl_count __profile_stats_value(PR_VALUE_NT_TRANSACT_IOCTL, count)
+#define NT_transact_ioctl_time __profile_stats_value(PR_VALUE_NT_TRANSACT_IOCTL, time)
+
+ PR_VALUE_NT_TRANSACT_SET_SECURITY_DESC,
+#define NT_transact_set_security_desc_count __profile_stats_value(PR_VALUE_NT_TRANSACT_SET_SECURITY_DESC, count)
+#define NT_transact_set_security_desc_time __profile_stats_value(PR_VALUE_NT_TRANSACT_SET_SECURITY_DESC, time)
+
+ PR_VALUE_NT_TRANSACT_NOTIFY_CHANGE,
+#define NT_transact_notify_change_count __profile_stats_value(PR_VALUE_NT_TRANSACT_NOTIFY_CHANGE, count)
+#define NT_transact_notify_change_time __profile_stats_value(PR_VALUE_NT_TRANSACT_NOTIFY_CHANGE, time)
+
+ PR_VALUE_NT_TRANSACT_RENAME,
+#define NT_transact_rename_count __profile_stats_value(PR_VALUE_NT_TRANSACT_RENAME, count)
+#define NT_transact_rename_time __profile_stats_value(PR_VALUE_NT_TRANSACT_RENAME, time)
+
+ PR_VALUE_NT_TRANSACT_QUERY_SECURITY_DESC,
+#define NT_transact_query_security_desc_count __profile_stats_value(PR_VALUE_NT_TRANSACT_QUERY_SECURITY_DESC, count)
+#define NT_transact_query_security_desc_time __profile_stats_value(PR_VALUE_NT_TRANSACT_QUERY_SECURITY_DESC, time)
+
+ PR_VALUE_NT_TRANSACT_GET_USER_QUOTA,
+#define NT_transact_get_user_quota_count __profile_stats_value(PR_VALUE_NT_TRANSACT_GET_USER_QUOTA, count)
+#define NT_transact_get_user_quota_time __profile_stats_value(PR_VALUE_NT_TRANSACT_GET_USER_QUOTA, time)
+
+ PR_VALUE_NT_TRANSACT_SET_USER_QUOTA,
+#define NT_transact_set_user_quota_count __profile_stats_value(PR_VALUE_NT_TRANSACT_SET_USER_QUOTA, count)
+#define NT_transact_set_user_quota_time __profile_stats_value(PR_VALUE_NT_TRANSACT_SET_USER_QUOTA, time)
+
+/* These are ACL manipulation calls */
+ PR_VALUE_GET_NT_ACL,
+#define get_nt_acl_count __profile_stats_value(PR_VALUE_GET_NT_ACL, count)
+#define get_nt_acl_time __profile_stats_value(PR_VALUE_GET_NT_ACL, time)
+
+ PR_VALUE_FGET_NT_ACL,
+#define fget_nt_acl_count __profile_stats_value(PR_VALUE_FGET_NT_ACL, count)
+#define fget_nt_acl_time __profile_stats_value(PR_VALUE_FGET_NT_ACL, time)
+
+ PR_VALUE_FSET_NT_ACL,
+#define fset_nt_acl_count __profile_stats_value(PR_VALUE_FSET_NT_ACL, count)
+#define fset_nt_acl_time __profile_stats_value(PR_VALUE_FSET_NT_ACL, time)
+
+ PR_VALUE_CHMOD_ACL,
+#define chmod_acl_count __profile_stats_value(PR_VALUE_CHMOD_ACL, count)
+#define chmod_acl_time __profile_stats_value(PR_VALUE_CHMOD_ACL, time)
+
+ PR_VALUE_FCHMOD_ACL,
+#define fchmod_acl_count __profile_stats_value(PR_VALUE_FCHMOD_ACL, count)
+#define fchmod_acl_time __profile_stats_value(PR_VALUE_FCHMOD_ACL, time)
+
+/* These are nmbd stats */
+ PR_VALUE_NAME_RELEASE,
+#define name_release_count __profile_stats_value(PR_VALUE_NAME_RELEASE, count)
+#define name_release_time __profile_stats_value(PR_VALUE_NAME_RELEASE, time)
+
+ PR_VALUE_NAME_REFRESH,
+#define name_refresh_count __profile_stats_value(PR_VALUE_NAME_REFRESH, count)
+#define name_refresh_time __profile_stats_value(PR_VALUE_NAME_REFRESH, time)
+
+ PR_VALUE_NAME_REGISTRATION,
+#define name_registration_count __profile_stats_value(PR_VALUE_NAME_REGISTRATION, count)
+#define name_registration_time __profile_stats_value(PR_VALUE_NAME_REGISTRATION, time)
+
+ PR_VALUE_NODE_STATUS,
+#define node_status_count __profile_stats_value(PR_VALUE_NODE_STATUS, count)
+#define node_status_time __profile_stats_value(PR_VALUE_NODE_STATUS, time)
+
+ PR_VALUE_NAME_QUERY,
+#define name_query_count __profile_stats_value(PR_VALUE_NAME_QUERY, count)
+#define name_query_time __profile_stats_value(PR_VALUE_NAME_QUERY, time)
+
+ PR_VALUE_HOST_ANNOUNCE,
+#define host_announce_count __profile_stats_value(PR_VALUE_HOST_ANNOUNCE, count)
+#define host_announce_time __profile_stats_value(PR_VALUE_HOST_ANNOUNCE, time)
+
+ PR_VALUE_WORKGROUP_ANNOUNCE,
+#define workgroup_announce_count __profile_stats_value(PR_VALUE_WORKGROUP_ANNOUNCE, count)
+#define workgroup_announce_time __profile_stats_value(PR_VALUE_WORKGROUP_ANNOUNCE, time)
+
+ PR_VALUE_LOCAL_MASTER_ANNOUNCE,
+#define local_master_announce_count __profile_stats_value(PR_VALUE_LOCAL_MASTER_ANNOUNCE, count)
+#define local_master_announce_time __profile_stats_value(PR_VALUE_LOCAL_MASTER_ANNOUNCE, time)
+
+ PR_VALUE_MASTER_BROWSER_ANNOUNCE,
+#define master_browser_announce_count __profile_stats_value(PR_VALUE_MASTER_BROWSER_ANNOUNCE, count)
+#define master_browser_announce_time __profile_stats_value(PR_VALUE_MASTER_BROWSER_ANNOUNCE, time)
+
+ PR_VALUE_LM_HOST_ANNOUNCE,
+#define lm_host_announce_count __profile_stats_value(PR_VALUE_LM_HOST_ANNOUNCE, count)
+#define lm_host_announce_time __profile_stats_value(PR_VALUE_LM_HOST_ANNOUNCE, time)
+
+ PR_VALUE_GET_BACKUP_LIST,
+#define get_backup_list_count __profile_stats_value(PR_VALUE_GET_BACKUP_LIST, count)
+#define get_backup_list_time __profile_stats_value(PR_VALUE_GET_BACKUP_LIST, time)
+
+ PR_VALUE_RESET_BROWSER,
+#define reset_browser_count __profile_stats_value(PR_VALUE_RESET_BROWSER, count)
+#define reset_browser_time __profile_stats_value(PR_VALUE_RESET_BROWSER, time)
+
+ PR_VALUE_ANNOUNCE_REQUEST,
+#define announce_request_count __profile_stats_value(PR_VALUE_ANNOUNCE_REQUEST, count)
+#define announce_request_time __profile_stats_value(PR_VALUE_ANNOUNCE_REQUEST, time)
+
+ PR_VALUE_LM_ANNOUNCE_REQUEST,
+#define lm_announce_request_count __profile_stats_value(PR_VALUE_LM_ANNOUNCE_REQUEST, count)
+#define lm_announce_request_time __profile_stats_value(PR_VALUE_LM_ANNOUNCE_REQUEST, time)
+
+ PR_VALUE_DOMAIN_LOGON,
+#define domain_logon_count __profile_stats_value(PR_VALUE_DOMAIN_LOGON, count)
+#define domain_logon_time __profile_stats_value(PR_VALUE_DOMAIN_LOGON, time)
+
+ PR_VALUE_SYNC_BROWSE_LISTS,
+#define sync_browse_lists_count __profile_stats_value(PR_VALUE_SYNC_BROWSE_LISTS, count)
+#define sync_browse_lists_time __profile_stats_value(PR_VALUE_SYNC_BROWSE_LISTS, time)
+
+ PR_VALUE_RUN_ELECTIONS,
+#define run_elections_count __profile_stats_value(PR_VALUE_RUN_ELECTIONS, count)
+#define run_elections_time __profile_stats_value(PR_VALUE_RUN_ELECTIONS, time)
+
+ PR_VALUE_ELECTION,
+#define election_count __profile_stats_value(PR_VALUE_ELECTION, count)
+#define election_time __profile_stats_value(PR_VALUE_ELECTION, time)
+
+ /* This mist remain the last value. */
+ PR_VALUE_MAX
+}; /* enum profile_stats_values */
+
+const char * profile_value_name(enum profile_stats_values val);
+
+struct profile_stats {
+/* general counters */
+ unsigned smb_count; /* how many SMB packets we have processed */
+ unsigned uid_changes; /* how many times we change our effective uid */
+
+/* system call and protocol operation counters and cumulative times */
+ unsigned count[PR_VALUE_MAX];
+ unsigned time[PR_VALUE_MAX];
+
+/* cumulative byte counts */
+ unsigned syscall_pread_bytes;
+ unsigned syscall_pwrite_bytes;
+ unsigned syscall_read_bytes;
+ unsigned syscall_write_bytes;
+ unsigned syscall_sendfile_bytes;
+ unsigned syscall_recvfile_bytes;
+
+/* stat cache counters */
+ unsigned statcache_lookups;
+ unsigned statcache_misses;
+ unsigned statcache_hits;
+
+/* write cache counters */
+ unsigned writecache_read_hits;
+ unsigned writecache_abutted_writes;
+ unsigned writecache_total_writes;
+ unsigned writecache_non_oplock_writes;
+ unsigned writecache_direct_writes;
+ unsigned writecache_init_writes;
+ unsigned writecache_flushed_writes[NUM_FLUSH_REASONS];
+ unsigned writecache_num_perfect_writes;
+ unsigned writecache_num_write_caches;
+ unsigned writecache_allocated_write_caches;
+};
+
+struct profile_header {
+ int prof_shm_magic;
+ int prof_shm_version;
+ struct profile_stats stats;
+};
+
+extern struct profile_header *profile_h;
+extern struct profile_stats *profile_p;
+extern bool do_profile_flag;
+extern bool do_profile_times;
+
+#ifdef WITH_PROFILE
+
+/* these are helper macros - do not call them directly in the code
+ * use the DO_PROFILE_* START_PROFILE and END_PROFILE ones
+ * below which test for the profile flage first
+ */
+#define INC_PROFILE_COUNT(x) profile_p->x++
+#define DEC_PROFILE_COUNT(x) profile_p->x--
+#define ADD_PROFILE_COUNT(x,y) profile_p->x += (y)
+
+#if defined(HAVE_CLOCK_GETTIME)
+
+extern clockid_t __profile_clock;
+
+static inline SMB_BIG_UINT profile_timestamp(void)
+{
+ struct timespec ts;
+
+ /* FIXME: On a single-CPU system, or a system where we have bound
+ * daemon threads to single CPUs (eg. using cpusets or processor
+ * affinity), it might be preferable to use CLOCK_PROCESS_CPUTIME_ID.
+ */
+
+ clock_gettime(__profile_clock, &ts);
+ return (ts.tv_sec * 1000000) + (ts.tv_nsec / 1000); /* usec */
+}
+
+#else
+
+static inline SMB_BIG_UINT profile_timestamp(void)
+{
+ struct timeval tv;
+ GetTimeOfDay(&tv);
+ return (tv.tv_sec * 1000000) + tv.tv_usec;
+}
+
+#endif
+
+/* end of helper macros */
+
+#define DO_PROFILE_INC(x) \
+ if (do_profile_flag) { \
+ INC_PROFILE_COUNT(x); \
+ }
+
+#define DO_PROFILE_DEC(x) \
+ if (do_profile_flag) { \
+ DEC_PROFILE_COUNT(x); \
+ }
+
+#define DO_PROFILE_DEC_INC(x,y) \
+ if (do_profile_flag) { \
+ DEC_PROFILE_COUNT(x); \
+ INC_PROFILE_COUNT(y); \
+ }
+
+#define DO_PROFILE_ADD(x,n) \
+ if (do_profile_flag) { \
+ ADD_PROFILE_COUNT(x,n); \
+ }
+
+#define START_PROFILE(x) \
+ SMB_BIG_UINT __profstamp_##x = 0; \
+ if (do_profile_flag) { \
+ __profstamp_##x = do_profile_times ? profile_timestamp() : 0;\
+ INC_PROFILE_COUNT(x##_count); \
+ }
+
+#define START_PROFILE_BYTES(x,n) \
+ SMB_BIG_UINT __profstamp_##x = 0; \
+ if (do_profile_flag) { \
+ __profstamp_##x = do_profile_times ? profile_timestamp() : 0;\
+ INC_PROFILE_COUNT(x##_count); \
+ ADD_PROFILE_COUNT(x##_bytes, n); \
+ }
+
+#define END_PROFILE(x) \
+ if (do_profile_times) { \
+ ADD_PROFILE_COUNT(x##_time, \
+ profile_timestamp() - __profstamp_##x); \
+ }
+
+
+#else /* WITH_PROFILE */
+
+#define DO_PROFILE_INC(x)
+#define DO_PROFILE_DEC(x)
+#define DO_PROFILE_DEC_INC(x,y)
+#define DO_PROFILE_ADD(x,n)
+#define START_PROFILE(x)
+#define START_PROFILE_BYTES(x,n)
+#define END_PROFILE(x)
+
+#endif /* WITH_PROFILE */
+
+#endif
diff --git a/source3/include/spnego.h b/source3/include/spnego.h
new file mode 100644
index 0000000000..02921ed18e
--- /dev/null
+++ b/source3/include/spnego.h
@@ -0,0 +1,64 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ RFC2478 Compliant SPNEGO implementation
+
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef SAMBA_SPNEGO_H
+#define SAMBA_SPNEGO_H
+
+#define SPNEGO_DELEG_FLAG 0x01
+#define SPNEGO_MUTUAL_FLAG 0x02
+#define SPNEGO_REPLAY_FLAG 0x04
+#define SPNEGO_SEQUENCE_FLAG 0x08
+#define SPNEGO_ANON_FLAG 0x10
+#define SPNEGO_CONF_FLAG 0x20
+#define SPNEGO_INTEG_FLAG 0x40
+#define SPNEGO_REQ_FLAG 0x80
+
+#define SPNEGO_NEG_TOKEN_INIT 0
+#define SPNEGO_NEG_TOKEN_TARG 1
+
+typedef enum _spnego_negResult {
+ SPNEGO_ACCEPT_COMPLETED = 0,
+ SPNEGO_ACCEPT_INCOMPLETE = 1,
+ SPNEGO_REJECT = 2
+} negResult_t;
+
+typedef struct spnego_negTokenInit {
+ const char **mechTypes;
+ int reqFlags;
+ DATA_BLOB mechToken;
+ DATA_BLOB mechListMIC;
+} negTokenInit_t;
+
+typedef struct spnego_negTokenTarg {
+ uint8 negResult;
+ char *supportedMech;
+ DATA_BLOB responseToken;
+ DATA_BLOB mechListMIC;
+} negTokenTarg_t;
+
+typedef struct spnego_spnego {
+ int type;
+ negTokenInit_t negTokenInit;
+ negTokenTarg_t negTokenTarg;
+} SPNEGO_DATA;
+
+#endif
diff --git a/source3/include/srvstr.h b/source3/include/srvstr.h
new file mode 100644
index 0000000000..588a807f64
--- /dev/null
+++ b/source3/include/srvstr.h
@@ -0,0 +1,37 @@
+/*
+ Unix SMB/CIFS implementation.
+ server specific string routines
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define srvstr_pull(base_ptr, smb_flags2, dest, src, dest_len, src_len, flags) \
+ pull_string(base_ptr, smb_flags2, dest, src, dest_len, src_len, flags)
+
+/* talloc version of above. */
+#define srvstr_pull_talloc(ctx, base_ptr, smb_flags2, dest, src, src_len, flags) \
+ pull_string_talloc(ctx, base_ptr, smb_flags2, dest, src, src_len, flags)
+
+/* pull a string from the smb_buf part of a packet. In this case the
+ string can either be null terminated or it can be terminated by the
+ end of the smbbuf area
+*/
+
+#define srvstr_pull_buf(inbuf, smb_flags2, dest, src, dest_len, flags) \
+ pull_string(inbuf, smb_flags2, dest, src, dest_len, smb_bufrem(inbuf, src), flags)
+
+/* talloc version of above. */
+#define srvstr_pull_buf_talloc(ctx, inbuf, smb_flags2, dest, src, flags) \
+ pull_string_talloc(ctx, inbuf, smb_flags2, dest, src, smb_bufrem(inbuf, src), flags)
diff --git a/source3/include/stamp-h.in b/source3/include/stamp-h.in
new file mode 100644
index 0000000000..c9061b3ad3
--- /dev/null
+++ b/source3/include/stamp-h.in
@@ -0,0 +1 @@
+Sun Jul 18 20:32:29 UTC 1999
diff --git a/source3/include/sysquotas.h b/source3/include/sysquotas.h
new file mode 100644
index 0000000000..a0754a3737
--- /dev/null
+++ b/source3/include/sysquotas.h
@@ -0,0 +1,75 @@
+/*
+ Unix SMB/CIFS implementation.
+ SYS QUOTA code constants
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SYSQUOTAS_H
+#define _SYSQUOTAS_H
+
+#ifdef HAVE_SYS_QUOTAS
+
+#if defined(HAVE_MNTENT_H)&&defined(HAVE_SETMNTENT)&&defined(HAVE_GETMNTENT)&&defined(HAVE_ENDMNTENT)
+#include <mntent.h>
+#define HAVE_MNTENT 1
+/*#endif defined(HAVE_MNTENT_H)&&defined(HAVE_SETMNTENT)&&defined(HAVE_GETMNTENT)&&defined(HAVE_ENDMNTENT) */
+#elif defined(HAVE_DEVNM_H)&&defined(HAVE_DEVNM)
+#include <devnm.h>
+#endif /* defined(HAVE_DEVNM_H)&&defined(HAVE_DEVNM) */
+
+#endif /* HAVE_SYS_QUOTAS */
+
+
+/**************************************************
+ Some stuff for the sys_quota api.
+ **************************************************/
+
+#define SMB_QUOTAS_NO_LIMIT ((SMB_BIG_UINT)(0))
+#define SMB_QUOTAS_NO_SPACE ((SMB_BIG_UINT)(1))
+
+#define SMB_QUOTAS_SET_NO_LIMIT(dp) \
+{\
+ (dp)->softlimit = SMB_QUOTAS_NO_LIMIT;\
+ (dp)->hardlimit = SMB_QUOTAS_NO_LIMIT;\
+ (dp)->isoftlimit = SMB_QUOTAS_NO_LIMIT;\
+ (dp)->ihardlimit = SMB_QUOTAS_NO_LIMIT;\
+}
+
+#define SMB_QUOTAS_SET_NO_SPACE(dp) \
+{\
+ (dp)->softlimit = SMB_QUOTAS_NO_SPACE;\
+ (dp)->hardlimit = SMB_QUOTAS_NO_SPACE;\
+ (dp)->isoftlimit = SMB_QUOTAS_NO_SPACE;\
+ (dp)->ihardlimit = SMB_QUOTAS_NO_SPACE;\
+}
+
+typedef struct _SMB_DISK_QUOTA {
+ enum SMB_QUOTA_TYPE qtype;
+ SMB_BIG_UINT bsize;
+ SMB_BIG_UINT hardlimit; /* In bsize units. */
+ SMB_BIG_UINT softlimit; /* In bsize units. */
+ SMB_BIG_UINT curblocks; /* In bsize units. */
+ SMB_BIG_UINT ihardlimit; /* inode hard limit. */
+ SMB_BIG_UINT isoftlimit; /* inode soft limit. */
+ SMB_BIG_UINT curinodes; /* Current used inodes. */
+ uint32 qflags;
+} SMB_DISK_QUOTA;
+
+#ifndef QUOTABLOCK_SIZE
+#define QUOTABLOCK_SIZE 1024
+#endif
+
+#endif /*_SYSQUOTAS_H */
diff --git a/source3/include/talloc_stack.h b/source3/include/talloc_stack.h
new file mode 100644
index 0000000000..a2a12f8a63
--- /dev/null
+++ b/source3/include/talloc_stack.h
@@ -0,0 +1,56 @@
+/*
+ Unix SMB/CIFS implementation.
+ Implement a stack of talloc contexts
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ * Implement a stack of talloc frames.
+ *
+ * When a new talloc stackframe is allocated with talloc_stackframe(), then
+ * the TALLOC_CTX returned with talloc_tos() is reset to that new
+ * frame. Whenever that stack frame is TALLOC_FREE()'ed, then the reverse
+ * happens: The previous talloc_tos() is restored.
+ *
+ * This API is designed to be robust in the sense that if someone forgets to
+ * TALLOC_FREE() a stackframe, then the next outer one correctly cleans up and
+ * resets the talloc_tos().
+ *
+ */
+
+#ifndef _TALLOC_STACK_H
+#define _TALLOC_STACK_H
+
+#include "lib/talloc/talloc.h"
+
+/*
+ * Create a new talloc stack frame.
+ *
+ * When free'd, it frees all stack frames that were created after this one and
+ * not explicitly freed.
+ */
+
+TALLOC_CTX *talloc_stackframe(void);
+TALLOC_CTX *talloc_stackframe_pool(size_t poolsize);
+
+/*
+ * Get us the current top of the talloc stack.
+ */
+
+TALLOC_CTX *talloc_tos(void);
+
+#endif
diff --git a/source3/include/trans2.h b/source3/include/trans2.h
new file mode 100644
index 0000000000..3759d59681
--- /dev/null
+++ b/source3/include/trans2.h
@@ -0,0 +1,772 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB transaction2 handling
+
+ Copyright (C) James Peach 2007
+ Copyright (C) Jeremy Allison 1994-2002.
+
+ Extensively modified by Andrew Tridgell, 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _TRANS2_H_
+#define _TRANS2_H_
+
+/* Define the structures needed for the trans2 calls. */
+
+/*******************************************************
+ For DosFindFirst/DosFindNext - level 1
+
+MAXFILENAMELEN = 255;
+FDATE == uint16
+FTIME == uint16
+ULONG == uint32
+USHORT == uint16
+
+typedef struct _FILEFINDBUF {
+Byte offset Type name description
+-------------+-------+-------------------+--------------
+0 FDATE fdateCreation;
+2 FTIME ftimeCreation;
+4 FDATE fdateLastAccess;
+6 FTIME ftimeLastAccess;
+8 FDATE fdateLastWrite;
+10 FTIME ftimeLastWrite;
+12 ULONG cbFile file length in bytes
+16 ULONG cbFileAlloc size of file allocation unit
+20 USHORT attrFile
+22 UCHAR cchName length of name to follow (not including zero)
+23 UCHAR achName[MAXFILENAMELEN]; Null terminated name
+} FILEFINDBUF;
+*********************************************************/
+
+#define l1_fdateCreation 0
+#define l1_fdateLastAccess 4
+#define l1_fdateLastWrite 8
+#define l1_cbFile 12
+#define l1_cbFileAlloc 16
+#define l1_attrFile 20
+#define l1_cchName 22
+#define l1_achName 23
+
+/**********************************************************
+For DosFindFirst/DosFindNext - level 2
+
+typedef struct _FILEFINDBUF2 {
+Byte offset Type name description
+-------------+-------+-------------------+--------------
+0 FDATE fdateCreation;
+2 FTIME ftimeCreation;
+4 FDATE fdateLastAccess;
+6 FTIME ftimeLastAccess;
+8 FDATE fdateLastWrite;
+10 FTIME ftimeLastWrite;
+12 ULONG cbFile file length in bytes
+16 ULONG cbFileAlloc size of file allocation unit
+20 USHORT attrFile
+22 ULONG cbList Extended attribute list (always 0)
+26 UCHAR cchName length of name to follow (not including zero)
+27 UCHAR achName[MAXFILENAMELEN]; Null terminated name
+} FILEFINDBUF2;
+*************************************************************/
+
+#define l2_fdateCreation 0
+#define l2_fdateLastAccess 4
+#define l2_fdateLastWrite 8
+#define l2_cbFile 12
+#define l2_cbFileAlloc 16
+#define l2_attrFile 20
+#define l2_cbList 22
+#define l2_cchName 26
+#define l2_achName 27
+
+
+/**********************************************************
+For DosFindFirst/DosFindNext - level 260
+
+typedef struct _FILEFINDBUF260 {
+Byte offset Type name description
+-------------+-------+-------------------+--------------
+0 ULONG NextEntryOffset;
+4 ULONG FileIndex;
+8 LARGE_INTEGER CreationTime;
+16 LARGE_INTEGER LastAccessTime;
+24 LARGE_INTEGER LastWriteTime;
+32 LARGE_INTEGER ChangeTime;
+40 LARGE_INTEGER EndOfFile;
+48 LARGE_INTEGER AllocationSize;
+56 ULONG FileAttributes;
+60 ULONG FileNameLength;
+64 ULONG EaSize;
+68 CHAR ShortNameLength;
+70 UNICODE ShortName[12];
+94 UNICODE FileName[];
+*************************************************************/
+
+#define l260_achName 94
+
+
+/**********************************************************
+For DosQueryPathInfo/DosQueryFileInfo/DosSetPathInfo/
+DosSetFileInfo - level 1
+
+typedef struct _FILESTATUS {
+Byte offset Type name description
+-------------+-------+-------------------+--------------
+0 FDATE fdateCreation;
+2 FTIME ftimeCreation;
+4 FDATE fdateLastAccess;
+6 FTIME ftimeLastAccess;
+8 FDATE fdateLastWrite;
+10 FTIME ftimeLastWrite;
+12 ULONG cbFile file length in bytes
+16 ULONG cbFileAlloc size of file allocation unit
+20 USHORT attrFile
+} FILESTATUS;
+*************************************************************/
+
+/* Use the l1_ defines from DosFindFirst */
+
+/**********************************************************
+For DosQueryPathInfo/DosQueryFileInfo/DosSetPathInfo/
+DosSetFileInfo - level 2
+
+typedef struct _FILESTATUS2 {
+Byte offset Type name description
+-------------+-------+-------------------+--------------
+0 FDATE fdateCreation;
+2 FTIME ftimeCreation;
+4 FDATE fdateLastAccess;
+6 FTIME ftimeLastAccess;
+8 FDATE fdateLastWrite;
+10 FTIME ftimeLastWrite;
+12 ULONG cbFile file length in bytes
+16 ULONG cbFileAlloc size of file allocation unit
+20 USHORT attrFile
+22 ULONG cbList Length of EA's (0)
+} FILESTATUS2;
+*************************************************************/
+
+/* Use the l2_ #defines from DosFindFirst */
+
+/**********************************************************
+For DosQFSInfo/DosSetFSInfo - level 1
+
+typedef struct _FSALLOCATE {
+Byte offset Type name description
+-------------+-------+-------------------+--------------
+0 ULONG idFileSystem id of file system
+4 ULONG cSectorUnit number of sectors per allocation unit
+8 ULONG cUnit number of allocation units
+12 ULONG cUnitAvail Available allocation units
+16 USHORT cbSector bytes per sector
+} FSALLOCATE;
+*************************************************************/
+
+#define l1_idFileSystem 0
+#define l1_cSectorUnit 4
+#define l1_cUnit 8
+#define l1_cUnitAvail 12
+#define l1_cbSector 16
+
+/**********************************************************
+For DosQFSInfo/DosSetFSInfo - level 2
+
+typedef struct _FSINFO {
+Byte offset Type name description
+-------------+-------+-------------------+--------------
+0 FDATE vol_fdateCreation
+2 FTIME vol_ftimeCreation
+4 UCHAR vol_cch length of volume name (excluding NULL)
+5 UCHAR vol_szVolLabel[12] volume name
+} FSINFO;
+*************************************************************/
+
+#define SMB_INFO_STANDARD 1 /* FILESTATUS3 struct */
+#define SMB_INFO_SET_EA 2 /* EAOP2 struct, only valid on set not query */
+#define SMB_INFO_QUERY_EA_SIZE 2 /* FILESTATUS4 struct, only valid on query not set */
+#define SMB_INFO_QUERY_EAS_FROM_LIST 3 /* only valid on query not set */
+#define SMB_INFO_QUERY_ALL_EAS 4 /* only valid on query not set */
+#define SMB_INFO_IS_NAME_VALID 6
+#define SMB_INFO_STANDARD_LONG 11 /* similar to level 1, ie struct FileStatus3 */
+#define SMB_QUERY_EA_SIZE_LONG 12 /* similar to level 2, ie struct FileStatus4 */
+#define SMB_QUERY_FS_LABEL_INFO 0x101
+#define SMB_QUERY_FS_VOLUME_INFO 0x102
+#define SMB_QUERY_FS_SIZE_INFO 0x103
+#define SMB_QUERY_FS_DEVICE_INFO 0x104
+#define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105
+#if 0
+#define SMB_QUERY_FS_QUOTA_INFO
+#endif
+
+#define l2_vol_fdateCreation 0
+#define l2_vol_cch 4
+#define l2_vol_szVolLabel 5
+
+
+#define SMB_QUERY_FILE_BASIC_INFO 0x101
+#define SMB_QUERY_FILE_STANDARD_INFO 0x102
+#define SMB_QUERY_FILE_EA_INFO 0x103
+#define SMB_QUERY_FILE_NAME_INFO 0x104
+#define SMB_QUERY_FILE_ALLOCATION_INFO 0x105
+#define SMB_QUERY_FILE_END_OF_FILEINFO 0x106
+#define SMB_QUERY_FILE_ALL_INFO 0x107
+#define SMB_QUERY_FILE_ALT_NAME_INFO 0x108
+#define SMB_QUERY_FILE_STREAM_INFO 0x109
+#define SMB_QUERY_COMPRESSION_INFO 0x10b
+
+#define SMB_FIND_INFO_STANDARD 1
+#define SMB_FIND_EA_SIZE 2
+#define SMB_FIND_EA_LIST 3
+#define SMB_FIND_FILE_DIRECTORY_INFO 0x101
+#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
+#define SMB_FIND_FILE_NAMES_INFO 0x103
+#define SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104
+#define SMB_FIND_ID_FULL_DIRECTORY_INFO 0x105
+#define SMB_FIND_ID_BOTH_DIRECTORY_INFO 0x106
+
+#define SMB_SET_FILE_BASIC_INFO 0x101
+#define SMB_SET_FILE_DISPOSITION_INFO 0x102
+#define SMB_SET_FILE_ALLOCATION_INFO 0x103
+#define SMB_SET_FILE_END_OF_FILE_INFO 0x104
+
+/* Query FS info. */
+#define SMB_INFO_ALLOCATION 1
+#define SMB_INFO_VOLUME 2
+
+/*
+ * Thursby MAC extensions....
+ */
+
+/*
+ * MAC CIFS Extensions have the range 0x300 - 0x2FF reserved.
+ * Supposedly Microsoft have agreed to this.
+ */
+
+#define MIN_MAC_INFO_LEVEL 0x300
+#define MAX_MAC_INFO_LEVEL 0x3FF
+
+#define SMB_MAC_QUERY_FS_INFO 0x301
+
+#define DIRLEN_GUESS (45+MAX(l1_achName,l2_achName))
+
+/*
+ * DeviceType and Characteristics returned in a
+ * SMB_QUERY_FS_DEVICE_INFO call.
+ */
+
+#define DEVICETYPE_CD_ROM 0x2
+#define DEVICETYPE_CD_ROM_FILE_SYSTEM 0x3
+#define DEVICETYPE_DISK 0x7
+#define DEVICETYPE_DISK_FILE_SYSTEM 0x8
+#define DEVICETYPE_FILE_SYSTEM 0x9
+
+/* Characteristics. */
+#define TYPE_REMOVABLE_MEDIA 0x1
+#define TYPE_READ_ONLY_DEVICE 0x2
+#define TYPE_FLOPPY 0x4
+#define TYPE_WORM 0x8
+#define TYPE_REMOTE 0x10
+#define TYPE_MOUNTED 0x20
+#define TYPE_VIRTUAL 0x40
+
+/* NT passthrough levels... */
+
+#define SMB_FILE_DIRECTORY_INFORMATION 1001
+#define SMB_FILE_FULL_DIRECTORY_INFORMATION 1002
+#define SMB_FILE_BOTH_DIRECTORY_INFORMATION 1003
+#define SMB_FILE_BASIC_INFORMATION 1004
+#define SMB_FILE_STANDARD_INFORMATION 1005
+#define SMB_FILE_INTERNAL_INFORMATION 1006
+#define SMB_FILE_EA_INFORMATION 1007
+#define SMB_FILE_ACCESS_INFORMATION 1008
+#define SMB_FILE_NAME_INFORMATION 1009
+#define SMB_FILE_RENAME_INFORMATION 1010
+#define SMB_FILE_LINK_INFORMATION 1011
+#define SMB_FILE_NAMES_INFORMATION 1012
+#define SMB_FILE_DISPOSITION_INFORMATION 1013
+#define SMB_FILE_POSITION_INFORMATION 1014
+#define SMB_FILE_FULL_EA_INFORMATION 1015
+#define SMB_FILE_MODE_INFORMATION 1016
+#define SMB_FILE_ALIGNMENT_INFORMATION 1017
+#define SMB_FILE_ALL_INFORMATION 1018
+#define SMB_FILE_ALLOCATION_INFORMATION 1019
+#define SMB_FILE_END_OF_FILE_INFORMATION 1020
+#define SMB_FILE_ALTERNATE_NAME_INFORMATION 1021
+#define SMB_FILE_STREAM_INFORMATION 1022
+#define SMB_FILE_PIPE_INFORMATION 1023
+#define SMB_FILE_PIPE_LOCAL_INFORMATION 1024
+#define SMB_FILE_PIPE_REMOTE_INFORMATION 1025
+#define SMB_FILE_MAILSLOT_QUERY_INFORMATION 1026
+#define SMB_FILE_MAILSLOT_SET_INFORMATION 1027
+#define SMB_FILE_COMPRESSION_INFORMATION 1028
+#define SMB_FILE_OBJECTID_INFORMATION 1029
+#define SMB_FILE_COMPLETION_INFORMATION 1030
+#define SMB_FILE_MOVE_CLUSTER_INFORMATION 1031
+#define SMB_FILE_QUOTA_INFORMATION 1032
+#define SMB_FILE_REPARSEPOINT_INFORMATION 1033
+#define SMB_FILE_NETWORK_OPEN_INFORMATION 1034
+#define SMB_FILE_ATTRIBUTE_TAG_INFORMATION 1035
+#define SMB_FILE_TRACKING_INFORMATION 1036
+#define SMB_FILE_MAXIMUM_INFORMATION 1037
+
+/* NT passthough levels for qfsinfo. */
+
+#define SMB_FS_VOLUME_INFORMATION 1001
+#define SMB_FS_LABEL_INFORMATION 1002
+#define SMB_FS_SIZE_INFORMATION 1003
+#define SMB_FS_DEVICE_INFORMATION 1004
+#define SMB_FS_ATTRIBUTE_INFORMATION 1005
+#define SMB_FS_QUOTA_INFORMATION 1006
+#define SMB_FS_FULL_SIZE_INFORMATION 1007
+#define SMB_FS_OBJECTID_INFORMATION 1008
+
+/* flags on trans2 findfirst/findnext that control search */
+#define FLAG_TRANS2_FIND_CLOSE 0x1
+#define FLAG_TRANS2_FIND_CLOSE_IF_END 0x2
+#define FLAG_TRANS2_FIND_REQUIRE_RESUME 0x4
+#define FLAG_TRANS2_FIND_CONTINUE 0x8
+#define FLAG_TRANS2_FIND_BACKUP_INTENT 0x10
+
+/* UNIX CIFS Extensions - created by HP */
+/*
+ * UNIX CIFS Extensions have the range 0x200 - 0x2FF reserved.
+ * Supposedly Microsoft have agreed to this.
+ */
+
+#define MIN_UNIX_INFO_LEVEL 0x200
+#define MAX_UNIX_INFO_LEVEL 0x2FF
+
+#define INFO_LEVEL_IS_UNIX(level) (((level) >= MIN_UNIX_INFO_LEVEL) && ((level) <= MAX_UNIX_INFO_LEVEL))
+
+#define SMB_QUERY_FILE_UNIX_BASIC 0x200 /* UNIX File Info*/
+#define SMB_SET_FILE_UNIX_BASIC 0x200
+#define SMB_SET_FILE_UNIX_INFO2 0x20B /* UNIX File Info2 */
+
+#define SMB_MODE_NO_CHANGE 0xFFFFFFFF /* file mode value which */
+ /* means "don't change it" */
+#define SMB_UID_NO_CHANGE 0xFFFFFFFF
+#define SMB_GID_NO_CHANGE 0xFFFFFFFF
+
+#define SMB_SIZE_NO_CHANGE_LO 0xFFFFFFFF
+#define SMB_SIZE_NO_CHANGE_HI 0xFFFFFFFF
+
+#define SMB_TIME_NO_CHANGE_LO 0xFFFFFFFF
+#define SMB_TIME_NO_CHANGE_HI 0xFFFFFFFF
+
+/*
+Offset Size Name
+0 LARGE_INTEGER EndOfFile File size
+8 LARGE_INTEGER Blocks Number of bytes used on disk (st_blocks).
+16 LARGE_INTEGER CreationTime Creation time
+24 LARGE_INTEGER LastAccessTime Last access time
+32 LARGE_INTEGER LastModificationTime Last modification time
+40 LARGE_INTEGER Uid Numeric user id for the owner
+48 LARGE_INTEGER Gid Numeric group id of owner
+56 ULONG Type Enumeration specifying the pathname type:
+ 0 -- File
+ 1 -- Directory
+ 2 -- Symbolic link
+ 3 -- Character device
+ 4 -- Block device
+ 5 -- FIFO (named pipe)
+ 6 -- Unix domain socket
+
+60 LARGE_INTEGER devmajor Major device number if type is device
+68 LARGE_INTEGER devminor Minor device number if type is device
+76 LARGE_INTEGER uniqueid This is a server-assigned unique id for the file. The client
+ will typically map this onto an inode number. The scope of
+ uniqueness is the share.
+84 LARGE_INTEGER permissions Standard UNIX file permissions - see below.
+92 LARGE_INTEGER nlinks The number of directory entries that map to this entry
+ (number of hard links)
+
+100 - end.
+*/
+
+#define SMB_FILE_UNIX_BASIC_SIZE 100
+
+/* UNIX filetype mappings. */
+
+#define UNIX_TYPE_FILE 0
+#define UNIX_TYPE_DIR 1
+#define UNIX_TYPE_SYMLINK 2
+#define UNIX_TYPE_CHARDEV 3
+#define UNIX_TYPE_BLKDEV 4
+#define UNIX_TYPE_FIFO 5
+#define UNIX_TYPE_SOCKET 6
+#define UNIX_TYPE_UNKNOWN 0xFFFFFFFF
+
+/*
+ * Oh this is fun. "Standard UNIX permissions" has no
+ * meaning in POSIX. We need to define the mapping onto
+ * and off the wire as this was not done in the original HP
+ * spec. JRA.
+ */
+
+#define UNIX_X_OTH 0000001
+#define UNIX_W_OTH 0000002
+#define UNIX_R_OTH 0000004
+#define UNIX_X_GRP 0000010
+#define UNIX_W_GRP 0000020
+#define UNIX_R_GRP 0000040
+#define UNIX_X_USR 0000100
+#define UNIX_W_USR 0000200
+#define UNIX_R_USR 0000400
+#define UNIX_STICKY 0001000
+#define UNIX_SET_GID 0002000
+#define UNIX_SET_UID 0004000
+
+/* Masks for the above */
+#define UNIX_OTH_MASK 0000007
+#define UNIX_GRP_MASK 0000070
+#define UNIX_USR_MASK 0000700
+#define UNIX_PERM_MASK 0000777
+#define UNIX_EXTRA_MASK 0007000
+#define UNIX_ALL_MASK 0007777
+
+/* Flags for chflags (CIFS_UNIX_EXTATTR_CAP capability) and
+ * SMB_QUERY_FILE_UNIX_INFO2.
+ */
+#define EXT_SECURE_DELETE 0x00000001
+#define EXT_ENABLE_UNDELETE 0x00000002
+#define EXT_SYNCHRONOUS 0x00000004
+#define EXT_IMMUTABLE 0x00000008
+#define EXT_OPEN_APPEND_ONLY 0x00000010
+#define EXT_DO_NOT_BACKUP 0x00000020
+#define EXT_NO_UPDATE_ATIME 0x00000040
+#define EXT_HIDDEN 0x00000080
+
+#define SMB_QUERY_FILE_UNIX_LINK 0x201
+#define SMB_SET_FILE_UNIX_LINK 0x201
+#define SMB_SET_FILE_UNIX_HLINK 0x203
+/* SMB_QUERY_POSIX_ACL 0x204 see below */
+#define SMB_QUERY_XATTR 0x205 /* need for non-user XATTRs */
+#define SMB_QUERY_ATTR_FLAGS 0x206 /* chflags, chattr */
+#define SMB_SET_ATTR_FLAGS 0x206
+#define SMB_QUERY_POSIX_PERMISSION 0x207
+/* Only valid for qfileinfo */
+#define SMB_QUERY_POSIX_LOCK 0x208
+/* Only valid for setfileinfo */
+#define SMB_SET_POSIX_LOCK 0x208
+
+/* The set info levels for POSIX path operations. */
+#define SMB_POSIX_PATH_OPEN 0x209
+#define SMB_POSIX_PATH_UNLINK 0x20A
+
+#define SMB_QUERY_FILE_UNIX_INFO2 0x20B /* UNIX File Info2 */
+#define SMB_SET_FILE_UNIX_INFO2 0x20B
+
+/*
+SMB_QUERY_FILE_UNIX_INFO2 is SMB_QUERY_FILE_UNIX_BASIC with create
+time and file flags appended. The corresponding info level for
+findfirst/findnext is SMB_FIND_FILE_UNIX_INFO2.
+ Size Offset Value
+ ---------------------
+ 0 LARGE_INTEGER EndOfFile File size
+ 8 LARGE_INTEGER Blocks Number of blocks used on disk
+ 16 LARGE_INTEGER ChangeTime Attribute change time
+ 24 LARGE_INTEGER LastAccessTime Last access time
+ 32 LARGE_INTEGER LastModificationTime Last modification time
+ 40 LARGE_INTEGER Uid Numeric user id for the owner
+ 48 LARGE_INTEGER Gid Numeric group id of owner
+ 56 ULONG Type Enumeration specifying the file type
+ 60 LARGE_INTEGER devmajor Major device number if type is device
+ 68 LARGE_INTEGER devminor Minor device number if type is device
+ 76 LARGE_INTEGER uniqueid This is a server-assigned unique id
+ 84 LARGE_INTEGER permissions Standard UNIX permissions
+ 92 LARGE_INTEGER nlinks Number of hard links
+ 100 LARGE_INTEGER CreationTime Create/birth time
+ 108 ULONG FileFlags File flags enumeration
+ 112 ULONG FileFlagsMask Mask of valid flags
+*/
+
+/* Transact 2 Find First levels */
+#define SMB_FIND_FILE_UNIX 0x202
+#define SMB_FIND_FILE_UNIX_INFO2 0x20B /* UNIX File Info2 */
+
+#define SMB_FILE_UNIX_INFO2_SIZE 116
+
+/*
+ Info level for TRANS2_QFSINFO - returns version of CIFS UNIX extensions, plus
+ 64-bits worth of capability fun :-).
+ Use the same info level for TRANS2_SETFSINFO
+*/
+
+#define SMB_QUERY_CIFS_UNIX_INFO 0x200
+#define SMB_SET_CIFS_UNIX_INFO 0x200
+
+/* Returns or sets the following.
+
+ UINT16 major version number
+ UINT16 minor version number
+ LARGE_INTEGER capability bitfield
+
+*/
+
+#define CIFS_UNIX_MAJOR_VERSION 1
+#define CIFS_UNIX_MINOR_VERSION 0
+
+#define CIFS_UNIX_FCNTL_LOCKS_CAP 0x1
+#define CIFS_UNIX_POSIX_ACLS_CAP 0x2
+#define CIFS_UNIX_XATTTR_CAP 0x4 /* for support of other xattr
+ namespaces such as system,
+ security and trusted */
+#define CIFS_UNIX_EXTATTR_CAP 0x8 /* for support of chattr
+ (chflags) and lsattr */
+#define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x10 /* Use POSIX pathnames on the wire. */
+#define CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP 0x20 /* We can cope with POSIX open/mkdir/unlink etc. */
+#define CIFS_UNIX_LARGE_READ_CAP 0x40 /* We can cope with 24 bit reads in readX. */
+#define CIFS_UNIX_LARGE_WRITE_CAP 0x80 /* We can cope with 24 bit writes in writeX. */
+#define CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP 0x100 /* We can do SPNEGO negotiations for encryption. */
+#define CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP 0x200 /* We *must* SPNEGO negotiations for encryption. */
+
+#define SMB_QUERY_POSIX_FS_INFO 0x201
+
+/* Returns FILE_SYSTEM_POSIX_INFO struct as follows
+ (NB For undefined values return -1 in that field)
+ le32 OptimalTransferSize; bsize on some os, iosize on other os, This
+ is a hint to the client about best size. Server
+ can return -1 if no preference, ie if SMB
+ negotiated size is adequate for optimal
+ read/write performance
+ le32 BlockSize; (often 512 bytes) NB: BlockSize * TotalBlocks = disk space
+ le64 TotalBlocks; redundant with other infolevels but easy to ret here
+ le64 BlocksAvail; although redundant, easy to return
+ le64 UserBlocksAvail; bavail
+ le64 TotalFileNodes;
+ le64 FreeFileNodes;
+ le64 FileSysIdentifier; fsid
+ (NB statfs field Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call)
+ (NB statfs field flags can come from FILE_SYSTEM_DEVICE_INFO call)
+*/
+
+#define SMB_QUERY_POSIX_WHO_AM_I 0x202 /* QFS Info */
+/* returns:
+ __u32 flags; 0 = Authenticated user 1 = GUEST
+ __u32 mask; which flags bits server understands ie 0x0001
+ __u64 unix_user_id;
+ __u64 unix_user_gid;
+ __u32 number_of_supplementary_gids; may be zero
+ __u32 number_of_sids; may be zero
+ __u32 length_of_sid_array; in bytes - may be zero
+ __u32 pad; reserved - MBZ
+ __u64 gid_array[0]; may be empty
+ __u8 * psid_list may be empty
+*/
+
+/* ... more as we think of them :-). */
+
+/* SMB POSIX ACL definitions. */
+/* Wire format is (all little endian) :
+
+[2 bytes] - Version number.
+[2 bytes] - Number of ACE entries to follow.
+[2 bytes] - Number of default ACE entries to follow.
+-------------------------------------
+^
+|
+ACE entries
+|
+v
+-------------------------------------
+^
+|
+Default ACE entries
+|
+v
+-------------------------------------
+
+Where an ACE entry looks like :
+
+[1 byte] - Entry type.
+
+Entry types are :
+
+ACL_USER_OBJ 0x01
+ACL_USER 0x02
+ACL_GROUP_OBJ 0x04
+ACL_GROUP 0x08
+ACL_MASK 0x10
+ACL_OTHER 0x20
+
+[1 byte] - permissions (perm_t)
+
+perm_t types are :
+
+ACL_READ 0x04
+ACL_WRITE 0x02
+ACL_EXECUTE 0x01
+
+[8 bytes] - uid/gid to apply this permission to.
+
+In the same format as the uid/gid fields in the other
+UNIX extensions definitions. Use 0xFFFFFFFFFFFFFFFF for
+the MASK and OTHER entry types.
+
+If the Number of ACE entries for either file or default ACE's
+is set to 0xFFFF this means ignore this kind of ACE (and the
+number of entries sent will be zero.
+
+*/
+
+#define SMB_QUERY_POSIX_WHOAMI 0x202
+
+enum smb_whoami_flags {
+ SMB_WHOAMI_GUEST = 0x1 /* Logged in as (or squashed to) guest */
+};
+
+/* Mask of which WHOAMI bits are valid. This should make it easier for clients
+ * to cope with servers that have different sets of WHOAMI flags (as more get
+ * added).
+ */
+#define SMB_WHOAMI_MASK 0x00000001
+
+/*
+ SMBWhoami - Query the user mapping performed by the server for the
+ connected tree. This is a subcommand of the TRANS2_QFSINFO.
+
+ Returns:
+ 4 bytes unsigned - mapping flags (smb_whoami_flags)
+ 4 bytes unsigned - flags mask
+
+ 8 bytes unsigned - primary UID
+ 8 bytes unsigned - primary GID
+ 4 bytes unsigned - number of supplementary GIDs
+ 4 bytes unsigned - number of SIDs
+ 4 bytes unsigned - SID list byte count
+ 4 bytes - pad / reserved (must be zero)
+
+ 8 bytes unsigned[] - list of GIDs (may be empty)
+ DOM_SID[] - list of SIDs (may be empty)
+*/
+
+/*
+ * The following trans2 is done between client and server
+ * as a FSINFO call to set up the encryption state for transport
+ * encryption.
+ * This is a subcommand of the TRANS2_QFSINFO.
+ *
+ * The request looks like :
+ *
+ * [data block] -> SPNEGO framed GSSAPI request.
+ *
+ * The reply looks like :
+ *
+ * [data block] -> SPNEGO framed GSSAPI reply - if error
+ * is NT_STATUS_OK then we're done, if it's
+ * NT_STATUS_MORE_PROCESSING_REQUIRED then the
+ * client needs to keep going. If it's an
+ * error it can be any NT_STATUS error.
+ *
+ */
+
+#define SMB_REQUEST_TRANSPORT_ENCRYPTION 0x203 /* QFSINFO */
+
+
+/* The query/set info levels for POSIX ACLs. */
+#define SMB_QUERY_POSIX_ACL 0x204
+#define SMB_SET_POSIX_ACL 0x204
+
+/* Current on the wire ACL version. */
+#define SMB_POSIX_ACL_VERSION 1
+
+/* ACE entry type. */
+#define SMB_POSIX_ACL_USER_OBJ 0x01
+#define SMB_POSIX_ACL_USER 0x02
+#define SMB_POSIX_ACL_GROUP_OBJ 0x04
+#define SMB_POSIX_ACL_GROUP 0x08
+#define SMB_POSIX_ACL_MASK 0x10
+#define SMB_POSIX_ACL_OTHER 0x20
+
+/* perm_t types. */
+#define SMB_POSIX_ACL_READ 0x04
+#define SMB_POSIX_ACL_WRITE 0x02
+#define SMB_POSIX_ACL_EXECUTE 0x01
+
+#define SMB_POSIX_ACL_HEADER_SIZE 6
+#define SMB_POSIX_ACL_ENTRY_SIZE 10
+
+#define SMB_POSIX_IGNORE_ACE_ENTRIES 0xFFFF
+
+/* Definition of data block of SMB_SET_POSIX_LOCK */
+/*
+ [2 bytes] lock_type - 0 = Read, 1 = Write, 2 = Unlock
+ [2 bytes] lock_flags - 1 = Wait (only valid for setlock)
+ [4 bytes] pid = locking context.
+ [8 bytes] start = unsigned 64 bits.
+ [8 bytes] length = unsigned 64 bits.
+*/
+
+#define POSIX_LOCK_TYPE_OFFSET 0
+#define POSIX_LOCK_FLAGS_OFFSET 2
+#define POSIX_LOCK_PID_OFFSET 4
+#define POSIX_LOCK_START_OFFSET 8
+#define POSIX_LOCK_LEN_OFFSET 16
+#define POSIX_LOCK_DATA_SIZE 24
+
+#define POSIX_LOCK_FLAG_NOWAIT 0
+#define POSIX_LOCK_FLAG_WAIT 1
+
+#define POSIX_LOCK_TYPE_READ 0
+#define POSIX_LOCK_TYPE_WRITE 1
+#define POSIX_LOCK_TYPE_UNLOCK 2
+
+/* SMB_POSIX_PATH_OPEN "open_mode" definitions. */
+#define SMB_O_RDONLY 0x1
+#define SMB_O_WRONLY 0x2
+#define SMB_O_RDWR 0x4
+
+#define SMB_ACCMODE 0x7
+
+#define SMB_O_CREAT 0x10
+#define SMB_O_EXCL 0x20
+#define SMB_O_TRUNC 0x40
+#define SMB_O_APPEND 0x80
+#define SMB_O_SYNC 0x100
+#define SMB_O_DIRECTORY 0x200
+#define SMB_O_NOFOLLOW 0x400
+#define SMB_O_DIRECT 0x800
+
+/* Definition of request data block for SMB_POSIX_PATH_OPEN */
+/*
+ [4 bytes] flags (as smb_ntcreate_Flags).
+ [4 bytes] open_mode - SMB_O_xxx flags above.
+ [8 bytes] mode_t (permissions) - same encoding as "Standard UNIX permissions" above in SMB_SET_FILE_UNIX_BASIC.
+ [2 bytes] ret_info_level - optimization. Info level to be returned.
+*/
+
+/* Definition of reply data block for SMB_POSIX_PATH_OPEN */
+
+#define SMB_NO_INFO_LEVEL_RETURNED 0xFFFF
+
+/*
+ [2 bytes] - flags field. Identical to flags reply for oplock response field in SMBNTCreateX)
+ [2 bytes] - FID returned.
+ [4 bytes] - CreateAction (same as in NTCreateX response).
+ [2 bytes] - reply info level - as requested or 0xFFFF if not available.
+ [2 bytes] - padding (must be zero)
+ [n bytes] - info level reply - if available.
+*/
+
+/* Definition of request data block for SMB_POSIX_UNLINK */
+/*
+ [2 bytes] flags (defined below).
+*/
+
+#define SMB_POSIX_UNLINK_FILE_TARGET 0
+#define SMB_POSIX_UNLINK_DIRECTORY_TARGET 1
+
+#endif
diff --git a/source3/include/transfer_file.h b/source3/include/transfer_file.h
new file mode 100644
index 0000000000..79ad9c4c34
--- /dev/null
+++ b/source3/include/transfer_file.h
@@ -0,0 +1,32 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Utility functions to transfer files.
+ *
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __TRANSFER_FILE_H__
+#define __TRANSFER_FILE_H__
+
+ssize_t transfer_file_internal(void *in_file,
+ void *out_file,
+ size_t n,
+ ssize_t (*read_fn)(void *, void *, size_t),
+ ssize_t (*write_fn)(void *, const void *, size_t));
+
+SMB_OFF_T transfer_file(int infd, int outfd, SMB_OFF_T n);
+
+#endif /* __TRANSFER_FILE_H__ */
diff --git a/source3/include/util_getent.h b/source3/include/util_getent.h
new file mode 100644
index 0000000000..c260e70f45
--- /dev/null
+++ b/source3/include/util_getent.h
@@ -0,0 +1,60 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Simo Sorce 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _UTIL_GETENT_H
+#define _UTIL_GETENT_H
+
+/* Element for a single linked list of group entries */
+/* Replace the use of struct group in some cases */
+/* Used by getgrent_list() */
+
+struct sys_grent {
+ char *gr_name;
+ char *gr_passwd;
+ gid_t gr_gid;
+ char **gr_mem;
+ struct sys_grent *next;
+};
+
+/* Element for a single linked list of passwd entries */
+/* Replace the use of struct passwd in some cases */
+/* Used by getpwent_list() */
+
+struct sys_pwent {
+ char *pw_name;
+ char *pw_passwd;
+ uid_t pw_uid;
+ gid_t pw_gid;
+ char *pw_gecos;
+ char *pw_dir;
+ char *pw_shell;
+ struct sys_pwent *next;
+};
+
+/* Element for a single linked list of user names in a group. */
+/* Used to return group lists that may span multiple lines in
+ /etc/group file. */
+/* Used by get_users_in_group() */
+
+struct sys_userlist {
+ struct sys_userlist *next, *prev;
+ char *unix_name;
+};
+
+#endif /* _UTIL_GETENT_H */
diff --git a/source3/include/util_tdb.h b/source3/include/util_tdb.h
new file mode 100644
index 0000000000..fcc723c511
--- /dev/null
+++ b/source3/include/util_tdb.h
@@ -0,0 +1,108 @@
+/*
+ Unix SMB/CIFS implementation.
+ tdb utility functions
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __TDBUTIL_H__
+#define __TDBUTIL_H__
+
+#include "tdb.h"
+
+#include "talloc.h" /* for tdb_wrap_open() */
+#include "nt_status.h" /* for map_nt_error_from_tdb() */
+
+/* single node of a list returned by tdb_search_keys */
+typedef struct keys_node
+{
+ struct keys_node *prev, *next;
+ TDB_DATA node_key;
+} TDB_LIST_NODE;
+
+struct tdb_wrap {
+ struct tdb_context *tdb;
+ const char *name;
+ struct tdb_wrap *next, *prev;
+};
+
+struct tdb_validation_status {
+ bool tdb_error;
+ bool bad_freelist;
+ bool bad_entry;
+ bool unknown_key;
+ bool success;
+};
+
+typedef int (*tdb_validate_data_func)(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state);
+
+TDB_DATA make_tdb_data(const uint8 *dptr, size_t dsize);
+TDB_DATA string_tdb_data(const char *string);
+TDB_DATA string_term_tdb_data(const char *string);
+
+TDB_LIST_NODE *tdb_search_keys(struct tdb_context*, const char*);
+void tdb_search_list_free(TDB_LIST_NODE*);
+
+int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key,
+ unsigned int timeout);
+int tdb_lock_bystring(struct tdb_context *tdb, const char *keyval);
+int tdb_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval,
+ int timeout);
+void tdb_unlock_bystring(struct tdb_context *tdb, const char *keyval);
+int tdb_read_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval,
+ unsigned int timeout);
+void tdb_read_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval);
+
+int32 tdb_fetch_int32_byblob(TDB_CONTEXT *tdb, TDB_DATA key);
+int32 tdb_fetch_int32(struct tdb_context *tdb, const char *keystr);
+bool tdb_store_uint32_byblob(TDB_CONTEXT *tdb, TDB_DATA key, uint32 value);
+bool tdb_store_uint32(struct tdb_context *tdb, const char *keystr, uint32 value);
+int tdb_store_int32_byblob(TDB_CONTEXT *tdb, TDB_DATA key, int32 v);
+int tdb_store_int32(struct tdb_context *tdb, const char *keystr, int32 v);
+bool tdb_fetch_uint32_byblob(TDB_CONTEXT *tdb, TDB_DATA key, uint32 *value);
+bool tdb_fetch_uint32(struct tdb_context *tdb, const char *keystr, uint32 *value);
+int32 tdb_change_int32_atomic(struct tdb_context *tdb, const char *keystr, int32 *oldval, int32 change_val);
+bool tdb_change_uint32_atomic(TDB_CONTEXT *tdb, const char *keystr,
+ uint32 *oldval, uint32 change_val);
+
+int tdb_store_bystring(struct tdb_context *tdb, const char *keystr, TDB_DATA data, int flags);
+int tdb_trans_store_bystring(TDB_CONTEXT *tdb, const char *keystr,
+ TDB_DATA data, int flags);
+TDB_DATA tdb_fetch_bystring(struct tdb_context *tdb, const char *keystr);
+int tdb_delete_bystring(struct tdb_context *tdb, const char *keystr);
+int tdb_trans_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
+ int flag);
+int tdb_trans_delete(struct tdb_context *tdb, TDB_DATA key);
+
+int tdb_unpack(const uint8 *buf, int bufsize, const char *fmt, ...);
+size_t tdb_pack(uint8 *buf, int bufsize, const char *fmt, ...);
+bool tdb_pack_append(TALLOC_CTX *mem_ctx, uint8 **buf, size_t *len,
+ const char *fmt, ...);
+
+struct tdb_context *tdb_open_log(const char *name, int hash_size,
+ int tdb_flags, int open_flags, mode_t mode);
+
+struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx,
+ const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode);
+
+NTSTATUS map_nt_error_from_tdb(enum TDB_ERROR err);
+
+int tdb_validate(struct tdb_context *tdb, tdb_validate_data_func validate_fn);
+int tdb_validate_open(const char *tdb_path, tdb_validate_data_func validate_fn);
+int tdb_validate_and_backup(const char *tdb_path,
+ tdb_validate_data_func validate_fn);
+
+#endif /* __TDBUTIL_H__ */
diff --git a/source3/include/vfs.h b/source3/include/vfs.h
new file mode 100644
index 0000000000..9b72f69328
--- /dev/null
+++ b/source3/include/vfs.h
@@ -0,0 +1,694 @@
+/*
+ Unix SMB/CIFS implementation.
+ VFS structures and parameters
+ Copyright (C) Jeremy Allison 1999-2005
+ Copyright (C) Tim Potter 1999
+ Copyright (C) Alexander Bokovoy 2002-2005
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ This work was sponsored by Optifacio Software Services, Inc.
+*/
+
+#ifndef _VFS_H
+#define _VFS_H
+
+/* Avoid conflict with an AIX include file */
+
+#ifdef vfs_ops
+#undef vfs_ops
+#endif
+
+/*
+ * As we're now (thanks Andrew ! :-) using file_structs and connection
+ * structs in the vfs - then anyone writing a vfs must include includes.h...
+ */
+
+/*
+ * This next constant specifies the version number of the VFS interface
+ * this smbd will load. Increment this if *ANY* changes are made to the
+ * vfs_ops below. JRA.
+ *
+ * If you change anything here, please also update modules/vfs_full_audit.c.
+ * VL.
+ */
+
+/* Changed to version 2 for CIFS UNIX extensions (mknod and link added). JRA. */
+/* Changed to version 3 for POSIX acl extensions. JRA. */
+/* Changed to version 4 for cascaded VFS interface. Alexander Bokovoy. */
+/* Changed to version 5 for sendfile addition. JRA. */
+/* Changed to version 6 for the new module system, fixed cascading and quota functions. --metze */
+/* Changed to version 7 to include the get_nt_acl info parameter. JRA. */
+/* Changed to version 8 includes EA calls. JRA. */
+/* Changed to version 9 to include the get_shadow_data call. --metze */
+/* Changed to version 10 to include pread/pwrite calls. */
+/* Changed to version 11 to include seekdir/telldir/rewinddir calls. JRA */
+/* Changed to version 12 to add mask and attributes to opendir(). JRA
+ Also include aio calls. JRA. */
+/* Changed to version 13 as the internal structure of files_struct has changed. JRA */
+/* Changed to version 14 as we had to change DIR to SMB_STRUCT_DIR. JRA */
+/* Changed to version 15 as we added the statvfs call. JRA */
+/* Changed to version 16 as we added the getlock call. JRA */
+/* Changed to version 17 as we removed redundant connection_struct parameters. --jpeach */
+/* Changed to version 18 to add fsp parameter to the open call -- jpeach
+ Also include kernel_flock call - jmcd */
+/* Changed to version 19, kernel change notify has been merged
+ Also included linux setlease call - jmcd */
+/* Changed to version 20, use ntimes call instead of utime (greater
+ * timestamp resolition. JRA. */
+/* Changed to version21 to add chflags operation -- jpeach */
+/* Changed to version22 to add lchown operation -- jra */
+/* Leave at 22 - not yet released. But change set_nt_acl to return an NTSTATUS. jra. */
+/* Leave at 22 - not yet released. Add file_id_create operation. --metze */
+/* Leave at 22 - not yet released. Change all BOOL parameters (int) to bool. jra. */
+/* Leave at 22 - not yet released. Added recvfile. */
+/* Leave at 22 - not yet released. Change get_nt_acl to return NTSTATUS - vl */
+/* Leave at 22 - not yet released. Change get_nt_acl to *not* take a
+ * files_struct. - obnox.*/
+/* Leave at 22 - not yet released. Remove parameter fd from fget_nt_acl. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from gset_nt_acl. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from pread. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from pwrite. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from lseek. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from fsync. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from fstat. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from fchmod. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from fchown. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from ftruncate. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from lock. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from kernel_flock. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from linux_setlease. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from getlock. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from sys_acl_get_fd. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from fchmod_acl. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from sys_acl_set_fd. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from fgetxattr. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from flistxattr. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from fremovexattr. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from fsetxattr. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from aio_cancel. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from read. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fd from write. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fromfd from sendfile. - obnox */
+/* Leave at 22 - not yet released. Remove parameter fromfd from recvfile. - obnox */
+/* Leave at 22 - not yet released. Additional change: add operations for offline files -- ab */
+/* Leave at 22 - not yet released. Add the streaminfo call. -- jpeach, vl */
+/* Leave at 22 - not yet released. Remove parameter fd from close_fn. - obnox */
+/* Changed to version 23 - remove set_nt_acl call. This can only be done via an
+ open handle. JRA. */
+
+#define SMB_VFS_INTERFACE_VERSION 23
+
+
+/* to bug old modules which are trying to compile with the old functions */
+#define vfs_init __ERROR_please_port_this_module_to_SMB_VFS_INTERFACE_VERSION_8_donot_use_vfs_init_anymore(void) { __ERROR_please_port_this_module_to_SMB_VFS_INTERFACE_VERSION_8_donot_use_vfs_init_anymore };
+#define lp_parm_string __ERROR_please_port_lp_parm_string_to_lp_parm_const_string_or_lp_parm_talloc_string { \
+ __ERROR_please_port_lp_parm_string_to_lp_parm_const_string_or_lp_parm_talloc_string };
+#define lp_vfs_options __ERROR_please_donot_use_lp_vfs_options_anymore_use_lp_parm_xxxx_functions_instead { \
+ __ERROR_please_donot_use_lp_vfs_options_anymore_use_lp_parm_xxxx_functions_instead };
+
+/*
+ All intercepted VFS operations must be declared as static functions inside module source
+ in order to keep smbd namespace unpolluted. See source of audit, extd_audit, fake_perms and recycle
+ example VFS modules for more details.
+*/
+
+/* VFS operations structure */
+
+struct vfs_handle_struct;
+struct connection_struct;
+struct files_struct;
+struct security_descriptor;
+struct vfs_statvfs_struct;
+
+/*
+ Available VFS operations. These values must be in sync with vfs_ops struct
+ (struct vfs_fn_pointers and struct vfs_handle_pointers inside of struct vfs_ops).
+ In particular, if new operations are added to vfs_ops, appropriate constants
+ should be added to vfs_op_type so that order of them kept same as in vfs_ops.
+*/
+
+typedef enum _vfs_op_type {
+ SMB_VFS_OP_NOOP = -1,
+
+ /* Disk operations */
+
+ SMB_VFS_OP_CONNECT = 0,
+ SMB_VFS_OP_DISCONNECT,
+ SMB_VFS_OP_DISK_FREE,
+ SMB_VFS_OP_GET_QUOTA,
+ SMB_VFS_OP_SET_QUOTA,
+ SMB_VFS_OP_GET_SHADOW_COPY_DATA,
+ SMB_VFS_OP_STATVFS,
+ SMB_VFS_OP_FS_CAPABILITIES,
+
+ /* Directory operations */
+
+ SMB_VFS_OP_OPENDIR,
+ SMB_VFS_OP_READDIR,
+ SMB_VFS_OP_SEEKDIR,
+ SMB_VFS_OP_TELLDIR,
+ SMB_VFS_OP_REWINDDIR,
+ SMB_VFS_OP_MKDIR,
+ SMB_VFS_OP_RMDIR,
+ SMB_VFS_OP_CLOSEDIR,
+
+ /* File operations */
+
+ SMB_VFS_OP_OPEN,
+ SMB_VFS_OP_CLOSE,
+ SMB_VFS_OP_READ,
+ SMB_VFS_OP_PREAD,
+ SMB_VFS_OP_WRITE,
+ SMB_VFS_OP_PWRITE,
+ SMB_VFS_OP_LSEEK,
+ SMB_VFS_OP_SENDFILE,
+ SMB_VFS_OP_RECVFILE,
+ SMB_VFS_OP_RENAME,
+ SMB_VFS_OP_FSYNC,
+ SMB_VFS_OP_STAT,
+ SMB_VFS_OP_FSTAT,
+ SMB_VFS_OP_LSTAT,
+ SMB_VFS_OP_UNLINK,
+ SMB_VFS_OP_CHMOD,
+ SMB_VFS_OP_FCHMOD,
+ SMB_VFS_OP_CHOWN,
+ SMB_VFS_OP_FCHOWN,
+ SMB_VFS_OP_LCHOWN,
+ SMB_VFS_OP_CHDIR,
+ SMB_VFS_OP_GETWD,
+ SMB_VFS_OP_NTIMES,
+ SMB_VFS_OP_FTRUNCATE,
+ SMB_VFS_OP_LOCK,
+ SMB_VFS_OP_KERNEL_FLOCK,
+ SMB_VFS_OP_LINUX_SETLEASE,
+ SMB_VFS_OP_GETLOCK,
+ SMB_VFS_OP_SYMLINK,
+ SMB_VFS_OP_READLINK,
+ SMB_VFS_OP_LINK,
+ SMB_VFS_OP_MKNOD,
+ SMB_VFS_OP_REALPATH,
+ SMB_VFS_OP_NOTIFY_WATCH,
+ SMB_VFS_OP_CHFLAGS,
+ SMB_VFS_OP_FILE_ID_CREATE,
+ SMB_VFS_OP_STREAMINFO,
+
+ /* NT ACL operations. */
+
+ SMB_VFS_OP_FGET_NT_ACL,
+ SMB_VFS_OP_GET_NT_ACL,
+ SMB_VFS_OP_FSET_NT_ACL,
+
+ /* POSIX ACL operations. */
+
+ SMB_VFS_OP_CHMOD_ACL,
+ SMB_VFS_OP_FCHMOD_ACL,
+
+ SMB_VFS_OP_SYS_ACL_GET_ENTRY,
+ SMB_VFS_OP_SYS_ACL_GET_TAG_TYPE,
+ SMB_VFS_OP_SYS_ACL_GET_PERMSET,
+ SMB_VFS_OP_SYS_ACL_GET_QUALIFIER,
+ SMB_VFS_OP_SYS_ACL_GET_FILE,
+ SMB_VFS_OP_SYS_ACL_GET_FD,
+ SMB_VFS_OP_SYS_ACL_CLEAR_PERMS,
+ SMB_VFS_OP_SYS_ACL_ADD_PERM,
+ SMB_VFS_OP_SYS_ACL_TO_TEXT,
+ SMB_VFS_OP_SYS_ACL_INIT,
+ SMB_VFS_OP_SYS_ACL_CREATE_ENTRY,
+ SMB_VFS_OP_SYS_ACL_SET_TAG_TYPE,
+ SMB_VFS_OP_SYS_ACL_SET_QUALIFIER,
+ SMB_VFS_OP_SYS_ACL_SET_PERMSET,
+ SMB_VFS_OP_SYS_ACL_VALID,
+ SMB_VFS_OP_SYS_ACL_SET_FILE,
+ SMB_VFS_OP_SYS_ACL_SET_FD,
+ SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
+ SMB_VFS_OP_SYS_ACL_GET_PERM,
+ SMB_VFS_OP_SYS_ACL_FREE_TEXT,
+ SMB_VFS_OP_SYS_ACL_FREE_ACL,
+ SMB_VFS_OP_SYS_ACL_FREE_QUALIFIER,
+
+ /* EA operations. */
+ SMB_VFS_OP_GETXATTR,
+ SMB_VFS_OP_LGETXATTR,
+ SMB_VFS_OP_FGETXATTR,
+ SMB_VFS_OP_LISTXATTR,
+ SMB_VFS_OP_LLISTXATTR,
+ SMB_VFS_OP_FLISTXATTR,
+ SMB_VFS_OP_REMOVEXATTR,
+ SMB_VFS_OP_LREMOVEXATTR,
+ SMB_VFS_OP_FREMOVEXATTR,
+ SMB_VFS_OP_SETXATTR,
+ SMB_VFS_OP_LSETXATTR,
+ SMB_VFS_OP_FSETXATTR,
+
+ /* aio operations */
+ SMB_VFS_OP_AIO_READ,
+ SMB_VFS_OP_AIO_WRITE,
+ SMB_VFS_OP_AIO_RETURN,
+ SMB_VFS_OP_AIO_CANCEL,
+ SMB_VFS_OP_AIO_ERROR,
+ SMB_VFS_OP_AIO_FSYNC,
+ SMB_VFS_OP_AIO_SUSPEND,
+ SMB_VFS_OP_AIO_FORCE,
+
+ /* offline operations */
+ SMB_VFS_OP_IS_OFFLINE,
+ SMB_VFS_OP_SET_OFFLINE,
+
+ /* This should always be last enum value */
+
+ SMB_VFS_OP_LAST
+} vfs_op_type;
+
+/*
+ Please keep vfs_op_type, struct vfs_fn_pointers and struct vfs_handles_pointers in sync.
+*/
+struct vfs_ops {
+ struct vfs_fn_pointers {
+ /* Disk operations */
+
+ int (*connect_fn)(struct vfs_handle_struct *handle, const char *service, const char *user);
+ void (*disconnect)(struct vfs_handle_struct *handle);
+ SMB_BIG_UINT (*disk_free)(struct vfs_handle_struct *handle, const char *path, bool small_query, SMB_BIG_UINT *bsize,
+ SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
+ int (*get_quota)(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt);
+ int (*set_quota)(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt);
+ int (*get_shadow_copy_data)(struct vfs_handle_struct *handle, struct files_struct *fsp, SHADOW_COPY_DATA *shadow_copy_data, bool labels);
+ int (*statvfs)(struct vfs_handle_struct *handle, const char *path, struct vfs_statvfs_struct *statbuf);
+ uint32_t (*fs_capabilities)(struct vfs_handle_struct *handle);
+
+ /* Directory operations */
+
+ SMB_STRUCT_DIR *(*opendir)(struct vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attributes);
+ SMB_STRUCT_DIRENT *(*readdir)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp);
+ void (*seekdir)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp, long offset);
+ long (*telldir)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp);
+ void (*rewind_dir)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp);
+ int (*mkdir)(struct vfs_handle_struct *handle, const char *path, mode_t mode);
+ int (*rmdir)(struct vfs_handle_struct *handle, const char *path);
+ int (*closedir)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dir);
+
+ /* File operations */
+
+ int (*open)(struct vfs_handle_struct *handle, const char *fname, files_struct *fsp, int flags, mode_t mode);
+ int (*close_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp);
+ ssize_t (*vfs_read)(struct vfs_handle_struct *handle, struct files_struct *fsp, void *data, size_t n);
+ ssize_t (*pread)(struct vfs_handle_struct *handle, struct files_struct *fsp, void *data, size_t n, SMB_OFF_T offset);
+ ssize_t (*write)(struct vfs_handle_struct *handle, struct files_struct *fsp, const void *data, size_t n);
+ ssize_t (*pwrite)(struct vfs_handle_struct *handle, struct files_struct *fsp, const void *data, size_t n, SMB_OFF_T offset);
+ SMB_OFF_T (*lseek)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_OFF_T offset, int whence);
+ ssize_t (*sendfile)(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *header, SMB_OFF_T offset, size_t count);
+ ssize_t (*recvfile)(struct vfs_handle_struct *handle, int fromfd, files_struct *tofsp, SMB_OFF_T offset, size_t count);
+ int (*rename)(struct vfs_handle_struct *handle, const char *oldname, const char *newname);
+ int (*fsync)(struct vfs_handle_struct *handle, struct files_struct *fsp);
+ int (*stat)(struct vfs_handle_struct *handle, const char *fname, SMB_STRUCT_STAT *sbuf);
+ int (*fstat)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_STAT *sbuf);
+ int (*lstat)(struct vfs_handle_struct *handle, const char *path, SMB_STRUCT_STAT *sbuf);
+ int (*unlink)(struct vfs_handle_struct *handle, const char *path);
+ int (*chmod)(struct vfs_handle_struct *handle, const char *path, mode_t mode);
+ int (*fchmod)(struct vfs_handle_struct *handle, struct files_struct *fsp, mode_t mode);
+ int (*chown)(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid);
+ int (*fchown)(struct vfs_handle_struct *handle, struct files_struct *fsp, uid_t uid, gid_t gid);
+ int (*lchown)(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid);
+ int (*chdir)(struct vfs_handle_struct *handle, const char *path);
+ char *(*getwd)(struct vfs_handle_struct *handle, char *buf);
+ int (*ntimes)(struct vfs_handle_struct *handle, const char *path, const struct timespec ts[2]);
+ int (*ftruncate)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_OFF_T offset);
+ bool (*lock)(struct vfs_handle_struct *handle, struct files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
+ int (*kernel_flock)(struct vfs_handle_struct *handle, struct files_struct *fsp, uint32 share_mode);
+ int (*linux_setlease)(struct vfs_handle_struct *handle, struct files_struct *fsp, int leasetype);
+ bool (*getlock)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid);
+ int (*symlink)(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath);
+ int (*vfs_readlink)(struct vfs_handle_struct *handle, const char *path, char *buf, size_t bufsiz);
+ int (*link)(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath);
+ int (*mknod)(struct vfs_handle_struct *handle, const char *path, mode_t mode, SMB_DEV_T dev);
+ char *(*realpath)(struct vfs_handle_struct *handle, const char *path, char *resolved_path);
+ NTSTATUS (*notify_watch)(struct vfs_handle_struct *handle,
+ struct sys_notify_context *ctx,
+ struct notify_entry *e,
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev),
+ void *private_data, void *handle_p);
+ int (*chflags)(struct vfs_handle_struct *handle, const char *path, unsigned int flags);
+ struct file_id (*file_id_create)(struct vfs_handle_struct *handle, SMB_DEV_T dev, SMB_INO_T inode);
+
+ NTSTATUS (*streaminfo)(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *fname,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *num_streams,
+ struct stream_struct **streams);
+
+ /* NT ACL operations. */
+
+ NTSTATUS (*fget_nt_acl)(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32 security_info,
+ struct security_descriptor **ppdesc);
+ NTSTATUS (*get_nt_acl)(struct vfs_handle_struct *handle,
+ const char *name,
+ uint32 security_info,
+ struct security_descriptor **ppdesc);
+ NTSTATUS (*fset_nt_acl)(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32 security_info_sent,
+ struct security_descriptor *psd);
+
+ /* POSIX ACL operations. */
+
+ int (*chmod_acl)(struct vfs_handle_struct *handle, const char *name, mode_t mode);
+ int (*fchmod_acl)(struct vfs_handle_struct *handle, struct files_struct *fsp, mode_t mode);
+
+ int (*sys_acl_get_entry)(struct vfs_handle_struct *handle, SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p);
+ int (*sys_acl_get_tag_type)(struct vfs_handle_struct *handle, SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p);
+ int (*sys_acl_get_permset)(struct vfs_handle_struct *handle, SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p);
+ void * (*sys_acl_get_qualifier)(struct vfs_handle_struct *handle, SMB_ACL_ENTRY_T entry_d);
+ SMB_ACL_T (*sys_acl_get_file)(struct vfs_handle_struct *handle, const char *path_p, SMB_ACL_TYPE_T type);
+ SMB_ACL_T (*sys_acl_get_fd)(struct vfs_handle_struct *handle, struct files_struct *fsp);
+ int (*sys_acl_clear_perms)(struct vfs_handle_struct *handle, SMB_ACL_PERMSET_T permset);
+ int (*sys_acl_add_perm)(struct vfs_handle_struct *handle, SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
+ char * (*sys_acl_to_text)(struct vfs_handle_struct *handle, SMB_ACL_T theacl, ssize_t *plen);
+ SMB_ACL_T (*sys_acl_init)(struct vfs_handle_struct *handle, int count);
+ int (*sys_acl_create_entry)(struct vfs_handle_struct *handle, SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry);
+ int (*sys_acl_set_tag_type)(struct vfs_handle_struct *handle, SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype);
+ int (*sys_acl_set_qualifier)(struct vfs_handle_struct *handle, SMB_ACL_ENTRY_T entry, void *qual);
+ int (*sys_acl_set_permset)(struct vfs_handle_struct *handle, SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset);
+ int (*sys_acl_valid)(struct vfs_handle_struct *handle, SMB_ACL_T theacl );
+ int (*sys_acl_set_file)(struct vfs_handle_struct *handle, const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl);
+ int (*sys_acl_set_fd)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_ACL_T theacl);
+ int (*sys_acl_delete_def_file)(struct vfs_handle_struct *handle, const char *path);
+ int (*sys_acl_get_perm)(struct vfs_handle_struct *handle, SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
+ int (*sys_acl_free_text)(struct vfs_handle_struct *handle, char *text);
+ int (*sys_acl_free_acl)(struct vfs_handle_struct *handle, SMB_ACL_T posix_acl);
+ int (*sys_acl_free_qualifier)(struct vfs_handle_struct *handle, void *qualifier, SMB_ACL_TAG_T tagtype);
+
+ /* EA operations. */
+ ssize_t (*getxattr)(struct vfs_handle_struct *handle,const char *path, const char *name, void *value, size_t size);
+ ssize_t (*lgetxattr)(struct vfs_handle_struct *handle,const char *path, const char *name, void *value, size_t size);
+ ssize_t (*fgetxattr)(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size);
+ ssize_t (*listxattr)(struct vfs_handle_struct *handle, const char *path, char *list, size_t size);
+ ssize_t (*llistxattr)(struct vfs_handle_struct *handle, const char *path, char *list, size_t size);
+ ssize_t (*flistxattr)(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size);
+ int (*removexattr)(struct vfs_handle_struct *handle, const char *path, const char *name);
+ int (*lremovexattr)(struct vfs_handle_struct *handle, const char *path, const char *name);
+ int (*fremovexattr)(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name);
+ int (*setxattr)(struct vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags);
+ int (*lsetxattr)(struct vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags);
+ int (*fsetxattr)(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags);
+
+ /* aio operations */
+ int (*aio_read)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
+ int (*aio_write)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
+ ssize_t (*aio_return_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
+ int (*aio_cancel)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
+ int (*aio_error_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
+ int (*aio_fsync)(struct vfs_handle_struct *handle, struct files_struct *fsp, int op, SMB_STRUCT_AIOCB *aiocb);
+ int (*aio_suspend)(struct vfs_handle_struct *handle, struct files_struct *fsp, const SMB_STRUCT_AIOCB * const aiocb[], int n, const struct timespec *timeout);
+ bool (*aio_force)(struct vfs_handle_struct *handle, struct files_struct *fsp);
+
+ /* offline operations */
+ bool (*is_offline)(struct vfs_handle_struct *handle, const char *path, SMB_STRUCT_STAT *sbuf);
+ int (*set_offline)(struct vfs_handle_struct *handle, const char *path);
+ } ops;
+
+ struct vfs_handles_pointers {
+ /* Disk operations */
+
+ struct vfs_handle_struct *connect_hnd;
+ struct vfs_handle_struct *disconnect;
+ struct vfs_handle_struct *disk_free;
+ struct vfs_handle_struct *get_quota;
+ struct vfs_handle_struct *set_quota;
+ struct vfs_handle_struct *get_shadow_copy_data;
+ struct vfs_handle_struct *statvfs;
+ struct vfs_handle_struct *fs_capabilities;
+
+ /* Directory operations */
+
+ struct vfs_handle_struct *opendir;
+ struct vfs_handle_struct *readdir;
+ struct vfs_handle_struct *seekdir;
+ struct vfs_handle_struct *telldir;
+ struct vfs_handle_struct *rewind_dir;
+ struct vfs_handle_struct *mkdir;
+ struct vfs_handle_struct *rmdir;
+ struct vfs_handle_struct *closedir;
+
+ /* File operations */
+
+ struct vfs_handle_struct *open;
+ struct vfs_handle_struct *close_hnd;
+ struct vfs_handle_struct *vfs_read;
+ struct vfs_handle_struct *pread;
+ struct vfs_handle_struct *write;
+ struct vfs_handle_struct *pwrite;
+ struct vfs_handle_struct *lseek;
+ struct vfs_handle_struct *sendfile;
+ struct vfs_handle_struct *recvfile;
+ struct vfs_handle_struct *rename;
+ struct vfs_handle_struct *fsync;
+ struct vfs_handle_struct *stat;
+ struct vfs_handle_struct *fstat;
+ struct vfs_handle_struct *lstat;
+ struct vfs_handle_struct *unlink;
+ struct vfs_handle_struct *chmod;
+ struct vfs_handle_struct *fchmod;
+ struct vfs_handle_struct *chown;
+ struct vfs_handle_struct *fchown;
+ struct vfs_handle_struct *lchown;
+ struct vfs_handle_struct *chdir;
+ struct vfs_handle_struct *getwd;
+ struct vfs_handle_struct *ntimes;
+ struct vfs_handle_struct *ftruncate;
+ struct vfs_handle_struct *lock;
+ struct vfs_handle_struct *kernel_flock;
+ struct vfs_handle_struct *linux_setlease;
+ struct vfs_handle_struct *getlock;
+ struct vfs_handle_struct *symlink;
+ struct vfs_handle_struct *vfs_readlink;
+ struct vfs_handle_struct *link;
+ struct vfs_handle_struct *mknod;
+ struct vfs_handle_struct *realpath;
+ struct vfs_handle_struct *notify_watch;
+ struct vfs_handle_struct *chflags;
+ struct vfs_handle_struct *file_id_create;
+ struct vfs_handle_struct *streaminfo;
+
+ /* NT ACL operations. */
+
+ struct vfs_handle_struct *fget_nt_acl;
+ struct vfs_handle_struct *get_nt_acl;
+ struct vfs_handle_struct *fset_nt_acl;
+
+ /* POSIX ACL operations. */
+
+ struct vfs_handle_struct *chmod_acl;
+ struct vfs_handle_struct *fchmod_acl;
+
+ struct vfs_handle_struct *sys_acl_get_entry;
+ struct vfs_handle_struct *sys_acl_get_tag_type;
+ struct vfs_handle_struct *sys_acl_get_permset;
+ struct vfs_handle_struct *sys_acl_get_qualifier;
+ struct vfs_handle_struct *sys_acl_get_file;
+ struct vfs_handle_struct *sys_acl_get_fd;
+ struct vfs_handle_struct *sys_acl_clear_perms;
+ struct vfs_handle_struct *sys_acl_add_perm;
+ struct vfs_handle_struct *sys_acl_to_text;
+ struct vfs_handle_struct *sys_acl_init;
+ struct vfs_handle_struct *sys_acl_create_entry;
+ struct vfs_handle_struct *sys_acl_set_tag_type;
+ struct vfs_handle_struct *sys_acl_set_qualifier;
+ struct vfs_handle_struct *sys_acl_set_permset;
+ struct vfs_handle_struct *sys_acl_valid;
+ struct vfs_handle_struct *sys_acl_set_file;
+ struct vfs_handle_struct *sys_acl_set_fd;
+ struct vfs_handle_struct *sys_acl_delete_def_file;
+ struct vfs_handle_struct *sys_acl_get_perm;
+ struct vfs_handle_struct *sys_acl_free_text;
+ struct vfs_handle_struct *sys_acl_free_acl;
+ struct vfs_handle_struct *sys_acl_free_qualifier;
+
+ /* EA operations. */
+ struct vfs_handle_struct *getxattr;
+ struct vfs_handle_struct *lgetxattr;
+ struct vfs_handle_struct *fgetxattr;
+ struct vfs_handle_struct *listxattr;
+ struct vfs_handle_struct *llistxattr;
+ struct vfs_handle_struct *flistxattr;
+ struct vfs_handle_struct *removexattr;
+ struct vfs_handle_struct *lremovexattr;
+ struct vfs_handle_struct *fremovexattr;
+ struct vfs_handle_struct *setxattr;
+ struct vfs_handle_struct *lsetxattr;
+ struct vfs_handle_struct *fsetxattr;
+
+ /* aio operations */
+ struct vfs_handle_struct *aio_read;
+ struct vfs_handle_struct *aio_write;
+ struct vfs_handle_struct *aio_return;
+ struct vfs_handle_struct *aio_cancel;
+ struct vfs_handle_struct *aio_error;
+ struct vfs_handle_struct *aio_fsync;
+ struct vfs_handle_struct *aio_suspend;
+ struct vfs_handle_struct *aio_force;
+
+ /* offline operations */
+ struct vfs_handle_struct *is_offline;
+ struct vfs_handle_struct *set_offline;
+ } handles;
+};
+
+/*
+ Possible VFS operation layers (per-operation)
+
+ These values are used by VFS subsystem when building vfs_ops for connection
+ from multiple VFS modules. Internally, Samba differentiates only opaque and
+ transparent layers at this process. Other types are used for providing better
+ diagnosing facilities.
+
+ Most modules will provide transparent layers. Opaque layer is for modules
+ which implement actual file system calls (like DB-based VFS). For example,
+ default POSIX VFS which is built in into Samba is an opaque VFS module.
+
+ Other layer types (audit, splitter, scanner) were designed to provide different
+ degree of transparency and for diagnosing VFS module behaviour.
+
+ Each module can implement several layers at the same time provided that only
+ one layer is used per each operation.
+
+*/
+
+typedef enum _vfs_op_layer {
+ SMB_VFS_LAYER_NOOP = -1, /* - For using in VFS module to indicate end of array */
+ /* of operations description */
+ SMB_VFS_LAYER_OPAQUE = 0, /* - Final level, does not call anything beyond itself */
+ SMB_VFS_LAYER_TRANSPARENT, /* - Normal operation, calls underlying layer after */
+ /* possibly changing passed data */
+ SMB_VFS_LAYER_LOGGER, /* - Logs data, calls underlying layer, logging may not */
+ /* use Samba VFS */
+ SMB_VFS_LAYER_SPLITTER, /* - Splits operation, calls underlying layer _and_ own facility, */
+ /* then combines result */
+ SMB_VFS_LAYER_SCANNER /* - Checks data and possibly initiates additional */
+ /* file activity like logging to files _inside_ samba VFS */
+} vfs_op_layer;
+
+/*
+ VFS operation description. Each VFS module registers an array of vfs_op_tuple to VFS subsystem,
+ which describes all operations this module is willing to intercept.
+ VFS subsystem initializes then the conn->vfs_ops and conn->vfs_opaque_ops structs
+ using this information.
+*/
+
+typedef struct vfs_op_tuple {
+ void* op;
+ vfs_op_type type;
+ vfs_op_layer layer;
+} vfs_op_tuple;
+
+
+typedef struct vfs_handle_struct {
+ struct vfs_handle_struct *next, *prev;
+ const char *param;
+ struct vfs_ops vfs_next;
+ struct connection_struct *conn;
+ void *data;
+ void (*free_data)(void **data);
+} vfs_handle_struct;
+
+
+typedef struct vfs_statvfs_struct {
+ /* For undefined recommended transfer size return -1 in that field */
+ uint32 OptimalTransferSize; /* bsize on some os, iosize on other os */
+ uint32 BlockSize;
+
+ /*
+ The next three fields are in terms of the block size.
+ (above). If block size is unknown, 4096 would be a
+ reasonable block size for a server to report.
+ Note that returning the blocks/blocksavail removes need
+ to make a second call (to QFSInfo level 0x103 to get this info.
+ UserBlockAvail is typically less than or equal to BlocksAvail,
+ if no distinction is made return the same value in each.
+ */
+
+ SMB_BIG_UINT TotalBlocks;
+ SMB_BIG_UINT BlocksAvail; /* bfree */
+ SMB_BIG_UINT UserBlocksAvail; /* bavail */
+
+ /* For undefined Node fields or FSID return -1 */
+ SMB_BIG_UINT TotalFileNodes;
+ SMB_BIG_UINT FreeFileNodes;
+ SMB_BIG_UINT FsIdentifier; /* fsid */
+ /* NB Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call */
+ /* NB flags can come from FILE_SYSTEM_DEVICE_INFO call */
+
+ int FsCapabilities;
+} vfs_statvfs_struct;
+
+/* Add a new FSP extension of the given type. Returns a pointer to the
+ * extenstion data.
+ */
+#define VFS_ADD_FSP_EXTENSION(handle, fsp, type) \
+ vfs_add_fsp_extension_notype(handle, (fsp), sizeof(type))
+
+/* Return a pointer to the existing FSP extension data. */
+#define VFS_FETCH_FSP_EXTENSION(handle, fsp) \
+ vfs_fetch_fsp_extension(handle, (fsp))
+
+/* Return the talloc context associated with an FSP extension. */
+#define VFS_MEMCTX_FSP_EXTENSION(handle, fsp) \
+ vfs_memctx_fsp_extension(handle, (fsp))
+
+/* Remove and destroy an FSP extension. */
+#define VFS_REMOVE_FSP_EXTENSION(handle, fsp) \
+ vfs_remove_fsp_extension((handle), (fsp))
+
+#define SMB_VFS_HANDLE_GET_DATA(handle, datap, type, ret) { \
+ if (!(handle)||((datap=(type *)(handle)->data)==NULL)) { \
+ DEBUG(0,("%s() failed to get vfs_handle->data!\n",FUNCTION_MACRO)); \
+ ret; \
+ } \
+}
+
+#define SMB_VFS_HANDLE_SET_DATA(handle, datap, free_fn, type, ret) { \
+ if (!(handle)) { \
+ DEBUG(0,("%s() failed to set handle->data!\n",FUNCTION_MACRO)); \
+ ret; \
+ } else { \
+ if ((handle)->free_data) { \
+ (handle)->free_data(&(handle)->data); \
+ } \
+ (handle)->data = (void *)datap; \
+ (handle)->free_data = free_fn; \
+ } \
+}
+
+#define SMB_VFS_HANDLE_FREE_DATA(handle) { \
+ if ((handle) && (handle)->free_data) { \
+ (handle)->free_data(&(handle)->data); \
+ } \
+}
+
+/* Check whether module-specific data handle was already allocated or not */
+#define SMB_VFS_HANDLE_TEST_DATA(handle) ( !(handle) || !(handle)->data ? False : True )
+
+#define SMB_VFS_OP(x) ((void *) x)
+
+#define DEFAULT_VFS_MODULE_NAME "/[Default VFS]/"
+
+#include "vfs_macros.h"
+
+#endif /* _VFS_H */
diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h
new file mode 100644
index 0000000000..7b3aeaa2c7
--- /dev/null
+++ b/source3/include/vfs_macros.h
@@ -0,0 +1,399 @@
+/*
+ Unix SMB/CIFS implementation.
+ VFS wrapper macros
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _VFS_MACROS_H
+#define _VFS_MACROS_H
+
+/*******************************************************************
+ Don't access conn->vfs.ops.* directly!!!
+ Use this macros!
+ (Fixes should go also into the vfs_opaque_* and vfs_next_* macros!)
+********************************************************************/
+
+/* Disk operations */
+#define SMB_VFS_CONNECT(conn, service, user) ((conn)->vfs.ops.connect_fn((conn)->vfs.handles.connect_hnd, (service), (user)))
+#define SMB_VFS_DISCONNECT(conn) ((conn)->vfs.ops.disconnect((conn)->vfs.handles.disconnect))
+#define SMB_VFS_DISK_FREE(conn, path, small_query, bsize, dfree ,dsize) ((conn)->vfs.ops.disk_free((conn)->vfs.handles.disk_free, (path), (small_query), (bsize), (dfree), (dsize)))
+#define SMB_VFS_GET_QUOTA(conn, qtype, id, qt) ((conn)->vfs.ops.get_quota((conn)->vfs.handles.get_quota, (qtype), (id), (qt)))
+#define SMB_VFS_SET_QUOTA(conn, qtype, id, qt) ((conn)->vfs.ops.set_quota((conn)->vfs.handles.set_quota, (qtype), (id), (qt)))
+#define SMB_VFS_GET_SHADOW_COPY_DATA(fsp,shadow_copy_data,labels) ((fsp)->conn->vfs.ops.get_shadow_copy_data((fsp)->conn->vfs.handles.get_shadow_copy_data,(fsp),(shadow_copy_data),(labels)))
+#define SMB_VFS_STATVFS(conn, path, statbuf) ((conn)->vfs.ops.statvfs((conn)->vfs.handles.statvfs, (path), (statbuf)))
+#define SMB_VFS_FS_CAPABILITIES(conn) ((conn)->vfs.ops.fs_capabilities((conn)->vfs.handles.fs_capabilities))
+
+/* Directory operations */
+#define SMB_VFS_OPENDIR(conn, fname, mask, attr) ((conn)->vfs.ops.opendir((conn)->vfs.handles.opendir, (fname), (mask), (attr)))
+#define SMB_VFS_READDIR(conn, dirp) ((conn)->vfs.ops.readdir((conn)->vfs.handles.readdir, (dirp)))
+#define SMB_VFS_SEEKDIR(conn, dirp, offset) ((conn)->vfs.ops.seekdir((conn)->vfs.handles.seekdir, (dirp), (offset)))
+#define SMB_VFS_TELLDIR(conn, dirp) ((conn)->vfs.ops.telldir((conn)->vfs.handles.telldir, (dirp)))
+#define SMB_VFS_REWINDDIR(conn, dirp) ((conn)->vfs.ops.rewind_dir((conn)->vfs.handles.rewind_dir, (dirp)))
+#define SMB_VFS_MKDIR(conn, path, mode) ((conn)->vfs.ops.mkdir((conn)->vfs.handles.mkdir,(path), (mode)))
+#define SMB_VFS_RMDIR(conn, path) ((conn)->vfs.ops.rmdir((conn)->vfs.handles.rmdir, (path)))
+#define SMB_VFS_CLOSEDIR(conn, dir) ((conn)->vfs.ops.closedir((conn)->vfs.handles.closedir, dir))
+
+/* File operations */
+#define SMB_VFS_OPEN(conn, fname, fsp, flags, mode) (((conn)->vfs.ops.open)((conn)->vfs.handles.open, (fname), (fsp), (flags), (mode)))
+#define SMB_VFS_CLOSE(fsp) ((fsp)->conn->vfs.ops.close_fn((fsp)->conn->vfs.handles.close_hnd, (fsp)))
+#define SMB_VFS_READ(fsp, data, n) ((fsp)->conn->vfs.ops.vfs_read((fsp)->conn->vfs.handles.vfs_read, (fsp), (data), (n)))
+#define SMB_VFS_PREAD(fsp, data, n, off) ((fsp)->conn->vfs.ops.pread((fsp)->conn->vfs.handles.pread, (fsp), (data), (n), (off)))
+#define SMB_VFS_WRITE(fsp, data, n) ((fsp)->conn->vfs.ops.write((fsp)->conn->vfs.handles.write, (fsp), (data), (n)))
+#define SMB_VFS_PWRITE(fsp, data, n, off) ((fsp)->conn->vfs.ops.pwrite((fsp)->conn->vfs.handles.pwrite, (fsp), (data), (n), (off)))
+#define SMB_VFS_LSEEK(fsp, offset, whence) ((fsp)->conn->vfs.ops.lseek((fsp)->conn->vfs.handles.lseek, (fsp), (offset), (whence)))
+#define SMB_VFS_SENDFILE(tofd, fromfsp, header, offset, count) ((fsp)->conn->vfs.ops.sendfile((fsp)->conn->vfs.handles.sendfile, (tofd), (fromfsp), (header), (offset), (count)))
+#define SMB_VFS_RECVFILE(fromfd, tofsp, offset, count) ((fsp)->conn->vfs.ops.recvfile((fsp)->conn->vfs.handles.recvfile, (fromfd), (tofsp), (offset), (count)))
+#define SMB_VFS_RENAME(conn, old, new) ((conn)->vfs.ops.rename((conn)->vfs.handles.rename, (old), (new)))
+#define SMB_VFS_FSYNC(fsp) ((fsp)->conn->vfs.ops.fsync((fsp)->conn->vfs.handles.fsync, (fsp)))
+#define SMB_VFS_STAT(conn, fname, sbuf) ((conn)->vfs.ops.stat((conn)->vfs.handles.stat, (fname), (sbuf)))
+#define SMB_VFS_FSTAT(fsp, sbuf) ((fsp)->conn->vfs.ops.fstat((fsp)->conn->vfs.handles.fstat, (fsp), (sbuf)))
+#define SMB_VFS_LSTAT(conn, path, sbuf) ((conn)->vfs.ops.lstat((conn)->vfs.handles.lstat, (path), (sbuf)))
+#define SMB_VFS_UNLINK(conn, path) ((conn)->vfs.ops.unlink((conn)->vfs.handles.unlink, (path)))
+#define SMB_VFS_CHMOD(conn, path, mode) ((conn)->vfs.ops.chmod((conn)->vfs.handles.chmod, (path), (mode)))
+#define SMB_VFS_FCHMOD(fsp, mode) ((fsp)->conn->vfs.ops.fchmod((fsp)->conn->vfs.handles.fchmod, (fsp), (mode)))
+#define SMB_VFS_CHOWN(conn, path, uid, gid) ((conn)->vfs.ops.chown((conn)->vfs.handles.chown, (path), (uid), (gid)))
+#define SMB_VFS_FCHOWN(fsp, uid, gid) ((fsp)->conn->vfs.ops.fchown((fsp)->conn->vfs.handles.fchown, (fsp), (uid), (gid)))
+#define SMB_VFS_LCHOWN(conn, path, uid, gid) ((conn)->vfs.ops.lchown((conn)->vfs.handles.lchown, (path), (uid), (gid)))
+#define SMB_VFS_CHDIR(conn, path) ((conn)->vfs.ops.chdir((conn)->vfs.handles.chdir, (path)))
+#define SMB_VFS_GETWD(conn, buf) ((conn)->vfs.ops.getwd((conn)->vfs.handles.getwd, (buf)))
+#define SMB_VFS_NTIMES(conn, path, ts) ((conn)->vfs.ops.ntimes((conn)->vfs.handles.ntimes, (path), (ts)))
+#define SMB_VFS_FTRUNCATE(fsp, offset) ((fsp)->conn->vfs.ops.ftruncate((fsp)->conn->vfs.handles.ftruncate, (fsp), (offset)))
+#define SMB_VFS_LOCK(fsp, op, offset, count, type) ((fsp)->conn->vfs.ops.lock((fsp)->conn->vfs.handles.lock, (fsp), (op), (offset), (count), (type)))
+#define SMB_VFS_KERNEL_FLOCK(fsp, share_mode) ((fsp)->conn->vfs.ops.kernel_flock((fsp)->conn->vfs.handles.kernel_flock, (fsp), (share_mode)))
+#define SMB_VFS_LINUX_SETLEASE(fsp, leasetype) ((fsp)->conn->vfs.ops.linux_setlease((fsp)->conn->vfs.handles.linux_setlease, (fsp), (leasetype)))
+#define SMB_VFS_GETLOCK(fsp, poffset, pcount, ptype, ppid) ((fsp)->conn->vfs.ops.getlock((fsp)->conn->vfs.handles.getlock, (fsp), (poffset), (pcount), (ptype), (ppid)))
+#define SMB_VFS_SYMLINK(conn, oldpath, newpath) ((conn)->vfs.ops.symlink((conn)->vfs.handles.symlink, (oldpath), (newpath)))
+#define SMB_VFS_READLINK(conn, path, buf, bufsiz) ((conn)->vfs.ops.vfs_readlink((conn)->vfs.handles.vfs_readlink, (path), (buf), (bufsiz)))
+#define SMB_VFS_LINK(conn, oldpath, newpath) ((conn)->vfs.ops.link((conn)->vfs.handles.link, (oldpath), (newpath)))
+#define SMB_VFS_MKNOD(conn, path, mode, dev) ((conn)->vfs.ops.mknod((conn)->vfs.handles.mknod, (path), (mode), (dev)))
+#define SMB_VFS_REALPATH(conn, path, resolved_path) ((conn)->vfs.ops.realpath((conn)->vfs.handles.realpath, (path), (resolved_path)))
+#define SMB_VFS_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs.ops.notify_watch((conn)->vfs.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p)))
+#define SMB_VFS_CHFLAGS(conn, path, flags) ((conn)->vfs.ops.chflags((conn)->vfs.handles.chflags, (path), (flags)))
+#define SMB_VFS_FILE_ID_CREATE(conn, dev, inode) ((conn)->vfs.ops.file_id_create((conn)->vfs.handles.file_id_create, (dev), (inode)))
+#define SMB_VFS_STREAMINFO(conn, fsp, fname, mem_ctx, num_streams, streams) ((conn)->vfs.ops.streaminfo((conn)->vfs.handles.streaminfo, (fsp), (fname), (mem_ctx), (num_streams), (streams)))
+
+/* NT ACL operations. */
+#define SMB_VFS_FGET_NT_ACL(fsp, security_info, ppdesc) ((fsp)->conn->vfs.ops.fget_nt_acl((fsp)->conn->vfs.handles.fget_nt_acl, (fsp), (security_info), (ppdesc)))
+#define SMB_VFS_GET_NT_ACL(conn, name, security_info, ppdesc) ((conn)->vfs.ops.get_nt_acl((conn)->vfs.handles.get_nt_acl, (name), (security_info), (ppdesc)))
+#define SMB_VFS_FSET_NT_ACL(fsp, security_info_sent, psd) ((fsp)->conn->vfs.ops.fset_nt_acl((fsp)->conn->vfs.handles.fset_nt_acl, (fsp), (security_info_sent), (psd)))
+
+/* POSIX ACL operations. */
+#define SMB_VFS_CHMOD_ACL(conn, name, mode) ((conn)->vfs.ops.chmod_acl((conn)->vfs.handles.chmod_acl, (name), (mode)))
+#define SMB_VFS_FCHMOD_ACL(fsp, mode) ((fsp)->conn->vfs.ops.fchmod_acl((fsp)->conn->vfs.handles.chmod_acl, (fsp), (mode)))
+
+#define SMB_VFS_SYS_ACL_GET_ENTRY(conn, theacl, entry_id, entry_p) ((conn)->vfs.ops.sys_acl_get_entry((conn)->vfs.handles.sys_acl_get_entry, (theacl), (entry_id), (entry_p)))
+#define SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry_d, tag_type_p) ((conn)->vfs.ops.sys_acl_get_tag_type((conn)->vfs.handles.sys_acl_get_tag_type, (entry_d), (tag_type_p)))
+#define SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry_d, permset_p) ((conn)->vfs.ops.sys_acl_get_permset((conn)->vfs.handles.sys_acl_get_permset, (entry_d), (permset_p)))
+#define SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry_d) ((conn)->vfs.ops.sys_acl_get_qualifier((conn)->vfs.handles.sys_acl_get_qualifier, (entry_d)))
+#define SMB_VFS_SYS_ACL_GET_FILE(conn, path_p, type) ((conn)->vfs.ops.sys_acl_get_file((conn)->vfs.handles.sys_acl_get_file, (path_p), (type)))
+#define SMB_VFS_SYS_ACL_GET_FD(fsp) ((fsp)->conn->vfs.ops.sys_acl_get_fd((fsp)->conn->vfs.handles.sys_acl_get_fd, (fsp)))
+#define SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, permset) ((conn)->vfs.ops.sys_acl_clear_perms((conn)->vfs.handles.sys_acl_clear_perms, (permset)))
+#define SMB_VFS_SYS_ACL_ADD_PERM(conn, permset, perm) ((conn)->vfs.ops.sys_acl_add_perm((conn)->vfs.handles.sys_acl_add_perm, (permset), (perm)))
+#define SMB_VFS_SYS_ACL_TO_TEXT(conn, theacl, plen) ((conn)->vfs.ops.sys_acl_to_text((conn)->vfs.handles.sys_acl_to_text, (theacl), (plen)))
+#define SMB_VFS_SYS_ACL_INIT(conn, count) ((conn)->vfs.ops.sys_acl_init((conn)->vfs.handles.sys_acl_init, (count)))
+#define SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, pacl, pentry) ((conn)->vfs.ops.sys_acl_create_entry((conn)->vfs.handles.sys_acl_create_entry, (pacl), (pentry)))
+#define SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, entry, tagtype) ((conn)->vfs.ops.sys_acl_set_tag_type((conn)->vfs.handles.sys_acl_set_tag_type, (entry), (tagtype)))
+#define SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, entry, qual) ((conn)->vfs.ops.sys_acl_set_qualifier((conn)->vfs.handles.sys_acl_set_qualifier, (entry), (qual)))
+#define SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) ((conn)->vfs.ops.sys_acl_set_permset((conn)->vfs.handles.sys_acl_set_permset, (entry), (permset)))
+#define SMB_VFS_SYS_ACL_VALID(conn, theacl) ((conn)->vfs.ops.sys_acl_valid((conn)->vfs.handles.sys_acl_valid, (theacl)))
+#define SMB_VFS_SYS_ACL_SET_FILE(conn, name, acltype, theacl) ((conn)->vfs.ops.sys_acl_set_file((conn)->vfs.handles.sys_acl_set_file, (name), (acltype), (theacl)))
+#define SMB_VFS_SYS_ACL_SET_FD(fsp, theacl) ((fsp)->conn->vfs.ops.sys_acl_set_fd((fsp)->conn->vfs.handles.sys_acl_set_fd, (fsp), (theacl)))
+#define SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, path) ((conn)->vfs.ops.sys_acl_delete_def_file((conn)->vfs.handles.sys_acl_delete_def_file, (path)))
+#define SMB_VFS_SYS_ACL_GET_PERM(conn, permset, perm) ((conn)->vfs.ops.sys_acl_get_perm((conn)->vfs.handles.sys_acl_get_perm, (permset), (perm)))
+#define SMB_VFS_SYS_ACL_FREE_TEXT(conn, text) ((conn)->vfs.ops.sys_acl_free_text((conn)->vfs.handles.sys_acl_free_text, (text)))
+#define SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl) ((conn)->vfs.ops.sys_acl_free_acl((conn)->vfs.handles.sys_acl_free_acl, (posix_acl)))
+#define SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, qualifier, tagtype) ((conn)->vfs.ops.sys_acl_free_qualifier((conn)->vfs.handles.sys_acl_free_qualifier, (qualifier), (tagtype)))
+
+/* EA operations. */
+#define SMB_VFS_GETXATTR(conn,path,name,value,size) ((conn)->vfs.ops.getxattr((conn)->vfs.handles.getxattr,(path),(name),(value),(size)))
+#define SMB_VFS_LGETXATTR(conn,path,name,value,size) ((conn)->vfs.ops.lgetxattr((conn)->vfs.handles.lgetxattr,(path),(name),(value),(size)))
+#define SMB_VFS_FGETXATTR(fsp,name,value,size) ((fsp)->conn->vfs.ops.fgetxattr((fsp)->conn->vfs.handles.fgetxattr,(fsp),(name),(value),(size)))
+#define SMB_VFS_LISTXATTR(conn,path,list,size) ((conn)->vfs.ops.listxattr((conn)->vfs.handles.listxattr,(path),(list),(size)))
+#define SMB_VFS_LLISTXATTR(conn,path,list,size) ((conn)->vfs.ops.llistxattr((conn)->vfs.handles.llistxattr,(path),(list),(size)))
+#define SMB_VFS_FLISTXATTR(fsp,list,size) ((fsp)->conn->vfs.ops.flistxattr((fsp)->conn->vfs.handles.flistxattr,(fsp),(list),(size)))
+#define SMB_VFS_REMOVEXATTR(conn,path,name) ((conn)->vfs.ops.removexattr((conn)->vfs.handles.removexattr,(path),(name)))
+#define SMB_VFS_LREMOVEXATTR(conn,path,name) ((conn)->vfs.ops.lremovexattr((conn)->vfs.handles.lremovexattr,(path),(name)))
+#define SMB_VFS_FREMOVEXATTR(fsp,name) ((fsp)->conn->vfs.ops.fremovexattr((fsp)->conn->vfs.handles.fremovexattr,(fsp),(name)))
+#define SMB_VFS_SETXATTR(conn,path,name,value,size,flags) ((conn)->vfs.ops.setxattr((conn)->vfs.handles.setxattr,(path),(name),(value),(size),(flags)))
+#define SMB_VFS_LSETXATTR(conn,path,name,value,size,flags) ((conn)->vfs.ops.lsetxattr((conn)->vfs.handles.lsetxattr,(path),(name),(value),(size),(flags)))
+#define SMB_VFS_FSETXATTR(fsp,name,value,size,flags) ((fsp)->conn->vfs.ops.fsetxattr((fsp)->conn->vfs.handles.fsetxattr,(fsp),(name),(value),(size),(flags)))
+
+/* AIO operations. */
+#define SMB_VFS_AIO_READ(fsp,aiocb) ((fsp)->conn->vfs.ops.aio_read((fsp)->conn->vfs.handles.aio_read,(fsp),(aiocb)))
+#define SMB_VFS_AIO_WRITE(fsp,aiocb) ((fsp)->conn->vfs.ops.aio_write((fsp)->conn->vfs.handles.aio_write,(fsp),(aiocb)))
+#define SMB_VFS_AIO_RETURN(fsp,aiocb) ((fsp)->conn->vfs.ops.aio_return_fn((fsp)->conn->vfs.handles.aio_return,(fsp),(aiocb)))
+#define SMB_VFS_AIO_CANCEL(fsp,aiocb) ((fsp)->conn->vfs.ops.aio_cancel((fsp)->conn->vfs.handles.aio_cancel,(fsp),(aiocb)))
+#define SMB_VFS_AIO_ERROR(fsp,aiocb) ((fsp)->conn->vfs.ops.aio_error_fn((fsp)->conn->vfs.handles.aio_error,(fsp),(aiocb)))
+#define SMB_VFS_AIO_FSYNC(fsp,op,aiocb) ((fsp)->conn->vfs.ops.aio_fsync((fsp)->conn->vfs.handles.aio_fsync,(fsp),(op),(aiocb)))
+#define SMB_VFS_AIO_SUSPEND(fsp,aiocb,n,ts) ((fsp)->conn->vfs.ops.aio_suspend((fsp)->conn->vfs.handles.aio_suspend,(fsp),(aiocb),(n),(ts)))
+#define SMB_VFS_AIO_FORCE(fsp) ((fsp)->conn->vfs.ops.aio_force((fsp)->conn->vfs.handles.aio_force,(fsp)))
+
+/* Offline operations */
+#define SMB_VFS_IS_OFFLINE(conn,path,sbuf) ((conn)->vfs.ops.is_offline((conn)->vfs.handles.is_offline,(path),(sbuf)))
+#define SMB_VFS_SET_OFFLINE(conn,path) ((conn)->vfs.ops.set_offline((conn)->vfs.handles.set_offline,(path)))
+
+/*******************************************************************
+ Don't access conn->vfs_opaque.ops directly!!!
+ Use this macros!
+ (Fixes should also go into the vfs_* and vfs_next_* macros!)
+********************************************************************/
+
+/* Disk operations */
+#define SMB_VFS_OPAQUE_CONNECT(conn, service, user) ((conn)->vfs_opaque.ops.connect_fn((conn)->vfs_opaque.handles.connect_hnd, (service), (user)))
+#define SMB_VFS_OPAQUE_DISCONNECT(conn) ((conn)->vfs_opaque.ops.disconnect((conn)->vfs_opaque.handles.disconnect))
+#define SMB_VFS_OPAQUE_DISK_FREE(conn, path, small_query, bsize, dfree ,dsize) ((conn)->vfs_opaque.ops.disk_free((conn)->vfs_opaque.handles.disk_free, (path), (small_query), (bsize), (dfree), (dsize)))
+#define SMB_VFS_OPAQUE_GET_QUOTA(conn, qtype, id, qt) ((conn)->vfs_opaque.ops.get_quota((conn)->vfs_opaque.handles.get_quota, (qtype), (id), (qt)))
+#define SMB_VFS_OPAQUE_SET_QUOTA(conn, qtype, id, qt) ((conn)->vfs_opaque.ops.set_quota((conn)->vfs_opaque.handles.set_quota, (qtype), (id), (qt)))
+#define SMB_VFS_OPAQUE_GET_SHADOW_COPY_DATA(fsp,shadow_copy_data,labels) ((fsp)->conn->vfs_opaque.ops.get_shadow_copy_data((fsp)->conn->vfs_opaque.handles.get_shadow_copy_data,(fsp),(shadow_copy_data),(labels)))
+#define SMB_VFS_OPAQUE_STATVFS(conn, path, statbuf) ((conn)->vfs_opaque.ops.statvfs((conn)->vfs_opaque.handles.statvfs, (path), (statbuf)))
+#define SMB_VFS_OPAQUE_FS_CAPABILITIES(conn) ((conn)->vfs_opaque.ops.fs_capabilities((conn)->vfs_opaque.handles.fs_capabilities))
+
+/* Directory operations */
+#define SMB_VFS_OPAQUE_OPENDIR(conn, fname, mask, attr) ((conn)->vfs_opaque.ops.opendir((conn)->vfs_opaque.handles.opendir, (fname), (mask), (attr)))
+#define SMB_VFS_OPAQUE_READDIR(conn, dirp) ((conn)->vfs_opaque.ops.readdir((conn)->vfs_opaque.handles.readdir, (dirp)))
+#define SMB_VFS_OPAQUE_SEEKDIR(conn, dirp, offset) ((conn)->vfs_opaque.ops.seekdir((conn)->vfs_opaque.handles.seekdir, (dirp), (offset)))
+#define SMB_VFS_OPAQUE_TELLDIR(conn, dirp) ((conn)->vfs_opaque.ops.telldir((conn)->vfs_opaque.handles.telldir, (dirp)))
+#define SMB_VFS_OPAQUE_REWINDDIR(conn, dirp) ((conn)->vfs_opaque.ops.rewind_dir((conn)->vfs_opaque.handles.rewind_dir, (dirp)))
+#define SMB_VFS_OPAQUE_MKDIR(conn, path, mode) ((conn)->vfs_opaque.ops.mkdir((conn)->vfs_opaque.handles.mkdir,(path), (mode)))
+#define SMB_VFS_OPAQUE_RMDIR(conn, path) ((conn)->vfs_opaque.ops.rmdir((conn)->vfs_opaque.handles.rmdir, (path)))
+#define SMB_VFS_OPAQUE_CLOSEDIR(conn, dir) ((conn)->vfs_opaque.ops.closedir((conn)->vfs_opaque.handles.closedir, dir))
+
+/* File operations */
+#define SMB_VFS_OPAQUE_OPEN(conn, fname, fsp, flags, mode) (((conn)->vfs_opaque.ops.open)((conn)->vfs_opaque.handles.open, (fname), (fsp), (flags), (mode)))
+#define SMB_VFS_OPAQUE_CLOSE(fsp) ((fsp)->conn->vfs_opaque.ops.close_fn((fsp)->conn->vfs_opaque.handles.close_hnd, (fsp)))
+#define SMB_VFS_OPAQUE_READ(fsp, data, n) ((fsp)->conn->vfs_opaque.ops.vfs_read((fsp)->conn->vfs_opaque.handles.vfs_read, (fsp), (data), (n)))
+#define SMB_VFS_OPAQUE_PREAD(fsp, data, n, off) ((fsp)->conn->vfs_opaque.ops.pread((fsp)->conn->vfs_opaque.handles.pread, (fsp), (data), (n), (off)))
+#define SMB_VFS_OPAQUE_WRITE(fsp, data, n) ((fsp)->conn->vfs_opaque.ops.write((fsp)->conn->vfs_opaque.handles.write, (fsp), (data), (n)))
+#define SMB_VFS_OPAQUE_PWRITE(fsp, data, n, off) ((fsp)->conn->vfs_opaque.ops.pwrite((fsp)->conn->vfs_opaque.handles.pwrite, (fsp), (data), (n), (off)))
+#define SMB_VFS_OPAQUE_LSEEK(fsp, offset, whence) ((fsp)->conn->vfs_opaque.ops.lseek((fsp)->conn->vfs_opaque.handles.lseek, (fsp), (offset), (whence)))
+#define SMB_VFS_OPAQUE_SENDFILE(tofd, fromfsp, header, offset, count) ((fsp)->conn->vfs_opaque.ops.sendfile((fsp)->conn->vfs_opaque.handles.sendfile, (tofd), (fromfsp), (header), (offset), (count)))
+#define SMB_VFS_OPAQUE_RECVFILE(fromfd, tofsp, offset, count) ((fsp)->conn->vfs_opaque.ops.recvfile((fsp)->conn->vfs_opaque.handles.recvfile, (fromfd), (tofsp), (offset), (count)))
+#define SMB_VFS_OPAQUE_RENAME(conn, old, new) ((conn)->vfs_opaque.ops.rename((conn)->vfs_opaque.handles.rename, (old), (new)))
+#define SMB_VFS_OPAQUE_FSYNC(fsp) ((fsp)->conn->vfs_opaque.ops.fsync((fsp)->conn->vfs_opaque.handles.fsync, (fsp)))
+#define SMB_VFS_OPAQUE_STAT(conn, fname, sbuf) ((conn)->vfs_opaque.ops.stat((conn)->vfs_opaque.handles.stat, (fname), (sbuf)))
+#define SMB_VFS_OPAQUE_FSTAT(fsp, sbuf) ((fsp)->conn->vfs_opaque.ops.fstat((fsp)->conn->vfs_opaque.handles.fstat, (fsp), (sbuf)))
+#define SMB_VFS_OPAQUE_LSTAT(conn, path, sbuf) ((conn)->vfs_opaque.ops.lstat((conn)->vfs_opaque.handles.lstat, (path), (sbuf)))
+#define SMB_VFS_OPAQUE_UNLINK(conn, path) ((conn)->vfs_opaque.ops.unlink((conn)->vfs_opaque.handles.unlink, (path)))
+#define SMB_VFS_OPAQUE_CHMOD(conn, path, mode) ((conn)->vfs_opaque.ops.chmod((conn)->vfs_opaque.handles.chmod, (path), (mode)))
+#define SMB_VFS_OPAQUE_FCHMOD(fsp, mode) ((fsp)->conn->vfs_opaque.ops.fchmod((fsp)->conn->vfs_opaque.handles.fchmod, (fsp), (mode)))
+#define SMB_VFS_OPAQUE_CHOWN(conn, path, uid, gid) ((conn)->vfs_opaque.ops.chown((conn)->vfs_opaque.handles.chown, (path), (uid), (gid)))
+#define SMB_VFS_OPAQUE_FCHOWN(fsp, uid, gid) ((fsp)->conn->vfs_opaque.ops.fchown((fsp)->conn->vfs_opaque.handles.fchown, (fsp), (uid), (gid)))
+#define SMB_VFS_OPAQUE_LCHOWN(conn, path, uid, gid) ((conn)->vfs_opaque.ops.lchown((conn)->vfs_opaque.handles.lchown, (path), (uid), (gid)))
+#define SMB_VFS_OPAQUE_CHDIR(conn, path) ((conn)->vfs_opaque.ops.chdir((conn)->vfs_opaque.handles.chdir, (path)))
+#define SMB_VFS_OPAQUE_GETWD(conn, buf) ((conn)->vfs_opaque.ops.getwd((conn)->vfs_opaque.handles.getwd, (buf)))
+#define SMB_VFS_OPAQUE_NTIMES(conn, path, ts) ((conn)->vfs_opaque.ops.ntimes((conn)->vfs_opaque.handles.ntimes, (path), (ts)))
+#define SMB_VFS_OPAQUE_FTRUNCATE(fsp, offset) ((fsp)->conn->vfs_opaque.ops.ftruncate((fsp)->conn->vfs_opaque.handles.ftruncate, (fsp), (offset)))
+#define SMB_VFS_OPAQUE_LOCK(fsp, op, offset, count, type) ((fsp)->conn->vfs_opaque.ops.lock((fsp)->conn->vfs_opaque.handles.lock, (fsp), (op), (offset), (count), (type)))
+#define SMB_VFS_OPAQUE_KERNEL_FLOCK(fsp, share_mode) ((fsp)->conn->vfs_opaque.ops.kernel_flock((fsp)->conn->vfs_opaque.handles.kernel_flock, (fsp), (share_mode)))
+#define SMB_VFS_OPAQUE_LINUX_SETLEASE(fsp, leasetype) ((fsp)->conn->vfs_opaque.ops.linux_setlease((fsp)->conn->vfs_opaque.handles.linux_setlease, (fsp), (leasetype)))
+#define SMB_VFS_OPAQUE_GETLOCK(fsp, poffset, pcount, ptype, ppid) ((fsp)->conn->vfs_opaque.ops.getlock((fsp)->conn->vfs_opaque.handles.getlock, (fsp), (poffset), (pcount), (ptype), (ppid)))
+#define SMB_VFS_OPAQUE_SYMLINK(conn, oldpath, newpath) ((conn)->vfs_opaque.ops.symlink((conn)->vfs_opaque.handles.symlink, (oldpath), (newpath)))
+#define SMB_VFS_OPAQUE_READLINK(conn, path, buf, bufsiz) ((conn)->vfs_opaque.ops.vfs_readlink((conn)->vfs_opaque.handles.vfs_readlink, (path), (buf), (bufsiz)))
+#define SMB_VFS_OPAQUE_LINK(conn, oldpath, newpath) ((conn)->vfs_opaque.ops.link((conn)->vfs_opaque.handles.link, (oldpath), (newpath)))
+#define SMB_VFS_OPAQUE_MKNOD(conn, path, mode, dev) ((conn)->vfs_opaque.ops.mknod((conn)->vfs_opaque.handles.mknod, (path), (mode), (dev)))
+#define SMB_VFS_OPAQUE_REALPATH(conn, path, resolved_path) ((conn)->vfs_opaque.ops.realpath((conn)->vfs_opaque.handles.realpath, (path), (resolved_path)))
+#define SMB_VFS_OPAQUE_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs_opaque.ops.notify_watch((conn)->vfs_opaque.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p)))
+#define SMB_VFS_OPAQUE_CHFLAGS(conn, path, flags) ((conn)->vfs_opaque.ops.chflags((conn)->vfs_opaque.handles.chflags, (path), (flags)))
+#define SMB_VFS_OPAQUE_FILE_ID_CREATE(conn, dev, inode) ((conn)->vfs.ops_opaque.file_id_create((conn)->vfs_opaque.handles.file_id_create, (dev), (inode)))
+#define SMB_VFS_OPAQUE_STREAMINFO(conn, fsp, fname, mem_ctx, num_streams, streams) ((conn)->vfs_opaque.ops.streaminfo((conn)->vfs_opaque.handles.streaminfo, (fsp), (fname), (mem_ctx), (num_streams), (streams)))
+
+/* NT ACL operations. */
+#define SMB_VFS_OPAQUE_FGET_NT_ACL(fsp, security_info, ppdesc) ((fsp)->conn->vfs_opaque.ops.fget_nt_acl((fsp)->conn->vfs_opaque.handles.fget_nt_acl, (fsp), (security_info), (ppdesc)))
+#define SMB_VFS_OPAQUE_GET_NT_ACL(conn, name, security_info, ppdesc) ((conn)->vfs_opaque.ops.get_nt_acl((conn)->vfs_opaque.handles.get_nt_acl, (name), (security_info), (ppdesc)))
+#define SMB_VFS_OPAQUE_FSET_NT_ACL(fsp, security_info_sent, psd) ((fsp)->conn->vfs_opaque.ops.fset_nt_acl((fsp)->conn->vfs_opaque.handles.fset_nt_acl, (fsp), (security_info_sent), (psd)))
+
+/* POSIX ACL operations. */
+#define SMB_VFS_OPAQUE_CHMOD_ACL(conn, name, mode) ((conn)->vfs_opaque.ops.chmod_acl((conn)->vfs_opaque.handles.chmod_acl, (name), (mode)))
+#define SMB_VFS_OPAQUE_FCHMOD_ACL(fsp, mode) ((fsp)->conn->vfs_opaque.ops.fchmod_acl((fsp)->conn->vfs_opaque.handles.chmod_acl, (fsp), (mode)))
+
+#define SMB_VFS_OPAQUE_SYS_ACL_GET_ENTRY(conn, theacl, entry_id, entry_p) ((conn)->vfs_opaque.ops.sys_acl_get_entry((conn)->vfs_opaque.handles.sys_acl_get_entry, (theacl), (entry_id), (entry_p)))
+#define SMB_VFS_OPAQUE_SYS_ACL_GET_TAG_TYPE(conn, entry_d, tag_type_p) ((conn)->vfs_opaque.ops.sys_acl_get_tag_type((conn)->vfs_opaque.handles.sys_acl_get_tag_type, (entry_d), (tag_type_p)))
+#define SMB_VFS_OPAQUE_SYS_ACL_GET_PERMSET(conn, entry_d, permset_p) ((conn)->vfs_opaque.ops.sys_acl_get_permset((conn)->vfs_opaque.handles.sys_acl_get_permset, (entry_d), (permset_p)))
+#define SMB_VFS_OPAQUE_SYS_ACL_GET_QUALIFIER(conn, entry_d) ((conn)->vfs_opaque.ops.sys_acl_get_qualifier((conn)->vfs_opaque.handles.sys_acl_get_qualifier, (entry_d)))
+#define SMB_VFS_OPAQUE_SYS_ACL_GET_FILE(conn, path_p, type) ((conn)->vfs_opaque.ops.sys_acl_get_file((conn)->vfs_opaque.handles.sys_acl_get_file, (path_p), (type)))
+#define SMB_VFS_OPAQUE_SYS_ACL_GET_FD(fsp) ((fsp)->conn->vfs_opaque.ops.sys_acl_get_fd((fsp)->conn->vfs_opaque.handles.sys_acl_get_fd, (fsp)))
+#define SMB_VFS_OPAQUE_SYS_ACL_CLEAR_PERMS(conn, permset) ((conn)->vfs_opaque.ops.sys_acl_clear_perms((conn)->vfs_opaque.handles.sys_acl_clear_perms, (permset)))
+#define SMB_VFS_OPAQUE_SYS_ACL_ADD_PERM(conn, permset, perm) ((conn)->vfs_opaque.ops.sys_acl_add_perm((conn)->vfs_opaque.handles.sys_acl_add_perm, (permset), (perm)))
+#define SMB_VFS_OPAQUE_SYS_ACL_TO_TEXT(conn, theacl, plen) ((conn)->vfs_opaque.ops.sys_acl_to_text((conn)->vfs_opaque.handles.sys_acl_to_text, (theacl), (plen)))
+#define SMB_VFS_OPAQUE_SYS_ACL_INIT(conn, count) ((conn)->vfs_opaque.ops.sys_acl_init((conn)->vfs_opaque.handles.sys_acl_init, (count)))
+#define SMB_VFS_OPAQUE_SYS_ACL_CREATE_ENTRY(conn, pacl, pentry) ((conn)->vfs_opaque.ops.sys_acl_create_entry((conn)->vfs_opaque.handles.sys_acl_create_entry, (pacl), (pentry)))
+#define SMB_VFS_OPAQUE_SYS_ACL_SET_TAG_TYPE(conn, entry, tagtype) ((conn)->vfs_opaque.ops.sys_acl_set_tag_type((conn)->vfs_opaque.handles.sys_acl_set_tag_type, (entry), (tagtype)))
+#define SMB_VFS_OPAQUE_SYS_ACL_SET_QUALIFIER(conn, entry, qual) ((conn)->vfs_opaque.ops.sys_acl_set_qualifier((conn)->vfs_opaque.handles.sys_acl_set_qualifier, (entry), (qual)))
+#define SMB_VFS_OPAQUE_SYS_ACL_SET_PERMSET(conn, entry, permset) ((conn)->vfs_opaque.ops.sys_acl_set_permset((conn)->vfs_opaque.handles.sys_acl_set_permset, (entry), (permset)))
+#define SMB_VFS_OPAQUE_SYS_ACL_VALID(conn, theacl) ((conn)->vfs_opaque.ops.sys_acl_valid((conn)->vfs_opaque.handles.sys_acl_valid, (theacl)))
+#define SMB_VFS_OPAQUE_SYS_ACL_SET_FILE(conn, name, acltype, theacl) ((conn)->vfs_opaque.ops.sys_acl_set_file((conn)->vfs_opaque.handles.sys_acl_set_file, (name), (acltype), (theacl)))
+#define SMB_VFS_OPAQUE_SYS_ACL_SET_FD(fsp, theacl) ((fsp)->conn->vfs_opaque.ops.sys_acl_set_fd((fsp)->conn->vfs_opaque.handles.sys_acl_set_fd, (fsp), (theacl)))
+#define SMB_VFS_OPAQUE_SYS_ACL_DELETE_DEF_FILE(conn, path) ((conn)->vfs_opaque.ops.sys_acl_delete_def_file((conn)->vfs_opaque.handles.sys_acl_delete_def_file, (path)))
+#define SMB_VFS_OPAQUE_SYS_ACL_GET_PERM(conn, permset, perm) ((conn)->vfs_opaque.ops.sys_acl_get_perm((conn)->vfs_opaque.handles.sys_acl_get_perm, (permset), (perm)))
+#define SMB_VFS_OPAQUE_SYS_ACL_FREE_TEXT(conn, text) ((conn)->vfs_opaque.ops.sys_acl_free_text((conn)->vfs_opaque.handles.sys_acl_free_text, (text)))
+#define SMB_VFS_OPAQUE_SYS_ACL_FREE_ACL(conn, posix_acl) ((conn)->vfs_opaque.ops.sys_acl_free_acl((conn)->vfs_opaque.handles.sys_acl_free_acl, (posix_acl)))
+#define SMB_VFS_OPAQUE_SYS_ACL_FREE_QUALIFIER(conn, qualifier, tagtype) ((conn)->vfs_opaque.ops.sys_acl_free_qualifier((conn)->vfs_opaque.handles.sys_acl_free_qualifier, (qualifier), (tagtype)))
+
+/* EA operations. */
+#define SMB_VFS_OPAQUE_GETXATTR(conn,path,name,value,size) ((conn)->vfs_opaque.ops.getxattr((conn)->vfs_opaque.handles.getxattr,(path),(name),(value),(size)))
+#define SMB_VFS_OPAQUE_LGETXATTR(conn,path,name,value,size) ((conn)->vfs_opaque.ops.lgetxattr((conn)->vfs_opaque.handles.lgetxattr,(path),(name),(value),(size)))
+#define SMB_VFS_OPAQUE_FGETXATTR(fsp,name,value,size) ((fsp)->conn->vfs_opaque.ops.fgetxattr((fsp)->conn->vfs_opaque.handles.fgetxattr,(fsp),(name),(value),(size)))
+#define SMB_VFS_OPAQUE_LISTXATTR(conn,path,list,size) ((conn)->vfs_opaque.ops.listxattr((conn)->vfs_opaque.handles.listxattr,(path),(list),(size)))
+#define SMB_VFS_OPAQUE_LLISTXATTR(conn,path,list,size) ((conn)->vfs_opaque.ops.llistxattr((conn)->vfs_opaque.handles.llistxattr,(path),(list),(size)))
+#define SMB_VFS_OPAQUE_FLISTXATTR(fsp,list,size) ((fsp)->conn->vfs_opaque.ops.flistxattr((fsp)->conn->vfs_opaque.handles.flistxattr,(fsp),(list),(size)))
+#define SMB_VFS_OPAQUE_REMOVEXATTR(conn,path,name) ((conn)->vfs_opaque.ops.removexattr((conn)->vfs_opaque.handles.removexattr,(path),(name)))
+#define SMB_VFS_OPAQUE_LREMOVEXATTR(conn,path,name) ((conn)->vfs_opaque.ops.lremovexattr((conn)->vfs_opaque.handles.lremovexattr,(path),(name)))
+#define SMB_VFS_OPAQUE_FREMOVEXATTR(fsp,name) ((fsp)->conn->vfs_opaque.ops.fremovexattr((fsp)->conn->vfs_opaque.handles.fremovexattr,(fsp),(name)))
+#define SMB_VFS_OPAQUE_SETXATTR(conn,path,name,value,size,flags) ((conn)->vfs_opaque.ops.setxattr((conn)->vfs_opaque.handles.setxattr,(path),(name),(value),(size),(flags)))
+#define SMB_VFS_OPAQUE_LSETXATTR(conn,path,name,value,size,flags) ((conn)->vfs_opaque.ops.lsetxattr((conn)->vfs_opaque.handles.lsetxattr,(path),(name),(value),(size),(flags)))
+#define SMB_VFS_OPAQUE_FSETXATTR(fsp,name,value,size,flags) ((fsp)->conn->vfs_opaque.ops.fsetxattr((fsp)->conn->vfs_opaque.handles.fsetxattr,(fsp),(name),(value),(size),(flags)))
+
+/* AIO operations. */
+#define SMB_VFS_OPAQUE_AIO_READ(fsp,aiocb) ((fsp)->conn->vfs_opaque.ops.aio_read((fsp)->conn->vfs_opaque.handles.aio_read,(fsp),(aiocb)))
+#define SMB_VFS_OPAQUE_AIO_WRITE(fsp,aiocb) ((fsp)->conn->vfs_opaque.ops.aio_write((fsp)->conn->vfs_opaque.handles.aio_write,(fsp),(aiocb)))
+#define SMB_VFS_OPAQUE_AIO_RETURN(fsp,aiocb) ((fsp)->conn->vfs_opaque.ops.aio_return_fn((fsp)->conn->vfs_opaque.handles.aio_return,(fsp),(aiocb)))
+#define SMB_VFS_OPAQUE_AIO_CANCEL(fsp,aiocb) ((fsp)->conn->vfs_opaque.ops.aio_cancel((fsp)->conn->vfs_opaque.handles.cancel,(fsp),(aiocb)))
+#define SMB_VFS_OPAQUE_AIO_ERROR(fsp,aiocb) ((fsp)->conn->vfs_opaque.ops.aio_error_fn((fsp)->conn->vfs_opaque.handles.aio_error,(fsp),(aiocb)))
+#define SMB_VFS_OPAQUE_AIO_FSYNC(fsp,op,aiocb) ((fsp)->conn->vfs_opaque.ops.aio_fsync((fsp)->conn->vfs_opaque.handles.aio_fsync,(fsp),(op),(aiocb)))
+#define SMB_VFS_OPAQUE_AIO_SUSPEND(fsp,aiocb,n,ts) ((fsp)->conn->vfs_opaque.ops.aio_suspend((fsp)->conn->vfs_opaque.handles.aio_suspend,(fsp),(aiocb),(n),(ts)))
+#define SMB_VFS_OPAQUE_AIO_FORCE(fsp) ((fsp)->conn->vfs_opaque.ops.aio_force((fsp)->conn->vfs_opaque.handles.aio_force,(fsp)))
+
+/* Offline operations */
+#define SMB_VFS_OPAQUE_IS_OFFLINE(conn,path,sbuf) ((conn)->vfs_opaque.ops.is_offline((conn)->vfs_opaque.handles.is_offline,(path),(sbuf)))
+#define SMB_VFS_OPAQUE_SET_OFFLINE(conn,path) ((conn)->vfs_opaque.ops.set_offline((conn)->vfs_opaque.handles.set_offline,(path)))
+
+/*******************************************************************
+ Don't access handle->vfs_next.ops.* directly!!!
+ Use this macros!
+ (Fixes should go also into the vfs_* and vfs_opaque_* macros!)
+********************************************************************/
+
+/* Disk operations */
+#define SMB_VFS_NEXT_CONNECT(handle, service, user) ((handle)->vfs_next.ops.connect_fn((handle)->vfs_next.handles.connect_hnd, (service), (user)))
+#define SMB_VFS_NEXT_DISCONNECT(handle) ((handle)->vfs_next.ops.disconnect((handle)->vfs_next.handles.disconnect))
+#define SMB_VFS_NEXT_DISK_FREE(handle, path, small_query, bsize, dfree ,dsize) ((handle)->vfs_next.ops.disk_free((handle)->vfs_next.handles.disk_free, (path), (small_query), (bsize), (dfree), (dsize)))
+#define SMB_VFS_NEXT_GET_QUOTA(handle, qtype, id, qt) ((handle)->vfs_next.ops.get_quota((handle)->vfs_next.handles.get_quota, (qtype), (id), (qt)))
+#define SMB_VFS_NEXT_SET_QUOTA(handle, qtype, id, qt) ((handle)->vfs_next.ops.set_quota((handle)->vfs_next.handles.set_quota, (qtype), (id), (qt)))
+#define SMB_VFS_NEXT_GET_SHADOW_COPY_DATA(handle, fsp, shadow_copy_data ,labels) ((handle)->vfs_next.ops.get_shadow_copy_data((handle)->vfs_next.handles.get_shadow_copy_data,(fsp),(shadow_copy_data),(labels)))
+#define SMB_VFS_NEXT_STATVFS(handle, path, statbuf) ((handle)->vfs_next.ops.statvfs((handle)->vfs_next.handles.statvfs, (path), (statbuf)))
+#define SMB_VFS_NEXT_FS_CAPABILITIES(handle) ((handle)->vfs_next.ops.fs_capabilities((handle)->vfs_next.handles.fs_capabilities))
+
+/* Directory operations */
+#define SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr) ((handle)->vfs_next.ops.opendir((handle)->vfs_next.handles.opendir, (fname), (mask), (attr)))
+#define SMB_VFS_NEXT_READDIR(handle, dirp) ((handle)->vfs_next.ops.readdir((handle)->vfs_next.handles.readdir, (dirp)))
+#define SMB_VFS_NEXT_SEEKDIR(handle, dirp, offset) ((handle)->vfs_next.ops.seekdir((handle)->vfs_next.handles.seekdir, (dirp), (offset)))
+#define SMB_VFS_NEXT_TELLDIR(handle, dirp) ((handle)->vfs_next.ops.telldir((handle)->vfs_next.handles.telldir, (dirp)))
+#define SMB_VFS_NEXT_REWINDDIR(handle, dirp) ((handle)->vfs_next.ops.rewind_dir((handle)->vfs_next.handles.rewind_dir, (dirp)))
+#define SMB_VFS_NEXT_DIR(handle, dirp) ((handle)->vfs_next.ops.readdir((handle)->vfs_next.handles.readdir, (dirp)))
+#define SMB_VFS_NEXT_MKDIR(handle, path, mode) ((handle)->vfs_next.ops.mkdir((handle)->vfs_next.handles.mkdir,(path), (mode)))
+#define SMB_VFS_NEXT_RMDIR(handle, path) ((handle)->vfs_next.ops.rmdir((handle)->vfs_next.handles.rmdir, (path)))
+#define SMB_VFS_NEXT_CLOSEDIR(handle, dir) ((handle)->vfs_next.ops.closedir((handle)->vfs_next.handles.closedir, dir))
+
+/* File operations */
+#define SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode) (((handle)->vfs_next.ops.open)((handle)->vfs_next.handles.open, (fname), (fsp), (flags), (mode)))
+#define SMB_VFS_NEXT_CLOSE(handle, fsp) ((handle)->vfs_next.ops.close_fn((handle)->vfs_next.handles.close_hnd, (fsp)))
+#define SMB_VFS_NEXT_READ(handle, fsp, data, n) ((handle)->vfs_next.ops.vfs_read((handle)->vfs_next.handles.vfs_read, (fsp), (data), (n)))
+#define SMB_VFS_NEXT_PREAD(handle, fsp, data, n, off) ((handle)->vfs_next.ops.pread((handle)->vfs_next.handles.pread, (fsp), (data), (n), (off)))
+#define SMB_VFS_NEXT_WRITE(handle, fsp, data, n) ((handle)->vfs_next.ops.write((handle)->vfs_next.handles.write, (fsp), (data), (n)))
+#define SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, off) ((handle)->vfs_next.ops.pwrite((handle)->vfs_next.handles.pwrite, (fsp), (data), (n), (off)))
+#define SMB_VFS_NEXT_LSEEK(handle, fsp, offset, whence) ((handle)->vfs_next.ops.lseek((handle)->vfs_next.handles.lseek, (fsp), (offset), (whence)))
+#define SMB_VFS_NEXT_SENDFILE(handle, tofd, fromfsp, header, offset, count) ((handle)->vfs_next.ops.sendfile((handle)->vfs_next.handles.sendfile, (tofd), (fromfsp), (header), (offset), (count)))
+#define SMB_VFS_NEXT_RECVFILE(handle, fromfd, tofsp, offset, count) ((handle)->vfs_next.ops.recvfile((handle)->vfs_next.handles.recvfile, (fromfd), (tofsp), (offset), (count)))
+#define SMB_VFS_NEXT_RENAME(handle, old, new) ((handle)->vfs_next.ops.rename((handle)->vfs_next.handles.rename, (old), (new)))
+#define SMB_VFS_NEXT_FSYNC(handle, fsp) ((handle)->vfs_next.ops.fsync((handle)->vfs_next.handles.fsync, (fsp)))
+#define SMB_VFS_NEXT_STAT(handle, fname, sbuf) ((handle)->vfs_next.ops.stat((handle)->vfs_next.handles.stat, (fname), (sbuf)))
+#define SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf) ((handle)->vfs_next.ops.fstat((handle)->vfs_next.handles.fstat, (fsp), (sbuf)))
+#define SMB_VFS_NEXT_LSTAT(handle, path, sbuf) ((handle)->vfs_next.ops.lstat((handle)->vfs_next.handles.lstat, (path), (sbuf)))
+#define SMB_VFS_NEXT_UNLINK(handle, path) ((handle)->vfs_next.ops.unlink((handle)->vfs_next.handles.unlink, (path)))
+#define SMB_VFS_NEXT_CHMOD(handle, path, mode) ((handle)->vfs_next.ops.chmod((handle)->vfs_next.handles.chmod, (path), (mode)))
+#define SMB_VFS_NEXT_FCHMOD(handle, fsp, mode) ((handle)->vfs_next.ops.fchmod((handle)->vfs_next.handles.fchmod, (fsp), (mode)))
+#define SMB_VFS_NEXT_CHOWN(handle, path, uid, gid) ((handle)->vfs_next.ops.chown((handle)->vfs_next.handles.chown, (path), (uid), (gid)))
+#define SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid) ((handle)->vfs_next.ops.fchown((handle)->vfs_next.handles.fchown, (fsp), (uid), (gid)))
+#define SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid) ((handle)->vfs_next.ops.lchown((handle)->vfs_next.handles.lchown, (path), (uid), (gid)))
+#define SMB_VFS_NEXT_CHDIR(handle, path) ((handle)->vfs_next.ops.chdir((handle)->vfs_next.handles.chdir, (path)))
+#define SMB_VFS_NEXT_GETWD(handle, buf) ((handle)->vfs_next.ops.getwd((handle)->vfs_next.handles.getwd, (buf)))
+#define SMB_VFS_NEXT_NTIMES(handle, path, ts) ((handle)->vfs_next.ops.ntimes((handle)->vfs_next.handles.ntimes, (path), (ts)))
+#define SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset) ((handle)->vfs_next.ops.ftruncate((handle)->vfs_next.handles.ftruncate, (fsp), (offset)))
+#define SMB_VFS_NEXT_LOCK(handle, fsp, op, offset, count, type) ((handle)->vfs_next.ops.lock((handle)->vfs_next.handles.lock, (fsp), (op), (offset), (count), (type)))
+#define SMB_VFS_NEXT_KERNEL_FLOCK(handle, fsp, share_mode)((handle)->vfs_next.ops.kernel_flock((handle)->vfs_next.handles.kernel_flock, (fsp), (share_mode)))
+#define SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, leasetype)((handle)->vfs_next.ops.linux_setlease((handle)->vfs_next.handles.linux_setlease, (fsp), (leasetype)))
+#define SMB_VFS_NEXT_GETLOCK(handle, fsp, poffset, pcount, ptype, ppid) ((handle)->vfs_next.ops.getlock((handle)->vfs_next.handles.getlock, (fsp), (poffset), (pcount), (ptype), (ppid)))
+#define SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath) ((handle)->vfs_next.ops.symlink((handle)->vfs_next.handles.symlink, (oldpath), (newpath)))
+#define SMB_VFS_NEXT_READLINK(handle, path, buf, bufsiz) ((handle)->vfs_next.ops.vfs_readlink((handle)->vfs_next.handles.vfs_readlink, (path), (buf), (bufsiz)))
+#define SMB_VFS_NEXT_LINK(handle, oldpath, newpath) ((handle)->vfs_next.ops.link((handle)->vfs_next.handles.link, (oldpath), (newpath)))
+#define SMB_VFS_NEXT_MKNOD(handle, path, mode, dev) ((handle)->vfs_next.ops.mknod((handle)->vfs_next.handles.mknod, (path), (mode), (dev)))
+#define SMB_VFS_NEXT_REALPATH(handle, path, resolved_path) ((handle)->vfs_next.ops.realpath((handle)->vfs_next.handles.realpath, (path), (resolved_path)))
+#define SMB_VFS_NEXT_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs_next.ops.notify_watch((conn)->vfs_next.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p)))
+#define SMB_VFS_NEXT_CHFLAGS(handle, path, flags) ((handle)->vfs_next.ops.chflags((handle)->vfs_next.handles.chflags, (path), (flags)))
+#define SMB_VFS_NEXT_FILE_ID_CREATE(handle, dev, inode) ((handle)->vfs_next.ops.file_id_create((handle)->vfs_next.handles.file_id_create, (dev), (inode)))
+#define SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname, mem_ctx, num_streams, streams) ((handle)->vfs_next.ops.streaminfo((handle)->vfs_next.handles.streaminfo, (fsp), (fname), (mem_ctx), (num_streams), (streams)))
+
+/* NT ACL operations. */
+#define SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, ppdesc) ((handle)->vfs_next.ops.fget_nt_acl((handle)->vfs_next.handles.fget_nt_acl, (fsp), (security_info), (ppdesc)))
+#define SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info, ppdesc) ((handle)->vfs_next.ops.get_nt_acl((handle)->vfs_next.handles.get_nt_acl, (name), (security_info), (ppdesc)))
+#define SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd) ((handle)->vfs_next.ops.fset_nt_acl((handle)->vfs_next.handles.fset_nt_acl, (fsp), (security_info_sent), (psd)))
+
+/* POSIX ACL operations. */
+#define SMB_VFS_NEXT_CHMOD_ACL(handle, name, mode) ((handle)->vfs_next.ops.chmod_acl((handle)->vfs_next.handles.chmod_acl, (name), (mode)))
+#define SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode) ((handle)->vfs_next.ops.fchmod_acl((handle)->vfs_next.handles.chmod_acl, (fsp), (mode)))
+
+#define SMB_VFS_NEXT_SYS_ACL_GET_ENTRY(handle, theacl, entry_id, entry_p) ((handle)->vfs_next.ops.sys_acl_get_entry((handle)->vfs_next.handles.sys_acl_get_entry, (theacl), (entry_id), (entry_p)))
+#define SMB_VFS_NEXT_SYS_ACL_GET_TAG_TYPE(handle, entry_d, tag_type_p) ((handle)->vfs_next.ops.sys_acl_get_tag_type((handle)->vfs_next.handles.sys_acl_get_tag_type, (entry_d), (tag_type_p)))
+#define SMB_VFS_NEXT_SYS_ACL_GET_PERMSET(handle, entry_d, permset_p) ((handle)->vfs_next.ops.sys_acl_get_permset((handle)->vfs_next.handles.sys_acl_get_permset, (entry_d), (permset_p)))
+#define SMB_VFS_NEXT_SYS_ACL_GET_QUALIFIER(handle, entry_d) ((handle)->vfs_next.ops.sys_acl_get_qualifier((handle)->vfs_next.handles.sys_acl_get_qualifier, (entry_d)))
+#define SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, path_p, type) ((handle)->vfs_next.ops.sys_acl_get_file((handle)->vfs_next.handles.sys_acl_get_file, (path_p), (type)))
+#define SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp) ((handle)->vfs_next.ops.sys_acl_get_fd((handle)->vfs_next.handles.sys_acl_get_fd, (fsp)))
+#define SMB_VFS_NEXT_SYS_ACL_CLEAR_PERMS(handle, permset) ((handle)->vfs_next.ops.sys_acl_clear_perms((handle)->vfs_next.handles.sys_acl_clear_perms, (permset)))
+#define SMB_VFS_NEXT_SYS_ACL_ADD_PERM(handle, permset, perm) ((handle)->vfs_next.ops.sys_acl_add_perm((handle)->vfs_next.handles.sys_acl_add_perm, (permset), (perm)))
+#define SMB_VFS_NEXT_SYS_ACL_TO_TEXT(handle, theacl, plen) ((handle)->vfs_next.ops.sys_acl_to_text((handle)->vfs_next.handles.sys_acl_to_text, (theacl), (plen)))
+#define SMB_VFS_NEXT_SYS_ACL_INIT(handle, count) ((handle)->vfs_next.ops.sys_acl_init((handle)->vfs_next.handles.sys_acl_init, (count)))
+#define SMB_VFS_NEXT_SYS_ACL_CREATE_ENTRY(handle, pacl, pentry) ((handle)->vfs_next.ops.sys_acl_create_entry((handle)->vfs_next.handles.sys_acl_create_entry, (pacl), (pentry)))
+#define SMB_VFS_NEXT_SYS_ACL_SET_TAG_TYPE(handle, entry, tagtype) ((handle)->vfs_next.ops.sys_acl_set_tag_type((handle)->vfs_next.handles.sys_acl_set_tag_type, (entry), (tagtype)))
+#define SMB_VFS_NEXT_SYS_ACL_SET_QUALIFIER(handle, entry, qual) ((handle)->vfs_next.ops.sys_acl_set_qualifier((handle)->vfs_next.handles.sys_acl_set_qualifier, (entry), (qual)))
+#define SMB_VFS_NEXT_SYS_ACL_SET_PERMSET(handle, entry, permset) ((handle)->vfs_next.ops.sys_acl_set_permset((handle)->vfs_next.handles.sys_acl_set_permset, (entry), (permset)))
+#define SMB_VFS_NEXT_SYS_ACL_VALID(handle, theacl) ((handle)->vfs_next.ops.sys_acl_valid((handle)->vfs_next.handles.sys_acl_valid, (theacl)))
+#define SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, name, acltype, theacl) ((handle)->vfs_next.ops.sys_acl_set_file((handle)->vfs_next.handles.sys_acl_set_file, (name), (acltype), (theacl)))
+#define SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, theacl) ((handle)->vfs_next.ops.sys_acl_set_fd((handle)->vfs_next.handles.sys_acl_set_fd, (fsp), (theacl)))
+#define SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, path) ((handle)->vfs_next.ops.sys_acl_delete_def_file((handle)->vfs_next.handles.sys_acl_delete_def_file, (path)))
+#define SMB_VFS_NEXT_SYS_ACL_GET_PERM(handle, permset, perm) ((handle)->vfs_next.ops.sys_acl_get_perm((handle)->vfs_next.handles.sys_acl_get_perm, (permset), (perm)))
+#define SMB_VFS_NEXT_SYS_ACL_FREE_TEXT(handle, text) ((handle)->vfs_next.ops.sys_acl_free_text((handle)->vfs_next.handles.sys_acl_free_text, (text)))
+#define SMB_VFS_NEXT_SYS_ACL_FREE_ACL(handle, posix_acl) ((handle)->vfs_next.ops.sys_acl_free_acl((handle)->vfs_next.handles.sys_acl_free_acl, (posix_acl)))
+#define SMB_VFS_NEXT_SYS_ACL_FREE_QUALIFIER(handle, qualifier, tagtype) ((handle)->vfs_next.ops.sys_acl_free_qualifier((handle)->vfs_next.handles.sys_acl_free_qualifier, (qualifier), (tagtype)))
+
+/* EA operations. */
+#define SMB_VFS_NEXT_GETXATTR(handle,path,name,value,size) ((handle)->vfs_next.ops.getxattr((handle)->vfs_next.handles.getxattr,(path),(name),(value),(size)))
+#define SMB_VFS_NEXT_LGETXATTR(handle,path,name,value,size) ((handle)->vfs_next.ops.lgetxattr((handle)->vfs_next.handles.lgetxattr,(path),(name),(value),(size)))
+#define SMB_VFS_NEXT_FGETXATTR(handle,fsp,name,value,size) ((handle)->vfs_next.ops.fgetxattr((handle)->vfs_next.handles.fgetxattr,(fsp),(name),(value),(size)))
+#define SMB_VFS_NEXT_LISTXATTR(handle,path,list,size) ((handle)->vfs_next.ops.listxattr((handle)->vfs_next.handles.listxattr,(path),(list),(size)))
+#define SMB_VFS_NEXT_LLISTXATTR(handle,path,list,size) ((handle)->vfs_next.ops.llistxattr((handle)->vfs_next.handles.llistxattr,(path),(list),(size)))
+#define SMB_VFS_NEXT_FLISTXATTR(handle,fsp,list,size) ((handle)->vfs_next.ops.flistxattr((handle)->vfs_next.handles.flistxattr,(fsp),(list),(size)))
+#define SMB_VFS_NEXT_REMOVEXATTR(handle,path,name) ((handle)->vfs_next.ops.removexattr((handle)->vfs_next.handles.removexattr,(path),(name)))
+#define SMB_VFS_NEXT_LREMOVEXATTR(handle,path,name) ((handle)->vfs_next.ops.lremovexattr((handle)->vfs_next.handles.lremovexattr,(path),(name)))
+#define SMB_VFS_NEXT_FREMOVEXATTR(handle,fsp,name) ((handle)->vfs_next.ops.fremovexattr((handle)->vfs_next.handles.fremovexattr,(fsp),(name)))
+#define SMB_VFS_NEXT_SETXATTR(handle,path,name,value,size,flags) ((handle)->vfs_next.ops.setxattr((handle)->vfs_next.handles.setxattr,(path),(name),(value),(size),(flags)))
+#define SMB_VFS_NEXT_LSETXATTR(handle,path,name,value,size,flags) ((handle)->vfs_next.ops.lsetxattr((handle)->vfs_next.handles.lsetxattr,(path),(name),(value),(size),(flags)))
+#define SMB_VFS_NEXT_FSETXATTR(handle,fsp,name,value,size,flags) ((handle)->vfs_next.ops.fsetxattr((handle)->vfs_next.handles.fsetxattr,(fsp),(name),(value),(size),(flags)))
+
+/* AIO operations. */
+#define SMB_VFS_NEXT_AIO_READ(handle,fsp,aiocb) ((handle)->vfs_next.ops.aio_read((handle)->vfs_next.handles.aio_read,(fsp),(aiocb)))
+#define SMB_VFS_NEXT_AIO_WRITE(handle,fsp,aiocb) ((handle)->vfs_next.ops.aio_write((handle)->vfs_next.handles.aio_write,(fsp),(aiocb)))
+#define SMB_VFS_NEXT_AIO_RETURN(handle,fsp,aiocb) ((handle)->vfs_next.ops.aio_return_fn((handle)->vfs_next.handles.aio_return,(fsp),(aiocb)))
+#define SMB_VFS_NEXT_AIO_CANCEL(handle,fsp,aiocb) ((handle)->vfs_next.ops.aio_cancel((handle)->vfs_next.handles.aio_cancel,(fsp),(aiocb)))
+#define SMB_VFS_NEXT_AIO_ERROR(handle,fsp,aiocb) ((handle)->vfs_next.ops.aio_error_fn((handle)->vfs_next.handles.aio_error,(fsp),(aiocb)))
+#define SMB_VFS_NEXT_AIO_FSYNC(handle,fsp,op,aiocb) ((handle)->vfs_next.ops.aio_fsync((handle)->vfs_next.handles.aio_fsync,(fsp),(op),(aiocb)))
+#define SMB_VFS_NEXT_AIO_SUSPEND(handle,fsp,aiocb,n,ts) ((handle)->vfs_next.ops.aio_suspend((handle)->vfs_next.handles.aio_suspend,(fsp),(aiocb),(n),(ts)))
+#define SMB_VFS_NEXT_AIO_FORCE(handle,fsp) ((handle)->vfs_next.ops.aio_force((handle)->vfs_next.handles.aio_force,(fsp)))
+
+/* Offline operations */
+#define SMB_VFS_NEXT_IS_OFFLINE(handle,path,sbuf) ((handle)->vfs_next.ops.is_offline((handle)->vfs_next.handles.is_offline,(path),(sbuf)))
+#define SMB_VFS_NEXT_SET_OFFLINE(handle,path) ((handle)->vfs_next.ops.set_offline((handle)->vfs_next.handles.set_offline,(path)))
+
+#endif /* _VFS_MACROS_H */
diff --git a/source3/include/xfile.h b/source3/include/xfile.h
new file mode 100644
index 0000000000..ffe4481a64
--- /dev/null
+++ b/source3/include/xfile.h
@@ -0,0 +1,48 @@
+/*
+ Unix SMB/CIFS implementation.
+ stdio replacement
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _XFILE_H_
+#define _XFILE_H_
+/*
+ see xfile.c for explanations
+*/
+
+typedef struct {
+ int fd;
+ char *buf;
+ char *next;
+ int bufsize;
+ int bufused;
+ int open_flags;
+ int buftype;
+ int flags;
+} XFILE;
+
+extern XFILE *x_stdin, *x_stdout, *x_stderr;
+
+/* buffering type */
+#define X_IOFBF 0
+#define X_IOLBF 1
+#define X_IONBF 2
+
+#define x_getc(f) x_fgetc(f)
+
+int x_vfprintf(XFILE *f, const char *format, va_list ap) PRINTF_ATTRIBUTE(2, 0);
+int x_fprintf(XFILE *f, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
+#endif /* _XFILE_H_ */
diff --git a/source3/iniparser/AUTHORS b/source3/iniparser/AUTHORS
new file mode 100644
index 0000000000..f3dc876574
--- /dev/null
+++ b/source3/iniparser/AUTHORS
@@ -0,0 +1,5 @@
+Author for this package:
+Nicolas Devillard <ndevilla@free.fr>
+
+Many thanks to the many people who contributed ideas, code, suggestions,
+corrections, enhancements.
diff --git a/source3/iniparser/INSTALL b/source3/iniparser/INSTALL
new file mode 100644
index 0000000000..0d319b2670
--- /dev/null
+++ b/source3/iniparser/INSTALL
@@ -0,0 +1,12 @@
+
+iniParser installation instructions
+-----------------------------------
+
+1. Modify the Makefile to suit your environment.
+2. Type 'make' to make the library.
+3. Type 'make check' to make the test program.
+4. Type 'test/iniexample' to launch the test program.
+
+Enjoy!
+N. Devillard
+Tue Jan 14 11:52:03 CET 2003
diff --git a/source3/iniparser/LICENSE b/source3/iniparser/LICENSE
new file mode 100644
index 0000000000..2eae408337
--- /dev/null
+++ b/source3/iniparser/LICENSE
@@ -0,0 +1,21 @@
+Copyright (c) 2000 by Nicolas Devillard.
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
diff --git a/source3/iniparser/Makefile b/source3/iniparser/Makefile
new file mode 100644
index 0000000000..bc5d61211a
--- /dev/null
+++ b/source3/iniparser/Makefile
@@ -0,0 +1,63 @@
+#
+# iniparser Makefile
+#
+
+# Compiler settings
+CC = gcc
+CFLAGS = -O3 -fPIC
+
+# Ar settings to build the library
+AR = ar
+ARFLAGS = rcv
+
+SHLD = ${CC} ${CFLAGS}
+LDSHFLAGS = -shared -Wl,-Bsymbolic -Wl,-rpath -Wl,/usr/lib -Wl,-rpath,/usr/lib
+LDFLAGS = -Wl,-rpath -Wl,/usr/lib -Wl,-rpath,/usr/lib
+
+# Set RANLIB to ranlib on systems that require it (Sun OS < 4, Mac OSX)
+# RANLIB = ranlib
+RANLIB = true
+
+RM = rm -f
+
+
+# Implicit rules
+
+SUFFIXES = .o .c .h .a .so .sl
+
+COMPILE.c=$(CC) $(CFLAGS) -c
+.c.o:
+ @(echo "compiling $< ...")
+ @($(COMPILE.c) -o $@ $<)
+
+
+SRCS = src/iniparser.c \
+ src/dictionary.c \
+ src/strlib.c
+
+OBJS = $(SRCS:.c=.o)
+
+
+default: libiniparser.a libiniparser.so
+
+libiniparser.a: $(OBJS)
+ @($(AR) $(ARFLAGS) libiniparser.a $(OBJS))
+ @($(RANLIB) libiniparser.a)
+
+libiniparser.so: $(OBJS)
+ @$(SHLD) $(LDSHFLAGS) -o $@.0 $(OBJS) $(LDFLAGS) \
+ -Wl,-soname=`basename $@`.0
+
+clean:
+ $(RM) $(OBJS)
+
+veryclean:
+ $(RM) $(OBJS) libiniparser.a libiniparser.so*
+ rm -rf ./html ; mkdir html
+ cd test ; $(MAKE) veryclean
+
+docs:
+ @(cd doc ; $(MAKE))
+
+check:
+ @(cd test ; $(MAKE))
diff --git a/source3/iniparser/README b/source3/iniparser/README
new file mode 100644
index 0000000000..466d079ba5
--- /dev/null
+++ b/source3/iniparser/README
@@ -0,0 +1,11 @@
+
+Welcome to iniParser!
+
+This modules offers parsing of ini files from the C level.
+See a complete documentation in HTML format, from this directory
+open the file html/index.html with any HTML-capable browser.
+
+Enjoy!
+
+N.Devillard
+Thu Nov 17 12:31:42 CET 2005
diff --git a/source3/iniparser/html/doxygen.css b/source3/iniparser/html/doxygen.css
new file mode 100644
index 0000000000..c7db1a8a04
--- /dev/null
+++ b/source3/iniparser/html/doxygen.css
@@ -0,0 +1,358 @@
+BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
+ font-family: Geneva, Arial, Helvetica, sans-serif;
+}
+BODY,TD {
+ font-size: 90%;
+}
+H1 {
+ text-align: center;
+ font-size: 160%;
+}
+H2 {
+ font-size: 120%;
+}
+H3 {
+ font-size: 100%;
+}
+CAPTION { font-weight: bold }
+DIV.qindex {
+ width: 100%;
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ padding: 2px;
+ line-height: 140%;
+}
+DIV.nav {
+ width: 100%;
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ padding: 2px;
+ line-height: 140%;
+}
+DIV.navtab {
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+TD.navtab {
+ font-size: 70%;
+}
+A.qindex {
+ text-decoration: none;
+ font-weight: bold;
+ color: #1A419D;
+}
+A.qindex:visited {
+ text-decoration: none;
+ font-weight: bold;
+ color: #1A419D
+}
+A.qindex:hover {
+ text-decoration: none;
+ background-color: #ddddff;
+}
+A.qindexHL {
+ text-decoration: none;
+ font-weight: bold;
+ background-color: #6666cc;
+ color: #ffffff;
+ border: 1px double #9295C2;
+}
+A.qindexHL:hover {
+ text-decoration: none;
+ background-color: #6666cc;
+ color: #ffffff;
+}
+A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff }
+A.el { text-decoration: none; font-weight: bold }
+A.elRef { font-weight: bold }
+A.code:link { text-decoration: none; font-weight: normal; color: #0000FF}
+A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF}
+A.codeRef:link { font-weight: normal; color: #0000FF}
+A.codeRef:visited { font-weight: normal; color: #0000FF}
+A:hover { text-decoration: none; background-color: #f2f2ff }
+DL.el { margin-left: -1cm }
+.fragment {
+ font-family: monospace, fixed;
+ font-size: 95%;
+}
+PRE.fragment {
+ border: 1px solid #CCCCCC;
+ background-color: #f5f5f5;
+ margin-top: 4px;
+ margin-bottom: 4px;
+ margin-left: 2px;
+ margin-right: 8px;
+ padding-left: 6px;
+ padding-right: 6px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+}
+DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px }
+
+DIV.groupHeader {
+ margin-left: 16px;
+ margin-top: 12px;
+ margin-bottom: 6px;
+ font-weight: bold;
+}
+DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% }
+BODY {
+ background: white;
+ color: black;
+ margin-right: 20px;
+ margin-left: 20px;
+}
+TD.indexkey {
+ background-color: #e8eef2;
+ font-weight: bold;
+ padding-right : 10px;
+ padding-top : 2px;
+ padding-left : 10px;
+ padding-bottom : 2px;
+ margin-left : 0px;
+ margin-right : 0px;
+ margin-top : 2px;
+ margin-bottom : 2px;
+ border: 1px solid #CCCCCC;
+}
+TD.indexvalue {
+ background-color: #e8eef2;
+ font-style: italic;
+ padding-right : 10px;
+ padding-top : 2px;
+ padding-left : 10px;
+ padding-bottom : 2px;
+ margin-left : 0px;
+ margin-right : 0px;
+ margin-top : 2px;
+ margin-bottom : 2px;
+ border: 1px solid #CCCCCC;
+}
+TR.memlist {
+ background-color: #f0f0f0;
+}
+P.formulaDsp { text-align: center; }
+IMG.formulaDsp { }
+IMG.formulaInl { vertical-align: middle; }
+SPAN.keyword { color: #008000 }
+SPAN.keywordtype { color: #604020 }
+SPAN.keywordflow { color: #e08000 }
+SPAN.comment { color: #800000 }
+SPAN.preprocessor { color: #806020 }
+SPAN.stringliteral { color: #002080 }
+SPAN.charliteral { color: #008080 }
+.mdescLeft {
+ padding: 0px 8px 4px 8px;
+ font-size: 80%;
+ font-style: italic;
+ background-color: #FAFAFA;
+ border-top: 1px none #E0E0E0;
+ border-right: 1px none #E0E0E0;
+ border-bottom: 1px none #E0E0E0;
+ border-left: 1px none #E0E0E0;
+ margin: 0px;
+}
+.mdescRight {
+ padding: 0px 8px 4px 8px;
+ font-size: 80%;
+ font-style: italic;
+ background-color: #FAFAFA;
+ border-top: 1px none #E0E0E0;
+ border-right: 1px none #E0E0E0;
+ border-bottom: 1px none #E0E0E0;
+ border-left: 1px none #E0E0E0;
+ margin: 0px;
+}
+.memItemLeft {
+ padding: 1px 0px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: solid;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memItemRight {
+ padding: 1px 8px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: solid;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memTemplItemLeft {
+ padding: 1px 0px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: none;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memTemplItemRight {
+ padding: 1px 8px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: none;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memTemplParams {
+ padding: 1px 0px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: solid;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ color: #606060;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.search { color: #003399;
+ font-weight: bold;
+}
+FORM.search {
+ margin-bottom: 0px;
+ margin-top: 0px;
+}
+INPUT.search { font-size: 75%;
+ color: #000080;
+ font-weight: normal;
+ background-color: #e8eef2;
+}
+TD.tiny { font-size: 75%;
+}
+a {
+ color: #1A41A8;
+}
+a:visited {
+ color: #2A3798;
+}
+.dirtab { padding: 4px;
+ border-collapse: collapse;
+ border: 1px solid #84b0c7;
+}
+TH.dirtab { background: #e8eef2;
+ font-weight: bold;
+}
+HR { height: 1px;
+ border: none;
+ border-top: 1px solid black;
+}
+
+/* Style for detailed member documentation */
+.memtemplate {
+ font-size: 80%;
+ color: #606060;
+ font-weight: normal;
+}
+.memnav {
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+.memitem {
+ padding: 4px;
+ background-color: #eef3f5;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #dedeee;
+ -moz-border-radius: 8px 8px 8px 8px;
+}
+.memname {
+ white-space: nowrap;
+ font-weight: bold;
+}
+.memdoc{
+ padding-left: 10px;
+}
+.memproto {
+ background-color: #d5e1e8;
+ width: 100%;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #84b0c7;
+ font-weight: bold;
+ -moz-border-radius: 8px 8px 8px 8px;
+}
+.paramkey {
+ text-align: right;
+}
+.paramtype {
+ white-space: nowrap;
+}
+.paramname {
+ color: #602020;
+ font-style: italic;
+ white-space: nowrap;
+}
+/* End Styling for detailed member documentation */
+
+/* for the tree view */
+.ftvtree {
+ font-family: sans-serif;
+ margin:0.5em;
+}
+.directory { font-size: 9pt; font-weight: bold; }
+.directory h3 { margin: 0px; margin-top: 1em; font-size: 11pt; }
+.directory > h3 { margin-top: 0; }
+.directory p { margin: 0px; white-space: nowrap; }
+.directory div { display: none; margin: 0px; }
+.directory img { vertical-align: -30%; }
diff --git a/source3/iniparser/html/doxygen.png b/source3/iniparser/html/doxygen.png
new file mode 100644
index 0000000000..f0a274bbaf
--- /dev/null
+++ b/source3/iniparser/html/doxygen.png
Binary files differ
diff --git a/source3/iniparser/html/globals_func.html b/source3/iniparser/html/globals_func.html
new file mode 100644
index 0000000000..dc5c7126f0
--- /dev/null
+++ b/source3/iniparser/html/globals_func.html
@@ -0,0 +1,54 @@
+<html>
+<head>
+ <meta name="author" content="ndevilla@free.fr">
+ <meta name="keywords" content="ini file, config file, parser, C library">
+ <link href="doxygen.css" rel="stylesheet" type="text/css">
+<title>iniparser 2.x</title>
+</head>
+
+<body text="#000000" bgcolor="#ffffff">
+
+
+
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="globals.html"><span>All</span></a></li>
+ <li id="current"><a href="globals_func.html"><span>Functions</span></a></li>
+ </ul>
+</div>
+&nbsp;
+<p>
+<ul>
+<li>iniparser_dump()
+: <a class="el" href="iniparser_8h.html#046436b3489cd8854ba8e29109250324">iniparser.h</a>
+<li>iniparser_dump_ini()
+: <a class="el" href="iniparser_8h.html#ece0e32de371c9e9592d8333f816dfac">iniparser.h</a>
+<li>iniparser_find_entry()
+: <a class="el" href="iniparser_8h.html#3d67c98bbc0cb5239f024ad54bdc63f1">iniparser.h</a>
+<li>iniparser_freedict()
+: <a class="el" href="iniparser_8h.html#90549ee518523921886b74454ff872eb">iniparser.h</a>
+<li>iniparser_getboolean()
+: <a class="el" href="iniparser_8h.html#eb93c13fcbb75efaa396f53bfd73ff4d">iniparser.h</a>
+<li>iniparser_getdouble()
+: <a class="el" href="iniparser_8h.html#480d35322f1252344cf2246ac21ee559">iniparser.h</a>
+<li>iniparser_getint()
+: <a class="el" href="iniparser_8h.html#694eb1110f4200db8648820a0bb405fa">iniparser.h</a>
+<li>iniparser_getnsec()
+: <a class="el" href="iniparser_8h.html#0b5d6cdc7587e2d27a30f5cdc4a91931">iniparser.h</a>
+<li>iniparser_getsecname()
+: <a class="el" href="iniparser_8h.html#393212be805f395bbfdeb1bafa8bb72a">iniparser.h</a>
+<li>iniparser_getstr()
+: <a class="el" href="iniparser_8h.html#587eafb48937fdee8ae414ad7a666db8">iniparser.h</a>
+<li>iniparser_getstring()
+: <a class="el" href="iniparser_8h.html#7894f8480e1f254d4a1b4a31bdc51b46">iniparser.h</a>
+<li>iniparser_load()
+: <a class="el" href="iniparser_8h.html#b0be559bfb769224b3f1b75e26242a67">iniparser.h</a>
+<li>iniparser_setstr()
+: <a class="el" href="iniparser_8h.html#605a88057bac4c3249513fc588421c32">iniparser.h</a>
+<li>iniparser_unset()
+: <a class="el" href="iniparser_8h.html#7b1a7f2492a35043867fa801b8f21e52">iniparser.h</a>
+</ul>
+
+</body>
+</html>
diff --git a/source3/iniparser/html/index.html b/source3/iniparser/html/index.html
new file mode 100644
index 0000000000..a09575587d
--- /dev/null
+++ b/source3/iniparser/html/index.html
@@ -0,0 +1,156 @@
+<html>
+<head>
+ <meta name="author" content="ndevilla@free.fr">
+ <meta name="keywords" content="ini file, config file, parser, C library">
+ <link href="doxygen.css" rel="stylesheet" type="text/css">
+<title>iniparser 2.x</title>
+</head>
+
+<body text="#000000" bgcolor="#ffffff">
+
+
+
+<!-- Generated by Doxygen 1.5.1 -->
+<h1>iniparser documentation</h1>
+<p>
+<h3 align="center">2.x </h3><hr>
+<h2><a class="anchor" name="welcome">
+Introduction</a></h2>
+iniParser is a simple C library offering ini file parsing services. The library is pretty small (less than 1500 lines of C) and robust, and does not depend on any other external library to compile. It is written in ANSI C and should compile anywhere without difficulty.<p>
+<hr>
+<h2><a class="anchor" name="inidef">
+What is an ini file?</a></h2>
+An ini file is an ASCII file describing simple parameters (character strings, integers, floating-point values or booleans) in an explicit format, easy to use and modify for users.<p>
+An ini file is segmented into Sections, declared by the following syntax:<p>
+<div class="fragment"><pre class="fragment">
+ [Section Name]
+ </pre></div><p>
+i.e. the section name enclosed in square brackets, alone on a line. Sections names are allowed to contain any character but square brackets or linefeeds. Slashes (/) are also reserved for hierarchical sections (see below).<p>
+In any section are zero or more variables, declared with the following syntax:<p>
+<div class="fragment"><pre class="fragment">
+ Key = value ; comment
+ </pre></div><p>
+The key is any string (possibly containing blanks). The value is any character on the right side of the equal sign. Values can be given enclosed with quotes. If no quotes are present, the value is understood as containing all characters between the first and the last non-blank characters. The following declarations are identical:<p>
+<div class="fragment"><pre class="fragment">
+ Hello = "this is a long string value" ; comment
+ Hello = this is a long string value ; comment
+ </pre></div><p>
+The semicolon and comment at the end of the line are optional. If there is a comment, it starts from the first character after the semicolon up to the end of the line.<p>
+Comments in an ini file are:<p>
+<ul>
+<li>Lines starting with a hash sign</li><li>Blank lines (only blanks or tabs)</li><li>Comments given on value lines after the semicolon (if present)</li></ul>
+<p>
+<hr>
+<h2><a class="anchor" name="install">
+Compiling/installing the library</a></h2>
+Edit the Makefile to indicate the C compiler you want to use, the options to provide to compile ANSI C, and possibly the options to pass to the <code>ar</code> program on your machine to build a library (.a) from a set of object (.o) files.<p>
+Defaults are set for the gcc compiler and the standard ar library builder.<p>
+Type 'make', that should do it.<p>
+To use the library in your programs, add the following line on top of your module:<p>
+<div class="fragment"><pre class="fragment"><span class="preprocessor"> #include "<a class="code" href="iniparser_8h.html">iniparser.h</a>"</span>
+</pre></div><p>
+And link your program with the iniparser library by adding <code>-liniparser.a</code> to the compile line.<p>
+See the file test/initest.c for an example.<p>
+<hr>
+<h2><a class="anchor" name="reference">
+Library reference</a></h2>
+The library is completely documented in its header file. On-line documentation has been generated and can be consulted here:<p>
+<ul>
+<li><a class="el" href="iniparser_8h.html">iniparser.h</a></li></ul>
+<p>
+<hr>
+<h2><a class="anchor" name="usage">
+Using the parser</a></h2>
+Comments are discarded by the parser. Then sections are identified, and in each section a new entry is created for every keyword found. The keywords are stored with the following syntax:<p>
+<div class="fragment"><pre class="fragment">
+ [Section]
+ Keyword = value ; comment
+ </pre></div><p>
+is converted to the following key pair:<p>
+<div class="fragment"><pre class="fragment">
+ ("section:keyword", "value")
+ </pre></div><p>
+This means that if you want to retrieve the value that was stored in the section called <code>Pizza</code>, in the keyword <code>Cheese</code>, you would make a request to the dictionary for <code>"pizza:cheese"</code>. All section and keyword names are converted to lowercase before storage in the structure. The value side is conserved as it has been parsed, though.<p>
+Section names are also stored in the structure. They are stored using as key the section name, and a NULL associated value. They can be queried through <a class="el" href="iniparser_8h.html#3d67c98bbc0cb5239f024ad54bdc63f1">iniparser_find_entry()</a>.<p>
+To launch the parser, simply use the function called <a class="el" href="iniparser_8h.html#b0be559bfb769224b3f1b75e26242a67">iniparser_load()</a>, which takes an input file name and returns a newly allocated <em>dictionary</em> structure. This latter object should remain opaque to the user and only accessed through the following accessor functions:<p>
+<ul>
+<li><a class="el" href="iniparser_8h.html#587eafb48937fdee8ae414ad7a666db8">iniparser_getstr()</a></li><li><a class="el" href="iniparser_8h.html#694eb1110f4200db8648820a0bb405fa">iniparser_getint()</a></li><li><a class="el" href="iniparser_8h.html#480d35322f1252344cf2246ac21ee559">iniparser_getdouble()</a></li><li><a class="el" href="iniparser_8h.html#eb93c13fcbb75efaa396f53bfd73ff4d">iniparser_getboolean()</a></li></ul>
+<p>
+Finally, discard this structure using <a class="el" href="iniparser_8h.html#90549ee518523921886b74454ff872eb">iniparser_freedict()</a>.<p>
+All values parsed from the ini file are stored as strings. The getint, getdouble and getboolean accessors are just converting these strings to the requested type on the fly, but you could basically perform this conversion by yourself after having called the getstr accessor.<p>
+Notice that the <a class="el" href="iniparser_8h.html#eb93c13fcbb75efaa396f53bfd73ff4d">iniparser_getboolean()</a> function will return an integer (0 or 1), trying to make sense of what was found in the file. Strings starting with "y", "Y", "t", "T" or "1" are considered true values (return 1), strings starting with "n", "N", "f", "F", "0" are considered false (return 0). This allows flexible handling of boolean answers.<p>
+If you want to add extra information into the structure that was not present in the ini file, you can use <a class="el" href="iniparser_8h.html#605a88057bac4c3249513fc588421c32">iniparser_setstr()</a> to insert a string.<p>
+<hr>
+<h2><a class="anchor" name="implementation">
+A word about the implementation</a></h2>
+The dictionary structure is a pretty simple dictionary implementation which might find some uses in other applications. If you are curious, look into the source.<p>
+<hr>
+<h2><a class="anchor" name="hierarchical">
+Hierarchical ini files</a></h2>
+ini files are nice to present informations to the user in a readable format, but lack a very useful feature: the possibility of organizing data in a hierarchical (tree-like) fashion. The following convention can be used to make ini files obtain this second dimension:<p>
+A section depends on another section if it contains its name as a prefix, separated by slashes (/). For example: we have 2 main sections in the ini file. The first one is called <code>Pizza</code> and has two child subsections called <code>Cheese</code> and <code>Ham</code>. The second main section in the ini file is called <code>Wine</code> and has two child subsections called <code>Year</code> and <code>Grape</code>. As a tree, this could appear as:<p>
+<div class="fragment"><pre class="fragment">
+ |
+ +-- Pizza
+ | +-- Cheese
+ | +-- Ham
+ +-- Wine
+ +--- Year
+ +--- Grape
+ </pre></div><p>
+In an ini file, that would be converted to:<p>
+<div class="fragment"><pre class="fragment">
+ [Pizza]
+
+ [Pizza/Cheese]
+ Name = Gorgonzola ;
+ Origin = Italy ;
+
+ [Pizza/Ham]
+ Name = Parma ;
+ Origin = Italy ;
+
+ [Wine]
+
+ [Wine/Year]
+ Value = 1998 ;
+
+ [Wine/Grape]
+ Name = Cabernet Sauvignon ;
+ Origin = Chile ;
+ </pre></div><p>
+This proposal is actually more related to the way people write ini files, more than the parser presented here. But it is certainly a useful way of making tree-like data declarations without going through painful formats like XML.<p>
+Accessing the above tree would give something like (error checking removed for clarity sake):<p>
+<div class="fragment"><pre class="fragment"> dictionary * d ;
+
+ d = <a class="code" href="iniparser_8h.html#b0be559bfb769224b3f1b75e26242a67">iniparser_load</a>(<span class="stringliteral">"example.ini"</span>);
+
+ printf(<span class="stringliteral">"cheese name is %s\n"</span>, <a class="code" href="iniparser_8h.html#587eafb48937fdee8ae414ad7a666db8">iniparser_getstr</a>(d, <span class="stringliteral">"pizza/cheese:name"</span>));
+ printf(<span class="stringliteral">"grape name is %s\n"</span>, <a class="code" href="iniparser_8h.html#587eafb48937fdee8ae414ad7a666db8">iniparser_getstr</a>(d, <span class="stringliteral">"wine/grape:name"</span>));
+
+ <a class="code" href="iniparser_8h.html#90549ee518523921886b74454ff872eb">iniparser_freedict</a>(d);
+</pre></div><p>
+The whole ini file above is represented in the dictionary as the following list of pairs:<p>
+<div class="fragment"><pre class="fragment">
+ key value
+
+ "pizza" NULL
+ "pizza/cheese" NULL
+ "pizza/cheese:name" "Gorgonzola"
+ "pizza/cheese:origin" "Italy"
+ "pizza/ham" NULL
+ "pizza/ham:name" "Parma"
+ "pizza/ham:origin" "Italy"
+ "wine" NULL
+ "wine/year" NULL
+ "wine/year:value" "1998"
+ "wine/grape" NULL
+ "wine/grape:name" "Cabernet Sauvignon"
+ "wine/grape:origin" "Chile"
+ </pre></div><p>
+<hr>
+<h2><a class="anchor" name="authors">
+Authors</a></h2>
+Nicolas Devillard (ndevilla AT free DOT fr).
+</body>
+</html>
diff --git a/source3/iniparser/html/iniparser_8h.html b/source3/iniparser/html/iniparser_8h.html
new file mode 100644
index 0000000000..9a7d5ecbc3
--- /dev/null
+++ b/source3/iniparser/html/iniparser_8h.html
@@ -0,0 +1,629 @@
+<html>
+<head>
+ <meta name="author" content="ndevilla@free.fr">
+ <meta name="keywords" content="ini file, config file, parser, C library">
+ <link href="doxygen.css" rel="stylesheet" type="text/css">
+<title>iniparser 2.x</title>
+</head>
+
+<body text="#000000" bgcolor="#ffffff">
+
+
+
+<!-- Generated by Doxygen 1.5.1 -->
+<h1>iniparser.h File Reference</h1>Parser for ini files. <a href="#_details">More...</a>
+<p>
+<table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+<tr><td colspan="2"><br><h2>Functions</h2></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">int&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#0b5d6cdc7587e2d27a30f5cdc4a91931">iniparser_getnsec</a> (dictionary *d)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Get number of sections in a dictionary. <a href="#0b5d6cdc7587e2d27a30f5cdc4a91931"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">char *&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#393212be805f395bbfdeb1bafa8bb72a">iniparser_getsecname</a> (dictionary *d, int n)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Get name for section n in a dictionary. <a href="#393212be805f395bbfdeb1bafa8bb72a"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#ece0e32de371c9e9592d8333f816dfac">iniparser_dump_ini</a> (dictionary *d, FILE *f)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Save a dictionary to a loadable ini file. <a href="#ece0e32de371c9e9592d8333f816dfac"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#046436b3489cd8854ba8e29109250324">iniparser_dump</a> (dictionary *d, FILE *f)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Dump a dictionary to an opened file pointer. <a href="#046436b3489cd8854ba8e29109250324"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">char *&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#587eafb48937fdee8ae414ad7a666db8">iniparser_getstr</a> (dictionary *d, const char *key)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Get the string associated to a key, return NULL if not found. <a href="#587eafb48937fdee8ae414ad7a666db8"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">char *&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#7894f8480e1f254d4a1b4a31bdc51b46">iniparser_getstring</a> (dictionary *d, const char *key, char *def)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Get the string associated to a key. <a href="#7894f8480e1f254d4a1b4a31bdc51b46"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">int&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#694eb1110f4200db8648820a0bb405fa">iniparser_getint</a> (dictionary *d, const char *key, int notfound)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Get the string associated to a key, convert to an int. <a href="#694eb1110f4200db8648820a0bb405fa"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">double&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#480d35322f1252344cf2246ac21ee559">iniparser_getdouble</a> (dictionary *d, char *key, double notfound)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Get the string associated to a key, convert to a double. <a href="#480d35322f1252344cf2246ac21ee559"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">int&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#eb93c13fcbb75efaa396f53bfd73ff4d">iniparser_getboolean</a> (dictionary *d, const char *key, int notfound)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Get the string associated to a key, convert to a boolean. <a href="#eb93c13fcbb75efaa396f53bfd73ff4d"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">int&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#605a88057bac4c3249513fc588421c32">iniparser_setstr</a> (dictionary *ini, char *entry, char *val)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Set an entry in a dictionary. <a href="#605a88057bac4c3249513fc588421c32"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#7b1a7f2492a35043867fa801b8f21e52">iniparser_unset</a> (dictionary *ini, char *entry)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Delete an entry in a dictionary. <a href="#7b1a7f2492a35043867fa801b8f21e52"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">int&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#3d67c98bbc0cb5239f024ad54bdc63f1">iniparser_find_entry</a> (dictionary *ini, char *entry)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Finds out if a given entry exists in a dictionary. <a href="#3d67c98bbc0cb5239f024ad54bdc63f1"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">dictionary *&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#b0be559bfb769224b3f1b75e26242a67">iniparser_load</a> (const char *ininame)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Parse an ini file and return an allocated dictionary object. <a href="#b0be559bfb769224b3f1b75e26242a67"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#90549ee518523921886b74454ff872eb">iniparser_freedict</a> (dictionary *d)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Free all memory associated to an ini dictionary. <a href="#90549ee518523921886b74454ff872eb"></a><br></td></tr>
+</table>
+<hr><a name="_details"></a><h2>Detailed Description</h2>
+Parser for ini files.
+<p>
+<dl class="author" compact><dt><b>Author:</b></dt><dd>N. Devillard </dd></dl>
+<dl class="date" compact><dt><b>Date:</b></dt><dd>Mar 2000 </dd></dl>
+<dl class="version" compact><dt><b>Version:</b></dt><dd><dl class="rcs" compact><dt><b>Revision</b></dt><dd>1.23 </dd></dl>
+</dd></dl>
+<hr><h2>Function Documentation</h2>
+<a class="anchor" name="046436b3489cd8854ba8e29109250324"></a><!-- doxytag: member="iniparser.h::iniparser_dump" ref="046436b3489cd8854ba8e29109250324" args="(dictionary *d, FILE *f)" -->
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">void iniparser_dump </td>
+ <td>(</td>
+ <td class="paramtype">dictionary *&nbsp;</td>
+ <td class="paramname"> <em>d</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">FILE *&nbsp;</td>
+ <td class="paramname"> <em>f</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Dump a dictionary to an opened file pointer.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to dump. </td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>f</em>&nbsp;</td><td>Opened file pointer to dump to. </td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>void</dd></dl>
+This function prints out the contents of a dictionary, one element by line, onto the provided file pointer. It is OK to specify <code>stderr</code> or <code>stdout</code> as output files. This function is meant for debugging purposes mostly.
+</div>
+</div><p>
+<a class="anchor" name="ece0e32de371c9e9592d8333f816dfac"></a><!-- doxytag: member="iniparser.h::iniparser_dump_ini" ref="ece0e32de371c9e9592d8333f816dfac" args="(dictionary *d, FILE *f)" -->
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">void iniparser_dump_ini </td>
+ <td>(</td>
+ <td class="paramtype">dictionary *&nbsp;</td>
+ <td class="paramname"> <em>d</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">FILE *&nbsp;</td>
+ <td class="paramname"> <em>f</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Save a dictionary to a loadable ini file.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to dump </td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>f</em>&nbsp;</td><td>Opened file pointer to dump to </td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>void</dd></dl>
+This function dumps a given dictionary into a loadable ini file. It is Ok to specify <code>stderr</code> or <code>stdout</code> as output files.
+</div>
+</div><p>
+<a class="anchor" name="3d67c98bbc0cb5239f024ad54bdc63f1"></a><!-- doxytag: member="iniparser.h::iniparser_find_entry" ref="3d67c98bbc0cb5239f024ad54bdc63f1" args="(dictionary *ini, char *entry)" -->
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">int iniparser_find_entry </td>
+ <td>(</td>
+ <td class="paramtype">dictionary *&nbsp;</td>
+ <td class="paramname"> <em>ini</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">char *&nbsp;</td>
+ <td class="paramname"> <em>entry</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Finds out if a given entry exists in a dictionary.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>ini</em>&nbsp;</td><td>Dictionary to search </td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>entry</em>&nbsp;</td><td>Name of the entry to look for </td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>integer 1 if entry exists, 0 otherwise</dd></dl>
+Finds out if a given entry exists in the dictionary. Since sections are stored as keys with NULL associated values, this is the only way of querying for the presence of sections in a dictionary.
+</div>
+</div><p>
+<a class="anchor" name="90549ee518523921886b74454ff872eb"></a><!-- doxytag: member="iniparser.h::iniparser_freedict" ref="90549ee518523921886b74454ff872eb" args="(dictionary *d)" -->
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">void iniparser_freedict </td>
+ <td>(</td>
+ <td class="paramtype">dictionary *&nbsp;</td>
+ <td class="paramname"> <em>d</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Free all memory associated to an ini dictionary.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to free </td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>void</dd></dl>
+Free all memory associated to an ini dictionary. It is mandatory to call this function before the dictionary object gets out of the current context.
+</div>
+</div><p>
+<a class="anchor" name="eb93c13fcbb75efaa396f53bfd73ff4d"></a><!-- doxytag: member="iniparser.h::iniparser_getboolean" ref="eb93c13fcbb75efaa396f53bfd73ff4d" args="(dictionary *d, const char *key, int notfound)" -->
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">int iniparser_getboolean </td>
+ <td>(</td>
+ <td class="paramtype">dictionary *&nbsp;</td>
+ <td class="paramname"> <em>d</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">const char *&nbsp;</td>
+ <td class="paramname"> <em>key</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int&nbsp;</td>
+ <td class="paramname"> <em>notfound</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Get the string associated to a key, convert to a boolean.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to search </td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>key</em>&nbsp;</td><td>Key string to look for </td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>notfound</em>&nbsp;</td><td>Value to return in case of error </td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>integer</dd></dl>
+This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the notfound value is returned.<p>
+A true boolean is found if one of the following is matched:<p>
+<ul>
+<li>A string starting with 'y'</li><li>A string starting with 'Y'</li><li>A string starting with 't'</li><li>A string starting with 'T'</li><li>A string starting with '1'</li></ul>
+<p>
+A false boolean is found if one of the following is matched:<p>
+<ul>
+<li>A string starting with 'n'</li><li>A string starting with 'N'</li><li>A string starting with 'f'</li><li>A string starting with 'F'</li><li>A string starting with '0'</li></ul>
+<p>
+The notfound value returned if no boolean is identified, does not necessarily have to be 0 or 1.
+</div>
+</div><p>
+<a class="anchor" name="480d35322f1252344cf2246ac21ee559"></a><!-- doxytag: member="iniparser.h::iniparser_getdouble" ref="480d35322f1252344cf2246ac21ee559" args="(dictionary *d, char *key, double notfound)" -->
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">double iniparser_getdouble </td>
+ <td>(</td>
+ <td class="paramtype">dictionary *&nbsp;</td>
+ <td class="paramname"> <em>d</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">char *&nbsp;</td>
+ <td class="paramname"> <em>key</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">double&nbsp;</td>
+ <td class="paramname"> <em>notfound</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Get the string associated to a key, convert to a double.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to search </td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>key</em>&nbsp;</td><td>Key string to look for </td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>notfound</em>&nbsp;</td><td>Value to return in case of error </td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>double</dd></dl>
+This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the notfound value is returned.
+</div>
+</div><p>
+<a class="anchor" name="694eb1110f4200db8648820a0bb405fa"></a><!-- doxytag: member="iniparser.h::iniparser_getint" ref="694eb1110f4200db8648820a0bb405fa" args="(dictionary *d, const char *key, int notfound)" -->
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">int iniparser_getint </td>
+ <td>(</td>
+ <td class="paramtype">dictionary *&nbsp;</td>
+ <td class="paramname"> <em>d</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">const char *&nbsp;</td>
+ <td class="paramname"> <em>key</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int&nbsp;</td>
+ <td class="paramname"> <em>notfound</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Get the string associated to a key, convert to an int.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to search </td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>key</em>&nbsp;</td><td>Key string to look for </td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>notfound</em>&nbsp;</td><td>Value to return in case of error </td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>integer</dd></dl>
+This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the notfound value is returned.<p>
+Supported values for integers include the usual C notation so decimal, octal (starting with 0) and hexadecimal (starting with 0x) are supported. Examples:<p>
+<ul>
+<li>"42" -&gt; 42</li><li>"042" -&gt; 34 (octal -&gt; decimal)</li><li>"0x42" -&gt; 66 (hexa -&gt; decimal)</li></ul>
+<p>
+Warning: the conversion may overflow in various ways. Conversion is totally outsourced to strtol(), see the associated man page for overflow handling.<p>
+Credits: Thanks to A. Becker for suggesting strtol()
+</div>
+</div><p>
+<a class="anchor" name="0b5d6cdc7587e2d27a30f5cdc4a91931"></a><!-- doxytag: member="iniparser.h::iniparser_getnsec" ref="0b5d6cdc7587e2d27a30f5cdc4a91931" args="(dictionary *d)" -->
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">int iniparser_getnsec </td>
+ <td>(</td>
+ <td class="paramtype">dictionary *&nbsp;</td>
+ <td class="paramname"> <em>d</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Get number of sections in a dictionary.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to examine </td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>int Number of sections found in dictionary</dd></dl>
+This function returns the number of sections found in a dictionary. The test to recognize sections is done on the string stored in the dictionary: a section name is given as "section" whereas a key is stored as "section:key", thus the test looks for entries that do not contain a colon.<p>
+This clearly fails in the case a section name contains a colon, but this should simply be avoided.<p>
+This function returns -1 in case of error.
+</div>
+</div><p>
+<a class="anchor" name="393212be805f395bbfdeb1bafa8bb72a"></a><!-- doxytag: member="iniparser.h::iniparser_getsecname" ref="393212be805f395bbfdeb1bafa8bb72a" args="(dictionary *d, int n)" -->
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">char* iniparser_getsecname </td>
+ <td>(</td>
+ <td class="paramtype">dictionary *&nbsp;</td>
+ <td class="paramname"> <em>d</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int&nbsp;</td>
+ <td class="paramname"> <em>n</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Get name for section n in a dictionary.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to examine </td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>n</em>&nbsp;</td><td>Section number (from 0 to nsec-1). </td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Pointer to char string</dd></dl>
+This function locates the n-th section in a dictionary and returns its name as a pointer to a string statically allocated inside the dictionary. Do not free or modify the returned string!<p>
+This function returns NULL in case of error.
+</div>
+</div><p>
+<a class="anchor" name="587eafb48937fdee8ae414ad7a666db8"></a><!-- doxytag: member="iniparser.h::iniparser_getstr" ref="587eafb48937fdee8ae414ad7a666db8" args="(dictionary *d, const char *key)" -->
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">char* iniparser_getstr </td>
+ <td>(</td>
+ <td class="paramtype">dictionary *&nbsp;</td>
+ <td class="paramname"> <em>d</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">const char *&nbsp;</td>
+ <td class="paramname"> <em>key</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Get the string associated to a key, return NULL if not found.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to search </td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>key</em>&nbsp;</td><td>Key string to look for </td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>pointer to statically allocated character string, or NULL.</dd></dl>
+This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, NULL is returned. The returned char pointer is pointing to a string allocated in the dictionary, do not free or modify it.<p>
+This function is only provided for backwards compatibility with previous versions of iniparser. It is recommended to use <a class="el" href="iniparser_8h.html#7894f8480e1f254d4a1b4a31bdc51b46">iniparser_getstring()</a> instead.
+</div>
+</div><p>
+<a class="anchor" name="7894f8480e1f254d4a1b4a31bdc51b46"></a><!-- doxytag: member="iniparser.h::iniparser_getstring" ref="7894f8480e1f254d4a1b4a31bdc51b46" args="(dictionary *d, const char *key, char *def)" -->
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">char* iniparser_getstring </td>
+ <td>(</td>
+ <td class="paramtype">dictionary *&nbsp;</td>
+ <td class="paramname"> <em>d</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">const char *&nbsp;</td>
+ <td class="paramname"> <em>key</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">char *&nbsp;</td>
+ <td class="paramname"> <em>def</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Get the string associated to a key.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>d</em>&nbsp;</td><td>Dictionary to search </td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>key</em>&nbsp;</td><td>Key string to look for </td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>def</em>&nbsp;</td><td>Default value to return if key not found. </td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>pointer to statically allocated character string</dd></dl>
+This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the pointer passed as 'def' is returned. The returned char pointer is pointing to a string allocated in the dictionary, do not free or modify it.
+</div>
+</div><p>
+<a class="anchor" name="b0be559bfb769224b3f1b75e26242a67"></a><!-- doxytag: member="iniparser.h::iniparser_load" ref="b0be559bfb769224b3f1b75e26242a67" args="(const char *ininame)" -->
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">dictionary* iniparser_load </td>
+ <td>(</td>
+ <td class="paramtype">const char *&nbsp;</td>
+ <td class="paramname"> <em>ininame</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Parse an ini file and return an allocated dictionary object.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>ininame</em>&nbsp;</td><td>Name of the ini file to read. </td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Pointer to newly allocated dictionary</dd></dl>
+This is the parser for ini files. This function is called, providing the name of the file to be read. It returns a dictionary object that should not be accessed directly, but through accessor functions instead.<p>
+The returned dictionary must be freed using <a class="el" href="iniparser_8h.html#90549ee518523921886b74454ff872eb">iniparser_freedict()</a>.
+</div>
+</div><p>
+<a class="anchor" name="605a88057bac4c3249513fc588421c32"></a><!-- doxytag: member="iniparser.h::iniparser_setstr" ref="605a88057bac4c3249513fc588421c32" args="(dictionary *ini, char *entry, char *val)" -->
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">int iniparser_setstr </td>
+ <td>(</td>
+ <td class="paramtype">dictionary *&nbsp;</td>
+ <td class="paramname"> <em>ini</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">char *&nbsp;</td>
+ <td class="paramname"> <em>entry</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">char *&nbsp;</td>
+ <td class="paramname"> <em>val</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Set an entry in a dictionary.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>ini</em>&nbsp;</td><td>Dictionary to modify. </td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>entry</em>&nbsp;</td><td>Entry to modify (entry name) </td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>val</em>&nbsp;</td><td>New value to associate to the entry. </td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>int 0 if Ok, -1 otherwise.</dd></dl>
+If the given entry can be found in the dictionary, it is modified to contain the provided value. If it cannot be found, -1 is returned. It is Ok to set val to NULL.
+</div>
+</div><p>
+<a class="anchor" name="7b1a7f2492a35043867fa801b8f21e52"></a><!-- doxytag: member="iniparser.h::iniparser_unset" ref="7b1a7f2492a35043867fa801b8f21e52" args="(dictionary *ini, char *entry)" -->
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">void iniparser_unset </td>
+ <td>(</td>
+ <td class="paramtype">dictionary *&nbsp;</td>
+ <td class="paramname"> <em>ini</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">char *&nbsp;</td>
+ <td class="paramname"> <em>entry</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Delete an entry in a dictionary.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>ini</em>&nbsp;</td><td>Dictionary to modify </td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>entry</em>&nbsp;</td><td>Entry to delete (entry name) </td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>void</dd></dl>
+If the given entry can be found, it is deleted from the dictionary.
+</div>
+</div><p>
+
+</body>
+</html>
diff --git a/source3/iniparser/html/iniparser_8main.html b/source3/iniparser/html/iniparser_8main.html
new file mode 100644
index 0000000000..a00eed2f9e
--- /dev/null
+++ b/source3/iniparser/html/iniparser_8main.html
@@ -0,0 +1,19 @@
+<html>
+<head>
+ <meta name="author" content="ndevilla@free.fr">
+ <meta name="keywords" content="ini file, config file, parser, C library">
+ <link href="doxygen.css" rel="stylesheet" type="text/css">
+<title>iniparser 2.x</title>
+</head>
+
+<body text="#000000" bgcolor="#ffffff">
+
+
+
+<!-- Generated by Doxygen 1.5.1 -->
+<h1>iniparser.main File Reference</h1><table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+</table>
+
+</body>
+</html>
diff --git a/source3/iniparser/html/tab_b.gif b/source3/iniparser/html/tab_b.gif
new file mode 100644
index 0000000000..0d623483ff
--- /dev/null
+++ b/source3/iniparser/html/tab_b.gif
Binary files differ
diff --git a/source3/iniparser/html/tab_l.gif b/source3/iniparser/html/tab_l.gif
new file mode 100644
index 0000000000..9b1e6337c9
--- /dev/null
+++ b/source3/iniparser/html/tab_l.gif
Binary files differ
diff --git a/source3/iniparser/html/tab_r.gif b/source3/iniparser/html/tab_r.gif
new file mode 100644
index 0000000000..ce9dd9f533
--- /dev/null
+++ b/source3/iniparser/html/tab_r.gif
Binary files differ
diff --git a/source3/iniparser/html/tabs.css b/source3/iniparser/html/tabs.css
new file mode 100644
index 0000000000..a61552a67a
--- /dev/null
+++ b/source3/iniparser/html/tabs.css
@@ -0,0 +1,102 @@
+/* tabs styles, based on http://www.alistapart.com/articles/slidingdoors */
+
+DIV.tabs
+{
+ float : left;
+ width : 100%;
+ background : url("tab_b.gif") repeat-x bottom;
+ margin-bottom : 4px;
+}
+
+DIV.tabs UL
+{
+ margin : 0px;
+ padding-left : 10px;
+ list-style : none;
+}
+
+DIV.tabs LI, DIV.tabs FORM
+{
+ display : inline;
+ margin : 0px;
+ padding : 0px;
+}
+
+DIV.tabs FORM
+{
+ float : right;
+}
+
+DIV.tabs A
+{
+ float : left;
+ background : url("tab_r.gif") no-repeat right top;
+ border-bottom : 1px solid #84B0C7;
+ font-size : x-small;
+ font-weight : bold;
+ text-decoration : none;
+}
+
+DIV.tabs A:hover
+{
+ background-position: 100% -150px;
+}
+
+DIV.tabs A:link, DIV.tabs A:visited,
+DIV.tabs A:active, DIV.tabs A:hover
+{
+ color: #1A419D;
+}
+
+DIV.tabs SPAN
+{
+ float : left;
+ display : block;
+ background : url("tab_l.gif") no-repeat left top;
+ padding : 5px 9px;
+ white-space : nowrap;
+}
+
+DIV.tabs INPUT
+{
+ float : right;
+ display : inline;
+ font-size : 1em;
+}
+
+DIV.tabs TD
+{
+ font-size : x-small;
+ font-weight : bold;
+ text-decoration : none;
+}
+
+
+
+/* Commented Backslash Hack hides rule from IE5-Mac \*/
+DIV.tabs SPAN {float : none;}
+/* End IE5-Mac hack */
+
+DIV.tabs A:hover SPAN
+{
+ background-position: 0% -150px;
+}
+
+DIV.tabs LI#current A
+{
+ background-position: 100% -150px;
+ border-width : 0px;
+}
+
+DIV.tabs LI#current SPAN
+{
+ background-position: 0% -150px;
+ padding-bottom : 6px;
+}
+
+DIV.nav
+{
+ background : none;
+ border : none;
+ border-bottom : 1px solid #84B0C7;
+}
diff --git a/source3/iniparser/src/dictionary.c b/source3/iniparser/src/dictionary.c
new file mode 100644
index 0000000000..b9d426dc7e
--- /dev/null
+++ b/source3/iniparser/src/dictionary.c
@@ -0,0 +1,514 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file dictionary.c
+ @author N. Devillard
+ @date Aug 2000
+ @version $Revision: 1.25 $
+ @brief Implements a dictionary for string variables.
+
+ This module implements a simple dictionary object, i.e. a list
+ of string/string associations. This object is useful to store e.g.
+ informations retrieved from a configuration file (ini files).
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+ $Id: dictionary.c,v 1.25 2007-05-27 13:03:43 ndevilla Exp $
+ $Author: ndevilla $
+ $Date: 2007-05-27 13:03:43 $
+ $Revision: 1.25 $
+*/
+
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+
+#include "dictionary.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+/** Maximum value size for integers and doubles. */
+#define MAXVALSZ 1024
+
+/** Minimal allocated number of entries in a dictionary */
+#define DICTMINSZ 128
+
+/** Invalid key token */
+#define DICT_INVALID_KEY ((char*)-1)
+
+
+/*---------------------------------------------------------------------------
+ Private functions
+ ---------------------------------------------------------------------------*/
+
+/* Doubles the allocated size associated to a pointer */
+/* 'size' is the current allocated size. */
+static void * mem_double(void * ptr, int size)
+{
+ void * newptr ;
+
+ newptr = calloc(2*size, 1);
+ memcpy(newptr, ptr, size);
+ free(ptr);
+ return newptr ;
+}
+
+
+/*---------------------------------------------------------------------------
+ Function codes
+ ---------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Compute the hash key for a string.
+ @param key Character string to use for key.
+ @return 1 unsigned int on at least 32 bits.
+
+ This hash function has been taken from an Article in Dr Dobbs Journal.
+ This is normally a collision-free function, distributing keys evenly.
+ The key is stored anyway in the struct so that collision can be avoided
+ by comparing the key itself in last resort.
+ */
+/*--------------------------------------------------------------------------*/
+
+unsigned dictionary_hash(char * key)
+{
+ int len ;
+ unsigned hash ;
+ int i ;
+
+ len = strlen(key);
+ for (hash=0, i=0 ; i<len ; i++) {
+ hash += (unsigned)key[i] ;
+ hash += (hash<<10);
+ hash ^= (hash>>6) ;
+ }
+ hash += (hash <<3);
+ hash ^= (hash >>11);
+ hash += (hash <<15);
+ return hash ;
+}
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Create a new dictionary object.
+ @param size Optional initial size of the dictionary.
+ @return 1 newly allocated dictionary objet.
+
+ This function allocates a new dictionary object of given size and returns
+ it. If you do not know in advance (roughly) the number of entries in the
+ dictionary, give size=0.
+ */
+/*--------------------------------------------------------------------------*/
+
+dictionary * dictionary_new(int size)
+{
+ dictionary * d ;
+
+ /* If no size was specified, allocate space for DICTMINSZ */
+ if (size<DICTMINSZ) size=DICTMINSZ ;
+
+ if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) {
+ return NULL;
+ }
+ d->size = size ;
+ d->val = (char **)calloc(size, sizeof(char*));
+ d->key = (char **)calloc(size, sizeof(char*));
+ d->hash = (unsigned int *)calloc(size, sizeof(unsigned));
+ return d ;
+}
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a dictionary object
+ @param d dictionary object to deallocate.
+ @return void
+
+ Deallocate a dictionary object and all memory associated to it.
+ */
+/*--------------------------------------------------------------------------*/
+
+void dictionary_del(dictionary * d)
+{
+ int i ;
+
+ if (d==NULL) return ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]!=NULL)
+ free(d->key[i]);
+ if (d->val[i]!=NULL)
+ free(d->val[i]);
+ }
+ free(d->val);
+ free(d->key);
+ free(d->hash);
+ free(d);
+ return ;
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get a value from a dictionary.
+ @param d dictionary object to search.
+ @param key Key to look for in the dictionary.
+ @param def Default value to return if key not found.
+ @return 1 pointer to internally allocated character string.
+
+ This function locates a key in a dictionary and returns a pointer to its
+ value, or the passed 'def' pointer if no such key can be found in
+ dictionary. The returned character pointer points to data internal to the
+ dictionary object, you should not try to free it or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * dictionary_get(dictionary * d, char * key, char * def)
+{
+ unsigned hash ;
+ int i ;
+
+ hash = dictionary_hash(key);
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key==NULL)
+ continue ;
+ /* Compare hash */
+ if (hash==d->hash[i]) {
+ /* Compare string, to avoid hash collisions */
+ if (!strcmp(key, d->key[i])) {
+ return d->val[i] ;
+ }
+ }
+ }
+ return def ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get a value from a dictionary, as a char.
+ @param d dictionary object to search.
+ @param key Key to look for in the dictionary.
+ @param def Default value for the key if not found.
+ @return char
+
+ This function locates a key in a dictionary using dictionary_get,
+ and returns the first char of the found string.
+ */
+/*--------------------------------------------------------------------------*/
+char dictionary_getchar(dictionary * d, char * key, char def)
+{
+ char * v ;
+
+ if ((v=dictionary_get(d,key,DICT_INVALID_KEY))==DICT_INVALID_KEY) {
+ return def ;
+ } else {
+ return v[0] ;
+ }
+}
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get a value from a dictionary, as an int.
+ @param d dictionary object to search.
+ @param key Key to look for in the dictionary.
+ @param def Default value for the key if not found.
+ @return int
+
+ This function locates a key in a dictionary using dictionary_get,
+ and applies atoi on it to return an int. If the value cannot be found
+ in the dictionary, the default is returned.
+ */
+/*--------------------------------------------------------------------------*/
+int dictionary_getint(dictionary * d, char * key, int def)
+{
+ char * v ;
+
+ if ((v=dictionary_get(d,key,DICT_INVALID_KEY))==DICT_INVALID_KEY) {
+ return def ;
+ } else {
+ return atoi(v);
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get a value from a dictionary, as a double.
+ @param d dictionary object to search.
+ @param key Key to look for in the dictionary.
+ @param def Default value for the key if not found.
+ @return double
+
+ This function locates a key in a dictionary using dictionary_get,
+ and applies atof on it to return a double. If the value cannot be found
+ in the dictionary, the default is returned.
+ */
+/*--------------------------------------------------------------------------*/
+double dictionary_getdouble(dictionary * d, char * key, double def)
+{
+ char * v ;
+
+ if ((v=dictionary_get(d,key,DICT_INVALID_KEY))==DICT_INVALID_KEY) {
+ return def ;
+ } else {
+ return atof(v);
+ }
+}
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set a value in a dictionary.
+ @param d dictionary object to modify.
+ @param key Key to modify or add.
+ @param val Value to add.
+ @return void
+
+ If the given key is found in the dictionary, the associated value is
+ replaced by the provided one. If the key cannot be found in the
+ dictionary, it is added to it.
+
+ It is Ok to provide a NULL value for val, but NULL values for the dictionary
+ or the key are considered as errors: the function will return immediately
+ in such a case.
+
+ Notice that if you dictionary_set a variable to NULL, a call to
+ dictionary_get will return a NULL value: the variable will be found, and
+ its value (NULL) is returned. In other words, setting the variable
+ content to NULL is equivalent to deleting the variable from the
+ dictionary. It is not possible (in this implementation) to have a key in
+ the dictionary without value.
+ */
+/*--------------------------------------------------------------------------*/
+
+void dictionary_set(dictionary * d, char * key, char * val)
+{
+ int i ;
+ unsigned hash ;
+
+ if (d==NULL || key==NULL) return ;
+
+ /* Compute hash for this key */
+ hash = dictionary_hash(key) ;
+ /* Find if value is already in blackboard */
+ if (d->n>0) {
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (hash==d->hash[i]) { /* Same hash value */
+ if (!strcmp(key, d->key[i])) { /* Same key */
+ /* Found a value: modify and return */
+ if (d->val[i]!=NULL)
+ free(d->val[i]);
+ d->val[i] = val ? strdup(val) : NULL ;
+ /* Value has been modified: return */
+ return ;
+ }
+ }
+ }
+ }
+ /* Add a new value */
+ /* See if dictionary needs to grow */
+ if (d->n==d->size) {
+
+ /* Reached maximum size: reallocate blackboard */
+ d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ;
+ d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ;
+ d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ;
+
+ /* Double size */
+ d->size *= 2 ;
+ }
+
+ /* Insert key in the first empty slot */
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL) {
+ /* Add key here */
+ break ;
+ }
+ }
+ /* Copy key */
+ d->key[i] = strdup(key);
+ d->val[i] = val ? strdup(val) : NULL ;
+ d->hash[i] = hash;
+ d->n ++ ;
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a key in a dictionary
+ @param d dictionary object to modify.
+ @param key Key to remove.
+ @return void
+
+ This function deletes a key in a dictionary. Nothing is done if the
+ key cannot be found.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_unset(dictionary * d, char * key)
+{
+ unsigned hash ;
+ int i ;
+
+ if (key == NULL) {
+ return;
+ }
+
+ hash = dictionary_hash(key);
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ /* Compare hash */
+ if (hash==d->hash[i]) {
+ /* Compare string, to avoid hash collisions */
+ if (!strcmp(key, d->key[i])) {
+ /* Found key */
+ break ;
+ }
+ }
+ }
+ if (i>=d->size)
+ /* Key not found */
+ return ;
+
+ free(d->key[i]);
+ d->key[i] = NULL ;
+ if (d->val[i]!=NULL) {
+ free(d->val[i]);
+ d->val[i] = NULL ;
+ }
+ d->hash[i] = 0 ;
+ d->n -- ;
+ return ;
+}
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set a key in a dictionary, providing an int.
+ @param d Dictionary to update.
+ @param key Key to modify or add
+ @param val Integer value to store (will be stored as a string).
+ @return void
+
+ This helper function calls dictionary_set() with the provided integer
+ converted to a string using %d.
+ */
+/*--------------------------------------------------------------------------*/
+
+
+void dictionary_setint(dictionary * d, char * key, int val)
+{
+ char sval[MAXVALSZ];
+ sprintf(sval, "%d", val);
+ dictionary_set(d, key, sval);
+}
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set a key in a dictionary, providing a double.
+ @param d Dictionary to update.
+ @param key Key to modify or add
+ @param val Double value to store (will be stored as a string).
+ @return void
+
+ This helper function calls dictionary_set() with the provided double
+ converted to a string using %g.
+ */
+/*--------------------------------------------------------------------------*/
+
+
+void dictionary_setdouble(dictionary * d, char * key, double val)
+{
+ char sval[MAXVALSZ];
+ sprintf(sval, "%g", val);
+ dictionary_set(d, key, sval);
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump
+ @param f Opened file pointer.
+ @return void
+
+ Dumps a dictionary onto an opened file pointer. Key pairs are printed out
+ as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
+ output file pointers.
+ */
+/*--------------------------------------------------------------------------*/
+
+void dictionary_dump(dictionary * d, FILE * out)
+{
+ int i ;
+
+ if (d==NULL || out==NULL) return ;
+ if (d->n<1) {
+ fprintf(out, "empty dictionary\n");
+ return ;
+ }
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]) {
+ fprintf(out, "%20s\t[%s]\n",
+ d->key[i],
+ d->val[i] ? d->val[i] : "UNDEF");
+ }
+ }
+ return ;
+}
+
+
+
+/* Example code */
+#ifdef TESTDIC
+#define NVALS 20000
+int main(int argc, char *argv[])
+{
+ dictionary * d ;
+ char * val ;
+ int i ;
+ char cval[90] ;
+
+ /* allocate blackboard */
+ printf("allocating...\n");
+ d = dictionary_new(0);
+
+ /* Set values in blackboard */
+ printf("setting %d values...\n", NVALS);
+ for (i=0 ; i<NVALS ; i++) {
+ sprintf(cval, "%04d", i);
+ dictionary_set(d, cval, "salut");
+ }
+ printf("getting %d values...\n", NVALS);
+ for (i=0 ; i<NVALS ; i++) {
+ sprintf(cval, "%04d", i);
+ val = dictionary_get(d, cval, DICT_INVALID_KEY);
+ if (val==DICT_INVALID_KEY) {
+ printf("cannot get value for key [%s]\n", cval);
+ }
+ }
+ printf("unsetting %d values...\n", NVALS);
+ for (i=0 ; i<NVALS ; i++) {
+ sprintf(cval, "%04d", i);
+ dictionary_unset(d, cval);
+ }
+ if (d->n != 0) {
+ printf("error deleting values\n");
+ }
+
+ printf("deallocating...\n");
+ dictionary_del(d);
+ return 0 ;
+}
+#endif
+/* vim: set ts=4 et sw=4 tw=75 */
diff --git a/source3/iniparser/src/dictionary.h b/source3/iniparser/src/dictionary.h
new file mode 100644
index 0000000000..b332680b04
--- /dev/null
+++ b/source3/iniparser/src/dictionary.h
@@ -0,0 +1,244 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file dictionary.h
+ @author N. Devillard
+ @date Aug 2000
+ @version $Revision: 1.11 $
+ @brief Implements a dictionary for string variables.
+
+ This module implements a simple dictionary object, i.e. a list
+ of string/string associations. This object is useful to store e.g.
+ informations retrieved from a configuration file (ini files).
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+ $Id: dictionary.h,v 1.11 2002-06-17 09:30:46 ndevilla Exp $
+ $Author: ndevilla $
+ $Date: 2002-06-17 09:30:46 $
+ $Revision: 1.11 $
+*/
+
+#ifndef _DICTIONARY_H_
+#define _DICTIONARY_H_
+
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*---------------------------------------------------------------------------
+ New types
+ ---------------------------------------------------------------------------*/
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dictionary object
+
+ This object contains a list of string/string associations. Each
+ association is identified by a unique string key. Looking up values
+ in the dictionary is speeded up by the use of a (hopefully collision-free)
+ hash function.
+ */
+/*-------------------------------------------------------------------------*/
+typedef struct _dictionary_ {
+ int n ; /** Number of entries in dictionary */
+ int size ; /** Storage size */
+ char ** val ; /** List of string values */
+ char ** key ; /** List of string keys */
+ unsigned * hash ; /** List of hash values for keys */
+} dictionary ;
+
+
+/*---------------------------------------------------------------------------
+ Function prototypes
+ ---------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Compute the hash key for a string.
+ @param key Character string to use for key.
+ @return 1 unsigned int on at least 32 bits.
+
+ This hash function has been taken from an Article in Dr Dobbs Journal.
+ This is normally a collision-free function, distributing keys evenly.
+ The key is stored anyway in the struct so that collision can be avoided
+ by comparing the key itself in last resort.
+ */
+/*--------------------------------------------------------------------------*/
+unsigned dictionary_hash(char * key);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Create a new dictionary object.
+ @param size Optional initial size of the dictionary.
+ @return 1 newly allocated dictionary objet.
+
+ This function allocates a new dictionary object of given size and returns
+ it. If you do not know in advance (roughly) the number of entries in the
+ dictionary, give size=0.
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * dictionary_new(int size);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a dictionary object
+ @param d dictionary object to deallocate.
+ @return void
+
+ Deallocate a dictionary object and all memory associated to it.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_del(dictionary * vd);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get a value from a dictionary.
+ @param d dictionary object to search.
+ @param key Key to look for in the dictionary.
+ @param def Default value to return if key not found.
+ @return 1 pointer to internally allocated character string.
+
+ This function locates a key in a dictionary and returns a pointer to its
+ value, or the passed 'def' pointer if no such key can be found in
+ dictionary. The returned character pointer points to data internal to the
+ dictionary object, you should not try to free it or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * dictionary_get(dictionary * d, char * key, char * def);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get a value from a dictionary, as a char.
+ @param d dictionary object to search.
+ @param key Key to look for in the dictionary.
+ @param def Default value for the key if not found.
+ @return char
+
+ This function locates a key in a dictionary using dictionary_get,
+ and returns the first char of the found string.
+ */
+/*--------------------------------------------------------------------------*/
+char dictionary_getchar(dictionary * d, char * key, char def) ;
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get a value from a dictionary, as an int.
+ @param d dictionary object to search.
+ @param key Key to look for in the dictionary.
+ @param def Default value for the key if not found.
+ @return int
+
+ This function locates a key in a dictionary using dictionary_get,
+ and applies atoi on it to return an int. If the value cannot be found
+ in the dictionary, the default is returned.
+ */
+/*--------------------------------------------------------------------------*/
+int dictionary_getint(dictionary * d, char * key, int def);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get a value from a dictionary, as a double.
+ @param d dictionary object to search.
+ @param key Key to look for in the dictionary.
+ @param def Default value for the key if not found.
+ @return double
+
+ This function locates a key in a dictionary using dictionary_get,
+ and applies atof on it to return a double. If the value cannot be found
+ in the dictionary, the default is returned.
+ */
+/*--------------------------------------------------------------------------*/
+double dictionary_getdouble(dictionary * d, char * key, double def);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set a value in a dictionary.
+ @param d dictionary object to modify.
+ @param key Key to modify or add.
+ @param val Value to add.
+ @return void
+
+ If the given key is found in the dictionary, the associated value is
+ replaced by the provided one. If the key cannot be found in the
+ dictionary, it is added to it.
+
+ It is Ok to provide a NULL value for val, but NULL values for the dictionary
+ or the key are considered as errors: the function will return immediately
+ in such a case.
+
+ Notice that if you dictionary_set a variable to NULL, a call to
+ dictionary_get will return a NULL value: the variable will be found, and
+ its value (NULL) is returned. In other words, setting the variable
+ content to NULL is equivalent to deleting the variable from the
+ dictionary. It is not possible (in this implementation) to have a key in
+ the dictionary without value.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_set(dictionary * vd, char * key, char * val);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a key in a dictionary
+ @param d dictionary object to modify.
+ @param key Key to remove.
+ @return void
+
+ This function deletes a key in a dictionary. Nothing is done if the
+ key cannot be found.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_unset(dictionary * d, char * key);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set a key in a dictionary, providing an int.
+ @param d Dictionary to update.
+ @param key Key to modify or add
+ @param val Integer value to store (will be stored as a string).
+ @return void
+
+ This helper function calls dictionary_set() with the provided integer
+ converted to a string using %d.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_setint(dictionary * d, char * key, int val);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set a key in a dictionary, providing a double.
+ @param d Dictionary to update.
+ @param key Key to modify or add
+ @param val Double value to store (will be stored as a string).
+ @return void
+
+ This helper function calls dictionary_set() with the provided double
+ converted to a string using %g.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_setdouble(dictionary * d, char * key, double val);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump
+ @param f Opened file pointer.
+ @return void
+
+ Dumps a dictionary onto an opened file pointer. Key pairs are printed out
+ as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
+ output file pointers.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_dump(dictionary * d, FILE * out);
+
+#endif
diff --git a/source3/iniparser/src/iniparser.c b/source3/iniparser/src/iniparser.c
new file mode 100644
index 0000000000..09340876d8
--- /dev/null
+++ b/source3/iniparser/src/iniparser.c
@@ -0,0 +1,536 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file iniparser.c
+ @author N. Devillard
+ @date Mar 2000
+ @version $Revision: 2.17 $
+ @brief Parser for ini files.
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+ $Id: iniparser.c,v 2.17 2007-05-27 13:03:43 ndevilla Exp $
+ $Author: ndevilla $
+ $Date: 2007-05-27 13:03:43 $
+ $Revision: 2.17 $
+*/
+
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+
+#include "iniparser.h"
+#include "strlib.h"
+
+#define ASCIILINESZ 1024
+#define INI_INVALID_KEY ((char*)-1)
+
+/*---------------------------------------------------------------------------
+ Private to this module
+ ---------------------------------------------------------------------------*/
+
+/* Private: add an entry to the dictionary */
+static void iniparser_add_entry(
+ dictionary * d,
+ char * sec,
+ char * key,
+ char * val)
+{
+ char longkey[2*ASCIILINESZ+1];
+
+ /* Make a key as section:keyword */
+ if (key!=NULL) {
+ sprintf(longkey, "%s:%s", sec, key);
+ } else {
+ strcpy(longkey, sec);
+ }
+
+ /* Add (key,val) to dictionary */
+ dictionary_set(d, longkey, val);
+ return ;
+}
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get number of sections in a dictionary
+ @param d Dictionary to examine
+ @return int Number of sections found in dictionary
+
+ This function returns the number of sections found in a dictionary.
+ The test to recognize sections is done on the string stored in the
+ dictionary: a section name is given as "section" whereas a key is
+ stored as "section:key", thus the test looks for entries that do not
+ contain a colon.
+
+ This clearly fails in the case a section name contains a colon, but
+ this should simply be avoided.
+
+ This function returns -1 in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+
+int iniparser_getnsec(dictionary * d)
+{
+ int i ;
+ int nsec ;
+
+ if (d==NULL) return -1 ;
+ nsec=0 ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (strchr(d->key[i], ':')==NULL) {
+ nsec ++ ;
+ }
+ }
+ return nsec ;
+}
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get name for section n in a dictionary.
+ @param d Dictionary to examine
+ @param n Section number (from 0 to nsec-1).
+ @return Pointer to char string
+
+ This function locates the n-th section in a dictionary and returns
+ its name as a pointer to a string statically allocated inside the
+ dictionary. Do not free or modify the returned string!
+
+ This function returns NULL in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+
+char * iniparser_getsecname(dictionary * d, int n)
+{
+ int i ;
+ int foundsec ;
+
+ if (d==NULL || n<0) return NULL ;
+ foundsec=0 ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (strchr(d->key[i], ':')==NULL) {
+ foundsec++ ;
+ if (foundsec>n)
+ break ;
+ }
+ }
+ if (foundsec<=n) {
+ return NULL ;
+ }
+ return d->key[i] ;
+}
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump.
+ @param f Opened file pointer to dump to.
+ @return void
+
+ This function prints out the contents of a dictionary, one element by
+ line, onto the provided file pointer. It is OK to specify @c stderr
+ or @c stdout as output files. This function is meant for debugging
+ purposes mostly.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump(dictionary * d, FILE * f)
+{
+ int i ;
+
+ if (d==NULL || f==NULL) return ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (d->val[i]!=NULL) {
+ fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
+ } else {
+ fprintf(f, "[%s]=UNDEF\n", d->key[i]);
+ }
+ }
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Save a dictionary to a loadable ini file
+ @param d Dictionary to dump
+ @param f Opened file pointer to dump to
+ @return void
+
+ This function dumps a given dictionary into a loadable ini file.
+ It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+
+void iniparser_dump_ini(dictionary * d, FILE * f)
+{
+ int i, j ;
+ char keym[ASCIILINESZ+1];
+ int nsec ;
+ char * secname ;
+ int seclen ;
+
+ if (d==NULL || f==NULL) return ;
+
+ nsec = iniparser_getnsec(d);
+ if (nsec<1) {
+ /* No section in file: dump all keys as they are */
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
+ }
+ return ;
+ }
+ for (i=0 ; i<nsec ; i++) {
+ secname = iniparser_getsecname(d, i) ;
+ seclen = (int)strlen(secname);
+ fprintf(f, "\n[%s]\n", secname);
+ sprintf(keym, "%s:", secname);
+ for (j=0 ; j<d->size ; j++) {
+ if (d->key[j]==NULL)
+ continue ;
+ if (!strncmp(d->key[j], keym, seclen+1)) {
+ fprintf(f,
+ "%-30s = %s\n",
+ d->key[j]+seclen+1,
+ d->val[j] ? d->val[j] : "");
+ }
+ }
+ }
+ fprintf(f, "\n");
+ return ;
+}
+
+
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, return NULL if not found
+ @param d Dictionary to search
+ @param key Key string to look for
+ @return pointer to statically allocated character string, or NULL.
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ NULL is returned.
+ The returned char pointer is pointing to a string allocated in
+ the dictionary, do not free or modify it.
+
+ This function is only provided for backwards compatibility with
+ previous versions of iniparser. It is recommended to use
+ iniparser_getstring() instead.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getstr(dictionary * d, const char * key)
+{
+ return iniparser_getstring(d, key, NULL);
+}
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param def Default value to return if key not found.
+ @return pointer to statically allocated character string
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the pointer passed as 'def' is returned.
+ The returned char pointer is pointing to a string allocated in
+ the dictionary, do not free or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getstring(dictionary * d, const char * key, char * def)
+{
+ char * lc_key ;
+ char * sval ;
+
+ if (d==NULL || key==NULL)
+ return def ;
+
+ if (!(lc_key = strdup(strlwc(key)))) {
+ return NULL;
+ }
+ sval = dictionary_get(d, lc_key, def);
+ free(lc_key);
+ return sval ;
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to an int
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return integer
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+
+ Supported values for integers include the usual C notation
+ so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
+ are supported. Examples:
+
+ "42" -> 42
+ "042" -> 34 (octal -> decimal)
+ "0x42" -> 66 (hexa -> decimal)
+
+ Warning: the conversion may overflow in various ways. Conversion is
+ totally outsourced to strtol(), see the associated man page for overflow
+ handling.
+
+ Credits: Thanks to A. Becker for suggesting strtol()
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getint(dictionary * d, const char * key, int notfound)
+{
+ char * str ;
+
+ str = iniparser_getstring(d, key, INI_INVALID_KEY);
+ if (str==INI_INVALID_KEY) return notfound ;
+ return (int)strtol(str, NULL, 0);
+}
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a double
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return double
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+ */
+/*--------------------------------------------------------------------------*/
+double iniparser_getdouble(dictionary * d, char * key, double notfound)
+{
+ char * str ;
+
+ str = iniparser_getstring(d, key, INI_INVALID_KEY);
+ if (str==INI_INVALID_KEY) return notfound ;
+ return atof(str);
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a boolean
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return integer
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+
+ A true boolean is found if one of the following is matched:
+
+ - A string starting with 'y'
+ - A string starting with 'Y'
+ - A string starting with 't'
+ - A string starting with 'T'
+ - A string starting with '1'
+
+ A false boolean is found if one of the following is matched:
+
+ - A string starting with 'n'
+ - A string starting with 'N'
+ - A string starting with 'f'
+ - A string starting with 'F'
+ - A string starting with '0'
+
+ The notfound value returned if no boolean is identified, does not
+ necessarily have to be 0 or 1.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getboolean(dictionary * d, const char * key, int notfound)
+{
+ char * c ;
+ int ret ;
+
+ c = iniparser_getstring(d, key, INI_INVALID_KEY);
+ if (c==INI_INVALID_KEY) return notfound ;
+ if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
+ ret = 1 ;
+ } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
+ ret = 0 ;
+ } else {
+ ret = notfound ;
+ }
+ return ret;
+}
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Finds out if a given entry exists in a dictionary
+ @param ini Dictionary to search
+ @param entry Name of the entry to look for
+ @return integer 1 if entry exists, 0 otherwise
+
+ Finds out if a given entry exists in the dictionary. Since sections
+ are stored as keys with NULL associated values, this is the only way
+ of querying for the presence of sections in a dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+
+int iniparser_find_entry(
+ dictionary * ini,
+ char * entry
+)
+{
+ int found=0 ;
+ if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
+ found = 1 ;
+ }
+ return found ;
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set an entry in a dictionary.
+ @param ini Dictionary to modify.
+ @param entry Entry to modify (entry name)
+ @param val New value to associate to the entry.
+ @return int 0 if Ok, -1 otherwise.
+
+ If the given entry can be found in the dictionary, it is modified to
+ contain the provided value. If it cannot be found, -1 is returned.
+ It is Ok to set val to NULL.
+ */
+/*--------------------------------------------------------------------------*/
+
+int iniparser_setstr(dictionary * ini, char * entry, char * val)
+{
+ dictionary_set(ini, strlwc(entry), val);
+ return 0 ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete an entry in a dictionary
+ @param ini Dictionary to modify
+ @param entry Entry to delete (entry name)
+ @return void
+
+ If the given entry can be found, it is deleted from the dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_unset(dictionary * ini, char * entry)
+{
+ dictionary_unset(ini, strlwc(entry));
+}
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Parse an ini file and return an allocated dictionary object
+ @param ininame Name of the ini file to read.
+ @return Pointer to newly allocated dictionary
+
+ This is the parser for ini files. This function is called, providing
+ the name of the file to be read. It returns a dictionary object that
+ should not be accessed directly, but through accessor functions
+ instead.
+
+ The returned dictionary must be freed using iniparser_freedict().
+ */
+/*--------------------------------------------------------------------------*/
+
+dictionary * iniparser_load(const char * ininame)
+{
+ dictionary * d ;
+ char lin[ASCIILINESZ+1];
+ char sec[ASCIILINESZ+1];
+ char key[ASCIILINESZ+1];
+ char val[ASCIILINESZ+1];
+ char * where ;
+ FILE * ini ;
+ int lineno ;
+
+ if ((ini=fopen(ininame, "r"))==NULL) {
+ return NULL ;
+ }
+
+ sec[0]=0;
+
+ /*
+ * Initialize a new dictionary entry
+ */
+ if (!(d = dictionary_new(0))) {
+ fclose(ini);
+ return NULL;
+ }
+ lineno = 0 ;
+ while (fgets(lin, ASCIILINESZ, ini)!=NULL) {
+ lineno++ ;
+ where = strskp(lin); /* Skip leading spaces */
+ if (*where==';' || *where=='#' || *where==0)
+ continue ; /* Comment lines */
+ else {
+ if (sscanf(where, "[%[^]]", sec)==1) {
+ /* Valid section name */
+ strcpy(sec, strlwc(sec));
+ iniparser_add_entry(d, sec, NULL, NULL);
+ } else if (sscanf (where, "%[^=] = \"%[^\"]\"", key, val) == 2
+ || sscanf (where, "%[^=] = '%[^\']'", key, val) == 2
+ || sscanf (where, "%[^=] = %[^;#]", key, val) == 2) {
+ strcpy(key, strlwc(strcrop(key)));
+ /*
+ * sscanf cannot handle "" or '' as empty value,
+ * this is done here
+ */
+ if (!strcmp(val, "\"\"") || !strcmp(val, "''")) {
+ val[0] = (char)0;
+ } else {
+ strcpy(val, strcrop(val));
+ }
+ iniparser_add_entry(d, sec, key, val);
+ }
+ }
+ }
+ fclose(ini);
+ return d ;
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Free all memory associated to an ini dictionary
+ @param d Dictionary to free
+ @return void
+
+ Free all memory associated to an ini dictionary.
+ It is mandatory to call this function before the dictionary object
+ gets out of the current context.
+ */
+/*--------------------------------------------------------------------------*/
+
+void iniparser_freedict(dictionary * d)
+{
+ dictionary_del(d);
+}
+
+/* vim: set ts=4 et sw=4 tw=75 */
diff --git a/source3/iniparser/src/iniparser.h b/source3/iniparser/src/iniparser.h
new file mode 100644
index 0000000000..5bbd9045cf
--- /dev/null
+++ b/source3/iniparser/src/iniparser.h
@@ -0,0 +1,296 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file iniparser.h
+ @author N. Devillard
+ @date Mar 2000
+ @version $Revision: 1.23 $
+ @brief Parser for ini files.
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+ $Id: iniparser.h,v 1.23 2006-09-27 11:03:35 ndevilla Exp $
+ $Author: ndevilla $
+ $Date: 2006-09-27 11:03:35 $
+ $Revision: 1.23 $
+*/
+
+#ifndef _INIPARSER_H_
+#define _INIPARSER_H_
+
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * The following #include is necessary on many Unixes but not Linux.
+ * It is not needed for Windows platforms.
+ * Uncomment it if needed.
+ */
+/* #include <unistd.h> */
+
+#include "dictionary.h"
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get number of sections in a dictionary
+ @param d Dictionary to examine
+ @return int Number of sections found in dictionary
+
+ This function returns the number of sections found in a dictionary.
+ The test to recognize sections is done on the string stored in the
+ dictionary: a section name is given as "section" whereas a key is
+ stored as "section:key", thus the test looks for entries that do not
+ contain a colon.
+
+ This clearly fails in the case a section name contains a colon, but
+ this should simply be avoided.
+
+ This function returns -1 in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+
+int iniparser_getnsec(dictionary * d);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get name for section n in a dictionary.
+ @param d Dictionary to examine
+ @param n Section number (from 0 to nsec-1).
+ @return Pointer to char string
+
+ This function locates the n-th section in a dictionary and returns
+ its name as a pointer to a string statically allocated inside the
+ dictionary. Do not free or modify the returned string!
+
+ This function returns NULL in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+
+char * iniparser_getsecname(dictionary * d, int n);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Save a dictionary to a loadable ini file
+ @param d Dictionary to dump
+ @param f Opened file pointer to dump to
+ @return void
+
+ This function dumps a given dictionary into a loadable ini file.
+ It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+
+void iniparser_dump_ini(dictionary * d, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump.
+ @param f Opened file pointer to dump to.
+ @return void
+
+ This function prints out the contents of a dictionary, one element by
+ line, onto the provided file pointer. It is OK to specify @c stderr
+ or @c stdout as output files. This function is meant for debugging
+ purposes mostly.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump(dictionary * d, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, return NULL if not found
+ @param d Dictionary to search
+ @param key Key string to look for
+ @return pointer to statically allocated character string, or NULL.
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ NULL is returned.
+ The returned char pointer is pointing to a string allocated in
+ the dictionary, do not free or modify it.
+
+ This function is only provided for backwards compatibility with
+ previous versions of iniparser. It is recommended to use
+ iniparser_getstring() instead.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getstr(dictionary * d, const char * key);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param def Default value to return if key not found.
+ @return pointer to statically allocated character string
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the pointer passed as 'def' is returned.
+ The returned char pointer is pointing to a string allocated in
+ the dictionary, do not free or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getstring(dictionary * d, const char * key, char * def);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to an int
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return integer
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+
+ Supported values for integers include the usual C notation
+ so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
+ are supported. Examples:
+
+ - "42" -> 42
+ - "042" -> 34 (octal -> decimal)
+ - "0x42" -> 66 (hexa -> decimal)
+
+ Warning: the conversion may overflow in various ways. Conversion is
+ totally outsourced to strtol(), see the associated man page for overflow
+ handling.
+
+ Credits: Thanks to A. Becker for suggesting strtol()
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getint(dictionary * d, const char * key, int notfound);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a double
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return double
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+ */
+/*--------------------------------------------------------------------------*/
+double iniparser_getdouble(dictionary * d, char * key, double notfound);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a boolean
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return integer
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+
+ A true boolean is found if one of the following is matched:
+
+ - A string starting with 'y'
+ - A string starting with 'Y'
+ - A string starting with 't'
+ - A string starting with 'T'
+ - A string starting with '1'
+
+ A false boolean is found if one of the following is matched:
+
+ - A string starting with 'n'
+ - A string starting with 'N'
+ - A string starting with 'f'
+ - A string starting with 'F'
+ - A string starting with '0'
+
+ The notfound value returned if no boolean is identified, does not
+ necessarily have to be 0 or 1.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getboolean(dictionary * d, const char * key, int notfound);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set an entry in a dictionary.
+ @param ini Dictionary to modify.
+ @param entry Entry to modify (entry name)
+ @param val New value to associate to the entry.
+ @return int 0 if Ok, -1 otherwise.
+
+ If the given entry can be found in the dictionary, it is modified to
+ contain the provided value. If it cannot be found, -1 is returned.
+ It is Ok to set val to NULL.
+ */
+/*--------------------------------------------------------------------------*/
+
+int iniparser_setstr(dictionary * ini, char * entry, char * val);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete an entry in a dictionary
+ @param ini Dictionary to modify
+ @param entry Entry to delete (entry name)
+ @return void
+
+ If the given entry can be found, it is deleted from the dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_unset(dictionary * ini, char * entry);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Finds out if a given entry exists in a dictionary
+ @param ini Dictionary to search
+ @param entry Name of the entry to look for
+ @return integer 1 if entry exists, 0 otherwise
+
+ Finds out if a given entry exists in the dictionary. Since sections
+ are stored as keys with NULL associated values, this is the only way
+ of querying for the presence of sections in a dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_find_entry(dictionary * ini, char * entry) ;
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Parse an ini file and return an allocated dictionary object
+ @param ininame Name of the ini file to read.
+ @return Pointer to newly allocated dictionary
+
+ This is the parser for ini files. This function is called, providing
+ the name of the file to be read. It returns a dictionary object that
+ should not be accessed directly, but through accessor functions
+ instead.
+
+ The returned dictionary must be freed using iniparser_freedict().
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * iniparser_load(const char * ininame);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Free all memory associated to an ini dictionary
+ @param d Dictionary to free
+ @return void
+
+ Free all memory associated to an ini dictionary.
+ It is mandatory to call this function before the dictionary object
+ gets out of the current context.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_freedict(dictionary * d);
+
+#endif
diff --git a/source3/iniparser/src/strlib.c b/source3/iniparser/src/strlib.c
new file mode 100644
index 0000000000..f0d85aea58
--- /dev/null
+++ b/source3/iniparser/src/strlib.c
@@ -0,0 +1,211 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file strlib.c
+ @author N. Devillard
+ @date Jan 2001
+ @version $Revision: 1.9 $
+ @brief Various string handling routines to complement the C lib.
+
+ This modules adds a few complementary string routines usually missing
+ in the standard C library.
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+ $Id: strlib.c,v 1.9 2006-09-27 11:04:11 ndevilla Exp $
+ $Author: ndevilla $
+ $Date: 2006-09-27 11:04:11 $
+ $Revision: 1.9 $
+*/
+
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+
+#include <string.h>
+#include <ctype.h>
+
+#include "strlib.h"
+
+/*---------------------------------------------------------------------------
+ Defines
+ ---------------------------------------------------------------------------*/
+#define ASCIILINESZ 1024
+
+/*---------------------------------------------------------------------------
+ Function codes
+ ---------------------------------------------------------------------------*/
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Convert a string to lowercase.
+ @param s String to convert.
+ @return ptr to statically allocated string.
+
+ This function returns a pointer to a statically allocated string
+ containing a lowercased version of the input string. Do not free
+ or modify the returned string! Since the returned string is statically
+ allocated, it will be modified at each function call (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+
+char * strlwc(const char * s)
+{
+ static char l[ASCIILINESZ+1];
+ int i ;
+
+ if (s==NULL) return NULL ;
+ memset(l, 0, ASCIILINESZ+1);
+ i=0 ;
+ while (s[i] && i<ASCIILINESZ) {
+ l[i] = (char)tolower((int)s[i]);
+ i++ ;
+ }
+ l[ASCIILINESZ]=(char)0;
+ return l ;
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Convert a string to uppercase.
+ @param s String to convert.
+ @return ptr to statically allocated string.
+
+ This function returns a pointer to a statically allocated string
+ containing an uppercased version of the input string. Do not free
+ or modify the returned string! Since the returned string is statically
+ allocated, it will be modified at each function call (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+
+char * strupc(char * s)
+{
+ static char l[ASCIILINESZ+1];
+ int i ;
+
+ if (s==NULL) return NULL ;
+ memset(l, 0, ASCIILINESZ+1);
+ i=0 ;
+ while (s[i] && i<ASCIILINESZ) {
+ l[i] = (char)toupper((int)s[i]);
+ i++ ;
+ }
+ l[ASCIILINESZ]=(char)0;
+ return l ;
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Skip blanks until the first non-blank character.
+ @param s String to parse.
+ @return Pointer to char inside given string.
+
+ This function returns a pointer to the first non-blank character in the
+ given string.
+ */
+/*--------------------------------------------------------------------------*/
+
+char * strskp(char * s)
+{
+ char * skip = s;
+ if (s==NULL) return NULL ;
+ while (isspace((int)*skip) && *skip) skip++;
+ return skip ;
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Remove blanks at the end of a string.
+ @param s String to parse.
+ @return ptr to statically allocated string.
+
+ This function returns a pointer to a statically allocated string,
+ which is identical to the input string, except that all blank
+ characters at the end of the string have been removed.
+ Do not free or modify the returned string! Since the returned string
+ is statically allocated, it will be modified at each function call
+ (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+
+char * strcrop(char * s)
+{
+ static char l[ASCIILINESZ+1];
+ char * last ;
+
+ if (s==NULL) return NULL ;
+ memset(l, 0, ASCIILINESZ+1);
+ strcpy(l, s);
+ last = l + strlen(l);
+ while (last > l) {
+ if (!isspace((int)*(last-1)))
+ break ;
+ last -- ;
+ }
+ *last = (char)0;
+ return l ;
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Remove blanks at the beginning and the end of a string.
+ @param s String to parse.
+ @return ptr to statically allocated string.
+
+ This function returns a pointer to a statically allocated string,
+ which is identical to the input string, except that all blank
+ characters at the end and the beg. of the string have been removed.
+ Do not free or modify the returned string! Since the returned string
+ is statically allocated, it will be modified at each function call
+ (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+char * strstrip(char * s)
+{
+ static char l[ASCIILINESZ+1];
+ char * last ;
+
+ if (s==NULL) return NULL ;
+
+ while (isspace((int)*s) && *s) s++;
+
+ memset(l, 0, ASCIILINESZ+1);
+ strcpy(l, s);
+ last = l + strlen(l);
+ while (last > l) {
+ if (!isspace((int)*(last-1)))
+ break ;
+ last -- ;
+ }
+ *last = (char)0;
+
+ return (char*)l ;
+}
+
+/* Test code */
+#ifdef TEST
+int main(int argc, char * argv[])
+{
+ char * str ;
+
+ str = "\t\tI'm a lumberkack and I'm OK " ;
+ printf("lowercase: [%s]\n", strlwc(str));
+ printf("uppercase: [%s]\n", strupc(str));
+ printf("skipped : [%s]\n", strskp(str));
+ printf("cropped : [%s]\n", strcrop(str));
+ printf("stripped : [%s]\n", strstrip(str));
+
+ return 0 ;
+}
+#endif
+/* vim: set ts=4 et sw=4 tw=75 */
diff --git a/source3/iniparser/src/strlib.h b/source3/iniparser/src/strlib.h
new file mode 100644
index 0000000000..cd70a6287d
--- /dev/null
+++ b/source3/iniparser/src/strlib.h
@@ -0,0 +1,108 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file strlib.h
+ @author N. Devillard
+ @date Jan 2001
+ @version $Revision: 1.4 $
+ @brief Various string handling routines to complement the C lib.
+
+ This modules adds a few complementary string routines usually missing
+ in the standard C library.
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+ $Id: strlib.h,v 1.4 2006-09-27 11:04:11 ndevilla Exp $
+ $Author: ndevilla $
+ $Date: 2006-09-27 11:04:11 $
+ $Revision: 1.4 $
+*/
+
+#ifndef _STRLIB_H_
+#define _STRLIB_H_
+
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/*---------------------------------------------------------------------------
+ Function codes
+ ---------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Convert a string to lowercase.
+ @param s String to convert.
+ @return ptr to statically allocated string.
+
+ This function returns a pointer to a statically allocated string
+ containing a lowercased version of the input string. Do not free
+ or modify the returned string! Since the returned string is statically
+ allocated, it will be modified at each function call (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+char * strlwc(const char * s);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Convert a string to uppercase.
+ @param s String to convert.
+ @return ptr to statically allocated string.
+
+ This function returns a pointer to a statically allocated string
+ containing an uppercased version of the input string. Do not free
+ or modify the returned string! Since the returned string is statically
+ allocated, it will be modified at each function call (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+char * strupc(char * s);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Skip blanks until the first non-blank character.
+ @param s String to parse.
+ @return Pointer to char inside given string.
+
+ This function returns a pointer to the first non-blank character in the
+ given string.
+ */
+/*--------------------------------------------------------------------------*/
+char * strskp(char * s);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Remove blanks at the end of a string.
+ @param s String to parse.
+ @return ptr to statically allocated string.
+
+ This function returns a pointer to a statically allocated string,
+ which is identical to the input string, except that all blank
+ characters at the end of the string have been removed.
+ Do not free or modify the returned string! Since the returned string
+ is statically allocated, it will be modified at each function call
+ (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+char * strcrop(char * s);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Remove blanks at the beginning and the end of a string.
+ @param s String to parse.
+ @return ptr to statically allocated string.
+
+ This function returns a pointer to a statically allocated string,
+ which is identical to the input string, except that all blank
+ characters at the end and the beg. of the string have been removed.
+ Do not free or modify the returned string! Since the returned string
+ is statically allocated, it will be modified at each function call
+ (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+char * strstrip(char * s) ;
+
+#endif
diff --git a/source3/iniparser/test/Makefile b/source3/iniparser/test/Makefile
new file mode 100644
index 0000000000..aa8fcb24b5
--- /dev/null
+++ b/source3/iniparser/test/Makefile
@@ -0,0 +1,24 @@
+#
+# iniparser tests Makefile
+#
+
+CC = gcc
+CFLAGS = -g -I../src
+LFLAGS = -L.. -liniparser
+AR = ar
+ARFLAGS = rcv
+RM = rm -f
+
+
+default: all
+
+all: iniexample
+
+iniexample: iniexample.c
+ $(CC) $(CFLAGS) -o iniexample iniexample.c -I../src -L.. -liniparser
+
+clean veryclean:
+ $(RM) iniexample example.ini
+
+
+
diff --git a/source3/iniparser/test/iniexample.c b/source3/iniparser/test/iniexample.c
new file mode 100644
index 0000000000..5e8e71cdf0
--- /dev/null
+++ b/source3/iniparser/test/iniexample.c
@@ -0,0 +1,117 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "iniparser.h"
+
+void create_example_ini_file(void);
+int parse_ini_file(char * ini_name);
+
+int main(int argc, char * argv[])
+{
+ int status ;
+
+ if (argc<2) {
+ create_example_ini_file();
+ status = parse_ini_file("example.ini");
+ } else {
+ status = parse_ini_file(argv[1]);
+ }
+ return status ;
+}
+
+void create_example_ini_file(void)
+{
+ FILE * ini ;
+
+ ini = fopen("example.ini", "w");
+ fprintf(ini, "\n\
+#\n\
+# This is an example of ini file\n\
+#\n\
+\n\
+[Pizza]\n\
+\n\
+Ham = yes ;\n\
+Mushrooms = TRUE ;\n\
+Capres = 0 ;\n\
+Cheese = NO ;\n\
+\n\
+\n\
+[Wine]\n\
+\n\
+Grape = Cabernet Sauvignon ;\n\
+Year = 1989 ;\n\
+Country = Spain ;\n\
+Alcohol = 12.5 ;\n\
+\n\
+#\n\
+# end of file\n\
+#\n");
+
+ fclose(ini);
+}
+
+
+int parse_ini_file(char * ini_name)
+{
+ dictionary * ini ;
+
+ /* Some temporary variables to hold query results */
+ int b ;
+ int i ;
+ double d ;
+ char * s ;
+
+ ini = iniparser_load(ini_name);
+ if (ini==NULL) {
+ fprintf(stderr, "cannot parse file [%s]", ini_name);
+ return -1 ;
+ }
+ iniparser_dump(ini, stderr);
+
+ /* Get pizza attributes */
+ printf("Pizza:\n");
+
+ b = iniparser_getboolean(ini, "pizza:ham", -1);
+ printf("Ham: [%d]\n", b);
+ b = iniparser_getboolean(ini, "pizza:mushrooms", -1);
+ printf("Mushrooms: [%d]\n", b);
+ b = iniparser_getboolean(ini, "pizza:capres", -1);
+ printf("Capres: [%d]\n", b);
+ b = iniparser_getboolean(ini, "pizza:cheese", -1);
+ printf("Cheese: [%d]\n", b);
+
+ /* Get wine attributes */
+ printf("Wine:\n");
+ s = iniparser_getstr(ini, "wine:grape");
+ if (s) {
+ printf("grape: [%s]\n", s);
+ } else {
+ printf("grape: not found\n");
+ }
+ i = iniparser_getint(ini, "wine:year", -1);
+ if (i>0) {
+ printf("year: [%d]\n", i);
+ } else {
+ printf("year: not found\n");
+ }
+ s = iniparser_getstr(ini, "wine:country");
+ if (s) {
+ printf("country: [%s]\n", s);
+ } else {
+ printf("country: not found\n");
+ }
+ d = iniparser_getdouble(ini, "wine:alcohol", -1.0);
+ if (d>0.0) {
+ printf("alcohol: [%g]\n", d);
+ } else {
+ printf("alcohol: not found\n");
+ }
+
+ iniparser_freedict(ini);
+ return 0 ;
+}
+
+
diff --git a/source3/iniparser_build/dictionary.c b/source3/iniparser_build/dictionary.c
new file mode 100644
index 0000000000..de98a4523f
--- /dev/null
+++ b/source3/iniparser_build/dictionary.c
@@ -0,0 +1,7 @@
+/*
+ for someplatforms it's needed to inject replace.h into
+ the iniparser source code
+ --metze
+*/
+#include "lib/replace/replace.h"
+#include "iniparser/src/dictionary.c"
diff --git a/source3/iniparser_build/iniparser.c b/source3/iniparser_build/iniparser.c
new file mode 100644
index 0000000000..4974f373ee
--- /dev/null
+++ b/source3/iniparser_build/iniparser.c
@@ -0,0 +1,7 @@
+/*
+ for someplatforms it's needed to inject replace.h into
+ the iniparser source code
+ --metze
+*/
+#include "lib/replace/replace.h"
+#include "iniparser/src/iniparser.c"
diff --git a/source3/iniparser_build/strlib.c b/source3/iniparser_build/strlib.c
new file mode 100644
index 0000000000..685ec8e04d
--- /dev/null
+++ b/source3/iniparser_build/strlib.c
@@ -0,0 +1,7 @@
+/*
+ for someplatforms it's needed to inject replace.h into
+ the iniparser source code
+ --metze
+*/
+#include "lib/replace/replace.h"
+#include "iniparser/src/strlib.c"
diff --git a/source3/install-sh b/source3/install-sh
new file mode 100755
index 0000000000..58719246f0
--- /dev/null
+++ b/source3/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/source3/intl/lang_tdb.c b/source3/intl/lang_tdb.c
new file mode 100644
index 0000000000..499b9eb87d
--- /dev/null
+++ b/source3/intl/lang_tdb.c
@@ -0,0 +1,246 @@
+/*
+ Unix SMB/CIFS implementation.
+ tdb based replacement for gettext
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static TDB_CONTEXT *tdb;
+
+/* the currently selected language */
+static char *current_lang;
+
+
+/* load a msg file into the tdb */
+static bool load_msg(const char *msg_file)
+{
+ char **lines;
+ int num_lines, i;
+ char *msgid, *msgstr;
+ TDB_DATA data;
+
+ lines = file_lines_load(msg_file, &num_lines,0);
+
+ if (!lines) {
+ return False;
+ }
+
+ if (tdb_lockall(tdb) != 0) {
+ file_lines_free(lines);
+ return False;
+ }
+
+ /* wipe the db */
+ tdb_wipe_all(tdb);
+
+ msgid = NULL;
+
+ for (i=0;i<num_lines;i++) {
+ if (strncmp(lines[i], "msgid \"", 7) == 0) {
+ msgid = lines[i] + 7;
+ }
+ if (msgid && strncmp(lines[i], "msgstr \"", 8) == 0) {
+ msgstr = lines[i] + 8;
+ trim_char(msgid, '\0', '\"');
+ trim_char(msgstr, '\0', '\"');
+ if (*msgstr == 0) {
+ msgstr = msgid;
+ }
+ all_string_sub(msgid, "\\n", "\n", 0);
+ all_string_sub(msgstr, "\\n", "\n", 0);
+ data = string_term_tdb_data(msgstr);
+ tdb_store_bystring(tdb, msgid, data, 0);
+ msgid = NULL;
+ }
+ }
+
+ file_lines_free(lines);
+ tdb_unlockall(tdb);
+
+ return True;
+}
+
+
+/* work out what language to use from locale variables */
+static const char *get_lang(void)
+{
+ const char *vars[] = {"LANGUAGE", "LC_ALL", "LC_LANG", "LANG", NULL};
+ int i;
+ char *p;
+
+ for (i=0; vars[i]; i++) {
+ if ((p = getenv(vars[i]))) {
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+/* initialise the message translation subsystem. If the "lang" argument
+ is NULL then get the language from the normal environment variables */
+bool lang_tdb_init(const char *lang)
+{
+ char *path = NULL;
+ char *msg_path = NULL;
+ struct stat st;
+ static int initialised;
+ time_t loadtime;
+ bool result = False;
+
+ /* we only want to init once per process, unless given
+ an override */
+ if (initialised && !lang)
+ return True;
+
+ if (initialised) {
+ /* we are re-initialising, free up any old init */
+ if (tdb) {
+ tdb_close(tdb);
+ tdb = NULL;
+ }
+ SAFE_FREE(current_lang);
+ }
+
+ initialised = 1;
+
+ if (!lang) {
+ /* no lang given, use environment */
+ lang = get_lang();
+ }
+
+ /* if no lang then we don't translate */
+ if (!lang)
+ return True;
+
+ if (asprintf(&msg_path, "%s.msg",
+ data_path((const char *)lang)) == -1) {
+ DEBUG(0, ("asprintf failed\n"));
+ goto done;
+ }
+ if (stat(msg_path, &st) != 0) {
+ /* the msg file isn't available */
+ DEBUG(10, ("lang_tdb_init: %s: %s\n", msg_path,
+ strerror(errno)));
+ goto done;
+ }
+
+ if (asprintf(&path, "%s%s.tdb", lock_path("lang_"), lang) == -1) {
+ DEBUG(0, ("asprintf failed\n"));
+ goto done;
+ }
+
+ DEBUG(10, ("lang_tdb_init: loading %s\n", path));
+
+ tdb = tdb_open_log(path, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0644);
+ if (!tdb) {
+ tdb = tdb_open_log(path, 0, TDB_DEFAULT, O_RDONLY, 0);
+ if (!tdb) {
+ DEBUG(10, ("lang_tdb_init: %s: %s\n", path,
+ strerror(errno)));
+ goto done;
+ }
+ current_lang = SMB_STRDUP(lang);
+ result = True;
+ goto done;
+ }
+
+ loadtime = tdb_fetch_int32(tdb, "/LOADTIME/");
+
+ if (loadtime == -1 || loadtime < st.st_mtime) {
+ load_msg(msg_path);
+ tdb_store_int32(tdb, "/LOADTIME/", (int)time(NULL));
+ }
+
+ current_lang = SMB_STRDUP(lang);
+ result = True;
+
+ done:
+ SAFE_FREE(msg_path);
+ SAFE_FREE(path);
+
+ return result;
+}
+
+/* translate a msgid to a message string in the current language
+ returns a string that must be freed by calling lang_msg_free()
+*/
+const char *lang_msg(const char *msgid)
+{
+ TDB_DATA data;
+ const char *p;
+ char *q, *msgid_quoted;
+ int count;
+
+ lang_tdb_init(NULL);
+
+ if (!tdb) return msgid;
+
+ /* Due to the way quotes in msgids are escaped in the msg file we
+ must replace " with \" before doing a lookup in the tdb. */
+
+ count = 0;
+
+ for(p = msgid; *p; p++) {
+ if (*p == '\"')
+ count++;
+ }
+
+ if (!(msgid_quoted = (char *)SMB_MALLOC(strlen(msgid) + count + 1)))
+ return msgid;
+
+ /* string_sub() is unsuitable here as it replaces some punctuation
+ chars with underscores. */
+
+ for(p = msgid, q = msgid_quoted; *p; p++) {
+ if (*p == '\"') {
+ *q = '\\';
+ q++;
+ }
+ *q = *p;
+ q++;
+ }
+
+ *q = 0;
+
+ data = tdb_fetch_bystring(tdb, msgid_quoted);
+
+ free(msgid_quoted);
+
+ /* if the message isn't found then we still need to return a pointer
+ that can be freed. Pity. */
+ if (!data.dptr)
+ return SMB_STRDUP(msgid);
+
+ return (const char *)data.dptr;
+}
+
+
+/* free up a string from lang_msg() */
+void lang_msg_free(const char *msgstr)
+{
+ if (!tdb) return;
+ free((void *)msgstr);
+}
+
+/*
+ return the current language - needed for language file mappings
+*/
+char *lang_tdb_current(void)
+{
+ return current_lang;
+}
diff --git a/source3/intl/linux-msg.sed b/source3/intl/linux-msg.sed
new file mode 100644
index 0000000000..19505b8a5d
--- /dev/null
+++ b/source3/intl/linux-msg.sed
@@ -0,0 +1,99 @@
+# po2msg.sed - Convert Uniforum style .po file to Linux style .msg file
+# Copyright (C) 1995 Free Software Foundation, Inc.
+# Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+#
+# The first directive in the .msg should be the definition of the
+# message set number. We use always set number 1.
+#
+1 {
+ i\
+$set 1 # Automatically created by po2msg.sed
+ h
+ s/.*/0/
+ x
+}
+#
+# Mitch's old catalog format does not allow comments.
+#
+# We copy the original message as a comment into the .msg file.
+#
+/^msgid/ {
+ s/msgid[ ]*"//
+#
+# This does not work now with the new format.
+# /"$/! {
+# s/\\$//
+# s/$/ ... (more lines following)"/
+# }
+ x
+# The following nice solution is by
+# Bruno <Haible@ma2s2.mathematik.uni-karlsruhe.de>
+ td
+# Increment a decimal number in pattern space.
+# First hide trailing `9' digits.
+ :d
+ s/9\(_*\)$/_\1/
+ td
+# Assure at least one digit is available.
+ s/^\(_*\)$/0\1/
+# Increment the last digit.
+ s/8\(_*\)$/9\1/
+ s/7\(_*\)$/8\1/
+ s/6\(_*\)$/7\1/
+ s/5\(_*\)$/6\1/
+ s/4\(_*\)$/5\1/
+ s/3\(_*\)$/4\1/
+ s/2\(_*\)$/3\1/
+ s/1\(_*\)$/2\1/
+ s/0\(_*\)$/1\1/
+# Convert the hidden `9' digits to `0's.
+ s/_/0/g
+ x
+ G
+ s/\(.*\)"\n\([0-9]*\)/$ #\2 Original Message:(\1)/p
+}
+#
+# The .msg file contains, other then the .po file, only the translations
+# but each given a unique ID. Starting from 1 and incrementing by 1 for
+# each message we assign them to the messages.
+# It is important that the .po file used to generate the cat-id-tbl.c file
+# (with po-to-tbl) is the same as the one used here. (At least the order
+# of declarations must not be changed.)
+#
+/^msgstr/ {
+ s/msgstr[ ]*"\(.*\)"/# \1/
+# Clear substitution flag.
+ tb
+# Append the next line.
+ :b
+ N
+# Look whether second part is continuation line.
+ s/\(.*\n\)"\(.*\)"/\1\2/
+# Yes, then branch.
+ ta
+ P
+ D
+# Note that D includes a jump to the start!!
+# We found a continuation line. But before printing insert '\'.
+ :a
+ s/\(.*\)\(\n.*\)/\1\\\2/
+ P
+# We cannot use D here.
+ s/.*\n\(.*\)/\1/
+ tb
+}
+d
diff --git a/source3/lib/access.c b/source3/lib/access.c
new file mode 100644
index 0000000000..6a445f8139
--- /dev/null
+++ b/source3/lib/access.c
@@ -0,0 +1,415 @@
+/*
+ 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 has been considerably changed from the original. Bug reports
+ should be sent to samba@samba.org
+
+ Updated for IPv6 by Jeremy Allison (C) 2007.
+*/
+
+#include "includes.h"
+
+#define NAME_INDEX 0
+#define ADDR_INDEX 1
+
+/* masked_match - match address against netnumber/netmask */
+static bool masked_match(const char *tok, const char *slash, const char *s)
+{
+ struct sockaddr_storage ss_mask;
+ struct sockaddr_storage ss_tok;
+ struct sockaddr_storage ss_host;
+ char *tok_copy = NULL;
+
+ if (!interpret_string_addr(&ss_host, s, 0)) {
+ return false;
+ }
+
+ if (*tok == '[') {
+ /* IPv6 address - remove braces. */
+ tok_copy = SMB_STRDUP(tok+1);
+ if (!tok_copy) {
+ return false;
+ }
+ /* Remove the terminating ']' */
+ tok_copy[PTR_DIFF(slash,tok)-1] = '\0';
+ } else {
+ tok_copy = SMB_STRDUP(tok);
+ if (!tok_copy) {
+ return false;
+ }
+ /* Remove the terminating '/' */
+ tok_copy[PTR_DIFF(slash,tok)] = '\0';
+ }
+
+ if (!interpret_string_addr(&ss_tok, tok_copy, 0)) {
+ SAFE_FREE(tok_copy);
+ return false;
+ }
+
+ SAFE_FREE(tok_copy);
+
+ if (strlen(slash + 1) > 2) {
+ if (!interpret_string_addr(&ss_mask, slash+1, 0)) {
+ return false;
+ }
+ } else {
+ char *endp = NULL;
+ unsigned long val = strtoul(slash+1, &endp, 0);
+ if (slash+1 == endp || (endp && *endp != '\0')) {
+ return false;
+ }
+ if (!make_netmask(&ss_mask, &ss_tok, val)) {
+ return false;
+ }
+ }
+
+ return same_net(&ss_host, &ss_tok, &ss_mask);
+}
+
+/* string_match - match string s against token tok */
+static bool string_match(const char *tok,const char *s)
+{
+ size_t tok_len;
+ size_t str_len;
+ const char *cut;
+
+ /* Return true if a token has the magic value "ALL". Return
+ * true 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))
+ && strequal(tok, s + str_len - tok_len)) {
+ return true;
+ }
+ } else if (tok[0] == '@') { /* netgroup: look it up */
+#ifdef HAVE_NETGROUP
+ DATA_BLOB tmp;
+ char *mydomain = NULL;
+ char *hostname = NULL;
+ bool netgroup_ok = false;
+
+ if (memcache_lookup(
+ NULL, SINGLETON_CACHE,
+ data_blob_string_const("yp_default_domain"),
+ &tmp)) {
+
+ SMB_ASSERT(tmp.length > 0);
+ mydomain = (tmp.data[0] == '\0')
+ ? NULL : (char *)tmp.data;
+ }
+ else {
+ yp_get_default_domain(&mydomain);
+
+ memcache_add(
+ NULL, SINGLETON_CACHE,
+ data_blob_string_const("yp_default_domain"),
+ data_blob_string_const(mydomain?mydomain:""));
+ }
+
+ if (!mydomain) {
+ DEBUG(0,("Unable to get default yp domain. "
+ "Try without it.\n"));
+ }
+ if (!(hostname = SMB_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?mydomain:"(ANY)",
+ tok+1,
+ BOOLSTR(netgroup_ok)));
+
+ SAFE_FREE(hostname);
+
+ if (netgroup_ok)
+ return true;
+#else
+ DEBUG(0,("access: netgroup support is not configured\n"));
+ return false;
+#endif
+ } else if (strequal(tok, "ALL")) { /* all: match any */
+ return true;
+ } else if (strequal(tok, "FAIL")) { /* fail: match any */
+ return true;
+ } else if (strequal(tok, "LOCAL")) { /* local: no dots */
+ if (strchr_m(s, '.') == 0 && !strequal(s, "unknown")) {
+ return true;
+ }
+ } else if (strequal(tok, s)) { /* match host name or address */
+ return true;
+ } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { /* network */
+ if (strncmp(tok, s, tok_len) == 0) {
+ return true;
+ }
+ } else if ((cut = strchr_m(tok, '/')) != 0) { /* netnumber/netmask */
+ if ((isdigit(s[0]) && strchr_m(tok, '.') != NULL) ||
+ (tok[0] == '[' && cut > tok && cut[-1] == ']') ||
+ ((isxdigit(s[0]) || s[0] == ':') &&
+ strchr_m(tok, ':') != NULL)) {
+ /* IPv4/netmask or
+ * [IPv6:addr]/netmask or IPv6:addr/netmask */
+ return masked_match(tok, cut, s);
+ }
+ } else if (strchr_m(tok, '*') != 0 || strchr_m(tok, '?')) {
+ return unix_wild_match(tok, s);
+ }
+ return false;
+}
+
+/* client_match - match host name and address against token */
+bool client_match(const char *tok, const void *item)
+{
+ const char **client = (const char **)item;
+
+ /*
+ * Try to match the address first. If that fails, try to match the host
+ * name if available.
+ */
+
+ if (string_match(tok, client[ADDR_INDEX])) {
+ return true;
+ }
+
+ if (strnequal(client[ADDR_INDEX],"::ffff:",7) &&
+ !strnequal(tok, "::ffff:",7)) {
+ /* client[ADDR_INDEX] is an IPv4 mapped to IPv6, but
+ * the list item is not. Try and match the IPv4 part of
+ * address only. This will happen a lot on IPv6 enabled
+ * systems with IPv4 allow/deny lists in smb.conf.
+ * Bug #5311. JRA.
+ */
+ if (string_match(tok, (client[ADDR_INDEX])+7)) {
+ return true;
+ }
+ }
+
+ if (client[NAME_INDEX][0] != 0) {
+ if (string_match(tok, client[NAME_INDEX])) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* list_match - match an item against a list of tokens with exceptions */
+bool list_match(const char **list,const void *item,
+ bool (*match_fn)(const char *, const void *))
+{
+ bool match = false;
+
+ if (!list) {
+ return false;
+ }
+
+ /*
+ * Process tokens one at a time. We have exhausted all possible matches
+ * when we reach an "EXCEPT" token or the end of the list. If we do find
+ * a match, look for an "EXCEPT" list and recurse to determine whether
+ * the match is affected by any exceptions.
+ */
+
+ for (; *list ; list++) {
+ if (strequal(*list, "EXCEPT")) {
+ /* EXCEPT: give up */
+ break;
+ }
+ if ((match = (*match_fn) (*list, item))) {
+ /* true or FAIL */
+ break;
+ }
+ }
+ /* Process exceptions to true or FAIL matches. */
+
+ if (match != false) {
+ while (*list && !strequal(*list, "EXCEPT")) {
+ list++;
+ }
+
+ for (; *list; list++) {
+ if ((*match_fn) (*list, item)) {
+ /* Exception Found */
+ return false;
+ }
+ }
+ }
+
+ return match;
+}
+
+/* return true if access should be allowed */
+static bool allow_access_internal(const char **deny_list,
+ const char **allow_list,
+ const char *cname,
+ const char *caddr)
+{
+ const char *client[2];
+
+ client[NAME_INDEX] = cname;
+ client[ADDR_INDEX] = caddr;
+
+ /* if it is loopback then always allow unless specifically denied */
+ if (strcmp(caddr, "127.0.0.1") == 0 || strcmp(caddr, "::1") == 0) {
+ /*
+ * If 127.0.0.1 matches both allow and deny then allow.
+ * Patch from Steve Langasek vorlon@netexpress.net.
+ */
+ if (deny_list &&
+ list_match(deny_list,client,client_match) &&
+ (!allow_list ||
+ !list_match(allow_list,client, client_match))) {
+ return false;
+ }
+ return true;
+ }
+
+ /* 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,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,client,client_match));
+ }
+
+ /* if there are both types of list then allow all hosts on the
+ allow list */
+ if (list_match(allow_list,(const char *)client,client_match)) {
+ return true;
+ }
+
+ /* if there are both types of list and it's not on the allow then
+ allow it if its not on the deny */
+ if (list_match(deny_list,(const char *)client,client_match)) {
+ return false;
+ }
+
+ return true;
+}
+
+/* return true if access should be allowed */
+bool allow_access(const char **deny_list,
+ const char **allow_list,
+ const char *cname,
+ const char *caddr)
+{
+ bool ret;
+ char *nc_cname = smb_xstrdup(cname);
+ char *nc_caddr = smb_xstrdup(caddr);
+
+ ret = allow_access_internal(deny_list, allow_list, nc_cname, nc_caddr);
+
+ SAFE_FREE(nc_cname);
+ SAFE_FREE(nc_caddr);
+ return ret;
+}
+
+/* return true if the char* contains ip addrs only. Used to avoid
+name lookup calls */
+
+static bool only_ipaddrs_in_list(const char **list)
+{
+ bool only_ip = true;
+
+ if (!list) {
+ return true;
+ }
+
+ for (; *list ; list++) {
+ /* factor out the special strings */
+ if (strequal(*list, "ALL") || strequal(*list, "FAIL") ||
+ strequal(*list, "EXCEPT")) {
+ continue;
+ }
+
+ if (!is_ipaddress(*list)) {
+ /*
+ * If we failed, make sure that it was not because
+ * the token was a network/netmask pair. Only
+ * network/netmask pairs have a '/' in them.
+ */
+ if ((strchr_m(*list, '/')) == NULL) {
+ only_ip = false;
+ DEBUG(3,("only_ipaddrs_in_list: list has "
+ "non-ip address (%s)\n",
+ *list));
+ break;
+ }
+ }
+ }
+
+ return only_ip;
+}
+
+/* return true if access should be allowed to a service for a socket */
+bool check_access(int sock, const char **allow_list, const char **deny_list)
+{
+ bool ret = false;
+ bool only_ip = false;
+
+ if ((!deny_list || *deny_list==0) && (!allow_list || *allow_list==0))
+ ret = true;
+
+ if (!ret) {
+ char addr[INET6_ADDRSTRLEN];
+
+ /* Bypass name resolution calls if the lists
+ * only contain IP addrs */
+ if (only_ipaddrs_in_list(allow_list) &&
+ only_ipaddrs_in_list(deny_list)) {
+ only_ip = true;
+ DEBUG (3, ("check_access: no hostnames "
+ "in host allow/deny list.\n"));
+ ret = allow_access(deny_list,
+ allow_list,
+ "",
+ get_peer_addr(sock,addr,sizeof(addr)));
+ } else {
+ DEBUG (3, ("check_access: hostnames in "
+ "host allow/deny list.\n"));
+ ret = allow_access(deny_list,
+ allow_list,
+ get_peer_name(sock,true),
+ get_peer_addr(sock,addr,sizeof(addr)));
+ }
+
+ if (ret) {
+ DEBUG(2,("Allowed connection from %s (%s)\n",
+ only_ip ? "" : get_peer_name(sock,true),
+ get_peer_addr(sock,addr,sizeof(addr))));
+ } else {
+ DEBUG(0,("Denied connection from %s (%s)\n",
+ only_ip ? "" : get_peer_name(sock,true),
+ get_peer_addr(sock,addr,sizeof(addr))));
+ }
+ }
+
+ return(ret);
+}
diff --git a/source3/lib/account_pol.c b/source3/lib/account_pol.c
new file mode 100644
index 0000000000..1e435ca53e
--- /dev/null
+++ b/source3/lib/account_pol.c
@@ -0,0 +1,454 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * account policy storage
+ * Copyright (C) Jean François Micouleau 1998-2001.
+ * Copyright (C) Andrew Bartlett 2002
+ * Copyright (C) Guenther Deschner 2004-2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+static struct db_context *db;
+
+/* cache all entries for 60 seconds for to save ldap-queries (cache is updated
+ * after this period if admins do not use pdbedit or usermanager but manipulate
+ * ldap directly) - gd */
+
+#define DATABASE_VERSION 3
+#define AP_TTL 60
+
+
+struct ap_table {
+ int field;
+ const char *string;
+ uint32 default_val;
+ const char *description;
+ const char *ldap_attr;
+};
+
+static const struct ap_table account_policy_names[] = {
+ {AP_MIN_PASSWORD_LEN, "min password length", MINPASSWDLENGTH,
+ "Minimal password length (default: 5)",
+ "sambaMinPwdLength" },
+
+ {AP_PASSWORD_HISTORY, "password history", 0,
+ "Length of Password History Entries (default: 0 => off)",
+ "sambaPwdHistoryLength" },
+
+ {AP_USER_MUST_LOGON_TO_CHG_PASS, "user must logon to change password", 0,
+ "Force Users to logon for password change (default: 0 => off, 2 => on)",
+ "sambaLogonToChgPwd" },
+
+ {AP_MAX_PASSWORD_AGE, "maximum password age", (uint32) -1,
+ "Maximum password age, in seconds (default: -1 => never expire passwords)",
+ "sambaMaxPwdAge" },
+
+ {AP_MIN_PASSWORD_AGE,"minimum password age", 0,
+ "Minimal password age, in seconds (default: 0 => allow immediate password change)",
+ "sambaMinPwdAge" },
+
+ {AP_LOCK_ACCOUNT_DURATION, "lockout duration", 30,
+ "Lockout duration in minutes (default: 30, -1 => forever)",
+ "sambaLockoutDuration" },
+
+ {AP_RESET_COUNT_TIME, "reset count minutes", 30,
+ "Reset time after lockout in minutes (default: 30)",
+ "sambaLockoutObservationWindow" },
+
+ {AP_BAD_ATTEMPT_LOCKOUT, "bad lockout attempt", 0,
+ "Lockout users after bad logon attempts (default: 0 => off)",
+ "sambaLockoutThreshold" },
+
+ {AP_TIME_TO_LOGOUT, "disconnect time", (uint32) -1,
+ "Disconnect Users outside logon hours (default: -1 => off, 0 => on)",
+ "sambaForceLogoff" },
+
+ {AP_REFUSE_MACHINE_PW_CHANGE, "refuse machine password change", 0,
+ "Allow Machine Password changes (default: 0 => off)",
+ "sambaRefuseMachinePwdChange" },
+
+ {0, NULL, 0, "", NULL}
+};
+
+void account_policy_names_list(const char ***names, int *num_names)
+{
+ const char **nl;
+ int i, count;
+
+ for (count=0; account_policy_names[count].string; count++) {
+ }
+ nl = SMB_MALLOC_ARRAY(const char *, count);
+ if (!nl) {
+ *num_names = 0;
+ return;
+ }
+ for (i=0; account_policy_names[i].string; i++) {
+ nl[i] = account_policy_names[i].string;
+ }
+ *num_names = count;
+ *names = nl;
+ return;
+}
+
+/****************************************************************************
+Get the account policy name as a string from its #define'ed number
+****************************************************************************/
+
+const char *decode_account_policy_name(int field)
+{
+ int i;
+ for (i=0; account_policy_names[i].string; i++) {
+ if (field == account_policy_names[i].field) {
+ return account_policy_names[i].string;
+ }
+ }
+ return NULL;
+}
+
+/****************************************************************************
+Get the account policy LDAP attribute as a string from its #define'ed number
+****************************************************************************/
+
+const char *get_account_policy_attr(int field)
+{
+ int i;
+ for (i=0; account_policy_names[i].field; i++) {
+ if (field == account_policy_names[i].field) {
+ return account_policy_names[i].ldap_attr;
+ }
+ }
+ return NULL;
+}
+
+/****************************************************************************
+Get the account policy description as a string from its #define'ed number
+****************************************************************************/
+
+const char *account_policy_get_desc(int field)
+{
+ int i;
+ for (i=0; account_policy_names[i].string; i++) {
+ if (field == account_policy_names[i].field) {
+ return account_policy_names[i].description;
+ }
+ }
+ return NULL;
+}
+
+/****************************************************************************
+Get the account policy name as a string from its #define'ed number
+****************************************************************************/
+
+int account_policy_name_to_fieldnum(const char *name)
+{
+ int i;
+ for (i=0; account_policy_names[i].string; i++) {
+ if (strcmp(name, account_policy_names[i].string) == 0) {
+ return account_policy_names[i].field;
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************
+Get default value for account policy
+*****************************************************************************/
+
+bool account_policy_get_default(int account_policy, uint32 *val)
+{
+ int i;
+ for (i=0; account_policy_names[i].field; i++) {
+ if (account_policy_names[i].field == account_policy) {
+ *val = account_policy_names[i].default_val;
+ return True;
+ }
+ }
+ DEBUG(0,("no default for account_policy index %d found. This should never happen\n",
+ account_policy));
+ return False;
+}
+
+/*****************************************************************************
+ Set default for a field if it is empty
+*****************************************************************************/
+
+static bool account_policy_set_default_on_empty(int account_policy)
+{
+
+ uint32 value;
+
+ if (!account_policy_get(account_policy, &value) &&
+ !account_policy_get_default(account_policy, &value)) {
+ return False;
+ }
+
+ return account_policy_set(account_policy, value);
+}
+
+/*****************************************************************************
+ Open the account policy tdb.
+***`*************************************************************************/
+
+bool init_account_policy(void)
+{
+
+ const char *vstring = "INFO/version";
+ uint32 version;
+ int i;
+
+ if (db != NULL) {
+ return True;
+ }
+
+ db = db_open(NULL, state_path("account_policy.tdb"), 0, TDB_DEFAULT,
+ O_RDWR, 0600);
+
+ if (db == NULL) { /* the account policies files does not exist or open
+ * failed, try to create a new one */
+ db = db_open(NULL, state_path("account_policy.tdb"), 0,
+ TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if (db == NULL) {
+ DEBUG(0,("Failed to open account policy database\n"));
+ return False;
+ }
+ }
+
+ version = dbwrap_fetch_int32(db, vstring);
+ if (version == DATABASE_VERSION) {
+ return true;
+ }
+
+ /* handle a Samba upgrade */
+
+ if (db->transaction_start(db) != 0) {
+ DEBUG(0, ("transaction_start failed\n"));
+ TALLOC_FREE(db);
+ return false;
+ }
+
+ version = dbwrap_fetch_int32(db, vstring);
+ if (version == DATABASE_VERSION) {
+ /*
+ * Race condition
+ */
+ if (db->transaction_cancel(db)) {
+ smb_panic("transaction_cancel failed");
+ }
+ return true;
+ }
+
+ if (version != DATABASE_VERSION) {
+ if (dbwrap_store_uint32(db, vstring, DATABASE_VERSION) != 0) {
+ DEBUG(0, ("dbwrap_store_uint32 failed\n"));
+ goto cancel;
+ }
+
+ for (i=0; account_policy_names[i].field; i++) {
+
+ if (!account_policy_set_default_on_empty(account_policy_names[i].field)) {
+ DEBUG(0,("failed to set default value in account policy tdb\n"));
+ goto cancel;
+ }
+ }
+ }
+
+ /* These exist by default on NT4 in [HKLM\SECURITY\Policy\Accounts] */
+
+ privilege_create_account( &global_sid_World );
+ privilege_create_account( &global_sid_Builtin_Account_Operators );
+ privilege_create_account( &global_sid_Builtin_Server_Operators );
+ privilege_create_account( &global_sid_Builtin_Print_Operators );
+ privilege_create_account( &global_sid_Builtin_Backup_Operators );
+
+ /* BUILTIN\Administrators get everything -- *always* */
+
+ if ( lp_enable_privileges() ) {
+ if ( !grant_all_privileges( &global_sid_Builtin_Administrators ) ) {
+ DEBUG(1,("init_account_policy: Failed to grant privileges "
+ "to BUILTIN\\Administrators!\n"));
+ }
+ }
+
+ if (db->transaction_commit(db) != 0) {
+ DEBUG(0, ("transaction_commit failed\n"));
+ TALLOC_FREE(db);
+ return false;
+ }
+
+ return True;
+
+ cancel:
+ if (db->transaction_cancel(db)) {
+ smb_panic("transaction_cancel failed");
+ }
+ TALLOC_FREE(db);
+
+ return false;
+}
+
+/*****************************************************************************
+Get an account policy (from tdb)
+*****************************************************************************/
+
+bool account_policy_get(int field, uint32 *value)
+{
+ const char *name;
+ uint32 regval;
+
+ if (!init_account_policy()) {
+ return False;
+ }
+
+ if (value) {
+ *value = 0;
+ }
+
+ name = decode_account_policy_name(field);
+ if (name == NULL) {
+ DEBUG(1, ("account_policy_get: Field %d is not a valid account policy type! Cannot get, returning 0.\n", field));
+ return False;
+ }
+
+ if (!dbwrap_fetch_uint32(db, name, &regval)) {
+ DEBUG(1, ("account_policy_get: tdb_fetch_uint32 failed for field %d (%s), returning 0\n", field, name));
+ return False;
+ }
+
+ if (value) {
+ *value = regval;
+ }
+
+ DEBUG(10,("account_policy_get: name: %s, val: %d\n", name, regval));
+ return True;
+}
+
+
+/****************************************************************************
+Set an account policy (in tdb)
+****************************************************************************/
+
+bool account_policy_set(int field, uint32 value)
+{
+ const char *name;
+ NTSTATUS status;
+
+ if (!init_account_policy()) {
+ return False;
+ }
+
+ name = decode_account_policy_name(field);
+ if (name == NULL) {
+ DEBUG(1, ("Field %d is not a valid account policy type! Cannot set.\n", field));
+ return False;
+ }
+
+ status = dbwrap_trans_store_uint32(db, name, value);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("store_uint32 failed for field %d (%s) on value "
+ "%u: %s\n", field, name, value, nt_errstr(status)));
+ return False;
+ }
+
+ DEBUG(10,("account_policy_set: name: %s, value: %d\n", name, value));
+
+ return True;
+}
+
+/****************************************************************************
+Set an account policy in the cache
+****************************************************************************/
+
+bool cache_account_policy_set(int field, uint32 value)
+{
+ const char *policy_name = NULL;
+ char *cache_key = NULL;
+ char *cache_value = NULL;
+ bool ret = False;
+
+ policy_name = decode_account_policy_name(field);
+ if (policy_name == NULL) {
+ DEBUG(0,("cache_account_policy_set: no policy found\n"));
+ return False;
+ }
+
+ if (asprintf(&cache_key, "ACCT_POL/%s", policy_name) < 0) {
+ DEBUG(0, ("asprintf failed\n"));
+ goto done;
+ }
+
+ if (asprintf(&cache_value, "%lu\n", (unsigned long)value) < 0) {
+ DEBUG(0, ("asprintf failed\n"));
+ goto done;
+ }
+
+ DEBUG(10,("cache_account_policy_set: updating account pol cache\n"));
+
+ ret = gencache_set(cache_key, cache_value, time(NULL)+AP_TTL);
+
+ done:
+ SAFE_FREE(cache_key);
+ SAFE_FREE(cache_value);
+ return ret;
+}
+
+/*****************************************************************************
+Get an account policy from the cache
+*****************************************************************************/
+
+bool cache_account_policy_get(int field, uint32 *value)
+{
+ const char *policy_name = NULL;
+ char *cache_key = NULL;
+ char *cache_value = NULL;
+ bool ret = False;
+
+ policy_name = decode_account_policy_name(field);
+ if (policy_name == NULL) {
+ DEBUG(0,("cache_account_policy_set: no policy found\n"));
+ return False;
+ }
+
+ if (asprintf(&cache_key, "ACCT_POL/%s", policy_name) < 0) {
+ DEBUG(0, ("asprintf failed\n"));
+ goto done;
+ }
+
+ if (gencache_get(cache_key, &cache_value, NULL)) {
+ uint32 tmp = strtoul(cache_value, NULL, 10);
+ *value = tmp;
+ ret = True;
+ }
+
+ done:
+ SAFE_FREE(cache_key);
+ SAFE_FREE(cache_value);
+ return ret;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+struct db_context *get_account_pol_db( void )
+{
+
+ if ( db == NULL ) {
+ if ( !init_account_policy() ) {
+ return NULL;
+ }
+ }
+
+ return db;
+}
+
diff --git a/source3/lib/adt_tree.c b/source3/lib/adt_tree.c
new file mode 100644
index 0000000000..6ac498d9e6
--- /dev/null
+++ b/source3/lib/adt_tree.c
@@ -0,0 +1,430 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Generic Abstract Data Types
+ * Copyright (C) Gerald Carter 2002.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "adt_tree.h"
+
+
+/**************************************************************************
+ *************************************************************************/
+
+static bool trim_tree_keypath( char *path, char **base, char **new_path )
+{
+ char *p;
+
+ *new_path = *base = NULL;
+
+ if ( !path )
+ return False;
+
+ *base = path;
+
+ p = strchr( path, '/' );
+
+ if ( p ) {
+ *p = '\0';
+ *new_path = p+1;
+ }
+
+ return True;
+}
+
+
+/**************************************************************************
+ Initialize the tree's root. The cmp_fn is a callback function used
+ for comparision of two children
+ *************************************************************************/
+
+ SORTED_TREE* pathtree_init( void *data_p, int (cmp_fn)(void*, void*) )
+{
+ SORTED_TREE *tree = NULL;
+
+ if ( !(tree = TALLOC_ZERO_P(NULL, SORTED_TREE)) )
+ return NULL;
+
+ tree->compare = cmp_fn;
+
+ if ( !(tree->root = TALLOC_ZERO_P(tree, TREE_NODE)) ) {
+ TALLOC_FREE( tree );
+ return NULL;
+ }
+
+ tree->root->data_p = data_p;
+
+ return tree;
+}
+
+
+/**************************************************************************
+ Find the next child given a key string
+ *************************************************************************/
+
+static TREE_NODE* pathtree_birth_child( TREE_NODE *node, char* key )
+{
+ TREE_NODE *infant = NULL;
+ TREE_NODE **siblings;
+ int i;
+
+ if ( !(infant = TALLOC_ZERO_P( node, TREE_NODE)) )
+ return NULL;
+
+ infant->key = talloc_strdup( infant, key );
+ infant->parent = node;
+
+ siblings = TALLOC_REALLOC_ARRAY( node, node->children, TREE_NODE *, node->num_children+1 );
+
+ if ( siblings )
+ node->children = siblings;
+
+ node->num_children++;
+
+ /* first child */
+
+ if ( node->num_children == 1 ) {
+ DEBUG(11,("pathtree_birth_child: First child of node [%s]! [%s]\n",
+ node->key ? node->key : "NULL", infant->key ));
+ node->children[0] = infant;
+ }
+ else
+ {
+ /*
+ * multiple siblings .... (at least 2 children)
+ *
+ * work from the end of the list forward
+ * The last child is not set at this point
+ * Insert the new infanct in ascending order
+ * from left to right
+ */
+
+ for ( i = node->num_children-1; i>=1; i-- )
+ {
+ DEBUG(11,("pathtree_birth_child: Looking for crib; infant -> [%s], child -> [%s]\n",
+ infant->key, node->children[i-1]->key));
+
+ /* the strings should never match assuming that we
+ have called pathtree_find_child() first */
+
+ if ( StrCaseCmp( infant->key, node->children[i-1]->key ) > 0 ) {
+ DEBUG(11,("pathtree_birth_child: storing infant in i == [%d]\n",
+ i));
+ node->children[i] = infant;
+ break;
+ }
+
+ /* bump everything towards the end on slot */
+
+ node->children[i] = node->children[i-1];
+ }
+
+ DEBUG(11,("pathtree_birth_child: Exiting loop (i == [%d])\n", i ));
+
+ /* if we haven't found the correct slot yet, the child
+ will be first in the list */
+
+ if ( i == 0 )
+ node->children[0] = infant;
+ }
+
+ return infant;
+}
+
+/**************************************************************************
+ Find the next child given a key string
+ *************************************************************************/
+
+static TREE_NODE* pathtree_find_child( TREE_NODE *node, char* key )
+{
+ TREE_NODE *next = NULL;
+ int i, result;
+
+ if ( !node ) {
+ DEBUG(0,("pathtree_find_child: NULL node passed into function!\n"));
+ return NULL;
+ }
+
+ if ( !key ) {
+ DEBUG(0,("pathtree_find_child: NULL key string passed into function!\n"));
+ return NULL;
+ }
+
+ for ( i=0; i<node->num_children; i++ )
+ {
+ DEBUG(11,("pathtree_find_child: child key => [%s]\n",
+ node->children[i]->key));
+
+ result = StrCaseCmp( node->children[i]->key, key );
+
+ if ( result == 0 )
+ next = node->children[i];
+
+ /* if result > 0 then we've gone to far because
+ the list of children is sorted by key name
+ If result == 0, then we have a match */
+
+ if ( result > 0 )
+ break;
+ }
+
+ DEBUG(11,("pathtree_find_child: %s [%s]\n",
+ next ? "Found" : "Did not find", key ));
+
+ return next;
+}
+
+/**************************************************************************
+ Add a new node into the tree given a key path and a blob of data
+ *************************************************************************/
+
+ WERROR pathtree_add( SORTED_TREE *tree, const char *path, void *data_p )
+{
+ char *str, *base, *path2;
+ TREE_NODE *current, *next;
+ WERROR ret = WERR_OK;
+
+ DEBUG(8,("pathtree_add: Enter\n"));
+
+ if ( !path || *path != '/' ) {
+ DEBUG(0,("pathtree_add: Attempt to add a node with a bad path [%s]\n",
+ path ? path : "NULL" ));
+ return WERR_INVALID_PARAM;
+ }
+
+ if ( !tree ) {
+ DEBUG(0,("pathtree_add: Attempt to add a node to an uninitialized tree!\n"));
+ return WERR_INVALID_PARAM;
+ }
+
+ /* move past the first '/' */
+
+ path++;
+ path2 = SMB_STRDUP( path );
+ if ( !path2 ) {
+ DEBUG(0,("pathtree_add: strdup() failed on string [%s]!?!?!\n", path));
+ return WERR_NOMEM;
+ }
+
+
+ /*
+ * this works sort of like a 'mkdir -p' call, possibly
+ * creating an entire path to the new node at once
+ * The path should be of the form /<key1>/<key2>/...
+ */
+
+ base = path2;
+ str = path2;
+ current = tree->root;
+
+ do {
+ /* break off the remaining part of the path */
+
+ str = strchr( str, '/' );
+ if ( str )
+ *str = '\0';
+
+ /* iterate to the next child--birth it if necessary */
+
+ next = pathtree_find_child( current, base );
+ if ( !next ) {
+ next = pathtree_birth_child( current, base );
+ if ( !next ) {
+ DEBUG(0,("pathtree_add: Failed to create new child!\n"));
+ ret = WERR_NOMEM;
+ goto done;
+ }
+ }
+ current = next;
+
+ /* setup the next part of the path */
+
+ base = str;
+ if ( base ) {
+ *base = '/';
+ base++;
+ str = base;
+ }
+
+ } while ( base != NULL );
+
+ current->data_p = data_p;
+
+ DEBUG(10,("pathtree_add: Successfully added node [%s] to tree\n",
+ path ));
+
+ DEBUG(8,("pathtree_add: Exit\n"));
+
+done:
+ SAFE_FREE( path2 );
+ return ret;
+}
+
+
+/**************************************************************************
+ Recursive routine to print out all children of a TREE_NODE
+ *************************************************************************/
+
+static void pathtree_print_children(TALLOC_CTX *ctx,
+ TREE_NODE *node,
+ int debug,
+ const char *path )
+{
+ int i;
+ int num_children;
+ char *path2 = NULL;
+
+ if ( !node )
+ return;
+
+ if ( node->key )
+ DEBUG(debug,("%s: [%s] (%s)\n", path ? path : "NULL", node->key,
+ node->data_p ? "data" : "NULL" ));
+
+ if ( path ) {
+ path2 = talloc_strdup(ctx, path);
+ if (!path2) {
+ return;
+ }
+ }
+
+ path2 = talloc_asprintf(ctx,
+ "%s%s/",
+ path ? path : "",
+ node->key ? node->key : "NULL");
+ if (!path2) {
+ return;
+ }
+
+ num_children = node->num_children;
+ for ( i=0; i<num_children; i++ ) {
+ pathtree_print_children(ctx, node->children[i], debug, path2 );
+ }
+}
+
+/**************************************************************************
+ Dump the kys for a tree to the log file
+ *************************************************************************/
+
+ void pathtree_print_keys( SORTED_TREE *tree, int debug )
+{
+ int i;
+ int num_children = tree->root->num_children;
+
+ if ( tree->root->key )
+ DEBUG(debug,("ROOT/: [%s] (%s)\n", tree->root->key,
+ tree->root->data_p ? "data" : "NULL" ));
+
+ for ( i=0; i<num_children; i++ ) {
+ TALLOC_CTX *ctx = talloc_stackframe();
+ pathtree_print_children(ctx, tree->root->children[i], debug,
+ tree->root->key ? tree->root->key : "ROOT/" );
+ TALLOC_FREE(ctx);
+ }
+
+}
+
+/**************************************************************************
+ return the data_p for for the node in tree matching the key string
+ The key string is the full path. We must break it apart and walk
+ the tree
+ *************************************************************************/
+
+ void* pathtree_find( SORTED_TREE *tree, char *key )
+{
+ char *keystr, *base = NULL, *str = NULL, *p;
+ TREE_NODE *current;
+ void *result = NULL;
+
+ DEBUG(10,("pathtree_find: Enter [%s]\n", key ? key : "NULL" ));
+
+ /* sanity checks first */
+
+ if ( !key ) {
+ DEBUG(0,("pathtree_find: Attempt to search tree using NULL search string!\n"));
+ return NULL;
+ }
+
+ if ( !tree ) {
+ DEBUG(0,("pathtree_find: Attempt to search an uninitialized tree using string [%s]!\n",
+ key ? key : "NULL" ));
+ return NULL;
+ }
+
+ if ( !tree->root )
+ return NULL;
+
+ /* make a copy to play with */
+
+ if ( *key == '/' )
+ keystr = SMB_STRDUP( key+1 );
+ else
+ keystr = SMB_STRDUP( key );
+
+ if ( !keystr ) {
+ DEBUG(0,("pathtree_find: strdup() failed on string [%s]!?!?!\n", key));
+ return NULL;
+ }
+
+ /* start breaking the path apart */
+
+ p = keystr;
+ current = tree->root;
+
+ if ( tree->root->data_p )
+ result = tree->root->data_p;
+
+ do
+ {
+ /* break off the remaining part of the path */
+
+ trim_tree_keypath( p, &base, &str );
+
+ DEBUG(11,("pathtree_find: [loop] base => [%s], new_path => [%s]\n",
+ base ? base : "",
+ str ? str : ""));
+
+ /* iterate to the next child */
+
+ current = pathtree_find_child( current, base );
+
+ /*
+ * the idea is that the data_p for a parent should
+ * be inherited by all children, but allow it to be
+ * overridden farther down
+ */
+
+ if ( current && current->data_p )
+ result = current->data_p;
+
+ /* reset the path pointer 'p' to the remaining part of the key string */
+
+ p = str;
+
+ } while ( str && current );
+
+ /* result should be the data_p from the lowest match node in the tree */
+ if ( result )
+ DEBUG(11,("pathtree_find: Found data_p!\n"));
+
+ SAFE_FREE( keystr );
+
+ DEBUG(10,("pathtree_find: Exit\n"));
+
+ return result;
+}
+
+
diff --git a/source3/lib/afs.c b/source3/lib/afs.c
new file mode 100644
index 0000000000..7193f0e46d
--- /dev/null
+++ b/source3/lib/afs.c
@@ -0,0 +1,298 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Generate AFS tickets
+ * Copyright (C) Volker Lendecke 2003
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#ifdef WITH_FAKE_KASERVER
+
+#define NO_ASN1_TYPEDEFS 1
+
+#include <afs/stds.h>
+#include <afs/afs.h>
+#include <afs/auth.h>
+#include <afs/venus.h>
+#include <asm/unistd.h>
+#include <openssl/des.h>
+
+struct ClearToken {
+ uint32 AuthHandle;
+ char HandShakeKey[8];
+ uint32 ViceId;
+ uint32 BeginTimestamp;
+ uint32 EndTimestamp;
+};
+
+static char *afs_encode_token(const char *cell, const DATA_BLOB ticket,
+ const struct ClearToken *ct)
+{
+ char *base64_ticket;
+ char *result = NULL;
+
+ DATA_BLOB key = data_blob(ct->HandShakeKey, 8);
+ char *base64_key;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_stackframe();
+ if (mem_ctx == NULL)
+ goto done;
+
+ base64_ticket = base64_encode_data_blob(mem_ctx, ticket);
+ if (base64_ticket == NULL)
+ goto done;
+
+ base64_key = base64_encode_data_blob(mem_ctx, key);
+ if (base64_key == NULL)
+ goto done;
+
+ asprintf(&result, "%s\n%u\n%s\n%u\n%u\n%u\n%s\n", cell,
+ ct->AuthHandle, base64_key, ct->ViceId, ct->BeginTimestamp,
+ ct->EndTimestamp, base64_ticket);
+
+ DEBUG(10, ("Got ticket string:\n%s\n", result));
+
+done:
+ TALLOC_FREE(mem_ctx);
+
+ return result;
+}
+
+/* Create a ClearToken and an encrypted ticket. ClearToken has not yet the
+ * ViceId set, this should be set by the caller. */
+
+static bool afs_createtoken(const char *username, const char *cell,
+ DATA_BLOB *ticket, struct ClearToken *ct)
+{
+ fstring clear_ticket;
+ char *p = clear_ticket;
+ uint32 len;
+ uint32 now;
+
+ struct afs_key key;
+ des_key_schedule key_schedule;
+
+ if (!secrets_init())
+ return False;
+
+ if (!secrets_fetch_afs_key(cell, &key)) {
+ DEBUG(1, ("Could not fetch AFS service key\n"));
+ return False;
+ }
+
+ ct->AuthHandle = key.kvno;
+
+ /* Build the ticket. This is going to be encrypted, so in our
+ way we fill in ct while we still have the unencrypted
+ form. */
+
+ p = clear_ticket;
+
+ /* The byte-order */
+ *p = 1;
+ p += 1;
+
+ /* "Alice", the client username */
+ strncpy(p, username, sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
+ p += strlen(p)+1;
+ strncpy(p, "", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
+ p += strlen(p)+1;
+ strncpy(p, cell, sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
+ p += strlen(p)+1;
+
+ /* Alice's network layer address. At least Openafs-1.2.10
+ ignores this, so we fill in a dummy value here. */
+ SIVAL(p, 0, 0);
+ p += 4;
+
+ /* We need to create a session key */
+ generate_random_buffer(p, 8);
+
+ /* Our client code needs the the key in the clear, it does not
+ know the server-key ... */
+ memcpy(ct->HandShakeKey, p, 8);
+
+ p += 8;
+
+ /* This is a kerberos 4 life time. The life time is expressed
+ * in units of 5 minute intervals up to 38400 seconds, after
+ * that a table is used up to lifetime 0xBF. Values between
+ * 0xC0 and 0xFF is undefined. 0xFF is defined to be the
+ * infinite time that never expire.
+ *
+ * So here we cheat and use the infinite time */
+ *p = 255;
+ p += 1;
+
+ /* Ticket creation time */
+ now = time(NULL);
+ SIVAL(p, 0, now);
+ ct->BeginTimestamp = now;
+
+ if(lp_afs_token_lifetime() == 0)
+ ct->EndTimestamp = NEVERDATE;
+ else
+ ct->EndTimestamp = now + lp_afs_token_lifetime();
+
+ if (((ct->EndTimestamp - ct->BeginTimestamp) & 1) == 1) {
+ ct->BeginTimestamp += 1; /* Lifetime must be even */
+ }
+ p += 4;
+
+ /* And here comes Bob's name and instance, in this case the
+ AFS server. */
+ strncpy(p, "afs", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
+ p += strlen(p)+1;
+ strncpy(p, "", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
+ p += strlen(p)+1;
+
+ /* And zero-pad to a multiple of 8 bytes */
+ len = PTR_DIFF(p, clear_ticket);
+ if (len & 7) {
+ uint32 extra_space = 8-(len & 7);
+ memset(p, 0, extra_space);
+ p+=extra_space;
+ }
+ len = PTR_DIFF(p, clear_ticket);
+
+ des_key_sched((const_des_cblock *)key.key, key_schedule);
+ des_pcbc_encrypt(clear_ticket, clear_ticket,
+ len, key_schedule, (C_Block *)key.key, 1);
+
+ ZERO_STRUCT(key);
+
+ *ticket = data_blob(clear_ticket, len);
+
+ return True;
+}
+
+char *afs_createtoken_str(const char *username, const char *cell)
+{
+ DATA_BLOB ticket;
+ struct ClearToken ct;
+ char *result;
+
+ if (!afs_createtoken(username, cell, &ticket, &ct))
+ return NULL;
+
+ result = afs_encode_token(cell, ticket, &ct);
+
+ data_blob_free(&ticket);
+
+ return result;
+}
+
+/*
+ This routine takes a radical approach completely bypassing the
+ Kerberos idea of security and using AFS simply as an intelligent
+ file backend. Samba has persuaded itself somehow that the user is
+ actually correctly identified and then we create a ticket that the
+ AFS server hopefully accepts using its KeyFile that the admin has
+ kindly stored to our secrets.tdb.
+
+ Thanks to the book "Network Security -- PRIVATE Communication in a
+ PUBLIC World" by Charlie Kaufman, Radia Perlman and Mike Speciner
+ Kerberos 4 tickets are not really hard to construct.
+
+ For the comments "Alice" is the User to be auth'ed, and "Bob" is the
+ AFS server. */
+
+bool afs_login(connection_struct *conn)
+{
+ DATA_BLOB ticket;
+ char *afs_username = NULL;
+ char *cell = NULL;
+ bool result;
+ char *ticket_str = NULL;
+ const DOM_SID *user_sid;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ struct ClearToken ct;
+
+ afs_username = talloc_strdup(ctx,
+ lp_afs_username_map());
+ if (!afs_username) {
+ return false;
+ }
+
+ afs_username = talloc_sub_advanced(ctx,
+ SNUM(conn), conn->user,
+ conn->connectpath, conn->gid,
+ conn->server_info->sanitized_username,
+ pdb_get_domain(conn->server_info->sam_account),
+ afs_username);
+ if (!afs_username) {
+ return false;
+ }
+
+ user_sid = &conn->server_info->ptok->user_sids[0];
+ afs_username = talloc_string_sub(talloc_tos(),
+ afs_username,
+ "%s",
+ sid_string_tos(user_sid));
+ if (!afs_username) {
+ return false;
+ }
+
+ /* The pts command always generates completely lower-case user
+ * names. */
+ strlower_m(afs_username);
+
+ cell = strchr(afs_username, '@');
+
+ if (cell == NULL) {
+ DEBUG(1, ("AFS username doesn't contain a @, "
+ "could not find cell\n"));
+ return false;
+ }
+
+ *cell = '\0';
+ cell += 1;
+
+ DEBUG(10, ("Trying to log into AFS for user %s@%s\n",
+ afs_username, cell));
+
+ if (!afs_createtoken(afs_username, cell, &ticket, &ct))
+ return False;
+
+ /* For which Unix-UID do we want to set the token? */
+ ct.ViceId = getuid();
+
+ ticket_str = afs_encode_token(cell, ticket, &ct);
+
+ result = afs_settoken_str(ticket_str);
+
+ SAFE_FREE(ticket_str);
+
+ data_blob_free(&ticket);
+
+ return result;
+}
+
+#else
+
+bool afs_login(connection_struct *conn)
+{
+ return True;
+}
+
+char *afs_createtoken_str(const char *username, const char *cell)
+{
+ return NULL;
+}
+
+#endif /* WITH_FAKE_KASERVER */
diff --git a/source3/lib/afs_settoken.c b/source3/lib/afs_settoken.c
new file mode 100644
index 0000000000..444f09efca
--- /dev/null
+++ b/source3/lib/afs_settoken.c
@@ -0,0 +1,239 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Generate AFS tickets
+ * Copyright (C) Volker Lendecke 2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#ifdef WITH_FAKE_KASERVER
+
+#define NO_ASN1_TYPEDEFS 1
+
+#include <afs/stds.h>
+#include <afs/afs.h>
+#include <afs/auth.h>
+#include <afs/venus.h>
+#include <asm/unistd.h>
+#include <openssl/des.h>
+#include <sys/syscall.h>
+
+int afs_syscall( int subcall,
+ char * path,
+ int cmd,
+ char * cmarg,
+ int follow)
+{
+ return( syscall( SYS_afs_syscall, subcall, path, cmd, cmarg, follow));
+}
+
+struct ClearToken {
+ uint32 AuthHandle;
+ char HandShakeKey[8];
+ uint32 ViceId;
+ uint32 BeginTimestamp;
+ uint32 EndTimestamp;
+};
+
+static bool afs_decode_token(const char *string, char **cell,
+ DATA_BLOB *ticket, struct ClearToken *ct)
+{
+ DATA_BLOB blob;
+ struct ClearToken result_ct;
+ char *saveptr;
+
+ char *s = SMB_STRDUP(string);
+
+ char *t;
+
+ if ((t = strtok_r(s, "\n", &saveptr)) == NULL) {
+ DEBUG(10, ("strtok_r failed\n"));
+ return False;
+ }
+
+ *cell = SMB_STRDUP(t);
+
+ if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
+ DEBUG(10, ("strtok_r failed\n"));
+ return False;
+ }
+
+ if (sscanf(t, "%u", &result_ct.AuthHandle) != 1) {
+ DEBUG(10, ("sscanf AuthHandle failed\n"));
+ return False;
+ }
+
+ if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
+ DEBUG(10, ("strtok_r failed\n"));
+ return False;
+ }
+
+ blob = base64_decode_data_blob(t);
+
+ if ( (blob.data == NULL) ||
+ (blob.length != sizeof(result_ct.HandShakeKey) )) {
+ DEBUG(10, ("invalid key: %x/%d\n", (uint32)blob.data,
+ blob.length));
+ return False;
+ }
+
+ memcpy(result_ct.HandShakeKey, blob.data, blob.length);
+
+ data_blob_free(&blob);
+
+ if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
+ DEBUG(10, ("strtok_r failed\n"));
+ return False;
+ }
+
+ if (sscanf(t, "%u", &result_ct.ViceId) != 1) {
+ DEBUG(10, ("sscanf ViceId failed\n"));
+ return False;
+ }
+
+ if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
+ DEBUG(10, ("strtok_r failed\n"));
+ return False;
+ }
+
+ if (sscanf(t, "%u", &result_ct.BeginTimestamp) != 1) {
+ DEBUG(10, ("sscanf BeginTimestamp failed\n"));
+ return False;
+ }
+
+ if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
+ DEBUG(10, ("strtok_r failed\n"));
+ return False;
+ }
+
+ if (sscanf(t, "%u", &result_ct.EndTimestamp) != 1) {
+ DEBUG(10, ("sscanf EndTimestamp failed\n"));
+ return False;
+ }
+
+ if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
+ DEBUG(10, ("strtok_r failed\n"));
+ return False;
+ }
+
+ blob = base64_decode_data_blob(t);
+
+ if (blob.data == NULL) {
+ DEBUG(10, ("Could not get ticket\n"));
+ return False;
+ }
+
+ *ticket = blob;
+ *ct = result_ct;
+
+ return True;
+}
+
+/*
+ Put an AFS token into the Kernel so that it can authenticate against
+ the AFS server. This assumes correct local uid settings.
+
+ This is currently highly Linux and OpenAFS-specific. The correct API
+ call for this would be ktc_SetToken. But to do that we would have to
+ import a REALLY big bunch of libraries which I would currently like
+ to avoid.
+*/
+
+static bool afs_settoken(const char *cell,
+ const struct ClearToken *ctok,
+ DATA_BLOB ticket)
+{
+ int ret;
+ struct {
+ char *in, *out;
+ uint16 in_size, out_size;
+ } iob;
+
+ char buf[1024];
+ char *p = buf;
+ int tmp;
+
+ memcpy(p, &ticket.length, sizeof(uint32));
+ p += sizeof(uint32);
+ memcpy(p, ticket.data, ticket.length);
+ p += ticket.length;
+
+ tmp = sizeof(struct ClearToken);
+ memcpy(p, &tmp, sizeof(uint32));
+ p += sizeof(uint32);
+ memcpy(p, ctok, tmp);
+ p += tmp;
+
+ tmp = 0;
+
+ memcpy(p, &tmp, sizeof(uint32));
+ p += sizeof(uint32);
+
+ tmp = strlen(cell);
+ if (tmp >= MAXKTCREALMLEN) {
+ DEBUG(1, ("Realm too long\n"));
+ return False;
+ }
+
+ strncpy(p, cell, tmp);
+ p += tmp;
+ *p = 0;
+ p +=1;
+
+ iob.in = buf;
+ iob.in_size = PTR_DIFF(p,buf);
+ iob.out = buf;
+ iob.out_size = sizeof(buf);
+
+#if 0
+ file_save("/tmp/ioctlbuf", iob.in, iob.in_size);
+#endif
+
+ ret = afs_syscall(AFSCALL_PIOCTL, 0, VIOCSETTOK, (char *)&iob, 0);
+
+ DEBUG(10, ("afs VIOCSETTOK returned %d\n", ret));
+ return (ret == 0);
+}
+
+bool afs_settoken_str(const char *token_string)
+{
+ DATA_BLOB ticket;
+ struct ClearToken ct;
+ bool result;
+ char *cell;
+
+ if (!afs_decode_token(token_string, &cell, &ticket, &ct))
+ return False;
+
+ if (geteuid() != 0)
+ ct.ViceId = getuid();
+
+ result = afs_settoken(cell, &ct, ticket);
+
+ SAFE_FREE(cell);
+ data_blob_free(&ticket);
+
+ return result;
+}
+
+#else
+
+bool afs_settoken_str(const char *token_string)
+{
+ return False;
+}
+
+#endif
diff --git a/source3/lib/arc4.c b/source3/lib/arc4.c
new file mode 100644
index 0000000000..af2564b6c0
--- /dev/null
+++ b/source3/lib/arc4.c
@@ -0,0 +1,79 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ An implementation of arc4.
+
+ Copyright (C) Jeremy Allison 2005.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*****************************************************************
+ Initialize state for an arc4 crypt/decrpyt.
+ arc4 state is 258 bytes - last 2 bytes are the index bytes.
+*****************************************************************/
+
+void smb_arc4_init(unsigned char arc4_state_out[258], const unsigned char *key, size_t keylen)
+{
+ size_t ind;
+ unsigned char j = 0;
+
+ for (ind = 0; ind < 256; ind++) {
+ arc4_state_out[ind] = (unsigned char)ind;
+ }
+
+ for( ind = 0; ind < 256; ind++) {
+ unsigned char tc;
+
+ j += (arc4_state_out[ind] + key[ind%keylen]);
+
+ tc = arc4_state_out[ind];
+ arc4_state_out[ind] = arc4_state_out[j];
+ arc4_state_out[j] = tc;
+ }
+ arc4_state_out[256] = 0;
+ arc4_state_out[257] = 0;
+}
+
+/*****************************************************************
+ Do the arc4 crypt/decrpyt.
+ arc4 state is 258 bytes - last 2 bytes are the index bytes.
+*****************************************************************/
+
+void smb_arc4_crypt(unsigned char arc4_state_inout[258], unsigned char *data, size_t len)
+{
+ unsigned char index_i = arc4_state_inout[256];
+ unsigned char index_j = arc4_state_inout[257];
+ size_t ind;
+
+ for( ind = 0; ind < len; ind++) {
+ unsigned char tc;
+ unsigned char t;
+
+ index_i++;
+ index_j += arc4_state_inout[index_i];
+
+ tc = arc4_state_inout[index_i];
+ arc4_state_inout[index_i] = arc4_state_inout[index_j];
+ arc4_state_inout[index_j] = tc;
+
+ t = arc4_state_inout[index_i] + arc4_state_inout[index_j];
+ data[ind] = data[ind] ^ arc4_state_inout[t];
+ }
+
+ arc4_state_inout[256] = index_i;
+ arc4_state_inout[257] = index_j;
+}
diff --git a/source3/lib/async_req.c b/source3/lib/async_req.c
new file mode 100644
index 0000000000..501a6b5524
--- /dev/null
+++ b/source3/lib/async_req.c
@@ -0,0 +1,174 @@
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async requests
+ Copyright (C) Volker Lendecke 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/**
+ * @brief Print an async_req structure
+ * @param[in] mem_ctx The memory context for the result
+ * @param[in] req The request to be printed
+ * @retval Text representation of req
+ *
+ * This is a default print function for async requests. Implementations should
+ * override this with more specific information.
+ *
+ * This function should not be used by async API users, this is non-static
+ * only to allow implementations to easily provide default information in
+ * their specific functions.
+ */
+
+char *async_req_print(TALLOC_CTX *mem_ctx, struct async_req *req)
+{
+ return talloc_asprintf(mem_ctx, "async_req: state=%d, status=%s, "
+ "priv=%s", req->state, nt_errstr(req->status),
+ talloc_get_name(req->private_data));
+}
+
+/**
+ * @brief Create an async request
+ * @param[in] mem_ctx The memory context for the result
+ * @param[in] ev The event context this async request will be driven by
+ * @retval A new async request
+ *
+ * The new async request will be initialized in state ASYNC_REQ_IN_PROGRESS
+ */
+
+struct async_req *async_req_new(TALLOC_CTX *mem_ctx, struct event_context *ev)
+{
+ struct async_req *result;
+
+ result = TALLOC_ZERO_P(mem_ctx, struct async_req);
+ if (result == NULL) {
+ return NULL;
+ }
+ result->state = ASYNC_REQ_IN_PROGRESS;
+ result->event_ctx = ev;
+ result->print = async_req_print;
+ return result;
+}
+
+/**
+ * @brief An async request has successfully finished
+ * @param[in] req The finished request
+ *
+ * async_req_done is to be used by implementors of async requests. When a
+ * request is successfully finished, this function calls the user's completion
+ * function.
+ */
+
+void async_req_done(struct async_req *req)
+{
+ req->status = NT_STATUS_OK;
+ req->state = ASYNC_REQ_DONE;
+ if (req->async.fn != NULL) {
+ req->async.fn(req);
+ }
+}
+
+/**
+ * @brief An async request has seen an error
+ * @param[in] req The request with an error
+ * @param[in] status The error code
+ *
+ * async_req_done is to be used by implementors of async requests. When a
+ * request can not successfully completed, the implementation should call this
+ * function with the appropriate status code.
+ */
+
+void async_req_error(struct async_req *req, NTSTATUS status)
+{
+ req->status = status;
+ req->state = ASYNC_REQ_ERROR;
+ if (req->async.fn != NULL) {
+ req->async.fn(req);
+ }
+}
+
+/**
+ * @brief Timed event callback
+ * @param[in] ev Event context
+ * @param[in] te The timed event
+ * @param[in] now current time
+ * @param[in] priv The async request to be finished
+ */
+
+static void async_trigger(struct event_context *ev, struct timed_event *te,
+ const struct timeval *now, void *priv)
+{
+ struct async_req *req = talloc_get_type_abort(priv, struct async_req);
+
+ TALLOC_FREE(te);
+ if (NT_STATUS_IS_OK(req->status)) {
+ async_req_done(req);
+ }
+ else {
+ async_req_error(req, req->status);
+ }
+}
+
+/**
+ * @brief Finish a request before it started processing
+ * @param[in] req The finished request
+ * @param[in] status The success code
+ *
+ * An implementation of an async request might find that it can either finish
+ * the request without waiting for an external event, or it can't even start
+ * the engine. To present the illusion of a callback to the user of the API,
+ * the implementation can call this helper function which triggers an
+ * immediate timed event. This way the caller can use the same calling
+ * conventions, independent of whether the request was actually deferred.
+ */
+
+bool async_post_status(struct async_req *req, NTSTATUS status)
+{
+ req->status = status;
+
+ if (event_add_timed(req->event_ctx, req, timeval_zero(),
+ "async_trigger",
+ async_trigger, req) == NULL) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * @brief Helper function for nomem check
+ * @param[in] p The pointer to be checked
+ * @param[in] req The request being processed
+ *
+ * Convenience helper to easily check alloc failure within a callback
+ * implementing the next step of an async request.
+ *
+ * Call pattern would be
+ * \code
+ * p = talloc(mem_ctx, bla);
+ * if (async_req_nomem(p, req)) {
+ * return;
+ * }
+ * \endcode
+ */
+
+bool async_req_nomem(const void *p, struct async_req *req)
+{
+ if (p != NULL) {
+ return false;
+ }
+ async_req_error(req, NT_STATUS_NO_MEMORY);
+ return true;
+}
diff --git a/source3/lib/async_sock.c b/source3/lib/async_sock.c
new file mode 100644
index 0000000000..1a4c27ba20
--- /dev/null
+++ b/source3/lib/async_sock.c
@@ -0,0 +1,674 @@
+/*
+ Unix SMB/CIFS implementation.
+ async socket syscalls
+ Copyright (C) Volker Lendecke 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/**
+ * Discriminator for async_syscall_state
+ */
+enum async_syscall_type {
+ ASYNC_SYSCALL_SEND,
+ ASYNC_SYSCALL_SENDALL,
+ ASYNC_SYSCALL_RECV,
+ ASYNC_SYSCALL_RECVALL,
+ ASYNC_SYSCALL_CONNECT
+};
+
+/**
+ * Holder for syscall arguments and the result
+ */
+
+struct async_syscall_state {
+ enum async_syscall_type syscall_type;
+ struct fd_event *fde;
+
+ union {
+ struct param_send {
+ int fd;
+ const void *buffer;
+ size_t length;
+ int flags;
+ } param_send;
+ struct param_sendall {
+ int fd;
+ const void *buffer;
+ size_t length;
+ int flags;
+ size_t sent;
+ } param_sendall;
+ struct param_recv {
+ int fd;
+ void *buffer;
+ size_t length;
+ int flags;
+ } param_recv;
+ struct param_recvall {
+ int fd;
+ void *buffer;
+ size_t length;
+ int flags;
+ size_t received;
+ } param_recvall;
+ struct param_connect {
+ /**
+ * connect needs to be done on a nonblocking
+ * socket. Keep the old flags around
+ */
+ long old_sockflags;
+ int fd;
+ const struct sockaddr *address;
+ socklen_t address_len;
+ } param_connect;
+ } param;
+
+ union {
+ ssize_t result_ssize_t;
+ size_t result_size_t;
+ int result_int;
+ } result;
+ int sys_errno;
+};
+
+/**
+ * @brief Create a new async syscall req
+ * @param[in] mem_ctx The memory context to hang the result off
+ * @param[in] ev The event context to work from
+ * @param[in] type Which syscall will this be
+ * @param[in] pstate Where to put the newly created private_data state
+ * @retval The new request
+ *
+ * This is a helper function to prepare a new struct async_req with an
+ * associated struct async_syscall_state. The async_syscall_state will be put
+ * into the async_req as private_data.
+ */
+
+static struct async_req *async_syscall_new(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ enum async_syscall_type type,
+ struct async_syscall_state **pstate)
+{
+ struct async_req *result;
+ struct async_syscall_state *state;
+
+ result = async_req_new(mem_ctx, ev);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ state = talloc(result, struct async_syscall_state);
+ if (state == NULL) {
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ state->syscall_type = type;
+
+ result->private_data = state;
+
+ *pstate = state;
+
+ return result;
+}
+
+/**
+ * @brief Create a new async syscall req based on a fd
+ * @param[in] mem_ctx The memory context to hang the result off
+ * @param[in] ev The event context to work from
+ * @param[in] type Which syscall will this be
+ * @param[in] fd The file descriptor we work on
+ * @param[in] fde_flags EVENT_FD_READ/WRITE -- what are we interested in?
+ * @param[in] fde_cb The callback function for the file descriptor event
+ * @param[in] pstate Where to put the newly created private_data state
+ * @retval The new request
+ *
+ * This is a helper function to prepare a new struct async_req with an
+ * associated struct async_syscall_state and an associated file descriptor
+ * event.
+ */
+
+static struct async_req *async_fde_syscall_new(
+ TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ enum async_syscall_type type,
+ int fd,
+ uint16_t fde_flags,
+ void (*fde_cb)(struct event_context *ev,
+ struct fd_event *fde, uint16_t flags,
+ void *priv),
+ struct async_syscall_state **pstate)
+{
+ struct async_req *result;
+ struct async_syscall_state *state;
+
+ result = async_syscall_new(mem_ctx, ev, type, &state);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ state->fde = event_add_fd(ev, state, fd, fde_flags, fde_cb, result);
+ if (state->fde == NULL) {
+ TALLOC_FREE(result);
+ return NULL;
+ }
+ *pstate = state;
+ return result;
+}
+
+/**
+ * Retrieve a ssize_t typed result from an async syscall
+ * @param[in] req The syscall that has just finished
+ * @param[out] perrno Where to put the syscall's errno
+ * @retval The return value from the asynchronously called syscall
+ */
+
+ssize_t async_syscall_result_ssize_t(struct async_req **req, int *perrno)
+{
+ struct async_syscall_state *state = talloc_get_type_abort(
+ (*req)->private_data, struct async_syscall_state);
+
+ int sys_errno = state->sys_errno;
+ ssize_t result = state->result.result_ssize_t;
+
+ TALLOC_FREE(*req);
+
+ *perrno = sys_errno;
+ return result;
+}
+
+/**
+ * Retrieve a size_t typed result from an async syscall
+ * @param[in] req The syscall that has just finished
+ * @param[out] perrno Where to put the syscall's errno
+ * @retval The return value from the asynchronously called syscall
+ */
+
+size_t async_syscall_result_size_t(struct async_req **req, int *perrno)
+{
+ struct async_syscall_state *state = talloc_get_type_abort(
+ (*req)->private_data, struct async_syscall_state);
+
+ int sys_errno = state->sys_errno;
+ size_t result = state->result.result_ssize_t;
+
+ TALLOC_FREE(*req);
+
+ *perrno = sys_errno;
+ return result;
+}
+
+/**
+ * Retrieve a int typed result from an async syscall
+ * @param[in] req The syscall that has just finished
+ * @param[out] perrno Where to put the syscall's errno
+ * @retval The return value from the asynchronously called syscall
+ */
+
+ssize_t async_syscall_result_int(struct async_req **req, int *perrno)
+{
+ struct async_syscall_state *state = talloc_get_type_abort(
+ (*req)->private_data, struct async_syscall_state);
+
+ int sys_errno = state->sys_errno;
+ int result = state->result.result_ssize_t;
+
+ TALLOC_FREE(*req);
+
+ *perrno = sys_errno;
+ return result;
+}
+
+/**
+ * fde event handler for the "send" syscall
+ * @param[in] ev The event context that sent us here
+ * @param[in] fde The file descriptor event associated with the send
+ * @param[in] flags Can only be EVENT_FD_WRITE here
+ * @param[in] priv private data, "struct async_req *" in this case
+ */
+
+static void async_send_callback(struct event_context *ev,
+ struct fd_event *fde, uint16_t flags,
+ void *priv)
+{
+ struct async_req *req = talloc_get_type_abort(
+ priv, struct async_req);
+ struct async_syscall_state *state = talloc_get_type_abort(
+ req->private_data, struct async_syscall_state);
+ struct param_send *p = &state->param.param_send;
+
+ SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_SEND);
+
+ state->result.result_ssize_t = send(p->fd, p->buffer, p->length,
+ p->flags);
+ state->sys_errno = errno;
+
+ TALLOC_FREE(state->fde);
+
+ async_req_done(req);
+}
+
+/**
+ * Async version of send(2)
+ * @param[in] mem_ctx The memory context to hang the result off
+ * @param[in] ev The event context to work from
+ * @param[in] fd The socket to send to
+ * @param[in] buffer The buffer to send
+ * @param[in] length How many bytes to send
+ * @param[in] flags flags passed to send(2)
+ *
+ * This function is a direct counterpart of send(2)
+ */
+
+struct async_req *async_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ int fd, const void *buffer, size_t length,
+ int flags)
+{
+ struct async_req *result;
+ struct async_syscall_state *state;
+
+ result = async_fde_syscall_new(
+ mem_ctx, ev, ASYNC_SYSCALL_SEND,
+ fd, EVENT_FD_WRITE, async_send_callback,
+ &state);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ state->param.param_send.fd = fd;
+ state->param.param_send.buffer = buffer;
+ state->param.param_send.length = length;
+ state->param.param_send.flags = flags;
+
+ return result;
+}
+
+/**
+ * fde event handler for the "sendall" syscall group
+ * @param[in] ev The event context that sent us here
+ * @param[in] fde The file descriptor event associated with the send
+ * @param[in] flags Can only be EVENT_FD_WRITE here
+ * @param[in] priv private data, "struct async_req *" in this case
+ */
+
+static void async_sendall_callback(struct event_context *ev,
+ struct fd_event *fde, uint16_t flags,
+ void *priv)
+{
+ struct async_req *req = talloc_get_type_abort(
+ priv, struct async_req);
+ struct async_syscall_state *state = talloc_get_type_abort(
+ req->private_data, struct async_syscall_state);
+ struct param_sendall *p = &state->param.param_sendall;
+
+ SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_SENDALL);
+
+ state->result.result_ssize_t = send(p->fd, (char *)p->buffer + p->sent,
+ p->length - p->sent, p->flags);
+ state->sys_errno = errno;
+
+ if (state->result.result_ssize_t == -1) {
+ async_req_error(req, map_nt_error_from_unix(state->sys_errno));
+ return;
+ }
+
+ if (state->result.result_ssize_t == 0) {
+ async_req_error(req, NT_STATUS_END_OF_FILE);
+ return;
+ }
+
+ p->sent += state->result.result_ssize_t;
+ SMB_ASSERT(p->sent <= p->length);
+
+ if (p->sent == p->length) {
+ TALLOC_FREE(state->fde);
+ async_req_done(req);
+ }
+}
+
+/**
+ * @brief Send all bytes to a socket
+ * @param[in] mem_ctx The memory context to hang the result off
+ * @param[in] ev The event context to work from
+ * @param[in] fd The socket to send to
+ * @param[in] buffer The buffer to send
+ * @param[in] length How many bytes to send
+ * @param[in] flags flags passed to send(2)
+ *
+ * async_sendall calls send(2) as long as it is necessary to send all of the
+ * "length" bytes
+ */
+
+struct async_req *async_sendall(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ int fd, const void *buffer, size_t length,
+ int flags)
+{
+ struct async_req *result;
+ struct async_syscall_state *state;
+
+ result = async_fde_syscall_new(
+ mem_ctx, ev, ASYNC_SYSCALL_SENDALL,
+ fd, EVENT_FD_WRITE, async_sendall_callback,
+ &state);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ state->param.param_sendall.fd = fd;
+ state->param.param_sendall.buffer = buffer;
+ state->param.param_sendall.length = length;
+ state->param.param_sendall.flags = flags;
+ state->param.param_sendall.sent = 0;
+
+ return result;
+}
+
+/**
+ * fde event handler for the "recv" syscall
+ * @param[in] ev The event context that sent us here
+ * @param[in] fde The file descriptor event associated with the recv
+ * @param[in] flags Can only be EVENT_FD_READ here
+ * @param[in] priv private data, "struct async_req *" in this case
+ */
+
+static void async_recv_callback(struct event_context *ev,
+ struct fd_event *fde, uint16_t flags,
+ void *priv)
+{
+ struct async_req *req = talloc_get_type_abort(
+ priv, struct async_req);
+ struct async_syscall_state *state = talloc_get_type_abort(
+ req->private_data, struct async_syscall_state);
+ struct param_recv *p = &state->param.param_recv;
+
+ SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_RECV);
+
+ state->result.result_ssize_t = recv(p->fd, p->buffer, p->length,
+ p->flags);
+ state->sys_errno = errno;
+
+ TALLOC_FREE(state->fde);
+
+ async_req_done(req);
+}
+
+/**
+ * Async version of recv(2)
+ * @param[in] mem_ctx The memory context to hang the result off
+ * @param[in] ev The event context to work from
+ * @param[in] fd The socket to recv from
+ * @param[in] buffer The buffer to recv into
+ * @param[in] length How many bytes to recv
+ * @param[in] flags flags passed to recv(2)
+ *
+ * This function is a direct counterpart of recv(2)
+ */
+
+struct async_req *async_recv(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ int fd, void *buffer, size_t length,
+ int flags)
+{
+ struct async_req *result;
+ struct async_syscall_state *state;
+
+ result = async_fde_syscall_new(
+ mem_ctx, ev, ASYNC_SYSCALL_RECV,
+ fd, EVENT_FD_READ, async_recv_callback,
+ &state);
+
+ if (result == NULL) {
+ return NULL;
+ }
+
+ state->param.param_recv.fd = fd;
+ state->param.param_recv.buffer = buffer;
+ state->param.param_recv.length = length;
+ state->param.param_recv.flags = flags;
+
+ return result;
+}
+
+/**
+ * fde event handler for the "recvall" syscall group
+ * @param[in] ev The event context that sent us here
+ * @param[in] fde The file descriptor event associated with the recv
+ * @param[in] flags Can only be EVENT_FD_READ here
+ * @param[in] priv private data, "struct async_req *" in this case
+ */
+
+static void async_recvall_callback(struct event_context *ev,
+ struct fd_event *fde, uint16_t flags,
+ void *priv)
+{
+ struct async_req *req = talloc_get_type_abort(
+ priv, struct async_req);
+ struct async_syscall_state *state = talloc_get_type_abort(
+ req->private_data, struct async_syscall_state);
+ struct param_recvall *p = &state->param.param_recvall;
+
+ SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_RECVALL);
+
+ state->result.result_ssize_t = recv(p->fd,
+ (char *)p->buffer + p->received,
+ p->length - p->received, p->flags);
+ state->sys_errno = errno;
+
+ if (state->result.result_ssize_t == -1) {
+ async_req_error(req, map_nt_error_from_unix(state->sys_errno));
+ return;
+ }
+
+ if (state->result.result_ssize_t == 0) {
+ async_req_error(req, NT_STATUS_END_OF_FILE);
+ return;
+ }
+
+ p->received += state->result.result_ssize_t;
+ SMB_ASSERT(p->received <= p->length);
+
+ if (p->received == p->length) {
+ TALLOC_FREE(state->fde);
+ async_req_done(req);
+ }
+}
+
+/**
+ * Receive a specified number of bytes from a socket
+ * @param[in] mem_ctx The memory context to hang the result off
+ * @param[in] ev The event context to work from
+ * @param[in] fd The socket to recv from
+ * @param[in] buffer The buffer to recv into
+ * @param[in] length How many bytes to recv
+ * @param[in] flags flags passed to recv(2)
+ *
+ * async_recvall will call recv(2) until "length" bytes are received
+ */
+
+struct async_req *async_recvall(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ int fd, void *buffer, size_t length,
+ int flags)
+{
+ struct async_req *result;
+ struct async_syscall_state *state;
+
+ result = async_fde_syscall_new(
+ mem_ctx, ev, ASYNC_SYSCALL_RECVALL,
+ fd, EVENT_FD_READ, async_recvall_callback,
+ &state);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ state->param.param_recvall.fd = fd;
+ state->param.param_recvall.buffer = buffer;
+ state->param.param_recvall.length = length;
+ state->param.param_recvall.flags = flags;
+ state->param.param_recvall.received = 0;
+
+ return result;
+}
+
+/**
+ * fde event handler for connect(2)
+ * @param[in] ev The event context that sent us here
+ * @param[in] fde The file descriptor event associated with the connect
+ * @param[in] flags Indicate read/writeability of the socket
+ * @param[in] priv private data, "struct async_req *" in this case
+ */
+
+static void async_connect_callback(struct event_context *ev,
+ struct fd_event *fde, uint16_t flags,
+ void *priv)
+{
+ struct async_req *req = talloc_get_type_abort(
+ priv, struct async_req);
+ struct async_syscall_state *state = talloc_get_type_abort(
+ req->private_data, struct async_syscall_state);
+ struct param_connect *p = &state->param.param_connect;
+
+ SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_CONNECT);
+
+ TALLOC_FREE(state->fde);
+
+ /*
+ * Stevens, Network Programming says that if there's a
+ * successful connect, the socket is only writable. Upon an
+ * error, it's both readable and writable.
+ */
+ if ((flags & (EVENT_FD_READ|EVENT_FD_WRITE))
+ == (EVENT_FD_READ|EVENT_FD_WRITE)) {
+ int sockerr;
+ socklen_t err_len = sizeof(sockerr);
+
+ if (getsockopt(p->fd, SOL_SOCKET, SO_ERROR,
+ (void *)&sockerr, &err_len) == 0) {
+ errno = sockerr;
+ }
+
+ state->sys_errno = errno;
+
+ DEBUG(10, ("connect returned %s\n", strerror(errno)));
+
+ sys_fcntl_long(p->fd, F_SETFL, p->old_sockflags);
+
+ async_req_error(req, map_nt_error_from_unix(state->sys_errno));
+ return;
+ }
+
+ sys_fcntl_long(p->fd, F_SETFL, p->old_sockflags);
+
+ state->result.result_int = 0;
+ state->sys_errno = 0;
+
+ async_req_done(req);
+}
+
+/**
+ * @brief async version of connect(2)
+ * @param[in] mem_ctx The memory context to hang the result off
+ * @param[in] ev The event context to work from
+ * @param[in] fd The socket to recv from
+ * @param[in] address Where to connect?
+ * @param[in] address_len Length of *address
+ * @retval The async request
+ *
+ * This function sets the socket into non-blocking state to be able to call
+ * connect in an async state. This will be reset when the request is finished.
+ */
+
+struct async_req *async_connect(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ int fd, const struct sockaddr *address,
+ socklen_t address_len)
+{
+ struct async_req *result;
+ struct async_syscall_state *state;
+ struct param_connect *p;
+
+ result = async_syscall_new(mem_ctx, ev, ASYNC_SYSCALL_CONNECT, &state);
+ if (result == NULL) {
+ return NULL;
+ }
+ p = &state->param.param_connect;
+
+ /**
+ * We have to set the socket to nonblocking for async connect(2). Keep
+ * the old sockflags around.
+ */
+
+ p->old_sockflags = sys_fcntl_long(fd, F_GETFL, 0);
+
+ if (p->old_sockflags == -1) {
+ if (async_post_status(result, map_nt_error_from_unix(errno))) {
+ return result;
+ }
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ set_blocking(fd, true);
+
+ state->result.result_int = connect(fd, address, address_len);
+
+ if (state->result.result_int == 0) {
+ state->sys_errno = 0;
+ if (async_post_status(result, NT_STATUS_OK)) {
+ return result;
+ }
+ sys_fcntl_long(fd, F_SETFL, p->old_sockflags);
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ /**
+ * A number of error messages show that something good is progressing
+ * and that we have to wait for readability.
+ *
+ * If none of them are present, bail out.
+ */
+
+ if (!(errno == EINPROGRESS || errno == EALREADY ||
+#ifdef EISCONN
+ errno == EISCONN ||
+#endif
+ errno == EAGAIN || errno == EINTR)) {
+
+ state->sys_errno = errno;
+
+ if (async_post_status(result, map_nt_error_from_unix(errno))) {
+ return result;
+ }
+ sys_fcntl_long(fd, F_SETFL, p->old_sockflags);
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ state->fde = event_add_fd(ev, state, fd,
+ EVENT_FD_READ | EVENT_FD_WRITE,
+ async_connect_callback, state);
+ if (state->fde == NULL) {
+ sys_fcntl_long(fd, F_SETFL, p->old_sockflags);
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ state->param.param_connect.fd = fd;
+ state->param.param_connect.address = address;
+ state->param.param_connect.address_len = address_len;
+
+ return result;
+}
+
diff --git a/source3/lib/audit.c b/source3/lib/audit.c
new file mode 100644
index 0000000000..0eb12a95e6
--- /dev/null
+++ b/source3/lib/audit.c
@@ -0,0 +1,148 @@
+/*
+ Unix SMB/CIFS implementation.
+ Auditing helper functions.
+ Copyright (C) Guenther Deschner 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static const struct audit_category_tab {
+ uint32 category;
+ const char *category_str;
+ const char *param_str;
+ const char *description;
+} audit_category_tab [] = {
+ { LSA_AUDIT_CATEGORY_LOGON,
+ "LSA_AUDIT_CATEGORY_LOGON",
+ "LOGON", "Logon events" },
+ { LSA_AUDIT_CATEGORY_USE_OF_USER_RIGHTS,
+ "LSA_AUDIT_CATEGORY_USE_OF_USER_RIGHTS",
+ "PRIVILEGE", "Privilege Use" },
+ { LSA_AUDIT_CATEGORY_SYSTEM,
+ "LSA_AUDIT_CATEGORY_SYSTEM",
+ "SYSTEM", "System Events" },
+ { LSA_AUDIT_CATEGORY_SECURITY_POLICY_CHANGES,
+ "LSA_AUDIT_CATEGORY_SECURITY_POLICY_CHANGES",
+ "POLICY", "Policy Change" },
+ { LSA_AUDIT_CATEGORY_PROCCESS_TRACKING,
+ "LSA_AUDIT_CATEGORY_PROCCESS_TRACKING",
+ "PROCESS", "Process Tracking" },
+ { LSA_AUDIT_CATEGORY_FILE_AND_OBJECT_ACCESS,
+ "LSA_AUDIT_CATEGORY_FILE_AND_OBJECT_ACCESS",
+ "OBJECT", "Object Access" },
+ { LSA_AUDIT_CATEGORY_ACCOUNT_MANAGEMENT,
+ "LSA_AUDIT_CATEGORY_ACCOUNT_MANAGEMENT",
+ "SAM", "Account Management" },
+ { LSA_AUDIT_CATEGORY_DIRECTORY_SERVICE_ACCESS,
+ "LSA_AUDIT_CATEGORY_DIRECTORY_SERVICE_ACCESS",
+ "DIRECTORY", "Directory service access" },
+ { LSA_AUDIT_CATEGORY_ACCOUNT_LOGON,
+ "LSA_AUDIT_CATEGORY_ACCOUNT_LOGON",
+ "ACCOUNT", "Account logon events" },
+ { 0, NULL, NULL }
+};
+
+const char *audit_category_str(uint32 category)
+{
+ int i;
+ for (i=0; audit_category_tab[i].category_str; i++) {
+ if (category == audit_category_tab[i].category) {
+ return audit_category_tab[i].category_str;
+ }
+ }
+ return NULL;
+}
+
+const char *audit_param_str(uint32 category)
+{
+ int i;
+ for (i=0; audit_category_tab[i].param_str; i++) {
+ if (category == audit_category_tab[i].category) {
+ return audit_category_tab[i].param_str;
+ }
+ }
+ return NULL;
+}
+
+const char *audit_description_str(uint32 category)
+{
+ int i;
+ for (i=0; audit_category_tab[i].description; i++) {
+ if (category == audit_category_tab[i].category) {
+ return audit_category_tab[i].description;
+ }
+ }
+ return NULL;
+}
+
+bool get_audit_category_from_param(const char *param, uint32 *audit_category)
+{
+ *audit_category = Undefined;
+
+ if (strequal(param, "SYSTEM")) {
+ *audit_category = LSA_AUDIT_CATEGORY_SYSTEM;
+ } else if (strequal(param, "LOGON")) {
+ *audit_category = LSA_AUDIT_CATEGORY_LOGON;
+ } else if (strequal(param, "OBJECT")) {
+ *audit_category = LSA_AUDIT_CATEGORY_FILE_AND_OBJECT_ACCESS;
+ } else if (strequal(param, "PRIVILEGE")) {
+ *audit_category = LSA_AUDIT_CATEGORY_USE_OF_USER_RIGHTS;
+ } else if (strequal(param, "PROCESS")) {
+ *audit_category = LSA_AUDIT_CATEGORY_PROCCESS_TRACKING;
+ } else if (strequal(param, "POLICY")) {
+ *audit_category = LSA_AUDIT_CATEGORY_SECURITY_POLICY_CHANGES;
+ } else if (strequal(param, "SAM")) {
+ *audit_category = LSA_AUDIT_CATEGORY_ACCOUNT_MANAGEMENT;
+ } else if (strequal(param, "DIRECTORY")) {
+ *audit_category = LSA_AUDIT_CATEGORY_DIRECTORY_SERVICE_ACCESS;
+ } else if (strequal(param, "ACCOUNT")) {
+ *audit_category = LSA_AUDIT_CATEGORY_ACCOUNT_LOGON;
+ } else {
+ DEBUG(0,("unknown parameter: %s\n", param));
+ return False;
+ }
+
+ return True;
+}
+
+const char *audit_policy_str(TALLOC_CTX *mem_ctx, uint32 policy)
+{
+ const char *ret = NULL;
+
+ if (policy == LSA_AUDIT_POLICY_NONE) {
+ return talloc_strdup(mem_ctx, "None");
+ }
+
+ if (policy & LSA_AUDIT_POLICY_SUCCESS) {
+ ret = talloc_strdup(mem_ctx, "Success");
+ if (ret == NULL) {
+ return NULL;
+ }
+ }
+
+ if (policy & LSA_AUDIT_POLICY_FAILURE) {
+ if (ret) {
+ ret = talloc_asprintf(mem_ctx, "%s, %s", ret, "Failure");
+ if (ret == NULL) {
+ return NULL;
+ }
+ } else {
+ return talloc_strdup(mem_ctx, "Failure");
+ }
+ }
+
+ return ret;
+}
diff --git a/source3/lib/bitmap.c b/source3/lib/bitmap.c
new file mode 100644
index 0000000000..5e623f474a
--- /dev/null
+++ b/source3/lib/bitmap.c
@@ -0,0 +1,176 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* these functions provide a simple way to allocate integers from a
+ pool without repetition */
+
+/****************************************************************************
+allocate a bitmap of the specified size
+****************************************************************************/
+struct bitmap *bitmap_allocate(int n)
+{
+ struct bitmap *bm;
+
+ bm = SMB_MALLOC_P(struct bitmap);
+
+ if (!bm) return NULL;
+
+ bm->n = n;
+ bm->b = SMB_MALLOC_ARRAY(uint32, (n+31)/32);
+ if (!bm->b) {
+ SAFE_FREE(bm);
+ return NULL;
+ }
+
+ memset(bm->b, 0, sizeof(uint32)*((n+31)/32));
+
+ return bm;
+}
+
+/****************************************************************************
+free a bitmap.
+****************************************************************************/
+
+void bitmap_free(struct bitmap *bm)
+{
+ if (!bm)
+ return;
+
+ SAFE_FREE(bm->b);
+ SAFE_FREE(bm);
+}
+
+/****************************************************************************
+talloc a bitmap
+****************************************************************************/
+struct bitmap *bitmap_talloc(TALLOC_CTX *mem_ctx, int n)
+{
+ struct bitmap *bm;
+
+ if (!mem_ctx) return NULL;
+
+ bm = TALLOC_P(mem_ctx, struct bitmap);
+
+ if (!bm) return NULL;
+
+ bm->n = n;
+ bm->b = TALLOC_ARRAY(mem_ctx, uint32, (n+31)/32);
+ if (!bm->b) {
+ return NULL;
+ }
+
+ memset(bm->b, 0, sizeof(uint32)*((n+31)/32));
+
+ return bm;
+}
+
+/****************************************************************************
+copy as much of the source bitmap as will fit in the destination bitmap.
+****************************************************************************/
+
+int bitmap_copy(struct bitmap * const dst, const struct bitmap * const src)
+{
+ int count = MIN(dst->n, src->n);
+
+ SMB_ASSERT(dst->b != src->b);
+ memcpy(dst->b, src->b, sizeof(uint32)*((count+31)/32));
+
+ return count;
+}
+
+/****************************************************************************
+set a bit in a bitmap
+****************************************************************************/
+bool bitmap_set(struct bitmap *bm, unsigned i)
+{
+ if (i >= bm->n) {
+ DEBUG(0,("Setting invalid bitmap entry %d (of %d)\n",
+ i, bm->n));
+ return False;
+ }
+ bm->b[i/32] |= (1<<(i%32));
+ return True;
+}
+
+/****************************************************************************
+clear a bit in a bitmap
+****************************************************************************/
+bool bitmap_clear(struct bitmap *bm, unsigned i)
+{
+ if (i >= bm->n) {
+ DEBUG(0,("clearing invalid bitmap entry %d (of %d)\n",
+ i, bm->n));
+ return False;
+ }
+ bm->b[i/32] &= ~(1<<(i%32));
+ return True;
+}
+
+/****************************************************************************
+query a bit in a bitmap
+****************************************************************************/
+bool bitmap_query(struct bitmap *bm, unsigned i)
+{
+ if (i >= bm->n) return False;
+ if (bm->b[i/32] & (1<<(i%32))) {
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************************
+find a zero bit in a bitmap starting at the specified offset, with
+wraparound
+****************************************************************************/
+int bitmap_find(struct bitmap *bm, unsigned ofs)
+{
+ unsigned 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/source3/lib/charcnv.c b/source3/lib/charcnv.c
new file mode 100644
index 0000000000..485212b100
--- /dev/null
+++ b/source3/lib/charcnv.c
@@ -0,0 +1,1937 @@
+/*
+ Unix SMB/CIFS implementation.
+ Character set conversion Extensions
+ Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Martin Pool 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+#include "includes.h"
+
+/* We can parameterize this if someone complains.... JRA. */
+
+char lp_failed_convert_char(void)
+{
+ return '_';
+}
+
+/**
+ * @file
+ *
+ * @brief Character-set conversion routines built on our iconv.
+ *
+ * @note Samba's internal character set (at least in the 3.0 series)
+ * is always the same as the one for the Unix filesystem. It is
+ * <b>not</b> necessarily UTF-8 and may be different on machines that
+ * need i18n filenames to be compatible with Unix software. It does
+ * have to be a superset of ASCII. All multibyte sequences must start
+ * with a byte with the high bit set.
+ *
+ * @sa lib/iconv.c
+ */
+
+
+static smb_iconv_t conv_handles[NUM_CHARSETS][NUM_CHARSETS];
+static bool conv_silent; /* Should we do a debug if the conversion fails ? */
+static bool initialized;
+
+/**
+ * Return the name of a charset to give to iconv().
+ **/
+static const char *charset_name(charset_t ch)
+{
+ const char *ret = NULL;
+
+ if (ch == CH_UTF16LE) ret = "UTF-16LE";
+ else if (ch == CH_UTF16BE) ret = "UTF-16BE";
+ else if (ch == CH_UNIX) ret = lp_unix_charset();
+ else if (ch == CH_DOS) ret = lp_dos_charset();
+ else if (ch == CH_DISPLAY) ret = lp_display_charset();
+ else if (ch == CH_UTF8) ret = "UTF8";
+
+#if defined(HAVE_NL_LANGINFO) && defined(CODESET)
+ if (ret && !strcmp(ret, "LOCALE")) {
+ const char *ln = NULL;
+
+#ifdef HAVE_SETLOCALE
+ setlocale(LC_ALL, "");
+#endif
+ ln = nl_langinfo(CODESET);
+ if (ln) {
+ /* Check whether the charset name is supported
+ by iconv */
+ smb_iconv_t handle = smb_iconv_open(ln,"UCS-2LE");
+ if (handle == (smb_iconv_t) -1) {
+ DEBUG(5,("Locale charset '%s' unsupported, using ASCII instead\n", ln));
+ ln = NULL;
+ } else {
+ DEBUG(5,("Substituting charset '%s' for LOCALE\n", ln));
+ smb_iconv_close(handle);
+ }
+ }
+ ret = ln;
+ }
+#endif
+
+ if (!ret || !*ret) ret = "ASCII";
+ return ret;
+}
+
+void lazy_initialize_conv(void)
+{
+ if (!initialized) {
+ load_case_tables();
+ init_iconv();
+ initialized = true;
+ }
+}
+
+/**
+ * Destroy global objects allocated by init_iconv()
+ **/
+void gfree_charcnv(void)
+{
+ int c1, c2;
+
+ for (c1=0;c1<NUM_CHARSETS;c1++) {
+ for (c2=0;c2<NUM_CHARSETS;c2++) {
+ if ( conv_handles[c1][c2] ) {
+ smb_iconv_close( conv_handles[c1][c2] );
+ conv_handles[c1][c2] = 0;
+ }
+ }
+ }
+ initialized = false;
+}
+
+/**
+ * Initialize iconv conversion descriptors.
+ *
+ * This is called the first time it is needed, and also called again
+ * every time the configuration is reloaded, because the charset or
+ * codepage might have changed.
+ **/
+void init_iconv(void)
+{
+ int c1, c2;
+ bool did_reload = False;
+
+ /* so that charset_name() works we need to get the UNIX<->UCS2 going
+ first */
+ if (!conv_handles[CH_UNIX][CH_UTF16LE])
+ conv_handles[CH_UNIX][CH_UTF16LE] = smb_iconv_open(charset_name(CH_UTF16LE), "ASCII");
+
+ if (!conv_handles[CH_UTF16LE][CH_UNIX])
+ conv_handles[CH_UTF16LE][CH_UNIX] = smb_iconv_open("ASCII", charset_name(CH_UTF16LE));
+
+ for (c1=0;c1<NUM_CHARSETS;c1++) {
+ for (c2=0;c2<NUM_CHARSETS;c2++) {
+ const char *n1 = charset_name((charset_t)c1);
+ const char *n2 = charset_name((charset_t)c2);
+ if (conv_handles[c1][c2] &&
+ strcmp(n1, conv_handles[c1][c2]->from_name) == 0 &&
+ strcmp(n2, conv_handles[c1][c2]->to_name) == 0)
+ continue;
+
+ did_reload = True;
+
+ if (conv_handles[c1][c2])
+ smb_iconv_close(conv_handles[c1][c2]);
+
+ conv_handles[c1][c2] = smb_iconv_open(n2,n1);
+ if (conv_handles[c1][c2] == (smb_iconv_t)-1) {
+ DEBUG(0,("init_iconv: Conversion from %s to %s not supported\n",
+ charset_name((charset_t)c1), charset_name((charset_t)c2)));
+ if (c1 != CH_UTF16LE && c1 != CH_UTF16BE) {
+ n1 = "ASCII";
+ }
+ if (c2 != CH_UTF16LE && c2 != CH_UTF16BE) {
+ n2 = "ASCII";
+ }
+ DEBUG(0,("init_iconv: Attempting to replace with conversion from %s to %s\n",
+ n1, n2 ));
+ conv_handles[c1][c2] = smb_iconv_open(n2,n1);
+ if (!conv_handles[c1][c2]) {
+ DEBUG(0,("init_iconv: Conversion from %s to %s failed", n1, n2));
+ smb_panic("init_iconv: conv_handle initialization failed");
+ }
+ }
+ }
+ }
+
+ if (did_reload) {
+ /* XXX: Does this really get called every time the dos
+ * codepage changes? */
+ /* XXX: Is the did_reload test too strict? */
+ conv_silent = True;
+ init_valid_table();
+ conv_silent = False;
+ }
+}
+
+/**
+ * Convert string from one encoding to another, making error checking etc
+ * Slow path version - uses (slow) iconv.
+ *
+ * @param src pointer to source string (multibyte or singlebyte)
+ * @param srclen length of the source string in bytes
+ * @param dest pointer to destination string (multibyte or singlebyte)
+ * @param destlen maximal length allowed for string
+ * @param allow_bad_conv determines if a "best effort" conversion is acceptable (never returns errors)
+ * @returns the number of bytes occupied in the destination
+ *
+ * Ensure the srclen contains the terminating zero.
+ *
+ **/
+
+static size_t convert_string_internal(charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t destlen, bool allow_bad_conv)
+{
+ size_t i_len, o_len;
+ size_t retval;
+ const char* inbuf = (const char*)src;
+ char* outbuf = (char*)dest;
+ smb_iconv_t descriptor;
+
+ lazy_initialize_conv();
+
+ descriptor = conv_handles[from][to];
+
+ if (srclen == (size_t)-1) {
+ if (from == CH_UTF16LE || from == CH_UTF16BE) {
+ srclen = (strlen_w((const smb_ucs2_t *)src)+1) * 2;
+ } else {
+ srclen = strlen((const char *)src)+1;
+ }
+ }
+
+
+ if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
+ if (!conv_silent)
+ DEBUG(0,("convert_string_internal: Conversion not supported.\n"));
+ return (size_t)-1;
+ }
+
+ i_len=srclen;
+ o_len=destlen;
+
+ again:
+
+ retval = smb_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len);
+ if(retval==(size_t)-1) {
+ const char *reason="unknown error";
+ switch(errno) {
+ case EINVAL:
+ reason="Incomplete multibyte sequence";
+ if (!conv_silent)
+ DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
+ if (allow_bad_conv)
+ goto use_as_is;
+ break;
+ case E2BIG:
+ reason="No more room";
+ if (!conv_silent) {
+ if (from == CH_UNIX) {
+ DEBUG(3,("E2BIG: convert_string(%s,%s): srclen=%u destlen=%u - '%s'\n",
+ charset_name(from), charset_name(to),
+ (unsigned int)srclen, (unsigned int)destlen, (const char *)src));
+ } else {
+ DEBUG(3,("E2BIG: convert_string(%s,%s): srclen=%u destlen=%u\n",
+ charset_name(from), charset_name(to),
+ (unsigned int)srclen, (unsigned int)destlen));
+ }
+ }
+ break;
+ case EILSEQ:
+ reason="Illegal multibyte sequence";
+ if (!conv_silent)
+ DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
+ if (allow_bad_conv)
+ goto use_as_is;
+ break;
+ default:
+ if (!conv_silent)
+ DEBUG(0,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
+ break;
+ }
+ /* smb_panic(reason); */
+ }
+ return destlen-o_len;
+
+ use_as_is:
+
+ /*
+ * Conversion not supported. This is actually an error, but there are so
+ * many misconfigured iconv systems and smb.conf's out there we can't just
+ * fail. Do a very bad conversion instead.... JRA.
+ */
+
+ {
+ if (o_len == 0 || i_len == 0)
+ return destlen - o_len;
+
+ if (((from == CH_UTF16LE)||(from == CH_UTF16BE)) &&
+ ((to != CH_UTF16LE)||(to != CH_UTF16BE))) {
+ /* Can't convert from utf16 any endian to multibyte.
+ Replace with the default fail char.
+ */
+ if (i_len < 2)
+ return destlen - o_len;
+ if (i_len >= 2) {
+ *outbuf = lp_failed_convert_char();
+
+ outbuf++;
+ o_len--;
+
+ inbuf += 2;
+ i_len -= 2;
+ }
+
+ if (o_len == 0 || i_len == 0)
+ return destlen - o_len;
+
+ /* Keep trying with the next char... */
+ goto again;
+
+ } else if (from != CH_UTF16LE && from != CH_UTF16BE && to == CH_UTF16LE) {
+ /* Can't convert to UTF16LE - just widen by adding the
+ default fail char then zero.
+ */
+ if (o_len < 2)
+ return destlen - o_len;
+
+ outbuf[0] = lp_failed_convert_char();
+ outbuf[1] = '\0';
+
+ inbuf++;
+ i_len--;
+
+ outbuf += 2;
+ o_len -= 2;
+
+ if (o_len == 0 || i_len == 0)
+ return destlen - o_len;
+
+ /* Keep trying with the next char... */
+ goto again;
+
+ } else if (from != CH_UTF16LE && from != CH_UTF16BE &&
+ to != CH_UTF16LE && to != CH_UTF16BE) {
+ /* Failed multibyte to multibyte. Just copy the default fail char and
+ try again. */
+ outbuf[0] = lp_failed_convert_char();
+
+ inbuf++;
+ i_len--;
+
+ outbuf++;
+ o_len--;
+
+ if (o_len == 0 || i_len == 0)
+ return destlen - o_len;
+
+ /* Keep trying with the next char... */
+ goto again;
+
+ } else {
+ /* Keep compiler happy.... */
+ return destlen - o_len;
+ }
+ }
+}
+
+/**
+ * Convert string from one encoding to another, making error checking etc
+ * Fast path version - handles ASCII first.
+ *
+ * @param src pointer to source string (multibyte or singlebyte)
+ * @param srclen length of the source string in bytes, or -1 for nul terminated.
+ * @param dest pointer to destination string (multibyte or singlebyte)
+ * @param destlen maximal length allowed for string - *NEVER* -1.
+ * @param allow_bad_conv determines if a "best effort" conversion is acceptable (never returns errors)
+ * @returns the number of bytes occupied in the destination
+ *
+ * Ensure the srclen contains the terminating zero.
+ *
+ * This function has been hand-tuned to provide a fast path.
+ * Don't change unless you really know what you are doing. JRA.
+ **/
+
+size_t convert_string(charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t destlen, bool allow_bad_conv)
+{
+ /*
+ * NB. We deliberately don't do a strlen here if srclen == -1.
+ * This is very expensive over millions of calls and is taken
+ * care of in the slow path in convert_string_internal. JRA.
+ */
+
+#ifdef DEVELOPER
+ SMB_ASSERT(destlen != (size_t)-1);
+#endif
+
+ if (srclen == 0)
+ return 0;
+
+ if (from != CH_UTF16LE && from != CH_UTF16BE && to != CH_UTF16LE && to != CH_UTF16BE) {
+ const unsigned char *p = (const unsigned char *)src;
+ unsigned char *q = (unsigned char *)dest;
+ size_t slen = srclen;
+ size_t dlen = destlen;
+ unsigned char lastp = '\0';
+ size_t retval = 0;
+
+ /* If all characters are ascii, fast path here. */
+ while (slen && dlen) {
+ if ((lastp = *p) <= 0x7f) {
+ *q++ = *p++;
+ if (slen != (size_t)-1) {
+ slen--;
+ }
+ dlen--;
+ retval++;
+ if (!lastp)
+ break;
+ } else {
+#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
+ goto general_case;
+#else
+ return retval + convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
+#endif
+ }
+ }
+ if (!dlen) {
+ /* Even if we fast path we should note if we ran out of room. */
+ if (((slen != (size_t)-1) && slen) ||
+ ((slen == (size_t)-1) && lastp)) {
+ errno = E2BIG;
+ }
+ }
+ return retval;
+ } else if (from == CH_UTF16LE && to != CH_UTF16LE) {
+ const unsigned char *p = (const unsigned char *)src;
+ unsigned char *q = (unsigned char *)dest;
+ size_t retval = 0;
+ size_t slen = srclen;
+ size_t dlen = destlen;
+ unsigned char lastp = '\0';
+
+ /* If all characters are ascii, fast path here. */
+ while (((slen == (size_t)-1) || (slen >= 2)) && dlen) {
+ if (((lastp = *p) <= 0x7f) && (p[1] == 0)) {
+ *q++ = *p;
+ if (slen != (size_t)-1) {
+ slen -= 2;
+ }
+ p += 2;
+ dlen--;
+ retval++;
+ if (!lastp)
+ break;
+ } else {
+#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
+ goto general_case;
+#else
+ return retval + convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
+#endif
+ }
+ }
+ if (!dlen) {
+ /* Even if we fast path we should note if we ran out of room. */
+ if (((slen != (size_t)-1) && slen) ||
+ ((slen == (size_t)-1) && lastp)) {
+ errno = E2BIG;
+ }
+ }
+ return retval;
+ } else if (from != CH_UTF16LE && from != CH_UTF16BE && to == CH_UTF16LE) {
+ const unsigned char *p = (const unsigned char *)src;
+ unsigned char *q = (unsigned char *)dest;
+ size_t retval = 0;
+ size_t slen = srclen;
+ size_t dlen = destlen;
+ unsigned char lastp = '\0';
+
+ /* If all characters are ascii, fast path here. */
+ while (slen && (dlen >= 2)) {
+ if ((lastp = *p) <= 0x7F) {
+ *q++ = *p++;
+ *q++ = '\0';
+ if (slen != (size_t)-1) {
+ slen--;
+ }
+ dlen -= 2;
+ retval += 2;
+ if (!lastp)
+ break;
+ } else {
+#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
+ goto general_case;
+#else
+ return retval + convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
+#endif
+ }
+ }
+ if (!dlen) {
+ /* Even if we fast path we should note if we ran out of room. */
+ if (((slen != (size_t)-1) && slen) ||
+ ((slen == (size_t)-1) && lastp)) {
+ errno = E2BIG;
+ }
+ }
+ return retval;
+ }
+
+#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
+ general_case:
+#endif
+ return convert_string_internal(from, to, src, srclen, dest, destlen, allow_bad_conv);
+}
+
+/**
+ * Convert between character sets, allocating a new buffer for the result.
+ *
+ * @param ctx TALLOC_CTX to use to allocate with. If NULL use malloc.
+ * (this is a bad interface and needs fixing. JRA).
+ * @param srclen length of source buffer.
+ * @param dest always set at least to NULL
+ * @param converted_size set to the size of the allocated buffer on return
+ * true
+ * @note -1 is not accepted for srclen.
+ *
+ * @return true if new buffer was correctly allocated, and string was
+ * converted.
+ *
+ * Ensure the srclen contains the terminating zero.
+ *
+ * I hate the goto's in this function. It's embarressing.....
+ * There has to be a cleaner way to do this. JRA.
+ **/
+
+bool convert_string_allocate(TALLOC_CTX *ctx, charset_t from, charset_t to,
+ void const *src, size_t srclen, void *dst,
+ size_t *converted_size, bool allow_bad_conv)
+{
+ size_t i_len, o_len, destlen = (srclen * 3) / 2;
+ size_t retval;
+ const char *inbuf = (const char *)src;
+ char *outbuf = NULL, *ob = NULL;
+ smb_iconv_t descriptor;
+ void **dest = (void **)dst;
+
+ *dest = NULL;
+
+ if (!converted_size) {
+ errno = EINVAL;
+ return false;
+ }
+
+ if (src == NULL || srclen == (size_t)-1) {
+ errno = EINVAL;
+ return false;
+ }
+ if (srclen == 0) {
+ *converted_size = 0;
+ return true;
+ }
+
+ lazy_initialize_conv();
+
+ descriptor = conv_handles[from][to];
+
+ if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
+ if (!conv_silent)
+ DEBUG(0,("convert_string_allocate: Conversion not supported.\n"));
+ errno = EOPNOTSUPP;
+ return false;
+ }
+
+ convert:
+
+ /* +2 is for ucs2 null termination. */
+ if ((destlen*2)+2 < destlen) {
+ /* wrapped ! abort. */
+ if (!conv_silent)
+ DEBUG(0, ("convert_string_allocate: destlen wrapped !\n"));
+ if (!ctx)
+ SAFE_FREE(outbuf);
+ errno = EOPNOTSUPP;
+ return false;
+ } else {
+ destlen = destlen * 2;
+ }
+
+ /* +2 is for ucs2 null termination. */
+ if (ctx) {
+ ob = (char *)TALLOC_REALLOC(ctx, ob, destlen + 2);
+ } else {
+ ob = (char *)SMB_REALLOC(ob, destlen + 2);
+ }
+
+ if (!ob) {
+ DEBUG(0, ("convert_string_allocate: realloc failed!\n"));
+ errno = ENOMEM;
+ return false;
+ }
+ outbuf = ob;
+ i_len = srclen;
+ o_len = destlen;
+
+ again:
+
+ retval = smb_iconv(descriptor,
+ &inbuf, &i_len,
+ &outbuf, &o_len);
+ if(retval == (size_t)-1) {
+ const char *reason="unknown error";
+ switch(errno) {
+ case EINVAL:
+ reason="Incomplete multibyte sequence";
+ if (!conv_silent)
+ DEBUG(3,("convert_string_allocate: Conversion error: %s(%s)\n",reason,inbuf));
+ if (allow_bad_conv)
+ goto use_as_is;
+ break;
+ case E2BIG:
+ goto convert;
+ case EILSEQ:
+ reason="Illegal multibyte sequence";
+ if (!conv_silent)
+ DEBUG(3,("convert_string_allocate: Conversion error: %s(%s)\n",reason,inbuf));
+ if (allow_bad_conv)
+ goto use_as_is;
+ break;
+ }
+ if (!conv_silent)
+ DEBUG(0,("Conversion error: %s(%s)\n",reason,inbuf));
+ /* smb_panic(reason); */
+ if (ctx) {
+ TALLOC_FREE(ob);
+ } else {
+ SAFE_FREE(ob);
+ }
+ return false;
+ }
+
+ out:
+
+ destlen = destlen - o_len;
+ /* Don't shrink unless we're reclaiming a lot of
+ * space. This is in the hot codepath and these
+ * reallocs *cost*. JRA.
+ */
+ if (o_len > 1024) {
+ /* We're shrinking here so we know the +2 is safe from wrap. */
+ if (ctx) {
+ ob = (char *)TALLOC_REALLOC(ctx,ob,destlen + 2);
+ } else {
+ ob = (char *)SMB_REALLOC(ob,destlen + 2);
+ }
+ }
+
+ if (destlen && !ob) {
+ DEBUG(0, ("convert_string_allocate: out of memory!\n"));
+ errno = ENOMEM;
+ return false;
+ }
+
+ *dest = ob;
+
+ /* Must ucs2 null terminate in the extra space we allocated. */
+ ob[destlen] = '\0';
+ ob[destlen+1] = '\0';
+
+ *converted_size = destlen;
+ return true;
+
+ use_as_is:
+
+ /*
+ * Conversion not supported. This is actually an error, but there are so
+ * many misconfigured iconv systems and smb.conf's out there we can't just
+ * fail. Do a very bad conversion instead.... JRA.
+ */
+
+ {
+ if (o_len == 0 || i_len == 0)
+ goto out;
+
+ if (((from == CH_UTF16LE)||(from == CH_UTF16BE)) &&
+ ((to != CH_UTF16LE)||(to != CH_UTF16BE))) {
+ /* Can't convert from utf16 any endian to multibyte.
+ Replace with the default fail char.
+ */
+
+ if (i_len < 2)
+ goto out;
+
+ if (i_len >= 2) {
+ *outbuf = lp_failed_convert_char();
+
+ outbuf++;
+ o_len--;
+
+ inbuf += 2;
+ i_len -= 2;
+ }
+
+ if (o_len == 0 || i_len == 0)
+ goto out;
+
+ /* Keep trying with the next char... */
+ goto again;
+
+ } else if (from != CH_UTF16LE && from != CH_UTF16BE && to == CH_UTF16LE) {
+ /* Can't convert to UTF16LE - just widen by adding the
+ default fail char then zero.
+ */
+ if (o_len < 2)
+ goto out;
+
+ outbuf[0] = lp_failed_convert_char();
+ outbuf[1] = '\0';
+
+ inbuf++;
+ i_len--;
+
+ outbuf += 2;
+ o_len -= 2;
+
+ if (o_len == 0 || i_len == 0)
+ goto out;
+
+ /* Keep trying with the next char... */
+ goto again;
+
+ } else if (from != CH_UTF16LE && from != CH_UTF16BE &&
+ to != CH_UTF16LE && to != CH_UTF16BE) {
+ /* Failed multibyte to multibyte. Just copy the default fail char and
+ try again. */
+ outbuf[0] = lp_failed_convert_char();
+
+ inbuf++;
+ i_len--;
+
+ outbuf++;
+ o_len--;
+
+ if (o_len == 0 || i_len == 0)
+ goto out;
+
+ /* Keep trying with the next char... */
+ goto again;
+
+ } else {
+ /* Keep compiler happy.... */
+ goto out;
+ }
+ }
+}
+
+/**
+ * Convert between character sets, allocating a new buffer using talloc for the result.
+ *
+ * @param srclen length of source buffer.
+ * @param dest always set at least to NULL
+ * @parm converted_size set to the number of bytes occupied by the string in
+ * the destination on success.
+ * @note -1 is not accepted for srclen.
+ *
+ * @return true if new buffer was correctly allocated, and string was
+ * converted.
+ */
+bool convert_string_talloc(TALLOC_CTX *ctx, charset_t from, charset_t to,
+ void const *src, size_t srclen, void *dst,
+ size_t *converted_size, bool allow_bad_conv)
+{
+ void **dest = (void **)dst;
+
+ *dest = NULL;
+ return convert_string_allocate(ctx, from, to, src, srclen, dest,
+ converted_size, allow_bad_conv);
+}
+
+size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
+{
+ size_t size;
+ smb_ucs2_t *buffer;
+
+ if (!push_ucs2_allocate(&buffer, src, &size)) {
+ return (size_t)-1;
+ }
+
+ if (!strupper_w(buffer) && (dest == src)) {
+ free(buffer);
+ return srclen;
+ }
+
+ size = convert_string(CH_UTF16LE, CH_UNIX, buffer, size, dest, destlen, True);
+ free(buffer);
+ return size;
+}
+
+/**
+ strdup() a unix string to upper case.
+**/
+
+char *strdup_upper(const char *s)
+{
+ char *out_buffer = SMB_STRDUP(s);
+ const unsigned char *p = (const unsigned char *)s;
+ unsigned char *q = (unsigned char *)out_buffer;
+
+ if (!q) {
+ return NULL;
+ }
+
+ /* this is quite a common operation, so we want it to be
+ fast. We optimise for the ascii case, knowing that all our
+ supported multi-byte character sets are ascii-compatible
+ (ie. they match for the first 128 chars) */
+
+ while (*p) {
+ if (*p & 0x80)
+ break;
+ *q++ = toupper_ascii_fast(*p);
+ p++;
+ }
+
+ if (*p) {
+ /* MB case. */
+ size_t converted_size, converted_size2;
+ smb_ucs2_t *buffer = NULL;
+
+ SAFE_FREE(out_buffer);
+ if (!convert_string_allocate(NULL, CH_UNIX, CH_UTF16LE, s,
+ strlen(s) + 1,
+ (void **)(void *)&buffer,
+ &converted_size, True))
+ {
+ return NULL;
+ }
+
+ strupper_w(buffer);
+
+ if (!convert_string_allocate(NULL, CH_UTF16LE, CH_UNIX, buffer,
+ converted_size,
+ (void **)(void *)&out_buffer,
+ &converted_size2, True))
+ {
+ TALLOC_FREE(buffer);
+ return NULL;
+ }
+
+ /* Don't need the intermediate buffer
+ * anymore.
+ */
+ TALLOC_FREE(buffer);
+ }
+
+ return out_buffer;
+}
+
+/**
+ talloc_strdup() a unix string to upper case.
+**/
+
+char *talloc_strdup_upper(TALLOC_CTX *ctx, const char *s)
+{
+ char *out_buffer = talloc_strdup(ctx,s);
+ const unsigned char *p = (const unsigned char *)s;
+ unsigned char *q = (unsigned char *)out_buffer;
+
+ if (!q) {
+ return NULL;
+ }
+
+ /* this is quite a common operation, so we want it to be
+ fast. We optimise for the ascii case, knowing that all our
+ supported multi-byte character sets are ascii-compatible
+ (ie. they match for the first 128 chars) */
+
+ while (*p) {
+ if (*p & 0x80)
+ break;
+ *q++ = toupper_ascii_fast(*p);
+ p++;
+ }
+
+ if (*p) {
+ /* MB case. */
+ size_t converted_size, converted_size2;
+ smb_ucs2_t *ubuf = NULL;
+
+ /* We're not using the ascii buffer above. */
+ TALLOC_FREE(out_buffer);
+
+ if (!convert_string_talloc(ctx, CH_UNIX, CH_UTF16LE, s,
+ strlen(s)+1, (void *)&ubuf,
+ &converted_size, True))
+ {
+ return NULL;
+ }
+
+ strupper_w(ubuf);
+
+ if (!convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX, ubuf,
+ converted_size, (void *)&out_buffer,
+ &converted_size2, True))
+ {
+ TALLOC_FREE(ubuf);
+ return NULL;
+ }
+
+ /* Don't need the intermediate buffer
+ * anymore.
+ */
+ TALLOC_FREE(ubuf);
+ }
+
+ return out_buffer;
+}
+
+size_t unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
+{
+ size_t size;
+ smb_ucs2_t *buffer = NULL;
+
+ if (!convert_string_allocate(NULL, CH_UNIX, CH_UTF16LE, src, srclen,
+ (void **)(void *)&buffer, &size,
+ True))
+ {
+ smb_panic("failed to create UCS2 buffer");
+ }
+ if (!strlower_w(buffer) && (dest == src)) {
+ SAFE_FREE(buffer);
+ return srclen;
+ }
+ size = convert_string(CH_UTF16LE, CH_UNIX, buffer, size, dest, destlen, True);
+ SAFE_FREE(buffer);
+ return size;
+}
+
+/**
+ strdup() a unix string to lower case.
+**/
+
+char *strdup_lower(const char *s)
+{
+ size_t converted_size;
+ smb_ucs2_t *buffer = NULL;
+ char *out_buffer;
+
+ if (!push_ucs2_allocate(&buffer, s, &converted_size)) {
+ return NULL;
+ }
+
+ strlower_w(buffer);
+
+ if (!pull_ucs2_allocate(&out_buffer, buffer, &converted_size)) {
+ SAFE_FREE(buffer);
+ return NULL;
+ }
+
+ SAFE_FREE(buffer);
+
+ return out_buffer;
+}
+
+char *talloc_strdup_lower(TALLOC_CTX *ctx, const char *s)
+{
+ size_t converted_size;
+ smb_ucs2_t *buffer = NULL;
+ char *out_buffer;
+
+ if (!push_ucs2_talloc(ctx, &buffer, s, &converted_size)) {
+ return NULL;
+ }
+
+ strlower_w(buffer);
+
+ if (!pull_ucs2_talloc(ctx, &out_buffer, buffer, &converted_size)) {
+ TALLOC_FREE(buffer);
+ return NULL;
+ }
+
+ TALLOC_FREE(buffer);
+
+ return out_buffer;
+}
+
+
+size_t ucs2_align(const void *base_ptr, const void *p, int flags)
+{
+ if (flags & (STR_NOALIGN|STR_ASCII))
+ return 0;
+ return PTR_DIFF(p, base_ptr) & 1;
+}
+
+
+/**
+ * Copy a string from a char* unix src to a dos codepage string destination.
+ *
+ * @return the number of bytes occupied by the string in the destination.
+ *
+ * @param flags can include
+ * <dl>
+ * <dt>STR_TERMINATE</dt> <dd>means include the null termination</dd>
+ * <dt>STR_UPPER</dt> <dd>means uppercase in the destination</dd>
+ * </dl>
+ *
+ * @param dest_len the maximum length in bytes allowed in the
+ * destination.
+ **/
+size_t push_ascii(void *dest, const char *src, size_t dest_len, int flags)
+{
+ size_t src_len = strlen(src);
+ char *tmpbuf = NULL;
+ size_t ret;
+
+ /* No longer allow a length of -1. */
+ if (dest_len == (size_t)-1) {
+ smb_panic("push_ascii - dest_len == -1");
+ }
+
+ if (flags & STR_UPPER) {
+ tmpbuf = SMB_STRDUP(src);
+ if (!tmpbuf) {
+ smb_panic("malloc fail");
+ }
+ strupper_m(tmpbuf);
+ src = tmpbuf;
+ }
+
+ if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII)) {
+ src_len++;
+ }
+
+ ret = convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len, True);
+ if (ret == (size_t)-1 &&
+ (flags & (STR_TERMINATE | STR_TERMINATE_ASCII))
+ && dest_len > 0) {
+ ((char *)dest)[0] = '\0';
+ }
+ SAFE_FREE(tmpbuf);
+ return ret;
+}
+
+size_t push_ascii_fstring(void *dest, const char *src)
+{
+ return push_ascii(dest, src, sizeof(fstring), STR_TERMINATE);
+}
+
+/********************************************************************
+ Push an nstring - ensure null terminated. Written by
+ moriyama@miraclelinux.com (MORIYAMA Masayuki).
+********************************************************************/
+
+size_t push_ascii_nstring(void *dest, const char *src)
+{
+ size_t i, buffer_len, dest_len;
+ smb_ucs2_t *buffer;
+
+ conv_silent = True;
+ if (!push_ucs2_allocate(&buffer, src, &buffer_len)) {
+ smb_panic("failed to create UCS2 buffer");
+ }
+
+ /* We're using buffer_len below to count ucs2 characters, not bytes. */
+ buffer_len /= sizeof(smb_ucs2_t);
+
+ dest_len = 0;
+ for (i = 0; buffer[i] != 0 && (i < buffer_len); i++) {
+ unsigned char mb[10];
+ /* Convert one smb_ucs2_t character at a time. */
+ size_t mb_len = convert_string(CH_UTF16LE, CH_DOS, buffer+i, sizeof(smb_ucs2_t), mb, sizeof(mb), False);
+ if ((mb_len != (size_t)-1) && (dest_len + mb_len <= MAX_NETBIOSNAME_LEN - 1)) {
+ memcpy((char *)dest + dest_len, mb, mb_len);
+ dest_len += mb_len;
+ } else {
+ errno = E2BIG;
+ break;
+ }
+ }
+ ((char *)dest)[dest_len] = '\0';
+
+ SAFE_FREE(buffer);
+ conv_silent = False;
+ return dest_len;
+}
+
+/********************************************************************
+ Push and malloc an ascii string. src and dest null terminated.
+********************************************************************/
+
+bool push_ascii_allocate(char **dest, const char *src, size_t *converted_size)
+{
+ size_t src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_allocate(NULL, CH_UNIX, CH_DOS, src, src_len,
+ (void **)dest, converted_size, True);
+}
+
+/**
+ * Copy a string from a dos codepage source to a unix char* destination.
+ *
+ * The resulting string in "dest" is always null terminated.
+ *
+ * @param flags can have:
+ * <dl>
+ * <dt>STR_TERMINATE</dt>
+ * <dd>STR_TERMINATE means the string in @p src
+ * is null terminated, and src_len is ignored.</dd>
+ * </dl>
+ *
+ * @param src_len is the length of the source area in bytes.
+ * @returns the number of bytes occupied by the string in @p src.
+ **/
+size_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
+{
+ size_t ret;
+
+ if (dest_len == (size_t)-1) {
+ /* No longer allow dest_len of -1. */
+ smb_panic("pull_ascii - invalid dest_len of -1");
+ }
+
+ if (flags & STR_TERMINATE) {
+ if (src_len == (size_t)-1) {
+ src_len = strlen((const char *)src) + 1;
+ } else {
+ size_t len = strnlen((const char *)src, src_len);
+ if (len < src_len)
+ len++;
+ src_len = len;
+ }
+ }
+
+ ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len, True);
+ if (ret == (size_t)-1) {
+ ret = 0;
+ dest_len = 0;
+ }
+
+ if (dest_len && ret) {
+ /* Did we already process the terminating zero ? */
+ if (dest[MIN(ret-1, dest_len-1)] != 0) {
+ dest[MIN(ret, dest_len-1)] = 0;
+ }
+ } else {
+ dest[0] = 0;
+ }
+
+ return src_len;
+}
+
+/**
+ * Copy a string from a dos codepage source to a unix char* destination.
+ Talloc version.
+ Uses malloc if TALLOC_CTX is NULL (this is a bad interface and
+ needs fixing. JRA).
+ *
+ * The resulting string in "dest" is always null terminated.
+ *
+ * @param flags can have:
+ * <dl>
+ * <dt>STR_TERMINATE</dt>
+ * <dd>STR_TERMINATE means the string in @p src
+ * is null terminated, and src_len is ignored.</dd>
+ * </dl>
+ *
+ * @param src_len is the length of the source area in bytes.
+ * @returns the number of bytes occupied by the string in @p src.
+ **/
+
+static size_t pull_ascii_base_talloc(TALLOC_CTX *ctx,
+ char **ppdest,
+ const void *src,
+ size_t src_len,
+ int flags)
+{
+ char *dest = NULL;
+ size_t converted_size;
+
+#ifdef DEVELOPER
+ /* Ensure we never use the braindead "malloc" varient. */
+ if (ctx == NULL) {
+ smb_panic("NULL talloc CTX in pull_ascii_base_talloc\n");
+ }
+#endif
+
+ *ppdest = NULL;
+
+ if (flags & STR_TERMINATE) {
+ if (src_len == (size_t)-1) {
+ src_len = strlen((const char *)src) + 1;
+ } else {
+ size_t len = strnlen((const char *)src, src_len);
+ if (len < src_len)
+ len++;
+ src_len = len;
+ }
+ /* Ensure we don't use an insane length from the client. */
+ if (src_len >= 1024*1024) {
+ char *msg = talloc_asprintf(ctx,
+ "Bad src length (%u) in "
+ "pull_ascii_base_talloc",
+ (unsigned int)src_len);
+ smb_panic(msg);
+ }
+ }
+
+ if (!convert_string_allocate(ctx, CH_DOS, CH_UNIX, src, src_len, &dest,
+ &converted_size, True))
+ {
+ converted_size = 0;
+ }
+
+ if (converted_size && dest) {
+ /* Did we already process the terminating zero ? */
+ if (dest[converted_size - 1] != 0) {
+ dest[converted_size - 1] = 0;
+ }
+ } else if (dest) {
+ dest[0] = 0;
+ }
+
+ *ppdest = dest;
+ return src_len;
+}
+
+size_t pull_ascii_fstring(char *dest, const void *src)
+{
+ return pull_ascii(dest, src, sizeof(fstring), -1, STR_TERMINATE);
+}
+
+/* When pulling an nstring it can expand into a larger size (dos cp -> utf8). Cope with this. */
+
+size_t pull_ascii_nstring(char *dest, size_t dest_len, const void *src)
+{
+ return pull_ascii(dest, src, dest_len, sizeof(nstring)-1, STR_TERMINATE);
+}
+
+/**
+ * Copy a string from a char* src to a unicode destination.
+ *
+ * @returns the number of bytes occupied by the string in the destination.
+ *
+ * @param flags can have:
+ *
+ * <dl>
+ * <dt>STR_TERMINATE <dd>means include the null termination.
+ * <dt>STR_UPPER <dd>means uppercase in the destination.
+ * <dt>STR_NOALIGN <dd>means don't do alignment.
+ * </dl>
+ *
+ * @param dest_len is the maximum length allowed in the
+ * destination.
+ **/
+
+size_t push_ucs2(const void *base_ptr, void *dest, const char *src, size_t dest_len, int flags)
+{
+ size_t len=0;
+ size_t src_len;
+ size_t ret;
+
+ if (dest_len == (size_t)-1) {
+ /* No longer allow dest_len of -1. */
+ smb_panic("push_ucs2 - invalid dest_len of -1");
+ }
+
+ if (flags & STR_TERMINATE)
+ src_len = (size_t)-1;
+ else
+ src_len = strlen(src);
+
+ if (ucs2_align(base_ptr, dest, flags)) {
+ *(char *)dest = 0;
+ dest = (void *)((char *)dest + 1);
+ if (dest_len)
+ dest_len--;
+ len++;
+ }
+
+ /* ucs2 is always a multiple of 2 bytes */
+ dest_len &= ~1;
+
+ ret = convert_string(CH_UNIX, CH_UTF16LE, src, src_len, dest, dest_len, True);
+ if (ret == (size_t)-1) {
+ if ((flags & STR_TERMINATE) &&
+ dest &&
+ dest_len) {
+ *(char *)dest = 0;
+ }
+ return len;
+ }
+
+ len += ret;
+
+ if (flags & STR_UPPER) {
+ smb_ucs2_t *dest_ucs2 = (smb_ucs2_t *)dest;
+ size_t i;
+
+ /* We check for i < (ret / 2) below as the dest string isn't null
+ terminated if STR_TERMINATE isn't set. */
+
+ for (i = 0; i < (ret / 2) && i < (dest_len / 2) && dest_ucs2[i]; i++) {
+ smb_ucs2_t v = toupper_w(dest_ucs2[i]);
+ if (v != dest_ucs2[i]) {
+ dest_ucs2[i] = v;
+ }
+ }
+ }
+
+ return len;
+}
+
+
+/**
+ * Copy a string from a unix char* src to a UCS2 destination,
+ * allocating a buffer using talloc().
+ *
+ * @param dest always set at least to NULL
+ * @parm converted_size set to the number of bytes occupied by the string in
+ * the destination on success.
+ *
+ * @return true if new buffer was correctly allocated, and string was
+ * converted.
+ **/
+bool push_ucs2_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src,
+ size_t *converted_size)
+{
+ size_t src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_talloc(ctx, CH_UNIX, CH_UTF16LE, src, src_len,
+ (void **)dest, converted_size, True);
+}
+
+
+/**
+ * Copy a string from a unix char* src to a UCS2 destination, allocating a buffer
+ *
+ * @param dest always set at least to NULL
+ * @parm converted_size set to the number of bytes occupied by the string in
+ * the destination on success.
+ *
+ * @return true if new buffer was correctly allocated, and string was
+ * converted.
+ **/
+
+bool push_ucs2_allocate(smb_ucs2_t **dest, const char *src,
+ size_t *converted_size)
+{
+ size_t src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_allocate(NULL, CH_UNIX, CH_UTF16LE, src, src_len,
+ (void **)dest, converted_size, True);
+}
+
+/**
+ Copy a string from a char* src to a UTF-8 destination.
+ Return the number of bytes occupied by the string in the destination
+ Flags can have:
+ STR_TERMINATE means include the null termination
+ STR_UPPER means uppercase in the destination
+ dest_len is the maximum length allowed in the destination. If dest_len
+ is -1 then no maxiumum is used.
+**/
+
+static size_t push_utf8(void *dest, const char *src, size_t dest_len, int flags)
+{
+ size_t src_len = 0;
+ size_t ret;
+ char *tmpbuf = NULL;
+
+ if (dest_len == (size_t)-1) {
+ /* No longer allow dest_len of -1. */
+ smb_panic("push_utf8 - invalid dest_len of -1");
+ }
+
+ if (flags & STR_UPPER) {
+ tmpbuf = strdup_upper(src);
+ if (!tmpbuf) {
+ return (size_t)-1;
+ }
+ src = tmpbuf;
+ src_len = strlen(src);
+ }
+
+ src_len = strlen(src);
+ if (flags & STR_TERMINATE) {
+ src_len++;
+ }
+
+ ret = convert_string(CH_UNIX, CH_UTF8, src, src_len, dest, dest_len, True);
+ SAFE_FREE(tmpbuf);
+ return ret;
+}
+
+size_t push_utf8_fstring(void *dest, const char *src)
+{
+ return push_utf8(dest, src, sizeof(fstring), STR_TERMINATE);
+}
+
+/**
+ * Copy a string from a unix char* src to a UTF-8 destination, allocating a buffer using talloc
+ *
+ * @param dest always set at least to NULL
+ * @parm converted_size set to the number of bytes occupied by the string in
+ * the destination on success.
+ *
+ * @return true if new buffer was correctly allocated, and string was
+ * converted.
+ **/
+
+bool push_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src,
+ size_t *converted_size)
+{
+ size_t src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_talloc(ctx, CH_UNIX, CH_UTF8, src, src_len,
+ (void**)dest, converted_size, True);
+}
+
+/**
+ * Copy a string from a unix char* src to a UTF-8 destination, allocating a buffer
+ *
+ * @param dest always set at least to NULL
+ * @parm converted_size set to the number of bytes occupied by the string in
+ * the destination on success.
+ *
+ * @return true if new buffer was correctly allocated, and string was
+ * converted.
+ **/
+
+bool push_utf8_allocate(char **dest, const char *src, size_t *converted_size)
+{
+ size_t src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_allocate(NULL, CH_UNIX, CH_UTF8, src, src_len,
+ (void **)dest, converted_size, True);
+}
+
+/**
+ Copy a string from a ucs2 source to a unix char* destination.
+ Flags can have:
+ STR_TERMINATE means the string in src is null terminated.
+ STR_NOALIGN means don't try to align.
+ if STR_TERMINATE is set then src_len is ignored if it is -1.
+ src_len is the length of the source area in bytes
+ Return the number of bytes occupied by the string in src.
+ The resulting string in "dest" is always null terminated.
+**/
+
+size_t pull_ucs2(const void *base_ptr, char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
+{
+ size_t ret;
+
+ if (dest_len == (size_t)-1) {
+ /* No longer allow dest_len of -1. */
+ smb_panic("pull_ucs2 - invalid dest_len of -1");
+ }
+
+ if (!src_len) {
+ if (dest && dest_len > 0) {
+ dest[0] = '\0';
+ }
+ return 0;
+ }
+
+ if (ucs2_align(base_ptr, src, flags)) {
+ src = (const void *)((const char *)src + 1);
+ if (src_len != (size_t)-1)
+ src_len--;
+ }
+
+ if (flags & STR_TERMINATE) {
+ /* src_len -1 is the default for null terminated strings. */
+ if (src_len != (size_t)-1) {
+ size_t len = strnlen_w((const smb_ucs2_t *)src,
+ src_len/2);
+ if (len < src_len/2)
+ len++;
+ src_len = len*2;
+ }
+ }
+
+ /* ucs2 is always a multiple of 2 bytes */
+ if (src_len != (size_t)-1)
+ src_len &= ~1;
+
+ ret = convert_string(CH_UTF16LE, CH_UNIX, src, src_len, dest, dest_len, True);
+ if (ret == (size_t)-1) {
+ ret = 0;
+ dest_len = 0;
+ }
+
+ if (src_len == (size_t)-1)
+ src_len = ret*2;
+
+ if (dest_len && ret) {
+ /* Did we already process the terminating zero ? */
+ if (dest[MIN(ret-1, dest_len-1)] != 0) {
+ dest[MIN(ret, dest_len-1)] = 0;
+ }
+ } else {
+ dest[0] = 0;
+ }
+
+ return src_len;
+}
+
+/**
+ Copy a string from a ucs2 source to a unix char* destination.
+ Talloc version with a base pointer.
+ Uses malloc if TALLOC_CTX is NULL (this is a bad interface and
+ needs fixing. JRA).
+ Flags can have:
+ STR_TERMINATE means the string in src is null terminated.
+ STR_NOALIGN means don't try to align.
+ if STR_TERMINATE is set then src_len is ignored if it is -1.
+ src_len is the length of the source area in bytes
+ Return the number of bytes occupied by the string in src.
+ The resulting string in "dest" is always null terminated.
+**/
+
+size_t pull_ucs2_base_talloc(TALLOC_CTX *ctx,
+ const void *base_ptr,
+ char **ppdest,
+ const void *src,
+ size_t src_len,
+ int flags)
+{
+ char *dest;
+ size_t dest_len;
+
+ *ppdest = NULL;
+
+#ifdef DEVELOPER
+ /* Ensure we never use the braindead "malloc" varient. */
+ if (ctx == NULL) {
+ smb_panic("NULL talloc CTX in pull_ucs2_base_talloc\n");
+ }
+#endif
+
+ if (!src_len) {
+ return 0;
+ }
+
+ if (ucs2_align(base_ptr, src, flags)) {
+ src = (const void *)((const char *)src + 1);
+ if (src_len != (size_t)-1)
+ src_len--;
+ }
+
+ if (flags & STR_TERMINATE) {
+ /* src_len -1 is the default for null terminated strings. */
+ if (src_len != (size_t)-1) {
+ size_t len = strnlen_w((const smb_ucs2_t *)src,
+ src_len/2);
+ if (len < src_len/2)
+ len++;
+ src_len = len*2;
+ } else {
+ /*
+ * src_len == -1 - alloc interface won't take this
+ * so we must calculate.
+ */
+ src_len = (strlen_w((const smb_ucs2_t *)src)+1)*sizeof(smb_ucs2_t);
+ }
+ /* Ensure we don't use an insane length from the client. */
+ if (src_len >= 1024*1024) {
+ smb_panic("Bad src length in pull_ucs2_base_talloc\n");
+ }
+ }
+
+ /* ucs2 is always a multiple of 2 bytes */
+ if (src_len != (size_t)-1) {
+ src_len &= ~1;
+ }
+
+ if (!convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX, src, src_len,
+ (void *)&dest, &dest_len, True)) {
+ dest_len = 0;
+ }
+
+ if (src_len == (size_t)-1)
+ src_len = dest_len*2;
+
+ if (dest_len) {
+ /* Did we already process the terminating zero ? */
+ if (dest[dest_len-1] != 0) {
+ size_t size = talloc_get_size(dest);
+ /* Have we got space to append the '\0' ? */
+ if (size <= dest_len) {
+ /* No, realloc. */
+ dest = TALLOC_REALLOC_ARRAY(ctx, dest, char,
+ dest_len+1);
+ if (!dest) {
+ /* talloc fail. */
+ dest_len = (size_t)-1;
+ return 0;
+ }
+ }
+ /* Yay - space ! */
+ dest[dest_len] = '\0';
+ dest_len++;
+ }
+ } else if (dest) {
+ dest[0] = 0;
+ }
+
+ *ppdest = dest;
+ return src_len;
+}
+
+size_t pull_ucs2_fstring(char *dest, const void *src)
+{
+ return pull_ucs2(NULL, dest, src, sizeof(fstring), -1, STR_TERMINATE);
+}
+
+/**
+ * Copy a string from a UCS2 src to a unix char * destination, allocating a buffer using talloc
+ *
+ * @param dest always set at least to NULL
+ * @parm converted_size set to the number of bytes occupied by the string in
+ * the destination on success.
+ *
+ * @return true if new buffer was correctly allocated, and string was
+ * converted.
+ **/
+
+bool pull_ucs2_talloc(TALLOC_CTX *ctx, char **dest, const smb_ucs2_t *src,
+ size_t *converted_size)
+{
+ size_t src_len = (strlen_w(src)+1) * sizeof(smb_ucs2_t);
+
+ *dest = NULL;
+ return convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX, src, src_len,
+ (void **)dest, converted_size, True);
+}
+
+/**
+ * Copy a string from a UCS2 src to a unix char * destination, allocating a buffer
+ *
+ * @param dest always set at least to NULL
+ * @parm converted_size set to the number of bytes occupied by the string in
+ * the destination on success.
+ * @return true if new buffer was correctly allocated, and string was
+ * converted.
+ **/
+
+bool pull_ucs2_allocate(char **dest, const smb_ucs2_t *src,
+ size_t *converted_size)
+{
+ size_t src_len = (strlen_w(src)+1) * sizeof(smb_ucs2_t);
+
+ *dest = NULL;
+ return convert_string_allocate(NULL, CH_UTF16LE, CH_UNIX, src, src_len,
+ (void **)dest, converted_size, True);
+}
+
+/**
+ * Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer using talloc
+ *
+ * @param dest always set at least to NULL
+ * @parm converted_size set to the number of bytes occupied by the string in
+ * the destination on success.
+ *
+ * @return true if new buffer was correctly allocated, and string was
+ * converted.
+ **/
+
+bool pull_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src,
+ size_t *converted_size)
+{
+ size_t src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_talloc(ctx, CH_UTF8, CH_UNIX, src, src_len,
+ (void **)dest, converted_size, True);
+}
+
+/**
+ * Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer
+ *
+ * @param dest always set at least to NULL
+ * @parm converted_size set to the number of bytes occupied by the string in
+ * the destination on success.
+ *
+ * @return true if new buffer was correctly allocated, and string was
+ * converted.
+ **/
+
+bool pull_utf8_allocate(char **dest, const char *src, size_t *converted_size)
+{
+ size_t src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_allocate(NULL, CH_UTF8, CH_UNIX, src, src_len,
+ (void **)dest, converted_size, True);
+}
+
+/**
+ * Copy a string from a DOS src to a unix char * destination, allocating a buffer using talloc
+ *
+ * @param dest always set at least to NULL
+ * @parm converted_size set to the number of bytes occupied by the string in
+ * the destination on success.
+ *
+ * @return true if new buffer was correctly allocated, and string was
+ * converted.
+ **/
+
+bool pull_ascii_talloc(TALLOC_CTX *ctx, char **dest, const char *src,
+ size_t *converted_size)
+{
+ size_t src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_talloc(ctx, CH_DOS, CH_UNIX, src, src_len,
+ (void **)dest, converted_size, True);
+}
+
+/**
+ Copy a string from a char* src to a unicode or ascii
+ dos codepage destination choosing unicode or ascii based on the
+ flags in the SMB buffer starting at base_ptr.
+ Return the number of bytes occupied by the string in the destination.
+ flags can have:
+ STR_TERMINATE means include the null termination.
+ STR_UPPER means uppercase in the destination.
+ STR_ASCII use ascii even with unicode packet.
+ STR_NOALIGN means don't do alignment.
+ dest_len is the maximum length allowed in the destination. If dest_len
+ is -1 then no maxiumum is used.
+**/
+
+size_t push_string_fn(const char *function, unsigned int line,
+ const void *base_ptr, uint16 flags2,
+ void *dest, const char *src,
+ size_t dest_len, int flags)
+{
+#ifdef DEVELOPER
+ /* We really need to zero fill here, not clobber
+ * region, as we want to ensure that valgrind thinks
+ * all of the outgoing buffer has been written to
+ * so a send() or write() won't trap an error.
+ * JRA.
+ */
+#if 0
+ clobber_region(function, line, dest, dest_len);
+#else
+ memset(dest, '\0', dest_len);
+#endif
+#endif
+
+ if (!(flags & STR_ASCII) && \
+ ((flags & STR_UNICODE || \
+ (flags2 & FLAGS2_UNICODE_STRINGS)))) {
+ return push_ucs2(base_ptr, dest, src, dest_len, flags);
+ }
+ return push_ascii(dest, src, dest_len, flags);
+}
+
+
+/**
+ Copy a string from a unicode or ascii source (depending on
+ the packet flags) to a char* destination.
+ Flags can have:
+ STR_TERMINATE means the string in src is null terminated.
+ STR_UNICODE means to force as unicode.
+ STR_ASCII use ascii even with unicode packet.
+ STR_NOALIGN means don't do alignment.
+ if STR_TERMINATE is set then src_len is ignored is it is -1
+ src_len is the length of the source area in bytes.
+ Return the number of bytes occupied by the string in src.
+ The resulting string in "dest" is always null terminated.
+**/
+
+size_t pull_string_fn(const char *function,
+ unsigned int line,
+ const void *base_ptr,
+ uint16 smb_flags2,
+ char *dest,
+ const void *src,
+ size_t dest_len,
+ size_t src_len,
+ int flags)
+{
+#ifdef DEVELOPER
+ clobber_region(function, line, dest, dest_len);
+#endif
+
+ if ((base_ptr == NULL) && ((flags & (STR_ASCII|STR_UNICODE)) == 0)) {
+ smb_panic("No base ptr to get flg2 and neither ASCII nor "
+ "UNICODE defined");
+ }
+
+ if (!(flags & STR_ASCII) && \
+ ((flags & STR_UNICODE || \
+ (smb_flags2 & FLAGS2_UNICODE_STRINGS)))) {
+ return pull_ucs2(base_ptr, dest, src, dest_len, src_len, flags);
+ }
+ return pull_ascii(dest, src, dest_len, src_len, flags);
+}
+
+/**
+ Copy a string from a unicode or ascii source (depending on
+ the packet flags) to a char* destination.
+ Variant that uses talloc.
+ Flags can have:
+ STR_TERMINATE means the string in src is null terminated.
+ STR_UNICODE means to force as unicode.
+ STR_ASCII use ascii even with unicode packet.
+ STR_NOALIGN means don't do alignment.
+ if STR_TERMINATE is set then src_len is ignored is it is -1
+ src_len is the length of the source area in bytes.
+ Return the number of bytes occupied by the string in src.
+ The resulting string in "dest" is always null terminated.
+**/
+
+size_t pull_string_talloc_fn(const char *function,
+ unsigned int line,
+ TALLOC_CTX *ctx,
+ const void *base_ptr,
+ uint16 smb_flags2,
+ char **ppdest,
+ const void *src,
+ size_t src_len,
+ int flags)
+{
+ if ((base_ptr == NULL) && ((flags & (STR_ASCII|STR_UNICODE)) == 0)) {
+ smb_panic("No base ptr to get flg2 and neither ASCII nor "
+ "UNICODE defined");
+ }
+
+ if (!(flags & STR_ASCII) && \
+ ((flags & STR_UNICODE || \
+ (smb_flags2 & FLAGS2_UNICODE_STRINGS)))) {
+ return pull_ucs2_base_talloc(ctx,
+ base_ptr,
+ ppdest,
+ src,
+ src_len,
+ flags);
+ }
+ return pull_ascii_base_talloc(ctx,
+ ppdest,
+ src,
+ src_len,
+ flags);
+}
+
+
+size_t align_string(const void *base_ptr, const char *p, int flags)
+{
+ if (!(flags & STR_ASCII) && \
+ ((flags & STR_UNICODE || \
+ (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
+ return ucs2_align(base_ptr, p, flags);
+ }
+ return 0;
+}
+
+/*
+ Return the unicode codepoint for the next multi-byte CH_UNIX character
+ in the string. The unicode codepoint (codepoint_t) is an unsinged 32 bit value.
+
+ Also return the number of bytes consumed (which tells the caller
+ how many bytes to skip to get to the next CH_UNIX character).
+
+ Return INVALID_CODEPOINT if the next character cannot be converted.
+*/
+
+codepoint_t next_codepoint(const char *str, size_t *size)
+{
+ /* It cannot occupy more than 4 bytes in UTF16 format */
+ uint8_t buf[4];
+ smb_iconv_t descriptor;
+ size_t ilen_orig;
+ size_t ilen;
+ size_t olen;
+ char *outbuf;
+
+ if ((str[0] & 0x80) == 0) {
+ *size = 1;
+ return (codepoint_t)str[0];
+ }
+
+ /* We assume that no multi-byte character can take
+ more than 5 bytes. This is OK as we only
+ support codepoints up to 1M */
+
+ ilen_orig = strnlen(str, 5);
+ ilen = ilen_orig;
+
+ lazy_initialize_conv();
+
+ descriptor = conv_handles[CH_UNIX][CH_UTF16LE];
+ if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
+ *size = 1;
+ return INVALID_CODEPOINT;
+ }
+
+ /* This looks a little strange, but it is needed to cope
+ with codepoints above 64k which are encoded as per RFC2781. */
+ olen = 2;
+ outbuf = (char *)buf;
+ smb_iconv(descriptor, &str, &ilen, &outbuf, &olen);
+ if (olen == 2) {
+ /* We failed to convert to a 2 byte character.
+ See if we can convert to a 4 UTF16-LE byte char encoding.
+ */
+ olen = 4;
+ outbuf = (char *)buf;
+ smb_iconv(descriptor, &str, &ilen, &outbuf, &olen);
+ if (olen == 4) {
+ /* We didn't convert any bytes */
+ *size = 1;
+ return INVALID_CODEPOINT;
+ }
+ olen = 4 - olen;
+ } else {
+ olen = 2 - olen;
+ }
+
+ *size = ilen_orig - ilen;
+
+ if (olen == 2) {
+ /* 2 byte, UTF16-LE encoded value. */
+ return (codepoint_t)SVAL(buf, 0);
+ }
+ if (olen == 4) {
+ /* Decode a 4 byte UTF16-LE character manually.
+ See RFC2871 for the encoding machanism.
+ */
+ codepoint_t w1 = SVAL(buf,0) & ~0xD800;
+ codepoint_t w2 = SVAL(buf,2) & ~0xDC00;
+
+ return (codepoint_t)0x10000 +
+ (w1 << 10) + w2;
+ }
+
+ /* no other length is valid */
+ return INVALID_CODEPOINT;
+}
diff --git a/source3/lib/clobber.c b/source3/lib/clobber.c
new file mode 100644
index 0000000000..e77e786fb5
--- /dev/null
+++ b/source3/lib/clobber.c
@@ -0,0 +1,63 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Martin Pool 2003
+ Copyright (C) Andrew Bartlett 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef DEVELOPER
+const char *global_clobber_region_function;
+unsigned int global_clobber_region_line;
+#endif
+
+/**
+ * In developer builds, clobber a region of memory.
+ *
+ * If we think a string buffer is longer than it really is, this ought
+ * to make the failure obvious, by segfaulting (if in the heap) or by
+ * killing the return address (on the stack), or by trapping under a
+ * memory debugger.
+ *
+ * This is meant to catch possible string overflows, even if the
+ * actual string copied is not big enough to cause an overflow.
+ *
+ * In addition, under Valgrind the buffer is marked as uninitialized.
+ **/
+void clobber_region(const char *fn, unsigned int line, char *dest, size_t len)
+{
+#ifdef DEVELOPER
+ global_clobber_region_function = fn;
+ global_clobber_region_line = line;
+
+ /* F1 is odd and 0xf1f1f1f1 shouldn't be a valid pointer */
+ memset(dest, 0xF1, len);
+#ifdef VALGRIND
+ /* Even though we just wrote to this, from the application's
+ * point of view it is not initialized.
+ *
+ * (This is not redundant with the clobbering above. The
+ * marking might not actually take effect if we're not running
+ * under valgrind.) */
+#if defined(VALGRIND_MAKE_MEM_UNDEFINED)
+ VALGRIND_MAKE_MEM_UNDEFINED(dest, len);
+#elif defined(VALGRIND_MAKE_WRITABLE)
+ VALGRIND_MAKE_WRITABLE(dest, len);
+#endif
+#endif /* VALGRIND */
+#endif /* DEVELOPER */
+}
diff --git a/source3/lib/compression/mszip.c b/source3/lib/compression/mszip.c
new file mode 100644
index 0000000000..aeeb2d8afd
--- /dev/null
+++ b/source3/lib/compression/mszip.c
@@ -0,0 +1,676 @@
+/* mszip decompression - based on cabextract.c code from
+ * Stuart Caie
+ *
+ * adapted for Samba by Andrew Tridgell and Stefan Metzmacher 2005
+ *
+ * (C) 2000-2001 Stuart Caie <kyzer@4u.net>
+ * reaktivate-specifics by Malte Starostik <malte@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "lib/compression/mszip.h"
+
+/*--------------------------------------------------------------------------*/
+/* our archiver information / state */
+
+/* MSZIP stuff */
+#define ZIPWSIZE 0x8000 /* window size */
+#define ZIPLBITS 9 /* bits in base literal/length lookup table */
+#define ZIPDBITS 6 /* bits in base distance lookup table */
+#define ZIPBMAX 16 /* maximum bit length of any code */
+#define ZIPN_MAX 288 /* maximum number of codes in any set */
+
+struct Ziphuft {
+ uint8_t e; /* number of extra bits or operation */
+ uint8_t b; /* number of bits in this code or subcode */
+ union {
+ uint16_t n; /* literal, length base, or distance base */
+ struct Ziphuft *t; /* pointer to next level of table */
+ } v;
+};
+
+struct ZIPstate {
+ uint32_t window_posn; /* current offset within the window */
+ uint32_t bb; /* bit buffer */
+ uint32_t bk; /* bits in bit buffer */
+ uint32_t ll[288+32]; /* literal/length and distance code lengths */
+ uint32_t c[ZIPBMAX+1]; /* bit length count table */
+ int32_t lx[ZIPBMAX+1]; /* memory for l[-1..ZIPBMAX-1] */
+ struct Ziphuft *u[ZIPBMAX]; /* table stack */
+ uint32_t v[ZIPN_MAX]; /* values in order of bit length */
+ uint32_t x[ZIPBMAX+1]; /* bit offsets, then code stack */
+ uint8_t *inpos;
+};
+
+/* generic stuff */
+#define CAB(x) (decomp_state->x)
+#define ZIP(x) (decomp_state->methods.zip.x)
+
+/* CAB data blocks are <= 32768 bytes in uncompressed form. Uncompressed
+ * blocks have zero growth. MSZIP guarantees that it won't grow above
+ * uncompressed size by more than 12 bytes. LZX guarantees it won't grow
+ * more than 6144 bytes.
+ */
+#define CAB_BLOCKMAX (32768)
+#define CAB_INPUTMAX (CAB_BLOCKMAX+6144)
+
+struct decomp_state {
+ struct folder *current; /* current folder we're extracting from */
+ uint32_t offset; /* uncompressed offset within folder */
+ uint8_t *outpos; /* (high level) start of data to use up */
+ uint16_t outlen; /* (high level) amount of data to use up */
+ uint16_t split; /* at which split in current folder? */
+ int (*decompress)(int, int); /* the chosen compression func */
+ uint8_t inbuf[CAB_INPUTMAX+2]; /* +2 for lzx bitbuffer overflows! */
+ uint8_t outbuf[CAB_BLOCKMAX];
+ union {
+ struct ZIPstate zip;
+ } methods;
+};
+
+
+/* MSZIP decruncher */
+
+/* Dirk Stoecker wrote the ZIP decoder, based on the InfoZip deflate code */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static const uint8_t Zipborder[] = /* Order of the bit length code lengths */
+{ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+static const uint16_t Zipcplens[] = /* Copy lengths for literal codes 257..285 */
+{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51,
+ 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+static const uint16_t Zipcplext[] = /* Extra bits for literal codes 257..285 */
+{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,
+ 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
+static const uint16_t Zipcpdist[] = /* Copy offsets for distance codes 0..29 */
+{ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385,
+513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};
+static const uint16_t Zipcpdext[] = /* Extra bits for distance codes */
+{ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
+10, 11, 11, 12, 12, 13, 13};
+
+/* And'ing with Zipmask[n] masks the lower n bits */
+static const uint16_t Zipmask[17] = {
+ 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#define ZIPNEEDBITS(n) {while(k<(n)){int32_t c=*(ZIP(inpos)++);\
+ b|=((uint32_t)c)<<k;k+=8;}}
+#define ZIPDUMPBITS(n) {b>>=(n);k-=(n);}
+
+static void Ziphuft_free(struct Ziphuft *t)
+{
+ register struct Ziphuft *p, *q;
+
+ /* Go through linked list, freeing from the allocated (t[-1]) address. */
+ p = t;
+ while (p != (struct Ziphuft *)NULL)
+ {
+ q = (--p)->v.t;
+ free(p);
+ p = q;
+ }
+}
+
+static int32_t Ziphuft_build(struct decomp_state *decomp_state,
+ uint32_t *b, uint32_t n, uint32_t s, const uint16_t *d, const uint16_t *e,
+ struct Ziphuft **t, int32_t *m)
+{
+ uint32_t a; /* counter for codes of length k */
+ uint32_t el; /* length of EOB code (value 256) */
+ uint32_t f; /* i repeats in table every f entries */
+ int32_t g; /* maximum code length */
+ int32_t h; /* table level */
+ register uint32_t i; /* counter, current code */
+ register uint32_t j; /* counter */
+ register int32_t k; /* number of bits in current code */
+ int32_t *l; /* stack of bits per table */
+ register uint32_t *p; /* pointer into ZIP(c)[],ZIP(b)[],ZIP(v)[] */
+ register struct Ziphuft *q; /* points to current table */
+ struct Ziphuft r; /* table entry for structure assignment */
+ register int32_t w; /* bits before this table == (l * h) */
+ uint32_t *xp; /* pointer into x */
+ int32_t y; /* number of dummy codes added */
+ uint32_t z; /* number of entries in current table */
+
+ l = ZIP(lx)+1;
+
+ /* Generate counts for each bit length */
+ el = n > 256 ? b[256] : ZIPBMAX; /* set length of EOB code, if any */
+
+ for(i = 0; i < ZIPBMAX+1; ++i)
+ ZIP(c)[i] = 0;
+ p = b; i = n;
+ do
+ {
+ ZIP(c)[*p]++; p++; /* assume all entries <= ZIPBMAX */
+ } while (--i);
+ if (ZIP(c)[0] == n) /* null input--all zero length codes */
+ {
+ *t = (struct Ziphuft *)NULL;
+ *m = 0;
+ return 0;
+ }
+
+ /* Find minimum and maximum length, bound *m by those */
+ for (j = 1; j <= ZIPBMAX; j++)
+ if (ZIP(c)[j])
+ break;
+ k = j; /* minimum code length */
+ if ((uint32_t)*m < j)
+ *m = j;
+ for (i = ZIPBMAX; i; i--)
+ if (ZIP(c)[i])
+ break;
+ g = i; /* maximum code length */
+ if ((uint32_t)*m > i)
+ *m = i;
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= ZIP(c)[j]) < 0)
+ return 2; /* bad input: more codes than bits */
+ if ((y -= ZIP(c)[i]) < 0)
+ return 2;
+ ZIP(c)[i] += y;
+
+ /* Generate starting offsets int32_to the value table for each length */
+ ZIP(x)[1] = j = 0;
+ p = ZIP(c) + 1; xp = ZIP(x) + 2;
+ while (--i)
+ { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do{
+ if ((j = *p++) != 0)
+ ZIP(v)[ZIP(x)[j]++] = i;
+ } while (++i < n);
+
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ ZIP(x)[0] = i = 0; /* first Huffman code is zero */
+ p = ZIP(v); /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = l[-1] = 0; /* no bits decoded yet */
+ ZIP(u)[0] = (struct Ziphuft *)NULL; /* just to keep compilers happy */
+ q = (struct Ziphuft *)NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = ZIP(c)[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l[h])
+ {
+ w += l[h++]; /* add bits already decoded */
+
+ /* compute minimum size table less than or equal to *m bits */
+ z = (z = g - w) > (uint32_t)*m ? *m : z; /* upper limit */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = ZIP(c) + k;
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ if ((uint32_t)w + j > el && (uint32_t)w < el)
+ j = el - w; /* make EOB code end at table */
+ z = 1 << j; /* table entries for j-bit table */
+ l[h] = j; /* set table size in stack */
+
+ /* allocate and link in new table */
+ if (!(q = (struct Ziphuft *)SMB_MALLOC((z + 1)*sizeof(struct Ziphuft))))
+ {
+ if(h)
+ Ziphuft_free(ZIP(u)[0]);
+ return 3; /* not enough memory */
+ }
+ *t = q + 1; /* link to list for Ziphuft_free() */
+ *(t = &(q->v.t)) = (struct Ziphuft *)NULL;
+ ZIP(u)[h] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ ZIP(x)[h] = i; /* save pattern for backing up */
+ r.b = (uint8_t)l[h-1]; /* bits to dump before this table */
+ r.e = (uint8_t)(16 + j); /* bits in this table */
+ r.v.t = q; /* pointer to this table */
+ j = (i & ((1 << w) - 1)) >> (w - l[h-1]);
+ ZIP(u)[h-1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.b = (uint8_t)(k - w);
+ if (p >= ZIP(v) + n)
+ r.e = 99; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.e = (uint8_t)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
+ r.v.n = *p++; /* simple code is just the value */
+ }
+ else
+ {
+ r.e = (uint8_t)e[*p - s]; /* non-simple--look up in lists */
+ r.v.n = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != ZIP(x)[h])
+ w -= l[--h]; /* don't need to update q */
+ }
+ }
+
+ /* return actual size of base table */
+ *m = l[0];
+
+ /* Return true (1) if we were given an incomplete table */
+ return y != 0 && g != 1;
+}
+
+static int32_t Zipinflate_codes(struct decomp_state *decomp_state,
+ struct Ziphuft *tl, struct Ziphuft *td,
+ int32_t bl, int32_t bd)
+{
+ register uint32_t e; /* table entry flag/number of extra bits */
+ uint32_t n, d; /* length and index for copy */
+ uint32_t w; /* current window position */
+ struct Ziphuft *t; /* pointer to table entry */
+ uint32_t ml, md; /* masks for bl and bd bits */
+ register uint32_t b; /* bit buffer */
+ register uint32_t k; /* number of bits in bit buffer */
+
+ DEBUG(10,("Zipinflate_codes\n"));
+
+ /* make local copies of globals */
+ b = ZIP(bb); /* initialize bit buffer */
+ k = ZIP(bk);
+ w = ZIP(window_posn); /* initialize window position */
+
+ /* inflate the coded data */
+ ml = Zipmask[bl]; /* precompute masks for speed */
+ md = Zipmask[bd];
+
+ for(;;)
+ {
+ ZIPNEEDBITS((uint32_t)bl)
+ if((e = (t = tl + ((uint32_t)b & ml))->e) > 16)
+ do
+ {
+ if (e == 99)
+ return 1;
+ ZIPDUMPBITS(t->b)
+ e -= 16;
+ ZIPNEEDBITS(e)
+ } while ((e = (t = t->v.t + ((uint32_t)b & Zipmask[e]))->e) > 16);
+ ZIPDUMPBITS(t->b)
+ if (w >= CAB_BLOCKMAX) break;
+ if (e == 16) /* then it's a literal */
+ CAB(outbuf)[w++] = (uint8_t)t->v.n;
+ else /* it's an EOB or a length */
+ {
+ /* exit if end of block */
+ if(e == 15)
+ break;
+
+ /* get length of block to copy */
+ ZIPNEEDBITS(e)
+ n = t->v.n + ((uint32_t)b & Zipmask[e]);
+ ZIPDUMPBITS(e);
+
+ /* decode distance of block to copy */
+ ZIPNEEDBITS((uint32_t)bd)
+ if ((e = (t = td + ((uint32_t)b & md))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ ZIPDUMPBITS(t->b)
+ e -= 16;
+ ZIPNEEDBITS(e)
+ } while ((e = (t = t->v.t + ((uint32_t)b & Zipmask[e]))->e) > 16);
+ ZIPDUMPBITS(t->b)
+ ZIPNEEDBITS(e)
+ d = w - t->v.n - ((uint32_t)b & Zipmask[e]);
+ ZIPDUMPBITS(e)
+ do
+ {
+ n -= (e = (e = ZIPWSIZE - ((d &= ZIPWSIZE-1) > w ? d : w)) > n ?n:e);
+ do
+ {
+ CAB(outbuf)[w++] = CAB(outbuf)[d++];
+ } while (--e);
+ } while (n);
+ }
+ }
+
+ /* restore the globals from the locals */
+ ZIP(window_posn) = w; /* restore global window pointer */
+ ZIP(bb) = b; /* restore global bit buffer */
+ ZIP(bk) = k;
+
+ /* done */
+ return 0;
+}
+
+/* "decompress" an inflated type 0 (stored) block. */
+static int32_t Zipinflate_stored(struct decomp_state *decomp_state)
+{
+ uint32_t n; /* number of bytes in block */
+ uint32_t w; /* current window position */
+ register uint32_t b; /* bit buffer */
+ register uint32_t k; /* number of bits in bit buffer */
+
+ /* make local copies of globals */
+ b = ZIP(bb); /* initialize bit buffer */
+ k = ZIP(bk);
+ w = ZIP(window_posn); /* initialize window position */
+
+ /* go to byte boundary */
+ n = k & 7;
+ ZIPDUMPBITS(n);
+
+ /* get the length and its complement */
+ ZIPNEEDBITS(16)
+ n = ((uint32_t)b & 0xffff);
+ ZIPDUMPBITS(16)
+ ZIPNEEDBITS(16)
+ if (n != (uint32_t)((~b) & 0xffff))
+ return 1; /* error in compressed data */
+ ZIPDUMPBITS(16)
+
+ /* read and output the compressed data */
+ while(n--)
+ {
+ ZIPNEEDBITS(8)
+ CAB(outbuf)[w++] = (uint8_t)b;
+ ZIPDUMPBITS(8)
+ }
+
+ /* restore the globals from the locals */
+ ZIP(window_posn) = w; /* restore global window pointer */
+ ZIP(bb) = b; /* restore global bit buffer */
+ ZIP(bk) = k;
+ return 0;
+}
+
+static int32_t Zipinflate_fixed(struct decomp_state *decomp_state)
+{
+ struct Ziphuft *fixed_tl;
+ struct Ziphuft *fixed_td;
+ int32_t fixed_bl, fixed_bd;
+ int32_t i; /* temporary variable */
+ uint32_t *l;
+
+ l = ZIP(ll);
+
+ /* literal table */
+ for(i = 0; i < 144; i++)
+ l[i] = 8;
+ for(; i < 256; i++)
+ l[i] = 9;
+ for(; i < 280; i++)
+ l[i] = 7;
+ for(; i < 288; i++) /* make a complete, but wrong code set */
+ l[i] = 8;
+ fixed_bl = 7;
+ if((i = Ziphuft_build(decomp_state, l, 288, 257, Zipcplens, Zipcplext, &fixed_tl, &fixed_bl)))
+ return i;
+
+ /* distance table */
+ for(i = 0; i < 30; i++) /* make an incomplete code set */
+ l[i] = 5;
+ fixed_bd = 5;
+ if((i = Ziphuft_build(decomp_state, l, 30, 0, Zipcpdist, Zipcpdext, &fixed_td, &fixed_bd)) > 1)
+ {
+ Ziphuft_free(fixed_tl);
+ return i;
+ }
+
+ /* decompress until an end-of-block code */
+ i = Zipinflate_codes(decomp_state, fixed_tl, fixed_td, fixed_bl, fixed_bd);
+
+ Ziphuft_free(fixed_td);
+ Ziphuft_free(fixed_tl);
+ return i;
+}
+
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+static int32_t Zipinflate_dynamic(struct decomp_state *decomp_state)
+{
+ int32_t i; /* temporary variables */
+ uint32_t j;
+ uint32_t *ll;
+ uint32_t l; /* last length */
+ uint32_t m; /* mask for bit lengths table */
+ uint32_t n; /* number of lengths to get */
+ struct Ziphuft *tl; /* literal/length code table */
+ struct Ziphuft *td; /* distance code table */
+ int32_t bl; /* lookup bits for tl */
+ int32_t bd; /* lookup bits for td */
+ uint32_t nb; /* number of bit length codes */
+ uint32_t nl; /* number of literal/length codes */
+ uint32_t nd; /* number of distance codes */
+ register uint32_t b; /* bit buffer */
+ register uint32_t k; /* number of bits in bit buffer */
+
+ /* make local bit buffer */
+ b = ZIP(bb);
+ k = ZIP(bk);
+ ll = ZIP(ll);
+
+ /* read in table lengths */
+ ZIPNEEDBITS(5)
+ nl = 257 + ((uint32_t)b & 0x1f); /* number of literal/length codes */
+ ZIPDUMPBITS(5)
+ ZIPNEEDBITS(5)
+ nd = 1 + ((uint32_t)b & 0x1f); /* number of distance codes */
+ ZIPDUMPBITS(5)
+ ZIPNEEDBITS(4)
+ nb = 4 + ((uint32_t)b & 0xf); /* number of bit length codes */
+ ZIPDUMPBITS(4)
+ if(nl > 288 || nd > 32)
+ return 1; /* bad lengths */
+
+ /* read in bit-length-code lengths */
+ for(j = 0; j < nb; j++)
+ {
+ ZIPNEEDBITS(3)
+ ll[Zipborder[j]] = (uint32_t)b & 7;
+ ZIPDUMPBITS(3)
+ }
+ for(; j < 19; j++)
+ ll[Zipborder[j]] = 0;
+
+ /* build decoding table for trees--single level, 7 bit lookup */
+ bl = 7;
+ if((i = Ziphuft_build(decomp_state, ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
+ {
+ if(i == 1)
+ Ziphuft_free(tl);
+ return i; /* incomplete code set */
+ }
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ m = Zipmask[bl];
+ i = l = 0;
+ while((uint32_t)i < n)
+ {
+ ZIPNEEDBITS((uint32_t)bl)
+ j = (td = tl + ((uint32_t)b & m))->b;
+ ZIPDUMPBITS(j)
+ j = td->v.n;
+ if (j < 16) /* length of code in bits (0..15) */
+ ll[i++] = l = j; /* save last length in l */
+ else if (j == 16) /* repeat last length 3 to 6 times */
+ {
+ ZIPNEEDBITS(2)
+ j = 3 + ((uint32_t)b & 3);
+ ZIPDUMPBITS(2)
+ if((uint32_t)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = l;
+ }
+ else if (j == 17) /* 3 to 10 zero length codes */
+ {
+ ZIPNEEDBITS(3)
+ j = 3 + ((uint32_t)b & 7);
+ ZIPDUMPBITS(3)
+ if ((uint32_t)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ else /* j == 18: 11 to 138 zero length codes */
+ {
+ ZIPNEEDBITS(7)
+ j = 11 + ((uint32_t)b & 0x7f);
+ ZIPDUMPBITS(7)
+ if ((uint32_t)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ }
+
+ /* free decoding table for trees */
+ Ziphuft_free(tl);
+
+ /* restore the global bit buffer */
+ ZIP(bb) = b;
+ ZIP(bk) = k;
+
+ /* build the decoding tables for literal/length and distance codes */
+ bl = ZIPLBITS;
+ if((i = Ziphuft_build(decomp_state, ll, nl, 257, Zipcplens, Zipcplext, &tl, &bl)) != 0)
+ {
+ if(i == 1)
+ Ziphuft_free(tl);
+ return i; /* incomplete code set */
+ }
+ bd = ZIPDBITS;
+ Ziphuft_build(decomp_state, ll + nl, nd, 0, Zipcpdist, Zipcpdext, &td, &bd);
+
+ /* decompress until an end-of-block code */
+ if(Zipinflate_codes(decomp_state, tl, td, bl, bd))
+ return 1;
+
+ /* free the decoding tables, return */
+ Ziphuft_free(tl);
+ Ziphuft_free(td);
+ return 0;
+}
+
+/* e == last block flag */
+static int32_t Zipinflate_block(struct decomp_state *decomp_state, int32_t *e)
+{ /* decompress an inflated block */
+ uint32_t t; /* block type */
+ register uint32_t b; /* bit buffer */
+ register uint32_t k; /* number of bits in bit buffer */
+
+ DEBUG(10,("Zipinflate_block\n"));
+
+ /* make local bit buffer */
+ b = ZIP(bb);
+ k = ZIP(bk);
+
+ /* read in last block bit */
+ ZIPNEEDBITS(1)
+ *e = (int32_t)b & 1;
+ ZIPDUMPBITS(1)
+
+ /* read in block type */
+ ZIPNEEDBITS(2)
+ t = (uint32_t)b & 3;
+ ZIPDUMPBITS(2)
+
+ /* restore the global bit buffer */
+ ZIP(bb) = b;
+ ZIP(bk) = k;
+
+ DEBUG(10,("inflate type %d\n", t));
+
+ /* inflate that block type */
+ if(t == 2)
+ return Zipinflate_dynamic(decomp_state);
+ if(t == 0)
+ return Zipinflate_stored(decomp_state);
+ if(t == 1)
+ return Zipinflate_fixed(decomp_state);
+ /* bad block type */
+ return 2;
+}
+
+_PUBLIC_ struct decomp_state *ZIPdecomp_state(TALLOC_CTX *mem_ctx)
+{
+ return talloc_zero(mem_ctx, struct decomp_state);
+}
+
+int ZIPdecompress(struct decomp_state *decomp_state, DATA_BLOB *inbuf, DATA_BLOB *outbuf)
+{
+ int32_t e = 0;/* last block flag */
+
+ ZIP(inpos) = CAB(inbuf);
+ ZIP(bb) = ZIP(bk) = ZIP(window_posn) = 0;
+
+ if (inbuf->length > sizeof(decomp_state->inbuf)) return DECR_INPUT;
+
+ if (outbuf->length > sizeof(decomp_state->outbuf)) return DECR_OUTPUT;
+
+ if (outbuf->length > ZIPWSIZE) return DECR_DATAFORMAT;
+
+ memcpy(decomp_state->inbuf, inbuf->data, inbuf->length);
+
+ /* CK = Chris Kirmse, official Microsoft purloiner */
+ if (ZIP(inpos)[0] != 'C' || ZIP(inpos)[1] != 'K') return DECR_ILLEGALDATA;
+ ZIP(inpos) += 2;
+
+ while (!e) {
+ if (Zipinflate_block(decomp_state, &e)) {
+ return DECR_ILLEGALDATA;
+ }
+ }
+
+ memcpy(outbuf->data, decomp_state->outbuf, outbuf->length);
+
+ return DECR_OK;
+}
diff --git a/source3/lib/compression/mszip.h b/source3/lib/compression/mszip.h
new file mode 100644
index 0000000000..bb835f2595
--- /dev/null
+++ b/source3/lib/compression/mszip.h
@@ -0,0 +1,33 @@
+/* mszip decompression - based on cabextract.c code from
+ * Stuart Caie
+ *
+ * adapted for Samba by Andrew Tridgell and Stefan Metzmacher 2005
+ *
+ * (C) 2000-2001 Stuart Caie <kyzer@4u.net>
+ * reaktivate-specifics by Malte Starostik <malte@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+struct decomp_state;
+struct decomp_state *ZIPdecomp_state(TALLOC_CTX *mem_ctx);
+
+#define DECR_OK (0)
+#define DECR_DATAFORMAT (1)
+#define DECR_ILLEGALDATA (2)
+#define DECR_NOMEMORY (3)
+#define DECR_CHECKSUM (4)
+#define DECR_INPUT (5)
+#define DECR_OUTPUT (6)
+int ZIPdecompress(struct decomp_state *decomp_state, DATA_BLOB *inbuf, DATA_BLOB *outbuf);
diff --git a/source3/lib/conn_tdb.c b/source3/lib/conn_tdb.c
new file mode 100644
index 0000000000..22d85c873d
--- /dev/null
+++ b/source3/lib/conn_tdb.c
@@ -0,0 +1,126 @@
+/*
+ Unix SMB/CIFS implementation.
+ Low-level connections.tdb access functions
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static struct db_context *connections_db_ctx(bool rw)
+{
+ static struct db_context *db_ctx;
+
+ if (db_ctx != NULL) {
+ return db_ctx;
+ }
+
+ if (rw) {
+ db_ctx = db_open(NULL, lock_path("connections.tdb"), 0,
+ TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
+ O_RDWR | O_CREAT, 0644);
+ }
+ else {
+ db_ctx = db_open(NULL, lock_path("connections.tdb"), 0,
+ TDB_CLEAR_IF_FIRST|TDB_DEFAULT, O_RDONLY, 0);
+ }
+
+ return db_ctx;
+}
+
+struct db_record *connections_fetch_record(TALLOC_CTX *mem_ctx,
+ TDB_DATA key)
+{
+ struct db_context *ctx = connections_db_ctx(True);
+
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ return ctx->fetch_locked(ctx, mem_ctx, key);
+}
+
+struct db_record *connections_fetch_entry(TALLOC_CTX *mem_ctx,
+ connection_struct *conn,
+ const char *name)
+{
+ struct connections_key ckey;
+ TDB_DATA key;
+
+ ZERO_STRUCT(ckey);
+ ckey.pid = procid_self();
+ ckey.cnum = conn ? conn->cnum : -1;
+ strlcpy(ckey.name, name, sizeof(ckey.name));
+
+ key.dsize = sizeof(ckey);
+ key.dptr = (uint8 *)&ckey;
+
+ return connections_fetch_record(mem_ctx, key);
+}
+
+struct conn_traverse_state {
+ int (*fn)(struct db_record *rec,
+ const struct connections_key *key,
+ const struct connections_data *data,
+ void *private_data);
+ void *private_data;
+};
+
+static int conn_traverse_fn(struct db_record *rec, void *private_data)
+{
+ struct conn_traverse_state *state =
+ (struct conn_traverse_state *)private_data;
+
+ if ((rec->key.dsize != sizeof(struct connections_key))
+ || (rec->value.dsize != sizeof(struct connections_data))) {
+ return 0;
+ }
+
+ return state->fn(rec, (const struct connections_key *)rec->key.dptr,
+ (const struct connections_data *)rec->value.dptr,
+ state->private_data);
+}
+
+int connections_traverse(int (*fn)(struct db_record *rec,
+ void *private_data),
+ void *private_data)
+{
+ struct db_context *ctx = connections_db_ctx(False);
+
+ if (ctx == NULL) {
+ return -1;
+ }
+
+ return ctx->traverse(ctx, fn, private_data);
+}
+
+int connections_forall(int (*fn)(struct db_record *rec,
+ const struct connections_key *key,
+ const struct connections_data *data,
+ void *private_data),
+ void *private_data)
+{
+ struct conn_traverse_state state;
+
+ state.fn = fn;
+ state.private_data = private_data;
+
+ return connections_traverse(conn_traverse_fn, (void *)&state);
+}
+
+bool connections_init(bool rw)
+{
+ return (connections_db_ctx(rw) != NULL);
+}
diff --git a/source3/lib/crc32.c b/source3/lib/crc32.c
new file mode 100644
index 0000000000..a4ae90c469
--- /dev/null
+++ b/source3/lib/crc32.c
@@ -0,0 +1,103 @@
+/*-
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ *
+ * First, the polynomial itself and its table of feedback terms. The
+ * polynomial is
+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ * Note that we take it "backwards" and put the highest-order term in
+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the
+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in
+ * the MSB being 1
+ *
+ * Note that the usual hardware shift register implementation, which
+ * is what we're using (we're merely optimizing it by doing eight-bit
+ * chunks at a time) shifts bits into the lowest-order term. In our
+ * implementation, that means shifting towards the right. Why do we
+ * do it this way? Because the calculated CRC must be transmitted in
+ * order from highest-order term to lowest-order term. UARTs transmit
+ * characters in order from LSB to MSB. By storing the CRC this way
+ * we hand it to the UART in the order low-byte to high-byte; the UART
+ * sends each low-bit to hight-bit; and the result is transmission bit
+ * by bit from highest- to lowest-order term without requiring any bit
+ * shuffling on our part. Reception works similarly
+ *
+ * The feedback terms table consists of 256, 32-bit entries. Notes
+ *
+ * The table can be generated at runtime if desired; code to do so
+ * is shown later. It might not be obvious, but the feedback
+ * terms simply represent the results of eight shift/xor opera
+ * tions for all combinations of data and CRC register values
+ *
+ * The values must be right-shifted by eight bits by the "updcrc
+ * logic; the shift must be unsigned (bring in zeroes). On some
+ * hardware you could probably optimize the shift in assembler by
+ * using byte-swap instructions
+ * polynomial $edb88320
+ *
+ *
+ * CRC32 code derived from work by Gary S. Brown.
+ */
+
+#include "includes.h"
+
+static const uint32 crc32_tab[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+uint32 crc32_calc_buffer(const char *buf, size_t size)
+{
+ const unsigned char *p;
+ uint32 crc;
+
+ p = (const unsigned char *)buf;
+ crc = ~0U;
+
+ while (size--)
+ crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+
+ return crc ^ ~0U;
+}
diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c
new file mode 100644
index 0000000000..1ae23bcf82
--- /dev/null
+++ b/source3/lib/ctdbd_conn.c
@@ -0,0 +1,1247 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba internal messaging functions
+ Copyright (C) 2007 by Volker Lendecke
+ Copyright (C) 2007 by Andrew Tridgell
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef CLUSTER_SUPPORT
+
+#include "librpc/gen_ndr/messaging.h"
+#include "librpc/gen_ndr/ndr_messaging.h"
+
+/* paths to these include files come from --with-ctdb= in configure */
+#include "ctdb.h"
+#include "ctdb_private.h"
+
+struct ctdbd_connection {
+ struct messaging_context *msg_ctx;
+ uint32 reqid;
+ uint32 our_vnn;
+ uint64 rand_srvid;
+ struct packet_context *pkt;
+ struct fd_event *fde;
+
+ void (*release_ip_handler)(const char *ip_addr, void *private_data);
+ void *release_ip_priv;
+};
+
+static NTSTATUS ctdbd_control(struct ctdbd_connection *conn,
+ uint32_t vnn, uint32 opcode,
+ uint64_t srvid, uint32_t flags, TDB_DATA data,
+ TALLOC_CTX *mem_ctx, TDB_DATA *outdata,
+ int *cstatus);
+
+/*
+ * exit on fatal communications errors with the ctdbd daemon
+ */
+static void cluster_fatal(const char *why)
+{
+ DEBUG(0,("cluster fatal event: %s - exiting immediately\n", why));
+ /* we don't use smb_panic() as we don't want to delay to write
+ a core file. We need to release this process id immediately
+ so that someone else can take over without getting sharing
+ violations */
+ _exit(0);
+}
+
+/*
+ *
+ */
+static void ctdb_packet_dump(struct ctdb_req_header *hdr)
+{
+ if (DEBUGLEVEL < 10) {
+ return;
+ }
+ DEBUGADD(10, ("len=%d, magic=%x, vers=%d, gen=%d, op=%d, reqid=%d\n",
+ (int)hdr->length, (int)hdr->ctdb_magic,
+ (int)hdr->ctdb_version, (int)hdr->generation,
+ (int)hdr->operation, (int)hdr->reqid));
+}
+
+/*
+ * Register a srvid with ctdbd
+ */
+static NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn,
+ uint64_t srvid)
+{
+
+ int cstatus;
+ return ctdbd_control(conn, CTDB_CURRENT_NODE,
+ CTDB_CONTROL_REGISTER_SRVID, srvid, 0,
+ tdb_null, NULL, NULL, &cstatus);
+}
+
+/*
+ * get our vnn from the cluster
+ */
+static NTSTATUS get_cluster_vnn(struct ctdbd_connection *conn, uint32 *vnn)
+{
+ int32_t cstatus=-1;
+ NTSTATUS status;
+ status = ctdbd_control(conn,
+ CTDB_CURRENT_NODE, CTDB_CONTROL_GET_PNN, 0, 0,
+ tdb_null, NULL, NULL, &cstatus);
+ if (!NT_STATUS_IS_OK(status)) {
+ cluster_fatal("ctdbd_control failed\n");
+ }
+ *vnn = (uint32_t)cstatus;
+ return status;
+}
+
+uint32 ctdbd_vnn(const struct ctdbd_connection *conn)
+{
+ return conn->our_vnn;
+}
+
+/*
+ * Get us a ctdb connection
+ */
+
+static NTSTATUS ctdbd_connect(TALLOC_CTX *mem_ctx,
+ struct packet_context **presult)
+{
+ struct packet_context *result;
+ const char *sockname = lp_ctdbd_socket();
+ struct sockaddr_un addr;
+ int fd;
+
+ if (!sockname || !*sockname) {
+ sockname = CTDB_PATH;
+ }
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd == -1) {
+ DEBUG(3, ("Could not create socket: %s\n", strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+
+ ZERO_STRUCT(addr);
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, sockname, sizeof(addr.sun_path));
+
+ if (sys_connect(fd, (struct sockaddr *)&addr) == -1) {
+ DEBUG(1, ("connect(%s) failed: %s\n", sockname,
+ strerror(errno)));
+ close(fd);
+ return map_nt_error_from_unix(errno);
+ }
+
+ if (!(result = packet_init(mem_ctx, fd))) {
+ close(fd);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *presult = result;
+ return NT_STATUS_OK;
+}
+
+/*
+ * Do we have a complete ctdb packet in the queue?
+ */
+
+static bool ctdb_req_complete(const struct data_blob *data,
+ size_t *length,
+ void *private_data)
+{
+ uint32 msglen;
+
+ if (data->length < sizeof(msglen)) {
+ return False;
+ }
+
+ msglen = *((uint32 *)data->data);
+
+ DEBUG(10, ("msglen = %d\n", msglen));
+
+ if (msglen < sizeof(struct ctdb_req_header)) {
+ DEBUG(0, ("Got invalid msglen: %d, expected at least %d for "
+ "the req_header\n", (int)msglen,
+ (int)sizeof(struct ctdb_req_header)));
+ cluster_fatal("ctdbd protocol error\n");
+ }
+
+ if (data->length >= msglen) {
+ *length = msglen;
+ return True;
+ }
+
+ return False;
+}
+
+/*
+ * State necessary to defer an incoming message while we are waiting for a
+ * ctdb reply.
+ */
+
+struct deferred_msg_state {
+ struct messaging_context *msg_ctx;
+ struct messaging_rec *rec;
+};
+
+/*
+ * Timed event handler for the deferred message
+ */
+
+static void deferred_message_dispatch(struct event_context *event_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ struct deferred_msg_state *state = talloc_get_type_abort(
+ private_data, struct deferred_msg_state);
+
+ messaging_dispatch_rec(state->msg_ctx, state->rec);
+ TALLOC_FREE(state);
+ TALLOC_FREE(te);
+}
+
+struct req_pull_state {
+ TALLOC_CTX *mem_ctx;
+ DATA_BLOB req;
+};
+
+/*
+ * Pull a ctdb request out of the incoming packet queue
+ */
+
+static NTSTATUS ctdb_req_pull(const struct data_blob *data,
+ void *private_data)
+{
+ struct req_pull_state *state = (struct req_pull_state *)private_data;
+
+ state->req = data_blob_talloc(state->mem_ctx, data->data,
+ data->length);
+ if (state->req.data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+/*
+ * Fetch a messaging_rec from an incoming ctdb style message
+ */
+
+static struct messaging_rec *ctdb_pull_messaging_rec(TALLOC_CTX *mem_ctx,
+ size_t overall_length,
+ struct ctdb_req_message *msg)
+{
+ struct messaging_rec *result;
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ if ((overall_length < offsetof(struct ctdb_req_message, data))
+ || (overall_length
+ < offsetof(struct ctdb_req_message, data) + msg->datalen)) {
+
+ cluster_fatal("got invalid msg length");
+ }
+
+ if (!(result = TALLOC_P(mem_ctx, struct messaging_rec))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ blob = data_blob_const(msg->data, msg->datalen);
+
+ ndr_err = ndr_pull_struct_blob(
+ &blob, result, result,
+ (ndr_pull_flags_fn_t)ndr_pull_messaging_rec);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_pull_struct_blob failed: %s\n",
+ ndr_errstr(ndr_err)));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ DEBUG(10, ("ctdb_pull_messaging_rec:\n"));
+ NDR_PRINT_DEBUG(messaging_rec, result);
+ }
+
+ return result;
+}
+
+/*
+ * Read a full ctdbd request. If we have a messaging context, defer incoming
+ * messages that might come in between.
+ */
+
+static NTSTATUS ctdb_read_req(struct ctdbd_connection *conn, uint32 reqid,
+ TALLOC_CTX *mem_ctx, void *result)
+{
+ struct ctdb_req_header *hdr;
+ struct req_pull_state state;
+ NTSTATUS status;
+
+ again:
+
+ status = packet_fd_read_sync(conn->pkt);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_BUSY)) {
+ /* EAGAIN */
+ goto again;
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
+ /* EAGAIN */
+ goto again;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("packet_fd_read failed: %s\n", nt_errstr(status)));
+ cluster_fatal("ctdbd died\n");
+ }
+
+ next_pkt:
+
+ ZERO_STRUCT(state);
+ state.mem_ctx = mem_ctx;
+
+ if (!packet_handler(conn->pkt, ctdb_req_complete, ctdb_req_pull,
+ &state, &status)) {
+ /*
+ * Not enough data
+ */
+ DEBUG(10, ("not enough data from ctdb socket, retrying\n"));
+ goto again;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Could not read packet: %s\n", nt_errstr(status)));
+ cluster_fatal("ctdbd died\n");
+ }
+
+ hdr = (struct ctdb_req_header *)state.req.data;
+
+ DEBUG(10, ("Received ctdb packet\n"));
+ ctdb_packet_dump(hdr);
+
+ if (hdr->operation == CTDB_REQ_MESSAGE) {
+ struct timed_event *evt;
+ struct deferred_msg_state *msg_state;
+ struct ctdb_req_message *msg = (struct ctdb_req_message *)hdr;
+
+ if (conn->msg_ctx == NULL) {
+ DEBUG(1, ("Got a message without having a msg ctx, "
+ "dropping msg %llu\n",
+ (long long unsigned)msg->srvid));
+ goto next_pkt;
+ }
+
+ if ((conn->release_ip_handler != NULL)
+ && (msg->srvid == CTDB_SRVID_RELEASE_IP)) {
+ /* must be dispatched immediately */
+ DEBUG(10, ("received CTDB_SRVID_RELEASE_IP\n"));
+ conn->release_ip_handler((const char *)msg->data,
+ conn->release_ip_priv);
+ TALLOC_FREE(hdr);
+ goto next_pkt;
+ }
+
+ if (msg->srvid == CTDB_SRVID_RECONFIGURE) {
+ DEBUG(0,("Got cluster reconfigure message in ctdb_read_req\n"));
+ messaging_send(conn->msg_ctx, procid_self(),
+ MSG_SMB_BRL_VALIDATE, &data_blob_null);
+ TALLOC_FREE(hdr);
+ goto next_pkt;
+ }
+
+ if (!(msg_state = TALLOC_P(NULL, struct deferred_msg_state))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(hdr);
+ goto next_pkt;
+ }
+
+ if (!(msg_state->rec = ctdb_pull_messaging_rec(
+ msg_state, state.req.length, msg))) {
+ DEBUG(0, ("ctdbd_pull_messaging_rec failed\n"));
+ TALLOC_FREE(msg_state);
+ TALLOC_FREE(hdr);
+ goto next_pkt;
+ }
+
+ TALLOC_FREE(hdr);
+
+ msg_state->msg_ctx = conn->msg_ctx;
+
+ /*
+ * We're waiting for a call reply, but an async message has
+ * crossed. Defer dispatching to the toplevel event loop.
+ */
+ evt = event_add_timed(conn->msg_ctx->event_ctx,
+ conn->msg_ctx->event_ctx,
+ timeval_zero(),
+ "deferred_message_dispatch",
+ deferred_message_dispatch,
+ msg_state);
+ if (evt == NULL) {
+ DEBUG(0, ("event_add_timed failed\n"));
+ TALLOC_FREE(msg_state);
+ TALLOC_FREE(hdr);
+ goto next_pkt;
+ }
+
+ goto next_pkt;
+ }
+
+ if (hdr->reqid != reqid) {
+ /* we got the wrong reply */
+ DEBUG(0,("Discarding mismatched ctdb reqid %u should have "
+ "been %u\n", hdr->reqid, reqid));
+ TALLOC_FREE(hdr);
+ goto again;
+ }
+
+ *((void **)result) = talloc_move(mem_ctx, &hdr);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * Get us a ctdbd connection
+ */
+
+NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx,
+ struct ctdbd_connection **pconn)
+{
+ struct ctdbd_connection *conn;
+ NTSTATUS status;
+
+ if (!(conn = TALLOC_ZERO_P(mem_ctx, struct ctdbd_connection))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = ctdbd_connect(conn, &conn->pkt);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("ctdbd_connect failed: %s\n", nt_errstr(status)));
+ goto fail;
+ }
+
+ status = get_cluster_vnn(conn, &conn->our_vnn);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("get_cluster_vnn failed: %s\n", nt_errstr(status)));
+ goto fail;
+ }
+
+ generate_random_buffer((unsigned char *)&conn->rand_srvid,
+ sizeof(conn->rand_srvid));
+
+ status = register_with_ctdbd(conn, conn->rand_srvid);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("Could not register random srvid: %s\n",
+ nt_errstr(status)));
+ goto fail;
+ }
+
+ *pconn = conn;
+ return NT_STATUS_OK;
+
+ fail:
+ TALLOC_FREE(conn);
+ return status;
+}
+
+/*
+ * Get us a ctdbd connection and register us as a process
+ */
+
+NTSTATUS ctdbd_messaging_connection(TALLOC_CTX *mem_ctx,
+ struct ctdbd_connection **pconn)
+{
+ struct ctdbd_connection *conn;
+ NTSTATUS status;
+
+ status = ctdbd_init_connection(mem_ctx, &conn);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = register_with_ctdbd(conn, (uint64_t)sys_getpid());
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ status = register_with_ctdbd(conn, MSG_SRVID_SAMBA);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ *pconn = conn;
+ return NT_STATUS_OK;
+
+ fail:
+ TALLOC_FREE(conn);
+ return status;
+}
+
+/*
+ * Packet handler to receive and handle a ctdb message
+ */
+static NTSTATUS ctdb_handle_message(const struct data_blob *data,
+ void *private_data)
+{
+ struct ctdbd_connection *conn = talloc_get_type_abort(
+ private_data, struct ctdbd_connection);
+ struct ctdb_req_message *msg;
+ struct messaging_rec *msg_rec;
+
+ msg = (struct ctdb_req_message *)data->data;
+
+ if (msg->hdr.operation != CTDB_REQ_MESSAGE) {
+ DEBUG(0, ("Received async msg of type %u, discarding\n",
+ msg->hdr.operation));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if ((conn->release_ip_handler != NULL)
+ && (msg->srvid == CTDB_SRVID_RELEASE_IP)) {
+ /* must be dispatched immediately */
+ DEBUG(10, ("received CTDB_SRVID_RELEASE_IP\n"));
+ conn->release_ip_handler((const char *)msg->data,
+ conn->release_ip_priv);
+ return NT_STATUS_OK;
+ }
+
+ SMB_ASSERT(conn->msg_ctx != NULL);
+
+ if (msg->srvid == CTDB_SRVID_RECONFIGURE) {
+ DEBUG(0,("Got cluster reconfigure message\n"));
+ /*
+ * when the cluster is reconfigured, we need to clean the brl
+ * database
+ */
+ messaging_send(conn->msg_ctx, procid_self(),
+ MSG_SMB_BRL_VALIDATE, &data_blob_null);
+
+ /*
+ * it's possible that we have just rejoined the cluster after
+ * an outage. In that case our pending locks could have been
+ * removed from the lockdb, so retry them once more
+ */
+ message_send_all(conn->msg_ctx, MSG_SMB_UNLOCK, NULL, 0, NULL);
+
+ return NT_STATUS_OK;
+
+ }
+
+ /* only messages to our pid or the broadcast are valid here */
+ if (msg->srvid != sys_getpid() && msg->srvid != MSG_SRVID_SAMBA) {
+ DEBUG(0,("Got unexpected message with srvid=%llu\n",
+ (unsigned long long)msg->srvid));
+ return NT_STATUS_OK;
+ }
+
+ if (!(msg_rec = ctdb_pull_messaging_rec(NULL, data->length, msg))) {
+ DEBUG(10, ("ctdb_pull_messaging_rec failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ messaging_dispatch_rec(conn->msg_ctx, msg_rec);
+
+ TALLOC_FREE(msg_rec);
+ return NT_STATUS_OK;
+}
+
+/*
+ * The ctdbd socket is readable asynchronuously
+ */
+
+static void ctdbd_socket_handler(struct event_context *event_ctx,
+ struct fd_event *event,
+ uint16 flags,
+ void *private_data)
+{
+ struct ctdbd_connection *conn = talloc_get_type_abort(
+ private_data, struct ctdbd_connection);
+
+ NTSTATUS status;
+
+ status = packet_fd_read(conn->pkt);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("packet_fd_read failed: %s\n", nt_errstr(status)));
+ cluster_fatal("ctdbd died\n");
+ }
+
+ while (packet_handler(conn->pkt, ctdb_req_complete,
+ ctdb_handle_message, conn, &status)) {
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("could not handle incoming message: %s\n",
+ nt_errstr(status)));
+ }
+ }
+}
+
+/*
+ * Prepare a ctdbd connection to receive messages
+ */
+
+NTSTATUS ctdbd_register_msg_ctx(struct ctdbd_connection *conn,
+ struct messaging_context *msg_ctx)
+{
+ SMB_ASSERT(conn->msg_ctx == NULL);
+ SMB_ASSERT(conn->fde == NULL);
+
+ if (!(conn->fde = event_add_fd(msg_ctx->event_ctx, conn,
+ packet_get_fd(conn->pkt),
+ EVENT_FD_READ,
+ ctdbd_socket_handler,
+ conn))) {
+ DEBUG(0, ("event_add_fd failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ conn->msg_ctx = msg_ctx;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * Send a messaging message across a ctdbd
+ */
+
+NTSTATUS ctdbd_messaging_send(struct ctdbd_connection *conn,
+ uint32 dst_vnn, uint64 dst_srvid,
+ struct messaging_rec *msg)
+{
+ struct ctdb_req_message r;
+ TALLOC_CTX *mem_ctx;
+ DATA_BLOB blob;
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+
+ if (!(mem_ctx = talloc_init("ctdbd_messaging_send"))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ndr_err = ndr_push_struct_blob(
+ &blob, mem_ctx, msg,
+ (ndr_push_flags_fn_t)ndr_push_messaging_rec);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_push_struct_blob failed: %s\n",
+ ndr_errstr(ndr_err)));
+ status = ndr_map_error2ntstatus(ndr_err);
+ goto fail;
+ }
+
+ r.hdr.length = offsetof(struct ctdb_req_message, data) + blob.length;
+ r.hdr.ctdb_magic = CTDB_MAGIC;
+ r.hdr.ctdb_version = CTDB_VERSION;
+ r.hdr.generation = 1;
+ r.hdr.operation = CTDB_REQ_MESSAGE;
+ r.hdr.destnode = dst_vnn;
+ r.hdr.srcnode = conn->our_vnn;
+ r.hdr.reqid = 0;
+ r.srvid = dst_srvid;
+ r.datalen = blob.length;
+
+ DEBUG(10, ("ctdbd_messaging_send: Sending ctdb packet\n"));
+ ctdb_packet_dump(&r.hdr);
+
+ status = packet_send(
+ conn->pkt, 2,
+ data_blob_const(&r, offsetof(struct ctdb_req_message, data)),
+ blob);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("packet_send failed: %s\n", nt_errstr(status)));
+ goto fail;
+ }
+
+ status = packet_flush(conn->pkt);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("write to ctdbd failed: %s\n", nt_errstr(status)));
+ cluster_fatal("cluster dispatch daemon msg write error\n");
+ }
+
+ status = NT_STATUS_OK;
+ fail:
+ TALLOC_FREE(mem_ctx);
+ return status;
+}
+
+/*
+ * send/recv a generic ctdb control message
+ */
+static NTSTATUS ctdbd_control(struct ctdbd_connection *conn,
+ uint32_t vnn, uint32 opcode,
+ uint64_t srvid, uint32_t flags,
+ TDB_DATA data,
+ TALLOC_CTX *mem_ctx, TDB_DATA *outdata,
+ int *cstatus)
+{
+ struct ctdb_req_control req;
+ struct ctdb_reply_control *reply = NULL;
+ struct ctdbd_connection *new_conn = NULL;
+ NTSTATUS status;
+
+ /* the samba3 ctdb code can't handle NOREPLY yet */
+ flags &= ~CTDB_CTRL_FLAG_NOREPLY;
+
+ if (conn == NULL) {
+ status = ctdbd_init_connection(NULL, &new_conn);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Could not init temp connection: %s\n",
+ nt_errstr(status)));
+ goto fail;
+ }
+
+ conn = new_conn;
+ }
+
+ ZERO_STRUCT(req);
+ req.hdr.length = offsetof(struct ctdb_req_control, data) + data.dsize;
+ req.hdr.ctdb_magic = CTDB_MAGIC;
+ req.hdr.ctdb_version = CTDB_VERSION;
+ req.hdr.operation = CTDB_REQ_CONTROL;
+ req.hdr.reqid = ++conn->reqid;
+ req.hdr.destnode = vnn;
+ req.opcode = opcode;
+ req.srvid = srvid;
+ req.datalen = data.dsize;
+
+ DEBUG(10, ("ctdbd_control: Sending ctdb packet\n"));
+ ctdb_packet_dump(&req.hdr);
+
+ status = packet_send(
+ conn->pkt, 2,
+ data_blob_const(&req, offsetof(struct ctdb_req_control, data)),
+ data_blob_const(data.dptr, data.dsize));
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("packet_send failed: %s\n", nt_errstr(status)));
+ goto fail;
+ }
+
+ status = packet_flush(conn->pkt);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("write to ctdbd failed: %s\n", nt_errstr(status)));
+ cluster_fatal("cluster dispatch daemon control write error\n");
+ }
+
+ if (flags & CTDB_CTRL_FLAG_NOREPLY) {
+ TALLOC_FREE(new_conn);
+ return NT_STATUS_OK;
+ }
+
+ status = ctdb_read_req(conn, req.hdr.reqid, NULL, (void *)&reply);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("ctdb_read_req failed: %s\n", nt_errstr(status)));
+ goto fail;
+ }
+
+ if (reply->hdr.operation != CTDB_REPLY_CONTROL) {
+ DEBUG(0, ("received invalid reply\n"));
+ goto fail;
+ }
+
+ if (outdata) {
+ if (!(outdata->dptr = (uint8 *)talloc_memdup(
+ mem_ctx, reply->data, reply->datalen))) {
+ TALLOC_FREE(reply);
+ return NT_STATUS_NO_MEMORY;
+ }
+ outdata->dsize = reply->datalen;
+ }
+ if (cstatus) {
+ (*cstatus) = reply->status;
+ }
+
+ status = NT_STATUS_OK;
+
+ fail:
+ TALLOC_FREE(new_conn);
+ TALLOC_FREE(reply);
+ return status;
+}
+
+/*
+ * see if a remote process exists
+ */
+bool ctdbd_process_exists(struct ctdbd_connection *conn, uint32 vnn, pid_t pid)
+{
+ NTSTATUS status;
+ TDB_DATA data;
+ int32_t cstatus;
+
+ data.dptr = (uint8_t*)&pid;
+ data.dsize = sizeof(pid);
+
+ status = ctdbd_control(conn, vnn, CTDB_CONTROL_PROCESS_EXISTS, 0, 0,
+ data, NULL, NULL, &cstatus);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, (__location__ " ctdb_control for process_exists "
+ "failed\n"));
+ return False;
+ }
+
+ return cstatus == 0;
+}
+
+/*
+ * Get a db path
+ */
+char *ctdbd_dbpath(struct ctdbd_connection *conn,
+ TALLOC_CTX *mem_ctx, uint32_t db_id)
+{
+ NTSTATUS status;
+ TDB_DATA data;
+ int32_t cstatus;
+
+ data.dptr = (uint8_t*)&db_id;
+ data.dsize = sizeof(db_id);
+
+ status = ctdbd_control(conn, CTDB_CURRENT_NODE,
+ CTDB_CONTROL_GETDBPATH, 0, 0, data,
+ mem_ctx, &data, &cstatus);
+ if (!NT_STATUS_IS_OK(status) || cstatus != 0) {
+ DEBUG(0,(__location__ " ctdb_control for getdbpath failed\n"));
+ return NULL;
+ }
+
+ return (char *)data.dptr;
+}
+
+/*
+ * attach to a ctdb database
+ */
+NTSTATUS ctdbd_db_attach(struct ctdbd_connection *conn,
+ const char *name, uint32_t *db_id, int tdb_flags)
+{
+ NTSTATUS status;
+ TDB_DATA data;
+ int32_t cstatus;
+ bool persistent = (tdb_flags & TDB_CLEAR_IF_FIRST) == 0;
+
+ data.dptr = (uint8_t*)name;
+ data.dsize = strlen(name)+1;
+
+ status = ctdbd_control(conn, CTDB_CURRENT_NODE,
+ persistent
+ ? CTDB_CONTROL_DB_ATTACH_PERSISTENT
+ : CTDB_CONTROL_DB_ATTACH,
+ 0, 0, data, NULL, &data, &cstatus);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, (__location__ " ctdb_control for db_attach "
+ "failed: %s\n", nt_errstr(status)));
+ return status;
+ }
+
+ if (cstatus != 0 || data.dsize != sizeof(uint32_t)) {
+ DEBUG(0,(__location__ " ctdb_control for db_attach failed\n"));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ *db_id = *(uint32_t *)data.dptr;
+ talloc_free(data.dptr);
+
+ if (!(tdb_flags & TDB_SEQNUM)) {
+ return NT_STATUS_OK;
+ }
+
+ data.dptr = (uint8_t *)db_id;
+ data.dsize = sizeof(*db_id);
+
+ status = ctdbd_control(conn, CTDB_CURRENT_NODE,
+ CTDB_CONTROL_ENABLE_SEQNUM, 0, 0, data,
+ NULL, NULL, &cstatus);
+ if (!NT_STATUS_IS_OK(status) || cstatus != 0) {
+ DEBUG(0,(__location__ " ctdb_control for enable seqnum "
+ "failed\n"));
+ return NT_STATUS_IS_OK(status) ? NT_STATUS_INTERNAL_ERROR :
+ status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * force the migration of a record to this node
+ */
+NTSTATUS ctdbd_migrate(struct ctdbd_connection *conn, uint32 db_id,
+ TDB_DATA key)
+{
+ struct ctdb_req_call req;
+ struct ctdb_reply_call *reply;
+ NTSTATUS status;
+
+ ZERO_STRUCT(req);
+
+ req.hdr.length = offsetof(struct ctdb_req_call, data) + key.dsize;
+ req.hdr.ctdb_magic = CTDB_MAGIC;
+ req.hdr.ctdb_version = CTDB_VERSION;
+ req.hdr.operation = CTDB_REQ_CALL;
+ req.hdr.reqid = ++conn->reqid;
+ req.flags = CTDB_IMMEDIATE_MIGRATION;
+ req.callid = CTDB_NULL_FUNC;
+ req.db_id = db_id;
+ req.keylen = key.dsize;
+
+ DEBUG(10, ("ctdbd_migrate: Sending ctdb packet\n"));
+ ctdb_packet_dump(&req.hdr);
+
+ status = packet_send(
+ conn->pkt, 2,
+ data_blob_const(&req, offsetof(struct ctdb_req_call, data)),
+ data_blob_const(key.dptr, key.dsize));
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("packet_send failed: %s\n", nt_errstr(status)));
+ return status;
+ }
+
+ status = packet_flush(conn->pkt);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("write to ctdbd failed: %s\n", nt_errstr(status)));
+ cluster_fatal("cluster dispatch daemon control write error\n");
+ }
+
+ status = ctdb_read_req(conn, req.hdr.reqid, NULL, (void *)&reply);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("ctdb_read_req failed: %s\n", nt_errstr(status)));
+ goto fail;
+ }
+
+ if (reply->hdr.operation != CTDB_REPLY_CALL) {
+ DEBUG(0, ("received invalid reply\n"));
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto fail;
+ }
+
+ status = NT_STATUS_OK;
+ fail:
+
+ TALLOC_FREE(reply);
+ return status;
+}
+
+/*
+ * remotely fetch a record without locking it or forcing a migration
+ */
+NTSTATUS ctdbd_fetch(struct ctdbd_connection *conn, uint32 db_id,
+ TDB_DATA key, TALLOC_CTX *mem_ctx, TDB_DATA *data)
+{
+ struct ctdb_req_call req;
+ struct ctdb_reply_call *reply;
+ NTSTATUS status;
+
+ ZERO_STRUCT(req);
+
+ req.hdr.length = offsetof(struct ctdb_req_call, data) + key.dsize;
+ req.hdr.ctdb_magic = CTDB_MAGIC;
+ req.hdr.ctdb_version = CTDB_VERSION;
+ req.hdr.operation = CTDB_REQ_CALL;
+ req.hdr.reqid = ++conn->reqid;
+ req.flags = 0;
+ req.callid = CTDB_FETCH_FUNC;
+ req.db_id = db_id;
+ req.keylen = key.dsize;
+
+ status = packet_send(
+ conn->pkt, 2,
+ data_blob_const(&req, offsetof(struct ctdb_req_call, data)),
+ data_blob_const(key.dptr, key.dsize));
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("packet_send failed: %s\n", nt_errstr(status)));
+ return status;
+ }
+
+ status = packet_flush(conn->pkt);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("write to ctdbd failed: %s\n", nt_errstr(status)));
+ cluster_fatal("cluster dispatch daemon control write error\n");
+ }
+
+ status = ctdb_read_req(conn, req.hdr.reqid, NULL, (void *)&reply);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("ctdb_read_req failed: %s\n", nt_errstr(status)));
+ goto fail;
+ }
+
+ if (reply->hdr.operation != CTDB_REPLY_CALL) {
+ DEBUG(0, ("received invalid reply\n"));
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto fail;
+ }
+
+ data->dsize = reply->datalen;
+ if (data->dsize == 0) {
+ data->dptr = NULL;
+ goto done;
+ }
+
+ data->dptr = (uint8 *)talloc_memdup(mem_ctx, &reply->data[0],
+ reply->datalen);
+ if (data->dptr == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ done:
+ status = NT_STATUS_OK;
+ fail:
+ TALLOC_FREE(reply);
+ return status;
+}
+
+struct ctdbd_traverse_state {
+ void (*fn)(TDB_DATA key, TDB_DATA data, void *private_data);
+ void *private_data;
+};
+
+/*
+ * Handle a traverse record coming in on the ctdbd connection
+ */
+
+static NTSTATUS ctdb_traverse_handler(const struct data_blob *blob,
+ void *private_data)
+{
+ struct ctdbd_traverse_state *state =
+ (struct ctdbd_traverse_state *)private_data;
+
+ struct ctdb_req_message *m;
+ struct ctdb_rec_data *d;
+ TDB_DATA key, data;
+
+ m = (struct ctdb_req_message *)blob->data;
+
+ if (blob->length < sizeof(*m) || m->hdr.length != blob->length) {
+ DEBUG(0, ("Got invalid message of length %d\n",
+ (int)blob->length));
+ return NT_STATUS_UNEXPECTED_IO_ERROR;
+ }
+
+ d = (struct ctdb_rec_data *)&m->data[0];
+ if (m->datalen < sizeof(uint32_t) || m->datalen != d->length) {
+ DEBUG(0, ("Got invalid traverse data of length %d\n",
+ (int)m->datalen));
+ return NT_STATUS_UNEXPECTED_IO_ERROR;
+ }
+
+ key.dsize = d->keylen;
+ key.dptr = &d->data[0];
+ data.dsize = d->datalen;
+ data.dptr = &d->data[d->keylen];
+
+ if (key.dsize == 0 && data.dsize == 0) {
+ /* end of traverse */
+ return NT_STATUS_END_OF_FILE;
+ }
+
+ if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
+ DEBUG(0, ("Got invalid ltdb header length %d\n",
+ (int)data.dsize));
+ return NT_STATUS_UNEXPECTED_IO_ERROR;
+ }
+ data.dsize -= sizeof(struct ctdb_ltdb_header);
+ data.dptr += sizeof(struct ctdb_ltdb_header);
+
+ if (state->fn) {
+ state->fn(key, data, state->private_data);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ Traverse a ctdb database. This uses a kind-of hackish way to open a second
+ connection to ctdbd to avoid the hairy recursive and async problems with
+ everything in-line.
+*/
+
+NTSTATUS ctdbd_traverse(uint32 db_id,
+ void (*fn)(TDB_DATA key, TDB_DATA data,
+ void *private_data),
+ void *private_data)
+{
+ struct ctdbd_connection *conn;
+ NTSTATUS status;
+
+ TDB_DATA data;
+ struct ctdb_traverse_start t;
+ int cstatus;
+ struct ctdbd_traverse_state state;
+
+ status = ctdbd_init_connection(NULL, &conn);
+
+ t.db_id = db_id;
+ t.srvid = conn->rand_srvid;
+ t.reqid = ++conn->reqid;
+
+ data.dptr = (uint8_t *)&t;
+ data.dsize = sizeof(t);
+
+ status = ctdbd_control(conn, CTDB_CURRENT_NODE,
+ CTDB_CONTROL_TRAVERSE_START, conn->rand_srvid, 0,
+ data, NULL, NULL, &cstatus);
+
+ if (!NT_STATUS_IS_OK(status) || (cstatus != 0)) {
+
+ DEBUG(0,("ctdbd_control failed: %s, %d\n", nt_errstr(status),
+ cstatus));
+
+ if (NT_STATUS_IS_OK(status)) {
+ /*
+ * We need a mapping here
+ */
+ status = NT_STATUS_UNSUCCESSFUL;
+ }
+ goto done;
+ }
+
+ state.fn = fn;
+ state.private_data = private_data;
+
+ while (True) {
+
+ status = NT_STATUS_OK;
+
+ if (packet_handler(conn->pkt, ctdb_req_complete,
+ ctdb_traverse_handler, &state, &status)) {
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
+ status = NT_STATUS_OK;
+ break;
+ }
+
+ /*
+ * There might be more in the queue
+ */
+ continue;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ break;
+ }
+
+ status = packet_fd_read_sync(conn->pkt);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
+ /*
+ * There might be more in the queue
+ */
+ continue;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
+ status = NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("packet_fd_read_sync failed: %s\n", nt_errstr(status)));
+ cluster_fatal("ctdbd died\n");
+ }
+ }
+
+ done:
+ TALLOC_FREE(conn);
+ return status;
+}
+
+/*
+ * Register us as a server for a particular tcp connection
+ */
+
+NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn,
+ const struct sockaddr_in *server,
+ const struct sockaddr_in *client,
+ void (*release_ip_handler)(const char *ip_addr,
+ void *private_data),
+ void *private_data)
+{
+ struct ctdb_control_tcp p;
+ TDB_DATA data;
+ NTSTATUS status;
+
+ /*
+ * Only one connection so far
+ */
+ SMB_ASSERT(conn->release_ip_handler == NULL);
+
+ conn->release_ip_handler = release_ip_handler;
+
+ /*
+ * We want to be told about IP releases
+ */
+
+ status = register_with_ctdbd(conn, CTDB_SRVID_RELEASE_IP);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ p.dest = *server;
+ p.src = *client;
+
+ /*
+ * inform ctdb of our tcp connection, so if IP takeover happens ctdb
+ * can send an extra ack to trigger a reset for our client, so it
+ * immediately reconnects
+ */
+ data.dptr = (uint8_t *)&p;
+ data.dsize = sizeof(p);
+
+ return ctdbd_control(conn, CTDB_CURRENT_NODE,
+ CTDB_CONTROL_TCP_CLIENT, 0,
+ CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL, NULL);
+}
+
+/*
+ * We want to handle reconfigure events
+ */
+NTSTATUS ctdbd_register_reconfigure(struct ctdbd_connection *conn)
+{
+ return register_with_ctdbd(conn, CTDB_SRVID_RECONFIGURE);
+}
+
+/*
+ call a control on the local node
+ */
+NTSTATUS ctdbd_control_local(struct ctdbd_connection *conn, uint32 opcode,
+ uint64_t srvid, uint32_t flags, TDB_DATA data,
+ TALLOC_CTX *mem_ctx, TDB_DATA *outdata,
+ int *cstatus)
+{
+ return ctdbd_control(conn, CTDB_CURRENT_NODE, opcode, srvid, flags, data, mem_ctx, outdata, cstatus);
+}
+
+#else
+
+NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx,
+ struct ctdbd_connection **pconn)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+#endif
diff --git a/source3/lib/data_blob.c b/source3/lib/data_blob.c
new file mode 100644
index 0000000000..66c5daf363
--- /dev/null
+++ b/source3/lib/data_blob.c
@@ -0,0 +1,180 @@
+/*
+ Unix SMB/CIFS implementation.
+ Easy management of byte-length data
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+const DATA_BLOB data_blob_null = { NULL, 0, NULL };
+
+/*******************************************************************
+ Free() a data blob.
+*******************************************************************/
+
+static void free_data_blob(DATA_BLOB *d)
+{
+ if ((d) && (d->free)) {
+ SAFE_FREE(d->data);
+ }
+}
+
+/*******************************************************************
+ Construct a data blob, must be freed with data_blob_free().
+ You can pass NULL for p and get a blank data blob
+*******************************************************************/
+
+DATA_BLOB data_blob(const void *p, size_t length)
+{
+ DATA_BLOB ret;
+
+ if (!length) {
+ ZERO_STRUCT(ret);
+ return ret;
+ }
+
+ if (p) {
+ ret.data = (uint8 *)smb_xmemdup(p, length);
+ } else {
+ ret.data = SMB_XMALLOC_ARRAY(uint8, length);
+ }
+ ret.length = length;
+ ret.free = free_data_blob;
+ return ret;
+}
+
+/*******************************************************************
+ Construct a data blob, using supplied TALLOC_CTX.
+*******************************************************************/
+
+DATA_BLOB data_blob_talloc(TALLOC_CTX *mem_ctx, const void *p, size_t length)
+{
+ DATA_BLOB ret;
+
+ if (!length) {
+ ZERO_STRUCT(ret);
+ return ret;
+ }
+
+ if (p) {
+ ret.data = (uint8 *)TALLOC_MEMDUP(mem_ctx, p, length);
+ if (ret.data == NULL)
+ smb_panic("data_blob_talloc: TALLOC_MEMDUP failed");
+ } else {
+ ret.data = (uint8 *)TALLOC(mem_ctx, length);
+ if (ret.data == NULL)
+ smb_panic("data_blob_talloc: TALLOC failed");
+ }
+
+ ret.length = length;
+ ret.free = NULL;
+ return ret;
+}
+
+/*******************************************************************
+ Free a data blob.
+*******************************************************************/
+
+void data_blob_free(DATA_BLOB *d)
+{
+ if (d) {
+ if (d->free) {
+ (d->free)(d);
+ }
+ d->length = 0;
+ }
+}
+
+/*******************************************************************
+ Clear a DATA_BLOB's contents
+*******************************************************************/
+
+void data_blob_clear(DATA_BLOB *d)
+{
+ if (d->data) {
+ memset(d->data, 0, d->length);
+ }
+}
+
+/*******************************************************************
+ Free a data blob and clear its contents
+*******************************************************************/
+
+void data_blob_clear_free(DATA_BLOB *d)
+{
+ data_blob_clear(d);
+ data_blob_free(d);
+}
+
+/**
+ useful for constructing data blobs in test suites, while
+ avoiding const warnings
+**/
+DATA_BLOB data_blob_string_const(const char *str)
+{
+ DATA_BLOB blob;
+ blob.data = CONST_DISCARD(uint8 *, str);
+ blob.length = strlen(str) + 1;
+ blob.free = NULL;
+ return blob;
+}
+
+/**
+ * Create a new data blob from const data
+ */
+DATA_BLOB data_blob_const(const void *p, size_t length)
+{
+ DATA_BLOB blob;
+ blob.data = CONST_DISCARD(uint8 *, p);
+ blob.length = length;
+ blob.free = NULL;
+ return blob;
+}
+
+/**
+ construct a zero data blob, using supplied TALLOC_CTX.
+ use this sparingly as it initialises data - better to initialise
+ yourself if you want specific data in the blob
+**/
+DATA_BLOB data_blob_talloc_zero(TALLOC_CTX *mem_ctx, size_t length)
+{
+ DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, length);
+ data_blob_clear(&blob);
+ return blob;
+}
+
+/**
+print the data_blob as hex string
+**/
+_PUBLIC_ char *data_blob_hex_string(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob)
+{
+ int i;
+ char *hex_string;
+
+ hex_string = talloc_array(mem_ctx, char, (blob->length*2)+1);
+ if (!hex_string) {
+ return NULL;
+ }
+
+ for (i = 0; i < blob->length; i++)
+ slprintf(&hex_string[i*2], 3, "%02X", blob->data[i]);
+
+ hex_string[(blob->length*2)] = '\0';
+ return hex_string;
+}
+
+
diff --git a/source3/lib/dbwrap.c b/source3/lib/dbwrap.c
new file mode 100644
index 0000000000..73c2761a1b
--- /dev/null
+++ b/source3/lib/dbwrap.c
@@ -0,0 +1,148 @@
+/*
+ Unix SMB/CIFS implementation.
+ Database interface wrapper
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2006
+
+ Major code contributions from Aleksey Fedoseev (fedoseev@ru.ibm.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#ifdef CLUSTER_SUPPORT
+#include "ctdb_private.h"
+#endif
+/*
+ * Fall back using fetch_locked if no genuine fetch operation is provided
+ */
+
+static int dbwrap_fallback_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
+ TDB_DATA key, TDB_DATA *data)
+{
+ struct db_record *rec;
+
+ if (!(rec = db->fetch_locked(db, mem_ctx, key))) {
+ return -1;
+ }
+
+ data->dsize = rec->value.dsize;
+ data->dptr = talloc_move(mem_ctx, &rec->value.dptr);
+ TALLOC_FREE(rec);
+ return 0;
+}
+
+/**
+ * open a database
+ */
+struct db_context *db_open(TALLOC_CTX *mem_ctx,
+ const char *name,
+ int hash_size, int tdb_flags,
+ int open_flags, mode_t mode)
+{
+ struct db_context *result = NULL;
+#ifdef CLUSTER_SUPPORT
+ const char *sockname = lp_ctdbd_socket();
+#endif
+
+#ifdef CLUSTER_SUPPORT
+ if(!sockname || !*sockname) {
+ sockname = CTDB_PATH;
+ }
+
+ if (lp_clustering()) {
+ const char *partname;
+
+ if (!socket_exist(sockname)) {
+ DEBUG(1, ("ctdb socket does not exist - is ctdb not "
+ "running?\n"));
+ return NULL;
+ }
+
+ /* ctdb only wants the file part of the name */
+ partname = strrchr(name, '/');
+ if (partname) {
+ partname++;
+ } else {
+ partname = name;
+ }
+ /* allow ctdb for individual databases to be disabled */
+ if (lp_parm_bool(-1, "ctdb", partname, True)) {
+ result = db_open_ctdb(mem_ctx, partname, hash_size,
+ tdb_flags, open_flags, mode);
+ if (result == NULL) {
+ DEBUG(0,("failed to attach to ctdb %s\n",
+ partname));
+ if (errno == 0) {
+ errno = EIO;
+ }
+ return NULL;
+ }
+ }
+ }
+
+#endif
+
+ if (result == NULL) {
+ result = db_open_tdb(mem_ctx, name, hash_size,
+ tdb_flags, open_flags, mode);
+ }
+
+ if ((result != NULL) && (result->fetch == NULL)) {
+ result->fetch = dbwrap_fallback_fetch;
+ }
+
+ return result;
+}
+
+NTSTATUS dbwrap_delete_bystring(struct db_context *db, const char *key)
+{
+ struct db_record *rec;
+ NTSTATUS status;
+
+ rec = db->fetch_locked(db, talloc_tos(), string_term_tdb_data(key));
+ if (rec == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ status = rec->delete_rec(rec);
+ TALLOC_FREE(rec);
+ return status;
+}
+
+NTSTATUS dbwrap_store_bystring(struct db_context *db, const char *key,
+ TDB_DATA data, int flags)
+{
+ struct db_record *rec;
+ NTSTATUS status;
+
+ rec = db->fetch_locked(db, talloc_tos(), string_term_tdb_data(key));
+ if (rec == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = rec->store(rec, data, flags);
+ TALLOC_FREE(rec);
+ return status;
+}
+
+TDB_DATA dbwrap_fetch_bystring(struct db_context *db, TALLOC_CTX *mem_ctx,
+ const char *key)
+{
+ TDB_DATA result;
+
+ if (db->fetch(db, mem_ctx, string_term_tdb_data(key), &result) == -1) {
+ return make_tdb_data(NULL, 0);
+ }
+
+ return result;
+}
diff --git a/source3/lib/dbwrap_ctdb.c b/source3/lib/dbwrap_ctdb.c
new file mode 100644
index 0000000000..63a5ce4de6
--- /dev/null
+++ b/source3/lib/dbwrap_ctdb.c
@@ -0,0 +1,1223 @@
+/*
+ Unix SMB/CIFS implementation.
+ Database interface wrapper around ctdbd
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#ifdef CLUSTER_SUPPORT
+#include "ctdb.h"
+#include "ctdb_private.h"
+#include "ctdbd_conn.h"
+
+struct db_ctdb_transaction_handle {
+ struct db_ctdb_ctx *ctx;
+ bool in_replay;
+ /* we store the reads and writes done under a transaction one
+ list stores both reads and writes, the other just writes
+ */
+ struct ctdb_marshall_buffer *m_all;
+ struct ctdb_marshall_buffer *m_write;
+ uint32_t nesting;
+ bool nested_cancel;
+};
+
+struct db_ctdb_ctx {
+ struct db_context *db;
+ struct tdb_wrap *wtdb;
+ uint32 db_id;
+ struct db_ctdb_transaction_handle *transaction;
+};
+
+struct db_ctdb_rec {
+ struct db_ctdb_ctx *ctdb_ctx;
+ struct ctdb_ltdb_header header;
+};
+
+static struct db_record *fetch_locked_internal(struct db_ctdb_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ TDB_DATA key,
+ bool persistent);
+
+static NTSTATUS tdb_error_to_ntstatus(struct tdb_context *tdb)
+{
+ NTSTATUS status;
+ enum TDB_ERROR tret = tdb_error(tdb);
+
+ switch (tret) {
+ case TDB_ERR_EXISTS:
+ status = NT_STATUS_OBJECT_NAME_COLLISION;
+ break;
+ case TDB_ERR_NOEXIST:
+ status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ break;
+ default:
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ break;
+ }
+
+ return status;
+}
+
+
+
+/*
+ form a ctdb_rec_data record from a key/data pair
+
+ note that header may be NULL. If not NULL then it is included in the data portion
+ of the record
+ */
+static struct ctdb_rec_data *db_ctdb_marshall_record(TALLOC_CTX *mem_ctx, uint32_t reqid,
+ TDB_DATA key,
+ struct ctdb_ltdb_header *header,
+ TDB_DATA data)
+{
+ size_t length;
+ struct ctdb_rec_data *d;
+
+ length = offsetof(struct ctdb_rec_data, data) + key.dsize +
+ data.dsize + (header?sizeof(*header):0);
+ d = (struct ctdb_rec_data *)talloc_size(mem_ctx, length);
+ if (d == NULL) {
+ return NULL;
+ }
+ d->length = length;
+ d->reqid = reqid;
+ d->keylen = key.dsize;
+ memcpy(&d->data[0], key.dptr, key.dsize);
+ if (header) {
+ d->datalen = data.dsize + sizeof(*header);
+ memcpy(&d->data[key.dsize], header, sizeof(*header));
+ memcpy(&d->data[key.dsize+sizeof(*header)], data.dptr, data.dsize);
+ } else {
+ d->datalen = data.dsize;
+ memcpy(&d->data[key.dsize], data.dptr, data.dsize);
+ }
+ return d;
+}
+
+
+/* helper function for marshalling multiple records */
+static struct ctdb_marshall_buffer *db_ctdb_marshall_add(TALLOC_CTX *mem_ctx,
+ struct ctdb_marshall_buffer *m,
+ uint64_t db_id,
+ uint32_t reqid,
+ TDB_DATA key,
+ struct ctdb_ltdb_header *header,
+ TDB_DATA data)
+{
+ struct ctdb_rec_data *r;
+ size_t m_size, r_size;
+ struct ctdb_marshall_buffer *m2;
+
+ r = db_ctdb_marshall_record(mem_ctx, reqid, key, header, data);
+ if (r == NULL) {
+ talloc_free(m);
+ return NULL;
+ }
+
+ if (m == NULL) {
+ m = (struct ctdb_marshall_buffer *)talloc_zero_size(
+ mem_ctx, offsetof(struct ctdb_marshall_buffer, data));
+ if (m == NULL) {
+ return NULL;
+ }
+ m->db_id = db_id;
+ }
+
+ m_size = talloc_get_size(m);
+ r_size = talloc_get_size(r);
+
+ m2 = (struct ctdb_marshall_buffer *)talloc_realloc_size(
+ mem_ctx, m, m_size + r_size);
+ if (m2 == NULL) {
+ talloc_free(m);
+ return NULL;
+ }
+
+ memcpy(m_size + (uint8_t *)m2, r, r_size);
+
+ talloc_free(r);
+
+ m2->count++;
+
+ return m2;
+}
+
+/* we've finished marshalling, return a data blob with the marshalled records */
+static TDB_DATA db_ctdb_marshall_finish(struct ctdb_marshall_buffer *m)
+{
+ TDB_DATA data;
+ data.dptr = (uint8_t *)m;
+ data.dsize = talloc_get_size(m);
+ return data;
+}
+
+/*
+ loop over a marshalling buffer
+
+ - pass r==NULL to start
+ - loop the number of times indicated by m->count
+*/
+static struct ctdb_rec_data *db_ctdb_marshall_loop_next(struct ctdb_marshall_buffer *m, struct ctdb_rec_data *r,
+ uint32_t *reqid,
+ struct ctdb_ltdb_header *header,
+ TDB_DATA *key, TDB_DATA *data)
+{
+ if (r == NULL) {
+ r = (struct ctdb_rec_data *)&m->data[0];
+ } else {
+ r = (struct ctdb_rec_data *)(r->length + (uint8_t *)r);
+ }
+
+ if (reqid != NULL) {
+ *reqid = r->reqid;
+ }
+
+ if (key != NULL) {
+ key->dptr = &r->data[0];
+ key->dsize = r->keylen;
+ }
+ if (data != NULL) {
+ data->dptr = &r->data[r->keylen];
+ data->dsize = r->datalen;
+ if (header != NULL) {
+ data->dptr += sizeof(*header);
+ data->dsize -= sizeof(*header);
+ }
+ }
+
+ if (header != NULL) {
+ if (r->datalen < sizeof(*header)) {
+ return NULL;
+ }
+ *header = *(struct ctdb_ltdb_header *)&r->data[r->keylen];
+ }
+
+ return r;
+}
+
+
+
+/* start a transaction on a database */
+static int db_ctdb_transaction_destructor(struct db_ctdb_transaction_handle *h)
+{
+ tdb_transaction_cancel(h->ctx->wtdb->tdb);
+ return 0;
+}
+
+/* start a transaction on a database */
+static int db_ctdb_transaction_fetch_start(struct db_ctdb_transaction_handle *h)
+{
+ struct db_record *rh;
+ TDB_DATA key;
+ TALLOC_CTX *tmp_ctx;
+ const char *keyname = CTDB_TRANSACTION_LOCK_KEY;
+ int ret;
+ struct db_ctdb_ctx *ctx = h->ctx;
+ TDB_DATA data;
+
+ key.dptr = (uint8_t *)discard_const(keyname);
+ key.dsize = strlen(keyname);
+
+again:
+ tmp_ctx = talloc_new(h);
+
+ rh = fetch_locked_internal(ctx, tmp_ctx, key, true);
+ if (rh == NULL) {
+ DEBUG(0,(__location__ " Failed to fetch_lock database\n"));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+ talloc_free(rh);
+
+ ret = tdb_transaction_start(ctx->wtdb->tdb);
+ if (ret != 0) {
+ DEBUG(0,(__location__ " Failed to start tdb transaction\n"));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ data = tdb_fetch(ctx->wtdb->tdb, key);
+ if ((data.dptr == NULL) ||
+ (data.dsize < sizeof(struct ctdb_ltdb_header)) ||
+ ((struct ctdb_ltdb_header *)data.dptr)->dmaster != get_my_vnn()) {
+ SAFE_FREE(data.dptr);
+ tdb_transaction_cancel(ctx->wtdb->tdb);
+ talloc_free(tmp_ctx);
+ goto again;
+ }
+
+ SAFE_FREE(data.dptr);
+ talloc_free(tmp_ctx);
+
+ return 0;
+}
+
+
+/* start a transaction on a database */
+static int db_ctdb_transaction_start(struct db_context *db)
+{
+ struct db_ctdb_transaction_handle *h;
+ int ret;
+ struct db_ctdb_ctx *ctx = talloc_get_type_abort(db->private_data,
+ struct db_ctdb_ctx);
+
+ if (!db->persistent) {
+ DEBUG(0,("transactions not supported on non-persistent database 0x%08x\n",
+ ctx->db_id));
+ return -1;
+ }
+
+ if (ctx->transaction) {
+ ctx->transaction->nesting++;
+ return 0;
+ }
+
+ h = talloc_zero(db, struct db_ctdb_transaction_handle);
+ if (h == NULL) {
+ DEBUG(0,(__location__ " oom for transaction handle\n"));
+ return -1;
+ }
+
+ h->ctx = ctx;
+
+ ret = db_ctdb_transaction_fetch_start(h);
+ if (ret != 0) {
+ talloc_free(h);
+ return -1;
+ }
+
+ talloc_set_destructor(h, db_ctdb_transaction_destructor);
+
+ ctx->transaction = h;
+
+ DEBUG(5,(__location__ " Started transaction on db 0x%08x\n", ctx->db_id));
+
+ return 0;
+}
+
+
+
+/*
+ fetch a record inside a transaction
+ */
+static int db_ctdb_transaction_fetch(struct db_ctdb_ctx *db,
+ TALLOC_CTX *mem_ctx,
+ TDB_DATA key, TDB_DATA *data)
+{
+ struct db_ctdb_transaction_handle *h = db->transaction;
+
+ *data = tdb_fetch(h->ctx->wtdb->tdb, key);
+
+ if (data->dptr != NULL) {
+ uint8_t *oldptr = (uint8_t *)data->dptr;
+ data->dsize -= sizeof(struct ctdb_ltdb_header);
+ if (data->dsize == 0) {
+ data->dptr = NULL;
+ } else {
+ data->dptr = (uint8 *)
+ talloc_memdup(
+ mem_ctx, data->dptr+sizeof(struct ctdb_ltdb_header),
+ data->dsize);
+ }
+ SAFE_FREE(oldptr);
+ if (data->dptr == NULL && data->dsize != 0) {
+ return -1;
+ }
+ }
+
+ if (!h->in_replay) {
+ h->m_all = db_ctdb_marshall_add(h, h->m_all, h->ctx->db_id, 1, key, NULL, *data);
+ if (h->m_all == NULL) {
+ DEBUG(0,(__location__ " Failed to add to marshalling record\n"));
+ data->dsize = 0;
+ talloc_free(data->dptr);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static NTSTATUS db_ctdb_store_transaction(struct db_record *rec, TDB_DATA data, int flag);
+static NTSTATUS db_ctdb_delete_transaction(struct db_record *rec);
+
+static struct db_record *db_ctdb_fetch_locked_transaction(struct db_ctdb_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ TDB_DATA key)
+{
+ struct db_record *result;
+ TDB_DATA ctdb_data;
+
+ if (!(result = talloc(mem_ctx, struct db_record))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ result->private_data = ctx->transaction;
+
+ result->key.dsize = key.dsize;
+ result->key.dptr = (uint8 *)talloc_memdup(result, key.dptr, key.dsize);
+ if (result->key.dptr == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ result->store = db_ctdb_store_transaction;
+ result->delete_rec = db_ctdb_delete_transaction;
+
+ ctdb_data = tdb_fetch(ctx->wtdb->tdb, key);
+ if (ctdb_data.dptr == NULL) {
+ /* create the record */
+ result->value = tdb_null;
+ return result;
+ }
+
+ result->value.dsize = ctdb_data.dsize - sizeof(struct ctdb_ltdb_header);
+ result->value.dptr = NULL;
+
+ if ((result->value.dsize != 0)
+ && !(result->value.dptr = (uint8 *)talloc_memdup(
+ result, ctdb_data.dptr + sizeof(struct ctdb_ltdb_header),
+ result->value.dsize))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(result);
+ }
+
+ SAFE_FREE(ctdb_data.dptr);
+
+ return result;
+}
+
+static int db_ctdb_record_destructor(struct db_record *rec)
+{
+ struct db_ctdb_transaction_handle *h = talloc_get_type_abort(
+ rec->private_data, struct db_ctdb_transaction_handle);
+ int ret = h->ctx->db->transaction_commit(h->ctx->db);
+ if (ret != 0) {
+ DEBUG(0,(__location__ " transaction_commit failed\n"));
+ }
+ return 0;
+}
+
+/*
+ auto-create a transaction for persistent databases
+ */
+static struct db_record *db_ctdb_fetch_locked_persistent(struct db_ctdb_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ TDB_DATA key)
+{
+ int res;
+ struct db_record *rec;
+
+ res = db_ctdb_transaction_start(ctx->db);
+ if (res == -1) {
+ return NULL;
+ }
+
+ rec = db_ctdb_fetch_locked_transaction(ctx, mem_ctx, key);
+ if (rec == NULL) {
+ ctx->db->transaction_cancel(ctx->db);
+ return NULL;
+ }
+
+ /* destroy this transaction when we release the lock */
+ talloc_set_destructor((struct db_record *)talloc_new(rec), db_ctdb_record_destructor);
+ return rec;
+}
+
+
+/*
+ stores a record inside a transaction
+ */
+static int db_ctdb_transaction_store(struct db_ctdb_transaction_handle *h,
+ TDB_DATA key, TDB_DATA data)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(h);
+ int ret;
+ TDB_DATA rec;
+ struct ctdb_ltdb_header header;
+
+ /* we need the header so we can update the RSN */
+ rec = tdb_fetch(h->ctx->wtdb->tdb, key);
+ if (rec.dptr == NULL) {
+ /* the record doesn't exist - create one with us as dmaster.
+ This is only safe because we are in a transaction and this
+ is a persistent database */
+ ZERO_STRUCT(header);
+ header.dmaster = get_my_vnn();
+ } else {
+ memcpy(&header, rec.dptr, sizeof(struct ctdb_ltdb_header));
+ rec.dsize -= sizeof(struct ctdb_ltdb_header);
+ /* a special case, we are writing the same data that is there now */
+ if (data.dsize == rec.dsize &&
+ memcmp(data.dptr, rec.dptr + sizeof(struct ctdb_ltdb_header), data.dsize) == 0) {
+ SAFE_FREE(rec.dptr);
+ talloc_free(tmp_ctx);
+ return 0;
+ }
+ SAFE_FREE(rec.dptr);
+ }
+
+ header.rsn++;
+
+ if (!h->in_replay) {
+ h->m_all = db_ctdb_marshall_add(h, h->m_all, h->ctx->db_id, 0, key, NULL, data);
+ if (h->m_all == NULL) {
+ DEBUG(0,(__location__ " Failed to add to marshalling record\n"));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+ }
+
+ h->m_write = db_ctdb_marshall_add(h, h->m_write, h->ctx->db_id, 0, key, &header, data);
+ if (h->m_write == NULL) {
+ DEBUG(0,(__location__ " Failed to add to marshalling record\n"));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ rec.dsize = data.dsize + sizeof(struct ctdb_ltdb_header);
+ rec.dptr = (uint8_t *)talloc_size(tmp_ctx, rec.dsize);
+ if (rec.dptr == NULL) {
+ DEBUG(0,(__location__ " Failed to alloc record\n"));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+ memcpy(rec.dptr, &header, sizeof(struct ctdb_ltdb_header));
+ memcpy(sizeof(struct ctdb_ltdb_header) + (uint8_t *)rec.dptr, data.dptr, data.dsize);
+
+ ret = tdb_store(h->ctx->wtdb->tdb, key, rec, TDB_REPLACE);
+
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+
+/*
+ a record store inside a transaction
+ */
+static NTSTATUS db_ctdb_store_transaction(struct db_record *rec, TDB_DATA data, int flag)
+{
+ struct db_ctdb_transaction_handle *h = talloc_get_type_abort(
+ rec->private_data, struct db_ctdb_transaction_handle);
+ int ret;
+
+ ret = db_ctdb_transaction_store(h, rec->key, data);
+ if (ret != 0) {
+ return tdb_error_to_ntstatus(h->ctx->wtdb->tdb);
+ }
+ return NT_STATUS_OK;
+}
+
+/*
+ a record delete inside a transaction
+ */
+static NTSTATUS db_ctdb_delete_transaction(struct db_record *rec)
+{
+ struct db_ctdb_transaction_handle *h = talloc_get_type_abort(
+ rec->private_data, struct db_ctdb_transaction_handle);
+ int ret;
+
+ ret = db_ctdb_transaction_store(h, rec->key, tdb_null);
+ if (ret != 0) {
+ return tdb_error_to_ntstatus(h->ctx->wtdb->tdb);
+ }
+ return NT_STATUS_OK;
+}
+
+
+/*
+ replay a transaction
+ */
+static int ctdb_replay_transaction(struct db_ctdb_transaction_handle *h)
+{
+ int ret, i;
+ struct ctdb_rec_data *rec = NULL;
+
+ h->in_replay = true;
+ talloc_free(h->m_write);
+ h->m_write = NULL;
+
+ ret = db_ctdb_transaction_fetch_start(h);
+ if (ret != 0) {
+ return ret;
+ }
+
+ for (i=0;i<h->m_all->count;i++) {
+ TDB_DATA key, data;
+
+ rec = db_ctdb_marshall_loop_next(h->m_all, rec, NULL, NULL, &key, &data);
+ if (rec == NULL) {
+ DEBUG(0, (__location__ " Out of records in ctdb_replay_transaction?\n"));
+ goto failed;
+ }
+
+ if (rec->reqid == 0) {
+ /* its a store */
+ if (db_ctdb_transaction_store(h, key, data) != 0) {
+ goto failed;
+ }
+ } else {
+ TDB_DATA data2;
+ TALLOC_CTX *tmp_ctx = talloc_new(h);
+
+ if (db_ctdb_transaction_fetch(h->ctx, tmp_ctx, key, &data2) != 0) {
+ talloc_free(tmp_ctx);
+ goto failed;
+ }
+ if (data2.dsize != data.dsize ||
+ memcmp(data2.dptr, data.dptr, data.dsize) != 0) {
+ /* the record has changed on us - we have to give up */
+ talloc_free(tmp_ctx);
+ goto failed;
+ }
+ talloc_free(tmp_ctx);
+ }
+ }
+
+ return 0;
+
+failed:
+ tdb_transaction_cancel(h->ctx->wtdb->tdb);
+ return -1;
+}
+
+
+/*
+ commit a transaction
+ */
+static int db_ctdb_transaction_commit(struct db_context *db)
+{
+ struct db_ctdb_ctx *ctx = talloc_get_type_abort(db->private_data,
+ struct db_ctdb_ctx);
+ NTSTATUS rets;
+ int ret;
+ int status;
+ int retries = 0;
+ struct db_ctdb_transaction_handle *h = ctx->transaction;
+ enum ctdb_controls failure_control = CTDB_CONTROL_TRANS2_ERROR;
+
+ if (h == NULL) {
+ DEBUG(0,(__location__ " transaction commit with no open transaction on db 0x%08x\n", ctx->db_id));
+ return -1;
+ }
+
+ if (h->nested_cancel) {
+ db->transaction_cancel(db);
+ DEBUG(5,(__location__ " Failed transaction commit after nested cancel\n"));
+ return -1;
+ }
+
+ if (h->nesting != 0) {
+ h->nesting--;
+ return 0;
+ }
+
+ DEBUG(5,(__location__ " Commit transaction on db 0x%08x\n", ctx->db_id));
+
+ talloc_set_destructor(h, NULL);
+
+ /* our commit strategy is quite complex.
+
+ - we first try to commit the changes to all other nodes
+
+ - if that works, then we commit locally and we are done
+
+ - if a commit on another node fails, then we need to cancel
+ the transaction, then restart the transaction (thus
+ opening a window of time for a pending recovery to
+ complete), then replay the transaction, checking all the
+ reads and writes (checking that reads give the same data,
+ and writes succeed). Then we retry the transaction to the
+ other nodes
+ */
+
+again:
+ if (h->m_write == NULL) {
+ /* no changes were made, potentially after a retry */
+ tdb_transaction_cancel(h->ctx->wtdb->tdb);
+ talloc_free(h);
+ ctx->transaction = NULL;
+ return 0;
+ }
+
+ /* tell ctdbd to commit to the other nodes */
+ rets = ctdbd_control_local(messaging_ctdbd_connection(),
+ retries==0?CTDB_CONTROL_TRANS2_COMMIT:CTDB_CONTROL_TRANS2_COMMIT_RETRY,
+ h->ctx->db_id, 0,
+ db_ctdb_marshall_finish(h->m_write), NULL, NULL, &status);
+ if (!NT_STATUS_IS_OK(rets) || status != 0) {
+ tdb_transaction_cancel(h->ctx->wtdb->tdb);
+ sleep(1);
+
+ if (!NT_STATUS_IS_OK(rets)) {
+ failure_control = CTDB_CONTROL_TRANS2_ERROR;
+ } else {
+ /* work out what error code we will give if we
+ have to fail the operation */
+ switch ((enum ctdb_trans2_commit_error)status) {
+ case CTDB_TRANS2_COMMIT_SUCCESS:
+ case CTDB_TRANS2_COMMIT_SOMEFAIL:
+ case CTDB_TRANS2_COMMIT_TIMEOUT:
+ failure_control = CTDB_CONTROL_TRANS2_ERROR;
+ break;
+ case CTDB_TRANS2_COMMIT_ALLFAIL:
+ failure_control = CTDB_CONTROL_TRANS2_FINISHED;
+ break;
+ }
+ }
+
+ if (++retries == 5) {
+ DEBUG(0,(__location__ " Giving up transaction on db 0x%08x after %d retries failure_control=%u\n",
+ h->ctx->db_id, retries, (unsigned)failure_control));
+ ctdbd_control_local(messaging_ctdbd_connection(), failure_control,
+ h->ctx->db_id, CTDB_CTRL_FLAG_NOREPLY,
+ tdb_null, NULL, NULL, NULL);
+ h->ctx->transaction = NULL;
+ talloc_free(h);
+ ctx->transaction = NULL;
+ return -1;
+ }
+
+ if (ctdb_replay_transaction(h) != 0) {
+ DEBUG(0,(__location__ " Failed to replay transaction failure_control=%u\n",
+ (unsigned)failure_control));
+ ctdbd_control_local(messaging_ctdbd_connection(), failure_control,
+ h->ctx->db_id, CTDB_CTRL_FLAG_NOREPLY,
+ tdb_null, NULL, NULL, NULL);
+ h->ctx->transaction = NULL;
+ talloc_free(h);
+ ctx->transaction = NULL;
+ return -1;
+ }
+ goto again;
+ } else {
+ failure_control = CTDB_CONTROL_TRANS2_ERROR;
+ }
+
+ /* do the real commit locally */
+ ret = tdb_transaction_commit(h->ctx->wtdb->tdb);
+ if (ret != 0) {
+ DEBUG(0,(__location__ " Failed to commit transaction failure_control=%u\n",
+ (unsigned)failure_control));
+ ctdbd_control_local(messaging_ctdbd_connection(), failure_control, h->ctx->db_id,
+ CTDB_CTRL_FLAG_NOREPLY, tdb_null, NULL, NULL, NULL);
+ h->ctx->transaction = NULL;
+ talloc_free(h);
+ return ret;
+ }
+
+ /* tell ctdbd that we are finished with our local commit */
+ ctdbd_control_local(messaging_ctdbd_connection(), CTDB_CONTROL_TRANS2_FINISHED,
+ h->ctx->db_id, CTDB_CTRL_FLAG_NOREPLY,
+ tdb_null, NULL, NULL, NULL);
+ h->ctx->transaction = NULL;
+ talloc_free(h);
+ return 0;
+}
+
+
+/*
+ cancel a transaction
+ */
+static int db_ctdb_transaction_cancel(struct db_context *db)
+{
+ struct db_ctdb_ctx *ctx = talloc_get_type_abort(db->private_data,
+ struct db_ctdb_ctx);
+ struct db_ctdb_transaction_handle *h = ctx->transaction;
+
+ if (h == NULL) {
+ DEBUG(0,(__location__ " transaction cancel with no open transaction on db 0x%08x\n", ctx->db_id));
+ return -1;
+ }
+
+ if (h->nesting != 0) {
+ h->nesting--;
+ h->nested_cancel = true;
+ return 0;
+ }
+
+ DEBUG(5,(__location__ " Cancel transaction on db 0x%08x\n", ctx->db_id));
+
+ ctx->transaction = NULL;
+ talloc_free(h);
+ return 0;
+}
+
+
+static NTSTATUS db_ctdb_store(struct db_record *rec, TDB_DATA data, int flag)
+{
+ struct db_ctdb_rec *crec = talloc_get_type_abort(
+ rec->private_data, struct db_ctdb_rec);
+ TDB_DATA cdata;
+ int ret;
+
+ cdata.dsize = sizeof(crec->header) + data.dsize;
+
+ if (!(cdata.dptr = SMB_MALLOC_ARRAY(uint8, cdata.dsize))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ memcpy(cdata.dptr, &crec->header, sizeof(crec->header));
+ memcpy(cdata.dptr + sizeof(crec->header), data.dptr, data.dsize);
+
+ ret = tdb_store(crec->ctdb_ctx->wtdb->tdb, rec->key, cdata, TDB_REPLACE);
+
+ SAFE_FREE(cdata.dptr);
+
+ return (ret == 0) ? NT_STATUS_OK
+ : tdb_error_to_ntstatus(crec->ctdb_ctx->wtdb->tdb);
+}
+
+
+
+static NTSTATUS db_ctdb_delete(struct db_record *rec)
+{
+ TDB_DATA data;
+
+ /*
+ * We have to store the header with empty data. TODO: Fix the
+ * tdb-level cleanup
+ */
+
+ ZERO_STRUCT(data);
+
+ return db_ctdb_store(rec, data, 0);
+
+}
+
+static int db_ctdb_record_destr(struct db_record* data)
+{
+ struct db_ctdb_rec *crec = talloc_get_type_abort(
+ data->private_data, struct db_ctdb_rec);
+
+ DEBUG(10, (DEBUGLEVEL > 10
+ ? "Unlocking db %u key %s\n"
+ : "Unlocking db %u key %.20s\n",
+ (int)crec->ctdb_ctx->db_id,
+ hex_encode(data, (unsigned char *)data->key.dptr,
+ data->key.dsize)));
+
+ if (tdb_chainunlock(crec->ctdb_ctx->wtdb->tdb, data->key) != 0) {
+ DEBUG(0, ("tdb_chainunlock failed\n"));
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct db_record *fetch_locked_internal(struct db_ctdb_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ TDB_DATA key,
+ bool persistent)
+{
+ struct db_record *result;
+ struct db_ctdb_rec *crec;
+ NTSTATUS status;
+ TDB_DATA ctdb_data;
+ int migrate_attempts = 0;
+
+ if (!(result = talloc(mem_ctx, struct db_record))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ if (!(crec = TALLOC_ZERO_P(result, struct db_ctdb_rec))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ result->private_data = (void *)crec;
+ crec->ctdb_ctx = ctx;
+
+ result->key.dsize = key.dsize;
+ result->key.dptr = (uint8 *)talloc_memdup(result, key.dptr, key.dsize);
+ if (result->key.dptr == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ /*
+ * Do a blocking lock on the record
+ */
+again:
+
+ if (DEBUGLEVEL >= 10) {
+ char *keystr = hex_encode(result, key.dptr, key.dsize);
+ DEBUG(10, (DEBUGLEVEL > 10
+ ? "Locking db %u key %s\n"
+ : "Locking db %u key %.20s\n",
+ (int)crec->ctdb_ctx->db_id, keystr));
+ TALLOC_FREE(keystr);
+ }
+
+ if (tdb_chainlock(ctx->wtdb->tdb, key) != 0) {
+ DEBUG(3, ("tdb_chainlock failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ result->store = db_ctdb_store;
+ result->delete_rec = db_ctdb_delete;
+ talloc_set_destructor(result, db_ctdb_record_destr);
+
+ ctdb_data = tdb_fetch(ctx->wtdb->tdb, key);
+
+ /*
+ * See if we have a valid record and we are the dmaster. If so, we can
+ * take the shortcut and just return it.
+ */
+
+ if ((ctdb_data.dptr == NULL) ||
+ (ctdb_data.dsize < sizeof(struct ctdb_ltdb_header)) ||
+ ((struct ctdb_ltdb_header *)ctdb_data.dptr)->dmaster != get_my_vnn()
+#if 0
+ || (random() % 2 != 0)
+#endif
+) {
+ SAFE_FREE(ctdb_data.dptr);
+ tdb_chainunlock(ctx->wtdb->tdb, key);
+ talloc_set_destructor(result, NULL);
+
+ migrate_attempts += 1;
+
+ DEBUG(10, ("ctdb_data.dptr = %p, dmaster = %u (%u)\n",
+ ctdb_data.dptr, ctdb_data.dptr ?
+ ((struct ctdb_ltdb_header *)ctdb_data.dptr)->dmaster : -1,
+ get_my_vnn()));
+
+ status = ctdbd_migrate(messaging_ctdbd_connection(),ctx->db_id, key);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("ctdb_migrate failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+ /* now its migrated, try again */
+ goto again;
+ }
+
+ if (migrate_attempts > 10) {
+ DEBUG(0, ("db_ctdb_fetch_locked needed %d attempts\n",
+ migrate_attempts));
+ }
+
+ memcpy(&crec->header, ctdb_data.dptr, sizeof(crec->header));
+
+ result->value.dsize = ctdb_data.dsize - sizeof(crec->header);
+ result->value.dptr = NULL;
+
+ if ((result->value.dsize != 0)
+ && !(result->value.dptr = (uint8 *)talloc_memdup(
+ result, ctdb_data.dptr + sizeof(crec->header),
+ result->value.dsize))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(result);
+ }
+
+ SAFE_FREE(ctdb_data.dptr);
+
+ return result;
+}
+
+static struct db_record *db_ctdb_fetch_locked(struct db_context *db,
+ TALLOC_CTX *mem_ctx,
+ TDB_DATA key)
+{
+ struct db_ctdb_ctx *ctx = talloc_get_type_abort(db->private_data,
+ struct db_ctdb_ctx);
+
+ if (ctx->transaction != NULL) {
+ return db_ctdb_fetch_locked_transaction(ctx, mem_ctx, key);
+ }
+
+ if (db->persistent) {
+ return db_ctdb_fetch_locked_persistent(ctx, mem_ctx, key);
+ }
+
+ return fetch_locked_internal(ctx, mem_ctx, key, db->persistent);
+}
+
+/*
+ fetch (unlocked, no migration) operation on ctdb
+ */
+static int db_ctdb_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
+ TDB_DATA key, TDB_DATA *data)
+{
+ struct db_ctdb_ctx *ctx = talloc_get_type_abort(db->private_data,
+ struct db_ctdb_ctx);
+ NTSTATUS status;
+ TDB_DATA ctdb_data;
+
+ if (ctx->transaction) {
+ return db_ctdb_transaction_fetch(ctx, mem_ctx, key, data);
+ }
+
+ /* try a direct fetch */
+ ctdb_data = tdb_fetch(ctx->wtdb->tdb, key);
+
+ /*
+ * See if we have a valid record and we are the dmaster. If so, we can
+ * take the shortcut and just return it.
+ * we bypass the dmaster check for persistent databases
+ */
+ if ((ctdb_data.dptr != NULL) &&
+ (ctdb_data.dsize >= sizeof(struct ctdb_ltdb_header)) &&
+ (db->persistent ||
+ ((struct ctdb_ltdb_header *)ctdb_data.dptr)->dmaster == get_my_vnn())) {
+ /* we are the dmaster - avoid the ctdb protocol op */
+
+ data->dsize = ctdb_data.dsize - sizeof(struct ctdb_ltdb_header);
+ if (data->dsize == 0) {
+ SAFE_FREE(ctdb_data.dptr);
+ data->dptr = NULL;
+ return 0;
+ }
+
+ data->dptr = (uint8 *)talloc_memdup(
+ mem_ctx, ctdb_data.dptr+sizeof(struct ctdb_ltdb_header),
+ data->dsize);
+
+ SAFE_FREE(ctdb_data.dptr);
+
+ if (data->dptr == NULL) {
+ return -1;
+ }
+ return 0;
+ }
+
+ SAFE_FREE(ctdb_data.dptr);
+
+ /* we weren't able to get it locally - ask ctdb to fetch it for us */
+ status = ctdbd_fetch(messaging_ctdbd_connection(),ctx->db_id, key, mem_ctx, data);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("ctdbd_fetch failed: %s\n", nt_errstr(status)));
+ return -1;
+ }
+
+ return 0;
+}
+
+struct traverse_state {
+ struct db_context *db;
+ int (*fn)(struct db_record *rec, void *private_data);
+ void *private_data;
+};
+
+static void traverse_callback(TDB_DATA key, TDB_DATA data, void *private_data)
+{
+ struct traverse_state *state = (struct traverse_state *)private_data;
+ struct db_record *rec;
+ TALLOC_CTX *tmp_ctx = talloc_new(state->db);
+ /* we have to give them a locked record to prevent races */
+ rec = db_ctdb_fetch_locked(state->db, tmp_ctx, key);
+ if (rec && rec->value.dsize > 0) {
+ state->fn(rec, state->private_data);
+ }
+ talloc_free(tmp_ctx);
+}
+
+static int traverse_persistent_callback(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
+ void *private_data)
+{
+ struct traverse_state *state = (struct traverse_state *)private_data;
+ struct db_record *rec;
+ TALLOC_CTX *tmp_ctx = talloc_new(state->db);
+ int ret = 0;
+ /* we have to give them a locked record to prevent races */
+ rec = db_ctdb_fetch_locked(state->db, tmp_ctx, kbuf);
+ if (rec && rec->value.dsize > 0) {
+ ret = state->fn(rec, state->private_data);
+ }
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static int db_ctdb_traverse(struct db_context *db,
+ int (*fn)(struct db_record *rec,
+ void *private_data),
+ void *private_data)
+{
+ struct db_ctdb_ctx *ctx = talloc_get_type_abort(db->private_data,
+ struct db_ctdb_ctx);
+ struct traverse_state state;
+
+ state.db = db;
+ state.fn = fn;
+ state.private_data = private_data;
+
+ if (db->persistent) {
+ /* for persistent databases we don't need to do a ctdb traverse,
+ we can do a faster local traverse */
+ return tdb_traverse(ctx->wtdb->tdb, traverse_persistent_callback, &state);
+ }
+
+
+ ctdbd_traverse(ctx->db_id, traverse_callback, &state);
+ return 0;
+}
+
+static NTSTATUS db_ctdb_store_deny(struct db_record *rec, TDB_DATA data, int flag)
+{
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+}
+
+static NTSTATUS db_ctdb_delete_deny(struct db_record *rec)
+{
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+}
+
+static void traverse_read_callback(TDB_DATA key, TDB_DATA data, void *private_data)
+{
+ struct traverse_state *state = (struct traverse_state *)private_data;
+ struct db_record rec;
+ rec.key = key;
+ rec.value = data;
+ rec.store = db_ctdb_store_deny;
+ rec.delete_rec = db_ctdb_delete_deny;
+ rec.private_data = state->db;
+ state->fn(&rec, state->private_data);
+}
+
+static int traverse_persistent_callback_read(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
+ void *private_data)
+{
+ struct traverse_state *state = (struct traverse_state *)private_data;
+ struct db_record rec;
+ rec.key = kbuf;
+ rec.value = dbuf;
+ rec.store = db_ctdb_store_deny;
+ rec.delete_rec = db_ctdb_delete_deny;
+ rec.private_data = state->db;
+
+ if (rec.value.dsize <= sizeof(struct ctdb_ltdb_header)) {
+ /* a deleted record */
+ return 0;
+ }
+ rec.value.dsize -= sizeof(struct ctdb_ltdb_header);
+ rec.value.dptr += sizeof(struct ctdb_ltdb_header);
+
+ return state->fn(&rec, state->private_data);
+}
+
+static int db_ctdb_traverse_read(struct db_context *db,
+ int (*fn)(struct db_record *rec,
+ void *private_data),
+ void *private_data)
+{
+ struct db_ctdb_ctx *ctx = talloc_get_type_abort(db->private_data,
+ struct db_ctdb_ctx);
+ struct traverse_state state;
+
+ state.db = db;
+ state.fn = fn;
+ state.private_data = private_data;
+
+ if (db->persistent) {
+ /* for persistent databases we don't need to do a ctdb traverse,
+ we can do a faster local traverse */
+ return tdb_traverse_read(ctx->wtdb->tdb, traverse_persistent_callback_read, &state);
+ }
+
+ ctdbd_traverse(ctx->db_id, traverse_read_callback, &state);
+ return 0;
+}
+
+static int db_ctdb_get_seqnum(struct db_context *db)
+{
+ struct db_ctdb_ctx *ctx = talloc_get_type_abort(db->private_data,
+ struct db_ctdb_ctx);
+ return tdb_get_seqnum(ctx->wtdb->tdb);
+}
+
+struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
+ const char *name,
+ int hash_size, int tdb_flags,
+ int open_flags, mode_t mode)
+{
+ struct db_context *result;
+ struct db_ctdb_ctx *db_ctdb;
+ char *db_path;
+
+ if (!lp_clustering()) {
+ DEBUG(10, ("Clustering disabled -- no ctdb\n"));
+ return NULL;
+ }
+
+ if (!(result = TALLOC_ZERO_P(mem_ctx, struct db_context))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ if (!(db_ctdb = TALLOC_P(result, struct db_ctdb_ctx))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ db_ctdb->transaction = NULL;
+ db_ctdb->db = result;
+
+ if (!NT_STATUS_IS_OK(ctdbd_db_attach(messaging_ctdbd_connection(),name, &db_ctdb->db_id, tdb_flags))) {
+ DEBUG(0, ("ctdbd_db_attach failed for %s\n", name));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ db_path = ctdbd_dbpath(messaging_ctdbd_connection(), db_ctdb, db_ctdb->db_id);
+
+ result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
+
+ /* only pass through specific flags */
+ tdb_flags &= TDB_SEQNUM;
+
+ /* honor permissions if user has specified O_CREAT */
+ if (open_flags & O_CREAT) {
+ chmod(db_path, mode);
+ }
+
+ db_ctdb->wtdb = tdb_wrap_open(db_ctdb, db_path, hash_size, tdb_flags, O_RDWR, 0);
+ if (db_ctdb->wtdb == NULL) {
+ DEBUG(0, ("Could not open tdb %s: %s\n", db_path, strerror(errno)));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+ talloc_free(db_path);
+
+ result->private_data = (void *)db_ctdb;
+ result->fetch_locked = db_ctdb_fetch_locked;
+ result->fetch = db_ctdb_fetch;
+ result->traverse = db_ctdb_traverse;
+ result->traverse_read = db_ctdb_traverse_read;
+ result->get_seqnum = db_ctdb_get_seqnum;
+ result->transaction_start = db_ctdb_transaction_start;
+ result->transaction_commit = db_ctdb_transaction_commit;
+ result->transaction_cancel = db_ctdb_transaction_cancel;
+
+ DEBUG(3,("db_open_ctdb: opened database '%s' with dbid 0x%x\n",
+ name, db_ctdb->db_id));
+
+ return result;
+}
+#endif
diff --git a/source3/lib/dbwrap_file.c b/source3/lib/dbwrap_file.c
new file mode 100644
index 0000000000..e3779de1e4
--- /dev/null
+++ b/source3/lib/dbwrap_file.c
@@ -0,0 +1,410 @@
+/*
+ Unix SMB/CIFS implementation.
+ Database interface using a file per record
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+struct db_file_ctx {
+ const char *dirname;
+
+ /* We only support one locked record at a time -- everything else
+ * would lead to a potential deadlock anyway! */
+ struct db_record *locked_record;
+};
+
+struct db_locked_file {
+ int fd;
+ uint8 hash;
+ const char *name;
+ const char *path;
+ struct db_file_ctx *parent;
+};
+
+/* Copy from statcache.c... */
+
+static uint32 fsh(const uint8 *p, int len)
+{
+ uint32 n = 0;
+ int i;
+ for (i=0; i<len; i++) {
+ n = ((n << 5) + n) ^ (uint32)(p[i]);
+ }
+ return n;
+}
+
+static int db_locked_file_destr(struct db_locked_file *data)
+{
+ if (data->parent != NULL) {
+ data->parent->locked_record = NULL;
+ }
+
+ if (close(data->fd) != 0) {
+ DEBUG(3, ("close failed: %s\n", strerror(errno)));
+ return -1;
+ }
+
+ return 0;
+}
+
+static NTSTATUS db_file_store(struct db_record *rec, TDB_DATA data, int flag);
+static NTSTATUS db_file_delete(struct db_record *rec);
+
+static struct db_record *db_file_fetch_locked(struct db_context *db,
+ TALLOC_CTX *mem_ctx,
+ TDB_DATA key)
+{
+ struct db_file_ctx *ctx = talloc_get_type_abort(db->private_data,
+ struct db_file_ctx);
+ struct db_record *result;
+ struct db_locked_file *file;
+ struct flock fl;
+ SMB_STRUCT_STAT statbuf;
+ ssize_t nread;
+ int ret;
+
+ SMB_ASSERT(ctx->locked_record == NULL);
+
+ again:
+ if (!(result = TALLOC_P(mem_ctx, struct db_record))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ if (!(file = TALLOC_P(result, struct db_locked_file))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ result->private_data = file;
+ result->store = db_file_store;
+ result->delete_rec = db_file_delete;
+
+ result->key.dsize = key.dsize;
+ result->key.dptr = (uint8 *)talloc_memdup(result, key.dptr, key.dsize);
+ if (result->key.dptr == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ /* Cut to 8 bits */
+ file->hash = fsh(key.dptr, key.dsize);
+ file->name = hex_encode(file, (unsigned char *)key.dptr, key.dsize);
+ if (file->name == NULL) {
+ DEBUG(0, ("hex_encode failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ file->path = talloc_asprintf(file, "%s/%2.2X/%s", ctx->dirname,
+ file->hash, file->name);
+ if (file->path == NULL) {
+ DEBUG(0, ("talloc_asprintf failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ become_root();
+ file->fd = open(file->path, O_RDWR|O_CREAT, 0644);
+ unbecome_root();
+
+ if (file->fd < 0) {
+ DEBUG(3, ("Could not open/create %s: %s\n",
+ file->path, strerror(errno)));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ talloc_set_destructor(file, db_locked_file_destr);
+
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 1;
+ fl.l_pid = 0;
+
+ do {
+ ret = fcntl(file->fd, F_SETLKW, &fl);
+ } while ((ret == -1) && (errno == EINTR));
+
+ if (ret == -1) {
+ DEBUG(3, ("Could not get lock on %s: %s\n",
+ file->path, strerror(errno)));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ if (sys_fstat(file->fd, &statbuf) != 0) {
+ DEBUG(3, ("Could not fstat %s: %s\n",
+ file->path, strerror(errno)));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ if (statbuf.st_nlink == 0) {
+ /* Someone has deleted it under the lock, retry */
+ TALLOC_FREE(result);
+ goto again;
+ }
+
+ result->value.dsize = 0;
+ result->value.dptr = NULL;
+
+ if (statbuf.st_size != 0) {
+ result->value.dsize = statbuf.st_size;
+ result->value.dptr = TALLOC_ARRAY(result, uint8,
+ statbuf.st_size);
+ if (result->value.dptr == NULL) {
+ DEBUG(1, ("talloc failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ nread = read_data(file->fd, (char *)result->value.dptr,
+ result->value.dsize);
+ if (nread != result->value.dsize) {
+ DEBUG(3, ("read_data failed: %s\n", strerror(errno)));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+ }
+
+ ctx->locked_record = result;
+ file->parent = (struct db_file_ctx *)talloc_reference(file, ctx);
+
+ return result;
+}
+
+static NTSTATUS db_file_store_root(int fd, TDB_DATA data)
+{
+ if (sys_lseek(fd, 0, SEEK_SET) != 0) {
+ DEBUG(0, ("sys_lseek failed: %s\n", strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+
+ if (write_data(fd, (char *)data.dptr, data.dsize) != data.dsize) {
+ DEBUG(3, ("write_data failed: %s\n", strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+
+ if (sys_ftruncate(fd, data.dsize) != 0) {
+ DEBUG(3, ("sys_ftruncate failed: %s\n", strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS db_file_store(struct db_record *rec, TDB_DATA data, int flag)
+{
+ struct db_locked_file *file =
+ talloc_get_type_abort(rec->private_data,
+ struct db_locked_file);
+ NTSTATUS status;
+
+ become_root();
+ status = db_file_store_root(file->fd, data);
+ unbecome_root();
+
+ return status;
+}
+
+static NTSTATUS db_file_delete(struct db_record *rec)
+{
+ struct db_locked_file *file =
+ talloc_get_type_abort(rec->private_data,
+ struct db_locked_file);
+ int res;
+
+ become_root();
+ res = unlink(file->path);
+ unbecome_root();
+
+ if (res == -1) {
+ DEBUG(3, ("unlink(%s) failed: %s\n", file->path,
+ strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static int db_file_traverse(struct db_context *db,
+ int (*fn)(struct db_record *rec,
+ void *private_data),
+ void *private_data)
+{
+ struct db_file_ctx *ctx = talloc_get_type_abort(db->private_data,
+ struct db_file_ctx);
+ TALLOC_CTX *mem_ctx = talloc_init("traversal %s\n", ctx->dirname);
+
+ int i;
+ int count = 0;
+
+ for (i=0; i<256; i++) {
+ const char *dirname = talloc_asprintf(mem_ctx, "%s/%2.2X",
+ ctx->dirname, i);
+ DIR *dir;
+ struct dirent *dirent;
+
+ if (dirname == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(mem_ctx);
+ return -1;
+ }
+
+ dir = opendir(dirname);
+ if (dir == NULL) {
+ DEBUG(3, ("Could not open dir %s: %s\n", dirname,
+ strerror(errno)));
+ TALLOC_FREE(mem_ctx);
+ return -1;
+ }
+
+ while ((dirent = readdir(dir)) != NULL) {
+ DATA_BLOB keyblob;
+ TDB_DATA key;
+ struct db_record *rec;
+
+ if ((dirent->d_name[0] == '.') &&
+ ((dirent->d_name[1] == '\0') ||
+ ((dirent->d_name[1] == '.') &&
+ (dirent->d_name[2] == '\0')))) {
+ continue;
+ }
+
+ keyblob = strhex_to_data_blob(mem_ctx, dirent->d_name);
+ if (keyblob.data == NULL) {
+ DEBUG(5, ("strhex_to_data_blob failed\n"));
+ continue;
+ }
+
+ key.dptr = keyblob.data;
+ key.dsize = keyblob.length;
+
+ if ((ctx->locked_record != NULL) &&
+ (key.dsize == ctx->locked_record->key.dsize) &&
+ (memcmp(key.dptr, ctx->locked_record->key.dptr,
+ key.dsize) == 0)) {
+ count += 1;
+ if (fn(ctx->locked_record,
+ private_data) != 0) {
+ TALLOC_FREE(mem_ctx);
+ closedir(dir);
+ return count;
+ }
+ }
+
+ rec = db_file_fetch_locked(db, mem_ctx, key);
+ if (rec == NULL) {
+ /* Someone might have deleted it */
+ continue;
+ }
+
+ if (rec->value.dptr == NULL) {
+ TALLOC_FREE(rec);
+ continue;
+ }
+
+ count += 1;
+
+ if (fn(rec, private_data) != 0) {
+ TALLOC_FREE(mem_ctx);
+ closedir(dir);
+ return count;
+ }
+ TALLOC_FREE(rec);
+ }
+
+ closedir(dir);
+ }
+
+ TALLOC_FREE(mem_ctx);
+ return count;
+}
+
+struct db_context *db_open_file(TALLOC_CTX *mem_ctx,
+ struct messaging_context *msg_ctx,
+ const char *name,
+ int hash_size, int tdb_flags,
+ int open_flags, mode_t mode)
+{
+ struct db_context *result = NULL;
+ struct db_file_ctx *ctx;
+
+ if (!(result = TALLOC_ZERO_P(mem_ctx, struct db_context))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ if (!(ctx = TALLOC_P(result, struct db_file_ctx))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ result->private_data = ctx;
+ result->fetch_locked = db_file_fetch_locked;
+ result->traverse = db_file_traverse;
+ result->traverse_read = db_file_traverse;
+ result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
+
+ ctx->locked_record = NULL;
+ if (!(ctx->dirname = talloc_strdup(ctx, name))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ if (open_flags & O_CREAT) {
+ int ret, i;
+
+ mode |= (mode & S_IRUSR) ? S_IXUSR : 0;
+ mode |= (mode & S_IRGRP) ? S_IXGRP : 0;
+ mode |= (mode & S_IROTH) ? S_IXOTH : 0;
+
+ ret = mkdir(name, mode);
+ if ((ret != 0) && (errno != EEXIST)) {
+ DEBUG(5, ("mkdir(%s,%o) failed: %s\n", name, mode,
+ strerror(errno)));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ for (i=0; i<256; i++) {
+ char *path;
+ path = talloc_asprintf(result, "%s/%2.2X", name, i);
+ if (path == NULL) {
+ DEBUG(0, ("asprintf failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+ ret = mkdir(path, mode);
+ if ((ret != 0) && (errno != EEXIST)) {
+ DEBUG(5, ("mkdir(%s,%o) failed: %s\n", path,
+ mode, strerror(errno)));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+ TALLOC_FREE(path);
+ }
+ }
+
+ return result;
+}
diff --git a/source3/lib/dbwrap_rbt.c b/source3/lib/dbwrap_rbt.c
new file mode 100644
index 0000000000..b70ce3dfa0
--- /dev/null
+++ b/source3/lib/dbwrap_rbt.c
@@ -0,0 +1,390 @@
+/*
+ Unix SMB/CIFS implementation.
+ Database interface wrapper around red-black trees
+ Copyright (C) Volker Lendecke 2007, 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rbtree.h"
+
+#define DBWRAP_RBT_ALIGN(_size_) (((_size_)+15)&~15)
+
+struct db_rbt_ctx {
+ struct rb_root tree;
+};
+
+struct db_rbt_rec {
+ struct db_rbt_ctx *db_ctx;
+ struct db_rbt_node *node;
+};
+
+/* The structure that ends up in the tree */
+
+struct db_rbt_node {
+ struct rb_node rb_node;
+ size_t keysize, valuesize;
+
+ /*
+ * key and value are appended implicitly, "data" is only here as a
+ * target for offsetof()
+ */
+
+ char data[1];
+};
+
+/*
+ * Hide the ugly pointer calculations in a function
+ */
+
+static struct db_rbt_node *db_rbt2node(struct rb_node *node)
+{
+ return (struct db_rbt_node *)
+ ((char *)node - offsetof(struct db_rbt_node, rb_node));
+}
+
+/*
+ * Compare two keys
+ */
+
+static int db_rbt_compare(TDB_DATA a, TDB_DATA b)
+{
+ int res;
+
+ res = memcmp(a.dptr, b.dptr, MIN(a.dsize, b.dsize));
+
+ if ((res < 0) || ((res == 0) && (a.dsize < b.dsize))) {
+ return -1;
+ }
+ if ((res > 0) || ((res == 0) && (a.dsize > b.dsize))) {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * dissect a db_rbt_node into its implicit key and value parts
+ */
+
+static void db_rbt_parse_node(struct db_rbt_node *node,
+ TDB_DATA *key, TDB_DATA *value)
+{
+ key->dptr = ((uint8 *)node) + offsetof(struct db_rbt_node, data);
+ key->dsize = node->keysize;
+ value->dptr = key->dptr + node->keysize;
+ value->dsize = node->valuesize;
+}
+
+static NTSTATUS db_rbt_store(struct db_record *rec, TDB_DATA data, int flag)
+{
+ struct db_rbt_rec *rec_priv = (struct db_rbt_rec *)rec->private_data;
+ struct db_rbt_node *node;
+
+ struct rb_node ** p;
+ struct rb_node * parent;
+
+ TDB_DATA this_key, this_val;
+
+ if (rec_priv->node != NULL) {
+
+ /*
+ * The record was around previously
+ */
+
+ db_rbt_parse_node(rec_priv->node, &this_key, &this_val);
+
+ SMB_ASSERT(this_key.dsize == rec->key.dsize);
+ SMB_ASSERT(memcmp(this_key.dptr, rec->key.dptr,
+ this_key.dsize) == 0);
+
+ if (this_val.dsize >= data.dsize) {
+ /*
+ * The new value fits into the old space
+ */
+ memcpy(this_val.dptr, data.dptr, data.dsize);
+ rec_priv->node->valuesize = data.dsize;
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * We need to delete the key from the tree and start fresh,
+ * there's not enough space in the existing record
+ */
+
+ rb_erase(&rec_priv->node->rb_node, &rec_priv->db_ctx->tree);
+
+ /*
+ * Keep the existing node around for a while: If the record
+ * existed before, we reference the key data in there.
+ */
+ }
+
+ node = (struct db_rbt_node *)SMB_MALLOC(
+ offsetof(struct db_rbt_node, data) + rec->key.dsize
+ + data.dsize);
+
+ if (node == NULL) {
+ SAFE_FREE(rec_priv->node);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCT(node->rb_node);
+
+ node->keysize = rec->key.dsize;
+ node->valuesize = data.dsize;
+
+ db_rbt_parse_node(node, &this_key, &this_val);
+
+ memcpy(this_key.dptr, rec->key.dptr, node->keysize);
+ SAFE_FREE(rec_priv->node);
+
+ memcpy(this_val.dptr, data.dptr, node->valuesize);
+
+ parent = NULL;
+ p = &rec_priv->db_ctx->tree.rb_node;
+
+ while (*p) {
+ struct db_rbt_node *r;
+ TDB_DATA search_key, search_val;
+ int res;
+
+ parent = (*p);
+
+ r = db_rbt2node(*p);
+
+ db_rbt_parse_node(r, &search_key, &search_val);
+
+ res = db_rbt_compare(this_key, search_key);
+
+ if (res == -1) {
+ p = &(*p)->rb_left;
+ }
+ else if (res == 1) {
+ p = &(*p)->rb_right;
+ }
+ else {
+ smb_panic("someone messed with the tree");
+ }
+ }
+
+ rb_link_node(&node->rb_node, parent, p);
+ rb_insert_color(&node->rb_node, &rec_priv->db_ctx->tree);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS db_rbt_delete(struct db_record *rec)
+{
+ struct db_rbt_rec *rec_priv = (struct db_rbt_rec *)rec->private_data;
+
+ if (rec_priv->node == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ rb_erase(&rec_priv->node->rb_node, &rec_priv->db_ctx->tree);
+ SAFE_FREE(rec_priv->node);
+
+ return NT_STATUS_OK;
+}
+
+static struct db_record *db_rbt_fetch_locked(struct db_context *db_ctx,
+ TALLOC_CTX *mem_ctx,
+ TDB_DATA key)
+{
+ struct db_rbt_ctx *ctx = talloc_get_type_abort(
+ db_ctx->private_data, struct db_rbt_ctx);
+
+ struct db_rbt_rec *rec_priv;
+ struct db_record *result;
+ struct rb_node *n;
+ size_t size;
+ bool found = false;
+ struct db_rbt_node *r = NULL;
+ TDB_DATA search_key = tdb_null, search_val = tdb_null;
+
+ n = ctx->tree.rb_node;
+
+ while (n != NULL) {
+ int res;
+
+ r = db_rbt2node(n);
+
+ db_rbt_parse_node(r, &search_key, &search_val);
+
+ res = db_rbt_compare(key, search_key);
+
+ if (res == -1) {
+ n = n->rb_left;
+ }
+ else if (res == 1) {
+ n = n->rb_right;
+ }
+ else {
+ found = true;
+ break;
+ }
+ }
+
+ /*
+ * In this low-level routine, play tricks to reduce the number of
+ * tallocs to one. Not recommened for general use, but here it pays
+ * off.
+ */
+
+ size = DBWRAP_RBT_ALIGN(sizeof(struct db_record))
+ + sizeof(struct db_rbt_rec);
+
+ if (!found) {
+ /*
+ * We need to keep the key around for later store
+ */
+ size += key.dsize;
+ }
+
+ result = (struct db_record *)talloc_size(mem_ctx, size);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ rec_priv = (struct db_rbt_rec *)
+ ((char *)result + DBWRAP_RBT_ALIGN(sizeof(struct db_record)));
+ rec_priv->db_ctx = ctx;
+
+ result->store = db_rbt_store;
+ result->delete_rec = db_rbt_delete;
+ result->private_data = rec_priv;
+
+ if (found) {
+ rec_priv->node = r;
+ result->key = search_key;
+ result->value = search_val;
+ }
+ else {
+ rec_priv->node = NULL;
+ result->key.dptr = (uint8 *)
+ ((char *)rec_priv + sizeof(*rec_priv));
+ result->key.dsize = key.dsize;
+ memcpy(result->key.dptr, key.dptr, key.dsize);
+
+ result->value = tdb_null;
+ }
+
+ return result;
+}
+
+static int db_rbt_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
+ TDB_DATA key, TDB_DATA *data)
+{
+ struct db_rbt_ctx *ctx = talloc_get_type_abort(
+ db->private_data, struct db_rbt_ctx);
+
+ struct rb_node *n;
+ bool found = false;
+ struct db_rbt_node *r = NULL;
+ TDB_DATA search_key, search_val;
+ uint8_t *result;
+
+ n = ctx->tree.rb_node;
+
+ while (n != NULL) {
+ int res;
+
+ r = db_rbt2node(n);
+
+ db_rbt_parse_node(r, &search_key, &search_val);
+
+ res = db_rbt_compare(key, search_key);
+
+ if (res == -1) {
+ n = n->rb_left;
+ }
+ else if (res == 1) {
+ n = n->rb_right;
+ }
+ else {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ *data = tdb_null;
+ return 0;
+ }
+
+ result = (uint8 *)talloc_memdup(mem_ctx, search_val.dptr,
+ search_val.dsize);
+ if (result == NULL) {
+ return -1;
+ }
+
+ data->dptr = result;
+ data->dsize = search_val.dsize;
+ return 0;
+}
+
+
+static int db_rbt_traverse(struct db_context *db,
+ int (*f)(struct db_record *db,
+ void *private_data),
+ void *private_data)
+{
+ /*
+ * Nobody uses this so far, and unused code is broken code :-)
+ */
+ return -1;
+}
+
+static int db_rbt_get_seqnum(struct db_context *db)
+{
+ return 0;
+}
+
+static int db_rbt_trans_dummy(struct db_context *db)
+{
+ /*
+ * Transactions are pretty pointless in-memory, just return success.
+ */
+ return 0;
+}
+
+struct db_context *db_open_rbt(TALLOC_CTX *mem_ctx)
+{
+ struct db_context *result;
+
+ result = talloc(mem_ctx, struct db_context);
+
+ if (result == NULL) {
+ return NULL;
+ }
+
+ result->private_data = TALLOC_ZERO_P(result, struct db_rbt_ctx);
+
+ if (result->private_data == NULL) {
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ result->fetch_locked = db_rbt_fetch_locked;
+ result->fetch = db_rbt_fetch;
+ result->traverse = db_rbt_traverse;
+ result->traverse_read = db_rbt_traverse;
+ result->get_seqnum = db_rbt_get_seqnum;
+ result->transaction_start = db_rbt_trans_dummy;
+ result->transaction_commit = db_rbt_trans_dummy;
+ result->transaction_cancel = db_rbt_trans_dummy;
+
+ return result;
+}
diff --git a/source3/lib/dbwrap_tdb.c b/source3/lib/dbwrap_tdb.c
new file mode 100644
index 0000000000..7bdadd3770
--- /dev/null
+++ b/source3/lib/dbwrap_tdb.c
@@ -0,0 +1,358 @@
+/*
+ Unix SMB/CIFS implementation.
+ Database interface wrapper around tdb
+ Copyright (C) Volker Lendecke 2005-2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+struct db_tdb_ctx {
+ struct tdb_wrap *wtdb;
+};
+
+static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag);
+static NTSTATUS db_tdb_delete(struct db_record *rec);
+
+static int db_tdb_record_destr(struct db_record* data)
+{
+ struct db_tdb_ctx *ctx =
+ talloc_get_type_abort(data->private_data, struct db_tdb_ctx);
+
+ /* This hex_encode() call allocates memory on data context. By way how current
+ __talloc_free() code works, it is OK to allocate in the destructor as
+ the children of data will be freed after call to the destructor and this
+ new 'child' will be caught and freed correctly.
+ */
+ DEBUG(10, (DEBUGLEVEL > 10
+ ? "Unlocking key %s\n" : "Unlocking key %.20s\n",
+ hex_encode(data, (unsigned char *)data->key.dptr,
+ data->key.dsize)));
+
+ if (tdb_chainunlock(ctx->wtdb->tdb, data->key) != 0) {
+ DEBUG(0, ("tdb_chainunlock failed\n"));
+ return -1;
+ }
+ return 0;
+}
+
+struct tdb_fetch_locked_state {
+ TALLOC_CTX *mem_ctx;
+ struct db_record *result;
+};
+
+static int db_tdb_fetchlock_parse(TDB_DATA key, TDB_DATA data,
+ void *private_data)
+{
+ struct tdb_fetch_locked_state *state =
+ (struct tdb_fetch_locked_state *)private_data;
+
+ state->result = (struct db_record *)talloc_size(
+ state->mem_ctx,
+ sizeof(struct db_record) + key.dsize + data.dsize);
+
+ if (state->result == NULL) {
+ return 0;
+ }
+
+ state->result->key.dsize = key.dsize;
+ state->result->key.dptr = ((uint8 *)state->result)
+ + sizeof(struct db_record);
+ memcpy(state->result->key.dptr, key.dptr, key.dsize);
+
+ state->result->value.dsize = data.dsize;
+
+ if (data.dsize > 0) {
+ state->result->value.dptr = state->result->key.dptr+key.dsize;
+ memcpy(state->result->value.dptr, data.dptr, data.dsize);
+ }
+ else {
+ state->result->value.dptr = NULL;
+ }
+
+ return 0;
+}
+
+static struct db_record *db_tdb_fetch_locked(struct db_context *db,
+ TALLOC_CTX *mem_ctx, TDB_DATA key)
+{
+ struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
+ struct db_tdb_ctx);
+ struct tdb_fetch_locked_state state;
+
+ /* Do not accidently allocate/deallocate w/o need when debug level is lower than needed */
+ if(DEBUGLEVEL >= 10) {
+ char *keystr = hex_encode(NULL, (unsigned char*)key.dptr, key.dsize);
+ DEBUG(10, (DEBUGLEVEL > 10
+ ? "Locking key %s\n" : "Locking key %.20s\n",
+ keystr));
+ TALLOC_FREE(keystr);
+ }
+
+ if (tdb_chainlock(ctx->wtdb->tdb, key) != 0) {
+ DEBUG(3, ("tdb_chainlock failed\n"));
+ return NULL;
+ }
+
+ state.mem_ctx = mem_ctx;
+ state.result = NULL;
+
+ tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_fetchlock_parse, &state);
+
+ if (state.result == NULL) {
+ db_tdb_fetchlock_parse(key, tdb_null, &state);
+ }
+
+ if (state.result == NULL) {
+ tdb_chainunlock(ctx->wtdb->tdb, key);
+ return NULL;
+ }
+
+ talloc_set_destructor(state.result, db_tdb_record_destr);
+
+ state.result->private_data = talloc_reference(state.result, ctx);
+ state.result->store = db_tdb_store;
+ state.result->delete_rec = db_tdb_delete;
+
+ DEBUG(10, ("Allocated locked data 0x%p\n", state.result));
+
+ return state.result;
+}
+
+struct tdb_fetch_state {
+ TALLOC_CTX *mem_ctx;
+ int result;
+ TDB_DATA data;
+};
+
+static int db_tdb_fetch_parse(TDB_DATA key, TDB_DATA data,
+ void *private_data)
+{
+ struct tdb_fetch_state *state =
+ (struct tdb_fetch_state *)private_data;
+
+ state->data.dptr = (uint8 *)talloc_memdup(state->mem_ctx, data.dptr,
+ data.dsize);
+ if (state->data.dptr == NULL) {
+ state->result = -1;
+ return 0;
+ }
+
+ state->data.dsize = data.dsize;
+ return 0;
+}
+
+static int db_tdb_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
+ TDB_DATA key, TDB_DATA *pdata)
+{
+ struct db_tdb_ctx *ctx = talloc_get_type_abort(
+ db->private_data, struct db_tdb_ctx);
+
+ struct tdb_fetch_state state;
+
+ state.mem_ctx = mem_ctx;
+ state.result = 0;
+ state.data = tdb_null;
+
+ tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_fetch_parse, &state);
+
+ if (state.result == -1) {
+ return -1;
+ }
+
+ *pdata = state.data;
+ return 0;
+}
+
+static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag)
+{
+ struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
+ struct db_tdb_ctx);
+
+ /*
+ * This has a bug: We need to replace rec->value for correct
+ * operation, but right now brlock and locking don't use the value
+ * anymore after it was stored.
+ */
+
+ return (tdb_store(ctx->wtdb->tdb, rec->key, data, flag) == 0) ?
+ NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+static NTSTATUS db_tdb_delete(struct db_record *rec)
+{
+ struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
+ struct db_tdb_ctx);
+
+ if (tdb_delete(ctx->wtdb->tdb, rec->key) == 0) {
+ return NT_STATUS_OK;
+ }
+
+ if (tdb_error(ctx->wtdb->tdb) == TDB_ERR_NOEXIST) {
+ return NT_STATUS_NOT_FOUND;
+ }
+
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+struct db_tdb_traverse_ctx {
+ struct db_context *db;
+ int (*f)(struct db_record *rec, void *private_data);
+ void *private_data;
+};
+
+static int db_tdb_traverse_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
+ void *private_data)
+{
+ struct db_tdb_traverse_ctx *ctx =
+ (struct db_tdb_traverse_ctx *)private_data;
+ struct db_record rec;
+
+ rec.key = kbuf;
+ rec.value = dbuf;
+ rec.store = db_tdb_store;
+ rec.delete_rec = db_tdb_delete;
+ rec.private_data = ctx->db->private_data;
+
+ return ctx->f(&rec, ctx->private_data);
+}
+
+static int db_tdb_traverse(struct db_context *db,
+ int (*f)(struct db_record *rec, void *private_data),
+ void *private_data)
+{
+ struct db_tdb_ctx *db_ctx =
+ talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
+ struct db_tdb_traverse_ctx ctx;
+
+ ctx.db = db;
+ ctx.f = f;
+ ctx.private_data = private_data;
+ return tdb_traverse(db_ctx->wtdb->tdb, db_tdb_traverse_func, &ctx);
+}
+
+static NTSTATUS db_tdb_store_deny(struct db_record *rec, TDB_DATA data, int flag)
+{
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+}
+
+static NTSTATUS db_tdb_delete_deny(struct db_record *rec)
+{
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+}
+
+static int db_tdb_traverse_read_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
+ void *private_data)
+{
+ struct db_tdb_traverse_ctx *ctx =
+ (struct db_tdb_traverse_ctx *)private_data;
+ struct db_record rec;
+
+ rec.key = kbuf;
+ rec.value = dbuf;
+ rec.store = db_tdb_store_deny;
+ rec.delete_rec = db_tdb_delete_deny;
+ rec.private_data = ctx->db->private_data;
+
+ return ctx->f(&rec, ctx->private_data);
+}
+
+static int db_tdb_traverse_read(struct db_context *db,
+ int (*f)(struct db_record *rec, void *private_data),
+ void *private_data)
+{
+ struct db_tdb_ctx *db_ctx =
+ talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
+ struct db_tdb_traverse_ctx ctx;
+
+ ctx.db = db;
+ ctx.f = f;
+ ctx.private_data = private_data;
+ return tdb_traverse_read(db_ctx->wtdb->tdb, db_tdb_traverse_read_func, &ctx);
+}
+
+static int db_tdb_get_seqnum(struct db_context *db)
+
+{
+ struct db_tdb_ctx *db_ctx =
+ talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
+ return tdb_get_seqnum(db_ctx->wtdb->tdb);
+}
+
+static int db_tdb_transaction_start(struct db_context *db)
+{
+ struct db_tdb_ctx *db_ctx =
+ talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
+ return tdb_transaction_start(db_ctx->wtdb->tdb);
+}
+
+static int db_tdb_transaction_commit(struct db_context *db)
+{
+ struct db_tdb_ctx *db_ctx =
+ talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
+ return tdb_transaction_commit(db_ctx->wtdb->tdb);
+}
+
+static int db_tdb_transaction_cancel(struct db_context *db)
+{
+ struct db_tdb_ctx *db_ctx =
+ talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
+ return tdb_transaction_cancel(db_ctx->wtdb->tdb);
+}
+
+struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
+ const char *name,
+ int hash_size, int tdb_flags,
+ int open_flags, mode_t mode)
+{
+ struct db_context *result = NULL;
+ struct db_tdb_ctx *db_tdb;
+
+ result = TALLOC_ZERO_P(mem_ctx, struct db_context);
+ if (result == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ goto fail;
+ }
+
+ result->private_data = db_tdb = TALLOC_P(result, struct db_tdb_ctx);
+ if (db_tdb == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ goto fail;
+ }
+
+ db_tdb->wtdb = tdb_wrap_open(db_tdb, name, hash_size, tdb_flags,
+ open_flags, mode);
+ if (db_tdb->wtdb == NULL) {
+ DEBUG(3, ("Could not open tdb: %s\n", strerror(errno)));
+ goto fail;
+ }
+
+ result->fetch_locked = db_tdb_fetch_locked;
+ result->fetch = db_tdb_fetch;
+ result->traverse = db_tdb_traverse;
+ result->traverse_read = db_tdb_traverse_read;
+ result->get_seqnum = db_tdb_get_seqnum;
+ result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
+ result->transaction_start = db_tdb_transaction_start;
+ result->transaction_commit = db_tdb_transaction_commit;
+ result->transaction_cancel = db_tdb_transaction_cancel;
+ return result;
+
+ fail:
+ if (result != NULL) {
+ TALLOC_FREE(result);
+ }
+ return NULL;
+}
diff --git a/source3/lib/dbwrap_util.c b/source3/lib/dbwrap_util.c
new file mode 100644
index 0000000000..ddc613150b
--- /dev/null
+++ b/source3/lib/dbwrap_util.c
@@ -0,0 +1,309 @@
+/*
+ Unix SMB/CIFS implementation.
+ Utility functions for the dbwrap API
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+int32_t dbwrap_fetch_int32(struct db_context *db, const char *keystr)
+{
+ TDB_DATA dbuf;
+ int32 ret;
+
+ if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
+ return -1;
+ }
+
+ if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(int32_t))) {
+ TALLOC_FREE(dbuf.dptr);
+ return -1;
+ }
+
+ ret = IVAL(dbuf.dptr, 0);
+ TALLOC_FREE(dbuf.dptr);
+ return ret;
+}
+
+int dbwrap_store_int32(struct db_context *db, const char *keystr, int32_t v)
+{
+ struct db_record *rec;
+ int32 v_store;
+ NTSTATUS status;
+
+ rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
+ if (rec == NULL) {
+ return -1;
+ }
+
+ SIVAL(&v_store, 0, v);
+
+ status = rec->store(rec, make_tdb_data((const uint8 *)&v_store,
+ sizeof(v_store)),
+ TDB_REPLACE);
+ TALLOC_FREE(rec);
+ return NT_STATUS_IS_OK(status) ? 0 : -1;
+}
+
+bool dbwrap_fetch_uint32(struct db_context *db, const char *keystr,
+ uint32_t *val)
+{
+ TDB_DATA dbuf;
+
+ if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
+ return false;
+ }
+
+ if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(uint32_t))) {
+ TALLOC_FREE(dbuf.dptr);
+ return false;
+ }
+
+ *val = IVAL(dbuf.dptr, 0);
+ TALLOC_FREE(dbuf.dptr);
+ return true;
+}
+
+bool dbwrap_store_uint32(struct db_context *db, const char *keystr, uint32_t v)
+{
+ struct db_record *rec;
+ uint32 v_store;
+ NTSTATUS status;
+
+ rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
+ if (rec == NULL) {
+ return false;
+ }
+
+ SIVAL(&v_store, 0, v);
+
+ status = rec->store(rec, make_tdb_data((const uint8 *)&v_store,
+ sizeof(v_store)),
+ TDB_REPLACE);
+ TALLOC_FREE(rec);
+ return NT_STATUS_IS_OK(status) ? 0 : -1;
+}
+
+/**
+ * Atomic unsigned integer change (addition):
+ *
+ * if value does not exist yet in the db, use *oldval as initial old value.
+ * return old value in *oldval.
+ * store *oldval + change_val to db.
+ */
+uint32_t dbwrap_change_uint32_atomic(struct db_context *db, const char *keystr,
+ uint32_t *oldval, uint32_t change_val)
+{
+ struct db_record *rec;
+ uint32 val = -1;
+ TDB_DATA data;
+
+ if (!(rec = db->fetch_locked(db, NULL,
+ string_term_tdb_data(keystr)))) {
+ return -1;
+ }
+
+ if (rec->value.dptr == NULL) {
+ val = *oldval;
+ } else if (rec->value.dsize == sizeof(val)) {
+ val = IVAL(rec->value.dptr, 0);
+ *oldval = val;
+ } else {
+ return -1;
+ }
+
+ val += change_val;
+
+ data.dsize = sizeof(val);
+ data.dptr = (uint8 *)&val;
+
+ rec->store(rec, data, TDB_REPLACE);
+
+ TALLOC_FREE(rec);
+
+ return 0;
+}
+
+/**
+ * Atomic integer change (addition):
+ *
+ * if value does not exist yet in the db, use *oldval as initial old value.
+ * return old value in *oldval.
+ * store *oldval + change_val to db.
+ */
+int32 dbwrap_change_int32_atomic(struct db_context *db, const char *keystr,
+ int32 *oldval, int32 change_val)
+{
+ struct db_record *rec;
+ int32 val = -1;
+ TDB_DATA data;
+
+ if (!(rec = db->fetch_locked(db, NULL,
+ string_term_tdb_data(keystr)))) {
+ return -1;
+ }
+
+ if (rec->value.dptr == NULL) {
+ val = *oldval;
+ } else if (rec->value.dsize == sizeof(val)) {
+ val = IVAL(rec->value.dptr, 0);
+ *oldval = val;
+ } else {
+ return -1;
+ }
+
+ val += change_val;
+
+ data.dsize = sizeof(val);
+ data.dptr = (uint8 *)&val;
+
+ rec->store(rec, data, TDB_REPLACE);
+
+ TALLOC_FREE(rec);
+
+ return 0;
+}
+
+NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
+ int flag)
+{
+ int res;
+ struct db_record *rec = NULL;
+ NTSTATUS status;
+
+ res = db->transaction_start(db);
+ if (res != 0) {
+ DEBUG(5, ("transaction_start failed\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ rec = db->fetch_locked(db, talloc_tos(), key);
+ if (rec == NULL) {
+ DEBUG(5, ("fetch_locked failed\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto cancel;
+ }
+
+ status = rec->store(rec, dbuf, flag);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("store returned %s\n", nt_errstr(status)));
+ goto cancel;
+ }
+
+ TALLOC_FREE(rec);
+
+ res = db->transaction_commit(db);
+ if (res != 0) {
+ DEBUG(5, ("tdb_transaction_commit failed\n"));
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ TALLOC_FREE(rec);
+ return status;
+ }
+
+ return NT_STATUS_OK;
+
+ cancel:
+ TALLOC_FREE(rec);
+
+ if (db->transaction_cancel(db) != 0) {
+ smb_panic("Cancelling transaction failed");
+ }
+ return status;
+}
+
+NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key)
+{
+ int res;
+ struct db_record *rec = NULL;
+ NTSTATUS status;
+
+ res = db->transaction_start(db);
+ if (res != 0) {
+ DEBUG(5, ("transaction_start failed\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ rec = db->fetch_locked(db, talloc_tos(), key);
+ if (rec == NULL) {
+ DEBUG(5, ("fetch_locked failed\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto cancel;
+ }
+
+ status = rec->delete_rec(rec);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("delete_rec returned %s\n", nt_errstr(status)));
+ goto cancel;
+ }
+
+ TALLOC_FREE(rec);
+
+ res = db->transaction_commit(db);
+ if (res != 0) {
+ DEBUG(5, ("tdb_transaction_commit failed\n"));
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ TALLOC_FREE(rec);
+ return status;
+ }
+
+ return NT_STATUS_OK;
+
+ cancel:
+ TALLOC_FREE(rec);
+
+ if (db->transaction_cancel(db) != 0) {
+ smb_panic("Cancelling transaction failed");
+ }
+ return status;
+}
+
+NTSTATUS dbwrap_trans_store_int32(struct db_context *db, const char *keystr,
+ int32_t v)
+{
+ int32 v_store;
+
+ SIVAL(&v_store, 0, v);
+
+ return dbwrap_trans_store(db, string_term_tdb_data(keystr),
+ make_tdb_data((const uint8 *)&v_store,
+ sizeof(v_store)),
+ TDB_REPLACE);
+}
+
+NTSTATUS dbwrap_trans_store_uint32(struct db_context *db, const char *keystr,
+ uint32_t v)
+{
+ uint32 v_store;
+
+ SIVAL(&v_store, 0, v);
+
+ return dbwrap_trans_store(db, string_term_tdb_data(keystr),
+ make_tdb_data((const uint8 *)&v_store,
+ sizeof(v_store)),
+ TDB_REPLACE);
+}
+
+NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
+ TDB_DATA data, int flags)
+{
+ return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
+}
+
+NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
+{
+ return dbwrap_trans_delete(db, string_term_tdb_data(key));
+}
diff --git a/source3/lib/debug.c b/source3/lib/debug.c
new file mode 100644
index 0000000000..d835ea7c17
--- /dev/null
+++ b/source3/lib/debug.c
@@ -0,0 +1,1100 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Elrond 2002
+ Copyright (C) Simo Sorce 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* -------------------------------------------------------------------------- **
+ * Defines...
+ *
+ * FORMAT_BUFR_MAX - Index of the last byte of the format buffer;
+ * format_bufr[FORMAT_BUFR_MAX] should always be reserved
+ * for a terminating null byte.
+ */
+
+#define FORMAT_BUFR_SIZE 1024
+#define FORMAT_BUFR_MAX (FORMAT_BUFR_SIZE - 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.
+ * DEBUGLEVEL - System-wide debug message limit. Messages with message-
+ * levels higher than DEBUGLEVEL will not be processed.
+ */
+
+XFILE *dbf = NULL;
+static char *debugf = NULL;
+bool debug_warn_unknown_class = True;
+bool debug_auto_add_unknown_class = True;
+bool AllowDebugChange = True;
+
+/*
+ used to check if the user specified a
+ logfile on the command line
+*/
+bool override_logfile;
+
+static TALLOC_CTX *tmp_debug_ctx;
+
+/*
+ * This is to allow assignment to DEBUGLEVEL before the debug
+ * system has been initialized.
+ */
+static int debug_all_class_hack = 1;
+static bool debug_all_class_isset_hack = True;
+
+static int debug_num_classes = 0;
+int *DEBUGLEVEL_CLASS = &debug_all_class_hack;
+bool *DEBUGLEVEL_CLASS_ISSET = &debug_all_class_isset_hack;
+
+/* DEBUGLEVEL is #defined to *debug_level */
+int DEBUGLEVEL = &debug_all_class_hack;
+
+
+/* -------------------------------------------------------------------------- **
+ * Internal variables.
+ *
+ * stdout_logging - Default False, if set to True then dbf will be set to
+ * stdout and debug output will go to dbf only, and not
+ * to syslog. Set in setup_logging() and read in Debug1().
+ *
+ * debug_count - Number of debug messages that have been output.
+ * Used to check log size.
+ *
+ * syslog_level - Internal copy of the message debug level. Written by
+ * dbghdr() and read by Debug1().
+ *
+ * format_bufr - Used to format debug messages. The dbgtext() function
+ * prints debug messages to a string, and then passes the
+ * string to format_debug_text(), which uses format_bufr
+ * to build the formatted output.
+ *
+ * format_pos - Marks the first free byte of the format_bufr.
+ *
+ *
+ * log_overflow - When this variable is True, never attempt to check the
+ * size of the log. This is a hack, so that we can write
+ * a message using DEBUG, from open_logs() when we
+ * are unable to open a new log file for some reason.
+ */
+
+static bool stdout_logging = False;
+static int debug_count = 0;
+#ifdef WITH_SYSLOG
+static int syslog_level = 0;
+#endif
+static char *format_bufr = NULL;
+static size_t format_pos = 0;
+static bool log_overflow = False;
+
+/*
+ * Define all the debug class selection names here. Names *MUST NOT* contain
+ * white space. There must be one name for each DBGC_<class name>, and they
+ * must be in the table in the order of DBGC_<class name>..
+ */
+static const char *default_classname_table[] = {
+ "all", /* DBGC_ALL; index refs traditional DEBUGLEVEL */
+ "tdb", /* DBGC_TDB */
+ "printdrivers", /* DBGC_PRINTDRIVERS */
+ "lanman", /* DBGC_LANMAN */
+ "smb", /* DBGC_SMB */
+ "rpc_parse", /* DBGC_RPC_PARSE */
+ "rpc_srv", /* DBGC_RPC_SRV */
+ "rpc_cli", /* DBGC_RPC_CLI */
+ "passdb", /* DBGC_PASSDB */
+ "sam", /* DBGC_SAM */
+ "auth", /* DBGC_AUTH */
+ "winbind", /* DBGC_WINBIND */
+ "vfs", /* DBGC_VFS */
+ "idmap", /* DBGC_IDMAP */
+ "quota", /* DBGC_QUOTA */
+ "acls", /* DBGC_ACLS */
+ "locking", /* DBGC_LOCKING */
+ "msdfs", /* DBGC_MSDFS */
+ "dmapi", /* DBGC_DMAPI */
+ "registry", /* DBGC_REGISTRY */
+ NULL
+};
+
+static char **classname_table = NULL;
+
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+/***************************************************************************
+ Free memory pointed to by global pointers.
+****************************************************************************/
+
+static bool initialized;
+
+void gfree_debugsyms(void)
+{
+ int i;
+
+ if ( classname_table ) {
+ for ( i = 0; i < debug_num_classes; i++ ) {
+ SAFE_FREE( classname_table[i] );
+ }
+ SAFE_FREE( classname_table );
+ }
+
+ if ( DEBUGLEVEL_CLASS != &debug_all_class_hack ) {
+ SAFE_FREE( DEBUGLEVEL_CLASS );
+ DEBUGLEVEL_CLASS = &debug_all_class_hack;
+ }
+
+ if ( DEBUGLEVEL_CLASS_ISSET != &debug_all_class_isset_hack ) {
+ SAFE_FREE( DEBUGLEVEL_CLASS_ISSET );
+ DEBUGLEVEL_CLASS_ISSET = &debug_all_class_isset_hack;
+ }
+
+ SAFE_FREE(format_bufr);
+
+ debug_num_classes = 0;
+
+ debug_level = DEBUGLEVEL_CLASS;
+
+ initialized = false;
+}
+
+/****************************************************************************
+utility lists registered debug class names's
+****************************************************************************/
+
+#define MAX_CLASS_NAME_SIZE 1024
+
+static char *debug_list_class_names_and_levels(void)
+{
+ int i, dim;
+ char **list;
+ char *buf = NULL;
+ char *b;
+ bool err = False;
+
+ if (DEBUGLEVEL_CLASS == &debug_all_class_hack) {
+ return NULL;
+ }
+
+ list = SMB_CALLOC_ARRAY(char *, debug_num_classes + 1);
+ if (!list) {
+ return NULL;
+ }
+
+ /* prepare strings */
+ for (i = 0, dim = 0; i < debug_num_classes; i++) {
+ int l = asprintf(&list[i],
+ "%s:%d ",
+ classname_table[i],
+ DEBUGLEVEL_CLASS_ISSET[i]?DEBUGLEVEL_CLASS[i]:DEBUGLEVEL);
+ if (l < 0 || l > MAX_CLASS_NAME_SIZE) {
+ err = True;
+ goto done;
+ }
+ dim += l;
+ }
+
+ /* create single string list - add space for newline */
+ b = buf = (char *)SMB_MALLOC(dim+1);
+ if (!buf) {
+ err = True;
+ goto done;
+ }
+ for (i = 0; i < debug_num_classes; i++) {
+ int l = strlen(list[i]);
+ strncpy(b, list[i], l);
+ b = b + l;
+ }
+ b[-1] = '\n'; /* replace last space with newline */
+ b[0] = '\0'; /* null terminate string */
+
+done:
+ /* free strings list */
+ for (i = 0; i < debug_num_classes; i++) {
+ SAFE_FREE(list[i]);
+ }
+ SAFE_FREE(list);
+
+ if (err) {
+ return NULL;
+ } else {
+ return buf;
+ }
+}
+
+/****************************************************************************
+ Utility access to debug class names's.
+****************************************************************************/
+
+const char *debug_classname_from_index(int ndx)
+{
+ if (ndx < 0 || ndx >= debug_num_classes)
+ return NULL;
+ else
+ return classname_table[ndx];
+}
+
+/****************************************************************************
+ Utility to translate names to debug class index's (internal version).
+****************************************************************************/
+
+static int debug_lookup_classname_int(const char* classname)
+{
+ int i;
+
+ if (!classname) return -1;
+
+ for (i=0; i < debug_num_classes; i++) {
+ if (strcmp(classname, classname_table[i])==0)
+ return i;
+ }
+ return -1;
+}
+
+/****************************************************************************
+ Add a new debug class to the system.
+****************************************************************************/
+
+int debug_add_class(const char *classname)
+{
+ int ndx;
+ void *new_ptr;
+
+ if (!classname)
+ return -1;
+
+ /* check the init has yet been called */
+ debug_init();
+
+ ndx = debug_lookup_classname_int(classname);
+ if (ndx >= 0)
+ return ndx;
+ ndx = debug_num_classes;
+
+ new_ptr = DEBUGLEVEL_CLASS;
+ if (DEBUGLEVEL_CLASS == &debug_all_class_hack) {
+ /* Initial loading... */
+ new_ptr = NULL;
+ }
+ new_ptr = SMB_REALLOC_ARRAY(new_ptr, int, debug_num_classes + 1);
+ if (!new_ptr)
+ return -1;
+ DEBUGLEVEL_CLASS = (int *)new_ptr;
+ DEBUGLEVEL_CLASS[ndx] = 0;
+
+ /* debug_level is the pointer used for the DEBUGLEVEL-thingy */
+ if (ndx==0) {
+ /* Transfer the initial level from debug_all_class_hack */
+ DEBUGLEVEL_CLASS[ndx] = DEBUGLEVEL;
+ }
+ debug_level = DEBUGLEVEL_CLASS;
+
+ new_ptr = DEBUGLEVEL_CLASS_ISSET;
+ if (new_ptr == &debug_all_class_isset_hack) {
+ new_ptr = NULL;
+ }
+ new_ptr = SMB_REALLOC_ARRAY(new_ptr, bool, debug_num_classes + 1);
+ if (!new_ptr)
+ return -1;
+ DEBUGLEVEL_CLASS_ISSET = (bool *)new_ptr;
+ DEBUGLEVEL_CLASS_ISSET[ndx] = False;
+
+ new_ptr = SMB_REALLOC_ARRAY(classname_table, char *, debug_num_classes + 1);
+ if (!new_ptr)
+ return -1;
+ classname_table = (char **)new_ptr;
+
+ classname_table[ndx] = SMB_STRDUP(classname);
+ if (! classname_table[ndx])
+ return -1;
+
+ debug_num_classes++;
+
+ return ndx;
+}
+
+/****************************************************************************
+ Utility to translate names to debug class index's (public version).
+****************************************************************************/
+
+int debug_lookup_classname(const char *classname)
+{
+ int ndx;
+
+ if (!classname || !*classname)
+ return -1;
+
+ ndx = debug_lookup_classname_int(classname);
+
+ if (ndx != -1)
+ return ndx;
+
+ if (debug_warn_unknown_class) {
+ DEBUG(0, ("debug_lookup_classname(%s): Unknown class\n",
+ classname));
+ }
+ if (debug_auto_add_unknown_class) {
+ return debug_add_class(classname);
+ }
+ return -1;
+}
+
+/****************************************************************************
+ Dump the current registered debug levels.
+****************************************************************************/
+
+static void debug_dump_status(int level)
+{
+ int q;
+
+ DEBUG(level, ("INFO: Current debug levels:\n"));
+ for (q = 0; q < debug_num_classes; q++) {
+ DEBUGADD(level, (" %s: %s/%d\n",
+ classname_table[q],
+ (DEBUGLEVEL_CLASS_ISSET[q]
+ ? "True" : "False"),
+ DEBUGLEVEL_CLASS[q]));
+ }
+}
+
+/****************************************************************************
+ parse the debug levels from smbcontrol. Example debug level parameter:
+ printdrivers:7
+****************************************************************************/
+
+static bool debug_parse_params(char **params)
+{
+ int i, ndx;
+ char *class_name;
+ char *class_level;
+
+ if (!params)
+ return False;
+
+ /* Allow DBGC_ALL to be specified w/o requiring its class name e.g."10"
+ * v.s. "all:10", this is the traditional way to set DEBUGLEVEL
+ */
+ if (isdigit((int)params[0][0])) {
+ DEBUGLEVEL_CLASS[DBGC_ALL] = atoi(params[0]);
+ DEBUGLEVEL_CLASS_ISSET[DBGC_ALL] = True;
+ i = 1; /* start processing at the next params */
+ } else {
+ i = 0; /* DBGC_ALL not specified OR class name was included */
+ }
+
+ /* Fill in new debug class levels */
+ for (; i < debug_num_classes && params[i]; i++) {
+ char *saveptr;
+ if ((class_name = strtok_r(params[i],":", &saveptr)) &&
+ (class_level = strtok_r(NULL, "\0", &saveptr)) &&
+ ((ndx = debug_lookup_classname(class_name)) != -1)) {
+ DEBUGLEVEL_CLASS[ndx] = atoi(class_level);
+ DEBUGLEVEL_CLASS_ISSET[ndx] = True;
+ } else {
+ DEBUG(0,("debug_parse_params: unrecognized debug class name or format [%s]\n", params[i]));
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Parse the debug levels from smb.conf. Example debug level string:
+ 3 tdb:5 printdrivers:7
+ Note: the 1st param has no "name:" preceeding it.
+****************************************************************************/
+
+bool debug_parse_levels(const char *params_str)
+{
+ char **params;
+
+ /* Just in case */
+ debug_init();
+
+ if (AllowDebugChange == False)
+ return True;
+
+ params = str_list_make(talloc_tos(), params_str, NULL);
+
+ if (debug_parse_params(params)) {
+ debug_dump_status(5);
+ TALLOC_FREE(params);
+ return True;
+ } else {
+ TALLOC_FREE(params);
+ return False;
+ }
+}
+
+/****************************************************************************
+ Receive a "set debug level" message.
+****************************************************************************/
+
+void debug_message(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ DATA_BLOB *data)
+{
+ const char *params_str = (const char *)data->data;
+
+ /* Check, it's a proper string! */
+ if (params_str[(data->length)-1] != '\0') {
+ DEBUG(1, ("Invalid debug message from pid %u to pid %u\n",
+ (unsigned int)procid_to_pid(&src),
+ (unsigned int)getpid()));
+ return;
+ }
+
+ DEBUG(3, ("INFO: Remote set of debug to `%s' (pid %u from pid %u)\n",
+ params_str, (unsigned int)getpid(),
+ (unsigned int)procid_to_pid(&src)));
+
+ debug_parse_levels(params_str);
+}
+
+/****************************************************************************
+ Return current debug level.
+****************************************************************************/
+
+static void debuglevel_message(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ DATA_BLOB *data)
+{
+ char *message = debug_list_class_names_and_levels();
+
+ if (!message) {
+ DEBUG(0,("debuglevel_message - debug_list_class_names_and_levels returned NULL\n"));
+ return;
+ }
+
+ DEBUG(1,("INFO: Received REQ_DEBUGLEVEL message from PID %s\n",
+ procid_str_static(&src)));
+ messaging_send_buf(msg_ctx, src, MSG_DEBUGLEVEL,
+ (uint8 *)message, strlen(message) + 1);
+
+ SAFE_FREE(message);
+}
+
+/****************************************************************************
+Init debugging (one time stuff)
+****************************************************************************/
+
+void debug_init(void)
+{
+ const char **p;
+
+ if (initialized)
+ return;
+
+ initialized = true;
+
+ for(p = default_classname_table; *p; p++) {
+ debug_add_class(*p);
+ }
+ format_bufr = (char *)SMB_MALLOC(FORMAT_BUFR_SIZE);
+ if (!format_bufr) {
+ smb_panic("debug_init: unable to create buffer");
+ }
+}
+
+void debug_register_msgs(struct messaging_context *msg_ctx)
+{
+ messaging_register(msg_ctx, NULL, MSG_DEBUG, debug_message);
+ messaging_register(msg_ctx, NULL, MSG_REQ_DEBUGLEVEL,
+ debuglevel_message);
+}
+
+/***************************************************************************
+ Get ready for syslog stuff
+**************************************************************************/
+
+void setup_logging(const char *pname, bool interactive)
+{
+ debug_init();
+
+ /* reset to allow multiple setup calls, going from interactive to
+ non-interactive */
+ stdout_logging = False;
+ if (dbf) {
+ x_fflush(dbf);
+ (void) x_fclose(dbf);
+ }
+
+ dbf = NULL;
+
+ if (interactive) {
+ stdout_logging = True;
+ dbf = x_stdout;
+ x_setbuf( x_stdout, NULL );
+ }
+#ifdef WITH_SYSLOG
+ else {
+ const char *p = strrchr_m( pname,'/' );
+ if (p)
+ pname = p + 1;
+#ifdef LOG_DAEMON
+ openlog( pname, LOG_PID, SYSLOG_FACILITY );
+#else
+ /* for old systems that have no facility codes. */
+ openlog( pname, LOG_PID );
+#endif
+ }
+#endif
+}
+
+/***************************************************************************
+ Set the logfile name.
+**************************************************************************/
+
+void debug_set_logfile(const char *name)
+{
+ SAFE_FREE(debugf);
+ debugf = SMB_STRDUP(name);
+}
+
+/**************************************************************************
+ reopen the log files
+ note that we now do this unconditionally
+ We attempt to open the new debug fp before closing the old. This means
+ if we run out of fd's we just keep using the old fd rather than aborting.
+ Fix from dgibson@linuxcare.com.
+**************************************************************************/
+
+bool reopen_logs( void )
+{
+ char *fname = NULL;
+ mode_t oldumask;
+ XFILE *new_dbf = NULL;
+ XFILE *old_dbf = NULL;
+ bool ret = True;
+
+ if (stdout_logging)
+ return True;
+
+ oldumask = umask( 022 );
+
+ fname = debugf;
+ if (!fname) {
+ return false;
+ }
+ debugf = NULL;
+
+ if (lp_loaded()) {
+ char *logfname;
+
+ logfname = lp_logfile();
+ if (*logfname) {
+ SAFE_FREE(fname);
+ fname = SMB_STRDUP(logfname);
+ if (!fname) {
+ return false;
+ }
+ }
+ }
+
+ debugf = fname;
+ new_dbf = x_fopen( debugf, O_WRONLY|O_APPEND|O_CREAT, 0644);
+
+ if (!new_dbf) {
+ log_overflow = True;
+ DEBUG(0, ("Unable to open new log file %s: %s\n", debugf, strerror(errno)));
+ log_overflow = False;
+ if (dbf)
+ x_fflush(dbf);
+ ret = False;
+ } else {
+ x_setbuf(new_dbf, NULL);
+ old_dbf = dbf;
+ dbf = new_dbf;
+ if (old_dbf)
+ (void) x_fclose(old_dbf);
+ }
+
+ /* Fix from klausr@ITAP.Physik.Uni-Stuttgart.De
+ * to fix problem where smbd's that generate less
+ * than 100 messages keep growing the log.
+ */
+ force_check_log_size();
+ (void)umask(oldumask);
+
+ /* Take over stderr to catch ouput into logs */
+ if (dbf && sys_dup2(x_fileno(dbf), 2) == -1) {
+ close_low_fds(True); /* Close stderr too, if dup2 can't point it
+ at the logfile */
+ }
+
+ return ret;
+}
+
+/**************************************************************************
+ Force a check of the log size.
+ ***************************************************************************/
+
+void force_check_log_size( void )
+{
+ debug_count = 100;
+}
+
+/***************************************************************************
+ Check to see if there is any need to check if the logfile has grown too big.
+**************************************************************************/
+
+bool need_to_check_log_size( void )
+{
+ int maxlog;
+
+ if( debug_count < 100 )
+ return( False );
+
+ maxlog = lp_max_log_size() * 1024;
+ if( !dbf || maxlog <= 0 ) {
+ debug_count = 0;
+ return(False);
+ }
+ return( True );
+}
+
+/**************************************************************************
+ Check to see if the log has grown to be too big.
+ **************************************************************************/
+
+void check_log_size( void )
+{
+ int maxlog;
+ SMB_STRUCT_STAT st;
+
+ /*
+ * We need to be root to check/change log-file, skip this and let the main
+ * loop check do a new check as root.
+ */
+
+ if( geteuid() != 0 )
+ return;
+
+ if(log_overflow || !need_to_check_log_size() )
+ return;
+
+ maxlog = lp_max_log_size() * 1024;
+
+ if( sys_fstat( x_fileno( dbf ), &st ) == 0 && st.st_size > maxlog ) {
+ (void)reopen_logs();
+ if( dbf && get_file_size( debugf ) > maxlog ) {
+ char *name = NULL;
+
+ if (asprintf(&name, "%s.old", debugf ) < 0) {
+ return;
+ }
+ (void)rename(debugf, name);
+
+ if (!reopen_logs()) {
+ /* We failed to reopen a log - continue using the old name. */
+ (void)rename(name, debugf);
+ }
+ SAFE_FREE(name);
+ }
+ }
+
+ /*
+ * Here's where we need to panic if dbf == NULL..
+ */
+
+ if(dbf == NULL) {
+ /* This code should only be reached in very strange
+ * circumstances. If we merely fail to open the new log we
+ * should stick with the old one. ergo this should only be
+ * reached when opening the logs for the first time: at
+ * startup or when the log level is increased from zero.
+ * -dwg 6 June 2000
+ */
+ dbf = x_fopen( "/dev/console", O_WRONLY, 0);
+ if(dbf) {
+ DEBUG(0,("check_log_size: open of debug file %s failed - using console.\n",
+ debugf ));
+ } else {
+ /*
+ * We cannot continue without a debug file handle.
+ */
+ abort();
+ }
+ }
+ debug_count = 0;
+}
+
+/*************************************************************************
+ Write an debug message on the debugfile.
+ This is called by dbghdr() and format_debug_text().
+************************************************************************/
+
+ int Debug1( const char *format_str, ... )
+{
+ va_list ap;
+ int old_errno = errno;
+
+ debug_count++;
+
+ if( stdout_logging ) {
+ va_start( ap, format_str );
+ if(dbf)
+ (void)x_vfprintf( dbf, format_str, ap );
+ va_end( ap );
+ errno = old_errno;
+ goto done;
+ }
+
+ /* prevent recursion by checking if reopen_logs() has temporaily
+ set the debugf string to NULL */
+ if( debugf == NULL)
+ goto done;
+
+#ifdef WITH_SYSLOG
+ if( !lp_syslog_only() )
+#endif
+ {
+ if( !dbf ) {
+ mode_t oldumask = umask( 022 );
+
+ dbf = x_fopen( debugf, O_WRONLY|O_APPEND|O_CREAT, 0644 );
+ (void)umask( oldumask );
+ if( dbf ) {
+ x_setbuf( dbf, NULL );
+ } else {
+ errno = old_errno;
+ goto done;
+ }
+ }
+ }
+
+#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;
+ char *msgbuf = NULL;
+ int ret;
+
+ if( syslog_level >= ( sizeof(priority_map) / sizeof(priority_map[0]) ) || syslog_level < 0)
+ priority = LOG_DEBUG;
+ else
+ priority = priority_map[syslog_level];
+
+ va_start(ap, format_str);
+ ret = vasprintf(&msgbuf, format_str, ap);
+ va_end(ap);
+
+ if (ret == -1) {
+ syslog(priority, "%s", msgbuf);
+ }
+ SAFE_FREE(msgbuf);
+ }
+#endif
+
+ check_log_size();
+
+#ifdef WITH_SYSLOG
+ if( !lp_syslog_only() )
+#endif
+ {
+ va_start( ap, format_str );
+ if(dbf)
+ (void)x_vfprintf( dbf, format_str, ap );
+ va_end( ap );
+ if(dbf)
+ (void)x_fflush( dbf );
+ }
+
+ done:
+ TALLOC_FREE(tmp_debug_ctx);
+
+ errno = old_errno;
+
+ return( 0 );
+}
+
+
+/**************************************************************************
+ 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;
+}
+
+/***************************************************************************
+ 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( const char *msg )
+{
+ size_t i;
+ bool timestamp = (!stdout_logging && (lp_timestamp_logs() || !(lp_loaded())));
+
+ if (!format_bufr) {
+ debug_init();
+ }
+
+ 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';
+}
+
+/***************************************************************************
+ Flush debug output, including the format buffer content.
+
+ Input: none
+ Output: none
+***************************************************************************/
+
+void dbgflush( void )
+{
+ bufr_print();
+ if(dbf)
+ (void)x_fflush( dbf );
+}
+
+/***************************************************************************
+ Print a Debug Header.
+
+ Input: level - Debug level of the message (not the system-wide debug
+ level. )
+ cls - Debuglevel class of the calling module.
+ 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, int cls, const char *file, const char *func, int line)
+{
+ /* Ensure we don't lose any real errno value. */
+ int old_errno = errno;
+
+ if( format_pos ) {
+ /* This is a fudge. If there is stuff sitting in the format_bufr, then
+ * the *right* thing to do is to call
+ * format_debug_text( "\n" );
+ * to write the remainder, and then proceed with the new header.
+ * Unfortunately, there are several places in the code at which
+ * the DEBUG() macro is used to build partial lines. That in mind,
+ * we'll work under the assumption that an incomplete line indicates
+ * that a new header is *not* desired.
+ */
+ return( True );
+ }
+
+#ifdef WITH_SYSLOG
+ /* Set syslog_level. */
+ syslog_level = level;
+#endif
+
+ /* Don't print a header if we're logging to stdout. */
+ if( stdout_logging )
+ return( True );
+
+ /* Print the header if timestamps are turned on. If parameters are
+ * not yet loaded, then default to timestamps on.
+ */
+ if( lp_timestamp_logs() || lp_debug_prefix_timestamp() || !(lp_loaded()) ) {
+ char header_str[200];
+
+ header_str[0] = '\0';
+
+ if( lp_debug_pid())
+ slprintf(header_str,sizeof(header_str)-1,", pid=%u",(unsigned int)sys_getpid());
+
+ if( lp_debug_uid()) {
+ size_t hs_len = strlen(header_str);
+ slprintf(header_str + hs_len,
+ sizeof(header_str) - 1 - hs_len,
+ ", effective(%u, %u), real(%u, %u)",
+ (unsigned int)geteuid(), (unsigned int)getegid(),
+ (unsigned int)getuid(), (unsigned int)getgid());
+ }
+
+ if (lp_debug_class() && (cls != DBGC_ALL)) {
+ size_t hs_len = strlen(header_str);
+ slprintf(header_str + hs_len,
+ sizeof(header_str) -1 - hs_len,
+ ", class=%s",
+ default_classname_table[cls]);
+ }
+
+ /* Print it all out at once to prevent split syslog output. */
+ if( lp_debug_prefix_timestamp() ) {
+ (void)Debug1( "[%s, %2d%s] ",
+ current_timestring(debug_ctx(),
+ lp_debug_hires_timestamp()),
+ level, header_str);
+ } else {
+ (void)Debug1( "[%s, %2d%s] %s:%s(%d)\n",
+ current_timestring(debug_ctx(),
+ lp_debug_hires_timestamp()),
+ level, header_str, file, func, line );
+ }
+ }
+
+ errno = old_errno;
+ return( True );
+}
+
+/***************************************************************************
+ Add text to the body of the "current" debug message via the format buffer.
+
+ Input: format_str - Format string, as used in printf(), et. al.
+ ... - Variable argument list.
+
+ ..or.. va_alist - Old style variable parameter list starting point.
+
+ Output: Always True. See dbghdr() for more info, though this is not
+ likely to be used in the same way.
+
+***************************************************************************/
+
+ bool dbgtext( const char *format_str, ... )
+{
+ va_list ap;
+ char *msgbuf = NULL;
+ bool ret = true;
+ int res;
+
+ va_start(ap, format_str);
+ res = vasprintf(&msgbuf, format_str, ap);
+ va_end(ap);
+
+ if (res != -1) {
+ format_debug_text(msgbuf);
+ } else {
+ ret = false;
+ }
+ SAFE_FREE(msgbuf);
+ return ret;
+}
+
+/*
+ * Get us a temporary talloc context usable just for DEBUG arguments
+ */
+TALLOC_CTX *debug_ctx(void)
+{
+ if (tmp_debug_ctx == NULL) {
+ tmp_debug_ctx = talloc_named_const(NULL, 0, "debug_ctx");
+ }
+ return tmp_debug_ctx;
+}
diff --git a/source3/lib/display_sec.c b/source3/lib/display_sec.c
new file mode 100644
index 0000000000..67392e4568
--- /dev/null
+++ b/source3/lib/display_sec.c
@@ -0,0 +1,317 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996 - 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+convert a security permissions into a string
+****************************************************************************/
+
+char *get_sec_mask_str(TALLOC_CTX *ctx, uint32 type)
+{
+ char *typestr = talloc_strdup(ctx, "");
+
+ if (!typestr) {
+ return NULL;
+ }
+
+ if (type & GENERIC_ALL_ACCESS) {
+ typestr = talloc_asprintf_append(typestr,
+ "Generic all access ");
+ if (!typestr) {
+ return NULL;
+ }
+ }
+ if (type & GENERIC_EXECUTE_ACCESS) {
+ typestr = talloc_asprintf_append(typestr,
+ "Generic execute access");
+ if (!typestr) {
+ return NULL;
+ }
+ }
+ if (type & GENERIC_WRITE_ACCESS) {
+ typestr = talloc_asprintf_append(typestr,
+ "Generic write access ");
+ if (!typestr) {
+ return NULL;
+ }
+ }
+ if (type & GENERIC_READ_ACCESS) {
+ typestr = talloc_asprintf_append(typestr,
+ "Generic read access ");
+ if (!typestr) {
+ return NULL;
+ }
+ }
+ if (type & MAXIMUM_ALLOWED_ACCESS) {
+ typestr = talloc_asprintf_append(typestr,
+ "MAXIMUM_ALLOWED_ACCESS ");
+ if (!typestr) {
+ return NULL;
+ }
+ }
+ if (type & SYSTEM_SECURITY_ACCESS) {
+ typestr = talloc_asprintf_append(typestr,
+ "SYSTEM_SECURITY_ACCESS ");
+ if (!typestr) {
+ return NULL;
+ }
+ }
+ if (type & SYNCHRONIZE_ACCESS) {
+ typestr = talloc_asprintf_append(typestr,
+ "SYNCHRONIZE_ACCESS ");
+ if (!typestr) {
+ return NULL;
+ }
+ }
+ if (type & WRITE_OWNER_ACCESS) {
+ typestr = talloc_asprintf_append(typestr,
+ "WRITE_OWNER_ACCESS ");
+ if (!typestr) {
+ return NULL;
+ }
+ }
+ if (type & WRITE_DAC_ACCESS) {
+ typestr = talloc_asprintf_append(typestr,
+ "WRITE_DAC_ACCESS ");
+ if (!typestr) {
+ return NULL;
+ }
+ }
+ if (type & READ_CONTROL_ACCESS) {
+ typestr = talloc_asprintf_append(typestr,
+ "READ_CONTROL_ACCESS ");
+ if (!typestr) {
+ return NULL;
+ }
+ }
+ if (type & DELETE_ACCESS) {
+ typestr = talloc_asprintf_append(typestr,
+ "DELETE_ACCESS ");
+ if (!typestr) {
+ return NULL;
+ }
+ }
+
+ printf("\t\tSpecific bits: 0x%lx\n", (unsigned long)type&SPECIFIC_RIGHTS_MASK);
+
+ return typestr;
+}
+
+/****************************************************************************
+ display sec_access structure
+ ****************************************************************************/
+void display_sec_access(SEC_ACCESS *info)
+{
+ char *mask_str = get_sec_mask_str(NULL, *info);
+ printf("\t\tPermissions: 0x%x: %s\n", *info, mask_str ? mask_str : "");
+ TALLOC_FREE(mask_str);
+}
+
+/****************************************************************************
+ display sec_ace flags
+ ****************************************************************************/
+void display_sec_ace_flags(uint8_t flags)
+{
+ if (flags & SEC_ACE_FLAG_OBJECT_INHERIT)
+ printf("SEC_ACE_FLAG_OBJECT_INHERIT ");
+ if (flags & SEC_ACE_FLAG_CONTAINER_INHERIT)
+ printf(" SEC_ACE_FLAG_CONTAINER_INHERIT ");
+ if (flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)
+ printf("SEC_ACE_FLAG_NO_PROPAGATE_INHERIT ");
+ if (flags & SEC_ACE_FLAG_INHERIT_ONLY)
+ printf("SEC_ACE_FLAG_INHERIT_ONLY ");
+ if (flags & SEC_ACE_FLAG_INHERITED_ACE)
+ printf("SEC_ACE_FLAG_INHERITED_ACE ");
+/* if (flags & SEC_ACE_FLAG_VALID_INHERIT)
+ printf("SEC_ACE_FLAG_VALID_INHERIT "); */
+ if (flags & SEC_ACE_FLAG_SUCCESSFUL_ACCESS)
+ printf("SEC_ACE_FLAG_SUCCESSFUL_ACCESS ");
+ if (flags & SEC_ACE_FLAG_FAILED_ACCESS)
+ printf("SEC_ACE_FLAG_FAILED_ACCESS ");
+
+ printf("\n");
+}
+
+/****************************************************************************
+ display sec_ace object
+ ****************************************************************************/
+static void disp_sec_ace_object(struct security_ace_object *object)
+{
+ if (object->flags & SEC_ACE_OBJECT_PRESENT) {
+ printf("Object type: SEC_ACE_OBJECT_PRESENT\n");
+ printf("Object GUID: %s\n", smb_uuid_string(talloc_tos(),
+ object->type.type));
+ }
+ if (object->flags & SEC_ACE_OBJECT_INHERITED_PRESENT) {
+ printf("Object type: SEC_ACE_OBJECT_INHERITED_PRESENT\n");
+ printf("Object GUID: %s\n", smb_uuid_string(talloc_tos(),
+ object->inherited_type.inherited_type));
+ }
+}
+
+/****************************************************************************
+ display sec_ace structure
+ ****************************************************************************/
+void display_sec_ace(SEC_ACE *ace)
+{
+ fstring sid_str;
+
+ printf("\tACE\n\t\ttype: ");
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ printf("ACCESS ALLOWED");
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ printf("ACCESS DENIED");
+ break;
+ case SEC_ACE_TYPE_SYSTEM_AUDIT:
+ printf("SYSTEM AUDIT");
+ break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM:
+ printf("SYSTEM ALARM");
+ break;
+ case SEC_ACE_TYPE_ALLOWED_COMPOUND:
+ printf("SEC_ACE_TYPE_ALLOWED_COMPOUND");
+ break;
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
+ printf("SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT");
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+ printf("SEC_ACE_TYPE_ACCESS_DENIED_OBJECT");
+ break;
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT:
+ printf("SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT");
+ break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT:
+ printf("SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT");
+ break;
+ default:
+ printf("????");
+ break;
+ }
+
+ printf(" (%d) flags: 0x%02x ", ace->type, ace->flags);
+ display_sec_ace_flags(ace->flags);
+ display_sec_access(&ace->access_mask);
+ sid_to_fstring(sid_str, &ace->trustee);
+ printf("\t\tSID: %s\n\n", sid_str);
+
+ if (sec_ace_object(ace->type)) {
+ disp_sec_ace_object(&ace->object.object);
+ }
+
+}
+
+/****************************************************************************
+ display sec_acl structure
+ ****************************************************************************/
+void display_sec_acl(SEC_ACL *sec_acl)
+{
+ int i;
+
+ printf("\tACL\tNum ACEs:\t%d\trevision:\t%x\n",
+ sec_acl->num_aces, sec_acl->revision);
+ printf("\t---\n");
+
+ if (sec_acl->size != 0 && sec_acl->num_aces != 0) {
+ for (i = 0; i < sec_acl->num_aces; i++) {
+ display_sec_ace(&sec_acl->aces[i]);
+ }
+ }
+}
+
+void display_acl_type(uint16 type)
+{
+ static fstring typestr="";
+
+ typestr[0] = 0;
+
+ if (type & SEC_DESC_OWNER_DEFAULTED) /* 0x0001 */
+ fstrcat(typestr, "SEC_DESC_OWNER_DEFAULTED ");
+ if (type & SEC_DESC_GROUP_DEFAULTED) /* 0x0002 */
+ fstrcat(typestr, "SEC_DESC_GROUP_DEFAULTED ");
+ if (type & SEC_DESC_DACL_PRESENT) /* 0x0004 */
+ fstrcat(typestr, "SEC_DESC_DACL_PRESENT ");
+ if (type & SEC_DESC_DACL_DEFAULTED) /* 0x0008 */
+ fstrcat(typestr, "SEC_DESC_DACL_DEFAULTED ");
+ if (type & SEC_DESC_SACL_PRESENT) /* 0x0010 */
+ fstrcat(typestr, "SEC_DESC_SACL_PRESENT ");
+ if (type & SEC_DESC_SACL_DEFAULTED) /* 0x0020 */
+ fstrcat(typestr, "SEC_DESC_SACL_DEFAULTED ");
+ if (type & SEC_DESC_DACL_TRUSTED) /* 0x0040 */
+ fstrcat(typestr, "SEC_DESC_DACL_TRUSTED ");
+ if (type & SEC_DESC_SERVER_SECURITY) /* 0x0080 */
+ fstrcat(typestr, "SEC_DESC_SERVER_SECURITY ");
+ if (type & SEC_DESC_DACL_AUTO_INHERIT_REQ) /* 0x0100 */
+ fstrcat(typestr, "SEC_DESC_DACL_AUTO_INHERIT_REQ ");
+ if (type & SEC_DESC_SACL_AUTO_INHERIT_REQ) /* 0x0200 */
+ fstrcat(typestr, "SEC_DESC_SACL_AUTO_INHERIT_REQ ");
+ if (type & SEC_DESC_DACL_AUTO_INHERITED) /* 0x0400 */
+ fstrcat(typestr, "SEC_DESC_DACL_AUTO_INHERITED ");
+ if (type & SEC_DESC_SACL_AUTO_INHERITED) /* 0x0800 */
+ fstrcat(typestr, "SEC_DESC_SACL_AUTO_INHERITED ");
+ if (type & SEC_DESC_DACL_PROTECTED) /* 0x1000 */
+ fstrcat(typestr, "SEC_DESC_DACL_PROTECTED ");
+ if (type & SEC_DESC_SACL_PROTECTED) /* 0x2000 */
+ fstrcat(typestr, "SEC_DESC_SACL_PROTECTED ");
+ if (type & SEC_DESC_RM_CONTROL_VALID) /* 0x4000 */
+ fstrcat(typestr, "SEC_DESC_RM_CONTROL_VALID ");
+ if (type & SEC_DESC_SELF_RELATIVE) /* 0x8000 */
+ fstrcat(typestr, "SEC_DESC_SELF_RELATIVE ");
+
+ printf("type: 0x%04x: %s\n", type, typestr);
+}
+
+/****************************************************************************
+ display sec_desc structure
+ ****************************************************************************/
+void display_sec_desc(SEC_DESC *sec)
+{
+ fstring sid_str;
+
+ if (!sec) {
+ printf("NULL\n");
+ return;
+ }
+
+ printf("revision: %d\n", sec->revision);
+ display_acl_type(sec->type);
+
+ if (sec->sacl) {
+ printf("SACL\n");
+ display_sec_acl(sec->sacl);
+ }
+
+ if (sec->dacl) {
+ printf("DACL\n");
+ display_sec_acl(sec->dacl);
+ }
+
+ if (sec->owner_sid) {
+ sid_to_fstring(sid_str, sec->owner_sid);
+ printf("\tOwner SID:\t%s\n", sid_str);
+ }
+
+ if (sec->group_sid) {
+ sid_to_fstring(sid_str, sec->group_sid);
+ printf("\tGroup SID:\t%s\n", sid_str);
+ }
+}
diff --git a/source3/lib/dmallocmsg.c b/source3/lib/dmallocmsg.c
new file mode 100644
index 0000000000..935fc1de1a
--- /dev/null
+++ b/source3/lib/dmallocmsg.c
@@ -0,0 +1,78 @@
+/*
+ samba -- Unix SMB/CIFS implementation.
+ Copyright (C) 2002 by Martin Pool
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/**
+ * @file dmallocmsg.c
+ *
+ * Glue code to cause dmalloc info to come out when we receive a prod
+ * over samba messaging.
+ **/
+
+#ifdef ENABLE_DMALLOC
+static unsigned long our_dm_mark = 0;
+#endif /* ENABLE_DMALLOC */
+
+
+/**
+ * Respond to a POOL_USAGE message by sending back string form of memory
+ * usage stats.
+ **/
+static void msg_req_dmalloc_mark(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+#ifdef ENABLE_DMALLOC
+ our_dm_mark = dmalloc_mark();
+ DEBUG(2,("Got MSG_REQ_DMALLOC_MARK: mark set\n"));
+#else
+ DEBUG(2,("Got MSG_REQ_DMALLOC_MARK but dmalloc not in this process\n"));
+#endif
+}
+
+
+
+static void msg_req_dmalloc_log_changed(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+#ifdef ENABLE_DMALLOC
+ dmalloc_log_changed(our_dm_mark, True, True, True);
+ DEBUG(2,("Got MSG_REQ_DMALLOC_LOG_CHANGED: done\n"));
+#else
+ DEBUG(2,("Got MSG_REQ_DMALLOC_LOG_CHANGED but dmalloc not in this process\n"));
+#endif
+}
+
+
+/**
+ * Register handler for MSG_REQ_POOL_USAGE
+ **/
+void register_dmalloc_msgs(struct messaging_context *msg_ctx)
+{
+ messaging_register(msg_ctx, NULL, MSG_REQ_DMALLOC_MARK,
+ msg_req_dmalloc_mark);
+ messaging_register(msg_ctx, NULL, MSG_REQ_DMALLOC_LOG_CHANGED,
+ msg_req_dmalloc_log_changed);
+ DEBUG(2, ("Registered MSG_REQ_DMALLOC_MARK and LOG_CHANGED\n"));
+}
diff --git a/source3/lib/dprintf.c b/source3/lib/dprintf.c
new file mode 100644
index 0000000000..a3bb5be43a
--- /dev/null
+++ b/source3/lib/dprintf.c
@@ -0,0 +1,118 @@
+/*
+ Unix SMB/CIFS implementation.
+ display print functions
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*
+ this module provides functions for printing internal strings in the "display charset"
+ This charset may be quite different from the chosen unix charset
+
+ Eventually these functions will need to take care of column count constraints
+
+ The d_ prefix on print functions in Samba refers to the display character set
+ conversion
+*/
+
+#include "includes.h"
+
+ int d_vfprintf(FILE *f, const char *format, va_list ap)
+{
+ char *p, *p2;
+ int ret, maxlen, clen;
+ const char *msgstr;
+ va_list ap2;
+
+ /* do any message translations */
+ msgstr = lang_msg(format);
+ if (!msgstr) return -1;
+
+ VA_COPY(ap2, ap);
+
+ ret = vasprintf(&p, msgstr, ap2);
+
+ lang_msg_free(msgstr);
+
+ if (ret <= 0) {
+ va_end(ap2);
+ return ret;
+ }
+
+ /* now we have the string in unix format, convert it to the display
+ charset, but beware of it growing */
+ maxlen = ret*2;
+again:
+ p2 = (char *)SMB_MALLOC(maxlen);
+ if (!p2) {
+ SAFE_FREE(p);
+ va_end(ap2);
+ return -1;
+ }
+ clen = convert_string(CH_UNIX, CH_DISPLAY, p, ret, p2, maxlen, True);
+
+ if (clen >= maxlen) {
+ /* it didn't fit - try a larger buffer */
+ maxlen *= 2;
+ SAFE_FREE(p2);
+ goto again;
+ }
+
+ /* good, its converted OK */
+ SAFE_FREE(p);
+ ret = fwrite(p2, 1, clen, f);
+ SAFE_FREE(p2);
+
+ va_end(ap2);
+
+ return ret;
+}
+
+
+ int d_fprintf(FILE *f, const char *format, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, format);
+ ret = d_vfprintf(f, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+static FILE *outfile;
+
+ int d_printf(const char *format, ...)
+{
+ int ret;
+ va_list ap;
+
+ if (!outfile) outfile = stdout;
+
+ va_start(ap, format);
+ ret = d_vfprintf(outfile, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+/* interactive programs need a way of tell d_*() to write to stderr instead
+ of stdout */
+void display_set_stderr(void)
+{
+ outfile = stderr;
+}
diff --git a/source3/lib/dummyroot.c b/source3/lib/dummyroot.c
new file mode 100644
index 0000000000..64ea75814a
--- /dev/null
+++ b/source3/lib/dummyroot.c
@@ -0,0 +1,34 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Tim Potter 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Stupid dummy functions required due to the horrible dependency mess
+ in Samba. */
+
+#include "includes.h"
+
+void become_root(void)
+{
+ return;
+}
+
+void unbecome_root(void)
+{
+ return;
+}
diff --git a/source3/lib/dummysmbd.c b/source3/lib/dummysmbd.c
new file mode 100644
index 0000000000..dbe886e3d1
--- /dev/null
+++ b/source3/lib/dummysmbd.c
@@ -0,0 +1,53 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Gerald (Jerry) Carter 2004.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Stupid dummy functions required due to the horrible dependency mess
+ in Samba. */
+
+#include "includes.h"
+
+int get_client_fd(void)
+{
+ return -1;
+}
+
+int find_service(fstring service)
+{
+ return -1;
+}
+
+bool conn_snum_used(int snum)
+{
+ return False;
+}
+
+void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck)
+{
+}
+
+void send_stat_cache_delete_message(const char *name)
+{
+}
+
+NTSTATUS can_delete_directory(struct connection_struct *conn,
+ const char *dirname)
+{
+ return NT_STATUS_OK;
+}
diff --git a/source3/lib/errmap_unix.c b/source3/lib/errmap_unix.c
new file mode 100644
index 0000000000..2cd2386c5c
--- /dev/null
+++ b/source3/lib/errmap_unix.c
@@ -0,0 +1,130 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * map unix to NT errors, an excerpt of libsmb/errormap.c
+ * Copyright (C) Andrew Tridgell 2001
+ * Copyright (C) Andrew Bartlett 2001
+ * Copyright (C) Tim Potter 2000
+ * Copyright (C) Jeremy Allison 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/* Mapping from Unix, to NT error numbers */
+
+const struct unix_error_map unix_dos_nt_errmap[] = {
+ { EPERM, ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED },
+ { EACCES, ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED },
+ { ENOENT, ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { ENOTDIR, ERRDOS, ERRbadpath, NT_STATUS_NOT_A_DIRECTORY },
+ { EIO, ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR },
+ { EBADF, ERRSRV, ERRsrverror, NT_STATUS_INVALID_HANDLE },
+ { EINVAL, ERRSRV, ERRsrverror, NT_STATUS_INVALID_HANDLE },
+ { EEXIST, ERRDOS, ERRfilexists, NT_STATUS_OBJECT_NAME_COLLISION},
+ { ENFILE, ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES },
+ { EMFILE, ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES },
+ { ENOSPC, ERRHRD, ERRdiskfull, NT_STATUS_DISK_FULL },
+ { ENOMEM, ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY },
+ { EISDIR, ERRDOS, ERRnoaccess, NT_STATUS_FILE_IS_A_DIRECTORY},
+ { EMLINK, ERRDOS, ERRgeneral, NT_STATUS_TOO_MANY_LINKS },
+ { EINTR, ERRHRD, ERRgeneral, NT_STATUS_RETRY },
+#ifdef ELOOP
+ { ELOOP, ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND },
+#endif
+#ifdef EDQUOT
+ { EDQUOT, ERRHRD, ERRdiskfull, NT_STATUS_DISK_FULL }, /* Windows apps need this, not NT_STATUS_QUOTA_EXCEEDED */
+#endif
+#ifdef ENOTEMPTY
+ { ENOTEMPTY, ERRDOS, ERRnoaccess, NT_STATUS_DIRECTORY_NOT_EMPTY },
+#endif
+#ifdef EXDEV
+ { EXDEV, ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE },
+#endif
+#ifdef EROFS
+ { EROFS, ERRHRD, ERRnowrite, NT_STATUS_ACCESS_DENIED },
+#endif
+#ifdef ENAMETOOLONG
+ { ENAMETOOLONG, ERRDOS, 206, NT_STATUS_OBJECT_NAME_INVALID },
+#endif
+#ifdef EFBIG
+ { EFBIG, ERRHRD, ERRdiskfull, NT_STATUS_DISK_FULL },
+#endif
+#ifdef ENOBUFS
+ { ENOBUFS, ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES },
+#endif
+ { EAGAIN, ERRDOS, 111, NT_STATUS_NETWORK_BUSY },
+#ifdef EADDRINUSE
+ { EADDRINUSE, ERRDOS, 52, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED},
+#endif
+#ifdef ENETUNREACH
+ { ENETUNREACH, ERRHRD, ERRgeneral, NT_STATUS_NETWORK_UNREACHABLE},
+#endif
+#ifdef EHOSTUNREACH
+ { EHOSTUNREACH, ERRHRD, ERRgeneral, NT_STATUS_HOST_UNREACHABLE},
+#endif
+#ifdef ECONNREFUSED
+ { ECONNREFUSED, ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_REFUSED},
+#endif
+#ifdef ETIMEDOUT
+ { ETIMEDOUT, ERRHRD, 121, NT_STATUS_IO_TIMEOUT},
+#endif
+#ifdef ECONNABORTED
+ { ECONNABORTED, ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ABORTED},
+#endif
+#ifdef ENODEV
+ { ENODEV, ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST},
+#endif
+#ifdef EPIPE
+ { EPIPE, ERRDOS, 109, NT_STATUS_PIPE_BROKEN},
+#endif
+#ifdef EWOULDBLOCK
+ { EWOULDBLOCK, ERRDOS, 111, NT_STATUS_NETWORK_BUSY },
+#endif
+#ifdef ENOATTR
+ { ENOATTR, ERRDOS, ERRbadfile, NT_STATUS_NOT_FOUND },
+#endif
+
+ { 0, 0, 0, NT_STATUS_OK }
+};
+
+/*********************************************************************
+ Map an NT error code from a Unix error code.
+*********************************************************************/
+
+NTSTATUS map_nt_error_from_unix(int unix_error)
+{
+ int i = 0;
+
+ if (unix_error == 0) {
+ /* we map this to an error, not success, as this
+ function is only called in an error path. Lots of
+ our virtualised functions may fail without making a
+ unix system call that fails (such as when they are
+ checking for some handle existing), so unix_error
+ may be unset
+ */
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* Look through list */
+ while(unix_dos_nt_errmap[i].unix_error != 0) {
+ if (unix_dos_nt_errmap[i].unix_error == unix_error)
+ return unix_dos_nt_errmap[i].nt_error;
+ i++;
+ }
+
+ /* Default return */
+ return NT_STATUS_ACCESS_DENIED;
+}
diff --git a/source3/lib/events.c b/source3/lib/events.c
new file mode 100644
index 0000000000..f03138708b
--- /dev/null
+++ b/source3/lib/events.c
@@ -0,0 +1,449 @@
+/*
+ Unix SMB/CIFS implementation.
+ Timed event library.
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+struct timed_event {
+ struct timed_event *next, *prev;
+ struct event_context *event_ctx;
+ struct timeval when;
+ const char *event_name;
+ void (*handler)(struct event_context *event_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data);
+ void *private_data;
+};
+
+struct fd_event {
+ struct fd_event *prev, *next;
+ struct event_context *event_ctx;
+ int fd;
+ uint16_t flags; /* see EVENT_FD_* flags */
+ void (*handler)(struct event_context *event_ctx,
+ struct fd_event *event,
+ uint16 flags,
+ void *private_data);
+ void *private_data;
+};
+
+#define EVENT_FD_WRITEABLE(fde) \
+ event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_WRITE)
+#define EVENT_FD_READABLE(fde) \
+ event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_READ)
+
+#define EVENT_FD_NOT_WRITEABLE(fde) \
+ event_set_fd_flags(fde, event_get_fd_flags(fde) & ~EVENT_FD_WRITE)
+#define EVENT_FD_NOT_READABLE(fde) \
+ event_set_fd_flags(fde, event_get_fd_flags(fde) & ~EVENT_FD_READ)
+
+struct event_context {
+ struct timed_event *timed_events;
+ struct fd_event *fd_events;
+};
+
+static int timed_event_destructor(struct timed_event *te)
+{
+ DEBUG(10, ("Destroying timed event %lx \"%s\"\n", (unsigned long)te,
+ te->event_name));
+ if (te->event_ctx != NULL) {
+ DLIST_REMOVE(te->event_ctx->timed_events, te);
+ }
+ return 0;
+}
+
+/****************************************************************************
+ Add te by time.
+****************************************************************************/
+
+static void add_event_by_time(struct timed_event *te)
+{
+ struct event_context *ctx = te->event_ctx;
+ struct timed_event *last_te, *cur_te;
+
+ /* Keep the list ordered by time. We must preserve this. */
+ last_te = NULL;
+ for (cur_te = ctx->timed_events; cur_te; cur_te = cur_te->next) {
+ /* if the new event comes before the current one break */
+ if (!timeval_is_zero(&cur_te->when) &&
+ timeval_compare(&te->when, &cur_te->when) < 0) {
+ break;
+ }
+ last_te = cur_te;
+ }
+
+ DLIST_ADD_AFTER(ctx->timed_events, te, last_te);
+}
+
+/****************************************************************************
+ Schedule a function for future calling, cancel with TALLOC_FREE().
+ It's the responsibility of the handler to call TALLOC_FREE() on the event
+ handed to it.
+****************************************************************************/
+
+struct timed_event *event_add_timed(struct event_context *event_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct timeval when,
+ const char *event_name,
+ void (*handler)(struct event_context *event_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data),
+ void *private_data)
+{
+ struct timed_event *te;
+
+ te = TALLOC_P(mem_ctx, struct timed_event);
+ if (te == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ te->event_ctx = event_ctx;
+ te->when = when;
+ te->event_name = event_name;
+ te->handler = handler;
+ te->private_data = private_data;
+
+ add_event_by_time(te);
+
+ talloc_set_destructor(te, timed_event_destructor);
+
+ DEBUG(10, ("Added timed event \"%s\": %lx\n", event_name,
+ (unsigned long)te));
+ return te;
+}
+
+static int fd_event_destructor(struct fd_event *fde)
+{
+ if (fde->event_ctx != NULL) {
+ DLIST_REMOVE(fde->event_ctx->fd_events, fde);
+ }
+ return 0;
+}
+
+struct fd_event *event_add_fd(struct event_context *event_ctx,
+ TALLOC_CTX *mem_ctx,
+ int fd, uint16_t flags,
+ void (*handler)(struct event_context *event_ctx,
+ struct fd_event *event,
+ uint16 flags,
+ void *private_data),
+ void *private_data)
+{
+ struct fd_event *fde;
+
+ if (!(fde = TALLOC_P(mem_ctx, struct fd_event))) {
+ return NULL;
+ }
+
+ fde->event_ctx = event_ctx;
+ fde->fd = fd;
+ fde->flags = flags;
+ fde->handler = handler;
+ fde->private_data = private_data;
+
+ DLIST_ADD(event_ctx->fd_events, fde);
+
+ talloc_set_destructor(fde, fd_event_destructor);
+ return fde;
+}
+
+void event_fd_set_writeable(struct fd_event *fde)
+{
+ fde->flags |= EVENT_FD_WRITE;
+}
+
+void event_fd_set_not_writeable(struct fd_event *fde)
+{
+ fde->flags &= ~EVENT_FD_WRITE;
+}
+
+void event_fd_set_readable(struct fd_event *fde)
+{
+ fde->flags |= EVENT_FD_READ;
+}
+
+void event_fd_set_not_readable(struct fd_event *fde)
+{
+ fde->flags &= ~EVENT_FD_READ;
+}
+
+/*
+ * Return if there's something in the queue
+ */
+
+bool event_add_to_select_args(struct event_context *event_ctx,
+ const struct timeval *now,
+ fd_set *read_fds, fd_set *write_fds,
+ struct timeval *timeout, int *maxfd)
+{
+ struct fd_event *fde;
+ struct timeval diff;
+ bool ret = False;
+
+ for (fde = event_ctx->fd_events; fde; fde = fde->next) {
+ if (fde->flags & EVENT_FD_READ) {
+ FD_SET(fde->fd, read_fds);
+ ret = True;
+ }
+ if (fde->flags & EVENT_FD_WRITE) {
+ FD_SET(fde->fd, write_fds);
+ ret = True;
+ }
+
+ if ((fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE))
+ && (fde->fd > *maxfd)) {
+ *maxfd = fde->fd;
+ }
+ }
+
+ if (event_ctx->timed_events == NULL) {
+ return ret;
+ }
+
+ diff = timeval_until(now, &event_ctx->timed_events->when);
+ *timeout = timeval_min(timeout, &diff);
+
+ return True;
+}
+
+bool events_pending(struct event_context *event_ctx)
+{
+ struct fd_event *fde;
+
+ if (event_ctx->timed_events != NULL) {
+ return True;
+ }
+ for (fde = event_ctx->fd_events; fde; fde = fde->next) {
+ if (fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE)) {
+ return True;
+ }
+ }
+ return False;
+}
+
+bool run_events(struct event_context *event_ctx,
+ int selrtn, fd_set *read_fds, fd_set *write_fds)
+{
+ bool fired = False;
+ struct fd_event *fde, *next;
+
+ /* Run all events that are pending, not just one (as we
+ did previously. */
+
+ while (event_ctx->timed_events) {
+ struct timeval now;
+ GetTimeOfDay(&now);
+
+ if (timeval_compare(
+ &now, &event_ctx->timed_events->when) < 0) {
+ /* Nothing to do yet */
+ DEBUG(11, ("run_events: Nothing to do\n"));
+ break;
+ }
+
+ DEBUG(10, ("Running event \"%s\" %lx\n",
+ event_ctx->timed_events->event_name,
+ (unsigned long)event_ctx->timed_events));
+
+ event_ctx->timed_events->handler(
+ event_ctx,
+ event_ctx->timed_events, &now,
+ event_ctx->timed_events->private_data);
+
+ fired = True;
+ }
+
+ if (fired) {
+ /*
+ * We might have changed the socket status during the timed
+ * events, return to run select again.
+ */
+ return True;
+ }
+
+ if (selrtn == 0) {
+ /*
+ * No fd ready
+ */
+ return fired;
+ }
+
+ for (fde = event_ctx->fd_events; fde; fde = next) {
+ uint16 flags = 0;
+
+ next = fde->next;
+ if (FD_ISSET(fde->fd, read_fds)) flags |= EVENT_FD_READ;
+ if (FD_ISSET(fde->fd, write_fds)) flags |= EVENT_FD_WRITE;
+
+ if (flags & fde->flags) {
+ fde->handler(event_ctx, fde, flags, fde->private_data);
+ fired = True;
+ }
+ }
+
+ return fired;
+}
+
+
+struct timeval *get_timed_events_timeout(struct event_context *event_ctx,
+ struct timeval *to_ret)
+{
+ struct timeval now;
+
+ if (event_ctx->timed_events == NULL) {
+ return NULL;
+ }
+
+ now = timeval_current();
+ *to_ret = timeval_until(&now, &event_ctx->timed_events->when);
+
+ DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret->tv_sec,
+ (int)to_ret->tv_usec));
+
+ return to_ret;
+}
+
+int event_loop_once(struct event_context *ev)
+{
+ struct timeval now, to;
+ fd_set r_fds, w_fds;
+ int maxfd = 0;
+ int ret;
+
+ FD_ZERO(&r_fds);
+ FD_ZERO(&w_fds);
+
+ to.tv_sec = 9999; /* Max timeout */
+ to.tv_usec = 0;
+
+ GetTimeOfDay(&now);
+
+ if (!event_add_to_select_args(ev, &now, &r_fds, &w_fds, &to, &maxfd)) {
+ return -1;
+ }
+
+ if (timeval_is_zero(&to)) {
+ run_events(ev, 0, NULL, NULL);
+ return 0;
+ }
+
+ ret = sys_select(maxfd+1, &r_fds, &w_fds, NULL, &to);
+
+ if (ret == -1 && errno != EINTR) {
+ return -1;
+ }
+
+ run_events(ev, ret, &r_fds, &w_fds);
+ return 0;
+}
+
+static int event_context_destructor(struct event_context *ev)
+{
+ while (ev->fd_events != NULL) {
+ ev->fd_events->event_ctx = NULL;
+ DLIST_REMOVE(ev->fd_events, ev->fd_events);
+ }
+ while (ev->timed_events != NULL) {
+ ev->timed_events->event_ctx = NULL;
+ DLIST_REMOVE(ev->timed_events, ev->timed_events);
+ }
+ return 0;
+}
+
+struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
+{
+ struct event_context *result;
+
+ result = TALLOC_ZERO_P(mem_ctx, struct event_context);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ talloc_set_destructor(result, event_context_destructor);
+ return result;
+}
+
+int set_event_dispatch_time(struct event_context *event_ctx,
+ const char *event_name, struct timeval when)
+{
+ struct timed_event *te;
+
+ for (te = event_ctx->timed_events; te; te = te->next) {
+ if (strcmp(event_name, te->event_name) == 0) {
+ DLIST_REMOVE(event_ctx->timed_events, te);
+ te->when = when;
+ add_event_by_time(te);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Returns 1 if event was found and cancelled, 0 otherwise. */
+
+int cancel_named_event(struct event_context *event_ctx,
+ const char *event_name)
+{
+ struct timed_event *te;
+
+ for (te = event_ctx->timed_events; te; te = te->next) {
+ if (strcmp(event_name, te->event_name) == 0) {
+ TALLOC_FREE(te);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void dump_event_list(struct event_context *event_ctx)
+{
+ struct timed_event *te;
+ struct fd_event *fe;
+ struct timeval evt, now;
+
+ if (!event_ctx) {
+ return;
+ }
+
+ now = timeval_current();
+
+ DEBUG(10,("dump_event_list:\n"));
+
+ for (te = event_ctx->timed_events; te; te = te->next) {
+
+ evt = timeval_until(&now, &te->when);
+
+ DEBUGADD(10,("Timed Event \"%s\" %lx handled in %d seconds (at %s)\n",
+ te->event_name,
+ (unsigned long)te,
+ (int)evt.tv_sec,
+ http_timestring(te->when.tv_sec)));
+ }
+
+ for (fe = event_ctx->fd_events; fe; fe = fe->next) {
+
+ DEBUGADD(10,("FD Event %d %lx, flags: 0x%04x\n",
+ fe->fd,
+ (unsigned long)fe,
+ fe->flags));
+ }
+}
diff --git a/source3/lib/fault.c b/source3/lib/fault.c
new file mode 100644
index 0000000000..d4c1142937
--- /dev/null
+++ b/source3/lib/fault.c
@@ -0,0 +1,223 @@
+/*
+ Unix SMB/CIFS implementation.
+ Critical Fault 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
+
+static void (*cont_fn)(void *);
+static char *corepath;
+
+/*******************************************************************
+report a fault
+********************************************************************/
+static void fault_report(int sig)
+{
+ static int counter;
+
+ if (counter) _exit(1);
+
+ counter++;
+
+ DEBUGSEP(0);
+ DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)sys_getpid(),SAMBA_VERSION_STRING));
+ DEBUG(0,("\nPlease read the Trouble-Shooting section of the Samba3-HOWTO\n"));
+ DEBUG(0,("\nFrom: http://www.samba.org/samba/docs/Samba3-HOWTO.pdf\n"));
+ DEBUGSEP(0);
+
+ smb_panic("internal error");
+
+ if (cont_fn) {
+ cont_fn(NULL);
+#ifdef SIGSEGV
+ CatchSignal(SIGSEGV,SIGNAL_CAST SIG_DFL);
+#endif
+#ifdef SIGBUS
+ CatchSignal(SIGBUS,SIGNAL_CAST SIG_DFL);
+#endif
+#ifdef SIGABRT
+ CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
+#endif
+ return; /* this should cause a core dump */
+ }
+ exit(1);
+}
+
+/****************************************************************************
+catch serious errors
+****************************************************************************/
+static void sig_fault(int sig)
+{
+ fault_report(sig);
+}
+
+/*******************************************************************
+setup our fault handlers
+********************************************************************/
+void fault_setup(void (*fn)(void *))
+{
+ cont_fn = fn;
+
+#ifdef SIGSEGV
+ CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault);
+#endif
+#ifdef SIGBUS
+ CatchSignal(SIGBUS,SIGNAL_CAST sig_fault);
+#endif
+#ifdef SIGABRT
+ CatchSignal(SIGABRT,SIGNAL_CAST sig_fault);
+#endif
+}
+
+/*******************************************************************
+make all the preparations to safely dump a core file
+********************************************************************/
+
+void dump_core_setup(const char *progname)
+{
+ char *logbase = NULL;
+ char *end = NULL;
+
+ if (lp_logfile() && *lp_logfile()) {
+ if (asprintf(&logbase, "%s", lp_logfile()) < 0) {
+ return;
+ }
+ if ((end = strrchr_m(logbase, '/'))) {
+ *end = '\0';
+ }
+ } else {
+ /* We will end up here is the log file is given on the command
+ * line by the -l option but the "log file" option is not set
+ * in smb.conf.
+ */
+ if (asprintf(&logbase, "%s", get_dyn_LOGFILEBASE()) < 0) {
+ return;
+ }
+ }
+
+ SMB_ASSERT(progname != NULL);
+
+ if (asprintf(&corepath, "%s/cores", logbase) < 0) {
+ SAFE_FREE(logbase);
+ return;
+ }
+ mkdir(corepath,0700);
+
+ SAFE_FREE(corepath);
+ if (asprintf(&corepath, "%s/cores/%s",
+ logbase, progname) < 0) {
+ SAFE_FREE(logbase);
+ return;
+ }
+ mkdir(corepath,0700);
+
+ sys_chown(corepath,getuid(),getgid());
+ chmod(corepath,0700);
+
+ SAFE_FREE(logbase);
+
+#ifdef HAVE_GETRLIMIT
+#ifdef RLIMIT_CORE
+ {
+ struct rlimit rlp;
+ getrlimit(RLIMIT_CORE, &rlp);
+ rlp.rlim_cur = MAX(16*1024*1024,rlp.rlim_cur);
+ setrlimit(RLIMIT_CORE, &rlp);
+ getrlimit(RLIMIT_CORE, &rlp);
+ DEBUG(3,("Maximum core file size limits now %d(soft) %d(hard)\n",
+ (int)rlp.rlim_cur,(int)rlp.rlim_max));
+ }
+#endif
+#endif
+
+#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
+ /* On Linux we lose the ability to dump core when we change our user
+ * ID. We know how to dump core safely, so let's make sure we have our
+ * dumpable flag set.
+ */
+ prctl(PR_SET_DUMPABLE, 1);
+#endif
+
+ /* FIXME: if we have a core-plus-pid facility, configurably set
+ * this up here.
+ */
+}
+
+ void dump_core(void)
+{
+ static bool called;
+
+ if (called) {
+ DEBUG(0, ("dump_core() called recursive\n"));
+ exit(1);
+ }
+ called = true;
+
+ /* Note that even if core dumping has been disabled, we still set up
+ * the core path. This is to handle the case where core dumping is
+ * turned on in smb.conf and the relevant daemon is not restarted.
+ */
+ if (!lp_enable_core_files()) {
+ DEBUG(0, ("Exiting on internal error (core file administratively disabled)\n"));
+ exit(1);
+ }
+
+#if DUMP_CORE
+ /* If we're running as non root we might not be able to dump the core
+ * file to the corepath. There must not be an unbecome_root() before
+ * we call abort(). */
+ if (geteuid() != 0) {
+ become_root();
+ }
+
+ if (corepath == NULL) {
+ DEBUG(0, ("Can not dump core: corepath not set up\n"));
+ exit(1);
+ }
+
+ if (*corepath != '\0') {
+ /* The chdir might fail if we dump core before we finish
+ * processing the config file.
+ */
+ if (chdir(corepath) != 0) {
+ DEBUG(0, ("unable to change to %s\n", corepath));
+ DEBUGADD(0, ("refusing to dump core\n"));
+ exit(1);
+ }
+
+ DEBUG(0,("dumping core in %s\n", corepath));
+ }
+
+ umask(~(0700));
+ dbgflush();
+
+ /* Ensure we don't have a signal handler for abort. */
+#ifdef SIGABRT
+ CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
+#endif
+
+ abort();
+
+#else /* DUMP_CORE */
+ exit(1);
+#endif /* DUMP_CORE */
+}
+
diff --git a/source3/lib/file_id.c b/source3/lib/file_id.c
new file mode 100644
index 0000000000..0633d4b88d
--- /dev/null
+++ b/source3/lib/file_id.c
@@ -0,0 +1,88 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ file_id structure handling
+
+ Copyright (C) Andrew Tridgell 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*
+ return a file_id which gives a unique ID for a file given the device and
+ inode numbers
+ */
+struct file_id file_id_create_dev(SMB_DEV_T dev, SMB_INO_T inode)
+{
+ struct file_id key;
+ /* the ZERO_STRUCT ensures padding doesn't break using the key as a
+ * blob */
+ ZERO_STRUCT(key);
+ key.devid = dev;
+ key.inode = inode;
+ return key;
+}
+
+/*
+ generate a file_id from a stat structure
+ */
+struct file_id vfs_file_id_from_sbuf(connection_struct *conn, const SMB_STRUCT_STAT *sbuf)
+{
+ return SMB_VFS_FILE_ID_CREATE(conn, sbuf->st_dev, sbuf->st_ino);
+}
+
+/*
+ return True if two file_id structures are equal
+ */
+bool file_id_equal(const struct file_id *id1, const struct file_id *id2)
+{
+ return id1->inode == id2->inode && id1->devid == id2->devid;
+}
+
+/*
+ a static string for a file_id structure
+ */
+const char *file_id_string_tos(const struct file_id *id)
+{
+ char *result = talloc_asprintf(talloc_tos(), "%llx:%llx",
+ (unsigned long long)id->devid,
+ (unsigned long long)id->inode);
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+/*
+ push a 16 byte version of a file id into a buffer
+ */
+void push_file_id_16(char *buf, const struct file_id *id)
+{
+ SIVAL(buf, 0, id->devid&0xFFFFFFFF);
+ SIVAL(buf, 4, id->devid>>32);
+ SIVAL(buf, 8, id->inode&0xFFFFFFFF);
+ SIVAL(buf, 12, id->inode>>32);
+}
+
+/*
+ pul a 16 byte version of a file id from a buffer
+ */
+void pull_file_id_16(char *buf, struct file_id *id)
+{
+ ZERO_STRUCTP(id);
+ id->devid = IVAL(buf, 0);
+ id->devid |= ((uint64_t)IVAL(buf,4))<<32;
+ id->inode = IVAL(buf, 8);
+ id->inode |= ((uint64_t)IVAL(buf,12))<<32;
+}
diff --git a/source3/lib/fsusage.c b/source3/lib/fsusage.c
new file mode 100644
index 0000000000..66ffb9f442
--- /dev/null
+++ b/source3/lib/fsusage.c
@@ -0,0 +1,157 @@
+/*
+ Unix SMB/CIFS implementation.
+ functions to calculate the free disk space
+ Copyright (C) Andrew Tridgell 1998-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+
+/* Return the number of TOSIZE-byte blocks used by
+ BLOCKS FROMSIZE-byte blocks, rounding away from zero.
+*/
+static SMB_BIG_UINT adjust_blocks(SMB_BIG_UINT blocks, SMB_BIG_UINT fromsize, SMB_BIG_UINT tosize)
+{
+ if (fromsize == tosize) { /* e.g., from 512 to 512 */
+ return blocks;
+ } else if (fromsize > tosize) { /* e.g., from 2048 to 512 */
+ return blocks * (fromsize / tosize);
+ } else { /* e.g., from 256 to 512 */
+ /* Protect against broken filesystems... */
+ if (fromsize == 0) {
+ fromsize = tosize;
+ }
+ return (blocks + 1) / (tosize / fromsize);
+ }
+}
+
+/* this does all of the system specific guff to get the free disk space.
+ It is derived from code in the GNU fileutils package, but has been
+ considerably mangled for use here
+
+ results are returned in *dfree and *dsize, in 512 byte units
+*/
+int sys_fsusage(const char *path, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+#ifdef STAT_STATFS3_OSF1
+#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_fsize, (SMB_BIG_UINT)512)
+ struct statfs fsd;
+
+ if (statfs (path, &fsd, sizeof (struct statfs)) != 0)
+ return -1;
+#endif /* STAT_STATFS3_OSF1 */
+
+#ifdef STAT_STATFS2_FS_DATA /* Ultrix */
+#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)1024, (SMB_BIG_UINT)512)
+ struct fs_data fsd;
+
+ if (statfs (path, &fsd) != 1)
+ return -1;
+
+ (*dsize) = CONVERT_BLOCKS (fsd.fd_req.btot);
+ (*dfree) = CONVERT_BLOCKS (fsd.fd_req.bfreen);
+#endif /* STAT_STATFS2_FS_DATA */
+
+#ifdef STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX */
+#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_bsize, (SMB_BIG_UINT)512)
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+
+#ifdef STATFS_TRUNCATES_BLOCK_COUNTS
+ /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
+ struct statfs are truncated to 2GB. These conditions detect that
+ truncation, presumably without botching the 4.1.1 case, in which
+ the values are not truncated. The correct counts are stored in
+ undocumented spare fields. */
+ if (fsd.f_blocks == 0x1fffff && fsd.f_spare[0] > 0) {
+ fsd.f_blocks = fsd.f_spare[0];
+ fsd.f_bfree = fsd.f_spare[1];
+ fsd.f_bavail = fsd.f_spare[2];
+ }
+#endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
+#endif /* STAT_STATFS2_BSIZE */
+
+
+#ifdef STAT_STATFS2_FSIZE /* 4.4BSD */
+#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_fsize, (SMB_BIG_UINT)512)
+
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+#endif /* STAT_STATFS2_FSIZE */
+
+#ifdef STAT_STATFS4 /* SVR3, Dynix, Irix, AIX */
+# if _AIX || defined(_CRAY)
+# define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_bsize, (SMB_BIG_UINT)512)
+# ifdef _CRAY
+# define f_bavail f_bfree
+# endif
+# else
+# define CONVERT_BLOCKS(B) ((SMB_BIG_UINT)B)
+# ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx */
+# ifndef DOLPHIN /* DOLPHIN 3.8.alfa/7.18 has f_bavail */
+# define f_bavail f_bfree
+# endif
+# endif
+# endif
+
+ struct statfs fsd;
+
+ if (statfs (path, &fsd, sizeof fsd, 0) < 0)
+ return -1;
+ /* Empirically, the block counts on most SVR3 and SVR3-derived
+ systems seem to always be in terms of 512-byte blocks,
+ no matter what value f_bsize has. */
+
+#endif /* STAT_STATFS4 */
+
+#if defined(STAT_STATVFS) || defined(STAT_STATVFS64) /* SVR4 */
+#if defined HAVE_FRSIZE
+# 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)
+#else
+# define CONVERT_BLOCKS(B) \
+ adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_bsize, (SMB_BIG_UINT)512)
+#endif
+
+#ifdef STAT_STATVFS64
+ struct statvfs64 fsd;
+ if (statvfs64(path, &fsd) < 0) return -1;
+#else
+ struct statvfs fsd;
+ if (statvfs(path, &fsd) < 0) return -1;
+#endif
+
+ /* f_frsize isn't guaranteed to be supported. */
+
+#endif /* STAT_STATVFS */
+
+#ifndef CONVERT_BLOCKS
+ /* we don't have any dfree code! */
+ return -1;
+#else
+#if !defined(STAT_STATFS2_FS_DATA)
+ /* !Ultrix */
+ (*dsize) = CONVERT_BLOCKS (fsd.f_blocks);
+ (*dfree) = CONVERT_BLOCKS (fsd.f_bavail);
+#endif /* not STAT_STATFS2_FS_DATA */
+#endif
+
+ return 0;
+}
diff --git a/source3/lib/gencache.c b/source3/lib/gencache.c
new file mode 100644
index 0000000000..b773f83c58
--- /dev/null
+++ b/source3/lib/gencache.c
@@ -0,0 +1,506 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Generic, persistent and shared between processes cache mechanism for use
+ by various parts of the Samba code
+
+ Copyright (C) Rafal Szczesniak 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_TDB
+
+#define TIMEOUT_LEN 12
+#define CACHE_DATA_FMT "%12u/%s"
+#define READ_CACHE_DATA_FMT_TEMPLATE "%%12u/%%%us"
+#define BLOB_TYPE "DATA_BLOB"
+#define BLOB_TYPE_LEN 9
+
+static TDB_CONTEXT *cache;
+
+/**
+ * @file gencache.c
+ * @brief Generic, persistent and shared between processes cache mechanism
+ * for use by various parts of the Samba code
+ *
+ **/
+
+
+/**
+ * Cache initialisation function. Opens cache tdb file or creates
+ * it if does not exist.
+ *
+ * @return true on successful initialisation of the cache or
+ * false on failure
+ **/
+
+bool gencache_init(void)
+{
+ char* cache_fname = NULL;
+
+ /* skip file open if it's already opened */
+ if (cache) return True;
+
+ cache_fname = lock_path("gencache.tdb");
+
+ DEBUG(5, ("Opening cache file at %s\n", cache_fname));
+
+ cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT,
+ O_RDWR|O_CREAT, 0644);
+
+ if (!cache && (errno == EACCES)) {
+ cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT, O_RDONLY, 0644);
+ if (cache) {
+ DEBUG(5, ("gencache_init: Opening cache file %s read-only.\n", cache_fname));
+ }
+ }
+
+ if (!cache) {
+ DEBUG(5, ("Attempt to open gencache.tdb has failed.\n"));
+ return False;
+ }
+ return True;
+}
+
+
+/**
+ * Cache shutdown function. Closes opened cache tdb file.
+ *
+ * @return true on successful closing the cache or
+ * false on failure during cache shutdown
+ **/
+
+bool gencache_shutdown(void)
+{
+ int ret;
+ /* tdb_close routine returns -1 on error */
+ if (!cache) return False;
+ DEBUG(5, ("Closing cache file\n"));
+ ret = tdb_close(cache);
+ cache = NULL;
+ return ret != -1;
+}
+
+
+/**
+ * Set an entry in the cache file. If there's no such
+ * one, then add it.
+ *
+ * @param keystr string that represents a key of this entry
+ * @param value text representation value being cached
+ * @param timeout time when the value is expired
+ *
+ * @retval true when entry is successfuly stored
+ * @retval false on failure
+ **/
+
+bool gencache_set(const char *keystr, const char *value, time_t timeout)
+{
+ int ret;
+ TDB_DATA databuf;
+ char* valstr = NULL;
+
+ /* fail completely if get null pointers passed */
+ SMB_ASSERT(keystr && value);
+
+ if (!gencache_init()) return False;
+
+ if (asprintf(&valstr, CACHE_DATA_FMT, (int)timeout, value) == -1) {
+ return False;
+ }
+
+ databuf = string_term_tdb_data(valstr);
+ DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout ="
+ " %s (%d seconds %s)\n", keystr, value,ctime(&timeout),
+ (int)(timeout - time(NULL)),
+ timeout > time(NULL) ? "ahead" : "in the past"));
+
+ ret = tdb_store_bystring(cache, keystr, databuf, 0);
+ SAFE_FREE(valstr);
+
+ return ret == 0;
+}
+
+/**
+ * Delete one entry from the cache file.
+ *
+ * @param keystr string that represents a key of this entry
+ *
+ * @retval true upon successful deletion
+ * @retval false in case of failure
+ **/
+
+bool gencache_del(const char *keystr)
+{
+ int ret;
+
+ /* fail completely if get null pointers passed */
+ SMB_ASSERT(keystr);
+
+ if (!gencache_init()) return False;
+
+ DEBUG(10, ("Deleting cache entry (key = %s)\n", keystr));
+ ret = tdb_delete_bystring(cache, keystr);
+
+ return ret == 0;
+}
+
+
+/**
+ * Get existing entry from the cache file.
+ *
+ * @param keystr string that represents a key of this entry
+ * @param valstr buffer that is allocated and filled with the entry value
+ * buffer's disposing must be done outside
+ * @param timeout pointer to a time_t that is filled with entry's
+ * timeout
+ *
+ * @retval true when entry is successfuly fetched
+ * @retval False for failure
+ **/
+
+bool gencache_get(const char *keystr, char **valstr, time_t *timeout)
+{
+ TDB_DATA databuf;
+ time_t t;
+ char *endptr;
+
+ /* fail completely if get null pointers passed */
+ SMB_ASSERT(keystr);
+
+ if (!gencache_init()) {
+ return False;
+ }
+
+ databuf = tdb_fetch_bystring(cache, keystr);
+
+ if (databuf.dptr == NULL) {
+ DEBUG(10, ("Cache entry with key = %s couldn't be found\n",
+ keystr));
+ return False;
+ }
+
+ t = strtol((const char *)databuf.dptr, &endptr, 10);
+
+ if ((endptr == NULL) || (*endptr != '/')) {
+ DEBUG(2, ("Invalid gencache data format: %s\n", databuf.dptr));
+ SAFE_FREE(databuf.dptr);
+ return False;
+ }
+
+ DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, "
+ "timeout = %s", t > time(NULL) ? "valid" :
+ "expired", keystr, endptr+1, ctime(&t)));
+
+ if (t <= time(NULL)) {
+
+ /* We're expired, delete the entry */
+ tdb_delete_bystring(cache, keystr);
+
+ SAFE_FREE(databuf.dptr);
+ return False;
+ }
+
+ if (valstr) {
+ *valstr = SMB_STRDUP(endptr+1);
+ if (*valstr == NULL) {
+ SAFE_FREE(databuf.dptr);
+ DEBUG(0, ("strdup failed\n"));
+ return False;
+ }
+ }
+
+ SAFE_FREE(databuf.dptr);
+
+ if (timeout) {
+ *timeout = t;
+ }
+
+ return True;
+}
+
+/**
+ * Get existing entry from the cache file.
+ *
+ * @param keystr string that represents a key of this entry
+ * @param blob DATA_BLOB that is filled with entry's blob
+ * @param expired pointer to a bool that indicates whether the entry is expired
+ *
+ * @retval true when entry is successfuly fetched
+ * @retval False for failure
+ **/
+
+bool gencache_get_data_blob(const char *keystr, DATA_BLOB *blob, bool *expired)
+{
+ TDB_DATA databuf;
+ time_t t;
+ char *blob_type;
+ unsigned char *buf = NULL;
+ bool ret = False;
+ fstring valstr;
+ int buflen = 0, len = 0, blob_len = 0;
+ unsigned char *blob_buf = NULL;
+
+ /* fail completely if get null pointers passed */
+ SMB_ASSERT(keystr);
+
+ if (!gencache_init()) {
+ return False;
+ }
+
+ databuf = tdb_fetch_bystring(cache, keystr);
+ if (!databuf.dptr) {
+ DEBUG(10,("Cache entry with key = %s couldn't be found\n",
+ keystr));
+ return False;
+ }
+
+ buf = (unsigned char *)databuf.dptr;
+ buflen = databuf.dsize;
+
+ len += tdb_unpack(buf+len, buflen-len, "fB",
+ &valstr,
+ &blob_len, &blob_buf);
+ if (len == -1) {
+ goto out;
+ }
+
+ t = strtol(valstr, &blob_type, 10);
+
+ if (strcmp(blob_type+1, BLOB_TYPE) != 0) {
+ goto out;
+ }
+
+ DEBUG(10,("Returning %s cache entry: key = %s, "
+ "timeout = %s", t > time(NULL) ? "valid" :
+ "expired", keystr, ctime(&t)));
+
+ if (t <= time(NULL)) {
+ /* We're expired */
+ if (expired) {
+ *expired = True;
+ }
+ }
+
+ if (blob) {
+ *blob = data_blob(blob_buf, blob_len);
+ if (!blob->data) {
+ goto out;
+ }
+ }
+
+ ret = True;
+ out:
+ SAFE_FREE(blob_buf);
+ SAFE_FREE(databuf.dptr);
+
+ return ret;
+}
+
+/**
+ * Set an entry in the cache file. If there's no such
+ * one, then add it.
+ *
+ * @param keystr string that represents a key of this entry
+ * @param blob DATA_BLOB value being cached
+ * @param timeout time when the value is expired
+ *
+ * @retval true when entry is successfuly stored
+ * @retval false on failure
+ **/
+
+bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob, time_t timeout)
+{
+ bool ret = False;
+ int tdb_ret;
+ TDB_DATA databuf;
+ char *valstr = NULL;
+ unsigned char *buf = NULL;
+ int len = 0, buflen = 0;
+
+ /* fail completely if get null pointers passed */
+ SMB_ASSERT(keystr && blob);
+
+ if (!gencache_init()) {
+ return False;
+ }
+
+ if (asprintf(&valstr, "%12u/%s", (int)timeout, BLOB_TYPE) == -1) {
+ return False;
+ }
+
+ again:
+ len = 0;
+
+ len += tdb_pack(buf+len, buflen-len, "fB",
+ valstr,
+ blob->length, blob->data);
+
+ if (len == -1) {
+ goto out;
+ }
+
+ if (buflen < len) {
+ SAFE_FREE(buf);
+ buf = SMB_MALLOC_ARRAY(unsigned char, len);
+ if (!buf) {
+ goto out;
+ }
+ buflen = len;
+ goto again;
+ }
+
+ databuf = make_tdb_data(buf, len);
+
+ DEBUG(10,("Adding cache entry with key = %s; "
+ "blob size = %d and timeout = %s"
+ "(%d seconds %s)\n", keystr, (int)databuf.dsize,
+ ctime(&timeout), (int)(timeout - time(NULL)),
+ timeout > time(NULL) ? "ahead" : "in the past"));
+
+ tdb_ret = tdb_store_bystring(cache, keystr, databuf, 0);
+ if (tdb_ret == 0) {
+ ret = True;
+ }
+
+ out:
+ SAFE_FREE(valstr);
+ SAFE_FREE(buf);
+
+ return ret;
+}
+
+/**
+ * Iterate through all entries which key matches to specified pattern
+ *
+ * @param fn pointer to the function that will be supplied with each single
+ * matching cache entry (key, value and timeout) as an arguments
+ * @param data void pointer to an arbitrary data that is passed directly to the fn
+ * function on each call
+ * @param keystr_pattern pattern the existing entries' keys are matched to
+ *
+ **/
+
+void gencache_iterate(void (*fn)(const char* key, const char *value, time_t timeout, void* dptr),
+ void* data, const char* keystr_pattern)
+{
+ TDB_LIST_NODE *node, *first_node;
+ TDB_DATA databuf;
+ char *keystr = NULL, *valstr = NULL, *entry = NULL;
+ time_t timeout = 0;
+ int status;
+ unsigned u;
+
+ /* fail completely if get null pointers passed */
+ SMB_ASSERT(fn && keystr_pattern);
+
+ if (!gencache_init()) return;
+
+ DEBUG(5, ("Searching cache keys with pattern %s\n", keystr_pattern));
+ node = tdb_search_keys(cache, keystr_pattern);
+ first_node = node;
+
+ while (node) {
+ char *fmt;
+
+ /* ensure null termination of the key string */
+ keystr = SMB_STRNDUP((const char *)node->node_key.dptr, node->node_key.dsize);
+ if (!keystr) {
+ break;
+ }
+
+ /*
+ * We don't use gencache_get function, because we need to iterate through
+ * all of the entries. Validity verification is up to fn routine.
+ */
+ databuf = tdb_fetch(cache, node->node_key);
+ if (!databuf.dptr || databuf.dsize <= TIMEOUT_LEN) {
+ SAFE_FREE(databuf.dptr);
+ SAFE_FREE(keystr);
+ node = node->next;
+ continue;
+ }
+ entry = SMB_STRNDUP((const char *)databuf.dptr, databuf.dsize);
+ if (!entry) {
+ SAFE_FREE(databuf.dptr);
+ SAFE_FREE(keystr);
+ break;
+ }
+
+ SAFE_FREE(databuf.dptr);
+
+ valstr = (char *)SMB_MALLOC(databuf.dsize + 1 - TIMEOUT_LEN);
+ if (!valstr) {
+ SAFE_FREE(entry);
+ SAFE_FREE(keystr);
+ break;
+ }
+
+ if (asprintf(&fmt, READ_CACHE_DATA_FMT_TEMPLATE,
+ (unsigned int)databuf.dsize - TIMEOUT_LEN)
+ == -1) {
+ SAFE_FREE(valstr);
+ SAFE_FREE(entry);
+ SAFE_FREE(keystr);
+ break;
+ }
+ status = sscanf(entry, fmt, &u, valstr);
+ SAFE_FREE(fmt);
+
+ if ( status != 2 ) {
+ DEBUG(0,("gencache_iterate: invalid return from sscanf %d\n",status));
+ }
+ timeout = u;
+
+ DEBUG(10, ("Calling function with arguments (key = %s, value = %s, timeout = %s)\n",
+ keystr, valstr, ctime(&timeout)));
+ fn(keystr, valstr, timeout, data);
+
+ SAFE_FREE(valstr);
+ SAFE_FREE(entry);
+ SAFE_FREE(keystr);
+ node = node->next;
+ }
+
+ tdb_search_list_free(first_node);
+}
+
+/********************************************************************
+ lock a key
+********************************************************************/
+
+int gencache_lock_entry( const char *key )
+{
+ if (!gencache_init())
+ return -1;
+
+ return tdb_lock_bystring(cache, key);
+}
+
+/********************************************************************
+ unlock a key
+********************************************************************/
+
+void gencache_unlock_entry( const char *key )
+{
+ if (!gencache_init())
+ return;
+
+ tdb_unlock_bystring(cache, key);
+ return;
+}
diff --git a/source3/lib/genrand.c b/source3/lib/genrand.c
new file mode 100644
index 0000000000..4590b812c5
--- /dev/null
+++ b/source3/lib/genrand.c
@@ -0,0 +1,223 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Functions to create reasonable random numbers for crypto use.
+
+ Copyright (C) Jeremy Allison 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static unsigned char smb_arc4_state[258];
+static uint32 counter;
+
+static bool done_reseed = False;
+static void (*reseed_callback)(int *newseed);
+
+/****************************************************************
+ Copy any user given reseed data.
+*****************************************************************/
+
+void set_rand_reseed_callback(void (*fn)(int *))
+{
+ reseed_callback = fn;
+ set_need_random_reseed();
+}
+
+void set_need_random_reseed(void)
+{
+ done_reseed = False;
+}
+
+static void get_rand_reseed_data(int *reseed_data)
+{
+ if (reseed_callback) {
+ reseed_callback(reseed_data);
+ } else {
+ *reseed_data = 0;
+ }
+}
+
+/****************************************************************
+ Get a 16 byte hash from the contents of a file.
+ Note that the hash is not initialised.
+*****************************************************************/
+
+static void do_filehash(const char *fname, unsigned char *the_hash)
+{
+ unsigned char buf[1011]; /* deliberate weird size */
+ unsigned char tmp_md4[16];
+ int fd, n;
+
+ fd = sys_open(fname,O_RDONLY,0);
+ if (fd == -1)
+ return;
+
+ while ((n = read(fd, (char *)buf, sizeof(buf))) > 0) {
+ mdfour(tmp_md4, buf, n);
+ for (n=0;n<16;n++)
+ the_hash[n] ^= tmp_md4[n];
+ }
+ close(fd);
+}
+
+/**************************************************************
+ Try and get a good random number seed. Try a number of
+ different factors. Firstly, try /dev/urandom - use if exists.
+
+ We use /dev/urandom as a read of /dev/random can block if
+ the entropy pool dries up. This leads clients to timeout
+ or be very slow on connect.
+
+ If we can't use /dev/urandom then seed the stream random generator
+ above...
+**************************************************************/
+
+static int do_reseed(bool use_fd, int fd)
+{
+ unsigned char seed_inbuf[40];
+ uint32 v1, v2; struct timeval tval; pid_t mypid;
+ struct passwd *pw;
+ int reseed_data = 0;
+
+ if (use_fd) {
+ if (fd != -1)
+ return fd;
+
+ fd = sys_open( "/dev/urandom", O_RDONLY,0);
+ if(fd >= 0)
+ return fd;
+ }
+
+ /* Add in some secret file contents */
+
+ do_filehash("/etc/shadow", &seed_inbuf[0]);
+ do_filehash(lp_smb_passwd_file(), &seed_inbuf[16]);
+
+ /*
+ * Add in the root encrypted password.
+ * On any system where security is taken
+ * seriously this will be secret.
+ */
+
+ pw = getpwnam_alloc(NULL, "root");
+ if (pw && pw->pw_passwd) {
+ size_t i;
+ unsigned char md4_tmp[16];
+ mdfour(md4_tmp, (unsigned char *)pw->pw_passwd, strlen(pw->pw_passwd));
+ for (i=0;i<16;i++)
+ seed_inbuf[8+i] ^= md4_tmp[i];
+ TALLOC_FREE(pw);
+ }
+
+ /*
+ * Add the counter, time of day, and pid.
+ */
+
+ GetTimeOfDay(&tval);
+ mypid = sys_getpid();
+ v1 = (counter++) + mypid + tval.tv_sec;
+ v2 = (counter++) * mypid + tval.tv_usec;
+
+ SIVAL(seed_inbuf, 32, v1 ^ IVAL(seed_inbuf, 32));
+ SIVAL(seed_inbuf, 36, v2 ^ IVAL(seed_inbuf, 36));
+
+ /*
+ * Add any user-given reseed data.
+ */
+
+ get_rand_reseed_data(&reseed_data);
+ if (reseed_data) {
+ size_t i;
+ for (i = 0; i < sizeof(seed_inbuf); i++)
+ seed_inbuf[i] ^= ((char *)(&reseed_data))[i % sizeof(reseed_data)];
+ }
+
+ smb_arc4_init(smb_arc4_state, seed_inbuf, sizeof(seed_inbuf));
+
+ return -1;
+}
+
+/*******************************************************************
+ Interface to the (hopefully) good crypto random number generator.
+********************************************************************/
+
+void generate_random_buffer( unsigned char *out, int len)
+{
+ static int urand_fd = -1;
+ unsigned char md4_buf[64];
+ unsigned char tmp_buf[16];
+ unsigned char *p;
+
+ if(!done_reseed) {
+ urand_fd = do_reseed(True, urand_fd);
+ done_reseed = True;
+ }
+
+ if (urand_fd != -1 && len > 0) {
+
+ if (read(urand_fd, out, len) == len)
+ return; /* len bytes of random data read from urandom. */
+
+ /* Read of urand error, drop back to non urand method. */
+ close(urand_fd);
+ urand_fd = -1;
+ do_reseed(False, -1);
+ done_reseed = True;
+ }
+
+ /*
+ * Generate random numbers in chunks of 64 bytes,
+ * then md4 them & copy to the output buffer.
+ * This way the raw state of the stream is never externally
+ * seen.
+ */
+
+ p = out;
+ while(len > 0) {
+ int copy_len = len > 16 ? 16 : len;
+
+ smb_arc4_crypt(smb_arc4_state, md4_buf, sizeof(md4_buf));
+ mdfour(tmp_buf, md4_buf, sizeof(md4_buf));
+ memcpy(p, tmp_buf, copy_len);
+ p += copy_len;
+ len -= copy_len;
+ }
+}
+
+/*******************************************************************
+ Use the random number generator to generate a random string.
+********************************************************************/
+
+static char c_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
+
+char *generate_random_str(size_t len)
+{
+ static unsigned char retstr[256];
+ size_t i;
+
+ memset(retstr, '\0', sizeof(retstr));
+
+ if (len > sizeof(retstr)-1)
+ len = sizeof(retstr) -1;
+ generate_random_buffer( retstr, len);
+ for (i = 0; i < len; i++)
+ retstr[i] = c_list[ retstr[i] % (sizeof(c_list)-1) ];
+
+ retstr[i] = '\0';
+
+ return (char *)retstr;
+}
diff --git a/source3/lib/hmacmd5.c b/source3/lib/hmacmd5.c
new file mode 100644
index 0000000000..86db3aa236
--- /dev/null
+++ b/source3/lib/hmacmd5.c
@@ -0,0 +1,135 @@
+/*
+ Unix SMB/CIFS implementation.
+ HMAC MD5 code for use in NTLMv2
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Andrew Tridgell 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* taken direct from rfc2104 implementation and modified for suitable use
+ * for ntlmv2.
+ */
+
+#include "includes.h"
+
+/***********************************************************************
+ the rfc 2104 version of hmac_md5 initialisation.
+***********************************************************************/
+
+void hmac_md5_init_rfc2104(const unsigned char *key, int key_len, HMACMD5Context *ctx)
+{
+ int i;
+ unsigned char tk[16];
+
+ /* if key is longer than 64 bytes reset it to key=MD5(key) */
+ if (key_len > 64) {
+ struct MD5Context tctx;
+
+ MD5Init(&tctx);
+ MD5Update(&tctx, key, key_len);
+ MD5Final(tk, &tctx);
+
+ key = tk;
+ key_len = 16;
+ }
+
+ /* start out by storing key in pads */
+ ZERO_STRUCT(ctx->k_ipad);
+ ZERO_STRUCT(ctx->k_opad);
+ memcpy( ctx->k_ipad, key, key_len);
+ memcpy( ctx->k_opad, key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i=0; i<64; i++) {
+ ctx->k_ipad[i] ^= 0x36;
+ ctx->k_opad[i] ^= 0x5c;
+ }
+
+ MD5Init(&ctx->ctx);
+ MD5Update(&ctx->ctx, ctx->k_ipad, 64);
+}
+
+/***********************************************************************
+ the microsoft version of hmac_md5 initialisation.
+***********************************************************************/
+
+void hmac_md5_init_limK_to_64(const unsigned char* key, int key_len,
+ HMACMD5Context *ctx)
+{
+ int i;
+
+ /* if key is longer than 64 bytes truncate it */
+ if (key_len > 64) {
+ key_len = 64;
+ }
+
+ /* start out by storing key in pads */
+ ZERO_STRUCT(ctx->k_ipad);
+ ZERO_STRUCT(ctx->k_opad);
+ memcpy( ctx->k_ipad, key, key_len);
+ memcpy( ctx->k_opad, key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i=0; i<64; i++) {
+ ctx->k_ipad[i] ^= 0x36;
+ ctx->k_opad[i] ^= 0x5c;
+ }
+
+ MD5Init(&ctx->ctx);
+ MD5Update(&ctx->ctx, ctx->k_ipad, 64);
+}
+
+/***********************************************************************
+ update hmac_md5 "inner" buffer
+***********************************************************************/
+
+void hmac_md5_update(const unsigned char *text, int text_len, HMACMD5Context *ctx)
+{
+ MD5Update(&ctx->ctx, text, text_len); /* then text of datagram */
+}
+
+/***********************************************************************
+ finish off hmac_md5 "inner" buffer and generate outer one.
+***********************************************************************/
+void hmac_md5_final(unsigned char *digest, HMACMD5Context *ctx)
+
+{
+ struct MD5Context ctx_o;
+
+ MD5Final(digest, &ctx->ctx);
+
+ MD5Init(&ctx_o);
+ MD5Update(&ctx_o, ctx->k_opad, 64);
+ MD5Update(&ctx_o, digest, 16);
+ MD5Final(digest, &ctx_o);
+}
+
+/***********************************************************
+ single function to calculate an HMAC MD5 digest from data.
+ use the microsoft hmacmd5 init method because the key is 16 bytes.
+************************************************************/
+
+void hmac_md5( unsigned char key[16], const unsigned char *data, int data_len,
+ unsigned char *digest)
+{
+ HMACMD5Context ctx;
+ hmac_md5_init_limK_to_64(key, 16, &ctx);
+ if (data_len != 0)
+ {
+ hmac_md5_update(data, data_len, &ctx);
+ }
+ hmac_md5_final(digest, &ctx);
+}
+
diff --git a/source3/lib/iconv.c b/source3/lib/iconv.c
new file mode 100644
index 0000000000..3ceb637b8e
--- /dev/null
+++ b/source3/lib/iconv.c
@@ -0,0 +1,775 @@
+/*
+ Unix SMB/CIFS implementation.
+ minimal iconv implementation
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jelmer Vernooij 2002,2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*
+ * We have to use strcasecmp here as the character conversions
+ * haven't been initialised yet. JRA.
+ */
+
+#undef strcasecmp
+
+/**
+ * @file
+ *
+ * @brief Samba wrapper/stub for iconv character set conversion.
+ *
+ * iconv is the XPG2 interface for converting between character
+ * encodings. This file provides a Samba wrapper around it, and also
+ * a simple reimplementation that is used if the system does not
+ * implement iconv.
+ *
+ * Samba only works with encodings that are supersets of ASCII: ascii
+ * characters like whitespace can be tested for directly, multibyte
+ * sequences start with a byte with the high bit set, and strings are
+ * terminated by a nul byte.
+ *
+ * Note that the only function provided by iconv is conversion between
+ * characters. It doesn't directly support operations like
+ * uppercasing or comparison. We have to convert to UCS-2 and compare
+ * there.
+ *
+ * @sa Samba Developers Guide
+ **/
+
+static_decl_charset;
+
+static size_t ascii_pull(void *,const char **, size_t *, char **, size_t *);
+static size_t ascii_push(void *,const char **, size_t *, char **, size_t *);
+static size_t latin1_push(void *,const char **, size_t *, char **, size_t *);
+static size_t utf8_pull(void *,const char **, size_t *, char **, size_t *);
+static size_t utf8_push(void *,const char **, size_t *, char **, size_t *);
+static size_t ucs2hex_pull(void *,const char **, size_t *, char **, size_t *);
+static size_t ucs2hex_push(void *,const char **, size_t *, char **, size_t *);
+static size_t iconv_copy(void *,const char **, size_t *, char **, size_t *);
+static size_t iconv_swab (void *,const char **, size_t *, char **, size_t *);
+
+static struct charset_functions builtin_functions[] = {
+ /* windows is really neither UCS-2 not UTF-16 */
+ {"UCS-2LE", iconv_copy, iconv_copy},
+ {"UTF-16LE", iconv_copy, iconv_copy},
+ {"UCS-2BE", iconv_swab, iconv_swab},
+ {"UTF-16BE", iconv_swab, iconv_swab},
+
+ /* we include the UTF-8 alias to cope with differing locale settings */
+ {"UTF8", utf8_pull, utf8_push},
+ {"UTF-8", utf8_pull, utf8_push},
+ {"ASCII", ascii_pull, ascii_push},
+ {"646", ascii_pull, ascii_push},
+ {"ISO-8859-1", ascii_pull, latin1_push},
+ {"UCS2-HEX", ucs2hex_pull, ucs2hex_push},
+ {NULL, NULL, NULL}
+};
+
+static struct charset_functions *charsets = NULL;
+
+static struct charset_functions *find_charset_functions(const char *name)
+{
+ struct charset_functions *c = charsets;
+
+ while(c) {
+ if (strcasecmp(name, c->name) == 0) {
+ return c;
+ }
+ c = c->next;
+ }
+
+ return NULL;
+}
+
+NTSTATUS smb_register_charset(struct charset_functions *funcs)
+{
+ if (!funcs) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ DEBUG(5, ("Attempting to register new charset %s\n", funcs->name));
+ /* Check whether we already have this charset... */
+ if (find_charset_functions(funcs->name)) {
+ DEBUG(0, ("Duplicate charset %s, not registering\n", funcs->name));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ funcs->next = funcs->prev = NULL;
+ DEBUG(5, ("Registered charset %s\n", funcs->name));
+ DLIST_ADD(charsets, funcs);
+ return NT_STATUS_OK;
+}
+
+static void lazy_initialize_iconv(void)
+{
+ static bool initialized;
+ int i;
+
+ if (!initialized) {
+ initialized = True;
+ for(i = 0; builtin_functions[i].name; i++)
+ smb_register_charset(&builtin_functions[i]);
+ static_init_charset;
+ }
+}
+
+#ifdef HAVE_NATIVE_ICONV
+/* if there was an error then reset the internal state,
+ this ensures that we don't have a shift state remaining for
+ character sets like SJIS */
+static size_t sys_iconv(void *cd,
+ const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ size_t ret = iconv((iconv_t)cd,
+ (void *)inbuf, inbytesleft,
+ outbuf, outbytesleft);
+ if (ret == (size_t)-1) {
+ int saved_errno = errno;
+ iconv(cd, NULL, NULL, NULL, NULL);
+ errno = saved_errno;
+ }
+ return ret;
+}
+#endif
+
+/**
+ * This is a simple portable iconv() implementaion.
+ *
+ * It only knows about a very small number of character sets - just
+ * enough that Samba works on systems that don't have iconv.
+ **/
+size_t smb_iconv(smb_iconv_t cd,
+ const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ char cvtbuf[2048];
+ char *bufp = cvtbuf;
+ size_t bufsize;
+
+ /* in many cases we can go direct */
+ if (cd->direct) {
+ return cd->direct(cd->cd_direct,
+ inbuf, inbytesleft, outbuf, outbytesleft);
+ }
+
+
+ /* otherwise we have to do it chunks at a time */
+ while (*inbytesleft > 0) {
+ bufp = cvtbuf;
+ bufsize = sizeof(cvtbuf);
+
+ if (cd->pull(cd->cd_pull,
+ inbuf, inbytesleft, &bufp, &bufsize) == -1
+ && errno != E2BIG) return -1;
+
+ bufp = cvtbuf;
+ bufsize = sizeof(cvtbuf) - bufsize;
+
+ if (cd->push(cd->cd_push,
+ (const char **)&bufp, &bufsize,
+ outbuf, outbytesleft) == -1) return -1;
+ }
+
+ return 0;
+}
+
+
+static bool is_utf16(const char *name)
+{
+ return strcasecmp(name, "UCS-2LE") == 0 ||
+ strcasecmp(name, "UTF-16LE") == 0;
+}
+
+/*
+ simple iconv_open() wrapper
+ */
+smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
+{
+ smb_iconv_t ret;
+ struct charset_functions *from, *to;
+
+ lazy_initialize_iconv();
+ from = charsets;
+ to = charsets;
+
+ ret = SMB_MALLOC_P(struct _smb_iconv_t);
+ if (!ret) {
+ errno = ENOMEM;
+ return (smb_iconv_t)-1;
+ }
+ memset(ret, 0, sizeof(struct _smb_iconv_t));
+
+ ret->from_name = SMB_STRDUP(fromcode);
+ ret->to_name = SMB_STRDUP(tocode);
+
+ /* check for the simplest null conversion */
+ if (strcasecmp(fromcode, tocode) == 0) {
+ ret->direct = iconv_copy;
+ return ret;
+ }
+
+ /* check if we have a builtin function for this conversion */
+ from = find_charset_functions(fromcode);
+ if(from)ret->pull = from->pull;
+
+ to = find_charset_functions(tocode);
+ if(to)ret->push = to->push;
+
+ /* check if we can use iconv for this conversion */
+#ifdef HAVE_NATIVE_ICONV
+ if (!ret->pull) {
+ ret->cd_pull = iconv_open("UTF-16LE", fromcode);
+ if (ret->cd_pull == (iconv_t)-1)
+ ret->cd_pull = iconv_open("UCS-2LE", fromcode);
+ if (ret->cd_pull != (iconv_t)-1)
+ ret->pull = sys_iconv;
+ }
+
+ if (!ret->push) {
+ ret->cd_push = iconv_open(tocode, "UTF-16LE");
+ if (ret->cd_push == (iconv_t)-1)
+ ret->cd_push = iconv_open(tocode, "UCS-2LE");
+ if (ret->cd_push != (iconv_t)-1)
+ ret->push = sys_iconv;
+ }
+#endif
+
+ /* check if there is a module available that can do this conversion */
+ if (!ret->pull && NT_STATUS_IS_OK(smb_probe_module("charset", fromcode))) {
+ if(!(from = find_charset_functions(fromcode)))
+ DEBUG(0, ("Module %s doesn't provide charset %s!\n", fromcode, fromcode));
+ else
+ ret->pull = from->pull;
+ }
+
+ if (!ret->push && NT_STATUS_IS_OK(smb_probe_module("charset", tocode))) {
+ if(!(to = find_charset_functions(tocode)))
+ DEBUG(0, ("Module %s doesn't provide charset %s!\n", tocode, tocode));
+ else
+ ret->push = to->push;
+ }
+
+ if (!ret->push || !ret->pull) {
+ SAFE_FREE(ret->from_name);
+ SAFE_FREE(ret->to_name);
+ SAFE_FREE(ret);
+ errno = EINVAL;
+ return (smb_iconv_t)-1;
+ }
+
+ /* check for conversion to/from ucs2 */
+ if (is_utf16(fromcode) && to) {
+ ret->direct = to->push;
+ ret->push = ret->pull = NULL;
+ return ret;
+ }
+
+ if (is_utf16(tocode) && from) {
+ ret->direct = from->pull;
+ ret->push = ret->pull = NULL;
+ return ret;
+ }
+
+ /* Check if we can do the conversion direct */
+#ifdef HAVE_NATIVE_ICONV
+ if (is_utf16(fromcode)) {
+ ret->direct = sys_iconv;
+ ret->cd_direct = ret->cd_push;
+ ret->cd_push = NULL;
+ return ret;
+ }
+ if (is_utf16(tocode)) {
+ ret->direct = sys_iconv;
+ ret->cd_direct = ret->cd_pull;
+ ret->cd_pull = NULL;
+ return ret;
+ }
+#endif
+
+ return ret;
+}
+
+/*
+ simple iconv_close() wrapper
+*/
+int smb_iconv_close (smb_iconv_t cd)
+{
+#ifdef HAVE_NATIVE_ICONV
+ if (cd->cd_direct) iconv_close((iconv_t)cd->cd_direct);
+ if (cd->cd_pull) iconv_close((iconv_t)cd->cd_pull);
+ if (cd->cd_push) iconv_close((iconv_t)cd->cd_push);
+#endif
+
+ SAFE_FREE(cd->from_name);
+ SAFE_FREE(cd->to_name);
+
+ memset(cd, 0, sizeof(*cd));
+ SAFE_FREE(cd);
+ return 0;
+}
+
+
+/**********************************************************************
+ the following functions implement the builtin character sets in Samba
+ and also the "test" character sets that are designed to test
+ multi-byte character set support for english users
+***********************************************************************/
+
+static size_t ascii_pull(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+ (*outbuf)[0] = (*inbuf)[0];
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= 1;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 1;
+ (*outbuf) += 2;
+ }
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t ascii_push(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int ir_count=0;
+
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ (*outbuf)[0] = (*inbuf)[0] & 0x7F;
+ if ((*inbuf)[1]) ir_count++;
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 1;
+ (*inbuf) += 2;
+ (*outbuf) += 1;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return ir_count;
+}
+
+static size_t latin1_push(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int ir_count=0;
+
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ (*outbuf)[0] = (*inbuf)[0];
+ if ((*inbuf)[1]) ir_count++;
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 1;
+ (*inbuf) += 2;
+ (*outbuf) += 1;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return ir_count;
+}
+
+static size_t ucs2hex_pull(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+ unsigned v;
+
+ if ((*inbuf)[0] != '@') {
+ /* seven bit ascii case */
+ (*outbuf)[0] = (*inbuf)[0];
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= 1;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 1;
+ (*outbuf) += 2;
+ continue;
+ }
+ /* it's a hex character */
+ if (*inbytesleft < 5) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (sscanf(&(*inbuf)[1], "%04x", &v) != 1) {
+ errno = EILSEQ;
+ return -1;
+ }
+
+ (*outbuf)[0] = v&0xff;
+ (*outbuf)[1] = v>>8;
+ (*inbytesleft) -= 5;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 5;
+ (*outbuf) += 2;
+ }
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t ucs2hex_push(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ char buf[6];
+
+ if ((*inbuf)[1] == 0 &&
+ ((*inbuf)[0] & 0x80) == 0 &&
+ (*inbuf)[0] != '@') {
+ (*outbuf)[0] = (*inbuf)[0];
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 1;
+ (*inbuf) += 2;
+ (*outbuf) += 1;
+ continue;
+ }
+ if (*outbytesleft < 5) {
+ errno = E2BIG;
+ return -1;
+ }
+ snprintf(buf, 6, "@%04x", SVAL(*inbuf, 0));
+ memcpy(*outbuf, buf, 5);
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 5;
+ (*inbuf) += 2;
+ (*outbuf) += 5;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t iconv_swab(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int n;
+
+ n = MIN(*inbytesleft, *outbytesleft);
+
+ swab(*inbuf, *outbuf, (n&~1));
+ if (n&1) {
+ (*outbuf)[n-1] = 0;
+ }
+
+ (*inbytesleft) -= n;
+ (*outbytesleft) -= n;
+ (*inbuf) += n;
+ (*outbuf) += n;
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t iconv_copy(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int n;
+
+ n = MIN(*inbytesleft, *outbytesleft);
+
+ memmove(*outbuf, *inbuf, n);
+
+ (*inbytesleft) -= n;
+ (*outbytesleft) -= n;
+ (*inbuf) += n;
+ (*outbuf) += n;
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t utf8_pull(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ size_t in_left=*inbytesleft, out_left=*outbytesleft;
+ const uint8 *c = (const uint8 *)*inbuf;
+ uint8 *uc = (uint8 *)*outbuf;
+
+ while (in_left >= 1 && out_left >= 2) {
+ unsigned int codepoint;
+
+ if ((c[0] & 0x80) == 0) {
+ uc[0] = c[0];
+ uc[1] = 0;
+ c += 1;
+ in_left -= 1;
+ out_left -= 2;
+ uc += 2;
+ continue;
+ }
+
+ if ((c[0] & 0xe0) == 0xc0) {
+ if (in_left < 2 ||
+ (c[1] & 0xc0) != 0x80) {
+ errno = EILSEQ;
+ goto error;
+ }
+ codepoint = (c[1]&0x3f) | ((c[0]&0x1f)<<6);
+ if (codepoint < 0x80) {
+ /* don't accept UTF-8 characters that are not minimally packed */
+ errno = EILSEQ;
+ goto error;
+ }
+ uc[1] = codepoint >> 8;
+ uc[0] = codepoint & 0xff;
+ c += 2;
+ in_left -= 2;
+ out_left -= 2;
+ uc += 2;
+ continue;
+ }
+
+ if ((c[0] & 0xf0) == 0xe0) {
+ if (in_left < 3 ||
+ (c[1] & 0xc0) != 0x80 ||
+ (c[2] & 0xc0) != 0x80) {
+ errno = EILSEQ;
+ goto error;
+ }
+ codepoint = (c[2]&0x3f) | ((c[1]&0x3f)<<6) | ((c[0]&0xf)<<12);
+ if (codepoint < 0x800) {
+ /* don't accept UTF-8 characters that are not minimally packed */
+ errno = EILSEQ;
+ goto error;
+ }
+ uc[1] = codepoint >> 8;
+ uc[0] = codepoint & 0xff;
+ c += 3;
+ in_left -= 3;
+ out_left -= 2;
+ uc += 2;
+ continue;
+ }
+
+ if ((c[0] & 0xf8) == 0xf0) {
+ if (in_left < 4 ||
+ (c[1] & 0xc0) != 0x80 ||
+ (c[2] & 0xc0) != 0x80 ||
+ (c[3] & 0xc0) != 0x80) {
+ errno = EILSEQ;
+ goto error;
+ }
+ codepoint =
+ (c[3]&0x3f) |
+ ((c[2]&0x3f)<<6) |
+ ((c[1]&0x3f)<<12) |
+ ((c[0]&0x7)<<18);
+ if (codepoint < 0x10000 || codepoint > 0x10ffff) {
+ /* don't accept UTF-8 characters that are not minimally packed */
+ errno = EILSEQ;
+ goto error;
+ }
+
+ codepoint -= 0x10000;
+
+ if (out_left < 4) {
+ errno = E2BIG;
+ goto error;
+ }
+
+ uc[0] = (codepoint>>10) & 0xFF;
+ uc[1] = (codepoint>>18) | 0xd8;
+ uc[2] = codepoint & 0xFF;
+ uc[3] = ((codepoint>>8) & 0x3) | 0xdc;
+ c += 4;
+ in_left -= 4;
+ out_left -= 4;
+ uc += 4;
+ continue;
+ }
+
+ /* we don't handle 5 byte sequences */
+ errno = EINVAL;
+ goto error;
+ }
+
+ if (in_left > 0) {
+ errno = E2BIG;
+ goto error;
+ }
+
+ *inbytesleft = in_left;
+ *outbytesleft = out_left;
+ *inbuf = (char *)c;
+ *outbuf = (char *)uc;
+ return 0;
+
+error:
+ *inbytesleft = in_left;
+ *outbytesleft = out_left;
+ *inbuf = (char *)c;
+ *outbuf = (char *)uc;
+ return -1;
+}
+
+static size_t utf8_push(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ size_t in_left=*inbytesleft, out_left=*outbytesleft;
+ uint8 *c = (uint8 *)*outbuf;
+ const uint8 *uc = (const uint8 *)*inbuf;
+
+ while (in_left >= 2 && out_left >= 1) {
+ unsigned int codepoint;
+
+ if (uc[1] == 0 && !(uc[0] & 0x80)) {
+ /* simplest case */
+ c[0] = uc[0];
+ in_left -= 2;
+ out_left -= 1;
+ uc += 2;
+ c += 1;
+ continue;
+ }
+
+ if ((uc[1]&0xf8) == 0) {
+ /* next simplest case */
+ if (out_left < 2) {
+ errno = E2BIG;
+ goto error;
+ }
+ c[0] = 0xc0 | (uc[0]>>6) | (uc[1]<<2);
+ c[1] = 0x80 | (uc[0] & 0x3f);
+ in_left -= 2;
+ out_left -= 2;
+ uc += 2;
+ c += 2;
+ continue;
+ }
+
+ if ((uc[1] & 0xfc) == 0xdc) {
+ /* its the second part of a 4 byte sequence. Illegal */
+ if (in_left < 4) {
+ errno = EINVAL;
+ } else {
+ errno = EILSEQ;
+ }
+ goto error;
+ }
+
+ if ((uc[1] & 0xfc) != 0xd8) {
+ codepoint = uc[0] | (uc[1]<<8);
+ if (out_left < 3) {
+ errno = E2BIG;
+ goto error;
+ }
+ c[0] = 0xe0 | (codepoint >> 12);
+ c[1] = 0x80 | ((codepoint >> 6) & 0x3f);
+ c[2] = 0x80 | (codepoint & 0x3f);
+
+ in_left -= 2;
+ out_left -= 3;
+ uc += 2;
+ c += 3;
+ continue;
+ }
+
+ /* its the first part of a 4 byte sequence */
+ if (in_left < 4) {
+ errno = EINVAL;
+ goto error;
+ }
+ if ((uc[3] & 0xfc) != 0xdc) {
+ errno = EILSEQ;
+ goto error;
+ }
+ codepoint = 0x10000 + (uc[2] | ((uc[3] & 0x3)<<8) |
+ (uc[0]<<10) | ((uc[1] & 0x3)<<18));
+
+ if (out_left < 4) {
+ errno = E2BIG;
+ goto error;
+ }
+ c[0] = 0xf0 | (codepoint >> 18);
+ c[1] = 0x80 | ((codepoint >> 12) & 0x3f);
+ c[2] = 0x80 | ((codepoint >> 6) & 0x3f);
+ c[3] = 0x80 | (codepoint & 0x3f);
+
+ in_left -= 4;
+ out_left -= 4;
+ uc += 4;
+ c += 4;
+ }
+
+ if (in_left == 1) {
+ errno = EINVAL;
+ goto error;
+ }
+
+ if (in_left > 1) {
+ errno = E2BIG;
+ goto error;
+ }
+
+ *inbytesleft = in_left;
+ *outbytesleft = out_left;
+ *inbuf = (char *)uc;
+ *outbuf = (char *)c;
+
+ return 0;
+
+error:
+ *inbytesleft = in_left;
+ *outbytesleft = out_left;
+ *inbuf = (char *)uc;
+ *outbuf = (char *)c;
+ return -1;
+}
+
diff --git a/source3/lib/idmap_cache.c b/source3/lib/idmap_cache.c
new file mode 100644
index 0000000000..6377635a65
--- /dev/null
+++ b/source3/lib/idmap_cache.c
@@ -0,0 +1,260 @@
+/*
+ Unix SMB/CIFS implementation.
+ ID Mapping Cache
+
+ Copyright (C) Volker Lendecke 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.*/
+
+#include "includes.h"
+
+/**
+ * Find a sid2uid mapping
+ * @param[in] sid the sid to map
+ * @param[out] puid where to put the result
+ * @param[out] expired is the cache entry expired?
+ * @retval Was anything in the cache at all?
+ *
+ * If *puid == -1 this was a negative mapping.
+ */
+
+bool idmap_cache_find_sid2uid(const struct dom_sid *sid, uid_t *puid,
+ bool *expired)
+{
+ fstring sidstr;
+ char *key;
+ char *value;
+ char *endptr;
+ time_t timeout;
+ uid_t uid;
+ bool ret;
+
+ key = talloc_asprintf(talloc_tos(), "IDMAP/SID2UID/%s",
+ sid_to_fstring(sidstr, sid));
+ if (key == NULL) {
+ return false;
+ }
+ ret = gencache_get(key, &value, &timeout);
+ TALLOC_FREE(key);
+ if (!ret) {
+ return false;
+ }
+ uid = strtol(value, &endptr, 10);
+ ret = (*endptr == '\0');
+ SAFE_FREE(value);
+ if (ret) {
+ *puid = uid;
+ *expired = (timeout <= time(NULL));
+ }
+ return ret;
+}
+
+/**
+ * Find a uid2sid mapping
+ * @param[in] uid the uid to map
+ * @param[out] sid where to put the result
+ * @param[out] expired is the cache entry expired?
+ * @retval Was anything in the cache at all?
+ *
+ * If "is_null_sid(sid)", this was a negative mapping.
+ */
+
+bool idmap_cache_find_uid2sid(uid_t uid, struct dom_sid *sid, bool *expired)
+{
+ char *key;
+ char *value;
+ time_t timeout;
+ bool ret = true;
+
+ key = talloc_asprintf(talloc_tos(), "IDMAP/UID2SID/%d", (int)uid);
+ if (key == NULL) {
+ return false;
+ }
+ ret = gencache_get(key, &value, &timeout);
+ TALLOC_FREE(key);
+ if (!ret) {
+ return false;
+ }
+ ZERO_STRUCTP(sid);
+ if (value[0] != '-') {
+ ret = string_to_sid(sid, value);
+ }
+ SAFE_FREE(value);
+ if (ret) {
+ *expired = (timeout <= time(NULL));
+ }
+ return ret;
+}
+
+/**
+ * Store a mapping in the idmap cache
+ * @param[in] sid the sid to map
+ * @param[in] uid the uid to map
+ *
+ * If both parameters are valid values, then a positive mapping in both
+ * directions is stored. If "is_null_sid(sid)" is true, then this will be a
+ * negative mapping of uid, we want to cache that for this uid we could not
+ * find anything. Likewise if "uid==-1", then we want to cache that we did not
+ * find a mapping for the sid passed here.
+ */
+
+void idmap_cache_set_sid2uid(const struct dom_sid *sid, uid_t uid)
+{
+ time_t now = time(NULL);
+ time_t timeout;
+ fstring sidstr, key, value;
+
+ if (!is_null_sid(sid)) {
+ fstr_sprintf(key, "IDMAP/SID2UID/%s",
+ sid_to_fstring(sidstr, sid));
+ fstr_sprintf(value, "%d", (int)uid);
+ timeout = (uid == -1)
+ ? lp_idmap_negative_cache_time()
+ : lp_idmap_cache_time();
+ gencache_set(key, value, now + timeout);
+ }
+ if (uid != -1) {
+ fstr_sprintf(key, "IDMAP/UID2SID/%d", (int)uid);
+ if (is_null_sid(sid)) {
+ /* negative uid mapping */
+ fstrcpy(value, "-");
+ timeout = lp_idmap_negative_cache_time();
+ }
+ else {
+ sid_to_fstring(value, sid);
+ timeout = lp_idmap_cache_time();
+ }
+ gencache_set(key, value, now + timeout);
+ }
+}
+
+/**
+ * Find a sid2gid mapping
+ * @param[in] sid the sid to map
+ * @param[out] pgid where to put the result
+ * @param[out] expired is the cache entry expired?
+ * @retval Was anything in the cache at all?
+ *
+ * If *pgid == -1 this was a negative mapping.
+ */
+
+bool idmap_cache_find_sid2gid(const struct dom_sid *sid, gid_t *pgid,
+ bool *expired)
+{
+ fstring sidstr;
+ char *key;
+ char *value;
+ char *endptr;
+ time_t timeout;
+ gid_t gid;
+ bool ret;
+
+ key = talloc_asprintf(talloc_tos(), "IDMAP/SID2GID/%s",
+ sid_to_fstring(sidstr, sid));
+ if (key == NULL) {
+ return false;
+ }
+ ret = gencache_get(key, &value, &timeout);
+ TALLOC_FREE(key);
+ if (!ret) {
+ return false;
+ }
+ gid = strtol(value, &endptr, 10);
+ ret = (*endptr == '\0');
+ SAFE_FREE(value);
+ if (ret) {
+ *pgid = gid;
+ *expired = (timeout <= time(NULL));
+ }
+ return ret;
+}
+
+/**
+ * Find a gid2sid mapping
+ * @param[in] gid the gid to map
+ * @param[out] sid where to put the result
+ * @param[out] expired is the cache entry expired?
+ * @retval Was anything in the cache at all?
+ *
+ * If "is_null_sid(sid)", this was a negative mapping.
+ */
+
+bool idmap_cache_find_gid2sid(gid_t gid, struct dom_sid *sid, bool *expired)
+{
+ char *key;
+ char *value;
+ time_t timeout;
+ bool ret = true;
+
+ key = talloc_asprintf(talloc_tos(), "IDMAP/GID2SID/%d", (int)gid);
+ if (key == NULL) {
+ return false;
+ }
+ ret = gencache_get(key, &value, &timeout);
+ TALLOC_FREE(key);
+ if (!ret) {
+ return false;
+ }
+ ZERO_STRUCTP(sid);
+ if (value[0] != '-') {
+ ret = string_to_sid(sid, value);
+ }
+ SAFE_FREE(value);
+ if (ret) {
+ *expired = (timeout <= time(NULL));
+ }
+ return ret;
+}
+
+/**
+ * Store a mapping in the idmap cache
+ * @param[in] sid the sid to map
+ * @param[in] gid the gid to map
+ *
+ * If both parameters are valid values, then a positive mapping in both
+ * directions is stored. If "is_null_sid(sid)" is true, then this will be a
+ * negative mapping of gid, we want to cache that for this gid we could not
+ * find anything. Likewise if "gid==-1", then we want to cache that we did not
+ * find a mapping for the sid passed here.
+ */
+
+void idmap_cache_set_sid2gid(const struct dom_sid *sid, gid_t gid)
+{
+ time_t now = time(NULL);
+ time_t timeout;
+ fstring sidstr, key, value;
+
+ if (!is_null_sid(sid)) {
+ fstr_sprintf(key, "IDMAP/SID2GID/%s",
+ sid_to_fstring(sidstr, sid));
+ fstr_sprintf(value, "%d", (int)gid);
+ timeout = (gid == -1)
+ ? lp_idmap_negative_cache_time()
+ : lp_idmap_cache_time();
+ gencache_set(key, value, now + timeout);
+ }
+ if (gid != -1) {
+ fstr_sprintf(key, "IDMAP/GID2SID/%d", (int)gid);
+ if (is_null_sid(sid)) {
+ /* negative gid mapping */
+ fstrcpy(value, "-");
+ timeout = lp_idmap_negative_cache_time();
+ }
+ else {
+ sid_to_fstring(value, sid);
+ timeout = lp_idmap_cache_time();
+ }
+ gencache_set(key, value, now + timeout);
+ }
+}
diff --git a/source3/lib/interface.c b/source3/lib/interface.c
new file mode 100644
index 0000000000..2e7c2706a0
--- /dev/null
+++ b/source3/lib/interface.c
@@ -0,0 +1,577 @@
+/*
+ Unix SMB/CIFS implementation.
+ multiple interface handling
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static struct iface_struct *probed_ifaces;
+static int total_probed;
+
+static struct interface *local_interfaces;
+
+/****************************************************************************
+ Check if an IP is one of mine.
+**************************************************************************/
+
+bool ismyaddr(const struct sockaddr_storage *ip)
+{
+ struct interface *i;
+ for (i=local_interfaces;i;i=i->next) {
+ if (addr_equal(&i->ip,ip)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ismyip_v4(struct in_addr ip)
+{
+ struct sockaddr_storage ss;
+ in_addr_to_sockaddr_storage(&ss, ip);
+ return ismyaddr(&ss);
+}
+
+/****************************************************************************
+ Try and find an interface that matches an ip. If we cannot, return NULL.
+**************************************************************************/
+
+static struct interface *iface_find(const struct sockaddr_storage *ip,
+ bool check_mask)
+{
+ struct interface *i;
+
+ if (is_address_any(ip)) {
+ return local_interfaces;
+ }
+
+ for (i=local_interfaces;i;i=i->next) {
+ if (check_mask) {
+ if (same_net(ip, &i->ip, &i->netmask)) {
+ return i;
+ }
+ } else if (addr_equal(&i->ip, ip)) {
+ return i;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Check if a packet is from a local (known) net.
+**************************************************************************/
+
+bool is_local_net(const struct sockaddr_storage *from)
+{
+ struct interface *i;
+ for (i=local_interfaces;i;i=i->next) {
+ if (same_net(from, &i->ip, &i->netmask)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+#if defined(HAVE_IPV6)
+void setup_linklocal_scope_id(struct sockaddr_storage *pss)
+{
+ struct interface *i;
+ for (i=local_interfaces;i;i=i->next) {
+ if (addr_equal(&i->ip,pss)) {
+ struct sockaddr_in6 *psa6 =
+ (struct sockaddr_in6 *)pss;
+ psa6->sin6_scope_id = if_nametoindex(i->name);
+ return;
+ }
+ }
+}
+#endif
+
+/****************************************************************************
+ Check if a packet is from a local (known) net.
+**************************************************************************/
+
+bool is_local_net_v4(struct in_addr from)
+{
+ struct sockaddr_storage ss;
+
+ in_addr_to_sockaddr_storage(&ss, from);
+ return is_local_net(&ss);
+}
+
+/****************************************************************************
+ 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;
+}
+
+/****************************************************************************
+ How many non-loopback IPv4 interfaces do we have ?
+**************************************************************************/
+
+int iface_count_v4_nl(void)
+{
+ int ret = 0;
+ struct interface *i;
+
+ for (i=local_interfaces;i;i=i->next) {
+ if (is_loopback_addr(&i->ip)) {
+ continue;
+ }
+ if (i->ip.ss_family == AF_INET) {
+ ret++;
+ }
+ }
+ return ret;
+}
+
+/****************************************************************************
+ Return a pointer to the in_addr of the first IPv4 interface.
+**************************************************************************/
+
+const struct in_addr *first_ipv4_iface(void)
+{
+ struct interface *i;
+
+ for (i=local_interfaces;i ;i=i->next) {
+ if (i->ip.ss_family == AF_INET) {
+ break;
+ }
+ }
+
+ if (!i) {
+ return NULL;
+ }
+ return &((const struct sockaddr_in *)&i->ip)->sin_addr;
+}
+
+/****************************************************************************
+ 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 sockaddr_storage of the Nth interface.
+**************************************************************************/
+
+const struct sockaddr_storage *iface_n_sockaddr_storage(int n)
+{
+ struct interface *i;
+
+ for (i=local_interfaces;i && n;i=i->next) {
+ n--;
+ }
+
+ if (i) {
+ return &i->ip;
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ Return IPv4 of the Nth interface (if a v4 address). NULL otherwise.
+**************************************************************************/
+
+const struct in_addr *iface_n_ip_v4(int n)
+{
+ struct interface *i;
+
+ for (i=local_interfaces;i && n;i=i->next) {
+ n--;
+ }
+
+ if (i && i->ip.ss_family == AF_INET) {
+ return &((const struct sockaddr_in *)&i->ip)->sin_addr;
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ Return IPv4 bcast of the Nth interface (if a v4 address). NULL otherwise.
+**************************************************************************/
+
+const struct in_addr *iface_n_bcast_v4(int n)
+{
+ struct interface *i;
+
+ for (i=local_interfaces;i && n;i=i->next) {
+ n--;
+ }
+
+ if (i && i->ip.ss_family == AF_INET) {
+ return &((const struct sockaddr_in *)&i->bcast)->sin_addr;
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ Return bcast of the Nth interface.
+**************************************************************************/
+
+const struct sockaddr_storage *iface_n_bcast(int n)
+{
+ struct interface *i;
+
+ for (i=local_interfaces;i && n;i=i->next) {
+ n--;
+ }
+
+ if (i) {
+ return &i->bcast;
+ }
+ return NULL;
+}
+
+/* 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. */
+
+const struct sockaddr_storage *iface_ip(const struct sockaddr_storage *ip)
+{
+ struct interface *i = iface_find(ip, true);
+ if (i) {
+ return &i->ip;
+ }
+
+ /* Search for the first interface with
+ * matching address family. */
+
+ for (i=local_interfaces;i;i=i->next) {
+ if (i->ip.ss_family == ip->ss_family) {
+ return &i->ip;
+ }
+ }
+ return NULL;
+}
+
+/*
+ return True if a IP is directly reachable on one of our interfaces
+*/
+
+bool iface_local(const struct sockaddr_storage *ip)
+{
+ return iface_find(ip, True) ? true : false;
+}
+
+/****************************************************************************
+ Add an interface to the linked list of interfaces.
+****************************************************************************/
+
+static void add_interface(const struct iface_struct *ifs)
+{
+ char addr[INET6_ADDRSTRLEN];
+ struct interface *iface;
+
+ if (iface_find(&ifs->ip, False)) {
+ DEBUG(3,("add_interface: not adding duplicate interface %s\n",
+ print_sockaddr(addr, sizeof(addr), &ifs->ip) ));
+ return;
+ }
+
+ if (!(ifs->flags & (IFF_BROADCAST|IFF_LOOPBACK))) {
+ DEBUG(3,("not adding non-broadcast interface %s\n",
+ ifs->name ));
+ return;
+ }
+
+ iface = SMB_MALLOC_P(struct interface);
+ if (!iface) {
+ return;
+ }
+
+ ZERO_STRUCTPN(iface);
+
+ iface->name = SMB_STRDUP(ifs->name);
+ if (!iface->name) {
+ SAFE_FREE(iface);
+ return;
+ }
+ iface->flags = ifs->flags;
+ iface->ip = ifs->ip;
+ iface->netmask = ifs->netmask;
+ iface->bcast = ifs->bcast;
+
+ DLIST_ADD(local_interfaces, iface);
+
+ DEBUG(2,("added interface %s ip=%s ",
+ iface->name,
+ print_sockaddr(addr, sizeof(addr), &iface->ip) ));
+ DEBUG(2,("bcast=%s ",
+ print_sockaddr(addr, sizeof(addr),
+ &iface->bcast) ));
+ DEBUG(2,("netmask=%s\n",
+ print_sockaddr(addr, sizeof(addr),
+ &iface->netmask) ));
+}
+
+/****************************************************************************
+ Interpret a single element from a interfaces= config line.
+
+ This handles the following different forms:
+
+ 1) wildcard interface name
+ 2) DNS name
+ 3) IP/masklen
+ 4) ip/mask
+ 5) bcast/mask
+****************************************************************************/
+
+static void interpret_interface(char *token)
+{
+ struct sockaddr_storage ss;
+ struct sockaddr_storage ss_mask;
+ struct sockaddr_storage ss_net;
+ struct sockaddr_storage ss_bcast;
+ struct iface_struct ifs;
+ char *p;
+ int i;
+ bool added=false;
+ bool goodaddr = false;
+
+ /* first check if it is an interface name */
+ for (i=0;i<total_probed;i++) {
+ if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
+ add_interface(&probed_ifaces[i]);
+ added = true;
+ }
+ }
+ if (added) {
+ return;
+ }
+
+ /* maybe it is a DNS name */
+ p = strchr_m(token,'/');
+ if (p == NULL) {
+ if (!interpret_string_addr(&ss, token, 0)) {
+ DEBUG(2, ("interpret_interface: Can't find address "
+ "for %s\n", token));
+ return;
+ }
+
+ for (i=0;i<total_probed;i++) {
+ if (addr_equal(&ss, &probed_ifaces[i].ip)) {
+ add_interface(&probed_ifaces[i]);
+ return;
+ }
+ }
+ DEBUG(2,("interpret_interface: "
+ "can't determine interface for %s\n",
+ token));
+ return;
+ }
+
+ /* parse it into an IP address/netmasklength pair */
+ *p = 0;
+ goodaddr = interpret_string_addr(&ss, token, 0);
+ *p++ = '/';
+
+ if (!goodaddr) {
+ DEBUG(2,("interpret_interface: "
+ "can't determine interface for %s\n",
+ token));
+ return;
+ }
+
+ if (strlen(p) > 2) {
+ goodaddr = interpret_string_addr(&ss_mask, p, 0);
+ if (!goodaddr) {
+ DEBUG(2,("interpret_interface: "
+ "can't determine netmask from %s\n",
+ p));
+ return;
+ }
+ } else {
+ char *endp = NULL;
+ unsigned long val = strtoul(p, &endp, 0);
+ if (p == endp || (endp && *endp != '\0')) {
+ DEBUG(2,("interpret_interface: "
+ "can't determine netmask value from %s\n",
+ p));
+ return;
+ }
+ if (!make_netmask(&ss_mask, &ss, val)) {
+ DEBUG(2,("interpret_interface: "
+ "can't apply netmask value %lu from %s\n",
+ val,
+ p));
+ return;
+ }
+ }
+
+ make_bcast(&ss_bcast, &ss, &ss_mask);
+ make_net(&ss_net, &ss, &ss_mask);
+
+ /* Maybe the first component was a broadcast address. */
+ if (addr_equal(&ss_bcast, &ss) || addr_equal(&ss_net, &ss)) {
+ for (i=0;i<total_probed;i++) {
+ if (same_net(&ss, &probed_ifaces[i].ip, &ss_mask)) {
+ /* Temporarily replace netmask on
+ * the detected interface - user knows
+ * best.... */
+ struct sockaddr_storage saved_mask =
+ probed_ifaces[i].netmask;
+ probed_ifaces[i].netmask = ss_mask;
+ DEBUG(2,("interpret_interface: "
+ "using netmask value %s from "
+ "config file on interface %s\n",
+ p,
+ probed_ifaces[i].name));
+ add_interface(&probed_ifaces[i]);
+ probed_ifaces[i].netmask = saved_mask;
+ return;
+ }
+ }
+ DEBUG(2,("interpret_interface: Can't determine ip for "
+ "broadcast address %s\n",
+ token));
+ return;
+ }
+
+ /* Just fake up the interface definition. User knows best. */
+
+ DEBUG(2,("interpret_interface: Adding interface %s\n",
+ token));
+
+ ZERO_STRUCT(ifs);
+ (void)strlcpy(ifs.name, token, sizeof(ifs.name));
+ ifs.flags = IFF_BROADCAST;
+ ifs.ip = ss;
+ ifs.netmask = ss_mask;
+ ifs.bcast = ss_bcast;
+ add_interface(&ifs);
+}
+
+/****************************************************************************
+ Load the list of network interfaces.
+****************************************************************************/
+
+void load_interfaces(void)
+{
+ struct iface_struct ifaces[MAX_INTERFACES];
+ const char **ptr = lp_interfaces();
+ int i;
+
+ SAFE_FREE(probed_ifaces);
+
+ /* dump the current interfaces if any */
+ while (local_interfaces) {
+ struct interface *iface = local_interfaces;
+ DLIST_REMOVE(local_interfaces, local_interfaces);
+ SAFE_FREE(iface->name);
+ SAFE_FREE(iface);
+ }
+
+ /* Probe the kernel for interfaces */
+ total_probed = get_interfaces(ifaces, MAX_INTERFACES);
+
+ if (total_probed > 0) {
+ probed_ifaces = (struct iface_struct *)memdup(ifaces,
+ sizeof(ifaces[0])*total_probed);
+ if (!probed_ifaces) {
+ DEBUG(0,("ERROR: memdup failed\n"));
+ exit(1);
+ }
+ }
+
+ /* if we don't have a interfaces line then use all broadcast capable
+ interfaces except loopback */
+ if (!ptr || !*ptr || !**ptr) {
+ if (total_probed <= 0) {
+ DEBUG(0,("ERROR: Could not determine network "
+ "interfaces, you must use a interfaces config line\n"));
+ exit(1);
+ }
+ for (i=0;i<total_probed;i++) {
+ if (probed_ifaces[i].flags & IFF_BROADCAST) {
+ add_interface(&probed_ifaces[i]);
+ }
+ }
+ return;
+ }
+
+ if (ptr) {
+ while (*ptr) {
+ char *ptr_cpy = SMB_STRDUP(*ptr);
+ if (ptr_cpy) {
+ interpret_interface(ptr_cpy);
+ free(ptr_cpy);
+ }
+ ptr++;
+ }
+ }
+
+ if (!local_interfaces) {
+ DEBUG(0,("WARNING: no network interfaces found\n"));
+ }
+}
+
+
+void gfree_interfaces(void)
+{
+ while (local_interfaces) {
+ struct interface *iface = local_interfaces;
+ DLIST_REMOVE(local_interfaces, local_interfaces);
+ SAFE_FREE(iface->name);
+ SAFE_FREE(iface);
+ }
+
+ SAFE_FREE(probed_ifaces);
+}
+
+/****************************************************************************
+ Return True if the list of probed interfaces has changed.
+****************************************************************************/
+
+bool interfaces_changed(void)
+{
+ int n;
+ struct iface_struct ifaces[MAX_INTERFACES];
+
+ n = get_interfaces(ifaces, MAX_INTERFACES);
+
+ if ((n > 0 )&& (n != total_probed ||
+ memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
+ return true;
+ }
+
+ return false;
+}
diff --git a/source3/lib/interfaces.c b/source3/lib/interfaces.c
new file mode 100644
index 0000000000..dd857ae672
--- /dev/null
+++ b/source3/lib/interfaces.c
@@ -0,0 +1,351 @@
+/*
+ Unix SMB/CIFS implementation.
+ return a list of network interfaces
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Jeremy Allison 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/* working out the interfaces for a OS is an incredibly non-portable
+ thing. We have several possible implementations below, and autoconf
+ tries each of them to see what works
+
+ Note that this file does _not_ include includes.h. That is so this code
+ can be called directly from the autoconf tests. That also means
+ this code cannot use any of the normal Samba debug stuff or defines.
+ This is standalone code.
+
+*/
+
+#ifndef AUTOCONF_TEST
+#include "config.h"
+#endif
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifdef HAVE_IFADDRS_H
+#include <ifaddrs.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifndef SIOCGIFCONF
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#ifdef __COMPAR_FN_T
+#define QSORT_CAST (__compar_fn_t)
+#endif
+
+#ifndef QSORT_CAST
+#define QSORT_CAST (int (*)(const void *, const void *))
+#endif
+
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+
+#define SOCKET_WRAPPER_NOT_REPLACE
+#include "interfaces.h"
+#include "lib/replace/replace.h"
+
+/****************************************************************************
+ Utility functions.
+****************************************************************************/
+
+/****************************************************************************
+ Create a struct sockaddr_storage with the netmask bits set to 1.
+****************************************************************************/
+
+bool make_netmask(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ unsigned long masklen)
+{
+ *pss_out = *pss_in;
+ /* Now apply masklen bits of mask. */
+#if defined(HAVE_IPV6)
+ if (pss_in->ss_family == AF_INET6) {
+ char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
+ unsigned int i;
+
+ if (masklen > 128) {
+ return false;
+ }
+ for (i = 0; masklen >= 8; masklen -= 8, i++) {
+ *p++ = 0xff;
+ }
+ /* Deal with the partial byte. */
+ *p++ &= (0xff & ~(0xff>>masklen));
+ i++;
+ for (;i < sizeof(struct in6_addr); i++) {
+ *p++ = '\0';
+ }
+ return true;
+ }
+#endif
+ if (pss_in->ss_family == AF_INET) {
+ if (masklen > 32) {
+ return false;
+ }
+ ((struct sockaddr_in *)pss_out)->sin_addr.s_addr =
+ htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL));
+ return true;
+ }
+ return false;
+}
+
+/****************************************************************************
+ Create a struct sockaddr_storage set to the broadcast or network adress from
+ an incoming sockaddr_storage.
+****************************************************************************/
+
+static void make_bcast_or_net(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ const struct sockaddr_storage *nmask,
+ bool make_bcast_p)
+{
+ unsigned int i = 0, len = 0;
+ char *pmask = NULL;
+ char *p = NULL;
+ *pss_out = *pss_in;
+
+ /* Set all zero netmask bits to 1. */
+#if defined(HAVE_IPV6)
+ if (pss_in->ss_family == AF_INET6) {
+ p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
+ pmask = (char *)&((struct sockaddr_in6 *)nmask)->sin6_addr;
+ len = 16;
+ }
+#endif
+ if (pss_in->ss_family == AF_INET) {
+ p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr;
+ pmask = (char *)&((struct sockaddr_in *)nmask)->sin_addr;
+ len = 4;
+ }
+
+ for (i = 0; i < len; i++, p++, pmask++) {
+ if (make_bcast_p) {
+ *p = (*p & *pmask) | (*pmask ^ 0xff);
+ } else {
+ /* make_net */
+ *p = (*p & *pmask);
+ }
+ }
+}
+
+void make_bcast(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ const struct sockaddr_storage *nmask)
+{
+ make_bcast_or_net(pss_out, pss_in, nmask, true);
+}
+
+void make_net(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ const struct sockaddr_storage *nmask)
+{
+ make_bcast_or_net(pss_out, pss_in, nmask, false);
+}
+
+/****************************************************************************
+ Try the "standard" getifaddrs/freeifaddrs interfaces.
+ Also gets IPv6 interfaces.
+****************************************************************************/
+
+/****************************************************************************
+ Get the netmask address for a local interface.
+****************************************************************************/
+
+static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
+{
+ struct ifaddrs *iflist = NULL;
+ struct ifaddrs *ifptr = NULL;
+ int total = 0;
+ size_t copy_size;
+
+ if (getifaddrs(&iflist) < 0) {
+ return -1;
+ }
+
+ /* Loop through interfaces, looking for given IP address */
+ for (ifptr = iflist, total = 0;
+ ifptr != NULL && total < max_interfaces;
+ ifptr = ifptr->ifa_next) {
+
+ memset(&ifaces[total], '\0', sizeof(ifaces[total]));
+
+ copy_size = sizeof(struct sockaddr_in);
+
+ if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
+ continue;
+ }
+
+ ifaces[total].flags = ifptr->ifa_flags;
+
+ /* Check the interface is up. */
+ if (!(ifaces[total].flags & IFF_UP)) {
+ continue;
+ }
+
+#if defined(HAVE_IPV6)
+ if (ifptr->ifa_addr->sa_family == AF_INET6) {
+ copy_size = sizeof(struct sockaddr_in6);
+ }
+#endif
+
+ memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size);
+ memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size);
+
+ if (ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) {
+ make_bcast(&ifaces[total].bcast,
+ &ifaces[total].ip,
+ &ifaces[total].netmask);
+ } else if ((ifaces[total].flags & IFF_POINTOPOINT) &&
+ ifptr->ifa_dstaddr ) {
+ memcpy(&ifaces[total].bcast,
+ ifptr->ifa_dstaddr,
+ copy_size);
+ } else {
+ continue;
+ }
+
+ strlcpy(ifaces[total].name, ifptr->ifa_name,
+ sizeof(ifaces[total].name));
+ total++;
+ }
+
+ freeifaddrs(iflist);
+
+ return total;
+}
+
+static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
+{
+ int r;
+
+#if defined(HAVE_IPV6)
+ /*
+ * If we have IPv6 - sort these interfaces lower
+ * than any IPv4 ones.
+ */
+ if (i1->ip.ss_family == AF_INET6 &&
+ i2->ip.ss_family == AF_INET) {
+ return -1;
+ } else if (i1->ip.ss_family == AF_INET &&
+ i2->ip.ss_family == AF_INET6) {
+ return 1;
+ }
+
+ if (i1->ip.ss_family == AF_INET6) {
+ struct sockaddr_in6 *s1 = (struct sockaddr_in6 *)&i1->ip;
+ struct sockaddr_in6 *s2 = (struct sockaddr_in6 *)&i2->ip;
+
+ r = memcmp(&s1->sin6_addr,
+ &s2->sin6_addr,
+ sizeof(struct in6_addr));
+ if (r) {
+ return r;
+ }
+
+ s1 = (struct sockaddr_in6 *)&i1->netmask;
+ s2 = (struct sockaddr_in6 *)&i2->netmask;
+
+ r = memcmp(&s1->sin6_addr,
+ &s2->sin6_addr,
+ sizeof(struct in6_addr));
+ if (r) {
+ return r;
+ }
+ }
+#endif
+
+ /* AIX uses __ss_family instead of ss_family inside of
+ sockaddr_storage. Instead of trying to figure out which field to
+ use, we can just cast it to a sockaddr.
+ */
+
+ if (((struct sockaddr *)&i1->ip)->sa_family == AF_INET) {
+ struct sockaddr_in *s1 = (struct sockaddr_in *)&i1->ip;
+ struct sockaddr_in *s2 = (struct sockaddr_in *)&i2->ip;
+
+ r = ntohl(s1->sin_addr.s_addr) -
+ ntohl(s2->sin_addr.s_addr);
+ if (r) {
+ return r;
+ }
+
+ s1 = (struct sockaddr_in *)&i1->netmask;
+ s2 = (struct sockaddr_in *)&i2->netmask;
+
+ return ntohl(s1->sin_addr.s_addr) -
+ ntohl(s2->sin_addr.s_addr);
+ }
+ return 0;
+}
+
+int get_interfaces(struct iface_struct *ifaces, int max_interfaces);
+/* this wrapper is used to remove duplicates from the interface list generated
+ above */
+int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
+{
+ int total, i, j;
+
+ total = _get_interfaces(ifaces, max_interfaces);
+ if (total <= 0) return total;
+
+ /* now we need to remove duplicates */
+ qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
+
+ for (i=1;i<total;) {
+ if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
+ for (j=i-1;j<total-1;j++) {
+ ifaces[j] = ifaces[j+1];
+ }
+ total--;
+ } else {
+ i++;
+ }
+ }
+
+ return total;
+}
+
diff --git a/source3/lib/ldap_debug_handler.c b/source3/lib/ldap_debug_handler.c
new file mode 100644
index 0000000000..2181ff014d
--- /dev/null
+++ b/source3/lib/ldap_debug_handler.c
@@ -0,0 +1,52 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Intercept libldap debug output.
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#if HAVE_LDAP
+
+static void samba_ldap_log_print_fn(LDAP_CONST char *data)
+{
+ DEBUG(lp_ldap_debug_threshold(), ("[LDAP] %s", data));
+}
+
+#endif
+
+void init_ldap_debugging(void)
+{
+#if defined(HAVE_LDAP) && defined(HAVE_LBER_LOG_PRINT_FN)
+ int ret;
+ int ldap_debug_level = lp_ldap_debug_level();
+
+ ret = ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &ldap_debug_level);
+ if (ret != LDAP_OPT_SUCCESS) {
+ DEBUG(10, ("Error setting LDAP debug level.\n"));
+ }
+
+ if (ldap_debug_level == 0) {
+ return;
+ }
+
+ ret = ber_set_option(NULL, LBER_OPT_LOG_PRINT_FN,
+ (void *)samba_ldap_log_print_fn);
+ if (ret != LBER_OPT_SUCCESS) {
+ DEBUG(10, ("Error setting LBER log print function.\n"));
+ }
+#endif /* HAVE_LDAP && HAVE_LBER_LOG_PRINT_FN */
+}
diff --git a/source3/lib/ldap_escape.c b/source3/lib/ldap_escape.c
new file mode 100644
index 0000000000..d101bc5ecd
--- /dev/null
+++ b/source3/lib/ldap_escape.c
@@ -0,0 +1,134 @@
+/*
+ Unix SMB/CIFS implementation.
+ ldap filter argument escaping
+
+ Copyright (C) 1998, 1999, 2000 Luke Howard <lukeh@padl.com>,
+ Copyright (C) 2003 Andrew Bartlett <abartlet@samba.org>
+
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/**
+ * Escape a parameter to an LDAP filter string, so they cannot contain
+ * embeded ( ) * or \ chars which may cause it not to parse correctly.
+ *
+ * @param s The input string
+ *
+ * @return A string allocated with malloc(), containing the escaped string,
+ * and to be free()ed by the caller.
+ **/
+
+char *escape_ldap_string_alloc(const char *s)
+{
+ size_t len = strlen(s)+1;
+ char *output = (char *)SMB_MALLOC(len);
+ const char *sub;
+ int i = 0;
+ char *p = output;
+
+ if (output == NULL) {
+ return NULL;
+ }
+
+ while (*s)
+ {
+ switch (*s)
+ {
+ case '*':
+ sub = "\\2a";
+ break;
+ case '(':
+ sub = "\\28";
+ break;
+ case ')':
+ sub = "\\29";
+ break;
+ case '\\':
+ sub = "\\5c";
+ break;
+ default:
+ sub = NULL;
+ break;
+ }
+
+ if (sub) {
+ len = len + 3;
+ output = (char *)SMB_REALLOC(output, len);
+ if (!output) {
+ return NULL;
+ }
+
+ p = &output[i];
+ strncpy (p, sub, 3);
+ p += 3;
+ i += 3;
+
+ } else {
+ *p = *s;
+ p++;
+ i++;
+ }
+ s++;
+ }
+
+ *p = '\0';
+ return output;
+}
+
+char *escape_rdn_val_string_alloc(const char *s)
+{
+ char *output, *p;
+
+ /* The maximum size of the escaped string can be twice the actual size */
+ output = (char *)SMB_MALLOC(2*strlen(s) + 1);
+
+ if (output == NULL) {
+ return NULL;
+ }
+
+ p = output;
+
+ while (*s)
+ {
+ switch (*s)
+ {
+ case ',':
+ case '=':
+ case '+':
+ case '<':
+ case '>':
+ case '#':
+ case ';':
+ case '\\':
+ case '\"':
+ *p++ = '\\';
+ *p++ = *s;
+ break;
+ default:
+ *p = *s;
+ p++;
+ }
+
+ s++;
+ }
+
+ *p = '\0';
+
+ /* resize the string to the actual final size */
+ output = (char *)SMB_REALLOC(output, strlen(output) + 1);
+ return output;
+}
diff --git a/source3/lib/ldb/Doxyfile b/source3/lib/ldb/Doxyfile
new file mode 100644
index 0000000000..07b12b516a
--- /dev/null
+++ b/source3/lib/ldb/Doxyfile
@@ -0,0 +1,26 @@
+PROJECT_NAME = LDB
+OUTPUT_DIRECTORY = apidocs
+REPEAT_BRIEF = YES
+OPTIMIZE_OUTPUT_FOR_C = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+GENERATE_TODOLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+SHOW_USED_FILES = NO
+SHOW_DIRECTORIES = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+INPUT = include .
+FILE_PATTERNS = *.h *.dox
+EXCLUDE = include/config.h include/dlinklist.h \
+ include/includes.h
+EXAMPLE_PATH = examples
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+GENERATE_MAN = YES
+ALWAYS_DETAILED_SEC = YES
+JAVADOC_AUTOBRIEF = YES
diff --git a/source3/lib/ldb/Makefile.in b/source3/lib/ldb/Makefile.in
new file mode 100644
index 0000000000..a091b4832e
--- /dev/null
+++ b/source3/lib/ldb/Makefile.in
@@ -0,0 +1,173 @@
+#!gmake
+#
+CC = @CC@
+GCOV = @GCOV@
+XSLTPROC = @XSLTPROC@
+DOXYGEN = @DOXYGEN@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+datarootdir = @datarootdir@
+includedir = @includedir@
+libdir = @libdir@
+bindir = @bindir@
+mandir = @mandir@
+VPATH = @srcdir@:@tdbdir@:@tallocdir@:@libreplacedir@:@poptdir@
+srcdir = @srcdir@
+builddir = @builddir@
+SLAPD = @SLAPD@
+EXTRA_OBJ=@EXTRA_OBJ@
+TESTS=test-tdb.sh @TESTS@
+
+CFLAGS=-g -I$(srcdir)/include -Iinclude -I$(srcdir) -I$(srcdir)/.. \
+ @POPT_CFLAGS@ -I@tallocdir@ -I@tdbdir@/include -I@libreplacedir@ \
+ -DLIBDIR=\"$(libdir)\" -DSHLIBEXT=\"@SHLIBEXT@\" -DUSE_MMAP=1 @CFLAGS@
+
+LIB_FLAGS=@LDFLAGS@ -Llib -lldb @LIBS@ @POPT_LIBS@
+
+LDB_TDB_DIR=ldb_tdb
+LDB_TDB_OBJ=$(LDB_TDB_DIR)/ldb_tdb.o \
+ $(LDB_TDB_DIR)/ldb_pack.o $(LDB_TDB_DIR)/ldb_search.o $(LDB_TDB_DIR)/ldb_index.o \
+ $(LDB_TDB_DIR)/ldb_cache.o $(LDB_TDB_DIR)/ldb_tdb_wrap.o
+
+COMDIR=common
+COMMON_OBJ=$(COMDIR)/ldb.o $(COMDIR)/ldb_ldif.o \
+ $(COMDIR)/ldb_parse.o $(COMDIR)/ldb_msg.o $(COMDIR)/ldb_utf8.o \
+ $(COMDIR)/ldb_debug.o $(COMDIR)/ldb_modules.o \
+ $(COMDIR)/ldb_dn.o $(COMDIR)/ldb_match.o $(COMDIR)/ldb_attributes.o \
+ $(COMDIR)/attrib_handlers.o $(COMDIR)/ldb_controls.o $(COMDIR)/qsort.o
+
+MODDIR=modules
+MODULES_OBJ=$(MODDIR)/operational.o $(MODDIR)/rdn_name.o \
+ $(MODDIR)/objectclass.o \
+ $(MODDIR)/paged_results.o $(MODDIR)/sort.o $(MODDIR)/asq.o
+
+NSSDIR=nssldb
+NSS_OBJ= $(NSSDIR)/ldb-nss.o $(NSSDIR)/ldb-pwd.o $(NSSDIR)/ldb-grp.o
+NSS_LIB = lib/libnss_ldb.so.2
+
+OBJS = $(MODULES_OBJ) $(COMMON_OBJ) $(LDB_TDB_OBJ) @TDBOBJ@ @TALLOCOBJ@ @POPTOBJ@ @LIBREPLACEOBJ@ $(EXTRA_OBJ)
+
+LDB_LIB = lib/libldb.a
+
+BINS = bin/ldbadd bin/ldbsearch bin/ldbdel bin/ldbmodify bin/ldbedit bin/ldbrename bin/ldbtest bin/oLschema2ldif
+
+LIBS = $(LDB_LIB)
+
+EXAMPLES = examples/ldbreader examples/ldifreader
+
+DIRS = lib bin common ldb_tdb ldb_ldap ldb_sqlite3 modules tools examples
+
+default: all
+
+nss: nssdir all $(NSS_LIB)
+
+nssdir:
+ @mkdir -p $(NSSDIR)
+
+all: showflags dirs $(OBJS) $(LDB_LIB) $(BINS) $(EXAMPLES) manpages
+
+showflags:
+ @echo 'ldb will be compiled with flags:'
+ @echo ' CFLAGS = $(CFLAGS)'
+ @echo ' LIBS = $(LIBS)'
+
+.c.o:
+ @echo Compiling $*.c
+ @mkdir -p `dirname $@`
+ @$(CC) $(CFLAGS) -c $< -o $@
+
+dirs:
+ @mkdir -p $(DIRS)
+
+lib/libldb.a: $(OBJS)
+ ar -rv $@ $(OBJS)
+ @-ranlib $@
+
+lib/libnss_ldb.so.2: $(NSS_OBJ) $(LIBS)
+ $(CC) -shared -Wl,-soname,libnss_ldb.so.2 -o lib/libnss_ldb.so.2 $(NSS_OBJ) $(OBJS) $(LIB_FLAGS)
+
+bin/ldbadd: tools/ldbadd.o tools/cmdline.o $(LIBS)
+ $(CC) -o bin/ldbadd tools/ldbadd.o tools/cmdline.o $(LIB_FLAGS)
+
+bin/ldbsearch: tools/ldbsearch.o tools/cmdline.o $(LIBS)
+ $(CC) -o bin/ldbsearch tools/ldbsearch.o tools/cmdline.o $(LIB_FLAGS)
+
+bin/ldbdel: tools/ldbdel.o tools/cmdline.o $(LIBS)
+ $(CC) -o bin/ldbdel tools/ldbdel.o tools/cmdline.o $(LIB_FLAGS)
+
+bin/ldbmodify: tools/ldbmodify.o tools/cmdline.o $(LIBS)
+ $(CC) -o bin/ldbmodify tools/ldbmodify.o tools/cmdline.o $(LIB_FLAGS)
+
+bin/ldbedit: tools/ldbedit.o tools/cmdline.o $(LIBS)
+ $(CC) -o bin/ldbedit tools/ldbedit.o tools/cmdline.o $(LIB_FLAGS)
+
+bin/ldbrename: tools/ldbrename.o tools/cmdline.o $(LIBS)
+ $(CC) -o bin/ldbrename tools/ldbrename.o tools/cmdline.o $(LIB_FLAGS)
+
+bin/ldbtest: tools/ldbtest.o tools/cmdline.o $(LIBS)
+ $(CC) -o bin/ldbtest tools/ldbtest.o tools/cmdline.o $(LIB_FLAGS)
+
+bin/oLschema2ldif: tools/oLschema2ldif.o tools/cmdline.o tools/convert.o $(LIBS)
+ $(CC) -o bin/oLschema2ldif tools/oLschema2ldif.o tools/cmdline.o tools/convert.o $(LIB_FLAGS)
+
+examples/ldbreader: examples/ldbreader.o $(LIBS)
+ $(CC) -o examples/ldbreader examples/ldbreader.o $(LIB_FLAGS)
+
+examples/ldifreader: examples/ldifreader.o $(LIBS)
+ $(CC) -o examples/ldifreader examples/ldifreader.o $(LIB_FLAGS)
+
+.SUFFIXES: .1 .1.xml .3 .3.xml .xml .html
+
+manpages:
+ @$(srcdir)/docs/builddocs.sh "$(XSLTPROC)" "$(srcdir)"
+
+doxygen:
+ test -z "$(DOXYGEN)" || (cd $(srcdir) && "$(DOXYGEN)")
+
+clean:
+ rm -f *.o */*.o *.gcov */*.gc?? tdbtest.ldb*
+ rm -f $(BINS) $(TDB_OBJ) $(TALLOC_OBJ) $(LDB_LIB) $(NSS_LIB)
+ rm -f man/*.1 man/*.3 man/*.html
+ rm -f $(EXAMPLES)
+ rm -rf apidocs/
+ rm -rf tests/schema/
+
+distclean: clean
+ rm -f *~ */*~
+ rm -rf bin lib
+ rm -f config.log config.status config.cache include/config.h
+ rm -f ldb.pc
+ rm -f Makefile
+
+realdistclean: distclean
+ rm -f configure.in include/config.h.in
+
+test: all
+ for t in $(TESTS); do echo STARTING $${t}; $(srcdir)/tests/$${t} || exit 1; done
+
+valgrindtest: all
+ for t in $(TESTS); do echo STARTING $${t}; VALGRIND="valgrind -q --db-attach=yes --num-callers=30" $(srcdir)/tests/$${t} || exit 1; done
+
+installcheck: install test
+
+install: all
+ mkdir -p $(includedir) $(libdir)/pkgconfig $(libdir) $(bindir)
+ cp $(srcdir)/include/ldb.h $(srcdir)/include/ldb_errors.h $(includedir)
+ cp $(LDB_LIB) $(libdir)
+ cp $(BINS) $(bindir)
+ cp ldb.pc $(libdir)/pkgconfig
+ $(srcdir)/docs/installdocs.sh $(mandir)
+
+gcov:
+ $(GCOV) -po ldb_sqlite3 $(srcdir)/ldb_sqlite3/*.c 2| tee ldb_sqlite3.report.gcov
+ $(GCOV) -po ldb_ldap $(srcdir)/ldb_ldap/*.c 2| tee ldb_ldap.report.gcov
+ $(GCOV) -po ldb_tdb $(srcdir)/ldb_tdb/*.c 2| tee ldb_tdb.report.gcov
+ $(GCOV) -po common $(srcdir)/common/*.c 2| tee common.report.gcov
+ $(GCOV) -po modules $(srcdir)/modules/*.c 2| tee modules.report.gcov
+ $(GCOV) -po tools $(srcdir)/tools/*.c 2| tee tools.report.gcov
+
+etags:
+ etags `find $(srcdir) -name "*.[ch]"`
+
+ctags:
+ ctags `find $(srcdir) -name "*.[ch]"`
diff --git a/source3/lib/ldb/README_gcov.txt b/source3/lib/ldb/README_gcov.txt
new file mode 100644
index 0000000000..2abd9378f4
--- /dev/null
+++ b/source3/lib/ldb/README_gcov.txt
@@ -0,0 +1,29 @@
+Here is how to use gcov to test code coverage in ldb.
+
+Step 1: build ldb with gcov enabled
+
+ make clean all WITH_GCOV=1
+
+Step 3: run the test suite
+ make test-tdb
+
+Step 4: produce the gcov report
+ make gcov
+
+Step 5: read the summary reports
+ less *.report.gcov
+
+Step 6: examine the per-file reports
+ less ldb_tdb\#ldb_tdb.c.gcov
+
+You can also combine steps 2 to 4 like this:
+
+ make clean all test-tdb gcov WITH_GCOV=1
+
+Note that you should not expect 100% coverage, as some error paths
+(such as memory allocation failures) are very hard to trigger. There
+are ways of working around this, but they are quite tricky (they
+involve allocation wrappers that "fork and fail on malloc").
+
+The lines to look for in the per-file reports are the ones starting
+with "#####". Those are lines that are never executed.
diff --git a/source3/lib/ldb/aclocal.m4 b/source3/lib/ldb/aclocal.m4
new file mode 100644
index 0000000000..5605e476ba
--- /dev/null
+++ b/source3/lib/ldb/aclocal.m4
@@ -0,0 +1 @@
+m4_include(libreplace.m4)
diff --git a/source3/lib/ldb/autogen.sh b/source3/lib/ldb/autogen.sh
new file mode 100755
index 0000000000..500cab87d5
--- /dev/null
+++ b/source3/lib/ldb/autogen.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+rm -rf autom4te.cache
+rm -f configure config.h.in
+
+IPATHS="-I libreplace -I lib/replace -I ../libreplace -I ../replace"
+IPATHS="$IPATHS -I lib/talloc -I talloc -I ../talloc"
+IPATHS="$IPATHS -I lib/tdb -I tdb -I ../tdb"
+IPATHS="$IPATHS -I lib/popt -I popt -I ../popt"
+autoheader $IPATHS || exit 1
+autoconf $IPATHS || exit 1
+
+rm -rf autom4te.cache
+
+echo "Now run ./configure and then make."
+exit 0
+
diff --git a/source3/lib/ldb/common/attrib_handlers.c b/source3/lib/ldb/common/attrib_handlers.c
new file mode 100644
index 0000000000..5f26db6776
--- /dev/null
+++ b/source3/lib/ldb/common/attrib_handlers.c
@@ -0,0 +1,405 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ attribute handlers for well known attribute types, selected by syntax OID
+ see rfc2252
+*/
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+#include "system/locale.h"
+
+/*
+ default handler that just copies a ldb_val.
+*/
+int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ *out = ldb_val_dup(mem_ctx, in);
+ if (in->length > 0 && out->data == NULL) {
+ ldb_oom(ldb);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ a case folding copy handler, removing leading and trailing spaces and
+ multiple internal spaces
+
+ We exploit the fact that utf8 never uses the space octet except for
+ the space itself
+*/
+static int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ char *s, *t;
+ int l;
+ if (!in || !out || !(in->data)) {
+ return -1;
+ }
+
+ out->data = (uint8_t *)ldb_casefold(ldb, mem_ctx, (const char *)(in->data));
+ if (out->data == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_handler_fold: unable to casefold string [%s]", in->data);
+ return -1;
+ }
+
+ s = (char *)(out->data);
+
+ /* remove trailing spaces if any */
+ l = strlen(s);
+ while (l > 0 && s[l - 1] == ' ') l--;
+ s[l] = '\0';
+
+ /* remove leading spaces if any */
+ if (*s == ' ') {
+ for (t = s; *s == ' '; s++) ;
+
+ /* remove leading spaces by moving down the string */
+ memmove(t, s, l);
+
+ s = t;
+ }
+
+ /* check middle spaces */
+ while ((t = strchr(s, ' ')) != NULL) {
+ for (s = t; *s == ' '; s++) ;
+
+ if ((s - t) > 1) {
+ l = strlen(s);
+
+ /* remove all spaces but one by moving down the string */
+ memmove(t + 1, s, l);
+ }
+ }
+
+ out->length = strlen((char *)out->data);
+ return 0;
+}
+
+
+
+/*
+ canonicalise a ldap Integer
+ rfc2252 specifies it should be in decimal form
+*/
+static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ char *end;
+ long long i = strtoll((char *)in->data, &end, 0);
+ if (*end != 0) {
+ return -1;
+ }
+ out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i);
+ if (out->data == NULL) {
+ return -1;
+ }
+ out->length = strlen((char *)out->data);
+ return 0;
+}
+
+/*
+ compare two Integers
+*/
+static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0);
+}
+
+/*
+ compare two binary blobs
+*/
+int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ if (v1->length != v2->length) {
+ return v1->length - v2->length;
+ }
+ return memcmp(v1->data, v2->data, v1->length);
+}
+
+/*
+ compare two case insensitive strings, ignoring multiple whitespaces
+ and leading and trailing whitespaces
+ see rfc2252 section 8.1
+
+ try to optimize for the ascii case,
+ but if we find out an utf8 codepoint revert to slower but correct function
+*/
+static int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
+ const char *u1, *u2;
+ char *b1, *b2;
+ int ret;
+ while (*s1 == ' ') s1++;
+ while (*s2 == ' ') s2++;
+ /* TODO: make utf8 safe, possibly with helper function from application */
+ while (*s1 && *s2) {
+ /* the first 127 (0x7F) chars are ascii and utf8 guarantes they
+ * never appear in multibyte sequences */
+ if (((unsigned char)s1[0]) & 0x80) goto utf8str;
+ if (((unsigned char)s2[0]) & 0x80) goto utf8str;
+ if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
+ break;
+ if (*s1 == ' ') {
+ while (s1[0] == s1[1]) s1++;
+ while (s2[0] == s2[1]) s2++;
+ }
+ s1++; s2++;
+ }
+ if (! (*s1 && *s2)) {
+ /* check for trailing spaces only if one of the pointers
+ * has reached the end of the strings otherwise we
+ * can mistakenly match.
+ * ex. "domain users" <-> "domainUpdates"
+ */
+ while (*s1 == ' ') s1++;
+ while (*s2 == ' ') s2++;
+ }
+ return (int)(toupper(*s1)) - (int)(toupper(*s2));
+
+utf8str:
+ /* no need to recheck from the start, just from the first utf8 char found */
+ b1 = ldb_casefold(ldb, mem_ctx, s1);
+ b2 = ldb_casefold(ldb, mem_ctx, s2);
+
+ if (b1 && b2) {
+ /* Both strings converted correctly */
+
+ u1 = b1;
+ u2 = b2;
+ } else {
+ /* One of the strings was not UTF8, so we have no options but to do a binary compare */
+
+ u1 = s1;
+ u2 = s2;
+ }
+
+ while (*u1 & *u2) {
+ if (*u1 != *u2)
+ break;
+ if (*u1 == ' ') {
+ while (u1[0] == u1[1]) u1++;
+ while (u2[0] == u2[1]) u2++;
+ }
+ u1++; u2++;
+ }
+ if (! (*u1 && *u2)) {
+ while (*u1 == ' ') u1++;
+ while (*u2 == ' ') u2++;
+ }
+ ret = (int)(*u1 - *u2);
+
+ talloc_free(b1);
+ talloc_free(b2);
+
+ return ret;
+}
+
+/*
+ canonicalise a attribute in DN format
+*/
+static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct ldb_dn *dn;
+ int ret = -1;
+
+ out->length = 0;
+ out->data = NULL;
+
+ dn = ldb_dn_explode_casefold(ldb, mem_ctx, (char *)in->data);
+ if (dn == NULL) {
+ return -1;
+ }
+
+ out->data = (uint8_t *)ldb_dn_linearize(mem_ctx, dn);
+ if (out->data == NULL) {
+ goto done;
+ }
+ out->length = strlen((char *)out->data);
+
+ ret = 0;
+
+done:
+ talloc_free(dn);
+
+ return ret;
+}
+
+/*
+ compare two dns
+*/
+static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ struct ldb_dn *dn1 = NULL, *dn2 = NULL;
+ int ret;
+
+ dn1 = ldb_dn_explode_casefold(ldb, mem_ctx, (char *)v1->data);
+ if (dn1 == NULL) return -1;
+
+ dn2 = ldb_dn_explode_casefold(ldb, mem_ctx, (char *)v2->data);
+ if (dn2 == NULL) {
+ talloc_free(dn1);
+ return -1;
+ }
+
+ ret = ldb_dn_compare(ldb, dn1, dn2);
+
+ talloc_free(dn1);
+ talloc_free(dn2);
+ return ret;
+}
+
+/*
+ compare two objectclasses, looking at subclasses
+*/
+static int ldb_comparison_objectclass(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ int ret, i;
+ const char **subclasses;
+ ret = ldb_comparison_fold(ldb, mem_ctx, v1, v2);
+ if (ret == 0) {
+ return 0;
+ }
+ subclasses = ldb_subclass_list(ldb, (char *)v1->data);
+ if (subclasses == NULL) {
+ return ret;
+ }
+ for (i=0;subclasses[i];i++) {
+ struct ldb_val vs;
+ vs.data = discard_const_p(uint8_t, subclasses[i]);
+ vs.length = strlen(subclasses[i]);
+ if (ldb_comparison_objectclass(ldb, mem_ctx, &vs, v2) == 0) {
+ return 0;
+ }
+ }
+ return ret;
+}
+
+/*
+ compare two utc time values. 1 second resolution
+*/
+static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ time_t t1, t2;
+ t1 = ldb_string_to_time((char *)v1->data);
+ t2 = ldb_string_to_time((char *)v2->data);
+ return (int)t2 - (int)t1;
+}
+
+/*
+ canonicalise a utc time
+*/
+static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ time_t t = ldb_string_to_time((char *)in->data);
+ out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
+ if (out->data == NULL) {
+ return -1;
+ }
+ out->length = strlen((char *)out->data);
+ return 0;
+}
+
+/*
+ table of standard attribute handlers
+*/
+static const struct ldb_attrib_handler ldb_standard_attribs[] = {
+ {
+ .attr = LDB_SYNTAX_INTEGER,
+ .flags = 0,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_canonicalise_Integer,
+ .comparison_fn = ldb_comparison_Integer
+ },
+ {
+ .attr = LDB_SYNTAX_OCTET_STRING,
+ .flags = 0,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = ldb_comparison_binary
+ },
+ {
+ .attr = LDB_SYNTAX_DIRECTORY_STRING,
+ .flags = 0,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_handler_fold,
+ .comparison_fn = ldb_comparison_fold
+ },
+ {
+ .attr = LDB_SYNTAX_DN,
+ .flags = 0,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_canonicalise_dn,
+ .comparison_fn = ldb_comparison_dn
+ },
+ {
+ .attr = LDB_SYNTAX_OBJECTCLASS,
+ .flags = 0,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_handler_fold,
+ .comparison_fn = ldb_comparison_objectclass
+ },
+ {
+ .attr = LDB_SYNTAX_UTC_TIME,
+ .flags = 0,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_canonicalise_utctime,
+ .comparison_fn = ldb_comparison_utctime
+ }
+};
+
+
+/*
+ return the attribute handlers for a given syntax name
+*/
+const struct ldb_attrib_handler *ldb_attrib_handler_syntax(struct ldb_context *ldb,
+ const char *syntax)
+{
+ int i;
+ unsigned num_handlers = sizeof(ldb_standard_attribs)/sizeof(ldb_standard_attribs[0]);
+ /* TODO: should be replaced with a binary search */
+ for (i=0;i<num_handlers;i++) {
+ if (strcmp(ldb_standard_attribs[i].attr, syntax) == 0) {
+ return &ldb_standard_attribs[i];
+ }
+ }
+ return NULL;
+}
+
diff --git a/source3/lib/ldb/common/ldb.c b/source3/lib/ldb/common/ldb.c
new file mode 100644
index 0000000000..743711b967
--- /dev/null
+++ b/source3/lib/ldb/common/ldb.c
@@ -0,0 +1,1132 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Simo Sorce 2005-2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb core API
+ *
+ * Description: core API routines interfacing to ldb backends
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+/*
+ initialise a ldb context
+ The mem_ctx is optional
+*/
+struct ldb_context *ldb_init(void *mem_ctx)
+{
+ struct ldb_context *ldb = talloc_zero(mem_ctx, struct ldb_context);
+ int ret;
+
+ ret = ldb_setup_wellknown_attributes(ldb);
+ if (ret != 0) {
+ talloc_free(ldb);
+ return NULL;
+ }
+
+ ldb_set_utf8_default(ldb);
+ ldb_set_create_perms(ldb, 0600);
+
+ return ldb;
+}
+
+static struct ldb_backend {
+ const char *name;
+ ldb_connect_fn connect_fn;
+ struct ldb_backend *prev, *next;
+} *ldb_backends = NULL;
+
+
+static ldb_connect_fn ldb_find_backend(const char *url)
+{
+ struct ldb_backend *backend;
+
+ for (backend = ldb_backends; backend; backend = backend->next) {
+ if (strncmp(backend->name, url, strlen(backend->name)) == 0) {
+ return backend->connect_fn;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ register a new ldb backend
+*/
+int ldb_register_backend(const char *url_prefix, ldb_connect_fn connectfn)
+{
+ struct ldb_backend *backend = talloc(talloc_autofree_context(), struct ldb_backend);
+
+ if (ldb_find_backend(url_prefix)) {
+ return LDB_SUCCESS;
+ }
+
+ /* Maybe check for duplicity here later on? */
+
+ backend->name = talloc_strdup(backend, url_prefix);
+ backend->connect_fn = connectfn;
+ DLIST_ADD(ldb_backends, backend);
+
+ return LDB_SUCCESS;
+}
+
+/*
+ Return the ldb module form of a database. The URL can either be one of the following forms
+ ldb://path
+ ldapi://path
+
+ flags is made up of LDB_FLG_*
+
+ the options are passed uninterpreted to the backend, and are
+ backend specific.
+
+ This allows modules to get at only the backend module, for example where a module
+ may wish to direct certain requests at a particular backend.
+*/
+int ldb_connect_backend(struct ldb_context *ldb, const char *url, const char *options[],
+ struct ldb_module **backend_module)
+{
+ int ret;
+ char *backend;
+ ldb_connect_fn fn;
+
+ if (strchr(url, ':') != NULL) {
+ backend = talloc_strndup(ldb, url, strchr(url, ':')-url);
+ } else {
+ /* Default to tdb */
+ backend = talloc_strdup(ldb, "tdb");
+ }
+
+ fn = ldb_find_backend(backend);
+
+ if (fn == NULL) {
+ if (ldb_try_load_dso(ldb, backend) == 0) {
+ fn = ldb_find_backend(backend);
+ }
+ }
+
+ talloc_free(backend);
+
+ if (fn == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to find backend for '%s'\n", url);
+ return LDB_ERR_OTHER;
+ }
+
+ ret = fn(ldb, url, ldb->flags, options, backend_module);
+
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to '%s'\n", url);
+ return ret;
+ }
+ return ret;
+}
+
+/*
+ try to autodetect a basedn if none specified. This fixes one of my
+ pet hates about ldapsearch, which is that you have to get a long,
+ complex basedn right to make any use of it.
+*/
+static const struct ldb_dn *ldb_set_default_basedn(struct ldb_context *ldb)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ static const char *attrs[] = { "defaultNamingContext", NULL };
+ struct ldb_result *res;
+ struct ldb_dn *basedn=NULL;
+
+ basedn = (struct ldb_dn *)ldb_get_opaque(ldb, "default_baseDN");
+ if (basedn) {
+ return basedn;
+ }
+
+ tmp_ctx = talloc_new(ldb);
+ ret = ldb_search(ldb, ldb_dn_new(tmp_ctx), LDB_SCOPE_BASE,
+ "(objectClass=*)", attrs, &res);
+ if (ret == LDB_SUCCESS) {
+ if (res->count == 1) {
+ basedn = ldb_msg_find_attr_as_dn(ldb, res->msgs[0], "defaultNamingContext");
+ ldb_set_opaque(ldb, "default_baseDN", basedn);
+ }
+ talloc_free(res);
+ }
+
+ talloc_free(tmp_ctx);
+ return basedn;
+}
+
+const struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb)
+{
+ return (const struct ldb_dn *)ldb_get_opaque(ldb, "default_baseDN");
+}
+
+/*
+ connect to a database. The URL can either be one of the following forms
+ ldb://path
+ ldapi://path
+
+ flags is made up of LDB_FLG_*
+
+ the options are passed uninterpreted to the backend, and are
+ backend specific
+*/
+int ldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[])
+{
+ int ret;
+
+ ldb->flags = flags;
+
+ ret = ldb_connect_backend(ldb, url, options, &ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ if (ldb_load_modules(ldb, options) != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to load modules for %s: %s\n",
+ url, ldb_errstring(ldb));
+ return LDB_ERR_OTHER;
+ }
+
+ /* TODO: get timeout from options if available there */
+ ldb->default_timeout = 300; /* set default to 5 minutes */
+
+ /* set the default base dn */
+ ldb_set_default_basedn(ldb);
+
+ return LDB_SUCCESS;
+}
+
+void ldb_set_errstring(struct ldb_context *ldb, const char *err_string)
+{
+ if (ldb->err_string) {
+ talloc_free(ldb->err_string);
+ }
+ ldb->err_string = talloc_strdup(ldb, err_string);
+}
+
+void ldb_asprintf_errstring(struct ldb_context *ldb, const char *format, ...)
+{
+ va_list ap;
+
+ if (ldb->err_string) {
+ talloc_free(ldb->err_string);
+ }
+
+ va_start(ap, format);
+ ldb->err_string = talloc_vasprintf(ldb, format, ap);
+ va_end(ap);
+}
+
+void ldb_reset_err_string(struct ldb_context *ldb)
+{
+ if (ldb->err_string) {
+ talloc_free(ldb->err_string);
+ ldb->err_string = NULL;
+ }
+}
+
+#define FIRST_OP(ldb, op) do { \
+ module = ldb->modules; \
+ while (module && module->ops->op == NULL) module = module->next; \
+ if (module == NULL) { \
+ ldb_asprintf_errstring(ldb, "unable to find module or backend to handle operation: " #op); \
+ return LDB_ERR_OPERATIONS_ERROR; \
+ } \
+} while (0)
+
+/*
+ start a transaction
+*/
+static int ldb_transaction_start_internal(struct ldb_context *ldb)
+{
+ struct ldb_module *module;
+ int status;
+ FIRST_OP(ldb, start_transaction);
+
+ ldb_reset_err_string(ldb);
+
+ status = module->ops->start_transaction(module);
+ if (status != LDB_SUCCESS) {
+ if (ldb->err_string == NULL) {
+ /* no error string was setup by the backend */
+ ldb_asprintf_errstring(ldb,
+ "ldb transaction start: %s (%d)",
+ ldb_strerror(status),
+ status);
+ }
+ }
+ return status;
+}
+
+/*
+ commit a transaction
+*/
+static int ldb_transaction_commit_internal(struct ldb_context *ldb)
+{
+ struct ldb_module *module;
+ int status;
+ FIRST_OP(ldb, end_transaction);
+
+ ldb_reset_err_string(ldb);
+
+ status = module->ops->end_transaction(module);
+ if (status != LDB_SUCCESS) {
+ if (ldb->err_string == NULL) {
+ /* no error string was setup by the backend */
+ ldb_asprintf_errstring(ldb,
+ "ldb transaction commit: %s (%d)",
+ ldb_strerror(status),
+ status);
+ }
+ }
+ return status;
+}
+
+/*
+ cancel a transaction
+*/
+static int ldb_transaction_cancel_internal(struct ldb_context *ldb)
+{
+ struct ldb_module *module;
+ int status;
+ FIRST_OP(ldb, del_transaction);
+
+ status = module->ops->del_transaction(module);
+ if (status != LDB_SUCCESS) {
+ if (ldb->err_string == NULL) {
+ /* no error string was setup by the backend */
+ ldb_asprintf_errstring(ldb,
+ "ldb transaction cancel: %s (%d)",
+ ldb_strerror(status),
+ status);
+ }
+ }
+ return status;
+}
+
+int ldb_transaction_start(struct ldb_context *ldb)
+{
+ /* disable autotransactions */
+ ldb->transaction_active++;
+
+ return ldb_transaction_start_internal(ldb);
+}
+
+int ldb_transaction_commit(struct ldb_context *ldb)
+{
+ /* renable autotransactions (when we reach 0) */
+ if (ldb->transaction_active > 0)
+ ldb->transaction_active--;
+
+ return ldb_transaction_commit_internal(ldb);
+}
+
+int ldb_transaction_cancel(struct ldb_context *ldb)
+{
+ /* renable autotransactions (when we reach 0) */
+ if (ldb->transaction_active > 0)
+ ldb->transaction_active--;
+
+ return ldb_transaction_cancel_internal(ldb);
+}
+
+static int ldb_autotransaction_start(struct ldb_context *ldb)
+{
+ /* explicit transaction active, ignore autotransaction request */
+ if (ldb->transaction_active)
+ return LDB_SUCCESS;
+
+ return ldb_transaction_start_internal(ldb);
+}
+
+static int ldb_autotransaction_commit(struct ldb_context *ldb)
+{
+ /* explicit transaction active, ignore autotransaction request */
+ if (ldb->transaction_active)
+ return LDB_SUCCESS;
+
+ return ldb_transaction_commit_internal(ldb);
+}
+
+static int ldb_autotransaction_cancel(struct ldb_context *ldb)
+{
+ /* explicit transaction active, ignore autotransaction request */
+ if (ldb->transaction_active)
+ return LDB_SUCCESS;
+
+ return ldb_transaction_cancel_internal(ldb);
+}
+
+/* autostarts a transacion if none active */
+static int ldb_autotransaction_request(struct ldb_context *ldb, struct ldb_request *req)
+{
+ int ret;
+
+ ret = ldb_autotransaction_start(ldb);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_request(ldb, req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+ if (ret == LDB_SUCCESS) {
+ return ldb_autotransaction_commit(ldb);
+ }
+ ldb_autotransaction_cancel(ldb);
+
+ if (ldb->err_string == NULL) {
+ /* no error string was setup by the backend */
+ ldb_asprintf_errstring(ldb, "%s (%d)", ldb_strerror(ret), ret);
+ }
+
+ return ret;
+}
+
+int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type)
+{
+ if (!handle) {
+ return LDB_SUCCESS;
+ }
+
+ return handle->module->ops->wait(handle, type);
+}
+
+/* set the specified timeout or, if timeout is 0 set the default timeout */
+/* timeout == -1 means no timeout */
+int ldb_set_timeout(struct ldb_context *ldb, struct ldb_request *req, int timeout)
+{
+ if (req == NULL) return LDB_ERR_OPERATIONS_ERROR;
+
+ if (timeout != 0) {
+ req->timeout = timeout;
+ } else {
+ req->timeout = ldb->default_timeout;
+ }
+ req->starttime = time(NULL);
+
+ return LDB_SUCCESS;
+}
+
+/* calculates the new timeout based on the previous starttime and timeout */
+int ldb_set_timeout_from_prev_req(struct ldb_context *ldb, struct ldb_request *oldreq, struct ldb_request *newreq)
+{
+ time_t now;
+
+ if (newreq == NULL) return LDB_ERR_OPERATIONS_ERROR;
+
+ now = time(NULL);
+
+ if (oldreq == NULL)
+ return ldb_set_timeout(ldb, newreq, 0);
+
+ if ((now - oldreq->starttime) > oldreq->timeout) {
+ return LDB_ERR_TIME_LIMIT_EXCEEDED;
+ }
+ newreq->starttime = oldreq->starttime;
+ newreq->timeout = oldreq->timeout - (now - oldreq->starttime);
+
+ return LDB_SUCCESS;
+}
+
+
+/*
+ set the permissions for new files to be passed to open() in
+ backends that use local files
+ */
+void ldb_set_create_perms(struct ldb_context *ldb, unsigned int perms)
+{
+ ldb->create_perms = perms;
+}
+
+/*
+ start an ldb request
+ NOTE: the request must be a talloc context.
+ returns LDB_ERR_* on errors.
+*/
+int ldb_request(struct ldb_context *ldb, struct ldb_request *req)
+{
+ struct ldb_module *module;
+ int ret;
+
+ ldb_reset_err_string(ldb);
+
+ /* call the first module in the chain */
+ switch (req->operation) {
+ case LDB_SEARCH:
+ FIRST_OP(ldb, search);
+ ret = module->ops->search(module, req);
+ break;
+ case LDB_ADD:
+ FIRST_OP(ldb, add);
+ ret = module->ops->add(module, req);
+ break;
+ case LDB_MODIFY:
+ FIRST_OP(ldb, modify);
+ ret = module->ops->modify(module, req);
+ break;
+ case LDB_DELETE:
+ FIRST_OP(ldb, del);
+ ret = module->ops->del(module, req);
+ break;
+ case LDB_RENAME:
+ FIRST_OP(ldb, rename);
+ ret = module->ops->rename(module, req);
+ break;
+ case LDB_SEQUENCE_NUMBER:
+ FIRST_OP(ldb, sequence_number);
+ ret = module->ops->sequence_number(module, req);
+ break;
+ default:
+ FIRST_OP(ldb, request);
+ ret = module->ops->request(module, req);
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ search the database given a LDAP-like search expression
+
+ returns an LDB error code
+
+ Use talloc_free to free the ldb_message returned in 'res', if successful
+
+*/
+int ldb_search_default_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+{
+ struct ldb_result *res;
+ int n;
+
+ if (!context) {
+ ldb_set_errstring(ldb, "NULL Context in callback");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ res = talloc_get_type(context, struct ldb_result);
+
+ if (!res || !ares) {
+ ldb_set_errstring(ldb, "NULL res or ares in callback");
+ goto error;
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, res->count + 2);
+ if (! res->msgs) {
+ goto error;
+ }
+
+ res->msgs[res->count + 1] = NULL;
+
+ res->msgs[res->count] = talloc_move(res->msgs, &ares->message);
+ res->count++;
+ break;
+ case LDB_REPLY_REFERRAL:
+ if (res->refs) {
+ for (n = 0; res->refs[n]; n++) /*noop*/ ;
+ } else {
+ n = 0;
+ }
+
+ res->refs = talloc_realloc(res, res->refs, char *, n + 2);
+ if (! res->refs) {
+ goto error;
+ }
+
+ res->refs[n] = talloc_move(res->refs, &ares->referral);
+ res->refs[n + 1] = NULL;
+ case LDB_REPLY_EXTENDED:
+ case LDB_REPLY_DONE:
+ /* TODO: we should really support controls on entries and referrals too! */
+ res->controls = talloc_move(res, &ares->controls);
+ break;
+ }
+ talloc_free(ares);
+ return LDB_SUCCESS;
+
+error:
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+int ldb_build_search_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ void *mem_ctx,
+ const struct ldb_dn *base,
+ enum ldb_scope scope,
+ const char *expression,
+ const char * const *attrs,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback)
+{
+ struct ldb_request *req;
+
+ *ret_req = NULL;
+
+ req = talloc(mem_ctx, struct ldb_request);
+ if (req == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_SEARCH;
+ if (base == NULL) {
+ req->op.search.base = ldb_dn_new(req);
+ } else {
+ req->op.search.base = base;
+ }
+ req->op.search.scope = scope;
+
+ req->op.search.tree = ldb_parse_tree(req, expression);
+ if (req->op.search.tree == NULL) {
+ ldb_set_errstring(ldb, "Unable to parse search expression");
+ talloc_free(req);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->op.search.attrs = attrs;
+ req->controls = controls;
+ req->context = context;
+ req->callback = callback;
+
+ *ret_req = req;
+ return LDB_SUCCESS;
+}
+
+int ldb_build_add_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ void *mem_ctx,
+ const struct ldb_message *message,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback)
+{
+ struct ldb_request *req;
+
+ *ret_req = NULL;
+
+ req = talloc(mem_ctx, struct ldb_request);
+ if (req == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_ADD;
+ req->op.add.message = message;
+ req->controls = controls;
+ req->context = context;
+ req->callback = callback;
+
+ *ret_req = req;
+
+ return LDB_SUCCESS;
+}
+
+int ldb_build_mod_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ void *mem_ctx,
+ const struct ldb_message *message,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback)
+{
+ struct ldb_request *req;
+
+ *ret_req = NULL;
+
+ req = talloc(mem_ctx, struct ldb_request);
+ if (req == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_MODIFY;
+ req->op.mod.message = message;
+ req->controls = controls;
+ req->context = context;
+ req->callback = callback;
+
+ *ret_req = req;
+
+ return LDB_SUCCESS;
+}
+
+int ldb_build_del_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ void *mem_ctx,
+ const struct ldb_dn *dn,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback)
+{
+ struct ldb_request *req;
+
+ *ret_req = NULL;
+
+ req = talloc(mem_ctx, struct ldb_request);
+ if (req == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_DELETE;
+ req->op.del.dn = dn;
+ req->controls = controls;
+ req->context = context;
+ req->callback = callback;
+
+ *ret_req = req;
+
+ return LDB_SUCCESS;
+}
+
+int ldb_build_rename_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ void *mem_ctx,
+ const struct ldb_dn *olddn,
+ const struct ldb_dn *newdn,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback)
+{
+ struct ldb_request *req;
+
+ *ret_req = NULL;
+
+ req = talloc(mem_ctx, struct ldb_request);
+ if (req == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_RENAME;
+ req->op.rename.olddn = olddn;
+ req->op.rename.newdn = newdn;
+ req->controls = controls;
+ req->context = context;
+ req->callback = callback;
+
+ *ret_req = req;
+
+ return LDB_SUCCESS;
+}
+
+/*
+ note that ldb_search() will automatically replace a NULL 'base' value with the
+ defaultNamingContext from the rootDSE if available.
+*/
+int ldb_search(struct ldb_context *ldb,
+ const struct ldb_dn *base,
+ enum ldb_scope scope,
+ const char *expression,
+ const char * const *attrs,
+ struct ldb_result **_res)
+{
+ struct ldb_request *req;
+ int ret;
+ struct ldb_result *res;
+
+ *_res = NULL;
+
+ res = talloc_zero(ldb, struct ldb_result);
+ if (!res) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_build_search_req(&req, ldb, ldb,
+ base?base:ldb_get_default_basedn(ldb),
+ scope,
+ expression,
+ attrs,
+ NULL,
+ res,
+ ldb_search_default_callback);
+
+ if (ret != LDB_SUCCESS) goto done;
+
+ ldb_set_timeout(ldb, req, 0); /* use default timeout */
+
+ ret = ldb_request(ldb, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+ talloc_free(req);
+
+done:
+ if (ret != LDB_SUCCESS) {
+ talloc_free(res);
+ }
+
+ *_res = res;
+ return ret;
+}
+
+/*
+ a useful search function where you can easily define the expression and that
+ takes a memory context where results are allocated
+*/
+
+int ldb_search_exp_fmt(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_result **result,
+ struct ldb_dn *base, enum ldb_scope scope, const char * const *attrs,
+ const char *exp_fmt, ...)
+{
+ struct ldb_result *res;
+ char *expression;
+ va_list ap;
+ int ret;
+
+ res = NULL;
+ *result = NULL;
+
+ va_start(ap, exp_fmt);
+ expression = talloc_vasprintf(mem_ctx, exp_fmt, ap);
+ va_end(ap);
+
+ if ( ! expression) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_search(ldb, base, scope, expression, attrs, &res);
+
+ if (ret == LDB_SUCCESS) {
+ talloc_steal(mem_ctx, res);
+ *result = res;
+ } else {
+ talloc_free(res);
+ }
+
+ talloc_free(expression);
+
+ return ret;
+}
+
+/*
+ add a record to the database. Will fail if a record with the given class and key
+ already exists
+*/
+int ldb_add(struct ldb_context *ldb,
+ const struct ldb_message *message)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_msg_sanity_check(ldb, message);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_build_add_req(&req, ldb, ldb,
+ message,
+ NULL,
+ NULL,
+ NULL);
+
+ if (ret != LDB_SUCCESS) return ret;
+
+ ldb_set_timeout(ldb, req, 0); /* use default timeout */
+
+ /* do request and autostart a transaction */
+ ret = ldb_autotransaction_request(ldb, req);
+
+ talloc_free(req);
+ return ret;
+}
+
+/*
+ modify the specified attributes of a record
+*/
+int ldb_modify(struct ldb_context *ldb,
+ const struct ldb_message *message)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_msg_sanity_check(ldb, message);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_build_mod_req(&req, ldb, ldb,
+ message,
+ NULL,
+ NULL,
+ NULL);
+
+ if (ret != LDB_SUCCESS) return ret;
+
+ ldb_set_timeout(ldb, req, 0); /* use default timeout */
+
+ /* do request and autostart a transaction */
+ ret = ldb_autotransaction_request(ldb, req);
+
+ talloc_free(req);
+ return ret;
+}
+
+
+/*
+ delete a record from the database
+*/
+int ldb_delete(struct ldb_context *ldb, const struct ldb_dn *dn)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_build_del_req(&req, ldb, ldb,
+ dn,
+ NULL,
+ NULL,
+ NULL);
+
+ if (ret != LDB_SUCCESS) return ret;
+
+ ldb_set_timeout(ldb, req, 0); /* use default timeout */
+
+ /* do request and autostart a transaction */
+ ret = ldb_autotransaction_request(ldb, req);
+
+ talloc_free(req);
+ return ret;
+}
+
+/*
+ rename a record in the database
+*/
+int ldb_rename(struct ldb_context *ldb, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_build_rename_req(&req, ldb, ldb,
+ olddn,
+ newdn,
+ NULL,
+ NULL,
+ NULL);
+
+ if (ret != LDB_SUCCESS) return ret;
+
+ ldb_set_timeout(ldb, req, 0); /* use default timeout */
+
+ /* do request and autostart a transaction */
+ ret = ldb_autotransaction_request(ldb, req);
+
+ talloc_free(req);
+ return ret;
+}
+
+
+/*
+ return the global sequence number
+*/
+int ldb_sequence_number(struct ldb_context *ldb, enum ldb_sequence_type type, uint64_t *seq_num)
+{
+ struct ldb_request *req;
+ int ret;
+
+ req = talloc(ldb, struct ldb_request);
+ if (req == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_SEQUENCE_NUMBER;
+ req->controls = NULL;
+ req->context = NULL;
+ req->callback = NULL;
+ ldb_set_timeout(ldb, req, 0); /* use default timeout */
+
+ req->op.seq_num.type = type;
+ /* do request and autostart a transaction */
+ ret = ldb_request(ldb, req);
+
+ if (ret == LDB_SUCCESS) {
+ *seq_num = req->op.seq_num.seq_num;
+ }
+
+ talloc_free(req);
+ return ret;
+}
+
+
+
+/*
+ return extended error information
+*/
+const char *ldb_errstring(struct ldb_context *ldb)
+{
+ if (ldb->err_string) {
+ return ldb->err_string;
+ }
+
+ return NULL;
+}
+
+/*
+ return a string explaining what a ldb error constant meancs
+*/
+const char *ldb_strerror(int ldb_err)
+{
+ switch (ldb_err) {
+ case LDB_SUCCESS:
+ return "Success";
+ case LDB_ERR_OPERATIONS_ERROR:
+ return "Operations error";
+ case LDB_ERR_PROTOCOL_ERROR:
+ return "Protocol error";
+ case LDB_ERR_TIME_LIMIT_EXCEEDED:
+ return "Time limit exceeded";
+ case LDB_ERR_SIZE_LIMIT_EXCEEDED:
+ return "Size limit exceeded";
+ case LDB_ERR_COMPARE_FALSE:
+ return "Compare false";
+ case LDB_ERR_COMPARE_TRUE:
+ return "Compare true";
+ case LDB_ERR_AUTH_METHOD_NOT_SUPPORTED:
+ return "Auth method not supported";
+ case LDB_ERR_STRONG_AUTH_REQUIRED:
+ return "Strong auth required";
+/* 9 RESERVED */
+ case LDB_ERR_REFERRAL:
+ return "Referral error";
+ case LDB_ERR_ADMIN_LIMIT_EXCEEDED:
+ return "Admin limit exceeded";
+ case LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION:
+ return "Unsupported critical extension";
+ case LDB_ERR_CONFIDENTIALITY_REQUIRED:
+ return "Confidentiality required";
+ case LDB_ERR_SASL_BIND_IN_PROGRESS:
+ return "SASL bind in progress";
+ case LDB_ERR_NO_SUCH_ATTRIBUTE:
+ return "No such attribute";
+ case LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE:
+ return "Undefined attribute type";
+ case LDB_ERR_INAPPROPRIATE_MATCHING:
+ return "Inappropriate matching";
+ case LDB_ERR_CONSTRAINT_VIOLATION:
+ return "Constraint violation";
+ case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
+ return "Attribute or value exists";
+ case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX:
+ return "Invalid attribute syntax";
+/* 22-31 unused */
+ case LDB_ERR_NO_SUCH_OBJECT:
+ return "No such object";
+ case LDB_ERR_ALIAS_PROBLEM:
+ return "Alias problem";
+ case LDB_ERR_INVALID_DN_SYNTAX:
+ return "Invalid DN syntax";
+/* 35 RESERVED */
+ case LDB_ERR_ALIAS_DEREFERENCING_PROBLEM:
+ return "Alias dereferencing problem";
+/* 37-47 unused */
+ case LDB_ERR_INAPPROPRIATE_AUTHENTICATION:
+ return "Inappropriate authentication";
+ case LDB_ERR_INVALID_CREDENTIALS:
+ return "Invalid credentials";
+ case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+ return "insufficient access rights";
+ case LDB_ERR_BUSY:
+ return "Busy";
+ case LDB_ERR_UNAVAILABLE:
+ return "Unavailable";
+ case LDB_ERR_UNWILLING_TO_PERFORM:
+ return "Unwilling to perform";
+ case LDB_ERR_LOOP_DETECT:
+ return "Loop detect";
+/* 55-63 unused */
+ case LDB_ERR_NAMING_VIOLATION:
+ return "Naming violation";
+ case LDB_ERR_OBJECT_CLASS_VIOLATION:
+ return "Object class violation";
+ case LDB_ERR_NOT_ALLOWED_ON_NON_LEAF:
+ return "Not allowed on non-leaf";
+ case LDB_ERR_NOT_ALLOWED_ON_RDN:
+ return "Not allowed on RDN";
+ case LDB_ERR_ENTRY_ALREADY_EXISTS:
+ return "Entry already exists";
+ case LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED:
+ return "Object class mods prohibited";
+/* 70 RESERVED FOR CLDAP */
+ case LDB_ERR_AFFECTS_MULTIPLE_DSAS:
+ return "Affects multiple DSAs";
+/* 72-79 unused */
+ case LDB_ERR_OTHER:
+ return "Other";
+ }
+
+ return "Unknown error";
+}
+
+/*
+ set backend specific opaque parameters
+*/
+int ldb_set_opaque(struct ldb_context *ldb, const char *name, void *value)
+{
+ struct ldb_opaque *o;
+
+ /* allow updating an existing value */
+ for (o=ldb->opaque;o;o=o->next) {
+ if (strcmp(o->name, name) == 0) {
+ o->value = value;
+ return LDB_SUCCESS;
+ }
+ }
+
+ o = talloc(ldb, struct ldb_opaque);
+ if (o == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OTHER;
+ }
+ o->next = ldb->opaque;
+ o->name = name;
+ o->value = value;
+ ldb->opaque = o;
+ return LDB_SUCCESS;
+}
+
+/*
+ get a previously set opaque value
+*/
+void *ldb_get_opaque(struct ldb_context *ldb, const char *name)
+{
+ struct ldb_opaque *o;
+ for (o=ldb->opaque;o;o=o->next) {
+ if (strcmp(o->name, name) == 0) {
+ return o->value;
+ }
+ }
+ return NULL;
+}
diff --git a/source3/lib/ldb/common/ldb_attributes.c b/source3/lib/ldb/common/ldb_attributes.c
new file mode 100644
index 0000000000..5ecbdc7940
--- /dev/null
+++ b/source3/lib/ldb/common/ldb_attributes.c
@@ -0,0 +1,308 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ register handlers for specific attributes and objectclass relationships
+
+ this allows a backend to store its schema information in any format
+ it likes (or to not have any schema information at all) while keeping the
+ message matching logic generic
+*/
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+/*
+ add to the list of ldif handlers for this ldb context
+*/
+int ldb_set_attrib_handlers(struct ldb_context *ldb,
+ const struct ldb_attrib_handler *handlers,
+ unsigned num_handlers)
+{
+ int i;
+ struct ldb_attrib_handler *h;
+ h = talloc_realloc(ldb, ldb->schema.attrib_handlers,
+ struct ldb_attrib_handler,
+ ldb->schema.num_attrib_handlers + num_handlers);
+ if (h == NULL) {
+ ldb_oom(ldb);
+ return -1;
+ }
+ ldb->schema.attrib_handlers = h;
+ memcpy(h + ldb->schema.num_attrib_handlers,
+ handlers, sizeof(*h) * num_handlers);
+ for (i=0;i<num_handlers;i++) {
+ if (h[ldb->schema.num_attrib_handlers+i].flags & LDB_ATTR_FLAG_ALLOCATED) {
+ h[ldb->schema.num_attrib_handlers+i].attr = talloc_strdup(ldb->schema.attrib_handlers,
+ h[ldb->schema.num_attrib_handlers+i].attr);
+ if (h[ldb->schema.num_attrib_handlers+i].attr == NULL) {
+ ldb_oom(ldb);
+ return -1;
+ }
+ }
+ }
+ ldb->schema.num_attrib_handlers += num_handlers;
+ return 0;
+}
+
+
+/*
+ default function for read/write/canonicalise
+*/
+static int ldb_default_copy(struct ldb_context *ldb,
+ void *mem_ctx,
+ const struct ldb_val *in,
+ struct ldb_val *out)
+{
+ *out = ldb_val_dup(mem_ctx, in);
+
+ if (out->data == NULL && in->data != NULL) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ default function for comparison
+*/
+static int ldb_default_cmp(struct ldb_context *ldb,
+ void *mem_ctx,
+ const struct ldb_val *v1,
+ const struct ldb_val *v2)
+{
+ if (v1->length != v2->length) {
+ return v1->length - v2->length;
+ }
+ return memcmp(v1->data, v2->data, v1->length);
+}
+
+/*
+ default handler function pointers
+*/
+static const struct ldb_attrib_handler ldb_default_attrib_handler = {
+ .attr = NULL,
+ .ldif_read_fn = ldb_default_copy,
+ .ldif_write_fn = ldb_default_copy,
+ .canonicalise_fn = ldb_default_copy,
+ .comparison_fn = ldb_default_cmp,
+};
+
+/*
+ return the attribute handlers for a given attribute
+*/
+const struct ldb_attrib_handler *ldb_attrib_handler(struct ldb_context *ldb,
+ const char *attrib)
+{
+ int i;
+ const struct ldb_attrib_handler *def = &ldb_default_attrib_handler;
+ /* TODO: should be replaced with a binary search, with a sort on add */
+ for (i=0;i<ldb->schema.num_attrib_handlers;i++) {
+ if (strcmp(ldb->schema.attrib_handlers[i].attr, "*") == 0) {
+ def = &ldb->schema.attrib_handlers[i];
+ }
+ if (ldb_attr_cmp(attrib, ldb->schema.attrib_handlers[i].attr) == 0) {
+ return &ldb->schema.attrib_handlers[i];
+ }
+ }
+ return def;
+}
+
+
+/*
+ add to the list of ldif handlers for this ldb context
+*/
+void ldb_remove_attrib_handler(struct ldb_context *ldb, const char *attrib)
+{
+ const struct ldb_attrib_handler *h;
+ int i;
+ h = ldb_attrib_handler(ldb, attrib);
+ if (h == &ldb_default_attrib_handler) {
+ return;
+ }
+ if (h->flags & LDB_ATTR_FLAG_ALLOCATED) {
+ talloc_free(discard_const_p(char, h->attr));
+ }
+ i = h - ldb->schema.attrib_handlers;
+ if (i < ldb->schema.num_attrib_handlers - 1) {
+ memmove(&ldb->schema.attrib_handlers[i],
+ h+1, sizeof(*h) * (ldb->schema.num_attrib_handlers-(i+1)));
+ }
+ ldb->schema.num_attrib_handlers--;
+}
+
+/*
+ setup a attribute handler using a standard syntax
+*/
+int ldb_set_attrib_handler_syntax(struct ldb_context *ldb,
+ const char *attr, const char *syntax)
+{
+ const struct ldb_attrib_handler *h = ldb_attrib_handler_syntax(ldb, syntax);
+ struct ldb_attrib_handler h2;
+ if (h == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Unknown syntax '%s'\n", syntax);
+ return -1;
+ }
+ h2 = *h;
+ h2.attr = attr;
+ return ldb_set_attrib_handlers(ldb, &h2, 1);
+}
+
+/*
+ setup the attribute handles for well known attributes
+*/
+int ldb_setup_wellknown_attributes(struct ldb_context *ldb)
+{
+ const struct {
+ const char *attr;
+ const char *syntax;
+ } wellknown[] = {
+ { "dn", LDB_SYNTAX_DN },
+ { "ncName", LDB_SYNTAX_DN },
+ { "distinguishedName", LDB_SYNTAX_DN },
+ { "cn", LDB_SYNTAX_DIRECTORY_STRING },
+ { "dc", LDB_SYNTAX_DIRECTORY_STRING },
+ { "ou", LDB_SYNTAX_DIRECTORY_STRING },
+ { "objectClass", LDB_SYNTAX_OBJECTCLASS }
+ };
+ int i;
+ for (i=0;i<ARRAY_SIZE(wellknown);i++) {
+ if (ldb_set_attrib_handler_syntax(ldb, wellknown[i].attr,
+ wellknown[i].syntax) != 0) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ return the list of subclasses for a class
+*/
+const char **ldb_subclass_list(struct ldb_context *ldb, const char *classname)
+{
+ int i;
+ for (i=0;i<ldb->schema.num_classes;i++) {
+ if (ldb_attr_cmp(classname, ldb->schema.classes[i].name) == 0) {
+ return (const char **)ldb->schema.classes[i].subclasses;
+ }
+ }
+ return NULL;
+}
+
+
+/*
+ add a new subclass
+*/
+static int ldb_subclass_new(struct ldb_context *ldb, const char *classname, const char *subclass)
+{
+ struct ldb_subclass *s, *c;
+ s = talloc_realloc(ldb, ldb->schema.classes, struct ldb_subclass, ldb->schema.num_classes+1);
+ if (s == NULL) goto failed;
+
+ ldb->schema.classes = s;
+ c = &s[ldb->schema.num_classes];
+ c->name = talloc_strdup(s, classname);
+ if (c->name == NULL) goto failed;
+
+ c->subclasses = talloc_array(s, char *, 2);
+ if (c->subclasses == NULL) goto failed;
+
+ c->subclasses[0] = talloc_strdup(c->subclasses, subclass);
+ if (c->subclasses[0] == NULL) goto failed;
+ c->subclasses[1] = NULL;
+
+ ldb->schema.num_classes++;
+
+ return 0;
+failed:
+ ldb_oom(ldb);
+ return -1;
+}
+
+/*
+ add a subclass
+*/
+int ldb_subclass_add(struct ldb_context *ldb, const char *classname, const char *subclass)
+{
+ int i, n;
+ struct ldb_subclass *c;
+ char **s;
+
+ for (i=0;i<ldb->schema.num_classes;i++) {
+ if (ldb_attr_cmp(classname, ldb->schema.classes[i].name) == 0) {
+ break;
+ }
+ }
+ if (i == ldb->schema.num_classes) {
+ return ldb_subclass_new(ldb, classname, subclass);
+ }
+ c = &ldb->schema.classes[i];
+
+ for (n=0;c->subclasses[n];n++) /* noop */;
+
+ s = talloc_realloc(ldb->schema.classes, c->subclasses, char *, n+2);
+ if (s == NULL) {
+ ldb_oom(ldb);
+ return -1;
+ }
+
+ c->subclasses = s;
+ s[n] = talloc_strdup(s, subclass);
+ if (s[n] == NULL) {
+ ldb_oom(ldb);
+ return -1;
+ }
+ s[n+1] = NULL;
+
+ return 0;
+}
+
+/*
+ remove a set of subclasses for a class
+*/
+void ldb_subclass_remove(struct ldb_context *ldb, const char *classname)
+{
+ int i;
+ struct ldb_subclass *c;
+
+ for (i=0;i<ldb->schema.num_classes;i++) {
+ if (ldb_attr_cmp(classname, ldb->schema.classes[i].name) == 0) {
+ break;
+ }
+ }
+ if (i == ldb->schema.num_classes) {
+ return;
+ }
+
+ c = &ldb->schema.classes[i];
+ talloc_free(c->name);
+ talloc_free(c->subclasses);
+ if (ldb->schema.num_classes-(i+1) > 0) {
+ memmove(c, c+1, sizeof(*c) * (ldb->schema.num_classes-(i+1)));
+ }
+ ldb->schema.num_classes--;
+ if (ldb->schema.num_classes == 0) {
+ talloc_free(ldb->schema.classes);
+ ldb->schema.classes = NULL;
+ }
+}
diff --git a/source3/lib/ldb/common/ldb_controls.c b/source3/lib/ldb/common/ldb_controls.c
new file mode 100644
index 0000000000..9b49470941
--- /dev/null
+++ b/source3/lib/ldb/common/ldb_controls.c
@@ -0,0 +1,105 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb_controls.c
+ *
+ * Component: ldb controls utility functions
+ *
+ * Description: helper functions for control modules
+ *
+ * Author: Simo Sorce
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+/* check if a control with the specified "oid" exist and return it */
+/* returns NULL if not found */
+struct ldb_control *get_control_from_list(struct ldb_control **controls, const char *oid)
+{
+ int i;
+
+ /* check if there's a paged request control */
+ if (controls != NULL) {
+ for (i = 0; controls[i]; i++) {
+ if (strcmp(oid, controls[i]->oid) == 0) {
+ break;
+ }
+ }
+
+ return controls[i];
+ }
+
+ return NULL;
+}
+
+/* saves the current controls list into the "saver" and replace the one in req with a new one excluding
+the "exclude" control */
+/* returns False on error */
+int save_controls(struct ldb_control *exclude, struct ldb_request *req, struct ldb_control ***saver)
+{
+ struct ldb_control **lcs;
+ int i, j;
+
+ *saver = req->controls;
+ for (i = 0; req->controls[i]; i++);
+ if (i == 1) {
+ req->controls = NULL;
+ return 1;
+ }
+
+ lcs = talloc_array(req, struct ldb_control *, i);
+ if (!lcs) {
+ return 0;
+ }
+
+ for (i = 0, j = 0; (*saver)[i]; i++) {
+ if (exclude == (*saver)[i]) continue;
+ lcs[j] = (*saver)[i];
+ j++;
+ }
+ lcs[j] = NULL;
+
+ req->controls = lcs;
+ return 1;
+}
+
+/* check if there's any control marked as critical in the list */
+/* return True if any, False if none */
+int check_critical_controls(struct ldb_control **controls)
+{
+ int i;
+
+ if (controls == NULL) {
+ return 0;
+ }
+
+ for (i = 0; controls[i]; i++) {
+ if (controls[i]->critical) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/source3/lib/ldb/common/ldb_debug.c b/source3/lib/ldb/common/ldb_debug.c
new file mode 100644
index 0000000000..3c9442ea9c
--- /dev/null
+++ b/source3/lib/ldb/common/ldb_debug.c
@@ -0,0 +1,104 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb debug
+ *
+ * Description: functions for printing debug messages
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+/*
+ this allows the user to choose their own debug function
+*/
+int ldb_set_debug(struct ldb_context *ldb,
+ void (*debug)(void *context, enum ldb_debug_level level,
+ const char *fmt, va_list ap),
+ void *context)
+{
+ ldb->debug_ops.debug = debug;
+ ldb->debug_ops.context = context;
+ return 0;
+}
+
+/*
+ debug function for ldb_set_debug_stderr
+*/
+static void ldb_debug_stderr(void *context, enum ldb_debug_level level,
+ const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
+static void ldb_debug_stderr(void *context, enum ldb_debug_level level,
+ const char *fmt, va_list ap)
+{
+ if (level <= LDB_DEBUG_WARNING) {
+ vfprintf(stderr, fmt, ap);
+ }
+}
+
+/*
+ convenience function to setup debug messages on stderr
+ messages of level LDB_DEBUG_WARNING and higher are printed
+*/
+int ldb_set_debug_stderr(struct ldb_context *ldb)
+{
+ return ldb_set_debug(ldb, ldb_debug_stderr, ldb);
+}
+
+/*
+ log a message
+*/
+void ldb_debug(struct ldb_context *ldb, enum ldb_debug_level level, const char *fmt, ...)
+{
+ va_list ap;
+ if (ldb->debug_ops.debug == NULL) {
+ ldb_set_debug_stderr(ldb);
+ }
+ va_start(ap, fmt);
+ ldb->debug_ops.debug(ldb->debug_ops.context, level, fmt, ap);
+ va_end(ap);
+}
+
+
+/*
+ log a message, and set the ldb error string to the same message
+*/
+void ldb_debug_set(struct ldb_context *ldb, enum ldb_debug_level level,
+ const char *fmt, ...)
+{
+ va_list ap;
+ char *msg;
+ va_start(ap, fmt);
+ msg = talloc_vasprintf(ldb, fmt, ap);
+ va_end(ap);
+ if (msg != NULL) {
+ ldb_set_errstring(ldb, msg);
+ ldb_debug(ldb, level, "%s", msg);
+ }
+ talloc_free(msg);
+}
+
diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c
new file mode 100644
index 0000000000..7ef3c38024
--- /dev/null
+++ b/source3/lib/ldb/common/ldb_dn.c
@@ -0,0 +1,1027 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb dn explode and utility functions
+ *
+ * Description: - explode a dn into its own basic elements
+ * and put them in a structure
+ * - manipulate ldb_dn structures
+ *
+ * Author: Simo Sorce
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#define LDB_DN_NULL_FAILED(x) if (!(x)) goto failed
+
+#define LDB_SPECIAL "@SPECIAL"
+
+/**
+ internal ldb exploded dn structures
+*/
+struct ldb_dn_component {
+ char *name;
+ struct ldb_val value;
+};
+
+struct ldb_dn {
+ int comp_num;
+ struct ldb_dn_component *components;
+};
+
+int ldb_dn_is_special(const struct ldb_dn *dn)
+{
+ if (dn == NULL || dn->comp_num != 1) return 0;
+
+ return ! strcmp(dn->components[0].name, LDB_SPECIAL);
+}
+
+int ldb_dn_check_special(const struct ldb_dn *dn, const char *check)
+{
+ if (dn == NULL || dn->comp_num != 1) return 0;
+
+ return ! strcmp((char *)dn->components[0].value.data, check);
+}
+
+char *ldb_dn_escape_value(void *mem_ctx, struct ldb_val value)
+{
+ const char *p, *s, *src;
+ char *d, *dst;
+ int len;
+
+ if (!value.length)
+ return NULL;
+
+ p = s = src = (const char *)value.data;
+ len = value.length;
+
+ /* allocate destination string, it will be at most 3 times the source */
+ dst = d = talloc_array(mem_ctx, char, len * 3 + 1);
+ LDB_DN_NULL_FAILED(dst);
+
+ while (p - src < len) {
+
+ p += strcspn(p, ",=\n+<>#;\\\"");
+
+ if (p - src == len) /* found no escapable chars */
+ break;
+
+ memcpy(d, s, p - s); /* copy the part of the string before the stop */
+ d += (p - s); /* move to current position */
+
+ if (*p) { /* it is a normal escapable character */
+ *d++ = '\\';
+ *d++ = *p++;
+ } else { /* we have a zero byte in the string */
+ strncpy(d, "\00", 3); /* escape the zero */
+ d = d + 3;
+ p++; /* skip the zero */
+ }
+ s = p; /* move forward */
+ }
+
+ /* copy the last part (with zero) and return */
+ memcpy(d, s, &src[len] - s + 1);
+
+ return dst;
+
+failed:
+ talloc_free(dst);
+ return NULL;
+}
+
+static struct ldb_val ldb_dn_unescape_value(void *mem_ctx, const char *src)
+{
+ struct ldb_val value;
+ unsigned x;
+ char *p, *dst = NULL, *end;
+
+ memset(&value, 0, sizeof(value));
+
+ LDB_DN_NULL_FAILED(src);
+
+ dst = p = (char *)talloc_memdup(mem_ctx, src, strlen(src) + 1);
+ LDB_DN_NULL_FAILED(dst);
+
+ end = &dst[strlen(dst)];
+
+ while (*p) {
+ p += strcspn(p, ",=\n+<>#;\\\"");
+
+ if (*p == '\\') {
+ if (strchr(",=\n+<>#;\\\"", p[1])) {
+ memmove(p, p + 1, end - (p + 1) + 1);
+ end--;
+ p++;
+ continue;
+ }
+
+ if (sscanf(p + 1, "%02x", &x) == 1) {
+ *p = (unsigned char)x;
+ memmove(p + 1, p + 3, end - (p + 3) + 1);
+ end -= 2;
+ p++;
+ continue;
+ }
+ }
+
+ /* a string with not escaped specials is invalid (tested) */
+ if (*p != '\0') {
+ goto failed;
+ }
+ }
+
+ value.length = end - dst;
+ value.data = (uint8_t *)dst;
+ return value;
+
+failed:
+ talloc_free(dst);
+ return value;
+}
+
+/* check if the string contains quotes
+ * skips leading and trailing spaces
+ * - returns 0 if no quotes found
+ * - returns 1 if quotes are found and put their position
+ * in *quote_start and *quote_end parameters
+ * - return -1 if there are open quotes
+ */
+
+static int get_quotes_position(const char *source, int *quote_start, int *quote_end)
+{
+ const char *p;
+
+ if (source == NULL || quote_start == NULL || quote_end == NULL) return -1;
+
+ p = source;
+
+ /* check if there are quotes surrounding the value */
+ p += strspn(p, " \n"); /* skip white spaces */
+
+ if (*p == '\"') {
+ *quote_start = p - source;
+
+ p++;
+ while (*p != '\"') {
+ p = strchr(p, '\"');
+ LDB_DN_NULL_FAILED(p);
+
+ if (*(p - 1) == '\\')
+ p++;
+ }
+
+ *quote_end = p - source;
+ return 1;
+ }
+
+ return 0;
+
+failed:
+ return -1;
+}
+
+static char *seek_to_separator(char *string, const char *separators)
+{
+ char *p, *q;
+ int ret, qs, qe, escaped;
+
+ if (string == NULL || separators == NULL) return NULL;
+
+ p = strchr(string, '=');
+ LDB_DN_NULL_FAILED(p);
+
+ p++;
+
+ /* check if there are quotes surrounding the value */
+
+ ret = get_quotes_position(p, &qs, &qe);
+ if (ret == -1)
+ return NULL;
+
+ if (ret == 1) { /* quotes found */
+
+ p += qe; /* positioning after quotes */
+ p += strspn(p, " \n"); /* skip white spaces after the quote */
+
+ if (strcspn(p, separators) != 0) /* if there are characters between quotes */
+ return NULL; /* and separators, the dn is invalid */
+
+ return p; /* return on the separator */
+ }
+
+ /* no quotes found seek to separators */
+ q = p;
+ do {
+ escaped = 0;
+ ret = strcspn(q, separators);
+
+ if (q[ret - 1] == '\\') {
+ escaped = 1;
+ q = q + ret + 1;
+ }
+ } while (escaped);
+
+ if (ret == 0 && p == q) /* no separators ?! bail out */
+ return NULL;
+
+ return q + ret;
+
+failed:
+ return NULL;
+}
+
+static char *ldb_dn_trim_string(char *string, const char *edge)
+{
+ char *s, *p;
+
+ /* seek out edge from start of string */
+ s = string + strspn(string, edge);
+
+ /* backwards skip from end of string */
+ p = &s[strlen(s) - 1];
+ while (p > s && strchr(edge, *p)) {
+ *p = '\0';
+ p--;
+ }
+
+ return s;
+}
+
+/* we choosed to not support multpile valued components */
+static struct ldb_dn_component ldb_dn_explode_component(void *mem_ctx, char *raw_component)
+{
+ struct ldb_dn_component dc;
+ char *p;
+ int ret, qs, qe;
+
+ memset(&dc, 0, sizeof(dc));
+
+ if (raw_component == NULL) {
+ return dc;
+ }
+
+ /* find attribute type/value separator */
+ p = strchr(raw_component, '=');
+ LDB_DN_NULL_FAILED(p);
+
+ *p++ = '\0'; /* terminate name and point to value */
+
+ /* copy and trim name in the component */
+ dc.name = talloc_strdup(mem_ctx, ldb_dn_trim_string(raw_component, " \n"));
+ if (!dc.name)
+ return dc;
+
+ if (! ldb_valid_attr_name(dc.name)) {
+ goto failed;
+ }
+
+ ret = get_quotes_position(p, &qs, &qe);
+
+ switch (ret) {
+ case 0: /* no quotes trim the string */
+ p = ldb_dn_trim_string(p, " \n");
+ dc.value = ldb_dn_unescape_value(mem_ctx, p);
+ break;
+
+ case 1: /* quotes found get the unquoted string */
+ p[qe] = '\0';
+ p = p + qs + 1;
+ dc.value.length = strlen(p);
+ dc.value.data = (uint8_t *)talloc_memdup(mem_ctx, p,
+ dc.value.length + 1);
+ break;
+
+ default: /* mismatched quotes ot other error, bail out */
+ goto failed;
+ }
+
+ if (dc.value.length == 0) {
+ goto failed;
+ }
+
+ return dc;
+
+failed:
+ talloc_free(dc.name);
+ dc.name = NULL;
+ return dc;
+}
+
+struct ldb_dn *ldb_dn_new(void *mem_ctx)
+{
+ struct ldb_dn *edn;
+
+ edn = talloc(mem_ctx, struct ldb_dn);
+ LDB_DN_NULL_FAILED(edn);
+
+ /* Initially there are no components */
+ edn->comp_num = 0;
+ edn->components = NULL;
+
+ return edn;
+
+failed:
+ return NULL;
+}
+
+/*
+ explode a DN string into a ldb_dn structure
+*/
+struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn)
+{
+ struct ldb_dn *edn; /* the exploded dn */
+ char *pdn, *p;
+
+ if (dn == NULL) return NULL;
+
+ /* Allocate a structure to hold the exploded DN */
+ edn = ldb_dn_new(mem_ctx);
+ if (edn == NULL) {
+ return NULL;
+ }
+
+ pdn = NULL;
+
+ /* Empty DNs */
+ if (dn[0] == '\0') {
+ return edn;
+ }
+
+ /* Special DNs case */
+ if (dn[0] == '@') {
+ edn->comp_num = 1;
+ edn->components = talloc(edn, struct ldb_dn_component);
+ if (edn->components == NULL) goto failed;
+ edn->components[0].name = talloc_strdup(edn->components, LDB_SPECIAL);
+ if (edn->components[0].name == NULL) goto failed;
+ edn->components[0].value.data = (uint8_t *)talloc_strdup(edn->components, dn);
+ if (edn->components[0].value.data== NULL) goto failed;
+ edn->components[0].value.length = strlen(dn);
+ return edn;
+ }
+
+ pdn = p = talloc_strdup(edn, dn);
+ LDB_DN_NULL_FAILED(pdn);
+
+ /* get the components */
+ do {
+ char *t;
+
+ /* terminate the current component and return pointer to the next one */
+ t = seek_to_separator(p, ",;");
+ LDB_DN_NULL_FAILED(t);
+
+ if (*t) { /* here there is a separator */
+ *t = '\0'; /*terminate */
+ t++; /* a separtor means another component follows */
+ }
+
+ /* allocate space to hold the dn component */
+ edn->components = talloc_realloc(edn, edn->components,
+ struct ldb_dn_component,
+ edn->comp_num + 1);
+ if (edn->components == NULL)
+ goto failed;
+
+ /* store the exploded component in the main structure */
+ edn->components[edn->comp_num] = ldb_dn_explode_component(edn, p);
+ LDB_DN_NULL_FAILED(edn->components[edn->comp_num].name);
+
+ edn->comp_num++;
+
+ /* jump to the next component if any */
+ p = t;
+
+ } while(*p);
+
+ talloc_free(pdn);
+ return edn;
+
+failed:
+ talloc_free(pdn);
+ talloc_free(edn);
+ return NULL;
+}
+
+struct ldb_dn *ldb_dn_explode_or_special(void *mem_ctx, const char *dn)
+{
+ struct ldb_dn *edn; /* the exploded dn */
+
+ if (dn == NULL) return NULL;
+
+ if (strncasecmp(dn, "<GUID=", 6) == 0) {
+ /* this is special DN returned when the
+ * exploded_dn control is used
+ */
+
+ /* Allocate a structure to hold the exploded DN */
+ if (!(edn = ldb_dn_new(mem_ctx))) {
+ return NULL;
+ }
+
+ edn->comp_num = 1;
+ edn->components = talloc(edn, struct ldb_dn_component);
+ if (edn->components == NULL) goto failed;
+ edn->components[0].name = talloc_strdup(edn->components, LDB_SPECIAL);
+ if (edn->components[0].name == NULL) goto failed;
+ edn->components[0].value.data = (uint8_t *)talloc_strdup(edn->components, dn);
+ if (edn->components[0].value.data== NULL) goto failed;
+ edn->components[0].value.length = strlen(dn);
+ return edn;
+
+ }
+
+ return ldb_dn_explode(mem_ctx, dn);
+
+failed:
+ talloc_free(edn);
+ return NULL;
+}
+
+char *ldb_dn_linearize(void *mem_ctx, const struct ldb_dn *edn)
+{
+ char *dn, *value;
+ int i;
+
+ if (edn == NULL) return NULL;
+
+ /* Special DNs */
+ if (ldb_dn_is_special(edn)) {
+ dn = talloc_strdup(mem_ctx, (char *)edn->components[0].value.data);
+ return dn;
+ }
+
+ dn = talloc_strdup(mem_ctx, "");
+ LDB_DN_NULL_FAILED(dn);
+
+ for (i = 0; i < edn->comp_num; i++) {
+ value = ldb_dn_escape_value(dn, edn->components[i].value);
+ LDB_DN_NULL_FAILED(value);
+
+ if (i == 0) {
+ dn = talloc_asprintf_append(dn, "%s=%s", edn->components[i].name, value);
+ } else {
+ dn = talloc_asprintf_append(dn, ",%s=%s", edn->components[i].name, value);
+ }
+ LDB_DN_NULL_FAILED(dn);
+
+ talloc_free(value);
+ }
+
+ return dn;
+
+failed:
+ talloc_free(dn);
+ return NULL;
+}
+
+/* Determine if dn is below base, in the ldap tree. Used for
+ * evaluating a subtree search.
+ * 0 if they match, otherwise non-zero
+ */
+
+int ldb_dn_compare_base(struct ldb_context *ldb,
+ const struct ldb_dn *base,
+ const struct ldb_dn *dn)
+{
+ int ret;
+ int n0, n1;
+
+ if (base == NULL || base->comp_num == 0) return 0;
+ if (dn == NULL || dn->comp_num == 0) return -1;
+
+ /* if the base has more componts than the dn, then they differ */
+ if (base->comp_num > dn->comp_num) {
+ return (dn->comp_num - base->comp_num);
+ }
+
+ n0 = base->comp_num - 1;
+ n1 = dn->comp_num - 1;
+ while (n0 >= 0 && n1 >= 0) {
+ const struct ldb_attrib_handler *h;
+
+ /* compare names (attribute names are guaranteed to be ASCII only) */
+ ret = ldb_attr_cmp(base->components[n0].name,
+ dn->components[n1].name);
+ if (ret) {
+ return ret;
+ }
+
+ /* names match, compare values */
+ h = ldb_attrib_handler(ldb, base->components[n0].name);
+ ret = h->comparison_fn(ldb, ldb, &(base->components[n0].value),
+ &(dn->components[n1].value));
+ if (ret) {
+ return ret;
+ }
+ n1--;
+ n0--;
+ }
+
+ return 0;
+}
+
+/* compare DNs using casefolding compare functions.
+
+ If they match, then return 0
+ */
+
+int ldb_dn_compare(struct ldb_context *ldb,
+ const struct ldb_dn *edn0,
+ const struct ldb_dn *edn1)
+{
+ if (edn0 == NULL || edn1 == NULL) return edn1 - edn0;
+
+ if (edn0->comp_num != edn1->comp_num)
+ return (edn1->comp_num - edn0->comp_num);
+
+ return ldb_dn_compare_base(ldb, edn0, edn1);
+}
+
+int ldb_dn_cmp(struct ldb_context *ldb, const char *dn0, const char *dn1)
+{
+ struct ldb_dn *edn0;
+ struct ldb_dn *edn1;
+ int ret;
+
+ if (dn0 == NULL || dn1 == NULL) return dn1 - dn0;
+
+ edn0 = ldb_dn_explode_casefold(ldb, ldb, dn0);
+ if (edn0 == NULL) return 1;
+
+ edn1 = ldb_dn_explode_casefold(ldb, ldb, dn1);
+ if (edn1 == NULL) {
+ talloc_free(edn0);
+ return -1;
+ }
+
+ ret = ldb_dn_compare(ldb, edn0, edn1);
+
+ talloc_free(edn0);
+ talloc_free(edn1);
+
+ return ret;
+}
+
+/*
+ casefold a dn. We need to casefold the attribute names, and canonicalize
+ attribute values of case insensitive attributes.
+*/
+struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, void *mem_ctx, const struct ldb_dn *edn)
+{
+ struct ldb_dn *cedn;
+ int i, ret;
+
+ if (edn == NULL) return NULL;
+
+ cedn = ldb_dn_new(mem_ctx);
+ if (!cedn) {
+ return NULL;
+ }
+
+ cedn->comp_num = edn->comp_num;
+ cedn->components = talloc_array(cedn, struct ldb_dn_component, edn->comp_num);
+ if (!cedn->components) {
+ talloc_free(cedn);
+ return NULL;
+ }
+
+ for (i = 0; i < edn->comp_num; i++) {
+ struct ldb_dn_component dc;
+ const struct ldb_attrib_handler *h;
+
+ memset(&dc, 0, sizeof(dc));
+ dc.name = ldb_attr_casefold(cedn->components, edn->components[i].name);
+ if (!dc.name) {
+ talloc_free(cedn);
+ return NULL;
+ }
+
+ h = ldb_attrib_handler(ldb, dc.name);
+ ret = h->canonicalise_fn(ldb, cedn->components,
+ &(edn->components[i].value),
+ &(dc.value));
+ if (ret != 0) {
+ talloc_free(cedn);
+ return NULL;
+ }
+
+ cedn->components[i] = dc;
+ }
+
+ return cedn;
+}
+
+struct ldb_dn *ldb_dn_explode_casefold(struct ldb_context *ldb, void *mem_ctx, const char *dn)
+{
+ struct ldb_dn *edn, *cdn;
+
+ if (dn == NULL) return NULL;
+
+ edn = ldb_dn_explode(ldb, dn);
+ if (edn == NULL) return NULL;
+
+ cdn = ldb_dn_casefold(ldb, mem_ctx, edn);
+
+ talloc_free(edn);
+ return cdn;
+}
+
+char *ldb_dn_linearize_casefold(struct ldb_context *ldb, void *mem_ctx, const struct ldb_dn *edn)
+{
+ struct ldb_dn *cdn;
+ char *dn;
+
+ if (edn == NULL) return NULL;
+
+ /* Special DNs */
+ if (ldb_dn_is_special(edn)) {
+ dn = talloc_strdup(mem_ctx, (char *)edn->components[0].value.data);
+ return dn;
+ }
+
+ cdn = ldb_dn_casefold(ldb, mem_ctx, edn);
+ if (cdn == NULL) return NULL;
+
+ dn = ldb_dn_linearize(ldb, cdn);
+ if (dn == NULL) {
+ talloc_free(cdn);
+ return NULL;
+ }
+
+ talloc_free(cdn);
+ return dn;
+}
+
+static struct ldb_dn_component ldb_dn_copy_component(void *mem_ctx, struct ldb_dn_component *src)
+{
+ struct ldb_dn_component dst;
+
+ memset(&dst, 0, sizeof(dst));
+
+ if (src == NULL) {
+ return dst;
+ }
+
+ dst.value = ldb_val_dup(mem_ctx, &(src->value));
+ if (dst.value.data == NULL) {
+ return dst;
+ }
+
+ dst.name = talloc_strdup(mem_ctx, src->name);
+ if (dst.name == NULL) {
+ talloc_free(dst.value.data);
+ dst.value.data = NULL;
+ }
+
+ return dst;
+}
+
+/* Copy a DN but replace the old with the new base DN. */
+struct ldb_dn *ldb_dn_copy_rebase(void *mem_ctx, const struct ldb_dn *old, const struct ldb_dn *old_base, const struct ldb_dn *new_base)
+{
+ struct ldb_dn *new_dn;
+ int i, offset;
+
+ /* Perhaps we don't need to rebase at all? */
+ if (!old_base || !new_base) {
+ return ldb_dn_copy(mem_ctx, old);
+ }
+
+ offset = old->comp_num - old_base->comp_num;
+ if (!(new_dn = ldb_dn_copy_partial(mem_ctx, new_base,
+ offset + new_base->comp_num))) {
+ return NULL;
+ }
+ for (i = 0; i < offset; i++) {
+ new_dn->components[i] = ldb_dn_copy_component(new_dn->components, &(old->components[i]));
+ }
+
+ return new_dn;
+}
+
+/* copy specified number of elements of a dn into a new one
+ element are copied from top level up to the unique rdn
+ num_el may be greater than dn->comp_num (see ldb_dn_make_child)
+*/
+struct ldb_dn *ldb_dn_copy_partial(void *mem_ctx, const struct ldb_dn *dn, int num_el)
+{
+ struct ldb_dn *newdn;
+ int i, n, e;
+
+ if (dn == NULL) return NULL;
+ if (num_el <= 0) return NULL;
+
+ newdn = ldb_dn_new(mem_ctx);
+ LDB_DN_NULL_FAILED(newdn);
+
+ newdn->comp_num = num_el;
+ n = newdn->comp_num - 1;
+ newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num);
+ if (newdn->components == NULL) goto failed;
+
+ if (dn->comp_num == 0) return newdn;
+ e = dn->comp_num - 1;
+
+ for (i = 0; i < newdn->comp_num; i++) {
+ newdn->components[n - i] = ldb_dn_copy_component(newdn->components,
+ &(dn->components[e - i]));
+ if ((e - i) == 0) {
+ return newdn;
+ }
+ }
+
+ return newdn;
+
+failed:
+ talloc_free(newdn);
+ return NULL;
+}
+
+struct ldb_dn *ldb_dn_copy(void *mem_ctx, const struct ldb_dn *dn)
+{
+ if (dn == NULL) return NULL;
+ return ldb_dn_copy_partial(mem_ctx, dn, dn->comp_num);
+}
+
+struct ldb_dn *ldb_dn_get_parent(void *mem_ctx, const struct ldb_dn *dn)
+{
+ if (dn == NULL) return NULL;
+ return ldb_dn_copy_partial(mem_ctx, dn, dn->comp_num - 1);
+}
+
+struct ldb_dn_component *ldb_dn_build_component(void *mem_ctx, const char *attr,
+ const char *val)
+{
+ struct ldb_dn_component *dc;
+
+ if (attr == NULL || val == NULL) return NULL;
+
+ dc = talloc(mem_ctx, struct ldb_dn_component);
+ if (dc == NULL) return NULL;
+
+ dc->name = talloc_strdup(dc, attr);
+ if (dc->name == NULL) {
+ talloc_free(dc);
+ return NULL;
+ }
+
+ dc->value.data = (uint8_t *)talloc_strdup(dc, val);
+ if (dc->value.data == NULL) {
+ talloc_free(dc);
+ return NULL;
+ }
+
+ dc->value.length = strlen(val);
+
+ return dc;
+}
+
+struct ldb_dn *ldb_dn_build_child(void *mem_ctx, const char *attr,
+ const char * value,
+ const struct ldb_dn *base)
+{
+ struct ldb_dn *newdn;
+ if (! ldb_valid_attr_name(attr)) return NULL;
+ if (value == NULL || value == '\0') return NULL;
+
+ if (base != NULL) {
+ newdn = ldb_dn_copy_partial(mem_ctx, base, base->comp_num + 1);
+ LDB_DN_NULL_FAILED(newdn);
+ } else {
+ newdn = ldb_dn_new(mem_ctx);
+ LDB_DN_NULL_FAILED(newdn);
+
+ newdn->comp_num = 1;
+ newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num);
+ LDB_DN_NULL_FAILED(newdn->components);
+ }
+
+ newdn->components[0].name = talloc_strdup(newdn->components, attr);
+ LDB_DN_NULL_FAILED(newdn->components[0].name);
+
+ newdn->components[0].value.data = (uint8_t *)talloc_strdup(newdn->components, value);
+ LDB_DN_NULL_FAILED(newdn->components[0].value.data);
+ newdn->components[0].value.length = strlen((char *)newdn->components[0].value.data);
+
+ return newdn;
+
+failed:
+ talloc_free(newdn);
+ return NULL;
+
+}
+
+struct ldb_dn *ldb_dn_compose(void *mem_ctx, const struct ldb_dn *dn1, const struct ldb_dn *dn2)
+{
+ int i;
+ struct ldb_dn *newdn;
+
+ if (dn2 == NULL && dn1 == NULL) {
+ return NULL;
+ }
+
+ if (dn2 == NULL) {
+ newdn = ldb_dn_new(mem_ctx);
+ LDB_DN_NULL_FAILED(newdn);
+
+ newdn->comp_num = dn1->comp_num;
+ newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num);
+ LDB_DN_NULL_FAILED(newdn->components);
+ } else {
+ int comp_num = dn2->comp_num;
+ if (dn1 != NULL) comp_num += dn1->comp_num;
+ newdn = ldb_dn_copy_partial(mem_ctx, dn2, comp_num);
+ LDB_DN_NULL_FAILED(newdn);
+ }
+
+ if (dn1 == NULL) {
+ return newdn;
+ }
+
+ for (i = 0; i < dn1->comp_num; i++) {
+ newdn->components[i] = ldb_dn_copy_component(newdn->components,
+ &(dn1->components[i]));
+ if (newdn->components[i].value.data == NULL) {
+ goto failed;
+ }
+ }
+
+ return newdn;
+
+failed:
+ talloc_free(newdn);
+ return NULL;
+}
+
+struct ldb_dn *ldb_dn_string_compose(void *mem_ctx, const struct ldb_dn *base, const char *child_fmt, ...)
+{
+ struct ldb_dn *dn, *dn1;
+ char *child_str;
+ va_list ap;
+
+ if (child_fmt == NULL) return NULL;
+
+ va_start(ap, child_fmt);
+ child_str = talloc_vasprintf(mem_ctx, child_fmt, ap);
+ va_end(ap);
+
+ if (child_str == NULL) return NULL;
+
+ dn1 = ldb_dn_explode(mem_ctx, child_str);
+ dn = ldb_dn_compose(mem_ctx, dn1, base);
+
+ talloc_free(child_str);
+ talloc_free(dn1);
+
+ return dn;
+}
+
+/* Create a 'canonical name' string from a DN:
+
+ ie dc=samba,dc=org -> samba.org/
+ uid=administrator,ou=users,dc=samba,dc=org = samba.org/users/administrator
+
+ There are two formats, the EX format has the last / replaced with a newline (\n).
+
+*/
+static char *ldb_dn_canonical(void *mem_ctx, const struct ldb_dn *dn, int ex_format) {
+ int i;
+ char *cracked = NULL;
+
+ /* Walk backwards down the DN, grabbing 'dc' components at first */
+ for (i = dn->comp_num - 1 ; i >= 0; i--) {
+ if (ldb_attr_cmp(dn->components[i].name, "dc") != 0) {
+ break;
+ }
+ if (cracked) {
+ cracked = talloc_asprintf(mem_ctx, "%s.%s",
+ ldb_dn_escape_value(mem_ctx, dn->components[i].value),
+ cracked);
+ } else {
+ cracked = ldb_dn_escape_value(mem_ctx, dn->components[i].value);
+ }
+ if (!cracked) {
+ return NULL;
+ }
+ }
+
+ /* Only domain components? Finish here */
+ if (i < 0) {
+ if (ex_format) {
+ cracked = talloc_asprintf(mem_ctx, "%s\n", cracked);
+ } else {
+ cracked = talloc_asprintf(mem_ctx, "%s/", cracked);
+ }
+ return cracked;
+ }
+
+ /* Now walk backwards appending remaining components */
+ for (; i > 0; i--) {
+ cracked = talloc_asprintf(mem_ctx, "%s/%s", cracked,
+ ldb_dn_escape_value(mem_ctx, dn->components[i].value));
+ if (!cracked) {
+ return NULL;
+ }
+ }
+
+ /* Last one, possibly a newline for the 'ex' format */
+ if (ex_format) {
+ cracked = talloc_asprintf(mem_ctx, "%s\n%s", cracked,
+ ldb_dn_escape_value(mem_ctx, dn->components[i].value));
+ } else {
+ cracked = talloc_asprintf(mem_ctx, "%s/%s", cracked,
+ ldb_dn_escape_value(mem_ctx, dn->components[i].value));
+ }
+ return cracked;
+}
+
+/* Wrapper functions for the above, for the two different string formats */
+char *ldb_dn_canonical_string(void *mem_ctx, const struct ldb_dn *dn) {
+ return ldb_dn_canonical(mem_ctx, dn, 0);
+
+}
+
+char *ldb_dn_canonical_ex_string(void *mem_ctx, const struct ldb_dn *dn) {
+ return ldb_dn_canonical(mem_ctx, dn, 1);
+}
+
+int ldb_dn_get_comp_num(const struct ldb_dn *dn)
+{
+ return dn->comp_num;
+}
+
+const char *ldb_dn_get_component_name(const struct ldb_dn *dn, unsigned int num)
+{
+ if (num >= dn->comp_num) return NULL;
+ return dn->components[num].name;
+}
+
+const struct ldb_val *ldb_dn_get_component_val(const struct ldb_dn *dn, unsigned int num)
+{
+ if (num >= dn->comp_num) return NULL;
+ return &dn->components[num].value;
+}
+
+const char *ldb_dn_get_rdn_name(const struct ldb_dn *dn) {
+ if (dn->comp_num == 0) return NULL;
+ return dn->components[0].name;
+}
+
+const struct ldb_val *ldb_dn_get_rdn_val(const struct ldb_dn *dn) {
+ if (dn->comp_num == 0) return NULL;
+ return &dn->components[0].value;
+}
+
+int ldb_dn_set_component(struct ldb_dn *dn, int num, const char *name, const struct ldb_val val)
+{
+ char *n;
+ struct ldb_val v;
+
+ if (num >= dn->comp_num) {
+ return LDB_ERR_OTHER;
+ }
+
+ n = talloc_strdup(dn, name);
+ if ( ! n) {
+ return LDB_ERR_OTHER;
+ }
+
+ v.length = val.length;
+ v.data = (uint8_t *)talloc_memdup(dn, val.data, v.length+1);
+ if ( ! v.data) {
+ return LDB_ERR_OTHER;
+ }
+
+ talloc_free(dn->components[num].name);
+ talloc_free(dn->components[num].value.data);
+ dn->components[num].name = n;
+ dn->components[num].value = v;
+
+ return LDB_SUCCESS;
+}
diff --git a/source3/lib/ldb/common/ldb_ldif.c b/source3/lib/ldb/common/ldb_ldif.c
new file mode 100644
index 0000000000..a6ed1b6055
--- /dev/null
+++ b/source3/lib/ldb/common/ldb_ldif.c
@@ -0,0 +1,760 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldif routines
+ *
+ * Description: ldif pack/unpack routines
+ *
+ * Author: Andrew Tridgell
+ */
+
+/*
+ see RFC2849 for the LDIF format definition
+*/
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+#include "system/locale.h"
+
+/*
+
+*/
+static int ldb_read_data_file(void *mem_ctx, struct ldb_val *value)
+{
+ struct stat statbuf;
+ char *buf;
+ int count, size, bytes;
+ int ret;
+ int f;
+ const char *fname = (const char *)value->data;
+
+ if (strncmp(fname, "file://", 7) != 0) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ fname += 7;
+
+ f = open(fname, O_RDONLY);
+ if (f == -1) {
+ return -1;
+ }
+
+ if (fstat(f, &statbuf) != 0) {
+ ret = -1;
+ goto done;
+ }
+
+ if (statbuf.st_size == 0) {
+ ret = -1;
+ goto done;
+ }
+
+ value->data = (uint8_t *)talloc_size(mem_ctx, statbuf.st_size + 1);
+ if (value->data == NULL) {
+ ret = -1;
+ goto done;
+ }
+ value->data[statbuf.st_size] = 0;
+
+ count = 0;
+ size = statbuf.st_size;
+ buf = (char *)value->data;
+ while (count < statbuf.st_size) {
+ bytes = read(f, buf, size);
+ if (bytes == -1) {
+ talloc_free(value->data);
+ ret = -1;
+ goto done;
+ }
+ count += bytes;
+ buf += bytes;
+ size -= bytes;
+ }
+
+ value->length = statbuf.st_size;
+ ret = statbuf.st_size;
+
+done:
+ close(f);
+ return ret;
+}
+
+/*
+ this base64 decoder was taken from jitterbug (written by tridge).
+ we might need to replace it with a new version
+*/
+int ldb_base64_decode(char *s)
+{
+ const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ int bit_offset=0, byte_offset, idx, i, n;
+ uint8_t *d = (uint8_t *)s;
+ char *p=NULL;
+
+ 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++;
+ }
+ if (bit_offset >= 3) {
+ n--;
+ }
+
+ if (*s && !p) {
+ /* the only termination allowed */
+ if (*s != '=') {
+ return -1;
+ }
+ }
+
+ /* null terminate */
+ d[n] = 0;
+ return n;
+}
+
+
+/*
+ encode as base64
+ caller frees
+*/
+char *ldb_base64_encode(void *mem_ctx, const char *buf, int len)
+{
+ const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ int bit_offset, byte_offset, idx, i;
+ const uint8_t *d = (const uint8_t *)buf;
+ int bytes = (len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
+ char *out;
+
+ out = talloc_array(mem_ctx, char, bytes+pad_bytes+1);
+ if (!out) return NULL;
+
+ for (i=0;i<bytes;i++) {
+ byte_offset = (i*6)/8;
+ bit_offset = (i*6)%8;
+ if (bit_offset < 3) {
+ idx = (d[byte_offset] >> (2-bit_offset)) & 0x3F;
+ } else {
+ idx = (d[byte_offset] << (bit_offset-2)) & 0x3F;
+ if (byte_offset+1 < len) {
+ idx |= (d[byte_offset+1] >> (8-(bit_offset-2)));
+ }
+ }
+ out[i] = b64[idx];
+ }
+
+ for (;i<bytes+pad_bytes;i++)
+ out[i] = '=';
+ out[i] = 0;
+
+ return out;
+}
+
+/*
+ see if a buffer should be base64 encoded
+*/
+int ldb_should_b64_encode(const struct ldb_val *val)
+{
+ unsigned int i;
+ uint8_t *p = val->data;
+
+ if (val->length == 0) {
+ return 0;
+ }
+
+ if (p[0] == ' ' || p[0] == ':') {
+ return 1;
+ }
+
+ for (i=0; i<val->length; i++) {
+ if (!isprint(p[i]) || p[i] == '\n') {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* this macro is used to handle the return checking on fprintf_fn() */
+#define CHECK_RET do { if (ret < 0) return ret; total += ret; } while (0)
+
+/*
+ write a line folded string onto a file
+*/
+static int fold_string(int (*fprintf_fn)(void *, const char *, ...), void *private_data,
+ const char *buf, size_t length, int start_pos)
+{
+ unsigned int i;
+ int total=0, ret;
+
+ for (i=0;i<length;i++) {
+ ret = fprintf_fn(private_data, "%c", buf[i]);
+ CHECK_RET;
+ if (i != (length-1) && (i + start_pos) % 77 == 0) {
+ ret = fprintf_fn(private_data, "\n ");
+ CHECK_RET;
+ }
+ }
+
+ return total;
+}
+
+#undef CHECK_RET
+
+/*
+ encode as base64 to a file
+*/
+static int base64_encode_f(struct ldb_context *ldb,
+ int (*fprintf_fn)(void *, const char *, ...),
+ void *private_data,
+ const char *buf, int len, int start_pos)
+{
+ char *b = ldb_base64_encode(ldb, buf, len);
+ int ret;
+
+ if (!b) {
+ return -1;
+ }
+
+ ret = fold_string(fprintf_fn, private_data, b, strlen(b), start_pos);
+
+ talloc_free(b);
+ return ret;
+}
+
+
+static const struct {
+ const char *name;
+ enum ldb_changetype changetype;
+} ldb_changetypes[] = {
+ {"add", LDB_CHANGETYPE_ADD},
+ {"delete", LDB_CHANGETYPE_DELETE},
+ {"modify", LDB_CHANGETYPE_MODIFY},
+ {NULL, 0}
+};
+
+/* this macro is used to handle the return checking on fprintf_fn() */
+#define CHECK_RET do { if (ret < 0) { talloc_free(mem_ctx); return ret; } total += ret; } while (0)
+
+/*
+ write to ldif, using a caller supplied write method
+*/
+int ldb_ldif_write(struct ldb_context *ldb,
+ int (*fprintf_fn)(void *, const char *, ...),
+ void *private_data,
+ const struct ldb_ldif *ldif)
+{
+ TALLOC_CTX *mem_ctx;
+ unsigned int i, j;
+ int total=0, ret;
+ const struct ldb_message *msg;
+
+ mem_ctx = talloc_named_const(NULL, 0, "ldb_ldif_write");
+
+ msg = ldif->msg;
+
+ ret = fprintf_fn(private_data, "dn: %s\n", ldb_dn_linearize(msg->dn, msg->dn));
+ CHECK_RET;
+
+ if (ldif->changetype != LDB_CHANGETYPE_NONE) {
+ for (i=0;ldb_changetypes[i].name;i++) {
+ if (ldb_changetypes[i].changetype == ldif->changetype) {
+ break;
+ }
+ }
+ if (!ldb_changetypes[i].name) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: Invalid ldif changetype %d\n",
+ ldif->changetype);
+ talloc_free(mem_ctx);
+ return -1;
+ }
+ ret = fprintf_fn(private_data, "changetype: %s\n", ldb_changetypes[i].name);
+ CHECK_RET;
+ }
+
+ for (i=0;i<msg->num_elements;i++) {
+ const struct ldb_attrib_handler *h;
+
+ h = ldb_attrib_handler(ldb, msg->elements[i].name);
+
+ if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
+ switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
+ case LDB_FLAG_MOD_ADD:
+ fprintf_fn(private_data, "add: %s\n",
+ msg->elements[i].name);
+ break;
+ case LDB_FLAG_MOD_DELETE:
+ fprintf_fn(private_data, "delete: %s\n",
+ msg->elements[i].name);
+ break;
+ case LDB_FLAG_MOD_REPLACE:
+ fprintf_fn(private_data, "replace: %s\n",
+ msg->elements[i].name);
+ break;
+ }
+ }
+
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ struct ldb_val v;
+ ret = h->ldif_write_fn(ldb, mem_ctx, &msg->elements[i].values[j], &v);
+ CHECK_RET;
+ if (ldb_should_b64_encode(&v)) {
+ ret = fprintf_fn(private_data, "%s:: ",
+ msg->elements[i].name);
+ CHECK_RET;
+ ret = base64_encode_f(ldb, fprintf_fn, private_data,
+ (char *)v.data, v.length,
+ strlen(msg->elements[i].name)+3);
+ CHECK_RET;
+ ret = fprintf_fn(private_data, "\n");
+ CHECK_RET;
+ } else {
+ ret = fprintf_fn(private_data, "%s: ", msg->elements[i].name);
+ CHECK_RET;
+ ret = fold_string(fprintf_fn, private_data,
+ (char *)v.data, v.length,
+ strlen(msg->elements[i].name)+2);
+ CHECK_RET;
+ ret = fprintf_fn(private_data, "\n");
+ CHECK_RET;
+ }
+ if (v.data != msg->elements[i].values[j].data) {
+ talloc_free(v.data);
+ }
+ }
+ if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
+ fprintf_fn(private_data, "-\n");
+ }
+ }
+ ret = fprintf_fn(private_data,"\n");
+ CHECK_RET;
+
+ return total;
+}
+
+#undef CHECK_RET
+
+
+/*
+ pull a ldif chunk, which is defined as a piece of data ending in \n\n or EOF
+ this routine removes any RFC2849 continuations and comments
+
+ caller frees
+*/
+static char *next_chunk(struct ldb_context *ldb,
+ int (*fgetc_fn)(void *), void *private_data)
+{
+ size_t alloc_size=0, chunk_size = 0;
+ char *chunk = NULL;
+ int c;
+ int in_comment = 0;
+
+ while ((c = fgetc_fn(private_data)) != EOF) {
+ if (chunk_size+1 >= alloc_size) {
+ char *c2;
+ alloc_size += 1024;
+ c2 = talloc_realloc(ldb, chunk, char, alloc_size);
+ if (!c2) {
+ talloc_free(chunk);
+ errno = ENOMEM;
+ return NULL;
+ }
+ chunk = c2;
+ }
+
+ if (in_comment) {
+ if (c == '\n') {
+ in_comment = 0;
+ }
+ continue;
+ }
+
+ /* handle continuation lines - see RFC2849 */
+ if (c == ' ' && chunk_size > 1 && chunk[chunk_size-1] == '\n') {
+ chunk_size--;
+ continue;
+ }
+
+ /* chunks are terminated by a double line-feed */
+ if (c == '\n' && chunk_size > 0 && chunk[chunk_size-1] == '\n') {
+ chunk[chunk_size-1] = 0;
+ return chunk;
+ }
+
+ if (c == '#' && (chunk_size == 0 || chunk[chunk_size-1] == '\n')) {
+ in_comment = 1;
+ continue;
+ }
+
+ /* ignore leading blank lines */
+ if (chunk_size == 0 && c == '\n') {
+ continue;
+ }
+
+ chunk[chunk_size++] = c;
+ }
+
+ if (chunk) {
+ chunk[chunk_size] = 0;
+ }
+
+ return chunk;
+}
+
+
+/* simple ldif attribute parser */
+static int next_attr(void *mem_ctx, char **s, const char **attr, struct ldb_val *value)
+{
+ char *p;
+ int base64_encoded = 0;
+ int binary_file = 0;
+
+ if (strncmp(*s, "-\n", 2) == 0) {
+ value->length = 0;
+ *attr = "-";
+ *s += 2;
+ return 0;
+ }
+
+ p = strchr(*s, ':');
+ if (!p) {
+ return -1;
+ }
+
+ *p++ = 0;
+
+ if (*p == ':') {
+ base64_encoded = 1;
+ p++;
+ }
+
+ if (*p == '<') {
+ binary_file = 1;
+ p++;
+ }
+
+ *attr = *s;
+
+ while (*p == ' ' || *p == '\t') {
+ p++;
+ }
+
+ value->data = (uint8_t *)p;
+
+ p = strchr(p, '\n');
+
+ if (!p) {
+ value->length = strlen((char *)value->data);
+ *s = ((char *)value->data) + value->length;
+ } else {
+ value->length = p - (char *)value->data;
+ *s = p+1;
+ *p = 0;
+ }
+
+ if (base64_encoded) {
+ int len = ldb_base64_decode((char *)value->data);
+ if (len == -1) {
+ /* it wasn't valid base64 data */
+ return -1;
+ }
+ value->length = len;
+ }
+
+ if (binary_file) {
+ int len = ldb_read_data_file(mem_ctx, value);
+ if (len == -1) {
+ /* an error occured hile trying to retrieve the file */
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ free a message from a ldif_read
+*/
+void ldb_ldif_read_free(struct ldb_context *ldb, struct ldb_ldif *ldif)
+{
+ talloc_free(ldif);
+}
+
+/*
+ read from a LDIF source, creating a ldb_message
+*/
+struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
+ int (*fgetc_fn)(void *), void *private_data)
+{
+ struct ldb_ldif *ldif;
+ struct ldb_message *msg;
+ const char *attr=NULL;
+ char *chunk=NULL, *s;
+ struct ldb_val value;
+ unsigned flags = 0;
+
+ value.data = NULL;
+
+ ldif = talloc(ldb, struct ldb_ldif);
+ if (!ldif) return NULL;
+
+ ldif->msg = talloc(ldif, struct ldb_message);
+ if (ldif->msg == NULL) {
+ talloc_free(ldif);
+ return NULL;
+ }
+
+ ldif->changetype = LDB_CHANGETYPE_NONE;
+ msg = ldif->msg;
+
+ msg->dn = NULL;
+ msg->elements = NULL;
+ msg->num_elements = 0;
+ msg->private_data = NULL;
+
+ chunk = next_chunk(ldb, fgetc_fn, private_data);
+ if (!chunk) {
+ goto failed;
+ }
+ talloc_steal(ldif, chunk);
+
+ msg->private_data = chunk;
+ s = chunk;
+
+ if (next_attr(ldif, &s, &attr, &value) != 0) {
+ goto failed;
+ }
+
+ /* first line must be a dn */
+ if (ldb_attr_cmp(attr, "dn") != 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: First line of ldif must be a dn not '%s'\n",
+ attr);
+ goto failed;
+ }
+
+ msg->dn = ldb_dn_explode(msg, (char *)value.data);
+
+ if (msg->dn == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: Unable to parse dn '%s'\n",
+ value.data);
+ goto failed;
+ }
+
+ while (next_attr(ldif, &s, &attr, &value) == 0) {
+ const struct ldb_attrib_handler *h;
+ struct ldb_message_element *el;
+ int ret, empty = 0;
+
+ if (ldb_attr_cmp(attr, "changetype") == 0) {
+ int i;
+ for (i=0;ldb_changetypes[i].name;i++) {
+ if (ldb_attr_cmp((char *)value.data, ldb_changetypes[i].name) == 0) {
+ ldif->changetype = ldb_changetypes[i].changetype;
+ break;
+ }
+ }
+ if (!ldb_changetypes[i].name) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: Bad ldif changetype '%s'\n",(char *)value.data);
+ }
+ flags = 0;
+ continue;
+ }
+
+ if (ldb_attr_cmp(attr, "add") == 0) {
+ flags = LDB_FLAG_MOD_ADD;
+ empty = 1;
+ }
+ if (ldb_attr_cmp(attr, "delete") == 0) {
+ flags = LDB_FLAG_MOD_DELETE;
+ empty = 1;
+ }
+ if (ldb_attr_cmp(attr, "replace") == 0) {
+ flags = LDB_FLAG_MOD_REPLACE;
+ empty = 1;
+ }
+ if (ldb_attr_cmp(attr, "-") == 0) {
+ flags = 0;
+ continue;
+ }
+
+ if (empty) {
+ if (ldb_msg_add_empty(msg, (char *)value.data, flags, NULL) != 0) {
+ goto failed;
+ }
+ continue;
+ }
+
+ el = &msg->elements[msg->num_elements-1];
+
+ h = ldb_attrib_handler(ldb, attr);
+
+ if (msg->num_elements > 0 && ldb_attr_cmp(attr, el->name) == 0 &&
+ flags == el->flags) {
+ /* its a continuation */
+ el->values =
+ talloc_realloc(msg->elements, el->values,
+ struct ldb_val, el->num_values+1);
+ if (!el->values) {
+ goto failed;
+ }
+ ret = h->ldif_read_fn(ldb, ldif, &value, &el->values[el->num_values]);
+ if (ret != 0) {
+ goto failed;
+ }
+ if (value.length == 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: Attribute value cannot be empty for attribute '%s'\n", el->name);
+ goto failed;
+ }
+ if (value.data != el->values[el->num_values].data) {
+ talloc_steal(el->values, el->values[el->num_values].data);
+ }
+ el->num_values++;
+ } else {
+ /* its a new attribute */
+ msg->elements = talloc_realloc(ldif, msg->elements,
+ struct ldb_message_element,
+ msg->num_elements+1);
+ if (!msg->elements) {
+ goto failed;
+ }
+ el = &msg->elements[msg->num_elements];
+ el->flags = flags;
+ el->name = talloc_strdup(msg->elements, attr);
+ el->values = talloc(msg->elements, struct ldb_val);
+ if (!el->values || !el->name) {
+ goto failed;
+ }
+ el->num_values = 1;
+ ret = h->ldif_read_fn(ldb, ldif, &value, &el->values[0]);
+ if (ret != 0) {
+ goto failed;
+ }
+ if (value.data != el->values[0].data) {
+ talloc_steal(el->values, el->values[0].data);
+ }
+ msg->num_elements++;
+ }
+ }
+
+ return ldif;
+
+failed:
+ talloc_free(ldif);
+ return NULL;
+}
+
+
+
+/*
+ a wrapper around ldif_read() for reading from FILE*
+*/
+struct ldif_read_file_state {
+ FILE *f;
+};
+
+static int fgetc_file(void *private_data)
+{
+ struct ldif_read_file_state *state =
+ (struct ldif_read_file_state *)private_data;
+ return fgetc(state->f);
+}
+
+struct ldb_ldif *ldb_ldif_read_file(struct ldb_context *ldb, FILE *f)
+{
+ struct ldif_read_file_state state;
+ state.f = f;
+ return ldb_ldif_read(ldb, fgetc_file, &state);
+}
+
+
+/*
+ a wrapper around ldif_read() for reading from const char*
+*/
+struct ldif_read_string_state {
+ const char *s;
+};
+
+static int fgetc_string(void *private_data)
+{
+ struct ldif_read_string_state *state =
+ (struct ldif_read_string_state *)private_data;
+ if (state->s[0] != 0) {
+ return *state->s++;
+ }
+ return EOF;
+}
+
+struct ldb_ldif *ldb_ldif_read_string(struct ldb_context *ldb, const char **s)
+{
+ struct ldif_read_string_state state;
+ struct ldb_ldif *ldif;
+ state.s = *s;
+ ldif = ldb_ldif_read(ldb, fgetc_string, &state);
+ *s = state.s;
+ return ldif;
+}
+
+
+/*
+ wrapper around ldif_write() for a file
+*/
+struct ldif_write_file_state {
+ FILE *f;
+};
+
+static int fprintf_file(void *private_data, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
+
+static int fprintf_file(void *private_data, const char *fmt, ...)
+{
+ struct ldif_write_file_state *state =
+ (struct ldif_write_file_state *)private_data;
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfprintf(state->f, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+int ldb_ldif_write_file(struct ldb_context *ldb, FILE *f, const struct ldb_ldif *ldif)
+{
+ struct ldif_write_file_state state;
+ state.f = f;
+ return ldb_ldif_write(ldb, fprintf_file, &state, ldif);
+}
diff --git a/source3/lib/ldb/common/ldb_match.c b/source3/lib/ldb/common/ldb_match.c
new file mode 100644
index 0000000000..066c997cee
--- /dev/null
+++ b/source3/lib/ldb/common/ldb_match.c
@@ -0,0 +1,430 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004-2005
+ Copyright (C) Simo Sorce 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb expression matching
+ *
+ * Description: ldb expression matching
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+/*
+ check if the scope matches in a search result
+*/
+static int ldb_match_scope(struct ldb_context *ldb,
+ const struct ldb_dn *base,
+ const struct ldb_dn *dn,
+ enum ldb_scope scope)
+{
+ int ret = 0;
+
+ if (base == NULL || dn == NULL) {
+ return 1;
+ }
+
+ switch (scope) {
+ case LDB_SCOPE_BASE:
+ if (ldb_dn_compare(ldb, base, dn) == 0) {
+ ret = 1;
+ }
+ break;
+
+ case LDB_SCOPE_ONELEVEL:
+ if (ldb_dn_get_comp_num(dn) == (ldb_dn_get_comp_num(base) + 1)) {
+ if (ldb_dn_compare_base(ldb, base, dn) == 0) {
+ ret = 1;
+ }
+ }
+ break;
+
+ case LDB_SCOPE_SUBTREE:
+ default:
+ if (ldb_dn_compare_base(ldb, base, dn) == 0) {
+ ret = 1;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+
+/*
+ match if node is present
+*/
+static int ldb_match_present(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ enum ldb_scope scope)
+{
+ if (ldb_attr_dn(tree->u.present.attr) == 0) {
+ return 1;
+ }
+
+ if (ldb_msg_find_element(msg, tree->u.present.attr)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int ldb_match_comparison(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ enum ldb_scope scope,
+ enum ldb_parse_op comp_op)
+{
+ unsigned int i;
+ struct ldb_message_element *el;
+ const struct ldb_attrib_handler *h;
+ int ret;
+
+ /* FIXME: APPROX comparison not handled yet */
+ if (comp_op == LDB_OP_APPROX) return 0;
+
+ el = ldb_msg_find_element(msg, tree->u.comparison.attr);
+ if (el == NULL) {
+ return 0;
+ }
+
+ h = ldb_attrib_handler(ldb, el->name);
+
+ for (i = 0; i < el->num_values; i++) {
+ ret = h->comparison_fn(ldb, ldb, &el->values[i], &tree->u.comparison.value);
+
+ if (ret == 0) {
+ return 1;
+ }
+ if (ret > 0 && comp_op == LDB_OP_GREATER) {
+ return 1;
+ }
+ if (ret < 0 && comp_op == LDB_OP_LESS) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ match a simple leaf node
+*/
+static int ldb_match_equality(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ enum ldb_scope scope)
+{
+ unsigned int i;
+ struct ldb_message_element *el;
+ const struct ldb_attrib_handler *h;
+ struct ldb_dn *valuedn;
+ int ret;
+
+ if (ldb_attr_dn(tree->u.equality.attr) == 0) {
+ valuedn = ldb_dn_explode_casefold(ldb, ldb,
+ (char *)tree->u.equality.value.data);
+ if (valuedn == NULL) {
+ return 0;
+ }
+
+ ret = ldb_dn_compare(ldb, msg->dn, valuedn);
+
+ talloc_free(valuedn);
+
+ if (ret == 0) return 1;
+ return 0;
+ }
+
+ /* TODO: handle the "*" case derived from an extended search
+ operation without the attibute type defined */
+ el = ldb_msg_find_element(msg, tree->u.equality.attr);
+ if (el == NULL) {
+ return 0;
+ }
+
+ h = ldb_attrib_handler(ldb, el->name);
+
+ for (i=0;i<el->num_values;i++) {
+ if (h->comparison_fn(ldb, ldb, &tree->u.equality.value,
+ &el->values[i]) == 0) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int ldb_wildcard_compare(struct ldb_context *ldb,
+ const struct ldb_parse_tree *tree,
+ const struct ldb_val value)
+{
+ const struct ldb_attrib_handler *h;
+ struct ldb_val val;
+ struct ldb_val cnk;
+ struct ldb_val *chunk;
+ char *p, *g;
+ uint8_t *save_p = NULL;
+ int c = 0;
+
+ h = ldb_attrib_handler(ldb, tree->u.substring.attr);
+
+ if(h->canonicalise_fn(ldb, ldb, &value, &val) != 0)
+ return -1;
+
+ save_p = val.data;
+ cnk.data = NULL;
+
+ if ( ! tree->u.substring.start_with_wildcard ) {
+
+ chunk = tree->u.substring.chunks[c];
+ if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
+
+ /* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */
+ if (cnk.length > val.length) {
+ goto failed;
+ }
+ if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) goto failed;
+ val.length -= cnk.length;
+ val.data += cnk.length;
+ c++;
+ talloc_free(cnk.data);
+ cnk.data = NULL;
+ }
+
+ while (tree->u.substring.chunks[c]) {
+
+ chunk = tree->u.substring.chunks[c];
+ if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
+
+ /* FIXME: case of embedded nulls */
+ p = strstr((char *)val.data, (char *)cnk.data);
+ if (p == NULL) goto failed;
+ if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) {
+ do { /* greedy */
+ g = strstr((char *)p + cnk.length, (char *)cnk.data);
+ if (g) p = g;
+ } while(g);
+ }
+ val.length = val.length - (p - (char *)(val.data)) - cnk.length;
+ val.data = (uint8_t *)(p + cnk.length);
+ c++;
+ talloc_free(cnk.data);
+ cnk.data = NULL;
+ }
+
+ if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto failed; /* last chunk have not reached end of string */
+ talloc_free(save_p);
+ return 1;
+
+failed:
+ talloc_free(save_p);
+ talloc_free(cnk.data);
+ return 0;
+}
+
+/*
+ match a simple leaf node
+*/
+static int ldb_match_substring(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ enum ldb_scope scope)
+{
+ unsigned int i;
+ struct ldb_message_element *el;
+
+ el = ldb_msg_find_element(msg, tree->u.substring.attr);
+ if (el == NULL) {
+ return 0;
+ }
+
+ for (i = 0; i < el->num_values; i++) {
+ if (ldb_wildcard_compare(ldb, tree, el->values[i]) == 1) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ bitwise-and comparator
+*/
+static int ldb_comparator_and(const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ uint64_t i1, i2;
+ i1 = strtoull((char *)v1->data, NULL, 0);
+ i2 = strtoull((char *)v2->data, NULL, 0);
+ return ((i1 & i2) == i2);
+}
+
+/*
+ bitwise-or comparator
+*/
+static int ldb_comparator_or(const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ uint64_t i1, i2;
+ i1 = strtoull((char *)v1->data, NULL, 0);
+ i2 = strtoull((char *)v2->data, NULL, 0);
+ return ((i1 & i2) != 0);
+}
+
+
+/*
+ extended match, handles things like bitops
+*/
+static int ldb_match_extended(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ enum ldb_scope scope)
+{
+ int i;
+ const struct {
+ const char *oid;
+ int (*comparator)(const struct ldb_val *, const struct ldb_val *);
+ } rules[] = {
+ { LDB_OID_COMPARATOR_AND, ldb_comparator_and},
+ { LDB_OID_COMPARATOR_OR, ldb_comparator_or}
+ };
+ int (*comp)(const struct ldb_val *, const struct ldb_val *) = NULL;
+ struct ldb_message_element *el;
+
+ if (tree->u.extended.dnAttributes) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: dnAttributes extended match not supported yet");
+ return -1;
+ }
+ if (tree->u.extended.rule_id == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet");
+ return -1;
+ }
+ if (tree->u.extended.attr == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet");
+ return -1;
+ }
+
+ for (i=0;i<ARRAY_SIZE(rules);i++) {
+ if (strcmp(rules[i].oid, tree->u.extended.rule_id) == 0) {
+ comp = rules[i].comparator;
+ break;
+ }
+ }
+ if (comp == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s\n",
+ tree->u.extended.rule_id);
+ return -1;
+ }
+
+ /* find the message element */
+ el = ldb_msg_find_element(msg, tree->u.extended.attr);
+ if (el == NULL) {
+ return 0;
+ }
+
+ for (i=0;i<el->num_values;i++) {
+ int ret = comp(&el->values[i], &tree->u.extended.value);
+ if (ret == -1 || ret == 1) return ret;
+ }
+
+ return 0;
+}
+
+/*
+ return 0 if the given parse tree matches the given message. Assumes
+ the message is in sorted order
+
+ return 1 if it matches, and 0 if it doesn't match
+
+ this is a recursive function, and does short-circuit evaluation
+ */
+static int ldb_match_message(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ enum ldb_scope scope)
+{
+ unsigned int i;
+ int v;
+
+ switch (tree->operation) {
+ case LDB_OP_AND:
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope);
+ if (!v) return 0;
+ }
+ return 1;
+
+ case LDB_OP_OR:
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope);
+ if (v) return 1;
+ }
+ return 0;
+
+ case LDB_OP_NOT:
+ return ! ldb_match_message(ldb, msg, tree->u.isnot.child, scope);
+
+ case LDB_OP_EQUALITY:
+ return ldb_match_equality(ldb, msg, tree, scope);
+
+ case LDB_OP_SUBSTRING:
+ return ldb_match_substring(ldb, msg, tree, scope);
+
+ case LDB_OP_GREATER:
+ return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER);
+
+ case LDB_OP_LESS:
+ return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS);
+
+ case LDB_OP_PRESENT:
+ return ldb_match_present(ldb, msg, tree, scope);
+
+ case LDB_OP_APPROX:
+ return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX);
+
+ case LDB_OP_EXTENDED:
+ return ldb_match_extended(ldb, msg, tree, scope);
+
+ }
+
+ return 0;
+}
+
+int ldb_match_msg(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ const struct ldb_dn *base,
+ enum ldb_scope scope)
+{
+ if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) {
+ return 0;
+ }
+
+ return ldb_match_message(ldb, msg, tree, scope);
+}
diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c
new file mode 100644
index 0000000000..fa7f685d97
--- /dev/null
+++ b/source3/lib/ldb/common/ldb_modules.c
@@ -0,0 +1,459 @@
+
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb modules core
+ *
+ * Description: core modules routines
+ *
+ * Author: Simo Sorce
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#if (_SAMBA_BUILD_ >= 4)
+#include "build.h"
+#include "dynconfig.h"
+#endif
+
+#define LDB_MODULE_PREFIX "modules:"
+#define LDB_MODULE_PREFIX_LEN 8
+
+static char *ldb_modules_strdup_no_spaces(TALLOC_CTX *mem_ctx, const char *string)
+{
+ int i, len;
+ char *trimmed;
+
+ trimmed = talloc_strdup(mem_ctx, string);
+ if (!trimmed) {
+ return NULL;
+ }
+
+ len = strlen(trimmed);
+ for (i = 0; trimmed[i] != '\0'; i++) {
+ switch (trimmed[i]) {
+ case ' ':
+ case '\t':
+ case '\n':
+ memmove(&trimmed[i], &trimmed[i + 1], len -i -1);
+ break;
+ }
+ }
+
+ return trimmed;
+}
+
+
+/* modules are called in inverse order on the stack.
+ Lets place them as an admin would think the right order is.
+ Modules order is important */
+const char **ldb_modules_list_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *string)
+{
+ char **modules = NULL;
+ const char **m;
+ char *modstr, *p;
+ int i;
+
+ /* spaces not admitted */
+ modstr = ldb_modules_strdup_no_spaces(mem_ctx, string);
+ if ( ! modstr) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_strdup_no_spaces()\n");
+ return NULL;
+ }
+
+ modules = talloc_realloc(mem_ctx, modules, char *, 2);
+ if ( ! modules ) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_list_from_string()\n");
+ talloc_free(modstr);
+ return NULL;
+ }
+ talloc_steal(modules, modstr);
+
+ i = 0;
+ /* The str*r*chr walks backwards: This is how we get the inverse order mentioned above */
+ while ((p = strrchr(modstr, ',')) != NULL) {
+ *p = '\0';
+ p++;
+ modules[i] = p;
+
+ i++;
+ modules = talloc_realloc(mem_ctx, modules, char *, i + 2);
+ if ( ! modules ) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_list_from_string()\n");
+ return NULL;
+ }
+
+ }
+ modules[i] = modstr;
+
+ modules[i + 1] = NULL;
+
+ m = (const char **)modules;
+
+ return m;
+}
+
+static struct ops_list_entry {
+ const struct ldb_module_ops *ops;
+ struct ops_list_entry *next;
+} *registered_modules = NULL;
+
+static const struct ldb_module_ops *ldb_find_module_ops(const char *name)
+{
+ struct ops_list_entry *e;
+
+ for (e = registered_modules; e; e = e->next) {
+ if (strcmp(e->ops->name, name) == 0)
+ return e->ops;
+ }
+
+ return NULL;
+}
+
+#ifndef STATIC_ldb_MODULES
+
+#ifdef HAVE_LDB_LDAP
+#define LDAP_INIT ldb_ldap_init,
+#else
+#define LDAP_INIT
+#endif
+
+#ifdef HAVE_LDB_SQLITE3
+#define SQLITE3_INIT ldb_sqlite3_init,
+#else
+#define SQLITE3_INIT
+#endif
+
+#define STATIC_ldb_MODULES \
+ { \
+ LDAP_INIT \
+ SQLITE3_INIT \
+ ldb_tdb_init, \
+ ldb_operational_init, \
+ ldb_rdn_name_init, \
+ ldb_objectclass_init, \
+ ldb_paged_results_init, \
+ ldb_sort_init, \
+ ldb_asq_init, \
+ NULL \
+ }
+#endif
+
+int ldb_global_init(void)
+{
+ static int (*static_init_fns[])(void) = STATIC_ldb_MODULES;
+
+ static int initialized = 0;
+ int ret = 0, i;
+
+ if (initialized)
+ return 0;
+
+ initialized = 1;
+
+ for (i = 0; static_init_fns[i]; i++) {
+ if (static_init_fns[i]() == -1)
+ ret = -1;
+ }
+
+ return ret;
+}
+
+int ldb_register_module(const struct ldb_module_ops *ops)
+{
+ struct ops_list_entry *entry = talloc(talloc_autofree_context(), struct ops_list_entry);
+
+ if (ldb_find_module_ops(ops->name) != NULL)
+ return -1;
+
+ if (entry == NULL)
+ return -1;
+
+ entry->ops = ops;
+ entry->next = registered_modules;
+ registered_modules = entry;
+
+ return 0;
+}
+
+int ldb_try_load_dso(struct ldb_context *ldb, const char *name)
+{
+ char *path;
+ void *handle;
+ int (*init_fn) (void);
+ char *modulesdir;
+ int ret;
+
+#ifdef HAVE_DLOPEN
+ if (getenv("LD_LDB_MODULE_PATH") != NULL) {
+ modulesdir = talloc_strdup(ldb, getenv("LD_LDB_MODULE_PATH"));
+ } else {
+#ifdef _SAMBA_BUILD_
+ modulesdir = talloc_asprintf(ldb, "%s/ldb", get_dyn_LIBDIR());
+#else
+ modulesdir = talloc_strdup(ldb, MODULESDIR);
+#endif
+ }
+
+ path = talloc_asprintf(ldb, "%s/%s.%s", modulesdir, name, SHLIBEXT);
+
+ talloc_free(modulesdir);
+
+ ldb_debug(ldb, LDB_DEBUG_TRACE, "trying to load %s from %s\n", name, path);
+
+ handle = dlopen(path, RTLD_NOW);
+ if (handle == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING, "unable to load %s from %s: %s\n", name, path, dlerror());
+ return -1;
+ }
+
+ init_fn = (int (*)(void))dlsym(handle, "init_samba_module");
+
+ if (init_fn == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "no symbol "
+ "`init_samba_module' found in %s: %s\n", path,
+ dlerror());
+ dlclose(handle);
+ return -1;
+ }
+
+ talloc_free(path);
+
+ ret = init_fn();
+ if (ret == -1) {
+ dlclose(handle);
+ }
+ return ret;
+#else
+ ldb_debug(ldb, LDB_DEBUG_TRACE, "no dlopen() - not trying to load %s module\n", name);
+ return -1;
+#endif
+}
+
+int ldb_load_modules_list(struct ldb_context *ldb, const char **module_list, struct ldb_module *backend, struct ldb_module **out)
+{
+ struct ldb_module *module;
+ int i;
+
+ module = backend;
+
+ for (i = 0; module_list[i] != NULL; i++) {
+ struct ldb_module *current;
+ const struct ldb_module_ops *ops;
+
+ ops = ldb_find_module_ops(module_list[i]);
+ if (ops == NULL) {
+ if (ldb_try_load_dso(ldb, module_list[i]) == 0) {
+ ops = ldb_find_module_ops(module_list[i]);
+ }
+ }
+
+ if (ops == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING, "WARNING: Module [%s] not found\n",
+ module_list[i]);
+ continue;
+ }
+
+ current = talloc_zero(ldb, struct ldb_module);
+ if (current == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ talloc_set_name(current, "ldb_module: %s", module_list[i]);
+
+ current->ldb = ldb;
+ current->ops = ops;
+
+ DLIST_ADD(module, current);
+ }
+ *out = module;
+ return LDB_SUCCESS;
+}
+
+int ldb_init_module_chain(struct ldb_context *ldb, struct ldb_module *module)
+{
+ while (module && module->ops->init_context == NULL)
+ module = module->next;
+
+ if (module && module->ops->init_context &&
+ module->ops->init_context(module) != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "module initialization failed\n");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return LDB_SUCCESS;
+}
+
+int ldb_load_modules(struct ldb_context *ldb, const char *options[])
+{
+ const char **modules = NULL;
+ int i;
+ int ret;
+ TALLOC_CTX *mem_ctx = talloc_new(ldb);
+ if (!mem_ctx) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* find out which modules we are requested to activate */
+
+ /* check if we have a custom module list passd as ldb option */
+ if (options) {
+ for (i = 0; options[i] != NULL; i++) {
+ if (strncmp(options[i], LDB_MODULE_PREFIX, LDB_MODULE_PREFIX_LEN) == 0) {
+ modules = ldb_modules_list_from_string(ldb, mem_ctx, &options[i][LDB_MODULE_PREFIX_LEN]);
+ }
+ }
+ }
+
+ /* if not overloaded by options and the backend is not ldap try to load the modules list from ldb */
+ if ((modules == NULL) && (strcmp("ldap", ldb->modules->ops->name) != 0)) {
+ const char * const attrs[] = { "@LIST" , NULL};
+ struct ldb_result *res = NULL;
+ struct ldb_dn *mods_dn;
+
+ mods_dn = ldb_dn_explode(mem_ctx, "@MODULES");
+ if (mods_dn == NULL) {
+ talloc_free(mem_ctx);
+ return -1;
+ }
+
+ ret = ldb_search(ldb, mods_dn, LDB_SCOPE_BASE, "", attrs, &res);
+ talloc_steal(mods_dn, res);
+ if (ret == LDB_SUCCESS && (res->count == 0 || res->msgs[0]->num_elements == 0)) {
+ ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db\n");
+ } else {
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "ldb error (%s) occurred searching for modules, bailing out\n", ldb_errstring(ldb));
+ talloc_free(mem_ctx);
+ return -1;
+ }
+ if (res->count > 1) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "Too many records found (%d), bailing out\n", res->count);
+ talloc_free(mem_ctx);
+ return -1;
+ }
+
+ modules = ldb_modules_list_from_string(ldb, mem_ctx,
+ (const char *)res->msgs[0]->elements[0].values[0].data);
+
+ }
+
+ talloc_free(mods_dn);
+ }
+
+ if (modules != NULL) {
+ ret = ldb_load_modules_list(ldb, modules, ldb->modules, &ldb->modules);
+ talloc_free(modules);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ } else {
+ ldb_debug(ldb, LDB_DEBUG_TRACE, "No modules specified for this database\n");
+ }
+
+ return ldb_init_module_chain(ldb, ldb->modules);
+}
+
+/*
+ by using this we allow ldb modules to only implement the functions they care about,
+ which makes writing a module simpler, and makes it more likely to keep working
+ when ldb is extended
+*/
+#define FIND_OP(module, op) do { \
+ struct ldb_context *ldb = module->ldb; \
+ module = module->next; \
+ while (module && module->ops->op == NULL) module = module->next; \
+ if (module == NULL) { \
+ ldb_asprintf_errstring(ldb, "Unable to find backend operation for " #op ); \
+ return LDB_ERR_OPERATIONS_ERROR; \
+ } \
+} while (0)
+
+
+/*
+ helper functions to call the next module in chain
+*/
+
+int ldb_next_request(struct ldb_module *module, struct ldb_request *request)
+{
+ switch (request->operation) {
+ case LDB_SEARCH:
+ FIND_OP(module, search);
+ return module->ops->search(module, request);
+ case LDB_ADD:
+ FIND_OP(module, add);
+ return module->ops->add(module, request);
+ case LDB_MODIFY:
+ FIND_OP(module, modify);
+ return module->ops->modify(module, request);
+ case LDB_DELETE:
+ FIND_OP(module, del);
+ return module->ops->del(module, request);
+ case LDB_RENAME:
+ FIND_OP(module, rename);
+ return module->ops->rename(module, request);
+ case LDB_SEQUENCE_NUMBER:
+ FIND_OP(module, sequence_number);
+ return module->ops->sequence_number(module, request);
+ default:
+ FIND_OP(module, request);
+ return module->ops->request(module, request);
+ }
+}
+
+int ldb_next_init(struct ldb_module *module)
+{
+ /* init is different in that it is not an error if modules
+ * do not require initialization */
+
+ module = module->next;
+
+ while (module && module->ops->init_context == NULL)
+ module = module->next;
+
+ if (module == NULL)
+ return LDB_SUCCESS;
+
+ return module->ops->init_context(module);
+}
+
+int ldb_next_start_trans(struct ldb_module *module)
+{
+ FIND_OP(module, start_transaction);
+ return module->ops->start_transaction(module);
+}
+
+int ldb_next_end_trans(struct ldb_module *module)
+{
+ FIND_OP(module, end_transaction);
+ return module->ops->end_transaction(module);
+}
+
+int ldb_next_del_trans(struct ldb_module *module)
+{
+ FIND_OP(module, del_transaction);
+ return module->ops->del_transaction(module);
+}
diff --git a/source3/lib/ldb/common/ldb_msg.c b/source3/lib/ldb/common/ldb_msg.c
new file mode 100644
index 0000000000..a8a6e93f12
--- /dev/null
+++ b/source3/lib/ldb/common/ldb_msg.c
@@ -0,0 +1,829 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb message component utility functions
+ *
+ * Description: functions for manipulating ldb_message structures
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f);
+int ldb_msg_element_compare_name(struct ldb_message_element *el1,
+ struct ldb_message_element *el2);
+
+/*
+ create a new ldb_message in a given memory context (NULL for top level)
+*/
+struct ldb_message *ldb_msg_new(void *mem_ctx)
+{
+ return talloc_zero(mem_ctx, struct ldb_message);
+}
+
+/*
+ find an element in a message by attribute name
+*/
+struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
+ const char *attr_name)
+{
+ unsigned int i;
+ for (i=0;i<msg->num_elements;i++) {
+ if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
+ return &msg->elements[i];
+ }
+ }
+ return NULL;
+}
+
+/*
+ see if two ldb_val structures contain exactly the same data
+ return 1 for a match, 0 for a mis-match
+*/
+int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ if (v1->length != v2->length) return 0;
+
+ if (v1->length == 0) return 1;
+
+ if (memcmp(v1->data, v2->data, v1->length) == 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ find a value in an element
+ assumes case sensitive comparison
+*/
+struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
+ struct ldb_val *val)
+{
+ unsigned int i;
+ for (i=0;i<el->num_values;i++) {
+ if (ldb_val_equal_exact(val, &el->values[i])) {
+ return &el->values[i];
+ }
+ }
+ return NULL;
+}
+
+/*
+ duplicate a ldb_val structure
+*/
+struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v)
+{
+ struct ldb_val v2;
+ v2.length = v->length;
+ if (v->data == NULL) {
+ v2.data = NULL;
+ return v2;
+ }
+
+ /* the +1 is to cope with buggy C library routines like strndup
+ that look one byte beyond */
+ v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
+ if (!v2.data) {
+ v2.length = 0;
+ return v2;
+ }
+
+ memcpy(v2.data, v->data, v->length);
+ ((char *)v2.data)[v->length] = 0;
+ return v2;
+}
+
+/*
+ add an empty element to a message
+*/
+int ldb_msg_add_empty( struct ldb_message *msg,
+ const char *attr_name,
+ int flags,
+ struct ldb_message_element **return_el)
+{
+ struct ldb_message_element *els;
+
+ if (! ldb_valid_attr_name(attr_name)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ els = talloc_realloc(msg, msg->elements,
+ struct ldb_message_element, msg->num_elements+1);
+ if (!els) {
+ errno = ENOMEM;
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ els[msg->num_elements].values = NULL;
+ els[msg->num_elements].num_values = 0;
+ els[msg->num_elements].flags = flags;
+ els[msg->num_elements].name = talloc_strdup(els, attr_name);
+ if (!els[msg->num_elements].name) {
+ errno = ENOMEM;
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->elements = els;
+ msg->num_elements++;
+
+ if (return_el) {
+ *return_el = &els[msg->num_elements-1];
+ }
+
+ return LDB_SUCCESS;
+}
+
+/*
+ add an empty element to a message
+*/
+int ldb_msg_add(struct ldb_message *msg,
+ const struct ldb_message_element *el,
+ int flags)
+{
+ if (ldb_msg_add_empty(msg, el->name, flags, NULL) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->elements[msg->num_elements-1] = *el;
+ msg->elements[msg->num_elements-1].flags = flags;
+
+ return LDB_SUCCESS;
+}
+
+/*
+ add a value to a message
+*/
+int ldb_msg_add_value(struct ldb_message *msg,
+ const char *attr_name,
+ const struct ldb_val *val,
+ struct ldb_message_element **return_el)
+{
+ struct ldb_message_element *el;
+ struct ldb_val *vals;
+ int ret;
+
+ el = ldb_msg_find_element(msg, attr_name);
+ if (!el) {
+ ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
+ if (!vals) {
+ errno = ENOMEM;
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ el->values = vals;
+ el->values[el->num_values] = *val;
+ el->num_values++;
+
+ if (return_el) {
+ *return_el = el;
+ }
+
+ return LDB_SUCCESS;
+}
+
+
+/*
+ add a value to a message, stealing it into the 'right' place
+*/
+int ldb_msg_add_steal_value(struct ldb_message *msg,
+ const char *attr_name,
+ struct ldb_val *val)
+{
+ int ret;
+ struct ldb_message_element *el;
+
+ ret = ldb_msg_add_value(msg, attr_name, val, &el);
+ if (ret == LDB_SUCCESS) {
+ talloc_steal(el->values, val->data);
+ }
+ return ret;
+}
+
+
+/*
+ add a string element to a message
+*/
+int ldb_msg_add_string(struct ldb_message *msg,
+ const char *attr_name, const char *str)
+{
+ struct ldb_val val;
+
+ val.data = discard_const_p(uint8_t, str);
+ val.length = strlen(str);
+
+ if (val.length == 0) {
+ /* allow empty strings as non-existant attributes */
+ return LDB_SUCCESS;
+ }
+
+ return ldb_msg_add_value(msg, attr_name, &val, NULL);
+}
+
+/*
+ add a string element to a message, stealing it into the 'right' place
+*/
+int ldb_msg_add_steal_string(struct ldb_message *msg,
+ const char *attr_name, char *str)
+{
+ struct ldb_val val;
+
+ val.data = (uint8_t *)str;
+ val.length = strlen(str);
+
+ return ldb_msg_add_steal_value(msg, attr_name, &val);
+}
+
+/*
+ add a printf formatted element to a message
+*/
+int ldb_msg_add_fmt(struct ldb_message *msg,
+ const char *attr_name, const char *fmt, ...)
+{
+ struct ldb_val val;
+ va_list ap;
+ char *str;
+
+ va_start(ap, fmt);
+ str = talloc_vasprintf(msg, fmt, ap);
+ va_end(ap);
+
+ if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
+
+ val.data = (uint8_t *)str;
+ val.length = strlen(str);
+
+ return ldb_msg_add_steal_value(msg, attr_name, &val);
+}
+
+/*
+ compare two ldb_message_element structures
+ assumes case senistive comparison
+*/
+int ldb_msg_element_compare(struct ldb_message_element *el1,
+ struct ldb_message_element *el2)
+{
+ unsigned int i;
+
+ if (el1->num_values != el2->num_values) {
+ return el1->num_values - el2->num_values;
+ }
+
+ for (i=0;i<el1->num_values;i++) {
+ if (!ldb_msg_find_val(el2, &el1->values[i])) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ compare two ldb_message_element structures
+ comparing by element name
+*/
+int ldb_msg_element_compare_name(struct ldb_message_element *el1,
+ struct ldb_message_element *el2)
+{
+ return ldb_attr_cmp(el1->name, el2->name);
+}
+
+/*
+ convenience functions to return common types from a message
+ these return the first value if the attribute is multi-valued
+*/
+const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name)
+{
+ struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
+ if (!el || el->num_values == 0) {
+ return NULL;
+ }
+ return &el->values[0];
+}
+
+int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
+ const char *attr_name,
+ int default_value)
+{
+ const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+ if (!v || !v->data) {
+ return default_value;
+ }
+ return strtol((const char *)v->data, NULL, 0);
+}
+
+unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
+ const char *attr_name,
+ unsigned int default_value)
+{
+ const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+ if (!v || !v->data) {
+ return default_value;
+ }
+ return strtoul((const char *)v->data, NULL, 0);
+}
+
+int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
+ const char *attr_name,
+ int64_t default_value)
+{
+ const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+ if (!v || !v->data) {
+ return default_value;
+ }
+ return strtoll((const char *)v->data, NULL, 0);
+}
+
+uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
+ const char *attr_name,
+ uint64_t default_value)
+{
+ const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+ if (!v || !v->data) {
+ return default_value;
+ }
+ return strtoull((const char *)v->data, NULL, 0);
+}
+
+double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
+ const char *attr_name,
+ double default_value)
+{
+ const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+ if (!v || !v->data) {
+ return default_value;
+ }
+ return strtod((const char *)v->data, NULL);
+}
+
+int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
+ const char *attr_name,
+ int default_value)
+{
+ const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+ if (!v || !v->data) {
+ return default_value;
+ }
+ if (strcasecmp((const char *)v->data, "FALSE") == 0) {
+ return 0;
+ }
+ if (strcasecmp((const char *)v->data, "TRUE") == 0) {
+ return 1;
+ }
+ return default_value;
+}
+
+const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
+ const char *attr_name,
+ const char *default_value)
+{
+ const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+ if (!v || !v->data) {
+ return default_value;
+ }
+ return (const char *)v->data;
+}
+
+struct ldb_dn *ldb_msg_find_attr_as_dn(void *mem_ctx,
+ const struct ldb_message *msg,
+ const char *attr_name)
+{
+ const struct ldb_val *v;
+
+ v = ldb_msg_find_ldb_val(msg, attr_name);
+ if (!v || !v->data) {
+ return NULL;
+ }
+ return ldb_dn_explode(mem_ctx, (const char *)v->data);
+}
+
+/*
+ sort the elements of a message by name
+*/
+void ldb_msg_sort_elements(struct ldb_message *msg)
+{
+ qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
+ (comparison_fn_t)ldb_msg_element_compare_name);
+}
+
+/*
+ shallow copy a message - copying only the elements array so that the caller
+ can safely add new elements without changing the message
+*/
+struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg)
+{
+ struct ldb_message *msg2;
+ int i;
+
+ msg2 = talloc(mem_ctx, struct ldb_message);
+ if (msg2 == NULL) return NULL;
+
+ *msg2 = *msg;
+ msg2->private_data = NULL;
+
+ msg2->elements = talloc_array(msg2, struct ldb_message_element,
+ msg2->num_elements);
+ if (msg2->elements == NULL) goto failed;
+
+ for (i=0;i<msg2->num_elements;i++) {
+ msg2->elements[i] = msg->elements[i];
+ }
+
+ return msg2;
+
+failed:
+ talloc_free(msg2);
+ return NULL;
+}
+
+
+/*
+ copy a message, allocating new memory for all parts
+*/
+struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg)
+{
+ struct ldb_message *msg2;
+ int i, j;
+
+ msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
+ if (msg2 == NULL) return NULL;
+
+ msg2->dn = ldb_dn_copy(msg2, msg2->dn);
+ if (msg2->dn == NULL) goto failed;
+
+ for (i=0;i<msg2->num_elements;i++) {
+ struct ldb_message_element *el = &msg2->elements[i];
+ struct ldb_val *values = el->values;
+ el->name = talloc_strdup(msg2->elements, el->name);
+ if (el->name == NULL) goto failed;
+ el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
+ for (j=0;j<el->num_values;j++) {
+ el->values[j] = ldb_val_dup(el->values, &values[j]);
+ if (el->values[j].data == NULL && values[j].length != 0) {
+ goto failed;
+ }
+ }
+ }
+
+ return msg2;
+
+failed:
+ talloc_free(msg2);
+ return NULL;
+}
+
+
+/*
+ canonicalise a message, merging elements of the same name
+*/
+struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
+ const struct ldb_message *msg)
+{
+ int i;
+ struct ldb_message *msg2;
+
+ msg2 = ldb_msg_copy(ldb, msg);
+ if (msg2 == NULL) return NULL;
+
+ ldb_msg_sort_elements(msg2);
+
+ for (i=1;i<msg2->num_elements;i++) {
+ struct ldb_message_element *el1 = &msg2->elements[i-1];
+ struct ldb_message_element *el2 = &msg2->elements[i];
+ if (ldb_msg_element_compare_name(el1, el2) == 0) {
+ el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val,
+ el1->num_values + el2->num_values);
+ if (el1->values == NULL) {
+ return NULL;
+ }
+ memcpy(el1->values + el1->num_values,
+ el2->values,
+ sizeof(struct ldb_val) * el2->num_values);
+ el1->num_values += el2->num_values;
+ talloc_free(discard_const_p(char, el2->name));
+ if (i+1<msg2->num_elements) {
+ memmove(el2, el2+1, sizeof(struct ldb_message_element) *
+ (msg2->num_elements - (i+1)));
+ }
+ msg2->num_elements--;
+ i--;
+ }
+ }
+
+ return msg2;
+}
+
+
+/*
+ return a ldb_message representing the differences between msg1 and msg2. If you
+ then use this in a ldb_modify() call it can be used to save edits to a message
+*/
+struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
+ struct ldb_message *msg1,
+ struct ldb_message *msg2)
+{
+ struct ldb_message *mod;
+ struct ldb_message_element *el;
+ unsigned int i;
+
+ mod = ldb_msg_new(ldb);
+
+ mod->dn = msg1->dn;
+ mod->num_elements = 0;
+ mod->elements = NULL;
+
+ msg2 = ldb_msg_canonicalize(ldb, msg2);
+ if (msg2 == NULL) {
+ return NULL;
+ }
+
+ /* look in msg2 to find elements that need to be added
+ or modified */
+ for (i=0;i<msg2->num_elements;i++) {
+ el = ldb_msg_find_element(msg1, msg2->elements[i].name);
+
+ if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
+ continue;
+ }
+
+ if (ldb_msg_add(mod,
+ &msg2->elements[i],
+ el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) {
+ return NULL;
+ }
+ }
+
+ /* look in msg1 to find elements that need to be deleted */
+ for (i=0;i<msg1->num_elements;i++) {
+ el = ldb_msg_find_element(msg2, msg1->elements[i].name);
+ if (!el) {
+ if (ldb_msg_add_empty(mod,
+ msg1->elements[i].name,
+ LDB_FLAG_MOD_DELETE, NULL) != 0) {
+ return NULL;
+ }
+ }
+ }
+
+ return mod;
+}
+
+int ldb_msg_sanity_check(struct ldb_context *ldb,
+ const struct ldb_message *msg)
+{
+ int i, j;
+
+ /* basic check on DN */
+ if (msg->dn == NULL) {
+ /* TODO: return also an error string */
+ ldb_set_errstring(ldb, "ldb message lacks a DN!");
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ /* basic syntax checks */
+ for (i = 0; i < msg->num_elements; i++) {
+ for (j = 0; j < msg->elements[i].num_values; j++) {
+ if (msg->elements[i].values[j].length == 0) {
+ TALLOC_CTX *mem_ctx = talloc_new(ldb);
+ /* an attribute cannot be empty */
+ /* TODO: return also an error string */
+ ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
+ msg->elements[i].name,
+ ldb_dn_linearize(mem_ctx, msg->dn));
+ talloc_free(mem_ctx);
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+
+
+
+/*
+ copy an attribute list. This only copies the array, not the elements
+ (ie. the elements are left as the same pointers)
+*/
+const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
+{
+ const char **ret;
+ int i;
+ for (i=0;attrs[i];i++) /* noop */ ;
+ ret = talloc_array(mem_ctx, const char *, i+1);
+ if (ret == NULL) {
+ return NULL;
+ }
+ for (i=0;attrs[i];i++) {
+ ret[i] = attrs[i];
+ }
+ ret[i] = attrs[i];
+ return ret;
+}
+
+
+/*
+ copy an attribute list. This only copies the array, not the elements
+ (ie. the elements are left as the same pointers). The new attribute is added to the list.
+*/
+const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
+{
+ const char **ret;
+ int i;
+ for (i=0;attrs[i];i++) /* noop */ ;
+ ret = talloc_array(mem_ctx, const char *, i+2);
+ if (ret == NULL) {
+ return NULL;
+ }
+ for (i=0;attrs[i];i++) {
+ ret[i] = attrs[i];
+ }
+ ret[i] = new_attr;
+ ret[i+1] = NULL;
+ return ret;
+}
+
+
+/*
+ return 1 if an attribute is in a list of attributes, or 0 otherwise
+*/
+int ldb_attr_in_list(const char * const *attrs, const char *attr)
+{
+ int i;
+ for (i=0;attrs[i];i++) {
+ if (ldb_attr_cmp(attrs[i], attr) == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ rename the specified attribute in a search result
+*/
+int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
+{
+ struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
+ if (el == NULL) {
+ return LDB_SUCCESS;
+ }
+ el->name = talloc_strdup(msg->elements, replace);
+ if (el->name == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return LDB_SUCCESS;
+}
+
+
+/*
+ copy the specified attribute in a search result to a new attribute
+*/
+int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
+{
+ struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
+ if (el == NULL) {
+ return LDB_SUCCESS;
+ }
+ if (ldb_msg_add(msg, el, 0) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return ldb_msg_rename_attr(msg, attr, replace);
+}
+
+
+/*
+ remove the specified attribute in a search result
+*/
+void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
+{
+ struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
+ if (el) {
+ int n = (el - msg->elements);
+ if (n != msg->num_elements-1) {
+ memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
+ }
+ msg->num_elements--;
+ }
+}
+
+/*
+ remove the specified element in a search result
+*/
+void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
+{
+ int n = (el - msg->elements);
+ if (n != msg->num_elements-1) {
+ memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
+ }
+ msg->num_elements--;
+}
+
+/*
+ return a LDAP formatted time string
+*/
+char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
+{
+ struct tm *tm = gmtime(&t);
+
+ if (!tm) {
+ return NULL;
+ }
+
+ /* formatted like: 20040408072012.0Z */
+ return talloc_asprintf(mem_ctx,
+ "%04u%02u%02u%02u%02u%02u.0Z",
+ tm->tm_year+1900, tm->tm_mon+1,
+ tm->tm_mday, tm->tm_hour, tm->tm_min,
+ tm->tm_sec);
+}
+
+
+/*
+ convert a LDAP time string to a time_t. Return 0 if unable to convert
+*/
+time_t ldb_string_to_time(const char *s)
+{
+ struct tm tm;
+
+ if (s == NULL) return 0;
+
+ memset(&tm, 0, sizeof(tm));
+ if (sscanf(s, "%04u%02u%02u%02u%02u%02u",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
+ return 0;
+ }
+ tm.tm_year -= 1900;
+ tm.tm_mon -= 1;
+
+ return timegm(&tm);
+}
+
+
+/*
+ dump a set of results to a file. Useful from within gdb
+*/
+void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
+{
+ int i;
+
+ for (i = 0; i < result->count; i++) {
+ struct ldb_ldif ldif;
+ fprintf(f, "# record %d\n", i+1);
+ ldif.changetype = LDB_CHANGETYPE_NONE;
+ ldif.msg = result->msgs[i];
+ ldb_ldif_write_file(ldb, f, &ldif);
+ }
+}
+
+int ldb_msg_check_string_attribute(const struct ldb_message *msg, const char *name, const char *value)
+{
+ struct ldb_message_element *el;
+ struct ldb_val val;
+
+ el = ldb_msg_find_element(msg, name);
+ if (el == NULL)
+ return 0;
+
+ val.data = discard_const_p(uint8_t, value);
+ val.length = strlen(value);
+
+ if (ldb_msg_find_val(el, &val))
+ return 1;
+
+ return 0;
+}
diff --git a/source3/lib/ldb/common/ldb_parse.c b/source3/lib/ldb/common/ldb_parse.c
new file mode 100644
index 0000000000..bcc92c5b5c
--- /dev/null
+++ b/source3/lib/ldb/common/ldb_parse.c
@@ -0,0 +1,818 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb expression parsing
+ *
+ * Description: parse LDAP-like search expressions
+ *
+ * Author: Andrew Tridgell
+ */
+
+/*
+ TODO:
+ - add RFC2254 binary string handling
+ - possibly add ~=, <= and >= handling
+ - expand the test suite
+ - add better parse error handling
+
+*/
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+#include "system/locale.h"
+
+struct ldb_val ldb_binary_decode(void *mem_ctx, const char *str);
+
+/*
+a filter is defined by:
+ <filter> ::= '(' <filtercomp> ')'
+ <filtercomp> ::= <and> | <or> | <not> | <simple>
+ <and> ::= '&' <filterlist>
+ <or> ::= '|' <filterlist>
+ <not> ::= '!' <filter>
+ <filterlist> ::= <filter> | <filter> <filterlist>
+ <simple> ::= <attributetype> <filtertype> <attributevalue>
+ <filtertype> ::= '=' | '~=' | '<=' | '>='
+*/
+
+/*
+ decode a RFC2254 binary string representation of a buffer.
+ Used in LDAP filters.
+*/
+struct ldb_val ldb_binary_decode(void *mem_ctx, const char *str)
+{
+ int i, j;
+ struct ldb_val ret;
+ int slen = str?strlen(str):0;
+
+ ret.data = (uint8_t *)talloc_size(mem_ctx, slen+1);
+ ret.length = 0;
+ if (ret.data == NULL) return ret;
+
+ for (i=j=0;i<slen;i++) {
+ if (str[i] == '\\') {
+ unsigned c;
+ if (sscanf(&str[i+1], "%02X", &c) != 1) {
+ talloc_free(ret.data);
+ memset(&ret, 0, sizeof(ret));
+ return ret;
+ }
+ ((uint8_t *)ret.data)[j++] = c;
+ i += 2;
+ } else {
+ ((uint8_t *)ret.data)[j++] = str[i];
+ }
+ }
+ ret.length = j;
+ ((uint8_t *)ret.data)[j] = 0;
+
+ return ret;
+}
+
+
+/*
+ encode a blob as a RFC2254 binary string, escaping any
+ non-printable or '\' characters
+*/
+char *ldb_binary_encode(void *mem_ctx, struct ldb_val val)
+{
+ int i;
+ char *ret;
+ int len = val.length;
+ unsigned char *buf = val.data;
+
+ for (i=0;i<val.length;i++) {
+ if (!isprint(buf[i]) || strchr(" *()\\&|!\"", buf[i])) {
+ len += 2;
+ }
+ }
+ ret = talloc_array(mem_ctx, char, len+1);
+ if (ret == NULL) return NULL;
+
+ len = 0;
+ for (i=0;i<val.length;i++) {
+ if (!isprint(buf[i]) || strchr(" *()\\&|!\"", buf[i])) {
+ snprintf(ret+len, 4, "\\%02X", buf[i]);
+ len += 3;
+ } else {
+ ret[len++] = buf[i];
+ }
+ }
+
+ ret[len] = 0;
+
+ return ret;
+}
+
+/*
+ encode a string as a RFC2254 binary string, escaping any
+ non-printable or '\' characters. This routine is suitable for use
+ in escaping user data in ldap filters.
+*/
+char *ldb_binary_encode_string(void *mem_ctx, const char *string)
+{
+ struct ldb_val val;
+ val.data = discard_const_p(uint8_t, string);
+ val.length = strlen(string);
+ return ldb_binary_encode(mem_ctx, val);
+}
+
+/* find the first matching wildcard */
+static char *ldb_parse_find_wildcard(char *value)
+{
+ while (*value) {
+ value = strpbrk(value, "\\*");
+ if (value == NULL) return NULL;
+
+ if (value[0] == '\\') {
+ if (value[1] == '\0') return NULL;
+ value += 2;
+ continue;
+ }
+
+ if (value[0] == '*') return value;
+ }
+
+ return NULL;
+}
+
+/* return a NULL terminated list of binary strings representing the value
+ chunks separated by wildcards that makes the value portion of the filter
+*/
+static struct ldb_val **ldb_wildcard_decode(void *mem_ctx, const char *string)
+{
+ struct ldb_val **ret = NULL;
+ int val = 0;
+ char *wc, *str;
+
+ wc = talloc_strdup(mem_ctx, string);
+ if (wc == NULL) return NULL;
+
+ while (wc && *wc) {
+ str = wc;
+ wc = ldb_parse_find_wildcard(str);
+ if (wc && *wc) {
+ if (wc == str) {
+ wc++;
+ continue;
+ }
+ *wc = 0;
+ wc++;
+ }
+
+ ret = talloc_realloc(mem_ctx, ret, struct ldb_val *, val + 2);
+ if (ret == NULL) return NULL;
+
+ ret[val] = talloc(mem_ctx, struct ldb_val);
+ if (ret[val] == NULL) return NULL;
+
+ *(ret[val]) = ldb_binary_decode(mem_ctx, str);
+ if ((ret[val])->data == NULL) return NULL;
+
+ val++;
+ }
+
+ if (ret != NULL) {
+ ret[val] = NULL;
+ }
+
+ return ret;
+}
+
+static struct ldb_parse_tree *ldb_parse_filter(void *mem_ctx, const char **s);
+
+
+/*
+ parse an extended match
+
+ possible forms:
+ (attr:oid:=value)
+ (attr:dn:oid:=value)
+ (attr:dn:=value)
+ (:dn:oid:=value)
+
+ the ':dn' part sets the dnAttributes boolean if present
+ the oid sets the rule_id string
+
+*/
+static struct ldb_parse_tree *ldb_parse_extended(struct ldb_parse_tree *ret,
+ char *attr, char *value)
+{
+ char *p1, *p2;
+
+ ret->operation = LDB_OP_EXTENDED;
+ ret->u.extended.value = ldb_binary_decode(ret, value);
+ if (ret->u.extended.value.data == NULL) goto failed;
+
+ p1 = strchr(attr, ':');
+ if (p1 == NULL) goto failed;
+ p2 = strchr(p1+1, ':');
+
+ *p1 = 0;
+ if (p2) *p2 = 0;
+
+ ret->u.extended.attr = attr;
+ if (strcmp(p1+1, "dn") == 0) {
+ ret->u.extended.dnAttributes = 1;
+ if (p2) {
+ ret->u.extended.rule_id = talloc_strdup(ret, p2+1);
+ if (ret->u.extended.rule_id == NULL) goto failed;
+ } else {
+ ret->u.extended.rule_id = NULL;
+ }
+ } else {
+ ret->u.extended.dnAttributes = 0;
+ ret->u.extended.rule_id = talloc_strdup(ret, p1+1);
+ if (ret->u.extended.rule_id == NULL) goto failed;
+ }
+
+ return ret;
+
+failed:
+ talloc_free(ret);
+ return NULL;
+}
+
+static enum ldb_parse_op ldb_parse_filtertype(void *mem_ctx, char **type, char **value, const char **s)
+{
+ enum ldb_parse_op filter = 0;
+ char *name, *val, *k;
+ const char *p = *s;
+ const char *t, *t1;
+
+ /* retrieve attributetype name */
+ t = p;
+
+ while ((isascii(*p) && isalnum((unsigned char)*p)) || (*p == '-')) { /* attribute names can only be alphanums */
+ p++;
+ }
+
+ if (*p == ':') { /* but extended searches have : and . chars too */
+ p = strstr(p, ":=");
+ if (p == NULL) { /* malformed attribute name */
+ return 0;
+ }
+ }
+
+ t1 = p;
+
+ while (isspace((unsigned char)*p)) p++;
+
+ if (!strchr("=<>~:", *p)) {
+ return 0;
+ }
+
+ /* save name */
+ name = (char *)talloc_memdup(mem_ctx, t, t1 - t + 1);
+ if (name == NULL) return 0;
+ name[t1 - t] = '\0';
+
+ /* retrieve filtertype */
+
+ if (*p == '=') {
+ filter = LDB_OP_EQUALITY;
+ } else if (*(p + 1) == '=') {
+ switch (*p) {
+ case '<':
+ filter = LDB_OP_LESS;
+ p++;
+ break;
+ case '>':
+ filter = LDB_OP_GREATER;
+ p++;
+ break;
+ case '~':
+ filter = LDB_OP_APPROX;
+ p++;
+ break;
+ case ':':
+ filter = LDB_OP_EXTENDED;
+ p++;
+ break;
+ }
+ }
+ if (!filter) {
+ talloc_free(name);
+ return filter;
+ }
+ p++;
+
+ while (isspace((unsigned char)*p)) p++;
+
+ /* retrieve value */
+ t = p;
+
+ while (*p && ((*p != ')') || ((*p == ')') && (*(p - 1) == '\\')))) p++;
+
+ val = (char *)talloc_memdup(mem_ctx, t, p - t + 1);
+ if (val == NULL) {
+ talloc_free(name);
+ return 0;
+ }
+ val[p - t] = '\0';
+
+ k = &(val[p - t]);
+
+ /* remove trailing spaces from value */
+ while ((k > val) && (isspace((unsigned char)*(k - 1)))) k--;
+ *k = '\0';
+
+ *type = name;
+ *value = val;
+ *s = p;
+ return filter;
+}
+
+/*
+ <simple> ::= <attributetype> <filtertype> <attributevalue>
+*/
+static struct ldb_parse_tree *ldb_parse_simple(void *mem_ctx, const char **s)
+{
+ char *attr, *value;
+ struct ldb_parse_tree *ret;
+ enum ldb_parse_op filtertype;
+
+ ret = talloc(mem_ctx, struct ldb_parse_tree);
+ if (!ret) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ filtertype = ldb_parse_filtertype(ret, &attr, &value, s);
+ if (!filtertype) {
+ talloc_free(ret);
+ return NULL;
+ }
+
+ switch (filtertype) {
+
+ case LDB_OP_PRESENT:
+ ret->operation = LDB_OP_PRESENT;
+ ret->u.present.attr = attr;
+ break;
+
+ case LDB_OP_EQUALITY:
+
+ if (strcmp(value, "*") == 0) {
+ ret->operation = LDB_OP_PRESENT;
+ ret->u.present.attr = attr;
+ break;
+ }
+
+ if (ldb_parse_find_wildcard(value) != NULL) {
+ ret->operation = LDB_OP_SUBSTRING;
+ ret->u.substring.attr = attr;
+ ret->u.substring.start_with_wildcard = 0;
+ ret->u.substring.end_with_wildcard = 0;
+ ret->u.substring.chunks = ldb_wildcard_decode(ret, value);
+ if (ret->u.substring.chunks == NULL){
+ talloc_free(ret);
+ return NULL;
+ }
+ if (value[0] == '*')
+ ret->u.substring.start_with_wildcard = 1;
+ if (value[strlen(value) - 1] == '*')
+ ret->u.substring.end_with_wildcard = 1;
+ talloc_free(value);
+
+ break;
+ }
+
+ ret->operation = LDB_OP_EQUALITY;
+ ret->u.equality.attr = attr;
+ ret->u.equality.value = ldb_binary_decode(ret, value);
+ if (ret->u.equality.value.data == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ talloc_free(value);
+ break;
+
+ case LDB_OP_GREATER:
+ ret->operation = LDB_OP_GREATER;
+ ret->u.comparison.attr = attr;
+ ret->u.comparison.value = ldb_binary_decode(ret, value);
+ if (ret->u.comparison.value.data == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ talloc_free(value);
+ break;
+
+ case LDB_OP_LESS:
+ ret->operation = LDB_OP_LESS;
+ ret->u.comparison.attr = attr;
+ ret->u.comparison.value = ldb_binary_decode(ret, value);
+ if (ret->u.comparison.value.data == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ talloc_free(value);
+ break;
+
+ case LDB_OP_APPROX:
+ ret->operation = LDB_OP_APPROX;
+ ret->u.comparison.attr = attr;
+ ret->u.comparison.value = ldb_binary_decode(ret, value);
+ if (ret->u.comparison.value.data == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ talloc_free(value);
+ break;
+
+ case LDB_OP_EXTENDED:
+
+ ret = ldb_parse_extended(ret, attr, value);
+ break;
+
+ default:
+ talloc_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+
+/*
+ parse a filterlist
+ <and> ::= '&' <filterlist>
+ <or> ::= '|' <filterlist>
+ <filterlist> ::= <filter> | <filter> <filterlist>
+*/
+static struct ldb_parse_tree *ldb_parse_filterlist(void *mem_ctx, const char **s)
+{
+ struct ldb_parse_tree *ret, *next;
+ enum ldb_parse_op op;
+ const char *p = *s;
+
+ switch (*p) {
+ case '&':
+ op = LDB_OP_AND;
+ break;
+ case '|':
+ op = LDB_OP_OR;
+ break;
+ default:
+ return NULL;
+ }
+ p++;
+
+ while (isspace((unsigned char)*p)) p++;
+
+ ret = talloc(mem_ctx, struct ldb_parse_tree);
+ if (!ret) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ ret->operation = op;
+ ret->u.list.num_elements = 1;
+ ret->u.list.elements = talloc(ret, struct ldb_parse_tree *);
+ if (!ret->u.list.elements) {
+ errno = ENOMEM;
+ talloc_free(ret);
+ return NULL;
+ }
+
+ ret->u.list.elements[0] = ldb_parse_filter(ret->u.list.elements, &p);
+ if (!ret->u.list.elements[0]) {
+ talloc_free(ret);
+ return NULL;
+ }
+
+ while (isspace((unsigned char)*p)) p++;
+
+ while (*p && (next = ldb_parse_filter(ret->u.list.elements, &p))) {
+ struct ldb_parse_tree **e;
+ e = talloc_realloc(ret, ret->u.list.elements,
+ struct ldb_parse_tree *,
+ ret->u.list.num_elements + 1);
+ if (!e) {
+ errno = ENOMEM;
+ talloc_free(ret);
+ return NULL;
+ }
+ ret->u.list.elements = e;
+ ret->u.list.elements[ret->u.list.num_elements] = next;
+ ret->u.list.num_elements++;
+ while (isspace((unsigned char)*p)) p++;
+ }
+
+ *s = p;
+
+ return ret;
+}
+
+
+/*
+ <not> ::= '!' <filter>
+*/
+static struct ldb_parse_tree *ldb_parse_not(void *mem_ctx, const char **s)
+{
+ struct ldb_parse_tree *ret;
+ const char *p = *s;
+
+ if (*p != '!') {
+ return NULL;
+ }
+ p++;
+
+ ret = talloc(mem_ctx, struct ldb_parse_tree);
+ if (!ret) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ ret->operation = LDB_OP_NOT;
+ ret->u.isnot.child = ldb_parse_filter(ret, &p);
+ if (!ret->u.isnot.child) {
+ talloc_free(ret);
+ return NULL;
+ }
+
+ *s = p;
+
+ return ret;
+}
+
+/*
+ parse a filtercomp
+ <filtercomp> ::= <and> | <or> | <not> | <simple>
+*/
+static struct ldb_parse_tree *ldb_parse_filtercomp(void *mem_ctx, const char **s)
+{
+ struct ldb_parse_tree *ret;
+ const char *p = *s;
+
+ while (isspace((unsigned char)*p)) p++;
+
+ switch (*p) {
+ case '&':
+ ret = ldb_parse_filterlist(mem_ctx, &p);
+ break;
+
+ case '|':
+ ret = ldb_parse_filterlist(mem_ctx, &p);
+ break;
+
+ case '!':
+ ret = ldb_parse_not(mem_ctx, &p);
+ break;
+
+ case '(':
+ case ')':
+ return NULL;
+
+ default:
+ ret = ldb_parse_simple(mem_ctx, &p);
+
+ }
+
+ *s = p;
+ return ret;
+}
+
+
+/*
+ <filter> ::= '(' <filtercomp> ')'
+*/
+static struct ldb_parse_tree *ldb_parse_filter(void *mem_ctx, const char **s)
+{
+ struct ldb_parse_tree *ret;
+ const char *p = *s;
+
+ if (*p != '(') {
+ return NULL;
+ }
+ p++;
+
+ ret = ldb_parse_filtercomp(mem_ctx, &p);
+
+ if (*p != ')') {
+ return NULL;
+ }
+ p++;
+
+ while (isspace((unsigned char)*p)) {
+ p++;
+ }
+
+ *s = p;
+
+ return ret;
+}
+
+
+/*
+ main parser entry point. Takes a search string and returns a parse tree
+
+ expression ::= <simple> | <filter>
+*/
+struct ldb_parse_tree *ldb_parse_tree(void *mem_ctx, const char *s)
+{
+ if (s == NULL || *s == 0) {
+ s = "(|(objectClass=*)(distinguishedName=*))";
+ }
+
+ while (isspace((unsigned char)*s)) s++;
+
+ if (*s == '(') {
+ return ldb_parse_filter(mem_ctx, &s);
+ }
+
+ return ldb_parse_simple(mem_ctx, &s);
+}
+
+
+/*
+ construct a ldap parse filter given a parse tree
+*/
+char *ldb_filter_from_tree(void *mem_ctx, struct ldb_parse_tree *tree)
+{
+ char *s, *s2, *ret;
+ int i;
+
+ if (tree == NULL) {
+ return NULL;
+ }
+
+ switch (tree->operation) {
+ case LDB_OP_AND:
+ case LDB_OP_OR:
+ ret = talloc_asprintf(mem_ctx, "(%c", tree->operation==LDB_OP_AND?'&':'|');
+ if (ret == NULL) return NULL;
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ s = ldb_filter_from_tree(mem_ctx, tree->u.list.elements[i]);
+ if (s == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ s2 = talloc_asprintf_append(ret, "%s", s);
+ talloc_free(s);
+ if (s2 == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ ret = s2;
+ }
+ s = talloc_asprintf_append(ret, ")");
+ if (s == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ return s;
+ case LDB_OP_NOT:
+ s = ldb_filter_from_tree(mem_ctx, tree->u.isnot.child);
+ if (s == NULL) return NULL;
+
+ ret = talloc_asprintf(mem_ctx, "(!%s)", s);
+ talloc_free(s);
+ return ret;
+ case LDB_OP_EQUALITY:
+ s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
+ if (s == NULL) return NULL;
+ ret = talloc_asprintf(mem_ctx, "(%s=%s)",
+ tree->u.equality.attr, s);
+ talloc_free(s);
+ return ret;
+ case LDB_OP_SUBSTRING:
+ ret = talloc_asprintf(mem_ctx, "(%s=%s", tree->u.substring.attr,
+ tree->u.substring.start_with_wildcard?"*":"");
+ if (ret == NULL) return NULL;
+ for (i = 0; tree->u.substring.chunks[i]; i++) {
+ s2 = ldb_binary_encode(mem_ctx, *(tree->u.substring.chunks[i]));
+ if (s2 == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ if (tree->u.substring.chunks[i+1] ||
+ tree->u.substring.end_with_wildcard) {
+ s = talloc_asprintf_append(ret, "%s*", s2);
+ } else {
+ s = talloc_asprintf_append(ret, "%s", s2);
+ }
+ if (s == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ ret = s;
+ }
+ s = talloc_asprintf_append(ret, ")");
+ if (s == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ ret = s;
+ return ret;
+ case LDB_OP_GREATER:
+ s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
+ if (s == NULL) return NULL;
+ ret = talloc_asprintf(mem_ctx, "(%s>=%s)",
+ tree->u.equality.attr, s);
+ talloc_free(s);
+ return ret;
+ case LDB_OP_LESS:
+ s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
+ if (s == NULL) return NULL;
+ ret = talloc_asprintf(mem_ctx, "(%s<=%s)",
+ tree->u.equality.attr, s);
+ talloc_free(s);
+ return ret;
+ case LDB_OP_PRESENT:
+ ret = talloc_asprintf(mem_ctx, "(%s=*)", tree->u.present.attr);
+ return ret;
+ case LDB_OP_APPROX:
+ s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
+ if (s == NULL) return NULL;
+ ret = talloc_asprintf(mem_ctx, "(%s~=%s)",
+ tree->u.equality.attr, s);
+ talloc_free(s);
+ return ret;
+ case LDB_OP_EXTENDED:
+ s = ldb_binary_encode(mem_ctx, tree->u.extended.value);
+ if (s == NULL) return NULL;
+ ret = talloc_asprintf(mem_ctx, "(%s%s%s%s:=%s)",
+ tree->u.extended.attr?tree->u.extended.attr:"",
+ tree->u.extended.dnAttributes?":dn":"",
+ tree->u.extended.rule_id?":":"",
+ tree->u.extended.rule_id?tree->u.extended.rule_id:"",
+ s);
+ talloc_free(s);
+ return ret;
+ }
+
+ return NULL;
+}
+
+
+/*
+ replace any occurances of an attribute name in the parse tree with a
+ new name
+*/
+void ldb_parse_tree_attr_replace(struct ldb_parse_tree *tree,
+ const char *attr,
+ const char *replace)
+{
+ int i;
+ switch (tree->operation) {
+ case LDB_OP_AND:
+ case LDB_OP_OR:
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ ldb_parse_tree_attr_replace(tree->u.list.elements[i],
+ attr, replace);
+ }
+ break;
+ case LDB_OP_NOT:
+ ldb_parse_tree_attr_replace(tree->u.isnot.child, attr, replace);
+ break;
+ case LDB_OP_EQUALITY:
+ case LDB_OP_GREATER:
+ case LDB_OP_LESS:
+ case LDB_OP_APPROX:
+ if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
+ tree->u.equality.attr = replace;
+ }
+ break;
+ case LDB_OP_SUBSTRING:
+ if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
+ tree->u.substring.attr = replace;
+ }
+ break;
+ case LDB_OP_PRESENT:
+ if (ldb_attr_cmp(tree->u.present.attr, attr) == 0) {
+ tree->u.present.attr = replace;
+ }
+ break;
+ case LDB_OP_EXTENDED:
+ if (tree->u.extended.attr &&
+ ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
+ tree->u.extended.attr = replace;
+ }
+ break;
+ }
+}
diff --git a/source3/lib/ldb/common/ldb_utf8.c b/source3/lib/ldb/common/ldb_utf8.c
new file mode 100644
index 0000000000..c576453b27
--- /dev/null
+++ b/source3/lib/ldb/common/ldb_utf8.c
@@ -0,0 +1,148 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb utf8 handling
+ *
+ * Description: case folding and case comparison for UTF8 strings
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+#include "system/locale.h"
+
+
+/*
+ this allow the user to pass in a caseless comparison
+ function to handle utf8 caseless comparisons
+ */
+void ldb_set_utf8_fns(struct ldb_context *ldb,
+ void *context,
+ char *(*casefold)(void *, void *, const char *))
+{
+ if (context)
+ ldb->utf8_fns.context = context;
+ if (casefold)
+ ldb->utf8_fns.casefold = casefold;
+}
+
+/*
+ a simple case folding function
+ NOTE: does not handle UTF8
+*/
+char *ldb_casefold_default(void *context, void *mem_ctx, const char *s)
+{
+ int i;
+ char *ret = talloc_strdup(mem_ctx, s);
+ if (!s) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ for (i=0;ret[i];i++) {
+ ret[i] = toupper((unsigned char)ret[i]);
+ }
+ return ret;
+}
+
+void ldb_set_utf8_default(struct ldb_context *ldb)
+{
+ ldb_set_utf8_fns(ldb, NULL, ldb_casefold_default);
+}
+
+char *ldb_casefold(struct ldb_context *ldb, void *mem_ctx, const char *s)
+{
+ return ldb->utf8_fns.casefold(ldb->utf8_fns.context, mem_ctx, s);
+}
+
+/*
+ check the attribute name is valid according to rfc2251
+ returns 1 if the name is ok
+ */
+
+int ldb_valid_attr_name(const char *s)
+{
+ int i;
+
+ if (!s || !s[0])
+ return 0;
+
+ /* handle special ldb_tdb wildcard */
+ if (strcmp(s, "*") == 0) return 1;
+
+ for (i = 0; s[i]; i++) {
+ if (! isascii(s[i])) {
+ return 0;
+ }
+ if (i == 0) { /* first char must be an alpha (or our special '@' identifier) */
+ if (! (isalpha(s[i]) || (s[i] == '@'))) {
+ return 0;
+ }
+ } else {
+ if (! (isalnum(s[i]) || (s[i] == '-'))) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+/*
+ compare two attribute names
+ attribute names are restricted by rfc2251 so using
+ strcasecmp and toupper here is ok.
+ return 0 for match
+*/
+int ldb_attr_cmp(const char *attr1, const char *attr2)
+{
+ return strcasecmp(attr1, attr2);
+}
+
+char *ldb_attr_casefold(void *mem_ctx, const char *s)
+{
+ int i;
+ char *ret = talloc_strdup(mem_ctx, s);
+ if (!ret) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ for (i = 0; ret[i]; i++) {
+ ret[i] = toupper((unsigned char)ret[i]);
+ }
+ return ret;
+}
+
+/*
+ we accept either 'dn' or 'distinguishedName' for a distinguishedName
+*/
+int ldb_attr_dn(const char *attr)
+{
+ if (ldb_attr_cmp(attr, "dn") == 0 ||
+ ldb_attr_cmp(attr, "distinguishedName") == 0) {
+ return 0;
+ }
+ return -1;
+}
diff --git a/source3/lib/ldb/common/qsort.c b/source3/lib/ldb/common/qsort.c
new file mode 100644
index 0000000000..79dd64128f
--- /dev/null
+++ b/source3/lib/ldb/common/qsort.c
@@ -0,0 +1,252 @@
+/* Copyright (C) 1991,1992,1996,1997,1999,2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */
+
+/* If you consider tuning this algorithm, you should consult first:
+ Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
+ Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993. */
+
+/* Modified to be used in samba4 by
+ * Simo Sorce <idra@samba.org> 2005
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+/* Byte-wise swap two items of size SIZE. */
+#define SWAP(a, b, size) \
+ do \
+ { \
+ register size_t __size = (size); \
+ register char *__a = (a), *__b = (b); \
+ do \
+ { \
+ char __tmp = *__a; \
+ *__a++ = *__b; \
+ *__b++ = __tmp; \
+ } while (--__size > 0); \
+ } while (0)
+
+/* Discontinue quicksort algorithm when partition gets below this size.
+ This particular magic number was chosen to work best on a Sun 4/260. */
+#define MAX_THRESH 4
+
+/* Stack node declarations used to store unfulfilled partition obligations. */
+typedef struct
+ {
+ char *lo;
+ char *hi;
+ } stack_node;
+
+/* The next 4 #defines implement a very fast in-line stack abstraction. */
+/* The stack needs log (total_elements) entries (we could even subtract
+ log(MAX_THRESH)). Since total_elements has type size_t, we get as
+ upper bound for log (total_elements):
+ bits per byte (CHAR_BIT) * sizeof(size_t). */
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+#define STACK_SIZE (CHAR_BIT * sizeof(size_t))
+#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
+#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi)))
+#define STACK_NOT_EMPTY (stack < top)
+
+
+/* Order size using quicksort. This implementation incorporates
+ four optimizations discussed in Sedgewick:
+
+ 1. Non-recursive, using an explicit stack of pointer that store the
+ next array partition to sort. To save time, this maximum amount
+ of space required to store an array of SIZE_MAX is allocated on the
+ stack. Assuming a 32-bit (64 bit) integer for size_t, this needs
+ only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
+ Pretty cheap, actually.
+
+ 2. Chose the pivot element using a median-of-three decision tree.
+ This reduces the probability of selecting a bad pivot value and
+ eliminates certain extraneous comparisons.
+
+ 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
+ insertion sort to order the MAX_THRESH items within each partition.
+ This is a big win, since insertion sort is faster for small, mostly
+ sorted array segments.
+
+ 4. The larger of the two sub-partitions is always pushed onto the
+ stack first, with the algorithm then concentrating on the
+ smaller partition. This *guarantees* no more than log (total_elems)
+ stack size is needed (actually O(1) in this case)! */
+
+void ldb_qsort (void *const pbase, size_t total_elems, size_t size,
+ void *opaque, ldb_qsort_cmp_fn_t cmp)
+{
+ register char *base_ptr = (char *) pbase;
+
+ const size_t max_thresh = MAX_THRESH * size;
+
+ if (total_elems == 0)
+ /* Avoid lossage with unsigned arithmetic below. */
+ return;
+
+ if (total_elems > MAX_THRESH)
+ {
+ char *lo = base_ptr;
+ char *hi = &lo[size * (total_elems - 1)];
+ stack_node stack[STACK_SIZE];
+ stack_node *top = stack;
+
+ PUSH (NULL, NULL);
+
+ while (STACK_NOT_EMPTY)
+ {
+ char *left_ptr;
+ char *right_ptr;
+
+ /* Select median value from among LO, MID, and HI. Rearrange
+ LO and HI so the three values are sorted. This lowers the
+ probability of picking a pathological pivot value and
+ skips a comparison for both the LEFT_PTR and RIGHT_PTR in
+ the while loops. */
+
+ char *mid = lo + size * ((hi - lo) / size >> 1);
+
+ if ((*cmp) ((void *) mid, (void *) lo, opaque) < 0)
+ SWAP (mid, lo, size);
+ if ((*cmp) ((void *) hi, (void *) mid, opaque) < 0)
+ SWAP (mid, hi, size);
+ else
+ goto jump_over;
+ if ((*cmp) ((void *) mid, (void *) lo, opaque) < 0)
+ SWAP (mid, lo, size);
+ jump_over:;
+
+ left_ptr = lo + size;
+ right_ptr = hi - size;
+
+ /* Here's the famous ``collapse the walls'' section of quicksort.
+ Gotta like those tight inner loops! They are the main reason
+ that this algorithm runs much faster than others. */
+ do
+ {
+ while ((*cmp) ((void *) left_ptr, (void *) mid, opaque) < 0)
+ left_ptr += size;
+
+ while ((*cmp) ((void *) mid, (void *) right_ptr, opaque) < 0)
+ right_ptr -= size;
+
+ if (left_ptr < right_ptr)
+ {
+ SWAP (left_ptr, right_ptr, size);
+ if (mid == left_ptr)
+ mid = right_ptr;
+ else if (mid == right_ptr)
+ mid = left_ptr;
+ left_ptr += size;
+ right_ptr -= size;
+ }
+ else if (left_ptr == right_ptr)
+ {
+ left_ptr += size;
+ right_ptr -= size;
+ break;
+ }
+ }
+ while (left_ptr <= right_ptr);
+
+ /* Set up pointers for next iteration. First determine whether
+ left and right partitions are below the threshold size. If so,
+ ignore one or both. Otherwise, push the larger partition's
+ bounds on the stack and continue sorting the smaller one. */
+
+ if ((size_t) (right_ptr - lo) <= max_thresh)
+ {
+ if ((size_t) (hi - left_ptr) <= max_thresh)
+ /* Ignore both small partitions. */
+ POP (lo, hi);
+ else
+ /* Ignore small left partition. */
+ lo = left_ptr;
+ }
+ else if ((size_t) (hi - left_ptr) <= max_thresh)
+ /* Ignore small right partition. */
+ hi = right_ptr;
+ else if ((right_ptr - lo) > (hi - left_ptr))
+ {
+ /* Push larger left partition indices. */
+ PUSH (lo, right_ptr);
+ lo = left_ptr;
+ }
+ else
+ {
+ /* Push larger right partition indices. */
+ PUSH (left_ptr, hi);
+ hi = right_ptr;
+ }
+ }
+ }
+
+ /* Once the BASE_PTR array is partially sorted by quicksort the rest
+ is completely sorted using insertion sort, since this is efficient
+ for partitions below MAX_THRESH size. BASE_PTR points to the beginning
+ of the array to sort, and END_PTR points at the very last element in
+ the array (*not* one beyond it!). */
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
+
+ {
+ char *const end_ptr = &base_ptr[size * (total_elems - 1)];
+ char *tmp_ptr = base_ptr;
+ char *thresh = min(end_ptr, base_ptr + max_thresh);
+ register char *run_ptr;
+
+ /* Find smallest element in first threshold and place it at the
+ array's beginning. This is the smallest array element,
+ and the operation speeds up insertion sort's inner loop. */
+
+ for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
+ if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0)
+ tmp_ptr = run_ptr;
+
+ if (tmp_ptr != base_ptr)
+ SWAP (tmp_ptr, base_ptr, size);
+
+ /* Insertion sort, running from left-hand-side up to right-hand-side. */
+
+ run_ptr = base_ptr + size;
+ while ((run_ptr += size) <= end_ptr)
+ {
+ tmp_ptr = run_ptr - size;
+ while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0)
+ tmp_ptr -= size;
+
+ tmp_ptr += size;
+ if (tmp_ptr != run_ptr)
+ {
+ char *trav;
+
+ trav = run_ptr + size;
+ while (--trav >= run_ptr)
+ {
+ char c = *trav;
+ char *hi, *lo;
+
+ for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
+ *hi = *lo;
+ *hi = c;
+ }
+ }
+ }
+ }
+}
diff --git a/source3/lib/ldb/config.guess b/source3/lib/ldb/config.guess
new file mode 100755
index 0000000000..354dbe175a
--- /dev/null
+++ b/source3/lib/ldb/config.guess
@@ -0,0 +1,1464 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+timestamp='2005-08-03'
+
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerppc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # 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 ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ 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 ;;
+ 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 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????: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 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ 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 ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep __LP64__ >/dev/null
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ x86:Interix*:[34]*)
+ echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
+ exit ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #ifdef __INTEL_COMPILER
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+ test x"${LIBC}" != x && {
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit
+ }
+ test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ 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 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *: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 ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ *86) UNAME_PROCESSOR=i686 ;;
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# 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 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+and
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/source3/lib/ldb/config.mk b/source3/lib/ldb/config.mk
new file mode 100644
index 0000000000..cd80adf721
--- /dev/null
+++ b/source3/lib/ldb/config.mk
@@ -0,0 +1,315 @@
+################################################
+# Start MODULE ldb_asq
+[MODULE::ldb_asq]
+PRIVATE_DEPENDENCIES = LIBTALLOC
+INIT_FUNCTION = ldb_asq_init
+SUBSYSTEM = ldb
+OBJ_FILES = \
+ modules/asq.o
+# End MODULE ldb_asq
+################################################
+
+################################################
+# Start MODULE ldb_server_sort
+[MODULE::ldb_server_sort]
+PRIVATE_DEPENDENCIES = LIBTALLOC
+INIT_FUNCTION = ldb_sort_init
+SUBSYSTEM = ldb
+OBJ_FILES = \
+ modules/sort.o
+# End MODULE ldb_sort
+################################################
+
+################################################
+# Start MODULE ldb_paged_results
+[MODULE::ldb_paged_results]
+INIT_FUNCTION = ldb_paged_results_init
+PRIVATE_DEPENDENCIES = LIBTALLOC
+SUBSYSTEM = ldb
+OBJ_FILES = \
+ modules/paged_results.o
+# End MODULE ldb_paged_results
+################################################
+
+################################################
+# Start MODULE ldb_paged_results
+[MODULE::ldb_paged_searches]
+INIT_FUNCTION = ldb_paged_searches_init
+PRIVATE_DEPENDENCIES = LIBTALLOC
+SUBSYSTEM = ldb
+OBJ_FILES = \
+ modules/paged_searches.o
+# End MODULE ldb_paged_results
+################################################
+
+################################################
+# Start MODULE ldb_operational
+[MODULE::ldb_operational]
+SUBSYSTEM = ldb
+PRIVATE_DEPENDENCIES = LIBTALLOC
+INIT_FUNCTION = ldb_operational_init
+OBJ_FILES = \
+ modules/operational.o
+# End MODULE ldb_operational
+################################################
+
+################################################
+# Start MODULE ldb_objectclass
+[MODULE::ldb_objectclass]
+INIT_FUNCTION = ldb_objectclass_init
+PRIVATE_DEPENDENCIES = LIBTALLOC
+SUBSYSTEM = ldb
+OBJ_FILES = \
+ modules/objectclass.o
+# End MODULE ldb_objectclass
+################################################
+
+################################################
+# Start MODULE ldb_rdn_name
+[MODULE::ldb_rdn_name]
+SUBSYSTEM = ldb
+PRIVATE_DEPENDENCIES = LIBTALLOC
+INIT_FUNCTION = ldb_rdn_name_init
+OBJ_FILES = \
+ modules/rdn_name.o
+# End MODULE ldb_rdn_name
+################################################
+
+################################################
+# Start MODULE ldb_ildap
+[MODULE::ldb_ildap]
+SUBSYSTEM = ldb
+PRIVATE_DEPENDENCIES = LIBTALLOC
+INIT_FUNCTION = ldb_ildap_init
+ALIASES = ldapi ldaps ldap
+OBJ_FILES = \
+ ldb_ildap/ldb_ildap.o
+PUBLIC_DEPENDENCIES = \
+ LIBCLI_LDAP
+# End MODULE ldb_ildap
+################################################
+
+################################################
+# Start MODULE ldb_map
+[MODULE::ldb_map]
+PRIVATE_DEPENDENCIES = LIBTALLOC
+SUBSYSTEM = ldb
+OBJ_FILES = \
+ modules/ldb_map_inbound.o \
+ modules/ldb_map_outbound.o \
+ modules/ldb_map.o
+# End MODULE ldb_map
+################################################
+
+################################################
+# Start MODULE ldb_skel
+[MODULE::ldb_skel]
+SUBSYSTEM = ldb
+PRIVATE_DEPENDENCIES = LIBTALLOC
+INIT_FUNCTION = ldb_skel_init
+OBJ_FILES = modules/skel.o
+# End MODULE ldb_skel
+################################################
+
+################################################
+# Start MODULE ldb_sqlite3
+[MODULE::ldb_sqlite3]
+SUBSYSTEM = ldb
+PRIVATE_DEPENDENCIES = LIBTALLOC
+INIT_FUNCTION = ldb_sqlite3_init
+OBJ_FILES = \
+ ldb_sqlite3/ldb_sqlite3.o
+PUBLIC_DEPENDENCIES = \
+ SQLITE3 LIBTALLOC
+# End MODULE ldb_sqlite3
+################################################
+
+################################################
+# Start MODULE ldb_tdb
+[MODULE::ldb_tdb]
+SUBSYSTEM = ldb
+INIT_FUNCTION = ldb_tdb_init
+OBJ_FILES = \
+ ldb_tdb/ldb_tdb.o \
+ ldb_tdb/ldb_search.o \
+ ldb_tdb/ldb_pack.o \
+ ldb_tdb/ldb_index.o \
+ ldb_tdb/ldb_cache.o \
+ ldb_tdb/ldb_tdb_wrap.o
+PUBLIC_DEPENDENCIES = \
+ LIBTDB LIBTALLOC
+# End MODULE ldb_tdb
+################################################
+
+./lib/ldb/common/ldb_modules.o: lib/ldb/common/ldb_modules.c Makefile
+ @echo Compiling $<
+ @$(CC) -Iinclude $(CFLAGS) -Ilib/replace -Ilib/talloc -Ilib/ldb $(PICFLAG) -DLDBMODULESDIR=\"$(MODULESDIR)/ldb\" -DSHLIBEXT=\"$(SHLIBEXT)\" -c $< -o $@
+
+################################################
+# Start SUBSYSTEM ldb
+[LIBRARY::ldb]
+VERSION = 0.0.1
+SO_VERSION = 0
+DESCRIPTION = LDAP-like embedded database library
+INIT_FUNCTION_TYPE = int (*) (void)
+OBJ_FILES = \
+ common/ldb.o \
+ common/ldb_ldif.o \
+ common/ldb_parse.o \
+ common/ldb_msg.o \
+ common/ldb_utf8.o \
+ common/ldb_debug.o \
+ common/ldb_modules.o \
+ common/ldb_match.o \
+ common/ldb_attributes.o \
+ common/attrib_handlers.o \
+ common/ldb_dn.o \
+ common/ldb_controls.o \
+ common/qsort.o
+PUBLIC_DEPENDENCIES = \
+ LIBTALLOC \
+ DYNCONFIG \
+ SOCKET_WRAPPER
+MANPAGE = man/ldb.3
+PUBLIC_HEADERS = include/ldb.h include/ldb_errors.h
+#
+# End SUBSYSTEM ldb
+################################################
+
+################################################
+# Start SUBSYSTEM LDBSAMBA
+[SUBSYSTEM::LDBSAMBA]
+PRIVATE_DEPENDENCIES = ldb
+PRIVATE_PROTO_HEADER = samba/ldif_handlers.h
+PUBLIC_DEPENDENCIES = LIBSECURITY SAMDB
+OBJ_FILES = \
+ samba/ldif_handlers.o
+# End SUBSYSTEM LDBSAMBA
+################################################
+
+################################################
+# Start SUBSYSTEM LIBLDB_CMDLINE
+[SUBSYSTEM::LIBLDB_CMDLINE]
+OBJ_FILES= \
+ tools/cmdline.o
+PUBLIC_DEPENDENCIES = ldb LIBSAMBA-UTIL LIBPOPT POPT_SAMBA POPT_CREDENTIALS
+PRIVATE_DEPENDENCIES = gensec
+# End SUBSYSTEM LIBLDB_CMDLINE
+################################################
+
+################################################
+# Start BINARY ldbadd
+[BINARY::ldbadd]
+INSTALLDIR = BINDIR
+OBJ_FILES = \
+ tools/ldbadd.o
+PRIVATE_DEPENDENCIES = \
+ LIBLDB_CMDLINE LIBCLI_RESOLVE
+MANPAGE = man/ldbadd.1
+# End BINARY ldbadd
+################################################
+
+################################################
+# Start BINARY ldbdel
+[BINARY::ldbdel]
+INSTALLDIR = BINDIR
+OBJ_FILES= \
+ tools/ldbdel.o
+PRIVATE_DEPENDENCIES = \
+ LIBLDB_CMDLINE
+MANPAGE = man/ldbdel.1
+# End BINARY ldbdel
+################################################
+
+################################################
+# Start BINARY ldbmodify
+[BINARY::ldbmodify]
+INSTALLDIR = BINDIR
+OBJ_FILES= \
+ tools/ldbmodify.o
+PRIVATE_DEPENDENCIES = \
+ LIBLDB_CMDLINE
+MANPAGE = man/ldbmodify.1
+# End BINARY ldbmodify
+################################################
+
+################################################
+# Start BINARY ldbsearch
+[BINARY::ldbsearch]
+INSTALLDIR = BINDIR
+OBJ_FILES= \
+ tools/ldbsearch.o
+PRIVATE_DEPENDENCIES = \
+ LIBLDB_CMDLINE
+MANPAGE = man/ldbsearch.1
+# End BINARY ldbsearch
+################################################
+
+################################################
+# Start BINARY ldbedit
+[BINARY::ldbedit]
+INSTALLDIR = BINDIR
+OBJ_FILES= \
+ tools/ldbedit.o
+PRIVATE_DEPENDENCIES = \
+ LIBLDB_CMDLINE
+MANPAGE = man/ldbedit.1
+# End BINARY ldbedit
+################################################
+
+################################################
+# Start BINARY ldbrename
+[BINARY::ldbrename]
+INSTALLDIR = BINDIR
+OBJ_FILES= \
+ tools/ldbrename.o
+PRIVATE_DEPENDENCIES = \
+ LIBLDB_CMDLINE
+MANPAGE = man/ldbrename.1
+# End BINARY ldbrename
+################################################
+
+################################################
+# Start BINARY ldbtest
+[BINARY::ldbtest]
+OBJ_FILES= \
+ tools/ldbtest.o
+PRIVATE_DEPENDENCIES = \
+ LIBLDB_CMDLINE
+# End BINARY ldbtest
+################################################
+
+################################################
+# Start BINARY oLschema2ldif
+[BINARY::oLschema2ldif]
+INSTALLDIR = BINDIR
+MANPAGE = man/oLschema2ldif.1
+OBJ_FILES= \
+ tools/convert.o \
+ tools/oLschema2ldif.o
+PRIVATE_DEPENDENCIES = \
+ LIBLDB_CMDLINE
+# End BINARY oLschema2ldif
+################################################
+
+################################################
+# Start BINARY ad2oLschema
+[BINARY::ad2oLschema]
+INSTALLDIR = BINDIR
+MANPAGE = man/ad2oLschema.1
+OBJ_FILES= \
+ tools/convert.o \
+ tools/ad2oLschema.o
+PRIVATE_DEPENDENCIES = \
+ LIBLDB_CMDLINE
+# End BINARY ad2oLschema
+################################################
+
+#######################
+# Start LIBRARY swig_ldb
+[LIBRARY::swig_ldb]
+PUBLIC_DEPENDENCIES = ldb DYNCONFIG
+LIBRARY_REALNAME = swig/_ldb.$(SHLIBEXT)
+OBJ_FILES = swig/ldb_wrap.o
+# End LIBRARY swig_ldb
+#######################
diff --git a/source3/lib/ldb/config.sub b/source3/lib/ldb/config.sub
new file mode 100755
index 0000000000..23cd6fd75c
--- /dev/null
+++ b/source3/lib/ldb/config.sub
@@ -0,0 +1,1577 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+timestamp='2005-07-08'
+
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \
+ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64vr | mips64vrel \
+ | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | ms1 \
+ | msp430 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b \
+ | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m32c)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | ms1-* \
+ | msp430-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ m32c-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ 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 | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16c)
+ basic_machine=cr16c-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/source3/lib/ldb/configure.ac b/source3/lib/ldb/configure.ac
new file mode 100644
index 0000000000..e1e9d49cee
--- /dev/null
+++ b/source3/lib/ldb/configure.ac
@@ -0,0 +1,74 @@
+AC_PREREQ(2.50)
+AC_DEFUN([AC_CHECK_LIB_EXT], [
+ AC_CHECK_LIB([$1],[$3],[$4],[$5],[$7])
+ ac_cv_lib_ext_$1_$3=$ac_cv_lib_$1_$3
+])
+AC_DEFUN([AC_CHECK_FUNC_EXT], [
+ AC_CHECK_FUNC([$1],[$3],[$4])
+ ac_cv_func_ext_$1=$ac_cv_func_$1
+])
+AC_DEFUN([SMB_MODULE_DEFAULT], [echo -n ""])
+AC_DEFUN([SMB_LIBRARY_ENABLE], [echo -n ""])
+AC_DEFUN([SMB_EXT_LIB], [echo -n ""])
+AC_DEFUN([SMB_ENABLE], [echo -n ""])
+AC_INIT(include/ldb.h)
+AC_CONFIG_SRCDIR([common/ldb.c])
+
+AC_LIBREPLACE_ALL_CHECKS
+
+if test "$ac_cv_prog_gcc" = yes; then
+ CFLAGS="$CFLAGS -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings"
+fi
+
+WITH_GCOV=0
+AC_ARG_ENABLE(gcov,
+ AS_HELP_STRING([--enable-gcov],[enable GCOV code coverage tests]),
+ [ WITH_GCOV=1])
+AC_SUBST(WITH_GCOV)
+if test x"$with_gcov_support" = x"yes"; then
+ CFLAGS="$CFLAGS -ftest-coverage -fprofile-arcs"
+ LIBS="$LIBS -lgcov"
+fi
+
+AC_PATH_PROG(XSLTPROC,xsltproc)
+AC_PATH_PROG(DOXYGEN,doxygen)
+AC_PATH_PROG(GCOV,gcov)
+AC_PATH_PROG(SLAPD,slapd)
+AC_CHECK_HEADERS(stdint.h dlfcn.h)
+AC_CONFIG_HEADER(include/config.h)
+AC_SEARCH_LIBS(dlopen, dl, AC_DEFINE(HAVE_DLOPEN, [1], [have dlopen]))
+
+SHLIBEXT="so" # Should be set based on OS later on
+AC_SUBST(SHLIBEXT)
+
+AC_DEFINE_UNQUOTED(MODULESDIR, LIBDIR "/ldb" , [Modules directory] )
+AC_SUBST(MODULESDIR)
+
+TESTS=""
+EXTRA_OBJ=""
+
+m4_include(libpopt.m4)
+m4_include(libtalloc.m4)
+m4_include(libtdb.m4)
+
+m4_include(ldap.m4)
+if test x"$with_ldap_support" = x"yes"; then
+ LIBS="$LIBS -llber -lldap"
+ CFLAGS="$CFLAGS -DHAVE_LDB_LDAP=1"
+ EXTRA_OBJ="$EXTRA_OBJ ldb_ldap/ldb_ldap.o"
+ TESTS="$TESTS test-ldap.sh"
+fi
+
+m4_include(sqlite3.m4)
+if test x"$with_sqlite3_support" = x"yes"; then
+ LIBS="$LIBS -lsqlite3"
+ CFLAGS="$CFLAGS -DHAVE_LDB_SQLITE3=1"
+ EXTRA_OBJ="$EXTRA_OBJ ldb_sqlite3/ldb_sqlite3.o"
+ TESTS="$TESTS test-sqlite3.sh"
+fi
+
+AC_SUBST(TESTS)
+AC_SUBST(EXTRA_OBJ)
+
+m4_include(libldb.m4)
+AC_OUTPUT(Makefile ldb.pc)
diff --git a/source3/lib/ldb/docs/builddocs.sh b/source3/lib/ldb/docs/builddocs.sh
new file mode 100755
index 0000000000..449dcb2681
--- /dev/null
+++ b/source3/lib/ldb/docs/builddocs.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# build ldb docs
+# tridge@samba.org August 2006
+
+XSLTPROC="$1"
+SRCDIR="$2"
+
+if [ -z "$XSLTPROC" ] || [ ! -x "$XSLTPROC" ]; then
+ echo "xsltproc not installed"
+ exit 0
+fi
+
+MANXSL="http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl"
+HTMLXSL="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"
+
+mkdir -p man
+
+for f in $SRCDIR/man/*.xml; do
+ base=`basename $f .xml`
+ out=man/"`basename $base`"
+ if [ ! -f "$out" ] || [ "$f" -nt "$out" ]; then
+ echo Processing manpage $f
+ $XSLTPROC --nonet -o "$out" "$MANXSL" $f
+ ret=$?
+ if [ "$ret" = "4" ]; then
+ echo "ignoring stylesheet error 4 for $MANXSL"
+ exit 0
+ fi
+ if [ "$ret" != "0" ]; then
+ echo "xsltproc failed with error $ret"
+ exit $ret
+ fi
+ fi
+done
+
+for f in $SRCDIR/man/*.xml; do
+ base=`basename $f .xml`
+ out=man/"`basename $base`".html
+ if [ ! -f "$out" ] || [ "$f" -nt "$out" ]; then
+ echo Processing html $f
+ $XSLTPROC --nonet -o "$out" "$HTMLXSL" $f
+ ret=$?
+ if [ "$ret" = "4" ]; then
+ echo "ignoring stylesheet error 4 for $HTMLXSL"
+ exit 0
+ fi
+ if [ "$ret" != "0" ]; then
+ echo "xsltproc failed with error $ret"
+ exit $ret
+ fi
+ fi
+done
diff --git a/source3/lib/ldb/docs/design.txt b/source3/lib/ldb/docs/design.txt
new file mode 100644
index 0000000000..0bb278b5b4
--- /dev/null
+++ b/source3/lib/ldb/docs/design.txt
@@ -0,0 +1,41 @@
+The list of indexed fields
+--------------------------
+
+dn=@INDEXLIST
+ list of field names that are indexed
+
+ contains fields of type @IDXATTR which contain attriute names
+ of indexed fields
+
+
+Data records
+------------
+
+for each user record in the db there is:
+ main record
+ key: DN=dn
+ data: packed attribute/value list
+
+ a index record for each indexed field in the record
+
+
+Index Records
+-------------
+
+The index records contain the list of dn's that contain records
+matching the index key
+
+All index records are of the form:
+ dn=@INDEX:field:value
+
+and contain fields of type @IDX which are the dns of the records
+that have that value for some attribute
+
+
+Search Expressions
+------------------
+
+Very similar to LDAP search expressions, but does not allow ~=, <= or >=
+
+ attrib0 := (field=value)
+ attrib := attrib0 | (attrib&&attrib) | (attrib||attrib) | !attrib
diff --git a/source3/lib/ldb/docs/installdocs.sh b/source3/lib/ldb/docs/installdocs.sh
new file mode 100755
index 0000000000..6cc7b74ad5
--- /dev/null
+++ b/source3/lib/ldb/docs/installdocs.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+# install ldb docs
+# tridge@samba.org August 2006
+
+MANDIR="$1"
+
+MAN1="`/bin/ls man/*.1`"
+MAN3="`/bin/ls man/*.3`"
+
+if [ -z "$MAN1" ] && [ -z "$MAN3" ]; then
+ echo "No manpages have been built"
+ exit 0
+fi
+
+mkdir -p "$MANDIR/man1" "$MANDIR/man3"
+cp $MAN1 "$MANDIR/man1/" || exit 1
+cp $MAN3 "$MANDIR/man3/" || exit 1
diff --git a/source3/lib/ldb/examples.dox b/source3/lib/ldb/examples.dox
new file mode 100644
index 0000000000..ef4b4f0a40
--- /dev/null
+++ b/source3/lib/ldb/examples.dox
@@ -0,0 +1,16 @@
+/** \example ldbreader.c
+
+The code below shows a simple LDB application.
+
+It lists / dumps the records in a LDB database to standard output.
+
+*/
+
+
+/** \example ldifreader.c
+
+The code below shows a simple LDB application.
+
+It lists / dumps the entries in an LDIF file to standard output.
+
+*/
diff --git a/source3/lib/ldb/examples/ldbreader.c b/source3/lib/ldb/examples/ldbreader.c
new file mode 100644
index 0000000000..baf0e9ab65
--- /dev/null
+++ b/source3/lib/ldb/examples/ldbreader.c
@@ -0,0 +1,123 @@
+/*
+ example code for the ldb database library
+
+ Copyright (C) Brad Hards (bradh@frogmouth.net) 2005-2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/** \example ldbreader.c
+
+The code below shows a simple LDB application.
+
+It lists / dumps the records in a LDB database to standard output.
+
+*/
+
+#include "includes.h"
+#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_errors.h"
+
+/*
+ ldb_ldif_write takes a function pointer to a custom output
+ function. This version is about as simple as the output function can
+ be. In a more complex example, you'd likely be doing something with
+ the private data function (e.g. holding a file handle).
+*/
+static int vprintf_fn(void *private_data, const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ va_start(ap, fmt);
+ /* We just write to standard output */
+ retval = vprintf(fmt, ap);
+ va_end(ap);
+ /* Note that the function should return the number of
+ bytes written, or a negative error code */
+ return retval;
+}
+
+int main(int argc, const char **argv)
+{
+ struct ldb_context *ldb;
+ const char *expression = "(dn=*)";
+ struct ldb_result *resultMsg;
+ int i;
+
+ /*
+ This is the always the first thing you want to do in an LDB
+ application - initialise up the context structure.
+
+ Note that you can use the context structure as a parent
+ for talloc allocations as well
+ */
+ ldb = ldb_init(NULL);
+
+ /*
+ We now open the database. In this example we just hard code the connection path.
+
+ Also note that the database is being opened read-only. This means that the
+ call will fail unless the database already exists.
+ */
+ if (LDB_SUCCESS != ldb_connect(ldb, "tdb://tdbtest.ldb", LDB_FLG_RDONLY, NULL) ){
+ printf("Problem on connection\n");
+ exit(-1);
+ }
+
+ /*
+ At this stage we have an open database, and can start using it. It is opened
+ read-only, so a query is possible.
+
+ We construct a search that just returns all the (sensible) contents. You can do
+ quite fine grained results with the LDAP search syntax, however it is a bit
+ confusing to start with. See RFC2254.
+ */
+ if (LDB_SUCCESS != ldb_search(ldb, NULL, LDB_SCOPE_DEFAULT,
+ expression, NULL, &resultMsg) ) {
+ printf("Problem in search\n");
+ exit(-1);
+ }
+
+ printf("%i records returned\n", resultMsg->count);
+
+ /*
+ We can now iterate through the results, writing them out
+ (to standard output) with our custom output routine as defined
+ at the top of this file
+ */
+ for (i = 0; i < resultMsg->count; ++i) {
+ struct ldb_ldif ldifMsg;
+
+ printf("Message: %i\n", i+1);
+
+ ldifMsg.changetype = LDB_CHANGETYPE_NONE;
+ ldifMsg.msg = resultMsg->msgs[i];
+ ldb_ldif_write(ldb, vprintf_fn, NULL, &ldifMsg);
+ }
+
+ /*
+ There are two objects to clean up - the result from the
+ ldb_search() query, and the original ldb context.
+ */
+ talloc_free(resultMsg);
+
+ talloc_free(ldb);
+
+ return 0;
+}
diff --git a/source3/lib/ldb/examples/ldifreader.c b/source3/lib/ldb/examples/ldifreader.c
new file mode 100644
index 0000000000..0c7e876465
--- /dev/null
+++ b/source3/lib/ldb/examples/ldifreader.c
@@ -0,0 +1,127 @@
+/*
+ example code for the ldb database library
+
+ Copyright (C) Brad Hards (bradh@frogmouth.net) 2005-2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/** \example ldifreader.c
+
+The code below shows a simple LDB application.
+
+It lists / dumps the entries in an LDIF file to standard output.
+
+*/
+
+#include "includes.h"
+#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_errors.h"
+
+/*
+ ldb_ldif_write takes a function pointer to a custom output
+ function. This version is about as simple as the output function can
+ be. In a more complex example, you'd likely be doing something with
+ the private data function (e.g. holding a file handle).
+*/
+static int vprintf_fn(void *private_data, const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ va_start(ap, fmt);
+ /* We just write to standard output */
+ retval = vprintf(fmt, ap);
+ va_end(ap);
+ /* Note that the function should return the number of
+ bytes written, or a negative error code */
+ return retval;
+}
+
+int main(int argc, const char **argv)
+{
+ struct ldb_context *ldb;
+ FILE *fileStream;
+ struct ldb_ldif *ldifMsg;
+
+ if (argc != 2) {
+ printf("Usage %s filename.ldif\n", argv[0]);
+ exit(1);
+ }
+
+ /*
+ This is the always the first thing you want to do in an LDB
+ application - initialise up the context structure.
+
+ Note that you can use the context structure as a parent
+ for talloc allocations as well
+ */
+ ldb = ldb_init(NULL);
+
+ fileStream = fopen(argv[1], "r");
+ if (0 == fileStream) {
+ perror(argv[1]);
+ exit(1);
+ }
+
+ /*
+ We now work through the filestream to get each entry.
+ */
+ while ( (ldifMsg = ldb_ldif_read_file(ldb, fileStream)) ) {
+ /*
+ Each message has a particular change type. For Add,
+ Modify and Delete, this will also appear in the
+ output listing (as changetype: add, changetype:
+ modify or changetype:delete, respectively).
+ */
+ switch (ldifMsg->changetype) {
+ case LDB_CHANGETYPE_NONE:
+ printf("ChangeType: None\n");
+ break;
+ case LDB_CHANGETYPE_ADD:
+ printf("ChangeType: Add\n");
+ break;
+ case LDB_CHANGETYPE_MODIFY:
+ printf("ChangeType: Modify\n");
+ break;
+ case LDB_CHANGETYPE_DELETE:
+ printf("ChangeType: Delete\n");
+ break;
+ default:
+ printf("ChangeType: Unknown\n");
+ }
+
+ /*
+ We can now write out the results, using our custom
+ output routine as defined at the top of this file.
+ */
+ ldb_ldif_write(ldb, vprintf_fn, NULL, ldifMsg);
+
+ /*
+ Clean up the message
+ */
+ ldb_ldif_read_free(ldb, ldifMsg);
+ }
+
+ /*
+ Clean up the context
+ */
+ talloc_free(ldb);
+
+ return 0;
+}
diff --git a/source3/lib/ldb/include/dlinklist.h b/source3/lib/ldb/include/dlinklist.h
new file mode 100644
index 0000000000..d3252751db
--- /dev/null
+++ b/source3/lib/ldb/include/dlinklist.h
@@ -0,0 +1,110 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* 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) \
+do { \
+ if (!(list)) { \
+ (list) = (p); \
+ (p)->next = (p)->prev = NULL; \
+ } else { \
+ (list)->prev = (p); \
+ (p)->next = (list); \
+ (p)->prev = NULL; \
+ (list) = (p); \
+ }\
+} while (0)
+
+/* remove an element from a list - element doesn't have to be in list. */
+#ifndef DLIST_REMOVE
+#define DLIST_REMOVE(list, p) \
+do { \
+ if ((p) == (list)) { \
+ (list) = (p)->next; \
+ if (list) (list)->prev = NULL; \
+ } else { \
+ if ((p)->prev) (p)->prev->next = (p)->next; \
+ if ((p)->next) (p)->next->prev = (p)->prev; \
+ } \
+ if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
+} while (0)
+#endif
+
+/* promote an element to the top of the list */
+#define DLIST_PROMOTE(list, p) \
+do { \
+ DLIST_REMOVE(list, p); \
+ DLIST_ADD(list, p); \
+} while (0)
+
+/* hook into the end of the list - needs a tmp pointer */
+#define DLIST_ADD_END(list, p, type) \
+do { \
+ if (!(list)) { \
+ (list) = (p); \
+ (p)->next = (p)->prev = NULL; \
+ } else { \
+ type tmp; \
+ for (tmp = (list); tmp->next; tmp = tmp->next) ; \
+ tmp->next = (p); \
+ (p)->next = NULL; \
+ (p)->prev = tmp; \
+ } \
+} while (0)
+
+/* insert 'p' after the given element 'el' in a list. If el is NULL then
+ this is the same as a DLIST_ADD() */
+#define DLIST_ADD_AFTER(list, p, el) \
+do { \
+ if (!(list) || !(el)) { \
+ DLIST_ADD(list, p); \
+ } else { \
+ p->prev = el; \
+ p->next = el->next; \
+ el->next = p; \
+ if (p->next) p->next->prev = p; \
+ }\
+} while (0)
+
+/* demote an element to the end of the list, needs a tmp pointer */
+#define DLIST_DEMOTE(list, p, tmp) \
+do { \
+ DLIST_REMOVE(list, p); \
+ DLIST_ADD_END(list, p, tmp); \
+} while (0)
+
+/* concatenate two lists - putting all elements of the 2nd list at the
+ end of the first list */
+#define DLIST_CONCATENATE(list1, list2, type) \
+do { \
+ if (!(list1)) { \
+ (list1) = (list2); \
+ } else { \
+ type tmp; \
+ for (tmp = (list1); tmp->next; tmp = tmp->next) ; \
+ tmp->next = (list2); \
+ if (list2) { \
+ (list2)->prev = tmp; \
+ } \
+ } \
+} while (0)
diff --git a/source3/lib/ldb/include/includes.h b/source3/lib/ldb/include/includes.h
new file mode 100644
index 0000000000..e2bcca2b04
--- /dev/null
+++ b/source3/lib/ldb/include/includes.h
@@ -0,0 +1,29 @@
+#ifndef _LDB_PRIVATE_INCLUDES_H_
+#define _LDB_PRIVATE_INCLUDES_H_
+/*
+ a temporary includes file until I work on the ldb build system
+*/
+
+#if (_SAMBA_BUILD_ >= 4)
+/* tell ldb we have the internal ldap code */
+#define HAVE_ILDAP 1
+#endif
+
+#if (_SAMBA_BUILD_ <= 3)
+/* allow forbidden string functions - should be replaced with _m functions */
+#undef strcasecmp
+#undef strncasecmp
+#define dyn_MODULESDIR dyn_LIBDIR
+#endif
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/network.h"
+#include "system/time.h"
+#include "talloc.h"
+#include "ldb.h"
+#include "ldb_errors.h"
+#include "ldb_private.h"
+#include "dlinklist.h"
+
+#endif /*_LDB_PRIVATE_INCLUDES_H_*/
diff --git a/source3/lib/ldb/include/ldb.h b/source3/lib/ldb/include/ldb.h
new file mode 100644
index 0000000000..0a745742d9
--- /dev/null
+++ b/source3/lib/ldb/include/ldb.h
@@ -0,0 +1,1560 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Simo Sorce 2005-2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb header
+ *
+ * Description: defines for base ldb API
+ *
+ * Author: Andrew Tridgell
+ * Author: Stefan Metzmacher
+ */
+
+/**
+ \file ldb.h Samba's ldb database
+
+ This header file provides the main API for ldb.
+*/
+
+#ifndef _LDB_H_
+
+/*! \cond DOXYGEN_IGNORE */
+#define _LDB_H_ 1
+/*! \endcond */
+
+/*
+ major restrictions as compared to normal LDAP:
+
+ - no async calls.
+ - each record must have a unique key field
+ - the key must be representable as a NULL terminated C string and may not
+ contain a comma or braces
+
+ major restrictions as compared to tdb:
+
+ - no explicit locking calls
+ UPDATE: we have transactions now, better than locking --SSS.
+
+*/
+
+#ifndef ldb_val
+/**
+ Result value
+
+ An individual lump of data in a result comes in this format. The
+ pointer will usually be to a UTF-8 string if the application is
+ sensible, but it can be to anything you like, including binary data
+ blobs of arbitrary size.
+
+ \note the data is null (0x00) terminated, but the length does not
+ include the terminator.
+*/
+struct ldb_val {
+ uint8_t *data; /*!< result data */
+ size_t length; /*!< length of data */
+};
+#endif
+
+/*! \cond DOXYGEN_IGNORE */
+#ifndef PRINTF_ATTRIBUTE
+#define PRINTF_ATTRIBUTE(a,b)
+#endif
+/*! \endcond */
+
+/* opaque ldb_dn structures, see ldb_dn.c for internals */
+struct ldb_dn_component;
+struct ldb_dn;
+
+/**
+ There are a number of flags that are used with ldap_modify() in
+ ldb_message_element.flags fields. The LDA_FLAGS_MOD_ADD,
+ LDA_FLAGS_MOD_DELETE and LDA_FLAGS_MOD_REPLACE flags are used in
+ ldap_modify() calls to specify whether attributes are being added,
+ deleted or modified respectively.
+*/
+#define LDB_FLAG_MOD_MASK 0x3
+
+/**
+ Flag value used in ldap_modify() to indicate that attributes are
+ being added.
+
+ \sa LDB_FLAG_MOD_MASK
+*/
+#define LDB_FLAG_MOD_ADD 1
+
+/**
+ Flag value used in ldap_modify() to indicate that attributes are
+ being replaced.
+
+ \sa LDB_FLAG_MOD_MASK
+*/
+#define LDB_FLAG_MOD_REPLACE 2
+
+/**
+ Flag value used in ldap_modify() to indicate that attributes are
+ being deleted.
+
+ \sa LDB_FLAG_MOD_MASK
+*/
+#define LDB_FLAG_MOD_DELETE 3
+
+/**
+ OID for logic AND comaprison.
+
+ This is the well known object ID for a logical AND comparitor.
+*/
+#define LDB_OID_COMPARATOR_AND "1.2.840.113556.1.4.803"
+
+/**
+ OID for logic OR comparison.
+
+ This is the well known object ID for a logical OR comparitor.
+*/
+#define LDB_OID_COMPARATOR_OR "1.2.840.113556.1.4.804"
+
+/**
+ results are given back as arrays of ldb_message_element
+*/
+struct ldb_message_element {
+ unsigned int flags;
+ const char *name;
+ unsigned int num_values;
+ struct ldb_val *values;
+};
+
+
+/**
+ a ldb_message represents all or part of a record. It can contain an arbitrary
+ number of elements.
+*/
+struct ldb_message {
+ struct ldb_dn *dn;
+ unsigned int num_elements;
+ struct ldb_message_element *elements;
+ void *private_data; /* private to the backend */
+};
+
+enum ldb_changetype {
+ LDB_CHANGETYPE_NONE=0,
+ LDB_CHANGETYPE_ADD,
+ LDB_CHANGETYPE_DELETE,
+ LDB_CHANGETYPE_MODIFY
+};
+
+/**
+ LDIF record
+
+ This structure contains a LDIF record, as returned from ldif_read()
+ and equivalent functions.
+*/
+struct ldb_ldif {
+ enum ldb_changetype changetype; /*!< The type of change */
+ struct ldb_message *msg; /*!< The changes */
+};
+
+enum ldb_scope {LDB_SCOPE_DEFAULT=-1,
+ LDB_SCOPE_BASE=0,
+ LDB_SCOPE_ONELEVEL=1,
+ LDB_SCOPE_SUBTREE=2};
+
+struct ldb_context;
+
+/* debugging uses one of the following levels */
+enum ldb_debug_level {LDB_DEBUG_FATAL, LDB_DEBUG_ERROR,
+ LDB_DEBUG_WARNING, LDB_DEBUG_TRACE};
+
+/**
+ the user can optionally supply a debug function. The function
+ is based on the vfprintf() style of interface, but with the addition
+ of a severity level
+*/
+struct ldb_debug_ops {
+ void (*debug)(void *context, enum ldb_debug_level level,
+ const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
+ void *context;
+};
+
+/**
+ The user can optionally supply a custom utf8 functions,
+ to handle comparisons and casefolding.
+*/
+struct ldb_utf8_fns {
+ void *context;
+ char *(*casefold)(void *context, void *mem_ctx, const char *s);
+};
+
+/**
+ Flag value for database connection mode.
+
+ If LDB_FLG_RDONLY is used in ldb_connect, then the database will be
+ opened read-only, if possible.
+*/
+#define LDB_FLG_RDONLY 1
+
+/**
+ Flag value for database connection mode.
+
+ If LDB_FLG_NOSYNC is used in ldb_connect, then the database will be
+ opened without synchronous operations, if possible.
+*/
+#define LDB_FLG_NOSYNC 2
+
+/**
+ Flag value to specify autoreconnect mode.
+
+ If LDB_FLG_RECONNECT is used in ldb_connect, then the backend will
+ be opened in a way that makes it try to auto reconnect if the
+ connection is dropped (actually make sense only with ldap).
+*/
+#define LDB_FLG_RECONNECT 4
+
+/**
+ Flag to tell backends not to use mmap
+*/
+#define LDB_FLG_NOMMAP 8
+
+/*
+ structures for ldb_parse_tree handling code
+*/
+enum ldb_parse_op { LDB_OP_AND=1, LDB_OP_OR=2, LDB_OP_NOT=3,
+ LDB_OP_EQUALITY=4, LDB_OP_SUBSTRING=5,
+ LDB_OP_GREATER=6, LDB_OP_LESS=7, LDB_OP_PRESENT=8,
+ LDB_OP_APPROX=9, LDB_OP_EXTENDED=10 };
+
+struct ldb_parse_tree {
+ enum ldb_parse_op operation;
+ union {
+ struct {
+ struct ldb_parse_tree *child;
+ } isnot;
+ struct {
+ const char *attr;
+ struct ldb_val value;
+ } equality;
+ struct {
+ const char *attr;
+ int start_with_wildcard;
+ int end_with_wildcard;
+ struct ldb_val **chunks;
+ } substring;
+ struct {
+ const char *attr;
+ } present;
+ struct {
+ const char *attr;
+ struct ldb_val value;
+ } comparison;
+ struct {
+ const char *attr;
+ int dnAttributes;
+ char *rule_id;
+ struct ldb_val value;
+ } extended;
+ struct {
+ unsigned int num_elements;
+ struct ldb_parse_tree **elements;
+ } list;
+ } u;
+};
+
+struct ldb_parse_tree *ldb_parse_tree(void *mem_ctx, const char *s);
+char *ldb_filter_from_tree(void *mem_ctx, struct ldb_parse_tree *tree);
+
+/**
+ Encode a binary blob
+
+ This function encodes a binary blob using the encoding rules in RFC
+ 2254 (Section 4). This function also escapes any non-printable
+ characters.
+
+ \param ctx the memory context to allocate the return string in.
+ \param val the (potentially) binary data to be encoded
+
+ \return the encoded data as a null terminated string
+
+ \sa <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>.
+*/
+char *ldb_binary_encode(void *ctx, struct ldb_val val);
+
+/**
+ Encode a string
+
+ This function encodes a string using the encoding rules in RFC 2254
+ (Section 4). This function also escapes any non-printable
+ characters.
+
+ \param mem_ctx the memory context to allocate the return string in.
+ \param string the string to be encoded
+
+ \return the encoded data as a null terminated string
+
+ \sa <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>.
+*/
+char *ldb_binary_encode_string(void *mem_ctx, const char *string);
+
+/*
+ functions for controlling attribute handling
+*/
+typedef int (*ldb_attr_handler_t)(struct ldb_context *, void *mem_ctx, const struct ldb_val *, struct ldb_val *);
+typedef int (*ldb_attr_comparison_t)(struct ldb_context *, void *mem_ctx, const struct ldb_val *, const struct ldb_val *);
+
+/*
+ attribute handler structure
+
+ attr -> The attribute name
+ flags -> LDB_ATTR_FLAG_*
+ ldif_read_fn -> convert from ldif to binary format
+ ldif_write_fn -> convert from binary to ldif format
+ canonicalise_fn -> canonicalise a value, for use by indexing and dn construction
+ comparison_fn -> compare two values
+*/
+
+struct ldb_attrib_handler {
+
+ const char *attr;
+ unsigned flags;
+
+ ldb_attr_handler_t ldif_read_fn;
+ ldb_attr_handler_t ldif_write_fn;
+ ldb_attr_handler_t canonicalise_fn;
+ ldb_attr_comparison_t comparison_fn;
+};
+
+/**
+ The attribute is not returned by default
+*/
+#define LDB_ATTR_FLAG_HIDDEN (1<<0)
+
+/* the attribute handler name should be freed when released */
+#define LDB_ATTR_FLAG_ALLOCATED (1<<1)
+
+/**
+ The attribute is constructed from other attributes
+*/
+#define LDB_ATTR_FLAG_CONSTRUCTED (1<<1)
+
+/**
+ LDAP attribute syntax for a DN
+
+ This is the well-known LDAP attribute syntax for a DN.
+
+ See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+*/
+#define LDB_SYNTAX_DN "1.3.6.1.4.1.1466.115.121.1.12"
+
+/**
+ LDAP attribute syntax for a Directory String
+
+ This is the well-known LDAP attribute syntax for a Directory String.
+
+ \sa <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+*/
+#define LDB_SYNTAX_DIRECTORY_STRING "1.3.6.1.4.1.1466.115.121.1.15"
+
+/**
+ LDAP attribute syntax for an integer
+
+ This is the well-known LDAP attribute syntax for an integer.
+
+ See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+*/
+#define LDB_SYNTAX_INTEGER "1.3.6.1.4.1.1466.115.121.1.27"
+
+/**
+ LDAP attribute syntax for an octet string
+
+ This is the well-known LDAP attribute syntax for an octet string.
+
+ See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+*/
+#define LDB_SYNTAX_OCTET_STRING "1.3.6.1.4.1.1466.115.121.1.40"
+
+/**
+ LDAP attribute syntax for UTC time.
+
+ This is the well-known LDAP attribute syntax for a UTC time.
+
+ See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+*/
+#define LDB_SYNTAX_UTC_TIME "1.3.6.1.4.1.1466.115.121.1.53"
+
+#define LDB_SYNTAX_OBJECTCLASS "LDB_SYNTAX_OBJECTCLASS"
+
+/* sorting helpers */
+typedef int (*ldb_qsort_cmp_fn_t) (void *v1, void *v2, void *opaque);
+
+/**
+ OID for the paged results control. This control is included in the
+ searchRequest and searchResultDone messages as part of the controls
+ field of the LDAPMessage, as defined in Section 4.1.12 of
+ LDAP v3.
+
+ \sa <a href="http://www.ietf.org/rfc/rfc2696.txt">RFC 2696</a>.
+*/
+#define LDB_CONTROL_PAGED_RESULTS_OID "1.2.840.113556.1.4.319"
+
+/**
+ OID for specifying the returned elements of the ntSecurityDescriptor
+
+ \sa <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap_server_sd_flags_oid.asp">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_SD_FLAGS_OID "1.2.840.113556.1.4.801"
+
+/**
+ OID for specifying an advanced scope for the search (one partition)
+
+ \sa <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap_server_domain_scope_oid.asp">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_DOMAIN_SCOPE_OID "1.2.840.113556.1.4.1339"
+
+/**
+ OID for specifying an advanced scope for a search
+
+ \sa <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap_server_search_options_oid.asp">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_SEARCH_OPTIONS_OID "1.2.840.113556.1.4.1340"
+
+/**
+ OID for notification
+
+ \sa <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap_server_notification_oid.asp">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_NOTIFICATION_OID "1.2.840.113556.1.4.528"
+
+/**
+ OID for getting deleted objects
+
+ \sa <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap_server_show_deleted_oid.asp">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_SHOW_DELETED_OID "1.2.840.113556.1.4.417"
+
+/**
+ OID for extended DN
+
+ \sa <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap_server_extended_dn_oid.asp">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_EXTENDED_DN_OID "1.2.840.113556.1.4.529"
+
+/**
+ OID for LDAP server sort result extension.
+
+ This control is included in the searchRequest message as part of
+ the controls field of the LDAPMessage, as defined in Section 4.1.12
+ of LDAP v3. The controlType is set to
+ "1.2.840.113556.1.4.473". The criticality MAY be either TRUE or
+ FALSE (where absent is also equivalent to FALSE) at the client's
+ option.
+
+ \sa <a href="http://www.ietf.org/rfc/rfc2891.txt">RFC 2891</a>.
+*/
+#define LDB_CONTROL_SERVER_SORT_OID "1.2.840.113556.1.4.473"
+
+/**
+ OID for LDAP server sort result response extension.
+
+ This control is included in the searchResultDone message as part of
+ the controls field of the LDAPMessage, as defined in Section 4.1.12 of
+ LDAP v3.
+
+ \sa <a href="http://www.ietf.org/rfc/rfc2891.txt">RFC 2891</a>.
+*/
+#define LDB_CONTROL_SORT_RESP_OID "1.2.840.113556.1.4.474"
+
+/**
+ OID for LDAP Attribute Scoped Query extension.
+
+ This control is included in SearchRequest or SearchResponse
+ messages as part of the controls field of the LDAPMessage.
+*/
+#define LDB_CONTROL_ASQ_OID "1.2.840.113556.1.4.1504"
+
+/**
+ OID for LDAP Directory Sync extension.
+
+ This control is included in SearchRequest or SearchResponse
+ messages as part of the controls field of the LDAPMessage.
+*/
+#define LDB_CONTROL_DIRSYNC_OID "1.2.840.113556.1.4.841"
+
+
+/**
+ OID for LDAP Virtual List View Request extension.
+
+ This control is included in SearchRequest messages
+ as part of the controls field of the LDAPMessage.
+*/
+#define LDB_CONTROL_VLV_REQ_OID "2.16.840.1.113730.3.4.9"
+
+/**
+ OID for LDAP Virtual List View Response extension.
+
+ This control is included in SearchResponse messages
+ as part of the controls field of the LDAPMessage.
+*/
+#define LDB_CONTROL_VLV_RESP_OID "2.16.840.1.113730.3.4.10"
+
+/**
+ OID to let modifies don't give an error when adding an existing
+ attribute with the same value or deleting an nonexisting one attribute
+
+ \sa <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap_server_permissive_modify_oid.asp">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_PERMISSIVE_MODIFY_OID "1.2.840.113556.1.4.1413"
+
+/**
+ OID for LDAP Extended Operation START_TLS.
+
+ This Extended operation is used to start a new TLS
+ channel on top of a clear text channel.
+*/
+#define LDB_EXTENDED_START_TLS_OID "1.3.6.1.4.1.1466.20037"
+
+/**
+ OID for LDAP Extended Operation START_TLS.
+
+ This Extended operation is used to start a new TLS
+ channel on top of a clear text channel.
+*/
+#define LDB_EXTENDED_DYNAMIC_OID "1.3.6.1.4.1.1466.101.119.1"
+
+/**
+ OID for LDAP Extended Operation START_TLS.
+
+ This Extended operation is used to start a new TLS
+ channel on top of a clear text channel.
+*/
+#define LDB_EXTENDED_FAST_BIND_OID "1.2.840.113556.1.4.1781"
+
+struct ldb_sd_flags_control {
+ /*
+ * request the owner 0x00000001
+ * request the group 0x00000002
+ * request the DACL 0x00000004
+ * request the SACL 0x00000008
+ */
+ unsigned secinfo_flags;
+};
+
+struct ldb_search_options_control {
+ /*
+ * DOMAIN_SCOPE 0x00000001
+ * this limits the search to one partition,
+ * and no referrals will be returned.
+ * (Note this doesn't limit the entries by there
+ * objectSid belonging to a domain! Builtin and Foreign Sids
+ * are still returned)
+ *
+ * PHANTOM_ROOT 0x00000002
+ * this search on the whole tree on a domain controller
+ * over multiple partitions without referrals.
+ * (This is the default behavior on the Global Catalog Port)
+ */
+ unsigned search_options;
+};
+
+struct ldb_paged_control {
+ int size;
+ int cookie_len;
+ char *cookie;
+};
+
+struct ldb_extended_dn_control {
+ int type;
+};
+
+struct ldb_server_sort_control {
+ char *attributeName;
+ char *orderingRule;
+ int reverse;
+};
+
+struct ldb_sort_resp_control {
+ int result;
+ char *attr_desc;
+};
+
+struct ldb_asq_control {
+ int request;
+ char *source_attribute;
+ int src_attr_len;
+ int result;
+};
+
+struct ldb_dirsync_control {
+ int flags;
+ int max_attributes;
+ int cookie_len;
+ char *cookie;
+};
+
+struct ldb_vlv_req_control {
+ int beforeCount;
+ int afterCount;
+ int type;
+ union {
+ struct {
+ int offset;
+ int contentCount;
+ } byOffset;
+ struct {
+ int value_len;
+ char *value;
+ } gtOrEq;
+ } match;
+ int ctxid_len;
+ char *contextId;
+};
+
+struct ldb_vlv_resp_control {
+ int targetPosition;
+ int contentCount;
+ int vlv_result;
+ int ctxid_len;
+ char *contextId;
+};
+
+struct ldb_control {
+ const char *oid;
+ int critical;
+ void *data;
+};
+
+enum ldb_request_type {
+ LDB_SEARCH,
+ LDB_ADD,
+ LDB_MODIFY,
+ LDB_DELETE,
+ LDB_RENAME,
+ LDB_EXTENDED,
+ LDB_REQ_REGISTER_CONTROL,
+ LDB_REQ_REGISTER_PARTITION,
+ LDB_SEQUENCE_NUMBER
+};
+
+enum ldb_reply_type {
+ LDB_REPLY_ENTRY,
+ LDB_REPLY_REFERRAL,
+ LDB_REPLY_EXTENDED,
+ LDB_REPLY_DONE
+};
+
+enum ldb_wait_type {
+ LDB_WAIT_ALL,
+ LDB_WAIT_NONE
+};
+
+enum ldb_state {
+ LDB_ASYNC_INIT,
+ LDB_ASYNC_PENDING,
+ LDB_ASYNC_DONE
+};
+
+struct ldb_result {
+ unsigned int count;
+ struct ldb_message **msgs;
+ char **refs;
+ struct ldb_control **controls;
+};
+
+struct ldb_extended {
+ const char *oid;
+ const char *value;
+ int value_len;
+};
+
+struct ldb_reply {
+ enum ldb_reply_type type;
+ struct ldb_message *message;
+ struct ldb_extended *response;
+ char *referral;
+ struct ldb_control **controls;
+};
+
+struct ldb_handle {
+ int status;
+ enum ldb_state state;
+ void *private_data;
+ struct ldb_module *module;
+};
+
+struct ldb_search {
+ const struct ldb_dn *base;
+ enum ldb_scope scope;
+ const struct ldb_parse_tree *tree;
+ const char * const *attrs;
+ struct ldb_result *res;
+};
+
+struct ldb_add {
+ const struct ldb_message *message;
+};
+
+struct ldb_modify {
+ const struct ldb_message *message;
+};
+
+struct ldb_delete {
+ const struct ldb_dn *dn;
+};
+
+struct ldb_rename {
+ const struct ldb_dn *olddn;
+ const struct ldb_dn *newdn;
+};
+
+struct ldb_register_control {
+ const char *oid;
+};
+
+struct ldb_register_partition {
+ const struct ldb_dn *dn;
+};
+
+struct ldb_sequence_number {
+ enum ldb_sequence_type {
+ LDB_SEQ_HIGHEST_SEQ,
+ LDB_SEQ_HIGHEST_TIMESTAMP,
+ LDB_SEQ_NEXT
+ } type;
+ uint64_t seq_num;
+ uint32_t flags;
+};
+
+typedef int (*ldb_request_callback_t)(struct ldb_context *, void *, struct ldb_reply *);
+struct ldb_request {
+
+ enum ldb_request_type operation;
+
+ union {
+ struct ldb_search search;
+ struct ldb_add add;
+ struct ldb_modify mod;
+ struct ldb_delete del;
+ struct ldb_rename rename;
+ struct ldb_register_control reg_control;
+ struct ldb_register_partition reg_partition;
+ struct ldb_sequence_number seq_num;
+ } op;
+
+ struct ldb_control **controls;
+
+ void *context;
+ ldb_request_callback_t callback;
+
+ int timeout;
+ time_t starttime;
+ struct ldb_handle *handle;
+};
+
+int ldb_request(struct ldb_context *ldb, struct ldb_request *request);
+
+int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type);
+
+int ldb_set_timeout(struct ldb_context *ldb, struct ldb_request *req, int timeout);
+int ldb_set_timeout_from_prev_req(struct ldb_context *ldb, struct ldb_request *oldreq, struct ldb_request *newreq);
+void ldb_set_create_perms(struct ldb_context *ldb, unsigned int perms);
+
+/**
+ Initialise ldbs' global information
+
+ This is required before any other LDB call
+
+ \return 0 if initialisation succeeded, -1 otherwise
+*/
+int ldb_global_init(void);
+
+/**
+ Initialise an ldb context
+
+ This is required before any other LDB call.
+
+ \param mem_ctx pointer to a talloc memory context. Pass NULL if there is
+ no suitable context available.
+
+ \return pointer to ldb_context that should be free'd (using talloc_free())
+ at the end of the program.
+*/
+struct ldb_context *ldb_init(void *mem_ctx);
+
+/**
+ Connect to a database.
+
+ This is typically called soon after ldb_init(), and is required prior to
+ any search or database modification operations.
+
+ The URL can be one of the following forms:
+ - tdb://path
+ - ldapi://path
+ - ldap://host
+ - sqlite://path
+
+ \param ldb the context associated with the database (from ldb_init())
+ \param url the URL of the database to connect to, as noted above
+ \param flags a combination of LDB_FLG_* to modify the connection behaviour
+ \param options backend specific options - passed uninterpreted to the backend
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+
+ \note It is an error to connect to a database that does not exist in readonly mode
+ (that is, with LDB_FLG_RDONLY). However in read-write mode, the database will be
+ created if it does not exist.
+*/
+int ldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[]);
+
+/*
+ return an automatic baseDN from the defaultNamingContext of the rootDSE
+ This value have been set in an opaque pointer at connection time
+*/
+const struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb);
+
+
+/**
+ The Default iasync search callback function
+
+ \param ldb the context associated with the database (from ldb_init())
+ \param context the callback context
+ \param ares a single reply from the async core
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+
+ \note this function expects the context to always be an struct ldb_result pointer
+ AND a talloc context, this function will steal on the context each message
+ from the ares reply passed on by the async core so that in the end all the
+ messages will be in the context (ldb_result) memory tree.
+ Freeing the passed context (ldb_result tree) will free all the resources
+ (the request need to be freed separately and the result doe not depend on the
+ request that can be freed as sson as the search request is finished)
+*/
+
+int ldb_search_default_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares);
+
+/**
+ Helper function to build a search request
+
+ \param ret_req the request structure is returned here (talloced on mem_ctx)
+ \param ldb the context associated with the database (from ldb_init())
+ \param mem_ctx a talloc emmory context (used as parent of ret_req)
+ \param base the Base Distinguished Name for the query (use ldb_dn_new() for an empty one)
+ \param scope the search scope for the query
+ \param expression the search expression to use for this query
+ \param attrs the search attributes for the query (pass NULL if none required)
+ \param controls an array of controls
+ \param context the callback function context
+ \param the callback function to handle the async replies
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+*/
+
+int ldb_build_search_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ void *mem_ctx,
+ const struct ldb_dn *base,
+ enum ldb_scope scope,
+ const char *expression,
+ const char * const *attrs,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback);
+
+/**
+ Helper function to build an add request
+
+ \param ret_req the request structure is returned here (talloced on mem_ctx)
+ \param ldb the context associated with the database (from ldb_init())
+ \param mem_ctx a talloc emmory context (used as parent of ret_req)
+ \param message contains the entry to be added
+ \param controls an array of controls
+ \param context the callback function context
+ \param the callback function to handle the async replies
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+*/
+
+int ldb_build_add_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ void *mem_ctx,
+ const struct ldb_message *message,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback);
+
+/**
+ Helper function to build a modify request
+
+ \param ret_req the request structure is returned here (talloced on mem_ctx)
+ \param ldb the context associated with the database (from ldb_init())
+ \param mem_ctx a talloc emmory context (used as parent of ret_req)
+ \param message contains the entry to be modified
+ \param controls an array of controls
+ \param context the callback function context
+ \param the callback function to handle the async replies
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+*/
+
+int ldb_build_mod_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ void *mem_ctx,
+ const struct ldb_message *message,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback);
+
+/**
+ Helper function to build a delete request
+
+ \param ret_req the request structure is returned here (talloced on mem_ctx)
+ \param ldb the context associated with the database (from ldb_init())
+ \param mem_ctx a talloc emmory context (used as parent of ret_req)
+ \param dn the DN to be deleted
+ \param controls an array of controls
+ \param context the callback function context
+ \param the callback function to handle the async replies
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+*/
+
+int ldb_build_del_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ void *mem_ctx,
+ const struct ldb_dn *dn,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback);
+
+/**
+ Helper function to build a rename request
+
+ \param ret_req the request structure is returned here (talloced on mem_ctx)
+ \param ldb the context associated with the database (from ldb_init())
+ \param mem_ctx a talloc emmory context (used as parent of ret_req)
+ \param olddn the old DN
+ \param newdn the new DN
+ \param controls an array of controls
+ \param context the callback function context
+ \param the callback function to handle the async replies
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+*/
+
+int ldb_build_rename_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ void *mem_ctx,
+ const struct ldb_dn *olddn,
+ const struct ldb_dn *newdn,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback);
+
+/**
+ Search the database
+
+ This function searches the database, and returns
+ records that match an LDAP-like search expression
+
+ \param ldb the context associated with the database (from ldb_init())
+ \param base the Base Distinguished Name for the query (use ldb_dn_new() for an empty one)
+ \param scope the search scope for the query
+ \param expression the search expression to use for this query
+ \param attrs the search attributes for the query (pass NULL if none required)
+ \param res the return result
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+
+ \note use talloc_free() to free the ldb_result returned
+*/
+int ldb_search(struct ldb_context *ldb,
+ const struct ldb_dn *base,
+ enum ldb_scope scope,
+ const char *expression,
+ const char * const *attrs, struct ldb_result **res);
+
+/*
+ * a useful search function where you can easily define the expression and
+ * that takes a memory context where results are allocated
+*/
+
+int ldb_search_exp_fmt(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
+ struct ldb_result **result, struct ldb_dn *base,
+ enum ldb_scope scope, const char * const *attrs,
+ const char *exp_fmt, ...);
+
+/*
+ like ldb_search() but takes a parse tree
+*/
+int ldb_search_bytree(struct ldb_context *ldb,
+ const struct ldb_dn *base,
+ enum ldb_scope scope,
+ struct ldb_parse_tree *tree,
+ const char * const *attrs, struct ldb_result **res);
+
+/**
+ Add a record to the database.
+
+ This function adds a record to the database. This function will fail
+ if a record with the specified class and key already exists in the
+ database.
+
+ \param ldb the context associated with the database (from
+ ldb_init())
+ \param message the message containing the record to add.
+
+ \return result code (LDB_SUCCESS if the record was added, otherwise
+ a failure code)
+*/
+int ldb_add(struct ldb_context *ldb,
+ const struct ldb_message *message);
+
+/**
+ Modify the specified attributes of a record
+
+ This function modifies a record that is in the database.
+
+ \param ldb the context associated with the database (from
+ ldb_init())
+ \param message the message containing the changes required.
+
+ \return result code (LDB_SUCCESS if the record was modified as
+ requested, otherwise a failure code)
+*/
+int ldb_modify(struct ldb_context *ldb,
+ const struct ldb_message *message);
+
+/**
+ Rename a record in the database
+
+ This function renames a record in the database.
+
+ \param ldb the context associated with the database (from
+ ldb_init())
+ \param olddn the DN for the record to be renamed.
+ \param newdn the new DN
+
+ \return result code (LDB_SUCCESS if the record was renamed as
+ requested, otherwise a failure code)
+*/
+int ldb_rename(struct ldb_context *ldb, const struct ldb_dn *olddn, const struct ldb_dn *newdn);
+
+/**
+ Delete a record from the database
+
+ This function deletes a record from the database.
+
+ \param ldb the context associated with the database (from
+ ldb_init())
+ \param dn the DN for the record to be deleted.
+
+ \return result code (LDB_SUCCESS if the record was deleted,
+ otherwise a failure code)
+*/
+int ldb_delete(struct ldb_context *ldb, const struct ldb_dn *dn);
+
+/**
+ start a transaction
+*/
+int ldb_transaction_start(struct ldb_context *ldb);
+
+/**
+ commit a transaction
+*/
+int ldb_transaction_commit(struct ldb_context *ldb);
+
+/**
+ cancel a transaction
+*/
+int ldb_transaction_cancel(struct ldb_context *ldb);
+
+
+/**
+ return extended error information from the last call
+*/
+const char *ldb_errstring(struct ldb_context *ldb);
+
+/**
+ return a string explaining what a ldb error constant meancs
+*/
+const char *ldb_strerror(int ldb_err);
+
+/**
+ setup the default utf8 functions
+ FIXME: these functions do not yet handle utf8
+*/
+void ldb_set_utf8_default(struct ldb_context *ldb);
+
+/**
+ Casefold a string
+
+ \param ldb the ldb context
+ \param mem_ctx the memory context to allocate the result string
+ memory from.
+ \param s the string that is to be folded
+ \return a copy of the string, converted to upper case
+
+ \note The default function is not yet UTF8 aware. Provide your own
+ set of functions through ldb_set_utf8_fns()
+*/
+char *ldb_casefold(struct ldb_context *ldb, void *mem_ctx, const char *s);
+
+/**
+ Check the attribute name is valid according to rfc2251
+ \param s tthe string to check
+
+ \return 1 if the name is ok
+*/
+int ldb_valid_attr_name(const char *s);
+
+/*
+ ldif manipulation functions
+*/
+/**
+ Write an LDIF message
+
+ This function writes an LDIF message using a caller supplied write
+ function.
+
+ \param ldb the ldb context (from ldb_init())
+ \param fprintf_fn a function pointer for the write function. This must take
+ a private data pointer, followed by a format string, and then a variable argument
+ list.
+ \param private_data pointer that will be provided back to the write
+ function. This is useful for maintaining state or context.
+ \param ldif the message to write out
+
+ \return the total number of bytes written, or an error code as returned
+ from the write function.
+
+ \sa ldb_ldif_write_file for a more convenient way to write to a
+ file stream.
+
+ \sa ldb_ldif_read for the reader equivalent to this function.
+*/
+int ldb_ldif_write(struct ldb_context *ldb,
+ int (*fprintf_fn)(void *, const char *, ...) PRINTF_ATTRIBUTE(2,3),
+ void *private_data,
+ const struct ldb_ldif *ldif);
+
+/**
+ Clean up an LDIF message
+
+ This function cleans up a LDIF message read using ldb_ldif_read()
+ or related functions (such as ldb_ldif_read_string() and
+ ldb_ldif_read_file().
+
+ \param ldb the ldb context (from ldb_init())
+ \param msg the message to clean up and free
+
+*/
+void ldb_ldif_read_free(struct ldb_context *ldb, struct ldb_ldif *msg);
+
+/**
+ Read an LDIF message
+
+ This function creates an LDIF message using a caller supplied read
+ function.
+
+ \param ldb the ldb context (from ldb_init())
+ \param fgetc_fn a function pointer for the read function. This must
+ take a private data pointer, and must return a pointer to an
+ integer corresponding to the next byte read (or EOF if there is no
+ more data to be read).
+ \param private_data pointer that will be provided back to the read
+ function. This is udeful for maintaining state or context.
+
+ \return the LDIF message that has been read in
+
+ \note You must free the LDIF message when no longer required, using
+ ldb_ldif_read_free().
+
+ \sa ldb_ldif_read_file for a more convenient way to read from a
+ file stream.
+
+ \sa ldb_ldif_read_string for a more convenient way to read from a
+ string (char array).
+
+ \sa ldb_ldif_write for the writer equivalent to this function.
+*/
+struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
+ int (*fgetc_fn)(void *), void *private_data);
+
+/**
+ Read an LDIF message from a file
+
+ This function reads the next LDIF message from the contents of a
+ file stream. If you want to get all of the LDIF messages, you will
+ need to repeatedly call this function, until it returns NULL.
+
+ \param ldb the ldb context (from ldb_init())
+ \param f the file stream to read from (typically from fdopen())
+
+ \sa ldb_ldif_read_string for an equivalent function that will read
+ from a string (char array).
+
+ \sa ldb_ldif_write_file for the writer equivalent to this function.
+
+*/
+struct ldb_ldif *ldb_ldif_read_file(struct ldb_context *ldb, FILE *f);
+
+/**
+ Read an LDIF message from a string
+
+ This function reads the next LDIF message from the contents of a char
+ array. If you want to get all of the LDIF messages, you will need
+ to repeatedly call this function, until it returns NULL.
+
+ \param ldb the ldb context (from ldb_init())
+ \param s pointer to the char array to read from
+
+ \sa ldb_ldif_read_file for an equivalent function that will read
+ from a file stream.
+
+ \sa ldb_ldif_write for a more general (arbitrary read function)
+ version of this function.
+*/
+struct ldb_ldif *ldb_ldif_read_string(struct ldb_context *ldb, const char **s);
+
+/**
+ Write an LDIF message to a file
+
+ \param ldb the ldb context (from ldb_init())
+ \param f the file stream to write to (typically from fdopen())
+ \param msg the message to write out
+
+ \return the total number of bytes written, or a negative error code
+
+ \sa ldb_ldif_read_file for the reader equivalent to this function.
+*/
+int ldb_ldif_write_file(struct ldb_context *ldb, FILE *f, const struct ldb_ldif *msg);
+
+/**
+ Base64 encode a buffer
+
+ \param mem_ctx the memory context that the result is allocated
+ from.
+ \param buf pointer to the array that is to be encoded
+ \param len the number of elements in the array to be encoded
+
+ \return pointer to an array containing the encoded data
+
+ \note The caller is responsible for freeing the result
+*/
+char *ldb_base64_encode(void *mem_ctx, const char *buf, int len);
+
+/**
+ Base64 decode a buffer
+
+ This function decodes a base64 encoded string in place.
+
+ \param s the string to decode.
+
+ \return the length of the returned (decoded) string.
+
+ \note the string is null terminated, but the null terminator is not
+ included in the length.
+*/
+int ldb_base64_decode(char *s);
+
+int ldb_attrib_add_handlers(struct ldb_context *ldb,
+ const struct ldb_attrib_handler *handlers,
+ unsigned num_handlers);
+
+/* The following definitions come from lib/ldb/common/ldb_dn.c */
+
+int ldb_dn_is_special(const struct ldb_dn *dn);
+int ldb_dn_check_special(const struct ldb_dn *dn, const char *check);
+char *ldb_dn_escape_value(void *mem_ctx, struct ldb_val value);
+struct ldb_dn *ldb_dn_new(void *mem_ctx);
+struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn);
+struct ldb_dn *ldb_dn_explode_or_special(void *mem_ctx, const char *dn);
+char *ldb_dn_linearize(void *mem_ctx, const struct ldb_dn *edn);
+char *ldb_dn_linearize_casefold(struct ldb_context *ldb, void *mem_ctx, const struct ldb_dn *edn);
+int ldb_dn_compare_base(struct ldb_context *ldb, const struct ldb_dn *base, const struct ldb_dn *dn);
+int ldb_dn_compare(struct ldb_context *ldb, const struct ldb_dn *edn0, const struct ldb_dn *edn1);
+struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, void *mem_ctx, const struct ldb_dn *edn);
+struct ldb_dn *ldb_dn_explode_casefold(struct ldb_context *ldb, void *mem_ctx, const char *dn);
+struct ldb_dn *ldb_dn_copy_partial(void *mem_ctx, const struct ldb_dn *dn, int num_el);
+struct ldb_dn *ldb_dn_copy(void *mem_ctx, const struct ldb_dn *dn);
+struct ldb_dn *ldb_dn_copy_rebase(void *mem_ctx, const struct ldb_dn *old, const struct ldb_dn *old_base, const struct ldb_dn *new_base);
+struct ldb_dn *ldb_dn_get_parent(void *mem_ctx, const struct ldb_dn *dn);
+struct ldb_dn_component *ldb_dn_build_component(void *mem_ctx, const char *attr,
+ const char *val);
+struct ldb_dn *ldb_dn_build_child(void *mem_ctx, const char *attr,
+ const char * value,
+ const struct ldb_dn *base);
+struct ldb_dn *ldb_dn_compose(void *mem_ctx, const struct ldb_dn *dn1, const struct ldb_dn *dn2);
+struct ldb_dn *ldb_dn_string_compose(void *mem_ctx, const struct ldb_dn *base, const char *child_fmt, ...) PRINTF_ATTRIBUTE(3,4);
+char *ldb_dn_canonical_string(void *mem_ctx, const struct ldb_dn *dn);
+char *ldb_dn_canonical_ex_string(void *mem_ctx, const struct ldb_dn *dn);
+int ldb_dn_get_comp_num(const struct ldb_dn *dn);
+const char *ldb_dn_get_component_name(const struct ldb_dn *dn, unsigned int num);
+const struct ldb_val *ldb_dn_get_component_val(const struct ldb_dn *dn, unsigned int num);
+const char *ldb_dn_get_rdn_name(const struct ldb_dn *dn);
+const struct ldb_val *ldb_dn_get_rdn_val(const struct ldb_dn *dn);
+int ldb_dn_set_component(struct ldb_dn *dn, int num, const char *name, const struct ldb_val val);
+
+
+
+/* useful functions for ldb_message structure manipulation */
+int ldb_dn_cmp(struct ldb_context *ldb, const char *dn1, const char *dn2);
+
+/**
+ Compare two attributes
+
+ This function compares to attribute names. Note that this is a
+ case-insensitive comparison.
+
+ \param attr1 the first attribute name to compare
+ \param attr2 the second attribute name to compare
+
+ \return 0 if the attribute names are the same, or only differ in
+ case; non-zero if there are any differences
+*/
+int ldb_attr_cmp(const char *attr1, const char *attr2);
+char *ldb_attr_casefold(void *mem_ctx, const char *s);
+int ldb_attr_dn(const char *attr);
+
+/**
+ Create an empty message
+
+ \param mem_ctx the memory context to create in. You can pass NULL
+ to get the top level context, however the ldb context (from
+ ldb_init()) may be a better choice
+*/
+struct ldb_message *ldb_msg_new(void *mem_ctx);
+
+/**
+ Find an element within an message
+*/
+struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
+ const char *attr_name);
+
+/**
+ Compare two ldb_val values
+
+ \param v1 first ldb_val structure to be tested
+ \param v2 second ldb_val structure to be tested
+
+ \return 1 for a match, 0 if there is any difference
+*/
+int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2);
+
+/**
+ find a value within an ldb_message_element
+
+ \param el the element to search
+ \param val the value to search for
+
+ \note This search is case sensitive
+*/
+struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
+ struct ldb_val *val);
+
+/**
+ add a new empty element to a ldb_message
+*/
+int ldb_msg_add_empty(struct ldb_message *msg,
+ const char *attr_name,
+ int flags,
+ struct ldb_message_element **return_el);
+
+/**
+ add a element to a ldb_message
+*/
+int ldb_msg_add(struct ldb_message *msg,
+ const struct ldb_message_element *el,
+ int flags);
+int ldb_msg_add_value(struct ldb_message *msg,
+ const char *attr_name,
+ const struct ldb_val *val,
+ struct ldb_message_element **return_el);
+int ldb_msg_add_steal_value(struct ldb_message *msg,
+ const char *attr_name,
+ struct ldb_val *val);
+int ldb_msg_add_steal_string(struct ldb_message *msg,
+ const char *attr_name, char *str);
+int ldb_msg_add_string(struct ldb_message *msg,
+ const char *attr_name, const char *str);
+int ldb_msg_add_fmt(struct ldb_message *msg,
+ const char *attr_name, const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+
+/**
+ compare two message elements - return 0 on match
+*/
+int ldb_msg_element_compare(struct ldb_message_element *el1,
+ struct ldb_message_element *el2);
+
+/**
+ Find elements in a message.
+
+ This function finds elements and converts to a specific type, with
+ a give default value if not found. Assumes that elements are
+ single valued.
+*/
+const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name);
+int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
+ const char *attr_name,
+ int default_value);
+unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
+ const char *attr_name,
+ unsigned int default_value);
+int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
+ const char *attr_name,
+ int64_t default_value);
+uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
+ const char *attr_name,
+ uint64_t default_value);
+double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
+ const char *attr_name,
+ double default_value);
+int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
+ const char *attr_name,
+ int default_value);
+const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
+ const char *attr_name,
+ const char *default_value);
+
+struct ldb_dn *ldb_msg_find_attr_as_dn(void *mem_ctx,
+ const struct ldb_message *msg,
+ const char *attr_name);
+
+void ldb_msg_sort_elements(struct ldb_message *msg);
+
+struct ldb_message *ldb_msg_copy_shallow(void *mem_ctx,
+ const struct ldb_message *msg);
+struct ldb_message *ldb_msg_copy(void *mem_ctx,
+ const struct ldb_message *msg);
+
+struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
+ const struct ldb_message *msg);
+
+
+struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
+ struct ldb_message *msg1,
+ struct ldb_message *msg2);
+
+int ldb_msg_check_string_attribute(const struct ldb_message *msg,
+ const char *name,
+ const char *value);
+
+/**
+ Integrity check an ldb_message
+
+ This function performs basic sanity / integrity checks on an
+ ldb_message.
+
+ \param msg the message to check
+
+ \return LDB_SUCCESS if the message is OK, or a non-zero error code
+ (one of LDB_ERR_INVALID_DN_SYNTAX, LDB_ERR_ENTRY_ALREADY_EXISTS or
+ LDB_ERR_INVALID_ATTRIBUTE_SYNTAX) if there is a problem with a
+ message.
+*/
+int ldb_msg_sanity_check(struct ldb_context *ldb,
+ const struct ldb_message *msg);
+
+/**
+ Duplicate an ldb_val structure
+
+ This function copies an ldb value structure.
+
+ \param mem_ctx the memory context that the duplicated value will be
+ allocated from
+ \param v the ldb_val to be duplicated.
+
+ \return the duplicated ldb_val structure.
+*/
+struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v);
+
+/**
+ this allows the user to set a debug function for error reporting
+*/
+int ldb_set_debug(struct ldb_context *ldb,
+ void (*debug)(void *context, enum ldb_debug_level level,
+ const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0),
+ void *context);
+
+/**
+ this allows the user to set custom utf8 function for error reporting
+*/
+void ldb_set_utf8_fns(struct ldb_context *ldb,
+ void *context,
+ char *(*casefold)(void *, void *, const char *));
+
+/**
+ this sets up debug to print messages on stderr
+*/
+int ldb_set_debug_stderr(struct ldb_context *ldb);
+
+/* control backend specific opaque values */
+int ldb_set_opaque(struct ldb_context *ldb, const char *name, void *value);
+void *ldb_get_opaque(struct ldb_context *ldb, const char *name);
+
+const struct ldb_attrib_handler *ldb_attrib_handler(struct ldb_context *ldb,
+ const char *attrib);
+
+
+const char **ldb_attr_list_copy(void *mem_ctx, const char * const *attrs);
+const char **ldb_attr_list_copy_add(void *mem_ctx, const char * const *attrs, const char *new_attr);
+int ldb_attr_in_list(const char * const *attrs, const char *attr);
+
+
+void ldb_parse_tree_attr_replace(struct ldb_parse_tree *tree,
+ const char *attr,
+ const char *replace);
+
+int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace);
+int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace);
+void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr);
+
+/**
+ Convert a time structure to a string
+
+ This function converts a time_t structure to an LDAP formatted time
+ string.
+
+ \param mem_ctx the memory context to allocate the return string in
+ \param t the time structure to convert
+
+ \return the formatted string, or NULL if the time structure could
+ not be converted
+*/
+char *ldb_timestring(void *mem_ctx, time_t t);
+
+/**
+ Convert a string to a time structure
+
+ This function converts an LDAP formatted time string to a time_t
+ structure.
+
+ \param s the string to convert
+
+ \return the time structure, or 0 if the string cannot be converted
+*/
+time_t ldb_string_to_time(const char *s);
+
+
+void ldb_qsort (void *const pbase, size_t total_elems, size_t size, void *opaque, ldb_qsort_cmp_fn_t cmp);
+#endif
diff --git a/source3/lib/ldb/include/ldb_errors.h b/source3/lib/ldb/include/ldb_errors.h
new file mode 100644
index 0000000000..9362233fd5
--- /dev/null
+++ b/source3/lib/ldb/include/ldb_errors.h
@@ -0,0 +1,310 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb header
+ *
+ * Description: defines error codes following RFC 2251 ldap error codes
+ *
+ * Author: Simo Sorce
+ */
+
+#ifndef _LDB_ERRORS_H_
+
+/*! \cond DOXYGEN_IGNORE */
+#define _LDB_ERRORS_H_ 1
+/*! \endcond */
+
+/**
+ \file ldb_errors.h
+
+ This header provides a set of result codes for LDB function calls.
+
+ Many LDB function calls return an integer value (int). As shown in
+ the function documentation, those return values may indicate
+ whether the function call worked correctly (in which case it
+ returns LDB_SUCCESS) or some problem occurred (in which case some
+ other value will be returned). As a special case,
+ LDB_ERR_COMPARE_FALSE or LDB_ERR_COMPARE_TRUE may be returned,
+ which does not indicate an error.
+
+ \note Not all error codes make sense for LDB, however they are
+ based on the LDAP error codes, and are kept for reference and to
+ avoid overlap.
+
+ \note Some of this documentation is based on information in
+ the OpenLDAP documentation, as developed and maintained by the
+ <a href="http://www.openldap.org/">The OpenLDAP Project</a>.
+ */
+
+/**
+ The function call succeeded.
+
+ If a function returns LDB_SUCCESS, then that function, and the
+ underlying transactions that may have been required, completed
+ successfully.
+*/
+#define LDB_SUCCESS 0
+
+/**
+ The function call failed for some non-specific reason.
+*/
+#define LDB_ERR_OPERATIONS_ERROR 1
+
+/**
+ The function call failed because of a protocol violation.
+*/
+#define LDB_ERR_PROTOCOL_ERROR 2
+
+/**
+ The function call failed because a time limit was exceeded.
+*/
+#define LDB_ERR_TIME_LIMIT_EXCEEDED 3
+
+/**
+ The function call failed because a size limit was exceeded.
+*/
+#define LDB_ERR_SIZE_LIMIT_EXCEEDED 4
+
+/**
+ The function was for value comparison, and the comparison operation
+ returned false.
+
+ \note This is a status value, and doesn't normally indicate an
+ error.
+*/
+#define LDB_ERR_COMPARE_FALSE 5
+
+/**
+ The function was for value comparison, and the comparison operation
+ returned true.
+
+ \note This is a status value, and doesn't normally indicate an
+ error.
+*/
+#define LDB_ERR_COMPARE_TRUE 6
+
+/**
+ The function used an authentication method that is not supported by
+ the database.
+*/
+#define LDB_ERR_AUTH_METHOD_NOT_SUPPORTED 7
+
+/**
+ The function call required a underlying operation that required
+ strong authentication.
+
+ This will normally only occur if you are using LDB with a LDAP
+ backend.
+*/
+#define LDB_ERR_STRONG_AUTH_REQUIRED 8
+/* 9 RESERVED */
+
+/**
+ The function resulted in a referral to another server.
+*/
+#define LDB_ERR_REFERRAL 10
+
+/**
+ The function failed because an administrative / policy limit was
+ exceeded.
+*/
+#define LDB_ERR_ADMIN_LIMIT_EXCEEDED 11
+
+/**
+ The function required an extension or capability that the
+ database cannot provide.
+*/
+#define LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION 12
+
+/**
+ The function involved a transaction or database operation that
+ could not be performed without a secure link.
+*/
+#define LDB_ERR_CONFIDENTIALITY_REQUIRED 13
+
+/**
+ This is an intermediate result code for SASL bind operations that
+ have more than one step.
+
+ \note This is a result code that does not normally indicate an
+ error has occurred.
+*/
+#define LDB_ERR_SASL_BIND_IN_PROGRESS 14
+
+/**
+ The function referred to an attribute type that is not present in
+ the entry.
+*/
+#define LDB_ERR_NO_SUCH_ATTRIBUTE 16
+
+/**
+ The function referred to an attribute type that is invalid
+*/
+#define LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE 17
+
+/**
+ The function required a filter type that is not available for the
+ specified attribute.
+*/
+#define LDB_ERR_INAPPROPRIATE_MATCHING 18
+
+/**
+ The function would have violated an attribute constraint.
+*/
+#define LDB_ERR_CONSTRAINT_VIOLATION 19
+
+/**
+ The function involved an attribute type or attribute value that
+ already exists in the entry.
+*/
+#define LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS 20
+/**
+ The function used an invalid (incorrect syntax) attribute value.
+*/
+#define LDB_ERR_INVALID_ATTRIBUTE_SYNTAX 21
+
+/* 22-31 unused */
+
+/**
+ The function referred to an object that does not exist in the
+ database.
+*/
+#define LDB_ERR_NO_SUCH_OBJECT 32
+
+/**
+ The function referred to an alias which points to a non-existant
+ object in the database.
+*/
+#define LDB_ERR_ALIAS_PROBLEM 33
+
+/**
+ The function used a DN which was invalid (incorrect syntax).
+*/
+#define LDB_ERR_INVALID_DN_SYNTAX 34
+
+/* 35 RESERVED */
+
+/**
+ The function required dereferencing of an alias, and something went
+ wrong during the dereferencing process.
+*/
+#define LDB_ERR_ALIAS_DEREFERENCING_PROBLEM 36
+
+/* 37-47 unused */
+
+/**
+ The function passed in the wrong authentication method.
+*/
+#define LDB_ERR_INAPPROPRIATE_AUTHENTICATION 48
+
+/**
+ The function passed in or referenced incorrect credentials during
+ authentication.
+*/
+#define LDB_ERR_INVALID_CREDENTIALS 49
+
+/**
+ The function required access permissions that the user does not
+ possess.
+*/
+#define LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS 50
+
+/**
+ The function required a transaction or call that the database could
+ not perform because it is busy.
+*/
+#define LDB_ERR_BUSY 51
+
+/**
+ The function required a transaction or call to a database that is
+ not available.
+*/
+#define LDB_ERR_UNAVAILABLE 52
+
+/**
+ The function required a transaction or call to a database that the
+ database declined to perform.
+*/
+#define LDB_ERR_UNWILLING_TO_PERFORM 53
+
+/**
+ The function failed because it resulted in a loop being detected.
+*/
+#define LDB_ERR_LOOP_DETECT 54
+
+/* 55-63 unused */
+
+/**
+ The function failed because it would have violated a naming rule.
+*/
+#define LDB_ERR_NAMING_VIOLATION 64
+
+/**
+ The function failed because it would have violated the schema.
+*/
+#define LDB_ERR_OBJECT_CLASS_VIOLATION 65
+
+/**
+ The function required an operation that is only allowed on leaf
+ objects, but the object is not a leaf.
+*/
+#define LDB_ERR_NOT_ALLOWED_ON_NON_LEAF 66
+
+/**
+ The function required an operation that cannot be performed on a
+ Relative DN, but the object is a Relative DN.
+*/
+#define LDB_ERR_NOT_ALLOWED_ON_RDN 67
+
+/**
+ The function failed because the entry already exists.
+*/
+#define LDB_ERR_ENTRY_ALREADY_EXISTS 68
+
+/**
+ The function failed because modifications to an object class are
+ not allowable.
+*/
+#define LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED 69
+
+/* 70 RESERVED FOR CLDAP */
+
+/**
+ The function failed because it needed to be applied to multiple
+ databases.
+*/
+#define LDB_ERR_AFFECTS_MULTIPLE_DSAS 71
+
+/* 72-79 unused */
+
+/**
+ The function failed for unknown reasons.
+*/
+#define LDB_ERR_OTHER 80
+
+/* 81-90 RESERVED for APIs */
+
+#endif /* _LDB_ERRORS_H_ */
diff --git a/source3/lib/ldb/include/ldb_private.h b/source3/lib/ldb/include/ldb_private.h
new file mode 100644
index 0000000000..368a903f2d
--- /dev/null
+++ b/source3/lib/ldb/include/ldb_private.h
@@ -0,0 +1,224 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Simo Sorce 2004-2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb private header
+ *
+ * Description: defines internal ldb structures used by the subsystem and modules
+ *
+ * Author: Andrew Tridgell
+ * Author: Stefan Metzmacher
+ */
+
+#ifndef _LDB_PRIVATE_H_
+#define _LDB_PRIVATE_H_ 1
+
+struct ldb_context;
+
+struct ldb_module_ops;
+
+/* basic module structure */
+struct ldb_module {
+ struct ldb_module *prev, *next;
+ struct ldb_context *ldb;
+ void *private_data;
+ const struct ldb_module_ops *ops;
+};
+
+/*
+ these function pointers define the operations that a ldb module must perform
+ they correspond exactly to the ldb_*() interface
+*/
+struct ldb_module_ops {
+ const char *name;
+ int (*init_context) (struct ldb_module *);
+ int (*search)(struct ldb_module *, struct ldb_request *); /* search */
+ int (*add)(struct ldb_module *, struct ldb_request *); /* add */
+ int (*modify)(struct ldb_module *, struct ldb_request *); /* modify */
+ int (*del)(struct ldb_module *, struct ldb_request *); /* delete */
+ int (*rename)(struct ldb_module *, struct ldb_request *); /* rename */
+ int (*request)(struct ldb_module *, struct ldb_request *); /* match any other operation */
+ int (*extended)(struct ldb_module *, struct ldb_request *); /* extended operations */
+ int (*start_transaction)(struct ldb_module *);
+ int (*end_transaction)(struct ldb_module *);
+ int (*del_transaction)(struct ldb_module *);
+ int (*wait)(struct ldb_handle *, enum ldb_wait_type);
+ int (*sequence_number)(struct ldb_module *, struct ldb_request *);
+};
+
+typedef int (*ldb_connect_fn) (struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[],
+ struct ldb_module **module);
+
+/*
+ schema related information needed for matching rules
+*/
+struct ldb_schema {
+ /* attribute handling table */
+ unsigned num_attrib_handlers;
+ struct ldb_attrib_handler *attrib_handlers;
+
+ /* objectclass information */
+ unsigned num_classes;
+ struct ldb_subclass {
+ char *name;
+ char **subclasses;
+ } *classes;
+};
+
+/*
+ every ldb connection is started by establishing a ldb_context
+*/
+struct ldb_context {
+ /* the operations provided by the backend */
+ struct ldb_module *modules;
+
+ /* debugging operations */
+ struct ldb_debug_ops debug_ops;
+
+ /* custom utf8 functions */
+ struct ldb_utf8_fns utf8_fns;
+
+ /* backend specific opaque parameters */
+ struct ldb_opaque {
+ struct ldb_opaque *next;
+ const char *name;
+ void *value;
+ } *opaque;
+
+ struct ldb_schema schema;
+
+ char *err_string;
+
+ int transaction_active;
+
+ int default_timeout;
+
+ unsigned int flags;
+
+ unsigned int create_perms;
+};
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+#endif
+
+/*
+ simplify out of memory handling
+*/
+#define ldb_oom(ldb) ldb_debug_set(ldb, LDB_DEBUG_FATAL, "ldb out of memory at %s:%d\n", __FILE__, __LINE__)
+
+/* The following definitions come from lib/ldb/common/ldb.c */
+
+int ldb_connect_backend(struct ldb_context *ldb, const char *url, const char *options[],
+ struct ldb_module **backend_module);
+
+/* The following definitions come from lib/ldb/common/ldb_modules.c */
+
+const char **ldb_modules_list_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *string);
+int ldb_load_modules_list(struct ldb_context *ldb, const char **module_list, struct ldb_module *backend, struct ldb_module **out);
+int ldb_load_modules(struct ldb_context *ldb, const char *options[]);
+int ldb_init_module_chain(struct ldb_context *ldb, struct ldb_module *module);
+int ldb_next_request(struct ldb_module *module, struct ldb_request *request);
+int ldb_next_start_trans(struct ldb_module *module);
+int ldb_next_end_trans(struct ldb_module *module);
+int ldb_next_del_trans(struct ldb_module *module);
+int ldb_next_init(struct ldb_module *module);
+
+void ldb_set_errstring(struct ldb_context *ldb, const char *err_string);
+void ldb_asprintf_errstring(struct ldb_context *ldb, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
+void ldb_reset_err_string(struct ldb_context *ldb);
+
+int ldb_register_module(const struct ldb_module_ops *);
+int ldb_register_backend(const char *url_prefix, ldb_connect_fn);
+int ldb_try_load_dso(struct ldb_context *ldb, const char *name);
+
+/* The following definitions come from lib/ldb/common/ldb_debug.c */
+void ldb_debug(struct ldb_context *ldb, enum ldb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
+void ldb_debug_set(struct ldb_context *ldb, enum ldb_debug_level level,
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
+
+/* The following definitions come from lib/ldb/common/ldb_ldif.c */
+int ldb_should_b64_encode(const struct ldb_val *val);
+
+int ldb_objectclass_init(void);
+int ldb_operational_init(void);
+int ldb_paged_results_init(void);
+int ldb_rdn_name_init(void);
+int ldb_schema_init(void);
+int ldb_asq_init(void);
+int ldb_sort_init(void);
+int ldb_ldap_init(void);
+int ldb_ildap_init(void);
+int ldb_tdb_init(void);
+int ldb_sqlite3_init(void);
+
+int ldb_match_msg(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ const struct ldb_dn *base,
+ enum ldb_scope scope);
+
+void ldb_remove_attrib_handler(struct ldb_context *ldb, const char *attrib);
+const struct ldb_attrib_handler *ldb_attrib_handler_syntax(struct ldb_context *ldb,
+ const char *syntax);
+int ldb_set_attrib_handlers(struct ldb_context *ldb,
+ const struct ldb_attrib_handler *handlers,
+ unsigned num_handlers);
+int ldb_setup_wellknown_attributes(struct ldb_context *ldb);
+int ldb_set_attrib_handler_syntax(struct ldb_context *ldb,
+ const char *attr, const char *syntax);
+
+/* The following definitions come from lib/ldb/common/ldb_attributes.c */
+const char **ldb_subclass_list(struct ldb_context *ldb, const char *classname);
+void ldb_subclass_remove(struct ldb_context *ldb, const char *classname);
+int ldb_subclass_add(struct ldb_context *ldb, const char *classname, const char *subclass);
+
+int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out);
+int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2);
+
+/* The following definitions come from lib/ldb/common/ldb_controls.c */
+struct ldb_control *get_control_from_list(struct ldb_control **controls, const char *oid);
+int save_controls(struct ldb_control *exclude, struct ldb_request *req, struct ldb_control ***saver);
+int check_critical_controls(struct ldb_control **controls);
+
+/* The following definitions come from lib/ldb/common/ldb_utf8.c */
+char *ldb_casefold_default(void *context, void *mem_ctx, const char *s);
+
+void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el);
+
+/**
+ Obtain current/next database sequence number
+*/
+int ldb_sequence_number(struct ldb_context *ldb, enum ldb_sequence_type type, uint64_t *seq_num);
+
+#define LDB_SEQ_GLOBAL_SEQUENCE 0x01
+#define LDB_SEQ_TIMESTAMP_SEQUENCE 0x02
+
+
+#endif
diff --git a/source3/lib/ldb/install-sh b/source3/lib/ldb/install-sh
new file mode 100755
index 0000000000..58719246f0
--- /dev/null
+++ b/source3/lib/ldb/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/source3/lib/ldb/ldap.m4 b/source3/lib/ldb/ldap.m4
new file mode 100644
index 0000000000..417083ed61
--- /dev/null
+++ b/source3/lib/ldb/ldap.m4
@@ -0,0 +1,90 @@
+########################################################
+# Compile with LDAP support?
+
+LDAP_LIBS=""
+with_ldap_support=auto
+AC_MSG_CHECKING([for LDAP support])
+
+AC_ARG_WITH(ldap,
+AS_HELP_STRING([--with-ldap],[LDAP backend support (default=yes)]),
+[ case "$withval" in
+ yes|no)
+ with_ldap_support=$withval
+ ;;
+ esac ])
+
+AC_MSG_RESULT($with_ldap_support)
+
+if test x"$with_ldap_support" != x"no"; then
+
+ ##################################################################
+ # first test for ldap.h and lber.h
+ # (ldap.h is required for this test)
+ AC_CHECK_HEADERS(ldap.h lber.h)
+
+ if test x"$ac_cv_header_ldap_h" != x"yes"; then
+ if test x"$with_ldap_support" = x"yes"; then
+ AC_MSG_ERROR(ldap.h is needed for LDAP support)
+ else
+ AC_MSG_WARN(ldap.h is needed for LDAP support)
+ fi
+
+ with_ldap_support=no
+ fi
+fi
+
+if test x"$with_ldap_support" != x"no"; then
+ ac_save_LIBS=$LIBS
+
+ ##################################################################
+ # we might need the lber lib on some systems. To avoid link errors
+ # this test must be before the libldap test
+ AC_CHECK_LIB_EXT(lber, LDAP_LIBS, ber_scanf)
+
+ ########################################################
+ # now see if we can find the ldap libs in standard paths
+ AC_CHECK_LIB_EXT(ldap, LDAP_LIBS, ldap_init)
+
+ AC_CHECK_FUNC_EXT(ldap_domain2hostlist,$LDAP_LIBS)
+
+ ########################################################
+ # If we have LDAP, does it's rebind procedure take 2 or 3 arguments?
+ # Check found in pam_ldap 145.
+ AC_CHECK_FUNC_EXT(ldap_set_rebind_proc,$LDAP_LIBS)
+
+ LIBS="$LIBS $LDAP_LIBS"
+ AC_CACHE_CHECK(whether ldap_set_rebind_proc takes 3 arguments, smb_ldap_cv_ldap_set_rebind_proc, [
+ AC_TRY_COMPILE([
+ #include <lber.h>
+ #include <ldap.h>],
+ [ldap_set_rebind_proc(0, 0, 0);],
+ [smb_ldap_cv_ldap_set_rebind_proc=3],
+ [smb_ldap_cv_ldap_set_rebind_proc=2]
+ )
+ ])
+
+ AC_DEFINE_UNQUOTED(LDAP_SET_REBIND_PROC_ARGS, $smb_ldap_cv_ldap_set_rebind_proc, [Number of arguments to ldap_set_rebind_proc])
+
+ AC_CHECK_FUNC_EXT(ldap_initialize,$LDAP_LIBS)
+
+ if test x"$ac_cv_lib_ext_ldap_ldap_init" = x"yes" -a x"$ac_cv_func_ext_ldap_domain2hostlist" = x"yes"; then
+ AC_DEFINE(HAVE_LDAP,1,[Whether ldap is available])
+ AC_DEFINE(HAVE_LDB_LDAP,1,[Whether ldb_ldap is available])
+ with_ldap_support=yes
+ AC_MSG_CHECKING(whether LDAP support is used)
+ AC_MSG_RESULT(yes)
+ SMB_ENABLE(LDAP,YES)
+ else
+ if test x"$with_ldap_support" = x"yes"; then
+ AC_MSG_ERROR(libldap is needed for LDAP support)
+ else
+ AC_MSG_WARN(libldap is needed for LDAP support)
+ fi
+
+ LDAP_LIBS=""
+ with_ldap_support=no
+ fi
+ LIBS=$ac_save_LIBS
+fi
+
+SMB_EXT_LIB(LDAP,[${LDAP_LIBS}],[${LDAP_CFLAGS}],[${LDAP_CPPFLAGS}],[${LDAP_LDFLAGS}])
diff --git a/source3/lib/ldb/ldb.pc.in b/source3/lib/ldb/ldb.pc.in
new file mode 100644
index 0000000000..815d663a7c
--- /dev/null
+++ b/source3/lib/ldb/ldb.pc.in
@@ -0,0 +1,15 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+modulesdir=@modulesdir@
+
+Name: ldb
+Description: An LDAP-like embedded database
+Version: 4.0
+Requires.private: tdb
+Requires: talloc
+Libs: -L${libdir} -lldb
+Cflags: -I${includedir} @CFLAGS@
+Modulesdir: ${modulesdir}
+URL: http://ldb.samba.org/
diff --git a/source3/lib/ldb/ldb_ildap/ldb_ildap.c b/source3/lib/ldb/ldb_ildap/ldb_ildap.c
new file mode 100644
index 0000000000..bc0fe66a1a
--- /dev/null
+++ b/source3/lib/ldb/ldb_ildap/ldb_ildap.c
@@ -0,0 +1,827 @@
+/*
+ ldb database library - ildap backend
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Simo Sorce 2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb_ildap
+ *
+ * Component: ldb ildap backend
+ *
+ * Description: This is a ldb backend for the internal ldap
+ * client library in Samba4. By using this backend we are
+ * independent of a system ldap library
+ *
+ * Author: Andrew Tridgell
+ *
+ * Modifications:
+ *
+ * - description: make the module use asyncronous calls
+ * date: Feb 2006
+ * author: Simo Sorce
+ */
+
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#include "lib/events/events.h"
+#include "libcli/ldap/ldap.h"
+#include "libcli/ldap/ldap_client.h"
+#include "auth/auth.h"
+#include "auth/credentials/credentials.h"
+
+struct ildb_private {
+ struct ldap_connection *ldap;
+ struct ldb_context *ldb;
+};
+
+struct ildb_context {
+ struct ldb_module *module;
+ struct ldap_request *req;
+ void *context;
+ int (*callback)(struct ldb_context *, void *, struct ldb_reply *);
+};
+
+/*
+ convert a ldb_message structure to a list of ldap_mod structures
+ ready for ildap_add() or ildap_modify()
+*/
+static struct ldap_mod **ildb_msg_to_mods(void *mem_ctx, int *num_mods,
+ const struct ldb_message *msg, int use_flags)
+{
+ struct ldap_mod **mods;
+ unsigned int i;
+ int n = 0;
+
+ /* allocate maximum number of elements needed */
+ mods = talloc_array(mem_ctx, struct ldap_mod *, msg->num_elements+1);
+ if (!mods) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ mods[0] = NULL;
+
+ for (i = 0; i < msg->num_elements; i++) {
+ const struct ldb_message_element *el = &msg->elements[i];
+
+ mods[n] = talloc(mods, struct ldap_mod);
+ if (!mods[n]) {
+ goto failed;
+ }
+ mods[n + 1] = NULL;
+ mods[n]->type = 0;
+ mods[n]->attrib = *el;
+ if (use_flags) {
+ switch (el->flags & LDB_FLAG_MOD_MASK) {
+ case LDB_FLAG_MOD_ADD:
+ mods[n]->type = LDAP_MODIFY_ADD;
+ break;
+ case LDB_FLAG_MOD_DELETE:
+ mods[n]->type = LDAP_MODIFY_DELETE;
+ break;
+ case LDB_FLAG_MOD_REPLACE:
+ mods[n]->type = LDAP_MODIFY_REPLACE;
+ break;
+ }
+ }
+ n++;
+ }
+
+ *num_mods = n;
+ return mods;
+
+failed:
+ talloc_free(mods);
+ return NULL;
+}
+
+
+/*
+ map an ildap NTSTATUS to a ldb error code
+*/
+static int ildb_map_error(struct ildb_private *ildb, NTSTATUS status)
+{
+ if (NT_STATUS_IS_OK(status)) {
+ return LDB_SUCCESS;
+ }
+ ldb_set_errstring(ildb->ldb, ldap_errstr(ildb->ldap, status));
+ if (NT_STATUS_IS_LDAP(status)) {
+ return NT_STATUS_LDAP_CODE(status);
+ }
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+static void ildb_request_timeout(struct event_context *ev, struct timed_event *te,
+ struct timeval t, void *private_data)
+{
+ struct ldb_handle *handle = talloc_get_type(private_data, struct ldb_handle);
+ struct ildb_context *ac = talloc_get_type(handle->private_data, struct ildb_context);
+
+ if (ac->req->state == LDAP_REQUEST_PENDING) {
+ DLIST_REMOVE(ac->req->conn->pending, ac->req);
+ }
+
+ handle->status = LDB_ERR_TIME_LIMIT_EXCEEDED;
+
+ return;
+}
+
+static void ildb_callback(struct ldap_request *req)
+{
+ struct ldb_handle *handle = talloc_get_type(req->async.private_data, struct ldb_handle);
+ struct ildb_context *ac = talloc_get_type(handle->private_data, struct ildb_context);
+ struct ildb_private *ildb = talloc_get_type(ac->module->private_data, struct ildb_private);
+ NTSTATUS status;
+ int i;
+
+ handle->status = LDB_SUCCESS;
+
+ if (!NT_STATUS_IS_OK(req->status)) {
+ handle->status = ildb_map_error(ildb, req->status);
+ return;
+ }
+
+ if (req->num_replies < 1) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ return;
+ }
+
+ switch (req->type) {
+
+ case LDAP_TAG_ModifyRequest:
+ if (req->replies[0]->type != LDAP_TAG_ModifyResponse) {
+ handle->status = LDB_ERR_PROTOCOL_ERROR;
+ return;
+ }
+ status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult);
+ handle->status = ildb_map_error(ildb, status);
+ if (ac->callback && handle->status == LDB_SUCCESS) {
+ /* FIXME: build a corresponding ares to pass on */
+ handle->status = ac->callback(ac->module->ldb, ac->context, NULL);
+ }
+ handle->state = LDB_ASYNC_DONE;
+ break;
+
+ case LDAP_TAG_AddRequest:
+ if (req->replies[0]->type != LDAP_TAG_AddResponse) {
+ handle->status = LDB_ERR_PROTOCOL_ERROR;
+ return;
+ }
+ status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult);
+ handle->status = ildb_map_error(ildb, status);
+ if (ac->callback && handle->status == LDB_SUCCESS) {
+ /* FIXME: build a corresponding ares to pass on */
+ handle->status = ac->callback(ac->module->ldb, ac->context, NULL);
+ }
+ handle->state = LDB_ASYNC_DONE;
+ break;
+
+ case LDAP_TAG_DelRequest:
+ if (req->replies[0]->type != LDAP_TAG_DelResponse) {
+ handle->status = LDB_ERR_PROTOCOL_ERROR;
+ return;
+ }
+ status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult);
+ handle->status = ildb_map_error(ildb, status);
+ if (ac->callback && handle->status == LDB_SUCCESS) {
+ /* FIXME: build a corresponding ares to pass on */
+ handle->status = ac->callback(ac->module->ldb, ac->context, NULL);
+ }
+ handle->state = LDB_ASYNC_DONE;
+ break;
+
+ case LDAP_TAG_ModifyDNRequest:
+ if (req->replies[0]->type != LDAP_TAG_ModifyDNResponse) {
+ handle->status = LDB_ERR_PROTOCOL_ERROR;
+ return;
+ }
+ status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult);
+ handle->status = ildb_map_error(ildb, status);
+ if (ac->callback && handle->status == LDB_SUCCESS) {
+ /* FIXME: build a corresponding ares to pass on */
+ handle->status = ac->callback(ac->module->ldb, ac->context, NULL);
+ }
+ handle->state = LDB_ASYNC_DONE;
+ break;
+
+ case LDAP_TAG_SearchRequest:
+ /* loop over all messages */
+ for (i = 0; i < req->num_replies; i++) {
+ struct ldap_SearchResEntry *search;
+ struct ldb_reply *ares = NULL;
+ struct ldap_message *msg;
+ int ret;
+
+ ares = talloc_zero(ac, struct ldb_reply);
+ if (!ares) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ return;
+ }
+
+ msg = req->replies[i];
+ switch (msg->type) {
+
+ case LDAP_TAG_SearchResultDone:
+
+ status = ldap_check_response(req->conn, &msg->r.GeneralResult);
+ if (!NT_STATUS_IS_OK(status)) {
+ handle->status = ildb_map_error(ildb, status);
+ return;
+ }
+
+ ares->controls = talloc_move(ares, &msg->controls);
+ if (msg->r.SearchResultDone.resultcode) {
+ if (msg->r.SearchResultDone.errormessage) {
+ ldb_set_errstring(ac->module->ldb, msg->r.SearchResultDone.errormessage);
+ }
+ }
+
+ handle->status = msg->r.SearchResultDone.resultcode;
+ handle->state = LDB_ASYNC_DONE;
+ ares->type = LDB_REPLY_DONE;
+ break;
+
+ case LDAP_TAG_SearchResultEntry:
+
+
+ ares->message = ldb_msg_new(ares);
+ if (!ares->message) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ return;
+ }
+
+ search = &(msg->r.SearchResultEntry);
+
+ ares->message->dn = ldb_dn_explode_or_special(ares->message, search->dn);
+ if (ares->message->dn == NULL) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ return;
+ }
+ ares->message->num_elements = search->num_attributes;
+ ares->message->elements = talloc_move(ares->message,
+ &search->attributes);
+
+ handle->status = LDB_SUCCESS;
+ handle->state = LDB_ASYNC_PENDING;
+ ares->type = LDB_REPLY_ENTRY;
+ break;
+
+ case LDAP_TAG_SearchResultReference:
+
+ ares->referral = talloc_strdup(ares, msg->r.SearchResultReference.referral);
+
+ handle->status = LDB_SUCCESS;
+ handle->state = LDB_ASYNC_PENDING;
+ ares->type = LDB_REPLY_REFERRAL;
+ break;
+
+ default:
+ /* TAG not handled, fail ! */
+ handle->status = LDB_ERR_PROTOCOL_ERROR;
+ return;
+ }
+
+ ret = ac->callback(ac->module->ldb, ac->context, ares);
+ if (ret) {
+ handle->status = ret;
+ }
+ }
+
+ talloc_free(req->replies);
+ req->replies = NULL;
+ req->num_replies = 0;
+
+ break;
+
+ default:
+ handle->status = LDB_ERR_PROTOCOL_ERROR;
+ return;
+ }
+}
+
+static struct ldb_handle *init_ildb_handle(struct ldb_module *module,
+ void *context,
+ int (*callback)(struct ldb_context *, void *, struct ldb_reply *))
+{
+ struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
+ struct ildb_context *ildb_ac;
+ struct ldb_handle *h;
+
+ h = talloc_zero(ildb->ldap, struct ldb_handle);
+ if (h == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ return NULL;
+ }
+
+ h->module = module;
+
+ ildb_ac = talloc(h, struct ildb_context);
+ if (ildb_ac == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ talloc_free(h);
+ return NULL;
+ }
+
+ h->private_data = (void *)ildb_ac;
+
+ h->state = LDB_ASYNC_INIT;
+ h->status = LDB_SUCCESS;
+
+ ildb_ac->module = module;
+ ildb_ac->context = context;
+ ildb_ac->callback = callback;
+
+ return h;
+}
+
+static int ildb_request_send(struct ldb_module *module, struct ldap_message *msg,
+ void *context,
+ int (*callback)(struct ldb_context *, void *, struct ldb_reply *),
+ int timeout,
+ struct ldb_handle **handle)
+{
+ struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
+ struct ldb_handle *h = init_ildb_handle(module, context, callback);
+ struct ildb_context *ildb_ac;
+ struct ldap_request *req;
+
+ if (!h) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ildb_ac = talloc_get_type(h->private_data, struct ildb_context);
+
+ req = ldap_request_send(ildb->ldap, msg);
+ if (req == NULL) {
+ ldb_set_errstring(module->ldb, "async send request failed");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (!req->conn) {
+ ldb_set_errstring(module->ldb, "connection to remote LDAP server dropped?");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ talloc_free(req->time_event);
+ req->time_event = NULL;
+ if (timeout) {
+ req->time_event = event_add_timed(req->conn->event.event_ctx, h,
+ timeval_current_ofs(timeout, 0),
+ ildb_request_timeout, h);
+ }
+
+ req->async.fn = ildb_callback;
+ req->async.private_data = (void *)h;
+ ildb_ac->req = talloc_move(ildb_ac, &req);
+
+ *handle = h;
+ return LDB_SUCCESS;
+}
+
+static int ildb_request_noop(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_handle *h = init_ildb_handle(module, req->context, req->callback);
+ struct ildb_context *ildb_ac;
+ int ret = LDB_SUCCESS;
+
+ if (!h) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ildb_ac = talloc_get_type(h->private_data, struct ildb_context);
+
+ req->handle = h;
+
+ if (ildb_ac->callback) {
+ ret = ildb_ac->callback(module->ldb, ildb_ac->context, NULL);
+ }
+ req->handle->state = LDB_ASYNC_DONE;
+ return ret;
+}
+
+/*
+ search for matching records using an asynchronous function
+ */
+static int ildb_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
+ struct ldap_message *msg;
+ int n;
+
+ req->handle = NULL;
+
+ if (!req->callback || !req->context) {
+ ldb_set_errstring(module->ldb, "Async interface called with NULL callback function or NULL context");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (req->op.search.tree == NULL) {
+ ldb_set_errstring(module->ldb, "Invalid expression parse tree");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg = new_ldap_message(ildb);
+ if (msg == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->type = LDAP_TAG_SearchRequest;
+
+ if (req->op.search.base == NULL) {
+ msg->r.SearchRequest.basedn = talloc_strdup(msg, "");
+ } else {
+ msg->r.SearchRequest.basedn = ldb_dn_linearize(msg, req->op.search.base);
+ }
+ if (msg->r.SearchRequest.basedn == NULL) {
+ ldb_set_errstring(module->ldb, "Unable to determine baseDN");
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (req->op.search.scope == LDB_SCOPE_DEFAULT) {
+ msg->r.SearchRequest.scope = LDB_SCOPE_SUBTREE;
+ } else {
+ msg->r.SearchRequest.scope = req->op.search.scope;
+ }
+
+ msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
+ msg->r.SearchRequest.timelimit = 0;
+ msg->r.SearchRequest.sizelimit = 0;
+ msg->r.SearchRequest.attributesonly = 0;
+ msg->r.SearchRequest.tree = discard_const_p(struct ldb_parse_tree, req->op.search.tree);
+
+ for (n = 0; req->op.search.attrs && req->op.search.attrs[n]; n++) /* noop */ ;
+ msg->r.SearchRequest.num_attributes = n;
+ msg->r.SearchRequest.attributes = discard_const_p(char *, req->op.search.attrs),
+
+ msg->controls = req->controls;
+
+ return ildb_request_send(module, msg, req->context, req->callback, req->timeout, &(req->handle));
+}
+
+/*
+ add a record
+*/
+static int ildb_add(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
+ struct ldap_message *msg;
+ struct ldap_mod **mods;
+ int i,n;
+
+ req->handle = NULL;
+
+ /* ignore ltdb specials */
+ if (ldb_dn_is_special(req->op.add.message->dn)) {
+ return ildb_request_noop(module, req);
+ }
+
+ msg = new_ldap_message(ildb->ldap);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->type = LDAP_TAG_AddRequest;
+
+ msg->r.AddRequest.dn = ldb_dn_linearize(msg, req->op.add.message->dn);
+ if (msg->r.AddRequest.dn == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ mods = ildb_msg_to_mods(msg, &n, req->op.add.message, 0);
+ if (mods == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->r.AddRequest.num_attributes = n;
+ msg->r.AddRequest.attributes = talloc_array(msg, struct ldb_message_element, n);
+ if (msg->r.AddRequest.attributes == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ for (i = 0; i < n; i++) {
+ msg->r.AddRequest.attributes[i] = mods[i]->attrib;
+ }
+
+ return ildb_request_send(module, msg, req->context, req->callback, req->timeout, &(req->handle));
+}
+
+/*
+ modify a record
+*/
+static int ildb_modify(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
+ struct ldap_message *msg;
+ struct ldap_mod **mods;
+ int i,n;
+
+ req->handle = NULL;
+
+ /* ignore ltdb specials */
+ if (ldb_dn_is_special(req->op.mod.message->dn)) {
+ return ildb_request_noop(module, req);
+ }
+
+ msg = new_ldap_message(ildb->ldap);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->type = LDAP_TAG_ModifyRequest;
+
+ msg->r.ModifyRequest.dn = ldb_dn_linearize(msg, req->op.mod.message->dn);
+ if (msg->r.ModifyRequest.dn == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ mods = ildb_msg_to_mods(msg, &n, req->op.mod.message, 1);
+ if (mods == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->r.ModifyRequest.num_mods = n;
+ msg->r.ModifyRequest.mods = talloc_array(msg, struct ldap_mod, n);
+ if (msg->r.ModifyRequest.mods == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ for (i = 0; i < n; i++) {
+ msg->r.ModifyRequest.mods[i] = *mods[i];
+ }
+
+ return ildb_request_send(module, msg, req->context, req->callback, req->timeout, &(req->handle));
+}
+
+/*
+ delete a record
+*/
+static int ildb_delete(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
+ struct ldap_message *msg;
+
+ req->handle = NULL;
+
+ /* ignore ltdb specials */
+ if (ldb_dn_is_special(req->op.del.dn)) {
+ return ildb_request_noop(module, req);
+ }
+
+ msg = new_ldap_message(ildb->ldap);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->type = LDAP_TAG_DelRequest;
+
+ msg->r.DelRequest.dn = ldb_dn_linearize(msg, req->op.del.dn);
+ if (msg->r.DelRequest.dn == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ return ildb_request_send(module, msg, req->context, req->callback, req->timeout, &(req->handle));
+}
+
+/*
+ rename a record
+*/
+static int ildb_rename(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
+ struct ldap_message *msg;
+
+ req->handle = NULL;
+
+ /* ignore ltdb specials */
+ if (ldb_dn_is_special(req->op.rename.olddn) || ldb_dn_is_special(req->op.rename.newdn)) {
+ return ildb_request_noop(module, req);
+ }
+
+ msg = new_ldap_message(ildb->ldap);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->type = LDAP_TAG_ModifyDNRequest;
+ msg->r.ModifyDNRequest.dn = ldb_dn_linearize(msg, req->op.rename.olddn);
+ if (msg->r.ModifyDNRequest.dn == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ msg->r.ModifyDNRequest.newrdn =
+ talloc_asprintf(msg, "%s=%s",
+ ldb_dn_get_rdn_name(req->op.rename.newdn),
+ ldb_dn_escape_value(msg, *ldb_dn_get_rdn_val(req->op.rename.newdn)));
+ if (msg->r.ModifyDNRequest.newrdn == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->r.ModifyDNRequest.newsuperior =
+ ldb_dn_linearize(msg,
+ ldb_dn_get_parent(msg, req->op.rename.newdn));
+ if (msg->r.ModifyDNRequest.newsuperior == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ msg->r.ModifyDNRequest.deleteolddn = True;
+
+ return ildb_request_send(module, msg, req->context, req->callback, req->timeout, &(req->handle));
+}
+
+static int ildb_start_trans(struct ldb_module *module)
+{
+ /* TODO implement a local locking mechanism here */
+
+ return LDB_SUCCESS;
+}
+
+static int ildb_end_trans(struct ldb_module *module)
+{
+ /* TODO implement a local transaction mechanism here */
+
+ return LDB_SUCCESS;
+}
+
+static int ildb_del_trans(struct ldb_module *module)
+{
+ /* TODO implement a local locking mechanism here */
+
+ return LDB_SUCCESS;
+}
+
+static int ildb_request(struct ldb_module *module, struct ldb_request *req)
+{
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+static int ildb_wait(struct ldb_handle *handle, enum ldb_wait_type type)
+{
+ struct ildb_context *ac = talloc_get_type(handle->private_data, struct ildb_context);
+
+ if (handle->state == LDB_ASYNC_DONE) {
+ return handle->status;
+ }
+
+ if (!ac) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ handle->state = LDB_ASYNC_INIT;
+
+ switch(type) {
+ case LDB_WAIT_NONE:
+ if (event_loop_once(ac->req->conn->event.event_ctx) != 0) {
+ return LDB_ERR_OTHER;
+ }
+ break;
+ case LDB_WAIT_ALL:
+ while (handle->status == LDB_SUCCESS && handle->state != LDB_ASYNC_DONE) {
+ if (event_loop_once(ac->req->conn->event.event_ctx) != 0) {
+ return LDB_ERR_OTHER;
+ }
+ }
+ break;
+ default:
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return handle->status;
+}
+
+static const struct ldb_module_ops ildb_ops = {
+ .name = "ldap",
+ .search = ildb_search,
+ .add = ildb_add,
+ .modify = ildb_modify,
+ .del = ildb_delete,
+ .rename = ildb_rename,
+ .request = ildb_request,
+ .start_transaction = ildb_start_trans,
+ .end_transaction = ildb_end_trans,
+ .del_transaction = ildb_del_trans,
+ .wait = ildb_wait
+};
+
+/*
+ connect to the database
+*/
+static int ildb_connect(struct ldb_context *ldb, const char *url,
+ unsigned int flags, const char *options[],
+ struct ldb_module **module)
+{
+ struct ildb_private *ildb = NULL;
+ NTSTATUS status;
+ struct cli_credentials *creds;
+
+ ildb = talloc(ldb, struct ildb_private);
+ if (!ildb) {
+ ldb_oom(ldb);
+ goto failed;
+ }
+
+ ildb->ldb = ldb;
+
+ ildb->ldap = ldap4_new_connection(ildb, ldb_get_opaque(ldb, "EventContext"));
+ if (!ildb->ldap) {
+ ldb_oom(ldb);
+ goto failed;
+ }
+
+ if (flags & LDB_FLG_RECONNECT) {
+ ldap_set_reconn_params(ildb->ldap, 10);
+ }
+
+ status = ldap_connect(ildb->ldap, url);
+ if (!NT_STATUS_IS_OK(status)) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to ldap URL '%s' - %s\n",
+ url, ldap_errstr(ildb->ldap, status));
+ goto failed;
+ }
+
+
+ *module = talloc(ldb, struct ldb_module);
+ if (!module) {
+ ldb_oom(ldb);
+ talloc_free(ildb);
+ return -1;
+ }
+ talloc_set_name_const(*module, "ldb_ildap backend");
+ (*module)->ldb = ldb;
+ (*module)->prev = (*module)->next = NULL;
+ (*module)->private_data = ildb;
+ (*module)->ops = &ildb_ops;
+
+ /* caller can optionally setup credentials using the opaque token 'credentials' */
+ creds = talloc_get_type(ldb_get_opaque(ldb, "credentials"), struct cli_credentials);
+ if (creds == NULL) {
+ struct auth_session_info *session_info = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"), struct auth_session_info);
+ if (session_info) {
+ creds = session_info->credentials;
+ }
+ }
+
+ if (creds != NULL && cli_credentials_authentication_requested(creds)) {
+ const char *bind_dn = cli_credentials_get_bind_dn(creds);
+ if (bind_dn) {
+ const char *password = cli_credentials_get_password(creds);
+ status = ldap_bind_simple(ildb->ldap, bind_dn, password);
+ if (!NT_STATUS_IS_OK(status)) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s\n",
+ ldap_errstr(ildb->ldap, status));
+ goto failed;
+ }
+ } else {
+ status = ldap_bind_sasl(ildb->ldap, creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s\n",
+ ldap_errstr(ildb->ldap, status));
+ goto failed;
+ }
+ }
+ }
+
+ return 0;
+
+failed:
+ talloc_free(ildb);
+ return -1;
+}
+
+int ldb_ildap_init(void)
+{
+ return ldb_register_backend("ldap", ildb_connect) +
+ ldb_register_backend("ldapi", ildb_connect) +
+ ldb_register_backend("ldaps", ildb_connect);
+}
diff --git a/source3/lib/ldb/ldb_ldap/ldb_ldap.c b/source3/lib/ldb/ldb_ldap/ldb_ldap.c
new file mode 100644
index 0000000000..51445d651f
--- /dev/null
+++ b/source3/lib/ldb/ldb_ldap/ldb_ldap.c
@@ -0,0 +1,846 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Simo Sorce 2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb_ldap
+ *
+ * Component: ldb ldap backend
+ *
+ * Description: core files for LDAP backend
+ *
+ * Author: Andrew Tridgell
+ *
+ * Modifications:
+ *
+ * - description: make the module use asyncronous calls
+ * date: Feb 2006
+ * author: Simo Sorce
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#define LDAP_DEPRECATED 1
+#include <ldap.h>
+
+struct lldb_private {
+ LDAP *ldap;
+};
+
+struct lldb_context {
+ struct ldb_module *module;
+ int msgid;
+ int timeout;
+ time_t starttime;
+ void *context;
+ int (*callback)(struct ldb_context *, void *, struct ldb_reply *);
+};
+
+static int lldb_ldap_to_ldb(int err) {
+ /* Ldap errors and ldb errors are defined to the same values */
+ return err;
+}
+
+static struct ldb_handle *init_handle(struct lldb_private *lldb, struct ldb_module *module,
+ void *context,
+ int (*callback)(struct ldb_context *, void *, struct ldb_reply *),
+ int timeout, time_t starttime)
+{
+ struct lldb_context *ac;
+ struct ldb_handle *h;
+
+ h = talloc_zero(lldb, struct ldb_handle);
+ if (h == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ return NULL;
+ }
+
+ h->module = module;
+
+ ac = talloc(h, struct lldb_context);
+ if (ac == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ talloc_free(h);
+ return NULL;
+ }
+
+ h->private_data = (void *)ac;
+
+ h->state = LDB_ASYNC_INIT;
+ h->status = LDB_SUCCESS;
+
+ ac->module = module;
+ ac->context = context;
+ ac->callback = callback;
+ ac->timeout = timeout;
+ ac->starttime = starttime;
+ ac->msgid = 0;
+
+ return h;
+}
+/*
+ convert a ldb_message structure to a list of LDAPMod structures
+ ready for ldap_add() or ldap_modify()
+*/
+static LDAPMod **lldb_msg_to_mods(void *mem_ctx, const struct ldb_message *msg, int use_flags)
+{
+ LDAPMod **mods;
+ unsigned int i, j;
+ int num_mods = 0;
+
+ /* allocate maximum number of elements needed */
+ mods = talloc_array(mem_ctx, LDAPMod *, msg->num_elements+1);
+ if (!mods) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ mods[0] = NULL;
+
+ for (i=0;i<msg->num_elements;i++) {
+ const struct ldb_message_element *el = &msg->elements[i];
+
+ mods[num_mods] = talloc(mods, LDAPMod);
+ if (!mods[num_mods]) {
+ goto failed;
+ }
+ mods[num_mods+1] = NULL;
+ mods[num_mods]->mod_op = LDAP_MOD_BVALUES;
+ if (use_flags) {
+ switch (el->flags & LDB_FLAG_MOD_MASK) {
+ case LDB_FLAG_MOD_ADD:
+ mods[num_mods]->mod_op |= LDAP_MOD_ADD;
+ break;
+ case LDB_FLAG_MOD_DELETE:
+ mods[num_mods]->mod_op |= LDAP_MOD_DELETE;
+ break;
+ case LDB_FLAG_MOD_REPLACE:
+ mods[num_mods]->mod_op |= LDAP_MOD_REPLACE;
+ break;
+ }
+ }
+ mods[num_mods]->mod_type = discard_const_p(char, el->name);
+ mods[num_mods]->mod_vals.modv_bvals = talloc_array(mods[num_mods],
+ struct berval *,
+ 1+el->num_values);
+ if (!mods[num_mods]->mod_vals.modv_bvals) {
+ goto failed;
+ }
+
+ for (j=0;j<el->num_values;j++) {
+ mods[num_mods]->mod_vals.modv_bvals[j] = talloc(mods[num_mods]->mod_vals.modv_bvals,
+ struct berval);
+ if (!mods[num_mods]->mod_vals.modv_bvals[j]) {
+ goto failed;
+ }
+ mods[num_mods]->mod_vals.modv_bvals[j]->bv_val =
+ (char *)el->values[j].data;
+ mods[num_mods]->mod_vals.modv_bvals[j]->bv_len = el->values[j].length;
+ }
+ mods[num_mods]->mod_vals.modv_bvals[j] = NULL;
+ num_mods++;
+ }
+
+ return mods;
+
+failed:
+ talloc_free(mods);
+ return NULL;
+}
+
+/*
+ add a single set of ldap message values to a ldb_message
+*/
+static int lldb_add_msg_attr(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ const char *attr, struct berval **bval)
+{
+ int count, i;
+ struct ldb_message_element *el;
+
+ count = ldap_count_values_len(bval);
+
+ if (count <= 0) {
+ return -1;
+ }
+
+ el = talloc_realloc(msg, msg->elements, struct ldb_message_element,
+ msg->num_elements + 1);
+ if (!el) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ msg->elements = el;
+
+ el = &msg->elements[msg->num_elements];
+
+ el->name = talloc_strdup(msg->elements, attr);
+ if (!el->name) {
+ errno = ENOMEM;
+ return -1;
+ }
+ el->flags = 0;
+
+ el->num_values = 0;
+ el->values = talloc_array(msg->elements, struct ldb_val, count);
+ if (!el->values) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ for (i=0;i<count;i++) {
+ /* we have to ensure this is null terminated so that
+ ldb_msg_find_attr_as_string() can work */
+ el->values[i].data =
+ (uint8_t *)talloc_size(el->values, bval[i]->bv_len+1);
+ if (!el->values[i].data) {
+ errno = ENOMEM;
+ return -1;
+ }
+ memcpy(el->values[i].data, bval[i]->bv_val, bval[i]->bv_len);
+ el->values[i].data[bval[i]->bv_len] = 0;
+ el->values[i].length = bval[i]->bv_len;
+ el->num_values++;
+ }
+
+ msg->num_elements++;
+
+ return 0;
+}
+
+/*
+ search for matching records
+*/
+static int lldb_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private);
+ struct lldb_context *lldb_ac;
+ struct timeval tv;
+ int ldap_scope;
+ char *search_base;
+ char *expression;
+ int ret;
+
+ if (!req->callback || !req->context) {
+ ldb_set_errstring(module->ldb, "Async interface called with NULL callback function or NULL context");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (req->op.search.tree == NULL) {
+ ldb_set_errstring(module->ldb, "Invalid expression parse tree");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (req->controls != NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls are not yet supported by ldb_ldap backend!\n");
+ }
+
+ req->handle = init_handle(lldb, module, req->context, req->callback, req->timeout, req->starttime);
+ if (req->handle == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ lldb_ac = talloc_get_type(req->handle->private_data, struct lldb_context);
+
+ search_base = ldb_dn_linearize(lldb_ac, req->op.search.base);
+ if (req->op.search.base == NULL) {
+ search_base = talloc_strdup(lldb_ac, "");
+ }
+ if (search_base == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ expression = ldb_filter_from_tree(
+ lldb_ac,
+ discard_const_p(struct ldb_parse_tree, req->op.search.tree));
+ if (expression == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ switch (req->op.search.scope) {
+ case LDB_SCOPE_BASE:
+ ldap_scope = LDAP_SCOPE_BASE;
+ break;
+ case LDB_SCOPE_ONELEVEL:
+ ldap_scope = LDAP_SCOPE_ONELEVEL;
+ break;
+ default:
+ ldap_scope = LDAP_SCOPE_SUBTREE;
+ break;
+ }
+
+ tv.tv_sec = req->timeout;
+ tv.tv_usec = 0;
+
+ ret = ldap_search_ext(lldb->ldap, search_base, ldap_scope,
+ expression,
+ discard_const_p(char *, req->op.search.attrs),
+ 0,
+ NULL,
+ NULL,
+ &tv,
+ LDAP_NO_LIMIT,
+ &lldb_ac->msgid);
+
+ if (ret != LDAP_SUCCESS) {
+ ldb_set_errstring(module->ldb, ldap_err2string(ret));
+ }
+
+ return lldb_ldap_to_ldb(ret);
+}
+
+/*
+ add a record
+*/
+static int lldb_add(struct ldb_module *module, struct ldb_request *req)
+{
+ struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private);
+ struct lldb_context *lldb_ac;
+ LDAPMod **mods;
+ char *dn;
+ int ret;
+
+ /* ltdb specials should not reach this point */
+ if (ldb_dn_is_special(req->op.add.message->dn)) {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ req->handle = init_handle(lldb, module, req->context, req->callback, req->timeout, req->starttime);
+ if (req->handle == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ lldb_ac = talloc_get_type(req->handle->private_data, struct lldb_context);
+
+ mods = lldb_msg_to_mods(lldb_ac, req->op.add.message, 0);
+ if (mods == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ dn = ldb_dn_linearize(lldb_ac, req->op.add.message->dn);
+ if (dn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldap_add_ext(lldb->ldap, dn, mods,
+ NULL,
+ NULL,
+ &lldb_ac->msgid);
+
+ if (ret != LDAP_SUCCESS) {
+ ldb_set_errstring(module->ldb, ldap_err2string(ret));
+ }
+
+ return lldb_ldap_to_ldb(ret);
+}
+
+/*
+ modify a record
+*/
+static int lldb_modify(struct ldb_module *module, struct ldb_request *req)
+{
+ struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private);
+ struct lldb_context *lldb_ac;
+ LDAPMod **mods;
+ char *dn;
+ int ret;
+
+ /* ltdb specials should not reach this point */
+ if (ldb_dn_is_special(req->op.mod.message->dn)) {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ req->handle = init_handle(lldb, module, req->context, req->callback, req->timeout, req->starttime);
+ if (req->handle == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ lldb_ac = talloc_get_type(req->handle->private_data, struct lldb_context);
+
+ mods = lldb_msg_to_mods(lldb_ac, req->op.mod.message, 1);
+ if (mods == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ dn = ldb_dn_linearize(lldb_ac, req->op.mod.message->dn);
+ if (dn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldap_modify_ext(lldb->ldap, dn, mods,
+ NULL,
+ NULL,
+ &lldb_ac->msgid);
+
+ if (ret != LDAP_SUCCESS) {
+ ldb_set_errstring(module->ldb, ldap_err2string(ret));
+ }
+
+ return lldb_ldap_to_ldb(ret);
+}
+
+/*
+ delete a record
+*/
+static int lldb_delete(struct ldb_module *module, struct ldb_request *req)
+{
+ struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private);
+ struct lldb_context *lldb_ac;
+ char *dnstr;
+ int ret;
+
+ /* ltdb specials should not reach this point */
+ if (ldb_dn_is_special(req->op.del.dn)) {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ req->handle = init_handle(lldb, module, req->context, req->callback, req->timeout, req->starttime);
+ if (req->handle == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ lldb_ac = talloc_get_type(req->handle->private_data, struct lldb_context);
+
+ dnstr = ldb_dn_linearize(lldb_ac, req->op.del.dn);
+
+ ret = ldap_delete_ext(lldb->ldap, dnstr,
+ NULL,
+ NULL,
+ &lldb_ac->msgid);
+
+ if (ret != LDAP_SUCCESS) {
+ ldb_set_errstring(module->ldb, ldap_err2string(ret));
+ }
+
+ return lldb_ldap_to_ldb(ret);
+}
+
+/*
+ rename a record
+*/
+static int lldb_rename(struct ldb_module *module, struct ldb_request *req)
+{
+ struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private);
+ struct lldb_context *lldb_ac;
+ char *old_dn;
+ char *newrdn;
+ char *parentdn;
+ int ret;
+
+ /* ltdb specials should not reach this point */
+ if (ldb_dn_is_special(req->op.rename.olddn) || ldb_dn_is_special(req->op.rename.newdn)) {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ req->handle = init_handle(lldb, module, req->context, req->callback, req->timeout, req->starttime);
+ if (req->handle == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ lldb_ac = talloc_get_type(req->handle->private_data, struct lldb_context);
+
+ old_dn = ldb_dn_linearize(lldb_ac, req->op.rename.olddn);
+ if (old_dn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ newrdn = talloc_asprintf(lldb_ac, "%s=%s",
+ ldb_dn_get_rdn_name(req->op.rename.newdn),
+ ldb_dn_escape_value(lldb, *(ldb_dn_get_rdn_val(req->op.rename.newdn))));
+ if (!newrdn) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ parentdn = ldb_dn_linearize(lldb_ac, ldb_dn_get_parent(lldb_ac, req->op.rename.newdn));
+ if (!parentdn) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldap_rename(lldb->ldap, old_dn, newrdn, parentdn,
+ 1, NULL, NULL,
+ &lldb_ac->msgid);
+
+ if (ret != LDAP_SUCCESS) {
+ ldb_set_errstring(module->ldb, ldap_err2string(ret));
+ }
+
+ return lldb_ldap_to_ldb(ret);
+}
+
+static int lldb_parse_result(struct ldb_handle *handle, LDAPMessage *result)
+{
+ struct lldb_context *ac = talloc_get_type(handle->private_data, struct lldb_context);
+ struct lldb_private *lldb = talloc_get_type(ac->module->private_data, struct lldb_private);
+ struct ldb_reply *ares = NULL;
+ LDAPMessage *msg;
+ int type;
+ char *matcheddnp = NULL;
+ char *errmsgp = NULL;
+ char **referralsp = NULL;
+ LDAPControl **serverctrlsp = NULL;
+ int ret = LDB_SUCCESS;
+
+ type = ldap_msgtype(result);
+
+ handle->status = 0;
+
+ switch (type) {
+
+ case LDAP_RES_SEARCH_ENTRY:
+ msg = ldap_first_entry(lldb->ldap, result);
+ if (msg != NULL) {
+ BerElement *berptr = NULL;
+ char *attr, *dn;
+
+ ares = talloc_zero(ac, struct ldb_reply);
+ if (!ares) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto error;
+ }
+
+ ares->message = ldb_msg_new(ares);
+ if (!ares->message) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto error;
+ }
+
+ dn = ldap_get_dn(lldb->ldap, msg);
+ if (!dn) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto error;
+ }
+ ares->message->dn = ldb_dn_explode_or_special(ares->message, dn);
+ if (ares->message->dn == NULL) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto error;
+ }
+ ldap_memfree(dn);
+
+ ares->message->num_elements = 0;
+ ares->message->elements = NULL;
+ ares->message->private_data = NULL;
+
+ /* loop over all attributes */
+ for (attr=ldap_first_attribute(lldb->ldap, msg, &berptr);
+ attr;
+ attr=ldap_next_attribute(lldb->ldap, msg, berptr)) {
+ struct berval **bval;
+ bval = ldap_get_values_len(lldb->ldap, msg, attr);
+
+ if (bval) {
+ lldb_add_msg_attr(ac->module->ldb, ares->message, attr, bval);
+ ldap_value_free_len(bval);
+ }
+ }
+ if (berptr) ber_free(berptr, 0);
+
+
+ ares->type = LDB_REPLY_ENTRY;
+ ret = ac->callback(ac->module->ldb, ac->context, ares);
+ } else {
+ handle->status = LDB_ERR_PROTOCOL_ERROR;
+ handle->state = LDB_ASYNC_DONE;
+ }
+ break;
+
+ case LDAP_RES_SEARCH_REFERENCE:
+ if (ldap_parse_result(lldb->ldap, result, &handle->status,
+ &matcheddnp, &errmsgp,
+ &referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto error;
+ }
+ if (referralsp == NULL) {
+ handle->status = LDB_ERR_PROTOCOL_ERROR;
+ goto error;
+ }
+
+ ares = talloc_zero(ac, struct ldb_reply);
+ if (!ares) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto error;
+ }
+
+ ares->referral = talloc_strdup(ares, *referralsp);
+ ares->type = LDB_REPLY_REFERRAL;
+ ret = ac->callback(ac->module->ldb, ac->context, ares);
+
+ break;
+
+ case LDAP_RES_SEARCH_RESULT:
+ if (ldap_parse_result(lldb->ldap, result, &handle->status,
+ &matcheddnp, &errmsgp,
+ &referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ goto error;
+ }
+
+ ares = talloc_zero(ac, struct ldb_reply);
+ if (!ares) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto error;
+ }
+
+ if (serverctrlsp != NULL) {
+ /* FIXME: transform the LDAPControl list into an ldb_control one */
+ ares->controls = NULL;
+ }
+
+ ares->type = LDB_REPLY_DONE;
+ handle->state = LDB_ASYNC_DONE;
+ ret = ac->callback(ac->module->ldb, ac->context, ares);
+
+ break;
+
+ case LDAP_RES_MODIFY:
+ case LDAP_RES_ADD:
+ case LDAP_RES_DELETE:
+ case LDAP_RES_MODDN:
+ if (ldap_parse_result(lldb->ldap, result, &handle->status,
+ &matcheddnp, &errmsgp,
+ &referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ goto error;
+ }
+ if (ac->callback && handle->status == LDB_SUCCESS) {
+ ares = NULL; /* FIXME: build a corresponding ares to pass on */
+ ret = ac->callback(ac->module->ldb, ac->context, ares);
+ }
+ handle->state = LDB_ASYNC_DONE;
+ break;
+
+ default:
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ goto error;
+ }
+
+ if (matcheddnp) ldap_memfree(matcheddnp);
+ if (errmsgp && *errmsgp) {
+ ldb_set_errstring(ac->module->ldb, errmsgp);
+ } else if (handle->status) {
+ ldb_set_errstring(ac->module->ldb, ldap_err2string(handle->status));
+ }
+ if (errmsgp) {
+ ldap_memfree(errmsgp);
+ }
+ if (referralsp) ldap_value_free(referralsp);
+ if (serverctrlsp) ldap_controls_free(serverctrlsp);
+
+ ldap_msgfree(result);
+ return lldb_ldap_to_ldb(handle->status);
+
+error:
+ handle->state = LDB_ASYNC_DONE;
+ ldap_msgfree(result);
+ return ret;
+}
+
+static int lldb_wait(struct ldb_handle *handle, enum ldb_wait_type type)
+{
+ struct lldb_context *ac = talloc_get_type(handle->private_data, struct lldb_context);
+ struct lldb_private *lldb = talloc_get_type(handle->module->private_data, struct lldb_private);
+ struct timeval timeout;
+ LDAPMessage *result;
+ int ret, lret;
+
+ if (handle->state == LDB_ASYNC_DONE) {
+ return handle->status;
+ }
+
+ if (!ac || !ac->msgid) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ handle->state = LDB_ASYNC_PENDING;
+ handle->status = LDB_SUCCESS;
+
+ switch(type) {
+ case LDB_WAIT_NONE:
+
+ if ((ac->timeout != -1) &&
+ ((ac->starttime + ac->timeout) > time(NULL))) {
+ return LDB_ERR_TIME_LIMIT_EXCEEDED;
+ }
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ lret = ldap_result(lldb->ldap, ac->msgid, 0, &timeout, &result);
+ if (lret == -1) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (lret == 0) {
+ ret = LDB_SUCCESS;
+ goto done;
+ }
+
+ return lldb_parse_result(handle, result);
+
+ case LDB_WAIT_ALL:
+ timeout.tv_usec = 0;
+ ret = LDB_ERR_OPERATIONS_ERROR;
+
+ while (handle->status == LDB_SUCCESS && handle->state != LDB_ASYNC_DONE) {
+
+ if (ac->timeout == -1) {
+ lret = ldap_result(lldb->ldap, ac->msgid, 0, NULL, &result);
+ } else {
+ timeout.tv_sec = ac->timeout - (time(NULL) - ac->starttime);
+ if (timeout.tv_sec <= 0)
+ return LDB_ERR_TIME_LIMIT_EXCEEDED;
+ lret = ldap_result(lldb->ldap, ac->msgid, 0, &timeout, &result);
+ }
+ if (lret == -1) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (lret == 0) {
+ return LDB_ERR_TIME_LIMIT_EXCEEDED;
+ }
+
+ ret = lldb_parse_result(handle, result);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ break;
+
+ default:
+ handle->state = LDB_ASYNC_DONE;
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ }
+
+done:
+ return ret;
+}
+
+static int lldb_start_trans(struct ldb_module *module)
+{
+ /* TODO implement a local transaction mechanism here */
+
+ return LDB_SUCCESS;
+}
+
+static int lldb_end_trans(struct ldb_module *module)
+{
+ /* TODO implement a local transaction mechanism here */
+
+ return LDB_SUCCESS;
+}
+
+static int lldb_del_trans(struct ldb_module *module)
+{
+ /* TODO implement a local transaction mechanism here */
+
+ return LDB_SUCCESS;
+}
+
+static int lldb_request(struct ldb_module *module, struct ldb_request *req)
+{
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+static const struct ldb_module_ops lldb_ops = {
+ .name = "ldap",
+ .search = lldb_search,
+ .add = lldb_add,
+ .modify = lldb_modify,
+ .del = lldb_delete,
+ .rename = lldb_rename,
+ .request = lldb_request,
+ .start_transaction = lldb_start_trans,
+ .end_transaction = lldb_end_trans,
+ .del_transaction = lldb_del_trans,
+ .wait = lldb_wait
+};
+
+
+static int lldb_destructor(struct lldb_private *lldb)
+{
+ ldap_unbind(lldb->ldap);
+ return 0;
+}
+
+/*
+ connect to the database
+*/
+static int lldb_connect(struct ldb_context *ldb,
+ const char *url,
+ unsigned int flags,
+ const char *options[],
+ struct ldb_module **module)
+{
+ struct lldb_private *lldb = NULL;
+ int version = 3;
+ int ret;
+
+ lldb = talloc(ldb, struct lldb_private);
+ if (!lldb) {
+ ldb_oom(ldb);
+ goto failed;
+ }
+
+ lldb->ldap = NULL;
+
+ ret = ldap_initialize(&lldb->ldap, url);
+ if (ret != LDAP_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "ldap_initialize failed for URL '%s' - %s\n",
+ url, ldap_err2string(ret));
+ goto failed;
+ }
+
+ talloc_set_destructor(lldb, lldb_destructor);
+
+ ret = ldap_set_option(lldb->ldap, LDAP_OPT_PROTOCOL_VERSION, &version);
+ if (ret != LDAP_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "ldap_set_option failed - %s\n",
+ ldap_err2string(ret));
+ goto failed;
+ }
+
+ *module = talloc(ldb, struct ldb_module);
+ if (*module == NULL) {
+ ldb_oom(ldb);
+ talloc_free(lldb);
+ return -1;
+ }
+ talloc_set_name_const(*module, "ldb_ldap backend");
+ (*module)->ldb = ldb;
+ (*module)->prev = (*module)->next = NULL;
+ (*module)->private_data = lldb;
+ (*module)->ops = &lldb_ops;
+
+ return 0;
+
+failed:
+ talloc_free(lldb);
+ return -1;
+}
+
+int ldb_ldap_init(void)
+{
+ return ldb_register_backend("ldap", lldb_connect) +
+ ldb_register_backend("ldapi", lldb_connect) +
+ ldb_register_backend("ldaps", lldb_connect);
+}
diff --git a/source3/lib/ldb/ldb_sqlite3/README b/source3/lib/ldb/ldb_sqlite3/README
new file mode 100644
index 0000000000..6cda0a7759
--- /dev/null
+++ b/source3/lib/ldb/ldb_sqlite3/README
@@ -0,0 +1,7 @@
+trees.ps contains an explanation of the Genealogical Representation of Trees
+in Databases which is being used in ldb_sqlite3. Note that we use fgID
+representation with 4 bytes per level, so we can represent 6.5E+08 subclasses
+of any object class. This should be adequate for our purposes. :-)
+
+The following document is the primary basis for the schema currently being
+used here: http://www.research.ibm.com/journal/sj/392/shi.html
diff --git a/source3/lib/ldb/ldb_sqlite3/base160.c b/source3/lib/ldb/ldb_sqlite3/base160.c
new file mode 100644
index 0000000000..423e2b6841
--- /dev/null
+++ b/source3/lib/ldb/ldb_sqlite3/base160.c
@@ -0,0 +1,154 @@
+/*
+ base160 code used by ldb_sqlite3
+
+ Copyright (C) 2004 Derrell Lipman
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*
+ * ldb_sqlite3_base160()
+ *
+ * Convert an integer value to a string containing the base 160 representation
+ * of the integer. We always convert to a string representation that is 4
+ * bytes in length, and we always null terminate.
+ *
+ * Parameters:
+ * val --
+ * The value to be converted
+ *
+ * result --
+ * Buffer in which the result is to be placed
+ *
+ * Returns:
+ * nothing
+ */
+static unsigned char base160tab[161] =
+{
+ 48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 , 56 , 57 , /* 0-9 */
+ 58 , 59 , 65 , 66 , 67 , 68 , 69 , 70 , 71 , 72 , /* : ; A-H */
+ 73 , 74 , 75 , 76 , 77 , 78 , 79 , 80 , 81 , 82 , /* I-R */
+ 83 , 84 , 85 , 86 , 87 , 88 , 89 , 90 , 97 , 98 , /* S-Z , a-b */
+ 99 , 100, 101, 102, 103, 104, 105, 106, 107, 108, /* c-l */
+ 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, /* m-v */
+ 119, 120, 121, 122, 160, 161, 162, 163, 164, 165, /* w-z, latin1 */
+ 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, /* latin1 */
+ 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, /* latin1 */
+ 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, /* latin1 */
+ 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, /* latin1 */
+ 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, /* latin1 */
+ 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, /* latin1 */
+ 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, /* latin1 */
+ 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, /* latin1 */
+ 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, /* latin1 */
+ '\0'
+};
+
+
+/*
+ * lsqlite3_base160()
+ *
+ * Convert an unsigned long integer into a base160 representation of the
+ * number.
+ *
+ * Parameters:
+ * val --
+ * value to be converted
+ *
+ * result --
+ * character array, 5 bytes long, into which the base160 representation
+ * will be placed. The result will be a four-digit representation of the
+ * number (with leading zeros prepended as necessary), and null
+ * terminated.
+ *
+ * Returns:
+ * Nothing
+ */
+void
+lsqlite3_base160(unsigned long val,
+ unsigned char result[5])
+{
+ int i;
+
+ for (i = 3; i >= 0; i--) {
+
+ result[i] = base160tab[val % 160];
+ val /= 160;
+ }
+
+ result[4] = '\0';
+}
+
+
+/*
+ * lsqlite3_base160Next()
+ *
+ * Retrieve the next-greater number in the base160 sequence for the terminal
+ * tree node (the last four digits). Only one tree level (four digits) are
+ * operated on.
+ *
+ * Parameters:
+ * base160 -- a character array containing either an empty string (in which
+ * case no operation is performed), or a string of base160 digits
+ * with a length of a multiple of four digits.
+ *
+ * Upon return, the trailing four digits (one tree level) will
+ * have been incremented by 1.
+ *
+ * Returns:
+ * base160 -- the modified array
+ */
+char *
+lsqlite3_base160Next(char base160[])
+{
+ int i;
+ int len;
+ unsigned char * pTab;
+ char * pBase160 = base160;
+
+ /*
+ * We need a minimum of four digits, and we will always get a multiple of
+ * four digits.
+ */
+ if (len = strlen(pBase160)) >= 4)
+ {
+ pBase160 += strlen(pBase160) - 1;
+
+ /* We only carry through four digits: one level in the tree */
+ for (i = 0; i < 4; i++) {
+
+ /* What base160 value does this digit have? */
+ pTab = strchr(base160tab, *pBase160);
+
+ /* Is there a carry? */
+ if (pTab < base160tab + sizeof(base160tab) - 1) {
+
+ /* Nope. Just increment this value and we're done. */
+ *pBase160 = *++pTab;
+ break;
+ } else {
+
+ /*
+ * There's a carry. This value gets base160tab[0], we
+ * decrement the buffer pointer to get the next higher-order
+ * digit, and continue in the loop.
+ */
+ *pBase160-- = base160tab[0];
+ }
+ }
+ }
+
+ return base160;
+}
diff --git a/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
new file mode 100644
index 0000000000..cb516b6e75
--- /dev/null
+++ b/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
@@ -0,0 +1,1911 @@
+/*
+ ldb database library
+
+ Copyright (C) Derrell Lipman 2005
+ Copyright (C) Simo Sorce 2005-2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb sqlite3 backend
+ *
+ * Description: core files for SQLITE3 backend
+ *
+ * Author: Derrell Lipman (based on Andrew Tridgell's LDAP backend)
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#include <sqlite3.h>
+
+struct lsqlite3_private {
+ int trans_count;
+ char **options;
+ sqlite3 *sqlite;
+};
+
+struct lsql_context {
+ struct ldb_module *module;
+
+ /* search stuff */
+ long long current_eid;
+ const char * const * attrs;
+ struct ldb_reply *ares;
+
+ /* async stuff */
+ void *context;
+ int (*callback)(struct ldb_context *, void *, struct ldb_reply *);
+};
+
+static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3,
+ struct ldb_module *module,
+ struct ldb_request *req)
+{
+ struct lsql_context *ac;
+ struct ldb_handle *h;
+
+ h = talloc_zero(lsqlite3, struct ldb_handle);
+ if (h == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ return NULL;
+ }
+
+ h->module = module;
+
+ ac = talloc(h, struct lsql_context);
+ if (ac == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ talloc_free(h);
+ return NULL;
+ }
+
+ h->private_data = (void *)ac;
+
+ h->state = LDB_ASYNC_INIT;
+ h->status = LDB_SUCCESS;
+
+ ac->module = module;
+ ac->context = req->context;
+ ac->callback = req->callback;
+
+ return h;
+}
+
+/*
+ * Macros used throughout
+ */
+
+#ifndef FALSE
+# define FALSE (0)
+# define TRUE (! FALSE)
+#endif
+
+#define RESULT_ATTR_TABLE "temp_result_attrs"
+
+//#define TEMPTAB /* for testing, create non-temporary table */
+#define TEMPTAB "TEMPORARY"
+
+/*
+ * Static variables
+ */
+sqlite3_stmt * stmtGetEID = NULL;
+
+static char *lsqlite3_tprintf(TALLOC_CTX *mem_ctx, const char *fmt, ...)
+{
+ char *str, *ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ str = sqlite3_vmprintf(fmt, ap);
+ va_end(ap);
+
+ if (str == NULL) return NULL;
+
+ ret = talloc_strdup(mem_ctx, str);
+ if (ret == NULL) {
+ sqlite3_free(str);
+ return NULL;
+ }
+
+ sqlite3_free(str);
+ return ret;
+}
+
+static char base160tab[161] = {
+ 48 ,49 ,50 ,51 ,52 ,53 ,54 ,55 ,56 ,57 , /* 0-9 */
+ 58 ,59 ,65 ,66 ,67 ,68 ,69 ,70 ,71 ,72 , /* : ; A-H */
+ 73 ,74 ,75 ,76 ,77 ,78 ,79 ,80 ,81 ,82 , /* I-R */
+ 83 ,84 ,85 ,86 ,87 ,88 ,89 ,90 ,97 ,98 , /* S-Z , a-b */
+ 99 ,100,101,102,103,104,105,106,107,108, /* c-l */
+ 109,110,111,112,113,114,115,116,117,118, /* m-v */
+ 119,120,121,122,160,161,162,163,164,165, /* w-z, latin1 */
+ 166,167,168,169,170,171,172,173,174,175, /* latin1 */
+ 176,177,178,179,180,181,182,183,184,185, /* latin1 */
+ 186,187,188,189,190,191,192,193,194,195, /* latin1 */
+ 196,197,198,199,200,201,202,203,204,205, /* latin1 */
+ 206,207,208,209,210,211,212,213,214,215, /* latin1 */
+ 216,217,218,219,220,221,222,223,224,225, /* latin1 */
+ 226,227,228,229,230,231,232,233,234,235, /* latin1 */
+ 236,237,238,239,240,241,242,243,244,245, /* latin1 */
+ 246,247,248,249,250,251,252,253,254,255, /* latin1 */
+ '\0'
+};
+
+
+/*
+ * base160()
+ *
+ * Convert an unsigned long integer into a base160 representation of the
+ * number.
+ *
+ * Parameters:
+ * val --
+ * value to be converted
+ *
+ * result --
+ * character array, 5 bytes long, into which the base160 representation
+ * will be placed. The result will be a four-digit representation of the
+ * number (with leading zeros prepended as necessary), and null
+ * terminated.
+ *
+ * Returns:
+ * Nothing
+ */
+static void
+base160_sql(sqlite3_context * hContext,
+ int argc,
+ sqlite3_value ** argv)
+{
+ int i;
+ long long val;
+ char result[5];
+
+ val = sqlite3_value_int64(argv[0]);
+
+ for (i = 3; i >= 0; i--) {
+
+ result[i] = base160tab[val % 160];
+ val /= 160;
+ }
+
+ result[4] = '\0';
+
+ sqlite3_result_text(hContext, result, -1, SQLITE_TRANSIENT);
+}
+
+
+/*
+ * base160next_sql()
+ *
+ * This function enhances sqlite by adding a "base160_next()" function which is
+ * accessible via queries.
+ *
+ * Retrieve the next-greater number in the base160 sequence for the terminal
+ * tree node (the last four digits). Only one tree level (four digits) is
+ * operated on.
+ *
+ * Input:
+ * A character string: either an empty string (in which case no operation is
+ * performed), or a string of base160 digits with a length of a multiple of
+ * four digits.
+ *
+ * Output:
+ * Upon return, the trailing four digits (one tree level) will have been
+ * incremented by 1.
+ */
+static void
+base160next_sql(sqlite3_context * hContext,
+ int argc,
+ sqlite3_value ** argv)
+{
+ int i;
+ int len;
+ char * pTab;
+ char * pBase160 = strdup((const char *)sqlite3_value_text(argv[0]));
+ char * pStart = pBase160;
+
+ /*
+ * We need a minimum of four digits, and we will always get a multiple
+ * of four digits.
+ */
+ if (pBase160 != NULL &&
+ (len = strlen(pBase160)) >= 4 &&
+ len % 4 == 0) {
+
+ if (pBase160 == NULL) {
+
+ sqlite3_result_null(hContext);
+ return;
+ }
+
+ pBase160 += strlen(pBase160) - 1;
+
+ /* We only carry through four digits: one level in the tree */
+ for (i = 0; i < 4; i++) {
+
+ /* What base160 value does this digit have? */
+ pTab = strchr(base160tab, *pBase160);
+
+ /* Is there a carry? */
+ if (pTab < base160tab + sizeof(base160tab) - 1) {
+
+ /*
+ * Nope. Just increment this value and we're
+ * done.
+ */
+ *pBase160 = *++pTab;
+ break;
+ } else {
+
+ /*
+ * There's a carry. This value gets
+ * base160tab[0], we decrement the buffer
+ * pointer to get the next higher-order digit,
+ * and continue in the loop.
+ */
+ *pBase160-- = base160tab[0];
+ }
+ }
+
+ sqlite3_result_text(hContext,
+ pStart,
+ strlen(pStart),
+ free);
+ } else {
+ sqlite3_result_value(hContext, argv[0]);
+ if (pBase160 != NULL) {
+ free(pBase160);
+ }
+ }
+}
+
+static char *parsetree_to_sql(struct ldb_module *module,
+ void *mem_ctx,
+ const struct ldb_parse_tree *t)
+{
+ const struct ldb_attrib_handler *h;
+ struct ldb_val value, subval;
+ char *wild_card_string;
+ char *child, *tmp;
+ char *ret = NULL;
+ char *attr;
+ int i;
+
+
+ switch(t->operation) {
+ case LDB_OP_AND:
+
+ tmp = parsetree_to_sql(module, mem_ctx, t->u.list.elements[0]);
+ if (tmp == NULL) return NULL;
+
+ for (i = 1; i < t->u.list.num_elements; i++) {
+
+ child = parsetree_to_sql(module, mem_ctx, t->u.list.elements[i]);
+ if (child == NULL) return NULL;
+
+ tmp = talloc_asprintf_append(tmp, " INTERSECT %s ", child);
+ if (tmp == NULL) return NULL;
+ }
+
+ ret = talloc_asprintf(mem_ctx, "SELECT * FROM ( %s )\n", tmp);
+
+ return ret;
+
+ case LDB_OP_OR:
+
+ tmp = parsetree_to_sql(module, mem_ctx, t->u.list.elements[0]);
+ if (tmp == NULL) return NULL;
+
+ for (i = 1; i < t->u.list.num_elements; i++) {
+
+ child = parsetree_to_sql(module, mem_ctx, t->u.list.elements[i]);
+ if (child == NULL) return NULL;
+
+ tmp = talloc_asprintf_append(tmp, " UNION %s ", child);
+ if (tmp == NULL) return NULL;
+ }
+
+ return talloc_asprintf(mem_ctx, "SELECT * FROM ( %s ) ", tmp);
+
+ case LDB_OP_NOT:
+
+ child = parsetree_to_sql(module, mem_ctx, t->u.isnot.child);
+ if (child == NULL) return NULL;
+
+ return talloc_asprintf(mem_ctx,
+ "SELECT eid FROM ldb_entry "
+ "WHERE eid NOT IN ( %s ) ", child);
+
+ case LDB_OP_EQUALITY:
+ /*
+ * For simple searches, we want to retrieve the list of EIDs that
+ * match the criteria.
+ */
+ attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr);
+ if (attr == NULL) return NULL;
+ h = ldb_attrib_handler(module->ldb, attr);
+
+ /* Get a canonicalised copy of the data */
+ h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value);
+ if (value.data == NULL) {
+ return NULL;
+ }
+
+ if (strcasecmp(t->u.equality.attr, "objectclass") == 0) {
+ /*
+ * For object classes, we want to search for all objectclasses
+ * that are subclasses as well.
+ */
+ return lsqlite3_tprintf(mem_ctx,
+ "SELECT eid FROM ldb_attribute_values\n"
+ "WHERE norm_attr_name = 'OBJECTCLASS' "
+ "AND norm_attr_value IN\n"
+ " (SELECT class_name FROM ldb_object_classes\n"
+ " WHERE tree_key GLOB\n"
+ " (SELECT tree_key FROM ldb_object_classes\n"
+ " WHERE class_name = '%q'\n"
+ " ) || '*'\n"
+ " )\n", value.data);
+
+ } else if (strcasecmp(t->u.equality.attr, "dn") == 0) {
+ /* DN query is a special ldb case */
+ char *cdn = ldb_dn_linearize_casefold(module->ldb,
+ mem_ctx,
+ ldb_dn_explode(module->ldb,
+ (const char *)value.data));
+
+ return lsqlite3_tprintf(mem_ctx,
+ "SELECT eid FROM ldb_entry "
+ "WHERE norm_dn = '%q'", cdn);
+
+ } else {
+ /* A normal query. */
+ return lsqlite3_tprintf(mem_ctx,
+ "SELECT eid FROM ldb_attribute_values "
+ "WHERE norm_attr_name = '%q' "
+ "AND norm_attr_value = '%q'",
+ attr,
+ value.data);
+
+ }
+
+ case LDB_OP_SUBSTRING:
+
+ wild_card_string = talloc_strdup(mem_ctx,
+ (t->u.substring.start_with_wildcard)?"*":"");
+ if (wild_card_string == NULL) return NULL;
+
+ for (i = 0; t->u.substring.chunks[i]; i++) {
+ wild_card_string = talloc_asprintf_append(wild_card_string, "%s*",
+ t->u.substring.chunks[i]->data);
+ if (wild_card_string == NULL) return NULL;
+ }
+
+ if ( ! t->u.substring.end_with_wildcard ) {
+ /* remove last wildcard */
+ wild_card_string[strlen(wild_card_string) - 1] = '\0';
+ }
+
+ attr = ldb_attr_casefold(mem_ctx, t->u.substring.attr);
+ if (attr == NULL) return NULL;
+ h = ldb_attrib_handler(module->ldb, attr);
+
+ subval.data = (void *)wild_card_string;
+ subval.length = strlen(wild_card_string) + 1;
+
+ /* Get a canonicalised copy of the data */
+ h->canonicalise_fn(module->ldb, mem_ctx, &(subval), &value);
+ if (value.data == NULL) {
+ return NULL;
+ }
+
+ return lsqlite3_tprintf(mem_ctx,
+ "SELECT eid FROM ldb_attribute_values "
+ "WHERE norm_attr_name = '%q' "
+ "AND norm_attr_value GLOB '%q'",
+ attr,
+ value.data);
+
+ case LDB_OP_GREATER:
+ attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr);
+ if (attr == NULL) return NULL;
+ h = ldb_attrib_handler(module->ldb, attr);
+
+ /* Get a canonicalised copy of the data */
+ h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value);
+ if (value.data == NULL) {
+ return NULL;
+ }
+
+ return lsqlite3_tprintf(mem_ctx,
+ "SELECT eid FROM ldb_attribute_values "
+ "WHERE norm_attr_name = '%q' "
+ "AND ldap_compare(norm_attr_value, '>=', '%q', '%q') ",
+ attr,
+ value.data,
+ attr);
+
+ case LDB_OP_LESS:
+ attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr);
+ if (attr == NULL) return NULL;
+ h = ldb_attrib_handler(module->ldb, attr);
+
+ /* Get a canonicalised copy of the data */
+ h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value);
+ if (value.data == NULL) {
+ return NULL;
+ }
+
+ return lsqlite3_tprintf(mem_ctx,
+ "SELECT eid FROM ldb_attribute_values "
+ "WHERE norm_attr_name = '%q' "
+ "AND ldap_compare(norm_attr_value, '<=', '%q', '%q') ",
+ attr,
+ value.data,
+ attr);
+
+ case LDB_OP_PRESENT:
+ if (strcasecmp(t->u.present.attr, "dn") == 0) {
+ return talloc_strdup(mem_ctx, "SELECT eid FROM ldb_entry");
+ }
+
+ attr = ldb_attr_casefold(mem_ctx, t->u.present.attr);
+ if (attr == NULL) return NULL;
+
+ return lsqlite3_tprintf(mem_ctx,
+ "SELECT eid FROM ldb_attribute_values "
+ "WHERE norm_attr_name = '%q' ",
+ attr);
+
+ case LDB_OP_APPROX:
+ attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr);
+ if (attr == NULL) return NULL;
+ h = ldb_attrib_handler(module->ldb, attr);
+
+ /* Get a canonicalised copy of the data */
+ h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value);
+ if (value.data == NULL) {
+ return NULL;
+ }
+
+ return lsqlite3_tprintf(mem_ctx,
+ "SELECT eid FROM ldb_attribute_values "
+ "WHERE norm_attr_name = '%q' "
+ "AND ldap_compare(norm_attr_value, '~%', 'q', '%q') ",
+ attr,
+ value.data,
+ attr);
+
+ case LDB_OP_EXTENDED:
+#warning "work out how to handle bitops"
+ return NULL;
+
+ default:
+ break;
+ };
+
+ /* should never occur */
+ abort();
+ return NULL;
+}
+
+/*
+ * query_int()
+ *
+ * This function is used for the common case of queries that return a single
+ * integer value.
+ *
+ * NOTE: If more than one value is returned by the query, all but the first
+ * one will be ignored.
+ */
+static int
+query_int(const struct lsqlite3_private * lsqlite3,
+ long long * pRet,
+ const char * pSql,
+ ...)
+{
+ int ret;
+ int bLoop;
+ char * p;
+ sqlite3_stmt * pStmt;
+ va_list args;
+
+ /* Begin access to variable argument list */
+ va_start(args, pSql);
+
+ /* Format the query */
+ if ((p = sqlite3_vmprintf(pSql, args)) == NULL) {
+ return SQLITE_NOMEM;
+ }
+
+ /*
+ * Prepare and execute the SQL statement. Loop allows retrying on
+ * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes,
+ * requiring retrying the operation.
+ */
+ for (bLoop = TRUE; bLoop; ) {
+
+ /* Compile the SQL statement into sqlite virtual machine */
+ if ((ret = sqlite3_prepare(lsqlite3->sqlite,
+ p,
+ -1,
+ &pStmt,
+ NULL)) == SQLITE_SCHEMA) {
+ if (stmtGetEID != NULL) {
+ sqlite3_finalize(stmtGetEID);
+ stmtGetEID = NULL;
+ }
+ continue;
+ } else if (ret != SQLITE_OK) {
+ break;
+ }
+
+ /* One row expected */
+ if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) {
+ if (stmtGetEID != NULL) {
+ sqlite3_finalize(stmtGetEID);
+ stmtGetEID = NULL;
+ }
+ (void) sqlite3_finalize(pStmt);
+ continue;
+ } else if (ret != SQLITE_ROW) {
+ (void) sqlite3_finalize(pStmt);
+ break;
+ }
+
+ /* Get the value to be returned */
+ *pRet = sqlite3_column_int64(pStmt, 0);
+
+ /* Free the virtual machine */
+ if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) {
+ if (stmtGetEID != NULL) {
+ sqlite3_finalize(stmtGetEID);
+ stmtGetEID = NULL;
+ }
+ continue;
+ } else if (ret != SQLITE_OK) {
+ (void) sqlite3_finalize(pStmt);
+ break;
+ }
+
+ /*
+ * Normal condition is only one time through loop. Loop is
+ * rerun in error conditions, via "continue", above.
+ */
+ bLoop = FALSE;
+ }
+
+ /* All done with variable argument list */
+ va_end(args);
+
+
+ /* Free the memory we allocated for our query string */
+ sqlite3_free(p);
+
+ return ret;
+}
+
+/*
+ * This is a bad hack to support ldap style comparisons whithin sqlite.
+ * val is the attribute in the row currently under test
+ * func is the desired test "<=" ">=" "~" ":"
+ * cmp is the value to compare against (eg: "test")
+ * attr is the attribute name the value of which we want to test
+ */
+
+static void lsqlite3_compare(sqlite3_context *ctx, int argc,
+ sqlite3_value **argv)
+{
+ struct ldb_context *ldb = (struct ldb_context *)sqlite3_user_data(ctx);
+ const char *val = (const char *)sqlite3_value_text(argv[0]);
+ const char *func = (const char *)sqlite3_value_text(argv[1]);
+ const char *cmp = (const char *)sqlite3_value_text(argv[2]);
+ const char *attr = (const char *)sqlite3_value_text(argv[3]);
+ const struct ldb_attrib_handler *h;
+ struct ldb_val valX;
+ struct ldb_val valY;
+ int ret;
+
+ switch (func[0]) {
+ /* greater */
+ case '>': /* >= */
+ h = ldb_attrib_handler(ldb, attr);
+ valX.data = (void *)cmp;
+ valX.length = strlen(cmp);
+ valY.data = (void *)val;
+ valY.length = strlen(val);
+ ret = h->comparison_fn(ldb, ldb, &valY, &valX);
+ if (ret >= 0)
+ sqlite3_result_int(ctx, 1);
+ else
+ sqlite3_result_int(ctx, 0);
+ return;
+
+ /* lesser */
+ case '<': /* <= */
+ h = ldb_attrib_handler(ldb, attr);
+ valX.data = (void *)cmp;
+ valX.length = strlen(cmp);
+ valY.data = (void *)val;
+ valY.length = strlen(val);
+ ret = h->comparison_fn(ldb, ldb, &valY, &valX);
+ if (ret <= 0)
+ sqlite3_result_int(ctx, 1);
+ else
+ sqlite3_result_int(ctx, 0);
+ return;
+
+ /* approx */
+ case '~':
+ /* TODO */
+ sqlite3_result_int(ctx, 0);
+ return;
+
+ /* bitops */
+ case ':':
+ /* TODO */
+ sqlite3_result_int(ctx, 0);
+ return;
+
+ default:
+ break;
+ }
+
+ sqlite3_result_error(ctx, "Value must start with a special operation char (<>~:)!", -1);
+ return;
+}
+
+
+/* rename a record */
+static int lsqlite3_safe_rollback(sqlite3 *sqlite)
+{
+ char *errmsg;
+ int ret;
+
+ /* execute */
+ ret = sqlite3_exec(sqlite, "ROLLBACK;", NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3_safe_rollback: Error: %s\n", errmsg);
+ free(errmsg);
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+/* return an eid as result */
+static int lsqlite3_eid_callback(void *result, int col_num, char **cols, char **names)
+{
+ long long *eid = (long long *)result;
+
+ if (col_num != 1) return SQLITE_ABORT;
+ if (strcasecmp(names[0], "eid") != 0) return SQLITE_ABORT;
+
+ *eid = atoll(cols[0]);
+ return SQLITE_OK;
+}
+
+/*
+ * add a single set of ldap message values to a ldb_message
+ */
+static int lsqlite3_search_callback(void *result, int col_num, char **cols, char **names)
+{
+ struct ldb_handle *handle = talloc_get_type(result, struct ldb_handle);
+ struct lsql_context *ac = talloc_get_type(handle->private_data, struct lsql_context);
+ struct ldb_message *msg;
+ long long eid;
+ int i;
+
+ /* eid, dn, attr_name, attr_value */
+ if (col_num != 4)
+ return SQLITE_ABORT;
+
+ eid = atoll(cols[0]);
+
+ if (eid != ac->current_eid) { /* here begin a new entry */
+
+ /* call the async callback for the last entry
+ * except the first time */
+ if (ac->current_eid != 0) {
+ ac->ares->message = ldb_msg_canonicalize(ac->module->ldb, ac->ares->message);
+ if (ac->ares->message == NULL)
+ return SQLITE_ABORT;
+
+ handle->status = ac->callback(ac->module->ldb, ac->context, ac->ares);
+ if (handle->status != LDB_SUCCESS)
+ return SQLITE_ABORT;
+ }
+
+ /* start over */
+ ac->ares = talloc_zero(ac, struct ldb_reply);
+ if (!ac->ares)
+ return SQLITE_ABORT;
+
+ ac->ares->message = ldb_msg_new(ac->ares);
+ if (!ac->ares->message)
+ return SQLITE_ABORT;
+
+ ac->ares->type = LDB_REPLY_ENTRY;
+ ac->current_eid = eid;
+ }
+
+ msg = ac->ares->message;
+
+ if (msg->dn == NULL) {
+ msg->dn = ldb_dn_explode(msg, cols[1]);
+ if (msg->dn == NULL)
+ return SQLITE_ABORT;
+ }
+
+ if (ac->attrs) {
+ int found = 0;
+ for (i = 0; ac->attrs[i]; i++) {
+ if (strcasecmp(cols[2], ac->attrs[i]) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) return SQLITE_OK;
+ }
+
+ if (ldb_msg_add_string(msg, cols[2], cols[3]) != 0) {
+ return SQLITE_ABORT;
+ }
+
+ return SQLITE_OK;
+}
+
+
+/*
+ * lsqlite3_get_eid()
+ * lsqlite3_get_eid_ndn()
+ *
+ * These functions are used for the very common case of retrieving an EID value
+ * given a (normalized) DN.
+ */
+
+static long long lsqlite3_get_eid_ndn(sqlite3 *sqlite, void *mem_ctx, const char *norm_dn)
+{
+ char *errmsg;
+ char *query;
+ long long eid = -1;
+ long long ret;
+
+ /* get object eid */
+ query = lsqlite3_tprintf(mem_ctx, "SELECT eid "
+ "FROM ldb_entry "
+ "WHERE norm_dn = '%q';", norm_dn);
+ if (query == NULL) return -1;
+
+ ret = sqlite3_exec(sqlite, query, lsqlite3_eid_callback, &eid, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3_get_eid: Fatal Error: %s\n", errmsg);
+ free(errmsg);
+ }
+ return -1;
+ }
+
+ return eid;
+}
+
+static long long lsqlite3_get_eid(struct ldb_module *module, const struct ldb_dn *dn)
+{
+ TALLOC_CTX *local_ctx;
+ struct lsqlite3_private *lsqlite3 = module->private_data;
+ long long eid = -1;
+ char *cdn;
+
+ /* ignore ltdb specials */
+ if (ldb_dn_is_special(dn)) {
+ return -1;
+ }
+
+ /* create a local ctx */
+ local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_get_eid local context");
+ if (local_ctx == NULL) {
+ return -1;
+ }
+
+ cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, local_ctx, dn));
+ if (!cdn) goto done;
+
+ eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, local_ctx, cdn);
+
+done:
+ talloc_free(local_ctx);
+ return eid;
+}
+
+/*
+ * Interface functions referenced by lsqlite3_ops
+ */
+
+/* search for matching records, by tree */
+int lsql_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private);
+ struct lsql_context *lsql_ac;
+ char *norm_basedn;
+ char *sqlfilter;
+ char *errmsg;
+ char *query = NULL;
+ int ret;
+
+ req->handle = init_handle(lsqlite3, module, req);
+ if (req->handle == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context);
+
+ if ((req->op.search.base == NULL || req->op.search.base->comp_num == 0) &&
+ (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL))
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ if (req->op.search.base) {
+ norm_basedn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, req->op.search.base));
+ if (norm_basedn == NULL) {
+ ret = LDB_ERR_INVALID_DN_SYNTAX;
+ goto failed;
+ }
+ } else norm_basedn = talloc_strdup(lsql_ac, "");
+
+ /* Convert filter into a series of SQL conditions (constraints) */
+ sqlfilter = parsetree_to_sql(module, lsql_ac, req->op.search.tree);
+
+ switch(req->op.search.scope) {
+ case LDB_SCOPE_DEFAULT:
+ case LDB_SCOPE_SUBTREE:
+ if (*norm_basedn != '\0') {
+ query = lsqlite3_tprintf(lsql_ac,
+ "SELECT entry.eid,\n"
+ " entry.dn,\n"
+ " av.attr_name,\n"
+ " av.attr_value\n"
+ " FROM ldb_entry AS entry\n"
+
+ " LEFT OUTER JOIN ldb_attribute_values AS av\n"
+ " ON av.eid = entry.eid\n"
+
+ " WHERE entry.eid IN\n"
+ " (SELECT DISTINCT ldb_entry.eid\n"
+ " FROM ldb_entry\n"
+ " WHERE (ldb_entry.norm_dn GLOB('*,%q')\n"
+ " OR ldb_entry.norm_dn = '%q')\n"
+ " AND ldb_entry.eid IN\n"
+ " (%s)\n"
+ " )\n"
+
+ " ORDER BY entry.eid ASC;",
+ norm_basedn,
+ norm_basedn,
+ sqlfilter);
+ } else {
+ query = lsqlite3_tprintf(lsql_ac,
+ "SELECT entry.eid,\n"
+ " entry.dn,\n"
+ " av.attr_name,\n"
+ " av.attr_value\n"
+ " FROM ldb_entry AS entry\n"
+
+ " LEFT OUTER JOIN ldb_attribute_values AS av\n"
+ " ON av.eid = entry.eid\n"
+
+ " WHERE entry.eid IN\n"
+ " (SELECT DISTINCT ldb_entry.eid\n"
+ " FROM ldb_entry\n"
+ " WHERE ldb_entry.eid IN\n"
+ " (%s)\n"
+ " )\n"
+
+ " ORDER BY entry.eid ASC;",
+ sqlfilter);
+ }
+
+ break;
+
+ case LDB_SCOPE_BASE:
+ query = lsqlite3_tprintf(lsql_ac,
+ "SELECT entry.eid,\n"
+ " entry.dn,\n"
+ " av.attr_name,\n"
+ " av.attr_value\n"
+ " FROM ldb_entry AS entry\n"
+
+ " LEFT OUTER JOIN ldb_attribute_values AS av\n"
+ " ON av.eid = entry.eid\n"
+
+ " WHERE entry.eid IN\n"
+ " (SELECT DISTINCT ldb_entry.eid\n"
+ " FROM ldb_entry\n"
+ " WHERE ldb_entry.norm_dn = '%q'\n"
+ " AND ldb_entry.eid IN\n"
+ " (%s)\n"
+ " )\n"
+
+ " ORDER BY entry.eid ASC;",
+ norm_basedn,
+ sqlfilter);
+ break;
+
+ case LDB_SCOPE_ONELEVEL:
+ query = lsqlite3_tprintf(lsql_ac,
+ "SELECT entry.eid,\n"
+ " entry.dn,\n"
+ " av.attr_name,\n"
+ " av.attr_value\n"
+ " FROM ldb_entry AS entry\n"
+
+ " LEFT OUTER JOIN ldb_attribute_values AS av\n"
+ " ON av.eid = entry.eid\n"
+
+ " WHERE entry.eid IN\n"
+ " (SELECT DISTINCT ldb_entry.eid\n"
+ " FROM ldb_entry\n"
+ " WHERE norm_dn GLOB('*,%q')\n"
+ " AND NOT norm_dn GLOB('*,*,%q')\n"
+ " AND ldb_entry.eid IN\n(%s)\n"
+ " )\n"
+
+ " ORDER BY entry.eid ASC;",
+ norm_basedn,
+ norm_basedn,
+ sqlfilter);
+ break;
+ }
+
+ if (query == NULL) {
+ goto failed;
+ }
+
+ /* * /
+ printf ("%s\n", query);
+ / * */
+
+ lsql_ac->current_eid = 0;
+ lsql_ac->attrs = req->op.search.attrs;
+ lsql_ac->ares = NULL;
+
+ req->handle->state = LDB_ASYNC_PENDING;
+
+ ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, req->handle, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(module->ldb, errmsg);
+ free(errmsg);
+ }
+ goto failed;
+ }
+
+ /* complete the last message if any */
+ if (lsql_ac->ares) {
+ lsql_ac->ares->message = ldb_msg_canonicalize(module->ldb, lsql_ac->ares->message);
+ if (lsql_ac->ares->message == NULL)
+ goto failed;
+
+ req->handle->status = lsql_ac->callback(module->ldb, lsql_ac->context, lsql_ac->ares);
+ if (req->handle->status != LDB_SUCCESS)
+ goto failed;
+ }
+
+ req->handle->state = LDB_ASYNC_DONE;
+
+ return LDB_SUCCESS;
+
+failed:
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+/* add a record */
+static int lsql_add(struct ldb_module *module, struct ldb_request *req)
+{
+ struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private);
+ struct lsql_context *lsql_ac;
+ struct ldb_message *msg = req->op.add.message;
+ long long eid;
+ char *dn, *ndn;
+ char *errmsg;
+ char *query;
+ int i;
+ int ret = LDB_SUCCESS;
+
+ req->handle = init_handle(lsqlite3, module, req);
+ if (req->handle == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context);
+ req->handle->state = LDB_ASYNC_DONE;
+ req->handle->status = LDB_SUCCESS;
+
+ /* See if this is an ltdb special */
+ if (ldb_dn_is_special(msg->dn)) {
+ struct ldb_dn *c;
+
+ c = ldb_dn_explode(lsql_ac, "@SUBCLASSES");
+ if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) {
+#warning "insert subclasses into object class tree"
+ ret = LDB_ERR_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+
+/*
+ c = ldb_dn_explode(local_ctx, "@INDEXLIST");
+ if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) {
+#warning "should we handle indexes somehow ?"
+ ret = LDB_ERR_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+*/
+ /* Others return an error */
+ ret = LDB_ERR_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+
+ /* create linearized and normalized dns */
+ dn = ldb_dn_linearize(lsql_ac, msg->dn);
+ ndn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, msg->dn));
+ if (dn == NULL || ndn == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ query = lsqlite3_tprintf(lsql_ac,
+ /* Add new entry */
+ "INSERT OR ABORT INTO ldb_entry "
+ "('dn', 'norm_dn') "
+ "VALUES ('%q', '%q');",
+ dn, ndn);
+ if (query == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(module->ldb, errmsg);
+ free(errmsg);
+ }
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, lsql_ac, ndn);
+ if (eid == -1) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ for (i = 0; i < msg->num_elements; i++) {
+ const struct ldb_message_element *el = &msg->elements[i];
+ const struct ldb_attrib_handler *h;
+ char *attr;
+ int j;
+
+ /* Get a case-folded copy of the attribute name */
+ attr = ldb_attr_casefold(lsql_ac, el->name);
+ if (attr == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ h = ldb_attrib_handler(module->ldb, el->name);
+
+ /* For each value of the specified attribute name... */
+ for (j = 0; j < el->num_values; j++) {
+ struct ldb_val value;
+ char *insert;
+
+ /* Get a canonicalised copy of the data */
+ h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value);
+ if (value.data == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ insert = lsqlite3_tprintf(lsql_ac,
+ "INSERT OR ROLLBACK INTO ldb_attribute_values "
+ "('eid', 'attr_name', 'norm_attr_name',"
+ " 'attr_value', 'norm_attr_value') "
+ "VALUES ('%lld', '%q', '%q', '%q', '%q');",
+ eid, el->name, attr,
+ el->values[j].data, value.data);
+ if (insert == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ ret = sqlite3_exec(lsqlite3->sqlite, insert, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(module->ldb, errmsg);
+ free(errmsg);
+ }
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+ }
+ }
+
+ if (lsql_ac->callback) {
+ req->handle->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL);
+ }
+
+done:
+ req->handle->state = LDB_ASYNC_DONE;
+ return ret;
+}
+
+/* modify a record */
+static int lsql_modify(struct ldb_module *module, struct ldb_request *req)
+{
+ struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private);
+ struct lsql_context *lsql_ac;
+ struct ldb_message *msg = req->op.mod.message;
+ long long eid;
+ char *errmsg;
+ int i;
+ int ret = LDB_SUCCESS;
+
+ req->handle = init_handle(lsqlite3, module, req);
+ if (req->handle == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context);
+ req->handle->state = LDB_ASYNC_DONE;
+ req->handle->status = LDB_SUCCESS;
+
+ /* See if this is an ltdb special */
+ if (ldb_dn_is_special(msg->dn)) {
+ struct ldb_dn *c;
+
+ c = ldb_dn_explode(lsql_ac, "@SUBCLASSES");
+ if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) {
+#warning "modify subclasses into object class tree"
+ ret = LDB_ERR_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+
+ /* Others return an error */
+ ret = LDB_ERR_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+
+ eid = lsqlite3_get_eid(module, msg->dn);
+ if (eid == -1) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ for (i = 0; i < msg->num_elements; i++) {
+ const struct ldb_message_element *el = &msg->elements[i];
+ const struct ldb_attrib_handler *h;
+ int flags = el->flags & LDB_FLAG_MOD_MASK;
+ char *attr;
+ char *mod;
+ int j;
+
+ /* Get a case-folded copy of the attribute name */
+ attr = ldb_attr_casefold(lsql_ac, el->name);
+ if (attr == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ h = ldb_attrib_handler(module->ldb, el->name);
+
+ switch (flags) {
+
+ case LDB_FLAG_MOD_REPLACE:
+
+ /* remove all attributes before adding the replacements */
+ mod = lsqlite3_tprintf(lsql_ac,
+ "DELETE FROM ldb_attribute_values "
+ "WHERE eid = '%lld' "
+ "AND norm_attr_name = '%q';",
+ eid, attr);
+ if (mod == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(module->ldb, errmsg);
+ free(errmsg);
+ }
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ /* MISSING break is INTENTIONAL */
+
+ case LDB_FLAG_MOD_ADD:
+#warning "We should throw an error if no value is provided!"
+ /* For each value of the specified attribute name... */
+ for (j = 0; j < el->num_values; j++) {
+ struct ldb_val value;
+
+ /* Get a canonicalised copy of the data */
+ h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value);
+ if (value.data == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ mod = lsqlite3_tprintf(lsql_ac,
+ "INSERT OR ROLLBACK INTO ldb_attribute_values "
+ "('eid', 'attr_name', 'norm_attr_name',"
+ " 'attr_value', 'norm_attr_value') "
+ "VALUES ('%lld', '%q', '%q', '%q', '%q');",
+ eid, el->name, attr,
+ el->values[j].data, value.data);
+
+ if (mod == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(module->ldb, errmsg);
+ free(errmsg);
+ }
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+ }
+
+ break;
+
+ case LDB_FLAG_MOD_DELETE:
+#warning "We should throw an error if the attribute we are trying to delete does not exist!"
+ if (el->num_values == 0) {
+ mod = lsqlite3_tprintf(lsql_ac,
+ "DELETE FROM ldb_attribute_values "
+ "WHERE eid = '%lld' "
+ "AND norm_attr_name = '%q';",
+ eid, attr);
+ if (mod == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(module->ldb, errmsg);
+ free(errmsg);
+ }
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+ }
+
+ /* For each value of the specified attribute name... */
+ for (j = 0; j < el->num_values; j++) {
+ struct ldb_val value;
+
+ /* Get a canonicalised copy of the data */
+ h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value);
+ if (value.data == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ mod = lsqlite3_tprintf(lsql_ac,
+ "DELETE FROM ldb_attribute_values "
+ "WHERE eid = '%lld' "
+ "AND norm_attr_name = '%q' "
+ "AND norm_attr_value = '%q';",
+ eid, attr, value.data);
+
+ if (mod == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(module->ldb, errmsg);
+ free(errmsg);
+ }
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+ }
+
+ break;
+ }
+ }
+
+ if (lsql_ac->callback) {
+ req->handle->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL);
+ }
+
+done:
+ req->handle->state = LDB_ASYNC_DONE;
+ return ret;
+}
+
+/* delete a record */
+static int lsql_delete(struct ldb_module *module, struct ldb_request *req)
+{
+ struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private);
+ struct lsql_context *lsql_ac;
+ long long eid;
+ char *errmsg;
+ char *query;
+ int ret = LDB_SUCCESS;
+
+
+ req->handle = init_handle(lsqlite3, module, req);
+ if (req->handle == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context);
+ req->handle->state = LDB_ASYNC_DONE;
+ req->handle->status = LDB_SUCCESS;
+
+ eid = lsqlite3_get_eid(module, req->op.del.dn);
+ if (eid == -1) {
+ goto done;
+ }
+
+ query = lsqlite3_tprintf(lsql_ac,
+ /* Delete entry */
+ "DELETE FROM ldb_entry WHERE eid = %lld; "
+ /* Delete attributes */
+ "DELETE FROM ldb_attribute_values WHERE eid = %lld; ",
+ eid, eid);
+ if (query == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(module->ldb, errmsg);
+ free(errmsg);
+ }
+ req->handle->status = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ if (lsql_ac->callback) {
+ ret = lsql_ac->callback(module->ldb, lsql_ac->context, NULL);
+ }
+
+done:
+ req->handle->state = LDB_ASYNC_DONE;
+ return ret;
+}
+
+/* rename a record */
+static int lsql_rename(struct ldb_module *module, struct ldb_request *req)
+{
+ struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private);
+ struct lsql_context *lsql_ac;
+ char *new_dn, *new_cdn, *old_cdn;
+ char *errmsg;
+ char *query;
+ int ret = LDB_SUCCESS;
+
+ req->handle = init_handle(lsqlite3, module, req);
+ if (req->handle == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context);
+ req->handle->state = LDB_ASYNC_DONE;
+ req->handle->status = LDB_SUCCESS;
+
+ /* create linearized and normalized dns */
+ old_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, req->op.rename.olddn));
+ new_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, req->op.rename.newdn));
+ new_dn = ldb_dn_linearize(lsql_ac, req->op.rename.newdn);
+ if (old_cdn == NULL || new_cdn == NULL || new_dn == NULL) {
+ goto done;
+ }
+
+ /* build the SQL query */
+ query = lsqlite3_tprintf(lsql_ac,
+ "UPDATE ldb_entry SET dn = '%q', norm_dn = '%q' "
+ "WHERE norm_dn = '%q';",
+ new_dn, new_cdn, old_cdn);
+ if (query == NULL) {
+ goto done;
+ }
+
+ /* execute */
+ ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(module->ldb, errmsg);
+ free(errmsg);
+ }
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ if (lsql_ac->callback) {
+ ret = lsql_ac->callback(module->ldb, lsql_ac->context, NULL);
+ }
+
+done:
+ req->handle->state = LDB_ASYNC_DONE;
+ return ret;
+}
+
+static int lsql_start_trans(struct ldb_module * module)
+{
+ int ret;
+ char *errmsg;
+ struct lsqlite3_private * lsqlite3 = module->private_data;
+
+ if (lsqlite3->trans_count == 0) {
+ ret = sqlite3_exec(lsqlite3->sqlite, "BEGIN IMMEDIATE;", NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3_start_trans: error: %s\n", errmsg);
+ free(errmsg);
+ }
+ return -1;
+ }
+ };
+
+ lsqlite3->trans_count++;
+
+ return 0;
+}
+
+static int lsql_end_trans(struct ldb_module *module)
+{
+ int ret;
+ char *errmsg;
+ struct lsqlite3_private *lsqlite3 = module->private_data;
+
+ if (lsqlite3->trans_count > 0) {
+ lsqlite3->trans_count--;
+ } else return -1;
+
+ if (lsqlite3->trans_count == 0) {
+ ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3_end_trans: error: %s\n", errmsg);
+ free(errmsg);
+ }
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int lsql_del_trans(struct ldb_module *module)
+{
+ struct lsqlite3_private *lsqlite3 = module->private_data;
+
+ if (lsqlite3->trans_count > 0) {
+ lsqlite3->trans_count--;
+ } else return -1;
+
+ if (lsqlite3->trans_count == 0) {
+ return lsqlite3_safe_rollback(lsqlite3->sqlite);
+ }
+
+ return -1;
+}
+
+static int destructor(struct lsqlite3_private *lsqlite3)
+{
+ if (lsqlite3->sqlite) {
+ sqlite3_close(lsqlite3->sqlite);
+ }
+ return 0;
+}
+
+static int lsql_request(struct ldb_module *module, struct ldb_request *req)
+{
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+static int lsql_wait(struct ldb_handle *handle, enum ldb_wait_type type)
+{
+ return handle->status;
+}
+
+/*
+ * Table of operations for the sqlite3 backend
+ */
+static const struct ldb_module_ops lsqlite3_ops = {
+ .name = "sqlite",
+ .search = lsql_search,
+ .add = lsql_add,
+ .modify = lsql_modify,
+ .del = lsql_delete,
+ .rename = lsql_rename,
+ .request = lsql_request,
+ .start_transaction = lsql_start_trans,
+ .end_transaction = lsql_end_trans,
+ .del_transaction = lsql_del_trans,
+ .wait = lsql_wait,
+};
+
+/*
+ * Static functions
+ */
+
+static int initialize(struct lsqlite3_private *lsqlite3,
+ struct ldb_context *ldb, const char *url, int flags)
+{
+ TALLOC_CTX *local_ctx;
+ long long queryInt;
+ int rollback = 0;
+ char *errmsg;
+ char *schema;
+ int ret;
+
+ /* create a local ctx */
+ local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_rename local context");
+ if (local_ctx == NULL) {
+ return -1;
+ }
+
+ schema = lsqlite3_tprintf(local_ctx,
+
+
+ "CREATE TABLE ldb_info AS "
+ " SELECT 'LDB' AS database_type,"
+ " '1.0' AS version;"
+
+ /*
+ * The entry table holds the information about an entry.
+ * This table is used to obtain the EID of the entry and to
+ * support scope=one and scope=base. The parent and child
+ * table is included in the entry table since all the other
+ * attributes are dependent on EID.
+ */
+ "CREATE TABLE ldb_entry "
+ "("
+ " eid INTEGER PRIMARY KEY AUTOINCREMENT,"
+ " dn TEXT UNIQUE NOT NULL,"
+ " norm_dn TEXT UNIQUE NOT NULL"
+ ");"
+
+
+ "CREATE TABLE ldb_object_classes"
+ "("
+ " class_name TEXT PRIMARY KEY,"
+ " parent_class_name TEXT,"
+ " tree_key TEXT UNIQUE,"
+ " max_child_num INTEGER DEFAULT 0"
+ ");"
+
+ /*
+ * We keep a full listing of attribute/value pairs here
+ */
+ "CREATE TABLE ldb_attribute_values"
+ "("
+ " eid INTEGER REFERENCES ldb_entry,"
+ " attr_name TEXT,"
+ " norm_attr_name TEXT,"
+ " attr_value TEXT,"
+ " norm_attr_value TEXT "
+ ");"
+
+
+ /*
+ * Indexes
+ */
+ "CREATE INDEX ldb_attribute_values_eid_idx "
+ " ON ldb_attribute_values (eid);"
+
+ "CREATE INDEX ldb_attribute_values_name_value_idx "
+ " ON ldb_attribute_values (attr_name, norm_attr_value);"
+
+
+
+ /*
+ * Triggers
+ */
+
+ "CREATE TRIGGER ldb_object_classes_insert_tr"
+ " AFTER INSERT"
+ " ON ldb_object_classes"
+ " FOR EACH ROW"
+ " BEGIN"
+ " UPDATE ldb_object_classes"
+ " SET tree_key = COALESCE(tree_key, "
+ " ("
+ " SELECT tree_key || "
+ " (SELECT base160(max_child_num + 1)"
+ " FROM ldb_object_classes"
+ " WHERE class_name = "
+ " new.parent_class_name)"
+ " FROM ldb_object_classes "
+ " WHERE class_name = new.parent_class_name "
+ " ));"
+ " UPDATE ldb_object_classes "
+ " SET max_child_num = max_child_num + 1"
+ " WHERE class_name = new.parent_class_name;"
+ " END;"
+
+ /*
+ * Table initialization
+ */
+
+ "INSERT INTO ldb_object_classes "
+ " (class_name, tree_key) "
+ " VALUES "
+ " ('TOP', '0001');");
+
+ /* Skip protocol indicator of url */
+ if (strncmp(url, "sqlite3://", 10) != 0) {
+ return SQLITE_MISUSE;
+ }
+
+ /* Update pointer to just after the protocol indicator */
+ url += 10;
+
+ /* Try to open the (possibly empty/non-existent) database */
+ if ((ret = sqlite3_open(url, &lsqlite3->sqlite)) != SQLITE_OK) {
+ return ret;
+ }
+
+ /* In case this is a new database, enable auto_vacuum */
+ ret = sqlite3_exec(lsqlite3->sqlite, "PRAGMA auto_vacuum = 1;", NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3 initializaion error: %s\n", errmsg);
+ free(errmsg);
+ }
+ goto failed;
+ }
+
+ if (flags & LDB_FLG_NOSYNC) {
+ /* DANGEROUS */
+ ret = sqlite3_exec(lsqlite3->sqlite, "PRAGMA synchronous = OFF;", NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3 initializaion error: %s\n", errmsg);
+ free(errmsg);
+ }
+ goto failed;
+ }
+ }
+
+ /* */
+
+ /* Establish a busy timeout of 30 seconds */
+ if ((ret = sqlite3_busy_timeout(lsqlite3->sqlite,
+ 30000)) != SQLITE_OK) {
+ return ret;
+ }
+
+ /* Create a function, callable from sql, to increment a tree_key */
+ if ((ret =
+ sqlite3_create_function(lsqlite3->sqlite,/* handle */
+ "base160_next", /* function name */
+ 1, /* number of args */
+ SQLITE_ANY, /* preferred text type */
+ NULL, /* user data */
+ base160next_sql, /* called func */
+ NULL, /* step func */
+ NULL /* final func */
+ )) != SQLITE_OK) {
+ return ret;
+ }
+
+ /* Create a function, callable from sql, to convert int to base160 */
+ if ((ret =
+ sqlite3_create_function(lsqlite3->sqlite,/* handle */
+ "base160", /* function name */
+ 1, /* number of args */
+ SQLITE_ANY, /* preferred text type */
+ NULL, /* user data */
+ base160_sql, /* called func */
+ NULL, /* step func */
+ NULL /* final func */
+ )) != SQLITE_OK) {
+ return ret;
+ }
+
+ /* Create a function, callable from sql, to perform various comparisons */
+ if ((ret =
+ sqlite3_create_function(lsqlite3->sqlite, /* handle */
+ "ldap_compare", /* function name */
+ 4, /* number of args */
+ SQLITE_ANY, /* preferred text type */
+ ldb , /* user data */
+ lsqlite3_compare, /* called func */
+ NULL, /* step func */
+ NULL /* final func */
+ )) != SQLITE_OK) {
+ return ret;
+ }
+
+ /* Begin a transaction */
+ ret = sqlite3_exec(lsqlite3->sqlite, "BEGIN EXCLUSIVE;", NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3: initialization error: %s\n", errmsg);
+ free(errmsg);
+ }
+ goto failed;
+ }
+ rollback = 1;
+
+ /* Determine if this is a new database. No tables means it is. */
+ if (query_int(lsqlite3,
+ &queryInt,
+ "SELECT COUNT(*)\n"
+ " FROM sqlite_master\n"
+ " WHERE type = 'table';") != 0) {
+ goto failed;
+ }
+
+ if (queryInt == 0) {
+ /*
+ * Create the database schema
+ */
+ ret = sqlite3_exec(lsqlite3->sqlite, schema, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3 initializaion error: %s\n", errmsg);
+ free(errmsg);
+ }
+ goto failed;
+ }
+ } else {
+ /*
+ * Ensure that the database we opened is one of ours
+ */
+ if (query_int(lsqlite3,
+ &queryInt,
+ "SELECT "
+ " (SELECT COUNT(*) = 2"
+ " FROM sqlite_master "
+ " WHERE type = 'table' "
+ " AND name IN "
+ " ("
+ " 'ldb_entry', "
+ " 'ldb_object_classes' "
+ " ) "
+ " ) "
+ " AND "
+ " (SELECT 1 "
+ " FROM ldb_info "
+ " WHERE database_type = 'LDB' "
+ " AND version = '1.0'"
+ " );") != 0 ||
+ queryInt != 1) {
+
+ /* It's not one that we created. See ya! */
+ goto failed;
+ }
+ }
+
+ /* Commit the transaction */
+ ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3: iniialization error: %s\n", errmsg);
+ free(errmsg);
+ }
+ goto failed;
+ }
+
+ return SQLITE_OK;
+
+failed:
+ if (rollback) lsqlite3_safe_rollback(lsqlite3->sqlite);
+ sqlite3_close(lsqlite3->sqlite);
+ return -1;
+}
+
+/*
+ * connect to the database
+ */
+static int lsqlite3_connect(struct ldb_context *ldb,
+ const char *url,
+ unsigned int flags,
+ const char *options[],
+ struct ldb_module **module)
+{
+ int i;
+ int ret;
+ struct lsqlite3_private * lsqlite3 = NULL;
+
+ lsqlite3 = talloc(ldb, struct lsqlite3_private);
+ if (!lsqlite3) {
+ goto failed;
+ }
+
+ lsqlite3->sqlite = NULL;
+ lsqlite3->options = NULL;
+ lsqlite3->trans_count = 0;
+
+ ret = initialize(lsqlite3, ldb, url, flags);
+ if (ret != SQLITE_OK) {
+ goto failed;
+ }
+
+ talloc_set_destructor(lsqlite3, destructor);
+
+
+
+ *module = talloc(ldb, struct ldb_module);
+ if (!module) {
+ ldb_oom(ldb);
+ goto failed;
+ }
+ talloc_set_name_const(*module, "ldb_sqlite3 backend");
+ (*module)->ldb = ldb;
+ (*module)->prev = (*module)->next = NULL;
+ (*module)->private_data = lsqlite3;
+ (*module)->ops = &lsqlite3_ops;
+
+ if (options) {
+ /*
+ * take a copy of the options array, so we don't have to rely
+ * on the caller keeping it around (it might be dynamic)
+ */
+ for (i=0;options[i];i++) ;
+
+ lsqlite3->options = talloc_array(lsqlite3, char *, i+1);
+ if (!lsqlite3->options) {
+ goto failed;
+ }
+
+ for (i=0;options[i];i++) {
+
+ lsqlite3->options[i+1] = NULL;
+ lsqlite3->options[i] =
+ talloc_strdup(lsqlite3->options, options[i]);
+ if (!lsqlite3->options[i]) {
+ goto failed;
+ }
+ }
+ }
+
+ return 0;
+
+failed:
+ if (lsqlite3->sqlite != NULL) {
+ (void) sqlite3_close(lsqlite3->sqlite);
+ }
+ talloc_free(lsqlite3);
+ return -1;
+}
+
+int ldb_sqlite3_init(void)
+{
+ return ldb_register_backend("sqlite3", lsqlite3_connect);
+}
diff --git a/source3/lib/ldb/ldb_sqlite3/schema b/source3/lib/ldb/ldb_sqlite3/schema
new file mode 100644
index 0000000000..08dc50de08
--- /dev/null
+++ b/source3/lib/ldb/ldb_sqlite3/schema
@@ -0,0 +1,363 @@
+ -- ------------------------------------------------------
+
+ PRAGMA auto_vacuum=1;
+
+ -- ------------------------------------------------------
+
+ BEGIN EXCLUSIVE;
+
+ -- ------------------------------------------------------
+
+ CREATE TABLE ldb_info AS
+ SELECT 'LDB' AS database_type,
+ '1.0' AS version;
+
+ /*
+ * Get the next USN value with:
+ * BEGIN EXCLUSIVE;
+ * UPDATE usn SET value = value + 1;
+ * SELECT value FROM usn;
+ * COMMIT;
+ */
+ CREATE TABLE usn
+ (
+ value INTEGER
+ );
+
+ CREATE TABLE ldb_object
+ (
+ /* tree_key is auto-generated by the insert trigger */
+ tree_key TEXT PRIMARY KEY,
+
+ parent_tree_key TEXT,
+ dn TEXT,
+
+ attr_name TEXT REFERENCES ldb_attributes,
+ attr_value TEXT,
+
+ /*
+ * object_type can take on these values (to date):
+ * 1: object is a node of a DN
+ * 2: object is an attribute/value pair of its parent DN
+ */
+ object_type INTEGER,
+
+ /*
+ * if object_type is 1, the node can have children.
+ * this tracks the maximum previously assigned child
+ * number so we can generate a new unique tree key for
+ * a new child object. note that this is always incremented,
+ * so if children are deleted, this will not represent
+ * the _number_ of children.
+ */
+ max_child_num INTEGER,
+
+ /*
+ * Automatically maintained meta-data (a gift for metze)
+ */
+ object_guid TEXT UNIQUE,
+ timestamp INTEGER, -- originating_time
+ invoke_id TEXT, -- GUID: originating_invocation_id
+ usn INTEGER, -- hyper: originating_usn
+
+ /* do not allow duplicate name/value pairs */
+ UNIQUE (parent_tree_key, attr_name, attr_value, object_type)
+ );
+
+ CREATE TABLE ldb_attributes
+ (
+ attr_name TEXT PRIMARY KEY,
+ parent_tree_key TEXT,
+
+ objectclass_p BOOLEAN DEFAULT 0,
+
+ case_insensitive_p BOOLEAN DEFAULT 0,
+ wildcard_p BOOLEAN DEFAULT 0,
+ hidden_p BOOLEAN DEFAULT 0,
+ integer_p BOOLEAN DEFAULT 0,
+
+ /* tree_key is auto-generated by the insert trigger */
+ tree_key TEXT, -- null if not a object/sub class
+ -- level 1 if an objectclass
+ -- level 1-n if a subclass
+ max_child_num INTEGER
+ );
+
+ -- ------------------------------------------------------
+
+ CREATE INDEX ldb_object_dn_idx
+ ON ldb_object (dn);
+
+ CREATE INDEX ldb_attributes_tree_key_ids
+ ON ldb_attributes (tree_key);
+
+ -- ------------------------------------------------------
+
+ /* Gifts for metze. Automatically updated meta-data */
+ CREATE TRIGGER ldb_object_insert_tr
+ AFTER INSERT
+ ON ldb_object
+ FOR EACH ROW
+ BEGIN
+ UPDATE ldb_object
+ SET max_child_num = max_child_num + 1
+ WHERE tree_key = new.parent_tree_key;
+ UPDATE usn SET value = value + 1;
+ UPDATE ldb_object
+ SET tree_key =
+ (SELECT
+ new.tree_key ||
+ base160(SELECT max_child_num
+ FROM ldb_object
+ WHERE tree_key =
+ new.parent_tree_key));
+ max_child_num = 0,
+ object_guid = random_guid(),
+ timestamp = strftime('%s', 'now'),
+ usn = (SELECT value FROM usn);
+ WHERE tree_key = new.tree_key;
+ END;
+
+ CREATE TRIGGER ldb_object_update_tr
+ AFTER UPDATE
+ ON ldb_object
+ FOR EACH ROW
+ BEGIN
+ UPDATE usn SET value = value + 1;
+ UPDATE ldb_object
+ SET timestamp = strftime('%s', 'now'),
+ usn = (SELECT value FROM usn);
+ WHERE tree_key = new.tree_key;
+ END;
+
+ CREATE TRIGGER ldb_attributes_insert_tr
+ AFTER INSERT
+ ON ldb_attributes
+ FOR EACH ROW
+ BEGIN
+ UPDATE ldb_attributes
+ SET max_child_num = max_child_num + 1
+ WHERE tree_key = new.parent_tree_key;
+ UPDATE ldb_attributes
+ SET tree_key =
+ (SELECT
+ new.tree_key ||
+ base160(SELECT max_child_num
+ FROM ldb_attributes
+ WHERE tree_key =
+ new.parent_tree_key));
+ max_child_num = 0
+ WHERE tree_key = new.tree_key;
+ END;
+
+
+ -- ------------------------------------------------------
+
+ /* Initialize usn */
+ INSERT INTO usn (value) VALUES (0);
+
+ /* Create root object */
+ INSERT INTO ldb_object
+ (tree_key, parent_tree_key,
+ dn,
+ object_type, max_child_num)
+ VALUES ('', NULL,
+ '',
+ 1, 0);
+
+ /* We need an implicit "top" level object class */
+ INSERT INTO ldb_attributes (attr_name,
+ parent_tree_key)
+ SELECT 'top', '';
+
+ -- ------------------------------------------------------
+
+ COMMIT;
+
+ -- ------------------------------------------------------
+
+/*
+ * dn: o=University of Michigan,c=US
+ * objectclass: organization
+ * objectclass: domainRelatedObject
+ */
+-- newDN
+BEGIN;
+
+INSERT OR IGNORE INTO ldb_object
+ (parent_tree_key
+ dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('',
+ 'c=US',
+ 'c', 'US', 1, 0);
+
+INSERT INTO ldb_object
+ (parent_tree_key,
+ dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('0001',
+ 'o=University of Michigan,c=US',
+ 'o', 'University of Michigan', 1, 0);
+
+-- newObjectClass
+INSERT OR IGNORE INTO ldb_attributes
+ (attr_name, parent_tree_key, objectclass_p)
+ VALUES
+ ('objectclass', '', 1);
+
+INSERT INTO ldb_object
+ (parent_tree_key,
+ dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('00010001',
+ NULL,
+ 'objectclass', 'organization', 2, 0);
+
+INSERT OR IGNORE INTO ldb_attributes
+ (attr_name, parent_tree_key, objectclass_p)
+ VALUES
+ ('objectclass', '', 1);
+
+INSERT INTO ldb_object
+ (parent_tree_key,
+ dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('00010001',
+ NULL,
+ 'objectclass', 'domainRelatedObject', 2, 0);
+
+COMMIT;
+
+
+/*
+ * dn: o=University of Michigan,c=US
+ * l: Ann Arbor, Michigan
+ * st: Michigan
+ * o: University of Michigan
+ * o: UMICH
+ * seeAlso:
+ * telephonenumber: +1 313 764-1817
+ */
+-- addAttrValuePair
+BEGIN;
+
+INSERT INTO ldb_object
+ (parent_tree_key, dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('00010001', NULL,
+ 'l', 'Ann Arbor, Michigan', 2, 0);
+
+INSERT INTO ldb_object
+ (parent_tree_key, dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('00010001', NULL,
+ 'st', 'Michigan', 2, 0);
+
+INSERT INTO ldb_object
+ (parent_tree_key, dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('00010001', NULL,
+ 'o', 'University of Michigan', 2, 0);
+
+INSERT INTO ldb_object
+ (parent_tree_key, dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('00010001', NULL,
+ 'o', 'UMICH', 2, 0);
+
+INSERT INTO ldb_object
+ (parent_tree_key, dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('00010001', NULL,
+ 'seeAlso', '', 2, 0);
+
+INSERT INTO ldb_object
+ (parent_tree_key, dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('00010001', NULL,
+ 'telephonenumber', '+1 313 764-1817', 2, 0);
+
+COMMIT;
+
+-- ----------------------------------------------------------------------
+
+/*
+ * dn: @ATTRIBUTES
+ * uid: CASE_INSENSITIVE WILDCARD
+ * cn: CASE_INSENSITIVE
+ * ou: CASE_INSENSITIVE
+ * dn: CASE_INSENSITIVE
+ */
+-- newAttribute
+
+BEGIN;
+
+INSERT OR IGNORE INTO ldb_attributes
+ (attr_name, parent_tree_key, objectclass_p)
+ VALUES
+ ('uid', '', 0);
+
+UPDATE ldb_attributes
+ SET case_insensitive_p = 1,
+ wildcard_p = 1,
+ hidden_p = 0,
+ integer_p = 0
+ WHERE attr_name = 'uid'
+
+UPDATE ldb_attributes
+ SET case_insensitive_p = 1,
+ wildcard_p = 0,
+ hidden_p = 0,
+ integer_p = 0
+ WHERE attr_name = 'cn'
+
+UPDATE ldb_attributes
+ SET case_insensitive_p = 1,
+ wildcard_p = 0,
+ hidden_p = 0,
+ integer_p = 0
+ WHERE attr_name = 'ou'
+
+UPDATE ldb_attributes
+ SET case_insensitive_p = 1,
+ wildcard_p = 0,
+ hidden_p = 0,
+ integer_p = 0
+ WHERE attr_name = 'dn'
+
+-- ----------------------------------------------------------------------
+
+/*
+ * dn: @SUBCLASSES
+ * top: domain
+ * top: person
+ * domain: domainDNS
+ * person: organizationalPerson
+ * person: fooPerson
+ * organizationalPerson: user
+ * organizationalPerson: OpenLDAPperson
+ * user: computer
+ */
+-- insertSubclass
+
+/* NOT YET UPDATED!!! *
+
+
+INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key)
+ SELECT 'domain', /* next_tree_key('top') */ '00010001';
+INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key)
+ SELECT 'person', /* next_tree_key('top') */ '00010002';
+INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key)
+ SELECT 'domainDNS', /* next_tree_key('domain') */ '000100010001';
+INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key)
+ SELECT 'organizationalPerson', /* next_tree_key('person') */ '000100020001';
+INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key)
+ SELECT 'fooPerson', /* next_tree_key('person') */ '000100020002';
+INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key)
+ SELECT 'user', /* next_tree_key('organizationalPerson') */ '0001000200010001';
+INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key)
+ SELECT 'OpenLDAPperson', /* next_tree_key('organizationPerson') */ '0001000200010002';
+INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key)
+ SELECT 'computer', /* next_tree_key('user') */ '0001000200010001';
+
diff --git a/source3/lib/ldb/ldb_sqlite3/trees.ps b/source3/lib/ldb/ldb_sqlite3/trees.ps
new file mode 100644
index 0000000000..433a064816
--- /dev/null
+++ b/source3/lib/ldb/ldb_sqlite3/trees.ps
@@ -0,0 +1,1760 @@
+%!PS-Adobe-2.0
+%%Creator: dvips(k) 5.86 Copyright 1999 Radical Eye Software
+%%Title: trees.dvi
+%%Pages: 7
+%%PageOrder: Ascend
+%%BoundingBox: 0 0 596 842
+%%EndComments
+%DVIPSWebPage: (www.radicaleye.com)
+%DVIPSCommandLine: dvips -f trees.dvi
+%DVIPSParameters: dpi=600, compressed
+%DVIPSSource: TeX output 2000.05.06:2055
+%%BeginProcSet: texc.pro
+%!
+/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S
+N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72
+mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0
+0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{
+landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize
+mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[
+matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round
+exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{
+statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0]
+N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin
+/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array
+/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2
+array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N
+df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A
+definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get
+}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub}
+B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr
+1 add N}if}B/id 0 N/rw 0 N/rc 0 N/gp 0 N/cp 0 N/G 0 N/CharBuilder{save 3
+1 roll S A/base get 2 index get S/BitMaps get S get/Cd X pop/ctr 0 N Cdx
+0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx
+sub Cy .1 sub]/id Ci N/rw Cw 7 add 8 idiv string N/rc 0 N/gp 0 N/cp 0 N{
+rc 0 ne{rc 1 sub/rc X rw}{G}ifelse}imagemask restore}B/G{{id gp get/gp
+gp 1 add N A 18 mod S 18 idiv pl S get exec}loop}B/adv{cp add/cp X}B
+/chg{rw cp id gp 4 index getinterval putinterval A gp add/gp X adv}B/nd{
+/cp 0 N rw exit}B/lsh{rw cp 2 copy get A 0 eq{pop 1}{A 255 eq{pop 254}{
+A A add 255 and S 1 and or}ifelse}ifelse put 1 adv}B/rsh{rw cp 2 copy
+get A 0 eq{pop 128}{A 255 eq{pop 127}{A 2 idiv S 128 and or}ifelse}
+ifelse put 1 adv}B/clr{rw cp 2 index string putinterval adv}B/set{rw cp
+fillstr 0 4 index getinterval putinterval adv}B/fillstr 18 string 0 1 17
+{2 copy 255 put pop}for N/pl[{adv 1 chg}{adv 1 chg nd}{1 add chg}{1 add
+chg nd}{adv lsh}{adv lsh nd}{adv rsh}{adv rsh nd}{1 add adv}{/rc X nd}{
+1 add set}{1 add clr}{adv 2 chg}{adv 2 chg nd}{pop nd}]A{bind pop}
+forall N/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn
+/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put
+}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{
+bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A
+mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{
+SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{
+userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X
+1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4
+index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N
+/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{
+/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT)
+(LaserWriter 16/600)]{A length product length le{A length product exch 0
+exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse
+end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask
+grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot}
+imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round
+exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto
+fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p
+delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M}
+B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{
+p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S
+rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end
+
+%%EndProcSet
+TeXDict begin 39158280 55380996 1000 600 600 (trees.dvi)
+@start
+%DVIPSBitmapFont: Fa cmr10 10 6
+/Fa 6 55 df<146014E0EB01C0EB0380EB0700130E131E5B5BA25B485AA2485AA212075B
+120F90C7FCA25A121EA2123EA35AA65AB2127CA67EA3121EA2121F7EA27F12077F1203A2
+6C7EA26C7E1378A27F7F130E7FEB0380EB01C0EB00E01460135278BD20>40
+D<12C07E12707E7E7E120F6C7E6C7EA26C7E6C7EA21378A2137C133C133E131EA2131F7F
+A21480A3EB07C0A6EB03E0B2EB07C0A6EB0F80A31400A25B131EA2133E133C137C1378A2
+5BA2485A485AA2485A48C7FC120E5A5A5A5A5A13527CBD20>I<15301578B3A6007FB812
+F8B912FCA26C17F8C80078C8FCB3A6153036367BAF41>43 D<EB03F8EB1FFF90387E0FC0
+9038F803E03901E000F0484813780007147C48487FA248C77EA2481580A3007EEC0FC0A6
+00FE15E0B3007E15C0A4007F141F6C1580A36C15006D5B000F143EA26C6C5B6C6C5B6C6C
+485A6C6C485A90387E0FC0D91FFFC7FCEB03F8233A7DB72A>48 D<EB01C013031307131F
+13FFB5FCA2131F1200B3B3A8497E007FB512F0A31C3879B72A>I<EC3FC0903801FFF001
+0713FC90380FE03E90383F800790387E001F49EB3F804848137F485AA2485A000FEC3F00
+49131E001F91C7FCA2485AA3127F90C9FCEB01FC903807FF8039FF1E07E090383801F049
+6C7E01607F01E0137E497FA249148016C0151FA290C713E0A57EA56C7E16C0A2121FED3F
+807F000F15006C6C5B15FE6C6C5B6C6C485A3900FE07F090383FFFC06D90C7FCEB03FC23
+3A7DB72A>54 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fb cmr7 7 3
+/Fb 3 55 df<EB3F803801FFF03803E0F83807803C48487E001E7F003E1480A2003C1307
+007C14C0A400FC14E0AE007C14C0A36CEB0F80A36CEB1F006C131E6C6C5A3803E0F86CB4
+5A38003F801B277EA521>48 D<13381378EA01F8121F12FE12E01200B3AB487EB512F8A2
+15267BA521>I<EB0FE0EB3FF8EBF81C3801E0063803C01F48485AEA0F005A121E003E13
+1E91C7FC5AA21304EB3FC038FCFFF038FDC078EB003CB4133E48131E141FA2481480A412
+7CA4003C1400123E001E131E143E6C133C6C6C5A3803C1F03801FFC06C6CC7FC19277DA5
+21>54 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fc cmmi10 10 1
+/Fc 1 69 df<0103B7FC4916E018F8903B0007F80007FE4BEB00FFF03F80020FED1FC018
+0F4B15E0F007F0021F1503A24B15F81801143F19FC5DA2147FA292C8FCA25C18035CA213
+0119F84A1507A2130319F04A150FA2010717E0181F4A16C0A2010FEE3F80A24AED7F0018
+7E011F16FE4D5A4A5D4D5A013F4B5A4D5A4A4A5A057FC7FC017F15FEEE03FC91C7EA0FF0
+49EC7FC0B8C8FC16FC16C03E397DB845>68 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fd ectt1000 10 73
+/Fd 73 126 df<D807801307D81FE0EB0F80151F487E486C133F1600007C5CD8FCFC137E
+EAF87C15FE5D14015DA21403D8FCFC5BEA7CF8007F13075D383FF00FD81FE05BA2380780
+1FC75B143F92C7FCA25C147E14FE5CA213015CA213035C13075CA2130F5C131FEC800FED
+3FC0013FEB7FE0140049EBFFF0017E13F9A2D9FE0113F801FC13F0A2120113F8120313F0
+15F90007010013F05B000F14FF49EB7FE0A20007EC3FC06C48EB0F0025417DB92C>37
+D<EA0F80EA1FE0EA3FF0127F13F8A213FCA2123F121F120FEA007CA313FC13F8A2120113
+F01203EA07E0A2EA0FC0EA3F80127FEAFF005A12F812700E1D71B22C>39
+D<143814FC13011303EB07F8EB0FF0EB1FC0EB3F80EB7F0013FE485A485A5B12075B120F
+5B485AA2123F90C7FCA25A127EA312FE5AAC7E127EA3127F7EA27F121FA26C7E7F12077F
+12037F6C7E6C7E137FEB3F80EB1FC0EB0FF0EB07F8EB03FC130113001438164272B92C>
+I<127012FC7E7E6C7E6C7EEA0FE06C7E6C7E6C7E6C7E137F7F1480131F14C0130FEB07E0
+A214F01303A214F81301A314FC1300AC130114F8A3130314F0A2130714E0A2EB0FC0131F
+1480133F14005B13FE485A485A485A485AEA3FC0485A48C7FC5A5A1270164279B92C>I<
+EB0380497EA60020140800F8143E00FE14FE00FF13C1EBC7C7EBE7CF003FB512F8000F14
+E0000314806C140038007FFCA248B5FC481480000F14E0003F14F839FFE7CFFEEBC7C7EB
+07C100FE13C000F8143E0020140800001400A66D5A1F247AAA2C>I<147014F8AF003FB6
+12E0B712F8A4C700F8C7FCB0147025267DAB2C>I<EA0F80EA1FE0EA3FF0EA7FF8A213FC
+A3123F121F120F120013F8A21201EA03F01207EA1FE0EA7FC0EAFF80130012FC12700E17
+718A2C>I<121FEA3F80EA7FC0EAFFE0A5EA7FC0EA3F80EA1F000B0B708A2C>46
+D<1507ED0F80A2151F16005D153E157E157CA215FC5D14015D14035D14075D140F5D141F
+92C7FC5C143EA2147E147C14FC5C13015C13035C13075C130F5C131F91C8FC5B133EA213
+7E137C13FC5B12015B12035B12075B120F5B121F90C9FCA25A123E127E127C12FC5AA212
+7021417BB92C>I<EB03F8EB0FFE90383FFF80497F90B57E3901FE0FF03903F803F84848
+6C7EEBE0004848137EA248487FA248C7EA1F80A2003E140F007E15C0A3007C140700FC15
+E0AC6C140F007E15C0A46CEC1F80A36C6CEB3F00A26C6C137E6D13FE00075CEBF0016C6C
+485A3901FE0FF06CB55A6D5B6D5BD90FFEC7FCEB03F823357CB32C>I<1307497EA2131F
+A2133F137F13FF5A1207127FB5FC13DF139FEA7C1F1200B3AE007FB512E0B612F0A36C14
+E01C3477B32C>I<EB0FF890387FFF8048B512E00007804814FC391FF80FFE393FE001FF
+903880007F48C7EA3F80007E141F00FE15C0150F6C15E01507A3127E123CC8FCA2150F16
+C0151F1680153F16005D15FE4A5A14034A5A4A5A4A5A4A5AECFF804948C7FC495A495A49
+5AEB3FE0EB7F8049C8FC485A4848EB03C04848EB07E0EA1FE0485A48B6FCB7FCA36C15C0
+23347CB32C>I<000FB512FE4880A35D0180C8FCADEB83FE90389FFF8090B512E015F881
+9038FE03FE9038F000FF01C07F49EB3F8090C7121F6C15C0C8120FA2ED07E0A4123C127E
+B4FC150F16C0A248141F007EEC3F80007FEC7F006C6C5B6D485A391FF80FFC6CB55A6C5C
+000114C06C6C90C7FCEB0FF823347CB22C>53 D<EC3FC0903801FFF801077F011F7F497F
+90387FE07F9039FF003F804848137FEA03F8485A5B000FEC3F004848131E4990C7FC123F
+90C9FCA25A127EEB03FE90381FFF80D8FC7F13E000FDB57EB67E9038FE07FC9038F001FE
+9038C0007F49EB3F8090C7121F16C048140F16E01507A3127EA47E150F6D14C0001F141F
+6D1480000F143F6DEB7F003907F801FE3903FE07FC6CB55A6C5C6D5B011F1380D907FCC7
+FC23357CB32C>I<1278B712C016E0A316C000FCC7EA3F80ED7F0015FE00785CC712014A
+5A4A5A5D140F5D4A5A143F92C7FC5C147E14FE5C13015CA2495AA213075CA3495AA4495A
+A5133F91C8FCAA131E23357CB32C>I<EA0F80EA1FC0EA3FE0EA7FF0A5EA3FE0EA1FC0EA
+0F80C7FCAEEA0F80EA1FE0EA3FF0EA7FF8A213FCA3123F121F120F120013F8A21201EA03
+F01207EA1FE0EA7FC0EAFF80130012FC12700E3071A32C>59 D<1502ED0F80151F157F15
+FF913803FE00EC0FFCEC1FF0EC7FE0ECFF80D903FEC7FC495AEB1FF0495AEBFF80000390
+C8FCEA07FCEA1FF8EA3FE0EAFF8090C9FCA27FEA3FE0EA1FF8EA07FC6CB4FCC67FEB3FE0
+6D7EEB07FC6D7E903800FF80EC7FE0EC1FF0EC0FFCEC03FE913800FF80157F151F150FED
+0200212A7BAD2C>I<007FB612F0B712F8A36C15F0CAFCA8007FB612F0B712F8A36C15F0
+25127DA12C>I<122012F87EB4FC7FEA3FE0EA1FF8EA07FC6CB4FCC67FEB3FE06D7EEB07
+FC6D7E903800FF80EC7FE0EC1FF0EC0FFCEC03FE913800FF80157FA215FF913803FE00EC
+0FFCEC1FF0EC7FE0ECFF80D903FEC7FC495AEB1FF0495AEBFF80000390C8FCEA07FCEA1F
+F8EA3FE0EAFF8090C9FC12FC5A1220212A7BAD2C>I<14FE497EA4497FA214EFA2130781
+A214C7A2010F7FA314C390381F83F0A590383F01F8A490387E00FCA549137E90B512FEA3
+4880A29038F8003FA34848EB1F80A4000715C049130FD87FFEEBFFFC6D5AB514FE6C15FC
+497E27347EB32C>65 D<007FB512E015F8B612FE6C8016C03903F0003FED0FE0ED07F015
+03A2ED01F8A6ED03F0A21507ED0FE0ED1FC0EDFF8090B612005D5D15FF16C09039F0001F
+E0ED07F0ED03F81501ED00FCA216FE167EA616FE16FC1501ED03F8150FED3FF0007FB612
+E016C0B712806CECFE0015F027337FB22C>I<02FF13700107EBE0F84913F9013F13FD49
+13FFEBFF813901FE007F4848131FD807F0130F1507485A491303485A150148C7FCA25A00
+7EEC00F01600A212FE5AAB7E127EA3007F15F06CEC01F8A26C7EA26C6C13036D14F06C6C
+130716E0D803FC131F6C6CEB3FC03A00FF81FF806DB512006D5B010F5B6D13F001001380
+25357DB32C>I<007FB5FCB612C015F0816C803907E003FEEC00FFED7F80153FED1FC0ED
+0FE0A2150716F0150316F81501A4ED00FCACED01F8A3150316F0A2150716E0150FED1FC0
+153FED7F80EDFF00EC03FE007FB55AB65A5D15C06C91C7FC26337EB22C>I<007FB612F0
+B712F8A37E3903F00001A7ED00F01600A4EC01E04A7EA490B5FCA5EBF003A46E5A91C8FC
+A5163C167EA8007FB612FEB7FCA36C15FC27337EB22C>I<007FB612F8B712FCA37ED803
+F0C7FCA716781600A515F04A7EA490B5FCA5EBF001A46E5A92C7FCAD387FFFE0B5FC805C
+7E26337EB22C>I<903901FC038090390FFF87C04913EF017F13FF90B6FC4813073803FC
+01497E4848137F4848133F49131F121F5B003F140F90C7FCA2127EED078092C7FCA212FE
+5AA8913803FFF84A13FCA27E007E6D13F89138000FC0A36C141FA27F121F6D133F120F6D
+137F6C7E6C6C13FF6D5A3801FF076C90B5FC6D13EF011F13CF6DEB0780D901FCC7FC2635
+7DB32C>I<D87FFEEBFFFCB54813FEA36C486C13FCD807E0EB0FC0B190B6FCA59038E000
+0FB3D87FFEEBFFFCB54813FEA36C486C13FC27337EB22C>I<007FB512F8B612FCA36C14
+F839000FC000B3B3A5007FB512F8B612FCA36C14F81E3379B22C>I<D87FFCEB7FF8486C
+EBFFFCA36C48EB7FF8D807C0EB1F80153FED7F00157E5D4A5A14034A5A5D4A5A4A5A143F
+4AC7FC147E5CEBC1F813C3EBC7FCA2EBCFFEEBDFBEEBFFBF141F01FE7F496C7E13F86E7E
+EBF00301E07FEBC001816E7EA2157E153E153F811680ED0FC0A2ED07E0D87FFCEB1FFC48
+6CEB3FFEA36C48EB1FFC27337EB22C>75 D<387FFFE0B57EA36C5BD803F0C8FCB3AE16F0
+ED01F8A8007FB6FCB7FCA36C15F025337DB22C>I<D87FE0EB0FFC486CEB1FFEA26D133F
+007F15FC000F15E001BC137BA4019E13F3A3EB9F01A2018F13E3A21483A2018713C314C7
+A201831383A214EFA201811303A214FFEB80FEA3147C14381400ACD87FF0EB1FFC486CEB
+3FFEA36C48EB1FFC27337EB22C>I<D87FF0EB7FFC486CEBFFFEA27F007FEC7FFCD807FE
+EB07C013DEA213DF13CFA2148013C714C0A213C314E0A213C114F0A213C014F8A2147CA3
+143EA2141E141FA2140F1587A2140715C7A2140315E71401A215F71400A215FFD87FFC13
+7F487E153FA26C48EB1F8027337EB22C>I<EB7FFF0003B512E0000F14F848804880EBE0
+03EB800048C7127FA2007E80A300FE158048141FB3A86C143FA2007E1500A3007F5CA26C
+6C13FEEBF00790B5FC6C5C6C5C000314E0C66C90C7FC21357BB32C>I<007FB512C0B612
+F88115FF6C15802603F00013C0153FED0FE0ED07F0A2150316F81501A6150316F01507A2
+ED0FE0ED3FC015FF90B61280160015FC5D15C001F0C8FCB0387FFF80B57EA36C5B25337E
+B22C>I<EB7FFF0003B512E0000F14F848804880EBF007EB800048C7127FA2007E80A300
+FE158048141FB3A7EB01F0EB03F800FE143F267E01FC1300A2EB00FE007F5C147FD83F80
+13FEEBF03F90B5FC6C5C6C5C000314E0C67E90380007F0A26E7EA26E7EA26E7EA2157FA2
+153E21407BB32C>I<387FFFFCB67E15E015F86C803907E007FE1401EC007F6F7E151FA2
+6F7EA64B5AA2153F4BC7FCEC01FE140790B55A5D15E081819038E007FCEC01FE1400157F
+81A8160FEE1F80A5D87FFEEB1FBFB5ECFF00815E6C486D5AC8EA01F029347EB22C>I<90
+381FF80790B5EA0F804814CF000714FF5A381FF01F383FC003497E48C7FC007E147F00FE
+143F5A151FA46CEC0F00007E91C7FC127F7FEA3FE0EA1FFCEBFFC06C13FC0003EBFFC06C
+14F06C6C7F01077F9038007FFEEC07FF02001380153FED1FC0A2ED0FE0A20078140712FC
+A56CEC0FC0A26CEC1F806D133F01E0EB7F009038FE01FF90B55A5D00F914F0D8F83F13C0
+D8700790C7FC23357CB32C>I<007FB612FCB712FEA43AFC007E007EA70078153CC71400
+B3AF90383FFFFCA2497F6D5BA227337EB22C>I<3B7FFF803FFFC0B56C4813E0A36C496C
+13C03B03F00001F800B3AF6D130300015DA26D130700005D6D130F017F495A6D6C485AEC
+E0FF6DB5C7FC6D5B010313F86D5B9038003F802B3480B22C>I<D87FFCEB7FFC486CEBFF
+FEA36C48EB7FFCD80FC0EB07E06D130F000715C0A36D131F00031580A36D133F00011500
+A36D5B0000147EA4017E5BA46D485AA490381F83F0A4010F5B14C7A301075BA214EFA201
+035BA214FFA26D90C7FCA46D5A27347EB22C>I<D87FF0EB07FF486C491380A36C486D13
+00001FC8127CA46C6C5CA76C6C495AA4143E147FA33A03E0FF83E0A214F7A201E113C3A3
+000101E35BA201F113C701F313E7A314C1A200005DA201F713F71480A301FF13FF017F91
+C7FC4A7EA4013E133E29347FB22C>I<3A3FFF03FFE0484913F0148714076C6D13E03A01
+F800FE007F0000495A13FE017E5BEB7F03013F5B1487011F5B14CF010F5B14FF6D5BA26D
+90C7FCA26D5AA26D5AA2497EA2497EA2497F81EB0FCF81EB1FC7EC87F0EB3F83EC03F8EB
+7F01017E7FEBFE00497F0001147E49137F000380491480151FD87FFEEBFFFC6D5AB514FE
+6C15FC497E27337EB22C>I<D87FFCEB7FFC486CEBFFFEA36C48EB7FFCD807F0EB0FC015
+1F000315806D133F12016DEB7F0012006D137E017E13FE017F5BEB3F01EC81F8131FEC83
+F0EB0FC314C7903807E7E0A201035B14EF6DB45AA292C7FC7F5C147EB0903807FFE0497F
+A36D5B27337EB22C>I<387FFFFCB512FEA314FC00FCC7FCB3B3B3B512FC14FEA36C13FC
+17416FB92C>91 D<127012F8A27E127C127E123E123F7EA27F120F7F12077F12037F1201
+7F12007F137C137E133EA2133F7F80130F80130780130380130180130080147C147E143E
+A2143F8081140F81140781140381140181140081157CA2157E153E153F811680150FA2ED
+070021417BB92C>I<387FFFFCB512FEA37EC7127EB3B3B3387FFFFEB5FCA36C13FC1741
+7DB92C>I<EB07C0EB1FF0EB7FFC48B5FC000714C0001F14F0397FFC7FFC39FFF01FFEEB
+C007EB0001007CEB007C003014181F0C7AAE2C>I<007FB6FCB71280A46C150021067B7D
+2C>I<1338137CEA01FC1203EA07F813F0EA0FC0EA1F80A2EA3F00123E127E127CA212FC
+5AA3EAFFC013E013F013F8A2127FA2123F13F0EA1FE0EA07C00E1D72B82C>I<3801FFF0
+000713FE001F6D7E15E048809038C01FF81407EC01FC381F80000006C77EC8127EA3ECFF
+FE131F90B5FC1203120F48EB807E383FF800EA7FC090C7FC12FE5AA47E007F14FEEB8003
+383FE01F6CB612FC6C15FE6C14BF0001EBFE1F3A003FF007FC27247CA32C>I<EA7FF048
+7EA3127F1201AAEC1FE0ECFFF801FB13FE90B6FC16809138F07FC09138801FE091380007
+F049EB03F85BED01FC491300A216FE167EA816FE6D14FCA2ED01F86D13036DEB07F0150F
+9138801FE09138E07FC091B51280160001FB5B01F813F83900F03FC027337FB22C>I<90
+3803FFE0011F13F8017F13FE48B5FC48804848C6FCEA0FF0485A49137E4848131890C9FC
+5A127EA25AA8127EA2127F6C140F6DEB1F806C7E6D133F6C6CEB7F003907FE03FF6CB55A
+6C5C6C6C5B011F13E0010390C7FC21247AA32C>I<EC0FFE4A7EA380EC003FAAEB07F8EB
+3FFE90B512BF4814FF5A3807FC0F380FF00348487E497E48487F90C7FC007E80A212FE5A
+A87E007E5CA2007F5C6C7E5C6C6C5A380FF0073807FC1F6CB612FC6CECBFFE6C143FEB3F
+FC90390FF01FFC27337DB22C>I<EB03FE90381FFFC0017F13F048B57E48803907FE03FE
+390FF800FFD81FE0EB3F805B4848EB1FC090C7120F5A007E15E015075AB7FCA416C000FC
+C9FC7E127EA2127F6CEC03C06DEB07E06C7ED80FF0130F6C6CEB3FC001FF13FF000190B5
+12806C1500013F13FC010F13F00101138023247CA32C>I<ED03F8903907F80FFC90391F
+FE3FFE017FB6FC48B7FC48ECFE7F9038FC0FF82607F003133E3A0FE001FC1CD9C0001300
+001F8049137EA66D13FE000F5CEBE0016C6C485A3903FC0FF048B5FC5D481480D99FFEC7
+FCEB87F80180C8FCA37F6C7E90B512F06C14FE48ECFF804815E04815F03A3FC0001FF848
+C7EA03FC007E1400007C157C00FC157E48153EA46C157E007E15FCD87F801303D83FE0EB
+0FF8D81FFCEB7FF06CB612E0000315806C1500D8003F13F8010713C028387EA42C>103
+D<EA7FF0487EA3127F1201AAEC1FE0EC7FFC9038F9FFFE01FB7F90B6FC9138F03F80ECC0
+1F02807FEC000F5B5BA25BB3267FFFE0B5FCB500F11480A36C01E0140029337FB22C>I<
+1307EB1FC0A2497EA36D5AA20107C7FC90C8FCA7387FFFC080B5FC7EA2EA0007B3A8007F
+B512FCB612FEA36C14FC1F3479B32C>I<EA7FE0487EA3127F1201AA91381FFFF04A13F8
+A36E13F0913800FE004A5A4A5A4A5A4A5A4A5A4A5A4AC7FC14FEEBF1FC13F3EBF7FE90B5
+FCA2EC9F80EC0FC001FE7FEBFC07496C7E496C7E811400157E811680151F3A7FFFC0FFFC
+B500E113FEA36C01C013FC27337EB22C>107 D<387FFFE0B57EA37EEA0003B3B3A5007F
+B61280B712C0A36C158022337BB22C>I<3A7F83F007E09039CFFC1FF83AFFDFFE3FFCD8
+7FFF13FF91B57E3A07FE1FFC3E01FCEBF83F496C487E01F013E001E013C0A301C01380B3
+3B7FFC3FF87FF0027F13FFD8FFFE6D13F8D87FFC4913F0023F137F2D2481A32C>I<397F
+F01FE039FFF87FFC9038F9FFFE01FB7F6CB6FC00019038F03F80ECC01F02807FEC000F5B
+5BA25BB3267FFFE0B5FCB500F11480A36C01E0140029247FA32C>I<EB07FCEB1FFF017F
+13C048B512F048803907FC07FC390FF001FE48486C7E0180133F003F158090C7121F007E
+EC0FC0A348EC07E0A76C140F007E15C0A2007F141F6C15806D133F6C6CEB7F006D5B6C6C
+485A3907FC07FC6CB55A6C5C6C6C13C0011F90C7FCEB07FC23247CA32C>I<397FF01FE0
+39FFF8FFF801FB13FE90B6FC6C158000019038F07FC09138801FE091380007F049EB03F8
+5BED01FC491300A216FE167EA816FE6D14FCA2ED01F86D13036DEB07F0150F9138801FE0
+9138E07FC091B51280160001FB5B01F813F8EC3FC091C8FCAD387FFFE0B57EA36C5B2736
+7FA32C>I<903903FC078090391FFF0FC0017F13CF48B512EF4814FF3807FE07380FF001
+48487E49137F4848133F90C7FC48141F127E150F5AA87E007E141FA26C143F7F6C6C137F
+6D13FF380FF0033807FC0F6CB6FC6C14EF6C6C138F6D130FEB07F890C7FCAD0203B5FC4A
+1480A36E140029367DA32C>I<D87FFEEB3FC0B53801FFF0020713F8021F13FC6C5B3900
+3F7FE1ECFF019138FC00F84A13704A13005CA25C5CA391C8FCAF007FB512E0B67EA36C5C
+26247EA32C>I<90387FF8700003B512F8120F5A5A387FC00F387E00034813015AA36CEB
+00F0007F140013F0383FFFC06C13FE6CEBFF80000314E0C66C13F8010113FCEB0007EC00
+FE0078147F00FC143F151F7EA26C143F6D133E6D13FE9038F007FC90B5FC15F815E000F8
+148039701FFC0020247AA32C>I<131E133FA9007FB6FCB71280A36C1500D8003FC8FCB1
+ED03C0ED07E0A5EC800F011FEB1FC0ECE07F6DB51280160001035B6D13F89038003FE023
+2E7EAD2C>I<3A7FF003FF80486C487FA3007F7F0001EB000FB3A3151FA2153F6D137F39
+00FE03FF90B7FC6D15807F6D13CF902603FE07130029247FA32C>I<3A3FFF03FFF04801
+8713F8A36C010313F03A00FC007E005D90387E01F8013F5BEB1F83EC87E090380FCFC090
+3807EF80EB03FF6D90C7FC5C6D5A147C14FE130180903803EF80903807CFC0EB0FC7EC83
+E090381F01F0013F7FEB7E00017C137C49137E0001803A7FFF01FFFC1483B514FE6C15FC
+140127247EA32C>120 D<3A7FFF01FFFCB5008113FE148314816C010113FC3A03E0000F
+806C7E151F6D140012005D6D133E137C017E137E013E137CA2013F13FC6D5BA2EB0F815D
+A2EB07C1ECC3E0A2EB03E3ECE7C0130114F75DEB00FFA292C7FC80A2143EA2147E147CA2
+14FC5CA2EA0C01003F5BEA7F83EB87E0EA7E0F495A387FFF806C90C8FC6C5A6C5AEA07E0
+27367EA32C>I<15FF02071380141F147F91B512004913C04AC7FCEB03F85CB31307EB1F
+E013FF007F5BB55A49C8FC6D7E6C7FC67F131FEB07F01303B380EB01FEECFFC06D13FF6E
+1380141F14070200130021417BB92C>123 D<127812FCB3B3B3A9127806416DB92C>I<EA
+7FC0EAFFF813FE6D7E6C7FC67F131FEB07F01303B380EB01FEECFFC06D13FF6E1380141F
+147F91B512004913C04AC7FCEB03F85CB31307EB1FE013FF007F5BB55A49C8FC13F8EA7F
+C021417BB92C>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fe ecti1000 10 33
+/Fe 33 122 df<EE3FFC4BB51280923907E007C092391F8001E0DB3F0013F0037E13034B
+1307A24A5A18E04A48EB038094C7FCA314075DA4140F5DA3010FB7FCA25F903A001F8000
+7EA217FE023F5C92C7FCA216015F5C147E16035FA214FE4A13075FA30101140F5F4AECC1
+C0A2161F1783010316805CA2EF870013074A5CEE0F8EEE079EEE03FC010FEC00F04A91C7
+FCA35C131FA2001C90CAFC127E5BEAFE3E133C137CEAF878EA78F0EA3FE0EA0F80344C82
+BA2F>28 D<150C151C153815F0EC01E0EC03C0EC0780EC0F00141E5C147C5C5C495A1303
+495A5C130F49C7FCA2133EA25BA25BA2485AA212035B12075BA2120F5BA2121FA290C8FC
+A25AA2123EA2127EA2127CA412FC5AAD1278A57EA3121C121EA2120E7EA26C7E6C7EA212
+001E5274BD22>40 D<140C140E80EC0380A2EC01C015E0A2140015F0A21578A4157C153C
+AB157CA715FCA215F8A21401A215F0A21403A215E0A21407A215C0140F1580A2141F1500
+A2143EA25CA25CA2495AA2495A5C1307495A91C7FC5B133E133C5B5B485A12035B48C8FC
+120E5A12785A12C01E527FBD22>I<4B7EA3150393C8FCA35D1506A3150E150CA3151C15
+18A315381530A31570B912E0A2C80060C8FC15E05DA314015DA3140392C9FCA35C1406A3
+140E140CA3141C1418A2333275AD40>43 D<EA03C0EA07F0120F121F13F8A313F0EA07B0
+EA003013701360A213E013C01201EA038013005A120E5A5A5A5A5A0D197A8819>I<120E
+EA3F80127F12FFA31300127E123C0909778819>46 D<0103B612FEEFFFC018F0903B0007
+F8000FF84BEB03FCEF00FE020F157FF03F804B141F19C0021F150F19E05D1807143F19F0
+5DA2147FA292C8FCA25C180F5CA2130119E04A151FA2130319C04A153FA201071780187F
+4A1600A2010F16FEA24A4A5A60011F15034D5A4A5D4D5A013F4B5A173F4A4AC7FC17FC01
+7FEC03F84C5A91C7EA1FC04949B45A007F90B548C8FCB712F016803C397CB83F>68
+D<0103B512F8A390390007F8005DA2140FA25DA2141FA25DA2143FA25DA2147FA292C7FC
+A25CA25CA21301A25CA21303A25CA21307A25CA2130FA25CA2131FA25CA2133FA25CA213
+7FA291C8FC497EB6FCA25C25397CB820>73 D<0107B512FCA25E9026000FF8C7FC5D5D14
+1FA25DA2143FA25DA2147FA292C8FCA25CA25CA21301A25CA21303A25CA21307A25CA213
+0F170C4A141CA2011F153C17384A1478A2013F157017F04A14E01601017F140317C091C7
+1207160F49EC1F80163F4914FF000102071300B8FCA25E2E397BB834>76
+D<ED03FE92383FFFC09238FC07F0913903E001F891390F80007C023FC77E027E8002F815
+804948EC0FC0EB07E04948EC07E0131F4A15F049C81203137E01FE16F8485AA2485AA248
+5AA2120F5B001F16075B123FA34848ED0FF0A448C9EA1FE0A3EF3FC0A21880177F18005F
+5F16015F6C4B5A4C5AA24C5A6C4B5A6D4A5A001F93C7FC6D147E000F5D6C6CEB03F06C6C
+495A6C6CEB0F806C6C013FC8FC90383F01FC90381FFFE0010190C9FC353D74BA40>79
+D<ED03FE92383FFFC09238FC07F0913903E001F891390FC0007C023FC77E027E804A1580
+D901F0EC0FC013074948EC07E0495A4A15F049C8FC49150301FE16F8485AA2485AA2485A
+A2120F491507121FA2485AA34848ED0FF0A448C9EA1FE0A3EF3FC0A21880177F4817005F
+5F16015F007F4B5A5F91380F800791393FE00FE06C903970601FC0902680E0305B261F81
+C049C7FC913880187ED80FC35C3A07E30019F00003EC1FE0D801FB14806CB46C48C8FC90
+263F81FC13186DB45A01010138133890C7003C1330177017F05FED3E03ED3F07EEFFC05F
+A294C7FC5E6F5A6F5AED07E0354B74BA40>81 D<92383FC00E913901FFF01C020713FC91
+391FC07E3C91393F001F7C027CEB0FF84A130749481303495A4948EB01F0A2495AA2011F
+15E091C7FCA34915C0A36E90C7FCA2806D7E14FCECFF806D13F015FE6D6D7E6D14E00100
+80023F7F14079138007FFC150F15031501A21500A2167C120EA3001E15FC5EA3003E4A5A
+A24B5AA2007F4A5A4B5A6D49C7FC6D133ED8F9F013FC39F8FC03F839F07FFFE0D8E01F13
+8026C003FCC8FC2F3D7ABA2F>83 D<0007B812E0A25AD9F800EB001F01C049EB07C0485A
+D900011403121E001C5C003C17801403123800785C00701607140700F01700485CA2140F
+C792C7FC5DA2141FA25DA2143FA25DA2147FA292C9FCA25CA25CA21301A25CA21303A25C
+A21307A25CA2130FA25CEB3FF0007FB512F8B6FCA2333971B83B>I<14F8EB07FE90381F
+871C90383E03FE137CEBF801120148486C5A485A120FEBC001001F5CA2EA3F801403007F
+5C1300A21407485C5AA2140F5D48ECC1C0A2141F15831680143F1587007C017F1300ECFF
+076C485B9038038F8E391F0F079E3907FE03FC3901F000F0222677A42A>97
+D<133FEA1FFFA3C67E137EA313FE5BA312015BA312035BA31207EBE0F8EBE7FE9038EF0F
+80390FFC07C013F89038F003E013E0D81FC013F0A21380A2123F1300A214075A127EA214
+0F12FE4814E0A2141F15C05AEC3F80A215005C147E5C387801F8007C5B383C03E0383E07
+C0381E1F80D80FFEC7FCEA01F01C3B77B926>I<147F903803FFC090380FC1E090381F00
+70017E13784913383901F801F83803F003120713E0120FD81FC013F091C7FC485AA2127F
+90C8FCA35A5AA45AA3153015381578007C14F0007EEB01E0003EEB03C0EC0F806CEB3E00
+380F81F83803FFE0C690C7FC1D2677A426>I<ED01F815FFA3150316F0A21507A216E0A2
+150FA216C0A2151FA21680A2153FA202F81300EB07FE90381F877F90383E03FF017C5BEB
+F80112013803F00048485B120FEBC001121F5DEA3F801403127F01005BA214075A485CA2
+140FA248ECC1C0A2141F15C3ED8380143F1587007C017F1300ECFF076C485B9038038F8E
+391F0F079E3907FE03FC3901F000F0253B77B92A>I<147F903803FFC090380FC1E09038
+3F00F0017E13785B485A485A485A120F4913F8001F14F0383F8001EC07E0EC1F80397F81
+FF00EBFFF8148090C8FC5A5AA55AA21530007C14381578007E14F0003EEB01E0EC03C06C
+EB0F806CEB3E00380781F83803FFE0C690C7FC1D2677A426>I<ED07C0ED1FF0ED3E38ED
+7C3CEDF8FC15F9140115F1020313F8EDF0F0160014075DA4140F5DA4141F5D010FB512C0
+5B16809039003F800092C7FCA45C147EA414FE5CA413015CA413035CA413075CA4130F5C
+A3131F5CA391C8FC5B121CEA7E3EA2EAFE3C137C1378EAF8F01278EA3FC0EA0F80264C82
+BA19>I<EC07C0EC3FF09138FC38E0903901F01FF0EB03E0903807C00FEB0F80011F1307
+D93F0013E05B017E130F13FE4914C01201151F1203491480A2153F1207491400A25DA249
+137EA215FEA25D00031301140314076C6C485A0000131FEB787BEB3FF390380FC3F0EB00
+031407A25DA2140F5D121C007E131F5D00FE49C7FC147E5C387801F8387C07E0381FFF80
+D803FEC8FC24367CA426>I<EB03F0EA01FFA3EA00075CA3130F5CA3131F5CA3133F91C8
+FCA35B90387E07F0EC1FFCEC783E9038FFE01F02C01380EC800F1400485A16C05B49EB1F
+8012035BA2153F000715005BA25D000F147E5B15FE5D121FD98001131C15F8163C003F01
+031338010013F0A216704814E0007E15F016E0EDE1C000FE903801E38048903800FF0000
+38143C263B7BB92A>I<EB01C0EB07E014F0130F14E01307EB038090C7FCAB13F0EA03FC
+EA071EEA0E1F121CA212385B1270A25BEAF07E12E013FEC65AA212015B1203A25B12075B
+A2000F13E013C013C1001F13C01381A2EB83801303EB0700A2130E6C5AEA07F8EA01E014
+3879B619>I<EB0FC0EA07FFA3EA001F1480A2133FA21400A25BA2137EA213FEA25BA212
+01A25BA21203A25BA21207A25BA2120FA25BA2121FA25BA2123FA290C7FCA25AA2EA7E0E
+A212FE131EEAFC1CA2133C133812F81378EA7870EA7CE0121FEA0F80123B79B915>108
+D<D801E001FEEB07F03C07F803FF801FFC3C0E3C0F07C0783E3C1E3E3C03E1E01F261C1F
+78D9F3C013803C383FF001F7800F02E01400007801C013FE007018C002805B4A4848EB1F
+80EAF07FD8E07E5CA200000207143F01FE1700495CA2030F5C0001177E495C18FE031F5C
+120349DA8001131C18F8033F153C00070403133849020013F0A24B1570000F17E049017E
+15F019E003FEECE1C0001FEE01E34949903800FF000007C70038143C3E2679A444>I<D8
+01E013FE3A07F803FF803A0E3C0F07C03A1E3E3C03E0261C1F787F39383FF00114E00078
+13C000708114804A485AEAF07FEAE07EA20000140701FE5C5BA2150F00015D5B151F5E12
+034990383F8380160316070007027F130049137EA2160E000F147C49141E161C5E001FEC
+3C7849EB1FE00007C7EA0780292679A42F>I<147F903803FFC090380FC1F090381F00F8
+017E137C5B4848137E4848133E0007143F5B120F485AA2485A157F127F90C7FCA215FF5A
+4814FEA2140115FC5AEC03F8A2EC07F015E0140F007C14C0007EEB1F80003EEB3F00147E
+6C13F8380F83F03803FFC0C648C7FC202677A42A>I<9039078007C090391FE03FF09039
+3CF0787C903938F8E03E9038787FC00170497EECFF00D9F0FE148013E05CEA01E113C15C
+A2D80003143FA25CA20107147FA24A1400A2010F5C5E5C4B5A131F5EEC80035E013F495A
+6E485A5E6E48C7FC017F133EEC70FC90387E3FF0EC0F8001FEC9FCA25BA21201A25BA212
+03A25B1207B512C0A3293580A42A>I<3903C003F0390FF01FFC391E783C0F381C7C703A
+3C3EE03F8038383FC0EB7F800078150000701300151CD8F07E90C7FCEAE0FE5BA2120012
+015BA312035BA312075BA3120F5BA3121F5BA3123F90C9FC120E212679A423>114
+D<14FE903807FF8090380F83C090383E00E04913F00178137001F813F00001130313F0A2
+15E00003EB01C06DC7FC7FEBFFC06C13F814FE6C7F6D13807F010F13C01300143F141F14
+0F123E127E00FE1480A348EB1F0012E06C133E00705B6C5B381E03E06CB45AD801FEC7FC
+1C267AA422>I<EB0380EB07C0130FA4131F1480A3133F1400A35B137E007FB5FCA2B6FC
+3800FC00A312015BA312035BA312075BA3120F5BA3121FEB801CA2143C003F1338EB0078
+147014F014E0EB01C0EA3E03381F0780380F0F00EA07FCEA01F0183579B31C>I<01F013
+0ED803FC133FD8071EEB7F80EA0E1F121C123C0038143F49131F0070140FA25BD8F07E14
+0000E08013FEC6485B150E12015B151E0003141C5BA2153C000714385B5DA35DA24A5A14
+0300035C6D48C7FC0001130E3800F83CEB7FF8EB0FC0212679A426>118
+D<903907E007C090391FF81FF89039787C383C9038F03E703A01E01EE0FE3803C01F0180
+13C0D8070014FC481480000E1570023F1300001E91C7FC121CA2C75AA2147EA214FEA25C
+A21301A24A1370A2010314F016E0001C5B007E1401010714C000FEEC0380010F1307010E
+EB0F0039781CF81E9038387C3C393FF03FF03907C00FC027267CA427>120
+D<13F0D803FCEB01C0D8071EEB03E0D80E1F1307121C123C0038140F4914C01270A24913
+1FD8F07E148012E013FEC648133F160012015B5D0003147E5BA215FE00075C5BA214015D
+A314035D14070003130FEBF01F3901F87FE038007FF7EB1FC7EB000F5DA2141F003F5C48
+133F92C7FC147E147C007E13FC387001F8EB03E06C485A383C1F80D80FFEC8FCEA03F023
+3679A428>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Ff cmsy10 10 1
+/Ff 1 16 df<EB1FF0EBFFFE487F000714C04814E04814F04814F8A24814FCA3B612FEA9
+6C14FCA36C14F8A26C14F06C14E06C14C0000114006C5BEB1FF01F1F7BA42A>15
+D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fg ecbx1000 10 36
+/Fg 36 119 df<913803FFC0027F13F00103B512FC010FEB00FED93FF8133FD97FE0EBFF
+8049485A5A1480484A13C04A6C1380A36F1300167E93C7FCA592383FFFC0B8FCA4000390
+C7FCB3ABB5D8FC3F13FFA4303A7EB935>28 D<B61280A819087F9620>45
+D<EA0F80EA3FE0EA7FF0A2EAFFF8A5EA7FF0A2EA3FE0EA0F800D0D798C1B>I<141E143E
+14FE1307137FB5FCA3138FEA000FB3B3A5007FB61280A4213679B530>49
+D<EB0FFE90387FFFC048B512F0000714FC390FE03FFF261F800F1380263F000313C0D87F
+8014E0EBE00100FF6D13F07FA2ED7FF8A46C5A6C5A0006C7FCC8FCEDFFF0A216E05C16C0
+4A138016004A5A4A5AEC1FF05D4A5A4AC7FC14FE495AD903F01378495A495A495A49C712
+F8017C14F05B49130148B6FC5A5A5A5A5A4815E0B7FCA425367BB530>I<EC0FF8ECFFFE
+0103EBFF8090390FF80FC090393FE003E090397F8001F09038FF000F48EC1FF84848133F
+485A120F5B121FA2003FEC1FF0ED0FE0484890C7FCA31408EC7FF039FFF1FFFC01F313FF
+D9F78013809039FF007FC049EB3FE04914F0ED1FF85B16FCA34914FEA4127FA5123F16FC
+A26C7E16F8000F143F6D14F0000715E06C6CEB7FC03A01FF81FF806C90B51200013F13FC
+010F13F00101138027377CB530>54 D<EA0F80EA3FE0EA7FF0A2EAFFF8A5EA7FF0A2EA3F
+E0EA0F80C7FCABEA0F80EA3FE0EA7FF0A2EAFFF8A5EA7FF0A2EA3FE0EA0F800D2579A41B
+>58 D<B812C017FC17FF18C028007FF000037F04007F717E717E171F84A2717EA74D5AA2
+60173F4D5A4D5A4C13C0040F5B91B600FCC7FCA2EFFF8002F0C713F0EF3FF8717E717E71
+7E19807113C0A319E0A719C0A25F4D138019005FEF7FFE4C485AB912F018C095C7FC17F0
+3B397DB844>66 D<DB3FFCEB01C00203B5EAC003021FECF00791B6EAFC0F01039039FC00
+FF3F4901C0EB1FFFD91FFEC77E49481403D97FF080494880485B48177F4849153F4890C9
+FC181F485A180F123F5B1807127FA24993C7FC12FFAD127F7FF003C0123FA27F001F1707
+A26C6C1780180F6C6D16006C6D5D6C173E6C6D157ED97FF85D6D6C4A5A6DB44A5A010701
+C0EB0FE06D01FCEBFF80010090B548C7FC021F14F8020314E09126003FFEC8FC3A3B7BB9
+45>I<B87E17F817FF18C028007FF8000713F09338007FF8EF1FFE717E050313807113C0
+A27113E0F07FF0A2F03FF8A219FC181FA219FEA419FFAC19FEA419FC183FA219F8187F19
+F0F0FFE0A24D13C04D13804D1300EF1FFEEF7FFC933807FFF0B912C095C7FC17FC178040
+397DB849>I<B612FCA439007FF800B3B3ADB612FCA41E397DB824>73
+D<B7FCA426007FF8C9FCB3ACEF0780A5170F1800A35FA25FA25F5F5E5EEE0FFE167FB8FC
+A431397DB839>76 D<B500F80403B512F06E5EA26E5ED8007FF1E000A2D97BFF161EA201
+796D5DA201786D5DA26E6C5DA36E6C4A5AA26E6C4A5AA26E6C4A5AA26E6C4A5AA26E6C14
+1EA36E6D5BA26E6D5BA26F6C5BA26F6C485AA36F6C485AA26F6C485AA26F6C48C7FCA292
+3803FF1EA36F13BCA26F13F8A2705AA2705AA213FCB500FC6D4848B612F0A2EE0F80EE07
+0054397DB85B>I<B500FC0203B512F0A28080C66C6D90390003F0006F6E5A81017B7F13
+798101787F6E7E6E7E6E7F6E7FA26E7F6E7F6E7F6E7F6F7E153F826F13806F13C06F13E0
+6F13F06F13F88117FCEE7FFEEE3FFF7013817013C17013E18218F17013F97013FDEF7FFF
+8383A28383838383187FA2183F181F01FC160FB500FC150718031801A244397DB84B>I<
+EDFFF8020FEBFF80027F14F0903A01FFC01FFC010790380007FFD91FFC010113C0D93FF0
+6D6C7E49486E7E49486E7E48496E7E48834890C86C7EA248486F1380A248486F13C0A200
+3F18E0A348486F13F0A400FF18F8AC007F18F06D5DA3003F18E0A26D5D001F18C0A26C6C
+4B13806C18006E5C6C6D4A5A6C5F6C6D4A5A6D6C4A5AD93FFC49485A6DB401075B0107D9
+C01F90C7FC010190B512FC6D6C14F0020F1480020001F8C8FC3D3B7BB948>I<B8FC17F0
+17FEEFFF8028007FF8000F13C0040113E07013F0EF7FF8EF3FFCA2EF1FFEA218FFA818FE
+A2EF3FFCA2EF7FF8EFFFF04C13E0040F13C091B7120017FC17E002F8C9FCB3A4B612FCA4
+38397DB841>I<EDFFF8020FEBFF80027F14F0903A01FFE03FFC010790380007FFD91FFC
+010113C049486D7FD97FE0EC3FF049486E7E488348496E7E4890C86C7EA248486F1380A2
+001F18C04981003F18E0A3007F18F04981A300FF18F8AC007F18F0A36D5D003F18E0A36C
+6C4B13C0A2000FDA1FC014806C6C90267FF0071300EDFFF86C903A81F07C0FFE6C903AC3
+C01E1FFC6CDA800F5BD97FE3ECBFF0D93FF36DB45AD91FFF5D010701C091C7FC01019038
+F01FFC6D6CB500F01308020F6E131C0200EBF9FC92260001FE133C9438FF80FC18FF8219
+F8A28319F0A27113E0A27113C0711380711300EF01FC3E4A7BB948>I<D907FF130E013F
+EBE01E90B5EAF83E0003ECFE7E3A07FC01FFFE390FF0001F4848130F4848130349130100
+7F140090C8FC167E5A163EA27F161E7F7F6D91C7FC13FC387FFFE014FEECFFF06C14FE6F
+7E6C816C15F06C816C81C681133F010F801301D9000F1480EC007F030F13C01503818100
+F0157FA3163FA27E17807E167F6C16007E6D14FE01E0495A01F813039039FF801FF800FC
+90B512E0D8F83F5CD8F00749C7FC39E0007FF02A3B7BB935>83 D<B600FC011FB512C0A4
+26007FF8C8381FC000725AB3B3181F013F94C7FC8060011F163E6D6C157E187C6D6C15FC
+6D6D495A6D6DEB07F06D01F0EB1FE0DA7FFEEBFFC0021FB6C8FC02075C020014F0030F13
+80423A7DB849>85 D<B600F00103B512E0A4C601F0C83807F0006E5E017F5F6E150FA201
+3F5F6E151F011F94C7FC6E5D6D163E6F147E6D167CA26F14FC6D5E6F13016D5E6F13036D
+5E811707027F5D6F130F023F5D6F131F021F92C8FC815F6E143EEE807E6E147CEEC0FC6E
+5C16E016E16E5C16F36E5C16FF6F5BA36F5BA26F90C9FCA26F5AA36F5AA26F5AA26F5A43
+3A7EB848>I<B6D8E01FB500FC90383FFFFCA4000101F0C7D83FFCC8EA7E006C71153C17
+1F6E197C017F701578836E7014F8013F6F5E6E1801011F4B6D5CA26E18036D4B6D5CA26D
+6D496D495A173C6F170F6D037C6D91C7FCEF787F6F5F6D4B6C6C131E816D02016E5BEFE0
+1F03F8177C027F01036E13784D7E03FCEE80F8023F49486C5C15FE021F010FEDC1E04D7E
+03FF16C36E49EDE3C0041E7F049E15F76E01BC6D5C04FC15FF6E95C8FC4C80A26E5F4C14
+3F6E5F4C141FA2037F5E4C140FA26F486E5AA2031F5E93C812036F5E5E3A7EB863>I<13
+FFB5FCA412077EAF4AB47E020F13F0023F13FC9138FE03FFDAF00013804AEB7FC00280EB
+3FE091C713F0EE1FF8A217FC160FA217FEAA17FCA3EE1FF8A217F06E133F6EEB7FE06E14
+C0903AFDF001FF80903AF8FC07FE009039F03FFFF8D9E00F13E0D9C00390C7FC2F3A7EB9
+35>98 D<EE7F80ED7FFFA4150381AF903801FF81010F13F1013F13FD9038FFC07F0003EB
+001FD807FC1307000F8048487F5B123FA2485AA312FFAA127FA27F123FA26C6C5B000F5C
+6C6C5B6C6C4913C02701FF80FD13FE39007FFFF9011F13E1010113012F3A7DB935>100
+D<903803FF80011F13F0017F13FC3901FF83FE3A03FE007F804848133F484814C0001FEC
+1FE05B003FEC0FF0A2485A16F8150712FFA290B6FCA301E0C8FCA4127FA36C7E1678121F
+6C6C14F86D14F000071403D801FFEB0FE06C9038C07FC06DB51200010F13FC010113E025
+257DA42C>I<EC1FF0903801FFFC010713FF90391FF87F8090383FE0FFD9FFC113C0A248
+1381A24813016E1380A2ED3E0092C7FCA8B6FCA4000390C8FCB3ABB512FEA4223A7DB91D
+>I<161FD907FEEBFFC090387FFFE348B6EAEFE02607FE07138F260FF801131F48486C13
+8F003F15CF4990387FC7C0EEC000007F81A6003F5DA26D13FF001F5D6C6C4890C7FC3907
+FE07FE48B512F86D13E0261E07FEC8FC90CAFCA2123E123F7F6C7E90B512F8EDFF8016E0
+6C15F86C816C815A001F81393FC0000F48C8138048157F5A163FA36C157F6C16006D5C6C
+6C495AD81FF0EB07FCD807FEEB3FF00001B612C06C6C91C7FC010713F02B377DA530>I<
+EA01F0EA07FC487EA2487EA56C5AA26C5AEA01F0C8FCA913FF127FA412077EB3A9B512F8
+A4153B7DBA1B>105 D<13FFB5FCA412077EAF92380FFFE0A4923803FC0016F0ED0FE0ED
+1F804BC7FC157E5DEC03F8EC07E04A5A141FEC7FE04A7E8181A2ECCFFEEC0FFF496C7F80
+6E7F6E7F82157F6F7E6F7E82150F82B5D8F83F13F8A42D3A7EB932>107
+D<13FFB5FCA412077EB3B3ACB512FCA4163A7DB91B>I<01FED97FE0EB0FFC00FF902601
+FFFC90383FFF80020701FF90B512E0DA1F81903983F03FF0DA3C00903887801F000749DA
+CF007F00034914DE6D48D97FFC6D7E4A5CA24A5CA291C75BB3A3B5D8FC1FB50083B512F0
+A44C257DA451>I<01FEEB7FC000FF903803FFF8020F13FE91381F03FFDA3C0113800007
+13780003497E6D4814C05CA25CA291C7FCB3A3B5D8FC3F13FFA430257DA435>I<903801
+FFC0010F13F8017F13FFD9FF807F3A03FE003FE048486D7E48486D7E48486D7EA2003F81
+491303007F81A300FF1680A9007F1600A3003F5D6D1307001F5DA26C6C495A6C6C495A6C
+6C495A6C6C6CB45A6C6CB5C7FC011F13FC010113C029257DA430>I<9038FE03F000FFEB
+0FFEEC3FFF91387C7F809138F8FFC000075B6C6C5A5CA29138807F80ED3F00150C92C7FC
+91C8FCB3A2B512FEA422257EA427>114 D<90383FF0383903FFFEF8000F13FF381FC00F
+383F0003007E1301007C130012FC15787E7E6D130013FCEBFFE06C13FCECFF806C14C06C
+14F06C14F81203C614FC131F9038007FFE140700F0130114007E157E7E157C6C14FC6C14
+F8EB80019038F007F090B512C000F8140038E01FF81F257DA426>I<130FA55BA45BA25B
+5BA25A1207001FEBFFE0B6FCA3000390C7FCB21578A815F86CEB80F014816CEBC3E09038
+3FFFC06D1380903803FE001D357EB425>I<B539F001FFF8A4000390C7EA1F00161E6E13
+3E6C153C6E137C6C15786E13F8017F5CECF001013F5C14F8011F495AA2ECFC07010F5CEC
+FE0F010791C7FC6E5A6D131E15BE6D13BC15FC6D5BA36E5AA26E5AA26E5AA26E5AA22D25
+7EA432>118 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fh ecrm1000 10 89
+/Fh 89 126 df<486C1360000314E039070001C0000EEB038048EB070000181306003813
+0E0030130C0070131C00601318A200E01338481330A400CEEB338039FF803FE001C013F0
+A3007F131FA2393F800FE0390E0003801C1981B91C>16 D<001C1307007FEB1FC039FF80
+3FE0A201C013F0A3007F131F001CEB073000001300A400011470491360A2000314E090C7
+12C048130100061480000E130348EB070048130E485B006013181C1980B91C>I<B81280
+A2290280962A>21 D<DA0FF813FC91397FFF07FF903B01F807DF83C0903A07E001FF0F90
+3B1F8007FE1FE090393F000FFC137E16F85B9338F007804848010790C7FC1503ACB812F8
+A32801F80003F0C7FCB3AB486C497E267FFFE0B512F0A3333B7FBA30>27
+D<EC0FF8EC7FFE903901F80780903907E001C090391F8000E090383F0007017E497EA25B
+A2485A6F5AED018092C8FCA9ED03F0B7FCA33901F8000F1503B3AA486C497E267FFFE0B5
+12C0A32A3B7FBA2E>I<DA0FF0EB1FF0DA7FFEEBFFFC903B01F80F83F00F903C07E001CF
+C00380903C1F8000FF0001C090273F0007FE130F017E4948497EA2495CA248485C03076E
+5A03030203C7FC95C8FCA9F007E0BAFCA33C01F80003F0001F1807B3AA486C496C497E26
+7FFFE0B500C1B51280A3413B7FBA45>30 D<EB0380A3EB0FF0EB7FFE48B512803903F38F
+C03907C381E0390F8380F0D81F031338123E003C141C007C140C150E0078143E00F814FE
+1481A400FCEB80FC157800FE140012FF127F13C313E3EA3FFF6C7F14F86C13FE6CEBFF80
+000114C06C14E0013F13F01303ECBFF8148FEC83FC1481A2EC80FE157E123C12FF153EA4
+12FE00F8143C00E0147C12600070147815F8003814F0003C1381001EEB83E0000FEB87C0
+3907E39F803901FFFE006C5BEB1FE0EB0380A41F437BBD2A>36 D<141FEC7FC0903801F0
+E0903803C0600107137090380F803090381F00381518A25BA2133E133F15381530A21570
+5D5D140190381F838092CAFC1487148E02DC49B51280EB0FF85C4A9039003FF8000107ED
+0FC06E5D71C7FC6E140E010F150CD91DFC141C01391518D970FE143801E015302601C07F
+1470D803805D00076D6C5BD80F00EBC00148011F5C4890380FE003003E6E48C8FC007E90
+3807F8060203130E00FE6E5A6E6C5A1400ED7F706C4B13036F5A6F7E6C6C6D6C5B701306
+6C6C496C130E6DD979FE5B281FF001F07F133C3C07F80FE03FC0F86CB539800FFFF0C690
+26FE000313C0D91FF0D9007FC7FC393E7DBB41>38 D<121C127FEAFF80A213C0A3127F12
+1C1200A412011380A2120313005A1206120E5A5A5A12600A1979B917>I<146014E0EB01
+C0EB0380EB0700130E131E5B5BA25B485AA2485AA212075B120F90C7FCA25A121EA2123E
+A35AA65AB2127CA67EA3121EA2121F7EA27F12077F1203A26C7EA26C7E1378A27F7F130E
+7FEB0380EB01C0EB00E01460135278BD20>I<12C07E12707E7E7E120F6C7E6C7EA26C7E
+6C7EA21378A2137C133C133E131EA2131F7FA21480A3EB07C0A6EB03E0B2EB07C0A6EB0F
+80A31400A25B131EA2133E133C137C1378A25BA2485A485AA2485A48C7FC120E5A5A5A5A
+5A13527CBD20>I<1530B3A8B912FCA2C80030C8FCB3A836367BAF41>43
+D<121C127FEAFF80A213C0A3127F121C1200A412011380A2120313005A1206120E5A5A5A
+12600A19798817>I<B512FCA516057F941C>I<121C127FEAFF80A5EA7F00121C09097988
+17>I<1506A2150E150CA2151C151815381530A215701560A215E015C0A214011580A214
+0315005C1406A2140E140CA2141C1418A214381430A21470146014E05CA213015CA21303
+91C7FCA25B1306A2130E130C131C1318A213381330A213701360A213E05BA212015B1203
+90C8FCA25A1206A2120E120CA2121C1218A21238123012701260A212E05AA21F537BBD2A
+>I<EB03F8EB1FFF90387E0FC09038F803E03901E000F0484813780007147C48487FA248
+C77EA2481580A3007EEC0FC0A500FE15E0B3007E15C0A4007F141F6C1580A36C1500A26C
+6C133EA26C6C5B6C6C5BEBF0013900F803E090387E0FC0D91FFFC7FCEB03F823397DB62A
+>I<EB01C013031307131F13FFB5FCA2131F1200B3B3A7497E007FB512F0A31C3779B62A>
+I<EB0FF0EB7FFE48B57E3903E03FE0390F000FF0001E6D7E001C6D7E486D7E5A6E7E1260
+12FE6CEC7F807FA56CC7FC121CC8FCEDFF00A25D14015D14035D4A5A4A5A5D4A5A4AC7FC
+147E5C495A14E0495A495A49C8FC011EEB01805B5B49130348481400485A485A90C75A48
+B6FC5A5A485CB6FCA321377CB62A>I<EB07F8EB3FFF90B512C03901F80FF03903C007F8
+48486C7E390E0001FEEA0F80391FE000FF7FA56C5A6C5AC7485AA25D14035D4A5A5DEC0F
+80027FC7FCEB1FFCECFF809038000FE06E7EEC01FC816E7EED7F80A216C0A2153F16E0A2
+121EEA7F80A2487EA316C0157F491480007EC7FC0070ECFF006C495A121E390F8003F839
+07F00FF00001B512C06C6C90C7FCEB0FF823397DB62A>I<1538A2157815F8A214011403
+1407A2140F141F141B14331473146314C313011483EB030313071306130C131C13181330
+1370136013C01201EA038013005A120E120C5A123812305A12E0B712F8A3C73803F800AA
+4A7E0103B512F8A325387EB72A>I<0006140CD80780133C9038F003F890B5FC5D5D1580
+92C7FC14FC38067FE090C9FCAAEB07F8EB1FFE9038780F809038E007E03907C003F0496C
+7E130000066D7E81C8FC8181A21680A4121C127F5A7FA390C713005D12FC00605C12704A
+5A6C5C6C1303001E495A6C6C485A3907E03F800001B5C7FC38007FFCEB1FE021397CB62A
+>I<EC3FC0903801FFF0010713FC90380FE03E90383F800790387E001F49EB3F80484813
+7F485A12075B000FEC3F0049131E001F91C7FC5B123FA3127F90C9FCEB01FC903807FF80
+39FF1E07E090383801F0496C7E01607F01E0137E497F16805BED1FC0A390C713E0A57EA4
+7F123F16C0A2001FEC3F807F000F15006D5B000714FE6C6C5B6C6C485A3900FE07F09038
+7FFFC0011F90C7FCEB03FC23397DB62A>I<12301238123E003FB612E0A316C05A168016
+000070C712060060140E5D5D00E014304814705D5DC712014A5A4AC7FC1406140E5CA25C
+1478147014F05C1301A213035C1307A2130FA3131F5CA2133FA5137FA96DC8FC131E233A
+7BB72A>I<EB03F8EB1FFF017F13C09038FC07F03901E001F83903C0007C4848133C90C7
+123E48141E000E141F001E80A3121FA26D5B6D131E7FD80FF85B6D137C01FF13786C6D5A
+6CEBE3E0ECF780C601FFC7FC6D5A6D6C7E010F13E0013F7F01F97F3901E07FFE48486C7E
+380F800F48486C1380001E010113C0487F007C143F0078EC1FE0150F00F81407481403A2
+1501A36C15C0A200781403007C15806C14076CEC0F006C6C131ED807E0137C3903F803F0
+C6B55A013F1380D907FCC7FC23397DB62A>I<EB03F8EB1FFF017F13C03901FC07E04848
+6C7E3907E001F8000F6D7E4848137E5B003F80A248C71380A25AED1FC0A516E0A56C143F
+A36C7E157F121F6C6C13FF6C6C13DF000313013901F0039F3900FC0F1FD93FFC13C0EB07
+F090C7FCA2153F1680A216005D120F486C137E486C5BA24A5A4A5A49485A381F000F001C
+EB1F80260F807FC7FC3807FFFE000113F838003FC023397DB62A>I<121C127FEAFF80A5
+EA7F00121CC7FCB2121C127FEAFF80A5EA7F00121C092479A317>I<121C127FEAFF80A5
+EA7F00121CC7FCB2121C127FEAFF80A213C0A3127F121C1200A412011380A2120313005A
+1206120E5A5A5A12600A3479A317>I<EF01C0EF0780EF1E0017F8EE03E0040FC7FC163C
+16F0ED03C0030FC8FC153CEC01F0EC07C0021EC9FC1478EB01E0EB0780011ECAFC13F8EA
+03E0000FCBFC123C12F0A2123C120FEA03E0EA00F8131EEB0780EB01E0EB0078141EEC07
+C0EC01F0EC003C150FED03C0ED00F0163C160FEE03E0EE00F8171EEF0780EF01C0322E79
+AB41>I<007FB812F8B912FCCCFCB0B912FC6C17F836147B9E41>I<12E01278121EEA07C0
+EA01F0EA003C130FEB03C0EB00F0143C140FEC03E0EC00F8151EED0780ED01E0ED007816
+1EEE07C0EE01F0EE003C170FEF03C0A2EF0F00173CEE01F0EE07C0041EC7FC1678ED01E0
+ED0780031EC8FC15F8EC03E0020FC9FC143C14F0EB03C0010FCAFC133CEA01F0EA07C000
+1ECBFC127812E0322E79AB41>I<EB3FE03801FFFE3907C03F80390E000FC0003CEB07F0
+00301303007014F8007C130100FE14FC7EA4127E003CEB03F8C7FCEC07F0A2EC0FE0EC1F
+80EC3F00147E147C5C495A5C495A5CA249C7FCA31306AA90C8FCA8130EEB3F80497EA56D
+5A010EC7FC1E3B7CBA27>I<1538A3157CA315FEA34A7EA34A6C7EA202077FEC063FA202
+0E7FEC0C1FA2021C7FEC180FA202387FEC3007A202707FEC6003A202C07F1501A2D90180
+7F81A249C77F167FA20106810107B6FCA24981010CC7121FA2496E7EA3496E7EA3496E7E
+A213E0707E1201486C81D80FFC02071380B56C90B512FEA3373C7DBB3E>65
+D<B712E016FC16FF0001903980007FC06C90C7EA1FE0707E707E707EA2707EA283A75F16
+035F4C5A4C5A4C5A4C5AEEFF8091B500FCC7FCA291C7EA7F80EE1FE0EE07F0707E707E83
+707EA21880177F18C0A7188017FFA24C13005F16034C5AEE1FF8486DEB7FF0B812C094C7
+FC16F832397DB83B>I<913A01FF800180020FEBE003027F13F8903A01FF807E07903A03
+FC000F0FD90FF0EB039F4948EB01DFD93F80EB00FF49C8127F01FE153F12014848151F48
+48150FA248481507A2485A1703123F5B007F1601A35B00FF93C7FCAD127F6DED0180A312
+3F7F001F160318006C7E5F6C7E17066C6C150E6C6C5D00001618017F15386D6C5CD91FE0
+5C6D6CEB03C0D903FCEB0F80902701FF803FC7FC9039007FFFFC020F13F002011380313D
+7BBA3C>I<B712C016F816FE000190398001FF806C90C7EA3FE0EE0FF0EE03F8707E707E
+177FA2EF3F8018C0171F18E0170F18F0A3EF07F8A418FCAC18F8A4EF0FF0A218E0A2171F
+18C0EF3F80A2EF7F0017FE4C5A4C5AEE0FF0EE3FE0486DEBFF80B8C7FC16F816C036397D
+B83F>I<B812FEA3000190388000076C90C8FC173F838383A383A31880170116C0A394C7
+FCA31501A21503150F91B5FCA3EC000F15031501A21500A21860A318E093C712C0A41701
+A3EF0380A21707A2170F173F177F486D903807FF00B9FCA333397EB838>I<B812F8A300
+01903880001F6C90C71201EE00FC177C173C171CA2170CA4170E1706A2ED0180A21700A4
+1503A21507151F91B5FCA3EC001F15071503A21501A692C8FCAD4813C0B612C0A32F397D
+B836>I<DBFF8013C0020FEBF001023F13FC9139FF803F03903A03FC000787D90FF0EB03
+CF4948EB00EF4948147F4948143F49C8121F485A4848150F48481507A248481503A2485A
+1701123F5B007F1600A448481600AB93B6FCA26C7E9338007FE0EF3FC0A2123F7F121FA2
+6C7EA26C7EA26C7E6C7E6C6C157F6D7E6D6C14FF6D6C14EFD90FF8EB03C7D903FEEB0783
+903A00FFC03F0191393FFFFC00020F01F0130002001380383D7CBA41>I<B648B512FEA3
+0001902680000313006C90C76C5AB3A491B6FCA391C71201B3A6486D497EB648B512FEA3
+37397DB83E>I<B612C0A3C6EBC0006D5AB3B3AD497EB612C0A31A397EB81E>I<013FB512
+E0A39039001FFC00EC07F8B3B3A3123FEA7F80EAFFC0A44A5A1380D87F005B0070131F6C
+5C6C495A6C49C7FC380781FC3801FFF038007F80233B7DB82B>I<B649B5FCA300010180
+9038007FF06C90C8EA3F80053EC7FC173C17385F5F4C5A4C5A4CC8FC160E5E5E5E5E4B5A
+ED0780030EC9FC5D153E157E15FF5C4A7F4A6C7E140E4A6C7E4A6C7E14704A6C7E4A6C7E
+14804A6C7E6F7EA26F7F707EA2707E707EA2707EA2707E707EA2707E707F8484486D497F
+B6011FEBFF80A339397DB841>I<B612E0A3000101C0C8FC6C90C9FCB3AD1718A5173817
+30A31770A317F0A216011603160FEE1FE0486D13FFB8FCA32D397DB834>I<B5933807FF
+F86E5DA20001F0FC002600DFC0ED1BF8A2D9CFE01533A3D9C7F01563A3D9C3F815C3A2D9
+C1FCEC0183A3D9C0FEEC0303A2027F1406A36E6C130CA36E6C1318A26E6C1330A36E6C13
+60A26E6C13C0A3913901FC0180A3913900FE0300A2ED7F06A3ED3F8CA2ED1FD8A3ED0FF0
+A3486C6D5A487ED80FFC6D48497EB500C00203B512F8A2ED018045397DB84C>I<B59138
+07FFFE8080C69238007FE06EEC1F80D9DFF0EC0F001706EBCFF8EBC7FCA2EBC3FEEBC1FF
+A201C07F6E7EA26E7E6E7E81140F6E7E8114036E7E168080ED7FC016E0153FED1FF0ED0F
+F8A2ED07FCED03FEA2ED01FF6F1386A2EE7FC6EE3FE6A2EE1FF6EE0FFEA216071603A216
+011600A2177E486C153E487ED80FFC151EB500C0140EA2170637397DB83E>I<EC03FF02
+1F13E09138FE01FC903901F8007ED907E0EB1F8049486D7ED93F80EB07F049C76C7E01FE
+6E7E48486E7E49157E0003167F4848ED3F80A24848ED1FC0A2001F17E049150F003F17F0
+A3007F17F8491507A300FF17FCAC007F17F86D150FA3003F17F0A26C6CED1FE0A36C6CED
+3FC0000717806D157F000317006C6C15FEA26C6C4A5A017F4A5A6D6C495A6D6C495AD907
+E0EB1F80D903F8017FC7FC903900FE01FC91381FFFE0020390C8FC363D7BBA41>I<B712
+C016FC16FF0001D9800013C06C90C7EA1FE0707EEE03F883707EA2707EA21880A71800A2
+4C5AA24C5A5FEE0FF04C5AEEFF8091B548C7FC16F091CAFCB3A5487FB6FCA331397EB838
+>I<EC03FF021F13E09138FE01FC903901F8007ED907E0EB1F8049486D7ED93F80EB07F0
+49C76C7E01FE6E7E48486E7EA24848157F0007178049153F000F17C049151F001F17E0A2
+4848ED0FF0A3007F17F8A2491507A200FF17FCAC007F17F8A26D150FA2003F17F0A26C6C
+ED1FE0A36C6CED3FC00007027C14804AB4FC3C03F80383807F003B01FC0701C0FEEC0E00
+2600FE0CEBE1FC017FEC63F8D93F8CEB77F0D91FCCEB3FE0D907EE14806DB449C7FC0100
+D981FC130CEC1FFF0203131C91C7001E131C161F183CEF807CEFC0F8EE0FFFA318F08218
+E07013C07013809338007E00364B7BBA41>I<B612FEEDFFE016F8000190388007FE6C90
+C76C7EEE3FC0707E707E707EA2707EA283A65FA24C5AA24C5A4C5AEE3F8004FFC8FCED07
+FC91B512E05E9138000FF0ED03F8ED00FE82707E707EA2161F83A583A6F00180A217F816
+0F1803486D01071400B66D6C5A04011306933800FE0ECAEA3FFCEF07F0393B7DB83D>I<
+D90FF813C090383FFE0190B512813903F807E33907E000F74848137F4848133F48C7121F
+003E140F007E1407A2007C140312FC1501A36C1400A37E6D14006C7E7F13F86CB47E6C13
+F8ECFF806C14E06C14F86C14FEC680013F1480010714C0EB007F020713E0EC007FED3FF0
+151F150FED07F8A200C01403A21501A37EA216F07E15036C15E06C14076C15C06C140F6D
+EB1F80D8FBF0EB3F00D8F0FE13FE39E03FFFF8010F13E0D8C00190C7FC253D7CBA2E>I<
+003FB812E0A3D9C003EB001F273E0001FE130348EE01F00078160000701770A300601730
+A400E01738481718A4C71600B3B0913807FF80011FB612E0A335397DB83C>I<B6903807
+FFFEA3000101809038007FE06C90C8EA1F80EF0F001706B3B2170E6D150C80171C133F17
+186D6C14385F6D6C14F06D6C5C6D6C495A6D6CEB07806D6C49C7FC91387F807E91381FFF
+F8020713E09138007F80373B7DB83E>I<B500FC91387FFF80A30003018091380FFC006C
+90C8EA07E0715A6C705A6E1403017F93C7FCA280013F1506A26E140E011F150C80010F5D
+A28001075DA26E147001031560A26D6C5CA2806D4A5AA2ED8003027F91C8FCA291383FC0
+06A215E0021F5BA2EDF01C020F1318A26E6C5AA215FC02035BA2EDFEE002015BA26E6C5A
+A36FC9FCA3153EA2151CA3393B7EB83E>I<B5D8FC07B5D8F001B5FCA30007902780001F
+FEC7EA1FF86C48C7D80FF8EC07E000010307ED03C01B807F6C6F6C1500A26E5F017F6E6C
+1406A280013F4A6C5CA280011F4A6D5BEE067FA26D6C010E6D5BEE0C3FA26D6C011C6D5B
+EE181FA26D6C6F5BEE300FA26D6C6F485AEE6007A26D6C4CC7FC9338C003FCA203805D91
+3B7F818001FE06A203C1150EDA3FC3C7EAFF0CA203E3151CDA1FE6EC7F98A215F6DA0FFC
+EC3FF0A302075E4B141FA202035E4B140FA202015E4B1407A2020093C8FC4B80503B7EB8
+55>I<B500FE91383FFFE0A3000301E0913807FE00C649EC03F0017F6F5A606D6C5D6D6C
+140395C7FC6D6C1406A26D6C5C6D6C141C17186D6C143817306D6D5B6E6C13E05F91383F
+E0015F91381FF003DA0FF890C8FC1606913807FC0E160C913803FE1C913801FF185E6E13
+B016E0157F6F5AB3A24B7E023FB512C0A33B397FB83E>89 D<003FB7FCA39039FC0001FE
+01C0130349495A003EC7FC003C4A5A5E0038141F00784A5A12704B5A5E006014FF4A90C7
+FCA24A5A5DC712074A5AA24A5A5D143F4A5AA24A5A92C8FC5B495AA2495A5C130F4948EB
+0180A2495A5C137F495A16034890C7FC5B1203485AEE0700485A495C001F5D48485C5E48
+48495A49130FB8FCA329397BB833>I<EAFFFCA2EAFC00B3B3B3B3A7EAFFFCA20E5379BD
+17>I<EAFFFCA21200B3B3B3B3A712FFA20E537FBD17>93 D<007FB81280B912C0A26C17
+803204797041>95 D<EB1FE0EBFFFC3803E03F3907000F80390F8007E0486C6C7E13E06E
+7EA26E7E6C5A6C5AC8FCA4147FEB07FFEB3FE0EBFE00EA03F8EA0FF0EA1FC0123F485A90
+C7FC160C12FEA31401A26C13036CEB077C903980063E18383FC01E3A0FE0781FF03A03FF
+F00FE03A007F8007C026277DA52A>97 D<EA03F012FFA3120F1203B0EC1FE0EC7FF89038
+F1E03E9039F3801F809039F7000FC001FEEB07E049EB03F049EB01F85BED00FCA216FEA2
+167E167FAA167E16FEA216FC15016D14F8ED03F07F01EEEB07E001C6EB0FC09039C7801F
+00903881E07E903800FFF8C7EA1FC0283B7EB92E>I<EB03FC90381FFF8090387E03E039
+01F80070484813F83907E001FC380FC003A2EA1F80123F90380001F848EB00F01500A212
+7E12FEAA127E127FA26C14067F001F140E6D130C000F141C6C6C13386C6C13706C6C13E0
+39007C07C090381FFF00EB07F81F277DA525>I<ED0FC0EC03FFA3EC003F150FB0EB03F8
+EB1FFF90387E078F9038F801EF3903F0007F4848133F4848131FA24848130F123F90C7FC
+5AA2127E12FEAA127E127FA27EA26C6C131FA26C6C133F6C6C137F6C6CEBEFF03A01F801
+CFFF39007C078F90381FFE0FD907F813C0283B7DB92E>I<EB07F8EB1FFF90387C0FC039
+01F803E03903F001F0D807E013F8380FC0004848137CA248C7127E153E5A153F127E12FE
+A3B7FCA248C8FCA5127EA2127FA26C14037F001F14076C6C13060007140E6D131CD801F0
+13386C6C137090387E03E090381FFF80903803FC0020277EA525>I<147E903803FF8090
+380FC1E0EB1F8790383F0FF0137EA213FCA23901F803C091C7FCADB512FCA3D801F8C7FC
+B3AB487E387FFFF8A31C3B7FBA19>I<ED03F090390FF00FF890393FFC3C3C9039F81F70
+7C3901F00FE03903E007C03A07C003E010000FECF000A248486C7EA86C6C485AA200075C
+6C6C485A6D485A6D48C7FC38073FFC38060FF0000EC9FCA4120FA213C06CB512C015F86C
+14FE6CECFF804815C03A0F80007FE048C7EA0FF0003E140348140116F8481400A56C1401
+007C15F06CEC03E0003F1407D80F80EB0F80D807E0EB3F003901FC01FC39007FFFF00107
+90C7FC26387EA52A>I<EA03F012FFA3120F1203B0EC0FF0EC3FFCECF03F9039F1C01F80
+9039F3800FC0EBF70013FE496D7EA25BA35BB3A3486C497EB500C1B51280A3293A7EB92E
+>I<EA0380EA0FE0487EA56C5AEA0380C8FCAAEA03F012FFA312071203B3AA487EB512C0
+A312387EB717>I<EB01C0EB07F0EB0FF8A5EB07F0EB01C090C7FCAAEB01F813FFA31307
+1301B3B3A2123C127E00FF13F01303A214E038FE07C0127C383C0F00EA0FFEEA03F81549
+84B719>I<EA03F012FFA3120F1203B1913801FFFCA39138007FC01600157C15705D4A5A
+4A5A4AC7FC141E1438147814FC13F1EBF3FEEBF73F01FE7FEBF81F496C7E8114076E7E6E
+7E811400157E157F811680ED1FC0486CEB3FF0B500C0B5FCA3283A7EB92C>I<EA03F012
+FFA3120F1203B3B3AD487EB512C0A3123A7EB917>I<2703F00FF0EB1FE000FFD93FFCEB
+7FF8913AF03F01E07E903BF1C01F83803F3D0FF3800FC7001F802603F70013CE01FE14DC
+49D907F8EB0FC0A2495CA3495CB3A3486C496CEB1FE0B500C1B50083B5FCA340257EA445
+>I<3903F00FF000FFEB3FFCECF03F9039F1C01F803A0FF3800FC03803F70013FE496D7E
+A25BA35BB3A3486C497EB500C1B51280A329257EA42E>I<EB03FE90380FFF8090383E03
+E09038F800F84848137C48487F48487F4848EB0F80001F15C090C712074815E0A2007EEC
+03F0A400FE15F8A9007E15F0A2007F14076C15E0A26C6CEB0FC0000F15806D131F6C6CEB
+3F006C6C137EC66C13F890387E03F090381FFFC0D903FEC7FC25277EA52A>I<3903F01F
+E000FFEB7FF89038F1E07E9039F3801F803A07F7000FC0D803FEEB07E049EB03F04914F8
+49130116FC150016FEA3167FAA16FEA3ED01FCA26DEB03F816F06D13076DEB0FE001F614
+C09039F7803F009038F1E07E9038F0FFF8EC1FC091C8FCAB487EB512C0A328357EA42E>
+I<D903F813C090381FFE0190387E07819038FC01C33903F000E300071477484813374913
+3F001F141F485A150F48C7FCA312FEAA127FA37E6D131F121F6D133F120F6C6C137F6C6C
+13EF3901F801CF39007E078F90381FFE0FEB07F890C7FCABED1FE00203B5FCA328357DA4
+2C>I<3807E01F00FFEB7FC09038E1E3E09038E387F0380FE707EA03E613EE9038EC03E0
+9038FC0080491300A45BB3A2487EB512F0A31C257EA421>I<EBFF03000313E7380F80FF
+381E003F487F487F00707F12F0A2807EA27EB490C7FCEA7FE013FF6C13E06C13F86C7F00
+037FC67F01071380EB007F141F00C0EB0FC01407A26C1303A37E15806C13077EEC0F00B4
+131E38F3C07C38E1FFF038C03F801A277DA521>I<1318A51338A31378A313F812011203
+1207001FB5FCB6FCA2D801F8C7FCB215C0A93800FC011580EB7C03017E13006D5AEB0FFE
+EB01F81A347FB220>I<D803F0EB07E000FFEB01FFA3000FEB001F00031407B3A4150FA3
+151F12016D133F0000EC77F86D9038E7FF8090383F03C790381FFF87903A03FC07E00029
+267EA42E>I<B538803FFEA33A0FF8000FF06C48EB07E00003EC03C06D148000011500A2
+6C6C1306A26D130E017E130CA26D5BA2EC8038011F1330A26D6C5AA214E001075BA29038
+03F180A3D901FBC7FCA214FF6D5AA2147CA31438A227257EA32C>I<B53A1FFFE03FFEA3
+260FF8009038000FF86C48017EEB03E018C00003023EEB0180A26C6C013FEB0300A36C6C
+EC8006156FA2017E9038EFC00C15C7171CD93F01EBE01815830281EBF038D91F83143015
+0102C3EBF87090260FC6001360A2D907E66D5A02EC137CA2D903FCEB7F804A133FA20101
+92C7FC4A7FA20100141E4A130E0260130C37257EA33C>I<B538807FFFA33A03FE003FF0
+0001EC1F80000092C7FC017E131C6D13186D6C5AECC070010F5B6D6C5AECF180EB03FB6D
+B4C8FC6D5AA2147F804A7E8114CF903801C7E090380383F090380703F8EB0601496C7E01
+1C137E49137F01787F496D7E486C80000FEC3FF0D8FFFE90B51280A329247FA32C>I<B5
+38803FFEA33A0FF8000FF06C48EB07C00003EC03806C7E16007F00001406A2017E5BA213
+7F6D5BA26D6C5AA2ECC070010F1360A26D6C5AA214F101035BA2D901FBC7FCA214FF6D5A
+A2147CA31438A21430A214701460A25CA2EA7C0100FE5B130391C8FC1306EAFC0EEA701C
+6C5AEA1FF0EA0FC027357EA32C>I<003FB512FCA2EB8003D83E0013F8003CEB07F00038
+EB0FE012300070EB1FC0EC3F800060137F150014FE495AA2C6485A495AA2495A495A495A
+A290387F000613FEA2485A485A0007140E5B4848130C4848131CA24848133C48C7127C48
+EB03FC90B5FCA21F247EA325>I<EC01F8140FEC3F80ECFC00495A495A495AA2130F5CB3
+A7131F5C133F49C7FC13FEEA03F8EA7FE048C8FCEA7FE0EA03F8EA00FE137F6D7E131F80
+130FB3A7801307A26D7E6D7E6D7EEC3F80EC0FF814011D537ABD2A>I<126012F0B3B3B3
+B3A91260045377BD17>I<12FCEAFFC0EA07F0EA01FCEA007E7F80131F80130FB3A78013
+07806D7E6D7EEB007EEC1FF0EC07F8EC1FF0EC7E00495A495A495A5C130F5CB3A7131F5C
+133F91C7FC137E485AEA07F0EAFFC000FCC8FC1D537ABD2A>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fi ecbx1440 14.4 34
+/Fi 34 118 df<EE7FFC031FB57E4AB612E0020715F8023F9038C00FFC913AFFFC0001FE
+4901F0EB007F010701C0EB03FF4949497F4990C75A5B5C495A4D7F01FF6F5B5CA27190C7
+FC715AEF00F895C8FCAA0407B512C0BAFCA5C601F8C7120F83B3B3A6B6D8F807B612C0A5
+42547DD349>28 D<B712E0AB230B7F9F2C>45 D<151E153E15FE1403140F147FEB07FF00
+03B5FCB6FCA3EBF87FEAFC00C7FCB3B3B3A6007FB712FCA52E4E76CD42>49
+D<EC1FFE49B512F0010F14FC013FECFF804915E02701FF803F7F2703FC000713FCD807F0
+01017F48486D7FD81F806E138048C87E7013C0D87FE016E001F8806D16F000FF817F7013
+F8A56C5AA26C5A6C5AEA0380C914F05EA218E05E18C05E18804C13005F4C5A4C5A5F4B5B
+4B5B4B5B94C7FCED0FFC4B5A4B5AED7FC04B5A4A90C8FCEC03FC4A5A4A4814F84A5A4A5A
+4AC8FC02FEEC01F0495A495A495A5CD90F80140349C8FC013E1507017FB7FC90B812E05A
+5A5A5A5A5A5AB9FC18C0A4354E7ACD42>I<913807FFC0027F13FC0103B67E010F15E090
+261FF80313F890267FC0007F01FEC7EA3FFE48488148486E138013FE486C6C6D13C08048
+17E080A66C5B18C06C5B6C90C75AD80038168090C8FC4C1300A24C5A5F4C5A4B5B4B13C0
+030F5BDB7FFEC7FC91387FFFF816C016FCEEFF80DA000313E09238007FF8EE3FFE707E70
+138018C07013E018F07013F8A218FC82A218FEA3EA03C0EA0FF0EA3FFC487EA2B5FCA218
+FCA25E18F8A26C4816F0495C4916E0D83FE04A13C06C485CD80FF04A1380D807FE91387F
+FE003B03FFE003FFFC6C90B65A6C6C15E0010F92C7FC010114FCD9001F1380374F7BCD42
+>I<17FC1601A216031607160FA2161F163F167FA216FF5D5DA25D5D5D167F153E157E15
+FC15F8EC01F01403EC07E015C0EC0F80141FEC3F00143E5C14FC495A5C495A1307495A5C
+49C7FC5B137E137C5B1201485A5B485A120F485A90C8FC123E127E5ABA1280A5C901FCC7
+FCAF021FB71280A5394F7CCE42>I<486C150601F0153E01FEEC01FED9FFF0133F91B65A
+5F5F5F5F5F94C7FC16FC5E16E093C8FC15FC01F0138091CAFCAC913807FF80023F13F891
+B512FE01F36E7E9026FFFC0113E09139E0007FF891C76C7E496E7E01F86E7E5B70138049
+16C0C9FC18E08218F0A418F8A31203EA0FE0EA3FF8487EA212FF7FA218F0A25B5E6C4816
+E05B01C016C06CC85A18806C6C4A13007FD80FF04A5A6C6CECFFFCD803FE4913F02701FF
+E00F5B6C6CB612806D92C7FC010F14F8010114C09026003FFCC8FC354F7ACD42>I<EA07
+E0EA1FF8EA3FFCEA7FFEA2B5FCA6EA7FFEA2EA3FFCEA1FF8EA07E0C7FCB3A3EA07E0EA1F
+F8EA3FFCEA7FFEA2B5FCA6EA7FFEA2EA3FFCEA1FF8EA07E0103576B425>58
+D<932603FFF01407047F01FF5C0307B600E05B033F03F85B92B700FE5B02039126C003FF
+5B020F01F8C7EA3FC1023F01C0EC0FE391B5C80003B5FC4901FC814949814901E082011F
+498249498292CA7E4948834948835A4A83485B4885A2484984A2485B87A2485B87A25AA2
+98C8FC91CFFCA2B5FCAE7E067FB7128080A37E95C76C90C7FC807EA36C7FA26C7FA26C7F
+7E806C7F137F6D7E816D6D93B5FC01077F6D01F85D6D7F6D01FF5D023F01E0EC0FEF020F
+01FCEC3FE30203903AFFE001FF81020091B6C6FC033F03FC133F030703F0130FDB007F02
+801303040301F8CAFC595479D267>71 D<B81280A5D8000701F0C7FCB3B3B3B2B81280A5
+29527DD130>73 D<B812E0A5D8000F01E0CAFCB3B3A91AF8A419011AF0A51903A31907A2
+190F1AE0191FA2193F197F19FF60180760187F0503B5FCBB12C0A545527CD14F>76
+D<B600F84BB612FC818181A2D800076E91C7383FE00070EE0F80828214DF02CF7F02C77F
+8202C37F14C102C0806F7F836F7F816F7F6F7F83816F7F6F80707F8482707F707F707F84
+82707F7080717F8583717F717F85717F83717F7114801AC07213E0847213F07213F81AFC
+7213FE847213FF72148F1BCF7313EF857313FF85A285858585A286868686A286868686EB
+1FF0B600FE177F1B3F1B1F1B0FA25E527CD167>78 D<B912FCF0FFE019FE737E1AE0D800
+0F01E0C7003F7F060313FC06007F737E7313807313C07313E0851BF0A21BF885A21BFCA9
+1BF8A3611BF0A21BE04F13C0614F13804F13004F5A060713F8063F5B92B812C097C7FC19
+F8198003E0CBFCB3AEB712FEA54E527CD15A>80 D<93381FFF800303B512FC033FECFFC0
+92B712F00207D9F80113FE021F903AC0003FFF804A48C700077FDAFFF8020113F049496E
+7F49496F7E49496F7E49496F7E4990C96C7F4948707F4948707F01FF854849707F4A8248
+86A24849717E48864A83A2481B80A248497113C0A4481BE0A291CB7EA3B51AF0AF6C1BE0
+A36E5FA26C1BC0A36C1B806E5FA26C1B006E5F6C62A26C6DD903FC4A5A6CDB0FFF5D6E49
+EBC0016C4B01E05C6D6C90277E07F0035B6E9039F801F807902A3FFF01F000780F5B6D04
+7C5C6DD981E06D4890C7FC6D01E191381F7FFE010101F1EDFFF86DD9F9F06D5BDA3FFF16
+C06E6D013F5B02079027FE01FFFEC8FC020190B612F8DA003F4B141003071838DB001FEB
+83F893C7EA03FC1C7885726C14F8F2C003F2F01F97B512F084A31CE085A27314C01C8085
+1C00735B735B735B735B9638003FC0556A79D263>I<B912E018FF19F019FE737ED80007
+01F0C714E0060F7F060313FC06007F737E737F8587737FA28785A287A863A26163636163
+4F90C8FC4F5A4F5A06035B060F13E095B5128092B748C9FC19F019C019F09226F0000713
+FC050013FF063F7F727F727F727F727FA2727FA28486A886A71D707513F8A2851C017301
+C013F0A273EBE003B86C6D9038F007E0739038FC1FC0070190B51280736C1400080F5BCE
+13F85D537CD162>I<DA0FFE141C91B500F0133C010702FC137C011F02FF13FC017F15C1
+9026FFF00113E148903980001FFB4890C7EA07FFD807FC14014848804848153F171F4848
+150FA2007F1607491503A2170112FFA217007FA26D167CA27F7F6D93C7FC6C7E14C014F8
+ECFF806C14F8EDFFC06C15FC6CEDFF8017F06C16FC6C826C707E6C836D82011F82010782
+13016D6C81020781EC007F030380ED003F040314801600173F837113C0838312F883A383
+7EA319807EA26C5E19007F6D4B5A7F6D4B5A01FC4B5A6D151FD9FFC04A5AD97FF8ECFFE0
+28FE1FFF80075B010790B6C7FCD8FC0115FC486C6C14F048010F14C0489026007FFCC8FC
+3A5479D249>I<003FBB12FCA59126C0007FEB000301FCC7ED003FD87FF0F00FFE491807
+49180349180190C81600A2007E1A7EA3007C1A3EA500FC1A3F481A1FA6C91700B3B3AC49
+B912C0A550517BD05B>I<EC3FFE0107B512E0011F14FC017F14FF2701FFC00F13C02703
+FE00037F486C01007F6E6D7E486D80707EA2707EA3707F6C5B6C90C7FC6C5AC9FCA60307
+B5FC0203B6FC147F0103B7FC011FEBF00F017F1300EBFFFC000313F04813C0485B4890C7
+FC5A5B485AF081F012FF5BA35EA26D5C127F6D5C003F03F713C36DD901E314E06CD9C007
+14FF00079026F01F8114C06C90B5C61480C602FC6D1300011F01F0EB3FFC01010180EB07
+F03C387CB642>97 D<913803FFE0023F13FE91B67E010315E0010F9038003FF8D93FFCEB
+07FC4948497E4948131F4849497E485B485BA24890C7FC5A5B003F6F5A705A705A007F92
+C8FC5BA312FFAD127F7FA3123F7F6CEE0F80A26C6D141F18006C6D5C6C6D143E6C6D147E
+6C6D5C6D6C495A6DB4EB07F0010F9038C01FE06D90B5128001014AC7FCD9003F13F80203
+138031387CB63A>99 D<943803FF80040FB5FCA5EE003F170FB3A4913803FF80023F13F8
+49B512FE0107ECFF8F011F9038C03FEF90273FFE0007B5FCD97FF8130149487F48498048
+4980484980488291C8FC5A5B123FA2127F5BA312FFAD127FA37F123FA3121F7F6C5E6C6D
+5C5F6C6D91B5FC6C6D5B6C6D4914E0D97FFCD90FEFEBFF80D91FFFEB7F8F010790B5120F
+010114FC6D6C13E00207010049C7FC41547CD249>I<913807FF80027F13F849B512FE01
+076E7E011F010313E0903A3FFC007FF0D97FF06D7E49486D7E4849130F48496D7E488248
+90C77E1880485A82003F17C0A3485A18E082A212FFA290B8FCA401FCCAFCA6127FA37F12
+3FA2EF03E06C7E17076C17C06C6D140F18806C6D141F6C6DEC3F006C6D147ED97FFC495A
+D91FFFEB07F86D9038E03FF0010390B512C001005D023F01FCC7FC020113E033387CB63C
+>I<ED1FF8913803FFFE020FEBFF80023F14C09139FFF83FE001039038E0FFF049138049
+010113F85BEB3FFEA2EB7FFCA26F13F0495AEE7FE0EE1F8093C7FCAEB712C0A5C601F8C8
+FCB3B3A7B612FEA52D547CD328>I<DA1FFE14FE49B539E007FF80010FDAFC1F13C0013F
+DAFF7F13E090267FF807EBFF072701FFE001EBF07F48497E484990387FF83F91C7003F14
+C048EEFC1F489338FE070049021F90C7FCA2003F82A9001F5EA26D143F6C5E6C5E6E137F
+6C6D495A6C6D485B6CD9F80713804890B6C8FCD803EF14FC01C114E02707C01FFEC9FC49
+CBFCA2487EA37FA27F13FC90B612FE6CEDFFF017FCEFFF806C8318F06C836C837F48B87E
+1207D80FFCC700037F4848EC003F4848150F48486F138083485A83A56D5D007F18006D5D
+003F5F6C6C4B5A01FE153FD807FFED7FF06C01C049485AC601FC011F1380013FB648C7FC
+010F15F8010115C0D9000F01F8C8FC3B4F7CB542>I<EB3FF8B5FCA51203C6FCB3A4EE1F
+FC93B57E030314E0030F14F892391FC07FFC92397E003FFE03F86D7EECF9F04B6D7FECFB
+C0ECFF8092C76C7FA25CA25CA45CB3ACB6D8F807B612C0A542537CD249>I<133FEBFFC0
+487F487FA2487FA66C5BA26C5B6C5B013FC7FC90C8FCAEEB1FF8B5FCA512017EB3B3A6B6
+12F0A51C547CD324>I<EB3FF8B5FCA51203C6FCB3B3B3B1B612F8A51D537CD224>108
+D<D93FF0D91FF84AB47EB591B56C010F13F8030302E0013F13FE030F6E90B6FCDB3F8090
+27F803F80F7F922A7E007FFC07E0077F000302F890283FFE0F80037FC6D9F1F0011F4948
+7EDAF3E0DAFF3E814B153CDAF7805D92C76C496D7F14FF4A5EA24A5EA34A5EB3ADB6D8F8
+0FB66CB612F8A565367BB56E>I<D93FF0EB1FFCB591B57E030314E0030F14F892391FC0
+7FFC92397E003FFE000302F86D7EC6EBF1F04B6D7FECF3C0ECF78092C76C7F14FF5CA25C
+A45CB3ACB6D8F807B612C0A542367CB549>I<913801FFC0023F13FE91B67E010315E001
+0F018013F8903A3FFC001FFED97FF0EB07FF49486D7F48496D7F48496D7F91C8127F4883
+488349153F001F83A2003F8349151FA2007F83A400FF1880AC007F1800A3003F5F6D153F
+A2001F5FA26C6C4B5AA26C6D4A5A6C5F6C6D495B6C6D495B6D6C4990C7FCD93FFCEB1FFE
+6DB46CB45A010790B512F0010115C0D9003F49C8FC020313E039387CB642>I<D93FF8EB
+7FF0B50107B5FC031F14C0037F14F09126F9FF0013FCDAFFF8EB3FFF000302E0010F7FC6
+02806D7F92C76C7F4A824A804A6E7F85187F85A2183F85A4721380AD4E1300A44E5AA261
+18FF616E5C616E4A5B6E4A5B6F495B03E04990C7FC6FEB7FFE913AF9FE01FFF802F8B65A
+033F14C0030749C8FC030013E093CAFCB1B612F8A5414D7DB549>I<90393FF001FCB590
+380FFF804B13E0037F13F09238FE1FF89138F1F83F00019138F07FFC6CEBF3E015C0ECF7
+80A2ECFF00EE3FF84AEB1FF0EE0FE093C7FC5CA45CB3ABB612FEA52E367DB535>114
+D<903903FFC00E011FEBFC1E90B6127E000315FE3907FE003FD80FF0130F484813034848
+1301491300127F90C8127EA248153EA27FA27F01F091C7FC13FCEBFF806C13FEECFFF06C
+14FE6F7E6C15E06C816C15FC6C81C681133F010F15801301D9000F14C0EC003F030713E0
+150100F880167F6C153FA2161F7EA217C07E6D143F17807F6DEC7F0001F85C6DEB03FE90
+39FF801FFC486CB512F0D8F81F14C0D8F00791C7FC39E0007FF02B387CB634>I<147CA6
+14FCA41301A31303A21307A2130F131F133F137F13FF1203000F90B512FEB7FCA426007F
+FCC8FCB3A9EE0F80ABEE1F006D7EA2011F143E806D6D5A6DEBC1F86DEBFFF001005C023F
+1380DA03FEC7FC294D7ECB33>I<D93FF8913801FFC0B50207B5FCA50003ED001FC61607
+B3AE5FA35FA25F137F5F6D6C14F7DC01E713F06D6CD907C7EBFFC0903A0FFF801F876D90
+B51207010114FC6D6C13F0020701C091C7FC42377CB549>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fj ecrm0900 9 5
+/Fj 5 109 df<123C127E12FFA4127E123C08087A8715>46 D<EB7F803803FFF0380F80
+FC381C003E003F133F6D6C7E6E7EA26E7EEA1F00C7FCA4EB01FF131FEBFF873803FC07EA
+0FF0EA1FC0EA3F80127F13004815C05AA3140FA26C131F6C133B3A3F8071F180391FC1E1
+FF2607FFC013003900FE003C22237DA126>97 D<EA03F012FFA312071203AEEC3F80ECFF
+E09038F3C0F89038F7007E01FE7F49EB1F8049EB0FC05BED07E016F0A2150316F8AA16F0
+150716E0A2ED0FC07F6DEB1F8001ECEB3F0001CF137C90388381F8903801FFE0C76CC7FC
+25357EB32B>I<EA03F012FFA312071203AEEC1FC0EC7FF09038F1E0FC9038F3807C9038
+F7007E13FE497FA25BA25BB3486CEB7F80B538C7FFFCA326347EB32B>104
+D<EA07E012FFA3120F1207B3B3A7EA0FF0B5FCA310347EB315>108
+D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fk ecbx0900 9 7
+/Fk 7 117 df<ED1F80A24B7EA24B7EA34B7EA24A7FA34A7FA24A7F15CFA2020F7F1587
+021F801503023F80EC3E01A2027E80EC7C0002FC804A137FA20101814A133F0103814A13
+1FA249B67EA24981A290271F8000077F91C77EA24982013E80017E82017C80A201FC8249
+157FB500F0013FB512F0A43C347DB343>65 D<EB7FFE0003B512E04814F8390FF00FFC39
+1FF803FF806E138016C0157F6C5A6C5AEA0180C8FCEC7FFF010FB5FC90B6FC0003EBF07F
+000F1300EA1FF8485A485A485A5BA315FF7F007F5B6D4813E03A3FF80FBFFF000FB5121F
+0003EBFC0F39007FE00728217EA02B>97 D<EA01FC12FFA4120F1207ADEC0FF8EC7FFF01
+FDB512C09039FFF01FF09138800FF84A6C7E496D7E496D7EA2178081A217C0A91780A25D
+1700A26D495A6D495A6E485A9039F7E03FF001E1B512C0D9C07F90C7FC9038801FF02A34
+7DB331>I<903807FF80013F13F090B512FC3903FE01FE4848487EEA0FF8EA1FF0EA3FE0
+A2007F6D5A496C5A153000FF91C7FCA9127F7FA2003FEC07807F6C6C130F000FEC1F00D8
+07FE133E3903FF80FCC6EBFFF8013F13E0010790C7FC21217DA027>I<3901F81F8000FF
+EB7FF0ECFFF89038F9E3FC9038FBC7FE380FFF876C1307A213FEEC03FCEC01F8EC006049
+1300B1B512F0A41F217EA024>114 D<9038FFE1C0000713FF5A383F803F387E000F1407
+5A14037EA26C6CC7FC13FCEBFFE06C13FC806CEBFF80000F14C06C14E0C6FC010F13F0EB
+007F140F00F0130714037EA26C14E06C13076CEB0FC09038C01F8090B5120000F913FC38
+E03FE01C217DA023>I<133CA5137CA313FCA21201A212031207001FB51280B6FCA3D807
+FCC7FCB0EC03C0A79038FE078012033901FF0F006C13FEEB3FFCEB0FF01A2F7EAE22>I
+E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fl ecrm1200 12 25
+/Fl 25 122 df<121EEA7F8012FF13C0A213E0A3127FEA1E601200A413E013C0A3120113
+80120313005A1206120E5A5A5A12600B1D78891B>44 D<14FF010713E090381F81F89038
+3E007C01FC133F4848EB1F8049130F4848EB07C04848EB03E0A2000F15F0491301001F15
+F8A2003F15FCA390C8FC4815FEA54815FFB3A46C15FEA56D1301003F15FCA3001F15F8A2
+6C6CEB03F0A36C6CEB07E0000315C06D130F6C6CEB1F806C6CEB3F00013E137C90381F81
+F8903807FFE0010090C7FC28447CC131>48 D<EB03FE90381FFFC0017F13F03901F80FFC
+3903C001FE48486C7E000EC7EA7F8048EC3FC0ED1FE04815F00030140F007015F8006014
+07126CB415FC7F7F1503A46C4813076CC7FCC8FC16F8A2150F16F0151F16E0A2ED3FC0ED
+7F8016005D5D4A5A4A5A4A5A5D4A5A4A5A4AC7FC147C5C5C495A495A495A49C7120C131E
+5B013814185B5B485A4848143848C81230000E1570001FB612F0A25A5AB712E0A326427B
+C131>50 D<EC07FCEC3FFF91B512C0903903FC03E0903907E000F0D91FC0133849C71258
+017EEB01FC01FE1303491307485A485AA24848EB03F8000FEC01F092C7FC485AA3485AA3
+127FA29038007F80903801FFF090380780FC39FF0E003E49EB1F8049EB0FC049EB07E013
+6001E0EB03F04914F8150116FC5BED00FEA390C812FFA47EA57F123FA216FE121F15016D
+14FC120FED03F86C7EED07F06C6C14E06C6CEB0FC06C6CEB1F80017EEB3F0090383F80FE
+90380FFFF8010313E00100138028447CC131>54 D<16C04B7EA34B7EA34B7EA34B7EA3ED
+19FEA3ED30FFA203707FED607FA203E07FEDC03FA2020180ED801FA2DA03007F160FA202
+06801607A24A6D7EA34A6D7EA34A6D7EA20270810260147FA202E08191B7FCA249820280
+C7121FA249C87F170FA20106821707A2496F7EA3496F7EA3496F7EA201788313F8486C83
+D80FFF03037FB500E0027FEBFFC0A342477DC649>65 D<B8FC17E017FC00019039C00003
+FF6C6C4801007FEF3FC0717E717E717E84170384170184A760A21703601707604D5A4D5A
+EF7FC04DC7FCEE03FEEE3FF091B65A17FC0280C7B47EEF1FC0EF0FF0717E717E717E717E
+1980187F19C0A2183F19E0A8F07FC0A2198018FF4D1300A24D5AEF0FFC4D5AEF7FE04848
+6C903803FFC0B9C7FC17FC17C03B447CC345>I<B712FEEEFFE017F800019039C00007FE
+6C6C48903800FF80EF3FC0EF0FF0717E717EEF00FE8484F03F80F01FC0A2F00FE019F018
+0719F8A2180319FCA3F001FEA419FFAD19FEA3180319FCA319F8180719F0180F19E0A2F0
+1FC0F03F80A2F07F0018FE4D5A4D5AEF0FF0EF3FE0EFFF8048486C010790C7FCB812FC17
+E04CC8FC40447CC34A>68 D<B56C933807FFFC6E5EA20001F1FE0026006FE0EE1BF8A3D9
+67F01633A2D963F81663A3D961FC16C3A3D960FEED0183A2027FED0303A36E6C1406A36E
+6C140CA26E6C1418A36E6C1430A36E6C1460A26E6C14C0A36E6CEB0180A3037FEB0300A2
+92383F8006A36F6C5AA36F6C5AA26F6C5AA36F6C5AA36F6C5AA26FB45AA370C7FC13F0A2
+486C143ED80FFFEF0FFEB500F0011C0107B512FCA34E447BC359>77
+D<003FB912F8A3903BF0001FF8001F01806D481303003EC7150048187C0078183CA20070
+181CA30060180CA5481806A5C81600B3B3A54B7EED7FFE49B77EA33F447DC346>84
+D<B600C0010FB5FCA3000101E0C813F026007F80ED1F80F00F00A21806B3B3A7180E6D6C
+150CA2181C131F6E1518010F163818306D6C1570606D6C14016D6C5D6D6CEC0780027F4A
+C7FC6E6C131EDA1FE0137C913907FC03F00201B55A6E6C1380DB07FCC8FC40467CC349>
+I<EB07FC90383FFF809038F80FE03903C003F048C66C7E000E6D7ED80FC0137E486C137F
+6D6D7EA36F7EA26C5AEA0380C8FCA4EC0FFF49B5FC90380FFE1FEB3FC0EBFF00EA03FC48
+5A485A485A485A127F5B176048C7FCA3153FA36D137F007F14EF6D9038C7E0C0003F1301
+3A1FE00783F13B07F81E03FF802701FFFC0113003A001FE0007C2B2E7CAC31>97
+D<EC7F80903803FFF090380FC07C90383F000F01FCEB03804848EB01C00003140F4848EB
+1FE049133F120F485AA2485AED1FC0007FEC070092C7FCA290C9FC5AAB7E7FA2123F1630
+7F001F15706C6C146016E06C6C14C06C6C13010001EC03806C6CEB0700013F131E90381F
+C078903807FFF001001380242E7DAC2B>99 D<167FED3FFFA315018182B3EC7F80903803
+FFF090380FC07C90383F000E017E1307496D5AD803F87F48487F5B000F81485AA2485AA2
+127FA290C8FC5AAB7E7FA2123FA26C7EA2000F5D7F6C6C5B00035C6C6C9038077F806C6C
+010E13C0013F011C13FE90380FC0F8903803FFE09026007F0013002F467DC436>I<EB01
+FE903807FFC090381F03F090387E00FC49137E48487F485A4848EB1F80000F15C049130F
+121F484814E01507A2007F15F090C7FCA25AA390B6FCA290C9FCA67EA27FA2123F16306C
+7E1670000F15606D14E06C6C14C0000314016C6CEB03806C6CEB0700013E131E90381F80
+F8903803FFE0010090C7FC242E7DAC2B>I<EE0F80D901FCEB7FE0903A0FFF81F0F09039
+3F07E3819039FC01FF033A01F800FE014848017E13E00007027FC7FC497F000F8149131F
+001F81A9000F5D6D133F000792C7FC6D5B0003147E6C6C5B6D485A3903BF07E090380FFF
+80260701FCC8FC90CAFCA25AA37F6C7E7F90B512F86C14FF16E06C15F86C6C8048B67E3A
+07C0000FFF48481300003FC8EA3F80003E151F48ED0FC0A2481507A56C150F007C168000
+7E151F003E16006C153E6C6C5CD807E0495AD801F8EB07E0D8007FEB3F8090261FFFFEC7
+FC010113E02C427DAC31>103 D<EA01E0EA07F8A2487EA46C5AA2EA01E0C8FCADEA01FC
+12FFA3120712031201B3B0487EB512F8A315437DC21C>105 D<EA01FC12FFA312071203
+1201B3B3B3A5487EB512F8A315457DC41C>108 D<3901FC01FE00FF903807FFC091381E
+07F091383801F8000701707F0003EBE0002601FDC07F5C01FF147F91C7FCA25BA35BB3A8
+486CECFF80B5D8F83F13FEA32F2C7DAB36>110 D<EC7F80903803FFF090380FC0FC9038
+3E001F496D7E496D7E48486D7E48486D7E48486D7E000F81A24848147E003F157FA290C8
+7E481680A44816C0AA6C1680A26D147F003F1600A2001F157E6D14FE000F5D6D13010007
+5D6C6C495A6C6C495A6C6C495A013E49C7FC90381FC0FE903807FFF89038007F802A2E7D
+AC31>I<3903F803F000FFEB1FFCEC3C3EEC707F0007EBE0FF3803F9C000015B13FBEC00
+7E153C01FF13005BA45BB3A748B4FCB512FEA3202C7DAB26>114
+D<90383FE0183901FFFC383907E01F78390F0003F8001E1301481300007C1478127800F8
+1438A21518A27EA27E6C6C13006C7E13FC383FFFE06C13FC6C13FF6C14C06C14E0C614F0
+011F13F81300EC0FFC140300C0EB01FE1400157E7E153EA27EA36C143C6C147C15786C14
+F86CEB01F039F38003E039F1F00F8039E07FFE0038C00FF01F2E7DAC26>I<1306A5130E
+A4131EA3133E137EA213FE12011207001FB512F0B6FCA2C648C7FCB3A4150CAA017E131C
+017F1318A26D133890381F8030ECC070903807E0E0903801FFC09038007F001E3E7EBC26
+>I<D801FC147F00FFEC3FFFA300071401000380000181B3A85EA35DA212006D5B017E90
+38077F80017F010E13C06D011C13FE90380FC078903803FFF09026007F8013002F2D7DAB
+36>I<B539F001FFFCA3000790C7EA7FE06C48EC1F8000011600160E1200160C017F5CA2
+80013F5CA26E1370011F146080010F5CA2ECF00101075CA26D6C48C7FCA26E5A01011306
+A26D6C5AA214FF6E5AA215B8EC3FB015F06E5AA36E5AA26E5AA36EC8FC2E2C7EAA33>I<
+B539F001FFFCA3000790C7EA7FE06C48EC1F8000011600160E0000150C6D141C6D1418A2
+6E1338013F1430A26D6C5BA26E13E0010F5CA26D6C485AA2ECF803010391C7FCA2903801
+FC06A2ECFE0E0100130CA2EC7F18A215B8EC3FB0A2EC1FE0A36E5AA26E5AA36EC8FCA214
+06A35CA25CA2123C007E5BB4FC5CA25CEAFE01387C0380D87007C9FCEA3C1EEA0FFCEA03
+F02E3F7EAA33>121 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fm ecbx1200 12 47
+/Fm 47 123 df<0118140C017C143E01FC147E48485C4848495A495C4848495A4848495A
+001F140F90C75B003E4AC7FCA2003C141E007C143E0078143CA200F8147CA2481478D8F1
+F014F8D8F7FCEB7BFEB46CEB7FFF6D1580028014C0A36C80A36C806C496C13806C486D13
+006C486D5AD801F0EB00F82A2283C427>16 D<D807C0EB03E0D81FF0EB0FF8486C497E48
+6C497E486C497E6D1580A3028014C0A36C806C80D81FF7EB0FFBD807C7EB03E3D80007EB
+0003010F1407A291C71380A249140F011E1500013E5CA249143E01FC147E49147C48485C
+4848495A000714034848495A4848495A90C75B000C0206C7FC2A2281C427>I<ED0FFF4A
+B512C0020F14F0027F80903A01FFF803FC499038C000FE010FEB00034948497E49485B5C
+495A4C138001FF6E13005CA3705AEE01F893C8FCA74BB51280B9FCA5C69038E00003B3B0
+007FD9FFC1B6FCA538467EC53E>28 D<EA07C0EA1FF0EA3FF8EA7FFCEAFFFEA7EA7FFCEA
+3FF8EA1FF0EA07C00F0F788E1F>46 D<EC3FF849B5FC010F14E0013F14F890397FF01FFC
+9039FFC007FE4890380001FF48486D1380000716C049147F000F16E049143F001F16F0A2
+003F16F8A249141F007F16FCA600FF16FEB3A3007F16FCA56C6CEC3FF8A3001F16F0A200
+0F16E06D147F000716C06D14FF6C6C4913806C6D4813006C6D485A90397FF01FFC6DB55A
+010F14E0010314809026003FF8C7FC2F427CC038>48 D<EC03C01407141F147FEB03FF13
+3FB6FCA413C3EA0003B3B3ADB712FCA5264177C038>I<ECFFE0010F13FE013F6D7E90B6
+12E0000315F82607FC0313FE3A0FE0007FFFD81F806D138048C7000F13C0488001C015E0
+01F07F00FF6E13F07F17F881A46C5A6C5A6C5AC9FC17F05DA217E05D17C04B13804B1300
+A2ED1FFC4B5A5E4B5A4B5A4A90C7FC4A5A4A5AEC0FF04A5AEC3F804AC7127814FE495A49
+4814F8D907E014F0495A495A49C8FC017C140149140348B7FC4816E05A5A5A5A5AB8FC17
+C0A42D417BC038>I<ECFFF0010713FF011F14C0017F14F049C66C7ED803F8EB3FFED807
+E06D7E81D80FF86D138013FE001F16C07FA66C5A6C4815806C485BC814005D5E4B5A4B5A
+4B5A4A5B020F1380902607FFFEC7FC15F815FF16C090C713F0ED3FFCED0FFEEEFF80816F
+13C017E0A26F13F0A217F8A3EA0FC0EA3FF0487EA2487EA217F0A25D17E06C5A494913C0
+5BD83F80491380D81FF0491300D80FFEEBFFFE6CB612F800015D6C6C14C0011F49C7FC01
+0113E02D427BC038>I<163FA25E5E5D5DA25D5D5D5DA25D92B5FCEC01F7EC03E7140715
+C7EC0F87EC1F07143E147E147C14F8EB01F0EB03E0130714C0EB0F80EB1F00133E5BA25B
+485A485A485A120F5B48C7FC123E5A12FCB91280A5C8000F90C7FCAC027FB61280A53141
+7DC038>I<0007150301E0143F01FFEB07FF91B6FC5E5E5E5E5E16804BC7FC5D15E092C8
+FC01C0C9FCAAEC3FF001C1B5FC01C714C001DF14F09039FFE03FFC9138000FFE01FC6D7E
+01F06D13804915C0497F6C4815E0C8FC6F13F0A317F8A4EA0F80EA3FE0487E12FF7FA317
+F05B5D6C4815E05B007EC74813C0123E003F4A1380D81FC0491300D80FF0495AD807FEEB
+FFFC6CB612F0C65D013F1480010F01FCC7FC010113C02D427BC038>I<4AB47E021F13F0
+027F13FC49B6FC01079038807F8090390FFC001FD93FF014C04948137F4948EBFFE04849
+5A5A1400485A120FA248486D13C0EE7F80EE1E00003F92C7FCA25B127FA2EC07FC91381F
+FF8000FF017F13E091B512F89039F9F01FFC9039FBC007FE9039FF8003FF17804A6C13C0
+5B6F13E0A24915F0A317F85BA4127FA5123FA217F07F121FA2000F4A13E0A26C6C15C06D
+4913806C018014006C6D485A6C9038E01FFC6DB55A011F5C010714C0010191C7FC903800
+3FF02D427BC038>I<121E121F13FC90B712FEA45A17FC17F817F017E017C0A248168000
+7EC8EA3F00007C157E5E00785D15014B5A00F84A5A484A5A5E151FC848C7FC157E5DA24A
+5A14035D14074A5AA2141F5D143FA2147F5D14FFA25BA35B92C8FCA35BA55BAA6D5A6D5A
+6D5A2F447AC238>I<EA07C0EA1FF0EA3FF8EA7FFCEAFFFEA7EA7FFCEA3FF8EA1FF0EA07
+C0C7FCAEEA07C0EA1FF0EA3FF8EA7FFCEAFFFEA7EA7FFCEA3FF8EA1FF0EA07C00F2C78AB
+1F>58 D<1A60F101F01907191FF17FC0953801FF00F007FCF01FF0F07FC04D48C7FCEF07
+FCEF3FF0EFFFC0040390C8FCEE0FFCEE3FE0EEFF80DB03FEC9FCED0FF8ED3FE0EDFF80DA
+07FECAFCEC1FF8EC7FE0903801FF80D907FCCBFCEB1FF0EB7FC04848CCFCEA07FCEA1FF0
+EA7FC048CDFCA2EA7FC0EA1FF0EA07FCEA01FF38007FC0EB1FF0EB07FC903801FF809038
+007FE0EC1FF8EC07FE913800FF80ED3FE0ED0FF8ED03FE923800FF80EE3FE0EE0FFCEE03
+FF040013C0EF3FF0EF07FCEF01FF9438007FC0F01FF0F007FCF001FF9538007FC0F11FF0
+19071901F10060444277B957>60 D<126012F812FE6C7EEA3FE0EA0FF8EA03FEC66C7EEB
+3FE0EB0FF8EB03FE903800FFC0EC3FF0EC0FFCEC03FF9138007FC0ED1FF0ED07FCED01FF
+9238007FC0EE1FF0EE07FE933801FF809338007FE0EF1FF8EF03FE943800FF80F03FE0F0
+0FF8F003FE953800FF80F13FE0F10FF0A2F13FE0F1FF80953803FE00F00FF8F03FE0F0FF
+80DD03FEC7FCEF1FF8EF7FE0933801FF80DC07FEC8FCEE1FF0EE7FC04B48C9FCED07FCED
+1FF0ED7FC0DA03FFCAFCEC0FFCEC3FF0ECFFC0D903FECBFCEB0FF8EB3FE0EBFF80D803FE
+CCFCEA0FF8EA3FE0EAFF8048CDFC12F81260444277B957>62 D<923803FFF0037FEBFF80
+0203B612F0020F15FC913A3FFC000FFFDAFFC0010013C0D903FEC8EA1FF0D907F0ED03F8
+D91FC0ED00FE4948167F017ECAEA1F8049717E4848717E49DAFF8013034848010F01F06D
+7E4848013F01FC6D7E92B6FC4848489026C07F80137C49489026001FC0133C484948D907
+E0133E001E49486D6C131E003E49480101141F023F913800FFE0003C4A82007C017F1880
+007819074A5AA300F81AC04848491603AB6C6C7F12781B801A076E7E127C003C133F003E
+6E1700021F4A5C001E6D6C5B001F6D6C49EBF01E6C6D6C011F143E6D6CD9C07F6D5A6C6C
+6C90B5383FFFF8033FD9FC0F5B6C6C010FD9F0035B6C6C0100903980007F806D91CBFC6C
+7E137E6D7E6D6CEF7FC0D907F0EE03FFD903FE043F1300902600FFC0913803FFF8DA3FFC
+49B512C0020FB748C7FC020316E0DA007F02FCC8FC030349C9FC4A477AC557>64
+D<EE1F80A24C7EA24C7EA34C7EA24B7FA34B7FA24B7FA34B7F169F031F80161F82033F80
+ED3E07037E80157C8203FC804B7E02018115F0820203814B137F0207815D173F020F814B
+7F021F8292C77EA24A82023E80027E82027FB7FCA291B87EA2498302F0C8FCA20103834A
+157F0107834A153FA249488284011F8491C97E4984133E017E82B6020FB612F0A54C457C
+C455>I<B9FC18F018FE727E19E026003FFCC700077F05017F716C7E727E727EA2721380
+A37213C0A74E1380A24E1300A24E5A4E5A4E5A4D5B05075B94B5128091B700FCC7FC18F0
+18FF19E002FCC7000113F8716C7EF01FFE727E7213801AC07213E0A27213F0A31AF8A71A
+F0A2601AE0604E13C0604E138095B5120005075BBA12F86119C04EC7FC18E045447CC350
+>I<DCFFF01470031F01FF14F04AB6EAE0010207EDF803023FEDFE0791B539E001FF0F49
+49C7EA3F9F010701F0EC0FFF4901C0804990C87E4948814948814948167F4849163F4849
+161F5A4A160F485B19074890CAFC19035A5BA2007F1801A34994C7FC12FFAE127F7F1AF0
+A2123FA27F6C18011AE06C7F19036C6D17C06E16077E6C6DEE0F806C6DEE1F006D6C5E6D
+6C167E6D6C6C5D6D6D4A5A6D01F0EC07F0010101FEEC1FE06D903AFFF001FF80023F90B6
+C7FC020715FC020115F0DA001F1480030001F8C8FC44467AC451>I<B9FC18F018FE727E
+19E026003FFEC7001F13F805017F9438003FFF060F7F727F727F727F84737E737EA2737E
+A2737EA21B80A2851BC0A51BE0AD1BC0A51B8061A21B006162193F624F5A19FF624E5B06
+075B4E5B063F90C7FC4DB45A050F13F8BA5A19C04EC8FC18F095C9FC4B447CC356>I<B7
+12E0A5D8001F90C7FCB3B3B3A4B712E0A523447DC32A>73 D<B500FE067FB512806E95B6
+FCA26F5EA2D8003F50C7FC013D6DEE03DFA2013C6DEE079FA26E6CEE0F1FA26E6C161EA2
+6E6C163CA36E6C1678A26E6C16F0A26E6DEC01E0A26E6DEC03C0A36E6DEC0780A26F6CEC
+0F00A26F6C141EA26F6C5CA36F6C5CA26F6C5CA26F6D485AA26F6D485AA26F6D485AA370
+6C48C7FCA293383FF81EA2706C5AA2706C5AA3706C5AA2705BA2705BA2705BA2B6057FB6
+128071C7FCA2173E171C61447CC36A>77 D<923807FFC092B512FE0207ECFFC0021F15F0
+91267FFE0013FC902601FFF0EB1FFF01070180010313C04990C76C7FD91FFC6E6C7E4948
+6F7E49486F7E01FF8348496F7E48496F1380A248496F13C0A24890C96C13E0A24819F049
+82003F19F8A3007F19FC49177FA400FF19FEAD007F19FC6D17FFA3003F19F8A26D5E6C19
+F0A26E5D6C19E0A26C6D4B13C06C19806E5D6C6D4B13006C6D4B5A6D6C4B5A6D6C4B5A6D
+6C4A5B6D01C001075B6D01F0011F5B010101FE90B5C7FC6D90B65A023F15F8020715C002
+004AC8FC030713C047467AC454>79 D<DAFFE0131C010701FE133C013F9038FF807C90B6
+EAE0FC4815F9489038801FFF3907FC00014848EB007F4848143F4848140F491407007F15
+035B1601160012FF177CA27FA26D153C7F7F6D92C7FC6C7EEBFFE014FE6CEBFFF015FF6C
+15E016FC6C816C6F7E6C826C826C6C81011F810107811300020F80140003077FED007F82
+040F1380828212F082A282A27EA218007EA26C5D6C5E6D14036D5D6D140701F84A5A01FF
+EC3FF002F8EBFFE0486CB65AD8FC1F92C7FCD8F80714FC48C614F0480107138031467AC4
+3E>83 D<007FBA12E0BB12F0A46C19E04406776757>95 D<903801FFE0011F13FE017F6D
+7E48B612E03A03FE007FF84848EB1FFC6D6D7E486C6D7EA26F7FA36F7F6C5A6C5AEA00F0
+90C7FCA40203B5FC91B6FC1307013F13F19038FFFC01000313E0481380381FFE00485A5B
+127F5B12FF5BA35DA26D5B6C6C5B4B13F0D83FFE013EEBFFC03A1FFF80FC7F0007EBFFF8
+6CECE01FC66CEB8007D90FFCC9FC322F7DAD36>97 D<EB7FC0B5FCA512037EB1ED0FF892
+B57E02C314E002CF14F89139DFC03FFC9139FF000FFE02FCEB03FF4A6D13804A15C04A6D
+13E05CEF7FF0A218F8173FA318FCAC18F8A2177F18F0A3EFFFE06E15C06E5B6E49138002
+7C491300496C495A903AFC1FC07FFC496CB512F0D9F00314C049C691C7FCC8EA1FF03646
+7DC43E>I<EC3FFC49B512C0010F14F0013F14FC90397FF003FE9039FFC001FF0003495A
+48494813805B120F485AA2485A6F1300007F6E5AED00784991C7FCA212FFAC6C7EA3123F
+6DEC03C0A26C6C1407000F16806D140F6C6DEB1F006C6D133E6C01F05B3A007FFC03F86D
+B55A010F14C0010391C7FC9038003FF82A2F7CAD32>I<EE03FEED07FFA5ED001F160FB1
+EC3FE0903803FFFC010FEBFF8F013F14CF9039FFF807FF48EBC00148903880007F4890C7
+123F4848141F49140F121F485AA3127F5BA212FFAC127FA37F123FA26C6C141FA26C6C14
+3F0007157F6C6C91B5FC6CD9C00314FC6C9038F01FEF6DB5128F011FEBFE0F010713F890
+26007FC0EBF80036467CC43E>I<EC3FF80103B57E010F14E0013F8090397FF83FF89039
+FFC007FC48496C7E48496C7E48486D1380485A001FED7FC05B003FED3FE0A2127F5B17F0
+161F12FFA290B7FCA401F0C9FCA5127FA27FA2123F17F06C7E16016C6C15E06C6C14036C
+6DEB07C06C6DEB0F806C01F0EB3F0090397FFE01FE011FB55A010714F0010114C0902600
+1FFEC7FC2C2F7DAD33>I<EDFF80020F13E0027F13F049B512F849EB8FFC90390FFE0FFE
+90381FFC1F14F8133FEB7FF0A2ED0FFCEBFFE0ED03F0ED00C01600ABB612F8A5C601E0C7
+FCB3B0007FEBFFE0A527467DC522>I<DAFFE0137E010F9039FE03FF80013FEBFF8F90B8
+12C048D9C07F133F489038001FF84848EB0FFC4848903907FE1F80001F9238FF0F00496D
+90C7FCA2003F82A8001F93C7FCA26D5B000F5D6C6C495A6C6C495A6C9038C07FF04890B5
+5A1680D8078F49C8FC018013E0000F90CAFCA47F7F7F90B612C016FC6CEDFF8017E06C82
+6C16FC7E000382000F82D81FF0C77ED83FC014074848020113808248C9FC177FA46D15FF
+007F17006D5C6C6C4A5A6C6C4A5AD80FFEEC3FF83B07FFC001FFF0000190B612C06C6C92
+C7FC010F14F8D9007F90C8FC32427DAC38>I<EB7FC0B5FCA512037EB1ED07FE92383FFF
+8092B512E002C114F89139C7F03FFC9138CF801F9139DF000FFE14DE14FC4A6D7E5CA25C
+A35CB3A7B60083B512FEA537457CC43E>I<137C48B4FC4813804813C0A24813E0A56C13
+C0A26C13806C1300EA007C90C7FCAAEB7FC0EA7FFFA512037EB3AFB6FCA518467CC520>
+I<EB7FC0B5FCA512037EB3B3B3A3B61280A519457CC420>108 D<90277F8007FEEC0FFC
+B590263FFFC090387FFF8092B5D8F001B512E002816E4880913D87F01FFC0FE03FF8913D
+8FC00FFE1F801FFC0003D99F009026FF3E007F6C019E6D013C130F02BC5D02F86D496D7E
+A24A5D4A5DA34A5DB3A7B60081B60003B512FEA5572D7CAC5E>I<90397F8007FEB59038
+3FFF8092B512E0028114F8913987F03FFC91388F801F000390399F000FFE6C139E14BC02
+F86D7E5CA25CA35CB3A7B60083B512FEA5372D7CAC3E>I<EC1FFC49B512C0010714F001
+1F14FC90397FF80FFF9026FFC0017F48496C7F4848C7EA3FE000078248486E7E49140F00
+1F82A2003F82491407007F82A400FF1780AA007F1700A46C6C4A5AA2001F5E6D141F000F
+5E6C6C4A5AA26C6C6CEBFFE06C6D485B27007FF80F90C7FC6DB55A010F14F8010114C090
+26001FFCC8FC312F7DAD38>I<90397FC00FF8B590B57E02C314E002CF14F89139DFC03F
+FC9139FF001FFE000301FCEB07FF6C496D13804A15C04A6D13E05C7013F0A2EF7FF8A4EF
+3FFCACEF7FF8A318F017FFA24C13E06E15C06E5B6E4913806E4913006E495A9139DFC07F
+FC02CFB512F002C314C002C091C7FCED1FF092C9FCADB67EA536407DAC3E>I<DA3FE013
+1E902603FFFC133E010F01FF137E013F1480903AFFF80FE0FE489038E003F148EBC00148
+90388000FB4890C7127F49143F001F151F485A160F5B127FA3485AAC6C7EA46C7EA26C6C
+141F163F6C6C147F6C15FF6C6D5A6C9038E003EF6C9038F01FCF6DB5128F011FEBFE0F01
+0313F89038007FC091C7FCAD0307B512FCA536407CAC3B>I<90387F807FB53881FFE002
+8313F0028F13F8ED8FFC91389F1FFE000313BE6C13BC14F8A214F0ED0FFC9138E007F8ED
+01E092C7FCA35CB3A5B612E0A5272D7DAC2E>I<90391FFC038090B51287000314FF120F
+381FF003383FC00049133F48C7121F127E00FE140FA215077EA27F01E090C7FC13FE387F
+FFF014FF6C14C015F06C14FC6C800003806C15806C7E010F14C0EB003F020313E0140000
+F0143FA26C141F150FA27EA26C15C06C141FA26DEB3F8001E0EB7F009038F803FE90B55A
+00FC5CD8F03F13E026E007FEC7FC232F7CAD2C>I<EB01E0A51303A41307A2130FA2131F
+A2133F137F13FF1203000F90B51280B7FCA4C601E0C7FCB3A3ED01E0A9150302F013C013
+7F150790393FF80F8090391FFC1F006DB5FC6D13FC01015B9038003FE023407EBE2C>I<
+D97FC049B4FCB50103B5FCA50003EC000F6C81B3A85EA25EA25E7E6E491380017FD901F7
+13FE9138F807E76DB512C7010F1407010313FE9026007FF0EBFC00372E7CAC3E>I<B690
+3803FFFCA5000101E09038003E006C163C80017F5D8017F8013F5D6E1301011F5D6E1303
+010F5D6E13076D5DED800F6D92C7FC15C05E6DEBE01E163E6D143CEDF07C027F1378EDF8
+F8023F5B15FD021F5B15FF6E5BA36E5BA26E90C8FCA26E5AA26E5AA21578362C7EAB3B>
+I<B500FE90383FFFF0A5C601F0903803E0006D6C495A6D6C495A011F4AC7FC6E5B6D6C13
+7E6DEB807C6D6D5A6DEBC1F0EDE3E06DEBF7C06EB45A806E90C8FC5D6E7E6E7F6E7FA24A
+7F4A7F8291381F3FFCEC3E1F027C7F4A6C7E49486C7F01036D7F49487E02C08049486C7F
+49C76C7E013E6E7E017E141FB500E090B512FCA5362C7EAB3B>120
+D<001FB71280A49026FC001F130001E0495A5B49495A90C7485A48495B123E4A5B4A5B00
+3C495BA24A90C7FC4A5A4A5AC7FC4A5A495B495BA2495B499038800780491300A2495A49
+48130F49481400A2485B48495B485BA248495B4890C75A48485C15034848EB1FFEB7FCA4
+292C7DAB32>122 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fn ecrm1728 17.28 8
+/Fn 8 117 df<B912F018FF19E019F8C601FCC8EA7FFED93FF892380FFF80011F04017F
+9538007FF0F11FF8737EF103FE737E737F747E747E747E1A0F87747E1A0387747EA27413
+80A2F37FC0A21CE01B3FA21CF0A21B1F1CF8A31CFCA21B0FA41CFEAF1CFCA51B1F1CF8A4
+F33FF0A21CE0A21B7F1CC01BFF1C80A2501300A2505A505AA2505A505A505A505A1AFF4F
+5B4F90C7FCF107FCF11FF8F17FF0953801FFC0013F04075BD9FFFCDB7FFEC8FCBA12F819
+E096C9FC18F0576278E167>68 D<BB12FCA4C601FCC8120FD93FF89238007FFE011F171F
+190719031900A21A7E1A3EA21A1EA21A1F86A486A6F20380A318E0A297C7FCA61701A417
+031707170F171F17FF91B7FCA402F8C7FC171F170F170717031701A41700A895C9FCB3A5
+80133F90B57EB712E0A4496278E158>70 D<EC3FE0903803FFFE010F6D7E90393FC03FE0
+90397C000FF801F0EB03FC48486D7E48486D7E48486E7E48C86C7E7F01F06E7E487E6D6E
+7EA3707EA36C5AEA03E0C9FCA6167FED7FFF020FB5FC91387FF807903801FF80903807FC
+00EB1FF0EB7FC0495AD803FEC7FC485A120F5B485A485AA24848EE01C0A312FF5BA2160F
+A3161F6D141B007F153B16736D17806C6C9138E1FC03001FEC03C16C6C903A0780FE0700
+D807FE49486C5A2701FF807CEB7FFE6C6CB4486D5A011F01E06D5A010390C7EA07E03A41
+79BF43>97 D<ED1FE0EDFFF8020313FE91380FF03F91391FC01F8091383F807F91397F00
+FFC014FE1301495A5C0107EC7F80A24948EB1E0093C7FCA2495AB3A5B712E0A426001FE0
+C8FCB3B3B0497EEB7FFC003FB512FEA42A657DE429>102 D<1378EA01FE487E487FA66C
+90C7FC6C5AEA007890C8FCB3A2EB0780EA0FFFB5FCA41203C6FCA2137FB3B3AC497E487F
+B61280A4195F7BDE25>105 D<010FEB07F8D80FFFEB1FFEB590387FFF809238F81FC091
+3801E03F913903C07FE00003EB0780C6EB0F00140E6D5A0218EB3FC00238EB1F800230EB
+0600027090C7FCA2146014E0A25CA55CB3B0497E4813F0B612F8A42B3F7BBE34>114
+D<9138FFC003010FEBF807017FEBFE0F3A01FF003F9FD803F0EB07DF48486DB4FCD80F80
+1300001F8148C8FC003E81007E81127C00FC81A4827EA27E7F6C7E6D91C7FC13F8EA3FFE
+381FFFE06C13FF15F0000314FE6C6E7E6C6C14E0011F14F801078001008002077FDA003F
+13801507030113C0ED007F00E0ED3FE0161F17F06C150F1607A36C1503A37EA26C16E016
+077E17C06D140F6D15806D141FD8FDF0EC3F00D8F8F8147E017C495A3AF01F801FF06DB5
+12C0D8E00391C7FC39C0007FF02C417CBF35>I<1470A714F0A51301A31303A21307A213
+0FA2131F133F137F13FF1203000F90B6FCB8FCA326000FF0C8FCB3AEEE01C0AE6D6CEB03
+80A316076D6C14005E6D6C130E6D6C131E6E6C5A91383FE0F86EB45A020713C0020090C7
+FC2A597ED734>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fo ecbx1728 17.28 18
+/Fo 18 117 df<BB7E1AFCF2FFC01BF01BFED8000191C8001F6D7E070014E0081F7F0807
+13FC08017F747F093F7F757F757F757F757F757F757FA2767E1E80881EC0881EE0881EF0
+A2881EF8A31EFC88A31EFEA61EFFB01EFEA61EFCA2641EF8A31EF064A21EE0641EC0641E
+80521300A2525A515B515BA2515B515B093F5B515B504848C7FC08075B081F5B97B512E0
+070F1480BC48C8FC1BF81BC008FCC9FC1A8068627BE177>68 D<942603FFF8151C94B66C
+143C040F03F0147C047F03FC14FC0303B81301030FDAC00113C0033F01F8C7381FF00392
+B500C0913807F807020349C83801FE0F020F01F89238007F1F4A01E0EE3FBF4A49EE0FFF
+91B5CA7E494983494983494983495B4949187F4B183F491A1F495B90B5CC120FA2484919
+075A4A19035A4A19015AA24A19005AA348491A7CA35A9AC8FCA35CA2B5FCB07EA26E043F
+B81280A47E96C7000701FCC7FCA26C7FA37E80A27E807E807E6C7FA26D7F6D7F7F816D7F
+6D6D5F6D7F6D6D5F6D6D7E023F6D5E6E01F05E6E6DEEFE7F020301FF923801FC3F020002
+C0913807F80F033F01FC91381FF007030F903BFFE001FFC001030391B6EA8000DB007F4B
+C7123C040F03F8140C040003C091C8FC050301F8CBFC696677E37A>71
+D<BA12E0F1FF801AF81AFF1BC0D8000191C7000114F0DE000F13FC070313FF070080083F
+7F747F747F747F747FA2747F88A28986A389A865A35091C8FCA26462646462505B505B50
+138097B5C9FC070313FC070F5B4EB512C093B8CAFC1AF81AC01AF893C7000713FE06006D
+7E073F7F7313F007077F737F87737F85888688A2747FAA88A91F707614F8A286A2746D13
+011FF086746D13037614E0B800FE6EED07C0746CEBC00F759038F07F80090F90B5120009
+035CCF6C13F80A0313E06D647BE173>82 D<001FBD12F0A59126F8000191C7123F4801C0
+060713F849C71700491A7F01F01A1F491A0F491A07A2491A03A290C81801A2007EF300FC
+A4007C1C7CA7481C3EA5C91900B3B3B3A5023FB912F8A55F617AE06C>84
+D<913803FFF0027F13FF0103B612E0010F15F890263FFC0013FED97FC090381FFF8049C7
+6C7F4801C06D7F486D6D7F6E6D7F48836E7F84177F84A36C496E7FA26C5B6C5B013FC8FC
+90C9FCA75F0307B6FC4AB7FC141F91B5EAF03F0103EBFE00010F13F0013F1380D9FFFEC7
+FC485B485B485B485B485B485BA24890C8FC1A7CA2485AA35FA394B5FC7F6C5D6EEB03DF
+6CDB07CFEBC0F86C6DEB0F8F6C6DD91F07EBF3F06C01F8017E14FF6C9027FE01FC0314E0
+C690B5D8F00114C0013F9126C0007F1380010791C7383FFE009026003FF8EC07F846437B
+C14D>97 D<903807FF80B6FCA5C6FC7F7FB3A9933801FFE0041F13FE047FEBFFC00381B6
+12F0922687FC0113FC923A9FE0003FFEDBBF8090380FFF8003FEC76C7F4B6E7F4B6E7F4B
+6E7F4B824B157F4B82737EA21B80851BC0A31BE085A41BF0AE1BE0A44F13C0A31B80A24F
+1300A262197F6F5E6F4B5A4E5B6F4A5BDAFCF84A5BDAF87E4A5B4A6C4A90C7FC9126E01F
+C0EB7FFC913BC00FF803FFF8DA8003B612E091C71580013E023F01FCC8FC90C800031380
+4C657CE356>I<ED1FFF4AB512F8020F14FF027F15C0902701FFF80013F04901E0EB0FF8
+010F0180EB03FC4990C7EA0FFE49484A7E49485C4948168048495C5A5C5A485BA2487013
+005C48705A715AEF03F04893C8FC91CBFCA4B5FCAE7EA280A27EA36C7FF003E07E6E1507
+6C18C06E150F6C18806C6D151F6C6DED3F006D6C157E6D6C15FE6D6D495A6D6D495A6D01
+F0EB0FE0010101FEEB7FC06D6CB6C7FC021F14FC020314E09126001FFEC8FC3B437BC145
+>I<ED3FFE0203B512E0021F14FC027F14FF902701FFF80F13C00107D9C0037F4990C77F
+49486E7E49486E7E49486E7E49486E7E5A48496E13805A4A16C0488219E0485B834818F0
+A34890C8FCA27113F8A3B5FCA391B8FCA491CBFCA67EA4807EA27E19F8806C17016C18F0
+806C17036C6DED07E06E16C06C170F6D6CED1F806D6CED3F006D6C6C14FE01076DEB03FC
+6D01F8EB0FF8010001FFEB7FE0023F90B51280020F4AC7FC020114F8DA000F13803D437C
+C146>101 D<EEFFE0031F13FC92B6FC02031580020F9038E03FC04A903800FFE091267F
+FE0113F04A485A49494813F84913F04913E0A25B15C05B7013F04913807013E09338007F
+80EF1E0094C7FCB1B8FCA5D8003F0180C8FCB3B3B2B712F8A535657CE42F>I<F13F8091
+2601FFF0903801FFE0021F01FF010713F091B6D8E01F13F801039238F87FCF010F903BC0
+7FFEFC0FFC903B1FFE000FFFF0D97FFC6DEBE01F49486D140F48496D13F01AF848496DEB
+F807489438FC01E096C7FC48496E7EA44883A96C5FA46C6D4A5AA26C5F6C6D495BA26C6D
+495B6D6C495B6D6C4990C8FC903A7FFFC07FFE017B90B512F801F015E0021F91C9FC0001
+010113F049CCFC1203A27FA37FA27F7F6D7E91B612FCEFFFE06C17FCF0FF806C18E0856D
+17FC6D836D837F017F188048BA12C000070180C712074848C96C13E04848160F48481603
+4982007F19F084485A197FA56D17FF007F19E0A26D5E6C6C4C13C0001F19806D5E6C6C4C
+1300000301C0ED3FFC6C01F0EDFFF826007FFC020313E090261FFFE0017F1380010790B6
+48C7FC010116F8D9001F1580DA007F01E0C8FC46607CC14D>I<EB0FE0EB3FF8497E497E
+487FA24880A76C91C7FCA26C5B6D5A6D5AEB0FE090C9FCB1903807FF80007FB5FCA5C6FC
+7F7FB3B3B0B712C0A522657CE42A>105 D<903807FF80B6FCA5C6FC7F7FB3B3B3B3AFB7
+12E0A523647CE32A>108 D<D90FFFEC7FF8B60103B5FC040F14E0043F80DC7F0113FC92
+2601F8007FC6DA03E06D7E6D49487F6D49488193C77E031E825D153803788003708215F0
+5DA35DA35DB3B3A2B7D8E03FB612F8A54D417BC056>110 D<92381FFF804AB512F8020F
+14FF023F15C09126FFFC0313F001039039E0007FFC490180EB1FFED91FFEC73807FF8049
+486E7F49486E7F49486E7F48496F7EA248496F7E4884A248496F7EA2481980A24819C091
+C97EA24819E0A5B518F0AD6C19E0A46C6D4B13C0A36C1980A26C6D4B1300A26C606E157F
+6C606C6D4B5A6C606D6C4A5B6D6C4A5B6D6C4A5B6D6C6C011F90C7FC010301E0EB7FFC6D
+9039FC03FFF86D6CB612E0020F92C8FC020114F8DA001F138044437CC14D>I<903B07FF
+8001FFE0B6011F13FE047FEBFFC00381B612F0922687FC0313FC923A9FE0007FFEC6DABF
+806D6C7E6D01FEC7000F7F6D496E7F4B824B6E7F4B6E7F4B804B82737EA21B80851BC0A2
+851BE0A4851BF0AE4F13E0A41BC061A21B80A24F1300A24F5AA26F4A5B6F4A5B626F4A5B
+6F4A5B03FE4A5B03BF027F90C7FCDB9FC0EBFFFC92268FF8075B0383B612E00380158004
+3F01FCC8FC0403138093CBFCB3A4B712E0A54C5D7CC056>I<D90FFFEB07F8B6EB3FFF4C
+13804BB512E0923903F83FF0923907E07FF8C691380F80FF6D020113FC6D131E153E153C
+1578A21570DBF00013F8EF7FF04BEB3FE0EF0F8094C7FC5DA65DB3B1B712F8A536417DC0
+3E>114 D<DA7FFC131C0107B5EAC03C011FECF0FC90B612FD489038C003FFD807FEC712
+7FD80FF8143F49140F4848140748481403A248481401A2160012FFA26D157CA27F7F7F6D
+92C7FCEBFF806C13F0ECFFC015FE6CECFFC016F86C15FE6C6F7E6C826C826C826C82013F
+81010F81010181EB003F02011580EC000F1500041F13C000F88182826C8182A26C167FA3
+7E18807F17FF6D16007F6D4A5A7F6D4A5A6DEC0FF86D6C495A3BFE1FF001FFE0486CB612
+80D8F8034AC7FC48C614F048010F90C8FC32437BC13D>I<EC07C0A6140FA5141FA3143F
+A2147FA214FF5BA25B5B5B5B137F48B5FC000F91B512F8B8FCA4D8001F01C0C7FCB3B017
+1FAD6D153E81A26D157C816D15F86D7F6D9038FC01F091397FFF07E06EEBFFC0020F1480
+0203EBFE009138003FF8305C7DDA3C>I E
+%EndDVIPSBitmapFont
+end
+%%EndProlog
+%%BeginSetup
+%%Feature: *Resolution 600dpi
+TeXDict begin
+%%PaperSize: A4
+
+%%EndSetup
+%%Page: 1 1
+1 0 bop 290 639 a Fo(Genealogical)56 b(Represen)l(tation)e(of)f(T)-13
+b(rees)52 b(in)g(Databases)1686 822 y Fn(First)46 b(Draft)1247
+1063 y Fm(Miguel)36 b(Sofer)i(<mig@utdt.edu>)1359 1179
+y Fl(Univ)m(ersidad)33 b(T)-8 b(orcuato)33 b(Di)f(T)-8
+b(ella)1728 1295 y(Buenos)33 b(Aires)1797 1411 y(Argen)m(tina)1746
+1606 y(Ma)m(y)h(6,)e(2000)1839 1905 y Fk(Abstract)441
+2035 y Fj(blah)25 b(blah)h(.)13 b(.)g(.)118 2310 y Fi(1)131
+b(In)l(tro)t(duction)118 2491 y Fh(T)-7 b(rees)28 b(are)h(a)g(v)n(ery)f
+(frequen)n(t)h(data)f(structure.)41 b(They)30 b(are)e(the)h(natural)g
+(represen)n(tation)e(for)i(instance)g(for)f(organiza-)118
+2591 y(tional)f(c)n(harts,)g(threaded)g(discussion)g(groups,)f(some)h
+(bills)g(of)h(materials,)e(.)14 b(.)g(.)243 2691 y(A)n(t)28
+b(least)f(t)n(w)n(o)f(alternativ)n(e)h(represen)n(tations)e(for)i
+(trees)g(in)h(RDBMs)g(are)e(kno)n(wn)h(and)h(used:)220
+2857 y(1.)41 b Fg(P)m(oin)m(ters:)k Fh(a)31 b(\034eld)h(in)h(the)f(c)n
+(hild)g(record)e(references)h(the)h(paren)n(t)f(no)r(de.)50
+b(This)32 b(seems)g(to)f(b)r(e)i(the)f(canonical)326
+2956 y(represen)n(tation.)38 b(Some)29 b(DB)g(engines)f(pro)n(vide)g
+(sp)r(ecial)g(SQL)g(extensions)g(to)h(simplify)g(tree)g(searc)n(hes;)e
+(Oracle)326 3056 y(tree)d(extensions)g(are)g(an)h(example)f(\(see)h
+(for)f(instance)g([1]\);)i(DB2's)f(WITH)g(can)f(b)r(e)i(used)e(for)h
+(this)g(purp)r(ose)f(to)r(o)326 3156 y(\(see)j([3],)g(pp)h(139-162\).)
+220 3322 y(2.)41 b Fg(Nested)35 b(Sets:)43 b Fh(t)n(w)n(o)30
+b(n)n(umeric)h(\034elds)g(in)g(ev)n(ery)f(no)r(de)h(record)f(co)r(de)h
+(the)g(tree)g(structure.)47 b(I)31 b(can't)g(pro)n(vide)f(a)326
+3421 y(b)r(etter)e(or)e(briefer)h(description)g(of)h(this)g(metho)r(d)g
+(than)f(the)h(four)f(articles)g([2].)118 3587 y(These)g(t)n(w)n(o)g
+(metho)r(ds)h(o\033er)f(di\033eren)n(t)h(adv)-5 b(an)n(tages)25
+b(and)j(disadv)-5 b(an)n(tages:)243 3753 y Ff(\017)41
+b Fh(P)n(oin)n(ters)30 b(are)g(extremely)g(e\036cien)n(t)h(for)f(no)r
+(de)h(insertion)f(and/or)g(deletion,)h(but)h(require)e(recursiv)n(e)f
+(table)i(ac-)326 3853 y(cesses)e(to)h(searc)n(h)f(the)h(tree)g(\(I)h
+(do)f(not)g(kno)n(w)f(the)i(implemen)n(tation)f(details)g(of)g(the)h
+(Oracle)e(tree)g(extensions,)326 3953 y(whic)n(h)e(as)g(far)g(as)g(I)g
+(kno)n(w)g(ma)n(y)g(solv)n(e)f(this)i(problem)f(in)n(ternally;)g(they)g
+(de\034nitely)h(solv)n(e)f(it)g(for)g(the)h(end)g(user\).)243
+4119 y Ff(\017)41 b Fh(Nested)30 b(sets)g(are)f(v)n(ery)f(e\036cien)n
+(t)i(for)g(tree)f(searc)n(hes,)g(but)i(are)e(rather)f(exp)r(ensiv)n(e)i
+(for)f(no)r(de)h(insertion)f(and/or)326 4218 y(deletion:)37
+b(they)27 b(require)g(up)r(dating)g(p)r(oten)n(tially)h(man)n(y)f(no)r
+(des.)243 4384 y(W)-7 b(e)30 b(prop)r(ose)f(here)h(a)g(di\033eren)n(t)h
+(represen)n(tation,)e(based)g(on)i(no)r(de)f(iden)n(ti\034ers)g(whic)n
+(h)g(are)f(\020genealogical)f(iden)n(ti-)118 4484 y(\034ers\021:)44
+b(they)32 b(con)n(tain)f(the)h(complete)f(genealogy)f(of)h(the)h(no)r
+(de,)h(i.e.,)g(the)f(list)g(of)g(ancestors)d(up)j(to)g(the)g(ro)r(ot)f
+(of)g(the)118 4584 y(tree.)243 4683 y(This)j(allo)n(ws)f(to)i(replace)e
+(man)n(y)h(searc)n(hes)f(in)h(database)g(tables)g(with)h(string)f(op)r
+(erations)f(on)h(the)h(index.)58 b(The)118 4783 y(result,)24
+b(as)f(explained)h(in)g(Section)g(3)f(is)h(that)g(tree)f(searc)n(hes)f
+(pro)r(ceed)h(at)h(\020nested)f(sets\021)30 b(sp)r(eed,)25
+b(while)f(no)r(de)g(insertions)118 4882 y(and)k(deletions)f(are)f(as)h
+(fast)h(as)f(with)h(p)r(oin)n(ters.)243 4982 y(The)i(ob)n(vious)f(do)n
+(wnside)h(of)h(the)g(metho)r(d)g(is)f(that)h(the)g(primary)f(k)n(ey)f
+(in)i(the)g(tree)f(needs)h(to)f(b)r(e)h(a)g(v)-5 b(ariable)29
+b(size)118 5082 y(text)j(\034eld,)h(and)f(that)g(the)g(iden)n
+(ti\034ers)f(ma)n(y)g(b)r(e)i(extremelly)e(long)g(for)g(deep)h(trees.)
+49 b(W)-7 b(e)32 b(will)g(pro)n(vide)e(estimates)i(of)118
+5181 y(the)c(size)f(required)g(as)g(a)g(function)h(of)g(the)f
+(magnitude)h(of)f(the)h(tree.)1987 5653 y(1)p eop
+%%Page: 2 2
+2 1 bop 118 291 a Fi(2)131 b(Genealogical)45 b(iden)l(ti\034ers)g(for)f
+(trees)118 489 y Fm(2.1)112 b(De\034nition)118 642 y
+Fh(W)-7 b(e)28 b(de\034ne)g Fe(gene)l(alo)l(gic)l(al)k(identi\034ers)j
+Fh(recursiv)n(ely)25 b(as)i(follo)n(ws:)326 808 y Fg(De\034nition:)59
+b Fe(The)42 b(gene)l(alo)l(gic)l(al)h(identi\034er)f(\(gID\))e(of)i(a)f
+(no)l(de)h(is)f(obtaine)l(d)h(by)g(app)l(ending)g(a)f(child)326
+908 y(identi\034er)30 b(to)g(the)g(gene)l(alo)l(gic)l(al)h
+(identi\034er)g(of)f(the)g(p)l(ar)l(ent)f(no)l(de.)243
+1074 y Fh(Remark)40 b(that)h(genealogical)e(iden)n(ti\034ers)i(are)f
+(rather)g(w)n(ell)h(kno)n(wn)f(and)h(used;)48 b(common)41
+b(examples)f(are)g(the)118 1174 y(\020path+\034le-name\021)33
+b(in)28 b(a)f(computer)g(\034le)h(system)f(and)h(the)f(URLs)h(within)g
+(a)f(WWW.)243 1273 y(The)d(name)g(\020genealogical)e(iden)n
+(ti\034er\021)30 b(is)24 b(suggested)g(b)n(y)g(the)g(fact)h(that)f(the)
+h(v)-5 b(alue)24 b(of)g(the)h(iden)n(ti\034er)f(con)n(tains)f(the)118
+1373 y(complete)30 b(genealogy)d(of)j(the)g(no)r(de:)41
+b(it)30 b(con)n(tains)e(as)h(a)h(substring)f(the)h(gID)f(of)h(its)g
+(father,)g(whic)n(h)f(in)h(turn)g(con)n(tains)118 1472
+y(as)d(a)g(substring)g(the)h(gID)g(of)f(the)h(grandfather,)e(.)14
+b(.)g(.)243 1572 y(The)27 b(ro)r(ot)g(no)r(de)h(of)f(the)h(tree)f(has)g
+(a)h(gID)f(with)h(v)-5 b(alue)28 b(\021)34 b(\(the)28
+b(empt)n(y)g(string\),)f(as)g(it)h(has)f(no)g(paren)n(t.)118
+1804 y Fm(2.2)112 b(Child)36 b(iden)m(ti\034ers)118 1958
+y Fh(The)26 b(ob)n(vious)e(c)n(hild)i(iden)n(ti\034er)g(is)f(a)h
+(zero-based)d(coun)n(ter:)35 b(iden)n(tify)26 b(the)h(c)n(hild)e(b)n(y)
+h(the)g(n)n(um)n(b)r(er)f(of)h(older)f(brethren)g(it)118
+2057 y(has.)243 2157 y(W)-7 b(e)25 b(could)f(represen)n(t)g(the)h(coun)
+n(ter)f(in)h(base)f(10;)h(this)g(ho)n(w)n(ev)n(er)e(is)i(extremely)f(w)
+n(asteful)g(of)h(resources.)34 b(It)25 b(is)g(m)n(uc)n(h)118
+2257 y(b)r(etter)33 b(to)f(represen)n(t)f(the)h(coun)n(ter)g(in)g(as)g
+(large)e(a)i(base)g(as)f(p)r(ossible:)46 b(in)n(terpret)32
+b(as)f(n)n(um)n(b)r(ers)h(a)g(set)g(of)g(c)n(haracters)118
+2356 y(larger)26 b(than)h({0,1,.)14 b(.)g(.)g(9}.)243
+2456 y(As)26 b(tree)f(op)r(erations)f(will)i(in)n(v)n(olv)n(e)f(string)
+g(op)r(erations)f(on)i(the)g(indices,)g(in)g(order)f(to)g(a)n(v)n(oid)g
+(a)g(\020quoting)g(hell\021)33 b(it)26 b(is)118 2555
+y(desirable)d(to)h(a)n(v)n(oid)e(using)h(an)n(y)g(c)n(haracter)f(with)i
+(a)g(sp)r(ecial)f(meaning)h(in)g(LIKE)g(expressions)e(or)g(regular)g
+(expressions;)118 2655 y(i.e.,)28 b(w)n(e)f(will)h(not)f(use)h(an)n(y)f
+(of)g(the)h(sym)n(b)r(ols)70 b Fd(.)44 b(*)f(^)g(\\)g([)g(])g({)h(})f
+(\()g(\))g(<)g(>)71 b Fh(?)37 b(|)28 b(&)f($)243 2755
+y(W)-7 b(e)28 b(prop)r(ose)e(to)h(reserv)n(e)f(also)g(/)i(as)f(a)g
+(separator)e(\(see)i(\020V)-7 b(ariable)27 b(Sized)g(gID\021)34
+b(b)r(elo)n(w\).)243 2854 y(If)g(w)n(e)f(limit)i(ourselv)n(es)d(to)i
+(ascii)f(c)n(haracters,)g(and)h(a)n(v)n(oid)e(to)i(b)r(e)g(safe)f(a)h
+(lot)g(of)g(other)f(c)n(haracters,)g(w)n(e)g(can)h(use)118
+2954 y(n)n(um)n(b)r(ers)27 b(in)h(base)f(64)g(b)n(y)g(represen)n(ting)
+243 3120 y Ff(\017)41 b Fh(0-9)26 b(with)i('0'-'9')f(\(dec)g(ascii)g
+(co)r(de)h(48-57\))243 3286 y Ff(\017)41 b Fh(10)26 b(with)i(':')37
+b(\(dec)28 b(ascii)f(co)r(de)h(58\))243 3452 y Ff(\017)41
+b Fh(11)26 b(with)i(';')g(\(dec)g(ascii)f(co)r(de)g(59\))243
+3618 y Ff(\017)41 b Fh(12-37)25 b(with)j('A'-'Z')g(\(dec)f(ascii)g(co)r
+(de)h(65-90\))243 3784 y Ff(\017)41 b Fh(38-63)25 b(with)j('a'-'z')f
+(\(dec)h(ascii)f(co)r(de)g(97-122\))118 3950 y(By)g(using)g(base)f(64,)
+h(up)g(to)h(4096)d(c)n(hildren)i(can)f(b)r(e)i(represen)n(ted)e(using)h
+(t)n(w)n(o)f(suc)n(h)h(digits,)g(up)h(to)f(262144)d(with)k(three)118
+4050 y(digits,)g(and)f(up)h(to)f(16777216)d(with)k(four)f(digits.)243
+4149 y(If)37 b(the)g(RDBMs)g(supp)r(orts)f(in)n(ternational)g(c)n
+(haracters,)h(it)g(is)g(p)r(ossible)f(to)h(further)f(increase)g(the)h
+(base;)k(as)36 b(an)118 4249 y(example,)30 b(b)n(y)f(using)g(the)h(95)f
+(additional)g(c)n(haracters)e(of)i(the)h(latin-1)f(c)n(haracter)e(set,)
+k(w)n(e)e(could)g(co)r(de)g(n)n(um)n(b)r(ers)g(in)h(a)118
+4349 y(base)f(up)g(to)g(160)f(\025)g(remark)g(that)h(ev)n(ery)f(single)
+h(digit)g(is)g(still)h(one)e(b)n(yte)h(in)h(this)f(represen)n(tation.)
+40 b(This)29 b(means)f(that)118 4448 y(w)n(e)f(expand)h(the)f(sym)n(b)r
+(ols)g(ab)r(o)n(v)n(e)f(b)n(y)i(represen)n(ting)243 4614
+y Ff(\017)41 b Fh(64-159)25 b(with)j(dec)f(latin1)g(co)r(de)h(160-255)
+243 4780 y(In)23 b(base)g(160,)g(up)g(to)h(25600)d(c)n(hildren)i(can)f
+(b)r(e)i(represen)n(ted)e(using)h(t)n(w)n(o)g(digits,)h(up)g(to)f
+(4096000)d(with)k(three)f(digits,)118 4880 y(and)28 b(up)f(to)h
+(6.5E+08)e(with)i(four)f(digits.)243 4980 y(Remark)g(that)h(base)f(con)
+n(v)n(ersions)f(only)h(need)i(to)e(b)r(e)i(p)r(erformed)e(at)h
+(insertion)g(time,)g(when)h(the)f(index)g(of)g(a)g(new)118
+5079 y(no)r(de)g(is)f(computed.)37 b(They)28 b(will)f(therefore)g(only)
+g(ha)n(v)n(e)f(an)i(impact)f(on)h(insertion)f(timings.)1987
+5653 y(2)p eop
+%%Page: 3 3
+3 2 bop 118 291 a Fm(2.3)112 b(Coun)m(ters:)50 b(\020delimited\021)44
+b(vs.)51 b(\020\034xed)38 b(size\021)118 444 y Fh(The)33
+b(standard)g(represen)n(tation)e(of)i(gID)h(uses)e(a)h(v)-5
+b(ariable)32 b(size)h(c)n(hild)h(iden)n(ti\034er,)g(and)f(delimiters)g
+(to)h(separate)d(the)118 543 y(gID)f(of)g(the)h(c)n(hild)f(no)r(de)g
+(from)f(the)i(gID)f(of)g(its)g(paren)n(t.)43 b(F)-7 b(or)30
+b(example,)g(w)n(e)g(can)f(represen)n(t)g(the)i(\034fth)g(c)n(hild)f
+(of)g(no)r(de)118 643 y('/23/27/1')24 b(as)j('/23/27/1/4'.)32
+b(Let)c(us)f(call)g(this)h(a)f Fg(vgID)h Fh(represen)n(tation)e(\(V)-7
+b(ariable)27 b(Size)h(Genealogical)d(ID\).)243 743 y(This)30
+b(represen)n(tation)f(allo)n(ws)f(for)i(an)n(y)g(n)n(um)n(b)r(er)g(of)g
+(c)n(hildren)g(of)h(a)f(no)r(de,)h(sub)5 b(ject)30 b(only)g(to)g(the)h
+(limitations)f(the)118 842 y(RDBMS)e(ma)n(y)f(ha)n(v)n(e)f(as)h(to)h
+(the)g(length)f(of)h(a)f(v)-5 b(ariable)27 b(sized)g(string.)243
+942 y(Alternativ)n(ely)-7 b(,)24 b(w)n(e)f(could)h(c)n(ho)r(ose)f(to)h
+(limit)g(from)g(the)g(outset)g(the)g(quan)n(tit)n(y)g(of)f(c)n(hildren)
+h(that)g(a)g(no)r(de)g(ma)n(y)f(ha)n(v)n(e;)118 1042
+y(this)28 b(limit)g(w)n(ould)f(dep)r(end)i(of)e(course)f(on)i(the)g
+(application.)36 b(Let)27 b(us)h(call)f(this)h(a)f Fg(fgID)h
+Fh(represen)n(tation.)243 1141 y(F)-7 b(or)25 b(example,)h(if)g(no)g
+(no)r(de)f(is)h(allo)n(w)n(ed)f(to)g(ha)n(v)n(e)g(more)g(than)h(25600)d
+(c)n(hildren,)j(w)n(e)g(could)f(represen)n(t)g(the)h(coun)n(ters)118
+1241 y(alw)n(a)n(ys)36 b(with)i(2)f(digits.)67 b(The)38
+b(no)r(de)f(whic)n(h)h(w)n(as)f(previously)f('/23/27/1/4')d(is)k(no)n
+(w)g('23270104'.)64 b(If)38 b(w)n(e)f(require)118 1340
+y(a)g(three)g(digit)h(represen)n(tation)d(of)i(no)r(des)g(\(up)h(to)f
+(ab)r(out)h(4)f(million)g(c)n(hildren\),)j(then)d(it)h(will)g(b)r(e)f
+(represen)n(ted)f(as)118 1440 y('023027001004'.)118 1672
+y Fm(2.4)112 b(Ordering)37 b(of)h(no)s(des)118 1825 y
+Fh(F)-7 b(or)35 b(some)g(applications)g(it)h(is)f(necessary)f(to)i
+(obtain)f(subtrees)g(ordered)f(according)g(to)i(some)f(sp)r(ecial)g
+(rules.)60 b(F)-7 b(or)118 1925 y(instance:)220 2090
+y(1.)41 b(the)34 b(complete)g(subtree)f(starting)g(at)h(a)f(no)r(de)h
+(is)g(listed)g(immediately)g(after)f(the)i(no)r(de)f(in)g(question)f
+(\(\020depth)326 2189 y(\034rst\021\))220 2354 y(2.)41
+b(no)r(des)27 b(with)h(a)f(common)g(paren)n(t)g(are)g(listed)g(c)n
+(hronologically)243 2519 y(F)-7 b(or)39 b(instance,)k(the)d(displa)n(y)
+f(of)h(an)f(organization)f(c)n(hart)h(is)g(usually)h(required)e(to)i
+(satisfy)g(at)f(least)h(the)g(\034rst)118 2619 y(condition.)h(In)29
+b(a)g(threaded)f(discussion)h(group)e(one)i(wishes)g(to)f(satisfy)h(b)r
+(oth)h(conditions)e(to)h(displa)n(y)f(the)h(messages)118
+2718 y(in)20 b(a)g(thread)g(\025)f(the)i(threads)e(themselv)n(es)h
+(\(i.e.,)i(c)n(hildren)e(of)g(the)g(ro)r(ot)f(no)r(de\))i(are)e
+(usually)g(listed)i(in)f(in)n(v)n(erse)f(c)n(hronolical)118
+2818 y(order.)243 2917 y(T)-7 b(o)35 b(mak)n(e)f(a)h(particular)f
+(ordering)g(e\036cien)n(t,)j(it)f(w)n(ould)f(b)r(e)h(a)f(nice)g
+(feature)g(if)h(it)g(could)f(b)r(e)h(made)f(to)g(coincide)118
+3017 y(with)28 b(a)f(lexicographic)f(ordering)f(of)j(the)g(indices)f
+(\025i.e.,)g(as)g(pro)r(duced)g(b)n(y)h(an)f(\020ORDER)h(BY)f(id)h
+(ASC\021)35 b(in)27 b(SQL.)h(The)118 3117 y(lexicographic)d(ordering)h
+(of)h(fgID)h(satis\034es)e(b)r(oth)i(conditions.)36 b(The)27
+b(lexicographic)f(ordering)f(of)i(vgID)g(as)g(describ)r(ed)118
+3216 y(ab)r(o)n(v)n(e)34 b(satis\034es)g(the)h(\034rst)g(requisite)f
+(if)i(the)f(separator)d(has)j(the)g(minimal)g(binary)g(represen)n
+(tation)e(of)i(all)f(allo)n(w)n(ed)118 3316 y(sym)n(b)r(ols)c(in)h(an)f
+(index)h(\025)f(this)h(is)g(wh)n(y)f(w)n(e)g(reserv)n(ed)f(/)h(for)g
+(the)i(separator.)43 b(But)31 b(the)g(second)f(prop)r(ert)n(y)g(is)g
+(missing:)118 3416 y(for)d(instance,)g(the)h(index)g('/1/10')d(is)j
+(lexicographically)d(b)r(efore)i('/1/2'.)243 3515 y(If)c(the)h(second)e
+(prop)r(ert)n(y)g(is)i(also)e(required)g(for)h(vgID,)g(w)n(e)f(can)h
+(sp)r(ecify)h(the)f(c)n(hild)h(iden)n(ti\034ers)e(with)i(coun)n(ters)e
+(built)118 3615 y(in)28 b(the)g(follo)n(wing)e(w)n(a)n(y:)36
+b(represen)n(t)26 b(a)h(n)n(um)n(b)r(er)h(b)n(y)f(a)g(string)g(of)g
+(digits,)h(where)243 3779 y Ff(\017)41 b Fh(the)25 b(\034rst)g(digit)h
+Fc(D)896 3791 y Fb(0)958 3779 y Fh(represen)n(ts)e(the)i(length)f(in)h
+(digits)f(of)g(the)h(decimal)f(expansion)f(of)i(the)f(n)n(um)n(b)r(er,)
+h(min)n(us)f(one)243 3945 y Ff(\017)41 b Fh(the)28 b(follo)n(wing)e
+Fa(\()p Fc(D)920 3957 y Fb(0)976 3945 y Fa(+)18 b(1\))27
+b Fh(digits)h(are)e(the)i(decimal)g(expansion)e(of)i(the)g(n)n(um)n(b)r
+(er)118 4109 y(Let)g(us)f(call)h(these)f(iden)n(ti\034ers)g
+Fg(m-vgID)p Fh(,)g(\020m\021)34 b(for)27 b(mo)r(di\034ed.)243
+4209 y(As)e(an)f(example,)h(the)g(no)r(de)g(whic)n(h)g(w)n(as)f
+(previously)f(represen)n(ted)h(b)n(y)g(/15/3/182)d(will,)k(after)g
+(this)g(mo)r(di\034cation,)118 4309 y(ha)n(v)n(e)h(the)i(index)g
+(/115/03/2182.)243 4408 y(The)37 b(lexicographic)f(ordering)g(of)i
+(m-vgID)f(is)h(the)g(desired)f(ordering)f(of)h(the)h(tree)g(no)r(des.)
+67 b(The)38 b(cost)f(of)g(this)118 4508 y(prop)r(ert)n(y)31
+b(is)i(that)f(\(a\))h(the)g(ID)f(are)g(no)n(w)g(longer,)g(\(b\))h(no)f
+(no)r(de)g(can)g(ha)n(v)n(e)g(more)f(than)i Fa(160)3106
+4478 y Fb(160)3240 4508 y Fh(c)n(hildren)f(\(actually)-7
+b(,)118 4607 y(this)32 b(is)g(a)f(non-issue\),)h(and)f(\(c\))h(the)g
+(index)g(structure)f(is)h(redundan)n(t,)g(some)f(formally)f(correct)h
+(indices)g(are)g(in)n(v)-5 b(alid)118 4707 y(\025e.g.,)24
+b(/316/013/11.)30 b(The)24 b(third)g(issue)g(can)g(b)r(e)g(addressed)f
+(b)n(y)g(k)n(eeping)g(a)h(strict)g(con)n(trol)e(on)i(the)g(generation)f
+(of)h(new)118 4807 y(indices)k(to)f(insure)g(that)h(all)f(indices)h
+(are)e(formally)h(correct.)243 4906 y(The)32 b(issue)f(of)h(the)g(rev)n
+(erse)e(c)n(hronological)f(indexing)j(of)f(threads)h(in)g(threaded)f
+(discussion)g(groups)g(can)g(b)r(e)h(ad-)118 5006 y(dressed)d(easily)f
+(enough)h(in)h(fgID:)f(coun)n(t)g(\020do)n(wn\021)36
+b(instead)29 b(of)g(\020up\021)36 b(the)30 b(c)n(hildren)f(of)g(the)h
+(ro)r(ot)e(no)r(de)i(\025)f(this)h(implies)118 5106 y(only)e(an)g
+(inconsequen)n(tial)f(mo)r(di\034cation)h(of)g(the)g(no)r(de)h
+(insertion)e(routine,)h(as)g(sho)n(wn)f(b)r(elo)n(w.)38
+b(The)29 b(problem)e(is)h(less)118 5205 y(trivial)i(with)g(vgID;)h(in)f
+(this)h(case,)f(ma)n(yb)r(e)f(a)h(thread)g(iden)n(ti\034er)g(should)g
+(b)r(e)h(k)n(ept)f(in)g(a)g(di\033eren)n(t)g(\034eld)h(-)f(i.e.,)h
+(repre-)118 5305 y(sen)n(ting)h(the)h(structure)f(as)g(a)h(forest)f
+(rather)f(than)i(a)f(tree,)i(where)e(the)h(thread_id)f(\034eld)h
+(selects)f(the)h(\020tree\021)38 b(in)33 b(the)118 5404
+y(forest.)1987 5653 y(3)p eop
+%%Page: 4 4
+4 3 bop 118 291 a Fi(3)131 b(T)-11 b(ree)45 b(op)t(erations)e(using)h
+(genealogical)g(indices)118 472 y Fh(In)32 b(this)f(section)g(w)n(e)g
+(sho)n(w)g(ho)n(w)g(to)g(implemen)n(t)h(v)-5 b(arious)30
+b(tree)h(op)r(erations)f(using)h(gID)g(as)g(the)h(primary)e(k)n(ey)h
+(in)g(the)118 572 y(no)r(de)d(table.)243 672 y(Some)h(implemen)n
+(tation)h(issues)g(are)f(relev)-5 b(an)n(t)29 b(here,)h(esp)r(ecially)f
+(concerning)g(the)h(utilisation)g(of)g(indices)g(b)n(y)f(the)118
+771 y(DB)f(engine.)243 871 y(W)-7 b(e)28 b(discuss)f(a)g(tree)g
+(represen)n(ted)f(in)i(a)f(table)h(of)f(the)h(form)326
+1034 y Fd(CREATE)41 b(TABLE)g(tree)h(\()456 1134 y(gid)304
+b(text)42 b(PRIMARY)f(KEY,)456 1234 y(nchildren)f(integer)h(DEFAULT)f
+(0,)456 1333 y(\\ldots)h(the)i(actual)e(node)h(data)326
+1433 y(\);)118 1597 y Fh(The)26 b(\034eld)g(\020nc)n(hildren\021)32
+b(is)26 b(a)f(coun)n(ter)g(for)g(the)i(n)n(um)n(b)r(er)e(of)h(c)n
+(hildren)f(that)h(the)h(no)r(de)f(has)f Fe(ever)35 b
+Fh(had;)27 b(w)n(e)e(assume)g(here)118 1696 y(it)j(is)g(not)f(up)r
+(dated)h(when)g(no)r(des)f(or)g(subtrees)g(are)f(deleted.)243
+1796 y(Section)h(4)g(pro)n(vides)f(a)i(complete)f(implemen)n(tation)h
+(of)f(these)h(op)r(erations)e(for)h(fgID)h(in)g(P)n(ostgreSQL.)118
+2028 y Fm(3.1)112 b(Computing)37 b(the)g(lev)m(el)f(of)h(a)h(no)s(de)
+118 2181 y Fg(Cost:)f Fe(string)30 b(op)l(er)l(ations)g(\(no)g(table)g
+(ac)l(c)l(ess\))243 2280 y Fh(This)d(is)h(a)f(pure)g(string)g(op)r
+(eration,)f(no)i(table)f(access)g(is)g(required.)243
+2460 y Ff(\017)41 b Fg(vgID:)27 b Fh(coun)n(t)h(the)g(n)n(um)n(b)r(er)f
+(of)g(separators)e(\('/'\))j(in)g(the)g(PK)243 2625 y
+Ff(\017)41 b Fg(fgID:)27 b Fh(coun)n(t)g(the)h(n)n(um)n(b)r(er)g(of)f
+(c)n(haracters)e(in)j(the)g(PK,)g(divide)g(b)n(y)f(the)h(\034xed)f
+(size)h(of)f(the)h(coun)n(ters.)118 2857 y Fm(3.2)112
+b(Selecting)36 b(or)h(deleting)f(a)i(subtree)118 3010
+y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l(e)l(e)243
+3173 y Ff(\017)41 b Fg(vgID:)27 b Fh(The)h(subtree)f(ro)r(oted)g(at)g
+(/26/5/7)e(is)i(selected)g(b)n(y)508 3338 y Fd(...)43
+b(WHERE)e(id)i(LIKE)f('/26/5/7\045')d(AND)j(id)h(<)g('/26/5/70')243
+3503 y Ff(\017)e Fg(m-vgID:)26 b Fh(The)h(subtree)h(ro)r(oted)e(at)i
+(/126/05/07)22 b(is)28 b(selected)f(b)n(y)508 3668 y
+Fd(...)43 b(WHERE)e(id)i(LIKE)f('/126/06/07\045')243
+3833 y Ff(\017)f Fg(fgID:)27 b Fh(The)h(subtree)f(ro)r(oted)g(at)g
+(260507)e(is)i(selected)h(b)n(y)508 3997 y Fd(...)43
+b(WHERE)e(id)i(LIKE)f('260507\045')118 4229 y Fm(3.3)112
+b(Selecting)36 b(the)h(direct)f(c)m(hildren)g(of)i(a)g(no)s(de)118
+4382 y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l(e)l(e)243
+4562 y Ff(\017)41 b Fg(vgID:)27 b Fh(The)h(direct)f(c)n(hildren)g(of)h
+(/26/5/7)c(are)j(selected)g(b)n(y)508 4727 y Fd(...)43
+b(WHERE)e(id)i(LIKE)f('/26/5/7/\045')d(AND)j(id)h(NOT)f(LIKE)g
+('26/5/7/\045/\045')243 4892 y Ff(\017)f Fg(m-vgID:)26
+b Fh(The)h(direct)h(c)n(hildren)f(of)g(/26/5/7)e(are)h(selected)i(b)n
+(y)508 5056 y Fd(...)43 b(WHERE)e(id)i(LIKE)f('/126/06/07/\045')37
+b(AND)43 b(id)f(NOT)h(LIKE)f('/126/05/07/\045/\045)o(')243
+5221 y Ff(\017)f Fg(fgID:)27 b Fh(The)h(direct)f(c)n(hildren)g(of)h
+(260507)c(are)j(selected)g(b)n(y)508 5386 y Fd(...)43
+b(WHERE)e(id)i(LIKE)f('260507\045')d(AND)k(char_length\(id\))37
+b(=)43 b(\(char_length\('26)o(05)o(07')o(\)+)o(2\))1987
+5653 y Fh(4)p eop
+%%Page: 5 5
+5 4 bop 118 291 a Fm(3.4)112 b(Inserting)37 b(a)h(no)s(de)g(or)f(a)h
+(subtree)118 444 y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l
+(e)l(e)f(+)h(string)f(and)h(math)g(op)l(er)l(ations)243
+543 y Fh(Insertion)f(is)g(a)h(pro)r(cedural)e(op)r(eration.)42
+b(As)30 b(eac)n(h)f(RDBMS)h(has)f(a)h(di\033eren)n(t)f(w)n(a)n(y)g(of)g
+(de\034ning)h(pro)r(cedures,)f(w)n(e)118 643 y(will)f(just)g(describ)r
+(e)f(here)g(the)h(necessary)e(steps.)37 b(Examples)27
+b(for)g(P)n(ostgreSQL)f(are)h(pro)n(vided)f(in)i(4.)243
+743 y(In)22 b(order)f(to)h(insert)g(a)g(new)g(c)n(hild)h(of)f
+(\020daddy\021)28 b(\(either)23 b(one)f(of)g(/26/5/7,)e(/126/05/07)d
+(or)22 b(260507)d(in)k(the)f(examples)118 842 y(ab)r(o)n(v)n(e\))27
+b(y)n(ou)f(ha)n(v)n(e)h(to)220 1008 y(1.)41 b(add)27
+b(one)g(to)h(the)g(n)n(um)n(b)r(er)f(of)g(c)n(hildren)h(of)f
+(\020daddy\021)508 1174 y Fd(UPDATE)41 b(tree)h(SET)h(nchildren)c(=)k
+(\(nchildren)d(+)j(1\))g(WHERE)e(ID)i(=)g(``daddy'';)220
+1340 y Fh(2.)e(enco)r(de)27 b(the)h(n)n(um)n(b)r(er)f(of)g(c)n(hildren)
+g(of)h(\020daddy\021)33 b(in)28 b(base)f(160,)f(bring)h(it)h(to)f(the)h
+(correct)e(format)h(dep)r(ending)h(on)326 1440 y(the)c(v)-5
+b(arian)n(t)23 b(of)h(gID)g(\(pad)g(with)h(0)e(or)g(not,)i(prep)r(end)f
+(a)g(digit)g(coun)n(ter)f(or)g(not,)i(prep)r(end)f(/)g(or)f(not,)i
+(coun)n(t)e(do)n(wn)326 1540 y(or)j(up,)i(.)14 b(.)g(.)g(\))37
+b(and)28 b(app)r(end)f(it)h(to)g(daddy's)f(gID)g(to)h(obtain)f(the)h
+(new)g(no)r(de's)f(gID.)220 1706 y(3.)41 b(insert)27
+b(the)h(new)f(no)r(de)243 1872 y(When)35 b(inserting)g(a)f(subtree,)j
+(the)e(index)g(of)g(the)h(ro)r(ot)e(of)h(the)g(subtree)g(has)f(to)h(b)r
+(e)h(computed)f(as)f(ab)r(o)n(v)n(e,)i(and)118 1971 y(prep)r(ended)28
+b(to)f(the)h(index)g(of)f(eac)n(h)g(no)r(de)h(of)f(the)h(subtree)f(b)r
+(efore)h(insertion.)243 2071 y(Remark)e(that)i(only)f(the)h(paren)n(t)f
+(no)r(de)h(has)f(to)g(b)r(e)h(up)r(dated)g(on)f(insertion.)118
+2303 y Fm(3.5)112 b(Selecting)36 b(the)h(ancestors)h(of)g(a)g(no)s(de)
+118 2457 y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l(e)l(e)243
+2556 y Fh(Y)-7 b(ou)27 b(can)g(sp)r(ecify)h(all)g(ancestors)d(of)j(a)f
+(no)r(de)h(in)f(a)h(single)f(SQL)g(statemen)n(t;)g(for)g(instance)h
+(for)f(vgID)326 2722 y Fd(...)42 b(WHERE)f('/25/6/7')f(LIKE)i(\(id)g
+(||)h('/\045'\))f(AND)g(id)h(<)g('/25/6/7')118 2888 y
+Fh(The)31 b(second)e(part)h(of)h(the)g(clause,)f(while)h(logically)e
+(redundan)n(t,)h(is)h(a)f(\020hin)n(t\021)37 b(to)30
+b(the)h(optimizer.)45 b(A)n(t)31 b(least)f(in)g(P)n(ost-)118
+2988 y(greSQL,)c(without)i(it)g(the)g(optimizer)f(will)h(c)n(ho)r(ose)e
+(a)i(sequen)n(tial)e(scan)h(of)h(the)g(table)f(and)h(disregard)d(the)j
+(index.)118 3220 y Fm(3.6)112 b(Selecting)36 b(all)g(lea)m(v)m(es)118
+3374 y Fg(Cost:)h Fe(sc)l(an)30 b(of)g(the)g(tr)l(e)l(e)243
+3473 y Fh(A)e(leaf)f(is)g(a)h(no)r(de)f(without)h(descendan)n(ts:)36
+b(it)28 b(has)f(0)g(c)n(hildren.)37 b(Hence)326 3639
+y Fd(...)42 b(WHERE)f(nchildren)f(=)j(0)118 3805 y Fh(If)28
+b(this)g(t)n(yp)r(e)g(of)f(query)g(is)h(often)f(necessary)-7
+b(,)26 b(y)n(ou)h(ma)n(y)g(b)r(e)h(w)n(ell)f(advised)g(to)g(k)n(eep)g
+(an)h(index)f(on)h(tree\(nc)n(hildren\).)118 4038 y Fm(3.7)112
+b(Determining)35 b(if)i(A)g(is)g(a)h(descendan)m(t)g(of)g(B)118
+4191 y Fg(Cost:)f Fe(string)30 b(op)l(er)l(ations,)h(no)f(table)g(ac)l
+(c)l(ess)243 4291 y Fh(This)d(is)h(a)f(pure)g(string)g(op)r(eration)f
+(on)i(the)g(indices,)f(no)g(table)h(access)e(is)i(necessary)-7
+b(.)118 4565 y Fi(4)131 b(Putting)45 b(it)f(all)h(together:)57
+b(a)44 b(P)l(ostgreSQL)f(implemen)l(tation)118 4747 y
+Fh(h)n(ttp://www.p)r(ostgresql.org/mhonarc/pgsq)o(l-sql/)o(20)o(00)o
+(-0)o(4/)o(msg0)o(02)o(67)o(.h)n(tml)243 4847 y(W)-7
+b(e)30 b(describ)r(e)g(here)g(a)g(small)f(pac)n(k)-5
+b(age)29 b(that)i(can)e(b)r(e)i(used)f(for)g(implemen)n(ting)g(gID)g
+(on)g(P)n(ostgreSQL.)f(It)i(can)e(b)r(e)118 4946 y(found)f(at)f(<h)n
+(ttp://...>)243 5046 y(The)21 b(pac)n(k)-5 b(age)21 b(uses)g(the)h(pro)
+r(cedural)e(language)h(PL/PGsql.)35 b(A)22 b(b)r(etter)g(implemen)n
+(tation)g(w)n(ould)f(probably)g(de\034ne)118 5145 y(the)28
+b(gID)g(as)f(new)g(P)n(ostgres)f(t)n(yp)r(es,)i(and)f(co)r(de)g(all)h
+(this)g(in)f(C.)243 5245 y(The)g(\034les)h(should)f(b)r(e)h(loaded)f
+(in)h(alphab)r(etical)f(order.)1987 5653 y(5)p eop
+%%Page: 6 6
+6 5 bop 118 291 a Fm(4.1)112 b(tree0_enco)s(ding.sql)118
+444 y Fh(This)28 b(\034le)f(de\034nes)h(and)f(p)r(opulates)h(the)f
+(table)h(_b160_digits)d(of)j(\020digits\021)33 b(in)28
+b(base)f(160,)326 604 y Fd(CREATE)41 b(TABLE)g(\\_b160\\_digits)d
+(\(deci)j(integer,)f(code)i(char\);)118 764 y Fh(and)28
+b(the)f(t)n(w)n(o)g(functions)326 924 y Fd(CREATE)41
+b(FUNCTION)f(\\_b160\\_encode\(i)o(nt)o(eg)o(er\))d(RETURNS)j(string)
+413 1024 y(AS)j('....')e(LANGUAGE)f('plpgsql';)326 1124
+y(CREATE)h(FUNCTION)f(\\_b160\\_encode\(i)o(nt)o(eg)o(er,)o(in)o(te)o
+(ger)o(\))d(RETURNS)k(string)413 1223 y(AS)i('....')e(LANGUAGE)f
+('plpgsql';)118 1384 y Fh(The)22 b(\034rst)h(function)f(returns)g(a)g
+(v)-5 b(ariable)21 b(size)h(enco)r(ding;)i(the)f(second)e(a)h(\034xed)h
+(size)f(enco)r(ding)g(\(the)h(second)e(parameter)118
+1483 y(is)g(the)h(size\),)g(and)f(raises)e(an)i(exception)g(if)h(the)f
+(n)n(um)n(b)r(er)g(is)g(to)r(o)g(large)e(to)i(b)r(e)h(represen)n(ted)e
+(with)h(the)h(requested)e(n)n(um)n(b)r(er)118 1583 y(of)28
+b(digits.)118 1814 y Fm(4.2)112 b(tree1_de\034ne.sql)118
+1967 y Fh(This)28 b(\034le)f(pro)n(vides)f(a)i(function)326
+2127 y Fd(CREATE)41 b(FUNCTION)f(_tree_create\(tex)o(t,)o(in)o(teg)o
+(er)o(,t)o(ext)o(,t)o(ex)o(t\))d(RETURNS)k(bpchar)413
+2227 y(AS)i('....')e(LANGUAGE)f('plpgsql';)118 2387 y
+Fh(that)e(creates)f(a)h(tree)f(infrastructure)g(of)h(either)g(fgID)g
+(or)f(vgID.)h(Assuming)f(y)n(ou)g(ha)n(v)n(e)g(a)h(table)f(\020m)n
+(ytable\021)44 b(with)118 2487 y(primary)26 b(k)n(ey)h(\020m)n
+(yid\021,)g(then)h(calling)326 2647 y Fd(SELECT)41 b(_tree_create\('m)o
+(yt)o(ree)o(',)o(2,')o(my)o(ta)o(ble)o(',)o('m)o(yid)o('\))o(;)118
+2807 y Fh(will)28 b(cause:)220 2967 y(1.)41 b(the)28
+b(creation)e(of)i(a)f(table)508 3131 y Fd(CREATE)41 b(TABLE)h
+(mytree_bkg\()683 3230 y(gid)g(text)g(PRIMARY)e(KEY,)683
+3330 y(nchildren)f(int,)683 3429 y(sid)j(integer)f(REFERENCES)e
+(mytable\(myid\))508 3529 y(\);)508 3629 y(CREATE)i(UNIQUE)g(INDEX)h
+(mytree_bkg_sid)37 b(ON)43 b(mytree_bkg\(sid\);)326 3792
+y Fh(for)27 b(the)h(tree)f(structure.)220 3955 y(2.)41
+b(the)28 b(creation)e(of)i(a)f(view)508 4118 y Fd(CREATE)41
+b(VIEW)h(mytree)f(AS)639 4218 y(SELECT)g(t.gid,n.*)900
+4317 y(FROM)h(mytable)f(n,)i(mytree_bkg)c(t)900 4417
+y(WHERE)j(t.sid=n.myid;)326 4580 y Fh(with:)35 b(a)23
+b(trigger)e(on)i(UPD)n(A)-7 b(TE)25 b(that)e(blo)r(c)n(ks)g(up)r
+(dating)g(the)h(gid)f(and)g(allo)n(ws)f(up)r(dating)h(the)g(no)r(de)h
+(data,)f(a)g(rule)326 4680 y(on)k(DELETE)i(that)f(deletes)f(the)h
+(corresp)r(onding)e(en)n(try)h(b)r(oth)h(in)g(m)n(ytree_bkg)d(and)j(m)n
+(ytable,)f(and)g(a)g(trigger)326 4779 y(ON)h(INSER)-7
+b(T)30 b(that)f(raises)e(an)h(exception)g(and)g(informs)h(the)f(user)g
+(to)h(use)f(the)h(insertion)f(function)h(describ)r(ed)326
+4879 y(b)r(elo)n(w.)220 5042 y(3.)41 b(t)n(w)n(o)26 b(insertion)h
+(functions)h(that)g(compute)g(automatically)e(the)i(gID)g(of)f(the)h
+(new)g(no)r(de:)425 5205 y Ff(\017)41 b Fh(a)27 b(function)i(m)n
+(ytree_insert\(text,text,in)n(teger,text\))d(for)h(insertion)g(sim)n
+(ultaneosly)f(in)i(b)r(oth)g(tables:)508 5305 y(m)n
+(ytree_insert\('2201','hello',0,'not)15 b(m)n(uc)n(h'\))j(inserts)g(a)g
+(new)g(c)n(hild)h(of)f(2201)f(with)h(data1='hello',)h(data2=0)508
+5404 y(and)28 b(data3='not)e(m)n(uc)n(h')1987 5653 y(6)p
+eop
+%%Page: 7 7
+7 6 bop 425 291 a Ff(\017)41 b Fh(a)27 b(function)i(m)n
+(ytree_insert_no)r(de\(text,in)n(teger\))c(for)i(insertion)g(in)h(m)n
+(ytree_bkg)508 390 y(m)n(ytree_insert\('2201',25\))c(inserts)j(in)h(m)n
+(ytree_bkg)e(a)h(new)h(c)n(hild)f(of)h(2201)d(with)j(sid=25)220
+556 y(4.)41 b(a)27 b(function)h(m)n(ytree_mo)n(v)n(e\(text,text\))e
+(that)i(mo)n(v)n(es)e(subtrees:)326 656 y(m)n(ytree_mo)n(v)n
+(e\('2201','23'\))d(mo)n(v)n(es)j(the)i(subtree)f(ro)r(oted)g(at)g
+(2201)f(to)h(a)h(place)f(b)r(elo)n(w)g(23)f(\(ma)n(yb)r(e)i(2307\))220
+822 y(5.)41 b(a)c(function)g(m)n(ytree_len\(\))g(that)h(returns)e(the)i
+(length)f(of)g(the)h(enco)r(dings)f(used)g(in)h(the)f(gID)g(\(2)h
+(here;)j(0)c(if)326 922 y(v)-5 b(ariable)26 b(size\).)118
+1196 y Fi(5)131 b(Non-tree)44 b(hierarc)l(hies)118 1378
+y Fh(sequence)22 b(as)f(id,)j(table)e(with)h(\(id,g-index\))f(with)g(p)
+r(ossibly)g(man)n(y)g(g-indices)f(for)h(eac)n(h)f(id)h(\(if)h(TOO)f
+(man)n(y)-7 b(,)23 b(bad)f(mo)r(del:)118 1478 y(list)28
+b(all)f(genealogies,)f(i.e.,)h(paths)h(from)f(the)h(ro)r(ot\))118
+1752 y Fi(References)160 1934 y Fh([1])41 b(Philip)28
+b(Greenspun,)g Fe(T)-6 b(r)l(e)l(es)29 b(in)h(Or)l(acle)g(SQL)p
+Fh(,)d(in)h Fg(SQL)k(for)g(W)-8 b(eb)31 b(Nerds)289 2033
+y Fh(<h)n(ttp://photo.net/sql/trees.h)n(tml>)160 2200
+y([2])41 b(Jo)r(e)27 b(Celk)n(o,)f Fe(SQL)j(for)i(Smarties)p
+Fh(,)d(in)g Fg(DBMS)j(Online)p Fh(,)26 b(Marc)n(h)h(to)g(June)h(1996)
+289 2299 y(<h)n(ttp://www.dbmsmag.com/9603d06.h)n(tml>)289
+2399 y(<h)n(ttp://www.dbmsmag.com/9604d06.h)n(tml>)289
+2498 y(<h)n(ttp://www.dbmsmag.com/9605d06.h)n(tml>)289
+2598 y(<h)n(ttp://www.dbmsmag.com/9606d06.h)n(tml>)160
+2764 y([3])41 b(Graeme)26 b(Birc)n(hall,)h Fg(DB2)32
+b(UDB)g(V6.1)f(SQL)h(Co)s(okb)s(o)s(ok)p Fh(,)289 2864
+y(<h)n(ttp://ourw)n(orld.compuserv)n(e.com/homepag)o(es/)o(Gra)o
+(eme_Bir)o(c)n(ha)o(ll/HTM_CO)o(OK)o(.HTM>)1987 5653
+y(7)p eop
+%%Trailer
+end
+userdict /end-hook known{end-hook}if
+%%EOF
diff --git a/source3/lib/ldb/ldb_tdb/ldb_cache.c b/source3/lib/ldb/ldb_tdb/ldb_cache.c
new file mode 100644
index 0000000000..16e8c55aec
--- /dev/null
+++ b/source3/lib/ldb/ldb_tdb/ldb_cache.c
@@ -0,0 +1,560 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb tdb cache functions
+ *
+ * Description: cache special records in a ldb/tdb
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#include "ldb/ldb_tdb/ldb_tdb.h"
+
+#define LTDB_FLAG_CASE_INSENSITIVE (1<<0)
+#define LTDB_FLAG_INTEGER (1<<1)
+#define LTDB_FLAG_HIDDEN (1<<2)
+#define LTDB_FLAG_OBJECTCLASS (1<<3)
+
+int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name);
+
+/* valid attribute flags */
+static const struct {
+ const char *name;
+ int value;
+} ltdb_valid_attr_flags[] = {
+ { "CASE_INSENSITIVE", LTDB_FLAG_CASE_INSENSITIVE },
+ { "INTEGER", LTDB_FLAG_INTEGER },
+ { "HIDDEN", LTDB_FLAG_HIDDEN },
+ { "NONE", 0 },
+ { NULL, 0 }
+};
+
+
+/*
+ de-register any special handlers for @ATTRIBUTES
+*/
+static void ltdb_attributes_unload(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb =
+ (struct ltdb_private *)module->private_data;
+ struct ldb_message *msg;
+ int i;
+
+ if (ltdb->cache->attributes == NULL) {
+ /* no previously loaded attributes */
+ return;
+ }
+
+ msg = ltdb->cache->attributes;
+ for (i=0;i<msg->num_elements;i++) {
+ ldb_remove_attrib_handler(module->ldb, msg->elements[i].name);
+ }
+
+ talloc_free(ltdb->cache->attributes);
+ ltdb->cache->attributes = NULL;
+}
+
+/*
+ add up the attrib flags for a @ATTRIBUTES element
+*/
+static int ltdb_attributes_flags(struct ldb_message_element *el, unsigned *v)
+{
+ int i;
+ unsigned value = 0;
+ for (i=0;i<el->num_values;i++) {
+ int j;
+ for (j=0;ltdb_valid_attr_flags[j].name;j++) {
+ if (strcmp(ltdb_valid_attr_flags[j].name,
+ (char *)el->values[i].data) == 0) {
+ value |= ltdb_valid_attr_flags[j].value;
+ break;
+ }
+ }
+ if (ltdb_valid_attr_flags[j].name == NULL) {
+ return -1;
+ }
+ }
+ *v = value;
+ return 0;
+}
+
+/*
+ register any special handlers from @ATTRIBUTES
+*/
+static int ltdb_attributes_load(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb =
+ (struct ltdb_private *)module->private_data;
+ struct ldb_message *msg = ltdb->cache->attributes;
+ struct ldb_dn *dn;
+ int i;
+
+ dn = ldb_dn_explode(module->ldb, LTDB_ATTRIBUTES);
+ if (dn == NULL) goto failed;
+
+ if (ltdb_search_dn1(module, dn, msg) == -1) {
+ talloc_free(dn);
+ goto failed;
+ }
+ talloc_free(dn);
+ /* mapping these flags onto ldap 'syntaxes' isn't strictly correct,
+ but its close enough for now */
+ for (i=0;i<msg->num_elements;i++) {
+ unsigned flags;
+ const char *syntax;
+ const struct ldb_attrib_handler *h;
+ struct ldb_attrib_handler h2;
+
+ if (ltdb_attributes_flags(&msg->elements[i], &flags) != 0) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Invalid @ATTRIBUTES element for '%s'\n", msg->elements[i].name);
+ goto failed;
+ }
+ switch (flags & ~LTDB_FLAG_HIDDEN) {
+ case 0:
+ syntax = LDB_SYNTAX_OCTET_STRING;
+ break;
+ case LTDB_FLAG_CASE_INSENSITIVE:
+ syntax = LDB_SYNTAX_DIRECTORY_STRING;
+ break;
+ case LTDB_FLAG_INTEGER:
+ syntax = LDB_SYNTAX_INTEGER;
+ break;
+ default:
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR,
+ "Invalid flag combination 0x%x for '%s' in @ATTRIBUTES\n",
+ flags, msg->elements[i].name);
+ goto failed;
+ }
+
+ h = ldb_attrib_handler_syntax(module->ldb, syntax);
+ if (h == NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR,
+ "Invalid attribute syntax '%s' for '%s' in @ATTRIBUTES\n",
+ syntax, msg->elements[i].name);
+ goto failed;
+ }
+ h2 = *h;
+ h2.attr = msg->elements[i].name;
+ h2.flags |= LDB_ATTR_FLAG_ALLOCATED;
+ if (ldb_set_attrib_handlers(module->ldb, &h2, 1) != 0) {
+ goto failed;
+ }
+ }
+
+ return 0;
+failed:
+ return -1;
+}
+
+
+/*
+ register any subclasses from @SUBCLASSES
+*/
+static int ltdb_subclasses_load(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb =
+ (struct ltdb_private *)module->private_data;
+ struct ldb_message *msg = ltdb->cache->subclasses;
+ struct ldb_dn *dn;
+ int i, j;
+
+ dn = ldb_dn_explode(module->ldb, LTDB_SUBCLASSES);
+ if (dn == NULL) goto failed;
+
+ if (ltdb_search_dn1(module, dn, msg) == -1) {
+ talloc_free(dn);
+ goto failed;
+ }
+ talloc_free(dn);
+
+ for (i=0;i<msg->num_elements;i++) {
+ struct ldb_message_element *el = &msg->elements[i];
+ for (j=0;j<el->num_values;j++) {
+ if (ldb_subclass_add(module->ldb, el->name,
+ (char *)el->values[j].data) != 0) {
+ goto failed;
+ }
+ }
+ }
+
+ return 0;
+failed:
+ return -1;
+}
+
+
+/*
+ de-register any @SUBCLASSES
+*/
+static void ltdb_subclasses_unload(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb =
+ (struct ltdb_private *)module->private_data;
+ struct ldb_message *msg;
+ int i;
+
+ if (ltdb->cache->subclasses == NULL) {
+ /* no previously loaded subclasses */
+ return;
+ }
+
+ msg = ltdb->cache->subclasses;
+ for (i=0;i<msg->num_elements;i++) {
+ ldb_subclass_remove(module->ldb, msg->elements[i].name);
+ }
+
+ talloc_free(ltdb->cache->subclasses);
+ ltdb->cache->subclasses = NULL;
+}
+
+
+/*
+ initialise the baseinfo record
+*/
+static int ltdb_baseinfo_init(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb =
+ (struct ltdb_private *)module->private_data;
+ struct ldb_message *msg;
+ struct ldb_message_element el;
+ struct ldb_val val;
+ int ret;
+ /* the initial sequence number must be different from the one
+ set in ltdb_cache_free(). Thanks to Jon for pointing this
+ out. */
+ const char *initial_sequence_number = "1";
+
+ ltdb->sequence_number = atof(initial_sequence_number);
+
+ msg = talloc(ltdb, struct ldb_message);
+ if (msg == NULL) {
+ goto failed;
+ }
+
+ msg->num_elements = 1;
+ msg->elements = &el;
+ msg->dn = ldb_dn_explode(msg, LTDB_BASEINFO);
+ if (!msg->dn) {
+ goto failed;
+ }
+ el.name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER);
+ if (!el.name) {
+ goto failed;
+ }
+ el.values = &val;
+ el.num_values = 1;
+ el.flags = 0;
+ val.data = (uint8_t *)talloc_strdup(msg, initial_sequence_number);
+ if (!val.data) {
+ goto failed;
+ }
+ val.length = 1;
+
+ ret = ltdb_store(module, msg, TDB_INSERT);
+
+ talloc_free(msg);
+
+ return ret;
+
+failed:
+ talloc_free(msg);
+ errno = ENOMEM;
+ return -1;
+}
+
+/*
+ free any cache records
+ */
+static void ltdb_cache_free(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb =
+ (struct ltdb_private *)module->private_data;
+
+ ltdb->sequence_number = 0;
+ talloc_free(ltdb->cache);
+ ltdb->cache = NULL;
+}
+
+/*
+ force a cache reload
+*/
+int ltdb_cache_reload(struct ldb_module *module)
+{
+ ltdb_attributes_unload(module);
+ ltdb_subclasses_unload(module);
+ ltdb_cache_free(module);
+ return ltdb_cache_load(module);
+}
+
+/*
+ load the cache records
+*/
+int ltdb_cache_load(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb =
+ (struct ltdb_private *)module->private_data;
+ struct ldb_dn *baseinfo_dn = NULL;
+ struct ldb_dn *indexlist_dn = NULL;
+ uint64_t seq;
+ struct ldb_message *baseinfo = NULL;
+
+ /* a very fast check to avoid extra database reads */
+ if (ltdb->cache != NULL &&
+ tdb_get_seqnum(ltdb->tdb) == ltdb->tdb_seqnum) {
+ return 0;
+ }
+
+ if (ltdb->cache == NULL) {
+ ltdb->cache = talloc_zero(ltdb, struct ltdb_cache);
+ if (ltdb->cache == NULL) goto failed;
+ ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message);
+ ltdb->cache->subclasses = talloc_zero(ltdb->cache, struct ldb_message);
+ ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message);
+ if (ltdb->cache->indexlist == NULL ||
+ ltdb->cache->subclasses == NULL ||
+ ltdb->cache->attributes == NULL) {
+ goto failed;
+ }
+ }
+
+ baseinfo = talloc(ltdb->cache, struct ldb_message);
+ if (baseinfo == NULL) goto failed;
+
+ baseinfo_dn = ldb_dn_explode(module->ldb, LTDB_BASEINFO);
+ if (baseinfo_dn == NULL) goto failed;
+
+ if (ltdb_search_dn1(module, baseinfo_dn, baseinfo) == -1) {
+ goto failed;
+ }
+
+ /* possibly initialise the baseinfo */
+ if (!baseinfo->dn) {
+ if (ltdb_baseinfo_init(module) != 0) {
+ goto failed;
+ }
+ if (ltdb_search_dn1(module, baseinfo_dn, baseinfo) != 1) {
+ goto failed;
+ }
+ }
+
+ ltdb->tdb_seqnum = tdb_get_seqnum(ltdb->tdb);
+
+ /* if the current internal sequence number is the same as the one
+ in the database then assume the rest of the cache is OK */
+ seq = ldb_msg_find_attr_as_uint64(baseinfo, LTDB_SEQUENCE_NUMBER, 0);
+ if (seq == ltdb->sequence_number) {
+ goto done;
+ }
+ ltdb->sequence_number = seq;
+
+ talloc_free(ltdb->cache->last_attribute.name);
+ memset(&ltdb->cache->last_attribute, 0, sizeof(ltdb->cache->last_attribute));
+
+ ltdb_attributes_unload(module);
+ ltdb_subclasses_unload(module);
+
+ talloc_free(ltdb->cache->indexlist);
+ talloc_free(ltdb->cache->subclasses);
+
+ ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message);
+ ltdb->cache->subclasses = talloc_zero(ltdb->cache, struct ldb_message);
+ ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message);
+ if (ltdb->cache->indexlist == NULL ||
+ ltdb->cache->subclasses == NULL ||
+ ltdb->cache->attributes == NULL) {
+ goto failed;
+ }
+
+ indexlist_dn = ldb_dn_explode(module->ldb, LTDB_INDEXLIST);
+ if (indexlist_dn == NULL) goto failed;
+
+ if (ltdb_search_dn1(module, indexlist_dn, ltdb->cache->indexlist) == -1) {
+ goto failed;
+ }
+
+ if (ltdb_attributes_load(module) == -1) {
+ goto failed;
+ }
+ if (ltdb_subclasses_load(module) == -1) {
+ goto failed;
+ }
+
+done:
+ talloc_free(baseinfo);
+ talloc_free(baseinfo_dn);
+ talloc_free(indexlist_dn);
+ return 0;
+
+failed:
+ talloc_free(baseinfo);
+ talloc_free(baseinfo_dn);
+ talloc_free(indexlist_dn);
+ return -1;
+}
+
+
+/*
+ increase the sequence number to indicate a database change
+*/
+int ltdb_increase_sequence_number(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb =
+ (struct ltdb_private *)module->private_data;
+ struct ldb_message *msg;
+ struct ldb_message_element el[2];
+ struct ldb_val val;
+ struct ldb_val val_time;
+ time_t t = time(NULL);
+ char *s = NULL;
+ int ret;
+
+ msg = talloc(ltdb, struct ldb_message);
+ if (msg == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ s = talloc_asprintf(msg, "%llu", ltdb->sequence_number+1);
+ if (!s) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ msg->num_elements = ARRAY_SIZE(el);
+ msg->elements = el;
+ msg->dn = ldb_dn_explode(msg, LTDB_BASEINFO);
+ if (msg->dn == NULL) {
+ talloc_free(msg);
+ errno = ENOMEM;
+ return -1;
+ }
+ el[0].name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER);
+ if (el[0].name == NULL) {
+ talloc_free(msg);
+ errno = ENOMEM;
+ return -1;
+ }
+ el[0].values = &val;
+ el[0].num_values = 1;
+ el[0].flags = LDB_FLAG_MOD_REPLACE;
+ val.data = (uint8_t *)s;
+ val.length = strlen(s);
+
+ el[1].name = talloc_strdup(msg, LTDB_MOD_TIMESTAMP);
+ if (el[1].name == NULL) {
+ talloc_free(msg);
+ errno = ENOMEM;
+ return -1;
+ }
+ el[1].values = &val_time;
+ el[1].num_values = 1;
+ el[1].flags = LDB_FLAG_MOD_REPLACE;
+
+ s = ldb_timestring(msg, t);
+ if (s == NULL) {
+ return -1;
+ }
+
+ val_time.data = (uint8_t *)s;
+ val_time.length = strlen(s);
+
+ ret = ltdb_modify_internal(module, msg);
+
+ talloc_free(msg);
+
+ if (ret == 0) {
+ ltdb->sequence_number += 1;
+ }
+
+ return ret;
+}
+
+
+/*
+ return the attribute flags from the @ATTRIBUTES record
+ for the given attribute
+*/
+int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name)
+{
+ struct ltdb_private *ltdb =
+ (struct ltdb_private *)module->private_data;
+ const struct ldb_message_element *attr_el;
+ int i, j, ret=0;
+
+ if (ltdb->cache->last_attribute.name &&
+ ldb_attr_cmp(ltdb->cache->last_attribute.name, attr_name) == 0) {
+ return ltdb->cache->last_attribute.flags;
+ }
+
+ /* objectclass is a special default case */
+ if (ldb_attr_cmp(attr_name, LTDB_OBJECTCLASS) == 0) {
+ ret = LTDB_FLAG_OBJECTCLASS | LTDB_FLAG_CASE_INSENSITIVE;
+ }
+
+ attr_el = ldb_msg_find_element(ltdb->cache->attributes, attr_name);
+
+ if (!attr_el) {
+ /* check if theres a wildcard attribute */
+ attr_el = ldb_msg_find_element(ltdb->cache->attributes, "*");
+
+ if (!attr_el) {
+ return ret;
+ }
+ }
+
+ for (i = 0; i < attr_el->num_values; i++) {
+ for (j=0; ltdb_valid_attr_flags[j].name; j++) {
+ if (strcmp(ltdb_valid_attr_flags[j].name,
+ (char *)attr_el->values[i].data) == 0) {
+ ret |= ltdb_valid_attr_flags[j].value;
+ }
+ }
+ }
+
+ talloc_free(ltdb->cache->last_attribute.name);
+
+ ltdb->cache->last_attribute.name = talloc_strdup(ltdb->cache, attr_name);
+ ltdb->cache->last_attribute.flags = ret;
+
+ return ret;
+}
+
+int ltdb_check_at_attributes_values(const struct ldb_val *value)
+{
+ int i;
+
+ for (i = 0; ltdb_valid_attr_flags[i].name != NULL; i++) {
+ if ((strcmp(ltdb_valid_attr_flags[i].name, (char *)value->data) == 0)) {
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
diff --git a/source3/lib/ldb/ldb_tdb/ldb_index.c b/source3/lib/ldb/ldb_tdb/ldb_index.c
new file mode 100644
index 0000000000..5545661f7a
--- /dev/null
+++ b/source3/lib/ldb/ldb_tdb/ldb_index.c
@@ -0,0 +1,1178 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb tdb backend - indexing
+ *
+ * Description: indexing routines for ldb tdb backend
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#include "ldb/ldb_tdb/ldb_tdb.h"
+
+/*
+ find an element in a list, using the given comparison function and
+ assuming that the list is already sorted using comp_fn
+
+ return -1 if not found, or the index of the first occurance of needle if found
+*/
+static int ldb_list_find(const void *needle,
+ const void *base, size_t nmemb, size_t size,
+ comparison_fn_t comp_fn)
+{
+ const char *base_p = (const char *)base;
+ size_t min_i, max_i, test_i;
+
+ if (nmemb == 0) {
+ return -1;
+ }
+
+ min_i = 0;
+ max_i = nmemb-1;
+
+ while (min_i < max_i) {
+ int r;
+
+ test_i = (min_i + max_i) / 2;
+ /* the following cast looks strange, but is
+ correct. The key to understanding it is that base_p
+ is a pointer to an array of pointers, so we have to
+ dereference it after casting to void **. The strange
+ const in the middle gives us the right type of pointer
+ after the dereference (tridge) */
+ r = comp_fn(needle, *(void * const *)(base_p + (size * test_i)));
+ if (r == 0) {
+ /* scan back for first element */
+ while (test_i > 0 &&
+ comp_fn(needle, *(void * const *)(base_p + (size * (test_i-1)))) == 0) {
+ test_i--;
+ }
+ return test_i;
+ }
+ if (r < 0) {
+ if (test_i == 0) {
+ return -1;
+ }
+ max_i = test_i - 1;
+ }
+ if (r > 0) {
+ min_i = test_i + 1;
+ }
+ }
+
+ if (comp_fn(needle, *(void * const *)(base_p + (size * min_i))) == 0) {
+ return min_i;
+ }
+
+ return -1;
+}
+
+struct dn_list {
+ unsigned int count;
+ char **dn;
+};
+
+/*
+ return the dn key to be used for an index
+ caller frees
+*/
+static struct ldb_dn *ldb_dn_key(struct ldb_context *ldb,
+ const char *attr, const struct ldb_val *value)
+{
+ struct ldb_dn *ret;
+ char *dn;
+ struct ldb_val v;
+ const struct ldb_attrib_handler *h;
+ char *attr_folded;
+
+ attr_folded = ldb_attr_casefold(ldb, attr);
+ if (!attr_folded) {
+ return NULL;
+ }
+
+ h = ldb_attrib_handler(ldb, attr);
+ if (h->canonicalise_fn(ldb, ldb, value, &v) != 0) {
+ /* canonicalisation can be refused. For example,
+ a attribute that takes wildcards will refuse to canonicalise
+ if the value contains a wildcard */
+ talloc_free(attr_folded);
+ return NULL;
+ }
+ if (ldb_should_b64_encode(&v)) {
+ char *vstr = ldb_base64_encode(ldb, (char *)v.data, v.length);
+ if (!vstr) return NULL;
+ dn = talloc_asprintf(ldb, "%s:%s::%s", LTDB_INDEX, attr_folded, vstr);
+ talloc_free(vstr);
+ if (v.data != value->data) {
+ talloc_free(v.data);
+ }
+ talloc_free(attr_folded);
+ if (dn == NULL) return NULL;
+ goto done;
+ }
+
+ dn = talloc_asprintf(ldb, "%s:%s:%.*s",
+ LTDB_INDEX, attr_folded, (int)v.length, (char *)v.data);
+
+ if (v.data != value->data) {
+ talloc_free(v.data);
+ }
+ talloc_free(attr_folded);
+
+done:
+ ret = ldb_dn_explode(ldb, dn);
+ talloc_free(dn);
+ return ret;
+}
+
+/*
+ see if a attribute value is in the list of indexed attributes
+*/
+static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr,
+ unsigned int *v_idx, const char *key)
+{
+ unsigned int i, j;
+ for (i=0;i<msg->num_elements;i++) {
+ if (ldb_attr_cmp(msg->elements[i].name, key) == 0) {
+ const struct ldb_message_element *el =
+ &msg->elements[i];
+ for (j=0;j<el->num_values;j++) {
+ if (ldb_attr_cmp((char *)el->values[j].data, attr) == 0) {
+ if (v_idx) {
+ *v_idx = j;
+ }
+ return i;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+/* used in sorting dn lists */
+static int list_cmp(const char **s1, const char **s2)
+{
+ return strcmp(*s1, *s2);
+}
+
+/*
+ return a list of dn's that might match a simple indexed search or
+ */
+static int ltdb_index_dn_simple(struct ldb_module *module,
+ const struct ldb_parse_tree *tree,
+ const struct ldb_message *index_list,
+ struct dn_list *list)
+{
+ struct ldb_context *ldb = module->ldb;
+ struct ldb_dn *dn;
+ int ret;
+ unsigned int i, j;
+ struct ldb_message *msg;
+
+ list->count = 0;
+ list->dn = NULL;
+
+ /* if the attribute isn't in the list of indexed attributes then
+ this node needs a full search */
+ if (ldb_msg_find_idx(index_list, tree->u.equality.attr, NULL, LTDB_IDXATTR) == -1) {
+ return -1;
+ }
+
+ /* the attribute is indexed. Pull the list of DNs that match the
+ search criterion */
+ dn = ldb_dn_key(ldb, tree->u.equality.attr, &tree->u.equality.value);
+ if (!dn) return -1;
+
+ msg = talloc(list, struct ldb_message);
+ if (msg == NULL) {
+ return -1;
+ }
+
+ ret = ltdb_search_dn1(module, dn, msg);
+ talloc_free(dn);
+ if (ret == 0 || ret == -1) {
+ return ret;
+ }
+
+ for (i=0;i<msg->num_elements;i++) {
+ struct ldb_message_element *el;
+
+ if (strcmp(msg->elements[i].name, LTDB_IDX) != 0) {
+ continue;
+ }
+
+ el = &msg->elements[i];
+
+ list->dn = talloc_array(list, char *, el->num_values);
+ if (!list->dn) {
+ talloc_free(msg);
+ return -1;
+ }
+
+ for (j=0;j<el->num_values;j++) {
+ list->dn[list->count] =
+ talloc_strdup(list->dn, (char *)el->values[j].data);
+ if (!list->dn[list->count]) {
+ talloc_free(msg);
+ return -1;
+ }
+ list->count++;
+ }
+ }
+
+ talloc_free(msg);
+
+ if (list->count > 1) {
+ qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t) list_cmp);
+ }
+
+ return 1;
+}
+
+
+static int list_union(struct ldb_context *, struct dn_list *, const struct dn_list *);
+
+/*
+ return a list of dn's that might match a simple indexed search on
+ the special objectclass attribute
+ */
+static int ltdb_index_dn_objectclass(struct ldb_module *module,
+ const struct ldb_parse_tree *tree,
+ const struct ldb_message *index_list,
+ struct dn_list *list)
+{
+ struct ldb_context *ldb = module->ldb;
+ unsigned int i;
+ int ret;
+ const char *target = (const char *)tree->u.equality.value.data;
+ const char **subclasses;
+
+ list->count = 0;
+ list->dn = NULL;
+
+ ret = ltdb_index_dn_simple(module, tree, index_list, list);
+
+ subclasses = ldb_subclass_list(module->ldb, target);
+
+ if (subclasses == NULL) {
+ return ret;
+ }
+
+ for (i=0;subclasses[i];i++) {
+ struct ldb_parse_tree tree2;
+ struct dn_list *list2;
+ tree2.operation = LDB_OP_EQUALITY;
+ tree2.u.equality.attr = LTDB_OBJECTCLASS;
+ if (!tree2.u.equality.attr) {
+ return -1;
+ }
+ tree2.u.equality.value.data =
+ (uint8_t *)talloc_strdup(list, subclasses[i]);
+ if (tree2.u.equality.value.data == NULL) {
+ return -1;
+ }
+ tree2.u.equality.value.length = strlen(subclasses[i]);
+ list2 = talloc(list, struct dn_list);
+ if (list2 == NULL) {
+ talloc_free(tree2.u.equality.value.data);
+ return -1;
+ }
+ if (ltdb_index_dn_objectclass(module, &tree2,
+ index_list, list2) == 1) {
+ if (list->count == 0) {
+ *list = *list2;
+ ret = 1;
+ } else {
+ list_union(ldb, list, list2);
+ talloc_free(list2);
+ }
+ }
+ talloc_free(tree2.u.equality.value.data);
+ }
+
+ return ret;
+}
+
+/*
+ return a list of dn's that might match a leaf indexed search
+ */
+static int ltdb_index_dn_leaf(struct ldb_module *module,
+ const struct ldb_parse_tree *tree,
+ const struct ldb_message *index_list,
+ struct dn_list *list)
+{
+ if (ldb_attr_cmp(tree->u.equality.attr, LTDB_OBJECTCLASS) == 0) {
+ return ltdb_index_dn_objectclass(module, tree, index_list, list);
+ }
+ if (ldb_attr_dn(tree->u.equality.attr) == 0) {
+ list->dn = talloc_array(list, char *, 1);
+ if (list->dn == NULL) {
+ ldb_oom(module->ldb);
+ return -1;
+ }
+ list->dn[0] = talloc_strdup(list->dn, (char *)tree->u.equality.value.data);
+ if (list->dn[0] == NULL) {
+ ldb_oom(module->ldb);
+ return -1;
+ }
+ list->count = 1;
+ return 1;
+ }
+ return ltdb_index_dn_simple(module, tree, index_list, list);
+}
+
+
+/*
+ list intersection
+ list = list & list2
+ relies on the lists being sorted
+*/
+static int list_intersect(struct ldb_context *ldb,
+ struct dn_list *list, const struct dn_list *list2)
+{
+ struct dn_list *list3;
+ unsigned int i;
+
+ if (list->count == 0 || list2->count == 0) {
+ /* 0 & X == 0 */
+ return 0;
+ }
+
+ list3 = talloc(ldb, struct dn_list);
+ if (list3 == NULL) {
+ return -1;
+ }
+
+ list3->dn = talloc_array(list3, char *, list->count);
+ if (!list3->dn) {
+ talloc_free(list3);
+ return -1;
+ }
+ list3->count = 0;
+
+ for (i=0;i<list->count;i++) {
+ if (ldb_list_find(list->dn[i], list2->dn, list2->count,
+ sizeof(char *), (comparison_fn_t)strcmp) != -1) {
+ list3->dn[list3->count] = talloc_move(list3->dn, &list->dn[i]);
+ list3->count++;
+ } else {
+ talloc_free(list->dn[i]);
+ }
+ }
+
+ talloc_free(list->dn);
+ list->dn = talloc_move(list, &list3->dn);
+ list->count = list3->count;
+ talloc_free(list3);
+
+ return 0;
+}
+
+
+/*
+ list union
+ list = list | list2
+ relies on the lists being sorted
+*/
+static int list_union(struct ldb_context *ldb,
+ struct dn_list *list, const struct dn_list *list2)
+{
+ unsigned int i;
+ char **d;
+ unsigned int count = list->count;
+
+ if (list->count == 0 && list2->count == 0) {
+ /* 0 | 0 == 0 */
+ return 0;
+ }
+
+ d = talloc_realloc(list, list->dn, char *, list->count + list2->count);
+ if (!d) {
+ return -1;
+ }
+ list->dn = d;
+
+ for (i=0;i<list2->count;i++) {
+ if (ldb_list_find(list2->dn[i], list->dn, count,
+ sizeof(char *), (comparison_fn_t)strcmp) == -1) {
+ list->dn[list->count] = talloc_strdup(list->dn, list2->dn[i]);
+ if (!list->dn[list->count]) {
+ return -1;
+ }
+ list->count++;
+ }
+ }
+
+ if (list->count != count) {
+ qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t)list_cmp);
+ }
+
+ return 0;
+}
+
+static int ltdb_index_dn(struct ldb_module *module,
+ const struct ldb_parse_tree *tree,
+ const struct ldb_message *index_list,
+ struct dn_list *list);
+
+
+/*
+ OR two index results
+ */
+static int ltdb_index_dn_or(struct ldb_module *module,
+ const struct ldb_parse_tree *tree,
+ const struct ldb_message *index_list,
+ struct dn_list *list)
+{
+ struct ldb_context *ldb = module->ldb;
+ unsigned int i;
+ int ret;
+
+ ret = -1;
+ list->dn = NULL;
+ list->count = 0;
+
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ struct dn_list *list2;
+ int v;
+
+ list2 = talloc(module, struct dn_list);
+ if (list2 == NULL) {
+ return -1;
+ }
+
+ v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2);
+
+ if (v == 0) {
+ /* 0 || X == X */
+ if (ret == -1) {
+ ret = 0;
+ }
+ talloc_free(list2);
+ continue;
+ }
+
+ if (v == -1) {
+ /* 1 || X == 1 */
+ talloc_free(list->dn);
+ talloc_free(list2);
+ return -1;
+ }
+
+ if (ret == -1) {
+ ret = 1;
+ list->dn = talloc_move(list, &list2->dn);
+ list->count = list2->count;
+ } else {
+ if (list_union(ldb, list, list2) == -1) {
+ talloc_free(list2);
+ return -1;
+ }
+ ret = 1;
+ }
+ talloc_free(list2);
+ }
+
+ if (list->count == 0) {
+ return 0;
+ }
+
+ return ret;
+}
+
+
+/*
+ NOT an index results
+ */
+static int ltdb_index_dn_not(struct ldb_module *module,
+ const struct ldb_parse_tree *tree,
+ const struct ldb_message *index_list,
+ struct dn_list *list)
+{
+ /* the only way to do an indexed not would be if we could
+ negate the not via another not or if we knew the total
+ number of database elements so we could know that the
+ existing expression covered the whole database.
+
+ instead, we just give up, and rely on a full index scan
+ (unless an outer & manages to reduce the list)
+ */
+ return -1;
+}
+
+/*
+ AND two index results
+ */
+static int ltdb_index_dn_and(struct ldb_module *module,
+ const struct ldb_parse_tree *tree,
+ const struct ldb_message *index_list,
+ struct dn_list *list)
+{
+ struct ldb_context *ldb = module->ldb;
+ unsigned int i;
+ int ret;
+
+ ret = -1;
+ list->dn = NULL;
+ list->count = 0;
+
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ struct dn_list *list2;
+ int v;
+
+ list2 = talloc(module, struct dn_list);
+ if (list2 == NULL) {
+ return -1;
+ }
+
+ v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2);
+
+ if (v == 0) {
+ /* 0 && X == 0 */
+ talloc_free(list->dn);
+ talloc_free(list2);
+ return 0;
+ }
+
+ if (v == -1) {
+ talloc_free(list2);
+ continue;
+ }
+
+ if (ret == -1) {
+ ret = 1;
+ talloc_free(list->dn);
+ list->dn = talloc_move(list, &list2->dn);
+ list->count = list2->count;
+ } else {
+ if (list_intersect(ldb, list, list2) == -1) {
+ talloc_free(list2);
+ return -1;
+ }
+ }
+
+ talloc_free(list2);
+
+ if (list->count == 0) {
+ talloc_free(list->dn);
+ return 0;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ return a list of dn's that might match a indexed search or
+ -1 if an error. return 0 for no matches, or 1 for matches
+ */
+static int ltdb_index_dn(struct ldb_module *module,
+ const struct ldb_parse_tree *tree,
+ const struct ldb_message *index_list,
+ struct dn_list *list)
+{
+ int ret = -1;
+
+ switch (tree->operation) {
+ case LDB_OP_AND:
+ ret = ltdb_index_dn_and(module, tree, index_list, list);
+ break;
+
+ case LDB_OP_OR:
+ ret = ltdb_index_dn_or(module, tree, index_list, list);
+ break;
+
+ case LDB_OP_NOT:
+ ret = ltdb_index_dn_not(module, tree, index_list, list);
+ break;
+
+ case LDB_OP_EQUALITY:
+ ret = ltdb_index_dn_leaf(module, tree, index_list, list);
+ break;
+
+ case LDB_OP_SUBSTRING:
+ case LDB_OP_GREATER:
+ case LDB_OP_LESS:
+ case LDB_OP_PRESENT:
+ case LDB_OP_APPROX:
+ case LDB_OP_EXTENDED:
+ /* we can't index with fancy bitops yet */
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ filter a candidate dn_list from an indexed search into a set of results
+ extracting just the given attributes
+*/
+static int ltdb_index_filter(const struct dn_list *dn_list,
+ struct ldb_handle *handle)
+{
+ struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
+ struct ldb_reply *ares = NULL;
+ unsigned int i;
+
+ if (!ac) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ for (i = 0; i < dn_list->count; i++) {
+ struct ldb_dn *dn;
+ int ret;
+
+ ares = talloc_zero(ac, struct ldb_reply);
+ if (!ares) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ handle->state = LDB_ASYNC_DONE;
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ares->message = ldb_msg_new(ares);
+ if (!ares->message) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ handle->state = LDB_ASYNC_DONE;
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+
+ dn = ldb_dn_explode(ares->message, dn_list->dn[i]);
+ if (dn == NULL) {
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ltdb_search_dn1(ac->module, dn, ares->message);
+ talloc_free(dn);
+ if (ret == 0) {
+ /* the record has disappeared? yes, this can happen */
+ talloc_free(ares);
+ continue;
+ }
+
+ if (ret == -1) {
+ /* an internal error */
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, ac->base, ac->scope)) {
+ talloc_free(ares);
+ continue;
+ }
+
+ /* filter the attributes that the user wants */
+ ret = ltdb_filter_attrs(ares->message, ac->attrs);
+
+ if (ret == -1) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ handle->state = LDB_ASYNC_DONE;
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ares->type = LDB_REPLY_ENTRY;
+ handle->state = LDB_ASYNC_PENDING;
+ handle->status = ac->callback(ac->module->ldb, ac->context, ares);
+
+ if (handle->status != LDB_SUCCESS) {
+ handle->state = LDB_ASYNC_DONE;
+ return handle->status;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+/*
+ search the database with a LDAP-like expression using indexes
+ returns -1 if an indexed search is not possible, in which
+ case the caller should call ltdb_search_full()
+*/
+int ltdb_search_indexed(struct ldb_handle *handle)
+{
+ struct ltdb_context *ac;
+ struct ltdb_private *ltdb;
+ struct dn_list *dn_list;
+ int ret;
+
+ if (!(ac = talloc_get_type(handle->private_data,
+ struct ltdb_context)) ||
+ !(ltdb = talloc_get_type(ac->module->private_data,
+ struct ltdb_private))) {
+ return -1;
+ }
+
+ if (ltdb->cache->indexlist->num_elements == 0 &&
+ ac->scope != LDB_SCOPE_BASE) {
+ /* no index list? must do full search */
+ return -1;
+ }
+
+ dn_list = talloc(handle, struct dn_list);
+ if (dn_list == NULL) {
+ return -1;
+ }
+
+ if (ac->scope == LDB_SCOPE_BASE) {
+ /* with BASE searches only one DN can match */
+ dn_list->dn = talloc_array(dn_list, char *, 1);
+ if (dn_list->dn == NULL) {
+ ldb_oom(ac->module->ldb);
+ return -1;
+ }
+ dn_list->dn[0] = ldb_dn_linearize(dn_list, ac->base);
+ if (dn_list->dn[0] == NULL) {
+ ldb_oom(ac->module->ldb);
+ return -1;
+ }
+ dn_list->count = 1;
+ ret = 1;
+ } else {
+ ret = ltdb_index_dn(ac->module, ac->tree, ltdb->cache->indexlist, dn_list);
+ }
+
+ if (ret == 1) {
+ /* we've got a candidate list - now filter by the full tree
+ and extract the needed attributes */
+ ret = ltdb_index_filter(dn_list, handle);
+ handle->status = ret;
+ handle->state = LDB_ASYNC_DONE;
+ }
+
+ talloc_free(dn_list);
+
+ return ret;
+}
+
+/*
+ add a index element where this is the first indexed DN for this value
+*/
+static int ltdb_index_add1_new(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ struct ldb_message_element *el,
+ const char *dn)
+{
+ struct ldb_message_element *el2;
+
+ /* add another entry */
+ el2 = talloc_realloc(msg, msg->elements,
+ struct ldb_message_element, msg->num_elements+1);
+ if (!el2) {
+ return -1;
+ }
+
+ msg->elements = el2;
+ msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, LTDB_IDX);
+ if (!msg->elements[msg->num_elements].name) {
+ return -1;
+ }
+ msg->elements[msg->num_elements].num_values = 0;
+ msg->elements[msg->num_elements].values = talloc(msg->elements, struct ldb_val);
+ if (!msg->elements[msg->num_elements].values) {
+ return -1;
+ }
+ msg->elements[msg->num_elements].values[0].length = strlen(dn);
+ msg->elements[msg->num_elements].values[0].data = discard_const_p(uint8_t, dn);
+ msg->elements[msg->num_elements].num_values = 1;
+ msg->num_elements++;
+
+ return 0;
+}
+
+
+/*
+ add a index element where this is not the first indexed DN for this
+ value
+*/
+static int ltdb_index_add1_add(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ struct ldb_message_element *el,
+ int idx,
+ const char *dn)
+{
+ struct ldb_val *v2;
+ unsigned int i;
+
+ /* for multi-valued attributes we can end up with repeats */
+ for (i=0;i<msg->elements[idx].num_values;i++) {
+ if (strcmp(dn, (char *)msg->elements[idx].values[i].data) == 0) {
+ return 0;
+ }
+ }
+
+ v2 = talloc_realloc(msg->elements, msg->elements[idx].values,
+ struct ldb_val,
+ msg->elements[idx].num_values+1);
+ if (!v2) {
+ return -1;
+ }
+ msg->elements[idx].values = v2;
+
+ msg->elements[idx].values[msg->elements[idx].num_values].length = strlen(dn);
+ msg->elements[idx].values[msg->elements[idx].num_values].data = discard_const_p(uint8_t, dn);
+ msg->elements[idx].num_values++;
+
+ return 0;
+}
+
+/*
+ add an index entry for one message element
+*/
+static int ltdb_index_add1(struct ldb_module *module, const char *dn,
+ struct ldb_message_element *el, int v_idx)
+{
+ struct ldb_context *ldb = module->ldb;
+ struct ldb_message *msg;
+ struct ldb_dn *dn_key;
+ int ret;
+ unsigned int i;
+
+ msg = talloc(module, struct ldb_message);
+ if (msg == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]);
+ if (!dn_key) {
+ talloc_free(msg);
+ errno = ENOMEM;
+ return -1;
+ }
+ talloc_steal(msg, dn_key);
+
+ ret = ltdb_search_dn1(module, dn_key, msg);
+ if (ret == -1) {
+ talloc_free(msg);
+ return -1;
+ }
+
+ if (ret == 0) {
+ msg->dn = dn_key;
+ msg->num_elements = 0;
+ msg->elements = NULL;
+ }
+
+ for (i=0;i<msg->num_elements;i++) {
+ if (strcmp(LTDB_IDX, msg->elements[i].name) == 0) {
+ break;
+ }
+ }
+
+ if (i == msg->num_elements) {
+ ret = ltdb_index_add1_new(ldb, msg, el, dn);
+ } else {
+ ret = ltdb_index_add1_add(ldb, msg, el, i, dn);
+ }
+
+ if (ret == 0) {
+ ret = ltdb_store(module, msg, TDB_REPLACE);
+ }
+
+ talloc_free(msg);
+
+ return ret;
+}
+
+static int ltdb_index_add0(struct ldb_module *module, const char *dn,
+ struct ldb_message_element *elements, int num_el)
+{
+ struct ltdb_private *ltdb =
+ (struct ltdb_private *)module->private_data;
+ int ret;
+ unsigned int i, j;
+
+ if (dn[0] == '@') {
+ return 0;
+ }
+
+ if (ltdb->cache->indexlist->num_elements == 0) {
+ /* no indexed fields */
+ return 0;
+ }
+
+ for (i = 0; i < num_el; i++) {
+ ret = ldb_msg_find_idx(ltdb->cache->indexlist, elements[i].name,
+ NULL, LTDB_IDXATTR);
+ if (ret == -1) {
+ continue;
+ }
+ for (j = 0; j < elements[i].num_values; j++) {
+ ret = ltdb_index_add1(module, dn, &elements[i], j);
+ if (ret == -1) {
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ add the index entries for a new record
+ return -1 on failure
+*/
+int ltdb_index_add(struct ldb_module *module, const struct ldb_message *msg)
+{
+ struct ltdb_private *ltdb =
+ (struct ltdb_private *)module->private_data;
+ char *dn;
+ int ret;
+
+ dn = ldb_dn_linearize(ltdb, msg->dn);
+ if (dn == NULL) {
+ return -1;
+ }
+
+ ret = ltdb_index_add0(module, dn, msg->elements, msg->num_elements);
+
+ talloc_free(dn);
+
+ return ret;
+}
+
+
+/*
+ delete an index entry for one message element
+*/
+int ltdb_index_del_value(struct ldb_module *module, const char *dn,
+ struct ldb_message_element *el, int v_idx)
+{
+ struct ldb_context *ldb = module->ldb;
+ struct ldb_message *msg;
+ struct ldb_dn *dn_key;
+ int ret, i;
+ unsigned int j;
+
+ if (dn[0] == '@') {
+ return 0;
+ }
+
+ dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]);
+ if (!dn_key) {
+ return -1;
+ }
+
+ msg = talloc(dn_key, struct ldb_message);
+ if (msg == NULL) {
+ talloc_free(dn_key);
+ return -1;
+ }
+
+ ret = ltdb_search_dn1(module, dn_key, msg);
+ if (ret == -1) {
+ talloc_free(dn_key);
+ return -1;
+ }
+
+ if (ret == 0) {
+ /* it wasn't indexed. Did we have an earlier error? If we did then
+ its gone now */
+ talloc_free(dn_key);
+ return 0;
+ }
+
+ i = ldb_msg_find_idx(msg, dn, &j, LTDB_IDX);
+ if (i == -1) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "ERROR: dn %s not found in %s\n", dn,
+ ldb_dn_linearize(dn_key, dn_key));
+ /* it ain't there. hmmm */
+ talloc_free(dn_key);
+ return 0;
+ }
+
+ if (j != msg->elements[i].num_values - 1) {
+ memmove(&msg->elements[i].values[j],
+ &msg->elements[i].values[j+1],
+ (msg->elements[i].num_values-(j+1)) *
+ sizeof(msg->elements[i].values[0]));
+ }
+ msg->elements[i].num_values--;
+
+ if (msg->elements[i].num_values == 0) {
+ ret = ltdb_delete_noindex(module, dn_key);
+ } else {
+ ret = ltdb_store(module, msg, TDB_REPLACE);
+ }
+
+ talloc_free(dn_key);
+
+ return ret;
+}
+
+/*
+ delete the index entries for a record
+ return -1 on failure
+*/
+int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg)
+{
+ struct ltdb_private *ltdb =
+ (struct ltdb_private *)module->private_data;
+ int ret;
+ char *dn;
+ unsigned int i, j;
+
+ /* find the list of indexed fields */
+ if (ltdb->cache->indexlist->num_elements == 0) {
+ /* no indexed fields */
+ return 0;
+ }
+
+ if (ldb_dn_is_special(msg->dn)) {
+ return 0;
+ }
+
+ dn = ldb_dn_linearize(ltdb, msg->dn);
+ if (dn == NULL) {
+ return -1;
+ }
+
+ for (i = 0; i < msg->num_elements; i++) {
+ ret = ldb_msg_find_idx(ltdb->cache->indexlist, msg->elements[i].name,
+ NULL, LTDB_IDXATTR);
+ if (ret == -1) {
+ continue;
+ }
+ for (j = 0; j < msg->elements[i].num_values; j++) {
+ ret = ltdb_index_del_value(module, dn, &msg->elements[i], j);
+ if (ret == -1) {
+ talloc_free(dn);
+ return -1;
+ }
+ }
+ }
+
+ talloc_free(dn);
+ return 0;
+}
+
+
+/*
+ traversal function that deletes all @INDEX records
+*/
+static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
+{
+ const char *dn = "DN=" LTDB_INDEX ":";
+ if (strncmp((char *)key.dptr, dn, strlen(dn)) == 0) {
+ return tdb_delete(tdb, key);
+ }
+ return 0;
+}
+
+/*
+ traversal function that adds @INDEX records during a re index
+*/
+static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
+{
+ struct ldb_module *module = (struct ldb_module *)state;
+ struct ldb_message *msg;
+ char *dn = NULL;
+ int ret;
+ TDB_DATA key2;
+
+ if (strncmp((char *)key.dptr, "DN=@", 4) == 0 ||
+ strncmp((char *)key.dptr, "DN=", 3) != 0) {
+ return 0;
+ }
+
+ msg = talloc(module, struct ldb_message);
+ if (msg == NULL) {
+ return -1;
+ }
+
+ ret = ltdb_unpack_data(module, &data, msg);
+ if (ret != 0) {
+ talloc_free(msg);
+ return -1;
+ }
+
+ /* check if the DN key has changed, perhaps due to the
+ case insensitivity of an element changing */
+ key2 = ltdb_key(module, msg->dn);
+ if (key2.dptr == NULL) {
+ /* probably a corrupt record ... darn */
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Invalid DN in re_index: %s\n",
+ ldb_dn_linearize(msg, msg->dn));
+ talloc_free(msg);
+ return 0;
+ }
+ if (strcmp((char *)key2.dptr, (char *)key.dptr) != 0) {
+ tdb_delete(tdb, key);
+ tdb_store(tdb, key2, data, 0);
+ }
+ talloc_free(key2.dptr);
+
+ if (msg->dn == NULL) {
+ dn = (char *)key.dptr + 3;
+ } else {
+ if (!(dn = ldb_dn_linearize(msg->dn, msg->dn))) {
+ talloc_free(msg);
+ return -1;
+ }
+ }
+
+ ret = ltdb_index_add0(module, dn, msg->elements, msg->num_elements);
+
+ talloc_free(msg);
+
+ return ret;
+}
+
+/*
+ force a complete reindex of the database
+*/
+int ltdb_reindex(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb =
+ (struct ltdb_private *)module->private_data;
+ int ret;
+
+ if (ltdb_cache_reload(module) != 0) {
+ return -1;
+ }
+
+ /* first traverse the database deleting any @INDEX records */
+ ret = tdb_traverse(ltdb->tdb, delete_index, NULL);
+ if (ret == -1) {
+ return -1;
+ }
+
+ /* now traverse adding any indexes for normal LDB records */
+ ret = tdb_traverse(ltdb->tdb, re_index, module);
+ if (ret == -1) {
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/source3/lib/ldb/ldb_tdb/ldb_pack.c b/source3/lib/ldb/ldb_tdb/ldb_pack.c
new file mode 100644
index 0000000000..3f3d1ccca7
--- /dev/null
+++ b/source3/lib/ldb/ldb_tdb/ldb_pack.c
@@ -0,0 +1,293 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb pack/unpack
+ *
+ * Description: pack/unpack routines for ldb messages as key/value blobs
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#include "ldb/ldb_tdb/ldb_tdb.h"
+
+/* change this if the data format ever changes */
+#define LTDB_PACKING_FORMAT 0x26011967
+
+/* old packing formats */
+#define LTDB_PACKING_FORMAT_NODN 0x26011966
+
+/* use a portable integer format */
+static void put_uint32(uint8_t *p, int ofs, unsigned int val)
+{
+ p += ofs;
+ p[0] = val&0xFF;
+ p[1] = (val>>8) & 0xFF;
+ p[2] = (val>>16) & 0xFF;
+ p[3] = (val>>24) & 0xFF;
+}
+
+static unsigned int pull_uint32(uint8_t *p, int ofs)
+{
+ p += ofs;
+ return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
+}
+
+static int attribute_storable_values(const struct ldb_message_element *el)
+{
+ if (el->num_values == 0) return 0;
+
+ if (ldb_attr_cmp(el->name, "dn") == 0) return 0;
+
+ if (ldb_attr_cmp(el->name, "distinguishedName") == 0) return 0;
+
+ return el->num_values;
+}
+
+/*
+ pack a ldb message into a linear buffer in a TDB_DATA
+
+ note that this routine avoids saving elements with zero values,
+ as these are equivalent to having no element
+
+ caller frees the data buffer after use
+*/
+int ltdb_pack_data(struct ldb_module *module,
+ const struct ldb_message *message,
+ struct TDB_DATA *data)
+{
+ struct ldb_context *ldb = module->ldb;
+ unsigned int i, j, real_elements=0;
+ size_t size;
+ char *dn;
+ uint8_t *p;
+ size_t len;
+
+ dn = ldb_dn_linearize(ldb, message->dn);
+ if (dn == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* work out how big it needs to be */
+ size = 8;
+
+ size += 1 + strlen(dn);
+
+ for (i=0;i<message->num_elements;i++) {
+ if (attribute_storable_values(&message->elements[i]) == 0) {
+ continue;
+ }
+
+ real_elements++;
+
+ size += 1 + strlen(message->elements[i].name) + 4;
+ for (j=0;j<message->elements[i].num_values;j++) {
+ size += 4 + message->elements[i].values[j].length + 1;
+ }
+ }
+
+ /* allocate it */
+ data->dptr = talloc_array(ldb, uint8_t, size);
+ if (!data->dptr) {
+ talloc_free(dn);
+ errno = ENOMEM;
+ return -1;
+ }
+ data->dsize = size;
+
+ p = (uint8_t *)data->dptr;
+ put_uint32(p, 0, LTDB_PACKING_FORMAT);
+ put_uint32(p, 4, real_elements);
+ p += 8;
+
+ /* the dn needs to be packed so we can be case preserving
+ while hashing on a case folded dn */
+ len = strlen(dn);
+ memcpy(p, dn, len+1);
+ p += len + 1;
+
+ for (i=0;i<message->num_elements;i++) {
+ if (attribute_storable_values(&message->elements[i]) == 0) {
+ continue;
+ }
+ len = strlen(message->elements[i].name);
+ memcpy(p, message->elements[i].name, len+1);
+ p += len + 1;
+ put_uint32(p, 0, message->elements[i].num_values);
+ p += 4;
+ for (j=0;j<message->elements[i].num_values;j++) {
+ put_uint32(p, 0, message->elements[i].values[j].length);
+ memcpy(p+4, message->elements[i].values[j].data,
+ message->elements[i].values[j].length);
+ p[4+message->elements[i].values[j].length] = 0;
+ p += 4 + message->elements[i].values[j].length + 1;
+ }
+ }
+
+ talloc_free(dn);
+ return 0;
+}
+
+/*
+ unpack a ldb message from a linear buffer in TDB_DATA
+
+ Free with ltdb_unpack_data_free()
+*/
+int ltdb_unpack_data(struct ldb_module *module,
+ const struct TDB_DATA *data,
+ struct ldb_message *message)
+{
+ struct ldb_context *ldb = module->ldb;
+ uint8_t *p;
+ unsigned int remaining;
+ unsigned int i, j;
+ unsigned format;
+ size_t len;
+
+ message->elements = NULL;
+
+ p = (uint8_t *)data->dptr;
+ if (data->dsize < 8) {
+ errno = EIO;
+ goto failed;
+ }
+
+ format = pull_uint32(p, 0);
+ message->num_elements = pull_uint32(p, 4);
+ p += 8;
+
+ remaining = data->dsize - 8;
+
+ switch (format) {
+ case LTDB_PACKING_FORMAT_NODN:
+ message->dn = NULL;
+ break;
+
+ case LTDB_PACKING_FORMAT:
+ len = strnlen((char *)p, remaining);
+ if (len == remaining) {
+ errno = EIO;
+ goto failed;
+ }
+ message->dn = ldb_dn_explode(message, (char *)p);
+ if (message->dn == NULL) {
+ errno = ENOMEM;
+ goto failed;
+ }
+ remaining -= len + 1;
+ p += len + 1;
+ break;
+
+ default:
+ errno = EIO;
+ goto failed;
+ }
+
+ if (message->num_elements == 0) {
+ message->elements = NULL;
+ return 0;
+ }
+
+ if (message->num_elements > remaining / 6) {
+ errno = EIO;
+ goto failed;
+ }
+
+ message->elements = talloc_array(message, struct ldb_message_element, message->num_elements);
+ if (!message->elements) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ memset(message->elements, 0,
+ message->num_elements * sizeof(struct ldb_message_element));
+
+ for (i=0;i<message->num_elements;i++) {
+ if (remaining < 10) {
+ errno = EIO;
+ goto failed;
+ }
+ len = strnlen((char *)p, remaining-6);
+ if (len == remaining-6) {
+ errno = EIO;
+ goto failed;
+ }
+ message->elements[i].flags = 0;
+ message->elements[i].name = talloc_strndup(message->elements, (char *)p, len);
+ if (message->elements[i].name == NULL) {
+ errno = ENOMEM;
+ goto failed;
+ }
+ remaining -= len + 1;
+ p += len + 1;
+ message->elements[i].num_values = pull_uint32(p, 0);
+ message->elements[i].values = NULL;
+ if (message->elements[i].num_values != 0) {
+ message->elements[i].values = talloc_array(message->elements,
+ struct ldb_val,
+ message->elements[i].num_values);
+ if (!message->elements[i].values) {
+ errno = ENOMEM;
+ goto failed;
+ }
+ }
+ p += 4;
+ remaining -= 4;
+ for (j=0;j<message->elements[i].num_values;j++) {
+ len = pull_uint32(p, 0);
+ if (len > remaining-5) {
+ errno = EIO;
+ goto failed;
+ }
+
+ message->elements[i].values[j].length = len;
+ message->elements[i].values[j].data = (uint8_t *)talloc_size(message->elements[i].values, len+1);
+ if (message->elements[i].values[j].data == NULL) {
+ errno = ENOMEM;
+ goto failed;
+ }
+ memcpy(message->elements[i].values[j].data, p+4, len);
+ message->elements[i].values[j].data[len] = 0;
+
+ remaining -= len+4+1;
+ p += len+4+1;
+ }
+ }
+
+ if (remaining != 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: %d bytes unread in ltdb_unpack_data\n", remaining);
+ }
+
+ return 0;
+
+failed:
+ talloc_free(message->elements);
+ return -1;
+}
diff --git a/source3/lib/ldb/ldb_tdb/ldb_search.c b/source3/lib/ldb/ldb_tdb/ldb_search.c
new file mode 100644
index 0000000000..9ef8eb9295
--- /dev/null
+++ b/source3/lib/ldb/ldb_tdb/ldb_search.c
@@ -0,0 +1,527 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb search functions
+ *
+ * Description: functions to search ldb+tdb databases
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#include "ldb/ldb_tdb/ldb_tdb.h"
+
+/*
+ add one element to a message
+*/
+static int msg_add_element(struct ldb_message *ret,
+ const struct ldb_message_element *el,
+ int check_duplicates)
+{
+ unsigned int i;
+ struct ldb_message_element *e2, *elnew;
+
+ if (check_duplicates && ldb_msg_find_element(ret, el->name)) {
+ /* its already there */
+ return 0;
+ }
+
+ e2 = talloc_realloc(ret, ret->elements, struct ldb_message_element, ret->num_elements+1);
+ if (!e2) {
+ return -1;
+ }
+ ret->elements = e2;
+
+ elnew = &e2[ret->num_elements];
+
+ elnew->name = talloc_strdup(ret->elements, el->name);
+ if (!elnew->name) {
+ return -1;
+ }
+
+ if (el->num_values) {
+ elnew->values = talloc_array(ret->elements, struct ldb_val, el->num_values);
+ if (!elnew->values) {
+ return -1;
+ }
+ } else {
+ elnew->values = NULL;
+ }
+
+ for (i=0;i<el->num_values;i++) {
+ elnew->values[i] = ldb_val_dup(elnew->values, &el->values[i]);
+ if (elnew->values[i].length != el->values[i].length) {
+ return -1;
+ }
+ }
+
+ elnew->num_values = el->num_values;
+
+ ret->num_elements++;
+
+ return 0;
+}
+
+/*
+ add the special distinguishedName element
+*/
+static int msg_add_distinguished_name(struct ldb_message *msg)
+{
+ struct ldb_message_element el;
+ struct ldb_val val;
+ int ret;
+
+ el.flags = 0;
+ el.name = "distinguishedName";
+ el.num_values = 1;
+ el.values = &val;
+ val.data = (uint8_t *)ldb_dn_linearize(msg, msg->dn);
+ val.length = strlen((char *)val.data);
+
+ ret = msg_add_element(msg, &el, 1);
+ return ret;
+}
+
+/*
+ add all elements from one message into another
+ */
+static int msg_add_all_elements(struct ldb_module *module, struct ldb_message *ret,
+ const struct ldb_message *msg)
+{
+ struct ldb_context *ldb = module->ldb;
+ unsigned int i;
+ int check_duplicates = (ret->num_elements != 0);
+
+ if (msg_add_distinguished_name(ret) != 0) {
+ return -1;
+ }
+
+ for (i=0;i<msg->num_elements;i++) {
+ const struct ldb_attrib_handler *h;
+ h = ldb_attrib_handler(ldb, msg->elements[i].name);
+ if (h->flags & LDB_ATTR_FLAG_HIDDEN) {
+ continue;
+ }
+ if (msg_add_element(ret, &msg->elements[i],
+ check_duplicates) != 0) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ pull the specified list of attributes from a message
+ */
+static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg,
+ const char * const *attrs)
+{
+ struct ldb_message *ret;
+ int i;
+
+ ret = talloc(mem_ctx, struct ldb_message);
+ if (!ret) {
+ return NULL;
+ }
+
+ ret->dn = ldb_dn_copy(ret, msg->dn);
+ if (!ret->dn) {
+ talloc_free(ret);
+ return NULL;
+ }
+
+ ret->num_elements = 0;
+ ret->elements = NULL;
+
+ if (!attrs) {
+ if (msg_add_all_elements(module, ret, msg) != 0) {
+ talloc_free(ret);
+ return NULL;
+ }
+ return ret;
+ }
+
+ for (i=0;attrs[i];i++) {
+ struct ldb_message_element *el;
+
+ if (strcmp(attrs[i], "*") == 0) {
+ if (msg_add_all_elements(module, ret, msg) != 0) {
+ talloc_free(ret);
+ return NULL;
+ }
+ continue;
+ }
+
+ if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
+ if (msg_add_distinguished_name(ret) != 0) {
+ return NULL;
+ }
+ continue;
+ }
+
+ el = ldb_msg_find_element(msg, attrs[i]);
+ if (!el) {
+ continue;
+ }
+ if (msg_add_element(ret, el, 1) != 0) {
+ talloc_free(ret);
+ return NULL;
+ }
+ }
+
+ return ret;
+}
+
+
+/*
+ search the database for a single simple dn, returning all attributes
+ in a single message
+
+ return 1 on success, 0 on record-not-found and -1 on error
+*/
+int ltdb_search_dn1(struct ldb_module *module, const struct ldb_dn *dn, struct ldb_message *msg)
+{
+ struct ltdb_private *ltdb =
+ (struct ltdb_private *)module->private_data;
+ int ret;
+ TDB_DATA tdb_key, tdb_data;
+
+ memset(msg, 0, sizeof(*msg));
+
+ /* form the key */
+ tdb_key = ltdb_key(module, dn);
+ if (!tdb_key.dptr) {
+ return -1;
+ }
+
+ tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
+ talloc_free(tdb_key.dptr);
+ if (!tdb_data.dptr) {
+ return 0;
+ }
+
+ msg->num_elements = 0;
+ msg->elements = NULL;
+
+ ret = ltdb_unpack_data(module, &tdb_data, msg);
+ free(tdb_data.dptr);
+ if (ret == -1) {
+ return -1;
+ }
+
+ if (!msg->dn) {
+ msg->dn = ldb_dn_copy(msg, dn);
+ }
+ if (!msg->dn) {
+ return -1;
+ }
+
+ return 1;
+}
+
+/*
+ lock the database for read - use by ltdb_search
+*/
+static int ltdb_lock_read(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb =
+ (struct ltdb_private *)module->private_data;
+ return tdb_lockall_read(ltdb->tdb);
+}
+
+/*
+ unlock the database after a ltdb_lock_read()
+*/
+static int ltdb_unlock_read(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb =
+ (struct ltdb_private *)module->private_data;
+ return tdb_unlockall_read(ltdb->tdb);
+}
+
+/*
+ add a set of attributes from a record to a set of results
+ return 0 on success, -1 on failure
+*/
+int ltdb_add_attr_results(struct ldb_module *module,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message *msg,
+ const char * const attrs[],
+ unsigned int *count,
+ struct ldb_message ***res)
+{
+ struct ldb_message *msg2;
+ struct ldb_message **res2;
+
+ /* pull the attributes that the user wants */
+ msg2 = ltdb_pull_attrs(module, mem_ctx, msg, attrs);
+ if (!msg2) {
+ return -1;
+ }
+
+ /* add to the results list */
+ res2 = talloc_realloc(mem_ctx, *res, struct ldb_message *, (*count)+2);
+ if (!res2) {
+ talloc_free(msg2);
+ return -1;
+ }
+
+ (*res) = res2;
+
+ (*res)[*count] = talloc_move(*res, &msg2);
+ (*res)[(*count)+1] = NULL;
+ (*count)++;
+
+ return 0;
+}
+
+
+
+/*
+ filter the specified list of attributes from a message
+ removing not requested attrs.
+ */
+int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs)
+{
+ int i, keep_all = 0;
+
+ if (attrs) {
+ /* check for special attrs */
+ for (i = 0; attrs[i]; i++) {
+ if (strcmp(attrs[i], "*") == 0) {
+ keep_all = 1;
+ break;
+ }
+
+ if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
+ if (msg_add_distinguished_name(msg) != 0) {
+ return -1;
+ }
+ }
+ }
+ } else {
+ keep_all = 1;
+ }
+
+ if (keep_all) {
+ if (msg_add_distinguished_name(msg) != 0) {
+ return -1;
+ }
+ return 0;
+ }
+
+ for (i = 0; i < msg->num_elements; i++) {
+ int j, found;
+
+ for (j = 0, found = 0; attrs[j]; j++) {
+ if (ldb_attr_cmp(msg->elements[i].name, attrs[j]) == 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ ldb_msg_remove_attr(msg, msg->elements[i].name);
+ i--;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ search function for a non-indexed search
+ */
+static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
+{
+ struct ldb_handle *handle = talloc_get_type(state, struct ldb_handle);
+ struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
+ struct ldb_reply *ares = NULL;
+ int ret;
+
+ if (key.dsize < 4 ||
+ strncmp((char *)key.dptr, "DN=", 3) != 0) {
+ return 0;
+ }
+
+ ares = talloc_zero(ac, struct ldb_reply);
+ if (!ares) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ handle->state = LDB_ASYNC_DONE;
+ return -1;
+ }
+
+ ares->message = ldb_msg_new(ares);
+ if (!ares->message) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ handle->state = LDB_ASYNC_DONE;
+ talloc_free(ares);
+ return -1;
+ }
+
+ /* unpack the record */
+ ret = ltdb_unpack_data(ac->module, &data, ares->message);
+ if (ret == -1) {
+ talloc_free(ares);
+ return -1;
+ }
+
+ if (!ares->message->dn) {
+ ares->message->dn = ldb_dn_explode(ares->message, (char *)key.dptr + 3);
+ if (ares->message->dn == NULL) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ handle->state = LDB_ASYNC_DONE;
+ talloc_free(ares);
+ return -1;
+ }
+ }
+
+ /* see if it matches the given expression */
+ if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree,
+ ac->base, ac->scope)) {
+ talloc_free(ares);
+ return 0;
+ }
+
+ /* filter the attributes that the user wants */
+ ret = ltdb_filter_attrs(ares->message, ac->attrs);
+
+ if (ret == -1) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ handle->state = LDB_ASYNC_DONE;
+ talloc_free(ares);
+ return -1;
+ }
+
+ ares->type = LDB_REPLY_ENTRY;
+ handle->state = LDB_ASYNC_PENDING;
+ handle->status = ac->callback(ac->module->ldb, ac->context, ares);
+
+ if (handle->status != LDB_SUCCESS) {
+ /* don't try to free ares here, the callback is in charge of that */
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ search the database with a LDAP-like expression.
+ this is the "full search" non-indexed variant
+*/
+static int ltdb_search_full(struct ldb_handle *handle)
+{
+ struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
+ struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private);
+ int ret;
+
+ ret = tdb_traverse_read(ltdb->tdb, search_func, handle);
+
+ if (ret == -1) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ handle->state = LDB_ASYNC_DONE;
+ return LDB_SUCCESS;
+}
+
+/*
+ search the database with a LDAP-like expression.
+ choses a search method
+*/
+int ltdb_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
+ struct ltdb_context *ltdb_ac;
+ struct ldb_reply *ares;
+ int ret;
+
+ if ((req->op.search.base == NULL || ldb_dn_get_comp_num(req->op.search.base) == 0) &&
+ (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL))
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ if (ltdb_lock_read(module) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (ltdb_cache_load(module) != 0) {
+ ltdb_unlock_read(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (req->op.search.tree == NULL) {
+ ltdb_unlock_read(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->handle = init_ltdb_handle(ltdb, module, req);
+ if (req->handle == NULL) {
+ ltdb_unlock_read(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context);
+
+ ltdb_ac->tree = req->op.search.tree;
+ ltdb_ac->scope = req->op.search.scope;
+ ltdb_ac->base = req->op.search.base;
+ ltdb_ac->attrs = req->op.search.attrs;
+
+ ret = ltdb_search_indexed(req->handle);
+ if (ret == -1) {
+ ret = ltdb_search_full(req->handle);
+ }
+ if (ret != LDB_SUCCESS) {
+ ldb_set_errstring(module->ldb, "Indexed and full searches both failed!\n");
+ req->handle->state = LDB_ASYNC_DONE;
+ req->handle->status = ret;
+ }
+
+ /* Finally send an LDB_REPLY_DONE packet when searching is finished */
+
+ ares = talloc_zero(req, struct ldb_reply);
+ if (!ares) {
+ ltdb_unlock_read(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->handle->state = LDB_ASYNC_DONE;
+ ares->type = LDB_REPLY_DONE;
+
+ ret = req->callback(module->ldb, req->context, ares);
+ req->handle->status = ret;
+
+ ltdb_unlock_read(module);
+
+ return LDB_SUCCESS;
+}
+
diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.c b/source3/lib/ldb/ldb_tdb/ldb_tdb.c
new file mode 100644
index 0000000000..27cc0c69c6
--- /dev/null
+++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -0,0 +1,1084 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Simo Sorce 2006
+
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb_tdb
+ *
+ * Component: ldb tdb backend
+ *
+ * Description: core functions for tdb backend
+ *
+ * Author: Andrew Tridgell
+ * Author: Stefan Metzmacher
+ *
+ * Modifications:
+ *
+ * - description: make the module use asyncronous calls
+ * date: Feb 2006
+ * Author: Simo Sorce
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#include "ldb/ldb_tdb/ldb_tdb.h"
+
+int ltdb_check_special_dn(struct ldb_module *module, const struct ldb_message *msg);
+
+/*
+ map a tdb error code to a ldb error code
+*/
+static int ltdb_err_map(enum TDB_ERROR tdb_code)
+{
+ switch (tdb_code) {
+ case TDB_SUCCESS:
+ return LDB_SUCCESS;
+ case TDB_ERR_CORRUPT:
+ case TDB_ERR_OOM:
+ case TDB_ERR_EINVAL:
+ return LDB_ERR_OPERATIONS_ERROR;
+ case TDB_ERR_IO:
+ return LDB_ERR_PROTOCOL_ERROR;
+ case TDB_ERR_LOCK:
+ case TDB_ERR_NOLOCK:
+ return LDB_ERR_BUSY;
+ case TDB_ERR_LOCK_TIMEOUT:
+ return LDB_ERR_TIME_LIMIT_EXCEEDED;
+ case TDB_ERR_EXISTS:
+ return LDB_ERR_ENTRY_ALREADY_EXISTS;
+ case TDB_ERR_NOEXIST:
+ return LDB_ERR_NO_SUCH_OBJECT;
+ case TDB_ERR_RDONLY:
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+ return LDB_ERR_OTHER;
+}
+
+
+struct ldb_handle *init_ltdb_handle(struct ltdb_private *ltdb, struct ldb_module *module,
+ struct ldb_request *req)
+{
+ struct ltdb_context *ac;
+ struct ldb_handle *h;
+
+ h = talloc_zero(req, struct ldb_handle);
+ if (h == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ return NULL;
+ }
+
+ h->module = module;
+
+ ac = talloc_zero(h, struct ltdb_context);
+ if (ac == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ talloc_free(h);
+ return NULL;
+ }
+
+ h->private_data = (void *)ac;
+
+ h->state = LDB_ASYNC_INIT;
+ h->status = LDB_SUCCESS;
+
+ ac->module = module;
+ ac->context = req->context;
+ ac->callback = req->callback;
+
+ return h;
+}
+
+/*
+ form a TDB_DATA for a record key
+ caller frees
+
+ note that the key for a record can depend on whether the
+ dn refers to a case sensitive index record or not
+*/
+struct TDB_DATA ltdb_key(struct ldb_module *module, const struct ldb_dn *dn)
+{
+ struct ldb_context *ldb = module->ldb;
+ TDB_DATA key;
+ char *key_str = NULL;
+ char *dn_folded = NULL;
+
+ /*
+ most DNs are case insensitive. The exception is index DNs for
+ case sensitive attributes
+
+ there are 3 cases dealt with in this code:
+
+ 1) if the dn doesn't start with @ then uppercase the attribute
+ names and the attributes values of case insensitive attributes
+ 2) if the dn starts with @ then leave it alone - the indexing code handles
+ the rest
+ */
+
+ dn_folded = ldb_dn_linearize_casefold(ldb, ldb, dn);
+ if (!dn_folded) {
+ goto failed;
+ }
+
+ key_str = talloc_asprintf(ldb, "DN=%s", dn_folded);
+
+ talloc_free(dn_folded);
+
+ if (!key_str) {
+ goto failed;
+ }
+
+ key.dptr = (uint8_t *)key_str;
+ key.dsize = strlen(key_str) + 1;
+
+ return key;
+
+failed:
+ errno = ENOMEM;
+ key.dptr = NULL;
+ key.dsize = 0;
+ return key;
+}
+
+/*
+ check special dn's have valid attributes
+ currently only @ATTRIBUTES is checked
+*/
+int ltdb_check_special_dn(struct ldb_module *module, const struct ldb_message *msg)
+{
+ int i, j;
+
+ if (! ldb_dn_is_special(msg->dn) ||
+ ! ldb_dn_check_special(msg->dn, LTDB_ATTRIBUTES)) {
+ return 0;
+ }
+
+ /* we have @ATTRIBUTES, let's check attributes are fine */
+ /* should we check that we deny multivalued attributes ? */
+ for (i = 0; i < msg->num_elements; i++) {
+ for (j = 0; j < msg->elements[i].num_values; j++) {
+ if (ltdb_check_at_attributes_values(&msg->elements[i].values[j]) != 0) {
+ ldb_set_errstring(module->ldb, "Invalid attribute value in an @ATTRIBUTES entry");
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ we've made a modification to a dn - possibly reindex and
+ update sequence number
+*/
+static int ltdb_modified(struct ldb_module *module, const struct ldb_dn *dn)
+{
+ int ret = 0;
+
+ if (ldb_dn_is_special(dn) &&
+ (ldb_dn_check_special(dn, LTDB_INDEXLIST) ||
+ ldb_dn_check_special(dn, LTDB_ATTRIBUTES)) ) {
+ ret = ltdb_reindex(module);
+ }
+
+ if (ret == 0 &&
+ !(ldb_dn_is_special(dn) &&
+ ldb_dn_check_special(dn, LTDB_BASEINFO)) ) {
+ ret = ltdb_increase_sequence_number(module);
+ }
+
+ return ret;
+}
+
+/*
+ store a record into the db
+*/
+int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs)
+{
+ struct ltdb_private *ltdb =
+ talloc_get_type(module->private_data, struct ltdb_private);
+ TDB_DATA tdb_key, tdb_data;
+ int ret;
+
+ tdb_key = ltdb_key(module, msg->dn);
+ if (!tdb_key.dptr) {
+ return LDB_ERR_OTHER;
+ }
+
+ ret = ltdb_pack_data(module, msg, &tdb_data);
+ if (ret == -1) {
+ talloc_free(tdb_key.dptr);
+ return LDB_ERR_OTHER;
+ }
+
+ ret = tdb_store(ltdb->tdb, tdb_key, tdb_data, flgs);
+ if (ret == -1) {
+ ret = ltdb_err_map(tdb_error(ltdb->tdb));
+ goto done;
+ }
+
+ ret = ltdb_index_add(module, msg);
+ if (ret == -1) {
+ tdb_delete(ltdb->tdb, tdb_key);
+ }
+
+done:
+ talloc_free(tdb_key.dptr);
+ talloc_free(tdb_data.dptr);
+
+ return ret;
+}
+
+
+static int ltdb_add_internal(struct ldb_module *module, const struct ldb_message *msg)
+{
+ int ret;
+
+ ret = ltdb_check_special_dn(module, msg);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ if (ltdb_cache_load(module) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ltdb_store(module, msg, TDB_INSERT);
+
+ if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+ char *dn;
+
+ dn = ldb_dn_linearize(module, msg->dn);
+ if (!dn) {
+ return ret;
+ }
+ ldb_asprintf_errstring(module->ldb, "Entry %s already exists", dn);
+ talloc_free(dn);
+ return ret;
+ }
+
+ if (ret == LDB_SUCCESS) {
+ ret = ltdb_modified(module, msg->dn);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ add a record to the database
+*/
+static int ltdb_add(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
+ struct ltdb_context *ltdb_ac;
+ int tret, ret = LDB_SUCCESS;
+
+ if (req->controls != NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_tdb backend!\n");
+ if (check_critical_controls(req->controls)) {
+ return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+ }
+ }
+
+ req->handle = init_ltdb_handle(ltdb, module, req);
+ if (req->handle == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context);
+
+ tret = ltdb_add_internal(module, req->op.add.message);
+ if (tret != LDB_SUCCESS) {
+ req->handle->status = tret;
+ goto done;
+ }
+
+ if (ltdb_ac->callback) {
+ ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL);
+ }
+done:
+ req->handle->state = LDB_ASYNC_DONE;
+ return ret;
+}
+
+/*
+ delete a record from the database, not updating indexes (used for deleting
+ index records)
+*/
+int ltdb_delete_noindex(struct ldb_module *module, const struct ldb_dn *dn)
+{
+ struct ltdb_private *ltdb =
+ talloc_get_type(module->private_data, struct ltdb_private);
+ TDB_DATA tdb_key;
+ int ret;
+
+ tdb_key = ltdb_key(module, dn);
+ if (!tdb_key.dptr) {
+ return LDB_ERR_OTHER;
+ }
+
+ ret = tdb_delete(ltdb->tdb, tdb_key);
+ talloc_free(tdb_key.dptr);
+
+ if (ret != 0) {
+ ret = ltdb_err_map(tdb_error(ltdb->tdb));
+ }
+
+ return ret;
+}
+
+static int ltdb_delete_internal(struct ldb_module *module, const struct ldb_dn *dn)
+{
+ struct ldb_message *msg;
+ int ret;
+
+ msg = talloc(module, struct ldb_message);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* in case any attribute of the message was indexed, we need
+ to fetch the old record */
+ ret = ltdb_search_dn1(module, dn, msg);
+ if (ret != 1) {
+ /* not finding the old record is an error */
+ talloc_free(msg);
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ ret = ltdb_delete_noindex(module, dn);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ /* remove any indexed attributes */
+ ret = ltdb_index_del(module, msg);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ltdb_modified(module, dn);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ talloc_free(msg);
+ return LDB_SUCCESS;
+}
+
+/*
+ delete a record from the database
+*/
+static int ltdb_delete(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
+ struct ltdb_context *ltdb_ac;
+ int tret, ret = LDB_SUCCESS;
+
+ if (req->controls != NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_tdb backend!\n");
+ if (check_critical_controls(req->controls)) {
+ return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+ }
+ }
+
+ req->handle = NULL;
+
+ if (ltdb_cache_load(module) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->handle = init_ltdb_handle(ltdb, module, req);
+ if (req->handle == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context);
+
+ tret = ltdb_delete_internal(module, req->op.del.dn);
+ if (tret != LDB_SUCCESS) {
+ req->handle->status = tret;
+ goto done;
+ }
+
+ if (ltdb_ac->callback) {
+ ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL);
+ }
+done:
+ req->handle->state = LDB_ASYNC_DONE;
+ return ret;
+}
+
+/*
+ find an element by attribute name. At the moment this does a linear search, it should
+ be re-coded to use a binary search once all places that modify records guarantee
+ sorted order
+
+ return the index of the first matching element if found, otherwise -1
+*/
+static int find_element(const struct ldb_message *msg, const char *name)
+{
+ unsigned int i;
+ for (i=0;i<msg->num_elements;i++) {
+ if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+/*
+ add an element to an existing record. Assumes a elements array that we
+ can call re-alloc on, and assumed that we can re-use the data pointers from the
+ passed in additional values. Use with care!
+
+ returns 0 on success, -1 on failure (and sets errno)
+*/
+static int msg_add_element(struct ldb_context *ldb,
+ struct ldb_message *msg, struct ldb_message_element *el)
+{
+ struct ldb_message_element *e2;
+ unsigned int i;
+
+ e2 = talloc_realloc(msg, msg->elements, struct ldb_message_element,
+ msg->num_elements+1);
+ if (!e2) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ msg->elements = e2;
+
+ e2 = &msg->elements[msg->num_elements];
+
+ e2->name = el->name;
+ e2->flags = el->flags;
+ e2->values = NULL;
+ if (el->num_values != 0) {
+ e2->values = talloc_array(msg->elements, struct ldb_val, el->num_values);
+ if (!e2->values) {
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ for (i=0;i<el->num_values;i++) {
+ e2->values[i] = el->values[i];
+ }
+ e2->num_values = el->num_values;
+
+ msg->num_elements++;
+
+ return 0;
+}
+
+/*
+ delete all elements having a specified attribute name
+*/
+static int msg_delete_attribute(struct ldb_module *module,
+ struct ldb_context *ldb,
+ struct ldb_message *msg, const char *name)
+{
+ char *dn;
+ unsigned int i, j;
+
+ dn = ldb_dn_linearize(ldb, msg->dn);
+ if (dn == NULL) {
+ return -1;
+ }
+
+ for (i=0;i<msg->num_elements;i++) {
+ if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ ltdb_index_del_value(module, dn, &msg->elements[i], j);
+ }
+ talloc_free(msg->elements[i].values);
+ if (msg->num_elements > (i+1)) {
+ memmove(&msg->elements[i],
+ &msg->elements[i+1],
+ sizeof(struct ldb_message_element)*
+ (msg->num_elements - (i+1)));
+ }
+ msg->num_elements--;
+ i--;
+ msg->elements = talloc_realloc(msg, msg->elements,
+ struct ldb_message_element,
+ msg->num_elements);
+ }
+ }
+
+ talloc_free(dn);
+ return 0;
+}
+
+/*
+ delete all elements matching an attribute name/value
+
+ return 0 on success, -1 on failure
+*/
+static int msg_delete_element(struct ldb_module *module,
+ struct ldb_message *msg,
+ const char *name,
+ const struct ldb_val *val)
+{
+ struct ldb_context *ldb = module->ldb;
+ unsigned int i;
+ int found;
+ struct ldb_message_element *el;
+ const struct ldb_attrib_handler *h;
+
+ found = find_element(msg, name);
+ if (found == -1) {
+ return -1;
+ }
+
+ el = &msg->elements[found];
+
+ h = ldb_attrib_handler(ldb, el->name);
+
+ for (i=0;i<el->num_values;i++) {
+ if (h->comparison_fn(ldb, ldb, &el->values[i], val) == 0) {
+ if (i<el->num_values-1) {
+ memmove(&el->values[i], &el->values[i+1],
+ sizeof(el->values[i])*(el->num_values-(i+1)));
+ }
+ el->num_values--;
+ if (el->num_values == 0) {
+ return msg_delete_attribute(module, ldb, msg, name);
+ }
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+/*
+ modify a record - internal interface
+
+ yuck - this is O(n^2). Luckily n is usually small so we probably
+ get away with it, but if we ever have really large attribute lists
+ then we'll need to look at this again
+*/
+int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg)
+{
+ struct ldb_context *ldb = module->ldb;
+ struct ltdb_private *ltdb =
+ talloc_get_type(module->private_data, struct ltdb_private);
+ TDB_DATA tdb_key, tdb_data;
+ struct ldb_message *msg2;
+ unsigned i, j;
+ int ret;
+
+ tdb_key = ltdb_key(module, msg->dn);
+ if (!tdb_key.dptr) {
+ return LDB_ERR_OTHER;
+ }
+
+ tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
+ if (!tdb_data.dptr) {
+ talloc_free(tdb_key.dptr);
+ return ltdb_err_map(tdb_error(ltdb->tdb));
+ }
+
+ msg2 = talloc(tdb_key.dptr, struct ldb_message);
+ if (msg2 == NULL) {
+ talloc_free(tdb_key.dptr);
+ return LDB_ERR_OTHER;
+ }
+
+ ret = ltdb_unpack_data(module, &tdb_data, msg2);
+ if (ret == -1) {
+ ret = LDB_ERR_OTHER;
+ goto failed;
+ }
+
+ if (!msg2->dn) {
+ msg2->dn = msg->dn;
+ }
+
+ for (i=0;i<msg->num_elements;i++) {
+ struct ldb_message_element *el = &msg->elements[i];
+ struct ldb_message_element *el2;
+ struct ldb_val *vals;
+ char *dn;
+
+ switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
+
+ case LDB_FLAG_MOD_ADD:
+ /* add this element to the message. fail if it
+ already exists */
+ ret = find_element(msg2, el->name);
+
+ if (ret == -1) {
+ if (msg_add_element(ldb, msg2, el) != 0) {
+ ret = LDB_ERR_OTHER;
+ goto failed;
+ }
+ continue;
+ }
+
+ el2 = &msg2->elements[ret];
+
+ /* An attribute with this name already exists, add all
+ * values if they don't already exist. */
+
+ for (j=0;j<el->num_values;j++) {
+ if (ldb_msg_find_val(el2, &el->values[j])) {
+ ldb_set_errstring(module->ldb, "Type or value exists");
+ ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ goto failed;
+ }
+ }
+
+ vals = talloc_realloc(msg2->elements, el2->values, struct ldb_val,
+ el2->num_values + el->num_values);
+
+ if (vals == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto failed;
+ }
+
+ for (j=0;j<el->num_values;j++) {
+ vals[el2->num_values + j] =
+ ldb_val_dup(vals, &el->values[j]);
+ }
+
+ el2->values = vals;
+ el2->num_values += el->num_values;
+
+ break;
+
+ case LDB_FLAG_MOD_REPLACE:
+ /* replace all elements of this attribute name with the elements
+ listed. The attribute not existing is not an error */
+ msg_delete_attribute(module, ldb, msg2, msg->elements[i].name);
+
+ /* add the replacement element, if not empty */
+ if (msg->elements[i].num_values != 0 &&
+ msg_add_element(ldb, msg2, &msg->elements[i]) != 0) {
+ ret = LDB_ERR_OTHER;
+ goto failed;
+ }
+ break;
+
+ case LDB_FLAG_MOD_DELETE:
+
+ dn = ldb_dn_linearize(msg2, msg->dn);
+ if (dn == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto failed;
+ }
+
+ /* we could be being asked to delete all
+ values or just some values */
+ if (msg->elements[i].num_values == 0) {
+ if (msg_delete_attribute(module, ldb, msg2,
+ msg->elements[i].name) != 0) {
+ ldb_asprintf_errstring(module->ldb, "No such attribute: %s for delete on %s", msg->elements[i].name, dn);
+ ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
+ goto failed;
+ }
+ break;
+ }
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ if (msg_delete_element(module,
+ msg2,
+ msg->elements[i].name,
+ &msg->elements[i].values[j]) != 0) {
+ ldb_asprintf_errstring(module->ldb, "No matching attribute value when deleting attribute: %s on %s", msg->elements[i].name, dn);
+ ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
+ goto failed;
+ }
+ if (ltdb_index_del_value(module, dn, &msg->elements[i], j) != 0) {
+ ret = LDB_ERR_OTHER;
+ goto failed;
+ }
+ }
+ break;
+ default:
+ ldb_asprintf_errstring(module->ldb, "Invalid ldb_modify flags on %s: 0x%x",
+ msg->elements[i].name,
+ msg->elements[i].flags & LDB_FLAG_MOD_MASK);
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ goto failed;
+ }
+ }
+
+ /* we've made all the mods - save the modified record back into the database */
+ ret = ltdb_store(module, msg2, TDB_MODIFY);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ if (ltdb_modified(module, msg->dn) != LDB_SUCCESS) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto failed;
+ }
+
+ talloc_free(tdb_key.dptr);
+ free(tdb_data.dptr);
+ return ret;
+
+failed:
+ talloc_free(tdb_key.dptr);
+ free(tdb_data.dptr);
+ return ret;
+}
+
+/*
+ modify a record
+*/
+static int ltdb_modify(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
+ struct ltdb_context *ltdb_ac;
+ int tret, ret = LDB_SUCCESS;
+
+ if (req->controls != NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_tdb backend!\n");
+ if (check_critical_controls(req->controls)) {
+ return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+ }
+ }
+
+ req->handle = NULL;
+
+ req->handle = init_ltdb_handle(ltdb, module, req);
+ if (req->handle == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context);
+
+ tret = ltdb_check_special_dn(module, req->op.mod.message);
+ if (tret != LDB_SUCCESS) {
+ req->handle->status = tret;
+ goto done;
+ }
+
+ if (ltdb_cache_load(module) != 0) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ tret = ltdb_modify_internal(module, req->op.mod.message);
+ if (tret != LDB_SUCCESS) {
+ req->handle->status = tret;
+ goto done;
+ }
+
+ if (ltdb_ac->callback) {
+ ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL);
+ }
+done:
+ req->handle->state = LDB_ASYNC_DONE;
+ return ret;
+}
+
+/*
+ rename a record
+*/
+static int ltdb_rename(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
+ struct ltdb_context *ltdb_ac;
+ struct ldb_message *msg;
+ int tret, ret = LDB_SUCCESS;
+
+ if (req->controls != NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_tdb backend!\n");
+ if (check_critical_controls(req->controls)) {
+ return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+ }
+ }
+
+ req->handle = NULL;
+
+ if (ltdb_cache_load(module) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->handle = init_ltdb_handle(ltdb, module, req);
+ if (req->handle == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context);
+
+ msg = talloc(ltdb_ac, struct ldb_message);
+ if (msg == NULL) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ /* in case any attribute of the message was indexed, we need
+ to fetch the old record */
+ tret = ltdb_search_dn1(module, req->op.rename.olddn, msg);
+ if (tret != 1) {
+ /* not finding the old record is an error */
+ req->handle->status = LDB_ERR_NO_SUCH_OBJECT;
+ goto done;
+ }
+
+ msg->dn = ldb_dn_copy(msg, req->op.rename.newdn);
+ if (!msg->dn) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ tret = ltdb_add_internal(module, msg);
+ if (tret != LDB_SUCCESS) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ tret = ltdb_delete_internal(module, req->op.rename.olddn);
+ if (tret != LDB_SUCCESS) {
+ ltdb_delete_internal(module, req->op.rename.newdn);
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ if (ltdb_ac->callback) {
+ ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL);
+ }
+done:
+ req->handle->state = LDB_ASYNC_DONE;
+ return ret;
+}
+
+static int ltdb_start_trans(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb =
+ talloc_get_type(module->private_data, struct ltdb_private);
+
+ if (tdb_transaction_start(ltdb->tdb) != 0) {
+ return ltdb_err_map(tdb_error(ltdb->tdb));
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int ltdb_end_trans(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb =
+ talloc_get_type(module->private_data, struct ltdb_private);
+
+ if (tdb_transaction_commit(ltdb->tdb) != 0) {
+ return ltdb_err_map(tdb_error(ltdb->tdb));
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int ltdb_del_trans(struct ldb_module *module)
+{
+ struct ltdb_private *ltdb =
+ talloc_get_type(module->private_data, struct ltdb_private);
+
+ if (tdb_transaction_cancel(ltdb->tdb) != 0) {
+ return ltdb_err_map(tdb_error(ltdb->tdb));
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int ltdb_wait(struct ldb_handle *handle, enum ldb_wait_type type)
+{
+ return handle->status;
+}
+
+static int ltdb_request(struct ldb_module *module, struct ldb_request *req)
+{
+ /* check for oustanding critical controls and return an error if found */
+ if (req->controls != NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_tdb backend!\n");
+ if (check_critical_controls(req->controls)) {
+ return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+ }
+ }
+
+ /* search, add, modify, delete, rename are handled by their own, no other op supported */
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+/*
+ return sequenceNumber from @BASEINFO
+*/
+static int ltdb_sequence_number(struct ldb_module *module, struct ldb_request *req)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(req);
+ struct ldb_message *msg = NULL;
+ struct ldb_dn *dn = ldb_dn_explode(tmp_ctx, LTDB_BASEINFO);
+ int tret;
+
+ if (tmp_ctx == NULL) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg = talloc(tmp_ctx, struct ldb_message);
+ if (msg == NULL) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->op.seq_num.flags = 0;
+
+ tret = ltdb_search_dn1(module, dn, msg);
+ if (tret != 1) {
+ talloc_free(tmp_ctx);
+ req->op.seq_num.seq_num = 0;
+ /* zero is as good as anything when we don't know */
+ return LDB_SUCCESS;
+ }
+
+ switch (req->op.seq_num.type) {
+ case LDB_SEQ_HIGHEST_SEQ:
+ req->op.seq_num.seq_num = ldb_msg_find_attr_as_uint64(msg, LTDB_SEQUENCE_NUMBER, 0);
+ break;
+ case LDB_SEQ_NEXT:
+ req->op.seq_num.seq_num = ldb_msg_find_attr_as_uint64(msg, LTDB_SEQUENCE_NUMBER, 0);
+ req->op.seq_num.seq_num++;
+ break;
+ case LDB_SEQ_HIGHEST_TIMESTAMP:
+ {
+ const char *date = ldb_msg_find_attr_as_string(msg, LTDB_MOD_TIMESTAMP, NULL);
+ if (date) {
+ req->op.seq_num.seq_num = ldb_string_to_time(date);
+ } else {
+ req->op.seq_num.seq_num = 0;
+ /* zero is as good as anything when we don't know */
+ }
+ break;
+ }
+ }
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+}
+
+static const struct ldb_module_ops ltdb_ops = {
+ .name = "tdb",
+ .search = ltdb_search,
+ .add = ltdb_add,
+ .modify = ltdb_modify,
+ .del = ltdb_delete,
+ .rename = ltdb_rename,
+ .request = ltdb_request,
+ .start_transaction = ltdb_start_trans,
+ .end_transaction = ltdb_end_trans,
+ .del_transaction = ltdb_del_trans,
+ .wait = ltdb_wait,
+ .sequence_number = ltdb_sequence_number
+};
+
+/*
+ connect to the database
+*/
+static int ltdb_connect(struct ldb_context *ldb, const char *url,
+ unsigned int flags, const char *options[],
+ struct ldb_module **module)
+{
+ const char *path;
+ int tdb_flags, open_flags;
+ struct ltdb_private *ltdb;
+
+ /* parse the url */
+ if (strchr(url, ':')) {
+ if (strncmp(url, "tdb://", 6) != 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid tdb URL '%s'", url);
+ return -1;
+ }
+ path = url+6;
+ } else {
+ path = url;
+ }
+
+ tdb_flags = TDB_DEFAULT | TDB_SEQNUM;
+
+ /* check for the 'nosync' option */
+ if (flags & LDB_FLG_NOSYNC) {
+ tdb_flags |= TDB_NOSYNC;
+ }
+
+ /* and nommap option */
+ if (flags & LDB_FLG_NOMMAP) {
+ tdb_flags |= TDB_NOMMAP;
+ }
+
+ if (flags & LDB_FLG_RDONLY) {
+ open_flags = O_RDONLY;
+ } else {
+ open_flags = O_CREAT | O_RDWR;
+ }
+
+ ltdb = talloc_zero(ldb, struct ltdb_private);
+ if (!ltdb) {
+ ldb_oom(ldb);
+ return -1;
+ }
+
+ /* note that we use quite a large default hash size */
+ ltdb->tdb = ltdb_wrap_open(ltdb, path, 10000,
+ tdb_flags, open_flags,
+ ldb->create_perms, ldb);
+ if (!ltdb->tdb) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Unable to open tdb '%s'\n", path);
+ talloc_free(ltdb);
+ return -1;
+ }
+
+ ltdb->sequence_number = 0;
+
+ *module = talloc(ldb, struct ldb_module);
+ if ((*module) == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ltdb);
+ return -1;
+ }
+ talloc_set_name_const(*module, "ldb_tdb backend");
+ (*module)->ldb = ldb;
+ (*module)->prev = (*module)->next = NULL;
+ (*module)->private_data = ltdb;
+ (*module)->ops = &ltdb_ops;
+
+ if (ltdb_cache_load(*module) != 0) {
+ talloc_free(*module);
+ talloc_free(ltdb);
+ return -1;
+ }
+
+ return 0;
+}
+
+int ldb_tdb_init(void)
+{
+ return ldb_register_backend("tdb", ltdb_connect);
+}
diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.h b/source3/lib/ldb/ldb_tdb/ldb_tdb.h
new file mode 100644
index 0000000000..42f3dc2421
--- /dev/null
+++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -0,0 +1,129 @@
+
+#ifdef _SAMBA_BUILD_
+#include "system/filesys.h"
+#endif
+
+#if (_SAMBA_BUILD_ >= 4)
+#include "lib/tdb/include/tdb.h"
+#elif defined(_SAMBA_BUILD_)
+#include "tdb/include/tdb.h"
+#else
+#include "tdb.h"
+#endif
+
+/* this private structure is used by the ltdb backend in the
+ ldb_context */
+struct ltdb_private {
+ TDB_CONTEXT *tdb;
+ unsigned int connect_flags;
+
+ /* a double is used for portability and ease of string
+ handling. It has plenty of digits of precision */
+ unsigned long long sequence_number;
+
+ /* the low level tdb seqnum - used to avoid loading BASEINFO when
+ possible */
+ int tdb_seqnum;
+
+ struct ltdb_cache {
+ struct ldb_message *indexlist;
+ struct ldb_message *attributes;
+ struct ldb_message *subclasses;
+
+ struct {
+ char *name;
+ int flags;
+ } last_attribute;
+ } *cache;
+};
+
+/*
+ the async local context
+ holds also internal search state during a full db search
+*/
+struct ltdb_context {
+ struct ldb_module *module;
+
+ /* search stuff */
+ const struct ldb_parse_tree *tree;
+ const struct ldb_dn *base;
+ enum ldb_scope scope;
+ const char * const *attrs;
+
+ /* async stuff */
+ void *context;
+ int (*callback)(struct ldb_context *, void *, struct ldb_reply *);
+};
+
+/* special record types */
+#define LTDB_INDEX "@INDEX"
+#define LTDB_INDEXLIST "@INDEXLIST"
+#define LTDB_IDX "@IDX"
+#define LTDB_IDXATTR "@IDXATTR"
+#define LTDB_BASEINFO "@BASEINFO"
+#define LTDB_ATTRIBUTES "@ATTRIBUTES"
+#define LTDB_SUBCLASSES "@SUBCLASSES"
+
+/* special attribute types */
+#define LTDB_SEQUENCE_NUMBER "sequenceNumber"
+#define LTDB_MOD_TIMESTAMP "whenChanged"
+#define LTDB_OBJECTCLASS "objectClass"
+
+/* The following definitions come from lib/ldb/ldb_tdb/ldb_cache.c */
+
+int ltdb_cache_reload(struct ldb_module *module);
+int ltdb_cache_load(struct ldb_module *module);
+int ltdb_increase_sequence_number(struct ldb_module *module);
+int ltdb_check_at_attributes_values(const struct ldb_val *value);
+
+/* The following definitions come from lib/ldb/ldb_tdb/ldb_index.c */
+
+struct ldb_parse_tree;
+
+int ltdb_search_indexed(struct ldb_handle *handle);
+int ltdb_index_add(struct ldb_module *module, const struct ldb_message *msg);
+int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg);
+int ltdb_reindex(struct ldb_module *module);
+
+/* The following definitions come from lib/ldb/ldb_tdb/ldb_pack.c */
+
+int ltdb_pack_data(struct ldb_module *module,
+ const struct ldb_message *message,
+ struct TDB_DATA *data);
+void ltdb_unpack_data_free(struct ldb_module *module,
+ struct ldb_message *message);
+int ltdb_unpack_data(struct ldb_module *module,
+ const struct TDB_DATA *data,
+ struct ldb_message *message);
+
+/* The following definitions come from lib/ldb/ldb_tdb/ldb_search.c */
+
+int ltdb_has_wildcard(struct ldb_module *module, const char *attr_name,
+ const struct ldb_val *val);
+void ltdb_search_dn1_free(struct ldb_module *module, struct ldb_message *msg);
+int ltdb_search_dn1(struct ldb_module *module, const struct ldb_dn *dn, struct ldb_message *msg);
+int ltdb_add_attr_results(struct ldb_module *module,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message *msg,
+ const char * const attrs[],
+ unsigned int *count,
+ struct ldb_message ***res);
+int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs);
+int ltdb_search(struct ldb_module *module, struct ldb_request *req);
+
+/* The following definitions come from lib/ldb/ldb_tdb/ldb_tdb.c */
+struct ldb_handle *init_ltdb_handle(struct ltdb_private *ltdb, struct ldb_module *module,
+ struct ldb_request *req);
+struct TDB_DATA ltdb_key(struct ldb_module *module, const struct ldb_dn *dn);
+int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs);
+int ltdb_delete_noindex(struct ldb_module *module, const struct ldb_dn *dn);
+int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg);
+
+int ltdb_index_del_value(struct ldb_module *module, const char *dn,
+ struct ldb_message_element *el, int v_idx);
+
+struct tdb_context *ltdb_wrap_open(TALLOC_CTX *mem_ctx,
+ const char *path, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode,
+ struct ldb_context *ldb);
+
diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c b/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c
new file mode 100644
index 0000000000..2fff74d59a
--- /dev/null
+++ b/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c
@@ -0,0 +1,154 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#include "ldb/ldb_tdb/ldb_tdb.h"
+
+/*
+ the purpose of this code is to work around the braindead posix locking
+ rules, to allow us to have a ldb open more than once while allowing
+ locking to work
+*/
+
+struct ltdb_wrap {
+ struct ltdb_wrap *next, *prev;
+ struct tdb_context *tdb;
+ dev_t device;
+ ino_t inode;
+};
+
+static struct ltdb_wrap *tdb_list;
+
+/* destroy the last connection to a tdb */
+static int ltdb_wrap_destructor(struct ltdb_wrap *w)
+{
+ tdb_close(w->tdb);
+ if (w->next) {
+ w->next->prev = w->prev;
+ }
+ if (w->prev) {
+ w->prev->next = w->next;
+ }
+ if (w == tdb_list) {
+ tdb_list = w->next;
+ }
+ return 0;
+}
+
+static void ltdb_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
+static void ltdb_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
+{
+ va_list ap;
+ const char *name = tdb_name(tdb);
+ struct ldb_context *ldb = talloc_get_type(tdb_get_logging_private(tdb), struct ldb_context);
+ enum ldb_debug_level ldb_level;
+ char *message;
+ va_start(ap, fmt);
+ message = talloc_vasprintf(ldb, fmt, ap);
+ va_end(ap);
+
+ switch (level) {
+ case TDB_DEBUG_FATAL:
+ ldb_level = LDB_DEBUG_FATAL;
+ break;
+ case TDB_DEBUG_ERROR:
+ ldb_level = LDB_DEBUG_ERROR;
+ break;
+ case TDB_DEBUG_WARNING:
+ ldb_level = LDB_DEBUG_WARNING;
+ break;
+ case TDB_DEBUG_TRACE:
+ ldb_level = LDB_DEBUG_TRACE;
+ break;
+ default:
+ ldb_level = LDB_DEBUG_FATAL;
+ }
+
+ ldb_debug(ldb, ldb_level, "ltdb: tdb(%s): %s", name, message);
+ talloc_free(message);
+}
+
+/*
+ wrapped connection to a tdb database. The caller should _not_ free
+ this as it is not a talloc structure (as tdb does not use talloc
+ yet). It will auto-close when the caller frees the mem_ctx that is
+ passed to this call
+ */
+struct tdb_context *ltdb_wrap_open(TALLOC_CTX *mem_ctx,
+ const char *path, int hash_size,
+ int tdb_flags,
+ int open_flags, mode_t mode,
+ struct ldb_context *ldb)
+{
+ struct ltdb_wrap *w;
+ struct stat st;
+ struct tdb_logging_context log_ctx;
+
+ log_ctx.log_fn = ltdb_log_fn;
+ log_ctx.log_private = ldb;
+
+ if (stat(path, &st) == 0) {
+ for (w=tdb_list;w;w=w->next) {
+ if (st.st_dev == w->device && st.st_ino == w->inode) {
+ if (!talloc_reference(mem_ctx, w)) {
+ return NULL;
+ }
+ return w->tdb;
+ }
+ }
+ }
+
+ w = talloc(mem_ctx, struct ltdb_wrap);
+ if (w == NULL) {
+ return NULL;
+ }
+
+ w->tdb = tdb_open_ex(path, hash_size, tdb_flags, open_flags, mode, &log_ctx, NULL);
+ if (w->tdb == NULL) {
+ talloc_free(w);
+ return NULL;
+ }
+
+ if (fstat(tdb_fd(w->tdb), &st) != 0) {
+ tdb_close(w->tdb);
+ talloc_free(w);
+ return NULL;
+ }
+
+ w->device = st.st_dev;
+ w->inode = st.st_ino;
+
+ talloc_set_destructor(w, ltdb_wrap_destructor);
+
+ w->next = tdb_list;
+ w->prev = NULL;
+ if (tdb_list) {
+ tdb_list->prev = w;
+ }
+ tdb_list = w;
+
+ return w->tdb;
+}
+
diff --git a/source3/lib/ldb/libldb.m4 b/source3/lib/ldb/libldb.m4
new file mode 100644
index 0000000000..845563b4a1
--- /dev/null
+++ b/source3/lib/ldb/libldb.m4
@@ -0,0 +1,33 @@
+SMB_ENABLE(ldb_sqlite3,$with_sqlite3_support)
+
+AC_MSG_CHECKING([for Python])
+
+PYTHON=
+
+AC_ARG_WITH(python,
+[ --with-python=PYTHONNAME build Python libraries],
+[ case "${withval-python}" in
+ yes)
+ PYTHON=python
+ ;;
+ no)
+ PYTHON=
+ ;;
+ *)
+ PYTHON=${withval-python}
+ ;;
+ esac ])
+
+if test x"$PYTHON" != "x"; then
+ incdir=`python -c 'import sys; print "%s/include/python%d.%d" % (sys.prefix, sys.version_info[[0]], sys.version_info[[1]])'`
+ CPPFLAGS="$CPPFLAGS -I $incdir"
+fi
+
+if test x"$PYTHON" != "x"; then
+ AC_MSG_RESULT([${withval-python}])
+else
+ AC_MSG_RESULT(no)
+ SMB_ENABLE(swig_ldb, NO)
+fi
+
+AC_SUBST(PYTHON)
diff --git a/source3/lib/ldb/mainpage.dox b/source3/lib/ldb/mainpage.dox
new file mode 100644
index 0000000000..bbd8d9c502
--- /dev/null
+++ b/source3/lib/ldb/mainpage.dox
@@ -0,0 +1,80 @@
+/**
+
+\mainpage ldb
+
+\section Overview
+
+ldb is a LDAP-like embedded database. It is not at all LDAP standards
+compliant, so if you want a standards compliant database then please
+see the excellent <a href="http://www.openldap.org/">OpenLDAP</a>
+project.<p>
+
+What ldb does is provide a fast database with an LDAP-like API
+designed to be used within an application. In some ways it can be seen
+as a intermediate solution between key-value pair databases and a real
+LDAP database.<p>
+
+ldb is the database engine used in Samba4.
+
+\section Features
+
+The main features that separate ldb from other solutions are:
+ - Safe multi-reader, multi-writer, using byte range locking
+ - LDAP-like API
+ - fast operation
+ - choice of local tdb, local sqlite3 or remote LDAP backends
+ - integration with <a href="http://talloc.samba.org">talloc</a>
+ - schema-less operation, for trivial setup
+ - modules for extensions (such as schema support)
+ - easy setup of indexes and attribute properties
+ - ldbedit tool for database editing (reminiscent of 'vipw')
+ - ldif for import/export
+
+\section Documentation
+
+ldb has limited programmer and administrator documentation:
+ - a list of <a href="globals_func.html">functions</a>
+ - a list of <a href="examples.html">examples</a>
+ - a list of <a href="annotated.html">data structures</a>
+ - a list of <a href="globals_defs.html">constants</a>
+
+If you need more information than is presented in this document, you
+may wish to look at the source code, especially the source code in the
+<a href="http://samba.org/ftp/unpacked/samba4/source/lib/ldb/tools/">tools directory</a>.
+
+ldb makes use of the LDAP Data Interchange Format (LDIF), which is
+documented in <a href="http://www.ietf.org/rfc/rfc2849.txt">RFC
+2849</a>.
+
+\section Support
+
+ldb does not currently have its own mailing list or bug tracking
+system. For now, please use the <a
+href="https://lists.samba.org/mailman/listinfo/samba-technical">samba-technical</a>
+mailing list, and the <a href="http://bugzilla.samba.org/">Samba
+bugzilla</a> bug tracking system.
+
+\section Download
+
+You can download the latest release either via rsync or anonymous
+svn. To fetch via svn use the following commands:
+
+\verbatim
+ svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/ldb ldb
+ svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/tdb tdb
+ svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/talloc talloc
+\endverbatim
+
+To fetch via rsync use these commands:
+
+\verbatim
+ rsync -Pavz samba.org::ftp/unpacked/samba4/source/lib/ldb .
+ rsync -Pavz samba.org::ftp/unpacked/samba4/source/lib/tdb .
+ rsync -Pavz samba.org::ftp/unpacked/samba4/source/lib/talloc .
+\endverbatim
+
+\section Credits
+
+ldb is another product of the prolific <a href="http://samba.org/~tridge/">Andrew Tridgell</a>.
+
+*/
diff --git a/source3/lib/ldb/man/ad2oLschema.1.xml b/source3/lib/ldb/man/ad2oLschema.1.xml
new file mode 100644
index 0000000000..6ae8996477
--- /dev/null
+++ b/source3/lib/ldb/man/ad2oLschema.1.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="ad2oLschema.1">
+
+<refmeta>
+ <refentrytitle>ad2oLschema</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>ad2oLschema</refname>
+ <refpurpose>Converts AC-like LDAP schemas to OpenLDAP
+ compatible schema files</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>ad2oLschema</command>
+ <arg choice="opt">-I INPUT-FILE</arg>
+ <arg choice="opt">-O OUTPUT-FILE</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>ad2oLschema is a simple tool that converts AD-like LDIF
+ schema files into OpenLDAP schema files.</para>
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-H url</term>
+ <listitem><para>URL to an LDB or LDAP server with an AD schema to read. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-I input-file</term> <listitem><para>AD schema
+ to read. If neither this nor -H is specified, the
+ schema file will be read from standard input.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-O output-file</term>
+ <listitem><para>File to write OpenLDAP version of schema to.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 4.0 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>ldb(7), ldbmodify, ldbdel, ldif(5)</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para> ldb was written by
+ <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
+ ad2oLschema was written by <ulink
+ url="http://samba.org/~abartlet/">Andrew Bartlett</ulink>.
+ </para>
+
+ <para>
+If you wish to report a problem or make a suggestion then please see
+the <ulink url="http://ldb.samba.org/"/> web site for
+current contact and maintainer information.
+ </para>
+
+</refsect1>
+
+</refentry>
diff --git a/source3/lib/ldb/man/ldb.3.xml b/source3/lib/ldb/man/ldb.3.xml
new file mode 100644
index 0000000000..19d9a89e10
--- /dev/null
+++ b/source3/lib/ldb/man/ldb.3.xml
@@ -0,0 +1,262 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="ldb.3">
+
+<refmeta>
+ <refentrytitle>ldb</refentrytitle>
+ <manvolnum>3</manvolnum>
+</refmeta>
+
+<refnamediv>
+ <refname>ldb</refname>
+ <refclass>The Samba Project</refclass>
+ <refpurpose>A light-weight database library</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <synopsis>#include &lt;ldb.h&gt;</synopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>description</title>
+
+ <para>
+ldb is a light weight embedded database library and API. With a
+programming interface that is very similar to LDAP, ldb can store its
+data either in a tdb(3) database or in a real LDAP database.
+ </para>
+
+ <para>
+When used with the tdb backend ldb does not require any database
+daemon. Instead, ldb function calls are processed immediately by the
+ldb library, which does IO directly on the database, while allowing
+multiple readers/writers using operating system byte range locks. This
+leads to an API with very low overheads, often resulting in speeds of
+more than 10x what can be achieved with a more traditional LDAP
+architecture.
+ </para>
+
+ <para>
+In a taxonomy of databases ldb would sit half way between key/value
+pair databases (such as berkley db or tdb) and a full LDAP
+database. With a structured attribute oriented API like LDAP and good
+indexing capabilities, ldb can be used for quite sophisticated
+applications that need a light weight database, without the
+administrative overhead of a full LDAP installation.
+ </para>
+
+ <para>
+Included with ldb are a number of useful command line tools for
+manipulating a ldb database. These tools are similar in style to the
+equivalent ldap command line tools.
+ </para>
+
+ <para>
+In its default mode of operation with a tdb backend, ldb can also be
+seen as a "schema-less LDAP". By default ldb does not require a
+schema, which greatly reduces the complexity of getting started with
+ldb databases. As the complexity of you application grows you can take
+advantage of some of the optional schema-like attributes that ldb
+offers, or you can migrate to using the full LDAP api while keeping
+your exiting ldb code.
+ </para>
+
+ <para>
+If you are new to ldb, then I suggest starting with the manual pages
+for ldbsearch(1) and ldbedit(1), and experimenting with a local
+database. Then I suggest you look at the ldb_connect(3) and
+ldb_search(3) manual pages.
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>TOOLS</title>
+
+ <itemizedlist>
+ <listitem><para>
+ <application>ldbsearch(1)</application>
+ - command line ldb search utility
+ </para></listitem>
+
+ <listitem><para>
+ <application>ldbedit(1)</application>
+ - edit all or part of a ldb database using your favourite editor
+ </para></listitem>
+
+ <listitem><para>
+ <application>ldbadd(1)</application>
+ - add records to a ldb database using LDIF formatted input
+ </para></listitem>
+
+ <listitem><para>
+ <application>ldbdel(1)</application>
+ - delete records from a ldb database
+ </para></listitem>
+
+ <listitem><para>
+ <application>ldbmodify(1)</application>
+ - modify records in a ldb database using LDIF formatted input
+ </para></listitem>
+ </itemizedlist>
+</refsect1>
+
+<refsect1>
+ <title>FUNCTIONS</title>
+
+ <itemizedlist>
+ <listitem><para>
+ <function>ldb_connect(3)</function>
+ - connect to a ldb backend
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_search(3)</function>
+ - perform a database search
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_add(3)</function>
+ - add a record to the database
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_delete(3)</function>
+ - delete a record from the database
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_modify(3)</function>
+ - modify a record in the database
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_errstring(3)</function>
+ - retrieve extended error information from the last operation
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_ldif_write(3)</function>
+ - write a LDIF formatted message
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_ldif_write_file(3)</function>
+ - write a LDIF formatted message to a file
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_ldif_read(3)</function>
+ - read a LDIF formatted message
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_ldif_read_free(3)</function>
+ - free the result of a ldb_ldif_read()
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_ldif_read_file(3)</function>
+ - read a LDIF message from a file
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_ldif_read_string(3)</function>
+ - read a LDIF message from a string
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_msg_find_element(3)</function>
+ - find an element in a ldb_message
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_val_equal_exact(3)</function>
+ - compare two ldb_val structures
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_msg_find_val(3)</function>
+ - find an element by value
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_msg_add_empty(3)</function>
+ - add an empty message element to a ldb_message
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_msg_add(3)</function>
+ - add a non-empty message element to a ldb_message
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_msg_element_compare(3)</function>
+ - compare two ldb_message_element structures
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_msg_find_int(3)</function>
+ - return an integer value from a ldb_message
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_msg_find_uint(3)</function>
+ - return an unsigned integer value from a ldb_message
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_msg_find_double(3)</function>
+ - return a double value from a ldb_message
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_msg_find_string(3)</function>
+ - return a string value from a ldb_message
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_set_alloc(3)</function>
+ - set the memory allocation function to be used by ldb
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_set_debug(3)</function>
+ - set a debug handler to be used by ldb
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_set_debug_stderr(3)</function>
+ - set a debug handler for stderr output
+ </para></listitem>
+ </itemizedlist>
+</refsect1>
+
+<refsect1>
+ <title>Author</title>
+
+ <para>
+ ldb was written by
+ <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
+ </para>
+
+ <para>
+If you wish to report a problem or make a suggestion then please see
+the <ulink url="http://ldb.samba.org/"/> web site for
+current contact and maintainer information.
+ </para>
+
+ <para>
+ldb is released under the GNU Lesser General Public License version 2
+or later. Please see the file COPYING for license details.
+ </para>
+</refsect1>
+</refentry>
diff --git a/source3/lib/ldb/man/ldbadd.1.xml b/source3/lib/ldb/man/ldbadd.1.xml
new file mode 100644
index 0000000000..7ad0f835d0
--- /dev/null
+++ b/source3/lib/ldb/man/ldbadd.1.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="ldbadd.1">
+
+<refmeta>
+ <refentrytitle>ldbadd</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>ldbadd</refname>
+ <refpurpose>Command-line utility for adding records to an LDB</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>ldbadd</command>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-H LDB-URL</arg>
+ <arg choice="opt">ldif-file1</arg>
+ <arg choice="opt">ldif-file2</arg>
+ <arg choice="opt">...</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>ldbadd adds records to an ldb(7) database. It reads
+ the ldif(5) files specified on the command line and adds
+ the records from these files to the LDB database, which is specified
+ by the -H option or the LDB_URL environment variable.
+ </para>
+
+ <para>If - is specified as a ldb file, the ldif input is read from
+ standard input.</para>
+
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>
+ Show list of available options.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-H &lt;ldb-url&gt;</term>
+ <listitem><para>
+ LDB URL to connect to. See ldb(7) for details.
+ </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>ENVIRONMENT</title>
+
+ <variablelist>
+ <varlistentry><term>LDB_URL</term>
+ <listitem><para>LDB URL to connect to (can be overrided by using the
+ -H command-line option.)</para></listitem>
+ </varlistentry>
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 4.0 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>ldb(7), ldbmodify, ldbdel, ldif(5)</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para> ldb was written by
+ <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
+ </para>
+
+ <para>
+If you wish to report a problem or make a suggestion then please see
+the <ulink url="http://ldb.samba.org/"/> web site for
+current contact and maintainer information.
+ </para>
+
+ <para>This manpage was written by Jelmer Vernooij.</para>
+
+</refsect1>
+
+</refentry>
diff --git a/source3/lib/ldb/man/ldbdel.1.xml b/source3/lib/ldb/man/ldbdel.1.xml
new file mode 100644
index 0000000000..7dfc7366f6
--- /dev/null
+++ b/source3/lib/ldb/man/ldbdel.1.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="ldbdel.1">
+
+<refmeta>
+ <refentrytitle>ldbdel</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>ldbdel</refname>
+ <refpurpose>Command-line program for deleting LDB records</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>ldbdel</command>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-H LDB-URL</arg>
+ <arg choice="opt">dn</arg>
+ <arg choice="opt">...</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>ldbdel deletes records from an ldb(7) database.
+ It deletes the records identified by the dn's specified
+ on the command-line. </para>
+
+ <para>ldbdel uses either the database that is specified with
+ the -H option or the database specified by the LDB_URL environment
+ variable.</para>
+
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>
+ Show list of available options.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-H &lt;ldb-url&gt;</term>
+ <listitem><para>
+ LDB URL to connect to. See ldb(7) for details.
+ </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>ENVIRONMENT</title>
+
+ <variablelist>
+ <varlistentry><term>LDB_URL</term>
+ <listitem><para>LDB URL to connect to (can be overrided by using the
+ -H command-line option.)</para></listitem>
+ </varlistentry>
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 4.0 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>ldb(7), ldbmodify, ldbadd, ldif(5)</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para> ldb was written by
+ <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
+ </para>
+
+ <para>
+If you wish to report a problem or make a suggestion then please see
+the <ulink url="http://ldb.samba.org/"/> web site for
+current contact and maintainer information.
+ </para>
+
+ <para>ldbdel was written by Andrew Tridgell.</para>
+
+ <para>This manpage was written by Jelmer Vernooij.</para>
+
+</refsect1>
+
+</refentry>
diff --git a/source3/lib/ldb/man/ldbedit.1.xml b/source3/lib/ldb/man/ldbedit.1.xml
new file mode 100644
index 0000000000..15c69b1b25
--- /dev/null
+++ b/source3/lib/ldb/man/ldbedit.1.xml
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="ldbedit.1">
+
+ <refmeta>
+ <refentrytitle>ldbedit</refentrytitle>
+ <manvolnum>1</manvolnum>
+ </refmeta>
+
+
+ <refnamediv>
+ <refname>ldbedit</refname>
+ <refpurpose>Edit LDB databases using your preferred editor</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>ldbedit</command>
+ <arg choice="opt">-?</arg>
+ <arg choice="opt">--usage</arg>
+ <arg choice="opt">-s base|one|sub</arg>
+ <arg choice="opt">-b basedn</arg>
+ <arg choice="opt">-a</arg>
+ <arg choice="opt">-e editor</arg>
+ <arg choice="opt">-H LDB-URL</arg>
+ <arg choice="opt">expression</arg>
+ <arg rep="repeat" choice="opt">attributes</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>ldbedit is a utility that allows you to edit LDB entries (in
+ tdb files, sqlite files or LDAP servers) using your preferred editor.
+ ldbedit generates an LDIF file based on your query, allows you to edit
+ the LDIF, and then merges that LDIF back into the LDB backend.
+ </para>
+
+</refsect1>
+
+
+ <refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-?</term>
+ <term>--help</term>
+ <listitem>
+ <para>
+ Show list of available options, and a phrase describing what that option
+ does.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>--usage</term>
+ <listitem>
+ <para>
+ Show list of available options. This is similar to the help option,
+ however it does not provide any description, and is hence shorter.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-H &lt;ldb-url&gt;</term>
+ <listitem>
+ <para>
+ LDB URL to connect to. For a tdb database,
+ this will be of the form
+ tdb://<replaceable>filename</replaceable>.
+ For a LDAP connection over unix domain
+ sockets, this will be of the form
+ ldapi://<replaceable>socket</replaceable>. For
+ a (potentially remote) LDAP connection over
+ TCP, this will be of the form
+ ldap://<replaceable>hostname</replaceable>. For
+ an SQLite database, this will be of the form
+ sqlite://<replaceable>filename</replaceable>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-s one|sub|base</term>
+ <listitem><para>Search scope to use. One-level, subtree or base.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-a</term>
+ <term>-all</term>
+ <listitem>
+ <para>Edit all records. This allows you to
+ apply the same change to a number of records
+ at once. You probably want to combine this
+ with an expression of the form
+ "objectclass=*".
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-e editor</term>
+ <term>--editor editor</term>
+ <listitem>
+ <para>Specify the editor that should be used (overrides
+ the VISUAL and EDITOR environment
+ variables). If this option is not used, and
+ neither VISUAL nor EDITOR environment variables
+ are set, then the vi editor will be used.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-b basedn</term>
+ <listitem><para>Specify Base Distinguished Name to use.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-v</term>
+ <term>--verbose</term>
+ <listitem>
+ <para>Make ldbedit more verbose about the
+ operations that are being performed. Without
+ this option, ldbedit will only provide a
+ summary change line.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+ </refsect1>
+
+ <refsect1>
+ <title>ENVIRONMENT</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>LDB_URL</term>
+ <listitem>
+ <para>LDB URL to connect to. This can be
+ overridden by using the -H command-line option.)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>VISUAL and EDITOR</term>
+ <listitem>
+ <para>
+ Environment variables used to determine what
+ editor to use. VISUAL takes precedence over
+ EDITOR, and both are overridden by the
+ -e command-line option.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </refsect1>
+
+ <refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 4.0 of the Samba suite.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>SEE ALSO</title>
+
+ <para>ldb(7), ldbmodify(1), ldbdel(1), ldif(5), vi(1)</para>
+
+ </refsect1>
+
+ <refsect1>
+ <title>AUTHOR</title>
+
+ <para>
+ ldb was written by
+ <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
+ </para>
+
+ <para>
+ If you wish to report a problem or make a suggestion then please see
+ the <ulink url="http://ldb.samba.org/"/> web site for
+ current contact and maintainer information.
+ </para>
+
+ <para>
+ This manpage was written by Jelmer Vernooij and updated
+ by Brad Hards.
+ </para>
+
+ </refsect1>
+
+</refentry>
diff --git a/source3/lib/ldb/man/ldbmodify.1.xml b/source3/lib/ldb/man/ldbmodify.1.xml
new file mode 100644
index 0000000000..bc19647785
--- /dev/null
+++ b/source3/lib/ldb/man/ldbmodify.1.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="ldbmodify.1">
+
+<refmeta>
+ <refentrytitle>ldbmodify</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>ldbmodify</refname>
+ <refpurpose>Modify records in a LDB database</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>ldbmodify</command>
+ <arg choice="opt">-H LDB-URL</arg>
+ <arg choice="opt">ldif-file</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>
+ ldbmodify changes, adds and deletes records in a LDB database.
+ The changes that should be made to the LDB database are read from
+ the specified LDIF-file. If - is specified as the filename, input is read from stdin.
+ </para>
+
+ <para>For now, see ldapmodify(1) for details on the LDIF file format.</para>
+
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-H &lt;ldb-url&gt;</term>
+ <listitem><para>
+ LDB URL to connect to. See ldb(7) for details.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>ENVIRONMENT</title>
+
+ <variablelist>
+ <varlistentry><term>LDB_URL</term>
+ <listitem><para>LDB URL to connect to (can be overrided by using the
+ -H command-line option.)</para></listitem>
+ </varlistentry>
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 4.0 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>ldb(7), ldbedit</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para> ldb was written by
+ <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
+ </para>
+
+ <para>
+If you wish to report a problem or make a suggestion then please see
+the <ulink url="http://ldb.samba.org/"/> web site for
+current contact and maintainer information.
+ </para>
+
+ <para>This manpage was written by Jelmer Vernooij.</para>
+
+</refsect1>
+
+</refentry>
diff --git a/source3/lib/ldb/man/ldbrename.1.xml b/source3/lib/ldb/man/ldbrename.1.xml
new file mode 100644
index 0000000000..391ec84ccc
--- /dev/null
+++ b/source3/lib/ldb/man/ldbrename.1.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="ldbrename.1">
+
+<refmeta>
+ <refentrytitle>ldbrename</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>ldbrename</refname>
+ <refpurpose>Edit LDB databases using your favorite editor</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>ldbrename</command>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-o options</arg>
+ <arg choice="req">olddn</arg>
+ <arg choice="req">newdb</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>ldbrename is a utility that allows you to rename trees in
+ an LDB database based by DN. This utility takes
+ two arguments: the original
+ DN name of the top element and the DN to change it to.
+ </para>
+
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>
+ Show list of available options.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-H &lt;ldb-url&gt;</term>
+ <listitem><para>
+ LDB URL to connect to. See ldb(7) for details.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-o options</term>
+ <listitem><para>Extra ldb options, such as
+ modules.</para></listitem>
+ </varlistentry>
+
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>ENVIRONMENT</title>
+
+ <variablelist>
+ <varlistentry><term>LDB_URL</term>
+ <listitem><para>LDB URL to connect to (can be overrided by using the
+ -H command-line option.)</para></listitem>
+ </varlistentry>
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 4.0 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>ldb(7), ldbmodify, ldbdel, ldif(5)</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para> ldb was written by
+ <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
+ </para>
+
+ <para>
+If you wish to report a problem or make a suggestion then please see
+the <ulink url="http://ldb.samba.org/"/> web site for
+current contact and maintainer information.
+ </para>
+
+ <para>This manpage was written by Jelmer Vernooij.</para>
+
+</refsect1>
+
+</refentry>
diff --git a/source3/lib/ldb/man/ldbsearch.1.xml b/source3/lib/ldb/man/ldbsearch.1.xml
new file mode 100644
index 0000000000..ed3749b920
--- /dev/null
+++ b/source3/lib/ldb/man/ldbsearch.1.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="ldbsearch.1">
+
+<refmeta>
+ <refentrytitle>ldbsearch</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>ldbsearch</refname>
+ <refpurpose>Search for records in a LDB database</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>ldbsearch</command>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-s base|one|sub</arg>
+ <arg choice="opt">-b basedn</arg>
+ <arg chioce="opt">-i</arg>
+ <arg choice="opt">-H LDB-URL</arg>
+ <arg choice="opt">expression</arg>
+ <arg choice="opt">attributes</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>ldbsearch searches a LDB database for records matching the
+ specified expression (see the ldapsearch(1) manpage for
+ a description of the expression format). For each
+ record, the specified attributes are printed.
+ </para>
+
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>
+ Show list of available options.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-H &lt;ldb-url&gt;</term>
+ <listitem><para>
+ LDB URL to connect to. See ldb(7) for details.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-s one|sub|base</term>
+ <listitem><para>Search scope to use. One-level, subtree or base.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-i</term>
+ <listitem><para>Read search expressions from stdin. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-b basedn</term>
+ <listitem><para>Specify Base DN to use.</para></listitem>
+ </varlistentry>
+
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>ENVIRONMENT</title>
+
+ <variablelist>
+ <varlistentry><term>LDB_URL</term>
+ <listitem><para>LDB URL to connect to (can be overrided by using the
+ -H command-line option.)</para></listitem>
+ </varlistentry>
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 4.0 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>ldb(7), ldbedit(1)</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para> ldb was written by
+ <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
+ </para>
+
+ <para>
+If you wish to report a problem or make a suggestion then please see
+the <ulink url="http://ldb.samba.org/"/> web site for
+current contact and maintainer information.
+ </para>
+
+ <para>This manpage was written by Jelmer Vernooij.</para>
+
+</refsect1>
+
+</refentry>
diff --git a/source3/lib/ldb/man/oLschema2ldif.1.xml b/source3/lib/ldb/man/oLschema2ldif.1.xml
new file mode 100644
index 0000000000..b1e681be4e
--- /dev/null
+++ b/source3/lib/ldb/man/oLschema2ldif.1.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="oLschema2ldif.1">
+
+<refmeta>
+ <refentrytitle>oLschema2ldif</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>oLschema2ldif</refname>
+ <refpurpose>Converts LDAP schema's to LDB-compatible LDIF</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>oLschema2ldif</command>
+ <arg choice="opt">-I INPUT-FILE</arg>
+ <arg choice="opt">-O OUTPUT-FILE</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>oLschema2ldif is a simple tool that converts standard OpenLDAP schema files to a LDIF format that is understood by LDB.</para>
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-I input-file</term>
+ <listitem><para>OpenLDAP schema to read. If none are specified,
+the schema file will be read from standard input.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-O output-file</term>
+ <listitem><para>File to write ldif version of schema to.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 4.0 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>ldb(7), ldbmodify, ldbdel, ldif(5)</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para> ldb was written by
+ <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
+ oLschema2ldif was written by <ulink url="mailto:idra@samba.org">Simo Sorce</ulink>.
+ </para>
+
+ <para>
+If you wish to report a problem or make a suggestion then please see
+the <ulink url="http://ldb.samba.org/"/> web site for
+current contact and maintainer information.
+ </para>
+
+</refsect1>
+
+</refentry>
diff --git a/source3/lib/ldb/modules/asq.c b/source3/lib/ldb/modules/asq.c
new file mode 100644
index 0000000000..413257f20a
--- /dev/null
+++ b/source3/lib/ldb/modules/asq.c
@@ -0,0 +1,488 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb attribute scoped query control module
+ *
+ * Description: this module searches all the the objects pointed
+ * by the DNs contained in the references attribute
+ *
+ * Author: Simo Sorce
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+struct asq_context {
+
+ enum {ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step;
+
+ struct ldb_module *module;
+ void *up_context;
+ int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
+
+ const char * const *req_attrs;
+ char *req_attribute;
+ enum {
+ ASQ_CTRL_SUCCESS = 0,
+ ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX = 21,
+ ASQ_CTRL_UNWILLING_TO_PERFORM = 53,
+ ASQ_CTRL_AFFECTS_MULTIPLE_DSA = 71
+ } asq_ret;
+
+ struct ldb_request *base_req;
+ struct ldb_reply *base_res;
+
+ struct ldb_request **reqs;
+ int num_reqs;
+ int cur_req;
+
+ struct ldb_control **controls;
+};
+
+static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module,
+ void *context,
+ int (*callback)(struct ldb_context *, void *, struct ldb_reply *))
+{
+ struct asq_context *ac;
+ struct ldb_handle *h;
+
+ h = talloc_zero(mem_ctx, struct ldb_handle);
+ if (h == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ return NULL;
+ }
+
+ h->module = module;
+
+ ac = talloc_zero(h, struct asq_context);
+ if (ac == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ talloc_free(h);
+ return NULL;
+ }
+
+ h->private_data = (void *)ac;
+
+ h->state = LDB_ASYNC_INIT;
+ h->status = LDB_SUCCESS;
+
+ ac->module = module;
+ ac->up_context = context;
+ ac->up_callback = callback;
+
+ return h;
+}
+
+static int asq_terminate(struct ldb_handle *handle)
+{
+ struct asq_context *ac;
+ struct ldb_reply *ares;
+ struct ldb_asq_control *asq;
+ int i;
+
+ ac = talloc_get_type(handle->private_data, struct asq_context);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ handle->status = LDB_SUCCESS;
+ handle->state = LDB_ASYNC_DONE;
+
+ ares = talloc_zero(ac, struct ldb_reply);
+ if (ares == NULL)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ ares->type = LDB_REPLY_DONE;
+
+ if (ac->controls) {
+ for (i = 0; ac->controls[i]; i++);
+ ares->controls = talloc_move(ares, &ac->controls);
+ } else {
+ i = 0;
+ }
+
+ ares->controls = talloc_realloc(ares, ares->controls, struct ldb_control *, i + 2);
+
+ if (ares->controls == NULL)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ ares->controls[i] = talloc(ares->controls, struct ldb_control);
+ if (ares->controls[i] == NULL)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ ares->controls[i]->oid = LDB_CONTROL_ASQ_OID;
+ ares->controls[i]->critical = 0;
+
+ asq = talloc_zero(ares->controls[i], struct ldb_asq_control);
+ if (asq == NULL)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ asq->result = ac->asq_ret;
+
+ ares->controls[i]->data = asq;
+
+ ares->controls[i + 1] = NULL;
+
+ ac->up_callback(ac->module->ldb, ac->up_context, ares);
+
+ return LDB_SUCCESS;
+}
+
+static int asq_base_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+{
+ struct asq_context *ac;
+
+ if (!context || !ares) {
+ ldb_set_errstring(ldb, "NULL Context or Result in callback");
+ goto error;
+ }
+
+ if (!(ac = talloc_get_type(context, struct asq_context))) {
+ goto error;
+ }
+
+ /* we are interested only in the single reply (base search) we receive here */
+ if (ares->type == LDB_REPLY_ENTRY) {
+ ac->base_res = talloc_move(ac, &ares);
+ } else {
+ talloc_free(ares);
+ }
+
+ return LDB_SUCCESS;
+error:
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+static int asq_reqs_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+{
+ struct asq_context *ac;
+
+ if (!context || !ares) {
+ ldb_set_errstring(ldb, "NULL Context or Result in callback");
+ goto error;
+ }
+
+ if (!(ac = talloc_get_type(context, struct asq_context))) {
+ goto error;
+ }
+
+ /* we are interested only in the single reply (base search) we receive here */
+ if (ares->type == LDB_REPLY_ENTRY) {
+
+ /* pass the message up to the original callback as we
+ * do not have to elaborate on it any further */
+ return ac->up_callback(ac->module->ldb, ac->up_context, ares);
+
+ } else { /* ignore any REFERRAL or DONE reply */
+ talloc_free(ares);
+ }
+
+ return LDB_SUCCESS;
+error:
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+static int asq_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_control *control;
+ struct ldb_asq_control *asq_ctrl;
+ struct asq_context *ac;
+ struct ldb_handle *h;
+ char **base_attrs;
+ int ret;
+
+ /* check if there's a paged request control */
+ control = get_control_from_list(req->controls, LDB_CONTROL_ASQ_OID);
+ if (control == NULL) {
+ /* not found go on */
+ return ldb_next_request(module, req);
+ }
+
+ req->handle = NULL;
+
+ if (!req->callback || !req->context) {
+ ldb_set_errstring(module->ldb,
+ "Async interface called with NULL callback function or NULL context");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ asq_ctrl = talloc_get_type(control->data, struct ldb_asq_control);
+ if (!asq_ctrl) {
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ h = init_handle(req, module, req->context, req->callback);
+ if (!h) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (!(ac = talloc_get_type(h->private_data, struct asq_context))) {
+
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->handle = h;
+
+ /* check the search is well formed */
+ if (req->op.search.scope != LDB_SCOPE_BASE) {
+ ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM;
+ return asq_terminate(h);
+ }
+
+ ac->req_attrs = req->op.search.attrs;
+ ac->req_attribute = talloc_strdup(ac, asq_ctrl->source_attribute);
+ if (ac->req_attribute == NULL)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ /* get the object to retrieve the DNs to search */
+ ac->base_req = talloc_zero(req, struct ldb_request);
+ if (ac->base_req == NULL)
+ return LDB_ERR_OPERATIONS_ERROR;
+ ac->base_req->operation = req->operation;
+ ac->base_req->op.search.base = req->op.search.base;
+ ac->base_req->op.search.scope = LDB_SCOPE_BASE;
+ ac->base_req->op.search.tree = req->op.search.tree;
+ base_attrs = talloc_array(ac->base_req, char *, 2);
+ if (base_attrs == NULL)
+ return LDB_ERR_OPERATIONS_ERROR;
+ base_attrs[0] = talloc_strdup(base_attrs, asq_ctrl->source_attribute);
+ if (base_attrs[0] == NULL)
+ return LDB_ERR_OPERATIONS_ERROR;
+ base_attrs[1] = NULL;
+ ac->base_req->op.search.attrs = (const char * const *)base_attrs;
+
+ ac->base_req->context = ac;
+ ac->base_req->callback = asq_base_callback;
+ ldb_set_timeout_from_prev_req(module->ldb, req, ac->base_req);
+
+ ac->step = ASQ_SEARCH_BASE;
+
+ ret = ldb_request(module->ldb, ac->base_req);
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int asq_requests(struct ldb_handle *handle) {
+ struct asq_context *ac;
+ struct ldb_message_element *el;
+ int i;
+
+ if (!(ac = talloc_get_type(handle->private_data,
+ struct asq_context))) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* look up the DNs */
+ if (ac->base_res == NULL) {
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+ el = ldb_msg_find_element(ac->base_res->message, ac->req_attribute);
+ /* no values found */
+ if (el == NULL) {
+ ac->asq_ret = ASQ_CTRL_SUCCESS;
+ return asq_terminate(handle);
+ }
+
+ /* build up the requests call chain */
+ ac->num_reqs = el->num_values;
+ ac->cur_req = 0;
+ ac->reqs = talloc_array(ac, struct ldb_request *, ac->num_reqs);
+ if (ac->reqs == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ for (i = 0; i < el->num_values; i++) {
+
+ ac->reqs[i] = talloc_zero(ac->reqs, struct ldb_request);
+ if (ac->reqs[i] == NULL)
+ return LDB_ERR_OPERATIONS_ERROR;
+ ac->reqs[i]->operation = LDB_SEARCH;
+ ac->reqs[i]->op.search.base = ldb_dn_explode(ac->reqs[i], (const char *)el->values[i].data);
+ if (ac->reqs[i]->op.search.base == NULL) {
+ ac->asq_ret = ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX;
+ return asq_terminate(handle);
+ }
+ ac->reqs[i]->op.search.scope = LDB_SCOPE_BASE;
+ ac->reqs[i]->op.search.tree = ac->base_req->op.search.tree;
+ ac->reqs[i]->op.search.attrs = ac->req_attrs;
+
+ ac->reqs[i]->context = ac;
+ ac->reqs[i]->callback = asq_reqs_callback;
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->base_req, ac->reqs[i]);
+ }
+
+ ac->step = ASQ_SEARCH_MULTI;
+
+ return LDB_SUCCESS;
+}
+
+static int asq_wait_none(struct ldb_handle *handle)
+{
+ struct asq_context *ac;
+ int ret;
+
+ if (!handle || !handle->private_data) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (handle->state == LDB_ASYNC_DONE) {
+ return handle->status;
+ }
+
+ handle->state = LDB_ASYNC_PENDING;
+ handle->status = LDB_SUCCESS;
+
+ if (!(ac = talloc_get_type(handle->private_data,
+ struct asq_context))) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ switch (ac->step) {
+ case ASQ_SEARCH_BASE:
+ ret = ldb_wait(ac->base_req->handle, LDB_WAIT_NONE);
+
+ if (ret != LDB_SUCCESS) {
+ handle->status = ret;
+ goto done;
+ }
+
+ if (ac->base_req->handle->status != LDB_SUCCESS) {
+ handle->status = ac->base_req->handle->status;
+ goto done;
+ }
+ if (ac->base_req->handle->state != LDB_ASYNC_DONE) {
+ return LDB_SUCCESS;
+ }
+
+ ret = asq_requests(handle);
+
+ /* no break nor return,
+ * the set of requests is performed in ASQ_SEARCH_MULTI
+ */
+
+ case ASQ_SEARCH_MULTI:
+
+ if (ac->reqs[ac->cur_req]->handle == NULL) {
+ ret = ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ ret = ldb_wait(ac->reqs[ac->cur_req]->handle, LDB_WAIT_NONE);
+
+ if (ret != LDB_SUCCESS) {
+ handle->status = ret;
+ goto done;
+ }
+ if (ac->reqs[ac->cur_req]->handle->status != LDB_SUCCESS) {
+ handle->status = ac->reqs[ac->cur_req]->handle->status;
+ }
+
+ if (ac->reqs[ac->cur_req]->handle->state == LDB_ASYNC_DONE) {
+ ac->cur_req++;
+ }
+
+ if (ac->cur_req < ac->num_reqs) {
+ return LDB_SUCCESS;
+ }
+
+ return asq_terminate(handle);
+
+ default:
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ ret = LDB_SUCCESS;
+
+done:
+ handle->state = LDB_ASYNC_DONE;
+ return ret;
+}
+
+static int asq_wait_all(struct ldb_handle *handle)
+{
+ int ret;
+
+ while (handle->state != LDB_ASYNC_DONE) {
+ ret = asq_wait_none(handle);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ return handle->status;
+}
+
+static int asq_wait(struct ldb_handle *handle, enum ldb_wait_type type)
+{
+ if (type == LDB_WAIT_ALL) {
+ return asq_wait_all(handle);
+ } else {
+ return asq_wait_none(handle);
+ }
+}
+
+static int asq_init(struct ldb_module *module)
+{
+ struct ldb_request *req;
+ int ret;
+
+ req = talloc_zero(module, struct ldb_request);
+ if (req == NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "asq: Out of memory!\n");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_REQ_REGISTER_CONTROL;
+ req->op.reg_control.oid = LDB_CONTROL_ASQ_OID;
+
+ ret = ldb_request(module->ldb, req);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING, "asq: Unable to register control with rootdse!\n");
+ }
+
+ return ldb_next_init(module);
+}
+
+
+static const struct ldb_module_ops asq_ops = {
+ .name = "asq",
+ .search = asq_search,
+ .wait = asq_wait,
+ .init_context = asq_init
+};
+
+int ldb_asq_init(void)
+{
+ return ldb_register_module(&asq_ops);
+}
diff --git a/source3/lib/ldb/modules/ldb_map.c b/source3/lib/ldb/modules/ldb_map.c
new file mode 100644
index 0000000000..54e1758c1e
--- /dev/null
+++ b/source3/lib/ldb/modules/ldb_map.c
@@ -0,0 +1,1337 @@
+/*
+ ldb database mapping module
+
+ Copyright (C) Jelmer Vernooij 2005
+ Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
+
+ * NOTICE: this module is NOT released under the GNU LGPL license as
+ * other ldb code. This module is release under the GNU GPL v2 or
+ * later license.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb ldb_map module
+ *
+ * Description: Map portions of data into a different format on a
+ * remote partition.
+ *
+ * Author: Jelmer Vernooij, Martin Kuehl
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#include "ldb/modules/ldb_map.h"
+#include "ldb/modules/ldb_map_private.h"
+
+/* Description of the provided ldb requests:
+ - special attribute 'isMapped'
+
+ - search:
+ - if parse tree can be split
+ - search remote records w/ remote attrs and parse tree
+ - otherwise
+ - enumerate all remote records
+ - for each remote result
+ - map remote result to local message
+ - search local result
+ - is present
+ - merge local into remote result
+ - run callback on merged result
+ - otherwise
+ - run callback on remote result
+
+ - add:
+ - split message into local and remote part
+ - if local message is not empty
+ - add isMapped to local message
+ - add local message
+ - add remote message
+
+ - modify:
+ - split message into local and remote part
+ - if local message is not empty
+ - add isMapped to local message
+ - search for local record
+ - if present
+ - modify local record
+ - otherwise
+ - add local message
+ - modify remote record
+
+ - delete:
+ - search for local record
+ - if present
+ - delete local record
+ - delete remote record
+
+ - rename:
+ - search for local record
+ - if present
+ - rename local record
+ - modify local isMapped
+ - rename remote record
+*/
+
+
+
+/* Private data structures
+ * ======================= */
+
+/* Global private data */
+/* Extract mappings from private data. */
+const struct ldb_map_context *map_get_context(struct ldb_module *module)
+{
+ const struct map_private *data = talloc_get_type(module->private_data, struct map_private);
+ return data->context;
+}
+
+/* Create a generic request context. */
+static struct map_context *map_init_context(struct ldb_handle *h, struct ldb_request *req)
+{
+ struct map_context *ac;
+
+ ac = talloc_zero(h, struct map_context);
+ if (ac == NULL) {
+ map_oom(h->module);
+ return NULL;
+ }
+
+ ac->module = h->module;
+ ac->orig_req = req;
+
+ return ac;
+}
+
+/* Create a search request context. */
+struct map_search_context *map_init_search_context(struct map_context *ac, struct ldb_reply *ares)
+{
+ struct map_search_context *sc;
+
+ sc = talloc_zero(ac, struct map_search_context);
+ if (sc == NULL) {
+ map_oom(ac->module);
+ return NULL;
+ }
+
+ sc->ac = ac;
+ sc->local_res = NULL;
+ sc->remote_res = ares;
+
+ return sc;
+}
+
+/* Create a request context and handle. */
+struct ldb_handle *map_init_handle(struct ldb_request *req, struct ldb_module *module)
+{
+ struct map_context *ac;
+ struct ldb_handle *h;
+
+ h = talloc_zero(req, struct ldb_handle);
+ if (h == NULL) {
+ map_oom(module);
+ return NULL;
+ }
+
+ h->module = module;
+
+ ac = map_init_context(h, req);
+ if (ac == NULL) {
+ talloc_free(h);
+ return NULL;
+ }
+
+ h->private_data = (void *)ac;
+
+ h->state = LDB_ASYNC_INIT;
+ h->status = LDB_SUCCESS;
+
+ return h;
+}
+
+
+/* Dealing with DNs for different partitions
+ * ========================================= */
+
+/* Check whether any data should be stored in the local partition. */
+BOOL map_check_local_db(struct ldb_module *module)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+
+ if (!data->remote_base_dn || !data->local_base_dn) {
+ return False;
+ }
+
+ return True;
+}
+
+/* Copy a DN with the base DN of the local partition. */
+static struct ldb_dn *ldb_dn_rebase_local(void *mem_ctx, const struct ldb_map_context *data, const struct ldb_dn *dn)
+{
+ return ldb_dn_copy_rebase(mem_ctx, dn, data->remote_base_dn, data->local_base_dn);
+}
+
+/* Copy a DN with the base DN of the remote partition. */
+static struct ldb_dn *ldb_dn_rebase_remote(void *mem_ctx, const struct ldb_map_context *data, const struct ldb_dn *dn)
+{
+ return ldb_dn_copy_rebase(mem_ctx, dn, data->local_base_dn, data->remote_base_dn);
+}
+
+/* Run a request and make sure it targets the remote partition. */
+/* TODO: free old DNs and messages? */
+int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ struct ldb_message *msg;
+
+ switch (request->operation) {
+ case LDB_SEARCH:
+ if (request->op.search.base) {
+ request->op.search.base = ldb_dn_rebase_remote(request, data, request->op.search.base);
+ } else {
+ request->op.search.base = data->remote_base_dn;
+ /* TODO: adjust scope? */
+ }
+ break;
+
+ case LDB_ADD:
+ msg = ldb_msg_copy_shallow(request, request->op.add.message);
+ msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn);
+ request->op.add.message = msg;
+ break;
+
+ case LDB_MODIFY:
+ msg = ldb_msg_copy_shallow(request, request->op.mod.message);
+ msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn);
+ request->op.mod.message = msg;
+ break;
+
+ case LDB_DELETE:
+ request->op.del.dn = ldb_dn_rebase_remote(request, data, request->op.del.dn);
+ break;
+
+ case LDB_RENAME:
+ request->op.rename.olddn = ldb_dn_rebase_remote(request, data, request->op.rename.olddn);
+ request->op.rename.newdn = ldb_dn_rebase_remote(request, data, request->op.rename.newdn);
+ break;
+
+ default:
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "Invalid remote request!\n");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_next_request(module, request);
+}
+
+
+/* Finding mappings for attributes and objectClasses
+ * ================================================= */
+
+/* Find an objectClass mapping by the local name. */
+static const struct ldb_map_objectclass *map_objectclass_find_local(const struct ldb_map_context *data, const char *name)
+{
+ int i;
+
+ for (i = 0; data->objectclass_maps && data->objectclass_maps[i].local_name; i++) {
+ if (ldb_attr_cmp(data->objectclass_maps[i].local_name, name) == 0) {
+ return &data->objectclass_maps[i];
+ }
+ }
+
+ return NULL;
+}
+
+/* Find an objectClass mapping by the remote name. */
+static const struct ldb_map_objectclass *map_objectclass_find_remote(const struct ldb_map_context *data, const char *name)
+{
+ int i;
+
+ for (i = 0; data->objectclass_maps && data->objectclass_maps[i].remote_name; i++) {
+ if (ldb_attr_cmp(data->objectclass_maps[i].remote_name, name) == 0) {
+ return &data->objectclass_maps[i];
+ }
+ }
+
+ return NULL;
+}
+
+/* Find an attribute mapping by the local name. */
+const struct ldb_map_attribute *map_attr_find_local(const struct ldb_map_context *data, const char *name)
+{
+ int i;
+
+ for (i = 0; data->attribute_maps[i].local_name; i++) {
+ if (ldb_attr_cmp(data->attribute_maps[i].local_name, name) == 0) {
+ return &data->attribute_maps[i];
+ }
+ }
+ for (i = 0; data->attribute_maps[i].local_name; i++) {
+ if (ldb_attr_cmp(data->attribute_maps[i].local_name, "*") == 0) {
+ return &data->attribute_maps[i];
+ }
+ }
+
+ return NULL;
+}
+
+/* Find an attribute mapping by the remote name. */
+const struct ldb_map_attribute *map_attr_find_remote(const struct ldb_map_context *data, const char *name)
+{
+ const struct ldb_map_attribute *map;
+ const struct ldb_map_attribute *wildcard = NULL;
+ int i, j;
+
+ for (i = 0; data->attribute_maps[i].local_name; i++) {
+ map = &data->attribute_maps[i];
+ if (ldb_attr_cmp(map->local_name, "*") == 0) {
+ wildcard = &data->attribute_maps[i];
+ }
+
+ switch (map->type) {
+ case MAP_IGNORE:
+ break;
+
+ case MAP_KEEP:
+ if (ldb_attr_cmp(map->local_name, name) == 0) {
+ return map;
+ }
+ break;
+
+ case MAP_RENAME:
+ case MAP_CONVERT:
+ if (ldb_attr_cmp(map->u.rename.remote_name, name) == 0) {
+ return map;
+ }
+ break;
+
+ case MAP_GENERATE:
+ for (j = 0; map->u.generate.remote_names && map->u.generate.remote_names[j]; j++) {
+ if (ldb_attr_cmp(map->u.generate.remote_names[j], name) == 0) {
+ return map;
+ }
+ }
+ break;
+ }
+ }
+
+ /* We didn't find it, so return the wildcard record if one was configured */
+ return wildcard;
+}
+
+
+/* Mapping attributes
+ * ================== */
+
+/* Check whether an attribute will be mapped into the remote partition. */
+BOOL map_attr_check_remote(const struct ldb_map_context *data, const char *attr)
+{
+ const struct ldb_map_attribute *map = map_attr_find_local(data, attr);
+
+ if (map == NULL) {
+ return False;
+ }
+ if (map->type == MAP_IGNORE) {
+ return False;
+ }
+
+ return True;
+}
+
+/* Map an attribute name into the remote partition. */
+const char *map_attr_map_local(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr)
+{
+ if (map == NULL) {
+ return talloc_strdup(mem_ctx, attr);
+ }
+
+ switch (map->type) {
+ case MAP_KEEP:
+ return talloc_strdup(mem_ctx, attr);
+
+ case MAP_RENAME:
+ case MAP_CONVERT:
+ return talloc_strdup(mem_ctx, map->u.rename.remote_name);
+
+ default:
+ return NULL;
+ }
+}
+
+/* Map an attribute name back into the local partition. */
+const char *map_attr_map_remote(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr)
+{
+ if (map == NULL) {
+ return talloc_strdup(mem_ctx, attr);
+ }
+
+ if (map->type == MAP_KEEP) {
+ return talloc_strdup(mem_ctx, attr);
+ }
+
+ return talloc_strdup(mem_ctx, map->local_name);
+}
+
+
+/* Merge two lists of attributes into a single one. */
+int map_attrs_merge(struct ldb_module *module, void *mem_ctx,
+ const char ***attrs, const char * const *more_attrs)
+{
+ int i, j, k;
+
+ for (i = 0; *attrs && (*attrs)[i]; i++) /* noop */ ;
+ for (j = 0; more_attrs && more_attrs[j]; j++) /* noop */ ;
+
+ *attrs = talloc_realloc(mem_ctx, *attrs, const char *, i+j+1);
+ if (*attrs == NULL) {
+ map_oom(module);
+ return -1;
+ }
+
+ for (k = 0; k < j; k++) {
+ (*attrs)[i + k] = more_attrs[k];
+ }
+
+ (*attrs)[i+k] = NULL;
+
+ return 0;
+}
+
+/* Mapping ldb values
+ * ================== */
+
+/* Map an ldb value into the remote partition. */
+struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx,
+ const struct ldb_map_attribute *map, const struct ldb_val *val)
+{
+ if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_local)) {
+ return map->u.convert.convert_local(module, mem_ctx, val);
+ }
+
+ return ldb_val_dup(mem_ctx, val);
+}
+
+/* Map an ldb value back into the local partition. */
+struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx,
+ const struct ldb_map_attribute *map, const struct ldb_val *val)
+{
+ if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_remote)) {
+ return map->u.convert.convert_remote(module, mem_ctx, val);
+ }
+
+ return ldb_val_dup(mem_ctx, val);
+}
+
+
+/* Mapping DNs
+ * =========== */
+
+/* Check whether a DN is below the local baseDN. */
+BOOL ldb_dn_check_local(struct ldb_module *module, const struct ldb_dn *dn)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+
+ if (!data->local_base_dn) {
+ return True;
+ }
+
+ return ldb_dn_compare_base(module->ldb, data->local_base_dn, dn) == 0;
+}
+
+/* Map a DN into the remote partition. */
+struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ struct ldb_dn *newdn;
+ const struct ldb_map_attribute *map;
+ enum ldb_map_attr_type map_type;
+ const char *name;
+ struct ldb_val value;
+ int i, ret;
+
+ if (dn == NULL) {
+ return NULL;
+ }
+
+ newdn = ldb_dn_copy(mem_ctx, dn);
+ if (newdn == NULL) {
+ map_oom(module);
+ return NULL;
+ }
+
+ /* For each RDN, map the component name and possibly the value */
+ for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) {
+ map = map_attr_find_local(data, ldb_dn_get_component_name(dn, i));
+
+ /* Unknown attribute - leave this RDN as is and hope the best... */
+ if (map == NULL) {
+ map_type = MAP_KEEP;
+ } else {
+ map_type = map->type;
+ }
+
+ switch (map_type) {
+ case MAP_IGNORE:
+ case MAP_GENERATE:
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "MAP_IGNORE/MAP_GENERATE attribute '%s' "
+ "used in DN!\n", ldb_dn_get_component_name(dn, i));
+ goto failed;
+
+ case MAP_CONVERT:
+ if (map->u.convert.convert_local == NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "'convert_local' not set for attribute '%s' "
+ "used in DN!\n", ldb_dn_get_component_name(dn, i));
+ goto failed;
+ }
+ /* fall through */
+ case MAP_KEEP:
+ case MAP_RENAME:
+ name = map_attr_map_local(newdn, map, ldb_dn_get_component_name(dn, i));
+ if (name == NULL) goto failed;
+
+ value = ldb_val_map_local(module, newdn, map, ldb_dn_get_component_val(dn, i));
+ if (value.data == NULL) goto failed;
+
+ ret = ldb_dn_set_component(newdn, i, name, value);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ break;
+ }
+ }
+
+ return newdn;
+
+failed:
+ talloc_free(newdn);
+ return NULL;
+}
+
+/* Map a DN into the local partition. */
+struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ struct ldb_dn *newdn;
+ const struct ldb_map_attribute *map;
+ enum ldb_map_attr_type map_type;
+ const char *name;
+ struct ldb_val value;
+ int i, ret;
+
+ if (dn == NULL) {
+ return NULL;
+ }
+
+ newdn = ldb_dn_copy(mem_ctx, dn);
+ if (newdn == NULL) {
+ map_oom(module);
+ return NULL;
+ }
+
+ /* For each RDN, map the component name and possibly the value */
+ for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) {
+ map = map_attr_find_remote(data, ldb_dn_get_component_name(dn, i));
+
+ /* Unknown attribute - leave this RDN as is and hope the best... */
+ if (map == NULL) {
+ map_type = MAP_KEEP;
+ } else {
+ map_type = map->type;
+ }
+
+ switch (map_type) {
+ case MAP_IGNORE:
+ case MAP_GENERATE:
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "MAP_IGNORE/MAP_GENERATE attribute '%s' "
+ "used in DN!\n", ldb_dn_get_component_name(dn, i));
+ goto failed;
+
+ case MAP_CONVERT:
+ if (map->u.convert.convert_remote == NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "'convert_remote' not set for attribute '%s' "
+ "used in DN!\n", ldb_dn_get_component_name(dn, i));
+ goto failed;
+ }
+ /* fall through */
+ case MAP_KEEP:
+ case MAP_RENAME:
+ name = map_attr_map_remote(newdn, map, ldb_dn_get_component_name(dn, i));
+ if (name == NULL) goto failed;
+
+ value = ldb_val_map_remote(module, newdn, map, ldb_dn_get_component_val(dn, i));
+ if (value.data == NULL) goto failed;
+
+ ret = ldb_dn_set_component(newdn, i, name, value);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ break;
+ }
+ }
+
+ return newdn;
+
+failed:
+ talloc_free(newdn);
+ return NULL;
+}
+
+/* Map a DN and its base into the local partition. */
+/* TODO: This should not be required with GUIDs. */
+struct ldb_dn *ldb_dn_map_rebase_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ struct ldb_dn *dn1, *dn2;
+
+ dn1 = ldb_dn_rebase_local(mem_ctx, data, dn);
+ dn2 = ldb_dn_map_remote(module, mem_ctx, dn1);
+
+ talloc_free(dn1);
+ return dn2;
+}
+
+
+/* Converting DNs and objectClasses (as ldb values)
+ * ================================================ */
+
+/* Map a DN contained in an ldb value into the remote partition. */
+static struct ldb_val ldb_dn_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
+{
+ struct ldb_dn *dn, *newdn;
+ struct ldb_val newval;
+
+ dn = ldb_dn_explode(mem_ctx, (char *)val->data);
+ newdn = ldb_dn_map_local(module, mem_ctx, dn);
+ talloc_free(dn);
+
+ newval.length = 0;
+ newval.data = (uint8_t *)ldb_dn_linearize(mem_ctx, newdn);
+ if (newval.data) {
+ newval.length = strlen((char *)newval.data);
+ }
+ talloc_free(newdn);
+
+ return newval;
+}
+
+/* Map a DN contained in an ldb value into the local partition. */
+static struct ldb_val ldb_dn_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
+{
+ struct ldb_dn *dn, *newdn;
+ struct ldb_val newval;
+
+ dn = ldb_dn_explode(mem_ctx, (char *)val->data);
+ newdn = ldb_dn_map_remote(module, mem_ctx, dn);
+ talloc_free(dn);
+
+ newval.length = 0;
+ newval.data = (uint8_t *)ldb_dn_linearize(mem_ctx, newdn);
+ if (newval.data) {
+ newval.length = strlen((char *)newval.data);
+ }
+ talloc_free(newdn);
+
+ return newval;
+}
+
+/* Map an objectClass into the remote partition. */
+static struct ldb_val map_objectclass_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const char *name = (char *)val->data;
+ const struct ldb_map_objectclass *map = map_objectclass_find_local(data, name);
+ struct ldb_val newval;
+
+ if (map) {
+ newval.data = (uint8_t*)talloc_strdup(mem_ctx, map->remote_name);
+ newval.length = strlen((char *)newval.data);
+ return newval;
+ }
+
+ return ldb_val_dup(mem_ctx, val);
+}
+
+/* Generate a remote message with a mapped objectClass. */
+static void map_objectclass_generate_remote(struct ldb_module *module, const char *local_attr, const struct ldb_message *old, struct ldb_message *remote, struct ldb_message *local)
+{
+ struct ldb_message_element *el, *oc;
+ struct ldb_val val;
+ BOOL found_extensibleObject = False;
+ int i;
+
+ /* Find old local objectClass */
+ oc = ldb_msg_find_element(old, "objectClass");
+ if (oc == NULL) {
+ return;
+ }
+
+ /* Prepare new element */
+ el = talloc_zero(remote, struct ldb_message_element);
+ if (el == NULL) {
+ ldb_oom(module->ldb);
+ return; /* TODO: fail? */
+ }
+
+ /* Copy local objectClass element, reverse space for an extra value */
+ el->num_values = oc->num_values + 1;
+ el->values = talloc_array(el, struct ldb_val, el->num_values);
+ if (el->values == NULL) {
+ talloc_free(el);
+ ldb_oom(module->ldb);
+ return; /* TODO: fail? */
+ }
+
+ /* Copy local element name "objectClass" */
+ el->name = talloc_strdup(el, local_attr);
+
+ /* Convert all local objectClasses */
+ for (i = 0; i < el->num_values - 1; i++) {
+ el->values[i] = map_objectclass_convert_local(module, el->values, &oc->values[i]);
+ if (ldb_attr_cmp((char *)el->values[i].data, "extensibleObject") == 0) {
+ found_extensibleObject = True;
+ }
+ }
+
+ if (!found_extensibleObject) {
+ val.data = (uint8_t *)talloc_strdup(el->values, "extensibleObject");
+ val.length = strlen((char *)val.data);
+
+ /* Append additional objectClass "extensibleObject" */
+ el->values[i] = val;
+ } else {
+ el->num_values--;
+ }
+
+ /* Add new objectClass to remote message */
+ ldb_msg_add(remote, el, 0);
+}
+
+/* Map an objectClass into the local partition. */
+static struct ldb_val map_objectclass_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const char *name = (char *)val->data;
+ const struct ldb_map_objectclass *map = map_objectclass_find_remote(data, name);
+ struct ldb_val newval;
+
+ if (map) {
+ newval.data = (uint8_t*)talloc_strdup(mem_ctx, map->local_name);
+ newval.length = strlen((char *)newval.data);
+ return newval;
+ }
+
+ return ldb_val_dup(mem_ctx, val);
+}
+
+/* Generate a local message with a mapped objectClass. */
+static struct ldb_message_element *map_objectclass_generate_local(struct ldb_module *module, void *mem_ctx, const char *local_attr, const struct ldb_message *remote)
+{
+ struct ldb_message_element *el, *oc;
+ struct ldb_val val;
+ int i;
+
+ /* Find old remote objectClass */
+ oc = ldb_msg_find_element(remote, "objectClass");
+ if (oc == NULL) {
+ return NULL;
+ }
+
+ /* Prepare new element */
+ el = talloc_zero(mem_ctx, struct ldb_message_element);
+ if (el == NULL) {
+ ldb_oom(module->ldb);
+ return NULL;
+ }
+
+ /* Copy remote objectClass element */
+ el->num_values = oc->num_values;
+ el->values = talloc_array(el, struct ldb_val, el->num_values);
+ if (el->values == NULL) {
+ talloc_free(el);
+ ldb_oom(module->ldb);
+ return NULL;
+ }
+
+ /* Copy remote element name "objectClass" */
+ el->name = talloc_strdup(el, local_attr);
+
+ /* Convert all remote objectClasses */
+ for (i = 0; i < el->num_values; i++) {
+ el->values[i] = map_objectclass_convert_remote(module, el->values, &oc->values[i]);
+ }
+
+ val.data = (uint8_t *)talloc_strdup(el->values, "extensibleObject");
+ val.length = strlen((char *)val.data);
+
+ /* Remove last value if it was "extensibleObject" */
+ if (ldb_val_equal_exact(&val, &el->values[i-1])) {
+ el->num_values--;
+ el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values);
+ if (el->values == NULL) {
+ talloc_free(el);
+ ldb_oom(module->ldb);
+ return NULL;
+ }
+ }
+
+ return el;
+}
+
+/* Mappings for searches on objectClass= assuming a one-to-one
+ * mapping. Needed because this is a generate operator for the
+ * add/modify code */
+static int map_objectclass_convert_operator(struct ldb_module *module, void *mem_ctx,
+ struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
+{
+
+ static const struct ldb_map_attribute objectclass_map = {
+ .local_name = "objectClass",
+ .type = MAP_CONVERT,
+ .u = {
+ .convert = {
+ .remote_name = "objectClass",
+ .convert_local = map_objectclass_convert_local,
+ .convert_remote = map_objectclass_convert_remote,
+ },
+ },
+ };
+
+ return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, &objectclass_map);
+}
+
+/* Auxiliary request construction
+ * ============================== */
+
+/* Store the DN of a single search result in context. */
+static int map_search_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+{
+ struct map_context *ac;
+
+ if (context == NULL || ares == NULL) {
+ ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback"));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac = talloc_get_type(context, struct map_context);
+
+ /* We are interested only in the single reply */
+ if (ares->type != LDB_REPLY_ENTRY) {
+ talloc_free(ares);
+ return LDB_SUCCESS;
+ }
+
+ /* We have already found a remote DN */
+ if (ac->local_dn) {
+ ldb_set_errstring(ldb, talloc_asprintf(ldb, "Too many results to base search"));
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Store local DN */
+ ac->local_dn = ares->message->dn;
+
+ return LDB_SUCCESS;
+}
+
+/* Build a request to search a record by its DN. */
+struct ldb_request *map_search_base_req(struct map_context *ac, const struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_search_callback callback)
+{
+ struct ldb_request *req;
+
+ req = talloc_zero(ac, struct ldb_request);
+ if (req == NULL) {
+ map_oom(ac->module);
+ return NULL;
+ }
+
+ req->operation = LDB_SEARCH;
+ req->op.search.base = dn;
+ req->op.search.scope = LDB_SCOPE_BASE;
+ req->op.search.attrs = attrs;
+
+ if (tree) {
+ req->op.search.tree = tree;
+ } else {
+ req->op.search.tree = ldb_parse_tree(req, NULL);
+ if (req->op.search.tree == NULL) {
+ talloc_free(req);
+ return NULL;
+ }
+ }
+
+ req->controls = NULL;
+ req->context = context;
+ req->callback = callback;
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, req);
+
+ return req;
+}
+
+/* Build a request to search the local record by its DN. */
+struct ldb_request *map_search_self_req(struct map_context *ac, const struct ldb_dn *dn)
+{
+ /* attrs[] is returned from this function in
+ * ac->search_req->op.search.attrs, so it must be static, as
+ * otherwise the compiler can put it on the stack */
+ static const char * const attrs[] = { IS_MAPPED, NULL };
+ struct ldb_parse_tree *tree;
+
+ /* Limit search to records with 'IS_MAPPED' present */
+ /* TODO: `tree = ldb_parse_tree(ac, IS_MAPPED);' won't do. */
+ tree = talloc_zero(ac, struct ldb_parse_tree);
+ if (tree == NULL) {
+ map_oom(ac->module);
+ return NULL;
+ }
+
+ tree->operation = LDB_OP_PRESENT;
+ tree->u.present.attr = talloc_strdup(tree, IS_MAPPED);
+
+ return map_search_base_req(ac, dn, attrs, tree, ac, map_search_self_callback);
+}
+
+/* Build a request to update the 'IS_MAPPED' attribute */
+struct ldb_request *map_build_fixup_req(struct map_context *ac, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
+{
+ struct ldb_request *req;
+ struct ldb_message *msg;
+ const char *dn;
+
+ /* Prepare request */
+ req = talloc_zero(ac, struct ldb_request);
+ if (req == NULL) {
+ map_oom(ac->module);
+ return NULL;
+ }
+
+ /* Prepare message */
+ msg = ldb_msg_new(req);
+ if (msg == NULL) {
+ map_oom(ac->module);
+ goto failed;
+ }
+
+ /* Update local 'IS_MAPPED' to the new remote DN */
+ msg->dn = discard_const_p(struct ldb_dn, olddn);
+ dn = ldb_dn_linearize(msg, newdn);
+ if (dn == NULL) {
+ goto failed;
+ }
+ if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
+ goto failed;
+ }
+ if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) {
+ goto failed;
+ }
+
+ req->operation = LDB_MODIFY;
+ req->op.mod.message = msg;
+ req->controls = NULL;
+ req->handle = NULL;
+ req->context = NULL;
+ req->callback = NULL;
+
+ return req;
+
+failed:
+ talloc_free(req);
+ return NULL;
+}
+
+
+/* Asynchronous call structure
+ * =========================== */
+
+/* Figure out which request is currently pending. */
+static struct ldb_request *map_get_req(struct map_context *ac)
+{
+ switch (ac->step) {
+ case MAP_SEARCH_SELF_MODIFY:
+ case MAP_SEARCH_SELF_DELETE:
+ case MAP_SEARCH_SELF_RENAME:
+ return ac->search_req;
+
+ case MAP_ADD_REMOTE:
+ case MAP_MODIFY_REMOTE:
+ case MAP_DELETE_REMOTE:
+ case MAP_RENAME_REMOTE:
+ return ac->remote_req;
+
+ case MAP_RENAME_FIXUP:
+ return ac->down_req;
+
+ case MAP_ADD_LOCAL:
+ case MAP_MODIFY_LOCAL:
+ case MAP_DELETE_LOCAL:
+ case MAP_RENAME_LOCAL:
+ return ac->local_req;
+
+ case MAP_SEARCH_REMOTE:
+ /* Can't happen */
+ break;
+ }
+
+ return NULL; /* unreachable; silences a warning */
+}
+
+typedef int (*map_next_function)(struct ldb_handle *handle);
+
+/* Figure out the next request to run. */
+static map_next_function map_get_next(struct map_context *ac)
+{
+ switch (ac->step) {
+ case MAP_SEARCH_REMOTE:
+ return NULL;
+
+ case MAP_ADD_LOCAL:
+ return map_add_do_remote;
+ case MAP_ADD_REMOTE:
+ return NULL;
+
+ case MAP_SEARCH_SELF_MODIFY:
+ return map_modify_do_local;
+ case MAP_MODIFY_LOCAL:
+ return map_modify_do_remote;
+ case MAP_MODIFY_REMOTE:
+ return NULL;
+
+ case MAP_SEARCH_SELF_DELETE:
+ return map_delete_do_local;
+ case MAP_DELETE_LOCAL:
+ return map_delete_do_remote;
+ case MAP_DELETE_REMOTE:
+ return NULL;
+
+ case MAP_SEARCH_SELF_RENAME:
+ return map_rename_do_local;
+ case MAP_RENAME_LOCAL:
+ return map_rename_do_fixup;
+ case MAP_RENAME_FIXUP:
+ return map_rename_do_remote;
+ case MAP_RENAME_REMOTE:
+ return NULL;
+ }
+
+ return NULL; /* unreachable; silences a warning */
+}
+
+/* Wait for the current pending request to finish and continue with the next. */
+static int map_wait_next(struct ldb_handle *handle)
+{
+ struct map_context *ac;
+ struct ldb_request *req;
+ map_next_function next;
+ int ret;
+
+ if (handle == NULL || handle->private_data == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (handle->state == LDB_ASYNC_DONE) {
+ return handle->status;
+ }
+
+ handle->state = LDB_ASYNC_PENDING;
+ handle->status = LDB_SUCCESS;
+
+ ac = talloc_get_type(handle->private_data, struct map_context);
+
+ if (ac->step == MAP_SEARCH_REMOTE) {
+ int i;
+ for (i = 0; i < ac->num_searches; i++) {
+ req = ac->search_reqs[i];
+ ret = ldb_wait(req->handle, LDB_WAIT_NONE);
+
+ if (ret != LDB_SUCCESS) {
+ handle->status = ret;
+ goto done;
+ }
+ if (req->handle->status != LDB_SUCCESS) {
+ handle->status = req->handle->status;
+ goto done;
+ }
+ if (req->handle->state != LDB_ASYNC_DONE) {
+ return LDB_SUCCESS;
+ }
+ }
+ } else {
+
+ req = map_get_req(ac);
+
+ ret = ldb_wait(req->handle, LDB_WAIT_NONE);
+
+ if (ret != LDB_SUCCESS) {
+ handle->status = ret;
+ goto done;
+ }
+ if (req->handle->status != LDB_SUCCESS) {
+ handle->status = req->handle->status;
+ goto done;
+ }
+ if (req->handle->state != LDB_ASYNC_DONE) {
+ return LDB_SUCCESS;
+ }
+
+ next = map_get_next(ac);
+ if (next) {
+ return next(handle);
+ }
+ }
+
+ ret = LDB_SUCCESS;
+
+done:
+ handle->state = LDB_ASYNC_DONE;
+ return ret;
+}
+
+/* Wait for all current pending requests to finish. */
+static int map_wait_all(struct ldb_handle *handle)
+{
+ int ret;
+
+ while (handle->state != LDB_ASYNC_DONE) {
+ ret = map_wait_next(handle);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ return handle->status;
+}
+
+/* Wait for pending requests to finish. */
+static int map_wait(struct ldb_handle *handle, enum ldb_wait_type type)
+{
+ if (type == LDB_WAIT_ALL) {
+ return map_wait_all(handle);
+ } else {
+ return map_wait_next(handle);
+ }
+}
+
+
+/* Module initialization
+ * ===================== */
+
+/* Provided module operations */
+static const struct ldb_module_ops map_ops = {
+ .name = "ldb_map",
+ .add = map_add,
+ .modify = map_modify,
+ .del = map_delete,
+ .rename = map_rename,
+ .search = map_search,
+ .wait = map_wait,
+};
+
+/* Builtin mappings for DNs and objectClasses */
+static const struct ldb_map_attribute builtin_attribute_maps[] = {
+ {
+ .local_name = "dn",
+ .type = MAP_CONVERT,
+ .u = {
+ .convert = {
+ .remote_name = "dn",
+ .convert_local = ldb_dn_convert_local,
+ .convert_remote = ldb_dn_convert_remote,
+ },
+ },
+ },
+ {
+ .local_name = "objectClass",
+ .type = MAP_GENERATE,
+ .convert_operator = map_objectclass_convert_operator,
+ .u = {
+ .generate = {
+ .remote_names = { "objectClass", NULL },
+ .generate_local = map_objectclass_generate_local,
+ .generate_remote = map_objectclass_generate_remote,
+ },
+ },
+ },
+ {
+ .local_name = NULL,
+ }
+};
+
+/* Find the special 'MAP_DN_NAME' record and store local and remote
+ * base DNs in private data. */
+static int map_init_dns(struct ldb_module *module, struct ldb_map_context *data, const char *name)
+{
+ static const char * const attrs[] = { MAP_DN_FROM, MAP_DN_TO, NULL };
+ struct ldb_dn *dn;
+ struct ldb_message *msg;
+ struct ldb_result *res;
+ int ret;
+
+ if (!name) {
+ data->local_base_dn = NULL;
+ data->remote_base_dn = NULL;
+ return LDB_SUCCESS;
+ }
+
+ dn = ldb_dn_string_compose(data, NULL, "%s=%s", MAP_DN_NAME, name);
+ if (dn == NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "Failed to construct '%s' DN!\n", MAP_DN_NAME);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_search(module->ldb, dn, LDB_SCOPE_BASE, NULL, attrs, &res);
+ talloc_free(dn);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if (res->count == 0) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "No results for '%s=%s'!\n", MAP_DN_NAME, name);
+ talloc_free(res);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ if (res->count > 1) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "Too many results for '%s=%s'!\n", MAP_DN_NAME, name);
+ talloc_free(res);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ msg = res->msgs[0];
+ data->local_base_dn = ldb_msg_find_attr_as_dn(data, msg, MAP_DN_FROM);
+ data->remote_base_dn = ldb_msg_find_attr_as_dn(data, msg, MAP_DN_TO);
+ talloc_free(res);
+
+ return LDB_SUCCESS;
+}
+
+/* Store attribute maps and objectClass maps in private data. */
+static int map_init_maps(struct ldb_module *module, struct ldb_map_context *data,
+ const struct ldb_map_attribute *attrs,
+ const struct ldb_map_objectclass *ocls,
+ const char * const *wildcard_attributes)
+{
+ int i, j, last;
+ last = 0;
+
+ /* Count specified attribute maps */
+ for (i = 0; attrs[i].local_name; i++) /* noop */ ;
+ /* Count built-in attribute maps */
+ for (j = 0; builtin_attribute_maps[j].local_name; j++) /* noop */ ;
+
+ /* Store list of attribute maps */
+ data->attribute_maps = talloc_array(data, struct ldb_map_attribute, i+j+1);
+ if (data->attribute_maps == NULL) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Specified ones go first */
+ for (i = 0; attrs[i].local_name; i++) {
+ data->attribute_maps[last] = attrs[i];
+ last++;
+ }
+
+ /* Built-in ones go last */
+ for (i = 0; builtin_attribute_maps[i].local_name; i++) {
+ data->attribute_maps[last] = builtin_attribute_maps[i];
+ last++;
+ }
+
+ /* Ensure 'local_name == NULL' for the last entry */
+ memset(&data->attribute_maps[last], 0, sizeof(struct ldb_map_attribute));
+
+ /* Store list of objectClass maps */
+ data->objectclass_maps = ocls;
+
+ data->wildcard_attributes = wildcard_attributes;
+
+ return LDB_SUCCESS;
+}
+
+/* Copy the list of provided module operations. */
+_PUBLIC_ struct ldb_module_ops ldb_map_get_ops(void)
+{
+ return map_ops;
+}
+
+/* Initialize global private data. */
+_PUBLIC_ int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs,
+ const struct ldb_map_objectclass *ocls,
+ const char * const *wildcard_attributes,
+ const char *name)
+{
+ struct map_private *data;
+ int ret;
+
+ /* Prepare private data */
+ data = talloc_zero(module, struct map_private);
+ if (data == NULL) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ module->private_data = data;
+
+ data->context = talloc_zero(data, struct ldb_map_context);
+ if (!data->context) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Store local and remote baseDNs */
+ ret = map_init_dns(module, data->context, name);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(data);
+ return ret;
+ }
+
+ /* Store list of attribute and objectClass maps */
+ ret = map_init_maps(module, data->context, attrs, ocls, wildcard_attributes);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(data);
+ return ret;
+ }
+
+ return LDB_SUCCESS;
+}
+
+/* Usage note for initialization of this module:
+ *
+ * ldb_map is meant to be used from a different module that sets up
+ * the mappings and gets registered in ldb.
+ *
+ * 'ldb_map_init' initializes the private data of this module and
+ * stores the attribute and objectClass maps in there. It also looks
+ * up the '@MAP' special DN so requests can be redirected to the
+ * remote partition.
+ *
+ * This function should be called from the 'init_context' op of the
+ * module using ldb_map.
+ *
+ * 'ldb_map_get_ops' returns a copy of ldb_maps module operations.
+ *
+ * It should be called from the initialize function of the using
+ * module, which should then override the 'init_context' op with a
+ * function making the appropriate calls to 'ldb_map_init'.
+ */
diff --git a/source3/lib/ldb/modules/ldb_map.h b/source3/lib/ldb/modules/ldb_map.h
new file mode 100644
index 0000000000..4457c6fc1d
--- /dev/null
+++ b/source3/lib/ldb/modules/ldb_map.h
@@ -0,0 +1,157 @@
+/*
+ ldb database mapping module
+
+ Copyright (C) Jelmer Vernooij 2005
+ Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
+
+ * NOTICE: this module is NOT released under the GNU LGPL license as
+ * other ldb code. This module is release under the GNU GPL v2 or
+ * later license.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __LDB_MAP_H__
+#define __LDB_MAP_H__
+
+/* ldb_map is a skeleton LDB module that can be used for any other modules
+ * that need to map attributes.
+ *
+ * The term 'remote' in this header refers to the connection where the
+ * original schema is used on while 'local' means the local connection
+ * that any upper layers will use.
+ *
+ * All local attributes will have to have a definition. Not all remote
+ * attributes need a definition as LDB is a lot less strict than LDAP
+ * (in other words, sending unknown attributes to an LDAP server hurts us,
+ * while returning too many attributes in ldb_search() doesn't)
+ */
+
+
+/* Name of the internal attribute pointing from the local to the
+ * remote part of a record */
+#define IS_MAPPED "isMapped"
+
+
+struct ldb_map_context;
+
+/* convert a local ldb_val to a remote ldb_val */
+typedef struct ldb_val (*ldb_map_convert_func) (struct ldb_module *module, void *mem_ctx, const struct ldb_val *val);
+
+#define LDB_MAP_MAX_REMOTE_NAMES 10
+
+/* map from local to remote attribute */
+struct ldb_map_attribute {
+ const char *local_name; /* local name */
+
+ enum ldb_map_attr_type {
+ MAP_IGNORE, /* Ignore this local attribute. Doesn't exist remotely. */
+ MAP_KEEP, /* Keep as is. Same name locally and remotely. */
+ MAP_RENAME, /* Simply rename the attribute. Name changes, data is the same */
+ MAP_CONVERT, /* Rename + convert data */
+ MAP_GENERATE /* Use generate function for generating new name/data.
+ Used for generating attributes based on
+ multiple remote attributes. */
+ } type;
+
+ /* if set, will be called for search expressions that contain this attribute */
+ int (*convert_operator)(struct ldb_module *, TALLOC_CTX *ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *);
+
+ union {
+ struct {
+ const char *remote_name;
+ } rename;
+
+ struct {
+ const char *remote_name;
+
+ /* Convert local to remote data */
+ ldb_map_convert_func convert_local;
+
+ /* Convert remote to local data */
+ /* an entry can have convert_remote set to NULL, as long as there as an entry with the same local_name
+ * that is non-NULL before it. */
+ ldb_map_convert_func convert_remote;
+ } convert;
+
+ struct {
+ /* Generate the local attribute from remote message */
+ struct ldb_message_element *(*generate_local)(struct ldb_module *, TALLOC_CTX *mem_ctx, const char *remote_attr, const struct ldb_message *remote);
+
+ /* Update remote message with information from local message */
+ void (*generate_remote)(struct ldb_module *, const char *local_attr, const struct ldb_message *old, struct ldb_message *remote, struct ldb_message *local);
+
+ /* Name(s) for this attribute on the remote server. This is an array since
+ * one local attribute's data can be split up into several attributes
+ * remotely */
+ const char *remote_names[LDB_MAP_MAX_REMOTE_NAMES];
+
+ /* Names of additional remote attributes
+ * required for the generation. NULL
+ * indicates that `local_attr' suffices. */
+ /*
+#define LDB_MAP_MAX_SELF_ATTRIBUTES 10
+ const char *self_attrs[LDB_MAP_MAX_SELF_ATTRIBUTES];
+ */
+ } generate;
+ } u;
+};
+
+
+#define LDB_MAP_MAX_SUBCLASSES 10
+#define LDB_MAP_MAX_MUSTS 10
+#define LDB_MAP_MAX_MAYS 50
+
+/* map from local to remote objectClass */
+struct ldb_map_objectclass {
+ const char *local_name;
+ const char *remote_name;
+ const char *base_classes[LDB_MAP_MAX_SUBCLASSES];
+ const char *musts[LDB_MAP_MAX_MUSTS];
+ const char *mays[LDB_MAP_MAX_MAYS];
+};
+
+
+/* private context data */
+struct ldb_map_context {
+ struct ldb_map_attribute *attribute_maps;
+ /* NOTE: Always declare base classes first here */
+ const struct ldb_map_objectclass *objectclass_maps;
+
+ /* Remote (often operational) attributes that should be added
+ * to any wildcard search */
+ const char * const *wildcard_attributes;
+
+ /* struct ldb_context *mapped_ldb; */
+ const struct ldb_dn *local_base_dn;
+ const struct ldb_dn *remote_base_dn;
+};
+
+/* Global private data */
+struct map_private {
+ void *caller_private;
+ struct ldb_map_context *context;
+};
+
+/* Initialize global private data. */
+int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs,
+ const struct ldb_map_objectclass *ocls,
+ const char * const *wildcard_attributes,
+ const char *name);
+
+/* get copy of map_ops */
+struct ldb_module_ops
+ldb_map_get_ops(void);
+
+#endif /* __LDB_MAP_H__ */
diff --git a/source3/lib/ldb/modules/ldb_map_inbound.c b/source3/lib/ldb/modules/ldb_map_inbound.c
new file mode 100644
index 0000000000..0508e724ab
--- /dev/null
+++ b/source3/lib/ldb/modules/ldb_map_inbound.c
@@ -0,0 +1,723 @@
+/*
+ ldb database mapping module
+
+ Copyright (C) Jelmer Vernooij 2005
+ Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
+
+ * NOTICE: this module is NOT released under the GNU LGPL license as
+ * other ldb code. This module is release under the GNU GPL v2 or
+ * later license.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#include "ldb/modules/ldb_map.h"
+#include "ldb/modules/ldb_map_private.h"
+
+
+/* Mapping message elements
+ * ======================== */
+
+/* Map a message element into the remote partition. */
+static struct ldb_message_element *ldb_msg_el_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_message_element *old)
+{
+ struct ldb_message_element *el;
+ int i;
+
+ el = talloc_zero(mem_ctx, struct ldb_message_element);
+ if (el == NULL) {
+ map_oom(module);
+ return NULL;
+ }
+
+ el->num_values = old->num_values;
+ el->values = talloc_array(el, struct ldb_val, el->num_values);
+ if (el->values == NULL) {
+ talloc_free(el);
+ map_oom(module);
+ return NULL;
+ }
+
+ el->name = map_attr_map_local(el, map, old->name);
+
+ for (i = 0; i < el->num_values; i++) {
+ el->values[i] = ldb_val_map_local(module, el->values, map, &old->values[i]);
+ }
+
+ return el;
+}
+
+/* Add a message element either to a local or to a remote message,
+ * depending on whether it goes into the local or remote partition. */
+static int ldb_msg_el_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg, const char *attr_name, /* const char * const names[], */ const struct ldb_message_element *old)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const struct ldb_map_attribute *map = map_attr_find_local(data, attr_name);
+ struct ldb_message_element *el=NULL;
+
+ /* Unknown attribute: ignore */
+ if (map == NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
+ "Not mapping attribute '%s': no mapping found\n",
+ old->name);
+ goto local;
+ }
+
+ switch (map->type) {
+ case MAP_IGNORE:
+ goto local;
+
+ case MAP_CONVERT:
+ if (map->u.convert.convert_local == NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
+ "Not mapping attribute '%s': "
+ "'convert_local' not set\n",
+ map->local_name);
+ goto local;
+ }
+ /* fall through */
+ case MAP_KEEP:
+ case MAP_RENAME:
+ el = ldb_msg_el_map_local(module, remote, map, old);
+ break;
+
+ case MAP_GENERATE:
+ if (map->u.generate.generate_remote == NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
+ "Not mapping attribute '%s': "
+ "'generate_remote' not set\n",
+ map->local_name);
+ goto local;
+ }
+
+ /* TODO: if this attr requires context:
+ * make sure all context attrs are mappable (in 'names')
+ * make sure all context attrs have already been mapped?
+ * maybe postpone generation until they have been mapped?
+ */
+
+ map->u.generate.generate_remote(module, map->local_name, msg, remote, local);
+ return 0;
+ }
+
+ if (el == NULL) {
+ return -1;
+ }
+
+ return ldb_msg_add(remote, el, old->flags);
+
+local:
+ el = talloc(local, struct ldb_message_element);
+ if (el == NULL) {
+ map_oom(module);
+ return -1;
+ }
+
+ *el = *old; /* copy the old element */
+
+ return ldb_msg_add(local, el, old->flags);
+}
+
+/* Mapping messages
+ * ================ */
+
+/* Check whether a message will be (partially) mapped into the remote partition. */
+static BOOL ldb_msg_check_remote(struct ldb_module *module, const struct ldb_message *msg)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ BOOL ret;
+ int i;
+
+ for (i = 0; i < msg->num_elements; i++) {
+ ret = map_attr_check_remote(data, msg->elements[i].name);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ return False;
+}
+
+/* Split message elements that stay in the local partition from those
+ * that are mapped into the remote partition. */
+static int ldb_msg_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg)
+{
+ /* const char * const names[]; */
+ int i, ret;
+
+ for (i = 0; i < msg->num_elements; i++) {
+ /* Skip 'IS_MAPPED' */
+ if (ldb_attr_cmp(msg->elements[i].name, IS_MAPPED) == 0) {
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
+ "Skipping attribute '%s'\n",
+ msg->elements[i].name);
+ continue;
+ }
+
+ ret = ldb_msg_el_partition(module, local, remote, msg, msg->elements[i].name, &msg->elements[i]);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+
+/* Inbound requests: add, modify, rename, delete
+ * ============================================= */
+
+/* Add the remote record. */
+int map_add_do_remote(struct ldb_handle *handle)
+{
+ struct map_context *ac;
+
+ ac = talloc_get_type(handle->private_data, struct map_context);
+
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
+
+ ac->step = MAP_ADD_REMOTE;
+
+ handle->state = LDB_ASYNC_INIT;
+ handle->status = LDB_SUCCESS;
+
+ return ldb_next_remote_request(ac->module, ac->remote_req);
+}
+
+/* Add the local record. */
+int map_add_do_local(struct ldb_handle *handle)
+{
+ struct map_context *ac;
+
+ ac = talloc_get_type(handle->private_data, struct map_context);
+
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
+
+ ac->step = MAP_ADD_LOCAL;
+
+ handle->state = LDB_ASYNC_INIT;
+ handle->status = LDB_SUCCESS;
+
+ return ldb_next_request(ac->module, ac->local_req);
+}
+
+/* Add a record. */
+int map_add(struct ldb_module *module, struct ldb_request *req)
+{
+ const struct ldb_message *msg = req->op.add.message;
+ struct ldb_handle *h;
+ struct map_context *ac;
+ struct ldb_message *local, *remote;
+ const char *dn;
+
+ /* Do not manipulate our control entries */
+ if (ldb_dn_is_special(msg->dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* No mapping requested (perhaps no DN mapping specified), skip to next module */
+ if (!ldb_dn_check_local(module, msg->dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* No mapping needed, fail */
+ if (!ldb_msg_check_remote(module, msg)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Prepare context and handle */
+ h = map_init_handle(req, module);
+ if (h == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac = talloc_get_type(h->private_data, struct map_context);
+
+ /* Prepare the local operation */
+ ac->local_req = talloc(ac, struct ldb_request);
+ if (ac->local_req == NULL) {
+ goto oom;
+ }
+
+ *(ac->local_req) = *req; /* copy the request */
+
+ ac->local_req->context = NULL;
+ ac->local_req->callback = NULL;
+
+ /* Prepare the remote operation */
+ ac->remote_req = talloc(ac, struct ldb_request);
+ if (ac->remote_req == NULL) {
+ goto oom;
+ }
+
+ *(ac->remote_req) = *req; /* copy the request */
+
+ ac->remote_req->context = NULL;
+ ac->remote_req->callback = NULL;
+
+ /* Prepare the local message */
+ local = ldb_msg_new(ac->local_req);
+ if (local == NULL) {
+ goto oom;
+ }
+ local->dn = msg->dn;
+
+ /* Prepare the remote message */
+ remote = ldb_msg_new(ac->remote_req);
+ if (remote == NULL) {
+ goto oom;
+ }
+ remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn);
+
+ /* Split local from remote message */
+ ldb_msg_partition(module, local, remote, msg);
+ ac->local_req->op.add.message = local;
+ ac->remote_req->op.add.message = remote;
+
+ if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) {
+ /* No local data or db, just run the remote request */
+ talloc_free(ac->local_req);
+ req->handle = h; /* return our own handle to deal with this call */
+ return map_add_do_remote(h);
+ }
+
+ /* Store remote DN in 'IS_MAPPED' */
+ /* TODO: use GUIDs here instead */
+ dn = ldb_dn_linearize(local, remote->dn);
+ if (ldb_msg_add_string(local, IS_MAPPED, dn) != 0) {
+ goto failed;
+ }
+
+ req->handle = h; /* return our own handle to deal with this call */
+ return map_add_do_local(h);
+
+oom:
+ map_oom(module);
+failed:
+ talloc_free(h);
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+/* Modify the remote record. */
+int map_modify_do_remote(struct ldb_handle *handle)
+{
+ struct map_context *ac;
+
+ ac = talloc_get_type(handle->private_data, struct map_context);
+
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
+
+ ac->step = MAP_MODIFY_REMOTE;
+
+ handle->state = LDB_ASYNC_INIT;
+ handle->status = LDB_SUCCESS;
+
+ return ldb_next_remote_request(ac->module, ac->remote_req);
+}
+
+/* Modify the local record. */
+int map_modify_do_local(struct ldb_handle *handle)
+{
+ struct map_context *ac;
+ struct ldb_message *msg;
+ char *dn;
+
+ ac = talloc_get_type(handle->private_data, struct map_context);
+
+ if (ac->local_dn == NULL) {
+ /* No local record present, add it instead */
+ msg = discard_const_p(struct ldb_message, ac->local_req->op.mod.message);
+
+ /* Add local 'IS_MAPPED' */
+ /* TODO: use GUIDs here instead */
+ dn = ldb_dn_linearize(msg, ac->remote_req->op.mod.message->dn);
+ if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_ADD, NULL) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Turn request into 'add' */
+ ac->local_req->operation = LDB_ADD;
+ ac->local_req->op.add.message = msg;
+ /* TODO: Could I just leave msg in there? I think so,
+ * but it looks clearer this way. */
+ }
+
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
+
+ ac->step = MAP_MODIFY_LOCAL;
+
+ handle->state = LDB_ASYNC_INIT;
+ handle->status = LDB_SUCCESS;
+
+ return ldb_next_request(ac->module, ac->local_req);
+}
+
+/* Modify a record. */
+int map_modify(struct ldb_module *module, struct ldb_request *req)
+{
+ const struct ldb_message *msg = req->op.mod.message;
+ struct ldb_handle *h;
+ struct map_context *ac;
+ struct ldb_message *local, *remote;
+
+ /* Do not manipulate our control entries */
+ if (ldb_dn_is_special(msg->dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* No mapping requested (perhaps no DN mapping specified), skip to next module */
+ if (!ldb_dn_check_local(module, msg->dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* No mapping needed, skip to next module */
+ /* TODO: What if the remote part exists, the local doesn't,
+ * and this request wants to modify local data and thus
+ * add the local record? */
+ if (!ldb_msg_check_remote(module, msg)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Prepare context and handle */
+ h = map_init_handle(req, module);
+ if (h == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac = talloc_get_type(h->private_data, struct map_context);
+
+ /* Prepare the local operation */
+ ac->local_req = talloc(ac, struct ldb_request);
+ if (ac->local_req == NULL) {
+ goto oom;
+ }
+
+ *(ac->local_req) = *req; /* copy the request */
+
+ ac->local_req->context = NULL;
+ ac->local_req->callback = NULL;
+
+ /* Prepare the remote operation */
+ ac->remote_req = talloc(ac, struct ldb_request);
+ if (ac->remote_req == NULL) {
+ goto oom;
+ }
+
+ *(ac->remote_req) = *req; /* copy the request */
+
+ ac->remote_req->context = NULL;
+ ac->remote_req->callback = NULL;
+
+ /* Prepare the local message */
+ local = ldb_msg_new(ac->local_req);
+ if (local == NULL) {
+ goto oom;
+ }
+ local->dn = msg->dn;
+
+ /* Prepare the remote message */
+ remote = ldb_msg_new(ac->remote_req);
+ if (remote == NULL) {
+ goto oom;
+ }
+ remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn);
+
+ /* Split local from remote message */
+ ldb_msg_partition(module, local, remote, msg);
+ ac->local_req->op.mod.message = local;
+ ac->remote_req->op.mod.message = remote;
+
+ if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) {
+ /* No local data or db, just run the remote request */
+ talloc_free(ac->local_req);
+ req->handle = h; /* return our own handle to deal with this call */
+ return map_modify_do_remote(h);
+ }
+
+ /* prepare the search operation */
+ ac->search_req = map_search_self_req(ac, msg->dn);
+ if (ac->search_req == NULL) {
+ goto failed;
+ }
+
+ ac->step = MAP_SEARCH_SELF_MODIFY;
+
+ req->handle = h; /* return our own handle to deal with this call */
+ return ldb_next_request(module, ac->search_req);
+
+oom:
+ map_oom(module);
+failed:
+ talloc_free(h);
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+/* Delete the remote record. */
+int map_delete_do_remote(struct ldb_handle *handle)
+{
+ struct map_context *ac;
+
+ ac = talloc_get_type(handle->private_data, struct map_context);
+
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
+
+ ac->step = MAP_DELETE_REMOTE;
+
+ handle->state = LDB_ASYNC_INIT;
+ handle->status = LDB_SUCCESS;
+
+ return ldb_next_remote_request(ac->module, ac->remote_req);
+}
+
+/* Delete the local record. */
+int map_delete_do_local(struct ldb_handle *handle)
+{
+ struct map_context *ac;
+
+ ac = talloc_get_type(handle->private_data, struct map_context);
+
+ /* No local record, continue remotely */
+ if (ac->local_dn == NULL) {
+ return map_delete_do_remote(handle);
+ }
+
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
+
+ ac->step = MAP_DELETE_LOCAL;
+
+ handle->state = LDB_ASYNC_INIT;
+ handle->status = LDB_SUCCESS;
+
+ return ldb_next_request(ac->module, ac->local_req);
+}
+
+/* Delete a record. */
+int map_delete(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_handle *h;
+ struct map_context *ac;
+
+ /* Do not manipulate our control entries */
+ if (ldb_dn_is_special(req->op.del.dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* No mapping requested (perhaps no DN mapping specified), skip to next module */
+ if (!ldb_dn_check_local(module, req->op.del.dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* Prepare context and handle */
+ h = map_init_handle(req, module);
+ if (h == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac = talloc_get_type(h->private_data, struct map_context);
+
+ /* Prepare the local operation */
+ ac->local_req = talloc(ac, struct ldb_request);
+ if (ac->local_req == NULL) {
+ goto oom;
+ }
+
+ *(ac->local_req) = *req; /* copy the request */
+ ac->local_req->op.del.dn = req->op.del.dn;
+
+ ac->local_req->context = NULL;
+ ac->local_req->callback = NULL;
+
+ /* Prepare the remote operation */
+ ac->remote_req = talloc(ac, struct ldb_request);
+ if (ac->remote_req == NULL) {
+ goto oom;
+ }
+
+ *(ac->remote_req) = *req; /* copy the request */
+ ac->remote_req->op.del.dn = ldb_dn_map_local(module, ac->remote_req, req->op.del.dn);
+
+ /* No local db, just run the remote request */
+ if (!map_check_local_db(ac->module)) {
+ req->handle = h; /* return our own handle to deal with this call */
+ return map_delete_do_remote(h);
+ }
+
+ ac->remote_req->context = NULL;
+ ac->remote_req->callback = NULL;
+
+ /* Prepare the search operation */
+ ac->search_req = map_search_self_req(ac, req->op.del.dn);
+ if (ac->search_req == NULL) {
+ goto failed;
+ }
+
+ req->handle = h; /* return our own handle to deal with this call */
+
+ ac->step = MAP_SEARCH_SELF_DELETE;
+
+ return ldb_next_request(module, ac->search_req);
+
+oom:
+ map_oom(module);
+failed:
+ talloc_free(h);
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+/* Rename the remote record. */
+int map_rename_do_remote(struct ldb_handle *handle)
+{
+ struct map_context *ac;
+
+ ac = talloc_get_type(handle->private_data, struct map_context);
+
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
+
+ ac->step = MAP_RENAME_REMOTE;
+
+ handle->state = LDB_ASYNC_INIT;
+ handle->status = LDB_SUCCESS;
+
+ return ldb_next_remote_request(ac->module, ac->remote_req);
+}
+
+/* Update the local 'IS_MAPPED' attribute. */
+int map_rename_do_fixup(struct ldb_handle *handle)
+{
+ struct map_context *ac;
+
+ ac = talloc_get_type(handle->private_data, struct map_context);
+
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->down_req);
+
+ ac->step = MAP_RENAME_FIXUP;
+
+ handle->state = LDB_ASYNC_INIT;
+ handle->status = LDB_SUCCESS;
+
+ return ldb_next_request(ac->module, ac->down_req);
+}
+
+/* Rename the local record. */
+int map_rename_do_local(struct ldb_handle *handle)
+{
+ struct map_context *ac;
+
+ ac = talloc_get_type(handle->private_data, struct map_context);
+
+ /* No local record, continue remotely */
+ if (ac->local_dn == NULL) {
+ return map_rename_do_remote(handle);
+ }
+
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
+
+ ac->step = MAP_RENAME_LOCAL;
+
+ handle->state = LDB_ASYNC_INIT;
+ handle->status = LDB_SUCCESS;
+
+ return ldb_next_request(ac->module, ac->local_req);
+}
+
+/* Rename a record. */
+int map_rename(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_handle *h;
+ struct map_context *ac;
+
+ /* Do not manipulate our control entries */
+ if (ldb_dn_is_special(req->op.rename.olddn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* No mapping requested (perhaps no DN mapping specified), skip to next module */
+ if ((!ldb_dn_check_local(module, req->op.rename.olddn)) &&
+ (!ldb_dn_check_local(module, req->op.rename.newdn))) {
+ return ldb_next_request(module, req);
+ }
+
+ /* Rename into/out of the mapped partition requested, bail out */
+ if (!ldb_dn_check_local(module, req->op.rename.olddn) ||
+ !ldb_dn_check_local(module, req->op.rename.newdn)) {
+ return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
+ }
+
+ /* Prepare context and handle */
+ h = map_init_handle(req, module);
+ if (h == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac = talloc_get_type(h->private_data, struct map_context);
+
+ /* Prepare the local operation */
+ ac->local_req = talloc(ac, struct ldb_request);
+ if (ac->local_req == NULL) {
+ goto oom;
+ }
+
+ *(ac->local_req) = *req; /* copy the request */
+ ac->local_req->op.rename.olddn = req->op.rename.olddn;
+ ac->local_req->op.rename.newdn = req->op.rename.newdn;
+
+ ac->local_req->context = NULL;
+ ac->local_req->callback = NULL;
+
+ /* Prepare the remote operation */
+ ac->remote_req = talloc(ac, struct ldb_request);
+ if (ac->remote_req == NULL) {
+ goto oom;
+ }
+
+ *(ac->remote_req) = *req; /* copy the request */
+ ac->remote_req->op.rename.olddn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.olddn);
+ ac->remote_req->op.rename.newdn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.newdn);
+
+ ac->remote_req->context = NULL;
+ ac->remote_req->callback = NULL;
+
+ /* No local db, just run the remote request */
+ if (!map_check_local_db(ac->module)) {
+ req->handle = h; /* return our own handle to deal with this call */
+ return map_rename_do_remote(h);
+ }
+
+ /* Prepare the fixup operation */
+ /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */
+ ac->down_req = map_build_fixup_req(ac, req->op.rename.newdn, ac->remote_req->op.rename.newdn);
+ if (ac->down_req == NULL) {
+ goto failed;
+ }
+
+ /* Prepare the search operation */
+ ac->search_req = map_search_self_req(ac, req->op.rename.olddn);
+ if (ac->search_req == NULL) {
+ goto failed;
+ }
+
+ req->handle = h; /* return our own handle to deal with this call */
+
+ ac->step = MAP_SEARCH_SELF_RENAME;
+
+ return ldb_next_request(module, ac->search_req);
+
+oom:
+ map_oom(module);
+failed:
+ talloc_free(h);
+ return LDB_ERR_OPERATIONS_ERROR;
+}
diff --git a/source3/lib/ldb/modules/ldb_map_outbound.c b/source3/lib/ldb/modules/ldb_map_outbound.c
new file mode 100644
index 0000000000..a02d26dcea
--- /dev/null
+++ b/source3/lib/ldb/modules/ldb_map_outbound.c
@@ -0,0 +1,1285 @@
+/*
+ ldb database mapping module
+
+ Copyright (C) Jelmer Vernooij 2005
+ Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
+
+ * NOTICE: this module is NOT released under the GNU LGPL license as
+ * other ldb code. This module is release under the GNU GPL v2 or
+ * later license.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#include "ldb/modules/ldb_map.h"
+#include "ldb/modules/ldb_map_private.h"
+
+
+/* Mapping attributes
+ * ================== */
+
+/* Select attributes that stay in the local partition. */
+static const char **map_attrs_select_local(struct ldb_module *module, void *mem_ctx, const char * const *attrs)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const char **result;
+ int i, last;
+
+ if (attrs == NULL)
+ return NULL;
+
+ last = 0;
+ result = talloc_array(mem_ctx, const char *, 1);
+ if (result == NULL) {
+ goto failed;
+ }
+ result[0] = NULL;
+
+ for (i = 0; attrs[i]; i++) {
+ /* Wildcards and ignored attributes are kept locally */
+ if ((ldb_attr_cmp(attrs[i], "*") == 0) ||
+ (!map_attr_check_remote(data, attrs[i]))) {
+ result = talloc_realloc(mem_ctx, result, const char *, last+2);
+ if (result == NULL) {
+ goto failed;
+ }
+
+ result[last] = talloc_strdup(result, attrs[i]);
+ result[last+1] = NULL;
+ last++;
+ }
+ }
+
+ return result;
+
+failed:
+ talloc_free(result);
+ map_oom(module);
+ return NULL;
+}
+
+/* Collect attributes that are mapped into the remote partition. */
+static const char **map_attrs_collect_remote(struct ldb_module *module, void *mem_ctx,
+ const char * const *attrs)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const char **result;
+ const struct ldb_map_attribute *map;
+ const char *name=NULL;
+ int i, j, last;
+ int ret;
+
+ last = 0;
+ result = talloc_array(mem_ctx, const char *, 1);
+ if (result == NULL) {
+ goto failed;
+ }
+ result[0] = NULL;
+
+ for (i = 0; attrs[i]; i++) {
+ /* Wildcards are kept remotely, too */
+ if (ldb_attr_cmp(attrs[i], "*") == 0) {
+ const char **new_attrs = NULL;
+ ret = map_attrs_merge(module, mem_ctx, &new_attrs, attrs);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+ ret = map_attrs_merge(module, mem_ctx, &new_attrs, data->wildcard_attributes);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ attrs = new_attrs;
+ break;
+ }
+ }
+
+ for (i = 0; attrs[i]; i++) {
+ /* Wildcards are kept remotely, too */
+ if (ldb_attr_cmp(attrs[i], "*") == 0) {
+ /* Add all 'include in wildcard' attributes */
+ name = attrs[i];
+ goto named;
+ }
+
+ /* Add remote names of mapped attrs */
+ map = map_attr_find_local(data, attrs[i]);
+ if (map == NULL) {
+ continue;
+ }
+
+ switch (map->type) {
+ case MAP_IGNORE:
+ continue;
+
+ case MAP_KEEP:
+ name = attrs[i];
+ goto named;
+
+ case MAP_RENAME:
+ case MAP_CONVERT:
+ name = map->u.rename.remote_name;
+ goto named;
+
+ case MAP_GENERATE:
+ /* Add all remote names of "generate" attrs */
+ for (j = 0; map->u.generate.remote_names[j]; j++) {
+ result = talloc_realloc(mem_ctx, result, const char *, last+2);
+ if (result == NULL) {
+ goto failed;
+ }
+
+ result[last] = talloc_strdup(result, map->u.generate.remote_names[j]);
+ result[last+1] = NULL;
+ last++;
+ }
+ continue;
+ }
+
+ named: /* We found a single remote name, add that */
+ result = talloc_realloc(mem_ctx, result, const char *, last+2);
+ if (result == NULL) {
+ goto failed;
+ }
+
+ result[last] = talloc_strdup(result, name);
+ result[last+1] = NULL;
+ last++;
+ }
+
+ return result;
+
+failed:
+ talloc_free(result);
+ map_oom(module);
+ return NULL;
+}
+
+/* Split attributes that stay in the local partition from those that
+ * are mapped into the remote partition. */
+static int map_attrs_partition(struct ldb_module *module, void *mem_ctx, const char ***local_attrs, const char ***remote_attrs, const char * const *attrs)
+{
+ *local_attrs = map_attrs_select_local(module, mem_ctx, attrs);
+ *remote_attrs = map_attrs_collect_remote(module, mem_ctx, attrs);
+
+ return 0;
+}
+
+/* Mapping message elements
+ * ======================== */
+
+/* Add an element to a message, overwriting any old identically named elements. */
+static int ldb_msg_replace(struct ldb_message *msg, const struct ldb_message_element *el)
+{
+ struct ldb_message_element *old;
+
+ old = ldb_msg_find_element(msg, el->name);
+
+ /* no local result, add as new element */
+ if (old == NULL) {
+ if (ldb_msg_add_empty(msg, el->name, 0, &old) != 0) {
+ return -1;
+ }
+ talloc_free(old->name);
+ }
+
+ /* copy new element */
+ *old = *el;
+
+ /* and make sure we reference the contents */
+ if (!talloc_reference(msg->elements, el->name)) {
+ return -1;
+ }
+ if (!talloc_reference(msg->elements, el->values)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Map a message element back into the local partition. */
+static struct ldb_message_element *ldb_msg_el_map_remote(struct ldb_module *module,
+ void *mem_ctx,
+ const struct ldb_map_attribute *map,
+ const char *attr_name,
+ const struct ldb_message_element *old)
+{
+ struct ldb_message_element *el;
+ int i;
+
+ el = talloc_zero(mem_ctx, struct ldb_message_element);
+ if (el == NULL) {
+ map_oom(module);
+ return NULL;
+ }
+
+ el->num_values = old->num_values;
+ el->values = talloc_array(el, struct ldb_val, el->num_values);
+ if (el->values == NULL) {
+ talloc_free(el);
+ map_oom(module);
+ return NULL;
+ }
+
+ el->name = talloc_strdup(el, attr_name);
+ if (el->name == NULL) {
+ talloc_free(el);
+ map_oom(module);
+ return NULL;
+ }
+
+ for (i = 0; i < el->num_values; i++) {
+ el->values[i] = ldb_val_map_remote(module, el->values, map, &old->values[i]);
+ }
+
+ return el;
+}
+
+/* Merge a remote message element into a local message. */
+static int ldb_msg_el_merge(struct ldb_module *module, struct ldb_message *local,
+ struct ldb_message *remote, const char *attr_name)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const struct ldb_map_attribute *map;
+ struct ldb_message_element *old, *el=NULL;
+ const char *remote_name = NULL;
+
+ /* We handle wildcards in ldb_msg_el_merge_wildcard */
+ if (ldb_attr_cmp(attr_name, "*") == 0) {
+ return 0;
+ }
+
+ map = map_attr_find_local(data, attr_name);
+
+ /* Unknown attribute in remote message:
+ * skip, attribute was probably auto-generated */
+ if (map == NULL) {
+ return 0;
+ }
+
+ switch (map->type) {
+ case MAP_IGNORE:
+ break;
+ case MAP_CONVERT:
+ remote_name = map->u.convert.remote_name;
+ break;
+ case MAP_KEEP:
+ remote_name = attr_name;
+ break;
+ case MAP_RENAME:
+ remote_name = map->u.rename.remote_name;
+ break;
+ case MAP_GENERATE:
+ break;
+ }
+
+ switch (map->type) {
+ case MAP_IGNORE:
+ return 0;
+
+ case MAP_CONVERT:
+ if (map->u.convert.convert_remote == NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "Skipping attribute '%s': "
+ "'convert_remote' not set\n",
+ attr_name);
+ return 0;
+ }
+ /* fall through */
+ case MAP_KEEP:
+ case MAP_RENAME:
+ old = ldb_msg_find_element(remote, remote_name);
+ if (old) {
+ el = ldb_msg_el_map_remote(module, local, map, attr_name, old);
+ } else {
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+ }
+ break;
+
+ case MAP_GENERATE:
+ if (map->u.generate.generate_local == NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "Skipping attribute '%s': "
+ "'generate_local' not set\n",
+ attr_name);
+ return 0;
+ }
+
+ el = map->u.generate.generate_local(module, local, attr_name, remote);
+ if (!el) {
+ /* Generation failure is probably due to lack of source attributes */
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+ }
+ break;
+ }
+
+ if (el == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_msg_replace(local, el);
+}
+
+/* Handle wildcard parts of merging a remote message element into a local message. */
+static int ldb_msg_el_merge_wildcard(struct ldb_module *module, struct ldb_message *local,
+ struct ldb_message *remote)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const struct ldb_map_attribute *map = map_attr_find_local(data, "*");
+ struct ldb_message_element *el=NULL;
+ int i, ret;
+
+ /* Perhaps we have a mapping for "*" */
+ if (map && map->type == MAP_KEEP) {
+ /* We copy everything over, and hope that anything with a
+ more specific rule is overwritten */
+ for (i = 0; i < remote->num_elements; i++) {
+ el = ldb_msg_el_map_remote(module, local, map, remote->elements[i].name,
+ &remote->elements[i]);
+ if (el == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_msg_replace(local, el);
+ if (ret) {
+ return ret;
+ }
+ }
+ }
+
+ /* Now walk the list of possible mappings, and apply each */
+ for (i = 0; data->attribute_maps[i].local_name; i++) {
+ ret = ldb_msg_el_merge(module, local, remote,
+ data->attribute_maps[i].local_name);
+ if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
+ continue;
+ } else if (ret) {
+ return ret;
+ } else {
+ continue;
+ }
+ }
+
+ return 0;
+}
+
+/* Mapping messages
+ * ================ */
+
+/* Merge two local messages into a single one. */
+static int ldb_msg_merge_local(struct ldb_module *module, struct ldb_message *msg1, struct ldb_message *msg2)
+{
+ int i, ret;
+
+ for (i = 0; i < msg2->num_elements; i++) {
+ ret = ldb_msg_replace(msg1, &msg2->elements[i]);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* Merge a local and a remote message into a single local one. */
+static int ldb_msg_merge_remote(struct map_context *ac, struct ldb_message *local,
+ struct ldb_message *remote)
+{
+ int i, ret;
+ const char * const *attrs = ac->all_attrs;
+ if (!attrs) {
+ ret = ldb_msg_el_merge_wildcard(ac->module, local, remote);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ for (i = 0; attrs && attrs[i]; i++) {
+ if (ldb_attr_cmp(attrs[i], "*") == 0) {
+ ret = ldb_msg_el_merge_wildcard(ac->module, local, remote);
+ if (ret) {
+ return ret;
+ }
+ break;
+ }
+ }
+
+ /* Try to map each attribute back;
+ * Add to local message is possible,
+ * Overwrite old local attribute if necessary */
+ for (i = 0; attrs && attrs[i]; i++) {
+ ret = ldb_msg_el_merge(ac->module, local, remote,
+ attrs[i]);
+ if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
+ } else if (ret) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* Mapping search results
+ * ====================== */
+
+/* Map a search result back into the local partition. */
+static int map_reply_remote(struct map_context *ac, struct ldb_reply *ares)
+{
+ struct ldb_message *msg;
+ struct ldb_dn *dn;
+ int ret;
+
+ /* There is no result message, skip */
+ if (ares->type != LDB_REPLY_ENTRY) {
+ return 0;
+ }
+
+ /* Create a new result message */
+ msg = ldb_msg_new(ares);
+ if (msg == NULL) {
+ map_oom(ac->module);
+ return -1;
+ }
+
+ /* Merge remote message into new message */
+ ret = ldb_msg_merge_remote(ac, msg, ares->message);
+ if (ret) {
+ talloc_free(msg);
+ return ret;
+ }
+
+ /* Create corresponding local DN */
+ dn = ldb_dn_map_rebase_remote(ac->module, msg, ares->message->dn);
+ if (dn == NULL) {
+ talloc_free(msg);
+ return -1;
+ }
+ msg->dn = dn;
+
+ /* Store new message with new DN as the result */
+ talloc_free(ares->message);
+ ares->message = msg;
+
+ return 0;
+}
+
+/* Mapping parse trees
+ * =================== */
+
+/* Check whether a parse tree can safely be split in two. */
+static BOOL ldb_parse_tree_check_splittable(const struct ldb_parse_tree *tree)
+{
+ const struct ldb_parse_tree *subtree = tree;
+ BOOL negate = False;
+
+ while (subtree) {
+ switch (subtree->operation) {
+ case LDB_OP_NOT:
+ negate = !negate;
+ subtree = subtree->u.isnot.child;
+ continue;
+
+ case LDB_OP_AND:
+ return !negate; /* if negate: False */
+
+ case LDB_OP_OR:
+ return negate; /* if negate: True */
+
+ default:
+ return True; /* simple parse tree */
+ }
+ }
+
+ return True; /* no parse tree */
+}
+
+/* Collect a list of attributes required to match a given parse tree. */
+static int ldb_parse_tree_collect_attrs(struct ldb_module *module, void *mem_ctx, const char ***attrs, const struct ldb_parse_tree *tree)
+{
+ const char **new_attrs;
+ int i, ret;
+
+ if (tree == NULL) {
+ return 0;
+ }
+
+ switch (tree->operation) {
+ case LDB_OP_OR:
+ case LDB_OP_AND: /* attributes stored in list of subtrees */
+ for (i = 0; i < tree->u.list.num_elements; i++) {
+ ret = ldb_parse_tree_collect_attrs(module, mem_ctx,
+ attrs, tree->u.list.elements[i]);
+ if (ret) {
+ return ret;
+ }
+ }
+ return 0;
+
+ case LDB_OP_NOT: /* attributes stored in single subtree */
+ return ldb_parse_tree_collect_attrs(module, mem_ctx, attrs, tree->u.isnot.child);
+
+ default: /* single attribute in tree */
+ new_attrs = ldb_attr_list_copy_add(mem_ctx, *attrs, tree->u.equality.attr);
+ talloc_free(*attrs);
+ *attrs = new_attrs;
+ return 0;
+ }
+
+ return -1;
+}
+
+static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree);
+
+/* Select a negated subtree that queries attributes in the local partition */
+static int map_subtree_select_local_not(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
+{
+ struct ldb_parse_tree *child;
+ int ret;
+
+ /* Prepare new tree */
+ *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
+ if (*new == NULL) {
+ map_oom(module);
+ return -1;
+ }
+
+ /* Generate new subtree */
+ ret = map_subtree_select_local(module, *new, &child, tree->u.isnot.child);
+ if (ret) {
+ talloc_free(*new);
+ return ret;
+ }
+
+ /* Prune tree without subtree */
+ if (child == NULL) {
+ talloc_free(*new);
+ *new = NULL;
+ return 0;
+ }
+
+ (*new)->u.isnot.child = child;
+
+ return ret;
+}
+
+/* Select a list of subtrees that query attributes in the local partition */
+static int map_subtree_select_local_list(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
+{
+ int i, j, ret=0;
+
+ /* Prepare new tree */
+ *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
+ if (*new == NULL) {
+ map_oom(module);
+ return -1;
+ }
+
+ /* Prepare list of subtrees */
+ (*new)->u.list.num_elements = 0;
+ (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements);
+ if ((*new)->u.list.elements == NULL) {
+ map_oom(module);
+ talloc_free(*new);
+ return -1;
+ }
+
+ /* Generate new list of subtrees */
+ j = 0;
+ for (i = 0; i < tree->u.list.num_elements; i++) {
+ struct ldb_parse_tree *child;
+ ret = map_subtree_select_local(module, *new, &child, tree->u.list.elements[i]);
+ if (ret) {
+ talloc_free(*new);
+ return ret;
+ }
+
+ if (child) {
+ (*new)->u.list.elements[j] = child;
+ j++;
+ }
+ }
+
+ /* Prune tree without subtrees */
+ if (j == 0) {
+ talloc_free(*new);
+ *new = NULL;
+ return 0;
+ }
+
+ /* Fix subtree list size */
+ (*new)->u.list.num_elements = j;
+ (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements);
+
+ return ret;
+}
+
+/* Select a simple subtree that queries attributes in the local partition */
+static int map_subtree_select_local_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
+{
+ /* Prepare new tree */
+ *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
+ if (*new == NULL) {
+ map_oom(module);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Select subtrees that query attributes in the local partition */
+static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+
+ if (tree == NULL) {
+ return 0;
+ }
+
+ if (tree->operation == LDB_OP_NOT) {
+ return map_subtree_select_local_not(module, mem_ctx, new, tree);
+ }
+
+ if (tree->operation == LDB_OP_AND || tree->operation == LDB_OP_OR) {
+ return map_subtree_select_local_list(module, mem_ctx, new, tree);
+ }
+
+ if (map_attr_check_remote(data, tree->u.equality.attr)) {
+ *new = NULL;
+ return 0;
+ }
+
+ return map_subtree_select_local_simple(module, mem_ctx, new, tree);
+}
+
+static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree);
+
+/* Collect a negated subtree that queries attributes in the remote partition */
+static int map_subtree_collect_remote_not(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
+{
+ struct ldb_parse_tree *child;
+ int ret;
+
+ /* Prepare new tree */
+ *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
+ if (*new == NULL) {
+ map_oom(module);
+ return -1;
+ }
+
+ /* Generate new subtree */
+ ret = map_subtree_collect_remote(module, *new, &child, tree->u.isnot.child);
+ if (ret) {
+ talloc_free(*new);
+ return ret;
+ }
+
+ /* Prune tree without subtree */
+ if (child == NULL) {
+ talloc_free(*new);
+ *new = NULL;
+ return 0;
+ }
+
+ (*new)->u.isnot.child = child;
+
+ return ret;
+}
+
+/* Collect a list of subtrees that query attributes in the remote partition */
+static int map_subtree_collect_remote_list(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
+{
+ int i, j, ret=0;
+
+ /* Prepare new tree */
+ *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
+ if (*new == NULL) {
+ map_oom(module);
+ return -1;
+ }
+
+ /* Prepare list of subtrees */
+ (*new)->u.list.num_elements = 0;
+ (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements);
+ if ((*new)->u.list.elements == NULL) {
+ map_oom(module);
+ talloc_free(*new);
+ return -1;
+ }
+
+ /* Generate new list of subtrees */
+ j = 0;
+ for (i = 0; i < tree->u.list.num_elements; i++) {
+ struct ldb_parse_tree *child;
+ ret = map_subtree_collect_remote(module, *new, &child, tree->u.list.elements[i]);
+ if (ret) {
+ talloc_free(*new);
+ return ret;
+ }
+
+ if (child) {
+ (*new)->u.list.elements[j] = child;
+ j++;
+ }
+ }
+
+ /* Prune tree without subtrees */
+ if (j == 0) {
+ talloc_free(*new);
+ *new = NULL;
+ return 0;
+ }
+
+ /* Fix subtree list size */
+ (*new)->u.list.num_elements = j;
+ (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements);
+
+ return ret;
+}
+
+/* Collect a simple subtree that queries attributes in the remote partition */
+int map_subtree_collect_remote_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree, const struct ldb_map_attribute *map)
+{
+ const char *attr;
+
+ /* Prepare new tree */
+ *new = talloc(mem_ctx, struct ldb_parse_tree);
+ if (*new == NULL) {
+ map_oom(module);
+ return -1;
+ }
+ **new = *tree;
+
+ if (map->type == MAP_KEEP) {
+ /* Nothing to do here */
+ return 0;
+ }
+
+ /* Store attribute and value in new tree */
+ switch (tree->operation) {
+ case LDB_OP_PRESENT:
+ attr = map_attr_map_local(*new, map, tree->u.present.attr);
+ (*new)->u.present.attr = attr;
+ break;
+ case LDB_OP_SUBSTRING:
+ {
+ attr = map_attr_map_local(*new, map, tree->u.substring.attr);
+ (*new)->u.substring.attr = attr;
+ break;
+ }
+ case LDB_OP_EQUALITY:
+ attr = map_attr_map_local(*new, map, tree->u.equality.attr);
+ (*new)->u.equality.attr = attr;
+ break;
+ case LDB_OP_LESS:
+ case LDB_OP_GREATER:
+ case LDB_OP_APPROX:
+ attr = map_attr_map_local(*new, map, tree->u.comparison.attr);
+ (*new)->u.comparison.attr = attr;
+ break;
+ case LDB_OP_EXTENDED:
+ attr = map_attr_map_local(*new, map, tree->u.extended.attr);
+ (*new)->u.extended.attr = attr;
+ break;
+ default: /* unknown kind of simple subtree */
+ talloc_free(*new);
+ return -1;
+ }
+
+ if (attr == NULL) {
+ talloc_free(*new);
+ *new = NULL;
+ return 0;
+ }
+
+ if (map->type == MAP_RENAME) {
+ /* Nothing more to do here, the attribute has been renamed */
+ return 0;
+ }
+
+ /* Store attribute and value in new tree */
+ switch (tree->operation) {
+ case LDB_OP_PRESENT:
+ break;
+ case LDB_OP_SUBSTRING:
+ {
+ int i;
+ /* Map value */
+ (*new)->u.substring.chunks = NULL;
+ for (i=0; tree->u.substring.chunks[i]; i++) {
+ (*new)->u.substring.chunks = talloc_realloc(*new, (*new)->u.substring.chunks, struct ldb_val *, i+2);
+ if (!(*new)->u.substring.chunks) {
+ talloc_free(*new);
+ *new = NULL;
+ return 0;
+ }
+ (*new)->u.substring.chunks[i] = talloc(*new, struct ldb_val);
+ if (!(*new)->u.substring.chunks[i]) {
+ talloc_free(*new);
+ *new = NULL;
+ return 0;
+ }
+ *(*new)->u.substring.chunks[i] = ldb_val_map_local(module, *new, map, tree->u.substring.chunks[i]);
+ (*new)->u.substring.chunks[i+1] = NULL;
+ }
+ break;
+ }
+ case LDB_OP_EQUALITY:
+ (*new)->u.equality.value = ldb_val_map_local(module, *new, map, &tree->u.equality.value);
+ break;
+ case LDB_OP_LESS:
+ case LDB_OP_GREATER:
+ case LDB_OP_APPROX:
+ (*new)->u.comparison.value = ldb_val_map_local(module, *new, map, &tree->u.comparison.value);
+ break;
+ case LDB_OP_EXTENDED:
+ (*new)->u.extended.value = ldb_val_map_local(module, *new, map, &tree->u.extended.value);
+ (*new)->u.extended.rule_id = talloc_strdup(*new, tree->u.extended.rule_id);
+ break;
+ default: /* unknown kind of simple subtree */
+ talloc_free(*new);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Collect subtrees that query attributes in the remote partition */
+static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const struct ldb_map_attribute *map;
+
+ if (tree == NULL) {
+ return 0;
+ }
+
+ if (tree->operation == LDB_OP_NOT) {
+ return map_subtree_collect_remote_not(module, mem_ctx, new, tree);
+ }
+
+ if ((tree->operation == LDB_OP_AND) || (tree->operation == LDB_OP_OR)) {
+ return map_subtree_collect_remote_list(module, mem_ctx, new, tree);
+ }
+
+ if (!map_attr_check_remote(data, tree->u.equality.attr)) {
+ *new = NULL;
+ return 0;
+ }
+
+ map = map_attr_find_local(data, tree->u.equality.attr);
+ if (map->convert_operator) {
+ return map->convert_operator(module, mem_ctx, new, tree);
+ }
+
+ if (map->type == MAP_GENERATE) {
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
+ "Skipping attribute '%s': "
+ "'convert_operator' not set\n",
+ tree->u.equality.attr);
+ *new = NULL;
+ return 0;
+ }
+
+ return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, map);
+}
+
+/* Split subtrees that query attributes in the local partition from
+ * those that query the remote partition. */
+static int ldb_parse_tree_partition(struct ldb_module *module, void *local_ctx, void *remote_ctx, struct ldb_parse_tree **local_tree, struct ldb_parse_tree **remote_tree, const struct ldb_parse_tree *tree)
+{
+ int ret;
+
+ *local_tree = NULL;
+ *remote_tree = NULL;
+
+ /* No original tree */
+ if (tree == NULL) {
+ return 0;
+ }
+
+ /* Generate local tree */
+ ret = map_subtree_select_local(module, local_ctx, local_tree, tree);
+ if (ret) {
+ return ret;
+ }
+
+ /* Generate remote tree */
+ ret = map_subtree_collect_remote(module, remote_ctx, remote_tree, tree);
+ if (ret) {
+ talloc_free(*local_tree);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Collect a list of attributes required either explicitly from a
+ * given list or implicitly from a given parse tree; split the
+ * collected list into local and remote parts. */
+static int map_attrs_collect_and_partition(struct ldb_module *module, struct map_context *ac,
+ const char * const *search_attrs,
+ const struct ldb_parse_tree *tree)
+{
+ void *tmp_ctx;
+ const char **tree_attrs;
+ const char **remote_attrs;
+ const char **local_attrs;
+ int ret;
+
+ /* Clear initial lists of partitioned attributes */
+
+ /* Clear initial lists of partitioned attributes */
+
+ /* There is no tree, just partition the searched attributes */
+ if (tree == NULL) {
+ ret = map_attrs_partition(module, ac,
+ &local_attrs, &remote_attrs, search_attrs);
+ if (ret == 0) {
+ ac->local_attrs = local_attrs;
+ ac->remote_attrs = remote_attrs;
+ ac->all_attrs = search_attrs;
+ }
+ return ret;
+ }
+
+ /* Create context for temporary memory */
+ tmp_ctx = talloc_new(ac);
+ if (tmp_ctx == NULL) {
+ goto oom;
+ }
+
+ /* Prepare list of attributes from tree */
+ tree_attrs = talloc_array(tmp_ctx, const char *, 1);
+ if (tree_attrs == NULL) {
+ talloc_free(tmp_ctx);
+ goto oom;
+ }
+ tree_attrs[0] = NULL;
+
+ /* Collect attributes from tree */
+ ret = ldb_parse_tree_collect_attrs(module, tmp_ctx, &tree_attrs, tree);
+ if (ret) {
+ goto done;
+ }
+
+ /* Merge attributes from search operation */
+ ret = map_attrs_merge(module, tmp_ctx, &tree_attrs, search_attrs);
+ if (ret) {
+ goto done;
+ }
+
+ /* Split local from remote attributes */
+ ret = map_attrs_partition(module, ac, &local_attrs,
+ &remote_attrs, tree_attrs);
+
+ if (ret == 0) {
+ ac->local_attrs = local_attrs;
+ ac->remote_attrs = remote_attrs;
+ talloc_steal(ac, tree_attrs);
+ ac->all_attrs = tree_attrs;
+ }
+done:
+ /* Free temporary memory */
+ talloc_free(tmp_ctx);
+ return ret;
+
+oom:
+ map_oom(module);
+ return -1;
+}
+
+
+/* Outbound requests: search
+ * ========================= */
+
+/* Pass a merged search result up the callback chain. */
+int map_up_callback(struct ldb_context *ldb, const struct ldb_request *req, struct ldb_reply *ares)
+{
+ int i;
+
+ /* No callback registered, stop */
+ if (req->callback == NULL) {
+ return LDB_SUCCESS;
+ }
+
+ /* Only records need special treatment */
+ if (ares->type != LDB_REPLY_ENTRY) {
+ return req->callback(ldb, req->context, ares);
+ }
+
+ /* Merged result doesn't match original query, skip */
+ if (!ldb_match_msg(ldb, ares->message, req->op.search.tree, req->op.search.base, req->op.search.scope)) {
+ ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_map: "
+ "Skipping record '%s': "
+ "doesn't match original search\n",
+ ldb_dn_linearize(ldb, ares->message->dn));
+ return LDB_SUCCESS;
+ }
+
+ /* Limit result to requested attrs */
+ if ((req->op.search.attrs) && (!ldb_attr_in_list(req->op.search.attrs, "*"))) {
+ for (i = 0; i < ares->message->num_elements; ) {
+ struct ldb_message_element *el = &ares->message->elements[i];
+ if (!ldb_attr_in_list(req->op.search.attrs, el->name)) {
+ ldb_msg_remove_element(ares->message, el);
+ } else {
+ i++;
+ }
+ }
+ }
+
+ return req->callback(ldb, req->context, ares);
+}
+
+/* Merge the remote and local parts of a search result. */
+int map_local_merge_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+{
+ struct map_search_context *sc;
+ int ret;
+
+ if (context == NULL || ares == NULL) {
+ ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: "
+ "NULL Context or Result in `map_local_merge_callback`"));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ sc = talloc_get_type(context, struct map_search_context);
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ /* We have already found a local record */
+ if (sc->local_res) {
+ ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: "
+ "Too many results to base search for local entry"));
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Store local result */
+ sc->local_res = ares;
+
+ /* Merge remote into local message */
+ ret = ldb_msg_merge_local(sc->ac->module, ares->message, sc->remote_res->message);
+ if (ret) {
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return map_up_callback(ldb, sc->ac->orig_req, ares);
+
+ case LDB_REPLY_DONE:
+ /* No local record found, continue with remote record */
+ if (sc->local_res == NULL) {
+ return map_up_callback(ldb, sc->ac->orig_req, sc->remote_res);
+ }
+ return LDB_SUCCESS;
+
+ default:
+ ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: "
+ "Unexpected result type in base search for local entry"));
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+}
+
+/* Search the local part of a remote search result. */
+int map_remote_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+{
+ struct map_context *ac;
+ struct map_search_context *sc;
+ struct ldb_request *req;
+ int ret;
+
+ if (context == NULL || ares == NULL) {
+ ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: "
+ "NULL Context or Result in `map_remote_search_callback`"));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac = talloc_get_type(context, struct map_context);
+
+ /* It's not a record, stop searching */
+ if (ares->type != LDB_REPLY_ENTRY) {
+ return map_up_callback(ldb, ac->orig_req, ares);
+ }
+
+ /* Map result record into a local message */
+ ret = map_reply_remote(ac, ares);
+ if (ret) {
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* There is no local db, stop searching */
+ if (!map_check_local_db(ac->module)) {
+ return map_up_callback(ldb, ac->orig_req, ares);
+ }
+
+ /* Prepare local search context */
+ sc = map_init_search_context(ac, ares);
+ if (sc == NULL) {
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Prepare local search request */
+ /* TODO: use GUIDs here instead? */
+
+ ac->search_reqs = talloc_realloc(ac, ac->search_reqs, struct ldb_request *, ac->num_searches + 2);
+ if (ac->search_reqs == NULL) {
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->search_reqs[ac->num_searches]
+ = req = map_search_base_req(ac, ares->message->dn,
+ NULL, NULL, sc, map_local_merge_callback);
+ if (req == NULL) {
+ talloc_free(sc);
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac->num_searches++;
+ ac->search_reqs[ac->num_searches] = NULL;
+
+ return ldb_next_request(ac->module, req);
+}
+
+/* Search a record. */
+int map_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_handle *h;
+ struct map_context *ac;
+ struct ldb_parse_tree *local_tree, *remote_tree;
+ int ret;
+
+ const char *wildcard[] = { "*", NULL };
+ const char * const *attrs;
+
+ /* Do not manipulate our control entries */
+ if (ldb_dn_is_special(req->op.search.base))
+ return ldb_next_request(module, req);
+
+ /* No mapping requested, skip to next module */
+ if ((req->op.search.base) && (!ldb_dn_check_local(module, req->op.search.base))) {
+ return ldb_next_request(module, req);
+ }
+
+ /* TODO: How can we be sure about which partition we are
+ * targetting when there is no search base? */
+
+ /* Prepare context and handle */
+ h = map_init_handle(req, module);
+ if (h == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac = talloc_get_type(h->private_data, struct map_context);
+
+ ac->search_reqs = talloc_array(ac, struct ldb_request *, 2);
+ if (ac->search_reqs == NULL) {
+ talloc_free(h);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac->num_searches = 1;
+ ac->search_reqs[1] = NULL;
+
+ /* Prepare the remote operation */
+ ac->search_reqs[0] = talloc(ac, struct ldb_request);
+ if (ac->search_reqs[0] == NULL) {
+ goto oom;
+ }
+
+ *(ac->search_reqs[0]) = *req; /* copy the request */
+
+ ac->search_reqs[0]->handle = h; /* return our own handle to deal with this call */
+
+ ac->search_reqs[0]->context = ac;
+ ac->search_reqs[0]->callback = map_remote_search_callback;
+
+ /* It is easier to deal with the two different ways of
+ * expressing the wildcard in the same codepath */
+ attrs = req->op.search.attrs;
+ if (attrs == NULL) {
+ attrs = wildcard;
+ }
+
+ /* Split local from remote attrs */
+ ret = map_attrs_collect_and_partition(module, ac,
+ attrs, req->op.search.tree);
+ if (ret) {
+ goto failed;
+ }
+
+ ac->search_reqs[0]->op.search.attrs = ac->remote_attrs;
+
+ /* Split local from remote tree */
+ ret = ldb_parse_tree_partition(module, ac, ac->search_reqs[0],
+ &local_tree, &remote_tree,
+ req->op.search.tree);
+ if (ret) {
+ goto failed;
+ }
+
+ if (((local_tree != NULL) && (remote_tree != NULL)) &&
+ (!ldb_parse_tree_check_splittable(req->op.search.tree))) {
+ /* The query can't safely be split, enumerate the remote partition */
+ local_tree = NULL;
+ remote_tree = NULL;
+ }
+
+ if (local_tree == NULL) {
+ /* Construct default local parse tree */
+ local_tree = talloc_zero(ac, struct ldb_parse_tree);
+ if (local_tree == NULL) {
+ map_oom(ac->module);
+ goto failed;
+ }
+
+ local_tree->operation = LDB_OP_PRESENT;
+ local_tree->u.present.attr = talloc_strdup(local_tree, IS_MAPPED);
+ }
+ if (remote_tree == NULL) {
+ /* Construct default remote parse tree */
+ remote_tree = ldb_parse_tree(ac->search_reqs[0], NULL);
+ if (remote_tree == NULL) {
+ goto failed;
+ }
+ }
+
+ ac->local_tree = local_tree;
+ ac->search_reqs[0]->op.search.tree = remote_tree;
+
+ ldb_set_timeout_from_prev_req(module->ldb, req, ac->search_reqs[0]);
+
+ h->state = LDB_ASYNC_INIT;
+ h->status = LDB_SUCCESS;
+
+ ac->step = MAP_SEARCH_REMOTE;
+
+ ret = ldb_next_remote_request(module, ac->search_reqs[0]);
+ if (ret == LDB_SUCCESS) {
+ req->handle = h;
+ }
+ return ret;
+
+oom:
+ map_oom(module);
+failed:
+ talloc_free(h);
+ return LDB_ERR_OPERATIONS_ERROR;
+}
diff --git a/source3/lib/ldb/modules/ldb_map_private.h b/source3/lib/ldb/modules/ldb_map_private.h
new file mode 100644
index 0000000000..8a08d0a5b6
--- /dev/null
+++ b/source3/lib/ldb/modules/ldb_map_private.h
@@ -0,0 +1,117 @@
+
+/* A handy macro to report Out of Memory conditions */
+#define map_oom(module) ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
+
+/* The type of search callback functions */
+typedef int (*ldb_search_callback)(struct ldb_context *, void *, struct ldb_reply *);
+
+/* The special DN from which the local and remote base DNs are fetched */
+#define MAP_DN_NAME "@MAP"
+#define MAP_DN_FROM "@FROM"
+#define MAP_DN_TO "@TO"
+
+/* Private data structures
+ * ======================= */
+
+/* Context data for mapped requests */
+struct map_context {
+ enum map_step {
+ MAP_SEARCH_REMOTE,
+ MAP_ADD_REMOTE,
+ MAP_ADD_LOCAL,
+ MAP_SEARCH_SELF_MODIFY,
+ MAP_MODIFY_REMOTE,
+ MAP_MODIFY_LOCAL,
+ MAP_SEARCH_SELF_DELETE,
+ MAP_DELETE_REMOTE,
+ MAP_DELETE_LOCAL,
+ MAP_SEARCH_SELF_RENAME,
+ MAP_RENAME_REMOTE,
+ MAP_RENAME_FIXUP,
+ MAP_RENAME_LOCAL
+ } step;
+
+ struct ldb_module *module;
+
+ const struct ldb_dn *local_dn;
+ const struct ldb_parse_tree *local_tree;
+ const char * const *local_attrs;
+ const char * const *remote_attrs;
+ const char * const *all_attrs;
+
+ struct ldb_request *orig_req;
+ struct ldb_request *local_req;
+ struct ldb_request *remote_req;
+ struct ldb_request *down_req;
+ struct ldb_request *search_req;
+
+ /* for search, we may have a lot of contexts */
+ int num_searches;
+ struct ldb_request **search_reqs;
+};
+
+/* Context data for mapped search requests */
+struct map_search_context {
+ struct map_context *ac;
+ struct ldb_reply *local_res;
+ struct ldb_reply *remote_res;
+};
+
+
+/* Common operations
+ * ================= */
+
+/* The following definitions come from lib/ldb/modules/ldb_map.c */
+const struct ldb_map_context *map_get_context(struct ldb_module *module);
+struct map_search_context *map_init_search_context(struct map_context *ac, struct ldb_reply *ares);
+struct ldb_handle *map_init_handle(struct ldb_request *req, struct ldb_module *module);
+
+int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request);
+
+BOOL map_check_local_db(struct ldb_module *module);
+BOOL map_attr_check_remote(const struct ldb_map_context *data, const char *attr);
+BOOL ldb_dn_check_local(struct ldb_module *module, const struct ldb_dn *dn);
+
+const struct ldb_map_attribute *map_attr_find_local(const struct ldb_map_context *data, const char *name);
+const struct ldb_map_attribute *map_attr_find_remote(const struct ldb_map_context *data, const char *name);
+
+const char *map_attr_map_local(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr);
+const char *map_attr_map_remote(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr);
+int map_attrs_merge(struct ldb_module *module, void *mem_ctx, const char ***attrs, const char * const *more_attrs);
+
+struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_val *val);
+struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_val *val);
+
+struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn);
+struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn);
+struct ldb_dn *ldb_dn_map_rebase_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn);
+
+struct ldb_request *map_search_base_req(struct map_context *ac, const struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_search_callback callback);
+struct ldb_request *map_search_self_req(struct map_context *ac, const struct ldb_dn *dn);
+struct ldb_request *map_build_fixup_req(struct map_context *ac, const struct ldb_dn *olddn, const struct ldb_dn *newdn);
+
+int map_subtree_collect_remote_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree, const struct ldb_map_attribute *map);
+
+/* LDB Requests
+ * ============ */
+
+/* The following definitions come from lib/ldb/modules/ldb_map_inbound.c */
+int map_add_do_remote(struct ldb_handle *handle);
+int map_add_do_local(struct ldb_handle *handle);
+int map_add(struct ldb_module *module, struct ldb_request *req);
+
+int map_modify_do_remote(struct ldb_handle *handle);
+int map_modify_do_local(struct ldb_handle *handle);
+int map_modify(struct ldb_module *module, struct ldb_request *req);
+
+int map_delete_do_remote(struct ldb_handle *handle);
+int map_delete_do_local(struct ldb_handle *handle);
+int map_delete(struct ldb_module *module, struct ldb_request *req);
+
+int map_rename_do_remote(struct ldb_handle *handle);
+int map_rename_do_fixup(struct ldb_handle *handle);
+int map_rename_do_local(struct ldb_handle *handle);
+int map_rename(struct ldb_module *module, struct ldb_request *req);
+
+/* The following definitions come from lib/ldb/modules/ldb_map_outbound.c */
+int map_search(struct ldb_module *module, struct ldb_request *req);
diff --git a/source3/lib/ldb/modules/objectclass.c b/source3/lib/ldb/modules/objectclass.c
new file mode 100644
index 0000000000..03e0967f0e
--- /dev/null
+++ b/source3/lib/ldb/modules/objectclass.c
@@ -0,0 +1,693 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2006
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: objectClass sorting module
+ *
+ * Description: sort the objectClass attribute into the class hierarchy
+ *
+ * Author: Andrew Bartlett
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+struct oc_context {
+
+ enum oc_step {OC_DO_REQ, OC_SEARCH_SELF, OC_DO_MOD} step;
+
+ struct ldb_module *module;
+ struct ldb_request *orig_req;
+
+ struct ldb_request *down_req;
+
+ struct ldb_request *search_req;
+ struct ldb_reply *search_res;
+
+ struct ldb_request *mod_req;
+};
+
+struct class_list {
+ struct class_list *prev, *next;
+ const char *objectclass;
+};
+
+static struct ldb_handle *oc_init_handle(struct ldb_request *req, struct ldb_module *module)
+{
+ struct oc_context *ac;
+ struct ldb_handle *h;
+
+ h = talloc_zero(req, struct ldb_handle);
+ if (h == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ return NULL;
+ }
+
+ h->module = module;
+
+ ac = talloc_zero(h, struct oc_context);
+ if (ac == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ talloc_free(h);
+ return NULL;
+ }
+
+ h->private_data = (void *)ac;
+
+ h->state = LDB_ASYNC_INIT;
+ h->status = LDB_SUCCESS;
+
+ ac->module = module;
+ ac->orig_req = req;
+
+ return h;
+}
+
+static int objectclass_sort(struct ldb_module *module,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *objectclass_element,
+ struct class_list **sorted_out)
+{
+ int i;
+ int layer;
+ struct class_list *sorted = NULL, *parent_class = NULL,
+ *subclass = NULL, *unsorted = NULL, *current, *poss_subclass;
+ /* DESIGN:
+ *
+ * We work on 4 different 'bins' (implemented here as linked lists):
+ *
+ * * sorted: the eventual list, in the order we wish to push
+ * into the database. This is the only ordered list.
+ *
+ * * parent_class: The current parent class 'bin' we are
+ * trying to find subclasses for
+ *
+ * * subclass: The subclasses we have found so far
+ *
+ * * unsorted: The remaining objectClasses
+ *
+ * The process is a matter of filtering objectClasses up from
+ * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
+ *
+ * We start with 'top' (found and promoted to parent_class
+ * initially). Then we find (in unsorted) all the direct
+ * subclasses of 'top'. parent_classes is concatenated onto
+ * the end of 'sorted', and subclass becomes the list in
+ * parent_class.
+ *
+ * We then repeat, until we find no more subclasses. Any left
+ * over classes are added to the end.
+ *
+ */
+
+ /* Firstly, dump all the objectClass elements into the
+ * unsorted bin, except for 'top', which is special */
+ for (i=0; i < objectclass_element->num_values; i++) {
+ current = talloc(mem_ctx, struct class_list);
+ if (!current) {
+ ldb_set_errstring(module->ldb, "objectclass: out of memory allocating objectclass list");
+ talloc_free(mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ current->objectclass = (const char *)objectclass_element->values[i].data;
+
+ /* this is the root of the tree. We will start
+ * looking for subclasses from here */
+ if (ldb_attr_cmp("top", current->objectclass) == 0) {
+ DLIST_ADD(parent_class, current);
+ } else {
+ DLIST_ADD(unsorted, current);
+ }
+ }
+
+ /* DEBUGGING aid: how many layers are we down now? */
+ layer = 0;
+ do {
+ layer++;
+ /* Find all the subclasses of classes in the
+ * parent_classes. Push them onto the subclass list */
+
+ /* Ensure we don't bother if there are no unsorted entries left */
+ for (current = parent_class; unsorted && current; current = current->next) {
+ const char **subclasses = ldb_subclass_list(module->ldb, current->objectclass);
+
+ /* Walk the list of possible subclasses in unsorted */
+ for (poss_subclass = unsorted; poss_subclass; ) {
+ struct class_list *next;
+
+ /* Save the next pointer, as the DLIST_ macros will change poss_subclass->next */
+ next = poss_subclass->next;
+
+ for (i = 0; subclasses && subclasses[i]; i++) {
+ if (ldb_attr_cmp(poss_subclass->objectclass, subclasses[i]) == 0) {
+ DLIST_REMOVE(unsorted, poss_subclass);
+ DLIST_ADD(subclass, poss_subclass);
+
+ break;
+ }
+ }
+ poss_subclass = next;
+ }
+ }
+
+ /* Now push the parent_classes as sorted, we are done with
+ these. Add to the END of the list by concatenation */
+ DLIST_CONCATENATE(sorted, parent_class, struct class_list *);
+
+ /* and now find subclasses of these */
+ parent_class = subclass;
+ subclass = NULL;
+
+ /* If we didn't find any subclasses we will fall out
+ * the bottom here */
+ } while (parent_class);
+
+ /* This shouldn't happen, and would break MMC, but we can't
+ * afford to loose objectClasses. Perhaps there was no 'top',
+ * or some other schema error?
+ *
+ * Detecting schema errors is the job of the schema module, so
+ * at this layer we just try not to loose data
+ */
+ DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
+
+ *sorted_out = sorted;
+ return LDB_SUCCESS;
+}
+
+static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_message_element *objectclass_element;
+ struct class_list *sorted, *current;
+ struct ldb_request *down_req;
+ struct ldb_message *msg;
+ int ret;
+ TALLOC_CTX *mem_ctx;
+
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
+
+ if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
+ return ldb_next_request(module, req);
+ }
+
+ objectclass_element = ldb_msg_find_element(req->op.add.message, "objectClass");
+
+ /* If no part of this add has an objectClass, then we don't
+ * need to make any changes. cn=rootdse doesn't have an objectClass */
+ if (!objectclass_element) {
+ return ldb_next_request(module, req);
+ }
+
+ mem_ctx = talloc_new(req);
+ if (mem_ctx == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = objectclass_sort(module, mem_ctx, objectclass_element, &sorted);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* prepare the first operation */
+ down_req = talloc(req, struct ldb_request);
+ if (down_req == NULL) {
+ ldb_set_errstring(module->ldb, "Out of memory!");
+ talloc_free(mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *down_req = *req; /* copy the request */
+
+ down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
+
+ if (down_req->op.add.message == NULL) {
+ talloc_free(mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ldb_msg_remove_attr(msg, "objectClass");
+ ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
+
+ if (ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ return ret;
+ }
+
+ /* We must completely replace the existing objectClass entry,
+ * because we need it sorted */
+
+ /* Move from the linked list back into an ldb msg */
+ for (current = sorted; current; current = current->next) {
+ ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
+ if (ret != LDB_SUCCESS) {
+ ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
+ talloc_free(mem_ctx);
+ return ret;
+ }
+ }
+
+ talloc_free(mem_ctx);
+ ret = ldb_msg_sanity_check(module->ldb, msg);
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* go on with the call chain */
+ ret = ldb_next_request(module, down_req);
+
+ /* do not free down_req as the call results may be linked to it,
+ * it will be freed when the upper level request get freed */
+ if (ret == LDB_SUCCESS) {
+ req->handle = down_req->handle;
+ }
+ return ret;
+}
+
+static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_message_element *objectclass_element;
+ struct ldb_message *msg;
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
+
+ if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
+ return ldb_next_request(module, req);
+ }
+
+ objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
+
+ /* If no part of this touches the objectClass, then we don't
+ * need to make any changes. */
+ /* If the only operation is the deletion of the objectClass then go on */
+ if (!objectclass_element) {
+ return ldb_next_request(module, req);
+ }
+
+ switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
+ case LDB_FLAG_MOD_DELETE:
+ /* Delete everything? Probably totally illigal, but hey! */
+ if (objectclass_element->num_values == 0) {
+ return ldb_next_request(module, req);
+ }
+ break;
+ case LDB_FLAG_MOD_REPLACE:
+ {
+ struct ldb_request *down_req;
+ struct class_list *sorted, *current;
+ TALLOC_CTX *mem_ctx;
+ int ret;
+ mem_ctx = talloc_new(req);
+ if (mem_ctx == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* prepare the first operation */
+ down_req = talloc(req, struct ldb_request);
+ if (down_req == NULL) {
+ ldb_set_errstring(module->ldb, "Out of memory!");
+ talloc_free(mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *down_req = *req; /* copy the request */
+
+ down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
+
+ if (down_req->op.add.message == NULL) {
+ talloc_free(mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = objectclass_sort(module, mem_ctx, objectclass_element, &sorted);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* We must completely replace the existing objectClass entry,
+ * because we need it sorted */
+
+ ldb_msg_remove_attr(msg, "objectClass");
+ ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
+
+ if (ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ return ret;
+ }
+
+ /* Move from the linked list back into an ldb msg */
+ for (current = sorted; current; current = current->next) {
+ ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
+ if (ret != LDB_SUCCESS) {
+ ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
+ talloc_free(mem_ctx);
+ return ret;
+ }
+ }
+
+ talloc_free(mem_ctx);
+
+ ret = ldb_msg_sanity_check(module->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ return ret;
+ }
+
+ /* go on with the call chain */
+ ret = ldb_next_request(module, down_req);
+
+ /* do not free down_req as the call results may be linked to it,
+ * it will be freed when the upper level request get freed */
+ if (ret == LDB_SUCCESS) {
+ req->handle = down_req->handle;
+ }
+ return ret;
+ }
+ }
+
+ {
+ struct ldb_handle *h;
+ struct oc_context *ac;
+
+ h = oc_init_handle(req, module);
+ if (!h) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac = talloc_get_type(h->private_data, struct oc_context);
+
+ /* return or own handle to deal with this call */
+ req->handle = h;
+
+ /* prepare the first operation */
+ ac->down_req = talloc(ac, struct ldb_request);
+ if (ac->down_req == NULL) {
+ ldb_set_errstring(module->ldb, "Out of memory!");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *(ac->down_req) = *req; /* copy the request */
+
+ ac->down_req->context = NULL;
+ ac->down_req->callback = NULL;
+ ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
+
+ ac->step = OC_DO_REQ;
+
+ return ldb_next_request(module, ac->down_req);
+ }
+}
+
+static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+{
+ struct oc_context *ac;
+
+ if (!context || !ares) {
+ ldb_set_errstring(ldb, "NULL Context or Result in callback");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac = talloc_get_type(context, struct oc_context);
+
+ /* we are interested only in the single reply (base search) we receive here */
+ if (ares->type == LDB_REPLY_ENTRY) {
+ if (ac->search_res != NULL) {
+ ldb_set_errstring(ldb, "Too many results");
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->search_res = talloc_move(ac, &ares);
+ } else {
+ talloc_free(ares);
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int objectclass_search_self(struct ldb_handle *h) {
+
+ struct oc_context *ac;
+ static const char * const attrs[] = { "objectClass", NULL };
+
+ ac = talloc_get_type(h->private_data, struct oc_context);
+
+ /* prepare the search operation */
+ ac->search_req = talloc_zero(ac, struct ldb_request);
+ if (ac->search_req == NULL) {
+ ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->search_req->operation = LDB_SEARCH;
+ ac->search_req->op.search.base = ac->orig_req->op.mod.message->dn;
+ ac->search_req->op.search.scope = LDB_SCOPE_BASE;
+ ac->search_req->op.search.tree = ldb_parse_tree(ac->search_req, NULL);
+ if (ac->search_req->op.search.tree == NULL) {
+ ldb_set_errstring(ac->module->ldb, "objectclass: Internal error producing null search");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac->search_req->op.search.attrs = attrs;
+ ac->search_req->controls = NULL;
+ ac->search_req->context = ac;
+ ac->search_req->callback = get_self_callback;
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
+
+ ac->step = OC_SEARCH_SELF;
+
+ return ldb_next_request(ac->module, ac->search_req);
+}
+
+static int objectclass_do_mod(struct ldb_handle *h) {
+
+ struct oc_context *ac;
+ struct ldb_message_element *objectclass_element;
+ struct ldb_message *msg;
+ TALLOC_CTX *mem_ctx;
+ struct class_list *sorted, *current;
+ int ret;
+
+ ac = talloc_get_type(h->private_data, struct oc_context);
+
+ mem_ctx = talloc_new(ac);
+ if (mem_ctx == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->mod_req = talloc(ac, struct ldb_request);
+ if (ac->mod_req == NULL) {
+ talloc_free(mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->mod_req->operation = LDB_MODIFY;
+ ac->mod_req->controls = NULL;
+ ac->mod_req->context = ac;
+ ac->mod_req->callback = NULL;
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->mod_req);
+
+ /* use a new message structure */
+ ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
+ if (msg == NULL) {
+ ldb_set_errstring(ac->module->ldb, "objectclass: could not create new modify msg");
+ talloc_free(mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* This is now the objectClass list from the database */
+ objectclass_element = ldb_msg_find_element(ac->search_res->message,
+ "objectClass");
+ if (!objectclass_element) {
+ /* Where did it go? Move along now, nothing to see here */
+ talloc_free(mem_ctx);
+ return LDB_SUCCESS;
+ }
+
+ /* modify dn */
+ msg->dn = ac->orig_req->op.mod.message->dn;
+
+ ret = objectclass_sort(ac->module, mem_ctx, objectclass_element, &sorted);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* We must completely replace the existing objectClass entry.
+ * We could do a constrained add/del, but we are meant to be
+ * in a transaction... */
+
+ ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
+ if (ret != LDB_SUCCESS) {
+ ldb_set_errstring(ac->module->ldb, "objectclass: could not clear objectclass in modify msg");
+ talloc_free(mem_ctx);
+ return ret;
+ }
+
+ /* Move from the linked list back into an ldb msg */
+ for (current = sorted; current; current = current->next) {
+ ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
+ if (ret != LDB_SUCCESS) {
+ ldb_set_errstring(ac->module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
+ talloc_free(mem_ctx);
+ return ret;
+ }
+ }
+
+ ret = ldb_msg_sanity_check(ac->module->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ return ret;
+ }
+
+
+ h->state = LDB_ASYNC_INIT;
+ h->status = LDB_SUCCESS;
+
+ ac->step = OC_DO_MOD;
+
+ talloc_free(mem_ctx);
+ /* perform the search */
+ return ldb_next_request(ac->module, ac->mod_req);
+}
+
+static int oc_wait(struct ldb_handle *handle) {
+ struct oc_context *ac;
+ int ret;
+
+ if (!handle || !handle->private_data) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (handle->state == LDB_ASYNC_DONE) {
+ return handle->status;
+ }
+
+ handle->state = LDB_ASYNC_PENDING;
+ handle->status = LDB_SUCCESS;
+
+ ac = talloc_get_type(handle->private_data, struct oc_context);
+
+ switch (ac->step) {
+ case OC_DO_REQ:
+ ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
+
+ if (ret != LDB_SUCCESS) {
+ handle->status = ret;
+ goto done;
+ }
+ if (ac->down_req->handle->status != LDB_SUCCESS) {
+ handle->status = ac->down_req->handle->status;
+ goto done;
+ }
+
+ if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
+ return LDB_SUCCESS;
+ }
+
+ /* mods done, go on */
+ return objectclass_search_self(handle);
+
+ case OC_SEARCH_SELF:
+ ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
+
+ if (ret != LDB_SUCCESS) {
+ handle->status = ret;
+ goto done;
+ }
+ if (ac->search_req->handle->status != LDB_SUCCESS) {
+ handle->status = ac->search_req->handle->status;
+ goto done;
+ }
+
+ if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
+ return LDB_SUCCESS;
+ }
+
+ /* self search done, go on */
+ return objectclass_do_mod(handle);
+
+ case OC_DO_MOD:
+ ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE);
+
+ if (ret != LDB_SUCCESS) {
+ handle->status = ret;
+ goto done;
+ }
+ if (ac->mod_req->handle->status != LDB_SUCCESS) {
+ handle->status = ac->mod_req->handle->status;
+ goto done;
+ }
+
+ if (ac->mod_req->handle->state != LDB_ASYNC_DONE) {
+ return LDB_SUCCESS;
+ }
+
+ break;
+
+ default:
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ ret = LDB_SUCCESS;
+
+done:
+ handle->state = LDB_ASYNC_DONE;
+ return ret;
+}
+
+static int oc_wait_all(struct ldb_handle *handle) {
+
+ int ret;
+
+ while (handle->state != LDB_ASYNC_DONE) {
+ ret = oc_wait(handle);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ return handle->status;
+}
+
+static int objectclass_wait(struct ldb_handle *handle, enum ldb_wait_type type)
+{
+ if (type == LDB_WAIT_ALL) {
+ return oc_wait_all(handle);
+ } else {
+ return oc_wait(handle);
+ }
+}
+
+static const struct ldb_module_ops objectclass_ops = {
+ .name = "objectclass",
+ .add = objectclass_add,
+ .modify = objectclass_modify,
+ .wait = objectclass_wait
+};
+
+int ldb_objectclass_init(void)
+{
+ return ldb_register_module(&objectclass_ops);
+}
+
diff --git a/source3/lib/ldb/modules/operational.c b/source3/lib/ldb/modules/operational.c
new file mode 100644
index 0000000000..7c8e03c337
--- /dev/null
+++ b/source3/lib/ldb/modules/operational.c
@@ -0,0 +1,311 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Simo Sorce 2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ handle operational attributes
+ */
+
+/*
+ createTimestamp: HIDDEN, searchable, ldaptime, alias for whenCreated
+ modifyTimestamp: HIDDEN, searchable, ldaptime, alias for whenChanged
+
+ for the above two, we do the search as normal, and if
+ createTimestamp or modifyTimestamp is asked for, then do
+ additional searches for whenCreated and whenChanged and fill in
+ the resulting values
+
+ we also need to replace these with the whenCreated/whenChanged
+ equivalent in the search expression trees
+
+ whenCreated: not-HIDDEN, CONSTRUCTED, SEARCHABLE
+ whenChanged: not-HIDDEN, CONSTRUCTED, SEARCHABLE
+
+ on init we need to setup attribute handlers for these so
+ comparisons are done correctly. The resolution is 1 second.
+
+ on add we need to add both the above, for current time
+
+ on modify we need to change whenChanged
+
+
+ subschemaSubentry: HIDDEN, not-searchable,
+ points at DN CN=Aggregate,CN=Schema,CN=Configuration,$BASEDN
+
+ for this one we do the search as normal, then add the static
+ value if requested. How do we work out the $BASEDN from inside a
+ module?
+
+
+ structuralObjectClass: HIDDEN, CONSTRUCTED, not-searchable. always same as objectclass?
+
+ for this one we do the search as normal, then if requested ask
+ for objectclass, change the attribute name, and add it
+
+ allowedAttributesEffective: HIDDEN, CONSTRUCTED, not-searchable,
+ list of attributes that can be modified - requires schema lookup
+
+
+ attributeTypes: in schema only
+ objectClasses: in schema only
+ matchingRules: in schema only
+ matchingRuleUse: in schema only
+ creatorsName: not supported by w2k3?
+ modifiersName: not supported by w2k3?
+*/
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+/*
+ construct a canonical name from a message
+*/
+static int construct_canonical_name(struct ldb_module *module, struct ldb_message *msg)
+{
+ char *canonicalName;
+ canonicalName = ldb_dn_canonical_string(msg, msg->dn);
+ if (canonicalName == NULL) {
+ return -1;
+ }
+ return ldb_msg_add_steal_string(msg, "canonicalName", canonicalName);
+}
+
+/*
+ a list of attribute names that should be substituted in the parse
+ tree before the search is done
+*/
+static const struct {
+ const char *attr;
+ const char *replace;
+} parse_tree_sub[] = {
+ { "createTimestamp", "whenCreated" },
+ { "modifyTimestamp", "whenChanged" }
+};
+
+
+/*
+ a list of attribute names that are hidden, but can be searched for
+ using another (non-hidden) name to produce the correct result
+*/
+static const struct {
+ const char *attr;
+ const char *replace;
+ int (*constructor)(struct ldb_module *, struct ldb_message *);
+} search_sub[] = {
+ { "createTimestamp", "whenCreated", NULL },
+ { "modifyTimestamp", "whenChanged", NULL },
+ { "structuralObjectClass", "objectClass", NULL },
+ { "canonicalName", "distinguishedName", construct_canonical_name }
+};
+
+/*
+ post process a search result record. For any search_sub[] attributes that were
+ asked for, we need to call the appropriate copy routine to copy the result
+ into the message, then remove any attributes that we added to the search but were
+ not asked for by the user
+*/
+static int operational_search_post_process(struct ldb_module *module,
+ struct ldb_message *msg,
+ const char * const *attrs)
+{
+ int i, a=0;
+
+ for (a=0;attrs && attrs[a];a++) {
+ for (i=0;i<ARRAY_SIZE(search_sub);i++) {
+ if (ldb_attr_cmp(attrs[a], search_sub[i].attr) != 0) {
+ continue;
+ }
+
+ /* construct the new attribute, using either a supplied
+ constructor or a simple copy */
+ if (search_sub[i].constructor) {
+ if (search_sub[i].constructor(module, msg) != 0) {
+ goto failed;
+ }
+ } else if (ldb_msg_copy_attr(msg,
+ search_sub[i].replace,
+ search_sub[i].attr) != 0) {
+ goto failed;
+ }
+
+ /* remove the added search attribute, unless it was asked for
+ by the user */
+ if (search_sub[i].replace == NULL ||
+ ldb_attr_in_list(attrs, search_sub[i].replace) ||
+ ldb_attr_in_list(attrs, "*")) {
+ continue;
+ }
+
+ ldb_msg_remove_attr(msg, search_sub[i].replace);
+ }
+ }
+
+ return 0;
+
+failed:
+ ldb_debug_set(module->ldb, LDB_DEBUG_WARNING,
+ "operational_search_post_process failed for attribute '%s'\n",
+ attrs[a]);
+ return -1;
+}
+
+
+/*
+ hook search operations
+*/
+
+struct operational_context {
+
+ struct ldb_module *module;
+ void *up_context;
+ int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
+
+ const char * const *attrs;
+};
+
+static int operational_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+{
+ struct operational_context *ac;
+
+ if (!context || !ares) {
+ ldb_set_errstring(ldb, "NULL Context or Result in callback");
+ goto error;
+ }
+
+ ac = talloc_get_type(context, struct operational_context);
+
+ if (ares->type == LDB_REPLY_ENTRY) {
+ /* for each record returned post-process to add any derived
+ attributes that have been asked for */
+ if (operational_search_post_process(ac->module, ares->message, ac->attrs) != 0) {
+ goto error;
+ }
+ }
+
+ return ac->up_callback(ldb, ac->up_context, ares);
+
+error:
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+static int operational_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct operational_context *ac;
+ struct ldb_request *down_req;
+ const char **search_attrs = NULL;
+ int i, a, ret;
+
+ req->handle = NULL;
+
+ ac = talloc(req, struct operational_context);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->module = module;
+ ac->up_context = req->context;
+ ac->up_callback = req->callback;
+ ac->attrs = req->op.search.attrs;
+
+ down_req = talloc_zero(req, struct ldb_request);
+ if (down_req == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ down_req->operation = req->operation;
+ down_req->op.search.base = req->op.search.base;
+ down_req->op.search.scope = req->op.search.scope;
+ down_req->op.search.tree = req->op.search.tree;
+
+ /* FIXME: I hink we should copy the tree and keep the original
+ * unmodified. SSS */
+ /* replace any attributes in the parse tree that are
+ searchable, but are stored using a different name in the
+ backend */
+ for (i=0;i<ARRAY_SIZE(parse_tree_sub);i++) {
+ ldb_parse_tree_attr_replace(discard_const_p(struct ldb_parse_tree, req->op.search.tree),
+ parse_tree_sub[i].attr,
+ parse_tree_sub[i].replace);
+ }
+
+ /* in the list of attributes we are looking for, rename any
+ attributes to the alias for any hidden attributes that can
+ be fetched directly using non-hidden names */
+ for (a=0;ac->attrs && ac->attrs[a];a++) {
+ for (i=0;i<ARRAY_SIZE(search_sub);i++) {
+ if (ldb_attr_cmp(ac->attrs[a], search_sub[i].attr) == 0 &&
+ search_sub[i].replace) {
+ if (!search_attrs) {
+ search_attrs = ldb_attr_list_copy(req, ac->attrs);
+ if (search_attrs == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+ search_attrs[a] = search_sub[i].replace;
+ }
+ }
+ }
+
+ /* use new set of attrs if any */
+ if (search_attrs) down_req->op.search.attrs = search_attrs;
+ else down_req->op.search.attrs = req->op.search.attrs;
+
+ down_req->controls = req->controls;
+
+ down_req->context = ac;
+ down_req->callback = operational_callback;
+ ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
+
+ /* perform the search */
+ ret = ldb_next_request(module, down_req);
+
+ /* do not free down_req as the call results may be linked to it,
+ * it will be freed when the upper level request get freed */
+ if (ret == LDB_SUCCESS) {
+ req->handle = down_req->handle;
+ }
+
+ return ret;
+}
+
+static int operational_init(struct ldb_module *ctx)
+{
+ /* setup some standard attribute handlers */
+ ldb_set_attrib_handler_syntax(ctx->ldb, "whenCreated", LDB_SYNTAX_UTC_TIME);
+ ldb_set_attrib_handler_syntax(ctx->ldb, "whenChanged", LDB_SYNTAX_UTC_TIME);
+ ldb_set_attrib_handler_syntax(ctx->ldb, "subschemaSubentry", LDB_SYNTAX_DN);
+ ldb_set_attrib_handler_syntax(ctx->ldb, "structuralObjectClass", LDB_SYNTAX_OBJECTCLASS);
+
+ return ldb_next_init(ctx);
+}
+
+static const struct ldb_module_ops operational_ops = {
+ .name = "operational",
+ .search = operational_search,
+ .init_context = operational_init
+};
+
+int ldb_operational_init(void)
+{
+ return ldb_register_module(&operational_ops);
+}
diff --git a/source3/lib/ldb/modules/paged_results.c b/source3/lib/ldb/modules/paged_results.c
new file mode 100644
index 0000000000..63f9ee6752
--- /dev/null
+++ b/source3/lib/ldb/modules/paged_results.c
@@ -0,0 +1,566 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005-2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: paged_result
+ *
+ * Component: ldb paged results control module
+ *
+ * Description: this module caches a complete search and sends back
+ * results in chunks as asked by the client
+ *
+ * Author: Simo Sorce
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+struct message_store {
+ /* keep the whole ldb_reply as an optimization
+ * instead of freeing and talloc-ing the container
+ * on each result */
+ struct ldb_reply *r;
+ struct message_store *next;
+};
+
+struct private_data;
+
+struct results_store {
+
+ struct private_data *priv;
+
+ char *cookie;
+ time_t timestamp;
+
+ struct results_store *prev;
+ struct results_store *next;
+
+ struct message_store *first;
+ struct message_store *last;
+ int num_entries;
+
+ struct message_store *first_ref;
+ struct message_store *last_ref;
+
+ struct ldb_control **controls;
+
+ struct ldb_request *req;
+};
+
+struct private_data {
+
+ int next_free_id;
+ struct results_store *store;
+
+};
+
+int store_destructor(struct results_store *store);
+
+int store_destructor(struct results_store *store)
+{
+ if (store->prev) {
+ store->prev->next = store->next;
+ }
+ if (store->next) {
+ store->next->prev = store->prev;
+ }
+
+ if (store == store->priv->store) {
+ store->priv->store = NULL;
+ }
+
+ return 0;
+}
+
+static struct results_store *new_store(struct private_data *priv)
+{
+ struct results_store *newr;
+ int new_id = priv->next_free_id++;
+
+ /* TODO: we should have a limit on the number of
+ * outstanding paged searches
+ */
+
+ newr = talloc(priv, struct results_store);
+ if (!newr) return NULL;
+
+ newr->priv = priv;
+
+ newr->cookie = talloc_asprintf(newr, "%d", new_id);
+ if (!newr->cookie) {
+ talloc_free(newr);
+ return NULL;
+ }
+
+ newr->timestamp = time(NULL);
+
+ newr->first = NULL;
+ newr->num_entries = 0;
+ newr->first_ref = NULL;
+ newr->controls = NULL;
+
+ /* put this entry as first */
+ newr->prev = NULL;
+ newr->next = priv->store;
+ if (priv->store != NULL) priv->store->prev = newr;
+ priv->store = newr;
+
+ talloc_set_destructor(newr, store_destructor);
+
+ return newr;
+}
+
+struct paged_context {
+ struct ldb_module *module;
+ void *up_context;
+ int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
+
+ int size;
+
+ struct results_store *store;
+};
+
+static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module,
+ void *context,
+ int (*callback)(struct ldb_context *, void *, struct ldb_reply *))
+{
+ struct paged_context *ac;
+ struct ldb_handle *h;
+
+ h = talloc_zero(mem_ctx, struct ldb_handle);
+ if (h == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ return NULL;
+ }
+
+ h->module = module;
+
+ ac = talloc_zero(h, struct paged_context);
+ if (ac == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ talloc_free(h);
+ return NULL;
+ }
+
+ h->private_data = (void *)ac;
+
+ h->state = LDB_ASYNC_INIT;
+ h->status = LDB_SUCCESS;
+
+ ac->module = module;
+ ac->up_context = context;
+ ac->up_callback = callback;
+
+ return h;
+}
+
+static int paged_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+{
+ struct paged_context *ac = NULL;
+
+ if (!context || !ares) {
+ ldb_set_errstring(ldb, "NULL Context or Result in callback");
+ goto error;
+ }
+
+ ac = talloc_get_type(context, struct paged_context);
+
+ if (ares->type == LDB_REPLY_ENTRY) {
+ if (ac->store->first == NULL) {
+ ac->store->first = ac->store->last = talloc(ac->store, struct message_store);
+ } else {
+ ac->store->last->next = talloc(ac->store, struct message_store);
+ ac->store->last = ac->store->last->next;
+ }
+ if (ac->store->last == NULL) {
+ goto error;
+ }
+
+ ac->store->num_entries++;
+
+ ac->store->last->r = talloc_steal(ac->store->last, ares);
+ ac->store->last->next = NULL;
+ }
+
+ if (ares->type == LDB_REPLY_REFERRAL) {
+ if (ac->store->first_ref == NULL) {
+ ac->store->first_ref = ac->store->last_ref = talloc(ac->store, struct message_store);
+ } else {
+ ac->store->last_ref->next = talloc(ac->store, struct message_store);
+ ac->store->last_ref = ac->store->last_ref->next;
+ }
+ if (ac->store->last_ref == NULL) {
+ goto error;
+ }
+
+ ac->store->last_ref->r = talloc_steal(ac->store->last, ares);
+ ac->store->last_ref->next = NULL;
+ }
+
+ if (ares->type == LDB_REPLY_DONE) {
+ ac->store->controls = talloc_move(ac->store, &ares->controls);
+ talloc_free(ares);
+ }
+
+ return LDB_SUCCESS;
+
+error:
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+static int paged_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_control *control;
+ struct private_data *private_data;
+ struct ldb_paged_control *paged_ctrl;
+ struct ldb_control **saved_controls;
+ struct paged_context *ac;
+ struct ldb_handle *h;
+ int ret;
+
+ /* check if there's a paged request control */
+ control = get_control_from_list(req->controls, LDB_CONTROL_PAGED_RESULTS_OID);
+ if (control == NULL) {
+ /* not found go on */
+ return ldb_next_request(module, req);
+ }
+
+ private_data = talloc_get_type(module->private_data, struct private_data);
+
+ req->handle = NULL;
+
+ if (!req->callback || !req->context) {
+ ldb_set_errstring(module->ldb,
+ "Async interface called with NULL callback function or NULL context");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ paged_ctrl = talloc_get_type(control->data, struct ldb_paged_control);
+ if (!paged_ctrl) {
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ h = init_handle(req, module, req->context, req->callback);
+ if (!h) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac = talloc_get_type(h->private_data, struct paged_context);
+
+ ac->size = paged_ctrl->size;
+
+ /* check if it is a continuation search the store */
+ if (paged_ctrl->cookie_len == 0) {
+
+ ac->store = new_store(private_data);
+ if (ac->store == NULL) {
+ talloc_free(h);
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ ac->store->req = talloc(ac->store, struct ldb_request);
+ if (!ac->store->req)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ ac->store->req->operation = req->operation;
+ ac->store->req->op.search.base = req->op.search.base;
+ ac->store->req->op.search.scope = req->op.search.scope;
+ ac->store->req->op.search.tree = req->op.search.tree;
+ ac->store->req->op.search.attrs = req->op.search.attrs;
+ ac->store->req->controls = req->controls;
+
+ /* save it locally and remove it from the list */
+ /* we do not need to replace them later as we
+ * are keeping the original req intact */
+ if (!save_controls(control, ac->store->req, &saved_controls)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->store->req->context = ac;
+ ac->store->req->callback = paged_search_callback;
+ ldb_set_timeout_from_prev_req(module->ldb, req, ac->store->req);
+
+ ret = ldb_next_request(module, ac->store->req);
+
+ } else {
+ struct results_store *current = NULL;
+
+ for (current = private_data->store; current; current = current->next) {
+ if (strcmp(current->cookie, paged_ctrl->cookie) == 0) {
+ current->timestamp = time(NULL);
+ break;
+ }
+ }
+ if (current == NULL) {
+ talloc_free(h);
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ ac->store = current;
+ ret = LDB_SUCCESS;
+ }
+
+ req->handle = h;
+
+ /* check if it is an abandon */
+ if (ac->size == 0) {
+ talloc_free(ac->store);
+ h->status = LDB_SUCCESS;
+ h->state = LDB_ASYNC_DONE;
+ return LDB_SUCCESS;
+ }
+
+ /* TODO: age out old outstanding requests */
+
+ return ret;
+
+}
+
+static int paged_results(struct ldb_handle *handle)
+{
+ struct paged_context *ac;
+ struct ldb_paged_control *paged;
+ struct ldb_reply *ares;
+ struct message_store *msg;
+ int i, num_ctrls, ret;
+
+ ac = talloc_get_type(handle->private_data, struct paged_context);
+
+ if (ac->store == NULL)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ while (ac->store->num_entries > 0 && ac->size > 0) {
+ msg = ac->store->first;
+ ret = ac->up_callback(ac->module->ldb, ac->up_context, msg->r);
+ if (ret != LDB_SUCCESS) {
+ handle->status = ret;
+ handle->state = LDB_ASYNC_DONE;
+ return ret;
+ }
+
+ ac->store->first = msg->next;
+ talloc_free(msg);
+ ac->store->num_entries--;
+ ac->size--;
+ }
+
+ handle->state = LDB_ASYNC_DONE;
+
+ while (ac->store->first_ref != NULL) {
+ msg = ac->store->first_ref;
+ ret = ac->up_callback(ac->module->ldb, ac->up_context, msg->r);
+ if (ret != LDB_SUCCESS) {
+ handle->status = ret;
+ handle->state = LDB_ASYNC_DONE;
+ return ret;
+ }
+
+ ac->store->first_ref = msg->next;
+ talloc_free(msg);
+ }
+
+ ares = talloc_zero(ac->store, struct ldb_reply);
+ if (ares == NULL) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ return handle->status;
+ }
+ num_ctrls = 2;
+ i = 0;
+
+ if (ac->store->controls != NULL) {
+ ares->controls = ac->store->controls;
+ while (ares->controls[i]) i++; /* counting */
+
+ ares->controls = talloc_move(ares, &ac->store->controls);
+ num_ctrls += i;
+ }
+
+ ares->controls = talloc_realloc(ares, ares->controls, struct ldb_control *, num_ctrls);
+ if (ares->controls == NULL) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ return handle->status;
+ }
+
+ ares->controls[i] = talloc(ares->controls, struct ldb_control);
+ if (ares->controls[i] == NULL) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ return handle->status;
+ }
+
+ ares->controls[i]->oid = talloc_strdup(ares->controls[i], LDB_CONTROL_PAGED_RESULTS_OID);
+ if (ares->controls[i]->oid == NULL) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ return handle->status;
+ }
+
+ ares->controls[i]->critical = 0;
+ ares->controls[i + 1] = NULL;
+
+ paged = talloc(ares->controls[i], struct ldb_paged_control);
+ if (paged == NULL) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ return handle->status;
+ }
+
+ ares->controls[i]->data = paged;
+
+ if (ac->size > 0) {
+ paged->size = 0;
+ paged->cookie = NULL;
+ paged->cookie_len = 0;
+ } else {
+ paged->size = ac->store->num_entries;
+ paged->cookie = talloc_strdup(paged, ac->store->cookie);
+ paged->cookie_len = strlen(paged->cookie) + 1;
+ }
+
+ ares->type = LDB_REPLY_DONE;
+
+ ret = ac->up_callback(ac->module->ldb, ac->up_context, ares);
+
+ handle->status = ret;
+
+ return ret;
+}
+
+static int paged_wait(struct ldb_handle *handle, enum ldb_wait_type type)
+{
+ struct paged_context *ac;
+ int ret;
+
+ if (!handle || !handle->private_data) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (handle->state == LDB_ASYNC_DONE) {
+ return handle->status;
+ }
+
+ handle->state = LDB_ASYNC_PENDING;
+
+ ac = talloc_get_type(handle->private_data, struct paged_context);
+
+ if (ac->store->req->handle->state == LDB_ASYNC_DONE) {
+ /* if lower level is finished we do not need to call it anymore */
+ /* return all we have until size == 0 or we empty storage */
+ ret = paged_results(handle);
+
+ /* we are done, if num_entries is zero free the storage
+ * as that mean we delivered the last batch */
+ if (ac->store->num_entries == 0) {
+ talloc_free(ac->store);
+ }
+
+ return ret;
+ }
+
+ if (type == LDB_WAIT_ALL) {
+ while (ac->store->req->handle->state != LDB_ASYNC_DONE) {
+ ret = ldb_wait(ac->store->req->handle, type);
+ if (ret != LDB_SUCCESS) {
+ handle->state = LDB_ASYNC_DONE;
+ handle->status = ret;
+ return ret;
+ }
+ }
+
+ ret = paged_results(handle);
+
+ /* we are done, if num_entries is zero free the storage
+ * as that mean we delivered the last batch */
+ if (ac->store->num_entries == 0) {
+ talloc_free(ac->store);
+ }
+
+ return ret;
+ }
+
+ ret = ldb_wait(ac->store->req->handle, type);
+ if (ret != LDB_SUCCESS) {
+ handle->state = LDB_ASYNC_DONE;
+ handle->status = ret;
+ return ret;
+ }
+
+ handle->status = ret;
+
+ if (ac->store->num_entries >= ac->size ||
+ ac->store->req->handle->state == LDB_ASYNC_DONE) {
+
+ ret = paged_results(handle);
+
+ /* we are done, if num_entries is zero free the storage
+ * as that mean we delivered the last batch */
+ if (ac->store->num_entries == 0) {
+ talloc_free(ac->store);
+ }
+ }
+
+ return ret;
+}
+
+static int paged_request_init(struct ldb_module *module)
+{
+ struct private_data *data;
+ struct ldb_request *req;
+ int ret;
+
+ data = talloc(module, struct private_data);
+ if (data == NULL) {
+ return LDB_ERR_OTHER;
+ }
+
+ data->next_free_id = 1;
+ data->store = NULL;
+ module->private_data = data;
+
+ req = talloc(module, struct ldb_request);
+ if (req == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_REQ_REGISTER_CONTROL;
+ req->op.reg_control.oid = LDB_CONTROL_PAGED_RESULTS_OID;
+ req->controls = NULL;
+
+ ret = ldb_request(module->ldb, req);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING, "paged_request: Unable to register control with rootdse!\n");
+ }
+
+ talloc_free(req);
+ return ldb_next_init(module);
+}
+
+static const struct ldb_module_ops paged_ops = {
+ .name = "paged_results",
+ .search = paged_search,
+ .wait = paged_wait,
+ .init_context = paged_request_init
+};
+
+int ldb_paged_results_init(void)
+{
+ return ldb_register_module(&paged_ops);
+}
+
diff --git a/source3/lib/ldb/modules/paged_searches.c b/source3/lib/ldb/modules/paged_searches.c
new file mode 100644
index 0000000000..99085d2764
--- /dev/null
+++ b/source3/lib/ldb/modules/paged_searches.c
@@ -0,0 +1,467 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005-2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: paged_searches
+ *
+ * Component: ldb paged searches module
+ *
+ * Description: this module detects if the remote ldap server supports
+ * paged results and use them to transparently access all objects
+ *
+ * Author: Simo Sorce
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#define PS_DEFAULT_PAGE_SIZE 500
+/* 500 objects per query seem to be a decent compromise
+ * the default AD limit per request is 1000 entries */
+
+struct private_data {
+
+ bool paged_supported;
+};
+
+struct ps_context {
+ struct ldb_module *module;
+ void *up_context;
+ int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
+
+ struct ldb_request *orig_req;
+
+ struct ldb_request *new_req;
+
+ bool pending;
+
+ char **saved_referrals;
+ int num_referrals;
+};
+
+static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module,
+ void *context,
+ int (*callback)(struct ldb_context *, void *, struct ldb_reply *))
+{
+ struct ps_context *ac;
+ struct ldb_handle *h;
+
+ h = talloc_zero(mem_ctx, struct ldb_handle);
+ if (h == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ return NULL;
+ }
+
+ h->module = module;
+
+ ac = talloc_zero(h, struct ps_context);
+ if (ac == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ talloc_free(h);
+ return NULL;
+ }
+
+ h->private_data = (void *)ac;
+
+ h->state = LDB_ASYNC_INIT;
+ h->status = LDB_SUCCESS;
+
+ ac->module = module;
+ ac->up_context = context;
+ ac->up_callback = callback;
+
+ ac->pending = False;
+ ac->saved_referrals = NULL;
+ ac->num_referrals = 0;
+
+ return h;
+}
+
+static int check_ps_continuation(struct ldb_reply *ares, struct ps_context *ac)
+{
+ struct ldb_paged_control *rep_control, *req_control;
+
+ /* look up our paged control */
+ if (!ares->controls || strcmp(LDB_CONTROL_PAGED_RESULTS_OID, ares->controls[0]->oid) != 0) {
+ /* something wrong here */
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ rep_control = talloc_get_type(ares->controls[0]->data, struct ldb_paged_control);
+ if (rep_control->cookie_len == 0) {
+ /* we are done */
+ ac->pending = False;
+ return LDB_SUCCESS;
+ }
+
+ /* more processing required */
+ /* let's fill in the request control with the new cookie */
+ /* if there's a reply control we must find a request
+ * control matching it */
+
+ if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, ac->new_req->controls[0]->oid) != 0) {
+ /* something wrong here */
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req_control = talloc_get_type(ac->new_req->controls[0]->data, struct ldb_paged_control);
+
+ if (req_control->cookie) {
+ talloc_free(req_control->cookie);
+ }
+
+ req_control->cookie = talloc_memdup(req_control,
+ rep_control->cookie,
+ rep_control->cookie_len);
+ req_control->cookie_len = rep_control->cookie_len;
+
+ ac->pending = True;
+ return LDB_SUCCESS;
+}
+
+static int store_referral(char *referral, struct ps_context *ac)
+{
+ ac->saved_referrals = talloc_realloc(ac, ac->saved_referrals, char *, ac->num_referrals + 2);
+ if (!ac->saved_referrals) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->saved_referrals[ac->num_referrals] = talloc_strdup(ac->saved_referrals, referral);
+ if (!ac->saved_referrals[ac->num_referrals]) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->num_referrals++;
+ ac->saved_referrals[ac->num_referrals] = NULL;
+
+ return LDB_SUCCESS;
+}
+
+static int send_referrals(struct ldb_context *ldb, struct ps_context *ac)
+{
+ struct ldb_reply *ares;
+ int i;
+
+ for (i = 0; i < ac->num_referrals; i++) {
+ ares = talloc_zero(ac, struct ldb_reply);
+ if (!ares) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ares->type = LDB_REPLY_REFERRAL;
+ ares->referral = ac->saved_referrals[i];
+
+ ac->up_callback(ldb, ac->up_context, ares);
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int ps_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+{
+ struct ps_context *ac = NULL;
+ int ret = LDB_ERR_OPERATIONS_ERROR;
+
+ if (!context || !ares) {
+ ldb_set_errstring(ldb, "NULL Context or Result in callback");
+ goto error;
+ }
+
+ ac = talloc_get_type(context, struct ps_context);
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ ac->up_callback(ldb, ac->up_context, ares);
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ ret = store_referral(ares->referral, ac);
+ if (ret != LDB_SUCCESS) {
+ goto error;
+ }
+ break;
+
+ case LDB_REPLY_DONE:
+ ret = check_ps_continuation(ares, ac);
+ if (ret != LDB_SUCCESS) {
+ goto error;
+ }
+ if (!ac->pending) {
+ /* send referrals */
+ ret = send_referrals(ldb, ac);
+ if (ret != LDB_SUCCESS) {
+ goto error;
+ }
+
+ /* send REPLY_DONE */
+ ac->up_callback(ldb, ac->up_context, ares);
+ }
+ break;
+ default:
+ goto error;
+ }
+
+ return LDB_SUCCESS;
+
+error:
+ talloc_free(ares);
+ return ret;
+}
+
+static int ps_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct private_data *private_data;
+ struct ldb_paged_control *control;
+ struct ps_context *ac;
+ struct ldb_handle *h;
+
+ private_data = talloc_get_type(module->private_data, struct private_data);
+
+ /* check if paging is supported and if there is a any control */
+ if (!private_data || !private_data->paged_supported || req->controls) {
+ /* do not touch this request paged controls not
+ * supported or explicit controls have been set or we
+ * are just not setup yet */
+ return ldb_next_request(module, req);
+ }
+
+ if (!req->callback || !req->context) {
+ ldb_set_errstring(module->ldb,
+ "Async interface called with NULL callback function or NULL context");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ h = init_handle(req, module, req->context, req->callback);
+ if (!h) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac = talloc_get_type(h->private_data, struct ps_context);
+
+ ac->new_req = talloc(ac, struct ldb_request);
+ if (!ac->new_req) return LDB_ERR_OPERATIONS_ERROR;
+
+ ac->new_req->controls = talloc_array(ac->new_req, struct ldb_control *, 2);
+ if (!ac->new_req->controls) return LDB_ERR_OPERATIONS_ERROR;
+
+ ac->new_req->controls[0] = talloc(ac->new_req->controls, struct ldb_control);
+ if (!ac->new_req->controls[0]) return LDB_ERR_OPERATIONS_ERROR;
+
+ control = talloc(ac->new_req->controls[0], struct ldb_paged_control);
+ if (!control) return LDB_ERR_OPERATIONS_ERROR;
+
+ control->size = PS_DEFAULT_PAGE_SIZE;
+ control->cookie = NULL;
+ control->cookie_len = 0;
+
+ ac->new_req->controls[0]->oid = LDB_CONTROL_PAGED_RESULTS_OID;
+ ac->new_req->controls[0]->critical = 1;
+ ac->new_req->controls[0]->data = control;
+
+ ac->new_req->controls[1] = NULL;
+
+ ac->new_req->operation = req->operation;
+ ac->new_req->op.search.base = req->op.search.base;
+ ac->new_req->op.search.scope = req->op.search.scope;
+ ac->new_req->op.search.tree = req->op.search.tree;
+ ac->new_req->op.search.attrs = req->op.search.attrs;
+ ac->new_req->context = ac;
+ ac->new_req->callback = ps_callback;
+ ldb_set_timeout_from_prev_req(module->ldb, req, ac->new_req);
+
+ req->handle = h;
+
+ return ldb_next_request(module, ac->new_req);
+}
+
+static int ps_continuation(struct ldb_handle *handle)
+{
+ struct ps_context *ac;
+
+ if (!handle || !handle->private_data) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac = talloc_get_type(handle->private_data, struct ps_context);
+
+ /* reset the requests handle */
+ ac->new_req->handle = NULL;
+
+ return ldb_next_request(handle->module, ac->new_req);
+}
+
+static int ps_wait_none(struct ldb_handle *handle)
+{
+ struct ps_context *ac;
+ int ret;
+
+ if (!handle || !handle->private_data) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (handle->state == LDB_ASYNC_DONE) {
+ return handle->status;
+ }
+
+ handle->state = LDB_ASYNC_PENDING;
+ handle->status = LDB_SUCCESS;
+
+ ac = talloc_get_type(handle->private_data, struct ps_context);
+
+ ret = ldb_wait(ac->new_req->handle, LDB_WAIT_NONE);
+
+ if (ret != LDB_SUCCESS) {
+ handle->status = ret;
+ goto done;
+ }
+
+ if (ac->new_req->handle->status != LDB_SUCCESS) {
+ handle->status = ac->new_req->handle->status;
+ goto done;
+ }
+
+ if (ac->new_req->handle->state != LDB_ASYNC_DONE) {
+ return LDB_SUCCESS;
+ }
+
+ /* see if we need to send another request for the next batch */
+ if (ac->pending) {
+ ret = ps_continuation(handle);
+ if (ret != LDB_SUCCESS) {
+ handle->status = ret;
+ goto done;
+ }
+
+ /* continue the search with the next request */
+ return LDB_SUCCESS;
+ }
+
+ ret = LDB_SUCCESS;
+
+done:
+ handle->state = LDB_ASYNC_DONE;
+ return ret;
+}
+
+static int ps_wait_all(struct ldb_handle *handle)
+{
+ int ret;
+
+ while (handle->state != LDB_ASYNC_DONE) {
+ ret = ps_wait_none(handle);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ return handle->status;
+}
+
+static int ps_wait(struct ldb_handle *handle, enum ldb_wait_type type)
+{
+ if (type == LDB_WAIT_ALL) {
+ return ps_wait_all(handle);
+ } else {
+ return ps_wait_none(handle);
+ }
+}
+
+static int check_supported_paged(struct ldb_context *ldb, void *context,
+ struct ldb_reply *ares)
+{
+ struct private_data *data;
+ data = talloc_get_type(context,
+ struct private_data);
+ if (ares->type == LDB_REPLY_ENTRY) {
+ if (ldb_msg_check_string_attribute(ares->message,
+ "supportedControl",
+ LDB_CONTROL_PAGED_RESULTS_OID)) {
+ data->paged_supported = True;
+ }
+ }
+ return LDB_SUCCESS;
+}
+
+
+static int ps_init(struct ldb_module *module)
+{
+ static const char *attrs[] = { "supportedControl", NULL };
+ struct private_data *data;
+ int ret;
+ struct ldb_request *req;
+
+ data = talloc(module, struct private_data);
+ if (data == NULL) {
+ return LDB_ERR_OTHER;
+ }
+ module->private_data = data;
+ data->paged_supported = False;
+
+ req = talloc(module, struct ldb_request);
+ if (req == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_SEARCH;
+ req->op.search.base = ldb_dn_new(req);
+ req->op.search.scope = LDB_SCOPE_BASE;
+
+ req->op.search.tree = ldb_parse_tree(req, "objectClass=*");
+ if (req->op.search.tree == NULL) {
+ ldb_set_errstring(module->ldb, "Unable to parse search expression");
+ talloc_free(req);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->op.search.attrs = attrs;
+ req->controls = NULL;
+ req->context = data;
+ req->callback = check_supported_paged;
+ ldb_set_timeout(module->ldb, req, 0); /* use default timeout */
+
+ ret = ldb_next_request(module, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+ talloc_free(req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ return ldb_next_init(module);
+}
+
+static const struct ldb_module_ops ps_ops = {
+ .name = "paged_searches",
+ .search = ps_search,
+ .wait = ps_wait,
+ .init_context = ps_init
+};
+
+int ldb_paged_searches_init(void)
+{
+ return ldb_register_module(&ps_ops);
+}
+
diff --git a/source3/lib/ldb/modules/rdn_name.c b/source3/lib/ldb/modules/rdn_name.c
new file mode 100644
index 0000000000..af2d77d41f
--- /dev/null
+++ b/source3/lib/ldb/modules/rdn_name.c
@@ -0,0 +1,342 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Bartlet 2005
+ Copyright (C) Simo Sorce 2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: rdb_name
+ *
+ * Component: ldb rdn name module
+ *
+ * Description: keep a consistent name attribute on objects manpulations
+ *
+ * Author: Andrew Bartlet
+ *
+ * Modifications:
+ * - made the module async
+ * Simo Sorce Mar 2006
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+static struct ldb_message_element *rdn_name_find_attribute(const struct ldb_message *msg, const char *name)
+{
+ int i;
+
+ for (i = 0; i < msg->num_elements; i++) {
+ if (ldb_attr_cmp(name, msg->elements[i].name) == 0) {
+ return &msg->elements[i];
+ }
+ }
+
+ return NULL;
+}
+
+static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_request *down_req;
+ struct ldb_message *msg;
+ struct ldb_message_element *attribute;
+ const char *rdn_name;
+ struct ldb_val rdn_val;
+ int i, ret;
+
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_add_record\n");
+
+ /* do not manipulate our control entries */
+ if (ldb_dn_is_special(req->op.add.message->dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ down_req = talloc(req, struct ldb_request);
+ if (down_req == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *down_req = *req;
+
+ down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ rdn_name = ldb_dn_get_rdn_name(msg->dn);
+ if (rdn_name == NULL) {
+ talloc_free(down_req);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(msg->dn));
+
+ /* Perhaps someone above us tried to set this? */
+ if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) {
+ attribute->num_values = 0;
+ }
+
+ if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) {
+ talloc_free(down_req);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ attribute = rdn_name_find_attribute(msg, rdn_name);
+
+ if (!attribute) {
+ if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) {
+ talloc_free(down_req);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ } else {
+ const struct ldb_attrib_handler *handler = ldb_attrib_handler(module->ldb, rdn_name);
+
+ for (i = 0; i < attribute->num_values; i++) {
+ if (handler->comparison_fn(module->ldb, msg, &rdn_val, &attribute->values[i]) == 0) {
+ /* overwrite so it matches in case */
+ attribute->values[i] = rdn_val;
+ break;
+ }
+ }
+ if (i == attribute->num_values) {
+ ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
+ "RDN mismatch on %s: %s (%s)",
+ ldb_dn_linearize(msg, msg->dn), rdn_name, rdn_val.data);
+ talloc_free(down_req);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ /* go on with the call chain */
+ ret = ldb_next_request(module, down_req);
+
+ /* do not free down_req as the call results may be linked to it,
+ * it will be freed when the upper level request get freed */
+ if (ret == LDB_SUCCESS) {
+ req->handle = down_req->handle;
+ }
+
+ return ret;
+}
+
+struct rename_context {
+
+ enum {RENAME_RENAME, RENAME_MODIFY} step;
+ struct ldb_request *orig_req;
+ struct ldb_request *down_req;
+ struct ldb_request *mod_req;
+};
+
+static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_handle *h;
+ struct rename_context *ac;
+
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_rename\n");
+
+ /* do not manipulate our control entries */
+ if (ldb_dn_is_special(req->op.rename.newdn)) {
+ return ldb_next_request(module, req);
+ }
+
+ h = talloc_zero(req, struct ldb_handle);
+ if (h == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ h->module = module;
+
+ ac = talloc_zero(h, struct rename_context);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ h->private_data = (void *)ac;
+
+ h->state = LDB_ASYNC_INIT;
+ h->status = LDB_SUCCESS;
+
+ ac->orig_req = req;
+ ac->down_req = talloc(req, struct ldb_request);
+ if (ac->down_req == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *(ac->down_req) = *req;
+
+ ac->step = RENAME_RENAME;
+
+ req->handle = h;
+
+ /* rename first, modify "name" if rename is ok */
+ return ldb_next_request(module, ac->down_req);
+}
+
+static int rdn_name_rename_do_mod(struct ldb_handle *h) {
+
+ struct rename_context *ac;
+ const char *rdn_name;
+ struct ldb_val rdn_val;
+ struct ldb_message *msg;
+
+ ac = talloc_get_type(h->private_data, struct rename_context);
+
+ ac->mod_req = talloc_zero(ac, struct ldb_request);
+
+ ac->mod_req->operation = LDB_MODIFY;
+ ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->dn = ldb_dn_copy(msg, ac->orig_req->op.rename.newdn);
+ if (msg->dn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ rdn_name = ldb_dn_get_rdn_name(ac->orig_req->op.rename.newdn);
+ if (rdn_name == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(ac->orig_req->op.rename.newdn));
+
+ if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ldb_set_timeout_from_prev_req(h->module->ldb, ac->orig_req, ac->mod_req);
+
+ ac->step = RENAME_MODIFY;
+
+ /* do the mod call */
+ return ldb_request(h->module->ldb, ac->mod_req);
+}
+
+static int rename_wait(struct ldb_handle *handle)
+{
+ struct rename_context *ac;
+ int ret;
+
+ if (!handle || !handle->private_data) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (handle->state == LDB_ASYNC_DONE) {
+ return handle->status;
+ }
+
+ handle->state = LDB_ASYNC_PENDING;
+ handle->status = LDB_SUCCESS;
+
+ ac = talloc_get_type(handle->private_data, struct rename_context);
+
+ switch(ac->step) {
+ case RENAME_RENAME:
+ ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
+ if (ret != LDB_SUCCESS) {
+ handle->status = ret;
+ goto done;
+ }
+ if (ac->down_req->handle->status != LDB_SUCCESS) {
+ handle->status = ac->down_req->handle->status;
+ goto done;
+ }
+
+ if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
+ return LDB_SUCCESS;
+ }
+
+ /* rename operation done */
+ return rdn_name_rename_do_mod(handle);
+
+ case RENAME_MODIFY:
+ ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE);
+ if (ret != LDB_SUCCESS) {
+ handle->status = ret;
+ goto done;
+ }
+ if (ac->mod_req->handle->status != LDB_SUCCESS) {
+ handle->status = ac->mod_req->handle->status;
+ goto done;
+ }
+
+ if (ac->mod_req->handle->state != LDB_ASYNC_DONE) {
+ return LDB_SUCCESS;
+ }
+
+ break;
+
+ default:
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ ret = LDB_SUCCESS;
+
+done:
+ handle->state = LDB_ASYNC_DONE;
+ return ret;
+}
+
+static int rename_wait_all(struct ldb_handle *handle) {
+
+ int ret;
+
+ while (handle->state != LDB_ASYNC_DONE) {
+ ret = rename_wait(handle);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ return handle->status;
+}
+
+static int rdn_name_wait(struct ldb_handle *handle, enum ldb_wait_type type)
+{
+ if (type == LDB_WAIT_ALL) {
+ return rename_wait_all(handle);
+ } else {
+ return rename_wait(handle);
+ }
+}
+
+static const struct ldb_module_ops rdn_name_ops = {
+ .name = "rdn_name",
+ .add = rdn_name_add,
+ .rename = rdn_name_rename,
+ .wait = rdn_name_wait
+};
+
+
+int ldb_rdn_name_init(void)
+{
+ return ldb_register_module(&rdn_name_ops);
+}
diff --git a/source3/lib/ldb/modules/skel.c b/source3/lib/ldb/modules/skel.c
new file mode 100644
index 0000000000..be3cefc84e
--- /dev/null
+++ b/source3/lib/ldb/modules/skel.c
@@ -0,0 +1,136 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb skel module
+ *
+ * Description: example module
+ *
+ * Author: Simo Sorce
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+struct private_data {
+
+ char *some_private_data;
+};
+
+/* search */
+static int skel_search(struct ldb_module *module, struct ldb_request *req)
+{
+ return ldb_next_request(module, req);
+}
+
+/* add */
+static int skel_add(struct ldb_module *module, struct ldb_request *req){
+ return ldb_next_request(module, req);
+}
+
+/* modify */
+static int skel_modify(struct ldb_module *module, struct ldb_request *req)
+{
+ return ldb_next_request(module, req);
+}
+
+/* delete */
+static int skel_delete(struct ldb_module *module, struct ldb_request *req)
+{
+ return ldb_next_request(module, req);
+}
+
+/* rename */
+static int skel_rename(struct ldb_module *module, struct ldb_request *req)
+{
+ return ldb_next_request(module, req);
+}
+
+/* start a transaction */
+static int skel_start_trans(struct ldb_module *module)
+{
+ return ldb_next_start_trans(module);
+}
+
+/* end a transaction */
+static int skel_end_trans(struct ldb_module *module)
+{
+ return ldb_next_end_trans(module);
+}
+
+/* delete a transaction */
+static int skel_del_trans(struct ldb_module *module)
+{
+ return ldb_next_del_trans(module);
+}
+
+static int skel_destructor(struct ldb_module *ctx)
+{
+ struct private_data *data = talloc_get_type(ctx->private_data, struct private_data);
+ /* put your clean-up functions here */
+ if (data->some_private_data) talloc_free(data->some_private_data);
+ return 0;
+}
+
+static int skel_request(struct ldb_module *module, struct ldb_request *req)
+{
+ return ldb_next_request(module, req);
+}
+
+static int skel_init(struct ldb_module *ctx)
+{
+ struct private_data *data;
+
+ data = talloc(ctx, struct private_data);
+ if (data == NULL) {
+ return 1;
+ }
+
+ data->some_private_data = NULL;
+ ctx->private_data = data;
+
+ talloc_set_destructor (ctx, skel_destructor);
+
+ return ldb_next_init(ctx);
+}
+
+static const struct ldb_module_ops skel_ops = {
+ .name = "skel",
+ .init_context = skel_init,
+ .search = skel_search,
+ .add = skel_add,
+ .modify = skel_modify,
+ .del = skel_delete,
+ .rename = skel_rename,
+ .request = skel_request,
+ .start_transaction = skel_start_trans,
+ .end_transaction = skel_end_trans,
+ .del_transaction = skel_del_trans,
+};
+
+int ldb_skel_init(void)
+{
+ return ldb_register_module(&skel_ops);
+}
diff --git a/source3/lib/ldb/modules/sort.c b/source3/lib/ldb/modules/sort.c
new file mode 100644
index 0000000000..9d82cae544
--- /dev/null
+++ b/source3/lib/ldb/modules/sort.c
@@ -0,0 +1,442 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb server side sort control module
+ *
+ * Description: this module sorts the results of a search
+ *
+ * Author: Simo Sorce
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+struct opaque {
+ struct ldb_context *ldb;
+ const struct ldb_attrib_handler *h;
+ const char *attribute;
+ int reverse;
+ int result;
+};
+
+struct sort_context {
+ struct ldb_module *module;
+ void *up_context;
+ int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
+
+ char *attributeName;
+ char *orderingRule;
+ int reverse;
+
+ struct ldb_request *req;
+ struct ldb_message **msgs;
+ char **referrals;
+ struct ldb_control **controls;
+ int num_msgs;
+ int num_refs;
+
+ const struct ldb_attrib_handler *h;
+ int sort_result;
+};
+
+static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module,
+ void *context,
+ int (*callback)(struct ldb_context *, void *, struct ldb_reply *))
+{
+ struct sort_context *ac;
+ struct ldb_handle *h;
+
+ h = talloc_zero(mem_ctx, struct ldb_handle);
+ if (h == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ return NULL;
+ }
+
+ h->module = module;
+
+ ac = talloc_zero(h, struct sort_context);
+ if (ac == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ talloc_free(h);
+ return NULL;
+ }
+
+ h->private_data = (void *)ac;
+
+ h->state = LDB_ASYNC_INIT;
+ h->status = LDB_SUCCESS;
+
+ ac->module = module;
+ ac->up_context = context;
+ ac->up_callback = callback;
+
+ return h;
+}
+
+static int build_response(void *mem_ctx, struct ldb_control ***ctrls, int result, const char *desc)
+{
+ struct ldb_control **controls;
+ struct ldb_sort_resp_control *resp;
+ int i;
+
+ if (*ctrls) {
+ controls = *ctrls;
+ for (i = 0; controls[i]; i++);
+ controls = talloc_realloc(mem_ctx, controls, struct ldb_control *, i + 2);
+ } else {
+ i = 0;
+ controls = talloc_array(mem_ctx, struct ldb_control *, 2);
+ }
+ if (! controls )
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ *ctrls = controls;
+
+ controls[i+1] = NULL;
+ controls[i] = talloc(controls, struct ldb_control);
+ if (! controls[i] )
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ controls[i]->oid = LDB_CONTROL_SORT_RESP_OID;
+ controls[i]->critical = 0;
+
+ resp = talloc(controls[i], struct ldb_sort_resp_control);
+ if (! resp )
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ resp->result = result;
+ resp->attr_desc = talloc_strdup(resp, desc);
+
+ if (! resp->attr_desc )
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ controls[i]->data = resp;
+
+ return LDB_SUCCESS;
+}
+
+static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, void *opaque)
+{
+ struct sort_context *ac = talloc_get_type(opaque, struct sort_context);
+ struct ldb_message_element *el1, *el2;
+
+ if (ac->sort_result != 0) {
+ /* an error occurred previously,
+ * let's exit the sorting by returning always 0 */
+ return 0;
+ }
+
+ el1 = ldb_msg_find_element(*msg1, ac->attributeName);
+ el2 = ldb_msg_find_element(*msg2, ac->attributeName);
+
+ if (!el1 || !el2) {
+ /* the attribute was not found return and
+ * set an error */
+ ac->sort_result = 53;
+ return 0;
+ }
+
+ if (ac->reverse)
+ return ac->h->comparison_fn(ac->module->ldb, ac, &el2->values[0], &el1->values[0]);
+
+ return ac->h->comparison_fn(ac->module->ldb, ac, &el1->values[0], &el2->values[0]);
+}
+
+static int server_sort_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+{
+ struct sort_context *ac = NULL;
+
+ if (!context || !ares) {
+ ldb_set_errstring(ldb, "NULL Context or Result in callback");
+ goto error;
+ }
+
+ ac = talloc_get_type(context, struct sort_context);
+
+ if (ares->type == LDB_REPLY_ENTRY) {
+ ac->msgs = talloc_realloc(ac, ac->msgs, struct ldb_message *, ac->num_msgs + 2);
+ if (! ac->msgs) {
+ goto error;
+ }
+
+ ac->msgs[ac->num_msgs + 1] = NULL;
+
+ ac->msgs[ac->num_msgs] = talloc_move(ac->msgs, &ares->message);
+ ac->num_msgs++;
+ }
+
+ if (ares->type == LDB_REPLY_REFERRAL) {
+ ac->referrals = talloc_realloc(ac, ac->referrals, char *, ac->num_refs + 2);
+ if (! ac->referrals) {
+ goto error;
+ }
+
+ ac->referrals[ac->num_refs + 1] = NULL;
+ ac->referrals[ac->num_refs] = talloc_move(ac->referrals, &ares->referral);
+
+ ac->num_refs++;
+ }
+
+ if (ares->type == LDB_REPLY_DONE) {
+ ac->controls = talloc_move(ac, &ares->controls);
+ }
+
+ talloc_free(ares);
+ return LDB_SUCCESS;
+
+error:
+ talloc_free(ares);
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+static int server_sort_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_control *control;
+ struct ldb_server_sort_control **sort_ctrls;
+ struct ldb_control **saved_controls;
+ struct sort_context *ac;
+ struct ldb_handle *h;
+ int ret;
+
+ /* check if there's a paged request control */
+ control = get_control_from_list(req->controls, LDB_CONTROL_SERVER_SORT_OID);
+ if (control == NULL) {
+ /* not found go on */
+ return ldb_next_request(module, req);
+ }
+
+ req->handle = NULL;
+
+ if (!req->callback || !req->context) {
+ ldb_set_errstring(module->ldb,
+ "Async interface called with NULL callback function or NULL context");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ h = init_handle(req, module, req->context, req->callback);
+ if (!h) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac = talloc_get_type(h->private_data, struct sort_context);
+
+ sort_ctrls = talloc_get_type(control->data, struct ldb_server_sort_control *);
+ if (!sort_ctrls) {
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ /* FIXME: we do not support more than one attribute for sorting right now */
+ /* FIXME: we need to check if the attribute type exist or return an error */
+
+ if (sort_ctrls[1] != NULL) {
+ if (control->critical) {
+ struct ldb_reply *ares;
+
+ ares = talloc_zero(req, struct ldb_reply);
+ if (!ares)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ /* 53 = unwilling to perform */
+ ares->type = LDB_REPLY_DONE;
+ if ((ret = build_response(ares, &ares->controls, 53, "sort control is not complete yet")) != LDB_SUCCESS) {
+ return ret;
+ }
+
+ h->status = LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+ h->state = LDB_ASYNC_DONE;
+ ret = ac->up_callback(module->ldb, ac->up_context, ares);
+
+ return ret;
+ } else {
+ /* just pass the call down and don't do any sorting */
+ ldb_next_request(module, req);
+ }
+ }
+
+ ac->attributeName = sort_ctrls[0]->attributeName;
+ ac->orderingRule = sort_ctrls[0]->orderingRule;
+ ac->reverse = sort_ctrls[0]->reverse;
+
+ ac->req = talloc(req, struct ldb_request);
+ if (!ac->req)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ ac->req->operation = req->operation;
+ ac->req->op.search.base = req->op.search.base;
+ ac->req->op.search.scope = req->op.search.scope;
+ ac->req->op.search.tree = req->op.search.tree;
+ ac->req->op.search.attrs = req->op.search.attrs;
+ ac->req->controls = req->controls;
+
+ /* save it locally and remove it from the list */
+ /* we do not need to replace them later as we
+ * are keeping the original req intact */
+ if (!save_controls(control, ac->req, &saved_controls)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->req->context = ac;
+ ac->req->callback = server_sort_search_callback;
+ ldb_set_timeout_from_prev_req(module->ldb, req, ac->req);
+
+ req->handle = h;
+
+ return ldb_next_request(module, ac->req);
+}
+
+static int server_sort_results(struct ldb_handle *handle)
+{
+ struct sort_context *ac;
+ struct ldb_reply *ares;
+ int i, ret;
+
+ ac = talloc_get_type(handle->private_data, struct sort_context);
+
+ ac->h = ldb_attrib_handler(ac->module->ldb, ac->attributeName);
+ ac->sort_result = 0;
+
+ ldb_qsort(ac->msgs, ac->num_msgs,
+ sizeof(struct ldb_message *),
+ ac, (ldb_qsort_cmp_fn_t)sort_compare);
+
+ for (i = 0; i < ac->num_msgs; i++) {
+ ares = talloc_zero(ac, struct ldb_reply);
+ if (!ares) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ return handle->status;
+ }
+
+ ares->type = LDB_REPLY_ENTRY;
+ ares->message = talloc_move(ares, &ac->msgs[i]);
+
+ handle->status = ac->up_callback(ac->module->ldb, ac->up_context, ares);
+ if (handle->status != LDB_SUCCESS) {
+ return handle->status;
+ }
+ }
+
+ for (i = 0; i < ac->num_refs; i++) {
+ ares = talloc_zero(ac, struct ldb_reply);
+ if (!ares) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ return handle->status;
+ }
+
+ ares->type = LDB_REPLY_REFERRAL;
+ ares->referral = talloc_move(ares, &ac->referrals[i]);
+
+ handle->status = ac->up_callback(ac->module->ldb, ac->up_context, ares);
+ if (handle->status != LDB_SUCCESS) {
+ return handle->status;
+ }
+ }
+
+ ares = talloc_zero(ac, struct ldb_reply);
+ if (!ares) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ return handle->status;
+ }
+
+ ares->type = LDB_REPLY_DONE;
+ ares->controls = talloc_move(ares, &ac->controls);
+
+ handle->status = ac->up_callback(ac->module->ldb, ac->up_context, ares);
+ if (handle->status != LDB_SUCCESS) {
+ return handle->status;
+ }
+
+ if ((ret = build_response(ac, &ac->controls, ac->sort_result, "sort control is not complete yet")) != LDB_SUCCESS) {
+ return ret;
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int server_sort_wait(struct ldb_handle *handle, enum ldb_wait_type type)
+{
+ struct sort_context *ac;
+ int ret;
+
+ if (!handle || !handle->private_data) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac = talloc_get_type(handle->private_data, struct sort_context);
+
+ ret = ldb_wait(ac->req->handle, type);
+
+ if (ret != LDB_SUCCESS) {
+ handle->status = ret;
+ return ret;
+ }
+
+ handle->state = ac->req->handle->state;
+ handle->status = ac->req->handle->status;
+
+ if (handle->status != LDB_SUCCESS) {
+ return handle->status;
+ }
+
+ if (handle->state == LDB_ASYNC_DONE) {
+ ret = server_sort_results(handle);
+ }
+
+ return ret;
+}
+
+static int server_sort_init(struct ldb_module *module)
+{
+ struct ldb_request *req;
+ int ret;
+
+ req = talloc(module, struct ldb_request);
+ if (req == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_REQ_REGISTER_CONTROL;
+ req->op.reg_control.oid = LDB_CONTROL_SERVER_SORT_OID;
+ req->controls = NULL;
+
+ ret = ldb_request(module->ldb, req);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING, "server_sort: Unable to register control with rootdse!\n");
+ }
+
+ talloc_free(req);
+ return ldb_next_init(module);
+}
+
+static const struct ldb_module_ops server_sort_ops = {
+ .name = "server_sort",
+ .search = server_sort_search,
+ .wait = server_sort_wait,
+ .init_context = server_sort_init
+};
+
+int ldb_sort_init(void)
+{
+ return ldb_register_module(&server_sort_ops);
+}
diff --git a/source3/lib/ldb/nssldb/README.txt b/source3/lib/ldb/nssldb/README.txt
new file mode 100644
index 0000000000..ddba62b380
--- /dev/null
+++ b/source3/lib/ldb/nssldb/README.txt
@@ -0,0 +1,34 @@
+
+This test code requires a tdb that is configured for to use the asq module.
+You can do that adding the following record to a tdb:
+
+dn: @MODULES
+@LIST: asq
+
+Other modules can be used as well (like rdn_name for example)
+
+The uidNumber 0 and the gidNumber 0 are considered invalid.
+
+The user records should contain the followin attributes:
+uid (required) the user name
+userPassword (optional) the user password (if not present "LDB" is
+ returned in the password field)
+uidNumber (required) the user uid
+gidNumber (required) the user primary gid
+gecos (optional) the GECOS
+homeDirectory (required) the home directory
+loginShell (required) the login shell
+memberOf (required) all the groups the user is member of should
+ be reported here using their DNs. The
+ primary group as well.
+
+The group accounts should contain the following attributes:
+cn (required) the group name
+uesrPassword (optional) the group password (if not present "LDB" is
+ returned in the password field)
+gidNumber (required) the group gid
+member (optional) the DNs of the member users, also the ones
+ that have this group as primary
+
+
+SSS
diff --git a/source3/lib/ldb/nssldb/ldb-grp.c b/source3/lib/ldb/nssldb/ldb-grp.c
new file mode 100644
index 0000000000..71e27a9161
--- /dev/null
+++ b/source3/lib/ldb/nssldb/ldb-grp.c
@@ -0,0 +1,425 @@
+/*
+ LDB nsswitch module
+
+ Copyright (C) Simo Sorce 2006
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ldb-nss.h"
+
+extern struct _ldb_nss_context *_ldb_nss_ctx;
+
+const char *_ldb_nss_gr_attrs[] = {
+ "cn",
+ "userPassword",
+ "gidNumber",
+ NULL
+};
+
+const char *_ldb_nss_mem_attrs[] = {
+ "uid",
+ NULL
+};
+
+#define _NSS_LDB_ENOMEM(amem) \
+ do { \
+ if ( ! amem) { \
+ errno = ENOMEM; \
+ talloc_free(memctx); \
+ return NSS_STATUS_UNAVAIL; \
+ } \
+ } while(0)
+
+/* This setgrent, getgrent, endgrent is not very efficient */
+
+NSS_STATUS _nss_ldb_setgrent(void)
+{
+ int ret;
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ _ldb_nss_ctx->gr_cur = 0;
+ if (_ldb_nss_ctx->gr_res != NULL) {
+ talloc_free(_ldb_nss_ctx->gr_res);
+ _ldb_nss_ctx->gr_res = NULL;
+ }
+
+ ret = ldb_search(_ldb_nss_ctx->ldb,
+ _ldb_nss_ctx->base,
+ LDB_SCOPE_SUBTREE,
+ _LDB_NSS_GRENT_FILTER,
+ _ldb_nss_gr_attrs,
+ &_ldb_nss_ctx->gr_res);
+ if (ret != LDB_SUCCESS) {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+NSS_STATUS _nss_ldb_endgrent(void)
+{
+ int ret;
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ _ldb_nss_ctx->gr_cur = 0;
+ if (_ldb_nss_ctx->gr_res) {
+ talloc_free(_ldb_nss_ctx->gr_res);
+ _ldb_nss_ctx->gr_res = NULL;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+NSS_STATUS _nss_ldb_getgrent_r(struct group *result_buf, char *buffer, size_t buflen, int *errnop)
+{
+ int ret;
+ struct ldb_result *res;
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ *errnop = 0;
+
+ if (_ldb_nss_ctx->gr_cur >= _ldb_nss_ctx->gr_res->count) {
+ /* already returned all entries */
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ res = talloc_zero(_ldb_nss_ctx->gr_res, struct ldb_result);
+ if ( ! res) {
+ errno = *errnop = ENOMEM;
+ _ldb_nss_ctx->gr_cur++; /* skip this entry */
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ ret = _ldb_nss_group_request(&res,
+ _ldb_nss_ctx->gr_res->msgs[_ldb_nss_ctx->gr_cur]->dn,
+ _ldb_nss_mem_attrs,
+ "member");
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ *errnop = errno;
+ talloc_free(res);
+ _ldb_nss_ctx->gr_cur++; /* skip this entry */
+ return ret;
+ }
+
+ ret = _ldb_nss_fill_group(result_buf,
+ buffer,
+ buflen,
+ errnop,
+ _ldb_nss_ctx->gr_res->msgs[_ldb_nss_ctx->gr_cur],
+ res);
+
+ talloc_free(res);
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ if (ret != NSS_STATUS_TRYAGAIN) {
+ _ldb_nss_ctx->gr_cur++; /* skip this entry */
+ }
+ return ret;
+ }
+
+ /* this entry is ok, increment counter to nex entry */
+ _ldb_nss_ctx->gr_cur++;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+NSS_STATUS _nss_ldb_getgrnam_r(const char *name, struct group *result_buf, char *buffer, size_t buflen, int *errnop)
+{
+ int ret;
+ char *filter;
+ TALLOC_CTX *ctx;
+ struct ldb_result *gr_res;
+ struct ldb_result *mem_res;
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ ctx = talloc_new(_ldb_nss_ctx->ldb);
+ if ( ! ctx) {
+ *errnop = errno = ENOMEM;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ /* build the filter for this uid */
+ filter = talloc_asprintf(ctx, _LDB_NSS_GRNAM_FILTER, name);
+ if (filter == NULL) {
+ /* this is a fatal error */
+ *errnop = errno = ENOMEM;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* search the entry */
+ ret = ldb_search(_ldb_nss_ctx->ldb,
+ _ldb_nss_ctx->base,
+ LDB_SCOPE_SUBTREE,
+ filter,
+ _ldb_nss_gr_attrs,
+ &gr_res);
+ if (ret != LDB_SUCCESS) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ talloc_steal(ctx, gr_res);
+
+ /* if none found return */
+ if (gr_res->count == 0) {
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ if (gr_res->count != 1) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ mem_res = talloc_zero(ctx, struct ldb_result);
+ if ( ! mem_res) {
+ errno = *errnop = ENOMEM;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ ret = _ldb_nss_group_request(&mem_res,
+ gr_res->msgs[0]->dn,
+ _ldb_nss_mem_attrs,
+ "member");
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ *errnop = errno;
+ goto done;
+ }
+
+ ret = _ldb_nss_fill_group(result_buf,
+ buffer,
+ buflen,
+ errnop,
+ gr_res->msgs[0],
+ mem_res);
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ ret = NSS_STATUS_SUCCESS;
+done:
+ talloc_free(ctx);
+ return ret;
+}
+
+NSS_STATUS _nss_ldb_getgrgid_r(gid_t gid, struct group *result_buf, char *buffer, size_t buflen, int *errnop)
+{
+ int ret;
+ char *filter;
+ TALLOC_CTX *ctx;
+ struct ldb_result *gr_res;
+ struct ldb_result *mem_res;
+
+ if (gid == 0) { /* we don't serve root gid by policy */
+ *errnop = errno = ENOENT;
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ ctx = talloc_new(_ldb_nss_ctx->ldb);
+ if ( ! ctx) {
+ *errnop = errno = ENOMEM;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ /* build the filter for this uid */
+ filter = talloc_asprintf(ctx, _LDB_NSS_GRGID_FILTER, gid);
+ if (filter == NULL) {
+ /* this is a fatal error */
+ *errnop = errno = ENOMEM;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* search the entry */
+ ret = ldb_search(_ldb_nss_ctx->ldb,
+ _ldb_nss_ctx->base,
+ LDB_SCOPE_SUBTREE,
+ filter,
+ _ldb_nss_gr_attrs,
+ &gr_res);
+ if (ret != LDB_SUCCESS) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ talloc_steal(ctx, gr_res);
+
+ /* if none found return */
+ if (gr_res->count == 0) {
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ if (gr_res->count != 1) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ mem_res = talloc_zero(ctx, struct ldb_result);
+ if ( ! mem_res) {
+ errno = *errnop = ENOMEM;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ ret = _ldb_nss_group_request(&mem_res,
+ gr_res->msgs[0]->dn,
+ _ldb_nss_mem_attrs,
+ "member");
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ *errnop = errno;
+ goto done;
+ }
+
+ ret = _ldb_nss_fill_group(result_buf,
+ buffer,
+ buflen,
+ errnop,
+ gr_res->msgs[0],
+ mem_res);
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ ret = NSS_STATUS_SUCCESS;
+done:
+ talloc_free(ctx);
+ return ret;
+}
+
+NSS_STATUS _nss_ldb_initgroups_dyn(const char *user, gid_t group, long int *start, long int *size, gid_t **groups, long int limit, int *errnop)
+{
+ int ret;
+ char *filter;
+ const char * attrs[] = { "uidNumber", "gidNumber", NULL };
+ struct ldb_result *uid_res;
+ struct ldb_result *mem_res;
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ mem_res = talloc_zero(_ldb_nss_ctx, struct ldb_result);
+ if ( ! mem_res) {
+ errno = *errnop = ENOMEM;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ /* build the filter for this name */
+ filter = talloc_asprintf(mem_res, _LDB_NSS_PWNAM_FILTER, user);
+ if (filter == NULL) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* search the entry */
+ ret = ldb_search(_ldb_nss_ctx->ldb,
+ _ldb_nss_ctx->base,
+ LDB_SCOPE_SUBTREE,
+ filter,
+ attrs,
+ &uid_res);
+ if (ret != LDB_SUCCESS) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ talloc_steal(mem_res, uid_res);
+
+ /* if none found return */
+ if (uid_res->count == 0) {
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ if (uid_res->count != 1) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ ret = _ldb_nss_group_request(&mem_res,
+ uid_res->msgs[0]->dn,
+ attrs,
+ "memberOf");
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ *errnop = errno;
+ goto done;
+ }
+
+ ret = _ldb_nss_fill_initgr(group,
+ limit,
+ start,
+ size,
+ groups,
+ errnop,
+ mem_res);
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ ret = NSS_STATUS_SUCCESS;
+
+done:
+ talloc_free(mem_res);
+ return ret;
+}
diff --git a/source3/lib/ldb/nssldb/ldb-nss.c b/source3/lib/ldb/nssldb/ldb-nss.c
new file mode 100644
index 0000000000..0e5850eab3
--- /dev/null
+++ b/source3/lib/ldb/nssldb/ldb-nss.c
@@ -0,0 +1,400 @@
+/*
+ LDB nsswitch module
+
+ Copyright (C) Simo Sorce 2006
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ldb-nss.h"
+
+struct _ldb_nss_context *_ldb_nss_ctx = NULL;
+
+NSS_STATUS _ldb_nss_init(void)
+{
+ int ret;
+
+ pid_t mypid = getpid();
+
+ if (_ldb_nss_ctx != NULL) {
+ if (_ldb_nss_ctx->pid == mypid) {
+ /* already initialized */
+ return NSS_STATUS_SUCCESS;
+ } else {
+ /* we are in a forked child now, reinitialize */
+ talloc_free(_ldb_nss_ctx);
+ _ldb_nss_ctx = NULL;
+ }
+ }
+
+ _ldb_nss_ctx = talloc_named(NULL, 0, "_ldb_nss_ctx(%u)", mypid);
+ if (_ldb_nss_ctx == NULL) {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ _ldb_nss_ctx->pid = mypid;
+
+ ret = ldb_global_init();
+ if (ret != 0) {
+ goto failed;
+ }
+
+ _ldb_nss_ctx->ldb = ldb_init(_ldb_nss_ctx);
+ if (_ldb_nss_ctx->ldb == NULL) {
+ goto failed;
+ }
+
+ ret = ldb_connect(_ldb_nss_ctx->ldb, _LDB_NSS_URL, LDB_FLG_RDONLY, NULL);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ _ldb_nss_ctx->base = ldb_dn_explode(_ldb_nss_ctx, _LDB_NSS_BASEDN);
+ if (_ldb_nss_ctx->base == NULL) {
+ goto failed;
+ }
+
+ _ldb_nss_ctx->pw_cur = 0;
+ _ldb_nss_ctx->pw_res = NULL;
+ _ldb_nss_ctx->gr_cur = 0;
+ _ldb_nss_ctx->gr_res = NULL;
+
+ return NSS_STATUS_SUCCESS;
+
+failed:
+ /* talloc_free(_ldb_nss_ctx); */
+ _ldb_nss_ctx = NULL;
+ return NSS_STATUS_UNAVAIL;
+}
+
+NSS_STATUS _ldb_nss_fill_passwd(struct passwd *result,
+ char *buffer,
+ int buflen,
+ int *errnop,
+ struct ldb_message *msg)
+{
+ int len;
+ int bufpos;
+ const char *tmp;
+
+ bufpos = 0;
+
+ /* get username */
+ tmp = ldb_msg_find_attr_as_string(msg, "uid", NULL);
+ if (tmp == NULL) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ return NSS_STATUS_UNAVAIL;
+ }
+ len = strlen(tmp)+1;
+ if (bufpos + len > buflen) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(&buffer[bufpos], tmp, len);
+ result->pw_name = &buffer[bufpos];
+ bufpos += len;
+
+ /* get userPassword */
+ tmp = ldb_msg_find_attr_as_string(msg, "userPassword", NULL);
+ if (tmp == NULL) {
+ tmp = "LDB";
+ }
+ len = strlen(tmp)+1;
+ if (bufpos + len > buflen) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(&buffer[bufpos], tmp, len);
+ result->pw_passwd = &buffer[bufpos];
+ bufpos += len;
+
+ /* this backend never serves an uid 0 user */
+ result->pw_uid = ldb_msg_find_attr_as_int(msg, "uidNumber", 0);
+ if (result->pw_uid == 0) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ result->pw_gid = ldb_msg_find_attr_as_int(msg, "gidNumber", 0);
+ if (result->pw_gid == 0) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ /* get gecos */
+ tmp = ldb_msg_find_attr_as_string(msg, "gecos", NULL);
+ if (tmp == NULL) {
+ tmp = "";
+ }
+ len = strlen(tmp)+1;
+ if (bufpos + len > buflen) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(&buffer[bufpos], tmp, len);
+ result->pw_gecos = &buffer[bufpos];
+ bufpos += len;
+
+ /* get homeDirectory */
+ tmp = ldb_msg_find_attr_as_string(msg, "homeDirectory", NULL);
+ if (tmp == NULL) {
+ tmp = "";
+ }
+ len = strlen(tmp)+1;
+ if (bufpos + len > buflen) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(&buffer[bufpos], tmp, len);
+ result->pw_dir = &buffer[bufpos];
+ bufpos += len;
+
+ /* get shell */
+ tmp = ldb_msg_find_attr_as_string(msg, "loginShell", NULL);
+ if (tmp == NULL) {
+ tmp = "";
+ }
+ len = strlen(tmp)+1;
+ if (bufpos + len > buflen) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(&buffer[bufpos], tmp, len);
+ result->pw_shell = &buffer[bufpos];
+ bufpos += len;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+NSS_STATUS _ldb_nss_fill_group(struct group *result,
+ char *buffer,
+ int buflen,
+ int *errnop,
+ struct ldb_message *group,
+ struct ldb_result *members)
+{
+ const char *tmp;
+ size_t len;
+ size_t bufpos;
+ size_t lsize;
+ int i;
+
+ bufpos = 0;
+
+ /* get group name */
+ tmp = ldb_msg_find_attr_as_string(group, "cn", NULL);
+ if (tmp == NULL) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ return NSS_STATUS_UNAVAIL;
+ }
+ len = strlen(tmp)+1;
+ if (bufpos + len > buflen) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(&buffer[bufpos], tmp, len);
+ result->gr_name = &buffer[bufpos];
+ bufpos += len;
+
+ /* get userPassword */
+ tmp = ldb_msg_find_attr_as_string(group, "userPassword", NULL);
+ if (tmp == NULL) {
+ tmp = "LDB";
+ }
+ len = strlen(tmp)+1;
+ if (bufpos + len > buflen) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(&buffer[bufpos], tmp, len);
+ result->gr_passwd = &buffer[bufpos];
+ bufpos += len;
+
+ result->gr_gid = ldb_msg_find_attr_as_int(group, "gidNumber", 0);
+ if (result->gr_gid == 0) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ /* check if there is enough memory for the list of pointers */
+ lsize = (members->count + 1) * sizeof(char *);
+
+ /* align buffer on pointer boundary */
+ bufpos += (sizeof(char*) - ((unsigned long)(buffer) % sizeof(char*)));
+ if ((buflen - bufpos) < lsize) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ result->gr_mem = (char **)&buffer[bufpos];
+ bufpos += lsize;
+
+ for (i = 0; i < members->count; i++) {
+ tmp = ldb_msg_find_attr_as_string(members->msgs[i], "uid", NULL);
+ if (tmp == NULL) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ return NSS_STATUS_UNAVAIL;
+ }
+ len = strlen(tmp)+1;
+ if (bufpos + len > buflen) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(&buffer[bufpos], tmp, len);
+ result->gr_mem[i] = &buffer[bufpos];
+ bufpos += len;
+ }
+
+ result->gr_mem[i] = NULL;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+NSS_STATUS _ldb_nss_fill_initgr(gid_t group,
+ long int limit,
+ long int *start,
+ long int *size,
+ gid_t **groups,
+ int *errnop,
+ struct ldb_result *grlist)
+{
+ NSS_STATUS ret;
+ int i;
+
+ for (i = 0; i < grlist->count; i++) {
+
+ if (limit && (*start > limit)) {
+ /* TODO: warn no all groups were reported */
+ *errnop = 0;
+ ret = NSS_STATUS_SUCCESS;
+ goto done;
+ }
+
+ if (*start == *size) {
+ /* buffer full, enlarge it */
+ long int gs;
+ gid_t *gm;
+
+ gs = (*size) + 32;
+ if (limit && (gs > limit)) {
+ gs = limit;
+ }
+
+ gm = (gid_t *)realloc((*groups), gs * sizeof(gid_t));
+ if ( ! gm) {
+ *errnop = ENOMEM;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ *groups = gm;
+ *size = gs;
+ }
+
+ (*groups)[*start] = ldb_msg_find_attr_as_int(grlist->msgs[i], "gidNumber", 0);
+ if ((*groups)[*start] == 0 || (*groups)[*start] == group) {
+ /* skip root group or primary group */
+ continue;
+ }
+ (*start)++;
+
+ }
+
+ *errnop = 0;
+ ret = NSS_STATUS_SUCCESS;
+done:
+ return ret;
+}
+
+#define _LDB_NSS_ALLOC_CHECK(mem) do { if (!mem) { errno = ENOMEM; return NSS_STATUS_UNAVAIL; } } while(0)
+
+NSS_STATUS _ldb_nss_group_request(struct ldb_result **_res,
+ struct ldb_dn *group_dn,
+ const char * const *attrs,
+ const char *mattr)
+{
+ struct ldb_control **ctrls;
+ struct ldb_control *ctrl;
+ struct ldb_asq_control *asqc;
+ struct ldb_request *req;
+ int ret;
+ struct ldb_result *res = *_res;
+
+ ctrls = talloc_array(res, struct ldb_control *, 2);
+ _LDB_NSS_ALLOC_CHECK(ctrls);
+
+ ctrl = talloc(ctrls, struct ldb_control);
+ _LDB_NSS_ALLOC_CHECK(ctrl);
+
+ asqc = talloc(ctrl, struct ldb_asq_control);
+ _LDB_NSS_ALLOC_CHECK(asqc);
+
+ asqc->source_attribute = talloc_strdup(asqc, mattr);
+ _LDB_NSS_ALLOC_CHECK(asqc->source_attribute);
+
+ asqc->request = 1;
+ asqc->src_attr_len = strlen(asqc->source_attribute);
+ ctrl->oid = LDB_CONTROL_ASQ_OID;
+ ctrl->critical = 1;
+ ctrl->data = asqc;
+ ctrls[0] = ctrl;
+ ctrls[1] = NULL;
+
+ ret = ldb_build_search_req(
+ &req,
+ _ldb_nss_ctx->ldb,
+ res,
+ group_dn,
+ LDB_SCOPE_BASE,
+ "(objectClass=*)",
+ attrs,
+ ctrls,
+ res,
+ ldb_search_default_callback);
+
+ if (ret != LDB_SUCCESS) {
+ errno = ENOENT;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ ldb_set_timeout(_ldb_nss_ctx->ldb, req, 0);
+
+ ret = ldb_request(_ldb_nss_ctx->ldb, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ } else {
+ talloc_free(req);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ talloc_free(req);
+ return NSS_STATUS_SUCCESS;
+}
+
diff --git a/source3/lib/ldb/nssldb/ldb-nss.h b/source3/lib/ldb/nssldb/ldb-nss.h
new file mode 100644
index 0000000000..1b1866abb9
--- /dev/null
+++ b/source3/lib/ldb/nssldb/ldb-nss.h
@@ -0,0 +1,84 @@
+/*
+ LDB nsswitch module
+
+ Copyright (C) Simo Sorce 2006
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _LDB_NSS
+#define _LDB_NSS
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#include <nss.h>
+#include <pwd.h>
+#include <grp.h>
+
+#define _LDB_NSS_URL "etc/users.ldb"
+#define _LDB_NSS_BASEDN "CN=Users,CN=System"
+#define _LDB_NSS_PWENT_FILTER "(&(objectClass=posixAccount)(!(uidNumber=0))(!(gidNumber=0)))"
+#define _LDB_NSS_PWUID_FILTER "(&(objectClass=posixAccount)(uidNumber=%d)(!(gidNumber=0)))"
+#define _LDB_NSS_PWNAM_FILTER "(&(objectClass=posixAccount)(uid=%s)(!(uidNumber=0))(!(gidNumber=0)))"
+
+#define _LDB_NSS_GRENT_FILTER "(&(objectClass=posixGroup)(!(gidNumber=0)))"
+#define _LDB_NSS_GRGID_FILTER "(&(objectClass=posixGroup)(gidNumber=%d)))"
+#define _LDB_NSS_GRNAM_FILTER "(&(objectClass=posixGroup)(cn=%s)(!(gidNumber=0)))"
+
+typedef enum nss_status NSS_STATUS;
+
+struct _ldb_nss_context {
+
+ pid_t pid;
+
+ struct ldb_context *ldb;
+ const struct ldb_dn *base;
+
+ int pw_cur;
+ struct ldb_result *pw_res;
+
+ int gr_cur;
+ struct ldb_result *gr_res;
+};
+
+NSS_STATUS _ldb_nss_init(void);
+
+NSS_STATUS _ldb_nss_fill_passwd(struct passwd *result,
+ char *buffer,
+ int buflen,
+ int *errnop,
+ struct ldb_message *msg);
+
+NSS_STATUS _ldb_nss_fill_group(struct group *result,
+ char *buffer,
+ int buflen,
+ int *errnop,
+ struct ldb_message *group,
+ struct ldb_result *members);
+
+NSS_STATUS _ldb_nss_fill_initgr(gid_t group,
+ long int limit,
+ long int *start,
+ long int *size,
+ gid_t **groups,
+ int *errnop,
+ struct ldb_result *grlist);
+
+NSS_STATUS _ldb_nss_group_request(struct ldb_result **res,
+ struct ldb_dn *group_dn,
+ const char * const *attrs,
+ const char *mattr);
+
+#endif /* _LDB_NSS */
diff --git a/source3/lib/ldb/nssldb/ldb-pwd.c b/source3/lib/ldb/nssldb/ldb-pwd.c
new file mode 100644
index 0000000000..44b0ab21ee
--- /dev/null
+++ b/source3/lib/ldb/nssldb/ldb-pwd.c
@@ -0,0 +1,239 @@
+/*
+ LDB nsswitch module
+
+ Copyright (C) Simo Sorce 2006
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ldb-nss.h"
+
+extern struct _ldb_nss_context *_ldb_nss_ctx;
+
+const char *_ldb_nss_pw_attrs[] = {
+ "uid",
+ "userPassword",
+ "uidNumber",
+ "gidNumber",
+ "gecos",
+ "homeDirectory",
+ "loginShell",
+ NULL
+};
+
+NSS_STATUS _nss_ldb_setpwent(void)
+{
+ int ret;
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ _ldb_nss_ctx->pw_cur = 0;
+ if (_ldb_nss_ctx->pw_res != NULL) {
+ talloc_free(_ldb_nss_ctx->pw_res);
+ _ldb_nss_ctx->pw_res = NULL;
+ }
+
+ ret = ldb_search(_ldb_nss_ctx->ldb,
+ _ldb_nss_ctx->base,
+ LDB_SCOPE_SUBTREE,
+ _LDB_NSS_PWENT_FILTER,
+ _ldb_nss_pw_attrs,
+ &_ldb_nss_ctx->pw_res);
+ if (ret != LDB_SUCCESS) {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+NSS_STATUS _nss_ldb_endpwent(void)
+{
+ int ret;
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ _ldb_nss_ctx->pw_cur = 0;
+ if (_ldb_nss_ctx->pw_res) {
+ talloc_free(_ldb_nss_ctx->pw_res);
+ _ldb_nss_ctx->pw_res = NULL;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+NSS_STATUS _nss_ldb_getpwent_r(struct passwd *result_buf,
+ char *buffer,
+ int buflen,
+ int *errnop)
+{
+ int ret;
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ *errnop = 0;
+
+ if (_ldb_nss_ctx->pw_cur >= _ldb_nss_ctx->pw_res->count) {
+ /* already returned all entries */
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ ret = _ldb_nss_fill_passwd(result_buf,
+ buffer,
+ buflen,
+ errnop,
+ _ldb_nss_ctx->pw_res->msgs[_ldb_nss_ctx->pw_cur]);
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ _ldb_nss_ctx->pw_cur++;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+NSS_STATUS _nss_ldb_getpwuid_r(uid_t uid, struct passwd *result_buf, char *buffer, size_t buflen, int *errnop)
+{
+ int ret;
+ char *filter;
+ struct ldb_result *res;
+
+ if (uid == 0) { /* we don't serve root uid by policy */
+ *errnop = errno = ENOENT;
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ /* build the filter for this uid */
+ filter = talloc_asprintf(_ldb_nss_ctx, _LDB_NSS_PWUID_FILTER, uid);
+ if (filter == NULL) {
+ /* this is a fatal error */
+ *errnop = errno = ENOMEM;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* search the entry */
+ ret = ldb_search(_ldb_nss_ctx->ldb,
+ _ldb_nss_ctx->base,
+ LDB_SCOPE_SUBTREE,
+ filter,
+ _ldb_nss_pw_attrs,
+ &res);
+ if (ret != LDB_SUCCESS) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* if none found return */
+ if (res->count == 0) {
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ if (res->count != 1) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* fill in the passwd struct */
+ ret = _ldb_nss_fill_passwd(result_buf,
+ buffer,
+ buflen,
+ errnop,
+ res->msgs[0]);
+
+done:
+ talloc_free(filter);
+ talloc_free(res);
+ return ret;
+}
+
+NSS_STATUS _nss_ldb_getpwnam_r(const char *name, struct passwd *result_buf, char *buffer, size_t buflen, int *errnop)
+{
+ int ret;
+ char *filter;
+ struct ldb_result *res;
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ /* build the filter for this name */
+ filter = talloc_asprintf(_ldb_nss_ctx, _LDB_NSS_PWNAM_FILTER, name);
+ if (filter == NULL) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* search the entry */
+ ret = ldb_search(_ldb_nss_ctx->ldb,
+ _ldb_nss_ctx->base,
+ LDB_SCOPE_SUBTREE,
+ filter,
+ _ldb_nss_pw_attrs,
+ &res);
+ if (ret != LDB_SUCCESS) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* if none found return */
+ if (res->count == 0) {
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ if (res->count != 1) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* fill in the passwd struct */
+ ret = _ldb_nss_fill_passwd(result_buf,
+ buffer,
+ buflen,
+ errnop,
+ res->msgs[0]);
+
+done:
+ talloc_free(filter);
+ talloc_free(res);
+ return ret;
+}
+
diff --git a/source3/lib/ldb/samba/README b/source3/lib/ldb/samba/README
new file mode 100644
index 0000000000..3fa47159ca
--- /dev/null
+++ b/source3/lib/ldb/samba/README
@@ -0,0 +1,7 @@
+This directory contains Samba specific extensions to ldb. It also
+serves as example code on how to extend ldb for your own application.
+
+The main extension Samba uses is to provide ldif encode/decode
+routines for specific attributes, so users can get nice pretty
+printing of attributes in ldbedit, while the attributes are stored in
+the standard NDR format in the database.
diff --git a/source3/lib/ldb/samba/ldif_handlers.c b/source3/lib/ldb/samba/ldif_handlers.c
new file mode 100644
index 0000000000..689a668c9e
--- /dev/null
+++ b/source3/lib/ldb/samba/ldif_handlers.c
@@ -0,0 +1,483 @@
+/*
+ ldb database library - ldif handlers for Samba
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Andrew Bartlett 2006
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "dsdb/samdb/samdb.h"
+#include "libcli/security/security.h"
+
+/*
+ convert a ldif formatted objectSid to a NDR formatted blob
+*/
+static int ldif_read_objectSid(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct dom_sid *sid;
+ NTSTATUS status;
+ sid = dom_sid_parse_talloc(mem_ctx, (const char *)in->data);
+ if (sid == NULL) {
+ return -1;
+ }
+ status = ndr_push_struct_blob(out, mem_ctx, sid,
+ (ndr_push_flags_fn_t)ndr_push_dom_sid);
+ talloc_free(sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ convert a NDR formatted blob to a ldif formatted objectSid
+*/
+static int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct dom_sid *sid;
+ NTSTATUS status;
+ sid = talloc(mem_ctx, struct dom_sid);
+ if (sid == NULL) {
+ return -1;
+ }
+ status = ndr_pull_struct_blob(in, sid, sid,
+ (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(sid);
+ return -1;
+ }
+ out->data = (uint8_t *)dom_sid_string(mem_ctx, sid);
+ talloc_free(sid);
+ if (out->data == NULL) {
+ return -1;
+ }
+ out->length = strlen((const char *)out->data);
+ return 0;
+}
+
+static BOOL ldb_comparision_objectSid_isString(const struct ldb_val *v)
+{
+ if (v->length < 3) {
+ return False;
+ }
+
+ if (strncmp("S-", (const char *)v->data, 2) != 0) return False;
+
+ return True;
+}
+
+/*
+ compare two objectSids
+*/
+static int ldb_comparison_objectSid(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ if (ldb_comparision_objectSid_isString(v1) && ldb_comparision_objectSid_isString(v2)) {
+ return strcmp((const char *)v1->data, (const char *)v2->data);
+ } else if (ldb_comparision_objectSid_isString(v1)
+ && !ldb_comparision_objectSid_isString(v2)) {
+ struct ldb_val v;
+ int ret;
+ if (ldif_read_objectSid(ldb, mem_ctx, v1, &v) != 0) {
+ return -1;
+ }
+ ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
+ talloc_free(v.data);
+ return ret;
+ } else if (!ldb_comparision_objectSid_isString(v1)
+ && ldb_comparision_objectSid_isString(v2)) {
+ struct ldb_val v;
+ int ret;
+ if (ldif_read_objectSid(ldb, mem_ctx, v2, &v) != 0) {
+ return -1;
+ }
+ ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
+ talloc_free(v.data);
+ return ret;
+ }
+ return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+}
+
+/*
+ canonicalise a objectSid
+*/
+static int ldb_canonicalise_objectSid(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ if (ldb_comparision_objectSid_isString(in)) {
+ return ldif_read_objectSid(ldb, mem_ctx, in, out);
+ }
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+}
+
+/*
+ convert a ldif formatted objectGUID to a NDR formatted blob
+*/
+static int ldif_read_objectGUID(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct GUID guid;
+ NTSTATUS status;
+
+ status = GUID_from_string((const char *)in->data, &guid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ status = ndr_push_struct_blob(out, mem_ctx, &guid,
+ (ndr_push_flags_fn_t)ndr_push_GUID);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ convert a NDR formatted blob to a ldif formatted objectGUID
+*/
+static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct GUID guid;
+ NTSTATUS status;
+ status = ndr_pull_struct_blob(in, mem_ctx, &guid,
+ (ndr_pull_flags_fn_t)ndr_pull_GUID);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+ out->data = (uint8_t *)GUID_string(mem_ctx, &guid);
+ if (out->data == NULL) {
+ return -1;
+ }
+ out->length = strlen((const char *)out->data);
+ return 0;
+}
+
+static BOOL ldb_comparision_objectGUID_isString(const struct ldb_val *v)
+{
+ struct GUID guid;
+ NTSTATUS status;
+
+ if (v->length < 33) return False;
+
+ /* see if the input if null-terninated (safety check for the below) */
+ if (v->data[v->length] != '\0') return False;
+
+ status = GUID_from_string((const char *)v->data, &guid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ return True;
+}
+
+/*
+ compare two objectGUIDs
+*/
+static int ldb_comparison_objectGUID(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ if (ldb_comparision_objectGUID_isString(v1) && ldb_comparision_objectGUID_isString(v2)) {
+ return strcmp((const char *)v1->data, (const char *)v2->data);
+ } else if (ldb_comparision_objectGUID_isString(v1)
+ && !ldb_comparision_objectGUID_isString(v2)) {
+ struct ldb_val v;
+ int ret;
+ if (ldif_read_objectGUID(ldb, mem_ctx, v1, &v) != 0) {
+ return -1;
+ }
+ ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
+ talloc_free(v.data);
+ return ret;
+ } else if (!ldb_comparision_objectGUID_isString(v1)
+ && ldb_comparision_objectGUID_isString(v2)) {
+ struct ldb_val v;
+ int ret;
+ if (ldif_read_objectGUID(ldb, mem_ctx, v2, &v) != 0) {
+ return -1;
+ }
+ ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
+ talloc_free(v.data);
+ return ret;
+ }
+ return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+}
+
+/*
+ canonicalise a objectGUID
+*/
+static int ldb_canonicalise_objectGUID(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ if (ldb_comparision_objectGUID_isString(in)) {
+ return ldif_read_objectGUID(ldb, mem_ctx, in, out);
+ }
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+}
+
+
+/*
+ convert a ldif (SDDL) formatted ntSecurityDescriptor to a NDR formatted blob
+*/
+static int ldif_read_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct security_descriptor *sd;
+ NTSTATUS status;
+
+ sd = sddl_decode(mem_ctx, (const char *)in->data, NULL);
+ if (sd == NULL) {
+ return -1;
+ }
+ status = ndr_push_struct_blob(out, mem_ctx, sd,
+ (ndr_push_flags_fn_t)ndr_push_security_descriptor);
+ talloc_free(sd);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ convert a NDR formatted blob to a ldif formatted ntSecurityDescriptor (SDDL format)
+*/
+static int ldif_write_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct security_descriptor *sd;
+ NTSTATUS status;
+
+ sd = talloc(mem_ctx, struct security_descriptor);
+ if (sd == NULL) {
+ return -1;
+ }
+ status = ndr_pull_struct_blob(in, sd, sd,
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(sd);
+ return -1;
+ }
+ out->data = (uint8_t *)sddl_encode(mem_ctx, sd, NULL);
+ talloc_free(sd);
+ if (out->data == NULL) {
+ return -1;
+ }
+ out->length = strlen((const char *)out->data);
+ return 0;
+}
+
+/*
+ canonicolise an objectCategory. We use the short form as the cannoical form:
+ cn=Person,cn=Schema,cn=Configuration,<basedn> becomes 'person'
+*/
+
+static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct ldb_dn *dn1 = NULL;
+ char *oc1, *oc2;
+
+ dn1 = ldb_dn_explode(mem_ctx, (char *)in->data);
+ if (dn1 == NULL) {
+ oc1 = talloc_strndup(mem_ctx, (char *)in->data, in->length);
+ } else if (ldb_dn_get_comp_num(dn1) >= 1 && strcasecmp(ldb_dn_get_rdn_name(dn1), "cn") == 0) {
+ const struct ldb_val *val = ldb_dn_get_rdn_val(dn1);
+ oc1 = talloc_strndup(mem_ctx, (char *)val->data, val->length);
+ } else {
+ return -1;
+ }
+
+ oc2 = ldb_casefold(ldb, mem_ctx, oc1);
+ out->data = (void *)oc2;
+ out->length = strlen(oc2);
+ talloc_free(oc1);
+ talloc_free(dn1);
+ return 0;
+}
+
+static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1,
+ const struct ldb_val *v2)
+{
+ struct ldb_dn *dn1 = NULL, *dn2 = NULL;
+ const char *oc1, *oc2;
+
+ dn1 = ldb_dn_explode(mem_ctx, (char *)v1->data);
+ if (dn1 == NULL) {
+ oc1 = talloc_strndup(mem_ctx, (char *)v1->data, v1->length);
+ } else if (ldb_dn_get_comp_num(dn1) >= 1 && strcasecmp(ldb_dn_get_rdn_name(dn1), "cn") == 0) {
+ const struct ldb_val *val = ldb_dn_get_rdn_val(dn1);
+ oc1 = talloc_strndup(mem_ctx, (char *)val->data, val->length);
+ } else {
+ oc1 = NULL;
+ }
+
+ dn2 = ldb_dn_explode(mem_ctx, (char *)v2->data);
+ if (dn2 == NULL) {
+ oc2 = talloc_strndup(mem_ctx, (char *)v2->data, v2->length);
+ } else if (ldb_dn_get_comp_num(dn2) >= 2 && strcasecmp(ldb_dn_get_rdn_name(dn2), "cn") == 0) {
+ const struct ldb_val *val = ldb_dn_get_rdn_val(dn2);
+ oc2 = talloc_strndup(mem_ctx, (char *)val->data, val->length);
+ } else {
+ oc2 = NULL;
+ }
+
+ oc1 = ldb_casefold(ldb, mem_ctx, oc1);
+ oc2 = ldb_casefold(ldb, mem_ctx, oc2);
+ if (!oc1 && oc2) {
+ return -1;
+ }
+ if (oc1 && !oc2) {
+ return 1;
+ }
+ if (!oc1 && !oc2) {
+ return -1;
+ }
+
+ return strcmp(oc1, oc2);
+}
+
+static const struct ldb_attrib_handler samba_handlers[] = {
+ {
+ .attr = "objectSid",
+ .flags = 0,
+ .ldif_read_fn = ldif_read_objectSid,
+ .ldif_write_fn = ldif_write_objectSid,
+ .canonicalise_fn = ldb_canonicalise_objectSid,
+ .comparison_fn = ldb_comparison_objectSid
+ },
+ {
+ .attr = "securityIdentifier",
+ .flags = 0,
+ .ldif_read_fn = ldif_read_objectSid,
+ .ldif_write_fn = ldif_write_objectSid,
+ .canonicalise_fn = ldb_canonicalise_objectSid,
+ .comparison_fn = ldb_comparison_objectSid
+ },
+ {
+ .attr = "ntSecurityDescriptor",
+ .flags = 0,
+ .ldif_read_fn = ldif_read_ntSecurityDescriptor,
+ .ldif_write_fn = ldif_write_ntSecurityDescriptor,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = ldb_comparison_binary
+ },
+ {
+ .attr = "objectGUID",
+ .flags = 0,
+ .ldif_read_fn = ldif_read_objectGUID,
+ .ldif_write_fn = ldif_write_objectGUID,
+ .canonicalise_fn = ldb_canonicalise_objectGUID,
+ .comparison_fn = ldb_comparison_objectGUID
+ },
+ {
+ .attr = "invocationId",
+ .flags = 0,
+ .ldif_read_fn = ldif_read_objectGUID,
+ .ldif_write_fn = ldif_write_objectGUID,
+ .canonicalise_fn = ldb_canonicalise_objectGUID,
+ .comparison_fn = ldb_comparison_objectGUID
+ },
+ {
+ .attr = "schemaIDGUID",
+ .flags = 0,
+ .ldif_read_fn = ldif_read_objectGUID,
+ .ldif_write_fn = ldif_write_objectGUID,
+ .canonicalise_fn = ldb_canonicalise_objectGUID,
+ .comparison_fn = ldb_comparison_objectGUID
+ },
+ {
+ .attr = "attributeSecurityGUID",
+ .flags = 0,
+ .ldif_read_fn = ldif_read_objectGUID,
+ .ldif_write_fn = ldif_write_objectGUID,
+ .canonicalise_fn = ldb_canonicalise_objectGUID,
+ .comparison_fn = ldb_comparison_objectGUID
+ },
+ {
+ .attr = "parentGUID",
+ .flags = 0,
+ .ldif_read_fn = ldif_read_objectGUID,
+ .ldif_write_fn = ldif_write_objectGUID,
+ .canonicalise_fn = ldb_canonicalise_objectGUID,
+ .comparison_fn = ldb_comparison_objectGUID
+ },
+ {
+ .attr = "siteGUID",
+ .flags = 0,
+ .ldif_read_fn = ldif_read_objectGUID,
+ .ldif_write_fn = ldif_write_objectGUID,
+ .canonicalise_fn = ldb_canonicalise_objectGUID,
+ .comparison_fn = ldb_comparison_objectGUID
+ },
+ {
+ .attr = "pKTGUID",
+ .flags = 0,
+ .ldif_read_fn = ldif_read_objectGUID,
+ .ldif_write_fn = ldif_write_objectGUID,
+ .canonicalise_fn = ldb_canonicalise_objectGUID,
+ .comparison_fn = ldb_comparison_objectGUID
+ },
+ {
+ .attr = "fRSVersionGUID",
+ .flags = 0,
+ .ldif_read_fn = ldif_read_objectGUID,
+ .ldif_write_fn = ldif_write_objectGUID,
+ .canonicalise_fn = ldb_canonicalise_objectGUID,
+ .comparison_fn = ldb_comparison_objectGUID
+ },
+ {
+ .attr = "fRSReplicaSetGUID",
+ .flags = 0,
+ .ldif_read_fn = ldif_read_objectGUID,
+ .ldif_write_fn = ldif_write_objectGUID,
+ .canonicalise_fn = ldb_canonicalise_objectGUID,
+ .comparison_fn = ldb_comparison_objectGUID
+ },
+ {
+ .attr = "netbootGUID",
+ .flags = 0,
+ .ldif_read_fn = ldif_read_objectGUID,
+ .ldif_write_fn = ldif_write_objectGUID,
+ .canonicalise_fn = ldb_canonicalise_objectGUID,
+ .comparison_fn = ldb_comparison_objectGUID
+ },
+ {
+ .attr = "objectCategory",
+ .flags = 0,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldif_canonicalise_objectCategory,
+ .comparison_fn = ldif_comparison_objectCategory,
+ }
+};
+
+/*
+ register the samba ldif handlers
+*/
+int ldb_register_samba_handlers(struct ldb_context *ldb)
+{
+ return ldb_set_attrib_handlers(ldb, samba_handlers, ARRAY_SIZE(samba_handlers));
+}
diff --git a/source3/lib/ldb/sqlite3.m4 b/source3/lib/ldb/sqlite3.m4
new file mode 100644
index 0000000000..d0a74ee53c
--- /dev/null
+++ b/source3/lib/ldb/sqlite3.m4
@@ -0,0 +1,62 @@
+########################################################
+# Compile with SQLITE3 support?
+
+SQLITE3_LIBS=""
+with_sqlite3_support=no
+AC_MSG_CHECKING([for SQLITE3 support])
+
+AC_ARG_WITH(sqlite3,
+AS_HELP_STRING([--with-sqlite3],[SQLITE3 backend support (default=no)]),
+[ case "$withval" in
+ yes|no|auto)
+ with_sqlite3_support=$withval
+ ;;
+ esac ])
+
+AC_MSG_RESULT($with_sqlite3_support)
+
+if test x"$with_sqlite3_support" != x"no"; then
+ ##################################################################
+ # first test for sqlite3.h
+ AC_CHECK_HEADERS(sqlite3.h)
+
+ if test x"$ac_cv_header_sqlite3_h" != x"yes"; then
+ if test x"$with_sqlite3_support" = x"yes"; then
+ AC_MSG_ERROR(sqlite3.h is needed for SQLITE3 support)
+ else
+ AC_MSG_WARN(sqlite3.h is needed for SQLITE3 support)
+ fi
+
+ with_sqlite3_support=no
+ fi
+fi
+
+if test x"$with_sqlite3_support" != x"no"; then
+ ac_save_LIBS=$LIBS
+
+ ########################################################
+ # now see if we can find the sqlite3 libs in standard paths
+ AC_CHECK_LIB_EXT(sqlite3, SQLITE3_LIBS, sqlite3_open)
+
+ if test x"$ac_cv_lib_ext_sqlite3_sqlite3_open" = x"yes"; then
+ AC_DEFINE(HAVE_SQLITE3,1,[Whether sqlite3 is available])
+ AC_DEFINE(HAVE_LDB_SQLITE3,1,[Whether ldb_sqlite3 is available])
+ AC_MSG_CHECKING(whether SQLITE3 support is used)
+ AC_MSG_RESULT(yes)
+ with_sqlite3_support=yes
+ SMB_ENABLE(SQLITE3,YES)
+ else
+ if test x"$with_sqlite3_support" = x"yes"; then
+ AC_MSG_ERROR(libsqlite3 is needed for SQLITE3 support)
+ else
+ AC_MSG_WARN(libsqlite3 is needed for SQLITE3 support)
+ fi
+
+ SQLITE3_LIBS=""
+ with_sqlite3_support=no
+ fi
+
+ LIBS=$ac_save_LIBS;
+fi
+
+SMB_EXT_LIB(SQLITE3,[${SQLITE3_LIBS}],[${SQLITE3_CFLAGS}],[${SQLITE3_CPPFLAGS}],[${SQLITE3_LDFLAGS}])
diff --git a/source3/lib/ldb/standalone.sh b/source3/lib/ldb/standalone.sh
new file mode 100755
index 0000000000..fa1b9bafe3
--- /dev/null
+++ b/source3/lib/ldb/standalone.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+cd ../replace
+make clean
+
+cd ../talloc
+make clean
+
+cd ../tdb
+make clean
+
+cd ../ldb
+make clean
+
+./autogen.sh
+
+rm -fr build
+mkdir build
+cd build
+
+../configure $*
+make dirs
+make all
+
+cd ..
diff --git a/source3/lib/ldb/swig/Ldb.py b/source3/lib/ldb/swig/Ldb.py
new file mode 100644
index 0000000000..4be3eec704
--- /dev/null
+++ b/source3/lib/ldb/swig/Ldb.py
@@ -0,0 +1,178 @@
+"""Provide a more Pythonic and object-oriented interface to ldb."""
+
+#
+# Swig interface to Samba
+#
+# Copyright (C) Tim Potter 2006
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Interface notes:
+#
+# - should an empty dn be represented as None, or an empty string?
+#
+# - should single-valued attributes be a string, or a list with one
+# element?
+#
+
+from ldb import *
+
+# Global initialisation
+
+result = ldb_global_init()
+
+if result != 0:
+ raise LdbError, (result, 'ldb_global_init failed')
+
+# Ldb exceptions
+
+class LdbError(Exception):
+ """An exception raised when a ldb error occurs.
+ The exception data is a tuple consisting of the ldb number and a
+ string description of the error."""
+ pass
+
+# Ldb classes
+
+class LdbMessage:
+ """A class representing a ldb message as a Python dictionary."""
+
+ def __init__(self):
+ self.mem_ctx = talloc_init(None)
+ self.msg = ldb_msg_new(self.mem_ctx)
+
+ def __del__(self):
+ if self.mem_ctx is not None:
+ talloc_free(self.mem_ctx)
+ self.mem_ctx = None
+ self.msg = None
+
+ # Make the dn attribute of the object dynamic
+
+ def __getattr__(self, attr):
+ if attr == 'dn':
+ return ldb_dn_linearize(None, self.msg.dn)
+ return self.__dict__[attr]
+
+ def __setattr__(self, attr, value):
+ if attr == 'dn':
+ self.msg.dn = ldb_dn_explode(self.msg, value)
+ if self.msg.dn == None:
+ err = LDB_ERR_INVALID_DN_SYNTAX
+ raise LdbError(err, ldb_strerror(err))
+ return
+ self.__dict__[attr] = value
+
+ # Get and set individual elements
+
+ def __getitem__(self, key):
+
+ elt = ldb_msg_find_element(self.msg, key)
+
+ if elt is None:
+ raise KeyError, "No such attribute '%s'" % key
+
+ return [ldb_val_array_getitem(elt.values, i)
+ for i in range(elt.num_values)]
+
+ def __setitem__(self, key, value):
+ ldb_msg_remove_attr(self.msg, key)
+ if type(value) in (list, tuple):
+ [ldb_msg_add_value(self.msg, key, v) for v in value]
+ else:
+ ldb_msg_add_value(self.msg, key, value)
+
+ # Dictionary interface
+ # TODO: move to iterator based interface
+
+ def len(self):
+ return self.msg.num_elements
+
+ def keys(self):
+ return [ldb_message_element_array_getitem(self.msg.elements, i).name
+ for i in range(self.msg.num_elements)]
+
+ def values(self):
+ return [self[k] for k in self.keys()]
+
+ def items(self):
+ return [(k, self[k]) for k in self.keys()]
+
+ # Misc stuff
+
+ def sanity_check(self):
+ return ldb_msg_sanity_check(self.msg)
+
+class Ldb:
+ """A class representing a binding to a ldb file."""
+
+ def __init__(self, url, flags = 0):
+ """Initialise underlying ldb."""
+
+ self.mem_ctx = talloc_init('mem_ctx for ldb 0x%x' % id(self))
+ self.ldb_ctx = ldb_init(self.mem_ctx)
+
+ result = ldb_connect(self.ldb_ctx, url, flags, None)
+
+ if result != LDB_SUCCESS:
+ raise LdbError, (result, ldb_strerror(result))
+
+ def __del__(self):
+ """Called when the object is to be garbage collected."""
+ self.close()
+
+ def close(self):
+ """Close down a ldb."""
+ if self.mem_ctx is not None:
+ talloc_free(self.mem_ctx)
+ self.mem_ctx = None
+ self.ldb_ctx = None
+
+ def _ldb_call(self, fn, *args):
+ """Call a ldb function with args. Raise a LdbError exception
+ if the function returns a non-zero return value."""
+
+ result = fn(*args)
+
+ if result != LDB_SUCCESS:
+ raise LdbError, (result, ldb_strerror(result))
+
+ def search(self, expression):
+ """Search a ldb for a given expression."""
+
+ self._ldb_call(ldb_search, self.ldb_ctx, None, LDB_SCOPE_DEFAULT,
+ expression, None);
+
+ return [LdbMessage(ldb_message_ptr_array_getitem(result.msgs, ndx))
+ for ndx in range(result.count)]
+
+ def delete(self, dn):
+ """Delete a dn."""
+
+ _dn = ldb_dn_explode(self.ldb_ctx, dn)
+
+ self._ldb_call(ldb_delete, self.ldb_ctx, _dn)
+
+ def rename(self, olddn, newdn):
+ """Rename a dn."""
+
+ _olddn = ldb_dn_explode(self.ldb_ctx, olddn)
+ _newdn = ldb_dn_explode(self.ldb_ctx, newdn)
+
+ self._ldb_call(ldb_rename, self.ldb_ctx, _olddn, _newdn)
+
+ def add(self, m):
+ self._ldb_call(ldb_add, self.ldb_ctx, m.msg)
diff --git a/source3/lib/ldb/swig/ldb.i b/source3/lib/ldb/swig/ldb.i
new file mode 100644
index 0000000000..fa460e3d6c
--- /dev/null
+++ b/source3/lib/ldb/swig/ldb.i
@@ -0,0 +1,239 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Swig interface to ldb.
+
+ Copyright (C) 2005,2006 Tim Potter <tpot@samba.org>
+ Copyright (C) 2006 Simo Sorce <idra@samba.org>
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+%module ldb
+
+%{
+
+/* Some typedefs to help swig along */
+
+typedef unsigned char uint8_t;
+typedef unsigned long long uint64_t;
+typedef long long int64_t;
+
+/* Include headers */
+
+#include "lib/ldb/include/ldb.h"
+#include "lib/talloc/talloc.h"
+
+%}
+
+%include "carrays.i"
+%include "exception.i"
+
+/*
+ * Constants
+ */
+
+#define LDB_SUCCESS 0
+#define LDB_ERR_OPERATIONS_ERROR 1
+#define LDB_ERR_PROTOCOL_ERROR 2
+#define LDB_ERR_TIME_LIMIT_EXCEEDED 3
+#define LDB_ERR_SIZE_LIMIT_EXCEEDED 4
+#define LDB_ERR_COMPARE_FALSE 5
+#define LDB_ERR_COMPARE_TRUE 6
+#define LDB_ERR_AUTH_METHOD_NOT_SUPPORTED 7
+#define LDB_ERR_STRONG_AUTH_REQUIRED 8
+/* 9 RESERVED */
+#define LDB_ERR_REFERRAL 10
+#define LDB_ERR_ADMIN_LIMIT_EXCEEDED 11
+#define LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION 12
+#define LDB_ERR_CONFIDENTIALITY_REQUIRED 13
+#define LDB_ERR_SASL_BIND_IN_PROGRESS 14
+#define LDB_ERR_NO_SUCH_ATTRIBUTE 16
+#define LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE 17
+#define LDB_ERR_INAPPROPRIATE_MATCHING 18
+#define LDB_ERR_CONSTRAINT_VIOLATION 19
+#define LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS 20
+#define LDB_ERR_INVALID_ATTRIBUTE_SYNTAX 21
+/* 22-31 unused */
+#define LDB_ERR_NO_SUCH_OBJECT 32
+#define LDB_ERR_ALIAS_PROBLEM 33
+#define LDB_ERR_INVALID_DN_SYNTAX 34
+/* 35 RESERVED */
+#define LDB_ERR_ALIAS_DEREFERENCING_PROBLEM 36
+/* 37-47 unused */
+#define LDB_ERR_INAPPROPRIATE_AUTHENTICATION 48
+#define LDB_ERR_INVALID_CREDENTIALS 49
+#define LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS 50
+#define LDB_ERR_BUSY 51
+#define LDB_ERR_UNAVAILABLE 52
+#define LDB_ERR_UNWILLING_TO_PERFORM 53
+#define LDB_ERR_LOOP_DETECT 54
+/* 55-63 unused */
+#define LDB_ERR_NAMING_VIOLATION 64
+#define LDB_ERR_OBJECT_CLASS_VIOLATION 65
+#define LDB_ERR_NOT_ALLOWED_ON_NON_LEAF 66
+#define LDB_ERR_NOT_ALLOWED_ON_RDN 67
+#define LDB_ERR_ENTRY_ALREADY_EXISTS 68
+#define LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED 69
+/* 70 RESERVED FOR CLDAP */
+#define LDB_ERR_AFFECTS_MULTIPLE_DSAS 71
+/* 72-79 unused */
+#define LDB_ERR_OTHER 80
+
+enum ldb_scope {LDB_SCOPE_DEFAULT=-1,
+ LDB_SCOPE_BASE=0,
+ LDB_SCOPE_ONELEVEL=1,
+ LDB_SCOPE_SUBTREE=2};
+
+/*
+ * Wrap struct ldb_context
+ */
+
+/* The ldb functions will crash if a NULL ldb context is passed so
+ catch this before it happens. */
+
+%typemap(check) struct ldb_context* {
+ if ($1 == NULL)
+ SWIG_exception(SWIG_ValueError,
+ "ldb context must be non-NULL");
+}
+
+/*
+ * Wrap a small bit of talloc
+ */
+
+/* Use talloc_init() to create a parameter to pass to ldb_init(). Don't
+ forget to free it using talloc_free() afterwards. */
+
+TALLOC_CTX *talloc_init(char *name);
+int talloc_free(TALLOC_CTX *ptr);
+
+/*
+ * Wrap struct ldb_val
+ */
+
+%typemap(in) struct ldb_val *INPUT (struct ldb_val temp) {
+ $1 = &temp;
+ if (!PyString_Check($input)) {
+ PyErr_SetString(PyExc_TypeError, "string arg expected");
+ return NULL;
+ }
+ $1->length = PyString_Size($input);
+ $1->data = PyString_AsString($input);
+}
+
+%typemap(out) struct ldb_val {
+ $result = PyString_FromStringAndSize($1.data, $1.length);
+}
+
+/*
+ * Wrap struct ldb_result
+ */
+
+%typemap(in, numinputs=0) struct ldb_result **OUT (struct ldb_result *temp_ldb_result) {
+ $1 = &temp_ldb_result;
+}
+
+%typemap(argout) struct ldb_result ** {
+ resultobj = SWIG_NewPointerObj(*$1, SWIGTYPE_p_ldb_result, 0);
+}
+
+%types(struct ldb_result *);
+
+/*
+ * Wrap struct ldb_message_element
+ */
+
+%array_functions(struct ldb_val, ldb_val_array);
+
+struct ldb_message_element {
+ unsigned int flags;
+ const char *name;
+ unsigned int num_values;
+ struct ldb_val *values;
+};
+
+/*
+ * Wrap struct ldb_message
+ */
+
+%array_functions(struct ldb_message_element, ldb_message_element_array);
+
+struct ldb_message {
+ struct ldb_dn *dn;
+ unsigned int num_elements;
+ struct ldb_message_element *elements;
+ void *private_data;
+};
+
+/*
+ * Wrap struct ldb_result
+ */
+
+%array_functions(struct ldb_message *, ldb_message_ptr_array);
+
+struct ldb_result {
+ unsigned int count;
+ struct ldb_message **msgs;
+ char **refs;
+ struct ldb_control **controls;
+};
+
+/*
+ * Wrap ldb functions
+ */
+
+/* Initialisation */
+
+int ldb_global_init(void);
+struct ldb_context *ldb_init(TALLOC_CTX *mem_ctx);
+
+/* Error handling */
+
+const char *ldb_errstring(struct ldb_context *ldb);
+const char *ldb_strerror(int ldb_err);
+
+/* Top-level ldb operations */
+
+int ldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[]);
+
+int ldb_search(struct ldb_context *ldb, const struct ldb_dn *base, enum ldb_scope scope, const char *expression, const char * const *attrs, struct ldb_result **OUT);
+
+int ldb_delete(struct ldb_context *ldb, const struct ldb_dn *dn);
+
+int ldb_rename(struct ldb_context *ldb, const struct ldb_dn *olddn, const struct ldb_dn *newdn);
+
+int ldb_add(struct ldb_context *ldb, const struct ldb_message *message);
+
+/* Ldb message operations */
+
+struct ldb_message *ldb_msg_new(void *mem_ctx);
+
+struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg, const char *attr_name);
+
+int ldb_msg_add_value(struct ldb_message *msg, const char *attr_name, const struct ldb_val *INPUT);
+
+void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr);
+
+int ldb_msg_sanity_check(struct ldb_message *msg);
+
+/* DN operations */
+
+struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn);
+
+char *ldb_dn_linearize(void *mem_ctx, const struct ldb_dn *dn);
diff --git a/source3/lib/ldb/tests/init.ldif b/source3/lib/ldb/tests/init.ldif
new file mode 100644
index 0000000000..2e0b83c769
--- /dev/null
+++ b/source3/lib/ldb/tests/init.ldif
@@ -0,0 +1,40 @@
+dn: o=University of Michigan,c=TEST
+objectclass: organization
+objectclass: domainRelatedObject
+l: Ann Arbor, Michigan
+st: Michigan
+o: University of Michigan
+o: UMICH
+o: UM
+o: U-M
+o: U of M
+description: The University of Michigan at Ann Arbor
+seeAlso:
+postaladdress: University of Michigan $ 535 W. William St. $ Ann Arbor, MI 481
+ 09 $ US
+telephonenumber: +1 313 764-1817
+associateddomain: example.com
+
+dn: ou=People,o=University of Michigan,c=TEST
+objectclass: organizationalUnit
+objectclass: extensibleObject
+ou: People
+uidNumber: 0
+gidNumber: 0
+
+dn: ou=Ldb Test,ou=People,o=University of Michigan,c=TEST
+objectclass: organizationalUnit
+objectclass: extensibleObject
+ou: People
+ou: Ldb Test
+uidNumber: 0
+gidNumber: 0
+
+dn: ou=LdbTspace,ou=People,o=University of Michigan,c=TEST
+objectclass: organizationalUnit
+objectclass: extensibleObject
+ou: People
+ou: LdbTspace
+description: test white space removal in comparisons
+uidNumber: 0
+gidNumber: 0
diff --git a/source3/lib/ldb/tests/init_slapd.sh b/source3/lib/ldb/tests/init_slapd.sh
new file mode 100755
index 0000000000..cf06acd08b
--- /dev/null
+++ b/source3/lib/ldb/tests/init_slapd.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+if [ -z "$LDBDIR" ]; then
+ LDBDIR=`dirname $0`/..
+ export LDBDIR
+fi
+
+rm -rf tests/tmp/db
+mkdir -p tests/tmp/db
+
+if [ -f tests/tmp/slapd.pid ]; then
+ kill `cat tests/tmp/slapd.pid`
+ sleep 1
+fi
+if [ -f tests/tmp/slapd.pid ]; then
+ kill -9 `cat tests/tmp/slapd.pid`
+ rm -f tests/tmp/slapd.pid
+fi
+
+# we don't consider a slapadd failure as a test suite failure, as it
+# has nothing to do with ldb
+
+MODCONF=tests/tmp/modules.conf
+rm -f $MODCONF
+touch $MODCONF || exit 1
+
+slaptest -u -f $LDBDIR/tests/slapd.conf > /dev/null 2>&1 || {
+ echo "enabling sladp modules"
+cat > $MODCONF <<EOF
+modulepath /usr/lib/ldap
+moduleload back_bdb
+EOF
+}
+
+slaptest -u -f $LDBDIR/tests/slapd.conf || {
+ echo "slaptest failed - skipping ldap tests"
+ exit 0
+}
+
+slapadd -f $LDBDIR/tests/slapd.conf < $LDBDIR/tests/init.ldif || exit 0
+
diff --git a/source3/lib/ldb/tests/kill_slapd.sh b/source3/lib/ldb/tests/kill_slapd.sh
new file mode 100755
index 0000000000..91beb10814
--- /dev/null
+++ b/source3/lib/ldb/tests/kill_slapd.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+if [ -z "$LDBDIR" ]; then
+ LDBDIR=`dirname $0`/..
+ export LDBDIR
+fi
+
+if [ -f tests/tmp/slapd.pid ]; then
+ echo "killing slapd process `cat tests/tmp/slapd.pid`"
+ kill -9 `cat tests/tmp/slapd.pid`
+ rm -f tests/tmp/slapd.pid
+fi
diff --git a/source3/lib/ldb/tests/ldapi_url.sh b/source3/lib/ldb/tests/ldapi_url.sh
new file mode 100755
index 0000000000..fef6c35f2b
--- /dev/null
+++ b/source3/lib/ldb/tests/ldapi_url.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# aargh, did LDAP ever have to expose this crap to users ...
+
+BASE=`pwd`
+
+TMPDIR=$BASE/tests/tmp
+
+LDAPI_ESCAPE=`echo $TMPDIR/ldapi | sed 's|/|%2F|g'`
+
+echo "ldapi://$LDAPI_ESCAPE"
diff --git a/source3/lib/ldb/tests/photo.ldif b/source3/lib/ldb/tests/photo.ldif
new file mode 100644
index 0000000000..28981b1f24
--- /dev/null
+++ b/source3/lib/ldb/tests/photo.ldif
@@ -0,0 +1,5 @@
+dn: cn=Hampster Ursula,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST
+changetype: modify
+add: jpegPhoto
+jpegPhoto:< file://tests/tmp/samba4.png
+
diff --git a/source3/lib/ldb/tests/samba4.png b/source3/lib/ldb/tests/samba4.png
new file mode 100644
index 0000000000..c8096889a6
--- /dev/null
+++ b/source3/lib/ldb/tests/samba4.png
Binary files differ
diff --git a/source3/lib/ldb/tests/schema-tests/schema-add-test.ldif b/source3/lib/ldb/tests/schema-tests/schema-add-test.ldif
new file mode 100644
index 0000000000..997b801d84
--- /dev/null
+++ b/source3/lib/ldb/tests/schema-tests/schema-add-test.ldif
@@ -0,0 +1,66 @@
+dn: CN=Users,DC=schema,DC=test
+objectClass: top
+objectClass: container
+cn: Users
+description: Default container for upgraded user accounts
+instanceType: 4
+whenCreated: 20050116175504.0Z
+whenChanged: 20050116175504.0Z
+uSNCreated: 1
+uSNChanged: 1
+showInAdvancedViewOnly: FALSE
+name: Users
+objectGUID: b847056a-9934-d87b-8a1a-99fabe0863c8
+systemFlags: 0x8c000000
+objectCategory: CN=Container,CN=Schema,CN=Configuration,DC=schema,DC=test
+isCriticalSystemObject: TRUE
+nTSecurityDescriptor: foo
+
+dn: CN=Administrator,CN=Users,DC=schema,DC=test
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: user
+cn: Administrator
+description: Built-in account for administering the computer/domain
+instanceType: 4
+whenCreated: 20050116175504.0Z
+whenChanged: 20050116175504.0Z
+uSNCreated: 1
+memberOf: CN=Group Policy Creator Owners,CN=Users,DC=schema,DC=test
+memberOf: CN=Domain Admins,CN=Users,DC=schema,DC=test
+memberOf: CN=Enterprise Admins,CN=Users,DC=schema,DC=test
+memberOf: CN=Schema Admins,CN=Users,DC=schema,DC=test
+memberOf: CN=Administrators,CN=Builtin,DC=schema,DC=test
+uSNChanged: 1
+name: Administrator
+objectGUID: 6c02f98c-46c6-aa38-5f13-a510cac04e6c
+userAccountControl: 0x10200
+badPwdCount: 0
+codePage: 0
+countryCode: 0
+badPasswordTime: 0
+lastLogoff: 0
+lastLogon: 0
+pwdLastSet: 0
+primaryGroupID: 513
+objectSid: S-1-5-21-43662522-77495566-38969261-500
+adminCount: 1
+accountExpires: -1
+logonCount: 0
+sAMAccountName: Administrator
+sAMAccountType: 0x30000000
+objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=schema,DC=test
+isCriticalSystemObject: TRUE
+unicodePwd: samba
+nTSecurityDescriptor: foo
+
+dn: CN=Test,CN=Users,DC=schema,DC=test
+objectClass: top
+objectClass: test
+cn: Test
+description: This is a test
+objectCategory: CN=Test,CN=Schema,CN=Configuration,DC=schema,DC=test
+nTSecurityDescriptor: foo
+instanceType: 4
+
diff --git a/source3/lib/ldb/tests/schema-tests/schema-mod-test-1.ldif b/source3/lib/ldb/tests/schema-tests/schema-mod-test-1.ldif
new file mode 100644
index 0000000000..b976724485
--- /dev/null
+++ b/source3/lib/ldb/tests/schema-tests/schema-mod-test-1.ldif
@@ -0,0 +1,5 @@
+dn: CN=Test,CN=Users,DC=schema,DC=test
+changetype: modify
+replace: description
+description: this test must not fail
+
diff --git a/source3/lib/ldb/tests/schema-tests/schema-mod-test-2.ldif b/source3/lib/ldb/tests/schema-tests/schema-mod-test-2.ldif
new file mode 100644
index 0000000000..fa193af683
--- /dev/null
+++ b/source3/lib/ldb/tests/schema-tests/schema-mod-test-2.ldif
@@ -0,0 +1,5 @@
+dn: CN=Test,CN=Users,DC=schema,DC=test
+changetype: modify
+delete: description
+# this test must not fail
+
diff --git a/source3/lib/ldb/tests/schema-tests/schema-mod-test-3.ldif b/source3/lib/ldb/tests/schema-tests/schema-mod-test-3.ldif
new file mode 100644
index 0000000000..8ab7798f9c
--- /dev/null
+++ b/source3/lib/ldb/tests/schema-tests/schema-mod-test-3.ldif
@@ -0,0 +1,5 @@
+dn: CN=Test,CN=Users,DC=schema,DC=test
+changetype: modify
+add: description
+description: this test must not fail
+
diff --git a/source3/lib/ldb/tests/schema-tests/schema-mod-test-4.ldif b/source3/lib/ldb/tests/schema-tests/schema-mod-test-4.ldif
new file mode 100644
index 0000000000..cbf0e60bbe
--- /dev/null
+++ b/source3/lib/ldb/tests/schema-tests/schema-mod-test-4.ldif
@@ -0,0 +1,5 @@
+dn: CN=Test,CN=Users,DC=schema,DC=test
+changetype: modify
+add: foo
+foo: this test must fail
+
diff --git a/source3/lib/ldb/tests/schema-tests/schema-mod-test-5.ldif b/source3/lib/ldb/tests/schema-tests/schema-mod-test-5.ldif
new file mode 100644
index 0000000000..bc64e9edb6
--- /dev/null
+++ b/source3/lib/ldb/tests/schema-tests/schema-mod-test-5.ldif
@@ -0,0 +1,5 @@
+dn: CN=Test,CN=Users,DC=schema,DC=test
+changetype: modify
+delete: nTSecurityDescriptor
+# this test must fail
+
diff --git a/source3/lib/ldb/tests/schema-tests/schema.ldif b/source3/lib/ldb/tests/schema-tests/schema.ldif
new file mode 100644
index 0000000000..515408144a
--- /dev/null
+++ b/source3/lib/ldb/tests/schema-tests/schema.ldif
@@ -0,0 +1,112 @@
+dn: @INDEXLIST
+@IDXATTR: name
+@IDXATTR: sAMAccountName
+@IDXATTR: objectSid
+@IDXATTR: objectClass
+@IDXATTR: member
+@IDXATTR: uidNumber
+@IDXATTR: gidNumber
+@IDXATTR: unixName
+@IDXATTR: privilege
+@IDXATTR: lDAPDisplayName
+
+dn: @ATTRIBUTES
+realm: CASE_INSENSITIVE
+userPrincipalName: CASE_INSENSITIVE
+servicePrincipalName: CASE_INSENSITIVE
+name: CASE_INSENSITIVE
+dn: CASE_INSENSITIVE
+sAMAccountName: CASE_INSENSITIVE
+objectClass: CASE_INSENSITIVE
+unicodePwd: HIDDEN
+ntPwdHash: HIDDEN
+ntPwdHistory: HIDDEN
+lmPwdHash: HIDDEN
+lmPwdHistory: HIDDEN
+createTimestamp: HIDDEN
+modifyTimestamp: HIDDEN
+
+dn: @SUBCLASSES
+top: domain
+top: person
+top: group
+domain: domainDNS
+domain: builtinDomain
+person: organizationalPerson
+organizationalPerson: user
+user: computer
+template: userTemplate
+template: groupTemplate
+
+dn: @MODULES
+@LIST: timestamps,schema
+
+dn: CN=Top,CN=Schema,CN=Configuration,DC=schema,DC=test
+objectClass: top
+objectClass: classSchema
+lDAPDisplayName: top
+cn: Top
+uSNCreated: 1
+uSNChanged: 1
+subClassOf: top
+systemMustContain: objectClass
+systemMayContain: structuralObjectClass
+systemMayContain: createTimeStamp
+systemMayContain: modifyTimeStamp
+systemMayContain: creatorsName
+systemMayContain: modifiersName
+systemMayContain: hasSubordinates
+systemMayContain: subschemaSubentry
+systemMayContain: collectiveSubentry
+systemMayContain: entryUUID
+systemMayContain: entryCSN
+systemMayContain: namingCSN
+systemMayContain: superiorUUID
+systemMayContain: contextCSN
+systemMayContain: whenCreated
+systemMayContain: whenChanged
+systemMayContain: uSNCreated
+systemMayContain: uSNChanged
+systemMayContain: distinguishedName
+systemMayContain: name
+systemMayContain: cn
+systemMayContain: userPassword
+systemMayContain: labeledURI
+
+dn: CN=Class-Schema,CN=Schema,CN=Configuration,DC=schema,DC=test
+objectClass: top
+objectClass: classSchema
+lDAPDisplayName: classSchema
+cn: Class-Schema
+uSNCreated: 2
+uSNChanged: 2
+lDAPDisplayName: classSchema
+subClassOf: top
+systemMustContain: cn
+systemMustContain: subClassOf
+systemMayContain: systemPossSuperiors
+systemMayContain: systemOnly
+systemMayContain: systemMustContain
+systemMayContain: systemMayContain
+systemMayContain: systemAuxiliaryClass
+systemMayContain: possSuperiors
+systemMayContain: mustContain
+systemMayContain: mayContain
+systemMayContain: lDAPDisplayName
+systemMayContain: auxiliaryClass
+
+dn: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=schema,DC=test
+objectClass: top
+objectClass: classSchema
+cn: Attribute-Schema
+uSNCreated: 3
+uSNChanged: 3
+lDAPDisplayName: attributeSchema
+subClassOf: top
+systemMustContain: oMSyntax
+systemMustContain: lDAPDisplayName
+systemMustContain: isSingleValued
+systemMustContain: cn
+systemMustContain: attributeSyntax
+systemMustContain: attributeID
+
diff --git a/source3/lib/ldb/tests/slapd.conf b/source3/lib/ldb/tests/slapd.conf
new file mode 100644
index 0000000000..fa2789d8c1
--- /dev/null
+++ b/source3/lib/ldb/tests/slapd.conf
@@ -0,0 +1,26 @@
+loglevel 0
+
+include tests/schema/core.schema
+include tests/schema/cosine.schema
+include tests/schema/inetorgperson.schema
+include tests/schema/openldap.schema
+include tests/schema/nis.schema
+
+
+pidfile tests/tmp/slapd.pid
+argsfile tests/tmp/slapd.args
+
+access to * by * write
+
+allow update_anon bind_anon_dn
+
+include tests/tmp/modules.conf
+
+defaultsearchbase "o=University of Michigan,c=TEST"
+
+backend bdb
+database bdb
+suffix "o=University of Michigan,c=TEST"
+directory tests/tmp/db
+index objectClass eq
+index uid eq
diff --git a/source3/lib/ldb/tests/start_slapd.sh b/source3/lib/ldb/tests/start_slapd.sh
new file mode 100755
index 0000000000..22e8548791
--- /dev/null
+++ b/source3/lib/ldb/tests/start_slapd.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+if [ -z "$LDBDIR" ]; then
+ LDBDIR=`dirname $0`/..
+ export LDBDIR
+fi
+
+mkdir -p $LDBDIR/tests/tmp/db
+
+# running slapd with -d0 means it stays in the same process group, so it can be
+# killed by timelimit
+slapd -d0 -f $LDBDIR/tests/slapd.conf -h "`$LDBDIR/tests/ldapi_url.sh`" $* &
+
+sleep 2
diff --git a/source3/lib/ldb/tests/test-attribs.ldif b/source3/lib/ldb/tests/test-attribs.ldif
new file mode 100644
index 0000000000..0bb3ebead6
--- /dev/null
+++ b/source3/lib/ldb/tests/test-attribs.ldif
@@ -0,0 +1,15 @@
+dn: @ATTRIBUTES
+uid: CASE_INSENSITIVE
+cn: CASE_INSENSITIVE
+ou: CASE_INSENSITIVE
+dn: CASE_INSENSITIVE
+
+dn: @SUBCLASSES
+top: domain
+top: person
+domain: domainDNS
+person: organizationalPerson
+person: fooPerson
+organizationalPerson: user
+organizationalPerson: OpenLDAPperson
+user: computer
diff --git a/source3/lib/ldb/tests/test-config.ldif b/source3/lib/ldb/tests/test-config.ldif
new file mode 100644
index 0000000000..7926a9e3c5
--- /dev/null
+++ b/source3/lib/ldb/tests/test-config.ldif
@@ -0,0 +1,67 @@
+##############################
+# global configuration options
+dn: cn=Global,cn=Config,cn=Samba
+objectclass: globalconfig
+LocalConfigCn: cn=%U,cn=Config,cn=Samba
+LocalConfigCn;1: cn=%U,cn=Config,cn=Samba
+LocalConfigCn;2: cn=%I,cn=Config,cn=Samba
+LocalConfigCn;3: cn=%M,cn=Config,cn=Samba
+
+#############
+dn: cn=Protocol,cn=Global,cn=Config,cn=Samba
+maxXmit: 7000
+
+################################
+dn: cn=Volker,cn=Config,cn=Samba
+Workgroup: VNET3
+UnixCharset: UTF8
+Security: user
+Interfaces: vmnet* eth*
+NetbiosName: blu
+GuestAccount: tridge
+
+#################################
+dn: cn=Volker,cn=Config,cn=Samba
+Workgroup: VNET3
+UnixCharset: UTF8
+Security: user
+Interfaces: vmnet* eth*
+NetbiosName: blu
+GuestAccount: tridge
+Include: cn=%U,cn=MyConfig,cn=Config,cn=Samba
+
+#### ((objectClass=fileshare)(cn=test))
+##############################
+# [test] share
+dn: cn=test,cn=Shares,cn=Config,cn=Samba
+objectclass: fileshare
+cn: test
+Comment: a test share
+Path: /home/tridge/samba4/prefix/test
+ReadOnly: no
+
+#####################################
+# [msdn] a remote proxy share, stored
+# on \\msdn\test
+dn: cn=msdn,cn=Shares,cn=Config,cn=Samba
+objectclass: fileshare
+cn: msdn
+NtvfsHandler: cifs
+ReadOnly: no
+_CifsServer: msdn
+_CifsUser: administrator
+_CifsPassword: penguin
+_CifsDomain: winxp
+_CifsShare: test
+
+
+##############################
+# [VisualC] share
+dn: cn=visualc,cn=Shares,cn=Config,cn=Samba
+objectclass: fileshare
+cn: VisualC
+Comment: VisualC development
+Path: /home/tridge/VisualC
+ReadOnly: no
+NtvfsHandler: simple
+
diff --git a/source3/lib/ldb/tests/test-default-config.ldif b/source3/lib/ldb/tests/test-default-config.ldif
new file mode 100644
index 0000000000..87b7bcd3cc
--- /dev/null
+++ b/source3/lib/ldb/tests/test-default-config.ldif
@@ -0,0 +1,17 @@
+##############################
+# global configuration options
+dn: cn=Global,cn=DefaultConfig,cn=Samba
+objectclass: globalconfig
+Workgroup: WORKGROUP
+UnixCharset: UTF8
+Security: user
+NetbiosName: blu
+GuestAccount: nobody
+
+##############################
+# [_default_] share
+dn: cn=_default_,cn=Shares,cn=DefaultConfig,cn=Samba
+objectclass: fileshare
+cn: _default_
+Path: /tmp
+ReadOnly: yes
diff --git a/source3/lib/ldb/tests/test-extended.sh b/source3/lib/ldb/tests/test-extended.sh
new file mode 100755
index 0000000000..a84e3b78a3
--- /dev/null
+++ b/source3/lib/ldb/tests/test-extended.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+echo "Running extended search tests"
+
+mv $LDB_URL $LDB_URL.1
+
+cat <<EOF | bin/ldbadd || exit 1
+dn: cn=testrec1,cn=TEST
+i1: 1
+i2: 0
+i3: 1234
+i4: 0x7003004
+
+dn: cn=testrec2,cn=TEST
+i1: 0x800000
+
+dn: cn=testrec3,cn=TEST
+i1: 0x101010101
+i1: 7
+
+dn: cn=auser1,cn=TEST
+groupType: 2147483648
+samAccountType: 805306368
+
+dn: cn=auser2,cn=TEST
+groupType: 2147483648
+samAccountType: 805306369
+
+dn: cn=auser3,cn=TEST
+groupType: 2147483649
+samAccountType: 805306370
+
+dn: cn=auser4,cn=TEST
+groupType: 2147483649
+samAccountType: 805306369
+EOF
+
+checkcount() {
+ count=$1
+ expression="$2"
+ n=`bin/ldbsearch "$expression" | grep '^dn' | wc -l`
+ if [ $n != $count ]; then
+ echo "Got $n but expected $count for $expression"
+ bin/ldbsearch "$expression"
+ exit 1
+ fi
+ echo "OK: $count $expression"
+}
+
+checkcount 1 '(i3=1234)'
+checkcount 0 '(i3=12345)'
+
+checkcount 2 '(i1:1.2.840.113556.1.4.803:=1)'
+checkcount 1 '(i1:1.2.840.113556.1.4.803:=3)'
+checkcount 1 '(i1:1.2.840.113556.1.4.803:=7)'
+checkcount 0 '(i1:1.2.840.113556.1.4.803:=15)'
+checkcount 1 '(i1:1.2.840.113556.1.4.803:=0x800000)'
+checkcount 1 '(i1:1.2.840.113556.1.4.803:=8388608)'
+
+checkcount 2 '(i1:1.2.840.113556.1.4.804:=1)'
+checkcount 2 '(i1:1.2.840.113556.1.4.804:=3)'
+checkcount 2 '(i1:1.2.840.113556.1.4.804:=7)'
+checkcount 2 '(i1:1.2.840.113556.1.4.804:=15)'
+checkcount 1 '(i1:1.2.840.113556.1.4.804:=0x800000)'
+checkcount 1 '(i1:1.2.840.113556.1.4.804:=8388608)'
+
+# this is one that w2k gives
+checkcount 3 '(|(|(&(!(groupType:1.2.840.113556.1.4.803:=1))(groupType:1.2.840.113556.1.4.803:=2147483648)(groupType:1.2.840.113556.1.4.804:=10))(samAccountType=805306368))(samAccountType=805306369))'
+
diff --git a/source3/lib/ldb/tests/test-generic.sh b/source3/lib/ldb/tests/test-generic.sh
new file mode 100755
index 0000000000..14337cc135
--- /dev/null
+++ b/source3/lib/ldb/tests/test-generic.sh
@@ -0,0 +1,128 @@
+#!/bin/sh
+
+if [ -z "$LDB_SPECIALS" ]; then
+ LDB_SPECIALS=1
+ export LDB_SPECIALS
+fi
+
+echo "LDB_URL: $LDB_URL"
+
+echo "Adding base elements"
+$VALGRIND ldbadd $LDBDIR/tests/test.ldif || exit 1
+
+echo "Adding again - should fail"
+ldbadd $LDBDIR/tests/test.ldif 2> /dev/null && {
+ echo "Should have failed to add again - gave $?"
+ exit 1
+}
+
+echo "Modifying elements"
+$VALGRIND ldbmodify $LDBDIR/tests/test-modify.ldif || exit 1
+
+echo "Showing modified record"
+$VALGRIND ldbsearch '(uid=uham)' || exit 1
+
+echo "Rename entry"
+OLDDN="cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST"
+NEWDN="cn=Hampster Ursula,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST"
+$VALGRIND ldbrename "$OLDDN" "$NEWDN" || exit 1
+
+echo "Showing renamed record"
+$VALGRIND ldbsearch '(uid=uham)' || exit 1
+
+echo "Starting ldbtest"
+$VALGRIND ldbtest --num-records 100 --num-searches 10 || exit 1
+
+if [ $LDB_SPECIALS = 1 ]; then
+ echo "Adding index"
+ $VALGRIND ldbadd $LDBDIR/tests/test-index.ldif || exit 1
+fi
+
+echo "Adding bad attributes - should fail"
+$VALGRIND ldbadd $LDBDIR/tests/test-wrong_attributes.ldif && {
+ echo "Should fhave failed - gave $?"
+ exit 1
+}
+
+echo "testing indexed search"
+$VALGRIND ldbsearch '(uid=uham)' || exit 1
+$VALGRIND ldbsearch '(&(objectclass=person)(objectclass=person)(objectclass=top))' || exit 1
+$VALGRIND ldbsearch '(&(uid=uham)(uid=uham))' || exit 1
+$VALGRIND ldbsearch '(|(uid=uham)(uid=uham))' || exit 1
+$VALGRIND ldbsearch '(|(uid=uham)(uid=uham)(objectclass=OpenLDAPperson))' || exit 1
+$VALGRIND ldbsearch '(&(uid=uham)(uid=uham)(!(objectclass=xxx)))' || exit 1
+$VALGRIND ldbsearch '(&(objectclass=person)(uid=uham)(!(uid=uhamxx)))' uid \* \+ dn || exit 1
+$VALGRIND ldbsearch '(&(uid=uham)(uid=uha*)(title=*))' uid || exit 1
+
+# note that the "((" is treated as an attribute not an expression
+# this matches the openldap ldapsearch behaviour of looking for a '='
+# to see if the first argument is an expression or not
+$VALGRIND ldbsearch '((' uid || exit 1
+$VALGRIND ldbsearch '(objectclass=)' uid || exit 1
+$VALGRIND ldbsearch -b 'cn=Hampster Ursula,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST' -s base "" sn || exit 1
+
+echo "Test wildcard match"
+$VALGRIND ldbadd $LDBDIR/tests/test-wildcard.ldif || exit 1
+$VALGRIND ldbsearch '(cn=test*multi)' || exit 1
+$VALGRIND ldbsearch '(cn=*test*multi*)' || exit 1
+$VALGRIND ldbsearch '(cn=*test_multi)' || exit 1
+$VALGRIND ldbsearch '(cn=test_multi*)' || exit 1
+$VALGRIND ldbsearch '(cn=test*multi*test*multi)' || exit 1
+$VALGRIND ldbsearch '(cn=test*multi*test*multi*multi_*)' || exit 1
+
+echo "Starting ldbtest indexed"
+$VALGRIND ldbtest --num-records 100 --num-searches 500 || exit 1
+
+echo "Testing one level search"
+count=`$VALGRIND ldbsearch -b 'ou=Groups,o=University of Michigan,c=TEST' -s one 'objectclass=*' none |grep '^dn' | wc -l`
+if [ $count != 3 ]; then
+ echo returned $count records - expected 3
+ exit 1
+fi
+
+echo "Testing binary file attribute value"
+mkdir -p tests/tmp
+cp $LDBDIR/tests/samba4.png tests/tmp/samba4.png
+$VALGRIND ldbmodify $LDBDIR/tests/photo.ldif || exit 1
+count=`$VALGRIND ldbsearch '(cn=Hampster Ursula)' jpegPhoto | grep '^dn' | wc -l`
+if [ $count != 1 ]; then
+ echo returned $count records - expected 1
+ exit 1
+fi
+rm -f tests/tmp/samba4.png
+
+echo "*TODO* Testing UTF8 upper lower case searches !!"
+
+echo "Testing compare"
+count=`$VALGRIND ldbsearch '(cn>=t)' cn | grep '^dn' | wc -l`
+if [ $count != 2 ]; then
+ echo returned $count records - expected 2
+ echo "this fails on openLdap ..."
+fi
+
+count=`$VALGRIND ldbsearch '(cn<=t)' cn | grep '^dn' | wc -l`
+if [ $count != 13 ]; then
+ echo returned $count records - expected 13
+ echo "this fails on opsnLdap ..."
+fi
+
+checkcount() {
+ count=$1
+ scope=$2
+ basedn=$3
+ expression="$4"
+ n=`bin/ldbsearch -s "$scope" -b "$basedn" "$expression" | grep '^dn' | wc -l`
+ if [ $n != $count ]; then
+ echo "Got $n but expected $count for $expression"
+ bin/ldbsearch "$expression"
+ exit 1
+ fi
+ echo "OK: $count $expression"
+}
+
+checkcount 0 'base' '' '(uid=uham)'
+checkcount 0 'one' '' '(uid=uham)'
+
+checkcount 1 'base' 'cn=Hampster Ursula,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST' '(uid=uham)'
+checkcount 1 'one' 'ou=Alumni Association,ou=People,o=University of Michigan,c=TEST' '(uid=uham)'
+checkcount 1 'one' 'ou=People,o=University of Michigan,c=TEST' '(ou=ldb test)'
diff --git a/source3/lib/ldb/tests/test-index.ldif b/source3/lib/ldb/tests/test-index.ldif
new file mode 100644
index 0000000000..a793537187
--- /dev/null
+++ b/source3/lib/ldb/tests/test-index.ldif
@@ -0,0 +1,11 @@
+dn: @INDEXLIST
+@IDXATTR: uid
+@IDXATTR: objectclass
+
+dn: @ATTRIBUTES
+uid: CASE_INSENSITIVE
+
+dn: @SUBCLASSES
+top: person
+person: organizationalPerson
+organizationalPerson: OpenLDAPperson
diff --git a/source3/lib/ldb/tests/test-ldap.sh b/source3/lib/ldb/tests/test-ldap.sh
new file mode 100755
index 0000000000..b9d224e0af
--- /dev/null
+++ b/source3/lib/ldb/tests/test-ldap.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+PATH=/usr/local/sbin:/usr/sbin:/sbin:$PATH
+export PATH
+SCHEMA_NEEDED="core nis cosine inetorgperson openldap"
+
+# setup needed schema files
+for f in $SCHEMA_NEEDED; do
+ if [ ! -r tests/schema/$f.schema ]; then
+ mkdir -p tests/schema
+ if [ -r /etc/ldap/schema/$f.schema ]; then
+ ln -s /etc/ldap/schema/$f.schema tests/schema/$f.schema
+ continue;
+ fi
+ if [ -r /etc/openldap/schema/$f.schema ]; then
+ ln -s /etc/openldap/schema/$f.schema tests/schema/$f.schema
+ continue;
+ fi
+
+ echo "SKIPPING TESTS: you need the following OpenLDAP schema files"
+ for f in $SCHEMA_NEEDED; do
+ echo " $f.schema"
+ done
+ exit 0
+ fi
+done
+
+if [ -z "$LDBDIR" ]; then
+ LDBDIR=`dirname $0`/..
+ export LDBDIR
+fi
+
+LDB_URL=`$LDBDIR/tests/ldapi_url.sh`
+export LDB_URL
+
+PATH=bin:$PATH
+export PATH
+
+LDB_SPECIALS=0
+export LDB_SPECIALS
+
+if $LDBDIR/tests/init_slapd.sh &&
+ $LDBDIR/tests/start_slapd.sh &&
+ $LDBDIR/tests/test-generic.sh; then
+ echo "ldap tests passed";
+ ret=0
+else
+ echo "ldap tests failed";
+ ret=$?
+fi
+
+$LDBDIR/tests/kill_slapd.sh
+
+exit $ret
diff --git a/source3/lib/ldb/tests/test-modify.ldif b/source3/lib/ldb/tests/test-modify.ldif
new file mode 100644
index 0000000000..e5b9ca4086
--- /dev/null
+++ b/source3/lib/ldb/tests/test-modify.ldif
@@ -0,0 +1,23 @@
+dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+changetype: modify
+add: drink
+drink: mango lassi
+-
+add: drink
+drink: lemonade
+-
+delete: pager
+-
+replace: telephonenumber
+telephonenumber: +61 2 6260 6012
+telephonenumber: +61 412 666 929
+-
+delete: telephonenumber
+telephonenumber: +61 2 6260 6012
+-
+delete: telephonenumber
+telephonenumber: +61 412 666 929
+-
+add: telephonenumber
+telephonenumber: +61 412 666 929
diff --git a/source3/lib/ldb/tests/test-schema.sh b/source3/lib/ldb/tests/test-schema.sh
new file mode 100755
index 0000000000..2f10fb45e2
--- /dev/null
+++ b/source3/lib/ldb/tests/test-schema.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+LDB_URL="tdb://schema.ldb"
+export LDB_URL
+
+rm -f schema.ldb
+
+echo "LDB_URL: $LDB_URL"
+
+echo "Adding schema"
+$VALGRIND bin/ldbadd $LDBDIR/tests/schema-tests/schema.ldif || exit 1
+
+echo "Adding few test elements (no failure expected here)"
+$VALGRIND bin/ldbadd $LDBDIR/tests/schema-tests/schema-add-test.ldif || exit 1
+
+echo "Modifying elements (2 failures expected here)"
+
+$VALGRIND bin/ldbmodify $LDBDIR/tests/schema-tests/schema-mod-test-1.ldif || exit 1
+$VALGRIND bin/ldbmodify $LDBDIR/tests/schema-tests/schema-mod-test-2.ldif || exit 1
+$VALGRIND bin/ldbmodify $LDBDIR/tests/schema-tests/schema-mod-test-3.ldif || exit 1
+$VALGRIND bin/ldbmodify $LDBDIR/tests/schema-tests/schema-mod-test-4.ldif
+if [ "$?" == "0" ]; then
+ echo "test failed!"
+ exit 1
+fi
+$VALGRIND bin/ldbmodify $LDBDIR/tests/schema-tests/schema-mod-test-5.ldif
+if [ "$?" == "0" ]; then
+ echo "test failed!"
+ exit 1
+fi
+
+echo "Showing modified record"
+$VALGRIND bin/ldbsearch '(cn=Test)' || exit 1
+
diff --git a/source3/lib/ldb/tests/test-sqlite3.sh b/source3/lib/ldb/tests/test-sqlite3.sh
new file mode 100755
index 0000000000..0cef318d98
--- /dev/null
+++ b/source3/lib/ldb/tests/test-sqlite3.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+
+LDB_URL="sqlite3://sqltest.ldb"
+export LDB_URL
+
+rm -f sqltest.ldb
+
+if [ -z "$LDBDIR" ]; then
+ LDBDIR=`dirname $0`/..
+ export LDBDIR
+fi
+
+PATH=bin:$PATH
+export PATH
+
+LDB_SPECIALS=0
+export LDB_SPECIALS
+
+$LDBDIR/tests/test-generic.sh
+
+#. $LDBDIR/tests/test-extended.sh
+
+#. $LDBDIR/tests/test-tdb-features.sh
+
diff --git a/source3/lib/ldb/tests/test-tdb-features.sh b/source3/lib/ldb/tests/test-tdb-features.sh
new file mode 100644
index 0000000000..6f1afdcf33
--- /dev/null
+++ b/source3/lib/ldb/tests/test-tdb-features.sh
@@ -0,0 +1,119 @@
+#!/bin/sh
+
+echo "Running tdb feature tests"
+
+mv $LDB_URL $LDB_URL.2
+
+checkcount() {
+ count=$1
+ expression="$2"
+ n=`bin/ldbsearch "$expression" | grep '^dn' | wc -l`
+ if [ $n != $count ]; then
+ echo "Got $n but expected $count for $expression"
+ $VALGRIND bin/ldbsearch "$expression"
+ exit 1
+ fi
+ echo "OK: $count $expression"
+}
+
+echo "Testing case sensitive search"
+cat <<EOF | $VALGRIND bin/ldbadd || exit 1
+dn: cn=t1,cn=TEST
+objectClass: testclass
+test: foo
+EOF
+checkcount 1 '(test=foo)'
+checkcount 0 '(test=FOO)'
+checkcount 0 '(test=FO*)'
+
+echo "Making case insensitive"
+cat <<EOF | $VALGRIND bin/ldbmodify || exit 1
+dn: @ATTRIBUTES
+changetype: add
+add: test
+test: CASE_INSENSITIVE
+EOF
+
+echo $ldif | $VALGRIND bin/ldbmodify || exit 1
+checkcount 1 '(test=foo)'
+checkcount 1 '(test=FOO)'
+checkcount 1 '(test=fo*)'
+
+echo "adding i"
+cat <<EOF | $VALGRIND bin/ldbmodify || exit 1
+dn: cn=t1,cn=TEST
+changetype: modify
+add: i
+i: 0x100
+EOF
+checkcount 1 '(i=0x100)'
+checkcount 0 '(i=256)'
+
+echo "marking i as INTEGER"
+cat <<EOF | $VALGRIND bin/ldbmodify || exit 1
+dn: @ATTRIBUTES
+changetype: modify
+add: i
+i: INTEGER
+EOF
+checkcount 1 '(i=0x100)'
+checkcount 1 '(i=256)'
+
+echo "adding j"
+cat <<EOF | $VALGRIND bin/ldbmodify || exit 1
+dn: cn=t1,cn=TEST
+changetype: modify
+add: j
+j: 0x100
+EOF
+checkcount 1 '(j=0x100)'
+checkcount 0 '(j=256)'
+
+echo "Adding wildcard attribute"
+cat <<EOF | $VALGRIND bin/ldbmodify || exit 1
+dn: @ATTRIBUTES
+changetype: modify
+add: *
+*: INTEGER
+EOF
+checkcount 1 '(j=0x100)'
+checkcount 1 '(j=256)'
+
+echo "Testing class search"
+checkcount 0 '(objectClass=otherclass)'
+checkcount 1 '(objectClass=testclass)'
+
+echo "Adding subclass"
+cat <<EOF | $VALGRIND bin/ldbmodify || exit 1
+dn: @SUBCLASSES
+changetype: add
+add: otherclass
+otherclass: testclass
+EOF
+checkcount 1 '(objectClass=otherclass)'
+checkcount 1 '(objectClass=testclass)'
+
+echo "Adding index"
+cat <<EOF | $VALGRIND bin/ldbadd || exit 1
+dn: @INDEXLIST
+@IDXATTR: i
+@IDXATTR: test
+EOF
+checkcount 1 '(i=0x100)'
+checkcount 1 '(i=256)'
+checkcount 0 '(i=-256)'
+checkcount 1 '(test=foo)'
+checkcount 1 '(test=FOO)'
+checkcount 1 '(test=*f*o)'
+
+echo "making test case sensitive"
+cat <<EOF | $VALGRIND bin/ldbmodify || exit 1
+dn: @ATTRIBUTES
+changetype: modify
+replace: test
+test: NONE
+EOF
+checkcount 1 '(test=foo)'
+checkcount 0 '(test=FOO)'
+checkcount 1 '(test=f*o*)'
+
diff --git a/source3/lib/ldb/tests/test-tdb.sh b/source3/lib/ldb/tests/test-tdb.sh
new file mode 100755
index 0000000000..7c4f5205b4
--- /dev/null
+++ b/source3/lib/ldb/tests/test-tdb.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+if [ -n "$TEST_DATA_PREFIX" ]; then
+ LDB_URL="$TEST_DATA_PREFIX/tdbtest.ldb"
+else
+ LDB_URL="tdbtest.ldb"
+fi
+export LDB_URL
+
+PATH=bin:$PATH
+export PATH
+
+rm -f $LDB_URL*
+
+if [ -z "$LDBDIR" ]; then
+ LDBDIR=`dirname $0`/..
+ export LDBDIR
+fi
+
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: @MODULES
+@LIST: rdn_name
+EOF
+
+$VALGRIND ldbadd $LDBDIR/tests/init.ldif || exit 1
+
+. $LDBDIR/tests/test-generic.sh
+
+. $LDBDIR/tests/test-extended.sh
+
+. $LDBDIR/tests/test-tdb-features.sh
diff --git a/source3/lib/ldb/tests/test-wildcard.ldif b/source3/lib/ldb/tests/test-wildcard.ldif
new file mode 100644
index 0000000000..222512eeab
--- /dev/null
+++ b/source3/lib/ldb/tests/test-wildcard.ldif
@@ -0,0 +1,5 @@
+dn: cn=test_multi_test_multi_test_multi,o=University of Michigan,c=TEST
+objectclass: person
+cn: test_multi_test_multi_test_multi
+sn: multi_test
+description: test multi wildcards matching
diff --git a/source3/lib/ldb/tests/test-wrong_attributes.ldif b/source3/lib/ldb/tests/test-wrong_attributes.ldif
new file mode 100644
index 0000000000..27f45f0e56
--- /dev/null
+++ b/source3/lib/ldb/tests/test-wrong_attributes.ldif
@@ -0,0 +1,3 @@
+dn: @ATTRIBUTES
+uid: CASE_INTENSIVE
+
diff --git a/source3/lib/ldb/tests/test.ldif b/source3/lib/ldb/tests/test.ldif
new file mode 100644
index 0000000000..e53fadc700
--- /dev/null
+++ b/source3/lib/ldb/tests/test.ldif
@@ -0,0 +1,411 @@
+dn: ou=Groups,o=University of Michigan,c=TEST
+objectclass: organizationalUnit
+ou: Groups
+
+dn: ou=Information Technology Division,ou=People,o=University of Michigan,c=TEST
+objectclass: organizationalUnit
+ou: Information Technology Division
+description:: aMODwoPDgsKCw4PCgsOCwotFVlZQw4PCg8OCwoPDg8KCw4LCv0zDg8KDw4LCgsOD
+ woLDgsKKT8ODwoPDgsKDw4PCgsOCwqs6w4PCg8OCwoLDg8KCw4LCjUQkw4PCg8OCwoLDg8KCw4LCi
+ 01QUcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoLDg8KCw4LCik/Dg8KDw4
+ LCgsODwoLDgsKLRCQoZitEJMODwoPDgsKCw4PCgsOCwrfDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoP
+ Dg8KCw4LCgcODwoPDgsKDw4PCgsOCwqHDg8KDw4LCgsODwoLDgsKLRCQkZitEJMODwoPDgsKCw4PC
+ gsOCwrfDg8KDw4LCg8ODwoLDgsKQw4PCg8OCwoPDg8KCw4LCisODwoPDgsKCw4PCgsOCwotFUVZqU
+ MODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKAw4PCg8OCwoLDg8KCw4LCik85dCTDg8KDw4
+ LCgsODwoLDgsKFQ8ODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4L
+ Cvzl0JMODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoPD
+ gsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKLRCTDg8KDw4LCgsODwoLDgsKDw4PCg8OCwoLDg8KCw
+ 4LCuMODwoPDgsKDw4PCgsOCwoR0Q8ODwoPDgsKCw4PCgsOCwoM9w4PCg8OCwoPDg8KCw4LChMODwo
+ PDgsKDw4PCgsOCwoFOdTrDg8KDw4LCg8ODwoLDgsKHw4PCg8OCwoPDg8KCw4LChMODwoPDgsKDw4P
+ CgsOCwoFOw4PCg8OCwoPDg8KCw4LCqMODwoPDgsKDw4PCgsOCwrtHw4PCg8OCwoLDg8KCw4LChcOD
+ woPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsK4dMODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODw
+ oLDgsKtR8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCiMODwo
+ PDgsKDw4PCgsOCwr9SfGrDg8KDw4LCgsODwoLDgsKLQGgxw4PCg8OCwoPDg8KCw4LCoWhQw4PCg8O
+ CwoPDg8KCw4LCv8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKKT8ODwoPDgsKCw4PCgsOC
+ wotEJDDDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHTDg8KDw4LCgsODwoLDgsKDw4PCg
+ 8OCwoPDg8KCw4LCuHXDg8KDw4LCgsODwoLDgsKLRCRqw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4
+ PCgsOCwojDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpPDg8K
+ Dw4LCg8ODwoLDgsKQXV9eW8ODwoPDgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsKEw4PCg8OCwoPD
+ g8KCw4LCgsODwoPDgsKDw4PCgsOCwozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODw
+ oPDgsKDw4PCgsOCwozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgs
+ OCwoxWV8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKxw4PCg8OCwoLDg8KCw4LCi3wkw4P
+ Cg8OCwoLDg8KCw4LCjcODwoPDgsKCw4PCgsOCwofDg8KDw4LCg8ODwoLDgsKof8ODwoPDgsKDw4PC
+ gsOCwr/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoLDg8KCw4LCg8ODwoPDgsKDw4PCgsOCwrh5w4PCg
+ 8OCwoLDg8KCw4LChzQzw4PCg8OCwoPDg8KCw4LCicODwoPDgsKCw4PCgsOCworDg8KDw4LCgsODwo
+ LDgsKIw4PCg8OCwoLDg8KCw4LCuDFBw4PCg8OCwoPDg8KCw4LCvyTDg8KDw4LCgsODwoLDgsKNdDF
+ Bw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODwoPD
+ gsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwoLDg8KCw
+ 4LCi8ODwoPDgsKDw4PCgsOCwo7Dg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw4LCv8ODwoPDgs
+ KCw4PCgsOCwoTDg8KDw4LCgsODwoLDgsKAdcODwoPDgsKDw4PCgsOCwqhtw4PCg8OCwoLDg8KCw4L
+ ChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKEw4PCg8OCwoPDg8KCw4LCsMODwoPDgsKC
+ w4PCgsOCwrhfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCg8ODwoLDgsKow4PCg8OCwoLDg8KCw4LCt
+ sODwoPDgsKDw4PCgsOCwq7Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4
+ PCgsOCwoPDg8KDw4LCg8ODwoLDgsKoZsODwoPDgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsK4w4P
+ Cg8OCwoLDg8KCw4LCh8ODwoPDgsKDw4PCgsOCwpUzw4PCg8OCwoPDg8KCw4LCicODwoPDgsKCw4PC
+ gsOCworDg8KDw4LCgsODwoLDgsKISDJBw4PCg8OCwoPDg8KCw4LCvyTDg8KDw4LCgsODwoLDgsKNN
+ DJBw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKOw4PCg8OCwo
+ PDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpDDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8O
+ DwoPDgsKDw4PCgsOCwojDg8KDw4LCg8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCnEzDg8KDw4LCgsOD
+ woLDgsKLSEBmw4PCg8OCwoLDg8KCw4LCg3lwdSTDg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw
+ 4LCv8ODwoPDgsKCw4PCgsOCwobDg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODwoPDgs
+ KCw4PCgsOCwp/Dg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwoj
+ Dg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODwoPDgsKCw4PCgsOCwpPDg8KDw4LCgsOD
+ woLDgsKBw4PCg8OCwoPDg8KCw4LCv1rDg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODw
+ oPDgsKCw4PCgsOCwodqw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwoBqaMODwoPDgsKCw4
+ PCgsOCwpBQw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKDIMODwoPDgsKCw4PCgsOCwopPw4PCg8OCwoL
+ Dg8KCw4LChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKOacODwoPDgsKCw4PCgsOCwrhf
+ XsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCw
+ oLDg8KCw4LCgcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKGw4PCg8OCwoLDg8KCw4LCgM
+ ODwoPDgsKCw4PCgsOCwoRJw4PCg8OCwoLDg8KCw4LCgcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsO
+ DwoLDgsKIw4PCg8OCwoLDg8KCw4LCgMODwoPDgsKCw4PCgsOCwoQ9w4PCg8OCwoLDg8KCw4LCgcOD
+ woPDgsKDw4PCgsOCwr9aw4PCg8OCwoLDg8KCw4LCgMODwoPDgsKCw4PCgsOCwoQxw4PCg8OCwoLDg
+ 8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwoM9w4PCg8OCwoPDg8KCw4LCm0
+ 7Dg8KDw4LCgsODwoLDgsKEw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsK
+ Cw4PCgsOCwrhfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLD
+ gsKCw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODw
+ oPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgs
+ OCwo7Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoLDg8KCw4LCkMODwoPDgsKDw4PCgsOCwojDg8KDw4L
+ CgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCiMODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODwoLDgsK+
+ S8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKww4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKDw
+ 4PCgsOCwoTDg8KDw4LCgsODwoLDgsKKT1DDg8KDw4LCg8ODwoLDgsKoRsODwoPDgsKCw4PCgsOCwo
+ vDg8KDw4LCg8ODwoLDgsK4w4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwrZ0Y8ODwoPDgsK
+ Cw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK/dF/Dg8KDw4LCgsODwoLDgsKhdHpPw4PCg8OCwoLDg8KC
+ w4LCi8ODwoPDgsKDw4PCgsOCwo5Qw4PCg8OCwoPDg8KCw4LCqC1Jw4PCg8OCwoLDg8KCw4LChcODw
+ oPDgsKDw4PCgsOCwoB1RMODwoPDgsKCw4PCgsOCwqFwek/Dg8KDw4LCgsODwoLDgsKLw4PCg8OCwo
+ PDg8KCw4LCj1DDg8KDw4LCg8ODwoLDgsKoScODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK
+ AdTPDg8KDw4LCgsODwoLDgsKhbHpPw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo5Qw4PC
+ g8OCwoPDg8KCw4LCqEnDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHXDg8KDw4LCgsODw
+ oLDgsKhaHpPw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo9Qw4PCg8OCwoPDg8KCw4LCqM
+ ODwoPDgsKDw4PCgsOCwrpIw4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwoB1M8ODwoPDgsK
+ Dw4PCgsOCwoBfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLD
+ gsKCw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgjPDg8KDw4LCg8ODwoLDgsKAX17Dg
+ 8KDw4LCg8ODwoLDgsKCw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo7Dg8KDw4LCg8ODwo
+ LDgsKoJ8ODwoPDgsKDw4PCgsOCwq3Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoP
+ DgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsK4aHU5w4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PC
+ gsOCwovDg8KDw4LCg8ODwoLDgsKOw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpDDg8KDw
+ 4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgs
+ KIw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpLDg8KDw4LCg8ODwoLDgsKEw4PCg8OCwoL
+ Dg8KCw4LChcODwoPDgsKDw4PCgsOCwoB0IcODwoPDgsKCw4PCgsOCwovDg8KDw4LCgsODwoLDgsKA
+ w4PCg8OCwoPDg8KCw4LCtMODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsKAdGbDg8KDw4LCg
+ sODwoLDgsKLQGY9dGY9dTPDg8KDw4LCg8ODwoLDgsKAX17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwo
+ LDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODwoPDgsKDw4PCgsO
+ CwoIzw4PCg8OCwoPDg8KCw4LCgF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwovDg8KD
+ w4LCg8ODwoLDgsK/Ri9BUC9BRi9BWi9BZC9BWzBBZC9BZTBBZC9BZC9BbzBBZC9BeTBBw4PCg8OCw
+ oLDg8KCw4LCgzBBMUFhMUFrMUE=
+description:: UF7Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOC
+ wozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOCwozDg8KDw4LCg
+ 8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCqFDDg8KDw4LCg8ODwoLDgsKpRsODwoPDgsKDw4PCgsOCwo
+ zDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOCwozDg8KDw4LCg8O
+ DwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKCw4PCgsOCwotEJCDDg8KDw4LCgsODwoLDgsKD
+ w4PCg8OCwoPDg8KCw4LCrMODwoPDgsKCw4PCgsOCwotUJCRTw4PCg8OCwoLDg8KCw4LCi1wkJFbDg
+ 8KDw4LCgsODwoLDgsKJTCRXVVBSU8ODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODwoLDgsKdT8ODwo
+ PDgsKCw4PCgsOCwoN8JDB1w4PCg8OCwoPDg8KCw4LCh8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCg8O
+ DwoLDgsKBTsODwoPDgsKDw4PCgsOCwqktw4PCg8OCwoLDg8KCw4LCg3wkMHTDg8KDw4LCgsODwoLD
+ gsKDfCQww4PCg8OCwoLDg8KCw4LChTPDg8KDw4LCg8ODwoLDgsK2OTXDg8KDw4LCg8ODwoLDgsKAw
+ 4PCg8OCwoPDg8KCw4LCgU7Dg8KDw4LCgsODwoLDgsKEIMODwoPDgsKCw4PCgsOCwqFIw4PCg8OCwo
+ PDg8KCw4LChU7Dg8KDw4LCgsODwoLDgsKJNcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCg8ODwoLDgsK
+ BTsODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKD
+ w4PCgsOCwr9TXMODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGw4PCg8OCwoLDg8KCw
+ 4LChMODwoPDgsKCw4PCgsOCwpHDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLIEjDg8
+ KDw4LCg8ODwoLDgsKFTlDDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv1Ngw4PCg8OCwoL
+ Dg8KCw4LCi8ODwoPDgsKDw4PCgsOCwpjDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCm3Rx
+ w4PCg8OCwoLDg8KCw4LCizvDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCi8ODwoPDgsKDw
+ 4PCgsOCwr9XaMODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGdGLDg8KDw4LCgsODwo
+ LDgsKLf2zDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCi1D
+ Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCl8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8OD
+ woLDgsKow4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwq10SmgoT03Dg8KDw4LCgsODwoLDg
+ sKLw4PCg8OCwoPDg8KCw4LCjcODwoPDgsKDw4PCgsOCwqggTMODwoPDgsKCw4PCgsOCwoXDg8KDw4
+ LCg8ODwoLDgsKAdDrDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLTSBQUcODwoPDgsK
+ Dw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoLDg8KCw4LCik/Dg8KDw4LCgsODwoLDgsKL
+ RCQoZitEJCDDg8KDw4LCgsODwoLDgsK3w4PCg8OCwoPDg8KCw4LCiMODwoPDgsKDw4PCgsOCwoHDg
+ 8KDw4LCg8ODwoLDgsKhw4PCg8OCwoLDg8KCw4LCi0QkJGYrRCTDg8KDw4LCgsODwoLDgsK3w4PCg8
+ OCwoPDg8KCw4LCkMODwoPDgsKDw4PCgsOCworDg8KDw4LCgsODwoLDgsKLRSBRVmpQw4PCg8OCwoP
+ Dg8KCw4LCv8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKKTzl0JHXDg8KDw4LCgsODwoLD
+ gsKhOXQkw4PCg8OCwoLDg8KCw4LChW/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODw
+ oPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKhRMODwoPDgsKDw4PCgsOCwoVOw4PCg8OCwoLDg8
+ KCw4LCi8ODwoPDgsKDw4PCgsOCwojDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv1Ncw4P
+ Cg8OCwoLDg8KCw4LCiUQkw4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsOD
+ woLDgsKEw4PCg8OCwoPDg8KCw4LCtjPDg8KDw4LCg8ODwoLDgsK2w4PCg8OCwoLDg8KCw4LCjUQkw
+ 4PCg8OCwoLDg8KCw4LCiyBEw4PCg8OCwoPDg8KCw4LChU5Qw4PCg8OCwoLDg8KCw4LCi8ODwoPDgs
+ KDw4PCgsOCwr9TYMODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsK4w4PCg8OCwoLDg8KCw4L
+ ChcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKEw4PCg8OCwoPDg8KCw4LCkMODwoPDgsKC
+ w4PCgsOCwovDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCj8ODwoPDgsKDw4PCgsOCwr9Ta
+ MODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGw4PCg8OCwoLDg8KCw4LChMODwoPDgs
+ KCw4PCgsOCwr3Dg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4L
+ Cj1DDg8KDw4LCg8ODwoLDgsK/U2zDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCqMODwoPD
+ gsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsKtw4PCg8OCwoLDg8KCw4LChMODwoPDgsKCw4PCgsOCw
+ p9oMMODwoPDgsKDw4PCgsOCwolMw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo3Dg8KDw4
+ LCg8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCq0vDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4L
+ CgMODwoPDgsKCw4PCgsOCwoTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoLDg8KCw4LCi0QkOcODwoPD
+ gsKCw4PCgsOCwrDDg8KDw4LCg8ODwoLDgsKEdEU5w4PCg8OCwoLDg8KCw4LCtTR0PcODwoPDgsKCw
+ 4PCgsOCwovDg8KDw4LCg8ODwoLDgsKNw4PCg8OCwoPDg8KCw4LCqMODwoPDgsKDw4PCgsOCwo5Lw4
+ PCg8OCwoLDg8KCw4LCi0AgUMODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKsw4PCg8OCwoL
+ Dg8KCw4LCik/Dg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHUow4PCg8OCwoLDg8KCw4LC
+ i8ODwoPDgsKDw4PCgsOCwo3Dg8KDw4LCgsODwoLDgsKJw4PCg8OCwoLDg8KCw4LCtTTDg8KDw4LCg
+ 8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCl8ODwoPDgsKDw4PCgsOCwrtWw4PCg8OCwoLDg8KCw4LCi8
+ ODwoPDgsKDw4PCgsOCwo3Dg8KDw4LCg8ODwoLDgsKow4PCg8OCwoLDg8KCw4LCnw==
+
+#LEAD COMMENT
+
+# another comment
+dn: CN=All Staff,ou=Groups,o=University of Michigan,c=TEST
+#EMBEDDED COMMENT
+member: cn=Manager,o=University of Michigan,c=TEST
+member: cn=Barbara Jensen,ou=Information Technology Division,ou=People,o=Unive
+ rsity of Michigan,c=TEST
+member: cn=Jane Doe,ou=Alumni Association,ou=People,o=University of Michigan,c
+ =US
+member: cn=John Doe,ou=Information Technology Division,ou=People,o=University
+ of Michigan,c=TEST
+member: cn=Mark Elliot,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=TEST
+member: cn=James A Jones 2,ou=Information Technology Division,ou=People,o=Univ
+ ersity of Michigan,c=TEST
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,o=University of Mich
+ igan,c=TEST
+member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=TEST
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=TEST
+member: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=Univers
+ ity of Michigan,c=TEST
+owner: cn=Manager,o=University of Michigan,c=TEST
+cn: All Staff
+description: Everyone in the sample data
+objectclass: groupofnames
+
+dn: cn=Alumni Assoc Staff,ou=Groups,o=University of Michigan,c=TEST
+member: cn=Manager,o=University of Michigan,c=TEST
+member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=TEST
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=TEST
+member: cn=Jane Doe,ou=Alumni Association,ou=People,o=University of Michigan,c
+ =US
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,o=University of Mich
+ igan,c=TEST
+member: cn=Mark Elliot,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=TEST
+owner: cn=Manager,o=University of Michigan,c=TEST
+description: All Alumni Assoc Staff
+cn: Alumni Assoc Staff
+objectclass: groupofnames
+
+dn: ou=Alumni Association,ou=People,o=University of Michigan,c=TEST
+objectclass: organizationalUnit
+ou: Alumni Association
+
+dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,o=Universit
+ y of Michigan,c=TEST
+objectclass: OpenLDAPperson
+cn: Barbara Jensen
+cn: Babs Jensen
+sn:: IEplbnNlbiA=
+uid:: YmplCW5zZW4
+title: Mythical Manager, Research Systems
+postaladdress: ITD Prod Dev & Deployment $ 535 W. William St. Room 4212 $ Ann
+ Arbor, MI 48103-4943
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+userpassword:: YmplbnNlbg==
+mail: bjensen@mailgw.example.com
+homepostaladdress: 123 Wesley $ Ann Arbor, MI 48103
+description: Mythical manager of the rsdd unix project
+drink: water
+homephone: +1 313 555 2333
+pager: +1 313 555 3233
+facsimiletelephonenumber: +1 313 555 2274
+telephonenumber: +1 313 555 9022
+
+dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=University
+ of Michigan,c=TEST
+objectclass: OpenLDAPperson
+cn: Bjorn Jensen
+cn: Biiff Jensen
+sn: Jensen
+uid: bjorn
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+userpassword:: Ympvcm4=
+homepostaladdress: 19923 Seven Mile Rd. $ South Lyon, MI 49999
+drink: Iced Tea
+description: Hiker, biker
+title: Director, Embedded Systems
+postaladdress: Info Tech Division $ 535 W. William St. $ Ann Arbor, MI 48103
+mail: bjorn@mailgw.example.com
+homephone: +1 313 555 5444
+pager: +1 313 555 4474
+facsimiletelephonenumber: +1 313 555 2177
+telephonenumber: +1 313 555 0355
+
+dn: cn=Dorothy Stevens,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+objectclass: OpenLDAPperson
+cn: Dorothy Stevens
+cn: Dot Stevens
+sn: Stevens
+uid: dots
+title: Secretary, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+drink: Lemonade
+homepostaladdress: 377 White St. Apt. 3 $ Ann Arbor, MI 48104
+description: Very tall
+facsimiletelephonenumber: +1 313 555 3223
+telephonenumber: +1 313 555 3664
+mail: dots@mail.alumni.example.com
+homephone: +1 313 555 0454
+
+dn: cn=ITD Staff,ou=Groups,o=University of Michigan,c=TEST
+owner: cn=Manager,o=University of Michigan,c=TEST
+description: All ITD Staff
+cn: ITD Staff
+objectclass: groupofuniquenames
+uniquemember: cn=Manager,o=University of Michigan,c=TEST
+uniquemember: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=U
+ niversity of Michigan,c=TEST
+uniquemember: cn=James A Jones 2,ou=Information Technology Division,ou=People,
+ o=University of Michigan,c=TEST
+uniquemember: cn=John Doe,ou=Information Technology Division,ou=People,o=Unive
+ rsity of Michigan,c=TEST
+
+dn: cn=James A Jones 1,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+objectclass: OpenLDAPperson
+cn: James A Jones 1
+cn: James Jones
+cn: Jim Jones
+sn: Jones
+uid: jaj
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+userpassword:: amFq
+homepostaladdress: 3882 Beverly Rd. $ Ann Arbor, MI 48105
+homephone: +1 313 555 4772
+description: Outstanding
+title: Mad Cow Researcher, UM Alumni Association
+pager: +1 313 555 3923
+mail: jaj@mail.alumni.example.com
+facsimiletelephonenumber: +1 313 555 4332
+telephonenumber: +1 313 555 0895
+
+dn: cn=James A Jones 2,ou=Information Technology Division,ou=People,o=Universi
+ ty of Michigan,c=TEST
+objectclass: OpenLDAPperson
+cn: James A Jones 2
+cn: James Jones
+cn: Jim Jones
+sn: Doe
+uid: jjones
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+homepostaladdress: 933 Brooks $ Ann Arbor, MI 48104
+homephone: +1 313 555 8838
+title: Senior Manager, Information Technology Division
+description: Not around very much
+mail: jjones@mailgw.example.com
+postaladdress: Info Tech Division $ 535 W William $ Ann Arbor, MI 48103
+pager: +1 313 555 2833
+facsimiletelephonenumber: +1 313 555 8688
+telephonenumber: +1 313 555 7334
+
+dn: cn=Jane Doe,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST
+objectclass: OpenLDAPperson
+cn: Jane Doe
+cn: Jane Alverson
+sn: Doe
+uid: jdoe
+title: Programmer Analyst, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+homepostaladdress: 123 Anystreet $ Ann Arbor, MI 48104
+drink: diet coke
+description: Enthusiastic
+mail: jdoe@woof.net
+homephone: +1 313 555 5445
+pager: +1 313 555 1220
+facsimiletelephonenumber: +1 313 555 2311
+telephonenumber: +1 313 555 4774
+
+dn: cn=Jennifer Smith,ou=Alumni Association,ou=People,o=University of Michigan
+ ,c=TEST
+objectclass: OpenLDAPperson
+cn: Jennifer Smith
+cn: Jen Smith
+sn: Smith
+uid: jen
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+drink: Sam Adams
+homepostaladdress: 1000 Maple #44 $ Ann Arbor, MI 48103
+title: Telemarketer, UM Alumni Association
+mail: jen@mail.alumni.example.com
+homephone: +1 313 555 2333
+pager: +1 313 555 6442
+facsimiletelephonenumber: +1 313 555 2756
+telephonenumber: +1 313 555 8232
+
+dn: cn=John Doe,ou=Information Technology Division,ou=People,o=University of M
+ ichigan,c=TEST
+objectclass: OpenLDAPperson
+cn: John Doe
+cn: Jonathon Doe
+sn: Doe
+uid: johnd
+postaladdress: ITD $ 535 W. William $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+homepostaladdress: 912 East Bllvd $ Ann Arbor, MI 48104
+title: System Administrator, Information Technology Division
+description: overworked!
+mail: johnd@mailgw.example.com
+homephone: +1 313 555 3774
+pager: +1 313 555 6573
+facsimiletelephonenumber: +1 313 555 4544
+telephonenumber: +1 313 555 9394
+
+dn: cn=Manager,o=University of Michigan,c=TEST
+objectclass: person
+cn: Manager
+cn: Directory Manager
+cn: Dir Man
+sn: Manager
+description: Manager of the directory
+userpassword:: c2VjcmV0
+
+dn: cn=Mark Elliot,ou=Alumni Association,ou=People,o=University of Michigan,c=
+ TEST
+objectclass: OpenLDAPperson
+cn: Mark Elliot
+cn: Mark A Elliot
+sn: Elliot
+uid: melliot
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+homepostaladdress: 199 Outer Drive $ Ypsilanti, MI 48198
+homephone: +1 313 555 0388
+drink: Gasoline
+title: Director, UM Alumni Association
+mail: melliot@mail.alumni.example.com
+pager: +1 313 555 7671
+facsimiletelephonenumber: +1 313 555 7762
+telephonenumber: +1 313 555 4177
+
+dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+objectclass: OpenLDAPperson
+cn: Ursula Hampster
+sn: Hampster
+uid: uham
+title: Secretary, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+homepostaladdress: 123 Anystreet $ Ann Arbor, MI 48104
+mail: uham@mail.alumni.example.com
+description: a long attribute name, longer than 128 bytes so that we
+ trigger sign extension problems in tdb_pack, no thats not long enough
+ yet, maybe this is. I'll just keep going till it triggers the error
+homephone: +1 313 555 8421
+pager: +1 313 555 2844
+facsimiletelephonenumber: +1 313 555 9700
+telephonenumber: +1 313 555 5331
diff --git a/source3/lib/ldb/tests/testdata.txt b/source3/lib/ldb/tests/testdata.txt
new file mode 100644
index 0000000000..dadb9f0f98
--- /dev/null
+++ b/source3/lib/ldb/tests/testdata.txt
@@ -0,0 +1,8 @@
+foo=bar5
+(&(|(a=b)(c=d))(e=f))
+(&(|(a=b)(c=d)(g=h))(e=f))
+name=firstname lastname
+(&(sid=S-1-2-3)(name = fred bloggs))
+(&(|(a=b)(c=d))(g=f))
+(&(sid=S-1-2-3)(!(name = fred bloggs)))
+(&(!(|(a=b)(c=d))(g=f)))
diff --git a/source3/lib/ldb/tests/testsearch.txt b/source3/lib/ldb/tests/testsearch.txt
new file mode 100644
index 0000000000..c5738639b7
--- /dev/null
+++ b/source3/lib/ldb/tests/testsearch.txt
@@ -0,0 +1,5 @@
+(blah=foo)
+(objectclass=person)
+(dn=*)
+(&(objectclass=person)(objectclass=person))
+(&(objectclass=person)(objectclass=personx))
diff --git a/source3/lib/ldb/tools/ad2oLschema.c b/source3/lib/ldb/tools/ad2oLschema.c
new file mode 100644
index 0000000000..fc51cb12d8
--- /dev/null
+++ b/source3/lib/ldb/tools/ad2oLschema.c
@@ -0,0 +1,629 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Bartlett 2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ad2oLschema
+ *
+ * Description: utility to convert an AD schema into the format required by OpenLDAP
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+#include "system/locale.h"
+#include "ldb/tools/cmdline.h"
+#include "ldb/tools/convert.h"
+
+struct schema_conv {
+ int count;
+ int skipped;
+ int failures;
+};
+
+enum convert_target {
+ TARGET_OPENLDAP,
+ TARGET_FEDORA_DS
+};
+
+
+static void usage(void)
+{
+ printf("Usage: ad2oLschema <options>\n");
+ printf("\nConvert AD-like LDIF to OpenLDAP schema format\n\n");
+ printf("Options:\n");
+ printf(" -I inputfile inputfile of mapped OIDs and skipped attributes/ObjectClasses");
+ printf(" -H url LDB or LDAP server to read schmea from\n");
+ printf(" -O outputfile outputfile otherwise STDOUT\n");
+ printf(" -o options pass options like modules to activate\n");
+ printf(" e.g: -o modules:timestamps\n");
+ printf("\n");
+ printf("Converts records from an AD-like LDIF schema into an openLdap formatted schema\n\n");
+ exit(1);
+}
+
+static int fetch_attrs_schema(struct ldb_context *ldb, struct ldb_dn *schemadn,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_result **attrs_res)
+{
+ TALLOC_CTX *local_ctx = talloc_new(mem_ctx);
+ int ret;
+ const char *attrs[] = {
+ "lDAPDisplayName",
+ "isSingleValued",
+ "attributeID",
+ "attributeSyntax",
+ "description",
+ NULL
+ };
+
+ if (!local_ctx) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Downlaod schema */
+ ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE,
+ "objectClass=attributeSchema",
+ attrs, attrs_res);
+ if (ret != LDB_SUCCESS) {
+ printf("Search failed: %s\n", ldb_errstring(ldb));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ret;
+}
+
+static const char *oc_attrs[] = {
+ "lDAPDisplayName",
+ "mayContain",
+ "mustContain",
+ "systemMayContain",
+ "systemMustContain",
+ "objectClassCategory",
+ "governsID",
+ "description",
+ "subClassOf",
+ NULL
+};
+
+static int fetch_oc_recursive(struct ldb_context *ldb, struct ldb_dn *schemadn,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_result *search_from,
+ struct ldb_result *res_list)
+{
+ int i;
+ int ret = 0;
+ for (i=0; i < search_from->count; i++) {
+ struct ldb_result *res;
+ const char *name = ldb_msg_find_attr_as_string(search_from->msgs[i],
+ "lDAPDisplayname", NULL);
+ char *filter = talloc_asprintf(mem_ctx, "(&(&(objectClass=classSchema)(subClassOf=%s))(!(lDAPDisplayName=%s)))",
+ name, name);
+
+ ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE,
+ filter,
+ oc_attrs, &res);
+ talloc_free(filter);
+ if (ret != LDB_SUCCESS) {
+ printf("Search failed: %s\n", ldb_errstring(ldb));
+ return ret;
+ }
+
+ talloc_steal(mem_ctx, res);
+
+ res_list->msgs = talloc_realloc(res_list, res_list->msgs,
+ struct ldb_message *, res_list->count + 2);
+ if (!res_list->msgs) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ res_list->msgs[res_list->count] = talloc_move(res_list,
+ &search_from->msgs[i]);
+ res_list->count++;
+ res_list->msgs[res_list->count] = NULL;
+
+ if (res->count > 0) {
+ ret = fetch_oc_recursive(ldb, schemadn, mem_ctx, res, res_list);
+ }
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static int fetch_objectclass_schema(struct ldb_context *ldb, struct ldb_dn *schemadn,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_result **objectclasses_res)
+{
+ TALLOC_CTX *local_ctx = talloc_new(mem_ctx);
+ struct ldb_result *top_res, *ret_res;
+ int ret;
+ if (!local_ctx) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Downlaod 'top' */
+ ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE,
+ "(&(objectClass=classSchema)(lDAPDisplayName=top))",
+ oc_attrs, &top_res);
+ if (ret != LDB_SUCCESS) {
+ printf("Search failed: %s\n", ldb_errstring(ldb));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ talloc_steal(local_ctx, top_res);
+
+ if (top_res->count != 1) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret_res = talloc_zero(local_ctx, struct ldb_result);
+ if (!ret_res) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = fetch_oc_recursive(ldb, schemadn, local_ctx, top_res, ret_res);
+
+ if (ret != LDB_SUCCESS) {
+ printf("Search failed: %s\n", ldb_errstring(ldb));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *objectclasses_res = talloc_move(mem_ctx, &ret_res);
+ return ret;
+}
+
+static struct ldb_dn *find_schema_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
+{
+ const char *rootdse_attrs[] = {"schemaNamingContext", NULL};
+ struct ldb_dn *schemadn;
+ struct ldb_dn *basedn = ldb_dn_explode(mem_ctx, "");
+ struct ldb_result *rootdse_res;
+ int ldb_ret;
+ if (!basedn) {
+ return NULL;
+ }
+
+ /* Search for rootdse */
+ ldb_ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, NULL, rootdse_attrs, &rootdse_res);
+ if (ldb_ret != LDB_SUCCESS) {
+ printf("Search failed: %s\n", ldb_errstring(ldb));
+ return NULL;
+ }
+
+ talloc_steal(mem_ctx, rootdse_res);
+
+ if (rootdse_res->count != 1) {
+ printf("Failed to find rootDSE");
+ return NULL;
+ }
+
+ /* Locate schema */
+ schemadn = ldb_msg_find_attr_as_dn(mem_ctx, rootdse_res->msgs[0], "schemaNamingContext");
+ if (!schemadn) {
+ return NULL;
+ }
+
+ talloc_free(rootdse_res);
+ return schemadn;
+}
+
+#define IF_NULL_FAIL_RET(x) do { \
+ if (!x) { \
+ ret.failures++; \
+ return ret; \
+ } \
+ } while (0)
+
+
+static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_target target, FILE *in, FILE *out)
+{
+ /* Read list of attributes to skip, OIDs to map */
+ TALLOC_CTX *mem_ctx = talloc_new(ldb);
+ char *line;
+ const char **attrs_skip = NULL;
+ int num_skip = 0;
+ struct oid_map {
+ char *old_oid;
+ char *new_oid;
+ } *oid_map = NULL;
+ int num_maps = 0;
+ struct ldb_result *attrs_res, *objectclasses_res;
+ struct ldb_dn *schemadn;
+ struct schema_conv ret;
+
+ int ldb_ret, i;
+
+ ret.count = 0;
+ ret.skipped = 0;
+ ret.failures = 0;
+
+ while ((line = afdgets(fileno(in), mem_ctx, 0))) {
+ /* Blank Line */
+ if (line[0] == '\0') {
+ continue;
+ }
+ /* Comment */
+ if (line[0] == '#') {
+ continue;
+ }
+ if (isdigit(line[0])) {
+ char *p = strchr(line, ':');
+ IF_NULL_FAIL_RET(p);
+ if (!p) {
+ ret.failures = 1;
+ return ret;
+ }
+ p[0] = '\0';
+ p++;
+ oid_map = talloc_realloc(mem_ctx, oid_map, struct oid_map, num_maps + 2);
+ trim_string(line, " ", " ");
+ oid_map[num_maps].old_oid = talloc_move(oid_map, &line);
+ trim_string(p, " ", " ");
+ oid_map[num_maps].new_oid = p;
+ num_maps++;
+ oid_map[num_maps].old_oid = NULL;
+ } else {
+ attrs_skip = talloc_realloc(mem_ctx, attrs_skip, const char *, num_skip + 2);
+ trim_string(line, " ", " ");
+ attrs_skip[num_skip] = talloc_move(attrs_skip, &line);
+ num_skip++;
+ attrs_skip[num_skip] = NULL;
+ }
+ }
+
+ schemadn = find_schema_dn(ldb, mem_ctx);
+ if (!schemadn) {
+ printf("Failed to find schema DN: %s\n", ldb_errstring(ldb));
+ ret.failures = 1;
+ return ret;
+ }
+
+ ldb_ret = fetch_attrs_schema(ldb, schemadn, mem_ctx, &attrs_res);
+ if (ldb_ret != LDB_SUCCESS) {
+ printf("Failed to fetch attribute schema: %s\n", ldb_errstring(ldb));
+ ret.failures = 1;
+ return ret;
+ }
+
+ switch (target) {
+ case TARGET_OPENLDAP:
+ break;
+ case TARGET_FEDORA_DS:
+ fprintf(out, "dn: cn=schema\n");
+ break;
+ }
+
+ for (i=0; i < attrs_res->count; i++) {
+ struct ldb_message *msg = attrs_res->msgs[i];
+
+ const char *name = ldb_msg_find_attr_as_string(msg, "lDAPDisplayName", NULL);
+ const char *description = ldb_msg_find_attr_as_string(msg, "description", NULL);
+ const char *oid = ldb_msg_find_attr_as_string(msg, "attributeID", NULL);
+ const char *syntax = ldb_msg_find_attr_as_string(msg, "attributeSyntax", NULL);
+ BOOL single_value = ldb_msg_find_attr_as_bool(msg, "isSingleValued", False);
+ const struct syntax_map *map = find_syntax_map_by_ad_oid(syntax);
+ char *schema_entry = NULL;
+ int j;
+
+ /* We have been asked to skip some attributes/objectClasses */
+ if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
+ ret.skipped++;
+ continue;
+ }
+
+ /* We might have been asked to remap this oid, due to a conflict */
+ for (j=0; oid && oid_map[j].old_oid; j++) {
+ if (strcmp(oid, oid_map[j].old_oid) == 0) {
+ oid = oid_map[j].new_oid;
+ break;
+ }
+ }
+
+ switch (target) {
+ case TARGET_OPENLDAP:
+ schema_entry = talloc_asprintf(mem_ctx,
+ "attributetype (\n"
+ " %s\n", oid);
+ break;
+ case TARGET_FEDORA_DS:
+ schema_entry = talloc_asprintf(mem_ctx,
+ "attributeTypes: (\n"
+ " %s\n", oid);
+ break;
+ }
+ IF_NULL_FAIL_RET(schema_entry);
+
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " NAME '%s'\n", name);
+ IF_NULL_FAIL_RET(schema_entry);
+
+ if (description) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " DESC %s\n", description);
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+
+ if (map) {
+ const char *syntax_oid;
+ if (map->equality) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " EQUALITY %s\n", map->equality);
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+ if (map->substring) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " SUBSTR %s\n", map->substring);
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+ syntax_oid = map->Standard_OID;
+ /* We might have been asked to remap this oid,
+ * due to a conflict, or lack of
+ * implementation */
+ for (j=0; syntax_oid && oid_map[j].old_oid; j++) {
+ if (strcmp(syntax_oid, oid_map[j].old_oid) == 0) {
+ syntax_oid = oid_map[j].new_oid;
+ break;
+ }
+ }
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " SYNTAX %s\n", syntax_oid);
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+
+ if (single_value) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " SINGLE-VALUE\n");
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " )");
+
+ switch (target) {
+ case TARGET_OPENLDAP:
+ fprintf(out, "%s\n\n", schema_entry);
+ break;
+ case TARGET_FEDORA_DS:
+ fprintf(out, "%s\n", schema_entry);
+ break;
+ }
+ ret.count++;
+ }
+
+ ldb_ret = fetch_objectclass_schema(ldb, schemadn, mem_ctx, &objectclasses_res);
+ if (ldb_ret != LDB_SUCCESS) {
+ printf("Failed to fetch objectClass schema elements: %s\n", ldb_errstring(ldb));
+ ret.failures = 1;
+ return ret;
+ }
+
+ for (i=0; i < objectclasses_res->count; i++) {
+ struct ldb_message *msg = objectclasses_res->msgs[i];
+ const char *name = ldb_msg_find_attr_as_string(msg, "lDAPDisplayName", NULL);
+ const char *description = ldb_msg_find_attr_as_string(msg, "description", NULL);
+ const char *oid = ldb_msg_find_attr_as_string(msg, "governsID", NULL);
+ const char *subClassOf = ldb_msg_find_attr_as_string(msg, "subClassOf", NULL);
+ int objectClassCategory = ldb_msg_find_attr_as_int(msg, "objectClassCategory", 0);
+ struct ldb_message_element *must = ldb_msg_find_element(msg, "mustContain");
+ struct ldb_message_element *sys_must = ldb_msg_find_element(msg, "systemMustContain");
+ struct ldb_message_element *may = ldb_msg_find_element(msg, "mayContain");
+ struct ldb_message_element *sys_may = ldb_msg_find_element(msg, "systemMayContain");
+ char *schema_entry = NULL;
+ int j;
+
+ /* We have been asked to skip some attributes/objectClasses */
+ if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
+ ret.skipped++;
+ continue;
+ }
+
+ /* We might have been asked to remap this oid, due to a conflict */
+ for (j=0; oid_map[j].old_oid; j++) {
+ if (strcmp(oid, oid_map[j].old_oid) == 0) {
+ oid = oid_map[j].new_oid;
+ break;
+ }
+ }
+
+ switch (target) {
+ case TARGET_OPENLDAP:
+ schema_entry = talloc_asprintf(mem_ctx,
+ "objectclass (\n"
+ " %s\n", oid);
+ break;
+ case TARGET_FEDORA_DS:
+ schema_entry = talloc_asprintf(mem_ctx,
+ "objectClasses: (\n"
+ " %s\n", oid);
+ break;
+ }
+ IF_NULL_FAIL_RET(schema_entry);
+ if (!schema_entry) {
+ ret.failures++;
+ break;
+ }
+
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " NAME '%s'\n", name);
+ IF_NULL_FAIL_RET(schema_entry);
+
+ if (!schema_entry) return ret;
+
+ if (description) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " DESC %s\n", description);
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+
+ if (subClassOf) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " SUP %s\n", subClassOf);
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+
+ switch (objectClassCategory) {
+ case 1:
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " STRUCTURAL\n");
+ IF_NULL_FAIL_RET(schema_entry);
+ break;
+ case 2:
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " ABSTRACT\n");
+ IF_NULL_FAIL_RET(schema_entry);
+ break;
+ case 3:
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " AUXILIARY\n");
+ IF_NULL_FAIL_RET(schema_entry);
+ break;
+ }
+
+#define APPEND_ATTRS(attributes) \
+ do { \
+ int k; \
+ for (k=0; attributes && k < attributes->num_values; k++) { \
+ schema_entry = talloc_asprintf_append(schema_entry, \
+ " %s", \
+ (const char *)attributes->values[k].data); \
+ IF_NULL_FAIL_RET(schema_entry); \
+ if (k != (attributes->num_values - 1)) { \
+ schema_entry = talloc_asprintf_append(schema_entry, \
+ " $"); \
+ IF_NULL_FAIL_RET(schema_entry); \
+ if (target == TARGET_OPENLDAP && ((k+1)%5 == 0)) { \
+ schema_entry = talloc_asprintf_append(schema_entry, \
+ "\n "); \
+ IF_NULL_FAIL_RET(schema_entry); \
+ } \
+ } \
+ } \
+ } while (0)
+
+ if (must || sys_must) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " MUST (");
+ IF_NULL_FAIL_RET(schema_entry);
+
+ APPEND_ATTRS(must);
+ if (must && sys_must) {
+ schema_entry = talloc_asprintf_append(schema_entry, \
+ " $"); \
+ }
+ APPEND_ATTRS(sys_must);
+
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " )\n");
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+
+ if (may || sys_may) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " MAY (");
+ IF_NULL_FAIL_RET(schema_entry);
+
+ APPEND_ATTRS(may);
+ if (may && sys_may) {
+ schema_entry = talloc_asprintf_append(schema_entry, \
+ " $"); \
+ }
+ APPEND_ATTRS(sys_may);
+
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " )\n");
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " )");
+
+ switch (target) {
+ case TARGET_OPENLDAP:
+ fprintf(out, "%s\n\n", schema_entry);
+ break;
+ case TARGET_FEDORA_DS:
+ fprintf(out, "%s\n", schema_entry);
+ break;
+ }
+ ret.count++;
+ }
+
+ return ret;
+}
+
+ int main(int argc, const char **argv)
+{
+ TALLOC_CTX *ctx;
+ struct ldb_cmdline *options;
+ FILE *in = stdin;
+ FILE *out = stdout;
+ struct ldb_context *ldb;
+ struct schema_conv ret;
+ const char *target_str;
+ enum convert_target target;
+
+ ldb_global_init();
+
+ ctx = talloc_new(NULL);
+ ldb = ldb_init(ctx);
+
+ options = ldb_cmdline_process(ldb, argc, argv, usage);
+
+ if (options->input) {
+ in = fopen(options->input, "r");
+ if (!in) {
+ perror(options->input);
+ exit(1);
+ }
+ }
+ if (options->output) {
+ out = fopen(options->output, "w");
+ if (!out) {
+ perror(options->output);
+ exit(1);
+ }
+ }
+
+ target_str = lp_parm_string(-1, "convert", "target");
+
+ if (!target_str || strcasecmp(target_str, "openldap") == 0) {
+ target = TARGET_OPENLDAP;
+ } else if (strcasecmp(target_str, "fedora-ds") == 0) {
+ target = TARGET_FEDORA_DS;
+ } else {
+ printf("Unsupported target: %s\n", target_str);
+ exit(1);
+ }
+
+ ret = process_convert(ldb, target, in, out);
+
+ fclose(in);
+ fclose(out);
+
+ printf("Converted %d records (skipped %d) with %d failures\n", ret.count, ret.skipped, ret.failures);
+
+ return 0;
+}
diff --git a/source3/lib/ldb/tools/cmdline.c b/source3/lib/ldb/tools/cmdline.c
new file mode 100644
index 0000000000..4744ab4989
--- /dev/null
+++ b/source3/lib/ldb/tools/cmdline.c
@@ -0,0 +1,754 @@
+/*
+ ldb database library - command line handling for ldb tools
+
+ Copyright (C) Andrew Tridgell 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+#include "ldb/tools/cmdline.h"
+
+#if (_SAMBA_BUILD_ >= 4)
+#include "lib/cmdline/popt_common.h"
+#include "lib/ldb/samba/ldif_handlers.h"
+#include "auth/gensec/gensec.h"
+#include "auth/auth.h"
+#include "db_wrap.h"
+#endif
+
+
+
+/*
+ process command line options
+*/
+struct ldb_cmdline *ldb_cmdline_process(struct ldb_context *ldb, int argc, const char **argv,
+ void (*usage)(void))
+{
+ static struct ldb_cmdline options; /* needs to be static for older compilers */
+ struct ldb_cmdline *ret=NULL;
+ poptContext pc;
+#if (_SAMBA_BUILD_ >= 4)
+ int r;
+#endif
+ int num_options = 0;
+ int opt;
+ int flags = 0;
+
+ struct poptOption popt_options[] = {
+ POPT_AUTOHELP
+ { "url", 'H', POPT_ARG_STRING, &options.url, 0, "database URL", "URL" },
+ { "basedn", 'b', POPT_ARG_STRING, &options.basedn, 0, "base DN", "DN" },
+ { "editor", 'e', POPT_ARG_STRING, &options.editor, 0, "external editor", "PROGRAM" },
+ { "scope", 's', POPT_ARG_STRING, NULL, 's', "search scope", "SCOPE" },
+ { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "increase verbosity", NULL },
+ { "interactive", 'i', POPT_ARG_NONE, &options.interactive, 0, "input from stdin", NULL },
+ { "recursive", 'r', POPT_ARG_NONE, &options.recursive, 0, "recursive delete", NULL },
+ { "num-searches", 0, POPT_ARG_INT, &options.num_searches, 0, "number of test searches", NULL },
+ { "num-records", 0, POPT_ARG_INT, &options.num_records, 0, "number of test records", NULL },
+ { "all", 'a', POPT_ARG_NONE, &options.all_records, 0, "(|(objectClass=*)(distinguishedName=*))", NULL },
+ { "nosync", 0, POPT_ARG_NONE, &options.nosync, 0, "non-synchronous transactions", NULL },
+ { "sorted", 'S', POPT_ARG_NONE, &options.sorted, 0, "sort attributes", NULL },
+ { "sasl-mechanism", 0, POPT_ARG_STRING, &options.sasl_mechanism, 0, "choose SASL mechanism", "MECHANISM" },
+ { "input", 'I', POPT_ARG_STRING, &options.input, 0, "Input File", "Input" },
+ { "output", 'O', POPT_ARG_STRING, &options.output, 0, "Output File", "Output" },
+ { NULL, 'o', POPT_ARG_STRING, NULL, 'o', "ldb_connect option", "OPTION" },
+ { "controls", 0, POPT_ARG_STRING, NULL, 'c', "controls", NULL },
+#if (_SAMBA_BUILD_ >= 4)
+ POPT_COMMON_SAMBA
+ POPT_COMMON_CREDENTIALS
+ POPT_COMMON_VERSION
+#endif
+ { NULL }
+ };
+
+ ldb_global_init();
+
+#if (_SAMBA_BUILD_ >= 4)
+ r = ldb_register_samba_handlers(ldb);
+ if (r != 0) {
+ goto failed;
+ }
+
+#endif
+
+ ret = talloc_zero(ldb, struct ldb_cmdline);
+ if (ret == NULL) {
+ ldb_oom(ldb);
+ goto failed;
+ }
+
+ options = *ret;
+
+ /* pull in URL */
+ options.url = getenv("LDB_URL");
+
+ /* and editor (used by ldbedit) */
+ options.editor = getenv("VISUAL");
+ if (!options.editor) {
+ options.editor = getenv("EDITOR");
+ }
+ if (!options.editor) {
+ options.editor = "vi";
+ }
+
+ options.scope = LDB_SCOPE_DEFAULT;
+
+ pc = poptGetContext(argv[0], argc, argv, popt_options,
+ POPT_CONTEXT_KEEP_FIRST);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 's': {
+ const char *arg = poptGetOptArg(pc);
+ if (strcmp(arg, "base") == 0) {
+ options.scope = LDB_SCOPE_BASE;
+ } else if (strcmp(arg, "sub") == 0) {
+ options.scope = LDB_SCOPE_SUBTREE;
+ } else if (strcmp(arg, "one") == 0) {
+ options.scope = LDB_SCOPE_ONELEVEL;
+ } else {
+ fprintf(stderr, "Invalid scope '%s'\n", arg);
+ goto failed;
+ }
+ break;
+ }
+
+ case 'v':
+ options.verbose++;
+ break;
+
+ case 'o':
+ options.options = talloc_realloc(ret, options.options,
+ const char *, num_options+3);
+ if (options.options == NULL) {
+ ldb_oom(ldb);
+ goto failed;
+ }
+ options.options[num_options] = poptGetOptArg(pc);
+ options.options[num_options+1] = NULL;
+ num_options++;
+ break;
+
+ case 'c': {
+ const char *cs = poptGetOptArg(pc);
+ const char *p, *q;
+ int cc;
+
+ for (p = cs, cc = 1; (q = strchr(p, ',')); cc++, p = q + 1) ;
+
+ options.controls = talloc_array(ret, char *, cc + 1);
+ if (options.controls == NULL) {
+ ldb_oom(ldb);
+ goto failed;
+ }
+ for (p = cs, cc = 0; p != NULL; cc++) {
+ const char *t;
+
+ t = strchr(p, ',');
+ if (t == NULL) {
+ options.controls[cc] = talloc_strdup(options.controls, p);
+ p = NULL;
+ } else {
+ options.controls[cc] = talloc_strndup(options.controls, p, t-p);
+ p = t + 1;
+ }
+ }
+ options.controls[cc] = NULL;
+
+ break;
+ }
+ default:
+ fprintf(stderr, "Invalid option %s: %s\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ if (usage) usage();
+ goto failed;
+ }
+ }
+
+ /* setup the remaining options for the main program to use */
+ options.argv = poptGetArgs(pc);
+ if (options.argv) {
+ options.argv++;
+ while (options.argv[options.argc]) options.argc++;
+ }
+
+ *ret = options;
+
+ /* all utils need some option */
+ if (ret->url == NULL) {
+ fprintf(stderr, "You must supply a url with -H or with $LDB_URL\n");
+ if (usage) usage();
+ goto failed;
+ }
+
+ if (strcmp(ret->url, "NONE") == 0) {
+ return ret;
+ }
+
+ if (options.nosync) {
+ flags |= LDB_FLG_NOSYNC;
+ }
+
+#if (_SAMBA_BUILD_ >= 4)
+ /* Must be after we have processed command line options */
+ gensec_init();
+
+ if (ldb_set_opaque(ldb, "sessionInfo", system_session(ldb))) {
+ goto failed;
+ }
+ if (ldb_set_opaque(ldb, "credentials", cmdline_credentials)) {
+ goto failed;
+ }
+ ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
+#endif
+
+ /* now connect to the ldb */
+ if (ldb_connect(ldb, ret->url, flags, ret->options) != 0) {
+ fprintf(stderr, "Failed to connect to %s - %s\n",
+ ret->url, ldb_errstring(ldb));
+ goto failed;
+ }
+
+ return ret;
+
+failed:
+ talloc_free(ret);
+ exit(1);
+ return NULL;
+}
+
+struct ldb_control **parse_controls(void *mem_ctx, char **control_strings)
+{
+ int i;
+ struct ldb_control **ctrl;
+
+ if (control_strings == NULL || control_strings[0] == NULL)
+ return NULL;
+
+ for (i = 0; control_strings[i]; i++);
+
+ ctrl = talloc_array(mem_ctx, struct ldb_control *, i + 1);
+
+ for (i = 0; control_strings[i]; i++) {
+ if (strncmp(control_strings[i], "vlv:", 4) == 0) {
+ struct ldb_vlv_req_control *control;
+ const char *p;
+ char attr[1024];
+ char ctxid[1024];
+ int crit, bc, ac, os, cc, ret;
+
+ attr[0] = '\0';
+ ctxid[0] = '\0';
+ p = &(control_strings[i][4]);
+ ret = sscanf(p, "%d:%d:%d:%d:%d:%1023[^$]", &crit, &bc, &ac, &os, &cc, ctxid);
+ if (ret < 5) {
+ ret = sscanf(p, "%d:%d:%d:%1023[^:]:%1023[^$]", &crit, &bc, &ac, attr, ctxid);
+ }
+
+ if ((ret < 4) || (crit < 0) || (crit > 1)) {
+ fprintf(stderr, "invalid server_sort control syntax\n");
+ fprintf(stderr, " syntax: crit(b):bc(n):ac(n):<os(n):cc(n)|attr(s)>[:ctxid(o)]\n");
+ fprintf(stderr, " note: b = boolean, n = number, s = string, o = b64 binary blob\n");
+ return NULL;
+ }
+ if (!(ctrl[i] = talloc(ctrl, struct ldb_control))) {
+ fprintf(stderr, "talloc failed\n");
+ return NULL;
+ }
+ ctrl[i]->oid = LDB_CONTROL_VLV_REQ_OID;
+ ctrl[i]->critical = crit;
+ if (!(control = talloc(ctrl[i],
+ struct ldb_vlv_req_control))) {
+ fprintf(stderr, "talloc failed\n");
+ return NULL;
+ }
+ control->beforeCount = bc;
+ control->afterCount = ac;
+ if (attr[0]) {
+ control->type = 1;
+ control->match.gtOrEq.value = talloc_strdup(control, attr);
+ control->match.gtOrEq.value_len = strlen(attr);
+ } else {
+ control->type = 0;
+ control->match.byOffset.offset = os;
+ control->match.byOffset.contentCount = cc;
+ }
+ if (ctxid[0]) {
+ control->ctxid_len = ldb_base64_decode(ctxid);
+ control->contextId = (char *)talloc_memdup(control, ctxid, control->ctxid_len);
+ } else {
+ control->ctxid_len = 0;
+ control->contextId = NULL;
+ }
+ ctrl[i]->data = control;
+
+ continue;
+ }
+
+ if (strncmp(control_strings[i], "dirsync:", 8) == 0) {
+ struct ldb_dirsync_control *control;
+ const char *p;
+ char cookie[1024];
+ int crit, flags, max_attrs, ret;
+
+ cookie[0] = '\0';
+ p = &(control_strings[i][8]);
+ ret = sscanf(p, "%d:%d:%d:%1023[^$]", &crit, &flags, &max_attrs, cookie);
+
+ if ((ret < 3) || (crit < 0) || (crit > 1) || (flags < 0) || (max_attrs < 0)) {
+ fprintf(stderr, "invalid dirsync control syntax\n");
+ fprintf(stderr, " syntax: crit(b):flags(n):max_attrs(n)[:cookie(o)]\n");
+ fprintf(stderr, " note: b = boolean, n = number, o = b64 binary blob\n");
+ return NULL;
+ }
+
+ /* w2k3 seems to ignore the parameter,
+ * but w2k sends a wrong cookie when this value is to small
+ * this would cause looping forever, while getting
+ * the same data and same cookie forever
+ */
+ if (max_attrs == 0) max_attrs = 0x0FFFFFFF;
+
+ ctrl[i] = talloc(ctrl, struct ldb_control);
+ ctrl[i]->oid = LDB_CONTROL_DIRSYNC_OID;
+ ctrl[i]->critical = crit;
+ control = talloc(ctrl[i], struct ldb_dirsync_control);
+ control->flags = flags;
+ control->max_attributes = max_attrs;
+ if (*cookie) {
+ control->cookie_len = ldb_base64_decode(cookie);
+ control->cookie = (char *)talloc_memdup(control, cookie, control->cookie_len);
+ } else {
+ control->cookie = NULL;
+ control->cookie_len = 0;
+ }
+ ctrl[i]->data = control;
+
+ continue;
+ }
+
+ if (strncmp(control_strings[i], "asq:", 4) == 0) {
+ struct ldb_asq_control *control;
+ const char *p;
+ char attr[256];
+ int crit, ret;
+
+ attr[0] = '\0';
+ p = &(control_strings[i][4]);
+ ret = sscanf(p, "%d:%255[^$]", &crit, attr);
+ if ((ret != 2) || (crit < 0) || (crit > 1) || (attr[0] == '\0')) {
+ fprintf(stderr, "invalid asq control syntax\n");
+ fprintf(stderr, " syntax: crit(b):attr(s)\n");
+ fprintf(stderr, " note: b = boolean, s = string\n");
+ return NULL;
+ }
+
+ ctrl[i] = talloc(ctrl, struct ldb_control);
+ ctrl[i]->oid = LDB_CONTROL_ASQ_OID;
+ ctrl[i]->critical = crit;
+ control = talloc(ctrl[i], struct ldb_asq_control);
+ control->request = 1;
+ control->source_attribute = talloc_strdup(control, attr);
+ control->src_attr_len = strlen(attr);
+ ctrl[i]->data = control;
+
+ continue;
+ }
+
+ if (strncmp(control_strings[i], "extended_dn:", 12) == 0) {
+ struct ldb_extended_dn_control *control;
+ const char *p;
+ int crit, type, ret;
+
+ p = &(control_strings[i][12]);
+ ret = sscanf(p, "%d:%d", &crit, &type);
+ if ((ret != 2) || (crit < 0) || (crit > 1) || (type < 0) || (type > 1)) {
+ fprintf(stderr, "invalid extended_dn control syntax\n");
+ fprintf(stderr, " syntax: crit(b):type(b)\n");
+ fprintf(stderr, " note: b = boolean\n");
+ return NULL;
+ }
+
+ ctrl[i] = talloc(ctrl, struct ldb_control);
+ ctrl[i]->oid = LDB_CONTROL_EXTENDED_DN_OID;
+ ctrl[i]->critical = crit;
+ control = talloc(ctrl[i], struct ldb_extended_dn_control);
+ control->type = type;
+ ctrl[i]->data = control;
+
+ continue;
+ }
+
+ if (strncmp(control_strings[i], "sd_flags:", 9) == 0) {
+ struct ldb_sd_flags_control *control;
+ const char *p;
+ int crit, ret;
+ unsigned secinfo_flags;
+
+ p = &(control_strings[i][9]);
+ ret = sscanf(p, "%d:%u", &crit, &secinfo_flags);
+ if ((ret != 2) || (crit < 0) || (crit > 1) || (secinfo_flags < 0) || (secinfo_flags > 0xF)) {
+ fprintf(stderr, "invalid sd_flags control syntax\n");
+ fprintf(stderr, " syntax: crit(b):secinfo_flags(n)\n");
+ fprintf(stderr, " note: b = boolean, n = number\n");
+ return NULL;
+ }
+
+ ctrl[i] = talloc(ctrl, struct ldb_control);
+ ctrl[i]->oid = LDB_CONTROL_SD_FLAGS_OID;
+ ctrl[i]->critical = crit;
+ control = talloc(ctrl[i], struct ldb_sd_flags_control);
+ control->secinfo_flags = secinfo_flags;
+ ctrl[i]->data = control;
+
+ continue;
+ }
+
+ if (strncmp(control_strings[i], "search_options:", 15) == 0) {
+ struct ldb_search_options_control *control;
+ const char *p;
+ int crit, ret;
+ unsigned search_options;
+
+ p = &(control_strings[i][15]);
+ ret = sscanf(p, "%d:%u", &crit, &search_options);
+ if ((ret != 2) || (crit < 0) || (crit > 1) || (search_options < 0) || (search_options > 0xF)) {
+ fprintf(stderr, "invalid search_options control syntax\n");
+ fprintf(stderr, " syntax: crit(b):search_options(n)\n");
+ fprintf(stderr, " note: b = boolean, n = number\n");
+ return NULL;
+ }
+
+ ctrl[i] = talloc(ctrl, struct ldb_control);
+ ctrl[i]->oid = LDB_CONTROL_SEARCH_OPTIONS_OID;
+ ctrl[i]->critical = crit;
+ control = talloc(ctrl[i], struct ldb_search_options_control);
+ control->search_options = search_options;
+ ctrl[i]->data = control;
+
+ continue;
+ }
+
+ if (strncmp(control_strings[i], "domain_scope:", 13) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[i][13]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ fprintf(stderr, "invalid domain_scope control syntax\n");
+ fprintf(stderr, " syntax: crit(b)\n");
+ fprintf(stderr, " note: b = boolean\n");
+ return NULL;
+ }
+
+ ctrl[i] = talloc(ctrl, struct ldb_control);
+ ctrl[i]->oid = LDB_CONTROL_DOMAIN_SCOPE_OID;
+ ctrl[i]->critical = crit;
+ ctrl[i]->data = NULL;
+
+ continue;
+ }
+
+ if (strncmp(control_strings[i], "paged_results:", 14) == 0) {
+ struct ldb_paged_control *control;
+ const char *p;
+ int crit, size, ret;
+
+ p = &(control_strings[i][14]);
+ ret = sscanf(p, "%d:%d", &crit, &size);
+
+ if ((ret != 2) || (crit < 0) || (crit > 1) || (size < 0)) {
+ fprintf(stderr, "invalid paged_results control syntax\n");
+ fprintf(stderr, " syntax: crit(b):size(n)\n");
+ fprintf(stderr, " note: b = boolean, n = number\n");
+ return NULL;
+ }
+
+ ctrl[i] = talloc(ctrl, struct ldb_control);
+ ctrl[i]->oid = LDB_CONTROL_PAGED_RESULTS_OID;
+ ctrl[i]->critical = crit;
+ control = talloc(ctrl[i], struct ldb_paged_control);
+ control->size = size;
+ control->cookie = NULL;
+ control->cookie_len = 0;
+ ctrl[i]->data = control;
+
+ continue;
+ }
+
+ if (strncmp(control_strings[i], "server_sort:", 12) == 0) {
+ struct ldb_server_sort_control **control;
+ const char *p;
+ char attr[256];
+ char rule[128];
+ int crit, rev, ret;
+
+ attr[0] = '\0';
+ rule[0] = '\0';
+ p = &(control_strings[i][12]);
+ ret = sscanf(p, "%d:%d:%255[^:]:%127[^:]", &crit, &rev, attr, rule);
+ if ((ret < 3) || (crit < 0) || (crit > 1) || (rev < 0 ) || (rev > 1) ||attr[0] == '\0') {
+ fprintf(stderr, "invalid server_sort control syntax\n");
+ fprintf(stderr, " syntax: crit(b):rev(b):attr(s)[:rule(s)]\n");
+ fprintf(stderr, " note: b = boolean, s = string\n");
+ return NULL;
+ }
+ ctrl[i] = talloc(ctrl, struct ldb_control);
+ ctrl[i]->oid = LDB_CONTROL_SERVER_SORT_OID;
+ ctrl[i]->critical = crit;
+ control = talloc_array(ctrl[i], struct ldb_server_sort_control *, 2);
+ control[0] = talloc(control, struct ldb_server_sort_control);
+ control[0]->attributeName = talloc_strdup(control, attr);
+ if (rule[0])
+ control[0]->orderingRule = talloc_strdup(control, rule);
+ else
+ control[0]->orderingRule = NULL;
+ control[0]->reverse = rev;
+ control[1] = NULL;
+ ctrl[i]->data = control;
+
+ continue;
+ }
+
+ if (strncmp(control_strings[i], "notification:", 13) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[i][13]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ fprintf(stderr, "invalid notification control syntax\n");
+ fprintf(stderr, " syntax: crit(b)\n");
+ fprintf(stderr, " note: b = boolean\n");
+ return NULL;
+ }
+
+ ctrl[i] = talloc(ctrl, struct ldb_control);
+ ctrl[i]->oid = LDB_CONTROL_NOTIFICATION_OID;
+ ctrl[i]->critical = crit;
+ ctrl[i]->data = NULL;
+
+ continue;
+ }
+
+ if (strncmp(control_strings[i], "show_deleted:", 13) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[i][13]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ fprintf(stderr, "invalid show_deleted control syntax\n");
+ fprintf(stderr, " syntax: crit(b)\n");
+ fprintf(stderr, " note: b = boolean\n");
+ return NULL;
+ }
+
+ ctrl[i] = talloc(ctrl, struct ldb_control);
+ ctrl[i]->oid = LDB_CONTROL_SHOW_DELETED_OID;
+ ctrl[i]->critical = crit;
+ ctrl[i]->data = NULL;
+
+ continue;
+ }
+
+ if (strncmp(control_strings[i], "permissive_modify:", 18) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[i][18]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ fprintf(stderr, "invalid permissive_modify control syntax\n");
+ fprintf(stderr, " syntax: crit(b)\n");
+ fprintf(stderr, " note: b = boolean\n");
+ return NULL;
+ }
+
+ ctrl[i] = talloc(ctrl, struct ldb_control);
+ ctrl[i]->oid = LDB_CONTROL_PERMISSIVE_MODIFY_OID;
+ ctrl[i]->critical = crit;
+ ctrl[i]->data = NULL;
+
+ continue;
+ }
+
+ /* no controls matched, throw an error */
+ fprintf(stderr, "Invalid control name: '%s'\n", control_strings[i]);
+ return NULL;
+ }
+
+ ctrl[i] = NULL;
+
+ return ctrl;
+}
+
+
+/* this function check controls reply and determines if more
+ * processing is needed setting up the request controls correctly
+ *
+ * returns:
+ * -1 error
+ * 0 all ok
+ * 1 all ok, more processing required
+ */
+int handle_controls_reply(struct ldb_control **reply, struct ldb_control **request)
+{
+ int i, j;
+ int ret = 0;
+
+ if (reply == NULL || request == NULL) return -1;
+
+ for (i = 0; reply[i]; i++) {
+ if (strcmp(LDB_CONTROL_VLV_RESP_OID, reply[i]->oid) == 0) {
+ struct ldb_vlv_resp_control *rep_control;
+
+ rep_control = talloc_get_type(reply[i]->data, struct ldb_vlv_resp_control);
+
+ /* check we have a matching control in the request */
+ for (j = 0; request[j]; j++) {
+ if (strcmp(LDB_CONTROL_VLV_REQ_OID, request[j]->oid) == 0)
+ break;
+ }
+ if (! request[j]) {
+ fprintf(stderr, "Warning VLV reply received but no request have been made\n");
+ continue;
+ }
+
+ /* check the result */
+ if (rep_control->vlv_result != 0) {
+ fprintf(stderr, "Warning: VLV not performed with error: %d\n", rep_control->vlv_result);
+ } else {
+ fprintf(stderr, "VLV Info: target position = %d, content count = %d\n", rep_control->targetPosition, rep_control->contentCount);
+ }
+
+ continue;
+ }
+
+ if (strcmp(LDB_CONTROL_ASQ_OID, reply[i]->oid) == 0) {
+ struct ldb_asq_control *rep_control;
+
+ rep_control = talloc_get_type(reply[i]->data, struct ldb_asq_control);
+
+ /* check the result */
+ if (rep_control->result != 0) {
+ fprintf(stderr, "Warning: ASQ not performed with error: %d\n", rep_control->result);
+ }
+
+ continue;
+ }
+
+ if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, reply[i]->oid) == 0) {
+ struct ldb_paged_control *rep_control, *req_control;
+
+ rep_control = talloc_get_type(reply[i]->data, struct ldb_paged_control);
+ if (rep_control->cookie_len == 0) /* we are done */
+ break;
+
+ /* more processing required */
+ /* let's fill in the request control with the new cookie */
+
+ for (j = 0; request[j]; j++) {
+ if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, request[j]->oid) == 0)
+ break;
+ }
+ /* if there's a reply control we must find a request
+ * control matching it */
+ if (! request[j]) return -1;
+
+ req_control = talloc_get_type(request[j]->data, struct ldb_paged_control);
+
+ if (req_control->cookie)
+ talloc_free(req_control->cookie);
+ req_control->cookie = (char *)talloc_memdup(
+ req_control, rep_control->cookie,
+ rep_control->cookie_len);
+ req_control->cookie_len = rep_control->cookie_len;
+
+ ret = 1;
+
+ continue;
+ }
+
+ if (strcmp(LDB_CONTROL_SORT_RESP_OID, reply[i]->oid) == 0) {
+ struct ldb_sort_resp_control *rep_control;
+
+ rep_control = talloc_get_type(reply[i]->data, struct ldb_sort_resp_control);
+
+ /* check we have a matching control in the request */
+ for (j = 0; request[j]; j++) {
+ if (strcmp(LDB_CONTROL_SERVER_SORT_OID, request[j]->oid) == 0)
+ break;
+ }
+ if (! request[j]) {
+ fprintf(stderr, "Warning Server Sort reply received but no request found\n");
+ continue;
+ }
+
+ /* check the result */
+ if (rep_control->result != 0) {
+ fprintf(stderr, "Warning: Sorting not performed with error: %d\n", rep_control->result);
+ }
+
+ continue;
+ }
+
+ if (strcmp(LDB_CONTROL_DIRSYNC_OID, reply[i]->oid) == 0) {
+ struct ldb_dirsync_control *rep_control, *req_control;
+ char *cookie;
+
+ rep_control = talloc_get_type(reply[i]->data, struct ldb_dirsync_control);
+ if (rep_control->cookie_len == 0) /* we are done */
+ break;
+
+ /* more processing required */
+ /* let's fill in the request control with the new cookie */
+
+ for (j = 0; request[j]; j++) {
+ if (strcmp(LDB_CONTROL_DIRSYNC_OID, request[j]->oid) == 0)
+ break;
+ }
+ /* if there's a reply control we must find a request
+ * control matching it */
+ if (! request[j]) return -1;
+
+ req_control = talloc_get_type(request[j]->data, struct ldb_dirsync_control);
+
+ if (req_control->cookie)
+ talloc_free(req_control->cookie);
+ req_control->cookie = (char *)talloc_memdup(
+ req_control, rep_control->cookie,
+ rep_control->cookie_len);
+ req_control->cookie_len = rep_control->cookie_len;
+
+ cookie = ldb_base64_encode(req_control, rep_control->cookie, rep_control->cookie_len);
+ printf("# DIRSYNC cookie returned was:\n# %s\n", cookie);
+
+ continue;
+ }
+
+ /* no controls matched, throw a warning */
+ fprintf(stderr, "Unknown reply control oid: %s\n", reply[i]->oid);
+ }
+
+ return ret;
+}
+
diff --git a/source3/lib/ldb/tools/cmdline.h b/source3/lib/ldb/tools/cmdline.h
new file mode 100644
index 0000000000..ae295d68a4
--- /dev/null
+++ b/source3/lib/ldb/tools/cmdline.h
@@ -0,0 +1,53 @@
+/*
+ ldb database library - command line handling for ldb tools
+
+ Copyright (C) Andrew Tridgell 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <popt.h>
+
+struct ldb_cmdline {
+ const char *url;
+ enum ldb_scope scope;
+ const char *basedn;
+ int interactive;
+ int sorted;
+ const char *editor;
+ int verbose;
+ int recursive;
+ int all_records;
+ int nosync;
+ const char **options;
+ int argc;
+ const char **argv;
+ int num_records;
+ int num_searches;
+ const char *sasl_mechanism;
+ const char *input;
+ const char *output;
+ char **controls;
+};
+
+struct ldb_cmdline *ldb_cmdline_process(struct ldb_context *ldb, int argc, const char **argv,
+ void (*usage)(void));
+
+
+struct ldb_control **parse_controls(void *mem_ctx, char **control_strings);
+int handle_controls_reply(struct ldb_control **reply, struct ldb_control **request);
diff --git a/source3/lib/ldb/tools/convert.c b/source3/lib/ldb/tools/convert.c
new file mode 100644
index 0000000000..879ff697c8
--- /dev/null
+++ b/source3/lib/ldb/tools/convert.c
@@ -0,0 +1,165 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "convert.h"
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+/* Shared map for converting syntax between formats */
+static const struct syntax_map syntax_map[] = {
+ {
+ .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.12",
+ .AD_OID = "2.5.5.1",
+ .equality = "distinguishedNameMatch",
+ .comment = "Object(DS-DN) == a DN"
+ },
+ {
+ .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.38",
+ .AD_OID = "2.5.5.2",
+ .equality = "objectIdentifierMatch",
+ .comment = "OID String"
+ },
+ {
+ .Standard_OID = "1.2.840.113556.1.4.905",
+ .AD_OID = "2.5.5.4",
+ .equality = "caseIgnoreMatch",
+ .substring = "caseIgnoreSubstringsMatch",
+ .comment = "Case Insensitive String"
+ },
+ {
+ .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.26",
+ .AD_OID = "2.5.5.5",
+ .equality = "caseExactIA5Match",
+ .comment = "Printable String"
+ },
+ {
+ .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.36",
+ .AD_OID = "2.5.5.6",
+ .equality = "numericStringMatch",
+ .substring = "numericStringSubstringsMatch",
+ .comment = "Numeric String"
+ },
+ {
+ .Standard_OID = "1.2.840.113556.1.4.903",
+ .AD_OID = "2.5.5.7",
+ .equality = "distinguishedNameMatch",
+ .comment = "OctetString: Binary+DN"
+ },
+ {
+ .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.7",
+ .AD_OID = "2.5.5.8",
+ .equality = "booleanMatch",
+ .comment = "Boolean"
+ },
+ {
+ .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.27",
+ .AD_OID = "2.5.5.9",
+ .equality = "integerMatch",
+ .comment = "Integer"
+ },
+ {
+ .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.40",
+ .AD_OID = "2.5.5.10",
+ .equality = "octetStringMatch",
+ .comment = "Octet String"
+ },
+ {
+ .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.24",
+ .AD_OID = "2.5.5.11",
+ .equality = "generalizedTimeMatch",
+ .comment = "Generalized Time"
+ },
+ {
+ .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.53",
+ .AD_OID = "2.5.5.11",
+ .equality = "generalizedTimeMatch",
+ .comment = "UTC Time"
+ },
+ {
+ .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.15",
+ .AD_OID = "2.5.5.12",
+ .equality = "caseIgnoreMatch",
+ .substring = "caseIgnoreSubstringsMatch",
+ .comment = "Directory String"
+ },
+ {
+ .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.43",
+ .AD_OID = "2.5.5.13",
+ .comment = "Presentation Address"
+ },
+ {
+ .Standard_OID = "Not Found Yet",
+ .AD_OID = "2.5.5.14",
+ .equality = "distinguishedNameMatch",
+ .comment = "OctetString: String+DN"
+ },
+ {
+ .Standard_OID = "1.2.840.113556.1.4.907",
+ .AD_OID = "2.5.5.15",
+ .equality = "octetStringMatch",
+ .comment = "NT Security Descriptor"
+ },
+ {
+ .Standard_OID = "1.2.840.113556.1.4.906",
+ .AD_OID = "2.5.5.16",
+ .equality = "integerMatch",
+ .comment = "Large Integer"
+ },
+ {
+ .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.40",
+ .AD_OID = "2.5.5.17",
+ .equality = "octetStringMatch",
+ .comment = "Octet String - Security Identifier (SID)"
+ },
+ {
+ .Standard_OID = "1.3.6.1.4.1.1466.115.121.1.26",
+ .AD_OID = "2.5.5.5",
+ .equality = "caseExactIA5Match",
+ .comment = "IA5 String"
+ },
+ { .Standard_OID = NULL
+ }
+};
+
+
+const struct syntax_map *find_syntax_map_by_ad_oid(const char *ad_oid)
+{
+ int i;
+ for (i=0; syntax_map[i].Standard_OID; i++) {
+ if (strcasecmp(ad_oid, syntax_map[i].AD_OID) == 0) {
+ return &syntax_map[i];
+ }
+ }
+ return NULL;
+}
+
+const struct syntax_map *find_syntax_map_by_standard_oid(const char *standard_oid)
+{
+ int i;
+ for (i=0; syntax_map[i].Standard_OID; i++) {
+ if (strcasecmp(standard_oid, syntax_map[i].Standard_OID) == 0) {
+ return &syntax_map[i];
+ }
+ }
+ return NULL;
+}
diff --git a/source3/lib/ldb/tools/convert.h b/source3/lib/ldb/tools/convert.h
new file mode 100644
index 0000000000..de379343a6
--- /dev/null
+++ b/source3/lib/ldb/tools/convert.h
@@ -0,0 +1,10 @@
+struct syntax_map {
+ const char *Standard_OID;
+ const char *AD_OID;
+ const char *equality;
+ const char *substring;
+ const char *comment;
+};
+
+const struct syntax_map *find_syntax_map_by_ad_oid(const char *ad_oid);
+const struct syntax_map *find_syntax_map_by_standard_oid(const char *standard_oid);
diff --git a/source3/lib/ldb/tools/ldbadd.c b/source3/lib/ldb/tools/ldbadd.c
new file mode 100644
index 0000000000..4dde2a1ef5
--- /dev/null
+++ b/source3/lib/ldb/tools/ldbadd.c
@@ -0,0 +1,119 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbadd
+ *
+ * Description: utility to add records - modelled on ldapadd
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+#include "ldb/tools/cmdline.h"
+
+static int failures;
+
+static void usage(void)
+{
+ printf("Usage: ldbadd <options> <ldif...>\n");
+ printf("Options:\n");
+ printf(" -H ldb_url choose the database (or $LDB_URL)\n");
+ printf(" -o options pass options like modules to activate\n");
+ printf(" e.g: -o modules:timestamps\n");
+ printf("\n");
+ printf("Adds records to a ldb, reading ldif the specified list of files\n\n");
+ exit(1);
+}
+
+
+/*
+ add records from an opened file
+*/
+static int process_file(struct ldb_context *ldb, FILE *f, int *count)
+{
+ struct ldb_ldif *ldif;
+ int ret = LDB_SUCCESS;
+
+ while ((ldif = ldb_ldif_read_file(ldb, f))) {
+ if (ldif->changetype != LDB_CHANGETYPE_ADD &&
+ ldif->changetype != LDB_CHANGETYPE_NONE) {
+ fprintf(stderr, "Only CHANGETYPE_ADD records allowed\n");
+ break;
+ }
+
+ ldif->msg = ldb_msg_canonicalize(ldb, ldif->msg);
+
+ ret = ldb_add(ldb, ldif->msg);
+ if (ret != LDB_SUCCESS) {
+ fprintf(stderr, "ERR: \"%s\" on DN %s\n",
+ ldb_errstring(ldb), ldb_dn_linearize(ldb, ldif->msg->dn));
+ failures++;
+ } else {
+ (*count)++;
+ }
+ ldb_ldif_read_free(ldb, ldif);
+ }
+
+ return ret;
+}
+
+
+
+int main(int argc, const char **argv)
+{
+ struct ldb_context *ldb;
+ int i, ret=0, count=0;
+ struct ldb_cmdline *options;
+
+ ldb_global_init();
+
+ ldb = ldb_init(NULL);
+
+ options = ldb_cmdline_process(ldb, argc, argv, usage);
+
+ if (options->argc == 0) {
+ ret = process_file(ldb, stdin, &count);
+ } else {
+ for (i=0;i<options->argc;i++) {
+ const char *fname = options->argv[i];
+ FILE *f;
+ f = fopen(fname, "r");
+ if (!f) {
+ perror(fname);
+ exit(1);
+ }
+ ret = process_file(ldb, f, &count);
+ fclose(f);
+ }
+ }
+
+ talloc_free(ldb);
+
+ printf("Added %d records with %d failures\n", count, failures);
+
+ return ret;
+}
diff --git a/source3/lib/ldb/tools/ldbdel.c b/source3/lib/ldb/tools/ldbdel.c
new file mode 100644
index 0000000000..a6d32f422f
--- /dev/null
+++ b/source3/lib/ldb/tools/ldbdel.c
@@ -0,0 +1,118 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbdel
+ *
+ * Description: utility to delete records - modelled on ldapdelete
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+#include "ldb/tools/cmdline.h"
+
+static int ldb_delete_recursive(struct ldb_context *ldb, const struct ldb_dn *dn)
+{
+ int ret, i, total=0;
+ const char *attrs[] = { NULL };
+ struct ldb_result *res;
+
+ ret = ldb_search(ldb, dn, LDB_SCOPE_SUBTREE, "distinguishedName=*", attrs, &res);
+ if (ret != LDB_SUCCESS) return -1;
+
+ for (i = 0; i < res->count; i++) {
+ if (ldb_delete(ldb, res->msgs[i]->dn) == 0) {
+ total++;
+ }
+ }
+
+ talloc_free(res);
+
+ if (total == 0) {
+ return -1;
+ }
+ printf("Deleted %d records\n", total);
+ return 0;
+}
+
+static void usage(void)
+{
+ printf("Usage: ldbdel <options> <DN...>\n");
+ printf("Options:\n");
+ printf(" -r recursively delete the given subtree\n");
+ printf(" -H ldb_url choose the database (or $LDB_URL)\n");
+ printf(" -o options pass options like modules to activate\n");
+ printf(" e.g: -o modules:timestamps\n");
+ printf("\n");
+ printf("Deletes records from a ldb\n\n");
+ exit(1);
+}
+
+int main(int argc, const char **argv)
+{
+ struct ldb_context *ldb;
+ int ret = 0, i;
+ struct ldb_cmdline *options;
+
+ ldb_global_init();
+
+ ldb = ldb_init(NULL);
+
+ options = ldb_cmdline_process(ldb, argc, argv, usage);
+
+ if (options->argc < 1) {
+ usage();
+ exit(1);
+ }
+
+ for (i=0;i<options->argc;i++) {
+ const struct ldb_dn *dn;
+
+ dn = ldb_dn_explode(ldb, options->argv[i]);
+ if (dn == NULL) {
+ printf("Invalid DN format\n");
+ exit(1);
+ }
+ if (options->recursive) {
+ ret = ldb_delete_recursive(ldb, dn);
+ } else {
+ ret = ldb_delete(ldb, dn);
+ if (ret == 0) {
+ printf("Deleted 1 record\n");
+ }
+ }
+ if (ret != 0) {
+ printf("delete of '%s' failed - %s\n",
+ ldb_dn_linearize(ldb, dn),
+ ldb_errstring(ldb));
+ }
+ }
+
+ talloc_free(ldb);
+
+ return ret;
+}
diff --git a/source3/lib/ldb/tools/ldbedit.c b/source3/lib/ldb/tools/ldbedit.c
new file mode 100644
index 0000000000..0e1fd38e4c
--- /dev/null
+++ b/source3/lib/ldb/tools/ldbedit.c
@@ -0,0 +1,330 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbedit
+ *
+ * Description: utility for ldb database editing
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+#include "ldb/tools/cmdline.h"
+
+static struct ldb_cmdline *options;
+
+/*
+ debug routine
+*/
+static void ldif_write_msg(struct ldb_context *ldb,
+ FILE *f,
+ enum ldb_changetype changetype,
+ struct ldb_message *msg)
+{
+ struct ldb_ldif ldif;
+ ldif.changetype = changetype;
+ ldif.msg = msg;
+ ldb_ldif_write_file(ldb, f, &ldif);
+}
+
+/*
+ modify a database record so msg1 becomes msg2
+ returns the number of modified elements
+*/
+static int modify_record(struct ldb_context *ldb,
+ struct ldb_message *msg1,
+ struct ldb_message *msg2)
+{
+ struct ldb_message *mod;
+
+ mod = ldb_msg_diff(ldb, msg1, msg2);
+ if (mod == NULL) {
+ fprintf(stderr, "Failed to calculate message differences\n");
+ return -1;
+ }
+
+ if (mod->num_elements == 0) {
+ return 0;
+ }
+
+ if (options->verbose > 0) {
+ ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_MODIFY, mod);
+ }
+
+ if (ldb_modify(ldb, mod) != 0) {
+ fprintf(stderr, "failed to modify %s - %s\n",
+ ldb_dn_linearize(ldb, msg1->dn), ldb_errstring(ldb));
+ return -1;
+ }
+
+ return mod->num_elements;
+}
+
+/*
+ find dn in msgs[]
+*/
+static struct ldb_message *msg_find(struct ldb_context *ldb,
+ struct ldb_message **msgs,
+ int count,
+ const struct ldb_dn *dn)
+{
+ int i;
+ for (i=0;i<count;i++) {
+ if (ldb_dn_compare(ldb, dn, msgs[i]->dn) == 0) {
+ return msgs[i];
+ }
+ }
+ return NULL;
+}
+
+/*
+ merge the changes in msgs2 into the messages from msgs1
+*/
+static int merge_edits(struct ldb_context *ldb,
+ struct ldb_message **msgs1, int count1,
+ struct ldb_message **msgs2, int count2)
+{
+ int i;
+ struct ldb_message *msg;
+ int ret = 0;
+ int adds=0, modifies=0, deletes=0;
+
+ /* do the adds and modifies */
+ for (i=0;i<count2;i++) {
+ msg = msg_find(ldb, msgs1, count1, msgs2[i]->dn);
+ if (!msg) {
+ if (options->verbose > 0) {
+ ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_ADD, msgs2[i]);
+ }
+ if (ldb_add(ldb, msgs2[i]) != 0) {
+ fprintf(stderr, "failed to add %s - %s\n",
+ ldb_dn_linearize(ldb, msgs2[i]->dn),
+ ldb_errstring(ldb));
+ return -1;
+ }
+ adds++;
+ } else {
+ if (modify_record(ldb, msg, msgs2[i]) > 0) {
+ modifies++;
+ }
+ }
+ }
+
+ /* do the deletes */
+ for (i=0;i<count1;i++) {
+ msg = msg_find(ldb, msgs2, count2, msgs1[i]->dn);
+ if (!msg) {
+ if (options->verbose > 0) {
+ ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_DELETE, msgs1[i]);
+ }
+ if (ldb_delete(ldb, msgs1[i]->dn) != 0) {
+ fprintf(stderr, "failed to delete %s - %s\n",
+ ldb_dn_linearize(ldb, msgs1[i]->dn),
+ ldb_errstring(ldb));
+ return -1;
+ }
+ deletes++;
+ }
+ }
+
+ printf("# %d adds %d modifies %d deletes\n", adds, modifies, deletes);
+
+ return ret;
+}
+
+/*
+ save a set of messages as ldif to a file
+*/
+static int save_ldif(struct ldb_context *ldb,
+ FILE *f, struct ldb_message **msgs, int count)
+{
+ int i;
+
+ fprintf(f, "# editing %d records\n", count);
+
+ for (i=0;i<count;i++) {
+ struct ldb_ldif ldif;
+ fprintf(f, "# record %d\n", i+1);
+
+ ldif.changetype = LDB_CHANGETYPE_NONE;
+ ldif.msg = msgs[i];
+
+ ldb_ldif_write_file(ldb, f, &ldif);
+ }
+
+ return 0;
+}
+
+
+/*
+ edit the ldb search results in msgs using the user selected editor
+*/
+static int do_edit(struct ldb_context *ldb, struct ldb_message **msgs1, int count1,
+ const char *editor)
+{
+ int fd, ret;
+ FILE *f;
+ char file_template[] = "/tmp/ldbedit.XXXXXX";
+ char *cmd;
+ struct ldb_ldif *ldif;
+ struct ldb_message **msgs2 = NULL;
+ int count2 = 0;
+
+ /* write out the original set of messages to a temporary
+ file */
+ fd = mkstemp(file_template);
+
+ if (fd == -1) {
+ perror(file_template);
+ return -1;
+ }
+
+ f = fdopen(fd, "r+");
+
+ if (!f) {
+ perror("fopen");
+ close(fd);
+ unlink(file_template);
+ return -1;
+ }
+
+ if (save_ldif(ldb, f, msgs1, count1) != 0) {
+ return -1;
+ }
+
+ fclose(f);
+
+ cmd = talloc_asprintf(ldb, "%s %s", editor, file_template);
+
+ if (!cmd) {
+ unlink(file_template);
+ fprintf(stderr, "out of memory\n");
+ return -1;
+ }
+
+ /* run the editor */
+ ret = system(cmd);
+ talloc_free(cmd);
+
+ if (ret != 0) {
+ unlink(file_template);
+ fprintf(stderr, "edit with %s failed\n", editor);
+ return -1;
+ }
+
+ /* read the resulting ldif into msgs2 */
+ f = fopen(file_template, "r");
+ if (!f) {
+ perror(file_template);
+ return -1;
+ }
+
+ while ((ldif = ldb_ldif_read_file(ldb, f))) {
+ msgs2 = talloc_realloc(ldb, msgs2, struct ldb_message *, count2+1);
+ if (!msgs2) {
+ fprintf(stderr, "out of memory");
+ return -1;
+ }
+ msgs2[count2++] = ldif->msg;
+ }
+
+ fclose(f);
+ unlink(file_template);
+
+ return merge_edits(ldb, msgs1, count1, msgs2, count2);
+}
+
+static void usage(void)
+{
+ printf("Usage: ldbedit <options> <expression> <attributes ...>\n");
+ printf("Options:\n");
+ printf(" -H ldb_url choose the database (or $LDB_URL)\n");
+ printf(" -s base|sub|one choose search scope\n");
+ printf(" -b basedn choose baseDN\n");
+ printf(" -a edit all records (expression 'objectclass=*')\n");
+ printf(" -e editor choose editor (or $VISUAL or $EDITOR)\n");
+ printf(" -v verbose mode\n");
+ exit(1);
+}
+
+int main(int argc, const char **argv)
+{
+ struct ldb_context *ldb;
+ struct ldb_result *result = NULL;
+ struct ldb_dn *basedn = NULL;
+ int ret;
+ const char *expression = "(|(objectClass=*)(distinguishedName=*))";
+ const char * const * attrs = NULL;
+
+ ldb_global_init();
+
+ ldb = ldb_init(NULL);
+
+ options = ldb_cmdline_process(ldb, argc, argv, usage);
+
+ /* the check for '=' is for compatibility with ldapsearch */
+ if (options->argc > 0 &&
+ strchr(options->argv[0], '=')) {
+ expression = options->argv[0];
+ options->argv++;
+ options->argc--;
+ }
+
+ if (options->argc > 0) {
+ attrs = (const char * const *)(options->argv);
+ }
+
+ if (options->basedn != NULL) {
+ basedn = ldb_dn_explode(ldb, options->basedn);
+ if (basedn == NULL) {
+ printf("Invalid Base DN format\n");
+ exit(1);
+ }
+ }
+
+ ret = ldb_search(ldb, basedn, options->scope, expression, attrs, &result);
+ if (ret != LDB_SUCCESS) {
+ printf("search failed - %s\n", ldb_errstring(ldb));
+ exit(1);
+ }
+
+ if (result->count == 0) {
+ printf("no matching records - cannot edit\n");
+ return 0;
+ }
+
+ do_edit(ldb, result->msgs, result->count, options->editor);
+
+ ret = talloc_free(result);
+ if (ret == -1) {
+ fprintf(stderr, "talloc_free failed\n");
+ exit(1);
+ }
+
+ talloc_free(ldb);
+ return 0;
+}
diff --git a/source3/lib/ldb/tools/ldbmodify.c b/source3/lib/ldb/tools/ldbmodify.c
new file mode 100644
index 0000000000..368b4cf996
--- /dev/null
+++ b/source3/lib/ldb/tools/ldbmodify.c
@@ -0,0 +1,119 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbmodify
+ *
+ * Description: utility to modify records - modelled on ldapmodify
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+#include "ldb/tools/cmdline.h"
+
+static int failures;
+
+static void usage(void)
+{
+ printf("Usage: ldbmodify <options> <ldif...>\n");
+ printf("Options:\n");
+ printf(" -H ldb_url choose the database (or $LDB_URL)\n");
+ printf(" -o options pass options like modules to activate\n");
+ printf(" e.g: -o modules:timestamps\n");
+ printf("\n");
+ printf("Modifies a ldb based upon ldif change records\n\n");
+ exit(1);
+}
+
+/*
+ process modifies for one file
+*/
+static int process_file(struct ldb_context *ldb, FILE *f, int *count)
+{
+ struct ldb_ldif *ldif;
+ int ret = LDB_SUCCESS;
+
+ while ((ldif = ldb_ldif_read_file(ldb, f))) {
+ switch (ldif->changetype) {
+ case LDB_CHANGETYPE_NONE:
+ case LDB_CHANGETYPE_ADD:
+ ret = ldb_add(ldb, ldif->msg);
+ break;
+ case LDB_CHANGETYPE_DELETE:
+ ret = ldb_delete(ldb, ldif->msg->dn);
+ break;
+ case LDB_CHANGETYPE_MODIFY:
+ ret = ldb_modify(ldb, ldif->msg);
+ break;
+ }
+ if (ret != LDB_SUCCESS) {
+ fprintf(stderr, "ERR: \"%s\" on DN %s\n",
+ ldb_errstring(ldb), ldb_dn_linearize(ldb, ldif->msg->dn));
+ failures++;
+ } else {
+ (*count)++;
+ }
+ ldb_ldif_read_free(ldb, ldif);
+ }
+
+ return ret;
+}
+
+int main(int argc, const char **argv)
+{
+ struct ldb_context *ldb;
+ int count=0;
+ int i, ret=LDB_SUCCESS;
+ struct ldb_cmdline *options;
+
+ ldb_global_init();
+
+ ldb = ldb_init(NULL);
+
+ options = ldb_cmdline_process(ldb, argc, argv, usage);
+
+ if (options->argc == 0) {
+ ret = process_file(ldb, stdin, &count);
+ } else {
+ for (i=0;i<options->argc;i++) {
+ const char *fname = options->argv[i];
+ FILE *f;
+ f = fopen(fname, "r");
+ if (!f) {
+ perror(fname);
+ exit(1);
+ }
+ ret = process_file(ldb, f, &count);
+ }
+ }
+
+ talloc_free(ldb);
+
+ printf("Modified %d records with %d failures\n", count, failures);
+
+ return ret;
+}
diff --git a/source3/lib/ldb/tools/ldbrename.c b/source3/lib/ldb/tools/ldbrename.c
new file mode 100644
index 0000000000..d6c3a4ab62
--- /dev/null
+++ b/source3/lib/ldb/tools/ldbrename.c
@@ -0,0 +1,84 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Stefan Metzmacher 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbrename
+ *
+ * Description: utility to rename records - modelled on ldapmodrdn
+ *
+ * Author: Andrew Tridgell
+ * Author: Stefan Metzmacher
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+#include "ldb/tools/cmdline.h"
+
+static void usage(void)
+{
+ printf("Usage: ldbrename [<options>] <olddn> <newdn>\n");
+ printf("Options:\n");
+ printf(" -H ldb_url choose the database (or $LDB_URL)\n");
+ printf(" -o options pass options like modules to activate\n");
+ printf(" e.g: -o modules:timestamps\n");
+ printf("\n");
+ printf("Renames records in a ldb\n\n");
+ exit(1);
+}
+
+
+int main(int argc, const char **argv)
+{
+ struct ldb_context *ldb;
+ int ret;
+ struct ldb_cmdline *options;
+ const struct ldb_dn *dn1, *dn2;
+
+ ldb_global_init();
+
+ ldb = ldb_init(NULL);
+
+ options = ldb_cmdline_process(ldb, argc, argv, usage);
+
+ if (options->argc < 2) {
+ usage();
+ }
+
+ dn1 = ldb_dn_explode(ldb, options->argv[0]);
+ dn2 = ldb_dn_explode(ldb, options->argv[1]);
+
+ ret = ldb_rename(ldb, dn1, dn2);
+ if (ret == 0) {
+ printf("Renamed 1 record\n");
+ } else {
+ printf("rename of '%s' to '%s' failed - %s\n",
+ options->argv[0], options->argv[1], ldb_errstring(ldb));
+ }
+
+ talloc_free(ldb);
+
+ return ret;
+}
diff --git a/source3/lib/ldb/tools/ldbsearch.c b/source3/lib/ldb/tools/ldbsearch.c
new file mode 100644
index 0000000000..e5cec0fa66
--- /dev/null
+++ b/source3/lib/ldb/tools/ldbsearch.c
@@ -0,0 +1,320 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbsearch
+ *
+ * Description: utility for ldb search - modelled on ldapsearch
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+#include "ldb/tools/cmdline.h"
+
+static void usage(void)
+{
+ printf("Usage: ldbsearch <options> <expression> <attrs...>\n");
+ printf("Options:\n");
+ printf(" -H ldb_url choose the database (or $LDB_URL)\n");
+ printf(" -s base|sub|one choose search scope\n");
+ printf(" -b basedn choose baseDN\n");
+ printf(" -i read search expressions from stdin\n");
+ printf(" -S sort returned attributes\n");
+ printf(" -o options pass options like modules to activate\n");
+ printf(" e.g: -o modules:timestamps\n");
+ exit(1);
+}
+
+static int do_compare_msg(struct ldb_message **el1,
+ struct ldb_message **el2,
+ void *opaque)
+{
+ struct ldb_context *ldb = talloc_get_type(opaque, struct ldb_context);
+ return ldb_dn_compare(ldb, (*el1)->dn, (*el2)->dn);
+}
+
+struct search_context {
+ struct ldb_control **req_ctrls;
+
+ int sort;
+ int num_stored;
+ struct ldb_message **store;
+ char **refs_store;
+
+ int entries;
+ int refs;
+
+ int pending;
+ int status;
+};
+
+static int store_message(struct ldb_message *msg, struct search_context *sctx) {
+
+ sctx->store = talloc_realloc(sctx, sctx->store, struct ldb_message *, sctx->num_stored + 2);
+ if (!sctx->store) {
+ fprintf(stderr, "talloc_realloc failed while storing messages\n");
+ return -1;
+ }
+
+ sctx->store[sctx->num_stored] = talloc_move(sctx->store, &msg);
+ sctx->num_stored++;
+ sctx->store[sctx->num_stored] = NULL;
+
+ return 0;
+}
+
+static int store_referral(char *referral, struct search_context *sctx) {
+
+ sctx->refs_store = talloc_realloc(sctx, sctx->refs_store, char *, sctx->refs + 2);
+ if (!sctx->refs_store) {
+ fprintf(stderr, "talloc_realloc failed while storing referrals\n");
+ return -1;
+ }
+
+ sctx->refs_store[sctx->refs] = talloc_move(sctx->refs_store, &referral);
+ sctx->refs++;
+ sctx->refs_store[sctx->refs] = NULL;
+
+ return 0;
+}
+
+static int display_message(struct ldb_context *ldb, struct ldb_message *msg, struct search_context *sctx) {
+ struct ldb_ldif ldif;
+
+ sctx->entries++;
+ printf("# record %d\n", sctx->entries);
+
+ ldif.changetype = LDB_CHANGETYPE_NONE;
+ ldif.msg = msg;
+
+ if (sctx->sort) {
+ /*
+ * Ensure attributes are always returned in the same
+ * order. For testing, this makes comparison of old
+ * vs. new much easier.
+ */
+ ldb_msg_sort_elements(ldif.msg);
+ }
+
+ ldb_ldif_write_file(ldb, stdout, &ldif);
+
+ return 0;
+}
+
+static int display_referral(char *referral, struct search_context *sctx)
+{
+
+ sctx->refs++;
+ printf("# Referral\nref: %s\n\n", referral);
+
+ return 0;
+}
+
+static int search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+{
+ struct search_context *sctx = talloc_get_type(context, struct search_context);
+ int ret;
+
+ switch (ares->type) {
+
+ case LDB_REPLY_ENTRY:
+ if (sctx->sort) {
+ ret = store_message(ares->message, sctx);
+ } else {
+ ret = display_message(ldb, ares->message, sctx);
+ }
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ if (sctx->sort) {
+ ret = store_referral(ares->referral, sctx);
+ } else {
+ ret = display_referral(ares->referral, sctx);
+ }
+ break;
+
+ case LDB_REPLY_DONE:
+ if (ares->controls) {
+ if (handle_controls_reply(ares->controls, sctx->req_ctrls) == 1)
+ sctx->pending = 1;
+ }
+ ret = 0;
+ break;
+
+ default:
+ fprintf(stderr, "unknown Reply Type\n");
+ return LDB_ERR_OTHER;
+ }
+
+ if (talloc_free(ares) == -1) {
+ fprintf(stderr, "talloc_free failed\n");
+ sctx->pending = 0;
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (ret) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int do_search(struct ldb_context *ldb,
+ const struct ldb_dn *basedn,
+ struct ldb_cmdline *options,
+ const char *expression,
+ const char * const *attrs)
+{
+ struct ldb_request *req;
+ struct search_context *sctx;
+ int ret;
+
+ req = talloc(ldb, struct ldb_request);
+ if (!req) return -1;
+
+ sctx = talloc(req, struct search_context);
+ if (!sctx) return -1;
+
+ sctx->sort = options->sorted;
+ sctx->num_stored = 0;
+ sctx->store = NULL;
+ sctx->req_ctrls = parse_controls(ldb, options->controls);
+ if (options->controls != NULL && sctx->req_ctrls== NULL) return -1;
+ sctx->entries = 0;
+ sctx->refs = 0;
+
+ if (basedn == NULL) {
+ basedn = ldb_get_default_basedn(ldb);
+ }
+
+ req->operation = LDB_SEARCH;
+ req->op.search.base = basedn;
+ req->op.search.scope = options->scope;
+ req->op.search.tree = ldb_parse_tree(req, expression);
+ if (req->op.search.tree == NULL) return -1;
+ req->op.search.attrs = attrs;
+ req->controls = sctx->req_ctrls;
+ req->context = sctx;
+ req->callback = &search_callback;
+ ldb_set_timeout(ldb, req, 0); /* TODO: make this settable by command line */
+
+again:
+ sctx->pending = 0;
+
+ ret = ldb_request(ldb, req);
+ if (ret != LDB_SUCCESS) {
+ printf("search failed - %s\n", ldb_errstring(ldb));
+ return -1;
+ }
+
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ if (ret != LDB_SUCCESS) {
+ printf("search error - %s\n", ldb_errstring(ldb));
+ return -1;
+ }
+
+ if (sctx->pending)
+ goto again;
+
+ if (sctx->sort && sctx->num_stored != 0) {
+ int i;
+
+ ldb_qsort(sctx->store, ret, sizeof(struct ldb_message *),
+ ldb, (ldb_qsort_cmp_fn_t)do_compare_msg);
+
+ if (ret != 0) {
+ fprintf(stderr, "An error occurred while sorting messages\n");
+ exit(1);
+ }
+
+ for (i = 0; i < sctx->num_stored; i++) {
+ display_message(ldb, sctx->store[i], sctx);
+ }
+
+ for (i = 0; i < sctx->refs; i++) {
+ display_referral(sctx->refs_store[i], sctx);
+ }
+ }
+
+ printf("# returned %d records\n# %d entries\n# %d referrals\n",
+ sctx->entries + sctx->refs, sctx->entries, sctx->refs);
+
+ talloc_free(req);
+
+ return 0;
+}
+
+int main(int argc, const char **argv)
+{
+ struct ldb_context *ldb;
+ struct ldb_dn *basedn = NULL;
+ const char * const * attrs = NULL;
+ struct ldb_cmdline *options;
+ int ret = -1;
+ const char *expression = "(|(objectClass=*)(distinguishedName=*))";
+
+ ldb_global_init();
+
+ ldb = ldb_init(NULL);
+
+ options = ldb_cmdline_process(ldb, argc, argv, usage);
+
+ /* the check for '=' is for compatibility with ldapsearch */
+ if (!options->interactive &&
+ options->argc > 0 &&
+ strchr(options->argv[0], '=')) {
+ expression = options->argv[0];
+ options->argv++;
+ options->argc--;
+ }
+
+ if (options->argc > 0) {
+ attrs = (const char * const *)(options->argv);
+ }
+
+ if (options->basedn != NULL) {
+ basedn = ldb_dn_explode(ldb, options->basedn);
+ if (basedn == NULL) {
+ fprintf(stderr, "Invalid Base DN format\n");
+ exit(1);
+ }
+ }
+
+ if (options->interactive) {
+ char line[1024];
+ while (fgets(line, sizeof(line), stdin)) {
+ if (do_search(ldb, basedn, options, line, attrs) == -1) {
+ ret = -1;
+ }
+ }
+ } else {
+ ret = do_search(ldb, basedn, options, expression, attrs);
+ }
+
+ talloc_free(ldb);
+ return ret;
+}
diff --git a/source3/lib/ldb/tools/ldbtest.c b/source3/lib/ldb/tools/ldbtest.c
new file mode 100644
index 0000000000..b7fa874ad3
--- /dev/null
+++ b/source3/lib/ldb/tools/ldbtest.c
@@ -0,0 +1,409 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbtest
+ *
+ * Description: utility to test ldb
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+#include "ldb/tools/cmdline.h"
+
+static struct timeval tp1,tp2;
+static struct ldb_cmdline *options;
+
+static void _start_timer(void)
+{
+ gettimeofday(&tp1,NULL);
+}
+
+static double _end_timer(void)
+{
+ gettimeofday(&tp2,NULL);
+ return((tp2.tv_sec - tp1.tv_sec) +
+ (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
+}
+
+static void add_records(struct ldb_context *ldb,
+ const struct ldb_dn *basedn,
+ int count)
+{
+ struct ldb_message msg;
+ int i;
+
+#if 0
+ if (ldb_lock(ldb, "transaction") != 0) {
+ printf("transaction lock failed\n");
+ exit(1);
+ }
+#endif
+ for (i=0;i<count;i++) {
+ struct ldb_message_element el[6];
+ struct ldb_val vals[6][1];
+ char *name;
+ TALLOC_CTX *tmp_ctx = talloc_new(ldb);
+
+ name = talloc_asprintf(tmp_ctx, "Test%d", i);
+
+ msg.dn = ldb_dn_build_child(tmp_ctx, "cn", name, basedn);
+ msg.num_elements = 6;
+ msg.elements = el;
+
+ el[0].flags = 0;
+ el[0].name = talloc_strdup(tmp_ctx, "cn");
+ el[0].num_values = 1;
+ el[0].values = vals[0];
+ vals[0][0].data = (uint8_t *)name;
+ vals[0][0].length = strlen(name);
+
+ el[1].flags = 0;
+ el[1].name = "title";
+ el[1].num_values = 1;
+ el[1].values = vals[1];
+ vals[1][0].data = (uint8_t *)talloc_asprintf(tmp_ctx, "The title of %s", name);
+ vals[1][0].length = strlen((char *)vals[1][0].data);
+
+ el[2].flags = 0;
+ el[2].name = talloc_strdup(tmp_ctx, "uid");
+ el[2].num_values = 1;
+ el[2].values = vals[2];
+ vals[2][0].data = (uint8_t *)ldb_casefold(ldb, tmp_ctx, name);
+ vals[2][0].length = strlen((char *)vals[2][0].data);
+
+ el[3].flags = 0;
+ el[3].name = talloc_strdup(tmp_ctx, "mail");
+ el[3].num_values = 1;
+ el[3].values = vals[3];
+ vals[3][0].data = (uint8_t *)talloc_asprintf(tmp_ctx, "%s@example.com", name);
+ vals[3][0].length = strlen((char *)vals[3][0].data);
+
+ el[4].flags = 0;
+ el[4].name = talloc_strdup(tmp_ctx, "objectClass");
+ el[4].num_values = 1;
+ el[4].values = vals[4];
+ vals[4][0].data = (uint8_t *)talloc_strdup(tmp_ctx, "OpenLDAPperson");
+ vals[4][0].length = strlen((char *)vals[4][0].data);
+
+ el[5].flags = 0;
+ el[5].name = talloc_strdup(tmp_ctx, "sn");
+ el[5].num_values = 1;
+ el[5].values = vals[5];
+ vals[5][0].data = (uint8_t *)name;
+ vals[5][0].length = strlen((char *)vals[5][0].data);
+
+ ldb_delete(ldb, msg.dn);
+
+ if (ldb_add(ldb, &msg) != 0) {
+ printf("Add of %s failed - %s\n", name, ldb_errstring(ldb));
+ exit(1);
+ }
+
+ printf("adding uid %s\r", name);
+ fflush(stdout);
+
+ talloc_free(tmp_ctx);
+ }
+#if 0
+ if (ldb_unlock(ldb, "transaction") != 0) {
+ printf("transaction unlock failed\n");
+ exit(1);
+ }
+#endif
+ printf("\n");
+}
+
+static void modify_records(struct ldb_context *ldb,
+ const struct ldb_dn *basedn,
+ int count)
+{
+ struct ldb_message msg;
+ int i;
+
+ for (i=0;i<count;i++) {
+ struct ldb_message_element el[3];
+ struct ldb_val vals[3];
+ char *name;
+ TALLOC_CTX *tmp_ctx = talloc_new(ldb);
+
+ name = talloc_asprintf(tmp_ctx, "Test%d", i);
+ msg.dn = ldb_dn_build_child(tmp_ctx, "cn", name, basedn);
+
+ msg.num_elements = 3;
+ msg.elements = el;
+
+ el[0].flags = LDB_FLAG_MOD_DELETE;
+ el[0].name = talloc_strdup(tmp_ctx, "mail");
+ el[0].num_values = 0;
+
+ el[1].flags = LDB_FLAG_MOD_ADD;
+ el[1].name = talloc_strdup(tmp_ctx, "mail");
+ el[1].num_values = 1;
+ el[1].values = &vals[1];
+ vals[1].data = (uint8_t *)talloc_asprintf(tmp_ctx, "%s@other.example.com", name);
+ vals[1].length = strlen((char *)vals[1].data);
+
+ el[2].flags = LDB_FLAG_MOD_REPLACE;
+ el[2].name = talloc_strdup(tmp_ctx, "mail");
+ el[2].num_values = 1;
+ el[2].values = &vals[2];
+ vals[2].data = (uint8_t *)talloc_asprintf(tmp_ctx, "%s@other2.example.com", name);
+ vals[2].length = strlen((char *)vals[2].data);
+
+ if (ldb_modify(ldb, &msg) != 0) {
+ printf("Modify of %s failed - %s\n", name, ldb_errstring(ldb));
+ exit(1);
+ }
+
+ printf("Modifying uid %s\r", name);
+ fflush(stdout);
+
+ talloc_free(tmp_ctx);
+ }
+
+ printf("\n");
+}
+
+
+static void delete_records(struct ldb_context *ldb,
+ const struct ldb_dn *basedn,
+ int count)
+{
+ int i;
+
+ for (i=0;i<count;i++) {
+ struct ldb_dn *dn;
+ char *name = talloc_asprintf(ldb, "Test%d", i);
+ dn = ldb_dn_build_child(name, "cn", name, basedn);
+
+ printf("Deleting uid Test%d\r", i);
+ fflush(stdout);
+
+ if (ldb_delete(ldb, dn) != 0) {
+ printf("Delete of %s failed - %s\n", ldb_dn_linearize(ldb, dn), ldb_errstring(ldb));
+ exit(1);
+ }
+ talloc_free(name);
+ }
+
+ printf("\n");
+}
+
+static void search_uid(struct ldb_context *ldb, struct ldb_dn *basedn, int nrecords, int nsearches)
+{
+ int i;
+
+ for (i=0;i<nsearches;i++) {
+ int uid = (i * 700 + 17) % (nrecords * 2);
+ char *expr;
+ struct ldb_result *res = NULL;
+ int ret;
+
+ expr = talloc_asprintf(ldb, "(uid=TEST%d)", uid);
+ ret = ldb_search(ldb, basedn, LDB_SCOPE_SUBTREE, expr, NULL, &res);
+
+ if (ret != LDB_SUCCESS || (uid < nrecords && res->count != 1)) {
+ printf("Failed to find %s - %s\n", expr, ldb_errstring(ldb));
+ exit(1);
+ }
+
+ if (uid >= nrecords && res->count > 0) {
+ printf("Found %s !? - %d\n", expr, ret);
+ exit(1);
+ }
+
+ printf("testing uid %d/%d - %d \r", i, uid, res->count);
+ fflush(stdout);
+
+ talloc_free(res);
+ talloc_free(expr);
+ }
+
+ printf("\n");
+}
+
+static void start_test(struct ldb_context *ldb, int nrecords, int nsearches)
+{
+ struct ldb_dn *basedn;
+
+ basedn = ldb_dn_explode(ldb, options->basedn);
+
+ printf("Adding %d records\n", nrecords);
+ add_records(ldb, basedn, nrecords);
+
+ printf("Starting search on uid\n");
+ _start_timer();
+ search_uid(ldb, basedn, nrecords, nsearches);
+ printf("uid search took %.2f seconds\n", _end_timer());
+
+ printf("Modifying records\n");
+ modify_records(ldb, basedn, nrecords);
+
+ printf("Deleting records\n");
+ delete_records(ldb, basedn, nrecords);
+}
+
+
+/*
+ 2) Store an @indexlist record
+
+ 3) Store a record that contains fields that should be index according
+to @index
+
+ 4) disconnection from database
+
+ 5) connect to same database
+
+ 6) search for record added in step 3 using a search key that should
+be indexed
+*/
+static void start_test_index(struct ldb_context **ldb)
+{
+ struct ldb_message *msg;
+ struct ldb_result *res = NULL;
+ struct ldb_dn *indexlist;
+ struct ldb_dn *basedn;
+ int ret;
+ int flags = 0;
+ const char *specials;
+
+ specials = getenv("LDB_SPECIALS");
+ if (specials && atoi(specials) == 0) {
+ printf("LDB_SPECIALS disabled - skipping index test\n");
+ return;
+ }
+
+ if (options->nosync) {
+ flags |= LDB_FLG_NOSYNC;
+ }
+
+ printf("Starting index test\n");
+
+ indexlist = ldb_dn_explode(NULL, "@INDEXLIST");
+
+ ldb_delete(*ldb, indexlist);
+
+ msg = ldb_msg_new(NULL);
+
+ msg->dn = indexlist;
+ ldb_msg_add_string(msg, "@IDXATTR", strdup("uid"));
+
+ if (ldb_add(*ldb, msg) != 0) {
+ printf("Add of %s failed - %s\n", ldb_dn_linearize(*ldb, msg->dn), ldb_errstring(*ldb));
+ exit(1);
+ }
+
+ basedn = ldb_dn_explode(NULL, options->basedn);
+
+ memset(msg, 0, sizeof(*msg));
+ msg->dn = ldb_dn_build_child(msg, "cn", "test", basedn);
+ ldb_msg_add_string(msg, "cn", strdup("test"));
+ ldb_msg_add_string(msg, "sn", strdup("test"));
+ ldb_msg_add_string(msg, "uid", strdup("test"));
+ ldb_msg_add_string(msg, "objectClass", strdup("OpenLDAPperson"));
+
+ if (ldb_add(*ldb, msg) != 0) {
+ printf("Add of %s failed - %s\n", ldb_dn_linearize(*ldb, msg->dn), ldb_errstring(*ldb));
+ exit(1);
+ }
+
+ if (talloc_free(*ldb) != 0) {
+ printf("failed to free/close ldb database");
+ exit(1);
+ }
+
+ (*ldb) = ldb_init(options);
+
+ ret = ldb_connect(*ldb, options->url, flags, NULL);
+ if (ret != 0) {
+ printf("failed to connect to %s\n", options->url);
+ exit(1);
+ }
+
+ ret = ldb_search(*ldb, basedn, LDB_SCOPE_SUBTREE, "uid=test", NULL, &res);
+ if (ret != LDB_SUCCESS) {
+ printf("Search with (uid=test) filter failed!\n");
+ exit(1);
+ }
+ if(res->count != 1) {
+ printf("Should have found 1 record - found %d\n", res->count);
+ exit(1);
+ }
+
+ if (ldb_delete(*ldb, msg->dn) != 0 ||
+ ldb_delete(*ldb, indexlist) != 0) {
+ printf("cleanup failed - %s\n", ldb_errstring(*ldb));
+ exit(1);
+ }
+
+ printf("Finished index test\n");
+}
+
+
+static void usage(void)
+{
+ printf("Usage: ldbtest <options>\n");
+ printf("Options:\n");
+ printf(" -H ldb_url choose the database (or $LDB_URL)\n");
+ printf(" --num-records nrecords database size to use\n");
+ printf(" --num-searches nsearches number of searches to do\n");
+ printf("\n");
+ printf("tests ldb API\n\n");
+ exit(1);
+}
+
+int main(int argc, const char **argv)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ struct ldb_context *ldb;
+
+ ldb_global_init();
+
+ ldb = ldb_init(mem_ctx);
+
+ options = ldb_cmdline_process(ldb, argc, argv, usage);
+
+ talloc_steal(mem_ctx, options);
+
+ if (options->basedn == NULL) {
+ options->basedn = "ou=Ldb Test,ou=People,o=University of Michigan,c=TEST";
+ }
+
+ srandom(1);
+
+ printf("Testing with num-records=%d and num-searches=%d\n",
+ options->num_records, options->num_searches);
+
+ start_test(ldb, options->num_records, options->num_searches);
+
+ start_test_index(&ldb);
+
+ talloc_free(mem_ctx);
+
+ return 0;
+}
diff --git a/source3/lib/ldb/tools/oLschema2ldif.c b/source3/lib/ldb/tools/oLschema2ldif.c
new file mode 100644
index 0000000000..c31c258759
--- /dev/null
+++ b/source3/lib/ldb/tools/oLschema2ldif.c
@@ -0,0 +1,607 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: oLschema2ldif
+ *
+ * Description: utility to convert an OpenLDAP schema into AD LDIF
+ *
+ * Author: Simo Sorce
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+#include "ldb/tools/cmdline.h"
+#include "ldb/tools/convert.h"
+
+#define SCHEMA_UNKNOWN 0
+#define SCHEMA_NAME 1
+#define SCHEMA_SUP 2
+#define SCHEMA_STRUCTURAL 3
+#define SCHEMA_ABSTRACT 4
+#define SCHEMA_AUXILIARY 5
+#define SCHEMA_MUST 6
+#define SCHEMA_MAY 7
+#define SCHEMA_SINGLE_VALUE 8
+#define SCHEMA_EQUALITY 9
+#define SCHEMA_ORDERING 10
+#define SCHEMA_SUBSTR 11
+#define SCHEMA_SYNTAX 12
+#define SCHEMA_DESC 13
+
+struct schema_conv {
+ int count;
+ int failures;
+};
+
+struct schema_token {
+ int type;
+ char *value;
+};
+
+struct ldb_context *ldb_ctx;
+struct ldb_dn *basedn;
+
+static int check_braces(const char *string)
+{
+ int b;
+ char *c;
+
+ b = 0;
+ if ((c = strchr(string, '(')) == NULL) {
+ return -1;
+ }
+ b++;
+ c++;
+ while (b) {
+ c = strpbrk(c, "()");
+ if (c == NULL) return 1;
+ if (*c == '(') b++;
+ if (*c == ')') b--;
+ c++;
+ }
+ return 0;
+}
+
+static char *skip_spaces(char *string) {
+ return (string + strspn(string, " \t\n"));
+}
+
+static int add_multi_string(struct ldb_message *msg, const char *attr, char *values)
+{
+ char *c;
+ char *s;
+ int n;
+
+ c = skip_spaces(values);
+ while (*c) {
+ n = strcspn(c, " \t$");
+ s = talloc_strndup(msg, c, n);
+ if (ldb_msg_add_string(msg, attr, s) != 0) {
+ return -1;
+ }
+ c += n;
+ c += strspn(c, " \t$");
+ }
+
+ return 0;
+}
+
+#define MSG_ADD_STRING(a, v) do { if (ldb_msg_add_string(msg, a, v) != 0) goto failed; } while(0)
+#define MSG_ADD_M_STRING(a, v) do { if (add_multi_string(msg, a, v) != 0) goto failed; } while(0)
+
+static char *get_def_value(TALLOC_CTX *ctx, char **string)
+{
+ char *c = *string;
+ char *value;
+ int n;
+
+ if (*c == '\'') {
+ c++;
+ n = strcspn(c, "\'");
+ value = talloc_strndup(ctx, c, n);
+ c += n;
+ c++; /* skip closing \' */
+ } else {
+ n = strcspn(c, " \t\n");
+ value = talloc_strndup(ctx, c, n);
+ c += n;
+ }
+ *string = c;
+
+ return value;
+}
+
+static struct schema_token *get_next_schema_token(TALLOC_CTX *ctx, char **string)
+{
+ char *c = skip_spaces(*string);
+ char *type;
+ struct schema_token *token;
+ int n;
+
+ token = talloc(ctx, struct schema_token);
+
+ n = strcspn(c, " \t\n");
+ type = talloc_strndup(token, c, n);
+ c += n;
+ c = skip_spaces(c);
+
+ if (strcasecmp("NAME", type) == 0) {
+ talloc_free(type);
+ token->type = SCHEMA_NAME;
+ /* we do not support aliases so we get only the first name given and skip others */
+ if (*c == '(') {
+ char *s = strchr(c, ')');
+ if (s == NULL) return NULL;
+ s = skip_spaces(s);
+ *string = s;
+
+ c++;
+ c = skip_spaces(c);
+ }
+
+ token->value = get_def_value(ctx, &c);
+
+ if (*string < c) { /* single name */
+ c = skip_spaces(c);
+ *string = c;
+ }
+ return token;
+ }
+ if (strcasecmp("SUP", type) == 0) {
+ talloc_free(type);
+ token->type = SCHEMA_SUP;
+
+ if (*c == '(') {
+ c++;
+ n = strcspn(c, ")");
+ token->value = talloc_strndup(ctx, c, n);
+ c += n;
+ c++;
+ } else {
+ token->value = get_def_value(ctx, &c);
+ }
+
+ c = skip_spaces(c);
+ *string = c;
+ return token;
+ }
+
+ if (strcasecmp("STRUCTURAL", type) == 0) {
+ talloc_free(type);
+ token->type = SCHEMA_STRUCTURAL;
+ *string = c;
+ return token;
+ }
+
+ if (strcasecmp("ABSTRACT", type) == 0) {
+ talloc_free(type);
+ token->type = SCHEMA_ABSTRACT;
+ *string = c;
+ return token;
+ }
+
+ if (strcasecmp("AUXILIARY", type) == 0) {
+ talloc_free(type);
+ token->type = SCHEMA_AUXILIARY;
+ *string = c;
+ return token;
+ }
+
+ if (strcasecmp("MUST", type) == 0) {
+ talloc_free(type);
+ token->type = SCHEMA_MUST;
+
+ if (*c == '(') {
+ c++;
+ n = strcspn(c, ")");
+ token->value = talloc_strndup(ctx, c, n);
+ c += n;
+ c++;
+ } else {
+ token->value = get_def_value(ctx, &c);
+ }
+
+ c = skip_spaces(c);
+ *string = c;
+ return token;
+ }
+
+ if (strcasecmp("MAY", type) == 0) {
+ talloc_free(type);
+ token->type = SCHEMA_MAY;
+
+ if (*c == '(') {
+ c++;
+ n = strcspn(c, ")");
+ token->value = talloc_strndup(ctx, c, n);
+ c += n;
+ c++;
+ } else {
+ token->value = get_def_value(ctx, &c);
+ }
+
+ c = skip_spaces(c);
+ *string = c;
+ return token;
+ }
+
+ if (strcasecmp("SINGLE-VALUE", type) == 0) {
+ talloc_free(type);
+ token->type = SCHEMA_SINGLE_VALUE;
+ *string = c;
+ return token;
+ }
+
+ if (strcasecmp("EQUALITY", type) == 0) {
+ talloc_free(type);
+ token->type = SCHEMA_EQUALITY;
+
+ token->value = get_def_value(ctx, &c);
+
+ c = skip_spaces(c);
+ *string = c;
+ return token;
+ }
+
+ if (strcasecmp("ORDERING", type) == 0) {
+ talloc_free(type);
+ token->type = SCHEMA_ORDERING;
+
+ token->value = get_def_value(ctx, &c);
+
+ c = skip_spaces(c);
+ *string = c;
+ return token;
+ }
+
+ if (strcasecmp("SUBSTR", type) == 0) {
+ talloc_free(type);
+ token->type = SCHEMA_SUBSTR;
+
+ token->value = get_def_value(ctx, &c);
+
+ c = skip_spaces(c);
+ *string = c;
+ return token;
+ }
+
+ if (strcasecmp("SYNTAX", type) == 0) {
+ talloc_free(type);
+ token->type = SCHEMA_SYNTAX;
+
+ token->value = get_def_value(ctx, &c);
+
+ c = skip_spaces(c);
+ *string = c;
+ return token;
+ }
+
+ if (strcasecmp("DESC", type) == 0) {
+ talloc_free(type);
+ token->type = SCHEMA_DESC;
+
+ token->value = get_def_value(ctx, &c);
+
+ c = skip_spaces(c);
+ *string = c;
+ return token;
+ }
+
+ token->type = SCHEMA_UNKNOWN;
+ token->value = type;
+ if (*c == ')') {
+ *string = c;
+ return token;
+ }
+ if (*c == '\'') {
+ c = strchr(++c, '\'');
+ c++;
+ } else {
+ c += strcspn(c, " \t\n");
+ }
+ c = skip_spaces(c);
+ *string = c;
+
+ return token;
+}
+
+static struct ldb_message *process_entry(TALLOC_CTX *mem_ctx, const char *entry)
+{
+ TALLOC_CTX *ctx;
+ struct ldb_message *msg;
+ struct schema_token *token;
+ char *c, *s;
+ int n;
+
+ ctx = talloc_new(mem_ctx);
+ msg = ldb_msg_new(ctx);
+
+ ldb_msg_add_string(msg, "objectClass", "top");
+
+ c = talloc_strdup(ctx, entry);
+ if (!c) return NULL;
+
+ c = skip_spaces(c);
+
+ switch (*c) {
+ case 'a':
+ if (strncmp(c, "attributetype", 13) == 0) {
+ c += 13;
+ MSG_ADD_STRING("objectClass", "attributeSchema");
+ break;
+ }
+ goto failed;
+ case 'o':
+ if (strncmp(c, "objectclass", 11) == 0) {
+ c += 11;
+ MSG_ADD_STRING("objectClass", "classSchema");
+ break;
+ }
+ goto failed;
+ default:
+ goto failed;
+ }
+
+ c = strchr(c, '(');
+ if (c == NULL) goto failed;
+ c++;
+
+ c = skip_spaces(c);
+
+ /* get attributeID */
+ n = strcspn(c, " \t");
+ s = talloc_strndup(msg, c, n);
+ MSG_ADD_STRING("attributeID", s);
+ c += n;
+ c = skip_spaces(c);
+
+ while (*c != ')') {
+ token = get_next_schema_token(msg, &c);
+ if (!token) goto failed;
+
+ switch (token->type) {
+ case SCHEMA_NAME:
+ MSG_ADD_STRING("cn", token->value);
+ MSG_ADD_STRING("name", token->value);
+ MSG_ADD_STRING("lDAPDisplayName", token->value);
+ msg->dn = ldb_dn_string_compose(msg, basedn,
+ "CN=%s,CN=Schema,CN=Configuration",
+ token->value);
+ break;
+
+ case SCHEMA_SUP:
+ MSG_ADD_M_STRING("subClassOf", token->value);
+ break;
+
+ case SCHEMA_STRUCTURAL:
+ MSG_ADD_STRING("objectClassCategory", "1");
+ break;
+
+ case SCHEMA_ABSTRACT:
+ MSG_ADD_STRING("objectClassCategory", "2");
+ break;
+
+ case SCHEMA_AUXILIARY:
+ MSG_ADD_STRING("objectClassCategory", "3");
+ break;
+
+ case SCHEMA_MUST:
+ MSG_ADD_M_STRING("mustContain", token->value);
+ break;
+
+ case SCHEMA_MAY:
+ MSG_ADD_M_STRING("mayContain", token->value);
+ break;
+
+ case SCHEMA_SINGLE_VALUE:
+ MSG_ADD_STRING("isSingleValued", "TRUE");
+ break;
+
+ case SCHEMA_EQUALITY:
+ /* TODO */
+ break;
+
+ case SCHEMA_ORDERING:
+ /* TODO */
+ break;
+
+ case SCHEMA_SUBSTR:
+ /* TODO */
+ break;
+
+ case SCHEMA_SYNTAX:
+ {
+ const struct syntax_map *map =
+ find_syntax_map_by_standard_oid(token->value);
+ if (!map) {
+ break;
+ }
+ MSG_ADD_STRING("attributeSyntax", map->AD_OID);
+ break;
+ }
+ case SCHEMA_DESC:
+ MSG_ADD_STRING("description", token->value);
+ break;
+
+ default:
+ fprintf(stderr, "Unknown Definition: %s\n", token->value);
+ }
+ }
+
+ talloc_steal(mem_ctx, msg);
+ talloc_free(ctx);
+ return msg;
+
+failed:
+ talloc_free(ctx);
+ return NULL;
+}
+
+static struct schema_conv process_file(FILE *in, FILE *out)
+{
+ TALLOC_CTX *ctx;
+ struct schema_conv ret;
+ char *entry;
+ int c, t, line;
+ struct ldb_ldif ldif;
+
+ ldif.changetype = LDB_CHANGETYPE_NONE;
+
+ ctx = talloc_new(NULL);
+
+ ret.count = 0;
+ ret.failures = 0;
+ line = 0;
+
+ while ((c = fgetc(in)) != EOF) {
+ line++;
+ /* fprintf(stderr, "Parsing line %d\n", line); */
+ if (c == '#') {
+ do {
+ c = fgetc(in);
+ } while (c != EOF && c != '\n');
+ continue;
+ }
+ if (c == '\n') {
+ continue;
+ }
+
+ t = 0;
+ entry = talloc_array(ctx, char, 1024);
+ if (entry == NULL) exit(-1);
+
+ do {
+ if (c == '\n') {
+ entry[t] = '\0';
+ if (check_braces(entry) == 0) {
+ ret.count++;
+ ldif.msg = process_entry(ctx, entry);
+ if (ldif.msg == NULL) {
+ ret.failures++;
+ fprintf(stderr, "No valid msg from entry \n[%s]\n at line %d\n", entry, line);
+ break;
+ }
+ ldb_ldif_write_file(ldb_ctx, out, &ldif);
+ break;
+ }
+ line++;
+ } else {
+ entry[t] = c;
+ t++;
+ }
+ if ((t % 1023) == 0) {
+ entry = talloc_realloc(ctx, entry, char, t + 1024);
+ if (entry == NULL) exit(-1);
+ }
+ } while ((c = fgetc(in)) != EOF);
+
+ if (c != '\n') {
+ entry[t] = '\0';
+ if (check_braces(entry) == 0) {
+ ret.count++;
+ ldif.msg = process_entry(ctx, entry);
+ if (ldif.msg == NULL) {
+ ret.failures++;
+ fprintf(stderr, "No valid msg from entry \n[%s]\n at line %d\n", entry, line);
+ break;
+ }
+ ldb_ldif_write_file(ldb_ctx, out, &ldif);
+ } else {
+ fprintf(stderr, "malformed entry on line %d\n", line);
+ ret.failures++;
+ }
+ }
+
+ if (c == EOF) break;
+ }
+
+ return ret;
+}
+
+static void usage(void)
+{
+ printf("Usage: oLschema2ldif -H NONE <options>\n");
+ printf("\nConvert OpenLDAP schema to AD-like LDIF format\n\n");
+ printf("Options:\n");
+ printf(" -I inputfile inputfile of OpenLDAP style schema otherwise STDIN\n");
+ printf(" -O outputfile outputfile otherwise STDOUT\n");
+ printf(" -o options pass options like modules to activate\n");
+ printf(" e.g: -o modules:timestamps\n");
+ printf("\n");
+ printf("Converts records from an openLdap formatted schema to an ldif schema\n\n");
+ exit(1);
+}
+
+ int main(int argc, const char **argv)
+{
+ TALLOC_CTX *ctx;
+ struct schema_conv ret;
+ struct ldb_cmdline *options;
+ FILE *in = stdin;
+ FILE *out = stdout;
+ ldb_global_init();
+
+ ctx = talloc_new(NULL);
+ ldb_ctx = ldb_init(ctx);
+
+ setenv("LDB_URL", "NONE", 1);
+ options = ldb_cmdline_process(ldb_ctx, argc, argv, usage);
+
+ if (options->basedn == NULL) {
+ perror("Base DN not specified");
+ exit(1);
+ } else {
+ basedn = ldb_dn_explode(ctx, options->basedn);
+ if (basedn == NULL) {
+ perror("Malformed Base DN");
+ exit(1);
+ }
+ }
+
+ if (options->input) {
+ in = fopen(options->input, "r");
+ if (!in) {
+ perror(options->input);
+ exit(1);
+ }
+ }
+ if (options->output) {
+ out = fopen(options->output, "w");
+ if (!out) {
+ perror(options->output);
+ exit(1);
+ }
+ }
+
+ ret = process_file(in, out);
+
+ fclose(in);
+ fclose(out);
+
+ printf("Converted %d records with %d failures\n", ret.count, ret.failures);
+
+ return 0;
+}
diff --git a/source3/lib/ldb/web/index.html b/source3/lib/ldb/web/index.html
new file mode 100644
index 0000000000..4c569caa25
--- /dev/null
+++ b/source3/lib/ldb/web/index.html
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+<TITLE>ldb</TITLE>
+</HEAD>
+<BODY BGCOLOR="#ffffff" TEXT="#000000" VLINK="#292555" LINK="#292555" ALINK="#cc0033">
+
+<h1>ldb</h1>
+
+ldb is a LDAP-like embedded database. It is not at all LDAP standards
+compliant, so if you want a standards compliant database then please
+see the excellent <a href="http://www.openldap.org/">OpenLDAP</a>
+project.<p>
+
+What ldb does is provide a fast database with an LDAP-like API
+designed to be used within an application. In some ways it can be seen
+as a intermediate solution between key-value pair databases and a real
+LDAP database.<p>
+
+ldb is the database engine used in Samba4.
+
+<h2>Features</h2>
+
+The main features that separate ldb from other solutions are:
+
+<ul>
+<li>Safe multi-reader, multi-writer, using byte range locking
+<li>LDAP-like API
+<li>fast operation
+<li>choice of local tdb or remote LDAP backends
+<li>integration with <a href="http://talloc.samba.org">talloc</a>
+<li>schema-less operation, for trivial setup
+<li>modules for extensions (such as schema support)
+<li>easy setup of indexes and attribute properties
+<li>ldbedit tool for database editing (reminiscent of 'vipw')
+<li>ldif for import/export
+</ul>
+
+<h2>Documentation</h2>
+
+Currently ldb is completely lacking in programmer or user
+documentation. This is your opportunity to make a contribution! Start
+with the public functions declared in <a
+href="http://samba.org/ftp/unpacked/ldb/include/ldb.h">ldb.h</a>
+and the example code in the <a
+href="http://samba.org/ftp/unpacked/ldb/tools/">tools
+directory</a>. Documentation in the same docbook format used by Samba
+would be preferred.
+
+<h2>Discussion and bug reports</h2>
+
+ldb does not currently have its own mailing list or bug tracking
+system. For now, please use the <a
+href="https://lists.samba.org/mailman/listinfo/samba-technical">samba-technical</a>
+mailing list or the <a href="https://lists.samba.org/mailman/listinfo/ldb">ldb</a>
+mailing list, and the <a href="http://bugzilla.samba.org/">Samba bugzilla</a> bug tracking system.
+
+<h2>Download</h2>
+
+You can download the latest release either via rsync or thtough git.<br>
+<br>
+To fetch via git see the following guide:<br>
+<a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development">Using Git for Samba Development</a><br>
+Once you have cloned the tree switch to the v4-0-test branch and cd into the source/lib/ldb directory.<br>
+<br>
+To fetch via rsync use these commands:
+
+<pre>
+ rsync -Pavz samba.org::ftp/unpacked/ldb .
+ rsync -Pavz samba.org::ftp/unpacked/tdb .
+ rsync -Pavz samba.org::ftp/unpacked/talloc .
+ rsync -Pavz samba.org::ftp/unpacked/libreplace .
+</pre>
+
+and build in ldb. It will find the other libraries in the directory
+above automatically.
+
+<hr>
+<tiny>
+<a href="http://samba.org/~tridge/">Andrew Tridgell</a><br>
+ldb AT tridgell.net
+</tiny>
+
+</BODY>
+</HTML>
diff --git a/source3/lib/md4.c b/source3/lib/md4.c
new file mode 100644
index 0000000000..bae0091e36
--- /dev/null
+++ b/source3/lib/md4.c
@@ -0,0 +1,174 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* NOTE: This code makes no attempt to be fast!
+
+ It assumes that a int is at least 32 bits long
+*/
+
+#if 0
+static uint32 A, B, C, D;
+#else
+#define A (state[0])
+#define B (state[1])
+#define C (state[2])
+#define D (state[3])
+#endif
+
+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_t *state, uint32 *M)
+{
+ int j;
+ uint32 AA, BB, CC, DD;
+ uint32 X[16];
+
+ for (j=0;j<16;j++)
+ X[j] = M[j];
+
+ AA = A; BB = B; CC = C; DD = D;
+
+ ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
+ ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
+ ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
+ ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
+ ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
+ ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
+ ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
+ ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
+
+ ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
+ ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
+ ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
+ ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
+ ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
+ ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
+ ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
+ ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
+
+ ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
+ ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
+ ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
+ ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
+ ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
+ ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
+ ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
+ ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
+
+ A += AA; B += BB; C += CC; D += DD;
+
+ A &= 0xFFFFFFFF; B &= 0xFFFFFFFF;
+ C &= 0xFFFFFFFF; D &= 0xFFFFFFFF;
+
+ for (j=0;j<16;j++)
+ X[j] = 0;
+}
+
+static void copy64(uint32 *M, const unsigned char *in)
+{
+ int i;
+
+ for (i=0;i<16;i++)
+ M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
+ (in[i*4+1]<<8) | (in[i*4+0]<<0);
+}
+
+static void copy4(unsigned char *out, uint32 x)
+{
+ out[0] = x&0xFF;
+ out[1] = (x>>8)&0xFF;
+ out[2] = (x>>16)&0xFF;
+ out[3] = (x>>24)&0xFF;
+}
+
+/* produce a md4 message digest from data of length n bytes */
+void mdfour(unsigned char *out, const unsigned char *in, int n)
+{
+ unsigned char buf[128];
+ uint32 M[16];
+ uint32 state[4];
+ uint32 b = n * 8;
+ int i;
+
+ A = 0x67452301;
+ B = 0xefcdab89;
+ C = 0x98badcfe;
+ D = 0x10325476;
+
+ while (n > 64) {
+ copy64(M, in);
+ mdfour64(state, M);
+ in += 64;
+ n -= 64;
+ }
+
+ 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(state, M);
+ } else {
+ copy4(buf+120, b);
+ copy64(M, buf);
+ mdfour64(state, M);
+ copy64(M, buf+64);
+ mdfour64(state, M);
+ }
+
+ for (i=0;i<128;i++)
+ buf[i] = 0;
+ copy64(M, buf);
+
+ copy4(out, A);
+ copy4(out+4, B);
+ copy4(out+8, C);
+ copy4(out+12, D);
+}
+
+
diff --git a/source3/lib/md5.c b/source3/lib/md5.c
new file mode 100644
index 0000000000..2121b17047
--- /dev/null
+++ b/source3/lib/md5.c
@@ -0,0 +1,247 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/* This code slightly modified to fit into Samba by
+ abartlet@samba.org Jun 2001 */
+
+#include "includes.h"
+
+#include "md5.h"
+
+static void MD5Transform(uint32 buf[4], uint32 const in[16]);
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+ uint32 t;
+ do {
+ t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(uint32 *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+ register uint32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memmove(p, buf, len);
+ return;
+ }
+ memmove(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memmove(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memmove(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+ unsigned int count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32 *) ctx->in)[14] = ctx->bits[0];
+ ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+ memmove(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(uint32 buf[4], uint32 const in[16])
+{
+ register uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
diff --git a/source3/lib/memcache.c b/source3/lib/memcache.c
new file mode 100644
index 0000000000..e1426bc811
--- /dev/null
+++ b/source3/lib/memcache.c
@@ -0,0 +1,417 @@
+/*
+ Unix SMB/CIFS implementation.
+ In-memory cache
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "memcache.h"
+#include "rbtree.h"
+
+static struct memcache *global_cache;
+
+struct memcache_element {
+ struct rb_node rb_node;
+ struct memcache_element *prev, *next;
+ size_t keylength, valuelength;
+ uint8 n; /* This is really an enum, but save memory */
+ char data[1]; /* placeholder for offsetof */
+};
+
+struct memcache {
+ struct memcache_element *mru, *lru;
+ struct rb_root tree;
+ size_t size;
+ size_t max_size;
+};
+
+static void memcache_element_parse(struct memcache_element *e,
+ DATA_BLOB *key, DATA_BLOB *value);
+
+static bool memcache_is_talloc(enum memcache_number n)
+{
+ bool result;
+
+ switch (n) {
+ case GETPWNAM_CACHE:
+ case PDB_GETPWSID_CACHE:
+ case SINGLETON_CACHE_TALLOC:
+ result = true;
+ break;
+ default:
+ result = false;
+ break;
+ }
+
+ return result;
+}
+
+static int memcache_destructor(struct memcache *cache) {
+ struct memcache_element *e, *next;
+
+ for (e = cache->mru; e != NULL; e = next) {
+ next = e->next;
+ if (memcache_is_talloc((enum memcache_number)e->n)
+ && (e->valuelength == sizeof(void *))) {
+ DATA_BLOB key, value;
+ void *ptr;
+ memcache_element_parse(e, &key, &value);
+ memcpy(&ptr, value.data, sizeof(ptr));
+ TALLOC_FREE(ptr);
+ }
+ SAFE_FREE(e);
+ }
+ return 0;
+}
+
+struct memcache *memcache_init(TALLOC_CTX *mem_ctx, size_t max_size)
+{
+ struct memcache *result;
+
+ result = TALLOC_ZERO_P(mem_ctx, struct memcache);
+ if (result == NULL) {
+ return NULL;
+ }
+ result->max_size = max_size;
+ talloc_set_destructor(result, memcache_destructor);
+ return result;
+}
+
+void memcache_set_global(struct memcache *cache)
+{
+ TALLOC_FREE(global_cache);
+ global_cache = cache;
+}
+
+static struct memcache_element *memcache_node2elem(struct rb_node *node)
+{
+ return (struct memcache_element *)
+ ((char *)node - offsetof(struct memcache_element, rb_node));
+}
+
+static void memcache_element_parse(struct memcache_element *e,
+ DATA_BLOB *key, DATA_BLOB *value)
+{
+ key->data = ((uint8 *)e) + offsetof(struct memcache_element, data);
+ key->length = e->keylength;
+ value->data = key->data + e->keylength;
+ value->length = e->valuelength;
+}
+
+static size_t memcache_element_size(size_t key_length, size_t value_length)
+{
+ return sizeof(struct memcache_element) - 1 + key_length + value_length;
+}
+
+static int memcache_compare(struct memcache_element *e, enum memcache_number n,
+ DATA_BLOB key)
+{
+ DATA_BLOB this_key, this_value;
+
+ if ((int)e->n < (int)n) return 1;
+ if ((int)e->n > (int)n) return -1;
+
+ if (e->keylength < key.length) return 1;
+ if (e->keylength > key.length) return -1;
+
+ memcache_element_parse(e, &this_key, &this_value);
+ return memcmp(this_key.data, key.data, key.length);
+}
+
+static struct memcache_element *memcache_find(
+ struct memcache *cache, enum memcache_number n, DATA_BLOB key)
+{
+ struct rb_node *node;
+
+ node = cache->tree.rb_node;
+
+ while (node != NULL) {
+ struct memcache_element *elem = memcache_node2elem(node);
+ int cmp;
+
+ cmp = memcache_compare(elem, n, key);
+ if (cmp == 0) {
+ return elem;
+ }
+ node = (cmp < 0) ? node->rb_left : node->rb_right;
+ }
+
+ return NULL;
+}
+
+bool memcache_lookup(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key, DATA_BLOB *value)
+{
+ struct memcache_element *e;
+
+ if (cache == NULL) {
+ cache = global_cache;
+ }
+ if (cache == NULL) {
+ return false;
+ }
+
+ e = memcache_find(cache, n, key);
+ if (e == NULL) {
+ return false;
+ }
+
+ if (cache->size != 0) {
+ /*
+ * Do LRU promotion only when we will ever shrink
+ */
+ if (e == cache->lru) {
+ cache->lru = e->prev;
+ }
+ DLIST_PROMOTE(cache->mru, e);
+ if (cache->mru == NULL) {
+ cache->mru = e;
+ }
+ }
+
+ memcache_element_parse(e, &key, value);
+ return true;
+}
+
+void *memcache_lookup_talloc(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key)
+{
+ DATA_BLOB value;
+ void *result;
+
+ if (!memcache_lookup(cache, n, key, &value)) {
+ return NULL;
+ }
+
+ if (value.length != sizeof(result)) {
+ return NULL;
+ }
+
+ memcpy(&result, value.data, sizeof(result));
+
+ return result;
+}
+
+static void memcache_delete_element(struct memcache *cache,
+ struct memcache_element *e)
+{
+ rb_erase(&e->rb_node, &cache->tree);
+
+ if (e == cache->lru) {
+ cache->lru = e->prev;
+ }
+ DLIST_REMOVE(cache->mru, e);
+
+ cache->size -= memcache_element_size(e->keylength, e->valuelength);
+
+ SAFE_FREE(e);
+}
+
+static void memcache_trim(struct memcache *cache)
+{
+ if (cache->max_size == 0) {
+ return;
+ }
+
+ while ((cache->size > cache->max_size) && (cache->lru != NULL)) {
+ memcache_delete_element(cache, cache->lru);
+ }
+}
+
+void memcache_delete(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key)
+{
+ struct memcache_element *e;
+
+ if (cache == NULL) {
+ cache = global_cache;
+ }
+ if (cache == NULL) {
+ return;
+ }
+
+ e = memcache_find(cache, n, key);
+ if (e == NULL) {
+ return;
+ }
+
+ memcache_delete_element(cache, e);
+}
+
+void memcache_add(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key, DATA_BLOB value)
+{
+ struct memcache_element *e;
+ struct rb_node **p;
+ struct rb_node *parent;
+ DATA_BLOB cache_key, cache_value;
+ size_t element_size;
+
+ if (cache == NULL) {
+ cache = global_cache;
+ }
+ if (cache == NULL) {
+ return;
+ }
+
+ if (key.length == 0) {
+ return;
+ }
+
+ e = memcache_find(cache, n, key);
+
+ if (e != NULL) {
+ memcache_element_parse(e, &cache_key, &cache_value);
+
+ if (value.length <= cache_value.length) {
+ /*
+ * We can reuse the existing record
+ */
+ memcpy(cache_value.data, value.data, value.length);
+ e->valuelength = value.length;
+ return;
+ }
+
+ memcache_delete_element(cache, e);
+ }
+
+ element_size = memcache_element_size(key.length, value.length);
+
+
+ e = (struct memcache_element *)SMB_MALLOC(element_size);
+
+ if (e == NULL) {
+ DEBUG(0, ("malloc failed\n"));
+ return;
+ }
+
+ e->n = n;
+ e->keylength = key.length;
+ e->valuelength = value.length;
+
+ memcache_element_parse(e, &cache_key, &cache_value);
+ memcpy(cache_key.data, key.data, key.length);
+ memcpy(cache_value.data, value.data, value.length);
+
+ parent = NULL;
+ p = &cache->tree.rb_node;
+
+ while (*p) {
+ struct memcache_element *elem = memcache_node2elem(*p);
+ int cmp;
+
+ parent = (*p);
+
+ cmp = memcache_compare(elem, n, key);
+
+ p = (cmp < 0) ? &(*p)->rb_left : &(*p)->rb_right;
+ }
+
+ rb_link_node(&e->rb_node, parent, p);
+ rb_insert_color(&e->rb_node, &cache->tree);
+
+ DLIST_ADD(cache->mru, e);
+ if (cache->lru == NULL) {
+ cache->lru = e;
+ }
+
+ cache->size += element_size;
+ memcache_trim(cache);
+}
+
+void memcache_add_talloc(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key, void *ptr)
+{
+ memcache_add(cache, n, key, data_blob_const(&ptr, sizeof(ptr)));
+}
+
+void memcache_flush(struct memcache *cache, enum memcache_number n)
+{
+ struct rb_node *node;
+
+ if (cache == NULL) {
+ cache = global_cache;
+ }
+ if (cache == NULL) {
+ return;
+ }
+
+ /*
+ * Find the smallest element of number n
+ */
+
+ node = cache->tree.rb_node;
+ if (node == NULL) {
+ return;
+ }
+
+ /*
+ * First, find *any* element of number n
+ */
+
+ while (true) {
+ struct memcache_element *elem = memcache_node2elem(node);
+ struct rb_node *next;
+
+ if ((int)elem->n == (int)n) {
+ break;
+ }
+
+ if ((int)elem->n < (int)n) {
+ next = node->rb_right;
+ }
+ else {
+ next = node->rb_left;
+ }
+ if (next == NULL) {
+ break;
+ }
+ node = next;
+ }
+
+ if (node == NULL) {
+ return;
+ }
+
+ /*
+ * Then, find the leftmost element with number n
+ */
+
+ while (true) {
+ struct rb_node *prev = rb_prev(node);
+ struct memcache_element *elem;
+
+ if (prev == NULL) {
+ break;
+ }
+ elem = memcache_node2elem(prev);
+ if ((int)elem->n != (int)n) {
+ break;
+ }
+ node = prev;
+ }
+
+ while (node != NULL) {
+ struct memcache_element *e = memcache_node2elem(node);
+ struct rb_node *next = rb_next(node);
+
+ if (e->n != n) {
+ break;
+ }
+
+ memcache_delete_element(cache, e);
+ node = next;
+ }
+}
diff --git a/source3/lib/messages.c b/source3/lib/messages.c
new file mode 100644
index 0000000000..f5933cafdb
--- /dev/null
+++ b/source3/lib/messages.c
@@ -0,0 +1,363 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba internal messaging functions
+ Copyright (C) Andrew Tridgell 2000
+ Copyright (C) 2001 by Martin Pool
+ Copyright (C) 2002 by Jeremy Allison
+ Copyright (C) 2007 by Volker Lendecke
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ @defgroup messages Internal messaging framework
+ @{
+ @file messages.c
+
+ @brief Module for internal messaging between Samba daemons.
+
+ The idea is that if a part of Samba wants to do communication with
+ another Samba process then it will do a message_register() of a
+ dispatch function, and use message_send_pid() to send messages to
+ that process.
+
+ The dispatch function is given the pid of the sender, and it can
+ use that to reply by message_send_pid(). See ping_message() for a
+ simple example.
+
+ @caution Dispatch functions must be able to cope with incoming
+ messages on an *odd* byte boundary.
+
+ This system doesn't have any inherent size limitations but is not
+ very efficient for large messages or when messages are sent in very
+ quick succession.
+
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/messaging.h"
+#include "librpc/gen_ndr/ndr_messaging.h"
+
+struct messaging_callback {
+ struct messaging_callback *prev, *next;
+ uint32 msg_type;
+ void (*fn)(struct messaging_context *msg, void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id, DATA_BLOB *data);
+ void *private_data;
+};
+
+/****************************************************************************
+ A useful function for testing the message system.
+****************************************************************************/
+
+static void ping_message(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ DATA_BLOB *data)
+{
+ const char *msg = data->data ? (const char *)data->data : "none";
+
+ DEBUG(1,("INFO: Received PING message from PID %s [%s]\n",
+ procid_str_static(&src), msg));
+ messaging_send(msg_ctx, src, MSG_PONG, data);
+}
+
+/****************************************************************************
+ Register/replace a dispatch function for a particular message type.
+ JRA changed Dec 13 2006. Only one message handler now permitted per type.
+ *NOTE*: Dispatch functions must be able to cope with incoming
+ messages on an *odd* byte boundary.
+****************************************************************************/
+
+struct msg_all {
+ struct messaging_context *msg_ctx;
+ int msg_type;
+ uint32 msg_flag;
+ const void *buf;
+ size_t len;
+ int n_sent;
+};
+
+/****************************************************************************
+ Send one of the messages for the broadcast.
+****************************************************************************/
+
+static int traverse_fn(struct db_record *rec,
+ const struct connections_key *ckey,
+ const struct connections_data *crec,
+ void *state)
+{
+ struct msg_all *msg_all = (struct msg_all *)state;
+ NTSTATUS status;
+
+ if (crec->cnum != -1)
+ return 0;
+
+ /* Don't send if the receiver hasn't registered an interest. */
+
+ if(!(crec->bcast_msg_flags & msg_all->msg_flag))
+ return 0;
+
+ /* If the msg send fails because the pid was not found (i.e. smbd died),
+ * the msg has already been deleted from the messages.tdb.*/
+
+ status = messaging_send_buf(msg_all->msg_ctx,
+ crec->pid, msg_all->msg_type,
+ (uint8 *)msg_all->buf, msg_all->len);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
+
+ /* If the pid was not found delete the entry from connections.tdb */
+
+ DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n",
+ procid_str_static(&crec->pid), crec->cnum,
+ crec->servicename));
+
+ rec->delete_rec(rec);
+ }
+ msg_all->n_sent++;
+ return 0;
+}
+
+/**
+ * Send a message to all smbd processes.
+ *
+ * It isn't very efficient, but should be OK for the sorts of
+ * applications that use it. When we need efficient broadcast we can add
+ * it.
+ *
+ * @param n_sent Set to the number of messages sent. This should be
+ * equal to the number of processes, but be careful for races.
+ *
+ * @retval True for success.
+ **/
+bool message_send_all(struct messaging_context *msg_ctx,
+ int msg_type,
+ const void *buf, size_t len,
+ int *n_sent)
+{
+ struct msg_all msg_all;
+
+ msg_all.msg_type = msg_type;
+ if (msg_type < 1000)
+ msg_all.msg_flag = FLAG_MSG_GENERAL;
+ else if (msg_type > 1000 && msg_type < 2000)
+ msg_all.msg_flag = FLAG_MSG_NMBD;
+ else if (msg_type > 2000 && msg_type < 2100)
+ msg_all.msg_flag = FLAG_MSG_PRINT_NOTIFY;
+ else if (msg_type > 2100 && msg_type < 3000)
+ msg_all.msg_flag = FLAG_MSG_PRINT_GENERAL;
+ else if (msg_type > 3000 && msg_type < 4000)
+ msg_all.msg_flag = FLAG_MSG_SMBD;
+ else if (msg_type > 4000 && msg_type < 5000)
+ msg_all.msg_flag = FLAG_MSG_DBWRAP;
+ else
+ return False;
+
+ msg_all.buf = buf;
+ msg_all.len = len;
+ msg_all.n_sent = 0;
+ msg_all.msg_ctx = msg_ctx;
+
+ connections_forall(traverse_fn, &msg_all);
+ if (n_sent)
+ *n_sent = msg_all.n_sent;
+ return True;
+}
+
+struct event_context *messaging_event_context(struct messaging_context *msg_ctx)
+{
+ return msg_ctx->event_ctx;
+}
+
+struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx,
+ struct server_id server_id,
+ struct event_context *ev)
+{
+ struct messaging_context *ctx;
+ NTSTATUS status;
+
+ if (!(ctx = TALLOC_ZERO_P(mem_ctx, struct messaging_context))) {
+ return NULL;
+ }
+
+ ctx->id = server_id;
+ ctx->event_ctx = ev;
+
+ status = messaging_tdb_init(ctx, ctx, &ctx->local);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("messaging_tdb_init failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(ctx);
+ return NULL;
+ }
+
+#ifdef CLUSTER_SUPPORT
+ if (lp_clustering()) {
+ status = messaging_ctdbd_init(ctx, ctx, &ctx->remote);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("messaging_ctdb_init failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(ctx);
+ return NULL;
+ }
+ }
+#endif
+
+ messaging_register(ctx, NULL, MSG_PING, ping_message);
+
+ /* Register some debugging related messages */
+
+ register_msg_pool_usage(ctx);
+ register_dmalloc_msgs(ctx);
+ debug_register_msgs(ctx);
+
+ return ctx;
+}
+
+/*
+ * re-init after a fork
+ */
+NTSTATUS messaging_reinit(struct messaging_context *msg_ctx)
+{
+#ifdef CLUSTER_SUPPORT
+
+ TALLOC_FREE(msg_ctx->remote);
+
+ if (lp_clustering()) {
+ NTSTATUS status;
+
+ status = messaging_ctdbd_init(msg_ctx, msg_ctx,
+ &msg_ctx->remote);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("messaging_ctdb_init failed: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+ }
+
+#endif
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ * Register a dispatch function for a particular message type. Allow multiple
+ * registrants
+*/
+NTSTATUS messaging_register(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ void (*fn)(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data))
+{
+ struct messaging_callback *cb;
+
+ /*
+ * Only one callback per type
+ */
+
+ for (cb = msg_ctx->callbacks; cb != NULL; cb = cb->next) {
+ if (cb->msg_type == msg_type) {
+ cb->fn = fn;
+ cb->private_data = private_data;
+ return NT_STATUS_OK;
+ }
+ }
+
+ if (!(cb = talloc(msg_ctx, struct messaging_callback))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ cb->msg_type = msg_type;
+ cb->fn = fn;
+ cb->private_data = private_data;
+
+ DLIST_ADD(msg_ctx->callbacks, cb);
+ return NT_STATUS_OK;
+}
+
+/*
+ De-register the function for a particular message type.
+*/
+void messaging_deregister(struct messaging_context *ctx, uint32_t msg_type,
+ void *private_data)
+{
+ struct messaging_callback *cb, *next;
+
+ for (cb = ctx->callbacks; cb; cb = next) {
+ next = cb->next;
+ if ((cb->msg_type == msg_type)
+ && (cb->private_data == private_data)) {
+ DLIST_REMOVE(ctx->callbacks, cb);
+ TALLOC_FREE(cb);
+ }
+ }
+}
+
+/*
+ Send a message to a particular server
+*/
+NTSTATUS messaging_send(struct messaging_context *msg_ctx,
+ struct server_id server, uint32_t msg_type,
+ const DATA_BLOB *data)
+{
+#ifdef CLUSTER_SUPPORT
+ if (!procid_is_local(&server)) {
+ return msg_ctx->remote->send_fn(msg_ctx, server,
+ msg_type, data,
+ msg_ctx->remote);
+ }
+#endif
+ return msg_ctx->local->send_fn(msg_ctx, server, msg_type, data,
+ msg_ctx->local);
+}
+
+NTSTATUS messaging_send_buf(struct messaging_context *msg_ctx,
+ struct server_id server, uint32_t msg_type,
+ const uint8 *buf, size_t len)
+{
+ DATA_BLOB blob = data_blob_const(buf, len);
+ return messaging_send(msg_ctx, server, msg_type, &blob);
+}
+
+/*
+ Dispatch one messsaging_rec
+*/
+void messaging_dispatch_rec(struct messaging_context *msg_ctx,
+ struct messaging_rec *rec)
+{
+ struct messaging_callback *cb, *next;
+
+ for (cb = msg_ctx->callbacks; cb != NULL; cb = next) {
+ next = cb->next;
+ if (cb->msg_type == rec->msg_type) {
+ cb->fn(msg_ctx, cb->private_data, rec->msg_type,
+ rec->src, &rec->buf);
+ return;
+ }
+ }
+ return;
+}
+
+/** @} **/
diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c
new file mode 100644
index 0000000000..847ab0fe6a
--- /dev/null
+++ b/source3/lib/messages_ctdbd.c
@@ -0,0 +1,158 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba internal messaging functions
+ Copyright (C) 2007 by Volker Lendecke
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef CLUSTER_SUPPORT
+
+#include "librpc/gen_ndr/messaging.h"
+#include "ctdb.h"
+#include "ctdb_private.h"
+#include "ctdbd_conn.h"
+
+
+struct messaging_ctdbd_context {
+ struct ctdbd_connection *conn;
+};
+
+/*
+ * This is a Samba3 hack/optimization. Routines like process_exists need to
+ * talk to ctdbd, and they don't get handed a messaging context.
+ */
+static struct ctdbd_connection *global_ctdbd_connection;
+static int global_ctdb_connection_pid;
+
+struct ctdbd_connection *messaging_ctdbd_connection(void)
+{
+ if (global_ctdb_connection_pid == 0 &&
+ global_ctdbd_connection == NULL) {
+ struct event_context *ev;
+ struct messaging_context *msg;
+
+ ev = event_context_init(NULL);
+ if (!ev) {
+ DEBUG(0,("event_context_init failed\n"));
+ }
+
+ msg = messaging_init(NULL, procid_self(), ev);
+ if (!msg) {
+ DEBUG(0,("messaging_init failed\n"));
+ return NULL;
+ }
+ }
+
+ if (global_ctdb_connection_pid != getpid()) {
+ DEBUG(0,("messaging_ctdbd_connection():"
+ "valid for pid[%d] but it's [%d]\n",
+ global_ctdb_connection_pid, getpid()));
+ smb_panic("messaging_ctdbd_connection() invalid process\n");
+ }
+
+ return global_ctdbd_connection;
+}
+
+static NTSTATUS messaging_ctdb_send(struct messaging_context *msg_ctx,
+ struct server_id pid, int msg_type,
+ const DATA_BLOB *data,
+ struct messaging_backend *backend)
+{
+ struct messaging_ctdbd_context *ctx = talloc_get_type_abort(
+ backend->private_data, struct messaging_ctdbd_context);
+
+ struct messaging_rec msg;
+
+ msg.msg_version = MESSAGE_VERSION;
+ msg.msg_type = msg_type;
+ msg.dest = pid;
+ msg.src = procid_self();
+ msg.buf = *data;
+
+ return ctdbd_messaging_send(ctx->conn, pid.vnn, pid.pid, &msg);
+}
+
+static int messaging_ctdbd_destructor(struct messaging_ctdbd_context *ctx)
+{
+ /*
+ * The global connection just went away
+ */
+ global_ctdb_connection_pid = 0;
+ global_ctdbd_connection = NULL;
+ return 0;
+}
+
+NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct messaging_backend **presult)
+{
+ struct messaging_backend *result;
+ struct messaging_ctdbd_context *ctx;
+ NTSTATUS status;
+
+ if (!(result = TALLOC_P(mem_ctx, struct messaging_backend))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!(ctx = TALLOC_P(result, struct messaging_ctdbd_context))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = ctdbd_messaging_connection(ctx, &ctx->conn);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("ctdbd_messaging_connection failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(result);
+ return status;
+ }
+
+ status = ctdbd_register_msg_ctx(ctx->conn, msg_ctx);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("ctdbd_register_msg_ctx failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(result);
+ return status;
+ }
+
+ global_ctdb_connection_pid = getpid();
+ global_ctdbd_connection = ctx->conn;
+ talloc_set_destructor(ctx, messaging_ctdbd_destructor);
+
+ set_my_vnn(ctdbd_vnn(ctx->conn));
+
+ result->send_fn = messaging_ctdb_send;
+ result->private_data = (void *)ctx;
+
+ *presult = result;
+ return NT_STATUS_OK;
+}
+
+#else
+
+NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct messaging_backend **presult)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+#endif
diff --git a/source3/lib/messages_local.c b/source3/lib/messages_local.c
new file mode 100644
index 0000000000..f436afc2ff
--- /dev/null
+++ b/source3/lib/messages_local.c
@@ -0,0 +1,436 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba internal messaging functions
+ Copyright (C) 2007 by Volker Lendecke
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ @defgroup messages Internal messaging framework
+ @{
+ @file messages.c
+
+ @brief Module for internal messaging between Samba daemons.
+
+ The idea is that if a part of Samba wants to do communication with
+ another Samba process then it will do a message_register() of a
+ dispatch function, and use message_send_pid() to send messages to
+ that process.
+
+ The dispatch function is given the pid of the sender, and it can
+ use that to reply by message_send_pid(). See ping_message() for a
+ simple example.
+
+ @caution Dispatch functions must be able to cope with incoming
+ messages on an *odd* byte boundary.
+
+ This system doesn't have any inherent size limitations but is not
+ very efficient for large messages or when messages are sent in very
+ quick succession.
+
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/messaging.h"
+#include "librpc/gen_ndr/ndr_messaging.h"
+
+static sig_atomic_t received_signal;
+
+static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
+ struct server_id pid, int msg_type,
+ const DATA_BLOB *data,
+ struct messaging_backend *backend);
+
+/****************************************************************************
+ Notifications come in as signals.
+****************************************************************************/
+
+static void sig_usr1(void)
+{
+ received_signal = 1;
+ sys_select_signal(SIGUSR1);
+}
+
+static int messaging_tdb_destructor(struct messaging_backend *tdb_ctx)
+{
+ struct tdb_wrap *tdb = (struct tdb_wrap *)tdb_ctx->private_data;
+ TALLOC_FREE(tdb);
+ return 0;
+}
+
+/****************************************************************************
+ Initialise the messaging functions.
+****************************************************************************/
+
+NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct messaging_backend **presult)
+{
+ struct messaging_backend *result;
+ struct tdb_wrap *tdb;
+
+ if (!(result = TALLOC_P(mem_ctx, struct messaging_backend))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ tdb = tdb_wrap_open(result, lock_path("messages.tdb"),
+ 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
+ O_RDWR|O_CREAT,0600);
+
+ if (!tdb) {
+ NTSTATUS status = map_nt_error_from_unix(errno);
+ DEBUG(0, ("ERROR: Failed to initialise messages database: "
+ "%s\n", strerror(errno)));
+ TALLOC_FREE(result);
+ return status;
+ }
+
+ sec_init();
+
+ /* Activate the per-hashchain freelist */
+ tdb_set_max_dead(tdb->tdb, 5);
+
+ CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1);
+
+ result->private_data = (void *)tdb;
+ result->send_fn = messaging_tdb_send;
+
+ talloc_set_destructor(result, messaging_tdb_destructor);
+
+ *presult = result;
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Form a static tdb key from a pid.
+******************************************************************/
+
+static TDB_DATA message_key_pid(TALLOC_CTX *mem_ctx, struct server_id pid)
+{
+ char *key;
+ TDB_DATA kbuf;
+
+ key = talloc_asprintf(talloc_tos(), "PID/%s", procid_str_static(&pid));
+
+ SMB_ASSERT(key != NULL);
+
+ kbuf.dptr = (uint8 *)key;
+ kbuf.dsize = strlen(key)+1;
+ return kbuf;
+}
+
+/*
+ Fetch the messaging array for a process
+ */
+
+static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
+ TDB_DATA key,
+ TALLOC_CTX *mem_ctx,
+ struct messaging_array **presult)
+{
+ struct messaging_array *result;
+ TDB_DATA data;
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ if (!(result = TALLOC_ZERO_P(mem_ctx, struct messaging_array))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ data = tdb_fetch(msg_tdb, key);
+
+ if (data.dptr == NULL) {
+ *presult = result;
+ return NT_STATUS_OK;
+ }
+
+ blob = data_blob_const(data.dptr, data.dsize);
+
+ ndr_err = ndr_pull_struct_blob(
+ &blob, result, result,
+ (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
+
+ SAFE_FREE(data.dptr);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(result);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ DEBUG(10, ("messaging_tdb_fetch:\n"));
+ NDR_PRINT_DEBUG(messaging_array, result);
+ }
+
+ *presult = result;
+ return NT_STATUS_OK;
+}
+
+/*
+ Store a messaging array for a pid
+*/
+
+static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
+ TDB_DATA key,
+ struct messaging_array *array)
+{
+ TDB_DATA data;
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ TALLOC_CTX *mem_ctx;
+ int ret;
+
+ if (array->num_messages == 0) {
+ tdb_delete(msg_tdb, key);
+ return NT_STATUS_OK;
+ }
+
+ if (!(mem_ctx = talloc_new(array))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ndr_err = ndr_push_struct_blob(
+ &blob, mem_ctx, array,
+ (ndr_push_flags_fn_t)ndr_push_messaging_array);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(mem_ctx);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ DEBUG(10, ("messaging_tdb_store:\n"));
+ NDR_PRINT_DEBUG(messaging_array, array);
+ }
+
+ data.dptr = blob.data;
+ data.dsize = blob.length;
+
+ ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
+ TALLOC_FREE(mem_ctx);
+
+ return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
+}
+
+/****************************************************************************
+ Notify a process that it has a message. If the process doesn't exist
+ then delete its record in the database.
+****************************************************************************/
+
+static NTSTATUS message_notify(struct server_id procid)
+{
+ pid_t pid = procid.pid;
+ int ret;
+ uid_t euid = geteuid();
+
+ /*
+ * Doing kill with a non-positive pid causes messages to be
+ * sent to places we don't want.
+ */
+
+ SMB_ASSERT(pid > 0);
+
+ if (euid != 0) {
+ /* If we're not root become so to send the message. */
+ save_re_uid();
+ set_effective_uid(0);
+ }
+
+ ret = kill(pid, SIGUSR1);
+
+ if (euid != 0) {
+ /* Go back to who we were. */
+ int saved_errno = errno;
+ restore_re_uid_fromroot();
+ errno = saved_errno;
+ }
+
+ if (ret == 0) {
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * Something has gone wrong
+ */
+
+ DEBUG(2,("message to process %d failed - %s\n", (int)pid,
+ strerror(errno)));
+
+ /*
+ * No call to map_nt_error_from_unix -- don't want to link in
+ * errormap.o into lots of utils.
+ */
+
+ if (errno == ESRCH) return NT_STATUS_INVALID_HANDLE;
+ if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
+ if (errno == EPERM) return NT_STATUS_ACCESS_DENIED;
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/****************************************************************************
+ Send a message to a particular pid.
+****************************************************************************/
+
+static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
+ struct server_id pid, int msg_type,
+ const DATA_BLOB *data,
+ struct messaging_backend *backend)
+{
+ struct messaging_array *msg_array;
+ struct messaging_rec *rec;
+ NTSTATUS status;
+ TDB_DATA key;
+ struct tdb_wrap *tdb = (struct tdb_wrap *)backend->private_data;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ /* NULL pointer means implicit length zero. */
+ if (!data->data) {
+ SMB_ASSERT(data->length == 0);
+ }
+
+ /*
+ * Doing kill with a non-positive pid causes messages to be
+ * sent to places we don't want.
+ */
+
+ SMB_ASSERT(procid_to_pid(&pid) > 0);
+
+ key = message_key_pid(frame, pid);
+
+ if (tdb_chainlock(tdb->tdb, key) == -1) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_LOCK_NOT_GRANTED;
+ }
+
+ status = messaging_tdb_fetch(tdb->tdb, key, talloc_tos(), &msg_array);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if ((msg_type & MSG_FLAG_LOWPRIORITY)
+ && (msg_array->num_messages > 1000)) {
+ DEBUG(5, ("Dropping message for PID %s\n",
+ procid_str_static(&pid)));
+ status = NT_STATUS_INSUFFICIENT_RESOURCES;
+ goto done;
+ }
+
+ if (!(rec = TALLOC_REALLOC_ARRAY(talloc_tos(), msg_array->messages,
+ struct messaging_rec,
+ msg_array->num_messages+1))) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rec[msg_array->num_messages].msg_version = MESSAGE_VERSION;
+ rec[msg_array->num_messages].msg_type = msg_type & MSG_TYPE_MASK;
+ rec[msg_array->num_messages].dest = pid;
+ rec[msg_array->num_messages].src = procid_self();
+ rec[msg_array->num_messages].buf = *data;
+
+ msg_array->messages = rec;
+ msg_array->num_messages += 1;
+
+ status = messaging_tdb_store(tdb->tdb, key, msg_array);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = message_notify(pid);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
+ DEBUG(2, ("pid %s doesn't exist - deleting messages record\n",
+ procid_str_static(&pid)));
+ tdb_delete(tdb->tdb, message_key_pid(talloc_tos(), pid));
+ }
+
+ done:
+ tdb_chainunlock(tdb->tdb, key);
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/****************************************************************************
+ Retrieve all messages for the current process.
+****************************************************************************/
+
+static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb,
+ TALLOC_CTX *mem_ctx,
+ struct messaging_array **presult)
+{
+ struct messaging_array *result;
+ TDB_DATA key = message_key_pid(mem_ctx, procid_self());
+ NTSTATUS status;
+
+ if (tdb_chainlock(msg_tdb, key) == -1) {
+ TALLOC_FREE(key.dptr);
+ return NT_STATUS_LOCK_NOT_GRANTED;
+ }
+
+ status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
+
+ /*
+ * We delete the record here, tdb_set_max_dead keeps it around
+ */
+ tdb_delete(msg_tdb, key);
+ tdb_chainunlock(msg_tdb, key);
+
+ if (NT_STATUS_IS_OK(status)) {
+ *presult = result;
+ }
+
+ TALLOC_FREE(key.dptr);
+
+ return status;
+}
+
+/****************************************************************************
+ Receive and dispatch any messages pending for this process.
+ JRA changed Dec 13 2006. Only one message handler now permitted per type.
+ *NOTE*: Dispatch functions must be able to cope with incoming
+ messages on an *odd* byte boundary.
+****************************************************************************/
+
+void message_dispatch(struct messaging_context *msg_ctx)
+{
+ struct messaging_array *msg_array = NULL;
+ struct tdb_wrap *tdb = (struct tdb_wrap *)
+ (msg_ctx->local->private_data);
+ uint32 i;
+
+ if (!received_signal)
+ return;
+
+ DEBUG(10, ("message_dispatch: received_signal = %d\n",
+ received_signal));
+
+ received_signal = 0;
+
+ if (!NT_STATUS_IS_OK(retrieve_all_messages(tdb->tdb, NULL,
+ &msg_array))) {
+ return;
+ }
+
+ for (i=0; i<msg_array->num_messages; i++) {
+ messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
+ }
+
+ TALLOC_FREE(msg_array);
+}
+
+/** @} **/
diff --git a/source3/lib/module.c b/source3/lib/module.c
new file mode 100644
index 0000000000..76983387ff
--- /dev/null
+++ b/source3/lib/module.c
@@ -0,0 +1,166 @@
+/*
+ Unix SMB/CIFS implementation.
+ module loading system
+
+ Copyright (C) Jelmer Vernooij 2002-2003
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_DLOPEN
+
+/* Load a dynamic module. Only log a level 0 error if we are not checking
+ for the existence of a module (probling). */
+
+static NTSTATUS do_smb_load_module(const char *module_name, bool is_probe)
+{
+ void *handle;
+ init_module_function *init;
+ NTSTATUS status;
+ const char *error;
+
+ /* Always try to use LAZY symbol resolving; if the plugin has
+ * backwards compatibility, there might be symbols in the
+ * plugin referencing to old (removed) functions
+ */
+ handle = sys_dlopen(module_name, RTLD_LAZY);
+
+ /* This call should reset any possible non-fatal errors that
+ occured since last call to dl* functions */
+ error = sys_dlerror();
+
+ if(!handle) {
+ int level = is_probe ? 3 : 0;
+ DEBUG(level, ("Error loading module '%s': %s\n", module_name, error ? error : ""));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ init = (init_module_function *)sys_dlsym(handle, "init_samba_module");
+
+ /* we must check sys_dlerror() to determine if it worked, because
+ sys_dlsym() can validly return NULL */
+ error = sys_dlerror();
+ if (error) {
+ DEBUG(0, ("Error trying to resolve symbol 'init_samba_module' "
+ "in %s: %s\n", module_name, error));
+ sys_dlclose(handle);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(2, ("Module '%s' loaded\n", module_name));
+
+ status = init();
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Module '%s' initialization failed: %s\n",
+ module_name, get_friendly_nt_error_msg(status)));
+ sys_dlclose(handle);
+ }
+
+ return status;
+}
+
+NTSTATUS smb_load_module(const char *module_name)
+{
+ return do_smb_load_module(module_name, False);
+}
+
+/* Load all modules in list and return number of
+ * modules that has been successfully loaded */
+int smb_load_modules(const char **modules)
+{
+ int i;
+ int success = 0;
+
+ for(i = 0; modules[i]; i++){
+ if(NT_STATUS_IS_OK(smb_load_module(modules[i]))) {
+ success++;
+ }
+ }
+
+ DEBUG(2, ("%d modules successfully loaded\n", success));
+
+ return success;
+}
+
+NTSTATUS smb_probe_module(const char *subsystem, const char *module)
+{
+ char *full_path = NULL;
+ TALLOC_CTX *ctx = talloc_stackframe();
+ NTSTATUS status;
+
+ /* Check for absolute path */
+
+ /* if we make any 'samba multibyte string'
+ calls here, we break
+ for loading string modules */
+
+ DEBUG(5, ("Probing module '%s'\n", module));
+
+ if (module[0] == '/') {
+ status = do_smb_load_module(module, True);
+ TALLOC_FREE(ctx);
+ return status;
+ }
+
+ full_path = talloc_asprintf(ctx,
+ "%s/%s.%s",
+ modules_path(subsystem),
+ module,
+ shlib_ext());
+ if (!full_path) {
+ TALLOC_FREE(ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(5, ("Probing module '%s': Trying to load from %s\n",
+ module, full_path));
+
+ status = do_smb_load_module(full_path, True);
+
+ TALLOC_FREE(ctx);
+ return status;
+}
+
+#else /* HAVE_DLOPEN */
+
+NTSTATUS smb_load_module(const char *module_name)
+{
+ DEBUG(0,("This samba executable has not been built with plugin support\n"));
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+int smb_load_modules(const char **modules)
+{
+ DEBUG(0,("This samba executable has not been built with plugin support\n"));
+ return -1;
+}
+
+NTSTATUS smb_probe_module(const char *subsystem, const char *module)
+{
+ DEBUG(0,("This samba executable has not been built with plugin support, not probing\n"));
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+#endif /* HAVE_DLOPEN */
+
+void init_modules(void)
+{
+ /* FIXME: This can cause undefined symbol errors :
+ * smb_register_vfs() isn't available in nmbd, for example */
+ if(lp_preload_modules())
+ smb_load_modules(lp_preload_modules());
+}
diff --git a/source3/lib/ms_fnmatch.c b/source3/lib/ms_fnmatch.c
new file mode 100644
index 0000000000..ca534467fa
--- /dev/null
+++ b/source3/lib/ms_fnmatch.c
@@ -0,0 +1,238 @@
+/*
+ Unix SMB/CIFS implementation.
+ filename matching routine
+ Copyright (C) Andrew Tridgell 1992-2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ This module was originally based on fnmatch.c copyright by the Free
+ Software Foundation. It bears little (if any) resemblence to that
+ code now
+*/
+
+
+#include "includes.h"
+
+static int null_match(const smb_ucs2_t *p)
+{
+ for (;*p;p++) {
+ if (*p != UCS2_CHAR('*') &&
+ *p != UCS2_CHAR('<') &&
+ *p != UCS2_CHAR('"') &&
+ *p != UCS2_CHAR('>')) return -1;
+ }
+ return 0;
+}
+
+/*
+ the max_n structure is purely for efficiency, it doesn't contribute
+ to the matching algorithm except by ensuring that the algorithm does
+ not grow exponentially
+*/
+struct max_n {
+ const smb_ucs2_t *predot;
+ const smb_ucs2_t *postdot;
+};
+
+
+/*
+ p and n are the pattern and string being matched. The max_n array is
+ an optimisation only. The ldot pointer is NULL if the string does
+ not contain a '.', otherwise it points at the last dot in 'n'.
+*/
+static int ms_fnmatch_core(const smb_ucs2_t *p, const smb_ucs2_t *n,
+ struct max_n *max_n, const smb_ucs2_t *ldot,
+ bool is_case_sensitive)
+{
+ smb_ucs2_t c;
+ int i;
+
+ while ((c = *p++)) {
+ switch (c) {
+ /* a '*' matches zero or more characters of any type */
+ case UCS2_CHAR('*'):
+ if (max_n->predot && max_n->predot <= n) {
+ return null_match(p);
+ }
+ for (i=0; n[i]; i++) {
+ if (ms_fnmatch_core(p, n+i, max_n+1, ldot, is_case_sensitive) == 0) {
+ return 0;
+ }
+ }
+ if (!max_n->predot || max_n->predot > n) max_n->predot = n;
+ return null_match(p);
+
+ /* a '<' matches zero or more characters of
+ any type, but stops matching at the last
+ '.' in the string. */
+ case UCS2_CHAR('<'):
+ if (max_n->predot && max_n->predot <= n) {
+ return null_match(p);
+ }
+ if (max_n->postdot && max_n->postdot <= n && n <= ldot) {
+ return -1;
+ }
+ for (i=0; n[i]; i++) {
+ if (ms_fnmatch_core(p, n+i, max_n+1, ldot, is_case_sensitive) == 0) return 0;
+ if (n+i == ldot) {
+ if (ms_fnmatch_core(p, n+i+1, max_n+1, ldot, is_case_sensitive) == 0) return 0;
+ if (!max_n->postdot || max_n->postdot > n) max_n->postdot = n;
+ return -1;
+ }
+ }
+ if (!max_n->predot || max_n->predot > n) max_n->predot = n;
+ return null_match(p);
+
+ /* a '?' matches any single character */
+ case UCS2_CHAR('?'):
+ if (! *n) {
+ return -1;
+ }
+ n++;
+ break;
+
+ /* a '?' matches any single character */
+ case UCS2_CHAR('>'):
+ if (n[0] == UCS2_CHAR('.')) {
+ if (! n[1] && null_match(p) == 0) {
+ return 0;
+ }
+ break;
+ }
+ if (! *n) return null_match(p);
+ n++;
+ break;
+
+ case UCS2_CHAR('"'):
+ if (*n == 0 && null_match(p) == 0) {
+ return 0;
+ }
+ if (*n != UCS2_CHAR('.')) return -1;
+ n++;
+ break;
+
+ default:
+ if (c != *n) {
+ if (is_case_sensitive) {
+ return -1;
+ }
+ if (toupper_w(c) != toupper_w(*n)) {
+ return -1;
+ }
+ }
+ n++;
+ break;
+ }
+ }
+
+ if (! *n) {
+ return 0;
+ }
+
+ return -1;
+}
+
+int ms_fnmatch(const char *pattern, const char *string, bool translate_pattern,
+ bool is_case_sensitive)
+{
+ smb_ucs2_t *p = NULL;
+ smb_ucs2_t *s = NULL;
+ int ret, count, i;
+ struct max_n *max_n = NULL;
+ struct max_n *max_n_free = NULL;
+ struct max_n one_max_n;
+ size_t converted_size;
+
+ if (ISDOTDOT(string)) {
+ string = ".";
+ }
+
+ if (strpbrk(pattern, "<>*?\"") == NULL) {
+ /* this is not just an optmisation - it is essential
+ for LANMAN1 correctness */
+ if (is_case_sensitive) {
+ return strcmp(pattern, string);
+ } else {
+ return StrCaseCmp(pattern, string);
+ }
+ }
+
+ if (!push_ucs2_allocate(&p, pattern, &converted_size)) {
+ return -1;
+ }
+
+ if (!push_ucs2_allocate(&s, string, &converted_size)) {
+ SAFE_FREE(p);
+ return -1;
+ }
+
+ if (translate_pattern) {
+ /*
+ for older negotiated protocols it is possible to
+ translate the pattern to produce a "new style"
+ pattern that exactly matches w2k behaviour
+ */
+ for (i=0;p[i];i++) {
+ if (p[i] == UCS2_CHAR('?')) {
+ p[i] = UCS2_CHAR('>');
+ } else if (p[i] == UCS2_CHAR('.') &&
+ (p[i+1] == UCS2_CHAR('?') ||
+ p[i+1] == UCS2_CHAR('*') ||
+ p[i+1] == 0)) {
+ p[i] = UCS2_CHAR('"');
+ } else if (p[i] == UCS2_CHAR('*') && p[i+1] == UCS2_CHAR('.')) {
+ p[i] = UCS2_CHAR('<');
+ }
+ }
+ }
+
+ for (count=i=0;p[i];i++) {
+ if (p[i] == UCS2_CHAR('*') || p[i] == UCS2_CHAR('<')) count++;
+ }
+
+ if (count != 0) {
+ if (count == 1) {
+ /*
+ * We're doing this a LOT, so save the effort to allocate
+ */
+ ZERO_STRUCT(one_max_n);
+ max_n = &one_max_n;
+ }
+ else {
+ max_n = SMB_CALLOC_ARRAY(struct max_n, count);
+ if (!max_n) {
+ SAFE_FREE(p);
+ SAFE_FREE(s);
+ return -1;
+ }
+ max_n_free = max_n;
+ }
+ }
+
+ ret = ms_fnmatch_core(p, s, max_n, strrchr_w(s, UCS2_CHAR('.')), is_case_sensitive);
+
+ SAFE_FREE(max_n_free);
+ SAFE_FREE(p);
+ SAFE_FREE(s);
+ return ret;
+}
+
+
+/* a generic fnmatch function - uses for non-CIFS pattern matching */
+int gen_fnmatch(const char *pattern, const char *string)
+{
+ return ms_fnmatch(pattern, string, PROTOCOL_NT1, False);
+}
diff --git a/source3/lib/netapi/Doxyfile b/source3/lib/netapi/Doxyfile
new file mode 100644
index 0000000000..44bf78b06c
--- /dev/null
+++ b/source3/lib/netapi/Doxyfile
@@ -0,0 +1,1362 @@
+# Doxyfile 1.5.5
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = Samba
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 3.2.0pre3
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = dox
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
+# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
+# and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH = $(PWD)/
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = NO
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = NO
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = NO
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = netapi.h
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS = *.c \
+ *.h \
+ *.idl
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = include/includes.h \
+ include/proto.h \
+ libnetapi.c \
+ libnetapi.h \
+ netapi.c
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH = examples
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 1
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = .
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 3
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = YES
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = NO
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is enabled by default, which results in a transparent
+# background. Warning: Depending on the platform used, enabling this option
+# may lead to badly anti-aliased labels on the edges of a graph (i.e. they
+# become hard to read).
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/source3/lib/netapi/cm.c b/source3/lib/netapi/cm.c
new file mode 100644
index 0000000000..a5c85bfe6b
--- /dev/null
+++ b/source3/lib/netapi/cm.c
@@ -0,0 +1,198 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi Support
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#include "lib/netapi/netapi.h"
+#include "lib/netapi/netapi_private.h"
+
+/********************************************************************
+********************************************************************/
+
+static WERROR libnetapi_open_ipc_connection(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ struct cli_state **cli)
+{
+ struct cli_state *cli_ipc = NULL;
+
+ if (!ctx || !cli || !server_name) {
+ return WERR_INVALID_PARAM;
+ }
+
+ cli_cm_set_signing_state(Undefined);
+
+ if (ctx->use_kerberos) {
+ cli_cm_set_use_kerberos();
+ }
+
+ if (ctx->password) {
+ cli_cm_set_password(ctx->password);
+ }
+ if (ctx->username) {
+ cli_cm_set_username(ctx->username);
+ }
+
+ if (ctx->username && ctx->username[0] &&
+ ctx->password && ctx->password[0] &&
+ ctx->use_kerberos) {
+ cli_cm_set_fallback_after_kerberos();
+ }
+
+ cli_ipc = cli_cm_open(ctx, NULL,
+ server_name, "IPC$",
+ false, false);
+ if (!cli_ipc) {
+ libnetapi_set_error_string(ctx,
+ "Failed to connect to IPC$ share on %s", server_name);
+ return WERR_CAN_NOT_COMPLETE;
+ }
+
+ *cli = cli_ipc;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR libnetapi_shutdown_cm(struct libnetapi_ctx *ctx)
+{
+ cli_cm_shutdown();
+
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+struct client_pipe_connection {
+ struct client_pipe_connection *prev, *next;
+ struct rpc_pipe_client *pipe;
+};
+
+static struct client_pipe_connection *pipe_connections;
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS pipe_cm_find(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ struct rpc_pipe_client **presult)
+{
+ struct client_pipe_connection *p;
+
+ for (p = pipe_connections; p; p = p->next) {
+
+ if (!rpc_pipe_np_smb_conn(p->pipe)) {
+ return NT_STATUS_PIPE_EMPTY;
+ }
+
+ if (strequal(cli->desthost, p->pipe->desthost)
+ && ndr_syntax_id_equal(&p->pipe->abstract_syntax,
+ interface)) {
+ *presult = p->pipe;
+ return NT_STATUS_OK;
+ }
+ }
+
+ return NT_STATUS_PIPE_NOT_AVAILABLE;
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS pipe_cm_connect(TALLOC_CTX *mem_ctx,
+ struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ struct rpc_pipe_client **presult)
+{
+ struct client_pipe_connection *p;
+ NTSTATUS status;
+
+ p = TALLOC_ZERO_ARRAY(mem_ctx, struct client_pipe_connection, 1);
+ if (!p) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = cli_rpc_pipe_open_noauth(cli, interface, &p->pipe);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(p);
+ return status;
+ }
+
+ DLIST_ADD(pipe_connections, p);
+
+ *presult = p->pipe;
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS pipe_cm_open(TALLOC_CTX *ctx,
+ struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ struct rpc_pipe_client **presult)
+{
+ if (NT_STATUS_IS_OK(pipe_cm_find(cli, interface, presult))) {
+ return NT_STATUS_OK;
+ }
+
+ return pipe_cm_connect(ctx, cli, interface, presult);
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR libnetapi_open_pipe(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const struct ndr_syntax_id *interface,
+ struct cli_state **pcli,
+ struct rpc_pipe_client **presult)
+{
+ struct rpc_pipe_client *result = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ struct cli_state *cli = NULL;
+
+ if (!presult) {
+ return WERR_INVALID_PARAM;
+ }
+
+ werr = libnetapi_open_ipc_connection(ctx, server_name, &cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ status = pipe_cm_open(ctx, cli, interface, &result);
+ if (!NT_STATUS_IS_OK(status)) {
+ libnetapi_set_error_string(ctx, "failed to open PIPE %s: %s",
+ cli_get_pipe_name_from_iface(debug_ctx(), cli,
+ interface),
+ get_friendly_nt_error_msg(status));
+ return WERR_DEST_NOT_FOUND;
+ }
+
+ *presult = result;
+ *pcli = cli;
+
+ return WERR_OK;
+}
+
+
diff --git a/source3/lib/netapi/examples/Makefile.in b/source3/lib/netapi/examples/Makefile.in
new file mode 100644
index 0000000000..b1c1e59be7
--- /dev/null
+++ b/source3/lib/netapi/examples/Makefile.in
@@ -0,0 +1,328 @@
+GTK_FLAGS=`pkg-config gtk+-2.0 --cflags`
+GTK_LIBS=`pkg-config gtk+-2.0 --libs`
+
+KRB5LIBS=@KRB5_LIBS@
+LDAP_LIBS=@LDAP_LIBS@
+LIBS=@LIBS@ -lnetapi -ltdb -ltalloc
+DEVELOPER_CFLAGS=@DEVELOPER_CFLAGS@
+FLAGS=-I../ -L../../../bin @CFLAGS@ $(GTK_FLAGS)
+CC=@CC@
+PICFLAG=@PICFLAG@
+LDFLAGS=@PIE_LDFLAGS@ @LDFLAGS@
+DYNEXP=@DYNEXP@
+NETAPI_LIBS=$(LIBS) $(KRB5LIBS) $(LDAP_LIBS)
+CMDLINE_LIBS=$(NETAPI_LIBS) @POPTLIBS@
+
+# Compile a source file.
+COMPILE_CC = $(CC) -I. $(FLAGS) $(PICFLAG) -c $< -o $@
+COMPILE = $(COMPILE_CC)
+
+PROGS = bin/getdc@EXEEXT@ \
+ bin/dsgetdc@EXEEXT@ \
+ bin/netdomjoin@EXEEXT@ \
+ bin/netdomjoin-gui@EXEEXT@ \
+ bin/getjoinableous@EXEEXT@ \
+ bin/rename_machine@EXEEXT@ \
+ bin/user_add@EXEEXT@ \
+ bin/user_del@EXEEXT@ \
+ bin/user_enum@EXEEXT@ \
+ bin/user_dispinfo@EXEEXT@ \
+ bin/user_chgpwd@EXEEXT@ \
+ bin/user_getinfo@EXEEXT@ \
+ bin/user_setinfo@EXEEXT@ \
+ bin/user_modalsget@EXEEXT@ \
+ bin/user_modalsset@EXEEXT@ \
+ bin/user_getgroups@EXEEXT@ \
+ bin/user_setgroups@EXEEXT@ \
+ bin/user_getlocalgroups@EXEEXT@ \
+ bin/group_add@EXEEXT@ \
+ bin/group_del@EXEEXT@ \
+ bin/group_enum@EXEEXT@ \
+ bin/group_setinfo@EXEEXT@ \
+ bin/group_getinfo@EXEEXT@ \
+ bin/group_adduser@EXEEXT@ \
+ bin/group_deluser@EXEEXT@ \
+ bin/group_getusers@EXEEXT@ \
+ bin/group_setusers@EXEEXT@ \
+ bin/localgroup_add@EXEEXT@ \
+ bin/localgroup_del@EXEEXT@ \
+ bin/localgroup_getinfo@EXEEXT@ \
+ bin/localgroup_setinfo@EXEEXT@ \
+ bin/localgroup_enum@EXEEXT@ \
+ bin/localgroup_addmembers@EXEEXT@ \
+ bin/localgroup_delmembers@EXEEXT@ \
+ bin/localgroup_setmembers@EXEEXT@ \
+ bin/localgroup_getmembers@EXEEXT@ \
+ bin/remote_tod@EXEEXT@ \
+ bin/server_getinfo@EXEEXT@ \
+ bin/share_add@EXEEXT@ \
+ bin/share_del@EXEEXT@ \
+ bin/share_enum@EXEEXT@ \
+ bin/share_getinfo@EXEEXT@ \
+ bin/share_setinfo@EXEEXT@ \
+ bin/file_close@EXEEXT@ \
+ bin/file_getinfo@EXEEXT@ \
+ bin/file_enum@EXEEXT@
+
+all: $(PROGS)
+
+MAKEDIR = || exec false; \
+ if test -d "$$dir"; then :; else \
+ echo mkdir "$$dir"; \
+ mkdir -p "$$dir" >/dev/null 2>&1 || \
+ test -d "$$dir" || \
+ mkdir "$$dir" || \
+ exec false; fi || exec false
+
+BINARY_PREREQS = bin/.dummy
+
+bin/.dummy:
+ @if (: >> $@ || : > $@) >/dev/null 2>&1; then :; else \
+ dir=bin $(MAKEDIR); fi
+ @: >> $@ || : > $@ # what a fancy emoticon!
+
+.c.o:
+ @if (: >> $@ || : > $@) >/dev/null 2>&1; then rm -f $@; else \
+ dir=`echo $@ | sed 's,/[^/]*$$,,;s,^$$,.,'` $(MAKEDIR); fi
+ @echo Compiling $*.c
+ @$(COMPILE) && exit 0;\
+ echo "The following command failed:" 1>&2;\
+ echo "$(COMPILE_CC)" 1>&2;\
+ $(COMPILE_CC) >/dev/null 2>&1
+
+CMDLINE_OBJ = common.o
+GETDC_OBJ = getdc/getdc.o $(CMDLINE_OBJ)
+DSGETDC_OBJ = dsgetdc/dsgetdc.o $(CMDLINE_OBJ)
+NETDOMJOIN_OBJ = join/netdomjoin.o $(CMDLINE_OBJ)
+NETDOMJOIN_GUI_OBJ = netdomjoin-gui/netdomjoin-gui.o
+GETJOINABLEOUS_OBJ = join/getjoinableous.o $(CMDLINE_OBJ)
+RENAMEMACHINE_OBJ = join/rename_machine.o $(CMDLINE_OBJ)
+USERADD_OBJ = user/user_add.o $(CMDLINE_OBJ)
+USERDEL_OBJ = user/user_del.o $(CMDLINE_OBJ)
+USERENUM_OBJ = user/user_enum.o $(CMDLINE_OBJ)
+USERDISPINFO_OBJ = user/user_dispinfo.o $(CMDLINE_OBJ)
+USERCHGPWD_OBJ = user/user_chgpwd.o $(CMDLINE_OBJ)
+USERGETINFO_OBJ = user/user_getinfo.o $(CMDLINE_OBJ)
+USERSETINFO_OBJ = user/user_setinfo.o $(CMDLINE_OBJ)
+USERMODALSGET_OBJ = user/user_modalsget.o $(CMDLINE_OBJ)
+USERMODALSSET_OBJ = user/user_modalsset.o $(CMDLINE_OBJ)
+USERGETGROUPS_OBJ = user/user_getgroups.o $(CMDLINE_OBJ)
+USERSETGROUPS_OBJ = user/user_setgroups.o $(CMDLINE_OBJ)
+USERGETLOCALGROUPS_OBJ = user/user_getlocalgroups.o $(CMDLINE_OBJ)
+GROUPADD_OBJ = group/group_add.o $(CMDLINE_OBJ)
+GROUPDEL_OBJ = group/group_del.o $(CMDLINE_OBJ)
+GROUPENUM_OBJ = group/group_enum.o $(CMDLINE_OBJ)
+GROUPSETINFO_OBJ = group/group_setinfo.o $(CMDLINE_OBJ)
+GROUPGETINFO_OBJ = group/group_getinfo.o $(CMDLINE_OBJ)
+GROUPADDUSER_OBJ = group/group_adduser.o $(CMDLINE_OBJ)
+GROUPDELUSER_OBJ = group/group_deluser.o $(CMDLINE_OBJ)
+GROUPGETUSERS_OBJ = group/group_getusers.o $(CMDLINE_OBJ)
+GROUPSETUSERS_OBJ = group/group_setusers.o $(CMDLINE_OBJ)
+LOCALGROUPADD_OBJ = localgroup/localgroup_add.o $(CMDLINE_OBJ)
+LOCALGROUPDEL_OBJ = localgroup/localgroup_del.o $(CMDLINE_OBJ)
+LOCALGROUPGETINFO_OBJ = localgroup/localgroup_getinfo.o $(CMDLINE_OBJ)
+LOCALGROUPSETINFO_OBJ = localgroup/localgroup_setinfo.o $(CMDLINE_OBJ)
+LOCALGROUPENUM_OBJ = localgroup/localgroup_enum.o $(CMDLINE_OBJ)
+LOCALGROUPADDMEMBERS_OBJ = localgroup/localgroup_addmembers.o $(CMDLINE_OBJ)
+LOCALGROUPDELMEMBERS_OBJ = localgroup/localgroup_delmembers.o $(CMDLINE_OBJ)
+LOCALGROUPSETMEMBERS_OBJ = localgroup/localgroup_setmembers.o $(CMDLINE_OBJ)
+LOCALGROUPGETMEMBERS_OBJ = localgroup/localgroup_getmembers.o $(CMDLINE_OBJ)
+REMOTETOD_OBJ = server/remote_tod.o $(CMDLINE_OBJ)
+SERVERGETINFO_OBJ = server/server_getinfo.o $(CMDLINE_OBJ)
+SHAREADD_OBJ = share/share_add.o $(CMDLINE_OBJ)
+SHAREDEL_OBJ = share/share_del.o $(CMDLINE_OBJ)
+SHAREENUM_OBJ = share/share_enum.o $(CMDLINE_OBJ)
+SHAREGETINFO_OBJ = share/share_getinfo.o $(CMDLINE_OBJ)
+SHARESETINFO_OBJ = share/share_setinfo.o $(CMDLINE_OBJ)
+FILECLOSE_OBJ = file/file_close.o $(CMDLINE_OBJ)
+FILEGETINFO_OBJ = file/file_getinfo.o $(CMDLINE_OBJ)
+FILEENUM_OBJ = file/file_enum.o $(CMDLINE_OBJ)
+
+bin/getdc@EXEEXT@: $(BINARY_PREREQS) $(GETDC_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(GETDC_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/dsgetdc@EXEEXT@: $(BINARY_PREREQS) $(DSGETDC_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(DSGETDC_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/getjoinableous@EXEEXT@: $(BINARY_PREREQS) $(GETJOINABLEOUS_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(GETJOINABLEOUS_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/rename_machine@EXEEXT@: $(BINARY_PREREQS) $(RENAMEMACHINE_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(RENAMEMACHINE_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/netdomjoin@EXEEXT@: $(BINARY_PREREQS) $(NETDOMJOIN_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(NETDOMJOIN_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/netdomjoin-gui@EXEEXT@: $(BINARY_PREREQS) $(NETDOMJOIN_GUI_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) $(GTK_FLAGS) -o $@ $(NETDOMJOIN_GUI_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) $(GTK_LIBS)
+
+bin/user_add@EXEEXT@: $(BINARY_PREREQS) $(USERADD_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(USERADD_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/user_del@EXEEXT@: $(BINARY_PREREQS) $(USERDEL_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(USERDEL_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/user_enum@EXEEXT@: $(BINARY_PREREQS) $(USERENUM_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(USERENUM_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/user_dispinfo@EXEEXT@: $(BINARY_PREREQS) $(USERDISPINFO_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(USERDISPINFO_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/user_chgpwd@EXEEXT@: $(BINARY_PREREQS) $(USERCHGPWD_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(USERCHGPWD_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/user_getinfo@EXEEXT@: $(BINARY_PREREQS) $(USERGETINFO_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(USERGETINFO_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/user_setinfo@EXEEXT@: $(BINARY_PREREQS) $(USERSETINFO_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(USERSETINFO_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/user_modalsget@EXEEXT@: $(BINARY_PREREQS) $(USERMODALSGET_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(USERMODALSGET_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/user_modalsset@EXEEXT@: $(BINARY_PREREQS) $(USERMODALSSET_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(USERMODALSSET_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/user_getgroups@EXEEXT@: $(BINARY_PREREQS) $(USERGETGROUPS_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(USERGETGROUPS_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/user_setgroups@EXEEXT@: $(BINARY_PREREQS) $(USERSETGROUPS_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(USERSETGROUPS_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/user_getlocalgroups@EXEEXT@: $(BINARY_PREREQS) $(USERGETLOCALGROUPS_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(USERGETLOCALGROUPS_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/group_add@EXEEXT@: $(BINARY_PREREQS) $(GROUPADD_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(GROUPADD_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/group_del@EXEEXT@: $(BINARY_PREREQS) $(GROUPDEL_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(GROUPDEL_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/group_enum@EXEEXT@: $(BINARY_PREREQS) $(GROUPENUM_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(GROUPENUM_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/group_setinfo@EXEEXT@: $(BINARY_PREREQS) $(GROUPSETINFO_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(GROUPSETINFO_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/group_getinfo@EXEEXT@: $(BINARY_PREREQS) $(GROUPGETINFO_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(GROUPGETINFO_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/group_adduser@EXEEXT@: $(BINARY_PREREQS) $(GROUPADDUSER_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(GROUPADDUSER_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/group_deluser@EXEEXT@: $(BINARY_PREREQS) $(GROUPDELUSER_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(GROUPDELUSER_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/group_getusers@EXEEXT@: $(BINARY_PREREQS) $(GROUPGETUSERS_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(GROUPGETUSERS_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/group_setusers@EXEEXT@: $(BINARY_PREREQS) $(GROUPSETUSERS_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(GROUPSETUSERS_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/localgroup_add@EXEEXT@: $(BINARY_PREREQS) $(LOCALGROUPADD_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LOCALGROUPADD_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/localgroup_del@EXEEXT@: $(BINARY_PREREQS) $(LOCALGROUPDEL_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LOCALGROUPDEL_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/localgroup_getinfo@EXEEXT@: $(BINARY_PREREQS) $(LOCALGROUPGETINFO_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LOCALGROUPGETINFO_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/localgroup_setinfo@EXEEXT@: $(BINARY_PREREQS) $(LOCALGROUPSETINFO_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LOCALGROUPSETINFO_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/localgroup_enum@EXEEXT@: $(BINARY_PREREQS) $(LOCALGROUPENUM_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LOCALGROUPENUM_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/localgroup_addmembers@EXEEXT@: $(BINARY_PREREQS) $(LOCALGROUPADDMEMBERS_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LOCALGROUPADDMEMBERS_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/localgroup_delmembers@EXEEXT@: $(BINARY_PREREQS) $(LOCALGROUPDELMEMBERS_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LOCALGROUPDELMEMBERS_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/localgroup_setmembers@EXEEXT@: $(BINARY_PREREQS) $(LOCALGROUPSETMEMBERS_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LOCALGROUPSETMEMBERS_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/localgroup_getmembers@EXEEXT@: $(BINARY_PREREQS) $(LOCALGROUPGETMEMBERS_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LOCALGROUPGETMEMBERS_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/remote_tod@EXEEXT@: $(BINARY_PREREQS) $(REMOTETOD_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(REMOTETOD_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/server_getinfo@EXEEXT@: $(BINARY_PREREQS) $(SERVERGETINFO_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SERVERGETINFO_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/share_add@EXEEXT@: $(BINARY_PREREQS) $(SHAREADD_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SHAREADD_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/share_del@EXEEXT@: $(BINARY_PREREQS) $(SHAREDEL_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SHAREDEL_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/share_enum@EXEEXT@: $(BINARY_PREREQS) $(SHAREENUM_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SHAREENUM_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/share_getinfo@EXEEXT@: $(BINARY_PREREQS) $(SHAREGETINFO_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SHAREGETINFO_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/share_setinfo@EXEEXT@: $(BINARY_PREREQS) $(SHARESETINFO_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SHARESETINFO_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/file_close@EXEEXT@: $(BINARY_PREREQS) $(FILECLOSE_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(FILECLOSE_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/file_getinfo@EXEEXT@: $(BINARY_PREREQS) $(FILEGETINFO_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(FILEGETINFO_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+bin/file_enum@EXEEXT@: $(BINARY_PREREQS) $(FILEENUM_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(FILEENUM_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+clean:
+ -rm -f $(PROGS)
+ -rm -f core */*~ *~ \
+ */*.o */*/*.o */*/*/*.o
diff --git a/source3/lib/netapi/examples/common.c b/source3/lib/netapi/examples/common.c
new file mode 100644
index 0000000000..74e28616bf
--- /dev/null
+++ b/source3/lib/netapi/examples/common.c
@@ -0,0 +1,65 @@
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <inttypes.h>
+
+#include <popt.h>
+#include <netapi.h>
+
+void popt_common_callback(poptContext con,
+ enum poptCallbackReason reason,
+ const struct poptOption *opt,
+ const char *arg, const void *data)
+{
+ struct libnetapi_ctx *ctx = NULL;
+
+ libnetapi_getctx(&ctx);
+
+ if (reason == POPT_CALLBACK_REASON_PRE) {
+ }
+
+ if (reason == POPT_CALLBACK_REASON_POST) {
+ }
+
+ if (!opt) {
+ return;
+ }
+ switch (opt->val) {
+ case 'U': {
+ char *puser = strdup(arg);
+ char *p = NULL;
+
+ if ((p = strchr(puser,'%'))) {
+ size_t len;
+ *p = 0;
+ libnetapi_set_username(ctx, puser);
+ libnetapi_set_password(ctx, p+1);
+ len = strlen(p+1);
+ memset(strchr(arg,'%')+1,'X',len);
+ } else {
+ libnetapi_set_username(ctx, puser);
+ }
+ free(puser);
+ break;
+ }
+ case 'd':
+ libnetapi_set_debuglevel(ctx, arg);
+ break;
+ case 'p':
+ libnetapi_set_password(ctx, arg);
+ break;
+ case 'k':
+ libnetapi_set_use_kerberos(ctx);
+ break;
+ }
+}
+
+struct poptOption popt_common_netapi_examples[] = {
+ { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, (void *)popt_common_callback },
+ { "user", 'U', POPT_ARG_STRING, NULL, 'U', "Username used for connection", "USERNAME" },
+ { "password", 'p', POPT_ARG_STRING, NULL, 'p', "Password used for connection", "PASSWORD" },
+ { "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Debuglevel", "DEBUGLEVEL" },
+ { "kerberos", 'k', POPT_ARG_NONE, NULL, 'k', "Use Kerberos", NULL },
+ POPT_TABLEEND
+};
+
diff --git a/source3/lib/netapi/examples/common.h b/source3/lib/netapi/examples/common.h
new file mode 100644
index 0000000000..85df51d868
--- /dev/null
+++ b/source3/lib/netapi/examples/common.h
@@ -0,0 +1,11 @@
+#include <popt.h>
+
+void popt_common_callback(poptContext con,
+ enum poptCallbackReason reason,
+ const struct poptOption *opt,
+ const char *arg, const void *data);
+
+extern struct poptOption popt_common_netapi_examples[];
+
+#define POPT_COMMON_LIBNETAPI_EXAMPLES { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_netapi_examples, 0, "Common samba netapi example options:", NULL },
+
diff --git a/source3/lib/netapi/examples/dsgetdc/dsgetdc.c b/source3/lib/netapi/examples/dsgetdc/dsgetdc.c
new file mode 100644
index 0000000000..6265e66a25
--- /dev/null
+++ b/source3/lib/netapi/examples/dsgetdc/dsgetdc.c
@@ -0,0 +1,101 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * DsGetDcName query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+
+ const char *hostname = NULL;
+ const char *domain = NULL;
+ uint32_t flags = 0;
+ struct DOMAIN_CONTROLLER_INFO *info = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ { "flags", 0, POPT_ARG_INT, NULL, 'f', "Query flags", "FLAGS" },
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("dsgetdc", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname domainname");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'f':
+ sscanf(poptGetOptArg(pc), "%x", &flags);
+ }
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ domain = poptGetArg(pc);
+
+ /* DsGetDcName */
+
+ status = DsGetDcName(hostname, domain, NULL, NULL, flags, &info);
+ if (status != 0) {
+ printf("DsGetDcName failed with: %s\n",
+ libnetapi_errstr(status));
+ return status;
+ }
+
+ printf("DC Name:\t\t%s\n", info->domain_controller_name);
+ printf("DC Address:\t\t%s\n", info->domain_controller_address);
+ printf("DC Address Type:\t%d\n", info->domain_controller_address_type);
+ printf("Domain Name:\t\t%s\n", info->domain_name);
+ printf("DNS Forest Name:\t%s\n", info->dns_forest_name);
+ printf("DC flags:\t\t0x%08x\n", info->flags);
+ printf("DC Sitename:\t\t%s\n", info->dc_site_name);
+ printf("Client Sitename:\t%s\n", info->client_site_name);
+
+ out:
+ NetApiBufferFree(info);
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/file/file_close.c b/source3/lib/netapi/examples/file/file_close.c
new file mode 100644
index 0000000000..759173a0ec
--- /dev/null
+++ b/source3/lib/netapi/examples/file/file_close.c
@@ -0,0 +1,83 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetFileClose query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ uint32_t fileid = 0;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("file_close", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname fileid");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ fileid = atoi(poptGetArg(pc));
+
+ /* NetFileClose */
+
+ status = NetFileClose(hostname, fileid);
+ if (status != 0) {
+ printf("NetFileClose failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/file/file_enum.c b/source3/lib/netapi/examples/file/file_enum.c
new file mode 100644
index 0000000000..5fbb285194
--- /dev/null
+++ b/source3/lib/netapi/examples/file/file_enum.c
@@ -0,0 +1,146 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetFileEnum query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *basepath = NULL;
+ const char *username = NULL;
+ uint32_t level = 3;
+ uint8_t *buffer = NULL;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ int i;
+
+ struct FILE_INFO_2 *i2 = NULL;
+ struct FILE_INFO_3 *i3 = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("file_enum", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname basepath username level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ basepath = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ username = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ /* NetFileEnum */
+
+ do {
+
+ status = NetFileEnum(hostname,
+ basepath,
+ username,
+ level,
+ &buffer,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries,
+ &resume_handle);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+ printf("total entries: %d\n", total_entries);
+ switch (level) {
+ case 2:
+ i2 = (struct FILE_INFO_2 *)buffer;
+ break;
+ case 3:
+ i3 = (struct FILE_INFO_3 *)buffer;
+ break;
+ default:
+ break;
+ }
+ for (i=0; i<entries_read; i++) {
+ switch (level) {
+ case 2:
+ printf("file_id: %d\n", i2->fi2_id);
+ i2++;
+ break;
+ case 3:
+ printf("file_id: %d\n", i3->fi3_id);
+ printf("permissions: %d\n", i3->fi3_permissions);
+ printf("num_locks: %d\n", i3->fi3_num_locks);
+ printf("pathname: %s\n", i3->fi3_pathname);
+ printf("username: %s\n", i3->fi3_username);
+ i3++;
+ break;
+ default:
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status != 0) {
+ printf("NetFileEnum failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/file/file_getinfo.c b/source3/lib/netapi/examples/file/file_getinfo.c
new file mode 100644
index 0000000000..9ad8305bc5
--- /dev/null
+++ b/source3/lib/netapi/examples/file/file_getinfo.c
@@ -0,0 +1,112 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetFileGetInfo query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ uint32_t fileid = 0;
+ uint32_t level = 3;
+ uint8_t *buffer = NULL;
+
+ struct FILE_INFO_2 *i2 = NULL;
+ struct FILE_INFO_3 *i3 = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("file_getinfo", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname fileid");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ fileid = atoi(poptGetArg(pc));
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ /* NetFileGetInfo */
+
+ status = NetFileGetInfo(hostname,
+ fileid,
+ level,
+ &buffer);
+ if (status != 0) {
+ printf("NetFileGetInfo failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ switch (level) {
+ case 2:
+ i2 = (struct FILE_INFO_2 *)buffer;
+ printf("file_id: %d\n", i2->fi2_id);
+ break;
+ case 3:
+ i3 = (struct FILE_INFO_3 *)buffer;
+ printf("file_id: %d\n", i3->fi3_id);
+ printf("permissions: %d\n", i3->fi3_permissions);
+ printf("num_locks: %d\n", i3->fi3_num_locks);
+ printf("pathname: %s\n", i3->fi3_pathname);
+ printf("username: %s\n", i3->fi3_username);
+ break;
+ default:
+ break;
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/getdc/getdc.c b/source3/lib/netapi/examples/getdc/getdc.c
new file mode 100644
index 0000000000..98bb6a13b2
--- /dev/null
+++ b/source3/lib/netapi/examples/getdc/getdc.c
@@ -0,0 +1,86 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * GetDCName query
+ * Copyright (C) Guenther Deschner 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+
+ const char *hostname = NULL;
+ const char *domain = NULL;
+ uint8_t *buffer = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("getdc", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname domainname");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ domain = poptGetArg(pc);
+
+ /* NetGetDCName */
+
+ status = NetGetDCName(hostname, domain, &buffer);
+ if (status != 0) {
+ printf("GetDcName failed with: %s\n", libnetapi_errstr(status));
+ } else {
+ printf("%s\n", (char *)buffer);
+ }
+
+ out:
+ NetApiBufferFree(buffer);
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/group/group_add.c b/source3/lib/netapi/examples/group/group_add.c
new file mode 100644
index 0000000000..4da97c5fc5
--- /dev/null
+++ b/source3/lib/netapi/examples/group/group_add.c
@@ -0,0 +1,90 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetGroupAdd query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *groupname = NULL;
+ struct GROUP_INFO_1 g1;
+ uint32_t parm_error = 0;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("group_add", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname groupname");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ groupname = poptGetArg(pc);
+
+ /* NetGroupAdd */
+
+ g1.grpi1_name = groupname;
+ g1.grpi1_comment = "Domain Group created using NetApi example code";
+
+ status = NetGroupAdd(hostname,
+ 1,
+ (uint8_t *)&g1,
+ &parm_error);
+ if (status != 0) {
+ printf("NetGroupAdd failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/group/group_adduser.c b/source3/lib/netapi/examples/group/group_adduser.c
new file mode 100644
index 0000000000..253b3c5ab4
--- /dev/null
+++ b/source3/lib/netapi/examples/group/group_adduser.c
@@ -0,0 +1,91 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetGroupAddUser query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *groupname = NULL;
+ const char *username = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("group_adduser", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname groupname username");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ groupname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ username = poptGetArg(pc);
+
+ /* NetGroupAddUser */
+
+ status = NetGroupAddUser(hostname,
+ groupname,
+ username);
+ if (status != 0) {
+ printf("NetGroupAddUser failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/group/group_del.c b/source3/lib/netapi/examples/group/group_del.c
new file mode 100644
index 0000000000..789e429ea2
--- /dev/null
+++ b/source3/lib/netapi/examples/group/group_del.c
@@ -0,0 +1,82 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetGroupDel query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *groupname = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("group_del", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname groupname");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ groupname = poptGetArg(pc);
+
+ /* NetGroupDel */
+
+ status = NetGroupDel(hostname, groupname);
+ if (status != 0) {
+ printf("NetGroupDel failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/group/group_deluser.c b/source3/lib/netapi/examples/group/group_deluser.c
new file mode 100644
index 0000000000..751ab5c630
--- /dev/null
+++ b/source3/lib/netapi/examples/group/group_deluser.c
@@ -0,0 +1,91 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetGroupDelUser query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *groupname = NULL;
+ const char *username = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("group_deluser", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname groupname username");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ groupname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ username = poptGetArg(pc);
+
+ /* NetGroupDelUser */
+
+ status = NetGroupDelUser(hostname,
+ groupname,
+ username);
+ if (status != 0) {
+ printf("NetGroupDelUser failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/group/group_enum.c b/source3/lib/netapi/examples/group/group_enum.c
new file mode 100644
index 0000000000..fe2aee1dab
--- /dev/null
+++ b/source3/lib/netapi/examples/group/group_enum.c
@@ -0,0 +1,153 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetGroupEnum query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ uint32_t level = 0;
+ uint8_t *buffer = NULL;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ int i;
+ char *sid_str = NULL;
+
+ struct GROUP_INFO_0 *info0 = NULL;
+ struct GROUP_INFO_1 *info1 = NULL;
+ struct GROUP_INFO_2 *info2 = NULL;
+ struct GROUP_INFO_3 *info3 = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("group_enum", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ /* NetGroupEnum */
+
+ do {
+ status = NetGroupEnum(hostname,
+ level,
+ &buffer,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries,
+ &resume_handle);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+ printf("total entries: %d\n", total_entries);
+ switch (level) {
+ case 0:
+ info0 = (struct GROUP_INFO_0 *)buffer;
+ break;
+ case 1:
+ info1 = (struct GROUP_INFO_1 *)buffer;
+ break;
+ case 2:
+ info2 = (struct GROUP_INFO_2 *)buffer;
+ break;
+ case 3:
+ info3 = (struct GROUP_INFO_3 *)buffer;
+ break;
+ default:
+ break;
+ }
+ for (i=0; i<entries_read; i++) {
+ switch (level) {
+ case 0:
+ printf("#%d group: %s\n", i, info0->grpi0_name);
+ info0++;
+ break;
+ case 1:
+ printf("#%d group: %s\n", i, info1->grpi1_name);
+ printf("#%d comment: %s\n", i, info1->grpi1_comment);
+ info1++;
+ break;
+ case 2:
+ printf("#%d group: %s\n", i, info2->grpi2_name);
+ printf("#%d comment: %s\n", i, info2->grpi2_comment);
+ printf("#%d rid: %d\n", i, info2->grpi2_group_id);
+ printf("#%d attributes: 0x%08x\n", i, info2->grpi2_attributes);
+ info2++;
+ break;
+ case 3:
+ printf("#%d group: %s\n", i, info3->grpi3_name);
+ printf("#%d comment: %s\n", i, info3->grpi3_comment);
+ if (ConvertSidToStringSid(info3->grpi3_group_sid,
+ &sid_str)) {
+ printf("#%d group_sid: %s\n", i, sid_str);
+ free(sid_str);
+ }
+ printf("#%d attributes: 0x%08x\n", i, info3->grpi3_attributes);
+ info3++;
+ break;
+
+
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status != 0) {
+ printf("NetGroupEnum failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/group/group_getinfo.c b/source3/lib/netapi/examples/group/group_getinfo.c
new file mode 100644
index 0000000000..2e5b793905
--- /dev/null
+++ b/source3/lib/netapi/examples/group/group_getinfo.c
@@ -0,0 +1,127 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetGroupGetInfo query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *groupname = NULL;
+ uint8_t *buffer = NULL;
+ uint32_t level = 0;
+ struct GROUP_INFO_0 *g0;
+ struct GROUP_INFO_1 *g1;
+ struct GROUP_INFO_2 *g2;
+ struct GROUP_INFO_3 *g3;
+ char *sid_str = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("group_getinfo", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname groupname level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ groupname = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ /* NetGroupGetInfo */
+
+ status = NetGroupGetInfo(hostname,
+ groupname,
+ level,
+ &buffer);
+ if (status != 0) {
+ printf("NetGroupGetInfo failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ switch (level) {
+ case 0:
+ g0 = (struct GROUP_INFO_0 *)buffer;
+ printf("name: %s\n", g0->grpi0_name);
+ break;
+ case 1:
+ g1 = (struct GROUP_INFO_1 *)buffer;
+ printf("name: %s\n", g1->grpi1_name);
+ printf("comment: %s\n", g1->grpi1_comment);
+ break;
+ case 2:
+ g2 = (struct GROUP_INFO_2 *)buffer;
+ printf("name: %s\n", g2->grpi2_name);
+ printf("comment: %s\n", g2->grpi2_comment);
+ printf("group_id: %d\n", g2->grpi2_group_id);
+ printf("attributes: %d\n", g2->grpi2_attributes);
+ break;
+ case 3:
+ g3 = (struct GROUP_INFO_3 *)buffer;
+ printf("name: %s\n", g3->grpi3_name);
+ printf("comment: %s\n", g3->grpi3_comment);
+ if (ConvertSidToStringSid(g3->grpi3_group_sid,
+ &sid_str)) {
+ printf("group_sid: %s\n", sid_str);
+ free(sid_str);
+ }
+ printf("attributes: %d\n", g3->grpi3_attributes);
+ break;
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/group/group_getusers.c b/source3/lib/netapi/examples/group/group_getusers.c
new file mode 100644
index 0000000000..72e79ec3a2
--- /dev/null
+++ b/source3/lib/netapi/examples/group/group_getusers.c
@@ -0,0 +1,132 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetGroupGetUsers query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *groupname = NULL;
+ uint32_t level = 0;
+ uint8_t *buffer = NULL;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ int i;
+
+ struct GROUP_USERS_INFO_0 *info0 = NULL;
+ struct GROUP_USERS_INFO_1 *info1 = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("group_getusers", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname groupname level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ groupname = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ /* NetGroupGetUsers */
+
+ do {
+ status = NetGroupGetUsers(hostname,
+ groupname,
+ level,
+ &buffer,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries,
+ &resume_handle);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+ printf("total entries: %d\n", total_entries);
+ switch (level) {
+ case 0:
+ info0 = (struct GROUP_USERS_INFO_0 *)buffer;
+ break;
+ case 1:
+ info1 = (struct GROUP_USERS_INFO_1 *)buffer;
+ break;
+ default:
+ break;
+ }
+ for (i=0; i<entries_read; i++) {
+ switch (level) {
+ case 0:
+ printf("#%d member: %s\n", i, info0->grui0_name);
+ info0++;
+ break;
+ case 1:
+ printf("#%d member: %s\n", i, info1->grui1_name);
+ printf("#%d attributes: %d\n", i, info1->grui1_attributes);
+ info1++;
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status != 0) {
+ printf("NetGroupGetUsers failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/group/group_setinfo.c b/source3/lib/netapi/examples/group/group_setinfo.c
new file mode 100644
index 0000000000..cd30d8b9b8
--- /dev/null
+++ b/source3/lib/netapi/examples/group/group_setinfo.c
@@ -0,0 +1,142 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetGroupSetInfo query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *groupname = NULL;
+ const char *option = NULL;
+ uint8_t *buffer = NULL;
+ uint32_t level = 0;
+ uint32_t parm_err = 0;
+ struct GROUP_INFO_0 g0;
+ struct GROUP_INFO_1 g1;
+ struct GROUP_INFO_2 g2;
+ struct GROUP_INFO_3 g3;
+ struct GROUP_INFO_1002 g1002;
+ struct GROUP_INFO_1005 g1005;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("group_setinfo", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname groupname level option");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ groupname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ level = atoi(poptGetArg(pc));
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ option = poptGetArg(pc);
+
+ /* NetGroupSetInfo */
+
+ switch (level) {
+ case 0:
+ g0.grpi0_name = option;
+ buffer = (uint8_t *)&g0;
+ break;
+ case 1:
+ g1.grpi1_name = option; /* this one will be ignored */
+ g1.grpi1_comment = option;
+ buffer = (uint8_t *)&g1;
+ break;
+ case 2:
+ g2.grpi2_name = option; /* this one will be ignored */
+ g2.grpi2_comment = option;
+ g2.grpi2_group_id = 4711; /* this one will be ignored */
+ g2.grpi2_attributes = 7;
+ buffer = (uint8_t *)&g2;
+ break;
+ case 3:
+ g3.grpi3_name = option; /* this one will be ignored */
+ g3.grpi3_comment = option;
+ g2.grpi2_attributes = 7;
+ buffer = (uint8_t *)&g3;
+ break;
+ case 1002:
+ g1002.grpi1002_comment = option;
+ buffer = (uint8_t *)&g1002;
+ break;
+ case 1005:
+ g1005.grpi1005_attributes = atoi(option);
+ buffer = (uint8_t *)&g1005;
+ break;
+ }
+
+ status = NetGroupSetInfo(hostname,
+ groupname,
+ level,
+ buffer,
+ &parm_err);
+ if (status != 0) {
+ printf("NetGroupSetInfo failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/group/group_setusers.c b/source3/lib/netapi/examples/group/group_setusers.c
new file mode 100644
index 0000000000..70cf10514c
--- /dev/null
+++ b/source3/lib/netapi/examples/group/group_setusers.c
@@ -0,0 +1,142 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetGroupSetUsers query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *groupname = NULL;
+ uint32_t level = 0;
+ uint8_t *buffer = NULL;
+ uint32_t num_entries = 0;
+ const char **names = NULL;
+ int i = 0;
+ size_t buf_size = 0;
+
+ struct GROUP_USERS_INFO_0 *g0 = NULL;
+ struct GROUP_USERS_INFO_1 *g1 = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("group_setusers", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname groupname level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ groupname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+
+ names = poptGetArgs(pc);
+ for (i=0; names[i] != NULL; i++) {
+ num_entries++;
+ }
+
+ switch (level) {
+ case 0:
+ buf_size = sizeof(struct GROUP_USERS_INFO_0) * num_entries;
+
+ status = NetApiBufferAllocate(buf_size, (void **)&g0);
+ if (status) {
+ printf("NetApiBufferAllocate failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ for (i=0; i<num_entries; i++) {
+ g0[i].grui0_name = names[i];
+ }
+
+ buffer = (uint8_t *)g0;
+ break;
+ case 1:
+ buf_size = sizeof(struct GROUP_USERS_INFO_1) * num_entries;
+
+ status = NetApiBufferAllocate(buf_size, (void **)&g1);
+ if (status) {
+ printf("NetApiBufferAllocate failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ for (i=0; i<num_entries; i++) {
+ g1[i].grui1_name = names[i];
+ }
+
+ buffer = (uint8_t *)g1;
+ break;
+ default:
+ break;
+ }
+
+ /* NetGroupSetUsers */
+
+ status = NetGroupSetUsers(hostname,
+ groupname,
+ level,
+ buffer,
+ num_entries);
+ if (status != 0) {
+ printf("NetGroupSetUsers failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/join/getjoinableous.c b/source3/lib/netapi/examples/join/getjoinableous.c
new file mode 100644
index 0000000000..732f73dd57
--- /dev/null
+++ b/source3/lib/netapi/examples/join/getjoinableous.c
@@ -0,0 +1,95 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Join Support (cmdline + netapi)
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <inttypes.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ const char *host_name = NULL;
+ const char *domain_name = NULL;
+ const char **ous = NULL;
+ uint32_t num_ous = 0;
+ struct libnetapi_ctx *ctx = NULL;
+ int i;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "domain", 0, POPT_ARG_STRING, NULL, 'D', "Domain name", "DOMAIN" },
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("getjoinableous", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname domainname");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'D':
+ domain_name = poptGetOptArg(pc);
+ break;
+ }
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ host_name = poptGetArg(pc);
+
+ /* NetGetJoinableOUs */
+
+ status = NetGetJoinableOUs(host_name,
+ domain_name,
+ ctx->username,
+ ctx->password,
+ &num_ous,
+ &ous);
+ if (status != 0) {
+ printf("failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ } else {
+ printf("Successfully queried joinable ous:\n");
+ for (i=0; i<num_ous; i++) {
+ printf("ou: %s\n", ous[i]);
+ }
+ }
+
+ out:
+ NetApiBufferFree(ous);
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/join/netdomjoin.c b/source3/lib/netapi/examples/join/netdomjoin.c
new file mode 100644
index 0000000000..08ce71b938
--- /dev/null
+++ b/source3/lib/netapi/examples/join/netdomjoin.c
@@ -0,0 +1,104 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Join Support (cmdline + netapi)
+ * Copyright (C) Guenther Deschner 2007-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+enum {
+ OPT_OU = 1000
+};
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ const char *host_name = NULL;
+ const char *domain_name = NULL;
+ const char *account_ou = NULL;
+ const char *account = NULL;
+ const char *password = NULL;
+ uint32_t join_flags = NETSETUP_JOIN_DOMAIN |
+ NETSETUP_ACCT_CREATE |
+ NETSETUP_DOMAIN_JOIN_IF_JOINED;
+ struct libnetapi_ctx *ctx = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "ou", 0, POPT_ARG_STRING, &account_ou, 'U', "Account ou", "ACCOUNT_OU" },
+ { "domain", 0, POPT_ARG_STRING, &domain_name, 'U', "Domain name (required)", "DOMAIN" },
+ { "userd", 0, POPT_ARG_STRING, &account, 'U', "Domain admin account", "USERNAME" },
+ { "passwordd", 0, POPT_ARG_STRING, &password, 'U', "Domain admin password", "PASSWORD" },
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("netdomjoin", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ host_name = poptGetArg(pc);
+
+ if (!domain_name) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+
+ /* NetJoinDomain */
+
+ status = NetJoinDomain(host_name,
+ domain_name,
+ account_ou,
+ account,
+ password,
+ join_flags);
+ if (status != 0) {
+ const char *errstr = NULL;
+ errstr = libnetapi_get_error_string(ctx, status);
+ printf("Join failed with: %s\n", errstr);
+ } else {
+ printf("Successfully joined\n");
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/join/rename_machine.c b/source3/lib/netapi/examples/join/rename_machine.c
new file mode 100644
index 0000000000..a21f9198d8
--- /dev/null
+++ b/source3/lib/netapi/examples/join/rename_machine.c
@@ -0,0 +1,86 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetRenameMachineInDomain query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <inttypes.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ const char *host_name = NULL;
+ const char *new_machine_name = NULL;
+ uint32_t rename_opt = 0;
+ struct libnetapi_ctx *ctx = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("rename_machine", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname newmachinename");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ host_name = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ new_machine_name = poptGetArg(pc);
+
+ /* NetRenameMachineInDomain */
+
+ status = NetRenameMachineInDomain(host_name,
+ new_machine_name,
+ ctx->username,
+ ctx->password,
+ rename_opt);
+ if (status != 0) {
+ printf("failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/localgroup/localgroup_add.c b/source3/lib/netapi/examples/localgroup/localgroup_add.c
new file mode 100644
index 0000000000..7f23c99db1
--- /dev/null
+++ b/source3/lib/netapi/examples/localgroup/localgroup_add.c
@@ -0,0 +1,106 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetLocalGroupAdd query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *groupname = NULL;
+ const char *comment = NULL;
+ struct LOCALGROUP_INFO_0 g0;
+ struct LOCALGROUP_INFO_1 g1;
+ uint32_t parm_error = 0;
+ uint8_t *buf = NULL;
+ uint32_t level = 0;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("localgroup_add", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname groupname comment");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ groupname = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ comment = poptGetArg(pc);
+ }
+
+ /* NetLocalGroupAdd */
+
+ if (comment) {
+ level = 1;
+ g1.lgrpi1_name = groupname;
+ g1.lgrpi1_comment = comment;
+ buf = (uint8_t *)&g1;
+ } else {
+ level = 0;
+ g0.lgrpi0_name = groupname;
+ buf = (uint8_t *)&g0;
+ }
+
+ status = NetLocalGroupAdd(hostname,
+ level,
+ buf,
+ &parm_error);
+ if (status != 0) {
+ printf("NetLocalGroupAdd failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/localgroup/localgroup_addmembers.c b/source3/lib/netapi/examples/localgroup/localgroup_addmembers.c
new file mode 100644
index 0000000000..aa4a9b59b0
--- /dev/null
+++ b/source3/lib/netapi/examples/localgroup/localgroup_addmembers.c
@@ -0,0 +1,141 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetLocalGroupAddMembers query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *groupname = NULL;
+ struct LOCALGROUP_MEMBERS_INFO_0 *g0;
+ struct LOCALGROUP_MEMBERS_INFO_3 *g3;
+ uint32_t total_entries = 0;
+ uint8_t *buffer = NULL;
+ uint32_t level = 3;
+ const char **names = NULL;
+ int i = 0;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("localgroup_addmembers", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname groupname member1 member2 ...");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ groupname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+
+ names = poptGetArgs(pc);
+ for (i=0; names[i] != NULL; i++) {
+ total_entries++;
+ }
+
+ switch (level) {
+ case 0:
+ status = NetApiBufferAllocate(sizeof(struct LOCALGROUP_MEMBERS_INFO_0) * total_entries,
+ (void **)&g0);
+ if (status) {
+ printf("NetApiBufferAllocate failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ for (i=0; i<total_entries; i++) {
+ if (!ConvertStringSidToSid(names[i], &g0[i].lgrmi0_sid)) {
+ printf("could not convert sid\n");
+ goto out;
+ }
+ }
+
+ buffer = (uint8_t *)g0;
+ break;
+ case 3:
+ status = NetApiBufferAllocate(sizeof(struct LOCALGROUP_MEMBERS_INFO_3) * total_entries,
+ (void **)&g3);
+ if (status) {
+ printf("NetApiBufferAllocate failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ for (i=0; i<total_entries; i++) {
+ g3[i].lgrmi3_domainandname = names[i];
+ }
+
+ buffer = (uint8_t *)g3;
+ break;
+ default:
+ break;
+ }
+
+ /* NetLocalGroupAddMembers */
+
+ status = NetLocalGroupAddMembers(hostname,
+ groupname,
+ level,
+ buffer,
+ total_entries);
+ if (status != 0) {
+ printf("NetLocalGroupAddMembers failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/localgroup/localgroup_del.c b/source3/lib/netapi/examples/localgroup/localgroup_del.c
new file mode 100644
index 0000000000..a2515dfdcd
--- /dev/null
+++ b/source3/lib/netapi/examples/localgroup/localgroup_del.c
@@ -0,0 +1,83 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetLocalGroupDel query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *groupname = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("localgroup_del", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname groupname");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ groupname = poptGetArg(pc);
+
+ /* NetLocalGroupDel */
+
+ status = NetLocalGroupDel(hostname,
+ groupname);
+ if (status != 0) {
+ printf("NetLocalGroupDel failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/localgroup/localgroup_delmembers.c b/source3/lib/netapi/examples/localgroup/localgroup_delmembers.c
new file mode 100644
index 0000000000..7bd3ec0993
--- /dev/null
+++ b/source3/lib/netapi/examples/localgroup/localgroup_delmembers.c
@@ -0,0 +1,141 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetLocalGroupDelMembers query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *groupname = NULL;
+ struct LOCALGROUP_MEMBERS_INFO_0 *g0;
+ struct LOCALGROUP_MEMBERS_INFO_3 *g3;
+ uint32_t total_entries = 0;
+ uint8_t *buffer = NULL;
+ uint32_t level = 3;
+ const char **names = NULL;
+ int i = 0;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("localgroup_delmembers", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname groupname member1 member2 ...");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ groupname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+
+ names = poptGetArgs(pc);
+ for (i=0; names[i] != NULL; i++) {
+ total_entries++;
+ }
+
+ switch (level) {
+ case 0:
+ status = NetApiBufferAllocate(sizeof(struct LOCALGROUP_MEMBERS_INFO_0) * total_entries,
+ (void **)&g0);
+ if (status) {
+ printf("NetApiBufferAllocate failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ for (i=0; i<total_entries; i++) {
+ if (!ConvertStringSidToSid(names[i], &g0[i].lgrmi0_sid)) {
+ printf("could not convert sid\n");
+ goto out;
+ }
+ }
+
+ buffer = (uint8_t *)g0;
+ break;
+ case 3:
+ status = NetApiBufferAllocate(sizeof(struct LOCALGROUP_MEMBERS_INFO_3) * total_entries,
+ (void **)&g3);
+ if (status) {
+ printf("NetApiBufferAllocate failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ for (i=0; i<total_entries; i++) {
+ g3[i].lgrmi3_domainandname = names[i];
+ }
+
+ buffer = (uint8_t *)g3;
+ break;
+ default:
+ break;
+ }
+
+ /* NetLocalGroupDelMembers */
+
+ status = NetLocalGroupDelMembers(hostname,
+ groupname,
+ level,
+ buffer,
+ total_entries);
+ if (status != 0) {
+ printf("NetLocalGroupDelMembers failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/localgroup/localgroup_enum.c b/source3/lib/netapi/examples/localgroup/localgroup_enum.c
new file mode 100644
index 0000000000..6fe0cf4173
--- /dev/null
+++ b/source3/lib/netapi/examples/localgroup/localgroup_enum.c
@@ -0,0 +1,126 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetLocalGroupEnum query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ uint32_t level = 0;
+ uint8_t *buffer = NULL;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ int i;
+
+ struct LOCALGROUP_INFO_0 *info0 = NULL;
+ struct LOCALGROUP_INFO_1 *info1 = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("localgroup_enum", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ /* NetLocalGroupEnum */
+
+ do {
+ status = NetLocalGroupEnum(hostname,
+ level,
+ &buffer,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries,
+ &resume_handle);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+ printf("total entries: %d\n", total_entries);
+ switch (level) {
+ case 0:
+ info0 = (struct LOCALGROUP_INFO_0 *)buffer;
+ break;
+ case 1:
+ info1 = (struct LOCALGROUP_INFO_1 *)buffer;
+ break;
+ default:
+ break;
+ }
+ for (i=0; i<entries_read; i++) {
+ switch (level) {
+ case 0:
+ printf("#%d group: %s\n", i, info0->lgrpi0_name);
+ info0++;
+ break;
+ case 1:
+ printf("#%d group: %s\n", i, info1->lgrpi1_name);
+ printf("#%d comment: %s\n", i, info1->lgrpi1_comment);
+ info1++;
+ break;
+ default:
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status != 0) {
+ printf("NetLocalGroupEnum failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/localgroup/localgroup_getinfo.c b/source3/lib/netapi/examples/localgroup/localgroup_getinfo.c
new file mode 100644
index 0000000000..cd8fa8c3b3
--- /dev/null
+++ b/source3/lib/netapi/examples/localgroup/localgroup_getinfo.c
@@ -0,0 +1,112 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetLocalGroupGetInfo query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *groupname = NULL;
+ uint8_t *buffer = NULL;
+ uint32_t level = 0;
+ struct LOCALGROUP_INFO_0 *g0;
+ struct LOCALGROUP_INFO_1 *g1;
+ struct LOCALGROUP_INFO_1002 *g1002;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("localgroup_getinfo", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname groupname level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ groupname = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ /* NetLocalGroupGetInfo */
+
+ status = NetLocalGroupGetInfo(hostname,
+ groupname,
+ level,
+ &buffer);
+ if (status != 0) {
+ printf("NetLocalGroupGetInfo failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ switch (level) {
+ case 0:
+ g0 = (struct LOCALGROUP_INFO_0 *)buffer;
+ printf("name: %s\n", g0->lgrpi0_name);
+ break;
+ case 1:
+ g1 = (struct LOCALGROUP_INFO_1 *)buffer;
+ printf("name: %s\n", g1->lgrpi1_name);
+ printf("comment: %s\n", g1->lgrpi1_comment);
+ break;
+ case 1002:
+ g1002 = (struct LOCALGROUP_INFO_1002 *)buffer;
+ printf("comment: %s\n", g1002->lgrpi1002_comment);
+ break;
+ }
+ NetApiBufferFree(buffer);
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/localgroup/localgroup_getmembers.c b/source3/lib/netapi/examples/localgroup/localgroup_getmembers.c
new file mode 100644
index 0000000000..0589870d02
--- /dev/null
+++ b/source3/lib/netapi/examples/localgroup/localgroup_getmembers.c
@@ -0,0 +1,165 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetLocalGroupGetMembers query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *groupname = NULL;
+ uint32_t level = 0;
+ uint8_t *buffer = NULL;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ char *sid_str = NULL;
+ int i;
+
+ struct LOCALGROUP_MEMBERS_INFO_0 *info0 = NULL;
+ struct LOCALGROUP_MEMBERS_INFO_1 *info1 = NULL;
+ struct LOCALGROUP_MEMBERS_INFO_2 *info2 = NULL;
+ struct LOCALGROUP_MEMBERS_INFO_3 *info3 = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("localgroup_getmembers", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname groupname level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ groupname = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ /* NetLocalGroupGetMembers */
+
+ do {
+ status = NetLocalGroupGetMembers(hostname,
+ groupname,
+ level,
+ &buffer,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries,
+ &resume_handle);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+ printf("total entries: %d\n", total_entries);
+ switch (level) {
+ case 0:
+ info0 = (struct LOCALGROUP_MEMBERS_INFO_0 *)buffer;
+ break;
+ case 1:
+ info1 = (struct LOCALGROUP_MEMBERS_INFO_1 *)buffer;
+ break;
+ case 2:
+ info2 = (struct LOCALGROUP_MEMBERS_INFO_2 *)buffer;
+ break;
+ case 3:
+ info3 = (struct LOCALGROUP_MEMBERS_INFO_3 *)buffer;
+ break;
+ default:
+ break;
+ }
+ for (i=0; i<entries_read; i++) {
+ switch (level) {
+ case 0:
+ if (ConvertSidToStringSid(info0->lgrmi0_sid,
+ &sid_str)) {
+ printf("#%d member sid: %s\n", i, sid_str);
+ free(sid_str);
+ }
+ info0++;
+ break;
+ case 1:
+ if (ConvertSidToStringSid(info1->lgrmi1_sid,
+ &sid_str)) {
+ printf("#%d member sid: %s\n", i, sid_str);
+ free(sid_str);
+ }
+ printf("#%d sid type: %d\n", i, info1->lgrmi1_sidusage);
+ printf("#%d name: %s\n", i, info1->lgrmi1_name);
+ info1++;
+ break;
+ case 2:
+ if (ConvertSidToStringSid(info2->lgrmi2_sid,
+ &sid_str)) {
+ printf("#%d member sid: %s\n", i, sid_str);
+ free(sid_str);
+ }
+ printf("#%d sid type: %d\n", i, info2->lgrmi2_sidusage);
+ printf("#%d full name: %s\n", i, info2->lgrmi2_domainandname);
+ info2++;
+ break;
+ case 3:
+ printf("#%d full name: %s\n", i, info3->lgrmi3_domainandname);
+ info3++;
+ break;
+ default:
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status != 0) {
+ printf("NetLocalGroupGetMembers failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/localgroup/localgroup_setinfo.c b/source3/lib/netapi/examples/localgroup/localgroup_setinfo.c
new file mode 100644
index 0000000000..efcec76786
--- /dev/null
+++ b/source3/lib/netapi/examples/localgroup/localgroup_setinfo.c
@@ -0,0 +1,128 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetLocalGroupSetInfo query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *groupname = NULL;
+ uint8_t *buffer = NULL;
+ uint32_t level = 0;
+ struct LOCALGROUP_INFO_0 g0;
+ struct LOCALGROUP_INFO_1 g1;
+ struct LOCALGROUP_INFO_1002 g1002;
+ const char *newname = NULL;
+ const char *newcomment = NULL;
+ uint32_t parm_err = 0;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ { "newname", 0, POPT_ARG_STRING, NULL, 'n', "New Local Group Name", "NEWNAME" },
+ { "newcomment", 0, POPT_ARG_STRING, NULL, 'c', "New Local Group Comment", "NETCOMMENT" },
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("localgroup_setinfo", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname groupname level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'n':
+ newname = poptGetOptArg(pc);
+ break;
+ case 'c':
+ newcomment = poptGetOptArg(pc);
+ break;
+ }
+
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ groupname = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ if (newname && !newcomment) {
+ g0.lgrpi0_name = newname;
+ buffer = (uint8_t *)&g0;
+ level = 0;
+ } else if (newcomment && !newname) {
+ g1002.lgrpi1002_comment = newcomment;
+ buffer = (uint8_t *)&g1002;
+ level = 1002;
+ } else if (newname && newcomment) {
+ g1.lgrpi1_name = newname;
+ g1.lgrpi1_comment = newcomment;
+ buffer = (uint8_t *)&g1;
+ level = 1;
+ } else {
+ printf("not enough input\n");
+ goto out;
+ }
+
+ /* NetLocalGroupSetInfo */
+
+ status = NetLocalGroupSetInfo(hostname,
+ groupname,
+ level,
+ buffer,
+ &parm_err);
+ if (status != 0) {
+ printf("NetLocalGroupSetInfo failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/localgroup/localgroup_setmembers.c b/source3/lib/netapi/examples/localgroup/localgroup_setmembers.c
new file mode 100644
index 0000000000..c35f2bbb81
--- /dev/null
+++ b/source3/lib/netapi/examples/localgroup/localgroup_setmembers.c
@@ -0,0 +1,146 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetLocalGroupSetMembers query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *groupname = NULL;
+ struct LOCALGROUP_MEMBERS_INFO_0 *g0;
+ struct LOCALGROUP_MEMBERS_INFO_3 *g3;
+ uint32_t total_entries = 0;
+ uint8_t *buffer = NULL;
+ uint32_t level = 3;
+ const char **names = NULL;
+ int i = 0;
+ size_t buf_size = 0;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("localgroup_setmembers", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname groupname member1 member2 ...");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ groupname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+
+ names = poptGetArgs(pc);
+ for (i=0; names[i] != NULL; i++) {
+ total_entries++;
+ }
+
+ switch (level) {
+ case 0:
+ buf_size = sizeof(struct LOCALGROUP_MEMBERS_INFO_0) * total_entries;
+
+ status = NetApiBufferAllocate(buf_size, (void **)&g0);
+ if (status) {
+ printf("NetApiBufferAllocate failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ for (i=0; i<total_entries; i++) {
+ if (!ConvertStringSidToSid(names[i], &g0[i].lgrmi0_sid)) {
+ printf("could not convert sid\n");
+ goto out;
+ }
+ }
+
+ buffer = (uint8_t *)g0;
+ break;
+ case 3:
+ buf_size = sizeof(struct LOCALGROUP_MEMBERS_INFO_3) * total_entries;
+
+ status = NetApiBufferAllocate(buf_size, (void **)&g3);
+ if (status) {
+ printf("NetApiBufferAllocate failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ for (i=0; i<total_entries; i++) {
+ g3[i].lgrmi3_domainandname = names[i];
+ }
+
+ buffer = (uint8_t *)g3;
+ break;
+ default:
+ break;
+ }
+
+ /* NetLocalGroupSetMembers */
+
+ status = NetLocalGroupSetMembers(hostname,
+ groupname,
+ level,
+ buffer,
+ total_entries);
+ if (status != 0) {
+ printf("NetLocalGroupSetMembers failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ NetApiBufferFree(buffer);
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/netdomjoin-gui/logo-small.png b/source3/lib/netapi/examples/netdomjoin-gui/logo-small.png
new file mode 100644
index 0000000000..f041198002
--- /dev/null
+++ b/source3/lib/netapi/examples/netdomjoin-gui/logo-small.png
Binary files differ
diff --git a/source3/lib/netapi/examples/netdomjoin-gui/logo.png b/source3/lib/netapi/examples/netdomjoin-gui/logo.png
new file mode 100644
index 0000000000..6df4ace659
--- /dev/null
+++ b/source3/lib/netapi/examples/netdomjoin-gui/logo.png
Binary files differ
diff --git a/source3/lib/netapi/examples/netdomjoin-gui/netdomjoin-gui.c b/source3/lib/netapi/examples/netdomjoin-gui/netdomjoin-gui.c
new file mode 100644
index 0000000000..40a6e415eb
--- /dev/null
+++ b/source3/lib/netapi/examples/netdomjoin-gui/netdomjoin-gui.c
@@ -0,0 +1,1817 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Join Support (gtk + netapi)
+ * Copyright (C) Guenther Deschner 2007-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <netdb.h>
+
+#include <gtk/gtk.h>
+#include <glib/gprintf.h>
+
+#include <netapi.h>
+
+#define MAX_CRED_LEN 256
+#define MAX_NETBIOS_NAME_LEN 15
+
+#define SAMBA_ICON_PATH "/usr/share/pixmaps/samba/samba.ico"
+#define SAMBA_IMAGE_PATH "/usr/share/pixmaps/samba/logo.png"
+#define SAMBA_IMAGE_PATH_SMALL "/usr/share/pixmaps/samba/logo-small.png"
+
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
+
+static gboolean verbose = FALSE;
+
+typedef struct join_state {
+ struct libnetapi_ctx *ctx;
+ GtkWidget *window_main;
+ GtkWidget *window_parent;
+ GtkWidget *window_do_change;
+ GtkWidget *window_creds_prompt;
+ GtkWidget *entry_account;
+ GtkWidget *entry_password;
+ GtkWidget *entry_domain;
+ GtkWidget *entry_ou_list;
+ GtkWidget *entry_workgroup;
+ GtkWidget *button_ok;
+ GtkWidget *button_apply;
+ GtkWidget *button_ok_creds;
+ GtkWidget *button_get_ous;
+ GtkWidget *label_reboot;
+ GtkWidget *label_current_name_buffer;
+ GtkWidget *label_current_name_type;
+ GtkWidget *label_full_computer_name;
+ GtkWidget *label_winbind;
+ uint16_t name_type_initial;
+ uint16_t name_type_new;
+ char *name_buffer_initial;
+ char *name_buffer_new;
+ char *password;
+ char *account;
+ char *comment;
+ char *comment_new;
+ char *my_fqdn;
+ char *my_dnsdomain;
+ char *my_hostname;
+ uint16_t server_role;
+ gboolean settings_changed;
+ gboolean hostname_changed;
+ uint32_t stored_num_ous;
+ char *target_hostname;
+} join_state;
+
+static void debug(const char *format, ...)
+{
+ va_list args;
+
+ if (!verbose) {
+ return;
+ }
+
+ va_start(args, format);
+ g_vprintf(format, args);
+ va_end(args);
+}
+
+static gboolean callback_delete_event(GtkWidget *widget,
+ GdkEvent *event,
+ gpointer data)
+{
+ gtk_main_quit();
+ return FALSE;
+}
+
+static void callback_do_close_data(GtkWidget *widget,
+ gpointer data)
+{
+ debug("callback_do_close_data called\n");
+
+ if (data) {
+ gtk_widget_destroy(GTK_WIDGET(data));
+ }
+}
+
+static void callback_do_close_widget(GtkWidget *widget,
+ gpointer data)
+{
+ debug("callback_do_close_widget called\n");
+
+ if (widget) {
+ gtk_widget_destroy(widget);
+ }
+}
+
+static void callback_do_freeauth(GtkWidget *widget,
+ gpointer data)
+{
+ struct join_state *state = (struct join_state *)data;
+
+ debug("callback_do_freeauth called\n");
+
+ SAFE_FREE(state->account);
+ SAFE_FREE(state->password);
+
+ if (state->window_creds_prompt) {
+ gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
+ state->window_creds_prompt = NULL;
+ }
+}
+
+static void callback_do_freeauth_and_close(GtkWidget *widget,
+ gpointer data)
+{
+ struct join_state *state = (struct join_state *)data;
+
+ debug("callback_do_freeauth_and_close called\n");
+
+ SAFE_FREE(state->account);
+ SAFE_FREE(state->password);
+
+ if (state->window_creds_prompt) {
+ gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
+ state->window_creds_prompt = NULL;
+ }
+ if (state->window_do_change) {
+ gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
+ state->window_do_change = NULL;
+ }
+}
+
+static void free_join_state(struct join_state *s)
+{
+ SAFE_FREE(s->name_buffer_initial);
+ SAFE_FREE(s->name_buffer_new);
+ SAFE_FREE(s->password);
+ SAFE_FREE(s->account);
+ SAFE_FREE(s->comment);
+ SAFE_FREE(s->comment_new);
+ SAFE_FREE(s->my_fqdn);
+ SAFE_FREE(s->my_dnsdomain);
+ SAFE_FREE(s->my_hostname);
+}
+
+static void do_cleanup(struct join_state *state)
+{
+ libnetapi_free(state->ctx);
+ free_join_state(state);
+}
+
+static void callback_apply_description_change(GtkWidget *widget,
+ gpointer data)
+{
+ struct join_state *state = (struct join_state *)data;
+ NET_API_STATUS status = 0;
+ uint32_t parm_err = 0;
+ struct SERVER_INFO_1005 info1005;
+ GtkWidget *dialog;
+
+ info1005.sv1005_comment = state->comment_new;
+
+ status = NetServerSetInfo(state->target_hostname,
+ 1005,
+ (uint8_t *)&info1005,
+ &parm_err);
+ if (status) {
+ debug("NetServerSetInfo failed with: %s\n",
+ libnetapi_errstr(status));
+ dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "Failed to change computer description: %s.",
+ libnetapi_get_error_string(state->ctx, status));
+ gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+ gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_main));
+
+ g_signal_connect_swapped(dialog, "response",
+ G_CALLBACK(gtk_widget_destroy),
+ dialog);
+
+ gtk_widget_show(dialog);
+ return;
+ }
+
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
+}
+
+static void callback_do_exit(GtkWidget *widget,
+ gpointer data)
+{
+#if 0
+ GtkWidget *dialog;
+ gint result;
+#endif
+ struct join_state *state = (struct join_state *)data;
+
+ if (!state->settings_changed) {
+ callback_delete_event(NULL, NULL, NULL);
+ return;
+ }
+
+#if 0
+ dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ "You must restart your computer before the new settings will take effect.");
+ gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+ result = gtk_dialog_run(GTK_DIALOG(dialog));
+ switch (result) {
+ case GTK_RESPONSE_YES:
+ g_print("would reboot here\n");
+ break;
+ case GTK_RESPONSE_NO:
+ default:
+ break;
+ }
+ if (dialog) {
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+ }
+#endif
+ if (state->window_main) {
+ gtk_widget_destroy(GTK_WIDGET(state->window_main));
+ state->window_main = NULL;
+ }
+ do_cleanup(state);
+ exit(0);
+}
+
+
+static void callback_do_reboot(GtkWidget *widget,
+ gpointer data,
+ gpointer data2)
+{
+ GtkWidget *dialog;
+ struct join_state *state = (struct join_state *)data2;
+
+ debug("callback_do_reboot\n");
+
+ state->settings_changed = TRUE;
+ dialog = gtk_message_dialog_new(GTK_WINDOW(data),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ "You must restart this computer for the changes to take effect.");
+ gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+ gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
+#if 0
+ g_signal_connect_swapped(dialog, "response",
+ G_CALLBACK(gtk_widget_destroy),
+ dialog);
+
+ debug("showing dialog\n");
+ gtk_widget_show(dialog);
+#else
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+#endif
+
+ gtk_label_set_text(GTK_LABEL(state->label_reboot),
+ "Changes will take effect after you restart this computer");
+
+ debug("destroying do_change window\n");
+ gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
+
+ {
+ uint32_t status;
+ const char *buffer;
+ uint16_t type;
+
+ status = NetGetJoinInformation(state->target_hostname,
+ &buffer,
+ &type);
+ if (status != 0) {
+ g_print("failed to query status\n");
+ return;
+ }
+
+ debug("got new status: %s\n", buffer);
+
+ SAFE_FREE(state->name_buffer_new);
+ state->name_buffer_new = strdup(buffer);
+ state->name_type_new = type;
+ state->name_buffer_initial = strdup(buffer);
+ state->name_type_initial = type;
+ NetApiBufferFree((void *)buffer);
+
+ gtk_label_set_text(GTK_LABEL(state->label_current_name_buffer),
+ state->name_buffer_new);
+ if (state->name_type_new == NetSetupDomainName) {
+ gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
+ "Domain:");
+ } else {
+ gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
+ "Workgroup:");
+ }
+ }
+}
+
+static void callback_return_username(GtkWidget *widget,
+ gpointer data)
+{
+ const gchar *entry_text;
+ struct join_state *state = (struct join_state *)data;
+ debug("callback_return_username called\n");
+ if (!widget) {
+ return;
+ }
+ entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
+ if (!entry_text) {
+ return;
+ }
+ debug("callback_return_username: %s\n", entry_text);
+ SAFE_FREE(state->account);
+ state->account = strdup(entry_text);
+}
+
+static void callback_return_username_and_enter(GtkWidget *widget,
+ gpointer data)
+{
+ const gchar *entry_text;
+ struct join_state *state = (struct join_state *)data;
+ if (!widget) {
+ return;
+ }
+ entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
+ if (!entry_text) {
+ return;
+ }
+ debug("callback_return_username_and_enter: %s\n", entry_text);
+ SAFE_FREE(state->account);
+ state->account = strdup(entry_text);
+ g_signal_emit_by_name(state->button_ok_creds, "clicked");
+}
+
+static void callback_return_password(GtkWidget *widget,
+ gpointer data)
+{
+ const gchar *entry_text;
+ struct join_state *state = (struct join_state *)data;
+ debug("callback_return_password called\n");
+ if (!widget) {
+ return;
+ }
+ entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
+ if (!entry_text) {
+ return;
+ }
+#ifdef DEBUG_PASSWORD
+ debug("callback_return_password: %s\n", entry_text);
+#else
+ debug("callback_return_password: (not printed)\n");
+#endif
+ SAFE_FREE(state->password);
+ state->password = strdup(entry_text);
+}
+
+static void callback_return_password_and_enter(GtkWidget *widget,
+ gpointer data)
+{
+ const gchar *entry_text;
+ struct join_state *state = (struct join_state *)data;
+ if (!widget) {
+ return;
+ }
+ entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
+ if (!entry_text) {
+ return;
+ }
+#ifdef DEBUG_PASSWORD
+ debug("callback_return_password_and_enter: %s\n", entry_text);
+#else
+ debug("callback_return_password_and_enter: (not printed)\n");
+#endif
+ SAFE_FREE(state->password);
+ state->password = strdup(entry_text);
+ g_signal_emit_by_name(state->button_ok_creds, "clicked");
+}
+
+static void callback_do_storeauth(GtkWidget *widget,
+ gpointer data)
+{
+ struct join_state *state = (struct join_state *)data;
+
+ debug("callback_do_storeauth called\n");
+
+ SAFE_FREE(state->account);
+ SAFE_FREE(state->password);
+
+ callback_return_username(state->entry_account, (gpointer)state);
+ callback_return_password(state->entry_password, (gpointer)state);
+
+ if (state->window_creds_prompt) {
+ gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
+ state->window_creds_prompt = NULL;
+ }
+}
+
+static void callback_continue(GtkWidget *widget,
+ gpointer data)
+{
+ struct join_state *state = (struct join_state *)data;
+
+ gtk_widget_grab_focus(GTK_WIDGET(state->button_ok));
+ g_signal_emit_by_name(state->button_ok, "clicked");
+}
+
+static void callback_do_storeauth_and_continue(GtkWidget *widget,
+ gpointer data)
+{
+ callback_do_storeauth(widget, data);
+ callback_continue(NULL, data);
+}
+
+static void callback_do_storeauth_and_scan(GtkWidget *widget,
+ gpointer data)
+{
+ struct join_state *state = (struct join_state *)data;
+ callback_do_storeauth(widget, data);
+ g_signal_emit_by_name(state->button_get_ous, "clicked");
+}
+
+static void callback_do_hostname_change(GtkWidget *widget,
+ gpointer data)
+{
+ GtkWidget *dialog;
+ const char *str = NULL;
+
+ struct join_state *state = (struct join_state *)data;
+
+ switch (state->name_type_initial) {
+ case NetSetupDomainName:
+ str = "To be implemented: call NetRenameMachineInDomain\n";
+ break;
+ case NetSetupWorkgroupName:
+ str = "To be implemented: call SetComputerNameEx\n";
+ break;
+ default:
+ break;
+ }
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ str);
+
+ gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+ gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_main));
+ g_signal_connect_swapped(dialog, "response",
+ G_CALLBACK(gtk_widget_destroy),
+ dialog);
+ gtk_widget_show(dialog);
+}
+
+static void callback_creds_prompt(GtkWidget *widget,
+ gpointer data,
+ const char *label_string,
+ gpointer cont_fn)
+{
+ GtkWidget *window;
+ GtkWidget *box1;
+ GtkWidget *bbox;
+ GtkWidget *button;
+ GtkWidget *label;
+
+ struct join_state *state = (struct join_state *)data;
+
+ debug("callback_creds_prompt\n");
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_modal(GTK_WINDOW(window), TRUE);
+
+ gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
+ gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+ gtk_widget_set_size_request(GTK_WIDGET(window), 380, 280);
+ gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
+ gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(state->window_do_change));
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
+
+ g_signal_connect(G_OBJECT(window), "delete_event",
+ G_CALLBACK(callback_do_close_widget), NULL);
+
+ state->window_creds_prompt = window;
+ gtk_container_set_border_width(GTK_CONTAINER(window), 10);
+
+ box1 = gtk_vbox_new(FALSE, 0);
+
+ gtk_container_add(GTK_CONTAINER(window), box1);
+
+ label = gtk_label_new(label_string);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+
+ gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
+
+ gtk_widget_show(label);
+
+ /* USER NAME */
+ label = gtk_label_new("User name:");
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
+ gtk_widget_show(label);
+
+ state->entry_account = gtk_entry_new();
+ gtk_entry_set_max_length(GTK_ENTRY(state->entry_account), MAX_CRED_LEN);
+ g_signal_connect(G_OBJECT(state->entry_account), "activate",
+ G_CALLBACK(callback_return_username_and_enter),
+ (gpointer)state);
+ gtk_editable_select_region(GTK_EDITABLE(state->entry_account),
+ 0, GTK_ENTRY(state->entry_account)->text_length);
+ gtk_box_pack_start(GTK_BOX(box1), state->entry_account, TRUE, TRUE, 0);
+ gtk_widget_show(state->entry_account);
+
+ /* PASSWORD */
+ label = gtk_label_new("Password:");
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
+ gtk_widget_show(label);
+
+ state->entry_password = gtk_entry_new();
+ gtk_entry_set_max_length(GTK_ENTRY(state->entry_password), MAX_CRED_LEN);
+ gtk_entry_set_visibility(GTK_ENTRY(state->entry_password), FALSE);
+ g_signal_connect(G_OBJECT(state->entry_password), "activate",
+ G_CALLBACK(callback_return_password_and_enter),
+ (gpointer)state);
+ gtk_editable_set_editable(GTK_EDITABLE(state->entry_password), TRUE);
+ gtk_editable_select_region(GTK_EDITABLE(state->entry_password),
+ 0, GTK_ENTRY(state->entry_password)->text_length);
+ gtk_box_pack_start(GTK_BOX(box1), state->entry_password, TRUE, TRUE, 0);
+ gtk_widget_show(state->entry_password);
+
+ /* BUTTONS */
+ bbox = gtk_hbutton_box_new();
+ gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
+ gtk_container_add(GTK_CONTAINER(box1), bbox);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing(GTK_BOX(bbox), 10);
+
+ state->button_ok_creds = gtk_button_new_from_stock(GTK_STOCK_OK);
+ gtk_widget_grab_focus(GTK_WIDGET(state->button_ok_creds));
+ gtk_container_add(GTK_CONTAINER(bbox), state->button_ok_creds);
+ g_signal_connect(G_OBJECT(state->button_ok_creds), "clicked",
+ G_CALLBACK(cont_fn),
+ (gpointer)state);
+ gtk_widget_show(state->button_ok_creds);
+
+ button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
+ gtk_container_add(GTK_CONTAINER(bbox), button);
+ g_signal_connect(G_OBJECT(button), "clicked",
+ G_CALLBACK(callback_do_freeauth),
+ (gpointer)state);
+ gtk_widget_show_all(window);
+}
+
+static void callback_do_join(GtkWidget *widget,
+ gpointer data)
+{
+ GtkWidget *dialog;
+
+ NET_API_STATUS status;
+ const char *err_str = NULL;
+ uint32_t join_flags = 0;
+ uint32_t unjoin_flags = 0;
+ gboolean domain_join = FALSE;
+ gboolean try_unjoin = FALSE;
+ gboolean join_creds_required = TRUE;
+ gboolean unjoin_creds_required = TRUE;
+ const char *new_workgroup_type = NULL;
+ const char *initial_workgroup_type = NULL;
+ const char *account_ou = NULL;
+
+ struct join_state *state = (struct join_state *)data;
+
+ if (state->hostname_changed) {
+ callback_do_hostname_change(NULL, state);
+ return;
+ }
+
+ switch (state->name_type_initial) {
+ case NetSetupWorkgroupName:
+ initial_workgroup_type = "workgroup";
+ break;
+ case NetSetupDomainName:
+ initial_workgroup_type = "domain";
+ break;
+ default:
+ break;
+ }
+
+ switch (state->name_type_new) {
+ case NetSetupWorkgroupName:
+ new_workgroup_type = "workgroup";
+ break;
+ case NetSetupDomainName:
+ new_workgroup_type = "domain";
+ break;
+ default:
+ break;
+ }
+
+ account_ou = gtk_combo_box_get_active_text(GTK_COMBO_BOX(state->entry_ou_list));
+ if (account_ou && strlen(account_ou) == 0) {
+ account_ou = NULL;
+ }
+
+ if ((state->name_type_initial != NetSetupDomainName) &&
+ (state->name_type_new != NetSetupDomainName)) {
+ join_creds_required = FALSE;
+ unjoin_creds_required = FALSE;
+ }
+
+ if (state->name_type_new == NetSetupDomainName) {
+ domain_join = TRUE;
+ join_creds_required = TRUE;
+ join_flags = NETSETUP_JOIN_DOMAIN |
+ NETSETUP_ACCT_CREATE |
+ NETSETUP_DOMAIN_JOIN_IF_JOINED; /* for testing */
+ }
+
+ if ((state->name_type_initial == NetSetupDomainName) &&
+ (state->name_type_new == NetSetupWorkgroupName)) {
+ try_unjoin = TRUE;
+ unjoin_creds_required = TRUE;
+ join_creds_required = FALSE;
+ unjoin_flags = NETSETUP_JOIN_DOMAIN |
+ NETSETUP_ACCT_DELETE;
+ }
+
+ if (try_unjoin) {
+
+ debug("callback_do_join: Unjoining\n");
+
+ if (unjoin_creds_required) {
+ if (!state->account || !state->password) {
+ debug("callback_do_join: no creds yet\n");
+ callback_creds_prompt(NULL, state,
+ "Enter the name and password of an account with permission to leave the domain.",
+ callback_do_storeauth_and_continue);
+ }
+
+ if (!state->account || !state->password) {
+ debug("callback_do_join: still no creds???\n");
+ return;
+ }
+ }
+
+ status = NetUnjoinDomain(state->target_hostname,
+ state->account,
+ state->password,
+ unjoin_flags);
+ if (status != 0) {
+ callback_do_freeauth(NULL, state);
+ err_str = libnetapi_get_error_string(state->ctx, status);
+ g_print("callback_do_join: failed to unjoin (%s)\n",
+ err_str);
+#if 0
+
+ /* in fact we shouldn't annoy the user with an error message here */
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "The following error occured attempting to unjoin the %s: \"%s\": %s",
+ initial_workgroup_type,
+ state->name_buffer_initial,
+ err_str);
+ gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+#endif
+ }
+
+ }
+
+ /* before prompting for creds, make sure we can find a dc */
+
+ if (domain_join) {
+
+ struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
+
+ status = DsGetDcName(NULL,
+ state->name_buffer_new,
+ NULL,
+ NULL,
+ 0,
+ &dc_info);
+ if (status != 0) {
+ err_str = libnetapi_get_error_string(state->ctx, status);
+ g_print("callback_do_join: failed find dc (%s)\n", err_str);
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "Failed to find a domain controller for domain: \"%s\": %s",
+ state->name_buffer_new,
+ err_str);
+
+ gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+ gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
+ g_signal_connect_swapped(dialog, "response",
+ G_CALLBACK(gtk_widget_destroy),
+ dialog);
+
+ gtk_widget_show(dialog);
+
+ return;
+ }
+ }
+
+ if (join_creds_required) {
+ if (!state->account || !state->password) {
+ debug("callback_do_join: no creds yet\n");
+ callback_creds_prompt(NULL, state,
+ "Enter the name and password of an account with permission to leave the domain.",
+ callback_do_storeauth_and_continue);
+ }
+
+ if (!state->account || !state->password) {
+ debug("callback_do_join: still no creds???\n");
+ return;
+ }
+ }
+
+ debug("callback_do_join: Joining a %s named %s using join_flags 0x%08x ",
+ new_workgroup_type,
+ state->name_buffer_new,
+ join_flags);
+ if (domain_join) {
+ debug("as %s ", state->account);
+#ifdef DEBUG_PASSWORD
+ debug("with %s ", state->password);
+#endif
+ }
+ debug("\n");
+
+ status = NetJoinDomain(state->target_hostname,
+ state->name_buffer_new,
+ account_ou,
+ state->account,
+ state->password,
+ join_flags);
+ if (status != 0) {
+ callback_do_freeauth(NULL, state);
+ err_str = libnetapi_get_error_string(state->ctx, status);
+ g_print("callback_do_join: failed to join (%s)\n", err_str);
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "The following error occured attempting to join the %s: \"%s\": %s",
+ new_workgroup_type,
+ state->name_buffer_new,
+ err_str);
+
+ gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+ gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
+ g_signal_connect_swapped(dialog, "response",
+ G_CALLBACK(gtk_widget_destroy),
+ dialog);
+
+ gtk_widget_show(dialog);
+
+ return;
+ }
+
+ debug("callback_do_join: Successfully joined %s\n",
+ new_workgroup_type);
+
+ callback_do_freeauth(NULL, state);
+ dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ "Welcome to the %s %s.",
+ state->name_buffer_new,
+ new_workgroup_type);
+
+ gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+ gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+
+ callback_do_reboot(NULL, state->window_parent, state);
+}
+
+static void callback_enter_hostname_and_unlock(GtkWidget *widget,
+ gpointer data)
+{
+ const gchar *entry_text = NULL;
+ char *str = NULL;
+ struct join_state *state = (struct join_state *)data;
+
+ entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
+ debug("callback_enter_hostname_and_unlock: %s\n", entry_text);
+ if (!entry_text || entry_text[0] == 0) {
+ state->hostname_changed = FALSE;
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
+ return;
+ }
+ if (strcasecmp(state->my_hostname, entry_text) == 0) {
+ state->hostname_changed = FALSE;
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
+ /* return; */
+ } else {
+ state->hostname_changed = TRUE;
+ }
+
+ if (state->name_type_initial == NetSetupDomainName) {
+ if (asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain) == -1) {
+ return;
+ }
+ } else {
+ if (asprintf(&str, "%s.", entry_text) == -1) {
+ return;
+ }
+ }
+ gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
+ free(str);
+
+ if (state->hostname_changed && str && str[0] != 0 && str[0] != '.') {
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
+ }
+}
+
+static void callback_enter_computer_description_and_unlock(GtkWidget *widget,
+ gpointer data)
+{
+ const gchar *entry_text = NULL;
+ struct join_state *state = (struct join_state *)data;
+ int string_unchanged = FALSE;
+
+ entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
+ debug("callback_enter_computer_description_and_unlock: %s\n",
+ entry_text);
+#if 0
+ if (!entry_text || entry_text[0] == 0) {
+ string_unchanged = 1;
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
+ FALSE);
+ return;
+ }
+#endif
+ if (entry_text && state->comment && strcasecmp(state->comment, entry_text) == 0) {
+ string_unchanged = TRUE;
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
+ FALSE);
+ return;
+ }
+
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), TRUE);
+ SAFE_FREE(state->comment_new);
+ state->comment_new = strdup(entry_text);
+
+}
+
+
+static void callback_enter_workgroup_and_unlock(GtkWidget *widget,
+ gpointer data)
+{
+ const gchar *entry_text = NULL;
+ struct join_state *state = (struct join_state *)data;
+
+ entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
+ debug("callback_enter_workgroup_and_unlock: %s\n", entry_text);
+ if (!entry_text || entry_text[0] == 0) {
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
+ return;
+ }
+ if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
+ return;
+ }
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
+ SAFE_FREE(state->name_buffer_new);
+ state->name_buffer_new = strdup(entry_text);
+ state->name_type_new = NetSetupWorkgroupName;
+}
+
+static void callback_enter_domain_and_unlock(GtkWidget *widget,
+ gpointer data)
+{
+ const gchar *entry_text = NULL;
+ struct join_state *state = (struct join_state *)data;
+
+ entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
+ debug("callback_enter_domain_and_unlock: %s\n", entry_text);
+ if (!entry_text || entry_text[0] == 0) {
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
+ return;
+ }
+ if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
+ return;
+ }
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), TRUE);
+ SAFE_FREE(state->name_buffer_new);
+ state->name_buffer_new = strdup(entry_text);
+ state->name_type_new = NetSetupDomainName;
+}
+
+static void callback_apply_continue(GtkWidget *widget,
+ gpointer data)
+{
+ struct join_state *state = (struct join_state *)data;
+
+ gtk_widget_grab_focus(GTK_WIDGET(state->button_apply));
+ g_signal_emit_by_name(state->button_apply, "clicked");
+}
+
+static void callback_do_join_workgroup(GtkWidget *widget,
+ gpointer data)
+{
+ struct join_state *state = (struct join_state *)data;
+ debug("callback_do_join_workgroup choosen\n");
+ gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
+ gtk_widget_grab_focus(GTK_WIDGET(state->entry_workgroup));
+ gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
+ callback_enter_workgroup_and_unlock(state->entry_workgroup, state); /* TEST */
+}
+
+static void callback_do_join_domain(GtkWidget *widget,
+ gpointer data)
+{
+ struct join_state *state = (struct join_state *)data;
+ debug("callback_do_join_domain choosen\n");
+ gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), TRUE);
+ gtk_widget_grab_focus(GTK_WIDGET(state->entry_domain));
+ gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), FALSE);
+ callback_enter_domain_and_unlock(state->entry_domain, state); /* TEST */
+}
+
+static void callback_do_getous(GtkWidget *widget,
+ gpointer data)
+{
+ NET_API_STATUS status;
+ uint32_t num_ous = 0;
+ const char **ous = NULL;
+ int i;
+ const char *domain = NULL;
+ struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
+ const char *err_str = NULL;
+ GtkWidget *dialog;
+
+ struct join_state *state = (struct join_state *)data;
+
+ debug("callback_do_getous called\n");
+
+ domain = state->name_buffer_new ? state->name_buffer_new : state->name_buffer_initial;
+
+ status = DsGetDcName(NULL,
+ domain,
+ NULL,
+ NULL,
+ 0,
+ &dc_info);
+ if (status != 0) {
+ err_str = libnetapi_get_error_string(state->ctx, status);
+ g_print("callback_do_getous: failed find dc (%s)\n", err_str);
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "Failed to find a domain controller for domain: \"%s\": %s",
+ domain,
+ err_str);
+
+ gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+ gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
+ g_signal_connect_swapped(dialog, "response",
+ G_CALLBACK(gtk_widget_destroy),
+ dialog);
+
+ gtk_widget_show(dialog);
+
+ return;
+ }
+
+ if (!state->account || !state->password) {
+ debug("callback_do_getous: no creds yet\n");
+ callback_creds_prompt(NULL, state,
+ "Enter the name and password of an account with permission to join the domain.",
+ callback_do_storeauth_and_scan);
+ }
+
+ if (!state->account || !state->password) {
+ debug("callback_do_getous: still no creds ???\n");
+ return;
+ }
+
+ status = NetGetJoinableOUs(state->target_hostname,
+ domain,
+ state->account,
+ state->password,
+ &num_ous, &ous);
+ if (status != NET_API_STATUS_SUCCESS) {
+ callback_do_freeauth(NULL, state);
+ debug("failed to call NetGetJoinableOUs: %s\n",
+ libnetapi_get_error_string(state->ctx, status));
+ dialog = gtk_message_dialog_new(NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ "Failed to query joinable OUs: %s",
+ libnetapi_get_error_string(state->ctx, status));
+ gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+ gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ return;
+ }
+
+ for (i=0; i<state->stored_num_ous; i++) {
+ gtk_combo_box_remove_text(GTK_COMBO_BOX(state->entry_ou_list), 0);
+ }
+ for (i=0; i<num_ous && ous[i] != NULL; i++) {
+ gtk_combo_box_append_text(GTK_COMBO_BOX(state->entry_ou_list),
+ ous[i]);
+ }
+ NetApiBufferFree(ous);
+ state->stored_num_ous = num_ous;
+ gtk_combo_box_set_active(GTK_COMBO_BOX(state->entry_ou_list), num_ous-1);
+}
+
+static void callback_do_change(GtkWidget *widget,
+ gpointer data)
+{
+ GtkWidget *window;
+ GtkWidget *box1;
+ GtkWidget *bbox;
+ GtkWidget *button_workgroup;
+ GtkWidget *button_domain;
+ GtkWidget *button;
+ GtkWidget *label;
+ GtkWidget *frame_horz;
+ GtkWidget *vbox;
+ GtkWidget *entry;
+ GSList *group;
+
+ struct join_state *state = (struct join_state *)data;
+
+ debug("callback_do_change called\n");
+
+#if 0
+ /* FIXME: add proper warnings for Samba as a DC */
+ if (state->server_role == 3) {
+ GtkWidget *dialog;
+ callback_do_freeauth(NULL, state);
+ dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "Domain controller cannot be moved from one domain to another, they must first be demoted. Renaming this domain controller may cause it to become temporarily unavailable to users and computers. For information on renaming domain controllers, including alternate renaming methods, see Help and Support. To continue renaming this domain controller, click OK.");
+ gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+ g_signal_connect_swapped(dialog, "response",
+ G_CALLBACK(gtk_widget_destroy),
+ dialog);
+
+ gtk_widget_show(dialog);
+ return;
+ }
+#endif
+
+ state->button_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
+ state->button_get_ous = gtk_button_new_with_label("Scan for joinable OUs");
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_modal(GTK_WINDOW(window), TRUE);
+
+ gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
+ gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
+ gtk_widget_set_size_request(GTK_WIDGET(window), 480, 650);
+ gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
+ gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(state->window_main));
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
+
+ g_signal_connect(G_OBJECT(window), "delete_event",
+ G_CALLBACK(callback_do_close_widget), NULL);
+
+ gtk_container_set_border_width(GTK_CONTAINER(window), 10);
+
+ box1 = gtk_vbox_new(FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(window), box1);
+
+ label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
+ gtk_widget_show(label);
+
+ /* COMPUTER NAME */
+ label = gtk_label_new("Computer name:");
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
+ gtk_widget_show(label);
+
+ state->label_full_computer_name = gtk_label_new(NULL);
+ {
+ entry = gtk_entry_new();
+ gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_NETBIOS_NAME_LEN);
+ g_signal_connect(G_OBJECT(entry), "changed",
+ G_CALLBACK(callback_enter_hostname_and_unlock),
+ (gpointer)state);
+ gtk_entry_set_text(GTK_ENTRY(entry), state->my_hostname);
+ gtk_editable_select_region(GTK_EDITABLE(entry),
+ 0, GTK_ENTRY(entry)->text_length);
+
+ gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
+ gtk_box_pack_start(GTK_BOX(box1), entry, TRUE, TRUE, 0);
+ gtk_widget_show(entry);
+ }
+
+ /* FULL COMPUTER NAME */
+ label = gtk_label_new("Full computer name:");
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
+ gtk_widget_show(label);
+
+ {
+ const gchar *entry_text;
+ char *str = NULL;
+ entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
+ if (state->name_type_initial == NetSetupDomainName) {
+ if (asprintf(&str, "%s.%s", entry_text,
+ state->my_dnsdomain) == -1) {
+ return;
+ }
+ } else {
+ if (asprintf(&str, "%s.", entry_text) == -1) {
+ return;
+ }
+ }
+ gtk_label_set_text(GTK_LABEL(state->label_full_computer_name),
+ str);
+ free(str);
+ gtk_misc_set_alignment(GTK_MISC(state->label_full_computer_name), 0, 0);
+ gtk_box_pack_start(GTK_BOX(box1),
+ state->label_full_computer_name, TRUE, TRUE, 0);
+ gtk_widget_show(state->label_full_computer_name);
+ }
+
+ /* BOX */
+ frame_horz = gtk_frame_new ("Member Of");
+ gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
+ gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
+
+ /* TWO ENTRIES */
+ state->entry_workgroup = gtk_entry_new();
+ state->entry_domain = gtk_entry_new();
+
+ /* DOMAIN */
+ button_domain = gtk_radio_button_new_with_label(NULL, "Domain");
+ if (state->name_type_initial == NetSetupDomainName) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_domain), TRUE);
+ }
+ gtk_box_pack_start(GTK_BOX(vbox), button_domain, TRUE, TRUE, 0);
+ g_signal_connect(G_OBJECT(button_domain), "clicked",
+ G_CALLBACK(callback_do_join_domain),
+ (gpointer)state);
+
+ {
+ gtk_entry_set_max_length(GTK_ENTRY(state->entry_domain), 50);
+ g_signal_connect(G_OBJECT(state->entry_domain), "changed",
+ G_CALLBACK(callback_enter_domain_and_unlock),
+ (gpointer)state);
+ g_signal_connect(G_OBJECT(state->entry_domain), "activate",
+ G_CALLBACK(callback_continue),
+ (gpointer)state);
+ if (state->name_type_initial == NetSetupDomainName) {
+ gtk_entry_set_text(GTK_ENTRY(state->entry_domain),
+ state->name_buffer_initial);
+ gtk_widget_set_sensitive(state->entry_workgroup, FALSE);
+ gtk_widget_set_sensitive(state->entry_domain, TRUE);
+ }
+ gtk_editable_set_editable(GTK_EDITABLE(state->entry_domain), TRUE);
+ gtk_box_pack_start(GTK_BOX(vbox), state->entry_domain, TRUE, TRUE, 0);
+ gtk_widget_show(state->entry_domain);
+ }
+ gtk_widget_show(button_domain);
+
+ /* WORKGROUP */
+ group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_domain));
+ button_workgroup = gtk_radio_button_new_with_label(group, "Workgroup");
+ if (state->name_type_initial == NetSetupWorkgroupName) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_workgroup), TRUE);
+ }
+ gtk_box_pack_start(GTK_BOX(vbox), button_workgroup, TRUE, TRUE, 0);
+ g_signal_connect(G_OBJECT(button_workgroup), "clicked",
+ G_CALLBACK(callback_do_join_workgroup),
+ (gpointer)state);
+ {
+ gtk_entry_set_max_length(GTK_ENTRY(state->entry_workgroup),
+ MAX_NETBIOS_NAME_LEN);
+ g_signal_connect(G_OBJECT(state->entry_workgroup), "changed",
+ G_CALLBACK(callback_enter_workgroup_and_unlock),
+ (gpointer)state);
+ g_signal_connect(G_OBJECT(state->entry_workgroup), "activate",
+ G_CALLBACK(callback_continue),
+ (gpointer)state);
+
+ if (state->name_type_initial == NetSetupWorkgroupName) {
+ gtk_entry_set_text(GTK_ENTRY(state->entry_workgroup),
+ state->name_buffer_initial);
+ gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
+ }
+ gtk_box_pack_start(GTK_BOX(vbox), state->entry_workgroup, TRUE, TRUE, 0);
+ gtk_widget_show(state->entry_workgroup);
+ }
+ gtk_widget_show(button_workgroup);
+
+ /* Advanced Options */
+ frame_horz = gtk_frame_new("Advanced Options");
+ gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
+ gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
+
+ /* OUs */
+ gtk_container_add(GTK_CONTAINER(vbox), state->button_get_ous);
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
+ g_signal_connect(G_OBJECT(state->button_get_ous), "clicked",
+ G_CALLBACK(callback_do_getous),
+ (gpointer)state);
+
+ state->entry_ou_list = gtk_combo_box_entry_new_text();
+ gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
+ if (state->name_type_initial == NetSetupWorkgroupName) {
+ gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
+ gtk_widget_set_sensitive(state->button_get_ous, FALSE);
+ }
+ gtk_box_pack_start(GTK_BOX(vbox), state->entry_ou_list, TRUE, TRUE, 0);
+ gtk_widget_show(state->entry_ou_list);
+
+ {
+ state->label_winbind = gtk_check_button_new_with_label("Modify winbind configuration");
+ gtk_box_pack_start(GTK_BOX(vbox), state->label_winbind, TRUE, TRUE, 0);
+ gtk_widget_set_sensitive(state->label_winbind, FALSE);
+ }
+
+
+ /* BUTTONS */
+ bbox = gtk_hbutton_box_new();
+ gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
+ gtk_container_add(GTK_CONTAINER(box1), bbox);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing(GTK_BOX(bbox), 10);
+
+ state->window_do_change = window;
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
+ gtk_container_add(GTK_CONTAINER(bbox), state->button_ok);
+ g_signal_connect(G_OBJECT(state->button_ok), "clicked",
+ G_CALLBACK(callback_do_join),
+ (gpointer)state);
+
+ button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
+ gtk_container_add(GTK_CONTAINER(bbox), button);
+ g_signal_connect(G_OBJECT(button), "clicked",
+ G_CALLBACK(callback_do_freeauth_and_close),
+ (gpointer)state);
+
+ gtk_widget_show_all(window);
+}
+
+static void callback_do_about(GtkWidget *widget,
+ gpointer data)
+{
+ GdkPixbuf *logo;
+ GError *error = NULL;
+ GtkWidget *about;
+
+ struct join_state *state = (struct join_state *)data;
+
+ debug("callback_do_about called\n");
+
+ logo = gdk_pixbuf_new_from_file(SAMBA_IMAGE_PATH,
+ &error);
+ if (logo == NULL) {
+ g_print("failed to load logo from %s: %s\n",
+ SAMBA_IMAGE_PATH, error->message);
+ }
+
+ about = gtk_about_dialog_new();
+ gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), "Samba");
+ gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), "3.2.0pre3");
+ gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about),
+ "Copyright Andrew Tridgell and the Samba Team 1992-2008\n"
+ "Copyright Günther Deschner 2007-2008");
+ gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about), "GPLv3");
+ gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
+ gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
+ if (logo) {
+ gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), logo);
+ }
+ gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), "Samba gtk domain join utility");
+ gtk_window_set_modal(GTK_WINDOW(about), TRUE);
+ gtk_window_set_transient_for(GTK_WINDOW(about), GTK_WINDOW(state->window_main));
+ g_signal_connect_swapped(about, "response",
+ G_CALLBACK(gtk_widget_destroy),
+ about);
+
+ gtk_widget_show(about);
+}
+
+static int draw_main_window(struct join_state *state)
+{
+ GtkWidget *window;
+ GtkWidget *button;
+ GtkWidget *label;
+ GtkWidget *main_vbox;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *bbox;
+ GtkWidget *image;
+ GtkWidget *table;
+ GtkWidget *entry;
+ GdkPixbuf *icon;
+ GError *error = NULL;
+
+ icon = gdk_pixbuf_new_from_file(SAMBA_ICON_PATH,
+ &error);
+ if (icon == NULL) {
+ g_print("failed to load icon from %s : %s\n",
+ SAMBA_ICON_PATH, error->message);
+ }
+
+#if 1
+ image = gtk_image_new_from_file(SAMBA_IMAGE_PATH_SMALL);
+#else
+ image = gtk_image_new_from_file("/usr/share/pixmaps/redhat-system_settings.png");
+#endif
+ if (image == NULL) {
+ g_print("failed to load logo from %s : %s\n",
+ SAMBA_IMAGE_PATH_SMALL, error->message);
+ }
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ state->window_main = window;
+
+ gtk_window_set_title(GTK_WINDOW(window), "Samba - Join Domain dialogue");
+ gtk_widget_set_size_request(GTK_WIDGET(window), 600, 600);
+ gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
+ gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
+
+ g_signal_connect(G_OBJECT(window), "delete_event",
+ G_CALLBACK(callback_delete_event), NULL);
+
+ gtk_container_set_border_width(GTK_CONTAINER(window), 10);
+
+ main_vbox = gtk_vbox_new(FALSE, 10);
+ gtk_container_add(GTK_CONTAINER(window), main_vbox);
+
+#if 0
+ gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10);
+ gtk_widget_show(image);
+#endif
+ /* Hbox */
+ hbox = gtk_hbox_new(FALSE, 10);
+ gtk_container_add(GTK_CONTAINER(main_vbox), hbox);
+
+ {
+/* gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10); */
+/* gtk_misc_set_alignment(GTK_MISC(image), 0, 0); */
+ gtk_widget_set_size_request(GTK_WIDGET(image), 150, 40);
+ gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 10);
+ gtk_widget_show(image);
+
+ /* Label */
+ label = gtk_label_new("Samba uses the following information to identify your computer on the network.");
+/* gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
+ gtk_widget_set_size_request(GTK_WIDGET(label), 400, 40);
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+ gtk_widget_show(label);
+ }
+
+ gtk_widget_show(hbox);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
+ gtk_container_add(GTK_CONTAINER(main_vbox), vbox);
+
+ /* Table */
+ table = gtk_table_new(6, 3, TRUE);
+ gtk_table_set_row_spacings(GTK_TABLE(table), 5);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 5);
+ gtk_container_add(GTK_CONTAINER(vbox), table);
+
+ {
+ /* Label */
+ label = gtk_label_new("Computer description:");
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
+ gtk_widget_show(label);
+
+ state->button_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
+
+ /* Entry */
+ entry = gtk_entry_new();
+ gtk_entry_set_max_length(GTK_ENTRY(entry), 256);
+ g_signal_connect(G_OBJECT(entry), "changed",
+ G_CALLBACK(callback_enter_computer_description_and_unlock),
+ state);
+ g_signal_connect(G_OBJECT(entry), "activate",
+ G_CALLBACK(callback_apply_continue),
+ (gpointer)state);
+
+ gtk_entry_set_text(GTK_ENTRY(entry), (char *)state->comment);
+ gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
+ gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 3, 0, 1);
+ gtk_widget_show(entry);
+ }
+
+ /* Label */
+ label = gtk_label_new("For example: \"Samba \%v\".");
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 1, 2);
+ gtk_widget_show(label);
+
+ /* Label */
+ label = gtk_label_new("Full computer name:");
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
+ gtk_widget_show(label);
+
+ {
+ /* Label */
+ char *str = NULL;
+ if (state->name_type_initial == NetSetupDomainName) {
+ if (asprintf(&str, "%s.%s", state->my_hostname,
+ state->my_dnsdomain) == -1) {
+ return -1;
+ }
+ } else {
+ if (asprintf(&str, "%s.", state->my_hostname) == -1) {
+ return -1;
+ }
+ }
+
+ label = gtk_label_new(str);
+ SAFE_FREE(str);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 2, 3);
+ gtk_widget_show(label);
+ }
+
+ /* Label */
+ if (state->name_type_initial == NetSetupDomainName) {
+ label = gtk_label_new("Domain:");
+ } else {
+ label = gtk_label_new("Workgroup:");
+ }
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
+ gtk_widget_show(label);
+ state->label_current_name_type = label;
+
+ /* Label */
+ label = gtk_label_new(state->name_buffer_initial);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 3, 4);
+ gtk_widget_show(label);
+ state->label_current_name_buffer = label;
+
+ {
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(vbox), hbox);
+ label = gtk_label_new("To rename this computer or join a domain, click Change.");
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+
+ }
+
+ /* bbox */
+ bbox = gtk_hbutton_box_new();
+ gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
+ gtk_container_add(GTK_CONTAINER(hbox), bbox);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing(GTK_BOX(bbox), 10);
+
+ button = gtk_button_new_with_mnemonic("Ch_ange");
+ g_signal_connect(G_OBJECT(button), "clicked",
+ G_CALLBACK(callback_do_change),
+ (gpointer)state);
+ gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
+ gtk_widget_show(button);
+
+ /* Label (hidden) */
+ state->label_reboot = gtk_label_new(NULL);
+ gtk_label_set_line_wrap(GTK_LABEL(state->label_reboot), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(state->label_reboot), 0, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), state->label_reboot, TRUE, TRUE, 0);
+ gtk_widget_show(state->label_reboot);
+
+#if 0
+ gtk_box_pack_start(GTK_BOX(vbox),
+ create_bbox(window, TRUE, NULL, 10, 85, 20, GTK_BUTTONBOX_END),
+ TRUE, TRUE, 5);
+#endif
+ {
+
+ GtkWidget *frame;
+ GtkWidget *bbox2;
+ GtkWidget *button2;
+
+ frame = gtk_frame_new(NULL);
+ bbox2 = gtk_hbutton_box_new();
+
+ gtk_container_set_border_width(GTK_CONTAINER(bbox2), 5);
+ gtk_container_add(GTK_CONTAINER(frame), bbox2);
+
+ /* Set the appearance of the Button Box */
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox2), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing(GTK_BOX(bbox2), 10);
+ /*gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox2), child_w, child_h);*/
+
+ button2 = gtk_button_new_from_stock(GTK_STOCK_OK);
+ gtk_container_add(GTK_CONTAINER(bbox2), button2);
+ g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(callback_do_exit), state);
+
+ button2 = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
+ gtk_container_add(GTK_CONTAINER(bbox2), button2);
+ g_signal_connect(G_OBJECT(button2), "clicked",
+ G_CALLBACK(callback_delete_event),
+ window);
+
+ gtk_container_add(GTK_CONTAINER(bbox2), state->button_apply);
+ g_signal_connect(G_OBJECT(state->button_apply), "clicked",
+ G_CALLBACK(callback_apply_description_change),
+ state);
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
+
+ button2 = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
+ gtk_container_add(GTK_CONTAINER(bbox2), button2);
+ g_signal_connect(G_OBJECT(button2), "clicked",
+ G_CALLBACK(callback_do_about),
+ state);
+#if 0
+ button2 = gtk_button_new_from_stock(GTK_STOCK_HELP);
+ gtk_container_add(GTK_CONTAINER(bbox2), button2);
+ g_signal_connect(G_OBJECT(button2), "clicked",
+ G_CALLBACK(callback_do_about),
+ window);
+#endif
+ gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
+ }
+
+ gtk_widget_show_all(window);
+
+ return 0;
+}
+
+static int init_join_state(struct join_state **state)
+{
+ struct join_state *s;
+
+ s = (struct join_state *)malloc(sizeof(struct join_state));
+ if (!s) {
+ return -1;
+ }
+
+ memset(s, '\0', sizeof(struct join_state));
+
+ *state = s;
+
+ return 0;
+}
+
+static NET_API_STATUS get_server_comment(struct join_state *state)
+{
+ struct SERVER_INFO_101 *info101 = NULL;
+ struct SERVER_INFO_1005 *info1005 = NULL;
+ NET_API_STATUS status;
+
+ status = NetServerGetInfo(state->target_hostname,
+ 101,
+ (uint8_t **)&info101);
+ if (status == 0) {
+ state->comment = strdup(info101->sv101_comment);
+ if (!state->comment) {
+ return -1;
+ }
+ NetApiBufferFree(info101);
+ return NET_API_STATUS_SUCCESS;
+ }
+
+ switch (status) {
+ case 124: /* WERR_UNKNOWN_LEVEL */
+ case 50: /* WERR_NOT_SUPPORTED */
+ break;
+ default:
+ goto failed;
+ }
+
+ status = NetServerGetInfo(state->target_hostname,
+ 1005,
+ (uint8_t **)&info1005);
+ if (status == 0) {
+ state->comment = strdup(info1005->sv1005_comment);
+ if (!state->comment) {
+ return -1;
+ }
+ NetApiBufferFree(info1005);
+ return NET_API_STATUS_SUCCESS;
+ }
+
+ failed:
+ printf("NetServerGetInfo failed with: %s\n",
+ libnetapi_get_error_string(state->ctx, status));
+
+ return status;
+}
+
+static int initialize_join_state(struct join_state *state,
+ const char *debug_level,
+ const char *target_hostname,
+ const char *target_username)
+{
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status = 0;
+
+ status = libnetapi_init(&ctx);
+ if (status) {
+ return status;
+ }
+
+ if (debug_level) {
+ libnetapi_set_debuglevel(ctx, debug_level);
+ }
+
+ if (target_hostname) {
+ state->target_hostname = strdup(target_hostname);
+ if (!state->target_hostname) {
+ return -1;
+ }
+ }
+
+ if (target_username) {
+ char *puser = strdup(target_username);
+ char *p = NULL;
+
+ if ((p = strchr(puser,'%'))) {
+ size_t len;
+ *p = 0;
+ libnetapi_set_username(ctx, puser);
+ libnetapi_set_password(ctx, p+1);
+ len = strlen(p+1);
+ memset(strchr(target_username,'%')+1,'X',len);
+ } else {
+ libnetapi_set_username(ctx, puser);
+ }
+ free(puser);
+ }
+
+ {
+ char my_hostname[HOST_NAME_MAX];
+ const char *p = NULL;
+ struct hostent *hp = NULL;
+
+ if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
+ return -1;
+ }
+
+ p = strchr(my_hostname, '.');
+ if (p) {
+ my_hostname[strlen(my_hostname)-strlen(p)] = '\0';
+ }
+ state->my_hostname = strdup(my_hostname);
+ if (!state->my_hostname) {
+ return -1;
+ }
+ debug("state->my_hostname: %s\n", state->my_hostname);
+
+ hp = gethostbyname(my_hostname);
+ if (!hp || !hp->h_name || !*hp->h_name) {
+ return -1;
+ }
+
+ state->my_fqdn = strdup(hp->h_name);
+ if (!state->my_fqdn) {
+ return -1;
+ }
+ debug("state->my_fqdn: %s\n", state->my_fqdn);
+
+ p = strchr(state->my_fqdn, '.');
+ if (p) {
+ p++;
+ state->my_dnsdomain = strdup(p);
+ } else {
+ state->my_dnsdomain = strdup("");
+ }
+ if (!state->my_dnsdomain) {
+ return -1;
+ }
+ debug("state->my_dnsdomain: %s\n", state->my_dnsdomain);
+ }
+
+ {
+ const char *buffer = NULL;
+ uint16_t type = 0;
+ status = NetGetJoinInformation(state->target_hostname,
+ &buffer,
+ &type);
+ if (status != 0) {
+ printf("NetGetJoinInformation failed with: %s\n",
+ libnetapi_get_error_string(state->ctx, status));
+ return status;
+ }
+ debug("NetGetJoinInformation gave: %s and %d\n", buffer, type);
+ state->name_buffer_initial = strdup(buffer);
+ if (!state->name_buffer_initial) {
+ return -1;
+ }
+ state->name_type_initial = type;
+ NetApiBufferFree((void *)buffer);
+ }
+
+ status = get_server_comment(state);
+ if (status != 0) {
+ return -1;
+ }
+
+ state->ctx = ctx;
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ GOptionContext *context = NULL;
+ static const char *debug_level = NULL;
+ static const char *target_hostname = NULL;
+ static const char *target_username = NULL;
+ struct join_state *state = NULL;
+ GError *error = NULL;
+ int ret = 0;
+
+ static GOptionEntry entries[] = {
+ { "debug", 'd', 0, G_OPTION_ARG_STRING, &debug_level, "Debug level (for samba)", "N" },
+ { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", 0 },
+ { "target", 'S', 0, G_OPTION_ARG_STRING, &target_hostname, "Target hostname", 0 },
+ { "username", 'U', 0, G_OPTION_ARG_STRING, &target_username, "Target hostname", 0 },
+ { NULL }
+ };
+
+ context = g_option_context_new("- Samba domain join utility");
+ g_option_context_add_main_entries(context, entries, NULL);
+/* g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); */
+ g_option_context_add_group(context, gtk_get_option_group(TRUE));
+ g_option_context_parse(context, &argc, &argv, &error);
+
+ gtk_init(&argc, &argv);
+ g_set_application_name("Samba");
+
+ ret = init_join_state(&state);
+ if (ret) {
+ return ret;
+ }
+
+ ret = initialize_join_state(state, debug_level,
+ target_hostname,
+ target_username);
+ if (ret) {
+ return ret;
+ }
+
+ draw_main_window(state);
+
+ gtk_main();
+
+ do_cleanup(state);
+
+ return 0;
+}
diff --git a/source3/lib/netapi/examples/netdomjoin-gui/samba.ico b/source3/lib/netapi/examples/netdomjoin-gui/samba.ico
new file mode 100755
index 0000000000..b70c9590de
--- /dev/null
+++ b/source3/lib/netapi/examples/netdomjoin-gui/samba.ico
Binary files differ
diff --git a/source3/lib/netapi/examples/server/remote_tod.c b/source3/lib/netapi/examples/server/remote_tod.c
new file mode 100644
index 0000000000..7636f6ac95
--- /dev/null
+++ b/source3/lib/netapi/examples/server/remote_tod.c
@@ -0,0 +1,83 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetRemoteTOD query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ struct TIME_OF_DAY_INFO *tod = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("tod", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+
+ /* NetRemoteTOD */
+
+ status = NetRemoteTOD(hostname,
+ (uint8_t **)&tod);
+ if (status != 0) {
+ printf("NetRemoteTOD failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ } else {
+ printf("%d-%d-%d %d:%d:%d\n",
+ tod->tod_day, tod->tod_month, tod->tod_year,
+ tod->tod_hours, tod->tod_mins, tod->tod_secs);
+ NetApiBufferFree(tod);
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/server/server_getinfo.c b/source3/lib/netapi/examples/server/server_getinfo.c
new file mode 100644
index 0000000000..afd2edd05d
--- /dev/null
+++ b/source3/lib/netapi/examples/server/server_getinfo.c
@@ -0,0 +1,128 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetServerGetInfo query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ uint8_t *buffer = NULL;
+ uint32_t level = 100;
+
+ struct SERVER_INFO_100 *i100;
+ struct SERVER_INFO_101 *i101;
+ struct SERVER_INFO_102 *i102;
+ struct SERVER_INFO_1005 *i1005;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("server_getinfo", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ /* NetServerGetInfo */
+
+ status = NetServerGetInfo(hostname,
+ level,
+ &buffer);
+ if (status != 0) {
+ printf("NetServerGetInfo failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ switch (level) {
+ case 100:
+ i100 = (struct SERVER_INFO_100 *)buffer;
+ printf("platform id: %d\n", i100->sv100_platform_id);
+ printf("name: %s\n", i100->sv100_name);
+ break;
+ case 101:
+ i101 = (struct SERVER_INFO_101 *)buffer;
+ printf("platform id: %d\n", i101->sv101_platform_id);
+ printf("name: %s\n", i101->sv101_name);
+ printf("version major: %d\n", i101->sv101_version_major);
+ printf("version minor: %d\n", i101->sv101_version_minor);
+ printf("type: 0x%08x\n", i101->sv101_type);
+ printf("comment: %s\n", i101->sv101_comment);
+ break;
+ case 102:
+ i102 = (struct SERVER_INFO_102 *)buffer;
+ printf("platform id: %d\n", i102->sv102_platform_id);
+ printf("name: %s\n", i102->sv102_name);
+ printf("version major: %d\n", i102->sv102_version_major);
+ printf("version minor: %d\n", i102->sv102_version_minor);
+ printf("type: 0x%08x\n", i102->sv102_type);
+ printf("comment: %s\n", i102->sv102_comment);
+ printf("users: %d\n", i102->sv102_users);
+ printf("disc: %d\n", i102->sv102_disc);
+ printf("hidden: %d\n", i102->sv102_hidden);
+ printf("announce: %d\n", i102->sv102_announce);
+ printf("anndelta: %d\n", i102->sv102_anndelta);
+ printf("licenses: %d\n", i102->sv102_licenses);
+ printf("userpath: %s\n", i102->sv102_userpath);
+ break;
+ case 1005:
+ i1005 = (struct SERVER_INFO_1005 *)buffer;
+ printf("comment: %s\n", i1005->sv1005_comment);
+ break;
+ default:
+ break;
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/share/share_add.c b/source3/lib/netapi/examples/share/share_add.c
new file mode 100644
index 0000000000..3d7948840d
--- /dev/null
+++ b/source3/lib/netapi/examples/share/share_add.c
@@ -0,0 +1,110 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetShareAdd query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *sharename = NULL;
+ const char *path = NULL;
+ uint32_t level = 0;
+ uint32_t parm_err = 0;
+
+ struct SHARE_INFO_2 i2;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("share_add", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname sharename path");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ sharename = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ path = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ /* NetShareAdd */
+
+ i2.shi2_netname = sharename;
+ i2.shi2_type = 0;
+ i2.shi2_remark = "Test share created via NetApi";
+ i2.shi2_permissions = 0;
+ i2.shi2_max_uses = (uint32_t)-1;
+ i2.shi2_current_uses = 0;
+ i2.shi2_path = path;
+ i2.shi2_passwd = NULL;
+
+ status = NetShareAdd(hostname,
+ 2,
+ (uint8_t *)&i2,
+ &parm_err);
+ if (status != 0) {
+ printf("NetShareAdd failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/share/share_del.c b/source3/lib/netapi/examples/share/share_del.c
new file mode 100644
index 0000000000..20e3ce5a8b
--- /dev/null
+++ b/source3/lib/netapi/examples/share/share_del.c
@@ -0,0 +1,85 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetShareDel query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *sharename = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("share_del", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname sharename");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ sharename = poptGetArg(pc);
+
+ /* NetShareDel */
+
+ status = NetShareDel(hostname,
+ sharename,
+ 0);
+ if (status != 0) {
+ printf("NetShareDel failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/share/share_enum.c b/source3/lib/netapi/examples/share/share_enum.c
new file mode 100644
index 0000000000..b1f4043795
--- /dev/null
+++ b/source3/lib/netapi/examples/share/share_enum.c
@@ -0,0 +1,142 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetShareEnum query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ uint32_t level = 0;
+ uint8_t *buffer = NULL;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ int i;
+
+ struct SHARE_INFO_0 *i0 = NULL;
+ struct SHARE_INFO_1 *i1 = NULL;
+ struct SHARE_INFO_2 *i2 = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("share_enum", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ /* NetShareEnum */
+
+ do {
+ status = NetShareEnum(hostname,
+ level,
+ &buffer,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries,
+ &resume_handle);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+ printf("total entries: %d\n", total_entries);
+ switch (level) {
+ case 0:
+ i0 = (struct SHARE_INFO_0 *)buffer;
+ break;
+ case 1:
+ i1 = (struct SHARE_INFO_1 *)buffer;
+ break;
+ case 2:
+ i2 = (struct SHARE_INFO_2 *)buffer;
+ break;
+ default:
+ break;
+ }
+ for (i=0; i<entries_read; i++) {
+ switch (level) {
+ case 0:
+ printf("#%d netname: %s\n", i, i0->shi0_netname);
+ i0++;
+ break;
+ case 1:
+ printf("#%d netname: %s\n", i, i1->shi1_netname);
+ printf("#%d type: %d\n", i, i1->shi1_type);
+ printf("#%d remark: %s\n", i, i1->shi1_remark);
+ i1++;
+ break;
+ case 2:
+ printf("#%d netname: %s\n", i, i2->shi2_netname);
+ printf("#%d type: %d\n", i, i2->shi2_type);
+ printf("#%d remark: %s\n", i, i2->shi2_remark);
+ printf("#%d permissions: %d\n", i, i2->shi2_permissions);
+ printf("#%d max users: %d\n", i, i2->shi2_max_uses);
+ printf("#%d current users: %d\n", i, i2->shi2_current_uses);
+ printf("#%d path: %s\n", i, i2->shi2_path);
+ printf("#%d password: %s\n", i, i2->shi2_passwd);
+ i2++;
+ break;
+ default:
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status != 0) {
+ printf("NetShareEnum failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/share/share_getinfo.c b/source3/lib/netapi/examples/share/share_getinfo.c
new file mode 100644
index 0000000000..479da5cc4a
--- /dev/null
+++ b/source3/lib/netapi/examples/share/share_getinfo.c
@@ -0,0 +1,152 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetShareGetInfo query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *sharename = NULL;
+ uint32_t level = 2;
+ uint8_t *buffer = NULL;
+
+ struct SHARE_INFO_0 *i0 = NULL;
+ struct SHARE_INFO_1 *i1 = NULL;
+ struct SHARE_INFO_2 *i2 = NULL;
+ struct SHARE_INFO_501 *i501 = NULL;
+ struct SHARE_INFO_1005 *i1005 = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("share_getinfo", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname sharename level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ sharename = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ /* NetShareGetInfo */
+
+ status = NetShareGetInfo(hostname,
+ sharename,
+ level,
+ &buffer);
+ if (status != 0) {
+ printf("NetShareGetInfo failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ switch (level) {
+ case 0:
+ i0 = (struct SHARE_INFO_0 *)buffer;
+ break;
+ case 1:
+ i1 = (struct SHARE_INFO_1 *)buffer;
+ break;
+ case 2:
+ i2 = (struct SHARE_INFO_2 *)buffer;
+ break;
+ case 501:
+ i501 = (struct SHARE_INFO_501 *)buffer;
+ break;
+ case 1005:
+ i1005 = (struct SHARE_INFO_1005 *)buffer;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (level) {
+ case 0:
+ printf("netname: %s\n", i0->shi0_netname);
+ break;
+ case 1:
+ printf("netname: %s\n", i1->shi1_netname);
+ printf("type: %d\n", i1->shi1_type);
+ printf("remark: %s\n", i1->shi1_remark);
+ break;
+ case 2:
+ printf("netname: %s\n", i2->shi2_netname);
+ printf("type: %d\n", i2->shi2_type);
+ printf("remark: %s\n", i2->shi2_remark);
+ printf("permissions: %d\n", i2->shi2_permissions);
+ printf("max users: %d\n", i2->shi2_max_uses);
+ printf("current users: %d\n", i2->shi2_current_uses);
+ printf("path: %s\n", i2->shi2_path);
+ printf("password: %s\n", i2->shi2_passwd);
+ break;
+ case 501:
+ printf("netname: %s\n", i501->shi501_netname);
+ printf("type: %d\n", i501->shi501_type);
+ printf("remark: %s\n", i501->shi501_remark);
+ printf("flags: %d\n", i501->shi501_flags);
+ break;
+ case 1005:
+ printf("flags: %d\n", i1005->shi1005_flags);
+ break;
+ default:
+ break;
+ }
+ NetApiBufferFree(buffer);
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/share/share_setinfo.c b/source3/lib/netapi/examples/share/share_setinfo.c
new file mode 100644
index 0000000000..f4748f4122
--- /dev/null
+++ b/source3/lib/netapi/examples/share/share_setinfo.c
@@ -0,0 +1,105 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetShareSetInfo query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *sharename = NULL;
+ const char *comment = "NetApi generated Share comment";
+ uint32_t level = 1004;
+ uint8_t *buffer = NULL;
+ uint32_t parm_err = 0;
+
+ struct SHARE_INFO_1004 i1004;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("share_setinfo", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname sharename comment");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ sharename = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ comment = poptGetArg(pc);
+ }
+
+ /* NetShareSetInfo */
+ switch (level) {
+ case 1004:
+ i1004.shi1004_remark = comment;
+ buffer = (uint8_t *)&i1004;
+ break;
+ default:
+ break;
+ }
+
+ status = NetShareSetInfo(hostname,
+ sharename,
+ level,
+ buffer,
+ &parm_err);
+ if (status != 0) {
+ printf("NetShareSetInfo failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/user/user_add.c b/source3/lib/netapi/examples/user/user_add.c
new file mode 100644
index 0000000000..5452f77bb7
--- /dev/null
+++ b/source3/lib/netapi/examples/user/user_add.c
@@ -0,0 +1,103 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetUserAdd query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *username = NULL;
+ const char *password = NULL;
+ struct USER_INFO_1 info1;
+ uint32_t parm_error = 0;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("user_add", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname username password");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ username = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ password = poptGetArg(pc);
+
+ /* NetUserAdd */
+
+ info1.usri1_name = username;
+ info1.usri1_password = password;
+ info1.usri1_password_age = 0;
+ info1.usri1_priv = 0;
+ info1.usri1_home_dir = NULL;
+ info1.usri1_comment = "User created using Samba NetApi Example code";
+ info1.usri1_flags = 0;
+ info1.usri1_script_path = NULL;
+
+ status = NetUserAdd(hostname,
+ 1,
+ (uint8_t *)&info1,
+ &parm_error);
+ if (status != 0) {
+ printf("NetUserAdd failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/user/user_chgpwd.c b/source3/lib/netapi/examples/user/user_chgpwd.c
new file mode 100644
index 0000000000..8b37ec2a99
--- /dev/null
+++ b/source3/lib/netapi/examples/user/user_chgpwd.c
@@ -0,0 +1,99 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetUserChangePassword query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *username = NULL;
+ const char *old_password = NULL;
+ const char *new_password = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("user_chgpwd", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname username old_password new_password");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ username = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ old_password = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ new_password = poptGetArg(pc);
+
+ /* NetUserChangePassword */
+
+ status = NetUserChangePassword(hostname,
+ username,
+ old_password,
+ new_password);
+ if (status != 0) {
+ printf("NetUserChangePassword failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/user/user_del.c b/source3/lib/netapi/examples/user/user_del.c
new file mode 100644
index 0000000000..9cf28a91ba
--- /dev/null
+++ b/source3/lib/netapi/examples/user/user_del.c
@@ -0,0 +1,82 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetUserDel query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *username = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("user_del", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname username");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ username = poptGetArg(pc);
+
+ /* NetUserDel */
+
+ status = NetUserDel(hostname, username);
+ if (status != 0) {
+ printf("NetUserDel failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/user/user_dispinfo.c b/source3/lib/netapi/examples/user/user_dispinfo.c
new file mode 100644
index 0000000000..23024fe9fe
--- /dev/null
+++ b/source3/lib/netapi/examples/user/user_dispinfo.c
@@ -0,0 +1,100 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetQueryDisplayInformation query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ void *buffer = NULL;
+ uint32_t entries_read = 0;
+ uint32_t idx = 0;
+ int i;
+
+ struct NET_DISPLAY_USER *user;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("user_dispinfo", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ /* NetQueryDisplayInformation */
+
+ do {
+ status = NetQueryDisplayInformation(hostname,
+ 1,
+ idx,
+ 1000,
+ (uint32_t)-1,
+ &entries_read,
+ &buffer);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+ user = (struct NET_DISPLAY_USER *)buffer;
+ for (i=0; i<entries_read; i++) {
+ printf("user %d: %s\n", i + idx,
+ user->usri1_name);
+ user++;
+ }
+ NetApiBufferFree(buffer);
+ }
+ idx += entries_read;
+ } while (status == ERROR_MORE_DATA);
+
+ if (status != 0) {
+ printf("NetQueryDisplayInformation failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/user/user_enum.c b/source3/lib/netapi/examples/user/user_enum.c
new file mode 100644
index 0000000000..cf77bf2d54
--- /dev/null
+++ b/source3/lib/netapi/examples/user/user_enum.c
@@ -0,0 +1,157 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetUserEnum query
+ * Copyright (C) Guenther Deschner 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ uint32_t level = 0;
+ uint8_t *buffer = NULL;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ char *sid_str = NULL;
+ int i;
+
+ struct USER_INFO_0 *info0 = NULL;
+ struct USER_INFO_10 *info10 = NULL;
+ struct USER_INFO_20 *info20 = NULL;
+ struct USER_INFO_23 *info23 = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("user_enum", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ /* NetUserEnum */
+
+ do {
+ status = NetUserEnum(hostname,
+ level,
+ FILTER_NORMAL_ACCOUNT,
+ &buffer,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries,
+ &resume_handle);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+
+ switch (level) {
+ case 0:
+ info0 = (struct USER_INFO_0 *)buffer;
+ break;
+ case 10:
+ info10 = (struct USER_INFO_10 *)buffer;
+ break;
+ case 20:
+ info20 = (struct USER_INFO_20 *)buffer;
+ break;
+ case 23:
+ info23 = (struct USER_INFO_23 *)buffer;
+ break;
+ default:
+ break;
+ }
+
+ for (i=0; i<entries_read; i++) {
+ switch (level) {
+ case 0:
+ printf("#%d user: %s\n", i, info0->usri0_name);
+ info0++;
+ break;
+ case 10:
+ printf("#%d user: %s\n", i, info10->usri10_name);
+ printf("#%d comment: %s\n", i, info10->usri10_comment);
+ printf("#%d usr_comment: %s\n", i, info10->usri10_usr_comment);
+ printf("#%d full_name: %s\n", i, info10->usri10_full_name);
+ info10++;
+ break;
+ case 20:
+ printf("#%d user: %s\n", i, info20->usri20_name);
+ printf("#%d comment: %s\n", i, info20->usri20_comment);
+ printf("#%d flags: 0x%08x\n", i, info20->usri20_flags);
+ printf("#%d rid: %d\n", i, info20->usri20_user_id);
+ info20++;
+ break;
+ case 23:
+ printf("#%d user: %s\n", i, info23->usri23_name);
+ printf("#%d comment: %s\n", i, info23->usri23_comment);
+ printf("#%d flags: 0x%08x\n", i, info23->usri23_flags);
+ if (ConvertSidToStringSid(info23->usri23_user_sid,
+ &sid_str)) {
+ printf("#%d sid: %s\n", i, sid_str);
+ free(sid_str);
+ }
+ info23++;
+ break;
+ default:
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status != 0) {
+ printf("NetUserEnum failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/user/user_getgroups.c b/source3/lib/netapi/examples/user/user_getgroups.c
new file mode 100644
index 0000000000..939415e0eb
--- /dev/null
+++ b/source3/lib/netapi/examples/user/user_getgroups.c
@@ -0,0 +1,133 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetUserGetGroups query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *username = NULL;
+ uint32_t level = 0;
+ uint8_t *buffer = NULL;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ int i;
+
+ struct GROUP_USERS_INFO_0 *info0 = NULL;
+ struct GROUP_USERS_INFO_1 *info1 = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("user_getgroups", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname username level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ username = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ /* NetUserGetGroups */
+
+ do {
+ status = NetUserGetGroups(hostname,
+ username,
+ level,
+ &buffer,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+
+ switch (level) {
+ case 0:
+ info0 = (struct GROUP_USERS_INFO_0 *)buffer;
+ break;
+ case 1:
+ info1 = (struct GROUP_USERS_INFO_1 *)buffer;
+ break;
+ default:
+ break;
+ }
+
+ for (i=0; i<entries_read; i++) {
+ switch (level) {
+ case 0:
+ printf("#%d group: %s\n", i, info0->grui0_name);
+ info0++;
+ break;
+ case 1:
+ printf("#%d group: %s\n", i, info1->grui1_name);
+ printf("#%d attributes: %d\n", i, info1->grui1_attributes);
+ info1++;
+ break;
+ default:
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status != 0) {
+ printf("NetUserGetGroups failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/user/user_getinfo.c b/source3/lib/netapi/examples/user/user_getinfo.c
new file mode 100644
index 0000000000..9e95260b5a
--- /dev/null
+++ b/source3/lib/netapi/examples/user/user_getinfo.c
@@ -0,0 +1,293 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetUserGetInfo query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *username = NULL;
+ uint8_t *buffer = NULL;
+ uint32_t level = 0;
+ char *sid_str = NULL;
+ int i;
+
+ struct USER_INFO_0 *u0;
+ struct USER_INFO_1 *u1;
+ struct USER_INFO_2 *u2;
+ struct USER_INFO_3 *u3;
+ struct USER_INFO_4 *u4;
+ struct USER_INFO_10 *u10;
+ struct USER_INFO_11 *u11;
+ struct USER_INFO_20 *u20;
+ struct USER_INFO_23 *u23;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("user_getinfo", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname username level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ username = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ /* NetUserGetInfo */
+
+ status = NetUserGetInfo(hostname,
+ username,
+ level,
+ &buffer);
+ if (status != 0) {
+ printf("NetUserGetInfo failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ switch (level) {
+ case 0:
+ u0 = (struct USER_INFO_0 *)buffer;
+ printf("name: %s\n", u0->usri0_name);
+ break;
+ case 1:
+ u1 = (struct USER_INFO_1 *)buffer;
+ printf("name: %s\n", u1->usri1_name);
+ printf("password: %s\n", u1->usri1_password);
+ printf("password_age: %d\n", u1->usri1_password_age);
+ printf("priv: %d\n", u1->usri1_priv);
+ printf("homedir: %s\n", u1->usri1_home_dir);
+ printf("comment: %s\n", u1->usri1_comment);
+ printf("flags: 0x%08x\n", u1->usri1_flags);
+ printf("script: %s\n", u1->usri1_script_path);
+ break;
+ case 2:
+ u2 = (struct USER_INFO_2 *)buffer;
+ printf("name: %s\n", u2->usri2_name);
+ printf("password: %s\n", u2->usri2_password);
+ printf("password_age: %d\n", u2->usri2_password_age);
+ printf("priv: %d\n", u2->usri2_priv);
+ printf("homedir: %s\n", u2->usri2_home_dir);
+ printf("comment: %s\n", u2->usri2_comment);
+ printf("flags: 0x%08x\n", u2->usri2_flags);
+ printf("script: %s\n", u2->usri2_script_path);
+ printf("auth flags: 0x%08x\n", u2->usri2_auth_flags);
+ printf("full name: %s\n", u2->usri2_full_name);
+ printf("user comment: %s\n", u2->usri2_usr_comment);
+ printf("user parameters: %s\n", u2->usri2_parms);
+ printf("workstations: %s\n", u2->usri2_workstations);
+ printf("last logon (seconds since jan. 1, 1970 GMT): %d\n",
+ u2->usri2_last_logon);
+ printf("last logoff (seconds since jan. 1, 1970 GMT): %d\n",
+ u2->usri2_last_logoff);
+ printf("account expires (seconds since jan. 1, 1970 GMT): %d\n",
+ u2->usri2_acct_expires);
+ printf("max storage: %d\n", u2->usri2_max_storage);
+ printf("units per week: %d\n", u2->usri2_units_per_week);
+ printf("logon hours:");
+ for (i=0; i<21; i++) {
+ printf(" %x", (uint8_t)u2->usri2_logon_hours[i]);
+ }
+ printf("\n");
+ printf("bad password count: %d\n", u2->usri2_bad_pw_count);
+ printf("logon count: %d\n", u2->usri2_num_logons);
+ printf("logon server: %s\n", u2->usri2_logon_server);
+ printf("country code: %d\n", u2->usri2_country_code);
+ printf("code page: %d\n", u2->usri2_code_page);
+ break;
+ case 3:
+ u3 = (struct USER_INFO_3 *)buffer;
+ printf("name: %s\n", u3->usri3_name);
+ printf("password_age: %d\n", u3->usri3_password_age);
+ printf("priv: %d\n", u3->usri3_priv);
+ printf("homedir: %s\n", u3->usri3_home_dir);
+ printf("comment: %s\n", u3->usri3_comment);
+ printf("flags: 0x%08x\n", u3->usri3_flags);
+ printf("script: %s\n", u3->usri3_script_path);
+ printf("auth flags: 0x%08x\n", u3->usri3_auth_flags);
+ printf("full name: %s\n", u3->usri3_full_name);
+ printf("user comment: %s\n", u3->usri3_usr_comment);
+ printf("user parameters: %s\n", u3->usri3_parms);
+ printf("workstations: %s\n", u3->usri3_workstations);
+ printf("last logon (seconds since jan. 1, 1970 GMT): %d\n",
+ u3->usri3_last_logon);
+ printf("last logoff (seconds since jan. 1, 1970 GMT): %d\n",
+ u3->usri3_last_logoff);
+ printf("account expires (seconds since jan. 1, 1970 GMT): %d\n",
+ u3->usri3_acct_expires);
+ printf("max storage: %d\n", u3->usri3_max_storage);
+ printf("units per week: %d\n", u3->usri3_units_per_week);
+ printf("logon hours:");
+ for (i=0; i<21; i++) {
+ printf(" %x", (uint8_t)u3->usri3_logon_hours[i]);
+ }
+ printf("\n");
+ printf("bad password count: %d\n", u3->usri3_bad_pw_count);
+ printf("logon count: %d\n", u3->usri3_num_logons);
+ printf("logon server: %s\n", u3->usri3_logon_server);
+ printf("country code: %d\n", u3->usri3_country_code);
+ printf("code page: %d\n", u3->usri3_code_page);
+ printf("user id: %d\n", u3->usri3_user_id);
+ printf("primary group id: %d\n", u3->usri3_primary_group_id);
+ printf("profile: %s\n", u3->usri3_profile);
+ printf("home dir drive: %s\n", u3->usri3_home_dir_drive);
+ printf("password expired: %d\n", u3->usri3_password_expired);
+ break;
+ case 4:
+ u4 = (struct USER_INFO_4 *)buffer;
+ printf("name: %s\n", u4->usri4_name);
+ printf("password: %s\n", u4->usri4_password);
+ printf("password_age: %d\n", u4->usri4_password_age);
+ printf("priv: %d\n", u4->usri4_priv);
+ printf("homedir: %s\n", u4->usri4_home_dir);
+ printf("comment: %s\n", u4->usri4_comment);
+ printf("flags: 0x%08x\n", u4->usri4_flags);
+ printf("script: %s\n", u4->usri4_script_path);
+ printf("auth flags: 0x%08x\n", u4->usri4_auth_flags);
+ printf("full name: %s\n", u4->usri4_full_name);
+ printf("user comment: %s\n", u4->usri4_usr_comment);
+ printf("user parameters: %s\n", u4->usri4_parms);
+ printf("workstations: %s\n", u4->usri4_workstations);
+ printf("last logon (seconds since jan. 1, 1970 GMT): %d\n",
+ u4->usri4_last_logon);
+ printf("last logoff (seconds since jan. 1, 1970 GMT): %d\n",
+ u4->usri4_last_logoff);
+ printf("account expires (seconds since jan. 1, 1970 GMT): %d\n",
+ u4->usri4_acct_expires);
+ printf("max storage: %d\n", u4->usri4_max_storage);
+ printf("units per week: %d\n", u4->usri4_units_per_week);
+ printf("logon hours:");
+ for (i=0; i<21; i++) {
+ printf(" %x", (uint8_t)u4->usri4_logon_hours[i]);
+ }
+ printf("\n");
+ printf("bad password count: %d\n", u4->usri4_bad_pw_count);
+ printf("logon count: %d\n", u4->usri4_num_logons);
+ printf("logon server: %s\n", u4->usri4_logon_server);
+ printf("country code: %d\n", u4->usri4_country_code);
+ printf("code page: %d\n", u4->usri4_code_page);
+ if (ConvertSidToStringSid(u4->usri4_user_sid,
+ &sid_str)) {
+ printf("user_sid: %s\n", sid_str);
+ free(sid_str);
+ }
+ printf("primary group id: %d\n", u4->usri4_primary_group_id);
+ printf("profile: %s\n", u4->usri4_profile);
+ printf("home dir drive: %s\n", u4->usri4_home_dir_drive);
+ printf("password expired: %d\n", u4->usri4_password_expired);
+ break;
+ case 10:
+ u10 = (struct USER_INFO_10 *)buffer;
+ printf("name: %s\n", u10->usri10_name);
+ printf("comment: %s\n", u10->usri10_comment);
+ printf("usr_comment: %s\n", u10->usri10_usr_comment);
+ printf("full_name: %s\n", u10->usri10_full_name);
+ break;
+ case 11:
+ u11 = (struct USER_INFO_11 *)buffer;
+ printf("name: %s\n", u11->usri11_name);
+ printf("comment: %s\n", u11->usri11_comment);
+ printf("user comment: %s\n", u11->usri11_usr_comment);
+ printf("full name: %s\n", u11->usri11_full_name);
+ printf("priv: %d\n", u11->usri11_priv);
+ printf("auth flags: 0x%08x\n", u11->usri11_auth_flags);
+ printf("password_age: %d\n", u11->usri11_password_age);
+ printf("homedir: %s\n", u11->usri11_home_dir);
+ printf("user parameters: %s\n", u11->usri11_parms);
+ printf("last logon (seconds since jan. 1, 1970 GMT): %d\n",
+ u11->usri11_last_logon);
+ printf("last logoff (seconds since jan. 1, 1970 GMT): %d\n",
+ u11->usri11_last_logoff);
+ printf("bad password count: %d\n", u11->usri11_bad_pw_count);
+ printf("logon count: %d\n", u11->usri11_num_logons);
+ printf("logon server: %s\n", u11->usri11_logon_server);
+ printf("country code: %d\n", u11->usri11_country_code);
+ printf("workstations: %s\n", u11->usri11_workstations);
+ printf("max storage: %d\n", u11->usri11_max_storage);
+ printf("units per week: %d\n", u11->usri11_units_per_week);
+ printf("logon hours:");
+ for (i=0; i<21; i++) {
+ printf(" %x", (uint8_t)u11->usri11_logon_hours[i]);
+ }
+ printf("\n");
+ printf("code page: %d\n", u11->usri11_code_page);
+ break;
+ case 20:
+ u20 = (struct USER_INFO_20 *)buffer;
+ printf("name: %s\n", u20->usri20_name);
+ printf("comment: %s\n", u20->usri20_comment);
+ printf("flags: 0x%08x\n", u20->usri20_flags);
+ printf("rid: %d\n", u20->usri20_user_id);
+ break;
+ case 23:
+ u23 = (struct USER_INFO_23 *)buffer;
+ printf("name: %s\n", u23->usri23_name);
+ printf("comment: %s\n", u23->usri23_comment);
+ printf("flags: 0x%08x\n", u23->usri23_flags);
+ if (ConvertSidToStringSid(u23->usri23_user_sid,
+ &sid_str)) {
+ printf("user_sid: %s\n", sid_str);
+ free(sid_str);
+ }
+ break;
+ default:
+ break;
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/user/user_getlocalgroups.c b/source3/lib/netapi/examples/user/user_getlocalgroups.c
new file mode 100644
index 0000000000..133104d7c1
--- /dev/null
+++ b/source3/lib/netapi/examples/user/user_getlocalgroups.c
@@ -0,0 +1,122 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetUserGetLocalGroups query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *username = NULL;
+ uint32_t level = 0;
+ uint8_t *buffer = NULL;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ uint32_t flags = 0;
+ int i;
+
+ struct LOCALGROUP_USERS_INFO_0 *info0 = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("user_getlocalgroups", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname username");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ username = poptGetArg(pc);
+
+ /* NetUserGetLocalGroups */
+
+ do {
+ status = NetUserGetLocalGroups(hostname,
+ username,
+ level,
+ flags,
+ &buffer,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+
+ switch (level) {
+ case 0:
+ info0 = (struct LOCALGROUP_USERS_INFO_0 *)buffer;
+ break;
+ default:
+ break;
+ }
+
+ for (i=0; i<entries_read; i++) {
+ switch (level) {
+ case 0:
+ printf("#%d group: %s\n", i, info0->lgrui0_name);
+ info0++;
+ break;
+ default:
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status != 0) {
+ printf("NetUserGetLocalGroups failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/user/user_modalsget.c b/source3/lib/netapi/examples/user/user_modalsget.c
new file mode 100644
index 0000000000..4dcb41bef7
--- /dev/null
+++ b/source3/lib/netapi/examples/user/user_modalsget.c
@@ -0,0 +1,131 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetUserModalsGet query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ uint8_t *buffer = NULL;
+ uint32_t level = 0;
+ char *sid_str = NULL;
+
+ struct USER_MODALS_INFO_0 *u0;
+ struct USER_MODALS_INFO_1 *u1;
+ struct USER_MODALS_INFO_2 *u2;
+ struct USER_MODALS_INFO_3 *u3;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("user_modalsget", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ /* NetUserModalsGet */
+
+ status = NetUserModalsGet(hostname,
+ level,
+ &buffer);
+ if (status != 0) {
+ printf("NetUserModalsGet failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ switch (level) {
+ case 0:
+ u0 = (struct USER_MODALS_INFO_0 *)buffer;
+ printf("min passwd len: %d character\n",
+ u0->usrmod0_min_passwd_len);
+ printf("max passwd age: %d (days)\n",
+ u0->usrmod0_max_passwd_age/86400);
+ printf("min passwd age: %d (days)\n",
+ u0->usrmod0_min_passwd_age/86400);
+ printf("force logoff: %d (seconds)\n",
+ u0->usrmod0_force_logoff);
+ printf("password history length: %d entries\n",
+ u0->usrmod0_password_hist_len);
+ break;
+ case 1:
+ u1 = (struct USER_MODALS_INFO_1 *)buffer;
+ printf("role: %d\n", u1->usrmod1_role);
+ printf("primary: %s\n", u1->usrmod1_primary);
+ break;
+ case 2:
+ u2 = (struct USER_MODALS_INFO_2 *)buffer;
+ printf("domain name: %s\n", u2->usrmod2_domain_name);
+ if (ConvertSidToStringSid(u2->usrmod2_domain_id,
+ &sid_str)) {
+ printf("domain sid: %s\n", sid_str);
+ free(sid_str);
+ }
+ break;
+ case 3:
+ u3 = (struct USER_MODALS_INFO_3 *)buffer;
+ printf("lockout duration: %d (seconds)\n",
+ u3->usrmod3_lockout_duration);
+ printf("lockout observation window: %d (seconds)\n",
+ u3->usrmod3_lockout_observation_window);
+ printf("lockout threshold: %d entries\n",
+ u3->usrmod3_lockout_threshold);
+ break;
+ default:
+ break;
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/user/user_modalsset.c b/source3/lib/netapi/examples/user/user_modalsset.c
new file mode 100644
index 0000000000..57e1ef70ea
--- /dev/null
+++ b/source3/lib/netapi/examples/user/user_modalsset.c
@@ -0,0 +1,141 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetUserModalsSet query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ uint8_t *buffer = NULL;
+ uint32_t level = 0;
+ uint32_t value = 0;
+ uint32_t parm_err = 0;
+
+ struct USER_MODALS_INFO_0 u0;
+ struct USER_MODALS_INFO_1 u1;
+ struct USER_MODALS_INFO_2 u2;
+ struct USER_MODALS_INFO_3 u3;
+ struct USER_MODALS_INFO_1001 u1001;
+ struct USER_MODALS_INFO_1002 u1002;
+ struct USER_MODALS_INFO_1003 u1003;
+ struct USER_MODALS_INFO_1004 u1004;
+ struct USER_MODALS_INFO_1005 u1005;
+ struct USER_MODALS_INFO_1006 u1006;
+ struct USER_MODALS_INFO_1007 u1007;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("user_modalsset", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname level value");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (poptPeekArg(pc)) {
+ level = atoi(poptGetArg(pc));
+ }
+
+ if (poptPeekArg(pc)) {
+ value = atoi(poptGetArg(pc));
+ }
+
+ switch (level) {
+ case 0:
+ u0.usrmod0_min_passwd_len = 0;
+ u0.usrmod0_max_passwd_age = (86400 * 30); /* once a month */
+ u0.usrmod0_min_passwd_age = 0;
+ u0.usrmod0_force_logoff = TIMEQ_FOREVER;
+ u0.usrmod0_password_hist_len = 0;
+ buffer = (uint8_t *)&u0;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 1001:
+ u1001.usrmod1001_min_passwd_len = 0;
+ buffer = (uint8_t *)&u1001;
+ break;
+ case 1002:
+ u1002.usrmod1002_max_passwd_age = 0;
+ buffer = (uint8_t *)&u1002;
+ break;
+ case 1003:
+ u1003.usrmod1003_min_passwd_age = (86400 * 30); /* once a month */
+ buffer = (uint8_t *)&u1003;
+ break;
+ case 1004:
+ u1004.usrmod1004_force_logoff = TIMEQ_FOREVER;
+ buffer = (uint8_t *)&u1004;
+ break;
+ case 1005:
+ u1005.usrmod1005_password_hist_len = 0;
+ buffer = (uint8_t *)&u1005;
+ break;
+ case 1006:
+ case 1007:
+ default:
+ break;
+ }
+
+ /* NetUserModalsSet */
+
+ status = NetUserModalsSet(hostname,
+ level,
+ buffer,
+ &parm_err);
+ if (status != 0) {
+ printf("NetUserModalsSet failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/user/user_setgroups.c b/source3/lib/netapi/examples/user/user_setgroups.c
new file mode 100644
index 0000000000..de3ff22ec8
--- /dev/null
+++ b/source3/lib/netapi/examples/user/user_setgroups.c
@@ -0,0 +1,144 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetUserSetGroups query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *username = NULL;
+ uint32_t level = 0;
+ uint8_t *buffer = NULL;
+ uint32_t num_entries = 0;
+ const char **names = NULL;
+ int i = 0;
+ size_t buf_size = 0;
+
+ struct GROUP_USERS_INFO_0 *g0 = NULL;
+ struct GROUP_USERS_INFO_1 *g1 = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("user_setgroups", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname username group1 group2 ...");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ username = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+
+ names = poptGetArgs(pc);
+ for (i=0; names[i] != NULL; i++) {
+ num_entries++;
+ }
+
+ switch (level) {
+ case 0:
+ buf_size = sizeof(struct GROUP_USERS_INFO_0) * num_entries;
+
+ status = NetApiBufferAllocate(buf_size, (void **)&g0);
+ if (status) {
+ printf("NetApiBufferAllocate failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ for (i=0; i<num_entries; i++) {
+ g0[i].grui0_name = names[i];
+ }
+
+ buffer = (uint8_t *)g0;
+ break;
+ case 1:
+ buf_size = sizeof(struct GROUP_USERS_INFO_1) * num_entries;
+
+ status = NetApiBufferAllocate(buf_size, (void **)&g1);
+ if (status) {
+ printf("NetApiBufferAllocate failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ for (i=0; i<num_entries; i++) {
+ g1[i].grui1_name = names[i];
+ g1[i].grui1_attributes = 0; /* ? */
+ }
+
+ buffer = (uint8_t *)g1;
+ break;
+ default:
+ break;
+ }
+
+ /* NetUserSetGroups */
+
+ status = NetUserSetGroups(hostname,
+ username,
+ level,
+ buffer,
+ num_entries);
+ if (status != 0) {
+ printf("NetUserSetGroups failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ out:
+ NetApiBufferFree(buffer);
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/user/user_setinfo.c b/source3/lib/netapi/examples/user/user_setinfo.c
new file mode 100644
index 0000000000..4f02ae7781
--- /dev/null
+++ b/source3/lib/netapi/examples/user/user_setinfo.c
@@ -0,0 +1,207 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetUserSetInfo query
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+ const char *username = NULL;
+ uint32_t level = 0;
+ uint32_t parm_err = 0;
+ uint8_t *buffer = NULL;
+ const char *val = NULL;
+
+ struct USER_INFO_0 u0;
+ struct USER_INFO_1 u1;
+ struct USER_INFO_2 u2;
+ struct USER_INFO_3 u3;
+ struct USER_INFO_4 u4;
+ struct USER_INFO_21 u21;
+ struct USER_INFO_22 u22;
+ struct USER_INFO_1003 u1003;
+ struct USER_INFO_1005 u1005;
+ struct USER_INFO_1006 u1006;
+ struct USER_INFO_1007 u1007;
+ struct USER_INFO_1008 u1008;
+ struct USER_INFO_1009 u1009;
+ struct USER_INFO_1010 u1010;
+ struct USER_INFO_1011 u1011;
+ struct USER_INFO_1012 u1012;
+ struct USER_INFO_1014 u1014;
+ struct USER_INFO_1017 u1017;
+ struct USER_INFO_1020 u1020;
+ struct USER_INFO_1024 u1024;
+ struct USER_INFO_1051 u1051;
+ struct USER_INFO_1052 u1052;
+ struct USER_INFO_1053 u1053;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("user_setinfo", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname username level");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ username = poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ level = atoi(poptGetArg(pc));
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ val = poptGetArg(pc);
+
+ /* NetUserSetInfo */
+
+ switch (level) {
+ case 0:
+ u0.usri0_name = val;
+ buffer = (uint8_t *)&u0;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ break;
+ case 21:
+ break;
+ case 22:
+ break;
+ case 1003:
+ u1003.usri1003_password = val;
+ buffer = (uint8_t *)&u1003;
+ break;
+ case 1005:
+ u1005.usri1005_priv = atoi(val);
+ buffer = (uint8_t *)&u1005;
+ break;
+ case 1006:
+ u1006.usri1006_home_dir = val;
+ buffer = (uint8_t *)&u1006;
+ break;
+ case 1007:
+ u1007.usri1007_comment = val;
+ buffer = (uint8_t *)&u1007;
+ break;
+ case 1008:
+ u1008.usri1008_flags = atoi(val);
+ buffer = (uint8_t *)&u1008;
+ break;
+ case 1009:
+ u1009.usri1009_script_path = val;
+ buffer = (uint8_t *)&u1009;
+ break;
+ case 1010:
+ u1010.usri1010_auth_flags = atoi(val);
+ buffer = (uint8_t *)&u1010;
+ break;
+ case 1011:
+ u1011.usri1011_full_name = val;
+ buffer = (uint8_t *)&u1011;
+ break;
+ case 1012:
+ u1012.usri1012_usr_comment = val;
+ buffer = (uint8_t *)&u1012;
+ break;
+ case 1014:
+ u1014.usri1014_workstations = val;
+ buffer = (uint8_t *)&u1014;
+ break;
+ case 1017:
+ u1017.usri1017_acct_expires = atoi(val);
+ buffer = (uint8_t *)&u1017;
+ break;
+ case 1020:
+ break;
+ case 1024:
+ u1024.usri1024_country_code = atoi(val);
+ buffer = (uint8_t *)&u1024;
+ break;
+ case 1051:
+ u1051.usri1051_primary_group_id = atoi(val);
+ buffer = (uint8_t *)&u1051;
+ break;
+ case 1052:
+ u1052.usri1052_profile = val;
+ buffer = (uint8_t *)&u1052;
+ break;
+ case 1053:
+ u1053.usri1053_home_dir_drive = val;
+ buffer = (uint8_t *)&u1053;
+ break;
+ default:
+ break;
+ }
+
+ status = NetUserSetInfo(hostname,
+ username,
+ level,
+ buffer,
+ &parm_err);
+ if (status != 0) {
+ printf("NetUserSetInfo failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ goto out;
+ }
+
+ out:
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/file.c b/source3/lib/netapi/file.c
new file mode 100644
index 0000000000..036af32f38
--- /dev/null
+++ b/source3/lib/netapi/file.c
@@ -0,0 +1,289 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi File Support
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#include "librpc/gen_ndr/libnetapi.h"
+#include "lib/netapi/netapi.h"
+#include "lib/netapi/netapi_private.h"
+#include "lib/netapi/libnetapi.h"
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetFileClose_r(struct libnetapi_ctx *ctx,
+ struct NetFileClose *r)
+{
+ WERROR werr;
+ NTSTATUS status;
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_srvsvc.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = rpccli_srvsvc_NetFileClose(pipe_cli, ctx,
+ r->in.server_name,
+ r->in.fileid,
+ &werr);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetFileClose_l(struct libnetapi_ctx *ctx,
+ struct NetFileClose *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetFileClose);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS map_srvsvc_FileInfo_to_FILE_INFO_buffer(TALLOC_CTX *mem_ctx,
+ uint32_t level,
+ union srvsvc_NetFileInfo *info,
+ uint8_t **buffer,
+ uint32_t *num_entries)
+{
+ struct FILE_INFO_2 i2;
+ struct FILE_INFO_3 i3;
+
+ switch (level) {
+ case 2:
+ i2.fi2_id = info->info2->fid;
+
+ ADD_TO_ARRAY(mem_ctx, struct FILE_INFO_2, i2,
+ (struct FILE_INFO_2 **)buffer,
+ num_entries);
+ break;
+ case 3:
+ i3.fi3_id = info->info3->fid;
+ i3.fi3_permissions = info->info3->permissions;
+ i3.fi3_num_locks = info->info3->num_locks;
+ i3.fi3_pathname = talloc_strdup(mem_ctx, info->info3->path);
+ i3.fi3_username = talloc_strdup(mem_ctx, info->info3->user);
+
+ NT_STATUS_HAVE_NO_MEMORY(i3.fi3_pathname);
+ NT_STATUS_HAVE_NO_MEMORY(i3.fi3_username);
+
+ ADD_TO_ARRAY(mem_ctx, struct FILE_INFO_3, i3,
+ (struct FILE_INFO_3 **)buffer,
+ num_entries);
+ break;
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetFileGetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetFileGetInfo *r)
+{
+ WERROR werr;
+ NTSTATUS status;
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ union srvsvc_NetFileInfo info;
+ uint32_t num_entries = 0;
+
+ if (!r->out.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 2:
+ case 3:
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_srvsvc.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = rpccli_srvsvc_NetFileGetInfo(pipe_cli, ctx,
+ r->in.server_name,
+ r->in.fileid,
+ r->in.level,
+ &info,
+ &werr);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = map_srvsvc_FileInfo_to_FILE_INFO_buffer(ctx,
+ r->in.level,
+ &info,
+ r->out.buffer,
+ &num_entries);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetFileGetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetFileGetInfo *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetFileGetInfo);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetFileEnum_r(struct libnetapi_ctx *ctx,
+ struct NetFileEnum *r)
+{
+ WERROR werr;
+ NTSTATUS status;
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct srvsvc_NetFileInfoCtr info_ctr;
+ struct srvsvc_NetFileCtr2 ctr2;
+ struct srvsvc_NetFileCtr3 ctr3;
+ uint32_t num_entries = 0;
+ uint32_t i;
+
+ if (!r->out.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 2:
+ case 3:
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_srvsvc.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ ZERO_STRUCT(info_ctr);
+
+ info_ctr.level = r->in.level;
+ switch (r->in.level) {
+ case 2:
+ ZERO_STRUCT(ctr2);
+ info_ctr.ctr.ctr2 = &ctr2;
+ break;
+ case 3:
+ ZERO_STRUCT(ctr3);
+ info_ctr.ctr.ctr3 = &ctr3;
+ break;
+ }
+
+ status = rpccli_srvsvc_NetFileEnum(pipe_cli, ctx,
+ r->in.server_name,
+ r->in.base_path,
+ r->in.user_name,
+ &info_ctr,
+ r->in.prefmaxlen,
+ r->out.total_entries,
+ r->out.resume_handle,
+ &werr);
+ if (NT_STATUS_IS_ERR(status)) {
+ goto done;
+ }
+
+ for (i=0; i < info_ctr.ctr.ctr2->count; i++) {
+ union srvsvc_NetFileInfo _i;
+ switch (r->in.level) {
+ case 2:
+ _i.info2 = &info_ctr.ctr.ctr2->array[i];
+ break;
+ case 3:
+ _i.info3 = &info_ctr.ctr.ctr3->array[i];
+ break;
+ }
+
+ status = map_srvsvc_FileInfo_to_FILE_INFO_buffer(ctx,
+ r->in.level,
+ &_i,
+ r->out.buffer,
+ &num_entries);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+
+ if (r->out.entries_read) {
+ *r->out.entries_read = num_entries;
+ }
+
+ if (r->out.total_entries) {
+ *r->out.total_entries = num_entries;
+ }
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetFileEnum_l(struct libnetapi_ctx *ctx,
+ struct NetFileEnum *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetFileEnum);
+}
diff --git a/source3/lib/netapi/getdc.c b/source3/lib/netapi/getdc.c
new file mode 100644
index 0000000000..07a6544af1
--- /dev/null
+++ b/source3/lib/netapi/getdc.c
@@ -0,0 +1,167 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi GetDC Support
+ * Copyright (C) Guenther Deschner 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#include "librpc/gen_ndr/libnetapi.h"
+#include "lib/netapi/netapi.h"
+#include "lib/netapi/netapi_private.h"
+#include "lib/netapi/libnetapi.h"
+#include "libnet/libnet.h"
+
+/********************************************************************
+********************************************************************/
+
+WERROR NetGetDCName_l(struct libnetapi_ctx *ctx,
+ struct NetGetDCName *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGetDCName);
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR NetGetDCName_r(struct libnetapi_ctx *ctx,
+ struct NetGetDCName *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_netlogon.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = rpccli_netr_GetDcName(pipe_cli, ctx,
+ r->in.server_name,
+ r->in.domain_name,
+ (const char **)r->out.buffer,
+ &werr);
+ done:
+
+ return werr;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR NetGetAnyDCName_l(struct libnetapi_ctx *ctx,
+ struct NetGetAnyDCName *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGetAnyDCName);
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR NetGetAnyDCName_r(struct libnetapi_ctx *ctx,
+ struct NetGetAnyDCName *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_netlogon.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = rpccli_netr_GetAnyDCName(pipe_cli, ctx,
+ r->in.server_name,
+ r->in.domain_name,
+ (const char **)r->out.buffer,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ done:
+
+ return werr;
+
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR DsGetDcName_l(struct libnetapi_ctx *ctx,
+ struct DsGetDcName *r)
+{
+ NTSTATUS status;
+
+ status = dsgetdcname(ctx,
+ NULL,
+ r->in.domain_name,
+ r->in.domain_guid,
+ r->in.site_name,
+ r->in.flags,
+ (struct netr_DsRGetDCNameInfo **)r->out.dc_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ libnetapi_set_error_string(ctx,
+ "failed to find DC: %s",
+ get_friendly_nt_error_msg(status));
+ }
+
+ return ntstatus_to_werror(status);
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR DsGetDcName_r(struct libnetapi_ctx *ctx,
+ struct DsGetDcName *r)
+{
+ WERROR werr;
+ NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_netlogon.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = rpccli_netr_DsRGetDCName(pipe_cli,
+ ctx,
+ r->in.server_name,
+ r->in.domain_name,
+ r->in.domain_guid,
+ NULL,
+ r->in.flags,
+ (struct netr_DsRGetDCNameInfo **)r->out.dc_info,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ done:
+ return werr;
+}
diff --git a/source3/lib/netapi/group.c b/source3/lib/netapi/group.c
new file mode 100644
index 0000000000..c3fccb4840
--- /dev/null
+++ b/source3/lib/netapi/group.c
@@ -0,0 +1,1691 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi Group Support
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#include "librpc/gen_ndr/libnetapi.h"
+#include "lib/netapi/netapi.h"
+#include "lib/netapi/netapi_private.h"
+#include "lib/netapi/libnetapi.h"
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupAdd_r(struct libnetapi_ctx *ctx,
+ struct NetGroupAdd *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ POLICY_HND connect_handle, domain_handle, group_handle;
+ struct lsa_String lsa_group_name;
+ struct dom_sid2 *domain_sid = NULL;
+ uint32_t rid = 0;
+
+ struct GROUP_INFO_0 *info0 = NULL;
+ struct GROUP_INFO_1 *info1 = NULL;
+ struct GROUP_INFO_2 *info2 = NULL;
+ struct GROUP_INFO_3 *info3 = NULL;
+ union samr_GroupInfo info;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(group_handle);
+
+ if (!r->in.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ info0 = (struct GROUP_INFO_0 *)r->in.buffer;
+ break;
+ case 1:
+ info1 = (struct GROUP_INFO_1 *)r->in.buffer;
+ break;
+ case 2:
+ info2 = (struct GROUP_INFO_2 *)r->in.buffer;
+ break;
+ case 3:
+ info3 = (struct GROUP_INFO_3 *)r->in.buffer;
+ break;
+ default:
+ werr = WERR_UNKNOWN_LEVEL;
+ goto done;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_CREATE_GROUP |
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ init_lsa_String(&lsa_group_name, info0->grpi0_name);
+ break;
+ case 1:
+ init_lsa_String(&lsa_group_name, info1->grpi1_name);
+ break;
+ case 2:
+ init_lsa_String(&lsa_group_name, info2->grpi2_name);
+ break;
+ case 3:
+ init_lsa_String(&lsa_group_name, info3->grpi3_name);
+ break;
+ }
+
+ status = rpccli_samr_CreateDomainGroup(pipe_cli, ctx,
+ &domain_handle,
+ &lsa_group_name,
+ SEC_STD_DELETE |
+ SAMR_GROUP_ACCESS_SET_INFO,
+ &group_handle,
+ &rid);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ switch (r->in.level) {
+ case 1:
+ if (info1->grpi1_comment) {
+ init_lsa_String(&info.description,
+ info1->grpi1_comment);
+
+ status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFODESCRIPTION,
+ &info);
+ }
+ break;
+ case 2:
+ if (info2->grpi2_comment) {
+ init_lsa_String(&info.description,
+ info2->grpi2_comment);
+
+ status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFODESCRIPTION,
+ &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto failed;
+ }
+ }
+
+ if (info2->grpi2_attributes != 0) {
+ info.attributes.attributes = info2->grpi2_attributes;
+ status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFOATTRIBUTES,
+ &info);
+
+ }
+ break;
+ case 3:
+ if (info3->grpi3_comment) {
+ init_lsa_String(&info.description,
+ info3->grpi3_comment);
+
+ status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFODESCRIPTION,
+ &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto failed;
+ }
+ }
+
+ if (info3->grpi3_attributes != 0) {
+ info.attributes.attributes = info3->grpi3_attributes;
+ status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFOATTRIBUTES,
+ &info);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto failed;
+ }
+
+ werr = WERR_OK;
+ goto done;
+
+ failed:
+ rpccli_samr_DeleteDomainGroup(pipe_cli, ctx,
+ &group_handle);
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&group_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &group_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupAdd_l(struct libnetapi_ctx *ctx,
+ struct NetGroupAdd *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupAdd);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupDel_r(struct libnetapi_ctx *ctx,
+ struct NetGroupDel *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ POLICY_HND connect_handle, domain_handle, group_handle;
+ struct lsa_String lsa_group_name;
+ struct dom_sid2 *domain_sid = NULL;
+ int i = 0;
+
+ struct samr_Ids rids;
+ struct samr_Ids types;
+ union samr_GroupInfo *info = NULL;
+ struct samr_RidTypeArray *rid_array = NULL;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(group_handle);
+
+ if (!r->in.group_name) {
+ return WERR_INVALID_PARAM;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_group_name, r->in.group_name);
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ 1,
+ &lsa_group_name,
+ &rids,
+ &types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ if (types.ids[0] != SID_NAME_DOM_GRP) {
+ werr = WERR_INVALID_DATATYPE;
+ goto done;
+ }
+
+ status = rpccli_samr_OpenGroup(pipe_cli, ctx,
+ &domain_handle,
+ SEC_STD_DELETE |
+ SAMR_GROUP_ACCESS_GET_MEMBERS |
+ SAMR_GROUP_ACCESS_REMOVE_MEMBER |
+ SAMR_GROUP_ACCESS_ADD_MEMBER |
+ SAMR_GROUP_ACCESS_LOOKUP_INFO,
+ rids.ids[0],
+ &group_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFOATTRIBUTES,
+ &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+#if 0
+ /* breaks against NT4 */
+ if (!(info->attributes.attributes & SE_GROUP_ENABLED)) {
+ werr = WERR_ACCESS_DENIED;
+ goto done;
+ }
+#endif
+ status = rpccli_samr_QueryGroupMember(pipe_cli, ctx,
+ &group_handle,
+ &rid_array);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ {
+ struct lsa_Strings names;
+ struct samr_Ids member_types;
+
+ status = rpccli_samr_LookupRids(pipe_cli, ctx,
+ &domain_handle,
+ rid_array->count,
+ rid_array->rids,
+ &names,
+ &member_types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+
+ for (i=0; i < rid_array->count; i++) {
+
+ status = rpccli_samr_DeleteGroupMember(pipe_cli, ctx,
+ &group_handle,
+ rid_array->rids[i]);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+
+ status = rpccli_samr_DeleteDomainGroup(pipe_cli, ctx,
+ &group_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ ZERO_STRUCT(group_handle);
+
+ werr = WERR_OK;
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&group_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &group_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupDel_l(struct libnetapi_ctx *ctx,
+ struct NetGroupDel *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupDel);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetGroupSetInfo *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ POLICY_HND connect_handle, domain_handle, group_handle;
+ struct lsa_String lsa_group_name;
+ struct dom_sid2 *domain_sid = NULL;
+
+ struct samr_Ids rids;
+ struct samr_Ids types;
+ union samr_GroupInfo info;
+ struct GROUP_INFO_0 *g0;
+ struct GROUP_INFO_1 *g1;
+ struct GROUP_INFO_2 *g2;
+ struct GROUP_INFO_3 *g3;
+ struct GROUP_INFO_1002 *g1002;
+ struct GROUP_INFO_1005 *g1005;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(group_handle);
+
+ if (!r->in.group_name) {
+ return WERR_INVALID_PARAM;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_group_name, r->in.group_name);
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ 1,
+ &lsa_group_name,
+ &rids,
+ &types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ if (types.ids[0] != SID_NAME_DOM_GRP) {
+ werr = WERR_INVALID_DATATYPE;
+ goto done;
+ }
+
+ status = rpccli_samr_OpenGroup(pipe_cli, ctx,
+ &domain_handle,
+ SAMR_GROUP_ACCESS_SET_INFO |
+ SAMR_GROUP_ACCESS_LOOKUP_INFO,
+ rids.ids[0],
+ &group_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ g0 = (struct GROUP_INFO_0 *)r->in.buffer;
+ init_lsa_String(&info.name, g0->grpi0_name);
+ status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFONAME,
+ &info);
+ break;
+ case 1:
+ g1 = (struct GROUP_INFO_1 *)r->in.buffer;
+ init_lsa_String(&info.description, g1->grpi1_comment);
+ status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFODESCRIPTION,
+ &info);
+ break;
+ case 2:
+ g2 = (struct GROUP_INFO_2 *)r->in.buffer;
+ init_lsa_String(&info.description, g2->grpi2_comment);
+ status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFODESCRIPTION,
+ &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ info.attributes.attributes = g2->grpi2_attributes;
+ status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFOATTRIBUTES,
+ &info);
+ break;
+ case 3:
+ g3 = (struct GROUP_INFO_3 *)r->in.buffer;
+ init_lsa_String(&info.description, g3->grpi3_comment);
+ status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFODESCRIPTION,
+ &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ info.attributes.attributes = g3->grpi3_attributes;
+ status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFOATTRIBUTES,
+ &info);
+ break;
+ case 1002:
+ g1002 = (struct GROUP_INFO_1002 *)r->in.buffer;
+ init_lsa_String(&info.description, g1002->grpi1002_comment);
+ status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFODESCRIPTION,
+ &info);
+ break;
+ case 1005:
+ g1005 = (struct GROUP_INFO_1005 *)r->in.buffer;
+ info.attributes.attributes = g1005->grpi1005_attributes;
+ status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFOATTRIBUTES,
+ &info);
+ break;
+ default:
+ status = NT_STATUS_INVALID_LEVEL;
+ break;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ werr = WERR_OK;
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&group_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &group_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupSetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetGroupSetInfo *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupSetInfo);
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR map_group_info_to_buffer(TALLOC_CTX *mem_ctx,
+ uint32_t level,
+ struct samr_GroupInfoAll *info,
+ struct dom_sid2 *domain_sid,
+ uint32_t rid,
+ uint8_t **buffer)
+{
+ struct GROUP_INFO_0 info0;
+ struct GROUP_INFO_1 info1;
+ struct GROUP_INFO_2 info2;
+ struct GROUP_INFO_3 info3;
+ struct dom_sid sid;
+
+ switch (level) {
+ case 0:
+ info0.grpi0_name = info->name.string;
+
+ *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info0, sizeof(info0));
+
+ break;
+ case 1:
+ info1.grpi1_name = info->name.string;
+ info1.grpi1_comment = info->description.string;
+
+ *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info1, sizeof(info1));
+
+ break;
+ case 2:
+ info2.grpi2_name = info->name.string;
+ info2.grpi2_comment = info->description.string;
+ info2.grpi2_group_id = rid;
+ info2.grpi2_attributes = info->attributes;
+
+ *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info2, sizeof(info2));
+
+ break;
+ case 3:
+ if (!sid_compose(&sid, domain_sid, rid)) {
+ return WERR_NOMEM;
+ }
+
+ info3.grpi3_name = info->name.string;
+ info3.grpi3_comment = info->description.string;
+ info3.grpi3_attributes = info->attributes;
+ info3.grpi3_group_sid = (struct domsid *)sid_dup_talloc(mem_ctx, &sid);
+
+ *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info3, sizeof(info3));
+
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ W_ERROR_HAVE_NO_MEMORY(*buffer);
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupGetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetGroupGetInfo *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ POLICY_HND connect_handle, domain_handle, group_handle;
+ struct lsa_String lsa_group_name;
+ struct dom_sid2 *domain_sid = NULL;
+
+ struct samr_Ids rids;
+ struct samr_Ids types;
+ union samr_GroupInfo *info = NULL;
+ bool group_info_all = false;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(group_handle);
+
+ if (!r->in.group_name) {
+ return WERR_INVALID_PARAM;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_group_name, r->in.group_name);
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ 1,
+ &lsa_group_name,
+ &rids,
+ &types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ if (types.ids[0] != SID_NAME_DOM_GRP) {
+ werr = WERR_INVALID_DATATYPE;
+ goto done;
+ }
+
+ status = rpccli_samr_OpenGroup(pipe_cli, ctx,
+ &domain_handle,
+ SAMR_GROUP_ACCESS_LOOKUP_INFO,
+ rids.ids[0],
+ &group_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFOALL2,
+ &info);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
+ status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFOALL,
+ &info);
+ group_info_all = true;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ werr = map_group_info_to_buffer(ctx, r->in.level,
+ group_info_all ? &info->all : &info->all2,
+ domain_sid, rids.ids[0],
+ r->out.buffer);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&group_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &group_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupGetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetGroupGetInfo *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupGetInfo);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx,
+ struct NetGroupAddUser *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ POLICY_HND connect_handle, domain_handle, group_handle;
+ struct lsa_String lsa_group_name, lsa_user_name;
+ struct dom_sid2 *domain_sid = NULL;
+
+ struct samr_Ids rids;
+ struct samr_Ids types;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(group_handle);
+
+ if (!r->in.group_name) {
+ return WERR_INVALID_PARAM;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_group_name, r->in.group_name);
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ 1,
+ &lsa_group_name,
+ &rids,
+ &types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = WERR_GROUP_NOT_FOUND;
+ goto done;
+ }
+
+ if (types.ids[0] != SID_NAME_DOM_GRP) {
+ werr = WERR_GROUP_NOT_FOUND;
+ goto done;
+ }
+
+ status = rpccli_samr_OpenGroup(pipe_cli, ctx,
+ &domain_handle,
+ SAMR_GROUP_ACCESS_ADD_MEMBER,
+ rids.ids[0],
+ &group_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ init_lsa_String(&lsa_user_name, r->in.user_name);
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ 1,
+ &lsa_user_name,
+ &rids,
+ &types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = WERR_USER_NOT_FOUND;
+ goto done;
+ }
+
+ if (types.ids[0] != SID_NAME_USER) {
+ werr = WERR_USER_NOT_FOUND;
+ goto done;
+ }
+
+ status = rpccli_samr_AddGroupMember(pipe_cli, ctx,
+ &group_handle,
+ rids.ids[0],
+ 7); /* why ? */
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ werr = WERR_OK;
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&group_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &group_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupAddUser_l(struct libnetapi_ctx *ctx,
+ struct NetGroupAddUser *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupAddUser);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx,
+ struct NetGroupDelUser *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ POLICY_HND connect_handle, domain_handle, group_handle;
+ struct lsa_String lsa_group_name, lsa_user_name;
+ struct dom_sid2 *domain_sid = NULL;
+
+ struct samr_Ids rids;
+ struct samr_Ids types;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(group_handle);
+
+ if (!r->in.group_name) {
+ return WERR_INVALID_PARAM;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_group_name, r->in.group_name);
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ 1,
+ &lsa_group_name,
+ &rids,
+ &types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = WERR_GROUP_NOT_FOUND;
+ goto done;
+ }
+
+ if (types.ids[0] != SID_NAME_DOM_GRP) {
+ werr = WERR_GROUP_NOT_FOUND;
+ goto done;
+ }
+
+ status = rpccli_samr_OpenGroup(pipe_cli, ctx,
+ &domain_handle,
+ SAMR_GROUP_ACCESS_REMOVE_MEMBER,
+ rids.ids[0],
+ &group_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ init_lsa_String(&lsa_user_name, r->in.user_name);
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ 1,
+ &lsa_user_name,
+ &rids,
+ &types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = WERR_USER_NOT_FOUND;
+ goto done;
+ }
+
+ if (types.ids[0] != SID_NAME_USER) {
+ werr = WERR_USER_NOT_FOUND;
+ goto done;
+ }
+
+ status = rpccli_samr_DeleteGroupMember(pipe_cli, ctx,
+ &group_handle,
+ rids.ids[0]);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ werr = WERR_OK;
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&group_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &group_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupDelUser_l(struct libnetapi_ctx *ctx,
+ struct NetGroupDelUser *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupDelUser);
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR convert_samr_disp_groups_to_GROUP_INFO_0_buffer(TALLOC_CTX *mem_ctx,
+ struct samr_DispInfoFullGroups *groups,
+ uint8_t **buffer)
+{
+ struct GROUP_INFO_0 *g0;
+ int i;
+
+ g0 = TALLOC_ZERO_ARRAY(mem_ctx, struct GROUP_INFO_0, groups->count);
+ W_ERROR_HAVE_NO_MEMORY(g0);
+
+ for (i=0; i<groups->count; i++) {
+ g0[i].grpi0_name = talloc_strdup(mem_ctx,
+ groups->entries[i].account_name.string);
+ W_ERROR_HAVE_NO_MEMORY(g0[i].grpi0_name);
+ }
+
+ *buffer = (uint8_t *)talloc_memdup(mem_ctx, g0,
+ sizeof(struct GROUP_INFO_0) * groups->count);
+ W_ERROR_HAVE_NO_MEMORY(*buffer);
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR convert_samr_disp_groups_to_GROUP_INFO_1_buffer(TALLOC_CTX *mem_ctx,
+ struct samr_DispInfoFullGroups *groups,
+ uint8_t **buffer)
+{
+ struct GROUP_INFO_1 *g1;
+ int i;
+
+ g1 = TALLOC_ZERO_ARRAY(mem_ctx, struct GROUP_INFO_1, groups->count);
+ W_ERROR_HAVE_NO_MEMORY(g1);
+
+ for (i=0; i<groups->count; i++) {
+ g1[i].grpi1_name = talloc_strdup(mem_ctx,
+ groups->entries[i].account_name.string);
+ g1[i].grpi1_comment = talloc_strdup(mem_ctx,
+ groups->entries[i].description.string);
+ W_ERROR_HAVE_NO_MEMORY(g1[i].grpi1_name);
+ }
+
+ *buffer = (uint8_t *)talloc_memdup(mem_ctx, g1,
+ sizeof(struct GROUP_INFO_1) * groups->count);
+ W_ERROR_HAVE_NO_MEMORY(*buffer);
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR convert_samr_disp_groups_to_GROUP_INFO_2_buffer(TALLOC_CTX *mem_ctx,
+ struct samr_DispInfoFullGroups *groups,
+ uint8_t **buffer)
+{
+ struct GROUP_INFO_2 *g2;
+ int i;
+
+ g2 = TALLOC_ZERO_ARRAY(mem_ctx, struct GROUP_INFO_2, groups->count);
+ W_ERROR_HAVE_NO_MEMORY(g2);
+
+ for (i=0; i<groups->count; i++) {
+ g2[i].grpi2_name = talloc_strdup(mem_ctx,
+ groups->entries[i].account_name.string);
+ g2[i].grpi2_comment = talloc_strdup(mem_ctx,
+ groups->entries[i].description.string);
+ g2[i].grpi2_group_id = groups->entries[i].rid;
+ g2[i].grpi2_attributes = groups->entries[i].acct_flags;
+ W_ERROR_HAVE_NO_MEMORY(g2[i].grpi2_name);
+ }
+
+ *buffer = (uint8_t *)talloc_memdup(mem_ctx, g2,
+ sizeof(struct GROUP_INFO_2) * groups->count);
+ W_ERROR_HAVE_NO_MEMORY(*buffer);
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR convert_samr_disp_groups_to_GROUP_INFO_3_buffer(TALLOC_CTX *mem_ctx,
+ struct samr_DispInfoFullGroups *groups,
+ const struct dom_sid *domain_sid,
+ uint8_t **buffer)
+{
+ struct GROUP_INFO_3 *g3;
+ int i;
+
+ g3 = TALLOC_ZERO_ARRAY(mem_ctx, struct GROUP_INFO_3, groups->count);
+ W_ERROR_HAVE_NO_MEMORY(g3);
+
+ for (i=0; i<groups->count; i++) {
+
+ struct dom_sid sid;
+
+ if (!sid_compose(&sid, domain_sid, groups->entries[i].rid)) {
+ return WERR_NOMEM;
+ }
+
+ g3[i].grpi3_name = talloc_strdup(mem_ctx,
+ groups->entries[i].account_name.string);
+ g3[i].grpi3_comment = talloc_strdup(mem_ctx,
+ groups->entries[i].description.string);
+ g3[i].grpi3_group_sid = (struct domsid *)sid_dup_talloc(mem_ctx, &sid);
+ g3[i].grpi3_attributes = groups->entries[i].acct_flags;
+ W_ERROR_HAVE_NO_MEMORY(g3[i].grpi3_name);
+ }
+
+ *buffer = (uint8_t *)talloc_memdup(mem_ctx, g3,
+ sizeof(struct GROUP_INFO_3) * groups->count);
+ W_ERROR_HAVE_NO_MEMORY(*buffer);
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR convert_samr_disp_groups_to_GROUP_INFO_buffer(TALLOC_CTX *mem_ctx,
+ uint32_t level,
+ struct samr_DispInfoFullGroups *groups,
+ const struct dom_sid *domain_sid,
+ uint32_t *entries_read,
+ uint8_t **buffer)
+{
+ if (entries_read) {
+ *entries_read = groups->count;
+ }
+
+ switch (level) {
+ case 0:
+ return convert_samr_disp_groups_to_GROUP_INFO_0_buffer(mem_ctx, groups, buffer);
+ case 1:
+ return convert_samr_disp_groups_to_GROUP_INFO_1_buffer(mem_ctx, groups, buffer);
+ case 2:
+ return convert_samr_disp_groups_to_GROUP_INFO_2_buffer(mem_ctx, groups, buffer);
+ case 3:
+ return convert_samr_disp_groups_to_GROUP_INFO_3_buffer(mem_ctx, groups, domain_sid, buffer);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupEnum_r(struct libnetapi_ctx *ctx,
+ struct NetGroupEnum *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct policy_handle connect_handle;
+ struct dom_sid2 *domain_sid = NULL;
+ struct policy_handle domain_handle;
+ union samr_DispInfo info;
+ union samr_DomainInfo *domain_info = NULL;
+
+ uint32_t total_size = 0;
+ uint32_t returned_size = 0;
+
+ NTSTATUS status = NT_STATUS_OK;
+ WERROR werr, tmp_werr;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+
+ switch (r->in.level) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 |
+ SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS |
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = rpccli_samr_QueryDomainInfo(pipe_cli, ctx,
+ &domain_handle,
+ 2,
+ &domain_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ if (r->out.total_entries) {
+ *r->out.total_entries = domain_info->info2.num_groups;
+ }
+
+ status = rpccli_samr_QueryDisplayInfo2(pipe_cli,
+ ctx,
+ &domain_handle,
+ 3,
+ r->in.resume_handle ?
+ *r->in.resume_handle : 0,
+ (uint32_t)-1,
+ r->in.prefmaxlen,
+ &total_size,
+ &returned_size,
+ &info);
+ werr = ntstatus_to_werror(status);
+ if (NT_STATUS_IS_ERR(status)) {
+ goto done;
+ }
+
+ if (r->out.resume_handle) {
+ *r->out.resume_handle =
+ info.info3.entries[info.info3.count-1].idx;
+ }
+
+ tmp_werr = convert_samr_disp_groups_to_GROUP_INFO_buffer(ctx,
+ r->in.level,
+ &info.info3,
+ domain_sid,
+ r->out.entries_read,
+ r->out.buffer);
+ if (!W_ERROR_IS_OK(tmp_werr)) {
+ werr = tmp_werr;
+ goto done;
+ }
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ /* if last query */
+ if (NT_STATUS_IS_OK(status) ||
+ NT_STATUS_IS_ERR(status)) {
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupEnum_l(struct libnetapi_ctx *ctx,
+ struct NetGroupEnum *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupEnum);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupGetUsers_r(struct libnetapi_ctx *ctx,
+ struct NetGroupGetUsers *r)
+{
+ /* FIXME: this call needs to cope with large replies */
+
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct policy_handle connect_handle, domain_handle, group_handle;
+ struct lsa_String lsa_account_name;
+ struct dom_sid2 *domain_sid = NULL;
+ struct samr_Ids group_rids, name_types;
+ struct samr_RidTypeArray *rid_array = NULL;
+ struct lsa_Strings names;
+ struct samr_Ids member_types;
+
+ int i;
+ uint32_t entries_read = 0;
+
+ NTSTATUS status = NT_STATUS_OK;
+ WERROR werr;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+
+ if (!r->out.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ *r->out.buffer = NULL;
+ *r->out.entries_read = 0;
+
+ switch (r->in.level) {
+ case 0:
+ case 1:
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_account_name, r->in.group_name);
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ 1,
+ &lsa_account_name,
+ &group_rids,
+ &name_types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_OpenGroup(pipe_cli, ctx,
+ &domain_handle,
+ SAMR_GROUP_ACCESS_GET_MEMBERS,
+ group_rids.ids[0],
+ &group_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_QueryGroupMember(pipe_cli, ctx,
+ &group_handle,
+ &rid_array);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_LookupRids(pipe_cli, ctx,
+ &domain_handle,
+ rid_array->count,
+ rid_array->rids,
+ &names,
+ &member_types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ for (i=0; i < names.count; i++) {
+
+ if (member_types.ids[i] != SID_NAME_USER) {
+ continue;
+ }
+
+ status = add_GROUP_USERS_INFO_X_buffer(ctx,
+ r->in.level,
+ names.names[i].string,
+ 7,
+ r->out.buffer,
+ &entries_read);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+
+ if (r->out.entries_read) {
+ *r->out.entries_read = entries_read;
+ }
+
+ if (r->out.total_entries) {
+ *r->out.total_entries = entries_read;
+ }
+
+ werr = WERR_OK;
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&group_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &group_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupGetUsers_l(struct libnetapi_ctx *ctx,
+ struct NetGroupGetUsers *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupGetUsers);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupSetUsers_r(struct libnetapi_ctx *ctx,
+ struct NetGroupSetUsers *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct policy_handle connect_handle, domain_handle, group_handle;
+ struct lsa_String lsa_account_name;
+ struct dom_sid2 *domain_sid = NULL;
+ union samr_GroupInfo *group_info = NULL;
+ struct samr_Ids user_rids, name_types;
+ struct samr_Ids group_rids, group_types;
+ struct samr_RidTypeArray *rid_array = NULL;
+ struct lsa_String *lsa_names = NULL;
+
+ uint32_t *add_rids = NULL;
+ uint32_t *del_rids = NULL;
+ size_t num_add_rids = 0;
+ size_t num_del_rids = 0;
+
+ uint32_t *member_rids = NULL;
+ size_t num_member_rids = 0;
+
+ struct GROUP_USERS_INFO_0 *i0 = NULL;
+ struct GROUP_USERS_INFO_1 *i1 = NULL;
+
+ int i, k;
+
+ NTSTATUS status = NT_STATUS_OK;
+ WERROR werr;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+
+ if (!r->in.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ case 1:
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_account_name, r->in.group_name);
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ 1,
+ &lsa_account_name,
+ &group_rids,
+ &group_types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_OpenGroup(pipe_cli, ctx,
+ &domain_handle,
+ SAMR_GROUP_ACCESS_GET_MEMBERS |
+ SAMR_GROUP_ACCESS_ADD_MEMBER |
+ SAMR_GROUP_ACCESS_REMOVE_MEMBER |
+ SAMR_GROUP_ACCESS_LOOKUP_INFO,
+ group_rids.ids[0],
+ &group_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx,
+ &group_handle,
+ GROUPINFOATTRIBUTES,
+ &group_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ i0 = (struct GROUP_USERS_INFO_0 *)r->in.buffer;
+ break;
+ case 1:
+ i1 = (struct GROUP_USERS_INFO_1 *)r->in.buffer;
+ break;
+ }
+
+ lsa_names = talloc_array(ctx, struct lsa_String, r->in.num_entries);
+ if (!lsa_names) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ for (i=0; i < r->in.num_entries; i++) {
+
+ switch (r->in.level) {
+ case 0:
+ init_lsa_String(&lsa_names[i], i0->grui0_name);
+ i0++;
+ break;
+ case 1:
+ init_lsa_String(&lsa_names[i], i1->grui1_name);
+ i1++;
+ break;
+ }
+ }
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ r->in.num_entries,
+ lsa_names,
+ &user_rids,
+ &name_types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ member_rids = user_rids.ids;
+ num_member_rids = user_rids.count;
+
+ status = rpccli_samr_QueryGroupMember(pipe_cli, ctx,
+ &group_handle,
+ &rid_array);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ /* add list */
+
+ for (i=0; i < r->in.num_entries; i++) {
+ bool already_member = false;
+ for (k=0; k < rid_array->count; k++) {
+ if (member_rids[i] == rid_array->rids[k]) {
+ already_member = true;
+ break;
+ }
+ }
+ if (!already_member) {
+ if (!add_rid_to_array_unique(ctx,
+ member_rids[i],
+ &add_rids, &num_add_rids)) {
+ werr = WERR_GENERAL_FAILURE;
+ goto done;
+ }
+ }
+ }
+
+ /* del list */
+
+ for (k=0; k < rid_array->count; k++) {
+ bool keep_member = false;
+ for (i=0; i < r->in.num_entries; i++) {
+ if (member_rids[i] == rid_array->rids[k]) {
+ keep_member = true;
+ break;
+ }
+ }
+ if (!keep_member) {
+ if (!add_rid_to_array_unique(ctx,
+ rid_array->rids[k],
+ &del_rids, &num_del_rids)) {
+ werr = WERR_GENERAL_FAILURE;
+ goto done;
+ }
+ }
+ }
+
+ /* add list */
+
+ for (i=0; i < num_add_rids; i++) {
+ status = rpccli_samr_AddGroupMember(pipe_cli, ctx,
+ &group_handle,
+ add_rids[i],
+ 7 /* ? */);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+
+ /* del list */
+
+ for (i=0; i < num_del_rids; i++) {
+ status = rpccli_samr_DeleteGroupMember(pipe_cli, ctx,
+ &group_handle,
+ del_rids[i]);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+
+ werr = WERR_OK;
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&group_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &group_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupSetUsers_l(struct libnetapi_ctx *ctx,
+ struct NetGroupSetUsers *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupSetUsers);
+}
diff --git a/source3/lib/netapi/joindomain.c b/source3/lib/netapi/joindomain.c
new file mode 100644
index 0000000000..d15e2e733c
--- /dev/null
+++ b/source3/lib/netapi/joindomain.c
@@ -0,0 +1,501 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi Join Support
+ * Copyright (C) Guenther Deschner 2007-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#include "librpc/gen_ndr/libnetapi.h"
+#include "lib/netapi/netapi.h"
+#include "lib/netapi/netapi_private.h"
+#include "lib/netapi/libnetapi.h"
+#include "libnet/libnet.h"
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetJoinDomain_l(struct libnetapi_ctx *mem_ctx,
+ struct NetJoinDomain *r)
+{
+ struct libnet_JoinCtx *j = NULL;
+ WERROR werr;
+
+ if (!r->in.domain) {
+ return WERR_INVALID_PARAM;
+ }
+
+ werr = libnet_init_JoinCtx(mem_ctx, &j);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ j->in.domain_name = talloc_strdup(mem_ctx, r->in.domain);
+ W_ERROR_HAVE_NO_MEMORY(j->in.domain_name);
+
+ if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
+ NTSTATUS status;
+ struct netr_DsRGetDCNameInfo *info = NULL;
+ const char *dc = NULL;
+ uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
+ DS_WRITABLE_REQUIRED |
+ DS_RETURN_DNS_NAME;
+ status = dsgetdcname(mem_ctx, NULL, r->in.domain,
+ NULL, NULL, flags, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ libnetapi_set_error_string(mem_ctx,
+ "%s", get_friendly_nt_error_msg(status));
+ return ntstatus_to_werror(status);
+ }
+
+ dc = strip_hostname(info->dc_unc);
+ j->in.dc_name = talloc_strdup(mem_ctx, dc);
+ W_ERROR_HAVE_NO_MEMORY(j->in.dc_name);
+ }
+
+ if (r->in.account_ou) {
+ j->in.account_ou = talloc_strdup(mem_ctx, r->in.account_ou);
+ W_ERROR_HAVE_NO_MEMORY(j->in.account_ou);
+ }
+
+ if (r->in.account) {
+ j->in.admin_account = talloc_strdup(mem_ctx, r->in.account);
+ W_ERROR_HAVE_NO_MEMORY(j->in.admin_account);
+ }
+
+ if (r->in.password) {
+ j->in.admin_password = talloc_strdup(mem_ctx, r->in.password);
+ W_ERROR_HAVE_NO_MEMORY(j->in.admin_password);
+ }
+
+ j->in.join_flags = r->in.join_flags;
+ j->in.modify_config = true;
+ j->in.debug = true;
+
+ werr = libnet_Join(mem_ctx, j);
+ if (!W_ERROR_IS_OK(werr) && j->out.error_string) {
+ libnetapi_set_error_string(mem_ctx, "%s", j->out.error_string);
+ }
+ TALLOC_FREE(j);
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetJoinDomain_r(struct libnetapi_ctx *ctx,
+ struct NetJoinDomain *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct wkssvc_PasswordBuffer *encrypted_password = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ unsigned int old_timeout = 0;
+
+ werr = libnetapi_open_pipe(ctx, r->in.server,
+ &ndr_table_wkssvc.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ if (r->in.password) {
+ encode_wkssvc_join_password_buffer(ctx,
+ r->in.password,
+ &cli->user_session_key,
+ &encrypted_password);
+ }
+
+ old_timeout = cli_set_timeout(cli, 600000);
+
+ status = rpccli_wkssvc_NetrJoinDomain2(pipe_cli, ctx,
+ r->in.server,
+ r->in.domain,
+ r->in.account_ou,
+ r->in.account,
+ encrypted_password,
+ r->in.join_flags,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ done:
+ if (cli) {
+ if (old_timeout) {
+ cli_set_timeout(cli, old_timeout);
+ }
+ }
+
+ return werr;
+}
+/****************************************************************
+****************************************************************/
+
+WERROR NetUnjoinDomain_l(struct libnetapi_ctx *mem_ctx,
+ struct NetUnjoinDomain *r)
+{
+ struct libnet_UnjoinCtx *u = NULL;
+ struct dom_sid domain_sid;
+ const char *domain = NULL;
+ WERROR werr;
+
+ if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
+ return WERR_SETUP_NOT_JOINED;
+ }
+
+ werr = libnet_init_UnjoinCtx(mem_ctx, &u);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ if (lp_realm()) {
+ domain = lp_realm();
+ } else {
+ domain = lp_workgroup();
+ }
+
+ if (r->in.server_name) {
+ u->in.dc_name = talloc_strdup(mem_ctx, r->in.server_name);
+ W_ERROR_HAVE_NO_MEMORY(u->in.dc_name);
+ } else {
+ NTSTATUS status;
+ struct netr_DsRGetDCNameInfo *info = NULL;
+ const char *dc = NULL;
+ uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
+ DS_WRITABLE_REQUIRED |
+ DS_RETURN_DNS_NAME;
+ status = dsgetdcname(mem_ctx, NULL, domain,
+ NULL, NULL, flags, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ libnetapi_set_error_string(mem_ctx,
+ "failed to find DC for domain %s: %s",
+ domain,
+ get_friendly_nt_error_msg(status));
+ return ntstatus_to_werror(status);
+ }
+
+ dc = strip_hostname(info->dc_unc);
+ u->in.dc_name = talloc_strdup(mem_ctx, dc);
+ W_ERROR_HAVE_NO_MEMORY(u->in.dc_name);
+
+ u->in.domain_name = domain;
+ }
+
+ if (r->in.account) {
+ u->in.admin_account = talloc_strdup(mem_ctx, r->in.account);
+ W_ERROR_HAVE_NO_MEMORY(u->in.admin_account);
+ }
+
+ if (r->in.password) {
+ u->in.admin_password = talloc_strdup(mem_ctx, r->in.password);
+ W_ERROR_HAVE_NO_MEMORY(u->in.admin_password);
+ }
+
+ u->in.domain_name = domain;
+ u->in.unjoin_flags = r->in.unjoin_flags;
+ u->in.modify_config = true;
+ u->in.debug = true;
+
+ u->in.domain_sid = &domain_sid;
+
+ werr = libnet_Unjoin(mem_ctx, u);
+ if (!W_ERROR_IS_OK(werr) && u->out.error_string) {
+ libnetapi_set_error_string(mem_ctx, "%s", u->out.error_string);
+ }
+ TALLOC_FREE(u);
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUnjoinDomain_r(struct libnetapi_ctx *ctx,
+ struct NetUnjoinDomain *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct wkssvc_PasswordBuffer *encrypted_password = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ unsigned int old_timeout = 0;
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_wkssvc.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ if (r->in.password) {
+ encode_wkssvc_join_password_buffer(ctx,
+ r->in.password,
+ &cli->user_session_key,
+ &encrypted_password);
+ }
+
+ old_timeout = cli_set_timeout(cli, 60000);
+
+ status = rpccli_wkssvc_NetrUnjoinDomain2(pipe_cli, ctx,
+ r->in.server_name,
+ r->in.account,
+ encrypted_password,
+ r->in.unjoin_flags,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ done:
+ if (cli) {
+ if (old_timeout) {
+ cli_set_timeout(cli, old_timeout);
+ }
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGetJoinInformation_r(struct libnetapi_ctx *ctx,
+ struct NetGetJoinInformation *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ const char *buffer = NULL;
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_wkssvc.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = rpccli_wkssvc_NetrGetJoinInformation(pipe_cli, ctx,
+ r->in.server_name,
+ &buffer,
+ (enum wkssvc_NetJoinStatus *)r->out.name_type,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ *r->out.name_buffer = talloc_strdup(ctx, buffer);
+ W_ERROR_HAVE_NO_MEMORY(*r->out.name_buffer);
+
+ done:
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGetJoinInformation_l(struct libnetapi_ctx *ctx,
+ struct NetGetJoinInformation *r)
+{
+ if ((lp_security() == SEC_ADS) && lp_realm()) {
+ *r->out.name_buffer = talloc_strdup(ctx, lp_realm());
+ } else {
+ *r->out.name_buffer = talloc_strdup(ctx, lp_workgroup());
+ }
+ if (!*r->out.name_buffer) {
+ return WERR_NOMEM;
+ }
+
+ switch (lp_server_role()) {
+ case ROLE_DOMAIN_MEMBER:
+ case ROLE_DOMAIN_PDC:
+ case ROLE_DOMAIN_BDC:
+ *r->out.name_type = NetSetupDomainName;
+ break;
+ case ROLE_STANDALONE:
+ default:
+ *r->out.name_type = NetSetupWorkgroupName;
+ break;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGetJoinableOUs_l(struct libnetapi_ctx *ctx,
+ struct NetGetJoinableOUs *r)
+{
+#ifdef WITH_ADS
+ NTSTATUS status;
+ ADS_STATUS ads_status;
+ ADS_STRUCT *ads = NULL;
+ struct netr_DsRGetDCNameInfo *info = NULL;
+ const char *dc = NULL;
+ uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
+ DS_RETURN_DNS_NAME;
+
+ status = dsgetdcname(ctx, NULL, r->in.domain,
+ NULL, NULL, flags, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ libnetapi_set_error_string(ctx, "%s",
+ get_friendly_nt_error_msg(status));
+ return ntstatus_to_werror(status);
+ }
+
+ dc = strip_hostname(info->dc_unc);
+
+ ads = ads_init(info->domain_name, info->domain_name, dc);
+ if (!ads) {
+ return WERR_GENERAL_FAILURE;
+ }
+
+ SAFE_FREE(ads->auth.user_name);
+ if (r->in.account) {
+ ads->auth.user_name = SMB_STRDUP(r->in.account);
+ } else if (ctx->username) {
+ ads->auth.user_name = SMB_STRDUP(ctx->username);
+ }
+
+ SAFE_FREE(ads->auth.password);
+ if (r->in.password) {
+ ads->auth.password = SMB_STRDUP(r->in.password);
+ } else if (ctx->password) {
+ ads->auth.password = SMB_STRDUP(ctx->password);
+ }
+
+ ads_status = ads_connect_user_creds(ads);
+ if (!ADS_ERR_OK(ads_status)) {
+ ads_destroy(&ads);
+ return WERR_DEFAULT_JOIN_REQUIRED;
+ }
+
+ ads_status = ads_get_joinable_ous(ads, ctx,
+ (char ***)r->out.ous,
+ (size_t *)r->out.ou_count);
+ if (!ADS_ERR_OK(ads_status)) {
+ ads_destroy(&ads);
+ return WERR_DEFAULT_JOIN_REQUIRED;
+ }
+
+ ads_destroy(&ads);
+ return WERR_OK;
+#else
+ return WERR_NOT_SUPPORTED;
+#endif
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGetJoinableOUs_r(struct libnetapi_ctx *ctx,
+ struct NetGetJoinableOUs *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct wkssvc_PasswordBuffer *encrypted_password = NULL;
+ NTSTATUS status;
+ WERROR werr;
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_wkssvc.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ if (r->in.password) {
+ encode_wkssvc_join_password_buffer(ctx,
+ r->in.password,
+ &cli->user_session_key,
+ &encrypted_password);
+ }
+
+ status = rpccli_wkssvc_NetrGetJoinableOus2(pipe_cli, ctx,
+ r->in.server_name,
+ r->in.domain,
+ r->in.account,
+ encrypted_password,
+ r->out.ou_count,
+ r->out.ous,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ done:
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetRenameMachineInDomain_r(struct libnetapi_ctx *ctx,
+ struct NetRenameMachineInDomain *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct wkssvc_PasswordBuffer *encrypted_password = NULL;
+ NTSTATUS status;
+ WERROR werr;
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_wkssvc.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ if (r->in.password) {
+ encode_wkssvc_join_password_buffer(ctx,
+ r->in.password,
+ &cli->user_session_key,
+ &encrypted_password);
+ }
+
+ status = rpccli_wkssvc_NetrRenameMachineInDomain2(pipe_cli, ctx,
+ r->in.server_name,
+ r->in.new_machine_name,
+ r->in.account,
+ encrypted_password,
+ r->in.rename_options,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ done:
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetRenameMachineInDomain_l(struct libnetapi_ctx *ctx,
+ struct NetRenameMachineInDomain *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetRenameMachineInDomain);
+}
diff --git a/source3/lib/netapi/libnetapi.c b/source3/lib/netapi/libnetapi.c
new file mode 100644
index 0000000000..043190a1f9
--- /dev/null
+++ b/source3/lib/netapi/libnetapi.c
@@ -0,0 +1,2355 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi Support
+ * Copyright (C) Guenther Deschner 2007-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/libnetapi.h"
+#include "lib/netapi/netapi.h"
+#include "lib/netapi/netapi_private.h"
+#include "lib/netapi/libnetapi.h"
+#include "librpc/gen_ndr/ndr_libnetapi.h"
+
+/****************************************************************
+ NetJoinDomain
+****************************************************************/
+
+NET_API_STATUS NetJoinDomain(const char * server /* [in] [unique] */,
+ const char * domain /* [in] [ref] */,
+ const char * account_ou /* [in] [unique] */,
+ const char * account /* [in] [unique] */,
+ const char * password /* [in] [unique] */,
+ uint32_t join_flags /* [in] */)
+{
+ struct NetJoinDomain r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server = server;
+ r.in.domain = domain;
+ r.in.account_ou = account_ou;
+ r.in.account = account;
+ r.in.password = password;
+ r.in.join_flags = join_flags;
+
+ /* Out parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetJoinDomain, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server)) {
+ werr = NetJoinDomain_l(ctx, &r);
+ } else {
+ werr = NetJoinDomain_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetJoinDomain, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetUnjoinDomain
+****************************************************************/
+
+NET_API_STATUS NetUnjoinDomain(const char * server_name /* [in] [unique] */,
+ const char * account /* [in] [unique] */,
+ const char * password /* [in] [unique] */,
+ uint32_t unjoin_flags /* [in] */)
+{
+ struct NetUnjoinDomain r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.account = account;
+ r.in.password = password;
+ r.in.unjoin_flags = unjoin_flags;
+
+ /* Out parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetUnjoinDomain, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetUnjoinDomain_l(ctx, &r);
+ } else {
+ werr = NetUnjoinDomain_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetUnjoinDomain, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetGetJoinInformation
+****************************************************************/
+
+NET_API_STATUS NetGetJoinInformation(const char * server_name /* [in] [unique] */,
+ const char * *name_buffer /* [out] [ref] */,
+ uint16_t *name_type /* [out] [ref] */)
+{
+ struct NetGetJoinInformation r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+
+ /* Out parameters */
+ r.out.name_buffer = name_buffer;
+ r.out.name_type = name_type;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetGetJoinInformation, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetGetJoinInformation_l(ctx, &r);
+ } else {
+ werr = NetGetJoinInformation_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetGetJoinInformation, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetGetJoinableOUs
+****************************************************************/
+
+NET_API_STATUS NetGetJoinableOUs(const char * server_name /* [in] [unique] */,
+ const char * domain /* [in] [ref] */,
+ const char * account /* [in] [unique] */,
+ const char * password /* [in] [unique] */,
+ uint32_t *ou_count /* [out] [ref] */,
+ const char * **ous /* [out] [ref] */)
+{
+ struct NetGetJoinableOUs r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.domain = domain;
+ r.in.account = account;
+ r.in.password = password;
+
+ /* Out parameters */
+ r.out.ou_count = ou_count;
+ r.out.ous = ous;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetGetJoinableOUs, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetGetJoinableOUs_l(ctx, &r);
+ } else {
+ werr = NetGetJoinableOUs_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetGetJoinableOUs, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetRenameMachineInDomain
+****************************************************************/
+
+NET_API_STATUS NetRenameMachineInDomain(const char * server_name /* [in] */,
+ const char * new_machine_name /* [in] */,
+ const char * account /* [in] */,
+ const char * password /* [in] */,
+ uint32_t rename_options /* [in] */)
+{
+ struct NetRenameMachineInDomain r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.new_machine_name = new_machine_name;
+ r.in.account = account;
+ r.in.password = password;
+ r.in.rename_options = rename_options;
+
+ /* Out parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetRenameMachineInDomain, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetRenameMachineInDomain_l(ctx, &r);
+ } else {
+ werr = NetRenameMachineInDomain_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetRenameMachineInDomain, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetServerGetInfo
+****************************************************************/
+
+NET_API_STATUS NetServerGetInfo(const char * server_name /* [in] [unique] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */)
+{
+ struct NetServerGetInfo r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetServerGetInfo, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetServerGetInfo_l(ctx, &r);
+ } else {
+ werr = NetServerGetInfo_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetServerGetInfo, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetServerSetInfo
+****************************************************************/
+
+NET_API_STATUS NetServerSetInfo(const char * server_name /* [in] [unique] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_error /* [out] [ref] */)
+{
+ struct NetServerSetInfo r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+ r.in.buffer = buffer;
+
+ /* Out parameters */
+ r.out.parm_error = parm_error;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetServerSetInfo, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetServerSetInfo_l(ctx, &r);
+ } else {
+ werr = NetServerSetInfo_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetServerSetInfo, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetGetDCName
+****************************************************************/
+
+NET_API_STATUS NetGetDCName(const char * server_name /* [in] [unique] */,
+ const char * domain_name /* [in] [unique] */,
+ uint8_t **buffer /* [out] [ref] */)
+{
+ struct NetGetDCName r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.domain_name = domain_name;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetGetDCName, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetGetDCName_l(ctx, &r);
+ } else {
+ werr = NetGetDCName_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetGetDCName, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetGetAnyDCName
+****************************************************************/
+
+NET_API_STATUS NetGetAnyDCName(const char * server_name /* [in] [unique] */,
+ const char * domain_name /* [in] [unique] */,
+ uint8_t **buffer /* [out] [ref] */)
+{
+ struct NetGetAnyDCName r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.domain_name = domain_name;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetGetAnyDCName, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetGetAnyDCName_l(ctx, &r);
+ } else {
+ werr = NetGetAnyDCName_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetGetAnyDCName, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ DsGetDcName
+****************************************************************/
+
+NET_API_STATUS DsGetDcName(const char * server_name /* [in] [unique] */,
+ const char * domain_name /* [in] [ref] */,
+ struct GUID *domain_guid /* [in] [unique] */,
+ const char * site_name /* [in] [unique] */,
+ uint32_t flags /* [in] */,
+ struct DOMAIN_CONTROLLER_INFO **dc_info /* [out] [ref] */)
+{
+ struct DsGetDcName r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.domain_name = domain_name;
+ r.in.domain_guid = domain_guid;
+ r.in.site_name = site_name;
+ r.in.flags = flags;
+
+ /* Out parameters */
+ r.out.dc_info = dc_info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(DsGetDcName, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = DsGetDcName_l(ctx, &r);
+ } else {
+ werr = DsGetDcName_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(DsGetDcName, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetUserAdd
+****************************************************************/
+
+NET_API_STATUS NetUserAdd(const char * server_name /* [in] [unique] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_error /* [out] [ref] */)
+{
+ struct NetUserAdd r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+ r.in.buffer = buffer;
+
+ /* Out parameters */
+ r.out.parm_error = parm_error;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetUserAdd, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetUserAdd_l(ctx, &r);
+ } else {
+ werr = NetUserAdd_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetUserAdd, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetUserDel
+****************************************************************/
+
+NET_API_STATUS NetUserDel(const char * server_name /* [in] [unique] */,
+ const char * user_name /* [in] [ref] */)
+{
+ struct NetUserDel r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.user_name = user_name;
+
+ /* Out parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetUserDel, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetUserDel_l(ctx, &r);
+ } else {
+ werr = NetUserDel_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetUserDel, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetUserEnum
+****************************************************************/
+
+NET_API_STATUS NetUserEnum(const char * server_name /* [in] [unique] */,
+ uint32_t level /* [in] */,
+ uint32_t filter /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */)
+{
+ struct NetUserEnum r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+ r.in.filter = filter;
+ r.in.prefmaxlen = prefmaxlen;
+ r.in.resume_handle = resume_handle;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+ r.out.entries_read = entries_read;
+ r.out.total_entries = total_entries;
+ r.out.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetUserEnum, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetUserEnum_l(ctx, &r);
+ } else {
+ werr = NetUserEnum_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetUserEnum, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetUserChangePassword
+****************************************************************/
+
+NET_API_STATUS NetUserChangePassword(const char * domain_name /* [in] */,
+ const char * user_name /* [in] */,
+ const char * old_password /* [in] */,
+ const char * new_password /* [in] */)
+{
+ struct NetUserChangePassword r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.domain_name = domain_name;
+ r.in.user_name = user_name;
+ r.in.old_password = old_password;
+ r.in.new_password = new_password;
+
+ /* Out parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetUserChangePassword, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(domain_name)) {
+ werr = NetUserChangePassword_l(ctx, &r);
+ } else {
+ werr = NetUserChangePassword_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetUserChangePassword, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetUserGetInfo
+****************************************************************/
+
+NET_API_STATUS NetUserGetInfo(const char * server_name /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */)
+{
+ struct NetUserGetInfo r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.user_name = user_name;
+ r.in.level = level;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetUserGetInfo, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetUserGetInfo_l(ctx, &r);
+ } else {
+ werr = NetUserGetInfo_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetUserGetInfo, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetUserSetInfo
+****************************************************************/
+
+NET_API_STATUS NetUserSetInfo(const char * server_name /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */)
+{
+ struct NetUserSetInfo r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.user_name = user_name;
+ r.in.level = level;
+ r.in.buffer = buffer;
+
+ /* Out parameters */
+ r.out.parm_err = parm_err;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetUserSetInfo, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetUserSetInfo_l(ctx, &r);
+ } else {
+ werr = NetUserSetInfo_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetUserSetInfo, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetUserGetGroups
+****************************************************************/
+
+NET_API_STATUS NetUserGetGroups(const char * server_name /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */)
+{
+ struct NetUserGetGroups r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.user_name = user_name;
+ r.in.level = level;
+ r.in.prefmaxlen = prefmaxlen;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+ r.out.entries_read = entries_read;
+ r.out.total_entries = total_entries;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetUserGetGroups, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetUserGetGroups_l(ctx, &r);
+ } else {
+ werr = NetUserGetGroups_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetUserGetGroups, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetUserSetGroups
+****************************************************************/
+
+NET_API_STATUS NetUserSetGroups(const char * server_name /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t num_entries /* [in] */)
+{
+ struct NetUserSetGroups r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.user_name = user_name;
+ r.in.level = level;
+ r.in.buffer = buffer;
+ r.in.num_entries = num_entries;
+
+ /* Out parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetUserSetGroups, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetUserSetGroups_l(ctx, &r);
+ } else {
+ werr = NetUserSetGroups_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetUserSetGroups, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetUserGetLocalGroups
+****************************************************************/
+
+NET_API_STATUS NetUserGetLocalGroups(const char * server_name /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint32_t flags /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */)
+{
+ struct NetUserGetLocalGroups r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.user_name = user_name;
+ r.in.level = level;
+ r.in.flags = flags;
+ r.in.prefmaxlen = prefmaxlen;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+ r.out.entries_read = entries_read;
+ r.out.total_entries = total_entries;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetUserGetLocalGroups, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetUserGetLocalGroups_l(ctx, &r);
+ } else {
+ werr = NetUserGetLocalGroups_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetUserGetLocalGroups, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetUserModalsGet
+****************************************************************/
+
+NET_API_STATUS NetUserModalsGet(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */)
+{
+ struct NetUserModalsGet r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetUserModalsGet, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetUserModalsGet_l(ctx, &r);
+ } else {
+ werr = NetUserModalsGet_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetUserModalsGet, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetUserModalsSet
+****************************************************************/
+
+NET_API_STATUS NetUserModalsSet(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */)
+{
+ struct NetUserModalsSet r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+ r.in.buffer = buffer;
+
+ /* Out parameters */
+ r.out.parm_err = parm_err;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetUserModalsSet, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetUserModalsSet_l(ctx, &r);
+ } else {
+ werr = NetUserModalsSet_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetUserModalsSet, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetQueryDisplayInformation
+****************************************************************/
+
+NET_API_STATUS NetQueryDisplayInformation(const char * server_name /* [in] [unique] */,
+ uint32_t level /* [in] */,
+ uint32_t idx /* [in] */,
+ uint32_t entries_requested /* [in] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ void **buffer /* [out] [noprint,ref] */)
+{
+ struct NetQueryDisplayInformation r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+ r.in.idx = idx;
+ r.in.entries_requested = entries_requested;
+ r.in.prefmaxlen = prefmaxlen;
+
+ /* Out parameters */
+ r.out.entries_read = entries_read;
+ r.out.buffer = buffer;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetQueryDisplayInformation, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetQueryDisplayInformation_l(ctx, &r);
+ } else {
+ werr = NetQueryDisplayInformation_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetQueryDisplayInformation, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetGroupAdd
+****************************************************************/
+
+NET_API_STATUS NetGroupAdd(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */)
+{
+ struct NetGroupAdd r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+ r.in.buffer = buffer;
+
+ /* Out parameters */
+ r.out.parm_err = parm_err;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetGroupAdd, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetGroupAdd_l(ctx, &r);
+ } else {
+ werr = NetGroupAdd_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetGroupAdd, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetGroupDel
+****************************************************************/
+
+NET_API_STATUS NetGroupDel(const char * server_name /* [in] */,
+ const char * group_name /* [in] */)
+{
+ struct NetGroupDel r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.group_name = group_name;
+
+ /* Out parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetGroupDel, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetGroupDel_l(ctx, &r);
+ } else {
+ werr = NetGroupDel_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetGroupDel, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetGroupEnum
+****************************************************************/
+
+NET_API_STATUS NetGroupEnum(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */)
+{
+ struct NetGroupEnum r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+ r.in.prefmaxlen = prefmaxlen;
+ r.in.resume_handle = resume_handle;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+ r.out.entries_read = entries_read;
+ r.out.total_entries = total_entries;
+ r.out.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetGroupEnum, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetGroupEnum_l(ctx, &r);
+ } else {
+ werr = NetGroupEnum_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetGroupEnum, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetGroupSetInfo
+****************************************************************/
+
+NET_API_STATUS NetGroupSetInfo(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */)
+{
+ struct NetGroupSetInfo r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.group_name = group_name;
+ r.in.level = level;
+ r.in.buffer = buffer;
+
+ /* Out parameters */
+ r.out.parm_err = parm_err;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetGroupSetInfo, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetGroupSetInfo_l(ctx, &r);
+ } else {
+ werr = NetGroupSetInfo_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetGroupSetInfo, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetGroupGetInfo
+****************************************************************/
+
+NET_API_STATUS NetGroupGetInfo(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */)
+{
+ struct NetGroupGetInfo r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.group_name = group_name;
+ r.in.level = level;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetGroupGetInfo, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetGroupGetInfo_l(ctx, &r);
+ } else {
+ werr = NetGroupGetInfo_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetGroupGetInfo, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetGroupAddUser
+****************************************************************/
+
+NET_API_STATUS NetGroupAddUser(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ const char * user_name /* [in] */)
+{
+ struct NetGroupAddUser r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.group_name = group_name;
+ r.in.user_name = user_name;
+
+ /* Out parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetGroupAddUser, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetGroupAddUser_l(ctx, &r);
+ } else {
+ werr = NetGroupAddUser_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetGroupAddUser, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetGroupDelUser
+****************************************************************/
+
+NET_API_STATUS NetGroupDelUser(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ const char * user_name /* [in] */)
+{
+ struct NetGroupDelUser r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.group_name = group_name;
+ r.in.user_name = user_name;
+
+ /* Out parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetGroupDelUser, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetGroupDelUser_l(ctx, &r);
+ } else {
+ werr = NetGroupDelUser_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetGroupDelUser, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetGroupGetUsers
+****************************************************************/
+
+NET_API_STATUS NetGroupGetUsers(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */)
+{
+ struct NetGroupGetUsers r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.group_name = group_name;
+ r.in.level = level;
+ r.in.prefmaxlen = prefmaxlen;
+ r.in.resume_handle = resume_handle;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+ r.out.entries_read = entries_read;
+ r.out.total_entries = total_entries;
+ r.out.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetGroupGetUsers, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetGroupGetUsers_l(ctx, &r);
+ } else {
+ werr = NetGroupGetUsers_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetGroupGetUsers, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetGroupSetUsers
+****************************************************************/
+
+NET_API_STATUS NetGroupSetUsers(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t num_entries /* [in] */)
+{
+ struct NetGroupSetUsers r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.group_name = group_name;
+ r.in.level = level;
+ r.in.buffer = buffer;
+ r.in.num_entries = num_entries;
+
+ /* Out parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetGroupSetUsers, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetGroupSetUsers_l(ctx, &r);
+ } else {
+ werr = NetGroupSetUsers_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetGroupSetUsers, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetLocalGroupAdd
+****************************************************************/
+
+NET_API_STATUS NetLocalGroupAdd(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */)
+{
+ struct NetLocalGroupAdd r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+ r.in.buffer = buffer;
+
+ /* Out parameters */
+ r.out.parm_err = parm_err;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetLocalGroupAdd, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetLocalGroupAdd_l(ctx, &r);
+ } else {
+ werr = NetLocalGroupAdd_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetLocalGroupAdd, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetLocalGroupDel
+****************************************************************/
+
+NET_API_STATUS NetLocalGroupDel(const char * server_name /* [in] */,
+ const char * group_name /* [in] */)
+{
+ struct NetLocalGroupDel r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.group_name = group_name;
+
+ /* Out parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetLocalGroupDel, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetLocalGroupDel_l(ctx, &r);
+ } else {
+ werr = NetLocalGroupDel_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetLocalGroupDel, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetLocalGroupGetInfo
+****************************************************************/
+
+NET_API_STATUS NetLocalGroupGetInfo(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */)
+{
+ struct NetLocalGroupGetInfo r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.group_name = group_name;
+ r.in.level = level;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetLocalGroupGetInfo, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetLocalGroupGetInfo_l(ctx, &r);
+ } else {
+ werr = NetLocalGroupGetInfo_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetLocalGroupGetInfo, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetLocalGroupSetInfo
+****************************************************************/
+
+NET_API_STATUS NetLocalGroupSetInfo(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */)
+{
+ struct NetLocalGroupSetInfo r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.group_name = group_name;
+ r.in.level = level;
+ r.in.buffer = buffer;
+
+ /* Out parameters */
+ r.out.parm_err = parm_err;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetLocalGroupSetInfo, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetLocalGroupSetInfo_l(ctx, &r);
+ } else {
+ werr = NetLocalGroupSetInfo_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetLocalGroupSetInfo, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetLocalGroupEnum
+****************************************************************/
+
+NET_API_STATUS NetLocalGroupEnum(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */)
+{
+ struct NetLocalGroupEnum r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+ r.in.prefmaxlen = prefmaxlen;
+ r.in.resume_handle = resume_handle;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+ r.out.entries_read = entries_read;
+ r.out.total_entries = total_entries;
+ r.out.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetLocalGroupEnum, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetLocalGroupEnum_l(ctx, &r);
+ } else {
+ werr = NetLocalGroupEnum_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetLocalGroupEnum, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetLocalGroupAddMembers
+****************************************************************/
+
+NET_API_STATUS NetLocalGroupAddMembers(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t total_entries /* [in] */)
+{
+ struct NetLocalGroupAddMembers r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.group_name = group_name;
+ r.in.level = level;
+ r.in.buffer = buffer;
+ r.in.total_entries = total_entries;
+
+ /* Out parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetLocalGroupAddMembers, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetLocalGroupAddMembers_l(ctx, &r);
+ } else {
+ werr = NetLocalGroupAddMembers_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetLocalGroupAddMembers, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetLocalGroupDelMembers
+****************************************************************/
+
+NET_API_STATUS NetLocalGroupDelMembers(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t total_entries /* [in] */)
+{
+ struct NetLocalGroupDelMembers r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.group_name = group_name;
+ r.in.level = level;
+ r.in.buffer = buffer;
+ r.in.total_entries = total_entries;
+
+ /* Out parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetLocalGroupDelMembers, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetLocalGroupDelMembers_l(ctx, &r);
+ } else {
+ werr = NetLocalGroupDelMembers_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetLocalGroupDelMembers, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetLocalGroupGetMembers
+****************************************************************/
+
+NET_API_STATUS NetLocalGroupGetMembers(const char * server_name /* [in] */,
+ const char * local_group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */)
+{
+ struct NetLocalGroupGetMembers r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.local_group_name = local_group_name;
+ r.in.level = level;
+ r.in.prefmaxlen = prefmaxlen;
+ r.in.resume_handle = resume_handle;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+ r.out.entries_read = entries_read;
+ r.out.total_entries = total_entries;
+ r.out.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetLocalGroupGetMembers, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetLocalGroupGetMembers_l(ctx, &r);
+ } else {
+ werr = NetLocalGroupGetMembers_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetLocalGroupGetMembers, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetLocalGroupSetMembers
+****************************************************************/
+
+NET_API_STATUS NetLocalGroupSetMembers(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t total_entries /* [in] */)
+{
+ struct NetLocalGroupSetMembers r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.group_name = group_name;
+ r.in.level = level;
+ r.in.buffer = buffer;
+ r.in.total_entries = total_entries;
+
+ /* Out parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetLocalGroupSetMembers, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetLocalGroupSetMembers_l(ctx, &r);
+ } else {
+ werr = NetLocalGroupSetMembers_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetLocalGroupSetMembers, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetRemoteTOD
+****************************************************************/
+
+NET_API_STATUS NetRemoteTOD(const char * server_name /* [in] */,
+ uint8_t **buffer /* [out] [ref] */)
+{
+ struct NetRemoteTOD r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetRemoteTOD, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetRemoteTOD_l(ctx, &r);
+ } else {
+ werr = NetRemoteTOD_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetRemoteTOD, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetShareAdd
+****************************************************************/
+
+NET_API_STATUS NetShareAdd(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */)
+{
+ struct NetShareAdd r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+ r.in.buffer = buffer;
+
+ /* Out parameters */
+ r.out.parm_err = parm_err;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetShareAdd, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetShareAdd_l(ctx, &r);
+ } else {
+ werr = NetShareAdd_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetShareAdd, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetShareDel
+****************************************************************/
+
+NET_API_STATUS NetShareDel(const char * server_name /* [in] */,
+ const char * net_name /* [in] */,
+ uint32_t reserved /* [in] */)
+{
+ struct NetShareDel r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.net_name = net_name;
+ r.in.reserved = reserved;
+
+ /* Out parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetShareDel, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetShareDel_l(ctx, &r);
+ } else {
+ werr = NetShareDel_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetShareDel, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetShareEnum
+****************************************************************/
+
+NET_API_STATUS NetShareEnum(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */)
+{
+ struct NetShareEnum r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+ r.in.prefmaxlen = prefmaxlen;
+ r.in.resume_handle = resume_handle;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+ r.out.entries_read = entries_read;
+ r.out.total_entries = total_entries;
+ r.out.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetShareEnum, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetShareEnum_l(ctx, &r);
+ } else {
+ werr = NetShareEnum_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetShareEnum, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetShareGetInfo
+****************************************************************/
+
+NET_API_STATUS NetShareGetInfo(const char * server_name /* [in] */,
+ const char * net_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */)
+{
+ struct NetShareGetInfo r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.net_name = net_name;
+ r.in.level = level;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetShareGetInfo, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetShareGetInfo_l(ctx, &r);
+ } else {
+ werr = NetShareGetInfo_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetShareGetInfo, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetShareSetInfo
+****************************************************************/
+
+NET_API_STATUS NetShareSetInfo(const char * server_name /* [in] */,
+ const char * net_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */)
+{
+ struct NetShareSetInfo r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.net_name = net_name;
+ r.in.level = level;
+ r.in.buffer = buffer;
+
+ /* Out parameters */
+ r.out.parm_err = parm_err;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetShareSetInfo, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetShareSetInfo_l(ctx, &r);
+ } else {
+ werr = NetShareSetInfo_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetShareSetInfo, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetFileClose
+****************************************************************/
+
+NET_API_STATUS NetFileClose(const char * server_name /* [in] */,
+ uint32_t fileid /* [in] */)
+{
+ struct NetFileClose r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.fileid = fileid;
+
+ /* Out parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetFileClose, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetFileClose_l(ctx, &r);
+ } else {
+ werr = NetFileClose_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetFileClose, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetFileGetInfo
+****************************************************************/
+
+NET_API_STATUS NetFileGetInfo(const char * server_name /* [in] */,
+ uint32_t fileid /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */)
+{
+ struct NetFileGetInfo r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.fileid = fileid;
+ r.in.level = level;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetFileGetInfo, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetFileGetInfo_l(ctx, &r);
+ } else {
+ werr = NetFileGetInfo_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetFileGetInfo, &r);
+ }
+
+ return r.out.result;
+}
+
+/****************************************************************
+ NetFileEnum
+****************************************************************/
+
+NET_API_STATUS NetFileEnum(const char * server_name /* [in] */,
+ const char * base_path /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */)
+{
+ struct NetFileEnum r;
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.base_path = base_path;
+ r.in.user_name = user_name;
+ r.in.level = level;
+ r.in.prefmaxlen = prefmaxlen;
+ r.in.resume_handle = resume_handle;
+
+ /* Out parameters */
+ r.out.buffer = buffer;
+ r.out.entries_read = entries_read;
+ r.out.total_entries = total_entries;
+ r.out.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(NetFileEnum, &r);
+ }
+
+ if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+ werr = NetFileEnum_l(ctx, &r);
+ } else {
+ werr = NetFileEnum_r(ctx, &r);
+ }
+
+ r.out.result = W_ERROR_V(werr);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(NetFileEnum, &r);
+ }
+
+ return r.out.result;
+}
+
diff --git a/source3/lib/netapi/libnetapi.h b/source3/lib/netapi/libnetapi.h
new file mode 100644
index 0000000000..1b84b75f94
--- /dev/null
+++ b/source3/lib/netapi/libnetapi.h
@@ -0,0 +1,429 @@
+#ifndef __LIBNETAPI_LIBNETAPI__
+#define __LIBNETAPI_LIBNETAPI__
+NET_API_STATUS NetJoinDomain(const char * server /* [in] [unique] */,
+ const char * domain /* [in] [ref] */,
+ const char * account_ou /* [in] [unique] */,
+ const char * account /* [in] [unique] */,
+ const char * password /* [in] [unique] */,
+ uint32_t join_flags /* [in] */);
+WERROR NetJoinDomain_r(struct libnetapi_ctx *ctx,
+ struct NetJoinDomain *r);
+WERROR NetJoinDomain_l(struct libnetapi_ctx *ctx,
+ struct NetJoinDomain *r);
+NET_API_STATUS NetUnjoinDomain(const char * server_name /* [in] [unique] */,
+ const char * account /* [in] [unique] */,
+ const char * password /* [in] [unique] */,
+ uint32_t unjoin_flags /* [in] */);
+WERROR NetUnjoinDomain_r(struct libnetapi_ctx *ctx,
+ struct NetUnjoinDomain *r);
+WERROR NetUnjoinDomain_l(struct libnetapi_ctx *ctx,
+ struct NetUnjoinDomain *r);
+NET_API_STATUS NetGetJoinInformation(const char * server_name /* [in] [unique] */,
+ const char * *name_buffer /* [out] [ref] */,
+ uint16_t *name_type /* [out] [ref] */);
+WERROR NetGetJoinInformation_r(struct libnetapi_ctx *ctx,
+ struct NetGetJoinInformation *r);
+WERROR NetGetJoinInformation_l(struct libnetapi_ctx *ctx,
+ struct NetGetJoinInformation *r);
+NET_API_STATUS NetGetJoinableOUs(const char * server_name /* [in] [unique] */,
+ const char * domain /* [in] [ref] */,
+ const char * account /* [in] [unique] */,
+ const char * password /* [in] [unique] */,
+ uint32_t *ou_count /* [out] [ref] */,
+ const char * **ous /* [out] [ref] */);
+WERROR NetGetJoinableOUs_r(struct libnetapi_ctx *ctx,
+ struct NetGetJoinableOUs *r);
+WERROR NetGetJoinableOUs_l(struct libnetapi_ctx *ctx,
+ struct NetGetJoinableOUs *r);
+NET_API_STATUS NetRenameMachineInDomain(const char * server_name /* [in] */,
+ const char * new_machine_name /* [in] */,
+ const char * account /* [in] */,
+ const char * password /* [in] */,
+ uint32_t rename_options /* [in] */);
+WERROR NetRenameMachineInDomain_r(struct libnetapi_ctx *ctx,
+ struct NetRenameMachineInDomain *r);
+WERROR NetRenameMachineInDomain_l(struct libnetapi_ctx *ctx,
+ struct NetRenameMachineInDomain *r);
+NET_API_STATUS NetServerGetInfo(const char * server_name /* [in] [unique] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */);
+WERROR NetServerGetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetServerGetInfo *r);
+WERROR NetServerGetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetServerGetInfo *r);
+NET_API_STATUS NetServerSetInfo(const char * server_name /* [in] [unique] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_error /* [out] [ref] */);
+WERROR NetServerSetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetServerSetInfo *r);
+WERROR NetServerSetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetServerSetInfo *r);
+NET_API_STATUS NetGetDCName(const char * server_name /* [in] [unique] */,
+ const char * domain_name /* [in] [unique] */,
+ uint8_t **buffer /* [out] [ref] */);
+WERROR NetGetDCName_r(struct libnetapi_ctx *ctx,
+ struct NetGetDCName *r);
+WERROR NetGetDCName_l(struct libnetapi_ctx *ctx,
+ struct NetGetDCName *r);
+NET_API_STATUS NetGetAnyDCName(const char * server_name /* [in] [unique] */,
+ const char * domain_name /* [in] [unique] */,
+ uint8_t **buffer /* [out] [ref] */);
+WERROR NetGetAnyDCName_r(struct libnetapi_ctx *ctx,
+ struct NetGetAnyDCName *r);
+WERROR NetGetAnyDCName_l(struct libnetapi_ctx *ctx,
+ struct NetGetAnyDCName *r);
+NET_API_STATUS DsGetDcName(const char * server_name /* [in] [unique] */,
+ const char * domain_name /* [in] [ref] */,
+ struct GUID *domain_guid /* [in] [unique] */,
+ const char * site_name /* [in] [unique] */,
+ uint32_t flags /* [in] */,
+ struct DOMAIN_CONTROLLER_INFO **dc_info /* [out] [ref] */);
+WERROR DsGetDcName_r(struct libnetapi_ctx *ctx,
+ struct DsGetDcName *r);
+WERROR DsGetDcName_l(struct libnetapi_ctx *ctx,
+ struct DsGetDcName *r);
+NET_API_STATUS NetUserAdd(const char * server_name /* [in] [unique] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_error /* [out] [ref] */);
+WERROR NetUserAdd_r(struct libnetapi_ctx *ctx,
+ struct NetUserAdd *r);
+WERROR NetUserAdd_l(struct libnetapi_ctx *ctx,
+ struct NetUserAdd *r);
+NET_API_STATUS NetUserDel(const char * server_name /* [in] [unique] */,
+ const char * user_name /* [in] [ref] */);
+WERROR NetUserDel_r(struct libnetapi_ctx *ctx,
+ struct NetUserDel *r);
+WERROR NetUserDel_l(struct libnetapi_ctx *ctx,
+ struct NetUserDel *r);
+NET_API_STATUS NetUserEnum(const char * server_name /* [in] [unique] */,
+ uint32_t level /* [in] */,
+ uint32_t filter /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */);
+WERROR NetUserEnum_r(struct libnetapi_ctx *ctx,
+ struct NetUserEnum *r);
+WERROR NetUserEnum_l(struct libnetapi_ctx *ctx,
+ struct NetUserEnum *r);
+NET_API_STATUS NetUserChangePassword(const char * domain_name /* [in] */,
+ const char * user_name /* [in] */,
+ const char * old_password /* [in] */,
+ const char * new_password /* [in] */);
+WERROR NetUserChangePassword_r(struct libnetapi_ctx *ctx,
+ struct NetUserChangePassword *r);
+WERROR NetUserChangePassword_l(struct libnetapi_ctx *ctx,
+ struct NetUserChangePassword *r);
+NET_API_STATUS NetUserGetInfo(const char * server_name /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */);
+WERROR NetUserGetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetUserGetInfo *r);
+WERROR NetUserGetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetUserGetInfo *r);
+NET_API_STATUS NetUserSetInfo(const char * server_name /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */);
+WERROR NetUserSetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetUserSetInfo *r);
+WERROR NetUserSetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetUserSetInfo *r);
+NET_API_STATUS NetUserGetGroups(const char * server_name /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */);
+WERROR NetUserGetGroups_r(struct libnetapi_ctx *ctx,
+ struct NetUserGetGroups *r);
+WERROR NetUserGetGroups_l(struct libnetapi_ctx *ctx,
+ struct NetUserGetGroups *r);
+NET_API_STATUS NetUserSetGroups(const char * server_name /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t num_entries /* [in] */);
+WERROR NetUserSetGroups_r(struct libnetapi_ctx *ctx,
+ struct NetUserSetGroups *r);
+WERROR NetUserSetGroups_l(struct libnetapi_ctx *ctx,
+ struct NetUserSetGroups *r);
+NET_API_STATUS NetUserGetLocalGroups(const char * server_name /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint32_t flags /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */);
+WERROR NetUserGetLocalGroups_r(struct libnetapi_ctx *ctx,
+ struct NetUserGetLocalGroups *r);
+WERROR NetUserGetLocalGroups_l(struct libnetapi_ctx *ctx,
+ struct NetUserGetLocalGroups *r);
+NET_API_STATUS NetUserModalsGet(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */);
+WERROR NetUserModalsGet_r(struct libnetapi_ctx *ctx,
+ struct NetUserModalsGet *r);
+WERROR NetUserModalsGet_l(struct libnetapi_ctx *ctx,
+ struct NetUserModalsGet *r);
+NET_API_STATUS NetUserModalsSet(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */);
+WERROR NetUserModalsSet_r(struct libnetapi_ctx *ctx,
+ struct NetUserModalsSet *r);
+WERROR NetUserModalsSet_l(struct libnetapi_ctx *ctx,
+ struct NetUserModalsSet *r);
+NET_API_STATUS NetQueryDisplayInformation(const char * server_name /* [in] [unique] */,
+ uint32_t level /* [in] */,
+ uint32_t idx /* [in] */,
+ uint32_t entries_requested /* [in] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ void **buffer /* [out] [noprint,ref] */);
+WERROR NetQueryDisplayInformation_r(struct libnetapi_ctx *ctx,
+ struct NetQueryDisplayInformation *r);
+WERROR NetQueryDisplayInformation_l(struct libnetapi_ctx *ctx,
+ struct NetQueryDisplayInformation *r);
+NET_API_STATUS NetGroupAdd(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */);
+WERROR NetGroupAdd_r(struct libnetapi_ctx *ctx,
+ struct NetGroupAdd *r);
+WERROR NetGroupAdd_l(struct libnetapi_ctx *ctx,
+ struct NetGroupAdd *r);
+NET_API_STATUS NetGroupDel(const char * server_name /* [in] */,
+ const char * group_name /* [in] */);
+WERROR NetGroupDel_r(struct libnetapi_ctx *ctx,
+ struct NetGroupDel *r);
+WERROR NetGroupDel_l(struct libnetapi_ctx *ctx,
+ struct NetGroupDel *r);
+NET_API_STATUS NetGroupEnum(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */);
+WERROR NetGroupEnum_r(struct libnetapi_ctx *ctx,
+ struct NetGroupEnum *r);
+WERROR NetGroupEnum_l(struct libnetapi_ctx *ctx,
+ struct NetGroupEnum *r);
+NET_API_STATUS NetGroupSetInfo(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */);
+WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetGroupSetInfo *r);
+WERROR NetGroupSetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetGroupSetInfo *r);
+NET_API_STATUS NetGroupGetInfo(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */);
+WERROR NetGroupGetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetGroupGetInfo *r);
+WERROR NetGroupGetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetGroupGetInfo *r);
+NET_API_STATUS NetGroupAddUser(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ const char * user_name /* [in] */);
+WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx,
+ struct NetGroupAddUser *r);
+WERROR NetGroupAddUser_l(struct libnetapi_ctx *ctx,
+ struct NetGroupAddUser *r);
+NET_API_STATUS NetGroupDelUser(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ const char * user_name /* [in] */);
+WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx,
+ struct NetGroupDelUser *r);
+WERROR NetGroupDelUser_l(struct libnetapi_ctx *ctx,
+ struct NetGroupDelUser *r);
+NET_API_STATUS NetGroupGetUsers(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */);
+WERROR NetGroupGetUsers_r(struct libnetapi_ctx *ctx,
+ struct NetGroupGetUsers *r);
+WERROR NetGroupGetUsers_l(struct libnetapi_ctx *ctx,
+ struct NetGroupGetUsers *r);
+NET_API_STATUS NetGroupSetUsers(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t num_entries /* [in] */);
+WERROR NetGroupSetUsers_r(struct libnetapi_ctx *ctx,
+ struct NetGroupSetUsers *r);
+WERROR NetGroupSetUsers_l(struct libnetapi_ctx *ctx,
+ struct NetGroupSetUsers *r);
+NET_API_STATUS NetLocalGroupAdd(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */);
+WERROR NetLocalGroupAdd_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupAdd *r);
+WERROR NetLocalGroupAdd_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupAdd *r);
+NET_API_STATUS NetLocalGroupDel(const char * server_name /* [in] */,
+ const char * group_name /* [in] */);
+WERROR NetLocalGroupDel_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupDel *r);
+WERROR NetLocalGroupDel_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupDel *r);
+NET_API_STATUS NetLocalGroupGetInfo(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */);
+WERROR NetLocalGroupGetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupGetInfo *r);
+WERROR NetLocalGroupGetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupGetInfo *r);
+NET_API_STATUS NetLocalGroupSetInfo(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */);
+WERROR NetLocalGroupSetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupSetInfo *r);
+WERROR NetLocalGroupSetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupSetInfo *r);
+NET_API_STATUS NetLocalGroupEnum(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */);
+WERROR NetLocalGroupEnum_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupEnum *r);
+WERROR NetLocalGroupEnum_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupEnum *r);
+NET_API_STATUS NetLocalGroupAddMembers(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t total_entries /* [in] */);
+WERROR NetLocalGroupAddMembers_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupAddMembers *r);
+WERROR NetLocalGroupAddMembers_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupAddMembers *r);
+NET_API_STATUS NetLocalGroupDelMembers(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t total_entries /* [in] */);
+WERROR NetLocalGroupDelMembers_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupDelMembers *r);
+WERROR NetLocalGroupDelMembers_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupDelMembers *r);
+NET_API_STATUS NetLocalGroupGetMembers(const char * server_name /* [in] */,
+ const char * local_group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */);
+WERROR NetLocalGroupGetMembers_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupGetMembers *r);
+WERROR NetLocalGroupGetMembers_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupGetMembers *r);
+NET_API_STATUS NetLocalGroupSetMembers(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t total_entries /* [in] */);
+WERROR NetLocalGroupSetMembers_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupSetMembers *r);
+WERROR NetLocalGroupSetMembers_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupSetMembers *r);
+NET_API_STATUS NetRemoteTOD(const char * server_name /* [in] */,
+ uint8_t **buffer /* [out] [ref] */);
+WERROR NetRemoteTOD_r(struct libnetapi_ctx *ctx,
+ struct NetRemoteTOD *r);
+WERROR NetRemoteTOD_l(struct libnetapi_ctx *ctx,
+ struct NetRemoteTOD *r);
+NET_API_STATUS NetShareAdd(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */);
+WERROR NetShareAdd_r(struct libnetapi_ctx *ctx,
+ struct NetShareAdd *r);
+WERROR NetShareAdd_l(struct libnetapi_ctx *ctx,
+ struct NetShareAdd *r);
+NET_API_STATUS NetShareDel(const char * server_name /* [in] */,
+ const char * net_name /* [in] */,
+ uint32_t reserved /* [in] */);
+WERROR NetShareDel_r(struct libnetapi_ctx *ctx,
+ struct NetShareDel *r);
+WERROR NetShareDel_l(struct libnetapi_ctx *ctx,
+ struct NetShareDel *r);
+NET_API_STATUS NetShareEnum(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */);
+WERROR NetShareEnum_r(struct libnetapi_ctx *ctx,
+ struct NetShareEnum *r);
+WERROR NetShareEnum_l(struct libnetapi_ctx *ctx,
+ struct NetShareEnum *r);
+NET_API_STATUS NetShareGetInfo(const char * server_name /* [in] */,
+ const char * net_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */);
+WERROR NetShareGetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetShareGetInfo *r);
+WERROR NetShareGetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetShareGetInfo *r);
+NET_API_STATUS NetShareSetInfo(const char * server_name /* [in] */,
+ const char * net_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */);
+WERROR NetShareSetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetShareSetInfo *r);
+WERROR NetShareSetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetShareSetInfo *r);
+NET_API_STATUS NetFileClose(const char * server_name /* [in] */,
+ uint32_t fileid /* [in] */);
+WERROR NetFileClose_r(struct libnetapi_ctx *ctx,
+ struct NetFileClose *r);
+WERROR NetFileClose_l(struct libnetapi_ctx *ctx,
+ struct NetFileClose *r);
+NET_API_STATUS NetFileGetInfo(const char * server_name /* [in] */,
+ uint32_t fileid /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */);
+WERROR NetFileGetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetFileGetInfo *r);
+WERROR NetFileGetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetFileGetInfo *r);
+NET_API_STATUS NetFileEnum(const char * server_name /* [in] */,
+ const char * base_path /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */);
+WERROR NetFileEnum_r(struct libnetapi_ctx *ctx,
+ struct NetFileEnum *r);
+WERROR NetFileEnum_l(struct libnetapi_ctx *ctx,
+ struct NetFileEnum *r);
+#endif /* __LIBNETAPI_LIBNETAPI__ */
diff --git a/source3/lib/netapi/localgroup.c b/source3/lib/netapi/localgroup.c
new file mode 100644
index 0000000000..25a3427bc1
--- /dev/null
+++ b/source3/lib/netapi/localgroup.c
@@ -0,0 +1,1358 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi LocalGroup Support
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#include "librpc/gen_ndr/libnetapi.h"
+#include "lib/netapi/netapi.h"
+#include "lib/netapi/netapi_private.h"
+#include "lib/netapi/libnetapi.h"
+
+static NTSTATUS libnetapi_samr_lookup_and_open_alias(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct policy_handle *domain_handle,
+ const char *group_name,
+ uint32_t access_rights,
+ struct policy_handle *alias_handle)
+{
+ NTSTATUS status;
+
+ struct lsa_String lsa_account_name;
+ struct samr_Ids user_rids, name_types;
+
+ init_lsa_String(&lsa_account_name, group_name);
+
+ status = rpccli_samr_LookupNames(pipe_cli, mem_ctx,
+ domain_handle,
+ 1,
+ &lsa_account_name,
+ &user_rids,
+ &name_types);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ switch (name_types.ids[0]) {
+ case SID_NAME_ALIAS:
+ case SID_NAME_WKN_GRP:
+ break;
+ default:
+ return NT_STATUS_INVALID_SID;
+ }
+
+ return rpccli_samr_OpenAlias(pipe_cli, mem_ctx,
+ domain_handle,
+ access_rights,
+ user_rids.ids[0],
+ alias_handle);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS libnetapi_samr_open_alias_queryinfo(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct policy_handle *handle,
+ uint32_t rid,
+ uint32_t access_rights,
+ enum samr_AliasInfoEnum level,
+ union samr_AliasInfo **alias_info)
+{
+ NTSTATUS status;
+ struct policy_handle alias_handle;
+ union samr_AliasInfo *_alias_info = NULL;
+
+ ZERO_STRUCT(alias_handle);
+
+ status = rpccli_samr_OpenAlias(pipe_cli, mem_ctx,
+ handle,
+ access_rights,
+ rid,
+ &alias_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = rpccli_samr_QueryAliasInfo(pipe_cli, mem_ctx,
+ &alias_handle,
+ level,
+ &_alias_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ *alias_info = _alias_info;
+
+ done:
+ if (is_valid_policy_hnd(&alias_handle)) {
+ rpccli_samr_Close(pipe_cli, mem_ctx, &alias_handle);
+ }
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupAdd_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupAdd *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ struct lsa_String lsa_account_name;
+ struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
+ struct dom_sid2 *domain_sid = NULL;
+ uint32_t rid;
+
+ struct LOCALGROUP_INFO_0 *info0 = NULL;
+ struct LOCALGROUP_INFO_1 *info1 = NULL;
+
+ const char *alias_name = NULL;
+
+ if (!r->in.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ info0 = (struct LOCALGROUP_INFO_0 *)r->in.buffer;
+ alias_name = info0->lgrpi0_name;
+ break;
+ case 1:
+ info1 = (struct LOCALGROUP_INFO_1 *)r->in.buffer;
+ alias_name = info1->lgrpi1_name;
+ break;
+ default:
+ werr = WERR_UNKNOWN_LEVEL;
+ goto done;
+ }
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(builtin_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(alias_handle);
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
+ SAMR_ACCESS_OPEN_DOMAIN |
+ SAMR_ACCESS_ENUM_DOMAINS,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &builtin_handle);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
+ &builtin_handle,
+ alias_name,
+ SAMR_ALIAS_ACCESS_LOOKUP_INFO,
+ &alias_handle);
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
+ }
+
+ if (NT_STATUS_IS_OK(status)) {
+ werr = WERR_ALIAS_EXISTS;
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_CREATE_ALIAS |
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_account_name, alias_name);
+
+ status = rpccli_samr_CreateDomAlias(pipe_cli, ctx,
+ &domain_handle,
+ &lsa_account_name,
+ SEC_STD_DELETE |
+ SAMR_ALIAS_ACCESS_SET_INFO,
+ &alias_handle,
+ &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ if (r->in.level == 1 && info1->lgrpi1_comment) {
+
+ union samr_AliasInfo alias_info;
+
+ init_lsa_String(&alias_info.description, info1->lgrpi1_comment);
+
+ status = rpccli_samr_SetAliasInfo(pipe_cli, ctx,
+ &alias_handle,
+ ALIASINFODESCRIPTION,
+ &alias_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+
+ werr = WERR_OK;
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&alias_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &alias_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupAdd_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupAdd *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupAdd);
+}
+
+/****************************************************************
+****************************************************************/
+
+
+WERROR NetLocalGroupDel_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupDel *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
+ struct dom_sid2 *domain_sid = NULL;
+
+ if (!r->in.group_name) {
+ return WERR_INVALID_PARAM;
+ }
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(builtin_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(alias_handle);
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
+ SAMR_ACCESS_OPEN_DOMAIN |
+ SAMR_ACCESS_ENUM_DOMAINS,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &builtin_handle);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
+ &builtin_handle,
+ r->in.group_name,
+ SEC_STD_DELETE,
+ &alias_handle);
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
+ }
+
+ if (NT_STATUS_IS_OK(status)) {
+ goto delete_alias;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_CREATE_ALIAS |
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
+ &domain_handle,
+ r->in.group_name,
+ SEC_STD_DELETE,
+ &alias_handle);
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+
+ delete_alias:
+ status = rpccli_samr_DeleteDomAlias(pipe_cli, ctx,
+ &alias_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ ZERO_STRUCT(alias_handle);
+
+ werr = WERR_OK;
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&alias_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &alias_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupDel_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupDel *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupDel);
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR map_alias_info_to_buffer(TALLOC_CTX *mem_ctx,
+ const char *alias_name,
+ struct samr_AliasInfoAll *info,
+ uint32_t level,
+ uint32_t *entries_read,
+ uint8_t **buffer)
+{
+ struct LOCALGROUP_INFO_0 g0;
+ struct LOCALGROUP_INFO_1 g1;
+ struct LOCALGROUP_INFO_1002 g1002;
+
+ switch (level) {
+ case 0:
+ g0.lgrpi0_name = talloc_strdup(mem_ctx, alias_name);
+ W_ERROR_HAVE_NO_MEMORY(g0.lgrpi0_name);
+
+ ADD_TO_ARRAY(mem_ctx, struct LOCALGROUP_INFO_0, g0,
+ (struct LOCALGROUP_INFO_0 **)buffer, entries_read);
+
+ break;
+ case 1:
+ g1.lgrpi1_name = talloc_strdup(mem_ctx, alias_name);
+ g1.lgrpi1_comment = talloc_strdup(mem_ctx, info->description.string);
+ W_ERROR_HAVE_NO_MEMORY(g1.lgrpi1_name);
+
+ ADD_TO_ARRAY(mem_ctx, struct LOCALGROUP_INFO_1, g1,
+ (struct LOCALGROUP_INFO_1 **)buffer, entries_read);
+
+ break;
+ case 1002:
+ g1002.lgrpi1002_comment = talloc_strdup(mem_ctx, info->description.string);
+
+ ADD_TO_ARRAY(mem_ctx, struct LOCALGROUP_INFO_1002, g1002,
+ (struct LOCALGROUP_INFO_1002 **)buffer, entries_read);
+
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupGetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupGetInfo *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
+ struct dom_sid2 *domain_sid = NULL;
+ union samr_AliasInfo *alias_info = NULL;
+ uint32_t entries_read = 0;
+
+ if (!r->in.group_name) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ case 1:
+ case 1002:
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(builtin_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(alias_handle);
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
+ SAMR_ACCESS_OPEN_DOMAIN |
+ SAMR_ACCESS_ENUM_DOMAINS,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &builtin_handle);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
+ &builtin_handle,
+ r->in.group_name,
+ SAMR_ALIAS_ACCESS_LOOKUP_INFO,
+ &alias_handle);
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
+ }
+
+ if (NT_STATUS_IS_OK(status)) {
+ goto query_alias;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_CREATE_ALIAS |
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
+ &domain_handle,
+ r->in.group_name,
+ SAMR_ALIAS_ACCESS_LOOKUP_INFO,
+ &alias_handle);
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ query_alias:
+ status = rpccli_samr_QueryAliasInfo(pipe_cli, ctx,
+ &alias_handle,
+ ALIASINFOALL,
+ &alias_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ werr = map_alias_info_to_buffer(ctx,
+ r->in.group_name,
+ &alias_info->all,
+ r->in.level, &entries_read,
+ r->out.buffer);
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&alias_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &alias_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupGetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupGetInfo *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupGetInfo);
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR map_buffer_to_alias_info(TALLOC_CTX *mem_ctx,
+ uint32_t level,
+ uint8_t *buffer,
+ enum samr_AliasInfoEnum *alias_level,
+ union samr_AliasInfo **alias_info)
+{
+ struct LOCALGROUP_INFO_0 *info0;
+ struct LOCALGROUP_INFO_1 *info1;
+ struct LOCALGROUP_INFO_1002 *info1002;
+ union samr_AliasInfo *info = NULL;
+
+ info = TALLOC_ZERO_P(mem_ctx, union samr_AliasInfo);
+ W_ERROR_HAVE_NO_MEMORY(info);
+
+ switch (level) {
+ case 0:
+ info0 = (struct LOCALGROUP_INFO_0 *)buffer;
+ init_lsa_String(&info->name, info0->lgrpi0_name);
+ *alias_level = ALIASINFONAME;
+ break;
+ case 1:
+ info1 = (struct LOCALGROUP_INFO_1 *)buffer;
+ /* group name will be ignored */
+ init_lsa_String(&info->description, info1->lgrpi1_comment);
+ *alias_level = ALIASINFODESCRIPTION;
+ break;
+ case 1002:
+ info1002 = (struct LOCALGROUP_INFO_1002 *)buffer;
+ init_lsa_String(&info->description, info1002->lgrpi1002_comment);
+ *alias_level = ALIASINFODESCRIPTION;
+ break;
+ }
+
+ *alias_info = info;
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupSetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupSetInfo *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ struct lsa_String lsa_account_name;
+ struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
+ struct dom_sid2 *domain_sid = NULL;
+ enum samr_AliasInfoEnum alias_level = 0;
+ union samr_AliasInfo *alias_info = NULL;
+
+ if (!r->in.group_name) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ case 1:
+ case 1002:
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(builtin_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(alias_handle);
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
+ SAMR_ACCESS_OPEN_DOMAIN |
+ SAMR_ACCESS_ENUM_DOMAINS,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &builtin_handle);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_account_name, r->in.group_name);
+
+ status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
+ &builtin_handle,
+ r->in.group_name,
+ SAMR_ALIAS_ACCESS_SET_INFO,
+ &alias_handle);
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
+ }
+
+ if (NT_STATUS_IS_OK(status)) {
+ goto set_alias;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
+ &domain_handle,
+ r->in.group_name,
+ SAMR_ALIAS_ACCESS_SET_INFO,
+ &alias_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ }
+
+ set_alias:
+
+ werr = map_buffer_to_alias_info(ctx, r->in.level, r->in.buffer,
+ &alias_level, &alias_info);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = rpccli_samr_SetAliasInfo(pipe_cli, ctx,
+ &alias_handle,
+ alias_level,
+ alias_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ werr = WERR_OK;
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&alias_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &alias_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupSetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupSetInfo *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupSetInfo);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupEnum_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupEnum *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
+ struct dom_sid2 *domain_sid = NULL;
+ uint32_t entries_read = 0;
+ union samr_DomainInfo *domain_info = NULL;
+ union samr_DomainInfo *builtin_info = NULL;
+ struct samr_SamArray *domain_sam_array = NULL;
+ struct samr_SamArray *builtin_sam_array = NULL;
+ int i;
+
+ if (!r->out.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ case 1:
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ if (r->out.total_entries) {
+ *r->out.total_entries = 0;
+ }
+ if (r->out.entries_read) {
+ *r->out.entries_read = 0;
+ }
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(builtin_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(alias_handle);
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
+ SAMR_ACCESS_OPEN_DOMAIN |
+ SAMR_ACCESS_ENUM_DOMAINS,
+ SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 |
+ SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS |
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &builtin_handle);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_OPEN_DOMAIN |
+ SAMR_ACCESS_ENUM_DOMAINS,
+ SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 |
+ SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS |
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = rpccli_samr_QueryDomainInfo(pipe_cli, ctx,
+ &builtin_handle,
+ 2,
+ &builtin_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ if (r->out.total_entries) {
+ *r->out.total_entries += builtin_info->info2.num_aliases;
+ }
+
+ status = rpccli_samr_QueryDomainInfo(pipe_cli, ctx,
+ &domain_handle,
+ 2,
+ &domain_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ if (r->out.total_entries) {
+ *r->out.total_entries += domain_info->info2.num_aliases;
+ }
+
+ status = rpccli_samr_EnumDomainAliases(pipe_cli, ctx,
+ &builtin_handle,
+ r->in.resume_handle,
+ &builtin_sam_array,
+ r->in.prefmaxlen,
+ &entries_read);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ for (i=0; i<builtin_sam_array->count; i++) {
+ union samr_AliasInfo *alias_info = NULL;
+
+ if (r->in.level == 1) {
+
+ status = libnetapi_samr_open_alias_queryinfo(ctx, pipe_cli,
+ &builtin_handle,
+ builtin_sam_array->entries[i].idx,
+ SAMR_ALIAS_ACCESS_LOOKUP_INFO,
+ ALIASINFOALL,
+ &alias_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+
+ werr = map_alias_info_to_buffer(ctx,
+ builtin_sam_array->entries[i].name.string,
+ alias_info ? &alias_info->all : NULL,
+ r->in.level,
+ r->out.entries_read,
+ r->out.buffer);
+ }
+
+ status = rpccli_samr_EnumDomainAliases(pipe_cli, ctx,
+ &domain_handle,
+ r->in.resume_handle,
+ &domain_sam_array,
+ r->in.prefmaxlen,
+ &entries_read);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ for (i=0; i<domain_sam_array->count; i++) {
+
+ union samr_AliasInfo *alias_info = NULL;
+
+ if (r->in.level == 1) {
+ status = libnetapi_samr_open_alias_queryinfo(ctx, pipe_cli,
+ &domain_handle,
+ domain_sam_array->entries[i].idx,
+ SAMR_ALIAS_ACCESS_LOOKUP_INFO,
+ ALIASINFOALL,
+ &alias_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+
+ werr = map_alias_info_to_buffer(ctx,
+ domain_sam_array->entries[i].name.string,
+ alias_info ? &alias_info->all : NULL,
+ r->in.level,
+ r->out.entries_read,
+ r->out.buffer);
+ }
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupEnum_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupEnum *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupEnum);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS libnetapi_lsa_lookup_names3(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *lsa_pipe,
+ const char *name,
+ struct dom_sid *sid)
+{
+ NTSTATUS status;
+ struct policy_handle lsa_handle;
+
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_TransSidArray3 sids;
+ uint32_t count = 0;
+
+ struct lsa_String names;
+ uint32_t num_names = 1;
+
+ if (!sid || !name) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ZERO_STRUCT(sids);
+
+ init_lsa_String(&names, name);
+
+ status = rpccli_lsa_open_policy2(lsa_pipe, mem_ctx,
+ false,
+ STD_RIGHT_READ_CONTROL_ACCESS |
+ LSA_POLICY_VIEW_LOCAL_INFORMATION |
+ LSA_POLICY_LOOKUP_NAMES,
+ &lsa_handle);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ status = rpccli_lsa_LookupNames3(lsa_pipe, mem_ctx,
+ &lsa_handle,
+ num_names,
+ &names,
+ &domains,
+ &sids,
+ LSA_LOOKUP_NAMES_ALL, /* sure ? */
+ &count,
+ 0, 0);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ if (count != 1 || sids.count != 1) {
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ sid_copy(sid, sids.sids[0].sid);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetLocalGroupModifyMembers_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupAddMembers *add,
+ struct NetLocalGroupDelMembers *del,
+ struct NetLocalGroupSetMembers *set)
+{
+ struct NetLocalGroupAddMembers *r = NULL;
+
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct rpc_pipe_client *lsa_pipe = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ struct lsa_String lsa_account_name;
+ struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
+ struct dom_sid2 *domain_sid = NULL;
+ struct dom_sid *member_sids = NULL;
+ int i = 0, k = 0;
+
+ struct LOCALGROUP_MEMBERS_INFO_0 *info0 = NULL;
+ struct LOCALGROUP_MEMBERS_INFO_3 *info3 = NULL;
+
+ struct dom_sid *add_sids = NULL;
+ struct dom_sid *del_sids = NULL;
+ size_t num_add_sids = 0;
+ size_t num_del_sids = 0;
+
+ if ((!add && !del && !set) || (add && del && set)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ if (add) {
+ r = add;
+ }
+
+ if (del) {
+ r = (struct NetLocalGroupAddMembers *)del;
+ }
+
+ if (set) {
+ r = (struct NetLocalGroupAddMembers *)set;
+ }
+
+ if (!r->in.group_name) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ case 3:
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ if (r->in.total_entries == 0 || !r->in.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(builtin_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(alias_handle);
+
+ member_sids = TALLOC_ZERO_ARRAY(ctx, struct dom_sid,
+ r->in.total_entries);
+ W_ERROR_HAVE_NO_MEMORY(member_sids);
+
+ switch (r->in.level) {
+ case 0:
+ info0 = (struct LOCALGROUP_MEMBERS_INFO_0 *)r->in.buffer;
+ for (i=0; i < r->in.total_entries; i++) {
+ sid_copy(&member_sids[i], (struct dom_sid *)info0[i].lgrmi0_sid);
+ }
+ break;
+ case 3:
+ info3 = (struct LOCALGROUP_MEMBERS_INFO_3 *)r->in.buffer;
+ break;
+ default:
+ break;
+ }
+
+ if (r->in.level == 3) {
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_lsarpc.syntax_id,
+ &cli,
+ &lsa_pipe);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ for (i=0; i < r->in.total_entries; i++) {
+ status = libnetapi_lsa_lookup_names3(ctx, lsa_pipe,
+ info3[i].lgrmi3_domainandname,
+ &member_sids[i]);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+ TALLOC_FREE(lsa_pipe);
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
+ SAMR_ACCESS_OPEN_DOMAIN |
+ SAMR_ACCESS_ENUM_DOMAINS,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &builtin_handle);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_account_name, r->in.group_name);
+
+ status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
+ &builtin_handle,
+ r->in.group_name,
+ SAMR_ALIAS_ACCESS_ADD_MEMBER |
+ SAMR_ALIAS_ACCESS_REMOVE_MEMBER |
+ SAMR_ALIAS_ACCESS_GET_MEMBERS |
+ SAMR_ALIAS_ACCESS_LOOKUP_INFO,
+ &alias_handle);
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
+ }
+
+ if (NT_STATUS_IS_OK(status)) {
+ goto modify_membership;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
+ &domain_handle,
+ r->in.group_name,
+ SAMR_ALIAS_ACCESS_ADD_MEMBER |
+ SAMR_ALIAS_ACCESS_REMOVE_MEMBER |
+ SAMR_ALIAS_ACCESS_GET_MEMBERS |
+ SAMR_ALIAS_ACCESS_LOOKUP_INFO,
+ &alias_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ }
+
+ modify_membership:
+
+ if (add) {
+ for (i=0; i < r->in.total_entries; i++) {
+ status = add_sid_to_array_unique(ctx, &member_sids[i],
+ &add_sids,
+ &num_add_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+ }
+
+ if (del) {
+ for (i=0; i < r->in.total_entries; i++) {
+ status = add_sid_to_array_unique(ctx, &member_sids[i],
+ &del_sids,
+ &num_del_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+ }
+
+ if (set) {
+
+ struct lsa_SidArray current_sids;
+
+ status = rpccli_samr_GetMembersInAlias(pipe_cli, ctx,
+ &alias_handle,
+ &current_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ /* add list */
+
+ for (i=0; i < r->in.total_entries; i++) {
+ bool already_member = false;
+ for (k=0; k < current_sids.num_sids; k++) {
+ if (sid_equal(&member_sids[i],
+ current_sids.sids[k].sid)) {
+ already_member = true;
+ break;
+ }
+ }
+ if (!already_member) {
+ status = add_sid_to_array_unique(ctx,
+ &member_sids[i],
+ &add_sids, &num_add_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+ }
+
+ /* del list */
+
+ for (k=0; k < current_sids.num_sids; k++) {
+ bool keep_member = false;
+ for (i=0; i < r->in.total_entries; i++) {
+ if (sid_equal(&member_sids[i],
+ current_sids.sids[k].sid)) {
+ keep_member = true;
+ break;
+ }
+ }
+ if (!keep_member) {
+ status = add_sid_to_array_unique(ctx,
+ current_sids.sids[k].sid,
+ &del_sids, &num_del_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+ }
+ }
+
+ /* add list */
+
+ for (i=0; i < num_add_sids; i++) {
+ status = rpccli_samr_AddAliasMember(pipe_cli, ctx,
+ &alias_handle,
+ &add_sids[i]);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+
+ /* del list */
+
+ for (i=0; i < num_del_sids; i++) {
+ status = rpccli_samr_DeleteAliasMember(pipe_cli, ctx,
+ &alias_handle,
+ &del_sids[i]);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+
+ werr = WERR_OK;
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&alias_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &alias_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupAddMembers_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupAddMembers *r)
+{
+ return NetLocalGroupModifyMembers_r(ctx, r, NULL, NULL);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupAddMembers_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupAddMembers *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupAddMembers);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupDelMembers_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupDelMembers *r)
+{
+ return NetLocalGroupModifyMembers_r(ctx, NULL, r, NULL);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupDelMembers_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupDelMembers *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupDelMembers);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupGetMembers_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupGetMembers *r)
+{
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupGetMembers_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupGetMembers *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupGetMembers);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupSetMembers_r(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupSetMembers *r)
+{
+ return NetLocalGroupModifyMembers_r(ctx, NULL, NULL, r);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetLocalGroupSetMembers_l(struct libnetapi_ctx *ctx,
+ struct NetLocalGroupSetMembers *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupSetMembers);
+}
+
diff --git a/source3/lib/netapi/netapi.c b/source3/lib/netapi/netapi.c
new file mode 100644
index 0000000000..889388173f
--- /dev/null
+++ b/source3/lib/netapi/netapi.c
@@ -0,0 +1,348 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi Support
+ * Copyright (C) Guenther Deschner 2007-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "lib/netapi/netapi.h"
+#include "lib/netapi/netapi_private.h"
+
+extern bool AllowDebugChange;
+
+struct libnetapi_ctx *stat_ctx = NULL;
+TALLOC_CTX *frame = NULL;
+static bool libnetapi_initialized = false;
+
+/****************************************************************
+****************************************************************/
+
+static NET_API_STATUS libnetapi_init_private_context(struct libnetapi_ctx *ctx)
+{
+ struct libnetapi_private_ctx *priv;
+
+ if (!ctx) {
+ return W_ERROR_V(WERR_INVALID_PARAM);
+ }
+
+ priv = TALLOC_ZERO_P(ctx, struct libnetapi_private_ctx);
+ if (!priv) {
+ return W_ERROR_V(WERR_NOMEM);
+ }
+
+ ctx->private_data = priv;
+
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_init(struct libnetapi_ctx **context)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ char *krb5_cc_env = NULL;
+
+ if (stat_ctx && libnetapi_initialized) {
+ *context = stat_ctx;
+ return NET_API_STATUS_SUCCESS;
+ }
+
+#if 0
+ talloc_enable_leak_report();
+#endif
+ frame = talloc_stackframe();
+
+ ctx = talloc_zero(frame, struct libnetapi_ctx);
+ if (!ctx) {
+ TALLOC_FREE(frame);
+ return W_ERROR_V(WERR_NOMEM);
+ }
+
+ if (!DEBUGLEVEL) {
+ DEBUGLEVEL = 0;
+ }
+
+ /* prevent setup_logging() from closing x_stderr... */
+ dbf = 0;
+ setup_logging("libnetapi", true);
+
+ dbf = x_stderr;
+ x_setbuf(x_stderr, NULL);
+ AllowDebugChange = false;
+
+ load_case_tables();
+
+ if (!lp_load(get_dyn_CONFIGFILE(), true, false, false, false)) {
+ TALLOC_FREE(frame);
+ fprintf(stderr, "lp_load failed\n");
+ return W_ERROR_V(WERR_GENERAL_FAILURE);
+ }
+
+ AllowDebugChange = true;
+
+ init_names();
+ load_interfaces();
+ reopen_logs();
+
+ BlockSignals(True, SIGPIPE);
+
+ krb5_cc_env = getenv(KRB5_ENV_CCNAME);
+ if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) {
+ ctx->krb5_cc_env = talloc_strdup(frame, "MEMORY:libnetapi");
+ setenv(KRB5_ENV_CCNAME, ctx->krb5_cc_env, 1);
+ }
+
+ if (getenv("USER")) {
+ ctx->username = talloc_strdup(frame, getenv("USER"));
+ } else {
+ ctx->username = talloc_strdup(frame, "");
+ }
+ if (!ctx->username) {
+ TALLOC_FREE(frame);
+ fprintf(stderr, "libnetapi_init: out of memory\n");
+ return W_ERROR_V(WERR_NOMEM);
+ }
+
+ status = libnetapi_init_private_context(ctx);
+ if (status != 0) {
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ libnetapi_initialized = true;
+
+ *context = stat_ctx = ctx;
+
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_getctx(struct libnetapi_ctx **ctx)
+{
+ if (stat_ctx) {
+ *ctx = stat_ctx;
+ return NET_API_STATUS_SUCCESS;
+ }
+
+ return libnetapi_init(ctx);
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_free(struct libnetapi_ctx *ctx)
+{
+ if (!ctx) {
+ return NET_API_STATUS_SUCCESS;
+ }
+
+ libnetapi_samr_free(ctx);
+
+ libnetapi_shutdown_cm(ctx);
+
+ if (ctx->krb5_cc_env) {
+ char *env = getenv(KRB5_ENV_CCNAME);
+ if (env && (strequal(ctx->krb5_cc_env, env))) {
+ unsetenv(KRB5_ENV_CCNAME);
+ }
+ }
+
+ gfree_names();
+ gfree_loadparm();
+ gfree_case_tables();
+ gfree_charcnv();
+ gfree_interfaces();
+
+ gencache_shutdown();
+ secrets_shutdown();
+
+ TALLOC_FREE(ctx);
+ TALLOC_FREE(frame);
+
+ gfree_debugsyms();
+
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_set_debuglevel(struct libnetapi_ctx *ctx,
+ const char *debuglevel)
+{
+ AllowDebugChange = true;
+ ctx->debuglevel = talloc_strdup(ctx, debuglevel);
+ if (!debug_parse_levels(debuglevel)) {
+ return W_ERROR_V(WERR_GENERAL_FAILURE);
+ }
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_get_debuglevel(struct libnetapi_ctx *ctx,
+ char **debuglevel)
+{
+ *debuglevel = ctx->debuglevel;
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_set_username(struct libnetapi_ctx *ctx,
+ const char *username)
+{
+ TALLOC_FREE(ctx->username);
+ ctx->username = talloc_strdup(ctx, username ? username : "");
+
+ if (!ctx->username) {
+ return W_ERROR_V(WERR_NOMEM);
+ }
+ return NET_API_STATUS_SUCCESS;
+}
+
+NET_API_STATUS libnetapi_set_password(struct libnetapi_ctx *ctx,
+ const char *password)
+{
+ TALLOC_FREE(ctx->password);
+ ctx->password = talloc_strdup(ctx, password);
+ if (!ctx->password) {
+ return W_ERROR_V(WERR_NOMEM);
+ }
+ return NET_API_STATUS_SUCCESS;
+}
+
+NET_API_STATUS libnetapi_set_workgroup(struct libnetapi_ctx *ctx,
+ const char *workgroup)
+{
+ TALLOC_FREE(ctx->workgroup);
+ ctx->workgroup = talloc_strdup(ctx, workgroup);
+ if (!ctx->workgroup) {
+ return W_ERROR_V(WERR_NOMEM);
+ }
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_set_use_kerberos(struct libnetapi_ctx *ctx)
+{
+ ctx->use_kerberos = true;
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+const char *libnetapi_errstr(NET_API_STATUS status)
+{
+ if (status & 0xc0000000) {
+ return get_friendly_nt_error_msg(NT_STATUS(status));
+ }
+
+ return get_friendly_werror_msg(W_ERROR(status));
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_set_error_string(struct libnetapi_ctx *ctx,
+ const char *format, ...)
+{
+ va_list args;
+
+ TALLOC_FREE(ctx->error_string);
+
+ va_start(args, format);
+ ctx->error_string = talloc_vasprintf(ctx, format, args);
+ va_end(args);
+
+ if (!ctx->error_string) {
+ return W_ERROR_V(WERR_NOMEM);
+ }
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+const char *libnetapi_get_error_string(struct libnetapi_ctx *ctx,
+ NET_API_STATUS status_in)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *tmp_ctx = ctx;
+
+ if (!tmp_ctx) {
+ status = libnetapi_getctx(&tmp_ctx);
+ if (status != 0) {
+ return NULL;
+ }
+ }
+
+ if (tmp_ctx->error_string) {
+ return tmp_ctx->error_string;
+ }
+
+ return libnetapi_errstr(status_in);
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS NetApiBufferAllocate(uint32_t byte_count,
+ void **buffer)
+{
+ void *buf = NULL;
+
+ if (!buffer) {
+ return W_ERROR_V(WERR_INSUFFICIENT_BUFFER);
+ }
+
+ if (byte_count == 0) {
+ goto done;
+ }
+
+ buf = talloc_size(NULL, byte_count);
+ if (!buf) {
+ return W_ERROR_V(WERR_NOMEM);
+ }
+
+ done:
+ *buffer = buf;
+
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS NetApiBufferFree(void *buffer)
+{
+ if (!buffer) {
+ return W_ERROR_V(WERR_INSUFFICIENT_BUFFER);
+ }
+
+ talloc_free(buffer);
+
+ return NET_API_STATUS_SUCCESS;
+}
diff --git a/source3/lib/netapi/netapi.h b/source3/lib/netapi/netapi.h
new file mode 100644
index 0000000000..9687461920
--- /dev/null
+++ b/source3/lib/netapi/netapi.h
@@ -0,0 +1,1840 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi Support
+ * Copyright (C) Guenther Deschner 2007-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_NETAPI_H__
+#define __LIB_NETAPI_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/****************************************************************
+ NET_API_STATUS
+****************************************************************/
+typedef enum {
+ NET_API_STATUS_SUCCESS = 0
+} NET_API_STATUS;
+
+#define ERROR_MORE_DATA ( 234L )
+
+#define ENCRYPTED_PWLEN ( 16 )
+
+/****************************************************************
+****************************************************************/
+
+#ifndef _HEADER_misc
+
+struct GUID {
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_hi_and_version;
+ uint8_t clock_seq[2];
+ uint8_t node[6];
+};
+
+#endif /* _HEADER_misc */
+
+#ifndef _HEADER_libnetapi
+
+#ifndef MAXSUBAUTHS
+#define MAXSUBAUTHS 15 /* max sub authorities in a SID */
+#endif
+
+struct domsid {
+ uint8_t sid_rev_num;
+ uint8_t num_auths;
+ uint8_t id_auth[6];
+ uint32_t sub_auths[MAXSUBAUTHS];
+};
+
+struct DOMAIN_CONTROLLER_INFO {
+ const char * domain_controller_name;
+ const char * domain_controller_address;
+ uint32_t domain_controller_address_type;
+ struct GUID domain_guid;
+ const char * domain_name;
+ const char * dns_forest_name;
+ uint32_t flags;
+ const char * dc_site_name;
+ const char * client_site_name;
+};
+
+/* bitmap NetJoinFlags */
+#define NETSETUP_JOIN_DOMAIN ( 0x00000001 )
+#define NETSETUP_ACCT_CREATE ( 0x00000002 )
+#define NETSETUP_ACCT_DELETE ( 0x00000004 )
+#define NETSETUP_WIN9X_UPGRADE ( 0x00000010 )
+#define NETSETUP_DOMAIN_JOIN_IF_JOINED ( 0x00000020 )
+#define NETSETUP_JOIN_UNSECURE ( 0x00000040 )
+#define NETSETUP_MACHINE_PWD_PASSED ( 0x00000080 )
+#define NETSETUP_DEFER_SPN_SET ( 0x00000100 )
+#define NETSETUP_JOIN_DC_ACCOUNT ( 0x00000200 )
+#define NETSETUP_JOIN_WITH_NEW_NAME ( 0x00000400 )
+#define NETSETUP_INSTALL_INVOCATION ( 0x00040000 )
+#define NETSETUP_IGNORE_UNSUPPORTED_FLAGS ( 0x10000000 )
+
+#define FILTER_TEMP_DUPLICATE_ACCOUNT ( 0x0001 )
+#define FILTER_NORMAL_ACCOUNT ( 0x0002 )
+#define FILTER_INTERDOMAIN_TRUST_ACCOUNT ( 0x0008 )
+#define FILTER_WORKSTATION_TRUST_ACCOUNT ( 0x0010 )
+#define FILTER_SERVER_TRUST_ACCOUNT ( 0x0020 )
+
+#define TIMEQ_FOREVER ( (uint32_t)-1L )
+
+enum NETSETUP_JOIN_STATUS {
+ NetSetupUnknownStatus=0,
+ NetSetupUnjoined=1,
+ NetSetupWorkgroupName=2,
+ NetSetupDomainName=3
+};
+
+struct SERVER_INFO_100 {
+ uint32_t sv100_platform_id;
+ const char * sv100_name;
+};
+
+struct SERVER_INFO_101 {
+ uint32_t sv101_platform_id;
+ const char * sv101_name;
+ uint32_t sv101_version_major;
+ uint32_t sv101_version_minor;
+ uint32_t sv101_type;
+ const char * sv101_comment;
+};
+
+struct SERVER_INFO_102 {
+ uint32_t sv102_platform_id;
+ const char * sv102_name;
+ uint32_t sv102_version_major;
+ uint32_t sv102_version_minor;
+ uint32_t sv102_type;
+ const char * sv102_comment;
+ uint32_t sv102_users;
+ uint32_t sv102_disc;
+ uint8_t sv102_hidden;
+ uint32_t sv102_announce;
+ uint32_t sv102_anndelta;
+ uint32_t sv102_licenses;
+ const char * sv102_userpath;
+};
+
+
+struct SERVER_INFO_1005 {
+ const char * sv1005_comment;
+};
+
+struct USER_INFO_0 {
+ const char * usri0_name;
+};
+
+#define USER_PRIV_GUEST ( 0 )
+#define USER_PRIV_USER ( 1 )
+#define USER_PRIV_ADMIN ( 2 )
+
+struct USER_INFO_1 {
+ const char * usri1_name;
+ const char * usri1_password;
+ uint32_t usri1_password_age;
+ uint32_t usri1_priv;
+ const char * usri1_home_dir;
+ const char * usri1_comment;
+ uint32_t usri1_flags;
+ const char * usri1_script_path;
+};
+
+#define AF_OP_PRINT ( 0x1 )
+#define AF_OP_COMM ( 0x2 )
+#define AF_OP_SERVER ( 0x4 )
+#define AF_OP_ACCOUNTS ( 0x8 )
+
+struct USER_INFO_2 {
+ const char * usri2_name;
+ const char * usri2_password;
+ uint32_t usri2_password_age;
+ uint32_t usri2_priv;
+ const char * usri2_home_dir;
+ const char * usri2_comment;
+ uint32_t usri2_flags;
+ const char * usri2_script_path;
+ uint32_t usri2_auth_flags;
+ const char * usri2_full_name;
+ const char * usri2_usr_comment;
+ const char * usri2_parms;
+ const char * usri2_workstations;
+ uint32_t usri2_last_logon;
+ uint32_t usri2_last_logoff;
+ uint32_t usri2_acct_expires;
+ uint32_t usri2_max_storage;
+ uint32_t usri2_units_per_week;
+ uint8_t *usri2_logon_hours;/* [unique] */
+ uint32_t usri2_bad_pw_count;
+ uint32_t usri2_num_logons;
+ const char * usri2_logon_server;
+ uint32_t usri2_country_code;
+ uint32_t usri2_code_page;
+};
+
+struct USER_INFO_3 {
+ const char * usri3_name;
+ uint32_t usri3_password_age;
+ uint32_t usri3_priv;
+ const char * usri3_home_dir;
+ const char * usri3_comment;
+ uint32_t usri3_flags;
+ const char * usri3_script_path;
+ uint32_t usri3_auth_flags;
+ const char * usri3_full_name;
+ const char * usri3_usr_comment;
+ const char * usri3_parms;
+ const char * usri3_workstations;
+ uint32_t usri3_last_logon;
+ uint32_t usri3_last_logoff;
+ uint32_t usri3_acct_expires;
+ uint32_t usri3_max_storage;
+ uint32_t usri3_units_per_week;
+ uint8_t *usri3_logon_hours;/* [unique] */
+ uint32_t usri3_bad_pw_count;
+ uint32_t usri3_num_logons;
+ const char * usri3_logon_server;
+ uint32_t usri3_country_code;
+ uint32_t usri3_code_page;
+ uint32_t usri3_user_id;
+ uint32_t usri3_primary_group_id;
+ const char * usri3_profile;
+ const char * usri3_home_dir_drive;
+ uint32_t usri3_password_expired;
+};
+
+struct USER_INFO_4 {
+ const char * usri4_name;
+ const char * usri4_password;
+ uint32_t usri4_password_age;
+ uint32_t usri4_priv;
+ const char * usri4_home_dir;
+ const char * usri4_comment;
+ uint32_t usri4_flags;
+ const char * usri4_script_path;
+ uint32_t usri4_auth_flags;
+ const char * usri4_full_name;
+ const char * usri4_usr_comment;
+ const char * usri4_parms;
+ const char * usri4_workstations;
+ uint32_t usri4_last_logon;
+ uint32_t usri4_last_logoff;
+ uint32_t usri4_acct_expires;
+ uint32_t usri4_max_storage;
+ uint32_t usri4_units_per_week;
+ uint8_t *usri4_logon_hours;/* [unique] */
+ uint32_t usri4_bad_pw_count;
+ uint32_t usri4_num_logons;
+ const char * usri4_logon_server;
+ uint32_t usri4_country_code;
+ uint32_t usri4_code_page;
+ struct domsid *usri4_user_sid;/* [unique] */
+ uint32_t usri4_primary_group_id;
+ const char * usri4_profile;
+ const char * usri4_home_dir_drive;
+ uint32_t usri4_password_expired;
+};
+
+struct USER_INFO_10 {
+ const char * usri10_name;
+ const char * usri10_comment;
+ const char * usri10_usr_comment;
+ const char * usri10_full_name;
+};
+
+struct USER_INFO_11 {
+ const char * usri11_name;
+ const char * usri11_comment;
+ const char * usri11_usr_comment;
+ const char * usri11_full_name;
+ uint32_t usri11_priv;
+ uint32_t usri11_auth_flags;
+ uint32_t usri11_password_age;
+ const char * usri11_home_dir;
+ const char * usri11_parms;
+ uint32_t usri11_last_logon;
+ uint32_t usri11_last_logoff;
+ uint32_t usri11_bad_pw_count;
+ uint32_t usri11_num_logons;
+ const char * usri11_logon_server;
+ uint32_t usri11_country_code;
+ const char * usri11_workstations;
+ uint32_t usri11_max_storage;
+ uint32_t usri11_units_per_week;
+ uint8_t *usri11_logon_hours;/* [unique] */
+ uint32_t usri11_code_page;
+};
+
+struct USER_INFO_20 {
+ const char * usri20_name;
+ const char * usri20_full_name;
+ const char * usri20_comment;
+ uint32_t usri20_flags;
+ uint32_t usri20_user_id;
+};
+
+struct USER_INFO_21 {
+ uint8_t *usri21_password;
+};
+
+struct USER_INFO_22 {
+ const char * usri22_name;
+ uint8_t *usri22_password;
+ uint32_t usri22_password_age;
+ uint32_t usri22_priv;
+ const char * usri22_home_dir;
+ const char * usri22_comment;
+ uint32_t usri22_flags;
+ uint32_t usri22_script_path;
+ uint32_t usri22_auth_flags;
+ const char * usri22_full_name;
+ const char * usri22_usr_comment;
+ const char * usri22_parms;
+ const char * usri22_workstations;
+ uint32_t usri22_last_logon;
+ uint32_t usri22_last_logoff;
+ uint32_t usri22_acct_expires;
+ uint32_t usri22_max_storage;
+ uint32_t usri22_units_per_week;
+ uint8_t *usri22_logon_hours;/* [unique] */
+ uint32_t usri22_bad_pw_count;
+ uint32_t usri22_num_logons;
+ const char * usri22_logon_server;
+ uint32_t usri22_country_code;
+ uint32_t usri22_code_page;
+};
+
+struct USER_INFO_23 {
+ const char * usri23_name;
+ const char * usri23_full_name;
+ const char * usri23_comment;
+ uint32_t usri23_flags;
+ struct domsid *usri23_user_sid;/* [unique] */
+};
+
+struct USER_INFO_1003 {
+ const char * usri1003_password;
+};
+
+struct USER_INFO_1005 {
+ uint32_t usri1005_priv;
+};
+
+struct USER_INFO_1006 {
+ const char * usri1006_home_dir;
+};
+
+struct USER_INFO_1007 {
+ const char * usri1007_comment;
+};
+
+struct USER_INFO_1008 {
+ uint32_t usri1008_flags;
+};
+
+struct USER_INFO_1009 {
+ const char * usri1009_script_path;
+};
+
+struct USER_INFO_1010 {
+ uint32_t usri1010_auth_flags;
+};
+
+struct USER_INFO_1011 {
+ const char * usri1011_full_name;
+};
+
+struct USER_INFO_1012 {
+ const char * usri1012_usr_comment;
+};
+
+struct USER_INFO_1013 {
+ const char * usri1013_parms;
+};
+
+struct USER_INFO_1014 {
+ const char * usri1014_workstations;
+};
+
+struct USER_INFO_1017 {
+ uint32_t usri1017_acct_expires;
+};
+
+struct USER_INFO_1018 {
+ uint32_t usri1018_max_storage;
+};
+
+struct USER_INFO_1020 {
+ uint32_t usri1020_units_per_week;
+ uint8_t *usri1020_logon_hours;/* [unique] */
+};
+
+struct USER_INFO_1023 {
+ const char * usri1023_logon_server;
+};
+
+struct USER_INFO_1024 {
+ uint32_t usri1024_country_code;
+};
+
+struct USER_INFO_1025 {
+ uint32_t usri1025_code_page;
+};
+
+struct USER_INFO_1051 {
+ uint32_t usri1051_primary_group_id;
+};
+
+struct USER_INFO_1052 {
+ const char * usri1052_profile;
+};
+
+struct USER_INFO_1053 {
+ const char * usri1053_home_dir_drive;
+};
+
+struct USER_MODALS_INFO_0 {
+ uint32_t usrmod0_min_passwd_len;
+ uint32_t usrmod0_max_passwd_age;
+ uint32_t usrmod0_min_passwd_age;
+ uint32_t usrmod0_force_logoff;
+ uint32_t usrmod0_password_hist_len;
+};
+
+struct USER_MODALS_INFO_1 {
+ uint32_t usrmod1_role;
+ const char * usrmod1_primary;
+};
+
+struct USER_MODALS_INFO_2 {
+ const char * usrmod2_domain_name;
+ struct domsid *usrmod2_domain_id;/* [unique] */
+};
+
+struct USER_MODALS_INFO_3 {
+ uint32_t usrmod3_lockout_duration;
+ uint32_t usrmod3_lockout_observation_window;
+ uint32_t usrmod3_lockout_threshold;
+};
+
+struct USER_MODALS_INFO_1001 {
+ uint32_t usrmod1001_min_passwd_len;
+};
+
+struct USER_MODALS_INFO_1002 {
+ uint32_t usrmod1002_max_passwd_age;
+};
+
+struct USER_MODALS_INFO_1003 {
+ uint32_t usrmod1003_min_passwd_age;
+};
+
+struct USER_MODALS_INFO_1004 {
+ uint32_t usrmod1004_force_logoff;
+};
+
+struct USER_MODALS_INFO_1005 {
+ uint32_t usrmod1005_password_hist_len;
+};
+
+struct USER_MODALS_INFO_1006 {
+ uint32_t usrmod1006_role;
+};
+
+struct USER_MODALS_INFO_1007 {
+ const char * usrmod1007_primary;
+};
+
+struct NET_DISPLAY_USER {
+ const char * usri1_name;
+ const char * usri1_comment;
+ uint32_t usri1_flags;
+ const char * usri1_full_name;
+ uint32_t usri1_user_id;
+ uint32_t usri1_next_index;
+};
+
+struct NET_DISPLAY_MACHINE {
+ const char * usri2_name;
+ const char * usri2_comment;
+ uint32_t usri2_flags;
+ uint32_t usri2_user_id;
+ uint32_t usri2_next_index;
+};
+
+struct NET_DISPLAY_GROUP {
+ const char * grpi3_name;
+ const char * grpi3_comment;
+ uint32_t grpi3_group_id;
+ uint32_t grpi3_attributes;
+ uint32_t grpi3_next_index;
+};
+
+struct GROUP_INFO_0 {
+ const char * grpi0_name;
+};
+
+struct GROUP_INFO_1 {
+ const char * grpi1_name;
+ const char * grpi1_comment;
+};
+
+struct GROUP_INFO_2 {
+ const char * grpi2_name;
+ const char * grpi2_comment;
+ uint32_t grpi2_group_id;
+ uint32_t grpi2_attributes;
+};
+
+struct GROUP_INFO_3 {
+ const char * grpi3_name;
+ const char * grpi3_comment;
+ struct domsid * grpi3_group_sid;
+ uint32_t grpi3_attributes;
+};
+
+struct GROUP_INFO_1002 {
+ const char * grpi1002_comment;
+};
+
+struct GROUP_INFO_1005 {
+ uint32_t grpi1005_attributes;
+};
+
+struct GROUP_USERS_INFO_0 {
+ const char * grui0_name;
+};
+
+struct GROUP_USERS_INFO_1 {
+ const char * grui1_name;
+ uint32_t grui1_attributes;
+};
+
+struct LOCALGROUP_INFO_0 {
+ const char * lgrpi0_name;
+};
+
+struct LOCALGROUP_INFO_1 {
+ const char * lgrpi1_name;
+ const char * lgrpi1_comment;
+};
+
+struct LOCALGROUP_INFO_1002 {
+ const char * lgrpi1002_comment;
+};
+
+enum SID_NAME_USE {
+ SidTypeUser=1,
+ SidTypeGroup=2,
+ SidTypeDomain=3,
+ SidTypeAlias=4,
+ SidTypeWellKnownGroup=5,
+ SidTypeDeletedAccount=6,
+ SidTypeInvalid=7,
+ SidTypeUnknown=8,
+ SidTypeComputer=9,
+ SidTypeLabel=10
+};
+
+struct LOCALGROUP_MEMBERS_INFO_0 {
+ struct domsid *lgrmi0_sid;/* [unique] */
+};
+
+struct LOCALGROUP_MEMBERS_INFO_1 {
+ struct domsid *lgrmi1_sid;/* [unique] */
+ enum SID_NAME_USE lgrmi1_sidusage;
+ const char * lgrmi1_name;
+};
+
+struct LOCALGROUP_MEMBERS_INFO_2 {
+ struct domsid *lgrmi2_sid;/* [unique] */
+ enum SID_NAME_USE lgrmi2_sidusage;
+ const char * lgrmi2_domainandname;
+};
+
+struct LOCALGROUP_MEMBERS_INFO_3 {
+ const char * lgrmi3_domainandname;
+};
+
+struct LOCALGROUP_USERS_INFO_0 {
+ const char * lgrui0_name;
+};
+
+struct TIME_OF_DAY_INFO {
+ uint32_t tod_elapsedt;
+ uint32_t tod_msecs;
+ uint32_t tod_hours;
+ uint32_t tod_mins;
+ uint32_t tod_secs;
+ uint32_t tod_hunds;
+ int32_t tod_timezone;
+ uint32_t tod_tinterval;
+ uint32_t tod_day;
+ uint32_t tod_month;
+ uint32_t tod_year;
+ uint32_t tod_weekday;
+};
+
+struct SHARE_INFO_0 {
+ const char * shi0_netname;
+};
+
+struct SHARE_INFO_1 {
+ const char * shi1_netname;
+ uint32_t shi1_type;
+ const char * shi1_remark;
+};
+
+struct SHARE_INFO_2 {
+ const char * shi2_netname;
+ uint32_t shi2_type;
+ const char * shi2_remark;
+ uint32_t shi2_permissions;
+ uint32_t shi2_max_uses;
+ uint32_t shi2_current_uses;
+ const char * shi2_path;
+ const char * shi2_passwd;
+};
+
+struct SHARE_INFO_501 {
+ const char * shi501_netname;
+ uint32_t shi501_type;
+ const char * shi501_remark;
+ uint32_t shi501_flags;
+};
+
+struct SHARE_INFO_1004 {
+ const char * shi1004_remark;
+};
+
+struct SHARE_INFO_1005 {
+ uint32_t shi1005_flags;
+};
+
+struct SHARE_INFO_1006 {
+ uint32_t shi1006_max_uses;
+};
+
+struct FILE_INFO_2 {
+ uint32_t fi2_id;
+};
+
+struct FILE_INFO_3 {
+ uint32_t fi3_id;
+ uint32_t fi3_permissions;
+ uint32_t fi3_num_locks;
+ const char * fi3_pathname;
+ const char * fi3_username;
+};
+
+#endif /* _HEADER_libnetapi */
+
+/****************************************************************
+****************************************************************/
+
+struct libnetapi_ctx {
+ char *debuglevel;
+ char *error_string;
+ char *username;
+ char *workgroup;
+ char *password;
+ char *krb5_cc_env;
+ int use_kerberos;
+ int disable_policy_handle_cache;
+
+ void *private_data;
+};
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_init(struct libnetapi_ctx **ctx);
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_free(struct libnetapi_ctx *ctx);
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_getctx(struct libnetapi_ctx **ctx);
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_set_debuglevel(struct libnetapi_ctx *ctx,
+ const char *debuglevel);
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_set_username(struct libnetapi_ctx *ctx,
+ const char *username);
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_set_password(struct libnetapi_ctx *ctx,
+ const char *password);
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_set_workgroup(struct libnetapi_ctx *ctx,
+ const char *workgroup);
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_set_use_kerberos(struct libnetapi_ctx *ctx);
+
+/****************************************************************
+****************************************************************/
+
+const char *libnetapi_errstr(NET_API_STATUS status);
+
+/****************************************************************
+****************************************************************/
+
+const char *libnetapi_get_error_string(struct libnetapi_ctx *ctx,
+ NET_API_STATUS status);
+
+/****************************************************************
+ NetApiBufferAllocate
+****************************************************************/
+
+NET_API_STATUS NetApiBufferAllocate(uint32_t byte_count,
+ void **buffer);
+
+/****************************************************************
+ NetApiBufferFree
+****************************************************************/
+
+NET_API_STATUS NetApiBufferFree(void *buffer);
+
+/************************************************************//**
+ *
+ * ConvertSidToStringSid
+ *
+ * @brief Convert a domain sid into a string
+ *
+ * @param[in] sid A pointer to a sid structure
+ * @param[in,out] sid_string A pointer that holds a pointer to a sid string. Caller
+ * needs to free with free(3)
+ * @return bool
+ ***************************************************************/
+
+int ConvertSidToStringSid(const struct domsid *sid,
+ char **sid_string);
+
+/************************************************************//**
+ *
+ * ConvertStringSidToSid
+ *
+ * @brief Convert a string into a domain sid
+ *
+ * @param[in] sid_string A pointer to a sid string.
+ * @param[in,out] sid A pointer that holds a pointer to a sid structure.
+ * Caller needs to free with free(3)
+ * @return bool
+ ***************************************************************/
+
+int ConvertStringSidToSid(const char *sid_string,
+ struct domsid **sid);
+
+/************************************************************//**
+ *
+ * NetJoinDomain
+ *
+ * @brief Join a computer to a domain or workgroup
+ *
+ * @param[in] server The server name to connect to
+ * @param[in] domain The domain or workgroup to join
+ * @param[in] account_ou The organizational Unit to create the computer account
+ * in (AD only)
+ * @param[in] account The domain account used for joining a domain
+ * @param[in] password The domain account's password used for joining a domain
+ * @param[in] join_flags Bitmask field to define specific join features
+ * @return NET_API_STATUS
+ *
+ * example netdomjoin/netdomjoin.c
+ ***************************************************************/
+
+NET_API_STATUS NetJoinDomain(const char * server /* [in] */,
+ const char * domain /* [in] [ref] */,
+ const char * account_ou /* [in] */,
+ const char * account /* [in] */,
+ const char * password /* [in] */,
+ uint32_t join_flags /* [in] */);
+
+/************************************************************//**
+ *
+ * NetUnjoinDomain
+ *
+ * @brief Unjoin a computer from a domain or workgroup
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] account The domain account used for unjoining a domain
+ * @param[in] password The domain account's password used for unjoining a domain
+ * @param[in] unjoin_flags Bitmask field to define specific unjoin features
+ * @return NET_API_STATUS
+ *
+ ***************************************************************/
+
+NET_API_STATUS NetUnjoinDomain(const char * server_name /* [in] */,
+ const char * account /* [in] */,
+ const char * password /* [in] */,
+ uint32_t unjoin_flags /* [in] */);
+
+/************************************************************//**
+ *
+ * NetGetJoinInformation
+ *
+ * @brief Unjoin a computer from a domain or workgroup
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[out] name_buffer Returns the name of the workgroup or domain
+ * @param[out] name_type Returns the type of that name
+ * @return NET_API_STATUS
+ *
+ * example netdomjoin-gui/netdomjoin-gui.c
+ *
+ ***************************************************************/
+
+NET_API_STATUS NetGetJoinInformation(const char * server_name /* [in] */,
+ const char * *name_buffer /* [out] [ref] */,
+ uint16_t *name_type /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetGetJoinableOUs
+ *
+ * @brief Query for the list of joinable organizational Units that can be used
+ * for joining AD
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] domain The AD domain to query
+ * @param[in] account The domain account used for the query
+ * @param[in] password The domain account's password used for the query
+ * @param[out] ou_count The number of ous returned
+ * @param[out] ous Returned string array containing the ous
+ * @return NET_API_STATUS
+ *
+ * example netdomjoin-gui/netdomjoin-gui.c
+ *
+ ***************************************************************/
+
+NET_API_STATUS NetGetJoinableOUs(const char * server_name /* [in] */,
+ const char * domain /* [in] [ref] */,
+ const char * account /* [in] */,
+ const char * password /* [in] */,
+ uint32_t *ou_count /* [out] [ref] */,
+ const char * **ous /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetRenameMachineInDomain
+ *
+ * @brief Rename a machine in a domain
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] new_machine_name The new machine name
+ * @param[in] account The domain account used for the query
+ * @param[in] password The domain account's password used for the query
+ * @param[in] rename_options Options used for the rename operation
+ * @return NET_API_STATUS
+ *
+ * example join/rename_machine.c
+ *
+ ***************************************************************/
+
+NET_API_STATUS NetRenameMachineInDomain(const char * server_name /* [in] */,
+ const char * new_machine_name /* [in] */,
+ const char * account /* [in] */,
+ const char * password /* [in] */,
+ uint32_t rename_options /* [in] */);
+
+/************************************************************//**
+ *
+ * NetServerGetInfo
+ *
+ * @brief Get Information on a server
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] level The level to define which information is requested
+ * @param[out] buffer The returned buffer carrying the SERVER_INFO structure
+ * @return NET_API_STATUS
+ *
+ ***************************************************************/
+
+NET_API_STATUS NetServerGetInfo(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetServerSetInfo
+ *
+ * @brief Get Information on a server
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] level The level to define which information is set
+ * @param[in] buffer The buffer carrying the SERVER_INFO structure
+ * @param[out] parm_error On failure returns the invalid SERVER_INFO member
+ * @return NET_API_STATUS
+ *
+ ***************************************************************/
+
+NET_API_STATUS NetServerSetInfo(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_error /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetGetDCName
+ *
+ * @brief Query for the PDC for a given domain
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] domain_name The name of the domain to lookup
+ * @param[out] buffer The name of the domain to lookup
+ * @return NET_API_STATUS
+ *
+ * example getdc/getdc.c
+ ***************************************************************/
+
+NET_API_STATUS NetGetDCName(const char * server_name /* [in] */,
+ const char * domain_name /* [in] */,
+ uint8_t **buffer /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetGetAnyDCName
+ *
+ * @brief Query for any DC for a given domain
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] domain_name The name of the domain to lookup
+ * @param[out] buffer The name of the domain to lookup
+ * @return NET_API_STATUS
+ *
+ * example getdc/getdc.c
+ ***************************************************************/
+
+NET_API_STATUS NetGetAnyDCName(const char * server_name /* [in] */,
+ const char * domain_name /* [in] */,
+ uint8_t **buffer /* [out] [ref] */);
+
+
+/************************************************************//**
+ *
+ * DsGetDcName
+ *
+ * @brief Lookup a DC for a given domain and return information structure
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] domain_name The name of the domain to lookup (cannot be NULL)
+ * @param[in] domain_guid The GUID of the domain to lookup (optional)
+ * @param[in] site_name The name of the site the DC should reside in
+ * @param[in] flags A bitmask to request specific features supported by the DC
+ * @param[out] dc_info Pointer to a DOMAIN_CONTROLLER_INFO structure
+ * @return NET_API_STATUS
+ *
+ * example dsgetdc/dsgetdc.c
+ ***************************************************************/
+
+NET_API_STATUS DsGetDcName(const char * server_name /* [in] [unique] */,
+ const char * domain_name /* [in] [ref] */,
+ struct GUID *domain_guid /* [in] [unique] */,
+ const char * site_name /* [in] [unique] */,
+ uint32_t flags /* [in] */,
+ struct DOMAIN_CONTROLLER_INFO **dc_info /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetUserAdd
+ *
+ * @brief Create a user on a given server
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] level The level of the USER_INFO structure passed in (Currently
+ * only level 1 is supported)
+ * @param[in] buffer The buffer carrying the USER_INFO structure
+ * @param[out] parm_error In case of error returns the failing member of the
+ * structure
+ * @return NET_API_STATUS
+ *
+ * example user/user_add.c
+ ***************************************************************/
+
+NET_API_STATUS NetUserAdd(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_error /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetUserDel
+ *
+ * @brief Delete a user on a given server
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] user_name The user account to delete
+ * @return NET_API_STATUS
+ *
+ * example user/user_del.c
+ ***************************************************************/
+
+NET_API_STATUS NetUserDel(const char * server_name /* [in] */,
+ const char * user_name /* [in] */);
+
+/************************************************************//**
+ *
+ * NetUserEnum
+ *
+ * @brief Enumerate accounts on a server
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] level The enumeration level used for the query (Currently only
+ * level 0 is supported)
+ * @param[in] filter The account flags filter used for the query
+ * @param[out] buffer The returned enumeration buffer
+ * @param[in] prefmaxlen The requested maximal buffer size
+ * @param[out] entries_read The number of returned entries
+ * @param[out] total_entries The number of total entries
+ * @param[in,out] resume_handle A handle passed in and returned for resuming
+ * operations
+ * @return NET_API_STATUS
+ *
+ * example user/user_enum.c
+ ***************************************************************/
+
+NET_API_STATUS NetUserEnum(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint32_t filter /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetUserChangePassword
+ *
+ * @brief Change the password for a user on a given server or in a given domain
+ *
+ * @param[in] domain_name The server or domain name to connect to
+ * @param[in] user_name The user account to change the password for
+ * @param[in] old_password The user account's old password
+ * @param[in] new_password The user account's new password
+ * @return NET_API_STATUS
+ *
+ * example user/user_chgpwd.c
+ ***************************************************************/
+
+NET_API_STATUS NetUserChangePassword(const char * domain_name /* [in] */,
+ const char * user_name /* [in] */,
+ const char * old_password /* [in] */,
+ const char * new_password /* [in] */);
+
+/************************************************************//**
+ *
+ * NetUserGetInfo
+ *
+ * @brief Get User Information
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] user_name The name of the user that is going to be queried
+ * @param[in] level The level defining the requested USER_INFO_X structure
+ * @param[out] buffer The buffer containing a USER_INFO_X structure
+ * @return NET_API_STATUS
+ *
+ * example user/user_getinfo.c
+ ***************************************************************/
+
+NET_API_STATUS NetUserGetInfo(const char * server_name /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetUserSetInfo
+ *
+ * @brief Set User Information
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] user_name The name of the user that is going to be modified
+ * @param[in] level The level defining the requested USER_INFO_X structure
+ * @param[in] buffer The buffer containing a USER_INFO_X structure
+ * @param[out] parm_err The returned parameter error number if any
+ * @return NET_API_STATUS
+ *
+ * example user/user_setinfo.c
+ ***************************************************************/
+
+NET_API_STATUS NetUserSetInfo(const char * server_name /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetUserModalsGet
+ *
+ * @brief Get SAM domain and password information
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] level The level defining which USER_MODALS_INFO_X buffer to query
+ * @param[out] buffer The returned USER_MODALS_INFO_X buffer
+ * @return NET_API_STATUS
+ *
+ * example user/user_modalsget.c
+ ***************************************************************/
+
+NET_API_STATUS NetUserModalsGet(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetUserModalsSet
+ *
+ * @brief Set SAM domain and password information
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] level The level defining which USER_MODALS_INFO_X buffer to query
+ * @param[out] buffer The buffer conntaing a USER_MODALS_INFO_X structure
+ * @param[out] parm_err The returned parameter error number if any
+ * @return NET_API_STATUS
+ *
+ * example user/user_modalsset.c
+ ***************************************************************/
+
+NET_API_STATUS NetUserModalsSet(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetUserGetGroups
+ *
+ * @brief Enumerate grouplist of a user on a server
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] user_name The user name to query
+ * @param[in] level The enumeration level used for the query (Currently only
+ * level 0 is supported)
+ * @param[out] buffer The returned enumeration buffer
+ * @param[in] prefmaxlen The requested maximal buffer size
+ * @param[out] entries_read The number of returned entries
+ * @param[out] total_entries The number of total entries
+ * @return NET_API_STATUS
+ *
+ * example user/user_getgroups.c
+ ***************************************************************/
+
+NET_API_STATUS NetUserGetGroups(const char * server_name /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetUserSetGroups
+ *
+ * @brief Set grouplist of a user on a server
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] user_name The user name to query
+ * @param[in] level The level defining the GROUP_USERS_INFO_X structures in the buffer
+ * @param[in] buffer The buffer containing GROUP_USERS_INFO_X structures
+ * @param[in] num_entries The number of X structures in the buffer
+ * @return NET_API_STATUS
+ *
+ * example user/user_setgroups.c
+ ***************************************************************/
+
+NET_API_STATUS NetUserSetGroups(const char * server_name /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t num_entries /* [in] */);
+
+/************************************************************//**
+ *
+ * NetUserGetLocalGroups
+ *
+ * @brief Enumerate local grouplist of a user on a server
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] user_name The user name to query
+ * @param[in] level The enumeration level used for the query
+ * @param[in] flags The flags used for the query
+ * @param[out] buffer The returned enumeration buffer
+ * @param[in] prefmaxlen The requested maximal buffer size
+ * @param[out] entries_read The number of returned entries
+ * @param[out] total_entries The number of total entries
+ * @return NET_API_STATUS
+ *
+ * example user/user_getlocalgroups.c
+ ***************************************************************/
+
+NET_API_STATUS NetUserGetLocalGroups(const char * server_name /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint32_t flags /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetQueryDisplayInformation
+ *
+ * @brief Enumerate accounts on a server
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] level The enumeration level used for the query
+ * @param[in] idx The index to start the the display enumeration at
+ * @param[in] entries_requested The number of entries requested
+ * @param[in] prefmaxlen The requested maximal buffer size
+ * @param[out] entries_read The number of returned entries
+ * @param[out] buffer The returned display information buffer
+ * @return NET_API_STATUS
+ *
+ * example user/user_dispinfo.c
+ ***************************************************************/
+
+NET_API_STATUS NetQueryDisplayInformation(const char * server_name /* [in] [unique] */,
+ uint32_t level /* [in] */,
+ uint32_t idx /* [in] */,
+ uint32_t entries_requested /* [in] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ void **buffer /* [out] [noprint,ref] */);
+
+/************************************************************//**
+ *
+ * NetGroupAdd
+ *
+ * @brief Create Domain Group
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] level The level used for the new group creation
+ * @param[in] buf The buffer containing the group structure
+ * @param[out] parm_err The returned parameter error number if any
+ * @return NET_API_STATUS
+ *
+ * example group/group_add.c
+ ***************************************************************/
+
+NET_API_STATUS NetGroupAdd(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buf /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetGroupDel
+ *
+ * @brief Delete Domain Group
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] group_name The name of the group that is going to be deleted
+ * @return NET_API_STATUS
+ *
+ * example group/group_del.c
+ ***************************************************************/
+
+NET_API_STATUS NetGroupDel(const char * server_name /* [in] */,
+ const char * group_name /* [in] */);
+
+/************************************************************//**
+ *
+ * NetGroupEnum
+ *
+ * @brief Enumerate groups on a server
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] level The enumeration level used for the query (Currently only
+ * level 0 is supported)
+ * @param[out] buffer The returned enumeration buffer
+ * @param[in] prefmaxlen The requested maximal buffer size
+ * @param[out] entries_read The number of returned entries
+ * @param[out] total_entries The number of total entries
+ * @param[in,out] resume_handle A handle passed in and returned for resuming
+ * operations
+ * @return NET_API_STATUS
+ *
+ * example group/group_enum.c
+ ***************************************************************/
+
+NET_API_STATUS NetGroupEnum(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetGroupSetInfo
+ *
+ * @brief Set Domain Group Information
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] group_name The name of the group that is going to be modified
+ * @param[in] level The level defining the structure type in buf
+ * @param[in] buf The buffer containing a GROUP_INFO_X structure
+ * @param[out] parm_err The returned parameter error number if any
+ * @return NET_API_STATUS
+ *
+ * example group/group_setinfo.c
+ ***************************************************************/
+
+NET_API_STATUS NetGroupSetInfo(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buf /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetGroupGetInfo
+ *
+ * @brief Get Domain Group Information
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] group_name The name of the group that is going to be queried
+ * @param[in] level The level defining the requested GROUP_INFO_X structure
+ * @param[out] buf The buffer containing a GROUP_INFO_X structure
+ * @return NET_API_STATUS
+ *
+ * example group/group_getinfo.c
+ ***************************************************************/
+
+NET_API_STATUS NetGroupGetInfo(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buf /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetGroupAddUser
+ *
+ * @brief Add existing User to existing Domain Group
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] group_name The name of the group that is going to be modified
+ * @param[in] user_name The name of the user that is going to be added to the
+ * group
+ * @return NET_API_STATUS
+ *
+ * example group/group_adduser.c
+ ***************************************************************/
+
+NET_API_STATUS NetGroupAddUser(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ const char * user_name /* [in] */);
+
+/************************************************************//**
+ *
+ * NetGroupDelUser
+ *
+ * @brief Remove User from Domain Group
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] group_name The name of the group that is going to be modified
+ * @param[in] user_name The name of the user that is going to be removed from
+ * the group
+ * @return NET_API_STATUS
+ *
+ * example group/group_deluser.c
+ ***************************************************************/
+
+NET_API_STATUS NetGroupDelUser(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ const char * user_name /* [in] */);
+
+/************************************************************//**
+ *
+ * NetGroupGetUsers
+ *
+ * @brief Get Users for a group on a server
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] group_name The group name to enumerate users for
+ * @param[in] level The enumeration level used for the query
+ * @param[out] buffer The returned enumeration buffer
+ * @param[in] prefmaxlen The requested maximal buffer size
+ * @param[out] entries_read The number of returned entries
+ * @param[out] total_entries The number of total entries
+ * @param[in,out] resume_handle A handle passed in and returned for resuming
+ * operations
+ * @return NET_API_STATUS
+ *
+ * example group/group_getusers.c
+ ***************************************************************/
+
+NET_API_STATUS NetGroupGetUsers(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetGroupSetUsers
+ *
+ * @brief Set Users for a group on a server
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] group_name The group name to enumerate users for
+ * @param[in] level The enumeration level used for the query
+ * @param[in] buffer The buffer containing a X structure
+ * @param[in] num_entries The number of X entries in the buffer
+ * @return NET_API_STATUS
+ *
+ * example group/group_setusers.c
+ ***************************************************************/
+
+NET_API_STATUS NetGroupSetUsers(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t num_entries /* [in] */);
+
+/************************************************************//**
+ *
+ * NetLocalGroupAdd
+ *
+ * @brief Create Local Group
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] level The level used for the new group creation
+ * @param[in] buf The buffer containing the group structure
+ * @param[out] parm_err The returned parameter error number if any
+ * @return NET_API_STATUS
+ *
+ * example localgroup/localgroup_add.c
+ ***************************************************************/
+
+NET_API_STATUS NetLocalGroupAdd(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buf /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetLocalGroupDel
+ *
+ * @brief Delete Local Group
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] group_name The name of the group that is going to be deleted
+ * @return NET_API_STATUS
+ *
+ * example localgroup/localgroup_del.c
+ ***************************************************************/
+
+
+NET_API_STATUS NetLocalGroupDel(const char * server_name /* [in] */,
+ const char * group_name /* [in] */);
+
+/************************************************************//**
+ *
+ * NetLocalGroupGetInfo
+ *
+ * @brief Get Local Group Information
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] group_name The name of the group that is going to be queried
+ * @param[in] level The level defining the requested LOCALGROUP_INFO_X structure
+ * @param[out] buf The buffer containing a LOCALGROUP_INFO_X structure
+ * @return NET_API_STATUS
+ *
+ * example localgroup/localgroup_getinfo.c
+ ***************************************************************/
+
+NET_API_STATUS NetLocalGroupGetInfo(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buf /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetLocalGroupSetInfo
+ *
+ * @brief Set Local Group Information
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] group_name The name of the group that is going to be modified
+ * @param[in] level The level defining the requested LOCALGROUP_INFO_X structure
+ * @param[in] buf The buffer containing a LOCALGROUP_INFO_X structure
+ * @param[out] parm_err The returned parameter error number if any
+ * @return NET_API_STATUS
+ *
+ * example localgroup/localgroup_setinfo.c
+ ***************************************************************/
+
+
+NET_API_STATUS NetLocalGroupSetInfo(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buf /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetLocalGroupEnum
+ *
+ * @brief Enumerate local groups on a server
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] level The enumeration level used for the query (Currently only
+ * level 0 is supported)
+ * @param[out] buffer The returned enumeration buffer
+ * @param[in] prefmaxlen The requested maximal buffer size
+ * @param[out] entries_read The number of returned entries
+ * @param[out] total_entries The number of total entries
+ * @param[in,out] resume_handle A handle passed in and returned for resuming
+ * operations
+ * @return NET_API_STATUS
+ *
+ * example localgroup/localgroup_enum.c
+ ***************************************************************/
+
+NET_API_STATUS NetLocalGroupEnum(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetLocalGroupAddMembers
+ *
+ * @brief Add Members to a Local Group
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] group_name The name of the group that is going to modified
+ * @param[in] level The level defining the LOCALGROUP_MEMBERS_INFO_X structure
+ * @param[in] buffer The buffer containing a LOCALGROUP_MEMBERS_INFO_X structure
+ * @param[in] total_entries The number of LOCALGROUP_MEMBERS_INFO_X entries in
+ * the buffer
+ * @return NET_API_STATUS
+ *
+ * example localgroup/localgroup_addmembers.c
+ ***************************************************************/
+
+NET_API_STATUS NetLocalGroupAddMembers(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t total_entries /* [in] */);
+
+/************************************************************//**
+ *
+ * NetLocalGroupDelMembers
+ *
+ * @brief Delete Members from a Local Group
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] group_name The name of the group that is going to modified
+ * @param[in] level The level defining the LOCALGROUP_MEMBERS_INFO_X structure
+ * @param[in] buffer The buffer containing a LOCALGROUP_MEMBERS_INFO_X structure
+ * @param[in] total_entries The number of LOCALGROUP_MEMBERS_INFO_X entries in
+ * the buffer
+ * @return NET_API_STATUS
+ *
+ * example localgroup/localgroup_delmembers.c
+ ***************************************************************/
+
+NET_API_STATUS NetLocalGroupDelMembers(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t total_entries /* [in] */);
+
+/************************************************************//**
+ *
+ * NetLocalGroupGetMembers
+ *
+ * @brief Enumerate Members in a local group
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] local_group_name The localgroup that is going to be queried
+ * @param[in] level The level defining the LOCALGROUP_MEMBERS_INFO_X structure
+ * @param[out] buffer The buffer containing a LOCALGROUP_MEMBERS_INFO_X
+ * structure
+ * @param[in] prefmaxlen The requested maximal buffer size
+ * @param[out] entries_read The number of LOCALGROUP_MEMBERS_INFO_X entries in the buffer
+ * @param[out] total_entries The total number of LOCALGROUP_MEMBERS_INFO_X entries for that group
+ * @param[in,out] resume_handle A handle passed in and returned for resuming
+ * operations
+ * @return NET_API_STATUS
+ *
+ * example localgroup/localgroup_getmembers.c
+ ***************************************************************/
+
+NET_API_STATUS NetLocalGroupGetMembers(const char * server_name /* [in] */,
+ const char * local_group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetLocalGroupSetMembers
+ *
+ * @brief Set Members in a Local Group
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] group_name The name of the group that is going to modified
+ * @param[in] level The level defining the LOCALGROUP_MEMBERS_INFO_X structure
+ * @param[in] buffer The buffer containing a LOCALGROUP_MEMBERS_INFO_X structure
+ * @param[in] total_entries The number of LOCALGROUP_MEMBERS_INFO_X entries in
+ * the buffer
+ * @return NET_API_STATUS
+ *
+ * example localgroup/localgroup_setmembers.c
+ ***************************************************************/
+
+NET_API_STATUS NetLocalGroupSetMembers(const char * server_name /* [in] */,
+ const char * group_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t total_entries /* [in] */);
+
+/************************************************************//**
+ *
+ * NetRemoteTOD
+ *
+ * @brief Query remote Time of Day
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[out] buf The buffer containing a TIME_OF_DAY_INFO structure
+ * @return NET_API_STATUS
+ *
+ * example server/remote_tod.c
+ ***************************************************************/
+
+NET_API_STATUS NetRemoteTOD(const char * server_name /* [in] */,
+ uint8_t **buf /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetShareAdd
+ *
+ * @brief Add Share
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] level The level defining the requested SHARE_INFO_X structure
+ * @param[in] buffer The buffer containing a SHARE_INFO_X structure
+ * @param[out] parm_err The returned parameter error number if any
+ * @return NET_API_STATUS
+ *
+ * example share/share_add.c
+ ***************************************************************/
+
+NET_API_STATUS NetShareAdd(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetShareDel
+ *
+ * @brief Delete Share
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] net_name The name of the share to delete
+ * @param[in] reserved
+ * @return NET_API_STATUS
+ *
+ * example share/share_del.c
+ ***************************************************************/
+
+NET_API_STATUS NetShareDel(const char * server_name /* [in] */,
+ const char * net_name /* [in] */,
+ uint32_t reserved /* [in] */);
+
+/************************************************************//**
+ *
+ * NetShareEnum
+ *
+ * @brief Enumerate Shares
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] level The level defining the SHARE_INFO_X structure
+ * @param[out] buffer The buffer containing a SHARE_INFO_X structure
+ * @param[in] prefmaxlen The requested maximal buffer size
+ * @param[out] entries_read The number of SHARE_INFO_X entries in the buffer
+ * @param[out] total_entries The total number of SHARE_INFO_X entries
+ * @param[in,out] resume_handle A handle passed in and returned for resuming
+ * operations
+ * @return NET_API_STATUS
+ *
+ * example share/share_enum.c
+ ***************************************************************/
+
+NET_API_STATUS NetShareEnum(const char * server_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetShareGetInfo
+ *
+ * @brief Get Share Info
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] net_name The name of the share to query
+ * @param[in] level The level defining the SHARE_INFO_X structure
+ * @param[out] buffer The buffer containing a SHARE_INFO_X structure
+ * @return NET_API_STATUS
+ *
+ * example share/share_getinfo.c
+ ***************************************************************/
+
+NET_API_STATUS NetShareGetInfo(const char * server_name /* [in] */,
+ const char * net_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetShareSetInfo
+ *
+ * @brief Set Share Info
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] net_name The name of the share to query
+ * @param[in] level The level defining the SHARE_INFO_X structure
+ * @param[in] buffer The buffer containing a SHARE_INFO_X structure
+ * @param[out] parm_err The returned parameter error number if any
+ * @return NET_API_STATUS
+ *
+ * example share/share_setinfo.c
+ ***************************************************************/
+
+NET_API_STATUS NetShareSetInfo(const char * server_name /* [in] */,
+ const char * net_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t *buffer /* [in] [ref] */,
+ uint32_t *parm_err /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetFileClose
+ *
+ * @brief Close a file
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] fileid The fileid of the file that is going to be closed
+ * @return NET_API_STATUS
+ *
+ * example file/file_close.c
+ ***************************************************************/
+
+NET_API_STATUS NetFileClose(const char * server_name /* [in] */,
+ uint32_t fileid /* [in] */);
+
+/************************************************************//**
+ *
+ * NetFileGetInfo
+ *
+ * @brief Close a file
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] fileid The fileid of the file that is going to be closed
+ * @param[in] level The level of the FILE_INFO_X buffer
+ * @param[out] buffer The buffer containing a FILE_INFO_X structure
+ * @return NET_API_STATUS
+ *
+ * example file/file_getinfo.c
+ ***************************************************************/
+
+NET_API_STATUS NetFileGetInfo(const char * server_name /* [in] */,
+ uint32_t fileid /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */);
+
+/************************************************************//**
+ *
+ * NetFileEnum
+ *
+ * @brief Enumerate Files
+ *
+ * @param[in] server_name The server name to connect to
+ * @param[in] base_path The
+ * @param[in] user_name The
+ * @param[in] level The level defining the FILE_INFO_X structure
+ * @param[out] buffer The buffer containing a FILE_INFO_X structure
+ * @param[in] prefmaxlen The requested maximal buffer size
+ * @param[out] entries_read The number of FILE_INFO_X entries in the buffer
+ * @param[out] total_entries The total number of FILE_INFO_X entries
+ * @param[in,out] resume_handle A handle passed in and returned for resuming
+ * operations
+ * @return NET_API_STATUS
+ *
+ * example file/file_enum.c
+ ***************************************************************/
+
+NET_API_STATUS NetFileEnum(const char * server_name /* [in] */,
+ const char * base_path /* [in] */,
+ const char * user_name /* [in] */,
+ uint32_t level /* [in] */,
+ uint8_t **buffer /* [out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __LIB_NETAPI_H__ */
diff --git a/source3/lib/netapi/netapi_private.h b/source3/lib/netapi/netapi_private.h
new file mode 100644
index 0000000000..e6a2eb8e99
--- /dev/null
+++ b/source3/lib/netapi/netapi_private.h
@@ -0,0 +1,87 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi Support
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_NETAPI_PRIVATE_H__
+#define __LIB_NETAPI_PRIVATE_H__
+
+#define LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, fn) \
+ DEBUG(10,("redirecting call %s to localhost\n", #fn)); \
+ if (!r->in.server_name) { \
+ r->in.server_name = "localhost"; \
+ } \
+ return fn ## _r(ctx, r);
+
+struct libnetapi_private_ctx {
+ struct {
+ const char *domain_name;
+ struct dom_sid *domain_sid;
+ struct rpc_pipe_client *cli;
+
+ uint32_t connect_mask;
+ struct policy_handle connect_handle;
+
+ uint32_t domain_mask;
+ struct policy_handle domain_handle;
+
+ uint32_t builtin_mask;
+ struct policy_handle builtin_handle;
+ } samr;
+
+};
+
+NET_API_STATUS libnetapi_get_password(struct libnetapi_ctx *ctx, char **password);
+NET_API_STATUS libnetapi_get_username(struct libnetapi_ctx *ctx, char **username);
+NET_API_STATUS libnetapi_set_error_string(struct libnetapi_ctx *ctx, const char *format, ...);
+NET_API_STATUS libnetapi_get_debuglevel(struct libnetapi_ctx *ctx, char **debuglevel);
+
+WERROR libnetapi_shutdown_cm(struct libnetapi_ctx *ctx);
+WERROR libnetapi_open_pipe(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const struct ndr_syntax_id *interface,
+ struct cli_state **pcli,
+ struct rpc_pipe_client **presult);
+WERROR libnetapi_samr_open_domain(struct libnetapi_ctx *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ uint32_t connect_mask,
+ uint32_t domain_mask,
+ struct policy_handle *connect_handle,
+ struct policy_handle *domain_handle,
+ struct dom_sid2 **domain_sid);
+WERROR libnetapi_samr_open_builtin_domain(struct libnetapi_ctx *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ uint32_t connect_mask,
+ uint32_t builtin_mask,
+ struct policy_handle *connect_handle,
+ struct policy_handle *builtin_handle);
+void libnetapi_samr_close_domain_handle(struct libnetapi_ctx *ctx,
+ struct policy_handle *handle);
+void libnetapi_samr_close_builtin_handle(struct libnetapi_ctx *ctx,
+ struct policy_handle *handle);
+void libnetapi_samr_close_connect_handle(struct libnetapi_ctx *ctx,
+ struct policy_handle *handle);
+void libnetapi_samr_free(struct libnetapi_ctx *ctx);
+
+NTSTATUS add_GROUP_USERS_INFO_X_buffer(TALLOC_CTX *mem_ctx,
+ uint32_t level,
+ const char *group_name,
+ uint32_t attributes,
+ uint8_t **buffer,
+ uint32_t *num_entries);
+
+#endif
diff --git a/source3/lib/netapi/samr.c b/source3/lib/netapi/samr.c
new file mode 100644
index 0000000000..dbcef38dc7
--- /dev/null
+++ b/source3/lib/netapi/samr.c
@@ -0,0 +1,319 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi Samr Support
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "lib/netapi/netapi.h"
+#include "lib/netapi/netapi_private.h"
+
+/****************************************************************
+****************************************************************/
+
+WERROR libnetapi_samr_open_domain(struct libnetapi_ctx *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ uint32_t connect_mask,
+ uint32_t domain_mask,
+ struct policy_handle *connect_handle,
+ struct policy_handle *domain_handle,
+ struct dom_sid2 **domain_sid)
+{
+ NTSTATUS status;
+ WERROR werr;
+ struct libnetapi_private_ctx *priv;
+ uint32_t resume_handle = 0;
+ uint32_t num_entries = 0;
+ struct samr_SamArray *sam = NULL;
+ const char *domain_name = NULL;
+ struct lsa_String lsa_domain_name;
+ bool domain_found = true;
+ int i;
+
+ priv = talloc_get_type_abort(mem_ctx->private_data,
+ struct libnetapi_private_ctx);
+
+ if (is_valid_policy_hnd(&priv->samr.connect_handle)) {
+ if ((priv->samr.connect_mask & connect_mask) == connect_mask) {
+ *connect_handle = priv->samr.connect_handle;
+ } else {
+ libnetapi_samr_close_connect_handle(mem_ctx,
+ &priv->samr.connect_handle);
+ }
+ }
+
+ if (is_valid_policy_hnd(&priv->samr.domain_handle)) {
+ if ((priv->samr.domain_mask & domain_mask) == domain_mask) {
+ *domain_handle = priv->samr.domain_handle;
+ } else {
+ libnetapi_samr_close_domain_handle(mem_ctx,
+ &priv->samr.domain_handle);
+ }
+ }
+
+ if (priv->samr.domain_sid) {
+ *domain_sid = priv->samr.domain_sid;
+ }
+
+ if (is_valid_policy_hnd(&priv->samr.connect_handle) &&
+ ((priv->samr.connect_mask & connect_mask) == connect_mask) &&
+ is_valid_policy_hnd(&priv->samr.domain_handle) &&
+ (priv->samr.domain_mask & domain_mask) == domain_mask) {
+ return WERR_OK;
+ }
+
+ if (!is_valid_policy_hnd(connect_handle)) {
+ status = rpccli_try_samr_connects(pipe_cli, mem_ctx,
+ connect_mask,
+ connect_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+
+ status = rpccli_samr_EnumDomains(pipe_cli, mem_ctx,
+ connect_handle,
+ &resume_handle,
+ &sam,
+ 0xffffffff,
+ &num_entries);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ for (i=0; i<num_entries; i++) {
+
+ domain_name = sam->entries[i].name.string;
+
+ if (strequal(domain_name, builtin_domain_name())) {
+ continue;
+ }
+
+ domain_found = true;
+ break;
+ }
+
+ if (!domain_found) {
+ werr = WERR_NO_SUCH_DOMAIN;
+ goto done;
+ }
+
+ init_lsa_String(&lsa_domain_name, domain_name);
+
+ status = rpccli_samr_LookupDomain(pipe_cli, mem_ctx,
+ connect_handle,
+ &lsa_domain_name,
+ domain_sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_OpenDomain(pipe_cli, mem_ctx,
+ connect_handle,
+ domain_mask,
+ *domain_sid,
+ domain_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ priv->samr.cli = pipe_cli;
+
+ priv->samr.domain_name = domain_name;
+ priv->samr.domain_sid = *domain_sid;
+
+ priv->samr.connect_mask = connect_mask;
+ priv->samr.connect_handle = *connect_handle;
+
+ priv->samr.domain_mask = domain_mask;
+ priv->samr.domain_handle = *domain_handle;
+
+ werr = WERR_OK;
+
+ done:
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR libnetapi_samr_open_builtin_domain(struct libnetapi_ctx *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ uint32_t connect_mask,
+ uint32_t builtin_mask,
+ struct policy_handle *connect_handle,
+ struct policy_handle *builtin_handle)
+{
+ NTSTATUS status;
+ WERROR werr;
+ struct libnetapi_private_ctx *priv;
+
+ priv = talloc_get_type_abort(mem_ctx->private_data,
+ struct libnetapi_private_ctx);
+
+ if (is_valid_policy_hnd(&priv->samr.connect_handle)) {
+ if ((priv->samr.connect_mask & connect_mask) == connect_mask) {
+ *connect_handle = priv->samr.connect_handle;
+ } else {
+ libnetapi_samr_close_connect_handle(mem_ctx,
+ &priv->samr.connect_handle);
+ }
+ }
+
+ if (is_valid_policy_hnd(&priv->samr.builtin_handle)) {
+ if ((priv->samr.builtin_mask & builtin_mask) == builtin_mask) {
+ *builtin_handle = priv->samr.builtin_handle;
+ } else {
+ libnetapi_samr_close_builtin_handle(mem_ctx,
+ &priv->samr.builtin_handle);
+ }
+ }
+
+ if (is_valid_policy_hnd(&priv->samr.connect_handle) &&
+ ((priv->samr.connect_mask & connect_mask) == connect_mask) &&
+ is_valid_policy_hnd(&priv->samr.builtin_handle) &&
+ (priv->samr.builtin_mask & builtin_mask) == builtin_mask) {
+ return WERR_OK;
+ }
+
+ if (!is_valid_policy_hnd(connect_handle)) {
+ status = rpccli_try_samr_connects(pipe_cli, mem_ctx,
+ connect_mask,
+ connect_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+
+ status = rpccli_samr_OpenDomain(pipe_cli, mem_ctx,
+ connect_handle,
+ builtin_mask,
+ CONST_DISCARD(DOM_SID *, &global_sid_Builtin),
+ builtin_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ priv->samr.cli = pipe_cli;
+
+ priv->samr.connect_mask = connect_mask;
+ priv->samr.connect_handle = *connect_handle;
+
+ priv->samr.builtin_mask = builtin_mask;
+ priv->samr.builtin_handle = *builtin_handle;
+
+ werr = WERR_OK;
+
+ done:
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+void libnetapi_samr_close_domain_handle(struct libnetapi_ctx *ctx,
+ struct policy_handle *handle)
+{
+ struct libnetapi_private_ctx *priv;
+
+ if (!is_valid_policy_hnd(handle)) {
+ return;
+ }
+
+ priv = talloc_get_type_abort(ctx->private_data,
+ struct libnetapi_private_ctx);
+
+ if (!policy_hnd_equal(handle, &priv->samr.domain_handle)) {
+ return;
+ }
+
+ rpccli_samr_Close(priv->samr.cli, ctx, handle);
+
+ ZERO_STRUCT(priv->samr.domain_handle);
+}
+
+/****************************************************************
+****************************************************************/
+
+void libnetapi_samr_close_builtin_handle(struct libnetapi_ctx *ctx,
+ struct policy_handle *handle)
+{
+ struct libnetapi_private_ctx *priv;
+
+ if (!is_valid_policy_hnd(handle)) {
+ return;
+ }
+
+ priv = talloc_get_type_abort(ctx->private_data,
+ struct libnetapi_private_ctx);
+
+ if (!policy_hnd_equal(handle, &priv->samr.builtin_handle)) {
+ return;
+ }
+
+ rpccli_samr_Close(priv->samr.cli, ctx, handle);
+
+ ZERO_STRUCT(priv->samr.builtin_handle);
+}
+
+/****************************************************************
+****************************************************************/
+
+void libnetapi_samr_close_connect_handle(struct libnetapi_ctx *ctx,
+ struct policy_handle *handle)
+{
+ struct libnetapi_private_ctx *priv;
+
+ if (!is_valid_policy_hnd(handle)) {
+ return;
+ }
+
+ priv = talloc_get_type_abort(ctx->private_data,
+ struct libnetapi_private_ctx);
+
+ if (!policy_hnd_equal(handle, &priv->samr.connect_handle)) {
+ return;
+ }
+
+ rpccli_samr_Close(priv->samr.cli, ctx, handle);
+
+ ZERO_STRUCT(priv->samr.connect_handle);
+}
+
+/****************************************************************
+****************************************************************/
+
+void libnetapi_samr_free(struct libnetapi_ctx *ctx)
+{
+ struct libnetapi_private_ctx *priv;
+
+ if (!ctx->private_data) {
+ return;
+ }
+
+ priv = talloc_get_type_abort(ctx->private_data,
+ struct libnetapi_private_ctx);
+
+ libnetapi_samr_close_domain_handle(ctx, &priv->samr.domain_handle);
+ libnetapi_samr_close_builtin_handle(ctx, &priv->samr.builtin_handle);
+ libnetapi_samr_close_connect_handle(ctx, &priv->samr.connect_handle);
+}
diff --git a/source3/lib/netapi/serverinfo.c b/source3/lib/netapi/serverinfo.c
new file mode 100644
index 0000000000..b2a134b0af
--- /dev/null
+++ b/source3/lib/netapi/serverinfo.c
@@ -0,0 +1,360 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi Server Support
+ * Copyright (C) Guenther Deschner 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#include "librpc/gen_ndr/libnetapi.h"
+#include "lib/netapi/netapi.h"
+#include "lib/netapi/netapi_private.h"
+#include "lib/netapi/libnetapi.h"
+#include "libnet/libnet.h"
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetServerGetInfo_l_101(struct libnetapi_ctx *ctx,
+ uint8_t **buffer)
+{
+ struct SERVER_INFO_101 i;
+
+ i.sv101_platform_id = PLATFORM_ID_NT;
+ i.sv101_name = global_myname();
+ i.sv101_version_major = lp_major_announce_version();
+ i.sv101_version_minor = lp_minor_announce_version();
+ i.sv101_type = lp_default_server_announce();
+ i.sv101_comment = lp_serverstring();
+
+ *buffer = (uint8_t *)talloc_memdup(ctx, &i, sizeof(i));
+ if (!*buffer) {
+ return WERR_NOMEM;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetServerGetInfo_l_1005(struct libnetapi_ctx *ctx,
+ uint8_t **buffer)
+{
+ struct SERVER_INFO_1005 info1005;
+
+ info1005.sv1005_comment = lp_serverstring();
+ *buffer = (uint8_t *)talloc_memdup(ctx, &info1005, sizeof(info1005));
+ if (!*buffer) {
+ return WERR_NOMEM;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetServerGetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetServerGetInfo *r)
+{
+ switch (r->in.level) {
+ case 101:
+ return NetServerGetInfo_l_101(ctx, r->out.buffer);
+ case 1005:
+ return NetServerGetInfo_l_1005(ctx, r->out.buffer);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return WERR_UNKNOWN_LEVEL;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS map_server_info_to_SERVER_INFO_buffer(TALLOC_CTX *mem_ctx,
+ uint32_t level,
+ union srvsvc_NetSrvInfo *i,
+ uint8_t **buffer)
+{
+ struct SERVER_INFO_100 i100;
+ struct SERVER_INFO_101 i101;
+ struct SERVER_INFO_102 i102;
+ struct SERVER_INFO_1005 i1005;
+
+ uint32_t num_info = 0;
+
+ switch (level) {
+ case 100:
+ i100.sv100_platform_id = i->info100->platform_id;
+ i100.sv100_name = talloc_strdup(mem_ctx, i->info100->server_name);
+
+ ADD_TO_ARRAY(mem_ctx, struct SERVER_INFO_100, i100,
+ (struct SERVER_INFO_100 **)buffer,
+ &num_info);
+ break;
+
+ case 101:
+ i101.sv101_platform_id = i->info101->platform_id;
+ i101.sv101_name = talloc_strdup(mem_ctx, i->info101->server_name);
+ i101.sv101_version_major = i->info101->version_major;
+ i101.sv101_version_minor = i->info101->version_minor;
+ i101.sv101_type = i->info101->server_type;
+ i101.sv101_comment = talloc_strdup(mem_ctx, i->info101->comment);
+
+ ADD_TO_ARRAY(mem_ctx, struct SERVER_INFO_101, i101,
+ (struct SERVER_INFO_101 **)buffer,
+ &num_info);
+ break;
+
+ case 102:
+ i102.sv102_platform_id = i->info102->platform_id;
+ i102.sv102_name = talloc_strdup(mem_ctx, i->info102->server_name);
+ i102.sv102_version_major = i->info102->version_major;
+ i102.sv102_version_minor = i->info102->version_minor;
+ i102.sv102_type = i->info102->server_type;
+ i102.sv102_comment = talloc_strdup(mem_ctx, i->info102->comment);
+ i102.sv102_users = i->info102->users;
+ i102.sv102_disc = i->info102->disc;
+ i102.sv102_hidden = i->info102->hidden;
+ i102.sv102_announce = i->info102->announce;
+ i102.sv102_anndelta = i->info102->anndelta;
+ i102.sv102_licenses = i->info102->licenses;
+ i102.sv102_userpath = talloc_strdup(mem_ctx, i->info102->userpath);
+
+ ADD_TO_ARRAY(mem_ctx, struct SERVER_INFO_102, i102,
+ (struct SERVER_INFO_102 **)buffer,
+ &num_info);
+ break;
+
+ case 1005:
+ i1005.sv1005_comment = talloc_strdup(mem_ctx, i->info1005->comment);
+
+ ADD_TO_ARRAY(mem_ctx, struct SERVER_INFO_1005, i1005,
+ (struct SERVER_INFO_1005 **)buffer,
+ &num_info);
+ break;
+ default:
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetServerGetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetServerGetInfo *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ union srvsvc_NetSrvInfo info;
+
+ if (!r->out.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 100:
+ case 101:
+ case 102:
+ case 1005:
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_srvsvc.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = rpccli_srvsvc_NetSrvGetInfo(pipe_cli, ctx,
+ r->in.server_name,
+ r->in.level,
+ &info,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = map_server_info_to_SERVER_INFO_buffer(ctx, r->in.level, &info,
+ r->out.buffer);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ done:
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetServerSetInfo_l_1005(struct libnetapi_ctx *ctx,
+ struct NetServerSetInfo *r)
+{
+ WERROR werr;
+ struct smbconf_ctx *conf_ctx;
+ struct srvsvc_NetSrvInfo1005 *info1005;
+
+ if (!r->in.buffer) {
+ *r->out.parm_error = 1005; /* sure here ? */
+ return WERR_INVALID_PARAM;
+ }
+
+ info1005 = (struct srvsvc_NetSrvInfo1005 *)r->in.buffer;
+
+ if (!info1005->comment) {
+ *r->out.parm_error = 1005;
+ return WERR_INVALID_PARAM;
+ }
+
+ if (!lp_config_backend_is_registry()) {
+ libnetapi_set_error_string(ctx,
+ "Configuration manipulation requested but not "
+ "supported by backend");
+ return WERR_NOT_SUPPORTED;
+ }
+
+ werr = smbconf_init_reg(ctx, &conf_ctx, NULL);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = smbconf_set_global_parameter(conf_ctx, "server string",
+ info1005->comment);
+
+ done:
+ smbconf_shutdown(conf_ctx);
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetServerSetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetServerSetInfo *r)
+{
+ switch (r->in.level) {
+ case 1005:
+ return NetServerSetInfo_l_1005(ctx, r);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return WERR_UNKNOWN_LEVEL;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetServerSetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetServerSetInfo *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ union srvsvc_NetSrvInfo info;
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_srvsvc.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ switch (r->in.level) {
+ case 1005:
+ info.info1005 = (struct srvsvc_NetSrvInfo1005 *)r->in.buffer;
+ break;
+ default:
+ werr = WERR_NOT_SUPPORTED;
+ goto done;
+ }
+
+ status = rpccli_srvsvc_NetSrvSetInfo(pipe_cli, ctx,
+ r->in.server_name,
+ r->in.level,
+ &info,
+ r->out.parm_error,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ done:
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetRemoteTOD_r(struct libnetapi_ctx *ctx,
+ struct NetRemoteTOD *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ struct srvsvc_NetRemoteTODInfo *info = NULL;
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_srvsvc.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = rpccli_srvsvc_NetRemoteTOD(pipe_cli, ctx,
+ r->in.server_name,
+ &info,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ *r->out.buffer = (uint8_t *)talloc_memdup(ctx, info,
+ sizeof(struct srvsvc_NetRemoteTODInfo));
+ W_ERROR_HAVE_NO_MEMORY(*r->out.buffer);
+
+ done:
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetRemoteTOD_l(struct libnetapi_ctx *ctx,
+ struct NetRemoteTOD *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetRemoteTOD);
+}
+
diff --git a/source3/lib/netapi/share.c b/source3/lib/netapi/share.c
new file mode 100644
index 0000000000..1d0e1810f1
--- /dev/null
+++ b/source3/lib/netapi/share.c
@@ -0,0 +1,555 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi Share Support
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#include "librpc/gen_ndr/libnetapi.h"
+#include "lib/netapi/netapi.h"
+#include "lib/netapi/netapi_private.h"
+#include "lib/netapi/libnetapi.h"
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS map_srvsvc_share_info_to_SHARE_INFO_buffer(TALLOC_CTX *mem_ctx,
+ uint32_t level,
+ union srvsvc_NetShareInfo *info,
+ uint8_t **buffer,
+ uint32_t *num_shares)
+{
+ struct SHARE_INFO_0 i0;
+ struct SHARE_INFO_1 i1;
+ struct SHARE_INFO_2 i2;
+ struct SHARE_INFO_501 i501;
+ struct SHARE_INFO_1005 i1005;
+
+ struct srvsvc_NetShareInfo0 *s0;
+ struct srvsvc_NetShareInfo1 *s1;
+ struct srvsvc_NetShareInfo2 *s2;
+ struct srvsvc_NetShareInfo501 *s501;
+ struct srvsvc_NetShareInfo1005 *s1005;
+
+ if (!buffer) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ switch (level) {
+ case 0:
+ s0 = info->info0;
+
+ i0.shi0_netname = talloc_strdup(mem_ctx, s0->name);
+
+ ADD_TO_ARRAY(mem_ctx, struct SHARE_INFO_0, i0,
+ (struct SHARE_INFO_0 **)buffer,
+ num_shares);
+ break;
+
+ case 1:
+ s1 = info->info1;
+
+ i1.shi1_netname = talloc_strdup(mem_ctx, s1->name);
+ i1.shi1_type = s1->type;
+ i1.shi1_remark = talloc_strdup(mem_ctx, s1->comment);
+
+ ADD_TO_ARRAY(mem_ctx, struct SHARE_INFO_1, i1,
+ (struct SHARE_INFO_1 **)buffer,
+ num_shares);
+ break;
+
+ case 2:
+ s2 = info->info2;
+
+ i2.shi2_netname = talloc_strdup(mem_ctx, s2->name);
+ i2.shi2_type = s2->type;
+ i2.shi2_remark = talloc_strdup(mem_ctx, s2->comment);
+ i2.shi2_permissions = s2->permissions;
+ i2.shi2_max_uses = s2->max_users;
+ i2.shi2_current_uses = s2->current_users;
+ i2.shi2_path = talloc_strdup(mem_ctx, s2->path);
+ i2.shi2_passwd = talloc_strdup(mem_ctx, s2->password);
+
+ ADD_TO_ARRAY(mem_ctx, struct SHARE_INFO_2, i2,
+ (struct SHARE_INFO_2 **)buffer,
+ num_shares);
+ break;
+
+ case 501:
+ s501 = info->info501;
+
+ i501.shi501_netname = talloc_strdup(mem_ctx, s501->name);
+ i501.shi501_type = s501->type;
+ i501.shi501_remark = talloc_strdup(mem_ctx, s501->comment);
+ i501.shi501_flags = s501->csc_policy;
+
+ ADD_TO_ARRAY(mem_ctx, struct SHARE_INFO_501, i501,
+ (struct SHARE_INFO_501 **)buffer,
+ num_shares);
+ break;
+
+ case 1005:
+ s1005 = info->info1005;
+
+ i1005.shi1005_flags = s1005->dfs_flags;
+
+ ADD_TO_ARRAY(mem_ctx, struct SHARE_INFO_1005, i1005,
+ (struct SHARE_INFO_1005 **)buffer,
+ num_shares);
+ break;
+
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS map_SHARE_INFO_buffer_to_srvsvc_share_info(TALLOC_CTX *mem_ctx,
+ uint8_t *buffer,
+ uint32_t level,
+ union srvsvc_NetShareInfo *info)
+{
+ struct SHARE_INFO_2 *i2 = NULL;
+ struct SHARE_INFO_1004 *i1004 = NULL;
+ struct srvsvc_NetShareInfo2 *s2 = NULL;
+ struct srvsvc_NetShareInfo1004 *s1004 = NULL;
+
+ if (!buffer) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ switch (level) {
+ case 2:
+ i2 = (struct SHARE_INFO_2 *)buffer;
+
+ s2 = TALLOC_P(mem_ctx, struct srvsvc_NetShareInfo2);
+ NT_STATUS_HAVE_NO_MEMORY(s2);
+
+ s2->name = i2->shi2_netname;
+ s2->type = i2->shi2_type;
+ s2->comment = i2->shi2_remark;
+ s2->permissions = i2->shi2_permissions;
+ s2->max_users = i2->shi2_max_uses;
+ s2->current_users = i2->shi2_current_uses;
+ s2->path = i2->shi2_path;
+ s2->password = i2->shi2_passwd;
+
+ info->info2 = s2;
+
+ break;
+ case 1004:
+ i1004 = (struct SHARE_INFO_1004 *)buffer;
+
+ s1004 = TALLOC_P(mem_ctx, struct srvsvc_NetShareInfo1004);
+ NT_STATUS_HAVE_NO_MEMORY(s1004);
+
+ s1004->comment = i1004->shi1004_remark;
+
+ info->info1004 = s1004;
+
+ break;
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetShareAdd_r(struct libnetapi_ctx *ctx,
+ struct NetShareAdd *r)
+{
+ WERROR werr;
+ NTSTATUS status;
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ union srvsvc_NetShareInfo info;
+
+ if (!r->in.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 2:
+ break;
+ case 502:
+ case 503:
+ return WERR_NOT_SUPPORTED;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_srvsvc.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = map_SHARE_INFO_buffer_to_srvsvc_share_info(ctx,
+ r->in.buffer,
+ r->in.level,
+ &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_srvsvc_NetShareAdd(pipe_cli, ctx,
+ r->in.server_name,
+ r->in.level,
+ &info,
+ r->out.parm_err,
+ &werr);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetShareAdd_l(struct libnetapi_ctx *ctx,
+ struct NetShareAdd *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetShareAdd);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetShareDel_r(struct libnetapi_ctx *ctx,
+ struct NetShareDel *r)
+{
+ WERROR werr;
+ NTSTATUS status;
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+
+ if (!r->in.net_name) {
+ return WERR_INVALID_PARAM;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_srvsvc.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = rpccli_srvsvc_NetShareDel(pipe_cli, ctx,
+ r->in.server_name,
+ r->in.net_name,
+ r->in.reserved,
+ &werr);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetShareDel_l(struct libnetapi_ctx *ctx,
+ struct NetShareDel *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetShareDel);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetShareEnum_r(struct libnetapi_ctx *ctx,
+ struct NetShareEnum *r)
+{
+ WERROR werr;
+ NTSTATUS status;
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct srvsvc_NetShareInfoCtr info_ctr;
+ struct srvsvc_NetShareCtr0 ctr0;
+ struct srvsvc_NetShareCtr1 ctr1;
+ struct srvsvc_NetShareCtr2 ctr2;
+ uint32_t i;
+
+ if (!r->out.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ case 1:
+ case 2:
+ break;
+ case 502:
+ case 503:
+ return WERR_NOT_SUPPORTED;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ ZERO_STRUCT(info_ctr);
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_srvsvc.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ info_ctr.level = r->in.level;
+ switch (r->in.level) {
+ case 0:
+ ZERO_STRUCT(ctr0);
+ info_ctr.ctr.ctr0 = &ctr0;
+ break;
+ case 1:
+ ZERO_STRUCT(ctr1);
+ info_ctr.ctr.ctr1 = &ctr1;
+ break;
+ case 2:
+ ZERO_STRUCT(ctr2);
+ info_ctr.ctr.ctr2 = &ctr2;
+ break;
+ }
+
+ status = rpccli_srvsvc_NetShareEnumAll(pipe_cli, ctx,
+ r->in.server_name,
+ &info_ctr,
+ r->in.prefmaxlen,
+ r->out.total_entries,
+ r->out.resume_handle,
+ &werr);
+ if (NT_STATUS_IS_ERR(status)) {
+ goto done;
+ }
+
+ for (i=0; i < info_ctr.ctr.ctr1->count; i++) {
+ union srvsvc_NetShareInfo _i;
+ switch (r->in.level) {
+ case 0:
+ _i.info0 = &info_ctr.ctr.ctr0->array[i];
+ break;
+ case 1:
+ _i.info1 = &info_ctr.ctr.ctr1->array[i];
+ break;
+ case 2:
+ _i.info2 = &info_ctr.ctr.ctr2->array[i];
+ break;
+ }
+
+ status = map_srvsvc_share_info_to_SHARE_INFO_buffer(ctx,
+ r->in.level,
+ &_i,
+ r->out.buffer,
+ r->out.entries_read);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ }
+ }
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetShareEnum_l(struct libnetapi_ctx *ctx,
+ struct NetShareEnum *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetShareEnum);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetShareGetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetShareGetInfo *r)
+{
+ WERROR werr;
+ NTSTATUS status;
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ union srvsvc_NetShareInfo info;
+ uint32_t num_entries = 0;
+
+ if (!r->in.net_name || !r->out.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ case 1:
+ case 2:
+ case 501:
+ case 1005:
+ break;
+ case 502:
+ case 503:
+ return WERR_NOT_SUPPORTED;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_srvsvc.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = rpccli_srvsvc_NetShareGetInfo(pipe_cli, ctx,
+ r->in.server_name,
+ r->in.net_name,
+ r->in.level,
+ &info,
+ &werr);
+
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = map_srvsvc_share_info_to_SHARE_INFO_buffer(ctx,
+ r->in.level,
+ &info,
+ r->out.buffer,
+ &num_entries);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ }
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetShareGetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetShareGetInfo *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetShareGetInfo);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetShareSetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetShareSetInfo *r)
+{
+ WERROR werr;
+ NTSTATUS status;
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ union srvsvc_NetShareInfo info;
+
+ if (!r->in.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 2:
+ case 1004:
+ break;
+ case 1:
+ case 502:
+ case 503:
+ case 1005:
+ case 1006:
+ case 1501:
+ return WERR_NOT_SUPPORTED;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_srvsvc.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = map_SHARE_INFO_buffer_to_srvsvc_share_info(ctx,
+ r->in.buffer,
+ r->in.level,
+ &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_srvsvc_NetShareSetInfo(pipe_cli, ctx,
+ r->in.server_name,
+ r->in.net_name,
+ r->in.level,
+ &info,
+ r->out.parm_err,
+ &werr);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetShareSetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetShareSetInfo *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetShareSetInfo);
+}
diff --git a/source3/lib/netapi/sid.c b/source3/lib/netapi/sid.c
new file mode 100644
index 0000000000..a9bca2689f
--- /dev/null
+++ b/source3/lib/netapi/sid.c
@@ -0,0 +1,76 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi Support
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#include "lib/netapi/netapi.h"
+
+/****************************************************************
+****************************************************************/
+
+int ConvertSidToStringSid(const struct domsid *sid,
+ char **sid_string)
+{
+ char *ret;
+
+ if (!sid || !sid_string) {
+ return false;
+ }
+
+ ret = sid_string_talloc(NULL, (const struct dom_sid *)sid);
+ if (!ret) {
+ return false;
+ }
+
+ *sid_string = SMB_STRDUP(ret);
+
+ TALLOC_FREE(ret);
+
+ if (!*sid_string) {
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+int ConvertStringSidToSid(const char *sid_string,
+ struct domsid **sid)
+{
+ struct dom_sid _sid;
+
+ if (!sid_string || !sid) {
+ return false;
+ }
+
+ if (!string_to_sid(&_sid, sid_string)) {
+ return false;
+ }
+
+ *sid = (struct domsid *)SMB_MALLOC(sizeof(struct domsid));
+ if (!*sid) {
+ return false;
+ }
+
+ sid_copy((struct dom_sid*)*sid, &_sid);
+
+ return true;
+}
diff --git a/source3/lib/netapi/tests/Makefile.in b/source3/lib/netapi/tests/Makefile.in
new file mode 100644
index 0000000000..d3f0663908
--- /dev/null
+++ b/source3/lib/netapi/tests/Makefile.in
@@ -0,0 +1,57 @@
+KRB5LIBS=@KRB5_LIBS@
+LDAP_LIBS=@LDAP_LIBS@
+LIBS=@LIBS@ -lnetapi -ltdb -ltalloc
+DEVELOPER_CFLAGS=@DEVELOPER_CFLAGS@
+FLAGS=-I../ -L../../../bin @CFLAGS@ $(GTK_FLAGS)
+CC=@CC@
+PICFLAG=@PICFLAG@
+LDFLAGS=@PIE_LDFLAGS@ @LDFLAGS@
+DYNEXP=@DYNEXP@
+NETAPI_LIBS=$(LIBS) $(KRB5LIBS) $(LDAP_LIBS)
+CMDLINE_LIBS=$(NETAPI_LIBS) @POPTLIBS@
+
+# Compile a source file.
+COMPILE_CC = $(CC) -I. $(FLAGS) $(PICFLAG) -c $< -o $@
+COMPILE = $(COMPILE_CC)
+
+PROGS = bin/netapitest@EXEEXT@
+
+all: $(PROGS)
+
+MAKEDIR = || exec false; \
+ if test -d "$$dir"; then :; else \
+ echo mkdir "$$dir"; \
+ mkdir -p "$$dir" >/dev/null 2>&1 || \
+ test -d "$$dir" || \
+ mkdir "$$dir" || \
+ exec false; fi || exec false
+
+BINARY_PREREQS = bin/.dummy
+
+bin/.dummy:
+ @if (: >> $@ || : > $@) >/dev/null 2>&1; then :; else \
+ dir=bin $(MAKEDIR); fi
+ @: >> $@ || : > $@ # what a fancy emoticon!
+
+.c.o:
+ @if (: >> $@ || : > $@) >/dev/null 2>&1; then rm -f $@; else \
+ dir=`echo $@ | sed 's,/[^/]*$$,,;s,^$$,.,'` $(MAKEDIR); fi
+ @echo Compiling $*.c
+ @$(COMPILE) && exit 0;\
+ echo "The following command failed:" 1>&2;\
+ echo "$(COMPILE_CC)" 1>&2;\
+ $(COMPILE_CC) >/dev/null 2>&1
+
+CMDLINE_OBJ = common.o
+NETAPIBUFFER_OBJ = netapibuffer.o
+NETAPITEST_OBJ = netapitest.o netlocalgroup.o netuser.o netgroup.o netdisplay.o netshare.o $(CMDLINE_OBJ)
+
+bin/netapitest@EXEEXT@: $(BINARY_PREREQS) $(NETAPITEST_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(NETAPITEST_OBJ) $(LDFLAGS) $(DYNEXP) $(CMDLINE_LIBS)
+
+clean:
+ -rm -f $(PROGS)
+ -rm -f core */*~ *~ \
+ */*.o */*/*.o */*/*/*.o
+
diff --git a/source3/lib/netapi/tests/common.c b/source3/lib/netapi/tests/common.c
new file mode 100644
index 0000000000..22175afb48
--- /dev/null
+++ b/source3/lib/netapi/tests/common.c
@@ -0,0 +1,86 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi testsuite
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <inttypes.h>
+
+#include <popt.h>
+#include <netapi.h>
+
+#include "common.h"
+
+void popt_common_callback(poptContext con,
+ enum poptCallbackReason reason,
+ const struct poptOption *opt,
+ const char *arg, const void *data)
+{
+ struct libnetapi_ctx *ctx = NULL;
+
+ libnetapi_getctx(&ctx);
+
+ if (reason == POPT_CALLBACK_REASON_PRE) {
+ }
+
+ if (reason == POPT_CALLBACK_REASON_POST) {
+ }
+
+ if (!opt) {
+ return;
+ }
+ switch (opt->val) {
+ case 'U': {
+ char *puser = strdup(arg);
+ char *p = NULL;
+
+ if ((p = strchr(puser,'%'))) {
+ size_t len;
+ *p = 0;
+ libnetapi_set_username(ctx, puser);
+ libnetapi_set_password(ctx, p+1);
+ len = strlen(p+1);
+ memset(strchr(arg,'%')+1,'X',len);
+ } else {
+ libnetapi_set_username(ctx, puser);
+ }
+ free(puser);
+ break;
+ }
+ case 'd':
+ libnetapi_set_debuglevel(ctx, arg);
+ break;
+ case 'p':
+ libnetapi_set_password(ctx, arg);
+ break;
+ case 'k':
+ libnetapi_set_use_kerberos(ctx);
+ break;
+ }
+}
+
+struct poptOption popt_common_netapi_examples[] = {
+ { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, (void *)popt_common_callback },
+ { "user", 'U', POPT_ARG_STRING, NULL, 'U', "Username used for connection", "USERNAME" },
+ { "password", 'p', POPT_ARG_STRING, NULL, 'p', "Password used for connection", "PASSWORD" },
+ { "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Debuglevel", "DEBUGLEVEL" },
+ { "kerberos", 'k', POPT_ARG_NONE, NULL, 'k', "Use Kerberos", NULL },
+ POPT_TABLEEND
+};
+
diff --git a/source3/lib/netapi/tests/common.h b/source3/lib/netapi/tests/common.h
new file mode 100644
index 0000000000..5a320321ba
--- /dev/null
+++ b/source3/lib/netapi/tests/common.h
@@ -0,0 +1,57 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi testsuite
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <popt.h>
+
+void popt_common_callback(poptContext con,
+ enum poptCallbackReason reason,
+ const struct poptOption *opt,
+ const char *arg, const void *data);
+
+extern struct poptOption popt_common_netapi_examples[];
+
+#define POPT_COMMON_LIBNETAPI_EXAMPLES { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_netapi_examples, 0, "Common samba netapi example options:", NULL },
+
+NET_API_STATUS test_netuseradd(const char *hostname,
+ const char *username);
+
+NET_API_STATUS netapitest_localgroup(struct libnetapi_ctx *ctx,
+ const char *hostname);
+NET_API_STATUS netapitest_user(struct libnetapi_ctx *ctx,
+ const char *hostname);
+NET_API_STATUS netapitest_group(struct libnetapi_ctx *ctx,
+ const char *hostname);
+NET_API_STATUS netapitest_display(struct libnetapi_ctx *ctx,
+ const char *hostname);
+NET_API_STATUS netapitest_share(struct libnetapi_ctx *ctx,
+ const char *hostname);
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+#endif
+
+#define NETAPI_STATUS(x,y,fn) \
+ printf("FAILURE: line %d: %s failed with status: %s (%d)\n", \
+ __LINE__, fn, libnetapi_get_error_string(x,y), y);
+
+#define NETAPI_STATUS_MSG(x,y,fn,z) \
+ printf("FAILURE: line %d: %s failed with status: %s (%d), %s\n", \
+ __LINE__, fn, libnetapi_get_error_string(x,y), y, z);
+
+#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
diff --git a/source3/lib/netapi/tests/netapitest.c b/source3/lib/netapi/tests/netapitest.c
new file mode 100644
index 0000000000..87144020f5
--- /dev/null
+++ b/source3/lib/netapi/tests/netapitest.c
@@ -0,0 +1,97 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi testsuite
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+int main(int argc, const char **argv)
+{
+ NET_API_STATUS status = 0;
+ struct libnetapi_ctx *ctx = NULL;
+ const char *hostname = NULL;
+
+ poptContext pc;
+ int opt;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_LIBNETAPI_EXAMPLES
+ POPT_TABLEEND
+ };
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ pc = poptGetContext("netapitest", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "hostname");
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+ hostname = poptGetArg(pc);
+
+ status = netapitest_localgroup(ctx, hostname);
+ if (status) {
+ goto out;
+ }
+
+ status = netapitest_user(ctx, hostname);
+ if (status) {
+ goto out;
+ }
+
+ status = netapitest_group(ctx, hostname);
+ if (status) {
+ goto out;
+ }
+
+ status = netapitest_display(ctx, hostname);
+ if (status) {
+ goto out;
+ }
+
+ status = netapitest_share(ctx, hostname);
+ if (status) {
+ goto out;
+ }
+
+ out:
+ if (status != 0) {
+ printf("testsuite failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ libnetapi_free(ctx);
+ poptFreeContext(pc);
+
+ return status;
+}
diff --git a/source3/lib/netapi/tests/netdisplay.c b/source3/lib/netapi/tests/netdisplay.c
new file mode 100644
index 0000000000..090792cec2
--- /dev/null
+++ b/source3/lib/netapi/tests/netdisplay.c
@@ -0,0 +1,150 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetGroup testsuite
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+static NET_API_STATUS test_netquerydisplayinformation(const char *hostname,
+ uint32_t level,
+ const char *name)
+{
+ NET_API_STATUS status;
+ uint32_t entries_read = 0;
+ int found_name = 0;
+ const char *current_name;
+ uint8_t *buffer = NULL;
+ uint32_t idx = 0;
+ int i;
+
+ struct NET_DISPLAY_USER *user;
+ struct NET_DISPLAY_GROUP *group;
+ struct NET_DISPLAY_MACHINE *machine;
+
+ printf("testing NetQueryDisplayInformation level %d\n", level);
+
+ do {
+ status = NetQueryDisplayInformation(hostname,
+ level,
+ idx,
+ 1000,
+ (uint32_t)-1,
+ &entries_read,
+ (void **)&buffer);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+ switch (level) {
+ case 1:
+ user = (struct NET_DISPLAY_USER *)buffer;
+ break;
+ case 2:
+ machine = (struct NET_DISPLAY_MACHINE *)buffer;
+ break;
+ case 3:
+ group = (struct NET_DISPLAY_GROUP *)buffer;
+ break;
+ default:
+ return -1;
+ }
+
+ for (i=0; i<entries_read; i++) {
+
+ switch (level) {
+ case 1:
+ current_name = user->usri1_name;
+ break;
+ case 2:
+ current_name = machine->usri2_name;
+ break;
+ case 3:
+ current_name = group->grpi3_name;
+ break;
+ default:
+ break;
+ }
+
+ if (name && strcasecmp(current_name, name) == 0) {
+ found_name = 1;
+ }
+
+ switch (level) {
+ case 1:
+ user++;
+ break;
+ case 2:
+ machine++;
+ break;
+ case 3:
+ group++;
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ idx += entries_read;
+ } while (status == ERROR_MORE_DATA);
+
+ if (status) {
+ return status;
+ }
+
+ if (name && !found_name) {
+ printf("failed to get name\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+NET_API_STATUS netapitest_display(struct libnetapi_ctx *ctx,
+ const char *hostname)
+{
+ NET_API_STATUS status = 0;
+ uint32_t levels[] = { 1, 2, 3};
+ int i;
+
+ printf("NetDisplay tests\n");
+
+ /* test enum */
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ status = test_netquerydisplayinformation(hostname, levels[i], NULL);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetQueryDisplayInformation");
+ goto out;
+ }
+ }
+
+ status = 0;
+
+ printf("NetDisplay tests succeeded\n");
+ out:
+ if (status != 0) {
+ printf("NetDisplay testsuite failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ return status;
+}
diff --git a/source3/lib/netapi/tests/netgroup.c b/source3/lib/netapi/tests/netgroup.c
new file mode 100644
index 0000000000..a89a772ce4
--- /dev/null
+++ b/source3/lib/netapi/tests/netgroup.c
@@ -0,0 +1,286 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetGroup testsuite
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+static NET_API_STATUS test_netgroupenum(const char *hostname,
+ uint32_t level,
+ const char *groupname)
+{
+ NET_API_STATUS status;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ int found_group = 0;
+ const char *current_name;
+ uint8_t *buffer = NULL;
+ int i;
+
+ struct GROUP_INFO_0 *info0;
+ struct GROUP_INFO_1 *info1;
+ struct GROUP_INFO_2 *info2;
+ struct GROUP_INFO_3 *info3;
+
+ printf("testing NetGroupEnum level %d\n", level);
+
+ do {
+ status = NetGroupEnum(hostname,
+ level,
+ &buffer,
+ 120, //(uint32_t)-1,
+ &entries_read,
+ &total_entries,
+ &resume_handle);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+ switch (level) {
+ case 0:
+ info0 = (struct GROUP_INFO_0 *)buffer;
+ break;
+ case 1:
+ info1 = (struct GROUP_INFO_1 *)buffer;
+ break;
+ case 2:
+ info2 = (struct GROUP_INFO_2 *)buffer;
+ break;
+ case 3:
+ info3 = (struct GROUP_INFO_3 *)buffer;
+ break;
+ default:
+ return -1;
+ }
+
+ for (i=0; i<entries_read; i++) {
+
+ switch (level) {
+ case 0:
+ current_name = info0->grpi0_name;
+ break;
+ case 1:
+ current_name = info1->grpi1_name;
+ break;
+ case 2:
+ current_name = info2->grpi2_name;
+ break;
+ case 3:
+ current_name = info3->grpi3_name;
+ break;
+ default:
+ break;
+ }
+
+ if (strcasecmp(current_name, groupname) == 0) {
+ found_group = 1;
+ }
+
+ switch (level) {
+ case 0:
+ info0++;
+ break;
+ case 1:
+ info1++;
+ break;
+ case 2:
+ info2++;
+ break;
+ case 3:
+ info3++;
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status) {
+ return status;
+ }
+
+ if (!found_group) {
+ printf("failed to get group\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+NET_API_STATUS netapitest_group(struct libnetapi_ctx *ctx,
+ const char *hostname)
+{
+ NET_API_STATUS status = 0;
+ const char *username, *groupname, *groupname2;
+ uint8_t *buffer = NULL;
+ struct GROUP_INFO_0 g0;
+ uint32_t parm_err = 0;
+ uint32_t levels[] = { 0, 1, 2, 3};
+ uint32_t enum_levels[] = { 0, 1, 2, 3};
+ int i;
+
+ printf("NetGroup tests\n");
+
+ username = "torture_test_user";
+ groupname = "torture_test_group";
+ groupname2 = "torture_test_group2";
+
+ /* cleanup */
+ NetGroupDel(hostname, groupname);
+ NetGroupDel(hostname, groupname2);
+ NetUserDel(hostname, username);
+
+ /* add a group */
+
+ g0.grpi0_name = groupname;
+
+ printf("testing NetGroupAdd\n");
+
+ status = NetGroupAdd(hostname, 0, (uint8_t *)&g0, &parm_err);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetGroupAdd");
+ goto out;
+ }
+
+ /* 2nd add must fail */
+
+ status = NetGroupAdd(hostname, 0, (uint8_t *)&g0, &parm_err);
+ if (status == 0) {
+ NETAPI_STATUS(ctx, status, "NetGroupAdd");
+ goto out;
+ }
+
+ /* test enum */
+
+ for (i=0; i<ARRAY_SIZE(enum_levels); i++) {
+
+ status = test_netgroupenum(hostname, enum_levels[i], groupname);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetGroupEnum");
+ goto out;
+ }
+ }
+
+ /* basic queries */
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ printf("testing NetGroupGetInfo level %d\n", levels[i]);
+
+ status = NetGroupGetInfo(hostname, groupname, levels[i], &buffer);
+ if (status && status != 124) {
+ NETAPI_STATUS(ctx, status, "NetGroupGetInfo");
+ goto out;
+ }
+ }
+
+ /* group rename */
+
+ g0.grpi0_name = groupname2;
+
+ printf("testing NetGroupSetInfo level 0\n");
+
+ status = NetGroupSetInfo(hostname, groupname, 0, (uint8_t *)&g0, &parm_err);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetGroupSetInfo");
+ goto out;
+ }
+
+ /* should not exist anymore */
+
+ status = NetGroupDel(hostname, groupname);
+ if (status == 0) {
+ NETAPI_STATUS(ctx, status, "NetGroupDel");
+ goto out;
+ }
+
+ /* query info */
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ status = NetGroupGetInfo(hostname, groupname2, levels[i], &buffer);
+ if (status && status != 124) {
+ NETAPI_STATUS(ctx, status, "NetGroupGetInfo");
+ goto out;
+ }
+ }
+
+ /* add user to group */
+
+ status = test_netuseradd(hostname, username);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetUserAdd");
+ goto out;
+ }
+
+ printf("testing NetGroupAddUser\n");
+
+ status = NetGroupAddUser(hostname, groupname2, username);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetGroupAddUser");
+ goto out;
+ }
+
+ printf("testing NetGroupDelUser\n");
+
+ status = NetGroupDelUser(hostname, groupname2, username);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetGroupDelUser");
+ goto out;
+ }
+
+ status = NetUserDel(hostname, username);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetUserDel");
+ goto out;
+ }
+
+ /* delete */
+
+ printf("testing NetGroupDel\n");
+
+ status = NetGroupDel(hostname, groupname2);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetGroupDel");
+ goto out;
+ };
+
+ /* should not exist anymore */
+
+ status = NetGroupGetInfo(hostname, groupname2, 0, &buffer);
+ if (status == 0) {
+ NETAPI_STATUS_MSG(ctx, status, "NetGroupGetInfo", "expected failure and error code");
+ goto out;
+ };
+
+ status = 0;
+
+ printf("NetGroup tests succeeded\n");
+ out:
+ if (status != 0) {
+ printf("NetGroup testsuite failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ return status;
+}
diff --git a/source3/lib/netapi/tests/netlocalgroup.c b/source3/lib/netapi/tests/netlocalgroup.c
new file mode 100644
index 0000000000..0d82059356
--- /dev/null
+++ b/source3/lib/netapi/tests/netlocalgroup.c
@@ -0,0 +1,226 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetLocalGroup testsuite
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+static NET_API_STATUS test_netlocalgroupenum(const char *hostname,
+ uint32_t level,
+ const char *groupname)
+{
+ NET_API_STATUS status;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ int found_group = 0;
+ const char *current_name;
+ uint8_t *buffer = NULL;
+ int i;
+
+ struct LOCALGROUP_INFO_0 *info0;
+ struct LOCALGROUP_INFO_1 *info1;
+
+ printf("testing NetLocalGroupEnum level %d\n", level);
+
+ do {
+ status = NetLocalGroupEnum(hostname,
+ level,
+ &buffer,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries,
+ &resume_handle);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+ switch (level) {
+ case 0:
+ info0 = (struct LOCALGROUP_INFO_0 *)buffer;
+ break;
+ case 1:
+ info1 = (struct LOCALGROUP_INFO_1 *)buffer;
+ break;
+ default:
+ return -1;
+ }
+
+ for (i=0; i<entries_read; i++) {
+
+ switch (level) {
+ case 0:
+ current_name = info0->lgrpi0_name;
+ break;
+ case 1:
+ current_name = info1->lgrpi1_name;
+ break;
+ default:
+ break;
+ }
+
+ if (strcasecmp(current_name, groupname) == 0) {
+ found_group = 1;
+ }
+
+ switch (level) {
+ case 0:
+ info0++;
+ break;
+ case 1:
+ info1++;
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status) {
+ return status;
+ }
+
+ if (!found_group) {
+ printf("failed to get group\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+NET_API_STATUS netapitest_localgroup(struct libnetapi_ctx *ctx,
+ const char *hostname)
+{
+ NET_API_STATUS status = 0;
+ const char *groupname, *groupname2;
+ uint8_t *buffer = NULL;
+ struct LOCALGROUP_INFO_0 g0;
+ uint32_t parm_err = 0;
+ uint32_t levels[] = { 0, 1, 1002 };
+ uint32_t enum_levels[] = { 0, 1 };
+ int i;
+
+ printf("NetLocalgroup tests\n");
+
+ groupname = "torture_test_localgroup";
+ groupname2 = "torture_test_localgroup2";
+
+ /* cleanup */
+ NetLocalGroupDel(hostname, groupname);
+ NetLocalGroupDel(hostname, groupname2);
+
+ /* add a localgroup */
+
+ printf("testing NetLocalGroupAdd\n");
+
+ g0.lgrpi0_name = groupname;
+
+ status = NetLocalGroupAdd(hostname, 0, (uint8_t *)&g0, &parm_err);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetLocalGroupAdd");
+ goto out;
+ };
+
+ /* test enum */
+
+ for (i=0; i<ARRAY_SIZE(enum_levels); i++) {
+
+ status = test_netlocalgroupenum(hostname, enum_levels[i], groupname);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetLocalGroupEnum");
+ goto out;
+ }
+ }
+
+
+ /* basic queries */
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ printf("testing NetLocalGroupGetInfo level %d\n", levels[i]);
+
+ status = NetLocalGroupGetInfo(hostname, groupname, levels[i], &buffer);
+ if (status && status != 124) {
+ NETAPI_STATUS(ctx, status, "NetLocalGroupGetInfo");
+ goto out;
+ };
+ }
+
+ /* alias rename */
+
+ printf("testing NetLocalGroupSetInfo level 0\n");
+
+ g0.lgrpi0_name = groupname2;
+
+ status = NetLocalGroupSetInfo(hostname, groupname, 0, (uint8_t *)&g0, &parm_err);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetLocalGroupSetInfo");
+ goto out;
+ };
+
+ /* should not exist anymore */
+
+ status = NetLocalGroupDel(hostname, groupname);
+ if (status == 0) {
+ NETAPI_STATUS(ctx, status, "NetLocalGroupDel");
+ goto out;
+ };
+
+ /* query info */
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+ status = NetLocalGroupGetInfo(hostname, groupname2, levels[i], &buffer);
+ if (status && status != 124) {
+ NETAPI_STATUS(ctx, status, "NetLocalGroupGetInfo");
+ goto out;
+ };
+ }
+
+ /* delete */
+
+ printf("testing NetLocalGroupDel\n");
+
+ status = NetLocalGroupDel(hostname, groupname2);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetLocalGroupDel");
+ goto out;
+ };
+
+ /* should not exist anymore */
+
+ status = NetLocalGroupGetInfo(hostname, groupname2, 0, &buffer);
+ if (status == 0) {
+ NETAPI_STATUS(ctx, status, "NetLocalGroupGetInfo");
+ goto out;
+ };
+
+ status = 0;
+
+ printf("NetLocalgroup tests succeeded\n");
+ out:
+ if (status != 0) {
+ printf("NetLocalGroup testsuite failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ return status;
+}
diff --git a/source3/lib/netapi/tests/netshare.c b/source3/lib/netapi/tests/netshare.c
new file mode 100644
index 0000000000..9446c307b3
--- /dev/null
+++ b/source3/lib/netapi/tests/netshare.c
@@ -0,0 +1,232 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetShare testsuite
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+static NET_API_STATUS test_netshareenum(const char *hostname,
+ uint32_t level,
+ const char *sharename)
+{
+ NET_API_STATUS status;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ int found_share = 0;
+ const char *current_name;
+ uint8_t *buffer = NULL;
+ int i;
+
+ struct SHARE_INFO_0 *i0;
+ struct SHARE_INFO_1 *i1;
+ struct SHARE_INFO_2 *i2;
+
+ printf("testing NetShareEnum level %d\n", level);
+
+ do {
+ status = NetShareEnum(hostname,
+ level,
+ &buffer,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries,
+ &resume_handle);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+ switch (level) {
+ case 0:
+ i0 = (struct SHARE_INFO_0 *)buffer;
+ break;
+ case 1:
+ i1 = (struct SHARE_INFO_1 *)buffer;
+ break;
+ case 2:
+ i2 = (struct SHARE_INFO_2 *)buffer;
+ break;
+ default:
+ return -1;
+ }
+
+ for (i=0; i<entries_read; i++) {
+
+ switch (level) {
+ case 0:
+ current_name = i0->shi0_netname;
+ break;
+ case 1:
+ current_name = i1->shi1_netname;
+ break;
+ case 2:
+ current_name = i2->shi2_netname;
+ break;
+ default:
+ break;
+ }
+
+ if (strcasecmp(current_name, sharename) == 0) {
+ found_share = 1;
+ }
+
+ switch (level) {
+ case 0:
+ i0++;
+ break;
+ case 1:
+ i1++;
+ break;
+ case 2:
+ i2++;
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status) {
+ return status;
+ }
+
+ if (!found_share) {
+ printf("failed to get share\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+NET_API_STATUS netapitest_share(struct libnetapi_ctx *ctx,
+ const char *hostname)
+{
+ NET_API_STATUS status = 0;
+ const char *sharename, *comment;
+ uint8_t *buffer = NULL;
+ struct SHARE_INFO_2 i2;
+ struct SHARE_INFO_1004 i1004;
+ struct SHARE_INFO_501 *i501 = NULL;
+ uint32_t parm_err = 0;
+ uint32_t levels[] = { 0, 1, 2, 501, 1005 };
+ uint32_t enum_levels[] = { 0, 1, 2 };
+ int i;
+
+ printf("NetShare tests\n");
+
+ sharename = "torture_test_share";
+
+ /* cleanup */
+ NetShareDel(hostname, sharename, 0);
+
+ /* add a share */
+
+ printf("testing NetShareAdd\n");
+
+ ZERO_STRUCT(i2);
+
+ i2.shi2_netname = sharename;
+ i2.shi2_path = "c:\\";
+
+ status = NetShareAdd(hostname, 2, (uint8_t *)&i2, &parm_err);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetShareAdd");
+ goto out;
+ };
+
+ /* test enum */
+
+ for (i=0; i<ARRAY_SIZE(enum_levels); i++) {
+
+ status = test_netshareenum(hostname, enum_levels[i], sharename);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetShareEnum");
+ goto out;
+ }
+ }
+
+ /* basic queries */
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ printf("testing NetShareGetInfo level %d\n", levels[i]);
+
+ status = NetShareGetInfo(hostname, sharename, levels[i], &buffer);
+ if (status && status != 124) {
+ NETAPI_STATUS(ctx, status, "NetShareGetInfo");
+ goto out;
+ }
+ }
+
+
+ comment = "NetApi generated comment";
+
+ i1004.shi1004_remark = comment;
+
+ printf("testing NetShareSetInfo level 1004\n");
+
+ status = NetShareSetInfo(hostname, sharename, 1004, (uint8_t *)&i1004, &parm_err);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetShareSetInfo");
+ goto out;
+ }
+
+ status = NetShareGetInfo(hostname, sharename, 501, (uint8_t **)&i501);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetShareGetInfo");
+ goto out;
+ }
+
+ if (strcasecmp(i501->shi501_remark, comment) != 0) {
+ NETAPI_STATUS(ctx, status, "NetShareGetInfo");
+ goto out;
+ }
+
+ /* delete */
+
+ printf("testing NetShareDel\n");
+
+ status = NetShareDel(hostname, sharename, 0);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetShareDel");
+ goto out;
+ };
+
+ /* should not exist anymore */
+
+ status = NetShareGetInfo(hostname, sharename, 0, &buffer);
+ if (status == 0) {
+ NETAPI_STATUS(ctx, status, "NetShareGetInfo");
+ goto out;
+ };
+
+ status = 0;
+
+ printf("NetShare tests succeeded\n");
+ out:
+ if (status != 0) {
+ printf("NetShare testsuite failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ return status;
+}
diff --git a/source3/lib/netapi/tests/netuser.c b/source3/lib/netapi/tests/netuser.c
new file mode 100644
index 0000000000..f1622e45c4
--- /dev/null
+++ b/source3/lib/netapi/tests/netuser.c
@@ -0,0 +1,458 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetUser testsuite
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+#include "common.h"
+
+static NET_API_STATUS test_netuserenum(const char *hostname,
+ uint32_t level,
+ const char *username)
+{
+ NET_API_STATUS status;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ const char *current_name;
+ int found_user = 0;
+ uint8_t *buffer = NULL;
+ int i;
+
+ struct USER_INFO_0 *info0;
+ struct USER_INFO_1 *info1;
+ struct USER_INFO_2 *info2;
+ struct USER_INFO_3 *info3;
+ struct USER_INFO_4 *info4;
+ struct USER_INFO_10 *info10;
+ struct USER_INFO_11 *info11;
+ struct USER_INFO_20 *info20;
+ struct USER_INFO_23 *info23;
+
+ printf("testing NetUserEnum level %d\n", level);
+
+ do {
+ status = NetUserEnum(hostname,
+ level,
+ FILTER_NORMAL_ACCOUNT,
+ &buffer,
+ 120, //(uint32_t)-1,
+ &entries_read,
+ &total_entries,
+ &resume_handle);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+ switch (level) {
+ case 0:
+ info0 = (struct USER_INFO_0 *)buffer;
+ break;
+ case 1:
+ info1 = (struct USER_INFO_1 *)buffer;
+ break;
+ case 2:
+ info2 = (struct USER_INFO_2 *)buffer;
+ break;
+ case 3:
+ info3 = (struct USER_INFO_3 *)buffer;
+ break;
+ case 4:
+ info4 = (struct USER_INFO_4 *)buffer;
+ break;
+ case 10:
+ info10 = (struct USER_INFO_10 *)buffer;
+ break;
+ case 11:
+ info11 = (struct USER_INFO_11 *)buffer;
+ break;
+ case 20:
+ info20 = (struct USER_INFO_20 *)buffer;
+ break;
+ case 23:
+ info23 = (struct USER_INFO_23 *)buffer;
+ break;
+ default:
+ return -1;
+ }
+
+ for (i=0; i<entries_read; i++) {
+
+ switch (level) {
+ case 0:
+ current_name = info0->usri0_name;
+ break;
+ case 1:
+ current_name = info1->usri1_name;
+ break;
+ case 2:
+ current_name = info2->usri2_name;
+ break;
+ case 3:
+ current_name = info3->usri3_name;
+ break;
+ case 4:
+ current_name = info4->usri4_name;
+ break;
+ case 10:
+ current_name = info10->usri10_name;
+ break;
+ case 11:
+ current_name = info11->usri11_name;
+ break;
+ case 20:
+ current_name = info20->usri20_name;
+ break;
+ case 23:
+ current_name = info23->usri23_name;
+ break;
+ default:
+ return -1;
+ }
+
+ if (strcasecmp(current_name, username) == 0) {
+ found_user = 1;
+ }
+
+ switch (level) {
+ case 0:
+ info0++;
+ break;
+ case 1:
+ info1++;
+ break;
+ case 2:
+ info2++;
+ break;
+ case 3:
+ info3++;
+ break;
+ case 4:
+ info4++;
+ break;
+ case 10:
+ info10++;
+ break;
+ case 11:
+ info11++;
+ break;
+ case 20:
+ info20++;
+ break;
+ case 23:
+ info23++;
+ break;
+ default:
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status) {
+ return status;
+ }
+
+ if (!found_user) {
+ printf("failed to get user\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+NET_API_STATUS test_netuseradd(const char *hostname,
+ const char *username)
+{
+ struct USER_INFO_1 u1;
+ uint32_t parm_err = 0;
+
+ ZERO_STRUCT(u1);
+
+ printf("testing NetUserAdd\n");
+
+ u1.usri1_name = username;
+ u1.usri1_password = "W297!832jD8J";
+ u1.usri1_password_age = 0;
+ u1.usri1_priv = 0;
+ u1.usri1_home_dir = NULL;
+ u1.usri1_comment = "User created using Samba NetApi Example code";
+ u1.usri1_flags = 0;
+ u1.usri1_script_path = NULL;
+
+ return NetUserAdd(hostname, 1, (uint8_t *)&u1, &parm_err);
+}
+
+static NET_API_STATUS test_netusermodals(struct libnetapi_ctx *ctx,
+ const char *hostname)
+{
+ NET_API_STATUS status;
+ struct USER_MODALS_INFO_0 *u0 = NULL;
+ struct USER_MODALS_INFO_0 *_u0 = NULL;
+ uint8_t *buffer = NULL;
+ uint32_t parm_err = 0;
+ uint32_t levels[] = { 0, 1, 2, 3 };
+ int i = 0;
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ printf("testing NetUserModalsGet level %d\n", levels[i]);
+
+ status = NetUserModalsGet(hostname, levels[i], &buffer);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetUserModalsGet");
+ return status;
+ }
+ }
+
+ status = NetUserModalsGet(hostname, 0, (uint8_t **)&u0);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetUserModalsGet");
+ return status;
+ }
+
+ printf("testing NetUserModalsSet\n");
+
+ status = NetUserModalsSet(hostname, 0, (uint8_t *)u0, &parm_err);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetUserModalsSet");
+ return status;
+ }
+
+ status = NetUserModalsGet(hostname, 0, (uint8_t **)&_u0);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetUserModalsGet");
+ return status;
+ }
+
+ if (memcmp(u0, _u0, sizeof(u0) != 0)) {
+ printf("USER_MODALS_INFO_0 struct has changed!!!!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static NET_API_STATUS test_netusergetgroups(const char *hostname,
+ uint32_t level,
+ const char *username,
+ const char *groupname)
+{
+ NET_API_STATUS status;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ const char *current_name;
+ int found_group = 0;
+ uint8_t *buffer = NULL;
+ int i;
+
+ struct GROUP_USERS_INFO_0 *i0;
+ struct GROUP_USERS_INFO_1 *i1;
+
+ printf("testing NetUserGetGroups level %d\n", level);
+
+ do {
+ status = NetUserGetGroups(hostname,
+ username,
+ level,
+ &buffer,
+ 120, //(uint32_t)-1,
+ &entries_read,
+ &total_entries);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+ switch (level) {
+ case 0:
+ i0 = (struct GROUP_USERS_INFO_0 *)buffer;
+ break;
+ case 1:
+ i1 = (struct GROUP_USERS_INFO_1 *)buffer;
+ break;
+ default:
+ return -1;
+ }
+
+ for (i=0; i<entries_read; i++) {
+
+ switch (level) {
+ case 0:
+ current_name = i0->grui0_name;
+ break;
+ case 1:
+ current_name = i1->grui1_name;
+ break;
+ default:
+ return -1;
+ }
+
+ if (groupname && strcasecmp(current_name, groupname) == 0) {
+ found_group = 1;
+ }
+
+ switch (level) {
+ case 0:
+ i0++;
+ break;
+ case 1:
+ i1++;
+ break;
+ default:
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status) {
+ return status;
+ }
+
+ if (groupname && !found_group) {
+ printf("failed to get membership\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+NET_API_STATUS netapitest_user(struct libnetapi_ctx *ctx,
+ const char *hostname)
+{
+ NET_API_STATUS status = 0;
+ const char *username, *username2;
+ uint8_t *buffer = NULL;
+ uint32_t levels[] = { 0, 1, 2, 3, 4, 10, 11, 20, 23 };
+ uint32_t enum_levels[] = { 0, 1, 2, 3, 4, 10, 11, 20, 23 };
+ uint32_t getgr_levels[] = { 0, 1 };
+ int i;
+
+ struct USER_INFO_1007 u1007;
+ uint32_t parm_err = 0;
+
+ printf("NetUser tests\n");
+
+ username = "torture_test_user";
+ username2 = "torture_test_user2";
+
+ /* cleanup */
+ NetUserDel(hostname, username);
+ NetUserDel(hostname, username2);
+
+ /* add a user */
+
+ status = test_netuseradd(hostname, username);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetUserAdd");
+ goto out;
+ }
+
+ /* enum the new user */
+
+ for (i=0; i<ARRAY_SIZE(enum_levels); i++) {
+
+ status = test_netuserenum(hostname, enum_levels[i], username);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetUserEnum");
+ goto out;
+ }
+ }
+
+ /* basic queries */
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ printf("testing NetUserGetInfo level %d\n", levels[i]);
+
+ status = NetUserGetInfo(hostname, username, levels[i], &buffer);
+ if (status && status != 124) {
+ NETAPI_STATUS(ctx, status, "NetUserGetInfo");
+ goto out;
+ }
+ }
+
+ /* testing getgroups */
+
+ for (i=0; i<ARRAY_SIZE(getgr_levels); i++) {
+
+ status = test_netusergetgroups(hostname, getgr_levels[i], username, NULL);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetUserGetGroups");
+ goto out;
+ }
+ }
+
+ /* modify description */
+
+ printf("testing NetUserSetInfo level %d\n", 1007);
+
+ u1007.usri1007_comment = "NetApi modified user";
+
+ status = NetUserSetInfo(hostname, username, 1007, (uint8_t *)&u1007, &parm_err);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetUserSetInfo");
+ goto out;
+ }
+
+ /* query info */
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+ status = NetUserGetInfo(hostname, username, levels[i], &buffer);
+ if (status && status != 124) {
+ NETAPI_STATUS(ctx, status, "NetUserGetInfo");
+ goto out;
+ }
+ }
+
+ /* delete */
+
+ printf("testing NetUserDel\n");
+
+ status = NetUserDel(hostname, username);
+ if (status) {
+ NETAPI_STATUS(ctx, status, "NetUserDel");
+ goto out;
+ }
+
+ /* should not exist anymore */
+
+ status = NetUserGetInfo(hostname, username, 0, &buffer);
+ if (status == 0) {
+ NETAPI_STATUS(ctx, status, "NetUserGetInfo");
+ goto out;
+ }
+
+ status = test_netusermodals(ctx, hostname);
+ if (status) {
+ goto out;
+ }
+
+ status = 0;
+
+ printf("NetUser tests succeeded\n");
+ out:
+ if (status != 0) {
+ printf("NetUser testsuite failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ }
+
+ return status;
+}
diff --git a/source3/lib/netapi/user.c b/source3/lib/netapi/user.c
new file mode 100644
index 0000000000..7d0c47f331
--- /dev/null
+++ b/source3/lib/netapi/user.c
@@ -0,0 +1,3440 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi User Support
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#include "librpc/gen_ndr/libnetapi.h"
+#include "lib/netapi/netapi.h"
+#include "lib/netapi/netapi_private.h"
+#include "lib/netapi/libnetapi.h"
+
+/****************************************************************
+****************************************************************/
+
+static void convert_USER_INFO_X_to_samr_user_info21(struct USER_INFO_X *infoX,
+ struct samr_UserInfo21 *info21)
+{
+ uint32_t fields_present = 0;
+ struct samr_LogonHours zero_logon_hours;
+ struct lsa_BinaryString zero_parameters;
+ NTTIME password_age;
+
+ ZERO_STRUCTP(info21);
+ ZERO_STRUCT(zero_logon_hours);
+ ZERO_STRUCT(zero_parameters);
+
+ if (infoX->usriX_flags) {
+ fields_present |= SAMR_FIELD_ACCT_FLAGS;
+ }
+ if (infoX->usriX_name) {
+ fields_present |= SAMR_FIELD_ACCOUNT_NAME;
+ }
+ if (infoX->usriX_password) {
+ fields_present |= SAMR_FIELD_PASSWORD;
+ }
+ if (infoX->usriX_flags) {
+ fields_present |= SAMR_FIELD_ACCT_FLAGS;
+ }
+ if (infoX->usriX_name) {
+ fields_present |= SAMR_FIELD_FULL_NAME;
+ }
+ if (infoX->usriX_home_dir) {
+ fields_present |= SAMR_FIELD_HOME_DIRECTORY;
+ }
+ if (infoX->usriX_script_path) {
+ fields_present |= SAMR_FIELD_LOGON_SCRIPT;
+ }
+ if (infoX->usriX_comment) {
+ fields_present |= SAMR_FIELD_DESCRIPTION;
+ }
+ if (infoX->usriX_password_age) {
+ fields_present |= SAMR_FIELD_FORCE_PWD_CHANGE;
+ }
+ if (infoX->usriX_full_name) {
+ fields_present |= SAMR_FIELD_FULL_NAME;
+ }
+ if (infoX->usriX_usr_comment) {
+ fields_present |= SAMR_FIELD_COMMENT;
+ }
+ if (infoX->usriX_profile) {
+ fields_present |= SAMR_FIELD_PROFILE_PATH;
+ }
+ if (infoX->usriX_home_dir_drive) {
+ fields_present |= SAMR_FIELD_HOME_DRIVE;
+ }
+ if (infoX->usriX_primary_group_id) {
+ fields_present |= SAMR_FIELD_PRIMARY_GID;
+ }
+ if (infoX->usriX_country_code) {
+ fields_present |= SAMR_FIELD_COUNTRY_CODE;
+ }
+ if (infoX->usriX_workstations) {
+ fields_present |= SAMR_FIELD_WORKSTATIONS;
+ }
+
+ unix_to_nt_time_abs(&password_age, infoX->usriX_password_age);
+
+ /* TODO: infoX->usriX_priv */
+ init_samr_user_info21(info21,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ password_age,
+ infoX->usriX_name,
+ infoX->usriX_full_name,
+ infoX->usriX_home_dir,
+ infoX->usriX_home_dir_drive,
+ infoX->usriX_script_path,
+ infoX->usriX_profile,
+ infoX->usriX_comment,
+ infoX->usriX_workstations,
+ infoX->usriX_usr_comment,
+ &zero_parameters,
+ 0,
+ infoX->usriX_primary_group_id,
+ infoX->usriX_flags,
+ fields_present,
+ zero_logon_hours,
+ 0,
+ 0,
+ infoX->usriX_country_code,
+ 0,
+ 0,
+ 0,
+ 0);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS construct_USER_INFO_X(uint32_t level,
+ uint8_t *buffer,
+ struct USER_INFO_X *uX)
+{
+ struct USER_INFO_0 *u0 = NULL;
+ struct USER_INFO_1 *u1 = NULL;
+ struct USER_INFO_2 *u2 = NULL;
+ struct USER_INFO_1003 *u1003 = NULL;
+ struct USER_INFO_1006 *u1006 = NULL;
+ struct USER_INFO_1007 *u1007 = NULL;
+ struct USER_INFO_1009 *u1009 = NULL;
+ struct USER_INFO_1011 *u1011 = NULL;
+ struct USER_INFO_1012 *u1012 = NULL;
+ struct USER_INFO_1014 *u1014 = NULL;
+ struct USER_INFO_1024 *u1024 = NULL;
+ struct USER_INFO_1051 *u1051 = NULL;
+ struct USER_INFO_1052 *u1052 = NULL;
+ struct USER_INFO_1053 *u1053 = NULL;
+
+ if (!buffer || !uX) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ZERO_STRUCTP(uX);
+
+ switch (level) {
+ case 0:
+ u0 = (struct USER_INFO_0 *)buffer;
+ uX->usriX_name = u0->usri0_name;
+ break;
+ case 1:
+ u1 = (struct USER_INFO_1 *)buffer;
+ uX->usriX_name = u1->usri1_name;
+ uX->usriX_password = u1->usri1_password;
+ uX->usriX_password_age = u1->usri1_password_age;
+ uX->usriX_priv = u1->usri1_priv;
+ uX->usriX_home_dir = u1->usri1_home_dir;
+ uX->usriX_comment = u1->usri1_comment;
+ uX->usriX_flags = u1->usri1_flags;
+ uX->usriX_script_path = u1->usri1_script_path;
+ break;
+ case 2:
+ u2 = (struct USER_INFO_2 *)buffer;
+ uX->usriX_name = u2->usri2_name;
+ uX->usriX_password = u2->usri2_password;
+ uX->usriX_password_age = u2->usri2_password_age;
+ uX->usriX_priv = u2->usri2_priv;
+ uX->usriX_home_dir = u2->usri2_home_dir;
+ uX->usriX_comment = u2->usri2_comment;
+ uX->usriX_flags = u2->usri2_flags;
+ uX->usriX_script_path = u2->usri2_script_path;
+ uX->usriX_auth_flags = u2->usri2_auth_flags;
+ uX->usriX_full_name = u2->usri2_full_name;
+ uX->usriX_usr_comment = u2->usri2_usr_comment;
+ uX->usriX_parms = u2->usri2_parms;
+ uX->usriX_workstations = u2->usri2_workstations;
+ uX->usriX_last_logon = u2->usri2_last_logon;
+ uX->usriX_last_logoff = u2->usri2_last_logoff;
+ uX->usriX_acct_expires = u2->usri2_acct_expires;
+ uX->usriX_max_storage = u2->usri2_max_storage;
+ uX->usriX_units_per_week= u2->usri2_units_per_week;
+ uX->usriX_logon_hours = u2->usri2_logon_hours;
+ uX->usriX_bad_pw_count = u2->usri2_bad_pw_count;
+ uX->usriX_num_logons = u2->usri2_num_logons;
+ uX->usriX_logon_server = u2->usri2_logon_server;
+ uX->usriX_country_code = u2->usri2_country_code;
+ uX->usriX_code_page = u2->usri2_code_page;
+ break;
+ case 1003:
+ u1003 = (struct USER_INFO_1003 *)buffer;
+ uX->usriX_password = u1003->usri1003_password;
+ break;
+ case 1006:
+ u1006 = (struct USER_INFO_1006 *)buffer;
+ uX->usriX_home_dir = u1006->usri1006_home_dir;
+ break;
+ case 1007:
+ u1007 = (struct USER_INFO_1007 *)buffer;
+ uX->usriX_comment = u1007->usri1007_comment;
+ break;
+ case 1009:
+ u1009 = (struct USER_INFO_1009 *)buffer;
+ uX->usriX_script_path = u1009->usri1009_script_path;
+ break;
+ case 1011:
+ u1011 = (struct USER_INFO_1011 *)buffer;
+ uX->usriX_full_name = u1011->usri1011_full_name;
+ break;
+ case 1012:
+ u1012 = (struct USER_INFO_1012 *)buffer;
+ uX->usriX_usr_comment = u1012->usri1012_usr_comment;
+ break;
+ case 1014:
+ u1014 = (struct USER_INFO_1014 *)buffer;
+ uX->usriX_workstations = u1014->usri1014_workstations;
+ break;
+ case 1024:
+ u1024 = (struct USER_INFO_1024 *)buffer;
+ uX->usriX_country_code = u1024->usri1024_country_code;
+ break;
+ case 1051:
+ u1051 = (struct USER_INFO_1051 *)buffer;
+ uX->usriX_primary_group_id = u1051->usri1051_primary_group_id;
+ break;
+ case 1052:
+ u1052 = (struct USER_INFO_1052 *)buffer;
+ uX->usriX_profile = u1052->usri1052_profile;
+ break;
+ case 1053:
+ u1053 = (struct USER_INFO_1053 *)buffer;
+ uX->usriX_home_dir_drive = u1053->usri1053_home_dir_drive;
+ break;
+ case 3:
+ case 4:
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS set_user_info_USER_INFO_X(TALLOC_CTX *ctx,
+ struct rpc_pipe_client *pipe_cli,
+ DATA_BLOB *session_key,
+ struct policy_handle *user_handle,
+ struct USER_INFO_X *uX)
+{
+ union samr_UserInfo user_info;
+ struct samr_UserInfo21 info21;
+ NTSTATUS status;
+
+ if (!uX) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ convert_USER_INFO_X_to_samr_user_info21(uX, &info21);
+
+ ZERO_STRUCT(user_info);
+
+ if (uX->usriX_password) {
+
+ user_info.info25.info = info21;
+
+ init_samr_CryptPasswordEx(uX->usriX_password,
+ session_key,
+ &user_info.info25.password);
+
+ status = rpccli_samr_SetUserInfo2(pipe_cli, ctx,
+ user_handle,
+ 25,
+ &user_info);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS(DCERPC_FAULT_INVALID_TAG))) {
+
+ user_info.info23.info = info21;
+
+ init_samr_CryptPassword(uX->usriX_password,
+ session_key,
+ &user_info.info23.password);
+
+ status = rpccli_samr_SetUserInfo2(pipe_cli, ctx,
+ user_handle,
+ 23,
+ &user_info);
+ }
+ } else {
+
+ user_info.info21 = info21;
+
+ status = rpccli_samr_SetUserInfo(pipe_cli, ctx,
+ user_handle,
+ 21,
+ &user_info);
+ }
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserAdd_r(struct libnetapi_ctx *ctx,
+ struct NetUserAdd *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ POLICY_HND connect_handle, domain_handle, user_handle;
+ struct lsa_String lsa_account_name;
+ struct dom_sid2 *domain_sid = NULL;
+ union samr_UserInfo *user_info = NULL;
+ struct samr_PwInfo pw_info;
+ uint32_t access_granted = 0;
+ uint32_t rid = 0;
+ struct USER_INFO_X uX;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(user_handle);
+
+ if (!r->in.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 1:
+ break;
+ case 2:
+ case 3:
+ case 4:
+ default:
+ werr = WERR_NOT_SUPPORTED;
+ goto done;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = construct_USER_INFO_X(r->in.level, r->in.buffer, &uX);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 |
+ SAMR_DOMAIN_ACCESS_CREATE_USER |
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_account_name, uX.usriX_name);
+
+ status = rpccli_samr_CreateUser2(pipe_cli, ctx,
+ &domain_handle,
+ &lsa_account_name,
+ ACB_NORMAL,
+ SEC_STD_WRITE_DAC |
+ SEC_STD_DELETE |
+ SAMR_USER_ACCESS_SET_PASSWORD |
+ SAMR_USER_ACCESS_SET_ATTRIBUTES |
+ SAMR_USER_ACCESS_GET_ATTRIBUTES,
+ &user_handle,
+ &access_granted,
+ &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_QueryUserInfo(pipe_cli, ctx,
+ &user_handle,
+ 16,
+ &user_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ if (!(user_info->info16.acct_flags & ACB_NORMAL)) {
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ status = rpccli_samr_GetUserPwInfo(pipe_cli, ctx,
+ &user_handle,
+ &pw_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ uX.usriX_flags |= ACB_NORMAL;
+
+ status = set_user_info_USER_INFO_X(ctx, pipe_cli,
+ &cli->user_session_key,
+ &user_handle,
+ &uX);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto failed;
+ }
+
+ werr = WERR_OK;
+ goto done;
+
+ failed:
+ rpccli_samr_DeleteUser(pipe_cli, ctx,
+ &user_handle);
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&user_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &user_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserAdd_l(struct libnetapi_ctx *ctx,
+ struct NetUserAdd *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetUserAdd);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserDel_r(struct libnetapi_ctx *ctx,
+ struct NetUserDel *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ POLICY_HND connect_handle, builtin_handle, domain_handle, user_handle;
+ struct lsa_String lsa_account_name;
+ struct samr_Ids user_rids, name_types;
+ struct dom_sid2 *domain_sid = NULL;
+ struct dom_sid2 user_sid;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(builtin_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(user_handle);
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = rpccli_samr_OpenDomain(pipe_cli, ctx,
+ &connect_handle,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ CONST_DISCARD(DOM_SID *, &global_sid_Builtin),
+ &builtin_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ init_lsa_String(&lsa_account_name, r->in.user_name);
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ 1,
+ &lsa_account_name,
+ &user_rids,
+ &name_types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_OpenUser(pipe_cli, ctx,
+ &domain_handle,
+ STD_RIGHT_DELETE_ACCESS,
+ user_rids.ids[0],
+ &user_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ sid_compose(&user_sid, domain_sid, user_rids.ids[0]);
+
+ status = rpccli_samr_RemoveMemberFromForeignDomain(pipe_cli, ctx,
+ &builtin_handle,
+ &user_sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_DeleteUser(pipe_cli, ctx,
+ &user_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ werr = WERR_OK;
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&user_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &user_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserDel_l(struct libnetapi_ctx *ctx,
+ struct NetUserDel *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetUserDel);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS libnetapi_samr_lookup_user(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct policy_handle *domain_handle,
+ struct policy_handle *builtin_handle,
+ const char *user_name,
+ const struct dom_sid *domain_sid,
+ uint32_t rid,
+ uint32_t level,
+ struct samr_UserInfo21 **info21,
+ struct sec_desc_buf **sec_desc,
+ uint32_t *auth_flag_p)
+{
+ NTSTATUS status;
+
+ struct policy_handle user_handle;
+ union samr_UserInfo *user_info = NULL;
+ struct samr_RidWithAttributeArray *rid_array = NULL;
+ uint32_t access_mask = SEC_STD_READ_CONTROL |
+ SAMR_USER_ACCESS_GET_ATTRIBUTES |
+ SAMR_USER_ACCESS_GET_NAME_ETC;
+
+ ZERO_STRUCT(user_handle);
+
+ switch (level) {
+ case 0:
+ break;
+ case 1:
+ access_mask |= SAMR_USER_ACCESS_GET_LOGONINFO |
+ SAMR_USER_ACCESS_GET_GROUPS;
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 11:
+ access_mask |= SAMR_USER_ACCESS_GET_LOGONINFO |
+ SAMR_USER_ACCESS_GET_GROUPS |
+ SAMR_USER_ACCESS_GET_LOCALE;
+ break;
+ case 10:
+ case 20:
+ case 23:
+ break;
+ default:
+ return NT_STATUS_INVALID_LEVEL;
+ }
+
+ if (level == 0) {
+ return NT_STATUS_OK;
+ }
+
+ status = rpccli_samr_OpenUser(pipe_cli, mem_ctx,
+ domain_handle,
+ access_mask,
+ rid,
+ &user_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = rpccli_samr_QueryUserInfo(pipe_cli, mem_ctx,
+ &user_handle,
+ 21,
+ &user_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = rpccli_samr_QuerySecurity(pipe_cli, mem_ctx,
+ &user_handle,
+ SECINFO_DACL,
+ sec_desc);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (access_mask & SAMR_USER_ACCESS_GET_GROUPS) {
+
+ struct lsa_SidArray sid_array;
+ struct samr_Ids alias_rids;
+ int i;
+ uint32_t auth_flag = 0;
+ struct dom_sid sid;
+
+ status = rpccli_samr_GetGroupsForUser(pipe_cli, mem_ctx,
+ &user_handle,
+ &rid_array);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ sid_array.num_sids = rid_array->count + 1;
+ sid_array.sids = talloc_array(mem_ctx, struct lsa_SidPtr,
+ sid_array.num_sids);
+ NT_STATUS_HAVE_NO_MEMORY(sid_array.sids);
+
+ for (i=0; i<rid_array->count; i++) {
+ sid_compose(&sid, domain_sid, rid_array->rids[i].rid);
+ sid_array.sids[i].sid = sid_dup_talloc(mem_ctx, &sid);
+ NT_STATUS_HAVE_NO_MEMORY(sid_array.sids[i].sid);
+ }
+
+ sid_compose(&sid, domain_sid, rid);
+ sid_array.sids[i].sid = sid_dup_talloc(mem_ctx, &sid);
+ NT_STATUS_HAVE_NO_MEMORY(sid_array.sids[i].sid);
+
+ status = rpccli_samr_GetAliasMembership(pipe_cli, mem_ctx,
+ builtin_handle,
+ &sid_array,
+ &alias_rids);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ for (i=0; i<alias_rids.count; i++) {
+ switch (alias_rids.ids[i]) {
+ case 550: /* Print Operators */
+ auth_flag |= AF_OP_PRINT;
+ break;
+ case 549: /* Server Operators */
+ auth_flag |= AF_OP_SERVER;
+ break;
+ case 548: /* Account Operators */
+ auth_flag |= AF_OP_ACCOUNTS;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (auth_flag_p) {
+ *auth_flag_p = auth_flag;
+ }
+ }
+
+ *info21 = &user_info->info21;
+
+ done:
+ if (is_valid_policy_hnd(&user_handle)) {
+ rpccli_samr_Close(pipe_cli, mem_ctx, &user_handle);
+ }
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+static uint32_t samr_rid_to_priv_level(uint32_t rid)
+{
+ switch (rid) {
+ case DOMAIN_RID_ADMINISTRATOR:
+ return USER_PRIV_ADMIN;
+ case DOMAIN_RID_GUEST:
+ return USER_PRIV_GUEST;
+ default:
+ return USER_PRIV_USER;
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+static uint32_t samr_acb_flags_to_netapi_flags(uint32_t acb)
+{
+ uint32_t fl = UF_SCRIPT; /* god knows why */
+
+ fl |= ads_acb2uf(acb);
+
+ return fl;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS info21_to_USER_INFO_1(TALLOC_CTX *mem_ctx,
+ const struct samr_UserInfo21 *i21,
+ struct USER_INFO_1 *i)
+{
+ ZERO_STRUCTP(i);
+ i->usri1_name = talloc_strdup(mem_ctx, i21->account_name.string);
+ NT_STATUS_HAVE_NO_MEMORY(i->usri1_name);
+ i->usri1_password = NULL;
+ i->usri1_password_age = time(NULL) - nt_time_to_unix(i21->last_password_change);
+ i->usri1_priv = samr_rid_to_priv_level(i21->rid);
+ i->usri1_home_dir = talloc_strdup(mem_ctx, i21->home_directory.string);
+ i->usri1_comment = talloc_strdup(mem_ctx, i21->description.string);
+ i->usri1_flags = samr_acb_flags_to_netapi_flags(i21->acct_flags);
+ i->usri1_script_path = talloc_strdup(mem_ctx, i21->logon_script.string);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS info21_to_USER_INFO_2(TALLOC_CTX *mem_ctx,
+ const struct samr_UserInfo21 *i21,
+ uint32_t auth_flag,
+ struct USER_INFO_2 *i)
+{
+ ZERO_STRUCTP(i);
+
+ i->usri2_name = talloc_strdup(mem_ctx, i21->account_name.string);
+ NT_STATUS_HAVE_NO_MEMORY(i->usri2_name);
+ i->usri2_password = NULL;
+ i->usri2_password_age = time(NULL) - nt_time_to_unix(i21->last_password_change);
+ i->usri2_priv = samr_rid_to_priv_level(i21->rid);
+ i->usri2_home_dir = talloc_strdup(mem_ctx, i21->home_directory.string);
+ i->usri2_comment = talloc_strdup(mem_ctx, i21->description.string);
+ i->usri2_flags = samr_acb_flags_to_netapi_flags(i21->acct_flags);
+ i->usri2_script_path = talloc_strdup(mem_ctx, i21->logon_script.string);
+ i->usri2_auth_flags = auth_flag;
+ i->usri2_full_name = talloc_strdup(mem_ctx, i21->full_name.string);
+ i->usri2_usr_comment = talloc_strdup(mem_ctx, i21->comment.string);
+ i->usri2_parms = talloc_strndup(mem_ctx, (const char *)i21->parameters.array, i21->parameters.size/2);
+ i->usri2_workstations = talloc_strdup(mem_ctx, i21->workstations.string);
+ i->usri2_last_logon = nt_time_to_unix(i21->last_logon);
+ i->usri2_last_logoff = nt_time_to_unix(i21->last_logoff);
+ i->usri2_acct_expires = nt_time_to_unix(i21->acct_expiry);
+ i->usri2_max_storage = USER_MAXSTORAGE_UNLIMITED; /* FIXME */
+ i->usri2_units_per_week = i21->logon_hours.units_per_week;
+ i->usri2_logon_hours = (uint8_t *)talloc_memdup(mem_ctx, i21->logon_hours.bits, 21);
+ i->usri2_bad_pw_count = i21->bad_password_count;
+ i->usri2_num_logons = i21->logon_count;
+ i->usri2_logon_server = talloc_strdup(mem_ctx, "\\\\*");
+ i->usri2_country_code = i21->country_code;
+ i->usri2_code_page = i21->code_page;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS info21_to_USER_INFO_3(TALLOC_CTX *mem_ctx,
+ const struct samr_UserInfo21 *i21,
+ uint32_t auth_flag,
+ struct USER_INFO_3 *i)
+{
+ ZERO_STRUCTP(i);
+
+ i->usri3_name = talloc_strdup(mem_ctx, i21->account_name.string);
+ NT_STATUS_HAVE_NO_MEMORY(i->usri3_name);
+ i->usri3_password_age = time(NULL) - nt_time_to_unix(i21->last_password_change);
+ i->usri3_priv = samr_rid_to_priv_level(i21->rid);
+ i->usri3_home_dir = talloc_strdup(mem_ctx, i21->home_directory.string);
+ i->usri3_comment = talloc_strdup(mem_ctx, i21->description.string);
+ i->usri3_flags = samr_acb_flags_to_netapi_flags(i21->acct_flags);
+ i->usri3_script_path = talloc_strdup(mem_ctx, i21->logon_script.string);
+ i->usri3_auth_flags = auth_flag;
+ i->usri3_full_name = talloc_strdup(mem_ctx, i21->full_name.string);
+ i->usri3_usr_comment = talloc_strdup(mem_ctx, i21->comment.string);
+ i->usri3_parms = talloc_strndup(mem_ctx, (const char *)i21->parameters.array, i21->parameters.size/2);
+ i->usri3_workstations = talloc_strdup(mem_ctx, i21->workstations.string);
+ i->usri3_last_logon = nt_time_to_unix(i21->last_logon);
+ i->usri3_last_logoff = nt_time_to_unix(i21->last_logoff);
+ i->usri3_acct_expires = nt_time_to_unix(i21->acct_expiry);
+ i->usri3_max_storage = USER_MAXSTORAGE_UNLIMITED; /* FIXME */
+ i->usri3_units_per_week = i21->logon_hours.units_per_week;
+ i->usri3_logon_hours = (uint8_t *)talloc_memdup(mem_ctx, i21->logon_hours.bits, 21);
+ i->usri3_bad_pw_count = i21->bad_password_count;
+ i->usri3_num_logons = i21->logon_count;
+ i->usri3_logon_server = talloc_strdup(mem_ctx, "\\\\*");
+ i->usri3_country_code = i21->country_code;
+ i->usri3_code_page = i21->code_page;
+ i->usri3_user_id = i21->rid;
+ i->usri3_primary_group_id = i21->primary_gid;
+ i->usri3_profile = talloc_strdup(mem_ctx, i21->profile_path.string);
+ i->usri3_home_dir_drive = talloc_strdup(mem_ctx, i21->home_drive.string);
+ i->usri3_password_expired = i21->password_expired;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS info21_to_USER_INFO_4(TALLOC_CTX *mem_ctx,
+ const struct samr_UserInfo21 *i21,
+ uint32_t auth_flag,
+ struct dom_sid *domain_sid,
+ struct USER_INFO_4 *i)
+{
+ struct dom_sid sid;
+
+ ZERO_STRUCTP(i);
+
+ i->usri4_name = talloc_strdup(mem_ctx, i21->account_name.string);
+ NT_STATUS_HAVE_NO_MEMORY(i->usri4_name);
+ i->usri4_password_age = time(NULL) - nt_time_to_unix(i21->last_password_change);
+ i->usri4_password = NULL;
+ i->usri4_priv = samr_rid_to_priv_level(i21->rid);
+ i->usri4_home_dir = talloc_strdup(mem_ctx, i21->home_directory.string);
+ i->usri4_comment = talloc_strdup(mem_ctx, i21->description.string);
+ i->usri4_flags = samr_acb_flags_to_netapi_flags(i21->acct_flags);
+ i->usri4_script_path = talloc_strdup(mem_ctx, i21->logon_script.string);
+ i->usri4_auth_flags = auth_flag;
+ i->usri4_full_name = talloc_strdup(mem_ctx, i21->full_name.string);
+ i->usri4_usr_comment = talloc_strdup(mem_ctx, i21->comment.string);
+ i->usri4_parms = talloc_strndup(mem_ctx, (const char *)i21->parameters.array, i21->parameters.size/2);
+ i->usri4_workstations = talloc_strdup(mem_ctx, i21->workstations.string);
+ i->usri4_last_logon = nt_time_to_unix(i21->last_logon);
+ i->usri4_last_logoff = nt_time_to_unix(i21->last_logoff);
+ i->usri4_acct_expires = nt_time_to_unix(i21->acct_expiry);
+ i->usri4_max_storage = USER_MAXSTORAGE_UNLIMITED; /* FIXME */
+ i->usri4_units_per_week = i21->logon_hours.units_per_week;
+ i->usri4_logon_hours = (uint8_t *)talloc_memdup(mem_ctx, i21->logon_hours.bits, 21);
+ i->usri4_bad_pw_count = i21->bad_password_count;
+ i->usri4_num_logons = i21->logon_count;
+ i->usri4_logon_server = talloc_strdup(mem_ctx, "\\\\*");
+ i->usri4_country_code = i21->country_code;
+ i->usri4_code_page = i21->code_page;
+ if (!sid_compose(&sid, domain_sid, i21->rid)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ i->usri4_user_sid = (struct domsid *)sid_dup_talloc(mem_ctx, &sid);
+ i->usri4_primary_group_id = i21->primary_gid;
+ i->usri4_profile = talloc_strdup(mem_ctx, i21->profile_path.string);
+ i->usri4_home_dir_drive = talloc_strdup(mem_ctx, i21->home_drive.string);
+ i->usri4_password_expired = i21->password_expired;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS info21_to_USER_INFO_10(TALLOC_CTX *mem_ctx,
+ const struct samr_UserInfo21 *i21,
+ struct USER_INFO_10 *i)
+{
+ ZERO_STRUCTP(i);
+
+ i->usri10_name = talloc_strdup(mem_ctx, i21->account_name.string);
+ NT_STATUS_HAVE_NO_MEMORY(i->usri10_name);
+ i->usri10_comment = talloc_strdup(mem_ctx, i21->description.string);
+ i->usri10_full_name = talloc_strdup(mem_ctx, i21->full_name.string);
+ i->usri10_usr_comment = talloc_strdup(mem_ctx, i21->comment.string);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS info21_to_USER_INFO_11(TALLOC_CTX *mem_ctx,
+ const struct samr_UserInfo21 *i21,
+ uint32_t auth_flag,
+ struct USER_INFO_11 *i)
+{
+ ZERO_STRUCTP(i);
+
+ i->usri11_name = talloc_strdup(mem_ctx, i21->account_name.string);
+ NT_STATUS_HAVE_NO_MEMORY(i->usri11_name);
+ i->usri11_comment = talloc_strdup(mem_ctx, i21->description.string);
+ i->usri11_usr_comment = talloc_strdup(mem_ctx, i21->comment.string);
+ i->usri11_full_name = talloc_strdup(mem_ctx, i21->full_name.string);
+ i->usri11_priv = samr_rid_to_priv_level(i21->rid);
+ i->usri11_auth_flags = auth_flag;
+ i->usri11_password_age = time(NULL) - nt_time_to_unix(i21->last_password_change);
+ i->usri11_home_dir = talloc_strdup(mem_ctx, i21->home_directory.string);
+ i->usri11_parms = talloc_strndup(mem_ctx, (const char *)i21->parameters.array, i21->parameters.size/2);
+ i->usri11_last_logon = nt_time_to_unix(i21->last_logon);
+ i->usri11_last_logoff = nt_time_to_unix(i21->last_logoff);
+ i->usri11_bad_pw_count = i21->bad_password_count;
+ i->usri11_num_logons = i21->logon_count;
+ i->usri11_logon_server = talloc_strdup(mem_ctx, "\\\\*");
+ i->usri11_country_code = i21->country_code;
+ i->usri11_workstations = talloc_strdup(mem_ctx, i21->workstations.string);
+ i->usri11_max_storage = USER_MAXSTORAGE_UNLIMITED; /* FIXME */
+ i->usri11_units_per_week = i21->logon_hours.units_per_week;
+ i->usri11_logon_hours = (uint8_t *)talloc_memdup(mem_ctx, i21->logon_hours.bits, 21);
+ i->usri11_code_page = i21->code_page;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS info21_to_USER_INFO_20(TALLOC_CTX *mem_ctx,
+ const struct samr_UserInfo21 *i21,
+ struct USER_INFO_20 *i)
+{
+ ZERO_STRUCTP(i);
+
+ i->usri20_name = talloc_strdup(mem_ctx, i21->account_name.string);
+ NT_STATUS_HAVE_NO_MEMORY(i->usri20_name);
+ i->usri20_comment = talloc_strdup(mem_ctx, i21->description.string);
+ i->usri20_full_name = talloc_strdup(mem_ctx, i21->full_name.string);
+ i->usri20_flags = samr_acb_flags_to_netapi_flags(i21->acct_flags);
+ i->usri20_user_id = i21->rid;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS info21_to_USER_INFO_23(TALLOC_CTX *mem_ctx,
+ const struct samr_UserInfo21 *i21,
+ struct dom_sid *domain_sid,
+ struct USER_INFO_23 *i)
+{
+ struct dom_sid sid;
+
+ ZERO_STRUCTP(i);
+
+ i->usri23_name = talloc_strdup(mem_ctx, i21->account_name.string);
+ NT_STATUS_HAVE_NO_MEMORY(i->usri23_name);
+ i->usri23_comment = talloc_strdup(mem_ctx, i21->description.string);
+ i->usri23_full_name = talloc_strdup(mem_ctx, i21->full_name.string);
+ i->usri23_flags = samr_acb_flags_to_netapi_flags(i21->acct_flags);
+ if (!sid_compose(&sid, domain_sid, i21->rid)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ i->usri23_user_sid = (struct domsid *)sid_dup_talloc(mem_ctx, &sid);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS libnetapi_samr_lookup_user_map_USER_INFO(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct dom_sid *domain_sid,
+ struct policy_handle *domain_handle,
+ struct policy_handle *builtin_handle,
+ const char *user_name,
+ uint32_t rid,
+ uint32_t level,
+ uint8_t **buffer,
+ uint32_t *num_entries)
+{
+ NTSTATUS status;
+
+ struct samr_UserInfo21 *info21 = NULL;
+ struct sec_desc_buf *sec_desc = NULL;
+ uint32_t auth_flag = 0;
+
+ struct USER_INFO_0 info0;
+ struct USER_INFO_1 info1;
+ struct USER_INFO_2 info2;
+ struct USER_INFO_3 info3;
+ struct USER_INFO_4 info4;
+ struct USER_INFO_10 info10;
+ struct USER_INFO_11 info11;
+ struct USER_INFO_20 info20;
+ struct USER_INFO_23 info23;
+
+ switch (level) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 10:
+ case 11:
+ case 20:
+ case 23:
+ break;
+ default:
+ return NT_STATUS_INVALID_LEVEL;
+ }
+
+ if (level == 0) {
+ info0.usri0_name = talloc_strdup(mem_ctx, user_name);
+ NT_STATUS_HAVE_NO_MEMORY(info0.usri0_name);
+
+ ADD_TO_ARRAY(mem_ctx, struct USER_INFO_0, info0,
+ (struct USER_INFO_0 **)buffer, num_entries);
+
+ return NT_STATUS_OK;
+ }
+
+ status = libnetapi_samr_lookup_user(mem_ctx, pipe_cli,
+ domain_handle,
+ builtin_handle,
+ user_name,
+ domain_sid,
+ rid,
+ level,
+ &info21,
+ &sec_desc,
+ &auth_flag);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ switch (level) {
+ case 0:
+ /* already returned above */
+ break;
+ case 1:
+ status = info21_to_USER_INFO_1(mem_ctx, info21, &info1);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ ADD_TO_ARRAY(mem_ctx, struct USER_INFO_1, info1,
+ (struct USER_INFO_1 **)buffer, num_entries);
+
+ break;
+ case 2:
+ status = info21_to_USER_INFO_2(mem_ctx, info21, auth_flag, &info2);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ ADD_TO_ARRAY(mem_ctx, struct USER_INFO_2, info2,
+ (struct USER_INFO_2 **)buffer, num_entries);
+
+ break;
+ case 3:
+ status = info21_to_USER_INFO_3(mem_ctx, info21, auth_flag, &info3);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ ADD_TO_ARRAY(mem_ctx, struct USER_INFO_3, info3,
+ (struct USER_INFO_3 **)buffer, num_entries);
+
+ break;
+ case 4:
+ status = info21_to_USER_INFO_4(mem_ctx, info21, auth_flag, domain_sid, &info4);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ ADD_TO_ARRAY(mem_ctx, struct USER_INFO_4, info4,
+ (struct USER_INFO_4 **)buffer, num_entries);
+
+ break;
+ case 10:
+ status = info21_to_USER_INFO_10(mem_ctx, info21, &info10);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ ADD_TO_ARRAY(mem_ctx, struct USER_INFO_10, info10,
+ (struct USER_INFO_10 **)buffer, num_entries);
+
+ break;
+ case 11:
+ status = info21_to_USER_INFO_11(mem_ctx, info21, auth_flag, &info11);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ ADD_TO_ARRAY(mem_ctx, struct USER_INFO_11, info11,
+ (struct USER_INFO_11 **)buffer, num_entries);
+
+ break;
+ case 20:
+ status = info21_to_USER_INFO_20(mem_ctx, info21, &info20);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ ADD_TO_ARRAY(mem_ctx, struct USER_INFO_20, info20,
+ (struct USER_INFO_20 **)buffer, num_entries);
+
+ break;
+ case 23:
+ status = info21_to_USER_INFO_23(mem_ctx, info21, domain_sid, &info23);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ ADD_TO_ARRAY(mem_ctx, struct USER_INFO_23, info23,
+ (struct USER_INFO_23 **)buffer, num_entries);
+ break;
+ default:
+ return NT_STATUS_INVALID_LEVEL;
+ }
+
+ done:
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserEnum_r(struct libnetapi_ctx *ctx,
+ struct NetUserEnum *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct policy_handle connect_handle;
+ struct dom_sid2 *domain_sid = NULL;
+ struct policy_handle domain_handle, builtin_handle;
+ struct samr_SamArray *sam = NULL;
+ uint32_t filter = ACB_NORMAL;
+ int i;
+ uint32_t entries_read = 0;
+
+ NTSTATUS status = NT_STATUS_OK;
+ WERROR werr;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(builtin_handle);
+
+ if (!r->out.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ *r->out.buffer = NULL;
+ *r->out.entries_read = 0;
+
+ switch (r->in.level) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 10:
+ case 11:
+ case 20:
+ case 23:
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT |
+ SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS,
+ &connect_handle,
+ &builtin_handle);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 |
+ SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS |
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ switch (r->in.filter) {
+ case FILTER_NORMAL_ACCOUNT:
+ filter = ACB_NORMAL;
+ break;
+ case FILTER_TEMP_DUPLICATE_ACCOUNT:
+ filter = ACB_TEMPDUP;
+ break;
+ case FILTER_INTERDOMAIN_TRUST_ACCOUNT:
+ filter = ACB_DOMTRUST;
+ break;
+ case FILTER_WORKSTATION_TRUST_ACCOUNT:
+ filter = ACB_WSTRUST;
+ break;
+ case FILTER_SERVER_TRUST_ACCOUNT:
+ filter = ACB_SVRTRUST;
+ break;
+ default:
+ break;
+ }
+
+ status = rpccli_samr_EnumDomainUsers(pipe_cli,
+ ctx,
+ &domain_handle,
+ r->in.resume_handle,
+ filter,
+ &sam,
+ r->in.prefmaxlen,
+ &entries_read);
+ werr = ntstatus_to_werror(status);
+ if (NT_STATUS_IS_ERR(status)) {
+ goto done;
+ }
+
+ for (i=0; i < sam->count; i++) {
+
+ status = libnetapi_samr_lookup_user_map_USER_INFO(ctx, pipe_cli,
+ domain_sid,
+ &domain_handle,
+ &builtin_handle,
+ sam->entries[i].name.string,
+ sam->entries[i].idx,
+ r->in.level,
+ r->out.buffer,
+ r->out.entries_read);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ /* if last query */
+ if (NT_STATUS_IS_OK(status) ||
+ NT_STATUS_IS_ERR(status)) {
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserEnum_l(struct libnetapi_ctx *ctx,
+ struct NetUserEnum *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetUserEnum);
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR convert_samr_dispinfo_to_NET_DISPLAY_USER(TALLOC_CTX *mem_ctx,
+ struct samr_DispInfoGeneral *info,
+ uint32_t *entries_read,
+ void **buffer)
+{
+ struct NET_DISPLAY_USER *user = NULL;
+ int i;
+
+ user = TALLOC_ZERO_ARRAY(mem_ctx,
+ struct NET_DISPLAY_USER,
+ info->count);
+ W_ERROR_HAVE_NO_MEMORY(user);
+
+ for (i = 0; i < info->count; i++) {
+ user[i].usri1_name = talloc_strdup(mem_ctx,
+ info->entries[i].account_name.string);
+ user[i].usri1_comment = talloc_strdup(mem_ctx,
+ info->entries[i].description.string);
+ user[i].usri1_flags =
+ info->entries[i].acct_flags;
+ user[i].usri1_full_name = talloc_strdup(mem_ctx,
+ info->entries[i].full_name.string);
+ user[i].usri1_user_id =
+ info->entries[i].rid;
+ user[i].usri1_next_index =
+ info->entries[i].idx;
+
+ if (!user[i].usri1_name) {
+ return WERR_NOMEM;
+ }
+ }
+
+ *buffer = talloc_memdup(mem_ctx, user,
+ sizeof(struct NET_DISPLAY_USER) * info->count);
+ W_ERROR_HAVE_NO_MEMORY(*buffer);
+
+ *entries_read = info->count;
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR convert_samr_dispinfo_to_NET_DISPLAY_MACHINE(TALLOC_CTX *mem_ctx,
+ struct samr_DispInfoFull *info,
+ uint32_t *entries_read,
+ void **buffer)
+{
+ struct NET_DISPLAY_MACHINE *machine = NULL;
+ int i;
+
+ machine = TALLOC_ZERO_ARRAY(mem_ctx,
+ struct NET_DISPLAY_MACHINE,
+ info->count);
+ W_ERROR_HAVE_NO_MEMORY(machine);
+
+ for (i = 0; i < info->count; i++) {
+ machine[i].usri2_name = talloc_strdup(mem_ctx,
+ info->entries[i].account_name.string);
+ machine[i].usri2_comment = talloc_strdup(mem_ctx,
+ info->entries[i].description.string);
+ machine[i].usri2_flags =
+ info->entries[i].acct_flags;
+ machine[i].usri2_user_id =
+ info->entries[i].rid;
+ machine[i].usri2_next_index =
+ info->entries[i].idx;
+
+ if (!machine[i].usri2_name) {
+ return WERR_NOMEM;
+ }
+ }
+
+ *buffer = talloc_memdup(mem_ctx, machine,
+ sizeof(struct NET_DISPLAY_MACHINE) * info->count);
+ W_ERROR_HAVE_NO_MEMORY(*buffer);
+
+ *entries_read = info->count;
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR convert_samr_dispinfo_to_NET_DISPLAY_GROUP(TALLOC_CTX *mem_ctx,
+ struct samr_DispInfoFullGroups *info,
+ uint32_t *entries_read,
+ void **buffer)
+{
+ struct NET_DISPLAY_GROUP *group = NULL;
+ int i;
+
+ group = TALLOC_ZERO_ARRAY(mem_ctx,
+ struct NET_DISPLAY_GROUP,
+ info->count);
+ W_ERROR_HAVE_NO_MEMORY(group);
+
+ for (i = 0; i < info->count; i++) {
+ group[i].grpi3_name = talloc_strdup(mem_ctx,
+ info->entries[i].account_name.string);
+ group[i].grpi3_comment = talloc_strdup(mem_ctx,
+ info->entries[i].description.string);
+ group[i].grpi3_group_id =
+ info->entries[i].rid;
+ group[i].grpi3_attributes =
+ info->entries[i].acct_flags;
+ group[i].grpi3_next_index =
+ info->entries[i].idx;
+
+ if (!group[i].grpi3_name) {
+ return WERR_NOMEM;
+ }
+ }
+
+ *buffer = talloc_memdup(mem_ctx, group,
+ sizeof(struct NET_DISPLAY_GROUP) * info->count);
+ W_ERROR_HAVE_NO_MEMORY(*buffer);
+
+ *entries_read = info->count;
+
+ return WERR_OK;
+
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR convert_samr_dispinfo_to_NET_DISPLAY(TALLOC_CTX *mem_ctx,
+ union samr_DispInfo *info,
+ uint32_t level,
+ uint32_t *entries_read,
+ void **buffer)
+{
+ switch (level) {
+ case 1:
+ return convert_samr_dispinfo_to_NET_DISPLAY_USER(mem_ctx,
+ &info->info1,
+ entries_read,
+ buffer);
+ case 2:
+ return convert_samr_dispinfo_to_NET_DISPLAY_MACHINE(mem_ctx,
+ &info->info2,
+ entries_read,
+ buffer);
+ case 3:
+ return convert_samr_dispinfo_to_NET_DISPLAY_GROUP(mem_ctx,
+ &info->info3,
+ entries_read,
+ buffer);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetQueryDisplayInformation_r(struct libnetapi_ctx *ctx,
+ struct NetQueryDisplayInformation *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct policy_handle connect_handle;
+ struct dom_sid2 *domain_sid = NULL;
+ struct policy_handle domain_handle;
+ union samr_DispInfo info;
+
+ uint32_t total_size = 0;
+ uint32_t returned_size = 0;
+
+ NTSTATUS status = NT_STATUS_OK;
+ WERROR werr;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+
+ switch (r->in.level) {
+ case 1:
+ case 2:
+ case 3:
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 |
+ SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS |
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = rpccli_samr_QueryDisplayInfo2(pipe_cli,
+ ctx,
+ &domain_handle,
+ r->in.level,
+ r->in.idx,
+ r->in.entries_requested,
+ r->in.prefmaxlen,
+ &total_size,
+ &returned_size,
+ &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ werr = convert_samr_dispinfo_to_NET_DISPLAY(ctx, &info,
+ r->in.level,
+ r->out.entries_read,
+ r->out.buffer);
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ /* if last query */
+ if (NT_STATUS_IS_OK(status) ||
+ NT_STATUS_IS_ERR(status)) {
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+ }
+
+ return werr;
+
+}
+
+/****************************************************************
+****************************************************************/
+
+
+WERROR NetQueryDisplayInformation_l(struct libnetapi_ctx *ctx,
+ struct NetQueryDisplayInformation *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetQueryDisplayInformation);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserChangePassword_r(struct libnetapi_ctx *ctx,
+ struct NetUserChangePassword *r)
+{
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserChangePassword_l(struct libnetapi_ctx *ctx,
+ struct NetUserChangePassword *r)
+{
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserGetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetUserGetInfo *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+
+ struct policy_handle connect_handle, domain_handle, builtin_handle, user_handle;
+ struct lsa_String lsa_account_name;
+ struct dom_sid2 *domain_sid = NULL;
+ struct samr_Ids user_rids, name_types;
+ uint32_t num_entries = 0;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(builtin_handle);
+ ZERO_STRUCT(user_handle);
+
+ if (!r->out.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 10:
+ case 11:
+ case 20:
+ case 23:
+ break;
+ default:
+ werr = WERR_UNKNOWN_LEVEL;
+ goto done;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT |
+ SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS,
+ &connect_handle,
+ &builtin_handle);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_account_name, r->in.user_name);
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ 1,
+ &lsa_account_name,
+ &user_rids,
+ &name_types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = libnetapi_samr_lookup_user_map_USER_INFO(ctx, pipe_cli,
+ domain_sid,
+ &domain_handle,
+ &builtin_handle,
+ r->in.user_name,
+ user_rids.ids[0],
+ r->in.level,
+ r->out.buffer,
+ &num_entries);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&user_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &user_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserGetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetUserGetInfo *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetUserGetInfo);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserSetInfo_r(struct libnetapi_ctx *ctx,
+ struct NetUserSetInfo *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+
+ struct policy_handle connect_handle, domain_handle, builtin_handle, user_handle;
+ struct lsa_String lsa_account_name;
+ struct dom_sid2 *domain_sid = NULL;
+ struct samr_Ids user_rids, name_types;
+ uint32_t user_mask = 0;
+
+ struct USER_INFO_X uX;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+ ZERO_STRUCT(builtin_handle);
+ ZERO_STRUCT(user_handle);
+
+ if (!r->in.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ case 1003:
+ user_mask = SAMR_USER_ACCESS_SET_PASSWORD;
+ break;
+ case 1006:
+ case 1007:
+ case 1009:
+ case 1011:
+ case 1014:
+ case 1052:
+ case 1053:
+ user_mask = SAMR_USER_ACCESS_SET_ATTRIBUTES;
+ break;
+ case 1012:
+ case 1024:
+ user_mask = SAMR_USER_ACCESS_SET_LOC_COM;
+ case 1051:
+ user_mask = SAMR_USER_ACCESS_SET_ATTRIBUTES |
+ SAMR_USER_ACCESS_GET_GROUPS;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 21:
+ case 22:
+ case 1005:
+ case 1008:
+ case 1010:
+ case 1017:
+ case 1020:
+ werr = WERR_NOT_SUPPORTED;
+ goto done;
+ default:
+ werr = WERR_UNKNOWN_LEVEL;
+ goto done;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 |
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT |
+ SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS,
+ &connect_handle,
+ &builtin_handle);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_account_name, r->in.user_name);
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ 1,
+ &lsa_account_name,
+ &user_rids,
+ &name_types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_OpenUser(pipe_cli, ctx,
+ &domain_handle,
+ user_mask,
+ user_rids.ids[0],
+ &user_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = construct_USER_INFO_X(r->in.level, r->in.buffer, &uX);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = set_user_info_USER_INFO_X(ctx, pipe_cli,
+ &cli->user_session_key,
+ &user_handle,
+ &uX);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ werr = WERR_OK;
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&user_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &user_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserSetInfo_l(struct libnetapi_ctx *ctx,
+ struct NetUserSetInfo *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetUserSetInfo);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS query_USER_MODALS_INFO_rpc(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct policy_handle *domain_handle,
+ struct samr_DomInfo1 *info1,
+ struct samr_DomInfo3 *info3,
+ struct samr_DomInfo5 *info5,
+ struct samr_DomInfo6 *info6,
+ struct samr_DomInfo7 *info7,
+ struct samr_DomInfo12 *info12)
+{
+ NTSTATUS status;
+ union samr_DomainInfo *dom_info = NULL;
+
+ if (info1) {
+ status = rpccli_samr_QueryDomainInfo(pipe_cli, mem_ctx,
+ domain_handle,
+ 1,
+ &dom_info);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *info1 = dom_info->info1;
+ }
+
+ if (info3) {
+ status = rpccli_samr_QueryDomainInfo(pipe_cli, mem_ctx,
+ domain_handle,
+ 3,
+ &dom_info);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *info3 = dom_info->info3;
+ }
+
+ if (info5) {
+ status = rpccli_samr_QueryDomainInfo(pipe_cli, mem_ctx,
+ domain_handle,
+ 5,
+ &dom_info);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *info5 = dom_info->info5;
+ }
+
+ if (info6) {
+ status = rpccli_samr_QueryDomainInfo(pipe_cli, mem_ctx,
+ domain_handle,
+ 6,
+ &dom_info);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *info6 = dom_info->info6;
+ }
+
+ if (info7) {
+ status = rpccli_samr_QueryDomainInfo(pipe_cli, mem_ctx,
+ domain_handle,
+ 7,
+ &dom_info);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *info7 = dom_info->info7;
+ }
+
+ if (info12) {
+ status = rpccli_samr_QueryDomainInfo2(pipe_cli, mem_ctx,
+ domain_handle,
+ 12,
+ &dom_info);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *info12 = dom_info->info12;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS query_USER_MODALS_INFO_0(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct policy_handle *domain_handle,
+ struct USER_MODALS_INFO_0 *info0)
+{
+ NTSTATUS status;
+ struct samr_DomInfo1 dom_info1;
+ struct samr_DomInfo3 dom_info3;
+
+ ZERO_STRUCTP(info0);
+
+ status = query_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ &dom_info1,
+ &dom_info3,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ info0->usrmod0_min_passwd_len =
+ dom_info1.min_password_length;
+ info0->usrmod0_max_passwd_age =
+ nt_time_to_unix_abs((NTTIME *)&dom_info1.max_password_age);
+ info0->usrmod0_min_passwd_age =
+ nt_time_to_unix_abs((NTTIME *)&dom_info1.min_password_age);
+ info0->usrmod0_password_hist_len =
+ dom_info1.password_history_length;
+
+ info0->usrmod0_force_logoff =
+ nt_time_to_unix_abs(&dom_info3.force_logoff_time);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS query_USER_MODALS_INFO_1(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct policy_handle *domain_handle,
+ struct USER_MODALS_INFO_1 *info1)
+{
+ NTSTATUS status;
+ struct samr_DomInfo6 dom_info6;
+ struct samr_DomInfo7 dom_info7;
+
+ status = query_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ NULL,
+ NULL,
+ NULL,
+ &dom_info6,
+ &dom_info7,
+ NULL);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ info1->usrmod1_primary =
+ talloc_strdup(mem_ctx, dom_info6.primary.string);
+
+ info1->usrmod1_role = dom_info7.role;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS query_USER_MODALS_INFO_2(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct policy_handle *domain_handle,
+ struct dom_sid *domain_sid,
+ struct USER_MODALS_INFO_2 *info2)
+{
+ NTSTATUS status;
+ struct samr_DomInfo5 dom_info5;
+
+ status = query_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ NULL,
+ NULL,
+ &dom_info5,
+ NULL,
+ NULL,
+ NULL);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ info2->usrmod2_domain_name =
+ talloc_strdup(mem_ctx, dom_info5.domain_name.string);
+ info2->usrmod2_domain_id =
+ (struct domsid *)sid_dup_talloc(mem_ctx, domain_sid);
+
+ NT_STATUS_HAVE_NO_MEMORY(info2->usrmod2_domain_name);
+ NT_STATUS_HAVE_NO_MEMORY(info2->usrmod2_domain_id);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS query_USER_MODALS_INFO_3(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct policy_handle *domain_handle,
+ struct USER_MODALS_INFO_3 *info3)
+{
+ NTSTATUS status;
+ struct samr_DomInfo12 dom_info12;
+
+ status = query_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &dom_info12);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ info3->usrmod3_lockout_duration =
+ nt_time_to_unix_abs(&dom_info12.lockout_duration);
+ info3->usrmod3_lockout_observation_window =
+ nt_time_to_unix_abs(&dom_info12.lockout_window);
+ info3->usrmod3_lockout_threshold =
+ dom_info12.lockout_threshold;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS query_USER_MODALS_INFO_to_buffer(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ uint32_t level,
+ struct policy_handle *domain_handle,
+ struct dom_sid *domain_sid,
+ uint8_t **buffer)
+{
+ NTSTATUS status;
+
+ struct USER_MODALS_INFO_0 info0;
+ struct USER_MODALS_INFO_1 info1;
+ struct USER_MODALS_INFO_2 info2;
+ struct USER_MODALS_INFO_3 info3;
+
+ if (!buffer) {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ switch (level) {
+ case 0:
+ status = query_USER_MODALS_INFO_0(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ &info0);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info0,
+ sizeof(info0));
+ break;
+
+ case 1:
+ status = query_USER_MODALS_INFO_1(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ &info1);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info1,
+ sizeof(info1));
+ break;
+ case 2:
+ status = query_USER_MODALS_INFO_2(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ domain_sid,
+ &info2);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info2,
+ sizeof(info2));
+ break;
+ case 3:
+ status = query_USER_MODALS_INFO_3(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ &info3);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info3,
+ sizeof(info3));
+ break;
+ default:
+ break;
+ }
+
+ NT_STATUS_HAVE_NO_MEMORY(*buffer);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserModalsGet_r(struct libnetapi_ctx *ctx,
+ struct NetUserModalsGet *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+
+ struct policy_handle connect_handle, domain_handle;
+ struct dom_sid2 *domain_sid = NULL;
+ uint32_t access_mask = SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+
+ if (!r->out.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ access_mask |= SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 |
+ SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2;
+ break;
+ case 1:
+ case 2:
+ access_mask |= SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2;
+ break;
+ case 3:
+ access_mask |= SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1;
+ break;
+ default:
+ werr = WERR_UNKNOWN_LEVEL;
+ goto done;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ access_mask,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ /* 0: 1 + 3 */
+ /* 1: 6 + 7 */
+ /* 2: 5 */
+ /* 3: 12 (DomainInfo2) */
+
+ status = query_USER_MODALS_INFO_to_buffer(ctx,
+ pipe_cli,
+ r->in.level,
+ &domain_handle,
+ domain_sid,
+ r->out.buffer);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserModalsGet_l(struct libnetapi_ctx *ctx,
+ struct NetUserModalsGet *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetUserModalsGet);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS set_USER_MODALS_INFO_rpc(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct policy_handle *domain_handle,
+ struct samr_DomInfo1 *info1,
+ struct samr_DomInfo3 *info3,
+ struct samr_DomInfo12 *info12)
+{
+ NTSTATUS status;
+ union samr_DomainInfo dom_info;
+
+ if (info1) {
+
+ ZERO_STRUCT(dom_info);
+
+ dom_info.info1 = *info1;
+
+ status = rpccli_samr_SetDomainInfo(pipe_cli, mem_ctx,
+ domain_handle,
+ 1,
+ &dom_info);
+ NT_STATUS_NOT_OK_RETURN(status);
+ }
+
+ if (info3) {
+
+ ZERO_STRUCT(dom_info);
+
+ dom_info.info3 = *info3;
+
+ status = rpccli_samr_SetDomainInfo(pipe_cli, mem_ctx,
+ domain_handle,
+ 3,
+ &dom_info);
+
+ NT_STATUS_NOT_OK_RETURN(status);
+ }
+
+ if (info12) {
+
+ ZERO_STRUCT(dom_info);
+
+ dom_info.info12 = *info12;
+
+ status = rpccli_samr_SetDomainInfo(pipe_cli, mem_ctx,
+ domain_handle,
+ 12,
+ &dom_info);
+
+ NT_STATUS_NOT_OK_RETURN(status);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS set_USER_MODALS_INFO_0_buffer(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct policy_handle *domain_handle,
+ struct USER_MODALS_INFO_0 *info0)
+{
+ NTSTATUS status;
+ struct samr_DomInfo1 dom_info_1;
+ struct samr_DomInfo3 dom_info_3;
+
+ status = query_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ &dom_info_1,
+ &dom_info_3,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ dom_info_1.min_password_length =
+ info0->usrmod0_min_passwd_len;
+ dom_info_1.password_history_length =
+ info0->usrmod0_password_hist_len;
+
+ unix_to_nt_time_abs((NTTIME *)&dom_info_1.max_password_age,
+ info0->usrmod0_max_passwd_age);
+ unix_to_nt_time_abs((NTTIME *)&dom_info_1.min_password_age,
+ info0->usrmod0_min_passwd_age);
+
+ unix_to_nt_time_abs(&dom_info_3.force_logoff_time,
+ info0->usrmod0_force_logoff);
+
+ return set_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ &dom_info_1,
+ &dom_info_3,
+ NULL);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS set_USER_MODALS_INFO_3_buffer(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct policy_handle *domain_handle,
+ struct USER_MODALS_INFO_3 *info3)
+{
+ NTSTATUS status;
+ struct samr_DomInfo12 dom_info_12;
+
+ status = query_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &dom_info_12);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ unix_to_nt_time_abs((NTTIME *)&dom_info_12.lockout_duration,
+ info3->usrmod3_lockout_duration);
+ unix_to_nt_time_abs((NTTIME *)&dom_info_12.lockout_window,
+ info3->usrmod3_lockout_observation_window);
+ dom_info_12.lockout_threshold = info3->usrmod3_lockout_threshold;
+
+ return set_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ NULL,
+ NULL,
+ &dom_info_12);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS set_USER_MODALS_INFO_1001_buffer(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct policy_handle *domain_handle,
+ struct USER_MODALS_INFO_1001 *info1001)
+{
+ NTSTATUS status;
+ struct samr_DomInfo1 dom_info_1;
+
+ status = query_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ &dom_info_1,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ dom_info_1.min_password_length =
+ info1001->usrmod1001_min_passwd_len;
+
+ return set_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ &dom_info_1,
+ NULL,
+ NULL);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS set_USER_MODALS_INFO_1002_buffer(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct policy_handle *domain_handle,
+ struct USER_MODALS_INFO_1002 *info1002)
+{
+ NTSTATUS status;
+ struct samr_DomInfo1 dom_info_1;
+
+ status = query_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ &dom_info_1,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ unix_to_nt_time_abs((NTTIME *)&dom_info_1.max_password_age,
+ info1002->usrmod1002_max_passwd_age);
+
+ return set_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ &dom_info_1,
+ NULL,
+ NULL);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS set_USER_MODALS_INFO_1003_buffer(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct policy_handle *domain_handle,
+ struct USER_MODALS_INFO_1003 *info1003)
+{
+ NTSTATUS status;
+ struct samr_DomInfo1 dom_info_1;
+
+ status = query_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ &dom_info_1,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ unix_to_nt_time_abs((NTTIME *)&dom_info_1.min_password_age,
+ info1003->usrmod1003_min_passwd_age);
+
+ return set_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ &dom_info_1,
+ NULL,
+ NULL);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS set_USER_MODALS_INFO_1004_buffer(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct policy_handle *domain_handle,
+ struct USER_MODALS_INFO_1004 *info1004)
+{
+ NTSTATUS status;
+ struct samr_DomInfo3 dom_info_3;
+
+ status = query_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ NULL,
+ &dom_info_3,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ unix_to_nt_time_abs(&dom_info_3.force_logoff_time,
+ info1004->usrmod1004_force_logoff);
+
+ return set_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ NULL,
+ &dom_info_3,
+ NULL);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS set_USER_MODALS_INFO_1005_buffer(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ struct policy_handle *domain_handle,
+ struct USER_MODALS_INFO_1005 *info1005)
+{
+ NTSTATUS status;
+ struct samr_DomInfo1 dom_info_1;
+
+ status = query_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ &dom_info_1,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ dom_info_1.password_history_length =
+ info1005->usrmod1005_password_hist_len;
+
+ return set_USER_MODALS_INFO_rpc(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ &dom_info_1,
+ NULL,
+ NULL);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS set_USER_MODALS_INFO_buffer(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_cli,
+ uint32_t level,
+ struct policy_handle *domain_handle,
+ struct dom_sid *domain_sid,
+ uint8_t *buffer)
+{
+ struct USER_MODALS_INFO_0 *info0;
+ struct USER_MODALS_INFO_3 *info3;
+ struct USER_MODALS_INFO_1001 *info1001;
+ struct USER_MODALS_INFO_1002 *info1002;
+ struct USER_MODALS_INFO_1003 *info1003;
+ struct USER_MODALS_INFO_1004 *info1004;
+ struct USER_MODALS_INFO_1005 *info1005;
+
+ if (!buffer) {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ switch (level) {
+ case 0:
+ info0 = (struct USER_MODALS_INFO_0 *)buffer;
+ return set_USER_MODALS_INFO_0_buffer(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ info0);
+ case 3:
+ info3 = (struct USER_MODALS_INFO_3 *)buffer;
+ return set_USER_MODALS_INFO_3_buffer(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ info3);
+ case 1001:
+ info1001 = (struct USER_MODALS_INFO_1001 *)buffer;
+ return set_USER_MODALS_INFO_1001_buffer(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ info1001);
+ case 1002:
+ info1002 = (struct USER_MODALS_INFO_1002 *)buffer;
+ return set_USER_MODALS_INFO_1002_buffer(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ info1002);
+ case 1003:
+ info1003 = (struct USER_MODALS_INFO_1003 *)buffer;
+ return set_USER_MODALS_INFO_1003_buffer(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ info1003);
+ case 1004:
+ info1004 = (struct USER_MODALS_INFO_1004 *)buffer;
+ return set_USER_MODALS_INFO_1004_buffer(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ info1004);
+ case 1005:
+ info1005 = (struct USER_MODALS_INFO_1005 *)buffer;
+ return set_USER_MODALS_INFO_1005_buffer(mem_ctx,
+ pipe_cli,
+ domain_handle,
+ info1005);
+
+ default:
+ break;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserModalsSet_r(struct libnetapi_ctx *ctx,
+ struct NetUserModalsSet *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+
+ struct policy_handle connect_handle, domain_handle;
+ struct dom_sid2 *domain_sid = NULL;
+ uint32_t access_mask = SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+
+ if (!r->in.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ access_mask |= SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 |
+ SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 |
+ SAMR_DOMAIN_ACCESS_SET_INFO_1 |
+ SAMR_DOMAIN_ACCESS_SET_INFO_2;
+ break;
+ case 3:
+ case 1001:
+ case 1002:
+ case 1003:
+ case 1005:
+ access_mask |= SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 |
+ SAMR_DOMAIN_ACCESS_SET_INFO_1;
+ break;
+ case 1004:
+ access_mask |= SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 |
+ SAMR_DOMAIN_ACCESS_SET_INFO_2;
+ break;
+ case 1:
+ case 2:
+ case 1006:
+ case 1007:
+ werr = WERR_NOT_SUPPORTED;
+ break;
+ default:
+ werr = WERR_UNKNOWN_LEVEL;
+ goto done;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ access_mask,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ status = set_USER_MODALS_INFO_buffer(ctx,
+ pipe_cli,
+ r->in.level,
+ &domain_handle,
+ domain_sid,
+ r->in.buffer);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserModalsSet_l(struct libnetapi_ctx *ctx,
+ struct NetUserModalsSet *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetUserModalsSet);
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS add_GROUP_USERS_INFO_X_buffer(TALLOC_CTX *mem_ctx,
+ uint32_t level,
+ const char *group_name,
+ uint32_t attributes,
+ uint8_t **buffer,
+ uint32_t *num_entries)
+{
+ struct GROUP_USERS_INFO_0 u0;
+ struct GROUP_USERS_INFO_1 u1;
+
+ switch (level) {
+ case 0:
+ u0.grui0_name = talloc_strdup(mem_ctx, group_name);
+ NT_STATUS_HAVE_NO_MEMORY(u0.grui0_name);
+
+ ADD_TO_ARRAY(mem_ctx, struct GROUP_USERS_INFO_0, u0,
+ (struct GROUP_USERS_INFO_0 **)buffer, num_entries);
+ break;
+ case 1:
+ u1.grui1_name = talloc_strdup(mem_ctx, group_name);
+ NT_STATUS_HAVE_NO_MEMORY(u1.grui1_name);
+
+ u1.grui1_attributes = attributes;
+
+ ADD_TO_ARRAY(mem_ctx, struct GROUP_USERS_INFO_1, u1,
+ (struct GROUP_USERS_INFO_1 **)buffer, num_entries);
+ break;
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserGetGroups_r(struct libnetapi_ctx *ctx,
+ struct NetUserGetGroups *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct policy_handle connect_handle, domain_handle, user_handle;
+ struct lsa_String lsa_account_name;
+ struct dom_sid2 *domain_sid = NULL;
+ struct samr_Ids user_rids, name_types;
+ struct samr_RidWithAttributeArray *rid_array = NULL;
+ struct lsa_Strings names;
+ struct samr_Ids types;
+ uint32_t *rids = NULL;
+
+ int i;
+ uint32_t entries_read = 0;
+
+ NTSTATUS status = NT_STATUS_OK;
+ WERROR werr;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+
+ if (!r->out.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ *r->out.buffer = NULL;
+ *r->out.entries_read = 0;
+
+ switch (r->in.level) {
+ case 0:
+ case 1:
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_account_name, r->in.user_name);
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ 1,
+ &lsa_account_name,
+ &user_rids,
+ &name_types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_OpenUser(pipe_cli, ctx,
+ &domain_handle,
+ SAMR_USER_ACCESS_GET_GROUPS,
+ user_rids.ids[0],
+ &user_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_GetGroupsForUser(pipe_cli, ctx,
+ &user_handle,
+ &rid_array);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ rids = talloc_array(ctx, uint32_t, rid_array->count);
+ if (!rids) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ for (i=0; i < rid_array->count; i++) {
+ rids[i] = rid_array->rids[i].rid;
+ }
+
+ status = rpccli_samr_LookupRids(pipe_cli, ctx,
+ &domain_handle,
+ rid_array->count,
+ rids,
+ &names,
+ &types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ for (i=0; i < rid_array->count; i++) {
+ status = add_GROUP_USERS_INFO_X_buffer(ctx,
+ r->in.level,
+ names.names[i].string,
+ rid_array->rids[i].attributes,
+ r->out.buffer,
+ &entries_read);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+
+ if (r->out.entries_read) {
+ *r->out.entries_read = entries_read;
+ }
+ if (r->out.total_entries) {
+ *r->out.total_entries = entries_read;
+ }
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserGetGroups_l(struct libnetapi_ctx *ctx,
+ struct NetUserGetGroups *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetUserGetGroups);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserSetGroups_r(struct libnetapi_ctx *ctx,
+ struct NetUserSetGroups *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct policy_handle connect_handle, domain_handle, user_handle, group_handle;
+ struct lsa_String lsa_account_name;
+ struct dom_sid2 *domain_sid = NULL;
+ struct samr_Ids user_rids, name_types;
+ struct samr_Ids group_rids;
+ struct samr_RidWithAttributeArray *rid_array = NULL;
+ struct lsa_String *lsa_names = NULL;
+
+ uint32_t *add_rids = NULL;
+ uint32_t *del_rids = NULL;
+ size_t num_add_rids = 0;
+ size_t num_del_rids = 0;
+
+ uint32_t *member_rids = NULL;
+ size_t num_member_rids = 0;
+
+ struct GROUP_USERS_INFO_0 *i0 = NULL;
+ struct GROUP_USERS_INFO_1 *i1 = NULL;
+
+ int i, k;
+
+ NTSTATUS status = NT_STATUS_OK;
+ WERROR werr;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+
+ if (!r->in.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ case 1:
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_account_name, r->in.user_name);
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ 1,
+ &lsa_account_name,
+ &user_rids,
+ &name_types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_OpenUser(pipe_cli, ctx,
+ &domain_handle,
+ SAMR_USER_ACCESS_GET_GROUPS,
+ user_rids.ids[0],
+ &user_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ i0 = (struct GROUP_USERS_INFO_0 *)r->in.buffer;
+ break;
+ case 1:
+ i1 = (struct GROUP_USERS_INFO_1 *)r->in.buffer;
+ break;
+ }
+
+ lsa_names = talloc_array(ctx, struct lsa_String, r->in.num_entries);
+ if (!lsa_names) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ for (i=0; i < r->in.num_entries; i++) {
+
+ switch (r->in.level) {
+ case 0:
+ init_lsa_String(&lsa_names[i], i0->grui0_name);
+ i0++;
+ break;
+ case 1:
+ init_lsa_String(&lsa_names[i], i1->grui1_name);
+ i1++;
+ break;
+ }
+ }
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ r->in.num_entries,
+ lsa_names,
+ &group_rids,
+ &name_types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ member_rids = group_rids.ids;
+ num_member_rids = group_rids.count;
+
+ status = rpccli_samr_GetGroupsForUser(pipe_cli, ctx,
+ &user_handle,
+ &rid_array);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ /* add list */
+
+ for (i=0; i < r->in.num_entries; i++) {
+ bool already_member = false;
+ for (k=0; k < rid_array->count; k++) {
+ if (member_rids[i] == rid_array->rids[k].rid) {
+ already_member = true;
+ break;
+ }
+ }
+ if (!already_member) {
+ if (!add_rid_to_array_unique(ctx,
+ member_rids[i],
+ &add_rids, &num_add_rids)) {
+ werr = WERR_GENERAL_FAILURE;
+ goto done;
+ }
+ }
+ }
+
+ /* del list */
+
+ for (k=0; k < rid_array->count; k++) {
+ bool keep_member = false;
+ for (i=0; i < r->in.num_entries; i++) {
+ if (member_rids[i] == rid_array->rids[k].rid) {
+ keep_member = true;
+ break;
+ }
+ }
+ if (!keep_member) {
+ if (!add_rid_to_array_unique(ctx,
+ rid_array->rids[k].rid,
+ &del_rids, &num_del_rids)) {
+ werr = WERR_GENERAL_FAILURE;
+ goto done;
+ }
+ }
+ }
+
+ /* add list */
+
+ for (i=0; i < num_add_rids; i++) {
+ status = rpccli_samr_OpenGroup(pipe_cli, ctx,
+ &domain_handle,
+ SAMR_GROUP_ACCESS_ADD_MEMBER,
+ add_rids[i],
+ &group_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_AddGroupMember(pipe_cli, ctx,
+ &group_handle,
+ user_rids.ids[0],
+ 7 /* ? */);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ if (is_valid_policy_hnd(&group_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &group_handle);
+ }
+ }
+
+ /* del list */
+
+ for (i=0; i < num_del_rids; i++) {
+ status = rpccli_samr_OpenGroup(pipe_cli, ctx,
+ &domain_handle,
+ SAMR_GROUP_ACCESS_REMOVE_MEMBER,
+ del_rids[i],
+ &group_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_DeleteGroupMember(pipe_cli, ctx,
+ &group_handle,
+ user_rids.ids[0]);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ if (is_valid_policy_hnd(&group_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &group_handle);
+ }
+ }
+
+ werr = WERR_OK;
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (is_valid_policy_hnd(&group_handle)) {
+ rpccli_samr_Close(pipe_cli, ctx, &group_handle);
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserSetGroups_l(struct libnetapi_ctx *ctx,
+ struct NetUserSetGroups *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetUserSetGroups);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS add_LOCALGROUP_USERS_INFO_X_buffer(TALLOC_CTX *mem_ctx,
+ uint32_t level,
+ const char *group_name,
+ uint8_t **buffer,
+ uint32_t *num_entries)
+{
+ struct LOCALGROUP_USERS_INFO_0 u0;
+
+ switch (level) {
+ case 0:
+ u0.lgrui0_name = talloc_strdup(mem_ctx, group_name);
+ NT_STATUS_HAVE_NO_MEMORY(u0.lgrui0_name);
+
+ ADD_TO_ARRAY(mem_ctx, struct LOCALGROUP_USERS_INFO_0, u0,
+ (struct LOCALGROUP_USERS_INFO_0 **)buffer, num_entries);
+ break;
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserGetLocalGroups_r(struct libnetapi_ctx *ctx,
+ struct NetUserGetLocalGroups *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct policy_handle connect_handle, domain_handle, user_handle,
+ builtin_handle;
+ struct lsa_String lsa_account_name;
+ struct dom_sid2 *domain_sid = NULL;
+ struct samr_Ids user_rids, name_types;
+ struct samr_RidWithAttributeArray *rid_array = NULL;
+ struct lsa_Strings names;
+ struct samr_Ids types;
+ uint32_t *rids = NULL;
+ size_t num_rids = 0;
+ struct dom_sid user_sid;
+ struct lsa_SidArray sid_array;
+ struct samr_Ids domain_rids;
+ struct samr_Ids builtin_rids;
+
+ int i;
+ uint32_t entries_read = 0;
+
+ NTSTATUS status = NT_STATUS_OK;
+ WERROR werr;
+
+ ZERO_STRUCT(connect_handle);
+ ZERO_STRUCT(domain_handle);
+
+ if (!r->out.buffer) {
+ return WERR_INVALID_PARAM;
+ }
+
+ *r->out.buffer = NULL;
+ *r->out.entries_read = 0;
+
+ switch (r->in.level) {
+ case 0:
+ case 1:
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ werr = libnetapi_open_pipe(ctx, r->in.server_name,
+ &ndr_table_samr.syntax_id,
+ &cli,
+ &pipe_cli);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT |
+ SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS,
+ &connect_handle,
+ &domain_handle,
+ &domain_sid);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
+ SAMR_ACCESS_ENUM_DOMAINS |
+ SAMR_ACCESS_OPEN_DOMAIN,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT |
+ SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS,
+ &connect_handle,
+ &builtin_handle);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_account_name, r->in.user_name);
+
+ status = rpccli_samr_LookupNames(pipe_cli, ctx,
+ &domain_handle,
+ 1,
+ &lsa_account_name,
+ &user_rids,
+ &name_types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_OpenUser(pipe_cli, ctx,
+ &domain_handle,
+ SAMR_USER_ACCESS_GET_GROUPS,
+ user_rids.ids[0],
+ &user_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_samr_GetGroupsForUser(pipe_cli, ctx,
+ &user_handle,
+ &rid_array);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ if (!sid_compose(&user_sid, domain_sid, user_rids.ids[0])) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ sid_array.num_sids = rid_array->count + 1;
+ sid_array.sids = TALLOC_ARRAY(ctx, struct lsa_SidPtr, sid_array.num_sids);
+ if (!sid_array.sids) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ sid_array.sids[0].sid = sid_dup_talloc(ctx, &user_sid);
+ if (!sid_array.sids[0].sid) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ for (i=0; i < rid_array->count; i++) {
+ struct dom_sid sid;
+
+ if (!sid_compose(&sid, domain_sid, rid_array->rids[i].rid)) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ sid_array.sids[i+1].sid = sid_dup_talloc(ctx, &sid);
+ if (!sid_array.sids[i+1].sid) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+ }
+
+ status = rpccli_samr_GetAliasMembership(pipe_cli, ctx,
+ &domain_handle,
+ &sid_array,
+ &domain_rids);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ for (i=0; i < domain_rids.count; i++) {
+ if (!add_rid_to_array_unique(ctx, domain_rids.ids[i],
+ &rids, &num_rids)) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+ }
+
+ status = rpccli_samr_GetAliasMembership(pipe_cli, ctx,
+ &builtin_handle,
+ &sid_array,
+ &builtin_rids);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ for (i=0; i < builtin_rids.count; i++) {
+ if (!add_rid_to_array_unique(ctx, builtin_rids.ids[i],
+ &rids, &num_rids)) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+ }
+
+ status = rpccli_samr_LookupRids(pipe_cli, ctx,
+ &builtin_handle,
+ num_rids,
+ rids,
+ &names,
+ &types);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ for (i=0; i < names.count; i++) {
+ status = add_LOCALGROUP_USERS_INFO_X_buffer(ctx,
+ r->in.level,
+ names.names[i].string,
+ r->out.buffer,
+ &entries_read);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+ }
+
+ if (r->out.entries_read) {
+ *r->out.entries_read = entries_read;
+ }
+ if (r->out.total_entries) {
+ *r->out.total_entries = entries_read;
+ }
+
+ done:
+ if (!cli) {
+ return werr;
+ }
+
+ if (ctx->disable_policy_handle_cache) {
+ libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+ libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserGetLocalGroups_l(struct libnetapi_ctx *ctx,
+ struct NetUserGetLocalGroups *r)
+{
+ LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetUserGetLocalGroups);
+}
diff --git a/source3/lib/nss_wrapper/config.m4 b/source3/lib/nss_wrapper/config.m4
new file mode 100644
index 0000000000..58e94f9830
--- /dev/null
+++ b/source3/lib/nss_wrapper/config.m4
@@ -0,0 +1,19 @@
+AC_ARG_ENABLE(nss-wrapper,
+[ --enable-nss-wrapper Turn on nss wrapper library (default=no)])
+
+HAVE_NSS_WRAPPER=no
+
+if eval "test x$developer = xyes"; then
+ enable_nss_wrapper=yes
+fi
+
+if eval "test x$enable_nss_wrapper = xyes"; then
+ AC_DEFINE(NSS_WRAPPER,1,[Use nss wrapper library])
+ HAVE_NSS_WRAPPER=yes
+
+ # this is only used for samba3
+ NSS_WRAPPER_OBJS="lib/nss_wrapper/nss_wrapper.o"
+fi
+
+AC_SUBST(HAVE_NSS_WRAPPER)
+AC_SUBST(NSS_WRAPPER_OBJS)
diff --git a/source3/lib/nss_wrapper/config.mk b/source3/lib/nss_wrapper/config.mk
new file mode 100644
index 0000000000..9751d2bf73
--- /dev/null
+++ b/source3/lib/nss_wrapper/config.mk
@@ -0,0 +1,10 @@
+##############################
+# Start SUBSYSTEM NSS_WRAPPER
+[LIBRARY::NSS_WRAPPER]
+VERSION = 0.0.1
+SO_VERSION = 0
+DESCRIPTION = Wrapper library for testing nss calls without being root
+PUBLIC_HEADERS = nss_wrapper.h
+OBJ_FILES = nss_wrapper.o
+# End SUBSYSTEM NSS_WRAPPER
+##############################
diff --git a/source3/lib/nss_wrapper/nss_wrapper.c b/source3/lib/nss_wrapper/nss_wrapper.c
new file mode 100644
index 0000000000..5d443facd3
--- /dev/null
+++ b/source3/lib/nss_wrapper/nss_wrapper.c
@@ -0,0 +1,1130 @@
+/*
+ * Copyright (C) Stefan Metzmacher 2007 <metze@samba.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef _SAMBA_BUILD_
+
+#define NSS_WRAPPER_NOT_REPLACE
+#include "lib/replace/replace.h"
+#include "system/passwd.h"
+#include "system/filesys.h"
+
+#else /* _SAMBA_BUILD_ */
+
+#error nss_wrapper_only_supported_in_samba_yet
+
+#endif
+
+#ifndef _PUBLIC_
+#define _PUBLIC_
+#endif
+
+/* not all systems have _r functions... */
+#ifndef HAVE_GETPWNAM_R
+#define getpwnam_r(name, pwdst, buf, buflen, pwdstp) ENOSYS
+#endif
+#ifndef HAVE_GETPWUID_R
+#define getpwuid_r(uid, pwdst, buf, buflen, pwdstp) ENOSYS
+#endif
+#ifndef HAVE_GETPWENT_R
+#define getpwent_r(pwdst, buf, buflen, pwdstp) ENOSYS
+#endif
+#ifndef HAVE_GETGRNAM_R
+#define getgrnam_r(name, grdst, buf, buflen, grdstp) ENOSYS
+#endif
+#ifndef HAVE_GETGRUID_R
+#define getgrgid_r(uid, grdst, buf, buflen, grdstp) ENOSYS
+#endif
+#ifndef HAVE_GETGRENT_R
+#define getgrent_r(grdst, buf, buflen, grdstp) ENOSYS
+#endif
+
+/* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support
+ * for now */
+#define REWRITE_CALLS
+
+#ifdef REWRITE_CALLS
+
+#define real_getpwnam getpwnam
+#define real_getpwnam_r getpwnam_r
+#define real_getpwuid getpwuid
+#define real_getpwuid_r getpwuid_r
+
+#define real_setpwent setpwent
+#define real_getpwent getpwent
+#define real_getpwent_r getpwent_r
+#define real_endpwent endpwent
+
+/*
+#define real_getgrlst getgrlst
+#define real_getgrlst_r getgrlst_r
+#define real_initgroups_dyn initgroups_dyn
+*/
+#define real_initgroups initgroups
+
+#define real_getgrnam getgrnam
+#define real_getgrnam_r getgrnam_r
+#define real_getgrgid getgrgid
+#define real_getgrgid_r getgrgid_r
+
+#define real_setgrent setgrent
+#define real_getgrent getgrent
+#define real_getgrent_r getgrent_r
+#define real_endgrent endgrent
+
+#endif
+
+#if 0
+# ifdef DEBUG
+# define NWRAP_ERROR(args) DEBUG(0, args)
+# else
+# define NWRAP_ERROR(args) printf args
+# endif
+#else
+#define NWRAP_ERROR(args)
+#endif
+
+#if 0
+# ifdef DEBUG
+# define NWRAP_DEBUG(args) DEBUG(0, args)
+# else
+# define NWRAP_DEBUG(args) printf args
+# endif
+#else
+#define NWRAP_DEBUG(args)
+#endif
+
+#if 0
+# ifdef DEBUG
+# define NWRAP_VERBOSE(args) DEBUG(0, args)
+# else
+# define NWRAP_VERBOSE(args) printf args
+# endif
+#else
+#define NWRAP_VERBOSE(args)
+#endif
+
+struct nwrap_cache {
+ const char *path;
+ int fd;
+ struct stat st;
+ uint8_t *buf;
+ void *private_data;
+ bool (*parse_line)(struct nwrap_cache *, char *line);
+ void (*unload)(struct nwrap_cache *);
+};
+
+struct nwrap_pw {
+ struct nwrap_cache *cache;
+
+ struct passwd *list;
+ int num;
+ int idx;
+};
+
+struct nwrap_cache __nwrap_cache_pw;
+struct nwrap_pw nwrap_pw_global;
+
+static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line);
+static void nwrap_pw_unload(struct nwrap_cache *nwrap);
+
+struct nwrap_gr {
+ struct nwrap_cache *cache;
+
+ struct group *list;
+ int num;
+ int idx;
+};
+
+struct nwrap_cache __nwrap_cache_gr;
+struct nwrap_gr nwrap_gr_global;
+
+static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line);
+static void nwrap_gr_unload(struct nwrap_cache *nwrap);
+
+static void nwrap_init(void)
+{
+ static bool initialized;
+
+ if (initialized) return;
+ initialized = true;
+
+ nwrap_pw_global.cache = &__nwrap_cache_pw;
+
+ nwrap_pw_global.cache->path = getenv("NSS_WRAPPER_PASSWD");
+ nwrap_pw_global.cache->fd = -1;
+ nwrap_pw_global.cache->private_data = &nwrap_pw_global;
+ nwrap_pw_global.cache->parse_line = nwrap_pw_parse_line;
+ nwrap_pw_global.cache->unload = nwrap_pw_unload;
+
+ nwrap_gr_global.cache = &__nwrap_cache_gr;
+
+ nwrap_gr_global.cache->path = getenv("NSS_WRAPPER_GROUP");
+ nwrap_gr_global.cache->fd = -1;
+ nwrap_gr_global.cache->private_data = &nwrap_gr_global;
+ nwrap_gr_global.cache->parse_line = nwrap_gr_parse_line;
+ nwrap_gr_global.cache->unload = nwrap_gr_unload;
+}
+
+static bool nwrap_enabled(void)
+{
+ nwrap_init();
+
+ if (!nwrap_pw_global.cache->path) {
+ return false;
+ }
+ if (nwrap_pw_global.cache->path[0] == '\0') {
+ return false;
+ }
+ if (!nwrap_gr_global.cache->path) {
+ return false;
+ }
+ if (nwrap_gr_global.cache->path[0] == '\0') {
+ return false;
+ }
+
+ return true;
+}
+
+static bool nwrap_parse_file(struct nwrap_cache *nwrap)
+{
+ int ret;
+ uint8_t *buf = NULL;
+ char *nline;
+
+ if (nwrap->st.st_size == 0) {
+ NWRAP_DEBUG(("%s: size == 0\n",
+ __location__));
+ goto done;
+ }
+
+ if (nwrap->st.st_size > INT32_MAX) {
+ NWRAP_ERROR(("%s: size[%u] larger than INT32_MAX\n",
+ __location__, (unsigned)nwrap->st.st_size));
+ goto failed;
+ }
+
+ ret = lseek(nwrap->fd, 0, SEEK_SET);
+ if (ret != 0) {
+ NWRAP_ERROR(("%s: lseek - %d\n",__location__,ret));
+ goto failed;
+ }
+
+ buf = (uint8_t *)malloc(nwrap->st.st_size + 1);
+ if (!buf) {
+ NWRAP_ERROR(("%s: malloc failed\n",__location__));
+ goto failed;
+ }
+
+ ret = read(nwrap->fd, buf, nwrap->st.st_size);
+ if (ret != nwrap->st.st_size) {
+ NWRAP_ERROR(("%s: read(%u) gave %d\n",
+ __location__, (unsigned)nwrap->st.st_size, ret));
+ goto failed;
+ }
+
+ buf[nwrap->st.st_size] = '\0';
+
+ nline = (char *)buf;
+ while (nline && nline[0]) {
+ char *line;
+ char *e;
+ bool ok;
+
+ line = nline;
+ nline = NULL;
+
+ e = strchr(line, '\n');
+ if (e) {
+ e[0] = '\0';
+ e++;
+ if (e[0] == '\r') {
+ e[0] = '\0';
+ e++;
+ }
+ nline = e;
+ }
+
+ NWRAP_VERBOSE(("%s:'%s'\n",__location__, line));
+
+ if (strlen(line) == 0) {
+ continue;
+ }
+
+ ok = nwrap->parse_line(nwrap, line);
+ if (!ok) {
+ goto failed;
+ }
+ }
+
+done:
+ nwrap->buf = buf;
+ return true;
+
+failed:
+ if (buf) free(buf);
+ return false;
+}
+
+static void nwrap_cache_unload(struct nwrap_cache *nwrap)
+{
+ nwrap->unload(nwrap);
+
+ if (nwrap->buf) free(nwrap->buf);
+
+ nwrap->buf = NULL;
+}
+
+static void nwrap_cache_reload(struct nwrap_cache *nwrap)
+{
+ struct stat st;
+ int ret;
+ bool ok;
+ bool retried = false;
+
+reopen:
+ if (nwrap->fd < 0) {
+ nwrap->fd = open(nwrap->path, O_RDONLY);
+ if (nwrap->fd < 0) {
+ NWRAP_ERROR(("%s: unable to open '%s' readonly %d:%s\n",
+ __location__,
+ nwrap->path, nwrap->fd,
+ strerror(errno)));
+ return;
+ }
+ NWRAP_VERBOSE(("%s: open '%s'\n", __location__, nwrap->path));
+ }
+
+ ret = fstat(nwrap->fd, &st);
+ if (ret != 0) {
+ NWRAP_ERROR(("%s: fstat(%s) - %d:%s\n",
+ __location__,
+ nwrap->path,
+ ret, strerror(errno)));
+ return;
+ }
+
+ if (retried == false && st.st_nlink == 0) {
+ /* maybe someone has replaced the file... */
+ NWRAP_DEBUG(("%s: st_nlink == 0, reopen %s\n",
+ __location__, nwrap->path));
+ retried = true;
+ memset(&nwrap->st, 0, sizeof(nwrap->st));
+ close(nwrap->fd);
+ nwrap->fd = -1;
+ goto reopen;
+ }
+
+ if (st.st_mtime == nwrap->st.st_mtime) {
+ NWRAP_VERBOSE(("%s: st_mtime[%u] hasn't changed, skip reload\n",
+ __location__, (unsigned)st.st_mtime));
+ return;
+ }
+ NWRAP_DEBUG(("%s: st_mtime has changed [%u] => [%u], start reload\n",
+ __location__, (unsigned)st.st_mtime,
+ (unsigned)nwrap->st.st_mtime));
+
+ nwrap->st = st;
+
+ nwrap_cache_unload(nwrap);
+
+ ok = nwrap_parse_file(nwrap);
+ if (!ok) {
+ NWRAP_ERROR(("%s: failed to reload %s\n",
+ __location__, nwrap->path));
+ nwrap_cache_unload(nwrap);
+ }
+ NWRAP_DEBUG(("%s: reloaded %s\n",
+ __location__, nwrap->path));
+}
+
+/*
+ * the caller has to call nwrap_unload() on failure
+ */
+static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line)
+{
+ struct nwrap_pw *nwrap_pw;
+ char *c;
+ char *p;
+ char *e;
+ struct passwd *pw;
+ size_t list_size;
+
+ nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
+
+ list_size = sizeof(*nwrap_pw->list) * (nwrap_pw->num+1);
+ pw = (struct passwd *)realloc(nwrap_pw->list, list_size);
+ if (!pw) {
+ NWRAP_ERROR(("%s:realloc(%u) failed\n",
+ __location__, list_size));
+ return false;
+ }
+ nwrap_pw->list = pw;
+
+ pw = &nwrap_pw->list[nwrap_pw->num];
+
+ c = line;
+
+ /* name */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
+ __location__, line, c));
+ return false;
+ }
+ *p = '\0';
+ p++;
+ pw->pw_name = c;
+ c = p;
+
+ NWRAP_VERBOSE(("name[%s]\n", pw->pw_name));
+
+ /* password */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
+ __location__, line, c));
+ return false;
+ }
+ *p = '\0';
+ p++;
+ pw->pw_passwd = c;
+ c = p;
+
+ NWRAP_VERBOSE(("password[%s]\n", pw->pw_passwd));
+
+ /* uid */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
+ __location__, line, c));
+ return false;
+ }
+ *p = '\0';
+ p++;
+ e = NULL;
+ pw->pw_uid = (uid_t)strtoul(c, &e, 10);
+ if (c == e) {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
+ __location__, line, c, strerror(errno)));
+ return false;
+ }
+ if (e == NULL) {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
+ __location__, line, c, strerror(errno)));
+ return false;
+ }
+ if (e[0] != '\0') {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
+ __location__, line, c, strerror(errno)));
+ return false;
+ }
+ c = p;
+
+ NWRAP_VERBOSE(("uid[%u]\n", pw->pw_uid));
+
+ /* gid */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
+ __location__, line, c));
+ return false;
+ }
+ *p = '\0';
+ p++;
+ e = NULL;
+ pw->pw_gid = (gid_t)strtoul(c, &e, 10);
+ if (c == e) {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
+ __location__, line, c, strerror(errno)));
+ return false;
+ }
+ if (e == NULL) {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
+ __location__, line, c, strerror(errno)));
+ return false;
+ }
+ if (e[0] != '\0') {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
+ __location__, line, c, strerror(errno)));
+ return false;
+ }
+ c = p;
+
+ NWRAP_VERBOSE(("gid[%u]\n", pw->pw_gid));
+
+ /* gecos */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
+ __location__, line, c));
+ return false;
+ }
+ *p = '\0';
+ p++;
+ pw->pw_gecos = c;
+ c = p;
+
+ NWRAP_VERBOSE(("gecos[%s]\n", pw->pw_gecos));
+
+ /* dir */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_ERROR(("%s:'%s'\n",__location__,c));
+ return false;
+ }
+ *p = '\0';
+ p++;
+ pw->pw_dir = c;
+ c = p;
+
+ NWRAP_VERBOSE(("dir[%s]\n", pw->pw_dir));
+
+ /* shell */
+ pw->pw_shell = c;
+ NWRAP_VERBOSE(("shell[%s]\n", pw->pw_shell));
+
+ NWRAP_DEBUG(("add user[%s:%s:%u:%u:%s:%s:%s]\n",
+ pw->pw_name, pw->pw_passwd,
+ pw->pw_uid, pw->pw_gid,
+ pw->pw_gecos, pw->pw_dir, pw->pw_shell));
+
+ nwrap_pw->num++;
+ return true;
+}
+
+static void nwrap_pw_unload(struct nwrap_cache *nwrap)
+{
+ struct nwrap_pw *nwrap_pw;
+ nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
+
+ if (nwrap_pw->list) free(nwrap_pw->list);
+
+ nwrap_pw->list = NULL;
+ nwrap_pw->num = 0;
+ nwrap_pw->idx = 0;
+}
+
+static int nwrap_pw_copy_r(const struct passwd *src, struct passwd *dst,
+ char *buf, size_t buflen, struct passwd **dstp)
+{
+ char *first;
+ char *last;
+ off_t ofs;
+
+ first = src->pw_name;
+
+ last = src->pw_shell;
+ while (*last) last++;
+
+ ofs = PTR_DIFF(last + 1, first);
+
+ if (ofs > buflen) {
+ return ERANGE;
+ }
+
+ memcpy(buf, first, ofs);
+
+ ofs = PTR_DIFF(src->pw_name, first);
+ dst->pw_name = buf + ofs;
+ ofs = PTR_DIFF(src->pw_passwd, first);
+ dst->pw_passwd = buf + ofs;
+ dst->pw_uid = src->pw_uid;
+ dst->pw_gid = src->pw_gid;
+ ofs = PTR_DIFF(src->pw_gecos, first);
+ dst->pw_gecos = buf + ofs;
+ ofs = PTR_DIFF(src->pw_dir, first);
+ dst->pw_dir = buf + ofs;
+ ofs = PTR_DIFF(src->pw_shell, first);
+ dst->pw_shell = buf + ofs;
+
+ if (dstp) {
+ *dstp = dst;
+ }
+
+ return 0;
+}
+
+/*
+ * the caller has to call nwrap_unload() on failure
+ */
+static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
+{
+ struct nwrap_gr *nwrap_gr;
+ char *c;
+ char *p;
+ char *e;
+ struct group *gr;
+ size_t list_size;
+ unsigned nummem;
+
+ nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
+
+ list_size = sizeof(*nwrap_gr->list) * (nwrap_gr->num+1);
+ gr = (struct group *)realloc(nwrap_gr->list, list_size);
+ if (!gr) {
+ NWRAP_ERROR(("%s:realloc failed\n",__location__));
+ return false;
+ }
+ nwrap_gr->list = gr;
+
+ gr = &nwrap_gr->list[nwrap_gr->num];
+
+ c = line;
+
+ /* name */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
+ __location__, line, c));
+ return false;
+ }
+ *p = '\0';
+ p++;
+ gr->gr_name = c;
+ c = p;
+
+ NWRAP_VERBOSE(("name[%s]\n", gr->gr_name));
+
+ /* password */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
+ __location__, line, c));
+ return false;
+ }
+ *p = '\0';
+ p++;
+ gr->gr_passwd = c;
+ c = p;
+
+ NWRAP_VERBOSE(("password[%s]\n", gr->gr_passwd));
+
+ /* gid */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
+ __location__, line, c));
+ return false;
+ }
+ *p = '\0';
+ p++;
+ e = NULL;
+ gr->gr_gid = (gid_t)strtoul(c, &e, 10);
+ if (c == e) {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
+ __location__, line, c, strerror(errno)));
+ return false;
+ }
+ if (e == NULL) {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
+ __location__, line, c, strerror(errno)));
+ return false;
+ }
+ if (e[0] != '\0') {
+ NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
+ __location__, line, c, strerror(errno)));
+ return false;
+ }
+ c = p;
+
+ NWRAP_VERBOSE(("gid[%u]\n", gr->gr_gid));
+
+ /* members */
+ gr->gr_mem = (char **)malloc(sizeof(char *));
+ if (!gr->gr_mem) {
+ NWRAP_ERROR(("%s:calloc failed\n",__location__));
+ return false;
+ }
+ gr->gr_mem[0] = NULL;
+
+ for(nummem=0; p; nummem++) {
+ char **m;
+ size_t m_size;
+ c = p;
+ p = strchr(c, ',');
+ if (p) {
+ *p = '\0';
+ p++;
+ }
+
+ if (strlen(c) == 0) {
+ break;
+ }
+
+ m_size = sizeof(char *) * (nummem+2);
+ m = (char **)realloc(gr->gr_mem, m_size);
+ if (!m) {
+ NWRAP_ERROR(("%s:realloc(%u) failed\n",
+ __location__, m_size));
+ return false;
+ }
+ gr->gr_mem = m;
+ gr->gr_mem[nummem] = c;
+ gr->gr_mem[nummem+1] = NULL;
+
+ NWRAP_VERBOSE(("member[%u]: '%s'\n", nummem, gr->gr_mem[nummem]));
+ }
+
+ NWRAP_DEBUG(("add group[%s:%s:%u:] with %u members\n",
+ gr->gr_name, gr->gr_passwd, gr->gr_gid, nummem));
+
+ nwrap_gr->num++;
+ return true;
+}
+
+static void nwrap_gr_unload(struct nwrap_cache *nwrap)
+{
+ int i;
+ struct nwrap_gr *nwrap_gr;
+ nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
+
+ if (nwrap_gr->list) {
+ for (i=0; i < nwrap_gr->num; i++) {
+ if (nwrap_gr->list[i].gr_mem) {
+ free(nwrap_gr->list[i].gr_mem);
+ }
+ }
+ free(nwrap_gr->list);
+ }
+
+ nwrap_gr->list = NULL;
+ nwrap_gr->num = 0;
+ nwrap_gr->idx = 0;
+}
+
+static int nwrap_gr_copy_r(const struct group *src, struct group *dst,
+ char *buf, size_t buflen, struct group **dstp)
+{
+ char *first;
+ char **lastm;
+ char *last;
+ off_t ofsb;
+ off_t ofsm;
+ off_t ofs;
+ unsigned i;
+
+ first = src->gr_name;
+
+ lastm = src->gr_mem;
+ while (*lastm) lastm++;
+
+ last = *lastm;
+ while (*last) last++;
+
+ ofsb = PTR_DIFF(last + 1, first);
+ ofsm = PTR_DIFF(lastm + 1, src->gr_mem);
+
+ if ((ofsb + ofsm) > buflen) {
+ return ERANGE;
+ }
+
+ memcpy(buf, first, ofsb);
+ memcpy(buf + ofsb, src->gr_mem, ofsm);
+
+ ofs = PTR_DIFF(src->gr_name, first);
+ dst->gr_name = buf + ofs;
+ ofs = PTR_DIFF(src->gr_passwd, first);
+ dst->gr_passwd = buf + ofs;
+ dst->gr_gid = src->gr_gid;
+
+ dst->gr_mem = (char **)(buf + ofsb);
+ for (i=0; src->gr_mem[i]; i++) {
+ ofs = PTR_DIFF(src->gr_mem[i], first);
+ dst->gr_mem[i] = buf + ofs;
+ }
+
+ if (dstp) {
+ *dstp = dst;
+ }
+
+ return 0;
+}
+
+/* user functions */
+_PUBLIC_ struct passwd *nwrap_getpwnam(const char *name)
+{
+ int i;
+
+ if (!nwrap_enabled()) {
+ return real_getpwnam(name);
+ }
+
+ nwrap_cache_reload(nwrap_pw_global.cache);
+
+ for (i=0; i<nwrap_pw_global.num; i++) {
+ if (strcmp(nwrap_pw_global.list[i].pw_name, name) == 0) {
+ NWRAP_DEBUG(("%s: user[%s] found\n",
+ __location__, name));
+ return &nwrap_pw_global.list[i];
+ }
+ NWRAP_VERBOSE(("%s: user[%s] does not match [%s]\n",
+ __location__, name,
+ nwrap_pw_global.list[i].pw_name));
+ }
+
+ NWRAP_DEBUG(("%s: user[%s] not found\n", __location__, name));
+
+ errno = ENOENT;
+ return NULL;
+}
+
+_PUBLIC_ int nwrap_getpwnam_r(const char *name, struct passwd *pwdst,
+ char *buf, size_t buflen, struct passwd **pwdstp)
+{
+ struct passwd *pw;
+
+ if (!nwrap_enabled()) {
+ return real_getpwnam_r(name, pwdst, buf, buflen, pwdstp);
+ }
+
+ pw = nwrap_getpwnam(name);
+ if (!pw) {
+ if (errno == 0) {
+ return ENOENT;
+ }
+ return errno;
+ }
+
+ return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
+}
+
+_PUBLIC_ struct passwd *nwrap_getpwuid(uid_t uid)
+{
+ int i;
+
+ if (!nwrap_enabled()) {
+ return real_getpwuid(uid);
+ }
+
+ nwrap_cache_reload(nwrap_pw_global.cache);
+
+ for (i=0; i<nwrap_pw_global.num; i++) {
+ if (nwrap_pw_global.list[i].pw_uid == uid) {
+ NWRAP_DEBUG(("%s: uid[%u] found\n",
+ __location__, uid));
+ return &nwrap_pw_global.list[i];
+ }
+ NWRAP_VERBOSE(("%s: uid[%u] does not match [%u]\n",
+ __location__, uid,
+ nwrap_pw_global.list[i].pw_uid));
+ }
+
+ NWRAP_DEBUG(("%s: uid[%u] not found\n", __location__, uid));
+
+ errno = ENOENT;
+ return NULL;
+}
+
+_PUBLIC_ int nwrap_getpwuid_r(uid_t uid, struct passwd *pwdst,
+ char *buf, size_t buflen, struct passwd **pwdstp)
+{
+ struct passwd *pw;
+
+ if (!nwrap_enabled()) {
+ return real_getpwuid_r(uid, pwdst, buf, buflen, pwdstp);
+ }
+
+ pw = nwrap_getpwuid(uid);
+ if (!pw) {
+ if (errno == 0) {
+ return ENOENT;
+ }
+ return errno;
+ }
+
+ return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
+}
+
+/* user enum functions */
+_PUBLIC_ void nwrap_setpwent(void)
+{
+ if (!nwrap_enabled()) {
+ real_setpwent();
+ }
+
+ nwrap_pw_global.idx = 0;
+}
+
+_PUBLIC_ struct passwd *nwrap_getpwent(void)
+{
+ struct passwd *pw;
+
+ if (!nwrap_enabled()) {
+ return real_getpwent();
+ }
+
+ if (nwrap_pw_global.idx == 0) {
+ nwrap_cache_reload(nwrap_pw_global.cache);
+ }
+
+ if (nwrap_pw_global.idx >= nwrap_pw_global.num) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ pw = &nwrap_pw_global.list[nwrap_pw_global.idx++];
+
+ NWRAP_VERBOSE(("%s: return user[%s] uid[%u]\n",
+ __location__, pw->pw_name, pw->pw_uid));
+
+ return pw;
+}
+
+_PUBLIC_ int nwrap_getpwent_r(struct passwd *pwdst, char *buf,
+ size_t buflen, struct passwd **pwdstp)
+{
+ struct passwd *pw;
+
+ if (!nwrap_enabled()) {
+#ifdef SOLARIS_GETPWENT_R
+ pw = real_getpwent_r(pwdst, buf, buflen);
+ if (!pw) {
+ if (errno == 0) {
+ return ENOENT;
+ }
+ return errno;
+ }
+ if (pwdstp) {
+ *pwdstp = pw;
+ }
+ return 0;
+#else
+ return real_getpwent_r(pwdst, buf, buflen, pwdstp);
+#endif
+ }
+
+ pw = nwrap_getpwent();
+ if (!pw) {
+ if (errno == 0) {
+ return ENOENT;
+ }
+ return errno;
+ }
+
+ return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
+}
+
+_PUBLIC_ void nwrap_endpwent(void)
+{
+ if (!nwrap_enabled()) {
+ real_endpwent();
+ }
+
+ nwrap_pw_global.idx = 0;
+}
+
+/* misc functions */
+_PUBLIC_ int nwrap_initgroups(const char *user, gid_t group)
+{
+ if (!nwrap_enabled()) {
+ return real_initgroups(user, group);
+ }
+
+ /* TODO: maybe we should also fake this... */
+ return EPERM;
+}
+
+/* group functions */
+_PUBLIC_ struct group *nwrap_getgrnam(const char *name)
+{
+ int i;
+
+ if (!nwrap_enabled()) {
+ return real_getgrnam(name);
+ }
+
+ nwrap_cache_reload(nwrap_gr_global.cache);
+
+ for (i=0; i<nwrap_gr_global.num; i++) {
+ if (strcmp(nwrap_gr_global.list[i].gr_name, name) == 0) {
+ NWRAP_DEBUG(("%s: group[%s] found\n",
+ __location__, name));
+ return &nwrap_gr_global.list[i];
+ }
+ NWRAP_VERBOSE(("%s: group[%s] does not match [%s]\n",
+ __location__, name,
+ nwrap_gr_global.list[i].gr_name));
+ }
+
+ NWRAP_DEBUG(("%s: group[%s] not found\n", __location__, name));
+
+ errno = ENOENT;
+ return NULL;
+}
+
+_PUBLIC_ int nwrap_getgrnam_r(const char *name, struct group *grdst,
+ char *buf, size_t buflen, struct group **grdstp)
+{
+ struct group *gr;
+
+ if (!nwrap_enabled()) {
+ return real_getgrnam_r(name, grdst, buf, buflen, grdstp);
+ }
+
+ gr = nwrap_getgrnam(name);
+ if (!gr) {
+ if (errno == 0) {
+ return ENOENT;
+ }
+ return errno;
+ }
+
+ return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
+}
+
+_PUBLIC_ struct group *nwrap_getgrgid(gid_t gid)
+{
+ int i;
+
+ if (!nwrap_enabled()) {
+ return real_getgrgid(gid);
+ }
+
+ nwrap_cache_reload(nwrap_gr_global.cache);
+
+ for (i=0; i<nwrap_gr_global.num; i++) {
+ if (nwrap_gr_global.list[i].gr_gid == gid) {
+ NWRAP_DEBUG(("%s: gid[%u] found\n",
+ __location__, gid));
+ return &nwrap_gr_global.list[i];
+ }
+ NWRAP_VERBOSE(("%s: gid[%u] does not match [%u]\n",
+ __location__, gid,
+ nwrap_gr_global.list[i].gr_gid));
+ }
+
+ NWRAP_DEBUG(("%s: gid[%u] not found\n", __location__, gid));
+
+ errno = ENOENT;
+ return NULL;
+}
+
+_PUBLIC_ int nwrap_getgrgid_r(gid_t gid, struct group *grdst,
+ char *buf, size_t buflen, struct group **grdstp)
+{
+ struct group *gr;
+
+ if (!nwrap_enabled()) {
+ return real_getgrgid_r(gid, grdst, buf, buflen, grdstp);
+ }
+
+ gr = nwrap_getgrgid(gid);
+ if (!gr) {
+ if (errno == 0) {
+ return ENOENT;
+ }
+ return errno;
+ }
+
+ return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
+
+ return ENOENT;
+}
+
+/* group enum functions */
+_PUBLIC_ void nwrap_setgrent(void)
+{
+ if (!nwrap_enabled()) {
+ real_setgrent();
+ }
+
+ nwrap_gr_global.idx = 0;
+}
+
+_PUBLIC_ struct group *nwrap_getgrent(void)
+{
+ struct group *gr;
+
+ if (!nwrap_enabled()) {
+ return real_getgrent();
+ }
+
+ if (nwrap_gr_global.idx == 0) {
+ nwrap_cache_reload(nwrap_gr_global.cache);
+ }
+
+ if (nwrap_gr_global.idx >= nwrap_gr_global.num) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ gr = &nwrap_gr_global.list[nwrap_gr_global.idx++];
+
+ NWRAP_VERBOSE(("%s: return group[%s] gid[%u]\n",
+ __location__, gr->gr_name, gr->gr_gid));
+
+ return gr;
+}
+
+_PUBLIC_ int nwrap_getgrent_r(struct group *grdst, char *buf,
+ size_t buflen, struct group **grdstp)
+{
+ struct group *gr;
+
+ if (!nwrap_enabled()) {
+#ifdef SOLARIS_GETGRENT_R
+ gr = real_getgrent_r(grdst, buf, buflen);
+ if (!gr) {
+ if (errno == 0) {
+ return ENOENT;
+ }
+ return errno;
+ }
+ if (grdstp) {
+ *grdstp = gr;
+ }
+ return 0;
+#else
+ return real_getgrent_r(grdst, buf, buflen, grdstp);
+#endif
+ }
+
+ gr = nwrap_getgrent();
+ if (!gr) {
+ if (errno == 0) {
+ return ENOENT;
+ }
+ return errno;
+ }
+
+ return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
+}
+
+_PUBLIC_ void nwrap_endgrent(void)
+{
+ if (!nwrap_enabled()) {
+ real_endgrent();
+ }
+
+ nwrap_gr_global.idx = 0;
+}
diff --git a/source3/lib/nss_wrapper/nss_wrapper.h b/source3/lib/nss_wrapper/nss_wrapper.h
new file mode 100644
index 0000000000..35a47348a8
--- /dev/null
+++ b/source3/lib/nss_wrapper/nss_wrapper.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) Stefan Metzmacher 2007 <metze@samba.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __NSS_WRAPPER_H__
+#define __NSS_WRAPPER_H__
+
+struct passwd *nwrap_getpwnam(const char *name);
+int nwrap_getpwnam_r(const char *name, struct passwd *pwbuf,
+ char *buf, size_t buflen, struct passwd **pwbufp);
+struct passwd *nwrap_getpwuid(uid_t uid);
+int nwrap_getpwuid_r(uid_t uid, struct passwd *pwbuf,
+ char *buf, size_t buflen, struct passwd **pwbufp);
+void nwrap_setpwent(void);
+struct passwd *nwrap_getpwent(void);
+int nwrap_getpwent_r(struct passwd *pwbuf, char *buf,
+ size_t buflen, struct passwd **pwbufp);
+void nwrap_endpwent(void);
+int nwrap_initgroups(const char *user, gid_t group);
+struct group *nwrap_getgrnam(const char *name);
+int nwrap_getgrnam_r(const char *name, struct group *gbuf,
+ char *buf, size_t buflen, struct group **gbufp);
+struct group *nwrap_getgrgid(gid_t gid);
+int nwrap_getgrgid_r(gid_t gid, struct group *gbuf,
+ char *buf, size_t buflen, struct group **gbufp);
+void nwrap_setgrent(void);
+struct group *nwrap_getgrent(void);
+int nwrap_getgrent_r(struct group *gbuf, char *buf,
+ size_t buflen, struct group **gbufp);
+void nwrap_endgrent(void);
+
+#ifdef NSS_WRAPPER_REPLACE
+
+#ifdef getpwnam
+#undef getpwnam
+#endif
+#define getpwnam nwrap_getpwnam
+
+#ifdef getpwnam_r
+#undef getpwnam_r
+#endif
+#define getpwnam_r nwrap_getpwnam_r
+
+#ifdef getpwuid
+#undef getpwuid
+#endif
+#define getpwuid nwrap_getpwuid
+
+#ifdef getpwuid_r
+#undef getpwuid_r
+#endif
+#define getpwuid_r nwrap_getpwuid_r
+
+#ifdef setpwent
+#undef setpwent
+#endif
+#define setpwent nwrap_setpwent
+
+#ifdef getpwent
+#undef getpwent
+#endif
+#define getpwent nwrap_getpwent
+
+#ifdef getpwent_r
+#undef getpwent_r
+#endif
+#define getpwent_r nwrap_getpwent_r
+
+#ifdef endpwent
+#undef endpwent
+#endif
+#define endpwent nwrap_endpwent
+
+#ifdef getgrlst
+#undef getgrlst
+#endif
+#define getgrlst __none_nwrap_getgrlst
+
+#ifdef getgrlst_r
+#undef getgrlst_r
+#endif
+#define getgrlst_r __none_nwrap_getgrlst_r
+
+#ifdef initgroups_dyn
+#undef initgroups_dyn
+#endif
+#define initgroups_dyn __none_nwrap_initgroups_dyn
+
+#ifdef initgroups
+#undef initgroups
+#endif
+#define initgroups nwrap_initgroups
+
+#ifdef getgrnam
+#undef getgrnam
+#endif
+#define getgrnam nwrap_getgrnam
+
+#ifdef getgrnam_r
+#undef getgrnam_r
+#endif
+#define getgrnam_r nwrap_getgrnam_r
+
+#ifdef getgrgid
+#undef getgrgid
+#endif
+#define getgrgid nwrap_getgrgid
+
+#ifdef getgrgid_r
+#undef getgrgid_r
+#endif
+#define getgrgid_r nwrap_getgrgid_r
+
+#ifdef setgrent
+#undef setgrent
+#endif
+#define setgrent nwrap_setgrent
+
+#ifdef getgrent
+#undef getgrent
+#endif
+#define getgrent nwrap_getgrent
+
+#ifdef getgrent_r
+#undef getgrent_r
+#endif
+#define getgrent_r nwrap_getgrent_r
+
+#ifdef endgrent
+#undef endgrent
+#endif
+#define endgrent nwrap_endgrent
+
+#endif /* NSS_WRAPPER_REPLACE */
+
+#endif /* __NSS_WRAPPER_H__ */
diff --git a/source3/lib/nss_wrapper/nss_wrapper.pl b/source3/lib/nss_wrapper/nss_wrapper.pl
new file mode 100644
index 0000000000..b1c9be5365
--- /dev/null
+++ b/source3/lib/nss_wrapper/nss_wrapper.pl
@@ -0,0 +1,265 @@
+#!/usr/bin/perl
+#
+
+use strict;
+
+use Getopt::Long;
+use Cwd qw(abs_path);
+
+my $opt_help = 0;
+my $opt_path = undef;
+my $opt_action = undef;
+my $opt_type = undef;
+my $opt_name = undef;
+
+my $passwdfn = undef;
+my $groupfn = undef;
+my $actionfn = undef;
+
+sub passwd_add($$);
+sub passwd_delete($$);
+sub group_add($$);
+sub group_delete($$);
+
+my $result = GetOptions(
+ 'help|h|?' => \$opt_help,
+ 'path=s' => \$opt_path,
+ 'action=s' => \$opt_action,
+ 'type=s' => \$opt_type,
+ 'name=s' => \$opt_name
+);
+
+sub usage($;$)
+{
+ my ($ret, $msg) = @_;
+
+ print $msg."\n\n" if defined($msg);
+
+ print "usage:
+
+ --help|-h|-? Show this help.
+
+ --path <path> Path of the 'passwd' or 'group' file.
+
+ --type <type> Only 'passwd' is supported yet,
+ but 'group' and maybe 'member' will be added
+ in future.
+
+ --action <action> 'add' or 'delete'.
+
+ --name <name> The name of the object.
+";
+ exit($ret);
+}
+
+usage(1) if (not $result);
+
+usage(0) if ($opt_help);
+
+if (not defined($opt_path)) {
+ usage(1, "missing: --path <path>");
+}
+if ($opt_path eq "" or $opt_path eq "/") {
+ usage(1, "invalid: --path <path>: '$opt_path'");
+}
+my $opt_fullpath = abs_path($opt_path);
+if (not defined($opt_fullpath)) {
+ usage(1, "invalid: --path <path>: '$opt_path'");
+}
+
+
+if (not defined($opt_action)) {
+ usage(1, "missing: --action [add|delete]");
+}
+if ($opt_action eq "add") {
+ $passwdfn = \&passwd_add;
+ $groupfn = \&group_add;
+} elsif ($opt_action eq "delete") {
+ $passwdfn = \&passwd_delete;
+ $groupfn = \&group_delete;
+} else {
+ usage(1, "invalid: --action [add|delete]: '$opt_action'");
+}
+
+if (not defined($opt_type)) {
+ usage(1, "missing: --type [passwd|group]");
+}
+if ($opt_type eq "passwd") {
+ $actionfn = $passwdfn;
+} elsif ($opt_type eq "group") {
+ $actionfn = $groupfn;
+} else {
+ usage(1, "invalid: --type [passwd|group]: '$opt_type'")
+}
+
+if (not defined($opt_name)) {
+ usage(1, "missing: --name <name>");
+}
+if ($opt_name eq "") {
+ usage(1, "invalid: --name <name>");
+}
+
+exit $actionfn->($opt_fullpath, $opt_name);
+
+sub passwd_add_entry($$);
+
+sub passwd_load($)
+{
+ my ($path) = @_;
+ my @lines;
+ my $passwd = undef;
+
+ open(PWD, "<$path") or die("Unable to open '$path' for read");
+ @lines = <PWD>;
+ close(PWD);
+
+ $passwd->{array} = ();
+ $passwd->{name} = {};
+ $passwd->{uid} = {};
+ $passwd->{path} = $path;
+
+ foreach my $line (@lines) {
+ passwd_add_entry($passwd, $line);
+ }
+
+ return $passwd;
+}
+
+sub passwd_lookup_name($$)
+{
+ my ($passwd, $name) = @_;
+
+ return undef unless defined($passwd->{name}{$name});
+
+ return $passwd->{name}{$name};
+}
+
+sub passwd_lookup_uid($$)
+{
+ my ($passwd, $uid) = @_;
+
+ return undef unless defined($passwd->{uid}{$uid});
+
+ return $passwd->{uid}{$uid};
+}
+
+sub passwd_get_free_uid($)
+{
+ my ($passwd) = @_;
+ my $uid = 1000;
+
+ while (passwd_lookup_uid($passwd, $uid)) {
+ $uid++;
+ }
+
+ return $uid;
+}
+
+sub passwd_add_entry($$)
+{
+ my ($passwd, $str) = @_;
+
+ chomp $str;
+ my @e = split(':', $str);
+
+ push(@{$passwd->{array}}, \@e);
+ $passwd->{name}{$e[0]} = \@e;
+ $passwd->{uid}{$e[2]} = \@e;
+}
+
+sub passwd_remove_entry($$)
+{
+ my ($passwd, $eref) = @_;
+
+ for(my $i; defined($passwd->{array}[$i]); $i++) {
+ if ($eref == $passwd->{array}[$i]) {
+ $passwd->{array}[$i] = undef;
+ }
+ }
+
+ delete $passwd->{name}{${$eref}[0]};
+ delete $passwd->{uid}{${$eref}[2]};
+}
+
+sub passwd_save($)
+{
+ my ($passwd) = @_;
+ my @lines = ();
+ my $path = $passwd->{path};
+ my $tmppath = $path.$$;
+
+ foreach my $eref (@{$passwd->{array}}) {
+ next unless defined($eref);
+
+ my $line = join(':', @{$eref});
+ push(@lines, $line);
+ }
+
+ open(PWD, ">$tmppath") or die("Unable to open '$tmppath' for write");
+ print PWD join("\n", @lines)."\n";
+ close(PWD);
+ rename($tmppath, $path) or die("Unable to rename $tmppath => $path");
+}
+
+sub passwd_add($$)
+{
+ my ($path, $name) = @_;
+
+ #print "passwd_add: '$name' in '$path'\n";
+
+ my $passwd = passwd_load($path);
+
+ my $e = passwd_lookup_name($passwd, $name);
+ die("account[$name] already exists in '$path'") if defined($e);
+
+ my $uid = passwd_get_free_uid($passwd);
+ my $gid = 65534;# nogroup gid
+
+ my $pwent = $name.":x:".$uid.":".$gid.":".$name." gecos:/nodir:/bin/false";
+
+ passwd_add_entry($passwd, $pwent);
+
+ passwd_save($passwd);
+
+ return 0;
+}
+
+sub passwd_delete($$)
+{
+ my ($path, $name) = @_;
+
+ #print "passwd_delete: '$name' in '$path'\n";
+
+ my $passwd = passwd_load($path);
+
+ my $e = passwd_lookup_name($passwd, $name);
+ die("account[$name] does not exists in '$path'") unless defined($e);
+
+ passwd_remove_entry($passwd, $e);
+
+ passwd_save($passwd);
+
+ return 0;
+}
+
+sub group_add($$)
+{
+ my ($path, $name) = @_;
+
+ #print "group_add: '$name' in '$path'\n";
+
+ die("group_add: not implemented yet!");
+
+ return 0;
+}
+
+sub group_delete($$)
+{
+ my ($path, $name) = @_;
+
+ #print "group_delete: '$name' in '$path'\n";
+
+ die("group_delete: not implemented yet!");
+
+ return 0;
+}
diff --git a/source3/lib/packet.c b/source3/lib/packet.c
new file mode 100644
index 0000000000..e0486165f3
--- /dev/null
+++ b/source3/lib/packet.c
@@ -0,0 +1,257 @@
+/*
+ Unix SMB/CIFS implementation.
+ Packet handling
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+struct packet_context {
+ int fd;
+ struct data_blob in, out;
+};
+
+/*
+ * Close the underlying fd
+ */
+static int packet_context_destructor(struct packet_context *ctx)
+{
+ return close(ctx->fd);
+}
+
+/*
+ * Initialize a packet context. The fd is given to the packet context, meaning
+ * that it is automatically closed when the packet context is freed.
+ */
+struct packet_context *packet_init(TALLOC_CTX *mem_ctx, int fd)
+{
+ struct packet_context *result;
+
+ if (!(result = TALLOC_ZERO_P(mem_ctx, struct packet_context))) {
+ return NULL;
+ }
+
+ result->fd = fd;
+ talloc_set_destructor(result, packet_context_destructor);
+ return result;
+}
+
+/*
+ * Pull data from the fd
+ */
+NTSTATUS packet_fd_read(struct packet_context *ctx)
+{
+ int res, available;
+ size_t new_size;
+ uint8 *in;
+
+ res = ioctl(ctx->fd, FIONREAD, &available);
+
+ if (res == -1) {
+ DEBUG(10, ("ioctl(FIONREAD) failed: %s\n", strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+
+ SMB_ASSERT(available >= 0);
+
+ if (available == 0) {
+ return NT_STATUS_END_OF_FILE;
+ }
+
+ new_size = ctx->in.length + available;
+
+ if (new_size < ctx->in.length) {
+ DEBUG(0, ("integer wrap\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!(in = TALLOC_REALLOC_ARRAY(ctx, ctx->in.data, uint8, new_size))) {
+ DEBUG(10, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ctx->in.data = in;
+
+ res = recv(ctx->fd, in + ctx->in.length, available, 0);
+
+ if (res < 0) {
+ DEBUG(10, ("recv failed: %s\n", strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+
+ if (res == 0) {
+ return NT_STATUS_END_OF_FILE;
+ }
+
+ ctx->in.length += res;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS packet_fd_read_sync(struct packet_context *ctx)
+{
+ int res;
+ fd_set r_fds;
+
+ FD_ZERO(&r_fds);
+ FD_SET(ctx->fd, &r_fds);
+
+ res = sys_select(ctx->fd+1, &r_fds, NULL, NULL, NULL);
+
+ if (res == -1) {
+ DEBUG(10, ("select returned %s\n", strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+
+ return packet_fd_read(ctx);
+}
+
+bool packet_handler(struct packet_context *ctx,
+ bool (*full_req)(const struct data_blob *data,
+ size_t *length,
+ void *private_data),
+ NTSTATUS (*callback)(const struct data_blob *data,
+ void *private_data),
+ void *private_data,
+ NTSTATUS *status)
+{
+ size_t length;
+ struct data_blob data;
+
+ if (!full_req(&ctx->in, &length, private_data)) {
+ return False;
+ }
+
+ SMB_ASSERT(length <= ctx->in.length);
+
+ data = data_blob(ctx->in.data, length);
+
+ memmove(ctx->in.data, ctx->in.data + length,
+ ctx->in.length - length);
+ ctx->in.length -= length;
+
+ *status = callback(&data, private_data);
+
+ data_blob_free(&data);
+
+ return True;
+}
+
+/*
+ * How many bytes of outgoing data do we have pending?
+ */
+size_t packet_outgoing_bytes(struct packet_context *ctx)
+{
+ return ctx->out.length;
+}
+
+/*
+ * Push data to the fd
+ */
+NTSTATUS packet_fd_write(struct packet_context *ctx)
+{
+ ssize_t sent;
+
+ sent = send(ctx->fd, ctx->out.data, ctx->out.length, 0);
+
+ if (sent == -1) {
+ DEBUG(0, ("send failed: %s\n", strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+
+ memmove(ctx->out.data, ctx->out.data + sent,
+ ctx->out.length - sent);
+ ctx->out.length -= sent;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * Sync flush all outgoing bytes
+ */
+NTSTATUS packet_flush(struct packet_context *ctx)
+{
+ while (ctx->out.length != 0) {
+ NTSTATUS status = packet_fd_write(ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
+/*
+ * Send a list of DATA_BLOBs
+ *
+ * Example: packet_send(ctx, 2, data_blob_const(&size, sizeof(size)),
+ * data_blob_const(buf, size));
+ */
+NTSTATUS packet_send(struct packet_context *ctx, int num_blobs, ...)
+{
+ va_list ap;
+ int i;
+ size_t len;
+ uint8 *out;
+
+ len = ctx->out.length;
+
+ va_start(ap, num_blobs);
+ for (i=0; i<num_blobs; i++) {
+ size_t tmp;
+ struct data_blob blob = va_arg(ap, struct data_blob);
+
+ tmp = len + blob.length;
+ if (tmp < len) {
+ DEBUG(0, ("integer overflow\n"));
+ va_end(ap);
+ return NT_STATUS_NO_MEMORY;
+ }
+ len = tmp;
+ }
+ va_end(ap);
+
+ if (len == 0) {
+ return NT_STATUS_OK;
+ }
+
+ if (!(out = TALLOC_REALLOC_ARRAY(ctx, ctx->out.data, uint8, len))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ctx->out.data = out;
+
+ va_start(ap, num_blobs);
+ for (i=0; i<num_blobs; i++) {
+ struct data_blob blob = va_arg(ap, struct data_blob);
+
+ memcpy(ctx->out.data+ctx->out.length, blob.data, blob.length);
+ ctx->out.length += blob.length;
+ }
+ va_end(ap);
+
+ SMB_ASSERT(ctx->out.length == len);
+ return NT_STATUS_OK;
+}
+
+/*
+ * Get the packet context's file descriptor
+ */
+int packet_get_fd(struct packet_context *ctx)
+{
+ return ctx->fd;
+}
+
diff --git a/source3/lib/pam_errors.c b/source3/lib/pam_errors.c
new file mode 100644
index 0000000000..1073f269e5
--- /dev/null
+++ b/source3/lib/pam_errors.c
@@ -0,0 +1,139 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * PAM error mapping functions
+ * Copyright (C) Andrew Bartlett 2002
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#ifdef WITH_PAM
+#if defined(HAVE_SECURITY_PAM_APPL_H)
+#include <security/pam_appl.h>
+#elif defined(HAVE_PAM_PAM_APPL_H)
+#include <pam/pam_appl.h>
+#endif
+
+#if defined(PAM_AUTHTOK_RECOVERY_ERR) && !defined(PAM_AUTHTOK_RECOVER_ERR)
+#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR
+#endif
+
+/* PAM -> NT_STATUS map */
+static const struct {
+ int pam_code;
+ NTSTATUS ntstatus;
+} pam_to_nt_status_map[] = {
+ {PAM_OPEN_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_SYMBOL_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_SERVICE_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_SYSTEM_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_BUF_ERR, NT_STATUS_NO_MEMORY},
+ {PAM_PERM_DENIED, NT_STATUS_ACCESS_DENIED},
+ {PAM_AUTH_ERR, NT_STATUS_WRONG_PASSWORD},
+ {PAM_CRED_INSUFFICIENT, NT_STATUS_INSUFFICIENT_LOGON_INFO}, /* FIXME: Is this correct? */
+ {PAM_AUTHINFO_UNAVAIL, NT_STATUS_LOGON_FAILURE},
+ {PAM_USER_UNKNOWN, NT_STATUS_NO_SUCH_USER},
+ {PAM_MAXTRIES, NT_STATUS_REMOTE_SESSION_LIMIT}, /* FIXME: Is this correct? */
+ {PAM_NEW_AUTHTOK_REQD, NT_STATUS_PASSWORD_MUST_CHANGE},
+ {PAM_ACCT_EXPIRED, NT_STATUS_ACCOUNT_EXPIRED},
+ {PAM_SESSION_ERR, NT_STATUS_INSUFFICIENT_RESOURCES},
+ {PAM_CRED_UNAVAIL, NT_STATUS_NO_TOKEN}, /* FIXME: Is this correct? */
+ {PAM_CRED_EXPIRED, NT_STATUS_PASSWORD_EXPIRED}, /* FIXME: Is this correct? */
+ {PAM_CRED_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_AUTHTOK_ERR, NT_STATUS_UNSUCCESSFUL},
+#ifdef PAM_AUTHTOK_RECOVER_ERR
+ {PAM_AUTHTOK_RECOVER_ERR, NT_STATUS_UNSUCCESSFUL},
+#endif
+ {PAM_AUTHTOK_EXPIRED, NT_STATUS_PASSWORD_EXPIRED},
+ {PAM_SUCCESS, NT_STATUS_OK}
+};
+
+/* NT_STATUS -> PAM map */
+static const struct {
+ NTSTATUS ntstatus;
+ int pam_code;
+} nt_status_to_pam_map[] = {
+ {NT_STATUS_UNSUCCESSFUL, PAM_SYSTEM_ERR},
+ {NT_STATUS_NO_SUCH_USER, PAM_USER_UNKNOWN},
+ {NT_STATUS_WRONG_PASSWORD, PAM_AUTH_ERR},
+ {NT_STATUS_LOGON_FAILURE, PAM_AUTH_ERR},
+ {NT_STATUS_ACCOUNT_EXPIRED, PAM_ACCT_EXPIRED},
+ {NT_STATUS_PASSWORD_EXPIRED, PAM_AUTHTOK_EXPIRED},
+ {NT_STATUS_PASSWORD_MUST_CHANGE, PAM_NEW_AUTHTOK_REQD},
+ {NT_STATUS_ACCOUNT_LOCKED_OUT, PAM_MAXTRIES},
+ {NT_STATUS_NO_MEMORY, PAM_BUF_ERR},
+ {NT_STATUS_PASSWORD_RESTRICTION, PAM_PERM_DENIED},
+ {NT_STATUS_BACKUP_CONTROLLER, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_NO_LOGON_SERVERS, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_INVALID_WORKSTATION, PAM_PERM_DENIED},
+ {NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_OK, PAM_SUCCESS}
+};
+
+/*****************************************************************************
+convert a PAM error to a NT status32 code
+ *****************************************************************************/
+NTSTATUS pam_to_nt_status(int pam_error)
+{
+ int i;
+ if (pam_error == 0) return NT_STATUS_OK;
+
+ for (i=0; NT_STATUS_V(pam_to_nt_status_map[i].ntstatus); i++) {
+ if (pam_error == pam_to_nt_status_map[i].pam_code)
+ return pam_to_nt_status_map[i].ntstatus;
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/*****************************************************************************
+convert an NT status32 code to a PAM error
+ *****************************************************************************/
+int nt_status_to_pam(NTSTATUS nt_status)
+{
+ int i;
+ if NT_STATUS_IS_OK(nt_status) return PAM_SUCCESS;
+
+ for (i=0; NT_STATUS_V(nt_status_to_pam_map[i].ntstatus); i++) {
+ if (NT_STATUS_EQUAL(nt_status,nt_status_to_pam_map[i].ntstatus))
+ return nt_status_to_pam_map[i].pam_code;
+ }
+ return PAM_SYSTEM_ERR;
+}
+
+#else
+
+/*****************************************************************************
+convert a PAM error to a NT status32 code
+ *****************************************************************************/
+NTSTATUS pam_to_nt_status(int pam_error)
+{
+ if (pam_error == 0) return NT_STATUS_OK;
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/*****************************************************************************
+convert an NT status32 code to a PAM error
+ *****************************************************************************/
+int nt_status_to_pam(NTSTATUS nt_status)
+{
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_OK)) return 0;
+ return 4; /* PAM_SYSTEM_ERR */
+}
+
+#endif
+
diff --git a/source3/lib/pidfile.c b/source3/lib/pidfile.c
new file mode 100644
index 0000000000..f49f8afbb6
--- /dev/null
+++ b/source3/lib/pidfile.c
@@ -0,0 +1,147 @@
+/* this code is broken - there is a race condition with the unlink (tridge) */
+
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK
+#endif
+
+/* return the pid in a pidfile. return 0 if the process (or pidfile)
+ does not exist */
+pid_t pidfile_pid(const char *name)
+{
+ int fd;
+ char pidstr[20];
+ pid_t pid;
+ unsigned int ret;
+ char * pidFile;
+
+ if (asprintf(&pidFile, "%s/%s.pid", lp_piddir(), name) == -1) {
+ return 0;
+ }
+
+ fd = sys_open(pidFile, O_NONBLOCK | O_RDONLY, 0644);
+ if (fd == -1) {
+ SAFE_FREE(pidFile);
+ return 0;
+ }
+
+ ZERO_ARRAY(pidstr);
+
+ if (read(fd, pidstr, sizeof(pidstr)-1) <= 0) {
+ goto noproc;
+ }
+
+ ret = atoi(pidstr);
+
+ if (ret == 0) {
+ /* Obviously we had some garbage in the pidfile... */
+ DEBUG(1, ("Could not parse contents of pidfile %s\n",
+ pidFile));
+ goto noproc;
+ }
+
+ pid = (pid_t)ret;
+ if (!process_exists_by_pid(pid)) {
+ goto noproc;
+ }
+
+ if (fcntl_lock(fd,SMB_F_SETLK,0,1,F_RDLCK)) {
+ /* we could get the lock - it can't be a Samba process */
+ goto noproc;
+ }
+
+ SAFE_FREE(pidFile);
+ close(fd);
+ return (pid_t)ret;
+
+ noproc:
+ close(fd);
+ unlink(pidFile);
+ SAFE_FREE(pidFile);
+ return 0;
+}
+
+/* create a pid file in the pid directory. open it and leave it locked */
+void pidfile_create(const char *program_name)
+{
+ int fd;
+ char buf[20];
+ const char *short_configfile;
+ char *name;
+ char *pidFile;
+ pid_t pid;
+
+ /* Add a suffix to the program name if this is a process with a
+ * none default configuration file name. */
+ if (strcmp( CONFIGFILE, get_dyn_CONFIGFILE()) == 0) {
+ name = SMB_STRDUP(program_name);
+ } else {
+ short_configfile = strrchr( get_dyn_CONFIGFILE(), '/');
+ if (short_configfile == NULL) {
+ /* conf file in current directory */
+ short_configfile = get_dyn_CONFIGFILE();
+ } else {
+ /* full/relative path provided */
+ short_configfile++;
+ }
+ if (asprintf(&name, "%s-%s", program_name,
+ short_configfile) == -1) {
+ smb_panic("asprintf failed");
+ }
+ }
+
+ if (asprintf(&pidFile, "%s/%s.pid", lp_piddir(), name) == -1) {
+ smb_panic("asprintf failed");
+ }
+
+ pid = pidfile_pid(name);
+ if (pid != 0) {
+ DEBUG(0,("ERROR: %s is already running. File %s exists and process id %d is running.\n",
+ name, pidFile, (int)pid));
+ exit(1);
+ }
+
+ fd = sys_open(pidFile, O_NONBLOCK | O_CREAT | O_WRONLY | O_EXCL, 0644);
+ if (fd == -1) {
+ DEBUG(0,("ERROR: can't open %s: Error was %s\n", pidFile,
+ strerror(errno)));
+ exit(1);
+ }
+
+ if (fcntl_lock(fd,SMB_F_SETLK,0,1,F_WRLCK)==False) {
+ DEBUG(0,("ERROR: %s : fcntl lock of file %s failed. Error was %s\n",
+ name, pidFile, strerror(errno)));
+ exit(1);
+ }
+
+ memset(buf, 0, sizeof(buf));
+ slprintf(buf, sizeof(buf) - 1, "%u\n", (unsigned int) sys_getpid());
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(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... */
+ SAFE_FREE(name);
+ SAFE_FREE(pidFile);
+}
diff --git a/source3/lib/popt_common.c b/source3/lib/popt_common.c
new file mode 100644
index 0000000000..8ceac26bf2
--- /dev/null
+++ b/source3/lib/popt_common.c
@@ -0,0 +1,555 @@
+/*
+ Unix SMB/CIFS implementation.
+ Common popt routines
+
+ Copyright (C) Tim Potter 2001,2002
+ Copyright (C) Jelmer Vernooij 2002,2003
+ Copyright (C) James Peach 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* Handle command line options:
+ * -d,--debuglevel
+ * -s,--configfile
+ * -O,--socket-options
+ * -V,--version
+ * -l,--log-base
+ * -n,--netbios-name
+ * -W,--workgroup
+ * -i,--scope
+ */
+
+extern bool AllowDebugChange;
+extern bool override_logfile;
+
+static void set_logfile(poptContext con, const char * arg)
+{
+
+ char *logfile = NULL;
+ const char *pname;
+
+ /* Find out basename of current program */
+ pname = strrchr_m(poptGetInvocationName(con),'/');
+
+ if (!pname)
+ pname = poptGetInvocationName(con);
+ else
+ pname++;
+
+ if (asprintf(&logfile, "%s/log.%s", arg, pname) < 0) {
+ return;
+ }
+ lp_set_logfile(logfile);
+ SAFE_FREE(logfile);
+}
+
+static bool PrintSambaVersionString;
+
+static void popt_common_callback(poptContext con,
+ enum poptCallbackReason reason,
+ const struct poptOption *opt,
+ const char *arg, const void *data)
+{
+
+ if (reason == POPT_CALLBACK_REASON_PRE) {
+ set_logfile(con, get_dyn_LOGFILEBASE());
+ return;
+ }
+
+ if (reason == POPT_CALLBACK_REASON_POST) {
+
+ if (PrintSambaVersionString) {
+ printf( "Version %s\n", SAMBA_VERSION_STRING);
+ exit(0);
+ }
+
+ if (is_default_dyn_CONFIGFILE()) {
+ if(getenv("SMB_CONF_PATH")) {
+ set_dyn_CONFIGFILE(getenv("SMB_CONF_PATH"));
+ }
+ }
+
+ /* Further 'every Samba program must do this' hooks here. */
+ return;
+ }
+
+ switch(opt->val) {
+ case 'd':
+ if (arg) {
+ debug_parse_levels(arg);
+ AllowDebugChange = False;
+ }
+ break;
+
+ case 'V':
+ PrintSambaVersionString = True;
+ break;
+
+ case 'O':
+ if (arg) {
+ lp_do_parameter(-1, "socket options", arg);
+ }
+ break;
+
+ case 's':
+ if (arg) {
+ set_dyn_CONFIGFILE(arg);
+ }
+ break;
+
+ case 'n':
+ if (arg) {
+ set_global_myname(arg);
+ }
+ break;
+
+ case 'l':
+ if (arg) {
+ set_logfile(con, arg);
+ override_logfile = True;
+ set_dyn_LOGFILEBASE(arg);
+ }
+ break;
+
+ case 'i':
+ if (arg) {
+ set_global_scope(arg);
+ }
+ break;
+
+ case 'W':
+ if (arg) {
+ set_global_myworkgroup(arg);
+ }
+ break;
+ }
+}
+
+struct poptOption popt_common_connection[] = {
+ { NULL, 0, POPT_ARG_CALLBACK, (void *)popt_common_callback },
+ { "socket-options", 'O', POPT_ARG_STRING, NULL, 'O', "socket options to use",
+ "SOCKETOPTIONS" },
+ { "netbiosname", 'n', POPT_ARG_STRING, NULL, 'n', "Primary netbios name", "NETBIOSNAME" },
+ { "workgroup", 'W', POPT_ARG_STRING, NULL, 'W', "Set the workgroup name", "WORKGROUP" },
+ { "scope", 'i', POPT_ARG_STRING, NULL, 'i', "Use this Netbios scope", "SCOPE" },
+
+ POPT_TABLEEND
+};
+
+struct poptOption popt_common_samba[] = {
+ { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, (void *)popt_common_callback },
+ { "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Set debug level", "DEBUGLEVEL" },
+ { "configfile", 's', POPT_ARG_STRING, NULL, 's', "Use alternate configuration file", "CONFIGFILE" },
+ { "log-basename", 'l', POPT_ARG_STRING, NULL, 'l', "Base name for log files", "LOGFILEBASE" },
+ { "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" },
+ POPT_TABLEEND
+};
+
+struct poptOption popt_common_configfile[] = {
+ { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, (void *)popt_common_callback },
+ { "configfile", 0, POPT_ARG_STRING, NULL, 's', "Use alternate configuration file", "CONFIGFILE" },
+ POPT_TABLEEND
+};
+
+struct poptOption popt_common_version[] = {
+ { NULL, 0, POPT_ARG_CALLBACK, (void *)popt_common_callback },
+ { "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" },
+ POPT_TABLEEND
+};
+
+struct poptOption popt_common_debuglevel[] = {
+ { NULL, 0, POPT_ARG_CALLBACK, (void *)popt_common_callback },
+ { "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Set debug level", "DEBUGLEVEL" },
+ POPT_TABLEEND
+};
+
+
+/* Handle command line options:
+ * --sbindir
+ * --bindir
+ * --swatdir
+ * --lmhostsfile
+ * --libdir
+ * --modulesdir
+ * --shlibext
+ * --lockdir
+ * --piddir
+ * --smb-passwd-file
+ * --private-dir
+ */
+
+enum dyn_item{
+ DYN_SBINDIR = 1,
+ DYN_BINDIR,
+ DYN_SWATDIR,
+ DYN_LMHOSTSFILE,
+ DYN_LIBDIR,
+ DYN_MODULESDIR,
+ DYN_SHLIBEXT,
+ DYN_LOCKDIR,
+ DYN_PIDDIR,
+ DYN_SMB_PASSWD_FILE,
+ DYN_PRIVATE_DIR,
+};
+
+
+static void popt_dynconfig_callback(poptContext con,
+ enum poptCallbackReason reason,
+ const struct poptOption *opt,
+ const char *arg, const void *data)
+{
+
+ switch (opt->val) {
+ case DYN_SBINDIR:
+ if (arg) {
+ set_dyn_SBINDIR(arg);
+ }
+ break;
+
+ case DYN_BINDIR:
+ if (arg) {
+ set_dyn_BINDIR(arg);
+ }
+ break;
+
+ case DYN_SWATDIR:
+ if (arg) {
+ set_dyn_SWATDIR(arg);
+ }
+ break;
+
+ case DYN_LMHOSTSFILE:
+ if (arg) {
+ set_dyn_LMHOSTSFILE(arg);
+ }
+ break;
+
+ case DYN_LIBDIR:
+ if (arg) {
+ set_dyn_LIBDIR(arg);
+ }
+ break;
+
+ case DYN_MODULESDIR:
+ if (arg) {
+ set_dyn_MODULESDIR(arg);
+ }
+ break;
+
+ case DYN_SHLIBEXT:
+ if (arg) {
+ set_dyn_SHLIBEXT(arg);
+ }
+ break;
+
+ case DYN_LOCKDIR:
+ if (arg) {
+ set_dyn_LOCKDIR(arg);
+ }
+ break;
+
+ case DYN_PIDDIR:
+ if (arg) {
+ set_dyn_PIDDIR(arg);
+ }
+ break;
+
+ case DYN_SMB_PASSWD_FILE:
+ if (arg) {
+ set_dyn_SMB_PASSWD_FILE(arg);
+ }
+ break;
+
+ case DYN_PRIVATE_DIR:
+ if (arg) {
+ set_dyn_PRIVATE_DIR(arg);
+ }
+ break;
+
+ }
+}
+
+const struct poptOption popt_common_dynconfig[] = {
+
+ { NULL, '\0', POPT_ARG_CALLBACK, (void *)popt_dynconfig_callback },
+
+ { "sbindir", '\0' , POPT_ARG_STRING, NULL, DYN_SBINDIR,
+ "Path to sbin directory", "SBINDIR" },
+ { "bindir", '\0' , POPT_ARG_STRING, NULL, DYN_BINDIR,
+ "Path to bin directory", "BINDIR" },
+ { "swatdir", '\0' , POPT_ARG_STRING, NULL, DYN_SWATDIR,
+ "Path to SWAT installation directory", "SWATDIR" },
+ { "lmhostsfile", '\0' , POPT_ARG_STRING, NULL, DYN_LMHOSTSFILE,
+ "Path to lmhosts file", "LMHOSTSFILE" },
+ { "libdir", '\0' , POPT_ARG_STRING, NULL, DYN_LIBDIR,
+ "Path to shared library directory", "LIBDIR" },
+ { "modulesdir", '\0' , POPT_ARG_STRING, NULL, DYN_MODULESDIR,
+ "Path to shared modules directory", "MODULESDIR" },
+ { "shlibext", '\0' , POPT_ARG_STRING, NULL, DYN_SHLIBEXT,
+ "Shared library extension", "SHLIBEXT" },
+ { "lockdir", '\0' , POPT_ARG_STRING, NULL, DYN_LOCKDIR,
+ "Path to lock file directory", "LOCKDIR" },
+ { "piddir", '\0' , POPT_ARG_STRING, NULL, DYN_PIDDIR,
+ "Path to PID file directory", "PIDDIR" },
+ { "smb-passwd-file", '\0' , POPT_ARG_STRING, NULL, DYN_SMB_PASSWD_FILE,
+ "Path to smbpasswd file", "SMB_PASSWD_FILE" },
+ { "private-dir", '\0' , POPT_ARG_STRING, NULL, DYN_PRIVATE_DIR,
+ "Path to private data directory", "PRIVATE_DIR" },
+
+ POPT_TABLEEND
+};
+
+/****************************************************************************
+ * get a password from a a file or file descriptor
+ * exit on failure
+ * ****************************************************************************/
+
+static void get_password_file(void)
+{
+ int fd = -1;
+ char *p;
+ bool close_it = False;
+ char *spec = NULL;
+ char pass[128];
+
+ if ((p = getenv("PASSWD_FD")) != NULL) {
+ if (asprintf(&spec, "descriptor %s", p) < 0) {
+ return;
+ }
+ sscanf(p, "%d", &fd);
+ close_it = false;
+ } else if ((p = getenv("PASSWD_FILE")) != NULL) {
+ fd = sys_open(p, O_RDONLY, 0);
+ spec = SMB_STRDUP(p);
+ if (fd < 0) {
+ fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
+ spec, strerror(errno));
+ exit(1);
+ }
+ close_it = True;
+ }
+
+ if (fd < 0) {
+ fprintf(stderr, "fd = %d, < 0\n", fd);
+ exit(1);
+ }
+
+ 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");
+ SAFE_FREE(spec);
+ exit(1);
+ }
+
+ default:
+ fprintf(stderr, "Error reading password from file %s: %s\n",
+ spec, strerror(errno));
+ SAFE_FREE(spec);
+ exit(1);
+ }
+ }
+ SAFE_FREE(spec);
+
+ set_cmdline_auth_info_password(pass);
+ if (close_it) {
+ close(fd);
+ }
+}
+
+static void get_credentials_file(const char *file)
+{
+ XFILE *auth;
+ fstring buf;
+ uint16 len = 0;
+ char *ptr, *val, *param;
+
+ if ((auth=x_fopen(file, O_RDONLY, 0)) == NULL)
+ {
+ /* fail if we can't open the credentials file */
+ d_printf("ERROR: Unable to open credentials file!\n");
+ exit(-1);
+ }
+
+ while (!x_feof(auth))
+ {
+ /* get a line from the file */
+ if (!x_fgets(buf, sizeof(buf), auth))
+ continue;
+ len = strlen(buf);
+
+ if ((len) && (buf[len-1]=='\n'))
+ {
+ buf[len-1] = '\0';
+ len--;
+ }
+ if (len == 0)
+ continue;
+
+ /* break up the line into parameter & value.
+ * will need to eat a little whitespace possibly */
+ param = buf;
+ if (!(ptr = strchr_m (buf, '=')))
+ continue;
+
+ val = ptr+1;
+ *ptr = '\0';
+
+ /* eat leading white space */
+ while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
+ val++;
+
+ if (strwicmp("password", param) == 0) {
+ set_cmdline_auth_info_password(val);
+ } else if (strwicmp("username", param) == 0) {
+ set_cmdline_auth_info_username(val);
+ } else if (strwicmp("domain", param) == 0) {
+ set_global_myworkgroup(val);
+ }
+ memset(buf, 0, sizeof(buf));
+ }
+ x_fclose(auth);
+}
+
+/* Handle command line options:
+ * -U,--user
+ * -A,--authentication-file
+ * -k,--use-kerberos
+ * -N,--no-pass
+ * -S,--signing
+ * -P --machine-pass
+ * -e --encrypt
+ */
+
+
+static void popt_common_credentials_callback(poptContext con,
+ enum poptCallbackReason reason,
+ const struct poptOption *opt,
+ const char *arg, const void *data)
+{
+ char *p;
+
+ if (reason == POPT_CALLBACK_REASON_PRE) {
+ set_cmdline_auth_info_username("GUEST");
+
+ if (getenv("LOGNAME")) {
+ set_cmdline_auth_info_username(getenv("LOGNAME"));
+ }
+
+ if (getenv("USER")) {
+ char *puser = SMB_STRDUP(getenv("USER"));
+ if (!puser) {
+ exit(ENOMEM);
+ }
+ set_cmdline_auth_info_username(puser);
+
+ if ((p = strchr_m(puser,'%'))) {
+ size_t len;
+ *p = 0;
+ len = strlen(p+1);
+ set_cmdline_auth_info_password(p+1);
+ memset(strchr_m(getenv("USER"),'%')+1,'X',len);
+ }
+ SAFE_FREE(puser);
+ }
+
+ if (getenv("PASSWD")) {
+ set_cmdline_auth_info_password(getenv("PASSWD"));
+ }
+
+ if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
+ get_password_file();
+ }
+
+ return;
+ }
+
+ switch(opt->val) {
+ case 'U':
+ {
+ char *lp;
+ char *puser = SMB_STRDUP(arg);
+
+ if ((lp=strchr_m(puser,'%'))) {
+ size_t len;
+ *lp = 0;
+ set_cmdline_auth_info_username(puser);
+ set_cmdline_auth_info_password(lp+1);
+ len = strlen(lp+1);
+ memset(strchr_m(arg,'%')+1,'X',len);
+ } else {
+ set_cmdline_auth_info_username(puser);
+ }
+ SAFE_FREE(puser);
+ }
+ break;
+
+ case 'A':
+ get_credentials_file(arg);
+ break;
+
+ case 'k':
+#ifndef HAVE_KRB5
+ d_printf("No kerberos support compiled in\n");
+ exit(1);
+#else
+ set_cmdline_auth_info_use_krb5_ticket();
+#endif
+ break;
+
+ case 'S':
+ if (!set_cmdline_auth_info_signing_state(arg)) {
+ fprintf(stderr, "Unknown signing option %s\n", arg );
+ exit(1);
+ }
+ break;
+ case 'P':
+ set_cmdline_auth_info_use_machine_account();
+ break;
+ case 'N':
+ set_cmdline_auth_info_password("");
+ break;
+ case 'e':
+ set_cmdline_auth_info_smb_encrypt();
+ break;
+
+ }
+}
+
+struct poptOption popt_common_credentials[] = {
+ { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE, (void *)popt_common_credentials_callback },
+ { "user", 'U', POPT_ARG_STRING, NULL, 'U', "Set the network username", "USERNAME" },
+ { "no-pass", 'N', POPT_ARG_NONE, NULL, 'N', "Don't ask for a password" },
+ { "kerberos", 'k', POPT_ARG_NONE, NULL, 'k', "Use kerberos (active directory) authentication" },
+ { "authentication-file", 'A', POPT_ARG_STRING, NULL, 'A', "Get the credentials from a file", "FILE" },
+ { "signing", 'S', POPT_ARG_STRING, NULL, 'S', "Set the client signing state", "on|off|required" },
+ {"machine-pass", 'P', POPT_ARG_NONE, NULL, 'P', "Use stored machine account password" },
+ {"encrypt", 'e', POPT_ARG_NONE, NULL, 'e', "Encrypt SMB transport (UNIX extended servers only)" },
+ POPT_TABLEEND
+};
diff --git a/source3/lib/privileges.c b/source3/lib/privileges.c
new file mode 100644
index 0000000000..c1bb783fbc
--- /dev/null
+++ b/source3/lib/privileges.c
@@ -0,0 +1,464 @@
+/*
+ Unix SMB/CIFS implementation.
+ Privileges handling functions
+ Copyright (C) Jean François Micouleau 1998-2001
+ Copyright (C) Simo Sorce 2002-2003
+ Copyright (C) Gerald (Jerry) Carter 2005
+ Copyright (C) Michael Adam 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+
+#define PRIVPREFIX "PRIV_"
+
+typedef struct {
+ size_t count;
+ DOM_SID *list;
+} SID_LIST;
+
+typedef struct {
+ TALLOC_CTX *mem_ctx;
+ SE_PRIV privilege;
+ SID_LIST sids;
+} PRIV_SID_LIST;
+
+
+static bool get_privileges( const DOM_SID *sid, SE_PRIV *mask )
+{
+ struct db_context *db = get_account_pol_db();
+ fstring tmp, keystr;
+ TDB_DATA data;
+
+ /* Fail if the admin has not enable privileges */
+
+ if ( !lp_enable_privileges() ) {
+ return False;
+ }
+
+ if ( db == NULL )
+ return False;
+
+ /* PRIV_<SID> (NULL terminated) as the key */
+
+ fstr_sprintf(keystr, "%s%s", PRIVPREFIX, sid_to_fstring(tmp, sid));
+
+ data = dbwrap_fetch_bystring( db, talloc_tos(), keystr );
+
+ if ( !data.dptr ) {
+ DEBUG(3, ("get_privileges: No privileges assigned to SID "
+ "[%s]\n", sid_string_dbg(sid)));
+ return False;
+ }
+
+ SMB_ASSERT( data.dsize == sizeof( SE_PRIV ) );
+
+ se_priv_copy( mask, (SE_PRIV*)data.dptr );
+ TALLOC_FREE(data.dptr);
+
+ return True;
+}
+
+/***************************************************************************
+ Store the privilege mask (set) for a given SID
+****************************************************************************/
+
+static bool set_privileges( const DOM_SID *sid, SE_PRIV *mask )
+{
+ struct db_context *db = get_account_pol_db();
+ fstring tmp, keystr;
+ TDB_DATA data;
+
+ if ( !lp_enable_privileges() )
+ return False;
+
+ if ( db == NULL )
+ return False;
+
+ if ( !sid || (sid->num_auths == 0) ) {
+ DEBUG(0,("set_privileges: Refusing to store empty SID!\n"));
+ return False;
+ }
+
+ /* PRIV_<SID> (NULL terminated) as the key */
+
+ fstr_sprintf(keystr, "%s%s", PRIVPREFIX, sid_to_fstring(tmp, sid));
+
+ /* no packing. static size structure, just write it out */
+
+ data.dptr = (uint8 *)mask;
+ data.dsize = sizeof(SE_PRIV);
+
+ return NT_STATUS_IS_OK(dbwrap_store_bystring(db, keystr, data,
+ TDB_REPLACE));
+}
+
+/*********************************************************************
+ get a list of all privileges for all sids in the list
+*********************************************************************/
+
+bool get_privileges_for_sids(SE_PRIV *privileges, DOM_SID *slist, int scount)
+{
+ SE_PRIV mask;
+ int i;
+ bool found = False;
+
+ se_priv_copy( privileges, &se_priv_none );
+
+ for ( i=0; i<scount; i++ ) {
+ /* don't add unless we actually have a privilege assigned */
+
+ if ( !get_privileges( &slist[i], &mask ) )
+ continue;
+
+ DEBUG(5,("get_privileges_for_sids: sid = %s\nPrivilege "
+ "set:\n", sid_string_dbg(&slist[i])));
+ dump_se_priv( DBGC_ALL, 5, &mask );
+
+ se_priv_add( privileges, &mask );
+ found = True;
+ }
+
+ return found;
+}
+
+
+/*********************************************************************
+ traversal functions for privilege_enumerate_accounts
+*********************************************************************/
+
+static int priv_traverse_fn(struct db_record *rec, void *state)
+{
+ PRIV_SID_LIST *priv = (PRIV_SID_LIST *)state;
+ int prefixlen = strlen(PRIVPREFIX);
+ DOM_SID sid;
+ fstring sid_string;
+
+ /* easy check first */
+
+ if (rec->value.dsize != sizeof(SE_PRIV) )
+ return 0;
+
+ /* check we have a PRIV_+SID entry */
+
+ if ( strncmp((char *)rec->key.dptr, PRIVPREFIX, prefixlen) != 0)
+ return 0;
+
+ /* check to see if we are looking for a particular privilege */
+
+ if ( !se_priv_equal(&priv->privilege, &se_priv_none) ) {
+ SE_PRIV mask;
+
+ se_priv_copy( &mask, (SE_PRIV*)rec->value.dptr );
+
+ /* if the SID does not have the specified privilege
+ then just return */
+
+ if ( !is_privilege_assigned( &mask, &priv->privilege) )
+ return 0;
+ }
+
+ fstrcpy( sid_string, (char *)&(rec->key.dptr[strlen(PRIVPREFIX)]) );
+
+ /* this is a last ditch safety check to preventing returning
+ and invalid SID (i've somehow run into this on development branches) */
+
+ if ( strcmp( "S-0-0", sid_string ) == 0 )
+ return 0;
+
+ if ( !string_to_sid(&sid, sid_string) ) {
+ DEBUG(0,("travsersal_fn_enum__acct: Could not convert SID [%s]\n",
+ sid_string));
+ return 0;
+ }
+
+ if (!NT_STATUS_IS_OK(add_sid_to_array(priv->mem_ctx, &sid,
+ &priv->sids.list,
+ &priv->sids.count)))
+ {
+ return 0;
+ }
+
+ return 0;
+}
+
+/*********************************************************************
+ Retreive list of privileged SIDs (for _lsa_enumerate_accounts()
+*********************************************************************/
+
+NTSTATUS privilege_enumerate_accounts(DOM_SID **sids, int *num_sids)
+{
+ struct db_context *db = get_account_pol_db();
+ PRIV_SID_LIST priv;
+
+ if (db == NULL) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ ZERO_STRUCT(priv);
+
+ se_priv_copy( &priv.privilege, &se_priv_none );
+
+ db->traverse_read(db, priv_traverse_fn, &priv);
+
+ /* give the memory away; caller will free */
+
+ *sids = priv.sids.list;
+ *num_sids = priv.sids.count;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Retrieve list of SIDs granted a particular privilege
+*********************************************************************/
+
+NTSTATUS privilege_enum_sids(const SE_PRIV *mask, TALLOC_CTX *mem_ctx,
+ DOM_SID **sids, int *num_sids)
+{
+ struct db_context *db = get_account_pol_db();
+ PRIV_SID_LIST priv;
+
+ if (db == NULL) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ ZERO_STRUCT(priv);
+
+ se_priv_copy(&priv.privilege, mask);
+ priv.mem_ctx = mem_ctx;
+
+ db->traverse_read(db, priv_traverse_fn, &priv);
+
+ /* give the memory away; caller will free */
+
+ *sids = priv.sids.list;
+ *num_sids = priv.sids.count;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ Add privilege to sid
+****************************************************************************/
+
+bool grant_privilege(const DOM_SID *sid, const SE_PRIV *priv_mask)
+{
+ SE_PRIV old_mask, new_mask;
+
+ ZERO_STRUCT( old_mask );
+ ZERO_STRUCT( new_mask );
+
+ if ( get_privileges( sid, &old_mask ) )
+ se_priv_copy( &new_mask, &old_mask );
+ else
+ se_priv_copy( &new_mask, &se_priv_none );
+
+ se_priv_add( &new_mask, priv_mask );
+
+ DEBUG(10,("grant_privilege: %s\n", sid_string_dbg(sid)));
+
+ DEBUGADD( 10, ("original privilege mask:\n"));
+ dump_se_priv( DBGC_ALL, 10, &old_mask );
+
+ DEBUGADD( 10, ("new privilege mask:\n"));
+ dump_se_priv( DBGC_ALL, 10, &new_mask );
+
+ return set_privileges( sid, &new_mask );
+}
+
+/*********************************************************************
+ Add a privilege based on its name
+*********************************************************************/
+
+bool grant_privilege_by_name(DOM_SID *sid, const char *name)
+{
+ SE_PRIV mask;
+
+ if (! se_priv_from_name(name, &mask)) {
+ DEBUG(3, ("grant_privilege_by_name: "
+ "No Such Privilege Found (%s)\n", name));
+ return False;
+ }
+
+ return grant_privilege( sid, &mask );
+}
+
+/***************************************************************************
+ Remove privilege from sid
+****************************************************************************/
+
+bool revoke_privilege(const DOM_SID *sid, const SE_PRIV *priv_mask)
+{
+ SE_PRIV mask;
+
+ /* if the user has no privileges, then we can't revoke any */
+
+ if ( !get_privileges( sid, &mask ) )
+ return True;
+
+ DEBUG(10,("revoke_privilege: %s\n", sid_string_dbg(sid)));
+
+ DEBUGADD( 10, ("original privilege mask:\n"));
+ dump_se_priv( DBGC_ALL, 10, &mask );
+
+ se_priv_remove( &mask, priv_mask );
+
+ DEBUGADD( 10, ("new privilege mask:\n"));
+ dump_se_priv( DBGC_ALL, 10, &mask );
+
+ return set_privileges( sid, &mask );
+}
+
+/*********************************************************************
+ Revoke all privileges
+*********************************************************************/
+
+bool revoke_all_privileges( DOM_SID *sid )
+{
+ return revoke_privilege( sid, &se_priv_all );
+}
+
+/*********************************************************************
+ Add a privilege based on its name
+*********************************************************************/
+
+bool revoke_privilege_by_name(DOM_SID *sid, const char *name)
+{
+ SE_PRIV mask;
+
+ if (! se_priv_from_name(name, &mask)) {
+ DEBUG(3, ("revoke_privilege_by_name: "
+ "No Such Privilege Found (%s)\n", name));
+ return False;
+ }
+
+ return revoke_privilege(sid, &mask);
+
+}
+
+/***************************************************************************
+ Retrieve the SIDs assigned to a given privilege
+****************************************************************************/
+
+NTSTATUS privilege_create_account(const DOM_SID *sid )
+{
+ return ( grant_privilege(sid, &se_priv_none) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL);
+}
+
+/****************************************************************************
+ initialise a privilege list and set the talloc context
+ ****************************************************************************/
+
+NTSTATUS privilege_set_init(PRIVILEGE_SET *priv_set)
+{
+ TALLOC_CTX *mem_ctx;
+
+ ZERO_STRUCTP( priv_set );
+
+ mem_ctx = talloc_init("privilege set");
+ if ( !mem_ctx ) {
+ DEBUG(0,("privilege_set_init: failed to initialize talloc ctx!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ priv_set->mem_ctx = mem_ctx;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ initialise a privilege list and with someone else's talloc context
+****************************************************************************/
+
+NTSTATUS privilege_set_init_by_ctx(TALLOC_CTX *mem_ctx, PRIVILEGE_SET *priv_set)
+{
+ ZERO_STRUCTP( priv_set );
+
+ priv_set->mem_ctx = mem_ctx;
+ priv_set->ext_ctx = True;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Free all memory used by a PRIVILEGE_SET
+****************************************************************************/
+
+void privilege_set_free(PRIVILEGE_SET *priv_set)
+{
+ if ( !priv_set )
+ return;
+
+ if ( !( priv_set->ext_ctx ) )
+ talloc_destroy( priv_set->mem_ctx );
+
+ ZERO_STRUCTP( priv_set );
+}
+
+/****************************************************************************
+ duplicate alloc luid_attr
+ ****************************************************************************/
+
+NTSTATUS dup_luid_attr(TALLOC_CTX *mem_ctx, LUID_ATTR **new_la, LUID_ATTR *old_la, int count)
+{
+ int i;
+
+ if ( !old_la )
+ return NT_STATUS_OK;
+
+ if (count) {
+ *new_la = TALLOC_ARRAY(mem_ctx, LUID_ATTR, count);
+ if ( !*new_la ) {
+ DEBUG(0,("dup_luid_attr: failed to alloc new LUID_ATTR array [%d]\n", count));
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ *new_la = NULL;
+ }
+
+ for (i=0; i<count; i++) {
+ (*new_la)[i].luid.high = old_la[i].luid.high;
+ (*new_la)[i].luid.low = old_la[i].luid.low;
+ (*new_la)[i].attr = old_la[i].attr;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+bool is_privileged_sid( const DOM_SID *sid )
+{
+ SE_PRIV mask;
+
+ return get_privileges( sid, &mask );
+}
+
+/*******************************************************************
+*******************************************************************/
+
+bool grant_all_privileges( const DOM_SID *sid )
+{
+ SE_PRIV mask;
+
+ if (!se_priv_put_all_privileges(&mask)) {
+ return False;
+ }
+
+ return grant_privilege( sid, &mask );
+}
diff --git a/source3/lib/privileges_basic.c b/source3/lib/privileges_basic.c
new file mode 100644
index 0000000000..865c1f655c
--- /dev/null
+++ b/source3/lib/privileges_basic.c
@@ -0,0 +1,515 @@
+/*
+ Unix SMB/CIFS implementation.
+ Privileges handling functions
+ Copyright (C) Jean François Micouleau 1998-2001
+ Copyright (C) Simo Sorce 2002-2003
+ Copyright (C) Gerald (Jerry) Carter 2005
+ Copyright (C) Michael Adam 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Basic privileges functions (mask-operations and conversion
+ * functions between the different formats (se_priv, privset, luid)
+ * moved here * from lib/privileges.c to minimize linker deps.
+ *
+ * generally SID- and LUID-related code is left in lib/privileges.c
+ *
+ * some extra functions to hide privs array from lib/privileges.c
+ */
+
+#include "includes.h"
+
+const SE_PRIV se_priv_all = SE_ALL_PRIVS;
+static const SE_PRIV se_priv_end = SE_END;
+
+/* Define variables for all privileges so we can use the
+ SE_PRIV* in the various se_priv_XXX() functions */
+
+const SE_PRIV se_priv_none = SE_NONE;
+const SE_PRIV se_machine_account = SE_MACHINE_ACCOUNT;
+const SE_PRIV se_print_operator = SE_PRINT_OPERATOR;
+const SE_PRIV se_add_users = SE_ADD_USERS;
+const SE_PRIV se_disk_operators = SE_DISK_OPERATOR;
+const SE_PRIV se_remote_shutdown = SE_REMOTE_SHUTDOWN;
+const SE_PRIV se_restore = SE_RESTORE;
+const SE_PRIV se_take_ownership = SE_TAKE_OWNERSHIP;
+
+/********************************************************************
+ This is a list of privileges reported by a WIndows 2000 SP4 AD DC
+ just for reference purposes (and I know the LUID is not guaranteed
+ across reboots):
+
+ SeCreateTokenPrivilege Create a token object ( 0x0, 0x2 )
+ SeAssignPrimaryTokenPrivilege Replace a process level token ( 0x0, 0x3 )
+ SeLockMemoryPrivilege Lock pages in memory ( 0x0, 0x4 )
+ SeIncreaseQuotaPrivilege Increase quotas ( 0x0, 0x5 )
+ SeMachineAccountPrivilege Add workstations to domain ( 0x0, 0x6 )
+ SeTcbPrivilege Act as part of the operating system ( 0x0, 0x7 )
+ SeSecurityPrivilege Manage auditing and security log ( 0x0, 0x8 )
+ SeTakeOwnershipPrivilege Take ownership of files or other objects ( 0x0, 0x9 )
+ SeLoadDriverPrivilege Load and unload device drivers ( 0x0, 0xa )
+ SeSystemProfilePrivilege Profile system performance ( 0x0, 0xb )
+ SeSystemtimePrivilege Change the system time ( 0x0, 0xc )
+ SeProfileSingleProcessPrivilege Profile single process ( 0x0, 0xd )
+ SeIncreaseBasePriorityPrivilege Increase scheduling priority ( 0x0, 0xe )
+ SeCreatePagefilePrivilege Create a pagefile ( 0x0, 0xf )
+ SeCreatePermanentPrivilege Create permanent shared objects ( 0x0, 0x10 )
+ SeBackupPrivilege Back up files and directories ( 0x0, 0x11 )
+ SeRestorePrivilege Restore files and directories ( 0x0, 0x12 )
+ SeShutdownPrivilege Shut down the system ( 0x0, 0x13 )
+ SeDebugPrivilege Debug programs ( 0x0, 0x14 )
+ SeAuditPrivilege Generate security audits ( 0x0, 0x15 )
+ SeSystemEnvironmentPrivilege Modify firmware environment values ( 0x0, 0x16 )
+ SeChangeNotifyPrivilege Bypass traverse checking ( 0x0, 0x17 )
+ SeRemoteShutdownPrivilege Force shutdown from a remote system ( 0x0, 0x18 )
+ SeUndockPrivilege Remove computer from docking station ( 0x0, 0x19 )
+ SeSyncAgentPrivilege Synchronize directory service data ( 0x0, 0x1a )
+ SeEnableDelegationPrivilege Enable computer and user accounts to be trusted for delegation ( 0x0, 0x1b )
+ SeManageVolumePrivilege Perform volume maintenance tasks ( 0x0, 0x1c )
+ SeImpersonatePrivilege Impersonate a client after authentication ( 0x0, 0x1d )
+ SeCreateGlobalPrivilege Create global objects ( 0x0, 0x1e )
+
+ ********************************************************************/
+
+/* we have to define the LUID here due to a horrible check by printmig.exe
+ that requires the SeBackupPrivilege match what is in Windows. So match
+ those that we implement and start Samba privileges at 0x1001 */
+
+PRIVS privs[] = {
+#if 0 /* usrmgr will display these twice if you include them. We don't
+ use them but we'll keep the bitmasks reserved in privileges.h anyways */
+
+ {SE_NETWORK_LOGON, "SeNetworkLogonRight", "Access this computer from network", { 0x0, 0x0 }},
+ {SE_INTERACTIVE_LOGON, "SeInteractiveLogonRight", "Log on locally", { 0x0, 0x0 }},
+ {SE_BATCH_LOGON, "SeBatchLogonRight", "Log on as a batch job", { 0x0, 0x0 }},
+ {SE_SERVICE_LOGON, "SeServiceLogonRight", "Log on as a service", { 0x0, 0x0 }},
+#endif
+ {SE_MACHINE_ACCOUNT, "SeMachineAccountPrivilege", "Add machines to domain", { 0x0, 0x0006 }},
+ {SE_TAKE_OWNERSHIP, "SeTakeOwnershipPrivilege", "Take ownership of files or other objects",{ 0x0, 0x0009 }},
+ {SE_BACKUP, "SeBackupPrivilege", "Back up files and directories", { 0x0, 0x0011 }},
+ {SE_RESTORE, "SeRestorePrivilege", "Restore files and directories", { 0x0, 0x0012 }},
+ {SE_REMOTE_SHUTDOWN, "SeRemoteShutdownPrivilege", "Force shutdown from a remote system", { 0x0, 0x0018 }},
+
+ {SE_PRINT_OPERATOR, "SePrintOperatorPrivilege", "Manage printers", { 0x0, 0x1001 }},
+ {SE_ADD_USERS, "SeAddUsersPrivilege", "Add users and groups to the domain", { 0x0, 0x1002 }},
+ {SE_DISK_OPERATOR, "SeDiskOperatorPrivilege", "Manage disk shares", { 0x0, 0x1003 }},
+
+ {SE_END, "", "", { 0x0, 0x0 }}
+};
+
+/***************************************************************************
+ copy an SE_PRIV structure
+****************************************************************************/
+
+bool se_priv_copy( SE_PRIV *dst, const SE_PRIV *src )
+{
+ if ( !dst || !src )
+ return False;
+
+ memcpy( dst, src, sizeof(SE_PRIV) );
+
+ return True;
+}
+
+/***************************************************************************
+ put all privileges into a mask
+****************************************************************************/
+
+bool se_priv_put_all_privileges(SE_PRIV *mask)
+{
+ int i;
+ uint32 num_privs = count_all_privileges();
+
+ if (!se_priv_copy(mask, &se_priv_none)) {
+ return False;
+ }
+ for ( i=0; i<num_privs; i++ ) {
+ se_priv_add(mask, &privs[i].se_priv);
+ }
+ return True;
+}
+
+/***************************************************************************
+ combine 2 SE_PRIV structures and store the resulting set in mew_mask
+****************************************************************************/
+
+void se_priv_add( SE_PRIV *mask, const SE_PRIV *addpriv )
+{
+ int i;
+
+ for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
+ mask->mask[i] |= addpriv->mask[i];
+ }
+}
+
+/***************************************************************************
+ remove one SE_PRIV sytucture from another and store the resulting set
+ in mew_mask
+****************************************************************************/
+
+void se_priv_remove( SE_PRIV *mask, const SE_PRIV *removepriv )
+{
+ int i;
+
+ for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
+ mask->mask[i] &= ~removepriv->mask[i];
+ }
+}
+
+/***************************************************************************
+ invert a given SE_PRIV and store the set in new_mask
+****************************************************************************/
+
+static void se_priv_invert( SE_PRIV *new_mask, const SE_PRIV *mask )
+{
+ SE_PRIV allprivs;
+
+ se_priv_copy( &allprivs, &se_priv_all );
+ se_priv_remove( &allprivs, mask );
+ se_priv_copy( new_mask, &allprivs );
+}
+
+/***************************************************************************
+ check if 2 SE_PRIV structure are equal
+****************************************************************************/
+
+bool se_priv_equal( const SE_PRIV *mask1, const SE_PRIV *mask2 )
+{
+ return ( memcmp(mask1, mask2, sizeof(SE_PRIV)) == 0 );
+}
+
+/***************************************************************************
+ check if a SE_PRIV has any assigned privileges
+****************************************************************************/
+
+static bool se_priv_empty( const SE_PRIV *mask )
+{
+ SE_PRIV p1;
+ int i;
+
+ se_priv_copy( &p1, mask );
+
+ for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
+ p1.mask[i] &= se_priv_all.mask[i];
+ }
+
+ return se_priv_equal( &p1, &se_priv_none );
+}
+
+/*********************************************************************
+ Lookup the SE_PRIV value for a privilege name
+*********************************************************************/
+
+bool se_priv_from_name( const char *name, SE_PRIV *mask )
+{
+ int i;
+
+ for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
+ if ( strequal( privs[i].name, name ) ) {
+ se_priv_copy( mask, &privs[i].se_priv );
+ return True;
+ }
+ }
+
+ return False;
+}
+
+/***************************************************************************
+ dump an SE_PRIV structure to the log files
+****************************************************************************/
+
+void dump_se_priv( int dbg_cl, int dbg_lvl, const SE_PRIV *mask )
+{
+ int i;
+
+ DEBUGADDC( dbg_cl, dbg_lvl,("SE_PRIV "));
+
+ for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
+ DEBUGADDC( dbg_cl, dbg_lvl,(" 0x%x", mask->mask[i] ));
+ }
+
+ DEBUGADDC( dbg_cl, dbg_lvl, ("\n"));
+}
+
+/****************************************************************************
+ check if the privilege is in the privilege list
+****************************************************************************/
+
+bool is_privilege_assigned(const SE_PRIV *privileges,
+ const SE_PRIV *check)
+{
+ SE_PRIV p1, p2;
+
+ if ( !privileges || !check )
+ return False;
+
+ /* everyone has privileges if you aren't checking for any */
+
+ if ( se_priv_empty( check ) ) {
+ DEBUG(1,("is_privilege_assigned: no privileges in check_mask!\n"));
+ return True;
+ }
+
+ se_priv_copy( &p1, check );
+
+ /* invert the SE_PRIV we want to check for and remove that from the
+ original set. If we are left with the SE_PRIV we are checking
+ for then return True */
+
+ se_priv_invert( &p1, check );
+ se_priv_copy( &p2, privileges );
+ se_priv_remove( &p2, &p1 );
+
+ return se_priv_equal( &p2, check );
+}
+
+/****************************************************************************
+ check if the privilege is in the privilege list
+****************************************************************************/
+
+static bool is_any_privilege_assigned( SE_PRIV *privileges, const SE_PRIV *check )
+{
+ SE_PRIV p1, p2;
+
+ if ( !privileges || !check )
+ return False;
+
+ /* everyone has privileges if you aren't checking for any */
+
+ if ( se_priv_empty( check ) ) {
+ DEBUG(1,("is_any_privilege_assigned: no privileges in check_mask!\n"));
+ return True;
+ }
+
+ se_priv_copy( &p1, check );
+
+ /* invert the SE_PRIV we want to check for and remove that from the
+ original set. If we are left with the SE_PRIV we are checking
+ for then return True */
+
+ se_priv_invert( &p1, check );
+ se_priv_copy( &p2, privileges );
+ se_priv_remove( &p2, &p1 );
+
+ /* see if we have any bits left */
+
+ return !se_priv_empty( &p2 );
+}
+
+/*********************************************************************
+ Generate the LUID_ATTR structure based on a bitmask
+*********************************************************************/
+
+const char* get_privilege_dispname( const char *name )
+{
+ int i;
+
+ if (!name) {
+ return NULL;
+ }
+
+ for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
+
+ if ( strequal( privs[i].name, name ) ) {
+ return privs[i].description;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ initialise a privilege list and set the talloc context
+ ****************************************************************************/
+
+/****************************************************************************
+ Does the user have the specified privilege ? We only deal with one privilege
+ at a time here.
+*****************************************************************************/
+
+bool user_has_privileges(const NT_USER_TOKEN *token, const SE_PRIV *privilege)
+{
+ if ( !token )
+ return False;
+
+ return is_privilege_assigned( &token->privileges, privilege );
+}
+
+/****************************************************************************
+ Does the user have any of the specified privileges ? We only deal with one privilege
+ at a time here.
+*****************************************************************************/
+
+bool user_has_any_privilege(NT_USER_TOKEN *token, const SE_PRIV *privilege)
+{
+ if ( !token )
+ return False;
+
+ return is_any_privilege_assigned( &token->privileges, privilege );
+}
+
+/*******************************************************************
+ return the number of elements in the privlege array
+*******************************************************************/
+
+int count_all_privileges( void )
+{
+ /*
+ * The -1 is due to the weird SE_END record...
+ */
+ return (sizeof(privs) / sizeof(privs[0])) - 1;
+}
+
+
+/*********************************************************************
+ Generate the LUID_ATTR structure based on a bitmask
+ The assumption here is that the privilege has already been validated
+ so we are guaranteed to find it in the list.
+*********************************************************************/
+
+LUID_ATTR get_privilege_luid( SE_PRIV *mask )
+{
+ LUID_ATTR priv_luid;
+ int i;
+
+ ZERO_STRUCT( priv_luid );
+
+ for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
+
+ if ( se_priv_equal( &privs[i].se_priv, mask ) ) {
+ priv_luid.luid = privs[i].luid;
+ break;
+ }
+ }
+
+ return priv_luid;
+}
+
+/****************************************************************************
+ Convert a LUID to a named string
+****************************************************************************/
+
+const char *luid_to_privilege_name(const LUID *set)
+{
+ int i;
+
+ if (set->high != 0)
+ return NULL;
+
+ for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
+ if ( set->low == privs[i].luid.low ) {
+ return privs[i].name;
+ }
+ }
+
+ return NULL;
+}
+
+
+/****************************************************************************
+ add a privilege to a privilege array
+ ****************************************************************************/
+
+static bool privilege_set_add(PRIVILEGE_SET *priv_set, LUID_ATTR set)
+{
+ LUID_ATTR *new_set;
+
+ /* we can allocate memory to add the new privilege */
+
+ new_set = TALLOC_REALLOC_ARRAY(priv_set->mem_ctx, priv_set->set, LUID_ATTR, priv_set->count + 1);
+ if ( !new_set ) {
+ DEBUG(0,("privilege_set_add: failed to allocate memory!\n"));
+ return False;
+ }
+
+ new_set[priv_set->count].luid.high = set.luid.high;
+ new_set[priv_set->count].luid.low = set.luid.low;
+ new_set[priv_set->count].attr = set.attr;
+
+ priv_set->count++;
+ priv_set->set = new_set;
+
+ return True;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+bool se_priv_to_privilege_set( PRIVILEGE_SET *set, SE_PRIV *mask )
+{
+ int i;
+ uint32 num_privs = count_all_privileges();
+ LUID_ATTR luid;
+
+ luid.attr = 0;
+ luid.luid.high = 0;
+
+ for ( i=0; i<num_privs; i++ ) {
+ if ( !is_privilege_assigned(mask, &privs[i].se_priv) )
+ continue;
+
+ luid.luid = privs[i].luid;
+
+ if ( !privilege_set_add( set, luid ) )
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool luid_to_se_priv( struct lsa_LUID *luid, SE_PRIV *mask )
+{
+ int i;
+ uint32 num_privs = count_all_privileges();
+
+ for ( i=0; i<num_privs; i++ ) {
+ if ( luid->low == privs[i].luid.low ) {
+ se_priv_copy( mask, &privs[i].se_priv );
+ return True;
+ }
+ }
+
+ return False;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+bool privilege_set_to_se_priv( SE_PRIV *mask, struct lsa_PrivilegeSet *privset )
+{
+ int i;
+
+ ZERO_STRUCTP( mask );
+
+ for ( i=0; i<privset->count; i++ ) {
+ SE_PRIV r;
+
+ /* sanity check for invalid privilege. we really
+ only care about the low 32 bits */
+
+ if ( privset->set[i].luid.high != 0 )
+ return False;
+
+ if ( luid_to_se_priv( &privset->set[i].luid, &r ) )
+ se_priv_add( mask, &r );
+ }
+
+ return True;
+}
+
diff --git a/source3/lib/rbtree.c b/source3/lib/rbtree.c
new file mode 100644
index 0000000000..f6868cab5d
--- /dev/null
+++ b/source3/lib/rbtree.c
@@ -0,0 +1,422 @@
+/*
+ Red Black Trees
+ (C) 1999 Andrea Arcangeli <andrea@suse.de>
+ (C) 2002 David Woodhouse <dwmw2@infradead.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ linux/lib/rbtree.c
+*/
+
+#include "includes.h"
+#include "rbtree.h"
+
+#define RB_RED 0
+#define RB_BLACK 1
+
+#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
+#define rb_color(r) ((r)->rb_parent_color & 1)
+#define rb_is_red(r) (!rb_color(r))
+#define rb_is_black(r) rb_color(r)
+#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
+#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
+
+static void rb_set_parent(struct rb_node *rb, struct rb_node *p)
+{
+ rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
+}
+static void rb_set_color(struct rb_node *rb, int color)
+{
+ rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
+}
+
+#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
+#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
+#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
+
+static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *right = node->rb_right;
+ struct rb_node *parent = rb_parent(node);
+
+ if ((node->rb_right = right->rb_left))
+ rb_set_parent(right->rb_left, node);
+ right->rb_left = node;
+
+ rb_set_parent(right, parent);
+
+ if (parent)
+ {
+ if (node == parent->rb_left)
+ parent->rb_left = right;
+ else
+ parent->rb_right = right;
+ }
+ else
+ root->rb_node = right;
+ rb_set_parent(node, right);
+}
+
+static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *left = node->rb_left;
+ struct rb_node *parent = rb_parent(node);
+
+ if ((node->rb_left = left->rb_right))
+ rb_set_parent(left->rb_right, node);
+ left->rb_right = node;
+
+ rb_set_parent(left, parent);
+
+ if (parent)
+ {
+ if (node == parent->rb_right)
+ parent->rb_right = left;
+ else
+ parent->rb_left = left;
+ }
+ else
+ root->rb_node = left;
+ rb_set_parent(node, left);
+}
+
+void rb_insert_color(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *parent, *gparent;
+
+ while ((parent = rb_parent(node)) && rb_is_red(parent))
+ {
+ gparent = rb_parent(parent);
+
+ if (parent == gparent->rb_left)
+ {
+ {
+ register struct rb_node *uncle = gparent->rb_right;
+ if (uncle && rb_is_red(uncle))
+ {
+ rb_set_black(uncle);
+ rb_set_black(parent);
+ rb_set_red(gparent);
+ node = gparent;
+ continue;
+ }
+ }
+
+ if (parent->rb_right == node)
+ {
+ register struct rb_node *tmp;
+ __rb_rotate_left(parent, root);
+ tmp = parent;
+ parent = node;
+ node = tmp;
+ }
+
+ rb_set_black(parent);
+ rb_set_red(gparent);
+ __rb_rotate_right(gparent, root);
+ } else {
+ {
+ register struct rb_node *uncle = gparent->rb_left;
+ if (uncle && rb_is_red(uncle))
+ {
+ rb_set_black(uncle);
+ rb_set_black(parent);
+ rb_set_red(gparent);
+ node = gparent;
+ continue;
+ }
+ }
+
+ if (parent->rb_left == node)
+ {
+ register struct rb_node *tmp;
+ __rb_rotate_right(parent, root);
+ tmp = parent;
+ parent = node;
+ node = tmp;
+ }
+
+ rb_set_black(parent);
+ rb_set_red(gparent);
+ __rb_rotate_left(gparent, root);
+ }
+ }
+
+ rb_set_black(root->rb_node);
+}
+
+static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
+ struct rb_root *root)
+{
+ struct rb_node *other;
+
+ while ((!node || rb_is_black(node)) && node != root->rb_node)
+ {
+ if (parent->rb_left == node)
+ {
+ other = parent->rb_right;
+ if (rb_is_red(other))
+ {
+ rb_set_black(other);
+ rb_set_red(parent);
+ __rb_rotate_left(parent, root);
+ other = parent->rb_right;
+ }
+ if ((!other->rb_left || rb_is_black(other->rb_left)) &&
+ (!other->rb_right || rb_is_black(other->rb_right)))
+ {
+ rb_set_red(other);
+ node = parent;
+ parent = rb_parent(node);
+ }
+ else
+ {
+ if (!other->rb_right || rb_is_black(other->rb_right))
+ {
+ struct rb_node *o_left;
+ if ((o_left = other->rb_left))
+ rb_set_black(o_left);
+ rb_set_red(other);
+ __rb_rotate_right(other, root);
+ other = parent->rb_right;
+ }
+ rb_set_color(other, rb_color(parent));
+ rb_set_black(parent);
+ if (other->rb_right)
+ rb_set_black(other->rb_right);
+ __rb_rotate_left(parent, root);
+ node = root->rb_node;
+ break;
+ }
+ }
+ else
+ {
+ other = parent->rb_left;
+ if (rb_is_red(other))
+ {
+ rb_set_black(other);
+ rb_set_red(parent);
+ __rb_rotate_right(parent, root);
+ other = parent->rb_left;
+ }
+ if ((!other->rb_left || rb_is_black(other->rb_left)) &&
+ (!other->rb_right || rb_is_black(other->rb_right)))
+ {
+ rb_set_red(other);
+ node = parent;
+ parent = rb_parent(node);
+ }
+ else
+ {
+ if (!other->rb_left || rb_is_black(other->rb_left))
+ {
+ register struct rb_node *o_right;
+ if ((o_right = other->rb_right))
+ rb_set_black(o_right);
+ rb_set_red(other);
+ __rb_rotate_left(other, root);
+ other = parent->rb_left;
+ }
+ rb_set_color(other, rb_color(parent));
+ rb_set_black(parent);
+ if (other->rb_left)
+ rb_set_black(other->rb_left);
+ __rb_rotate_right(parent, root);
+ node = root->rb_node;
+ break;
+ }
+ }
+ }
+ if (node)
+ rb_set_black(node);
+}
+
+void rb_erase(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *child, *parent;
+ int color;
+
+ if (!node->rb_left)
+ child = node->rb_right;
+ else if (!node->rb_right)
+ child = node->rb_left;
+ else
+ {
+ struct rb_node *old = node, *left;
+
+ node = node->rb_right;
+ while ((left = node->rb_left) != NULL)
+ node = left;
+ child = node->rb_right;
+ parent = rb_parent(node);
+ color = rb_color(node);
+
+ if (child)
+ rb_set_parent(child, parent);
+ if (parent == old) {
+ parent->rb_right = child;
+ parent = node;
+ } else
+ parent->rb_left = child;
+
+ node->rb_parent_color = old->rb_parent_color;
+ node->rb_right = old->rb_right;
+ node->rb_left = old->rb_left;
+
+ if (rb_parent(old))
+ {
+ if (rb_parent(old)->rb_left == old)
+ rb_parent(old)->rb_left = node;
+ else
+ rb_parent(old)->rb_right = node;
+ } else
+ root->rb_node = node;
+
+ rb_set_parent(old->rb_left, node);
+ if (old->rb_right)
+ rb_set_parent(old->rb_right, node);
+ goto color;
+ }
+
+ parent = rb_parent(node);
+ color = rb_color(node);
+
+ if (child)
+ rb_set_parent(child, parent);
+ if (parent)
+ {
+ if (parent->rb_left == node)
+ parent->rb_left = child;
+ else
+ parent->rb_right = child;
+ }
+ else
+ root->rb_node = child;
+
+ color:
+ if (color == RB_BLACK)
+ __rb_erase_color(child, parent, root);
+}
+
+/*
+ * This function returns the first node (in sort order) of the tree.
+ */
+struct rb_node *rb_first(struct rb_root *root)
+{
+ struct rb_node *n;
+
+ n = root->rb_node;
+ if (!n)
+ return NULL;
+ while (n->rb_left)
+ n = n->rb_left;
+ return n;
+}
+
+struct rb_node *rb_last(struct rb_root *root)
+{
+ struct rb_node *n;
+
+ n = root->rb_node;
+ if (!n)
+ return NULL;
+ while (n->rb_right)
+ n = n->rb_right;
+ return n;
+}
+
+struct rb_node *rb_next(struct rb_node *node)
+{
+ struct rb_node *parent;
+
+ if (rb_parent(node) == node)
+ return NULL;
+
+ /* If we have a right-hand child, go down and then left as far
+ as we can. */
+ if (node->rb_right) {
+ node = node->rb_right;
+ while (node->rb_left)
+ node=node->rb_left;
+ return node;
+ }
+
+ /* No right-hand children. Everything down and left is
+ smaller than us, so any 'next' node must be in the general
+ direction of our parent. Go up the tree; any time the
+ ancestor is a right-hand child of its parent, keep going
+ up. First time it's a left-hand child of its parent, said
+ parent is our 'next' node. */
+ while ((parent = rb_parent(node)) && node == parent->rb_right)
+ node = parent;
+
+ return parent;
+}
+
+struct rb_node *rb_prev(struct rb_node *node)
+{
+ struct rb_node *parent;
+
+ if (rb_parent(node) == node)
+ return NULL;
+
+ /* If we have a left-hand child, go down and then right as far
+ as we can. */
+ if (node->rb_left) {
+ node = node->rb_left;
+ while (node->rb_right)
+ node=node->rb_right;
+ return node;
+ }
+
+ /* No left-hand children. Go up till we find an ancestor which
+ is a right-hand child of its parent */
+ while ((parent = rb_parent(node)) && node == parent->rb_left)
+ node = parent;
+
+ return parent;
+}
+
+void rb_replace_node(struct rb_node *victim, struct rb_node *new_node,
+ struct rb_root *root)
+{
+ struct rb_node *parent = rb_parent(victim);
+
+ /* Set the surrounding nodes to point to the replacement */
+ if (parent) {
+ if (victim == parent->rb_left)
+ parent->rb_left = new_node;
+ else
+ parent->rb_right = new_node;
+ } else {
+ root->rb_node = new_node;
+ }
+ if (victim->rb_left)
+ rb_set_parent(victim->rb_left, new_node);
+ if (victim->rb_right)
+ rb_set_parent(victim->rb_right, new_node);
+
+ /* Copy the pointers/colour from the victim to the replacement */
+ *new_node = *victim;
+}
+
+void rb_link_node(struct rb_node * node, struct rb_node * parent,
+ struct rb_node ** rb_link)
+{
+ node->rb_parent_color = (unsigned long )parent;
+ node->rb_left = node->rb_right = NULL;
+
+ *rb_link = node;
+}
diff --git a/source3/lib/readline.c b/source3/lib/readline.c
new file mode 100644
index 0000000000..254f55c86a
--- /dev/null
+++ b/source3/lib/readline.c
@@ -0,0 +1,181 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba readline wrapper implementation
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#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
+
+#ifdef HAVE_NEW_LIBREADLINE
+# define RL_COMPLETION_CAST (rl_completion_func_t *)
+#else
+/* This type is missing from libreadline<4.0 (approximately) */
+# define RL_COMPLETION_CAST
+#endif /* HAVE_NEW_LIBREADLINE */
+
+/****************************************************************************
+ Display the prompt and wait for input. Call callback() regularly
+****************************************************************************/
+
+static char *smb_readline_replacement(const char *prompt, void (*callback)(void),
+ char **(completion_fn)(const char *text, int start, int end))
+{
+ fd_set fds;
+ char *line = NULL;
+ struct timeval timeout;
+ int fd = x_fileno(x_stdin);
+ char *ret;
+
+ /* Prompt might be NULL in non-interactive mode. */
+ if (prompt) {
+ x_fprintf(x_stdout, "%s", prompt);
+ x_fflush(x_stdout);
+ }
+
+ line = (char *)SMB_MALLOC(BUFSIZ);
+ if (!line) {
+ return NULL;
+ }
+
+ while (1) {
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+
+ FD_ZERO(&fds);
+ FD_SET(fd,&fds);
+
+ if (sys_select_intr(fd+1,&fds,NULL,NULL,&timeout) == 1) {
+ ret = x_fgets(line, BUFSIZ, x_stdin);
+ if (ret == 0) {
+ SAFE_FREE(line);
+ }
+ return ret;
+ }
+ if (callback) {
+ callback();
+ }
+ }
+}
+
+/****************************************************************************
+ Display the prompt and wait for input. Call callback() regularly.
+****************************************************************************/
+
+char *smb_readline(const char *prompt, void (*callback)(void),
+ char **(completion_fn)(const char *text, int start, int end))
+{
+ char *ret;
+ bool interactive;
+
+ interactive = isatty(x_fileno(x_stdin)) || getenv("CLI_FORCE_INTERACTIVE");
+ if (!interactive) {
+ return smb_readline_replacement(NULL, callback, completion_fn);
+ }
+
+#if HAVE_LIBREADLINE
+
+ /* Aargh! Readline does bizzare things with the terminal width
+ that mucks up expect(1). Set CLI_NO_READLINE in the environment
+ to force readline not to be used. */
+
+ if (getenv("CLI_NO_READLINE"))
+ return smb_readline_replacement(prompt, callback, completion_fn);
+
+ if (completion_fn) {
+ /* The callback prototype has changed slightly between
+ different versions of Readline, so the same function
+ works in all of them to date, but we get compiler
+ warnings in some. */
+ rl_attempted_completion_function = RL_COMPLETION_CAST completion_fn;
+ }
+
+#if HAVE_DECL_RL_EVENT_HOOK
+ if (callback)
+ rl_event_hook = (Function *)callback;
+#endif
+ ret = readline(prompt);
+ if (ret && *ret)
+ add_history(ret);
+
+#else
+ ret = smb_readline_replacement(prompt, callback, completion_fn);
+#endif
+
+ return ret;
+}
+
+/****************************************************************************
+ * return line buffer text
+ ****************************************************************************/
+const char *smb_readline_get_line_buffer(void)
+{
+#if defined(HAVE_LIBREADLINE)
+ return rl_line_buffer;
+#else
+ return NULL;
+#endif
+}
+
+
+/****************************************************************************
+ * set completion append character
+ ***************************************************************************/
+void smb_readline_ca_char(char c)
+{
+#if defined(HAVE_LIBREADLINE)
+ rl_completion_append_character = c;
+#endif
+}
+
+/****************************************************************************
+history
+****************************************************************************/
+int cmd_history(void)
+{
+#if defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_LIST)
+ HIST_ENTRY **hlist;
+ int i;
+
+ hlist = history_list();
+
+ for (i = 0; hlist && hlist[i]; i++) {
+ DEBUG(0, ("%d: %s\n", i, hlist[i]->line));
+ }
+#else
+ DEBUG(0,("no history without readline support\n"));
+#endif
+
+ return 0;
+}
diff --git a/source3/lib/recvfile.c b/source3/lib/recvfile.c
new file mode 100644
index 0000000000..513742ce8f
--- /dev/null
+++ b/source3/lib/recvfile.c
@@ -0,0 +1,233 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.2.x
+ recvfile implementations.
+ Copyright (C) Jeremy Allison 2007.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * This file handles the OS dependent recvfile implementations.
+ * The API is such that it returns -1 on error, else returns the
+ * number of bytes written.
+ */
+
+#include "includes.h"
+
+/* Do this on our own in TRANSFER_BUF_SIZE chunks.
+ * It's safe to make direct syscalls to lseek/write here
+ * as we're below the Samba vfs layer.
+ *
+ * If tofd is -1 we just drain the incoming socket of count
+ * bytes without writing to the outgoing fd.
+ * If a write fails we do the same (to cope with disk full)
+ * errors.
+ *
+ * Returns -1 on short reads from fromfd (read error)
+ * and sets errno.
+ *
+ * Returns number of bytes written to 'tofd'
+ * or thrown away if 'tofd == -1'.
+ * return != count then sets errno.
+ * Returns count if complete success.
+ */
+
+#ifndef TRANSFER_BUF_SIZE
+#define TRANSFER_BUF_SIZE (128*1024)
+#endif
+
+static ssize_t default_sys_recvfile(int fromfd,
+ int tofd,
+ SMB_OFF_T offset,
+ size_t count)
+{
+ int saved_errno = 0;
+ size_t total = 0;
+ size_t bufsize = MIN(TRANSFER_BUF_SIZE,count);
+ size_t total_written = 0;
+ char *buffer = NULL;
+
+ DEBUG(10,("default_sys_recvfile: from = %d, to = %d, "
+ "offset=%.0f, count = %lu\n",
+ fromfd, tofd, (double)offset,
+ (unsigned long)count));
+
+ if (count == 0) {
+ return 0;
+ }
+
+ if (tofd != -1 && offset != (SMB_OFF_T)-1) {
+ if (sys_lseek(tofd, offset, SEEK_SET) == -1) {
+ if (errno != ESPIPE) {
+ return -1;
+ }
+ }
+ }
+
+ buffer = SMB_MALLOC_ARRAY(char, bufsize);
+ if (buffer == NULL) {
+ return -1;
+ }
+
+ while (total < count) {
+ size_t num_written = 0;
+ ssize_t read_ret;
+ size_t toread = MIN(bufsize,count - total);
+
+ /* Read from socket - ignore EINTR. */
+ read_ret = sys_read(fromfd, buffer, toread);
+ if (read_ret <= 0) {
+ /* EOF or socket error. */
+ free(buffer);
+ return -1;
+ }
+
+ num_written = 0;
+
+ while (num_written < read_ret) {
+ ssize_t write_ret;
+
+ if (tofd == -1) {
+ write_ret = read_ret;
+ } else {
+ /* Write to file - ignore EINTR. */
+ write_ret = sys_write(tofd,
+ buffer + num_written,
+ read_ret - num_written);
+
+ if (write_ret <= 0) {
+ /* write error - stop writing. */
+ tofd = -1;
+ saved_errno = errno;
+ continue;
+ }
+ }
+
+ num_written += (size_t)write_ret;
+ total_written += (size_t)write_ret;
+ }
+
+ total += read_ret;
+ }
+
+ free(buffer);
+ if (saved_errno) {
+ /* Return the correct write error. */
+ errno = saved_errno;
+ }
+ return (ssize_t)total_written;
+}
+
+#if defined(HAVE_LINUX_SPLICE)
+
+/*
+ * Try and use the Linux system call to do this.
+ * Remember we only return -1 if the socket read
+ * failed. Else we return the number of bytes
+ * actually written. We always read count bytes
+ * from the network in the case of return != -1.
+ */
+
+
+ssize_t sys_recvfile(int fromfd,
+ int tofd,
+ SMB_OFF_T offset,
+ size_t count)
+{
+ static bool try_splice_call = true;
+ size_t total_written = 0;
+
+ DEBUG(10,("sys_recvfile: from = %d, to = %d, "
+ "offset=%.0f, count = %lu\n",
+ fromfd, tofd, (double)offset,
+ (unsigned long)count));
+
+ if (count == 0) {
+ return 0;
+ }
+
+ /*
+ * Older Linux kernels have splice for sendfile,
+ * but it fails for recvfile. Ensure we only try
+ * this once and always fall back to the userspace
+ * implementation if recvfile splice fails. JRA.
+ */
+
+ if (!try_splice_call) {
+ return default_sys_recvfile(fromfd,
+ tofd,
+ offset,
+ count);
+ }
+
+ while (total_written < count) {
+ ssize_t ret = splice(fromfd,
+ NULL,
+ tofd,
+ &offset,
+ count,
+ 0);
+ if (ret == -1) {
+ if (errno != EINTR) {
+ if (total_written == 0 &&
+ (errno == EBADF || errno == EINVAL)) {
+ try_splice_call = false;
+ return default_sys_recvfile(fromfd,
+ tofd,
+ offset,
+ count);
+ }
+ break;
+ }
+ continue;
+ }
+ total_written += ret;
+ count -= ret;
+ }
+
+ if (total_written < count) {
+ int saved_errno = errno;
+ if (drain_socket(fromfd, count-total_written) !=
+ count-total_written) {
+ /* socket is dead. */
+ return -1;
+ }
+ errno = saved_errno;
+ }
+
+ return total_written;
+}
+#else
+
+/*****************************************************************
+ No recvfile system call - use the default 128 chunk implementation.
+*****************************************************************/
+
+ssize_t sys_recvfile(int fromfd,
+ int tofd,
+ SMB_OFF_T offset,
+ size_t count)
+{
+ return default_sys_recvfile(fromfd, tofd, offset, count);
+}
+#endif
+
+/*****************************************************************
+ Throw away "count" bytes from the client socket.
+*****************************************************************/
+
+ssize_t drain_socket(int sockfd, size_t count)
+{
+ return default_sys_recvfile(sockfd, -1, (SMB_OFF_T)-1, count);
+}
diff --git a/source3/lib/replace/.checker_innocent b/source3/lib/replace/.checker_innocent
new file mode 100644
index 0000000000..e619176540
--- /dev/null
+++ b/source3/lib/replace/.checker_innocent
@@ -0,0 +1,4 @@
+>>>MISTAKE21_create_files_6a9e68ada99a97cb
+>>>MISTAKE21_os2_delete_9b2bfa7f38711d09
+>>>MISTAKE21_os2_delete_2fcc29aaa99a97cb
+>>>SECURITY2_os2_delete_9b2bfa7f1c9396ca
diff --git a/source3/lib/replace/Makefile.in b/source3/lib/replace/Makefile.in
new file mode 100644
index 0000000000..c989835a8d
--- /dev/null
+++ b/source3/lib/replace/Makefile.in
@@ -0,0 +1,63 @@
+#!gmake
+#
+CC = @CC@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+includedir = @includedir@
+libdir = @libdir@
+VPATH = @libreplacedir@
+srcdir = @srcdir@
+builddir = @builddir@
+INSTALL = @INSTALL@
+LIBS = @LIBS@
+
+.PHONY: test all showflags install installcheck clean distclean realdistclean
+
+CFLAGS=-I. @CFLAGS@
+LDFLAGS=@LDFLAGS@
+
+OBJS = @LIBREPLACEOBJ@
+
+all: showflags libreplace.a testsuite
+
+showflags:
+ @echo 'libreplace will be compiled with flags:'
+ @echo ' CC = $(CC)'
+ @echo ' CFLAGS = $(CFLAGS)'
+ @echo ' LDFLAGS= $(LDFLAGS)'
+ @echo ' LIBS = $(LIBS)'
+
+install: all
+ mkdir -p $(libdir)
+ $(INSTALL) libreplace.a $(libdir)
+
+libreplace.a: $(OBJS)
+ ar -rcsv $@ $(OBJS)
+
+test: all
+ ./testsuite
+
+installcheck: install test
+
+TEST_OBJS = test/testsuite.o test/os2_delete.o test/strptime.o test/getifaddrs.o
+
+testsuite: libreplace.a $(TEST_OBJS)
+ $(CC) -o testsuite $(TEST_OBJS) -L. -lreplace $(LDFLAGS) $(LIBS)
+
+.c.o:
+ @echo Compiling $*.c
+ @mkdir -p `dirname $@`
+ @$(CC) $(CFLAGS) -c $< -o $@
+
+clean:
+ rm -f *.o test/*.o *.a testsuite
+ rm -f testfile.dat
+
+distclean: clean
+ rm -f *~ */*~
+ rm -f config.log config.status config.h config.cache
+ rm -f Makefile
+
+realdistclean: distclean
+ rm -f configure config.h.in
diff --git a/source3/lib/replace/README b/source3/lib/replace/README
new file mode 100644
index 0000000000..4d94317c4b
--- /dev/null
+++ b/source3/lib/replace/README
@@ -0,0 +1,113 @@
+This subsystem ensures that we can always use a certain core set of
+functions and types, that are either provided by the OS or by replacement
+functions / definitions in this subsystem. The aim is to try to stick
+to POSIX functions in here as much as possible. Convenience functions
+that are available on no platform at all belong in other subsystems
+(such as LIBUTIL).
+
+The following functions are guaranteed:
+
+ftruncate
+strlcpy
+strlcat
+mktime
+rename
+initgroups
+memmove
+strdup
+setlinebuf
+vsyslog
+timegm
+setenv
+unsetenv
+strndup
+strnlen
+waitpid
+seteuid
+setegid
+asprintf
+snprintf
+vasprintf
+vsnprintf
+opendir
+readdir
+telldir
+seekdir
+closedir
+dlopen
+dlclose
+dlsym
+dlerror
+chroot
+bzero
+strerror
+errno
+mkdtemp
+mkstemp (a secure one!)
+pread
+pwrite
+getpass
+readline (the library)
+inet_ntoa
+inet_ntop
+inet_pton
+inet_aton
+strtoll
+strtoull
+socketpair
+strptime
+getaddrinfo
+freeaddrinfo
+getnameinfo
+gai_strerror
+getifaddrs
+freeifaddrs
+utime
+utimes
+
+Types:
+bool
+socklen_t
+uint_t
+uint{8,16,32,64}_t
+int{8,16,32,64}_t
+intptr_t
+
+Constants:
+PATH_NAME_MAX
+UINT{16,32,64}_MAX
+INT32_MAX
+RTLD_LAZY
+HOST_NAME_MAX
+UINT16_MAX
+UINT32_MAX
+UINT64_MAX
+CHAR_BIT
+
+Macros:
+va_copy
+__FUNCTION__
+__FILE__
+__LINE__
+__LINESTR__
+__location__
+__STRING
+__STRINGSTRING
+MIN
+MAX
+QSORT_CAST
+ZERO_STRUCT
+ZERO_STRUCTP
+ZERO_STRUCTPN
+ZERO_ARRAY
+ARRAY_SIZE
+PTR_DIFF
+
+Headers:
+stdint.h
+stdbool.h
+
+Prerequisites:
+memset (for bzero)
+syslog (for vsyslog)
+mktemp (for mkstemp and mkdtemp)
diff --git a/source3/lib/replace/aclocal.m4 b/source3/lib/replace/aclocal.m4
new file mode 100644
index 0000000000..5605e476ba
--- /dev/null
+++ b/source3/lib/replace/aclocal.m4
@@ -0,0 +1 @@
+m4_include(libreplace.m4)
diff --git a/source3/lib/replace/autoconf-2.60.m4 b/source3/lib/replace/autoconf-2.60.m4
new file mode 100644
index 0000000000..acdcd38efe
--- /dev/null
+++ b/source3/lib/replace/autoconf-2.60.m4
@@ -0,0 +1,210 @@
+# AC_GNU_SOURCE
+# --------------
+AC_DEFUN([AC_GNU_SOURCE],
+[AH_VERBATIM([_GNU_SOURCE],
+[/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif])dnl
+AC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl
+AC_BEFORE([$0], [AC_RUN_IFELSE])dnl
+AC_DEFINE([_GNU_SOURCE])
+])
+
+# _AC_C_STD_TRY(STANDARD, TEST-PROLOGUE, TEST-BODY, OPTION-LIST,
+# ACTION-IF-AVAILABLE, ACTION-IF-UNAVAILABLE)
+# --------------------------------------------------------------
+# Check whether the C compiler accepts features of STANDARD (e.g `c89', `c99')
+# by trying to compile a program of TEST-PROLOGUE and TEST-BODY. If this fails,
+# try again with each compiler option in the space-separated OPTION-LIST; if one
+# helps, append it to CC. If eventually successful, run ACTION-IF-AVAILABLE,
+# else ACTION-IF-UNAVAILABLE.
+AC_DEFUN([_AC_C_STD_TRY],
+[AC_MSG_CHECKING([for $CC option to accept ISO ]m4_translit($1, [c], [C]))
+AC_CACHE_VAL(ac_cv_prog_cc_$1,
+[ac_cv_prog_cc_$1=no
+ac_save_CC=$CC
+AC_LANG_CONFTEST([AC_LANG_PROGRAM([$2], [$3])])
+for ac_arg in '' $4
+do
+ CC="$ac_save_CC $ac_arg"
+ _AC_COMPILE_IFELSE([], [ac_cv_prog_cc_$1=$ac_arg])
+ test "x$ac_cv_prog_cc_$1" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+])# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_$1" in
+ x)
+ AC_MSG_RESULT([none needed]) ;;
+ xno)
+ AC_MSG_RESULT([unsupported]) ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_$1"
+ AC_MSG_RESULT([$ac_cv_prog_cc_$1]) ;;
+esac
+AS_IF([test "x$ac_cv_prog_cc_$1" != xno], [$5], [$6])
+])# _AC_C_STD_TRY
+
+# _AC_PROG_CC_C99 ([ACTION-IF-AVAILABLE], [ACTION-IF-UNAVAILABLE])
+# ----------------------------------------------------------------
+# If the C compiler is not in ISO C99 mode by default, try to add an
+# option to output variable CC to make it so. This macro tries
+# various options that select ISO C99 on some system or another. It
+# considers the compiler to be in ISO C99 mode if it handles mixed
+# code and declarations, _Bool, inline and restrict.
+AC_DEFUN([_AC_PROG_CC_C99],
+[_AC_C_STD_TRY([c99],
+[[#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <stdio.h>
+
+struct incomplete_array
+{
+ int datasize;
+ double data[];
+};
+
+struct named_init {
+ int number;
+ const wchar_t *name;
+ double average;
+};
+
+typedef const char *ccp;
+
+static inline int
+test_restrict(ccp restrict text)
+{
+ // See if C++-style comments work.
+ // Iterate through items via the restricted pointer.
+ // Also check for declarations in for loops.
+ for (unsigned int i = 0; *(text+i) != '\0'; ++i)
+ continue;
+ return 0;
+}
+
+// Check varargs and va_copy work.
+static void
+test_varargs(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ va_list args_copy;
+ va_copy(args_copy, args);
+
+ const char *str;
+ int number;
+ float fnumber;
+
+ while (*format)
+ {
+ switch (*format++)
+ {
+ case 's': // string
+ str = va_arg(args_copy, const char *);
+ break;
+ case 'd': // int
+ number = va_arg(args_copy, int);
+ break;
+ case 'f': // float
+ fnumber = (float) va_arg(args_copy, double);
+ break;
+ default:
+ break;
+ }
+ }
+ va_end(args_copy);
+ va_end(args);
+}
+]],
+[[
+ // Check bool and long long datatypes.
+ _Bool success = false;
+ long long int bignum = -1234567890LL;
+ unsigned long long int ubignum = 1234567890uLL;
+
+ // Check restrict.
+ if (test_restrict("String literal") != 0)
+ success = true;
+ char *restrict newvar = "Another string";
+
+ // Check varargs.
+ test_varargs("s, d' f .", "string", 65, 34.234);
+
+ // Check incomplete arrays work.
+ struct incomplete_array *ia =
+ malloc(sizeof(struct incomplete_array) + (sizeof(double) * 10));
+ ia->datasize = 10;
+ for (int i = 0; i < ia->datasize; ++i)
+ ia->data[i] = (double) i * 1.234;
+
+ // Check named initialisers.
+ struct named_init ni = {
+ .number = 34,
+ .name = L"Test wide string",
+ .average = 543.34343,
+ };
+
+ ni.number = 58;
+
+ int dynamic_array[ni.number];
+ dynamic_array[43] = 543;
+
+ // work around unused variable warnings
+ return bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x';
+]],
+dnl Try
+dnl GCC -std=gnu99 (unused restrictive modes: -std=c99 -std=iso9899:1999)
+dnl AIX -qlanglvl=extc99 (unused restrictive mode: -qlanglvl=stdc99)
+dnl Intel ICC -c99
+dnl IRIX -c99
+dnl Solaris (unused because it causes the compiler to assume C99 semantics for
+dnl library functions, and this is invalid before Solaris 10: -xc99)
+dnl Tru64 -c99
+dnl with extended modes being tried first.
+[[-std=gnu99 -c99 -qlanglvl=extc99]], [$1], [$2])[]dnl
+])# _AC_PROG_CC_C99
+
+# AC_PROG_CC_C99
+# --------------
+AC_DEFUN([AC_PROG_CC_C99],
+[ AC_REQUIRE([AC_PROG_CC])dnl
+ _AC_PROG_CC_C99
+])
+
+# AC_USE_SYSTEM_EXTENSIONS
+# ------------------------
+# Enable extensions on systems that normally disable them,
+# typically due to standards-conformance issues.
+AC_DEFUN([AC_USE_SYSTEM_EXTENSIONS],
+[
+ AC_BEFORE([$0], [AC_COMPILE_IFELSE])
+ AC_BEFORE([$0], [AC_RUN_IFELSE])
+
+ AC_REQUIRE([AC_GNU_SOURCE])
+ AC_REQUIRE([AC_AIX])
+ AC_REQUIRE([AC_MINIX])
+
+ AH_VERBATIM([__EXTENSIONS__],
+[/* Enable extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif])
+ AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__],
+ [ac_cv_safe_to_define___extensions__],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([
+# define __EXTENSIONS__ 1
+ AC_INCLUDES_DEFAULT])],
+ [ac_cv_safe_to_define___extensions__=yes],
+ [ac_cv_safe_to_define___extensions__=no])])
+ test $ac_cv_safe_to_define___extensions__ = yes &&
+ AC_DEFINE([__EXTENSIONS__])
+ AC_DEFINE([_POSIX_PTHREAD_SEMANTICS])
+])
diff --git a/source3/lib/replace/autogen.sh b/source3/lib/replace/autogen.sh
new file mode 100755
index 0000000000..d46a4279f3
--- /dev/null
+++ b/source3/lib/replace/autogen.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+rm -rf autom4te.cache
+rm -f configure config.h.in
+
+autoheader || exit 1
+autoconf || exit 1
+
+rm -rf autom4te.cache
+
+echo "Now run ./configure and then make."
+exit 0
+
diff --git a/source3/lib/replace/config.guess b/source3/lib/replace/config.guess
new file mode 100755
index 0000000000..354dbe175a
--- /dev/null
+++ b/source3/lib/replace/config.guess
@@ -0,0 +1,1464 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+timestamp='2005-08-03'
+
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerppc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # 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 ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ 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 ;;
+ 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 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????: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 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ 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 ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep __LP64__ >/dev/null
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ x86:Interix*:[34]*)
+ echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
+ exit ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #ifdef __INTEL_COMPILER
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+ test x"${LIBC}" != x && {
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit
+ }
+ test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ 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 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *: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 ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ *86) UNAME_PROCESSOR=i686 ;;
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# 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 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+and
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/source3/lib/replace/config.sub b/source3/lib/replace/config.sub
new file mode 100755
index 0000000000..23cd6fd75c
--- /dev/null
+++ b/source3/lib/replace/config.sub
@@ -0,0 +1,1577 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+timestamp='2005-07-08'
+
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \
+ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64vr | mips64vrel \
+ | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | ms1 \
+ | msp430 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b \
+ | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m32c)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | ms1-* \
+ | msp430-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ m32c-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ 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 | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16c)
+ basic_machine=cr16c-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/source3/lib/replace/configure.ac b/source3/lib/replace/configure.ac
new file mode 100644
index 0000000000..81997e09b7
--- /dev/null
+++ b/source3/lib/replace/configure.ac
@@ -0,0 +1,30 @@
+AC_PREREQ(2.50)
+AC_INIT(replace.c)
+AC_CONFIG_SRCDIR([replace.c])
+AC_CONFIG_HEADER(config.h)
+
+CFLAGS="$CFLAGS -I$srcdir"
+
+AC_LIBREPLACE_ALL_CHECKS
+AC_LIBREPLACE_NETWORK_CHECKS
+
+if test "$ac_cv_prog_gcc" = yes; then
+ CFLAGS="$CFLAGS -Wall"
+ CFLAGS="$CFLAGS -W"
+ CFLAGS="$CFLAGS -Wshadow"
+ CFLAGS="$CFLAGS -Wstrict-prototypes"
+ CFLAGS="$CFLAGS -Wpointer-arith"
+ CFLAGS="$CFLAGS -Wcast-qual"
+ CFLAGS="$CFLAGS -Wcast-align"
+ CFLAGS="$CFLAGS -Wwrite-strings"
+ CFLAGS="$CFLAGS -Werror-implicit-function-declaration"
+ CFLAGS="$CFLAGS -Wformat=2"
+ CFLAGS="$CFLAGS -Wno-format-y2k"
+fi
+
+LIBS="${LIBREPLACE_NETWORK_LIBS}"
+AC_SUBST(LIBS)
+
+AC_SUBST(LDFLAGS)
+
+AC_OUTPUT(Makefile)
diff --git a/source3/lib/replace/dlfcn.c b/source3/lib/replace/dlfcn.c
new file mode 100644
index 0000000000..3b109d7e40
--- /dev/null
+++ b/source3/lib/replace/dlfcn.c
@@ -0,0 +1,75 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba system utilities
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1998-2002
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#ifdef HAVE_DL_H
+#include <dl.h>
+#endif
+
+#ifndef HAVE_DLOPEN
+#ifdef DLOPEN_TAKES_UNSIGNED_FLAGS
+void *rep_dlopen(const char *name, unsigned int flags)
+#else
+void *rep_dlopen(const char *name, int flags)
+#endif
+{
+#ifdef HAVE_SHL_LOAD
+ if (name == NULL)
+ return PROG_HANDLE;
+ return (void *)shl_load(name, flags, 0);
+#else
+ return NULL;
+#endif
+}
+#endif
+
+#ifndef HAVE_DLSYM
+void *rep_dlsym(void *handle, const char *symbol)
+{
+#ifdef HAVE_SHL_FINDSYM
+ void *sym_addr;
+ if (!shl_findsym((shl_t *)&handle, symbol, TYPE_UNDEFINED, &sym_addr))
+ return sym_addr;
+#endif
+ return NULL;
+}
+#endif
+
+#ifndef HAVE_DLERROR
+char *rep_dlerror(void)
+{
+ return "dynamic loading of objects not supported on this platform";
+}
+#endif
+
+#ifndef HAVE_DLCLOSE
+int rep_dlclose(void *handle)
+{
+#ifdef HAVE_SHL_CLOSE
+ return shl_unload((shl_t)handle);
+#else
+ return 0;
+#endif
+}
+#endif
diff --git a/source3/lib/replace/dlfcn.m4 b/source3/lib/replace/dlfcn.m4
new file mode 100644
index 0000000000..42f56f26be
--- /dev/null
+++ b/source3/lib/replace/dlfcn.m4
@@ -0,0 +1,31 @@
+dnl dummies provided by dlfcn.c if not available
+save_LIBS="$LIBS"
+LIBS=""
+
+libreplace_cv_dlfcn=no
+AC_SEARCH_LIBS(dlopen, dl)
+
+AC_CHECK_HEADERS(dlfcn.h)
+AC_CHECK_FUNCS([dlopen dlsym dlerror dlclose],[],[libreplace_cv_dlfcn=yes])
+
+libreplace_cv_shl=no
+AC_SEARCH_LIBS(shl_load, sl)
+AC_CHECK_HEADERS(dl.h)
+AC_CHECK_FUNCS([shl_load shl_unload shl_findsym],[],[libreplace_cv_shl=yes])
+
+AC_VERIFY_C_PROTOTYPE([void *dlopen(const char* filename, unsigned int flags)],
+ [
+ return 0;
+ ],[
+ AC_DEFINE(DLOPEN_TAKES_UNSIGNED_FLAGS, 1, [Whether dlopen takes unsigned int flags])
+ ],[],[
+ #include <dlfcn.h>
+ ])
+
+if test x"${libreplace_cv_dlfcn}" = x"yes";then
+ LIBREPLACEOBJ="${LIBREPLACEOBJ} dlfcn.o"
+fi
+
+LIBDL="$LIBS"
+AC_SUBST(LIBDL)
+LIBS="$save_LIBS"
diff --git a/source3/lib/replace/getaddrinfo.c b/source3/lib/replace/getaddrinfo.c
new file mode 100644
index 0000000000..c5cd52be93
--- /dev/null
+++ b/source3/lib/replace/getaddrinfo.c
@@ -0,0 +1,497 @@
+/*
+PostgreSQL Database Management System
+(formerly known as Postgres, then as Postgres95)
+
+Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group
+
+Portions Copyright (c) 1994, The Regents of the University of California
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose, without fee, and without a written agreement
+is hereby granted, provided that the above copyright notice and this paragraph
+and the following two paragraphs appear in all copies.
+
+IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
+EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS
+TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+*/
+
+/*-------------------------------------------------------------------------
+ *
+ * getaddrinfo.c
+ * Support getaddrinfo() on platforms that don't have it.
+ *
+ * We also supply getnameinfo() here, assuming that the platform will have
+ * it if and only if it has getaddrinfo(). If this proves false on some
+ * platform, we'll need to split this file and provide a separate configure
+ * test for getnameinfo().
+ *
+ * Copyright (c) 2003-2007, PostgreSQL Global Development Group
+ *
+ * Copyright (C) 2007 Jeremy Allison.
+ * Modified to return multiple IPv4 addresses for Samba.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "replace.h"
+#include "system/network.h"
+
+#ifndef SMB_MALLOC
+#define SMB_MALLOC(s) malloc(s)
+#endif
+
+#ifndef SMB_STRDUP
+#define SMB_STRDUP(s) strdup(s)
+#endif
+
+static int check_hostent_err(struct hostent *hp)
+{
+ if (!hp) {
+ switch (h_errno) {
+ case HOST_NOT_FOUND:
+ case NO_DATA:
+ return EAI_NONAME;
+ case TRY_AGAIN:
+ return EAI_AGAIN;
+ case NO_RECOVERY:
+ default:
+ return EAI_FAIL;
+ }
+ }
+ if (!hp->h_name || hp->h_addrtype != AF_INET) {
+ return EAI_FAIL;
+ }
+ return 0;
+}
+
+static char *canon_name_from_hostent(struct hostent *hp,
+ int *perr)
+{
+ char *ret = NULL;
+
+ *perr = check_hostent_err(hp);
+ if (*perr) {
+ return NULL;
+ }
+ ret = SMB_STRDUP(hp->h_name);
+ if (!ret) {
+ *perr = EAI_MEMORY;
+ }
+ return ret;
+}
+
+static char *get_my_canon_name(int *perr)
+{
+ char name[HOST_NAME_MAX+1];
+
+ if (gethostname(name, HOST_NAME_MAX) == -1) {
+ *perr = EAI_FAIL;
+ return NULL;
+ }
+ /* Ensure null termination. */
+ name[HOST_NAME_MAX] = '\0';
+ return canon_name_from_hostent(gethostbyname(name), perr);
+}
+
+static char *get_canon_name_from_addr(struct in_addr ip,
+ int *perr)
+{
+ return canon_name_from_hostent(
+ gethostbyaddr(&ip, sizeof(ip), AF_INET),
+ perr);
+}
+
+static struct addrinfo *alloc_entry(const struct addrinfo *hints,
+ struct in_addr ip,
+ unsigned short port)
+{
+ struct sockaddr_in *psin = NULL;
+ struct addrinfo *ai = SMB_MALLOC(sizeof(*ai));
+
+ if (!ai) {
+ return NULL;
+ }
+ memset(ai, '\0', sizeof(*ai));
+
+ psin = SMB_MALLOC(sizeof(*psin));
+ if (!psin) {
+ free(ai);
+ return NULL;
+ }
+
+ memset(psin, '\0', sizeof(*psin));
+
+ psin->sin_family = AF_INET;
+ psin->sin_port = htons(port);
+ psin->sin_addr = ip;
+
+ ai->ai_flags = 0;
+ ai->ai_family = AF_INET;
+ ai->ai_socktype = hints->ai_socktype;
+ ai->ai_protocol = hints->ai_protocol;
+ ai->ai_addrlen = sizeof(*psin);
+ ai->ai_addr = (struct sockaddr *) psin;
+ ai->ai_canonname = NULL;
+ ai->ai_next = NULL;
+
+ return ai;
+}
+
+/*
+ * get address info for a single ipv4 address.
+ *
+ * Bugs: - servname can only be a number, not text.
+ */
+
+static int getaddr_info_single_addr(const char *service,
+ uint32_t addr,
+ const struct addrinfo *hints,
+ struct addrinfo **res)
+{
+
+ struct addrinfo *ai = NULL;
+ struct in_addr ip;
+ unsigned short port = 0;
+
+ if (service) {
+ port = (unsigned short)atoi(service);
+ }
+ ip.s_addr = htonl(addr);
+
+ ai = alloc_entry(hints, ip, port);
+ if (!ai) {
+ return EAI_MEMORY;
+ }
+
+ /* If we're asked for the canonical name,
+ * make sure it returns correctly. */
+ if (!(hints->ai_flags & AI_NUMERICSERV) &&
+ hints->ai_flags & AI_CANONNAME) {
+ int err;
+ if (addr == INADDR_LOOPBACK || addr == INADDR_ANY) {
+ ai->ai_canonname = get_my_canon_name(&err);
+ } else {
+ ai->ai_canonname =
+ get_canon_name_from_addr(ip,&err);
+ }
+ if (ai->ai_canonname == NULL) {
+ freeaddrinfo(ai);
+ return err;
+ }
+ }
+
+ *res = ai;
+ return 0;
+}
+
+/*
+ * get address info for multiple ipv4 addresses.
+ *
+ * Bugs: - servname can only be a number, not text.
+ */
+
+static int getaddr_info_name(const char *node,
+ const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo **res)
+{
+ struct addrinfo *listp = NULL, *prevp = NULL;
+ char **pptr = NULL;
+ int err;
+ struct hostent *hp = NULL;
+ unsigned short port = 0;
+
+ if (service) {
+ port = (unsigned short)atoi(service);
+ }
+
+ hp = gethostbyname(node);
+ err = check_hostent_err(hp);
+ if (err) {
+ return err;
+ }
+
+ for(pptr = hp->h_addr_list; *pptr; pptr++) {
+ struct in_addr ip = *(struct in_addr *)*pptr;
+ struct addrinfo *ai = alloc_entry(hints, ip, port);
+
+ if (!ai) {
+ freeaddrinfo(listp);
+ return EAI_MEMORY;
+ }
+
+ if (!listp) {
+ listp = ai;
+ prevp = ai;
+ ai->ai_canonname = SMB_STRDUP(hp->h_name);
+ if (!ai->ai_canonname) {
+ freeaddrinfo(listp);
+ return EAI_MEMORY;
+ }
+ } else {
+ prevp->ai_next = ai;
+ prevp = ai;
+ }
+ }
+ *res = listp;
+ return 0;
+}
+
+/*
+ * get address info for ipv4 sockets.
+ *
+ * Bugs: - servname can only be a number, not text.
+ */
+
+int rep_getaddrinfo(const char *node,
+ const char *service,
+ const struct addrinfo * hintp,
+ struct addrinfo ** res)
+{
+ struct addrinfo hints;
+
+ /* Setup the hints struct. */
+ if (hintp == NULL) {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ } else {
+ memcpy(&hints, hintp, sizeof(hints));
+ }
+
+ if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) {
+ return EAI_FAMILY;
+ }
+
+ if (hints.ai_socktype == 0) {
+ hints.ai_socktype = SOCK_STREAM;
+ }
+
+ if (!node && !service) {
+ return EAI_NONAME;
+ }
+
+ if (node) {
+ if (node[0] == '\0') {
+ return getaddr_info_single_addr(service,
+ INADDR_ANY,
+ &hints,
+ res);
+ } else if (hints.ai_flags & AI_NUMERICHOST) {
+ struct in_addr ip;
+ if (!inet_aton(node, &ip)) {
+ return EAI_FAIL;
+ }
+ return getaddr_info_single_addr(service,
+ ntohl(ip.s_addr),
+ &hints,
+ res);
+ } else {
+ return getaddr_info_name(node,
+ service,
+ &hints,
+ res);
+ }
+ } else if (hints.ai_flags & AI_PASSIVE) {
+ return getaddr_info_single_addr(service,
+ INADDR_ANY,
+ &hints,
+ res);
+ }
+ return getaddr_info_single_addr(service,
+ INADDR_LOOPBACK,
+ &hints,
+ res);
+}
+
+
+void rep_freeaddrinfo(struct addrinfo *res)
+{
+ struct addrinfo *next = NULL;
+
+ for (;res; res = next) {
+ next = res->ai_next;
+ if (res->ai_canonname) {
+ free(res->ai_canonname);
+ }
+ if (res->ai_addr) {
+ free(res->ai_addr);
+ }
+ free(res);
+ }
+}
+
+
+const char *rep_gai_strerror(int errcode)
+{
+#ifdef HAVE_HSTRERROR
+ int hcode;
+
+ switch (errcode)
+ {
+ case EAI_NONAME:
+ hcode = HOST_NOT_FOUND;
+ break;
+ case EAI_AGAIN:
+ hcode = TRY_AGAIN;
+ break;
+ case EAI_FAIL:
+ default:
+ hcode = NO_RECOVERY;
+ break;
+ }
+
+ return hstrerror(hcode);
+#else /* !HAVE_HSTRERROR */
+
+ switch (errcode)
+ {
+ case EAI_NONAME:
+ return "Unknown host";
+ case EAI_AGAIN:
+ return "Host name lookup failure";
+#ifdef EAI_BADFLAGS
+ case EAI_BADFLAGS:
+ return "Invalid argument";
+#endif
+#ifdef EAI_FAMILY
+ case EAI_FAMILY:
+ return "Address family not supported";
+#endif
+#ifdef EAI_MEMORY
+ case EAI_MEMORY:
+ return "Not enough memory";
+#endif
+#ifdef EAI_NODATA
+ case EAI_NODATA:
+ return "No host data of that type was found";
+#endif
+#ifdef EAI_SERVICE
+ case EAI_SERVICE:
+ return "Class type not found";
+#endif
+#ifdef EAI_SOCKTYPE
+ case EAI_SOCKTYPE:
+ return "Socket type not supported";
+#endif
+ default:
+ return "Unknown server error";
+ }
+#endif /* HAVE_HSTRERROR */
+}
+
+static int gethostnameinfo(const struct sockaddr *sa,
+ char *node,
+ size_t nodelen,
+ int flags)
+{
+ int ret = -1;
+ char *p = NULL;
+
+ if (!(flags & NI_NUMERICHOST)) {
+ struct hostent *hp = gethostbyaddr(
+ &((struct sockaddr_in *)sa)->sin_addr,
+ sizeof(struct in_addr),
+ sa->sa_family);
+ ret = check_hostent_err(hp);
+ if (ret == 0) {
+ /* Name looked up successfully. */
+ ret = snprintf(node, nodelen, "%s", hp->h_name);
+ if (ret < 0 || (size_t)ret >= nodelen) {
+ return EAI_MEMORY;
+ }
+ if (flags & NI_NOFQDN) {
+ p = strchr(node,'.');
+ if (p) {
+ *p = '\0';
+ }
+ }
+ return 0;
+ }
+
+ if (flags & NI_NAMEREQD) {
+ /* If we require a name and didn't get one,
+ * automatically fail. */
+ return ret;
+ }
+ /* Otherwise just fall into the numeric host code... */
+ }
+ p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
+ ret = snprintf(node, nodelen, "%s", p);
+ if (ret < 0 || (size_t)ret >= nodelen) {
+ return EAI_MEMORY;
+ }
+ return 0;
+}
+
+static int getservicenameinfo(const struct sockaddr *sa,
+ char *service,
+ size_t servicelen,
+ int flags)
+{
+ int ret = -1;
+ int port = ntohs(((struct sockaddr_in *)sa)->sin_port);
+
+ if (!(flags & NI_NUMERICSERV)) {
+ struct servent *se = getservbyport(
+ port,
+ (flags & NI_DGRAM) ? "udp" : "tcp");
+ if (se && se->s_name) {
+ /* Service name looked up successfully. */
+ ret = snprintf(service, servicelen, "%s", se->s_name);
+ if (ret < 0 || (size_t)ret >= servicelen) {
+ return EAI_MEMORY;
+ }
+ return 0;
+ }
+ /* Otherwise just fall into the numeric service code... */
+ }
+ ret = snprintf(service, servicelen, "%d", port);
+ if (ret < 0 || (size_t)ret >= servicelen) {
+ return EAI_MEMORY;
+ }
+ return 0;
+}
+
+/*
+ * Convert an ipv4 address to a hostname.
+ *
+ * Bugs: - No IPv6 support.
+ */
+int rep_getnameinfo(const struct sockaddr *sa, socklen_t salen,
+ char *node, size_t nodelen,
+ char *service, size_t servicelen, int flags)
+{
+
+ /* Invalid arguments. */
+ if (sa == NULL || (node == NULL && service == NULL)) {
+ return EAI_FAIL;
+ }
+
+ if (sa->sa_family != AF_INET) {
+ return EAI_FAIL;
+ }
+
+ if (salen < sizeof(struct sockaddr_in)) {
+ return EAI_FAIL;
+ }
+
+ if (node) {
+ return gethostnameinfo(sa, node, nodelen, flags);
+ }
+
+ if (service) {
+ return getservicenameinfo(sa, service, servicelen, flags);
+ }
+ return 0;
+}
diff --git a/source3/lib/replace/getaddrinfo.h b/source3/lib/replace/getaddrinfo.h
new file mode 100644
index 0000000000..dddd699b62
--- /dev/null
+++ b/source3/lib/replace/getaddrinfo.h
@@ -0,0 +1,89 @@
+/*
+PostgreSQL Database Management System
+(formerly known as Postgres, then as Postgres95)
+
+Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group
+
+Portions Copyright (c) 1994, The Regents of the University of California
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose, without fee, and without a written agreement
+is hereby granted, provided that the above copyright notice and this paragraph
+and the following two paragraphs appear in all copies.
+
+IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
+EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS
+TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+*/
+
+/*-------------------------------------------------------------------------
+ *
+ * getaddrinfo.h
+ * Support getaddrinfo() on platforms that don't have it.
+ *
+ * Note: we use our own routines on platforms that don't HAVE_STRUCT_ADDRINFO,
+ * whether or not the library routine getaddrinfo() can be found. This
+ * policy is needed because on some platforms a manually installed libbind.a
+ * may provide getaddrinfo(), yet the system headers may not provide the
+ * struct definitions needed to call it. To avoid conflict with the libbind
+ * definition in such cases, we rename our routines to pg_xxx() via macros.
+ *
+
+in lib/replace we use rep_xxx()
+
+ * This code will also work on platforms where struct addrinfo is defined
+ * in the system headers but no getaddrinfo() can be located.
+ *
+ * Copyright (c) 2003-2007, PostgreSQL Global Development Group
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef GETADDRINFO_H
+#define GETADDRINFO_H
+
+#ifndef HAVE_GETADDRINFO
+
+/* Rename private copies per comments above */
+#ifdef getaddrinfo
+#undef getaddrinfo
+#endif
+#define getaddrinfo rep_getaddrinfo
+#define HAVE_GETADDRINFO
+
+#ifdef freeaddrinfo
+#undef freeaddrinfo
+#endif
+#define freeaddrinfo rep_freeaddrinfo
+#define HAVE_FREEADDRINFO
+
+#ifdef gai_strerror
+#undef gai_strerror
+#endif
+#define gai_strerror rep_gai_strerror
+#define HAVE_GAI_STRERROR
+
+#ifdef getnameinfo
+#undef getnameinfo
+#endif
+#define getnameinfo rep_getnameinfo
+#define HAVE_GETNAMEINFO
+
+extern int rep_getaddrinfo(const char *node, const char *service,
+ const struct addrinfo * hints, struct addrinfo ** res);
+extern void rep_freeaddrinfo(struct addrinfo * res);
+extern const char *rep_gai_strerror(int errcode);
+extern int rep_getnameinfo(const struct sockaddr * sa, socklen_t salen,
+ char *node, size_t nodelen,
+ char *service, size_t servicelen, int flags);
+#endif /* HAVE_GETADDRINFO */
+
+#endif /* GETADDRINFO_H */
diff --git a/source3/lib/replace/getifaddrs.c b/source3/lib/replace/getifaddrs.c
new file mode 100644
index 0000000000..f6f0ec080c
--- /dev/null
+++ b/source3/lib/replace/getifaddrs.c
@@ -0,0 +1,361 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Jeremy Allison 2007
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define SOCKET_WRAPPER_NOT_REPLACE
+
+#include "replace.h"
+#include "system/network.h"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifndef SIOCGIFCONF
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#endif
+
+#ifdef HAVE_IFACE_GETIFADDRS
+#define _FOUND_IFACE_ANY
+#else
+
+void rep_freeifaddrs(struct ifaddrs *ifp)
+{
+ if (ifp != NULL) {
+ free(ifp->ifa_name);
+ free(ifp->ifa_addr);
+ free(ifp->ifa_netmask);
+ free(ifp->ifa_dstaddr);
+ freeifaddrs(ifp->ifa_next);
+ free(ifp);
+ }
+}
+
+static struct sockaddr *sockaddr_dup(struct sockaddr *sa)
+{
+ struct sockaddr *ret;
+ socklen_t socklen;
+#ifdef HAVE_SOCKADDR_SA_LEN
+ socklen = sa->sa_len;
+#else
+ socklen = sizeof(struct sockaddr_storage);
+#endif
+ ret = calloc(1, socklen);
+ if (ret == NULL)
+ return NULL;
+ memcpy(ret, sa, socklen);
+ return ret;
+}
+#endif
+
+#if HAVE_IFACE_IFCONF
+
+/* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
+ V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
+
+ It probably also works on any BSD style system. */
+
+int rep_getifaddrs(struct ifaddrs **ifap)
+{
+ struct ifconf ifc;
+ char buff[8192];
+ int fd, i, n;
+ struct ifreq *ifr=NULL;
+ struct in_addr ipaddr;
+ struct in_addr nmask;
+ char *iname;
+ struct ifaddrs *curif;
+ struct ifaddrs *lastif = NULL;
+
+ *ifap = NULL;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ return -1;
+ }
+
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+
+ if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
+ close(fd);
+ return -1;
+ }
+
+ ifr = ifc.ifc_req;
+
+ n = ifc.ifc_len / sizeof(struct ifreq);
+
+ /* Loop through interfaces, looking for given IP address */
+ for (i=n-1; i>=0; i--) {
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) == -1) {
+ freeifaddrs(*ifap);
+ return -1;
+ }
+
+ curif = calloc(1, sizeof(struct ifaddrs));
+ curif->ifa_name = strdup(ifr[i].ifr_name);
+ curif->ifa_flags = ifr[i].ifr_flags;
+ curif->ifa_dstaddr = NULL;
+ curif->ifa_data = NULL;
+ curif->ifa_next = NULL;
+
+ curif->ifa_addr = NULL;
+ if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != -1) {
+ curif->ifa_addr = sockaddr_dup(&ifr[i].ifr_addr);
+ }
+
+ curif->ifa_netmask = NULL;
+ if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != -1) {
+ curif->ifa_netmask = sockaddr_dup(&ifr[i].ifr_addr);
+ }
+
+ if (lastif == NULL) {
+ *ifap = curif;
+ } else {
+ lastif->ifa_next = curif;
+ }
+ lastif = curif;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+#define _FOUND_IFACE_ANY
+#endif /* HAVE_IFACE_IFCONF */
+#ifdef HAVE_IFACE_IFREQ
+
+#ifndef I_STR
+#include <sys/stropts.h>
+#endif
+
+/****************************************************************************
+this should cover most of the streams based systems
+Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
+****************************************************************************/
+int rep_getifaddrs(struct ifaddrs **ifap)
+{
+ struct ifreq ifreq;
+ struct strioctl strioctl;
+ char buff[8192];
+ int fd, i, n;
+ struct ifreq *ifr=NULL;
+ struct in_addr ipaddr;
+ struct in_addr nmask;
+ char *iname;
+ struct ifaddrs *curif;
+ struct ifaddrs *lastif = NULL;
+
+ *ifap = NULL;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ return -1;
+ }
+
+ strioctl.ic_cmd = SIOCGIFCONF;
+ strioctl.ic_dp = buff;
+ strioctl.ic_len = sizeof(buff);
+ if (ioctl(fd, I_STR, &strioctl) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ /* we can ignore the possible sizeof(int) here as the resulting
+ number of interface structures won't change */
+ n = strioctl.ic_len / sizeof(struct ifreq);
+
+ /* we will assume that the kernel returns the length as an int
+ at the start of the buffer if the offered size is a
+ multiple of the structure size plus an int */
+ if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
+ ifr = (struct ifreq *)(buff + sizeof(int));
+ } else {
+ ifr = (struct ifreq *)buff;
+ }
+
+ /* Loop through interfaces */
+
+ for (i = 0; i<n; i++) {
+ ifreq = ifr[i];
+
+ curif = calloc(1, sizeof(struct ifaddrs));
+ if (lastif == NULL) {
+ *ifap = curif;
+ } else {
+ lastif->ifa_next = curif;
+ }
+
+ strioctl.ic_cmd = SIOCGIFFLAGS;
+ strioctl.ic_dp = (char *)&ifreq;
+ strioctl.ic_len = sizeof(struct ifreq);
+ if (ioctl(fd, I_STR, &strioctl) != 0) {
+ freeifaddrs(*ifap);
+ return -1;
+ }
+
+ curif->ifa_flags = ifreq.ifr_flags;
+
+ strioctl.ic_cmd = SIOCGIFADDR;
+ strioctl.ic_dp = (char *)&ifreq;
+ strioctl.ic_len = sizeof(struct ifreq);
+ if (ioctl(fd, I_STR, &strioctl) != 0) {
+ freeifaddrs(*ifap);
+ return -1;
+ }
+
+ curif->ifa_name = strdup(ifreq.ifr_name);
+ curif->ifa_addr = sockaddr_dup(&ifreq.ifr_addr);
+ curif->ifa_dstaddr = NULL;
+ curif->ifa_data = NULL;
+ curif->ifa_next = NULL;
+ curif->ifa_netmask = NULL;
+
+ strioctl.ic_cmd = SIOCGIFNETMASK;
+ strioctl.ic_dp = (char *)&ifreq;
+ strioctl.ic_len = sizeof(struct ifreq);
+ if (ioctl(fd, I_STR, &strioctl) != 0) {
+ freeifaddrs(*ifap);
+ return -1;
+ }
+
+ curif->ifa_netmask = sockaddr_dup(&ifreq.ifr_addr);
+
+ lastif = curif;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+#define _FOUND_IFACE_ANY
+#endif /* HAVE_IFACE_IFREQ */
+#ifdef HAVE_IFACE_AIX
+
+/****************************************************************************
+this one is for AIX (tested on 4.2)
+****************************************************************************/
+int rep_getifaddrs(struct ifaddrs **ifap)
+{
+ char buff[8192];
+ int fd, i;
+ struct ifconf ifc;
+ struct ifreq *ifr=NULL;
+ struct in_addr ipaddr;
+ struct in_addr nmask;
+ char *iname;
+ struct ifaddrs *curif;
+ struct ifaddrs *lastif = NULL;
+
+ *ifap = NULL;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ return -1;
+ }
+
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+
+ if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
+ close(fd);
+ return -1;
+ }
+
+ ifr = ifc.ifc_req;
+
+ /* Loop through interfaces */
+ i = ifc.ifc_len;
+
+ while (i > 0) {
+ uint_t inc;
+
+ inc = ifr->ifr_addr.sa_len;
+
+ if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
+ freeaddrinfo(*ifap);
+ return -1;
+ }
+
+ curif = calloc(1, sizeof(struct ifaddrs));
+ if (lastif == NULL) {
+ *ifap = curif;
+ } else {
+ lastif->ifa_next = curif;
+ }
+
+ curif->ifa_name = strdup(ifr->ifr_name);
+ curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr);
+ curif->ifa_dstaddr = NULL;
+ curif->ifa_data = NULL;
+ curif->ifa_netmask = NULL;
+ curif->ifa_next = NULL;
+
+ if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
+ freeaddrinfo(*ifap);
+ return -1;
+ }
+
+ curif->ifa_flags = ifr->ifr_flags;
+
+ if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
+ freeaddrinfo(*ifap);
+ return -1;
+ }
+
+ curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr);
+
+ lastif = curif;
+
+ next:
+ /*
+ * Patch from Archie Cobbs (archie@whistle.com). The
+ * addresses in the SIOCGIFCONF interface list have a
+ * minimum size. Usually this doesn't matter, but if
+ * your machine has tunnel interfaces, etc. that have
+ * a zero length "link address", this does matter. */
+
+ if (inc < sizeof(ifr->ifr_addr))
+ inc = sizeof(ifr->ifr_addr);
+ inc += IFNAMSIZ;
+
+ ifr = (struct ifreq*) (((char*) ifr) + inc);
+ i -= inc;
+ }
+
+ close(fd);
+ return 0;
+}
+
+#define _FOUND_IFACE_ANY
+#endif /* HAVE_IFACE_AIX */
+#ifndef _FOUND_IFACE_ANY
+int rep_getifaddrs(struct ifaddrs **ifap)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
diff --git a/source3/lib/replace/getpass.c b/source3/lib/replace/getpass.c
new file mode 100644
index 0000000000..0be618fc91
--- /dev/null
+++ b/source3/lib/replace/getpass.c
@@ -0,0 +1,222 @@
+/* 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
+modify it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation; either version 3 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, see <http://www.gnu.org/licenses/>. */
+
+/* Modified to use with samba by Jeremy Allison, 8th July 1995. */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "system/terminal.h"
+#include "system/passwd.h"
+
+/*
+ * Define additional missing types
+ */
+#ifndef HAVE_SIG_ATOMIC_T_TYPE
+typedef int sig_atomic_t;
+#endif
+
+#ifndef SIGCLD
+#define SIGCLD SIGCHLD
+#endif
+
+#ifndef SIGNAL_CAST
+#define SIGNAL_CAST (RETSIGTYPE (*)(int))
+#endif
+
+#ifdef SYSV_TERMIO
+
+/* SYSTEM V TERMIO HANDLING */
+
+static struct termio t;
+
+#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)
+
+#ifndef TCSAFLUSH
+#define TCSAFLUSH 1
+#endif
+
+#ifndef TCSANOW
+#define TCSANOW 0
+#endif
+
+static int tcgetattr(int fd, struct termio *_t)
+{
+ return ioctl(fd, TCGETA, _t);
+}
+
+static int tcsetattr(int fd, int flags, struct termio *_t)
+{
+ if(flags & TCSAFLUSH)
+ ioctl(fd, TCFLSH, TCIOFLUSH);
+ return ioctl(fd, TCSETS, _t);
+}
+
+#elif !defined(TCSAFLUSH)
+
+/* BSD TERMIO HANDLING */
+
+static struct sgttyb t;
+
+#define ECHO_IS_ON(t) ((t).sg_flags & ECHO)
+#define TURN_ECHO_OFF(t) ((t).sg_flags &= ~ECHO)
+#define TURN_ECHO_ON(t) ((t).sg_flags |= ECHO)
+
+#define TCSAFLUSH 1
+#define TCSANOW 0
+
+static int tcgetattr(int fd, struct sgttyb *_t)
+{
+ return ioctl(fd, TIOCGETP, (char *)_t);
+}
+
+static int tcsetattr(int fd, int flags, struct sgttyb *_t)
+{
+ return ioctl(fd, TIOCSETP, (char *)_t);
+}
+
+#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 /* SYSV_TERMIO */
+
+static void catch_signal(int signum,void (*handler)(int ))
+{
+#ifdef HAVE_SIGACTION
+ struct sigaction act;
+ struct sigaction oldact;
+
+ memset(&act, 0, sizeof(act));
+
+ act.sa_handler = handler;
+#ifdef SA_RESTART
+ /*
+ * We *want* SIGALRM to interrupt a system call.
+ */
+ if(signum != SIGALRM)
+ act.sa_flags = SA_RESTART;
+#endif
+ sigemptyset(&act.sa_mask);
+ sigaddset(&act.sa_mask,signum);
+ sigaction(signum,&act,&oldact);
+#else /* !HAVE_SIGACTION */
+ /* FIXME: need to handle sigvec and systems with broken signal() */
+ signal(signum, handler);
+#endif
+}
+
+static sig_atomic_t gotintr;
+static int in_fd = -1;
+
+/***************************************************************
+ Signal function to tell us were ^C'ed.
+****************************************************************/
+
+static void gotintr_sig(void)
+{
+ gotintr = 1;
+ if (in_fd != -1)
+ close(in_fd); /* Safe way to force a return. */
+ in_fd = -1;
+}
+
+char *rep_getpass(const char *prompt)
+{
+ FILE *in, *out;
+ int echo_off;
+ static char buf[256];
+ static size_t bufsize = sizeof(buf);
+ size_t nread;
+
+ /* Catch problematic signals */
+ catch_signal(SIGINT, SIGNAL_CAST gotintr_sig);
+
+ /* Try to write to and read from the terminal if we can.
+ If we can't open the terminal, use stderr and stdin. */
+
+ in = fopen ("/dev/tty", "w+");
+ if (in == NULL) {
+ in = stdin;
+ out = stderr;
+ } else {
+ out = in;
+ }
+
+ setvbuf(in, NULL, _IONBF, 0);
+
+ /* Turn echoing off if it is on now. */
+
+ if (tcgetattr (fileno (in), &t) == 0) {
+ if (ECHO_IS_ON(t)) {
+ TURN_ECHO_OFF(t);
+ echo_off = tcsetattr (fileno (in), TCSAFLUSH, &t) == 0;
+ TURN_ECHO_ON(t);
+ } else {
+ echo_off = 0;
+ }
+ } else {
+ echo_off = 0;
+ }
+
+ /* Write the prompt. */
+ fputs(prompt, out);
+ fflush(out);
+
+ /* Read the password. */
+ buf[0] = 0;
+ if (!gotintr) {
+ in_fd = fileno(in);
+ if (fgets(buf, bufsize, in) == NULL) {
+ buf[0] = 0;
+ }
+ }
+ nread = strlen(buf);
+ if (nread) {
+ if (buf[nread - 1] == '\n')
+ buf[nread - 1] = '\0';
+ }
+
+ /* Restore echoing. */
+ if (echo_off) {
+ if (gotintr && in_fd == -1) {
+ in = fopen ("/dev/tty", "w+");
+ }
+ if (in != NULL)
+ tcsetattr (fileno (in), TCSANOW, &t);
+ }
+
+ fprintf(out, "\n");
+ fflush(out);
+
+ if (in && in != stdin) /* We opened the terminal; now close it. */
+ fclose(in);
+
+ /* Catch problematic signals */
+ catch_signal(SIGINT, SIGNAL_CAST SIG_DFL);
+
+ if (gotintr) {
+ printf("Interupted by signal.\n");
+ fflush(stdout);
+ exit(1);
+ }
+ return buf;
+}
diff --git a/source3/lib/replace/getpass.m4 b/source3/lib/replace/getpass.m4
new file mode 100644
index 0000000000..b93817f9d3
--- /dev/null
+++ b/source3/lib/replace/getpass.m4
@@ -0,0 +1,24 @@
+AC_CHECK_FUNC(getpass, libreplace_cv_HAVE_GETPASS=yes)
+AC_CHECK_FUNC(getpassphrase, libreplace_cv_HAVE_GETPASSPHRASE=yes)
+if test x"$libreplace_cv_HAVE_GETPASS" = x"yes" -a x"$libreplace_cv_HAVE_GETPASSPHRASE" = x"yes"; then
+ AC_DEFINE(REPLACE_GETPASS_BY_GETPASSPHRASE, 1, [getpass returns <9 chars where getpassphrase returns <265 chars])
+ AC_DEFINE(REPLACE_GETPASS,1,[Whether getpass should be replaced])
+ LIBREPLACEOBJ="${LIBREPLACEOBJ} getpass.o"
+else
+
+AC_CACHE_CHECK([whether getpass should be replaced],libreplace_cv_REPLACE_GETPASS,[
+SAVE_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS -I$libreplacedir/"
+AC_TRY_COMPILE([
+#include "confdefs.h"
+#define NO_CONFIG_H
+#include "$libreplacedir/getpass.c"
+],[],libreplace_cv_REPLACE_GETPASS=yes,libreplace_cv_REPLACE_GETPASS=no)
+CPPFLAGS="$SAVE_CPPFLAGS"
+])
+if test x"$libreplace_cv_REPLACE_GETPASS" = x"yes"; then
+ AC_DEFINE(REPLACE_GETPASS,1,[Whether getpass should be replaced])
+ LIBREPLACEOBJ="${LIBREPLACEOBJ} getpass.o"
+fi
+
+fi
diff --git a/source3/lib/replace/inet_aton.c b/source3/lib/replace/inet_aton.c
new file mode 100644
index 0000000000..c6b3bb11a7
--- /dev/null
+++ b/source3/lib/replace/inet_aton.c
@@ -0,0 +1,33 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * replacement functions
+ * Copyright (C) Michael Adam <obnox@samba.org> 2008
+ *
+ * ** NOTE! The following LGPL license applies to the replace
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/network.h"
+
+/**
+ * We know that we have inet_pton from earlier libreplace checks.
+ */
+int rep_inet_aton(const char *src, struct in_addr *dst)
+{
+ return (inet_pton(AF_INET, src, dst) > 0) ? 1 : 0;
+}
diff --git a/source3/lib/replace/inet_ntoa.c b/source3/lib/replace/inet_ntoa.c
new file mode 100644
index 0000000000..e3b80ebef8
--- /dev/null
+++ b/source3/lib/replace/inet_ntoa.c
@@ -0,0 +1,39 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * replacement routines for broken systems
+ * Copyright (C) Andrew Tridgell 2003
+ * Copyright (C) Michael Adam 2008
+ *
+ * ** NOTE! The following LGPL license applies to the replace
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/network.h"
+
+/**
+ * NOTE: this is not thread safe, but it can't be, either
+ * since it returns a pointer to static memory.
+ */
+char *rep_inet_ntoa(struct in_addr ip)
+{
+ uint8_t *p = (uint8_t *)&ip.s_addr;
+ static char buf[18];
+ slprintf(buf, 17, "%d.%d.%d.%d",
+ (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
+ return buf;
+}
diff --git a/source3/lib/replace/inet_ntop.c b/source3/lib/replace/inet_ntop.c
new file mode 100644
index 0000000000..fb3d8e90c8
--- /dev/null
+++ b/source3/lib/replace/inet_ntop.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 1996-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#include "replace.h"
+#include "system/network.h"
+
+#define NS_INT16SZ 2
+#define NS_IN6ADDRSZ 16
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static const char *inet_ntop4(const unsigned char *src, char *dst,
+ socklen_t size);
+
+#ifdef AF_INET6
+static const char *inet_ntop6(const unsigned char *src, char *dst,
+ socklen_t size);
+#endif
+
+/* char *
+ * isc_net_ntop(af, src, dst, size)
+ * convert a network format address to presentation format.
+ * return:
+ * pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ * Paul Vixie, 1996.
+ */
+const char *
+rep_inet_ntop(int af, const void *src, char *dst, socklen_t size)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_ntop4(src, dst, size));
+#ifdef AF_INET6
+ case AF_INET6:
+ return (inet_ntop6(src, dst, size));
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+ /* NOTREACHED */
+}
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ * format an IPv4 address
+ * return:
+ * `dst' (as a const)
+ * notes:
+ * (1) uses no statics
+ * (2) takes a unsigned char* not an in_addr as input
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(const unsigned char *src, char *dst, socklen_t size)
+{
+ static const char *fmt = "%u.%u.%u.%u";
+ char tmp[sizeof "255.255.255.255"];
+ size_t len;
+
+ len = snprintf(tmp, sizeof tmp, fmt, src[0], src[1], src[2], src[3]);
+ if (len >= size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ memcpy(dst, tmp, len + 1);
+
+ return (dst);
+}
+
+/* const char *
+ * isc_inet_ntop6(src, dst, size)
+ * convert IPv6 binary address into presentation (printable) format
+ * author:
+ * Paul Vixie, 1996.
+ */
+#ifdef AF_INET6
+static const char *
+inet_ntop6(const unsigned char *src, char *dst, socklen_t size)
+{
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+ struct { int base, len; } best, cur;
+ unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
+ int i, inc;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof words);
+ for (i = 0; i < NS_IN6ADDRSZ; i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ best.len = 0;
+ cur.base = -1;
+ cur.len = 0;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 &&
+ (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+ if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
+ return (NULL);
+ tp += strlen(tp);
+ break;
+ }
+ inc = snprintf(tp, 5, "%x", words[i]);
+ if (inc >= 5) {
+ abort();
+ }
+ tp += inc;
+ }
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) ==
+ (NS_IN6ADDRSZ / NS_INT16SZ))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) > size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ memcpy(dst, tmp, tp - tmp);
+ return (dst);
+}
+#endif /* AF_INET6 */
diff --git a/source3/lib/replace/inet_pton.c b/source3/lib/replace/inet_pton.c
new file mode 100644
index 0000000000..80e4865ef4
--- /dev/null
+++ b/source3/lib/replace/inet_pton.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 1996-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "replace.h"
+#include "system/network.h"
+
+#define NS_INT16SZ 2
+#define NS_INADDRSZ 4
+#define NS_IN6ADDRSZ 16
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int inet_pton4(const char *src, unsigned char *dst);
+#ifdef AF_INET6
+static int inet_pton6(const char *src, unsigned char *dst);
+#endif
+
+/* int
+ * inet_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ * Paul Vixie, 1996.
+ */
+int
+rep_inet_pton(int af,
+ const char *src,
+ void *dst)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, dst));
+#ifdef AF_INET6
+ case AF_INET6:
+ return (inet_pton6(src, dst));
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(src, dst)
+ const char *src;
+ unsigned char *dst;
+{
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ unsigned char tmp[NS_INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ unsigned int new = *tp * 10 + (pch - digits);
+
+ if (new > 255)
+ return (0);
+ *tp = new;
+ if (! saw_digit) {
+ if (++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return (0);
+ }
+ if (octets < 4)
+ return (0);
+ memcpy(dst, tmp, NS_INADDRSZ);
+ return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+#ifdef AF_INET6
+static int
+inet_pton6(src, dst)
+ const char *src;
+ unsigned char *dst;
+{
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ unsigned int val;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return (0);
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ }
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += NS_INADDRSZ;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (saw_xdigit) {
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return (0);
+ memcpy(dst, tmp, NS_IN6ADDRSZ);
+ return (1);
+}
+#endif
diff --git a/source3/lib/replace/install-sh b/source3/lib/replace/install-sh
new file mode 100755
index 0000000000..58719246f0
--- /dev/null
+++ b/source3/lib/replace/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/source3/lib/replace/libreplace.m4 b/source3/lib/replace/libreplace.m4
new file mode 100644
index 0000000000..71fa041672
--- /dev/null
+++ b/source3/lib/replace/libreplace.m4
@@ -0,0 +1,303 @@
+AC_DEFUN_ONCE(AC_LIBREPLACE_LOCATION_CHECKS,
+[
+echo "LIBREPLACE_LOCATION_CHECKS: START"
+
+dnl find the libreplace sources. This is meant to work both for
+dnl libreplace standalone builds, and builds of packages using libreplace
+libreplacedir=""
+libreplacepaths="$srcdir $srcdir/lib/replace $srcdir/libreplace $srcdir/../libreplace $srcdir/../replace"
+for d in $libreplacepaths; do
+ if test -f "$d/replace.c"; then
+ libreplacedir="$d"
+ AC_SUBST(libreplacedir)
+ break;
+ fi
+done
+if test x"$libreplacedir" = "x"; then
+ AC_MSG_ERROR([cannot find libreplace in $libreplacepaths])
+fi
+LIBREPLACEOBJ="replace.o"
+AC_SUBST(LIBREPLACEOBJ)
+
+AC_CANONICAL_BUILD
+AC_CANONICAL_HOST
+AC_CANONICAL_TARGET
+
+echo "LIBREPLACE_LOCATION_CHECKS: END"
+]) dnl end AC_LIBREPLACE_LOCATION_CHECKS
+
+
+AC_DEFUN_ONCE(AC_LIBREPLACE_BROKEN_CHECKS,
+[
+echo "LIBREPLACE_BROKEN_CHECKS: START"
+
+dnl find the libreplace sources. This is meant to work both for
+dnl libreplace standalone builds, and builds of packages using libreplace
+libreplacedir=""
+for d in "$srcdir" "$srcdir/lib/replace" "$srcdir/libreplace" "$srcdir/../libreplace" "$srcdir/../replace"; do
+ if test -f "$d/replace.c"; then
+ libreplacedir="$d"
+ AC_SUBST(libreplacedir)
+ break;
+ fi
+done
+LIBREPLACEOBJ="replace.o"
+AC_SUBST(LIBREPLACEOBJ)
+
+LIBREPLACEOBJ="${LIBREPLACEOBJ} snprintf.o"
+
+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(loff_t,off_t)
+AC_CHECK_TYPE(offset_t,loff_t)
+
+AC_FUNC_MEMCMP
+
+AC_CHECK_FUNCS(pipe strftime srandom random srand rand usleep setbuffer lstat getpgrp)
+
+AC_CHECK_HEADERS(stdbool.h stdint.h sys/select.h)
+AC_CHECK_HEADERS(setjmp.h)
+
+LIBREPLACE_PROVIDE_HEADER([stdint.h])
+LIBREPLACE_PROVIDE_HEADER([stdbool.h])
+
+AC_CHECK_TYPE(bool,
+[AC_DEFINE(HAVE_BOOL, 1, [Whether the bool type is available])],,
+[
+AC_INCLUDES_DEFAULT
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif]
+)
+
+AC_CHECK_TYPE(_Bool,
+[AC_DEFINE(HAVE__Bool, 1, [Whether the _Bool type is available])],,
+[
+AC_INCLUDES_DEFAULT
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif]
+)
+
+AC_CACHE_CHECK([for working mmap],libreplace_cv_HAVE_MMAP,[
+AC_TRY_RUN([#include "$libreplacedir/test/shared_mmap.c"],
+ libreplace_cv_HAVE_MMAP=yes,libreplace_cv_HAVE_MMAP=no,libreplace_cv_HAVE_MMAP=cross)])
+if test x"$libreplace_cv_HAVE_MMAP" = x"yes"; then
+ AC_DEFINE(HAVE_MMAP,1,[Whether mmap works])
+fi
+
+
+AC_CHECK_HEADERS(sys/syslog.h syslog.h)
+AC_CHECK_HEADERS(sys/time.h time.h)
+AC_CHECK_HEADERS(stdarg.h vararg.h)
+AC_CHECK_HEADERS(sys/mount.h mntent.h)
+AC_CHECK_HEADERS(stropts.h)
+
+AC_CHECK_FUNCS(seteuid setresuid setegid setresgid chroot bzero strerror)
+AC_CHECK_FUNCS(vsyslog setlinebuf mktime ftruncate chsize rename)
+AC_CHECK_FUNCS(waitpid strlcpy strlcat initgroups memmove strdup)
+AC_CHECK_FUNCS(pread pwrite strndup strcasestr strtok_r mkdtemp)
+AC_CHECK_FUNCS(isatty)
+AC_HAVE_DECL(setresuid, [#include <unistd.h>])
+AC_HAVE_DECL(setresgid, [#include <unistd.h>])
+AC_HAVE_DECL(errno, [#include <errno.h>])
+
+AC_CACHE_CHECK([for secure mkstemp],libreplace_cv_HAVE_SECURE_MKSTEMP,[
+AC_TRY_RUN([#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+main() {
+ struct stat st;
+ char tpl[20]="/tmp/test.XXXXXX";
+ int fd = mkstemp(tpl);
+ if (fd == -1) exit(1);
+ unlink(tpl);
+ if (fstat(fd, &st) != 0) exit(1);
+ if ((st.st_mode & 0777) != 0600) exit(1);
+ exit(0);
+}],
+libreplace_cv_HAVE_SECURE_MKSTEMP=yes,
+libreplace_cv_HAVE_SECURE_MKSTEMP=no,
+libreplace_cv_HAVE_SECURE_MKSTEMP=cross)])
+if test x"$libreplace_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then
+ AC_DEFINE(HAVE_SECURE_MKSTEMP,1,[Whether mkstemp is secure])
+fi
+
+dnl Provided by snprintf.c:
+AC_CHECK_HEADERS(stdio.h strings.h)
+AC_CHECK_DECLS([snprintf, vsnprintf, asprintf, vasprintf])
+AC_CHECK_FUNCS(snprintf vsnprintf asprintf vasprintf)
+
+AC_CACHE_CHECK([for C99 vsnprintf],libreplace_cv_HAVE_C99_VSNPRINTF,[
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+void foo(const char *format, ...) {
+ va_list ap;
+ int len;
+ char buf[20];
+ long long l = 1234567890;
+ l *= 100;
+
+ va_start(ap, format);
+ len = vsnprintf(buf, 0, format, ap);
+ va_end(ap);
+ if (len != 5) exit(1);
+
+ va_start(ap, format);
+ len = vsnprintf(0, 0, format, ap);
+ va_end(ap);
+ if (len != 5) exit(2);
+
+ if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(3);
+
+ if (snprintf(buf, 20, "%lld", l) != 12 || strcmp(buf, "123456789000") != 0) exit(4);
+ if (snprintf(buf, 20, "%zu", 123456789) != 9 || strcmp(buf, "123456789") != 0) exit(5);
+ if (snprintf(buf, 20, "%2\$d %1\$d", 3, 4) != 3 || strcmp(buf, "4 3") != 0) exit(6);
+ if (snprintf(buf, 20, "%s", 0) < 3) exit(7);
+
+ exit(0);
+}
+main() { foo("hello"); }
+],
+libreplace_cv_HAVE_C99_VSNPRINTF=yes,libreplace_cv_HAVE_C99_VSNPRINTF=no,libreplace_cv_HAVE_C99_VSNPRINTF=cross)])
+if test x"$libreplace_cv_HAVE_C99_VSNPRINTF" = x"yes"; then
+ AC_DEFINE(HAVE_C99_VSNPRINTF,1,[Whether there is a C99 compliant vsnprintf])
+fi
+
+
+dnl VA_COPY
+AC_CACHE_CHECK([for va_copy],libreplace_cv_HAVE_VA_COPY,[
+AC_TRY_LINK([#include <stdarg.h>
+va_list ap1,ap2;], [va_copy(ap1,ap2);],
+libreplace_cv_HAVE_VA_COPY=yes,libreplace_cv_HAVE_VA_COPY=no)])
+if test x"$libreplace_cv_HAVE_VA_COPY" = x"yes"; then
+ AC_DEFINE(HAVE_VA_COPY,1,[Whether va_copy() is available])
+fi
+
+if test x"$libreplace_cv_HAVE_VA_COPY" != x"yes"; then
+AC_CACHE_CHECK([for __va_copy],libreplace_cv_HAVE___VA_COPY,[
+AC_TRY_LINK([#include <stdarg.h>
+va_list ap1,ap2;], [__va_copy(ap1,ap2);],
+libreplace_cv_HAVE___VA_COPY=yes,libreplace_cv_HAVE___VA_COPY=no)])
+if test x"$libreplace_cv_HAVE___VA_COPY" = x"yes"; then
+ AC_DEFINE(HAVE___VA_COPY,1,[Whether __va_copy() is available])
+fi
+fi
+
+dnl __FUNCTION__ macro
+AC_CACHE_CHECK([for __FUNCTION__ macro],libreplace_cv_HAVE_FUNCTION_MACRO,[
+AC_TRY_COMPILE([#include <stdio.h>], [printf("%s\n", __FUNCTION__);],
+libreplace_cv_HAVE_FUNCTION_MACRO=yes,libreplace_cv_HAVE_FUNCTION_MACRO=no)])
+if test x"$libreplace_cv_HAVE_FUNCTION_MACRO" = x"yes"; then
+ AC_DEFINE(HAVE_FUNCTION_MACRO,1,[Whether there is a __FUNCTION__ macro])
+else
+ dnl __func__ macro
+ AC_CACHE_CHECK([for __func__ macro],libreplace_cv_HAVE_func_MACRO,[
+ AC_TRY_COMPILE([#include <stdio.h>], [printf("%s\n", __func__);],
+ libreplace_cv_HAVE_func_MACRO=yes,libreplace_cv_HAVE_func_MACRO=no)])
+ if test x"$libreplace_cv_HAVE_func_MACRO" = x"yes"; then
+ AC_DEFINE(HAVE_func_MACRO,1,[Whether there is a __func__ macro])
+ fi
+fi
+
+AC_CHECK_HEADERS([sys/param.h limits.h])
+
+AC_CHECK_TYPE(comparison_fn_t,
+[AC_DEFINE(HAVE_COMPARISON_FN_T, 1,[Whether or not we have comparison_fn_t])])
+
+AC_HAVE_DECL(setenv, [#include <stdlib.h>])
+AC_CHECK_FUNCS(setenv unsetenv)
+
+AC_CHECK_FUNCS(strnlen)
+AC_CHECK_FUNCS(strtoull __strtoull strtouq strtoll __strtoll strtoq)
+
+# this test disabled as we don't actually need __VA_ARGS__ yet
+AC_TRY_CPP([
+#define eprintf(...) fprintf(stderr, __VA_ARGS__)
+eprintf("bla", "bar");
+], AC_DEFINE(HAVE__VA_ARGS__MACRO, 1, [Whether the __VA_ARGS__ macro is available]))
+
+
+AC_CACHE_CHECK([for sig_atomic_t type],libreplace_cv_sig_atomic_t, [
+ AC_TRY_COMPILE([
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#include <signal.h>],[sig_atomic_t i = 0],
+ libreplace_cv_sig_atomic_t=yes,libreplace_cv_sig_atomic_t=no)])
+if test x"$libreplace_cv_sig_atomic_t" = x"yes"; then
+ AC_DEFINE(HAVE_SIG_ATOMIC_T_TYPE,1,[Whether we have the atomic_t variable type])
+fi
+
+
+AC_CACHE_CHECK([for O_DIRECT flag to open(2)],libreplace_cv_HAVE_OPEN_O_DIRECT,[
+AC_TRY_COMPILE([
+#include <unistd.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif],
+[int fd = open("/dev/null", O_DIRECT);],
+libreplace_cv_HAVE_OPEN_O_DIRECT=yes,libreplace_cv_HAVE_OPEN_O_DIRECT=no)])
+if test x"$libreplace_cv_HAVE_OPEN_O_DIRECT" = x"yes"; then
+ AC_DEFINE(HAVE_OPEN_O_DIRECT,1,[Whether the open(2) accepts O_DIRECT])
+fi
+
+
+dnl Check if the C compiler understands volatile (it should, being ANSI).
+AC_CACHE_CHECK([that the C compiler understands volatile],libreplace_cv_volatile, [
+ AC_TRY_COMPILE([#include <sys/types.h>],[volatile int i = 0],
+ libreplace_cv_volatile=yes,libreplace_cv_volatile=no)])
+if test x"$libreplace_cv_volatile" = x"yes"; then
+ AC_DEFINE(HAVE_VOLATILE, 1, [Whether the C compiler understands volatile])
+fi
+
+m4_include(system/config.m4)
+
+m4_include(dlfcn.m4)
+m4_include(getpass.m4)
+m4_include(strptime.m4)
+m4_include(win32.m4)
+m4_include(timegm.m4)
+m4_include(repdir.m4)
+
+AC_CHECK_FUNCS([syslog printf memset memcpy],,[AC_MSG_ERROR([Required function not found])])
+
+echo "LIBREPLACE_BROKEN_CHECKS: END"
+]) dnl end AC_LIBREPLACE_BROKEN_CHECKS
+
+AC_DEFUN_ONCE(AC__LIBREPLACE_ALL_CHECKS_START,
+[
+#LIBREPLACE_ALL_CHECKS: START"
+])
+AC_DEFUN_ONCE(AC__LIBREPLACE_ALL_CHECKS_END,
+[
+#LIBREPLACE_ALL_CHECKS: END"
+])
+m4_define(AC_LIBREPLACE_ALL_CHECKS,
+[
+AC__LIBREPLACE_ALL_CHECKS_START
+AC_LIBREPLACE_LOCATION_CHECKS
+AC_LIBREPLACE_CC_CHECKS
+AC_LIBREPLACE_BROKEN_CHECKS
+AC__LIBREPLACE_ALL_CHECKS_END
+CFLAGS="$CFLAGS -I$libreplacedir"
+])
+
+m4_include(libreplace_cc.m4)
+m4_include(libreplace_ld.m4)
+m4_include(libreplace_network.m4)
+m4_include(libreplace_macros.m4)
+
+m4_ifndef([AC_USE_SYSTEM_EXTENSIONS],[m4_include(autoconf-2.60.m4)])
diff --git a/source3/lib/replace/libreplace_cc.m4 b/source3/lib/replace/libreplace_cc.m4
new file mode 100644
index 0000000000..30c63f2f05
--- /dev/null
+++ b/source3/lib/replace/libreplace_cc.m4
@@ -0,0 +1,182 @@
+
+AC_DEFUN_ONCE(AC__LIBREPLACE_ONLY_CC_CHECKS_START,
+[
+echo "LIBREPLACE_CC_CHECKS: START"
+])
+
+AC_DEFUN_ONCE(AC__LIBREPLACE_ONLY_CC_CHECKS_END,
+[
+echo "LIBREPLACE_CC_CHECKS: END"
+])
+
+dnl
+dnl
+dnl AC_LIBREPLACE_CC_CHECKS
+dnl
+dnl Note: we need to use m4_define instead of AC_DEFUN because
+dnl of the ordering of tests
+dnl
+dnl
+m4_define(AC_LIBREPLACE_CC_CHECKS,
+[
+AC__LIBREPLACE_ONLY_CC_CHECKS_START
+
+dnl stop the C89 attempt by autoconf - if autoconf detects -Ae it will enable it
+dnl which conflicts with C99 on HPUX
+ac_cv_prog_cc_Ae=no
+
+savedCFLAGS=$CFLAGS
+AC_PROG_CC
+CFLAGS=$savedCFLAGS
+
+dnl don't try for C99 if we are using gcc, as otherwise we
+dnl lose immediate structure constants
+if test x"$GCC" != x"yes" ; then
+AC_PROG_CC_C99
+fi
+
+if test x"$GCC" = x"yes" ; then
+ AC_MSG_CHECKING([for version of gcc])
+ GCC_VERSION=`$CC -dumpversion`
+ AC_MSG_RESULT(${GCC_VERSION})
+fi
+AC_USE_SYSTEM_EXTENSIONS
+AC_C_BIGENDIAN
+AC_C_INLINE
+LIBREPLACE_C99_STRUCT_INIT([],[AC_MSG_WARN([c99 structure initializer are not supported])])
+
+AC_PROG_INSTALL
+
+AC_ISC_POSIX
+AC_N_DEFINE(_XOPEN_SOURCE_EXTENDED)
+
+AC_SYS_LARGEFILE
+
+dnl Add #include for broken IRIX header files
+case "$host_os" in
+ *irix6*) AC_ADD_INCLUDE(<standards.h>)
+ ;;
+ *hpux*)
+ # mmap on HPUX is completely broken...
+ AC_DEFINE(MMAP_BLACKLIST, 1, [Whether MMAP is broken])
+ if test "`uname -r`" = "B.11.00" -o "`uname -r`" = "B.11.11"; then
+ AC_MSG_WARN([Enabling HPUX 11.00/11.11 header bug workaround])
+ CFLAGS="$CFLAGS -Dpread=pread64 -Dpwrite=pwrite64"
+ fi
+ if test "`uname -r`" = "B.11.23"; then
+ AC_MSG_WARN([Enabling HPUX 11.23 machine/sys/getppdp.h bug workaround])
+ CFLAGS="$CFLAGS -D_MACHINE_SYS_GETPPDP_INCLUDED"
+ fi
+ ;;
+ *aix*)
+ AC_DEFINE(BROKEN_STRNDUP, 1, [Whether strndup is broken])
+ AC_DEFINE(BROKEN_STRNLEN, 1, [Whether strnlen is broken])
+ if test "${GCC}" != "yes"; then
+ ## for funky AIX compiler using strncpy()
+ CFLAGS="$CFLAGS -D_LINUX_SOURCE_COMPAT -qmaxmem=32000"
+ fi
+ ;;
+ *osf*)
+ # this brings in socklen_t
+ AC_N_DEFINE(_XOPEN_SOURCE,600)
+ AC_N_DEFINE(_OSF_SOURCE)
+ ;;
+ #
+ # VOS may need to have POSIX support and System V compatibility enabled.
+ #
+ *vos*)
+ case "$CFLAGS" in
+ *-D_POSIX_C_SOURCE*);;
+ *)
+ CFLAGS="$CFLAGS -D_POSIX_C_SOURCE=200112L"
+ AC_DEFINE(_POSIX_C_SOURCE, 200112L, [Whether to enable POSIX support])
+ ;;
+ esac
+ case "$CFLAGS" in
+ *-D_SYSV*|*-D_SVID_SOURCE*);;
+ *)
+ CFLAGS="$CFLAGS -D_SYSV"
+ AC_DEFINE(_SYSV, 1, [Whether to enable System V compatibility])
+ ;;
+ esac
+ ;;
+esac
+
+
+
+AC_CHECK_HEADERS([standards.h])
+
+# Solaris needs HAVE_LONG_LONG defined
+AC_CHECK_TYPES(long long)
+
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(char)
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(long long)
+
+AC_CHECK_TYPE(uint_t, unsigned int)
+AC_CHECK_TYPE(int8_t, char)
+AC_CHECK_TYPE(uint8_t, unsigned char)
+AC_CHECK_TYPE(int16_t, short)
+AC_CHECK_TYPE(uint16_t, unsigned short)
+
+if test $ac_cv_sizeof_int -eq 4 ; then
+AC_CHECK_TYPE(int32_t, int)
+AC_CHECK_TYPE(uint32_t, unsigned int)
+elif test $ac_cv_size_long -eq 4 ; then
+AC_CHECK_TYPE(int32_t, long)
+AC_CHECK_TYPE(uint32_t, unsigned long)
+else
+AC_MSG_ERROR([LIBREPLACE no 32-bit type found])
+fi
+
+AC_CHECK_TYPE(int64_t, long long)
+AC_CHECK_TYPE(uint64_t, unsigned long long)
+
+AC_CHECK_TYPE(size_t, unsigned int)
+AC_CHECK_TYPE(ssize_t, int)
+
+AC_CHECK_SIZEOF(off_t)
+AC_CHECK_SIZEOF(size_t)
+AC_CHECK_SIZEOF(ssize_t)
+
+AC_CHECK_TYPE(intptr_t, long long)
+AC_CHECK_TYPE(uintptr_t, unsigned long long)
+AC_CHECK_TYPE(ptrdiff_t, unsigned long long)
+
+if test x"$ac_cv_type_long_long" != x"yes";then
+ AC_MSG_ERROR([LIBREPLACE needs type 'long long'])
+fi
+if test $ac_cv_sizeof_long_long -lt 8;then
+ AC_MSG_ERROR([LIBREPLACE needs sizeof(long long) >= 8])
+fi
+
+############################################
+# check if the compiler can do immediate structures
+AC_SUBST(libreplace_cv_immediate_structures)
+AC_CACHE_CHECK([for immediate structures],libreplace_cv_immediate_structures,[
+ AC_TRY_COMPILE([
+ #include <stdio.h>
+ ],[
+ typedef struct {unsigned x;} FOOBAR;
+ #define X_FOOBAR(x) ((FOOBAR) { x })
+ #define FOO_ONE X_FOOBAR(1)
+ FOOBAR f = FOO_ONE;
+ static const struct {
+ FOOBAR y;
+ } f2[] = {
+ {FOO_ONE}
+ };
+ static const FOOBAR f3[] = {FOO_ONE};
+ ],
+ libreplace_cv_immediate_structures=yes,
+ libreplace_cv_immediate_structures=no,
+ libreplace_cv_immediate_structures=cross)
+])
+if test x"$libreplace_cv_immediate_structures" = x"yes"; then
+ AC_DEFINE(HAVE_IMMEDIATE_STRUCTURES,1,[Whether the compiler supports immediate structures])
+fi
+
+AC__LIBREPLACE_ONLY_CC_CHECKS_END
+]) dnl end AC_LIBREPLACE_CC_CHECKS
diff --git a/source3/lib/replace/libreplace_ld.m4 b/source3/lib/replace/libreplace_ld.m4
new file mode 100644
index 0000000000..81bde46219
--- /dev/null
+++ b/source3/lib/replace/libreplace_ld.m4
@@ -0,0 +1,319 @@
+#
+# This offers a nice overview how to build shared libraries on all platforms
+# http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
+#
+
+AC_DEFUN([AC_LIBREPLACE_STLD],
+[
+ AC_PATH_PROG(PROG_AR, ar)
+
+ STLD=${PROG_AR}
+
+ AC_SUBST(STLD)
+])
+
+AC_DEFUN([AC_LIBREPLACE_STLD_FLAGS],
+[
+ STLD_FLAGS="-rcs"
+ AC_SUBST(STLD_FLAGS)
+])
+
+AC_DEFUN([AC_LD_EXPORT_DYNAMIC],
+[
+saved_LDFLAGS="$LDFLAGS"
+if AC_TRY_COMMAND([${CC-cc} $CFLAGS -Wl,--version 2>&1 | grep "GNU ld" >/dev/null]); then
+ LD_EXPORT_DYNAMIC="-Wl,-export-dynamic"
+else
+ case "$host_os" in
+ hpux* )
+ LD_EXPORT_DYNAMIC="-Wl,-E"
+ ;;
+ *)
+ LD_EXPORT_DYNAMIC=""
+ ;;
+ esac
+fi
+AC_SUBST(LD_EXPORT_DYNAMIC)
+LDFLAGS="$saved_LDFLAGS"
+])
+
+AC_DEFUN([AC_LD_PICFLAG],
+[
+case "$host_os" in
+ *linux*)
+ PICFLAG="-fPIC"
+ ;;
+ *solaris*)
+ if test "${GCC}" = "yes"; then
+ PICFLAG="-fPIC"
+ else
+ PICFLAG="-KPIC"
+ fi
+ ;;
+ *sunos*)
+ PICFLAG="-KPIC" # Is this correct for SunOS
+ ;;
+ *netbsd* | *freebsd* | *dragonfly* )
+ PICFLAG="-fPIC -DPIC"
+ ;;
+ *openbsd*)
+ PICFLAG="-fPIC"
+ ;;
+ *irix*)
+ if test "${GCC}" = "yes"; then
+ PICFLAG="-fPIC"
+ else
+ PICFLAG="-KPIC"
+ fi
+ ;;
+ *aix*)
+ # as AIX code is always position independent...
+ PICFLAG="-O2"
+ ;;
+ *hpux*)
+ if test $ac_cv_prog_cc_Ae = yes; then
+ PICFLAG="+z +ESnolit"
+ elif test "${GCC}" = "yes"; then
+ PICFLAG="-fPIC"
+ fi
+ if test "$host_cpu" = "ia64"; then
+ PICFLAG="+z"
+ fi
+ ;;
+ *osf*)
+ PICFLAG="-fPIC"
+ ;;
+ *unixware*)
+ PICFLAG="-KPIC"
+ ;;
+ *darwin*)
+ PICFLAG="-fno-common"
+ ;;
+esac
+AC_SUBST(PICFLAG)
+])
+
+AC_DEFUN([AC_LIBREPLACE_LD_SHLIB_LINKER],
+[
+ LD_SHLIB_LINKER="${CC}"
+
+ case "$host_os" in
+ *irix*)
+ LD_SHLIB_LINKER="${PROG_LD}"
+ ;;
+ esac
+
+ AC_SUBST(LD_SHLIB_LINKER)
+])
+
+AC_DEFUN([AC_LIBREPLACE_LD_SHLIB_FLAGS],
+[
+ LD_SHLIB_FLAGS="-shared"
+
+ case "$host_os" in
+ *linux*)
+ LD_SHLIB_FLAGS="-shared -Wl,-Bsymbolic"
+ ;;
+ *solaris*)
+ LD_SHLIB_FLAGS="-G"
+ if test "${GCC}" = "no"; then
+ ## ${CFLAGS} added for building 64-bit shared
+ ## libs using Sun's Compiler
+ LD_SHLIB_FLAGS="-G \${CFLAGS}"
+ fi
+ ;;
+ *sunos*)
+ LD_SHLIB_FLAGS="-G"
+ ;;
+ *irix*)
+ LD_SHLIB_FLAGS="-shared"
+ ;;
+ *aix*)
+ LD_SHLIB_FLAGS="-Wl,-G,-bexpall,-bbigtoc"
+ ;;
+ *hpux*)
+ if test "${GCC}" = "yes"; then
+ LD_SHLIB_FLAGS="-shared"
+ else
+ LD_SHLIB_FLAGS="-b"
+ fi
+ ;;
+ *osf*)
+ LD_SHLIB_FLAGS="-shared"
+ ;;
+ *darwin*)
+ LD_SHLIB_FLAGS="-dynamiclib -Wl,-search_paths_first"
+ ;;
+ esac
+
+ AC_SUBST(LD_SHLIB_FLAGS)
+])
+
+AC_DEFUN([AC_LIBREPLACE_LD_SHLIB_DISALLOW_UNDEF_FLAG],
+[
+ LD_SHLIB_DISALLOW_UNDEF_FLAG=""
+
+ #
+ # TODO: enforce error not only warnings
+ #
+ # NOTE: -Wl,--no-allow-shlib-undefined isn't what we want...
+ # as it bails out on broken system libraries
+ #
+ case "$host_os" in
+ *osf*)
+ LD_SHLIB_DISALLOW_UNDEF_FLAG="-warning_unresolved"
+ ;;
+ *darwin*)
+ LD_SHLIB_DISALLOW_UNDEF_FLAG="-undefined error"
+ ;;
+ esac
+
+ AC_SUBST(LD_SHLIB_DISALLOW_UNDEF_FLAG)
+])
+
+AC_DEFUN([AC_LIBREPLACE_SHLD],
+[
+ AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_LINKER])
+ SHLD="$LD_SHLIB_LINKER"
+ AC_SUBST(SHLD)
+])
+
+AC_DEFUN([AC_LIBREPLACE_SHLD_FLAGS],
+[
+ AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_FLAGS])
+ AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_DISALLOW_UNDEF_FLAG])
+ SHLD_FLAGS="$LD_SHLIB_FLAGS $LD_SHLIB_DISALLOW_UNDEF_FLAG"
+ AC_SUBST(SHLD_FLAGS)
+])
+
+AC_DEFUN([AC_LD_SHLIBEXT],
+[
+ SHLIBEXT="so"
+ case "$host_os" in
+ *hpux*)
+ if test "$host_cpu" = "ia64"; then
+ SHLIBEXT="so"
+ else
+ SHLIBEXT="sl"
+ fi
+ ;;
+ *darwin*)
+ SHLIBEXT="dylib"
+ ;;
+ esac
+ AC_SUBST(SHLIBEXT)
+])
+
+AC_DEFUN([AC_LD_SONAMEFLAG],
+[
+ AC_SUBST(SONAMEFLAG)
+ SONAMEFLAG=""
+ case "$host_os" in
+ *linux*)
+ SONAMEFLAG="-Wl,-soname="
+ ;;
+ *solaris*)
+ SONAMEFLAG="-h "
+ if test "${GCC}" = "yes"; then
+ SONAMEFLAG="-Wl,-soname="
+ fi
+ ;;
+ *sunos*)
+ SONAMEFLAG="-Wl,-h,"
+ ;;
+ *netbsd* | *freebsd* | *dragonfly* )
+ SONAMEFLAG="-Wl,-soname,"
+ ;;
+ *openbsd*)
+ SONAMEFLAG="-Wl,-soname,"
+ ;;
+ *irix*)
+ SONAMEFLAG="-Wl,-soname,"
+ ;;
+ *hpux*)
+ SONAMEFLAG="-Wl,+h,"
+ ;;
+ *osf*)
+ SONAMEFLAG="-Wl,-soname,"
+ ;;
+ *unixware*)
+ SONAMEFLAG="-Wl,-soname,"
+ ;;
+ *darwin*)
+ SONAMEFLAG="#"
+ ;;
+ *aix*)
+ # Not supported
+ SONAMEFLAG="#"
+ ;;
+ esac
+])
+
+AC_DEFUN([AC_LIBREPLACE_MDLD],
+[
+ AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_LINKER])
+ MDLD="$LD_SHLIB_LINKER"
+ AC_SUBST(MDLD)
+])
+
+AC_DEFUN([AC_LIBREPLACE_LD_SHLIB_ALLOW_UNDEF_FLAG],
+[
+ LD_ALLOW_SHLIB_UNDEF_FLAG=""
+
+ case "$host_os" in
+ *linux*)
+ LD_SHLIB_ALLOW_UNDEF_FLAG="-Wl,--allow-shlib-undefined"
+ ;;
+ *osf*)
+ LD_SHLIB_ALLOW_UNDEF_FLAG="-Wl,-expect_unresolved,\"*\""
+ ;;
+ *darwin*)
+ LD_SHLIB_ALLOW_UNDEF_FLAG="-undefined dynamic_lookup"
+ ;;
+ *aix*)
+ LD_SHLIB_ALLOW_UNDEF_FLAG="-Wl,-bnoentry"
+ ;;
+ esac
+
+ AC_SUBST(LD_SHLIB_ALLOW_UNDEF_FLAG)
+])
+
+AC_DEFUN([AC_LIBREPLACE_MDLD_FLAGS],
+[
+ AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_FLAGS])
+ AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_ALLOW_UNDEF_FLAG])
+ MDLD_FLAGS="$LD_SHLIB_FLAGS $LD_SHLIB_ALLOW_UNDEF_FLAG"
+ AC_SUBST(MDLD_FLAGS)
+])
+
+AC_DEFUN([AC_LIBREPLACE_RUNTIME_LIB_PATH_VAR],
+[
+ case "$host_os" in
+ *linux*)
+ LIB_PATH_VAR=LD_LIBRARY_PATH
+ ;;
+ *netbsd*)
+ LIB_PATH_VAR=LD_LIBRARY_PATH
+ ;;
+ *solaris*)
+ LIB_PATH_VAR=LD_LIBRARY_PATH
+ ;;
+ *hpux*)
+ LIB_PATH_VAR=SHLIB_PATH
+ ;;
+ *osf*)
+ LIB_PATH_VAR=LD_LIBRARY_PATH
+ ;;
+ *aix*)
+ LIB_PATH_VAR=LIB_PATH
+ ;;
+ *irix*)
+ LIB_PATH_VAR=LD_LIBRARY_PATH
+ ;;
+ *darwin*)
+ LIB_PATH_VAR=DYLD_LIBRARY_PATH
+ ;;
+ esac
+
+ AC_SUBST(LIB_PATH_VAR)
+])
diff --git a/source3/lib/replace/libreplace_macros.m4 b/source3/lib/replace/libreplace_macros.m4
new file mode 100644
index 0000000000..1856eacf66
--- /dev/null
+++ b/source3/lib/replace/libreplace_macros.m4
@@ -0,0 +1,332 @@
+#
+# This is a collection of useful autoconf macros
+#
+
+############################################
+# Check if the compiler handles c99 struct initialization, and if not try -AC99 and -c99 flags
+# Usage: LIBREPLACE_C99_STRUCT_INIT(success-action,failure-action)
+# changes CFLAGS to add -AC99 or -c99 if needed
+AC_DEFUN([LIBREPLACE_C99_STRUCT_INIT],
+[
+saved_CFLAGS="$CFLAGS";
+c99_init=no
+if test x"$c99_init" = x"no"; then
+ AC_MSG_CHECKING(for C99 designated initializers)
+ CFLAGS="$saved_CFLAGS";
+ AC_TRY_COMPILE([#include <stdio.h>],
+ [ struct foo {int x;char y;};
+ struct foo bar = { .y = 'X', .x = 1 };
+ ],
+ [AC_MSG_RESULT(yes); c99_init=yes],[AC_MSG_RESULT(no)])
+fi
+if test x"$c99_init" = x"no"; then
+ AC_MSG_CHECKING(for C99 designated initializers with -AC99)
+ CFLAGS="$saved_CFLAGS -AC99";
+ AC_TRY_COMPILE([#include <stdio.h>],
+ [ struct foo {int x;char y;};
+ struct foo bar = { .y = 'X', .x = 1 };
+ ],
+ [AC_MSG_RESULT(yes); c99_init=yes],[AC_MSG_RESULT(no)])
+fi
+if test x"$c99_init" = x"no"; then
+ AC_MSG_CHECKING(for C99 designated initializers with -qlanglvl=extc99)
+ CFLAGS="$saved_CFLAGS -qlanglvl=extc99";
+ AC_TRY_COMPILE([#include <stdio.h>],
+ [ struct foo {int x;char y;};
+ struct foo bar = { .y = 'X', .x = 1 };
+ ],
+ [AC_MSG_RESULT(yes); c99_init=yes],[AC_MSG_RESULT(no)])
+fi
+if test x"$c99_init" = x"no"; then
+ AC_MSG_CHECKING(for C99 designated initializers with -qlanglvl=stdc99)
+ CFLAGS="$saved_CFLAGS -qlanglvl=stdc99";
+ AC_TRY_COMPILE([#include <stdio.h>],
+ [ struct foo {int x;char y;};
+ struct foo bar = { .y = 'X', .x = 1 };
+ ],
+ [AC_MSG_RESULT(yes); c99_init=yes],[AC_MSG_RESULT(no)])
+fi
+if test x"$c99_init" = x"no"; then
+ AC_MSG_CHECKING(for C99 designated initializers with -c99)
+ CFLAGS="$saved_CFLAGS -c99"
+ AC_TRY_COMPILE([#include <stdio.h>],
+ [ struct foo {int x;char y;};
+ struct foo bar = { .y = 'X', .x = 1 };
+ ],
+ [AC_MSG_RESULT(yes); c99_init=yes],[AC_MSG_RESULT(no)])
+fi
+
+if test "`uname`" = "HP-UX"; then
+ if test "$ac_cv_c_compiler_gnu" = no; then
+ # special override for broken HP-UX compiler - I can't find a way to test
+ # this properly (its a compiler bug)
+ CFLAGS="$CFLAGS -AC99";
+ c99_init=yes;
+ fi
+fi
+
+if test x"$c99_init" = x"yes"; then
+ saved_CFLAGS=""
+ $1
+else
+ CFLAGS="$saved_CFLAGS"
+ saved_CFLAGS=""
+ $2
+fi
+])
+
+dnl AC_PROG_CC_FLAG(flag)
+AC_DEFUN(AC_PROG_CC_FLAG,
+[AC_CACHE_CHECK(whether ${CC-cc} accepts -$1, ac_cv_prog_cc_$1,
+[echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -$1 -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_$1=yes
+else
+ ac_cv_prog_cc_$1=no
+fi
+rm -f conftest*
+])])
+
+dnl see if a declaration exists for a function or variable
+dnl defines HAVE_function_DECL if it exists
+dnl AC_HAVE_DECL(var, includes)
+AC_DEFUN(AC_HAVE_DECL,
+[
+ AC_CACHE_CHECK([for $1 declaration],ac_cv_have_$1_decl,[
+ AC_TRY_COMPILE([$2],[int i = (int)$1],
+ ac_cv_have_$1_decl=yes,ac_cv_have_$1_decl=no)])
+ if test x"$ac_cv_have_$1_decl" = x"yes"; then
+ AC_DEFINE([HAVE_]translit([$1], [a-z], [A-Z])[_DECL],1,[Whether $1() is available])
+ fi
+])
+
+
+# AC_CHECK_LIB_EXT(LIBRARY, [EXT_LIBS], [FUNCTION],
+# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND],
+# [ADD-ACTION-IF-FOUND],[OTHER-LIBRARIES])
+# ------------------------------------------------------
+#
+# Use a cache variable name containing both the library and function name,
+# because the test really is for library $1 defining function $3, not
+# just for library $1. Separate tests with the same $1 and different $3s
+# may have different results.
+#
+# Note that using directly AS_VAR_PUSHDEF([ac_Lib], [ac_cv_lib_$1_$3])
+# is asking for trouble, since AC_CHECK_LIB($lib, fun) would give
+# ac_cv_lib_$lib_fun, which is definitely not what was meant. Hence
+# the AS_LITERAL_IF indirection.
+#
+# FIXME: This macro is extremely suspicious. It DEFINEs unconditionally,
+# whatever the FUNCTION, in addition to not being a *S macro. Note
+# that the cache does depend upon the function we are looking for.
+#
+# It is on purpose we used `ac_check_lib_ext_save_LIBS' and not just
+# `ac_save_LIBS': there are many macros which don't want to see `LIBS'
+# changed but still want to use AC_CHECK_LIB_EXT, so they save `LIBS'.
+# And ``ac_save_LIBS' is too tempting a name, so let's leave them some
+# freedom.
+AC_DEFUN([AC_CHECK_LIB_EXT],
+[
+AH_CHECK_LIB_EXT([$1])
+ac_check_lib_ext_save_LIBS=$LIBS
+LIBS="-l$1 $$2 $7 $LIBS"
+AS_LITERAL_IF([$1],
+ [AS_VAR_PUSHDEF([ac_Lib_ext], [ac_cv_lib_ext_$1])],
+ [AS_VAR_PUSHDEF([ac_Lib_ext], [ac_cv_lib_ext_$1''])])dnl
+
+m4_ifval([$3],
+ [
+ AH_CHECK_FUNC_EXT([$3])
+ AS_LITERAL_IF([$1],
+ [AS_VAR_PUSHDEF([ac_Lib_func], [ac_cv_lib_ext_$1_$3])],
+ [AS_VAR_PUSHDEF([ac_Lib_func], [ac_cv_lib_ext_$1''_$3])])dnl
+ AC_CACHE_CHECK([for $3 in -l$1], ac_Lib_func,
+ [AC_TRY_LINK_FUNC($3,
+ [AS_VAR_SET(ac_Lib_func, yes);
+ AS_VAR_SET(ac_Lib_ext, yes)],
+ [AS_VAR_SET(ac_Lib_func, no);
+ AS_VAR_SET(ac_Lib_ext, no)])
+ ])
+ AS_IF([test AS_VAR_GET(ac_Lib_func) = yes],
+ [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$3))])dnl
+ AS_VAR_POPDEF([ac_Lib_func])dnl
+ ],[
+ AC_CACHE_CHECK([for -l$1], ac_Lib_ext,
+ [AC_TRY_LINK_FUNC([main],
+ [AS_VAR_SET(ac_Lib_ext, yes)],
+ [AS_VAR_SET(ac_Lib_ext, no)])
+ ])
+ ])
+LIBS=$ac_check_lib_ext_save_LIBS
+
+AS_IF([test AS_VAR_GET(ac_Lib_ext) = yes],
+ [m4_default([$4],
+ [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_LIB$1))
+ case "$$2" in
+ *-l$1*)
+ ;;
+ *)
+ $2="-l$1 $$2"
+ ;;
+ esac])
+ [$6]
+ ],
+ [$5])dnl
+AS_VAR_POPDEF([ac_Lib_ext])dnl
+])# AC_CHECK_LIB_EXT
+
+# AH_CHECK_LIB_EXT(LIBNAME)
+# ---------------------
+m4_define([AH_CHECK_LIB_EXT],
+[AH_TEMPLATE(AS_TR_CPP(HAVE_LIB$1),
+ [Define to 1 if you have the `]$1[' library (-l]$1[).])])
+
+dnl AC_SEARCH_LIBS_EXT(FUNCTION, SEARCH-LIBS, EXT_LIBS,
+dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND],
+dnl [OTHER-LIBRARIES])
+dnl --------------------------------------------------------
+dnl Search for a library defining FUNC, if it's not already available.
+AC_DEFUN([AC_SEARCH_LIBS_EXT],
+[AC_CACHE_CHECK([for library containing $1], [ac_cv_search_ext_$1],
+[
+ac_func_search_ext_save_LIBS=$LIBS
+ac_cv_search_ext_$1=no
+AC_LINK_IFELSE([AC_LANG_CALL([], [$1])],
+ [ac_cv_search_ext_$1="none required"])
+if test "$ac_cv_search_ext_$1" = no; then
+ for ac_lib in $2; do
+ LIBS="-l$ac_lib $$3 $6 $ac_func_search_save_ext_LIBS"
+ AC_LINK_IFELSE([AC_LANG_CALL([], [$1])],
+ [ac_cv_search_ext_$1="-l$ac_lib"
+break])
+ done
+fi
+LIBS=$ac_func_search_ext_save_LIBS])
+AS_IF([test "$ac_cv_search_ext_$1" != no],
+ [test "$ac_cv_search_ext_$1" = "none required" || $3="$ac_cv_search_ext_$1 $$3"
+ $4],
+ [$5])dnl
+])
+
+dnl check for a function in a $LIBS and $OTHER_LIBS libraries variable.
+dnl AC_CHECK_FUNC_EXT(func,OTHER_LIBS,IF-TRUE,IF-FALSE)
+AC_DEFUN([AC_CHECK_FUNC_EXT],
+[
+ AH_CHECK_FUNC_EXT($1)
+ ac_check_func_ext_save_LIBS=$LIBS
+ LIBS="$2 $LIBS"
+ AS_VAR_PUSHDEF([ac_var], [ac_cv_func_ext_$1])dnl
+ AC_CACHE_CHECK([for $1], ac_var,
+ [AC_LINK_IFELSE([AC_LANG_FUNC_LINK_TRY([$1])],
+ [AS_VAR_SET(ac_var, yes)],
+ [AS_VAR_SET(ac_var, no)])])
+ LIBS=$ac_check_func_ext_save_LIBS
+ AS_IF([test AS_VAR_GET(ac_var) = yes],
+ [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_$1])) $3],
+ [$4])dnl
+AS_VAR_POPDEF([ac_var])dnl
+])# AC_CHECK_FUNC
+
+# AH_CHECK_FUNC_EXT(FUNCNAME)
+# ---------------------
+m4_define([AH_CHECK_FUNC_EXT],
+[AH_TEMPLATE(AS_TR_CPP(HAVE_$1),
+ [Define to 1 if you have the `]$1[' function.])])
+
+dnl Define an AC_DEFINE with ifndef guard.
+dnl AC_N_DEFINE(VARIABLE [, VALUE])
+AC_DEFUN([AC_N_DEFINE],
+[
+AH_VERBATIM([$1], [
+#ifndef $1
+# undef $1
+#endif
+])
+
+ cat >>confdefs.h <<\EOF
+#ifndef $1
+[#define] $1 m4_if($#, 1, 1, [$2])
+#endif
+EOF
+])
+
+dnl Add an #include
+dnl AC_ADD_INCLUDE(VARIABLE)
+define(AC_ADD_INCLUDE,
+[cat >> confdefs.h <<\EOF
+[#include] $1
+EOF
+])
+
+dnl remove an #include
+dnl AC_REMOVE_INCLUDE(VARIABLE)
+define(AC_REMOVE_INCLUDE,
+[
+grep -v '[#include] $1' confdefs.h >confdefs.h.tmp
+cat confdefs.h.tmp > confdefs.h
+rm confdefs.h.tmp
+])
+
+dnl remove an #define
+dnl AC_REMOVE_DEFINE(VARIABLE)
+define(AC_REMOVE_DEFINE,
+[
+grep -v '[#define] $1 ' confdefs.h |grep -v '[#define] $1[$]'>confdefs.h.tmp
+cat confdefs.h.tmp > confdefs.h
+rm confdefs.h.tmp
+])
+
+dnl AS_HELP_STRING is not available in autoconf 2.57, and AC_HELP_STRING is deprecated
+dnl in autoconf 2.59, so define AS_HELP_STRING to be AC_HELP_STRING unless it is already
+dnl defined.
+m4_ifdef([AS_HELP_STRING], , [m4_define([AS_HELP_STRING], m4_defn([AC_HELP_STRING]))])
+
+dnl check if the prototype in the header matches the given one
+dnl AC_VERIFY_C_PROTOTYPE(prototype,functionbody,[IF-TRUE].[IF-FALSE],[extraheaders])
+AC_DEFUN(AC_VERIFY_C_PROTOTYPE,
+[AC_CACHE_CHECK([for prototype $1], AS_TR_SH([ac_cv_c_prototype_$1]),
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+ AC_INCLUDES_DEFAULT
+ $5
+ $1
+ {
+ $2
+ }
+ ])],[
+ AS_TR_SH([ac_cv_c_prototype_$1])=yes
+ ],[
+ AS_TR_SH([ac_cv_c_prototype_$1])=no
+ ])
+)
+AS_IF([test $AS_TR_SH([ac_cv_c_prototype_$1]) = yes],[$3],[$4])
+])
+
+AC_DEFUN(LIBREPLACE_PROVIDE_HEADER,
+[AC_CHECK_HEADER([$1],
+ [ AC_CONFIG_COMMANDS(rm-$1, [rm -f $libreplacedir/$1], [libreplacedir=$libreplacedir]) ],
+ [ AC_CONFIG_COMMANDS(mk-$1, [echo "#include \"replace.h\"" > $libreplacedir/$1], [libreplacedir=$libreplacedir]) ]
+ )
+])
+
+dnl AC_HAVE_TYPE(TYPE,INCLUDES)
+AC_DEFUN([AC_HAVE_TYPE], [
+AC_REQUIRE([AC_HEADER_STDC])
+cv=`echo "$1" | sed 'y%./+- %__p__%'`
+AC_MSG_CHECKING(for $1)
+AC_CACHE_VAL([ac_cv_type_$cv],
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+AC_INCLUDES_DEFAULT
+$2]],
+[[$1 foo;]])],
+[eval "ac_cv_type_$cv=yes"],
+[eval "ac_cv_type_$cv=no"]))dnl
+ac_foo=`eval echo \\$ac_cv_type_$cv`
+AC_MSG_RESULT($ac_foo)
+if test "$ac_foo" = yes; then
+ ac_tr_hdr=HAVE_`echo $1 | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'`
+if false; then
+ AC_CHECK_TYPES($1)
+fi
+ AC_DEFINE_UNQUOTED($ac_tr_hdr, 1, [Define if you have type `$1'])
+fi
+])
diff --git a/source3/lib/replace/libreplace_network.m4 b/source3/lib/replace/libreplace_network.m4
new file mode 100644
index 0000000000..4edb55c03a
--- /dev/null
+++ b/source3/lib/replace/libreplace_network.m4
@@ -0,0 +1,377 @@
+AC_DEFUN_ONCE(AC_LIBREPLACE_NETWORK_CHECKS,
+[
+echo "LIBREPLACE_NETWORK_CHECKS: START"
+
+AC_DEFINE(LIBREPLACE_NETWORK_CHECKS, 1, [LIBREPLACE_NETWORK_CHECKS were used])
+LIBREPLACE_NETWORK_OBJS=""
+LIBREPLACE_NETWORK_LIBS=""
+
+AC_CHECK_HEADERS(sys/socket.h netinet/in.h netdb.h arpa/inet.h)
+AC_CHECK_HEADERS(netinet/ip.h netinet/tcp.h netinet/in_systm.h netinet/in_ip.h)
+AC_CHECK_HEADERS(sys/sockio.h sys/un.h)
+
+dnl we need to check that net/if.h really can be used, to cope with hpux
+dnl where including it always fails
+AC_CACHE_CHECK([for usable net/if.h],libreplace_cv_USABLE_NET_IF_H,[
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+ AC_INCLUDES_DEFAULT
+ #if HAVE_SYS_SOCKET_H
+ # include <sys/socket.h>
+ #endif
+ #include <net/if.h>
+ int main(void) {return 0;}])],
+ [libreplace_cv_USABLE_NET_IF_H=yes],
+ [libreplace_cv_USABLE_NET_IF_H=no]
+ )
+])
+if test x"$libreplace_cv_USABLE_NET_IF_H" = x"yes";then
+ AC_DEFINE(HAVE_NET_IF_H, 1, usability of net/if.h)
+fi
+
+AC_HAVE_TYPE([socklen_t],[#include <sys/socket.h>])
+AC_HAVE_TYPE([sa_family_t],[#include <sys/socket.h>])
+AC_HAVE_TYPE([struct addrinfo], [#include <netdb.h>])
+AC_HAVE_TYPE([struct sockaddr], [#include <sys/socket.h>])
+AC_HAVE_TYPE([struct sockaddr_storage], [
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+])
+AC_HAVE_TYPE([struct sockaddr_in6], [
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+])
+
+if test x"$ac_cv_type_struct_sockaddr_storage" = x"yes"; then
+AC_CHECK_MEMBER(struct sockaddr_storage.ss_family,
+ AC_DEFINE(HAVE_SS_FAMILY, 1, [Defined if struct sockaddr_storage has ss_family field]),,
+ [
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+ ])
+
+if test x"$ac_cv_member_struct_sockaddr_storage_ss_family" != x"yes"; then
+AC_CHECK_MEMBER(struct sockaddr_storage.__ss_family,
+ AC_DEFINE(HAVE___SS_FAMILY, 1, [Defined if struct sockaddr_storage has __ss_family field]),,
+ [
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+ ])
+fi
+fi
+
+AC_CACHE_CHECK([for sin_len in sock],libreplace_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);
+ ],[
+ libreplace_cv_HAVE_SOCK_SIN_LEN=yes
+ ],[
+ libreplace_cv_HAVE_SOCK_SIN_LEN=no
+ ])
+])
+if test x"$libreplace_cv_HAVE_SOCK_SIN_LEN" = x"yes"; then
+ AC_DEFINE(HAVE_SOCK_SIN_LEN,1,[Whether the sockaddr_in struct has a sin_len property])
+fi
+
+############################################
+# check for unix domain sockets
+AC_CACHE_CHECK([for unix domain sockets],libreplace_cv_HAVE_UNIXSOCKET,[
+ AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+ ],[
+struct sockaddr_un sunaddr;
+sunaddr.sun_family = AF_UNIX;
+ ],[
+ libreplace_cv_HAVE_UNIXSOCKET=yes
+ ],[
+ libreplace_cv_HAVE_UNIXSOCKET=no
+ ])
+])
+if test x"$libreplace_cv_HAVE_UNIXSOCKET" = x"yes"; then
+ AC_DEFINE(HAVE_UNIXSOCKET,1,[If we need to build with unixscoket support])
+fi
+
+dnl The following test is roughl taken from the cvs sources.
+dnl
+dnl If we can't find connect, try looking in -lsocket, -lnsl, and -linet.
+dnl The Irix 5 libc.so has connect and gethostbyname, but Irix 5 also has
+dnl libsocket.so which has a bad implementation of gethostbyname (it
+dnl only looks in /etc/hosts), so we only look for -lsocket if we need
+dnl it.
+AC_CHECK_FUNCS(connect)
+if test x"$ac_cv_func_connect" = x"no"; then
+ AC_CHECK_LIB_EXT(nsl_s, LIBREPLACE_NETWORK_LIBS, connect)
+ AC_CHECK_LIB_EXT(nsl, LIBREPLACE_NETWORK_LIBS, connect)
+ AC_CHECK_LIB_EXT(socket, LIBREPLACE_NETWORK_LIBS, connect)
+ AC_CHECK_LIB_EXT(inet, LIBREPLACE_NETWORK_LIBS, connect)
+ dnl We can't just call AC_CHECK_FUNCS(connect) here,
+ dnl because the value has been cached.
+ if test x"$ac_cv_lib_ext_nsl_s_connect" = x"yes" ||
+ test x"$ac_cv_lib_ext_nsl_connect" = x"yes" ||
+ test x"$ac_cv_lib_ext_socket_connect" = x"yes" ||
+ test x"$ac_cv_lib_ext_inet_connect" = x"yes"
+ then
+ AC_DEFINE(HAVE_CONNECT,1,[Whether the system has connect()])
+ fi
+fi
+
+AC_CHECK_FUNCS(gethostbyname)
+if test x"$ac_cv_func_gethostbyname" = x"no"; then
+ AC_CHECK_LIB_EXT(nsl_s, LIBREPLACE_NETWORK_LIBS, gethostbyname)
+ AC_CHECK_LIB_EXT(nsl, LIBREPLACE_NETWORK_LIBS, gethostbyname)
+ AC_CHECK_LIB_EXT(socket, LIBREPLACE_NETWORK_LIBS, gethostbyname)
+ dnl We can't just call AC_CHECK_FUNCS(gethostbyname) here,
+ dnl because the value has been cached.
+ if test x"$ac_cv_lib_ext_nsl_s_gethostbyname" = x"yes" ||
+ test x"$ac_cv_lib_ext_nsl_gethostbyname" = x"yes" ||
+ test x"$ac_cv_lib_ext_socket_gethostbyname" = x"yes"
+ then
+ AC_DEFINE(HAVE_GETHOSTBYNAME,1,
+ [Whether the system has gethostbyname()])
+ fi
+fi
+
+dnl HP-UX has if_nametoindex in -lipv6
+AC_CHECK_FUNCS(if_nametoindex)
+if test x"$ac_cv_func_if_nametoindex" = x"no"; then
+ AC_CHECK_LIB_EXT(ipv6, LIBREPLACE_NETWORK_LIBS, if_nametoindex)
+ dnl We can't just call AC_CHECK_FUNCS(if_nametoindex) here,
+ dnl because the value has been cached.
+ if test x"$ac_cv_lib_ext_ipv6_if_nametoindex" = x"yes"
+ then
+ AC_DEFINE(HAVE_IF_NAMETOINDEX, 1,
+ [Whether the system has if_nametoindex()])
+ fi
+fi
+
+# The following tests need LIBS="${LIBREPLACE_NETWORK_LIBS}"
+old_LIBS=$LIBS
+LIBS="${LIBREPLACE_NETWORK_LIBS}"
+SAVE_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS -I$libreplacedir"
+
+AC_CHECK_FUNCS(socketpair,[],[LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} socketpair.o"])
+
+AC_CACHE_CHECK([for broken inet_ntoa],libreplace_cv_REPLACE_INET_NTOA,[
+AC_TRY_RUN([
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+main() { struct in_addr ip; ip.s_addr = 0x12345678;
+if (strcmp(inet_ntoa(ip),"18.52.86.120") &&
+ strcmp(inet_ntoa(ip),"120.86.52.18")) { exit(0); }
+exit(1);}],
+ libreplace_cv_REPLACE_INET_NTOA=yes,libreplace_cv_REPLACE_INET_NTOA=no,libreplace_cv_REPLACE_INET_NTOA=cross)])
+
+AC_CHECK_FUNCS(inet_ntoa,[],[libreplace_cv_REPLACE_INET_NTOA=yes])
+if test x"$libreplace_cv_REPLACE_INET_NTOA" = x"yes"; then
+ AC_DEFINE(REPLACE_INET_NTOA,1,[Whether inet_ntoa should be replaced])
+ LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} inet_ntoa.o"
+fi
+
+AC_CHECK_FUNCS(inet_aton,[],[LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} inet_aton.o"])
+
+AC_CHECK_FUNCS(inet_ntop,[],[LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} inet_ntop.o"])
+
+AC_CHECK_FUNCS(inet_pton,[],[LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} inet_pton.o"])
+
+dnl test for getaddrinfo/getnameinfo
+AC_CACHE_CHECK([for getaddrinfo],libreplace_cv_HAVE_GETADDRINFO,[
+AC_TRY_LINK([
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#include <sys/socket.h>
+#include <netdb.h>],
+[
+struct sockaddr sa;
+struct addrinfo *ai = NULL;
+int ret = getaddrinfo(NULL, NULL, NULL, &ai);
+if (ret != 0) {
+ const char *es = gai_strerror(ret);
+}
+freeaddrinfo(ai);
+ret = getnameinfo(&sa, sizeof(sa),
+ NULL, 0,
+ NULL, 0, 0);
+
+],
+libreplace_cv_HAVE_GETADDRINFO=yes,libreplace_cv_HAVE_GETADDRINFO=no)])
+if test x"$libreplace_cv_HAVE_GETADDRINFO" = x"yes"; then
+ AC_DEFINE(HAVE_GETADDRINFO,1,[Whether the system has getaddrinfo])
+ AC_DEFINE(HAVE_GETNAMEINFO,1,[Whether the system has getnameinfo])
+ AC_DEFINE(HAVE_FREEADDRINFO,1,[Whether the system has freeaddrinfo])
+ AC_DEFINE(HAVE_GAI_STRERROR,1,[Whether the system has gai_strerror])
+else
+ LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} getaddrinfo.o"
+fi
+
+AC_CHECK_HEADERS([ifaddrs.h])
+
+dnl Used when getifaddrs is not available
+AC_CHECK_MEMBERS([struct sockaddr.sa_len],
+ [AC_DEFINE(HAVE_SOCKADDR_SA_LEN, 1, [Whether struct sockaddr has a sa_len member])],
+ [],
+ [#include <sys/socket.h>])
+
+dnl test for getifaddrs and freeifaddrs
+AC_CACHE_CHECK([for getifaddrs and freeifaddrs],libreplace_cv_HAVE_GETIFADDRS,[
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <netdb.h>],
+[
+struct ifaddrs *ifp = NULL;
+int ret = getifaddrs (&ifp);
+freeifaddrs(ifp);
+],
+libreplace_cv_HAVE_GETIFADDRS=yes,libreplace_cv_HAVE_GETIFADDRS=no)])
+if test x"$libreplace_cv_HAVE_GETIFADDRS" = x"yes"; then
+ AC_DEFINE(HAVE_GETIFADDRS,1,[Whether the system has getifaddrs])
+ AC_DEFINE(HAVE_FREEIFADDRS,1,[Whether the system has freeifaddrs])
+ AC_DEFINE(HAVE_STRUCT_IFADDRS,1,[Whether struct ifaddrs is available])
+fi
+
+##################
+# look for a method of finding the list of network interfaces
+iface=no;
+AC_CACHE_CHECK([for iface getifaddrs],libreplace_cv_HAVE_IFACE_GETIFADDRS,[
+AC_TRY_RUN([
+#define HAVE_IFACE_GETIFADDRS 1
+#define NO_CONFIG_H 1
+#define AUTOCONF_TEST 1
+#define SOCKET_WRAPPER_NOT_REPLACE
+#include "$libreplacedir/replace.c"
+#include "$libreplacedir/inet_ntop.c"
+#include "$libreplacedir/snprintf.c"
+#include "$libreplacedir/getifaddrs.c"
+#define getifaddrs_test main
+#include "$libreplacedir/test/getifaddrs.c"],
+ libreplace_cv_HAVE_IFACE_GETIFADDRS=yes,libreplace_cv_HAVE_IFACE_GETIFADDRS=no,libreplace_cv_HAVE_IFACE_GETIFADDRS=cross)])
+if test x"$libreplace_cv_HAVE_IFACE_GETIFADDRS" = x"yes"; then
+ iface=yes;AC_DEFINE(HAVE_IFACE_GETIFADDRS,1,[Whether iface getifaddrs is available])
+else
+ LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} getifaddrs.o"
+fi
+
+
+if test $iface = no; then
+AC_CACHE_CHECK([for iface AIX],libreplace_cv_HAVE_IFACE_AIX,[
+AC_TRY_RUN([
+#define HAVE_IFACE_AIX 1
+#define NO_CONFIG_H 1
+#define AUTOCONF_TEST 1
+#undef _XOPEN_SOURCE_EXTENDED
+#define SOCKET_WRAPPER_NOT_REPLACE
+#include "$libreplacedir/replace.c"
+#include "$libreplacedir/inet_ntop.c"
+#include "$libreplacedir/snprintf.c"
+#include "$libreplacedir/getifaddrs.c"
+#define getifaddrs_test main
+#include "$libreplacedir/test/getifaddrs.c"],
+ libreplace_cv_HAVE_IFACE_AIX=yes,libreplace_cv_HAVE_IFACE_AIX=no,libreplace_cv_HAVE_IFACE_AIX=cross)])
+if test x"$libreplace_cv_HAVE_IFACE_AIX" = x"yes"; then
+ iface=yes;AC_DEFINE(HAVE_IFACE_AIX,1,[Whether iface AIX is available])
+fi
+fi
+
+
+if test $iface = no; then
+AC_CACHE_CHECK([for iface ifconf],libreplace_cv_HAVE_IFACE_IFCONF,[
+AC_TRY_RUN([
+#define HAVE_IFACE_IFCONF 1
+#define NO_CONFIG_H 1
+#define AUTOCONF_TEST 1
+#define SOCKET_WRAPPER_NOT_REPLACE
+#include "$libreplacedir/replace.c"
+#include "$libreplacedir/inet_ntop.c"
+#include "$libreplacedir/snprintf.c"
+#include "$libreplacedir/getifaddrs.c"
+#define getifaddrs_test main
+#include "$libreplacedir/test/getifaddrs.c"],
+ libreplace_cv_HAVE_IFACE_IFCONF=yes,libreplace_cv_HAVE_IFACE_IFCONF=no,libreplace_cv_HAVE_IFACE_IFCONF=cross)])
+if test x"$libreplace_cv_HAVE_IFACE_IFCONF" = x"yes"; then
+ iface=yes;AC_DEFINE(HAVE_IFACE_IFCONF,1,[Whether iface ifconf is available])
+fi
+fi
+
+if test $iface = no; then
+AC_CACHE_CHECK([for iface ifreq],libreplace_cv_HAVE_IFACE_IFREQ,[
+AC_TRY_RUN([
+#define HAVE_IFACE_IFREQ 1
+#define NO_CONFIG_H 1
+#define AUTOCONF_TEST 1
+#define SOCKET_WRAPPER_NOT_REPLACE
+#include "$libreplacedir/replace.c"
+#include "$libreplacedir/inet_ntop.c"
+#include "$libreplacedir/snprintf.c"
+#include "$libreplacedir/getifaddrs.c"
+#define getifaddrs_test main
+#include "$libreplacedir/test/getifaddrs.c"],
+ libreplace_cv_HAVE_IFACE_IFREQ=yes,libreplace_cv_HAVE_IFACE_IFREQ=no,libreplace_cv_HAVE_IFACE_IFREQ=cross)])
+if test x"$libreplace_cv_HAVE_IFACE_IFREQ" = x"yes"; then
+ iface=yes;AC_DEFINE(HAVE_IFACE_IFREQ,1,[Whether iface ifreq is available])
+fi
+fi
+
+dnl test for ipv6
+AC_CACHE_CHECK([for ipv6 support],libreplace_cv_HAVE_IPV6,[
+ AC_TRY_LINK([
+#include <stdlib.h> /* for NULL */
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netdb.h>
+ ],
+ [
+struct sockaddr_storage sa_store;
+struct addrinfo *ai = NULL;
+struct in6_addr in6addr;
+int idx = if_nametoindex("iface1");
+int s = socket(AF_INET6, SOCK_STREAM, 0);
+int ret = getaddrinfo(NULL, NULL, NULL, &ai);
+if (ret != 0) {
+ const char *es = gai_strerror(ret);
+}
+freeaddrinfo(ai);
+ ],[
+ libreplace_cv_HAVE_IPV6=yes
+ ],[
+ libreplace_cv_HAVE_IPV6=no
+ ])
+])
+if test x"$libreplace_cv_HAVE_IPV6" = x"yes"; then
+ AC_DEFINE(HAVE_IPV6,1,[Whether the system has IPv6 support])
+fi
+
+LIBS=$old_LIBS
+CPPFLAGS="$SAVE_CPPFLAGS"
+
+LIBREPLACEOBJ="${LIBREPLACEOBJ} ${LIBREPLACE_NETWORK_OBJS}"
+
+echo "LIBREPLACE_NETWORK_CHECKS: END"
+]) dnl end AC_LIBREPLACE_NETWORK_CHECKS
diff --git a/source3/lib/replace/repdir.m4 b/source3/lib/replace/repdir.m4
new file mode 100644
index 0000000000..f53a4c2974
--- /dev/null
+++ b/source3/lib/replace/repdir.m4
@@ -0,0 +1,78 @@
+AC_CACHE_CHECK([for broken readdir],libreplace_cv_READDIR_NEEDED,[
+ AC_TRY_RUN([
+#define test_readdir_os2_delete main
+#include "$libreplacedir/test/os2_delete.c"],
+ [libreplace_cv_READDIR_NEEDED=no],
+ [libreplace_cv_READDIR_NEEDED=yes],
+ [libreplace_cv_READDIR_NEEDED="assuming not"])
+])
+
+#
+# try to replace with getdirentries() if needed
+#
+if test x"$libreplace_cv_READDIR_NEEDED" = x"yes"; then
+AC_CHECK_FUNCS(getdirentries)
+AC_VERIFY_C_PROTOTYPE([long telldir(const DIR *dir)],
+ [
+ return 0;
+ ],[
+ AC_DEFINE(TELLDIR_TAKES_CONST_DIR, 1, [Whether telldir takes a const pointer])
+ ],[],[
+ #include <dirent.h>
+ ])
+
+AC_VERIFY_C_PROTOTYPE([int seekdir(DIR *dir, long ofs)],
+ [
+ return 0;
+ ],[
+ AC_DEFINE(SEEKDIR_RETURNS_INT, 1, [Whether seekdir returns an int])
+ ],[],[
+ #include <dirent.h>
+ ])
+AC_CACHE_CHECK([for replacing readdir using getdirentries()],libreplace_cv_READDIR_GETDIRENTRIES,[
+ AC_TRY_RUN([
+#define _LIBREPLACE_REPLACE_H
+#include "$libreplacedir/repdir_getdirentries.c"
+#define test_readdir_os2_delete main
+#include "$libreplacedir/test/os2_delete.c"],
+ [libreplace_cv_READDIR_GETDIRENTRIES=yes],
+ [libreplace_cv_READDIR_GETDIRENTRIES=no])
+])
+fi
+if test x"$libreplace_cv_READDIR_GETDIRENTRIES" = x"yes"; then
+ AC_DEFINE(REPLACE_READDIR,1,[replace readdir])
+ AC_DEFINE(REPLACE_READDIR_GETDIRENTRIES,1,[replace readdir using getdirentries()])
+ LIBREPLACEOBJ="${LIBREPLACEOBJ} repdir_getdirentries.o"
+ libreplace_cv_READDIR_NEEDED=no
+fi
+
+#
+# try to replace with getdents() if needed
+#
+if test x"$libreplace_cv_READDIR_NEEDED" = x"yes"; then
+AC_CHECK_FUNCS(getdents)
+AC_CACHE_CHECK([for replacing readdir using getdents()],libreplace_cv_READDIR_GETDENTS,[
+ AC_TRY_RUN([
+#define _LIBREPLACE_REPLACE_H
+#error _donot_use_getdents_replacement_anymore
+#include "$libreplacedir/repdir_getdents.c"
+#define test_readdir_os2_delete main
+#include "$libreplacedir/test/os2_delete.c"],
+ [libreplace_cv_READDIR_GETDENTS=yes],
+ [libreplace_cv_READDIR_GETDENTS=no])
+])
+fi
+if test x"$libreplace_cv_READDIR_GETDENTS" = x"yes"; then
+ AC_DEFINE(REPLACE_READDIR,1,[replace readdir])
+ AC_DEFINE(REPLACE_READDIR_GETDENTS,1,[replace readdir using getdents()])
+ LIBREPLACEOBJ="${LIBREPLACEOBJ} repdir_getdents.o"
+ libreplace_cv_READDIR_NEEDED=no
+fi
+
+AC_MSG_CHECKING([a usable readdir()])
+if test x"$libreplace_cv_READDIR_NEEDED" = x"yes"; then
+ AC_MSG_RESULT(no)
+ AC_MSG_WARN([the provided readdir() is broken])
+else
+ AC_MSG_RESULT(yes)
+fi
diff --git a/source3/lib/replace/repdir_getdents.c b/source3/lib/replace/repdir_getdents.c
new file mode 100644
index 0000000000..afc634a796
--- /dev/null
+++ b/source3/lib/replace/repdir_getdents.c
@@ -0,0 +1,166 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2005
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ a replacement for opendir/readdir/telldir/seekdir/closedir for BSD systems
+
+ This is needed because the existing directory handling in FreeBSD
+ and OpenBSD (and possibly NetBSD) doesn't correctly handle unlink()
+ on files in a directory where telldir() has been used. On a block
+ boundary it will occasionally miss a file when seekdir() is used to
+ return to a position previously recorded with telldir().
+
+ This also fixes a severe performance and memory usage problem with
+ telldir() on BSD systems. Each call to telldir() in BSD adds an
+ entry to a linked list, and those entries are cleaned up on
+ closedir(). This means with a large directory closedir() can take an
+ arbitrary amount of time, causing network timeouts as millions of
+ telldir() entries are freed
+
+ Note! This replacement code is not portable. It relies on getdents()
+ always leaving the file descriptor at a seek offset that is a
+ multiple of DIR_BUF_SIZE. If the code detects that this doesn't
+ happen then it will abort(). It also does not handle directories
+ with offsets larger than can be stored in a long,
+
+ This code is available under other free software licenses as
+ well. Contact the author.
+*/
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#define DIR_BUF_BITS 9
+#define DIR_BUF_SIZE (1<<DIR_BUF_BITS)
+
+struct dir_buf {
+ int fd;
+ int nbytes, ofs;
+ off_t seekpos;
+ char buf[DIR_BUF_SIZE];
+};
+
+DIR *opendir(const char *dname)
+{
+ struct dir_buf *d;
+ struct stat sb;
+ d = malloc(sizeof(*d));
+ if (d == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ d->fd = open(dname, O_RDONLY);
+ if (d->fd == -1) {
+ free(d);
+ return NULL;
+ }
+ if (fstat(d->fd, &sb) < 0) {
+ close(d->fd);
+ free(d);
+ return NULL;
+ }
+ if (!S_ISDIR(sb.st_mode)) {
+ close(d->fd);
+ free(d);
+ errno = ENOTDIR;
+ return NULL;
+ }
+ d->ofs = 0;
+ d->seekpos = 0;
+ d->nbytes = 0;
+ return (DIR *)d;
+}
+
+struct dirent *readdir(DIR *dir)
+{
+ struct dir_buf *d = (struct dir_buf *)dir;
+ struct dirent *de;
+
+ if (d->ofs >= d->nbytes) {
+ d->seekpos = lseek(d->fd, 0, SEEK_CUR);
+ d->nbytes = getdents(d->fd, d->buf, DIR_BUF_SIZE);
+ d->ofs = 0;
+ }
+ if (d->ofs >= d->nbytes) {
+ return NULL;
+ }
+ de = (struct dirent *)&d->buf[d->ofs];
+ d->ofs += de->d_reclen;
+ return de;
+}
+
+long telldir(DIR *dir)
+{
+ struct dir_buf *d = (struct dir_buf *)dir;
+ if (d->ofs >= d->nbytes) {
+ d->seekpos = lseek(d->fd, 0, SEEK_CUR);
+ d->ofs = 0;
+ d->nbytes = 0;
+ }
+ /* this relies on seekpos always being a multiple of
+ DIR_BUF_SIZE. Is that always true on BSD systems? */
+ if (d->seekpos & (DIR_BUF_SIZE-1)) {
+ abort();
+ }
+ return d->seekpos + d->ofs;
+}
+
+void seekdir(DIR *dir, long ofs)
+{
+ struct dir_buf *d = (struct dir_buf *)dir;
+ d->seekpos = lseek(d->fd, ofs & ~(DIR_BUF_SIZE-1), SEEK_SET);
+ d->nbytes = getdents(d->fd, d->buf, DIR_BUF_SIZE);
+ d->ofs = 0;
+ while (d->ofs < (ofs & (DIR_BUF_SIZE-1))) {
+ if (readdir(dir) == NULL) break;
+ }
+}
+
+void rewinddir(DIR *dir)
+{
+ seekdir(dir, 0);
+}
+
+int closedir(DIR *dir)
+{
+ struct dir_buf *d = (struct dir_buf *)dir;
+ int r = close(d->fd);
+ if (r != 0) {
+ return r;
+ }
+ free(d);
+ return 0;
+}
+
+#ifndef dirfd
+/* darn, this is a macro on some systems. */
+int dirfd(DIR *dir)
+{
+ struct dir_buf *d = (struct dir_buf *)dir;
+ return d->fd;
+}
+#endif
diff --git a/source3/lib/replace/repdir_getdirentries.c b/source3/lib/replace/repdir_getdirentries.c
new file mode 100644
index 0000000000..197e5931fc
--- /dev/null
+++ b/source3/lib/replace/repdir_getdirentries.c
@@ -0,0 +1,183 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2005
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ a replacement for opendir/readdir/telldir/seekdir/closedir for BSD
+ systems using getdirentries
+
+ This is needed because the existing directory handling in FreeBSD
+ and OpenBSD (and possibly NetBSD) doesn't correctly handle unlink()
+ on files in a directory where telldir() has been used. On a block
+ boundary it will occasionally miss a file when seekdir() is used to
+ return to a position previously recorded with telldir().
+
+ This also fixes a severe performance and memory usage problem with
+ telldir() on BSD systems. Each call to telldir() in BSD adds an
+ entry to a linked list, and those entries are cleaned up on
+ closedir(). This means with a large directory closedir() can take an
+ arbitrary amount of time, causing network timeouts as millions of
+ telldir() entries are freed
+
+ Note! This replacement code is not portable. It relies on
+ getdirentries() always leaving the file descriptor at a seek offset
+ that is a multiple of DIR_BUF_SIZE. If the code detects that this
+ doesn't happen then it will abort(). It also does not handle
+ directories with offsets larger than can be stored in a long,
+
+ This code is available under other free software licenses as
+ well. Contact the author.
+*/
+
+#include "replace.h"
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#define DIR_BUF_BITS 9
+#define DIR_BUF_SIZE (1<<DIR_BUF_BITS)
+
+struct dir_buf {
+ int fd;
+ int nbytes, ofs;
+ off_t seekpos;
+ char buf[DIR_BUF_SIZE];
+};
+
+DIR *opendir(const char *dname)
+{
+ struct dir_buf *d;
+ struct stat sb;
+ d = malloc(sizeof(*d));
+ if (d == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ d->fd = open(dname, O_RDONLY);
+ if (d->fd == -1) {
+ free(d);
+ return NULL;
+ }
+ if (fstat(d->fd, &sb) < 0) {
+ close(d->fd);
+ free(d);
+ return NULL;
+ }
+ if (!S_ISDIR(sb.st_mode)) {
+ close(d->fd);
+ free(d);
+ errno = ENOTDIR;
+ return NULL;
+ }
+ d->ofs = 0;
+ d->seekpos = 0;
+ d->nbytes = 0;
+ return (DIR *)d;
+}
+
+struct dirent *readdir(DIR *dir)
+{
+ struct dir_buf *d = (struct dir_buf *)dir;
+ struct dirent *de;
+
+ if (d->ofs >= d->nbytes) {
+ long pos;
+ d->nbytes = getdirentries(d->fd, d->buf, DIR_BUF_SIZE, &pos);
+ d->seekpos = pos;
+ d->ofs = 0;
+ }
+ if (d->ofs >= d->nbytes) {
+ return NULL;
+ }
+ de = (struct dirent *)&d->buf[d->ofs];
+ d->ofs += de->d_reclen;
+ return de;
+}
+
+#ifdef TELLDIR_TAKES_CONST_DIR
+long telldir(const DIR *dir)
+#else
+long telldir(DIR *dir)
+#endif
+{
+ struct dir_buf *d = (struct dir_buf *)dir;
+ if (d->ofs >= d->nbytes) {
+ d->seekpos = lseek(d->fd, 0, SEEK_CUR);
+ d->ofs = 0;
+ d->nbytes = 0;
+ }
+ /* this relies on seekpos always being a multiple of
+ DIR_BUF_SIZE. Is that always true on BSD systems? */
+ if (d->seekpos & (DIR_BUF_SIZE-1)) {
+ abort();
+ }
+ return d->seekpos + d->ofs;
+}
+
+#ifdef SEEKDIR_RETURNS_INT
+int seekdir(DIR *dir, long ofs)
+#else
+void seekdir(DIR *dir, long ofs)
+#endif
+{
+ struct dir_buf *d = (struct dir_buf *)dir;
+ long pos;
+ d->seekpos = lseek(d->fd, ofs & ~(DIR_BUF_SIZE-1), SEEK_SET);
+ d->nbytes = getdirentries(d->fd, d->buf, DIR_BUF_SIZE, &pos);
+ d->ofs = 0;
+ while (d->ofs < (ofs & (DIR_BUF_SIZE-1))) {
+ if (readdir(dir) == NULL) break;
+ }
+#ifdef SEEKDIR_RETURNS_INT
+ return -1;
+#endif
+}
+
+void rewinddir(DIR *dir)
+{
+ seekdir(dir, 0);
+}
+
+int closedir(DIR *dir)
+{
+ struct dir_buf *d = (struct dir_buf *)dir;
+ int r = close(d->fd);
+ if (r != 0) {
+ return r;
+ }
+ free(d);
+ return 0;
+}
+
+#ifndef dirfd
+/* darn, this is a macro on some systems. */
+int dirfd(DIR *dir)
+{
+ struct dir_buf *d = (struct dir_buf *)dir;
+ return d->fd;
+}
+#endif
+
+
diff --git a/source3/lib/replace/replace.c b/source3/lib/replace/replace.c
new file mode 100644
index 0000000000..98d799b07e
--- /dev/null
+++ b/source3/lib/replace/replace.c
@@ -0,0 +1,616 @@
+/*
+ Unix SMB/CIFS implementation.
+ replacement routines for broken systems
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+
+#include "system/filesys.h"
+#include "system/time.h"
+#include "system/passwd.h"
+#include "system/syslog.h"
+#include "system/locale.h"
+#include "system/wait.h"
+
+void replace_dummy(void);
+void replace_dummy(void) {}
+
+#ifndef HAVE_FTRUNCATE
+ /*******************************************************************
+ftruncate for operating systems that don't have it
+********************************************************************/
+int rep_ftruncate(int f, off_t l)
+{
+#ifdef HAVE_CHSIZE
+ return chsize(f,l);
+#elif defined(F_FREESP)
+ 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);
+#else
+#error "you must have a ftruncate function"
+#endif
+}
+#endif /* HAVE_FTRUNCATE */
+
+
+#ifndef HAVE_STRLCPY
+/* like strncpy but does not 0 fill the buffer and always null
+ terminates. bufsize is the size of the destination buffer */
+size_t rep_strlcpy(char *d, const char *s, size_t bufsize)
+{
+ size_t len = strlen(s);
+ size_t ret = len;
+ if (bufsize <= 0) return 0;
+ if (len >= bufsize) len = bufsize-1;
+ memcpy(d, s, len);
+ d[len] = 0;
+ return ret;
+}
+#endif
+
+#ifndef HAVE_STRLCAT
+/* like strncat but does not 0 fill the buffer and always null
+ terminates. bufsize is the length of the buffer, which should
+ be one more than the maximum resulting string length */
+size_t rep_strlcat(char *d, const char *s, size_t bufsize)
+{
+ size_t len1 = strlen(d);
+ size_t len2 = strlen(s);
+ size_t ret = len1 + len2;
+
+ if (len1+len2 >= bufsize) {
+ if (bufsize < (len1+1)) {
+ return ret;
+ }
+ len2 = bufsize - (len1+1);
+ }
+ if (len2 > 0) {
+ memcpy(d+len1, s, len2);
+ d[len1+len2] = 0;
+ }
+ return ret;
+}
+#endif
+
+#ifndef HAVE_MKTIME
+/*******************************************************************
+a mktime() replacement for those who don't have it - contributed by
+C.A. Lademann <cal@zls.com>
+Corrections by richard.kettlewell@kewill.com
+********************************************************************/
+
+#define MINUTE 60
+#define HOUR 60*MINUTE
+#define DAY 24*HOUR
+#define YEAR 365*DAY
+time_t rep_mktime(struct tm *t)
+{
+ struct tm *u;
+ time_t epoch = 0;
+ int n;
+ int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ y, m, i;
+
+ if(t->tm_year < 70)
+ return((time_t)-1);
+
+ n = t->tm_year + 1900 - 1;
+ epoch = (t->tm_year - 70) * YEAR +
+ ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
+
+ y = t->tm_year + 1900;
+ m = 0;
+
+ for(i = 0; i < t->tm_mon; i++) {
+ epoch += mon [m] * DAY;
+ if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
+ epoch += DAY;
+
+ if(++m > 11) {
+ m = 0;
+ y++;
+ }
+ }
+
+ epoch += (t->tm_mday - 1) * DAY;
+ epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
+
+ if((u = localtime(&epoch)) != NULL) {
+ t->tm_sec = u->tm_sec;
+ t->tm_min = u->tm_min;
+ t->tm_hour = u->tm_hour;
+ t->tm_mday = u->tm_mday;
+ t->tm_mon = u->tm_mon;
+ t->tm_year = u->tm_year;
+ t->tm_wday = u->tm_wday;
+ t->tm_yday = u->tm_yday;
+ t->tm_isdst = u->tm_isdst;
+ }
+
+ return(epoch);
+}
+#endif /* !HAVE_MKTIME */
+
+
+#ifndef HAVE_INITGROUPS
+/****************************************************************************
+ some systems don't have an initgroups call
+****************************************************************************/
+int rep_initgroups(char *name, gid_t id)
+{
+#ifndef HAVE_SETGROUPS
+ /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
+ errno = ENOSYS;
+ return -1;
+#else /* HAVE_SETGROUPS */
+
+#include <grp.h>
+
+ gid_t *grouplst = NULL;
+ int max_gr = NGROUPS_MAX;
+ int ret;
+ int i,j;
+ struct group *g;
+ char *gr;
+
+ if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ grouplst[0] = id;
+ i = 1;
+ while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
+ if (g->gr_gid == id)
+ continue;
+ j = 0;
+ gr = g->gr_mem[0];
+ while (gr && (*gr != (char)NULL)) {
+ if (strcmp(name,gr) == 0) {
+ grouplst[i] = g->gr_gid;
+ i++;
+ gr = (char *)NULL;
+ break;
+ }
+ gr = g->gr_mem[++j];
+ }
+ }
+ endgrent();
+ ret = setgroups(i, grouplst);
+ free(grouplst);
+ return ret;
+#endif /* HAVE_SETGROUPS */
+}
+#endif /* HAVE_INITGROUPS */
+
+
+#if (defined(SecureWare) && defined(SCO))
+/* This is needed due to needing the nap() function but we don't want
+ to include the Xenix libraries since that will break other things...
+ BTW: system call # 0x0c28 is the same as calling nap() */
+long nap(long milliseconds) {
+ return syscall(0x0c28, milliseconds);
+ }
+#endif
+
+
+#ifndef HAVE_MEMMOVE
+/*******************************************************************
+safely copies memory, ensuring no overlap problems.
+this is only used if the machine does not have its own memmove().
+this is not the fastest algorithm in town, but it will do for our
+needs.
+********************************************************************/
+void *rep_memmove(void *dest,const void *src,int size)
+{
+ unsigned long d,s;
+ int i;
+ if (dest==src || !size) return(dest);
+
+ d = (unsigned long)dest;
+ s = (unsigned long)src;
+
+ if ((d >= (s+size)) || (s >= (d+size))) {
+ /* no overlap */
+ memcpy(dest,src,size);
+ return(dest);
+ }
+
+ if (d < s) {
+ /* we can forward copy */
+ if (s-d >= sizeof(int) &&
+ !(s%sizeof(int)) &&
+ !(d%sizeof(int)) &&
+ !(size%sizeof(int))) {
+ /* do it all as words */
+ int *idest = (int *)dest;
+ int *isrc = (int *)src;
+ size /= sizeof(int);
+ for (i=0;i<size;i++) idest[i] = isrc[i];
+ } else {
+ /* simplest */
+ char *cdest = (char *)dest;
+ char *csrc = (char *)src;
+ for (i=0;i<size;i++) cdest[i] = csrc[i];
+ }
+ } else {
+ /* must backward copy */
+ if (d-s >= sizeof(int) &&
+ !(s%sizeof(int)) &&
+ !(d%sizeof(int)) &&
+ !(size%sizeof(int))) {
+ /* do it all as words */
+ int *idest = (int *)dest;
+ int *isrc = (int *)src;
+ size /= sizeof(int);
+ for (i=size-1;i>=0;i--) idest[i] = isrc[i];
+ } else {
+ /* simplest */
+ char *cdest = (char *)dest;
+ char *csrc = (char *)src;
+ for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
+ }
+ }
+ return(dest);
+}
+#endif /* HAVE_MEMMOVE */
+
+#ifndef HAVE_STRDUP
+/****************************************************************************
+duplicate a string
+****************************************************************************/
+char *rep_strdup(const char *s)
+{
+ size_t len;
+ char *ret;
+
+ if (!s) return(NULL);
+
+ len = strlen(s)+1;
+ ret = (char *)malloc(len);
+ if (!ret) return(NULL);
+ memcpy(ret,s,len);
+ return(ret);
+}
+#endif /* HAVE_STRDUP */
+
+#ifndef HAVE_SETLINEBUF
+void rep_setlinebuf(FILE *stream)
+{
+ setvbuf(stream, (char *)NULL, _IOLBF, 0);
+}
+#endif /* HAVE_SETLINEBUF */
+
+#ifndef HAVE_VSYSLOG
+#ifdef HAVE_SYSLOG
+void rep_vsyslog (int facility_priority, const char *format, va_list arglist)
+{
+ char *msg = NULL;
+ vasprintf(&msg, format, arglist);
+ if (!msg)
+ return;
+ syslog(facility_priority, "%s", msg);
+ free(msg);
+}
+#endif /* HAVE_SYSLOG */
+#endif /* HAVE_VSYSLOG */
+
+#ifndef HAVE_STRNLEN
+/**
+ Some platforms don't have strnlen
+**/
+ size_t rep_strnlen(const char *s, size_t max)
+{
+ size_t len;
+
+ for (len = 0; len < max; len++) {
+ if (s[len] == '\0') {
+ break;
+ }
+ }
+ return len;
+}
+#endif
+
+#ifndef HAVE_STRNDUP
+/**
+ Some platforms don't have strndup.
+**/
+char *rep_strndup(const char *s, size_t n)
+{
+ char *ret;
+
+ n = strnlen(s, n);
+ ret = malloc(n+1);
+ if (!ret)
+ return NULL;
+ memcpy(ret, s, n);
+ ret[n] = 0;
+
+ return ret;
+}
+#endif
+
+#ifndef HAVE_WAITPID
+int rep_waitpid(pid_t pid,int *status,int options)
+{
+ return wait4(pid, status, options, NULL);
+}
+#endif
+
+#ifndef HAVE_SETEUID
+int rep_seteuid(uid_t euid)
+{
+#ifdef HAVE_SETRESUID
+ return setresuid(-1, euid, -1);
+#else
+# error "You need a seteuid function"
+#endif
+}
+#endif
+
+#ifndef HAVE_SETEGID
+int rep_setegid(gid_t egid)
+{
+#ifdef HAVE_SETRESGID
+ return setresgid(-1, egid, -1);
+#else
+# error "You need a setegid function"
+#endif
+}
+#endif
+
+/*******************************************************************
+os/2 also doesn't have chroot
+********************************************************************/
+#ifndef HAVE_CHROOT
+int rep_chroot(const char *dname)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+/*****************************************************************
+ Possibly replace mkstemp if it is broken.
+*****************************************************************/
+
+#ifndef HAVE_SECURE_MKSTEMP
+int rep_mkstemp(char *template)
+{
+ /* have a reasonable go at emulating it. Hope that
+ the system mktemp() isn't completly hopeless */
+ char *p = mktemp(template);
+ if (!p)
+ return -1;
+ return open(p, O_CREAT|O_EXCL|O_RDWR, 0600);
+}
+#endif
+
+#ifndef HAVE_MKDTEMP
+char *rep_mkdtemp(char *template)
+{
+ char *dname;
+
+ if ((dname = mktemp(template))) {
+ if (mkdir(dname, 0700) >= 0) {
+ return dname;
+ }
+ }
+
+ return NULL;
+}
+#endif
+
+/*****************************************************************
+ Watch out: this is not thread safe.
+*****************************************************************/
+
+#ifndef HAVE_PREAD
+ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset)
+{
+ if (lseek(__fd, __offset, SEEK_SET) != __offset) {
+ return -1;
+ }
+ return read(__fd, __buf, __nbytes);
+}
+#endif
+
+/*****************************************************************
+ Watch out: this is not thread safe.
+*****************************************************************/
+
+#ifndef HAVE_PWRITE
+ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
+{
+ if (lseek(__fd, __offset, SEEK_SET) != __offset) {
+ return -1;
+ }
+ return write(__fd, __buf, __nbytes);
+}
+#endif
+
+#ifndef HAVE_STRCASESTR
+char *rep_strcasestr(const char *haystack, const char *needle)
+{
+ const char *s;
+ size_t nlen = strlen(needle);
+ for (s=haystack;*s;s++) {
+ if (toupper(*needle) == toupper(*s) &&
+ strncasecmp(s, needle, nlen) == 0) {
+ return (char *)((uintptr_t)s);
+ }
+ }
+ return NULL;
+}
+#endif
+
+#ifndef HAVE_STRTOK_R
+/* based on GLIBC version, copyright Free Software Foundation */
+char *rep_strtok_r(char *s, const char *delim, char **save_ptr)
+{
+ char *token;
+
+ if (s == NULL) s = *save_ptr;
+
+ s += strspn(s, delim);
+ if (*s == '\0') {
+ *save_ptr = s;
+ return NULL;
+ }
+
+ token = s;
+ s = strpbrk(token, delim);
+ if (s == NULL) {
+ *save_ptr = token + strlen(token);
+ } else {
+ *s = '\0';
+ *save_ptr = s + 1;
+ }
+
+ return token;
+}
+#endif
+
+#ifndef HAVE_STRTOLL
+long long int rep_strtoll(const char *str, char **endptr, int base)
+{
+#ifdef HAVE_STRTOQ
+ return strtoq(str, endptr, base);
+#elif defined(HAVE___STRTOLL)
+ return __strtoll(str, endptr, base);
+#elif SIZEOF_LONG == SIZEOF_LONG_LONG
+ return (long long int) strtol(str, endptr, base);
+#else
+# error "You need a strtoll function"
+#endif
+}
+#endif
+
+
+#ifndef HAVE_STRTOULL
+unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
+{
+#ifdef HAVE_STRTOUQ
+ return strtouq(str, endptr, base);
+#elif defined(HAVE___STRTOULL)
+ return __strtoull(str, endptr, base);
+#elif SIZEOF_LONG == SIZEOF_LONG_LONG
+ return (unsigned long long int) strtoul(str, endptr, base);
+#else
+# error "You need a strtoull function"
+#endif
+}
+#endif
+
+#ifndef HAVE_SETENV
+int rep_setenv(const char *name, const char *value, int overwrite)
+{
+ char *p;
+ size_t l1, l2;
+ int ret;
+
+ if (!overwrite && getenv(name)) {
+ return 0;
+ }
+
+ l1 = strlen(name);
+ l2 = strlen(value);
+
+ p = malloc(l1+l2+2);
+ if (p == NULL) {
+ return -1;
+ }
+ memcpy(p, name, l1);
+ p[l1] = '=';
+ memcpy(p+l1+1, value, l2);
+ p[l1+l2+1] = 0;
+
+ ret = putenv(p);
+ if (ret != 0) {
+ free(p);
+ }
+
+ return ret;
+}
+#endif
+
+#ifndef HAVE_UNSETENV
+int rep_unsetenv(const char *name)
+{
+ extern char **environ;
+ size_t len = strlen(name);
+ size_t i, count;
+
+ if (environ == NULL || getenv(name) == NULL) {
+ return 0;
+ }
+
+ for (i=0;environ[i];i++) /* noop */ ;
+
+ count=i;
+
+ for (i=0;i<count;) {
+ if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') {
+ /* note: we do _not_ free the old variable here. It is unsafe to
+ do so, as the pointer may not have come from malloc */
+ memmove(&environ[i], &environ[i+1], (count-i)*sizeof(char *));
+ count--;
+ } else {
+ i++;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef HAVE_UTIME
+int rep_utime(const char *filename, const struct utimbuf *buf)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+#ifndef HAVE_UTIMES
+int rep_utimes(const char *filename, const struct timeval tv[2])
+{
+ struct utimbuf u;
+
+ u.actime = tv[0].tv_sec;
+ if (tv[0].tv_usec > 500000) {
+ u.actime += 1;
+ }
+
+ u.modtime = tv[1].tv_sec;
+ if (tv[1].tv_usec > 500000) {
+ u.modtime += 1;
+ }
+
+ return utime(filename, &u);
+}
+#endif
diff --git a/source3/lib/replace/replace.h b/source3/lib/replace/replace.h
new file mode 100644
index 0000000000..c69ea6cdac
--- /dev/null
+++ b/source3/lib/replace/replace.h
@@ -0,0 +1,582 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ macros to go along with the lib/replace/ portability layer code
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Jelmer Vernooij 2006
+ Copyright (C) Jeremy Allison 2007.
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _LIBREPLACE_REPLACE_H
+#define _LIBREPLACE_REPLACE_H
+
+#ifndef NO_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STANDARDS_H
+#include <standards.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#include "win32_replace.h"
+#endif
+
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+/* force off HAVE_INTTYPES_H so that roken doesn't try to include both,
+ which causes a warning storm on irix */
+#undef HAVE_INTTYPES_H
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+
+#ifndef HAVE_STRERROR
+extern char *sys_errlist[];
+#define strerror(i) sys_errlist[i]
+#endif
+
+#ifndef HAVE_ERRNO_DECL
+extern int errno;
+#endif
+
+#ifndef HAVE_STRDUP
+#define strdup rep_strdup
+char *rep_strdup(const char *s);
+#endif
+
+#ifndef HAVE_MEMMOVE
+#define memmove rep_memmove
+void *rep_memmove(void *dest,const void *src,int size);
+#endif
+
+#ifndef HAVE_MKTIME
+#define mktime rep_mktime
+/* prototype is in "system/time.h" */
+#endif
+
+#ifndef HAVE_TIMEGM
+#define timegm rep_timegm
+/* prototype is in "system/time.h" */
+#endif
+
+#ifndef HAVE_UTIME
+#define utime rep_utime
+/* prototype is in "system/time.h" */
+#endif
+
+#ifndef HAVE_UTIMES
+#define utimes rep_utimes
+/* prototype is in "system/time.h" */
+#endif
+
+#ifndef HAVE_STRLCPY
+#define strlcpy rep_strlcpy
+size_t rep_strlcpy(char *d, const char *s, size_t bufsize);
+#endif
+
+#ifndef HAVE_STRLCAT
+#define strlcat rep_strlcat
+size_t rep_strlcat(char *d, const char *s, size_t bufsize);
+#endif
+
+#if (defined(BROKEN_STRNDUP) || !defined(HAVE_STRNDUP))
+#undef HAVE_STRNDUP
+#define strndup rep_strndup
+char *rep_strndup(const char *s, size_t n);
+#endif
+
+#if (defined(BROKEN_STRNLEN) || !defined(HAVE_STRNLEN))
+#undef HAVE_STRNLEN
+#define strnlen rep_strnlen
+size_t rep_strnlen(const char *s, size_t n);
+#endif
+
+#ifndef HAVE_SETENV
+#define setenv rep_setenv
+int rep_setenv(const char *name, const char *value, int overwrite);
+#else
+#ifndef HAVE_SETENV_DECL
+int setenv(const char *name, const char *value, int overwrite);
+#endif
+#endif
+
+#ifndef HAVE_UNSETENV
+#define unsetenv rep_unsetenv
+int rep_unsetenv(const char *name);
+#endif
+
+#ifndef HAVE_SETEUID
+#define seteuid rep_seteuid
+int rep_seteuid(uid_t);
+#endif
+
+#ifndef HAVE_SETEGID
+#define setegid rep_setegid
+int rep_setegid(gid_t);
+#endif
+
+#ifndef HAVE_SETLINEBUF
+#define setlinebuf rep_setlinebuf
+void rep_setlinebuf(FILE *);
+#endif
+
+#ifndef HAVE_STRCASESTR
+#define strcasestr rep_strcasestr
+char *rep_strcasestr(const char *haystack, const char *needle);
+#endif
+
+#ifndef HAVE_STRTOK_R
+#define strtok_r rep_strtok_r
+char *rep_strtok_r(char *s, const char *delim, char **save_ptr);
+#endif
+
+#ifndef HAVE_STRTOLL
+#define strtoll rep_strtoll
+long long int rep_strtoll(const char *str, char **endptr, int base);
+#endif
+
+#ifndef HAVE_STRTOULL
+#define strtoull rep_strtoull
+unsigned long long int rep_strtoull(const char *str, char **endptr, int base);
+#endif
+
+#ifndef HAVE_FTRUNCATE
+#define ftruncate rep_ftruncate
+int rep_ftruncate(int,off_t);
+#endif
+
+#ifndef HAVE_INITGROUPS
+#define initgroups rep_initgroups
+int rep_initgroups(char *name, gid_t id);
+#endif
+
+#if !defined(HAVE_BZERO) && defined(HAVE_MEMSET)
+#define bzero(a,b) memset((a),'\0',(b))
+#endif
+
+#ifndef HAVE_DLERROR
+#define dlerror rep_dlerror
+char *rep_dlerror(void);
+#endif
+
+#ifndef HAVE_DLOPEN
+#define dlopen rep_dlopen
+#ifdef DLOPEN_TAKES_UNSIGNED_FLAGS
+void *rep_dlopen(const char *name, unsigned int flags);
+#else
+void *rep_dlopen(const char *name, int flags);
+#endif
+#endif
+
+#ifndef HAVE_DLSYM
+#define dlsym rep_dlsym
+void *rep_dlsym(void *handle, const char *symbol);
+#endif
+
+#ifndef HAVE_DLCLOSE
+#define dlclose rep_dlclose
+int rep_dlclose(void *handle);
+#endif
+
+#ifndef HAVE_SOCKETPAIR
+#define socketpair rep_socketpair
+/* prototype is in system/network.h */
+#endif
+
+#ifndef PRINTF_ATTRIBUTE
+#if (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 )
+/** Use gcc attribute to check printf fns. a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument. Note that some gcc 2.x versions don't handle this
+ * properly **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+#endif
+
+#ifndef _DEPRECATED_
+#if (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 )
+#define _DEPRECATED_ __attribute__ ((deprecated))
+#else
+#define _DEPRECATED_
+#endif
+#endif
+
+#ifndef HAVE_VASPRINTF
+#define vasprintf rep_vasprintf
+int rep_vasprintf(char **ptr, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0);
+#endif
+
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+#define snprintf rep_snprintf
+int rep_snprintf(char *,size_t ,const char *, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+
+#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+#define vsnprintf rep_vsnprintf
+int rep_vsnprintf(char *,size_t ,const char *, va_list ap) PRINTF_ATTRIBUTE(3,0);
+#endif
+
+#ifndef HAVE_ASPRINTF
+#define asprintf rep_asprintf
+int rep_asprintf(char **,const char *, ...) PRINTF_ATTRIBUTE(2,3);
+#endif
+
+#ifndef HAVE_VSYSLOG
+#ifdef HAVE_SYSLOG
+#define vsyslog rep_vsyslog
+void rep_vsyslog (int facility_priority, const char *format, va_list arglist) PRINTF_ATTRIBUTE(2,0);
+#endif
+#endif
+
+/* we used to use these fns, but now we have good replacements
+ for snprintf and vsnprintf */
+#define slprintf snprintf
+
+
+#ifndef HAVE_VA_COPY
+#undef va_copy
+#ifdef HAVE___VA_COPY
+#define va_copy(dest, src) __va_copy(dest, src)
+#else
+#define va_copy(dest, src) (dest) = (src)
+#endif
+#endif
+
+#ifndef HAVE_VOLATILE
+#define volatile
+#endif
+
+#ifndef HAVE_COMPARISON_FN_T
+typedef int (*comparison_fn_t)(const void *, const void *);
+#endif
+
+#ifdef REPLACE_STRPTIME
+#define strptime rep_strptime
+struct tm;
+char *rep_strptime(const char *buf, const char *format, struct tm *tm);
+#endif
+
+/* Load header file for dynamic linking stuff */
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#ifndef RTLD_LAZY
+#define RTLD_LAZY 0
+#endif
+#ifndef RTLD_NOW
+#define RTLD_NOW 0
+#endif
+#ifndef RTLD_GLOBAL
+#define RTLD_GLOBAL 0
+#endif
+
+#ifndef HAVE_SECURE_MKSTEMP
+#define mkstemp(path) rep_mkstemp(path)
+int rep_mkstemp(char *temp);
+#endif
+
+#ifndef HAVE_MKDTEMP
+#define mkdtemp rep_mkdtemp
+char *rep_mkdtemp(char *template);
+#endif
+
+#ifndef HAVE_PREAD
+#define pread rep_pread
+ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset);
+#endif
+
+#ifndef HAVE_PWRITE
+#define pwrite rep_pwrite
+ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset);
+#endif
+
+#if !defined(HAVE_INET_NTOA) || defined(REPLACE_INET_NTOA)
+#define inet_ntoa rep_inet_ntoa
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_INET_PTON
+#define inet_pton rep_inet_pton
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_INET_NTOP
+#define inet_ntop rep_inet_ntop
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_INET_ATON
+#define inet_aton rep_inet_aton
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_CONNECT
+#define connect rep_connect
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_GETHOSTBYNAME
+#define gethostbyname rep_gethostbyname
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_GETIFADDRS
+#define getifaddrs rep_getifaddrs
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_FREEIFADDRS
+#define freeifaddrs rep_freeifaddrs
+/* prototype is in "system/network.h" */
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+/* The extra casts work around common compiler bugs. */
+#define _TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+/* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
+ It is necessary at least when t == time_t. */
+#define _TYPE_MINIMUM(t) ((t) (_TYPE_SIGNED (t) \
+ ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
+#define _TYPE_MAXIMUM(t) ((t) (~ (t) 0 - _TYPE_MINIMUM (t)))
+
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 255
+#endif
+
+/*
+ * Some older systems seem not to have MAXHOSTNAMELEN
+ * defined.
+ */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN HOST_NAME_MAX
+#endif
+
+#ifndef UINT16_MAX
+#define UINT16_MAX 65535
+#endif
+
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef UINT64_MAX
+#define UINT64_MAX ((uint64_t)-1)
+#endif
+
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+#ifndef INT32_MAX
+#define INT32_MAX _TYPE_MAXIMUM(int32_t)
+#endif
+
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif
+
+#if !defined(HAVE_BOOL)
+#ifdef HAVE__Bool
+#define bool _Bool
+#else
+typedef int bool;
+#endif
+#endif
+
+/*
+ * to prevent <rpcsvc/yp_prot.h> from doing a redefine of 'bool'
+ *
+ * IRIX, HPUX, MacOS 10 and Solaris need BOOL_DEFINED
+ * Tru64 needs _BOOL_EXISTS
+ * AIX needs _BOOL,_TRUE,_FALSE
+ */
+#ifndef BOOL_DEFINED
+#define BOOL_DEFINED
+#endif
+#ifndef _BOOL_EXISTS
+#define _BOOL_EXISTS
+#endif
+#ifndef _BOOL
+#define _BOOL
+#endif
+
+#ifndef __bool_true_false_are_defined
+#define __bool_true_false_are_defined
+#endif
+
+#ifndef true
+#define true (1)
+#endif
+#ifndef false
+#define false (0)
+#endif
+
+#ifndef _TRUE
+#define _TRUE true
+#endif
+#ifndef _FALSE
+#define _FALSE false
+#endif
+
+#ifndef HAVE_FUNCTION_MACRO
+#ifdef HAVE_func_MACRO
+#define __FUNCTION__ __func__
+#else
+#define __FUNCTION__ ("")
+#endif
+#endif
+
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+#if !defined(HAVE_VOLATILE)
+#define volatile
+#endif
+
+/**
+ this is a warning hack. The idea is to use this everywhere that we
+ get the "discarding const" warning from gcc. That doesn't actually
+ fix the problem of course, but it means that when we do get to
+ cleaning them up we can do it by searching the code for
+ discard_const.
+
+ It also means that other error types aren't as swamped by the noise
+ of hundreds of const warnings, so we are more likely to notice when
+ we get new errors.
+
+ Please only add more uses of this macro when you find it
+ _really_ hard to fix const warnings. Our aim is to eventually use
+ this function in only a very few places.
+
+ Also, please call this via the discard_const_p() macro interface, as that
+ makes the return type safe.
+*/
+#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
+
+/** Type-safe version of discard_const */
+#define discard_const_p(type, ptr) ((type *)discard_const(ptr))
+
+#ifndef __STRING
+#define __STRING(x) #x
+#endif
+
+#ifndef __STRINGSTRING
+#define __STRINGSTRING(x) __STRING(x)
+#endif
+
+#ifndef __LINESTR__
+#define __LINESTR__ __STRINGSTRING(__LINE__)
+#endif
+
+#ifndef __location__
+#define __location__ __FILE__ ":" __LINESTR__
+#endif
+
+/**
+ * zero a structure
+ */
+#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
+
+/**
+ * zero a structure given a pointer to the structure
+ */
+#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
+
+/**
+ * zero a structure given a pointer to the structure - no zero check
+ */
+#define ZERO_STRUCTPN(x) memset((char *)(x), 0, sizeof(*(x)))
+
+/* zero an array - note that sizeof(array) must work - ie. it must not be a
+ pointer */
+#define ZERO_ARRAY(x) memset((char *)(x), 0, sizeof(x))
+
+/**
+ * work out how many elements there are in a static array
+ */
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+/**
+ * pointer difference macro
+ */
+#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((const char *)(p1)) - (const char *)(p2)))
+
+#if MMAP_BLACKLIST
+#undef HAVE_MMAP
+#endif
+
+#ifdef __COMPAR_FN_T
+#define QSORT_CAST (__compar_fn_t)
+#endif
+
+#ifndef QSORT_CAST
+#define QSORT_CAST (int (*)(const void *, const void *))
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+#ifndef MAX_DNS_NAME_LENGTH
+#define MAX_DNS_NAME_LENGTH 256 /* Actually 255 but +1 for terminating null. */
+#endif
+
+#endif /* _LIBREPLACE_REPLACE_H */
diff --git a/source3/lib/replace/samba.m4 b/source3/lib/replace/samba.m4
new file mode 100644
index 0000000000..07c4d38887
--- /dev/null
+++ b/source3/lib/replace/samba.m4
@@ -0,0 +1,35 @@
+AC_LIBREPLACE_BROKEN_CHECKS
+AC_LIBREPLACE_NETWORK_CHECKS
+
+SMB_EXT_LIB(LIBREPLACE_EXT, [${LIBDL}])
+SMB_ENABLE(LIBREPLACE_EXT)
+
+SMB_EXT_LIB(LIBREPLACE_NETWORK, [${LIBREPLACE_NETWORK_LIBS}])
+SMB_ENABLE(LIBREPLACE_NETWORK)
+
+# remove leading ./
+LIBREPLACE_DIR=`echo ${libreplacedir} |sed -e 's/^\.\///g'`
+
+# remove leading srcdir .. we are looking for the relative
+# path within the samba source tree or wherever libreplace is.
+# We need to make sure the object is not forced to end up in
+# the source directory because we might be using a separate
+# build directory.
+LIBREPLACE_DIR=`echo ${LIBREPLACE_DIR} | sed -e "s|^$srcdir/||g"`
+
+LIBREPLACE_OBJS=""
+for obj in ${LIBREPLACEOBJ}; do
+ LIBREPLACE_OBJS="${LIBREPLACE_OBJS} ${LIBREPLACE_DIR}/${obj}"
+done
+
+SMB_SUBSYSTEM(LIBREPLACE,
+ [${LIBREPLACE_OBJS}],
+ [LIBREPLACE_EXT LIBREPLACE_NETWORK],
+ [-Ilib/replace])
+
+LIBREPLACE_HOSTCC_OBJS=`echo ${LIBREPLACE_OBJS} |sed -e 's/\.o/\.ho/g'`
+
+SMB_SUBSYSTEM(LIBREPLACE_HOSTCC,
+ [${LIBREPLACE_HOSTCC_OBJS}],
+ [],
+ [-Ilib/replace])
diff --git a/source3/lib/replace/snprintf.c b/source3/lib/replace/snprintf.c
new file mode 100644
index 0000000000..c54d721ce5
--- /dev/null
+++ b/source3/lib/replace/snprintf.c
@@ -0,0 +1,1530 @@
+/*
+ * NOTE: If you change this file, please merge it into rsync, samba, etc.
+ */
+
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell@astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh. This sort of thing is always nasty do deal with. Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length. This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ *
+ * More Recently:
+ * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
+ * This was ugly. It is still ugly. I opted out of floating point
+ * numbers, but the formatter understands just about everything
+ * from the normal C string format, at least as far as I can tell from
+ * the Solaris 2.5 printf(3S) man page.
+ *
+ * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
+ * Ok, added some minimal floating point support, which means this
+ * probably requires libm on most operating systems. Don't yet
+ * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
+ * was pretty badly broken, it just wasn't being exercised in ways
+ * which showed it, so that's been fixed. Also, formated the code
+ * to mutt conventions, and removed dead code left over from the
+ * original. Also, there is now a builtin-test, just compile with:
+ * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
+ * and run snprintf for results.
+ *
+ * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
+ * The PGP code was using unsigned hexadecimal formats.
+ * Unfortunately, unsigned formats simply didn't work.
+ *
+ * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
+ * The original code assumed that both snprintf() and vsnprintf() were
+ * missing. Some systems only have snprintf() but not vsnprintf(), so
+ * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ * Andrew Tridgell (tridge@samba.org) Oct 1998
+ * fixed handling of %.0f
+ * added test for HAVE_LONG_DOUBLE
+ *
+ * tridge@samba.org, idra@samba.org, April 2001
+ * got rid of fcvt code (twas buggy and made testing harder)
+ * added C99 semantics
+ *
+ * date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0
+ * actually print args for %g and %e
+ *
+ * date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0
+ * Since includes.h isn't included here, VA_COPY has to be defined here. I don't
+ * see any include file that is guaranteed to be here, so I'm defining it
+ * locally. Fixes AIX and Solaris builds.
+ *
+ * date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13
+ * put the ifdef for HAVE_VA_COPY in one place rather than in lots of
+ * functions
+ *
+ * date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4
+ * Fix usage of va_list passed as an arg. Use __va_copy before using it
+ * when it exists.
+ *
+ * date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14
+ * Fix incorrect zpadlen handling in fmtfp.
+ * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
+ * few mods to make it easier to compile the tests.
+ * addedd the "Ollie" test to the floating point ones.
+ *
+ * Martin Pool (mbp@samba.org) April 2003
+ * Remove NO_CONFIG_H so that the test case can be built within a source
+ * tree with less trouble.
+ * Remove unnecessary SAFE_FREE() definition.
+ *
+ * Martin Pool (mbp@samba.org) May 2003
+ * Put in a prototype for dummy_snprintf() to quiet compiler warnings.
+ *
+ * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
+ * if the C library has some snprintf functions already.
+ *
+ * Darren Tucker (dtucker@zip.com.au) 2005
+ * Fix bug allowing read overruns of the source string with "%.*s"
+ * Usually harmless unless the read runs outside the process' allocation
+ * (eg if your malloc does guard pages) in which case it will segfault.
+ * From OpenSSH. Also added test for same.
+ *
+ * Simo Sorce (idra@samba.org) Jan 2006
+ *
+ * Add support for position independent parameters
+ * fix fmtstr now it conforms to sprintf wrt min.max
+ *
+ **************************************************************/
+
+#include "replace.h"
+#include "system/locale.h"
+
+#ifdef TEST_SNPRINTF /* need math library headers for testing */
+
+/* In test mode, we pretend that this system doesn't have any snprintf
+ * functions, regardless of what config.h says. */
+# undef HAVE_SNPRINTF
+# undef HAVE_VSNPRINTF
+# undef HAVE_C99_VSNPRINTF
+# undef HAVE_ASPRINTF
+# undef HAVE_VASPRINTF
+# include <math.h>
+#endif /* TEST_SNPRINTF */
+
+#if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
+/* only include stdio.h if we are not re-defining snprintf or vsnprintf */
+#include <stdio.h>
+ /* make the compiler happy with an empty file */
+ void dummy_snprintf(void);
+ void dummy_snprintf(void) {}
+#endif /* HAVE_SNPRINTF, etc */
+
+/* yes this really must be a ||. Don't muck with this (tridge) */
+#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+
+#ifdef HAVE_LONG_DOUBLE
+#define LDOUBLE long double
+#else
+#define LDOUBLE double
+#endif
+
+#ifdef HAVE_LONG_LONG
+#define LLONG long long
+#else
+#define LLONG long
+#endif
+
+#ifndef VA_COPY
+#ifdef HAVE_VA_COPY
+#define VA_COPY(dest, src) va_copy(dest, src)
+#else
+#ifdef HAVE___VA_COPY
+#define VA_COPY(dest, src) __va_copy(dest, src)
+#else
+#define VA_COPY(dest, src) (dest) = (src)
+#endif
+#endif
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS 1
+#define DP_S_MIN 2
+#define DP_S_DOT 3
+#define DP_S_MAX 4
+#define DP_S_MOD 5
+#define DP_S_CONV 6
+#define DP_S_DONE 7
+
+/* format flags - Bits */
+#define DP_F_MINUS (1 << 0)
+#define DP_F_PLUS (1 << 1)
+#define DP_F_SPACE (1 << 2)
+#define DP_F_NUM (1 << 3)
+#define DP_F_ZERO (1 << 4)
+#define DP_F_UP (1 << 5)
+#define DP_F_UNSIGNED (1 << 6)
+
+/* Conversion Flags */
+#define DP_C_CHAR 1
+#define DP_C_SHORT 2
+#define DP_C_LONG 3
+#define DP_C_LDOUBLE 4
+#define DP_C_LLONG 5
+#define DP_C_SIZET 6
+
+/* Chunk types */
+#define CNK_FMT_STR 0
+#define CNK_INT 1
+#define CNK_OCTAL 2
+#define CNK_UINT 3
+#define CNK_HEX 4
+#define CNK_FLOAT 5
+#define CNK_CHAR 6
+#define CNK_STRING 7
+#define CNK_PTR 8
+#define CNK_NUM 9
+#define CNK_PRCNT 10
+
+#define char_to_int(p) ((p)- '0')
+#ifndef MAX
+#define MAX(p,q) (((p) >= (q)) ? (p) : (q))
+#endif
+
+struct pr_chunk {
+ int type; /* chunk type */
+ int num; /* parameter number */
+ int min;
+ int max;
+ int flags;
+ int cflags;
+ int start;
+ int len;
+ LLONG value;
+ LDOUBLE fvalue;
+ char *strvalue;
+ void *pnum;
+ struct pr_chunk *min_star;
+ struct pr_chunk *max_star;
+ struct pr_chunk *next;
+};
+
+struct pr_chunk_x {
+ struct pr_chunk **chunks;
+ int num;
+};
+
+static int dopr(char *buffer, size_t maxlen, const char *format,
+ va_list args_in);
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+ char *value, int flags, int min, int max);
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
+ LLONG value, int base, int min, int max, int flags);
+static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
+ LDOUBLE fvalue, int min, int max, int flags);
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
+static struct pr_chunk *new_chunk(void);
+static int add_cnk_list_entry(struct pr_chunk_x **list,
+ int max_num, struct pr_chunk *chunk);
+
+static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
+{
+ char ch;
+ int state;
+ int pflag;
+ int pnum;
+ int pfirst;
+ size_t currlen;
+ va_list args;
+ const char *base;
+ struct pr_chunk *chunks = NULL;
+ struct pr_chunk *cnk = NULL;
+ struct pr_chunk_x *clist = NULL;
+ int max_pos;
+ int ret = -1;
+
+ VA_COPY(args, args_in);
+
+ state = DP_S_DEFAULT;
+ pfirst = 1;
+ pflag = 0;
+ pnum = 0;
+
+ max_pos = 0;
+ base = format;
+ ch = *format++;
+
+ /* retrieve the string structure as chunks */
+ while (state != DP_S_DONE) {
+ if (ch == '\0')
+ state = DP_S_DONE;
+
+ switch(state) {
+ case DP_S_DEFAULT:
+
+ if (cnk) {
+ cnk->next = new_chunk();
+ cnk = cnk->next;
+ } else {
+ cnk = new_chunk();
+ }
+ if (!cnk) goto done;
+ if (!chunks) chunks = cnk;
+
+ if (ch == '%') {
+ state = DP_S_FLAGS;
+ ch = *format++;
+ } else {
+ cnk->type = CNK_FMT_STR;
+ cnk->start = format - base -1;
+ while ((ch != '\0') && (ch != '%')) ch = *format++;
+ cnk->len = format - base - cnk->start -1;
+ }
+ break;
+ case DP_S_FLAGS:
+ switch (ch) {
+ case '-':
+ cnk->flags |= DP_F_MINUS;
+ ch = *format++;
+ break;
+ case '+':
+ cnk->flags |= DP_F_PLUS;
+ ch = *format++;
+ break;
+ case ' ':
+ cnk->flags |= DP_F_SPACE;
+ ch = *format++;
+ break;
+ case '#':
+ cnk->flags |= DP_F_NUM;
+ ch = *format++;
+ break;
+ case '0':
+ cnk->flags |= DP_F_ZERO;
+ ch = *format++;
+ break;
+ case 'I':
+ /* internationalization not supported yet */
+ ch = *format++;
+ break;
+ default:
+ state = DP_S_MIN;
+ break;
+ }
+ break;
+ case DP_S_MIN:
+ if (isdigit((unsigned char)ch)) {
+ cnk->min = 10 * cnk->min + char_to_int (ch);
+ ch = *format++;
+ } else if (ch == '$') {
+ if (!pfirst && !pflag) {
+ /* parameters must be all positioned or none */
+ goto done;
+ }
+ if (pfirst) {
+ pfirst = 0;
+ pflag = 1;
+ }
+ if (cnk->min == 0) /* what ?? */
+ goto done;
+ cnk->num = cnk->min;
+ cnk->min = 0;
+ ch = *format++;
+ } else if (ch == '*') {
+ if (pfirst) pfirst = 0;
+ cnk->min_star = new_chunk();
+ if (!cnk->min_star) /* out of memory :-( */
+ goto done;
+ cnk->min_star->type = CNK_INT;
+ if (pflag) {
+ int num;
+ ch = *format++;
+ if (!isdigit((unsigned char)ch)) {
+ /* parameters must be all positioned or none */
+ goto done;
+ }
+ for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
+ num = 10 * num + char_to_int(ch);
+ }
+ cnk->min_star->num = num;
+ if (ch != '$') /* what ?? */
+ goto done;
+ } else {
+ cnk->min_star->num = ++pnum;
+ }
+ max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star);
+ if (max_pos == 0) /* out of memory :-( */
+ goto done;
+ ch = *format++;
+ state = DP_S_DOT;
+ } else {
+ if (pfirst) pfirst = 0;
+ state = DP_S_DOT;
+ }
+ break;
+ case DP_S_DOT:
+ if (ch == '.') {
+ state = DP_S_MAX;
+ ch = *format++;
+ } else {
+ state = DP_S_MOD;
+ }
+ break;
+ case DP_S_MAX:
+ if (isdigit((unsigned char)ch)) {
+ if (cnk->max < 0)
+ cnk->max = 0;
+ cnk->max = 10 * cnk->max + char_to_int (ch);
+ ch = *format++;
+ } else if (ch == '$') {
+ if (!pfirst && !pflag) {
+ /* parameters must be all positioned or none */
+ goto done;
+ }
+ if (cnk->max <= 0) /* what ?? */
+ goto done;
+ cnk->num = cnk->max;
+ cnk->max = -1;
+ ch = *format++;
+ } else if (ch == '*') {
+ cnk->max_star = new_chunk();
+ if (!cnk->max_star) /* out of memory :-( */
+ goto done;
+ cnk->max_star->type = CNK_INT;
+ if (pflag) {
+ int num;
+ ch = *format++;
+ if (!isdigit((unsigned char)ch)) {
+ /* parameters must be all positioned or none */
+ goto done;
+ }
+ for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
+ num = 10 * num + char_to_int(ch);
+ }
+ cnk->max_star->num = num;
+ if (ch != '$') /* what ?? */
+ goto done;
+ } else {
+ cnk->max_star->num = ++pnum;
+ }
+ max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star);
+ if (max_pos == 0) /* out of memory :-( */
+ goto done;
+
+ ch = *format++;
+ state = DP_S_MOD;
+ } else {
+ state = DP_S_MOD;
+ }
+ break;
+ case DP_S_MOD:
+ switch (ch) {
+ case 'h':
+ cnk->cflags = DP_C_SHORT;
+ ch = *format++;
+ if (ch == 'h') {
+ cnk->cflags = DP_C_CHAR;
+ ch = *format++;
+ }
+ break;
+ case 'l':
+ cnk->cflags = DP_C_LONG;
+ ch = *format++;
+ if (ch == 'l') { /* It's a long long */
+ cnk->cflags = DP_C_LLONG;
+ ch = *format++;
+ }
+ break;
+ case 'L':
+ cnk->cflags = DP_C_LDOUBLE;
+ ch = *format++;
+ break;
+ case 'z':
+ cnk->cflags = DP_C_SIZET;
+ ch = *format++;
+ break;
+ default:
+ break;
+ }
+ state = DP_S_CONV;
+ break;
+ case DP_S_CONV:
+ if (cnk->num == 0) cnk->num = ++pnum;
+ max_pos = add_cnk_list_entry(&clist, max_pos, cnk);
+ if (max_pos == 0) /* out of memory :-( */
+ goto done;
+
+ switch (ch) {
+ case 'd':
+ case 'i':
+ cnk->type = CNK_INT;
+ break;
+ case 'o':
+ cnk->type = CNK_OCTAL;
+ cnk->flags |= DP_F_UNSIGNED;
+ break;
+ case 'u':
+ cnk->type = CNK_UINT;
+ cnk->flags |= DP_F_UNSIGNED;
+ break;
+ case 'X':
+ cnk->flags |= DP_F_UP;
+ case 'x':
+ cnk->type = CNK_HEX;
+ cnk->flags |= DP_F_UNSIGNED;
+ break;
+ case 'A':
+ /* hex float not supported yet */
+ case 'E':
+ case 'G':
+ case 'F':
+ cnk->flags |= DP_F_UP;
+ case 'a':
+ /* hex float not supported yet */
+ case 'e':
+ case 'f':
+ case 'g':
+ cnk->type = CNK_FLOAT;
+ break;
+ case 'c':
+ cnk->type = CNK_CHAR;
+ break;
+ case 's':
+ cnk->type = CNK_STRING;
+ break;
+ case 'p':
+ cnk->type = CNK_PTR;
+ break;
+ case 'n':
+ cnk->type = CNK_NUM;
+ break;
+ case '%':
+ cnk->type = CNK_PRCNT;
+ break;
+ default:
+ /* Unknown, bail out*/
+ goto done;
+ }
+ ch = *format++;
+ state = DP_S_DEFAULT;
+ break;
+ case DP_S_DONE:
+ break;
+ default:
+ /* hmm? */
+ break; /* some picky compilers need this */
+ }
+ }
+
+ /* retrieve the format arguments */
+ for (pnum = 0; pnum < max_pos; pnum++) {
+ int i;
+
+ if (clist[pnum].num == 0) {
+ /* ignoring a parameter should not be permitted
+ * all parameters must be matched at least once
+ * BUT seem some system ignore this rule ...
+ * at least my glibc based system does --SSS
+ */
+#ifdef DEBUG_SNPRINTF
+ printf("parameter at position %d not used\n", pnum+1);
+#endif
+ /* eat the parameter */
+ va_arg (args, int);
+ continue;
+ }
+ for (i = 1; i < clist[pnum].num; i++) {
+ if (clist[pnum].chunks[0]->type != clist[pnum].chunks[i]->type) {
+ /* nooo noo no!
+ * all the references to a parameter
+ * must be of the same type
+ */
+ goto done;
+ }
+ }
+ cnk = clist[pnum].chunks[0];
+ switch (cnk->type) {
+ case CNK_INT:
+ if (cnk->cflags == DP_C_SHORT)
+ cnk->value = va_arg (args, int);
+ else if (cnk->cflags == DP_C_LONG)
+ cnk->value = va_arg (args, long int);
+ else if (cnk->cflags == DP_C_LLONG)
+ cnk->value = va_arg (args, LLONG);
+ else if (cnk->cflags == DP_C_SIZET)
+ cnk->value = va_arg (args, ssize_t);
+ else
+ cnk->value = va_arg (args, int);
+
+ for (i = 1; i < clist[pnum].num; i++) {
+ clist[pnum].chunks[i]->value = cnk->value;
+ }
+ break;
+
+ case CNK_OCTAL:
+ case CNK_UINT:
+ case CNK_HEX:
+ if (cnk->cflags == DP_C_SHORT)
+ cnk->value = va_arg (args, unsigned int);
+ else if (cnk->cflags == DP_C_LONG)
+ cnk->value = (unsigned long int)va_arg (args, unsigned long int);
+ else if (cnk->cflags == DP_C_LLONG)
+ cnk->value = (LLONG)va_arg (args, unsigned LLONG);
+ else if (cnk->cflags == DP_C_SIZET)
+ cnk->value = (size_t)va_arg (args, size_t);
+ else
+ cnk->value = (unsigned int)va_arg (args, unsigned int);
+
+ for (i = 1; i < clist[pnum].num; i++) {
+ clist[pnum].chunks[i]->value = cnk->value;
+ }
+ break;
+
+ case CNK_FLOAT:
+ if (cnk->cflags == DP_C_LDOUBLE)
+ cnk->fvalue = va_arg (args, LDOUBLE);
+ else
+ cnk->fvalue = va_arg (args, double);
+
+ for (i = 1; i < clist[pnum].num; i++) {
+ clist[pnum].chunks[i]->fvalue = cnk->fvalue;
+ }
+ break;
+
+ case CNK_CHAR:
+ cnk->value = va_arg (args, int);
+
+ for (i = 1; i < clist[pnum].num; i++) {
+ clist[pnum].chunks[i]->value = cnk->value;
+ }
+ break;
+
+ case CNK_STRING:
+ cnk->strvalue = va_arg (args, char *);
+ if (!cnk->strvalue) cnk->strvalue = "(NULL)";
+
+ for (i = 1; i < clist[pnum].num; i++) {
+ clist[pnum].chunks[i]->strvalue = cnk->strvalue;
+ }
+ break;
+
+ case CNK_PTR:
+ cnk->strvalue = va_arg (args, void *);
+ for (i = 1; i < clist[pnum].num; i++) {
+ clist[pnum].chunks[i]->strvalue = cnk->strvalue;
+ }
+ break;
+
+ case CNK_NUM:
+ if (cnk->cflags == DP_C_CHAR)
+ cnk->pnum = va_arg (args, char *);
+ else if (cnk->cflags == DP_C_SHORT)
+ cnk->pnum = va_arg (args, short int *);
+ else if (cnk->cflags == DP_C_LONG)
+ cnk->pnum = va_arg (args, long int *);
+ else if (cnk->cflags == DP_C_LLONG)
+ cnk->pnum = va_arg (args, LLONG *);
+ else if (cnk->cflags == DP_C_SIZET)
+ cnk->pnum = va_arg (args, ssize_t *);
+ else
+ cnk->pnum = va_arg (args, int *);
+
+ for (i = 1; i < clist[pnum].num; i++) {
+ clist[pnum].chunks[i]->pnum = cnk->pnum;
+ }
+ break;
+
+ case CNK_PRCNT:
+ break;
+
+ default:
+ /* what ?? */
+ goto done;
+ }
+ }
+ /* print out the actual string from chunks */
+ currlen = 0;
+ cnk = chunks;
+ while (cnk) {
+ int len, min, max;
+
+ if (cnk->min_star) min = cnk->min_star->value;
+ else min = cnk->min;
+ if (cnk->max_star) max = cnk->max_star->value;
+ else max = cnk->max;
+
+ switch (cnk->type) {
+
+ case CNK_FMT_STR:
+ if (maxlen != 0 && maxlen > currlen) {
+ if (maxlen > (currlen + cnk->len)) len = cnk->len;
+ else len = maxlen - currlen;
+
+ memcpy(&(buffer[currlen]), &(base[cnk->start]), len);
+ }
+ currlen += cnk->len;
+
+ break;
+
+ case CNK_INT:
+ case CNK_UINT:
+ fmtint (buffer, &currlen, maxlen, cnk->value, 10, min, max, cnk->flags);
+ break;
+
+ case CNK_OCTAL:
+ fmtint (buffer, &currlen, maxlen, cnk->value, 8, min, max, cnk->flags);
+ break;
+
+ case CNK_HEX:
+ fmtint (buffer, &currlen, maxlen, cnk->value, 16, min, max, cnk->flags);
+ break;
+
+ case CNK_FLOAT:
+ fmtfp (buffer, &currlen, maxlen, cnk->fvalue, min, max, cnk->flags);
+ break;
+
+ case CNK_CHAR:
+ dopr_outch (buffer, &currlen, maxlen, cnk->value);
+ break;
+
+ case CNK_STRING:
+ if (max == -1) {
+ max = strlen(cnk->strvalue);
+ }
+ fmtstr (buffer, &currlen, maxlen, cnk->strvalue, cnk->flags, min, max);
+ break;
+
+ case CNK_PTR:
+ fmtint (buffer, &currlen, maxlen, (long)(cnk->strvalue), 16, min, max, cnk->flags);
+ break;
+
+ case CNK_NUM:
+ if (cnk->cflags == DP_C_CHAR)
+ *((char *)(cnk->pnum)) = (char)currlen;
+ else if (cnk->cflags == DP_C_SHORT)
+ *((short int *)(cnk->pnum)) = (short int)currlen;
+ else if (cnk->cflags == DP_C_LONG)
+ *((long int *)(cnk->pnum)) = (long int)currlen;
+ else if (cnk->cflags == DP_C_LLONG)
+ *((LLONG *)(cnk->pnum)) = (LLONG)currlen;
+ else if (cnk->cflags == DP_C_SIZET)
+ *((ssize_t *)(cnk->pnum)) = (ssize_t)currlen;
+ else
+ *((int *)(cnk->pnum)) = (int)currlen;
+ break;
+
+ case CNK_PRCNT:
+ dopr_outch (buffer, &currlen, maxlen, '%');
+ break;
+
+ default:
+ /* what ?? */
+ goto done;
+ }
+ cnk = cnk->next;
+ }
+ if (maxlen != 0) {
+ if (currlen < maxlen - 1)
+ buffer[currlen] = '\0';
+ else if (maxlen > 0)
+ buffer[maxlen - 1] = '\0';
+ }
+ ret = currlen;
+
+done:
+ va_end(args);
+
+ while (chunks) {
+ cnk = chunks->next;
+ free(chunks);
+ chunks = cnk;
+ }
+ if (clist) {
+ for (pnum = 0; pnum < max_pos; pnum++) {
+ if (clist[pnum].chunks) free(clist[pnum].chunks);
+ }
+ free(clist);
+ }
+ return ret;
+}
+
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+ char *value, int flags, int min, int max)
+{
+ int padlen, strln; /* amount to pad */
+ int cnt = 0;
+
+#ifdef DEBUG_SNPRINTF
+ printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
+#endif
+ if (value == 0) {
+ value = "<NULL>";
+ }
+
+ for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */
+ padlen = min - strln;
+ if (padlen < 0)
+ padlen = 0;
+ if (flags & DP_F_MINUS)
+ padlen = -padlen; /* Left Justify */
+
+ while (padlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ --padlen;
+ }
+ while (*value && (cnt < max)) {
+ dopr_outch (buffer, currlen, maxlen, *value++);
+ ++cnt;
+ }
+ while (padlen < 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ ++padlen;
+ }
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
+ LLONG value, int base, int min, int max, int flags)
+{
+ int signvalue = 0;
+ unsigned LLONG uvalue;
+ char convert[20];
+ int place = 0;
+ int spadlen = 0; /* amount to space pad */
+ int zpadlen = 0; /* amount to zero pad */
+ int caps = 0;
+
+ if (max < 0)
+ max = 0;
+
+ uvalue = value;
+
+ if(!(flags & DP_F_UNSIGNED)) {
+ if( value < 0 ) {
+ signvalue = '-';
+ uvalue = -value;
+ } else {
+ if (flags & DP_F_PLUS) /* Do a sign (+/i) */
+ signvalue = '+';
+ else if (flags & DP_F_SPACE)
+ signvalue = ' ';
+ }
+ }
+
+ if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+
+ do {
+ convert[place++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")
+ [uvalue % (unsigned)base ];
+ uvalue = (uvalue / (unsigned)base );
+ } while(uvalue && (place < 20));
+ if (place == 20) place--;
+ convert[place] = 0;
+
+ zpadlen = max - place;
+ spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
+ if (zpadlen < 0) zpadlen = 0;
+ if (spadlen < 0) spadlen = 0;
+ if (flags & DP_F_ZERO) {
+ zpadlen = MAX(zpadlen, spadlen);
+ spadlen = 0;
+ }
+ if (flags & DP_F_MINUS)
+ spadlen = -spadlen; /* Left Justifty */
+
+#ifdef DEBUG_SNPRINTF
+ printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
+ zpadlen, spadlen, min, max, place);
+#endif
+
+ /* Spaces */
+ while (spadlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ --spadlen;
+ }
+
+ /* Sign */
+ if (signvalue)
+ dopr_outch (buffer, currlen, maxlen, signvalue);
+
+ /* Zeros */
+ if (zpadlen > 0) {
+ while (zpadlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, '0');
+ --zpadlen;
+ }
+ }
+
+ /* Digits */
+ while (place > 0)
+ dopr_outch (buffer, currlen, maxlen, convert[--place]);
+
+ /* Left Justified spaces */
+ while (spadlen < 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ ++spadlen;
+ }
+}
+
+static LDOUBLE abs_val(LDOUBLE value)
+{
+ LDOUBLE result = value;
+
+ if (value < 0)
+ result = -value;
+
+ return result;
+}
+
+static LDOUBLE POW10(int exp)
+{
+ LDOUBLE result = 1;
+
+ while (exp) {
+ result *= 10;
+ exp--;
+ }
+
+ return result;
+}
+
+static LLONG ROUND(LDOUBLE value)
+{
+ LLONG intpart;
+
+ intpart = (LLONG)value;
+ value = value - intpart;
+ if (value >= 0.5) intpart++;
+
+ return intpart;
+}
+
+/* a replacement for modf that doesn't need the math library. Should
+ be portable, but slow */
+static double my_modf(double x0, double *iptr)
+{
+ int i;
+ LLONG l=0;
+ double x = x0;
+ double f = 1.0;
+
+ for (i=0;i<100;i++) {
+ l = (long)x;
+ if (l <= (x+1) && l >= (x-1)) break;
+ x *= 0.1;
+ f *= 10.0;
+ }
+
+ if (i == 100) {
+ /* yikes! the number is beyond what we can handle. What do we do? */
+ (*iptr) = 0;
+ return 0;
+ }
+
+ if (i != 0) {
+ double i2;
+ double ret;
+
+ ret = my_modf(x0-l*f, &i2);
+ (*iptr) = l*f + i2;
+ return ret;
+ }
+
+ (*iptr) = l;
+ return x - (*iptr);
+}
+
+
+static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
+ LDOUBLE fvalue, int min, int max, int flags)
+{
+ int signvalue = 0;
+ double ufvalue;
+ char iconvert[311];
+ char fconvert[311];
+ int iplace = 0;
+ int fplace = 0;
+ int padlen = 0; /* amount to pad */
+ int zpadlen = 0;
+ int caps = 0;
+ int idx;
+ double intpart;
+ double fracpart;
+ double temp;
+
+ /*
+ * AIX manpage says the default is 0, but Solaris says the default
+ * is 6, and sprintf on AIX defaults to 6
+ */
+ if (max < 0)
+ max = 6;
+
+ ufvalue = abs_val (fvalue);
+
+ if (fvalue < 0) {
+ signvalue = '-';
+ } else {
+ if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
+ signvalue = '+';
+ } else {
+ if (flags & DP_F_SPACE)
+ signvalue = ' ';
+ }
+ }
+
+#if 0
+ if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+#endif
+
+#if 0
+ if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
+#endif
+
+ /*
+ * Sorry, we only support 9 digits past the decimal because of our
+ * conversion method
+ */
+ if (max > 9)
+ max = 9;
+
+ /* We "cheat" by converting the fractional part to integer by
+ * multiplying by a factor of 10
+ */
+
+ temp = ufvalue;
+ my_modf(temp, &intpart);
+
+ fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
+
+ if (fracpart >= POW10(max)) {
+ intpart++;
+ fracpart -= POW10(max);
+ }
+
+
+ /* Convert integer part */
+ do {
+ temp = intpart*0.1;
+ my_modf(temp, &intpart);
+ idx = (int) ((temp -intpart +0.05)* 10.0);
+ /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
+ /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
+ iconvert[iplace++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
+ } while (intpart && (iplace < 311));
+ if (iplace == 311) iplace--;
+ iconvert[iplace] = 0;
+
+ /* Convert fractional part */
+ if (fracpart)
+ {
+ do {
+ temp = fracpart*0.1;
+ my_modf(temp, &fracpart);
+ idx = (int) ((temp -fracpart +0.05)* 10.0);
+ /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
+ /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
+ fconvert[fplace++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
+ } while(fracpart && (fplace < 311));
+ if (fplace == 311) fplace--;
+ }
+ fconvert[fplace] = 0;
+
+ /* -1 for decimal point, another -1 if we are printing a sign */
+ padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
+ zpadlen = max - fplace;
+ if (zpadlen < 0) zpadlen = 0;
+ if (padlen < 0)
+ padlen = 0;
+ if (flags & DP_F_MINUS)
+ padlen = -padlen; /* Left Justifty */
+
+ if ((flags & DP_F_ZERO) && (padlen > 0)) {
+ if (signvalue) {
+ dopr_outch (buffer, currlen, maxlen, signvalue);
+ --padlen;
+ signvalue = 0;
+ }
+ while (padlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, '0');
+ --padlen;
+ }
+ }
+ while (padlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ --padlen;
+ }
+ if (signvalue)
+ dopr_outch (buffer, currlen, maxlen, signvalue);
+
+ while (iplace > 0)
+ dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
+
+#ifdef DEBUG_SNPRINTF
+ printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
+#endif
+
+ /*
+ * Decimal point. This should probably use locale to find the correct
+ * char to print out.
+ */
+ if (max > 0) {
+ dopr_outch (buffer, currlen, maxlen, '.');
+
+ while (zpadlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, '0');
+ --zpadlen;
+ }
+
+ while (fplace > 0)
+ dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
+ }
+
+ while (padlen < 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ ++padlen;
+ }
+}
+
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
+{
+ if (*currlen < maxlen) {
+ buffer[(*currlen)] = c;
+ }
+ (*currlen)++;
+}
+
+static struct pr_chunk *new_chunk(void) {
+ struct pr_chunk *new_c = (struct pr_chunk *)malloc(sizeof(struct pr_chunk));
+
+ if (!new_c)
+ return NULL;
+
+ new_c->type = 0;
+ new_c->num = 0;
+ new_c->min = 0;
+ new_c->min_star = NULL;
+ new_c->max = -1;
+ new_c->max_star = NULL;
+ new_c->flags = 0;
+ new_c->cflags = 0;
+ new_c->start = 0;
+ new_c->len = 0;
+ new_c->value = 0;
+ new_c->fvalue = 0;
+ new_c->strvalue = NULL;
+ new_c->pnum = NULL;
+ new_c->next = NULL;
+
+ return new_c;
+}
+
+static int add_cnk_list_entry(struct pr_chunk_x **list,
+ int max_num, struct pr_chunk *chunk) {
+ struct pr_chunk_x *l;
+ struct pr_chunk **c;
+ int max;
+ int cnum;
+ int i, pos;
+
+ if (chunk->num > max_num) {
+ max = chunk->num;
+
+ if (*list == NULL) {
+ l = (struct pr_chunk_x *)malloc(sizeof(struct pr_chunk_x) * max);
+ pos = 0;
+ } else {
+ l = (struct pr_chunk_x *)realloc(*list, sizeof(struct pr_chunk_x) * max);
+ pos = max_num;
+ }
+ if (l == NULL) {
+ for (i = 0; i < max; i++) {
+ if ((*list)[i].chunks) free((*list)[i].chunks);
+ }
+ return 0;
+ }
+ for (i = pos; i < max; i++) {
+ l[i].chunks = NULL;
+ l[i].num = 0;
+ }
+ } else {
+ l = *list;
+ max = max_num;
+ }
+
+ i = chunk->num - 1;
+ cnum = l[i].num + 1;
+ if (l[i].chunks == NULL) {
+ c = (struct pr_chunk **)malloc(sizeof(struct pr_chunk *) * cnum);
+ } else {
+ c = (struct pr_chunk **)realloc(l[i].chunks, sizeof(struct pr_chunk *) * cnum);
+ }
+ if (c == NULL) {
+ for (i = 0; i < max; i++) {
+ if (l[i].chunks) free(l[i].chunks);
+ }
+ return 0;
+ }
+ c[l[i].num] = chunk;
+ l[i].chunks = c;
+ l[i].num = cnum;
+
+ *list = l;
+ return max;
+}
+
+ int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
+{
+ return dopr(str, count, fmt, args);
+}
+#endif
+
+/* yes this really must be a ||. Don't muck with this (tridge)
+ *
+ * The logic for these two is that we need our own definition if the
+ * OS *either* has no definition of *sprintf, or if it does have one
+ * that doesn't work properly according to the autoconf test.
+ */
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+ int snprintf(char *str,size_t count,const char *fmt,...)
+{
+ size_t ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(str, count, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+#endif
+
+#ifndef HAVE_C99_VSNPRINTF
+ int printf(const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+ char *s;
+
+ s = NULL;
+ va_start(ap, fmt);
+ ret = vasprintf(&s, fmt, ap);
+ va_end(ap);
+
+ if (s) {
+ fwrite(s, 1, strlen(s), stdout);
+ }
+ free(s);
+
+ return ret;
+}
+#endif
+
+#ifndef HAVE_C99_VSNPRINTF
+ int fprintf(FILE *stream, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+ char *s;
+
+ s = NULL;
+ va_start(ap, fmt);
+ ret = vasprintf(&s, fmt, ap);
+ va_end(ap);
+
+ if (s) {
+ fwrite(s, 1, strlen(s), stream);
+ }
+ free(s);
+
+ return ret;
+}
+#endif
+
+#endif
+
+#ifndef HAVE_VASPRINTF
+ int vasprintf(char **ptr, const char *format, va_list ap)
+{
+ int ret;
+ va_list ap2;
+
+ VA_COPY(ap2, ap);
+ ret = vsnprintf(NULL, 0, format, ap2);
+ va_end(ap2);
+ if (ret < 0) return ret;
+
+ (*ptr) = (char *)malloc(ret+1);
+ if (!*ptr) return -1;
+
+ VA_COPY(ap2, ap);
+ ret = vsnprintf(*ptr, ret+1, format, ap2);
+ va_end(ap2);
+
+ return ret;
+}
+#endif
+
+
+#ifndef HAVE_ASPRINTF
+ int asprintf(char **ptr, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ *ptr = NULL;
+ va_start(ap, format);
+ ret = vasprintf(ptr, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+#endif
+
+#ifdef TEST_SNPRINTF
+
+ int sprintf(char *str,const char *fmt,...);
+ int printf(const char *fmt,...);
+
+ int main (void)
+{
+ char buf1[1024];
+ char buf2[1024];
+ char *buf3;
+ char *fp_fmt[] = {
+ "%1.1f",
+ "%-1.5f",
+ "%1.5f",
+ "%123.9f",
+ "%10.5f",
+ "% 10.5f",
+ "%+22.9f",
+ "%+4.9f",
+ "%01.3f",
+ "%4f",
+ "%3.1f",
+ "%3.2f",
+ "%.0f",
+ "%f",
+ "%-8.8f",
+ "%-9.9f",
+ NULL
+ };
+ double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996,
+ 0.9996, 1.996, 4.136, 5.030201, 0.00205,
+ /* END LIST */ 0};
+ char *int_fmt[] = {
+ "%-1.5d",
+ "%1.5d",
+ "%123.9d",
+ "%5.5d",
+ "%10.5d",
+ "% 10.5d",
+ "%+22.33d",
+ "%01.3d",
+ "%4d",
+ "%d",
+ NULL
+ };
+ long int_nums[] = { -1, 134, 91340, 341, 0203, 1234567890, 0};
+ char *str_fmt[] = {
+ "%10.5s",
+ "%-10.5s",
+ "%5.10s",
+ "%-5.10s",
+ "%10.1s",
+ "%0.10s",
+ "%10.0s",
+ "%1.10s",
+ "%s",
+ "%.1s",
+ "%.10s",
+ "%10s",
+ NULL
+ };
+ char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
+#ifdef HAVE_LONG_LONG
+ char *ll_fmt[] = {
+ "%llu",
+ NULL
+ };
+ LLONG ll_nums[] = { 134, 91340, 341, 0203, 1234567890, 128006186140000000LL, 0};
+#endif
+ int x, y;
+ int fail = 0;
+ int num = 0;
+ int l1, l2;
+ char *ss_fmt[] = {
+ "%zd",
+ "%zu",
+ NULL
+ };
+ size_t ss_nums[] = {134, 91340, 123456789, 0203, 1234567890, 0};
+
+ printf ("Testing snprintf format codes against system sprintf...\n");
+
+ for (x = 0; fp_fmt[x] ; x++) {
+ for (y = 0; fp_nums[y] != 0 ; y++) {
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
+ l2 = sprintf (buf2, fp_fmt[x], fp_nums[y]);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp (buf1, buf2) || (l1 != l2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ fp_fmt[x], l1, buf1, l2, buf2);
+ fail++;
+ }
+ num++;
+ }
+ }
+
+ for (x = 0; int_fmt[x] ; x++) {
+ for (y = 0; int_nums[y] != 0 ; y++) {
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
+ l2 = sprintf (buf2, int_fmt[x], int_nums[y]);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp (buf1, buf2) || (l1 != l2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ int_fmt[x], l1, buf1, l2, buf2);
+ fail++;
+ }
+ num++;
+ }
+ }
+
+ for (x = 0; str_fmt[x] ; x++) {
+ for (y = 0; str_vals[y] != 0 ; y++) {
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
+ l2 = sprintf (buf2, str_fmt[x], str_vals[y]);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp (buf1, buf2) || (l1 != l2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ str_fmt[x], l1, buf1, l2, buf2);
+ fail++;
+ }
+ num++;
+ }
+ }
+
+#ifdef HAVE_LONG_LONG
+ for (x = 0; ll_fmt[x] ; x++) {
+ for (y = 0; ll_nums[y] != 0 ; y++) {
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
+ l2 = sprintf (buf2, ll_fmt[x], ll_nums[y]);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp (buf1, buf2) || (l1 != l2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ ll_fmt[x], l1, buf1, l2, buf2);
+ fail++;
+ }
+ num++;
+ }
+ }
+#endif
+
+#define BUFSZ 2048
+
+ buf1[0] = buf2[0] = '\0';
+ if ((buf3 = malloc(BUFSZ)) == NULL) {
+ fail++;
+ } else {
+ num++;
+ memset(buf3, 'a', BUFSZ);
+ snprintf(buf1, sizeof(buf1), "%.*s", 1, buf3);
+ buf1[1023] = '\0';
+ if (strcmp(buf1, "a") != 0) {
+ printf("length limit buf1 '%s' expected 'a'\n", buf1);
+ fail++;
+ }
+ }
+
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
+ l2 = sprintf(buf2, "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp(buf1, buf2) || (l1 != l2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
+ fail++;
+ }
+
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
+ l2 = sprintf(buf2, "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp(buf1, buf2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
+ fail++;
+ }
+
+ for (x = 0; ss_fmt[x] ; x++) {
+ for (y = 0; ss_nums[y] != 0 ; y++) {
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), ss_fmt[x], ss_nums[y]);
+ l2 = sprintf (buf2, ss_fmt[x], ss_nums[y]);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp (buf1, buf2) || (l1 != l2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ ss_fmt[x], l1, buf1, l2, buf2);
+ fail++;
+ }
+ num++;
+ }
+ }
+#if 0
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), "%lld", (LLONG)1234567890);
+ l2 = sprintf(buf2, "%lld", (LLONG)1234567890);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp(buf1, buf2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ "%lld", l1, buf1, l2, buf2);
+ fail++;
+ }
+
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), "%Lf", (LDOUBLE)890.1234567890123);
+ l2 = sprintf(buf2, "%Lf", (LDOUBLE)890.1234567890123);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp(buf1, buf2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ "%Lf", l1, buf1, l2, buf2);
+ fail++;
+ }
+#endif
+ printf ("%d tests failed out of %d.\n", fail, num);
+
+ printf("seeing how many digits we support\n");
+ {
+ double v0 = 0.12345678901234567890123456789012345678901;
+ for (x=0; x<100; x++) {
+ double p = pow(10, x);
+ double r = v0*p;
+ snprintf(buf1, sizeof(buf1), "%1.1f", r);
+ sprintf(buf2, "%1.1f", r);
+ if (strcmp(buf1, buf2)) {
+ printf("we seem to support %d digits\n", x-1);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+#endif /* TEST_SNPRINTF */
diff --git a/source3/lib/replace/socket.c b/source3/lib/replace/socket.c
new file mode 100644
index 0000000000..35e975fce7
--- /dev/null
+++ b/source3/lib/replace/socket.c
@@ -0,0 +1,35 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Dummy replacements for socket functions.
+ *
+ * Copyright (C) Michael Adam <obnox@samba.org> 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/network.h"
+
+int rep_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+struct hostent *rep_gethostbyname(const char *name)
+{
+ errno = ENOSYS;
+ return NULL;
+}
diff --git a/source3/lib/replace/socketpair.c b/source3/lib/replace/socketpair.c
new file mode 100644
index 0000000000..c775730952
--- /dev/null
+++ b/source3/lib/replace/socketpair.c
@@ -0,0 +1,46 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * replacement routines for broken systems
+ * Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2006
+ * Copyright (C) Michael Adam <obnox@samba.org> 2008
+ *
+ * ** NOTE! The following LGPL license applies to the replace
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/network.h"
+
+int rep_socketpair(int d, int type, int protocol, int sv[2])
+{
+ if (d != AF_UNIX) {
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ if (protocol != 0) {
+ errno = EPROTONOSUPPORT;
+ return -1;
+ }
+
+ if (type != SOCK_STREAM) {
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+
+ return pipe(sv);
+}
diff --git a/source3/lib/replace/strptime.c b/source3/lib/replace/strptime.c
new file mode 100644
index 0000000000..0e40f7561a
--- /dev/null
+++ b/source3/lib/replace/strptime.c
@@ -0,0 +1,990 @@
+/* Convert a string representation of time to a time value.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 3 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ see <http://www.gnu.org/licenses/>. */
+
+/* XXX This version of the implementation is not really complete.
+ Some of the fields cannot add information alone. But if seeing
+ some of them in the same format (such as year, week and weekday)
+ this is enough information for determining the date. */
+
+#include "replace.h"
+#include "system/locale.h"
+#include "system/time.h"
+
+#ifndef __P
+# if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
+# define __P(args) args
+# else
+# define __P(args) ()
+# endif /* GCC. */
+#endif /* Not __P. */
+
+#if ! HAVE_LOCALTIME_R && ! defined localtime_r
+# ifdef _LIBC
+# define localtime_r __localtime_r
+# else
+/* Approximate localtime_r as best we can in its absence. */
+# define localtime_r my_localtime_r
+static struct tm *localtime_r __P ((const time_t *, struct tm *));
+static struct tm *
+localtime_r (t, tp)
+ const time_t *t;
+ struct tm *tp;
+{
+ struct tm *l = localtime (t);
+ if (! l)
+ return 0;
+ *tp = *l;
+ return tp;
+}
+# endif /* ! _LIBC */
+#endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
+
+
+#define match_char(ch1, ch2) if (ch1 != ch2) return NULL
+#if defined __GNUC__ && __GNUC__ >= 2
+# define match_string(cs1, s2) \
+ ({ size_t len = strlen (cs1); \
+ int result = strncasecmp ((cs1), (s2), len) == 0; \
+ if (result) (s2) += len; \
+ result; })
+#else
+/* Oh come on. Get a reasonable compiler. */
+# define match_string(cs1, s2) \
+ (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
+#endif
+/* We intentionally do not use isdigit() for testing because this will
+ lead to problems with the wide character version. */
+#define get_number(from, to, n) \
+ do { \
+ int __n = n; \
+ val = 0; \
+ while (*rp == ' ') \
+ ++rp; \
+ if (*rp < '0' || *rp > '9') \
+ return NULL; \
+ do { \
+ val *= 10; \
+ val += *rp++ - '0'; \
+ } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \
+ if (val < from || val > to) \
+ return NULL; \
+ } while (0)
+#ifdef _NL_CURRENT
+# define get_alt_number(from, to, n) \
+ ({ \
+ __label__ do_normal; \
+ if (*decided != raw) \
+ { \
+ const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS); \
+ int __n = n; \
+ int any = 0; \
+ while (*rp == ' ') \
+ ++rp; \
+ val = 0; \
+ do { \
+ val *= 10; \
+ while (*alts != '\0') \
+ { \
+ size_t len = strlen (alts); \
+ if (strncasecmp (alts, rp, len) == 0) \
+ break; \
+ alts += len + 1; \
+ ++val; \
+ } \
+ if (*alts == '\0') \
+ { \
+ if (*decided == not && ! any) \
+ goto do_normal; \
+ /* If we haven't read anything it's an error. */ \
+ if (! any) \
+ return NULL; \
+ /* Correct the premature multiplication. */ \
+ val /= 10; \
+ break; \
+ } \
+ else \
+ *decided = loc; \
+ } while (--__n > 0 && val * 10 <= to); \
+ if (val < from || val > to) \
+ return NULL; \
+ } \
+ else \
+ { \
+ do_normal: \
+ get_number (from, to, n); \
+ } \
+ 0; \
+ })
+#else
+# define get_alt_number(from, to, n) \
+ /* We don't have the alternate representation. */ \
+ get_number(from, to, n)
+#endif
+#define recursive(new_fmt) \
+ (*(new_fmt) != '\0' \
+ && (rp = strptime_internal (rp, (new_fmt), tm, decided, era_cnt)) != NULL)
+
+
+#ifdef _LIBC
+/* This is defined in locale/C-time.c in the GNU libc. */
+extern const struct locale_data _nl_C_LC_TIME;
+extern const unsigned short int __mon_yday[2][13];
+
+# define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
+# define ab_weekday_name \
+ (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
+# define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
+# define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
+# define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
+# define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
+# define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
+# define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
+# define HERE_T_FMT_AMPM \
+ (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
+# define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
+
+# define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
+#else
+static char const weekday_name[][10] =
+ {
+ "Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday"
+ };
+static char const ab_weekday_name[][4] =
+ {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+static char const month_name[][10] =
+ {
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"
+ };
+static char const ab_month_name[][4] =
+ {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+# define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
+# define HERE_D_FMT "%m/%d/%y"
+# define HERE_AM_STR "AM"
+# define HERE_PM_STR "PM"
+# define HERE_T_FMT_AMPM "%I:%M:%S %p"
+# define HERE_T_FMT "%H:%M:%S"
+
+static const unsigned short int __mon_yday[2][13] =
+ {
+ /* Normal years. */
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ /* Leap years. */
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+ };
+#endif
+
+/* Status of lookup: do we use the locale data or the raw data? */
+enum locale_status { not, loc, raw };
+
+
+#ifndef __isleap
+/* Nonzero if YEAR is a leap year (every 4 years,
+ except every 100th isn't, and every 400th is). */
+# define __isleap(year) \
+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+#endif
+
+/* Compute the day of the week. */
+static void
+day_of_the_week (struct tm *tm)
+{
+ /* We know that January 1st 1970 was a Thursday (= 4). Compute the
+ the difference between this data in the one on TM and so determine
+ the weekday. */
+ int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
+ int wday = (-473
+ + (365 * (tm->tm_year - 70))
+ + (corr_year / 4)
+ - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
+ + (((corr_year / 4) / 25) / 4)
+ + __mon_yday[0][tm->tm_mon]
+ + tm->tm_mday - 1);
+ tm->tm_wday = ((wday % 7) + 7) % 7;
+}
+
+/* Compute the day of the year. */
+static void
+day_of_the_year (struct tm *tm)
+{
+ tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
+ + (tm->tm_mday - 1));
+}
+
+static char *
+#ifdef _LIBC
+internal_function
+#endif
+strptime_internal __P ((const char *rp, const char *fmt, struct tm *tm,
+ enum locale_status *decided, int era_cnt));
+
+static char *
+#ifdef _LIBC
+internal_function
+#endif
+strptime_internal (rp, fmt, tm, decided, era_cnt)
+ const char *rp;
+ const char *fmt;
+ struct tm *tm;
+ enum locale_status *decided;
+ int era_cnt;
+{
+ const char *rp_backup;
+ int cnt;
+ size_t val;
+ int have_I, is_pm;
+ int century, want_century;
+ int want_era;
+ int have_wday, want_xday;
+ int have_yday;
+ int have_mon, have_mday;
+#ifdef _NL_CURRENT
+ size_t num_eras;
+#endif
+ struct era_entry *era;
+
+ have_I = is_pm = 0;
+ century = -1;
+ want_century = 0;
+ want_era = 0;
+ era = NULL;
+
+ have_wday = want_xday = have_yday = have_mon = have_mday = 0;
+
+ while (*fmt != '\0')
+ {
+ /* A white space in the format string matches 0 more or white
+ space in the input string. */
+ if (isspace (*fmt))
+ {
+ while (isspace (*rp))
+ ++rp;
+ ++fmt;
+ continue;
+ }
+
+ /* Any character but `%' must be matched by the same character
+ in the iput string. */
+ if (*fmt != '%')
+ {
+ match_char (*fmt++, *rp++);
+ continue;
+ }
+
+ ++fmt;
+#ifndef _NL_CURRENT
+ /* We need this for handling the `E' modifier. */
+ start_over:
+#endif
+
+ /* Make back up of current processing pointer. */
+ rp_backup = rp;
+
+ switch (*fmt++)
+ {
+ case '%':
+ /* Match the `%' character itself. */
+ match_char ('%', *rp++);
+ break;
+ case 'a':
+ case 'A':
+ /* Match day of week. */
+ for (cnt = 0; cnt < 7; ++cnt)
+ {
+#ifdef _NL_CURRENT
+ if (*decided !=raw)
+ {
+ if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
+ {
+ if (*decided == not
+ && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
+ weekday_name[cnt]))
+ *decided = loc;
+ break;
+ }
+ if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
+ {
+ if (*decided == not
+ && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
+ ab_weekday_name[cnt]))
+ *decided = loc;
+ break;
+ }
+ }
+#endif
+ if (*decided != loc
+ && (match_string (weekday_name[cnt], rp)
+ || match_string (ab_weekday_name[cnt], rp)))
+ {
+ *decided = raw;
+ break;
+ }
+ }
+ if (cnt == 7)
+ /* Does not match a weekday name. */
+ return NULL;
+ tm->tm_wday = cnt;
+ have_wday = 1;
+ break;
+ case 'b':
+ case 'B':
+ case 'h':
+ /* Match month name. */
+ for (cnt = 0; cnt < 12; ++cnt)
+ {
+#ifdef _NL_CURRENT
+ if (*decided !=raw)
+ {
+ if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
+ {
+ if (*decided == not
+ && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
+ month_name[cnt]))
+ *decided = loc;
+ break;
+ }
+ if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
+ {
+ if (*decided == not
+ && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
+ ab_month_name[cnt]))
+ *decided = loc;
+ break;
+ }
+ }
+#endif
+ if (match_string (month_name[cnt], rp)
+ || match_string (ab_month_name[cnt], rp))
+ {
+ *decided = raw;
+ break;
+ }
+ }
+ if (cnt == 12)
+ /* Does not match a month name. */
+ return NULL;
+ tm->tm_mon = cnt;
+ want_xday = 1;
+ break;
+ case 'c':
+ /* Match locale's date and time format. */
+#ifdef _NL_CURRENT
+ if (*decided != raw)
+ {
+ if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (*decided == not &&
+ strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
+ *decided = loc;
+ want_xday = 1;
+ break;
+ }
+ *decided = raw;
+ }
+#endif
+ if (!recursive (HERE_D_T_FMT))
+ return NULL;
+ want_xday = 1;
+ break;
+ case 'C':
+ /* Match century number. */
+#ifdef _NL_CURRENT
+ match_century:
+#endif
+ get_number (0, 99, 2);
+ century = val;
+ want_xday = 1;
+ break;
+ case 'd':
+ case 'e':
+ /* Match day of month. */
+ get_number (1, 31, 2);
+ tm->tm_mday = val;
+ have_mday = 1;
+ want_xday = 1;
+ break;
+ case 'F':
+ if (!recursive ("%Y-%m-%d"))
+ return NULL;
+ want_xday = 1;
+ break;
+ case 'x':
+#ifdef _NL_CURRENT
+ if (*decided != raw)
+ {
+ if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (*decided == not
+ && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
+ *decided = loc;
+ want_xday = 1;
+ break;
+ }
+ *decided = raw;
+ }
+#endif
+ /* Fall through. */
+ case 'D':
+ /* Match standard day format. */
+ if (!recursive (HERE_D_FMT))
+ return NULL;
+ want_xday = 1;
+ break;
+ case 'k':
+ case 'H':
+ /* Match hour in 24-hour clock. */
+ get_number (0, 23, 2);
+ tm->tm_hour = val;
+ have_I = 0;
+ break;
+ case 'I':
+ /* Match hour in 12-hour clock. */
+ get_number (1, 12, 2);
+ tm->tm_hour = val % 12;
+ have_I = 1;
+ break;
+ case 'j':
+ /* Match day number of year. */
+ get_number (1, 366, 3);
+ tm->tm_yday = val - 1;
+ have_yday = 1;
+ break;
+ case 'm':
+ /* Match number of month. */
+ get_number (1, 12, 2);
+ tm->tm_mon = val - 1;
+ have_mon = 1;
+ want_xday = 1;
+ break;
+ case 'M':
+ /* Match minute. */
+ get_number (0, 59, 2);
+ tm->tm_min = val;
+ break;
+ case 'n':
+ case 't':
+ /* Match any white space. */
+ while (isspace (*rp))
+ ++rp;
+ break;
+ case 'p':
+ /* Match locale's equivalent of AM/PM. */
+#ifdef _NL_CURRENT
+ if (*decided != raw)
+ {
+ if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
+ {
+ if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
+ *decided = loc;
+ break;
+ }
+ if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
+ {
+ if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
+ *decided = loc;
+ is_pm = 1;
+ break;
+ }
+ *decided = raw;
+ }
+#endif
+ if (!match_string (HERE_AM_STR, rp)) {
+ if (match_string (HERE_PM_STR, rp)) {
+ is_pm = 1;
+ } else {
+ return NULL;
+ }
+ }
+ break;
+ case 'r':
+#ifdef _NL_CURRENT
+ if (*decided != raw)
+ {
+ if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (*decided == not &&
+ strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
+ HERE_T_FMT_AMPM))
+ *decided = loc;
+ break;
+ }
+ *decided = raw;
+ }
+#endif
+ if (!recursive (HERE_T_FMT_AMPM))
+ return NULL;
+ break;
+ case 'R':
+ if (!recursive ("%H:%M"))
+ return NULL;
+ break;
+ case 's':
+ {
+ /* The number of seconds may be very high so we cannot use
+ the `get_number' macro. Instead read the number
+ character for character and construct the result while
+ doing this. */
+ time_t secs = 0;
+ if (*rp < '0' || *rp > '9')
+ /* We need at least one digit. */
+ return NULL;
+
+ do
+ {
+ secs *= 10;
+ secs += *rp++ - '0';
+ }
+ while (*rp >= '0' && *rp <= '9');
+
+ if (localtime_r (&secs, tm) == NULL)
+ /* Error in function. */
+ return NULL;
+ }
+ break;
+ case 'S':
+ get_number (0, 61, 2);
+ tm->tm_sec = val;
+ break;
+ case 'X':
+#ifdef _NL_CURRENT
+ if (*decided != raw)
+ {
+ if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
+ *decided = loc;
+ break;
+ }
+ *decided = raw;
+ }
+#endif
+ /* Fall through. */
+ case 'T':
+ if (!recursive (HERE_T_FMT))
+ return NULL;
+ break;
+ case 'u':
+ get_number (1, 7, 1);
+ tm->tm_wday = val % 7;
+ have_wday = 1;
+ break;
+ case 'g':
+ get_number (0, 99, 2);
+ /* XXX This cannot determine any field in TM. */
+ break;
+ case 'G':
+ if (*rp < '0' || *rp > '9')
+ return NULL;
+ /* XXX Ignore the number since we would need some more
+ information to compute a real date. */
+ do
+ ++rp;
+ while (*rp >= '0' && *rp <= '9');
+ break;
+ case 'U':
+ case 'V':
+ case 'W':
+ get_number (0, 53, 2);
+ /* XXX This cannot determine any field in TM without some
+ information. */
+ break;
+ case 'w':
+ /* Match number of weekday. */
+ get_number (0, 6, 1);
+ tm->tm_wday = val;
+ have_wday = 1;
+ break;
+ case 'y':
+#ifdef _NL_CURRENT
+ match_year_in_century:
+#endif
+ /* Match year within century. */
+ get_number (0, 99, 2);
+ /* The "Year 2000: The Millennium Rollover" paper suggests that
+ values in the range 69-99 refer to the twentieth century. */
+ tm->tm_year = val >= 69 ? val : val + 100;
+ /* Indicate that we want to use the century, if specified. */
+ want_century = 1;
+ want_xday = 1;
+ break;
+ case 'Y':
+ /* Match year including century number. */
+ get_number (0, 9999, 4);
+ tm->tm_year = val - 1900;
+ want_century = 0;
+ want_xday = 1;
+ break;
+ case 'Z':
+ /* XXX How to handle this? */
+ break;
+ case 'E':
+#ifdef _NL_CURRENT
+ switch (*fmt++)
+ {
+ case 'c':
+ /* Match locale's alternate date and time format. */
+ if (*decided != raw)
+ {
+ const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
+
+ if (*fmt == '\0')
+ fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
+
+ if (!recursive (fmt))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (strcmp (fmt, HERE_D_T_FMT))
+ *decided = loc;
+ want_xday = 1;
+ break;
+ }
+ *decided = raw;
+ }
+ /* The C locale has no era information, so use the
+ normal representation. */
+ if (!recursive (HERE_D_T_FMT))
+ return NULL;
+ want_xday = 1;
+ break;
+ case 'C':
+ if (*decided != raw)
+ {
+ if (era_cnt >= 0)
+ {
+ era = _nl_select_era_entry (era_cnt);
+ if (match_string (era->era_name, rp))
+ {
+ *decided = loc;
+ break;
+ }
+ else
+ return NULL;
+ }
+ else
+ {
+ num_eras = _NL_CURRENT_WORD (LC_TIME,
+ _NL_TIME_ERA_NUM_ENTRIES);
+ for (era_cnt = 0; era_cnt < (int) num_eras;
+ ++era_cnt, rp = rp_backup)
+ {
+ era = _nl_select_era_entry (era_cnt);
+ if (match_string (era->era_name, rp))
+ {
+ *decided = loc;
+ break;
+ }
+ }
+ if (era_cnt == (int) num_eras)
+ {
+ era_cnt = -1;
+ if (*decided == loc)
+ return NULL;
+ }
+ else
+ break;
+ }
+
+ *decided = raw;
+ }
+ /* The C locale has no era information, so use the
+ normal representation. */
+ goto match_century;
+ case 'y':
+ if (*decided == raw)
+ goto match_year_in_century;
+
+ get_number(0, 9999, 4);
+ tm->tm_year = val;
+ want_era = 1;
+ want_xday = 1;
+ break;
+ case 'Y':
+ if (*decided != raw)
+ {
+ num_eras = _NL_CURRENT_WORD (LC_TIME,
+ _NL_TIME_ERA_NUM_ENTRIES);
+ for (era_cnt = 0; era_cnt < (int) num_eras;
+ ++era_cnt, rp = rp_backup)
+ {
+ era = _nl_select_era_entry (era_cnt);
+ if (recursive (era->era_format))
+ break;
+ }
+ if (era_cnt == (int) num_eras)
+ {
+ era_cnt = -1;
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ *decided = loc;
+ era_cnt = -1;
+ break;
+ }
+
+ *decided = raw;
+ }
+ get_number (0, 9999, 4);
+ tm->tm_year = val - 1900;
+ want_century = 0;
+ want_xday = 1;
+ break;
+ case 'x':
+ if (*decided != raw)
+ {
+ const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
+
+ if (*fmt == '\0')
+ fmt = _NL_CURRENT (LC_TIME, D_FMT);
+
+ if (!recursive (fmt))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (strcmp (fmt, HERE_D_FMT))
+ *decided = loc;
+ break;
+ }
+ *decided = raw;
+ }
+ if (!recursive (HERE_D_FMT))
+ return NULL;
+ break;
+ case 'X':
+ if (*decided != raw)
+ {
+ const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
+
+ if (*fmt == '\0')
+ fmt = _NL_CURRENT (LC_TIME, T_FMT);
+
+ if (!recursive (fmt))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (strcmp (fmt, HERE_T_FMT))
+ *decided = loc;
+ break;
+ }
+ *decided = raw;
+ }
+ if (!recursive (HERE_T_FMT))
+ return NULL;
+ break;
+ default:
+ return NULL;
+ }
+ break;
+#else
+ /* We have no information about the era format. Just use
+ the normal format. */
+ if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
+ && *fmt != 'x' && *fmt != 'X')
+ /* This is an illegal format. */
+ return NULL;
+
+ goto start_over;
+#endif
+ case 'O':
+ switch (*fmt++)
+ {
+ case 'd':
+ case 'e':
+ /* Match day of month using alternate numeric symbols. */
+ get_alt_number (1, 31, 2);
+ tm->tm_mday = val;
+ have_mday = 1;
+ want_xday = 1;
+ break;
+ case 'H':
+ /* Match hour in 24-hour clock using alternate numeric
+ symbols. */
+ get_alt_number (0, 23, 2);
+ tm->tm_hour = val;
+ have_I = 0;
+ break;
+ case 'I':
+ /* Match hour in 12-hour clock using alternate numeric
+ symbols. */
+ get_alt_number (1, 12, 2);
+ tm->tm_hour = val - 1;
+ have_I = 1;
+ break;
+ case 'm':
+ /* Match month using alternate numeric symbols. */
+ get_alt_number (1, 12, 2);
+ tm->tm_mon = val - 1;
+ have_mon = 1;
+ want_xday = 1;
+ break;
+ case 'M':
+ /* Match minutes using alternate numeric symbols. */
+ get_alt_number (0, 59, 2);
+ tm->tm_min = val;
+ break;
+ case 'S':
+ /* Match seconds using alternate numeric symbols. */
+ get_alt_number (0, 61, 2);
+ tm->tm_sec = val;
+ break;
+ case 'U':
+ case 'V':
+ case 'W':
+ get_alt_number (0, 53, 2);
+ /* XXX This cannot determine any field in TM without
+ further information. */
+ break;
+ case 'w':
+ /* Match number of weekday using alternate numeric symbols. */
+ get_alt_number (0, 6, 1);
+ tm->tm_wday = val;
+ have_wday = 1;
+ break;
+ case 'y':
+ /* Match year within century using alternate numeric symbols. */
+ get_alt_number (0, 99, 2);
+ tm->tm_year = val >= 69 ? val : val + 100;
+ want_xday = 1;
+ break;
+ default:
+ return NULL;
+ }
+ break;
+ default:
+ return NULL;
+ }
+ }
+
+ if (have_I && is_pm)
+ tm->tm_hour += 12;
+
+ if (century != -1)
+ {
+ if (want_century)
+ tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
+ else
+ /* Only the century, but not the year. Strange, but so be it. */
+ tm->tm_year = (century - 19) * 100;
+ }
+
+#ifdef _NL_CURRENT
+ if (era_cnt != -1)
+ {
+ era = _nl_select_era_entry(era_cnt);
+ if (want_era)
+ tm->tm_year = (era->start_date[0]
+ + ((tm->tm_year - era->offset)
+ * era->absolute_direction));
+ else
+ /* Era start year assumed. */
+ tm->tm_year = era->start_date[0];
+ }
+ else
+#endif
+ if (want_era)
+ return NULL;
+
+ if (want_xday && !have_wday)
+ {
+ if ( !(have_mon && have_mday) && have_yday)
+ {
+ /* We don't have tm_mon and/or tm_mday, compute them. */
+ int t_mon = 0;
+ while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
+ t_mon++;
+ if (!have_mon)
+ tm->tm_mon = t_mon - 1;
+ if (!have_mday)
+ tm->tm_mday =
+ (tm->tm_yday
+ - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
+ }
+ day_of_the_week (tm);
+ }
+ if (want_xday && !have_yday)
+ day_of_the_year (tm);
+
+ return discard_const_p(char, rp);
+}
+
+
+char *rep_strptime(const char *buf, const char *format, struct tm *tm)
+{
+ enum locale_status decided;
+
+#ifdef _NL_CURRENT
+ decided = not;
+#else
+ decided = raw;
+#endif
+ return strptime_internal (buf, format, tm, &decided, -1);
+}
diff --git a/source3/lib/replace/strptime.m4 b/source3/lib/replace/strptime.m4
new file mode 100644
index 0000000000..da22fc5a97
--- /dev/null
+++ b/source3/lib/replace/strptime.m4
@@ -0,0 +1,13 @@
+AC_CACHE_CHECK([whether strptime is available and works],libreplace_cv_STRPTIME_OK,[
+ AC_TRY_RUN([
+ #define LIBREPLACE_CONFIGURE_TEST_STRPTIME
+ #include "$libreplacedir/test/strptime.c"
+ ],
+ [libreplace_cv_STRPTIME_OK=yes],
+ [libreplace_cv_STRPTIME_OK=no],
+ [libreplace_cv_STRPTIME_OK="assuming not"])
+])
+if test x"$libreplace_cv_STRPTIME_OK" != x"yes"; then
+ AC_DEFINE(REPLACE_STRPTIME,1,[Whether strptime should be replaced])
+ LIBREPLACEOBJ="${LIBREPLACEOBJ} strptime.o"
+fi
diff --git a/source3/lib/replace/system/README b/source3/lib/replace/system/README
new file mode 100644
index 0000000000..69a2b80b56
--- /dev/null
+++ b/source3/lib/replace/system/README
@@ -0,0 +1,4 @@
+This directory contains wrappers around logical groups of system
+include files. The idea is to avoid #ifdef blocks in the main code,
+and instead put all the necessary conditional includes in subsystem
+specific header files in this directory.
diff --git a/source3/lib/replace/system/aio.h b/source3/lib/replace/system/aio.h
new file mode 100644
index 0000000000..784d77fa28
--- /dev/null
+++ b/source3/lib/replace/system/aio.h
@@ -0,0 +1,32 @@
+#ifndef _system_aio_h
+#define _system_aio_h
+/*
+ Unix SMB/CIFS implementation.
+
+ AIO system include wrappers
+
+ Copyright (C) Andrew Tridgell 2006
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_LIBAIO_H
+#include <libaio.h>
+#endif
+
+#endif
diff --git a/source3/lib/replace/system/capability.h b/source3/lib/replace/system/capability.h
new file mode 100644
index 0000000000..a7b78f0275
--- /dev/null
+++ b/source3/lib/replace/system/capability.h
@@ -0,0 +1,55 @@
+#ifndef _system_capability_h
+#define _system_capability_h
+/*
+ Unix SMB/CIFS implementation.
+
+ capability system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_SYS_CAPABILITY_H
+
+#if defined(BROKEN_REDHAT_7_SYSTEM_HEADERS) && !defined(_I386_STATFS_H) && !defined(_PPC_STATFS_H)
+#define _I386_STATFS_H
+#define _PPC_STATFS_H
+#define BROKEN_REDHAT_7_STATFS_WORKAROUND
+#endif
+
+#if defined(BROKEN_RHEL5_SYS_CAP_HEADER) && !defined(_LINUX_TYPES_H)
+#define BROKEN_RHEL5_SYS_CAP_HEADER_WORKAROUND
+#endif
+
+#include <sys/capability.h>
+
+#ifdef BROKEN_RHEL5_SYS_CAP_HEADER_WORKAROUND
+#undef _LINUX_TYPES_H
+#undef BROKEN_RHEL5_SYS_CAP_HEADER_WORKAROUND
+#endif
+
+#ifdef BROKEN_REDHAT_7_STATFS_WORKAROUND
+#undef _PPC_STATFS_H
+#undef _I386_STATFS_H
+#undef BROKEN_REDHAT_7_STATFS_WORKAROUND
+#endif
+
+#endif
+
+#endif
diff --git a/source3/lib/replace/system/config.m4 b/source3/lib/replace/system/config.m4
new file mode 100644
index 0000000000..5c9b53d5c5
--- /dev/null
+++ b/source3/lib/replace/system/config.m4
@@ -0,0 +1,130 @@
+# filesys
+AC_HEADER_DIRENT
+AC_CHECK_HEADERS(fcntl.h sys/fcntl.h sys/resource.h sys/ioctl.h sys/mode.h sys/filio.h sys/fs/s5param.h sys/filsys.h)
+AC_CHECK_HEADERS(sys/acl.h acl/libacl.h)
+
+# select
+AC_CHECK_HEADERS(sys/select.h)
+
+# time
+AC_CHECK_HEADERS(sys/time.h utime.h)
+AC_HEADER_TIME
+AC_CHECK_FUNCS(utime utimes)
+
+# wait
+AC_HEADER_SYS_WAIT
+
+# capability
+AC_CHECK_HEADERS(sys/capability.h)
+
+case "$host_os" in
+*linux*)
+AC_CACHE_CHECK([for broken RedHat 7.2 system header files],libreplace_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS,[
+AC_TRY_COMPILE([
+ #ifdef HAVE_SYS_VFS_H
+ #include <sys/vfs.h>
+ #endif
+ #ifdef HAVE_SYS_CAPABILITY_H
+ #include <sys/capability.h>
+ #endif
+ ],[
+ int i;
+ ],
+ libreplace_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS=no,
+ libreplace_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS=yes
+)])
+if test x"$libreplace_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS" = x"yes"; then
+ AC_DEFINE(BROKEN_REDHAT_7_SYSTEM_HEADERS,1,[Broken RedHat 7.2 system header files])
+fi
+
+AC_CACHE_CHECK([for broken RHEL5 sys/capability.h],libreplace_cv_BROKEN_RHEL5_SYS_CAP_HEADER,[
+AC_TRY_COMPILE([
+ #ifdef HAVE_SYS_CAPABILITY_H
+ #include <sys/capability.h>
+ #endif
+ #include <linux/types.h>
+ ],[
+ __s8 i;
+ ],
+ libreplace_cv_BROKEN_RHEL5_SYS_CAP_HEADER=no,
+ libreplace_cv_BROKEN_RHEL5_SYS_CAP_HEADER=yes
+)])
+if test x"$libreplace_cv_BROKEN_RHEL5_SYS_CAP_HEADER" = x"yes"; then
+ AC_DEFINE(BROKEN_RHEL5_SYS_CAP_HEADER,1,[Broken RHEL5 sys/capability.h])
+fi
+;;
+esac
+
+# passwd
+AC_CHECK_HEADERS(grp.h sys/id.h compat.h shadow.h sys/priv.h pwd.h sys/security.h)
+AC_CHECK_FUNCS(getpwnam_r getpwuid_r getpwent_r)
+AC_HAVE_DECL(getpwent_r, [
+ #include <unistd.h>
+ #include <pwd.h>
+ ])
+AC_VERIFY_C_PROTOTYPE([struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)],
+ [
+ #ifndef HAVE_GETPWENT_R_DECL
+ #error missing getpwent_r prototype
+ #endif
+ return NULL;
+ ],[
+ AC_DEFINE(SOLARIS_GETPWENT_R, 1, [getpwent_r solaris function prototype])
+ ],[],[
+ #include <unistd.h>
+ #include <pwd.h>
+ ])
+AC_VERIFY_C_PROTOTYPE([struct passwd *getpwent_r(struct passwd *src, char *buf, size_t buflen)],
+ [
+ #ifndef HAVE_GETPWENT_R_DECL
+ #error missing getpwent_r prototype
+ #endif
+ return NULL;
+ ],[
+ AC_DEFINE(SOLARIS_GETPWENT_R, 1, [getpwent_r irix (similar to solaris) function prototype])
+ ],[],[
+ #include <unistd.h>
+ #include <pwd.h>
+ ])
+AC_CHECK_FUNCS(getgrnam_r getgrgid_r getgrent_r)
+AC_HAVE_DECL(getgrent_r, [
+ #include <unistd.h>
+ #include <grp.h>
+ ])
+AC_VERIFY_C_PROTOTYPE([struct group *getgrent_r(struct group *src, char *buf, int buflen)],
+ [
+ #ifndef HAVE_GETGRENT_R_DECL
+ #error missing getgrent_r prototype
+ #endif
+ return NULL;
+ ],[
+ AC_DEFINE(SOLARIS_GETGRENT_R, 1, [getgrent_r solaris function prototype])
+ ],[],[
+ #include <unistd.h>
+ #include <grp.h>
+ ])
+
+AC_VERIFY_C_PROTOTYPE([struct group *getgrent_r(struct group *src, char *buf, size_t buflen)],
+ [
+ #ifndef HAVE_GETGRENT_R_DECL
+ #error missing getgrent_r prototype
+ #endif
+ return NULL;
+ ],[
+ AC_DEFINE(SOLARIS_GETGRENT_R, 1, [getgrent_r irix (similar to solaris) function prototype])
+ ],[],[
+ #include <unistd.h>
+ #include <grp.h>
+ ])
+
+# locale
+AC_CHECK_HEADERS(ctype.h locale.h)
+
+# glob
+AC_CHECK_HEADERS(fnmatch.h)
+
+# shmem
+AC_CHECK_HEADERS(sys/ipc.h sys/mman.h sys/shm.h )
+
+# terminal
+AC_CHECK_HEADERS(termios.h termio.h sys/termio.h )
diff --git a/source3/lib/replace/system/dir.h b/source3/lib/replace/system/dir.h
new file mode 100644
index 0000000000..dec2d54649
--- /dev/null
+++ b/source3/lib/replace/system/dir.h
@@ -0,0 +1,67 @@
+#ifndef _system_dir_h
+#define _system_dir_h
+/*
+ Unix SMB/CIFS implementation.
+
+ directory system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#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
+
+#ifndef HAVE_MKDIR_MODE
+#define mkdir(dir, mode) mkdir(dir)
+#endif
+
+/* Test whether a file name is the "." or ".." directory entries.
+ * These really should be inline functions.
+ */
+#ifndef ISDOT
+#define ISDOT(path) ( \
+ *((const char *)(path)) == '.' && \
+ *(((const char *)(path)) + 1) == '\0' \
+ )
+#endif
+
+#ifndef ISDOTDOT
+#define ISDOTDOT(path) ( \
+ *((const char *)(path)) == '.' && \
+ *(((const char *)(path)) + 1) == '.' && \
+ *(((const char *)(path)) + 2) == '\0' \
+ )
+#endif
+
+#endif
diff --git a/source3/lib/replace/system/filesys.h b/source3/lib/replace/system/filesys.h
new file mode 100644
index 0000000000..4bf1f64865
--- /dev/null
+++ b/source3/lib/replace/system/filesys.h
@@ -0,0 +1,182 @@
+#ifndef _system_filesys_h
+#define _system_filesys_h
+/*
+ Unix SMB/CIFS implementation.
+
+ filesystem system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <unistd.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+
+#ifdef HAVE_MNTENT_H
+#include <mntent.h>
+#endif
+
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+
+#ifdef HAVE_SYS_ACL_H
+#include <sys/acl.h>
+#endif
+
+#ifdef HAVE_ACL_LIBACL_H
+#include <acl/libacl.h>
+#endif
+
+#ifdef HAVE_SYS_FS_S5PARAM_H
+#include <sys/fs/s5param.h>
+#endif
+
+#if defined (HAVE_SYS_FILSYS_H) && !defined (_CRAY)
+#include <sys/filsys.h>
+#endif
+
+#ifdef HAVE_SYS_STATFS_H
+# include <sys/statfs.h>
+#endif
+
+#ifdef HAVE_DUSTAT_H
+#include <sys/dustat.h>
+#endif
+
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+
+#include <sys/file.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#ifdef HAVE_SYS_FCNTL_H
+#include <sys/fcntl.h>
+#endif
+#endif
+
+#ifdef HAVE_SYS_MODE_H
+/* apparently AIX needs this for S_ISLNK */
+#ifndef S_ISLNK
+#include <sys/mode.h>
+#endif
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+/*
+ * Veritas File System. Often in addition to native.
+ * Quotas different.
+ */
+#if defined(HAVE_SYS_FS_VX_QUOTA_H)
+#define VXFS_QUOTA
+#endif
+
+#if HAVE_SYS_ATTRIBUTES_H
+#include <sys/attributes.h>
+#endif
+
+/* mutually exclusive (SuSE 8.2) */
+#if HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#elif HAVE_SYS_XATTR_H
+#include <sys/xattr.h>
+#endif
+
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+/* Some POSIX definitions for those without */
+
+#ifndef S_IFDIR
+#define S_IFDIR 0x4000
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(mode) ((mode & 0xF000) == S_IFDIR)
+#endif
+#ifndef S_IRWXU
+#define S_IRWXU 00700 /* read, write, execute: owner */
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR 00400 /* read permission: owner */
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR 00200 /* write permission: owner */
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR 00100 /* execute permission: owner */
+#endif
+#ifndef S_IRWXG
+#define S_IRWXG 00070 /* read, write, execute: group */
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP 00040 /* read permission: group */
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP 00020 /* write permission: group */
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 00010 /* execute permission: group */
+#endif
+#ifndef S_IRWXO
+#define S_IRWXO 00007 /* read, write, execute: other */
+#endif
+#ifndef S_IROTH
+#define S_IROTH 00004 /* read permission: other */
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 00002 /* write permission: other */
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 00001 /* execute permission: other */
+#endif
+
+#ifndef O_ACCMODE
+#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
+#endif
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 256
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+#endif
diff --git a/source3/lib/replace/system/glob.h b/source3/lib/replace/system/glob.h
new file mode 100644
index 0000000000..3e23db6828
--- /dev/null
+++ b/source3/lib/replace/system/glob.h
@@ -0,0 +1,37 @@
+#ifndef _system_glob_h
+#define _system_glob_h
+/*
+ Unix SMB/CIFS implementation.
+
+ glob system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_GLOB_H
+#include <glob.h>
+#endif
+
+#ifdef HAVE_FNMATCH_H
+#include <fnmatch.h>
+#endif
+
+#endif
diff --git a/source3/lib/replace/system/iconv.h b/source3/lib/replace/system/iconv.h
new file mode 100644
index 0000000000..3c8a71f2f7
--- /dev/null
+++ b/source3/lib/replace/system/iconv.h
@@ -0,0 +1,57 @@
+#ifndef _system_iconv_h
+#define _system_iconv_h
+/*
+ Unix SMB/CIFS implementation.
+
+ iconv memory system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#if !defined(HAVE_ICONV) && defined(HAVE_ICONV_H)
+#define HAVE_ICONV
+#endif
+
+#if !defined(HAVE_GICONV) && defined(HAVE_GICONV_H)
+#define HAVE_GICONV
+#endif
+
+#if !defined(HAVE_BICONV) && defined(HAVE_BICONV_H)
+#define HAVE_BICONV
+#endif
+
+#ifdef HAVE_NATIVE_ICONV
+#if defined(HAVE_ICONV)
+#include <iconv.h>
+#elif defined(HAVE_GICONV)
+#include <giconv.h>
+#elif defined(HAVE_BICONV)
+#include <biconv.h>
+#endif
+#endif /* HAVE_NATIVE_ICONV */
+
+/* needed for some systems without iconv. Doesn't really matter
+ what error code we use */
+#ifndef EILSEQ
+#define EILSEQ EIO
+#endif
+
+#endif
diff --git a/source3/lib/replace/system/kerberos.h b/source3/lib/replace/system/kerberos.h
new file mode 100644
index 0000000000..2981024bee
--- /dev/null
+++ b/source3/lib/replace/system/kerberos.h
@@ -0,0 +1,137 @@
+#ifndef _system_kerberos_h
+#define _system_kerberos_h
+
+/*
+ Unix SMB/CIFS implementation.
+
+ kerberos system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_KRB5
+/* Whether the krb5_address struct has a addrtype property */
+/* #undef HAVE_ADDRTYPE_IN_KRB5_ADDRESS */
+/* Whether the krb5_address struct has a addr_type property */
+#define HAVE_ADDR_TYPE_IN_KRB5_ADDRESS 1
+/* Define to 1 if you have the `gsskrb5_extract_authz_data_from_sec_context' */
+#define HAVE_GSSKRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT 1
+/* Define to 1 if you have the `gsskrb5_get_initiator_subkey' function. */
+#define HAVE_GSSKRB5_GET_INITIATOR_SUBKEY 1
+/* Define to 1 if you have the `gsskrb5_register_acceptor_identity' function. */
+#define HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY 1
+/* Define to 1 if you have the `gss_krb5_ccache_name' function. */
+#define HAVE_GSS_KRB5_CCACHE_NAME 1
+/* Define to 1 if you have the `krb5_addlog_func' function. */
+#define HAVE_KRB5_ADDLOG_FUNC 1
+/* Define to 1 if you have the `krb5_auth_con_setkey' function. */
+#define HAVE_KRB5_AUTH_CON_SETKEY 1
+/* Define to 1 if you have the `krb5_auth_con_setuseruserkey' function. */
+/* #undef HAVE_KRB5_AUTH_CON_SETUSERUSERKEY */
+/* Define to 1 if you have the `krb5_c_enctype_compare' function. */
+#define HAVE_KRB5_C_ENCTYPE_COMPARE 1
+/* Define to 1 if you have the `krb5_c_verify_checksum' function. */
+#define HAVE_KRB5_C_VERIFY_CHECKSUM 1
+/* Whether the type krb5_encrypt_block exists */
+/* #undef HAVE_KRB5_ENCRYPT_BLOCK */
+/* Define to 1 if you have the `krb5_encrypt_data' function. */
+/* #undef HAVE_KRB5_ENCRYPT_DATA */
+/* Define to 1 if you have the `krb5_enctypes_compatible_keys' function. */
+#define HAVE_KRB5_ENCTYPES_COMPATIBLE_KEYS 1
+/* Define to 1 if you have the `krb5_free_data_contents' function. */
+#define HAVE_KRB5_FREE_DATA_CONTENTS 1
+/* Define to 1 if you have the `krb5_free_error_string' function. */
+#define HAVE_KRB5_FREE_ERROR_STRING 1
+/* Define to 1 if you have the `krb5_free_keytab_entry_contents' function. */
+/* #undef HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS */
+/* Define to 1 if you have the `krb5_free_ktypes' function. */
+/* #undef HAVE_KRB5_FREE_KTYPES */
+/* Define to 1 if you have the `krb5_free_unparsed_name' function. */
+/* #undef HAVE_KRB5_FREE_UNPARSED_NAME */
+/* Define to 1 if you have the `krb5_get_default_in_tkt_etypes' function. */
+#define HAVE_KRB5_GET_DEFAULT_IN_TKT_ETYPES 1
+/* Define to 1 if you have the `krb5_get_error_string' function. */
+#define HAVE_KRB5_GET_ERROR_STRING 1
+/* Define to 1 if you have the `krb5_get_permitted_enctypes' function. */
+/* #undef HAVE_KRB5_GET_PERMITTED_ENCTYPES */
+/* Define to 1 if you have the `krb5_get_pw_salt' function. */
+#define HAVE_KRB5_GET_PW_SALT 1
+/* Define to 1 if you have the <krb5.h> header file. */
+#define HAVE_KRB5_H 1
+/* Define to 1 if you have the `krb5_initlog' function. */
+#define HAVE_KRB5_INITLOG 1
+/* Define to 1 if you have the `krb5_kdc_default_config' function. */
+#define HAVE_KRB5_KDC_DEFAULT_CONFIG 1
+/* Whether the krb5_creds struct has a keyblock property */
+/* #undef HAVE_KRB5_KEYBLOCK_IN_CREDS */
+/* Whether the krb5_keyblock struct has a keyvalue property */
+#define HAVE_KRB5_KEYBLOCK_KEYVALUE 1
+/* Whether krb5_keytab_entry has key member */
+/* #undef HAVE_KRB5_KEYTAB_ENTRY_KEY */
+/* Whether krb5_keytab_entry has keyblock member */
+#define HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK 1
+/* Define to 1 if you have the `krb5_krbhst_get_addrinfo' function. */
+#define HAVE_KRB5_KRBHST_GET_ADDRINFO 1
+/* Define to 1 if you have the `krb5_kt_compare' function. */
+#define HAVE_KRB5_KT_COMPARE 1
+/* Define to 1 if you have the `krb5_kt_free_entry' function. */
+#define HAVE_KRB5_KT_FREE_ENTRY 1
+/* Whether the type krb5_log_facility exists */
+#define HAVE_KRB5_LOG_FACILITY 1
+/* Define to 1 if you have the `krb5_mk_req_extended' function. */
+#define HAVE_KRB5_MK_REQ_EXTENDED 1
+/* Define to 1 if you have the `krb5_principal2salt' function. */
+/* #undef HAVE_KRB5_PRINCIPAL2SALT */
+/* Define to 1 if you have the `krb5_principal_get_comp_string' function. */
+#define HAVE_KRB5_PRINCIPAL_GET_COMP_STRING 1
+/* Whether krb5_princ_component is available */
+/* #undef HAVE_KRB5_PRINC_COMPONENT */
+/* Whether the krb5_creds struct has a session property */
+#define HAVE_KRB5_SESSION_IN_CREDS 1
+/* Define to 1 if you have the `krb5_set_default_in_tkt_etypes' function. */
+#define HAVE_KRB5_SET_DEFAULT_IN_TKT_ETYPES 1
+/* Define to 1 if you have the `krb5_set_default_tgs_ktypes' function. */
+/* #undef HAVE_KRB5_SET_DEFAULT_TGS_KTYPES */
+/* Define to 1 if you have the `krb5_set_real_time' function. */
+#define HAVE_KRB5_SET_REAL_TIME 1
+/* Define to 1 if you have the `krb5_set_warn_dest' function. */
+#define HAVE_KRB5_SET_WARN_DEST 1
+/* Define to 1 if you have the `krb5_string_to_key' function. */
+#define HAVE_KRB5_STRING_TO_KEY 1
+/* Define to 1 if you have the `krb5_string_to_key_salt' function. */
+#define HAVE_KRB5_STRING_TO_KEY_SALT 1
+/* Define to 1 if you have the `krb5_ticket_get_authorization_data_type' */
+#define HAVE_KRB5_TICKET_GET_AUTHORIZATION_DATA_TYPE 1
+/* Whether the krb5_ticket struct has a enc_part2 property */
+/* #undef HAVE_KRB5_TKT_ENC_PART2 */
+/* Define to 1 if you have the `krb5_use_enctype' function. */
+/* #undef HAVE_KRB5_USE_ENCTYPE */
+/* Define to 1 if you have the `krb5_verify_checksum' function. */
+#define HAVE_KRB5_VERIFY_CHECKSUM 1
+/* Whether krb5_princ_realm returns krb5_realm or krb5_data */
+#define KRB5_PRINC_REALM_RETURNS_REALM 1
+
+#include <krb5.h>
+#include <com_err.h>
+
+#endif
+
+#endif
diff --git a/source3/lib/replace/system/locale.h b/source3/lib/replace/system/locale.h
new file mode 100644
index 0000000000..e73a9bb274
--- /dev/null
+++ b/source3/lib/replace/system/locale.h
@@ -0,0 +1,38 @@
+#ifndef _system_locale_h
+#define _system_locale_h
+
+/*
+ Unix SMB/CIFS implementation.
+
+ locale include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#endif
diff --git a/source3/lib/replace/system/network.h b/source3/lib/replace/system/network.h
new file mode 100644
index 0000000000..077892a54e
--- /dev/null
+++ b/source3/lib/replace/system/network.h
@@ -0,0 +1,332 @@
+#ifndef _system_network_h
+#define _system_network_h
+/*
+ Unix SMB/CIFS implementation.
+
+ networking system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Jelmer Vernooij 2007
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef LIBREPLACE_NETWORK_CHECKS
+#error "AC_LIBREPLACE_NETWORK_CHECKS missing in configure"
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_UNIXSOCKET
+#include <sys/un.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+/*
+ * The next three defines are needed to access the IPTOS_* options
+ * on some systems.
+ */
+
+#ifdef HAVE_NETINET_IN_SYSTM_H
+#include <netinet/in_systm.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_IP_H
+#include <netinet/in_ip.h>
+#endif
+
+#ifdef HAVE_NETINET_IP_H
+#include <netinet/ip.h>
+#endif
+
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_STROPTS_H
+#include <stropts.h>
+#endif
+
+#ifndef HAVE_SOCKLEN_T
+#define HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif
+
+#if !defined (HAVE_INET_NTOA) || defined(REPLACE_INET_NTOA)
+/* define is in "replace.h" */
+char *rep_inet_ntoa(struct in_addr ip);
+#endif
+
+#ifndef HAVE_INET_PTON
+/* define is in "replace.h" */
+int rep_inet_pton(int af, const char *src, void *dst);
+#endif
+
+#ifndef HAVE_INET_NTOP
+/* define is in "replace.h" */
+const char *rep_inet_ntop(int af, const void *src, char *dst, socklen_t size);
+#endif
+
+#ifndef HAVE_INET_ATON
+/* define is in "replace.h" */
+int rep_inet_aton(const char *src, struct in_addr *dst);
+#endif
+
+#ifndef HAVE_CONNECT
+/* define is in "replace.h" */
+int rep_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+#endif
+
+#ifndef HAVE_GETHOSTBYNAME
+/* define is in "replace.h" */
+struct hostent *rep_gethostbyname(const char *name);
+#endif
+
+#ifdef HAVE_IFADDRS_H
+#include <ifaddrs.h>
+#endif
+
+#ifndef HAVE_STRUCT_IFADDRS
+struct ifaddrs {
+ struct ifaddrs *ifa_next; /* Pointer to next struct */
+ char *ifa_name; /* Interface name */
+ unsigned int ifa_flags; /* Interface flags */
+ struct sockaddr *ifa_addr; /* Interface address */
+ struct sockaddr *ifa_netmask; /* Interface netmask */
+#undef ifa_dstaddr
+ struct sockaddr *ifa_dstaddr; /* P2P interface destination */
+ void *ifa_data; /* Address specific data */
+};
+#endif
+
+#ifndef HAVE_GETIFADDRS
+int rep_getifaddrs(struct ifaddrs **);
+#endif
+
+#ifndef HAVE_FREEIFADDRS
+void rep_freeifaddrs(struct ifaddrs *);
+#endif
+
+#ifndef HAVE_SOCKETPAIR
+/* define is in "replace.h" */
+int rep_socketpair(int d, int type, int protocol, int sv[2]);
+#endif
+
+/*
+ * Some systems have getaddrinfo but not the
+ * defines needed to use it.
+ */
+
+/* Various macros that ought to be in <netdb.h>, but might not be */
+
+#ifndef EAI_FAIL
+#define EAI_BADFLAGS (-1)
+#define EAI_NONAME (-2)
+#define EAI_AGAIN (-3)
+#define EAI_FAIL (-4)
+#define EAI_FAMILY (-6)
+#define EAI_SOCKTYPE (-7)
+#define EAI_SERVICE (-8)
+#define EAI_MEMORY (-10)
+#define EAI_SYSTEM (-11)
+#endif /* !EAI_FAIL */
+
+#ifndef AI_PASSIVE
+#define AI_PASSIVE 0x0001
+#endif
+
+#ifndef AI_CANONNAME
+#define AI_CANONNAME 0x0002
+#endif
+
+#ifndef AI_NUMERICHOST
+/*
+ * some platforms don't support AI_NUMERICHOST; define as zero if using
+ * the system version of getaddrinfo...
+ */
+#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO)
+#define AI_NUMERICHOST 0
+#else
+#define AI_NUMERICHOST 0x0004
+#endif
+#endif
+
+#ifndef AI_ADDRCONFIG
+/*
+ * logic copied from AI_NUMERICHOST
+ */
+#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO)
+#define AI_ADDRCONFIG 0
+#else
+#define AI_ADDRCONFIG 0x0020
+#endif
+#endif
+
+#ifndef AI_NUMERICSERV
+/*
+ * logic copied from AI_NUMERICHOST
+ */
+#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO)
+#define AI_NUMERICSERV 0
+#else
+#define AI_NUMERICSERV 0x0400
+#endif
+#endif
+
+#ifndef NI_NUMERICHOST
+#define NI_NUMERICHOST 1
+#endif
+
+#ifndef NI_NUMERICSERV
+#define NI_NUMERICSERV 2
+#endif
+
+#ifndef NI_NOFQDN
+#define NI_NOFQDN 4
+#endif
+
+#ifndef NI_NAMEREQD
+#define NI_NAMEREQD 8
+#endif
+
+#ifndef NI_DGRAM
+#define NI_DGRAM 16
+#endif
+
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
+
+#ifndef NI_MAXSERV
+#define NI_MAXSERV 32
+#endif
+
+/*
+ * glibc on linux doesn't seem to have MSG_WAITALL
+ * defined. I think the kernel has it though..
+ */
+#ifndef MSG_WAITALL
+#define MSG_WAITALL 0
+#endif
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+#ifndef EAFNOSUPPORT
+#define EAFNOSUPPORT EINVAL
+#endif
+
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN 16
+#endif
+
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 256
+#endif
+
+#ifndef HAVE_SA_FAMILY_T
+#define HAVE_SA_FAMILY_T
+typedef unsigned short int sa_family_t;
+#endif
+
+#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
+#define HAVE_STRUCT_SOCKADDR_STORAGE
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+#define sockaddr_storage sockaddr_in6
+#define ss_family sin6_family
+#define HAVE_SS_FAMILY 1
+#else
+#define sockaddr_storage sockaddr_in
+#define ss_family sin_family
+#define HAVE_SS_FAMILY 1
+#endif
+#endif
+
+#ifndef HAVE_SS_FAMILY
+#ifdef HAVE___SS_FAMILY
+#define ss_family __ss_family
+#define HAVE_SS_FAMILY 1
+#endif
+#endif
+
+#ifndef HAVE_STRUCT_ADDRINFO
+#define HAVE_STRUCT_ADDRINFO
+struct addrinfo {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ socklen_t ai_addrlen;
+ struct sockaddr *ai_addr;
+ char *ai_canonname;
+ struct addrinfo *ai_next;
+};
+#endif /* HAVE_STRUCT_ADDRINFO */
+
+#if !defined(HAVE_GETADDRINFO)
+#include "getaddrinfo.h"
+#endif
+
+/* Needed for some systems that don't define it (Solaris). */
+#ifndef ifr_netmask
+#define ifr_netmask ifr_addr
+#endif
+
+#ifdef SOCKET_WRAPPER
+#ifndef SOCKET_WRAPPER_NOT_REPLACE
+#define SOCKET_WRAPPER_REPLACE
+#endif
+#include "lib/socket_wrapper/socket_wrapper.h"
+#endif
+
+#endif
diff --git a/source3/lib/replace/system/passwd.h b/source3/lib/replace/system/passwd.h
new file mode 100644
index 0000000000..cad3197ccb
--- /dev/null
+++ b/source3/lib/replace/system/passwd.h
@@ -0,0 +1,110 @@
+#ifndef _system_passwd_h
+#define _system_passwd_h
+
+/*
+ Unix SMB/CIFS implementation.
+
+ passwd system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/* this needs to be included before nss_wrapper.h on some systems */
+#include <unistd.h>
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+#ifdef HAVE_SYS_PRIV_H
+#include <sys/priv.h>
+#endif
+#ifdef HAVE_SYS_ID_H
+#include <sys/id.h>
+#endif
+
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif
+
+#ifdef HAVE_SYS_SECURITY_H
+#include <sys/security.h>
+#include <prot.h>
+#define PASSWORD_LENGTH 16
+#endif /* HAVE_SYS_SECURITY_H */
+
+#ifdef HAVE_GETPWANAM
+#include <sys/label.h>
+#include <sys/audit.h>
+#include <pwdadj.h>
+#endif
+
+#ifdef HAVE_COMPAT_H
+#include <compat.h>
+#endif
+
+#ifdef REPLACE_GETPASS
+#if defined(REPLACE_GETPASS_BY_GETPASSPHRASE)
+#define getpass(prompt) getpassphrase(prompt)
+#else
+#define getpass(prompt) rep_getpass(prompt)
+char *rep_getpass(const char *prompt);
+#endif
+#endif
+
+#ifndef NGROUPS_MAX
+#define NGROUPS_MAX 32 /* Guess... */
+#endif
+
+/* 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
+
+#if defined(HAVE_PUTPRPWNAM) && defined(AUTH_CLEARTEXT_SEG_CHARS)
+#define OSF1_ENH_SEC 1
+#endif
+
+#ifndef ALLOW_CHANGE_PASSWORD
+#if (defined(HAVE_TERMIOS_H) && defined(HAVE_DUP2) && defined(HAVE_SETSID))
+#define ALLOW_CHANGE_PASSWORD 1
+#endif
+#endif
+
+#if defined(HAVE_CRYPT16) && defined(HAVE_GETAUTHUID)
+#define ULTRIX_AUTH 1
+#endif
+
+#ifdef NSS_WRAPPER
+#ifndef NSS_WRAPPER_NOT_REPLACE
+#define NSS_WRAPPER_REPLACE
+#endif
+#include "lib/nss_wrapper/nss_wrapper.h"
+#endif
+
+#endif
diff --git a/source3/lib/replace/system/readline.h b/source3/lib/replace/system/readline.h
new file mode 100644
index 0000000000..ba34dc6a61
--- /dev/null
+++ b/source3/lib/replace/system/readline.h
@@ -0,0 +1,52 @@
+#ifndef _system_readline_h
+#define _system_readline_h
+/*
+ Unix SMB/CIFS implementation.
+
+ Readline wrappers
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#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
+
+#ifdef HAVE_NEW_LIBREADLINE
+# define RL_COMPLETION_CAST (rl_completion_func_t *)
+#else
+/* This type is missing from libreadline<4.0 (approximately) */
+# define RL_COMPLETION_CAST
+#endif /* HAVE_NEW_LIBREADLINE */
+
+#endif
diff --git a/source3/lib/replace/system/select.h b/source3/lib/replace/system/select.h
new file mode 100644
index 0000000000..da18de0cfc
--- /dev/null
+++ b/source3/lib/replace/system/select.h
@@ -0,0 +1,41 @@
+#ifndef _system_select_h
+#define _system_select_h
+/*
+ Unix SMB/CIFS implementation.
+
+ select system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef HAVE_SYS_EPOLL_H
+#include <sys/epoll.h>
+#endif
+
+#ifndef SELECT_CAST
+#define SELECT_CAST
+#endif
+
+#endif
diff --git a/source3/lib/replace/system/shmem.h b/source3/lib/replace/system/shmem.h
new file mode 100644
index 0000000000..64fe39b6cb
--- /dev/null
+++ b/source3/lib/replace/system/shmem.h
@@ -0,0 +1,59 @@
+#ifndef _system_shmem_h
+#define _system_shmem_h
+/*
+ Unix SMB/CIFS implementation.
+
+ shared memory system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#if defined(HAVE_SYS_IPC_H)
+#include <sys/ipc.h>
+#endif /* HAVE_SYS_IPC_H */
+
+#if defined(HAVE_SYS_SHM_H)
+#include <sys/shm.h>
+#endif /* HAVE_SYS_SHM_H */
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+/* NetBSD doesn't have these */
+#ifndef SHM_R
+#define SHM_R 0400
+#endif
+
+#ifndef SHM_W
+#define SHM_W 0200
+#endif
+
+
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+#endif
diff --git a/source3/lib/replace/system/syslog.h b/source3/lib/replace/system/syslog.h
new file mode 100644
index 0000000000..104be1df84
--- /dev/null
+++ b/source3/lib/replace/system/syslog.h
@@ -0,0 +1,70 @@
+#ifndef _system_syslog_h
+#define _system_syslog_h
+/*
+ Unix SMB/CIFS implementation.
+
+ syslog system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#else
+#ifdef HAVE_SYS_SYSLOG_H
+#include <sys/syslog.h>
+#endif
+#endif
+
+/* For sys_adminlog(). */
+#ifndef LOG_EMERG
+#define LOG_EMERG 0 /* system is unusable */
+#endif
+
+#ifndef LOG_ALERT
+#define LOG_ALERT 1 /* action must be taken immediately */
+#endif
+
+#ifndef LOG_CRIT
+#define LOG_CRIT 2 /* critical conditions */
+#endif
+
+#ifndef LOG_ERR
+#define LOG_ERR 3 /* error conditions */
+#endif
+
+#ifndef LOG_WARNING
+#define LOG_WARNING 4 /* warning conditions */
+#endif
+
+#ifndef LOG_NOTICE
+#define LOG_NOTICE 5 /* normal but significant condition */
+#endif
+
+#ifndef LOG_INFO
+#define LOG_INFO 6 /* informational */
+#endif
+
+#ifndef LOG_DEBUG
+#define LOG_DEBUG 7 /* debug-level messages */
+#endif
+
+#endif
diff --git a/source3/lib/replace/system/terminal.h b/source3/lib/replace/system/terminal.h
new file mode 100644
index 0000000000..9ad601ace0
--- /dev/null
+++ b/source3/lib/replace/system/terminal.h
@@ -0,0 +1,46 @@
+#ifndef _system_terminal_h
+#define _system_terminal_h
+/*
+ Unix SMB/CIFS implementation.
+
+ terminal system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef SUNOS4
+/* on SUNOS4 termios.h conflicts with sys/ioctl.h */
+#undef HAVE_TERMIOS_H
+#endif
+
+
+#if defined(HAVE_TERMIOS_H)
+/* POSIX terminal handling. */
+#include <termios.h>
+#elif defined(HAVE_TERMIO_H)
+/* Older SYSV terminal handling - don't use if we can avoid it. */
+#include <termio.h>
+#elif defined(HAVE_SYS_TERMIO_H)
+/* Older SYSV terminal handling - don't use if we can avoid it. */
+#include <sys/termio.h>
+#endif
+
+#endif
diff --git a/source3/lib/replace/system/time.h b/source3/lib/replace/system/time.h
new file mode 100644
index 0000000000..4abf295d1a
--- /dev/null
+++ b/source3/lib/replace/system/time.h
@@ -0,0 +1,69 @@
+#ifndef _system_time_h
+#define _system_time_h
+/*
+ Unix SMB/CIFS implementation.
+
+ time system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#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 HAVE_UTIME_H
+#include <utime.h>
+#else
+struct utimbuf {
+ time_t actime; /* access time */
+ time_t modtime; /* modification time */
+};
+#endif
+
+#ifndef HAVE_MKTIME
+/* define is in "replace.h" */
+time_t rep_mktime(struct tm *t);
+#endif
+
+#ifndef HAVE_TIMEGM
+/* define is in "replace.h" */
+time_t rep_timegm(struct tm *tm);
+#endif
+
+#ifndef HAVE_UTIME
+/* define is in "replace.h" */
+int rep_utime(const char *filename, const struct utimbuf *buf);
+#endif
+
+#ifndef HAVE_UTIMES
+/* define is in "replace.h" */
+int rep_utimes(const char *filename, const struct timeval tv[2]);
+#endif
+
+#endif
diff --git a/source3/lib/replace/system/wait.h b/source3/lib/replace/system/wait.h
new file mode 100644
index 0000000000..5784b1ae92
--- /dev/null
+++ b/source3/lib/replace/system/wait.h
@@ -0,0 +1,55 @@
+#ifndef _system_wait_h
+#define _system_wait_h
+/*
+ Unix SMB/CIFS implementation.
+
+ waitpid system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include <signal.h>
+
+#ifndef SIGCLD
+#define SIGCLD SIGCHLD
+#endif
+
+#ifndef SIGNAL_CAST
+#define SIGNAL_CAST (RETSIGTYPE (*)(int))
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifndef SA_RESETHAND
+#define SA_RESETHAND SA_ONESHOT
+#endif
+
+#if !defined(HAVE_SIG_ATOMIC_T_TYPE)
+typedef int sig_atomic_t;
+#endif
+
+#endif
diff --git a/source3/lib/replace/test/getifaddrs.c b/source3/lib/replace/test/getifaddrs.c
new file mode 100644
index 0000000000..8b00ac2f40
--- /dev/null
+++ b/source3/lib/replace/test/getifaddrs.c
@@ -0,0 +1,100 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * libreplace getifaddrs test
+ *
+ * Copyright (C) Michael Adam <obnox@samba.org> 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef AUTOCONF_TEST
+#include "replace.h"
+#include "system/network.h"
+#endif
+
+#ifdef HAVE_INET_NTOP
+#define rep_inet_ntop inet_ntop
+#endif
+
+static const char *format_sockaddr(struct sockaddr *addr,
+ char *addrstring,
+ socklen_t addrlen)
+{
+ const char *result = NULL;
+
+ if (addr->sa_family == AF_INET) {
+ result = rep_inet_ntop(AF_INET,
+ &((struct sockaddr_in *)addr)->sin_addr,
+ addrstring,
+ addrlen);
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+ } else if (addr->sa_family == AF_INET6) {
+ result = rep_inet_ntop(AF_INET6,
+ &((struct sockaddr_in6 *)addr)->sin6_addr,
+ addrstring,
+ addrlen);
+#endif
+ }
+ return result;
+}
+
+int getifaddrs_test(void)
+{
+ struct ifaddrs *ifs = NULL;
+ struct ifaddrs *ifs_head = NULL;
+ int ret;
+
+ ret = getifaddrs(&ifs);
+ ifs_head = ifs;
+ if (ret != 0) {
+ fprintf(stderr, "getifaddrs() failed: %s\n", strerror(errno));
+ return 1;
+ }
+
+ while (ifs) {
+ printf("%-10s ", ifs->ifa_name);
+ if (ifs->ifa_addr != NULL) {
+ char addrstring[INET6_ADDRSTRLEN];
+ const char *result;
+
+ result = format_sockaddr(ifs->ifa_addr,
+ addrstring,
+ sizeof(addrstring));
+ if (result != NULL) {
+ printf("IP=%s ", addrstring);
+ }
+
+ if (ifs->ifa_netmask != NULL) {
+ result = format_sockaddr(ifs->ifa_netmask,
+ addrstring,
+ sizeof(addrstring));
+ if (result != NULL) {
+ printf("NETMASK=%s", addrstring);
+ }
+ } else {
+ printf("AF=%d ", ifs->ifa_addr->sa_family);
+ }
+ } else {
+ printf("<no address>");
+ }
+
+ printf("\n");
+ ifs = ifs->ifa_next;
+ }
+
+ freeifaddrs(ifs_head);
+
+ return 0;
+}
diff --git a/source3/lib/replace/test/os2_delete.c b/source3/lib/replace/test/os2_delete.c
new file mode 100644
index 0000000000..b45c135355
--- /dev/null
+++ b/source3/lib/replace/test/os2_delete.c
@@ -0,0 +1,124 @@
+/*
+ test readdir/unlink pattern that OS/2 uses
+ tridge@samba.org July 2005
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+
+#define NUM_FILES 700
+#define READDIR_SIZE 100
+#define DELETE_SIZE 4
+
+#define TESTDIR "test.dir"
+
+static int test_readdir_os2_delete_ret;
+
+#define FAILED(d) (printf("failure: readdir [\nFailed for %s - %d = %s\n]\n", d, errno, strerror(errno)), test_readdir_os2_delete_ret = 1, 1)
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+static void cleanup(void)
+{
+ /* I'm a lazy bastard */
+ system("rm -rf " TESTDIR);
+ mkdir(TESTDIR, 0700) == 0 || FAILED("mkdir");
+}
+
+static void create_files(void)
+{
+ int i;
+ for (i=0;i<NUM_FILES;i++) {
+ char fname[40];
+ int fd;
+ sprintf(fname, TESTDIR "/test%u.txt", i);
+ fd = open(fname, O_CREAT|O_RDWR, 0600);
+ if (fd < 0) {
+ FAILED("open");
+ }
+ if (close(fd) != 0) {
+ FAILED("close");
+ }
+ }
+}
+
+static int os2_delete(DIR *d)
+{
+ off_t offsets[READDIR_SIZE];
+ int i, j;
+ struct dirent *de;
+ char names[READDIR_SIZE][30];
+
+ /* scan, remembering offsets */
+ for (i=0, de=readdir(d);
+ de && i < READDIR_SIZE;
+ de=readdir(d), i++) {
+ offsets[i] = telldir(d);
+ strcpy(names[i], de->d_name);
+ }
+
+ if (i == 0) {
+ return 0;
+ }
+
+ /* delete the first few */
+ for (j=0; j<MIN(i, DELETE_SIZE); j++) {
+ char fname[40];
+ sprintf(fname, TESTDIR "/%s", names[j]);
+ unlink(fname) == 0 || FAILED("unlink");
+ }
+
+ /* seek to just after the deletion */
+ seekdir(d, offsets[j-1]);
+
+ /* return number deleted */
+ return j;
+}
+
+int test_readdir_os2_delete(void)
+{
+ int total_deleted = 0;
+ DIR *d;
+ struct dirent *de;
+
+ test_readdir_os2_delete_ret = 0;
+
+ cleanup();
+ create_files();
+
+ d = opendir(TESTDIR "/test0.txt");
+ if (d != NULL) FAILED("opendir() on file succeed");
+ if (errno != ENOTDIR) FAILED("opendir() on file didn't give ENOTDIR");
+
+ d = opendir(TESTDIR);
+
+ /* skip past . and .. */
+ de = readdir(d);
+ strcmp(de->d_name, ".") == 0 || FAILED("match .");
+ de = readdir(d);
+ strcmp(de->d_name, "..") == 0 || FAILED("match ..");
+
+ while (1) {
+ int n = os2_delete(d);
+ if (n == 0) break;
+ total_deleted += n;
+ }
+ closedir(d);
+
+ fprintf(stderr, "Deleted %d files of %d\n", total_deleted, NUM_FILES);
+
+ rmdir(TESTDIR) == 0 || FAILED("rmdir");
+
+ system("rm -rf " TESTDIR);
+
+ return test_readdir_os2_delete_ret;
+}
diff --git a/source3/lib/replace/test/shared_mmap.c b/source3/lib/replace/test/shared_mmap.c
new file mode 100644
index 0000000000..50dad8d696
--- /dev/null
+++ b/source3/lib/replace/test/shared_mmap.c
@@ -0,0 +1,68 @@
+/* this tests whether we can use a shared writeable mmap on a file -
+ as needed for the mmap variant of FAST_SHARE_MODES */
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define DATA "conftest.mmap"
+
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+main()
+{
+ int *buf;
+ int i;
+ int fd = open(DATA,O_RDWR|O_CREAT|O_TRUNC,0666);
+ int count=7;
+
+ if (fd == -1) exit(1);
+
+ for (i=0;i<10000;i++) {
+ write(fd,&i,sizeof(i));
+ }
+
+ close(fd);
+
+ if (fork() == 0) {
+ fd = open(DATA,O_RDWR);
+ if (fd == -1) exit(1);
+
+ buf = (int *)mmap(NULL, 10000*sizeof(int),
+ (PROT_READ | PROT_WRITE),
+ MAP_FILE | MAP_SHARED,
+ fd, 0);
+
+ while (count-- && buf[9124] != 55732) sleep(1);
+
+ if (count <= 0) exit(1);
+
+ buf[1763] = 7268;
+ exit(0);
+ }
+
+ fd = open(DATA,O_RDWR);
+ if (fd == -1) exit(1);
+
+ buf = (int *)mmap(NULL, 10000*sizeof(int),
+ (PROT_READ | PROT_WRITE),
+ MAP_FILE | MAP_SHARED,
+ fd, 0);
+
+ if (buf == (int *)-1) exit(1);
+
+ buf[9124] = 55732;
+
+ while (count-- && buf[1763] != 7268) sleep(1);
+
+ unlink(DATA);
+
+ if (count > 0) exit(0);
+ exit(1);
+}
diff --git a/source3/lib/replace/test/strptime.c b/source3/lib/replace/test/strptime.c
new file mode 100644
index 0000000000..fade3ecc57
--- /dev/null
+++ b/source3/lib/replace/test/strptime.c
@@ -0,0 +1,172 @@
+
+#ifdef LIBREPLACE_CONFIGURE_TEST_STRPTIME
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define true 1
+#define false 0
+
+#ifndef __STRING
+#define __STRING(x) #x
+#endif
+
+/* make printf a no-op */
+#define printf if(0) printf
+
+#else /* LIBREPLACE_CONFIGURE_TEST_STRPTIME */
+
+#include "replace.h"
+#include "system/time.h"
+
+#endif /* LIBREPLACE_CONFIGURE_TEST_STRPTIME */
+
+int libreplace_test_strptime(void)
+{
+ const char *s = "20070414101546Z";
+ char *ret;
+ struct tm t, t2;
+
+ memset(&t, 0, sizeof(t));
+ memset(&t2, 0, sizeof(t2));
+
+ printf("test: strptime\n");
+
+ ret = strptime(s, "%Y%m%d%H%M%S", &t);
+ if ( ret == NULL ) {
+ printf("failure: strptime [\n"
+ "returned NULL\n"
+ "]\n");
+ return false;
+ }
+
+ if ( *ret != 'Z' ) {
+ printf("failure: strptime [\n"
+ "ret doesn't point to 'Z'\n"
+ "]\n");
+ return false;
+ }
+
+ ret = strptime(s, "%Y%m%d%H%M%SZ", &t2);
+ if ( ret == NULL ) {
+ printf("failure: strptime [\n"
+ "returned NULL with Z\n"
+ "]\n");
+ return false;
+ }
+
+ if ( *ret != '\0' ) {
+ printf("failure: strptime [\n"
+ "ret doesn't point to '\\0'\n"
+ "]\n");
+ return false;
+ }
+
+#define CMP_TM_ELEMENT(t1,t2,elem) \
+ if (t1.elem != t2.elem) { \
+ printf("failure: strptime [\n" \
+ "result differs if the format string has a 'Z' at the end\n" \
+ "element: %s %d != %d\n" \
+ "]\n", \
+ __STRING(elen), t1.elem, t2.elem); \
+ return false; \
+ }
+
+ CMP_TM_ELEMENT(t,t2,tm_sec);
+ CMP_TM_ELEMENT(t,t2,tm_min);
+ CMP_TM_ELEMENT(t,t2,tm_hour);
+ CMP_TM_ELEMENT(t,t2,tm_mday);
+ CMP_TM_ELEMENT(t,t2,tm_mon);
+ CMP_TM_ELEMENT(t,t2,tm_year);
+ CMP_TM_ELEMENT(t,t2,tm_wday);
+ CMP_TM_ELEMENT(t,t2,tm_yday);
+ CMP_TM_ELEMENT(t,t2,tm_isdst);
+
+ if (t.tm_sec != 46) {
+ printf("failure: strptime [\n"
+ "tm_sec: expected: 46, got: %d\n"
+ "]\n",
+ t.tm_sec);
+ return false;
+ }
+
+ if (t.tm_min != 15) {
+ printf("failure: strptime [\n"
+ "tm_min: expected: 15, got: %d\n"
+ "]\n",
+ t.tm_min);
+ return false;
+ }
+
+ if (t.tm_hour != 10) {
+ printf("failure: strptime [\n"
+ "tm_hour: expected: 10, got: %d\n"
+ "]\n",
+ t.tm_hour);
+ return false;
+ }
+
+ if (t.tm_mday != 14) {
+ printf("failure: strptime [\n"
+ "tm_mday: expected: 14, got: %d\n"
+ "]\n",
+ t.tm_mday);
+ return false;
+ }
+
+ if (t.tm_mon != 3) {
+ printf("failure: strptime [\n"
+ "tm_mon: expected: 3, got: %d\n"
+ "]\n",
+ t.tm_mon);
+ return false;
+ }
+
+ if (t.tm_year != 107) {
+ printf("failure: strptime [\n"
+ "tm_year: expected: 107, got: %d\n"
+ "]\n",
+ t.tm_year);
+ return false;
+ }
+
+ if (t.tm_wday != 6) { /* saturday */
+ printf("failure: strptime [\n"
+ "tm_wday: expected: 6, got: %d\n"
+ "]\n",
+ t.tm_wday);
+ return false;
+ }
+
+ if (t.tm_yday != 103) {
+ printf("failure: strptime [\n"
+ "tm_yday: expected: 103, got: %d\n"
+ "]\n",
+ t.tm_yday);
+ return false;
+ }
+
+ /* we don't test this as it depends on the host configuration
+ if (t.tm_isdst != 0) {
+ printf("failure: strptime [\n"
+ "tm_isdst: expected: 0, got: %d\n"
+ "]\n",
+ t.tm_isdst);
+ return false;
+ }*/
+
+ printf("success: strptime\n");
+
+ return true;
+}
+
+#ifdef LIBREPLACE_CONFIGURE_TEST_STRPTIME
+int main (void)
+{
+ int ret;
+ ret = libreplace_test_strptime();
+ if (ret == false) return 1;
+ return 0;
+}
+#endif
diff --git a/source3/lib/replace/test/testsuite.c b/source3/lib/replace/test/testsuite.c
new file mode 100644
index 0000000000..1e8290906e
--- /dev/null
+++ b/source3/lib/replace/test/testsuite.c
@@ -0,0 +1,1080 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ libreplace tests
+
+ Copyright (C) Jelmer Vernooij 2006
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+
+/*
+ we include all the system/ include files here so that libreplace tests
+ them in the build farm
+*/
+#include "system/capability.h"
+#include "system/dir.h"
+#include "system/filesys.h"
+#include "system/glob.h"
+#include "system/iconv.h"
+#include "system/locale.h"
+#include "system/network.h"
+#include "system/passwd.h"
+#include "system/readline.h"
+#include "system/select.h"
+#include "system/shmem.h"
+#include "system/syslog.h"
+#include "system/terminal.h"
+#include "system/time.h"
+#include "system/wait.h"
+#include "system/aio.h"
+
+#define TESTFILE "testfile.dat"
+
+/*
+ test ftruncate() function
+ */
+static int test_ftruncate(void)
+{
+ struct stat st;
+ int fd;
+ const int size = 1234;
+ printf("test: ftruncate\n");
+ unlink(TESTFILE);
+ fd = open(TESTFILE, O_RDWR|O_CREAT, 0600);
+ if (fd == -1) {
+ printf("failure: ftruncate [\n"
+ "creating '%s' failed - %s\n]\n", TESTFILE, strerror(errno));
+ return false;
+ }
+ if (ftruncate(fd, size) != 0) {
+ printf("failure: ftruncate [\n%s\n]\n", strerror(errno));
+ return false;
+ }
+ if (fstat(fd, &st) != 0) {
+ printf("failure: ftruncate [\nfstat failed - %s\n]\n", strerror(errno));
+ return false;
+ }
+ if (st.st_size != size) {
+ printf("failure: ftruncate [\ngave wrong size %d - expected %d\n]\n",
+ (int)st.st_size, size);
+ return false;
+ }
+ unlink(TESTFILE);
+ printf("success: ftruncate\n");
+ return true;
+}
+
+/*
+ test strlcpy() function.
+ see http://www.gratisoft.us/todd/papers/strlcpy.html
+ */
+static int test_strlcpy(void)
+{
+ char buf[4];
+ const struct {
+ const char *src;
+ size_t result;
+ } tests[] = {
+ { "abc", 3 },
+ { "abcdef", 6 },
+ { "abcd", 4 },
+ { "", 0 },
+ { NULL, 0 }
+ };
+ int i;
+ printf("test: strlcpy\n");
+ for (i=0;tests[i].src;i++) {
+ if (strlcpy(buf, tests[i].src, sizeof(buf)) != tests[i].result) {
+ printf("failure: strlcpy [\ntest %d failed\n]\n", i);
+ return false;
+ }
+ }
+ printf("success: strlcpy\n");
+ return true;
+}
+
+static int test_strlcat(void)
+{
+ char tmp[10];
+ printf("test: strlcat\n");
+ strlcpy(tmp, "", sizeof(tmp));
+ if (strlcat(tmp, "bla", 3) != 3) {
+ printf("failure: strlcat [\ninvalid return code\n]\n");
+ return false;
+ }
+ if (strcmp(tmp, "bl") != 0) {
+ printf("failure: strlcat [\nexpected \"bl\", got \"%s\"\n]\n",
+ tmp);
+ return false;
+ }
+
+ strlcpy(tmp, "da", sizeof(tmp));
+ if (strlcat(tmp, "me", 4) != 4) {
+ printf("failure: strlcat [\nexpected \"dam\", got \"%s\"\n]\n",
+ tmp);
+ return false;
+ }
+
+ printf("success: strlcat\n");
+ return true;
+}
+
+static int test_mktime(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_initgroups(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_memmove(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_strdup(void)
+{
+ char *x;
+ printf("test: strdup\n");
+ x = strdup("bla");
+ if (strcmp("bla", x) != 0) {
+ printf("failure: strdup [\nfailed: expected \"bla\", got \"%s\"\n]\n",
+ x);
+ return false;
+ }
+ free(x);
+ printf("success: strdup\n");
+ return true;
+}
+
+static int test_setlinebuf(void)
+{
+ printf("test: setlinebuf\n");
+ setlinebuf(stdout);
+ printf("success: setlinebuf\n");
+ return true;
+}
+
+static int test_vsyslog(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_timegm(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_setenv(void)
+{
+#define TEST_SETENV(key, value, overwrite, result) do { \
+ int _ret; \
+ char *_v; \
+ _ret = setenv(key, value, overwrite); \
+ if (_ret != 0) { \
+ printf("failure: setenv [\n" \
+ "setenv(%s, %s, %d) failed\n" \
+ "]\n", \
+ key, value, overwrite); \
+ return false; \
+ } \
+ _v=getenv(key); \
+ if (!_v) { \
+ printf("failure: setenv [\n" \
+ "getenv(%s) returned NULL\n" \
+ "]\n", \
+ key); \
+ return false; \
+ } \
+ if (strcmp(result, _v) != 0) { \
+ printf("failure: setenv [\n" \
+ "getenv(%s): '%s' != '%s'\n" \
+ "]\n", \
+ key, result, _v); \
+ return false; \
+ } \
+} while(0)
+
+#define TEST_UNSETENV(key) do { \
+ char *_v; \
+ unsetenv(key); \
+ _v=getenv(key); \
+ if (_v) { \
+ printf("failure: setenv [\n" \
+ "getenv(%s): NULL != '%s'\n" \
+ "]\n", \
+ SETENVTEST_KEY, _v); \
+ return false; \
+ } \
+} while (0)
+
+#define SETENVTEST_KEY "SETENVTESTKEY"
+#define SETENVTEST_VAL "SETENVTESTVAL"
+
+ printf("test: setenv\n");
+ TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"1", 0, SETENVTEST_VAL"1");
+ TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"2", 0, SETENVTEST_VAL"1");
+ TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"3", 1, SETENVTEST_VAL"3");
+ TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"4", 1, SETENVTEST_VAL"4");
+ TEST_UNSETENV(SETENVTEST_KEY);
+ TEST_UNSETENV(SETENVTEST_KEY);
+ TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"5", 0, SETENVTEST_VAL"5");
+ TEST_UNSETENV(SETENVTEST_KEY);
+ TEST_UNSETENV(SETENVTEST_KEY);
+ printf("success: setenv\n");
+ return true;
+}
+
+static int test_strndup(void)
+{
+ char *x;
+ printf("test: strndup\n");
+ x = strndup("bla", 0);
+ if (strcmp(x, "") != 0) {
+ printf("failure: strndup [\ninvalid\n]\n");
+ return false;
+ }
+ free(x);
+ x = strndup("bla", 2);
+ if (strcmp(x, "bl") != 0) {
+ printf("failure: strndup [\ninvalid\n]\n");
+ return false;
+ }
+ free(x);
+ x = strndup("bla", 10);
+ if (strcmp(x, "bla") != 0) {
+ printf("failure: strndup [\ninvalid\n]\n");
+ return false;
+ }
+ free(x);
+ printf("success: strndup\n");
+ return true;
+}
+
+static int test_strnlen(void)
+{
+ printf("test: strnlen\n");
+ if (strnlen("bla", 2) != 2) {
+ printf("failure: strnlen [\nunexpected length\n]\n");
+ return false;
+ }
+
+ if (strnlen("some text\n", 0) != 0) {
+ printf("failure: strnlen [\nunexpected length\n]\n");
+ return false;
+ }
+
+ if (strnlen("some text", 20) != 9) {
+ printf("failure: strnlen [\nunexpected length\n]\n");
+ return false;
+ }
+
+ printf("success: strnlen\n");
+ return true;
+}
+
+static int test_waitpid(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_seteuid(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_setegid(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_asprintf(void)
+{
+ char *x;
+ printf("test: asprintf\n");
+ if (asprintf(&x, "%d", 9) != 1) {
+ printf("failure: asprintf [\ngenerate asprintf\n]\n");
+ return false;
+ }
+ if (strcmp(x, "9") != 0) {
+ printf("failure: asprintf [\ngenerate asprintf\n]\n");
+ return false;
+ }
+ if (asprintf(&x, "dat%s", "a") != 4) {
+ printf("failure: asprintf [\ngenerate asprintf\n]\n");
+ return false;
+ }
+ if (strcmp(x, "data") != 0) {
+ printf("failure: asprintf [\ngenerate asprintf\n]\n");
+ return false;
+ }
+ printf("success: asprintf\n");
+ return true;
+}
+
+static int test_snprintf(void)
+{
+ char tmp[10];
+ printf("test: snprintf\n");
+ if (snprintf(tmp, 3, "foo%d", 9) != 4) {
+ printf("failure: snprintf [\nsnprintf return code failed\n]\n");
+ return false;
+ }
+
+ if (strcmp(tmp, "fo") != 0) {
+ printf("failure: snprintf [\nsnprintf failed\n]\n");
+ return false;
+ }
+
+ printf("success: snprintf\n");
+ return true;
+}
+
+static int test_vasprintf(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_vsnprintf(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_opendir(void)
+{
+ /* FIXME */
+ return true;
+}
+
+extern int test_readdir_os2_delete(void);
+
+static int test_readdir(void)
+{
+ printf("test: readdir\n");
+ if (test_readdir_os2_delete() != 0) {
+ return false;
+ }
+ printf("success: readdir\n");
+ return true;
+}
+
+static int test_telldir(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_seekdir(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_dlopen(void)
+{
+ /* FIXME: test dlopen, dlsym, dlclose, dlerror */
+ return true;
+}
+
+
+static int test_chroot(void)
+{
+ /* FIXME: chroot() */
+ return true;
+}
+
+static int test_bzero(void)
+{
+ /* FIXME: bzero */
+ return true;
+}
+
+static int test_strerror(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_errno(void)
+{
+ printf("test: errno\n");
+ errno = 3;
+ if (errno != 3) {
+ printf("failure: errno [\nerrno failed\n]\n");
+ return false;
+ }
+
+ printf("success: errno\n");
+ return true;
+}
+
+static int test_mkdtemp(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_mkstemp(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_pread(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_pwrite(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_getpass(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_inet_ntoa(void)
+{
+ /* FIXME */
+ return true;
+}
+
+#define TEST_STRTO_X(type,fmt,func,str,base,res,diff,rrnoo) do {\
+ type _v; \
+ char _s[64]; \
+ char *_p = NULL;\
+ char *_ep = NULL; \
+ strlcpy(_s, str, sizeof(_s));\
+ if (diff >= 0) { \
+ _ep = &_s[diff]; \
+ } \
+ errno = 0; \
+ _v = func(_s, &_p, base); \
+ if (errno != rrnoo) { \
+ printf("failure: %s [\n" \
+ "\t%s\n" \
+ "\t%s(\"%s\",%d,%d): " fmt " (=/!)= " fmt "\n" \
+ "\terrno: %d != %d\n" \
+ "]\n", \
+ __STRING(func), __location__, __STRING(func), \
+ str, diff, base, res, _v, rrnoo, errno); \
+ return false; \
+ } else if (_v != res) { \
+ printf("failure: %s [\n" \
+ "\t%s\n" \
+ "\t%s(\"%s\",%d,%d): " fmt " != " fmt "\n" \
+ "]\n", \
+ __STRING(func), __location__, __STRING(func), \
+ str, diff, base, res, _v); \
+ return false; \
+ } else if (_p != _ep) { \
+ printf("failure: %s [\n" \
+ "\t%s\n" \
+ "\t%s(\"%s\",%d,%d): " fmt " (=/!)= " fmt "\n" \
+ "\tptr: %p - %p = %d != %d\n" \
+ "]\n", \
+ __STRING(func), __location__, __STRING(func), \
+ str, diff, base, res, _v, _ep, _p, (int)(diff - (_ep - _p)), diff); \
+ return false; \
+ } \
+} while (0)
+
+static int test_strtoll(void)
+{
+ printf("test: strtoll\n");
+
+#define TEST_STRTOLL(str,base,res,diff,errnoo) TEST_STRTO_X(long long int, "%lld", strtoll,str,base,res,diff,errnoo)
+
+ TEST_STRTOLL("15", 10, 15LL, 2, 0);
+ TEST_STRTOLL(" 15", 10, 15LL, 4, 0);
+ TEST_STRTOLL("15", 0, 15LL, 2, 0);
+ TEST_STRTOLL(" 15 ", 0, 15LL, 3, 0);
+ TEST_STRTOLL("+15", 10, 15LL, 3, 0);
+ TEST_STRTOLL(" +15", 10, 15LL, 5, 0);
+ TEST_STRTOLL("+15", 0, 15LL, 3, 0);
+ TEST_STRTOLL(" +15 ", 0, 15LL, 4, 0);
+ TEST_STRTOLL("-15", 10, -15LL, 3, 0);
+ TEST_STRTOLL(" -15", 10, -15LL, 5, 0);
+ TEST_STRTOLL("-15", 0, -15LL, 3, 0);
+ TEST_STRTOLL(" -15 ", 0, -15LL, 4, 0);
+ TEST_STRTOLL("015", 10, 15LL, 3, 0);
+ TEST_STRTOLL(" 015", 10, 15LL, 5, 0);
+ TEST_STRTOLL("015", 0, 13LL, 3, 0);
+ TEST_STRTOLL(" 015", 0, 13LL, 5, 0);
+ TEST_STRTOLL("0x15", 10, 0LL, 1, 0);
+ TEST_STRTOLL(" 0x15", 10, 0LL, 3, 0);
+ TEST_STRTOLL("0x15", 0, 21LL, 4, 0);
+ TEST_STRTOLL(" 0x15", 0, 21LL, 6, 0);
+
+ TEST_STRTOLL("10", 16, 16LL, 2, 0);
+ TEST_STRTOLL(" 10 ", 16, 16LL, 4, 0);
+ TEST_STRTOLL("0x10", 16, 16LL, 4, 0);
+ TEST_STRTOLL("0x10", 0, 16LL, 4, 0);
+ TEST_STRTOLL(" 0x10 ", 0, 16LL, 5, 0);
+ TEST_STRTOLL("+10", 16, 16LL, 3, 0);
+ TEST_STRTOLL(" +10 ", 16, 16LL, 5, 0);
+ TEST_STRTOLL("+0x10", 16, 16LL, 5, 0);
+ TEST_STRTOLL("+0x10", 0, 16LL, 5, 0);
+ TEST_STRTOLL(" +0x10 ", 0, 16LL, 6, 0);
+ TEST_STRTOLL("-10", 16, -16LL, 3, 0);
+ TEST_STRTOLL(" -10 ", 16, -16LL, 5, 0);
+ TEST_STRTOLL("-0x10", 16, -16LL, 5, 0);
+ TEST_STRTOLL("-0x10", 0, -16LL, 5, 0);
+ TEST_STRTOLL(" -0x10 ", 0, -16LL, 6, 0);
+ TEST_STRTOLL("010", 16, 16LL, 3, 0);
+ TEST_STRTOLL(" 010 ", 16, 16LL, 5, 0);
+ TEST_STRTOLL("-010", 16, -16LL, 4, 0);
+
+ TEST_STRTOLL("11", 8, 9LL, 2, 0);
+ TEST_STRTOLL("011", 8, 9LL, 3, 0);
+ TEST_STRTOLL("011", 0, 9LL, 3, 0);
+ TEST_STRTOLL("-11", 8, -9LL, 3, 0);
+ TEST_STRTOLL("-011", 8, -9LL, 4, 0);
+ TEST_STRTOLL("-011", 0, -9LL, 4, 0);
+
+ TEST_STRTOLL("011", 8, 9LL, 3, 0);
+ TEST_STRTOLL("011", 0, 9LL, 3, 0);
+ TEST_STRTOLL("-11", 8, -9LL, 3, 0);
+ TEST_STRTOLL("-011", 8, -9LL, 4, 0);
+ TEST_STRTOLL("-011", 0, -9LL, 4, 0);
+
+ TEST_STRTOLL("Text", 0, 0LL, 0, 0);
+
+ TEST_STRTOLL("9223372036854775807", 10, 9223372036854775807LL, 19, 0);
+ TEST_STRTOLL("9223372036854775807", 0, 9223372036854775807LL, 19, 0);
+ TEST_STRTOLL("9223372036854775808", 0, 9223372036854775807LL, 19, ERANGE);
+ TEST_STRTOLL("9223372036854775808", 10, 9223372036854775807LL, 19, ERANGE);
+ TEST_STRTOLL("0x7FFFFFFFFFFFFFFF", 0, 9223372036854775807LL, 18, 0);
+ TEST_STRTOLL("0x7FFFFFFFFFFFFFFF", 16, 9223372036854775807LL, 18, 0);
+ TEST_STRTOLL("7FFFFFFFFFFFFFFF", 16, 9223372036854775807LL, 16, 0);
+ TEST_STRTOLL("0x8000000000000000", 0, 9223372036854775807LL, 18, ERANGE);
+ TEST_STRTOLL("0x8000000000000000", 16, 9223372036854775807LL, 18, ERANGE);
+ TEST_STRTOLL("80000000000000000", 16, 9223372036854775807LL, 17, ERANGE);
+ TEST_STRTOLL("0777777777777777777777", 0, 9223372036854775807LL, 22, 0);
+ TEST_STRTOLL("0777777777777777777777", 8, 9223372036854775807LL, 22, 0);
+ TEST_STRTOLL("777777777777777777777", 8, 9223372036854775807LL, 21, 0);
+ TEST_STRTOLL("01000000000000000000000", 0, 9223372036854775807LL, 23, ERANGE);
+ TEST_STRTOLL("01000000000000000000000", 8, 9223372036854775807LL, 23, ERANGE);
+ TEST_STRTOLL("1000000000000000000000", 8, 9223372036854775807LL, 22, ERANGE);
+
+ TEST_STRTOLL("-9223372036854775808", 10, -9223372036854775807LL -1, 20, 0);
+ TEST_STRTOLL("-9223372036854775808", 0, -9223372036854775807LL -1, 20, 0);
+ TEST_STRTOLL("-9223372036854775809", 0, -9223372036854775807LL -1, 20, ERANGE);
+ TEST_STRTOLL("-9223372036854775809", 10, -9223372036854775807LL -1, 20, ERANGE);
+ TEST_STRTOLL("-0x8000000000000000", 0, -9223372036854775807LL -1, 19, 0);
+ TEST_STRTOLL("-0x8000000000000000", 16, -9223372036854775807LL -1, 19, 0);
+ TEST_STRTOLL("-8000000000000000", 16, -9223372036854775807LL -1, 17, 0);
+ TEST_STRTOLL("-0x8000000000000001", 0, -9223372036854775807LL -1, 19, ERANGE);
+ TEST_STRTOLL("-0x8000000000000001", 16, -9223372036854775807LL -1, 19, ERANGE);
+ TEST_STRTOLL("-80000000000000001", 16, -9223372036854775807LL -1, 18, ERANGE);
+ TEST_STRTOLL("-01000000000000000000000",0, -9223372036854775807LL -1, 24, 0);
+ TEST_STRTOLL("-01000000000000000000000",8, -9223372036854775807LL -1, 24, 0);
+ TEST_STRTOLL("-1000000000000000000000", 8, -9223372036854775807LL -1, 23, 0);
+ TEST_STRTOLL("-01000000000000000000001",0, -9223372036854775807LL -1, 24, ERANGE);
+ TEST_STRTOLL("-01000000000000000000001",8, -9223372036854775807LL -1, 24, ERANGE);
+ TEST_STRTOLL("-1000000000000000000001", 8, -9223372036854775807LL -1, 23, ERANGE);
+
+ printf("success: strtoll\n");
+ return true;
+}
+
+static int test_strtoull(void)
+{
+ printf("test: strtoull\n");
+
+#define TEST_STRTOULL(str,base,res,diff,errnoo) TEST_STRTO_X(long long unsigned int,"%llu",strtoull,str,base,res,diff,errnoo)
+
+ TEST_STRTOULL("15", 10, 15LLU, 2, 0);
+ TEST_STRTOULL(" 15", 10, 15LLU, 4, 0);
+ TEST_STRTOULL("15", 0, 15LLU, 2, 0);
+ TEST_STRTOULL(" 15 ", 0, 15LLU, 3, 0);
+ TEST_STRTOULL("+15", 10, 15LLU, 3, 0);
+ TEST_STRTOULL(" +15", 10, 15LLU, 5, 0);
+ TEST_STRTOULL("+15", 0, 15LLU, 3, 0);
+ TEST_STRTOULL(" +15 ", 0, 15LLU, 4, 0);
+ TEST_STRTOULL("-15", 10, 18446744073709551601LLU, 3, 0);
+ TEST_STRTOULL(" -15", 10, 18446744073709551601LLU, 5, 0);
+ TEST_STRTOULL("-15", 0, 18446744073709551601LLU, 3, 0);
+ TEST_STRTOULL(" -15 ", 0, 18446744073709551601LLU, 4, 0);
+ TEST_STRTOULL("015", 10, 15LLU, 3, 0);
+ TEST_STRTOULL(" 015", 10, 15LLU, 5, 0);
+ TEST_STRTOULL("015", 0, 13LLU, 3, 0);
+ TEST_STRTOULL(" 015", 0, 13LLU, 5, 0);
+ TEST_STRTOULL("0x15", 10, 0LLU, 1, 0);
+ TEST_STRTOULL(" 0x15", 10, 0LLU, 3, 0);
+ TEST_STRTOULL("0x15", 0, 21LLU, 4, 0);
+ TEST_STRTOULL(" 0x15", 0, 21LLU, 6, 0);
+
+ TEST_STRTOULL("10", 16, 16LLU, 2, 0);
+ TEST_STRTOULL(" 10 ", 16, 16LLU, 4, 0);
+ TEST_STRTOULL("0x10", 16, 16LLU, 4, 0);
+ TEST_STRTOULL("0x10", 0, 16LLU, 4, 0);
+ TEST_STRTOULL(" 0x10 ", 0, 16LLU, 5, 0);
+ TEST_STRTOULL("+10", 16, 16LLU, 3, 0);
+ TEST_STRTOULL(" +10 ", 16, 16LLU, 5, 0);
+ TEST_STRTOULL("+0x10", 16, 16LLU, 5, 0);
+ TEST_STRTOULL("+0x10", 0, 16LLU, 5, 0);
+ TEST_STRTOULL(" +0x10 ", 0, 16LLU, 6, 0);
+ TEST_STRTOULL("-10", 16, -16LLU, 3, 0);
+ TEST_STRTOULL(" -10 ", 16, -16LLU, 5, 0);
+ TEST_STRTOULL("-0x10", 16, -16LLU, 5, 0);
+ TEST_STRTOULL("-0x10", 0, -16LLU, 5, 0);
+ TEST_STRTOULL(" -0x10 ", 0, -16LLU, 6, 0);
+ TEST_STRTOULL("010", 16, 16LLU, 3, 0);
+ TEST_STRTOULL(" 010 ", 16, 16LLU, 5, 0);
+ TEST_STRTOULL("-010", 16, -16LLU, 4, 0);
+
+ TEST_STRTOULL("11", 8, 9LLU, 2, 0);
+ TEST_STRTOULL("011", 8, 9LLU, 3, 0);
+ TEST_STRTOULL("011", 0, 9LLU, 3, 0);
+ TEST_STRTOULL("-11", 8, -9LLU, 3, 0);
+ TEST_STRTOULL("-011", 8, -9LLU, 4, 0);
+ TEST_STRTOULL("-011", 0, -9LLU, 4, 0);
+
+ TEST_STRTOULL("011", 8, 9LLU, 3, 0);
+ TEST_STRTOULL("011", 0, 9LLU, 3, 0);
+ TEST_STRTOULL("-11", 8, -9LLU, 3, 0);
+ TEST_STRTOULL("-011", 8, -9LLU, 4, 0);
+ TEST_STRTOULL("-011", 0, -9LLU, 4, 0);
+
+ TEST_STRTOULL("Text", 0, 0LLU, 0, 0);
+
+ TEST_STRTOULL("9223372036854775807", 10, 9223372036854775807LLU, 19, 0);
+ TEST_STRTOULL("9223372036854775807", 0, 9223372036854775807LLU, 19, 0);
+ TEST_STRTOULL("9223372036854775808", 0, 9223372036854775808LLU, 19, 0);
+ TEST_STRTOULL("9223372036854775808", 10, 9223372036854775808LLU, 19, 0);
+ TEST_STRTOULL("0x7FFFFFFFFFFFFFFF", 0, 9223372036854775807LLU, 18, 0);
+ TEST_STRTOULL("0x7FFFFFFFFFFFFFFF", 16, 9223372036854775807LLU, 18, 0);
+ TEST_STRTOULL("7FFFFFFFFFFFFFFF", 16, 9223372036854775807LLU, 16, 0);
+ TEST_STRTOULL("0x8000000000000000", 0, 9223372036854775808LLU, 18, 0);
+ TEST_STRTOULL("0x8000000000000000", 16, 9223372036854775808LLU, 18, 0);
+ TEST_STRTOULL("8000000000000000", 16, 9223372036854775808LLU, 16, 0);
+ TEST_STRTOULL("0777777777777777777777", 0, 9223372036854775807LLU, 22, 0);
+ TEST_STRTOULL("0777777777777777777777", 8, 9223372036854775807LLU, 22, 0);
+ TEST_STRTOULL("777777777777777777777", 8, 9223372036854775807LLU, 21, 0);
+ TEST_STRTOULL("01000000000000000000000",0, 9223372036854775808LLU, 23, 0);
+ TEST_STRTOULL("01000000000000000000000",8, 9223372036854775808LLU, 23, 0);
+ TEST_STRTOULL("1000000000000000000000", 8, 9223372036854775808LLU, 22, 0);
+
+ TEST_STRTOULL("-9223372036854775808", 10, 9223372036854775808LLU, 20, 0);
+ TEST_STRTOULL("-9223372036854775808", 0, 9223372036854775808LLU, 20, 0);
+ TEST_STRTOULL("-9223372036854775809", 0, 9223372036854775807LLU, 20, 0);
+ TEST_STRTOULL("-9223372036854775809", 10, 9223372036854775807LLU, 20, 0);
+ TEST_STRTOULL("-0x8000000000000000", 0, 9223372036854775808LLU, 19, 0);
+ TEST_STRTOULL("-0x8000000000000000", 16, 9223372036854775808LLU, 19, 0);
+ TEST_STRTOULL("-8000000000000000", 16, 9223372036854775808LLU, 17, 0);
+ TEST_STRTOULL("-0x8000000000000001", 0, 9223372036854775807LLU, 19, 0);
+ TEST_STRTOULL("-0x8000000000000001", 16, 9223372036854775807LLU, 19, 0);
+ TEST_STRTOULL("-8000000000000001", 16, 9223372036854775807LLU, 17, 0);
+ TEST_STRTOULL("-01000000000000000000000",0, 9223372036854775808LLU, 24, 0);
+ TEST_STRTOULL("-01000000000000000000000",8, 9223372036854775808LLU, 24, 0);
+ TEST_STRTOULL("-1000000000000000000000",8, 9223372036854775808LLU, 23, 0);
+ TEST_STRTOULL("-01000000000000000000001",0, 9223372036854775807LLU, 24, 0);
+ TEST_STRTOULL("-01000000000000000000001",8, 9223372036854775807LLU, 24, 0);
+ TEST_STRTOULL("-1000000000000000000001",8, 9223372036854775807LLU, 23, 0);
+
+ TEST_STRTOULL("18446744073709551615", 0, 18446744073709551615LLU, 20, 0);
+ TEST_STRTOULL("18446744073709551615", 10, 18446744073709551615LLU, 20, 0);
+ TEST_STRTOULL("18446744073709551616", 0, 18446744073709551615LLU, 20, ERANGE);
+ TEST_STRTOULL("18446744073709551616", 10, 18446744073709551615LLU, 20, ERANGE);
+ TEST_STRTOULL("0xFFFFFFFFFFFFFFFF", 0, 18446744073709551615LLU, 18, 0);
+ TEST_STRTOULL("0xFFFFFFFFFFFFFFFF", 16, 18446744073709551615LLU, 18, 0);
+ TEST_STRTOULL("FFFFFFFFFFFFFFFF", 16, 18446744073709551615LLU, 16, 0);
+ TEST_STRTOULL("0x10000000000000000", 0, 18446744073709551615LLU, 19, ERANGE);
+ TEST_STRTOULL("0x10000000000000000", 16, 18446744073709551615LLU, 19, ERANGE);
+ TEST_STRTOULL("10000000000000000", 16, 18446744073709551615LLU, 17, ERANGE);
+ TEST_STRTOULL("01777777777777777777777",0, 18446744073709551615LLU, 23, 0);
+ TEST_STRTOULL("01777777777777777777777",8, 18446744073709551615LLU, 23, 0);
+ TEST_STRTOULL("1777777777777777777777", 8, 18446744073709551615LLU, 22, 0);
+ TEST_STRTOULL("02000000000000000000000",0, 18446744073709551615LLU, 23, ERANGE);
+ TEST_STRTOULL("02000000000000000000000",8, 18446744073709551615LLU, 23, ERANGE);
+ TEST_STRTOULL("2000000000000000000000", 8, 18446744073709551615LLU, 22, ERANGE);
+
+ TEST_STRTOULL("-18446744073709551615", 0, 1LLU, 21, 0);
+ TEST_STRTOULL("-18446744073709551615", 10, 1LLU, 21, 0);
+ TEST_STRTOULL("-18446744073709551616", 0, 18446744073709551615LLU, 21, ERANGE);
+ TEST_STRTOULL("-18446744073709551616", 10, 18446744073709551615LLU, 21, ERANGE);
+ TEST_STRTOULL("-0xFFFFFFFFFFFFFFFF", 0, 1LLU, 19, 0);
+ TEST_STRTOULL("-0xFFFFFFFFFFFFFFFF", 16, 1LLU, 19, 0);
+ TEST_STRTOULL("-FFFFFFFFFFFFFFFF", 16, 1LLU, 17, 0);
+ TEST_STRTOULL("-0x10000000000000000", 0, 18446744073709551615LLU, 20, ERANGE);
+ TEST_STRTOULL("-0x10000000000000000", 16, 18446744073709551615LLU, 20, ERANGE);
+ TEST_STRTOULL("-10000000000000000", 16, 18446744073709551615LLU, 18, ERANGE);
+ TEST_STRTOULL("-01777777777777777777777",0, 1LLU, 24, 0);
+ TEST_STRTOULL("-01777777777777777777777",8, 1LLU, 24, 0);
+ TEST_STRTOULL("-1777777777777777777777",8, 1LLU, 23, 0);
+ TEST_STRTOULL("-02000000000000000000000",0, 18446744073709551615LLU, 24, ERANGE);
+ TEST_STRTOULL("-02000000000000000000000",8, 18446744073709551615LLU, 24, ERANGE);
+ TEST_STRTOULL("-2000000000000000000000",8, 18446744073709551615LLU, 23, ERANGE);
+
+ printf("success: strtoull\n");
+ return true;
+}
+
+/*
+FIXME:
+Types:
+bool
+socklen_t
+uint_t
+uint{8,16,32,64}_t
+int{8,16,32,64}_t
+intptr_t
+
+Constants:
+PATH_NAME_MAX
+UINT{16,32,64}_MAX
+INT32_MAX
+*/
+
+static int test_va_copy(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_FUNCTION(void)
+{
+ printf("test: FUNCTION\n");
+ if (strcmp(__FUNCTION__, "test_FUNCTION") != 0) {
+ printf("failure: FAILURE [\nFAILURE invalid\n]\n");
+ return false;
+ }
+ printf("success: FUNCTION\n");
+ return true;
+}
+
+static int test_MIN(void)
+{
+ printf("test: MIN\n");
+ if (MIN(20, 1) != 1) {
+ printf("failure: MIN [\nMIN invalid\n]\n");
+ return false;
+ }
+ if (MIN(1, 20) != 1) {
+ printf("failure: MIN [\nMIN invalid\n]\n");
+ return false;
+ }
+ printf("success: MIN\n");
+ return true;
+}
+
+static int test_MAX(void)
+{
+ printf("test: MAX\n");
+ if (MAX(20, 1) != 20) {
+ printf("failure: MAX [\nMAX invalid\n]\n");
+ return false;
+ }
+ if (MAX(1, 20) != 20) {
+ printf("failure: MAX [\nMAX invalid\n]\n");
+ return false;
+ }
+ printf("success: MAX\n");
+ return true;
+}
+
+static int test_socketpair(void)
+{
+ int sock[2];
+ char buf[20];
+
+ printf("test: socketpair\n");
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock) == -1) {
+ printf("failure: socketpair [\n"
+ "socketpair() failed\n"
+ "]\n");
+ return false;
+ }
+
+ if (write(sock[1], "automatisch", 12) == -1) {
+ printf("failure: socketpair [\n"
+ "write() failed: %s\n"
+ "]\n", strerror(errno));
+ return false;
+ }
+
+ if (read(sock[0], buf, 12) == -1) {
+ printf("failure: socketpair [\n"
+ "read() failed: %s\n"
+ "]\n", strerror(errno));
+ return false;
+ }
+
+ if (strcmp(buf, "automatisch") != 0) {
+ printf("failure: socketpair [\n"
+ "expected: automatisch, got: %s\n"
+ "]\n", buf);
+ return false;
+ }
+
+ printf("success: socketpair\n");
+
+ return true;
+}
+
+extern int libreplace_test_strptime(void);
+
+static int test_strptime(void)
+{
+ return libreplace_test_strptime();
+}
+
+extern int getifaddrs_test(void);
+
+static int test_getifaddrs(void)
+{
+
+ printf("test: getifaddrs\n");
+
+ if (getifaddrs_test() != 0) {
+ printf("failure: getifaddrs\n");
+ return false;
+ }
+
+ printf("success: getifaddrs\n");
+ return true;
+}
+
+static int test_utime(void)
+{
+ struct utimbuf u;
+ struct stat st1, st2, st3;
+ int fd;
+
+ printf("test: utime\n");
+ unlink(TESTFILE);
+
+ fd = open(TESTFILE, O_RDWR|O_CREAT, 0600);
+ if (fd == -1) {
+ printf("failure: utime [\n"
+ "creating '%s' failed - %s\n]\n",
+ TESTFILE, strerror(errno));
+ return false;
+ }
+
+ if (fstat(fd, &st1) != 0) {
+ printf("failure: utime [\n"
+ "fstat (1) failed - %s\n]\n",
+ strerror(errno));
+ return false;
+ }
+
+ u.actime = st1.st_atime + 300;
+ u.modtime = st1.st_mtime - 300;
+ if (utime(TESTFILE, &u) != 0) {
+ printf("failure: utime [\n"
+ "utime(&u) failed - %s\n]\n",
+ strerror(errno));
+ return false;
+ }
+
+ if (fstat(fd, &st2) != 0) {
+ printf("failure: utime [\n"
+ "fstat (2) failed - %s\n]\n",
+ strerror(errno));
+ return false;
+ }
+
+ if (utime(TESTFILE, NULL) != 0) {
+ printf("failure: utime [\n"
+ "utime(NULL) failed - %s\n]\n",
+ strerror(errno));
+ return false;
+ }
+
+ if (fstat(fd, &st3) != 0) {
+ printf("failure: utime [\n"
+ "fstat (3) failed - %s\n]\n",
+ strerror(errno));
+ return false;
+ }
+
+#define CMP_VAL(a,c,b) do { \
+ if (a c b) { \
+ printf("failure: utime [\n" \
+ "%s: %s(%d) %s %s(%d)\n]\n", \
+ __location__, \
+ #a, (int)a, #c, #b, (int)b); \
+ return false; \
+ } \
+} while(0)
+#define EQUAL_VAL(a,b) CMP_VAL(a,!=,b)
+#define GREATER_VAL(a,b) CMP_VAL(a,<=,b)
+#define LESSER_VAL(a,b) CMP_VAL(a,>=,b)
+
+ EQUAL_VAL(st2.st_atime, st1.st_atime + 300);
+ EQUAL_VAL(st2.st_mtime, st1.st_mtime - 300);
+ LESSER_VAL(st3.st_atime, st2.st_atime);
+ GREATER_VAL(st3.st_mtime, st2.st_mtime);
+
+#undef CMP_VAL
+#undef EQUAL_VAL
+#undef GREATER_VAL
+#undef LESSER_VAL
+
+ unlink(TESTFILE);
+ printf("success: utime\n");
+ return true;
+}
+
+static int test_utimes(void)
+{
+ struct timeval tv[2];
+ struct stat st1, st2;
+ int fd;
+
+ printf("test: utimes\n");
+ unlink(TESTFILE);
+
+ fd = open(TESTFILE, O_RDWR|O_CREAT, 0600);
+ if (fd == -1) {
+ printf("failure: utimes [\n"
+ "creating '%s' failed - %s\n]\n",
+ TESTFILE, strerror(errno));
+ return false;
+ }
+
+ if (fstat(fd, &st1) != 0) {
+ printf("failure: utimes [\n"
+ "fstat (1) failed - %s\n]\n",
+ strerror(errno));
+ return false;
+ }
+
+ ZERO_STRUCT(tv);
+ tv[0].tv_sec = st1.st_atime + 300;
+ tv[1].tv_sec = st1.st_mtime - 300;
+ if (utimes(TESTFILE, tv) != 0) {
+ printf("failure: utimes [\n"
+ "utimes(tv) failed - %s\n]\n",
+ strerror(errno));
+ return false;
+ }
+
+ if (fstat(fd, &st2) != 0) {
+ printf("failure: utimes [\n"
+ "fstat (2) failed - %s\n]\n",
+ strerror(errno));
+ return false;
+ }
+
+#define EQUAL_VAL(a,b) do { \
+ if (a != b) { \
+ printf("failure: utimes [\n" \
+ "%s: %s(%d) != %s(%d)\n]\n", \
+ __location__, \
+ #a, (int)a, #b, (int)b); \
+ return false; \
+ } \
+} while(0)
+
+ EQUAL_VAL(st2.st_atime, st1.st_atime + 300);
+ EQUAL_VAL(st2.st_mtime, st1.st_mtime - 300);
+
+#undef EQUAL_VAL
+
+ unlink(TESTFILE);
+ printf("success: utimes\n");
+ return true;
+}
+
+struct torture_context;
+bool torture_local_replace(struct torture_context *ctx)
+{
+ bool ret = true;
+ ret &= test_ftruncate();
+ ret &= test_strlcpy();
+ ret &= test_strlcat();
+ ret &= test_mktime();
+ ret &= test_initgroups();
+ ret &= test_memmove();
+ ret &= test_strdup();
+ ret &= test_setlinebuf();
+ ret &= test_vsyslog();
+ ret &= test_timegm();
+ ret &= test_setenv();
+ ret &= test_strndup();
+ ret &= test_strnlen();
+ ret &= test_waitpid();
+ ret &= test_seteuid();
+ ret &= test_setegid();
+ ret &= test_asprintf();
+ ret &= test_snprintf();
+ ret &= test_vasprintf();
+ ret &= test_vsnprintf();
+ ret &= test_opendir();
+ ret &= test_readdir();
+ ret &= test_telldir();
+ ret &= test_seekdir();
+ ret &= test_dlopen();
+ ret &= test_chroot();
+ ret &= test_bzero();
+ ret &= test_strerror();
+ ret &= test_errno();
+ ret &= test_mkdtemp();
+ ret &= test_mkstemp();
+ ret &= test_pread();
+ ret &= test_pwrite();
+ ret &= test_getpass();
+ ret &= test_inet_ntoa();
+ ret &= test_strtoll();
+ ret &= test_strtoull();
+ ret &= test_va_copy();
+ ret &= test_FUNCTION();
+ ret &= test_MIN();
+ ret &= test_MAX();
+ ret &= test_socketpair();
+ ret &= test_strptime();
+ ret &= test_getifaddrs();
+ ret &= test_utime();
+ ret &= test_utimes();
+
+ return ret;
+}
+
+#if _SAMBA_BUILD_<4
+int main(void)
+{
+ bool ret = torture_local_replace(NULL);
+ if (ret)
+ return 0;
+ return -1;
+}
+#endif
diff --git a/source3/lib/replace/timegm.c b/source3/lib/replace/timegm.c
new file mode 100644
index 0000000000..395c684e11
--- /dev/null
+++ b/source3/lib/replace/timegm.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ adapted for Samba4 by Andrew Tridgell
+*/
+
+#include "replace.h"
+#include "system/time.h"
+
+static int is_leap(unsigned y)
+{
+ y += 1900;
+ return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0);
+}
+
+time_t rep_timegm(struct tm *tm)
+{
+ static const unsigned ndays[2][12] ={
+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
+ time_t res = 0;
+ unsigned i;
+
+ if (tm->tm_mon > 12 ||
+ tm->tm_mon < 0 ||
+ tm->tm_mday > 31 ||
+ tm->tm_min > 60 ||
+ tm->tm_sec > 60 ||
+ tm->tm_hour > 24) {
+ /* invalid tm structure */
+ return 0;
+ }
+
+ for (i = 70; i < tm->tm_year; ++i)
+ res += is_leap(i) ? 366 : 365;
+
+ for (i = 0; i < tm->tm_mon; ++i)
+ res += ndays[is_leap(tm->tm_year)][i];
+ res += tm->tm_mday - 1;
+ res *= 24;
+ res += tm->tm_hour;
+ res *= 60;
+ res += tm->tm_min;
+ res *= 60;
+ res += tm->tm_sec;
+ return res;
+}
diff --git a/source3/lib/replace/timegm.m4 b/source3/lib/replace/timegm.m4
new file mode 100644
index 0000000000..59f3ae0521
--- /dev/null
+++ b/source3/lib/replace/timegm.m4
@@ -0,0 +1 @@
+AC_CHECK_FUNCS(timegm,[],[LIBREPLACEOBJ="${LIBREPLACEOBJ} timegm.o"])
diff --git a/source3/lib/replace/win32.m4 b/source3/lib/replace/win32.m4
new file mode 100644
index 0000000000..eb364e2cb9
--- /dev/null
+++ b/source3/lib/replace/win32.m4
@@ -0,0 +1,20 @@
+AC_CHECK_HEADERS(direct.h windows.h winsock2.h ws2tcpip.h)
+
+#######################################
+# Check for mkdir mode
+AC_CACHE_CHECK( [whether mkdir supports mode], libreplace_cv_mkdir_has_mode,
+ AC_TRY_COMPILE([
+ #include <stdio.h>
+ #ifdef HAVE_DIRECT_H
+ #include <direct.h>
+ #endif],[
+ mkdir("foo",0777);
+ return 0;
+ ],
+ libreplace_cv_mkdir_has_mode="yes",
+ libreplace_cv_mkdir_has_mode="no") )
+
+if test "$libreplace_cv_mkdir_has_mode" = "yes"
+then
+ AC_DEFINE(HAVE_MKDIR_MODE, 1, [Define if target mkdir supports mode option])
+fi
diff --git a/source3/lib/replace/win32_replace.h b/source3/lib/replace/win32_replace.h
new file mode 100644
index 0000000000..9901e72f6e
--- /dev/null
+++ b/source3/lib/replace/win32_replace.h
@@ -0,0 +1,159 @@
+#ifndef _WIN32_REPLACE_H
+#define _WIN32_REPLACE_H
+
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
+/* Map BSD Socket errorcodes to the WSA errorcodes (if possible) */
+
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define ECONNREFUSED WSAECONNREFUSED
+#define EINPROGRESS WSAEINPROGRESS
+#define EMSGSIZE WSAEMSGSIZE
+#define ENOBUFS WSAENOBUFS
+#define ENOTSOCK WSAENOTSOCK
+#define ENETUNREACH WSAENETUNREACH
+#define ENOPROTOOPT WSAENOPROTOOPT
+#define ENOTCONN WSAENOTCONN
+#define ENOTSUP 134
+
+/* We undefine the following constants due to conflicts with the w32api headers
+ * and the Windows Platform SDK/DDK.
+ */
+
+#undef interface
+
+#undef ERROR_INVALID_PARAMETER
+#undef ERROR_INSUFFICIENT_BUFFER
+#undef ERROR_INVALID_DATATYPE
+
+#undef FILE_GENERIC_READ
+#undef FILE_GENERIC_WRITE
+#undef FILE_GENERIC_EXECUTE
+#undef FILE_ATTRIBUTE_READONLY
+#undef FILE_ATTRIBUTE_HIDDEN
+#undef FILE_ATTRIBUTE_SYSTEM
+#undef FILE_ATTRIBUTE_DIRECTORY
+#undef FILE_ATTRIBUTE_ARCHIVE
+#undef FILE_ATTRIBUTE_DEVICE
+#undef FILE_ATTRIBUTE_NORMAL
+#undef FILE_ATTRIBUTE_TEMPORARY
+#undef FILE_ATTRIBUTE_REPARSE_POINT
+#undef FILE_ATTRIBUTE_COMPRESSED
+#undef FILE_ATTRIBUTE_OFFLINE
+#undef FILE_ATTRIBUTE_ENCRYPTED
+#undef FILE_FLAG_WRITE_THROUGH
+#undef FILE_FLAG_NO_BUFFERING
+#undef FILE_FLAG_RANDOM_ACCESS
+#undef FILE_FLAG_SEQUENTIAL_SCAN
+#undef FILE_FLAG_DELETE_ON_CLOSE
+#undef FILE_FLAG_BACKUP_SEMANTICS
+#undef FILE_FLAG_POSIX_SEMANTICS
+#undef FILE_TYPE_DISK
+#undef FILE_TYPE_UNKNOWN
+#undef FILE_CASE_SENSITIVE_SEARCH
+#undef FILE_CASE_PRESERVED_NAMES
+#undef FILE_UNICODE_ON_DISK
+#undef FILE_PERSISTENT_ACLS
+#undef FILE_FILE_COMPRESSION
+#undef FILE_VOLUME_QUOTAS
+#undef FILE_VOLUME_IS_COMPRESSED
+#undef FILE_NOTIFY_CHANGE_FILE_NAME
+#undef FILE_NOTIFY_CHANGE_DIR_NAME
+#undef FILE_NOTIFY_CHANGE_ATTRIBUTES
+#undef FILE_NOTIFY_CHANGE_SIZE
+#undef FILE_NOTIFY_CHANGE_LAST_WRITE
+#undef FILE_NOTIFY_CHANGE_LAST_ACCESS
+#undef FILE_NOTIFY_CHANGE_CREATION
+#undef FILE_NOTIFY_CHANGE_EA
+#undef FILE_NOTIFY_CHANGE_SECURITY
+#undef FILE_NOTIFY_CHANGE_STREAM_NAME
+#undef FILE_NOTIFY_CHANGE_STREAM_SIZE
+#undef FILE_NOTIFY_CHANGE_STREAM_WRITE
+#undef FILE_NOTIFY_CHANGE_NAME
+
+#undef PRINTER_ATTRIBUTE_QUEUED
+#undef PRINTER_ATTRIBUTE_DIRECT
+#undef PRINTER_ATTRIBUTE_DEFAULT
+#undef PRINTER_ATTRIBUTE_SHARED
+#undef PRINTER_ATTRIBUTE_NETWORK
+#undef PRINTER_ATTRIBUTE_HIDDEN
+#undef PRINTER_ATTRIBUTE_LOCAL
+#undef PRINTER_ATTRIBUTE_ENABLE_DEVQ
+#undef PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS
+#undef PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST
+#undef PRINTER_ATTRIBUTE_WORK_OFFLINE
+#undef PRINTER_ATTRIBUTE_ENABLE_BIDI
+#undef PRINTER_ATTRIBUTE_RAW_ONLY
+#undef PRINTER_ATTRIBUTE_PUBLISHED
+#undef PRINTER_ENUM_DEFAULT
+#undef PRINTER_ENUM_LOCAL
+#undef PRINTER_ENUM_CONNECTIONS
+#undef PRINTER_ENUM_FAVORITE
+#undef PRINTER_ENUM_NAME
+#undef PRINTER_ENUM_REMOTE
+#undef PRINTER_ENUM_SHARED
+#undef PRINTER_ENUM_NETWORK
+#undef PRINTER_ENUM_EXPAND
+#undef PRINTER_ENUM_CONTAINER
+#undef PRINTER_ENUM_ICON1
+#undef PRINTER_ENUM_ICON2
+#undef PRINTER_ENUM_ICON3
+#undef PRINTER_ENUM_ICON4
+#undef PRINTER_ENUM_ICON5
+#undef PRINTER_ENUM_ICON6
+#undef PRINTER_ENUM_ICON7
+#undef PRINTER_ENUM_ICON8
+#undef PRINTER_STATUS_PAUSED
+#undef PRINTER_STATUS_ERROR
+#undef PRINTER_STATUS_PENDING_DELETION
+#undef PRINTER_STATUS_PAPER_JAM
+#undef PRINTER_STATUS_PAPER_OUT
+#undef PRINTER_STATUS_MANUAL_FEED
+#undef PRINTER_STATUS_PAPER_PROBLEM
+#undef PRINTER_STATUS_OFFLINE
+#undef PRINTER_STATUS_IO_ACTIVE
+#undef PRINTER_STATUS_BUSY
+#undef PRINTER_STATUS_PRINTING
+#undef PRINTER_STATUS_OUTPUT_BIN_FULL
+#undef PRINTER_STATUS_NOT_AVAILABLE
+#undef PRINTER_STATUS_WAITING
+#undef PRINTER_STATUS_PROCESSING
+#undef PRINTER_STATUS_INITIALIZING
+#undef PRINTER_STATUS_WARMING_UP
+#undef PRINTER_STATUS_TONER_LOW
+#undef PRINTER_STATUS_NO_TONER
+#undef PRINTER_STATUS_PAGE_PUNT
+#undef PRINTER_STATUS_USER_INTERVENTION
+#undef PRINTER_STATUS_OUT_OF_MEMORY
+#undef PRINTER_STATUS_DOOR_OPEN
+#undef PRINTER_STATUS_SERVER_UNKNOWN
+#undef PRINTER_STATUS_POWER_SAVE
+
+#undef DWORD
+#undef HKEY_CLASSES_ROOT
+#undef HKEY_CURRENT_USER
+#undef HKEY_LOCAL_MACHINE
+#undef HKEY_USERS
+#undef HKEY_PERFORMANCE_DATA
+#undef HKEY_CURRENT_CONFIG
+#undef HKEY_DYN_DATA
+#undef REG_DWORD
+#undef REG_QWORD
+
+#undef SERVICE_STATE_ALL
+
+#undef SE_GROUP_MANDATORY
+#undef SE_GROUP_ENABLED_BY_DEFAULT
+#undef SE_GROUP_ENABLED
+
+#endif /* _WIN32_REPLACE_H */
diff --git a/source3/lib/secace.c b/source3/lib/secace.c
new file mode 100644
index 0000000000..8760a6109a
--- /dev/null
+++ b/source3/lib/secace.c
@@ -0,0 +1,293 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * SEC_ACE handling functions
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Jeremy R. Allison 1995-2003.
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/*******************************************************************
+ Check if ACE has OBJECT type.
+********************************************************************/
+
+bool sec_ace_object(uint8 type)
+{
+ if (type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
+ type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT ||
+ type == SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT ||
+ type == SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT) {
+ return True;
+ }
+ return False;
+}
+
+/*******************************************************************
+ copy a SEC_ACE structure.
+********************************************************************/
+void sec_ace_copy(SEC_ACE *ace_dest, SEC_ACE *ace_src)
+{
+ ace_dest->type = ace_src->type;
+ ace_dest->flags = ace_src->flags;
+ ace_dest->size = ace_src->size;
+ ace_dest->access_mask = ace_src->access_mask;
+ ace_dest->object = ace_src->object;
+ sid_copy(&ace_dest->trustee, &ace_src->trustee);
+}
+
+/*******************************************************************
+ Sets up a SEC_ACE structure.
+********************************************************************/
+
+void init_sec_ace(SEC_ACE *t, const DOM_SID *sid, enum security_ace_type type,
+ uint32 mask, uint8 flag)
+{
+ t->type = type;
+ t->flags = flag;
+ t->size = ndr_size_dom_sid(sid, 0) + 8;
+ t->access_mask = mask;
+
+ ZERO_STRUCTP(&t->trustee);
+ sid_copy(&t->trustee, sid);
+}
+
+/*******************************************************************
+ adds new SID with its permissions to ACE list
+********************************************************************/
+
+NTSTATUS sec_ace_add_sid(TALLOC_CTX *ctx, SEC_ACE **pp_new, SEC_ACE *old, unsigned *num, DOM_SID *sid, uint32 mask)
+{
+ unsigned int i = 0;
+
+ if (!ctx || !pp_new || !old || !sid || !num) return NT_STATUS_INVALID_PARAMETER;
+
+ *num += 1;
+
+ if((pp_new[0] = TALLOC_ZERO_ARRAY(ctx, SEC_ACE, *num )) == 0)
+ return NT_STATUS_NO_MEMORY;
+
+ for (i = 0; i < *num - 1; i ++)
+ sec_ace_copy(&(*pp_new)[i], &old[i]);
+
+ (*pp_new)[i].type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ (*pp_new)[i].flags = 0;
+ (*pp_new)[i].size = SEC_ACE_HEADER_SIZE + ndr_size_dom_sid(sid, 0);
+ (*pp_new)[i].access_mask = mask;
+ sid_copy(&(*pp_new)[i].trustee, sid);
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ modify SID's permissions at ACL
+********************************************************************/
+
+NTSTATUS sec_ace_mod_sid(SEC_ACE *ace, size_t num, DOM_SID *sid, uint32 mask)
+{
+ unsigned int i = 0;
+
+ if (!ace || !sid) return NT_STATUS_INVALID_PARAMETER;
+
+ for (i = 0; i < num; i ++) {
+ if (sid_compare(&ace[i].trustee, sid) == 0) {
+ ace[i].access_mask = mask;
+ return NT_STATUS_OK;
+ }
+ }
+ return NT_STATUS_NOT_FOUND;
+}
+
+/*******************************************************************
+ delete SID from ACL
+********************************************************************/
+
+NTSTATUS sec_ace_del_sid(TALLOC_CTX *ctx, SEC_ACE **pp_new, SEC_ACE *old, uint32 *num, DOM_SID *sid)
+{
+ unsigned int i = 0;
+ unsigned int n_del = 0;
+
+ if (!ctx || !pp_new || !old || !sid || !num) return NT_STATUS_INVALID_PARAMETER;
+
+ if (*num) {
+ if((pp_new[0] = TALLOC_ZERO_ARRAY(ctx, SEC_ACE, *num )) == 0)
+ return NT_STATUS_NO_MEMORY;
+ } else {
+ pp_new[0] = NULL;
+ }
+
+ for (i = 0; i < *num; i ++) {
+ if (sid_compare(&old[i].trustee, sid) != 0)
+ sec_ace_copy(&(*pp_new)[i], &old[i]);
+ else
+ n_del ++;
+ }
+ if (n_del == 0)
+ return NT_STATUS_NOT_FOUND;
+ else {
+ *num -= n_del;
+ return NT_STATUS_OK;
+ }
+}
+
+/*******************************************************************
+ Compares two SEC_ACE structures
+********************************************************************/
+
+bool sec_ace_equal(SEC_ACE *s1, SEC_ACE *s2)
+{
+ /* Trivial case */
+
+ if (!s1 && !s2) {
+ return True;
+ }
+
+ if (!s1 || !s2) {
+ return False;
+ }
+
+ /* Check top level stuff */
+
+ if (s1->type != s2->type || s1->flags != s2->flags ||
+ s1->access_mask != s2->access_mask) {
+ return False;
+ }
+
+ /* Check SID */
+
+ if (!sid_equal(&s1->trustee, &s2->trustee)) {
+ return False;
+ }
+
+ return True;
+}
+
+int nt_ace_inherit_comp( SEC_ACE *a1, SEC_ACE *a2)
+{
+ int a1_inh = a1->flags & SEC_ACE_FLAG_INHERITED_ACE;
+ int a2_inh = a2->flags & SEC_ACE_FLAG_INHERITED_ACE;
+
+ if (a1_inh == a2_inh)
+ return 0;
+
+ if (!a1_inh && a2_inh)
+ return -1;
+ return 1;
+}
+
+/*******************************************************************
+ Comparison function to apply the order explained below in a group.
+*******************************************************************/
+
+int nt_ace_canon_comp( SEC_ACE *a1, SEC_ACE *a2)
+{
+ if ((a1->type == SEC_ACE_TYPE_ACCESS_DENIED) &&
+ (a2->type != SEC_ACE_TYPE_ACCESS_DENIED))
+ return -1;
+
+ if ((a2->type == SEC_ACE_TYPE_ACCESS_DENIED) &&
+ (a1->type != SEC_ACE_TYPE_ACCESS_DENIED))
+ return 1;
+
+ /* Both access denied or access allowed. */
+
+ /* 1. ACEs that apply to the object itself */
+
+ if (!(a1->flags & SEC_ACE_FLAG_INHERIT_ONLY) &&
+ (a2->flags & SEC_ACE_FLAG_INHERIT_ONLY))
+ return -1;
+ else if (!(a2->flags & SEC_ACE_FLAG_INHERIT_ONLY) &&
+ (a1->flags & SEC_ACE_FLAG_INHERIT_ONLY))
+ return 1;
+
+ /* 2. ACEs that apply to a subobject of the object, such as
+ * a property set or property. */
+
+ if (a1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT) &&
+ !(a2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT)))
+ return -1;
+ else if (a2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT) &&
+ !(a1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT)))
+ return 1;
+
+ return 0;
+}
+
+/*******************************************************************
+ Functions to convert a SEC_DESC ACE DACL list into canonical order.
+ JRA.
+
+--- from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/order_of_aces_in_a_dacl.asp
+
+The following describes the preferred order:
+
+ To ensure that noninherited ACEs have precedence over inherited ACEs,
+ place all noninherited ACEs in a group before any inherited ACEs.
+ This ordering ensures, for example, that a noninherited access-denied ACE
+ is enforced regardless of any inherited ACE that allows access.
+
+ Within the groups of noninherited ACEs and inherited ACEs, order ACEs according to ACE type, as the following shows:
+ 1. Access-denied ACEs that apply to the object itself
+ 2. Access-denied ACEs that apply to a subobject of the object, such as a property set or property
+ 3. Access-allowed ACEs that apply to the object itself
+ 4. Access-allowed ACEs that apply to a subobject of the object"
+
+********************************************************************/
+
+void dacl_sort_into_canonical_order(SEC_ACE *srclist, unsigned int num_aces)
+{
+ unsigned int i;
+
+ if (!srclist || num_aces == 0)
+ return;
+
+ /* Sort so that non-inherited ACE's come first. */
+ qsort( srclist, num_aces, sizeof(srclist[0]), QSORT_CAST nt_ace_inherit_comp);
+
+ /* Find the boundary between non-inherited ACEs. */
+ for (i = 0; i < num_aces; i++ ) {
+ SEC_ACE *curr_ace = &srclist[i];
+
+ if (curr_ace->flags & SEC_ACE_FLAG_INHERITED_ACE)
+ break;
+ }
+
+ /* i now points at entry number of the first inherited ACE. */
+
+ /* Sort the non-inherited ACEs. */
+ if (i)
+ qsort( srclist, i, sizeof(srclist[0]), QSORT_CAST nt_ace_canon_comp);
+
+ /* Now sort the inherited ACEs. */
+ if (num_aces - i)
+ qsort( &srclist[i], num_aces - i, sizeof(srclist[0]), QSORT_CAST nt_ace_canon_comp);
+}
+
+/*******************************************************************
+ Check if this ACE has a SID in common with the token.
+********************************************************************/
+
+bool token_sid_in_ace(const NT_USER_TOKEN *token, const SEC_ACE *ace)
+{
+ size_t i;
+
+ for (i = 0; i < token->num_sids; i++) {
+ if (sid_equal(&ace->trustee, &token->user_sids[i]))
+ return True;
+ }
+
+ return False;
+}
diff --git a/source3/lib/secacl.c b/source3/lib/secacl.c
new file mode 100644
index 0000000000..5e82242e1b
--- /dev/null
+++ b/source3/lib/secacl.c
@@ -0,0 +1,118 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * SEC_ACL handling routines
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Jeremy R. Allison 1995-2003.
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/*******************************************************************
+ Create a SEC_ACL structure.
+********************************************************************/
+
+SEC_ACL *make_sec_acl(TALLOC_CTX *ctx, enum security_acl_revision revision,
+ int num_aces, SEC_ACE *ace_list)
+{
+ SEC_ACL *dst;
+ int i;
+
+ if((dst = TALLOC_ZERO_P(ctx,SEC_ACL)) == NULL)
+ return NULL;
+
+ dst->revision = revision;
+ dst->num_aces = num_aces;
+ dst->size = SEC_ACL_HEADER_SIZE;
+
+ /* Now we need to return a non-NULL address for the ace list even
+ if the number of aces required is zero. This is because there
+ is a distinct difference between a NULL ace and an ace with zero
+ entries in it. This is achieved by checking that num_aces is a
+ positive number. */
+
+ if ((num_aces) &&
+ ((dst->aces = TALLOC_ARRAY(ctx, SEC_ACE, num_aces))
+ == NULL)) {
+ return NULL;
+ }
+
+ for (i = 0; i < num_aces; i++) {
+ dst->aces[i] = ace_list[i]; /* Structure copy. */
+ dst->size += ace_list[i].size;
+ }
+
+ return dst;
+}
+
+/*******************************************************************
+ Duplicate a SEC_ACL structure.
+********************************************************************/
+
+SEC_ACL *dup_sec_acl(TALLOC_CTX *ctx, SEC_ACL *src)
+{
+ if(src == NULL)
+ return NULL;
+
+ return make_sec_acl(ctx, src->revision, src->num_aces, src->aces);
+}
+
+/*******************************************************************
+ Compares two SEC_ACL structures
+********************************************************************/
+
+bool sec_acl_equal(SEC_ACL *s1, SEC_ACL *s2)
+{
+ unsigned int i, j;
+
+ /* Trivial cases */
+
+ if (!s1 && !s2) return True;
+ if (!s1 || !s2) return False;
+
+ /* Check top level stuff */
+
+ if (s1->revision != s2->revision) {
+ DEBUG(10, ("sec_acl_equal(): revision differs (%d != %d)\n",
+ s1->revision, s2->revision));
+ return False;
+ }
+
+ if (s1->num_aces != s2->num_aces) {
+ DEBUG(10, ("sec_acl_equal(): num_aces differs (%d != %d)\n",
+ s1->revision, s2->revision));
+ return False;
+ }
+
+ /* The ACEs could be in any order so check each ACE in s1 against
+ each ACE in s2. */
+
+ for (i = 0; i < s1->num_aces; i++) {
+ bool found = False;
+
+ for (j = 0; j < s2->num_aces; j++) {
+ if (sec_ace_equal(&s1->aces[i], &s2->aces[j])) {
+ found = True;
+ break;
+ }
+ }
+
+ if (!found) return False;
+ }
+
+ return True;
+}
diff --git a/source3/lib/secdesc.c b/source3/lib/secdesc.c
new file mode 100644
index 0000000000..44ae23271e
--- /dev/null
+++ b/source3/lib/secdesc.c
@@ -0,0 +1,559 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * SEC_DESC handling functions
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Jeremy R. Allison 1995-2003.
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/* Map generic permissions to file object specific permissions */
+
+const struct generic_mapping file_generic_mapping = {
+ FILE_GENERIC_READ,
+ FILE_GENERIC_WRITE,
+ FILE_GENERIC_EXECUTE,
+ FILE_GENERIC_ALL
+};
+
+/*******************************************************************
+ Compares two SEC_DESC structures
+********************************************************************/
+
+bool sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
+{
+ /* Trivial case */
+
+ if (!s1 && !s2) {
+ goto done;
+ }
+
+ if (!s1 || !s2) {
+ return False;
+ }
+
+ /* Check top level stuff */
+
+ if (s1->revision != s2->revision) {
+ DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
+ s1->revision, s2->revision));
+ return False;
+ }
+
+ if (s1->type!= s2->type) {
+ DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
+ s1->type, s2->type));
+ return False;
+ }
+
+ /* Check owner and group */
+
+ if (!sid_equal(s1->owner_sid, s2->owner_sid)) {
+ DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
+ sid_string_dbg(s1->owner_sid),
+ sid_string_dbg(s2->owner_sid)));
+ return False;
+ }
+
+ if (!sid_equal(s1->group_sid, s2->group_sid)) {
+ DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
+ sid_string_dbg(s1->group_sid),
+ sid_string_dbg(s2->group_sid)));
+ return False;
+ }
+
+ /* Check ACLs present in one but not the other */
+
+ if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
+ (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) {
+ DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
+ return False;
+ }
+
+ /* Sigh - we have to do it the hard way by iterating over all
+ the ACEs in the ACLs */
+
+ if (!sec_acl_equal(s1->dacl, s2->dacl) ||
+ !sec_acl_equal(s1->sacl, s2->sacl)) {
+ DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
+ return False;
+ }
+
+ done:
+ DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
+ return True;
+}
+
+/*******************************************************************
+ Merge part of security descriptor old_sec in to the empty sections of
+ security descriptor new_sec.
+********************************************************************/
+
+SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
+{
+ DOM_SID *owner_sid, *group_sid;
+ SEC_DESC_BUF *return_sdb;
+ SEC_ACL *dacl, *sacl;
+ SEC_DESC *psd = NULL;
+ uint16 secdesc_type;
+ size_t secdesc_size;
+
+ /* Copy over owner and group sids. There seems to be no flag for
+ this so just check the pointer values. */
+
+ owner_sid = new_sdb->sd->owner_sid ? new_sdb->sd->owner_sid :
+ old_sdb->sd->owner_sid;
+
+ group_sid = new_sdb->sd->group_sid ? new_sdb->sd->group_sid :
+ old_sdb->sd->group_sid;
+
+ secdesc_type = new_sdb->sd->type;
+
+ /* Ignore changes to the system ACL. This has the effect of making
+ changes through the security tab audit button not sticking.
+ Perhaps in future Samba could implement these settings somehow. */
+
+ sacl = NULL;
+ secdesc_type &= ~SEC_DESC_SACL_PRESENT;
+
+ /* Copy across discretionary ACL */
+
+ if (secdesc_type & SEC_DESC_DACL_PRESENT) {
+ dacl = new_sdb->sd->dacl;
+ } else {
+ dacl = old_sdb->sd->dacl;
+ }
+
+ /* Create new security descriptor from bits */
+
+ psd = make_sec_desc(ctx, new_sdb->sd->revision, secdesc_type,
+ owner_sid, group_sid, sacl, dacl, &secdesc_size);
+
+ return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
+
+ return(return_sdb);
+}
+
+/*******************************************************************
+ Creates a SEC_DESC structure
+********************************************************************/
+
+SEC_DESC *make_sec_desc(TALLOC_CTX *ctx,
+ enum security_descriptor_revision revision,
+ uint16 type,
+ const DOM_SID *owner_sid, const DOM_SID *grp_sid,
+ SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
+{
+ SEC_DESC *dst;
+ uint32 offset = 0;
+
+ *sd_size = 0;
+
+ if(( dst = TALLOC_ZERO_P(ctx, SEC_DESC)) == NULL)
+ return NULL;
+
+ dst->revision = revision;
+ dst->type = type;
+
+ if (sacl)
+ dst->type |= SEC_DESC_SACL_PRESENT;
+ if (dacl)
+ dst->type |= SEC_DESC_DACL_PRESENT;
+
+ dst->owner_sid = NULL;
+ dst->group_sid = NULL;
+ dst->sacl = NULL;
+ dst->dacl = NULL;
+
+ if(owner_sid && ((dst->owner_sid = sid_dup_talloc(dst,owner_sid)) == NULL))
+ goto error_exit;
+
+ if(grp_sid && ((dst->group_sid = sid_dup_talloc(dst,grp_sid)) == NULL))
+ goto error_exit;
+
+ if(sacl && ((dst->sacl = dup_sec_acl(dst, sacl)) == NULL))
+ goto error_exit;
+
+ if(dacl && ((dst->dacl = dup_sec_acl(dst, dacl)) == NULL))
+ goto error_exit;
+
+ offset = SEC_DESC_HEADER_SIZE;
+
+ /*
+ * Work out the linearization sizes.
+ */
+
+ if (dst->sacl != NULL) {
+ offset += dst->sacl->size;
+ }
+ if (dst->dacl != NULL) {
+ offset += dst->dacl->size;
+ }
+
+ if (dst->owner_sid != NULL) {
+ offset += ndr_size_dom_sid(dst->owner_sid, 0);
+ }
+
+ if (dst->group_sid != NULL) {
+ offset += ndr_size_dom_sid(dst->group_sid, 0);
+ }
+
+ *sd_size = (size_t)offset;
+ return dst;
+
+error_exit:
+
+ *sd_size = 0;
+ return NULL;
+}
+
+/*******************************************************************
+ Duplicate a SEC_DESC structure.
+********************************************************************/
+
+SEC_DESC *dup_sec_desc(TALLOC_CTX *ctx, const SEC_DESC *src)
+{
+ size_t dummy;
+
+ if(src == NULL)
+ return NULL;
+
+ return make_sec_desc( ctx, src->revision, src->type,
+ src->owner_sid, src->group_sid, src->sacl,
+ src->dacl, &dummy);
+}
+
+/*******************************************************************
+ Convert a secdesc into a byte stream
+********************************************************************/
+NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx,
+ struct security_descriptor *secdesc,
+ uint8 **data, size_t *len)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_push_struct_blob(
+ &blob, mem_ctx, secdesc,
+ (ndr_push_flags_fn_t)ndr_push_security_descriptor);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_push_security_descriptor failed: %s\n",
+ ndr_errstr(ndr_err)));
+ return ndr_map_error2ntstatus(ndr_err);;
+ }
+
+ *data = blob.data;
+ *len = blob.length;
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Parse a byte stream into a secdesc
+********************************************************************/
+NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8 *data, size_t len,
+ struct security_descriptor **psecdesc)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ struct security_descriptor *result;
+
+ if ((data == NULL) || (len == 0)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ result = TALLOC_ZERO_P(mem_ctx, struct security_descriptor);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ blob = data_blob_const(data, len);
+
+ ndr_err = ndr_pull_struct_blob(
+ &blob, result, result,
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_pull_security_descriptor failed: %s\n",
+ ndr_errstr(ndr_err)));
+ TALLOC_FREE(result);
+ return ndr_map_error2ntstatus(ndr_err);;
+ }
+
+ *psecdesc = result;
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Creates a SEC_DESC structure with typical defaults.
+********************************************************************/
+
+SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, const DOM_SID *owner_sid, const DOM_SID *grp_sid,
+ SEC_ACL *dacl, size_t *sd_size)
+{
+ return make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
+ SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid, NULL,
+ dacl, sd_size);
+}
+
+/*******************************************************************
+ Creates a SEC_DESC_BUF structure.
+********************************************************************/
+
+SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
+{
+ SEC_DESC_BUF *dst;
+
+ if((dst = TALLOC_ZERO_P(ctx, SEC_DESC_BUF)) == NULL)
+ return NULL;
+
+ /* max buffer size (allocated size) */
+ dst->sd_size = (uint32)len;
+
+ if(sec_desc && ((dst->sd = dup_sec_desc(ctx, sec_desc)) == NULL)) {
+ return NULL;
+ }
+
+ return dst;
+}
+
+/*******************************************************************
+ Duplicates a SEC_DESC_BUF structure.
+********************************************************************/
+
+SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
+{
+ if(src == NULL)
+ return NULL;
+
+ return make_sec_desc_buf( ctx, src->sd_size, src->sd);
+}
+
+/*******************************************************************
+ Add a new SID with its permissions to SEC_DESC.
+********************************************************************/
+
+NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
+{
+ SEC_DESC *sd = 0;
+ SEC_ACL *dacl = 0;
+ SEC_ACE *ace = 0;
+ NTSTATUS status;
+
+ if (!ctx || !psd || !sid || !sd_size)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ *sd_size = 0;
+
+ status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid, mask);
+
+ if (!NT_STATUS_IS_OK(status))
+ return status;
+
+ if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
+ psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ *psd = sd;
+ sd = 0;
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Modify a SID's permissions in a SEC_DESC.
+********************************************************************/
+
+NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
+{
+ NTSTATUS status;
+
+ if (!sd || !sid)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
+
+ if (!NT_STATUS_IS_OK(status))
+ return status;
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Delete a SID from a SEC_DESC.
+********************************************************************/
+
+NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
+{
+ SEC_DESC *sd = 0;
+ SEC_ACL *dacl = 0;
+ SEC_ACE *ace = 0;
+ NTSTATUS status;
+
+ if (!ctx || !psd[0] || !sid || !sd_size)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ *sd_size = 0;
+
+ status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid);
+
+ if (!NT_STATUS_IS_OK(status))
+ return status;
+
+ if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
+ psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ *psd = sd;
+ sd = 0;
+ return NT_STATUS_OK;
+}
+
+/* Create a child security descriptor using another security descriptor as
+ the parent container. This child object can either be a container or
+ non-container object. */
+
+SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr,
+ bool child_container)
+{
+ SEC_DESC_BUF *sdb;
+ SEC_DESC *sd;
+ SEC_ACL *new_dacl, *the_acl;
+ SEC_ACE *new_ace_list = NULL;
+ unsigned int new_ace_list_ndx = 0, i;
+ size_t size;
+
+ /* Currently we only process the dacl when creating the child. The
+ sacl should also be processed but this is left out as sacls are
+ not implemented in Samba at the moment.*/
+
+ the_acl = parent_ctr->dacl;
+
+ if (the_acl->num_aces) {
+ if (!(new_ace_list = TALLOC_ARRAY(ctx, SEC_ACE, the_acl->num_aces)))
+ return NULL;
+ } else {
+ new_ace_list = NULL;
+ }
+
+ for (i = 0; i < the_acl->num_aces; i++) {
+ SEC_ACE *ace = &the_acl->aces[i];
+ SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
+ uint8 new_flags = 0;
+ bool inherit = False;
+
+ /* The OBJECT_INHERIT_ACE flag causes the ACE to be
+ inherited by non-container children objects. Container
+ children objects will inherit it as an INHERIT_ONLY
+ ACE. */
+
+ if (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
+
+ if (!child_container) {
+ new_flags |= SEC_ACE_FLAG_OBJECT_INHERIT;
+ } else {
+ new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+ }
+
+ inherit = True;
+ }
+
+ /* The CONAINER_INHERIT_ACE flag means all child container
+ objects will inherit and use the ACE. */
+
+ if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
+ if (!child_container) {
+ inherit = False;
+ } else {
+ new_flags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
+ }
+ }
+
+ /* The INHERIT_ONLY_ACE is not used by the se_access_check()
+ function for the parent container, but is inherited by
+ all child objects as a normal ACE. */
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ /* Move along, nothing to see here */
+ }
+
+ /* The SEC_ACE_FLAG_NO_PROPAGATE_INHERIT flag means the ACE
+ is inherited by child objects but not grandchildren
+ objects. We clear the object inherit and container
+ inherit flags in the inherited ACE. */
+
+ if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
+ new_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT);
+ }
+
+ /* Add ACE to ACE list */
+
+ if (!inherit)
+ continue;
+
+ init_sec_access(&new_ace->access_mask, ace->access_mask);
+ init_sec_ace(new_ace, &ace->trustee, ace->type,
+ new_ace->access_mask, new_flags);
+
+ DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
+ " inherited as %s:%d/0x%02x/0x%08x\n",
+ sid_string_dbg(&ace->trustee),
+ ace->type, ace->flags, ace->access_mask,
+ sid_string_dbg(&ace->trustee),
+ new_ace->type, new_ace->flags,
+ new_ace->access_mask));
+
+ new_ace_list_ndx++;
+ }
+
+ /* Create child security descriptor to return */
+
+ new_dacl = make_sec_acl(ctx, ACL_REVISION, new_ace_list_ndx, new_ace_list);
+
+ /* Use the existing user and group sids. I don't think this is
+ correct. Perhaps the user and group should be passed in as
+ parameters by the caller? */
+
+ sd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
+ SEC_DESC_SELF_RELATIVE,
+ parent_ctr->owner_sid,
+ parent_ctr->group_sid,
+ parent_ctr->sacl,
+ new_dacl, &size);
+
+ sdb = make_sec_desc_buf(ctx, size, sd);
+
+ return sdb;
+}
+
+/*******************************************************************
+ Sets up a SEC_ACCESS structure.
+********************************************************************/
+
+void init_sec_access(uint32 *t, uint32 mask)
+{
+ *t = mask;
+}
+
+
diff --git a/source3/lib/select.c b/source3/lib/select.c
new file mode 100644
index 0000000000..c3da6a9bba
--- /dev/null
+++ b/source3/lib/select.c
@@ -0,0 +1,192 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba select/poll implementation
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* This is here because it allows us to avoid a nasty race in signal handling.
+ We need to guarantee that when we get a signal we get out of a select immediately
+ but doing that involves a race condition. We can avoid the race by getting the
+ signal handler to write to a pipe that is in the select/poll list
+
+ This means all Samba signal handlers should call sys_select_signal().
+*/
+
+static pid_t initialised;
+static int select_pipe[2];
+static VOLATILE unsigned pipe_written, pipe_read;
+
+/*******************************************************************
+ Call this from all Samba signal handlers if you want to avoid a
+ nasty signal race condition.
+********************************************************************/
+
+void sys_select_signal(char c)
+{
+ if (!initialised) return;
+
+ if (pipe_written > pipe_read+256) return;
+
+ if (write(select_pipe[1], &c, 1) == 1) pipe_written++;
+}
+
+/*******************************************************************
+ Like select() but avoids the signal race using a pipe
+ it also guuarantees that fds on return only ever contains bits set
+ for file descriptors that were readable.
+********************************************************************/
+
+int sys_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval)
+{
+ int ret, saved_errno;
+ fd_set *readfds2, readfds_buf;
+
+ if (initialised != sys_getpid()) {
+ if (pipe(select_pipe) == -1)
+ smb_panic("Could not create select pipe");
+
+ /*
+ * These next two lines seem to fix a bug with the Linux
+ * 2.0.x kernel (and probably other UNIXes as well) where
+ * the one byte read below can block even though the
+ * select returned that there is data in the pipe and
+ * the pipe_written variable was incremented. Thanks to
+ * HP for finding this one. JRA.
+ */
+
+ if(set_blocking(select_pipe[0],0)==-1)
+ smb_panic("select_pipe[0]: O_NONBLOCK failed");
+ if(set_blocking(select_pipe[1],0)==-1)
+ smb_panic("select_pipe[1]: O_NONBLOCK failed");
+
+ initialised = sys_getpid();
+ }
+
+ maxfd = MAX(select_pipe[0]+1, maxfd);
+
+ /* If readfds is NULL we need to provide our own set. */
+ if (readfds) {
+ readfds2 = readfds;
+ } else {
+ readfds2 = &readfds_buf;
+ FD_ZERO(readfds2);
+ }
+ FD_SET(select_pipe[0], readfds2);
+
+ errno = 0;
+ ret = select(maxfd,readfds2,writefds,errorfds,tval);
+
+ if (ret <= 0) {
+ FD_ZERO(readfds2);
+ if (writefds)
+ FD_ZERO(writefds);
+ if (errorfds)
+ FD_ZERO(errorfds);
+ } else if (FD_ISSET(select_pipe[0], readfds2)) {
+ char c;
+ saved_errno = errno;
+ if (read(select_pipe[0], &c, 1) == 1) {
+ pipe_read++;
+ /* Mark Weaver <mark-clist@npsl.co.uk> pointed out a critical
+ fix to ensure we don't lose signals. We must always
+ return -1 when the select pipe is set, otherwise if another
+ fd is also ready (so ret == 2) then we used to eat the
+ byte in the pipe and lose the signal. JRA.
+ */
+ ret = -1;
+#if 0
+ /* JRA - we can use this to debug the signal messaging... */
+ DEBUG(0,("select got %u signal\n", (unsigned int)c));
+#endif
+ errno = EINTR;
+ } else {
+ FD_CLR(select_pipe[0], readfds2);
+ ret--;
+ errno = saved_errno;
+ }
+ }
+
+ return ret;
+}
+
+/*******************************************************************
+ Similar to sys_select() but catch EINTR and continue.
+ This is what sys_select() used to do in Samba.
+********************************************************************/
+
+int sys_select_intr(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval)
+{
+ int ret;
+ fd_set *readfds2, readfds_buf, *writefds2, writefds_buf, *errorfds2, errorfds_buf;
+ struct timeval tval2, *ptval, end_time;
+
+ readfds2 = (readfds ? &readfds_buf : NULL);
+ writefds2 = (writefds ? &writefds_buf : NULL);
+ errorfds2 = (errorfds ? &errorfds_buf : NULL);
+ if (tval) {
+ GetTimeOfDay(&end_time);
+ end_time.tv_sec += tval->tv_sec;
+ end_time.tv_usec += tval->tv_usec;
+ end_time.tv_sec += end_time.tv_usec / 1000000;
+ end_time.tv_usec %= 1000000;
+ errno = 0;
+ tval2 = *tval;
+ ptval = &tval2;
+ } else {
+ ptval = NULL;
+ }
+
+ do {
+ if (readfds)
+ readfds_buf = *readfds;
+ if (writefds)
+ writefds_buf = *writefds;
+ if (errorfds)
+ errorfds_buf = *errorfds;
+ if (ptval && (errno == EINTR)) {
+ struct timeval now_time;
+ SMB_BIG_INT tdif;
+
+ GetTimeOfDay(&now_time);
+ tdif = usec_time_diff(&end_time, &now_time);
+ if (tdif <= 0) {
+ ret = 0; /* time expired. */
+ break;
+ }
+ ptval->tv_sec = tdif / 1000000;
+ ptval->tv_usec = tdif % 1000000;
+ }
+
+ /* We must use select and not sys_select here. If we use
+ sys_select we'd lose the fact a signal occurred when sys_select
+ read a byte from the pipe. Fix from Mark Weaver
+ <mark-clist@npsl.co.uk>
+ */
+ ret = select(maxfd, readfds2, writefds2, errorfds2, ptval);
+ } while (ret == -1 && errno == EINTR);
+
+ if (readfds)
+ *readfds = readfds_buf;
+ if (writefds)
+ *writefds = writefds_buf;
+ if (errorfds)
+ *errorfds = errorfds_buf;
+
+ return ret;
+}
diff --git a/source3/lib/sendfile.c b/source3/lib/sendfile.c
new file mode 100644
index 0000000000..d1b178577c
--- /dev/null
+++ b/source3/lib/sendfile.c
@@ -0,0 +1,461 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2.x / 3.0.x
+ sendfile implementations.
+ Copyright (C) Jeremy Allison 2002.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * This file handles the OS dependent sendfile implementations.
+ * The API is such that it returns -1 on error, else returns the
+ * number of bytes written.
+ */
+
+#include "includes.h"
+
+#if defined(LINUX_SENDFILE_API)
+
+#include <sys/sendfile.h>
+
+#ifndef MSG_MORE
+#define MSG_MORE 0x8000
+#endif
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ size_t total=0;
+ ssize_t ret;
+ size_t hdr_len = 0;
+
+ /*
+ * Send the header first.
+ * Use MSG_MORE to cork the TCP output until sendfile is called.
+ */
+
+ if (header) {
+ hdr_len = header->length;
+ while (total < hdr_len) {
+ ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
+ if (ret == -1)
+ return -1;
+ total += ret;
+ }
+ }
+
+ total = count;
+ while (total) {
+ ssize_t nwritten;
+ do {
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
+ nwritten = sendfile64(tofd, fromfd, &offset, total);
+#else
+ nwritten = sendfile(tofd, fromfd, &offset, total);
+#endif
+ } while (nwritten == -1 && errno == EINTR);
+ if (nwritten == -1) {
+ if (errno == ENOSYS) {
+ /* Ok - we're in a world of pain here. We just sent
+ * the header, but the sendfile failed. We have to
+ * emulate the sendfile at an upper layer before we
+ * disable it's use. So we do something really ugly.
+ * We set the errno to a strange value so we can detect
+ * this at the upper level and take care of it without
+ * layer violation. JRA.
+ */
+ errno = EINTR; /* Normally we can never return this. */
+ }
+ return -1;
+ }
+ if (nwritten == 0)
+ return -1; /* I think we're at EOF here... */
+ total -= nwritten;
+ }
+ return count + hdr_len;
+}
+
+#elif defined(LINUX_BROKEN_SENDFILE_API)
+
+/*
+ * We must use explicit 32 bit types here. This code path means Linux
+ * won't do proper 64-bit sendfile. JRA.
+ */
+
+extern int32 sendfile (int out_fd, int in_fd, int32 *offset, uint32 count);
+
+
+#ifndef MSG_MORE
+#define MSG_MORE 0x8000
+#endif
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ size_t total=0;
+ ssize_t ret;
+ ssize_t hdr_len = 0;
+ uint32 small_total = 0;
+ int32 small_offset;
+
+ /*
+ * Fix for broken Linux 2.4 systems with no working sendfile64().
+ * If the offset+count > 2 GB then pretend we don't have the
+ * system call sendfile at all. The upper layer catches this
+ * and uses a normal read. JRA.
+ */
+
+ if ((sizeof(SMB_OFF_T) >= 8) && (offset + count > (SMB_OFF_T)0x7FFFFFFF)) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ /*
+ * Send the header first.
+ * Use MSG_MORE to cork the TCP output until sendfile is called.
+ */
+
+ if (header) {
+ hdr_len = header->length;
+ while (total < hdr_len) {
+ ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
+ if (ret == -1)
+ return -1;
+ total += ret;
+ }
+ }
+
+ small_total = (uint32)count;
+ small_offset = (int32)offset;
+
+ while (small_total) {
+ int32 nwritten;
+ do {
+ nwritten = sendfile(tofd, fromfd, &small_offset, small_total);
+ } while (nwritten == -1 && errno == EINTR);
+ if (nwritten == -1) {
+ if (errno == ENOSYS) {
+ /* Ok - we're in a world of pain here. We just sent
+ * the header, but the sendfile failed. We have to
+ * emulate the sendfile at an upper layer before we
+ * disable it's use. So we do something really ugly.
+ * We set the errno to a strange value so we can detect
+ * this at the upper level and take care of it without
+ * layer violation. JRA.
+ */
+ errno = EINTR; /* Normally we can never return this. */
+ }
+ return -1;
+ }
+ if (nwritten == 0)
+ return -1; /* I think we're at EOF here... */
+ small_total -= nwritten;
+ }
+ return count + hdr_len;
+}
+
+
+#elif defined(SOLARIS_SENDFILE_API)
+
+/*
+ * Solaris sendfile code written by Pierre Belanger <belanger@pobox.com>.
+ */
+
+#include <sys/sendfile.h>
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ int sfvcnt;
+ size_t total, xferred;
+ struct sendfilevec vec[2];
+ ssize_t hdr_len = 0;
+
+ if (header) {
+ sfvcnt = 2;
+
+ vec[0].sfv_fd = SFV_FD_SELF;
+ vec[0].sfv_flag = 0;
+ vec[0].sfv_off = (off_t)header->data;
+ vec[0].sfv_len = hdr_len = header->length;
+
+ vec[1].sfv_fd = fromfd;
+ vec[1].sfv_flag = 0;
+ vec[1].sfv_off = offset;
+ vec[1].sfv_len = count;
+
+ } else {
+ sfvcnt = 1;
+
+ vec[0].sfv_fd = fromfd;
+ vec[0].sfv_flag = 0;
+ vec[0].sfv_off = offset;
+ vec[0].sfv_len = count;
+ }
+
+ total = count + hdr_len;
+
+ while (total) {
+ ssize_t nwritten;
+
+ /*
+ * Although not listed in the API error returns, this is almost certainly
+ * a slow system call and will be interrupted by a signal with EINTR. JRA.
+ */
+
+ xferred = 0;
+
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILEV64)
+ nwritten = sendfilev64(tofd, vec, sfvcnt, &xferred);
+#else
+ nwritten = sendfilev(tofd, vec, sfvcnt, &xferred);
+#endif
+ if (nwritten == -1 && errno == EINTR) {
+ if (xferred == 0)
+ continue; /* Nothing written yet. */
+ else
+ nwritten = xferred;
+ }
+
+ if (nwritten == -1)
+ return -1;
+ if (nwritten == 0)
+ return -1; /* I think we're at EOF here... */
+
+ /*
+ * If this was a short (signal interrupted) write we may need
+ * to subtract it from the header data, or null out the header
+ * data altogether if we wrote more than vec[0].sfv_len bytes.
+ * We move vec[1].* to vec[0].* and set sfvcnt to 1
+ */
+
+ if (sfvcnt == 2 && nwritten >= vec[0].sfv_len) {
+ vec[1].sfv_off += nwritten - vec[0].sfv_len;
+ vec[1].sfv_len -= nwritten - vec[0].sfv_len;
+
+ /* Move vec[1].* to vec[0].* and set sfvcnt to 1 */
+ vec[0] = vec[1];
+ sfvcnt = 1;
+ } else {
+ vec[0].sfv_off += nwritten;
+ vec[0].sfv_len -= nwritten;
+ }
+ total -= nwritten;
+ }
+ return count + hdr_len;
+}
+
+#elif defined(HPUX_SENDFILE_API)
+
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ size_t total=0;
+ struct iovec hdtrl[2];
+ size_t hdr_len = 0;
+
+ if (header) {
+ /* Set up the header/trailer iovec. */
+ hdtrl[0].iov_base = header->data;
+ hdtrl[0].iov_len = hdr_len = header->length;
+ } else {
+ hdtrl[0].iov_base = NULL;
+ hdtrl[0].iov_len = hdr_len = 0;
+ }
+ hdtrl[1].iov_base = NULL;
+ hdtrl[1].iov_len = 0;
+
+ total = count;
+ while (total + hdtrl[0].iov_len) {
+ ssize_t nwritten;
+
+ /*
+ * HPUX guarantees that if any data was written before
+ * a signal interrupt then sendfile returns the number of
+ * bytes written (which may be less than requested) not -1.
+ * nwritten includes the header data sent.
+ */
+
+ do {
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
+ nwritten = sendfile64(tofd, fromfd, offset, total, &hdtrl[0], 0);
+#else
+ nwritten = sendfile(tofd, fromfd, offset, total, &hdtrl[0], 0);
+#endif
+ } while (nwritten == -1 && errno == EINTR);
+ if (nwritten == -1)
+ return -1;
+ if (nwritten == 0)
+ return -1; /* I think we're at EOF here... */
+
+ /*
+ * If this was a short (signal interrupted) write we may need
+ * to subtract it from the header data, or null out the header
+ * data altogether if we wrote more than hdtrl[0].iov_len bytes.
+ * We change nwritten to be the number of file bytes written.
+ */
+
+ if (hdtrl[0].iov_base && hdtrl[0].iov_len) {
+ if (nwritten >= hdtrl[0].iov_len) {
+ nwritten -= hdtrl[0].iov_len;
+ hdtrl[0].iov_base = NULL;
+ hdtrl[0].iov_len = 0;
+ } else {
+ /* iov_base is defined as a void *... */
+ hdtrl[0].iov_base = ((char *)hdtrl[0].iov_base) + nwritten;
+ hdtrl[0].iov_len -= nwritten;
+ nwritten = 0;
+ }
+ }
+ total -= nwritten;
+ offset += nwritten;
+ }
+ return count + hdr_len;
+}
+
+#elif defined(FREEBSD_SENDFILE_API)
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ size_t total=0;
+ struct sf_hdtr hdr;
+ struct iovec hdtrl;
+ size_t hdr_len = 0;
+
+ hdr.headers = &hdtrl;
+ hdr.hdr_cnt = 1;
+ hdr.trailers = NULL;
+ hdr.trl_cnt = 0;
+
+ /* Set up the header iovec. */
+ if (header) {
+ hdtrl.iov_base = header->data;
+ hdtrl.iov_len = hdr_len = header->length;
+ } else {
+ hdtrl.iov_base = NULL;
+ hdtrl.iov_len = 0;
+ }
+
+ total = count;
+ while (total + hdtrl.iov_len) {
+ SMB_OFF_T nwritten;
+ int ret;
+
+ /*
+ * FreeBSD sendfile returns 0 on success, -1 on error.
+ * Remember, the tofd and fromfd are reversed..... :-).
+ * nwritten includes the header data sent.
+ */
+
+ do {
+ ret = sendfile(fromfd, tofd, offset, total, &hdr, &nwritten, 0);
+ } while (ret == -1 && errno == EINTR);
+ if (ret == -1)
+ return -1;
+
+ if (nwritten == 0)
+ return -1; /* I think we're at EOF here... */
+
+ /*
+ * If this was a short (signal interrupted) write we may need
+ * to subtract it from the header data, or null out the header
+ * data altogether if we wrote more than hdtrl.iov_len bytes.
+ * We change nwritten to be the number of file bytes written.
+ */
+
+ if (hdtrl.iov_base && hdtrl.iov_len) {
+ if (nwritten >= hdtrl.iov_len) {
+ nwritten -= hdtrl.iov_len;
+ hdtrl.iov_base = NULL;
+ hdtrl.iov_len = 0;
+ } else {
+ hdtrl.iov_base =
+ (caddr_t)hdtrl.iov_base + nwritten;
+ hdtrl.iov_len -= nwritten;
+ nwritten = 0;
+ }
+ }
+ total -= nwritten;
+ offset += nwritten;
+ }
+ return count + hdr_len;
+}
+
+#elif defined(AIX_SENDFILE_API)
+
+/* BEGIN AIX SEND_FILE */
+
+/* Contributed by William Jojo <jojowil@hvcc.edu> */
+#include <sys/socket.h>
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ struct sf_parms hdtrl;
+
+ /* Set up the header/trailer struct params. */
+ if (header) {
+ hdtrl.header_data = header->data;
+ hdtrl.header_length = header->length;
+ } else {
+ hdtrl.header_data = NULL;
+ hdtrl.header_length = 0;
+ }
+ hdtrl.trailer_data = NULL;
+ hdtrl.trailer_length = 0;
+
+ hdtrl.file_descriptor = fromfd;
+ hdtrl.file_offset = offset;
+ hdtrl.file_bytes = count;
+
+ while ( hdtrl.file_bytes + hdtrl.header_length ) {
+ ssize_t ret;
+
+ /*
+ Return Value
+
+ There are three possible return values from send_file:
+
+ Value Description
+
+ -1 an error has occurred, errno contains the error code.
+
+ 0 the command has completed successfully.
+
+ 1 the command was completed partially, some data has been
+ transmitted but the command has to return for some reason,
+ for example, the command was interrupted by signals.
+ */
+ do {
+ ret = send_file(&tofd, &hdtrl, 0);
+ } while ( (ret == 1) || (ret == -1 && errno == EINTR) );
+ if ( ret == -1 )
+ return -1;
+ }
+
+ return count + header->length;
+}
+/* END AIX SEND_FILE */
+
+#else /* No sendfile implementation. Return error. */
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ /* No sendfile syscall. */
+ errno = ENOSYS;
+ return -1;
+}
+#endif
diff --git a/source3/lib/server_mutex.c b/source3/lib/server_mutex.c
new file mode 100644
index 0000000000..43c0de1975
--- /dev/null
+++ b/source3/lib/server_mutex.c
@@ -0,0 +1,78 @@
+/*
+ Unix SMB/CIFS implementation.
+ Authenticate against a remote domain
+ Copyright (C) Andrew Tridgell 1992-2002
+ Copyright (C) Andrew Bartlett 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* For reasons known only to MS, many of their NT/Win2k versions
+ need serialised access only. Two connections at the same time
+ may (in certain situations) cause connections to be reset,
+ or access to be denied.
+
+ This locking allows smbd's mutlithread architecture to look
+ like the single-connection that NT makes. */
+
+struct named_mutex {
+ struct tdb_wrap *tdb;
+ char *name;
+};
+
+static int unlock_named_mutex(struct named_mutex *mutex)
+{
+ tdb_unlock_bystring(mutex->tdb->tdb, mutex->name);
+ return 0;
+}
+
+struct named_mutex *grab_named_mutex(TALLOC_CTX *mem_ctx, const char *name,
+ int timeout)
+{
+ struct named_mutex *result;
+
+ result = talloc(mem_ctx, struct named_mutex);
+ if (result == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ result->name = talloc_strdup(result, name);
+ if (result->name == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ result->tdb = tdb_wrap_open(result, lock_path("mutex.tdb"), 0,
+ TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if (result->tdb == NULL) {
+ DEBUG(1, ("Could not open mutex.tdb: %s\n",
+ strerror(errno)));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ if (tdb_lock_bystring_with_timeout(result->tdb->tdb, name,
+ timeout) == -1) {
+ DEBUG(1, ("Could not get the lock for %s\n", name));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ talloc_set_destructor(result, unlock_named_mutex);
+ return result;
+}
diff --git a/source3/lib/sharesec.c b/source3/lib/sharesec.c
new file mode 100644
index 0000000000..33f66ca47f
--- /dev/null
+++ b/source3/lib/sharesec.c
@@ -0,0 +1,400 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * SEC_DESC handling functions
+ * Copyright (C) Jeremy R. Allison 1995-2003.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/*******************************************************************
+ Create the share security tdb.
+ ********************************************************************/
+
+static struct db_context *share_db; /* used for share security descriptors */
+#define SHARE_DATABASE_VERSION_V1 1
+#define SHARE_DATABASE_VERSION_V2 2 /* version id in little endian. */
+
+/* Map generic permissions to file object specific permissions */
+
+extern const struct generic_mapping file_generic_mapping;
+
+static int delete_fn(struct db_record *rec, void *priv)
+{
+ rec->delete_rec(rec);
+ return 0;
+}
+
+static bool share_info_db_init(void)
+{
+ const char *vstring = "INFO/version";
+ int32 vers_id;
+
+ if (share_db != NULL) {
+ return True;
+ }
+
+ share_db = db_open(NULL, state_path("share_info.tdb"), 0,
+ TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if (share_db == NULL) {
+ DEBUG(0,("Failed to open share info database %s (%s)\n",
+ state_path("share_info.tdb"), strerror(errno) ));
+ return False;
+ }
+
+ vers_id = dbwrap_fetch_int32(share_db, vstring);
+ if (vers_id == SHARE_DATABASE_VERSION_V2) {
+ return true;
+ }
+
+ if (share_db->transaction_start(share_db) != 0) {
+ DEBUG(0, ("transaction_start failed\n"));
+ TALLOC_FREE(share_db);
+ return false;
+ }
+
+ vers_id = dbwrap_fetch_int32(share_db, vstring);
+ if (vers_id == SHARE_DATABASE_VERSION_V2) {
+ /*
+ * Race condition
+ */
+ if (share_db->transaction_cancel(share_db)) {
+ smb_panic("transaction_cancel failed");
+ }
+ return true;
+ }
+
+ /* Cope with byte-reversed older versions of the db. */
+ if ((vers_id == SHARE_DATABASE_VERSION_V1) || (IREV(vers_id) == SHARE_DATABASE_VERSION_V1)) {
+ /* Written on a bigendian machine with old fetch_int code. Save as le. */
+
+ if (dbwrap_store_int32(share_db, vstring,
+ SHARE_DATABASE_VERSION_V2) != 0) {
+ DEBUG(0, ("dbwrap_store_int32 failed\n"));
+ goto cancel;
+ }
+ vers_id = SHARE_DATABASE_VERSION_V2;
+ }
+
+ if (vers_id != SHARE_DATABASE_VERSION_V2) {
+ int ret;
+ ret = share_db->traverse(share_db, delete_fn, NULL);
+ if (ret < 0) {
+ DEBUG(0, ("traverse failed\n"));
+ goto cancel;
+ }
+ if (dbwrap_store_int32(share_db, vstring,
+ SHARE_DATABASE_VERSION_V2) != 0) {
+ DEBUG(0, ("dbwrap_store_int32 failed\n"));
+ goto cancel;
+ }
+ }
+
+ if (share_db->transaction_commit(share_db) != 0) {
+ DEBUG(0, ("transaction_commit failed\n"));
+ return false;
+ }
+
+ return true;
+
+ cancel:
+ if (share_db->transaction_cancel(share_db)) {
+ smb_panic("transaction_cancel failed");
+ }
+
+ return false;
+}
+
+/*******************************************************************
+ Fake up a Everyone, default access as a default.
+ def_access is a GENERIC_XXX access mode.
+ ********************************************************************/
+
+SEC_DESC *get_share_security_default( TALLOC_CTX *ctx, size_t *psize, uint32 def_access)
+{
+ SEC_ACCESS sa;
+ SEC_ACE ace;
+ SEC_ACL *psa = NULL;
+ SEC_DESC *psd = NULL;
+ uint32 spec_access = def_access;
+
+ se_map_generic(&spec_access, &file_generic_mapping);
+
+ init_sec_access(&sa, def_access | spec_access );
+ init_sec_ace(&ace, &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, sa, 0);
+
+ if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 1, &ace)) != NULL) {
+ psd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
+ SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL,
+ psa, psize);
+ }
+
+ if (!psd) {
+ DEBUG(0,("get_share_security: Failed to make SEC_DESC.\n"));
+ return NULL;
+ }
+
+ return psd;
+}
+
+/*******************************************************************
+ Pull a security descriptor from the share tdb.
+ ********************************************************************/
+
+SEC_DESC *get_share_security( TALLOC_CTX *ctx, const char *servicename,
+ size_t *psize)
+{
+ char *key;
+ SEC_DESC *psd = NULL;
+ TDB_DATA data;
+ NTSTATUS status;
+
+ if (!share_info_db_init()) {
+ return NULL;
+ }
+
+ if (!(key = talloc_asprintf(ctx, "SECDESC/%s", servicename))) {
+ DEBUG(0, ("talloc_asprintf failed\n"));
+ return NULL;
+ }
+
+ data = dbwrap_fetch_bystring(share_db, talloc_tos(), key);
+
+ TALLOC_FREE(key);
+
+ if (data.dptr == NULL) {
+ return get_share_security_default(ctx, psize,
+ GENERIC_ALL_ACCESS);
+ }
+
+ status = unmarshall_sec_desc(ctx, data.dptr, data.dsize, &psd);
+
+ TALLOC_FREE(data.dptr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("unmarshall_sec_desc failed: %s\n",
+ nt_errstr(status)));
+ return NULL;
+ }
+
+ if (psd)
+ *psize = ndr_size_security_descriptor(psd, 0);
+
+ return psd;
+}
+
+/*******************************************************************
+ Store a security descriptor in the share db.
+ ********************************************************************/
+
+bool set_share_security(const char *share_name, SEC_DESC *psd)
+{
+ TALLOC_CTX *frame;
+ char *key;
+ bool ret = False;
+ TDB_DATA blob;
+ NTSTATUS status;
+
+ if (!share_info_db_init()) {
+ return False;
+ }
+
+ frame = talloc_stackframe();
+
+ status = marshall_sec_desc(frame, psd, &blob.dptr, &blob.dsize);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("marshall_sec_desc failed: %s\n",
+ nt_errstr(status)));
+ goto out;
+ }
+
+ if (!(key = talloc_asprintf(frame, "SECDESC/%s", share_name))) {
+ DEBUG(0, ("talloc_asprintf failed\n"));
+ goto out;
+ }
+
+ status = dbwrap_trans_store(share_db, string_term_tdb_data(key), blob,
+ TDB_REPLACE);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("set_share_security: Failed to store secdesc for "
+ "%s: %s\n", share_name, nt_errstr(status)));
+ goto out;
+ }
+
+ DEBUG(5,("set_share_security: stored secdesc for %s\n", share_name ));
+ ret = True;
+
+ out:
+ TALLOC_FREE(frame);
+ return ret;
+}
+
+/*******************************************************************
+ Delete a security descriptor.
+********************************************************************/
+
+bool delete_share_security(const char *servicename)
+{
+ TDB_DATA kbuf;
+ char *key;
+ NTSTATUS status;
+
+ if (!(key = talloc_asprintf(talloc_tos(), "SECDESC/%s",
+ servicename))) {
+ return False;
+ }
+ kbuf = string_term_tdb_data(key);
+
+ status = dbwrap_trans_delete(share_db, kbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("delete_share_security: Failed to delete entry for "
+ "share %s: %s\n", servicename, nt_errstr(status)));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Can this user access with share with the required permissions ?
+********************************************************************/
+
+bool share_access_check(const NT_USER_TOKEN *token, const char *sharename,
+ uint32 desired_access)
+{
+ uint32 granted;
+ NTSTATUS status;
+ SEC_DESC *psd = NULL;
+ size_t sd_size;
+ bool ret = True;
+
+ psd = get_share_security(talloc_tos(), sharename, &sd_size);
+
+ if (!psd) {
+ return True;
+ }
+
+ ret = se_access_check(psd, token, desired_access, &granted, &status);
+
+ TALLOC_FREE(psd);
+
+ return ret;
+}
+
+/***************************************************************************
+ Parse the contents of an acl string from a usershare file.
+***************************************************************************/
+
+bool parse_usershare_acl(TALLOC_CTX *ctx, const char *acl_str, SEC_DESC **ppsd)
+{
+ size_t s_size = 0;
+ const char *pacl = acl_str;
+ int num_aces = 0;
+ SEC_ACE *ace_list = NULL;
+ SEC_ACL *psa = NULL;
+ SEC_DESC *psd = NULL;
+ size_t sd_size = 0;
+ int i;
+
+ *ppsd = NULL;
+
+ /* If the acl string is blank return "Everyone:R" */
+ if (!*acl_str) {
+ SEC_DESC *default_psd = get_share_security_default(ctx, &s_size, GENERIC_READ_ACCESS);
+ if (!default_psd) {
+ return False;
+ }
+ *ppsd = default_psd;
+ return True;
+ }
+
+ num_aces = 1;
+
+ /* Add the number of ',' characters to get the number of aces. */
+ num_aces += count_chars(pacl,',');
+
+ ace_list = TALLOC_ARRAY(ctx, SEC_ACE, num_aces);
+ if (!ace_list) {
+ return False;
+ }
+
+ for (i = 0; i < num_aces; i++) {
+ SEC_ACCESS sa;
+ uint32 g_access;
+ uint32 s_access;
+ DOM_SID sid;
+ char *sidstr;
+ enum security_ace_type type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+
+ if (!next_token_talloc(ctx, &pacl, &sidstr, ":")) {
+ DEBUG(0,("parse_usershare_acl: malformed usershare acl looking "
+ "for ':' in string '%s'\n", pacl));
+ return False;
+ }
+
+ if (!string_to_sid(&sid, sidstr)) {
+ DEBUG(0,("parse_usershare_acl: failed to convert %s to sid.\n",
+ sidstr ));
+ return False;
+ }
+
+ switch (*pacl) {
+ case 'F': /* Full Control, ie. R+W */
+ case 'f': /* Full Control, ie. R+W */
+ s_access = g_access = GENERIC_ALL_ACCESS;
+ break;
+ case 'R': /* Read only. */
+ case 'r': /* Read only. */
+ s_access = g_access = GENERIC_READ_ACCESS;
+ break;
+ case 'D': /* Deny all to this SID. */
+ case 'd': /* Deny all to this SID. */
+ type = SEC_ACE_TYPE_ACCESS_DENIED;
+ s_access = g_access = GENERIC_ALL_ACCESS;
+ break;
+ default:
+ DEBUG(0,("parse_usershare_acl: unknown acl type at %s.\n",
+ pacl ));
+ return False;
+ }
+
+ pacl++;
+ if (*pacl && *pacl != ',') {
+ DEBUG(0,("parse_usershare_acl: bad acl string at %s.\n",
+ pacl ));
+ return False;
+ }
+ pacl++; /* Go past any ',' */
+
+ se_map_generic(&s_access, &file_generic_mapping);
+ init_sec_access(&sa, g_access | s_access );
+ init_sec_ace(&ace_list[i], &sid, type, sa, 0);
+ }
+
+ if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, num_aces, ace_list)) != NULL) {
+ psd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
+ SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL,
+ psa, &sd_size);
+ }
+
+ if (!psd) {
+ DEBUG(0,("parse_usershare_acl: Failed to make SEC_DESC.\n"));
+ return False;
+ }
+
+ *ppsd = psd;
+ return True;
+}
diff --git a/source3/lib/signal.c b/source3/lib/signal.c
new file mode 100644
index 0000000000..4b1c95eb77
--- /dev/null
+++ b/source3/lib/signal.c
@@ -0,0 +1,138 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Catch child exits and reap the child zombie status.
+****************************************************************************/
+
+static void sig_cld(int signum)
+{
+ while (sys_waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0)
+ ;
+
+ /*
+ * Turns out it's *really* important not to
+ * restore the signal handler here if we have real POSIX
+ * signal handling. If we do, then we get the signal re-delivered
+ * immediately - hey presto - instant loop ! JRA.
+ */
+
+#if !defined(HAVE_SIGACTION)
+ CatchSignal(SIGCLD, sig_cld);
+#endif
+}
+
+/****************************************************************************
+catch child exits - leave status;
+****************************************************************************/
+
+static void sig_cld_leave_status(int signum)
+{
+ /*
+ * Turns out it's *really* important not to
+ * restore the signal handler here if we have real POSIX
+ * signal handling. If we do, then we get the signal re-delivered
+ * immediately - hey presto - instant loop ! JRA.
+ */
+
+#if !defined(HAVE_SIGACTION)
+ CatchSignal(SIGCLD, sig_cld_leave_status);
+#endif
+}
+
+/*******************************************************************
+ Block sigs.
+********************************************************************/
+
+void BlockSignals(bool block,int signum)
+{
+#ifdef HAVE_SIGPROCMASK
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set,signum);
+ sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL);
+#elif defined(HAVE_SIGBLOCK)
+ if (block) {
+ sigblock(sigmask(signum));
+ } else {
+ sigsetmask(siggetmask() & ~sigmask(signum));
+ }
+#else
+ /* yikes! This platform can't block signals? */
+ static int done;
+ if (!done) {
+ DEBUG(0,("WARNING: No signal blocking available\n"));
+ done=1;
+ }
+#endif
+}
+
+/*******************************************************************
+ Catch a signal. This should implement the following semantics:
+
+ 1) The handler remains installed after being called.
+ 2) The signal should be blocked during handler execution.
+********************************************************************/
+
+void (*CatchSignal(int signum,void (*handler)(int )))(int)
+{
+#ifdef HAVE_SIGACTION
+ struct sigaction act;
+ struct sigaction oldact;
+
+ ZERO_STRUCT(act);
+
+ act.sa_handler = handler;
+#ifdef SA_RESTART
+ /*
+ * We *want* SIGALRM to interrupt a system call.
+ */
+ if(signum != SIGALRM)
+ act.sa_flags = SA_RESTART;
+#endif
+ sigemptyset(&act.sa_mask);
+ sigaddset(&act.sa_mask,signum);
+ sigaction(signum,&act,&oldact);
+ return oldact.sa_handler;
+#else /* !HAVE_SIGACTION */
+ /* FIXME: need to handle sigvec and systems with broken signal() */
+ return signal(signum, handler);
+#endif
+}
+
+/*******************************************************************
+ Ignore SIGCLD via whatever means is necessary for this OS.
+********************************************************************/
+
+void CatchChild(void)
+{
+ CatchSignal(SIGCLD, sig_cld);
+}
+
+/*******************************************************************
+ Catch SIGCLD but leave the child around so it's status can be reaped.
+********************************************************************/
+
+void CatchChildLeaveStatus(void)
+{
+ CatchSignal(SIGCLD, sig_cld_leave_status);
+}
diff --git a/source3/lib/smbconf/smbconf.c b/source3/lib/smbconf/smbconf.c
new file mode 100644
index 0000000000..1a9b4e07f9
--- /dev/null
+++ b/source3/lib/smbconf/smbconf.c
@@ -0,0 +1,388 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libsmbconf - Samba configuration library
+ * Copyright (C) Michael Adam 2007-2008
+ * Copyright (C) Guenther Deschner 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "smbconf_private.h"
+
+/**********************************************************************
+ *
+ * internal helper functions
+ *
+ **********************************************************************/
+
+static WERROR smbconf_global_check(struct smbconf_ctx *ctx)
+{
+ if (!smbconf_share_exists(ctx, GLOBAL_NAME)) {
+ return smbconf_create_share(ctx, GLOBAL_NAME);
+ }
+ return WERR_OK;
+}
+
+
+/**********************************************************************
+ *
+ * The actual libsmbconf API functions that are exported.
+ *
+ **********************************************************************/
+
+/**
+ * Close the configuration.
+ */
+void smbconf_shutdown(struct smbconf_ctx *ctx)
+{
+ TALLOC_FREE(ctx);
+}
+
+/**
+ * Detect changes in the configuration.
+ * The given csn struct is filled with the current csn.
+ * smbconf_changed() can also be used for initial retrieval
+ * of the csn.
+ */
+bool smbconf_changed(struct smbconf_ctx *ctx, struct smbconf_csn *csn,
+ const char *service, const char *param)
+{
+ struct smbconf_csn old_csn;
+
+ if (csn == NULL) {
+ return false;
+ }
+
+ old_csn = *csn;
+
+ ctx->ops->get_csn(ctx, csn, service, param);
+ return (csn->csn != old_csn.csn);
+}
+
+/**
+ * Drop the whole configuration (restarting empty).
+ */
+WERROR smbconf_drop(struct smbconf_ctx *ctx)
+{
+ return ctx->ops->drop(ctx);
+}
+
+/**
+ * Get the whole configuration as lists of strings with counts:
+ *
+ * num_shares : number of shares
+ * share_names : list of length num_shares of share names
+ * num_params : list of length num_shares of parameter counts for each share
+ * param_names : list of lists of parameter names for each share
+ * param_values : list of lists of parameter values for each share
+ */
+WERROR smbconf_get_config(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_shares,
+ struct smbconf_service ***services)
+{
+ WERROR werr = WERR_OK;
+ TALLOC_CTX *tmp_ctx = NULL;
+ uint32_t tmp_num_shares;
+ char **tmp_share_names;
+ struct smbconf_service **tmp_services;
+ uint32_t count;
+
+ if ((num_shares == NULL) || (services == NULL)) {
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ tmp_ctx = talloc_stackframe();
+
+ werr = smbconf_get_share_names(ctx, tmp_ctx, &tmp_num_shares,
+ &tmp_share_names);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ tmp_services = TALLOC_ARRAY(tmp_ctx, struct smbconf_service *,
+ tmp_num_shares);
+
+ if (tmp_services == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ for (count = 0; count < tmp_num_shares; count++) {
+ werr = smbconf_get_share(ctx, tmp_services,
+ tmp_share_names[count],
+ &tmp_services[count]);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ }
+
+ werr = WERR_OK;
+
+ *num_shares = tmp_num_shares;
+ if (tmp_num_shares > 0) {
+ *services = talloc_move(mem_ctx, &tmp_services);
+ } else {
+ *services = NULL;
+ }
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+}
+
+/**
+ * get the list of share names defined in the configuration.
+ */
+WERROR smbconf_get_share_names(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_shares,
+ char ***share_names)
+{
+ return ctx->ops->get_share_names(ctx, mem_ctx, num_shares,
+ share_names);
+}
+
+/**
+ * check if a share/service of a given name exists
+ */
+bool smbconf_share_exists(struct smbconf_ctx *ctx,
+ const char *servicename)
+{
+ return ctx->ops->share_exists(ctx, servicename);
+}
+
+/**
+ * Add a service if it does not already exist.
+ */
+WERROR smbconf_create_share(struct smbconf_ctx *ctx,
+ const char *servicename)
+{
+ if ((servicename != NULL) && smbconf_share_exists(ctx, servicename)) {
+ return WERR_ALREADY_EXISTS;
+ }
+
+ return ctx->ops->create_share(ctx, servicename);
+}
+
+/**
+ * get a definition of a share (service) from configuration.
+ */
+WERROR smbconf_get_share(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *servicename,
+ struct smbconf_service **service)
+{
+ if (!smbconf_share_exists(ctx, servicename)) {
+ return WERR_NO_SUCH_SERVICE;
+ }
+
+ return ctx->ops->get_share(ctx, mem_ctx, servicename, service);
+}
+
+/**
+ * delete a service from configuration
+ */
+WERROR smbconf_delete_share(struct smbconf_ctx *ctx, const char *servicename)
+{
+ if (!smbconf_share_exists(ctx, servicename)) {
+ return WERR_NO_SUCH_SERVICE;
+ }
+
+ return ctx->ops->delete_share(ctx, servicename);
+}
+
+/**
+ * set a configuration parameter to the value provided.
+ */
+WERROR smbconf_set_parameter(struct smbconf_ctx *ctx,
+ const char *service,
+ const char *param,
+ const char *valstr)
+{
+ if (!smbconf_share_exists(ctx, service)) {
+ return WERR_NO_SUCH_SERVICE;
+ }
+
+ return ctx->ops->set_parameter(ctx, service, param, valstr);
+}
+
+/**
+ * Set a global parameter
+ * (i.e. a parameter in the [global] service).
+ *
+ * This also creates [global] when it does not exist.
+ */
+WERROR smbconf_set_global_parameter(struct smbconf_ctx *ctx,
+ const char *param, const char *val)
+{
+ WERROR werr;
+
+ werr = smbconf_global_check(ctx);
+ if (W_ERROR_IS_OK(werr)) {
+ werr = smbconf_set_parameter(ctx, GLOBAL_NAME, param, val);
+ }
+
+ return werr;
+}
+
+/**
+ * get the value of a configuration parameter as a string
+ */
+WERROR smbconf_get_parameter(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ const char *param,
+ char **valstr)
+{
+ if (valstr == NULL) {
+ return WERR_INVALID_PARAM;
+ }
+
+ if (!smbconf_share_exists(ctx, service)) {
+ return WERR_NO_SUCH_SERVICE;
+ }
+
+ return ctx->ops->get_parameter(ctx, mem_ctx, service, param, valstr);
+}
+
+/**
+ * Get the value of a global parameter.
+ *
+ * Create [global] if it does not exist.
+ */
+WERROR smbconf_get_global_parameter(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *param,
+ char **valstr)
+{
+ WERROR werr;
+
+ werr = smbconf_global_check(ctx);
+ if (W_ERROR_IS_OK(werr)) {
+ werr = smbconf_get_parameter(ctx, mem_ctx, GLOBAL_NAME, param,
+ valstr);
+ }
+
+ return werr;
+}
+
+/**
+ * delete a parameter from configuration
+ */
+WERROR smbconf_delete_parameter(struct smbconf_ctx *ctx,
+ const char *service, const char *param)
+{
+ if (!smbconf_share_exists(ctx, service)) {
+ return WERR_NO_SUCH_SERVICE;
+ }
+
+ return ctx->ops->delete_parameter(ctx, service, param);
+}
+
+/**
+ * Delete a global parameter.
+ *
+ * Create [global] if it does not exist.
+ */
+WERROR smbconf_delete_global_parameter(struct smbconf_ctx *ctx,
+ const char *param)
+{
+ WERROR werr;
+
+ werr = smbconf_global_check(ctx);
+ if (W_ERROR_IS_OK(werr)) {
+ werr = smbconf_delete_parameter(ctx, GLOBAL_NAME, param);
+ }
+
+ return werr;
+}
+
+WERROR smbconf_get_includes(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ uint32_t *num_includes, char ***includes)
+{
+ if (!smbconf_share_exists(ctx, service)) {
+ return WERR_NO_SUCH_SERVICE;
+ }
+
+ return ctx->ops->get_includes(ctx, mem_ctx, service, num_includes,
+ includes);
+}
+
+WERROR smbconf_get_global_includes(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_includes, char ***includes)
+{
+ WERROR werr;
+
+ werr = smbconf_global_check(ctx);
+ if (W_ERROR_IS_OK(werr)) {
+ werr = smbconf_get_includes(ctx, mem_ctx, GLOBAL_NAME,
+ num_includes, includes);
+ }
+
+ return werr;
+}
+
+WERROR smbconf_set_includes(struct smbconf_ctx *ctx,
+ const char *service,
+ uint32_t num_includes, const char **includes)
+{
+ if (!smbconf_share_exists(ctx, service)) {
+ return WERR_NO_SUCH_SERVICE;
+ }
+
+ return ctx->ops->set_includes(ctx, service, num_includes, includes);
+}
+
+WERROR smbconf_set_global_includes(struct smbconf_ctx *ctx,
+ uint32_t num_includes,
+ const char **includes)
+{
+ WERROR werr;
+
+ werr = smbconf_global_check(ctx);
+ if (W_ERROR_IS_OK(werr)) {
+ werr = smbconf_set_includes(ctx, GLOBAL_NAME,
+ num_includes, includes);
+ }
+
+ return werr;
+}
+
+
+WERROR smbconf_delete_includes(struct smbconf_ctx *ctx, const char *service)
+{
+ if (!smbconf_share_exists(ctx, service)) {
+ return WERR_NO_SUCH_SERVICE;
+ }
+
+ return ctx->ops->delete_includes(ctx, service);
+}
+
+WERROR smbconf_delete_global_includes(struct smbconf_ctx *ctx)
+{
+ WERROR werr;
+
+ werr = smbconf_global_check(ctx);
+ if (W_ERROR_IS_OK(werr)) {
+ werr = smbconf_delete_includes(ctx, GLOBAL_NAME);
+ }
+
+ return werr;
+}
diff --git a/source3/lib/smbconf/smbconf.h b/source3/lib/smbconf/smbconf.h
new file mode 100644
index 0000000000..e337476665
--- /dev/null
+++ b/source3/lib/smbconf/smbconf.h
@@ -0,0 +1,114 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libsmbconf - Samba configuration library
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIBSMBCONF_H__
+#define __LIBSMBCONF_H__
+
+struct smbconf_ctx;
+
+/* the change sequence number */
+struct smbconf_csn {
+ uint64_t csn;
+};
+
+struct smbconf_service {
+ char *name;
+ uint32_t num_params;
+ char **param_names;
+ char **param_values;
+};
+
+
+/**
+ * intialization dispatcher function.
+ * takes source string in the form of "backend:path"
+ */
+WERROR smbconf_init(TALLOC_CTX *mem_ctx, struct smbconf_ctx **conf_ctx,
+ const char *source);
+
+/**
+ * initialization functions for the available modules
+ */
+
+WERROR smbconf_init_reg(TALLOC_CTX *mem_ctx, struct smbconf_ctx **conf_ctx,
+ const char *path);
+
+WERROR smbconf_init_txt(TALLOC_CTX *mem_ctx,
+ struct smbconf_ctx **conf_ctx,
+ const char *path);
+
+/*
+ * the smbconf API functions
+ */
+void smbconf_shutdown(struct smbconf_ctx *ctx);
+bool smbconf_changed(struct smbconf_ctx *ctx, struct smbconf_csn *csn,
+ const char *service, const char *param);
+WERROR smbconf_drop(struct smbconf_ctx *ctx);
+WERROR smbconf_get_config(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_shares,
+ struct smbconf_service ***services);
+WERROR smbconf_get_share_names(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_shares,
+ char ***share_names);
+bool smbconf_share_exists(struct smbconf_ctx *ctx, const char *servicename);
+WERROR smbconf_create_share(struct smbconf_ctx *ctx, const char *servicename);
+WERROR smbconf_get_share(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *servicename,
+ struct smbconf_service **service);
+WERROR smbconf_delete_share(struct smbconf_ctx *ctx,
+ const char *servicename);
+WERROR smbconf_set_parameter(struct smbconf_ctx *ctx,
+ const char *service,
+ const char *param,
+ const char *valstr);
+WERROR smbconf_set_global_parameter(struct smbconf_ctx *ctx,
+ const char *param, const char *val);
+WERROR smbconf_get_parameter(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ const char *param,
+ char **valstr);
+WERROR smbconf_get_global_parameter(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *param,
+ char **valstr);
+WERROR smbconf_delete_parameter(struct smbconf_ctx *ctx,
+ const char *service, const char *param);
+WERROR smbconf_delete_global_parameter(struct smbconf_ctx *ctx,
+ const char *param);
+WERROR smbconf_get_includes(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ uint32_t *num_includes, char ***includes);
+WERROR smbconf_get_global_includes(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_includes, char ***includes);
+WERROR smbconf_set_includes(struct smbconf_ctx *ctx,
+ const char *service,
+ uint32_t num_includes, const char **includes);
+WERROR smbconf_set_global_includes(struct smbconf_ctx *ctx,
+ uint32_t num_includes,
+ const char **includes);
+WERROR smbconf_delete_includes(struct smbconf_ctx *ctx, const char *service);
+WERROR smbconf_delete_global_includes(struct smbconf_ctx *ctx);
+
+#endif /* _LIBSMBCONF_H_ */
diff --git a/source3/lib/smbconf/smbconf_init.c b/source3/lib/smbconf/smbconf_init.c
new file mode 100644
index 0000000000..4efc440819
--- /dev/null
+++ b/source3/lib/smbconf/smbconf_init.c
@@ -0,0 +1,95 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libsmbconf - Samba configuration library, init dispatcher
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "smbconf_private.h"
+
+#define INCLUDES_VALNAME "includes"
+
+
+/**
+ * smbconf initialization dispatcher
+ *
+ * this takes a configuration source in the form of
+ * backend:path and calles the appropriate backend
+ * init function with the path argument
+ *
+ * known backends:
+ * - "registry" or "reg"
+ * - "txt" or "file"
+ */
+WERROR smbconf_init(TALLOC_CTX *mem_ctx, struct smbconf_ctx **conf_ctx,
+ const char *source)
+{
+ WERROR werr;
+ char *backend = NULL;
+ char *path = NULL;
+ char *sep;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ if (conf_ctx == NULL) {
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ if ((source == NULL) || (*source == '\0')) {
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ backend = talloc_strdup(tmp_ctx, source);
+ if (backend == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ sep = strchr(backend, ':');
+ if (sep != NULL) {
+ *sep = '\0';
+ path = sep + 1;
+ if (strlen(path) == 0) {
+ path = NULL;
+ }
+ }
+
+ if (strequal(backend, "registry") || strequal(backend, "reg")) {
+ werr = smbconf_init_reg(mem_ctx, conf_ctx, path);
+ } else if (strequal(backend, "file") || strequal(backend, "txt")) {
+ werr = smbconf_init_txt(mem_ctx, conf_ctx, path);
+ } else if (sep == NULL) {
+ /*
+ * If no separator was given in the source, and the string is
+ * not a know backend, assume file backend and use the source
+ * string as a path argument.
+ */
+ werr = smbconf_init_txt(mem_ctx, conf_ctx, backend);
+ } else {
+ /*
+ * Separator was specified but this is not a known backend.
+ * Can't handle this.
+ */
+ DEBUG(1, ("smbconf_init: ERROR - unknown backend '%s' given\n",
+ backend));
+ werr = WERR_INVALID_PARAM;
+ }
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+}
diff --git a/source3/lib/smbconf/smbconf_private.h b/source3/lib/smbconf/smbconf_private.h
new file mode 100644
index 0000000000..8e7d6a9983
--- /dev/null
+++ b/source3/lib/smbconf/smbconf_private.h
@@ -0,0 +1,85 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libsmbconf - Samba configuration library
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIBSMBCONF_PRIVATE_H__
+#define __LIBSMBCONF_PRIVATE_H__
+
+struct smbconf_ops {
+ WERROR (*init)(struct smbconf_ctx *ctx, const char *path);
+ int (*shutdown)(struct smbconf_ctx *ctx);
+ WERROR (*open_conf)(struct smbconf_ctx *ctx);
+ int (*close_conf)(struct smbconf_ctx *ctx);
+ void (*get_csn)(struct smbconf_ctx *ctx, struct smbconf_csn *csn,
+ const char *service, const char *param);
+ WERROR (*drop)(struct smbconf_ctx *ctx);
+ WERROR (*get_share_names)(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_shares,
+ char ***share_names);
+ bool (*share_exists)(struct smbconf_ctx *ctx, const char *service);
+ WERROR (*create_share)(struct smbconf_ctx *ctx, const char *service);
+ WERROR (*get_share)(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *servicename,
+ struct smbconf_service **service);
+ WERROR (*delete_share)(struct smbconf_ctx *ctx,
+ const char *servicename);
+ WERROR (*set_parameter)(struct smbconf_ctx *ctx,
+ const char *service,
+ const char *param,
+ const char *valstr);
+ WERROR (*get_parameter)(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ const char *param,
+ char **valstr);
+ WERROR (*delete_parameter)(struct smbconf_ctx *ctx,
+ const char *service, const char *param);
+ WERROR (*get_includes)(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ uint32_t *num_includes, char ***includes);
+ WERROR (*set_includes)(struct smbconf_ctx *ctx,
+ const char *service,
+ uint32_t num_includes, const char **includes);
+ WERROR (*delete_includes)(struct smbconf_ctx *ctx,
+ const char *service);
+};
+
+struct smbconf_ctx {
+ const char *path;
+ struct smbconf_ops *ops;
+ void *data; /* private data for use in backends */
+};
+
+WERROR smbconf_init_internal(TALLOC_CTX *mem_ctx, struct smbconf_ctx **conf_ctx,
+ const char *path, struct smbconf_ops *ops);
+
+WERROR smbconf_add_string_to_array(TALLOC_CTX *mem_ctx,
+ char ***array,
+ uint32_t count,
+ const char *string);
+
+bool smbconf_find_in_array(const char *string, char **list,
+ uint32_t num_entries, uint32_t *entry);
+
+bool smbconf_reverse_find_in_array(const char *string, char **list,
+ uint32_t num_entries, uint32_t *entry);
+
+#endif
diff --git a/source3/lib/smbconf/smbconf_reg.c b/source3/lib/smbconf/smbconf_reg.c
new file mode 100644
index 0000000000..033f800e2a
--- /dev/null
+++ b/source3/lib/smbconf/smbconf_reg.c
@@ -0,0 +1,1148 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libsmbconf - Samba configuration library, registry backend
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "smbconf_private.h"
+
+#define INCLUDES_VALNAME "includes"
+
+struct reg_private_data {
+ NT_USER_TOKEN *token;
+ bool open; /* did _we_ open the registry? */
+};
+
+/**********************************************************************
+ *
+ * helper functions
+ *
+ **********************************************************************/
+
+/**
+ * a convenience helper to cast the private data structure
+ */
+static struct reg_private_data *rpd(struct smbconf_ctx *ctx)
+{
+ return (struct reg_private_data *)(ctx->data);
+}
+
+/*
+ * check whether a given value name is forbidden in registry (smbconf)
+ */
+static bool smbconf_reg_valname_forbidden(const char *valname)
+{
+ /* hard code the list of forbidden names here for now */
+ const char *forbidden_valnames[] = {
+ "lock directory",
+ "lock dir",
+ "config backend",
+ "include",
+ "includes", /* this has a special meaning internally */
+ NULL
+ };
+ const char **forbidden = NULL;
+
+ for (forbidden = forbidden_valnames; *forbidden != NULL; forbidden++) {
+ if (strwicmp(valname, *forbidden) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool smbconf_reg_valname_valid(const char *valname)
+{
+ return (!smbconf_reg_valname_forbidden(valname) &&
+ lp_parameter_is_valid(valname));
+}
+
+/**
+ * Open a registry key specified by "path"
+ */
+static WERROR smbconf_reg_open_path(TALLOC_CTX *mem_ctx,
+ struct smbconf_ctx *ctx,
+ const char *path,
+ uint32 desired_access,
+ struct registry_key **key)
+{
+ WERROR werr = WERR_OK;
+
+ if (ctx == NULL) {
+ DEBUG(1, ("Error: configuration is not open!\n"));
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ if (rpd(ctx)->token == NULL) {
+ DEBUG(1, ("Error: token missing from smbconf_ctx. "
+ "was smbconf_init() called?\n"));
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ werr = ctx->ops->open_conf(ctx);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(1, ("Error opening the registry.\n"));
+ goto done;
+ }
+
+ if (path == NULL) {
+ DEBUG(1, ("Error: NULL path string given\n"));
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ werr = reg_open_path(mem_ctx, path, desired_access, rpd(ctx)->token,
+ key);
+
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(5, ("Error opening registry path '%s': %s\n",
+ path, dos_errstr(werr)));
+ }
+
+done:
+ return werr;
+}
+
+/**
+ * Open a subkey of the base key (i.e a service)
+ */
+static WERROR smbconf_reg_open_service_key(TALLOC_CTX *mem_ctx,
+ struct smbconf_ctx *ctx,
+ const char *servicename,
+ uint32 desired_access,
+ struct registry_key **key)
+{
+ WERROR werr = WERR_OK;
+ char *path = NULL;
+
+ if (servicename == NULL) {
+ path = talloc_strdup(mem_ctx, ctx->path);
+ } else {
+ path = talloc_asprintf(mem_ctx, "%s\\%s", ctx->path,
+ servicename);
+ }
+ if (path == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ werr = smbconf_reg_open_path(mem_ctx, ctx, path, desired_access, key);
+
+done:
+ TALLOC_FREE(path);
+ return werr;
+}
+
+/**
+ * open the base key
+ */
+static WERROR smbconf_reg_open_base_key(TALLOC_CTX *mem_ctx,
+ struct smbconf_ctx *ctx,
+ uint32 desired_access,
+ struct registry_key **key)
+{
+ return smbconf_reg_open_path(mem_ctx, ctx, ctx->path, desired_access,
+ key);
+}
+
+/**
+ * check if a value exists in a given registry key
+ */
+static bool smbconf_value_exists(struct registry_key *key, const char *param)
+{
+ bool ret = false;
+ WERROR werr = WERR_OK;
+ TALLOC_CTX *ctx = talloc_stackframe();
+ struct registry_value *value = NULL;
+
+ werr = reg_queryvalue(ctx, key, param, &value);
+ if (W_ERROR_IS_OK(werr)) {
+ ret = true;
+ }
+
+ TALLOC_FREE(ctx);
+ return ret;
+}
+
+/**
+ * create a subkey of the base key (i.e. a service...)
+ */
+static WERROR smbconf_reg_create_service_key(TALLOC_CTX *mem_ctx,
+ struct smbconf_ctx *ctx,
+ const char * subkeyname,
+ struct registry_key **newkey)
+{
+ WERROR werr = WERR_OK;
+ struct registry_key *create_parent = NULL;
+ TALLOC_CTX *create_ctx;
+ enum winreg_CreateAction action = REG_ACTION_NONE;
+
+ /* create a new talloc ctx for creation. it will hold
+ * the intermediate parent key (SMBCONF) for creation
+ * and will be destroyed when leaving this function... */
+ create_ctx = talloc_stackframe();
+
+ werr = smbconf_reg_open_base_key(create_ctx, ctx, REG_KEY_WRITE,
+ &create_parent);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = reg_createkey(mem_ctx, create_parent, subkeyname,
+ REG_KEY_WRITE, newkey, &action);
+ if (W_ERROR_IS_OK(werr) && (action != REG_CREATED_NEW_KEY)) {
+ DEBUG(10, ("Key '%s' already exists.\n", subkeyname));
+ werr = WERR_ALREADY_EXISTS;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(5, ("Error creating key %s: %s\n",
+ subkeyname, dos_errstr(werr)));
+ }
+
+done:
+ TALLOC_FREE(create_ctx);
+ return werr;
+}
+
+/**
+ * add a value to a key.
+ */
+static WERROR smbconf_reg_set_value(struct registry_key *key,
+ const char *valname,
+ const char *valstr)
+{
+ struct registry_value val;
+ WERROR werr = WERR_OK;
+ char *subkeyname;
+ const char *canon_valname;
+ const char *canon_valstr;
+
+ if (!lp_canonicalize_parameter_with_value(valname, valstr,
+ &canon_valname,
+ &canon_valstr))
+ {
+ if (canon_valname == NULL) {
+ DEBUG(5, ("invalid parameter '%s' given\n",
+ valname));
+ } else {
+ DEBUG(5, ("invalid value '%s' given for "
+ "parameter '%s'\n", valstr, valname));
+ }
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ if (smbconf_reg_valname_forbidden(canon_valname)) {
+ DEBUG(5, ("Parameter '%s' not allowed in registry.\n",
+ canon_valname));
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ subkeyname = strrchr_m(key->key->name, '\\');
+ if ((subkeyname == NULL) || (*(subkeyname +1) == '\0')) {
+ DEBUG(5, ("Invalid registry key '%s' given as "
+ "smbconf section.\n", key->key->name));
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+ subkeyname++;
+ if (!strequal(subkeyname, GLOBAL_NAME) &&
+ lp_parameter_is_global(valname))
+ {
+ DEBUG(5, ("Global paramter '%s' not allowed in "
+ "service definition ('%s').\n", canon_valname,
+ subkeyname));
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ ZERO_STRUCT(val);
+
+ val.type = REG_SZ;
+ val.v.sz.str = CONST_DISCARD(char *, canon_valstr);
+ val.v.sz.len = strlen(canon_valstr) + 1;
+
+ werr = reg_setvalue(key, canon_valname, &val);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(5, ("Error adding value '%s' to "
+ "key '%s': %s\n",
+ canon_valname, key->key->name, dos_errstr(werr)));
+ }
+
+done:
+ return werr;
+}
+
+static WERROR smbconf_reg_set_multi_sz_value(struct registry_key *key,
+ const char *valname,
+ const uint32_t num_strings,
+ const char **strings)
+{
+ WERROR werr;
+ struct registry_value *value;
+ uint32_t count;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ if (strings == NULL) {
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ value = TALLOC_ZERO_P(tmp_ctx, struct registry_value);
+
+ value->type = REG_MULTI_SZ;
+ value->v.multi_sz.num_strings = num_strings;
+ value->v.multi_sz.strings = TALLOC_ARRAY(tmp_ctx, char *, num_strings);
+ if (value->v.multi_sz.strings == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+ for (count = 0; count < num_strings; count++) {
+ value->v.multi_sz.strings[count] =
+ talloc_strdup(value->v.multi_sz.strings,
+ strings[count]);
+ if (value->v.multi_sz.strings[count] == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+ }
+
+ werr = reg_setvalue(key, valname, value);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(5, ("Error adding value '%s' to key '%s': %s\n",
+ valname, key->key->name, dos_errstr(werr)));
+ }
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+}
+
+/**
+ * format a registry_value into a string.
+ *
+ * This is intended to be used for smbconf registry values,
+ * which are ar stored as REG_SZ values, so the incomplete
+ * handling should be ok.
+ */
+static char *smbconf_format_registry_value(TALLOC_CTX *mem_ctx,
+ struct registry_value *value)
+{
+ char *result = NULL;
+
+ /* alternatively, create a new talloc context? */
+ if (mem_ctx == NULL) {
+ return result;
+ }
+
+ switch (value->type) {
+ case REG_DWORD:
+ result = talloc_asprintf(mem_ctx, "%d", value->v.dword);
+ break;
+ case REG_SZ:
+ case REG_EXPAND_SZ:
+ result = talloc_asprintf(mem_ctx, "%s", value->v.sz.str);
+ break;
+ case REG_MULTI_SZ: {
+ uint32 j;
+ for (j = 0; j < value->v.multi_sz.num_strings; j++) {
+ result = talloc_asprintf(mem_ctx, "%s\"%s\" ",
+ result ? result : "" ,
+ value->v.multi_sz.strings[j]);
+ if (result == NULL) {
+ break;
+ }
+ }
+ break;
+ }
+ case REG_BINARY:
+ result = talloc_asprintf(mem_ctx, "binary (%d bytes)",
+ (int)value->v.binary.length);
+ break;
+ default:
+ result = talloc_asprintf(mem_ctx, "<unprintable>");
+ break;
+ }
+ return result;
+}
+
+static WERROR smbconf_reg_get_includes_internal(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ uint32_t *num_includes,
+ char ***includes)
+{
+ WERROR werr;
+ uint32_t count;
+ struct registry_value *value = NULL;
+ char **tmp_includes = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ if (!smbconf_value_exists(key, INCLUDES_VALNAME)) {
+ /* no includes */
+ *num_includes = 0;
+ *includes = NULL;
+ werr = WERR_OK;
+ goto done;
+ }
+
+ werr = reg_queryvalue(tmp_ctx, key, INCLUDES_VALNAME, &value);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ if (value->type != REG_MULTI_SZ) {
+ /* wront type -- ignore */
+ goto done;
+ }
+
+ for (count = 0; count < value->v.multi_sz.num_strings; count++)
+ {
+ werr = smbconf_add_string_to_array(tmp_ctx,
+ &tmp_includes,
+ count,
+ value->v.multi_sz.strings[count]);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ }
+
+ if (count > 0) {
+ *includes = talloc_move(mem_ctx, &tmp_includes);
+ if (*includes == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+ *num_includes = count;
+ } else {
+ *num_includes = 0;
+ *includes = NULL;
+ }
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+}
+
+/**
+ * Get the values of a key as a list of value names
+ * and a list of value strings (ordered)
+ */
+static WERROR smbconf_reg_get_values(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ uint32_t *num_values,
+ char ***value_names,
+ char ***value_strings)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ WERROR werr = WERR_OK;
+ uint32_t count;
+ struct registry_value *valvalue = NULL;
+ char *valname = NULL;
+ uint32_t tmp_num_values = 0;
+ char **tmp_valnames = NULL;
+ char **tmp_valstrings = NULL;
+ uint32_t num_includes = 0;
+ char **includes = NULL;
+
+ if ((num_values == NULL) || (value_names == NULL) ||
+ (value_strings == NULL))
+ {
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ tmp_ctx = talloc_stackframe();
+
+ for (count = 0;
+ werr = reg_enumvalue(tmp_ctx, key, count, &valname, &valvalue),
+ W_ERROR_IS_OK(werr);
+ count++)
+ {
+ char *valstring;
+
+ if (!smbconf_reg_valname_valid(valname)) {
+ continue;
+ }
+
+ werr = smbconf_add_string_to_array(tmp_ctx,
+ &tmp_valnames,
+ tmp_num_values, valname);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ valstring = smbconf_format_registry_value(tmp_ctx, valvalue);
+ werr = smbconf_add_string_to_array(tmp_ctx, &tmp_valstrings,
+ tmp_num_values, valstring);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ tmp_num_values++;
+ }
+ if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
+ goto done;
+ }
+
+ /* now add the includes at the end */
+ werr = smbconf_reg_get_includes_internal(tmp_ctx, key, &num_includes,
+ &includes);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ for (count = 0; count < num_includes; count++) {
+ werr = smbconf_add_string_to_array(tmp_ctx, &tmp_valnames,
+ tmp_num_values, "include");
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = smbconf_add_string_to_array(tmp_ctx, &tmp_valstrings,
+ tmp_num_values,
+ includes[count]);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ tmp_num_values++;
+ }
+
+ *num_values = tmp_num_values;
+ if (tmp_num_values > 0) {
+ *value_names = talloc_move(mem_ctx, &tmp_valnames);
+ *value_strings = talloc_move(mem_ctx, &tmp_valstrings);
+ } else {
+ *value_names = NULL;
+ *value_strings = NULL;
+ }
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+}
+
+static bool smbconf_reg_key_has_values(struct registry_key *key)
+{
+ WERROR werr;
+ uint32_t num_subkeys;
+ uint32_t max_subkeylen;
+ uint32_t max_subkeysize;
+ uint32_t num_values;
+ uint32_t max_valnamelen;
+ uint32_t max_valbufsize;
+ uint32_t secdescsize;
+ NTTIME last_changed_time;
+
+ werr = reg_queryinfokey(key, &num_subkeys, &max_subkeylen,
+ &max_subkeysize, &num_values, &max_valnamelen,
+ &max_valbufsize, &secdescsize,
+ &last_changed_time);
+ if (!W_ERROR_IS_OK(werr)) {
+ return false;
+ }
+
+ return (num_values != 0);
+}
+
+/**
+ * delete all values from a key
+ */
+static WERROR smbconf_reg_delete_values(struct registry_key *key)
+{
+ WERROR werr;
+ char *valname;
+ struct registry_value *valvalue;
+ uint32_t count;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ for (count = 0;
+ werr = reg_enumvalue(mem_ctx, key, count, &valname, &valvalue),
+ W_ERROR_IS_OK(werr);
+ count++)
+ {
+ werr = reg_deletevalue(key, valname);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ }
+ if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
+ DEBUG(1, ("smbconf_reg_delete_values: "
+ "Error enumerating values of %s: %s\n",
+ key->key->name,
+ dos_errstr(werr)));
+ goto done;
+ }
+
+ werr = WERR_OK;
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return werr;
+}
+
+/**********************************************************************
+ *
+ * smbconf operations: registry implementations
+ *
+ **********************************************************************/
+
+/**
+ * initialize the registry smbconf backend
+ */
+static WERROR smbconf_reg_init(struct smbconf_ctx *ctx, const char *path)
+{
+ WERROR werr = WERR_OK;
+
+ if (path == NULL) {
+ path = KEY_SMBCONF;
+ }
+ ctx->path = talloc_strdup(ctx, path);
+ if (ctx->path == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ ctx->data = TALLOC_ZERO_P(ctx, struct reg_private_data);
+
+ werr = ntstatus_to_werror(registry_create_admin_token(ctx,
+ &(rpd(ctx)->token)));
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(1, ("Error creating admin token\n"));
+ goto done;
+ }
+ rpd(ctx)->open = false;
+
+ werr = registry_init_smbconf(path);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+done:
+ return werr;
+}
+
+static int smbconf_reg_shutdown(struct smbconf_ctx *ctx)
+{
+ return ctx->ops->close_conf(ctx);
+}
+
+static WERROR smbconf_reg_open(struct smbconf_ctx *ctx)
+{
+ WERROR werr;
+
+ if (rpd(ctx)->open) {
+ return WERR_OK;
+ }
+
+ werr = regdb_open();
+ if (W_ERROR_IS_OK(werr)) {
+ rpd(ctx)->open = true;
+ }
+ return werr;
+}
+
+static int smbconf_reg_close(struct smbconf_ctx *ctx)
+{
+ int ret;
+
+ if (!rpd(ctx)->open) {
+ return 0;
+ }
+
+ ret = regdb_close();
+ if (ret == 0) {
+ rpd(ctx)->open = false;
+ }
+ return ret;
+}
+
+/**
+ * Get the change sequence number of the given service/parameter.
+ * service and parameter strings may be NULL.
+ */
+static void smbconf_reg_get_csn(struct smbconf_ctx *ctx,
+ struct smbconf_csn *csn,
+ const char *service, const char *param)
+{
+ if (csn == NULL) {
+ return;
+ }
+
+ if (!W_ERROR_IS_OK(ctx->ops->open_conf(ctx))) {
+ return;
+ }
+
+ csn->csn = (uint64_t)regdb_get_seqnum();
+}
+
+/**
+ * Drop the whole configuration (restarting empty) - registry version
+ */
+static WERROR smbconf_reg_drop(struct smbconf_ctx *ctx)
+{
+ char *path, *p;
+ WERROR werr = WERR_OK;
+ struct registry_key *parent_key = NULL;
+ struct registry_key *new_key = NULL;
+ TALLOC_CTX* mem_ctx = talloc_stackframe();
+ enum winreg_CreateAction action;
+
+ path = talloc_strdup(mem_ctx, ctx->path);
+ if (path == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+ p = strrchr(path, '\\');
+ *p = '\0';
+ werr = smbconf_reg_open_path(mem_ctx, ctx, path, REG_KEY_WRITE,
+ &parent_key);
+
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = reg_deletekey_recursive(mem_ctx, parent_key, p+1);
+
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = reg_createkey(mem_ctx, parent_key, p+1, REG_KEY_WRITE,
+ &new_key, &action);
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return werr;
+}
+
+/**
+ * get the list of share names defined in the configuration.
+ * registry version.
+ */
+static WERROR smbconf_reg_get_share_names(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_shares,
+ char ***share_names)
+{
+ uint32_t count;
+ uint32_t added_count = 0;
+ TALLOC_CTX *tmp_ctx = NULL;
+ WERROR werr = WERR_OK;
+ struct registry_key *key = NULL;
+ char *subkey_name = NULL;
+ char **tmp_share_names = NULL;
+
+ if ((num_shares == NULL) || (share_names == NULL)) {
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ tmp_ctx = talloc_stackframe();
+
+ /* if there are values in the base key, return NULL as share name */
+ werr = smbconf_reg_open_base_key(tmp_ctx, ctx,
+ SEC_RIGHTS_ENUM_SUBKEYS, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ if (smbconf_reg_key_has_values(key)) {
+ werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
+ 0, NULL);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ added_count++;
+ }
+
+ /* make sure "global" is always listed first */
+ if (smbconf_share_exists(ctx, GLOBAL_NAME)) {
+ werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
+ added_count, GLOBAL_NAME);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ added_count++;
+ }
+
+ for (count = 0;
+ werr = reg_enumkey(tmp_ctx, key, count, &subkey_name, NULL),
+ W_ERROR_IS_OK(werr);
+ count++)
+ {
+ if (strequal(subkey_name, GLOBAL_NAME)) {
+ continue;
+ }
+
+ werr = smbconf_add_string_to_array(tmp_ctx,
+ &tmp_share_names,
+ added_count,
+ subkey_name);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ added_count++;
+ }
+ if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
+ goto done;
+ }
+ werr = WERR_OK;
+
+ *num_shares = added_count;
+ if (added_count > 0) {
+ *share_names = talloc_move(mem_ctx, &tmp_share_names);
+ } else {
+ *share_names = NULL;
+ }
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+}
+
+/**
+ * check if a share/service of a given name exists - registry version
+ */
+static bool smbconf_reg_share_exists(struct smbconf_ctx *ctx,
+ const char *servicename)
+{
+ bool ret = false;
+ WERROR werr = WERR_OK;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+ struct registry_key *key = NULL;
+
+ werr = smbconf_reg_open_service_key(mem_ctx, ctx, servicename,
+ REG_KEY_READ, &key);
+ if (W_ERROR_IS_OK(werr)) {
+ ret = true;
+ }
+
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+/**
+ * Add a service if it does not already exist - registry version
+ */
+static WERROR smbconf_reg_create_share(struct smbconf_ctx *ctx,
+ const char *servicename)
+{
+ WERROR werr;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+ struct registry_key *key = NULL;
+
+ if (servicename == NULL) {
+ werr = smbconf_reg_open_base_key(mem_ctx, ctx, REG_KEY_WRITE,
+ &key);
+ } else {
+ werr = smbconf_reg_create_service_key(mem_ctx, ctx,
+ servicename, &key);
+ }
+
+ TALLOC_FREE(mem_ctx);
+ return werr;
+}
+
+/**
+ * get a definition of a share (service) from configuration.
+ */
+static WERROR smbconf_reg_get_share(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *servicename,
+ struct smbconf_service **service)
+{
+ WERROR werr = WERR_OK;
+ struct registry_key *key = NULL;
+ struct smbconf_service *tmp_service = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ werr = smbconf_reg_open_service_key(tmp_ctx, ctx, servicename,
+ REG_KEY_READ, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ tmp_service = TALLOC_ZERO_P(tmp_ctx, struct smbconf_service);
+ if (tmp_service == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ if (servicename != NULL) {
+ tmp_service->name = talloc_strdup(tmp_service, servicename);
+ if (tmp_service->name == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+ }
+
+ werr = smbconf_reg_get_values(tmp_service, key,
+ &(tmp_service->num_params),
+ &(tmp_service->param_names),
+ &(tmp_service->param_values));
+
+ if (W_ERROR_IS_OK(werr)) {
+ *service = talloc_move(mem_ctx, &tmp_service);
+ }
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+}
+
+/**
+ * delete a service from configuration
+ */
+static WERROR smbconf_reg_delete_share(struct smbconf_ctx *ctx,
+ const char *servicename)
+{
+ WERROR werr = WERR_OK;
+ struct registry_key *key = NULL;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ werr = smbconf_reg_open_base_key(mem_ctx, ctx, REG_KEY_WRITE, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ if (servicename != NULL) {
+ werr = reg_deletekey_recursive(key, key, servicename);
+ } else {
+ werr = smbconf_reg_delete_values(key);
+ }
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return werr;
+}
+
+/**
+ * set a configuration parameter to the value provided.
+ */
+static WERROR smbconf_reg_set_parameter(struct smbconf_ctx *ctx,
+ const char *service,
+ const char *param,
+ const char *valstr)
+{
+ WERROR werr;
+ struct registry_key *key = NULL;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ werr = smbconf_reg_open_service_key(mem_ctx, ctx, service,
+ REG_KEY_WRITE, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = smbconf_reg_set_value(key, param, valstr);
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return werr;
+}
+
+/**
+ * get the value of a configuration parameter as a string
+ */
+static WERROR smbconf_reg_get_parameter(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ const char *param,
+ char **valstr)
+{
+ WERROR werr = WERR_OK;
+ struct registry_key *key = NULL;
+ struct registry_value *value = NULL;
+
+ werr = smbconf_reg_open_service_key(mem_ctx, ctx, service,
+ REG_KEY_READ, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ if (!smbconf_reg_valname_valid(param)) {
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ if (!smbconf_value_exists(key, param)) {
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ werr = reg_queryvalue(mem_ctx, key, param, &value);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ *valstr = smbconf_format_registry_value(mem_ctx, value);
+
+ if (*valstr == NULL) {
+ werr = WERR_NOMEM;
+ }
+
+done:
+ TALLOC_FREE(key);
+ TALLOC_FREE(value);
+ return werr;
+}
+
+/**
+ * delete a parameter from configuration
+ */
+static WERROR smbconf_reg_delete_parameter(struct smbconf_ctx *ctx,
+ const char *service,
+ const char *param)
+{
+ struct registry_key *key = NULL;
+ WERROR werr = WERR_OK;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ werr = smbconf_reg_open_service_key(mem_ctx, ctx, service,
+ REG_KEY_ALL, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ if (!smbconf_reg_valname_valid(param)) {
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ if (!smbconf_value_exists(key, param)) {
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ werr = reg_deletevalue(key, param);
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return werr;
+}
+
+static WERROR smbconf_reg_get_includes(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ uint32_t *num_includes,
+ char ***includes)
+{
+ WERROR werr;
+ struct registry_key *key = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ werr = smbconf_reg_open_service_key(tmp_ctx, ctx, service,
+ REG_KEY_READ, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = smbconf_reg_get_includes_internal(mem_ctx, key, num_includes,
+ includes);
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+}
+
+static WERROR smbconf_reg_set_includes(struct smbconf_ctx *ctx,
+ const char *service,
+ uint32_t num_includes,
+ const char **includes)
+{
+ WERROR werr = WERR_OK;
+ struct registry_key *key = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ werr = smbconf_reg_open_service_key(tmp_ctx, ctx, service,
+ REG_KEY_ALL, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ if (num_includes == 0) {
+ if (!smbconf_value_exists(key, INCLUDES_VALNAME)) {
+ goto done;
+ }
+ werr = reg_deletevalue(key, INCLUDES_VALNAME);
+ } else {
+ werr = smbconf_reg_set_multi_sz_value(key, INCLUDES_VALNAME,
+ num_includes, includes);
+ }
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+}
+
+static WERROR smbconf_reg_delete_includes(struct smbconf_ctx *ctx,
+ const char *service)
+{
+ WERROR werr = WERR_OK;
+ struct registry_key *key = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ werr = smbconf_reg_open_service_key(tmp_ctx, ctx, service,
+ REG_KEY_ALL, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ if (!smbconf_value_exists(key, INCLUDES_VALNAME)) {
+ goto done;
+ }
+
+ werr = reg_deletevalue(key, INCLUDES_VALNAME);
+
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+}
+
+struct smbconf_ops smbconf_ops_reg = {
+ .init = smbconf_reg_init,
+ .shutdown = smbconf_reg_shutdown,
+ .open_conf = smbconf_reg_open,
+ .close_conf = smbconf_reg_close,
+ .get_csn = smbconf_reg_get_csn,
+ .drop = smbconf_reg_drop,
+ .get_share_names = smbconf_reg_get_share_names,
+ .share_exists = smbconf_reg_share_exists,
+ .create_share = smbconf_reg_create_share,
+ .get_share = smbconf_reg_get_share,
+ .delete_share = smbconf_reg_delete_share,
+ .set_parameter = smbconf_reg_set_parameter,
+ .get_parameter = smbconf_reg_get_parameter,
+ .delete_parameter = smbconf_reg_delete_parameter,
+ .get_includes = smbconf_reg_get_includes,
+ .set_includes = smbconf_reg_set_includes,
+ .delete_includes = smbconf_reg_delete_includes,
+};
+
+
+/**
+ * initialize the smbconf registry backend
+ * the only function that is exported from this module
+ */
+WERROR smbconf_init_reg(TALLOC_CTX *mem_ctx, struct smbconf_ctx **conf_ctx,
+ const char *path)
+{
+ return smbconf_init_internal(mem_ctx, conf_ctx, path, &smbconf_ops_reg);
+}
diff --git a/source3/lib/smbconf/smbconf_txt.c b/source3/lib/smbconf/smbconf_txt.c
new file mode 100644
index 0000000000..1a29f40164
--- /dev/null
+++ b/source3/lib/smbconf/smbconf_txt.c
@@ -0,0 +1,641 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libsmbconf - Samba configuration library, text backend
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This is a sample implementation of a libsmbconf text backend
+ * using the params.c parser.
+ *
+ * It is read only.
+ * Don't expect brilliant performance, since it is not hashing the lists.
+ */
+
+#include "includes.h"
+#include "smbconf_private.h"
+
+struct txt_cache {
+ uint32_t current_share;
+ uint32_t num_shares;
+ char **share_names;
+ uint32_t *num_params;
+ char ***param_names;
+ char ***param_values;
+};
+
+struct txt_private_data {
+ struct txt_cache *cache;
+ uint64_t csn;
+ bool verbatim;
+};
+
+/**********************************************************************
+ *
+ * helper functions
+ *
+ **********************************************************************/
+
+/**
+ * a convenience helper to cast the private data structure
+ */
+static struct txt_private_data *pd(struct smbconf_ctx *ctx)
+{
+ return (struct txt_private_data *)(ctx->data);
+}
+
+static bool smbconf_txt_do_section(const char *section, void *private_data)
+{
+ WERROR werr;
+ uint32_t idx;
+ struct txt_private_data *tpd = (struct txt_private_data *)private_data;
+ struct txt_cache *cache = tpd->cache;
+
+ if (smbconf_find_in_array(section, cache->share_names,
+ cache->num_shares, &idx))
+ {
+ cache->current_share = idx;
+ return true;
+ }
+
+ werr = smbconf_add_string_to_array(cache, &(cache->share_names),
+ cache->num_shares, section);
+ if (!W_ERROR_IS_OK(werr)) {
+ return false;
+ }
+ cache->current_share = cache->num_shares;
+ cache->num_shares++;
+
+ cache->param_names = TALLOC_REALLOC_ARRAY(cache,
+ cache->param_names,
+ char **,
+ cache->num_shares);
+ if (cache->param_names == NULL) {
+ return false;
+ }
+ cache->param_names[cache->current_share] = NULL;
+
+ cache->param_values = TALLOC_REALLOC_ARRAY(cache,
+ cache->param_values,
+ char **,
+ cache->num_shares);
+ if (cache->param_values == NULL) {
+ return false;
+ }
+ cache->param_values[cache->current_share] = NULL;
+
+ cache->num_params = TALLOC_REALLOC_ARRAY(cache,
+ cache->num_params,
+ uint32_t,
+ cache->num_shares);
+ if (cache->num_params == NULL) {
+ return false;
+ }
+ cache->num_params[cache->current_share] = 0;
+
+ return true;
+}
+
+static bool smbconf_txt_do_parameter(const char *param_name,
+ const char *param_value,
+ void *private_data)
+{
+ WERROR werr;
+ char **param_names, **param_values;
+ uint32_t num_params;
+ uint32_t idx;
+ struct txt_private_data *tpd = (struct txt_private_data *)private_data;
+ struct txt_cache *cache = tpd->cache;
+
+ if (cache->num_shares == 0) {
+ /*
+ * not in any share yet,
+ * initialize the "empty" section (NULL):
+ * parameters without a previous [section] are stored here.
+ */
+ if (!smbconf_txt_do_section(NULL, private_data)) {
+ return false;
+ }
+ }
+
+ param_names = cache->param_names[cache->current_share];
+ param_values = cache->param_values[cache->current_share];
+ num_params = cache->num_params[cache->current_share];
+
+ if (!(tpd->verbatim) &&
+ smbconf_find_in_array(param_name, param_names, num_params, &idx))
+ {
+ TALLOC_FREE(param_values[idx]);
+ param_values[idx] = talloc_strdup(cache, param_value);
+ if (param_values[idx] == NULL) {
+ return false;
+ }
+ return true;
+ }
+ werr = smbconf_add_string_to_array(cache,
+ &(cache->param_names[cache->current_share]),
+ num_params, param_name);
+ if (!W_ERROR_IS_OK(werr)) {
+ return false;
+ }
+ werr = smbconf_add_string_to_array(cache,
+ &(cache->param_values[cache->current_share]),
+ num_params, param_value);
+ cache->num_params[cache->current_share]++;
+ return W_ERROR_IS_OK(werr);
+}
+
+static void smbconf_txt_flush_cache(struct smbconf_ctx *ctx)
+{
+ TALLOC_FREE(pd(ctx)->cache);
+}
+
+static WERROR smbconf_txt_init_cache(struct smbconf_ctx *ctx)
+{
+ if (pd(ctx)->cache != NULL) {
+ smbconf_txt_flush_cache(ctx);
+ }
+
+ pd(ctx)->cache = TALLOC_ZERO_P(pd(ctx), struct txt_cache);
+
+ if (pd(ctx)->cache == NULL) {
+ return WERR_NOMEM;
+ }
+
+ return WERR_OK;
+}
+
+static WERROR smbconf_txt_load_file(struct smbconf_ctx *ctx)
+{
+ WERROR werr;
+ uint64_t new_csn;
+
+ if (!file_exist(ctx->path, NULL)) {
+ return WERR_BADFILE;
+ }
+
+ new_csn = (uint64_t)file_modtime(ctx->path);
+ if (new_csn == pd(ctx)->csn) {
+ return WERR_OK;
+ }
+
+ werr = smbconf_txt_init_cache(ctx);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ if (!pm_process(ctx->path, smbconf_txt_do_section,
+ smbconf_txt_do_parameter, pd(ctx)))
+ {
+ return WERR_CAN_NOT_COMPLETE;
+ }
+
+ pd(ctx)->csn = new_csn;
+
+ return WERR_OK;
+}
+
+
+/**********************************************************************
+ *
+ * smbconf operations: text backend implementations
+ *
+ **********************************************************************/
+
+/**
+ * initialize the text based smbconf backend
+ */
+static WERROR smbconf_txt_init(struct smbconf_ctx *ctx, const char *path)
+{
+ if (path == NULL) {
+ path = get_dyn_CONFIGFILE();
+ }
+ ctx->path = talloc_strdup(ctx, path);
+ if (ctx->path == NULL) {
+ return WERR_NOMEM;
+ }
+
+ ctx->data = TALLOC_ZERO_P(ctx, struct txt_private_data);
+ if (ctx->data == NULL) {
+ return WERR_NOMEM;
+ }
+
+ pd(ctx)->verbatim = true;
+
+ return WERR_OK;
+}
+
+static int smbconf_txt_shutdown(struct smbconf_ctx *ctx)
+{
+ return ctx->ops->close_conf(ctx);
+}
+
+static WERROR smbconf_txt_open(struct smbconf_ctx *ctx)
+{
+ return smbconf_txt_load_file(ctx);
+}
+
+static int smbconf_txt_close(struct smbconf_ctx *ctx)
+{
+ smbconf_txt_flush_cache(ctx);
+ return 0;
+}
+
+/**
+ * Get the change sequence number of the given service/parameter.
+ * service and parameter strings may be NULL.
+ */
+static void smbconf_txt_get_csn(struct smbconf_ctx *ctx,
+ struct smbconf_csn *csn,
+ const char *service, const char *param)
+{
+ if (csn == NULL) {
+ return;
+ }
+
+ csn->csn = (uint64_t)file_modtime(ctx->path);
+}
+
+/**
+ * Drop the whole configuration (restarting empty)
+ */
+static WERROR smbconf_txt_drop(struct smbconf_ctx *ctx)
+{
+ return WERR_NOT_SUPPORTED;
+}
+
+/**
+ * get the list of share names defined in the configuration.
+ */
+static WERROR smbconf_txt_get_share_names(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_shares,
+ char ***share_names)
+{
+ uint32_t count;
+ uint32_t added_count = 0;
+ TALLOC_CTX *tmp_ctx = NULL;
+ WERROR werr = WERR_OK;
+ char **tmp_share_names = NULL;
+
+ if ((num_shares == NULL) || (share_names == NULL)) {
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ werr = smbconf_txt_load_file(ctx);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ tmp_ctx = talloc_stackframe();
+
+ /* make sure "global" is always listed first,
+ * possibly after NULL section */
+
+ if (smbconf_share_exists(ctx, NULL)) {
+ werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
+ 0, NULL);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ added_count++;
+ }
+
+ if (smbconf_share_exists(ctx, GLOBAL_NAME)) {
+ werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
+ added_count, GLOBAL_NAME);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ added_count++;
+ }
+
+ for (count = 0; count < pd(ctx)->cache->num_shares; count++) {
+ if (strequal(pd(ctx)->cache->share_names[count], GLOBAL_NAME) ||
+ (pd(ctx)->cache->share_names[count] == NULL))
+ {
+ continue;
+ }
+
+ werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
+ added_count,
+ pd(ctx)->cache->share_names[count]);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ added_count++;
+ }
+
+ *num_shares = added_count;
+ if (added_count > 0) {
+ *share_names = talloc_move(mem_ctx, &tmp_share_names);
+ } else {
+ *share_names = NULL;
+ }
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+}
+
+/**
+ * check if a share/service of a given name exists
+ */
+static bool smbconf_txt_share_exists(struct smbconf_ctx *ctx,
+ const char *servicename)
+{
+ WERROR werr;
+
+ werr = smbconf_txt_load_file(ctx);
+ if (!W_ERROR_IS_OK(werr)) {
+ return false;
+ }
+
+ return smbconf_find_in_array(servicename,
+ pd(ctx)->cache->share_names,
+ pd(ctx)->cache->num_shares, NULL);
+}
+
+/**
+ * Add a service if it does not already exist
+ */
+static WERROR smbconf_txt_create_share(struct smbconf_ctx *ctx,
+ const char *servicename)
+{
+ return WERR_NOT_SUPPORTED;
+}
+
+/**
+ * get a definition of a share (service) from configuration.
+ */
+static WERROR smbconf_txt_get_share(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *servicename,
+ struct smbconf_service **service)
+{
+ WERROR werr;
+ uint32_t sidx, count;
+ bool found;
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct smbconf_service *tmp_service = NULL;
+
+ werr = smbconf_txt_load_file(ctx);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ found = smbconf_find_in_array(servicename,
+ pd(ctx)->cache->share_names,
+ pd(ctx)->cache->num_shares,
+ &sidx);
+ if (!found) {
+ return WERR_NO_SUCH_SERVICE;
+ }
+
+ tmp_ctx = talloc_stackframe();
+
+ tmp_service = TALLOC_ZERO_P(tmp_ctx, struct smbconf_service);
+ if (tmp_service == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ if (servicename != NULL) {
+ tmp_service->name = talloc_strdup(tmp_service, servicename);
+ if (tmp_service->name == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+ }
+
+ for (count = 0; count < pd(ctx)->cache->num_params[sidx]; count++) {
+ werr = smbconf_add_string_to_array(tmp_service,
+ &(tmp_service->param_names),
+ count,
+ pd(ctx)->cache->param_names[sidx][count]);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ werr = smbconf_add_string_to_array(tmp_service,
+ &(tmp_service->param_values),
+ count,
+ pd(ctx)->cache->param_values[sidx][count]);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ }
+
+ tmp_service->num_params = count;
+ if (count > 0) {
+ *service = talloc_move(mem_ctx, &tmp_service);
+ } else {
+ *service = NULL;
+ }
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+}
+
+/**
+ * delete a service from configuration
+ */
+static WERROR smbconf_txt_delete_share(struct smbconf_ctx *ctx,
+ const char *servicename)
+{
+ return WERR_NOT_SUPPORTED;
+}
+
+/**
+ * set a configuration parameter to the value provided.
+ */
+static WERROR smbconf_txt_set_parameter(struct smbconf_ctx *ctx,
+ const char *service,
+ const char *param,
+ const char *valstr)
+{
+ return WERR_NOT_SUPPORTED;
+}
+
+/**
+ * get the value of a configuration parameter as a string
+ */
+static WERROR smbconf_txt_get_parameter(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ const char *param,
+ char **valstr)
+{
+ WERROR werr;
+ bool found;
+ uint32_t share_index, param_index;
+
+ werr = smbconf_txt_load_file(ctx);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ found = smbconf_find_in_array(service,
+ pd(ctx)->cache->share_names,
+ pd(ctx)->cache->num_shares,
+ &share_index);
+ if (!found) {
+ return WERR_NO_SUCH_SERVICE;
+ }
+
+ found = smbconf_reverse_find_in_array(param,
+ pd(ctx)->cache->param_names[share_index],
+ pd(ctx)->cache->num_params[share_index],
+ &param_index);
+ if (!found) {
+ return WERR_INVALID_PARAM;
+ }
+
+ *valstr = talloc_strdup(mem_ctx,
+ pd(ctx)->cache->param_values[share_index][param_index]);
+
+ if (*valstr == NULL) {
+ return WERR_NOMEM;
+ }
+
+ return WERR_OK;
+}
+
+/**
+ * delete a parameter from configuration
+ */
+static WERROR smbconf_txt_delete_parameter(struct smbconf_ctx *ctx,
+ const char *service,
+ const char *param)
+{
+ return WERR_NOT_SUPPORTED;
+}
+
+static WERROR smbconf_txt_get_includes(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ uint32_t *num_includes,
+ char ***includes)
+{
+ WERROR werr;
+ bool found;
+ uint32_t sidx, count;
+ TALLOC_CTX *tmp_ctx = NULL;
+ uint32_t tmp_num_includes = 0;
+ char **tmp_includes = NULL;
+
+ werr = smbconf_txt_load_file(ctx);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ found = smbconf_find_in_array(service,
+ pd(ctx)->cache->share_names,
+ pd(ctx)->cache->num_shares,
+ &sidx);
+ if (!found) {
+ return WERR_NO_SUCH_SERVICE;
+ }
+
+ tmp_ctx = talloc_stackframe();
+
+ for (count = 0; count < pd(ctx)->cache->num_params[sidx]; count++) {
+ if (strequal(pd(ctx)->cache->param_names[sidx][count],
+ "include"))
+ {
+ werr = smbconf_add_string_to_array(tmp_ctx,
+ &tmp_includes,
+ tmp_num_includes,
+ pd(ctx)->cache->param_values[sidx][count]);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ tmp_num_includes++;
+ }
+ }
+
+ *num_includes = tmp_num_includes;
+ if (*num_includes > 0) {
+ *includes = talloc_move(mem_ctx, &tmp_includes);
+ if (*includes == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+ } else {
+ *includes = NULL;
+ }
+
+ werr = WERR_OK;
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+}
+
+static WERROR smbconf_txt_set_includes(struct smbconf_ctx *ctx,
+ const char *service,
+ uint32_t num_includes,
+ const char **includes)
+{
+ return WERR_NOT_SUPPORTED;
+}
+
+static WERROR smbconf_txt_delete_includes(struct smbconf_ctx *ctx,
+ const char *service)
+{
+ return WERR_NOT_SUPPORTED;
+}
+
+
+static struct smbconf_ops smbconf_ops_txt = {
+ .init = smbconf_txt_init,
+ .shutdown = smbconf_txt_shutdown,
+ .open_conf = smbconf_txt_open,
+ .close_conf = smbconf_txt_close,
+ .get_csn = smbconf_txt_get_csn,
+ .drop = smbconf_txt_drop,
+ .get_share_names = smbconf_txt_get_share_names,
+ .share_exists = smbconf_txt_share_exists,
+ .create_share = smbconf_txt_create_share,
+ .get_share = smbconf_txt_get_share,
+ .delete_share = smbconf_txt_delete_share,
+ .set_parameter = smbconf_txt_set_parameter,
+ .get_parameter = smbconf_txt_get_parameter,
+ .delete_parameter = smbconf_txt_delete_parameter,
+ .get_includes = smbconf_txt_get_includes,
+ .set_includes = smbconf_txt_set_includes,
+ .delete_includes = smbconf_txt_delete_includes,
+};
+
+
+/**
+ * initialize the smbconf text backend
+ * the only function that is exported from this module
+ */
+WERROR smbconf_init_txt(TALLOC_CTX *mem_ctx,
+ struct smbconf_ctx **conf_ctx,
+ const char *path)
+{
+ WERROR werr;
+
+ werr = smbconf_init_internal(mem_ctx, conf_ctx, path, &smbconf_ops_txt);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ return smbconf_txt_load_file(*conf_ctx);
+}
diff --git a/source3/lib/smbconf/smbconf_util.c b/source3/lib/smbconf/smbconf_util.c
new file mode 100644
index 0000000000..271fc47dd4
--- /dev/null
+++ b/source3/lib/smbconf/smbconf_util.c
@@ -0,0 +1,151 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libsmbconf - Samba configuration library, utility functions
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "smbconf_private.h"
+
+
+static int smbconf_destroy_ctx(struct smbconf_ctx *ctx)
+{
+ return ctx->ops->shutdown(ctx);
+}
+
+/**
+ * Initialize the configuration.
+ *
+ * This should be the first function in a sequence of calls to smbconf
+ * functions:
+ *
+ * Upon success, this creates and returns the conf context
+ * that should be passed around in subsequent calls to the other
+ * smbconf functions.
+ *
+ * After the work with the configuration is completed, smbconf_shutdown()
+ * should be called.
+ */
+WERROR smbconf_init_internal(TALLOC_CTX *mem_ctx, struct smbconf_ctx **conf_ctx,
+ const char *path, struct smbconf_ops *ops)
+{
+ WERROR werr = WERR_OK;
+ struct smbconf_ctx *ctx;
+
+ if (conf_ctx == NULL) {
+ return WERR_INVALID_PARAM;
+ }
+
+ ctx = TALLOC_ZERO_P(mem_ctx, struct smbconf_ctx);
+ if (ctx == NULL) {
+ return WERR_NOMEM;
+ }
+
+ ctx->ops = ops;
+
+ werr = ctx->ops->init(ctx, path);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto fail;
+ }
+
+ talloc_set_destructor(ctx, smbconf_destroy_ctx);
+
+ *conf_ctx = ctx;
+ return werr;
+
+fail:
+ TALLOC_FREE(ctx);
+ return werr;
+}
+
+
+/**
+ * add a string to a talloced array of strings.
+ */
+WERROR smbconf_add_string_to_array(TALLOC_CTX *mem_ctx,
+ char ***array,
+ uint32_t count,
+ const char *string)
+{
+ char **new_array = NULL;
+
+ if (array == NULL) {
+ return WERR_INVALID_PARAM;
+ }
+
+ new_array = TALLOC_REALLOC_ARRAY(mem_ctx, *array, char *, count + 1);
+ if (new_array == NULL) {
+ return WERR_NOMEM;
+ }
+
+ if (string == NULL) {
+ new_array[count] = NULL;
+ } else {
+ new_array[count] = talloc_strdup(new_array, string);
+ if (new_array[count] == NULL) {
+ TALLOC_FREE(new_array);
+ return WERR_NOMEM;
+ }
+ }
+
+ *array = new_array;
+
+ return WERR_OK;
+}
+
+bool smbconf_find_in_array(const char *string, char **list,
+ uint32_t num_entries, uint32_t *entry)
+{
+ uint32_t i;
+
+ if (list == NULL) {
+ return false;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if (((string == NULL) && (list[i] == NULL)) ||
+ strequal(string, list[i]))
+ {
+ if (entry != NULL) {
+ *entry = i;
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool smbconf_reverse_find_in_array(const char *string, char **list,
+ uint32_t num_entries, uint32_t *entry)
+{
+ int32_t i;
+
+ if ((string == NULL) || (list == NULL) || (num_entries == 0)) {
+ return false;
+ }
+
+ for (i = num_entries - 1; i >= 0; i--) {
+ if (strequal(string, list[i])) {
+ if (entry != NULL) {
+ *entry = i;
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/source3/lib/smbconf/testsuite.c b/source3/lib/smbconf/testsuite.c
new file mode 100644
index 0000000000..cffd239df6
--- /dev/null
+++ b/source3/lib/smbconf/testsuite.c
@@ -0,0 +1,283 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libsmbconf - Samba configuration library: testsuite
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+static void print_strings(const char *prefix,
+ uint32_t num_strings, const char **strings)
+{
+ uint32_t count;
+
+ if (prefix == NULL) {
+ prefix = "";
+ }
+
+ for (count = 0; count < num_strings; count++) {
+ printf("%s%s\n", prefix, strings[count]);
+ }
+}
+
+static bool test_get_includes(struct smbconf_ctx *ctx)
+{
+ WERROR werr;
+ bool ret = false;
+ uint32_t num_includes = 0;
+ char **includes = NULL;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ printf("test: get_includes\n");
+ werr = smbconf_get_global_includes(ctx, mem_ctx,
+ &num_includes, &includes);
+ if (!W_ERROR_IS_OK(werr)) {
+ printf("failure: get_includes - %s\n", dos_errstr(werr));
+ goto done;
+ }
+
+ printf("got %u includes%s\n", num_includes,
+ (num_includes > 0) ? ":" : ".");
+ print_strings("", num_includes, (const char **)includes);
+
+ printf("success: get_includes\n");
+ ret = true;
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static bool test_set_get_includes(struct smbconf_ctx *ctx)
+{
+ WERROR werr;
+ uint32_t count;
+ bool ret = false;
+ const char *set_includes[] = {
+ "/path/to/include1",
+ "/path/to/include2"
+ };
+ uint32_t set_num_includes = 2;
+ char **get_includes = NULL;
+ uint32_t get_num_includes = 0;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ printf("test: set_get_includes\n");
+
+ werr = smbconf_set_global_includes(ctx, set_num_includes, set_includes);
+ if (!W_ERROR_IS_OK(werr)) {
+ printf("failure: get_set_includes (setting includes) - %s\n",
+ dos_errstr(werr));
+ goto done;
+ }
+
+ werr = smbconf_get_global_includes(ctx, mem_ctx, &get_num_includes,
+ &get_includes);
+ if (!W_ERROR_IS_OK(werr)) {
+ printf("failure: get_set_includes (getting includes) - %s\n",
+ dos_errstr(werr));
+ goto done;
+ }
+
+ if (get_num_includes != set_num_includes) {
+ printf("failure: get_set_includes - set %d includes, got %d\n",
+ set_num_includes, get_num_includes);
+ goto done;
+ }
+
+ for (count = 0; count < get_num_includes; count++) {
+ if (!strequal(set_includes[count], get_includes[count])) {
+ printf("expected: \n");
+ print_strings("* ", set_num_includes, set_includes);
+ printf("got: \n");
+ print_strings("* ", get_num_includes,
+ (const char **)get_includes);
+ printf("failure: get_set_includes - data mismatch:\n");
+ goto done;
+ }
+ }
+
+ printf("success: set_includes\n");
+ ret = true;
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static bool test_delete_includes(struct smbconf_ctx *ctx)
+{
+ WERROR werr;
+ bool ret = false;
+ const char *set_includes[] = {
+ "/path/to/include",
+ };
+ uint32_t set_num_includes = 1;
+ char **get_includes = NULL;
+ uint32_t get_num_includes = 0;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ printf("test: delete_includes\n");
+
+ werr = smbconf_set_global_includes(ctx, set_num_includes, set_includes);
+ if (!W_ERROR_IS_OK(werr)) {
+ printf("failure: delete_includes (setting includes) - %s\n",
+ dos_errstr(werr));
+ goto done;
+ }
+
+ werr = smbconf_delete_global_includes(ctx);
+ if (!W_ERROR_IS_OK(werr)) {
+ printf("failure: delete_includes (deleting includes) - %s\n",
+ dos_errstr(werr));
+ goto done;
+ }
+
+ werr = smbconf_get_global_includes(ctx, mem_ctx, &get_num_includes,
+ &get_includes);
+ if (!W_ERROR_IS_OK(werr)) {
+ printf("failure: delete_includes (getting includes) - %s\n",
+ dos_errstr(werr));
+ goto done;
+ }
+
+ if (get_num_includes != 0) {
+ printf("failure: delete_includes (not empty after delete)\n");
+ goto done;
+ }
+
+ werr = smbconf_delete_global_includes(ctx);
+ if (!W_ERROR_IS_OK(werr)) {
+ printf("failuer: delete_includes (delete empty includes) - "
+ "%s\n", dos_errstr(werr));
+ goto done;
+ }
+
+ printf("success: delete_includes\n");
+ ret = true;
+
+done:
+ return ret;
+}
+
+static bool torture_smbconf_txt(void)
+{
+ WERROR werr;
+ bool ret = true;
+ struct smbconf_ctx *conf_ctx = NULL;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ printf("test: text backend\n");
+
+ printf("test: init\n");
+ werr = smbconf_init_txt(mem_ctx, &conf_ctx, NULL);
+ if (!W_ERROR_IS_OK(werr)) {
+ printf("failure: init failed: %s\n", dos_errstr(werr));
+ ret = false;
+ goto done;
+ }
+ printf("success: init\n");
+
+ ret &= test_get_includes(conf_ctx);
+
+ smbconf_shutdown(conf_ctx);
+
+ printf("%s: text backend\n", ret ? "success" : "failure");
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static bool torture_smbconf_reg(void)
+{
+ WERROR werr;
+ bool ret = true;
+ struct smbconf_ctx *conf_ctx = NULL;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ printf("test: registry backend\n");
+
+ printf("test: init\n");
+ werr = smbconf_init_reg(mem_ctx, &conf_ctx, NULL);
+ if (!W_ERROR_IS_OK(werr)) {
+ printf("failure: init failed: %s\n", dos_errstr(werr));
+ ret = false;
+ goto done;
+ }
+ printf("success: init\n");
+
+ ret &= test_get_includes(conf_ctx);
+ ret &= test_set_get_includes(conf_ctx);
+ ret &= test_delete_includes(conf_ctx);
+
+ smbconf_shutdown(conf_ctx);
+
+ printf("%s: registry backend\n", ret ? "success" : "failure");
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static bool torture_smbconf(void)
+{
+ bool ret = true;
+ ret &= torture_smbconf_txt();
+ printf("\n");
+ ret &= torture_smbconf_reg();
+ return ret;
+}
+
+int main(int argc, const char **argv)
+{
+ bool ret;
+ poptContext pc;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ struct poptOption long_options[] = {
+ POPT_COMMON_SAMBA
+ {0, 0, 0, 0}
+ };
+
+ load_case_tables();
+ dbf = x_stderr;
+
+ /* parse options */
+ pc = poptGetContext("smbconftort", argc, (const char **)argv,
+ long_options, 0);
+
+ while(poptGetNextOpt(pc) != -1) { }
+
+ poptFreeContext(pc);
+
+ ret = lp_load(get_dyn_CONFIGFILE(),
+ true, /* globals_only */
+ false, /* save_defaults */
+ false, /* add_ipc */
+ true /* initialize globals */);
+
+ if (!ret) {
+ printf("failure: error loading the configuration\n");
+ goto done;
+ }
+
+ ret = torture_smbconf();
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret ? 0 : -1;
+}
diff --git a/source3/lib/smbldap.c b/source3/lib/smbldap.c
new file mode 100644
index 0000000000..93494d6dad
--- /dev/null
+++ b/source3/lib/smbldap.c
@@ -0,0 +1,1824 @@
+/*
+ Unix SMB/CIFS implementation.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Jean François Micouleau 1998
+ Copyright (C) Gerald Carter 2001-2003
+ Copyright (C) Shahms King 2001
+ Copyright (C) Andrew Bartlett 2002-2003
+ Copyright (C) Stefan (metze) Metzmacher 2002-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include "smbldap.h"
+
+#ifndef LDAP_OPT_SUCCESS
+#define LDAP_OPT_SUCCESS 0
+#endif
+
+/* Try not to hit the up or down server forever */
+
+#define SMBLDAP_DONT_PING_TIME 10 /* ping only all 10 seconds */
+#define SMBLDAP_NUM_RETRIES 8 /* retry only 8 times */
+
+#define SMBLDAP_IDLE_TIME 150 /* After 2.5 minutes disconnect */
+
+
+/* attributes used by Samba 2.2 */
+
+ATTRIB_MAP_ENTRY attrib_map_v22[] = {
+ { LDAP_ATTR_UID, "uid" },
+ { LDAP_ATTR_UIDNUMBER, LDAP_ATTRIBUTE_UIDNUMBER},
+ { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER},
+ { LDAP_ATTR_UNIX_HOME, "homeDirectory" },
+ { LDAP_ATTR_PWD_LAST_SET, "pwdLastSet" },
+ { LDAP_ATTR_PWD_CAN_CHANGE, "pwdCanChange" },
+ { LDAP_ATTR_PWD_MUST_CHANGE, "pwdMustChange" },
+ { LDAP_ATTR_LOGON_TIME, "logonTime" },
+ { LDAP_ATTR_LOGOFF_TIME, "logoffTime" },
+ { LDAP_ATTR_KICKOFF_TIME, "kickoffTime" },
+ { LDAP_ATTR_CN, "cn" },
+ { LDAP_ATTR_SN, "sn" },
+ { LDAP_ATTR_DISPLAY_NAME, "displayName" },
+ { LDAP_ATTR_HOME_PATH, "smbHome" },
+ { LDAP_ATTR_HOME_DRIVE, "homeDrive" },
+ { LDAP_ATTR_LOGON_SCRIPT, "scriptPath" },
+ { LDAP_ATTR_PROFILE_PATH, "profilePath" },
+ { LDAP_ATTR_DESC, "description" },
+ { LDAP_ATTR_USER_WKS, "userWorkstations"},
+ { LDAP_ATTR_USER_RID, "rid" },
+ { LDAP_ATTR_PRIMARY_GROUP_RID, "primaryGroupID"},
+ { LDAP_ATTR_LMPW, "lmPassword" },
+ { LDAP_ATTR_NTPW, "ntPassword" },
+ { LDAP_ATTR_DOMAIN, "domain" },
+ { LDAP_ATTR_OBJCLASS, "objectClass" },
+ { LDAP_ATTR_ACB_INFO, "acctFlags" },
+ { LDAP_ATTR_MOD_TIMESTAMP, "modifyTimestamp" },
+ { LDAP_ATTR_LIST_END, NULL }
+};
+
+ATTRIB_MAP_ENTRY attrib_map_to_delete_v22[] = {
+ { LDAP_ATTR_PWD_LAST_SET, "pwdLastSet" },
+ { LDAP_ATTR_PWD_CAN_CHANGE, "pwdCanChange" },
+ { LDAP_ATTR_PWD_MUST_CHANGE, "pwdMustChange" },
+ { LDAP_ATTR_LOGON_TIME, "logonTime" },
+ { LDAP_ATTR_LOGOFF_TIME, "logoffTime" },
+ { LDAP_ATTR_KICKOFF_TIME, "kickoffTime" },
+ { LDAP_ATTR_DISPLAY_NAME, "displayName" },
+ { LDAP_ATTR_HOME_PATH, "smbHome" },
+ { LDAP_ATTR_HOME_DRIVE, "homeDrives" },
+ { LDAP_ATTR_LOGON_SCRIPT, "scriptPath" },
+ { LDAP_ATTR_PROFILE_PATH, "profilePath" },
+ { LDAP_ATTR_USER_WKS, "userWorkstations"},
+ { LDAP_ATTR_USER_RID, "rid" },
+ { LDAP_ATTR_PRIMARY_GROUP_RID, "primaryGroupID"},
+ { LDAP_ATTR_LMPW, "lmPassword" },
+ { LDAP_ATTR_NTPW, "ntPassword" },
+ { LDAP_ATTR_DOMAIN, "domain" },
+ { LDAP_ATTR_ACB_INFO, "acctFlags" },
+ { LDAP_ATTR_LIST_END, NULL }
+};
+
+/* attributes used by Samba 3.0's sambaSamAccount */
+
+ATTRIB_MAP_ENTRY attrib_map_v30[] = {
+ { LDAP_ATTR_UID, "uid" },
+ { LDAP_ATTR_UIDNUMBER, LDAP_ATTRIBUTE_UIDNUMBER},
+ { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER},
+ { LDAP_ATTR_UNIX_HOME, "homeDirectory" },
+ { LDAP_ATTR_PWD_LAST_SET, "sambaPwdLastSet" },
+ { LDAP_ATTR_PWD_CAN_CHANGE, "sambaPwdCanChange" },
+ { LDAP_ATTR_PWD_MUST_CHANGE, "sambaPwdMustChange" },
+ { LDAP_ATTR_LOGON_TIME, "sambaLogonTime" },
+ { LDAP_ATTR_LOGOFF_TIME, "sambaLogoffTime" },
+ { LDAP_ATTR_KICKOFF_TIME, "sambaKickoffTime" },
+ { LDAP_ATTR_CN, "cn" },
+ { LDAP_ATTR_SN, "sn" },
+ { LDAP_ATTR_DISPLAY_NAME, "displayName" },
+ { LDAP_ATTR_HOME_DRIVE, "sambaHomeDrive" },
+ { LDAP_ATTR_HOME_PATH, "sambaHomePath" },
+ { LDAP_ATTR_LOGON_SCRIPT, "sambaLogonScript" },
+ { LDAP_ATTR_PROFILE_PATH, "sambaProfilePath" },
+ { LDAP_ATTR_DESC, "description" },
+ { LDAP_ATTR_USER_WKS, "sambaUserWorkstations" },
+ { LDAP_ATTR_USER_SID, LDAP_ATTRIBUTE_SID },
+ { LDAP_ATTR_PRIMARY_GROUP_SID, "sambaPrimaryGroupSID" },
+ { LDAP_ATTR_LMPW, "sambaLMPassword" },
+ { LDAP_ATTR_NTPW, "sambaNTPassword" },
+ { LDAP_ATTR_DOMAIN, "sambaDomainName" },
+ { LDAP_ATTR_OBJCLASS, "objectClass" },
+ { LDAP_ATTR_ACB_INFO, "sambaAcctFlags" },
+ { LDAP_ATTR_MUNGED_DIAL, "sambaMungedDial" },
+ { LDAP_ATTR_BAD_PASSWORD_COUNT, "sambaBadPasswordCount" },
+ { LDAP_ATTR_BAD_PASSWORD_TIME, "sambaBadPasswordTime" },
+ { LDAP_ATTR_PWD_HISTORY, "sambaPasswordHistory" },
+ { LDAP_ATTR_MOD_TIMESTAMP, "modifyTimestamp" },
+ { LDAP_ATTR_LOGON_HOURS, "sambaLogonHours" },
+ { LDAP_ATTR_LIST_END, NULL }
+};
+
+ATTRIB_MAP_ENTRY attrib_map_to_delete_v30[] = {
+ { LDAP_ATTR_PWD_LAST_SET, "sambaPwdLastSet" },
+ { LDAP_ATTR_PWD_CAN_CHANGE, "sambaPwdCanChange" },
+ { LDAP_ATTR_PWD_MUST_CHANGE, "sambaPwdMustChange" },
+ { LDAP_ATTR_LOGON_TIME, "sambaLogonTime" },
+ { LDAP_ATTR_LOGOFF_TIME, "sambaLogoffTime" },
+ { LDAP_ATTR_KICKOFF_TIME, "sambaKickoffTime" },
+ { LDAP_ATTR_DISPLAY_NAME, "displayName" },
+ { LDAP_ATTR_HOME_DRIVE, "sambaHomeDrive" },
+ { LDAP_ATTR_HOME_PATH, "sambaHomePath" },
+ { LDAP_ATTR_LOGON_SCRIPT, "sambaLogonScript" },
+ { LDAP_ATTR_PROFILE_PATH, "sambaProfilePath" },
+ { LDAP_ATTR_USER_WKS, "sambaUserWorkstations" },
+ { LDAP_ATTR_USER_SID, LDAP_ATTRIBUTE_SID },
+ { LDAP_ATTR_PRIMARY_GROUP_SID, "sambaPrimaryGroupSID" },
+ { LDAP_ATTR_LMPW, "sambaLMPassword" },
+ { LDAP_ATTR_NTPW, "sambaNTPassword" },
+ { LDAP_ATTR_DOMAIN, "sambaDomainName" },
+ { LDAP_ATTR_ACB_INFO, "sambaAcctFlags" },
+ { LDAP_ATTR_MUNGED_DIAL, "sambaMungedDial" },
+ { LDAP_ATTR_BAD_PASSWORD_COUNT, "sambaBadPasswordCount" },
+ { LDAP_ATTR_BAD_PASSWORD_TIME, "sambaBadPasswordTime" },
+ { LDAP_ATTR_PWD_HISTORY, "sambaPasswordHistory" },
+ { LDAP_ATTR_LOGON_HOURS, "sambaLogonHours" },
+ { LDAP_ATTR_LIST_END, NULL }
+};
+
+/* attributes used for allocating RIDs */
+
+ATTRIB_MAP_ENTRY dominfo_attr_list[] = {
+ { LDAP_ATTR_DOMAIN, "sambaDomainName" },
+ { LDAP_ATTR_NEXT_RID, "sambaNextRid" },
+ { LDAP_ATTR_NEXT_USERRID, "sambaNextUserRid" },
+ { LDAP_ATTR_NEXT_GROUPRID, "sambaNextGroupRid" },
+ { LDAP_ATTR_DOM_SID, LDAP_ATTRIBUTE_SID },
+ { LDAP_ATTR_ALGORITHMIC_RID_BASE,"sambaAlgorithmicRidBase"},
+ { LDAP_ATTR_OBJCLASS, "objectClass" },
+ { LDAP_ATTR_LIST_END, NULL },
+};
+
+/* Samba 3.0 group mapping attributes */
+
+ATTRIB_MAP_ENTRY groupmap_attr_list[] = {
+ { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER},
+ { LDAP_ATTR_GROUP_SID, LDAP_ATTRIBUTE_SID },
+ { LDAP_ATTR_GROUP_TYPE, "sambaGroupType" },
+ { LDAP_ATTR_SID_LIST, "sambaSIDList" },
+ { LDAP_ATTR_DESC, "description" },
+ { LDAP_ATTR_DISPLAY_NAME, "displayName" },
+ { LDAP_ATTR_CN, "cn" },
+ { LDAP_ATTR_OBJCLASS, "objectClass" },
+ { LDAP_ATTR_LIST_END, NULL }
+};
+
+ATTRIB_MAP_ENTRY groupmap_attr_list_to_delete[] = {
+ { LDAP_ATTR_GROUP_SID, LDAP_ATTRIBUTE_SID },
+ { LDAP_ATTR_GROUP_TYPE, "sambaGroupType" },
+ { LDAP_ATTR_DESC, "description" },
+ { LDAP_ATTR_DISPLAY_NAME, "displayName" },
+ { LDAP_ATTR_SID_LIST, "sambaSIDList" },
+ { LDAP_ATTR_LIST_END, NULL }
+};
+
+/* idmap_ldap sambaUnixIdPool */
+
+ATTRIB_MAP_ENTRY idpool_attr_list[] = {
+ { LDAP_ATTR_UIDNUMBER, LDAP_ATTRIBUTE_UIDNUMBER},
+ { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER},
+ { LDAP_ATTR_OBJCLASS, "objectClass" },
+ { LDAP_ATTR_LIST_END, NULL }
+};
+
+ATTRIB_MAP_ENTRY sidmap_attr_list[] = {
+ { LDAP_ATTR_SID, LDAP_ATTRIBUTE_SID },
+ { LDAP_ATTR_UIDNUMBER, LDAP_ATTRIBUTE_UIDNUMBER},
+ { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER},
+ { LDAP_ATTR_OBJCLASS, "objectClass" },
+ { LDAP_ATTR_LIST_END, NULL }
+};
+
+/**********************************************************************
+ perform a simple table lookup and return the attribute name
+ **********************************************************************/
+
+ const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key )
+{
+ int i = 0;
+
+ while ( table[i].attrib != LDAP_ATTR_LIST_END ) {
+ if ( table[i].attrib == key )
+ return table[i].name;
+ i++;
+ }
+
+ return NULL;
+}
+
+
+/**********************************************************************
+ Return the list of attribute names from a mapping table
+ **********************************************************************/
+
+ const char** get_attr_list( TALLOC_CTX *mem_ctx, ATTRIB_MAP_ENTRY table[] )
+{
+ const char **names;
+ int i = 0;
+
+ while ( table[i].attrib != LDAP_ATTR_LIST_END )
+ i++;
+ i++;
+
+ names = TALLOC_ARRAY( mem_ctx, const char*, i );
+ if ( !names ) {
+ DEBUG(0,("get_attr_list: out of memory\n"));
+ return NULL;
+ }
+
+ i = 0;
+ while ( table[i].attrib != LDAP_ATTR_LIST_END ) {
+ names[i] = talloc_strdup( names, table[i].name );
+ i++;
+ }
+ names[i] = NULL;
+
+ return names;
+}
+
+/*******************************************************************
+ Search an attribute and return the first value found.
+******************************************************************/
+
+ bool smbldap_get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
+ const char *attribute, char *value,
+ int max_len)
+{
+ char **values;
+
+ if ( !attribute )
+ return False;
+
+ value[0] = '\0';
+
+ if ((values = ldap_get_values (ldap_struct, entry, attribute)) == NULL) {
+ DEBUG (10, ("smbldap_get_single_attribute: [%s] = [<does not exist>]\n", attribute));
+
+ return False;
+ }
+
+ if (convert_string(CH_UTF8, CH_UNIX,values[0], -1, value, max_len, False) == (size_t)-1) {
+ DEBUG(1, ("smbldap_get_single_attribute: string conversion of [%s] = [%s] failed!\n",
+ attribute, values[0]));
+ ldap_value_free(values);
+ return False;
+ }
+
+ ldap_value_free(values);
+#ifdef DEBUG_PASSWORDS
+ DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n", attribute, value));
+#endif
+ return True;
+}
+
+ char * smbldap_talloc_single_attribute(LDAP *ldap_struct, LDAPMessage *entry,
+ const char *attribute,
+ TALLOC_CTX *mem_ctx)
+{
+ char **values;
+ char *result;
+ size_t converted_size;
+
+ if (attribute == NULL) {
+ return NULL;
+ }
+
+ values = ldap_get_values(ldap_struct, entry, attribute);
+
+ if (values == NULL) {
+ DEBUG(10, ("attribute %s does not exist\n", attribute));
+ return NULL;
+ }
+
+ if (ldap_count_values(values) != 1) {
+ DEBUG(10, ("attribute %s has %d values, expected only one\n",
+ attribute, ldap_count_values(values)));
+ ldap_value_free(values);
+ return NULL;
+ }
+
+ if (!pull_utf8_talloc(mem_ctx, &result, values[0], &converted_size)) {
+ DEBUG(10, ("pull_utf8_talloc failed\n"));
+ ldap_value_free(values);
+ return NULL;
+ }
+
+ ldap_value_free(values);
+
+#ifdef DEBUG_PASSWORDS
+ DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n",
+ attribute, result));
+#endif
+ return result;
+}
+
+ static int ldapmsg_destructor(LDAPMessage **result) {
+ ldap_msgfree(*result);
+ return 0;
+}
+
+ void talloc_autofree_ldapmsg(TALLOC_CTX *mem_ctx, LDAPMessage *result)
+{
+ LDAPMessage **handle;
+
+ if (result == NULL) {
+ return;
+ }
+
+ handle = TALLOC_P(mem_ctx, LDAPMessage *);
+ SMB_ASSERT(handle != NULL);
+
+ *handle = result;
+ talloc_set_destructor(handle, ldapmsg_destructor);
+}
+
+ static int ldapmod_destructor(LDAPMod ***mod) {
+ ldap_mods_free(*mod, True);
+ return 0;
+}
+
+ void talloc_autofree_ldapmod(TALLOC_CTX *mem_ctx, LDAPMod **mod)
+{
+ LDAPMod ***handle;
+
+ if (mod == NULL) {
+ return;
+ }
+
+ handle = TALLOC_P(mem_ctx, LDAPMod **);
+ SMB_ASSERT(handle != NULL);
+
+ *handle = mod;
+ talloc_set_destructor(handle, ldapmod_destructor);
+}
+
+/************************************************************************
+ Routine to manage the LDAPMod structure array
+ manage memory used by the array, by each struct, and values
+ ***********************************************************************/
+
+ void smbldap_set_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value)
+{
+ LDAPMod **mods;
+ int i;
+ int j;
+
+ mods = *modlist;
+
+ /* sanity checks on the mod values */
+
+ if (attribute == NULL || *attribute == '\0') {
+ return;
+ }
+
+#if 0 /* commented out after discussion with abartlet. Do not reenable.
+ left here so other do not re-add similar code --jerry */
+ if (value == NULL || *value == '\0')
+ return;
+#endif
+
+ if (mods == NULL) {
+ mods = SMB_MALLOC_P(LDAPMod *);
+ if (mods == NULL) {
+ smb_panic("smbldap_set_mod: out of memory!");
+ /* notreached. */
+ }
+ mods[0] = NULL;
+ }
+
+ for (i = 0; mods[i] != NULL; ++i) {
+ if (mods[i]->mod_op == modop && strequal(mods[i]->mod_type, attribute))
+ break;
+ }
+
+ if (mods[i] == NULL) {
+ mods = SMB_REALLOC_ARRAY (mods, LDAPMod *, i + 2);
+ if (mods == NULL) {
+ smb_panic("smbldap_set_mod: out of memory!");
+ /* notreached. */
+ }
+ mods[i] = SMB_MALLOC_P(LDAPMod);
+ if (mods[i] == NULL) {
+ smb_panic("smbldap_set_mod: out of memory!");
+ /* notreached. */
+ }
+ mods[i]->mod_op = modop;
+ mods[i]->mod_values = NULL;
+ mods[i]->mod_type = SMB_STRDUP(attribute);
+ mods[i + 1] = NULL;
+ }
+
+ if (value != NULL) {
+ char *utf8_value = NULL;
+ size_t converted_size;
+
+ j = 0;
+ if (mods[i]->mod_values != NULL) {
+ for (; mods[i]->mod_values[j] != NULL; j++);
+ }
+ mods[i]->mod_values = SMB_REALLOC_ARRAY(mods[i]->mod_values, char *, j + 2);
+
+ if (mods[i]->mod_values == NULL) {
+ smb_panic("smbldap_set_mod: out of memory!");
+ /* notreached. */
+ }
+
+ if (!push_utf8_allocate(&utf8_value, value, &converted_size)) {
+ smb_panic("smbldap_set_mod: String conversion failure!");
+ /* notreached. */
+ }
+
+ mods[i]->mod_values[j] = utf8_value;
+
+ mods[i]->mod_values[j + 1] = NULL;
+ }
+ *modlist = mods;
+}
+
+/**********************************************************************
+ Set attribute to newval in LDAP, regardless of what value the
+ attribute had in LDAP before.
+*********************************************************************/
+
+ void smbldap_make_mod(LDAP *ldap_struct, LDAPMessage *existing,
+ LDAPMod ***mods,
+ const char *attribute, const char *newval)
+{
+ char oldval[2048]; /* current largest allowed value is mungeddial */
+ bool existed;
+
+ if (attribute == NULL) {
+ /* This can actually happen for ldapsam_compat where we for
+ * example don't have a password history */
+ return;
+ }
+
+ if (existing != NULL) {
+ existed = smbldap_get_single_attribute(ldap_struct, existing, attribute, oldval, sizeof(oldval));
+ } else {
+ existed = False;
+ *oldval = '\0';
+ }
+
+ /* all of our string attributes are case insensitive */
+
+ if (existed && newval && (StrCaseCmp(oldval, newval) == 0)) {
+
+ /* Believe it or not, but LDAP will deny a delete and
+ an add at the same time if the values are the
+ same... */
+ DEBUG(10,("smbldap_make_mod: attribute |%s| not changed.\n", attribute));
+ return;
+ }
+
+ if (existed) {
+ /* There has been no value before, so don't delete it.
+ * Here's a possible race: We might end up with
+ * duplicate attributes */
+ /* By deleting exactly the value we found in the entry this
+ * should be race-free in the sense that the LDAP-Server will
+ * deny the complete operation if somebody changed the
+ * attribute behind our back. */
+ /* This will also allow modifying single valued attributes
+ * in Novell NDS. In NDS you have to first remove attribute and then
+ * you could add new value */
+
+ DEBUG(10,("smbldap_make_mod: deleting attribute |%s| values |%s|\n", attribute, oldval));
+ smbldap_set_mod(mods, LDAP_MOD_DELETE, attribute, oldval);
+ }
+
+ /* Regardless of the real operation (add or modify)
+ we add the new value here. We rely on deleting
+ the old value, should it exist. */
+
+ if ((newval != NULL) && (strlen(newval) > 0)) {
+ DEBUG(10,("smbldap_make_mod: adding attribute |%s| value |%s|\n", attribute, newval));
+ smbldap_set_mod(mods, LDAP_MOD_ADD, attribute, newval);
+ }
+}
+
+/**********************************************************************
+ Some varients of the LDAP rebind code do not pass in the third 'arg'
+ pointer to a void*, so we try and work around it by assuming that the
+ value of the 'LDAP *' pointer is the same as the one we had passed in
+ **********************************************************************/
+
+struct smbldap_state_lookup {
+ LDAP *ld;
+ struct smbldap_state *smbldap_state;
+ struct smbldap_state_lookup *prev, *next;
+};
+
+static struct smbldap_state_lookup *smbldap_state_lookup_list;
+
+static struct smbldap_state *smbldap_find_state(LDAP *ld)
+{
+ struct smbldap_state_lookup *t;
+
+ for (t = smbldap_state_lookup_list; t; t = t->next) {
+ if (t->ld == ld) {
+ return t->smbldap_state;
+ }
+ }
+ return NULL;
+}
+
+static void smbldap_delete_state(struct smbldap_state *smbldap_state)
+{
+ struct smbldap_state_lookup *t;
+
+ for (t = smbldap_state_lookup_list; t; t = t->next) {
+ if (t->smbldap_state == smbldap_state) {
+ DLIST_REMOVE(smbldap_state_lookup_list, t);
+ SAFE_FREE(t);
+ return;
+ }
+ }
+}
+
+static void smbldap_store_state(LDAP *ld, struct smbldap_state *smbldap_state)
+{
+ struct smbldap_state *tmp_ldap_state;
+ struct smbldap_state_lookup *t;
+
+ if ((tmp_ldap_state = smbldap_find_state(ld))) {
+ SMB_ASSERT(tmp_ldap_state == smbldap_state);
+ return;
+ }
+
+ t = SMB_XMALLOC_P(struct smbldap_state_lookup);
+ ZERO_STRUCTP(t);
+
+ DLIST_ADD_END(smbldap_state_lookup_list, t, struct smbldap_state_lookup *);
+ t->ld = ld;
+ t->smbldap_state = smbldap_state;
+}
+
+/********************************************************************
+ start TLS on an existing LDAP connection
+*******************************************************************/
+
+int smb_ldap_start_tls(LDAP *ldap_struct, int version)
+{
+ int rc;
+
+ if (lp_ldap_ssl() != LDAP_SSL_START_TLS) {
+ return LDAP_SUCCESS;
+ }
+
+#ifdef LDAP_OPT_X_TLS
+ if (version != LDAP_VERSION3) {
+ DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ((rc = ldap_start_tls_s (ldap_struct, NULL, NULL)) != LDAP_SUCCESS) {
+ DEBUG(0,("Failed to issue the StartTLS instruction: %s\n",
+ ldap_err2string(rc)));
+ return rc;
+ }
+
+ DEBUG (3, ("StartTLS issued: using a TLS connection\n"));
+ return LDAP_SUCCESS;
+#else
+ DEBUG(0,("StartTLS not supported by LDAP client libraries!\n"));
+ return LDAP_OPERATIONS_ERROR;
+#endif
+}
+
+/********************************************************************
+ setup a connection to the LDAP server based on a uri
+*******************************************************************/
+
+int smb_ldap_setup_conn(LDAP **ldap_struct, const char *uri)
+{
+ int rc;
+
+ DEBUG(10, ("smb_ldap_setup_connection: %s\n", uri));
+
+#ifdef HAVE_LDAP_INITIALIZE
+
+ rc = ldap_initialize(ldap_struct, uri);
+ if (rc) {
+ DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc)));
+ }
+
+ return rc;
+#else
+
+ /* Parse the string manually */
+
+ {
+ int port = 0;
+ fstring protocol;
+ fstring host;
+ SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
+
+
+ /* skip leading "URL:" (if any) */
+ if ( strnequal( uri, "URL:", 4 ) ) {
+ uri += 4;
+ }
+
+ sscanf(uri, "%10[^:]://%254[^:/]:%d", protocol, host, &port);
+
+ if (port == 0) {
+ if (strequal(protocol, "ldap")) {
+ port = LDAP_PORT;
+ } else if (strequal(protocol, "ldaps")) {
+ port = LDAPS_PORT;
+ } else {
+ DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
+ }
+ }
+
+ if ((*ldap_struct = ldap_init(host, port)) == NULL) {
+ DEBUG(0, ("ldap_init failed !\n"));
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (strequal(protocol, "ldaps")) {
+#ifdef LDAP_OPT_X_TLS
+ int tls = LDAP_OPT_X_TLS_HARD;
+ if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
+ {
+ DEBUG(0, ("Failed to setup a TLS session\n"));
+ }
+
+ DEBUG(3,("LDAPS option set...!\n"));
+#else
+ DEBUG(0,("smbldap_open_connection: Secure connection not supported by LDAP client libraries!\n"));
+ return LDAP_OPERATIONS_ERROR;
+#endif /* LDAP_OPT_X_TLS */
+ }
+ }
+#endif /* HAVE_LDAP_INITIALIZE */
+
+
+ /* now set connection timeout */
+#ifdef LDAP_X_OPT_CONNECT_TIMEOUT /* Netscape */
+ {
+ int ct = lp_ldap_connection_timeout()*1000;
+ rc = ldap_set_option(*ldap_struct, LDAP_X_OPT_CONNECT_TIMEOUT, &ct);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("Failed to setup an ldap connection timeout %d: %s\n",
+ ct, ldap_err2string(rc)));
+ }
+ }
+#elif defined (LDAP_OPT_NETWORK_TIMEOUT) /* OpenLDAP */
+ {
+ struct timeval ct;
+ ct.tv_usec = 0;
+ ct.tv_sec = lp_ldap_connection_timeout();
+ rc = ldap_set_option(*ldap_struct, LDAP_OPT_NETWORK_TIMEOUT, &ct);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("Failed to setup an ldap connection timeout %d: %s\n",
+ (int)ct.tv_sec, ldap_err2string(rc)));
+ }
+ }
+#endif
+
+ return LDAP_SUCCESS;
+}
+
+/********************************************************************
+ try to upgrade to Version 3 LDAP if not already, in either case return current
+ version
+ *******************************************************************/
+
+int smb_ldap_upgrade_conn(LDAP *ldap_struct, int *new_version)
+{
+ int version;
+ int rc;
+
+ /* assume the worst */
+ *new_version = LDAP_VERSION2;
+
+ rc = ldap_get_option(ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
+ if (rc) {
+ return rc;
+ }
+
+ if (version == LDAP_VERSION3) {
+ *new_version = LDAP_VERSION3;
+ return LDAP_SUCCESS;
+ }
+
+ /* try upgrade */
+ version = LDAP_VERSION3;
+ rc = ldap_set_option (ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
+ if (rc) {
+ return rc;
+ }
+
+ *new_version = LDAP_VERSION3;
+ return LDAP_SUCCESS;
+}
+
+/*******************************************************************
+ open a connection to the ldap server (just until the bind)
+ ******************************************************************/
+
+int smb_ldap_setup_full_conn(LDAP **ldap_struct, const char *uri)
+{
+ int rc, version;
+
+ rc = smb_ldap_setup_conn(ldap_struct, uri);
+ if (rc) {
+ return rc;
+ }
+
+ rc = smb_ldap_upgrade_conn(*ldap_struct, &version);
+ if (rc) {
+ return rc;
+ }
+
+ rc = smb_ldap_start_tls(*ldap_struct, version);
+ if (rc) {
+ return rc;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+/*******************************************************************
+ open a connection to the ldap server.
+******************************************************************/
+static int smbldap_open_connection (struct smbldap_state *ldap_state)
+
+{
+ int rc = LDAP_SUCCESS;
+ int version;
+ LDAP **ldap_struct = &ldap_state->ldap_struct;
+
+ rc = smb_ldap_setup_conn(ldap_struct, ldap_state->uri);
+ if (rc) {
+ return rc;
+ }
+
+ /* Store the LDAP pointer in a lookup list */
+
+ smbldap_store_state(*ldap_struct, ldap_state);
+
+ /* Upgrade to LDAPv3 if possible */
+
+ rc = smb_ldap_upgrade_conn(*ldap_struct, &version);
+ if (rc) {
+ return rc;
+ }
+
+ /* Start TLS if required */
+
+ rc = smb_ldap_start_tls(*ldap_struct, version);
+ if (rc) {
+ return rc;
+ }
+
+ DEBUG(2, ("smbldap_open_connection: connection opened\n"));
+ return rc;
+}
+
+/*******************************************************************
+ a rebind function for authenticated referrals
+ This version takes a void* that we can shove useful stuff in :-)
+******************************************************************/
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+#else
+static int rebindproc_with_state (LDAP * ld, char **whop, char **credp,
+ int *methodp, int freeit, void *arg)
+{
+ struct smbldap_state *ldap_state = arg;
+
+ /** @TODO Should we be doing something to check what servers we rebind to?
+ Could we get a referral to a machine that we don't want to give our
+ username and password to? */
+
+ if (freeit) {
+ SAFE_FREE(*whop);
+ if (*credp) {
+ memset(*credp, '\0', strlen(*credp));
+ }
+ SAFE_FREE(*credp);
+ } else {
+ DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n",
+ ldap_state->bind_dn?ldap_state->bind_dn:"[Anonymous bind]"));
+
+ if (ldap_state->anonymous) {
+ *whop = NULL;
+ *credp = NULL;
+ } else {
+ *whop = SMB_STRDUP(ldap_state->bind_dn);
+ if (!*whop) {
+ return LDAP_NO_MEMORY;
+ }
+ *credp = SMB_STRDUP(ldap_state->bind_secret);
+ if (!*credp) {
+ SAFE_FREE(*whop);
+ return LDAP_NO_MEMORY;
+ }
+ }
+ *methodp = LDAP_AUTH_SIMPLE;
+ }
+
+ GetTimeOfDay(&ldap_state->last_rebind);
+
+ return 0;
+}
+#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
+
+/*******************************************************************
+ a rebind function for authenticated referrals
+ This version takes a void* that we can shove useful stuff in :-)
+ and actually does the connection.
+******************************************************************/
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+static int rebindproc_connect_with_state (LDAP *ldap_struct,
+ LDAP_CONST char *url,
+ ber_tag_t request,
+ ber_int_t msgid, void *arg)
+{
+ struct smbldap_state *ldap_state =
+ (struct smbldap_state *)arg;
+ int rc;
+ int version;
+
+ DEBUG(5,("rebindproc_connect_with_state: Rebinding to %s as \"%s\"\n",
+ url, ldap_state->bind_dn?ldap_state->bind_dn:"[Anonymous bind]"));
+
+ /* call START_TLS again (ldaps:// is handled by the OpenLDAP library
+ * itself) before rebinding to another LDAP server to avoid to expose
+ * our credentials. At least *try* to secure the connection - Guenther */
+
+ smb_ldap_upgrade_conn(ldap_struct, &version);
+ smb_ldap_start_tls(ldap_struct, version);
+
+ /** @TODO Should we be doing something to check what servers we rebind to?
+ Could we get a referral to a machine that we don't want to give our
+ username and password to? */
+
+ rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
+
+ /* only set the last rebind timestamp when we did rebind after a
+ * non-read LDAP operation. That way we avoid the replication sleep
+ * after a simple redirected search operation - Guenther */
+
+ switch (request) {
+
+ case LDAP_REQ_MODIFY:
+ case LDAP_REQ_ADD:
+ case LDAP_REQ_DELETE:
+ case LDAP_REQ_MODDN:
+ case LDAP_REQ_EXTENDED:
+ DEBUG(10,("rebindproc_connect_with_state: "
+ "setting last_rebind timestamp "
+ "(req: 0x%02x)\n", (unsigned int)request));
+ GetTimeOfDay(&ldap_state->last_rebind);
+ break;
+ default:
+ ZERO_STRUCT(ldap_state->last_rebind);
+ break;
+ }
+
+ return rc;
+}
+#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
+
+/*******************************************************************
+ Add a rebind function for authenticated referrals
+******************************************************************/
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+#else
+# if LDAP_SET_REBIND_PROC_ARGS == 2
+static int rebindproc (LDAP *ldap_struct, char **whop, char **credp,
+ int *method, int freeit )
+{
+ struct smbldap_state *ldap_state = smbldap_find_state(ldap_struct);
+
+ return rebindproc_with_state(ldap_struct, whop, credp,
+ method, freeit, ldap_state);
+
+}
+# endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
+#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
+
+/*******************************************************************
+ a rebind function for authenticated referrals
+ this also does the connection, but no void*.
+******************************************************************/
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+# if LDAP_SET_REBIND_PROC_ARGS == 2
+static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
+ ber_int_t msgid)
+{
+ struct smbldap_state *ldap_state = smbldap_find_state(ld);
+
+ return rebindproc_connect_with_state(ld, url, (ber_tag_t)request, msgid,
+ ldap_state);
+}
+# endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
+#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
+
+/*******************************************************************
+ connect to the ldap server under system privilege.
+******************************************************************/
+static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_struct)
+{
+ int rc;
+ int version;
+
+ if (!ldap_state->anonymous && !ldap_state->bind_dn) {
+
+ /* get the default dn and password only if they are not set already */
+ if (!fetch_ldap_pw(&ldap_state->bind_dn, &ldap_state->bind_secret)) {
+ DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n"));
+ return LDAP_INVALID_CREDENTIALS;
+ }
+ }
+
+ /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
+ (OpenLDAP) doesnt' seem to support it */
+
+ DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n",
+ ldap_state->uri, ldap_state->bind_dn));
+
+#ifdef HAVE_LDAP_SET_REBIND_PROC
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+# if LDAP_SET_REBIND_PROC_ARGS == 2
+ ldap_set_rebind_proc(ldap_struct, &rebindproc_connect);
+# endif
+# if LDAP_SET_REBIND_PROC_ARGS == 3
+ ldap_set_rebind_proc(ldap_struct, &rebindproc_connect_with_state, (void *)ldap_state);
+# endif
+#else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
+# if LDAP_SET_REBIND_PROC_ARGS == 2
+ ldap_set_rebind_proc(ldap_struct, &rebindproc);
+# endif
+# if LDAP_SET_REBIND_PROC_ARGS == 3
+ ldap_set_rebind_proc(ldap_struct, &rebindproc_with_state, (void *)ldap_state);
+# endif
+#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
+#endif
+
+ rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
+
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
+ &ld_error);
+ DEBUG(ldap_state->num_failures ? 2 : 0,
+ ("failed to bind to server %s with dn=\"%s\" Error: %s\n\t%s\n",
+ ldap_state->uri,
+ ldap_state->bind_dn ? ldap_state->bind_dn : "[Anonymous bind]",
+ ldap_err2string(rc),
+ ld_error ? ld_error : "(unknown)"));
+ SAFE_FREE(ld_error);
+ ldap_state->num_failures++;
+ return rc;
+ }
+
+ ldap_state->num_failures = 0;
+ ldap_state->paged_results = False;
+
+ ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
+
+ if (smbldap_has_control(ldap_state->ldap_struct, ADS_PAGE_CTL_OID) && version == 3) {
+ ldap_state->paged_results = True;
+ }
+
+ DEBUG(3, ("ldap_connect_system: successful connection to the LDAP server\n"));
+ DEBUGADD(10, ("ldap_connect_system: LDAP server %s support paged results\n",
+ ldap_state->paged_results ? "does" : "does not"));
+ return rc;
+}
+
+static void smbldap_idle_fn(struct event_context *event_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data);
+
+/**********************************************************************
+ Connect to LDAP server (called before every ldap operation)
+*********************************************************************/
+static int smbldap_open(struct smbldap_state *ldap_state)
+{
+ int rc, opt_rc;
+ bool reopen = False;
+ SMB_ASSERT(ldap_state);
+
+#ifndef NO_LDAP_SECURITY
+ if (geteuid() != 0) {
+ DEBUG(0, ("smbldap_open: cannot access LDAP when not root\n"));
+ return LDAP_INSUFFICIENT_ACCESS;
+ }
+#endif
+
+ if ((ldap_state->ldap_struct != NULL) && ((ldap_state->last_ping + SMBLDAP_DONT_PING_TIME) < time(NULL))) {
+
+#ifdef HAVE_UNIXSOCKET
+ struct sockaddr_un addr;
+#else
+ struct sockaddr addr;
+#endif
+ socklen_t len = sizeof(addr);
+ int sd;
+
+ opt_rc = ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_DESC, &sd);
+ if (opt_rc == 0 && (getpeername(sd, (struct sockaddr *) &addr, &len)) < 0 )
+ reopen = True;
+
+#ifdef HAVE_UNIXSOCKET
+ if (opt_rc == 0 && addr.sun_family == AF_UNIX)
+ reopen = True;
+#endif
+ if (reopen) {
+ /* the other end has died. reopen. */
+ ldap_unbind(ldap_state->ldap_struct);
+ ldap_state->ldap_struct = NULL;
+ ldap_state->last_ping = (time_t)0;
+ } else {
+ ldap_state->last_ping = time(NULL);
+ }
+ }
+
+ if (ldap_state->ldap_struct != NULL) {
+ DEBUG(11,("smbldap_open: already connected to the LDAP server\n"));
+ return LDAP_SUCCESS;
+ }
+
+ if ((rc = smbldap_open_connection(ldap_state))) {
+ return rc;
+ }
+
+ if ((rc = smbldap_connect_system(ldap_state, ldap_state->ldap_struct))) {
+ ldap_unbind(ldap_state->ldap_struct);
+ ldap_state->ldap_struct = NULL;
+ return rc;
+ }
+
+
+ ldap_state->last_ping = time(NULL);
+ ldap_state->pid = sys_getpid();
+
+ TALLOC_FREE(ldap_state->idle_event);
+
+ if (ldap_state->event_context != NULL) {
+ ldap_state->idle_event = event_add_timed(
+ ldap_state->event_context, NULL,
+ timeval_current_ofs(SMBLDAP_IDLE_TIME, 0),
+ "smbldap_idle_fn", smbldap_idle_fn, ldap_state);
+ }
+
+ DEBUG(4,("The LDAP server is successfully connected\n"));
+
+ return LDAP_SUCCESS;
+}
+
+/**********************************************************************
+Disconnect from LDAP server
+*********************************************************************/
+static NTSTATUS smbldap_close(struct smbldap_state *ldap_state)
+{
+ if (!ldap_state)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ if (ldap_state->ldap_struct != NULL) {
+ ldap_unbind(ldap_state->ldap_struct);
+ ldap_state->ldap_struct = NULL;
+ }
+
+ smbldap_delete_state(ldap_state);
+
+ DEBUG(5,("The connection to the LDAP server was closed\n"));
+ /* maybe free the results here --metze */
+
+ return NT_STATUS_OK;
+}
+
+static bool got_alarm;
+
+static void (*old_handler)(int);
+
+static void gotalarm_sig(int dummy)
+{
+ got_alarm = True;
+}
+
+static int another_ldap_try(struct smbldap_state *ldap_state, int *rc,
+ int *attempts, time_t endtime)
+{
+ time_t now = time(NULL);
+ int open_rc = LDAP_SERVER_DOWN;
+
+ if (*rc != LDAP_SERVER_DOWN)
+ goto no_next;
+
+ if (now >= endtime) {
+ smbldap_close(ldap_state);
+ *rc = LDAP_TIMEOUT;
+ goto no_next;
+ }
+
+ if (*attempts == 0) {
+ got_alarm = False;
+ old_handler = CatchSignal(SIGALRM, gotalarm_sig);
+ alarm(endtime - now);
+
+ if (ldap_state->pid != sys_getpid())
+ smbldap_close(ldap_state);
+ }
+
+ while (1) {
+
+ if (*attempts != 0)
+ smb_msleep(1000);
+
+ *attempts += 1;
+
+ open_rc = smbldap_open(ldap_state);
+
+ if (open_rc == LDAP_SUCCESS) {
+ ldap_state->last_use = now;
+ return True;
+ }
+
+ if (open_rc == LDAP_INSUFFICIENT_ACCESS) {
+ /* The fact that we are non-root or any other
+ * access-denied condition will not change in the next
+ * round of trying */
+ *rc = open_rc;
+ break;
+ }
+
+ if (got_alarm) {
+ *rc = LDAP_TIMEOUT;
+ break;
+ }
+
+ if (open_rc != LDAP_SUCCESS) {
+ DEBUG(1, ("Connection to LDAP server failed for the "
+ "%d try!\n", *attempts));
+ }
+ }
+
+ no_next:
+ CatchSignal(SIGALRM, old_handler);
+ alarm(0);
+ ldap_state->last_use = now;
+ return False;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+static int smbldap_search_ext(struct smbldap_state *ldap_state,
+ const char *base, int scope, const char *filter,
+ const char *attrs[], int attrsonly,
+ LDAPControl **sctrls, LDAPControl **cctrls,
+ int sizelimit, LDAPMessage **res)
+{
+ int rc = LDAP_SERVER_DOWN;
+ int attempts = 0;
+ char *utf8_filter;
+ time_t endtime = time(NULL)+lp_ldap_timeout();
+ struct timeval timeout;
+ size_t converted_size;
+
+ SMB_ASSERT(ldap_state);
+
+ DEBUG(5,("smbldap_search_ext: base => [%s], filter => [%s], "
+ "scope => [%d]\n", base, filter, scope));
+
+ if (ldap_state->last_rebind.tv_sec > 0) {
+ struct timeval tval;
+ SMB_BIG_INT tdiff = 0;
+ int sleep_time = 0;
+
+ ZERO_STRUCT(tval);
+ GetTimeOfDay(&tval);
+
+ tdiff = usec_time_diff(&tval, &ldap_state->last_rebind);
+ tdiff /= 1000; /* Convert to milliseconds. */
+
+ sleep_time = lp_ldap_replication_sleep()-(int)tdiff;
+ sleep_time = MIN(sleep_time, MAX_LDAP_REPLICATION_SLEEP_TIME);
+
+ if (sleep_time > 0) {
+ /* we wait for the LDAP replication */
+ DEBUG(5,("smbldap_search_ext: waiting %d milliseconds "
+ "for LDAP replication.\n",sleep_time));
+ smb_msleep(sleep_time);
+ DEBUG(5,("smbldap_search_ext: go on!\n"));
+ }
+ ZERO_STRUCT(ldap_state->last_rebind);
+ }
+
+ if (!push_utf8_allocate(&utf8_filter, filter, &converted_size)) {
+ return LDAP_NO_MEMORY;
+ }
+
+ /* Setup timeout for the ldap_search_ext_s call - local and remote. */
+ timeout.tv_sec = lp_ldap_timeout();
+ timeout.tv_usec = 0;
+
+ /* Setup alarm timeout.... Do we need both of these ? JRA.
+ * Yes, I think we do need both of these. The server timeout only
+ * covers the case where the server's operation takes too long. It
+ * does not cover the case where the request hangs on its way to the
+ * server. The server side timeout is not strictly necessary, it's
+ * just a bit more kind to the server. VL. */
+
+ got_alarm = 0;
+ CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+ alarm(lp_ldap_timeout());
+ /* End setup timeout. */
+
+ while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) {
+ rc = ldap_search_ext_s(ldap_state->ldap_struct, base, scope,
+ utf8_filter,
+ CONST_DISCARD(char **, attrs),
+ attrsonly, sctrls, cctrls, &timeout,
+ sizelimit, res);
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ int ld_errno;
+
+ ldap_get_option(ldap_state->ldap_struct,
+ LDAP_OPT_ERROR_NUMBER, &ld_errno);
+
+ ldap_get_option(ldap_state->ldap_struct,
+ LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(10, ("Failed search for base: %s, error: %d (%s) "
+ "(%s)\n", base, ld_errno,
+ ldap_err2string(rc),
+ ld_error ? ld_error : "unknown"));
+ SAFE_FREE(ld_error);
+
+ if (ld_errno == LDAP_SERVER_DOWN) {
+ ldap_unbind(ldap_state->ldap_struct);
+ ldap_state->ldap_struct = NULL;
+ }
+ }
+ }
+
+ SAFE_FREE(utf8_filter);
+
+ /* Teardown timeout. */
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
+ alarm(0);
+
+ if (got_alarm != 0)
+ return LDAP_TIMELIMIT_EXCEEDED;
+
+ return rc;
+}
+
+int smbldap_search(struct smbldap_state *ldap_state,
+ const char *base, int scope, const char *filter,
+ const char *attrs[], int attrsonly,
+ LDAPMessage **res)
+{
+ return smbldap_search_ext(ldap_state, base, scope, filter, attrs,
+ attrsonly, NULL, NULL, LDAP_NO_LIMIT, res);
+}
+
+int smbldap_search_paged(struct smbldap_state *ldap_state,
+ const char *base, int scope, const char *filter,
+ const char **attrs, int attrsonly, int pagesize,
+ LDAPMessage **res, void **cookie)
+{
+ LDAPControl pr;
+ LDAPControl **rcontrols;
+ LDAPControl *controls[2] = { NULL, NULL};
+ BerElement *cookie_be = NULL;
+ struct berval *cookie_bv = NULL;
+ int tmp = 0, i, rc;
+ bool critical = True;
+
+ *res = NULL;
+
+ DEBUG(3,("smbldap_search_paged: base => [%s], filter => [%s],"
+ "scope => [%d], pagesize => [%d]\n",
+ base, filter, scope, pagesize));
+
+ cookie_be = ber_alloc_t(LBER_USE_DER);
+ if (cookie_be == NULL) {
+ DEBUG(0,("smbldap_create_page_control: ber_alloc_t returns "
+ "NULL\n"));
+ return LDAP_NO_MEMORY;
+ }
+
+ /* construct cookie */
+ if (*cookie != NULL) {
+ ber_printf(cookie_be, "{iO}", (ber_int_t) pagesize, *cookie);
+ ber_bvfree((struct berval *)*cookie); /* don't need it from last time */
+ *cookie = NULL;
+ } else {
+ ber_printf(cookie_be, "{io}", (ber_int_t) pagesize, "", 0);
+ }
+ ber_flatten(cookie_be, &cookie_bv);
+
+ pr.ldctl_oid = CONST_DISCARD(char *, ADS_PAGE_CTL_OID);
+ pr.ldctl_iscritical = (char) critical;
+ pr.ldctl_value.bv_len = cookie_bv->bv_len;
+ pr.ldctl_value.bv_val = cookie_bv->bv_val;
+
+ controls[0] = &pr;
+ controls[1] = NULL;
+
+ rc = smbldap_search_ext(ldap_state, base, scope, filter, attrs,
+ 0, controls, NULL, LDAP_NO_LIMIT, res);
+
+ ber_free(cookie_be, 1);
+ ber_bvfree(cookie_bv);
+
+ if (rc != 0) {
+ DEBUG(3,("smbldap_search_paged: smbldap_search_ext(%s) "
+ "failed with [%s]\n", filter, ldap_err2string(rc)));
+ goto done;
+ }
+
+ DEBUG(3,("smbldap_search_paged: search was successfull\n"));
+
+ rc = ldap_parse_result(ldap_state->ldap_struct, *res, NULL, NULL,
+ NULL, NULL, &rcontrols, 0);
+ if (rc != 0) {
+ DEBUG(3,("smbldap_search_paged: ldap_parse_result failed " \
+ "with [%s]\n", ldap_err2string(rc)));
+ goto done;
+ }
+
+ if (rcontrols == NULL)
+ goto done;
+
+ for (i=0; rcontrols[i]; i++) {
+
+ if (strcmp(ADS_PAGE_CTL_OID, rcontrols[i]->ldctl_oid) != 0)
+ continue;
+
+ cookie_be = ber_init(&rcontrols[i]->ldctl_value);
+ ber_scanf(cookie_be,"{iO}", &tmp, &cookie_bv);
+ /* the berval is the cookie, but must be freed when it is all
+ done */
+ if (cookie_bv->bv_len)
+ *cookie=ber_bvdup(cookie_bv);
+ else
+ *cookie=NULL;
+ ber_bvfree(cookie_bv);
+ ber_free(cookie_be, 1);
+ break;
+ }
+ ldap_controls_free(rcontrols);
+done:
+ return rc;
+}
+
+int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
+{
+ int rc = LDAP_SERVER_DOWN;
+ int attempts = 0;
+ char *utf8_dn;
+ time_t endtime = time(NULL)+lp_ldap_timeout();
+ size_t converted_size;
+
+ SMB_ASSERT(ldap_state);
+
+ DEBUG(5,("smbldap_modify: dn => [%s]\n", dn ));
+
+ if (!push_utf8_allocate(&utf8_dn, dn, &converted_size)) {
+ return LDAP_NO_MEMORY;
+ }
+
+ while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) {
+ rc = ldap_modify_s(ldap_state->ldap_struct, utf8_dn, attrs);
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ int ld_errno;
+
+ ldap_get_option(ldap_state->ldap_struct,
+ LDAP_OPT_ERROR_NUMBER, &ld_errno);
+
+ ldap_get_option(ldap_state->ldap_struct,
+ LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(10, ("Failed to modify dn: %s, error: %d (%s) "
+ "(%s)\n", dn, ld_errno,
+ ldap_err2string(rc),
+ ld_error ? ld_error : "unknown"));
+ SAFE_FREE(ld_error);
+
+ if (ld_errno == LDAP_SERVER_DOWN) {
+ ldap_unbind(ldap_state->ldap_struct);
+ ldap_state->ldap_struct = NULL;
+ }
+ }
+ }
+
+ SAFE_FREE(utf8_dn);
+ return rc;
+}
+
+int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
+{
+ int rc = LDAP_SERVER_DOWN;
+ int attempts = 0;
+ char *utf8_dn;
+ time_t endtime = time(NULL)+lp_ldap_timeout();
+ size_t converted_size;
+
+ SMB_ASSERT(ldap_state);
+
+ DEBUG(5,("smbldap_add: dn => [%s]\n", dn ));
+
+ if (!push_utf8_allocate(&utf8_dn, dn, &converted_size)) {
+ return LDAP_NO_MEMORY;
+ }
+
+ while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) {
+ rc = ldap_add_s(ldap_state->ldap_struct, utf8_dn, attrs);
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ int ld_errno;
+
+ ldap_get_option(ldap_state->ldap_struct,
+ LDAP_OPT_ERROR_NUMBER, &ld_errno);
+
+ ldap_get_option(ldap_state->ldap_struct,
+ LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(10, ("Failed to add dn: %s, error: %d (%s) "
+ "(%s)\n", dn, ld_errno,
+ ldap_err2string(rc),
+ ld_error ? ld_error : "unknown"));
+ SAFE_FREE(ld_error);
+
+ if (ld_errno == LDAP_SERVER_DOWN) {
+ ldap_unbind(ldap_state->ldap_struct);
+ ldap_state->ldap_struct = NULL;
+ }
+ }
+ }
+
+ SAFE_FREE(utf8_dn);
+ return rc;
+}
+
+int smbldap_delete(struct smbldap_state *ldap_state, const char *dn)
+{
+ int rc = LDAP_SERVER_DOWN;
+ int attempts = 0;
+ char *utf8_dn;
+ time_t endtime = time(NULL)+lp_ldap_timeout();
+ size_t converted_size;
+
+ SMB_ASSERT(ldap_state);
+
+ DEBUG(5,("smbldap_delete: dn => [%s]\n", dn ));
+
+ if (!push_utf8_allocate(&utf8_dn, dn, &converted_size)) {
+ return LDAP_NO_MEMORY;
+ }
+
+ while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) {
+ rc = ldap_delete_s(ldap_state->ldap_struct, utf8_dn);
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ int ld_errno;
+
+ ldap_get_option(ldap_state->ldap_struct,
+ LDAP_OPT_ERROR_NUMBER, &ld_errno);
+
+ ldap_get_option(ldap_state->ldap_struct,
+ LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(10, ("Failed to delete dn: %s, error: %d (%s) "
+ "(%s)\n", dn, ld_errno,
+ ldap_err2string(rc),
+ ld_error ? ld_error : "unknown"));
+ SAFE_FREE(ld_error);
+
+ if (ld_errno == LDAP_SERVER_DOWN) {
+ ldap_unbind(ldap_state->ldap_struct);
+ ldap_state->ldap_struct = NULL;
+ }
+ }
+ }
+
+ SAFE_FREE(utf8_dn);
+ return rc;
+}
+
+int smbldap_extended_operation(struct smbldap_state *ldap_state,
+ LDAP_CONST char *reqoid, struct berval *reqdata,
+ LDAPControl **serverctrls, LDAPControl **clientctrls,
+ char **retoidp, struct berval **retdatap)
+{
+ int rc = LDAP_SERVER_DOWN;
+ int attempts = 0;
+ time_t endtime = time(NULL)+lp_ldap_timeout();
+
+ if (!ldap_state)
+ return (-1);
+
+ while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) {
+ rc = ldap_extended_operation_s(ldap_state->ldap_struct, reqoid,
+ reqdata, serverctrls,
+ clientctrls, retoidp, retdatap);
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ int ld_errno;
+
+ ldap_get_option(ldap_state->ldap_struct,
+ LDAP_OPT_ERROR_NUMBER, &ld_errno);
+
+ ldap_get_option(ldap_state->ldap_struct,
+ LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(10, ("Extended operation failed with error: "
+ "%d (%s) (%s)\n", ld_errno,
+ ldap_err2string(rc),
+ ld_error ? ld_error : "unknown"));
+ SAFE_FREE(ld_error);
+
+ if (ld_errno == LDAP_SERVER_DOWN) {
+ ldap_unbind(ldap_state->ldap_struct);
+ ldap_state->ldap_struct = NULL;
+ }
+ }
+ }
+
+ return rc;
+}
+
+/*******************************************************************
+ run the search by name.
+******************************************************************/
+int smbldap_search_suffix (struct smbldap_state *ldap_state,
+ const char *filter, const char **search_attr,
+ LDAPMessage ** result)
+{
+ return smbldap_search(ldap_state, lp_ldap_suffix(), LDAP_SCOPE_SUBTREE,
+ filter, search_attr, 0, result);
+}
+
+static void smbldap_idle_fn(struct event_context *event_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ struct smbldap_state *state = (struct smbldap_state *)private_data;
+
+ TALLOC_FREE(state->idle_event);
+
+ if (state->ldap_struct == NULL) {
+ DEBUG(10,("ldap connection not connected...\n"));
+ return;
+ }
+
+ if ((state->last_use+SMBLDAP_IDLE_TIME) > now->tv_sec) {
+ DEBUG(10,("ldap connection not idle...\n"));
+
+ state->idle_event = event_add_timed(
+ event_ctx, NULL,
+ timeval_add(now, SMBLDAP_IDLE_TIME, 0),
+ "smbldap_idle_fn", smbldap_idle_fn,
+ private_data);
+ return;
+ }
+
+ DEBUG(7,("ldap connection idle...closing connection\n"));
+ smbldap_close(state);
+}
+
+/**********************************************************************
+ Housekeeping
+ *********************************************************************/
+
+void smbldap_free_struct(struct smbldap_state **ldap_state)
+{
+ smbldap_close(*ldap_state);
+
+ if ((*ldap_state)->bind_secret) {
+ memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret));
+ }
+
+ SAFE_FREE((*ldap_state)->bind_dn);
+ SAFE_FREE((*ldap_state)->bind_secret);
+
+ TALLOC_FREE((*ldap_state)->idle_event);
+
+ *ldap_state = NULL;
+
+ /* No need to free any further, as it is talloc()ed */
+}
+
+
+/**********************************************************************
+ Intitalise the 'general' ldap structures, on which ldap operations may be conducted
+ *********************************************************************/
+
+NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, struct event_context *event_ctx,
+ const char *location,
+ struct smbldap_state **smbldap_state)
+{
+ *smbldap_state = TALLOC_ZERO_P(mem_ctx, struct smbldap_state);
+ if (!*smbldap_state) {
+ DEBUG(0, ("talloc() failed for ldapsam private_data!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (location) {
+ (*smbldap_state)->uri = talloc_strdup(mem_ctx, location);
+ } else {
+ (*smbldap_state)->uri = "ldap://localhost";
+ }
+
+ (*smbldap_state)->event_context = event_ctx;
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Return a copy of the DN for a LDAPMessage. Convert from utf8 to CH_UNIX.
+********************************************************************/
+char *smbldap_get_dn(LDAP *ld, LDAPMessage *entry)
+{
+ char *utf8_dn, *unix_dn;
+ size_t converted_size;
+
+ utf8_dn = ldap_get_dn(ld, entry);
+ if (!utf8_dn) {
+ DEBUG (5, ("smbldap_get_dn: ldap_get_dn failed\n"));
+ return NULL;
+ }
+ if (!pull_utf8_allocate(&unix_dn, utf8_dn, &converted_size)) {
+ DEBUG (0, ("smbldap_get_dn: String conversion failure utf8 "
+ "[%s]\n", utf8_dn));
+ return NULL;
+ }
+ ldap_memfree(utf8_dn);
+ return unix_dn;
+}
+
+ const char *smbldap_talloc_dn(TALLOC_CTX *mem_ctx, LDAP *ld,
+ LDAPMessage *entry)
+{
+ char *utf8_dn, *unix_dn;
+ size_t converted_size;
+
+ utf8_dn = ldap_get_dn(ld, entry);
+ if (!utf8_dn) {
+ DEBUG (5, ("smbldap_get_dn: ldap_get_dn failed\n"));
+ return NULL;
+ }
+ if (!pull_utf8_talloc(mem_ctx, &unix_dn, utf8_dn, &converted_size)) {
+ DEBUG (0, ("smbldap_get_dn: String conversion failure utf8 "
+ "[%s]\n", utf8_dn));
+ return NULL;
+ }
+ ldap_memfree(utf8_dn);
+ return unix_dn;
+}
+
+/*******************************************************************
+ Check if root-dse has a certain Control or Extension
+********************************************************************/
+
+static bool smbldap_check_root_dse(LDAP *ld, const char **attrs, const char *value)
+{
+ LDAPMessage *msg = NULL;
+ LDAPMessage *entry = NULL;
+ char **values = NULL;
+ int rc, num_result, num_values, i;
+ bool result = False;
+
+ if (!attrs[0]) {
+ DEBUG(3,("smbldap_check_root_dse: nothing to look for\n"));
+ return False;
+ }
+
+ if (!strequal(attrs[0], "supportedExtension") &&
+ !strequal(attrs[0], "supportedControl") &&
+ !strequal(attrs[0], "namingContexts")) {
+ DEBUG(3,("smbldap_check_root_dse: no idea what to query root-dse for: %s ?\n", attrs[0]));
+ return False;
+ }
+
+ rc = ldap_search_s(ld, "", LDAP_SCOPE_BASE,
+ "(objectclass=*)", CONST_DISCARD(char **, attrs), 0 , &msg);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(3,("smbldap_check_root_dse: Could not search rootDSE\n"));
+ return False;
+ }
+
+ num_result = ldap_count_entries(ld, msg);
+
+ if (num_result != 1) {
+ DEBUG(3,("smbldap_check_root_dse: Expected one rootDSE, got %d\n", num_result));
+ goto done;
+ }
+
+ entry = ldap_first_entry(ld, msg);
+
+ if (entry == NULL) {
+ DEBUG(3,("smbldap_check_root_dse: Could not retrieve rootDSE\n"));
+ goto done;
+ }
+
+ values = ldap_get_values(ld, entry, attrs[0]);
+
+ if (values == NULL) {
+ DEBUG(5,("smbldap_check_root_dse: LDAP Server does not support any %s\n", attrs[0]));
+ goto done;
+ }
+
+ num_values = ldap_count_values(values);
+
+ if (num_values == 0) {
+ DEBUG(5,("smbldap_check_root_dse: LDAP Server does not have any %s\n", attrs[0]));
+ goto done;
+ }
+
+ for (i=0; i<num_values; i++) {
+ if (strcmp(values[i], value) == 0)
+ result = True;
+ }
+
+
+ done:
+ if (values != NULL)
+ ldap_value_free(values);
+ if (msg != NULL)
+ ldap_msgfree(msg);
+
+ return result;
+
+}
+
+/*******************************************************************
+ Check if LDAP-Server supports a certain Control (OID in string format)
+********************************************************************/
+
+bool smbldap_has_control(LDAP *ld, const char *control)
+{
+ const char *attrs[] = { "supportedControl", NULL };
+ return smbldap_check_root_dse(ld, attrs, control);
+}
+
+/*******************************************************************
+ Check if LDAP-Server supports a certain Extension (OID in string format)
+********************************************************************/
+
+bool smbldap_has_extension(LDAP *ld, const char *extension)
+{
+ const char *attrs[] = { "supportedExtension", NULL };
+ return smbldap_check_root_dse(ld, attrs, extension);
+}
+
+/*******************************************************************
+ Check if LDAP-Server holds a given namingContext
+********************************************************************/
+
+bool smbldap_has_naming_context(LDAP *ld, const char *naming_context)
+{
+ const char *attrs[] = { "namingContexts", NULL };
+ return smbldap_check_root_dse(ld, attrs, naming_context);
+}
+
+bool smbldap_set_creds(struct smbldap_state *ldap_state, bool anon, const char *dn, const char *secret)
+{
+ ldap_state->anonymous = anon;
+
+ /* free any previously set credential */
+
+ SAFE_FREE(ldap_state->bind_dn);
+ if (ldap_state->bind_secret) {
+ /* make sure secrets are zeroed out of memory */
+ memset(ldap_state->bind_secret, '\0', strlen(ldap_state->bind_secret));
+ SAFE_FREE(ldap_state->bind_secret);
+ }
+
+ if ( ! anon) {
+ ldap_state->bind_dn = SMB_STRDUP(dn);
+ ldap_state->bind_secret = SMB_STRDUP(secret);
+ }
+
+ return True;
+}
diff --git a/source3/lib/smbldap_util.c b/source3/lib/smbldap_util.c
new file mode 100644
index 0000000000..66aef6ba66
--- /dev/null
+++ b/source3/lib/smbldap_util.c
@@ -0,0 +1,334 @@
+/*
+ Unix SMB/CIFS mplementation.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Jean François Micouleau 1998
+ Copyright (C) Gerald Carter 2001-2003
+ Copyright (C) Shahms King 2001
+ Copyright (C) Andrew Bartlett 2002-2003
+ Copyright (C) Stefan (metze) Metzmacher 2002-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include "smbldap.h"
+
+/**********************************************************************
+ Add the account-policies below the sambaDomain object to LDAP,
+*********************************************************************/
+
+static NTSTATUS add_new_domain_account_policies(struct smbldap_state *ldap_state,
+ const char *domain_name)
+{
+ NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL;
+ int i, rc;
+ uint32 policy_default;
+ const char *policy_attr = NULL;
+ char *dn = NULL;
+ LDAPMod **mods = NULL;
+ char *escape_domain_name;
+
+ DEBUG(3,("add_new_domain_account_policies: Adding new account policies for domain\n"));
+
+ escape_domain_name = escape_rdn_val_string_alloc(domain_name);
+ if (!escape_domain_name) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (asprintf(&dn, "%s=%s,%s",
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
+ escape_domain_name, lp_ldap_suffix()) < 0) {
+ SAFE_FREE(escape_domain_name);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SAFE_FREE(escape_domain_name);
+
+ for (i=1; decode_account_policy_name(i) != NULL; i++) {
+ char *val = NULL;
+
+ policy_attr = get_account_policy_attr(i);
+ if (!policy_attr) {
+ DEBUG(0,("add_new_domain_account_policies: ops. no policy!\n"));
+ continue;
+ }
+
+ if (!account_policy_get_default(i, &policy_default)) {
+ DEBUG(0,("add_new_domain_account_policies: failed to get default account policy\n"));
+ SAFE_FREE(dn);
+ return ntstatus;
+ }
+
+ DEBUG(10,("add_new_domain_account_policies: adding \"%s\" with value: %d\n", policy_attr, policy_default));
+
+ if (asprintf(&val, "%d", policy_default) < 0) {
+ SAFE_FREE(dn);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ smbldap_set_mod( &mods, LDAP_MOD_REPLACE, policy_attr, val);
+
+ rc = smbldap_modify(ldap_state, dn, mods);
+
+ SAFE_FREE(val);
+
+ if (rc!=LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(1,("add_new_domain_account_policies: failed to add account policies to dn= %s with: %s\n\t%s\n",
+ dn, ldap_err2string(rc),
+ ld_error ? ld_error : "unknown"));
+ SAFE_FREE(ld_error);
+ SAFE_FREE(dn);
+ ldap_mods_free(mods, True);
+ return ntstatus;
+ }
+ }
+
+ SAFE_FREE(dn);
+ ldap_mods_free(mods, True);
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Add the sambaDomain to LDAP, so we don't have to search for this stuff
+ again. This is a once-add operation for now.
+
+ TODO: Add other attributes, and allow modification.
+*********************************************************************/
+
+static NTSTATUS add_new_domain_info(struct smbldap_state *ldap_state,
+ const char *domain_name)
+{
+ fstring sid_string;
+ fstring algorithmic_rid_base_string;
+ char *filter = NULL;
+ char *dn = NULL;
+ LDAPMod **mods = NULL;
+ int rc;
+ LDAPMessage *result = NULL;
+ int num_result;
+ const char **attr_list;
+ char *escape_domain_name;
+
+ /* escape for filter */
+ escape_domain_name = escape_ldap_string_alloc(domain_name);
+ if (!escape_domain_name) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (asprintf(&filter, "(&(%s=%s)(objectclass=%s))",
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
+ escape_domain_name, LDAP_OBJ_DOMINFO) < 0) {
+ SAFE_FREE(escape_domain_name);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SAFE_FREE(escape_domain_name);
+
+ attr_list = get_attr_list(NULL, dominfo_attr_list );
+ rc = smbldap_search_suffix(ldap_state, filter, attr_list, &result);
+ TALLOC_FREE( attr_list );
+ SAFE_FREE(filter);
+
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ num_result = ldap_count_entries(ldap_state->ldap_struct, result);
+
+ if (num_result > 1) {
+ DEBUG (0, ("add_new_domain_info: More than domain with that name exists: bailing "
+ "out!\n"));
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* Check if we need to add an entry */
+ DEBUG(3,("add_new_domain_info: Adding new domain\n"));
+
+ /* this time escape for DN */
+ escape_domain_name = escape_rdn_val_string_alloc(domain_name);
+ if (!escape_domain_name) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (asprintf(&dn, "%s=%s,%s",
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
+ escape_domain_name, lp_ldap_suffix()) < 0) {
+ SAFE_FREE(escape_domain_name);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SAFE_FREE(escape_domain_name);
+
+ /* Free original search */
+ ldap_msgfree(result);
+
+ /* make the changes - the entry *must* not already have samba
+ * attributes */
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD,
+ get_attr_key2string(dominfo_attr_list,
+ LDAP_ATTR_DOMAIN),
+ domain_name);
+
+ /* If we don't have an entry, then ask secrets.tdb for what it thinks.
+ It may choose to make it up */
+
+ sid_to_fstring(sid_string, get_global_sam_sid());
+ smbldap_set_mod(&mods, LDAP_MOD_ADD,
+ get_attr_key2string(dominfo_attr_list,
+ LDAP_ATTR_DOM_SID),
+ sid_string);
+
+ slprintf(algorithmic_rid_base_string,
+ sizeof(algorithmic_rid_base_string) - 1, "%i",
+ algorithmic_rid_base());
+ smbldap_set_mod(&mods, LDAP_MOD_ADD,
+ get_attr_key2string(dominfo_attr_list,
+ LDAP_ATTR_ALGORITHMIC_RID_BASE),
+ algorithmic_rid_base_string);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_DOMINFO);
+
+ /* add the sambaNextUserRid attributes. */
+
+ {
+ uint32 rid = BASE_RID;
+ fstring rid_str;
+
+ fstr_sprintf( rid_str, "%i", rid );
+ DEBUG(10,("add_new_domain_info: setting next available user rid [%s]\n", rid_str));
+ smbldap_set_mod(&mods, LDAP_MOD_ADD,
+ get_attr_key2string(dominfo_attr_list,
+ LDAP_ATTR_NEXT_USERRID),
+ rid_str);
+ }
+
+
+ rc = smbldap_add(ldap_state, dn, mods);
+
+ if (rc!=LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ ldap_get_option(ldap_state->ldap_struct,
+ LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(1,("add_new_domain_info: failed to add domain dn= %s with: %s\n\t%s\n",
+ dn, ldap_err2string(rc),
+ ld_error?ld_error:"unknown"));
+ SAFE_FREE(ld_error);
+ SAFE_FREE(dn);
+ ldap_mods_free(mods, True);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(2,("add_new_domain_info: added: domain = %s in the LDAP database\n", domain_name));
+ ldap_mods_free(mods, True);
+ SAFE_FREE(dn);
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+Search for the domain info entry
+*********************************************************************/
+
+NTSTATUS smbldap_search_domain_info(struct smbldap_state *ldap_state,
+ LDAPMessage ** result, const char *domain_name,
+ bool try_add)
+{
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ char *filter = NULL;
+ int rc;
+ const char **attr_list;
+ int count;
+ char *escape_domain_name;
+
+ escape_domain_name = escape_ldap_string_alloc(domain_name);
+ if (!escape_domain_name) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (asprintf(&filter, "(&(objectClass=%s)(%s=%s))",
+ LDAP_OBJ_DOMINFO,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
+ escape_domain_name) < 0) {
+ SAFE_FREE(escape_domain_name);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SAFE_FREE(escape_domain_name);
+
+ DEBUG(2, ("smbldap_search_domain_info: Searching for:[%s]\n", filter));
+
+ attr_list = get_attr_list( NULL, dominfo_attr_list );
+ rc = smbldap_search_suffix(ldap_state, filter, attr_list , result);
+ TALLOC_FREE( attr_list );
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(2,("smbldap_search_domain_info: Problem during LDAPsearch: %s\n", ldap_err2string (rc)));
+ DEBUG(2,("smbldap_search_domain_info: Query was: %s, %s\n", lp_ldap_suffix(), filter));
+ goto failed;
+ }
+
+ SAFE_FREE(filter);
+
+ count = ldap_count_entries(ldap_state->ldap_struct, *result);
+
+ if (count == 1) {
+ return NT_STATUS_OK;
+ }
+
+ ldap_msgfree(*result);
+ *result = NULL;
+
+ if (count < 1) {
+
+ DEBUG(3, ("smbldap_search_domain_info: Got no domain info entries for domain\n"));
+
+ if (!try_add)
+ goto failed;
+
+ status = add_new_domain_info(ldap_state, domain_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("smbldap_search_domain_info: Adding domain info for %s failed with %s\n",
+ domain_name, nt_errstr(status)));
+ goto failed;
+ }
+
+ status = add_new_domain_account_policies(ldap_state, domain_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("smbldap_search_domain_info: Adding domain account policies for %s failed with %s\n",
+ domain_name, nt_errstr(status)));
+ goto failed;
+ }
+
+ return smbldap_search_domain_info(ldap_state, result, domain_name, False);
+
+ }
+
+ if (count > 1 ) {
+
+ DEBUG(0, ("smbldap_search_domain_info: Got too many (%d) domain info entries for domain %s\n",
+ count, domain_name));
+ goto failed;
+ }
+
+failed:
+ return status;
+}
diff --git a/source3/lib/smbrun.c b/source3/lib/smbrun.c
new file mode 100644
index 0000000000..515fcd75c2
--- /dev/null
+++ b/source3/lib/smbrun.c
@@ -0,0 +1,341 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* need to move this from here!! need some sleep ... */
+struct current_user current_user;
+
+/****************************************************************************
+This is a utility function of smbrun().
+****************************************************************************/
+
+static int setup_out_fd(void)
+{
+ int fd;
+ TALLOC_CTX *ctx = talloc_stackframe();
+ char *path = NULL;
+
+ path = talloc_asprintf(ctx,
+ "%s/smb.XXXXXX",
+ tmpdir());
+ if (!path) {
+ TALLOC_FREE(ctx);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* now create the file */
+ fd = smb_mkstemp(path);
+
+ if (fd == -1) {
+ DEBUG(0,("setup_out_fd: Failed to create file %s. (%s)\n",
+ path, strerror(errno) ));
+ TALLOC_FREE(ctx);
+ return -1;
+ }
+
+ DEBUG(10,("setup_out_fd: Created tmp file %s\n", path ));
+
+ /* Ensure file only kept around by open fd. */
+ unlink(path);
+ TALLOC_FREE(ctx);
+ return fd;
+}
+
+/****************************************************************************
+run a command being careful about uid/gid handling and putting the output in
+outfd (or discard it if outfd is NULL).
+****************************************************************************/
+
+static int smbrun_internal(const char *cmd, int *outfd, bool sanitize)
+{
+ pid_t pid;
+ uid_t uid = current_user.ut.uid;
+ gid_t gid = current_user.ut.gid;
+
+ /*
+ * Lose any elevated privileges.
+ */
+ drop_effective_capability(KERNEL_OPLOCK_CAPABILITY);
+ drop_effective_capability(DMAPI_ACCESS_CAPABILITY);
+
+ /* point our stdout at the file we want output to go into */
+
+ if (outfd && ((*outfd = setup_out_fd()) == -1)) {
+ return -1;
+ }
+
+ /* in this method we will exec /bin/sh with the correct
+ arguments, after first setting stdout to point at the file */
+
+ /*
+ * We need to temporarily stop CatchChild from eating
+ * SIGCLD signals as it also eats the exit status code. JRA.
+ */
+
+ CatchChildLeaveStatus();
+
+ if ((pid=sys_fork()) < 0) {
+ DEBUG(0,("smbrun: fork failed with error %s\n", strerror(errno) ));
+ CatchChild();
+ if (outfd) {
+ close(*outfd);
+ *outfd = -1;
+ }
+ return errno;
+ }
+
+ if (pid) {
+ /*
+ * Parent.
+ */
+ int status=0;
+ pid_t wpid;
+
+
+ /* the parent just waits for the child to exit */
+ while((wpid = sys_waitpid(pid,&status,0)) < 0) {
+ if(errno == EINTR) {
+ errno = 0;
+ continue;
+ }
+ break;
+ }
+
+ CatchChild();
+
+ if (wpid != pid) {
+ DEBUG(2,("waitpid(%d) : %s\n",(int)pid,strerror(errno)));
+ if (outfd) {
+ close(*outfd);
+ *outfd = -1;
+ }
+ return -1;
+ }
+
+ /* Reset the seek pointer. */
+ if (outfd) {
+ sys_lseek(*outfd, 0, SEEK_SET);
+ }
+
+#if defined(WIFEXITED) && defined(WEXITSTATUS)
+ if (WIFEXITED(status)) {
+ return WEXITSTATUS(status);
+ }
+#endif
+
+ return status;
+ }
+
+ CatchChild();
+
+ /* we are in the child. we exec /bin/sh to do the work for us. we
+ don't directly exec the command we want because it may be a
+ pipeline or anything else the config file specifies */
+
+ /* point our stdout at the file we want output to go into */
+ if (outfd) {
+ close(1);
+ if (sys_dup2(*outfd,1) != 1) {
+ DEBUG(2,("Failed to create stdout file descriptor\n"));
+ close(*outfd);
+ exit(80);
+ }
+ }
+
+ /* now completely lose our privileges. This is a fairly paranoid
+ way of doing it, but it does work on all systems that I know of */
+
+ become_user_permanently(uid, gid);
+
+ if (getuid() != uid || geteuid() != uid ||
+ getgid() != gid || getegid() != gid) {
+ /* we failed to lose our privileges - do not execute
+ the command */
+ exit(81); /* we can't print stuff at this stage,
+ instead use exit codes for debugging */
+ }
+
+#ifndef __INSURE__
+ /* close all other file descriptors, leaving only 0, 1 and 2. 0 and
+ 2 point to /dev/null from the startup code */
+ {
+ int fd;
+ for (fd=3;fd<256;fd++) close(fd);
+ }
+#endif
+
+ {
+ const char *newcmd = sanitize ? escape_shell_string(cmd) : cmd;
+ if (!newcmd) {
+ exit(82);
+ }
+ execl("/bin/sh","sh","-c",newcmd,NULL);
+ }
+
+ /* not reached */
+ exit(83);
+ return 1;
+}
+
+/****************************************************************************
+ Use only in known safe shell calls (printing).
+****************************************************************************/
+
+int smbrun_no_sanitize(const char *cmd, int *outfd)
+{
+ return smbrun_internal(cmd, outfd, False);
+}
+
+/****************************************************************************
+ By default this now sanitizes shell expansion.
+****************************************************************************/
+
+int smbrun(const char *cmd, int *outfd)
+{
+ return smbrun_internal(cmd, outfd, True);
+}
+
+/****************************************************************************
+run a command being careful about uid/gid handling and putting the output in
+outfd (or discard it if outfd is NULL).
+sends the provided secret to the child stdin.
+****************************************************************************/
+
+int smbrunsecret(const char *cmd, const char *secret)
+{
+ pid_t pid;
+ uid_t uid = current_user.ut.uid;
+ gid_t gid = current_user.ut.gid;
+ int ifd[2];
+
+ /*
+ * Lose any elevated privileges.
+ */
+ drop_effective_capability(KERNEL_OPLOCK_CAPABILITY);
+ drop_effective_capability(DMAPI_ACCESS_CAPABILITY);
+
+ /* build up an input pipe */
+ if(pipe(ifd)) {
+ return -1;
+ }
+
+ /* in this method we will exec /bin/sh with the correct
+ arguments, after first setting stdout to point at the file */
+
+ /*
+ * We need to temporarily stop CatchChild from eating
+ * SIGCLD signals as it also eats the exit status code. JRA.
+ */
+
+ CatchChildLeaveStatus();
+
+ if ((pid=sys_fork()) < 0) {
+ DEBUG(0, ("smbrunsecret: fork failed with error %s\n", strerror(errno)));
+ CatchChild();
+ return errno;
+ }
+
+ if (pid) {
+ /*
+ * Parent.
+ */
+ int status = 0;
+ pid_t wpid;
+ size_t towrite;
+ ssize_t wrote;
+
+ close(ifd[0]);
+ /* send the secret */
+ towrite = strlen(secret);
+ wrote = write(ifd[1], secret, towrite);
+ if ( wrote != towrite ) {
+ DEBUG(0,("smbrunsecret: wrote %ld of %lu bytes\n",(long)wrote,(unsigned long)towrite));
+ }
+ fsync(ifd[1]);
+ close(ifd[1]);
+
+ /* the parent just waits for the child to exit */
+ while((wpid = sys_waitpid(pid, &status, 0)) < 0) {
+ if(errno == EINTR) {
+ errno = 0;
+ continue;
+ }
+ break;
+ }
+
+ CatchChild();
+
+ if (wpid != pid) {
+ DEBUG(2, ("waitpid(%d) : %s\n", (int)pid, strerror(errno)));
+ return -1;
+ }
+
+#if defined(WIFEXITED) && defined(WEXITSTATUS)
+ if (WIFEXITED(status)) {
+ return WEXITSTATUS(status);
+ }
+#endif
+
+ return status;
+ }
+
+ CatchChild();
+
+ /* we are in the child. we exec /bin/sh to do the work for us. we
+ don't directly exec the command we want because it may be a
+ pipeline or anything else the config file specifies */
+
+ close(ifd[1]);
+ close(0);
+ if (sys_dup2(ifd[0], 0) != 0) {
+ DEBUG(2,("Failed to create stdin file descriptor\n"));
+ close(ifd[0]);
+ exit(80);
+ }
+
+ /* now completely lose our privileges. This is a fairly paranoid
+ way of doing it, but it does work on all systems that I know of */
+
+ become_user_permanently(uid, gid);
+
+ if (getuid() != uid || geteuid() != uid ||
+ getgid() != gid || getegid() != gid) {
+ /* we failed to lose our privileges - do not execute
+ the command */
+ exit(81); /* we can't print stuff at this stage,
+ instead use exit codes for debugging */
+ }
+
+#ifndef __INSURE__
+ /* close all other file descriptors, leaving only 0, 1 and 2. 0 and
+ 2 point to /dev/null from the startup code */
+ {
+ int fd;
+ for (fd = 3; fd < 256; fd++) close(fd);
+ }
+#endif
+
+ execl("/bin/sh", "sh", "-c", cmd, NULL);
+
+ /* not reached */
+ exit(82);
+ return 1;
+}
diff --git a/source3/lib/sock_exec.c b/source3/lib/sock_exec.c
new file mode 100644
index 0000000000..2333d7c739
--- /dev/null
+++ b/source3/lib/sock_exec.c
@@ -0,0 +1,118 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Tim Potter 2000-2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*******************************************************************
+this is like socketpair but uses tcp. It is used by the Samba
+regression test code
+The function guarantees that nobody else can attach to the socket,
+or if they do that this function fails and the socket gets closed
+returns 0 on success, -1 on failure
+the resulting file descriptors are symmetrical
+ ******************************************************************/
+static int socketpair_tcp(int fd[2])
+{
+ int listener;
+ struct sockaddr_in sock;
+ struct sockaddr_in sock2;
+ socklen_t socklen = sizeof(sock);
+ int connect_done = 0;
+
+ fd[0] = fd[1] = listener = -1;
+
+ memset(&sock, 0, sizeof(sock));
+
+ if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
+
+ memset(&sock2, 0, sizeof(sock2));
+#ifdef HAVE_SOCK_SIN_LEN
+ sock2.sin_len = sizeof(sock2);
+#endif
+ sock2.sin_family = PF_INET;
+
+ if (bind(listener, (struct sockaddr *)&sock2, sizeof(sock2)) != 0) goto failed;
+
+ if (listen(listener, 1) != 0) goto failed;
+
+ if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
+
+ if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
+
+ set_blocking(fd[1], 0);
+
+ sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ if (sys_connect(fd[1], (struct sockaddr *)&sock) == -1) {
+ if (errno != EINPROGRESS) goto failed;
+ } else {
+ connect_done = 1;
+ }
+
+ if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
+
+ close(listener);
+ if (connect_done == 0) {
+ if (sys_connect(fd[1], (struct sockaddr *)&sock) != 0
+ && errno != EISCONN) goto failed;
+ }
+
+ set_blocking(fd[1], 1);
+
+ /* all OK! */
+ return 0;
+
+ failed:
+ if (fd[0] != -1) close(fd[0]);
+ if (fd[1] != -1) close(fd[1]);
+ if (listener != -1) close(listener);
+ return -1;
+}
+
+
+/*******************************************************************
+run a program on a local tcp socket, this is used to launch smbd
+when regression testing
+the return value is a socket which is attached to a subprocess
+running "prog". stdin and stdout are attached. stderr is left
+attached to the original stderr
+ ******************************************************************/
+int sock_exec(const char *prog)
+{
+ int fd[2];
+ if (socketpair_tcp(fd) != 0) {
+ DEBUG(0,("socketpair_tcp failed (%s)\n", strerror(errno)));
+ return -1;
+ }
+ if (fork() == 0) {
+ close(fd[0]);
+ close(0);
+ close(1);
+ if (dup(fd[1]) == -1) {
+ exit(1);
+ }
+ if (dup(fd[1]) == -1) {
+ exit(1);
+ }
+ exit(system(prog));
+ }
+ close(fd[1]);
+ return fd[0];
+}
diff --git a/source3/lib/socket_wrapper/config.m4 b/source3/lib/socket_wrapper/config.m4
new file mode 100644
index 0000000000..f3ffb895a9
--- /dev/null
+++ b/source3/lib/socket_wrapper/config.m4
@@ -0,0 +1,22 @@
+AC_ARG_ENABLE(socket-wrapper,
+[ --enable-socket-wrapper Turn on socket wrapper library (default=no)])
+
+DEFAULT_TEST_OPTIONS=
+HAVE_SOCKET_WRAPPER=no
+
+if eval "test x$developer = xyes"; then
+ enable_socket_wrapper=yes
+fi
+
+if eval "test x$enable_socket_wrapper = xyes"; then
+ AC_DEFINE(SOCKET_WRAPPER,1,[Use socket wrapper library])
+ DEFAULT_TEST_OPTIONS=--socket-wrapper
+ HAVE_SOCKET_WRAPPER=yes
+
+ # this is only used for samba3
+ SOCKET_WRAPPER_OBJS="lib/socket_wrapper/socket_wrapper.o"
+fi
+
+AC_SUBST(DEFAULT_TEST_OPTIONS)
+AC_SUBST(HAVE_SOCKET_WRAPPER)
+AC_SUBST(SOCKET_WRAPPER_OBJS)
diff --git a/source3/lib/socket_wrapper/config.mk b/source3/lib/socket_wrapper/config.mk
new file mode 100644
index 0000000000..60cfb3209a
--- /dev/null
+++ b/source3/lib/socket_wrapper/config.mk
@@ -0,0 +1,8 @@
+##############################
+# Start SUBSYSTEM SOCKET_WRAPPER
+[SUBSYSTEM::SOCKET_WRAPPER]
+PRIVATE_DEPENDENCIES = LIBREPLACE_NETWORK
+# End SUBSYSTEM SOCKET_WRAPPER
+##############################
+
+SOCKET_WRAPPER_OBJ_FILES = $(socketwrappersrcdir)/socket_wrapper.o
diff --git a/source3/lib/socket_wrapper/socket_wrapper.c b/source3/lib/socket_wrapper/socket_wrapper.c
new file mode 100644
index 0000000000..33e4b38370
--- /dev/null
+++ b/source3/lib/socket_wrapper/socket_wrapper.c
@@ -0,0 +1,1841 @@
+/*
+ * Copyright (C) Jelmer Vernooij 2005,2008 <jelmer@samba.org>
+ * Copyright (C) Stefan Metzmacher 2006 <metze@samba.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ Socket wrapper library. Passes all socket communication over
+ unix domain sockets if the environment variable SOCKET_WRAPPER_DIR
+ is set.
+*/
+
+#ifdef _SAMBA_BUILD_
+
+#define SOCKET_WRAPPER_NOT_REPLACE
+#include "lib/replace/replace.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/time.h"
+
+#else /* _SAMBA_BUILD_ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/filio.h>
+#include <errno.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#endif
+
+#ifndef _PUBLIC_
+#define _PUBLIC_
+#endif
+
+#define SWRAP_DLIST_ADD(list,item) do { \
+ if (!(list)) { \
+ (item)->prev = NULL; \
+ (item)->next = NULL; \
+ (list) = (item); \
+ } else { \
+ (item)->prev = NULL; \
+ (item)->next = (list); \
+ (list)->prev = (item); \
+ (list) = (item); \
+ } \
+} while (0)
+
+#define SWRAP_DLIST_REMOVE(list,item) do { \
+ if ((list) == (item)) { \
+ (list) = (item)->next; \
+ if (list) { \
+ (list)->prev = NULL; \
+ } \
+ } else { \
+ if ((item)->prev) { \
+ (item)->prev->next = (item)->next; \
+ } \
+ if ((item)->next) { \
+ (item)->next->prev = (item)->prev; \
+ } \
+ } \
+ (item)->prev = NULL; \
+ (item)->next = NULL; \
+} while (0)
+
+/* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support
+ * for now */
+#define REWRITE_CALLS
+
+#ifdef REWRITE_CALLS
+#define real_accept accept
+#define real_connect connect
+#define real_bind bind
+#define real_listen listen
+#define real_getpeername getpeername
+#define real_getsockname getsockname
+#define real_getsockopt getsockopt
+#define real_setsockopt setsockopt
+#define real_recvfrom recvfrom
+#define real_sendto sendto
+#define real_ioctl ioctl
+#define real_recv recv
+#define real_send send
+#define real_socket socket
+#define real_close close
+#endif
+
+#ifdef HAVE_GETTIMEOFDAY_TZ
+#define swrapGetTimeOfDay(tval) gettimeofday(tval,NULL)
+#else
+#define swrapGetTimeOfDay(tval) gettimeofday(tval)
+#endif
+
+/* we need to use a very terse format here as IRIX 6.4 silently
+ truncates names to 16 chars, so if we use a longer name then we
+ can't tell which port a packet came from with recvfrom()
+
+ with this format we have 8 chars left for the directory name
+*/
+#define SOCKET_FORMAT "%c%02X%04X"
+#define SOCKET_TYPE_CHAR_TCP 'T'
+#define SOCKET_TYPE_CHAR_UDP 'U'
+#define SOCKET_TYPE_CHAR_TCP_V6 'X'
+#define SOCKET_TYPE_CHAR_UDP_V6 'Y'
+
+#define MAX_WRAPPED_INTERFACES 16
+
+#define SW_IPV6_ADDRESS 1
+
+static struct sockaddr *sockaddr_dup(const void *data, socklen_t len)
+{
+ struct sockaddr *ret = (struct sockaddr *)malloc(len);
+ memcpy(ret, data, len);
+ return ret;
+}
+
+static void set_port(int family, int prt, struct sockaddr *addr)
+{
+ switch (family) {
+ case AF_INET:
+ ((struct sockaddr_in *)addr)->sin_port = htons(prt);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ ((struct sockaddr_in6 *)addr)->sin6_port = htons(prt);
+ break;
+#endif
+ }
+}
+
+static size_t socket_length(int family)
+{
+ switch (family) {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+#endif
+ }
+ return 0;
+}
+
+
+
+struct socket_info
+{
+ int fd;
+
+ int family;
+ int type;
+ int protocol;
+ int bound;
+ int bcast;
+ int is_server;
+
+ char *path;
+ char *tmp_path;
+
+ struct sockaddr *myname;
+ socklen_t myname_len;
+
+ struct sockaddr *peername;
+ socklen_t peername_len;
+
+ struct {
+ unsigned long pck_snd;
+ unsigned long pck_rcv;
+ } io;
+
+ struct socket_info *prev, *next;
+};
+
+static struct socket_info *sockets;
+
+const char *socket_wrapper_dir(void)
+{
+ const char *s = getenv("SOCKET_WRAPPER_DIR");
+ if (s == NULL) {
+ return NULL;
+ }
+ if (strncmp(s, "./", 2) == 0) {
+ s += 2;
+ }
+ return s;
+}
+
+unsigned int socket_wrapper_default_iface(void)
+{
+ const char *s = getenv("SOCKET_WRAPPER_DEFAULT_IFACE");
+ if (s) {
+ unsigned int iface;
+ if (sscanf(s, "%u", &iface) == 1) {
+ if (iface >= 1 && iface <= MAX_WRAPPED_INTERFACES) {
+ return iface;
+ }
+ }
+ }
+
+ return 1;/* 127.0.0.1 */
+}
+
+static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, socklen_t *len)
+{
+ unsigned int iface;
+ unsigned int prt;
+ const char *p;
+ char type;
+
+ p = strrchr(un->sun_path, '/');
+ if (p) p++; else p = un->sun_path;
+
+ if (sscanf(p, SOCKET_FORMAT, &type, &iface, &prt) != 3) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (prt > 0xFFFF) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ switch(type) {
+ case SOCKET_TYPE_CHAR_TCP:
+ case SOCKET_TYPE_CHAR_UDP: {
+ struct sockaddr_in *in2 = (struct sockaddr_in *)in;
+
+ if ((*len) < sizeof(*in2)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(in2, 0, sizeof(*in2));
+ in2->sin_family = AF_INET;
+ in2->sin_addr.s_addr = htonl((127<<24) | iface);
+ in2->sin_port = htons(prt);
+
+ *len = sizeof(*in2);
+ break;
+ }
+#ifdef HAVE_IPV6
+ case SOCKET_TYPE_CHAR_TCP_V6:
+ case SOCKET_TYPE_CHAR_UDP_V6: {
+ struct sockaddr_in6 *in2 = (struct sockaddr_in6 *)in;
+
+ if ((*len) < sizeof(*in2)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(in2, 0, sizeof(*in2));
+ in2->sin6_family = AF_INET6;
+ in2->sin6_addr.s6_addr[0] = SW_IPV6_ADDRESS;
+ in2->sin6_port = htons(prt);
+
+ *len = sizeof(*in2);
+ break;
+ }
+#endif
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un,
+ int *bcast)
+{
+ char type = '\0';
+ unsigned int prt;
+ unsigned int iface;
+ int is_bcast = 0;
+
+ if (bcast) *bcast = 0;
+
+ switch (si->family) {
+ case AF_INET: {
+ const struct sockaddr_in *in =
+ (const struct sockaddr_in *)inaddr;
+ unsigned int addr = ntohl(in->sin_addr.s_addr);
+ char u_type = '\0';
+ char b_type = '\0';
+ char a_type = '\0';
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ u_type = SOCKET_TYPE_CHAR_TCP;
+ break;
+ case SOCK_DGRAM:
+ u_type = SOCKET_TYPE_CHAR_UDP;
+ a_type = SOCKET_TYPE_CHAR_UDP;
+ b_type = SOCKET_TYPE_CHAR_UDP;
+ break;
+ }
+
+ prt = ntohs(in->sin_port);
+ if (a_type && addr == 0xFFFFFFFF) {
+ /* 255.255.255.255 only udp */
+ is_bcast = 2;
+ type = a_type;
+ iface = socket_wrapper_default_iface();
+ } else if (b_type && addr == 0x7FFFFFFF) {
+ /* 127.255.255.255 only udp */
+ is_bcast = 1;
+ type = b_type;
+ iface = socket_wrapper_default_iface();
+ } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
+ /* 127.0.0.X */
+ is_bcast = 0;
+ type = u_type;
+ iface = (addr & 0x000000FF);
+ } else {
+ errno = ENETUNREACH;
+ return -1;
+ }
+ if (bcast) *bcast = is_bcast;
+ break;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6: {
+ const struct sockaddr_in6 *in =
+ (const struct sockaddr_in6 *)inaddr;
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ type = SOCKET_TYPE_CHAR_TCP_V6;
+ break;
+ case SOCK_DGRAM:
+ type = SOCKET_TYPE_CHAR_UDP_V6;
+ break;
+ }
+
+ /* XXX no multicast/broadcast */
+
+ prt = ntohs(in->sin6_port);
+ iface = SW_IPV6_ADDRESS;
+
+ break;
+ }
+#endif
+ default:
+ errno = ENETUNREACH;
+ return -1;
+ }
+
+ if (prt == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (is_bcast) {
+ snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL",
+ socket_wrapper_dir());
+ /* the caller need to do more processing */
+ return 0;
+ }
+
+ snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
+ socket_wrapper_dir(), type, iface, prt);
+
+ return 0;
+}
+
+static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un,
+ int *bcast)
+{
+ char type = '\0';
+ unsigned int prt;
+ unsigned int iface;
+ struct stat st;
+ int is_bcast = 0;
+
+ if (bcast) *bcast = 0;
+
+ switch (si->family) {
+ case AF_INET: {
+ const struct sockaddr_in *in =
+ (const struct sockaddr_in *)inaddr;
+ unsigned int addr = ntohl(in->sin_addr.s_addr);
+ char u_type = '\0';
+ char d_type = '\0';
+ char b_type = '\0';
+ char a_type = '\0';
+
+ prt = ntohs(in->sin_port);
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ u_type = SOCKET_TYPE_CHAR_TCP;
+ d_type = SOCKET_TYPE_CHAR_TCP;
+ break;
+ case SOCK_DGRAM:
+ u_type = SOCKET_TYPE_CHAR_UDP;
+ d_type = SOCKET_TYPE_CHAR_UDP;
+ a_type = SOCKET_TYPE_CHAR_UDP;
+ b_type = SOCKET_TYPE_CHAR_UDP;
+ break;
+ }
+
+ if (addr == 0) {
+ /* 0.0.0.0 */
+ is_bcast = 0;
+ type = d_type;
+ iface = socket_wrapper_default_iface();
+ } else if (a_type && addr == 0xFFFFFFFF) {
+ /* 255.255.255.255 only udp */
+ is_bcast = 2;
+ type = a_type;
+ iface = socket_wrapper_default_iface();
+ } else if (b_type && addr == 0x7FFFFFFF) {
+ /* 127.255.255.255 only udp */
+ is_bcast = 1;
+ type = b_type;
+ iface = socket_wrapper_default_iface();
+ } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
+ /* 127.0.0.X */
+ is_bcast = 0;
+ type = u_type;
+ iface = (addr & 0x000000FF);
+ } else {
+ errno = EADDRNOTAVAIL;
+ return -1;
+ }
+ break;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6: {
+ const struct sockaddr_in6 *in =
+ (const struct sockaddr_in6 *)inaddr;
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ type = SOCKET_TYPE_CHAR_TCP_V6;
+ break;
+ case SOCK_DGRAM:
+ type = SOCKET_TYPE_CHAR_UDP_V6;
+ break;
+ }
+
+ /* XXX no multicast/broadcast */
+
+ prt = ntohs(in->sin6_port);
+ iface = SW_IPV6_ADDRESS;
+
+ break;
+ }
+#endif
+ default:
+ errno = ENETUNREACH;
+ return -1;
+ }
+
+
+ if (bcast) *bcast = is_bcast;
+
+ if (prt == 0) {
+ /* handle auto-allocation of ephemeral ports */
+ for (prt = 5001; prt < 10000; prt++) {
+ snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
+ socket_wrapper_dir(), type, iface, prt);
+ if (stat(un->sun_path, &st) == 0) continue;
+
+ set_port(si->family, prt, si->myname);
+ break;
+ }
+ if (prt == 10000) {
+ errno = ENFILE;
+ return -1;
+ }
+ }
+
+ snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
+ socket_wrapper_dir(), type, iface, prt);
+ return 0;
+}
+
+static struct socket_info *find_socket_info(int fd)
+{
+ struct socket_info *i;
+ for (i = sockets; i; i = i->next) {
+ if (i->fd == fd)
+ return i;
+ }
+
+ return NULL;
+}
+
+static int sockaddr_convert_to_un(struct socket_info *si, const struct sockaddr *in_addr, socklen_t in_len,
+ struct sockaddr_un *out_addr, int alloc_sock, int *bcast)
+{
+ if (!out_addr)
+ return 0;
+
+ out_addr->sun_family = AF_UNIX;
+
+ switch (in_addr->sa_family) {
+ case AF_INET:
+#ifdef HAVE_IPV6
+ case AF_INET6:
+#endif
+ switch (si->type) {
+ case SOCK_STREAM:
+ case SOCK_DGRAM:
+ break;
+ default:
+ errno = ESOCKTNOSUPPORT;
+ return -1;
+ }
+ if (alloc_sock) {
+ return convert_in_un_alloc(si, in_addr, out_addr, bcast);
+ } else {
+ return convert_in_un_remote(si, in_addr, out_addr, bcast);
+ }
+ default:
+ break;
+ }
+
+ errno = EAFNOSUPPORT;
+ return -1;
+}
+
+static int sockaddr_convert_from_un(const struct socket_info *si,
+ const struct sockaddr_un *in_addr,
+ socklen_t un_addrlen,
+ int family,
+ struct sockaddr *out_addr,
+ socklen_t *out_addrlen)
+{
+ if (out_addr == NULL || out_addrlen == NULL)
+ return 0;
+
+ if (un_addrlen == 0) {
+ *out_addrlen = 0;
+ return 0;
+ }
+
+ switch (family) {
+ case AF_INET:
+#ifdef HAVE_IPV6
+ case AF_INET6:
+#endif
+ switch (si->type) {
+ case SOCK_STREAM:
+ case SOCK_DGRAM:
+ break;
+ default:
+ errno = ESOCKTNOSUPPORT;
+ return -1;
+ }
+ return convert_un_in(in_addr, out_addr, out_addrlen);
+ default:
+ break;
+ }
+
+ errno = EAFNOSUPPORT;
+ return -1;
+}
+
+enum swrap_packet_type {
+ SWRAP_CONNECT_SEND,
+ SWRAP_CONNECT_UNREACH,
+ SWRAP_CONNECT_RECV,
+ SWRAP_CONNECT_ACK,
+ SWRAP_ACCEPT_SEND,
+ SWRAP_ACCEPT_RECV,
+ SWRAP_ACCEPT_ACK,
+ SWRAP_RECVFROM,
+ SWRAP_SENDTO,
+ SWRAP_SENDTO_UNREACH,
+ SWRAP_PENDING_RST,
+ SWRAP_RECV,
+ SWRAP_RECV_RST,
+ SWRAP_SEND,
+ SWRAP_SEND_RST,
+ SWRAP_CLOSE_SEND,
+ SWRAP_CLOSE_RECV,
+ SWRAP_CLOSE_ACK
+};
+
+struct swrap_file_hdr {
+ uint32_t magic;
+ uint16_t version_major;
+ uint16_t version_minor;
+ int32_t timezone;
+ uint32_t sigfigs;
+ uint32_t frame_max_len;
+#define SWRAP_FRAME_LENGTH_MAX 0xFFFF
+ uint32_t link_type;
+};
+#define SWRAP_FILE_HDR_SIZE 24
+
+struct swrap_packet {
+ struct {
+ uint32_t seconds;
+ uint32_t micro_seconds;
+ uint32_t recorded_length;
+ uint32_t full_length;
+ } frame;
+#define SWRAP_PACKET__FRAME_SIZE 16
+
+ struct {
+ struct {
+ uint8_t ver_hdrlen;
+ uint8_t tos;
+ uint16_t packet_length;
+ uint16_t identification;
+ uint8_t flags;
+ uint8_t fragment;
+ uint8_t ttl;
+ uint8_t protocol;
+ uint16_t hdr_checksum;
+ uint32_t src_addr;
+ uint32_t dest_addr;
+ } hdr;
+#define SWRAP_PACKET__IP_HDR_SIZE 20
+
+ union {
+ struct {
+ uint16_t source_port;
+ uint16_t dest_port;
+ uint32_t seq_num;
+ uint32_t ack_num;
+ uint8_t hdr_length;
+ uint8_t control;
+ uint16_t window;
+ uint16_t checksum;
+ uint16_t urg;
+ } tcp;
+#define SWRAP_PACKET__IP_P_TCP_SIZE 20
+ struct {
+ uint16_t source_port;
+ uint16_t dest_port;
+ uint16_t length;
+ uint16_t checksum;
+ } udp;
+#define SWRAP_PACKET__IP_P_UDP_SIZE 8
+ struct {
+ uint8_t type;
+ uint8_t code;
+ uint16_t checksum;
+ uint32_t unused;
+ } icmp;
+#define SWRAP_PACKET__IP_P_ICMP_SIZE 8
+ } p;
+ } ip;
+};
+#define SWRAP_PACKET_SIZE 56
+
+static const char *socket_wrapper_pcap_file(void)
+{
+ static int initialized = 0;
+ static const char *s = NULL;
+ static const struct swrap_file_hdr h = { 0, };
+ static const struct swrap_packet p = { { 0, }, { { 0, }, { { 0, } } } };
+
+ if (initialized == 1) {
+ return s;
+ }
+ initialized = 1;
+
+ /*
+ * TODO: don't use the structs use plain buffer offsets
+ * and PUSH_U8(), PUSH_U16() and PUSH_U32()
+ *
+ * for now make sure we disable PCAP support
+ * if the struct has alignment!
+ */
+ if (sizeof(h) != SWRAP_FILE_HDR_SIZE) {
+ return NULL;
+ }
+ if (sizeof(p) != SWRAP_PACKET_SIZE) {
+ return NULL;
+ }
+ if (sizeof(p.frame) != SWRAP_PACKET__FRAME_SIZE) {
+ return NULL;
+ }
+ if (sizeof(p.ip.hdr) != SWRAP_PACKET__IP_HDR_SIZE) {
+ return NULL;
+ }
+ if (sizeof(p.ip.p.tcp) != SWRAP_PACKET__IP_P_TCP_SIZE) {
+ return NULL;
+ }
+ if (sizeof(p.ip.p.udp) != SWRAP_PACKET__IP_P_UDP_SIZE) {
+ return NULL;
+ }
+ if (sizeof(p.ip.p.icmp) != SWRAP_PACKET__IP_P_ICMP_SIZE) {
+ return NULL;
+ }
+
+ s = getenv("SOCKET_WRAPPER_PCAP_FILE");
+ if (s == NULL) {
+ return NULL;
+ }
+ if (strncmp(s, "./", 2) == 0) {
+ s += 2;
+ }
+ return s;
+}
+
+static struct swrap_packet *swrap_packet_init(struct timeval *tval,
+ const struct sockaddr_in *src_addr,
+ const struct sockaddr_in *dest_addr,
+ int socket_type,
+ const unsigned char *payload,
+ size_t payload_len,
+ unsigned long tcp_seqno,
+ unsigned long tcp_ack,
+ unsigned char tcp_ctl,
+ int unreachable,
+ size_t *_packet_len)
+{
+ struct swrap_packet *ret;
+ struct swrap_packet *packet;
+ size_t packet_len;
+ size_t alloc_len;
+ size_t nonwire_len = sizeof(packet->frame);
+ size_t wire_hdr_len = 0;
+ size_t wire_len = 0;
+ size_t icmp_hdr_len = 0;
+ size_t icmp_truncate_len = 0;
+ unsigned char protocol = 0, icmp_protocol = 0;
+ unsigned short src_port = src_addr->sin_port;
+ unsigned short dest_port = dest_addr->sin_port;
+
+ switch (socket_type) {
+ case SOCK_STREAM:
+ protocol = 0x06; /* TCP */
+ wire_hdr_len = sizeof(packet->ip.hdr) + sizeof(packet->ip.p.tcp);
+ wire_len = wire_hdr_len + payload_len;
+ break;
+
+ case SOCK_DGRAM:
+ protocol = 0x11; /* UDP */
+ wire_hdr_len = sizeof(packet->ip.hdr) + sizeof(packet->ip.p.udp);
+ wire_len = wire_hdr_len + payload_len;
+ break;
+
+ default:
+ return NULL;
+ }
+
+ if (unreachable) {
+ icmp_protocol = protocol;
+ protocol = 0x01; /* ICMP */
+ if (wire_len > 64 ) {
+ icmp_truncate_len = wire_len - 64;
+ }
+ icmp_hdr_len = sizeof(packet->ip.hdr) + sizeof(packet->ip.p.icmp);
+ wire_hdr_len += icmp_hdr_len;
+ wire_len += icmp_hdr_len;
+ }
+
+ packet_len = nonwire_len + wire_len;
+ alloc_len = packet_len;
+ if (alloc_len < sizeof(struct swrap_packet)) {
+ alloc_len = sizeof(struct swrap_packet);
+ }
+ ret = (struct swrap_packet *)malloc(alloc_len);
+ if (!ret) return NULL;
+
+ packet = ret;
+
+ packet->frame.seconds = tval->tv_sec;
+ packet->frame.micro_seconds = tval->tv_usec;
+ packet->frame.recorded_length = wire_len - icmp_truncate_len;
+ packet->frame.full_length = wire_len - icmp_truncate_len;
+
+ packet->ip.hdr.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
+ packet->ip.hdr.tos = 0x00;
+ packet->ip.hdr.packet_length = htons(wire_len - icmp_truncate_len);
+ packet->ip.hdr.identification = htons(0xFFFF);
+ packet->ip.hdr.flags = 0x40; /* BIT 1 set - means don't fraqment */
+ packet->ip.hdr.fragment = htons(0x0000);
+ packet->ip.hdr.ttl = 0xFF;
+ packet->ip.hdr.protocol = protocol;
+ packet->ip.hdr.hdr_checksum = htons(0x0000);
+ packet->ip.hdr.src_addr = src_addr->sin_addr.s_addr;
+ packet->ip.hdr.dest_addr = dest_addr->sin_addr.s_addr;
+
+ if (unreachable) {
+ packet->ip.p.icmp.type = 0x03; /* destination unreachable */
+ packet->ip.p.icmp.code = 0x01; /* host unreachable */
+ packet->ip.p.icmp.checksum = htons(0x0000);
+ packet->ip.p.icmp.unused = htonl(0x00000000);
+
+ /* set the ip header in the ICMP payload */
+ packet = (struct swrap_packet *)(((unsigned char *)ret) + icmp_hdr_len);
+ packet->ip.hdr.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
+ packet->ip.hdr.tos = 0x00;
+ packet->ip.hdr.packet_length = htons(wire_len - icmp_hdr_len);
+ packet->ip.hdr.identification = htons(0xFFFF);
+ packet->ip.hdr.flags = 0x40; /* BIT 1 set - means don't fraqment */
+ packet->ip.hdr.fragment = htons(0x0000);
+ packet->ip.hdr.ttl = 0xFF;
+ packet->ip.hdr.protocol = icmp_protocol;
+ packet->ip.hdr.hdr_checksum = htons(0x0000);
+ packet->ip.hdr.src_addr = dest_addr->sin_addr.s_addr;
+ packet->ip.hdr.dest_addr = src_addr->sin_addr.s_addr;
+
+ src_port = dest_addr->sin_port;
+ dest_port = src_addr->sin_port;
+ }
+
+ switch (socket_type) {
+ case SOCK_STREAM:
+ packet->ip.p.tcp.source_port = src_port;
+ packet->ip.p.tcp.dest_port = dest_port;
+ packet->ip.p.tcp.seq_num = htonl(tcp_seqno);
+ packet->ip.p.tcp.ack_num = htonl(tcp_ack);
+ packet->ip.p.tcp.hdr_length = 0x50; /* 5 * 32 bit words */
+ packet->ip.p.tcp.control = tcp_ctl;
+ packet->ip.p.tcp.window = htons(0x7FFF);
+ packet->ip.p.tcp.checksum = htons(0x0000);
+ packet->ip.p.tcp.urg = htons(0x0000);
+
+ break;
+
+ case SOCK_DGRAM:
+ packet->ip.p.udp.source_port = src_addr->sin_port;
+ packet->ip.p.udp.dest_port = dest_addr->sin_port;
+ packet->ip.p.udp.length = htons(8 + payload_len);
+ packet->ip.p.udp.checksum = htons(0x0000);
+
+ break;
+ }
+
+ if (payload && payload_len > 0) {
+ unsigned char *p = (unsigned char *)ret;
+ p += nonwire_len;
+ p += wire_hdr_len;
+ memcpy(p, payload, payload_len);
+ }
+
+ *_packet_len = packet_len - icmp_truncate_len;
+ return ret;
+}
+
+static int swrap_get_pcap_fd(const char *fname)
+{
+ static int fd = -1;
+
+ if (fd != -1) return fd;
+
+ fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0644);
+ if (fd != -1) {
+ struct swrap_file_hdr file_hdr;
+ file_hdr.magic = 0xA1B2C3D4;
+ file_hdr.version_major = 0x0002;
+ file_hdr.version_minor = 0x0004;
+ file_hdr.timezone = 0x00000000;
+ file_hdr.sigfigs = 0x00000000;
+ file_hdr.frame_max_len = SWRAP_FRAME_LENGTH_MAX;
+ file_hdr.link_type = 0x0065; /* 101 RAW IP */
+
+ write(fd, &file_hdr, sizeof(file_hdr));
+ return fd;
+ }
+
+ fd = open(fname, O_WRONLY|O_APPEND, 0644);
+
+ return fd;
+}
+
+static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
+ const struct sockaddr *addr,
+ enum swrap_packet_type type,
+ const void *buf, size_t len,
+ size_t *packet_len)
+{
+ const struct sockaddr_in *src_addr;
+ const struct sockaddr_in *dest_addr;
+ unsigned long tcp_seqno = 0;
+ unsigned long tcp_ack = 0;
+ unsigned char tcp_ctl = 0;
+ int unreachable = 0;
+
+ struct timeval tv;
+
+ switch (si->family) {
+ case AF_INET:
+ break;
+ default:
+ return NULL;
+ }
+
+ switch (type) {
+ case SWRAP_CONNECT_SEND:
+ if (si->type != SOCK_STREAM) return NULL;
+
+ src_addr = (const struct sockaddr_in *)si->myname;
+ dest_addr = (const struct sockaddr_in *)addr;
+
+ tcp_seqno = si->io.pck_snd;
+ tcp_ack = si->io.pck_rcv;
+ tcp_ctl = 0x02; /* SYN */
+
+ si->io.pck_snd += 1;
+
+ break;
+
+ case SWRAP_CONNECT_RECV:
+ if (si->type != SOCK_STREAM) return NULL;
+
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)addr;
+
+ tcp_seqno = si->io.pck_rcv;
+ tcp_ack = si->io.pck_snd;
+ tcp_ctl = 0x12; /** SYN,ACK */
+
+ si->io.pck_rcv += 1;
+
+ break;
+
+ case SWRAP_CONNECT_UNREACH:
+ if (si->type != SOCK_STREAM) return NULL;
+
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)addr;
+
+ /* Unreachable: resend the data of SWRAP_CONNECT_SEND */
+ tcp_seqno = si->io.pck_snd - 1;
+ tcp_ack = si->io.pck_rcv;
+ tcp_ctl = 0x02; /* SYN */
+ unreachable = 1;
+
+ break;
+
+ case SWRAP_CONNECT_ACK:
+ if (si->type != SOCK_STREAM) return NULL;
+
+ src_addr = (const struct sockaddr_in *)si->myname;
+ dest_addr = (const struct sockaddr_in *)addr;
+
+ tcp_seqno = si->io.pck_snd;
+ tcp_ack = si->io.pck_rcv;
+ tcp_ctl = 0x10; /* ACK */
+
+ break;
+
+ case SWRAP_ACCEPT_SEND:
+ if (si->type != SOCK_STREAM) return NULL;
+
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)addr;
+
+ tcp_seqno = si->io.pck_rcv;
+ tcp_ack = si->io.pck_snd;
+ tcp_ctl = 0x02; /* SYN */
+
+ si->io.pck_rcv += 1;
+
+ break;
+
+ case SWRAP_ACCEPT_RECV:
+ if (si->type != SOCK_STREAM) return NULL;
+
+ src_addr = (const struct sockaddr_in *)si->myname;
+ dest_addr = (const struct sockaddr_in *)addr;
+
+ tcp_seqno = si->io.pck_snd;
+ tcp_ack = si->io.pck_rcv;
+ tcp_ctl = 0x12; /* SYN,ACK */
+
+ si->io.pck_snd += 1;
+
+ break;
+
+ case SWRAP_ACCEPT_ACK:
+ if (si->type != SOCK_STREAM) return NULL;
+
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)addr;
+
+ tcp_seqno = si->io.pck_rcv;
+ tcp_ack = si->io.pck_snd;
+ tcp_ctl = 0x10; /* ACK */
+
+ break;
+
+ case SWRAP_SEND:
+ src_addr = (const struct sockaddr_in *)si->myname;
+ dest_addr = (const struct sockaddr_in *)si->peername;
+
+ tcp_seqno = si->io.pck_snd;
+ tcp_ack = si->io.pck_rcv;
+ tcp_ctl = 0x18; /* PSH,ACK */
+
+ si->io.pck_snd += len;
+
+ break;
+
+ case SWRAP_SEND_RST:
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)si->peername;
+
+ if (si->type == SOCK_DGRAM) {
+ return swrap_marshall_packet(si, si->peername,
+ SWRAP_SENDTO_UNREACH,
+ buf, len, packet_len);
+ }
+
+ tcp_seqno = si->io.pck_rcv;
+ tcp_ack = si->io.pck_snd;
+ tcp_ctl = 0x14; /** RST,ACK */
+
+ break;
+
+ case SWRAP_PENDING_RST:
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)si->peername;
+
+ if (si->type == SOCK_DGRAM) {
+ return NULL;
+ }
+
+ tcp_seqno = si->io.pck_rcv;
+ tcp_ack = si->io.pck_snd;
+ tcp_ctl = 0x14; /* RST,ACK */
+
+ break;
+
+ case SWRAP_RECV:
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)si->peername;
+
+ tcp_seqno = si->io.pck_rcv;
+ tcp_ack = si->io.pck_snd;
+ tcp_ctl = 0x18; /* PSH,ACK */
+
+ si->io.pck_rcv += len;
+
+ break;
+
+ case SWRAP_RECV_RST:
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)si->peername;
+
+ if (si->type == SOCK_DGRAM) {
+ return NULL;
+ }
+
+ tcp_seqno = si->io.pck_rcv;
+ tcp_ack = si->io.pck_snd;
+ tcp_ctl = 0x14; /* RST,ACK */
+
+ break;
+
+ case SWRAP_SENDTO:
+ src_addr = (const struct sockaddr_in *)si->myname;
+ dest_addr = (const struct sockaddr_in *)addr;
+
+ si->io.pck_snd += len;
+
+ break;
+
+ case SWRAP_SENDTO_UNREACH:
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)addr;
+
+ unreachable = 1;
+
+ break;
+
+ case SWRAP_RECVFROM:
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)addr;
+
+ si->io.pck_rcv += len;
+
+ break;
+
+ case SWRAP_CLOSE_SEND:
+ if (si->type != SOCK_STREAM) return NULL;
+
+ src_addr = (const struct sockaddr_in *)si->myname;
+ dest_addr = (const struct sockaddr_in *)si->peername;
+
+ tcp_seqno = si->io.pck_snd;
+ tcp_ack = si->io.pck_rcv;
+ tcp_ctl = 0x11; /* FIN, ACK */
+
+ si->io.pck_snd += 1;
+
+ break;
+
+ case SWRAP_CLOSE_RECV:
+ if (si->type != SOCK_STREAM) return NULL;
+
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)si->peername;
+
+ tcp_seqno = si->io.pck_rcv;
+ tcp_ack = si->io.pck_snd;
+ tcp_ctl = 0x11; /* FIN,ACK */
+
+ si->io.pck_rcv += 1;
+
+ break;
+
+ case SWRAP_CLOSE_ACK:
+ if (si->type != SOCK_STREAM) return NULL;
+
+ src_addr = (const struct sockaddr_in *)si->myname;
+ dest_addr = (const struct sockaddr_in *)si->peername;
+
+ tcp_seqno = si->io.pck_snd;
+ tcp_ack = si->io.pck_rcv;
+ tcp_ctl = 0x10; /* ACK */
+
+ break;
+ default:
+ return NULL;
+ }
+
+ swrapGetTimeOfDay(&tv);
+
+ return swrap_packet_init(&tv, src_addr, dest_addr, si->type,
+ (const unsigned char *)buf, len,
+ tcp_seqno, tcp_ack, tcp_ctl, unreachable,
+ packet_len);
+}
+
+static void swrap_dump_packet(struct socket_info *si,
+ const struct sockaddr *addr,
+ enum swrap_packet_type type,
+ const void *buf, size_t len)
+{
+ const char *file_name;
+ struct swrap_packet *packet;
+ size_t packet_len = 0;
+ int fd;
+
+ file_name = socket_wrapper_pcap_file();
+ if (!file_name) {
+ return;
+ }
+
+ packet = swrap_marshall_packet(si, addr, type, buf, len, &packet_len);
+ if (!packet) {
+ return;
+ }
+
+ fd = swrap_get_pcap_fd(file_name);
+ if (fd != -1) {
+ write(fd, packet, packet_len);
+ }
+
+ free(packet);
+}
+
+_PUBLIC_ int swrap_socket(int family, int type, int protocol)
+{
+ struct socket_info *si;
+ int fd;
+
+ if (!socket_wrapper_dir()) {
+ return real_socket(family, type, protocol);
+ }
+
+ switch (family) {
+ case AF_INET:
+#ifdef HAVE_IPV6
+ case AF_INET6:
+#endif
+ break;
+ case AF_UNIX:
+ return real_socket(family, type, protocol);
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ switch (type) {
+ case SOCK_STREAM:
+ break;
+ case SOCK_DGRAM:
+ break;
+ default:
+ errno = EPROTONOSUPPORT;
+ return -1;
+ }
+
+ switch (protocol) {
+ case 0:
+ break;
+ case 6:
+ if (type == SOCK_STREAM) {
+ break;
+ }
+ /*fall through*/
+ case 17:
+ if (type == SOCK_DGRAM) {
+ break;
+ }
+ /*fall through*/
+ default:
+ errno = EPROTONOSUPPORT;
+ return -1;
+ }
+
+ fd = real_socket(AF_UNIX, type, 0);
+
+ if (fd == -1) return -1;
+
+ si = (struct socket_info *)calloc(1, sizeof(struct socket_info));
+
+ si->family = family;
+ si->type = type;
+ si->protocol = protocol;
+ si->fd = fd;
+
+ SWRAP_DLIST_ADD(sockets, si);
+
+ return si->fd;
+}
+
+_PUBLIC_ int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
+{
+ struct socket_info *parent_si, *child_si;
+ int fd;
+ struct sockaddr_un un_addr;
+ socklen_t un_addrlen = sizeof(un_addr);
+ struct sockaddr_un un_my_addr;
+ socklen_t un_my_addrlen = sizeof(un_my_addr);
+ struct sockaddr *my_addr;
+ socklen_t my_addrlen, len;
+ int ret;
+
+ parent_si = find_socket_info(s);
+ if (!parent_si) {
+ return real_accept(s, addr, addrlen);
+ }
+
+ /*
+ * assume out sockaddr have the same size as the in parent
+ * socket family
+ */
+ my_addrlen = socket_length(parent_si->family);
+ if (my_addrlen <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ my_addr = (struct sockaddr *)malloc(my_addrlen);
+ if (my_addr == NULL) {
+ return -1;
+ }
+
+ memset(&un_addr, 0, sizeof(un_addr));
+ memset(&un_my_addr, 0, sizeof(un_my_addr));
+
+ ret = real_accept(s, (struct sockaddr *)&un_addr, &un_addrlen);
+ if (ret == -1) {
+ free(my_addr);
+ return ret;
+ }
+
+ fd = ret;
+
+ len = my_addrlen;
+ ret = sockaddr_convert_from_un(parent_si, &un_addr, un_addrlen,
+ parent_si->family, my_addr, &len);
+ if (ret == -1) {
+ free(my_addr);
+ close(fd);
+ return ret;
+ }
+
+ child_si = (struct socket_info *)malloc(sizeof(struct socket_info));
+ memset(child_si, 0, sizeof(*child_si));
+
+ child_si->fd = fd;
+ child_si->family = parent_si->family;
+ child_si->type = parent_si->type;
+ child_si->protocol = parent_si->protocol;
+ child_si->bound = 1;
+ child_si->is_server = 1;
+
+ child_si->peername_len = len;
+ child_si->peername = sockaddr_dup(my_addr, len);
+
+ if (addr != NULL && addrlen != NULL) {
+ *addrlen = len;
+ if (*addrlen >= len)
+ memcpy(addr, my_addr, len);
+ *addrlen = 0;
+ }
+
+ ret = real_getsockname(fd, (struct sockaddr *)&un_my_addr, &un_my_addrlen);
+ if (ret == -1) {
+ free(child_si);
+ close(fd);
+ return ret;
+ }
+
+ len = my_addrlen;
+ ret = sockaddr_convert_from_un(child_si, &un_my_addr, un_my_addrlen,
+ child_si->family, my_addr, &len);
+ if (ret == -1) {
+ free(child_si);
+ free(my_addr);
+ close(fd);
+ return ret;
+ }
+
+ child_si->myname_len = len;
+ child_si->myname = sockaddr_dup(my_addr, len);
+ free(my_addr);
+
+ SWRAP_DLIST_ADD(sockets, child_si);
+
+ swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0);
+ swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_RECV, NULL, 0);
+ swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_ACK, NULL, 0);
+
+ return fd;
+}
+
+static int autobind_start_init;
+static int autobind_start;
+
+/* using sendto() or connect() on an unbound socket would give the
+ recipient no way to reply, as unlike UDP and TCP, a unix domain
+ socket can't auto-assign emphemeral port numbers, so we need to
+ assign it here */
+static int swrap_auto_bind(struct socket_info *si)
+{
+ struct sockaddr_un un_addr;
+ int i;
+ char type;
+ int ret;
+ int port;
+ struct stat st;
+
+ if (autobind_start_init != 1) {
+ autobind_start_init = 1;
+ autobind_start = getpid();
+ autobind_start %= 50000;
+ autobind_start += 10000;
+ }
+
+ un_addr.sun_family = AF_UNIX;
+
+ switch (si->family) {
+ case AF_INET: {
+ struct sockaddr_in in;
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ type = SOCKET_TYPE_CHAR_TCP;
+ break;
+ case SOCK_DGRAM:
+ type = SOCKET_TYPE_CHAR_UDP;
+ break;
+ default:
+ errno = ESOCKTNOSUPPORT;
+ return -1;
+ }
+
+ memset(&in, 0, sizeof(in));
+ in.sin_family = AF_INET;
+ in.sin_addr.s_addr = htonl(127<<24 |
+ socket_wrapper_default_iface());
+
+ si->myname_len = sizeof(in);
+ si->myname = sockaddr_dup(&in, si->myname_len);
+ break;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6: {
+ struct sockaddr_in6 in6;
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ type = SOCKET_TYPE_CHAR_TCP_V6;
+ break;
+ case SOCK_DGRAM:
+ type = SOCKET_TYPE_CHAR_UDP_V6;
+ break;
+ default:
+ errno = ESOCKTNOSUPPORT;
+ return -1;
+ }
+
+ memset(&in6, 0, sizeof(in6));
+ in6.sin6_family = AF_INET6;
+ in6.sin6_addr.s6_addr[0] = SW_IPV6_ADDRESS;
+ si->myname_len = sizeof(in6);
+ si->myname = sockaddr_dup(&in6, si->myname_len);
+ break;
+ }
+#endif
+ default:
+ errno = ESOCKTNOSUPPORT;
+ return -1;
+ }
+
+ if (autobind_start > 60000) {
+ autobind_start = 10000;
+ }
+
+ for (i=0;i<1000;i++) {
+ port = autobind_start + i;
+ snprintf(un_addr.sun_path, sizeof(un_addr.sun_path),
+ "%s/"SOCKET_FORMAT, socket_wrapper_dir(),
+ type, socket_wrapper_default_iface(), port);
+ if (stat(un_addr.sun_path, &st) == 0) continue;
+
+ ret = real_bind(si->fd, (struct sockaddr *)&un_addr, sizeof(un_addr));
+ if (ret == -1) return ret;
+
+ si->tmp_path = strdup(un_addr.sun_path);
+ si->bound = 1;
+ autobind_start = port + 1;
+ break;
+ }
+ if (i == 1000) {
+ errno = ENFILE;
+ return -1;
+ }
+
+ set_port(si->family, port, si->myname);
+
+ return 0;
+}
+
+
+_PUBLIC_ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen)
+{
+ int ret;
+ struct sockaddr_un un_addr;
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_connect(s, serv_addr, addrlen);
+ }
+
+ if (si->bound == 0) {
+ ret = swrap_auto_bind(si);
+ if (ret == -1) return -1;
+ }
+
+ if (si->family != serv_addr->sa_family) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = sockaddr_convert_to_un(si, (const struct sockaddr *)serv_addr, addrlen, &un_addr, 0, NULL);
+ if (ret == -1) return -1;
+
+ swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0);
+
+ ret = real_connect(s, (struct sockaddr *)&un_addr,
+ sizeof(struct sockaddr_un));
+
+ /* to give better errors */
+ if (ret == -1 && errno == ENOENT) {
+ errno = EHOSTUNREACH;
+ }
+
+ if (ret == 0) {
+ si->peername_len = addrlen;
+ si->peername = sockaddr_dup(serv_addr, addrlen);
+
+ swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0);
+ swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0);
+ } else {
+ swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_UNREACH, NULL, 0);
+ }
+
+ return ret;
+}
+
+_PUBLIC_ int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
+{
+ int ret;
+ struct sockaddr_un un_addr;
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_bind(s, myaddr, addrlen);
+ }
+
+ si->myname_len = addrlen;
+ si->myname = sockaddr_dup(myaddr, addrlen);
+
+ ret = sockaddr_convert_to_un(si, (const struct sockaddr *)myaddr, addrlen, &un_addr, 1, &si->bcast);
+ if (ret == -1) return -1;
+
+ unlink(un_addr.sun_path);
+
+ ret = real_bind(s, (struct sockaddr *)&un_addr,
+ sizeof(struct sockaddr_un));
+
+ if (ret == 0) {
+ si->bound = 1;
+ }
+
+ return ret;
+}
+
+_PUBLIC_ int swrap_listen(int s, int backlog)
+{
+ int ret;
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_listen(s, backlog);
+ }
+
+ ret = real_listen(s, backlog);
+
+ return ret;
+}
+
+_PUBLIC_ int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
+{
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_getpeername(s, name, addrlen);
+ }
+
+ if (!si->peername)
+ {
+ errno = ENOTCONN;
+ return -1;
+ }
+
+ memcpy(name, si->peername, si->peername_len);
+ *addrlen = si->peername_len;
+
+ return 0;
+}
+
+_PUBLIC_ int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
+{
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_getsockname(s, name, addrlen);
+ }
+
+ memcpy(name, si->myname, si->myname_len);
+ *addrlen = si->myname_len;
+
+ return 0;
+}
+
+_PUBLIC_ int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
+{
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_getsockopt(s, level, optname, optval, optlen);
+ }
+
+ if (level == SOL_SOCKET) {
+ return real_getsockopt(s, level, optname, optval, optlen);
+ }
+
+ errno = ENOPROTOOPT;
+ return -1;
+}
+
+_PUBLIC_ int swrap_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
+{
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_setsockopt(s, level, optname, optval, optlen);
+ }
+
+ if (level == SOL_SOCKET) {
+ return real_setsockopt(s, level, optname, optval, optlen);
+ }
+
+ switch (si->family) {
+ case AF_INET:
+ return 0;
+ default:
+ errno = ENOPROTOOPT;
+ return -1;
+ }
+}
+
+_PUBLIC_ ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
+{
+ struct sockaddr_un un_addr;
+ socklen_t un_addrlen = sizeof(un_addr);
+ int ret;
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_recvfrom(s, buf, len, flags, from, fromlen);
+ }
+
+ len = MIN(len, 1500);
+
+ /* irix 6.4 forgets to null terminate the sun_path string :-( */
+ memset(&un_addr, 0, sizeof(un_addr));
+ ret = real_recvfrom(s, buf, len, flags, (struct sockaddr *)&un_addr, &un_addrlen);
+ if (ret == -1)
+ return ret;
+
+ if (sockaddr_convert_from_un(si, &un_addr, un_addrlen,
+ si->family, from, fromlen) == -1) {
+ return -1;
+ }
+
+ swrap_dump_packet(si, from, SWRAP_RECVFROM, buf, ret);
+
+ return ret;
+}
+
+
+_PUBLIC_ ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
+{
+ struct sockaddr_un un_addr;
+ int ret;
+ struct socket_info *si = find_socket_info(s);
+ int bcast = 0;
+
+ if (!si) {
+ return real_sendto(s, buf, len, flags, to, tolen);
+ }
+
+ len = MIN(len, 1500);
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ ret = real_send(s, buf, len, flags);
+ break;
+ case SOCK_DGRAM:
+ if (si->bound == 0) {
+ ret = swrap_auto_bind(si);
+ if (ret == -1) return -1;
+ }
+
+ ret = sockaddr_convert_to_un(si, to, tolen, &un_addr, 0, &bcast);
+ if (ret == -1) return -1;
+
+ if (bcast) {
+ struct stat st;
+ unsigned int iface;
+ unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
+ char type;
+
+ type = SOCKET_TYPE_CHAR_UDP;
+
+ for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
+ snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
+ socket_wrapper_dir(), type, iface, prt);
+ if (stat(un_addr.sun_path, &st) != 0) continue;
+
+ /* ignore the any errors in broadcast sends */
+ real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
+ }
+
+ swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+
+ return len;
+ }
+
+ ret = real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
+ break;
+ default:
+ ret = -1;
+ errno = EHOSTUNREACH;
+ break;
+ }
+
+ /* to give better errors */
+ if (ret == -1 && errno == ENOENT) {
+ errno = EHOSTUNREACH;
+ }
+
+ if (ret == -1) {
+ swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+ swrap_dump_packet(si, to, SWRAP_SENDTO_UNREACH, buf, len);
+ } else {
+ swrap_dump_packet(si, to, SWRAP_SENDTO, buf, ret);
+ }
+
+ return ret;
+}
+
+_PUBLIC_ int swrap_ioctl(int s, int r, void *p)
+{
+ int ret;
+ struct socket_info *si = find_socket_info(s);
+ int value;
+
+ if (!si) {
+ return real_ioctl(s, r, p);
+ }
+
+ ret = real_ioctl(s, r, p);
+
+ switch (r) {
+ case FIONREAD:
+ value = *((int *)p);
+ if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
+ swrap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
+ } else if (value == 0) { /* END OF FILE */
+ swrap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
+ }
+ break;
+ }
+
+ return ret;
+}
+
+_PUBLIC_ ssize_t swrap_recv(int s, void *buf, size_t len, int flags)
+{
+ int ret;
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_recv(s, buf, len, flags);
+ }
+
+ len = MIN(len, 1500);
+
+ ret = real_recv(s, buf, len, flags);
+ if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
+ swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
+ } else if (ret == 0) { /* END OF FILE */
+ swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
+ } else {
+ swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
+ }
+
+ return ret;
+}
+
+
+_PUBLIC_ ssize_t swrap_send(int s, const void *buf, size_t len, int flags)
+{
+ int ret;
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_send(s, buf, len, flags);
+ }
+
+ len = MIN(len, 1500);
+
+ ret = real_send(s, buf, len, flags);
+
+ if (ret == -1) {
+ swrap_dump_packet(si, NULL, SWRAP_SEND, buf, len);
+ swrap_dump_packet(si, NULL, SWRAP_SEND_RST, NULL, 0);
+ } else {
+ swrap_dump_packet(si, NULL, SWRAP_SEND, buf, ret);
+ }
+
+ return ret;
+}
+
+_PUBLIC_ int swrap_close(int fd)
+{
+ struct socket_info *si = find_socket_info(fd);
+ int ret;
+
+ if (!si) {
+ return real_close(fd);
+ }
+
+ SWRAP_DLIST_REMOVE(sockets, si);
+
+ if (si->myname && si->peername) {
+ swrap_dump_packet(si, NULL, SWRAP_CLOSE_SEND, NULL, 0);
+ }
+
+ ret = real_close(fd);
+
+ if (si->myname && si->peername) {
+ swrap_dump_packet(si, NULL, SWRAP_CLOSE_RECV, NULL, 0);
+ swrap_dump_packet(si, NULL, SWRAP_CLOSE_ACK, NULL, 0);
+ }
+
+ if (si->path) free(si->path);
+ if (si->myname) free(si->myname);
+ if (si->peername) free(si->peername);
+ if (si->tmp_path) {
+ unlink(si->tmp_path);
+ free(si->tmp_path);
+ }
+ free(si);
+
+ return ret;
+}
diff --git a/source3/lib/socket_wrapper/socket_wrapper.h b/source3/lib/socket_wrapper/socket_wrapper.h
new file mode 100644
index 0000000000..cc8b937608
--- /dev/null
+++ b/source3/lib/socket_wrapper/socket_wrapper.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) Jelmer Vernooij 2005 <jelmer@samba.org>
+ * Copyright (C) Stefan Metzmacher 2006 <metze@samba.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef __SOCKET_WRAPPER_H__
+#define __SOCKET_WRAPPER_H__
+
+const char *socket_wrapper_dir(void);
+unsigned int socket_wrapper_default_iface(void);
+int swrap_socket(int family, int type, int protocol);
+int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen);
+int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen);
+int swrap_listen(int s, int backlog);
+int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen);
+int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen);
+int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen);
+int swrap_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
+ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
+ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);
+int swrap_ioctl(int s, int req, void *ptr);
+ssize_t swrap_recv(int s, void *buf, size_t len, int flags);
+ssize_t swrap_send(int s, const void *buf, size_t len, int flags);
+int swrap_close(int);
+
+#ifdef SOCKET_WRAPPER_REPLACE
+
+#ifdef accept
+#undef accept
+#endif
+#define accept(s,addr,addrlen) swrap_accept(s,addr,addrlen)
+
+#ifdef connect
+#undef connect
+#endif
+#define connect(s,serv_addr,addrlen) swrap_connect(s,serv_addr,addrlen)
+
+#ifdef bind
+#undef bind
+#endif
+#define bind(s,myaddr,addrlen) swrap_bind(s,myaddr,addrlen)
+
+#ifdef listen
+#undef listen
+#endif
+#define listen(s,blog) swrap_listen(s,blog)
+
+#ifdef getpeername
+#undef getpeername
+#endif
+#define getpeername(s,name,addrlen) swrap_getpeername(s,name,addrlen)
+
+#ifdef getsockname
+#undef getsockname
+#endif
+#define getsockname(s,name,addrlen) swrap_getsockname(s,name,addrlen)
+
+#ifdef getsockopt
+#undef getsockopt
+#endif
+#define getsockopt(s,level,optname,optval,optlen) swrap_getsockopt(s,level,optname,optval,optlen)
+
+#ifdef setsockopt
+#undef setsockopt
+#endif
+#define setsockopt(s,level,optname,optval,optlen) swrap_setsockopt(s,level,optname,optval,optlen)
+
+#ifdef recvfrom
+#undef recvfrom
+#endif
+#define recvfrom(s,buf,len,flags,from,fromlen) swrap_recvfrom(s,buf,len,flags,from,fromlen)
+
+#ifdef sendto
+#undef sendto
+#endif
+#define sendto(s,buf,len,flags,to,tolen) swrap_sendto(s,buf,len,flags,to,tolen)
+
+#ifdef ioctl
+#undef ioctl
+#endif
+#define ioctl(s,req,ptr) swrap_ioctl(s,req,ptr)
+
+#ifdef recv
+#undef recv
+#endif
+#define recv(s,buf,len,flags) swrap_recv(s,buf,len,flags)
+
+#ifdef send
+#undef send
+#endif
+#define send(s,buf,len,flags) swrap_send(s,buf,len,flags)
+
+#ifdef socket
+#undef socket
+#endif
+#define socket(domain,type,protocol) swrap_socket(domain,type,protocol)
+
+#ifdef close
+#undef close
+#endif
+#define close(s) swrap_close(s)
+#endif
+
+
+#endif /* __SOCKET_WRAPPER_H__ */
diff --git a/source3/lib/socket_wrapper/testsuite.c b/source3/lib/socket_wrapper/testsuite.c
new file mode 100644
index 0000000000..8877418e4c
--- /dev/null
+++ b/source3/lib/socket_wrapper/testsuite.c
@@ -0,0 +1,105 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ local testing of the socket wrapper
+
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/network.h"
+#include "lib/socket_wrapper/socket_wrapper.h"
+#include "torture/torture.h"
+
+static char *old_dir = NULL;
+static char *old_iface = NULL;
+
+static void backup_env(void)
+{
+ old_dir = getenv("SOCKET_WRAPPER_DIR");
+ old_iface = getenv("SOCKET_WRAPPER_DEFAULT_IFACE");
+}
+
+static void restore_env(void)
+{
+ if (old_dir == NULL)
+ unsetenv("SOCKET_WRAPPER_DIR");
+ else
+ setenv("SOCKET_WRAPPER_DIR", old_dir, 1);
+ if (old_iface == NULL)
+ unsetenv("SOCKET_WRAPPER_DEFAULT_IFACE");
+ else
+ setenv("SOCKET_WRAPPER_DEFAULT_IFACE", old_iface, 1);
+}
+
+static bool test_socket_wrapper_dir(struct torture_context *tctx)
+{
+ backup_env();
+
+ setenv("SOCKET_WRAPPER_DIR", "foo", 1);
+ torture_assert_str_equal(tctx, socket_wrapper_dir(), "foo", "setting failed");
+ setenv("SOCKET_WRAPPER_DIR", "./foo", 1);
+ torture_assert_str_equal(tctx, socket_wrapper_dir(), "foo", "setting failed");
+ unsetenv("SOCKET_WRAPPER_DIR");
+ torture_assert_str_equal(tctx, socket_wrapper_dir(), NULL, "resetting failed");
+
+ restore_env();
+
+ return true;
+}
+
+static bool test_swrap_socket(struct torture_context *tctx)
+{
+ backup_env();
+ setenv("SOCKET_WRAPPER_DIR", "foo", 1);
+
+ torture_assert_int_equal(tctx, swrap_socket(1337, 1337, 0), -1, "unknown address family fails");
+ torture_assert_int_equal(tctx, errno, EAFNOSUPPORT, "correct errno set");
+ torture_assert_int_equal(tctx, swrap_socket(AF_INET, 1337, 0), -1, "unknown type fails");
+ torture_assert_int_equal(tctx, errno, EPROTONOSUPPORT, "correct errno set");
+ torture_assert_int_equal(tctx, swrap_socket(AF_INET, SOCK_DGRAM, 10), -1, "unknown protocol fails");
+ torture_assert_int_equal(tctx, errno, EPROTONOSUPPORT, "correct errno set");
+
+ restore_env();
+
+ return true;
+}
+
+unsigned int socket_wrapper_default_iface(void);
+static bool test_socket_wrapper_default_iface(struct torture_context *tctx)
+{
+ backup_env();
+ unsetenv("SOCKET_WRAPPER_DEFAULT_IFACE");
+ torture_assert_int_equal(tctx, socket_wrapper_default_iface(), 1, "unset");
+ setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "2", 1);
+ torture_assert_int_equal(tctx, socket_wrapper_default_iface(), 2, "unset");
+ setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "bla", 1);
+ torture_assert_int_equal(tctx, socket_wrapper_default_iface(), 1, "unset");
+ restore_env();
+ return true;
+}
+
+struct torture_suite *torture_local_socket_wrapper(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx,
+ "SOCKET-WRAPPER");
+
+ torture_suite_add_simple_test(suite, "socket_wrapper_dir", test_socket_wrapper_dir);
+ torture_suite_add_simple_test(suite, "socket", test_swrap_socket);
+ torture_suite_add_simple_test(suite, "socket_wrapper_default_iface", test_socket_wrapper_default_iface);
+
+ return suite;
+}
diff --git a/source3/lib/substitute.c b/source3/lib/substitute.c
new file mode 100644
index 0000000000..acfe55d761
--- /dev/null
+++ b/source3/lib/substitute.c
@@ -0,0 +1,915 @@
+/*
+ Unix SMB/CIFS implementation.
+ string substitution functions
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Gerald Carter 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+
+userdom_struct current_user_info;
+fstring remote_proto="UNKNOWN";
+
+/**
+ * Set the 'local' machine name
+ * @param local_name the name we are being called
+ * @param if this is the 'final' name for us, not be be changed again
+ */
+
+static char *local_machine;
+
+void free_local_machine_name(void)
+{
+ SAFE_FREE(local_machine);
+}
+
+bool set_local_machine_name(const char *local_name, bool perm)
+{
+ static bool already_perm = false;
+ char *tmp_local_machine = NULL;
+ char addr[INET6_ADDRSTRLEN];
+ size_t len;
+
+ tmp_local_machine = SMB_STRDUP(local_name);
+ if (!tmp_local_machine) {
+ return false;
+ }
+ trim_char(tmp_local_machine,' ',' ');
+
+ /*
+ * Windows NT/2k uses "*SMBSERVER" and XP uses "*SMBSERV"
+ * arrggg!!!
+ */
+
+ if (strequal(tmp_local_machine, "*SMBSERVER") ||
+ strequal(tmp_local_machine, "*SMBSERV") ) {
+ SAFE_FREE(local_machine);
+ local_machine = SMB_STRDUP(client_socket_addr(get_client_fd(),
+ addr, sizeof(addr)) );
+ SAFE_FREE(tmp_local_machine);
+ return local_machine ? true : false;
+ }
+
+ if (already_perm) {
+ return true;
+ }
+
+ SAFE_FREE(local_machine);
+ len = strlen(tmp_local_machine);
+ local_machine = SMB_CALLOC_ARRAY(char, len+1);
+ if (!local_machine) {
+ SAFE_FREE(tmp_local_machine);
+ return false;
+ }
+ /* alpha_strcpy includes the space for the terminating nul. */
+ alpha_strcpy(local_machine,tmp_local_machine,
+ SAFE_NETBIOS_CHARS,len+1);
+ strlower_m(local_machine);
+ SAFE_FREE(tmp_local_machine);
+
+ already_perm = perm;
+
+ return true;
+}
+
+const char *get_local_machine_name(void)
+{
+ if (!local_machine || !*local_machine) {
+ return global_myname();
+ }
+
+ return local_machine;
+}
+
+/**
+ * Set the 'remote' machine name
+ * @param remote_name the name our client wants to be called by
+ * @param if this is the 'final' name for them, not be be changed again
+ */
+
+static char *remote_machine;
+
+bool set_remote_machine_name(const char *remote_name, bool perm)
+{
+ static bool already_perm = False;
+ char *tmp_remote_machine;
+ size_t len;
+
+ if (already_perm) {
+ return true;
+ }
+
+ tmp_remote_machine = SMB_STRDUP(remote_name);
+ if (!tmp_remote_machine) {
+ return false;
+ }
+ trim_char(tmp_remote_machine,' ',' ');
+
+ SAFE_FREE(remote_machine);
+ len = strlen(tmp_remote_machine);
+ remote_machine = SMB_CALLOC_ARRAY(char, len+1);
+ if (!remote_machine) {
+ SAFE_FREE(tmp_remote_machine);
+ return false;
+ }
+
+ /* alpha_strcpy includes the space for the terminating nul. */
+ alpha_strcpy(remote_machine,tmp_remote_machine,
+ SAFE_NETBIOS_CHARS,len+1);
+ strlower_m(remote_machine);
+ SAFE_FREE(tmp_remote_machine);
+
+ already_perm = perm;
+
+ return true;
+}
+
+const char *get_remote_machine_name(void)
+{
+ return remote_machine ? remote_machine : "";
+}
+
+/*******************************************************************
+ Setup the string used by %U substitution.
+********************************************************************/
+
+static char *smb_user_name;
+
+void sub_set_smb_name(const char *name)
+{
+ char *tmp;
+ size_t len;
+ bool is_machine_account = false;
+
+ /* don't let anonymous logins override the name */
+ if (!name || !*name) {
+ return;
+ }
+
+ tmp = SMB_STRDUP(name);
+ if (!tmp) {
+ return;
+ }
+ trim_char(tmp, ' ', ' ');
+ strlower_m(tmp);
+
+ len = strlen(tmp);
+
+ if (len == 0) {
+ SAFE_FREE(tmp);
+ return;
+ }
+
+ /* long story but here goes....we have to allow usernames
+ ending in '$' as they are valid machine account names.
+ So check for a machine account and re-add the '$'
+ at the end after the call to alpha_strcpy(). --jerry */
+
+ if (tmp[len-1] == '$') {
+ is_machine_account = True;
+ }
+
+ SAFE_FREE(smb_user_name);
+ smb_user_name = SMB_CALLOC_ARRAY(char, len+1);
+ if (!smb_user_name) {
+ SAFE_FREE(tmp);
+ return;
+ }
+
+ /* alpha_strcpy includes the space for the terminating nul. */
+ alpha_strcpy(smb_user_name, tmp,
+ SAFE_NETBIOS_CHARS,
+ len+1);
+
+ SAFE_FREE(tmp);
+
+ if (is_machine_account) {
+ len = strlen(smb_user_name);
+ smb_user_name[len-1] = '$';
+ }
+}
+
+static const char *get_smb_user_name(void)
+{
+ return smb_user_name ? smb_user_name : "";
+}
+
+/*******************************************************************
+ Setup the strings used by substitutions. Called per packet. Ensure
+ %U name is set correctly also.
+
+ smb_name must be sanitized by alpha_strcpy
+********************************************************************/
+
+void set_current_user_info(const char *smb_name, const char *unix_name,
+ const char *full_name, const char *domain)
+{
+ fstrcpy(current_user_info.smb_name, smb_name);
+ fstrcpy(current_user_info.unix_name, unix_name);
+ fstrcpy(current_user_info.full_name, full_name);
+ fstrcpy(current_user_info.domain, domain);
+
+ /* The following is safe as current_user_info.smb_name
+ * has already been sanitised in register_existing_vuid. */
+
+ sub_set_smb_name(current_user_info.smb_name);
+}
+
+/*******************************************************************
+ Return the current active user name.
+*******************************************************************/
+
+const char *get_current_username(void)
+{
+ if (current_user_info.smb_name[0] == '\0' ) {
+ return get_smb_user_name();
+ }
+
+ return current_user_info.smb_name;
+}
+
+/*******************************************************************
+ Given a pointer to a %$(NAME) in p and the whole string in str
+ expand it as an environment variable.
+ Return a new allocated and expanded string.
+ Based on code by Branko Cibej <branko.cibej@hermes.si>
+ When this is called p points at the '%' character.
+ May substitute multiple occurrencies of the same env var.
+********************************************************************/
+
+static char * realloc_expand_env_var(char *str, char *p)
+{
+ char *envname;
+ char *envval;
+ char *q, *r;
+ int copylen;
+
+ if (p[0] != '%' || p[1] != '$' || p[2] != '(') {
+ return str;
+ }
+
+ /*
+ * Look for the terminating ')'.
+ */
+
+ if ((q = strchr_m(p,')')) == NULL) {
+ DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p));
+ return str;
+ }
+
+ /*
+ * Extract the name from within the %$(NAME) string.
+ */
+
+ r = p + 3;
+ copylen = q - r;
+
+ /* reserve space for use later add %$() chars */
+ if ( (envname = (char *)SMB_MALLOC(copylen + 1 + 4)) == NULL ) {
+ return NULL;
+ }
+
+ strncpy(envname,r,copylen);
+ envname[copylen] = '\0';
+
+ if ((envval = getenv(envname)) == NULL) {
+ DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname));
+ SAFE_FREE(envname);
+ return str;
+ }
+
+ /*
+ * Copy the full %$(NAME) into envname so it
+ * can be replaced.
+ */
+
+ copylen = q + 1 - p;
+ strncpy(envname,p,copylen);
+ envname[copylen] = '\0';
+ r = realloc_string_sub(str, envname, envval);
+ SAFE_FREE(envname);
+
+ return r;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static char *longvar_domainsid( void )
+{
+ DOM_SID sid;
+ fstring tmp;
+ char *sid_string;
+
+ if ( !secrets_fetch_domain_sid( lp_workgroup(), &sid ) ) {
+ return NULL;
+ }
+
+ sid_string = SMB_STRDUP( sid_to_fstring( tmp, &sid ) );
+
+ if ( !sid_string ) {
+ DEBUG(0,("longvar_domainsid: failed to dup SID string!\n"));
+ }
+
+ return sid_string;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+struct api_longvar {
+ const char *name;
+ char* (*fn)( void );
+};
+
+static struct api_longvar longvar_table[] = {
+ { "DomainSID", longvar_domainsid },
+ { NULL, NULL }
+};
+
+static char *get_longvar_val( const char *varname )
+{
+ int i;
+
+ DEBUG(7,("get_longvar_val: expanding variable [%s]\n", varname));
+
+ for ( i=0; longvar_table[i].name; i++ ) {
+ if ( strequal( longvar_table[i].name, varname ) ) {
+ return longvar_table[i].fn();
+ }
+ }
+
+ return NULL;
+}
+
+/*******************************************************************
+ Expand the long smb.conf variable names given a pointer to a %(NAME).
+ Return the number of characters by which the pointer should be advanced.
+ When this is called p points at the '%' character.
+********************************************************************/
+
+static char *realloc_expand_longvar(char *str, char *p)
+{
+ fstring varname;
+ char *value;
+ char *q, *r;
+ int copylen;
+
+ if ( p[0] != '%' || p[1] != '(' ) {
+ return str;
+ }
+
+ /* Look for the terminating ')'.*/
+
+ if ((q = strchr_m(p,')')) == NULL) {
+ DEBUG(0,("realloc_expand_longvar: Unterminated environment variable [%s]\n", p));
+ return str;
+ }
+
+ /* Extract the name from within the %(NAME) string.*/
+
+ r = p+2;
+ copylen = MIN( (q-r), (sizeof(varname)-1) );
+ strncpy(varname, r, copylen);
+ varname[copylen] = '\0';
+
+ if ((value = get_longvar_val(varname)) == NULL) {
+ DEBUG(0,("realloc_expand_longvar: Variable [%s] not set. Skipping\n", varname));
+ return str;
+ }
+
+ /* Copy the full %(NAME) into envname so it can be replaced.*/
+
+ copylen = MIN( (q+1-p),(sizeof(varname)-1) );
+ strncpy( varname, p, copylen );
+ varname[copylen] = '\0';
+ r = realloc_string_sub(str, varname, value);
+ SAFE_FREE( value );
+
+ /* skip over the %(varname) */
+
+ return r;
+}
+
+/*******************************************************************
+ Patch from jkf@soton.ac.uk
+ Added this to implement %p (NIS auto-map version of %H)
+*******************************************************************/
+
+static const char *automount_path(const char *user_name)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ const char *server_path;
+
+ /* use the passwd entry as the default */
+ /* this will be the default if WITH_AUTOMOUNT is not used or fails */
+
+ server_path = talloc_strdup(ctx, get_user_home_dir(ctx, user_name));
+ if (!server_path) {
+ return "";
+ }
+
+#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
+
+ if (lp_nis_home_map()) {
+ const char *home_path_start;
+ char *automount_value = automount_lookup(ctx, user_name);
+
+ if(automount_value && strlen(automount_value) > 0) {
+ home_path_start = strchr_m(automount_value,':');
+ if (home_path_start != NULL) {
+ DEBUG(5, ("NIS lookup succeeded. "
+ "Home path is: %s\n",
+ home_path_start ?
+ (home_path_start+1):""));
+ server_path = talloc_strdup(ctx,
+ home_path_start+1);
+ if (!server_path) {
+ server_path = "";
+ }
+ }
+ } else {
+ /* NIS key lookup failed: default to
+ * user home directory from password file */
+ DEBUG(5, ("NIS lookup failed. Using Home path from "
+ "passwd file. Home path is: %s\n", server_path ));
+ }
+ }
+#endif
+
+ DEBUG(4,("Home server path: %s\n", server_path));
+ return server_path;
+}
+
+/*******************************************************************
+ Patch from jkf@soton.ac.uk
+ This is Luke's original function with the NIS lookup code
+ moved out to a separate function.
+*******************************************************************/
+
+static const char *automount_server(const char *user_name)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ const char *server_name;
+ const char *local_machine_name = get_local_machine_name();
+
+ /* use the local machine name as the default */
+ /* this will be the default if WITH_AUTOMOUNT is not used or fails */
+ if (local_machine_name && *local_machine_name) {
+ server_name = talloc_strdup(ctx, local_machine_name);
+ } else {
+ server_name = talloc_strdup(ctx, global_myname());
+ }
+
+ if (!server_name) {
+ return "";
+ }
+
+#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
+ if (lp_nis_home_map()) {
+ char *p;
+ char *srv;
+ char *automount_value = automount_lookup(ctx, user_name);
+ if (!automount_value) {
+ return "";
+ }
+ srv = talloc_strdup(ctx, automount_value);
+ if (!srv) {
+ return "";
+ }
+ p = strchr_m(srv, ':');
+ if (!p) {
+ return "";
+ }
+ *p = '\0';
+ server_name = srv;
+ DEBUG(5, ("NIS lookup succeeded. Home server %s\n",
+ server_name));
+ }
+#endif
+
+ DEBUG(4,("Home server: %s\n", server_name));
+ return server_name;
+}
+
+/****************************************************************************
+ Do some standard substitutions in a string.
+ len is the length in bytes of the space allowed in string str. If zero means
+ don't allow expansions.
+****************************************************************************/
+
+void standard_sub_basic(const char *smb_name, const char *domain_name,
+ char *str, size_t len)
+{
+ char *s;
+
+ if ( (s = alloc_sub_basic( smb_name, domain_name, str )) != NULL ) {
+ strncpy( str, s, len );
+ }
+
+ SAFE_FREE( s );
+
+}
+
+/****************************************************************************
+ Do some standard substitutions in a string.
+ This function will return an allocated string that have to be freed.
+****************************************************************************/
+
+char *talloc_sub_basic(TALLOC_CTX *mem_ctx, const char *smb_name,
+ const char *domain_name, const char *str)
+{
+ char *a, *t;
+
+ if ( (a = alloc_sub_basic(smb_name, domain_name, str)) == NULL ) {
+ return NULL;
+ }
+ t = talloc_strdup(mem_ctx, a);
+ SAFE_FREE(a);
+ return t;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+char *alloc_sub_basic(const char *smb_name, const char *domain_name,
+ const char *str)
+{
+ char *b, *p, *s, *r, *a_string;
+ fstring pidstr, vnnstr;
+ char addr[INET6_ADDRSTRLEN];
+ const char *local_machine_name = get_local_machine_name();
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ /* workaround to prevent a crash while looking at bug #687 */
+
+ if (!str) {
+ DEBUG(0,("alloc_sub_basic: NULL source string! This should not happen\n"));
+ return NULL;
+ }
+
+ a_string = SMB_STRDUP(str);
+ if (a_string == NULL) {
+ DEBUG(0, ("alloc_sub_basic: Out of memory!\n"));
+ return NULL;
+ }
+
+ tmp_ctx = talloc_stackframe();
+
+ for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
+
+ r = NULL;
+ b = a_string;
+
+ switch (*(p+1)) {
+ case 'U' :
+ r = strdup_lower(smb_name);
+ if (r == NULL) {
+ goto error;
+ }
+ a_string = realloc_string_sub(a_string, "%U", r);
+ break;
+ case 'G' : {
+ struct passwd *pass;
+ r = SMB_STRDUP(smb_name);
+ if (r == NULL) {
+ goto error;
+ }
+ pass = Get_Pwnam_alloc(tmp_ctx, r);
+ if (pass != NULL) {
+ a_string = realloc_string_sub(
+ a_string, "%G",
+ gidtoname(pass->pw_gid));
+ }
+ TALLOC_FREE(pass);
+ break;
+ }
+ case 'D' :
+ r = strdup_upper(domain_name);
+ if (r == NULL) {
+ goto error;
+ }
+ a_string = realloc_string_sub(a_string, "%D", r);
+ break;
+ case 'I' : {
+ int offset = 0;
+ client_addr(get_client_fd(), addr, sizeof(addr));
+ if (strnequal(addr,"::ffff:",7)) {
+ offset = 7;
+ }
+ a_string = realloc_string_sub(a_string, "%I",
+ addr + offset);
+ break;
+ }
+ case 'i':
+ a_string = realloc_string_sub( a_string, "%i",
+ client_socket_addr(get_client_fd(), addr, sizeof(addr)) );
+ break;
+ case 'L' :
+ if ( StrnCaseCmp(p, "%LOGONSERVER%", strlen("%LOGONSERVER%")) == 0 ) {
+ break;
+ }
+ if (local_machine_name && *local_machine_name) {
+ a_string = realloc_string_sub(a_string, "%L", local_machine_name);
+ } else {
+ a_string = realloc_string_sub(a_string, "%L", global_myname());
+ }
+ break;
+ case 'N':
+ a_string = realloc_string_sub(a_string, "%N", automount_server(smb_name));
+ break;
+ case 'M' :
+ a_string = realloc_string_sub(a_string, "%M", client_name(get_client_fd()));
+ break;
+ case 'R' :
+ a_string = realloc_string_sub(a_string, "%R", remote_proto);
+ break;
+ case 'T' :
+ a_string = realloc_string_sub(a_string, "%T", current_timestring(tmp_ctx, False));
+ break;
+ case 'a' :
+ a_string = realloc_string_sub(a_string, "%a",
+ get_remote_arch_str());
+ break;
+ case 'd' :
+ slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)sys_getpid());
+ a_string = realloc_string_sub(a_string, "%d", pidstr);
+ break;
+ case 'h' :
+ a_string = realloc_string_sub(a_string, "%h", myhostname());
+ break;
+ case 'm' :
+ a_string = realloc_string_sub(a_string, "%m",
+ remote_machine
+ ? remote_machine
+ : "");
+ break;
+ case 'v' :
+ a_string = realloc_string_sub(a_string, "%v", SAMBA_VERSION_STRING);
+ break;
+ case 'w' :
+ a_string = realloc_string_sub(a_string, "%w", lp_winbind_separator());
+ break;
+ case '$' :
+ a_string = realloc_expand_env_var(a_string, p); /* Expand environment variables */
+ break;
+ case '(':
+ a_string = realloc_expand_longvar( a_string, p );
+ break;
+ case 'V' :
+ slprintf(vnnstr,sizeof(vnnstr)-1, "%u", get_my_vnn());
+ a_string = realloc_string_sub(a_string, "%V", vnnstr);
+ break;
+ default:
+ break;
+ }
+
+ p++;
+ SAFE_FREE(r);
+
+ if (a_string == NULL) {
+ goto done;
+ }
+ }
+
+ goto done;
+
+error:
+ SAFE_FREE(a_string);
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return a_string;
+}
+
+/****************************************************************************
+ Do some specific substitutions in a string.
+ This function will return an allocated string that have to be freed.
+****************************************************************************/
+
+char *talloc_sub_specified(TALLOC_CTX *mem_ctx,
+ const char *input_string,
+ const char *username,
+ const char *domain,
+ uid_t uid,
+ gid_t gid)
+{
+ char *a_string;
+ char *ret_string = NULL;
+ char *b, *p, *s;
+ TALLOC_CTX *tmp_ctx;
+
+ if (!(tmp_ctx = talloc_new(mem_ctx))) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return NULL;
+ }
+
+ a_string = talloc_strdup(tmp_ctx, input_string);
+ if (a_string == NULL) {
+ DEBUG(0, ("talloc_sub_specified: Out of memory!\n"));
+ goto done;
+ }
+
+ for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
+
+ b = a_string;
+
+ switch (*(p+1)) {
+ case 'U' :
+ a_string = talloc_string_sub(
+ tmp_ctx, a_string, "%U", username);
+ break;
+ case 'u' :
+ a_string = talloc_string_sub(
+ tmp_ctx, a_string, "%u", username);
+ break;
+ case 'G' :
+ if (gid != -1) {
+ a_string = talloc_string_sub(
+ tmp_ctx, a_string, "%G",
+ gidtoname(gid));
+ } else {
+ a_string = talloc_string_sub(
+ tmp_ctx, a_string,
+ "%G", "NO_GROUP");
+ }
+ break;
+ case 'g' :
+ if (gid != -1) {
+ a_string = talloc_string_sub(
+ tmp_ctx, a_string, "%g",
+ gidtoname(gid));
+ } else {
+ a_string = talloc_string_sub(
+ tmp_ctx, a_string, "%g", "NO_GROUP");
+ }
+ break;
+ case 'D' :
+ a_string = talloc_string_sub(tmp_ctx, a_string,
+ "%D", domain);
+ break;
+ case 'N' :
+ a_string = talloc_string_sub(
+ tmp_ctx, a_string, "%N",
+ automount_server(username));
+ break;
+ default:
+ break;
+ }
+
+ p++;
+ if (a_string == NULL) {
+ goto done;
+ }
+ }
+
+ /* Watch out, using "mem_ctx" here, so all intermediate stuff goes
+ * away with the TALLOC_FREE(tmp_ctx) further down. */
+
+ ret_string = talloc_sub_basic(mem_ctx, username, domain, a_string);
+
+ done:
+ TALLOC_FREE(tmp_ctx);
+ return ret_string;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static char *alloc_sub_advanced(const char *servicename, const char *user,
+ const char *connectpath, gid_t gid,
+ const char *smb_name, const char *domain_name,
+ const char *str)
+{
+ char *a_string, *ret_string;
+ char *b, *p, *s;
+
+ a_string = SMB_STRDUP(str);
+ if (a_string == NULL) {
+ DEBUG(0, ("alloc_sub_advanced: Out of memory!\n"));
+ return NULL;
+ }
+
+ for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
+
+ b = a_string;
+
+ switch (*(p+1)) {
+ case 'N' :
+ a_string = realloc_string_sub(a_string, "%N", automount_server(user));
+ break;
+ case 'H': {
+ char *h;
+ if ((h = get_user_home_dir(talloc_tos(), user)))
+ a_string = realloc_string_sub(a_string, "%H", h);
+ TALLOC_FREE(h);
+ break;
+ }
+ case 'P':
+ a_string = realloc_string_sub(a_string, "%P", connectpath);
+ break;
+ case 'S':
+ a_string = realloc_string_sub(a_string, "%S", servicename);
+ break;
+ case 'g':
+ a_string = realloc_string_sub(a_string, "%g", gidtoname(gid));
+ break;
+ case 'u':
+ a_string = realloc_string_sub(a_string, "%u", 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':
+ a_string = realloc_string_sub(a_string, "%p",
+ automount_path(servicename));
+ break;
+
+ default:
+ break;
+ }
+
+ p++;
+ if (a_string == NULL) {
+ return NULL;
+ }
+ }
+
+ ret_string = alloc_sub_basic(smb_name, domain_name, a_string);
+ SAFE_FREE(a_string);
+ return ret_string;
+}
+
+/*
+ * This obviously is inefficient and needs to be merged into
+ * alloc_sub_advanced...
+ */
+
+char *talloc_sub_advanced(TALLOC_CTX *mem_ctx,
+ const char *servicename, const char *user,
+ const char *connectpath, gid_t gid,
+ const char *smb_name, const char *domain_name,
+ const char *str)
+{
+ char *a, *t;
+
+ if (!(a = alloc_sub_advanced(servicename, user, connectpath, gid,
+ smb_name, domain_name, str))) {
+ return NULL;
+ }
+ t = talloc_strdup(mem_ctx, a);
+ SAFE_FREE(a);
+ return t;
+}
+
+
+void standard_sub_advanced(const char *servicename, const char *user,
+ const char *connectpath, gid_t gid,
+ const char *smb_name, const char *domain_name,
+ char *str, size_t len)
+{
+ char *s;
+
+ s = alloc_sub_advanced(servicename, user, connectpath,
+ gid, smb_name, domain_name, str);
+
+ if ( s ) {
+ strncpy( str, s, len );
+ SAFE_FREE( s );
+ }
+}
+
+/****************************************************************************
+ Do some standard substitutions in a string.
+****************************************************************************/
+
+char *standard_sub_conn(TALLOC_CTX *ctx, connection_struct *conn, const char *str)
+{
+ return talloc_sub_advanced(ctx,
+ lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name,
+ conn->connectpath,
+ conn->server_info->utok.gid,
+ get_smb_user_name(),
+ "",
+ str);
+}
diff --git a/source3/lib/sysacls.c b/source3/lib/sysacls.c
new file mode 100644
index 0000000000..9c1256ed65
--- /dev/null
+++ b/source3/lib/sysacls.c
@@ -0,0 +1,621 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba system utilities for ACL support.
+ Copyright (C) Jeremy Allison 2000.
+ Copyright (C) Volker Lendecke 2006
+ Copyright (C) Michael Adam 2006,2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_ACLS
+
+/*
+ * Note that while this code implements sufficient functionality
+ * to support the sys_acl_* interfaces it does not provide all
+ * of the semantics of the POSIX ACL interfaces.
+ *
+ * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
+ * from a call to sys_acl_get_entry() should not be assumed to be
+ * valid after calling any of the following functions, which may
+ * reorder the entries in the ACL.
+ *
+ * sys_acl_valid()
+ * sys_acl_set_file()
+ * sys_acl_set_fd()
+ */
+
+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+{
+ if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (entry_p == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
+ acl_d->next = 0;
+ }
+
+ if (acl_d->next < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_d->next >= acl_d->count) {
+ return 0;
+ }
+
+ *entry_p = &acl_d->acl[acl_d->next++];
+
+ return 1;
+}
+
+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
+{
+ *type_p = entry_d->a_type;
+
+ return 0;
+}
+
+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
+{
+ *permset_p = &entry_d->a_perm;
+
+ return 0;
+}
+
+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
+{
+ if (entry_d->a_type == SMB_ACL_USER) {
+ return &entry_d->uid;
+ }
+
+ if (entry_d->a_type == SMB_ACL_GROUP) {
+ return &entry_d->gid;
+ }
+
+ errno = EINVAL;
+ return NULL;
+}
+
+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
+{
+ *permset_d = 0;
+
+ return 0;
+}
+
+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
+{
+ if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
+ && perm != SMB_ACL_EXECUTE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (permset_d == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ *permset_d |= perm;
+
+ return 0;
+}
+
+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
+{
+ return *permset_d & perm;
+}
+
+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
+{
+ int i;
+ int len, maxlen;
+ char *text;
+
+ /*
+ * use an initial estimate of 20 bytes per ACL entry
+ * when allocating memory for the text representation
+ * of the ACL
+ */
+ len = 0;
+ maxlen = 20 * acl_d->count;
+ if ((text = (char *)SMB_MALLOC(maxlen)) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ for (i = 0; i < acl_d->count; i++) {
+ struct smb_acl_entry *ap = &acl_d->acl[i];
+ struct group *gr;
+ char tagbuf[12];
+ char idbuf[12];
+ const char *tag;
+ const char *id = "";
+ char perms[4];
+ int nbytes;
+
+ switch (ap->a_type) {
+ /*
+ * for debugging purposes it's probably more
+ * useful to dump unknown tag types rather
+ * than just returning an error
+ */
+ default:
+ slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
+ ap->a_type);
+ tag = tagbuf;
+ break;
+
+ case SMB_ACL_USER:
+ id = uidtoname(ap->uid);
+ case SMB_ACL_USER_OBJ:
+ tag = "user";
+ break;
+
+ case SMB_ACL_GROUP:
+ if ((gr = getgrgid(ap->gid)) == NULL) {
+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
+ (long)ap->gid);
+ id = idbuf;
+ } else {
+ id = gr->gr_name;
+ }
+ case SMB_ACL_GROUP_OBJ:
+ tag = "group";
+ break;
+
+ case SMB_ACL_OTHER:
+ tag = "other";
+ break;
+
+ case SMB_ACL_MASK:
+ tag = "mask";
+ break;
+
+ }
+
+ perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
+ perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
+ perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
+ perms[3] = '\0';
+
+ /* <tag> : <qualifier> : rwx \n \0 */
+ nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
+
+ /*
+ * If this entry would overflow the buffer
+ * allocate enough additional memory for this
+ * entry and an estimate of another 20 bytes
+ * for each entry still to be processed
+ */
+ if ((len + nbytes) > maxlen) {
+ maxlen += nbytes + 20 * (acl_d->count - i);
+ if ((text = (char *)SMB_REALLOC(text, maxlen)) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ }
+
+ slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
+ len += nbytes - 1;
+ }
+
+ if (len_p)
+ *len_p = len;
+
+ return text;
+}
+
+SMB_ACL_T sys_acl_init(int count)
+{
+ SMB_ACL_T a;
+
+ if (count < 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /*
+ * note that since the definition of the structure pointed
+ * to by the SMB_ACL_T includes the first element of the
+ * acl[] array, this actually allocates an ACL with room
+ * for (count+1) entries
+ */
+ if ((a = (struct smb_acl_t *)SMB_MALLOC(
+ sizeof(struct smb_acl_t) +
+ count * sizeof(struct smb_acl_entry))) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ a->size = count + 1;
+ a->count = 0;
+ a->next = -1;
+
+ return a;
+}
+
+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
+{
+ SMB_ACL_T acl_d;
+ SMB_ACL_ENTRY_T entry_d;
+
+ if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_d->count >= acl_d->size) {
+ errno = ENOSPC;
+ return -1;
+ }
+
+ entry_d = &acl_d->acl[acl_d->count++];
+ entry_d->a_type = SMB_ACL_TAG_INVALID;
+ entry_d->uid = -1;
+ entry_d->gid = -1;
+ entry_d->a_perm = 0;
+ *entry_p = entry_d;
+
+ return 0;
+}
+
+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
+{
+ switch (tag_type) {
+ case SMB_ACL_USER:
+ case SMB_ACL_USER_OBJ:
+ case SMB_ACL_GROUP:
+ case SMB_ACL_GROUP_OBJ:
+ case SMB_ACL_OTHER:
+ case SMB_ACL_MASK:
+ entry_d->a_type = tag_type;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
+{
+ if (entry_d->a_type == SMB_ACL_USER) {
+ entry_d->uid = *((uid_t *)qual_p);
+ return 0;
+ }
+ if (entry_d->a_type == SMB_ACL_GROUP) {
+ entry_d->gid = *((gid_t *)qual_p);
+ return 0;
+ }
+
+ errno = EINVAL;
+ return -1;
+}
+
+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
+{
+ if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ entry_d->a_perm = *permset_d;
+
+ return 0;
+}
+
+int sys_acl_free_text(char *text)
+{
+ SAFE_FREE(text);
+ return 0;
+}
+
+int sys_acl_free_acl(SMB_ACL_T acl_d)
+{
+ SAFE_FREE(acl_d);
+ return 0;
+}
+
+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
+{
+ return 0;
+}
+
+int sys_acl_valid(SMB_ACL_T acl_d)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+/*
+ * acl_get_file, acl_get_fd, acl_set_file, acl_set_fd and
+ * sys_acl_delete_def_file are to be redirected to the default
+ * statically-bound acl vfs module, but they are replacable.
+ */
+
+#if defined(HAVE_POSIX_ACLS)
+
+SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p, SMB_ACL_TYPE_T type)
+{
+ return posixacl_sys_acl_get_file(handle, path_p, type);
+}
+
+SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp)
+{
+ return posixacl_sys_acl_get_fd(handle, fsp);
+}
+
+int sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
+{
+ return posixacl_sys_acl_set_file(handle, name, type, acl_d);
+}
+
+int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_ACL_T acl_d)
+{
+ return posixacl_sys_acl_set_fd(handle, fsp, acl_d);
+}
+
+int sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path)
+{
+ return posixacl_sys_acl_delete_def_file(handle, path);
+}
+
+#elif defined(HAVE_AIX_ACLS)
+
+SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p, SMB_ACL_TYPE_T type)
+{
+ return aixacl_sys_acl_get_file(handle, path_p, type);
+}
+
+SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp)
+{
+ return aixacl_sys_acl_get_fd(handle, fsp);
+}
+
+int sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
+{
+ return aixacl_sys_acl_set_file(handle, name, type, acl_d);
+}
+
+int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_ACL_T acl_d)
+{
+ return aixacl_sys_acl_set_fd(handle, fsp, acl_d);
+}
+
+int sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path)
+{
+ return aixacl_sys_acl_delete_def_file(handle, path);
+}
+
+#elif defined(HAVE_TRU64_ACLS)
+
+SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p, SMB_ACL_TYPE_T type)
+{
+ return tru64acl_sys_acl_get_file(handle, path_p, type);
+}
+
+SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp)
+{
+ return tru64acl_sys_acl_get_fd(handle, fsp);
+}
+
+int sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
+{
+ return tru64acl_sys_acl_set_file(handle, name, type, acl_d);
+}
+
+int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_ACL_T acl_d)
+{
+ return tru64acl_sys_acl_set_fd(handle, fsp, acl_d);
+}
+
+int sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path)
+{
+ return tru64acl_sys_acl_delete_def_file(handle, path);
+}
+
+#elif defined(HAVE_SOLARIS_ACLS) || defined(HAVE_UNIXWARE_ACLS)
+
+SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p, SMB_ACL_TYPE_T type)
+{
+ return solarisacl_sys_acl_get_file(handle, path_p, type);
+}
+
+SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp)
+{
+ return solarisacl_sys_acl_get_fd(handle, fsp);
+}
+
+int sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
+{
+ return solarisacl_sys_acl_set_file(handle, name, type, acl_d);
+}
+
+int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_ACL_T acl_d)
+{
+ return solarisacl_sys_acl_set_fd(handle, fsp, acl_d);
+}
+
+int sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path)
+{
+ return solarisacl_sys_acl_delete_def_file(handle, path);
+}
+
+#elif defined(HAVE_HPUX_ACLS)
+
+SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p, SMB_ACL_TYPE_T type)
+{
+ return hpuxacl_sys_acl_get_file(handle, path_p, type);
+}
+
+SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp)
+{
+ return hpuxacl_sys_acl_get_fd(handle, fsp);
+}
+
+int sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
+{
+ return hpuxacl_sys_acl_set_file(handle, name, type, acl_d);
+}
+
+int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_ACL_T acl_d)
+{
+ return hpuxacl_sys_acl_set_fd(handle, fsp, acl_d);
+}
+
+int sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path)
+{
+ return hpuxacl_sys_acl_delete_def_file(handle, path);
+}
+
+#elif defined(HAVE_IRIX_ACLS)
+
+SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p, SMB_ACL_TYPE_T type)
+{
+ return irixacl_sys_acl_get_file(handle, path_p, type);
+}
+
+SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp)
+{
+ return irixacl_sys_acl_get_fd(handle, fsp);
+}
+
+int sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
+{
+ return irixacl_sys_acl_set_file(handle, name, type, acl_d);
+}
+
+int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_ACL_T acl_d)
+{
+ return irixacl_sys_acl_set_fd(handle, fsp, acl_d);
+}
+
+int sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path)
+{
+ return irixacl_sys_acl_delete_def_file(handle, path);
+}
+
+#else /* No ACLs. */
+
+SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p, SMB_ACL_TYPE_T type)
+{
+#ifdef ENOTSUP
+ errno = ENOTSUP;
+#else
+ errno = ENOSYS;
+#endif
+ return NULL;
+}
+
+SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp)
+{
+#ifdef ENOTSUP
+ errno = ENOTSUP;
+#else
+ errno = ENOSYS;
+#endif
+ return NULL;
+}
+
+int sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
+{
+#ifdef ENOTSUP
+ errno = ENOTSUP;
+#else
+ errno = ENOSYS;
+#endif
+ return -1;
+}
+
+int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_ACL_T acl_d)
+{
+#ifdef ENOTSUP
+ errno = ENOTSUP;
+#else
+ errno = ENOSYS;
+#endif
+ return -1;
+}
+
+int sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path)
+{
+#ifdef ENOTSUP
+ errno = ENOTSUP;
+#else
+ errno = ENOSYS;
+#endif
+ return -1;
+}
+
+#endif
+
+/************************************************************************
+ Deliberately outside the ACL defines. Return 1 if this is a "no acls"
+ errno, 0 if not.
+************************************************************************/
+
+int no_acl_syscall_error(int err)
+{
+#if defined(ENOSYS)
+ if (err == ENOSYS) {
+ return 1;
+ }
+#endif
+#if defined(ENOTSUP)
+ if (err == ENOTSUP) {
+ return 1;
+ }
+#endif
+ return 0;
+}
diff --git a/source3/lib/sysquotas.c b/source3/lib/sysquotas.c
new file mode 100644
index 0000000000..4a2d88abdf
--- /dev/null
+++ b/source3/lib/sysquotas.c
@@ -0,0 +1,547 @@
+/*
+ Unix SMB/CIFS implementation.
+ System QUOTA function wrappers
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_QUOTA
+
+#ifdef HAVE_SYS_QUOTAS
+
+#if defined(HAVE_QUOTACTL_4A)
+
+/*#endif HAVE_QUOTACTL_4A */
+#elif defined(HAVE_QUOTACTL_4B)
+
+#error HAVE_QUOTACTL_4B not implemeted
+
+/*#endif HAVE_QUOTACTL_4B */
+#elif defined(HAVE_QUOTACTL_3)
+
+#error HAVE_QUOTACTL_3 not implemented
+
+/* #endif HAVE_QUOTACTL_3 */
+#else /* NO_QUOTACTL_USED */
+
+#endif /* NO_QUOTACTL_USED */
+
+#ifdef HAVE_MNTENT
+static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
+{
+ int ret = -1;
+ SMB_STRUCT_STAT S;
+ FILE *fp;
+ struct mntent *mnt;
+ SMB_DEV_T devno;
+
+ /* find the block device file */
+
+ if (!path||!mntpath||!bdev||!fs)
+ smb_panic("sys_path_to_bdev: called with NULL pointer");
+
+ (*mntpath) = NULL;
+ (*bdev) = NULL;
+ (*fs) = NULL;
+
+ if ( sys_stat(path, &S) == -1 )
+ return (-1);
+
+ devno = S.st_dev ;
+
+ fp = setmntent(MOUNTED,"r");
+ if (fp == NULL) {
+ return -1;
+ }
+
+ while ((mnt = getmntent(fp))) {
+ if ( sys_stat(mnt->mnt_dir,&S) == -1 )
+ continue ;
+
+ if (S.st_dev == devno) {
+ (*mntpath) = SMB_STRDUP(mnt->mnt_dir);
+ (*bdev) = SMB_STRDUP(mnt->mnt_fsname);
+ (*fs) = SMB_STRDUP(mnt->mnt_type);
+ if ((*mntpath)&&(*bdev)&&(*fs)) {
+ ret = 0;
+ } else {
+ SAFE_FREE(*mntpath);
+ SAFE_FREE(*bdev);
+ SAFE_FREE(*fs);
+ ret = -1;
+ }
+
+ break;
+ }
+ }
+
+ endmntent(fp) ;
+
+ return ret;
+}
+/* #endif HAVE_MNTENT */
+#elif defined(HAVE_DEVNM)
+
+/* we have this on HPUX, ... */
+static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
+{
+ int ret = -1;
+ char dev_disk[256];
+ SMB_STRUCT_STAT S;
+
+ if (!path||!mntpath||!bdev||!fs)
+ smb_panic("sys_path_to_bdev: called with NULL pointer");
+
+ (*mntpath) = NULL;
+ (*bdev) = NULL;
+ (*fs) = NULL;
+
+ /* find the block device file */
+
+ if ((ret=sys_stat(path, &S))!=0) {
+ return ret;
+ }
+
+ if ((ret=devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1))!=0) {
+ return ret;
+ }
+
+ /* we should get the mntpath right...
+ * but I don't know how
+ * --metze
+ */
+ (*mntpath) = SMB_STRDUP(path);
+ (*bdev) = SMB_STRDUP(dev_disk);
+ if ((*mntpath)&&(*bdev)) {
+ ret = 0;
+ } else {
+ SAFE_FREE(*mntpath);
+ SAFE_FREE(*bdev);
+ ret = -1;
+ }
+
+
+ return ret;
+}
+
+/* #endif HAVE_DEVNM */
+#else
+/* we should fake this up...*/
+static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
+{
+ int ret = -1;
+
+ if (!path||!mntpath||!bdev||!fs)
+ smb_panic("sys_path_to_bdev: called with NULL pointer");
+
+ (*mntpath) = NULL;
+ (*bdev) = NULL;
+ (*fs) = NULL;
+
+ (*mntpath) = SMB_STRDUP(path);
+ if (*mntpath) {
+ ret = 0;
+ } else {
+ SAFE_FREE(*mntpath);
+ ret = -1;
+ }
+
+ return ret;
+}
+#endif
+
+/*********************************************************************
+ Now the list of all filesystem specific quota systems we have found
+**********************************************************************/
+static struct {
+ const char *name;
+ int (*get_quota)(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
+ int (*set_quota)(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
+} sys_quota_backends[] = {
+#ifdef HAVE_XFS_QUOTAS
+ {"xfs", sys_get_xfs_quota, sys_set_xfs_quota},
+#endif /* HAVE_XFS_QUOTAS */
+ {NULL, NULL, NULL}
+};
+
+static int command_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+{
+ const char *get_quota_command;
+ char **lines = NULL;
+
+ get_quota_command = lp_get_quota_command();
+ if (get_quota_command && *get_quota_command) {
+ const char *p;
+ char *p2;
+ char *syscmd = NULL;
+ int _id = -1;
+
+ switch(qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ case SMB_USER_FS_QUOTA_TYPE:
+ _id = id.uid;
+ break;
+ case SMB_GROUP_QUOTA_TYPE:
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ _id = id.gid;
+ break;
+ default:
+ DEBUG(0,("invalid quota type.\n"));
+ return -1;
+ }
+
+ if (asprintf(&syscmd, "%s \"%s\" %d %d",
+ get_quota_command, path, qtype, _id) < 0) {
+ return -1;
+ }
+
+ DEBUG (3, ("get_quota: Running command %s\n", syscmd));
+
+ lines = file_lines_pload(syscmd, NULL);
+ SAFE_FREE(syscmd);
+
+ if (lines) {
+ char *line = lines[0];
+
+ DEBUG (3, ("Read output from get_quota, \"%s\"\n", line));
+
+ /* we need to deal with long long unsigned here, if supported */
+
+ dp->qflags = (enum SMB_QUOTA_TYPE)strtoul(line, &p2, 10);
+ p = p2;
+ while (p && *p && isspace(*p)) {
+ p++;
+ }
+
+ if (p && *p) {
+ dp->curblocks = STR_TO_SMB_BIG_UINT(p, &p);
+ } else {
+ goto invalid_param;
+ }
+
+ while (p && *p && isspace(*p)) {
+ p++;
+ }
+
+ if (p && *p) {
+ dp->softlimit = STR_TO_SMB_BIG_UINT(p, &p);
+ } else {
+ goto invalid_param;
+ }
+
+ while (p && *p && isspace(*p)) {
+ p++;
+ }
+
+ if (p && *p) {
+ dp->hardlimit = STR_TO_SMB_BIG_UINT(p, &p);
+ } else {
+ goto invalid_param;
+ }
+
+ while (p && *p && isspace(*p)) {
+ p++;
+ }
+
+ if (p && *p) {
+ dp->curinodes = STR_TO_SMB_BIG_UINT(p, &p);
+ } else {
+ goto invalid_param;
+ }
+
+ while (p && *p && isspace(*p)) {
+ p++;
+ }
+
+ if (p && *p) {
+ dp->isoftlimit = STR_TO_SMB_BIG_UINT(p, &p);
+ } else {
+ goto invalid_param;
+ }
+
+ while (p && *p && isspace(*p)) {
+ p++;
+ }
+
+ if (p && *p) {
+ dp->ihardlimit = STR_TO_SMB_BIG_UINT(p, &p);
+ } else {
+ goto invalid_param;
+ }
+
+ while (p && *p && isspace(*p)) {
+ p++;
+ }
+
+ if (p && *p) {
+ dp->bsize = STR_TO_SMB_BIG_UINT(p, NULL);
+ } else {
+ dp->bsize = 1024;
+ }
+
+ file_lines_free(lines);
+ lines = NULL;
+
+ DEBUG (3, ("Parsed output of get_quota, ...\n"));
+
+#ifdef LARGE_SMB_OFF_T
+ DEBUGADD (5,(
+ "qflags:%u curblocks:%llu softlimit:%llu hardlimit:%llu\n"
+ "curinodes:%llu isoftlimit:%llu ihardlimit:%llu bsize:%llu\n",
+ dp->qflags,(long long unsigned)dp->curblocks,
+ (long long unsigned)dp->softlimit,(long long unsigned)dp->hardlimit,
+ (long long unsigned)dp->curinodes,
+ (long long unsigned)dp->isoftlimit,(long long unsigned)dp->ihardlimit,
+ (long long unsigned)dp->bsize));
+#else /* LARGE_SMB_OFF_T */
+ DEBUGADD (5,(
+ "qflags:%u curblocks:%lu softlimit:%lu hardlimit:%lu\n"
+ "curinodes:%lu isoftlimit:%lu ihardlimit:%lu bsize:%lu\n",
+ dp->qflags,(long unsigned)dp->curblocks,
+ (long unsigned)dp->softlimit,(long unsigned)dp->hardlimit,
+ (long unsigned)dp->curinodes,
+ (long unsigned)dp->isoftlimit,(long unsigned)dp->ihardlimit,
+ (long unsigned)dp->bsize));
+#endif /* LARGE_SMB_OFF_T */
+ return 0;
+ }
+
+ DEBUG (0, ("get_quota_command failed!\n"));
+ return -1;
+ }
+
+ errno = ENOSYS;
+ return -1;
+
+invalid_param:
+
+ file_lines_free(lines);
+ DEBUG(0,("The output of get_quota_command is invalid!\n"));
+ return -1;
+}
+
+static int command_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+{
+ const char *set_quota_command;
+
+ set_quota_command = lp_set_quota_command();
+ if (set_quota_command && *set_quota_command) {
+ char **lines = NULL;
+ char *syscmd = NULL;
+ int _id = -1;
+
+ switch(qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ case SMB_USER_FS_QUOTA_TYPE:
+ _id = id.uid;
+ break;
+ case SMB_GROUP_QUOTA_TYPE:
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ _id = id.gid;
+ break;
+ default:
+ return -1;
+ }
+
+#ifdef LARGE_SMB_OFF_T
+ if (asprintf(&syscmd,
+ "%s \"%s\" %d %d "
+ "%u %llu %llu "
+ "%llu %llu %llu ",
+ set_quota_command, path, qtype, _id, dp->qflags,
+ (long long unsigned)dp->softlimit,(long long unsigned)dp->hardlimit,
+ (long long unsigned)dp->isoftlimit,(long long unsigned)dp->ihardlimit,
+ (long long unsigned)dp->bsize) < 0) {
+ return -1;
+ }
+#else /* LARGE_SMB_OFF_T */
+ if (asprintf(&syscmd,
+ "%s \"%s\" %d %d "
+ "%u %lu %lu "
+ "%lu %lu %lu ",
+ set_quota_command, path, qtype, _id, dp->qflags,
+ (long unsigned)dp->softlimit,(long unsigned)dp->hardlimit,
+ (long unsigned)dp->isoftlimit,(long unsigned)dp->ihardlimit,
+ (long unsigned)dp->bsize) < 0) {
+ return -1;
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ DEBUG (3, ("get_quota: Running command %s\n", syscmd));
+
+ lines = file_lines_pload(syscmd, NULL);
+ SAFE_FREE(syscmd);
+ if (lines) {
+ char *line = lines[0];
+
+ DEBUG (3, ("Read output from set_quota, \"%s\"\n", line));
+
+ file_lines_free(lines);
+
+ return 0;
+ }
+ DEBUG (0, ("set_quota_command failed!\n"));
+ return -1;
+ }
+
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+{
+ int ret = -1;
+ int i;
+ bool ready = False;
+ char *mntpath = NULL;
+ char *bdev = NULL;
+ char *fs = NULL;
+
+ if (!path||!dp)
+ smb_panic("sys_get_quota: called with NULL pointer");
+
+ if (command_get_quota(path, qtype, id, dp)==0) {
+ return 0;
+ } else if (errno != ENOSYS) {
+ return -1;
+ }
+
+ if ((ret=sys_path_to_bdev(path,&mntpath,&bdev,&fs))!=0) {
+ DEBUG(0,("sys_path_to_bdev() failed for path [%s]!\n",path));
+ return ret;
+ }
+
+ errno = 0;
+ DEBUG(10,("sys_get_quota() uid(%u, %u)\n", (unsigned)getuid(), (unsigned)geteuid()));
+
+ for (i=0;(fs && sys_quota_backends[i].name && sys_quota_backends[i].get_quota);i++) {
+ if (strcmp(fs,sys_quota_backends[i].name)==0) {
+ ret = sys_quota_backends[i].get_quota(mntpath, bdev, qtype, id, dp);
+ if (ret!=0) {
+ DEBUG(3,("sys_get_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
+ fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
+ } else {
+ DEBUG(10,("sys_get_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
+ fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
+ }
+ ready = True;
+ break;
+ }
+ }
+
+ if (!ready) {
+ /* use the default vfs quota functions */
+ ret=sys_get_vfs_quota(mntpath, bdev, qtype, id, dp);
+ if (ret!=0) {
+ DEBUG(3,("sys_get_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s\n",
+ "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
+ } else {
+ DEBUG(10,("sys_get_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
+ "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
+ }
+ }
+
+ SAFE_FREE(mntpath);
+ SAFE_FREE(bdev);
+ SAFE_FREE(fs);
+
+ if ((ret!=0)&& (errno == EDQUOT)) {
+ DEBUG(10,("sys_get_quota() warning over quota!\n"));
+ return 0;
+ }
+
+ return ret;
+}
+
+int sys_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+{
+ int ret = -1;
+ int i;
+ bool ready = False;
+ char *mntpath = NULL;
+ char *bdev = NULL;
+ char *fs = NULL;
+
+ /* find the block device file */
+
+ if (!path||!dp)
+ smb_panic("get_smb_quota: called with NULL pointer");
+
+ if (command_set_quota(path, qtype, id, dp)==0) {
+ return 0;
+ } else if (errno != ENOSYS) {
+ return -1;
+ }
+
+ if ((ret=sys_path_to_bdev(path,&mntpath,&bdev,&fs))!=0) {
+ DEBUG(0,("sys_path_to_bdev() failed for path [%s]!\n",path));
+ return ret;
+ }
+
+ errno = 0;
+ DEBUG(10,("sys_set_quota() uid(%u, %u)\n", (unsigned)getuid(), (unsigned)geteuid()));
+
+ for (i=0;(fs && sys_quota_backends[i].name && sys_quota_backends[i].set_quota);i++) {
+ if (strcmp(fs,sys_quota_backends[i].name)==0) {
+ ret = sys_quota_backends[i].set_quota(mntpath, bdev, qtype, id, dp);
+ if (ret!=0) {
+ DEBUG(3,("sys_set_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
+ fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
+ } else {
+ DEBUG(10,("sys_set_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
+ fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
+ }
+ ready = True;
+ break;
+ }
+ }
+
+ if (!ready) {
+ /* use the default vfs quota functions */
+ ret=sys_set_vfs_quota(mntpath, bdev, qtype, id, dp);
+ if (ret!=0) {
+ DEBUG(3,("sys_set_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
+ "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
+ } else {
+ DEBUG(10,("sys_set_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
+ "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
+ }
+ }
+
+ SAFE_FREE(mntpath);
+ SAFE_FREE(bdev);
+ SAFE_FREE(fs);
+
+ if ((ret!=0)&& (errno == EDQUOT)) {
+ DEBUG(10,("sys_set_quota() warning over quota!\n"));
+ return 0;
+ }
+
+ return ret;
+}
+
+#else /* HAVE_SYS_QUOTAS */
+ void dummy_sysquotas_c(void);
+
+ void dummy_sysquotas_c(void)
+{
+ return;
+}
+#endif /* HAVE_SYS_QUOTAS */
+
diff --git a/source3/lib/sysquotas_4A.c b/source3/lib/sysquotas_4A.c
new file mode 100644
index 0000000000..f185bba6df
--- /dev/null
+++ b/source3/lib/sysquotas_4A.c
@@ -0,0 +1,346 @@
+/*
+ Unix SMB/CIFS implementation.
+ System QUOTA function wrappers for QUOTACTL_4A
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_QUOTA
+
+#ifndef HAVE_SYS_QUOTAS
+#ifdef HAVE_QUOTACTL_4A
+#undef HAVE_QUOTACTL_4A
+#endif
+#endif
+
+#ifdef HAVE_QUOTACTL_4A
+/* long quotactl(int cmd, char *special, qid_t id, caddr_t addr) */
+/* this is used by: HPUX,IRIX */
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+
+#ifdef HAVE_SYS_QUOTA_H
+#include <sys/quota.h>
+#endif
+
+#ifndef Q_SETQLIM
+#define Q_SETQLIM Q_SETQUOTA
+#endif
+
+#ifndef QCMD
+#define QCMD(x,y) x
+#endif
+
+#ifndef QCMD
+#define QCMD(x,y) x
+#endif
+
+#ifdef GRPQUOTA
+#define HAVE_GROUP_QUOTA
+#endif
+
+#ifndef QUOTABLOCK_SIZE
+#define QUOTABLOCK_SIZE DEV_BSIZE
+#endif
+
+#ifdef HAVE_DQB_FSOFTLIMIT
+#define dqb_isoftlimit dqb_fsoftlimit
+#define dqb_ihardlimit dqb_fhardlimit
+#define dqb_curinodes dqb_curfiles
+#endif
+
+#ifdef INITQFNAMES
+#define USERQUOTAFILE_EXTENSION ".user"
+#else
+#define USERQUOTAFILE_EXTENSION ""
+#endif
+
+#if !defined(QUOTAFILENAME) && defined(QFILENAME)
+#define QUOTAFILENAME QFILENAME
+#endif
+
+/****************************************************************************
+ Abstract out the quotactl_4A get calls.
+****************************************************************************/
+int sys_get_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+{
+ int ret = -1;
+ uint32 qflags = 0;
+ struct dqblk D;
+ SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
+
+ ZERO_STRUCT(D);
+ ZERO_STRUCT(*dp);
+ dp->qtype = qtype;
+
+ switch (qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ DEBUG(10,("sys_get_vfs_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
+ path, bdev, (unsigned)id.uid));
+
+ if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), (caddr_t)bdev, id.uid, (void *)&D))&&errno != EDQUOT) {
+ return ret;
+ }
+
+ if ((D.dqb_curblocks==0)&&
+ (D.dqb_bsoftlimit==0)&&
+ (D.dqb_bhardlimit==0)) {
+ /* the upper layer functions don't want empty quota records...*/
+ return -1;
+ }
+
+ break;
+#ifdef HAVE_GROUP_QUOTA
+ case SMB_GROUP_QUOTA_TYPE:
+ DEBUG(10,("sys_get_vfs_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
+ path, bdev, (unsigned)id.gid));
+
+ if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), (caddr_t)bdev, id.gid, (void *)&D))&&errno != EDQUOT) {
+ return ret;
+ }
+
+ if ((D.dqb_curblocks==0)&&
+ (D.dqb_bsoftlimit==0)&&
+ (D.dqb_bhardlimit==0)) {
+ /* the upper layer functions don't want empty quota records...*/
+ return -1;
+ }
+
+ break;
+#endif /* HAVE_GROUP_QUOTA */
+ case SMB_USER_FS_QUOTA_TYPE:
+ id.uid = getuid();
+
+ DEBUG(10,("sys_get_vfs_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
+ path, (caddr_t)bdev, (unsigned)id.uid));
+
+ if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), (caddr_t)bdev, id.uid, (void *)&D))==0) {
+ qflags |= QUOTAS_DENY_DISK;
+ }
+
+ ret = 0;
+ break;
+#ifdef HAVE_GROUP_QUOTA
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ id.gid = getgid();
+
+ DEBUG(10,("sys_get_vfs_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
+ path, bdev, (unsigned)id.gid));
+
+ if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), (caddr_t)bdev, id.gid, (void *)&D))==0) {
+ qflags |= QUOTAS_DENY_DISK;
+ }
+
+ ret = 0;
+ break;
+#endif /* HAVE_GROUP_QUOTA */
+ default:
+ errno = ENOSYS;
+ return -1;
+ }
+
+ dp->bsize = bsize;
+ dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
+ dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
+ dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
+ dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
+ dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
+ dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
+
+
+ dp->qflags = qflags;
+
+ return ret;
+}
+
+/****************************************************************************
+ Abstract out the quotactl_4A set calls.
+****************************************************************************/
+int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+{
+ int ret = -1;
+ uint32 qflags = 0;
+ uint32 oldqflags = 0;
+ struct dqblk D;
+ SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
+
+ ZERO_STRUCT(D);
+
+ if (bsize == dp->bsize) {
+ D.dqb_bsoftlimit = dp->softlimit;
+ D.dqb_bhardlimit = dp->hardlimit;
+ D.dqb_ihardlimit = dp->ihardlimit;
+ D.dqb_isoftlimit = dp->isoftlimit;
+ } else {
+ D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize;
+ D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize;
+ D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize;
+ D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize;
+ }
+
+ qflags = dp->qflags;
+
+ switch (qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ DEBUG(10,("sys_set_vfs_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
+ path, bdev, (unsigned)id.uid));
+
+ ret = quotactl(QCMD(Q_SETQLIM,USRQUOTA), (caddr_t)bdev, id.uid, (void *)&D);
+ break;
+#ifdef HAVE_GROUP_QUOTA
+ case SMB_GROUP_QUOTA_TYPE:
+ DEBUG(10,("sys_set_vfs_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
+ path, bdev, (unsigned)id.gid));
+
+ ret = quotactl(QCMD(Q_SETQLIM,GRPQUOTA), (caddr_t)bdev, id.gid, (void *)&D);
+ break;
+#endif /* HAVE_GROUP_QUOTA */
+ case SMB_USER_FS_QUOTA_TYPE:
+ /* this stuff didn't work as it should:
+ * switching on/off quota via quotactl()
+ * didn't work!
+ * So we just return 0
+ * --metze
+ *
+ * On HPUX we didn't have the mount path,
+ * we need to fix sys_path_to_bdev()
+ *
+ */
+ id.uid = getuid();
+ DEBUG(10,("sys_set_vfs_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
+ path, bdev, (unsigned)id.uid));
+
+#if 0
+ ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), (caddr_t)bdev, id.uid, (void *)&D);
+
+ if ((qflags&QUOTAS_DENY_DISK)||(qflags&QUOTAS_ENABLED)) {
+ if (ret == 0) {
+ char *quota_file = NULL;
+
+ asprintf(&quota_file,"/%s/%s%s",path, QUOTAFILENAME,USERQUOTAFILE_EXTENSION);
+ if (quota_file == NULL) {
+ DEBUG(0,("asprintf() failed!\n"));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ ret = quotactl(QCMD(Q_QUOTAON,USRQUOTA), (caddr_t)bdev, -1,(void *)quota_file);
+ } else {
+ ret = 0;
+ }
+ } else {
+ if (ret != 0) {
+ /* turn off */
+ ret = quotactl(QCMD(Q_QUOTAOFF,USRQUOTA), (caddr_t)bdev, -1, (void *)0);
+ } else {
+ ret = 0;
+ }
+ }
+
+ DEBUG(0,("sys_set_vfs_quota: ret(%d) errno(%d)[%s] uid(%d) bdev[%s]\n",
+ ret,errno,strerror(errno),id.uid,bdev));
+#else
+ if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), (caddr_t)bdev, id.uid, (void *)&D))==0) {
+ oldqflags |= QUOTAS_DENY_DISK;
+ }
+
+ if (oldqflags == qflags) {
+ ret = 0;
+ } else {
+ ret = -1;
+ }
+#endif
+ break;
+#ifdef HAVE_GROUP_QUOTA
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ /* this stuff didn't work as it should:
+ * switching on/off quota via quotactl()
+ * didn't work!
+ * So we just return 0
+ * --metze
+ *
+ * On HPUX we didn't have the mount path,
+ * we need to fix sys_path_to_bdev()
+ *
+ */
+ id.gid = getgid();
+ DEBUG(10,("sys_set_vfs_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
+ path, bdev, (unsigned)id.gid));
+
+#if 0
+ ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id, (void *)&D);
+
+ if ((qflags&QUOTAS_DENY_DISK)||(qflags&QUOTAS_ENABLED)) {
+ if (ret == 0) {
+ char *quota_file = NULL;
+
+ asprintf(&quota_file,"/%s/%s%s",path, QUOTAFILENAME,GROUPQUOTAFILE_EXTENSION);
+ if (quota_file == NULL) {
+ DEBUG(0,("asprintf() failed!\n"));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ ret = quotactl(QCMD(Q_QUOTAON,GRPQUOTA), (caddr_t)bdev, -1,(void *)quota_file);
+ } else {
+ ret = 0;
+ }
+ } else {
+ if (ret != 0) {
+ /* turn off */
+ ret = quotactl(QCMD(Q_QUOTAOFF,GRPQUOTA), (caddr_t)bdev, -1, (void *)0);
+ } else {
+ ret = 0;
+ }
+ }
+
+ DEBUG(0,("sys_set_vfs_quota: ret(%d) errno(%d)[%s] uid(%d) bdev[%s]\n",
+ ret,errno,strerror(errno),id.gid,bdev));
+#else
+ if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), (caddr_t)bdev, id.gid, (void *)&D))==0) {
+ oldqflags |= QUOTAS_DENY_DISK;
+ }
+
+ if (oldqflags == qflags) {
+ ret = 0;
+ } else {
+ ret = -1;
+ }
+#endif
+ break;
+#endif /* HAVE_GROUP_QUOTA */
+ default:
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return ret;
+}
+
+#else /* HAVE_QUOTACTL_4A */
+ void dummy_sysquotas_4A(void);
+
+ void dummy_sysquotas_4A(void){}
+#endif /* HAVE_QUOTACTL_4A */
diff --git a/source3/lib/sysquotas_linux.c b/source3/lib/sysquotas_linux.c
new file mode 100644
index 0000000000..f9a0464086
--- /dev/null
+++ b/source3/lib/sysquotas_linux.c
@@ -0,0 +1,568 @@
+/*
+ Unix SMB/CIFS implementation.
+ System QUOTA function wrappers for LINUX
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_QUOTA
+
+#ifndef HAVE_SYS_QUOTAS
+#ifdef HAVE_QUOTACTL_LINUX
+#undef HAVE_QUOTACTL_LINUX
+#endif
+#endif
+
+#ifdef HAVE_QUOTACTL_LINUX
+
+#include "samba_linux_quota.h"
+
+/****************************************************************************
+ Abstract out the v1 Linux quota get calls.
+****************************************************************************/
+static int sys_get_linux_v1_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+{
+ int ret = -1;
+ uint32 qflags = 0;
+ struct v1_kern_dqblk D;
+ SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
+
+ ZERO_STRUCT(D);
+
+ switch (qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
+ path, bdev, (unsigned)id.uid));
+
+ if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))&&errno != EDQUOT) {
+ return ret;
+ }
+
+ break;
+ case SMB_GROUP_QUOTA_TYPE:
+ DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
+ path, bdev, (unsigned)id.gid));
+
+ if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))&&errno != EDQUOT) {
+ return ret;
+ }
+
+ break;
+ case SMB_USER_FS_QUOTA_TYPE:
+ DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
+ path, bdev, (unsigned)id.uid));
+
+ if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
+ qflags |= QUOTAS_DENY_DISK;
+ }
+
+ break;
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
+ path, bdev, (unsigned)id.gid));
+
+ if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
+ qflags |= QUOTAS_DENY_DISK;
+ }
+
+ break;
+ default:
+ errno = ENOSYS;
+ return -1;
+ }
+
+ dp->bsize = bsize;
+ dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
+ dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
+ dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
+ dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
+ dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
+ dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
+
+
+ dp->qflags = qflags;
+
+ return ret;
+}
+
+/****************************************************************************
+ Abstract out the v1 Linux quota set calls.
+****************************************************************************/
+static int sys_set_linux_v1_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+{
+ int ret = -1;
+ uint32 qflags = 0;
+ uint32 oldqflags = 0;
+ struct v1_kern_dqblk D;
+ SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
+
+ ZERO_STRUCT(D);
+
+ if (bsize == dp->bsize) {
+ D.dqb_bsoftlimit = dp->softlimit;
+ D.dqb_bhardlimit = dp->hardlimit;
+ D.dqb_ihardlimit = dp->ihardlimit;
+ D.dqb_isoftlimit = dp->isoftlimit;
+ } else {
+ D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize;
+ D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize;
+ D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize;
+ D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize;
+ }
+
+ qflags = dp->qflags;
+
+ switch (qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
+ path, bdev, (unsigned)id.uid));
+
+ ret = quotactl(QCMD(Q_V1_SETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D);
+ break;
+ case SMB_GROUP_QUOTA_TYPE:
+ DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
+ path, bdev, (unsigned)id.gid));
+
+ ret = quotactl(QCMD(Q_V1_SETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D);
+ break;
+ case SMB_USER_FS_QUOTA_TYPE:
+ DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
+ path, bdev, (unsigned)id.uid));
+
+ if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
+ oldqflags |= QUOTAS_DENY_DISK;
+ }
+
+ break;
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
+ path, bdev, (unsigned)id.gid));
+
+ if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
+ oldqflags |= QUOTAS_DENY_DISK;
+ }
+
+ break;
+ default:
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Abstract out the v2 Linux quota get calls.
+****************************************************************************/
+static int sys_get_linux_v2_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+{
+ int ret = -1;
+ uint32 qflags = 0;
+ struct v2_kern_dqblk D;
+ SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
+
+ ZERO_STRUCT(D);
+
+ switch (qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
+ path, bdev, (unsigned)id.uid));
+
+ if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))&&errno != EDQUOT) {
+ return ret;
+ }
+
+ break;
+ case SMB_GROUP_QUOTA_TYPE:
+ DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
+ path, bdev, (unsigned)id.gid));
+
+ if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))&&errno != EDQUOT) {
+ return ret;
+ }
+
+ break;
+ case SMB_USER_FS_QUOTA_TYPE:
+ DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
+ path, bdev, (unsigned)id.uid));
+
+ if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
+ qflags |= QUOTAS_DENY_DISK;
+ }
+
+ break;
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
+ path, bdev, (unsigned)id.gid));
+
+ if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
+ qflags |= QUOTAS_DENY_DISK;
+ }
+
+ break;
+ default:
+ errno = ENOSYS;
+ return -1;
+ }
+
+ dp->bsize = bsize;
+ dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
+ dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
+ dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
+ dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
+ dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
+ dp->curblocks = (SMB_BIG_UINT)D.dqb_curspace/bsize;
+
+
+ dp->qflags = qflags;
+
+ return ret;
+}
+
+/****************************************************************************
+ Abstract out the v2 Linux quota set calls.
+****************************************************************************/
+static int sys_set_linux_v2_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+{
+ int ret = -1;
+ uint32 qflags = 0;
+ uint32 oldqflags = 0;
+ struct v2_kern_dqblk D;
+ SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
+
+ ZERO_STRUCT(D);
+
+ if (bsize == dp->bsize) {
+ D.dqb_bsoftlimit = dp->softlimit;
+ D.dqb_bhardlimit = dp->hardlimit;
+ D.dqb_ihardlimit = dp->ihardlimit;
+ D.dqb_isoftlimit = dp->isoftlimit;
+ } else {
+ D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize;
+ D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize;
+ D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize;
+ D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize;
+ }
+
+ qflags = dp->qflags;
+
+ switch (qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
+ path, bdev, (unsigned)id.uid));
+
+ ret = quotactl(QCMD(Q_V2_SETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D);
+ break;
+ case SMB_GROUP_QUOTA_TYPE:
+ DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
+ path, bdev, (unsigned)id.gid));
+
+ ret = quotactl(QCMD(Q_V2_SETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D);
+ break;
+ case SMB_USER_FS_QUOTA_TYPE:
+ DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
+ path, bdev, (unsigned)id.uid));
+
+ if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
+ oldqflags |= QUOTAS_DENY_DISK;
+ }
+
+ break;
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
+ path, bdev, (unsigned)id.gid));
+
+ if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
+ oldqflags |= QUOTAS_DENY_DISK;
+ }
+
+ break;
+ default:
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Abstract out the generic Linux quota get calls.
+****************************************************************************/
+static int sys_get_linux_gen_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+{
+ int ret = -1;
+ uint32 qflags = 0;
+ struct if_dqblk D;
+ SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
+
+ ZERO_STRUCT(D);
+
+ switch (qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
+ path, bdev, (unsigned)id.uid));
+
+ if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))&&errno != EDQUOT) {
+ return ret;
+ }
+
+ break;
+ case SMB_GROUP_QUOTA_TYPE:
+ DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
+ path, bdev, (unsigned)id.gid));
+
+ if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))&&errno != EDQUOT) {
+ return ret;
+ }
+
+ break;
+ case SMB_USER_FS_QUOTA_TYPE:
+ DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
+ path, bdev, (unsigned)id.uid));
+
+ if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
+ qflags |= QUOTAS_DENY_DISK;
+ }
+
+ break;
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
+ path, bdev, (unsigned)id.gid));
+
+ if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
+ qflags |= QUOTAS_DENY_DISK;
+ }
+
+ break;
+ default:
+ errno = ENOSYS;
+ return -1;
+ }
+
+ dp->bsize = bsize;
+ dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
+ dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
+ dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
+ dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
+ dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
+ dp->curblocks = (SMB_BIG_UINT)D.dqb_curspace/bsize;
+
+
+ dp->qflags = qflags;
+
+ return ret;
+}
+
+/****************************************************************************
+ Abstract out the gen Linux quota set calls.
+****************************************************************************/
+static int sys_set_linux_gen_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+{
+ int ret = -1;
+ uint32 qflags = 0;
+ uint32 oldqflags = 0;
+ struct if_dqblk D;
+ SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
+
+ ZERO_STRUCT(D);
+
+ if (bsize == dp->bsize) {
+ D.dqb_bsoftlimit = dp->softlimit;
+ D.dqb_bhardlimit = dp->hardlimit;
+ D.dqb_ihardlimit = dp->ihardlimit;
+ D.dqb_isoftlimit = dp->isoftlimit;
+ } else {
+ D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize;
+ D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize;
+ D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize;
+ D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize;
+ }
+ D.dqb_valid = QIF_LIMITS;
+
+ qflags = dp->qflags;
+
+ switch (qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
+ path, bdev, (unsigned)id.uid));
+
+ ret = quotactl(QCMD(Q_SETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D);
+ break;
+ case SMB_GROUP_QUOTA_TYPE:
+ DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
+ path, bdev, (unsigned)id.gid));
+
+ ret = quotactl(QCMD(Q_SETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D);
+ break;
+ case SMB_USER_FS_QUOTA_TYPE:
+ DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
+ path, bdev, (unsigned)id.uid));
+
+ if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
+ oldqflags |= QUOTAS_DENY_DISK;
+ }
+
+ break;
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
+ path, bdev, (unsigned)id.gid));
+
+ if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
+ oldqflags |= QUOTAS_DENY_DISK;
+ }
+
+ break;
+ default:
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Abstract out the Linux quota get calls.
+****************************************************************************/
+int sys_get_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+{
+ int ret = -1;
+
+ if (!path||!bdev||!dp)
+ smb_panic("sys_set_vfs_quota: called with NULL pointer");
+
+ ZERO_STRUCT(*dp);
+ dp->qtype = qtype;
+
+ switch (qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ case SMB_GROUP_QUOTA_TYPE:
+ if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
+ if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
+ if ((ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
+ return ret;
+ }
+ }
+ }
+
+ if ((dp->curblocks==0)&&
+ (dp->softlimit==0)&&
+ (dp->hardlimit==0)) {
+ /* the upper layer functions don't want empty quota records...*/
+ return -1;
+ }
+
+ break;
+ case SMB_USER_FS_QUOTA_TYPE:
+ id.uid = getuid();
+
+ if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
+ if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
+ ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp);
+ }
+ }
+
+ ret = 0;
+ break;
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ id.gid = getgid();
+
+ if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
+ if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
+ ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp);
+ }
+ }
+
+ ret = 0;
+ break;
+ default:
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Abstract out the Linux quota set calls.
+****************************************************************************/
+int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+{
+ int ret = -1;
+ uint32 oldqflags = 0;
+
+ if (!path||!bdev||!dp)
+ smb_panic("sys_set_vfs_quota: called with NULL pointer");
+
+ oldqflags = dp->qflags;
+
+ switch (qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ case SMB_GROUP_QUOTA_TYPE:
+ if ((ret=sys_set_linux_gen_quota(path, bdev, qtype, id, dp))) {
+ if ((ret=sys_set_linux_v2_quota(path, bdev, qtype, id, dp))) {
+ if ((ret=sys_set_linux_v1_quota(path, bdev, qtype, id, dp))) {
+ return ret;
+ }
+ }
+ }
+ break;
+ case SMB_USER_FS_QUOTA_TYPE:
+ id.uid = getuid();
+
+ if ((ret=sys_set_linux_gen_quota(path, bdev, qtype, id, dp))) {
+ if ((ret=sys_set_linux_v2_quota(path, bdev, qtype, id, dp))) {
+ ret=sys_set_linux_v1_quota(path, bdev, qtype, id, dp);
+ }
+ }
+
+ if (oldqflags == dp->qflags) {
+ ret = 0;
+ } else {
+ ret = -1;
+ }
+ break;
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ id.gid = getgid();
+
+ if ((ret=sys_set_linux_gen_quota(path, bdev, qtype, id, dp))) {
+ if ((ret=sys_set_linux_v2_quota(path, bdev, qtype, id, dp))) {
+ ret=sys_set_linux_v1_quota(path, bdev, qtype, id, dp);
+ }
+ }
+
+ if (oldqflags == dp->qflags) {
+ ret = 0;
+ } else {
+ ret = -1;
+ }
+
+ break;
+ default:
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return ret;
+}
+
+#else /* HAVE_QUOTACTL_LINUX */
+ void dummy_sysquotas_linux(void);
+
+ void dummy_sysquotas_linux(void){}
+#endif /* HAVE_QUOTACTL_LINUX */
diff --git a/source3/lib/sysquotas_xfs.c b/source3/lib/sysquotas_xfs.c
new file mode 100644
index 0000000000..30538c167b
--- /dev/null
+++ b/source3/lib/sysquotas_xfs.c
@@ -0,0 +1,336 @@
+/*
+ Unix SMB/CIFS implementation.
+ System QUOTA function wrappers for XFS
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_QUOTA
+
+#ifndef HAVE_SYS_QUOTAS
+#ifdef HAVE_XFS_QUOTAS
+#undef HAVE_XFS_QUOTAS
+#endif
+#endif
+
+#ifdef HAVE_XFS_QUOTAS
+
+#ifdef HAVE_LINUX_XFS_QUOTAS
+#include "samba_linux_quota.h"
+#ifdef HAVE_LINUX_DQBLK_XFS_H
+#include <linux/dqblk_xfs.h>
+#endif
+#define HAVE_GROUP_QUOTA
+#else /* IRIX */
+#include <sys/quota.h>
+#endif
+
+/* on IRIX */
+#ifndef Q_XQUOTAON
+#define Q_XQUOTAON Q_QUOTAON
+#endif /* Q_XQUOTAON */
+#ifndef Q_XQUOTAOFF
+#define Q_XQUOTAOFF Q_QUOTAOFF
+#endif /* Q_XQUOTAOFF */
+#ifndef Q_XGETQSTAT
+#define Q_XGETQSTAT Q_GETQSTAT
+#endif /* Q_XGETQSTAT */
+
+/* currently doesn't support Group and Project quotas on IRIX
+ */
+
+#ifndef QCMD
+#define QCMD(x,y) x
+#endif
+
+/*
+ * IRIX has BBSIZE in <sys/param.h>
+ */
+#ifndef BBSHIFT
+#define BBSHIFT 9
+#endif /* BBSHIFT */
+#ifndef BBSIZE
+#define BBSIZE (1<<BBSHIFT)
+#endif /* BBSIZE */
+
+/****************************************************************************
+ Abstract out the XFS Quota Manager quota get call.
+****************************************************************************/
+int sys_get_xfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+{
+ int ret = -1;
+ uint32 qflags = 0;
+ SMB_BIG_UINT bsize = (SMB_BIG_UINT)BBSIZE;
+ struct fs_disk_quota D;
+ struct fs_quota_stat F;
+ ZERO_STRUCT(D);
+ ZERO_STRUCT(F);
+
+ if (!bdev||!dp)
+ smb_panic("sys_get_xfs_quota: called with NULL pointer");
+
+ ZERO_STRUCT(*dp);
+ dp->qtype = qtype;
+
+ switch (qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ DEBUG(10,("sys_get_xfs_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
+ path, bdev, (unsigned)id.uid));
+
+ if ((ret=quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D)))
+ return ret;
+ break;
+#ifdef HAVE_GROUP_QUOTA
+ case SMB_GROUP_QUOTA_TYPE:
+ DEBUG(10,("sys_get_xfs_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
+ path, bdev, (unsigned)id.gid));
+
+ if ((ret=quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D)))
+ return ret;
+ break;
+#endif /* HAVE_GROUP_QUOTA */
+ case SMB_USER_FS_QUOTA_TYPE:
+ DEBUG(10,("sys_get_xfs_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
+ path, bdev, (unsigned)id.uid));
+
+ quotactl(QCMD(Q_XGETQSTAT,USRQUOTA), bdev, -1, (caddr_t)&F);
+
+ if (F.qs_flags & XFS_QUOTA_UDQ_ENFD) {
+ qflags |= QUOTAS_DENY_DISK;
+ }
+ else if (F.qs_flags & XFS_QUOTA_UDQ_ACCT) {
+ qflags |= QUOTAS_ENABLED;
+ }
+
+ ret = 0;
+
+ break;
+#ifdef HAVE_GROUP_QUOTA
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ DEBUG(10,("sys_get_xfs_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
+ path, bdev, (unsigned)id.gid));
+
+ quotactl(QCMD(Q_XGETQSTAT,GRPQUOTA), bdev, -1, (caddr_t)&F);
+
+ if (F.qs_flags & XFS_QUOTA_GDQ_ENFD) {
+ qflags |= QUOTAS_DENY_DISK;
+ }
+ else if (F.qs_flags & XFS_QUOTA_GDQ_ACCT) {
+ qflags |= QUOTAS_ENABLED;
+ }
+
+ ret = 0;
+
+ break;
+#endif /* HAVE_GROUP_QUOTA */
+ default:
+ errno = ENOSYS;
+ return -1;
+ }
+
+ dp->bsize = bsize;
+ dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit;
+ dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit;
+ dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit;
+ dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit;
+ dp->curinodes = (SMB_BIG_UINT)D.d_icount;
+ dp->curblocks = (SMB_BIG_UINT)D.d_bcount;
+ dp->qflags = qflags;
+
+ return ret;
+}
+
+/****************************************************************************
+ Abstract out the XFS Quota Manager quota set call.
+****************************************************************************/
+int sys_set_xfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+{
+ int ret = -1;
+ uint32 qflags = 0;
+ SMB_BIG_UINT bsize = (SMB_BIG_UINT)BBSIZE;
+ struct fs_disk_quota D;
+ struct fs_quota_stat F;
+ int q_on = 0;
+ int q_off = 0;
+ ZERO_STRUCT(D);
+ ZERO_STRUCT(F);
+
+ if (!bdev||!dp)
+ smb_panic("sys_set_xfs_quota: called with NULL pointer");
+
+ if (bsize == dp->bsize) {
+ D.d_blk_softlimit = dp->softlimit;
+ D.d_blk_hardlimit = dp->hardlimit;
+ D.d_ino_hardlimit = dp->ihardlimit;
+ D.d_ino_softlimit = dp->isoftlimit;
+ } else {
+ D.d_blk_softlimit = (dp->softlimit*dp->bsize)/bsize;
+ D.d_blk_hardlimit = (dp->hardlimit*dp->bsize)/bsize;
+ D.d_ino_hardlimit = (dp->ihardlimit*dp->bsize)/bsize;
+ D.d_ino_softlimit = (dp->isoftlimit*dp->bsize)/bsize;
+ }
+
+ qflags = dp->qflags;
+
+ switch (qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ DEBUG(10,("sys_set_xfs_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
+ path, bdev, (unsigned)id.uid));
+
+ D.d_fieldmask |= FS_DQ_LIMIT_MASK;
+ ret = quotactl(QCMD(Q_XSETQLIM,USRQUOTA), bdev, id.uid, (caddr_t)&D);
+ break;
+#ifdef HAVE_GROUP_QUOTA
+ case SMB_GROUP_QUOTA_TYPE:
+ DEBUG(10,("sys_set_xfs_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
+ path, bdev, (unsigned)id.gid));
+
+ D.d_fieldmask |= FS_DQ_LIMIT_MASK;
+ ret = quotactl(QCMD(Q_XSETQLIM,GRPQUOTA), bdev, id.gid, (caddr_t)&D);
+ break;
+#endif /* HAVE_GROUP_QUOTA */
+ case SMB_USER_FS_QUOTA_TYPE:
+ DEBUG(10,("sys_set_xfs_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
+ path, bdev, (unsigned)id.uid));
+
+ quotactl(QCMD(Q_XGETQSTAT,USRQUOTA), bdev, -1, (caddr_t)&F);
+
+ if (qflags & QUOTAS_DENY_DISK) {
+ if (!(F.qs_flags & XFS_QUOTA_UDQ_ENFD))
+ q_on |= XFS_QUOTA_UDQ_ENFD;
+ if (!(F.qs_flags & XFS_QUOTA_UDQ_ACCT))
+ q_on |= XFS_QUOTA_UDQ_ACCT;
+
+ if (q_on != 0) {
+ ret = quotactl(QCMD(Q_XQUOTAON,USRQUOTA),bdev, -1, (caddr_t)&q_on);
+ } else {
+ ret = 0;
+ }
+
+ } else if (qflags & QUOTAS_ENABLED) {
+ if (F.qs_flags & XFS_QUOTA_UDQ_ENFD)
+ q_off |= XFS_QUOTA_UDQ_ENFD;
+
+ if (q_off != 0) {
+ ret = quotactl(QCMD(Q_XQUOTAOFF,USRQUOTA),bdev, -1, (caddr_t)&q_off);
+ } else {
+ ret = 0;
+ }
+
+ if (!(F.qs_flags & XFS_QUOTA_UDQ_ACCT))
+ q_on |= XFS_QUOTA_UDQ_ACCT;
+
+ if (q_on != 0) {
+ ret = quotactl(QCMD(Q_XQUOTAON,USRQUOTA),bdev, -1, (caddr_t)&q_on);
+ } else {
+ ret = 0;
+ }
+ } else {
+#if 0
+ /* Switch on XFS_QUOTA_UDQ_ACCT didn't work!
+ * only swittching off XFS_QUOTA_UDQ_ACCT work
+ */
+ if (F.qs_flags & XFS_QUOTA_UDQ_ENFD)
+ q_off |= XFS_QUOTA_UDQ_ENFD;
+ if (F.qs_flags & XFS_QUOTA_UDQ_ACCT)
+ q_off |= XFS_QUOTA_UDQ_ACCT;
+
+ if (q_off !=0) {
+ ret = quotactl(QCMD(Q_XQUOTAOFF,USRQUOTA),bdev, -1, (caddr_t)&q_off);
+ } else {
+ ret = 0;
+ }
+#else
+ ret = -1;
+#endif
+ }
+
+ break;
+#ifdef HAVE_GROUP_QUOTA
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ DEBUG(10,("sys_set_xfs_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
+ path, bdev, (unsigned)id.gid));
+
+ quotactl(QCMD(Q_XGETQSTAT,GRPQUOTA), bdev, -1, (caddr_t)&F);
+
+ if (qflags & QUOTAS_DENY_DISK) {
+ if (!(F.qs_flags & XFS_QUOTA_GDQ_ENFD))
+ q_on |= XFS_QUOTA_GDQ_ENFD;
+ if (!(F.qs_flags & XFS_QUOTA_GDQ_ACCT))
+ q_on |= XFS_QUOTA_GDQ_ACCT;
+
+ if (q_on != 0) {
+ ret = quotactl(QCMD(Q_XQUOTAON,GRPQUOTA),bdev, -1, (caddr_t)&q_on);
+ } else {
+ ret = 0;
+ }
+
+ } else if (qflags & QUOTAS_ENABLED) {
+ if (F.qs_flags & XFS_QUOTA_GDQ_ENFD)
+ q_off |= XFS_QUOTA_GDQ_ENFD;
+
+ if (q_off != 0) {
+ ret = quotactl(QCMD(Q_XQUOTAOFF,GRPQUOTA),bdev, -1, (caddr_t)&q_off);
+ } else {
+ ret = 0;
+ }
+
+ if (!(F.qs_flags & XFS_QUOTA_GDQ_ACCT))
+ q_on |= XFS_QUOTA_GDQ_ACCT;
+
+ if (q_on != 0) {
+ ret = quotactl(QCMD(Q_XQUOTAON,GRPQUOTA),bdev, -1, (caddr_t)&q_on);
+ } else {
+ ret = 0;
+ }
+ } else {
+#if 0
+ /* Switch on XFS_QUOTA_UDQ_ACCT didn't work!
+ * only swittching off XFS_QUOTA_UDQ_ACCT work
+ */
+ if (F.qs_flags & XFS_QUOTA_GDQ_ENFD)
+ q_off |= XFS_QUOTA_GDQ_ENFD;
+ if (F.qs_flags & XFS_QUOTA_GDQ_ACCT)
+ q_off |= XFS_QUOTA_GDQ_ACCT;
+
+ if (q_off !=0) {
+ ret = quotactl(QCMD(Q_XQUOTAOFF,GRPQUOTA),bdev, -1, (caddr_t)&q_off);
+ } else {
+ ret = 0;
+ }
+#else
+ ret = -1;
+#endif
+ }
+
+ break;
+#endif /* HAVE_GROUP_QUOTA */
+ default:
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return ret;
+}
+
+#else /* HAVE_XFS_QUOTAS */
+ void dummy_sysquotas_xfs(void);
+
+ void dummy_sysquotas_xfs(void){}
+#endif /* HAVE_XFS_QUOTAS */
diff --git a/source3/lib/system.c b/source3/lib/system.c
new file mode 100644
index 0000000000..eabb6d6dc4
--- /dev/null
+++ b/source3/lib/system.c
@@ -0,0 +1,2492 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba system utilities
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1998-2005
+ Copyright (C) Timur Bakeyev 2005
+ Copyright (C) Bjoern Jacke 2006-2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
+
+/*
+ The idea is that this file will eventually have wrappers around all
+ 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.
+*/
+
+
+
+/*******************************************************************
+ A wrapper for memalign
+********************************************************************/
+
+void *sys_memalign( size_t align, size_t size )
+{
+#if defined(HAVE_POSIX_MEMALIGN)
+ void *p = NULL;
+ int ret = posix_memalign( &p, align, size );
+ if ( ret == 0 )
+ return p;
+
+ return NULL;
+#elif defined(HAVE_MEMALIGN)
+ return memalign( align, size );
+#else
+ /* On *BSD systems memaligns doesn't exist, but memory will
+ * be aligned on allocations of > pagesize. */
+#if defined(SYSCONF_SC_PAGESIZE)
+ size_t pagesize = (size_t)sysconf(_SC_PAGESIZE);
+#elif defined(HAVE_GETPAGESIZE)
+ size_t pagesize = (size_t)getpagesize();
+#else
+ size_t pagesize = (size_t)-1;
+#endif
+ if (pagesize == (size_t)-1) {
+ DEBUG(0,("memalign functionalaity not available on this platform!\n"));
+ return NULL;
+ }
+ if (size < pagesize) {
+ size = pagesize;
+ }
+ return SMB_MALLOC(size);
+#endif
+}
+
+/*******************************************************************
+ A wrapper for usleep in case we don't have one.
+********************************************************************/
+
+int sys_usleep(long usecs)
+{
+#ifndef HAVE_USLEEP
+ struct timeval tval;
+#endif
+
+ /*
+ * We need this braindamage as the glibc usleep
+ * is not SPEC1170 complient... grumble... JRA.
+ */
+
+ if(usecs < 0 || usecs > 1000000) {
+ errno = EINVAL;
+ return -1;
+ }
+
+#if HAVE_USLEEP
+ usleep(usecs);
+ return 0;
+#else /* HAVE_USLEEP */
+ /*
+ * Fake it with select...
+ */
+ tval.tv_sec = 0;
+ tval.tv_usec = usecs/1000;
+ select(0,NULL,NULL,NULL,&tval);
+ return 0;
+#endif /* HAVE_USLEEP */
+}
+
+/*******************************************************************
+A read wrapper that will deal with EINTR.
+********************************************************************/
+
+ssize_t sys_read(int fd, void *buf, size_t count)
+{
+ ssize_t ret;
+
+ do {
+ ret = read(fd, buf, count);
+ } while (ret == -1 && errno == EINTR);
+ return ret;
+}
+
+/*******************************************************************
+A write wrapper that will deal with EINTR.
+********************************************************************/
+
+ssize_t sys_write(int fd, const void *buf, size_t count)
+{
+ ssize_t ret;
+
+ do {
+ ret = write(fd, buf, count);
+ } while (ret == -1 && errno == EINTR);
+ return ret;
+}
+
+/*******************************************************************
+A pread wrapper that will deal with EINTR and 64-bit file offsets.
+********************************************************************/
+
+#if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
+ssize_t sys_pread(int fd, void *buf, size_t count, SMB_OFF_T off)
+{
+ ssize_t ret;
+
+ do {
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PREAD64)
+ ret = pread64(fd, buf, count, off);
+#else
+ ret = pread(fd, buf, count, off);
+#endif
+ } while (ret == -1 && errno == EINTR);
+ return ret;
+}
+#endif
+
+/*******************************************************************
+A write wrapper that will deal with EINTR and 64-bit file offsets.
+********************************************************************/
+
+#if defined(HAVE_PWRITE) || defined(HAVE_PWRITE64)
+ssize_t sys_pwrite(int fd, const void *buf, size_t count, SMB_OFF_T off)
+{
+ ssize_t ret;
+
+ do {
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PWRITE64)
+ ret = pwrite64(fd, buf, count, off);
+#else
+ ret = pwrite(fd, buf, count, off);
+#endif
+ } while (ret == -1 && errno == EINTR);
+ return ret;
+}
+#endif
+
+/*******************************************************************
+A send wrapper that will deal with EINTR.
+********************************************************************/
+
+ssize_t sys_send(int s, const void *msg, size_t len, int flags)
+{
+ ssize_t ret;
+
+ do {
+ ret = send(s, msg, len, flags);
+ } while (ret == -1 && errno == EINTR);
+ return ret;
+}
+
+/*******************************************************************
+A sendto wrapper that will deal with EINTR.
+********************************************************************/
+
+ssize_t sys_sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
+{
+ ssize_t ret;
+
+ do {
+ ret = sendto(s, msg, len, flags, to, tolen);
+ } while (ret == -1 && errno == EINTR);
+ return ret;
+}
+
+/*******************************************************************
+A recv wrapper that will deal with EINTR.
+********************************************************************/
+
+ssize_t sys_recv(int fd, void *buf, size_t count, int flags)
+{
+ ssize_t ret;
+
+ do {
+ ret = recv(fd, buf, count, flags);
+ } while (ret == -1 && errno == EINTR);
+ return ret;
+}
+
+/*******************************************************************
+A recvfrom wrapper that will deal with EINTR.
+********************************************************************/
+
+ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
+{
+ ssize_t ret;
+
+ do {
+ ret = recvfrom(s, buf, len, flags, from, fromlen);
+ } while (ret == -1 && errno == EINTR);
+ return ret;
+}
+
+/*******************************************************************
+A fcntl wrapper that will deal with EINTR.
+********************************************************************/
+
+int sys_fcntl_ptr(int fd, int cmd, void *arg)
+{
+ int ret;
+
+ do {
+ ret = fcntl(fd, cmd, arg);
+ } while (ret == -1 && errno == EINTR);
+ return ret;
+}
+
+/*******************************************************************
+A fcntl wrapper that will deal with EINTR.
+********************************************************************/
+
+int sys_fcntl_long(int fd, int cmd, long arg)
+{
+ int ret;
+
+ do {
+ ret = fcntl(fd, cmd, arg);
+ } while (ret == -1 && errno == EINTR);
+ return ret;
+}
+
+/*******************************************************************
+A stat() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
+{
+ int ret;
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
+ ret = stat64(fname, sbuf);
+#else
+ ret = stat(fname, sbuf);
+#endif
+ /* we always want directories to appear zero size */
+ if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
+ return ret;
+}
+
+/*******************************************************************
+ An fstat() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
+{
+ int ret;
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
+ ret = fstat64(fd, sbuf);
+#else
+ ret = fstat(fd, sbuf);
+#endif
+ /* we always want directories to appear zero size */
+ if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
+ return ret;
+}
+
+/*******************************************************************
+ An lstat() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
+{
+ int ret;
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
+ ret = lstat64(fname, sbuf);
+#else
+ ret = lstat(fname, sbuf);
+#endif
+ /* we always want directories to appear zero size */
+ if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
+ return ret;
+}
+
+/*******************************************************************
+ An ftruncate() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_ftruncate(int fd, SMB_OFF_T offset)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
+ return ftruncate64(fd, offset);
+#else
+ return ftruncate(fd, offset);
+#endif
+}
+
+/*******************************************************************
+ 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_EXPLICIT_LARGEFILE_SUPPORT) && 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(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
+ return fseek64(fp, offset, whence);
+#elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
+ return fseeko64(fp, offset, whence);
+#else
+ return fseek(fp, offset, whence);
+#endif
+}
+
+/*******************************************************************
+ An ftell() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+SMB_OFF_T sys_ftell(FILE *fp)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
+ return (SMB_OFF_T)ftell64(fp);
+#elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
+ return (SMB_OFF_T)ftello64(fp);
+#else
+ return (SMB_OFF_T)ftell(fp);
+#endif
+}
+
+/*******************************************************************
+ A creat() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_creat(const char *path, mode_t mode)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
+ return creat64(path, mode);
+#else
+ /*
+ * If creat64 isn't defined then ensure we call a potential open64.
+ * JRA.
+ */
+ return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
+#endif
+}
+
+/*******************************************************************
+ An open() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_open(const char *path, int oflag, mode_t mode)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
+ return open64(path, oflag, mode);
+#else
+ return open(path, oflag, mode);
+#endif
+}
+
+/*******************************************************************
+ An fopen() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+FILE *sys_fopen(const char *path, const char *type)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
+ return fopen64(path, type);
+#else
+ return fopen(path, type);
+#endif
+}
+
+
+/*******************************************************************
+ A flock() wrapper that will perform the kernel flock.
+********************************************************************/
+
+void kernel_flock(int fd, uint32 share_mode)
+{
+#if HAVE_KERNEL_SHARE_MODES
+ int kernel_mode = 0;
+ if (share_mode == FILE_SHARE_WRITE) {
+ kernel_mode = LOCK_MAND|LOCK_WRITE;
+ } else if (share_mode == FILE_SHARE_READ) {
+ kernel_mode = LOCK_MAND|LOCK_READ;
+ } else if (share_mode == FILE_SHARE_NONE) {
+ kernel_mode = LOCK_MAND;
+ }
+ if (kernel_mode) {
+ flock(fd, kernel_mode);
+ }
+#endif
+ ;
+}
+
+
+
+/*******************************************************************
+ An opendir wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+SMB_STRUCT_DIR *sys_opendir(const char *name)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPENDIR64)
+ return opendir64(name);
+#else
+ return opendir(name);
+#endif
+}
+
+/*******************************************************************
+ A readdir wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+SMB_STRUCT_DIRENT *sys_readdir(SMB_STRUCT_DIR *dirp)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
+ return readdir64(dirp);
+#else
+ return readdir(dirp);
+#endif
+}
+
+/*******************************************************************
+ A seekdir wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+void sys_seekdir(SMB_STRUCT_DIR *dirp, long offset)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_SEEKDIR64)
+ seekdir64(dirp, offset);
+#else
+ seekdir(dirp, offset);
+#endif
+}
+
+/*******************************************************************
+ A telldir wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+long sys_telldir(SMB_STRUCT_DIR *dirp)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_TELLDIR64)
+ return (long)telldir64(dirp);
+#else
+ return (long)telldir(dirp);
+#endif
+}
+
+/*******************************************************************
+ A rewinddir wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+void sys_rewinddir(SMB_STRUCT_DIR *dirp)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_REWINDDIR64)
+ rewinddir64(dirp);
+#else
+ rewinddir(dirp);
+#endif
+}
+
+/*******************************************************************
+ A close wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_closedir(SMB_STRUCT_DIR *dirp)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CLOSEDIR64)
+ return closedir64(dirp);
+#else
+ return closedir(dirp);
+#endif
+}
+
+/*******************************************************************
+ An mknod() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
+{
+#if defined(HAVE_MKNOD) || defined(HAVE_MKNOD64)
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_MKNOD64) && defined(HAVE_DEV64_T)
+ return mknod64(path, mode, dev);
+#else
+ return mknod(path, mode, dev);
+#endif
+#else
+ /* No mknod system call. */
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+/*******************************************************************
+ Wrapper for realpath.
+********************************************************************/
+
+char *sys_realpath(const char *path, char *resolved_path)
+{
+#if defined(HAVE_REALPATH)
+ return realpath(path, resolved_path);
+#else
+ /* As realpath is not a system call we can't return ENOSYS. */
+ errno = EINVAL;
+ return NULL;
+#endif
+}
+
+/*******************************************************************
+The wait() calls vary between systems
+********************************************************************/
+
+int sys_waitpid(pid_t pid,int *status,int options)
+{
+#ifdef HAVE_WAITPID
+ return waitpid(pid,status,options);
+#else /* HAVE_WAITPID */
+ return wait4(pid, status, options, NULL);
+#endif /* HAVE_WAITPID */
+}
+
+/*******************************************************************
+ System wrapper for getwd
+********************************************************************/
+
+char *sys_getwd(char *s)
+{
+ char *wd;
+#ifdef HAVE_GETCWD
+ wd = (char *)getcwd(s, PATH_MAX);
+#else
+ wd = (char *)getwd(s);
+#endif
+ return wd;
+}
+
+/*******************************************************************
+system wrapper for symlink
+********************************************************************/
+
+int sys_symlink(const char *oldpath, const char *newpath)
+{
+#ifndef HAVE_SYMLINK
+ errno = ENOSYS;
+ return -1;
+#else
+ return symlink(oldpath, newpath);
+#endif
+}
+
+/*******************************************************************
+system wrapper for readlink
+********************************************************************/
+
+int sys_readlink(const char *path, char *buf, size_t bufsiz)
+{
+#ifndef HAVE_READLINK
+ errno = ENOSYS;
+ return -1;
+#else
+ return readlink(path, buf, bufsiz);
+#endif
+}
+
+/*******************************************************************
+system wrapper for link
+********************************************************************/
+
+int sys_link(const char *oldpath, const char *newpath)
+{
+#ifndef HAVE_LINK
+ errno = ENOSYS;
+ return -1;
+#else
+ return link(oldpath, newpath);
+#endif
+}
+
+/*******************************************************************
+chown isn't used much but OS/2 doesn't have it
+********************************************************************/
+
+int sys_chown(const char *fname,uid_t uid,gid_t gid)
+{
+#ifndef HAVE_CHOWN
+ static int done;
+ if (!done) {
+ DEBUG(1,("WARNING: no chown!\n"));
+ done=1;
+ }
+ errno = ENOSYS;
+ return -1;
+#else
+ return(chown(fname,uid,gid));
+#endif
+}
+
+/*******************************************************************
+ Wrapper for lchown.
+********************************************************************/
+
+int sys_lchown(const char *fname,uid_t uid,gid_t gid)
+{
+#ifndef HAVE_LCHOWN
+ static int done;
+ if (!done) {
+ DEBUG(1,("WARNING: no lchown!\n"));
+ done=1;
+ }
+ errno = ENOSYS;
+ return -1;
+#else
+ return(lchown(fname,uid,gid));
+#endif
+}
+
+/*******************************************************************
+os/2 also doesn't have chroot
+********************************************************************/
+int sys_chroot(const char *dname)
+{
+#ifndef HAVE_CHROOT
+ static int done;
+ if (!done) {
+ DEBUG(1,("WARNING: no chroot!\n"));
+ done=1;
+ }
+ errno = ENOSYS;
+ return -1;
+#else
+ return(chroot(dname));
+#endif
+}
+
+#if defined(HAVE_POSIX_CAPABILITIES)
+
+/**************************************************************************
+ Try and abstract process capabilities (for systems that have them).
+****************************************************************************/
+
+/* Set the POSIX capabilities needed for the given purpose into the effective
+ * capability set of the current process. Make sure they are always removed
+ * from the inheritable set, because there is no circumstance in which our
+ * children should inherit our elevated privileges.
+ */
+static bool set_process_capability(enum smbd_capability capability,
+ bool enable)
+{
+ cap_value_t cap_vals[2] = {0};
+ int num_cap_vals = 0;
+
+ cap_t cap;
+
+#if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
+ /* On Linux, make sure that any capabilities we grab are sticky
+ * across UID changes. We expect that this would allow us to keep both
+ * the effective and permitted capability sets, but as of circa 2.6.16,
+ * only the permitted set is kept. It is a bug (which we work around)
+ * that the effective set is lost, but we still require the effective
+ * set to be kept.
+ */
+ if (!prctl(PR_GET_KEEPCAPS)) {
+ prctl(PR_SET_KEEPCAPS, 1);
+ }
+#endif
+
+ cap = cap_get_proc();
+ if (cap == NULL) {
+ DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
+ strerror(errno)));
+ return False;
+ }
+
+ switch (capability) {
+ case KERNEL_OPLOCK_CAPABILITY:
+#ifdef CAP_NETWORK_MGT
+ /* IRIX has CAP_NETWORK_MGT for oplocks. */
+ cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
+#endif
+ break;
+ case DMAPI_ACCESS_CAPABILITY:
+#ifdef CAP_DEVICE_MGT
+ /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
+ cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
+#elif CAP_MKNOD
+ /* Linux has CAP_MKNOD for DMAPI access. */
+ cap_vals[num_cap_vals++] = CAP_MKNOD;
+#endif
+ break;
+ case LEASE_CAPABILITY:
+#ifdef CAP_LEASE
+ cap_vals[num_cap_vals++] = CAP_LEASE;
+#endif
+ break;
+ }
+
+ SMB_ASSERT(num_cap_vals <= ARRAY_SIZE(cap_vals));
+
+ if (num_cap_vals == 0) {
+ cap_free(cap);
+ return True;
+ }
+
+ cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
+ enable ? CAP_SET : CAP_CLEAR);
+
+ /* We never want to pass capabilities down to our children, so make
+ * sure they are not inherited.
+ */
+ cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
+
+ if (cap_set_proc(cap) == -1) {
+ DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
+ strerror(errno)));
+ cap_free(cap);
+ return False;
+ }
+
+ cap_free(cap);
+ return True;
+}
+
+#endif /* HAVE_POSIX_CAPABILITIES */
+
+/****************************************************************************
+ Gain the oplock capability from the kernel if possible.
+****************************************************************************/
+
+void set_effective_capability(enum smbd_capability capability)
+{
+#if defined(HAVE_POSIX_CAPABILITIES)
+ set_process_capability(capability, True);
+#endif /* HAVE_POSIX_CAPABILITIES */
+}
+
+void drop_effective_capability(enum smbd_capability capability)
+{
+#if defined(HAVE_POSIX_CAPABILITIES)
+ set_process_capability(capability, False);
+#endif /* HAVE_POSIX_CAPABILITIES */
+}
+
+/**************************************************************************
+ Wrapper for random().
+****************************************************************************/
+
+long sys_random(void)
+{
+#if defined(HAVE_RANDOM)
+ return (long)random();
+#elif defined(HAVE_RAND)
+ return (long)rand();
+#else
+ DEBUG(0,("Error - no random function available !\n"));
+ exit(1);
+#endif
+}
+
+/**************************************************************************
+ Wrapper for srandom().
+****************************************************************************/
+
+void sys_srandom(unsigned int seed)
+{
+#if defined(HAVE_SRANDOM)
+ srandom(seed);
+#elif defined(HAVE_SRAND)
+ srand(seed);
+#else
+ DEBUG(0,("Error - no srandom function available !\n"));
+ exit(1);
+#endif
+}
+
+/**************************************************************************
+ Returns equivalent to NGROUPS_MAX - using sysconf if needed.
+****************************************************************************/
+
+int groups_max(void)
+{
+#if defined(SYSCONF_SC_NGROUPS_MAX)
+ int ret = sysconf(_SC_NGROUPS_MAX);
+ return (ret == -1) ? NGROUPS_MAX : ret;
+#else
+ return NGROUPS_MAX;
+#endif
+}
+
+/**************************************************************************
+ Wrap setgroups and getgroups for systems that declare getgroups() as
+ returning an array of gid_t, but actuall return an array of int.
+****************************************************************************/
+
+#if defined(HAVE_BROKEN_GETGROUPS)
+static int sys_broken_getgroups(int setlen, gid_t *gidset)
+{
+ GID_T gid;
+ GID_T *group_list;
+ int i, ngroups;
+
+ if(setlen == 0) {
+ return getgroups(setlen, &gid);
+ }
+
+ /*
+ * Broken case. We need to allocate a
+ * GID_T array of size setlen.
+ */
+
+ if(setlen < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (setlen == 0)
+ setlen = groups_max();
+
+ if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
+ DEBUG(0,("sys_getgroups: Malloc fail.\n"));
+ return -1;
+ }
+
+ if((ngroups = getgroups(setlen, group_list)) < 0) {
+ int saved_errno = errno;
+ SAFE_FREE(group_list);
+ errno = saved_errno;
+ return -1;
+ }
+
+ for(i = 0; i < ngroups; i++)
+ gidset[i] = (gid_t)group_list[i];
+
+ SAFE_FREE(group_list);
+ return ngroups;
+}
+
+static int sys_broken_setgroups(int setlen, gid_t *gidset)
+{
+ GID_T *group_list;
+ int i ;
+
+ if (setlen == 0)
+ return 0 ;
+
+ if (setlen < 0 || setlen > groups_max()) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Broken case. We need to allocate a
+ * GID_T array of size setlen.
+ */
+
+ if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
+ DEBUG(0,("sys_setgroups: Malloc fail.\n"));
+ return -1;
+ }
+
+ for(i = 0; i < setlen; i++)
+ group_list[i] = (GID_T) gidset[i];
+
+ if(setgroups(setlen, group_list) != 0) {
+ int saved_errno = errno;
+ SAFE_FREE(group_list);
+ errno = saved_errno;
+ return -1;
+ }
+
+ SAFE_FREE(group_list);
+ return 0 ;
+}
+
+#endif /* HAVE_BROKEN_GETGROUPS */
+
+/* This is a list of systems that require the first GID passed to setgroups(2)
+ * to be the effective GID. If your system is one of these, add it here.
+ */
+#if defined (FREEBSD) || defined (DARWINOS)
+#define USE_BSD_SETGROUPS
+#endif
+
+#if defined(USE_BSD_SETGROUPS)
+/* Depending on the particular BSD implementation, the first GID that is
+ * passed to setgroups(2) will either be ignored or will set the credential's
+ * effective GID. In either case, the right thing to do is to guarantee that
+ * gidset[0] is the effective GID.
+ */
+static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
+{
+ gid_t *new_gidset = NULL;
+ int max;
+ int ret;
+
+ /* setgroups(2) will fail with EINVAL if we pass too many groups. */
+ max = groups_max();
+
+ /* No group list, just make sure we are setting the efective GID. */
+ if (setlen == 0) {
+ return setgroups(1, &primary_gid);
+ }
+
+ /* If the primary gid is not the first array element, grow the array
+ * and insert it at the front.
+ */
+ if (gidset[0] != primary_gid) {
+ new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
+ if (new_gidset == NULL) {
+ return -1;
+ }
+
+ memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
+ new_gidset[0] = primary_gid;
+ setlen++;
+ }
+
+ if (setlen > max) {
+ DEBUG(3, ("forced to truncate group list from %d to %d\n",
+ setlen, max));
+ setlen = max;
+ }
+
+#if defined(HAVE_BROKEN_GETGROUPS)
+ ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
+#else
+ ret = setgroups(setlen, new_gidset ? new_gidset : gidset);
+#endif
+
+ if (new_gidset) {
+ int errsav = errno;
+ SAFE_FREE(new_gidset);
+ errno = errsav;
+ }
+
+ return ret;
+}
+
+#endif /* USE_BSD_SETGROUPS */
+
+/**************************************************************************
+ Wrapper for getgroups. Deals with broken (int) case.
+****************************************************************************/
+
+int sys_getgroups(int setlen, gid_t *gidset)
+{
+#if defined(HAVE_BROKEN_GETGROUPS)
+ return sys_broken_getgroups(setlen, gidset);
+#else
+ return getgroups(setlen, gidset);
+#endif
+}
+
+/**************************************************************************
+ Wrapper for setgroups. Deals with broken (int) case and BSD case.
+****************************************************************************/
+
+int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
+{
+#if !defined(HAVE_SETGROUPS)
+ errno = ENOSYS;
+ return -1;
+#endif /* HAVE_SETGROUPS */
+
+#if defined(USE_BSD_SETGROUPS)
+ return sys_bsd_setgroups(primary_gid, setlen, gidset);
+#elif defined(HAVE_BROKEN_GETGROUPS)
+ return sys_broken_setgroups(setlen, gidset);
+#else
+ return setgroups(setlen, gidset);
+#endif
+}
+
+/**************************************************************************
+ Wrappers for setpwent(), getpwent() and endpwent()
+****************************************************************************/
+
+void sys_setpwent(void)
+{
+ setpwent();
+}
+
+struct passwd *sys_getpwent(void)
+{
+ return getpwent();
+}
+
+void sys_endpwent(void)
+{
+ endpwent();
+}
+
+/**************************************************************************
+ Wrappers for getpwnam(), getpwuid(), getgrnam(), getgrgid()
+****************************************************************************/
+
+
+struct passwd *sys_getpwnam(const char *name)
+{
+ return getpwnam(name);
+}
+
+struct passwd *sys_getpwuid(uid_t uid)
+{
+ return getpwuid(uid);
+}
+
+struct group *sys_getgrnam(const char *name)
+{
+ return getgrnam(name);
+}
+
+struct group *sys_getgrgid(gid_t gid)
+{
+ return getgrgid(gid);
+}
+
+/**************************************************************************
+ Extract a command into an arg list.
+****************************************************************************/
+
+static char **extract_args(TALLOC_CTX *mem_ctx, const char *command)
+{
+ char *trunc_cmd;
+ char *saveptr;
+ char *ptr;
+ int argcl;
+ char **argl = NULL;
+ int i;
+
+ if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
+ DEBUG(0, ("talloc failed\n"));
+ goto nomem;
+ }
+
+ if(!(ptr = strtok_r(trunc_cmd, " \t", &saveptr))) {
+ TALLOC_FREE(trunc_cmd);
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /*
+ * Count the args.
+ */
+
+ for( argcl = 1; ptr; ptr = strtok_r(NULL, " \t", &saveptr))
+ argcl++;
+
+ TALLOC_FREE(trunc_cmd);
+
+ if (!(argl = TALLOC_ARRAY(mem_ctx, char *, argcl + 1))) {
+ goto nomem;
+ }
+
+ /*
+ * Now do the extraction.
+ */
+
+ if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
+ goto nomem;
+ }
+
+ ptr = strtok_r(trunc_cmd, " \t", &saveptr);
+ i = 0;
+
+ if (!(argl[i++] = talloc_strdup(argl, ptr))) {
+ goto nomem;
+ }
+
+ while((ptr = strtok_r(NULL, " \t", &saveptr)) != NULL) {
+
+ if (!(argl[i++] = talloc_strdup(argl, ptr))) {
+ goto nomem;
+ }
+ }
+
+ argl[i++] = NULL;
+ return argl;
+
+ nomem:
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(trunc_cmd);
+ TALLOC_FREE(argl);
+ errno = ENOMEM;
+ return NULL;
+}
+
+/**************************************************************************
+ Wrapper for fork. Ensures that mypid is reset. Used so we can write
+ a sys_getpid() that only does a system call *once*.
+****************************************************************************/
+
+static pid_t mypid = (pid_t)-1;
+
+pid_t sys_fork(void)
+{
+ pid_t forkret = fork();
+
+ if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
+ mypid = (pid_t) -1;
+
+ return forkret;
+}
+
+/**************************************************************************
+ Wrapper for getpid. Ensures we only do a system call *once*.
+****************************************************************************/
+
+pid_t sys_getpid(void)
+{
+ if (mypid == (pid_t)-1)
+ mypid = getpid();
+
+ return mypid;
+}
+
+/**************************************************************************
+ Wrapper for popen. Safer as it doesn't search a path.
+ Modified from the glibc sources.
+ modified by tridge to return a file descriptor. We must kick our FILE* habit
+****************************************************************************/
+
+typedef struct _popen_list
+{
+ int fd;
+ pid_t child_pid;
+ struct _popen_list *next;
+} popen_list;
+
+static popen_list *popen_chain;
+
+int sys_popen(const char *command)
+{
+ int parent_end, child_end;
+ int pipe_fds[2];
+ popen_list *entry = NULL;
+ char **argl = NULL;
+
+ if (pipe(pipe_fds) < 0)
+ return -1;
+
+ parent_end = pipe_fds[0];
+ child_end = pipe_fds[1];
+
+ if (!*command) {
+ errno = EINVAL;
+ goto err_exit;
+ }
+
+ if((entry = SMB_MALLOC_P(popen_list)) == NULL)
+ goto err_exit;
+
+ ZERO_STRUCTP(entry);
+
+ /*
+ * Extract the command and args into a NULL terminated array.
+ */
+
+ if(!(argl = extract_args(NULL, command)))
+ goto err_exit;
+
+ entry->child_pid = sys_fork();
+
+ if (entry->child_pid == -1) {
+ goto err_exit;
+ }
+
+ if (entry->child_pid == 0) {
+
+ /*
+ * Child !
+ */
+
+ int child_std_end = STDOUT_FILENO;
+ popen_list *p;
+
+ close(parent_end);
+ if (child_end != child_std_end) {
+ dup2 (child_end, child_std_end);
+ close (child_end);
+ }
+
+ /*
+ * POSIX.2: "popen() shall ensure that any streams from previous
+ * popen() calls that remain open in the parent process are closed
+ * in the new child process."
+ */
+
+ for (p = popen_chain; p; p = p->next)
+ close(p->fd);
+
+ execv(argl[0], argl);
+ _exit (127);
+ }
+
+ /*
+ * Parent.
+ */
+
+ close (child_end);
+ TALLOC_FREE(argl);
+
+ /* Link into popen_chain. */
+ entry->next = popen_chain;
+ popen_chain = entry;
+ entry->fd = parent_end;
+
+ return entry->fd;
+
+err_exit:
+
+ SAFE_FREE(entry);
+ SAFE_FREE(argl);
+ close(pipe_fds[0]);
+ close(pipe_fds[1]);
+ return -1;
+}
+
+/**************************************************************************
+ Wrapper for pclose. Modified from the glibc sources.
+****************************************************************************/
+
+int sys_pclose(int fd)
+{
+ int wstatus;
+ popen_list **ptr = &popen_chain;
+ popen_list *entry = NULL;
+ pid_t wait_pid;
+ int status = -1;
+
+ /* Unlink from popen_chain. */
+ for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
+ if ((*ptr)->fd == fd) {
+ entry = *ptr;
+ *ptr = (*ptr)->next;
+ status = 0;
+ break;
+ }
+ }
+
+ if (status < 0 || close(entry->fd) < 0)
+ return -1;
+
+ /*
+ * As Samba is catching and eating child process
+ * exits we don't really care about the child exit
+ * code, a -1 with errno = ECHILD will do fine for us.
+ */
+
+ do {
+ wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
+ } while (wait_pid == -1 && errno == EINTR);
+
+ SAFE_FREE(entry);
+
+ if (wait_pid == -1)
+ return -1;
+ return wstatus;
+}
+
+/**************************************************************************
+ Wrappers for dlopen, dlsym, dlclose.
+****************************************************************************/
+
+void *sys_dlopen(const char *name, int flags)
+{
+#if defined(HAVE_DLOPEN)
+ return dlopen(name, flags);
+#else
+ return NULL;
+#endif
+}
+
+void *sys_dlsym(void *handle, const char *symbol)
+{
+#if defined(HAVE_DLSYM)
+ return dlsym(handle, symbol);
+#else
+ return NULL;
+#endif
+}
+
+int sys_dlclose (void *handle)
+{
+#if defined(HAVE_DLCLOSE)
+ return dlclose(handle);
+#else
+ return 0;
+#endif
+}
+
+const char *sys_dlerror(void)
+{
+#if defined(HAVE_DLERROR)
+ return dlerror();
+#else
+ return NULL;
+#endif
+}
+
+int sys_dup2(int oldfd, int newfd)
+{
+#if defined(HAVE_DUP2)
+ return dup2(oldfd, newfd);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+/**************************************************************************
+ Wrapper for Admin Logs.
+****************************************************************************/
+
+ void sys_adminlog(int priority, const char *format_str, ...)
+{
+ va_list ap;
+ int ret;
+ char *msgbuf = NULL;
+
+ va_start( ap, format_str );
+ ret = vasprintf( &msgbuf, format_str, ap );
+ va_end( ap );
+
+ if (ret == -1)
+ return;
+
+#if defined(HAVE_SYSLOG)
+ syslog( priority, "%s", msgbuf );
+#else
+ DEBUG(0,("%s", msgbuf ));
+#endif
+ SAFE_FREE(msgbuf);
+}
+
+/******** Solaris EA helper function prototypes ********/
+#ifdef HAVE_ATTROPEN
+#define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
+static int solaris_write_xattr(int attrfd, const char *value, size_t size);
+static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
+static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
+static int solaris_unlinkat(int attrdirfd, const char *name);
+static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
+static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
+#endif
+
+/**************************************************************************
+ Wrappers for extented attribute calls. Based on the Linux package with
+ support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
+****************************************************************************/
+
+ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
+{
+#if defined(HAVE_GETXATTR)
+#ifndef XATTR_ADD_OPT
+ return getxattr(path, name, value, size);
+#else
+ int options = 0;
+ return getxattr(path, name, value, size, 0, options);
+#endif
+#elif defined(HAVE_GETEA)
+ return getea(path, name, value, size);
+#elif defined(HAVE_EXTATTR_GET_FILE)
+ char *s;
+ ssize_t retval;
+ int attrnamespace = (strncmp(name, "system", 6) == 0) ?
+ EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
+ const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
+ /*
+ * The BSD implementation has a nasty habit of silently truncating
+ * the returned value to the size of the buffer, so we have to check
+ * that the buffer is large enough to fit the returned value.
+ */
+ if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
+ if(retval > size) {
+ errno = ERANGE;
+ return -1;
+ }
+ if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
+ return retval;
+ }
+
+ DEBUG(10,("sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno)));
+ return -1;
+#elif defined(HAVE_ATTR_GET)
+ int retval, flags = 0;
+ int valuelength = (int)size;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+ retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
+
+ return retval ? retval : valuelength;
+#elif defined(HAVE_ATTROPEN)
+ ssize_t ret = -1;
+ int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
+ if (attrfd >= 0) {
+ ret = solaris_read_xattr(attrfd, value, size);
+ close(attrfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size)
+{
+#if defined(HAVE_LGETXATTR)
+ return lgetxattr(path, name, value, size);
+#elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
+ int options = XATTR_NOFOLLOW;
+ return getxattr(path, name, value, size, 0, options);
+#elif defined(HAVE_LGETEA)
+ return lgetea(path, name, value, size);
+#elif defined(HAVE_EXTATTR_GET_LINK)
+ char *s;
+ ssize_t retval;
+ int attrnamespace = (strncmp(name, "system", 6) == 0) ?
+ EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
+ const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
+
+ if((retval=extattr_get_link(path, attrnamespace, attrname, NULL, 0)) >= 0) {
+ if(retval > size) {
+ errno = ERANGE;
+ return -1;
+ }
+ if((retval=extattr_get_link(path, attrnamespace, attrname, value, size)) >= 0)
+ return retval;
+ }
+
+ DEBUG(10,("sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno)));
+ return -1;
+#elif defined(HAVE_ATTR_GET)
+ int retval, flags = ATTR_DONTFOLLOW;
+ int valuelength = (int)size;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+ retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
+
+ return retval ? retval : valuelength;
+#elif defined(HAVE_ATTROPEN)
+ ssize_t ret = -1;
+ int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
+ if (attrfd >= 0) {
+ ret = solaris_read_xattr(attrfd, value, size);
+ close(attrfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
+{
+#if defined(HAVE_FGETXATTR)
+#ifndef XATTR_ADD_OPT
+ return fgetxattr(filedes, name, value, size);
+#else
+ int options = 0;
+ return fgetxattr(filedes, name, value, size, 0, options);
+#endif
+#elif defined(HAVE_FGETEA)
+ return fgetea(filedes, name, value, size);
+#elif defined(HAVE_EXTATTR_GET_FD)
+ char *s;
+ ssize_t retval;
+ int attrnamespace = (strncmp(name, "system", 6) == 0) ?
+ EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
+ const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
+
+ if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
+ if(retval > size) {
+ errno = ERANGE;
+ return -1;
+ }
+ if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
+ return retval;
+ }
+
+ DEBUG(10,("sys_fgetxattr: extattr_get_fd() failed with: %s\n", strerror(errno)));
+ return -1;
+#elif defined(HAVE_ATTR_GETF)
+ int retval, flags = 0;
+ int valuelength = (int)size;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+ retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
+
+ return retval ? retval : valuelength;
+#elif defined(HAVE_ATTROPEN)
+ ssize_t ret = -1;
+ int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
+ if (attrfd >= 0) {
+ ret = solaris_read_xattr(attrfd, value, size);
+ close(attrfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+#if defined(HAVE_EXTATTR_LIST_FILE)
+
+#define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
+
+static struct {
+ int space;
+ const char *name;
+ size_t len;
+}
+extattr[] = {
+ { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
+ { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
+};
+
+typedef union {
+ const char *path;
+ int filedes;
+} extattr_arg;
+
+static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
+{
+ ssize_t list_size, total_size = 0;
+ int i, t, len;
+ char *buf;
+ /* Iterate through extattr(2) namespaces */
+ for(t = 0; t < (sizeof(extattr)/sizeof(extattr[0])); t++) {
+ switch(type) {
+#if defined(HAVE_EXTATTR_LIST_FILE)
+ case 0:
+ list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
+ break;
+#endif
+#if defined(HAVE_EXTATTR_LIST_LINK)
+ case 1:
+ list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
+ break;
+#endif
+#if defined(HAVE_EXTATTR_LIST_FD)
+ case 2:
+ list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
+ break;
+#endif
+ default:
+ errno = ENOSYS;
+ return -1;
+ }
+ /* Some error happend. Errno should be set by the previous call */
+ if(list_size < 0)
+ return -1;
+ /* No attributes */
+ if(list_size == 0)
+ continue;
+ /* XXX: Call with an empty buffer may be used to calculate
+ necessary buffer size. Unfortunately, we can't say, how
+ many attributes were returned, so here is the potential
+ problem with the emulation.
+ */
+ if(list == NULL) {
+ /* Take the worse case of one char attribute names -
+ two bytes per name plus one more for sanity.
+ */
+ total_size += list_size + (list_size/2 + 1)*extattr[t].len;
+ continue;
+ }
+ /* Count necessary offset to fit namespace prefixes */
+ len = 0;
+ for(i = 0; i < list_size; i += list[i] + 1)
+ len += extattr[t].len;
+
+ total_size += list_size + len;
+ /* Buffer is too small to fit the results */
+ if(total_size > size) {
+ errno = ERANGE;
+ return -1;
+ }
+ /* Shift results back, so we can prepend prefixes */
+ buf = memmove(list + len, list, list_size);
+
+ for(i = 0; i < list_size; i += len + 1) {
+ len = buf[i];
+ strncpy(list, extattr[t].name, extattr[t].len + 1);
+ list += extattr[t].len;
+ strncpy(list, buf + i + 1, len);
+ list[len] = '\0';
+ list += len + 1;
+ }
+ size -= total_size;
+ }
+ return total_size;
+}
+
+#endif
+
+#if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
+static char attr_buffer[ATTR_MAX_VALUELEN];
+
+static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
+{
+ int retval = 0, index;
+ attrlist_cursor_t *cursor = 0;
+ int total_size = 0;
+ attrlist_t * al = (attrlist_t *)attr_buffer;
+ attrlist_ent_t *ae;
+ size_t ent_size, left = size;
+ char *bp = list;
+
+ while (True) {
+ if (filedes)
+ retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
+ else
+ retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
+ if (retval) break;
+ for (index = 0; index < al->al_count; index++) {
+ ae = ATTR_ENTRY(attr_buffer, index);
+ ent_size = strlen(ae->a_name) + sizeof("user.");
+ if (left >= ent_size) {
+ strncpy(bp, "user.", sizeof("user."));
+ strncat(bp, ae->a_name, ent_size - sizeof("user."));
+ bp += ent_size;
+ left -= ent_size;
+ } else if (size) {
+ errno = ERANGE;
+ retval = -1;
+ break;
+ }
+ total_size += ent_size;
+ }
+ if (al->al_more == 0) break;
+ }
+ if (retval == 0) {
+ flags |= ATTR_ROOT;
+ cursor = 0;
+ while (True) {
+ if (filedes)
+ retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
+ else
+ retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
+ if (retval) break;
+ for (index = 0; index < al->al_count; index++) {
+ ae = ATTR_ENTRY(attr_buffer, index);
+ ent_size = strlen(ae->a_name) + sizeof("system.");
+ if (left >= ent_size) {
+ strncpy(bp, "system.", sizeof("system."));
+ strncat(bp, ae->a_name, ent_size - sizeof("system."));
+ bp += ent_size;
+ left -= ent_size;
+ } else if (size) {
+ errno = ERANGE;
+ retval = -1;
+ break;
+ }
+ total_size += ent_size;
+ }
+ if (al->al_more == 0) break;
+ }
+ }
+ return (ssize_t)(retval ? retval : total_size);
+}
+
+#endif
+
+ssize_t sys_listxattr (const char *path, char *list, size_t size)
+{
+#if defined(HAVE_LISTXATTR)
+#ifndef XATTR_ADD_OPT
+ return listxattr(path, list, size);
+#else
+ int options = 0;
+ return listxattr(path, list, size, options);
+#endif
+#elif defined(HAVE_LISTEA)
+ return listea(path, list, size);
+#elif defined(HAVE_EXTATTR_LIST_FILE)
+ extattr_arg arg;
+ arg.path = path;
+ return bsd_attr_list(0, arg, list, size);
+#elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
+ return irix_attr_list(path, 0, list, size, 0);
+#elif defined(HAVE_ATTROPEN)
+ ssize_t ret = -1;
+ int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
+ if (attrdirfd >= 0) {
+ ret = solaris_list_xattr(attrdirfd, list, size);
+ close(attrdirfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+ssize_t sys_llistxattr (const char *path, char *list, size_t size)
+{
+#if defined(HAVE_LLISTXATTR)
+ return llistxattr(path, list, size);
+#elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
+ int options = XATTR_NOFOLLOW;
+ return listxattr(path, list, size, options);
+#elif defined(HAVE_LLISTEA)
+ return llistea(path, list, size);
+#elif defined(HAVE_EXTATTR_LIST_LINK)
+ extattr_arg arg;
+ arg.path = path;
+ return bsd_attr_list(1, arg, list, size);
+#elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
+ return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
+#elif defined(HAVE_ATTROPEN)
+ ssize_t ret = -1;
+ int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
+ if (attrdirfd >= 0) {
+ ret = solaris_list_xattr(attrdirfd, list, size);
+ close(attrdirfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+ssize_t sys_flistxattr (int filedes, char *list, size_t size)
+{
+#if defined(HAVE_FLISTXATTR)
+#ifndef XATTR_ADD_OPT
+ return flistxattr(filedes, list, size);
+#else
+ int options = 0;
+ return flistxattr(filedes, list, size, options);
+#endif
+#elif defined(HAVE_FLISTEA)
+ return flistea(filedes, list, size);
+#elif defined(HAVE_EXTATTR_LIST_FD)
+ extattr_arg arg;
+ arg.filedes = filedes;
+ return bsd_attr_list(2, arg, list, size);
+#elif defined(HAVE_ATTR_LISTF)
+ return irix_attr_list(NULL, filedes, list, size, 0);
+#elif defined(HAVE_ATTROPEN)
+ ssize_t ret = -1;
+ int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
+ if (attrdirfd >= 0) {
+ ret = solaris_list_xattr(attrdirfd, list, size);
+ close(attrdirfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int sys_removexattr (const char *path, const char *name)
+{
+#if defined(HAVE_REMOVEXATTR)
+#ifndef XATTR_ADD_OPT
+ return removexattr(path, name);
+#else
+ int options = 0;
+ return removexattr(path, name, options);
+#endif
+#elif defined(HAVE_REMOVEEA)
+ return removeea(path, name);
+#elif defined(HAVE_EXTATTR_DELETE_FILE)
+ char *s;
+ int attrnamespace = (strncmp(name, "system", 6) == 0) ?
+ EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
+ const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
+
+ return extattr_delete_file(path, attrnamespace, attrname);
+#elif defined(HAVE_ATTR_REMOVE)
+ int flags = 0;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+ return attr_remove(path, attrname, flags);
+#elif defined(HAVE_ATTROPEN)
+ int ret = -1;
+ int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
+ if (attrdirfd >= 0) {
+ ret = solaris_unlinkat(attrdirfd, name);
+ close(attrdirfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int sys_lremovexattr (const char *path, const char *name)
+{
+#if defined(HAVE_LREMOVEXATTR)
+ return lremovexattr(path, name);
+#elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
+ int options = XATTR_NOFOLLOW;
+ return removexattr(path, name, options);
+#elif defined(HAVE_LREMOVEEA)
+ return lremoveea(path, name);
+#elif defined(HAVE_EXTATTR_DELETE_LINK)
+ char *s;
+ int attrnamespace = (strncmp(name, "system", 6) == 0) ?
+ EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
+ const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
+
+ return extattr_delete_link(path, attrnamespace, attrname);
+#elif defined(HAVE_ATTR_REMOVE)
+ int flags = ATTR_DONTFOLLOW;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+ return attr_remove(path, attrname, flags);
+#elif defined(HAVE_ATTROPEN)
+ int ret = -1;
+ int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
+ if (attrdirfd >= 0) {
+ ret = solaris_unlinkat(attrdirfd, name);
+ close(attrdirfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int sys_fremovexattr (int filedes, const char *name)
+{
+#if defined(HAVE_FREMOVEXATTR)
+#ifndef XATTR_ADD_OPT
+ return fremovexattr(filedes, name);
+#else
+ int options = 0;
+ return fremovexattr(filedes, name, options);
+#endif
+#elif defined(HAVE_FREMOVEEA)
+ return fremoveea(filedes, name);
+#elif defined(HAVE_EXTATTR_DELETE_FD)
+ char *s;
+ int attrnamespace = (strncmp(name, "system", 6) == 0) ?
+ EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
+ const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
+
+ return extattr_delete_fd(filedes, attrnamespace, attrname);
+#elif defined(HAVE_ATTR_REMOVEF)
+ int flags = 0;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+ return attr_removef(filedes, attrname, flags);
+#elif defined(HAVE_ATTROPEN)
+ int ret = -1;
+ int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
+ if (attrdirfd >= 0) {
+ ret = solaris_unlinkat(attrdirfd, name);
+ close(attrdirfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
+{
+#if defined(HAVE_SETXATTR)
+#ifndef XATTR_ADD_OPT
+ return setxattr(path, name, value, size, flags);
+#else
+ int options = 0;
+ return setxattr(path, name, value, size, 0, options);
+#endif
+#elif defined(HAVE_SETEA)
+ return setea(path, name, value, size, flags);
+#elif defined(HAVE_EXTATTR_SET_FILE)
+ char *s;
+ int retval = 0;
+ int attrnamespace = (strncmp(name, "system", 6) == 0) ?
+ EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
+ const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
+ if (flags) {
+ /* Check attribute existence */
+ retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
+ if (retval < 0) {
+ /* REPLACE attribute, that doesn't exist */
+ if (flags & XATTR_REPLACE && errno == ENOATTR) {
+ errno = ENOATTR;
+ return -1;
+ }
+ /* Ignore other errors */
+ }
+ else {
+ /* CREATE attribute, that already exists */
+ if (flags & XATTR_CREATE) {
+ errno = EEXIST;
+ return -1;
+ }
+ }
+ }
+ retval = extattr_set_file(path, attrnamespace, attrname, value, size);
+ return (retval < 0) ? -1 : 0;
+#elif defined(HAVE_ATTR_SET)
+ int myflags = 0;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
+ if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
+ if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
+
+ return attr_set(path, attrname, (const char *)value, size, myflags);
+#elif defined(HAVE_ATTROPEN)
+ int ret = -1;
+ int myflags = O_RDWR;
+ int attrfd;
+ if (flags & XATTR_CREATE) myflags |= O_EXCL;
+ if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
+ attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
+ if (attrfd >= 0) {
+ ret = solaris_write_xattr(attrfd, value, size);
+ close(attrfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags)
+{
+#if defined(HAVE_LSETXATTR)
+ return lsetxattr(path, name, value, size, flags);
+#elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
+ int options = XATTR_NOFOLLOW;
+ return setxattr(path, name, value, size, 0, options);
+#elif defined(LSETEA)
+ return lsetea(path, name, value, size, flags);
+#elif defined(HAVE_EXTATTR_SET_LINK)
+ char *s;
+ int retval = 0;
+ int attrnamespace = (strncmp(name, "system", 6) == 0) ?
+ EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
+ const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
+ if (flags) {
+ /* Check attribute existence */
+ retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
+ if (retval < 0) {
+ /* REPLACE attribute, that doesn't exist */
+ if (flags & XATTR_REPLACE && errno == ENOATTR) {
+ errno = ENOATTR;
+ return -1;
+ }
+ /* Ignore other errors */
+ }
+ else {
+ /* CREATE attribute, that already exists */
+ if (flags & XATTR_CREATE) {
+ errno = EEXIST;
+ return -1;
+ }
+ }
+ }
+
+ retval = extattr_set_link(path, attrnamespace, attrname, value, size);
+ return (retval < 0) ? -1 : 0;
+#elif defined(HAVE_ATTR_SET)
+ int myflags = ATTR_DONTFOLLOW;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
+ if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
+ if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
+
+ return attr_set(path, attrname, (const char *)value, size, myflags);
+#elif defined(HAVE_ATTROPEN)
+ int ret = -1;
+ int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
+ int attrfd;
+ if (flags & XATTR_CREATE) myflags |= O_EXCL;
+ if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
+ attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
+ if (attrfd >= 0) {
+ ret = solaris_write_xattr(attrfd, value, size);
+ close(attrfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
+{
+#if defined(HAVE_FSETXATTR)
+#ifndef XATTR_ADD_OPT
+ return fsetxattr(filedes, name, value, size, flags);
+#else
+ int options = 0;
+ return fsetxattr(filedes, name, value, size, 0, options);
+#endif
+#elif defined(HAVE_FSETEA)
+ return fsetea(filedes, name, value, size, flags);
+#elif defined(HAVE_EXTATTR_SET_FD)
+ char *s;
+ int retval = 0;
+ int attrnamespace = (strncmp(name, "system", 6) == 0) ?
+ EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
+ const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
+ if (flags) {
+ /* Check attribute existence */
+ retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
+ if (retval < 0) {
+ /* REPLACE attribute, that doesn't exist */
+ if (flags & XATTR_REPLACE && errno == ENOATTR) {
+ errno = ENOATTR;
+ return -1;
+ }
+ /* Ignore other errors */
+ }
+ else {
+ /* CREATE attribute, that already exists */
+ if (flags & XATTR_CREATE) {
+ errno = EEXIST;
+ return -1;
+ }
+ }
+ }
+ retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
+ return (retval < 0) ? -1 : 0;
+#elif defined(HAVE_ATTR_SETF)
+ int myflags = 0;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
+ if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
+ if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
+
+ return attr_setf(filedes, attrname, (const char *)value, size, myflags);
+#elif defined(HAVE_ATTROPEN)
+ int ret = -1;
+ int myflags = O_RDWR | O_XATTR;
+ int attrfd;
+ if (flags & XATTR_CREATE) myflags |= O_EXCL;
+ if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
+ attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
+ if (attrfd >= 0) {
+ ret = solaris_write_xattr(attrfd, value, size);
+ close(attrfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+/**************************************************************************
+ helper functions for Solaris' EA support
+****************************************************************************/
+#ifdef HAVE_ATTROPEN
+static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
+{
+ struct stat sbuf;
+
+ if (fstat(attrfd, &sbuf) == -1) {
+ errno = ENOATTR;
+ return -1;
+ }
+
+ /* This is to return the current size of the named extended attribute */
+ if (size == 0) {
+ return sbuf.st_size;
+ }
+
+ /* check size and read xattr */
+ if (sbuf.st_size > size) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ return read(attrfd, value, sbuf.st_size);
+}
+
+static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
+{
+ ssize_t len = 0;
+ int stop = 0;
+ DIR *dirp;
+ struct dirent *de;
+ int newfd = dup(attrdirfd);
+ /* CAUTION: The originating file descriptor should not be
+ used again following the call to fdopendir().
+ For that reason we dup() the file descriptor
+ here to make things more clear. */
+ dirp = fdopendir(newfd);
+
+ while ((de = readdir(dirp))) {
+ size_t listlen = strlen(de->d_name);
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
+ /* we don't want "." and ".." here: */
+ DEBUG(10,("skipped EA %s\n",de->d_name));
+ continue;
+ }
+
+ if (size == 0) {
+ /* return the current size of the list of extended attribute names*/
+ len += listlen + 1;
+ } else {
+ /* check size and copy entrieѕ + nul into list. */
+ if ((len + listlen + 1) > size) {
+ errno = ERANGE;
+ len = -1;
+ break;
+ } else {
+ safe_strcpy(list + len, de->d_name, listlen);
+ len += listlen;
+ list[len] = '\0';
+ ++len;
+ }
+ }
+ }
+
+ if (closedir(dirp) == -1) {
+ DEBUG(0,("closedir dirp failed: %s\n",strerror(errno)));
+ return -1;
+ }
+ return len;
+}
+
+static int solaris_unlinkat(int attrdirfd, const char *name)
+{
+ if (unlinkat(attrdirfd, name, 0) == -1) {
+ if (errno == ENOENT) {
+ errno = ENOATTR;
+ }
+ return -1;
+ }
+ return 0;
+}
+
+static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
+{
+ int filedes = attropen(path, attrpath, oflag, mode);
+ if (filedes == -1) {
+ DEBUG(10,("attropen FAILED: path: %s, name: %s, errno: %s\n",path,attrpath,strerror(errno)));
+ if (errno == EINVAL) {
+ errno = ENOTSUP;
+ } else {
+ errno = ENOATTR;
+ }
+ }
+ return filedes;
+}
+
+static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
+{
+ int filedes = openat(fildes, path, oflag, mode);
+ if (filedes == -1) {
+ DEBUG(10,("openat FAILED: fd: %s, path: %s, errno: %s\n",filedes,path,strerror(errno)));
+ if (errno == EINVAL) {
+ errno = ENOTSUP;
+ } else {
+ errno = ENOATTR;
+ }
+ }
+ return filedes;
+}
+
+static int solaris_write_xattr(int attrfd, const char *value, size_t size)
+{
+ if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
+ return 0;
+ } else {
+ DEBUG(10,("solaris_write_xattr FAILED!\n"));
+ return -1;
+ }
+}
+#endif /*HAVE_ATTROPEN*/
+
+
+/****************************************************************************
+ Return the major devicenumber for UNIX extensions.
+****************************************************************************/
+
+uint32 unix_dev_major(SMB_DEV_T dev)
+{
+#if defined(HAVE_DEVICE_MAJOR_FN)
+ return (uint32)major(dev);
+#else
+ return (uint32)(dev >> 8);
+#endif
+}
+
+/****************************************************************************
+ Return the minor devicenumber for UNIX extensions.
+****************************************************************************/
+
+uint32 unix_dev_minor(SMB_DEV_T dev)
+{
+#if defined(HAVE_DEVICE_MINOR_FN)
+ return (uint32)minor(dev);
+#else
+ return (uint32)(dev & 0xff);
+#endif
+}
+
+#if defined(WITH_AIO)
+
+/*******************************************************************
+ An aio_read wrapper that will deal with 64-bit sizes.
+********************************************************************/
+
+int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_READ64)
+ return aio_read64(aiocb);
+#elif defined(HAVE_AIO_READ)
+ return aio_read(aiocb);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+/*******************************************************************
+ An aio_write wrapper that will deal with 64-bit sizes.
+********************************************************************/
+
+int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_WRITE64)
+ return aio_write64(aiocb);
+#elif defined(HAVE_AIO_WRITE)
+ return aio_write(aiocb);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+/*******************************************************************
+ An aio_return wrapper that will deal with 64-bit sizes.
+********************************************************************/
+
+ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_RETURN64)
+ return aio_return64(aiocb);
+#elif defined(HAVE_AIO_RETURN)
+ return aio_return(aiocb);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+/*******************************************************************
+ An aio_cancel wrapper that will deal with 64-bit sizes.
+********************************************************************/
+
+int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_CANCEL64)
+ return aio_cancel64(fd, aiocb);
+#elif defined(HAVE_AIO_CANCEL)
+ return aio_cancel(fd, aiocb);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+/*******************************************************************
+ An aio_error wrapper that will deal with 64-bit sizes.
+********************************************************************/
+
+int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_ERROR64)
+ return aio_error64(aiocb);
+#elif defined(HAVE_AIO_ERROR)
+ return aio_error(aiocb);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+/*******************************************************************
+ An aio_fsync wrapper that will deal with 64-bit sizes.
+********************************************************************/
+
+int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_FSYNC64)
+ return aio_fsync64(op, aiocb);
+#elif defined(HAVE_AIO_FSYNC)
+ return aio_fsync(op, aiocb);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+/*******************************************************************
+ An aio_fsync wrapper that will deal with 64-bit sizes.
+********************************************************************/
+
+int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_SUSPEND64)
+ return aio_suspend64(cblist, n, timeout);
+#elif defined(HAVE_AIO_FSYNC)
+ return aio_suspend(cblist, n, timeout);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+#else /* !WITH_AIO */
+
+int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif /* WITH_AIO */
+
+int sys_getpeereid( int s, uid_t *uid)
+{
+#if defined(HAVE_PEERCRED)
+ struct ucred cred;
+ socklen_t cred_len = sizeof(struct ucred);
+ int ret;
+
+ ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len);
+ if (ret != 0) {
+ return -1;
+ }
+
+ if (cred_len != sizeof(struct ucred)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ *uid = cred.uid;
+ return 0;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int sys_getnameinfo(const struct sockaddr *psa,
+ socklen_t salen,
+ char *host,
+ size_t hostlen,
+ char *service,
+ size_t servlen,
+ int flags)
+{
+ /*
+ * For Solaris we must make sure salen is the
+ * correct length for the incoming sa_family.
+ */
+
+ if (salen == sizeof(struct sockaddr_storage)) {
+ salen = sizeof(struct sockaddr_in);
+#if defined(HAVE_IPV6)
+ if (psa->sa_family == AF_INET6) {
+ salen = sizeof(struct sockaddr_in6);
+ }
+#endif
+ }
+ return getnameinfo(psa, salen, host, hostlen, service, servlen, flags);
+}
+
+int sys_connect(int fd, const struct sockaddr * addr)
+{
+ socklen_t salen = -1;
+
+ if (addr->sa_family == AF_INET) {
+ salen = sizeof(struct sockaddr_in);
+ } else if (addr->sa_family == AF_UNIX) {
+ salen = sizeof(struct sockaddr_un);
+ }
+#if defined(HAVE_IPV6)
+ else if (addr->sa_family == AF_INET6) {
+ salen = sizeof(struct sockaddr_in6);
+ }
+#endif
+
+ return connect(fd, addr, salen);
+}
diff --git a/source3/lib/system_smbd.c b/source3/lib/system_smbd.c
new file mode 100644
index 0000000000..1f5dd3172f
--- /dev/null
+++ b/source3/lib/system_smbd.c
@@ -0,0 +1,198 @@
+/*
+ Unix SMB/CIFS implementation.
+ system call wrapper interface.
+ Copyright (C) Andrew Tridgell 2002
+ Copyright (C) Andrew Barteltt 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ This file may assume linkage with smbd - for things like become_root()
+ etc.
+*/
+
+#include "includes.h"
+
+#ifndef HAVE_GETGROUPLIST
+
+/*
+ This is a *much* faster way of getting the list of groups for a user
+ without changing the current supplementary group list. The old
+ method used getgrent() which could take 20 minutes on a really big
+ network with hundeds of thousands of groups and users. The new method
+ takes a couple of seconds.
+
+ NOTE!! this function only works if it is called as root!
+ */
+
+static int getgrouplist_internals(const char *user, gid_t gid, gid_t *groups,
+ int *grpcnt)
+{
+ gid_t *gids_saved;
+ int ret, ngrp_saved, num_gids;
+
+ if (non_root_mode()) {
+ *grpcnt = 0;
+ return 0;
+ }
+
+ /* work out how many groups we need to save */
+ ngrp_saved = getgroups(0, NULL);
+ if (ngrp_saved == -1) {
+ /* this shouldn't happen */
+ return -1;
+ }
+
+ gids_saved = SMB_MALLOC_ARRAY(gid_t, ngrp_saved+1);
+ if (!gids_saved) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ ngrp_saved = getgroups(ngrp_saved, gids_saved);
+ if (ngrp_saved == -1) {
+ SAFE_FREE(gids_saved);
+ /* very strange! */
+ return -1;
+ }
+
+ if (initgroups(user, gid) != 0) {
+ DEBUG(0, ("getgrouplist_internals: initgroups() failed!\n"));
+ SAFE_FREE(gids_saved);
+ return -1;
+ }
+
+ /* this must be done to cope with systems that put the current egid in the
+ return from getgroups() */
+ save_re_gid();
+ set_effective_gid(gid);
+ setgid(gid);
+
+ num_gids = getgroups(0, NULL);
+ if (num_gids == -1) {
+ SAFE_FREE(gids_saved);
+ /* very strange! */
+ return -1;
+ }
+
+ if (num_gids + 1 > *grpcnt) {
+ *grpcnt = num_gids + 1;
+ ret = -1;
+ } else {
+ ret = getgroups(*grpcnt - 1, &groups[1]);
+ if (ret < 0) {
+ SAFE_FREE(gids_saved);
+ /* very strange! */
+ return -1;
+ }
+ groups[0] = gid;
+ *grpcnt = ret + 1;
+ }
+
+ restore_re_gid();
+
+ if (sys_setgroups(gid, ngrp_saved, gids_saved) != 0) {
+ /* yikes! */
+ DEBUG(0,("ERROR: getgrouplist: failed to reset group list!\n"));
+ smb_panic("getgrouplist: failed to reset group list!");
+ }
+
+ free(gids_saved);
+ return ret;
+}
+#endif
+
+static int sys_getgrouplist(const char *user, gid_t gid, gid_t *groups, int *grpcnt)
+{
+ int retval;
+ bool winbind_env;
+
+ DEBUG(10,("sys_getgrouplist: user [%s]\n", user));
+
+ /* This is only ever called for Unix users, remote memberships are
+ * always determined by the info3 coming back from auth3 or the
+ * PAC. */
+ winbind_env = winbind_env_set();
+ (void)winbind_off();
+
+#ifdef HAVE_GETGROUPLIST
+ retval = getgrouplist(user, gid, groups, grpcnt);
+#else
+ become_root();
+ retval = getgrouplist_internals(user, gid, groups, grpcnt);
+ unbecome_root();
+#endif
+
+ /* allow winbindd lookups, but only if they were not already disabled */
+ if (!winbind_env) {
+ (void)winbind_on();
+ }
+
+ return retval;
+}
+
+bool getgroups_unix_user(TALLOC_CTX *mem_ctx, const char *user,
+ gid_t primary_gid,
+ gid_t **ret_groups, size_t *p_ngroups)
+{
+ size_t ngrp;
+ int max_grp;
+ gid_t *temp_groups;
+ gid_t *groups;
+ int i;
+
+ max_grp = MIN(32, groups_max());
+ temp_groups = SMB_MALLOC_ARRAY(gid_t, max_grp);
+ if (! temp_groups) {
+ return False;
+ }
+
+ if (sys_getgrouplist(user, primary_gid, temp_groups, &max_grp) == -1) {
+ temp_groups = SMB_REALLOC_ARRAY(temp_groups, gid_t, max_grp);
+ if (!temp_groups) {
+ return False;
+ }
+
+ if (sys_getgrouplist(user, primary_gid,
+ temp_groups, &max_grp) == -1) {
+ DEBUG(0, ("get_user_groups: failed to get the unix "
+ "group list\n"));
+ SAFE_FREE(temp_groups);
+ return False;
+ }
+ }
+
+ ngrp = 0;
+ groups = NULL;
+
+ /* Add in primary group first */
+ if (!add_gid_to_array_unique(mem_ctx, primary_gid, &groups, &ngrp)) {
+ SAFE_FREE(temp_groups);
+ return False;
+ }
+
+ for (i=0; i<max_grp; i++) {
+ if (!add_gid_to_array_unique(mem_ctx, temp_groups[i],
+ &groups, &ngrp)) {
+ SAFE_FREE(temp_groups);
+ return False;
+ }
+ }
+
+ *p_ngroups = ngrp;
+ *ret_groups = groups;
+ SAFE_FREE(temp_groups);
+ return True;
+}
diff --git a/source3/lib/talloc/Makefile.in b/source3/lib/talloc/Makefile.in
new file mode 100644
index 0000000000..07b8fd4ff0
--- /dev/null
+++ b/source3/lib/talloc/Makefile.in
@@ -0,0 +1,43 @@
+#!gmake
+#
+prefix = @prefix@
+datarootdir = @datarootdir@
+exec_prefix = @exec_prefix@
+includedir = @includedir@
+libdir = @libdir@
+mandir = @mandir@
+VPATH = @srcdir@:@libreplacedir@
+srcdir = @srcdir@
+builddir = @builddir@
+XSLTPROC = @XSLTPROC@
+INSTALLCMD = @INSTALL@
+CC = @CC@
+CFLAGS = @CFLAGS@ -DHAVE_CONFIG_H= -I. -I@srcdir@
+EXTRA_TARGETS = @DOC_TARGET@
+PICFLAG = @PICFLAG@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+SHLIBEXT = @SHLIBEXT@
+SHLD = @SHLD@
+SHLD_FLAGS = @SHLD_FLAGS@
+tallocdir = @tallocdir@
+
+LIBOBJ = $(TALLOC_OBJ) @LIBREPLACEOBJ@
+
+all:: showflags $(EXTRA_TARGETS)
+
+include $(tallocdir)/rules.mk
+include $(tallocdir)/talloc.mk
+
+$(TALLOC_SOLIB): $(LIBOBJ)
+ $(SHLD) $(SHLD_FLAGS) -o $@ $(LIBOBJ) @SONAMEFLAG@$(TALLOC_SONAME)
+
+check: test
+
+installcheck:: test install
+
+distclean:: clean
+ rm -f Makefile
+ rm -f config.log config.status config.h config.cache
+
+realdistclean:: distclean
+ rm -f configure config.h.in
diff --git a/source3/lib/talloc/NEWS b/source3/lib/talloc/NEWS
new file mode 100644
index 0000000000..e5b3aa0731
--- /dev/null
+++ b/source3/lib/talloc/NEWS
@@ -0,0 +1,13 @@
+1.0.1 26 May 2007
+
+ BUGS
+
+ * Set name of correctly when using talloc_append_string() (metze)
+
+ LICENSE
+
+ * Change license of files in lib/replace to LGPL (was GPL). (jelmer)
+
+1.0.0 30 April 2007
+
+ Initial release.
diff --git a/source3/lib/talloc/aclocal.m4 b/source3/lib/talloc/aclocal.m4
new file mode 100644
index 0000000000..5605e476ba
--- /dev/null
+++ b/source3/lib/talloc/aclocal.m4
@@ -0,0 +1 @@
+m4_include(libreplace.m4)
diff --git a/source3/lib/talloc/autogen.sh b/source3/lib/talloc/autogen.sh
new file mode 100755
index 0000000000..bf84eeee19
--- /dev/null
+++ b/source3/lib/talloc/autogen.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+rm -rf autom4te.cache
+rm -f configure config.h.in
+
+IPATHS="-I libreplace -I lib/replace -I ../libreplace -I ../replace"
+autoconf $IPATHS || exit 1
+autoheader $IPATHS || exit 1
+
+rm -rf autom4te.cache
+
+echo "Now run ./configure and then make."
+exit 0
+
diff --git a/source3/lib/talloc/config.guess b/source3/lib/talloc/config.guess
new file mode 100755
index 0000000000..354dbe175a
--- /dev/null
+++ b/source3/lib/talloc/config.guess
@@ -0,0 +1,1464 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+timestamp='2005-08-03'
+
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerppc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # 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 ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ 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 ;;
+ 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 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????: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 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ 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 ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep __LP64__ >/dev/null
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ x86:Interix*:[34]*)
+ echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
+ exit ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #ifdef __INTEL_COMPILER
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+ test x"${LIBC}" != x && {
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit
+ }
+ test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ 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 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *: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 ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ *86) UNAME_PROCESSOR=i686 ;;
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# 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 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+and
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/source3/lib/talloc/config.mk b/source3/lib/talloc/config.mk
new file mode 100644
index 0000000000..c13e1b79ab
--- /dev/null
+++ b/source3/lib/talloc/config.mk
@@ -0,0 +1,7 @@
+[LIBRARY::LIBTALLOC]
+OUTPUT_TYPE = MERGED_OBJ
+CFLAGS = -Ilib/talloc
+
+LIBTALLOC_OBJ_FILES = lib/talloc/talloc.o
+
+MANPAGES += $(tallocdir)/talloc.3
diff --git a/source3/lib/talloc/config.sub b/source3/lib/talloc/config.sub
new file mode 100755
index 0000000000..23cd6fd75c
--- /dev/null
+++ b/source3/lib/talloc/config.sub
@@ -0,0 +1,1577 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+timestamp='2005-07-08'
+
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \
+ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64vr | mips64vrel \
+ | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | ms1 \
+ | msp430 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b \
+ | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m32c)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | ms1-* \
+ | msp430-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ m32c-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ 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 | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16c)
+ basic_machine=cr16c-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/source3/lib/talloc/configure.ac b/source3/lib/talloc/configure.ac
new file mode 100644
index 0000000000..4719aa04b5
--- /dev/null
+++ b/source3/lib/talloc/configure.ac
@@ -0,0 +1,24 @@
+AC_PREREQ(2.50)
+AC_INIT(talloc, 1.2.0)
+AC_CONFIG_SRCDIR([talloc.c])
+AC_SUBST(datarootdir)
+AC_CONFIG_HEADER(config.h)
+
+AC_LIBREPLACE_ALL_CHECKS
+
+m4_include(libtalloc.m4)
+
+AC_PATH_PROG(XSLTPROC,xsltproc)
+DOC_TARGET=""
+if test -n "$XSLTPROC"; then
+ DOC_TARGET=doc
+fi
+AC_SUBST(DOC_TARGET)
+
+AC_LD_PICFLAG
+AC_LD_SHLIBEXT
+AC_LD_SONAMEFLAG
+AC_LIBREPLACE_SHLD
+AC_LIBREPLACE_SHLD_FLAGS
+
+AC_OUTPUT(Makefile talloc.pc)
diff --git a/source3/lib/talloc/install-sh b/source3/lib/talloc/install-sh
new file mode 100755
index 0000000000..58719246f0
--- /dev/null
+++ b/source3/lib/talloc/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/source3/lib/talloc/libtalloc.m4 b/source3/lib/talloc/libtalloc.m4
new file mode 100644
index 0000000000..fd2b4b22cd
--- /dev/null
+++ b/source3/lib/talloc/libtalloc.m4
@@ -0,0 +1,33 @@
+dnl find the talloc sources. This is meant to work both for
+dnl talloc standalone builds, and builds of packages using talloc
+tallocdir=""
+tallocpaths=". lib/talloc talloc ../talloc"
+for d in $tallocpaths; do
+ if test -f "$srcdir/$d/talloc.c"; then
+ tallocdir="$d"
+ AC_SUBST(tallocdir)
+ break;
+ fi
+done
+if test x"$tallocdir" = "x"; then
+ AC_MSG_ERROR([cannot find talloc source in $tallocpaths])
+fi
+TALLOC_OBJ="talloc.o"
+AC_SUBST(TALLOC_OBJ)
+
+TALLOC_CFLAGS="-I$srcdir/$tallocdir"
+AC_SUBST(TALLOC_CFLAGS)
+
+TALLOC_LIBS=""
+AC_SUBST(TALLOC_LIBS)
+
+AC_CHECK_SIZEOF(size_t,cross)
+AC_CHECK_SIZEOF(void *,cross)
+
+if test $ac_cv_sizeof_size_t -lt $ac_cv_sizeof_void_p; then
+ AC_WARN([size_t cannot represent the amount of used memory of a process])
+ AC_WARN([please report this to <samba-technical@samba.org>])
+ AC_WARN([sizeof(size_t) = $ac_cv_sizeof_size_t])
+ AC_WARN([sizeof(void *) = $ac_cv_sizeof_void_p])
+ AC_ERROR([sizeof(size_t) < sizeof(void *)])
+fi
diff --git a/source3/lib/talloc/rules.mk b/source3/lib/talloc/rules.mk
new file mode 100644
index 0000000000..6cee126529
--- /dev/null
+++ b/source3/lib/talloc/rules.mk
@@ -0,0 +1,18 @@
+.SUFFIXES: .c .o .3 .3.xml .xml .html
+
+showflags::
+ @echo 'talloc will be compiled with flags:'
+ @echo ' CFLAGS = $(CFLAGS)'
+ @echo ' LIBS = $(LIBS)'
+
+.c.o:
+ $(CC) $(PICFLAG) -o $@ -c $< $(CFLAGS)
+
+.3.xml.3:
+ -test -z "$(XSLTPROC)" || $(XSLTPROC) --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
+
+.xml.html:
+ -test -z "$(XSLTPROC)" || $(XSLTPROC) --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl $<
+
+distclean::
+ rm -f *~ */*~
diff --git a/source3/lib/talloc/talloc.3.xml b/source3/lib/talloc/talloc.3.xml
new file mode 100644
index 0000000000..67de15bfc8
--- /dev/null
+++ b/source3/lib/talloc/talloc.3.xml
@@ -0,0 +1,738 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry>
+ <refmeta>
+ <refentrytitle>talloc</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>talloc</refname>
+<refpurpose>hierarchical reference counted memory pool system with destructors</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+<synopsis>#include &lt;talloc/talloc.h&gt;</synopsis>
+ </refsynopsisdiv>
+ <refsect1><title>DESCRIPTION</title>
+ <para>
+ If you are used to talloc from Samba3 then please read this
+ carefully, as talloc has changed a lot.
+ </para>
+ <para>
+ The new talloc is a hierarchical, reference counted memory pool
+ system with destructors. Quite a mouthful really, but not too bad
+ once you get used to it.
+ </para>
+ <para>
+ Perhaps the biggest change from Samba3 is that there is no
+ distinction between a "talloc context" and a "talloc pointer". Any
+ pointer returned from talloc() is itself a valid talloc context.
+ This means you can do this:
+ </para>
+ <programlisting>
+ struct foo *X = talloc(mem_ctx, struct foo);
+ X->name = talloc_strdup(X, "foo");
+ </programlisting>
+ <para>
+ and the pointer <literal role="code">X-&gt;name</literal>
+ would be a "child" of the talloc context <literal
+ role="code">X</literal> which is itself a child of
+ <literal role="code">mem_ctx</literal>. So if you do
+ <literal role="code">talloc_free(mem_ctx)</literal> then
+ it is all destroyed, whereas if you do <literal
+ role="code">talloc_free(X)</literal> then just <literal
+ role="code">X</literal> and <literal
+ role="code">X-&gt;name</literal> are destroyed, and if
+ you do <literal
+ role="code">talloc_free(X-&gt;name)</literal> then just
+ the name element of <literal role="code">X</literal> is
+ destroyed.
+ </para>
+ <para>
+ If you think about this, then what this effectively gives you is an
+ n-ary tree, where you can free any part of the tree with
+ talloc_free().
+ </para>
+ <para>
+ If you find this confusing, then I suggest you run the <literal
+ role="code">testsuite</literal> program to watch talloc
+ in action. You may also like to add your own tests to <literal
+ role="code">testsuite.c</literal> to clarify how some
+ particular situation is handled.
+ </para>
+ </refsect1>
+ <refsect1><title>TALLOC API</title>
+ <para>
+ The following is a complete guide to the talloc API. Read it all at
+ least twice.
+ </para>
+ <refsect2><title>(type *)talloc(const void *ctx, type);</title>
+ <para>
+ The talloc() macro is the core of the talloc library. It takes a
+ memory <emphasis role="italic">ctx</emphasis> and a <emphasis
+ role="italic">type</emphasis>, and returns a pointer to a new
+ area of memory of the given <emphasis
+ role="italic">type</emphasis>.
+ </para>
+ <para>
+ The returned pointer is itself a talloc context, so you can use
+ it as the <emphasis role="italic">ctx</emphasis> argument to more
+ calls to talloc() if you wish.
+ </para>
+ <para>
+ The returned pointer is a "child" of the supplied context. This
+ means that if you talloc_free() the <emphasis
+ role="italic">ctx</emphasis> then the new child disappears as
+ well. Alternatively you can free just the child.
+ </para>
+ <para>
+ The <emphasis role="italic">ctx</emphasis> argument to talloc()
+ can be NULL, in which case a new top level context is created.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_size(const void *ctx, size_t size);</title>
+ <para>
+ The function talloc_size() should be used when you don't have a
+ convenient type to pass to talloc(). Unlike talloc(), it is not
+ type safe (as it returns a void *), so you are on your own for
+ type checking.
+ </para>
+ </refsect2>
+ <refsect2><title>(typeof(ptr)) talloc_ptrtype(const void *ctx, ptr);</title>
+ <para>
+ The talloc_ptrtype() macro should be used when you have a pointer and
+ want to allocate memory to point at with this pointer. When compiling
+ with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size()
+ and talloc_get_name() will return the current location in the source file.
+ and not the type.
+ </para>
+ </refsect2>
+ <refsect2><title>int talloc_free(void *ptr);</title>
+ <para>
+ The talloc_free() function frees a piece of talloc memory, and
+ all its children. You can call talloc_free() on any pointer
+ returned by talloc().
+ </para>
+ <para>
+ The return value of talloc_free() indicates success or failure,
+ with 0 returned for success and -1 for failure. The only
+ possible failure condition is if <emphasis
+ role="italic">ptr</emphasis> had a destructor attached to it and
+ the destructor returned -1. See <link
+ linkend="talloc_set_destructor"><quote>talloc_set_destructor()</quote></link>
+ for details on destructors.
+ </para>
+ <para>
+ If this pointer has an additional parent when talloc_free() is
+ called then the memory is not actually released, but instead the
+ most recently established parent is destroyed. See <link
+ linkend="talloc_reference"><quote>talloc_reference()</quote></link>
+ for details on establishing additional parents.
+ </para>
+ <para>
+ For more control on which parent is removed, see <link
+ linkend="talloc_unlink"><quote>talloc_unlink()</quote></link>.
+ </para>
+ <para>
+ talloc_free() operates recursively on its children.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_reference"><title>void *talloc_reference(const void *ctx, const void *ptr);</title>
+ <para>
+ The talloc_reference() function makes <emphasis
+ role="italic">ctx</emphasis> an additional parent of <emphasis
+ role="italic">ptr</emphasis>.
+ </para>
+ <para>
+ The return value of talloc_reference() is always the original
+ pointer <emphasis role="italic">ptr</emphasis>, unless talloc ran
+ out of memory in creating the reference in which case it will
+ return NULL (each additional reference consumes around 48 bytes
+ of memory on intel x86 platforms).
+ </para>
+ <para>
+ If <emphasis role="italic">ptr</emphasis> is NULL, then the
+ function is a no-op, and simply returns NULL.
+ </para>
+ <para>
+ After creating a reference you can free it in one of the
+ following ways:
+ </para>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ you can talloc_free() any parent of the original pointer.
+ That will reduce the number of parents of this pointer by 1,
+ and will cause this pointer to be freed if it runs out of
+ parents.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ you can talloc_free() the pointer itself. That will destroy
+ the most recently established parent to the pointer and leave
+ the pointer as a child of its current parent.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ For more control on which parent to remove, see <link
+ linkend="talloc_unlink"><quote>talloc_unlink()</quote></link>.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_unlink"><title>int talloc_unlink(const void *ctx, const void *ptr);</title>
+ <para>
+ The talloc_unlink() function removes a specific parent from
+ <emphasis role="italic">ptr</emphasis>. The <emphasis
+ role="italic">ctx</emphasis> passed must either be a context used
+ in talloc_reference() with this pointer, or must be a direct
+ parent of ptr.
+ </para>
+ <para>
+ Note that if the parent has already been removed using
+ talloc_free() then this function will fail and will return -1.
+ Likewise, if <emphasis role="italic">ptr</emphasis> is NULL, then
+ the function will make no modifications and return -1.
+ </para>
+ <para>
+ Usually you can just use talloc_free() instead of
+ talloc_unlink(), but sometimes it is useful to have the
+ additional control on which parent is removed.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_set_destructor"><title>void talloc_set_destructor(const void *ptr, int (*destructor)(void *));</title>
+ <para>
+ The function talloc_set_destructor() sets the <emphasis
+ role="italic">destructor</emphasis> for the pointer <emphasis
+ role="italic">ptr</emphasis>. A <emphasis
+ role="italic">destructor</emphasis> is a function that is called
+ when the memory used by a pointer is about to be released. The
+ destructor receives <emphasis role="italic">ptr</emphasis> as an
+ argument, and should return 0 for success and -1 for failure.
+ </para>
+ <para>
+ The <emphasis role="italic">destructor</emphasis> can do anything
+ it wants to, including freeing other pieces of memory. A common
+ use for destructors is to clean up operating system resources
+ (such as open file descriptors) contained in the structure the
+ destructor is placed on.
+ </para>
+ <para>
+ You can only place one destructor on a pointer. If you need more
+ than one destructor then you can create a zero-length child of
+ the pointer and place an additional destructor on that.
+ </para>
+ <para>
+ To remove a destructor call talloc_set_destructor() with NULL for
+ the destructor.
+ </para>
+ <para>
+ If your destructor attempts to talloc_free() the pointer that it
+ is the destructor for then talloc_free() will return -1 and the
+ free will be ignored. This would be a pointless operation
+ anyway, as the destructor is only called when the memory is just
+ about to go away.
+ </para>
+ </refsect2>
+ <refsect2><title>int talloc_increase_ref_count(const void *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ The talloc_increase_ref_count(<emphasis
+ role="italic">ptr</emphasis>) function is exactly equivalent to:
+ </para>
+ <programlisting>talloc_reference(NULL, ptr);</programlisting>
+ <para>
+ You can use either syntax, depending on which you think is
+ clearer in your code.
+ </para>
+ <para>
+ It returns 0 on success and -1 on failure.
+ </para>
+ </refsect2>
+ <refsect2><title>size_t talloc_reference_count(const void *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ Return the number of references to the pointer.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_set_name"><title>void talloc_set_name(const void *ptr, const char *fmt, ...);</title>
+ <para>
+ Each talloc pointer has a "name". The name is used principally
+ for debugging purposes, although it is also possible to set and
+ get the name on a pointer in as a way of "marking" pointers in
+ your code.
+ </para>
+ <para>
+ The main use for names on pointer is for "talloc reports". See
+ <link
+ linkend="talloc_report"><quote>talloc_report_depth_cb()</quote></link>,
+ <link
+ linkend="talloc_report"><quote>talloc_report_depth_file()</quote></link>,
+ <link
+ linkend="talloc_report"><quote>talloc_report()</quote></link>
+ <link
+ linkend="talloc_report"><quote>talloc_report()</quote></link>
+ and <link
+ linkend="talloc_report_full"><quote>talloc_report_full()</quote></link>
+ for details. Also see <link
+ linkend="talloc_enable_leak_report"><quote>talloc_enable_leak_report()</quote></link>
+ and <link
+ linkend="talloc_enable_leak_report_full"><quote>talloc_enable_leak_report_full()</quote></link>.
+ </para>
+ <para>
+ The talloc_set_name() function allocates memory as a child of the
+ pointer. It is logically equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...));</programlisting>
+ <para>
+ Note that multiple calls to talloc_set_name() will allocate more
+ memory without releasing the name. All of the memory is released
+ when the ptr is freed using talloc_free().
+ </para>
+ </refsect2>
+ <refsect2><title>void talloc_set_name_const(const void *<emphasis role="italic">ptr</emphasis>, const char *<emphasis role="italic">name</emphasis>);</title>
+ <para>
+ The function talloc_set_name_const() is just like
+ talloc_set_name(), but it takes a string constant, and is much
+ faster. It is extensively used by the "auto naming" macros, such
+ as talloc_p().
+ </para>
+ <para>
+ This function does not allocate any memory. It just copies the
+ supplied pointer into the internal representation of the talloc
+ ptr. This means you must not pass a <emphasis
+ role="italic">name</emphasis> pointer to memory that will
+ disappear before <emphasis role="italic">ptr</emphasis> is freed
+ with talloc_free().
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_named(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, ...);</title>
+ <para>
+ The talloc_named() function creates a named talloc pointer. It
+ is equivalent to:
+ </para>
+ <programlisting>ptr = talloc_size(ctx, size);
+talloc_set_name(ptr, fmt, ....);</programlisting>
+ </refsect2>
+ <refsect2><title>void *talloc_named_const(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>, const char *<emphasis role="italic">name</emphasis>);</title>
+ <para>
+ This is equivalent to:
+ </para>
+ <programlisting>ptr = talloc_size(ctx, size);
+talloc_set_name_const(ptr, name);</programlisting>
+ </refsect2>
+ <refsect2><title>const char *talloc_get_name(const void *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ This returns the current name for the given talloc pointer,
+ <emphasis role="italic">ptr</emphasis>. See <link
+ linkend="talloc_set_name"><quote>talloc_set_name()</quote></link>
+ for details.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_init(const char *<emphasis role="italic">fmt</emphasis>, ...);</title>
+ <para>
+ This function creates a zero length named talloc context as a top
+ level context. It is equivalent to:
+ </para>
+ <programlisting>talloc_named(NULL, 0, fmt, ...);</programlisting>
+ </refsect2>
+ <refsect2><title>void *talloc_new(void *<emphasis role="italic">ctx</emphasis>);</title>
+ <para>
+ This is a utility macro that creates a new memory context hanging
+ off an exiting context, automatically naming it "talloc_new:
+ __location__" where __location__ is the source line it is called
+ from. It is particularly useful for creating a new temporary
+ working context.
+ </para>
+ </refsect2>
+ <refsect2><title>(<emphasis role="italic">type</emphasis> *)talloc_realloc(const void *<emphasis role="italic">ctx</emphasis>, void *<emphasis role="italic">ptr</emphasis>, <emphasis role="italic">type</emphasis>, <emphasis role="italic">count</emphasis>);</title>
+ <para>
+ The talloc_realloc() macro changes the size of a talloc pointer.
+ It has the following equivalences:
+ </para>
+ <programlisting>talloc_realloc(ctx, NULL, type, 1) ==> talloc(ctx, type);
+talloc_realloc(ctx, ptr, type, 0) ==> talloc_free(ptr);</programlisting>
+ <para>
+ The <emphasis role="italic">ctx</emphasis> argument is only used
+ if <emphasis role="italic">ptr</emphasis> is not NULL, otherwise
+ it is ignored.
+ </para>
+ <para>
+ talloc_realloc() returns the new pointer, or NULL on failure.
+ The call will fail either due to a lack of memory, or because the
+ pointer has more than one parent (see <link
+ linkend="talloc_reference"><quote>talloc_reference()</quote></link>).
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_realloc_size(const void *ctx, void *ptr, size_t size);</title>
+ <para>
+ the talloc_realloc_size() function is useful when the type is not
+ known so the type-safe talloc_realloc() cannot be used.
+ </para>
+ </refsect2>
+ <refsect2><title>TYPE *talloc_steal(const void *<emphasis role="italic">new_ctx</emphasis>, const TYPE *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ The talloc_steal() function changes the parent context of a
+ talloc pointer. It is typically used when the context that the
+ pointer is currently a child of is going to be freed and you wish
+ to keep the memory for a longer time.
+ </para>
+ <para>
+ The talloc_steal() function returns the pointer that you pass it.
+ It does not have any failure modes.
+ </para>
+ <para>
+ NOTE: It is possible to produce loops in the parent/child
+ relationship if you are not careful with talloc_steal(). No
+ guarantees are provided as to your sanity or the safety of your
+ data if you do this.
+ </para>
+ </refsect2>
+ <refsect2><title>TYPE *talloc_move(const void *<emphasis role="italic">new_ctx</emphasis>, TYPE **<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ The talloc_move() function is a wrapper around
+ talloc_steal() which zeros the source pointer after the
+ move. This avoids a potential source of bugs where a
+ programmer leaves a pointer in two structures, and uses the
+ pointer from the old structure after it has been moved to a
+ new one.
+ </para>
+ </refsect2>
+ <refsect2><title>size_t talloc_total_size(const void *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ The talloc_total_size() function returns the total size in bytes
+ used by this pointer and all child pointers. Mostly useful for
+ debugging.
+ </para>
+ <para>
+ Passing NULL is allowed, but it will only give a meaningful
+ result if talloc_enable_leak_report() or
+ talloc_enable_leak_report_full() has been called.
+ </para>
+ </refsect2>
+ <refsect2><title>size_t talloc_total_blocks(const void *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ The talloc_total_blocks() function returns the total memory block
+ count used by this pointer and all child pointers. Mostly useful
+ for debugging.
+ </para>
+ <para>
+ Passing NULL is allowed, but it will only give a meaningful
+ result if talloc_enable_leak_report() or
+ talloc_enable_leak_report_full() has been called.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_report"><title>void talloc_report(const void *ptr, FILE *f);</title>
+ <para>
+ The talloc_report() function prints a summary report of all
+ memory used by <emphasis role="italic">ptr</emphasis>. One line
+ of report is printed for each immediate child of ptr, showing the
+ total memory and number of blocks used by that child.
+ </para>
+ <para>
+ You can pass NULL for the pointer, in which case a report is
+ printed for the top level memory context, but only if
+ talloc_enable_leak_report() or talloc_enable_leak_report_full()
+ has been called.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_report_full"><title>void talloc_report_full(const void *<emphasis role="italic">ptr</emphasis>, FILE *<emphasis role="italic">f</emphasis>);</title>
+ <para>
+ This provides a more detailed report than talloc_report(). It
+ will recursively print the entire tree of memory referenced by
+ the pointer. References in the tree are shown by giving the name
+ of the pointer that is referenced.
+ </para>
+ <para>
+ You can pass NULL for the pointer, in which case a report is
+ printed for the top level memory context, but only if
+ talloc_enable_leak_report() or talloc_enable_leak_report_full()
+ has been called.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_report_depth_cb">
+ <funcsynopsis><funcprototype>
+ <funcdef>void <function>talloc_report_depth_cb</function></funcdef>
+ <paramdef><parameter>const void *ptr</parameter></paramdef>
+ <paramdef><parameter>int depth</parameter></paramdef>
+ <paramdef><parameter>int max_depth</parameter></paramdef>
+ <paramdef><parameter>void (*callback)(const void *ptr, int depth, int max_depth, int is_ref, void *priv)</parameter></paramdef>
+ <paramdef><parameter>void *priv</parameter></paramdef>
+ </funcprototype></funcsynopsis>
+ <para>
+ This provides a more flexible reports than talloc_report(). It
+ will recursively call the callback for the entire tree of memory
+ referenced by the pointer. References in the tree are passed with
+ <emphasis role="italic">is_ref = 1</emphasis> and the pointer that is referenced.
+ </para>
+ <para>
+ You can pass NULL for the pointer, in which case a report is
+ printed for the top level memory context, but only if
+ talloc_enable_leak_report() or talloc_enable_leak_report_full()
+ has been called.
+ </para>
+ <para>
+ The recursion is stopped when depth >= max_depth.
+ max_depth = -1 means only stop at leaf nodes.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_report_depth_file">
+ <funcsynopsis><funcprototype>
+ <funcdef>void <function>talloc_report_depth_file</function></funcdef>
+ <paramdef><parameter>const void *ptr</parameter></paramdef>
+ <paramdef><parameter>int depth</parameter></paramdef>
+ <paramdef><parameter>int max_depth</parameter></paramdef>
+ <paramdef><parameter>FILE *f</parameter></paramdef>
+ </funcprototype></funcsynopsis>
+ <para>
+ This provides a more flexible reports than talloc_report(). It
+ will let you specify the depth and max_depth.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_enable_leak_report"><title>void talloc_enable_leak_report(void);</title>
+ <para>
+ This enables calling of talloc_report(NULL, stderr) when the
+ program exits. In Samba4 this is enabled by using the
+ --leak-report command line option.
+ </para>
+ <para>
+ For it to be useful, this function must be called before any
+ other talloc function as it establishes a "null context" that
+ acts as the top of the tree. If you don't call this function
+ first then passing NULL to talloc_report() or
+ talloc_report_full() won't give you the full tree printout.
+ </para>
+ <para>
+ Here is a typical talloc report:
+ </para>
+ <screen format="linespecific">talloc report on 'null_context' (total 267 bytes in 15 blocks)
+libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+iconv(UTF8,CP850) contains 42 bytes in 2 blocks
+libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+iconv(CP850,UTF8) contains 42 bytes in 2 blocks
+iconv(UTF8,UTF-16LE) contains 45 bytes in 2 blocks
+iconv(UTF-16LE,UTF8) contains 45 bytes in 2 blocks
+ </screen>
+ </refsect2>
+ <refsect2 id="talloc_enable_leak_report_full"><title>void talloc_enable_leak_report_full(void);</title>
+ <para>
+ This enables calling of talloc_report_full(NULL, stderr) when the
+ program exits. In Samba4 this is enabled by using the
+ --leak-report-full command line option.
+ </para>
+ <para>
+ For it to be useful, this function must be called before any
+ other talloc function as it establishes a "null context" that
+ acts as the top of the tree. If you don't call this function
+ first then passing NULL to talloc_report() or
+ talloc_report_full() won't give you the full tree printout.
+ </para>
+ <para>
+ Here is a typical full report:
+ </para>
+ <screen format="linespecific">full talloc report on 'root' (total 18 bytes in 8 blocks)
+p1 contains 18 bytes in 7 blocks (ref 0)
+ r1 contains 13 bytes in 2 blocks (ref 0)
+ reference to: p2
+ p2 contains 1 bytes in 1 blocks (ref 1)
+ x3 contains 1 bytes in 1 blocks (ref 0)
+ x2 contains 1 bytes in 1 blocks (ref 0)
+ x1 contains 1 bytes in 1 blocks (ref 0)
+ </screen>
+ </refsect2>
+ <refsect2><title>(<emphasis role="italic">type</emphasis> *)talloc_zero(const void *<emphasis role="italic">ctx</emphasis>, <emphasis role="italic">type</emphasis>);</title>
+ <para>
+ The talloc_zero() macro is equivalent to:
+ </para>
+ <programlisting>ptr = talloc(ctx, type);
+if (ptr) memset(ptr, 0, sizeof(type));</programlisting>
+ </refsect2>
+ <refsect2><title>void *talloc_zero_size(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>)</title>
+ <para>
+ The talloc_zero_size() function is useful when you don't have a
+ known type.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_memdup(const void *<emphasis role="italic">ctx</emphasis>, const void *<emphasis role="italic">p</emphasis>, size_t size);</title>
+ <para>
+ The talloc_memdup() function is equivalent to:
+ </para>
+ <programlisting>ptr = talloc_size(ctx, size);
+if (ptr) memcpy(ptr, p, size);</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_strdup(const void *<emphasis role="italic">ctx</emphasis>, const char *<emphasis role="italic">p</emphasis>);</title>
+ <para>
+ The talloc_strdup() function is equivalent to:
+ </para>
+ <programlisting>ptr = talloc_size(ctx, strlen(p)+1);
+if (ptr) memcpy(ptr, p, strlen(p)+1);</programlisting>
+ <para>
+ This function sets the name of the new pointer to the passed
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_strndup(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">p</emphasis>, size_t <emphasis role="italic">n</emphasis>);</title>
+ <para>
+ The talloc_strndup() function is the talloc equivalent of the C
+ library function strndup(3).
+ </para>
+ <para>
+ This function sets the name of the new pointer to the passed
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_append_string(const void *<emphasis role="italic">t</emphasis>, char *<emphasis role="italic">orig</emphasis>, const char *<emphasis role="italic">append</emphasis>);</title>
+ <para>
+ The talloc_append_string() function appends the given formatted
+ string to the given string.
+ </para>
+ <para>
+ This function sets the name of the new pointer to the new
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_vasprintf(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, va_list <emphasis role="italic">ap</emphasis>);</title>
+ <para>
+ The talloc_vasprintf() function is the talloc equivalent of the C
+ library function vasprintf(3).
+ </para>
+ <para>
+ This function sets the name of the new pointer to the new
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_asprintf(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, ...);</title>
+ <para>
+ The talloc_asprintf() function is the talloc equivalent of the C
+ library function asprintf(3).
+ </para>
+ <para>
+ This function sets the name of the new pointer to the passed
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_asprintf_append(char *s, const char *fmt, ...);</title>
+ <para>
+ The talloc_asprintf_append() function appends the given formatted
+ string to the given string.
+ </para>
+ <para>
+ This function sets the name of the new pointer to the new
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>(type *)talloc_array(const void *ctx, type, uint_t count);</title>
+ <para>
+ The talloc_array() macro is equivalent to:
+ </para>
+ <programlisting>(type *)talloc_size(ctx, sizeof(type) * count);</programlisting>
+ <para>
+ except that it provides integer overflow protection for the
+ multiply, returning NULL if the multiply overflows.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_array_size(const void *ctx, size_t size, uint_t count);</title>
+ <para>
+ The talloc_array_size() function is useful when the type is not
+ known. It operates in the same way as talloc_array(), but takes a
+ size instead of a type.
+ </para>
+ </refsect2>
+ <refsect2><title>(typeof(ptr)) talloc_array_ptrtype(const void *ctx, ptr, uint_t count);</title>
+ <para>
+ The talloc_ptrtype() macro should be used when you have a pointer to an array
+ and want to allocate memory of an array to point at with this pointer. When compiling
+ with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_array_size()
+ and talloc_get_name() will return the current location in the source file.
+ and not the type.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_realloc_fn(const void *ctx, void *ptr, size_t size)</title>
+ <para>
+ This is a non-macro version of talloc_realloc(), which is useful
+ as libraries sometimes want a realloc function pointer. A
+ realloc(3) implementation encapsulates the functionality of
+ malloc(3), free(3) and realloc(3) in one call, which is why it is
+ useful to be able to pass around a single function pointer.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_autofree_context(void);</title>
+ <para>
+ This is a handy utility function that returns a talloc context
+ which will be automatically freed on program exit. This can be
+ used to reduce the noise in memory leak reports.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_check_name(const void *ptr, const char *name);</title>
+ <para>
+ This function checks if a pointer has the specified <emphasis
+ role="italic">name</emphasis>. If it does then the pointer is
+ returned. It it doesn't then NULL is returned.
+ </para>
+ </refsect2>
+ <refsect2><title>(type *)talloc_get_type(const void *ptr, type);</title>
+ <para>
+ This macro allows you to do type checking on talloc pointers. It
+ is particularly useful for void* private pointers. It is
+ equivalent to this:
+ </para>
+ <programlisting>(type *)talloc_check_name(ptr, #type)</programlisting>
+ </refsect2>
+ <refsect2><title>talloc_set_type(const void *ptr, type);</title>
+ <para>
+ This macro allows you to force the name of a pointer to be a
+ particular <emphasis>type</emphasis>. This can be
+ used in conjunction with talloc_get_type() to do type checking on
+ void* pointers.
+ </para>
+ <para>
+ It is equivalent to this:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, #type)</programlisting>
+ </refsect2>
+ </refsect1>
+ <refsect1><title>PERFORMANCE</title>
+ <para>
+ All the additional features of talloc(3) over malloc(3) do come at a
+ price. We have a simple performance test in Samba4 that measures
+ talloc() versus malloc() performance, and it seems that talloc() is
+ about 10% slower than malloc() on my x86 Debian Linux box. For
+ Samba, the great reduction in code complexity that we get by using
+ talloc makes this worthwhile, especially as the total overhead of
+ talloc/malloc in Samba is already quite small.
+ </para>
+ </refsect1>
+ <refsect1><title>SEE ALSO</title>
+ <para>
+ malloc(3), strndup(3), vasprintf(3), asprintf(3),
+ <ulink url="http://talloc.samba.org/"/>
+ </para>
+ </refsect1>
+ <refsect1><title>COPYRIGHT/LICENSE</title>
+ <para>
+ Copyright (C) Andrew Tridgell 2004
+ </para>
+ <para>
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or (at
+ your option) any later version.
+ </para>
+ <para>
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+ </para>
+ <para>
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see http://www.gnu.org/licenses/.
+ </para>
+ </refsect1>
+</refentry>
diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c
new file mode 100644
index 0000000000..1f7e52439f
--- /dev/null
+++ b/source3/lib/talloc/talloc.c
@@ -0,0 +1,1732 @@
+/*
+ Samba Unix SMB/CIFS implementation.
+
+ Samba trivial allocation library - new interface
+
+ NOTE: Please read talloc_guide.txt for full documentation
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Stefan Metzmacher 2006
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ inspired by http://swapped.cc/halloc/
+*/
+
+#ifdef _SAMBA_BUILD_
+#include "version.h"
+#if (SAMBA_VERSION_MAJOR<4)
+#include "includes.h"
+/* This is to circumvent SAMBA3's paranoid malloc checker. Here in this file
+ * we trust ourselves... */
+#ifdef malloc
+#undef malloc
+#endif
+#ifdef realloc
+#undef realloc
+#endif
+#define _TALLOC_SAMBA3
+#endif /* (SAMBA_VERSION_MAJOR<4) */
+#endif /* _SAMBA_BUILD_ */
+
+#ifndef _TALLOC_SAMBA3
+#include "replace.h"
+#include "talloc.h"
+#endif /* not _TALLOC_SAMBA3 */
+
+/* use this to force every realloc to change the pointer, to stress test
+ code that might not cope */
+#define ALWAYS_REALLOC 0
+
+
+#define MAX_TALLOC_SIZE 0x10000000
+#define TALLOC_MAGIC 0xe814ec70
+#define TALLOC_FLAG_FREE 0x01
+#define TALLOC_FLAG_LOOP 0x02
+#define TALLOC_FLAG_POOL 0x04 /* This is a talloc pool */
+#define TALLOC_FLAG_POOLMEM 0x08 /* This is allocated in a pool */
+#define TALLOC_MAGIC_REFERENCE ((const char *)1)
+
+/* by default we abort when given a bad pointer (such as when talloc_free() is called
+ on a pointer that came from malloc() */
+#ifndef TALLOC_ABORT
+#define TALLOC_ABORT(reason) abort()
+#endif
+
+#ifndef discard_const_p
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
+#else
+# define discard_const_p(type, ptr) ((type *)(ptr))
+#endif
+#endif
+
+/* these macros gain us a few percent of speed on gcc */
+#if (__GNUC__ >= 3)
+/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
+ as its first argument */
+#ifndef likely
+#define likely(x) __builtin_expect(!!(x), 1)
+#endif
+#ifndef unlikely
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#endif
+#else
+#ifndef likely
+#define likely(x) (x)
+#endif
+#ifndef unlikely
+#define unlikely(x) (x)
+#endif
+#endif
+
+/* this null_context is only used if talloc_enable_leak_report() or
+ talloc_enable_leak_report_full() is called, otherwise it remains
+ NULL
+*/
+static void *null_context;
+static void *autofree_context;
+
+struct talloc_reference_handle {
+ struct talloc_reference_handle *next, *prev;
+ void *ptr;
+};
+
+typedef int (*talloc_destructor_t)(void *);
+
+struct talloc_chunk {
+ struct talloc_chunk *next, *prev;
+ struct talloc_chunk *parent, *child;
+ struct talloc_reference_handle *refs;
+ talloc_destructor_t destructor;
+ const char *name;
+ size_t size;
+ unsigned flags;
+
+ /*
+ * "pool" has dual use:
+ *
+ * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool"
+ * marks the end of the currently allocated area.
+ *
+ * For members of the pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool"
+ * is a pointer to the struct talloc_chunk of the pool that it was
+ * allocated from. This way children can quickly find the pool to chew
+ * from.
+ */
+ void *pool;
+};
+
+/* 16 byte alignment seems to keep everyone happy */
+#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
+#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
+
+static void talloc_abort_double_free(void)
+{
+ TALLOC_ABORT("Bad talloc magic value - double free");
+}
+
+static void talloc_abort_unknown_value(void)
+{
+ TALLOC_ABORT("Bad talloc magic value - unknown value");
+}
+
+/* panic if we get a bad magic value */
+static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
+{
+ const char *pp = (const char *)ptr;
+ struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
+ if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) {
+ if (tc->flags & TALLOC_FLAG_FREE) {
+ talloc_abort_double_free();
+ } else {
+ talloc_abort_unknown_value();
+ }
+ }
+ return tc;
+}
+
+/* hook into the front of the list */
+#define _TLIST_ADD(list, p) \
+do { \
+ if (!(list)) { \
+ (list) = (p); \
+ (p)->next = (p)->prev = NULL; \
+ } else { \
+ (list)->prev = (p); \
+ (p)->next = (list); \
+ (p)->prev = NULL; \
+ (list) = (p); \
+ }\
+} while (0)
+
+/* remove an element from a list - element doesn't have to be in list. */
+#define _TLIST_REMOVE(list, p) \
+do { \
+ if ((p) == (list)) { \
+ (list) = (p)->next; \
+ if (list) (list)->prev = NULL; \
+ } else { \
+ if ((p)->prev) (p)->prev->next = (p)->next; \
+ if ((p)->next) (p)->next->prev = (p)->prev; \
+ } \
+ if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
+} while (0)
+
+
+/*
+ return the parent chunk of a pointer
+*/
+static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr)
+{
+ struct talloc_chunk *tc;
+
+ if (unlikely(ptr == NULL)) {
+ return NULL;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+ while (tc->prev) tc=tc->prev;
+
+ return tc->parent;
+}
+
+void *talloc_parent(const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_parent_chunk(ptr);
+ return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
+}
+
+/*
+ find parents name
+*/
+const char *talloc_parent_name(const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_parent_chunk(ptr);
+ return tc? tc->name : NULL;
+}
+
+/*
+ A pool carries an in-pool object count count in the first 16 bytes.
+ bytes. This is done to support talloc_steal() to a parent outside of the
+ pool. The count includes the pool itself, so a talloc_free() on a pool will
+ only destroy the pool if the count has dropped to zero. A talloc_free() of a
+ pool member will reduce the count, and eventually also call free(3) on the
+ pool memory.
+
+ The object count is not put into "struct talloc_chunk" because it is only
+ relevant for talloc pools and the alignment to 16 bytes would increase the
+ memory footprint of each talloc chunk by those 16 bytes.
+*/
+
+#define TALLOC_POOL_HDR_SIZE 16
+
+static unsigned int *talloc_pool_objectcount(struct talloc_chunk *tc)
+{
+ return (unsigned int *)((char *)tc + sizeof(struct talloc_chunk));
+}
+
+/*
+ Allocate from a pool
+*/
+
+static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
+ size_t size)
+{
+ struct talloc_chunk *pool_ctx = NULL;
+ size_t space_left;
+ struct talloc_chunk *result;
+ size_t chunk_size;
+
+ if (parent == NULL) {
+ return NULL;
+ }
+
+ if (parent->flags & TALLOC_FLAG_POOL) {
+ pool_ctx = parent;
+ }
+ else if (parent->flags & TALLOC_FLAG_POOLMEM) {
+ pool_ctx = (struct talloc_chunk *)parent->pool;
+ }
+
+ if (pool_ctx == NULL) {
+ return NULL;
+ }
+
+ space_left = ((char *)pool_ctx + TC_HDR_SIZE + pool_ctx->size)
+ - ((char *)pool_ctx->pool);
+
+ /*
+ * Align size to 16 bytes
+ */
+ chunk_size = ((size + 15) & ~15);
+
+ if (space_left < chunk_size) {
+ return NULL;
+ }
+
+ result = (struct talloc_chunk *)pool_ctx->pool;
+
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
+ VALGRIND_MAKE_MEM_UNDEFINED(result, size);
+#endif
+
+ pool_ctx->pool = (void *)((char *)result + chunk_size);
+
+ result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM;
+ result->pool = pool_ctx;
+
+ *talloc_pool_objectcount(pool_ctx) += 1;
+
+ return result;
+}
+
+/*
+ Allocate a bit of memory as a child of an existing pointer
+*/
+static inline void *__talloc(const void *context, size_t size)
+{
+ struct talloc_chunk *tc = NULL;
+
+ if (unlikely(context == NULL)) {
+ context = null_context;
+ }
+
+ if (unlikely(size >= MAX_TALLOC_SIZE)) {
+ return NULL;
+ }
+
+ if (context != NULL) {
+ tc = talloc_alloc_pool(talloc_chunk_from_ptr(context),
+ TC_HDR_SIZE+size);
+ }
+
+ if (tc == NULL) {
+ tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size);
+ if (unlikely(tc == NULL)) return NULL;
+ tc->flags = TALLOC_MAGIC;
+ tc->pool = NULL;
+ }
+
+ tc->size = size;
+ tc->destructor = NULL;
+ tc->child = NULL;
+ tc->name = NULL;
+ tc->refs = NULL;
+
+ if (likely(context)) {
+ struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
+
+ if (parent->child) {
+ parent->child->parent = NULL;
+ tc->next = parent->child;
+ tc->next->prev = tc;
+ } else {
+ tc->next = NULL;
+ }
+ tc->parent = parent;
+ tc->prev = NULL;
+ parent->child = tc;
+ } else {
+ tc->next = tc->prev = tc->parent = NULL;
+ }
+
+ return TC_PTR_FROM_CHUNK(tc);
+}
+
+/*
+ * Create a talloc pool
+ */
+
+void *talloc_pool(const void *context, size_t size)
+{
+ void *result = __talloc(context, size + TALLOC_POOL_HDR_SIZE);
+ struct talloc_chunk *tc;
+
+ if (unlikely(result == NULL)) {
+ return NULL;
+ }
+
+ tc = talloc_chunk_from_ptr(result);
+
+ tc->flags |= TALLOC_FLAG_POOL;
+ tc->pool = (char *)result + TALLOC_POOL_HDR_SIZE;
+
+ *talloc_pool_objectcount(tc) = 1;
+
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
+ VALGRIND_MAKE_MEM_NOACCESS(tc->pool, size);
+#endif
+
+ return result;
+}
+
+/*
+ setup a destructor to be called on free of a pointer
+ the destructor should return 0 on success, or -1 on failure.
+ if the destructor fails then the free is failed, and the memory can
+ be continued to be used
+*/
+void _talloc_set_destructor(const void *ptr, int (*destructor)(void *))
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ tc->destructor = destructor;
+}
+
+/*
+ increase the reference count on a piece of memory.
+*/
+int talloc_increase_ref_count(const void *ptr)
+{
+ if (unlikely(!talloc_reference(null_context, ptr))) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ helper for talloc_reference()
+
+ this is referenced by a function pointer and should not be inline
+*/
+static int talloc_reference_destructor(struct talloc_reference_handle *handle)
+{
+ struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr);
+ _TLIST_REMOVE(ptr_tc->refs, handle);
+ return 0;
+}
+
+/*
+ more efficient way to add a name to a pointer - the name must point to a
+ true string constant
+*/
+static inline void _talloc_set_name_const(const void *ptr, const char *name)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ tc->name = name;
+}
+
+/*
+ internal talloc_named_const()
+*/
+static inline void *_talloc_named_const(const void *context, size_t size, const char *name)
+{
+ void *ptr;
+
+ ptr = __talloc(context, size);
+ if (unlikely(ptr == NULL)) {
+ return NULL;
+ }
+
+ _talloc_set_name_const(ptr, name);
+
+ return ptr;
+}
+
+/*
+ make a secondary reference to a pointer, hanging off the given context.
+ the pointer remains valid until both the original caller and this given
+ context are freed.
+
+ the major use for this is when two different structures need to reference the
+ same underlying data, and you want to be able to free the two instances separately,
+ and in either order
+*/
+void *_talloc_reference(const void *context, const void *ptr)
+{
+ struct talloc_chunk *tc;
+ struct talloc_reference_handle *handle;
+ if (unlikely(ptr == NULL)) return NULL;
+
+ tc = talloc_chunk_from_ptr(ptr);
+ handle = (struct talloc_reference_handle *)_talloc_named_const(context,
+ sizeof(struct talloc_reference_handle),
+ TALLOC_MAGIC_REFERENCE);
+ if (unlikely(handle == NULL)) return NULL;
+
+ /* note that we hang the destructor off the handle, not the
+ main context as that allows the caller to still setup their
+ own destructor on the context if they want to */
+ talloc_set_destructor(handle, talloc_reference_destructor);
+ handle->ptr = discard_const_p(void, ptr);
+ _TLIST_ADD(tc->refs, handle);
+ return handle->ptr;
+}
+
+
+/*
+ internal talloc_free call
+*/
+static inline int _talloc_free(void *ptr)
+{
+ struct talloc_chunk *tc;
+
+ if (unlikely(ptr == NULL)) {
+ return -1;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (unlikely(tc->refs)) {
+ int is_child;
+ /* check this is a reference from a child or grantchild
+ * back to it's parent or grantparent
+ *
+ * in that case we need to remove the reference and
+ * call another instance of talloc_free() on the current
+ * pointer.
+ */
+ is_child = talloc_is_parent(tc->refs, ptr);
+ _talloc_free(tc->refs);
+ if (is_child) {
+ return _talloc_free(ptr);
+ }
+ return -1;
+ }
+
+ if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) {
+ /* we have a free loop - stop looping */
+ return 0;
+ }
+
+ if (unlikely(tc->destructor)) {
+ talloc_destructor_t d = tc->destructor;
+ if (d == (talloc_destructor_t)-1) {
+ return -1;
+ }
+ tc->destructor = (talloc_destructor_t)-1;
+ if (d(ptr) == -1) {
+ tc->destructor = d;
+ return -1;
+ }
+ tc->destructor = NULL;
+ }
+
+ if (tc->parent) {
+ _TLIST_REMOVE(tc->parent->child, tc);
+ if (tc->parent->child) {
+ tc->parent->child->parent = tc->parent;
+ }
+ } else {
+ if (tc->prev) tc->prev->next = tc->next;
+ if (tc->next) tc->next->prev = tc->prev;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+
+ while (tc->child) {
+ /* we need to work out who will own an abandoned child
+ if it cannot be freed. In priority order, the first
+ choice is owner of any remaining reference to this
+ pointer, the second choice is our parent, and the
+ final choice is the null context. */
+ void *child = TC_PTR_FROM_CHUNK(tc->child);
+ const void *new_parent = null_context;
+ if (unlikely(tc->child->refs)) {
+ struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
+ if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+ }
+ if (unlikely(_talloc_free(child) == -1)) {
+ if (new_parent == null_context) {
+ struct talloc_chunk *p = talloc_parent_chunk(ptr);
+ if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+ }
+ talloc_steal(new_parent, child);
+ }
+ }
+
+ tc->flags |= TALLOC_FLAG_FREE;
+
+ if (tc->flags & (TALLOC_FLAG_POOL|TALLOC_FLAG_POOLMEM)) {
+ struct talloc_chunk *pool;
+ unsigned int *pool_object_count;
+
+ pool = (tc->flags & TALLOC_FLAG_POOL)
+ ? tc : (struct talloc_chunk *)tc->pool;
+
+ pool_object_count = talloc_pool_objectcount(pool);
+
+ if (*pool_object_count == 0) {
+ TALLOC_ABORT("Pool object count zero!");
+ }
+
+ *pool_object_count -= 1;
+
+ if (*pool_object_count == 0) {
+ free(pool);
+ }
+ }
+ else {
+ free(tc);
+ }
+ return 0;
+}
+
+/*
+ move a lump of memory from one talloc context to another return the
+ ptr on success, or NULL if it could not be transferred.
+ passing NULL as ptr will always return NULL with no side effects.
+*/
+void *_talloc_steal(const void *new_ctx, const void *ptr)
+{
+ struct talloc_chunk *tc, *new_tc;
+
+ if (unlikely(!ptr)) {
+ return NULL;
+ }
+
+ if (unlikely(new_ctx == NULL)) {
+ new_ctx = null_context;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (unlikely(new_ctx == NULL)) {
+ if (tc->parent) {
+ _TLIST_REMOVE(tc->parent->child, tc);
+ if (tc->parent->child) {
+ tc->parent->child->parent = tc->parent;
+ }
+ } else {
+ if (tc->prev) tc->prev->next = tc->next;
+ if (tc->next) tc->next->prev = tc->prev;
+ }
+
+ tc->parent = tc->next = tc->prev = NULL;
+ return discard_const_p(void, ptr);
+ }
+
+ new_tc = talloc_chunk_from_ptr(new_ctx);
+
+ if (unlikely(tc == new_tc || tc->parent == new_tc)) {
+ return discard_const_p(void, ptr);
+ }
+
+ if (tc->parent) {
+ _TLIST_REMOVE(tc->parent->child, tc);
+ if (tc->parent->child) {
+ tc->parent->child->parent = tc->parent;
+ }
+ } else {
+ if (tc->prev) tc->prev->next = tc->next;
+ if (tc->next) tc->next->prev = tc->prev;
+ }
+
+ tc->parent = new_tc;
+ if (new_tc->child) new_tc->child->parent = NULL;
+ _TLIST_ADD(new_tc->child, tc);
+
+ return discard_const_p(void, ptr);
+}
+
+
+
+/*
+ remove a secondary reference to a pointer. This undo's what
+ talloc_reference() has done. The context and pointer arguments
+ must match those given to a talloc_reference()
+*/
+static inline int talloc_unreference(const void *context, const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ struct talloc_reference_handle *h;
+
+ if (unlikely(context == NULL)) {
+ context = null_context;
+ }
+
+ for (h=tc->refs;h;h=h->next) {
+ struct talloc_chunk *p = talloc_parent_chunk(h);
+ if (p == NULL) {
+ if (context == NULL) break;
+ } else if (TC_PTR_FROM_CHUNK(p) == context) {
+ break;
+ }
+ }
+ if (h == NULL) {
+ return -1;
+ }
+
+ return _talloc_free(h);
+}
+
+/*
+ remove a specific parent context from a pointer. This is a more
+ controlled varient of talloc_free()
+*/
+int talloc_unlink(const void *context, void *ptr)
+{
+ struct talloc_chunk *tc_p, *new_p;
+ void *new_parent;
+
+ if (ptr == NULL) {
+ return -1;
+ }
+
+ if (context == NULL) {
+ context = null_context;
+ }
+
+ if (talloc_unreference(context, ptr) == 0) {
+ return 0;
+ }
+
+ if (context == NULL) {
+ if (talloc_parent_chunk(ptr) != NULL) {
+ return -1;
+ }
+ } else {
+ if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
+ return -1;
+ }
+ }
+
+ tc_p = talloc_chunk_from_ptr(ptr);
+
+ if (tc_p->refs == NULL) {
+ return _talloc_free(ptr);
+ }
+
+ new_p = talloc_parent_chunk(tc_p->refs);
+ if (new_p) {
+ new_parent = TC_PTR_FROM_CHUNK(new_p);
+ } else {
+ new_parent = NULL;
+ }
+
+ if (talloc_unreference(new_parent, ptr) != 0) {
+ return -1;
+ }
+
+ talloc_steal(new_parent, ptr);
+
+ return 0;
+}
+
+/*
+ add a name to an existing pointer - va_list version
+*/
+static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ tc->name = talloc_vasprintf(ptr, fmt, ap);
+ if (likely(tc->name)) {
+ _talloc_set_name_const(tc->name, ".name");
+ }
+ return tc->name;
+}
+
+/*
+ add a name to an existing pointer
+*/
+const char *talloc_set_name(const void *ptr, const char *fmt, ...)
+{
+ const char *name;
+ va_list ap;
+ va_start(ap, fmt);
+ name = talloc_set_name_v(ptr, fmt, ap);
+ va_end(ap);
+ return name;
+}
+
+
+/*
+ create a named talloc pointer. Any talloc pointer can be named, and
+ talloc_named() operates just like talloc() except that it allows you
+ to name the pointer.
+*/
+void *talloc_named(const void *context, size_t size, const char *fmt, ...)
+{
+ va_list ap;
+ void *ptr;
+ const char *name;
+
+ ptr = __talloc(context, size);
+ if (unlikely(ptr == NULL)) return NULL;
+
+ va_start(ap, fmt);
+ name = talloc_set_name_v(ptr, fmt, ap);
+ va_end(ap);
+
+ if (unlikely(name == NULL)) {
+ _talloc_free(ptr);
+ return NULL;
+ }
+
+ return ptr;
+}
+
+/*
+ return the name of a talloc ptr, or "UNNAMED"
+*/
+const char *talloc_get_name(const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) {
+ return ".reference";
+ }
+ if (likely(tc->name)) {
+ return tc->name;
+ }
+ return "UNNAMED";
+}
+
+
+/*
+ check if a pointer has the given name. If it does, return the pointer,
+ otherwise return NULL
+*/
+void *talloc_check_name(const void *ptr, const char *name)
+{
+ const char *pname;
+ if (unlikely(ptr == NULL)) return NULL;
+ pname = talloc_get_name(ptr);
+ if (likely(pname == name || strcmp(pname, name) == 0)) {
+ return discard_const_p(void, ptr);
+ }
+ return NULL;
+}
+
+
+/*
+ this is for compatibility with older versions of talloc
+*/
+void *talloc_init(const char *fmt, ...)
+{
+ va_list ap;
+ void *ptr;
+ const char *name;
+
+ /*
+ * samba3 expects talloc_report_depth_cb(NULL, ...)
+ * reports all talloc'ed memory, so we need to enable
+ * null_tracking
+ */
+ talloc_enable_null_tracking();
+
+ ptr = __talloc(NULL, 0);
+ if (unlikely(ptr == NULL)) return NULL;
+
+ va_start(ap, fmt);
+ name = talloc_set_name_v(ptr, fmt, ap);
+ va_end(ap);
+
+ if (unlikely(name == NULL)) {
+ _talloc_free(ptr);
+ return NULL;
+ }
+
+ return ptr;
+}
+
+/*
+ this is a replacement for the Samba3 talloc_destroy_pool functionality. It
+ should probably not be used in new code. It's in here to keep the talloc
+ code consistent across Samba 3 and 4.
+*/
+void talloc_free_children(void *ptr)
+{
+ struct talloc_chunk *tc;
+
+ if (unlikely(ptr == NULL)) {
+ return;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ while (tc->child) {
+ /* we need to work out who will own an abandoned child
+ if it cannot be freed. In priority order, the first
+ choice is owner of any remaining reference to this
+ pointer, the second choice is our parent, and the
+ final choice is the null context. */
+ void *child = TC_PTR_FROM_CHUNK(tc->child);
+ const void *new_parent = null_context;
+ if (unlikely(tc->child->refs)) {
+ struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
+ if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+ }
+ if (unlikely(_talloc_free(child) == -1)) {
+ if (new_parent == null_context) {
+ struct talloc_chunk *p = talloc_parent_chunk(ptr);
+ if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+ }
+ talloc_steal(new_parent, child);
+ }
+ }
+
+ if ((tc->flags & TALLOC_FLAG_POOL)
+ && (*talloc_pool_objectcount(tc) == 1)) {
+ tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE);
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
+ VALGRIND_MAKE_MEM_NOACCESS(
+ tc->pool, tc->size - TALLOC_POOL_HDR_SIZE);
+#endif
+ }
+}
+
+/*
+ Allocate a bit of memory as a child of an existing pointer
+*/
+void *_talloc(const void *context, size_t size)
+{
+ return __talloc(context, size);
+}
+
+/*
+ externally callable talloc_set_name_const()
+*/
+void talloc_set_name_const(const void *ptr, const char *name)
+{
+ _talloc_set_name_const(ptr, name);
+}
+
+/*
+ create a named talloc pointer. Any talloc pointer can be named, and
+ talloc_named() operates just like talloc() except that it allows you
+ to name the pointer.
+*/
+void *talloc_named_const(const void *context, size_t size, const char *name)
+{
+ return _talloc_named_const(context, size, name);
+}
+
+/*
+ free a talloc pointer. This also frees all child pointers of this
+ pointer recursively
+
+ return 0 if the memory is actually freed, otherwise -1. The memory
+ will not be freed if the ref_count is > 1 or the destructor (if
+ any) returns non-zero
+*/
+int talloc_free(void *ptr)
+{
+ return _talloc_free(ptr);
+}
+
+
+
+/*
+ A talloc version of realloc. The context argument is only used if
+ ptr is NULL
+*/
+void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
+{
+ struct talloc_chunk *tc;
+ void *new_ptr;
+ bool malloced = false;
+
+ /* size zero is equivalent to free() */
+ if (unlikely(size == 0)) {
+ _talloc_free(ptr);
+ return NULL;
+ }
+
+ if (unlikely(size >= MAX_TALLOC_SIZE)) {
+ return NULL;
+ }
+
+ /* realloc(NULL) is equivalent to malloc() */
+ if (ptr == NULL) {
+ return _talloc_named_const(context, size, name);
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ /* don't allow realloc on referenced pointers */
+ if (unlikely(tc->refs)) {
+ return NULL;
+ }
+
+ /* don't shrink if we have less than 1k to gain */
+ if ((size < tc->size) && ((tc->size - size) < 1024)) {
+ tc->size = size;
+ return ptr;
+ }
+
+ /* by resetting magic we catch users of the old memory */
+ tc->flags |= TALLOC_FLAG_FREE;
+
+#if ALWAYS_REALLOC
+ new_ptr = malloc(size + TC_HDR_SIZE);
+ if (new_ptr) {
+ memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
+ free(tc);
+ }
+#else
+ if (tc->flags & TALLOC_FLAG_POOLMEM) {
+
+ new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE);
+ *talloc_pool_objectcount((struct talloc_chunk *)
+ (tc->pool)) -= 1;
+
+ if (new_ptr == NULL) {
+ new_ptr = malloc(TC_HDR_SIZE+size);
+ malloced = true;
+ }
+
+ if (new_ptr) {
+ memcpy(new_ptr, tc, MIN(tc->size,size) + TC_HDR_SIZE);
+ }
+ }
+ else {
+ new_ptr = realloc(tc, size + TC_HDR_SIZE);
+ }
+#endif
+ if (unlikely(!new_ptr)) {
+ tc->flags &= ~TALLOC_FLAG_FREE;
+ return NULL;
+ }
+
+ tc = (struct talloc_chunk *)new_ptr;
+ tc->flags &= ~TALLOC_FLAG_FREE;
+ if (malloced) {
+ tc->flags &= ~TALLOC_FLAG_POOLMEM;
+ }
+ if (tc->parent) {
+ tc->parent->child = tc;
+ }
+ if (tc->child) {
+ tc->child->parent = tc;
+ }
+
+ if (tc->prev) {
+ tc->prev->next = tc;
+ }
+ if (tc->next) {
+ tc->next->prev = tc;
+ }
+
+ tc->size = size;
+ _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
+
+ return TC_PTR_FROM_CHUNK(tc);
+}
+
+/*
+ a wrapper around talloc_steal() for situations where you are moving a pointer
+ between two structures, and want the old pointer to be set to NULL
+*/
+void *_talloc_move(const void *new_ctx, const void *_pptr)
+{
+ const void **pptr = discard_const_p(const void *,_pptr);
+ void *ret = _talloc_steal(new_ctx, *pptr);
+ (*pptr) = NULL;
+ return ret;
+}
+
+/*
+ return the total size of a talloc pool (subtree)
+*/
+size_t talloc_total_size(const void *ptr)
+{
+ size_t total = 0;
+ struct talloc_chunk *c, *tc;
+
+ if (ptr == NULL) {
+ ptr = null_context;
+ }
+ if (ptr == NULL) {
+ return 0;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (tc->flags & TALLOC_FLAG_LOOP) {
+ return 0;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+
+ total = tc->size;
+ for (c=tc->child;c;c=c->next) {
+ total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
+ }
+
+ tc->flags &= ~TALLOC_FLAG_LOOP;
+
+ return total;
+}
+
+/*
+ return the total number of blocks in a talloc pool (subtree)
+*/
+size_t talloc_total_blocks(const void *ptr)
+{
+ size_t total = 0;
+ struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
+
+ if (tc->flags & TALLOC_FLAG_LOOP) {
+ return 0;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+
+ total++;
+ for (c=tc->child;c;c=c->next) {
+ total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
+ }
+
+ tc->flags &= ~TALLOC_FLAG_LOOP;
+
+ return total;
+}
+
+/*
+ return the number of external references to a pointer
+*/
+size_t talloc_reference_count(const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ struct talloc_reference_handle *h;
+ size_t ret = 0;
+
+ for (h=tc->refs;h;h=h->next) {
+ ret++;
+ }
+ return ret;
+}
+
+/*
+ report on memory usage by all children of a pointer, giving a full tree view
+*/
+void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
+ void (*callback)(const void *ptr,
+ int depth, int max_depth,
+ int is_ref,
+ void *private_data),
+ void *private_data)
+{
+ struct talloc_chunk *c, *tc;
+
+ if (ptr == NULL) {
+ ptr = null_context;
+ }
+ if (ptr == NULL) return;
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (tc->flags & TALLOC_FLAG_LOOP) {
+ return;
+ }
+
+ callback(ptr, depth, max_depth, 0, private_data);
+
+ if (max_depth >= 0 && depth >= max_depth) {
+ return;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+ for (c=tc->child;c;c=c->next) {
+ if (c->name == TALLOC_MAGIC_REFERENCE) {
+ struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c);
+ callback(h->ptr, depth + 1, max_depth, 1, private_data);
+ } else {
+ talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data);
+ }
+ }
+ tc->flags &= ~TALLOC_FLAG_LOOP;
+}
+
+static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f)
+{
+ const char *name = talloc_get_name(ptr);
+ FILE *f = (FILE *)_f;
+
+ if (is_ref) {
+ fprintf(f, "%*sreference to: %s\n", depth*4, "", name);
+ return;
+ }
+
+ if (depth == 0) {
+ fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n",
+ (max_depth < 0 ? "full " :""), name,
+ (unsigned long)talloc_total_size(ptr),
+ (unsigned long)talloc_total_blocks(ptr));
+ return;
+ }
+
+ fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n",
+ depth*4, "",
+ name,
+ (unsigned long)talloc_total_size(ptr),
+ (unsigned long)talloc_total_blocks(ptr),
+ (int)talloc_reference_count(ptr), ptr);
+
+#if 0
+ fprintf(f, "content: ");
+ if (talloc_total_size(ptr)) {
+ int tot = talloc_total_size(ptr);
+ int i;
+
+ for (i = 0; i < tot; i++) {
+ if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) {
+ fprintf(f, "%c", ((char *)ptr)[i]);
+ } else {
+ fprintf(f, "~%02x", ((char *)ptr)[i]);
+ }
+ }
+ }
+ fprintf(f, "\n");
+#endif
+}
+
+/*
+ report on memory usage by all children of a pointer, giving a full tree view
+*/
+void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f)
+{
+ talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f);
+ fflush(f);
+}
+
+/*
+ report on memory usage by all children of a pointer, giving a full tree view
+*/
+void talloc_report_full(const void *ptr, FILE *f)
+{
+ talloc_report_depth_file(ptr, 0, -1, f);
+}
+
+/*
+ report on memory usage by all children of a pointer
+*/
+void talloc_report(const void *ptr, FILE *f)
+{
+ talloc_report_depth_file(ptr, 0, 1, f);
+}
+
+/*
+ report on any memory hanging off the null context
+*/
+static void talloc_report_null(void)
+{
+ if (talloc_total_size(null_context) != 0) {
+ talloc_report(null_context, stderr);
+ }
+}
+
+/*
+ report on any memory hanging off the null context
+*/
+static void talloc_report_null_full(void)
+{
+ if (talloc_total_size(null_context) != 0) {
+ talloc_report_full(null_context, stderr);
+ }
+}
+
+/*
+ enable tracking of the NULL context
+*/
+void talloc_enable_null_tracking(void)
+{
+ if (null_context == NULL) {
+ null_context = _talloc_named_const(NULL, 0, "null_context");
+ }
+}
+
+/*
+ disable tracking of the NULL context
+*/
+void talloc_disable_null_tracking(void)
+{
+ _talloc_free(null_context);
+ null_context = NULL;
+}
+
+/*
+ enable leak reporting on exit
+*/
+void talloc_enable_leak_report(void)
+{
+ talloc_enable_null_tracking();
+ atexit(talloc_report_null);
+}
+
+/*
+ enable full leak reporting on exit
+*/
+void talloc_enable_leak_report_full(void)
+{
+ talloc_enable_null_tracking();
+ atexit(talloc_report_null_full);
+}
+
+/*
+ talloc and zero memory.
+*/
+void *_talloc_zero(const void *ctx, size_t size, const char *name)
+{
+ void *p = _talloc_named_const(ctx, size, name);
+
+ if (p) {
+ memset(p, '\0', size);
+ }
+
+ return p;
+}
+
+/*
+ memdup with a talloc.
+*/
+void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
+{
+ void *newp = _talloc_named_const(t, size, name);
+
+ if (likely(newp)) {
+ memcpy(newp, p, size);
+ }
+
+ return newp;
+}
+
+static inline char *__talloc_strlendup(const void *t, const char *p, size_t len)
+{
+ char *ret;
+
+ ret = (char *)__talloc(t, len + 1);
+ if (unlikely(!ret)) return NULL;
+
+ memcpy(ret, p, len);
+ ret[len] = 0;
+
+ _talloc_set_name_const(ret, ret);
+ return ret;
+}
+
+/*
+ strdup with a talloc
+*/
+char *talloc_strdup(const void *t, const char *p)
+{
+ if (unlikely(!p)) return NULL;
+ return __talloc_strlendup(t, p, strlen(p));
+}
+
+/*
+ strndup with a talloc
+*/
+char *talloc_strndup(const void *t, const char *p, size_t n)
+{
+ if (unlikely(!p)) return NULL;
+ return __talloc_strlendup(t, p, strnlen(p, n));
+}
+
+static inline char *__talloc_strlendup_append(char *s, size_t slen,
+ const char *a, size_t alen)
+{
+ char *ret;
+
+ ret = talloc_realloc(NULL, s, char, slen + alen + 1);
+ if (unlikely(!ret)) return NULL;
+
+ /* append the string and the trailing \0 */
+ memcpy(&ret[slen], a, alen);
+ ret[slen+alen] = 0;
+
+ _talloc_set_name_const(ret, ret);
+ return ret;
+}
+
+/*
+ * Appends at the end of the string.
+ */
+char *talloc_strdup_append(char *s, const char *a)
+{
+ if (unlikely(!s)) {
+ return talloc_strdup(NULL, a);
+ }
+
+ if (unlikely(!a)) {
+ return s;
+ }
+
+ return __talloc_strlendup_append(s, strlen(s), a, strlen(a));
+}
+
+/*
+ * Appends at the end of the talloc'ed buffer,
+ * not the end of the string.
+ */
+char *talloc_strdup_append_buffer(char *s, const char *a)
+{
+ size_t slen;
+
+ if (unlikely(!s)) {
+ return talloc_strdup(NULL, a);
+ }
+
+ if (unlikely(!a)) {
+ return s;
+ }
+
+ slen = talloc_get_size(s);
+ if (likely(slen > 0)) {
+ slen--;
+ }
+
+ return __talloc_strlendup_append(s, slen, a, strlen(a));
+}
+
+/*
+ * Appends at the end of the string.
+ */
+char *talloc_strndup_append(char *s, const char *a, size_t n)
+{
+ if (unlikely(!s)) {
+ return talloc_strdup(NULL, a);
+ }
+
+ if (unlikely(!a)) {
+ return s;
+ }
+
+ return __talloc_strlendup_append(s, strlen(s), a, strnlen(a, n));
+}
+
+/*
+ * Appends at the end of the talloc'ed buffer,
+ * not the end of the string.
+ */
+char *talloc_strndup_append_buffer(char *s, const char *a, size_t n)
+{
+ size_t slen;
+
+ if (unlikely(!s)) {
+ return talloc_strdup(NULL, a);
+ }
+
+ if (unlikely(!a)) {
+ return s;
+ }
+
+ slen = talloc_get_size(s);
+ if (likely(slen > 0)) {
+ slen--;
+ }
+
+ return __talloc_strlendup_append(s, slen, a, strnlen(a, n));
+}
+
+#ifndef HAVE_VA_COPY
+#ifdef HAVE___VA_COPY
+#define va_copy(dest, src) __va_copy(dest, src)
+#else
+#define va_copy(dest, src) (dest) = (src)
+#endif
+#endif
+
+char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
+{
+ int len;
+ char *ret;
+ va_list ap2;
+ char c;
+
+ /* this call looks strange, but it makes it work on older solaris boxes */
+ va_copy(ap2, ap);
+ len = vsnprintf(&c, 1, fmt, ap2);
+ va_end(ap2);
+ if (unlikely(len < 0)) {
+ return NULL;
+ }
+
+ ret = (char *)__talloc(t, len+1);
+ if (unlikely(!ret)) return NULL;
+
+ va_copy(ap2, ap);
+ vsnprintf(ret, len+1, fmt, ap2);
+ va_end(ap2);
+
+ _talloc_set_name_const(ret, ret);
+ return ret;
+}
+
+
+/*
+ Perform string formatting, and return a pointer to newly allocated
+ memory holding the result, inside a memory pool.
+ */
+char *talloc_asprintf(const void *t, const char *fmt, ...)
+{
+ va_list ap;
+ char *ret;
+
+ va_start(ap, fmt);
+ ret = talloc_vasprintf(t, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
+ const char *fmt, va_list ap)
+ PRINTF_ATTRIBUTE(3,0);
+
+static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
+ const char *fmt, va_list ap)
+{
+ ssize_t alen;
+ va_list ap2;
+ char c;
+
+ va_copy(ap2, ap);
+ alen = vsnprintf(&c, 1, fmt, ap2);
+ va_end(ap2);
+
+ if (alen <= 0) {
+ /* Either the vsnprintf failed or the format resulted in
+ * no characters being formatted. In the former case, we
+ * ought to return NULL, in the latter we ought to return
+ * the original string. Most current callers of this
+ * function expect it to never return NULL.
+ */
+ return s;
+ }
+
+ s = talloc_realloc(NULL, s, char, slen + alen + 1);
+ if (!s) return NULL;
+
+ va_copy(ap2, ap);
+ vsnprintf(s + slen, alen + 1, fmt, ap2);
+ va_end(ap2);
+
+ _talloc_set_name_const(s, s);
+ return s;
+}
+
+/**
+ * Realloc @p s to append the formatted result of @p fmt and @p ap,
+ * and return @p s, which may have moved. Good for gradually
+ * accumulating output into a string buffer. Appends at the end
+ * of the string.
+ **/
+char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
+{
+ if (unlikely(!s)) {
+ return talloc_vasprintf(NULL, fmt, ap);
+ }
+
+ return __talloc_vaslenprintf_append(s, strlen(s), fmt, ap);
+}
+
+/**
+ * Realloc @p s to append the formatted result of @p fmt and @p ap,
+ * and return @p s, which may have moved. Always appends at the
+ * end of the talloc'ed buffer, not the end of the string.
+ **/
+char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap)
+{
+ size_t slen;
+
+ if (unlikely(!s)) {
+ return talloc_vasprintf(NULL, fmt, ap);
+ }
+
+ slen = talloc_get_size(s);
+ if (likely(slen > 0)) {
+ slen--;
+ }
+
+ return __talloc_vaslenprintf_append(s, slen, fmt, ap);
+}
+
+/*
+ Realloc @p s to append the formatted result of @p fmt and return @p
+ s, which may have moved. Good for gradually accumulating output
+ into a string buffer.
+ */
+char *talloc_asprintf_append(char *s, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ s = talloc_vasprintf_append(s, fmt, ap);
+ va_end(ap);
+ return s;
+}
+
+/*
+ Realloc @p s to append the formatted result of @p fmt and return @p
+ s, which may have moved. Good for gradually accumulating output
+ into a buffer.
+ */
+char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ s = talloc_vasprintf_append_buffer(s, fmt, ap);
+ va_end(ap);
+ return s;
+}
+
+/*
+ alloc an array, checking for integer overflow in the array size
+*/
+void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
+{
+ if (count >= MAX_TALLOC_SIZE/el_size) {
+ return NULL;
+ }
+ return _talloc_named_const(ctx, el_size * count, name);
+}
+
+/*
+ alloc an zero array, checking for integer overflow in the array size
+*/
+void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
+{
+ if (count >= MAX_TALLOC_SIZE/el_size) {
+ return NULL;
+ }
+ return _talloc_zero(ctx, el_size * count, name);
+}
+
+/*
+ realloc an array, checking for integer overflow in the array size
+*/
+void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
+{
+ if (count >= MAX_TALLOC_SIZE/el_size) {
+ return NULL;
+ }
+ return _talloc_realloc(ctx, ptr, el_size * count, name);
+}
+
+/*
+ a function version of talloc_realloc(), so it can be passed as a function pointer
+ to libraries that want a realloc function (a realloc function encapsulates
+ all the basic capabilities of an allocation library, which is why this is useful)
+*/
+void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
+{
+ return _talloc_realloc(context, ptr, size, NULL);
+}
+
+
+static int talloc_autofree_destructor(void *ptr)
+{
+ autofree_context = NULL;
+ return 0;
+}
+
+static void talloc_autofree(void)
+{
+ _talloc_free(autofree_context);
+}
+
+/*
+ return a context which will be auto-freed on exit
+ this is useful for reducing the noise in leak reports
+*/
+void *talloc_autofree_context(void)
+{
+ if (autofree_context == NULL) {
+ autofree_context = _talloc_named_const(NULL, 0, "autofree_context");
+ talloc_set_destructor(autofree_context, talloc_autofree_destructor);
+ atexit(talloc_autofree);
+ }
+ return autofree_context;
+}
+
+size_t talloc_get_size(const void *context)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL)
+ return 0;
+
+ tc = talloc_chunk_from_ptr(context);
+
+ return tc->size;
+}
+
+/*
+ find a parent of this context that has the given name, if any
+*/
+void *talloc_find_parent_byname(const void *context, const char *name)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL) {
+ return NULL;
+ }
+
+ tc = talloc_chunk_from_ptr(context);
+ while (tc) {
+ if (tc->name && strcmp(tc->name, name) == 0) {
+ return TC_PTR_FROM_CHUNK(tc);
+ }
+ while (tc && tc->prev) tc = tc->prev;
+ if (tc) {
+ tc = tc->parent;
+ }
+ }
+ return NULL;
+}
+
+/*
+ show the parentage of a context
+*/
+void talloc_show_parents(const void *context, FILE *file)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL) {
+ fprintf(file, "talloc no parents for NULL\n");
+ return;
+ }
+
+ tc = talloc_chunk_from_ptr(context);
+ fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
+ while (tc) {
+ fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
+ while (tc && tc->prev) tc = tc->prev;
+ if (tc) {
+ tc = tc->parent;
+ }
+ }
+ fflush(file);
+}
+
+/*
+ return 1 if ptr is a parent of context
+*/
+int talloc_is_parent(const void *context, const void *ptr)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL) {
+ return 0;
+ }
+
+ tc = talloc_chunk_from_ptr(context);
+ while (tc) {
+ if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1;
+ while (tc && tc->prev) tc = tc->prev;
+ if (tc) {
+ tc = tc->parent;
+ }
+ }
+ return 0;
+}
diff --git a/source3/lib/talloc/talloc.h b/source3/lib/talloc/talloc.h
new file mode 100644
index 0000000000..5431971655
--- /dev/null
+++ b/source3/lib/talloc/talloc.h
@@ -0,0 +1,183 @@
+#ifndef _TALLOC_H_
+#define _TALLOC_H_
+/*
+ Unix SMB/CIFS implementation.
+ Samba temporary memory allocation functions
+
+ Copyright (C) Andrew Tridgell 2004-2005
+ Copyright (C) Stefan Metzmacher 2006
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+/* this is only needed for compatibility with the old talloc */
+typedef void TALLOC_CTX;
+
+/*
+ this uses a little trick to allow __LINE__ to be stringified
+*/
+#ifndef __location__
+#define __TALLOC_STRING_LINE1__(s) #s
+#define __TALLOC_STRING_LINE2__(s) __TALLOC_STRING_LINE1__(s)
+#define __TALLOC_STRING_LINE3__ __TALLOC_STRING_LINE2__(__LINE__)
+#define __location__ __FILE__ ":" __TALLOC_STRING_LINE3__
+#endif
+
+#ifndef TALLOC_DEPRECATED
+#define TALLOC_DEPRECATED 0
+#endif
+
+#ifndef PRINTF_ATTRIBUTE
+#if (__GNUC__ >= 3)
+/** Use gcc attribute to check printf fns. a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument. Note that some gcc 2.x versions don't handle this
+ * properly **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+#endif
+
+/* try to make talloc_set_destructor() and talloc_steal() type safe,
+ if we have a recent gcc */
+#if (__GNUC__ >= 3)
+#define _TALLOC_TYPEOF(ptr) __typeof__(ptr)
+#define talloc_set_destructor(ptr, function) \
+ do { \
+ int (*_talloc_destructor_fn)(_TALLOC_TYPEOF(ptr)) = (function); \
+ _talloc_set_destructor((ptr), (int (*)(void *))_talloc_destructor_fn); \
+ } while(0)
+/* this extremely strange macro is to avoid some braindamaged warning
+ stupidity in gcc 4.1.x */
+#define talloc_steal(ctx, ptr) ({ _TALLOC_TYPEOF(ptr) __talloc_steal_ret = (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr)); __talloc_steal_ret; })
+#else
+#define talloc_set_destructor(ptr, function) \
+ _talloc_set_destructor((ptr), (int (*)(void *))(function))
+#define _TALLOC_TYPEOF(ptr) void *
+#define talloc_steal(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr))
+#endif
+
+#define talloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_reference((ctx),(ptr))
+#define talloc_move(ctx, ptr) (_TALLOC_TYPEOF(*(ptr)))_talloc_move((ctx),(void *)(ptr))
+
+/* useful macros for creating type checked pointers */
+#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
+#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__)
+#define talloc_ptrtype(ctx, ptr) (_TALLOC_TYPEOF(ptr))talloc_size(ctx, sizeof(*(ptr)))
+
+#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__)
+
+#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
+#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__)
+
+#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type)
+#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
+#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__)
+#define talloc_array_ptrtype(ctx, ptr, count) (_TALLOC_TYPEOF(ptr))talloc_array_size(ctx, sizeof(*(ptr)), count)
+
+#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type)
+#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__)
+
+#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__)
+
+#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type)
+#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type)
+
+#define talloc_find_parent_bytype(ptr, type) (type *)talloc_find_parent_byname(ptr, #type)
+
+#if TALLOC_DEPRECATED
+#define talloc_zero_p(ctx, type) talloc_zero(ctx, type)
+#define talloc_p(ctx, type) talloc(ctx, type)
+#define talloc_array_p(ctx, type, count) talloc_array(ctx, type, count)
+#define talloc_realloc_p(ctx, p, type, count) talloc_realloc(ctx, p, type, count)
+#define talloc_destroy(ctx) talloc_free(ctx)
+#define talloc_append_string(c, s, a) (s?talloc_strdup_append(s,a):talloc_strdup(c, a))
+#endif
+
+/* The following definitions come from talloc.c */
+void *_talloc(const void *context, size_t size);
+void *talloc_pool(const void *context, size_t size);
+void _talloc_set_destructor(const void *ptr, int (*destructor)(void *));
+int talloc_increase_ref_count(const void *ptr);
+size_t talloc_reference_count(const void *ptr);
+void *_talloc_reference(const void *context, const void *ptr);
+int talloc_unlink(const void *context, void *ptr);
+const char *talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+void talloc_set_name_const(const void *ptr, const char *name);
+void *talloc_named(const void *context, size_t size,
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+void *talloc_named_const(const void *context, size_t size, const char *name);
+const char *talloc_get_name(const void *ptr);
+void *talloc_check_name(const void *ptr, const char *name);
+void *talloc_parent(const void *ptr);
+const char *talloc_parent_name(const void *ptr);
+void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
+int talloc_free(void *ptr);
+void talloc_free_children(void *ptr);
+void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name);
+void *_talloc_steal(const void *new_ctx, const void *ptr);
+void *_talloc_move(const void *new_ctx, const void *pptr);
+size_t talloc_total_size(const void *ptr);
+size_t talloc_total_blocks(const void *ptr);
+void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
+ void (*callback)(const void *ptr,
+ int depth, int max_depth,
+ int is_ref,
+ void *private_data),
+ void *private_data);
+void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f);
+void talloc_report_full(const void *ptr, FILE *f);
+void talloc_report(const void *ptr, FILE *f);
+void talloc_enable_null_tracking(void);
+void talloc_disable_null_tracking(void);
+void talloc_enable_leak_report(void);
+void talloc_enable_leak_report_full(void);
+void *_talloc_zero(const void *ctx, size_t size, const char *name);
+void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name);
+void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name);
+void *talloc_realloc_fn(const void *context, void *ptr, size_t size);
+void *talloc_autofree_context(void);
+size_t talloc_get_size(const void *ctx);
+void *talloc_find_parent_byname(const void *ctx, const char *name);
+void talloc_show_parents(const void *context, FILE *file);
+int talloc_is_parent(const void *context, const void *ptr);
+
+char *talloc_strdup(const void *t, const char *p);
+char *talloc_strdup_append(char *s, const char *a);
+char *talloc_strdup_append_buffer(char *s, const char *a);
+
+char *talloc_strndup(const void *t, const char *p, size_t n);
+char *talloc_strndup_append(char *s, const char *a, size_t n);
+char *talloc_strndup_append_buffer(char *s, const char *a, size_t n);
+
+char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+char *talloc_asprintf_append(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+#endif
diff --git a/source3/lib/talloc/talloc.i b/source3/lib/talloc/talloc.i
new file mode 100644
index 0000000000..a9afb97ed7
--- /dev/null
+++ b/source3/lib/talloc/talloc.i
@@ -0,0 +1,31 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Don't expose talloc contexts in Python code. Python does reference
+ counting for us, so just create a new top-level talloc context.
+ */
+%typemap(in, numinputs=0, noblock=1) TALLOC_CTX * {
+ $1 = NULL;
+}
+
+%define %talloctype(TYPE)
+%nodefaultctor TYPE;
+%extend TYPE {
+ ~TYPE() { talloc_free($self); }
+}
+%enddef
diff --git a/source3/lib/talloc/talloc.mk b/source3/lib/talloc/talloc.mk
new file mode 100644
index 0000000000..e1fe88c84b
--- /dev/null
+++ b/source3/lib/talloc/talloc.mk
@@ -0,0 +1,37 @@
+TALLOC_OBJ = $(tallocdir)/talloc.o
+
+TALLOC_SOLIB = libtalloc.$(SHLIBEXT).$(PACKAGE_VERSION)
+TALLOC_SONAME = libtalloc.$(SHLIBEXT).1
+
+all:: libtalloc.a $(TALLOC_SOLIB) testsuite
+
+testsuite:: $(LIBOBJ) testsuite.o
+ $(CC) $(CFLAGS) -o testsuite testsuite.o $(LIBOBJ) $(LIBS)
+
+libtalloc.a: $(LIBOBJ)
+ ar -rv $@ $(LIBOBJ)
+ @-ranlib $@
+
+install:: all
+ ${INSTALLCMD} -d $(DESTDIR)$(libdir)
+ ${INSTALLCMD} -d $(DESTDIR)$(libdir)/pkgconfig
+ ${INSTALLCMD} -m 755 libtalloc.a $(DESTDIR)$(libdir)
+ ${INSTALLCMD} -m 755 $(TALLOC_SOLIB) $(DESTDIR)$(libdir)
+ ${INSTALLCMD} -d $(DESTDIR)${includedir}
+ ${INSTALLCMD} -m 644 $(srcdir)/talloc.h $(DESTDIR)$(includedir)
+ ${INSTALLCMD} -m 644 talloc.pc $(DESTDIR)$(libdir)/pkgconfig
+ if [ -f talloc.3 ];then ${INSTALLCMD} -d $(DESTDIR)$(mandir)/man3; fi
+ if [ -f talloc.3 ];then ${INSTALLCMD} -m 644 talloc.3 $(DESTDIR)$(mandir)/man3; fi
+ which swig >/dev/null 2>&1 && ${INSTALLCMD} -d $(DESTDIR)`swig -swiglib` || true
+ which swig >/dev/null 2>&1 && ${INSTALLCMD} -m 644 talloc.i $(DESTDIR)`swig -swiglib` || true
+
+doc:: talloc.3 talloc.3.html
+
+clean::
+ rm -f *~ $(LIBOBJ) $(TALLOC_SOLIB) libtalloc.a testsuite testsuite.o *.gc?? talloc.3 talloc.3.html
+
+test:: testsuite
+ ./testsuite
+
+gcov::
+ gcov talloc.c
diff --git a/source3/lib/talloc/talloc.pc.in b/source3/lib/talloc/talloc.pc.in
new file mode 100644
index 0000000000..459cce70b1
--- /dev/null
+++ b/source3/lib/talloc/talloc.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: talloc
+Description: A hierarchical pool based memory system with destructors
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -ltalloc
+Cflags: -I${includedir}
+URL: http://talloc.samba.org/
diff --git a/source3/lib/talloc/talloc_guide.txt b/source3/lib/talloc/talloc_guide.txt
new file mode 100644
index 0000000000..18663b370d
--- /dev/null
+++ b/source3/lib/talloc/talloc_guide.txt
@@ -0,0 +1,685 @@
+Using talloc in Samba4
+----------------------
+
+Andrew Tridgell
+September 2004
+
+The most current version of this document is available at
+ http://samba.org/ftp/unpacked/samba4/source/lib/talloc/talloc_guide.txt
+
+If you are used to the "old" talloc from Samba3 before 3.0.20 then please read
+this carefully, as talloc has changed a lot. With 3.0.20 (or 3.0.14?) the
+Samba4 talloc has been ported back to Samba3, so this guide applies to both.
+
+The new talloc is a hierarchical, reference counted memory pool system
+with destructors. Quite a mouthful really, but not too bad once you
+get used to it.
+
+Perhaps the biggest change from Samba3 is that there is no distinction
+between a "talloc context" and a "talloc pointer". Any pointer
+returned from talloc() is itself a valid talloc context. This means
+you can do this:
+
+ struct foo *X = talloc(mem_ctx, struct foo);
+ X->name = talloc_strdup(X, "foo");
+
+and the pointer X->name would be a "child" of the talloc context "X"
+which is itself a child of mem_ctx. So if you do talloc_free(mem_ctx)
+then it is all destroyed, whereas if you do talloc_free(X) then just X
+and X->name are destroyed, and if you do talloc_free(X->name) then
+just the name element of X is destroyed.
+
+If you think about this, then what this effectively gives you is an
+n-ary tree, where you can free any part of the tree with
+talloc_free().
+
+If you find this confusing, then I suggest you run the testsuite to
+watch talloc in action. You may also like to add your own tests to
+testsuite.c to clarify how some particular situation is handled.
+
+
+Performance
+-----------
+
+All the additional features of talloc() over malloc() do come at a
+price. We have a simple performance test in Samba4 that measures
+talloc() versus malloc() performance, and it seems that talloc() is
+about 4% slower than malloc() on my x86 Debian Linux box. For Samba,
+the great reduction in code complexity that we get by using talloc
+makes this worthwhile, especially as the total overhead of
+talloc/malloc in Samba is already quite small.
+
+
+talloc API
+----------
+
+The following is a complete guide to the talloc API. Read it all at
+least twice.
+
+Multi-threading
+---------------
+
+talloc itself does not deal with threads. It is thread-safe (assuming
+the underlying "malloc" is), as long as each thread uses different
+memory contexts.
+If two threads uses the same context then they need to synchronize in
+order to be safe. In particular:
+- when using talloc_enable_leak_report(), giving directly NULL as a
+parent context implicitly refers to a hidden "null context" global
+variable, so this should not be used in a multi-threaded environment
+without proper synchronization ;
+- the context returned by talloc_autofree_context() is also global so
+shouldn't be used by several threads simultaneously without
+synchronization.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(type *)talloc(const void *context, type);
+
+The talloc() macro is the core of the talloc library. It takes a
+memory context and a type, and returns a pointer to a new area of
+memory of the given type.
+
+The returned pointer is itself a talloc context, so you can use it as
+the context argument to more calls to talloc if you wish.
+
+The returned pointer is a "child" of the supplied context. This means
+that if you talloc_free() the context then the new child disappears as
+well. Alternatively you can free just the child.
+
+The context argument to talloc() can be NULL, in which case a new top
+level context is created.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_size(const void *context, size_t size);
+
+The function talloc_size() should be used when you don't have a
+convenient type to pass to talloc(). Unlike talloc(), it is not type
+safe (as it returns a void *), so you are on your own for type checking.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(typeof(ptr)) talloc_ptrtype(const void *ctx, ptr);
+
+The talloc_ptrtype() macro should be used when you have a pointer and
+want to allocate memory to point at with this pointer. When compiling
+with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size()
+and talloc_get_name() will return the current location in the source file.
+and not the type.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+int talloc_free(void *ptr);
+
+The talloc_free() function frees a piece of talloc memory, and all its
+children. You can call talloc_free() on any pointer returned by
+talloc().
+
+The return value of talloc_free() indicates success or failure, with 0
+returned for success and -1 for failure. The only possible failure
+condition is if the pointer had a destructor attached to it and the
+destructor returned -1. See talloc_set_destructor() for details on
+destructors.
+
+If this pointer has an additional parent when talloc_free() is called
+then the memory is not actually released, but instead the most
+recently established parent is destroyed. See talloc_reference() for
+details on establishing additional parents.
+
+For more control on which parent is removed, see talloc_unlink()
+
+talloc_free() operates recursively on its children.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+int talloc_free_children(void *ptr);
+
+The talloc_free_children() walks along the list of all children of a
+talloc context and talloc_free()s only the children, not the context
+itself.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_reference(const void *context, const void *ptr);
+
+The talloc_reference() function makes "context" an additional parent
+of "ptr".
+
+The return value of talloc_reference() is always the original pointer
+"ptr", unless talloc ran out of memory in creating the reference in
+which case it will return NULL (each additional reference consumes
+around 48 bytes of memory on intel x86 platforms).
+
+If "ptr" is NULL, then the function is a no-op, and simply returns NULL.
+
+After creating a reference you can free it in one of the following
+ways:
+
+ - you can talloc_free() any parent of the original pointer. That
+ will reduce the number of parents of this pointer by 1, and will
+ cause this pointer to be freed if it runs out of parents.
+
+ - you can talloc_free() the pointer itself. That will destroy the
+ most recently established parent to the pointer and leave the
+ pointer as a child of its current parent.
+
+For more control on which parent to remove, see talloc_unlink()
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+int talloc_unlink(const void *context, const void *ptr);
+
+The talloc_unlink() function removes a specific parent from ptr. The
+context passed must either be a context used in talloc_reference()
+with this pointer, or must be a direct parent of ptr.
+
+Note that if the parent has already been removed using talloc_free()
+then this function will fail and will return -1. Likewise, if "ptr"
+is NULL, then the function will make no modifications and return -1.
+
+Usually you can just use talloc_free() instead of talloc_unlink(), but
+sometimes it is useful to have the additional control on which parent
+is removed.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_set_destructor(const void *ptr, int (*destructor)(void *));
+
+The function talloc_set_destructor() sets the "destructor" for the
+pointer "ptr". A destructor is a function that is called when the
+memory used by a pointer is about to be released. The destructor
+receives the pointer as an argument, and should return 0 for success
+and -1 for failure.
+
+The destructor can do anything it wants to, including freeing other
+pieces of memory. A common use for destructors is to clean up
+operating system resources (such as open file descriptors) contained
+in the structure the destructor is placed on.
+
+You can only place one destructor on a pointer. If you need more than
+one destructor then you can create a zero-length child of the pointer
+and place an additional destructor on that.
+
+To remove a destructor call talloc_set_destructor() with NULL for the
+destructor.
+
+If your destructor attempts to talloc_free() the pointer that it is
+the destructor for then talloc_free() will return -1 and the free will
+be ignored. This would be a pointless operation anyway, as the
+destructor is only called when the memory is just about to go away.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+int talloc_increase_ref_count(const void *ptr);
+
+The talloc_increase_ref_count(ptr) function is exactly equivalent to:
+
+ talloc_reference(NULL, ptr);
+
+You can use either syntax, depending on which you think is clearer in
+your code.
+
+It returns 0 on success and -1 on failure.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+size_t talloc_reference_count(const void *ptr);
+
+Return the number of references to the pointer.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_set_name(const void *ptr, const char *fmt, ...);
+
+Each talloc pointer has a "name". The name is used principally for
+debugging purposes, although it is also possible to set and get the
+name on a pointer in as a way of "marking" pointers in your code.
+
+The main use for names on pointer is for "talloc reports". See
+talloc_report() and talloc_report_full() for details. Also see
+talloc_enable_leak_report() and talloc_enable_leak_report_full().
+
+The talloc_set_name() function allocates memory as a child of the
+pointer. It is logically equivalent to:
+ talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...));
+
+Note that multiple calls to talloc_set_name() will allocate more
+memory without releasing the name. All of the memory is released when
+the ptr is freed using talloc_free().
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_set_name_const(const void *ptr, const char *name);
+
+The function talloc_set_name_const() is just like talloc_set_name(),
+but it takes a string constant, and is much faster. It is extensively
+used by the "auto naming" macros, such as talloc_p().
+
+This function does not allocate any memory. It just copies the
+supplied pointer into the internal representation of the talloc
+ptr. This means you must not pass a name pointer to memory that will
+disappear before the ptr is freed with talloc_free().
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_named(const void *context, size_t size, const char *fmt, ...);
+
+The talloc_named() function creates a named talloc pointer. It is
+equivalent to:
+
+ ptr = talloc_size(context, size);
+ talloc_set_name(ptr, fmt, ....);
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_named_const(const void *context, size_t size, const char *name);
+
+This is equivalent to:
+
+ ptr = talloc_size(context, size);
+ talloc_set_name_const(ptr, name);
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+const char *talloc_get_name(const void *ptr);
+
+This returns the current name for the given talloc pointer. See
+talloc_set_name() for details.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_init(const char *fmt, ...);
+
+This function creates a zero length named talloc context as a top
+level context. It is equivalent to:
+
+ talloc_named(NULL, 0, fmt, ...);
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_new(void *ctx);
+
+This is a utility macro that creates a new memory context hanging
+off an exiting context, automatically naming it "talloc_new: __location__"
+where __location__ is the source line it is called from. It is
+particularly useful for creating a new temporary working context.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(type *)talloc_realloc(const void *context, void *ptr, type, count);
+
+The talloc_realloc() macro changes the size of a talloc
+pointer. The "count" argument is the number of elements of type "type"
+that you want the resulting pointer to hold.
+
+talloc_realloc() has the following equivalences:
+
+ talloc_realloc(context, NULL, type, 1) ==> talloc(context, type);
+ talloc_realloc(context, NULL, type, N) ==> talloc_array(context, type, N);
+ talloc_realloc(context, ptr, type, 0) ==> talloc_free(ptr);
+
+The "context" argument is only used if "ptr" is NULL, otherwise it is
+ignored.
+
+talloc_realloc() returns the new pointer, or NULL on failure. The call
+will fail either due to a lack of memory, or because the pointer has
+more than one parent (see talloc_reference()).
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_realloc_size(const void *context, void *ptr, size_t size);
+
+the talloc_realloc_size() function is useful when the type is not
+known so the typesafe talloc_realloc() cannot be used.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_steal(const void *new_ctx, const void *ptr);
+
+The talloc_steal() function changes the parent context of a talloc
+pointer. It is typically used when the context that the pointer is
+currently a child of is going to be freed and you wish to keep the
+memory for a longer time.
+
+The talloc_steal() function returns the pointer that you pass it. It
+does not have any failure modes.
+
+NOTE: It is possible to produce loops in the parent/child relationship
+if you are not careful with talloc_steal(). No guarantees are provided
+as to your sanity or the safety of your data if you do this.
+
+talloc_steal (new_ctx, NULL) will return NULL with no sideeffects.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+size_t talloc_total_size(const void *ptr);
+
+The talloc_total_size() function returns the total size in bytes used
+by this pointer and all child pointers. Mostly useful for debugging.
+
+Passing NULL is allowed, but it will only give a meaningful result if
+talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+been called.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+size_t talloc_total_blocks(const void *ptr);
+
+The talloc_total_blocks() function returns the total memory block
+count used by this pointer and all child pointers. Mostly useful for
+debugging.
+
+Passing NULL is allowed, but it will only give a meaningful result if
+talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+been called.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
+ void (*callback)(const void *ptr,
+ int depth, int max_depth,
+ int is_ref,
+ void *priv),
+ void *priv);
+
+This provides a more flexible reports than talloc_report(). It
+will recursively call the callback for the entire tree of memory
+referenced by the pointer. References in the tree are passed with
+is_ref = 1 and the pointer that is referenced.
+
+You can pass NULL for the pointer, in which case a report is
+printed for the top level memory context, but only if
+talloc_enable_leak_report() or talloc_enable_leak_report_full()
+has been called.
+
+The recursion is stopped when depth >= max_depth.
+max_depth = -1 means only stop at leaf nodes.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f);
+
+This provides a more flexible reports than talloc_report(). It
+will let you specify the depth and max_depth.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_report(const void *ptr, FILE *f);
+
+The talloc_report() function prints a summary report of all memory
+used by ptr. One line of report is printed for each immediate child of
+ptr, showing the total memory and number of blocks used by that child.
+
+You can pass NULL for the pointer, in which case a report is printed
+for the top level memory context, but only if
+talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+been called.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_report_full(const void *ptr, FILE *f);
+
+This provides a more detailed report than talloc_report(). It will
+recursively print the ensire tree of memory referenced by the
+pointer. References in the tree are shown by giving the name of the
+pointer that is referenced.
+
+You can pass NULL for the pointer, in which case a report is printed
+for the top level memory context, but only if
+talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+been called.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_enable_leak_report(void);
+
+This enables calling of talloc_report(NULL, stderr) when the program
+exits. In Samba4 this is enabled by using the --leak-report command
+line option.
+
+For it to be useful, this function must be called before any other
+talloc function as it establishes a "null context" that acts as the
+top of the tree. If you don't call this function first then passing
+NULL to talloc_report() or talloc_report_full() won't give you the
+full tree printout.
+
+Here is a typical talloc report:
+
+talloc report on 'null_context' (total 267 bytes in 15 blocks)
+ libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+ libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+ iconv(UTF8,CP850) contains 42 bytes in 2 blocks
+ libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+ iconv(CP850,UTF8) contains 42 bytes in 2 blocks
+ iconv(UTF8,UTF-16LE) contains 45 bytes in 2 blocks
+ iconv(UTF-16LE,UTF8) contains 45 bytes in 2 blocks
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_enable_leak_report_full(void);
+
+This enables calling of talloc_report_full(NULL, stderr) when the
+program exits. In Samba4 this is enabled by using the
+--leak-report-full command line option.
+
+For it to be useful, this function must be called before any other
+talloc function as it establishes a "null context" that acts as the
+top of the tree. If you don't call this function first then passing
+NULL to talloc_report() or talloc_report_full() won't give you the
+full tree printout.
+
+Here is a typical full report:
+
+full talloc report on 'root' (total 18 bytes in 8 blocks)
+ p1 contains 18 bytes in 7 blocks (ref 0)
+ r1 contains 13 bytes in 2 blocks (ref 0)
+ reference to: p2
+ p2 contains 1 bytes in 1 blocks (ref 1)
+ x3 contains 1 bytes in 1 blocks (ref 0)
+ x2 contains 1 bytes in 1 blocks (ref 0)
+ x1 contains 1 bytes in 1 blocks (ref 0)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_enable_null_tracking(void);
+
+This enables tracking of the NULL memory context without enabling leak
+reporting on exit. Useful for when you want to do your own leak
+reporting call via talloc_report_null_full();
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_disable_null_tracking(void);
+
+This disables tracking of the NULL memory context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(type *)talloc_zero(const void *ctx, type);
+
+The talloc_zero() macro is equivalent to:
+
+ ptr = talloc(ctx, type);
+ if (ptr) memset(ptr, 0, sizeof(type));
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_zero_size(const void *ctx, size_t size)
+
+The talloc_zero_size() function is useful when you don't have a known type
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_memdup(const void *ctx, const void *p, size_t size);
+
+The talloc_memdup() function is equivalent to:
+
+ ptr = talloc_size(ctx, size);
+ if (ptr) memcpy(ptr, p, size);
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_strdup(const void *ctx, const char *p);
+
+The talloc_strdup() function is equivalent to:
+
+ ptr = talloc_size(ctx, strlen(p)+1);
+ if (ptr) memcpy(ptr, p, strlen(p)+1);
+
+This functions sets the name of the new pointer to the passed
+string. This is equivalent to:
+ talloc_set_name_const(ptr, ptr)
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_strndup(const void *t, const char *p, size_t n);
+
+The talloc_strndup() function is the talloc equivalent of the C
+library function strndup()
+
+This functions sets the name of the new pointer to the passed
+string. This is equivalent to:
+ talloc_set_name_const(ptr, ptr)
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_append_string(const void *t, char *orig, const char *append);
+
+The talloc_append_string() function appends the given formatted
+string to the given string.
+
+This function sets the name of the new pointer to the new
+string. This is equivalent to:
+ talloc_set_name_const(ptr, ptr)
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_vasprintf(const void *t, const char *fmt, va_list ap);
+
+The talloc_vasprintf() function is the talloc equivalent of the C
+library function vasprintf()
+
+This functions sets the name of the new pointer to the new
+string. This is equivalent to:
+ talloc_set_name_const(ptr, ptr)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_asprintf(const void *t, const char *fmt, ...);
+
+The talloc_asprintf() function is the talloc equivalent of the C
+library function asprintf()
+
+This functions sets the name of the new pointer to the new
+string. This is equivalent to:
+ talloc_set_name_const(ptr, ptr)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_asprintf_append(char *s, const char *fmt, ...);
+
+The talloc_asprintf_append() function appends the given formatted
+string to the given string.
+Use this varient when the string in the current talloc buffer may
+have been truncated in length.
+
+This functions sets the name of the new pointer to the new
+string. This is equivalent to:
+ talloc_set_name_const(ptr, ptr)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...);
+
+The talloc_asprintf_append() function appends the given formatted
+string to the end of the currently allocated talloc buffer.
+Use this varient when the string in the current talloc buffer has
+not been changed.
+
+This functions sets the name of the new pointer to the new
+string. This is equivalent to:
+ talloc_set_name_const(ptr, ptr)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+((type *)talloc_array(const void *ctx, type, uint_t count);
+
+The talloc_array() macro is equivalent to:
+
+ (type *)talloc_size(ctx, sizeof(type) * count);
+
+except that it provides integer overflow protection for the multiply,
+returning NULL if the multiply overflows.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_array_size(const void *ctx, size_t size, uint_t count);
+
+The talloc_array_size() function is useful when the type is not
+known. It operates in the same way as talloc_array(), but takes a size
+instead of a type.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(typeof(ptr)) talloc_array_ptrtype(const void *ctx, ptr, uint_t count);
+
+The talloc_ptrtype() macro should be used when you have a pointer to an array
+and want to allocate memory of an array to point at with this pointer. When compiling
+with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_array_size()
+and talloc_get_name() will return the current location in the source file.
+and not the type.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_realloc_fn(const void *ctx, void *ptr, size_t size);
+
+This is a non-macro version of talloc_realloc(), which is useful
+as libraries sometimes want a ralloc function pointer. A realloc()
+implementation encapsulates the functionality of malloc(), free() and
+realloc() in one call, which is why it is useful to be able to pass
+around a single function pointer.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_autofree_context(void);
+
+This is a handy utility function that returns a talloc context
+which will be automatically freed on program exit. This can be used
+to reduce the noise in memory leak reports.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_check_name(const void *ptr, const char *name);
+
+This function checks if a pointer has the specified name. If it does
+then the pointer is returned. It it doesn't then NULL is returned.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(type *)talloc_get_type(const void *ptr, type);
+
+This macro allows you to do type checking on talloc pointers. It is
+particularly useful for void* private pointers. It is equivalent to
+this:
+
+ (type *)talloc_check_name(ptr, #type)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+talloc_set_type(const void *ptr, type);
+
+This macro allows you to force the name of a pointer to be a
+particular type. This can be used in conjunction with
+talloc_get_type() to do type checking on void* pointers.
+
+It is equivalent to this:
+ talloc_set_name_const(ptr, #type)
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+talloc_get_size(const void *ctx);
+
+This function lets you know the amount of memory alloced so far by
+this context. It does NOT account for subcontext memory.
+This can be used to calculate the size of an array.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_find_parent_byname(const void *ctx, const char *name);
+
+Find a parent memory context of the current context that has the given
+name. This can be very useful in complex programs where it may be
+difficult to pass all information down to the level you need, but you
+know the structure you want is a parent of another context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(type *)talloc_find_parent_bytype(ctx, type);
+
+Like talloc_find_parent_byname() but takes a type, making it typesafe.
+
diff --git a/source3/lib/talloc/testsuite.c b/source3/lib/talloc/testsuite.c
new file mode 100644
index 0000000000..3f06eee566
--- /dev/null
+++ b/source3/lib/talloc/testsuite.c
@@ -0,0 +1,1152 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ local testing of talloc routines.
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/time.h"
+#include "talloc.h"
+
+static struct timeval timeval_current(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv;
+}
+
+static double timeval_elapsed(struct timeval *tv)
+{
+ struct timeval tv2 = timeval_current();
+ return (tv2.tv_sec - tv->tv_sec) +
+ (tv2.tv_usec - tv->tv_usec)*1.0e-6;
+}
+
+#define torture_assert(test, expr, str) if (!(expr)) { \
+ printf("failure: %s [\n%s: Expression %s failed: %s\n]\n", \
+ test, __location__, #expr, str); \
+ return false; \
+}
+
+#define torture_assert_str_equal(test, arg1, arg2, desc) \
+ if (arg1 == NULL && arg2 == NULL) { \
+ } else if (strcmp(arg1, arg2)) { \
+ printf("failure: %s [\n%s: Expected %s, got %s: %s\n]\n", \
+ test, __location__, arg1, arg2, desc); \
+ return false; \
+ }
+
+#if _SAMBA_BUILD_==3
+#ifdef malloc
+#undef malloc
+#endif
+#ifdef strdup
+#undef strdup
+#endif
+#endif
+
+#define CHECK_SIZE(test, ptr, tsize) do { \
+ if (talloc_total_size(ptr) != (tsize)) { \
+ printf("failed: %s [\nwrong '%s' tree size: got %u expected %u\n]\n", \
+ test, #ptr, \
+ (unsigned)talloc_total_size(ptr), \
+ (unsigned)tsize); \
+ talloc_report_full(ptr, stdout); \
+ return false; \
+ } \
+} while (0)
+
+#define CHECK_BLOCKS(test, ptr, tblocks) do { \
+ if (talloc_total_blocks(ptr) != (tblocks)) { \
+ printf("failed: %s [\nwrong '%s' tree blocks: got %u expected %u\n]\n", \
+ test, #ptr, \
+ (unsigned)talloc_total_blocks(ptr), \
+ (unsigned)tblocks); \
+ talloc_report_full(ptr, stdout); \
+ return false; \
+ } \
+} while (0)
+
+#define CHECK_PARENT(test, ptr, parent) do { \
+ if (talloc_parent(ptr) != (parent)) { \
+ printf("failed: %s [\n'%s' has wrong parent: got %p expected %p\n]\n", \
+ test, #ptr, \
+ talloc_parent(ptr), \
+ (parent)); \
+ talloc_report_full(ptr, stdout); \
+ talloc_report_full(parent, stdout); \
+ talloc_report_full(NULL, stdout); \
+ return false; \
+ } \
+} while (0)
+
+
+/*
+ test references
+*/
+static bool test_ref1(void)
+{
+ void *root, *p1, *p2, *ref, *r1;
+
+ printf("test: ref1\n# SINGLE REFERENCE FREE\n");
+
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "p1");
+ p2 = talloc_named_const(p1, 1, "p2");
+ talloc_named_const(p1, 1, "x1");
+ talloc_named_const(p1, 2, "x2");
+ talloc_named_const(p1, 3, "x3");
+
+ r1 = talloc_named_const(root, 1, "r1");
+ ref = talloc_reference(r1, p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref1", p1, 5);
+ CHECK_BLOCKS("ref1", p2, 1);
+ CHECK_BLOCKS("ref1", r1, 2);
+
+ fprintf(stderr, "Freeing p2\n");
+ talloc_free(p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref1", p1, 5);
+ CHECK_BLOCKS("ref1", p2, 1);
+ CHECK_BLOCKS("ref1", r1, 1);
+
+ fprintf(stderr, "Freeing p1\n");
+ talloc_free(p1);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref1", r1, 1);
+
+ fprintf(stderr, "Freeing r1\n");
+ talloc_free(r1);
+ talloc_report_full(NULL, stderr);
+
+ fprintf(stderr, "Testing NULL\n");
+ if (talloc_reference(root, NULL)) {
+ return false;
+ }
+
+ CHECK_BLOCKS("ref1", root, 1);
+
+ CHECK_SIZE("ref1", root, 0);
+
+ talloc_free(root);
+ printf("success: ref1\n");
+ return true;
+}
+
+/*
+ test references
+*/
+static bool test_ref2(void)
+{
+ void *root, *p1, *p2, *ref, *r1;
+
+ printf("test: ref2\n# DOUBLE REFERENCE FREE\n");
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "p1");
+ talloc_named_const(p1, 1, "x1");
+ talloc_named_const(p1, 1, "x2");
+ talloc_named_const(p1, 1, "x3");
+ p2 = talloc_named_const(p1, 1, "p2");
+
+ r1 = talloc_named_const(root, 1, "r1");
+ ref = talloc_reference(r1, p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref2", p1, 5);
+ CHECK_BLOCKS("ref2", p2, 1);
+ CHECK_BLOCKS("ref2", r1, 2);
+
+ fprintf(stderr, "Freeing ref\n");
+ talloc_free(ref);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref2", p1, 5);
+ CHECK_BLOCKS("ref2", p2, 1);
+ CHECK_BLOCKS("ref2", r1, 1);
+
+ fprintf(stderr, "Freeing p2\n");
+ talloc_free(p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref2", p1, 4);
+ CHECK_BLOCKS("ref2", r1, 1);
+
+ fprintf(stderr, "Freeing p1\n");
+ talloc_free(p1);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref2", r1, 1);
+
+ fprintf(stderr, "Freeing r1\n");
+ talloc_free(r1);
+ talloc_report_full(root, stderr);
+
+ CHECK_SIZE("ref2", root, 0);
+
+ talloc_free(root);
+ printf("success: ref2\n");
+ return true;
+}
+
+/*
+ test references
+*/
+static bool test_ref3(void)
+{
+ void *root, *p1, *p2, *ref, *r1;
+
+ printf("test: ref3\n# PARENT REFERENCE FREE\n");
+
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "p1");
+ p2 = talloc_named_const(root, 1, "p2");
+ r1 = talloc_named_const(p1, 1, "r1");
+ ref = talloc_reference(p2, r1);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref3", p1, 2);
+ CHECK_BLOCKS("ref3", p2, 2);
+ CHECK_BLOCKS("ref3", r1, 1);
+
+ fprintf(stderr, "Freeing p1\n");
+ talloc_free(p1);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref3", p2, 2);
+ CHECK_BLOCKS("ref3", r1, 1);
+
+ fprintf(stderr, "Freeing p2\n");
+ talloc_free(p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_SIZE("ref3", root, 0);
+
+ talloc_free(root);
+
+ printf("success: ref3\n");
+ return true;
+}
+
+/*
+ test references
+*/
+static bool test_ref4(void)
+{
+ void *root, *p1, *p2, *ref, *r1;
+
+ printf("test: ref4\n# REFERRER REFERENCE FREE\n");
+
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "p1");
+ talloc_named_const(p1, 1, "x1");
+ talloc_named_const(p1, 1, "x2");
+ talloc_named_const(p1, 1, "x3");
+ p2 = talloc_named_const(p1, 1, "p2");
+
+ r1 = talloc_named_const(root, 1, "r1");
+ ref = talloc_reference(r1, p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref4", p1, 5);
+ CHECK_BLOCKS("ref4", p2, 1);
+ CHECK_BLOCKS("ref4", r1, 2);
+
+ fprintf(stderr, "Freeing r1\n");
+ talloc_free(r1);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref4", p1, 5);
+ CHECK_BLOCKS("ref4", p2, 1);
+
+ fprintf(stderr, "Freeing p2\n");
+ talloc_free(p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref4", p1, 4);
+
+ fprintf(stderr, "Freeing p1\n");
+ talloc_free(p1);
+ talloc_report_full(root, stderr);
+
+ CHECK_SIZE("ref4", root, 0);
+
+ talloc_free(root);
+
+ printf("success: ref4\n");
+ return true;
+}
+
+
+/*
+ test references
+*/
+static bool test_unlink1(void)
+{
+ void *root, *p1, *p2, *ref, *r1;
+
+ printf("test: unlink\n# UNLINK\n");
+
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "p1");
+ talloc_named_const(p1, 1, "x1");
+ talloc_named_const(p1, 1, "x2");
+ talloc_named_const(p1, 1, "x3");
+ p2 = talloc_named_const(p1, 1, "p2");
+
+ r1 = talloc_named_const(p1, 1, "r1");
+ ref = talloc_reference(r1, p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("unlink", p1, 7);
+ CHECK_BLOCKS("unlink", p2, 1);
+ CHECK_BLOCKS("unlink", r1, 2);
+
+ fprintf(stderr, "Unreferencing r1\n");
+ talloc_unlink(r1, p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("unlink", p1, 6);
+ CHECK_BLOCKS("unlink", p2, 1);
+ CHECK_BLOCKS("unlink", r1, 1);
+
+ fprintf(stderr, "Freeing p1\n");
+ talloc_free(p1);
+ talloc_report_full(root, stderr);
+
+ CHECK_SIZE("unlink", root, 0);
+
+ talloc_free(root);
+
+ printf("success: unlink\n");
+ return true;
+}
+
+static int fail_destructor(void *ptr)
+{
+ return -1;
+}
+
+/*
+ miscellaneous tests to try to get a higher test coverage percentage
+*/
+static bool test_misc(void)
+{
+ void *root, *p1;
+ char *p2;
+ double *d;
+ const char *name;
+
+ printf("test: misc\n# MISCELLANEOUS\n");
+
+ root = talloc_new(NULL);
+
+ p1 = talloc_size(root, 0x7fffffff);
+ torture_assert("misc", !p1, "failed: large talloc allowed\n");
+
+ p1 = talloc_strdup(root, "foo");
+ talloc_increase_ref_count(p1);
+ talloc_increase_ref_count(p1);
+ talloc_increase_ref_count(p1);
+ CHECK_BLOCKS("misc", p1, 1);
+ CHECK_BLOCKS("misc", root, 2);
+ talloc_free(p1);
+ CHECK_BLOCKS("misc", p1, 1);
+ CHECK_BLOCKS("misc", root, 2);
+ talloc_unlink(NULL, p1);
+ CHECK_BLOCKS("misc", p1, 1);
+ CHECK_BLOCKS("misc", root, 2);
+ p2 = talloc_strdup(p1, "foo");
+ torture_assert("misc", talloc_unlink(root, p2) == -1,
+ "failed: talloc_unlink() of non-reference context should return -1\n");
+ torture_assert("misc", talloc_unlink(p1, p2) == 0,
+ "failed: talloc_unlink() of parent should succeed\n");
+ talloc_free(p1);
+ CHECK_BLOCKS("misc", p1, 1);
+ CHECK_BLOCKS("misc", root, 2);
+
+ name = talloc_set_name(p1, "my name is %s", "foo");
+ torture_assert_str_equal("misc", talloc_get_name(p1), "my name is foo",
+ "failed: wrong name after talloc_set_name(my name is foo)");
+ CHECK_BLOCKS("misc", p1, 2);
+ CHECK_BLOCKS("misc", root, 3);
+
+ talloc_set_name_const(p1, NULL);
+ torture_assert_str_equal ("misc", talloc_get_name(p1), "UNNAMED",
+ "failed: wrong name after talloc_set_name(NULL)");
+ CHECK_BLOCKS("misc", p1, 2);
+ CHECK_BLOCKS("misc", root, 3);
+
+ torture_assert("misc", talloc_free(NULL) == -1,
+ "talloc_free(NULL) should give -1\n");
+
+ talloc_set_destructor(p1, fail_destructor);
+ torture_assert("misc", talloc_free(p1) == -1,
+ "Failed destructor should cause talloc_free to fail\n");
+ talloc_set_destructor(p1, NULL);
+
+ talloc_report(root, stderr);
+
+
+ p2 = (char *)talloc_zero_size(p1, 20);
+ torture_assert("misc", p2[19] == 0, "Failed to give zero memory\n");
+ talloc_free(p2);
+
+ torture_assert("misc", talloc_strdup(root, NULL) == NULL,
+ "failed: strdup on NULL should give NULL\n");
+
+ p2 = talloc_strndup(p1, "foo", 2);
+ torture_assert("misc", strcmp("fo", p2) == 0,
+ "strndup doesn't work\n");
+ p2 = talloc_asprintf_append_buffer(p2, "o%c", 'd');
+ torture_assert("misc", strcmp("food", p2) == 0,
+ "talloc_asprintf_append_buffer doesn't work\n");
+ CHECK_BLOCKS("misc", p2, 1);
+ CHECK_BLOCKS("misc", p1, 3);
+
+ p2 = talloc_asprintf_append_buffer(NULL, "hello %s", "world");
+ torture_assert("misc", strcmp("hello world", p2) == 0,
+ "talloc_asprintf_append_buffer doesn't work\n");
+ CHECK_BLOCKS("misc", p2, 1);
+ CHECK_BLOCKS("misc", p1, 3);
+ talloc_free(p2);
+
+ d = talloc_array(p1, double, 0x20000000);
+ torture_assert("misc", !d, "failed: integer overflow not detected\n");
+
+ d = talloc_realloc(p1, d, double, 0x20000000);
+ torture_assert("misc", !d, "failed: integer overflow not detected\n");
+
+ talloc_free(p1);
+ CHECK_BLOCKS("misc", root, 1);
+
+ p1 = talloc_named(root, 100, "%d bytes", 100);
+ CHECK_BLOCKS("misc", p1, 2);
+ CHECK_BLOCKS("misc", root, 3);
+ talloc_unlink(root, p1);
+
+ p1 = talloc_init("%d bytes", 200);
+ p2 = talloc_asprintf(p1, "my test '%s'", "string");
+ torture_assert_str_equal("misc", p2, "my test 'string'",
+ "failed: talloc_asprintf(\"my test '%%s'\", \"string\") gave: \"%s\"");
+ CHECK_BLOCKS("misc", p1, 3);
+ CHECK_SIZE("misc", p2, 17);
+ CHECK_BLOCKS("misc", root, 1);
+ talloc_unlink(NULL, p1);
+
+ p1 = talloc_named_const(root, 10, "p1");
+ p2 = (char *)talloc_named_const(root, 20, "p2");
+ (void)talloc_reference(p1, p2);
+ talloc_report_full(root, stderr);
+ talloc_unlink(root, p2);
+ talloc_report_full(root, stderr);
+ CHECK_BLOCKS("misc", p2, 1);
+ CHECK_BLOCKS("misc", p1, 2);
+ CHECK_BLOCKS("misc", root, 3);
+ talloc_unlink(p1, p2);
+ talloc_unlink(root, p1);
+
+ p1 = talloc_named_const(root, 10, "p1");
+ p2 = (char *)talloc_named_const(root, 20, "p2");
+ (void)talloc_reference(NULL, p2);
+ talloc_report_full(root, stderr);
+ talloc_unlink(root, p2);
+ talloc_report_full(root, stderr);
+ CHECK_BLOCKS("misc", p2, 1);
+ CHECK_BLOCKS("misc", p1, 1);
+ CHECK_BLOCKS("misc", root, 2);
+ talloc_unlink(NULL, p2);
+ talloc_unlink(root, p1);
+
+ /* Test that talloc_unlink is a no-op */
+
+ torture_assert("misc", talloc_unlink(root, NULL) == -1,
+ "failed: talloc_unlink(root, NULL) == -1\n");
+
+ talloc_report(root, stderr);
+ talloc_report(NULL, stderr);
+
+ CHECK_SIZE("misc", root, 0);
+
+ talloc_free(root);
+
+ CHECK_SIZE("misc", NULL, 0);
+
+ talloc_enable_leak_report();
+ talloc_enable_leak_report_full();
+
+ printf("success: misc\n");
+
+ return true;
+}
+
+
+/*
+ test realloc
+*/
+static bool test_realloc(void)
+{
+ void *root, *p1, *p2;
+
+ printf("test: realloc\n# REALLOC\n");
+
+ root = talloc_new(NULL);
+
+ p1 = talloc_size(root, 10);
+ CHECK_SIZE("realloc", p1, 10);
+
+ p1 = talloc_realloc_size(NULL, p1, 20);
+ CHECK_SIZE("realloc", p1, 20);
+
+ talloc_new(p1);
+
+ p2 = talloc_realloc_size(p1, NULL, 30);
+
+ talloc_new(p1);
+
+ p2 = talloc_realloc_size(p1, p2, 40);
+
+ CHECK_SIZE("realloc", p2, 40);
+ CHECK_SIZE("realloc", root, 60);
+ CHECK_BLOCKS("realloc", p1, 4);
+
+ p1 = talloc_realloc_size(NULL, p1, 20);
+ CHECK_SIZE("realloc", p1, 60);
+
+ talloc_increase_ref_count(p2);
+ torture_assert("realloc", talloc_realloc_size(NULL, p2, 5) == NULL,
+ "failed: talloc_realloc() on a referenced pointer should fail\n");
+ CHECK_BLOCKS("realloc", p1, 4);
+
+ talloc_realloc_size(NULL, p2, 0);
+ talloc_realloc_size(NULL, p2, 0);
+ CHECK_BLOCKS("realloc", p1, 3);
+
+ torture_assert("realloc", talloc_realloc_size(NULL, p1, 0x7fffffff) == NULL,
+ "failed: oversize talloc should fail\n");
+
+ talloc_realloc_size(NULL, p1, 0);
+
+ CHECK_BLOCKS("realloc", root, 1);
+ CHECK_SIZE("realloc", root, 0);
+
+ talloc_free(root);
+
+ printf("success: realloc\n");
+
+ return true;
+}
+
+/*
+ test realloc with a child
+*/
+static bool test_realloc_child(void)
+{
+ void *root;
+ struct el2 {
+ const char *name;
+ } *el2;
+ struct el1 {
+ int count;
+ struct el2 **list, **list2, **list3;
+ } *el1;
+
+ printf("test: REALLOC WITH CHILD\n");
+
+ root = talloc_new(NULL);
+
+ el1 = talloc(root, struct el1);
+ el1->list = talloc(el1, struct el2 *);
+ el1->list[0] = talloc(el1->list, struct el2);
+ el1->list[0]->name = talloc_strdup(el1->list[0], "testing");
+
+ el1->list2 = talloc(el1, struct el2 *);
+ el1->list2[0] = talloc(el1->list2, struct el2);
+ el1->list2[0]->name = talloc_strdup(el1->list2[0], "testing2");
+
+ el1->list3 = talloc(el1, struct el2 *);
+ el1->list3[0] = talloc(el1->list3, struct el2);
+ el1->list3[0]->name = talloc_strdup(el1->list3[0], "testing2");
+
+ el2 = talloc(el1->list, struct el2);
+ el2 = talloc(el1->list2, struct el2);
+ el2 = talloc(el1->list3, struct el2);
+
+ el1->list = talloc_realloc(el1, el1->list, struct el2 *, 100);
+ el1->list2 = talloc_realloc(el1, el1->list2, struct el2 *, 200);
+ el1->list3 = talloc_realloc(el1, el1->list3, struct el2 *, 300);
+
+ talloc_free(root);
+
+ printf("success: REALLOC WITH CHILD\n");
+ return true;
+}
+
+/*
+ test type checking
+*/
+static bool test_type(void)
+{
+ void *root;
+ struct el1 {
+ int count;
+ };
+ struct el2 {
+ int count;
+ };
+ struct el1 *el1;
+
+ printf("test: type\n# talloc type checking\n");
+
+ root = talloc_new(NULL);
+
+ el1 = talloc(root, struct el1);
+
+ el1->count = 1;
+
+ torture_assert("type", talloc_get_type(el1, struct el1) == el1,
+ "type check failed on el1\n");
+ torture_assert("type", talloc_get_type(el1, struct el2) == NULL,
+ "type check failed on el1 with el2\n");
+ talloc_set_type(el1, struct el2);
+ torture_assert("type", talloc_get_type(el1, struct el2) == (struct el2 *)el1,
+ "type set failed on el1 with el2\n");
+
+ talloc_free(root);
+
+ printf("success: type\n");
+ return true;
+}
+
+/*
+ test steal
+*/
+static bool test_steal(void)
+{
+ void *root, *p1, *p2;
+
+ printf("test: steal\n# STEAL\n");
+
+ root = talloc_new(NULL);
+
+ p1 = talloc_array(root, char, 10);
+ CHECK_SIZE("steal", p1, 10);
+
+ p2 = talloc_realloc(root, NULL, char, 20);
+ CHECK_SIZE("steal", p1, 10);
+ CHECK_SIZE("steal", root, 30);
+
+ torture_assert("steal", talloc_steal(p1, NULL) == NULL,
+ "failed: stealing NULL should give NULL\n");
+
+ torture_assert("steal", talloc_steal(p1, p1) == p1,
+ "failed: stealing to ourselves is a nop\n");
+ CHECK_BLOCKS("steal", root, 3);
+ CHECK_SIZE("steal", root, 30);
+
+ talloc_steal(NULL, p1);
+ talloc_steal(NULL, p2);
+ CHECK_BLOCKS("steal", root, 1);
+ CHECK_SIZE("steal", root, 0);
+
+ talloc_free(p1);
+ talloc_steal(root, p2);
+ CHECK_BLOCKS("steal", root, 2);
+ CHECK_SIZE("steal", root, 20);
+
+ talloc_free(p2);
+
+ CHECK_BLOCKS("steal", root, 1);
+ CHECK_SIZE("steal", root, 0);
+
+ talloc_free(root);
+
+ p1 = talloc_size(NULL, 3);
+ talloc_report_full(NULL, stderr);
+ CHECK_SIZE("steal", NULL, 3);
+ talloc_free(p1);
+
+ printf("success: steal\n");
+ return true;
+}
+
+/*
+ test move
+*/
+static bool test_move(void)
+{
+ void *root;
+ struct t_move {
+ char *p;
+ int *x;
+ } *t1, *t2;
+
+ printf("test: move\n# MOVE\n");
+
+ root = talloc_new(NULL);
+
+ t1 = talloc(root, struct t_move);
+ t2 = talloc(root, struct t_move);
+ t1->p = talloc_strdup(t1, "foo");
+ t1->x = talloc(t1, int);
+ *t1->x = 42;
+
+ t2->p = talloc_move(t2, &t1->p);
+ t2->x = talloc_move(t2, &t1->x);
+ torture_assert("move", t1->p == NULL && t1->x == NULL &&
+ strcmp(t2->p, "foo") == 0 && *t2->x == 42,
+ "talloc move failed");
+
+ talloc_free(root);
+
+ printf("success: move\n");
+
+ return true;
+}
+
+/*
+ test talloc_realloc_fn
+*/
+static bool test_realloc_fn(void)
+{
+ void *root, *p1;
+
+ printf("test: realloc_fn\n# talloc_realloc_fn\n");
+
+ root = talloc_new(NULL);
+
+ p1 = talloc_realloc_fn(root, NULL, 10);
+ CHECK_BLOCKS("realloc_fn", root, 2);
+ CHECK_SIZE("realloc_fn", root, 10);
+ p1 = talloc_realloc_fn(root, p1, 20);
+ CHECK_BLOCKS("realloc_fn", root, 2);
+ CHECK_SIZE("realloc_fn", root, 20);
+ p1 = talloc_realloc_fn(root, p1, 0);
+ CHECK_BLOCKS("realloc_fn", root, 1);
+ CHECK_SIZE("realloc_fn", root, 0);
+
+ talloc_free(root);
+
+ printf("success: realloc_fn\n");
+ return true;
+}
+
+
+static bool test_unref_reparent(void)
+{
+ void *root, *p1, *p2, *c1;
+
+ printf("test: unref_reparent\n# UNREFERENCE AFTER PARENT FREED\n");
+
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "orig parent");
+ p2 = talloc_named_const(root, 1, "parent by reference");
+
+ c1 = talloc_named_const(p1, 1, "child");
+ talloc_reference(p2, c1);
+
+ CHECK_PARENT("unref_reparent", c1, p1);
+
+ talloc_free(p1);
+
+ CHECK_PARENT("unref_reparent", c1, p2);
+
+ talloc_unlink(p2, c1);
+
+ CHECK_SIZE("unref_reparent", root, 1);
+
+ talloc_free(p2);
+ talloc_free(root);
+
+ printf("success: unref_reparent\n");
+ return true;
+}
+
+/*
+ measure the speed of talloc versus malloc
+*/
+static bool test_speed(void)
+{
+ void *ctx = talloc_new(NULL);
+ unsigned count;
+ const int loop = 1000;
+ int i;
+ struct timeval tv;
+
+ printf("test: speed\n# TALLOC VS MALLOC SPEED\n");
+
+ tv = timeval_current();
+ count = 0;
+ do {
+ void *p1, *p2, *p3;
+ for (i=0;i<loop;i++) {
+ p1 = talloc_size(ctx, loop % 100);
+ p2 = talloc_strdup(p1, "foo bar");
+ p3 = talloc_size(p1, 300);
+ talloc_free(p1);
+ }
+ count += 3 * loop;
+ } while (timeval_elapsed(&tv) < 5.0);
+
+ fprintf(stderr, "talloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
+
+ talloc_free(ctx);
+
+ ctx = talloc_pool(NULL, 1024);
+
+ tv = timeval_current();
+ count = 0;
+ do {
+ void *p1, *p2, *p3;
+ for (i=0;i<loop;i++) {
+ p1 = talloc_size(ctx, loop % 100);
+ p2 = talloc_strdup(p1, "foo bar");
+ p3 = talloc_size(p1, 300);
+ talloc_free_children(ctx);
+ }
+ count += 3 * loop;
+ } while (timeval_elapsed(&tv) < 5.0);
+
+ talloc_free(ctx);
+
+ fprintf(stderr, "talloc_pool: %.0f ops/sec\n", count/timeval_elapsed(&tv));
+
+ tv = timeval_current();
+ count = 0;
+ do {
+ void *p1, *p2, *p3;
+ for (i=0;i<loop;i++) {
+ p1 = malloc(loop % 100);
+ p2 = strdup("foo bar");
+ p3 = malloc(300);
+ free(p1);
+ free(p2);
+ free(p3);
+ }
+ count += 3 * loop;
+ } while (timeval_elapsed(&tv) < 5.0);
+ fprintf(stderr, "malloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
+
+ printf("success: speed\n");
+
+ return true;
+}
+
+static bool test_lifeless(void)
+{
+ void *top = talloc_new(NULL);
+ char *parent, *child;
+ void *child_owner = talloc_new(NULL);
+
+ printf("test: lifeless\n# TALLOC_UNLINK LOOP\n");
+
+ parent = talloc_strdup(top, "parent");
+ child = talloc_strdup(parent, "child");
+ (void)talloc_reference(child, parent);
+ (void)talloc_reference(child_owner, child);
+ talloc_report_full(top, stderr);
+ talloc_unlink(top, parent);
+ talloc_free(child);
+ talloc_report_full(top, stderr);
+ talloc_free(top);
+ talloc_free(child_owner);
+ talloc_free(child);
+
+ printf("success: lifeless\n");
+ return true;
+}
+
+static int loop_destructor_count;
+
+static int test_loop_destructor(char *ptr)
+{
+ loop_destructor_count++;
+ return 0;
+}
+
+static bool test_loop(void)
+{
+ void *top = talloc_new(NULL);
+ char *parent;
+ struct req1 {
+ char *req2, *req3;
+ } *req1;
+
+ printf("test: loop\n# TALLOC LOOP DESTRUCTION\n");
+
+ parent = talloc_strdup(top, "parent");
+ req1 = talloc(parent, struct req1);
+ req1->req2 = talloc_strdup(req1, "req2");
+ talloc_set_destructor(req1->req2, test_loop_destructor);
+ req1->req3 = talloc_strdup(req1, "req3");
+ (void)talloc_reference(req1->req3, req1);
+ talloc_report_full(top, stderr);
+ talloc_free(parent);
+ talloc_report_full(top, stderr);
+ talloc_report_full(NULL, stderr);
+ talloc_free(top);
+
+ torture_assert("loop", loop_destructor_count == 1,
+ "FAILED TO FIRE LOOP DESTRUCTOR\n");
+ loop_destructor_count = 0;
+
+ printf("success: loop\n");
+ return true;
+}
+
+static int fail_destructor_str(char *ptr)
+{
+ return -1;
+}
+
+static bool test_free_parent_deny_child(void)
+{
+ void *top = talloc_new(NULL);
+ char *level1;
+ char *level2;
+ char *level3;
+
+ printf("test: free_parent_deny_child\n# TALLOC FREE PARENT DENY CHILD\n");
+
+ level1 = talloc_strdup(top, "level1");
+ level2 = talloc_strdup(level1, "level2");
+ level3 = talloc_strdup(level2, "level3");
+
+ talloc_set_destructor(level3, fail_destructor_str);
+ talloc_free(level1);
+ talloc_set_destructor(level3, NULL);
+
+ CHECK_PARENT("free_parent_deny_child", level3, top);
+
+ talloc_free(top);
+
+ printf("success: free_parent_deny_child\n");
+ return true;
+}
+
+static bool test_talloc_ptrtype(void)
+{
+ void *top = talloc_new(NULL);
+ struct struct1 {
+ int foo;
+ int bar;
+ } *s1, *s2, **s3, ***s4;
+ const char *location1;
+ const char *location2;
+ const char *location3;
+ const char *location4;
+
+ printf("test: ptrtype\n# TALLOC PTRTYPE\n");
+
+ s1 = talloc_ptrtype(top, s1);location1 = __location__;
+
+ if (talloc_get_size(s1) != sizeof(struct struct1)) {
+ printf("failure: ptrtype [\n"
+ "talloc_ptrtype() allocated the wrong size %lu (should be %lu)\n"
+ "]\n", (unsigned long)talloc_get_size(s1),
+ (unsigned long)sizeof(struct struct1));
+ return false;
+ }
+
+ if (strcmp(location1, talloc_get_name(s1)) != 0) {
+ printf("failure: ptrtype [\n"
+ "talloc_ptrtype() sets the wrong name '%s' (should be '%s')\n]\n",
+ talloc_get_name(s1), location1);
+ return false;
+ }
+
+ s2 = talloc_array_ptrtype(top, s2, 10);location2 = __location__;
+
+ if (talloc_get_size(s2) != (sizeof(struct struct1) * 10)) {
+ printf("failure: ptrtype [\n"
+ "talloc_array_ptrtype() allocated the wrong size "
+ "%lu (should be %lu)\n]\n",
+ (unsigned long)talloc_get_size(s2),
+ (unsigned long)(sizeof(struct struct1)*10));
+ return false;
+ }
+
+ if (strcmp(location2, talloc_get_name(s2)) != 0) {
+ printf("failure: ptrtype [\n"
+ "talloc_array_ptrtype() sets the wrong name '%s' (should be '%s')\n]\n",
+ talloc_get_name(s2), location2);
+ return false;
+ }
+
+ s3 = talloc_array_ptrtype(top, s3, 10);location3 = __location__;
+
+ if (talloc_get_size(s3) != (sizeof(struct struct1 *) * 10)) {
+ printf("failure: ptrtype [\n"
+ "talloc_array_ptrtype() allocated the wrong size "
+ "%lu (should be %lu)\n]\n",
+ (unsigned long)talloc_get_size(s3),
+ (unsigned long)(sizeof(struct struct1 *)*10));
+ return false;
+ }
+
+ torture_assert_str_equal("ptrtype", location3, talloc_get_name(s3),
+ "talloc_array_ptrtype() sets the wrong name");
+
+ s4 = talloc_array_ptrtype(top, s4, 10);location4 = __location__;
+
+ if (talloc_get_size(s4) != (sizeof(struct struct1 **) * 10)) {
+ printf("failure: ptrtype [\n"
+ "talloc_array_ptrtype() allocated the wrong size "
+ "%lu (should be %lu)\n]\n",
+ (unsigned long)talloc_get_size(s4),
+ (unsigned long)(sizeof(struct struct1 **)*10));
+ return false;
+ }
+
+ torture_assert_str_equal("ptrtype", location4, talloc_get_name(s4),
+ "talloc_array_ptrtype() sets the wrong name");
+
+ talloc_free(top);
+
+ printf("success: ptrtype\n");
+ return true;
+}
+
+static int _test_talloc_free_in_destructor(void **ptr)
+{
+ talloc_free(*ptr);
+ return 0;
+}
+
+static bool test_talloc_free_in_destructor(void)
+{
+ void *level0;
+ void *level1;
+ void *level2;
+ void *level3;
+ void *level4;
+ void **level5;
+
+ printf("test: free_in_destructor\n# TALLOC FREE IN DESTRUCTOR\n");
+
+ level0 = talloc_new(NULL);
+ level1 = talloc_new(level0);
+ level2 = talloc_new(level1);
+ level3 = talloc_new(level2);
+ level4 = talloc_new(level3);
+ level5 = talloc(level4, void *);
+
+ *level5 = level3;
+ (void)talloc_reference(level0, level3);
+ (void)talloc_reference(level3, level3);
+ (void)talloc_reference(level5, level3);
+
+ talloc_set_destructor(level5, _test_talloc_free_in_destructor);
+
+ talloc_free(level1);
+
+ talloc_free(level0);
+
+ printf("success: free_in_destructor\n");
+ return true;
+}
+
+static bool test_autofree(void)
+{
+#if _SAMBA_BUILD_ < 4
+ /* autofree test would kill smbtorture */
+ void *p;
+ printf("test: autofree\n# TALLOC AUTOFREE CONTEXT\n");
+
+ p = talloc_autofree_context();
+ talloc_free(p);
+
+ p = talloc_autofree_context();
+ talloc_free(p);
+
+ printf("success: autofree\n");
+#endif
+ return true;
+}
+
+static bool test_pool(void)
+{
+ void *pool;
+ void *p1, *p2, *p3, *p4;
+
+ pool = talloc_pool(NULL, 1024);
+
+ p1 = talloc_size(pool, 80);
+ p2 = talloc_size(pool, 20);
+ p3 = talloc_size(p1, 50);
+ p4 = talloc_size(p3, 1000);
+
+ talloc_free(pool);
+
+ return true;
+}
+
+struct torture_context;
+bool torture_local_talloc(struct torture_context *tctx)
+{
+ bool ret = true;
+
+ setlinebuf(stdout);
+
+ talloc_disable_null_tracking();
+ talloc_enable_null_tracking();
+
+ ret &= test_ref1();
+ ret &= test_ref2();
+ ret &= test_ref3();
+ ret &= test_ref4();
+ ret &= test_unlink1();
+ ret &= test_misc();
+ ret &= test_realloc();
+ ret &= test_realloc_child();
+ ret &= test_steal();
+ ret &= test_move();
+ ret &= test_unref_reparent();
+ ret &= test_realloc_fn();
+ ret &= test_type();
+ ret &= test_lifeless();
+ ret &= test_loop();
+ ret &= test_free_parent_deny_child();
+ ret &= test_talloc_ptrtype();
+ ret &= test_talloc_free_in_destructor();
+ ret &= test_pool();
+
+ if (ret) {
+ ret &= test_speed();
+ }
+ ret &= test_autofree();
+
+ return ret;
+}
+
+#if _SAMBA_BUILD_ < 4
+int main(void)
+{
+ bool ret = torture_local_talloc(NULL);
+ if (!ret)
+ return -1;
+ return 0;
+}
+#endif
diff --git a/source3/lib/talloc/web/index.html b/source3/lib/talloc/web/index.html
new file mode 100644
index 0000000000..5deab93665
--- /dev/null
+++ b/source3/lib/talloc/web/index.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+<TITLE>talloc</TITLE>
+</HEAD>
+<BODY BGCOLOR="#ffffff" TEXT="#000000" VLINK="#292555" LINK="#292555" ALINK="#cc0033">
+
+<h1>talloc</h1>
+
+talloc is a hierarchical pool based memory allocator with
+destructors. It is the core memory allocator used in Samba4, and has
+made a huge difference in many aspects of Samba4 development.<p>
+
+To get started with talloc, I would recommend you read the <a
+href="http://samba.org/ftp/unpacked/talloc/talloc_guide.txt">talloc guide</a>.
+
+<h2>Discussion and bug reports</h2>
+
+talloc does not currently have its own mailing list or bug tracking
+system. For now, please use the <a
+href="https://lists.samba.org/mailman/listinfo/samba-technical">samba-technical</a>
+mailing list, and the <a href="http://bugzilla.samba.org/">Samba
+bugzilla</a> bug tracking system.
+
+<h2>Download</h2>
+
+You can download the latest release either via rsync or git.<br>
+<br>
+To fetch via git see the following guide:<br>
+<a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development">Using Git for Samba Development</a><br>
+Once you have cloned the tree switch to the v4-0-test branch and cd into the source/lib/talloc directory.<br>
+<br>
+To fetch via rsync use this command:
+
+<pre>
+ rsync -Pavz samba.org::ftp/unpacked/talloc .
+</pre>
+
+<hr>
+<tiny>
+<a href="http://samba.org/~tridge/">Andrew Tridgell</a><br>
+talloc AT tridgell.net
+</tiny>
+
+</BODY>
+</HTML>
diff --git a/source3/lib/talloc_stack.c b/source3/lib/talloc_stack.c
new file mode 100644
index 0000000000..2722fb9676
--- /dev/null
+++ b/source3/lib/talloc_stack.c
@@ -0,0 +1,130 @@
+/*
+ Unix SMB/CIFS implementation.
+ Implement a stack of talloc contexts
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ * Implement a stack of talloc frames.
+ *
+ * When a new talloc stackframe is allocated with talloc_stackframe(), then
+ * the TALLOC_CTX returned with talloc_tos() is reset to that new
+ * frame. Whenever that stack frame is TALLOC_FREE()'ed, then the reverse
+ * happens: The previous talloc_tos() is restored.
+ *
+ * This API is designed to be robust in the sense that if someone forgets to
+ * TALLOC_FREE() a stackframe, then the next outer one correctly cleans up and
+ * resets the talloc_tos().
+ *
+ * This robustness feature means that we can't rely on a linked list with
+ * talloc destructors because in a hierarchy of talloc destructors the parent
+ * destructor is called before its children destructors. The child destructor
+ * called after the parent would set the talloc_tos() to the wrong value.
+ */
+
+#include "includes.h"
+
+static int talloc_stacksize;
+static int talloc_stack_arraysize;
+static TALLOC_CTX **talloc_stack;
+
+static int talloc_pop(TALLOC_CTX *frame)
+{
+ int i;
+
+ for (i=talloc_stacksize-1; i>0; i--) {
+ if (frame == talloc_stack[i]) {
+ break;
+ }
+ talloc_free(talloc_stack[i]);
+ }
+
+ talloc_stacksize = i;
+ return 0;
+}
+
+/*
+ * Create a new talloc stack frame.
+ *
+ * When free'd, it frees all stack frames that were created after this one and
+ * not explicitly freed.
+ */
+
+static TALLOC_CTX *talloc_stackframe_internal(size_t poolsize)
+{
+ TALLOC_CTX **tmp, *top, *parent;
+
+ if (talloc_stack_arraysize < talloc_stacksize + 1) {
+ tmp = TALLOC_REALLOC_ARRAY(NULL, talloc_stack, TALLOC_CTX *,
+ talloc_stacksize + 1);
+ if (tmp == NULL) {
+ goto fail;
+ }
+ talloc_stack = tmp;
+ talloc_stack_arraysize = talloc_stacksize + 1;
+ }
+
+ if (talloc_stacksize == 0) {
+ parent = talloc_stack;
+ }
+ else {
+ parent = talloc_stack[talloc_stacksize-1];
+ }
+
+ if (poolsize) {
+ top = talloc_pool(parent, poolsize);
+ } else {
+ top = talloc_new(parent);
+ }
+
+ if (top == NULL) {
+ goto fail;
+ }
+
+ talloc_set_destructor(top, talloc_pop);
+
+ talloc_stack[talloc_stacksize++] = top;
+ return top;
+
+ fail:
+ smb_panic("talloc_stackframe failed");
+ return NULL;
+}
+
+TALLOC_CTX *talloc_stackframe(void)
+{
+ return talloc_stackframe_internal(0);
+}
+
+TALLOC_CTX *talloc_stackframe_pool(size_t poolsize)
+{
+ return talloc_stackframe_internal(poolsize);
+}
+
+/*
+ * Get us the current top of the talloc stack.
+ */
+
+TALLOC_CTX *talloc_tos(void)
+{
+ if (talloc_stacksize == 0) {
+ talloc_stackframe();
+ DEBUG(0, ("no talloc stackframe around, leaking memory\n"));
+ }
+
+ return talloc_stack[talloc_stacksize-1];
+}
diff --git a/source3/lib/tallocmsg.c b/source3/lib/tallocmsg.c
new file mode 100644
index 0000000000..b4bea5a5b5
--- /dev/null
+++ b/source3/lib/tallocmsg.c
@@ -0,0 +1,107 @@
+/*
+ samba -- Unix SMB/CIFS implementation.
+ Copyright (C) 2001, 2002 by Martin Pool
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/**
+ * @file tallocmsg.c
+ *
+ * Glue code between talloc profiling and the Samba messaging system.
+ **/
+
+struct msg_pool_usage_state {
+ TALLOC_CTX *mem_ctx;
+ ssize_t len;
+ size_t buflen;
+ char *s;
+};
+
+static void msg_pool_usage_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_s)
+{
+ const char *name = talloc_get_name(ptr);
+ struct msg_pool_usage_state *state = (struct msg_pool_usage_state *)_s;
+
+ if (is_ref) {
+ sprintf_append(state->mem_ctx, &state->s, &state->len, &state->buflen,
+ "%*sreference to: %s\n", depth*4, "", name);
+ return;
+ }
+
+ if (depth == 0) {
+ sprintf_append(state->mem_ctx, &state->s, &state->len, &state->buflen,
+ "%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n",
+ (max_depth < 0 ? "full " :""), name,
+ (unsigned long)talloc_total_size(ptr),
+ (unsigned long)talloc_total_blocks(ptr));
+ return;
+ }
+
+ sprintf_append(state->mem_ctx, &state->s, &state->len, &state->buflen,
+ "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n",
+ depth*4, "",
+ name,
+ (unsigned long)talloc_total_size(ptr),
+ (unsigned long)talloc_total_blocks(ptr),
+ talloc_reference_count(ptr));
+}
+
+/**
+ * Respond to a POOL_USAGE message by sending back string form of memory
+ * usage stats.
+ **/
+static void msg_pool_usage(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ DATA_BLOB *data)
+{
+ struct msg_pool_usage_state state;
+
+ SMB_ASSERT(msg_type == MSG_REQ_POOL_USAGE);
+
+ DEBUG(2,("Got POOL_USAGE\n"));
+
+ state.mem_ctx = talloc_init("msg_pool_usage");
+ if (!state.mem_ctx) {
+ return;
+ }
+ state.len = 0;
+ state.buflen = 512;
+ state.s = NULL;
+
+ talloc_report_depth_cb(NULL, 0, -1, msg_pool_usage_helper, &state);
+
+ if (!state.s) {
+ talloc_destroy(state.mem_ctx);
+ return;
+ }
+
+ messaging_send_buf(msg_ctx, src, MSG_POOL_USAGE,
+ (uint8 *)state.s, strlen(state.s)+1);
+
+ talloc_destroy(state.mem_ctx);
+}
+
+/**
+ * Register handler for MSG_REQ_POOL_USAGE
+ **/
+void register_msg_pool_usage(struct messaging_context *msg_ctx)
+{
+ messaging_register(msg_ctx, NULL, MSG_REQ_POOL_USAGE, msg_pool_usage);
+ DEBUG(2, ("Registered MSG_REQ_POOL_USAGE\n"));
+}
diff --git a/source3/lib/tdb/Makefile.in b/source3/lib/tdb/Makefile.in
new file mode 100644
index 0000000000..090bb6e2dc
--- /dev/null
+++ b/source3/lib/tdb/Makefile.in
@@ -0,0 +1,59 @@
+#!gmake
+#
+# Makefile for tdb directory
+#
+
+CC = @CC@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+includedir = @includedir@
+libdir = @libdir@
+VPATH = @srcdir@:@libreplacedir@
+srcdir = @srcdir@
+builddir = @builddir@
+CPPFLAGS = @CPPFLAGS@ -I$(srcdir)/include -Iinclude
+CFLAGS = $(CPPFLAGS) @CFLAGS@
+LDFLAGS = @LDFLAGS@
+EXEEXT = @EXEEXT@
+SHLD = @SHLD@
+SHLD_FLAGS = @SHLD_FLAGS@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PICFLAG = @PICFLAG@
+SHLIBEXT = @SHLIBEXT@
+SWIG = swig
+PYTHON = @PYTHON@
+PYTHON_CONFIG = @PYTHON_CONFIG@
+PYTHON_BUILD_TARGET = @PYTHON_BUILD_TARGET@
+PYTHON_INSTALL_TARGET = @PYTHON_INSTALL_TARGET@
+PYTHON_CHECK_TARGET = @PYTHON_CHECK_TARGET@
+LIB_PATH_VAR = @LIB_PATH_VAR@
+tdbdir = @tdbdir@
+
+TDB_OBJ = @TDB_OBJ@ @LIBREPLACEOBJ@
+
+default: all
+
+include $(tdbdir)/tdb.mk
+include $(tdbdir)/rules.mk
+
+all:: showflags dirs $(PROGS) $(TDB_SOLIB) libtdb.a $(PYTHON_BUILD_TARGET)
+
+install:: all
+$(TDB_SOLIB): $(TDB_OBJ)
+ $(SHLD) $(SHLD_FLAGS) -o $@ $(TDB_OBJ) @SONAMEFLAG@$(TDB_SONAME)
+
+check: test
+
+test:: $(PYTHON_CHECK_TARGET)
+installcheck:: test install
+
+clean::
+ rm -f *.o *.a */*.o
+
+distclean:: clean
+ rm -f config.log config.status include/config.h config.cache
+ rm -f Makefile
+
+realdistclean:: distclean
+ rm -f configure include/config.h.in
diff --git a/source3/lib/tdb/aclocal.m4 b/source3/lib/tdb/aclocal.m4
new file mode 100644
index 0000000000..5605e476ba
--- /dev/null
+++ b/source3/lib/tdb/aclocal.m4
@@ -0,0 +1 @@
+m4_include(libreplace.m4)
diff --git a/source3/lib/tdb/autogen.sh b/source3/lib/tdb/autogen.sh
new file mode 100755
index 0000000000..88ac4cfcf7
--- /dev/null
+++ b/source3/lib/tdb/autogen.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+rm -rf autom4te.cache
+rm -f configure config.h.in
+
+IPATHS="-I libreplace -I lib/replace -I ../libreplace -I ../replace"
+autoconf $IPATHS || exit 1
+autoheader $IPATHS || exit 1
+
+rm -rf autom4te.cache
+
+swig -O -Wall -python -keyword tdb.i # Ignore errors for now
+
+echo "Now run ./configure and then make."
+exit 0
+
diff --git a/source3/lib/tdb/common/dump.c b/source3/lib/tdb/common/dump.c
new file mode 100644
index 0000000000..d1c902ddfd
--- /dev/null
+++ b/source3/lib/tdb/common/dump.c
@@ -0,0 +1,137 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2005
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+static tdb_off_t tdb_dump_record(struct tdb_context *tdb, int hash,
+ tdb_off_t offset)
+{
+ struct list_struct rec;
+ tdb_off_t tailer_ofs, tailer;
+
+ if (tdb->methods->tdb_read(tdb, offset, (char *)&rec,
+ sizeof(rec), DOCONV()) == -1) {
+ printf("ERROR: failed to read record at %u\n", offset);
+ return 0;
+ }
+
+ printf(" rec: hash=%d offset=0x%08x next=0x%08x rec_len=%d "
+ "key_len=%d data_len=%d full_hash=0x%x magic=0x%x\n",
+ hash, offset, rec.next, rec.rec_len, rec.key_len, rec.data_len,
+ rec.full_hash, rec.magic);
+
+ tailer_ofs = offset + sizeof(rec) + rec.rec_len - sizeof(tdb_off_t);
+
+ if (tdb_ofs_read(tdb, tailer_ofs, &tailer) == -1) {
+ printf("ERROR: failed to read tailer at %u\n", tailer_ofs);
+ return rec.next;
+ }
+
+ if (tailer != rec.rec_len + sizeof(rec)) {
+ printf("ERROR: tailer does not match record! tailer=%u totalsize=%u\n",
+ (unsigned int)tailer, (unsigned int)(rec.rec_len + sizeof(rec)));
+ }
+ return rec.next;
+}
+
+static int tdb_dump_chain(struct tdb_context *tdb, int i)
+{
+ tdb_off_t rec_ptr, top;
+
+ top = TDB_HASH_TOP(i);
+
+ if (tdb_lock(tdb, i, F_WRLCK) != 0)
+ return -1;
+
+ if (tdb_ofs_read(tdb, top, &rec_ptr) == -1)
+ return tdb_unlock(tdb, i, F_WRLCK);
+
+ if (rec_ptr)
+ printf("hash=%d\n", i);
+
+ while (rec_ptr) {
+ rec_ptr = tdb_dump_record(tdb, i, rec_ptr);
+ }
+
+ return tdb_unlock(tdb, i, F_WRLCK);
+}
+
+void tdb_dump_all(struct tdb_context *tdb)
+{
+ int i;
+ for (i=0;i<tdb->header.hash_size;i++) {
+ tdb_dump_chain(tdb, i);
+ }
+ printf("freelist:\n");
+ tdb_dump_chain(tdb, -1);
+}
+
+int tdb_printfreelist(struct tdb_context *tdb)
+{
+ int ret;
+ long total_free = 0;
+ tdb_off_t offset, rec_ptr;
+ struct list_struct rec;
+
+ if ((ret = tdb_lock(tdb, -1, F_WRLCK)) != 0)
+ return ret;
+
+ offset = FREELIST_TOP;
+
+ /* read in the freelist top */
+ if (tdb_ofs_read(tdb, offset, &rec_ptr) == -1) {
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return 0;
+ }
+
+ printf("freelist top=[0x%08x]\n", rec_ptr );
+ while (rec_ptr) {
+ if (tdb->methods->tdb_read(tdb, rec_ptr, (char *)&rec,
+ sizeof(rec), DOCONV()) == -1) {
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return -1;
+ }
+
+ if (rec.magic != TDB_FREE_MAGIC) {
+ printf("bad magic 0x%08x in free list\n", rec.magic);
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return -1;
+ }
+
+ printf("entry offset=[0x%08x], rec.rec_len = [0x%08x (%d)] (end = 0x%08x)\n",
+ rec_ptr, rec.rec_len, rec.rec_len, rec_ptr + rec.rec_len);
+ total_free += rec.rec_len;
+
+ /* move to the next record */
+ rec_ptr = rec.next;
+ }
+ printf("total rec_len = [0x%08x (%d)]\n", (int)total_free,
+ (int)total_free);
+
+ return tdb_unlock(tdb, -1, F_WRLCK);
+}
+
diff --git a/source3/lib/tdb/common/error.c b/source3/lib/tdb/common/error.c
new file mode 100644
index 0000000000..195ab23815
--- /dev/null
+++ b/source3/lib/tdb/common/error.c
@@ -0,0 +1,57 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2005
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+enum TDB_ERROR tdb_error(struct tdb_context *tdb)
+{
+ return tdb->ecode;
+}
+
+static struct tdb_errname {
+ enum TDB_ERROR ecode; const char *estring;
+} emap[] = { {TDB_SUCCESS, "Success"},
+ {TDB_ERR_CORRUPT, "Corrupt database"},
+ {TDB_ERR_IO, "IO Error"},
+ {TDB_ERR_LOCK, "Locking error"},
+ {TDB_ERR_OOM, "Out of memory"},
+ {TDB_ERR_EXISTS, "Record exists"},
+ {TDB_ERR_NOLOCK, "Lock exists on other keys"},
+ {TDB_ERR_EINVAL, "Invalid parameter"},
+ {TDB_ERR_NOEXIST, "Record does not exist"},
+ {TDB_ERR_RDONLY, "write not permitted"} };
+
+/* Error string for the last tdb error */
+const char *tdb_errorstr(struct tdb_context *tdb)
+{
+ uint32_t i;
+ for (i = 0; i < sizeof(emap) / sizeof(struct tdb_errname); i++)
+ if (tdb->ecode == emap[i].ecode)
+ return emap[i].estring;
+ return "Invalid error code";
+}
+
diff --git a/source3/lib/tdb/common/freelist.c b/source3/lib/tdb/common/freelist.c
new file mode 100644
index 0000000000..2f2a4c379b
--- /dev/null
+++ b/source3/lib/tdb/common/freelist.c
@@ -0,0 +1,382 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2005
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+/* 'right' merges can involve O(n^2) cost when combined with a
+ traverse, so they are disabled until we find a way to do them in
+ O(1) time
+*/
+#define USE_RIGHT_MERGES 0
+
+/* read a freelist record and check for simple errors */
+int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct list_struct *rec)
+{
+ if (tdb->methods->tdb_read(tdb, off, rec, sizeof(*rec),DOCONV()) == -1)
+ return -1;
+
+ if (rec->magic == TDB_MAGIC) {
+ /* this happens when a app is showdown while deleting a record - we should
+ not completely fail when this happens */
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read non-free magic 0x%x at offset=%d - fixing\n",
+ rec->magic, off));
+ rec->magic = TDB_FREE_MAGIC;
+ if (tdb->methods->tdb_write(tdb, off, rec, sizeof(*rec)) == -1)
+ return -1;
+ }
+
+ if (rec->magic != TDB_FREE_MAGIC) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_CORRUPT;
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read bad magic 0x%x at offset=%d\n",
+ rec->magic, off));
+ return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
+ }
+ if (tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0) != 0)
+ return -1;
+ return 0;
+}
+
+
+#if USE_RIGHT_MERGES
+/* Remove an element from the freelist. Must have alloc lock. */
+static int remove_from_freelist(struct tdb_context *tdb, tdb_off_t off, tdb_off_t next)
+{
+ tdb_off_t last_ptr, i;
+
+ /* read in the freelist top */
+ last_ptr = FREELIST_TOP;
+ while (tdb_ofs_read(tdb, last_ptr, &i) != -1 && i != 0) {
+ if (i == off) {
+ /* We've found it! */
+ return tdb_ofs_write(tdb, last_ptr, &next);
+ }
+ /* Follow chain (next offset is at start of record) */
+ last_ptr = i;
+ }
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"remove_from_freelist: not on list at off=%d\n", off));
+ return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
+}
+#endif
+
+
+/* update a record tailer (must hold allocation lock) */
+static int update_tailer(struct tdb_context *tdb, tdb_off_t offset,
+ const struct list_struct *rec)
+{
+ tdb_off_t totalsize;
+
+ /* Offset of tailer from record header */
+ totalsize = sizeof(*rec) + rec->rec_len;
+ return tdb_ofs_write(tdb, offset + totalsize - sizeof(tdb_off_t),
+ &totalsize);
+}
+
+/* Add an element into the freelist. Merge adjacent records if
+ neccessary. */
+int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec)
+{
+ /* Allocation and tailer lock */
+ if (tdb_lock(tdb, -1, F_WRLCK) != 0)
+ return -1;
+
+ /* set an initial tailer, so if we fail we don't leave a bogus record */
+ if (update_tailer(tdb, offset, rec) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed!\n"));
+ goto fail;
+ }
+
+#if USE_RIGHT_MERGES
+ /* Look right first (I'm an Australian, dammit) */
+ if (offset + sizeof(*rec) + rec->rec_len + sizeof(*rec) <= tdb->map_size) {
+ tdb_off_t right = offset + sizeof(*rec) + rec->rec_len;
+ struct list_struct r;
+
+ if (tdb->methods->tdb_read(tdb, right, &r, sizeof(r), DOCONV()) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: right read failed at %u\n", right));
+ goto left;
+ }
+
+ /* If it's free, expand to include it. */
+ if (r.magic == TDB_FREE_MAGIC) {
+ if (remove_from_freelist(tdb, right, r.next) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: right free failed at %u\n", right));
+ goto left;
+ }
+ rec->rec_len += sizeof(r) + r.rec_len;
+ if (update_tailer(tdb, offset, rec) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset));
+ goto fail;
+ }
+ }
+ }
+left:
+#endif
+
+ /* Look left */
+ if (offset - sizeof(tdb_off_t) > TDB_DATA_START(tdb->header.hash_size)) {
+ tdb_off_t left = offset - sizeof(tdb_off_t);
+ struct list_struct l;
+ tdb_off_t leftsize;
+
+ /* Read in tailer and jump back to header */
+ if (tdb_ofs_read(tdb, left, &leftsize) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left offset read failed at %u\n", left));
+ goto update;
+ }
+
+ /* it could be uninitialised data */
+ if (leftsize == 0 || leftsize == TDB_PAD_U32) {
+ goto update;
+ }
+
+ left = offset - leftsize;
+
+ if (leftsize > offset ||
+ left < TDB_DATA_START(tdb->header.hash_size)) {
+ goto update;
+ }
+
+ /* Now read in the left record */
+ if (tdb->methods->tdb_read(tdb, left, &l, sizeof(l), DOCONV()) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left read failed at %u (%u)\n", left, leftsize));
+ goto update;
+ }
+
+ /* If it's free, expand to include it. */
+ if (l.magic == TDB_FREE_MAGIC) {
+ /* we now merge the new record into the left record, rather than the other
+ way around. This makes the operation O(1) instead of O(n). This change
+ prevents traverse from being O(n^2) after a lot of deletes */
+ l.rec_len += sizeof(*rec) + rec->rec_len;
+ if (tdb_rec_write(tdb, left, &l) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_left failed at %u\n", left));
+ goto fail;
+ }
+ if (update_tailer(tdb, left, &l) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset));
+ goto fail;
+ }
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return 0;
+ }
+ }
+
+update:
+
+ /* Now, prepend to free list */
+ rec->magic = TDB_FREE_MAGIC;
+
+ if (tdb_ofs_read(tdb, FREELIST_TOP, &rec->next) == -1 ||
+ tdb_rec_write(tdb, offset, rec) == -1 ||
+ tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free record write failed at offset=%d\n", offset));
+ goto fail;
+ }
+
+ /* And we're done. */
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return 0;
+
+ fail:
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return -1;
+}
+
+
+
+/*
+ the core of tdb_allocate - called when we have decided which
+ free list entry to use
+
+ Note that we try to allocate by grabbing data from the end of an existing record,
+ not the beginning. This is so the left merge in a free is more likely to be
+ able to free up the record without fragmentation
+ */
+static tdb_off_t tdb_allocate_ofs(struct tdb_context *tdb,
+ tdb_len_t length, tdb_off_t rec_ptr,
+ struct list_struct *rec, tdb_off_t last_ptr)
+{
+#define MIN_REC_SIZE (sizeof(struct list_struct) + sizeof(tdb_off_t) + 8)
+
+ if (rec->rec_len < length + MIN_REC_SIZE) {
+ /* we have to grab the whole record */
+
+ /* unlink it from the previous record */
+ if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1) {
+ return 0;
+ }
+
+ /* mark it not free */
+ rec->magic = TDB_MAGIC;
+ if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
+ return 0;
+ }
+ return rec_ptr;
+ }
+
+ /* we're going to just shorten the existing record */
+ rec->rec_len -= (length + sizeof(*rec));
+ if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
+ return 0;
+ }
+ if (update_tailer(tdb, rec_ptr, rec) == -1) {
+ return 0;
+ }
+
+ /* and setup the new record */
+ rec_ptr += sizeof(*rec) + rec->rec_len;
+
+ memset(rec, '\0', sizeof(*rec));
+ rec->rec_len = length;
+ rec->magic = TDB_MAGIC;
+
+ if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
+ return 0;
+ }
+
+ if (update_tailer(tdb, rec_ptr, rec) == -1) {
+ return 0;
+ }
+
+ return rec_ptr;
+}
+
+/* allocate some space from the free list. The offset returned points
+ to a unconnected list_struct within the database with room for at
+ least length bytes of total data
+
+ 0 is returned if the space could not be allocated
+ */
+tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct list_struct *rec)
+{
+ tdb_off_t rec_ptr, last_ptr, newrec_ptr;
+ struct {
+ tdb_off_t rec_ptr, last_ptr;
+ tdb_len_t rec_len;
+ } bestfit;
+ float multiplier = 1.0;
+
+ if (tdb_lock(tdb, -1, F_WRLCK) == -1)
+ return 0;
+
+ /* Extra bytes required for tailer */
+ length += sizeof(tdb_off_t);
+ length = TDB_ALIGN(length, TDB_ALIGNMENT);
+
+ again:
+ last_ptr = FREELIST_TOP;
+
+ /* read in the freelist top */
+ if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1)
+ goto fail;
+
+ bestfit.rec_ptr = 0;
+ bestfit.last_ptr = 0;
+ bestfit.rec_len = 0;
+
+ /*
+ this is a best fit allocation strategy. Originally we used
+ a first fit strategy, but it suffered from massive fragmentation
+ issues when faced with a slowly increasing record size.
+ */
+ while (rec_ptr) {
+ if (tdb_rec_free_read(tdb, rec_ptr, rec) == -1) {
+ goto fail;
+ }
+
+ if (rec->rec_len >= length) {
+ if (bestfit.rec_ptr == 0 ||
+ rec->rec_len < bestfit.rec_len) {
+ bestfit.rec_len = rec->rec_len;
+ bestfit.rec_ptr = rec_ptr;
+ bestfit.last_ptr = last_ptr;
+ }
+ }
+
+ /* move to the next record */
+ last_ptr = rec_ptr;
+ rec_ptr = rec->next;
+
+ /* if we've found a record that is big enough, then
+ stop searching if its also not too big. The
+ definition of 'too big' changes as we scan
+ through */
+ if (bestfit.rec_len > 0 &&
+ bestfit.rec_len < length * multiplier) {
+ break;
+ }
+
+ /* this multiplier means we only extremely rarely
+ search more than 50 or so records. At 50 records we
+ accept records up to 11 times larger than what we
+ want */
+ multiplier *= 1.05;
+ }
+
+ if (bestfit.rec_ptr != 0) {
+ if (tdb_rec_free_read(tdb, bestfit.rec_ptr, rec) == -1) {
+ goto fail;
+ }
+
+ newrec_ptr = tdb_allocate_ofs(tdb, length, bestfit.rec_ptr,
+ rec, bestfit.last_ptr);
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return newrec_ptr;
+ }
+
+ /* we didn't find enough space. See if we can expand the
+ database and if we can then try again */
+ if (tdb_expand(tdb, length + sizeof(*rec)) == 0)
+ goto again;
+ fail:
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return 0;
+}
+
+
+
+/*
+ return the size of the freelist - used to decide if we should repack
+*/
+int tdb_freelist_size(struct tdb_context *tdb)
+{
+ tdb_off_t ptr;
+ int count=0;
+
+ if (tdb_lock(tdb, -1, F_RDLCK) == -1) {
+ return -1;
+ }
+
+ ptr = FREELIST_TOP;
+ while (tdb_ofs_read(tdb, ptr, &ptr) == 0 && ptr != 0) {
+ count++;
+ }
+
+ tdb_unlock(tdb, -1, F_RDLCK);
+ return count;
+}
diff --git a/source3/lib/tdb/common/freelistcheck.c b/source3/lib/tdb/common/freelistcheck.c
new file mode 100644
index 0000000000..efc050df9c
--- /dev/null
+++ b/source3/lib/tdb/common/freelistcheck.c
@@ -0,0 +1,107 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Jeremy Allison 2006
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+/* Check the freelist is good and contains no loops.
+ Very memory intensive - only do this as a consistency
+ checker. Heh heh - uses an in memory tdb as the storage
+ for the "seen" record list. For some reason this strikes
+ me as extremely clever as I don't have to write another tree
+ data structure implementation :-).
+ */
+
+static int seen_insert(struct tdb_context *mem_tdb, tdb_off_t rec_ptr)
+{
+ TDB_DATA key, data;
+
+ memset(&data, '\0', sizeof(data));
+ key.dptr = (unsigned char *)&rec_ptr;
+ key.dsize = sizeof(rec_ptr);
+ return tdb_store(mem_tdb, key, data, TDB_INSERT);
+}
+
+int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries)
+{
+ struct tdb_context *mem_tdb = NULL;
+ struct list_struct rec;
+ tdb_off_t rec_ptr, last_ptr;
+ int ret = -1;
+
+ *pnum_entries = 0;
+
+ mem_tdb = tdb_open("flval", tdb->header.hash_size,
+ TDB_INTERNAL, O_RDWR, 0600);
+ if (!mem_tdb) {
+ return -1;
+ }
+
+ if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
+ tdb_close(mem_tdb);
+ return 0;
+ }
+
+ last_ptr = FREELIST_TOP;
+
+ /* Store the FREELIST_TOP record. */
+ if (seen_insert(mem_tdb, last_ptr) == -1) {
+ ret = TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
+ goto fail;
+ }
+
+ /* read in the freelist top */
+ if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1) {
+ goto fail;
+ }
+
+ while (rec_ptr) {
+
+ /* If we can't store this record (we've seen it
+ before) then the free list has a loop and must
+ be corrupt. */
+
+ if (seen_insert(mem_tdb, rec_ptr)) {
+ ret = TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
+ goto fail;
+ }
+
+ if (tdb_rec_free_read(tdb, rec_ptr, &rec) == -1) {
+ goto fail;
+ }
+
+ /* move to the next record */
+ last_ptr = rec_ptr;
+ rec_ptr = rec.next;
+ *pnum_entries += 1;
+ }
+
+ ret = 0;
+
+ fail:
+
+ tdb_close(mem_tdb);
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return ret;
+}
diff --git a/source3/lib/tdb/common/io.c b/source3/lib/tdb/common/io.c
new file mode 100644
index 0000000000..661f761489
--- /dev/null
+++ b/source3/lib/tdb/common/io.c
@@ -0,0 +1,473 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2005
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "tdb_private.h"
+
+/* check for an out of bounds access - if it is out of bounds then
+ see if the database has been expanded by someone else and expand
+ if necessary
+ note that "len" is the minimum length needed for the db
+*/
+static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, int probe)
+{
+ struct stat st;
+ if (len <= tdb->map_size)
+ return 0;
+ if (tdb->flags & TDB_INTERNAL) {
+ if (!probe) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %d beyond internal malloc size %d\n",
+ (int)len, (int)tdb->map_size));
+ }
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+ }
+
+ if (fstat(tdb->fd, &st) == -1) {
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+ }
+
+ if (st.st_size < (size_t)len) {
+ if (!probe) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %d beyond eof at %d\n",
+ (int)len, (int)st.st_size));
+ }
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+ }
+
+ /* Unmap, update size, remap */
+ if (tdb_munmap(tdb) == -1)
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+ tdb->map_size = st.st_size;
+ tdb_mmap(tdb);
+ return 0;
+}
+
+/* write a lump of data at a specified offset */
+static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
+ const void *buf, tdb_len_t len)
+{
+ if (len == 0) {
+ return 0;
+ }
+
+ if (tdb->read_only || tdb->traverse_read) {
+ tdb->ecode = TDB_ERR_RDONLY;
+ return -1;
+ }
+
+ if (tdb->methods->tdb_oob(tdb, off + len, 0) != 0)
+ return -1;
+
+ if (tdb->map_ptr) {
+ memcpy(off + (char *)tdb->map_ptr, buf, len);
+ } else {
+ ssize_t written = pwrite(tdb->fd, buf, len, off);
+ if ((written != (ssize_t)len) && (written != -1)) {
+ /* try once more */
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: wrote only "
+ "%d of %d bytes at %d, trying once more\n",
+ (int)written, len, off));
+ errno = ENOSPC;
+ written = pwrite(tdb->fd, (const void *)((const char *)buf+written),
+ len-written,
+ off+written);
+ }
+ if (written == -1) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_write failed at %d "
+ "len=%d (%s)\n", off, len, strerror(errno)));
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+ } else if (written != (ssize_t)len) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: failed to "
+ "write %d bytes at %d in two attempts\n",
+ len, off));
+ errno = ENOSPC;
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+ }
+ }
+ return 0;
+}
+
+/* Endian conversion: we only ever deal with 4 byte quantities */
+void *tdb_convert(void *buf, uint32_t size)
+{
+ uint32_t i, *p = (uint32_t *)buf;
+ for (i = 0; i < size / 4; i++)
+ p[i] = TDB_BYTEREV(p[i]);
+ return buf;
+}
+
+
+/* read a lump of data at a specified offset, maybe convert */
+static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
+ tdb_len_t len, int cv)
+{
+ if (tdb->methods->tdb_oob(tdb, off + len, 0) != 0) {
+ return -1;
+ }
+
+ if (tdb->map_ptr) {
+ memcpy(buf, off + (char *)tdb->map_ptr, len);
+ } else {
+ ssize_t ret = pread(tdb->fd, buf, len, off);
+ if (ret != (ssize_t)len) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_read failed at %d "
+ "len=%d ret=%d (%s) map_size=%d\n",
+ (int)off, (int)len, (int)ret, strerror(errno),
+ (int)tdb->map_size));
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+ }
+ }
+ if (cv) {
+ tdb_convert(buf, len);
+ }
+ return 0;
+}
+
+
+
+/*
+ do an unlocked scan of the hash table heads to find the next non-zero head. The value
+ will then be confirmed with the lock held
+*/
+static void tdb_next_hash_chain(struct tdb_context *tdb, uint32_t *chain)
+{
+ uint32_t h = *chain;
+ if (tdb->map_ptr) {
+ for (;h < tdb->header.hash_size;h++) {
+ if (0 != *(uint32_t *)(TDB_HASH_TOP(h) + (unsigned char *)tdb->map_ptr)) {
+ break;
+ }
+ }
+ } else {
+ uint32_t off=0;
+ for (;h < tdb->header.hash_size;h++) {
+ if (tdb_ofs_read(tdb, TDB_HASH_TOP(h), &off) != 0 || off != 0) {
+ break;
+ }
+ }
+ }
+ (*chain) = h;
+}
+
+
+int tdb_munmap(struct tdb_context *tdb)
+{
+ if (tdb->flags & TDB_INTERNAL)
+ return 0;
+
+#ifdef HAVE_MMAP
+ if (tdb->map_ptr) {
+ int ret;
+
+ ret = munmap(tdb->map_ptr, tdb->map_size);
+ if (ret != 0)
+ return ret;
+ }
+#endif
+ tdb->map_ptr = NULL;
+ return 0;
+}
+
+void tdb_mmap(struct tdb_context *tdb)
+{
+ if (tdb->flags & TDB_INTERNAL)
+ return;
+
+#ifdef HAVE_MMAP
+ if (!(tdb->flags & TDB_NOMMAP)) {
+ tdb->map_ptr = mmap(NULL, tdb->map_size,
+ PROT_READ|(tdb->read_only? 0:PROT_WRITE),
+ MAP_SHARED|MAP_FILE, tdb->fd, 0);
+
+ /*
+ * NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!!
+ */
+
+ if (tdb->map_ptr == MAP_FAILED) {
+ tdb->map_ptr = NULL;
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %d (%s)\n",
+ tdb->map_size, strerror(errno)));
+ }
+ } else {
+ tdb->map_ptr = NULL;
+ }
+#else
+ tdb->map_ptr = NULL;
+#endif
+}
+
+/* expand a file. we prefer to use ftruncate, as that is what posix
+ says to use for mmap expansion */
+static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t addition)
+{
+ char buf[8192];
+
+ if (tdb->read_only || tdb->traverse_read) {
+ tdb->ecode = TDB_ERR_RDONLY;
+ return -1;
+ }
+
+ if (ftruncate(tdb->fd, size+addition) == -1) {
+ char b = 0;
+ ssize_t written = pwrite(tdb->fd, &b, 1, (size+addition) - 1);
+ if (written == 0) {
+ /* try once more, potentially revealing errno */
+ written = pwrite(tdb->fd, &b, 1, (size+addition) - 1);
+ }
+ if (written == 0) {
+ /* again - give up, guessing errno */
+ errno = ENOSPC;
+ }
+ if (written != 1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %d failed (%s)\n",
+ size+addition, strerror(errno)));
+ return -1;
+ }
+ }
+
+ /* now fill the file with something. This ensures that the
+ file isn't sparse, which would be very bad if we ran out of
+ disk. This must be done with write, not via mmap */
+ memset(buf, TDB_PAD_BYTE, sizeof(buf));
+ while (addition) {
+ size_t n = addition>sizeof(buf)?sizeof(buf):addition;
+ ssize_t written = pwrite(tdb->fd, buf, n, size);
+ if (written == 0) {
+ /* prevent infinite loops: try _once_ more */
+ written = pwrite(tdb->fd, buf, n, size);
+ }
+ if (written == 0) {
+ /* give up, trying to provide a useful errno */
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
+ "returned 0 twice: giving up!\n"));
+ errno = ENOSPC;
+ return -1;
+ } else if (written == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of "
+ "%d bytes failed (%s)\n", (int)n,
+ strerror(errno)));
+ return -1;
+ } else if (written != n) {
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: wrote "
+ "only %d of %d bytes - retrying\n", (int)written,
+ (int)n));
+ }
+ addition -= written;
+ size += written;
+ }
+ return 0;
+}
+
+
+/* expand the database at least size bytes by expanding the underlying
+ file and doing the mmap again if necessary */
+int tdb_expand(struct tdb_context *tdb, tdb_off_t size)
+{
+ struct list_struct rec;
+ tdb_off_t offset, new_size;
+
+ if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "lock failed in tdb_expand\n"));
+ return -1;
+ }
+
+ /* must know about any previous expansions by another process */
+ tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1);
+
+ /* always make room for at least 100 more records, and at
+ least 25% more space. Round the database up to a multiple
+ of the page size */
+ new_size = MAX(tdb->map_size + size*100, tdb->map_size * 1.25);
+ size = TDB_ALIGN(new_size, tdb->page_size) - tdb->map_size;
+
+ if (!(tdb->flags & TDB_INTERNAL))
+ tdb_munmap(tdb);
+
+ /*
+ * We must ensure the file is unmapped before doing this
+ * to ensure consistency with systems like OpenBSD where
+ * writes and mmaps are not consistent.
+ */
+
+ /* expand the file itself */
+ if (!(tdb->flags & TDB_INTERNAL)) {
+ if (tdb->methods->tdb_expand_file(tdb, tdb->map_size, size) != 0)
+ goto fail;
+ }
+
+ tdb->map_size += size;
+
+ if (tdb->flags & TDB_INTERNAL) {
+ char *new_map_ptr = (char *)realloc(tdb->map_ptr,
+ tdb->map_size);
+ if (!new_map_ptr) {
+ tdb->map_size -= size;
+ goto fail;
+ }
+ tdb->map_ptr = new_map_ptr;
+ } else {
+ /*
+ * We must ensure the file is remapped before adding the space
+ * to ensure consistency with systems like OpenBSD where
+ * writes and mmaps are not consistent.
+ */
+
+ /* We're ok if the mmap fails as we'll fallback to read/write */
+ tdb_mmap(tdb);
+ }
+
+ /* form a new freelist record */
+ memset(&rec,'\0',sizeof(rec));
+ rec.rec_len = size - sizeof(rec);
+
+ /* link it into the free list */
+ offset = tdb->map_size - size;
+ if (tdb_free(tdb, offset, &rec) == -1)
+ goto fail;
+
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return 0;
+ fail:
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return -1;
+}
+
+/* read/write a tdb_off_t */
+int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d)
+{
+ return tdb->methods->tdb_read(tdb, offset, (char*)d, sizeof(*d), DOCONV());
+}
+
+int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d)
+{
+ tdb_off_t off = *d;
+ return tdb->methods->tdb_write(tdb, offset, CONVERT(off), sizeof(*d));
+}
+
+
+/* read a lump of data, allocating the space for it */
+unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len)
+{
+ unsigned char *buf;
+
+ /* some systems don't like zero length malloc */
+ if (len == 0) {
+ len = 1;
+ }
+
+ if (!(buf = (unsigned char *)malloc(len))) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_OOM;
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_alloc_read malloc failed len=%d (%s)\n",
+ len, strerror(errno)));
+ return TDB_ERRCODE(TDB_ERR_OOM, buf);
+ }
+ if (tdb->methods->tdb_read(tdb, offset, buf, len, 0) == -1) {
+ SAFE_FREE(buf);
+ return NULL;
+ }
+ return buf;
+}
+
+/* Give a piece of tdb data to a parser */
+
+int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key,
+ tdb_off_t offset, tdb_len_t len,
+ int (*parser)(TDB_DATA key, TDB_DATA data,
+ void *private_data),
+ void *private_data)
+{
+ TDB_DATA data;
+ int result;
+
+ data.dsize = len;
+
+ if ((tdb->transaction == NULL) && (tdb->map_ptr != NULL)) {
+ /*
+ * Optimize by avoiding the malloc/memcpy/free, point the
+ * parser directly at the mmap area.
+ */
+ if (tdb->methods->tdb_oob(tdb, offset+len, 0) != 0) {
+ return -1;
+ }
+ data.dptr = offset + (unsigned char *)tdb->map_ptr;
+ return parser(key, data, private_data);
+ }
+
+ if (!(data.dptr = tdb_alloc_read(tdb, offset, len))) {
+ return -1;
+ }
+
+ result = parser(key, data, private_data);
+ free(data.dptr);
+ return result;
+}
+
+/* read/write a record */
+int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec)
+{
+ if (tdb->methods->tdb_read(tdb, offset, rec, sizeof(*rec),DOCONV()) == -1)
+ return -1;
+ if (TDB_BAD_MAGIC(rec)) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_CORRUPT;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_rec_read bad magic 0x%x at offset=%d\n", rec->magic, offset));
+ return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
+ }
+ return tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0);
+}
+
+int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec)
+{
+ struct list_struct r = *rec;
+ return tdb->methods->tdb_write(tdb, offset, CONVERT(r), sizeof(r));
+}
+
+static const struct tdb_methods io_methods = {
+ tdb_read,
+ tdb_write,
+ tdb_next_hash_chain,
+ tdb_oob,
+ tdb_expand_file,
+ tdb_brlock
+};
+
+/*
+ initialise the default methods table
+*/
+void tdb_io_init(struct tdb_context *tdb)
+{
+ tdb->methods = &io_methods;
+}
diff --git a/source3/lib/tdb/common/lock.c b/source3/lib/tdb/common/lock.c
new file mode 100644
index 0000000000..f156c0fa7b
--- /dev/null
+++ b/source3/lib/tdb/common/lock.c
@@ -0,0 +1,553 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2005
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+#define TDB_MARK_LOCK 0x80000000
+
+void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *ptr)
+{
+ tdb->interrupt_sig_ptr = ptr;
+}
+
+/* a byte range locking function - return 0 on success
+ this functions locks/unlocks 1 byte at the specified offset.
+
+ On error, errno is also set so that errors are passed back properly
+ through tdb_open().
+
+ note that a len of zero means lock to end of file
+*/
+int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset,
+ int rw_type, int lck_type, int probe, size_t len)
+{
+ struct flock fl;
+ int ret;
+
+ if (tdb->flags & TDB_NOLOCK) {
+ return 0;
+ }
+
+ if ((rw_type == F_WRLCK) && (tdb->read_only || tdb->traverse_read)) {
+ tdb->ecode = TDB_ERR_RDONLY;
+ return -1;
+ }
+
+ fl.l_type = rw_type;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = offset;
+ fl.l_len = len;
+ fl.l_pid = 0;
+
+ do {
+ ret = fcntl(tdb->fd,lck_type,&fl);
+
+ /* Check for a sigalarm break. */
+ if (ret == -1 && errno == EINTR &&
+ tdb->interrupt_sig_ptr &&
+ *tdb->interrupt_sig_ptr) {
+ break;
+ }
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret == -1) {
+ /* Generic lock error. errno set by fcntl.
+ * EAGAIN is an expected return from non-blocking
+ * locks. */
+ if (!probe && lck_type != F_SETLK) {
+ /* Ensure error code is set for log fun to examine. */
+ tdb->ecode = TDB_ERR_LOCK;
+ TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d len=%d\n",
+ tdb->fd, offset, rw_type, lck_type, (int)len));
+ }
+ return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+ }
+ return 0;
+}
+
+
+/*
+ upgrade a read lock to a write lock. This needs to be handled in a
+ special way as some OSes (such as solaris) have too conservative
+ deadlock detection and claim a deadlock when progress can be
+ made. For those OSes we may loop for a while.
+*/
+int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len)
+{
+ int count = 1000;
+ while (count--) {
+ struct timeval tv;
+ if (tdb_brlock(tdb, offset, F_WRLCK, F_SETLKW, 1, len) == 0) {
+ return 0;
+ }
+ if (errno != EDEADLK) {
+ break;
+ }
+ /* sleep for as short a time as we can - more portable than usleep() */
+ tv.tv_sec = 0;
+ tv.tv_usec = 1;
+ select(0, NULL, NULL, NULL, &tv);
+ }
+ TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock_upgrade failed at offset %d\n", offset));
+ return -1;
+}
+
+
+/* lock a list in the database. list -1 is the alloc list */
+static int _tdb_lock(struct tdb_context *tdb, int list, int ltype, int op)
+{
+ struct tdb_lock_type *new_lck;
+ int i;
+ bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK);
+
+ ltype &= ~TDB_MARK_LOCK;
+
+ /* a global lock allows us to avoid per chain locks */
+ if (tdb->global_lock.count &&
+ (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) {
+ return 0;
+ }
+
+ if (tdb->global_lock.count) {
+ return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+ }
+
+ if (list < -1 || list >= (int)tdb->header.hash_size) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid list %d for ltype=%d\n",
+ list, ltype));
+ return -1;
+ }
+ if (tdb->flags & TDB_NOLOCK)
+ return 0;
+
+ for (i=0; i<tdb->num_lockrecs; i++) {
+ if (tdb->lockrecs[i].list == list) {
+ if (tdb->lockrecs[i].count == 0) {
+ /*
+ * Can't happen, see tdb_unlock(). It should
+ * be an assert.
+ */
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock: "
+ "lck->count == 0 for list %d", list));
+ }
+ /*
+ * Just increment the in-memory struct, posix locks
+ * don't stack.
+ */
+ tdb->lockrecs[i].count++;
+ return 0;
+ }
+ }
+
+ new_lck = (struct tdb_lock_type *)realloc(
+ tdb->lockrecs,
+ sizeof(*tdb->lockrecs) * (tdb->num_lockrecs+1));
+ if (new_lck == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+ tdb->lockrecs = new_lck;
+
+ /* Since fcntl locks don't nest, we do a lock for the first one,
+ and simply bump the count for future ones */
+ if (!mark_lock &&
+ tdb->methods->tdb_brlock(tdb,FREELIST_TOP+4*list, ltype, op,
+ 0, 1)) {
+ return -1;
+ }
+
+ tdb->num_locks++;
+
+ tdb->lockrecs[tdb->num_lockrecs].list = list;
+ tdb->lockrecs[tdb->num_lockrecs].count = 1;
+ tdb->lockrecs[tdb->num_lockrecs].ltype = ltype;
+ tdb->num_lockrecs += 1;
+
+ return 0;
+}
+
+/* lock a list in the database. list -1 is the alloc list */
+int tdb_lock(struct tdb_context *tdb, int list, int ltype)
+{
+ int ret;
+ ret = _tdb_lock(tdb, list, ltype, F_SETLKW);
+ if (ret) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d "
+ "ltype=%d (%s)\n", list, ltype, strerror(errno)));
+ }
+ return ret;
+}
+
+/* lock a list in the database. list -1 is the alloc list. non-blocking lock */
+int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype)
+{
+ return _tdb_lock(tdb, list, ltype, F_SETLK);
+}
+
+
+/* unlock the database: returns void because it's too late for errors. */
+ /* changed to return int it may be interesting to know there
+ has been an error --simo */
+int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
+{
+ int ret = -1;
+ int i;
+ struct tdb_lock_type *lck = NULL;
+ bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK);
+
+ ltype &= ~TDB_MARK_LOCK;
+
+ /* a global lock allows us to avoid per chain locks */
+ if (tdb->global_lock.count &&
+ (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) {
+ return 0;
+ }
+
+ if (tdb->global_lock.count) {
+ return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+ }
+
+ if (tdb->flags & TDB_NOLOCK)
+ return 0;
+
+ /* Sanity checks */
+ if (list < -1 || list >= (int)tdb->header.hash_size) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: list %d invalid (%d)\n", list, tdb->header.hash_size));
+ return ret;
+ }
+
+ for (i=0; i<tdb->num_lockrecs; i++) {
+ if (tdb->lockrecs[i].list == list) {
+ lck = &tdb->lockrecs[i];
+ break;
+ }
+ }
+
+ if ((lck == NULL) || (lck->count == 0)) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: count is 0\n"));
+ return -1;
+ }
+
+ if (lck->count > 1) {
+ lck->count--;
+ return 0;
+ }
+
+ /*
+ * This lock has count==1 left, so we need to unlock it in the
+ * kernel. We don't bother with decrementing the in-memory array
+ * element, we're about to overwrite it with the last array element
+ * anyway.
+ */
+
+ if (mark_lock) {
+ ret = 0;
+ } else {
+ ret = tdb->methods->tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK,
+ F_SETLKW, 0, 1);
+ }
+ tdb->num_locks--;
+
+ /*
+ * Shrink the array by overwriting the element just unlocked with the
+ * last array element.
+ */
+
+ if (tdb->num_lockrecs > 1) {
+ *lck = tdb->lockrecs[tdb->num_lockrecs-1];
+ }
+ tdb->num_lockrecs -= 1;
+
+ /*
+ * We don't bother with realloc when the array shrinks, but if we have
+ * a completely idle tdb we should get rid of the locked array.
+ */
+
+ if (tdb->num_lockrecs == 0) {
+ SAFE_FREE(tdb->lockrecs);
+ }
+
+ if (ret)
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: An error occurred unlocking!\n"));
+ return ret;
+}
+
+/*
+ get the transaction lock
+ */
+int tdb_transaction_lock(struct tdb_context *tdb, int ltype)
+{
+ if (tdb->have_transaction_lock || tdb->global_lock.count) {
+ return 0;
+ }
+ if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, ltype,
+ F_SETLKW, 0, 1) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_lock: failed to get transaction lock\n"));
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+ tdb->have_transaction_lock = 1;
+ return 0;
+}
+
+/*
+ release the transaction lock
+ */
+int tdb_transaction_unlock(struct tdb_context *tdb)
+{
+ int ret;
+ if (!tdb->have_transaction_lock) {
+ return 0;
+ }
+ ret = tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1);
+ if (ret == 0) {
+ tdb->have_transaction_lock = 0;
+ }
+ return ret;
+}
+
+
+
+
+/* lock/unlock entire database */
+static int _tdb_lockall(struct tdb_context *tdb, int ltype, int op)
+{
+ bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK);
+
+ ltype &= ~TDB_MARK_LOCK;
+
+ /* There are no locks on read-only dbs */
+ if (tdb->read_only || tdb->traverse_read)
+ return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+
+ if (tdb->global_lock.count && tdb->global_lock.ltype == ltype) {
+ tdb->global_lock.count++;
+ return 0;
+ }
+
+ if (tdb->global_lock.count) {
+ /* a global lock of a different type exists */
+ return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+ }
+
+ if (tdb->num_locks != 0) {
+ /* can't combine global and chain locks */
+ return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+ }
+
+ if (!mark_lock &&
+ tdb->methods->tdb_brlock(tdb, FREELIST_TOP, ltype, op,
+ 0, 4*tdb->header.hash_size)) {
+ if (op == F_SETLKW) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lockall failed (%s)\n", strerror(errno)));
+ }
+ return -1;
+ }
+
+ tdb->global_lock.count = 1;
+ tdb->global_lock.ltype = ltype;
+
+ return 0;
+}
+
+
+
+/* unlock entire db */
+static int _tdb_unlockall(struct tdb_context *tdb, int ltype)
+{
+ bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK);
+
+ ltype &= ~TDB_MARK_LOCK;
+
+ /* There are no locks on read-only dbs */
+ if (tdb->read_only || tdb->traverse_read) {
+ return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+ }
+
+ if (tdb->global_lock.ltype != ltype || tdb->global_lock.count == 0) {
+ return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+ }
+
+ if (tdb->global_lock.count > 1) {
+ tdb->global_lock.count--;
+ return 0;
+ }
+
+ if (!mark_lock &&
+ tdb->methods->tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW,
+ 0, 4*tdb->header.hash_size)) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlockall failed (%s)\n", strerror(errno)));
+ return -1;
+ }
+
+ tdb->global_lock.count = 0;
+ tdb->global_lock.ltype = 0;
+
+ return 0;
+}
+
+/* lock entire database with write lock */
+int tdb_lockall(struct tdb_context *tdb)
+{
+ return _tdb_lockall(tdb, F_WRLCK, F_SETLKW);
+}
+
+/* lock entire database with write lock - mark only */
+int tdb_lockall_mark(struct tdb_context *tdb)
+{
+ return _tdb_lockall(tdb, F_WRLCK | TDB_MARK_LOCK, F_SETLKW);
+}
+
+/* unlock entire database with write lock - unmark only */
+int tdb_lockall_unmark(struct tdb_context *tdb)
+{
+ return _tdb_unlockall(tdb, F_WRLCK | TDB_MARK_LOCK);
+}
+
+/* lock entire database with write lock - nonblocking varient */
+int tdb_lockall_nonblock(struct tdb_context *tdb)
+{
+ return _tdb_lockall(tdb, F_WRLCK, F_SETLK);
+}
+
+/* unlock entire database with write lock */
+int tdb_unlockall(struct tdb_context *tdb)
+{
+ return _tdb_unlockall(tdb, F_WRLCK);
+}
+
+/* lock entire database with read lock */
+int tdb_lockall_read(struct tdb_context *tdb)
+{
+ return _tdb_lockall(tdb, F_RDLCK, F_SETLKW);
+}
+
+/* lock entire database with read lock - nonblock varient */
+int tdb_lockall_read_nonblock(struct tdb_context *tdb)
+{
+ return _tdb_lockall(tdb, F_RDLCK, F_SETLK);
+}
+
+/* unlock entire database with read lock */
+int tdb_unlockall_read(struct tdb_context *tdb)
+{
+ return _tdb_unlockall(tdb, F_RDLCK);
+}
+
+/* lock/unlock one hash chain. This is meant to be used to reduce
+ contention - it cannot guarantee how many records will be locked */
+int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key)
+{
+ return tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
+}
+
+/* lock/unlock one hash chain, non-blocking. This is meant to be used
+ to reduce contention - it cannot guarantee how many records will be
+ locked */
+int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key)
+{
+ return tdb_lock_nonblock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
+}
+
+/* mark a chain as locked without actually locking it. Warning! use with great caution! */
+int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key)
+{
+ return tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK);
+}
+
+/* unmark a chain as locked without actually locking it. Warning! use with great caution! */
+int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key)
+{
+ return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK);
+}
+
+int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key)
+{
+ return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
+}
+
+int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key)
+{
+ return tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK);
+}
+
+int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key)
+{
+ return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK);
+}
+
+
+
+/* record lock stops delete underneath */
+int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off)
+{
+ if (tdb->global_lock.count) {
+ return 0;
+ }
+ return off ? tdb->methods->tdb_brlock(tdb, off, F_RDLCK, F_SETLKW, 0, 1) : 0;
+}
+
+/*
+ Write locks override our own fcntl readlocks, so check it here.
+ Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not
+ an error to fail to get the lock here.
+*/
+int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off)
+{
+ struct tdb_traverse_lock *i;
+ for (i = &tdb->travlocks; i; i = i->next)
+ if (i->off == off)
+ return -1;
+ return tdb->methods->tdb_brlock(tdb, off, F_WRLCK, F_SETLK, 1, 1);
+}
+
+/*
+ Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not
+ an error to fail to get the lock here.
+*/
+int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off)
+{
+ return tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLK, 0, 1);
+}
+
+/* fcntl locks don't stack: avoid unlocking someone else's */
+int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off)
+{
+ struct tdb_traverse_lock *i;
+ uint32_t count = 0;
+
+ if (tdb->global_lock.count) {
+ return 0;
+ }
+
+ if (off == 0)
+ return 0;
+ for (i = &tdb->travlocks; i; i = i->next)
+ if (i->off == off)
+ count++;
+ return (count == 1 ? tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLKW, 0, 1) : 0);
+}
diff --git a/source3/lib/tdb/common/open.c b/source3/lib/tdb/common/open.c
new file mode 100644
index 0000000000..b19e4cea29
--- /dev/null
+++ b/source3/lib/tdb/common/open.c
@@ -0,0 +1,488 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2005
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+/* all contexts, to ensure no double-opens (fcntl locks don't nest!) */
+static struct tdb_context *tdbs = NULL;
+
+
+/* This is based on the hash algorithm from gdbm */
+static unsigned int default_tdb_hash(TDB_DATA *key)
+{
+ uint32_t value; /* Used to compute the hash value. */
+ uint32_t i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++)
+ value = (value + (key->dptr[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345);
+}
+
+
+/* initialise a new database with a specified hash size */
+static int tdb_new_database(struct tdb_context *tdb, int hash_size)
+{
+ struct tdb_header *newdb;
+ size_t size;
+ int ret = -1;
+ ssize_t written;
+
+ /* We make it up in memory, then write it out if not internal */
+ size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off_t);
+ if (!(newdb = (struct tdb_header *)calloc(size, 1)))
+ return TDB_ERRCODE(TDB_ERR_OOM, -1);
+
+ /* Fill in the header */
+ newdb->version = TDB_VERSION;
+ newdb->hash_size = hash_size;
+ if (tdb->flags & TDB_INTERNAL) {
+ tdb->map_size = size;
+ tdb->map_ptr = (char *)newdb;
+ memcpy(&tdb->header, newdb, sizeof(tdb->header));
+ /* Convert the `ondisk' version if asked. */
+ CONVERT(*newdb);
+ return 0;
+ }
+ if (lseek(tdb->fd, 0, SEEK_SET) == -1)
+ goto fail;
+
+ if (ftruncate(tdb->fd, 0) == -1)
+ goto fail;
+
+ /* This creates an endian-converted header, as if read from disk */
+ CONVERT(*newdb);
+ memcpy(&tdb->header, newdb, sizeof(tdb->header));
+ /* Don't endian-convert the magic food! */
+ memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
+ /* we still have "ret == -1" here */
+ written = write(tdb->fd, newdb, size);
+ if (written == size) {
+ ret = 0;
+ } else if (written != -1) {
+ /* call write once again, this usually should return -1 and
+ * set errno appropriately */
+ size -= written;
+ written = write(tdb->fd, newdb+written, size);
+ if (written == size) {
+ ret = 0;
+ } else if (written >= 0) {
+ /* a second incomplete write - we give up.
+ * guessing the errno... */
+ errno = ENOSPC;
+ }
+ }
+
+ fail:
+ SAFE_FREE(newdb);
+ return ret;
+}
+
+
+
+static int tdb_already_open(dev_t device,
+ ino_t ino)
+{
+ struct tdb_context *i;
+
+ for (i = tdbs; i; i = i->next) {
+ if (i->device == device && i->inode == ino) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* open the database, creating it if necessary
+
+ The open_flags and mode are passed straight to the open call on the
+ database file. A flags value of O_WRONLY is invalid. The hash size
+ is advisory, use zero for a default value.
+
+ Return is NULL on error, in which case errno is also set. Don't
+ try to call tdb_error or tdb_errname, just do strerror(errno).
+
+ @param name may be NULL for internal databases. */
+struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode)
+{
+ return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL, NULL);
+}
+
+/* a default logging function */
+static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
+static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
+{
+}
+
+
+struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode,
+ const struct tdb_logging_context *log_ctx,
+ tdb_hash_func hash_fn)
+{
+ struct tdb_context *tdb;
+ struct stat st;
+ int rev = 0, locked = 0;
+ unsigned char *vp;
+ uint32_t vertest;
+ unsigned v;
+
+ if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) {
+ /* Can't log this */
+ errno = ENOMEM;
+ goto fail;
+ }
+ tdb_io_init(tdb);
+ tdb->fd = -1;
+ tdb->name = NULL;
+ tdb->map_ptr = NULL;
+ tdb->flags = tdb_flags;
+ tdb->open_flags = open_flags;
+ if (log_ctx) {
+ tdb->log = *log_ctx;
+ } else {
+ tdb->log.log_fn = null_log_fn;
+ tdb->log.log_private = NULL;
+ }
+ tdb->hash_fn = hash_fn ? hash_fn : default_tdb_hash;
+
+ /* cache the page size */
+ tdb->page_size = getpagesize();
+ if (tdb->page_size <= 0) {
+ tdb->page_size = 0x2000;
+ }
+
+ tdb->max_dead_records = (tdb_flags & TDB_VOLATILE) ? 5 : 0;
+
+ if ((open_flags & O_ACCMODE) == O_WRONLY) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't open tdb %s write-only\n",
+ name));
+ errno = EINVAL;
+ goto fail;
+ }
+
+ if (hash_size == 0)
+ hash_size = DEFAULT_HASH_SIZE;
+ if ((open_flags & O_ACCMODE) == O_RDONLY) {
+ tdb->read_only = 1;
+ /* read only databases don't do locking or clear if first */
+ tdb->flags |= TDB_NOLOCK;
+ tdb->flags &= ~TDB_CLEAR_IF_FIRST;
+ }
+
+ /* internal databases don't mmap or lock, and start off cleared */
+ if (tdb->flags & TDB_INTERNAL) {
+ tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
+ tdb->flags &= ~TDB_CLEAR_IF_FIRST;
+ if (tdb_new_database(tdb, hash_size) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: tdb_new_database failed!"));
+ goto fail;
+ }
+ goto internal;
+ }
+
+ if ((tdb->fd = open(name, open_flags, mode)) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_open_ex: could not open file %s: %s\n",
+ name, strerror(errno)));
+ goto fail; /* errno set by open(2) */
+ }
+
+ /* on exec, don't inherit the fd */
+ v = fcntl(tdb->fd, F_GETFD, 0);
+ fcntl(tdb->fd, F_SETFD, v | FD_CLOEXEC);
+
+ /* ensure there is only one process initialising at once */
+ if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get global lock on %s: %s\n",
+ name, strerror(errno)));
+ goto fail; /* errno set by tdb_brlock */
+ }
+
+ /* we need to zero database if we are the only one with it open */
+ if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
+ (!tdb->read_only) &&
+ (locked = (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0, 1) == 0))) {
+ open_flags |= O_CREAT;
+ if (ftruncate(tdb->fd, 0) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "failed to truncate %s: %s\n",
+ name, strerror(errno)));
+ goto fail; /* errno set by ftruncate */
+ }
+ }
+
+ errno = 0;
+ if (read(tdb->fd, &tdb->header, sizeof(tdb->header)) != sizeof(tdb->header)
+ || strcmp(tdb->header.magic_food, TDB_MAGIC_FOOD) != 0
+ || (tdb->header.version != TDB_VERSION
+ && !(rev = (tdb->header.version==TDB_BYTEREV(TDB_VERSION))))) {
+ /* its not a valid database - possibly initialise it */
+ if (!(open_flags & O_CREAT) || tdb_new_database(tdb, hash_size) == -1) {
+ if (errno == 0) {
+ errno = EIO; /* ie bad format or something */
+ }
+ goto fail;
+ }
+ rev = (tdb->flags & TDB_CONVERT);
+ }
+ vp = (unsigned char *)&tdb->header.version;
+ vertest = (((uint32_t)vp[0]) << 24) | (((uint32_t)vp[1]) << 16) |
+ (((uint32_t)vp[2]) << 8) | (uint32_t)vp[3];
+ tdb->flags |= (vertest==TDB_VERSION) ? TDB_BIGENDIAN : 0;
+ if (!rev)
+ tdb->flags &= ~TDB_CONVERT;
+ else {
+ tdb->flags |= TDB_CONVERT;
+ tdb_convert(&tdb->header, sizeof(tdb->header));
+ }
+ if (fstat(tdb->fd, &st) == -1)
+ goto fail;
+
+ if (tdb->header.rwlocks != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n"));
+ goto fail;
+ }
+
+ /* Is it already in the open list? If so, fail. */
+ if (tdb_already_open(st.st_dev, st.st_ino)) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
+ "%s (%d,%d) is already open in this process\n",
+ name, (int)st.st_dev, (int)st.st_ino));
+ errno = EBUSY;
+ goto fail;
+ }
+
+ if (!(tdb->name = (char *)strdup(name))) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ tdb->map_size = st.st_size;
+ tdb->device = st.st_dev;
+ tdb->inode = st.st_ino;
+ tdb_mmap(tdb);
+ if (locked) {
+ if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0, 1) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
+ "failed to take ACTIVE_LOCK on %s: %s\n",
+ name, strerror(errno)));
+ goto fail;
+ }
+
+ }
+
+ /* We always need to do this if the CLEAR_IF_FIRST flag is set, even if
+ we didn't get the initial exclusive lock as we need to let all other
+ users know we're using it. */
+
+ if (tdb_flags & TDB_CLEAR_IF_FIRST) {
+ /* leave this lock in place to indicate it's in use */
+ if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)
+ goto fail;
+ }
+
+ /* if needed, run recovery */
+ if (tdb_transaction_recover(tdb) == -1) {
+ goto fail;
+ }
+
+ internal:
+ /* Internal (memory-only) databases skip all the code above to
+ * do with disk files, and resume here by releasing their
+ * global lock and hooking into the active list. */
+ if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1) == -1)
+ goto fail;
+ tdb->next = tdbs;
+ tdbs = tdb;
+ return tdb;
+
+ fail:
+ { int save_errno = errno;
+
+ if (!tdb)
+ return NULL;
+
+ if (tdb->map_ptr) {
+ if (tdb->flags & TDB_INTERNAL)
+ SAFE_FREE(tdb->map_ptr);
+ else
+ tdb_munmap(tdb);
+ }
+ SAFE_FREE(tdb->name);
+ if (tdb->fd != -1)
+ if (close(tdb->fd) != 0)
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n"));
+ SAFE_FREE(tdb);
+ errno = save_errno;
+ return NULL;
+ }
+}
+
+/*
+ * Set the maximum number of dead records per hash chain
+ */
+
+void tdb_set_max_dead(struct tdb_context *tdb, int max_dead)
+{
+ tdb->max_dead_records = max_dead;
+}
+
+/**
+ * Close a database.
+ *
+ * @returns -1 for error; 0 for success.
+ **/
+int tdb_close(struct tdb_context *tdb)
+{
+ struct tdb_context **i;
+ int ret = 0;
+
+ if (tdb->transaction) {
+ tdb_transaction_cancel(tdb);
+ }
+
+ if (tdb->map_ptr) {
+ if (tdb->flags & TDB_INTERNAL)
+ SAFE_FREE(tdb->map_ptr);
+ else
+ tdb_munmap(tdb);
+ }
+ SAFE_FREE(tdb->name);
+ if (tdb->fd != -1)
+ ret = close(tdb->fd);
+ SAFE_FREE(tdb->lockrecs);
+
+ /* Remove from contexts list */
+ for (i = &tdbs; *i; i = &(*i)->next) {
+ if (*i == tdb) {
+ *i = tdb->next;
+ break;
+ }
+ }
+
+ memset(tdb, 0, sizeof(*tdb));
+ SAFE_FREE(tdb);
+
+ return ret;
+}
+
+/* register a loging function */
+void tdb_set_logging_function(struct tdb_context *tdb,
+ const struct tdb_logging_context *log_ctx)
+{
+ tdb->log = *log_ctx;
+}
+
+void *tdb_get_logging_private(struct tdb_context *tdb)
+{
+ return tdb->log.log_private;
+}
+
+/* reopen a tdb - this can be used after a fork to ensure that we have an independent
+ seek pointer from our parent and to re-establish locks */
+int tdb_reopen(struct tdb_context *tdb)
+{
+ struct stat st;
+
+ if (tdb->flags & TDB_INTERNAL) {
+ return 0; /* Nothing to do. */
+ }
+
+ if (tdb->num_locks != 0 || tdb->global_lock.count) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed with locks held\n"));
+ goto fail;
+ }
+
+ if (tdb->transaction != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed inside a transaction\n"));
+ goto fail;
+ }
+
+ if (tdb_munmap(tdb) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: munmap failed (%s)\n", strerror(errno)));
+ goto fail;
+ }
+ if (close(tdb->fd) != 0)
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: WARNING closing tdb->fd failed!\n"));
+ tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0);
+ if (tdb->fd == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: open failed (%s)\n", strerror(errno)));
+ goto fail;
+ }
+ if ((tdb->flags & TDB_CLEAR_IF_FIRST) &&
+ (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n"));
+ goto fail;
+ }
+ if (fstat(tdb->fd, &st) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: fstat failed (%s)\n", strerror(errno)));
+ goto fail;
+ }
+ if (st.st_ino != tdb->inode || st.st_dev != tdb->device) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: file dev/inode has changed!\n"));
+ goto fail;
+ }
+ tdb_mmap(tdb);
+
+ return 0;
+
+fail:
+ tdb_close(tdb);
+ return -1;
+}
+
+/* reopen all tdb's */
+int tdb_reopen_all(int parent_longlived)
+{
+ struct tdb_context *tdb;
+
+ for (tdb=tdbs; tdb; tdb = tdb->next) {
+ /*
+ * If the parent is longlived (ie. a
+ * parent daemon architecture), we know
+ * it will keep it's active lock on a
+ * tdb opened with CLEAR_IF_FIRST. Thus
+ * for child processes we don't have to
+ * add an active lock. This is essential
+ * to improve performance on systems that
+ * keep POSIX locks as a non-scalable data
+ * structure in the kernel.
+ */
+ if (parent_longlived) {
+ /* Ensure no clear-if-first. */
+ tdb->flags &= ~TDB_CLEAR_IF_FIRST;
+ }
+
+ if (tdb_reopen(tdb) != 0)
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/source3/lib/tdb/common/tdb.c b/source3/lib/tdb/common/tdb.c
new file mode 100644
index 0000000000..c7cec297f6
--- /dev/null
+++ b/source3/lib/tdb/common/tdb.c
@@ -0,0 +1,802 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2005
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+TDB_DATA tdb_null;
+
+/*
+ non-blocking increment of the tdb sequence number if the tdb has been opened using
+ the TDB_SEQNUM flag
+*/
+void tdb_increment_seqnum_nonblock(struct tdb_context *tdb)
+{
+ tdb_off_t seqnum=0;
+
+ if (!(tdb->flags & TDB_SEQNUM)) {
+ return;
+ }
+
+ /* we ignore errors from this, as we have no sane way of
+ dealing with them.
+ */
+ tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
+ seqnum++;
+ tdb_ofs_write(tdb, TDB_SEQNUM_OFS, &seqnum);
+}
+
+/*
+ increment the tdb sequence number if the tdb has been opened using
+ the TDB_SEQNUM flag
+*/
+static void tdb_increment_seqnum(struct tdb_context *tdb)
+{
+ if (!(tdb->flags & TDB_SEQNUM)) {
+ return;
+ }
+
+ if (tdb_brlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, F_SETLKW, 1, 1) != 0) {
+ return;
+ }
+
+ tdb_increment_seqnum_nonblock(tdb);
+
+ tdb_brlock(tdb, TDB_SEQNUM_OFS, F_UNLCK, F_SETLKW, 1, 1);
+}
+
+static int tdb_key_compare(TDB_DATA key, TDB_DATA data, void *private_data)
+{
+ return memcmp(data.dptr, key.dptr, data.dsize);
+}
+
+/* Returns 0 on fail. On success, return offset of record, and fills
+ in rec */
+static tdb_off_t tdb_find(struct tdb_context *tdb, TDB_DATA key, uint32_t hash,
+ struct list_struct *r)
+{
+ tdb_off_t rec_ptr;
+
+ /* read in the hash top */
+ if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
+ return 0;
+
+ /* keep looking until we find the right record */
+ while (rec_ptr) {
+ if (tdb_rec_read(tdb, rec_ptr, r) == -1)
+ return 0;
+
+ if (!TDB_DEAD(r) && hash==r->full_hash
+ && key.dsize==r->key_len
+ && tdb_parse_data(tdb, key, rec_ptr + sizeof(*r),
+ r->key_len, tdb_key_compare,
+ NULL) == 0) {
+ return rec_ptr;
+ }
+ rec_ptr = r->next;
+ }
+ return TDB_ERRCODE(TDB_ERR_NOEXIST, 0);
+}
+
+/* As tdb_find, but if you succeed, keep the lock */
+tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype,
+ struct list_struct *rec)
+{
+ uint32_t rec_ptr;
+
+ if (tdb_lock(tdb, BUCKET(hash), locktype) == -1)
+ return 0;
+ if (!(rec_ptr = tdb_find(tdb, key, hash, rec)))
+ tdb_unlock(tdb, BUCKET(hash), locktype);
+ return rec_ptr;
+}
+
+
+/* update an entry in place - this only works if the new data size
+ is <= the old data size and the key exists.
+ on failure return -1.
+*/
+static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, TDB_DATA dbuf)
+{
+ struct list_struct rec;
+ tdb_off_t rec_ptr;
+
+ /* find entry */
+ if (!(rec_ptr = tdb_find(tdb, key, hash, &rec)))
+ return -1;
+
+ /* must be long enough key, data and tailer */
+ if (rec.rec_len < key.dsize + dbuf.dsize + sizeof(tdb_off_t)) {
+ tdb->ecode = TDB_SUCCESS; /* Not really an error */
+ return -1;
+ }
+
+ if (tdb->methods->tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
+ dbuf.dptr, dbuf.dsize) == -1)
+ return -1;
+
+ if (dbuf.dsize != rec.data_len) {
+ /* update size */
+ rec.data_len = dbuf.dsize;
+ return tdb_rec_write(tdb, rec_ptr, &rec);
+ }
+
+ return 0;
+}
+
+/* find an entry in the database given a key */
+/* If an entry doesn't exist tdb_err will be set to
+ * TDB_ERR_NOEXIST. If a key has no data attached
+ * then the TDB_DATA will have zero length but
+ * a non-zero pointer
+ */
+TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
+{
+ tdb_off_t rec_ptr;
+ struct list_struct rec;
+ TDB_DATA ret;
+ uint32_t hash;
+
+ /* find which hash bucket it is in */
+ hash = tdb->hash_fn(&key);
+ if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec)))
+ return tdb_null;
+
+ ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
+ rec.data_len);
+ ret.dsize = rec.data_len;
+ tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
+ return ret;
+}
+
+/*
+ * Find an entry in the database and hand the record's data to a parsing
+ * function. The parsing function is executed under the chain read lock, so it
+ * should be fast and should not block on other syscalls.
+ *
+ * DONT CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS.
+ *
+ * For mmapped tdb's that do not have a transaction open it points the parsing
+ * function directly at the mmap area, it avoids the malloc/memcpy in this
+ * case. If a transaction is open or no mmap is available, it has to do
+ * malloc/read/parse/free.
+ *
+ * This is interesting for all readers of potentially large data structures in
+ * the tdb records, ldb indexes being one example.
+ */
+
+int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
+ int (*parser)(TDB_DATA key, TDB_DATA data,
+ void *private_data),
+ void *private_data)
+{
+ tdb_off_t rec_ptr;
+ struct list_struct rec;
+ int ret;
+ uint32_t hash;
+
+ /* find which hash bucket it is in */
+ hash = tdb->hash_fn(&key);
+
+ if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) {
+ return TDB_ERRCODE(TDB_ERR_NOEXIST, 0);
+ }
+
+ ret = tdb_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len,
+ rec.data_len, parser, private_data);
+
+ tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
+
+ return ret;
+}
+
+/* check if an entry in the database exists
+
+ note that 1 is returned if the key is found and 0 is returned if not found
+ this doesn't match the conventions in the rest of this module, but is
+ compatible with gdbm
+*/
+static int tdb_exists_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
+{
+ struct list_struct rec;
+
+ if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0)
+ return 0;
+ tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
+ return 1;
+}
+
+int tdb_exists(struct tdb_context *tdb, TDB_DATA key)
+{
+ uint32_t hash = tdb->hash_fn(&key);
+ return tdb_exists_hash(tdb, key, hash);
+}
+
+/* actually delete an entry in the database given the offset */
+int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct list_struct *rec)
+{
+ tdb_off_t last_ptr, i;
+ struct list_struct lastrec;
+
+ if (tdb->read_only || tdb->traverse_read) return -1;
+
+ if (((tdb->traverse_write != 0) && (!TDB_DEAD(rec))) ||
+ tdb_write_lock_record(tdb, rec_ptr) == -1) {
+ /* Someone traversing here: mark it as dead */
+ rec->magic = TDB_DEAD_MAGIC;
+ return tdb_rec_write(tdb, rec_ptr, rec);
+ }
+ if (tdb_write_unlock_record(tdb, rec_ptr) != 0)
+ return -1;
+
+ /* find previous record in hash chain */
+ if (tdb_ofs_read(tdb, TDB_HASH_TOP(rec->full_hash), &i) == -1)
+ return -1;
+ for (last_ptr = 0; i != rec_ptr; last_ptr = i, i = lastrec.next)
+ if (tdb_rec_read(tdb, i, &lastrec) == -1)
+ return -1;
+
+ /* unlink it: next ptr is at start of record. */
+ if (last_ptr == 0)
+ last_ptr = TDB_HASH_TOP(rec->full_hash);
+ if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1)
+ return -1;
+
+ /* recover the space */
+ if (tdb_free(tdb, rec_ptr, rec) == -1)
+ return -1;
+ return 0;
+}
+
+static int tdb_count_dead(struct tdb_context *tdb, uint32_t hash)
+{
+ int res = 0;
+ tdb_off_t rec_ptr;
+ struct list_struct rec;
+
+ /* read in the hash top */
+ if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
+ return 0;
+
+ while (rec_ptr) {
+ if (tdb_rec_read(tdb, rec_ptr, &rec) == -1)
+ return 0;
+
+ if (rec.magic == TDB_DEAD_MAGIC) {
+ res += 1;
+ }
+ rec_ptr = rec.next;
+ }
+ return res;
+}
+
+/*
+ * Purge all DEAD records from a hash chain
+ */
+static int tdb_purge_dead(struct tdb_context *tdb, uint32_t hash)
+{
+ int res = -1;
+ struct list_struct rec;
+ tdb_off_t rec_ptr;
+
+ if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
+ return -1;
+ }
+
+ /* read in the hash top */
+ if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
+ goto fail;
+
+ while (rec_ptr) {
+ tdb_off_t next;
+
+ if (tdb_rec_read(tdb, rec_ptr, &rec) == -1) {
+ goto fail;
+ }
+
+ next = rec.next;
+
+ if (rec.magic == TDB_DEAD_MAGIC
+ && tdb_do_delete(tdb, rec_ptr, &rec) == -1) {
+ goto fail;
+ }
+ rec_ptr = next;
+ }
+ res = 0;
+ fail:
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return res;
+}
+
+/* delete an entry in the database given a key */
+static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
+{
+ tdb_off_t rec_ptr;
+ struct list_struct rec;
+ int ret;
+
+ if (tdb->max_dead_records != 0) {
+
+ /*
+ * Allow for some dead records per hash chain, mainly for
+ * tdb's with a very high create/delete rate like locking.tdb.
+ */
+
+ if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
+ return -1;
+
+ if (tdb_count_dead(tdb, hash) >= tdb->max_dead_records) {
+ /*
+ * Don't let the per-chain freelist grow too large,
+ * delete all existing dead records
+ */
+ tdb_purge_dead(tdb, hash);
+ }
+
+ if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) {
+ tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
+ return -1;
+ }
+
+ /*
+ * Just mark the record as dead.
+ */
+ rec.magic = TDB_DEAD_MAGIC;
+ ret = tdb_rec_write(tdb, rec_ptr, &rec);
+ }
+ else {
+ if (!(rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK,
+ &rec)))
+ return -1;
+
+ ret = tdb_do_delete(tdb, rec_ptr, &rec);
+ }
+
+ if (ret == 0) {
+ tdb_increment_seqnum(tdb);
+ }
+
+ if (tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK) != 0)
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_delete: WARNING tdb_unlock failed!\n"));
+ return ret;
+}
+
+int tdb_delete(struct tdb_context *tdb, TDB_DATA key)
+{
+ uint32_t hash = tdb->hash_fn(&key);
+ return tdb_delete_hash(tdb, key, hash);
+}
+
+/*
+ * See if we have a dead record around with enough space
+ */
+static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
+ struct list_struct *r, tdb_len_t length)
+{
+ tdb_off_t rec_ptr;
+
+ /* read in the hash top */
+ if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
+ return 0;
+
+ /* keep looking until we find the right record */
+ while (rec_ptr) {
+ if (tdb_rec_read(tdb, rec_ptr, r) == -1)
+ return 0;
+
+ if (TDB_DEAD(r) && r->rec_len >= length) {
+ /*
+ * First fit for simple coding, TODO: change to best
+ * fit
+ */
+ return rec_ptr;
+ }
+ rec_ptr = r->next;
+ }
+ return 0;
+}
+
+/* store an element in the database, replacing any existing element
+ with the same key
+
+ return 0 on success, -1 on failure
+*/
+int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
+{
+ struct list_struct rec;
+ uint32_t hash;
+ tdb_off_t rec_ptr;
+ char *p = NULL;
+ int ret = -1;
+
+ if (tdb->read_only || tdb->traverse_read) {
+ tdb->ecode = TDB_ERR_RDONLY;
+ return -1;
+ }
+
+ /* find which hash bucket it is in */
+ hash = tdb->hash_fn(&key);
+ if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
+ return -1;
+
+ /* check for it existing, on insert. */
+ if (flag == TDB_INSERT) {
+ if (tdb_exists_hash(tdb, key, hash)) {
+ tdb->ecode = TDB_ERR_EXISTS;
+ goto fail;
+ }
+ } else {
+ /* first try in-place update, on modify or replace. */
+ if (tdb_update_hash(tdb, key, hash, dbuf) == 0) {
+ goto done;
+ }
+ if (tdb->ecode == TDB_ERR_NOEXIST &&
+ flag == TDB_MODIFY) {
+ /* if the record doesn't exist and we are in TDB_MODIFY mode then
+ we should fail the store */
+ goto fail;
+ }
+ }
+ /* reset the error code potentially set by the tdb_update() */
+ tdb->ecode = TDB_SUCCESS;
+
+ /* delete any existing record - if it doesn't exist we don't
+ care. Doing this first reduces fragmentation, and avoids
+ coalescing with `allocated' block before it's updated. */
+ if (flag != TDB_INSERT)
+ tdb_delete_hash(tdb, key, hash);
+
+ /* Copy key+value *before* allocating free space in case malloc
+ fails and we are left with a dead spot in the tdb. */
+
+ if (!(p = (char *)malloc(key.dsize + dbuf.dsize))) {
+ tdb->ecode = TDB_ERR_OOM;
+ goto fail;
+ }
+
+ memcpy(p, key.dptr, key.dsize);
+ if (dbuf.dsize)
+ memcpy(p+key.dsize, dbuf.dptr, dbuf.dsize);
+
+ if (tdb->max_dead_records != 0) {
+ /*
+ * Allow for some dead records per hash chain, look if we can
+ * find one that can hold the new record. We need enough space
+ * for key, data and tailer. If we find one, we don't have to
+ * consult the central freelist.
+ */
+ rec_ptr = tdb_find_dead(
+ tdb, hash, &rec,
+ key.dsize + dbuf.dsize + sizeof(tdb_off_t));
+
+ if (rec_ptr != 0) {
+ rec.key_len = key.dsize;
+ rec.data_len = dbuf.dsize;
+ rec.full_hash = hash;
+ rec.magic = TDB_MAGIC;
+ if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
+ || tdb->methods->tdb_write(
+ tdb, rec_ptr + sizeof(rec),
+ p, key.dsize + dbuf.dsize) == -1) {
+ goto fail;
+ }
+ goto done;
+ }
+ }
+
+ /*
+ * We have to allocate some space from the freelist, so this means we
+ * have to lock it. Use the chance to purge all the DEAD records from
+ * the hash chain under the freelist lock.
+ */
+
+ if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
+ goto fail;
+ }
+
+ if ((tdb->max_dead_records != 0)
+ && (tdb_purge_dead(tdb, hash) == -1)) {
+ tdb_unlock(tdb, -1, F_WRLCK);
+ goto fail;
+ }
+
+ /* we have to allocate some space */
+ rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec);
+
+ tdb_unlock(tdb, -1, F_WRLCK);
+
+ if (rec_ptr == 0) {
+ goto fail;
+ }
+
+ /* Read hash top into next ptr */
+ if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)
+ goto fail;
+
+ rec.key_len = key.dsize;
+ rec.data_len = dbuf.dsize;
+ rec.full_hash = hash;
+ rec.magic = TDB_MAGIC;
+
+ /* write out and point the top of the hash chain at it */
+ if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
+ || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+dbuf.dsize)==-1
+ || tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) {
+ /* Need to tdb_unallocate() here */
+ goto fail;
+ }
+
+ done:
+ ret = 0;
+ fail:
+ if (ret == 0) {
+ tdb_increment_seqnum(tdb);
+ }
+
+ SAFE_FREE(p);
+ tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
+ return ret;
+}
+
+
+/* Append to an entry. Create if not exist. */
+int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
+{
+ uint32_t hash;
+ TDB_DATA dbuf;
+ int ret = -1;
+
+ /* find which hash bucket it is in */
+ hash = tdb->hash_fn(&key);
+ if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
+ return -1;
+
+ dbuf = tdb_fetch(tdb, key);
+
+ if (dbuf.dptr == NULL) {
+ dbuf.dptr = (unsigned char *)malloc(new_dbuf.dsize);
+ } else {
+ unsigned char *new_dptr = (unsigned char *)realloc(dbuf.dptr,
+ dbuf.dsize + new_dbuf.dsize);
+ if (new_dptr == NULL) {
+ free(dbuf.dptr);
+ }
+ dbuf.dptr = new_dptr;
+ }
+
+ if (dbuf.dptr == NULL) {
+ tdb->ecode = TDB_ERR_OOM;
+ goto failed;
+ }
+
+ memcpy(dbuf.dptr + dbuf.dsize, new_dbuf.dptr, new_dbuf.dsize);
+ dbuf.dsize += new_dbuf.dsize;
+
+ ret = tdb_store(tdb, key, dbuf, 0);
+
+failed:
+ tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
+ SAFE_FREE(dbuf.dptr);
+ return ret;
+}
+
+
+/*
+ return the name of the current tdb file
+ useful for external logging functions
+*/
+const char *tdb_name(struct tdb_context *tdb)
+{
+ return tdb->name;
+}
+
+/*
+ return the underlying file descriptor being used by tdb, or -1
+ useful for external routines that want to check the device/inode
+ of the fd
+*/
+int tdb_fd(struct tdb_context *tdb)
+{
+ return tdb->fd;
+}
+
+/*
+ return the current logging function
+ useful for external tdb routines that wish to log tdb errors
+*/
+tdb_log_func tdb_log_fn(struct tdb_context *tdb)
+{
+ return tdb->log.log_fn;
+}
+
+
+/*
+ get the tdb sequence number. Only makes sense if the writers opened
+ with TDB_SEQNUM set. Note that this sequence number will wrap quite
+ quickly, so it should only be used for a 'has something changed'
+ test, not for code that relies on the count of the number of changes
+ made. If you want a counter then use a tdb record.
+
+ The aim of this sequence number is to allow for a very lightweight
+ test of a possible tdb change.
+*/
+int tdb_get_seqnum(struct tdb_context *tdb)
+{
+ tdb_off_t seqnum=0;
+
+ tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
+ return seqnum;
+}
+
+int tdb_hash_size(struct tdb_context *tdb)
+{
+ return tdb->header.hash_size;
+}
+
+size_t tdb_map_size(struct tdb_context *tdb)
+{
+ return tdb->map_size;
+}
+
+int tdb_get_flags(struct tdb_context *tdb)
+{
+ return tdb->flags;
+}
+
+void tdb_add_flags(struct tdb_context *tdb, unsigned flags)
+{
+ tdb->flags |= flags;
+}
+
+void tdb_remove_flags(struct tdb_context *tdb, unsigned flags)
+{
+ tdb->flags &= ~flags;
+}
+
+
+/*
+ enable sequence number handling on an open tdb
+*/
+void tdb_enable_seqnum(struct tdb_context *tdb)
+{
+ tdb->flags |= TDB_SEQNUM;
+}
+
+
+/*
+ add a region of the file to the freelist. Length is the size of the region in bytes,
+ which includes the free list header that needs to be added
+ */
+static int tdb_free_region(struct tdb_context *tdb, tdb_off_t offset, ssize_t length)
+{
+ struct list_struct rec;
+ if (length <= sizeof(rec)) {
+ /* the region is not worth adding */
+ return 0;
+ }
+ if (length + offset > tdb->map_size) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: adding region beyond end of file\n"));
+ return -1;
+ }
+ memset(&rec,'\0',sizeof(rec));
+ rec.rec_len = length - sizeof(rec);
+ if (tdb_free(tdb, offset, &rec) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: failed to add free record\n"));
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ wipe the entire database, deleting all records. This can be done
+ very fast by using a global lock. The entire data portion of the
+ file becomes a single entry in the freelist.
+
+ This code carefully steps around the recovery area, leaving it alone
+ */
+int tdb_wipe_all(struct tdb_context *tdb)
+{
+ int i;
+ tdb_off_t offset = 0;
+ ssize_t data_len;
+ tdb_off_t recovery_head;
+ tdb_len_t recovery_size = 0;
+
+ if (tdb_lockall(tdb) != 0) {
+ return -1;
+ }
+
+ /* see if the tdb has a recovery area, and remember its size
+ if so. We don't want to lose this as otherwise each
+ tdb_wipe_all() in a transaction will increase the size of
+ the tdb by the size of the recovery area */
+ if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery head\n"));
+ goto failed;
+ }
+
+ if (recovery_head != 0) {
+ struct list_struct rec;
+ if (tdb->methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery record\n"));
+ return -1;
+ }
+ recovery_size = rec.rec_len + sizeof(rec);
+ }
+
+ /* wipe the hashes */
+ for (i=0;i<tdb->header.hash_size;i++) {
+ if (tdb_ofs_write(tdb, TDB_HASH_TOP(i), &offset) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write hash %d\n", i));
+ goto failed;
+ }
+ }
+
+ /* wipe the freelist */
+ if (tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write freelist\n"));
+ goto failed;
+ }
+
+ /* add all the rest of the file to the freelist, possibly leaving a gap
+ for the recovery area */
+ if (recovery_size == 0) {
+ /* the simple case - the whole file can be used as a freelist */
+ data_len = (tdb->map_size - TDB_DATA_START(tdb->header.hash_size));
+ if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) {
+ goto failed;
+ }
+ } else {
+ /* we need to add two freelist entries - one on either
+ side of the recovery area
+
+ Note that we cannot shift the recovery area during
+ this operation. Only the transaction.c code may
+ move the recovery area or we risk subtle data
+ corruption
+ */
+ data_len = (recovery_head - TDB_DATA_START(tdb->header.hash_size));
+ if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) {
+ goto failed;
+ }
+ /* and the 2nd free list entry after the recovery area - if any */
+ data_len = tdb->map_size - (recovery_head+recovery_size);
+ if (tdb_free_region(tdb, recovery_head+recovery_size, data_len) != 0) {
+ goto failed;
+ }
+ }
+
+ if (tdb_unlockall(tdb) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to unlock\n"));
+ goto failed;
+ }
+
+ return 0;
+
+failed:
+ tdb_unlockall(tdb);
+ return -1;
+}
diff --git a/source3/lib/tdb/common/tdb_private.h b/source3/lib/tdb/common/tdb_private.h
new file mode 100644
index 0000000000..ffac89ff0e
--- /dev/null
+++ b/source3/lib/tdb/common/tdb_private.h
@@ -0,0 +1,213 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library - private includes
+
+ Copyright (C) Andrew Tridgell 2005
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "system/shmem.h"
+#include "system/select.h"
+#include "system/wait.h"
+#include "tdb.h"
+
+#ifndef HAVE_GETPAGESIZE
+#define getpagesize() 0x2000
+#endif
+
+typedef uint32_t tdb_len_t;
+typedef uint32_t tdb_off_t;
+
+#ifndef offsetof
+#define offsetof(t,f) ((unsigned int)&((t *)0)->f)
+#endif
+
+#define TDB_MAGIC_FOOD "TDB file\n"
+#define TDB_VERSION (0x26011967 + 6)
+#define TDB_MAGIC (0x26011999U)
+#define TDB_FREE_MAGIC (~TDB_MAGIC)
+#define TDB_DEAD_MAGIC (0xFEE1DEAD)
+#define TDB_RECOVERY_MAGIC (0xf53bc0e7U)
+#define TDB_ALIGNMENT 4
+#define DEFAULT_HASH_SIZE 131
+#define FREELIST_TOP (sizeof(struct tdb_header))
+#define TDB_ALIGN(x,a) (((x) + (a)-1) & ~((a)-1))
+#define TDB_BYTEREV(x) (((((x)&0xff)<<24)|((x)&0xFF00)<<8)|(((x)>>8)&0xFF00)|((x)>>24))
+#define TDB_DEAD(r) ((r)->magic == TDB_DEAD_MAGIC)
+#define TDB_BAD_MAGIC(r) ((r)->magic != TDB_MAGIC && !TDB_DEAD(r))
+#define TDB_HASH_TOP(hash) (FREELIST_TOP + (BUCKET(hash)+1)*sizeof(tdb_off_t))
+#define TDB_HASHTABLE_SIZE(tdb) ((tdb->header.hash_size+1)*sizeof(tdb_off_t))
+#define TDB_DATA_START(hash_size) (TDB_HASH_TOP(hash_size-1) + sizeof(tdb_off_t))
+#define TDB_RECOVERY_HEAD offsetof(struct tdb_header, recovery_start)
+#define TDB_SEQNUM_OFS offsetof(struct tdb_header, sequence_number)
+#define TDB_PAD_BYTE 0x42
+#define TDB_PAD_U32 0x42424242
+
+/* NB assumes there is a local variable called "tdb" that is the
+ * current context, also takes doubly-parenthesized print-style
+ * argument. */
+#define TDB_LOG(x) tdb->log.log_fn x
+
+/* lock offsets */
+#define GLOBAL_LOCK 0
+#define ACTIVE_LOCK 4
+#define TRANSACTION_LOCK 8
+
+/* free memory if the pointer is valid and zero the pointer */
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
+#endif
+
+#define BUCKET(hash) ((hash) % tdb->header.hash_size)
+
+#define DOCONV() (tdb->flags & TDB_CONVERT)
+#define CONVERT(x) (DOCONV() ? tdb_convert(&x, sizeof(x)) : &x)
+
+
+/* the body of the database is made of one list_struct for the free space
+ plus a separate data list for each hash value */
+struct list_struct {
+ tdb_off_t next; /* offset of the next record in the list */
+ tdb_len_t rec_len; /* total byte length of record */
+ tdb_len_t key_len; /* byte length of key */
+ tdb_len_t data_len; /* byte length of data */
+ uint32_t full_hash; /* the full 32 bit hash of the key */
+ uint32_t magic; /* try to catch errors */
+ /* the following union is implied:
+ union {
+ char record[rec_len];
+ struct {
+ char key[key_len];
+ char data[data_len];
+ }
+ uint32_t totalsize; (tailer)
+ }
+ */
+};
+
+
+/* this is stored at the front of every database */
+struct tdb_header {
+ char magic_food[32]; /* for /etc/magic */
+ uint32_t version; /* version of the code */
+ uint32_t hash_size; /* number of hash entries */
+ tdb_off_t rwlocks; /* obsolete - kept to detect old formats */
+ tdb_off_t recovery_start; /* offset of transaction recovery region */
+ tdb_off_t sequence_number; /* used when TDB_SEQNUM is set */
+ tdb_off_t reserved[29];
+};
+
+struct tdb_lock_type {
+ int list;
+ uint32_t count;
+ uint32_t ltype;
+};
+
+struct tdb_traverse_lock {
+ struct tdb_traverse_lock *next;
+ uint32_t off;
+ uint32_t hash;
+ int lock_rw;
+};
+
+
+struct tdb_methods {
+ int (*tdb_read)(struct tdb_context *, tdb_off_t , void *, tdb_len_t , int );
+ int (*tdb_write)(struct tdb_context *, tdb_off_t, const void *, tdb_len_t);
+ void (*next_hash_chain)(struct tdb_context *, uint32_t *);
+ int (*tdb_oob)(struct tdb_context *, tdb_off_t , int );
+ int (*tdb_expand_file)(struct tdb_context *, tdb_off_t , tdb_off_t );
+ int (*tdb_brlock)(struct tdb_context *, tdb_off_t , int, int, int, size_t);
+};
+
+struct tdb_context {
+ char *name; /* the name of the database */
+ void *map_ptr; /* where it is currently mapped */
+ int fd; /* open file descriptor for the database */
+ tdb_len_t map_size; /* how much space has been mapped */
+ int read_only; /* opened read-only */
+ int traverse_read; /* read-only traversal */
+ int traverse_write; /* read-write traversal */
+ struct tdb_lock_type global_lock;
+ int num_lockrecs;
+ struct tdb_lock_type *lockrecs; /* only real locks, all with count>0 */
+ enum TDB_ERROR ecode; /* error code for last tdb error */
+ struct tdb_header header; /* a cached copy of the header */
+ uint32_t flags; /* the flags passed to tdb_open */
+ struct tdb_traverse_lock travlocks; /* current traversal locks */
+ struct tdb_context *next; /* all tdbs to avoid multiple opens */
+ dev_t device; /* uniquely identifies this tdb */
+ ino_t inode; /* uniquely identifies this tdb */
+ struct tdb_logging_context log;
+ unsigned int (*hash_fn)(TDB_DATA *key);
+ int open_flags; /* flags used in the open - needed by reopen */
+ unsigned int num_locks; /* number of chain locks held */
+ const struct tdb_methods *methods;
+ struct tdb_transaction *transaction;
+ int page_size;
+ int max_dead_records;
+ bool have_transaction_lock;
+ volatile sig_atomic_t *interrupt_sig_ptr;
+};
+
+
+/*
+ internal prototypes
+*/
+int tdb_munmap(struct tdb_context *tdb);
+void tdb_mmap(struct tdb_context *tdb);
+int tdb_lock(struct tdb_context *tdb, int list, int ltype);
+int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype);
+int tdb_unlock(struct tdb_context *tdb, int list, int ltype);
+int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset, int rw_type, int lck_type, int probe, size_t len);
+int tdb_transaction_lock(struct tdb_context *tdb, int ltype);
+int tdb_transaction_unlock(struct tdb_context *tdb);
+int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len);
+int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off);
+int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off);
+int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
+int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
+void *tdb_convert(void *buf, uint32_t size);
+int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec);
+tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct list_struct *rec);
+int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
+int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
+int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off);
+int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off);
+int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec);
+int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec);
+int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct list_struct *rec);
+unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len);
+int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key,
+ tdb_off_t offset, tdb_len_t len,
+ int (*parser)(TDB_DATA key, TDB_DATA data,
+ void *private_data),
+ void *private_data);
+tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype,
+ struct list_struct *rec);
+void tdb_io_init(struct tdb_context *tdb);
+int tdb_expand(struct tdb_context *tdb, tdb_off_t size);
+int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off,
+ struct list_struct *rec);
+
+
diff --git a/source3/lib/tdb/common/transaction.c b/source3/lib/tdb/common/transaction.c
new file mode 100644
index 0000000000..7acda640c8
--- /dev/null
+++ b/source3/lib/tdb/common/transaction.c
@@ -0,0 +1,1119 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 2005
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+/*
+ transaction design:
+
+ - only allow a single transaction at a time per database. This makes
+ using the transaction API simpler, as otherwise the caller would
+ have to cope with temporary failures in transactions that conflict
+ with other current transactions
+
+ - keep the transaction recovery information in the same file as the
+ database, using a special 'transaction recovery' record pointed at
+ by the header. This removes the need for extra journal files as
+ used by some other databases
+
+ - dynamically allocated the transaction recover record, re-using it
+ for subsequent transactions. If a larger record is needed then
+ tdb_free() the old record to place it on the normal tdb freelist
+ before allocating the new record
+
+ - during transactions, keep a linked list of writes all that have
+ been performed by intercepting all tdb_write() calls. The hooked
+ transaction versions of tdb_read() and tdb_write() check this
+ linked list and try to use the elements of the list in preference
+ to the real database.
+
+ - don't allow any locks to be held when a transaction starts,
+ otherwise we can end up with deadlock (plus lack of lock nesting
+ in posix locks would mean the lock is lost)
+
+ - if the caller gains a lock during the transaction but doesn't
+ release it then fail the commit
+
+ - allow for nested calls to tdb_transaction_start(), re-using the
+ existing transaction record. If the inner transaction is cancelled
+ then a subsequent commit will fail
+
+ - keep a mirrored copy of the tdb hash chain heads to allow for the
+ fast hash heads scan on traverse, updating the mirrored copy in
+ the transaction version of tdb_write
+
+ - allow callers to mix transaction and non-transaction use of tdb,
+ although once a transaction is started then an exclusive lock is
+ gained until the transaction is committed or cancelled
+
+ - the commit stategy involves first saving away all modified data
+ into a linearised buffer in the transaction recovery area, then
+ marking the transaction recovery area with a magic value to
+ indicate a valid recovery record. In total 4 fsync/msync calls are
+ needed per commit to prevent race conditions. It might be possible
+ to reduce this to 3 or even 2 with some more work.
+
+ - check for a valid recovery record on open of the tdb, while the
+ global lock is held. Automatically recover from the transaction
+ recovery area if needed, then continue with the open as
+ usual. This allows for smooth crash recovery with no administrator
+ intervention.
+
+ - if TDB_NOSYNC is passed to flags in tdb_open then transactions are
+ still available, but no transaction recovery area is used and no
+ fsync/msync calls are made.
+
+*/
+
+
+/*
+ hold the context of any current transaction
+*/
+struct tdb_transaction {
+ /* we keep a mirrored copy of the tdb hash heads here so
+ tdb_next_hash_chain() can operate efficiently */
+ uint32_t *hash_heads;
+
+ /* the original io methods - used to do IOs to the real db */
+ const struct tdb_methods *io_methods;
+
+ /* the list of transaction blocks. When a block is first
+ written to, it gets created in this list */
+ uint8_t **blocks;
+ uint32_t num_blocks;
+ uint32_t block_size; /* bytes in each block */
+ uint32_t last_block_size; /* number of valid bytes in the last block */
+
+ /* non-zero when an internal transaction error has
+ occurred. All write operations will then fail until the
+ transaction is ended */
+ int transaction_error;
+
+ /* when inside a transaction we need to keep track of any
+ nested tdb_transaction_start() calls, as these are allowed,
+ but don't create a new transaction */
+ int nesting;
+
+ /* old file size before transaction */
+ tdb_len_t old_map_size;
+};
+
+
+/*
+ read while in a transaction. We need to check first if the data is in our list
+ of transaction elements, then if not do a real read
+*/
+static int transaction_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
+ tdb_len_t len, int cv)
+{
+ uint32_t blk;
+
+ /* break it down into block sized ops */
+ while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
+ tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
+ if (transaction_read(tdb, off, buf, len2, cv) != 0) {
+ return -1;
+ }
+ len -= len2;
+ off += len2;
+ buf = (void *)(len2 + (char *)buf);
+ }
+
+ if (len == 0) {
+ return 0;
+ }
+
+ blk = off / tdb->transaction->block_size;
+
+ /* see if we have it in the block list */
+ if (tdb->transaction->num_blocks <= blk ||
+ tdb->transaction->blocks[blk] == NULL) {
+ /* nope, do a real read */
+ if (tdb->transaction->io_methods->tdb_read(tdb, off, buf, len, cv) != 0) {
+ goto fail;
+ }
+ return 0;
+ }
+
+ /* it is in the block list. Now check for the last block */
+ if (blk == tdb->transaction->num_blocks-1) {
+ if (len > tdb->transaction->last_block_size) {
+ goto fail;
+ }
+ }
+
+ /* now copy it out of this block */
+ memcpy(buf, tdb->transaction->blocks[blk] + (off % tdb->transaction->block_size), len);
+ if (cv) {
+ tdb_convert(buf, len);
+ }
+ return 0;
+
+fail:
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_read: failed at off=%d len=%d\n", off, len));
+ tdb->ecode = TDB_ERR_IO;
+ tdb->transaction->transaction_error = 1;
+ return -1;
+}
+
+
+/*
+ write while in a transaction
+*/
+static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
+ const void *buf, tdb_len_t len)
+{
+ uint32_t blk;
+
+ /* if the write is to a hash head, then update the transaction
+ hash heads */
+ if (len == sizeof(tdb_off_t) && off >= FREELIST_TOP &&
+ off < FREELIST_TOP+TDB_HASHTABLE_SIZE(tdb)) {
+ uint32_t chain = (off-FREELIST_TOP) / sizeof(tdb_off_t);
+ memcpy(&tdb->transaction->hash_heads[chain], buf, len);
+ }
+
+ /* break it up into block sized chunks */
+ while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
+ tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
+ if (transaction_write(tdb, off, buf, len2) != 0) {
+ return -1;
+ }
+ len -= len2;
+ off += len2;
+ if (buf != NULL) {
+ buf = (const void *)(len2 + (const char *)buf);
+ }
+ }
+
+ if (len == 0) {
+ return 0;
+ }
+
+ blk = off / tdb->transaction->block_size;
+ off = off % tdb->transaction->block_size;
+
+ if (tdb->transaction->num_blocks <= blk) {
+ uint8_t **new_blocks;
+ /* expand the blocks array */
+ if (tdb->transaction->blocks == NULL) {
+ new_blocks = (uint8_t **)malloc(
+ (blk+1)*sizeof(uint8_t *));
+ } else {
+ new_blocks = (uint8_t **)realloc(
+ tdb->transaction->blocks,
+ (blk+1)*sizeof(uint8_t *));
+ }
+ if (new_blocks == NULL) {
+ tdb->ecode = TDB_ERR_OOM;
+ goto fail;
+ }
+ memset(&new_blocks[tdb->transaction->num_blocks], 0,
+ (1+(blk - tdb->transaction->num_blocks))*sizeof(uint8_t *));
+ tdb->transaction->blocks = new_blocks;
+ tdb->transaction->num_blocks = blk+1;
+ tdb->transaction->last_block_size = 0;
+ }
+
+ /* allocate and fill a block? */
+ if (tdb->transaction->blocks[blk] == NULL) {
+ tdb->transaction->blocks[blk] = (uint8_t *)calloc(tdb->transaction->block_size, 1);
+ if (tdb->transaction->blocks[blk] == NULL) {
+ tdb->ecode = TDB_ERR_OOM;
+ tdb->transaction->transaction_error = 1;
+ return -1;
+ }
+ if (tdb->transaction->old_map_size > blk * tdb->transaction->block_size) {
+ tdb_len_t len2 = tdb->transaction->block_size;
+ if (len2 + (blk * tdb->transaction->block_size) > tdb->transaction->old_map_size) {
+ len2 = tdb->transaction->old_map_size - (blk * tdb->transaction->block_size);
+ }
+ if (tdb->transaction->io_methods->tdb_read(tdb, blk * tdb->transaction->block_size,
+ tdb->transaction->blocks[blk],
+ len2, 0) != 0) {
+ SAFE_FREE(tdb->transaction->blocks[blk]);
+ tdb->ecode = TDB_ERR_IO;
+ goto fail;
+ }
+ if (blk == tdb->transaction->num_blocks-1) {
+ tdb->transaction->last_block_size = len2;
+ }
+ }
+ }
+
+ /* overwrite part of an existing block */
+ if (buf == NULL) {
+ memset(tdb->transaction->blocks[blk] + off, 0, len);
+ } else {
+ memcpy(tdb->transaction->blocks[blk] + off, buf, len);
+ }
+ if (blk == tdb->transaction->num_blocks-1) {
+ if (len + off > tdb->transaction->last_block_size) {
+ tdb->transaction->last_block_size = len + off;
+ }
+ }
+
+ return 0;
+
+fail:
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: failed at off=%d len=%d\n",
+ (blk*tdb->transaction->block_size) + off, len));
+ tdb->transaction->transaction_error = 1;
+ return -1;
+}
+
+
+/*
+ write while in a transaction - this varient never expands the transaction blocks, it only
+ updates existing blocks. This means it cannot change the recovery size
+*/
+static int transaction_write_existing(struct tdb_context *tdb, tdb_off_t off,
+ const void *buf, tdb_len_t len)
+{
+ uint32_t blk;
+
+ /* break it up into block sized chunks */
+ while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
+ tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
+ if (transaction_write_existing(tdb, off, buf, len2) != 0) {
+ return -1;
+ }
+ len -= len2;
+ off += len2;
+ if (buf != NULL) {
+ buf = (const void *)(len2 + (const char *)buf);
+ }
+ }
+
+ if (len == 0) {
+ return 0;
+ }
+
+ blk = off / tdb->transaction->block_size;
+ off = off % tdb->transaction->block_size;
+
+ if (tdb->transaction->num_blocks <= blk ||
+ tdb->transaction->blocks[blk] == NULL) {
+ return 0;
+ }
+
+ if (blk == tdb->transaction->num_blocks-1 &&
+ off + len > tdb->transaction->last_block_size) {
+ if (off >= tdb->transaction->last_block_size) {
+ return 0;
+ }
+ len = tdb->transaction->last_block_size - off;
+ }
+
+ /* overwrite part of an existing block */
+ memcpy(tdb->transaction->blocks[blk] + off, buf, len);
+
+ return 0;
+}
+
+
+/*
+ accelerated hash chain head search, using the cached hash heads
+*/
+static void transaction_next_hash_chain(struct tdb_context *tdb, uint32_t *chain)
+{
+ uint32_t h = *chain;
+ for (;h < tdb->header.hash_size;h++) {
+ /* the +1 takes account of the freelist */
+ if (0 != tdb->transaction->hash_heads[h+1]) {
+ break;
+ }
+ }
+ (*chain) = h;
+}
+
+/*
+ out of bounds check during a transaction
+*/
+static int transaction_oob(struct tdb_context *tdb, tdb_off_t len, int probe)
+{
+ if (len <= tdb->map_size) {
+ return 0;
+ }
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+}
+
+/*
+ transaction version of tdb_expand().
+*/
+static int transaction_expand_file(struct tdb_context *tdb, tdb_off_t size,
+ tdb_off_t addition)
+{
+ /* add a write to the transaction elements, so subsequent
+ reads see the zero data */
+ if (transaction_write(tdb, size, NULL, addition) != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ brlock during a transaction - ignore them
+*/
+static int transaction_brlock(struct tdb_context *tdb, tdb_off_t offset,
+ int rw_type, int lck_type, int probe, size_t len)
+{
+ return 0;
+}
+
+static const struct tdb_methods transaction_methods = {
+ transaction_read,
+ transaction_write,
+ transaction_next_hash_chain,
+ transaction_oob,
+ transaction_expand_file,
+ transaction_brlock
+};
+
+
+/*
+ start a tdb transaction. No token is returned, as only a single
+ transaction is allowed to be pending per tdb_context
+*/
+int tdb_transaction_start(struct tdb_context *tdb)
+{
+ /* some sanity checks */
+ if (tdb->read_only || (tdb->flags & TDB_INTERNAL) || tdb->traverse_read) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction on a read-only or internal db\n"));
+ tdb->ecode = TDB_ERR_EINVAL;
+ return -1;
+ }
+
+ /* cope with nested tdb_transaction_start() calls */
+ if (tdb->transaction != NULL) {
+ tdb->transaction->nesting++;
+ TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_start: nesting %d\n",
+ tdb->transaction->nesting));
+ return 0;
+ }
+
+ if (tdb->num_locks != 0 || tdb->global_lock.count) {
+ /* the caller must not have any locks when starting a
+ transaction as otherwise we'll be screwed by lack
+ of nested locks in posix */
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction with locks held\n"));
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+
+ if (tdb->travlocks.next != NULL) {
+ /* you cannot use transactions inside a traverse (although you can use
+ traverse inside a transaction) as otherwise you can end up with
+ deadlock */
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction within a traverse\n"));
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+
+ tdb->transaction = (struct tdb_transaction *)
+ calloc(sizeof(struct tdb_transaction), 1);
+ if (tdb->transaction == NULL) {
+ tdb->ecode = TDB_ERR_OOM;
+ return -1;
+ }
+
+ /* a page at a time seems like a reasonable compromise between compactness and efficiency */
+ tdb->transaction->block_size = tdb->page_size;
+
+ /* get the transaction write lock. This is a blocking lock. As
+ discussed with Volker, there are a number of ways we could
+ make this async, which we will probably do in the future */
+ if (tdb_transaction_lock(tdb, F_WRLCK) == -1) {
+ SAFE_FREE(tdb->transaction->blocks);
+ SAFE_FREE(tdb->transaction);
+ return -1;
+ }
+
+ /* get a read lock from the freelist to the end of file. This
+ is upgraded to a write lock during the commit */
+ if (tdb_brlock(tdb, FREELIST_TOP, F_RDLCK, F_SETLKW, 0, 0) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to get hash locks\n"));
+ tdb->ecode = TDB_ERR_LOCK;
+ goto fail;
+ }
+
+ /* setup a copy of the hash table heads so the hash scan in
+ traverse can be fast */
+ tdb->transaction->hash_heads = (uint32_t *)
+ calloc(tdb->header.hash_size+1, sizeof(uint32_t));
+ if (tdb->transaction->hash_heads == NULL) {
+ tdb->ecode = TDB_ERR_OOM;
+ goto fail;
+ }
+ if (tdb->methods->tdb_read(tdb, FREELIST_TOP, tdb->transaction->hash_heads,
+ TDB_HASHTABLE_SIZE(tdb), 0) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_start: failed to read hash heads\n"));
+ tdb->ecode = TDB_ERR_IO;
+ goto fail;
+ }
+
+ /* make sure we know about any file expansions already done by
+ anyone else */
+ tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1);
+ tdb->transaction->old_map_size = tdb->map_size;
+
+ /* finally hook the io methods, replacing them with
+ transaction specific methods */
+ tdb->transaction->io_methods = tdb->methods;
+ tdb->methods = &transaction_methods;
+
+ return 0;
+
+fail:
+ tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0);
+ tdb_transaction_unlock(tdb);
+ SAFE_FREE(tdb->transaction->blocks);
+ SAFE_FREE(tdb->transaction->hash_heads);
+ SAFE_FREE(tdb->transaction);
+ return -1;
+}
+
+
+/*
+ cancel the current transaction
+*/
+int tdb_transaction_cancel(struct tdb_context *tdb)
+{
+ int i;
+
+ if (tdb->transaction == NULL) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_cancel: no transaction\n"));
+ return -1;
+ }
+
+ if (tdb->transaction->nesting != 0) {
+ tdb->transaction->transaction_error = 1;
+ tdb->transaction->nesting--;
+ return 0;
+ }
+
+ tdb->map_size = tdb->transaction->old_map_size;
+
+ /* free all the transaction blocks */
+ for (i=0;i<tdb->transaction->num_blocks;i++) {
+ if (tdb->transaction->blocks[i] != NULL) {
+ free(tdb->transaction->blocks[i]);
+ }
+ }
+ SAFE_FREE(tdb->transaction->blocks);
+
+ /* remove any global lock created during the transaction */
+ if (tdb->global_lock.count != 0) {
+ tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 4*tdb->header.hash_size);
+ tdb->global_lock.count = 0;
+ }
+
+ /* remove any locks created during the transaction */
+ if (tdb->num_locks != 0) {
+ for (i=0;i<tdb->num_lockrecs;i++) {
+ tdb_brlock(tdb,FREELIST_TOP+4*tdb->lockrecs[i].list,
+ F_UNLCK,F_SETLKW, 0, 1);
+ }
+ tdb->num_locks = 0;
+ tdb->num_lockrecs = 0;
+ SAFE_FREE(tdb->lockrecs);
+ }
+
+ /* restore the normal io methods */
+ tdb->methods = tdb->transaction->io_methods;
+
+ tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0);
+ tdb_transaction_unlock(tdb);
+ SAFE_FREE(tdb->transaction->hash_heads);
+ SAFE_FREE(tdb->transaction);
+
+ return 0;
+}
+
+/*
+ sync to disk
+*/
+static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t length)
+{
+ if (fsync(tdb->fd) != 0) {
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n"));
+ return -1;
+ }
+#ifdef HAVE_MMAP
+ if (tdb->map_ptr) {
+ tdb_off_t moffset = offset & ~(tdb->page_size-1);
+ if (msync(moffset + (char *)tdb->map_ptr,
+ length + (offset - moffset), MS_SYNC) != 0) {
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: msync failed - %s\n",
+ strerror(errno)));
+ return -1;
+ }
+ }
+#endif
+ return 0;
+}
+
+
+/*
+ work out how much space the linearised recovery data will consume
+*/
+static tdb_len_t tdb_recovery_size(struct tdb_context *tdb)
+{
+ tdb_len_t recovery_size = 0;
+ int i;
+
+ recovery_size = sizeof(uint32_t);
+ for (i=0;i<tdb->transaction->num_blocks;i++) {
+ if (i * tdb->transaction->block_size >= tdb->transaction->old_map_size) {
+ break;
+ }
+ if (tdb->transaction->blocks[i] == NULL) {
+ continue;
+ }
+ recovery_size += 2*sizeof(tdb_off_t);
+ if (i == tdb->transaction->num_blocks-1) {
+ recovery_size += tdb->transaction->last_block_size;
+ } else {
+ recovery_size += tdb->transaction->block_size;
+ }
+ }
+
+ return recovery_size;
+}
+
+/*
+ allocate the recovery area, or use an existing recovery area if it is
+ large enough
+*/
+static int tdb_recovery_allocate(struct tdb_context *tdb,
+ tdb_len_t *recovery_size,
+ tdb_off_t *recovery_offset,
+ tdb_len_t *recovery_max_size)
+{
+ struct list_struct rec;
+ const struct tdb_methods *methods = tdb->transaction->io_methods;
+ tdb_off_t recovery_head;
+
+ if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery head\n"));
+ return -1;
+ }
+
+ rec.rec_len = 0;
+
+ if (recovery_head != 0 &&
+ methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery record\n"));
+ return -1;
+ }
+
+ *recovery_size = tdb_recovery_size(tdb);
+
+ if (recovery_head != 0 && *recovery_size <= rec.rec_len) {
+ /* it fits in the existing area */
+ *recovery_max_size = rec.rec_len;
+ *recovery_offset = recovery_head;
+ return 0;
+ }
+
+ /* we need to free up the old recovery area, then allocate a
+ new one at the end of the file. Note that we cannot use
+ tdb_allocate() to allocate the new one as that might return
+ us an area that is being currently used (as of the start of
+ the transaction) */
+ if (recovery_head != 0) {
+ if (tdb_free(tdb, recovery_head, &rec) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to free previous recovery area\n"));
+ return -1;
+ }
+ }
+
+ /* the tdb_free() call might have increased the recovery size */
+ *recovery_size = tdb_recovery_size(tdb);
+
+ /* round up to a multiple of page size */
+ *recovery_max_size = TDB_ALIGN(sizeof(rec) + *recovery_size, tdb->page_size) - sizeof(rec);
+ *recovery_offset = tdb->map_size;
+ recovery_head = *recovery_offset;
+
+ if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size,
+ (tdb->map_size - tdb->transaction->old_map_size) +
+ sizeof(rec) + *recovery_max_size) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to create recovery area\n"));
+ return -1;
+ }
+
+ /* remap the file (if using mmap) */
+ methods->tdb_oob(tdb, tdb->map_size + 1, 1);
+
+ /* we have to reset the old map size so that we don't try to expand the file
+ again in the transaction commit, which would destroy the recovery area */
+ tdb->transaction->old_map_size = tdb->map_size;
+
+ /* write the recovery header offset and sync - we can sync without a race here
+ as the magic ptr in the recovery record has not been set */
+ CONVERT(recovery_head);
+ if (methods->tdb_write(tdb, TDB_RECOVERY_HEAD,
+ &recovery_head, sizeof(tdb_off_t)) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n"));
+ return -1;
+ }
+ if (transaction_write_existing(tdb, TDB_RECOVERY_HEAD, &recovery_head, sizeof(tdb_off_t)) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n"));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ setup the recovery data that will be used on a crash during commit
+*/
+static int transaction_setup_recovery(struct tdb_context *tdb,
+ tdb_off_t *magic_offset)
+{
+ tdb_len_t recovery_size;
+ unsigned char *data, *p;
+ const struct tdb_methods *methods = tdb->transaction->io_methods;
+ struct list_struct *rec;
+ tdb_off_t recovery_offset, recovery_max_size;
+ tdb_off_t old_map_size = tdb->transaction->old_map_size;
+ uint32_t magic, tailer;
+ int i;
+
+ /*
+ check that the recovery area has enough space
+ */
+ if (tdb_recovery_allocate(tdb, &recovery_size,
+ &recovery_offset, &recovery_max_size) == -1) {
+ return -1;
+ }
+
+ data = (unsigned char *)malloc(recovery_size + sizeof(*rec));
+ if (data == NULL) {
+ tdb->ecode = TDB_ERR_OOM;
+ return -1;
+ }
+
+ rec = (struct list_struct *)data;
+ memset(rec, 0, sizeof(*rec));
+
+ rec->magic = 0;
+ rec->data_len = recovery_size;
+ rec->rec_len = recovery_max_size;
+ rec->key_len = old_map_size;
+ CONVERT(rec);
+
+ /* build the recovery data into a single blob to allow us to do a single
+ large write, which should be more efficient */
+ p = data + sizeof(*rec);
+ for (i=0;i<tdb->transaction->num_blocks;i++) {
+ tdb_off_t offset;
+ tdb_len_t length;
+
+ if (tdb->transaction->blocks[i] == NULL) {
+ continue;
+ }
+
+ offset = i * tdb->transaction->block_size;
+ length = tdb->transaction->block_size;
+ if (i == tdb->transaction->num_blocks-1) {
+ length = tdb->transaction->last_block_size;
+ }
+
+ if (offset >= old_map_size) {
+ continue;
+ }
+ if (offset + length > tdb->transaction->old_map_size) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: transaction data over new region boundary\n"));
+ free(data);
+ tdb->ecode = TDB_ERR_CORRUPT;
+ return -1;
+ }
+ memcpy(p, &offset, 4);
+ memcpy(p+4, &length, 4);
+ if (DOCONV()) {
+ tdb_convert(p, 8);
+ }
+ /* the recovery area contains the old data, not the
+ new data, so we have to call the original tdb_read
+ method to get it */
+ if (methods->tdb_read(tdb, offset, p + 8, length, 0) != 0) {
+ free(data);
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+ p += 8 + length;
+ }
+
+ /* and the tailer */
+ tailer = sizeof(*rec) + recovery_max_size;
+ memcpy(p, &tailer, 4);
+ CONVERT(p);
+
+ /* write the recovery data to the recovery area */
+ if (methods->tdb_write(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write recovery data\n"));
+ free(data);
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+ if (transaction_write_existing(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write secondary recovery data\n"));
+ free(data);
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+ /* as we don't have ordered writes, we have to sync the recovery
+ data before we update the magic to indicate that the recovery
+ data is present */
+ if (transaction_sync(tdb, recovery_offset, sizeof(*rec) + recovery_size) == -1) {
+ free(data);
+ return -1;
+ }
+
+ free(data);
+
+ magic = TDB_RECOVERY_MAGIC;
+ CONVERT(magic);
+
+ *magic_offset = recovery_offset + offsetof(struct list_struct, magic);
+
+ if (methods->tdb_write(tdb, *magic_offset, &magic, sizeof(magic)) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write recovery magic\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+ if (transaction_write_existing(tdb, *magic_offset, &magic, sizeof(magic)) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write secondary recovery magic\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+ /* ensure the recovery magic marker is on disk */
+ if (transaction_sync(tdb, *magic_offset, sizeof(magic)) == -1) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ commit the current transaction
+*/
+int tdb_transaction_commit(struct tdb_context *tdb)
+{
+ const struct tdb_methods *methods;
+ tdb_off_t magic_offset = 0;
+ uint32_t zero = 0;
+ int i;
+
+ if (tdb->transaction == NULL) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\n"));
+ return -1;
+ }
+
+ if (tdb->transaction->transaction_error) {
+ tdb->ecode = TDB_ERR_IO;
+ tdb_transaction_cancel(tdb);
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: transaction error pending\n"));
+ return -1;
+ }
+
+
+ if (tdb->transaction->nesting != 0) {
+ tdb->transaction->nesting--;
+ return 0;
+ }
+
+ /* check for a null transaction */
+ if (tdb->transaction->blocks == NULL) {
+ tdb_transaction_cancel(tdb);
+ return 0;
+ }
+
+ methods = tdb->transaction->io_methods;
+
+ /* if there are any locks pending then the caller has not
+ nested their locks properly, so fail the transaction */
+ if (tdb->num_locks || tdb->global_lock.count) {
+ tdb->ecode = TDB_ERR_LOCK;
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: locks pending on commit\n"));
+ tdb_transaction_cancel(tdb);
+ return -1;
+ }
+
+ /* upgrade the main transaction lock region to a write lock */
+ if (tdb_brlock_upgrade(tdb, FREELIST_TOP, 0) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to upgrade hash locks\n"));
+ tdb->ecode = TDB_ERR_LOCK;
+ tdb_transaction_cancel(tdb);
+ return -1;
+ }
+
+ /* get the global lock - this prevents new users attaching to the database
+ during the commit */
+ if (tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: failed to get global lock\n"));
+ tdb->ecode = TDB_ERR_LOCK;
+ tdb_transaction_cancel(tdb);
+ return -1;
+ }
+
+ if (!(tdb->flags & TDB_NOSYNC)) {
+ /* write the recovery data to the end of the file */
+ if (transaction_setup_recovery(tdb, &magic_offset) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: failed to setup recovery data\n"));
+ tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
+ tdb_transaction_cancel(tdb);
+ return -1;
+ }
+ }
+
+ /* expand the file to the new size if needed */
+ if (tdb->map_size != tdb->transaction->old_map_size) {
+ if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size,
+ tdb->map_size -
+ tdb->transaction->old_map_size) == -1) {
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: expansion failed\n"));
+ tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
+ tdb_transaction_cancel(tdb);
+ return -1;
+ }
+ tdb->map_size = tdb->transaction->old_map_size;
+ methods->tdb_oob(tdb, tdb->map_size + 1, 1);
+ }
+
+ /* perform all the writes */
+ for (i=0;i<tdb->transaction->num_blocks;i++) {
+ tdb_off_t offset;
+ tdb_len_t length;
+
+ if (tdb->transaction->blocks[i] == NULL) {
+ continue;
+ }
+
+ offset = i * tdb->transaction->block_size;
+ length = tdb->transaction->block_size;
+ if (i == tdb->transaction->num_blocks-1) {
+ length = tdb->transaction->last_block_size;
+ }
+
+ if (methods->tdb_write(tdb, offset, tdb->transaction->blocks[i], length) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed during commit\n"));
+
+ /* we've overwritten part of the data and
+ possibly expanded the file, so we need to
+ run the crash recovery code */
+ tdb->methods = methods;
+ tdb_transaction_recover(tdb);
+
+ tdb_transaction_cancel(tdb);
+ tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
+
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed\n"));
+ return -1;
+ }
+ SAFE_FREE(tdb->transaction->blocks[i]);
+ }
+
+ SAFE_FREE(tdb->transaction->blocks);
+ tdb->transaction->num_blocks = 0;
+
+ if (!(tdb->flags & TDB_NOSYNC)) {
+ /* ensure the new data is on disk */
+ if (transaction_sync(tdb, 0, tdb->map_size) == -1) {
+ return -1;
+ }
+
+ /* remove the recovery marker */
+ if (methods->tdb_write(tdb, magic_offset, &zero, 4) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: failed to remove recovery magic\n"));
+ return -1;
+ }
+
+ /* ensure the recovery marker has been removed on disk */
+ if (transaction_sync(tdb, magic_offset, 4) == -1) {
+ return -1;
+ }
+ }
+
+ tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
+
+ /*
+ TODO: maybe write to some dummy hdr field, or write to magic
+ offset without mmap, before the last sync, instead of the
+ utime() call
+ */
+
+ /* on some systems (like Linux 2.6.x) changes via mmap/msync
+ don't change the mtime of the file, this means the file may
+ not be backed up (as tdb rounding to block sizes means that
+ file size changes are quite rare too). The following forces
+ mtime changes when a transaction completes */
+#ifdef HAVE_UTIME
+ utime(tdb->name, NULL);
+#endif
+
+ /* use a transaction cancel to free memory and remove the
+ transaction locks */
+ tdb_transaction_cancel(tdb);
+
+ return 0;
+}
+
+
+/*
+ recover from an aborted transaction. Must be called with exclusive
+ database write access already established (including the global
+ lock to prevent new processes attaching)
+*/
+int tdb_transaction_recover(struct tdb_context *tdb)
+{
+ tdb_off_t recovery_head, recovery_eof;
+ unsigned char *data, *p;
+ uint32_t zero = 0;
+ struct list_struct rec;
+
+ /* find the recovery area */
+ if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery head\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+ if (recovery_head == 0) {
+ /* we have never allocated a recovery record */
+ return 0;
+ }
+
+ /* read the recovery record */
+ if (tdb->methods->tdb_read(tdb, recovery_head, &rec,
+ sizeof(rec), DOCONV()) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery record\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+ if (rec.magic != TDB_RECOVERY_MAGIC) {
+ /* there is no valid recovery data */
+ return 0;
+ }
+
+ if (tdb->read_only) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: attempt to recover read only database\n"));
+ tdb->ecode = TDB_ERR_CORRUPT;
+ return -1;
+ }
+
+ recovery_eof = rec.key_len;
+
+ data = (unsigned char *)malloc(rec.data_len);
+ if (data == NULL) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to allocate recovery data\n"));
+ tdb->ecode = TDB_ERR_OOM;
+ return -1;
+ }
+
+ /* read the full recovery data */
+ if (tdb->methods->tdb_read(tdb, recovery_head + sizeof(rec), data,
+ rec.data_len, 0) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery data\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+ /* recover the file data */
+ p = data;
+ while (p+8 < data + rec.data_len) {
+ uint32_t ofs, len;
+ if (DOCONV()) {
+ tdb_convert(p, 8);
+ }
+ memcpy(&ofs, p, 4);
+ memcpy(&len, p+4, 4);
+
+ if (tdb->methods->tdb_write(tdb, ofs, p+8, len) == -1) {
+ free(data);
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to recover %d bytes at offset %d\n", len, ofs));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+ p += 8 + len;
+ }
+
+ free(data);
+
+ if (transaction_sync(tdb, 0, tdb->map_size) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to sync recovery\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+ /* if the recovery area is after the recovered eof then remove it */
+ if (recovery_eof <= recovery_head) {
+ if (tdb_ofs_write(tdb, TDB_RECOVERY_HEAD, &zero) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery head\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+ }
+
+ /* remove the recovery magic */
+ if (tdb_ofs_write(tdb, recovery_head + offsetof(struct list_struct, magic),
+ &zero) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery magic\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+ /* reduce the file size to the old size */
+ tdb_munmap(tdb);
+ if (ftruncate(tdb->fd, recovery_eof) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to reduce to recovery size\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+ tdb->map_size = recovery_eof;
+ tdb_mmap(tdb);
+
+ if (transaction_sync(tdb, 0, recovery_eof) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to sync2 recovery\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+ TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_recover: recovered %d byte database\n",
+ recovery_eof));
+
+ /* all done */
+ return 0;
+}
diff --git a/source3/lib/tdb/common/traverse.c b/source3/lib/tdb/common/traverse.c
new file mode 100644
index 0000000000..69c81e6e98
--- /dev/null
+++ b/source3/lib/tdb/common/traverse.c
@@ -0,0 +1,348 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2005
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+/* Uses traverse lock: 0 = finish, -1 = error, other = record offset */
+static int tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock *tlock,
+ struct list_struct *rec)
+{
+ int want_next = (tlock->off != 0);
+
+ /* Lock each chain from the start one. */
+ for (; tlock->hash < tdb->header.hash_size; tlock->hash++) {
+ if (!tlock->off && tlock->hash != 0) {
+ /* this is an optimisation for the common case where
+ the hash chain is empty, which is particularly
+ common for the use of tdb with ldb, where large
+ hashes are used. In that case we spend most of our
+ time in tdb_brlock(), locking empty hash chains.
+
+ To avoid this, we do an unlocked pre-check to see
+ if the hash chain is empty before starting to look
+ inside it. If it is empty then we can avoid that
+ hash chain. If it isn't empty then we can't believe
+ the value we get back, as we read it without a
+ lock, so instead we get the lock and re-fetch the
+ value below.
+
+ Notice that not doing this optimisation on the
+ first hash chain is critical. We must guarantee
+ that we have done at least one fcntl lock at the
+ start of a search to guarantee that memory is
+ coherent on SMP systems. If records are added by
+ others during the search then thats OK, and we
+ could possibly miss those with this trick, but we
+ could miss them anyway without this trick, so the
+ semantics don't change.
+
+ With a non-indexed ldb search this trick gains us a
+ factor of around 80 in speed on a linux 2.6.x
+ system (testing using ldbtest).
+ */
+ tdb->methods->next_hash_chain(tdb, &tlock->hash);
+ if (tlock->hash == tdb->header.hash_size) {
+ continue;
+ }
+ }
+
+ if (tdb_lock(tdb, tlock->hash, tlock->lock_rw) == -1)
+ return -1;
+
+ /* No previous record? Start at top of chain. */
+ if (!tlock->off) {
+ if (tdb_ofs_read(tdb, TDB_HASH_TOP(tlock->hash),
+ &tlock->off) == -1)
+ goto fail;
+ } else {
+ /* Otherwise unlock the previous record. */
+ if (tdb_unlock_record(tdb, tlock->off) != 0)
+ goto fail;
+ }
+
+ if (want_next) {
+ /* We have offset of old record: grab next */
+ if (tdb_rec_read(tdb, tlock->off, rec) == -1)
+ goto fail;
+ tlock->off = rec->next;
+ }
+
+ /* Iterate through chain */
+ while( tlock->off) {
+ tdb_off_t current;
+ if (tdb_rec_read(tdb, tlock->off, rec) == -1)
+ goto fail;
+
+ /* Detect infinite loops. From "Shlomi Yaakobovich" <Shlomi@exanet.com>. */
+ if (tlock->off == rec->next) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: loop detected.\n"));
+ goto fail;
+ }
+
+ if (!TDB_DEAD(rec)) {
+ /* Woohoo: we found one! */
+ if (tdb_lock_record(tdb, tlock->off) != 0)
+ goto fail;
+ return tlock->off;
+ }
+
+ /* Try to clean dead ones from old traverses */
+ current = tlock->off;
+ tlock->off = rec->next;
+ if (!(tdb->read_only || tdb->traverse_read) &&
+ tdb_do_delete(tdb, current, rec) != 0)
+ goto fail;
+ }
+ tdb_unlock(tdb, tlock->hash, tlock->lock_rw);
+ want_next = 0;
+ }
+ /* We finished iteration without finding anything */
+ return TDB_ERRCODE(TDB_SUCCESS, 0);
+
+ fail:
+ tlock->off = 0;
+ if (tdb_unlock(tdb, tlock->hash, tlock->lock_rw) != 0)
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: On error unlock failed!\n"));
+ return -1;
+}
+
+/* traverse the entire database - calling fn(tdb, key, data) on each element.
+ return -1 on error or the record count traversed
+ if fn is NULL then it is not called
+ a non-zero return value from fn() indicates that the traversal should stop
+ */
+static int tdb_traverse_internal(struct tdb_context *tdb,
+ tdb_traverse_func fn, void *private_data,
+ struct tdb_traverse_lock *tl)
+{
+ TDB_DATA key, dbuf;
+ struct list_struct rec;
+ int ret, count = 0;
+
+ /* This was in the initializaton, above, but the IRIX compiler
+ * did not like it. crh
+ */
+ tl->next = tdb->travlocks.next;
+
+ /* fcntl locks don't stack: beware traverse inside traverse */
+ tdb->travlocks.next = tl;
+
+ /* tdb_next_lock places locks on the record returned, and its chain */
+ while ((ret = tdb_next_lock(tdb, tl, &rec)) > 0) {
+ count++;
+ /* now read the full record */
+ key.dptr = tdb_alloc_read(tdb, tl->off + sizeof(rec),
+ rec.key_len + rec.data_len);
+ if (!key.dptr) {
+ ret = -1;
+ if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0)
+ goto out;
+ if (tdb_unlock_record(tdb, tl->off) != 0)
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: key.dptr == NULL and unlock_record failed!\n"));
+ goto out;
+ }
+ key.dsize = rec.key_len;
+ dbuf.dptr = key.dptr + rec.key_len;
+ dbuf.dsize = rec.data_len;
+
+ /* Drop chain lock, call out */
+ if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0) {
+ ret = -1;
+ SAFE_FREE(key.dptr);
+ goto out;
+ }
+ if (fn && fn(tdb, key, dbuf, private_data)) {
+ /* They want us to terminate traversal */
+ ret = count;
+ if (tdb_unlock_record(tdb, tl->off) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: unlock_record failed!\n"));;
+ ret = -1;
+ }
+ SAFE_FREE(key.dptr);
+ goto out;
+ }
+ SAFE_FREE(key.dptr);
+ }
+out:
+ tdb->travlocks.next = tl->next;
+ if (ret < 0)
+ return -1;
+ else
+ return count;
+}
+
+
+/*
+ a write style traverse - temporarily marks the db read only
+*/
+int tdb_traverse_read(struct tdb_context *tdb,
+ tdb_traverse_func fn, void *private_data)
+{
+ struct tdb_traverse_lock tl = { NULL, 0, 0, F_RDLCK };
+ int ret;
+ bool in_transaction = (tdb->transaction != NULL);
+
+ /* we need to get a read lock on the transaction lock here to
+ cope with the lock ordering semantics of solaris10 */
+ if (!in_transaction) {
+ if (tdb_transaction_lock(tdb, F_RDLCK)) {
+ return -1;
+ }
+ }
+
+ tdb->traverse_read++;
+ ret = tdb_traverse_internal(tdb, fn, private_data, &tl);
+ tdb->traverse_read--;
+
+ if (!in_transaction) {
+ tdb_transaction_unlock(tdb);
+ }
+
+ return ret;
+}
+
+/*
+ a write style traverse - needs to get the transaction lock to
+ prevent deadlocks
+
+ WARNING: The data buffer given to the callback fn does NOT meet the
+ alignment restrictions malloc gives you.
+*/
+int tdb_traverse(struct tdb_context *tdb,
+ tdb_traverse_func fn, void *private_data)
+{
+ struct tdb_traverse_lock tl = { NULL, 0, 0, F_WRLCK };
+ int ret;
+ bool in_transaction = (tdb->transaction != NULL);
+
+ if (tdb->read_only || tdb->traverse_read) {
+ return tdb_traverse_read(tdb, fn, private_data);
+ }
+
+ if (!in_transaction) {
+ if (tdb_transaction_lock(tdb, F_WRLCK)) {
+ return -1;
+ }
+ }
+
+ tdb->traverse_write++;
+ ret = tdb_traverse_internal(tdb, fn, private_data, &tl);
+ tdb->traverse_write--;
+
+ if (!in_transaction) {
+ tdb_transaction_unlock(tdb);
+ }
+
+ return ret;
+}
+
+
+/* find the first entry in the database and return its key */
+TDB_DATA tdb_firstkey(struct tdb_context *tdb)
+{
+ TDB_DATA key;
+ struct list_struct rec;
+
+ /* release any old lock */
+ if (tdb_unlock_record(tdb, tdb->travlocks.off) != 0)
+ return tdb_null;
+ tdb->travlocks.off = tdb->travlocks.hash = 0;
+ tdb->travlocks.lock_rw = F_RDLCK;
+
+ /* Grab first record: locks chain and returned record. */
+ if (tdb_next_lock(tdb, &tdb->travlocks, &rec) <= 0)
+ return tdb_null;
+ /* now read the key */
+ key.dsize = rec.key_len;
+ key.dptr =tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),key.dsize);
+
+ /* Unlock the hash chain of the record we just read. */
+ if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0)
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_firstkey: error occurred while tdb_unlocking!\n"));
+ return key;
+}
+
+/* find the next entry in the database, returning its key */
+TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
+{
+ uint32_t oldhash;
+ TDB_DATA key = tdb_null;
+ struct list_struct rec;
+ unsigned char *k = NULL;
+
+ /* Is locked key the old key? If so, traverse will be reliable. */
+ if (tdb->travlocks.off) {
+ if (tdb_lock(tdb,tdb->travlocks.hash,tdb->travlocks.lock_rw))
+ return tdb_null;
+ if (tdb_rec_read(tdb, tdb->travlocks.off, &rec) == -1
+ || !(k = tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),
+ rec.key_len))
+ || memcmp(k, oldkey.dptr, oldkey.dsize) != 0) {
+ /* No, it wasn't: unlock it and start from scratch */
+ if (tdb_unlock_record(tdb, tdb->travlocks.off) != 0) {
+ SAFE_FREE(k);
+ return tdb_null;
+ }
+ if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0) {
+ SAFE_FREE(k);
+ return tdb_null;
+ }
+ tdb->travlocks.off = 0;
+ }
+
+ SAFE_FREE(k);
+ }
+
+ if (!tdb->travlocks.off) {
+ /* No previous element: do normal find, and lock record */
+ tdb->travlocks.off = tdb_find_lock_hash(tdb, oldkey, tdb->hash_fn(&oldkey), tdb->travlocks.lock_rw, &rec);
+ if (!tdb->travlocks.off)
+ return tdb_null;
+ tdb->travlocks.hash = BUCKET(rec.full_hash);
+ if (tdb_lock_record(tdb, tdb->travlocks.off) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: lock_record failed (%s)!\n", strerror(errno)));
+ return tdb_null;
+ }
+ }
+ oldhash = tdb->travlocks.hash;
+
+ /* Grab next record: locks chain and returned record,
+ unlocks old record */
+ if (tdb_next_lock(tdb, &tdb->travlocks, &rec) > 0) {
+ key.dsize = rec.key_len;
+ key.dptr = tdb_alloc_read(tdb, tdb->travlocks.off+sizeof(rec),
+ key.dsize);
+ /* Unlock the chain of this new record */
+ if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0)
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
+ }
+ /* Unlock the chain of old record */
+ if (tdb_unlock(tdb, BUCKET(oldhash), tdb->travlocks.lock_rw) != 0)
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
+ return key;
+}
+
diff --git a/source3/lib/tdb/config.guess b/source3/lib/tdb/config.guess
new file mode 100755
index 0000000000..354dbe175a
--- /dev/null
+++ b/source3/lib/tdb/config.guess
@@ -0,0 +1,1464 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+timestamp='2005-08-03'
+
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerppc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # 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 ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ 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 ;;
+ 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 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????: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 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ 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 ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep __LP64__ >/dev/null
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ x86:Interix*:[34]*)
+ echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
+ exit ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #ifdef __INTEL_COMPILER
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+ test x"${LIBC}" != x && {
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit
+ }
+ test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ 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 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *: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 ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ *86) UNAME_PROCESSOR=i686 ;;
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# 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 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+and
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/source3/lib/tdb/config.mk b/source3/lib/tdb/config.mk
new file mode 100644
index 0000000000..b9a8f80dda
--- /dev/null
+++ b/source3/lib/tdb/config.mk
@@ -0,0 +1,57 @@
+################################################
+# Start SUBSYSTEM LIBTDB
+[LIBRARY::LIBTDB]
+OUTPUT_TYPE = STATIC_LIBRARY
+CFLAGS = -Ilib/tdb/include
+#
+# End SUBSYSTEM ldb
+################################################
+
+LIBTDB_OBJ_FILES = $(addprefix lib/tdb/common/, \
+ tdb.o dump.o io.o lock.o \
+ open.o traverse.o freelist.o \
+ error.o transaction.o)
+
+################################################
+# Start BINARY tdbtool
+[BINARY::tdbtool]
+INSTALLDIR = BINDIR
+PRIVATE_DEPENDENCIES = \
+ LIBTDB
+# End BINARY tdbtool
+################################################
+
+tdbtool_OBJ_FILES = lib/tdb/tools/tdbtool.o
+
+################################################
+# Start BINARY tdbtorture
+[BINARY::tdbtorture]
+INSTALLDIR = BINDIR
+PRIVATE_DEPENDENCIES = \
+ LIBTDB
+# End BINARY tdbtorture
+################################################
+
+tdbtorture_OBJ_FILES = lib/tdb/tools/tdbtorture.o
+
+################################################
+# Start BINARY tdbdump
+[BINARY::tdbdump]
+INSTALLDIR = BINDIR
+PRIVATE_DEPENDENCIES = \
+ LIBTDB
+# End BINARY tdbdump
+################################################
+
+tdbdump_OBJ_FILES = lib/tdb/tools/tdbdump.o
+
+################################################
+# Start BINARY tdbbackup
+[BINARY::tdbbackup]
+INSTALLDIR = BINDIR
+PRIVATE_DEPENDENCIES = \
+ LIBTDB
+# End BINARY tdbbackup
+################################################
+
+tdbbackup_OBJ_FILES = lib/tdb/tools/tdbbackup.o
diff --git a/source3/lib/tdb/config.sub b/source3/lib/tdb/config.sub
new file mode 100755
index 0000000000..23cd6fd75c
--- /dev/null
+++ b/source3/lib/tdb/config.sub
@@ -0,0 +1,1577 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+timestamp='2005-07-08'
+
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \
+ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64vr | mips64vrel \
+ | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | ms1 \
+ | msp430 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b \
+ | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m32c)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | ms1-* \
+ | msp430-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ m32c-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ 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 | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16c)
+ basic_machine=cr16c-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/source3/lib/tdb/configure.ac b/source3/lib/tdb/configure.ac
new file mode 100644
index 0000000000..eaf70d30b4
--- /dev/null
+++ b/source3/lib/tdb/configure.ac
@@ -0,0 +1,30 @@
+AC_PREREQ(2.50)
+AC_DEFUN([SMB_MODULE_DEFAULT], [echo -n ""])
+AC_DEFUN([SMB_LIBRARY_ENABLE], [echo -n ""])
+AC_DEFUN([SMB_ENABLE], [echo -n ""])
+AC_INIT(tdb, 1.1.2)
+AC_CONFIG_SRCDIR([common/tdb.c])
+AC_CONFIG_HEADER(include/config.h)
+AC_LIBREPLACE_ALL_CHECKS
+AC_LD_SONAMEFLAG
+AC_LD_PICFLAG
+AC_LD_SHLIBEXT
+AC_LIBREPLACE_SHLD
+AC_LIBREPLACE_SHLD_FLAGS
+AC_LIBREPLACE_RUNTIME_LIB_PATH_VAR
+m4_include(libtdb.m4)
+AC_PATH_PROGS([PYTHON_CONFIG], [python2.6-config python2.5-config python2.4-config python-config])
+AC_PATH_PROGS([PYTHON], [python2.6 python2.5 python2.4 python])
+
+PYTHON_BUILD_TARGET="build-python"
+PYTHON_INSTALL_TARGET="install-python"
+PYTHON_CHECK_TARGET="check-python"
+AC_SUBST(PYTHON_BUILD_TARGET)
+AC_SUBST(PYTHON_INSTALL_TARGET)
+AC_SUBST(PYTHON_CHECK_TARGET)
+if test -z "$PYTHON_CONFIG"; then
+ PYTHON_BUILD_TARGET=""
+ PYTHON_INSTALL_TARGET=""
+ PYTHON_CHECK_TARGET=""
+fi
+AC_OUTPUT(Makefile tdb.pc)
diff --git a/source3/lib/tdb/docs/README b/source3/lib/tdb/docs/README
new file mode 100644
index 0000000000..63fcf5e049
--- /dev/null
+++ b/source3/lib/tdb/docs/README
@@ -0,0 +1,238 @@
+tdb - a trivial database system
+tridge@linuxcare.com December 1999
+==================================
+
+This is a simple database API. It was inspired by the realisation that
+in Samba we have several ad-hoc bits of code that essentially
+implement small databases for sharing structures between parts of
+Samba. As I was about to add another I realised that a generic
+database module was called for to replace all the ad-hoc bits.
+
+I based the interface on gdbm. I couldn't use gdbm as we need to be
+able to have multiple writers to the databases at one time.
+
+Compilation
+-----------
+
+add HAVE_MMAP=1 to use mmap instead of read/write
+add NOLOCK=1 to disable locking code
+
+Testing
+-------
+
+Compile tdbtest.c and link with gdbm for testing. tdbtest will perform
+identical operations via tdb and gdbm then make sure the result is the
+same
+
+Also included is tdbtool, which allows simple database manipulation
+on the commandline.
+
+tdbtest and tdbtool are not built as part of Samba, but are included
+for completeness.
+
+Interface
+---------
+
+The interface is very similar to gdbm except for the following:
+
+- different open interface. The tdb_open call is more similar to a
+ traditional open()
+- no tdbm_reorganise() function
+- no tdbm_sync() function. No operations are cached in the library anyway
+- added a tdb_traverse() function for traversing the whole database
+- added transactions support
+
+A general rule for using tdb is that the caller frees any returned
+TDB_DATA structures. Just call free(p.dptr) to free a TDB_DATA
+return value called p. This is the same as gdbm.
+
+here is a full list of tdb functions with brief descriptions.
+
+
+----------------------------------------------------------------------
+TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode)
+
+ open the database, creating it if necessary
+
+ The open_flags and mode are passed straight to the open call on the database
+ file. A flags value of O_WRONLY is invalid
+
+ The hash size is advisory, use zero for a default value.
+
+ return is NULL on error
+
+ possible tdb_flags are:
+ TDB_CLEAR_IF_FIRST - clear database if we are the only one with it open
+ TDB_INTERNAL - don't use a file, instaed store the data in
+ memory. The filename is ignored in this case.
+ TDB_NOLOCK - don't do any locking
+ TDB_NOMMAP - don't use mmap
+ TDB_NOSYNC - don't synchronise transactions to disk
+
+----------------------------------------------------------------------
+TDB_CONTEXT *tdb_open_ex(char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode,
+ tdb_log_func log_fn,
+ tdb_hash_func hash_fn)
+
+This is like tdb_open(), but allows you to pass an initial logging and
+hash function. Be careful when passing a hash function - all users of
+the database must use the same hash function or you will get data
+corruption.
+
+
+----------------------------------------------------------------------
+char *tdb_error(TDB_CONTEXT *tdb);
+
+ return a error string for the last tdb error
+
+----------------------------------------------------------------------
+int tdb_close(TDB_CONTEXT *tdb);
+
+ close a database
+
+----------------------------------------------------------------------
+int tdb_update(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf);
+
+ update an entry in place - this only works if the new data size
+ is <= the old data size and the key exists.
+ on failure return -1
+
+----------------------------------------------------------------------
+TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ fetch an entry in the database given a key
+ if the return value has a null dptr then a error occurred
+
+ caller must free the resulting data
+
+----------------------------------------------------------------------
+int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ check if an entry in the database exists
+
+ note that 1 is returned if the key is found and 0 is returned if not found
+ this doesn't match the conventions in the rest of this module, but is
+ compatible with gdbm
+
+----------------------------------------------------------------------
+int tdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb,
+ TDB_DATA key, TDB_DATA dbuf, void *state), void *state);
+
+ traverse the entire database - calling fn(tdb, key, data, state) on each
+ element.
+
+ return -1 on error or the record count traversed
+
+ if fn is NULL then it is not called
+
+ a non-zero return value from fn() indicates that the traversal
+ should stop. Traversal callbacks may not start transactions.
+
+ WARNING: The data buffer given to the callback fn does NOT meet the
+ alignment restrictions malloc gives you.
+
+----------------------------------------------------------------------
+int tdb_traverse_read(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb,
+ TDB_DATA key, TDB_DATA dbuf, void *state), void *state);
+
+ traverse the entire database - calling fn(tdb, key, data, state) on
+ each element, but marking the database read only during the
+ traversal, so any write operations will fail. This allows tdb to
+ use read locks, which increases the parallelism possible during the
+ traversal.
+
+ return -1 on error or the record count traversed
+
+ if fn is NULL then it is not called
+
+ a non-zero return value from fn() indicates that the traversal
+ should stop. Traversal callbacks may not start transactions.
+
+----------------------------------------------------------------------
+TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb);
+
+ find the first entry in the database and return its key
+
+ the caller must free the returned data
+
+----------------------------------------------------------------------
+TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ find the next entry in the database, returning its key
+
+ the caller must free the returned data
+
+----------------------------------------------------------------------
+int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ delete an entry in the database given a key
+
+----------------------------------------------------------------------
+int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
+
+ store an element in the database, replacing any existing element
+ with the same key
+
+ If flag==TDB_INSERT then don't overwrite an existing entry
+ If flag==TDB_MODIFY then don't create a new entry
+
+ return 0 on success, -1 on failure
+
+----------------------------------------------------------------------
+int tdb_writelock(TDB_CONTEXT *tdb);
+
+ lock the database. If we already have it locked then don't do anything
+
+----------------------------------------------------------------------
+int tdb_writeunlock(TDB_CONTEXT *tdb);
+ unlock the database
+
+----------------------------------------------------------------------
+int tdb_lockchain(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ lock one hash chain. This is meant to be used to reduce locking
+ contention - it cannot guarantee how many records will be locked
+
+----------------------------------------------------------------------
+int tdb_unlockchain(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ unlock one hash chain
+
+----------------------------------------------------------------------
+int tdb_transaction_start(TDB_CONTEXT *tdb)
+
+ start a transaction. All operations after the transaction start can
+ either be committed with tdb_transaction_commit() or cancelled with
+ tdb_transaction_cancel().
+
+ If you call tdb_transaction_start() again on the same tdb context
+ while a transaction is in progress, then the same transaction
+ buffer is re-used. The number of tdb_transaction_{commit,cancel}
+ operations must match the number of successful
+ tdb_transaction_start() calls.
+
+ Note that transactions are by default disk synchronous, and use a
+ recover area in the database to automatically recover the database
+ on the next open if the system crashes during a transaction. You
+ can disable the synchronous transaction recovery setup using the
+ TDB_NOSYNC flag, which will greatly speed up operations at the risk
+ of corrupting your database if the system crashes.
+
+ Operations made within a transaction are not visible to other users
+ of the database until a successful commit.
+
+----------------------------------------------------------------------
+int tdb_transaction_cancel(TDB_CONTEXT *tdb)
+
+ cancel a current transaction, discarding all write and lock
+ operations that have been made since the transaction started.
+
+
+----------------------------------------------------------------------
+int tdb_transaction_commit(TDB_CONTEXT *tdb)
+
+ commit a current transaction, updating the database and releasing
+ the transaction locks.
+
diff --git a/source3/lib/tdb/docs/tdb.magic b/source3/lib/tdb/docs/tdb.magic
new file mode 100644
index 0000000000..f5619e7327
--- /dev/null
+++ b/source3/lib/tdb/docs/tdb.magic
@@ -0,0 +1,10 @@
+# Magic file(1) information about tdb files.
+#
+# Install this into /etc/magic or the corresponding location for your
+# system, or pass as a -m argument to file(1).
+
+# You may use and redistribute this file without restriction.
+
+0 string TDB\ file TDB database
+>32 lelong =0x2601196D version 6, little-endian
+>>36 lelong x hash size %d bytes
diff --git a/source3/lib/tdb/include/tdb.h b/source3/lib/tdb/include/tdb.h
new file mode 100644
index 0000000000..0008085de5
--- /dev/null
+++ b/source3/lib/tdb/include/tdb.h
@@ -0,0 +1,167 @@
+#ifndef __TDB_H__
+#define __TDB_H__
+
+/*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2004
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* flags to tdb_store() */
+#define TDB_REPLACE 1 /* Unused */
+#define TDB_INSERT 2 /* Don't overwrite an existing entry */
+#define TDB_MODIFY 3 /* Don't create an existing entry */
+
+/* flags for tdb_open() */
+#define TDB_DEFAULT 0 /* just a readability place holder */
+#define TDB_CLEAR_IF_FIRST 1
+#define TDB_INTERNAL 2 /* don't store on disk */
+#define TDB_NOLOCK 4 /* don't do any locking */
+#define TDB_NOMMAP 8 /* don't use mmap */
+#define TDB_CONVERT 16 /* convert endian (internal use) */
+#define TDB_BIGENDIAN 32 /* header is big-endian (internal use) */
+#define TDB_NOSYNC 64 /* don't use synchronous transactions */
+#define TDB_SEQNUM 128 /* maintain a sequence number */
+#define TDB_VOLATILE 256 /* Activate the per-hashchain freelist, default 5 */
+
+#define TDB_ERRCODE(code, ret) ((tdb->ecode = (code)), ret)
+
+/* error codes */
+enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK,
+ TDB_ERR_OOM, TDB_ERR_EXISTS, TDB_ERR_NOLOCK, TDB_ERR_LOCK_TIMEOUT,
+ TDB_ERR_NOEXIST, TDB_ERR_EINVAL, TDB_ERR_RDONLY};
+
+/* debugging uses one of the following levels */
+enum tdb_debug_level {TDB_DEBUG_FATAL = 0, TDB_DEBUG_ERROR,
+ TDB_DEBUG_WARNING, TDB_DEBUG_TRACE};
+
+typedef struct TDB_DATA {
+ unsigned char *dptr;
+ size_t dsize;
+} TDB_DATA;
+
+#ifndef PRINTF_ATTRIBUTE
+#if (__GNUC__ >= 3)
+/** Use gcc attribute to check printf fns. a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument. Note that some gcc 2.x versions don't handle this
+ * properly **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+#endif
+
+/* this is the context structure that is returned from a db open */
+typedef struct tdb_context TDB_CONTEXT;
+
+typedef int (*tdb_traverse_func)(struct tdb_context *, TDB_DATA, TDB_DATA, void *);
+typedef void (*tdb_log_func)(struct tdb_context *, enum tdb_debug_level, const char *, ...) PRINTF_ATTRIBUTE(3, 4);
+typedef unsigned int (*tdb_hash_func)(TDB_DATA *key);
+
+struct tdb_logging_context {
+ tdb_log_func log_fn;
+ void *log_private;
+};
+
+struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode);
+struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode,
+ const struct tdb_logging_context *log_ctx,
+ tdb_hash_func hash_fn);
+void tdb_set_max_dead(struct tdb_context *tdb, int max_dead);
+
+int tdb_reopen(struct tdb_context *tdb);
+int tdb_reopen_all(int parent_longlived);
+void tdb_set_logging_function(struct tdb_context *tdb, const struct tdb_logging_context *log_ctx);
+enum TDB_ERROR tdb_error(struct tdb_context *tdb);
+const char *tdb_errorstr(struct tdb_context *tdb);
+TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
+int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
+ int (*parser)(TDB_DATA key, TDB_DATA data,
+ void *private_data),
+ void *private_data);
+int tdb_delete(struct tdb_context *tdb, TDB_DATA key);
+int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
+int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf);
+int tdb_close(struct tdb_context *tdb);
+TDB_DATA tdb_firstkey(struct tdb_context *tdb);
+TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA key);
+int tdb_traverse(struct tdb_context *tdb, tdb_traverse_func fn, void *);
+int tdb_traverse_read(struct tdb_context *tdb, tdb_traverse_func fn, void *);
+int tdb_exists(struct tdb_context *tdb, TDB_DATA key);
+int tdb_lockall(struct tdb_context *tdb);
+int tdb_lockall_nonblock(struct tdb_context *tdb);
+int tdb_unlockall(struct tdb_context *tdb);
+int tdb_lockall_read(struct tdb_context *tdb);
+int tdb_lockall_read_nonblock(struct tdb_context *tdb);
+int tdb_unlockall_read(struct tdb_context *tdb);
+int tdb_lockall_mark(struct tdb_context *tdb);
+int tdb_lockall_unmark(struct tdb_context *tdb);
+const char *tdb_name(struct tdb_context *tdb);
+int tdb_fd(struct tdb_context *tdb);
+tdb_log_func tdb_log_fn(struct tdb_context *tdb);
+void *tdb_get_logging_private(struct tdb_context *tdb);
+int tdb_transaction_start(struct tdb_context *tdb);
+int tdb_transaction_commit(struct tdb_context *tdb);
+int tdb_transaction_cancel(struct tdb_context *tdb);
+int tdb_transaction_recover(struct tdb_context *tdb);
+int tdb_get_seqnum(struct tdb_context *tdb);
+int tdb_hash_size(struct tdb_context *tdb);
+size_t tdb_map_size(struct tdb_context *tdb);
+int tdb_get_flags(struct tdb_context *tdb);
+void tdb_add_flags(struct tdb_context *tdb, unsigned flag);
+void tdb_remove_flags(struct tdb_context *tdb, unsigned flag);
+void tdb_enable_seqnum(struct tdb_context *tdb);
+void tdb_increment_seqnum_nonblock(struct tdb_context *tdb);
+
+/* Low level locking functions: use with care */
+int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key);
+int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key);
+int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key);
+int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key);
+int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key);
+int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key);
+int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key);
+
+void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *sigptr);
+
+/* Debug functions. Not used in production. */
+void tdb_dump_all(struct tdb_context *tdb);
+int tdb_printfreelist(struct tdb_context *tdb);
+int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries);
+int tdb_wipe_all(struct tdb_context *tdb);
+int tdb_freelist_size(struct tdb_context *tdb);
+
+extern TDB_DATA tdb_null;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* tdb.h */
diff --git a/source3/lib/tdb/install-sh b/source3/lib/tdb/install-sh
new file mode 100755
index 0000000000..58719246f0
--- /dev/null
+++ b/source3/lib/tdb/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/source3/lib/tdb/libtdb.m4 b/source3/lib/tdb/libtdb.m4
new file mode 100644
index 0000000000..1e17a7a4f2
--- /dev/null
+++ b/source3/lib/tdb/libtdb.m4
@@ -0,0 +1,30 @@
+dnl find the tdb sources. This is meant to work both for
+dnl tdb standalone builds, and builds of packages using tdb
+tdbdir=""
+tdbpaths="$srcdir $srcdir/lib/tdb $srcdir/tdb $srcdir/../tdb"
+for d in $tdbpaths; do
+ if test -f "$d/common/tdb.c"; then
+ tdbdir="$d"
+ AC_SUBST(tdbdir)
+ break;
+ fi
+done
+if test x"$tdbdir" = "x"; then
+ AC_MSG_ERROR([cannot find tdb source in $tdbpaths])
+fi
+TDB_OBJ="common/tdb.o common/dump.o common/transaction.o common/error.o common/traverse.o"
+TDB_OBJ="$TDB_OBJ common/freelist.o common/freelistcheck.o common/io.o common/lock.o common/open.o"
+AC_SUBST(TDB_OBJ)
+AC_SUBST(LIBREPLACEOBJ)
+
+TDB_LIBS=""
+AC_SUBST(TDB_LIBS)
+
+TDB_CFLAGS="-I$tdbdir/include"
+AC_SUBST(TDB_CFLAGS)
+
+AC_CHECK_FUNCS(mmap pread pwrite getpagesize utime)
+AC_CHECK_HEADERS(getopt.h sys/select.h sys/time.h)
+
+AC_HAVE_DECL(pread, [#include <unistd.h>])
+AC_HAVE_DECL(pwrite, [#include <unistd.h>])
diff --git a/source3/lib/tdb/python.mk b/source3/lib/tdb/python.mk
new file mode 100644
index 0000000000..12e8217df9
--- /dev/null
+++ b/source3/lib/tdb/python.mk
@@ -0,0 +1,10 @@
+[PYTHON::swig_tdb]
+LIBRARY_REALNAME = _tdb.$(SHLIBEXT)
+PUBLIC_DEPENDENCIES = LIBTDB DYNCONFIG
+
+swig_tdb_OBJ_FILES = $(tdbsrcdir)/tdb_wrap.o
+
+$(eval $(call python_py_module_template,tdb.py,$(tdbsrcdir)/tdb.py))
+
+$(swig_tdb_OBJ_FILES): CFLAGS+=$(CFLAG_NO_UNUSED_MACROS) $(CFLAG_NO_CAST_QUAL)
+
diff --git a/source3/lib/tdb/python/tdbdump.py b/source3/lib/tdb/python/tdbdump.py
new file mode 100644
index 0000000000..d759d771c8
--- /dev/null
+++ b/source3/lib/tdb/python/tdbdump.py
@@ -0,0 +1,12 @@
+#!/usr/bin/python
+# Trivial reimplementation of tdbdump in Python
+
+import tdb, sys
+
+if len(sys.argv) < 2:
+ print "Usage: tdbdump.py <tdb-file>"
+ sys.exit(1)
+
+db = tdb.Tdb(sys.argv[1])
+for (k, v) in db.iteritems():
+ print "{\nkey(%d) = %r\ndata(%d) = %r\n}" % (len(k), k, len(v), v)
diff --git a/source3/lib/tdb/python/tests/simple.py b/source3/lib/tdb/python/tests/simple.py
new file mode 100644
index 0000000000..7147718c91
--- /dev/null
+++ b/source3/lib/tdb/python/tests/simple.py
@@ -0,0 +1,152 @@
+#!/usr/bin/python
+# Some simple tests for the Python bindings for TDB
+# Note that this tests the interface of the Python bindings
+# It does not test tdb itself.
+#
+# Copyright (C) 2007-2008 Jelmer Vernooij <jelmer@samba.org>
+# Published under the GNU LGPLv3 or later
+
+import tdb
+from unittest import TestCase
+import os, tempfile
+
+
+class OpenTdbTests(TestCase):
+ def test_nonexistant_read(self):
+ self.assertRaises(IOError, tdb.Tdb, "/some/nonexistant/file", 0, tdb.DEFAULT, os.O_RDWR)
+
+
+class SimpleTdbTests(TestCase):
+ def setUp(self):
+ super(SimpleTdbTests, self).setUp()
+ self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT, os.O_CREAT|os.O_RDWR)
+ self.assertNotEqual(None, self.tdb)
+
+ def tearDown(self):
+ del self.tdb
+
+ def test_repr(self):
+ self.assertTrue(repr(self.tdb).startswith("Tdb('"))
+
+ def test_lockall(self):
+ self.tdb.lock_all()
+
+ def test_max_dead(self):
+ self.tdb.max_dead = 20
+
+ def test_unlockall(self):
+ self.tdb.lock_all()
+ self.tdb.unlock_all()
+
+ def test_lockall_read(self):
+ self.tdb.read_lock_all()
+ self.tdb.read_unlock_all()
+
+ def test_reopen(self):
+ self.tdb.reopen()
+
+ def test_store(self):
+ self.tdb.store("bar", "bla")
+ self.assertEquals("bla", self.tdb.get("bar"))
+
+ def test_getitem(self):
+ self.tdb["bar"] = "foo"
+ self.tdb.reopen()
+ self.assertEquals("foo", self.tdb["bar"])
+
+ def test_delete(self):
+ self.tdb["bar"] = "foo"
+ del self.tdb["bar"]
+ self.assertRaises(KeyError, lambda: self.tdb["bar"])
+
+ def test_contains(self):
+ self.tdb["bla"] = "bloe"
+ self.assertTrue("bla" in self.tdb)
+
+ def test_keyerror(self):
+ self.assertRaises(KeyError, lambda: self.tdb["bla"])
+
+ def test_hash_size(self):
+ self.tdb.hash_size
+
+ def test_map_size(self):
+ self.tdb.map_size
+
+ def test_name(self):
+ self.tdb.name
+
+ def test_iterator(self):
+ self.tdb["bla"] = "1"
+ self.tdb["brainslug"] = "2"
+ self.assertEquals(["bla", "brainslug"], list(self.tdb))
+
+ def test_items(self):
+ self.tdb["bla"] = "1"
+ self.tdb["brainslug"] = "2"
+ self.assertEquals([("bla", "1"), ("brainslug", "2")], self.tdb.items())
+
+ def test_iteritems(self):
+ self.tdb["bloe"] = "2"
+ self.tdb["bla"] = "25"
+ i = self.tdb.iteritems()
+ self.assertEquals(set([("bla", "25"), ("bloe", "2")]),
+ set([i.next(), i.next()]))
+
+ def test_transaction_cancel(self):
+ self.tdb["bloe"] = "2"
+ self.tdb.transaction_start()
+ self.tdb["bloe"] = "1"
+ self.tdb.transaction_cancel()
+ self.assertEquals("2", self.tdb["bloe"])
+
+ def test_transaction_commit(self):
+ self.tdb["bloe"] = "2"
+ self.tdb.transaction_start()
+ self.tdb["bloe"] = "1"
+ self.tdb.transaction_commit()
+ self.assertEquals("1", self.tdb["bloe"])
+
+ def test_iterator(self):
+ self.tdb["bloe"] = "2"
+ self.tdb["bla"] = "hoi"
+ i = iter(self.tdb)
+ self.assertEquals(set(["bloe", "bla"]), set([i.next(), i.next()]))
+
+ def test_keys(self):
+ self.tdb["bloe"] = "2"
+ self.tdb["bla"] = "25"
+ self.assertEquals(["bla", "bloe"], self.tdb.keys())
+
+ def test_iterkeys(self):
+ self.tdb["bloe"] = "2"
+ self.tdb["bla"] = "25"
+ i = self.tdb.iterkeys()
+ self.assertEquals(set(["bloe", "bla"]), set([i.next(), i.next()]))
+
+ def test_values(self):
+ self.tdb["bloe"] = "2"
+ self.tdb["bla"] = "25"
+ self.assertEquals(["25", "2"], self.tdb.values())
+
+ def test_itervalues(self):
+ self.tdb["bloe"] = "2"
+ self.tdb["bla"] = "25"
+ i = self.tdb.itervalues()
+ self.assertEquals(set(["25", "2"]), set([i.next(), i.next()]))
+
+ def test_clear(self):
+ self.tdb["bloe"] = "2"
+ self.tdb["bla"] = "25"
+ self.assertEquals(2, len(self.tdb))
+ self.tdb.clear()
+ self.assertEquals(0, len(self.tdb))
+
+ def test_len(self):
+ self.assertEquals(0, len(self.tdb))
+ self.tdb["entry"] = "value"
+ self.assertEquals(1, len(self.tdb))
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.TestProgram()
diff --git a/source3/lib/tdb/rules.mk b/source3/lib/tdb/rules.mk
new file mode 100644
index 0000000000..7b765625df
--- /dev/null
+++ b/source3/lib/tdb/rules.mk
@@ -0,0 +1,21 @@
+.SUFFIXES: .i _wrap.c
+
+.i_wrap.c:
+ $(SWIG) -O -Wall -python -keyword $<
+
+showflags::
+ @echo 'tdb will be compiled with flags:'
+ @echo ' CFLAGS = $(CFLAGS)'
+ @echo ' CPPFLAGS = $(CPPFLAGS)'
+ @echo ' LDFLAGS = $(LDFLAGS)'
+ @echo ' LIBS = $(LIBS)'
+
+.SUFFIXES: .c .o
+
+.c.o:
+ @echo Compiling $*.c
+ @mkdir -p `dirname $@`
+ @$(CC) $(PICFLAG) $(CFLAGS) -c $< -o $@
+
+distclean::
+ rm -f *~ */*~
diff --git a/source3/lib/tdb/tdb.i b/source3/lib/tdb/tdb.i
new file mode 100644
index 0000000000..3d8b697732
--- /dev/null
+++ b/source3/lib/tdb/tdb.i
@@ -0,0 +1,323 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Swig interface to tdb.
+
+ Copyright (C) 2004-2006 Tim Potter <tpot@samba.org>
+ Copyright (C) 2007 Jelmer Vernooij <jelmer@samba.org>
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+%define DOCSTRING
+"TDB is a simple key-value database similar to GDBM that supports multiple writers."
+%enddef
+
+%module(docstring=DOCSTRING) tdb
+
+%{
+
+/* This symbol is used in both includes.h and Python.h which causes an
+ annoying compiler warning. */
+
+#ifdef HAVE_FSTAT
+#undef HAVE_FSTAT
+#endif
+
+/* Include tdb headers */
+#include <stdint.h>
+#include <signal.h>
+#include <tdb.h>
+#include <fcntl.h>
+
+typedef TDB_CONTEXT tdb;
+%}
+
+/* The tdb functions will crash if a NULL tdb context is passed */
+
+%import exception.i
+%import stdint.i
+
+%typemap(check,noblock=1) TDB_CONTEXT* {
+ if ($1 == NULL)
+ SWIG_exception(SWIG_ValueError,
+ "tdb context must be non-NULL");
+}
+
+/* In and out typemaps for the TDB_DATA structure. This is converted to
+ and from the Python string type which can contain arbitrary binary
+ data.. */
+
+%typemap(in,noblock=1) TDB_DATA {
+ if ($input == Py_None) {
+ $1.dsize = 0;
+ $1.dptr = NULL;
+ } else if (!PyString_Check($input)) {
+ PyErr_SetString(PyExc_TypeError, "string arg expected");
+ return NULL;
+ } else {
+ $1.dsize = PyString_Size($input);
+ $1.dptr = (uint8_t *)PyString_AsString($input);
+ }
+}
+
+%typemap(out,noblock=1) TDB_DATA {
+ if ($1.dptr == NULL && $1.dsize == 0) {
+ $result = Py_None;
+ } else {
+ $result = PyString_FromStringAndSize((const char *)$1.dptr, $1.dsize);
+ free($1.dptr);
+ }
+}
+
+/* Treat a mode_t as an unsigned integer */
+typedef int mode_t;
+
+/* flags to tdb_store() */
+%constant int REPLACE = TDB_REPLACE;
+%constant int INSERT = TDB_INSERT;
+%constant int MODIFY = TDB_MODIFY;
+
+/* flags for tdb_open() */
+%constant int DEFAULT = TDB_DEFAULT;
+%constant int CLEAR_IF_FIRST = TDB_CLEAR_IF_FIRST;
+%constant int INTERNAL = TDB_INTERNAL;
+%constant int NOLOCK = TDB_NOLOCK;
+%constant int NOMMAP = TDB_NOMMAP;
+%constant int CONVERT = TDB_CONVERT;
+%constant int BIGENDIAN = TDB_BIGENDIAN;
+
+enum TDB_ERROR {
+ TDB_SUCCESS=0,
+ TDB_ERR_CORRUPT,
+ TDB_ERR_IO,
+ TDB_ERR_LOCK,
+ TDB_ERR_OOM,
+ TDB_ERR_EXISTS,
+ TDB_ERR_NOLOCK,
+ TDB_ERR_LOCK_TIMEOUT,
+ TDB_ERR_NOEXIST,
+ TDB_ERR_EINVAL,
+ TDB_ERR_RDONLY
+};
+
+%rename(lock_all) tdb_context::lockall;
+%rename(unlock_all) tdb_context::unlockall;
+
+%rename(read_lock_all) tdb_context::lockall_read;
+%rename(read_unlock_all) tdb_context::unlockall_read;
+
+%typemap(default,noblock=1) int tdb_flags {
+ $1 = TDB_DEFAULT;
+}
+
+%typemap(default,noblock=1) int flags {
+ $1 = O_RDWR;
+}
+
+%typemap(default,noblock=1) int hash_size {
+ $1 = 0;
+}
+
+%typemap(default,noblock=1) mode_t mode {
+ $1 = 0600;
+}
+
+%typemap(default,noblock=1) int flag {
+ $1 = TDB_REPLACE;
+}
+
+%rename(Tdb) tdb_context;
+%feature("docstring") tdb_context "A TDB file.";
+%typemap(out,noblock=1) tdb * {
+ /* Throw an IOError exception from errno if tdb_open() returns NULL */
+ if ($1 == NULL) {
+ PyErr_SetFromErrno(PyExc_IOError);
+ SWIG_fail;
+ }
+ $result = SWIG_NewPointerObj($1, $1_descriptor, 0);
+}
+
+typedef struct tdb_context {
+ %extend {
+ %feature("docstring") tdb "S.__init__(name,hash_size=0,tdb_flags=TDB_DEFAULT,flags=O_RDWR,mode=0600)\n"
+ "Open a TDB file.";
+ tdb(const char *name, int hash_size, int tdb_flags, int flags, mode_t mode) {
+ return tdb_open(name, hash_size, tdb_flags, flags, mode);
+ }
+ %feature("docstring") error "S.error() -> int\n"
+ "Find last error number returned by operation on this TDB.";
+ enum TDB_ERROR error();
+ ~tdb() { tdb_close($self); }
+ %feature("docstring") close "S.close() -> None\n"
+ "Close the TDB file.";
+ int close();
+ int append(TDB_DATA key, TDB_DATA new_dbuf);
+ %feature("docstring") errorstr "S.errorstr() -> errorstring\n"
+ "Obtain last error message.";
+ const char *errorstr();
+ %rename(get) fetch;
+ %feature("docstring") fetch "S.fetch(key) -> value\n"
+ "Fetch a value.";
+ TDB_DATA fetch(TDB_DATA key);
+ %feature("docstring") delete "S.delete(key) -> None\n"
+ "Delete an entry.";
+ int delete(TDB_DATA key);
+ %feature("docstring") store "S.store(key, value, flag=TDB_REPLACE) -> None\n"
+ "Store an entry.";
+ int store(TDB_DATA key, TDB_DATA dbuf, int flag);
+ %feature("docstring") exists "S.exists(key) -> bool\n"
+ "Check whether key exists in this database.";
+ int exists(TDB_DATA key);
+ %feature("docstring") firstkey "S.firstkey() -> data\n"
+ "Return the first key in this database.";
+ TDB_DATA firstkey();
+ %feature("docstring") nextkey "S.nextkey(prev) -> data\n"
+ "Return the next key in this database.";
+ TDB_DATA nextkey(TDB_DATA key);
+ %feature("docstring") lockall "S.lockall() -> bool";
+ int lockall();
+ %feature("docstring") unlockall "S.unlockall() -> bool";
+ int unlockall();
+ %feature("docstring") unlockall "S.lockall_read() -> bool";
+ int lockall_read();
+ %feature("docstring") unlockall "S.unlockall_read() -> bool";
+ int unlockall_read();
+ %feature("docstring") reopen "S.reopen() -> bool\n"
+ "Reopen this file.";
+ int reopen();
+ %feature("docstring") transaction_start "S.transaction_start() -> None\n"
+ "Start a new transaction.";
+ int transaction_start();
+ %feature("docstring") transaction_commit "S.transaction_commit() -> None\n"
+ "Commit the currently active transaction.";
+ int transaction_commit();
+ %feature("docstring") transaction_cancel "S.transaction_cancel() -> None\n"
+ "Cancel the currently active transaction.";
+ int transaction_cancel();
+ int transaction_recover();
+ %feature("docstring") hash_size "S.hash_size() -> int";
+ int hash_size();
+ %feature("docstring") map_size "S.map_size() -> int";
+ size_t map_size();
+ %feature("docstring") get_flags "S.get_flags() -> int";
+ int get_flags();
+ %feature("docstring") set_max_dead "S.set_max_dead(int) -> None";
+ void set_max_dead(int max_dead);
+ %feature("docstring") name "S.name() -> path\n" \
+ "Return filename of this TDB file.";
+ const char *name();
+ }
+
+ %pythoncode {
+ def __repr__(self):
+ return "Tdb('%s')" % self.name()
+
+ # Random access to keys, values
+ def __getitem__(self, key):
+ result = self.get(key)
+ if result is None:
+ raise KeyError, '%s: %s' % (key, self.errorstr())
+ return result
+
+ def __setitem__(self, key, item):
+ if self.store(key, item) == -1:
+ raise IOError, self.errorstr()
+
+ def __delitem__(self, key):
+ if not self.exists(key):
+ raise KeyError, '%s: %s' % (key, self.errorstr())
+ self.delete(key)
+
+ def __contains__(self, key):
+ return self.exists(key) != 0
+
+ def has_key(self, key):
+ return self.exists(key) != 0
+
+ def fetch_uint32(self, key):
+ data = self.get(key)
+ if data is None:
+ return None
+ import struct
+ return struct.unpack("<L", data)[0]
+
+ def fetch_int32(self, key):
+ data = self.get(key)
+ if data is None:
+ return None
+ import struct
+ return struct.unpack("<l", data)[0]
+
+ # Tdb iterator
+ class TdbIterator:
+ def __init__(self, tdb):
+ self.tdb = tdb
+ self.key = None
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ if self.key is None:
+ self.key = self.tdb.firstkey()
+ if self.key is None:
+ raise StopIteration
+ return self.key
+ else:
+ self.key = self.tdb.nextkey(self.key)
+ if self.key is None:
+ raise StopIteration
+ return self.key
+
+ def __iter__(self):
+ return self.TdbIterator(self)
+
+ # Implement other dict functions using TdbIterator
+
+ def keys(self):
+ return [k for k in iter(self)]
+
+ def values(self):
+ return [self[k] for k in iter(self)]
+
+ def items(self):
+ return [(k, self[k]) for k in iter(self)]
+
+ def __len__(self):
+ return len(self.keys())
+
+ def clear(self):
+ for k in iter(self):
+ del(self[k])
+
+ def iterkeys(self):
+ for k in iter(self):
+ yield k
+
+ def itervalues(self):
+ for k in iter(self):
+ yield self[k]
+
+ def iteritems(self):
+ for k in iter(self):
+ yield (k, self[k])
+
+ # TODO: any other missing methods for container types
+ }
+} tdb;
diff --git a/source3/lib/tdb/tdb.mk b/source3/lib/tdb/tdb.mk
new file mode 100644
index 0000000000..fa8db6d34c
--- /dev/null
+++ b/source3/lib/tdb/tdb.mk
@@ -0,0 +1,86 @@
+dirs::
+ @mkdir -p bin common tools
+
+PROGS = bin/tdbtool$(EXEEXT) bin/tdbdump$(EXEEXT) bin/tdbbackup$(EXEEXT)
+PROGS_NOINSTALL = bin/tdbtest$(EXEEXT) bin/tdbtorture$(EXEEXT)
+ALL_PROGS = $(PROGS) $(PROGS_NOINSTALL)
+
+TDB_SONAME = libtdb.$(SHLIBEXT).1
+TDB_SOLIB = libtdb.$(SHLIBEXT).$(PACKAGE_VERSION)
+
+TDB_LIB = libtdb.a
+
+bin/tdbtest$(EXEEXT): tools/tdbtest.o $(TDB_LIB)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o bin/tdbtest tools/tdbtest.o -L. -ltdb -lgdbm
+
+bin/tdbtool$(EXEEXT): tools/tdbtool.o $(TDB_LIB)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o bin/tdbtool tools/tdbtool.o -L. -ltdb
+
+bin/tdbtorture$(EXEEXT): tools/tdbtorture.o $(TDB_LIB)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o bin/tdbtorture tools/tdbtorture.o -L. -ltdb
+
+bin/tdbdump$(EXEEXT): tools/tdbdump.o $(TDB_LIB)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o bin/tdbdump tools/tdbdump.o -L. -ltdb
+
+bin/tdbbackup$(EXEEXT): tools/tdbbackup.o $(TDB_LIB)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o bin/tdbbackup tools/tdbbackup.o -L. -ltdb
+
+test:: bin/tdbtorture$(EXEEXT) $(TDB_SONAME)
+ $(LIB_PATH_VAR)=. bin/tdbtorture$(EXEEXT)
+
+clean::
+ rm -f test.db test.tdb torture.tdb test.gdbm
+ rm -f $(TDB_SONAME) $(TDB_SOLIB) libtdb.a libtdb.$(SHLIBEXT)
+ rm -f $(ALL_PROGS) tdb.pc
+
+build-python:: _tdb.$(SHLIBEXT)
+
+tdb_wrap.o: $(tdbdir)/tdb_wrap.c
+ $(CC) $(PICFLAG) -c $(tdbdir)/tdb_wrap.c $(CFLAGS) `$(PYTHON_CONFIG) --cflags`
+
+_tdb.$(SHLIBEXT): libtdb.$(SHLIBEXT) tdb_wrap.o
+ $(SHLD) $(SHLD_FLAGS) -o $@ tdb_wrap.o -L. -ltdb `$(PYTHON_CONFIG) --ldflags`
+
+install:: installdirs installbin installheaders installlibs \
+ $(PYTHON_INSTALL_TARGET)
+
+install-python:: build-python
+ mkdir -p $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(0, prefix='$(prefix)')"` \
+ $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"`
+ cp $(tdbdir)/tdb.py $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(0, prefix='$(prefix)')"`
+ cp _tdb.$(SHLIBEXT) $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"`
+
+check-python:: build-python $(TDB_SONAME)
+ $(LIB_PATH_VAR)=. PYTHONPATH=".:$(tdbdir)" $(PYTHON) $(tdbdir)/python/tests/simple.py
+
+install-swig::
+ mkdir -p $(DESTDIR)`$(SWIG) -swiglib`
+ cp tdb.i $(DESTDIR)`$(SWIG) -swiglib`
+
+clean::
+ rm -f _tdb.$(SHLIBEXT)
+
+installdirs::
+ mkdir -p $(DESTDIR)$(bindir)
+ mkdir -p $(DESTDIR)$(includedir)
+ mkdir -p $(DESTDIR)$(libdir)
+ mkdir -p $(DESTDIR)$(libdir)/pkgconfig
+
+installbin:: all installdirs
+ cp $(PROGS) $(DESTDIR)$(bindir)
+
+installheaders:: installdirs
+ cp $(srcdir)/include/tdb.h $(DESTDIR)$(includedir)
+
+installlibs:: all installdirs
+ cp tdb.pc $(DESTDIR)$(libdir)/pkgconfig
+ cp libtdb.a $(TDB_SOLIB) $(DESTDIR)$(libdir)
+
+libtdb.a: $(TDB_OBJ)
+ ar -rv libtdb.a $(TDB_OBJ)
+
+libtdb.$(SHLIBEXT): $(TDB_SOLIB)
+ ln -fs $< $@
+
+$(TDB_SONAME): $(TDB_SOLIB)
+ ln -fs $< $@
diff --git a/source3/lib/tdb/tdb.pc.in b/source3/lib/tdb/tdb.pc.in
new file mode 100644
index 0000000000..6f8f553736
--- /dev/null
+++ b/source3/lib/tdb/tdb.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: tdb
+Description: A trivial database
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -ltdb
+Cflags: -I${includedir}
+URL: http://tdb.samba.org/
diff --git a/source3/lib/tdb/tdb.py b/source3/lib/tdb/tdb.py
new file mode 100644
index 0000000000..9f306bab8c
--- /dev/null
+++ b/source3/lib/tdb/tdb.py
@@ -0,0 +1,341 @@
+# This file was automatically generated by SWIG (http://www.swig.org).
+# Version 1.3.35
+#
+# Don't modify this file, modify the SWIG interface instead.
+
+"""
+TDB is a simple key-value database similar to GDBM that supports multiple writers.
+"""
+
+import _tdb
+import new
+new_instancemethod = new.instancemethod
+try:
+ _swig_property = property
+except NameError:
+ pass # Python < 2.2 doesn't have 'property'.
+def _swig_setattr_nondynamic(self,class_type,name,value,static=1):
+ if (name == "thisown"): return self.this.own(value)
+ if (name == "this"):
+ if type(value).__name__ == 'PySwigObject':
+ self.__dict__[name] = value
+ return
+ method = class_type.__swig_setmethods__.get(name,None)
+ if method: return method(self,value)
+ if (not static) or hasattr(self,name):
+ self.__dict__[name] = value
+ else:
+ raise AttributeError("You cannot add attributes to %s" % self)
+
+def _swig_setattr(self,class_type,name,value):
+ return _swig_setattr_nondynamic(self,class_type,name,value,0)
+
+def _swig_getattr(self,class_type,name):
+ if (name == "thisown"): return self.this.own()
+ method = class_type.__swig_getmethods__.get(name,None)
+ if method: return method(self)
+ raise AttributeError,name
+
+def _swig_repr(self):
+ try: strthis = "proxy of " + self.this.__repr__()
+ except: strthis = ""
+ return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)
+
+import types
+try:
+ _object = types.ObjectType
+ _newclass = 1
+except AttributeError:
+ class _object : pass
+ _newclass = 0
+del types
+
+
+def _swig_setattr_nondynamic_method(set):
+ def set_attr(self,name,value):
+ if (name == "thisown"): return self.this.own(value)
+ if hasattr(self,name) or (name == "this"):
+ set(self,name,value)
+ else:
+ raise AttributeError("You cannot add attributes to %s" % self)
+ return set_attr
+
+
+REPLACE = _tdb.REPLACE
+INSERT = _tdb.INSERT
+MODIFY = _tdb.MODIFY
+DEFAULT = _tdb.DEFAULT
+CLEAR_IF_FIRST = _tdb.CLEAR_IF_FIRST
+INTERNAL = _tdb.INTERNAL
+NOLOCK = _tdb.NOLOCK
+NOMMAP = _tdb.NOMMAP
+CONVERT = _tdb.CONVERT
+BIGENDIAN = _tdb.BIGENDIAN
+TDB_SUCCESS = _tdb.TDB_SUCCESS
+TDB_ERR_CORRUPT = _tdb.TDB_ERR_CORRUPT
+TDB_ERR_IO = _tdb.TDB_ERR_IO
+TDB_ERR_LOCK = _tdb.TDB_ERR_LOCK
+TDB_ERR_OOM = _tdb.TDB_ERR_OOM
+TDB_ERR_EXISTS = _tdb.TDB_ERR_EXISTS
+TDB_ERR_NOLOCK = _tdb.TDB_ERR_NOLOCK
+TDB_ERR_LOCK_TIMEOUT = _tdb.TDB_ERR_LOCK_TIMEOUT
+TDB_ERR_NOEXIST = _tdb.TDB_ERR_NOEXIST
+TDB_ERR_EINVAL = _tdb.TDB_ERR_EINVAL
+TDB_ERR_RDONLY = _tdb.TDB_ERR_RDONLY
+class Tdb(object):
+ """A TDB file."""
+ thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag')
+ __repr__ = _swig_repr
+ def __init__(self, *args, **kwargs):
+ """
+ S.__init__(name,hash_size=0,tdb_flags=TDB_DEFAULT,flags=O_RDWR,mode=0600)
+ Open a TDB file.
+ """
+ _tdb.Tdb_swiginit(self,_tdb.new_Tdb(*args, **kwargs))
+ def error(*args, **kwargs):
+ """
+ S.error() -> int
+ Find last error number returned by operation on this TDB.
+ """
+ return _tdb.Tdb_error(*args, **kwargs)
+
+ __swig_destroy__ = _tdb.delete_Tdb
+ def close(*args, **kwargs):
+ """
+ S.close() -> None
+ Close the TDB file.
+ """
+ return _tdb.Tdb_close(*args, **kwargs)
+
+ def errorstr(*args, **kwargs):
+ """
+ S.errorstr() -> errorstring
+ Obtain last error message.
+ """
+ return _tdb.Tdb_errorstr(*args, **kwargs)
+
+ def get(*args, **kwargs):
+ """
+ S.fetch(key) -> value
+ Fetch a value.
+ """
+ return _tdb.Tdb_get(*args, **kwargs)
+
+ def delete(*args, **kwargs):
+ """
+ S.delete(key) -> None
+ Delete an entry.
+ """
+ return _tdb.Tdb_delete(*args, **kwargs)
+
+ def store(*args, **kwargs):
+ """
+ S.store(key, value, flag=TDB_REPLACE) -> None
+ Store an entry.
+ """
+ return _tdb.Tdb_store(*args, **kwargs)
+
+ def exists(*args, **kwargs):
+ """
+ S.exists(key) -> bool
+ Check whether key exists in this database.
+ """
+ return _tdb.Tdb_exists(*args, **kwargs)
+
+ def firstkey(*args, **kwargs):
+ """
+ S.firstkey() -> data
+ Return the first key in this database.
+ """
+ return _tdb.Tdb_firstkey(*args, **kwargs)
+
+ def nextkey(*args, **kwargs):
+ """
+ S.nextkey(prev) -> data
+ Return the next key in this database.
+ """
+ return _tdb.Tdb_nextkey(*args, **kwargs)
+
+ def lock_all(*args, **kwargs):
+ """S.lockall() -> bool"""
+ return _tdb.Tdb_lock_all(*args, **kwargs)
+
+ def unlock_all(*args, **kwargs):
+ """S.unlockall() -> bool"""
+ return _tdb.Tdb_unlock_all(*args, **kwargs)
+
+ def reopen(*args, **kwargs):
+ """
+ S.reopen() -> bool
+ Reopen this file.
+ """
+ return _tdb.Tdb_reopen(*args, **kwargs)
+
+ def transaction_start(*args, **kwargs):
+ """
+ S.transaction_start() -> None
+ Start a new transaction.
+ """
+ return _tdb.Tdb_transaction_start(*args, **kwargs)
+
+ def transaction_commit(*args, **kwargs):
+ """
+ S.transaction_commit() -> None
+ Commit the currently active transaction.
+ """
+ return _tdb.Tdb_transaction_commit(*args, **kwargs)
+
+ def transaction_cancel(*args, **kwargs):
+ """
+ S.transaction_cancel() -> None
+ Cancel the currently active transaction.
+ """
+ return _tdb.Tdb_transaction_cancel(*args, **kwargs)
+
+ def hash_size(*args, **kwargs):
+ """S.hash_size() -> int"""
+ return _tdb.Tdb_hash_size(*args, **kwargs)
+
+ def map_size(*args, **kwargs):
+ """S.map_size() -> int"""
+ return _tdb.Tdb_map_size(*args, **kwargs)
+
+ def get_flags(*args, **kwargs):
+ """S.get_flags() -> int"""
+ return _tdb.Tdb_get_flags(*args, **kwargs)
+
+ def set_max_dead(*args, **kwargs):
+ """S.set_max_dead(int) -> None"""
+ return _tdb.Tdb_set_max_dead(*args, **kwargs)
+
+ def name(*args, **kwargs):
+ """
+ S.name() -> path
+ Return filename of this TDB file.
+ """
+ return _tdb.Tdb_name(*args, **kwargs)
+
+ def __repr__(self):
+ return "Tdb('%s')" % self.name()
+
+
+ def __getitem__(self, key):
+ result = self.get(key)
+ if result is None:
+ raise KeyError, '%s: %s' % (key, self.errorstr())
+ return result
+
+ def __setitem__(self, key, item):
+ if self.store(key, item) == -1:
+ raise IOError, self.errorstr()
+
+ def __delitem__(self, key):
+ if not self.exists(key):
+ raise KeyError, '%s: %s' % (key, self.errorstr())
+ self.delete(key)
+
+ def __contains__(self, key):
+ return self.exists(key) != 0
+
+ def has_key(self, key):
+ return self.exists(key) != 0
+
+ def fetch_uint32(self, key):
+ data = self.get(key)
+ if data is None:
+ return None
+ import struct
+ return struct.unpack("<L", data)[0]
+
+ def fetch_int32(self, key):
+ data = self.get(key)
+ if data is None:
+ return None
+ import struct
+ return struct.unpack("<l", data)[0]
+
+
+ class TdbIterator:
+ def __init__(self, tdb):
+ self.tdb = tdb
+ self.key = None
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ if self.key is None:
+ self.key = self.tdb.firstkey()
+ if self.key is None:
+ raise StopIteration
+ return self.key
+ else:
+ self.key = self.tdb.nextkey(self.key)
+ if self.key is None:
+ raise StopIteration
+ return self.key
+
+ def __iter__(self):
+ return self.TdbIterator(self)
+
+
+
+ def keys(self):
+ return [k for k in iter(self)]
+
+ def values(self):
+ return [self[k] for k in iter(self)]
+
+ def items(self):
+ return [(k, self[k]) for k in iter(self)]
+
+ def __len__(self):
+ return len(self.keys())
+
+ def clear(self):
+ for k in iter(self):
+ del(self[k])
+
+ def iterkeys(self):
+ for k in iter(self):
+ yield k
+
+ def itervalues(self):
+ for k in iter(self):
+ yield self[k]
+
+ def iteritems(self):
+ for k in iter(self):
+ yield (k, self[k])
+
+
+
+Tdb.error = new_instancemethod(_tdb.Tdb_error,None,Tdb)
+Tdb.close = new_instancemethod(_tdb.Tdb_close,None,Tdb)
+Tdb.append = new_instancemethod(_tdb.Tdb_append,None,Tdb)
+Tdb.errorstr = new_instancemethod(_tdb.Tdb_errorstr,None,Tdb)
+Tdb.get = new_instancemethod(_tdb.Tdb_get,None,Tdb)
+Tdb.delete = new_instancemethod(_tdb.Tdb_delete,None,Tdb)
+Tdb.store = new_instancemethod(_tdb.Tdb_store,None,Tdb)
+Tdb.exists = new_instancemethod(_tdb.Tdb_exists,None,Tdb)
+Tdb.firstkey = new_instancemethod(_tdb.Tdb_firstkey,None,Tdb)
+Tdb.nextkey = new_instancemethod(_tdb.Tdb_nextkey,None,Tdb)
+Tdb.lock_all = new_instancemethod(_tdb.Tdb_lock_all,None,Tdb)
+Tdb.unlock_all = new_instancemethod(_tdb.Tdb_unlock_all,None,Tdb)
+Tdb.read_lock_all = new_instancemethod(_tdb.Tdb_read_lock_all,None,Tdb)
+Tdb.read_unlock_all = new_instancemethod(_tdb.Tdb_read_unlock_all,None,Tdb)
+Tdb.reopen = new_instancemethod(_tdb.Tdb_reopen,None,Tdb)
+Tdb.transaction_start = new_instancemethod(_tdb.Tdb_transaction_start,None,Tdb)
+Tdb.transaction_commit = new_instancemethod(_tdb.Tdb_transaction_commit,None,Tdb)
+Tdb.transaction_cancel = new_instancemethod(_tdb.Tdb_transaction_cancel,None,Tdb)
+Tdb.transaction_recover = new_instancemethod(_tdb.Tdb_transaction_recover,None,Tdb)
+Tdb.hash_size = new_instancemethod(_tdb.Tdb_hash_size,None,Tdb)
+Tdb.map_size = new_instancemethod(_tdb.Tdb_map_size,None,Tdb)
+Tdb.get_flags = new_instancemethod(_tdb.Tdb_get_flags,None,Tdb)
+Tdb.set_max_dead = new_instancemethod(_tdb.Tdb_set_max_dead,None,Tdb)
+Tdb.name = new_instancemethod(_tdb.Tdb_name,None,Tdb)
+Tdb_swigregister = _tdb.Tdb_swigregister
+Tdb_swigregister(Tdb)
+
+
+
diff --git a/source3/lib/tdb/tdb_wrap.c b/source3/lib/tdb/tdb_wrap.c
new file mode 100644
index 0000000000..32665d79fd
--- /dev/null
+++ b/source3/lib/tdb/tdb_wrap.c
@@ -0,0 +1,4307 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 1.3.35
+ *
+ * This file is not intended to be easily readable and contains a number of
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG
+ * interface file instead.
+ * ----------------------------------------------------------------------------- */
+
+#define SWIGPYTHON
+#define SWIG_PYTHON_NO_BUILD_NONE
+/* -----------------------------------------------------------------------------
+ * This section contains generic SWIG labels for method/variable
+ * declarations/attributes, and other compiler dependent labels.
+ * ----------------------------------------------------------------------------- */
+
+/* template workaround for compilers that cannot correctly implement the C++ standard */
+#ifndef SWIGTEMPLATEDISAMBIGUATOR
+# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
+# define SWIGTEMPLATEDISAMBIGUATOR template
+# elif defined(__HP_aCC)
+/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */
+/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */
+# define SWIGTEMPLATEDISAMBIGUATOR template
+# else
+# define SWIGTEMPLATEDISAMBIGUATOR
+# endif
+#endif
+
+/* inline attribute */
+#ifndef SWIGINLINE
+# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
+# define SWIGINLINE inline
+# else
+# define SWIGINLINE
+# endif
+#endif
+
+/* attribute recognised by some compilers to avoid 'unused' warnings */
+#ifndef SWIGUNUSED
+# if defined(__GNUC__)
+# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+# define SWIGUNUSED __attribute__ ((__unused__))
+# else
+# define SWIGUNUSED
+# endif
+# elif defined(__ICC)
+# define SWIGUNUSED __attribute__ ((__unused__))
+# else
+# define SWIGUNUSED
+# endif
+#endif
+
+#ifndef SWIGUNUSEDPARM
+# ifdef __cplusplus
+# define SWIGUNUSEDPARM(p)
+# else
+# define SWIGUNUSEDPARM(p) p SWIGUNUSED
+# endif
+#endif
+
+/* internal SWIG method */
+#ifndef SWIGINTERN
+# define SWIGINTERN static SWIGUNUSED
+#endif
+
+/* internal inline SWIG method */
+#ifndef SWIGINTERNINLINE
+# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
+#endif
+
+/* exporting methods */
+#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+# ifndef GCC_HASCLASSVISIBILITY
+# define GCC_HASCLASSVISIBILITY
+# endif
+#endif
+
+#ifndef SWIGEXPORT
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+# if defined(STATIC_LINKED)
+# define SWIGEXPORT
+# else
+# define SWIGEXPORT __declspec(dllexport)
+# endif
+# else
+# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
+# define SWIGEXPORT __attribute__ ((visibility("default")))
+# else
+# define SWIGEXPORT
+# endif
+# endif
+#endif
+
+/* calling conventions for Windows */
+#ifndef SWIGSTDCALL
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+# define SWIGSTDCALL __stdcall
+# else
+# define SWIGSTDCALL
+# endif
+#endif
+
+/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
+#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+# define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */
+#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE)
+# define _SCL_SECURE_NO_DEPRECATE
+#endif
+
+
+
+/* Python.h has to appear first */
+#include <Python.h>
+
+/* -----------------------------------------------------------------------------
+ * swigrun.swg
+ *
+ * This file contains generic CAPI SWIG runtime support for pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+/* This should only be incremented when either the layout of swig_type_info changes,
+ or for whatever reason, the runtime changes incompatibly */
+#define SWIG_RUNTIME_VERSION "4"
+
+/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */
+#ifdef SWIG_TYPE_TABLE
+# define SWIG_QUOTE_STRING(x) #x
+# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x)
+# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE)
+#else
+# define SWIG_TYPE_TABLE_NAME
+#endif
+
+/*
+ You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for
+ creating a static or dynamic library from the swig runtime code.
+ In 99.9% of the cases, swig just needs to declare them as 'static'.
+
+ But only do this if is strictly necessary, ie, if you have problems
+ with your compiler or so.
+*/
+
+#ifndef SWIGRUNTIME
+# define SWIGRUNTIME SWIGINTERN
+#endif
+
+#ifndef SWIGRUNTIMEINLINE
+# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE
+#endif
+
+/* Generic buffer size */
+#ifndef SWIG_BUFFER_SIZE
+# define SWIG_BUFFER_SIZE 1024
+#endif
+
+/* Flags for pointer conversions */
+#define SWIG_POINTER_DISOWN 0x1
+#define SWIG_CAST_NEW_MEMORY 0x2
+
+/* Flags for new pointer objects */
+#define SWIG_POINTER_OWN 0x1
+
+
+/*
+ Flags/methods for returning states.
+
+ The swig conversion methods, as ConvertPtr, return and integer
+ that tells if the conversion was successful or not. And if not,
+ an error code can be returned (see swigerrors.swg for the codes).
+
+ Use the following macros/flags to set or process the returning
+ states.
+
+ In old swig versions, you usually write code as:
+
+ if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) {
+ // success code
+ } else {
+ //fail code
+ }
+
+ Now you can be more explicit as:
+
+ int res = SWIG_ConvertPtr(obj,vptr,ty.flags);
+ if (SWIG_IsOK(res)) {
+ // success code
+ } else {
+ // fail code
+ }
+
+ that seems to be the same, but now you can also do
+
+ Type *ptr;
+ int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags);
+ if (SWIG_IsOK(res)) {
+ // success code
+ if (SWIG_IsNewObj(res) {
+ ...
+ delete *ptr;
+ } else {
+ ...
+ }
+ } else {
+ // fail code
+ }
+
+ I.e., now SWIG_ConvertPtr can return new objects and you can
+ identify the case and take care of the deallocation. Of course that
+ requires also to SWIG_ConvertPtr to return new result values, as
+
+ int SWIG_ConvertPtr(obj, ptr,...) {
+ if (<obj is ok>) {
+ if (<need new object>) {
+ *ptr = <ptr to new allocated object>;
+ return SWIG_NEWOBJ;
+ } else {
+ *ptr = <ptr to old object>;
+ return SWIG_OLDOBJ;
+ }
+ } else {
+ return SWIG_BADOBJ;
+ }
+ }
+
+ Of course, returning the plain '0(success)/-1(fail)' still works, but you can be
+ more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the
+ swig errors code.
+
+ Finally, if the SWIG_CASTRANK_MODE is enabled, the result code
+ allows to return the 'cast rank', for example, if you have this
+
+ int food(double)
+ int fooi(int);
+
+ and you call
+
+ food(1) // cast rank '1' (1 -> 1.0)
+ fooi(1) // cast rank '0'
+
+ just use the SWIG_AddCast()/SWIG_CheckState()
+
+
+ */
+#define SWIG_OK (0)
+#define SWIG_ERROR (-1)
+#define SWIG_IsOK(r) (r >= 0)
+#define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError)
+
+/* The CastRankLimit says how many bits are used for the cast rank */
+#define SWIG_CASTRANKLIMIT (1 << 8)
+/* The NewMask denotes the object was created (using new/malloc) */
+#define SWIG_NEWOBJMASK (SWIG_CASTRANKLIMIT << 1)
+/* The TmpMask is for in/out typemaps that use temporal objects */
+#define SWIG_TMPOBJMASK (SWIG_NEWOBJMASK << 1)
+/* Simple returning values */
+#define SWIG_BADOBJ (SWIG_ERROR)
+#define SWIG_OLDOBJ (SWIG_OK)
+#define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK)
+#define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK)
+/* Check, add and del mask methods */
+#define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r)
+#define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r)
+#define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK))
+#define SWIG_AddTmpMask(r) (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r)
+#define SWIG_DelTmpMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r)
+#define SWIG_IsTmpObj(r) (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK))
+
+
+/* Cast-Rank Mode */
+#if defined(SWIG_CASTRANK_MODE)
+# ifndef SWIG_TypeRank
+# define SWIG_TypeRank unsigned long
+# endif
+# ifndef SWIG_MAXCASTRANK /* Default cast allowed */
+# define SWIG_MAXCASTRANK (2)
+# endif
+# define SWIG_CASTRANKMASK ((SWIG_CASTRANKLIMIT) -1)
+# define SWIG_CastRank(r) (r & SWIG_CASTRANKMASK)
+SWIGINTERNINLINE int SWIG_AddCast(int r) {
+ return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r;
+}
+SWIGINTERNINLINE int SWIG_CheckState(int r) {
+ return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0;
+}
+#else /* no cast-rank mode */
+# define SWIG_AddCast
+# define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0)
+#endif
+
+
+
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *(*swig_converter_func)(void *, int *);
+typedef struct swig_type_info *(*swig_dycast_func)(void **);
+
+/* Structure to store information on one type */
+typedef struct swig_type_info {
+ const char *name; /* mangled name of this type */
+ const char *str; /* human readable name of this type */
+ swig_dycast_func dcast; /* dynamic cast function down a hierarchy */
+ struct swig_cast_info *cast; /* linked list of types that can cast into this type */
+ void *clientdata; /* language specific type data */
+ int owndata; /* flag if the structure owns the clientdata */
+} swig_type_info;
+
+/* Structure to store a type and conversion function used for casting */
+typedef struct swig_cast_info {
+ swig_type_info *type; /* pointer to type that is equivalent to this type */
+ swig_converter_func converter; /* function to cast the void pointers */
+ struct swig_cast_info *next; /* pointer to next cast in linked list */
+ struct swig_cast_info *prev; /* pointer to the previous cast */
+} swig_cast_info;
+
+/* Structure used to store module information
+ * Each module generates one structure like this, and the runtime collects
+ * all of these structures and stores them in a circularly linked list.*/
+typedef struct swig_module_info {
+ swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */
+ size_t size; /* Number of types in this module */
+ struct swig_module_info *next; /* Pointer to next element in circularly linked list */
+ swig_type_info **type_initial; /* Array of initially generated type structures */
+ swig_cast_info **cast_initial; /* Array of initially generated casting structures */
+ void *clientdata; /* Language specific module data */
+} swig_module_info;
+
+/*
+ Compare two type names skipping the space characters, therefore
+ "char*" == "char *" and "Class<int>" == "Class<int >", etc.
+
+ Return 0 when the two name types are equivalent, as in
+ strncmp, but skipping ' '.
+*/
+SWIGRUNTIME int
+SWIG_TypeNameComp(const char *f1, const char *l1,
+ const char *f2, const char *l2) {
+ for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) {
+ while ((*f1 == ' ') && (f1 != l1)) ++f1;
+ while ((*f2 == ' ') && (f2 != l2)) ++f2;
+ if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1;
+ }
+ return (int)((l1 - f1) - (l2 - f2));
+}
+
+/*
+ Check type equivalence in a name list like <name1>|<name2>|...
+ Return 0 if not equal, 1 if equal
+*/
+SWIGRUNTIME int
+SWIG_TypeEquiv(const char *nb, const char *tb) {
+ int equiv = 0;
+ const char* te = tb + strlen(tb);
+ const char* ne = nb;
+ while (!equiv && *ne) {
+ for (nb = ne; *ne; ++ne) {
+ if (*ne == '|') break;
+ }
+ equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+ if (*ne) ++ne;
+ }
+ return equiv;
+}
+
+/*
+ Check type equivalence in a name list like <name1>|<name2>|...
+ Return 0 if equal, -1 if nb < tb, 1 if nb > tb
+*/
+SWIGRUNTIME int
+SWIG_TypeCompare(const char *nb, const char *tb) {
+ int equiv = 0;
+ const char* te = tb + strlen(tb);
+ const char* ne = nb;
+ while (!equiv && *ne) {
+ for (nb = ne; *ne; ++ne) {
+ if (*ne == '|') break;
+ }
+ equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+ if (*ne) ++ne;
+ }
+ return equiv;
+}
+
+
+/* think of this as a c++ template<> or a scheme macro */
+#define SWIG_TypeCheck_Template(comparison, ty) \
+ if (ty) { \
+ swig_cast_info *iter = ty->cast; \
+ while (iter) { \
+ if (comparison) { \
+ if (iter == ty->cast) return iter; \
+ /* Move iter to the top of the linked list */ \
+ iter->prev->next = iter->next; \
+ if (iter->next) \
+ iter->next->prev = iter->prev; \
+ iter->next = ty->cast; \
+ iter->prev = 0; \
+ if (ty->cast) ty->cast->prev = iter; \
+ ty->cast = iter; \
+ return iter; \
+ } \
+ iter = iter->next; \
+ } \
+ } \
+ return 0
+
+/*
+ Check the typename
+*/
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheck(const char *c, swig_type_info *ty) {
+ SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty);
+}
+
+/* Same as previous function, except strcmp is replaced with a pointer comparison */
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) {
+ SWIG_TypeCheck_Template(iter->type == from, into);
+}
+
+/*
+ Cast a pointer up an inheritance hierarchy
+*/
+SWIGRUNTIMEINLINE void *
+SWIG_TypeCast(swig_cast_info *ty, void *ptr, int *newmemory) {
+ return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr, newmemory);
+}
+
+/*
+ Dynamic pointer casting. Down an inheritance hierarchy
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) {
+ swig_type_info *lastty = ty;
+ if (!ty || !ty->dcast) return ty;
+ while (ty && (ty->dcast)) {
+ ty = (*ty->dcast)(ptr);
+ if (ty) lastty = ty;
+ }
+ return lastty;
+}
+
+/*
+ Return the name associated with this type
+*/
+SWIGRUNTIMEINLINE const char *
+SWIG_TypeName(const swig_type_info *ty) {
+ return ty->name;
+}
+
+/*
+ Return the pretty name associated with this type,
+ that is an unmangled type name in a form presentable to the user.
+*/
+SWIGRUNTIME const char *
+SWIG_TypePrettyName(const swig_type_info *type) {
+ /* The "str" field contains the equivalent pretty names of the
+ type, separated by vertical-bar characters. We choose
+ to print the last name, as it is often (?) the most
+ specific. */
+ if (!type) return NULL;
+ if (type->str != NULL) {
+ const char *last_name = type->str;
+ const char *s;
+ for (s = type->str; *s; s++)
+ if (*s == '|') last_name = s+1;
+ return last_name;
+ }
+ else
+ return type->name;
+}
+
+/*
+ Set the clientdata field for a type
+*/
+SWIGRUNTIME void
+SWIG_TypeClientData(swig_type_info *ti, void *clientdata) {
+ swig_cast_info *cast = ti->cast;
+ /* if (ti->clientdata == clientdata) return; */
+ ti->clientdata = clientdata;
+
+ while (cast) {
+ if (!cast->converter) {
+ swig_type_info *tc = cast->type;
+ if (!tc->clientdata) {
+ SWIG_TypeClientData(tc, clientdata);
+ }
+ }
+ cast = cast->next;
+ }
+}
+SWIGRUNTIME void
+SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) {
+ SWIG_TypeClientData(ti, clientdata);
+ ti->owndata = 1;
+}
+
+/*
+ Search for a swig_type_info structure only by mangled name
+ Search is a O(log #types)
+
+ We start searching at module start, and finish searching when start == end.
+ Note: if start == end at the beginning of the function, we go all the way around
+ the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_MangledTypeQueryModule(swig_module_info *start,
+ swig_module_info *end,
+ const char *name) {
+ swig_module_info *iter = start;
+ do {
+ if (iter->size) {
+ register size_t l = 0;
+ register size_t r = iter->size - 1;
+ do {
+ /* since l+r >= 0, we can (>> 1) instead (/ 2) */
+ register size_t i = (l + r) >> 1;
+ const char *iname = iter->types[i]->name;
+ if (iname) {
+ register int compare = strcmp(name, iname);
+ if (compare == 0) {
+ return iter->types[i];
+ } else if (compare < 0) {
+ if (i) {
+ r = i - 1;
+ } else {
+ break;
+ }
+ } else if (compare > 0) {
+ l = i + 1;
+ }
+ } else {
+ break; /* should never happen */
+ }
+ } while (l <= r);
+ }
+ iter = iter->next;
+ } while (iter != end);
+ return 0;
+}
+
+/*
+ Search for a swig_type_info structure for either a mangled name or a human readable name.
+ It first searches the mangled names of the types, which is a O(log #types)
+ If a type is not found it then searches the human readable names, which is O(#types).
+
+ We start searching at module start, and finish searching when start == end.
+ Note: if start == end at the beginning of the function, we go all the way around
+ the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeQueryModule(swig_module_info *start,
+ swig_module_info *end,
+ const char *name) {
+ /* STEP 1: Search the name field using binary search */
+ swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name);
+ if (ret) {
+ return ret;
+ } else {
+ /* STEP 2: If the type hasn't been found, do a complete search
+ of the str field (the human readable name) */
+ swig_module_info *iter = start;
+ do {
+ register size_t i = 0;
+ for (; i < iter->size; ++i) {
+ if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name)))
+ return iter->types[i];
+ }
+ iter = iter->next;
+ } while (iter != end);
+ }
+
+ /* neither found a match */
+ return 0;
+}
+
+/*
+ Pack binary data into a string
+*/
+SWIGRUNTIME char *
+SWIG_PackData(char *c, void *ptr, size_t sz) {
+ static const char hex[17] = "0123456789abcdef";
+ register const unsigned char *u = (unsigned char *) ptr;
+ register const unsigned char *eu = u + sz;
+ for (; u != eu; ++u) {
+ register unsigned char uu = *u;
+ *(c++) = hex[(uu & 0xf0) >> 4];
+ *(c++) = hex[uu & 0xf];
+ }
+ return c;
+}
+
+/*
+ Unpack binary data from a string
+*/
+SWIGRUNTIME const char *
+SWIG_UnpackData(const char *c, void *ptr, size_t sz) {
+ register unsigned char *u = (unsigned char *) ptr;
+ register const unsigned char *eu = u + sz;
+ for (; u != eu; ++u) {
+ register char d = *(c++);
+ register unsigned char uu;
+ if ((d >= '0') && (d <= '9'))
+ uu = ((d - '0') << 4);
+ else if ((d >= 'a') && (d <= 'f'))
+ uu = ((d - ('a'-10)) << 4);
+ else
+ return (char *) 0;
+ d = *(c++);
+ if ((d >= '0') && (d <= '9'))
+ uu |= (d - '0');
+ else if ((d >= 'a') && (d <= 'f'))
+ uu |= (d - ('a'-10));
+ else
+ return (char *) 0;
+ *u = uu;
+ }
+ return c;
+}
+
+/*
+ Pack 'void *' into a string buffer.
+*/
+SWIGRUNTIME char *
+SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) {
+ char *r = buff;
+ if ((2*sizeof(void *) + 2) > bsz) return 0;
+ *(r++) = '_';
+ r = SWIG_PackData(r,&ptr,sizeof(void *));
+ if (strlen(name) + 1 > (bsz - (r - buff))) return 0;
+ strcpy(r,name);
+ return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) {
+ if (*c != '_') {
+ if (strcmp(c,"NULL") == 0) {
+ *ptr = (void *) 0;
+ return name;
+ } else {
+ return 0;
+ }
+ }
+ return SWIG_UnpackData(++c,ptr,sizeof(void *));
+}
+
+SWIGRUNTIME char *
+SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) {
+ char *r = buff;
+ size_t lname = (name ? strlen(name) : 0);
+ if ((2*sz + 2 + lname) > bsz) return 0;
+ *(r++) = '_';
+ r = SWIG_PackData(r,ptr,sz);
+ if (lname) {
+ strncpy(r,name,lname+1);
+ } else {
+ *r = 0;
+ }
+ return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) {
+ if (*c != '_') {
+ if (strcmp(c,"NULL") == 0) {
+ memset(ptr,0,sz);
+ return name;
+ } else {
+ return 0;
+ }
+ }
+ return SWIG_UnpackData(++c,ptr,sz);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Errors in SWIG */
+#define SWIG_UnknownError -1
+#define SWIG_IOError -2
+#define SWIG_RuntimeError -3
+#define SWIG_IndexError -4
+#define SWIG_TypeError -5
+#define SWIG_DivisionByZero -6
+#define SWIG_OverflowError -7
+#define SWIG_SyntaxError -8
+#define SWIG_ValueError -9
+#define SWIG_SystemError -10
+#define SWIG_AttributeError -11
+#define SWIG_MemoryError -12
+#define SWIG_NullReferenceError -13
+
+
+
+
+/* Add PyOS_snprintf for old Pythons */
+#if PY_VERSION_HEX < 0x02020000
+# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM)
+# define PyOS_snprintf _snprintf
+# else
+# define PyOS_snprintf snprintf
+# endif
+#endif
+
+/* A crude PyString_FromFormat implementation for old Pythons */
+#if PY_VERSION_HEX < 0x02020000
+
+#ifndef SWIG_PYBUFFER_SIZE
+# define SWIG_PYBUFFER_SIZE 1024
+#endif
+
+static PyObject *
+PyString_FromFormat(const char *fmt, ...) {
+ va_list ap;
+ char buf[SWIG_PYBUFFER_SIZE * 2];
+ int res;
+ va_start(ap, fmt);
+ res = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ return (res < 0 || res >= (int)sizeof(buf)) ? 0 : PyString_FromString(buf);
+}
+#endif
+
+/* Add PyObject_Del for old Pythons */
+#if PY_VERSION_HEX < 0x01060000
+# define PyObject_Del(op) PyMem_DEL((op))
+#endif
+#ifndef PyObject_DEL
+# define PyObject_DEL PyObject_Del
+#endif
+
+/* A crude PyExc_StopIteration exception for old Pythons */
+#if PY_VERSION_HEX < 0x02020000
+# ifndef PyExc_StopIteration
+# define PyExc_StopIteration PyExc_RuntimeError
+# endif
+# ifndef PyObject_GenericGetAttr
+# define PyObject_GenericGetAttr 0
+# endif
+#endif
+/* Py_NotImplemented is defined in 2.1 and up. */
+#if PY_VERSION_HEX < 0x02010000
+# ifndef Py_NotImplemented
+# define Py_NotImplemented PyExc_RuntimeError
+# endif
+#endif
+
+
+/* A crude PyString_AsStringAndSize implementation for old Pythons */
+#if PY_VERSION_HEX < 0x02010000
+# ifndef PyString_AsStringAndSize
+# define PyString_AsStringAndSize(obj, s, len) {*s = PyString_AsString(obj); *len = *s ? strlen(*s) : 0;}
+# endif
+#endif
+
+/* PySequence_Size for old Pythons */
+#if PY_VERSION_HEX < 0x02000000
+# ifndef PySequence_Size
+# define PySequence_Size PySequence_Length
+# endif
+#endif
+
+
+/* PyBool_FromLong for old Pythons */
+#if PY_VERSION_HEX < 0x02030000
+static
+PyObject *PyBool_FromLong(long ok)
+{
+ PyObject *result = ok ? Py_True : Py_False;
+ Py_INCREF(result);
+ return result;
+}
+#endif
+
+/* Py_ssize_t for old Pythons */
+/* This code is as recommended by: */
+/* http://www.python.org/dev/peps/pep-0353/#conversion-guidelines */
+#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
+typedef int Py_ssize_t;
+# define PY_SSIZE_T_MAX INT_MAX
+# define PY_SSIZE_T_MIN INT_MIN
+#endif
+
+/* -----------------------------------------------------------------------------
+ * error manipulation
+ * ----------------------------------------------------------------------------- */
+
+SWIGRUNTIME PyObject*
+SWIG_Python_ErrorType(int code) {
+ PyObject* type = 0;
+ switch(code) {
+ case SWIG_MemoryError:
+ type = PyExc_MemoryError;
+ break;
+ case SWIG_IOError:
+ type = PyExc_IOError;
+ break;
+ case SWIG_RuntimeError:
+ type = PyExc_RuntimeError;
+ break;
+ case SWIG_IndexError:
+ type = PyExc_IndexError;
+ break;
+ case SWIG_TypeError:
+ type = PyExc_TypeError;
+ break;
+ case SWIG_DivisionByZero:
+ type = PyExc_ZeroDivisionError;
+ break;
+ case SWIG_OverflowError:
+ type = PyExc_OverflowError;
+ break;
+ case SWIG_SyntaxError:
+ type = PyExc_SyntaxError;
+ break;
+ case SWIG_ValueError:
+ type = PyExc_ValueError;
+ break;
+ case SWIG_SystemError:
+ type = PyExc_SystemError;
+ break;
+ case SWIG_AttributeError:
+ type = PyExc_AttributeError;
+ break;
+ default:
+ type = PyExc_RuntimeError;
+ }
+ return type;
+}
+
+
+SWIGRUNTIME void
+SWIG_Python_AddErrorMsg(const char* mesg)
+{
+ PyObject *type = 0;
+ PyObject *value = 0;
+ PyObject *traceback = 0;
+
+ if (PyErr_Occurred()) PyErr_Fetch(&type, &value, &traceback);
+ if (value) {
+ PyObject *old_str = PyObject_Str(value);
+ PyErr_Clear();
+ Py_XINCREF(type);
+ PyErr_Format(type, "%s %s", PyString_AsString(old_str), mesg);
+ Py_DECREF(old_str);
+ Py_DECREF(value);
+ } else {
+ PyErr_SetString(PyExc_RuntimeError, mesg);
+ }
+}
+
+
+
+#if defined(SWIG_PYTHON_NO_THREADS)
+# if defined(SWIG_PYTHON_THREADS)
+# undef SWIG_PYTHON_THREADS
+# endif
+#endif
+#if defined(SWIG_PYTHON_THREADS) /* Threading support is enabled */
+# if !defined(SWIG_PYTHON_USE_GIL) && !defined(SWIG_PYTHON_NO_USE_GIL)
+# if (PY_VERSION_HEX >= 0x02030000) /* For 2.3 or later, use the PyGILState calls */
+# define SWIG_PYTHON_USE_GIL
+# endif
+# endif
+# if defined(SWIG_PYTHON_USE_GIL) /* Use PyGILState threads calls */
+# ifndef SWIG_PYTHON_INITIALIZE_THREADS
+# define SWIG_PYTHON_INITIALIZE_THREADS PyEval_InitThreads()
+# endif
+# ifdef __cplusplus /* C++ code */
+ class SWIG_Python_Thread_Block {
+ bool status;
+ PyGILState_STATE state;
+ public:
+ void end() { if (status) { PyGILState_Release(state); status = false;} }
+ SWIG_Python_Thread_Block() : status(true), state(PyGILState_Ensure()) {}
+ ~SWIG_Python_Thread_Block() { end(); }
+ };
+ class SWIG_Python_Thread_Allow {
+ bool status;
+ PyThreadState *save;
+ public:
+ void end() { if (status) { PyEval_RestoreThread(save); status = false; }}
+ SWIG_Python_Thread_Allow() : status(true), save(PyEval_SaveThread()) {}
+ ~SWIG_Python_Thread_Allow() { end(); }
+ };
+# define SWIG_PYTHON_THREAD_BEGIN_BLOCK SWIG_Python_Thread_Block _swig_thread_block
+# define SWIG_PYTHON_THREAD_END_BLOCK _swig_thread_block.end()
+# define SWIG_PYTHON_THREAD_BEGIN_ALLOW SWIG_Python_Thread_Allow _swig_thread_allow
+# define SWIG_PYTHON_THREAD_END_ALLOW _swig_thread_allow.end()
+# else /* C code */
+# define SWIG_PYTHON_THREAD_BEGIN_BLOCK PyGILState_STATE _swig_thread_block = PyGILState_Ensure()
+# define SWIG_PYTHON_THREAD_END_BLOCK PyGILState_Release(_swig_thread_block)
+# define SWIG_PYTHON_THREAD_BEGIN_ALLOW PyThreadState *_swig_thread_allow = PyEval_SaveThread()
+# define SWIG_PYTHON_THREAD_END_ALLOW PyEval_RestoreThread(_swig_thread_allow)
+# endif
+# else /* Old thread way, not implemented, user must provide it */
+# if !defined(SWIG_PYTHON_INITIALIZE_THREADS)
+# define SWIG_PYTHON_INITIALIZE_THREADS
+# endif
+# if !defined(SWIG_PYTHON_THREAD_BEGIN_BLOCK)
+# define SWIG_PYTHON_THREAD_BEGIN_BLOCK
+# endif
+# if !defined(SWIG_PYTHON_THREAD_END_BLOCK)
+# define SWIG_PYTHON_THREAD_END_BLOCK
+# endif
+# if !defined(SWIG_PYTHON_THREAD_BEGIN_ALLOW)
+# define SWIG_PYTHON_THREAD_BEGIN_ALLOW
+# endif
+# if !defined(SWIG_PYTHON_THREAD_END_ALLOW)
+# define SWIG_PYTHON_THREAD_END_ALLOW
+# endif
+# endif
+#else /* No thread support */
+# define SWIG_PYTHON_INITIALIZE_THREADS
+# define SWIG_PYTHON_THREAD_BEGIN_BLOCK
+# define SWIG_PYTHON_THREAD_END_BLOCK
+# define SWIG_PYTHON_THREAD_BEGIN_ALLOW
+# define SWIG_PYTHON_THREAD_END_ALLOW
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Python API portion that goes into the runtime
+ * ----------------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} /* cc-mode */
+#endif
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Constant declarations
+ * ----------------------------------------------------------------------------- */
+
+/* Constant Types */
+#define SWIG_PY_POINTER 4
+#define SWIG_PY_BINARY 5
+
+/* Constant information structure */
+typedef struct swig_const_info {
+ int type;
+ char *name;
+ long lvalue;
+ double dvalue;
+ void *pvalue;
+ swig_type_info **ptype;
+} swig_const_info;
+
+#ifdef __cplusplus
+#if 0
+{ /* cc-mode */
+#endif
+}
+#endif
+
+
+/* -----------------------------------------------------------------------------
+ * See the LICENSE file for information on copyright, usage and redistribution
+ * of SWIG, and the README file for authors - http://www.swig.org/release.html.
+ *
+ * pyrun.swg
+ *
+ * This file contains the runtime support for Python modules
+ * and includes code for managing global variables and pointer
+ * type checking.
+ *
+ * ----------------------------------------------------------------------------- */
+
+/* Common SWIG API */
+
+/* for raw pointers */
+#define SWIG_Python_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, 0)
+#define SWIG_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtr(obj, pptr, type, flags)
+#define SWIG_ConvertPtrAndOwn(obj,pptr,type,flags,own) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, own)
+#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(ptr, type, flags)
+#define SWIG_CheckImplicit(ty) SWIG_Python_CheckImplicit(ty)
+#define SWIG_AcquirePtr(ptr, src) SWIG_Python_AcquirePtr(ptr, src)
+#define swig_owntype int
+
+/* for raw packed data */
+#define SWIG_ConvertPacked(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty)
+#define SWIG_NewPackedObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type)
+
+/* for class or struct pointers */
+#define SWIG_ConvertInstance(obj, pptr, type, flags) SWIG_ConvertPtr(obj, pptr, type, flags)
+#define SWIG_NewInstanceObj(ptr, type, flags) SWIG_NewPointerObj(ptr, type, flags)
+
+/* for C or C++ function pointers */
+#define SWIG_ConvertFunctionPtr(obj, pptr, type) SWIG_Python_ConvertFunctionPtr(obj, pptr, type)
+#define SWIG_NewFunctionPtrObj(ptr, type) SWIG_Python_NewPointerObj(ptr, type, 0)
+
+/* for C++ member pointers, ie, member methods */
+#define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty)
+#define SWIG_NewMemberObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type)
+
+
+/* Runtime API */
+
+#define SWIG_GetModule(clientdata) SWIG_Python_GetModule()
+#define SWIG_SetModule(clientdata, pointer) SWIG_Python_SetModule(pointer)
+#define SWIG_NewClientData(obj) PySwigClientData_New(obj)
+
+#define SWIG_SetErrorObj SWIG_Python_SetErrorObj
+#define SWIG_SetErrorMsg SWIG_Python_SetErrorMsg
+#define SWIG_ErrorType(code) SWIG_Python_ErrorType(code)
+#define SWIG_Error(code, msg) SWIG_Python_SetErrorMsg(SWIG_ErrorType(code), msg)
+#define SWIG_fail goto fail
+
+
+/* Runtime API implementation */
+
+/* Error manipulation */
+
+SWIGINTERN void
+SWIG_Python_SetErrorObj(PyObject *errtype, PyObject *obj) {
+ SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+ PyErr_SetObject(errtype, obj);
+ Py_DECREF(obj);
+ SWIG_PYTHON_THREAD_END_BLOCK;
+}
+
+SWIGINTERN void
+SWIG_Python_SetErrorMsg(PyObject *errtype, const char *msg) {
+ SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+ PyErr_SetString(errtype, (char *) msg);
+ SWIG_PYTHON_THREAD_END_BLOCK;
+}
+
+#define SWIG_Python_Raise(obj, type, desc) SWIG_Python_SetErrorObj(SWIG_Python_ExceptionType(desc), obj)
+
+/* Set a constant value */
+
+SWIGINTERN void
+SWIG_Python_SetConstant(PyObject *d, const char *name, PyObject *obj) {
+ PyDict_SetItemString(d, (char*) name, obj);
+ Py_DECREF(obj);
+}
+
+/* Append a value to the result obj */
+
+SWIGINTERN PyObject*
+SWIG_Python_AppendOutput(PyObject* result, PyObject* obj) {
+#if !defined(SWIG_PYTHON_OUTPUT_TUPLE)
+ if (!result) {
+ result = obj;
+ } else if (result == Py_None) {
+ Py_DECREF(result);
+ result = obj;
+ } else {
+ if (!PyList_Check(result)) {
+ PyObject *o2 = result;
+ result = PyList_New(1);
+ PyList_SetItem(result, 0, o2);
+ }
+ PyList_Append(result,obj);
+ Py_DECREF(obj);
+ }
+ return result;
+#else
+ PyObject* o2;
+ PyObject* o3;
+ if (!result) {
+ result = obj;
+ } else if (result == Py_None) {
+ Py_DECREF(result);
+ result = obj;
+ } else {
+ if (!PyTuple_Check(result)) {
+ o2 = result;
+ result = PyTuple_New(1);
+ PyTuple_SET_ITEM(result, 0, o2);
+ }
+ o3 = PyTuple_New(1);
+ PyTuple_SET_ITEM(o3, 0, obj);
+ o2 = result;
+ result = PySequence_Concat(o2, o3);
+ Py_DECREF(o2);
+ Py_DECREF(o3);
+ }
+ return result;
+#endif
+}
+
+/* Unpack the argument tuple */
+
+SWIGINTERN int
+SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, PyObject **objs)
+{
+ if (!args) {
+ if (!min && !max) {
+ return 1;
+ } else {
+ PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got none",
+ name, (min == max ? "" : "at least "), (int)min);
+ return 0;
+ }
+ }
+ if (!PyTuple_Check(args)) {
+ PyErr_SetString(PyExc_SystemError, "UnpackTuple() argument list is not a tuple");
+ return 0;
+ } else {
+ register Py_ssize_t l = PyTuple_GET_SIZE(args);
+ if (l < min) {
+ PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d",
+ name, (min == max ? "" : "at least "), (int)min, (int)l);
+ return 0;
+ } else if (l > max) {
+ PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d",
+ name, (min == max ? "" : "at most "), (int)max, (int)l);
+ return 0;
+ } else {
+ register int i;
+ for (i = 0; i < l; ++i) {
+ objs[i] = PyTuple_GET_ITEM(args, i);
+ }
+ for (; l < max; ++l) {
+ objs[l] = 0;
+ }
+ return i + 1;
+ }
+ }
+}
+
+/* A functor is a function object with one single object argument */
+#if PY_VERSION_HEX >= 0x02020000
+#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunctionObjArgs(functor, obj, NULL);
+#else
+#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunction(functor, "O", obj);
+#endif
+
+/*
+ Helper for static pointer initialization for both C and C++ code, for example
+ static PyObject *SWIG_STATIC_POINTER(MyVar) = NewSomething(...);
+*/
+#ifdef __cplusplus
+#define SWIG_STATIC_POINTER(var) var
+#else
+#define SWIG_STATIC_POINTER(var) var = 0; if (!var) var
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Pointer declarations
+ * ----------------------------------------------------------------------------- */
+
+/* Flags for new pointer objects */
+#define SWIG_POINTER_NOSHADOW (SWIG_POINTER_OWN << 1)
+#define SWIG_POINTER_NEW (SWIG_POINTER_NOSHADOW | SWIG_POINTER_OWN)
+
+#define SWIG_POINTER_IMPLICIT_CONV (SWIG_POINTER_DISOWN << 1)
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} /* cc-mode */
+#endif
+#endif
+
+/* How to access Py_None */
+#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+# ifndef SWIG_PYTHON_NO_BUILD_NONE
+# ifndef SWIG_PYTHON_BUILD_NONE
+# define SWIG_PYTHON_BUILD_NONE
+# endif
+# endif
+#endif
+
+#ifdef SWIG_PYTHON_BUILD_NONE
+# ifdef Py_None
+# undef Py_None
+# define Py_None SWIG_Py_None()
+# endif
+SWIGRUNTIMEINLINE PyObject *
+_SWIG_Py_None(void)
+{
+ PyObject *none = Py_BuildValue((char*)"");
+ Py_DECREF(none);
+ return none;
+}
+SWIGRUNTIME PyObject *
+SWIG_Py_None(void)
+{
+ static PyObject *SWIG_STATIC_POINTER(none) = _SWIG_Py_None();
+ return none;
+}
+#endif
+
+/* The python void return value */
+
+SWIGRUNTIMEINLINE PyObject *
+SWIG_Py_Void(void)
+{
+ PyObject *none = Py_None;
+ Py_INCREF(none);
+ return none;
+}
+
+/* PySwigClientData */
+
+typedef struct {
+ PyObject *klass;
+ PyObject *newraw;
+ PyObject *newargs;
+ PyObject *destroy;
+ int delargs;
+ int implicitconv;
+} PySwigClientData;
+
+SWIGRUNTIMEINLINE int
+SWIG_Python_CheckImplicit(swig_type_info *ty)
+{
+ PySwigClientData *data = (PySwigClientData *)ty->clientdata;
+ return data ? data->implicitconv : 0;
+}
+
+SWIGRUNTIMEINLINE PyObject *
+SWIG_Python_ExceptionType(swig_type_info *desc) {
+ PySwigClientData *data = desc ? (PySwigClientData *) desc->clientdata : 0;
+ PyObject *klass = data ? data->klass : 0;
+ return (klass ? klass : PyExc_RuntimeError);
+}
+
+
+SWIGRUNTIME PySwigClientData *
+PySwigClientData_New(PyObject* obj)
+{
+ if (!obj) {
+ return 0;
+ } else {
+ PySwigClientData *data = (PySwigClientData *)malloc(sizeof(PySwigClientData));
+ /* the klass element */
+ data->klass = obj;
+ Py_INCREF(data->klass);
+ /* the newraw method and newargs arguments used to create a new raw instance */
+ if (PyClass_Check(obj)) {
+ data->newraw = 0;
+ data->newargs = obj;
+ Py_INCREF(obj);
+ } else {
+#if (PY_VERSION_HEX < 0x02020000)
+ data->newraw = 0;
+#else
+ data->newraw = PyObject_GetAttrString(data->klass, (char *)"__new__");
+#endif
+ if (data->newraw) {
+ Py_INCREF(data->newraw);
+ data->newargs = PyTuple_New(1);
+ PyTuple_SetItem(data->newargs, 0, obj);
+ } else {
+ data->newargs = obj;
+ }
+ Py_INCREF(data->newargs);
+ }
+ /* the destroy method, aka as the C++ delete method */
+ data->destroy = PyObject_GetAttrString(data->klass, (char *)"__swig_destroy__");
+ if (PyErr_Occurred()) {
+ PyErr_Clear();
+ data->destroy = 0;
+ }
+ if (data->destroy) {
+ int flags;
+ Py_INCREF(data->destroy);
+ flags = PyCFunction_GET_FLAGS(data->destroy);
+#ifdef METH_O
+ data->delargs = !(flags & (METH_O));
+#else
+ data->delargs = 0;
+#endif
+ } else {
+ data->delargs = 0;
+ }
+ data->implicitconv = 0;
+ return data;
+ }
+}
+
+SWIGRUNTIME void
+PySwigClientData_Del(PySwigClientData* data)
+{
+ Py_XDECREF(data->newraw);
+ Py_XDECREF(data->newargs);
+ Py_XDECREF(data->destroy);
+}
+
+/* =============== PySwigObject =====================*/
+
+typedef struct {
+ PyObject_HEAD
+ void *ptr;
+ swig_type_info *ty;
+ int own;
+ PyObject *next;
+} PySwigObject;
+
+SWIGRUNTIME PyObject *
+PySwigObject_long(PySwigObject *v)
+{
+ return PyLong_FromVoidPtr(v->ptr);
+}
+
+SWIGRUNTIME PyObject *
+PySwigObject_format(const char* fmt, PySwigObject *v)
+{
+ PyObject *res = NULL;
+ PyObject *args = PyTuple_New(1);
+ if (args) {
+ if (PyTuple_SetItem(args, 0, PySwigObject_long(v)) == 0) {
+ PyObject *ofmt = PyString_FromString(fmt);
+ if (ofmt) {
+ res = PyString_Format(ofmt,args);
+ Py_DECREF(ofmt);
+ }
+ Py_DECREF(args);
+ }
+ }
+ return res;
+}
+
+SWIGRUNTIME PyObject *
+PySwigObject_oct(PySwigObject *v)
+{
+ return PySwigObject_format("%o",v);
+}
+
+SWIGRUNTIME PyObject *
+PySwigObject_hex(PySwigObject *v)
+{
+ return PySwigObject_format("%x",v);
+}
+
+SWIGRUNTIME PyObject *
+#ifdef METH_NOARGS
+PySwigObject_repr(PySwigObject *v)
+#else
+PySwigObject_repr(PySwigObject *v, PyObject *args)
+#endif
+{
+ const char *name = SWIG_TypePrettyName(v->ty);
+ PyObject *hex = PySwigObject_hex(v);
+ PyObject *repr = PyString_FromFormat("<Swig Object of type '%s' at 0x%s>", name, PyString_AsString(hex));
+ Py_DECREF(hex);
+ if (v->next) {
+#ifdef METH_NOARGS
+ PyObject *nrep = PySwigObject_repr((PySwigObject *)v->next);
+#else
+ PyObject *nrep = PySwigObject_repr((PySwigObject *)v->next, args);
+#endif
+ PyString_ConcatAndDel(&repr,nrep);
+ }
+ return repr;
+}
+
+SWIGRUNTIME int
+PySwigObject_print(PySwigObject *v, FILE *fp, int SWIGUNUSEDPARM(flags))
+{
+#ifdef METH_NOARGS
+ PyObject *repr = PySwigObject_repr(v);
+#else
+ PyObject *repr = PySwigObject_repr(v, NULL);
+#endif
+ if (repr) {
+ fputs(PyString_AsString(repr), fp);
+ Py_DECREF(repr);
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+SWIGRUNTIME PyObject *
+PySwigObject_str(PySwigObject *v)
+{
+ char result[SWIG_BUFFER_SIZE];
+ return SWIG_PackVoidPtr(result, v->ptr, v->ty->name, sizeof(result)) ?
+ PyString_FromString(result) : 0;
+}
+
+SWIGRUNTIME int
+PySwigObject_compare(PySwigObject *v, PySwigObject *w)
+{
+ void *i = v->ptr;
+ void *j = w->ptr;
+ return (i < j) ? -1 : ((i > j) ? 1 : 0);
+}
+
+SWIGRUNTIME PyTypeObject* _PySwigObject_type(void);
+
+SWIGRUNTIME PyTypeObject*
+PySwigObject_type(void) {
+ static PyTypeObject *SWIG_STATIC_POINTER(type) = _PySwigObject_type();
+ return type;
+}
+
+SWIGRUNTIMEINLINE int
+PySwigObject_Check(PyObject *op) {
+ return ((op)->ob_type == PySwigObject_type())
+ || (strcmp((op)->ob_type->tp_name,"PySwigObject") == 0);
+}
+
+SWIGRUNTIME PyObject *
+PySwigObject_New(void *ptr, swig_type_info *ty, int own);
+
+SWIGRUNTIME void
+PySwigObject_dealloc(PyObject *v)
+{
+ PySwigObject *sobj = (PySwigObject *) v;
+ PyObject *next = sobj->next;
+ if (sobj->own == SWIG_POINTER_OWN) {
+ swig_type_info *ty = sobj->ty;
+ PySwigClientData *data = ty ? (PySwigClientData *) ty->clientdata : 0;
+ PyObject *destroy = data ? data->destroy : 0;
+ if (destroy) {
+ /* destroy is always a VARARGS method */
+ PyObject *res;
+ if (data->delargs) {
+ /* we need to create a temporal object to carry the destroy operation */
+ PyObject *tmp = PySwigObject_New(sobj->ptr, ty, 0);
+ res = SWIG_Python_CallFunctor(destroy, tmp);
+ Py_DECREF(tmp);
+ } else {
+ PyCFunction meth = PyCFunction_GET_FUNCTION(destroy);
+ PyObject *mself = PyCFunction_GET_SELF(destroy);
+ res = ((*meth)(mself, v));
+ }
+ Py_XDECREF(res);
+ }
+#if !defined(SWIG_PYTHON_SILENT_MEMLEAK)
+ else {
+ const char *name = SWIG_TypePrettyName(ty);
+ printf("swig/python detected a memory leak of type '%s', no destructor found.\n", (name ? name : "unknown"));
+ }
+#endif
+ }
+ Py_XDECREF(next);
+ PyObject_DEL(v);
+}
+
+SWIGRUNTIME PyObject*
+PySwigObject_append(PyObject* v, PyObject* next)
+{
+ PySwigObject *sobj = (PySwigObject *) v;
+#ifndef METH_O
+ PyObject *tmp = 0;
+ if (!PyArg_ParseTuple(next,(char *)"O:append", &tmp)) return NULL;
+ next = tmp;
+#endif
+ if (!PySwigObject_Check(next)) {
+ return NULL;
+ }
+ sobj->next = next;
+ Py_INCREF(next);
+ return SWIG_Py_Void();
+}
+
+SWIGRUNTIME PyObject*
+#ifdef METH_NOARGS
+PySwigObject_next(PyObject* v)
+#else
+PySwigObject_next(PyObject* v, PyObject *SWIGUNUSEDPARM(args))
+#endif
+{
+ PySwigObject *sobj = (PySwigObject *) v;
+ if (sobj->next) {
+ Py_INCREF(sobj->next);
+ return sobj->next;
+ } else {
+ return SWIG_Py_Void();
+ }
+}
+
+SWIGINTERN PyObject*
+#ifdef METH_NOARGS
+PySwigObject_disown(PyObject *v)
+#else
+PySwigObject_disown(PyObject* v, PyObject *SWIGUNUSEDPARM(args))
+#endif
+{
+ PySwigObject *sobj = (PySwigObject *)v;
+ sobj->own = 0;
+ return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject*
+#ifdef METH_NOARGS
+PySwigObject_acquire(PyObject *v)
+#else
+PySwigObject_acquire(PyObject* v, PyObject *SWIGUNUSEDPARM(args))
+#endif
+{
+ PySwigObject *sobj = (PySwigObject *)v;
+ sobj->own = SWIG_POINTER_OWN;
+ return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject*
+PySwigObject_own(PyObject *v, PyObject *args)
+{
+ PyObject *val = 0;
+#if (PY_VERSION_HEX < 0x02020000)
+ if (!PyArg_ParseTuple(args,(char *)"|O:own",&val))
+#else
+ if (!PyArg_UnpackTuple(args, (char *)"own", 0, 1, &val))
+#endif
+ {
+ return NULL;
+ }
+ else
+ {
+ PySwigObject *sobj = (PySwigObject *)v;
+ PyObject *obj = PyBool_FromLong(sobj->own);
+ if (val) {
+#ifdef METH_NOARGS
+ if (PyObject_IsTrue(val)) {
+ PySwigObject_acquire(v);
+ } else {
+ PySwigObject_disown(v);
+ }
+#else
+ if (PyObject_IsTrue(val)) {
+ PySwigObject_acquire(v,args);
+ } else {
+ PySwigObject_disown(v,args);
+ }
+#endif
+ }
+ return obj;
+ }
+}
+
+#ifdef METH_O
+static PyMethodDef
+swigobject_methods[] = {
+ {(char *)"disown", (PyCFunction)PySwigObject_disown, METH_NOARGS, (char *)"releases ownership of the pointer"},
+ {(char *)"acquire", (PyCFunction)PySwigObject_acquire, METH_NOARGS, (char *)"aquires ownership of the pointer"},
+ {(char *)"own", (PyCFunction)PySwigObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"},
+ {(char *)"append", (PyCFunction)PySwigObject_append, METH_O, (char *)"appends another 'this' object"},
+ {(char *)"next", (PyCFunction)PySwigObject_next, METH_NOARGS, (char *)"returns the next 'this' object"},
+ {(char *)"__repr__",(PyCFunction)PySwigObject_repr, METH_NOARGS, (char *)"returns object representation"},
+ {0, 0, 0, 0}
+};
+#else
+static PyMethodDef
+swigobject_methods[] = {
+ {(char *)"disown", (PyCFunction)PySwigObject_disown, METH_VARARGS, (char *)"releases ownership of the pointer"},
+ {(char *)"acquire", (PyCFunction)PySwigObject_acquire, METH_VARARGS, (char *)"aquires ownership of the pointer"},
+ {(char *)"own", (PyCFunction)PySwigObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"},
+ {(char *)"append", (PyCFunction)PySwigObject_append, METH_VARARGS, (char *)"appends another 'this' object"},
+ {(char *)"next", (PyCFunction)PySwigObject_next, METH_VARARGS, (char *)"returns the next 'this' object"},
+ {(char *)"__repr__",(PyCFunction)PySwigObject_repr, METH_VARARGS, (char *)"returns object representation"},
+ {0, 0, 0, 0}
+};
+#endif
+
+#if PY_VERSION_HEX < 0x02020000
+SWIGINTERN PyObject *
+PySwigObject_getattr(PySwigObject *sobj,char *name)
+{
+ return Py_FindMethod(swigobject_methods, (PyObject *)sobj, name);
+}
+#endif
+
+SWIGRUNTIME PyTypeObject*
+_PySwigObject_type(void) {
+ static char swigobject_doc[] = "Swig object carries a C/C++ instance pointer";
+
+ static PyNumberMethods PySwigObject_as_number = {
+ (binaryfunc)0, /*nb_add*/
+ (binaryfunc)0, /*nb_subtract*/
+ (binaryfunc)0, /*nb_multiply*/
+ (binaryfunc)0, /*nb_divide*/
+ (binaryfunc)0, /*nb_remainder*/
+ (binaryfunc)0, /*nb_divmod*/
+ (ternaryfunc)0,/*nb_power*/
+ (unaryfunc)0, /*nb_negative*/
+ (unaryfunc)0, /*nb_positive*/
+ (unaryfunc)0, /*nb_absolute*/
+ (inquiry)0, /*nb_nonzero*/
+ 0, /*nb_invert*/
+ 0, /*nb_lshift*/
+ 0, /*nb_rshift*/
+ 0, /*nb_and*/
+ 0, /*nb_xor*/
+ 0, /*nb_or*/
+ (coercion)0, /*nb_coerce*/
+ (unaryfunc)PySwigObject_long, /*nb_int*/
+ (unaryfunc)PySwigObject_long, /*nb_long*/
+ (unaryfunc)0, /*nb_float*/
+ (unaryfunc)PySwigObject_oct, /*nb_oct*/
+ (unaryfunc)PySwigObject_hex, /*nb_hex*/
+#if PY_VERSION_HEX >= 0x02050000 /* 2.5.0 */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index */
+#elif PY_VERSION_HEX >= 0x02020000 /* 2.2.0 */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_true_divide */
+#elif PY_VERSION_HEX >= 0x02000000 /* 2.0.0 */
+ 0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_or */
+#endif
+ };
+
+ static PyTypeObject pyswigobject_type;
+ static int type_init = 0;
+ if (!type_init) {
+ const PyTypeObject tmp
+ = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ (char *)"PySwigObject", /* tp_name */
+ sizeof(PySwigObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)PySwigObject_dealloc, /* tp_dealloc */
+ (printfunc)PySwigObject_print, /* tp_print */
+#if PY_VERSION_HEX < 0x02020000
+ (getattrfunc)PySwigObject_getattr, /* tp_getattr */
+#else
+ (getattrfunc)0, /* tp_getattr */
+#endif
+ (setattrfunc)0, /* tp_setattr */
+ (cmpfunc)PySwigObject_compare, /* tp_compare */
+ (reprfunc)PySwigObject_repr, /* tp_repr */
+ &PySwigObject_as_number, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)PySwigObject_str, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ swigobject_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+#if PY_VERSION_HEX >= 0x02020000
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ swigobject_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+#endif
+#if PY_VERSION_HEX >= 0x02030000
+ 0, /* tp_del */
+#endif
+#ifdef COUNT_ALLOCS
+ 0,0,0,0 /* tp_alloc -> tp_next */
+#endif
+ };
+ pyswigobject_type = tmp;
+ pyswigobject_type.ob_type = &PyType_Type;
+ type_init = 1;
+ }
+ return &pyswigobject_type;
+}
+
+SWIGRUNTIME PyObject *
+PySwigObject_New(void *ptr, swig_type_info *ty, int own)
+{
+ PySwigObject *sobj = PyObject_NEW(PySwigObject, PySwigObject_type());
+ if (sobj) {
+ sobj->ptr = ptr;
+ sobj->ty = ty;
+ sobj->own = own;
+ sobj->next = 0;
+ }
+ return (PyObject *)sobj;
+}
+
+/* -----------------------------------------------------------------------------
+ * Implements a simple Swig Packed type, and use it instead of string
+ * ----------------------------------------------------------------------------- */
+
+typedef struct {
+ PyObject_HEAD
+ void *pack;
+ swig_type_info *ty;
+ size_t size;
+} PySwigPacked;
+
+SWIGRUNTIME int
+PySwigPacked_print(PySwigPacked *v, FILE *fp, int SWIGUNUSEDPARM(flags))
+{
+ char result[SWIG_BUFFER_SIZE];
+ fputs("<Swig Packed ", fp);
+ if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) {
+ fputs("at ", fp);
+ fputs(result, fp);
+ }
+ fputs(v->ty->name,fp);
+ fputs(">", fp);
+ return 0;
+}
+
+SWIGRUNTIME PyObject *
+PySwigPacked_repr(PySwigPacked *v)
+{
+ char result[SWIG_BUFFER_SIZE];
+ if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) {
+ return PyString_FromFormat("<Swig Packed at %s%s>", result, v->ty->name);
+ } else {
+ return PyString_FromFormat("<Swig Packed %s>", v->ty->name);
+ }
+}
+
+SWIGRUNTIME PyObject *
+PySwigPacked_str(PySwigPacked *v)
+{
+ char result[SWIG_BUFFER_SIZE];
+ if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))){
+ return PyString_FromFormat("%s%s", result, v->ty->name);
+ } else {
+ return PyString_FromString(v->ty->name);
+ }
+}
+
+SWIGRUNTIME int
+PySwigPacked_compare(PySwigPacked *v, PySwigPacked *w)
+{
+ size_t i = v->size;
+ size_t j = w->size;
+ int s = (i < j) ? -1 : ((i > j) ? 1 : 0);
+ return s ? s : strncmp((char *)v->pack, (char *)w->pack, 2*v->size);
+}
+
+SWIGRUNTIME PyTypeObject* _PySwigPacked_type(void);
+
+SWIGRUNTIME PyTypeObject*
+PySwigPacked_type(void) {
+ static PyTypeObject *SWIG_STATIC_POINTER(type) = _PySwigPacked_type();
+ return type;
+}
+
+SWIGRUNTIMEINLINE int
+PySwigPacked_Check(PyObject *op) {
+ return ((op)->ob_type == _PySwigPacked_type())
+ || (strcmp((op)->ob_type->tp_name,"PySwigPacked") == 0);
+}
+
+SWIGRUNTIME void
+PySwigPacked_dealloc(PyObject *v)
+{
+ if (PySwigPacked_Check(v)) {
+ PySwigPacked *sobj = (PySwigPacked *) v;
+ free(sobj->pack);
+ }
+ PyObject_DEL(v);
+}
+
+SWIGRUNTIME PyTypeObject*
+_PySwigPacked_type(void) {
+ static char swigpacked_doc[] = "Swig object carries a C/C++ instance pointer";
+ static PyTypeObject pyswigpacked_type;
+ static int type_init = 0;
+ if (!type_init) {
+ const PyTypeObject tmp
+ = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ (char *)"PySwigPacked", /* tp_name */
+ sizeof(PySwigPacked), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)PySwigPacked_dealloc, /* tp_dealloc */
+ (printfunc)PySwigPacked_print, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+ (cmpfunc)PySwigPacked_compare, /* tp_compare */
+ (reprfunc)PySwigPacked_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)PySwigPacked_str, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ swigpacked_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+#if PY_VERSION_HEX >= 0x02020000
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+#endif
+#if PY_VERSION_HEX >= 0x02030000
+ 0, /* tp_del */
+#endif
+#ifdef COUNT_ALLOCS
+ 0,0,0,0 /* tp_alloc -> tp_next */
+#endif
+ };
+ pyswigpacked_type = tmp;
+ pyswigpacked_type.ob_type = &PyType_Type;
+ type_init = 1;
+ }
+ return &pyswigpacked_type;
+}
+
+SWIGRUNTIME PyObject *
+PySwigPacked_New(void *ptr, size_t size, swig_type_info *ty)
+{
+ PySwigPacked *sobj = PyObject_NEW(PySwigPacked, PySwigPacked_type());
+ if (sobj) {
+ void *pack = malloc(size);
+ if (pack) {
+ memcpy(pack, ptr, size);
+ sobj->pack = pack;
+ sobj->ty = ty;
+ sobj->size = size;
+ } else {
+ PyObject_DEL((PyObject *) sobj);
+ sobj = 0;
+ }
+ }
+ return (PyObject *) sobj;
+}
+
+SWIGRUNTIME swig_type_info *
+PySwigPacked_UnpackData(PyObject *obj, void *ptr, size_t size)
+{
+ if (PySwigPacked_Check(obj)) {
+ PySwigPacked *sobj = (PySwigPacked *)obj;
+ if (sobj->size != size) return 0;
+ memcpy(ptr, sobj->pack, size);
+ return sobj->ty;
+ } else {
+ return 0;
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * pointers/data manipulation
+ * ----------------------------------------------------------------------------- */
+
+SWIGRUNTIMEINLINE PyObject *
+_SWIG_This(void)
+{
+ return PyString_FromString("this");
+}
+
+SWIGRUNTIME PyObject *
+SWIG_This(void)
+{
+ static PyObject *SWIG_STATIC_POINTER(swig_this) = _SWIG_This();
+ return swig_this;
+}
+
+/* #define SWIG_PYTHON_SLOW_GETSET_THIS */
+
+SWIGRUNTIME PySwigObject *
+SWIG_Python_GetSwigThis(PyObject *pyobj)
+{
+ if (PySwigObject_Check(pyobj)) {
+ return (PySwigObject *) pyobj;
+ } else {
+ PyObject *obj = 0;
+#if (!defined(SWIG_PYTHON_SLOW_GETSET_THIS) && (PY_VERSION_HEX >= 0x02030000))
+ if (PyInstance_Check(pyobj)) {
+ obj = _PyInstance_Lookup(pyobj, SWIG_This());
+ } else {
+ PyObject **dictptr = _PyObject_GetDictPtr(pyobj);
+ if (dictptr != NULL) {
+ PyObject *dict = *dictptr;
+ obj = dict ? PyDict_GetItem(dict, SWIG_This()) : 0;
+ } else {
+#ifdef PyWeakref_CheckProxy
+ if (PyWeakref_CheckProxy(pyobj)) {
+ PyObject *wobj = PyWeakref_GET_OBJECT(pyobj);
+ return wobj ? SWIG_Python_GetSwigThis(wobj) : 0;
+ }
+#endif
+ obj = PyObject_GetAttr(pyobj,SWIG_This());
+ if (obj) {
+ Py_DECREF(obj);
+ } else {
+ if (PyErr_Occurred()) PyErr_Clear();
+ return 0;
+ }
+ }
+ }
+#else
+ obj = PyObject_GetAttr(pyobj,SWIG_This());
+ if (obj) {
+ Py_DECREF(obj);
+ } else {
+ if (PyErr_Occurred()) PyErr_Clear();
+ return 0;
+ }
+#endif
+ if (obj && !PySwigObject_Check(obj)) {
+ /* a PyObject is called 'this', try to get the 'real this'
+ PySwigObject from it */
+ return SWIG_Python_GetSwigThis(obj);
+ }
+ return (PySwigObject *)obj;
+ }
+}
+
+/* Acquire a pointer value */
+
+SWIGRUNTIME int
+SWIG_Python_AcquirePtr(PyObject *obj, int own) {
+ if (own == SWIG_POINTER_OWN) {
+ PySwigObject *sobj = SWIG_Python_GetSwigThis(obj);
+ if (sobj) {
+ int oldown = sobj->own;
+ sobj->own = own;
+ return oldown;
+ }
+ }
+ return 0;
+}
+
+/* Convert a pointer value */
+
+SWIGRUNTIME int
+SWIG_Python_ConvertPtrAndOwn(PyObject *obj, void **ptr, swig_type_info *ty, int flags, int *own) {
+ if (!obj) return SWIG_ERROR;
+ if (obj == Py_None) {
+ if (ptr) *ptr = 0;
+ return SWIG_OK;
+ } else {
+ PySwigObject *sobj = SWIG_Python_GetSwigThis(obj);
+ if (own)
+ *own = 0;
+ while (sobj) {
+ void *vptr = sobj->ptr;
+ if (ty) {
+ swig_type_info *to = sobj->ty;
+ if (to == ty) {
+ /* no type cast needed */
+ if (ptr) *ptr = vptr;
+ break;
+ } else {
+ swig_cast_info *tc = SWIG_TypeCheck(to->name,ty);
+ if (!tc) {
+ sobj = (PySwigObject *)sobj->next;
+ } else {
+ if (ptr) {
+ int newmemory = 0;
+ *ptr = SWIG_TypeCast(tc,vptr,&newmemory);
+ if (newmemory == SWIG_CAST_NEW_MEMORY) {
+ assert(own);
+ if (own)
+ *own = *own | SWIG_CAST_NEW_MEMORY;
+ }
+ }
+ break;
+ }
+ }
+ } else {
+ if (ptr) *ptr = vptr;
+ break;
+ }
+ }
+ if (sobj) {
+ if (own)
+ *own = *own | sobj->own;
+ if (flags & SWIG_POINTER_DISOWN) {
+ sobj->own = 0;
+ }
+ return SWIG_OK;
+ } else {
+ int res = SWIG_ERROR;
+ if (flags & SWIG_POINTER_IMPLICIT_CONV) {
+ PySwigClientData *data = ty ? (PySwigClientData *) ty->clientdata : 0;
+ if (data && !data->implicitconv) {
+ PyObject *klass = data->klass;
+ if (klass) {
+ PyObject *impconv;
+ data->implicitconv = 1; /* avoid recursion and call 'explicit' constructors*/
+ impconv = SWIG_Python_CallFunctor(klass, obj);
+ data->implicitconv = 0;
+ if (PyErr_Occurred()) {
+ PyErr_Clear();
+ impconv = 0;
+ }
+ if (impconv) {
+ PySwigObject *iobj = SWIG_Python_GetSwigThis(impconv);
+ if (iobj) {
+ void *vptr;
+ res = SWIG_Python_ConvertPtrAndOwn((PyObject*)iobj, &vptr, ty, 0, 0);
+ if (SWIG_IsOK(res)) {
+ if (ptr) {
+ *ptr = vptr;
+ /* transfer the ownership to 'ptr' */
+ iobj->own = 0;
+ res = SWIG_AddCast(res);
+ res = SWIG_AddNewMask(res);
+ } else {
+ res = SWIG_AddCast(res);
+ }
+ }
+ }
+ Py_DECREF(impconv);
+ }
+ }
+ }
+ }
+ return res;
+ }
+ }
+}
+
+/* Convert a function ptr value */
+
+SWIGRUNTIME int
+SWIG_Python_ConvertFunctionPtr(PyObject *obj, void **ptr, swig_type_info *ty) {
+ if (!PyCFunction_Check(obj)) {
+ return SWIG_ConvertPtr(obj, ptr, ty, 0);
+ } else {
+ void *vptr = 0;
+
+ /* here we get the method pointer for callbacks */
+ const char *doc = (((PyCFunctionObject *)obj) -> m_ml -> ml_doc);
+ const char *desc = doc ? strstr(doc, "swig_ptr: ") : 0;
+ if (desc) {
+ desc = ty ? SWIG_UnpackVoidPtr(desc + 10, &vptr, ty->name) : 0;
+ if (!desc) return SWIG_ERROR;
+ }
+ if (ty) {
+ swig_cast_info *tc = SWIG_TypeCheck(desc,ty);
+ if (tc) {
+ int newmemory = 0;
+ *ptr = SWIG_TypeCast(tc,vptr,&newmemory);
+ assert(!newmemory); /* newmemory handling not yet implemented */
+ } else {
+ return SWIG_ERROR;
+ }
+ } else {
+ *ptr = vptr;
+ }
+ return SWIG_OK;
+ }
+}
+
+/* Convert a packed value value */
+
+SWIGRUNTIME int
+SWIG_Python_ConvertPacked(PyObject *obj, void *ptr, size_t sz, swig_type_info *ty) {
+ swig_type_info *to = PySwigPacked_UnpackData(obj, ptr, sz);
+ if (!to) return SWIG_ERROR;
+ if (ty) {
+ if (to != ty) {
+ /* check type cast? */
+ swig_cast_info *tc = SWIG_TypeCheck(to->name,ty);
+ if (!tc) return SWIG_ERROR;
+ }
+ }
+ return SWIG_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * Create a new pointer object
+ * ----------------------------------------------------------------------------- */
+
+/*
+ Create a new instance object, whitout calling __init__, and set the
+ 'this' attribute.
+*/
+
+SWIGRUNTIME PyObject*
+SWIG_Python_NewShadowInstance(PySwigClientData *data, PyObject *swig_this)
+{
+#if (PY_VERSION_HEX >= 0x02020000)
+ PyObject *inst = 0;
+ PyObject *newraw = data->newraw;
+ if (newraw) {
+ inst = PyObject_Call(newraw, data->newargs, NULL);
+ if (inst) {
+#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS)
+ PyObject **dictptr = _PyObject_GetDictPtr(inst);
+ if (dictptr != NULL) {
+ PyObject *dict = *dictptr;
+ if (dict == NULL) {
+ dict = PyDict_New();
+ *dictptr = dict;
+ PyDict_SetItem(dict, SWIG_This(), swig_this);
+ }
+ }
+#else
+ PyObject *key = SWIG_This();
+ PyObject_SetAttr(inst, key, swig_this);
+#endif
+ }
+ } else {
+ PyObject *dict = PyDict_New();
+ PyDict_SetItem(dict, SWIG_This(), swig_this);
+ inst = PyInstance_NewRaw(data->newargs, dict);
+ Py_DECREF(dict);
+ }
+ return inst;
+#else
+#if (PY_VERSION_HEX >= 0x02010000)
+ PyObject *inst;
+ PyObject *dict = PyDict_New();
+ PyDict_SetItem(dict, SWIG_This(), swig_this);
+ inst = PyInstance_NewRaw(data->newargs, dict);
+ Py_DECREF(dict);
+ return (PyObject *) inst;
+#else
+ PyInstanceObject *inst = PyObject_NEW(PyInstanceObject, &PyInstance_Type);
+ if (inst == NULL) {
+ return NULL;
+ }
+ inst->in_class = (PyClassObject *)data->newargs;
+ Py_INCREF(inst->in_class);
+ inst->in_dict = PyDict_New();
+ if (inst->in_dict == NULL) {
+ Py_DECREF(inst);
+ return NULL;
+ }
+#ifdef Py_TPFLAGS_HAVE_WEAKREFS
+ inst->in_weakreflist = NULL;
+#endif
+#ifdef Py_TPFLAGS_GC
+ PyObject_GC_Init(inst);
+#endif
+ PyDict_SetItem(inst->in_dict, SWIG_This(), swig_this);
+ return (PyObject *) inst;
+#endif
+#endif
+}
+
+SWIGRUNTIME void
+SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this)
+{
+ PyObject *dict;
+#if (PY_VERSION_HEX >= 0x02020000) && !defined(SWIG_PYTHON_SLOW_GETSET_THIS)
+ PyObject **dictptr = _PyObject_GetDictPtr(inst);
+ if (dictptr != NULL) {
+ dict = *dictptr;
+ if (dict == NULL) {
+ dict = PyDict_New();
+ *dictptr = dict;
+ }
+ PyDict_SetItem(dict, SWIG_This(), swig_this);
+ return;
+ }
+#endif
+ dict = PyObject_GetAttrString(inst, (char*)"__dict__");
+ PyDict_SetItem(dict, SWIG_This(), swig_this);
+ Py_DECREF(dict);
+}
+
+
+SWIGINTERN PyObject *
+SWIG_Python_InitShadowInstance(PyObject *args) {
+ PyObject *obj[2];
+ if (!SWIG_Python_UnpackTuple(args,(char*)"swiginit", 2, 2, obj)) {
+ return NULL;
+ } else {
+ PySwigObject *sthis = SWIG_Python_GetSwigThis(obj[0]);
+ if (sthis) {
+ PySwigObject_append((PyObject*) sthis, obj[1]);
+ } else {
+ SWIG_Python_SetSwigThis(obj[0], obj[1]);
+ }
+ return SWIG_Py_Void();
+ }
+}
+
+/* Create a new pointer object */
+
+SWIGRUNTIME PyObject *
+SWIG_Python_NewPointerObj(void *ptr, swig_type_info *type, int flags) {
+ if (!ptr) {
+ return SWIG_Py_Void();
+ } else {
+ int own = (flags & SWIG_POINTER_OWN) ? SWIG_POINTER_OWN : 0;
+ PyObject *robj = PySwigObject_New(ptr, type, own);
+ PySwigClientData *clientdata = type ? (PySwigClientData *)(type->clientdata) : 0;
+ if (clientdata && !(flags & SWIG_POINTER_NOSHADOW)) {
+ PyObject *inst = SWIG_Python_NewShadowInstance(clientdata, robj);
+ if (inst) {
+ Py_DECREF(robj);
+ robj = inst;
+ }
+ }
+ return robj;
+ }
+}
+
+/* Create a new packed object */
+
+SWIGRUNTIMEINLINE PyObject *
+SWIG_Python_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) {
+ return ptr ? PySwigPacked_New((void *) ptr, sz, type) : SWIG_Py_Void();
+}
+
+/* -----------------------------------------------------------------------------*
+ * Get type list
+ * -----------------------------------------------------------------------------*/
+
+#ifdef SWIG_LINK_RUNTIME
+void *SWIG_ReturnGlobalTypeList(void *);
+#endif
+
+SWIGRUNTIME swig_module_info *
+SWIG_Python_GetModule(void) {
+ static void *type_pointer = (void *)0;
+ /* first check if module already created */
+ if (!type_pointer) {
+#ifdef SWIG_LINK_RUNTIME
+ type_pointer = SWIG_ReturnGlobalTypeList((void *)0);
+#else
+ type_pointer = PyCObject_Import((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION,
+ (char*)"type_pointer" SWIG_TYPE_TABLE_NAME);
+ if (PyErr_Occurred()) {
+ PyErr_Clear();
+ type_pointer = (void *)0;
+ }
+#endif
+ }
+ return (swig_module_info *) type_pointer;
+}
+
+#if PY_MAJOR_VERSION < 2
+/* PyModule_AddObject function was introduced in Python 2.0. The following function
+ is copied out of Python/modsupport.c in python version 2.3.4 */
+SWIGINTERN int
+PyModule_AddObject(PyObject *m, char *name, PyObject *o)
+{
+ PyObject *dict;
+ if (!PyModule_Check(m)) {
+ PyErr_SetString(PyExc_TypeError,
+ "PyModule_AddObject() needs module as first arg");
+ return SWIG_ERROR;
+ }
+ if (!o) {
+ PyErr_SetString(PyExc_TypeError,
+ "PyModule_AddObject() needs non-NULL value");
+ return SWIG_ERROR;
+ }
+
+ dict = PyModule_GetDict(m);
+ if (dict == NULL) {
+ /* Internal error -- modules must have a dict! */
+ PyErr_Format(PyExc_SystemError, "module '%s' has no __dict__",
+ PyModule_GetName(m));
+ return SWIG_ERROR;
+ }
+ if (PyDict_SetItemString(dict, name, o))
+ return SWIG_ERROR;
+ Py_DECREF(o);
+ return SWIG_OK;
+}
+#endif
+
+SWIGRUNTIME void
+SWIG_Python_DestroyModule(void *vptr)
+{
+ swig_module_info *swig_module = (swig_module_info *) vptr;
+ swig_type_info **types = swig_module->types;
+ size_t i;
+ for (i =0; i < swig_module->size; ++i) {
+ swig_type_info *ty = types[i];
+ if (ty->owndata) {
+ PySwigClientData *data = (PySwigClientData *) ty->clientdata;
+ if (data) PySwigClientData_Del(data);
+ }
+ }
+ Py_DECREF(SWIG_This());
+}
+
+SWIGRUNTIME void
+SWIG_Python_SetModule(swig_module_info *swig_module) {
+ static PyMethodDef swig_empty_runtime_method_table[] = { {NULL, NULL, 0, NULL} };/* Sentinel */
+
+ PyObject *module = Py_InitModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION,
+ swig_empty_runtime_method_table);
+ PyObject *pointer = PyCObject_FromVoidPtr((void *) swig_module, SWIG_Python_DestroyModule);
+ if (pointer && module) {
+ PyModule_AddObject(module, (char*)"type_pointer" SWIG_TYPE_TABLE_NAME, pointer);
+ } else {
+ Py_XDECREF(pointer);
+ }
+}
+
+/* The python cached type query */
+SWIGRUNTIME PyObject *
+SWIG_Python_TypeCache(void) {
+ static PyObject *SWIG_STATIC_POINTER(cache) = PyDict_New();
+ return cache;
+}
+
+SWIGRUNTIME swig_type_info *
+SWIG_Python_TypeQuery(const char *type)
+{
+ PyObject *cache = SWIG_Python_TypeCache();
+ PyObject *key = PyString_FromString(type);
+ PyObject *obj = PyDict_GetItem(cache, key);
+ swig_type_info *descriptor;
+ if (obj) {
+ descriptor = (swig_type_info *) PyCObject_AsVoidPtr(obj);
+ } else {
+ swig_module_info *swig_module = SWIG_Python_GetModule();
+ descriptor = SWIG_TypeQueryModule(swig_module, swig_module, type);
+ if (descriptor) {
+ obj = PyCObject_FromVoidPtr(descriptor, NULL);
+ PyDict_SetItem(cache, key, obj);
+ Py_DECREF(obj);
+ }
+ }
+ Py_DECREF(key);
+ return descriptor;
+}
+
+/*
+ For backward compatibility only
+*/
+#define SWIG_POINTER_EXCEPTION 0
+#define SWIG_arg_fail(arg) SWIG_Python_ArgFail(arg)
+#define SWIG_MustGetPtr(p, type, argnum, flags) SWIG_Python_MustGetPtr(p, type, argnum, flags)
+
+SWIGRUNTIME int
+SWIG_Python_AddErrMesg(const char* mesg, int infront)
+{
+ if (PyErr_Occurred()) {
+ PyObject *type = 0;
+ PyObject *value = 0;
+ PyObject *traceback = 0;
+ PyErr_Fetch(&type, &value, &traceback);
+ if (value) {
+ PyObject *old_str = PyObject_Str(value);
+ Py_XINCREF(type);
+ PyErr_Clear();
+ if (infront) {
+ PyErr_Format(type, "%s %s", mesg, PyString_AsString(old_str));
+ } else {
+ PyErr_Format(type, "%s %s", PyString_AsString(old_str), mesg);
+ }
+ Py_DECREF(old_str);
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+SWIGRUNTIME int
+SWIG_Python_ArgFail(int argnum)
+{
+ if (PyErr_Occurred()) {
+ /* add information about failing argument */
+ char mesg[256];
+ PyOS_snprintf(mesg, sizeof(mesg), "argument number %d:", argnum);
+ return SWIG_Python_AddErrMesg(mesg, 1);
+ } else {
+ return 0;
+ }
+}
+
+SWIGRUNTIMEINLINE const char *
+PySwigObject_GetDesc(PyObject *self)
+{
+ PySwigObject *v = (PySwigObject *)self;
+ swig_type_info *ty = v ? v->ty : 0;
+ return ty ? ty->str : (char*)"";
+}
+
+SWIGRUNTIME void
+SWIG_Python_TypeError(const char *type, PyObject *obj)
+{
+ if (type) {
+#if defined(SWIG_COBJECT_TYPES)
+ if (obj && PySwigObject_Check(obj)) {
+ const char *otype = (const char *) PySwigObject_GetDesc(obj);
+ if (otype) {
+ PyErr_Format(PyExc_TypeError, "a '%s' is expected, 'PySwigObject(%s)' is received",
+ type, otype);
+ return;
+ }
+ } else
+#endif
+ {
+ const char *otype = (obj ? obj->ob_type->tp_name : 0);
+ if (otype) {
+ PyObject *str = PyObject_Str(obj);
+ const char *cstr = str ? PyString_AsString(str) : 0;
+ if (cstr) {
+ PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s(%s)' is received",
+ type, otype, cstr);
+ } else {
+ PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s' is received",
+ type, otype);
+ }
+ Py_XDECREF(str);
+ return;
+ }
+ }
+ PyErr_Format(PyExc_TypeError, "a '%s' is expected", type);
+ } else {
+ PyErr_Format(PyExc_TypeError, "unexpected type is received");
+ }
+}
+
+
+/* Convert a pointer value, signal an exception on a type mismatch */
+SWIGRUNTIME void *
+SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int argnum, int flags) {
+ void *result;
+ if (SWIG_Python_ConvertPtr(obj, &result, ty, flags) == -1) {
+ PyErr_Clear();
+ if (flags & SWIG_POINTER_EXCEPTION) {
+ SWIG_Python_TypeError(SWIG_TypePrettyName(ty), obj);
+ SWIG_Python_ArgFail(argnum);
+ }
+ }
+ return result;
+}
+
+
+#ifdef __cplusplus
+#if 0
+{ /* cc-mode */
+#endif
+}
+#endif
+
+
+
+#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0)
+
+#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else
+
+
+
+/* -------- TYPES TABLE (BEGIN) -------- */
+
+#define SWIGTYPE_p_TDB_DATA swig_types[0]
+#define SWIGTYPE_p_char swig_types[1]
+#define SWIGTYPE_p_int swig_types[2]
+#define SWIGTYPE_p_long_long swig_types[3]
+#define SWIGTYPE_p_short swig_types[4]
+#define SWIGTYPE_p_signed_char swig_types[5]
+#define SWIGTYPE_p_tdb_context swig_types[6]
+#define SWIGTYPE_p_unsigned_char swig_types[7]
+#define SWIGTYPE_p_unsigned_int swig_types[8]
+#define SWIGTYPE_p_unsigned_long_long swig_types[9]
+#define SWIGTYPE_p_unsigned_short swig_types[10]
+static swig_type_info *swig_types[12];
+static swig_module_info swig_module = {swig_types, 11, 0, 0, 0, 0};
+#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
+#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
+
+/* -------- TYPES TABLE (END) -------- */
+
+#if (PY_VERSION_HEX <= 0x02000000)
+# if !defined(SWIG_PYTHON_CLASSIC)
+# error "This python version requires swig to be run with the '-classic' option"
+# endif
+#endif
+#if (PY_VERSION_HEX <= 0x02020000)
+# error "This python version requires swig to be run with the '-nomodern' option"
+#endif
+#if (PY_VERSION_HEX <= 0x02020000)
+# error "This python version requires swig to be run with the '-nomodernargs' option"
+#endif
+#ifndef METH_O
+# error "This python version requires swig to be run with the '-nofastunpack' option"
+#endif
+#ifdef SWIG_TypeQuery
+# undef SWIG_TypeQuery
+#endif
+#define SWIG_TypeQuery SWIG_Python_TypeQuery
+
+/*-----------------------------------------------
+ @(target):= _tdb.so
+ ------------------------------------------------*/
+#define SWIG_init init_tdb
+
+#define SWIG_name "_tdb"
+
+#define SWIGVERSION 0x010335
+#define SWIG_VERSION SWIGVERSION
+
+
+#define SWIG_as_voidptr(a) (void *)((const void *)(a))
+#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a))
+
+
+
+/* This symbol is used in both includes.h and Python.h which causes an
+ annoying compiler warning. */
+
+#ifdef HAVE_FSTAT
+#undef HAVE_FSTAT
+#endif
+
+/* Include tdb headers */
+#include <stdint.h>
+#include <signal.h>
+#include <tdb.h>
+#include <fcntl.h>
+
+typedef TDB_CONTEXT tdb;
+
+
+ #define SWIG_From_long PyInt_FromLong
+
+
+SWIGINTERNINLINE PyObject *
+SWIG_From_int (int value)
+{
+ return SWIG_From_long (value);
+}
+
+
+SWIGINTERN swig_type_info*
+SWIG_pchar_descriptor(void)
+{
+ static int init = 0;
+ static swig_type_info* info = 0;
+ if (!init) {
+ info = SWIG_TypeQuery("_p_char");
+ init = 1;
+ }
+ return info;
+}
+
+
+SWIGINTERN int
+SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc)
+{
+ if (PyString_Check(obj)) {
+ char *cstr; Py_ssize_t len;
+ PyString_AsStringAndSize(obj, &cstr, &len);
+ if (cptr) {
+ if (alloc) {
+ /*
+ In python the user should not be able to modify the inner
+ string representation. To warranty that, if you define
+ SWIG_PYTHON_SAFE_CSTRINGS, a new/copy of the python string
+ buffer is always returned.
+
+ The default behavior is just to return the pointer value,
+ so, be careful.
+ */
+#if defined(SWIG_PYTHON_SAFE_CSTRINGS)
+ if (*alloc != SWIG_OLDOBJ)
+#else
+ if (*alloc == SWIG_NEWOBJ)
+#endif
+ {
+ *cptr = (char *)memcpy((char *)malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1));
+ *alloc = SWIG_NEWOBJ;
+ }
+ else {
+ *cptr = cstr;
+ *alloc = SWIG_OLDOBJ;
+ }
+ } else {
+ *cptr = PyString_AsString(obj);
+ }
+ }
+ if (psize) *psize = len + 1;
+ return SWIG_OK;
+ } else {
+ swig_type_info* pchar_descriptor = SWIG_pchar_descriptor();
+ if (pchar_descriptor) {
+ void* vptr = 0;
+ if (SWIG_ConvertPtr(obj, &vptr, pchar_descriptor, 0) == SWIG_OK) {
+ if (cptr) *cptr = (char *) vptr;
+ if (psize) *psize = vptr ? (strlen((char *)vptr) + 1) : 0;
+ if (alloc) *alloc = SWIG_OLDOBJ;
+ return SWIG_OK;
+ }
+ }
+ }
+ return SWIG_TypeError;
+}
+
+
+
+
+
+#include <limits.h>
+#if !defined(SWIG_NO_LLONG_MAX)
+# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__)
+# define LLONG_MAX __LONG_LONG_MAX__
+# define LLONG_MIN (-LLONG_MAX - 1LL)
+# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
+# endif
+#endif
+
+
+SWIGINTERN int
+SWIG_AsVal_double (PyObject *obj, double *val)
+{
+ int res = SWIG_TypeError;
+ if (PyFloat_Check(obj)) {
+ if (val) *val = PyFloat_AsDouble(obj);
+ return SWIG_OK;
+ } else if (PyInt_Check(obj)) {
+ if (val) *val = PyInt_AsLong(obj);
+ return SWIG_OK;
+ } else if (PyLong_Check(obj)) {
+ double v = PyLong_AsDouble(obj);
+ if (!PyErr_Occurred()) {
+ if (val) *val = v;
+ return SWIG_OK;
+ } else {
+ PyErr_Clear();
+ }
+ }
+#ifdef SWIG_PYTHON_CAST_MODE
+ {
+ int dispatch = 0;
+ double d = PyFloat_AsDouble(obj);
+ if (!PyErr_Occurred()) {
+ if (val) *val = d;
+ return SWIG_AddCast(SWIG_OK);
+ } else {
+ PyErr_Clear();
+ }
+ if (!dispatch) {
+ long v = PyLong_AsLong(obj);
+ if (!PyErr_Occurred()) {
+ if (val) *val = v;
+ return SWIG_AddCast(SWIG_AddCast(SWIG_OK));
+ } else {
+ PyErr_Clear();
+ }
+ }
+ }
+#endif
+ return res;
+}
+
+
+#include <float.h>
+
+
+#include <math.h>
+
+
+SWIGINTERNINLINE int
+SWIG_CanCastAsInteger(double *d, double min, double max) {
+ double x = *d;
+ if ((min <= x && x <= max)) {
+ double fx = floor(x);
+ double cx = ceil(x);
+ double rd = ((x - fx) < 0.5) ? fx : cx; /* simple rint */
+ if ((errno == EDOM) || (errno == ERANGE)) {
+ errno = 0;
+ } else {
+ double summ, reps, diff;
+ if (rd < x) {
+ diff = x - rd;
+ } else if (rd > x) {
+ diff = rd - x;
+ } else {
+ return 1;
+ }
+ summ = rd + x;
+ reps = diff/summ;
+ if (reps < 8*DBL_EPSILON) {
+ *d = rd;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_long (PyObject *obj, long* val)
+{
+ if (PyInt_Check(obj)) {
+ if (val) *val = PyInt_AsLong(obj);
+ return SWIG_OK;
+ } else if (PyLong_Check(obj)) {
+ long v = PyLong_AsLong(obj);
+ if (!PyErr_Occurred()) {
+ if (val) *val = v;
+ return SWIG_OK;
+ } else {
+ PyErr_Clear();
+ }
+ }
+#ifdef SWIG_PYTHON_CAST_MODE
+ {
+ int dispatch = 0;
+ long v = PyInt_AsLong(obj);
+ if (!PyErr_Occurred()) {
+ if (val) *val = v;
+ return SWIG_AddCast(SWIG_OK);
+ } else {
+ PyErr_Clear();
+ }
+ if (!dispatch) {
+ double d;
+ int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d));
+ if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) {
+ if (val) *val = (long)(d);
+ return res;
+ }
+ }
+ }
+#endif
+ return SWIG_TypeError;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_int (PyObject * obj, int *val)
+{
+ long v;
+ int res = SWIG_AsVal_long (obj, &v);
+ if (SWIG_IsOK(res)) {
+ if ((v < INT_MIN || v > INT_MAX)) {
+ return SWIG_OverflowError;
+ } else {
+ if (val) *val = (int)(v);
+ }
+ }
+ return res;
+}
+
+SWIGINTERN tdb *new_tdb(char const *name,int hash_size,int tdb_flags,int flags,mode_t mode){
+ return tdb_open(name, hash_size, tdb_flags, flags, mode);
+ }
+SWIGINTERN void delete_tdb(tdb *self){ tdb_close(self); }
+
+SWIGINTERNINLINE PyObject *
+SWIG_FromCharPtrAndSize(const char* carray, size_t size)
+{
+ if (carray) {
+ if (size > INT_MAX) {
+ swig_type_info* pchar_descriptor = SWIG_pchar_descriptor();
+ return pchar_descriptor ?
+ SWIG_NewPointerObj((char *)(carray), pchar_descriptor, 0) : SWIG_Py_Void();
+ } else {
+ return PyString_FromStringAndSize(carray, (int)(size));
+ }
+ } else {
+ return SWIG_Py_Void();
+ }
+}
+
+
+SWIGINTERNINLINE PyObject *
+SWIG_FromCharPtr(const char *cptr)
+{
+ return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0));
+}
+
+
+SWIGINTERNINLINE PyObject*
+SWIG_From_unsigned_SS_long (unsigned long value)
+{
+ return (value > LONG_MAX) ?
+ PyLong_FromUnsignedLong(value) : PyInt_FromLong((long)(value));
+}
+
+
+SWIGINTERNINLINE PyObject *
+SWIG_From_size_t (size_t value)
+{
+ return SWIG_From_unsigned_SS_long ((unsigned long)(value));
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+SWIGINTERN PyObject *_wrap_new_Tdb(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+ PyObject *resultobj = 0;
+ char *arg1 = (char *) 0 ;
+ int arg2 ;
+ int arg3 ;
+ int arg4 ;
+ mode_t arg5 ;
+ tdb *result = 0 ;
+ int res1 ;
+ char *buf1 = 0 ;
+ int alloc1 = 0 ;
+ int val2 ;
+ int ecode2 = 0 ;
+ int val3 ;
+ int ecode3 = 0 ;
+ int val4 ;
+ int ecode4 = 0 ;
+ int val5 ;
+ int ecode5 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ PyObject * obj2 = 0 ;
+ PyObject * obj3 = 0 ;
+ PyObject * obj4 = 0 ;
+ char * kwnames[] = {
+ (char *) "name",(char *) "hash_size",(char *) "tdb_flags",(char *) "flags",(char *) "mode", NULL
+ };
+
+ arg2 = 0;
+ arg3 = TDB_DEFAULT;
+ arg4 = O_RDWR;
+ arg5 = 0600;
+ if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OOOO:new_Tdb",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail;
+ res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1);
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_Tdb" "', argument " "1"" of type '" "char const *""'");
+ }
+ arg1 = (char *)(buf1);
+ if (obj1) {
+ ecode2 = SWIG_AsVal_int(obj1, &val2);
+ if (!SWIG_IsOK(ecode2)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "new_Tdb" "', argument " "2"" of type '" "int""'");
+ }
+ arg2 = (int)(val2);
+ }
+ if (obj2) {
+ ecode3 = SWIG_AsVal_int(obj2, &val3);
+ if (!SWIG_IsOK(ecode3)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "new_Tdb" "', argument " "3"" of type '" "int""'");
+ }
+ arg3 = (int)(val3);
+ }
+ if (obj3) {
+ ecode4 = SWIG_AsVal_int(obj3, &val4);
+ if (!SWIG_IsOK(ecode4)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "new_Tdb" "', argument " "4"" of type '" "int""'");
+ }
+ arg4 = (int)(val4);
+ }
+ if (obj4) {
+ ecode5 = SWIG_AsVal_int(obj4, &val5);
+ if (!SWIG_IsOK(ecode5)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "new_Tdb" "', argument " "5"" of type '" "mode_t""'");
+ }
+ arg5 = (mode_t)(val5);
+ }
+ result = (tdb *)new_tdb((char const *)arg1,arg2,arg3,arg4,arg5);
+ /* Throw an IOError exception from errno if tdb_open() returns NULL */
+ if (result == NULL) {
+ PyErr_SetFromErrno(PyExc_IOError);
+ SWIG_fail;
+ }
+ resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_tdb_context, 0);
+ if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+ return resultobj;
+fail:
+ if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_error(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ enum TDB_ERROR result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_error" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = (enum TDB_ERROR)tdb_error(arg1);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_delete_Tdb(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, SWIG_POINTER_DISOWN | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Tdb" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ delete_tdb(arg1);
+
+ resultobj = SWIG_Py_Void();
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_close(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ int result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_close" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = (int)tdb_close(arg1);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_append(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ TDB_DATA arg2 ;
+ TDB_DATA arg3 ;
+ int result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ PyObject * obj2 = 0 ;
+ char * kwnames[] = {
+ (char *) "self",(char *) "key",(char *) "new_dbuf", NULL
+ };
+
+ if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO:Tdb_append",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
+ res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_append" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ if (obj1 == Py_None) {
+ (&arg2)->dsize = 0;
+ (&arg2)->dptr = NULL;
+ } else if (!PyString_Check(obj1)) {
+ PyErr_SetString(PyExc_TypeError, "string arg expected");
+ return NULL;
+ } else {
+ (&arg2)->dsize = PyString_Size(obj1);
+ (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1);
+ }
+ if (obj2 == Py_None) {
+ (&arg3)->dsize = 0;
+ (&arg3)->dptr = NULL;
+ } else if (!PyString_Check(obj2)) {
+ PyErr_SetString(PyExc_TypeError, "string arg expected");
+ return NULL;
+ } else {
+ (&arg3)->dsize = PyString_Size(obj2);
+ (&arg3)->dptr = (uint8_t *)PyString_AsString(obj2);
+ }
+ result = (int)tdb_append(arg1,arg2,arg3);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_errorstr(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ char *result = 0 ;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_errorstr" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = (char *)tdb_errorstr(arg1);
+ resultobj = SWIG_FromCharPtr((const char *)result);
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ TDB_DATA arg2 ;
+ TDB_DATA result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ char * kwnames[] = {
+ (char *) "self",(char *) "key", NULL
+ };
+
+ if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Tdb_get",kwnames,&obj0,&obj1)) SWIG_fail;
+ res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_get" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ if (obj1 == Py_None) {
+ (&arg2)->dsize = 0;
+ (&arg2)->dptr = NULL;
+ } else if (!PyString_Check(obj1)) {
+ PyErr_SetString(PyExc_TypeError, "string arg expected");
+ return NULL;
+ } else {
+ (&arg2)->dsize = PyString_Size(obj1);
+ (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1);
+ }
+ result = tdb_fetch(arg1,arg2);
+ if ((&result)->dptr == NULL && (&result)->dsize == 0) {
+ resultobj = Py_None;
+ } else {
+ resultobj = PyString_FromStringAndSize((const char *)(&result)->dptr, (&result)->dsize);
+ free((&result)->dptr);
+ }
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_delete(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ TDB_DATA arg2 ;
+ int result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ char * kwnames[] = {
+ (char *) "self",(char *) "key", NULL
+ };
+
+ if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Tdb_delete",kwnames,&obj0,&obj1)) SWIG_fail;
+ res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_delete" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ if (obj1 == Py_None) {
+ (&arg2)->dsize = 0;
+ (&arg2)->dptr = NULL;
+ } else if (!PyString_Check(obj1)) {
+ PyErr_SetString(PyExc_TypeError, "string arg expected");
+ return NULL;
+ } else {
+ (&arg2)->dsize = PyString_Size(obj1);
+ (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1);
+ }
+ result = (int)tdb_delete(arg1,arg2);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_store(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ TDB_DATA arg2 ;
+ TDB_DATA arg3 ;
+ int arg4 ;
+ int result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ int val4 ;
+ int ecode4 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ PyObject * obj2 = 0 ;
+ PyObject * obj3 = 0 ;
+ char * kwnames[] = {
+ (char *) "self",(char *) "key",(char *) "dbuf",(char *) "flag", NULL
+ };
+
+ arg4 = TDB_REPLACE;
+ if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|O:Tdb_store",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+ res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_store" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ if (obj1 == Py_None) {
+ (&arg2)->dsize = 0;
+ (&arg2)->dptr = NULL;
+ } else if (!PyString_Check(obj1)) {
+ PyErr_SetString(PyExc_TypeError, "string arg expected");
+ return NULL;
+ } else {
+ (&arg2)->dsize = PyString_Size(obj1);
+ (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1);
+ }
+ if (obj2 == Py_None) {
+ (&arg3)->dsize = 0;
+ (&arg3)->dptr = NULL;
+ } else if (!PyString_Check(obj2)) {
+ PyErr_SetString(PyExc_TypeError, "string arg expected");
+ return NULL;
+ } else {
+ (&arg3)->dsize = PyString_Size(obj2);
+ (&arg3)->dptr = (uint8_t *)PyString_AsString(obj2);
+ }
+ if (obj3) {
+ ecode4 = SWIG_AsVal_int(obj3, &val4);
+ if (!SWIG_IsOK(ecode4)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Tdb_store" "', argument " "4"" of type '" "int""'");
+ }
+ arg4 = (int)(val4);
+ }
+ result = (int)tdb_store(arg1,arg2,arg3,arg4);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_exists(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ TDB_DATA arg2 ;
+ int result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ char * kwnames[] = {
+ (char *) "self",(char *) "key", NULL
+ };
+
+ if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Tdb_exists",kwnames,&obj0,&obj1)) SWIG_fail;
+ res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_exists" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ if (obj1 == Py_None) {
+ (&arg2)->dsize = 0;
+ (&arg2)->dptr = NULL;
+ } else if (!PyString_Check(obj1)) {
+ PyErr_SetString(PyExc_TypeError, "string arg expected");
+ return NULL;
+ } else {
+ (&arg2)->dsize = PyString_Size(obj1);
+ (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1);
+ }
+ result = (int)tdb_exists(arg1,arg2);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_firstkey(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ TDB_DATA result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_firstkey" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = tdb_firstkey(arg1);
+ if ((&result)->dptr == NULL && (&result)->dsize == 0) {
+ resultobj = Py_None;
+ } else {
+ resultobj = PyString_FromStringAndSize((const char *)(&result)->dptr, (&result)->dsize);
+ free((&result)->dptr);
+ }
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_nextkey(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ TDB_DATA arg2 ;
+ TDB_DATA result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ char * kwnames[] = {
+ (char *) "self",(char *) "key", NULL
+ };
+
+ if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Tdb_nextkey",kwnames,&obj0,&obj1)) SWIG_fail;
+ res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_nextkey" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ if (obj1 == Py_None) {
+ (&arg2)->dsize = 0;
+ (&arg2)->dptr = NULL;
+ } else if (!PyString_Check(obj1)) {
+ PyErr_SetString(PyExc_TypeError, "string arg expected");
+ return NULL;
+ } else {
+ (&arg2)->dsize = PyString_Size(obj1);
+ (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1);
+ }
+ result = tdb_nextkey(arg1,arg2);
+ if ((&result)->dptr == NULL && (&result)->dsize == 0) {
+ resultobj = Py_None;
+ } else {
+ resultobj = PyString_FromStringAndSize((const char *)(&result)->dptr, (&result)->dsize);
+ free((&result)->dptr);
+ }
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_lock_all(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ int result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_lock_all" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = (int)tdb_lockall(arg1);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_unlock_all(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ int result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_unlock_all" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = (int)tdb_unlockall(arg1);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_read_lock_all(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ int result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_read_lock_all" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = (int)tdb_lockall_read(arg1);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_read_unlock_all(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ int result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_read_unlock_all" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = (int)tdb_unlockall_read(arg1);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_reopen(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ int result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_reopen" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = (int)tdb_reopen(arg1);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_transaction_start(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ int result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_transaction_start" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = (int)tdb_transaction_start(arg1);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_transaction_commit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ int result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_transaction_commit" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = (int)tdb_transaction_commit(arg1);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_transaction_cancel(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ int result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_transaction_cancel" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = (int)tdb_transaction_cancel(arg1);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_transaction_recover(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ int result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_transaction_recover" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = (int)tdb_transaction_recover(arg1);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_hash_size(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ int result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_hash_size" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = (int)tdb_hash_size(arg1);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_map_size(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ size_t result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_map_size" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = tdb_map_size(arg1);
+ resultobj = SWIG_From_size_t((size_t)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_get_flags(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ int result;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_get_flags" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = (int)tdb_get_flags(arg1);
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_set_max_dead(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ int arg2 ;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ int val2 ;
+ int ecode2 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ char * kwnames[] = {
+ (char *) "self",(char *) "max_dead", NULL
+ };
+
+ if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Tdb_set_max_dead",kwnames,&obj0,&obj1)) SWIG_fail;
+ res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_set_max_dead" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ ecode2 = SWIG_AsVal_int(obj1, &val2);
+ if (!SWIG_IsOK(ecode2)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Tdb_set_max_dead" "', argument " "2"" of type '" "int""'");
+ }
+ arg2 = (int)(val2);
+ tdb_set_max_dead(arg1,arg2);
+ resultobj = SWIG_Py_Void();
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Tdb_name(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ tdb *arg1 = (tdb *) 0 ;
+ char *result = 0 ;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ PyObject *swig_obj[1] ;
+
+ if (!args) SWIG_fail;
+ swig_obj[0] = args;
+ res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_name" "', argument " "1"" of type '" "tdb *""'");
+ }
+ arg1 = (tdb *)(argp1);
+ result = (char *)tdb_name(arg1);
+ resultobj = SWIG_FromCharPtr((const char *)result);
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *Tdb_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *obj;
+ if (!SWIG_Python_UnpackTuple(args,(char*)"swigregister", 1, 1,&obj)) return NULL;
+ SWIG_TypeNewClientData(SWIGTYPE_p_tdb_context, SWIG_NewClientData(obj));
+ return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject *Tdb_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ return SWIG_Python_InitShadowInstance(args);
+}
+
+static PyMethodDef SwigMethods[] = {
+ { (char *)"new_Tdb", (PyCFunction) _wrap_new_Tdb, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
+ "S.__init__(name,hash_size=0,tdb_flags=TDB_DEFAULT,flags=O_RDWR,mode=0600)\n"
+ "Open a TDB file.\n"
+ ""},
+ { (char *)"Tdb_error", (PyCFunction)_wrap_Tdb_error, METH_O, (char *)"\n"
+ "S.error() -> int\n"
+ "Find last error number returned by operation on this TDB.\n"
+ ""},
+ { (char *)"delete_Tdb", (PyCFunction)_wrap_delete_Tdb, METH_O, NULL},
+ { (char *)"Tdb_close", (PyCFunction)_wrap_Tdb_close, METH_O, (char *)"\n"
+ "S.close() -> None\n"
+ "Close the TDB file.\n"
+ ""},
+ { (char *)"Tdb_append", (PyCFunction) _wrap_Tdb_append, METH_VARARGS | METH_KEYWORDS, NULL},
+ { (char *)"Tdb_errorstr", (PyCFunction)_wrap_Tdb_errorstr, METH_O, (char *)"\n"
+ "S.errorstr() -> errorstring\n"
+ "Obtain last error message.\n"
+ ""},
+ { (char *)"Tdb_get", (PyCFunction) _wrap_Tdb_get, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
+ "S.fetch(key) -> value\n"
+ "Fetch a value.\n"
+ ""},
+ { (char *)"Tdb_delete", (PyCFunction) _wrap_Tdb_delete, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
+ "S.delete(key) -> None\n"
+ "Delete an entry.\n"
+ ""},
+ { (char *)"Tdb_store", (PyCFunction) _wrap_Tdb_store, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
+ "S.store(key, value, flag=TDB_REPLACE) -> None\n"
+ "Store an entry.\n"
+ ""},
+ { (char *)"Tdb_exists", (PyCFunction) _wrap_Tdb_exists, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
+ "S.exists(key) -> bool\n"
+ "Check whether key exists in this database.\n"
+ ""},
+ { (char *)"Tdb_firstkey", (PyCFunction)_wrap_Tdb_firstkey, METH_O, (char *)"\n"
+ "S.firstkey() -> data\n"
+ "Return the first key in this database.\n"
+ ""},
+ { (char *)"Tdb_nextkey", (PyCFunction) _wrap_Tdb_nextkey, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
+ "S.nextkey(prev) -> data\n"
+ "Return the next key in this database.\n"
+ ""},
+ { (char *)"Tdb_lock_all", (PyCFunction)_wrap_Tdb_lock_all, METH_O, (char *)"S.lockall() -> bool"},
+ { (char *)"Tdb_unlock_all", (PyCFunction)_wrap_Tdb_unlock_all, METH_O, (char *)"S.unlockall() -> bool"},
+ { (char *)"Tdb_read_lock_all", (PyCFunction)_wrap_Tdb_read_lock_all, METH_O, NULL},
+ { (char *)"Tdb_read_unlock_all", (PyCFunction)_wrap_Tdb_read_unlock_all, METH_O, NULL},
+ { (char *)"Tdb_reopen", (PyCFunction)_wrap_Tdb_reopen, METH_O, (char *)"\n"
+ "S.reopen() -> bool\n"
+ "Reopen this file.\n"
+ ""},
+ { (char *)"Tdb_transaction_start", (PyCFunction)_wrap_Tdb_transaction_start, METH_O, (char *)"\n"
+ "S.transaction_start() -> None\n"
+ "Start a new transaction.\n"
+ ""},
+ { (char *)"Tdb_transaction_commit", (PyCFunction)_wrap_Tdb_transaction_commit, METH_O, (char *)"\n"
+ "S.transaction_commit() -> None\n"
+ "Commit the currently active transaction.\n"
+ ""},
+ { (char *)"Tdb_transaction_cancel", (PyCFunction)_wrap_Tdb_transaction_cancel, METH_O, (char *)"\n"
+ "S.transaction_cancel() -> None\n"
+ "Cancel the currently active transaction.\n"
+ ""},
+ { (char *)"Tdb_transaction_recover", (PyCFunction)_wrap_Tdb_transaction_recover, METH_O, NULL},
+ { (char *)"Tdb_hash_size", (PyCFunction)_wrap_Tdb_hash_size, METH_O, (char *)"S.hash_size() -> int"},
+ { (char *)"Tdb_map_size", (PyCFunction)_wrap_Tdb_map_size, METH_O, (char *)"S.map_size() -> int"},
+ { (char *)"Tdb_get_flags", (PyCFunction)_wrap_Tdb_get_flags, METH_O, (char *)"S.get_flags() -> int"},
+ { (char *)"Tdb_set_max_dead", (PyCFunction) _wrap_Tdb_set_max_dead, METH_VARARGS | METH_KEYWORDS, (char *)"S.set_max_dead(int) -> None"},
+ { (char *)"Tdb_name", (PyCFunction)_wrap_Tdb_name, METH_O, (char *)"\n"
+ "S.name() -> path\n"
+ "Return filename of this TDB file.\n"
+ ""},
+ { (char *)"Tdb_swigregister", Tdb_swigregister, METH_VARARGS, NULL},
+ { (char *)"Tdb_swiginit", Tdb_swiginit, METH_VARARGS, NULL},
+ { NULL, NULL, 0, NULL }
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
+
+static swig_type_info _swigt__p_TDB_DATA = {"_p_TDB_DATA", "TDB_DATA *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_int = {"_p_int", "intptr_t *|int *|int_least32_t *|int_fast32_t *|int32_t *|int_fast16_t *|mode_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_long_long = {"_p_long_long", "int_least64_t *|int_fast64_t *|int64_t *|long long *|intmax_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_short = {"_p_short", "short *|int_least16_t *|int16_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_signed_char = {"_p_signed_char", "signed char *|int_least8_t *|int_fast8_t *|int8_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_tdb_context = {"_p_tdb_context", "struct tdb_context *|tdb *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "unsigned char *|uint_least8_t *|uint_fast8_t *|uint8_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_unsigned_int = {"_p_unsigned_int", "uintptr_t *|uint_least32_t *|uint_fast32_t *|uint32_t *|unsigned int *|uint_fast16_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_unsigned_long_long = {"_p_unsigned_long_long", "uint_least64_t *|uint_fast64_t *|uint64_t *|unsigned long long *|uintmax_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_unsigned_short = {"_p_unsigned_short", "unsigned short *|uint_least16_t *|uint16_t *", 0, 0, (void*)0, 0};
+
+static swig_type_info *swig_type_initial[] = {
+ &_swigt__p_TDB_DATA,
+ &_swigt__p_char,
+ &_swigt__p_int,
+ &_swigt__p_long_long,
+ &_swigt__p_short,
+ &_swigt__p_signed_char,
+ &_swigt__p_tdb_context,
+ &_swigt__p_unsigned_char,
+ &_swigt__p_unsigned_int,
+ &_swigt__p_unsigned_long_long,
+ &_swigt__p_unsigned_short,
+};
+
+static swig_cast_info _swigc__p_TDB_DATA[] = { {&_swigt__p_TDB_DATA, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_char[] = { {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_int[] = { {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_long_long[] = { {&_swigt__p_long_long, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_short[] = { {&_swigt__p_short, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_signed_char[] = { {&_swigt__p_signed_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_tdb_context[] = { {&_swigt__p_tdb_context, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_unsigned_char[] = { {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_unsigned_int[] = { {&_swigt__p_unsigned_int, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_unsigned_long_long[] = { {&_swigt__p_unsigned_long_long, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_unsigned_short[] = { {&_swigt__p_unsigned_short, 0, 0, 0},{0, 0, 0, 0}};
+
+static swig_cast_info *swig_cast_initial[] = {
+ _swigc__p_TDB_DATA,
+ _swigc__p_char,
+ _swigc__p_int,
+ _swigc__p_long_long,
+ _swigc__p_short,
+ _swigc__p_signed_char,
+ _swigc__p_tdb_context,
+ _swigc__p_unsigned_char,
+ _swigc__p_unsigned_int,
+ _swigc__p_unsigned_long_long,
+ _swigc__p_unsigned_short,
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
+
+static swig_const_info swig_const_table[] = {
+{0, 0, 0, 0.0, 0, 0}};
+
+#ifdef __cplusplus
+}
+#endif
+/* -----------------------------------------------------------------------------
+ * Type initialization:
+ * This problem is tough by the requirement that no dynamic
+ * memory is used. Also, since swig_type_info structures store pointers to
+ * swig_cast_info structures and swig_cast_info structures store pointers back
+ * to swig_type_info structures, we need some lookup code at initialization.
+ * The idea is that swig generates all the structures that are needed.
+ * The runtime then collects these partially filled structures.
+ * The SWIG_InitializeModule function takes these initial arrays out of
+ * swig_module, and does all the lookup, filling in the swig_module.types
+ * array with the correct data and linking the correct swig_cast_info
+ * structures together.
+ *
+ * The generated swig_type_info structures are assigned staticly to an initial
+ * array. We just loop through that array, and handle each type individually.
+ * First we lookup if this type has been already loaded, and if so, use the
+ * loaded structure instead of the generated one. Then we have to fill in the
+ * cast linked list. The cast data is initially stored in something like a
+ * two-dimensional array. Each row corresponds to a type (there are the same
+ * number of rows as there are in the swig_type_initial array). Each entry in
+ * a column is one of the swig_cast_info structures for that type.
+ * The cast_initial array is actually an array of arrays, because each row has
+ * a variable number of columns. So to actually build the cast linked list,
+ * we find the array of casts associated with the type, and loop through it
+ * adding the casts to the list. The one last trick we need to do is making
+ * sure the type pointer in the swig_cast_info struct is correct.
+ *
+ * First off, we lookup the cast->type name to see if it is already loaded.
+ * There are three cases to handle:
+ * 1) If the cast->type has already been loaded AND the type we are adding
+ * casting info to has not been loaded (it is in this module), THEN we
+ * replace the cast->type pointer with the type pointer that has already
+ * been loaded.
+ * 2) If BOTH types (the one we are adding casting info to, and the
+ * cast->type) are loaded, THEN the cast info has already been loaded by
+ * the previous module so we just ignore it.
+ * 3) Finally, if cast->type has not already been loaded, then we add that
+ * swig_cast_info to the linked list (because the cast->type) pointer will
+ * be correct.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} /* c-mode */
+#endif
+#endif
+
+#if 0
+#define SWIGRUNTIME_DEBUG
+#endif
+
+
+SWIGRUNTIME void
+SWIG_InitializeModule(void *clientdata) {
+ size_t i;
+ swig_module_info *module_head, *iter;
+ int found, init;
+
+ clientdata = clientdata;
+
+ /* check to see if the circular list has been setup, if not, set it up */
+ if (swig_module.next==0) {
+ /* Initialize the swig_module */
+ swig_module.type_initial = swig_type_initial;
+ swig_module.cast_initial = swig_cast_initial;
+ swig_module.next = &swig_module;
+ init = 1;
+ } else {
+ init = 0;
+ }
+
+ /* Try and load any already created modules */
+ module_head = SWIG_GetModule(clientdata);
+ if (!module_head) {
+ /* This is the first module loaded for this interpreter */
+ /* so set the swig module into the interpreter */
+ SWIG_SetModule(clientdata, &swig_module);
+ module_head = &swig_module;
+ } else {
+ /* the interpreter has loaded a SWIG module, but has it loaded this one? */
+ found=0;
+ iter=module_head;
+ do {
+ if (iter==&swig_module) {
+ found=1;
+ break;
+ }
+ iter=iter->next;
+ } while (iter!= module_head);
+
+ /* if the is found in the list, then all is done and we may leave */
+ if (found) return;
+ /* otherwise we must add out module into the list */
+ swig_module.next = module_head->next;
+ module_head->next = &swig_module;
+ }
+
+ /* When multiple interpeters are used, a module could have already been initialized in
+ a different interpreter, but not yet have a pointer in this interpreter.
+ In this case, we do not want to continue adding types... everything should be
+ set up already */
+ if (init == 0) return;
+
+ /* Now work on filling in swig_module.types */
+#ifdef SWIGRUNTIME_DEBUG
+ printf("SWIG_InitializeModule: size %d\n", swig_module.size);
+#endif
+ for (i = 0; i < swig_module.size; ++i) {
+ swig_type_info *type = 0;
+ swig_type_info *ret;
+ swig_cast_info *cast;
+
+#ifdef SWIGRUNTIME_DEBUG
+ printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+#endif
+
+ /* if there is another module already loaded */
+ if (swig_module.next != &swig_module) {
+ type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name);
+ }
+ if (type) {
+ /* Overwrite clientdata field */
+#ifdef SWIGRUNTIME_DEBUG
+ printf("SWIG_InitializeModule: found type %s\n", type->name);
+#endif
+ if (swig_module.type_initial[i]->clientdata) {
+ type->clientdata = swig_module.type_initial[i]->clientdata;
+#ifdef SWIGRUNTIME_DEBUG
+ printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name);
+#endif
+ }
+ } else {
+ type = swig_module.type_initial[i];
+ }
+
+ /* Insert casting types */
+ cast = swig_module.cast_initial[i];
+ while (cast->type) {
+ /* Don't need to add information already in the list */
+ ret = 0;
+#ifdef SWIGRUNTIME_DEBUG
+ printf("SWIG_InitializeModule: look cast %s\n", cast->type->name);
+#endif
+ if (swig_module.next != &swig_module) {
+ ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name);
+#ifdef SWIGRUNTIME_DEBUG
+ if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name);
+#endif
+ }
+ if (ret) {
+ if (type == swig_module.type_initial[i]) {
+#ifdef SWIGRUNTIME_DEBUG
+ printf("SWIG_InitializeModule: skip old type %s\n", ret->name);
+#endif
+ cast->type = ret;
+ ret = 0;
+ } else {
+ /* Check for casting already in the list */
+ swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type);
+#ifdef SWIGRUNTIME_DEBUG
+ if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name);
+#endif
+ if (!ocast) ret = 0;
+ }
+ }
+
+ if (!ret) {
+#ifdef SWIGRUNTIME_DEBUG
+ printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name);
+#endif
+ if (type->cast) {
+ type->cast->prev = cast;
+ cast->next = type->cast;
+ }
+ type->cast = cast;
+ }
+ cast++;
+ }
+ /* Set entry in modules->types array equal to the type */
+ swig_module.types[i] = type;
+ }
+ swig_module.types[i] = 0;
+
+#ifdef SWIGRUNTIME_DEBUG
+ printf("**** SWIG_InitializeModule: Cast List ******\n");
+ for (i = 0; i < swig_module.size; ++i) {
+ int j = 0;
+ swig_cast_info *cast = swig_module.cast_initial[i];
+ printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+ while (cast->type) {
+ printf("SWIG_InitializeModule: cast type %s\n", cast->type->name);
+ cast++;
+ ++j;
+ }
+ printf("---- Total casts: %d\n",j);
+ }
+ printf("**** SWIG_InitializeModule: Cast List ******\n");
+#endif
+}
+
+/* This function will propagate the clientdata field of type to
+* any new swig_type_info structures that have been added into the list
+* of equivalent types. It is like calling
+* SWIG_TypeClientData(type, clientdata) a second time.
+*/
+SWIGRUNTIME void
+SWIG_PropagateClientData(void) {
+ size_t i;
+ swig_cast_info *equiv;
+ static int init_run = 0;
+
+ if (init_run) return;
+ init_run = 1;
+
+ for (i = 0; i < swig_module.size; i++) {
+ if (swig_module.types[i]->clientdata) {
+ equiv = swig_module.types[i]->cast;
+ while (equiv) {
+ if (!equiv->converter) {
+ if (equiv->type && !equiv->type->clientdata)
+ SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata);
+ }
+ equiv = equiv->next;
+ }
+ }
+ }
+}
+
+#ifdef __cplusplus
+#if 0
+{
+ /* c-mode */
+#endif
+}
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /* Python-specific SWIG API */
+#define SWIG_newvarlink() SWIG_Python_newvarlink()
+#define SWIG_addvarlink(p, name, get_attr, set_attr) SWIG_Python_addvarlink(p, name, get_attr, set_attr)
+#define SWIG_InstallConstants(d, constants) SWIG_Python_InstallConstants(d, constants)
+
+ /* -----------------------------------------------------------------------------
+ * global variable support code.
+ * ----------------------------------------------------------------------------- */
+
+ typedef struct swig_globalvar {
+ char *name; /* Name of global variable */
+ PyObject *(*get_attr)(void); /* Return the current value */
+ int (*set_attr)(PyObject *); /* Set the value */
+ struct swig_globalvar *next;
+ } swig_globalvar;
+
+ typedef struct swig_varlinkobject {
+ PyObject_HEAD
+ swig_globalvar *vars;
+ } swig_varlinkobject;
+
+ SWIGINTERN PyObject *
+ swig_varlink_repr(swig_varlinkobject *SWIGUNUSEDPARM(v)) {
+ return PyString_FromString("<Swig global variables>");
+ }
+
+ SWIGINTERN PyObject *
+ swig_varlink_str(swig_varlinkobject *v) {
+ PyObject *str = PyString_FromString("(");
+ swig_globalvar *var;
+ for (var = v->vars; var; var=var->next) {
+ PyString_ConcatAndDel(&str,PyString_FromString(var->name));
+ if (var->next) PyString_ConcatAndDel(&str,PyString_FromString(", "));
+ }
+ PyString_ConcatAndDel(&str,PyString_FromString(")"));
+ return str;
+ }
+
+ SWIGINTERN int
+ swig_varlink_print(swig_varlinkobject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) {
+ PyObject *str = swig_varlink_str(v);
+ fprintf(fp,"Swig global variables ");
+ fprintf(fp,"%s\n", PyString_AsString(str));
+ Py_DECREF(str);
+ return 0;
+ }
+
+ SWIGINTERN void
+ swig_varlink_dealloc(swig_varlinkobject *v) {
+ swig_globalvar *var = v->vars;
+ while (var) {
+ swig_globalvar *n = var->next;
+ free(var->name);
+ free(var);
+ var = n;
+ }
+ }
+
+ SWIGINTERN PyObject *
+ swig_varlink_getattr(swig_varlinkobject *v, char *n) {
+ PyObject *res = NULL;
+ swig_globalvar *var = v->vars;
+ while (var) {
+ if (strcmp(var->name,n) == 0) {
+ res = (*var->get_attr)();
+ break;
+ }
+ var = var->next;
+ }
+ if (res == NULL && !PyErr_Occurred()) {
+ PyErr_SetString(PyExc_NameError,"Unknown C global variable");
+ }
+ return res;
+ }
+
+ SWIGINTERN int
+ swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) {
+ int res = 1;
+ swig_globalvar *var = v->vars;
+ while (var) {
+ if (strcmp(var->name,n) == 0) {
+ res = (*var->set_attr)(p);
+ break;
+ }
+ var = var->next;
+ }
+ if (res == 1 && !PyErr_Occurred()) {
+ PyErr_SetString(PyExc_NameError,"Unknown C global variable");
+ }
+ return res;
+ }
+
+ SWIGINTERN PyTypeObject*
+ swig_varlink_type(void) {
+ static char varlink__doc__[] = "Swig var link object";
+ static PyTypeObject varlink_type;
+ static int type_init = 0;
+ if (!type_init) {
+ const PyTypeObject tmp
+ = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* Number of items in variable part (ob_size) */
+ (char *)"swigvarlink", /* Type name (tp_name) */
+ sizeof(swig_varlinkobject), /* Basic size (tp_basicsize) */
+ 0, /* Itemsize (tp_itemsize) */
+ (destructor) swig_varlink_dealloc, /* Deallocator (tp_dealloc) */
+ (printfunc) swig_varlink_print, /* Print (tp_print) */
+ (getattrfunc) swig_varlink_getattr, /* get attr (tp_getattr) */
+ (setattrfunc) swig_varlink_setattr, /* Set attr (tp_setattr) */
+ 0, /* tp_compare */
+ (reprfunc) swig_varlink_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ (reprfunc)swig_varlink_str, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ 0, /* tp_flags */
+ varlink__doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+#if PY_VERSION_HEX >= 0x02020000
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* tp_iter -> tp_weaklist */
+#endif
+#if PY_VERSION_HEX >= 0x02030000
+ 0, /* tp_del */
+#endif
+#ifdef COUNT_ALLOCS
+ 0,0,0,0 /* tp_alloc -> tp_next */
+#endif
+ };
+ varlink_type = tmp;
+ varlink_type.ob_type = &PyType_Type;
+ type_init = 1;
+ }
+ return &varlink_type;
+ }
+
+ /* Create a variable linking object for use later */
+ SWIGINTERN PyObject *
+ SWIG_Python_newvarlink(void) {
+ swig_varlinkobject *result = PyObject_NEW(swig_varlinkobject, swig_varlink_type());
+ if (result) {
+ result->vars = 0;
+ }
+ return ((PyObject*) result);
+ }
+
+ SWIGINTERN void
+ SWIG_Python_addvarlink(PyObject *p, char *name, PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) {
+ swig_varlinkobject *v = (swig_varlinkobject *) p;
+ swig_globalvar *gv = (swig_globalvar *) malloc(sizeof(swig_globalvar));
+ if (gv) {
+ size_t size = strlen(name)+1;
+ gv->name = (char *)malloc(size);
+ if (gv->name) {
+ strncpy(gv->name,name,size);
+ gv->get_attr = get_attr;
+ gv->set_attr = set_attr;
+ gv->next = v->vars;
+ }
+ }
+ v->vars = gv;
+ }
+
+ SWIGINTERN PyObject *
+ SWIG_globals(void) {
+ static PyObject *_SWIG_globals = 0;
+ if (!_SWIG_globals) _SWIG_globals = SWIG_newvarlink();
+ return _SWIG_globals;
+ }
+
+ /* -----------------------------------------------------------------------------
+ * constants/methods manipulation
+ * ----------------------------------------------------------------------------- */
+
+ /* Install Constants */
+ SWIGINTERN void
+ SWIG_Python_InstallConstants(PyObject *d, swig_const_info constants[]) {
+ PyObject *obj = 0;
+ size_t i;
+ for (i = 0; constants[i].type; ++i) {
+ switch(constants[i].type) {
+ case SWIG_PY_POINTER:
+ obj = SWIG_NewPointerObj(constants[i].pvalue, *(constants[i]).ptype,0);
+ break;
+ case SWIG_PY_BINARY:
+ obj = SWIG_NewPackedObj(constants[i].pvalue, constants[i].lvalue, *(constants[i].ptype));
+ break;
+ default:
+ obj = 0;
+ break;
+ }
+ if (obj) {
+ PyDict_SetItemString(d, constants[i].name, obj);
+ Py_DECREF(obj);
+ }
+ }
+ }
+
+ /* -----------------------------------------------------------------------------*/
+ /* Fix SwigMethods to carry the callback ptrs when needed */
+ /* -----------------------------------------------------------------------------*/
+
+ SWIGINTERN void
+ SWIG_Python_FixMethods(PyMethodDef *methods,
+ swig_const_info *const_table,
+ swig_type_info **types,
+ swig_type_info **types_initial) {
+ size_t i;
+ for (i = 0; methods[i].ml_name; ++i) {
+ const char *c = methods[i].ml_doc;
+ if (c && (c = strstr(c, "swig_ptr: "))) {
+ int j;
+ swig_const_info *ci = 0;
+ const char *name = c + 10;
+ for (j = 0; const_table[j].type; ++j) {
+ if (strncmp(const_table[j].name, name,
+ strlen(const_table[j].name)) == 0) {
+ ci = &(const_table[j]);
+ break;
+ }
+ }
+ if (ci) {
+ size_t shift = (ci->ptype) - types;
+ swig_type_info *ty = types_initial[shift];
+ size_t ldoc = (c - methods[i].ml_doc);
+ size_t lptr = strlen(ty->name)+2*sizeof(void*)+2;
+ char *ndoc = (char*)malloc(ldoc + lptr + 10);
+ if (ndoc) {
+ char *buff = ndoc;
+ void *ptr = (ci->type == SWIG_PY_POINTER) ? ci->pvalue : 0;
+ if (ptr) {
+ strncpy(buff, methods[i].ml_doc, ldoc);
+ buff += ldoc;
+ strncpy(buff, "swig_ptr: ", 10);
+ buff += 10;
+ SWIG_PackVoidPtr(buff, ptr, ty->name, lptr);
+ methods[i].ml_doc = ndoc;
+ }
+ }
+ }
+ }
+ }
+ }
+
+#ifdef __cplusplus
+}
+#endif
+
+/* -----------------------------------------------------------------------------*
+ * Partial Init method
+ * -----------------------------------------------------------------------------*/
+
+#ifdef __cplusplus
+extern "C"
+#endif
+SWIGEXPORT void SWIG_init(void) {
+ PyObject *m, *d;
+
+ /* Fix SwigMethods to carry the callback ptrs when needed */
+ SWIG_Python_FixMethods(SwigMethods, swig_const_table, swig_types, swig_type_initial);
+
+ m = Py_InitModule((char *) SWIG_name, SwigMethods);
+ d = PyModule_GetDict(m);
+
+ SWIG_InitializeModule(0);
+ SWIG_InstallConstants(d,swig_const_table);
+
+
+ SWIG_Python_SetConstant(d, "REPLACE",SWIG_From_int((int)(TDB_REPLACE)));
+ SWIG_Python_SetConstant(d, "INSERT",SWIG_From_int((int)(TDB_INSERT)));
+ SWIG_Python_SetConstant(d, "MODIFY",SWIG_From_int((int)(TDB_MODIFY)));
+ SWIG_Python_SetConstant(d, "DEFAULT",SWIG_From_int((int)(TDB_DEFAULT)));
+ SWIG_Python_SetConstant(d, "CLEAR_IF_FIRST",SWIG_From_int((int)(TDB_CLEAR_IF_FIRST)));
+ SWIG_Python_SetConstant(d, "INTERNAL",SWIG_From_int((int)(TDB_INTERNAL)));
+ SWIG_Python_SetConstant(d, "NOLOCK",SWIG_From_int((int)(TDB_NOLOCK)));
+ SWIG_Python_SetConstant(d, "NOMMAP",SWIG_From_int((int)(TDB_NOMMAP)));
+ SWIG_Python_SetConstant(d, "CONVERT",SWIG_From_int((int)(TDB_CONVERT)));
+ SWIG_Python_SetConstant(d, "BIGENDIAN",SWIG_From_int((int)(TDB_BIGENDIAN)));
+ SWIG_Python_SetConstant(d, "TDB_SUCCESS",SWIG_From_int((int)(TDB_SUCCESS)));
+ SWIG_Python_SetConstant(d, "TDB_ERR_CORRUPT",SWIG_From_int((int)(TDB_ERR_CORRUPT)));
+ SWIG_Python_SetConstant(d, "TDB_ERR_IO",SWIG_From_int((int)(TDB_ERR_IO)));
+ SWIG_Python_SetConstant(d, "TDB_ERR_LOCK",SWIG_From_int((int)(TDB_ERR_LOCK)));
+ SWIG_Python_SetConstant(d, "TDB_ERR_OOM",SWIG_From_int((int)(TDB_ERR_OOM)));
+ SWIG_Python_SetConstant(d, "TDB_ERR_EXISTS",SWIG_From_int((int)(TDB_ERR_EXISTS)));
+ SWIG_Python_SetConstant(d, "TDB_ERR_NOLOCK",SWIG_From_int((int)(TDB_ERR_NOLOCK)));
+ SWIG_Python_SetConstant(d, "TDB_ERR_LOCK_TIMEOUT",SWIG_From_int((int)(TDB_ERR_LOCK_TIMEOUT)));
+ SWIG_Python_SetConstant(d, "TDB_ERR_NOEXIST",SWIG_From_int((int)(TDB_ERR_NOEXIST)));
+ SWIG_Python_SetConstant(d, "TDB_ERR_EINVAL",SWIG_From_int((int)(TDB_ERR_EINVAL)));
+ SWIG_Python_SetConstant(d, "TDB_ERR_RDONLY",SWIG_From_int((int)(TDB_ERR_RDONLY)));
+}
+
diff --git a/source3/lib/tdb/tools/tdbbackup.c b/source3/lib/tdb/tools/tdbbackup.c
new file mode 100644
index 0000000000..6f3ca48314
--- /dev/null
+++ b/source3/lib/tdb/tools/tdbbackup.c
@@ -0,0 +1,300 @@
+/*
+ Unix SMB/CIFS implementation.
+ low level tdb backup and restore utility
+ Copyright (C) Andrew Tridgell 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+
+ This program is meant for backup/restore of tdb databases. Typical usage would be:
+ tdbbackup *.tdb
+ when Samba shuts down cleanly, which will make a backup of all the local databases
+ to *.bak files. Then on Samba startup you would use:
+ tdbbackup -v *.tdb
+ and this will check the databases for corruption and if corruption is detected then
+ the backup will be restored.
+
+ You may also like to do a backup on a regular basis while Samba is
+ running, perhaps using cron.
+
+ The reason this program is needed is to cope with power failures
+ while Samba is running. A power failure could lead to database
+ corruption and Samba will then not start correctly.
+
+ Note that many of the databases in Samba are transient and thus
+ don't need to be backed up, so you can optimise the above a little
+ by only running the backup on the critical databases.
+
+ */
+
+#include "replace.h"
+#include "system/locale.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "tdb.h"
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+static int failed;
+
+static char *add_suffix(const char *name, const char *suffix)
+{
+ char *ret;
+ int len = strlen(name) + strlen(suffix) + 1;
+ ret = (char *)malloc(len);
+ if (!ret) {
+ fprintf(stderr,"Out of memory!\n");
+ exit(1);
+ }
+ snprintf(ret, len, "%s%s", name, suffix);
+ return ret;
+}
+
+static int copy_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ TDB_CONTEXT *tdb_new = (TDB_CONTEXT *)state;
+
+ if (tdb_store(tdb_new, key, dbuf, TDB_INSERT) != 0) {
+ fprintf(stderr,"Failed to insert into %s\n", tdb_name(tdb_new));
+ failed = 1;
+ return 1;
+ }
+ return 0;
+}
+
+
+static int test_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ return 0;
+}
+
+/*
+ carefully backup a tdb, validating the contents and
+ only doing the backup if its OK
+ this function is also used for restore
+*/
+static int backup_tdb(const char *old_name, const char *new_name, int hash_size)
+{
+ TDB_CONTEXT *tdb;
+ TDB_CONTEXT *tdb_new;
+ char *tmp_name;
+ struct stat st;
+ int count1, count2;
+
+ tmp_name = add_suffix(new_name, ".tmp");
+
+ /* stat the old tdb to find its permissions */
+ if (stat(old_name, &st) != 0) {
+ perror(old_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* open the old tdb */
+ tdb = tdb_open(old_name, 0, 0, O_RDWR, 0);
+ if (!tdb) {
+ printf("Failed to open %s\n", old_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* create the new tdb */
+ unlink(tmp_name);
+ tdb_new = tdb_open(tmp_name,
+ hash_size ? hash_size : tdb_hash_size(tdb),
+ TDB_DEFAULT, O_RDWR|O_CREAT|O_EXCL,
+ st.st_mode & 0777);
+ if (!tdb_new) {
+ perror(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* lock the old tdb */
+ if (tdb_lockall(tdb) != 0) {
+ fprintf(stderr,"Failed to lock %s\n", old_name);
+ tdb_close(tdb);
+ tdb_close(tdb_new);
+ unlink(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ failed = 0;
+
+ /* traverse and copy */
+ count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new);
+ if (count1 < 0 || failed) {
+ fprintf(stderr,"failed to copy %s\n", old_name);
+ tdb_close(tdb);
+ tdb_close(tdb_new);
+ unlink(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* close the old tdb */
+ tdb_close(tdb);
+
+ /* close the new tdb and re-open read-only */
+ tdb_close(tdb_new);
+ tdb_new = tdb_open(tmp_name, 0, TDB_DEFAULT, O_RDONLY, 0);
+ if (!tdb_new) {
+ fprintf(stderr,"failed to reopen %s\n", tmp_name);
+ unlink(tmp_name);
+ perror(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* traverse the new tdb to confirm */
+ count2 = tdb_traverse(tdb_new, test_fn, NULL);
+ if (count2 != count1) {
+ fprintf(stderr,"failed to copy %s\n", old_name);
+ tdb_close(tdb_new);
+ unlink(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* make sure the new tdb has reached stable storage */
+ fsync(tdb_fd(tdb_new));
+
+ /* close the new tdb and rename it to .bak */
+ tdb_close(tdb_new);
+ if (rename(tmp_name, new_name) != 0) {
+ perror(new_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ free(tmp_name);
+
+ return 0;
+}
+
+/*
+ verify a tdb and if it is corrupt then restore from *.bak
+*/
+static int verify_tdb(const char *fname, const char *bak_name)
+{
+ TDB_CONTEXT *tdb;
+ int count = -1;
+
+ /* open the tdb */
+ tdb = tdb_open(fname, 0, 0, O_RDONLY, 0);
+
+ /* traverse the tdb, then close it */
+ if (tdb) {
+ count = tdb_traverse(tdb, test_fn, NULL);
+ tdb_close(tdb);
+ }
+
+ /* count is < 0 means an error */
+ if (count < 0) {
+ printf("restoring %s\n", fname);
+ return backup_tdb(bak_name, fname, 0);
+ }
+
+ printf("%s : %d records\n", fname, count);
+
+ return 0;
+}
+
+/*
+ see if one file is newer than another
+*/
+static int file_newer(const char *fname1, const char *fname2)
+{
+ struct stat st1, st2;
+ if (stat(fname1, &st1) != 0) {
+ return 0;
+ }
+ if (stat(fname2, &st2) != 0) {
+ return 1;
+ }
+ return (st1.st_mtime > st2.st_mtime);
+}
+
+static void usage(void)
+{
+ printf("Usage: tdbbackup [options] <fname...>\n\n");
+ printf(" -h this help message\n");
+ printf(" -s suffix set the backup suffix\n");
+ printf(" -v verify mode (restore if corrupt)\n");
+ printf(" -n hashsize set the new hash size for the backup\n");
+}
+
+
+ int main(int argc, char *argv[])
+{
+ int i;
+ int ret = 0;
+ int c;
+ int verify = 0;
+ int hashsize = 0;
+ const char *suffix = ".bak";
+
+ while ((c = getopt(argc, argv, "vhs:n:")) != -1) {
+ switch (c) {
+ case 'h':
+ usage();
+ exit(0);
+ case 'v':
+ verify = 1;
+ break;
+ case 's':
+ suffix = optarg;
+ break;
+ case 'n':
+ hashsize = atoi(optarg);
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ usage();
+ exit(1);
+ }
+
+ for (i=0; i<argc; i++) {
+ const char *fname = argv[i];
+ char *bak_name;
+
+ bak_name = add_suffix(fname, suffix);
+
+ if (verify) {
+ if (verify_tdb(fname, bak_name) != 0) {
+ ret = 1;
+ }
+ } else {
+ if (file_newer(fname, bak_name) &&
+ backup_tdb(fname, bak_name, hashsize) != 0) {
+ ret = 1;
+ }
+ }
+
+ free(bak_name);
+ }
+
+ return ret;
+}
diff --git a/source3/lib/tdb/tools/tdbdump.c b/source3/lib/tdb/tools/tdbdump.c
new file mode 100644
index 0000000000..8d930383b0
--- /dev/null
+++ b/source3/lib/tdb/tools/tdbdump.c
@@ -0,0 +1,116 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple tdb dump util
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/locale.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "tdb.h"
+
+static void print_data(TDB_DATA d)
+{
+ unsigned char *p = (unsigned char *)d.dptr;
+ int len = d.dsize;
+ while (len--) {
+ if (isprint(*p) && !strchr("\"\\", *p)) {
+ fputc(*p, stdout);
+ } else {
+ printf("\\%02X", *p);
+ }
+ p++;
+ }
+}
+
+static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ printf("{\n");
+ printf("key(%d) = \"", (int)key.dsize);
+ print_data(key);
+ printf("\"\n");
+ printf("data(%d) = \"", (int)dbuf.dsize);
+ print_data(dbuf);
+ printf("\"\n");
+ printf("}\n");
+ return 0;
+}
+
+static int dump_tdb(const char *fname, const char *keyname)
+{
+ TDB_CONTEXT *tdb;
+ TDB_DATA key, value;
+
+ tdb = tdb_open(fname, 0, 0, O_RDONLY, 0);
+ if (!tdb) {
+ printf("Failed to open %s\n", fname);
+ return 1;
+ }
+
+ if (!keyname) {
+ tdb_traverse(tdb, traverse_fn, NULL);
+ } else {
+ key.dptr = discard_const_p(uint8_t,keyname);
+ key.dsize = strlen( keyname);
+ value = tdb_fetch(tdb, key);
+ if (!value.dptr) {
+ return 1;
+ } else {
+ print_data(value);
+ free(value.dptr);
+ }
+ }
+
+ return 0;
+}
+
+static void usage( void)
+{
+ printf( "Usage: tdbdump [options] <filename>\n\n");
+ printf( " -h this help message\n");
+ printf( " -k keyname dumps value of keyname\n");
+}
+
+ int main(int argc, char *argv[])
+{
+ char *fname, *keyname=NULL;
+ int c;
+
+ if (argc < 2) {
+ printf("Usage: tdbdump <fname>\n");
+ exit(1);
+ }
+
+ while ((c = getopt( argc, argv, "hk:")) != -1) {
+ switch (c) {
+ case 'h':
+ usage();
+ exit( 0);
+ case 'k':
+ keyname = optarg;
+ break;
+ default:
+ usage();
+ exit( 1);
+ }
+ }
+
+ fname = argv[optind];
+
+ return dump_tdb(fname, keyname);
+}
diff --git a/source3/lib/tdb/tools/tdbtest.c b/source3/lib/tdb/tools/tdbtest.c
new file mode 100644
index 0000000000..416bc50a5b
--- /dev/null
+++ b/source3/lib/tdb/tools/tdbtest.c
@@ -0,0 +1,265 @@
+/* a test program for tdb - the trivial database */
+
+#include "replace.h"
+#include "tdb.h"
+#include "system/filesys.h"
+#include "system/time.h"
+
+#include <gdbm.h>
+
+
+#define DELETE_PROB 7
+#define STORE_PROB 5
+
+static struct tdb_context *db;
+static GDBM_FILE gdbm;
+
+struct timeval tp1,tp2;
+
+static void _start_timer(void)
+{
+ gettimeofday(&tp1,NULL);
+}
+
+static double _end_timer(void)
+{
+ gettimeofday(&tp2,NULL);
+ return((tp2.tv_sec - tp1.tv_sec) +
+ (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
+}
+
+static void fatal(const char *why)
+{
+ perror(why);
+ exit(1);
+}
+
+#ifdef PRINTF_ATTRIBUTE
+static void tdb_log(struct tdb_context *tdb, int level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+static void tdb_log(struct tdb_context *tdb, int level, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vfprintf(stdout, format, ap);
+ va_end(ap);
+ fflush(stdout);
+}
+
+static void compare_db(void)
+{
+ TDB_DATA d, key, nextkey;
+ datum gd, gkey, gnextkey;
+
+ key = tdb_firstkey(db);
+ while (key.dptr) {
+ d = tdb_fetch(db, key);
+ gkey.dptr = key.dptr;
+ gkey.dsize = key.dsize;
+
+ gd = gdbm_fetch(gdbm, gkey);
+
+ if (!gd.dptr) fatal("key not in gdbm");
+ if (gd.dsize != d.dsize) fatal("data sizes differ");
+ if (memcmp(gd.dptr, d.dptr, d.dsize)) {
+ fatal("data differs");
+ }
+
+ nextkey = tdb_nextkey(db, key);
+ free(key.dptr);
+ free(d.dptr);
+ free(gd.dptr);
+ key = nextkey;
+ }
+
+ gkey = gdbm_firstkey(gdbm);
+ while (gkey.dptr) {
+ gd = gdbm_fetch(gdbm, gkey);
+ key.dptr = gkey.dptr;
+ key.dsize = gkey.dsize;
+
+ d = tdb_fetch(db, key);
+
+ if (!d.dptr) fatal("key not in db");
+ if (d.dsize != gd.dsize) fatal("data sizes differ");
+ if (memcmp(d.dptr, gd.dptr, gd.dsize)) {
+ fatal("data differs");
+ }
+
+ gnextkey = gdbm_nextkey(gdbm, gkey);
+ free(gkey.dptr);
+ free(gd.dptr);
+ free(d.dptr);
+ gkey = gnextkey;
+ }
+}
+
+static char *randbuf(int len)
+{
+ char *buf;
+ int i;
+ buf = (char *)malloc(len+1);
+
+ for (i=0;i<len;i++) {
+ buf[i] = 'a' + (rand() % 26);
+ }
+ buf[i] = 0;
+ return buf;
+}
+
+static void addrec_db(void)
+{
+ int klen, dlen;
+ char *k, *d;
+ TDB_DATA key, data;
+
+ klen = 1 + (rand() % 4);
+ dlen = 1 + (rand() % 100);
+
+ k = randbuf(klen);
+ d = randbuf(dlen);
+
+ key.dptr = k;
+ key.dsize = klen+1;
+
+ data.dptr = d;
+ data.dsize = dlen+1;
+
+ if (rand() % DELETE_PROB == 0) {
+ tdb_delete(db, key);
+ } else if (rand() % STORE_PROB == 0) {
+ if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+ fatal("tdb_store failed");
+ }
+ } else {
+ data = tdb_fetch(db, key);
+ if (data.dptr) free(data.dptr);
+ }
+
+ free(k);
+ free(d);
+}
+
+static void addrec_gdbm(void)
+{
+ int klen, dlen;
+ char *k, *d;
+ datum key, data;
+
+ klen = 1 + (rand() % 4);
+ dlen = 1 + (rand() % 100);
+
+ k = randbuf(klen);
+ d = randbuf(dlen);
+
+ key.dptr = k;
+ key.dsize = klen+1;
+
+ data.dptr = d;
+ data.dsize = dlen+1;
+
+ if (rand() % DELETE_PROB == 0) {
+ gdbm_delete(gdbm, key);
+ } else if (rand() % STORE_PROB == 0) {
+ if (gdbm_store(gdbm, key, data, GDBM_REPLACE) != 0) {
+ fatal("gdbm_store failed");
+ }
+ } else {
+ data = gdbm_fetch(gdbm, key);
+ if (data.dptr) free(data.dptr);
+ }
+
+ free(k);
+ free(d);
+}
+
+static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+#if 0
+ printf("[%s] [%s]\n", key.dptr, dbuf.dptr);
+#endif
+ tdb_delete(tdb, key);
+ return 0;
+}
+
+static void merge_test(void)
+{
+ int i;
+ char keys[5][2];
+ char tdata[] = "test";
+ TDB_DATA key, data;
+
+ for (i = 0; i < 5; i++) {
+ snprintf(keys[i],2, "%d", i);
+ key.dptr = keys[i];
+ key.dsize = 2;
+
+ data.dptr = tdata;
+ data.dsize = 4;
+
+ if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+ fatal("tdb_store failed");
+ }
+ }
+
+ key.dptr = keys[0];
+ tdb_delete(db, key);
+ key.dptr = keys[4];
+ tdb_delete(db, key);
+ key.dptr = keys[2];
+ tdb_delete(db, key);
+ key.dptr = keys[1];
+ tdb_delete(db, key);
+ key.dptr = keys[3];
+ tdb_delete(db, key);
+}
+
+ int main(int argc, const char *argv[])
+{
+ int i, seed=0;
+ int loops = 10000;
+ int num_entries;
+ char test_gdbm[] = "test.gdbm";
+
+ unlink("test.gdbm");
+
+ db = tdb_open("test.tdb", 0, TDB_CLEAR_IF_FIRST,
+ O_RDWR | O_CREAT | O_TRUNC, 0600);
+ gdbm = gdbm_open(test_gdbm, 512, GDBM_WRITER|GDBM_NEWDB|GDBM_FAST,
+ 0600, NULL);
+
+ if (!db || !gdbm) {
+ fatal("db open failed");
+ }
+
+#if 1
+ srand(seed);
+ _start_timer();
+ for (i=0;i<loops;i++) addrec_gdbm();
+ printf("gdbm got %.2f ops/sec\n", i/_end_timer());
+#endif
+
+ merge_test();
+
+ srand(seed);
+ _start_timer();
+ for (i=0;i<loops;i++) addrec_db();
+ printf("tdb got %.2f ops/sec\n", i/_end_timer());
+
+ if (tdb_validate_freelist(db, &num_entries) == -1) {
+ printf("tdb freelist is corrupt\n");
+ } else {
+ printf("tdb freelist is good (%d entries)\n", num_entries);
+ }
+
+ compare_db();
+
+ printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL));
+ printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL));
+
+ tdb_close(db);
+ gdbm_close(gdbm);
+
+ return 0;
+}
diff --git a/source3/lib/tdb/tools/tdbtool.c b/source3/lib/tdb/tools/tdbtool.c
new file mode 100644
index 0000000000..d104ccd7c4
--- /dev/null
+++ b/source3/lib/tdb/tools/tdbtool.c
@@ -0,0 +1,659 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba database functions
+ Copyright (C) Andrew Tridgell 1999-2000
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000
+ Copyright (C) Andrew Esh 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/locale.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "tdb.h"
+
+static int do_command(void);
+const char *cmdname;
+char *arg1, *arg2;
+size_t arg1len, arg2len;
+int bIterate = 0;
+char *line;
+TDB_DATA iterate_kbuf;
+char cmdline[1024];
+static int disable_mmap;
+
+enum commands {
+ CMD_CREATE_TDB,
+ CMD_OPEN_TDB,
+ CMD_ERASE,
+ CMD_DUMP,
+ CMD_INSERT,
+ CMD_MOVE,
+ CMD_STORE,
+ CMD_SHOW,
+ CMD_KEYS,
+ CMD_HEXKEYS,
+ CMD_DELETE,
+ CMD_LIST_HASH_FREE,
+ CMD_LIST_FREE,
+ CMD_INFO,
+ CMD_MMAP,
+ CMD_SPEED,
+ CMD_FIRST,
+ CMD_NEXT,
+ CMD_SYSTEM,
+ CMD_QUIT,
+ CMD_HELP
+};
+
+typedef struct {
+ const char *name;
+ enum commands cmd;
+} COMMAND_TABLE;
+
+COMMAND_TABLE cmd_table[] = {
+ {"create", CMD_CREATE_TDB},
+ {"open", CMD_OPEN_TDB},
+ {"erase", CMD_ERASE},
+ {"dump", CMD_DUMP},
+ {"insert", CMD_INSERT},
+ {"move", CMD_MOVE},
+ {"store", CMD_STORE},
+ {"show", CMD_SHOW},
+ {"keys", CMD_KEYS},
+ {"hexkeys", CMD_HEXKEYS},
+ {"delete", CMD_DELETE},
+ {"list", CMD_LIST_HASH_FREE},
+ {"free", CMD_LIST_FREE},
+ {"info", CMD_INFO},
+ {"speed", CMD_SPEED},
+ {"mmap", CMD_MMAP},
+ {"first", CMD_FIRST},
+ {"1", CMD_FIRST},
+ {"next", CMD_NEXT},
+ {"n", CMD_NEXT},
+ {"quit", CMD_QUIT},
+ {"q", CMD_QUIT},
+ {"!", CMD_SYSTEM},
+ {NULL, CMD_HELP}
+};
+
+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);
+}
+
+/* a tdb tool for manipulating a tdb database */
+
+static TDB_CONTEXT *tdb;
+
+static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
+static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
+static int print_hexkey(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
+
+static void print_asc(const char *buf,int len)
+{
+ int i;
+
+ /* We're probably printing ASCII strings so don't try to display
+ the trailing NULL character. */
+
+ if (buf[len - 1] == 0)
+ len--;
+
+ for (i=0;i<len;i++)
+ printf("%c",isprint(buf[i])?buf[i]:'.');
+}
+
+static void print_data(const char *buf,int len)
+{
+ int i=0;
+ if (len<=0) return;
+ printf("[%03X] ",i);
+ for (i=0;i<len;) {
+ printf("%02X ",(int)((unsigned char)buf[i]));
+ i++;
+ if (i%8 == 0) printf(" ");
+ if (i%16 == 0) {
+ print_asc(&buf[i-16],8); printf(" ");
+ print_asc(&buf[i-8],8); printf("\n");
+ if (i<len) printf("[%03X] ",i);
+ }
+ }
+ if (i%16) {
+ int n;
+
+ n = 16 - (i%16);
+ printf(" ");
+ if (n>8) printf(" ");
+ while (n--) printf(" ");
+
+ n = i%16;
+ if (n > 8) n = 8;
+ print_asc(&buf[i-(i%16)],n); printf(" ");
+ n = (i%16) - n;
+ if (n>0) print_asc(&buf[i-n],n);
+ printf("\n");
+ }
+}
+
+static void help(void)
+{
+ printf("\n"
+"tdbtool: \n"
+" create dbname : create a database\n"
+" open dbname : open an existing database\n"
+" erase : erase the database\n"
+" dump : dump the database as strings\n"
+" keys : dump the database keys as strings\n"
+" hexkeys : dump the database keys as hex values\n"
+" info : print summary info about the database\n"
+" insert key data : insert a record\n"
+" move key file : move a record to a destination tdb\n"
+" store key data : store a record (replace)\n"
+" show key : show a record by key\n"
+" delete key : delete a record by key\n"
+" list : print the database hash table and freelist\n"
+" free : print the database freelist\n"
+" ! command : execute system command\n"
+" 1 | first : print the first record\n"
+" n | next : print the next record\n"
+" q | quit : terminate\n"
+" \\n : repeat 'next' command\n"
+"\n");
+}
+
+static void terror(const char *why)
+{
+ printf("%s\n", why);
+}
+
+static void create_tdb(const char *tdbname)
+{
+ if (tdb) tdb_close(tdb);
+ tdb = tdb_open(tdbname, 0, TDB_CLEAR_IF_FIRST | (disable_mmap?TDB_NOMMAP:0),
+ O_RDWR | O_CREAT | O_TRUNC, 0600);
+ if (!tdb) {
+ printf("Could not create %s: %s\n", tdbname, strerror(errno));
+ }
+}
+
+static void open_tdb(const char *tdbname)
+{
+ if (tdb) tdb_close(tdb);
+ tdb = tdb_open(tdbname, 0, disable_mmap?TDB_NOMMAP:0, O_RDWR, 0600);
+ if (!tdb) {
+ printf("Could not open %s: %s\n", tdbname, strerror(errno));
+ }
+}
+
+static void insert_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
+{
+ TDB_DATA key, dbuf;
+
+ if ((keyname == NULL) || (keylen == 0)) {
+ terror("need key");
+ return;
+ }
+
+ key.dptr = (unsigned char *)keyname;
+ key.dsize = keylen;
+ dbuf.dptr = (unsigned char *)data;
+ dbuf.dsize = datalen;
+
+ if (tdb_store(tdb, key, dbuf, TDB_INSERT) == -1) {
+ terror("insert failed");
+ }
+}
+
+static void store_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
+{
+ TDB_DATA key, dbuf;
+
+ if ((keyname == NULL) || (keylen == 0)) {
+ terror("need key");
+ return;
+ }
+
+ if ((data == NULL) || (datalen == 0)) {
+ terror("need data");
+ return;
+ }
+
+ key.dptr = (unsigned char *)keyname;
+ key.dsize = keylen;
+ dbuf.dptr = (unsigned char *)data;
+ dbuf.dsize = datalen;
+
+ printf("Storing key:\n");
+ print_rec(tdb, key, dbuf, NULL);
+
+ if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) {
+ terror("store failed");
+ }
+}
+
+static void show_tdb(char *keyname, size_t keylen)
+{
+ TDB_DATA key, dbuf;
+
+ if ((keyname == NULL) || (keylen == 0)) {
+ terror("need key");
+ return;
+ }
+
+ key.dptr = (unsigned char *)keyname;
+ key.dsize = keylen;
+
+ dbuf = tdb_fetch(tdb, key);
+ if (!dbuf.dptr) {
+ terror("fetch failed");
+ return;
+ }
+
+ print_rec(tdb, key, dbuf, NULL);
+
+ free( dbuf.dptr );
+
+ return;
+}
+
+static void delete_tdb(char *keyname, size_t keylen)
+{
+ TDB_DATA key;
+
+ if ((keyname == NULL) || (keylen == 0)) {
+ terror("need key");
+ return;
+ }
+
+ key.dptr = (unsigned char *)keyname;
+ key.dsize = keylen;
+
+ if (tdb_delete(tdb, key) != 0) {
+ terror("delete failed");
+ }
+}
+
+static void move_rec(char *keyname, size_t keylen, char* tdbname)
+{
+ TDB_DATA key, dbuf;
+ TDB_CONTEXT *dst_tdb;
+
+ if ((keyname == NULL) || (keylen == 0)) {
+ terror("need key");
+ return;
+ }
+
+ if ( !tdbname ) {
+ terror("need destination tdb name");
+ return;
+ }
+
+ key.dptr = (unsigned char *)keyname;
+ key.dsize = keylen;
+
+ dbuf = tdb_fetch(tdb, key);
+ if (!dbuf.dptr) {
+ terror("fetch failed");
+ return;
+ }
+
+ print_rec(tdb, key, dbuf, NULL);
+
+ dst_tdb = tdb_open(tdbname, 0, 0, O_RDWR, 0600);
+ if ( !dst_tdb ) {
+ terror("unable to open destination tdb");
+ return;
+ }
+
+ if ( tdb_store( dst_tdb, key, dbuf, TDB_REPLACE ) == -1 ) {
+ terror("failed to move record");
+ }
+ else
+ printf("record moved\n");
+
+ tdb_close( dst_tdb );
+
+ return;
+}
+
+static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ printf("\nkey %d bytes\n", (int)key.dsize);
+ print_asc((const char *)key.dptr, key.dsize);
+ printf("\ndata %d bytes\n", (int)dbuf.dsize);
+ print_data((const char *)dbuf.dptr, dbuf.dsize);
+ return 0;
+}
+
+static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ printf("key %d bytes: ", (int)key.dsize);
+ print_asc((const char *)key.dptr, key.dsize);
+ printf("\n");
+ return 0;
+}
+
+static int print_hexkey(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ printf("key %d bytes\n", (int)key.dsize);
+ print_data((const char *)key.dptr, key.dsize);
+ printf("\n");
+ return 0;
+}
+
+static int total_bytes;
+
+static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ total_bytes += dbuf.dsize;
+ return 0;
+}
+
+static void info_tdb(void)
+{
+ int count;
+ total_bytes = 0;
+ if ((count = tdb_traverse(tdb, traverse_fn, NULL)) == -1)
+ printf("Error = %s\n", tdb_errorstr(tdb));
+ else
+ printf("%d records totalling %d bytes\n", count, total_bytes);
+}
+
+static void speed_tdb(const char *tlimit)
+{
+ unsigned timelimit = tlimit?atoi(tlimit):0;
+ double t;
+ int ops=0;
+ if (timelimit == 0) timelimit = 10;
+ printf("Testing traverse speed for %u seconds\n", timelimit);
+ _start_timer();
+ while ((t=_end_timer()) < timelimit) {
+ tdb_traverse(tdb, traverse_fn, NULL);
+ printf("%10.3f ops/sec\r", (++ops)/t);
+ }
+ printf("\n");
+}
+
+static void toggle_mmap(void)
+{
+ disable_mmap = !disable_mmap;
+ if (disable_mmap) {
+ printf("mmap is disabled\n");
+ } else {
+ printf("mmap is enabled\n");
+ }
+}
+
+static char *tdb_getline(const char *prompt)
+{
+ static char thisline[1024];
+ char *p;
+ fputs(prompt, stdout);
+ thisline[0] = 0;
+ p = fgets(thisline, sizeof(thisline)-1, stdin);
+ if (p) p = strchr(p, '\n');
+ if (p) *p = 0;
+ return p?thisline:NULL;
+}
+
+static int do_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
+ void *state)
+{
+ return tdb_delete(the_tdb, key);
+}
+
+static void first_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey)
+{
+ TDB_DATA dbuf;
+ *pkey = tdb_firstkey(the_tdb);
+
+ dbuf = tdb_fetch(the_tdb, *pkey);
+ if (!dbuf.dptr) terror("fetch failed");
+ else {
+ print_rec(the_tdb, *pkey, dbuf, NULL);
+ }
+}
+
+static void next_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey)
+{
+ TDB_DATA dbuf;
+ *pkey = tdb_nextkey(the_tdb, *pkey);
+
+ dbuf = tdb_fetch(the_tdb, *pkey);
+ if (!dbuf.dptr)
+ terror("fetch failed");
+ else
+ print_rec(the_tdb, *pkey, dbuf, NULL);
+}
+
+static int do_command(void)
+{
+ COMMAND_TABLE *ctp = cmd_table;
+ enum commands mycmd = CMD_HELP;
+ int cmd_len;
+
+ if (cmdname && strlen(cmdname) == 0) {
+ mycmd = CMD_NEXT;
+ } else {
+ while (ctp->name) {
+ cmd_len = strlen(ctp->name);
+ if (strncmp(ctp->name,cmdname,cmd_len) == 0) {
+ mycmd = ctp->cmd;
+ break;
+ }
+ ctp++;
+ }
+ }
+
+ switch (mycmd) {
+ case CMD_CREATE_TDB:
+ bIterate = 0;
+ create_tdb(arg1);
+ return 0;
+ case CMD_OPEN_TDB:
+ bIterate = 0;
+ open_tdb(arg1);
+ return 0;
+ case CMD_SYSTEM:
+ /* Shell command */
+ system(arg1);
+ return 0;
+ case CMD_QUIT:
+ return 1;
+ default:
+ /* all the rest require a open database */
+ if (!tdb) {
+ bIterate = 0;
+ terror("database not open");
+ help();
+ return 0;
+ }
+ switch (mycmd) {
+ case CMD_ERASE:
+ bIterate = 0;
+ tdb_traverse(tdb, do_delete_fn, NULL);
+ return 0;
+ case CMD_DUMP:
+ bIterate = 0;
+ tdb_traverse(tdb, print_rec, NULL);
+ return 0;
+ case CMD_INSERT:
+ bIterate = 0;
+ insert_tdb(arg1, arg1len,arg2,arg2len);
+ return 0;
+ case CMD_MOVE:
+ bIterate = 0;
+ move_rec(arg1,arg1len,arg2);
+ return 0;
+ case CMD_STORE:
+ bIterate = 0;
+ store_tdb(arg1,arg1len,arg2,arg2len);
+ return 0;
+ case CMD_SHOW:
+ bIterate = 0;
+ show_tdb(arg1, arg1len);
+ return 0;
+ case CMD_KEYS:
+ tdb_traverse(tdb, print_key, NULL);
+ return 0;
+ case CMD_HEXKEYS:
+ tdb_traverse(tdb, print_hexkey, NULL);
+ return 0;
+ case CMD_DELETE:
+ bIterate = 0;
+ delete_tdb(arg1,arg1len);
+ return 0;
+ case CMD_LIST_HASH_FREE:
+ tdb_dump_all(tdb);
+ return 0;
+ case CMD_LIST_FREE:
+ tdb_printfreelist(tdb);
+ return 0;
+ case CMD_INFO:
+ info_tdb();
+ return 0;
+ case CMD_SPEED:
+ speed_tdb(arg1);
+ return 0;
+ case CMD_MMAP:
+ toggle_mmap();
+ return 0;
+ case CMD_FIRST:
+ bIterate = 1;
+ first_record(tdb, &iterate_kbuf);
+ return 0;
+ case CMD_NEXT:
+ if (bIterate)
+ next_record(tdb, &iterate_kbuf);
+ return 0;
+ case CMD_HELP:
+ help();
+ return 0;
+ case CMD_CREATE_TDB:
+ case CMD_OPEN_TDB:
+ case CMD_SYSTEM:
+ case CMD_QUIT:
+ /*
+ * unhandled commands. cases included here to avoid compiler
+ * warnings.
+ */
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static char *convert_string(char *instring, size_t *sizep)
+{
+ size_t length = 0;
+ char *outp, *inp;
+ char temp[3];
+
+
+ outp = inp = instring;
+
+ while (*inp) {
+ if (*inp == '\\') {
+ inp++;
+ if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
+ temp[0] = *inp++;
+ temp[1] = '\0';
+ if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
+ temp[1] = *inp++;
+ temp[2] = '\0';
+ }
+ *outp++ = (char)strtol((const char *)temp,NULL,16);
+ } else {
+ *outp++ = *inp++;
+ }
+ } else {
+ *outp++ = *inp++;
+ }
+ length++;
+ }
+ *sizep = length;
+ return instring;
+}
+
+int main(int argc, char *argv[])
+{
+ cmdname = "";
+ arg1 = NULL;
+ arg1len = 0;
+ arg2 = NULL;
+ arg2len = 0;
+
+ if (argv[1]) {
+ cmdname = "open";
+ arg1 = argv[1];
+ do_command();
+ cmdname = "";
+ arg1 = NULL;
+ }
+
+ switch (argc) {
+ case 1:
+ case 2:
+ /* Interactive mode */
+ while ((cmdname = tdb_getline("tdb> "))) {
+ arg2 = arg1 = NULL;
+ if ((arg1 = strchr((const char *)cmdname,' ')) != NULL) {
+ arg1++;
+ arg2 = arg1;
+ while (*arg2) {
+ if (*arg2 == ' ') {
+ *arg2++ = '\0';
+ break;
+ }
+ if ((*arg2++ == '\\') && (*arg2 == ' ')) {
+ arg2++;
+ }
+ }
+ }
+ if (arg1) arg1 = convert_string(arg1,&arg1len);
+ if (arg2) arg2 = convert_string(arg2,&arg2len);
+ if (do_command()) break;
+ }
+ break;
+ case 5:
+ arg2 = convert_string(argv[4],&arg2len);
+ case 4:
+ arg1 = convert_string(argv[3],&arg1len);
+ case 3:
+ cmdname = argv[2];
+ default:
+ do_command();
+ break;
+ }
+
+ if (tdb) tdb_close(tdb);
+
+ return 0;
+}
diff --git a/source3/lib/tdb/tools/tdbtorture.c b/source3/lib/tdb/tools/tdbtorture.c
new file mode 100644
index 0000000000..9265cf07aa
--- /dev/null
+++ b/source3/lib/tdb/tools/tdbtorture.c
@@ -0,0 +1,318 @@
+/* this tests tdb by doing lots of ops from several simultaneous
+ writers - that stresses the locking code.
+*/
+
+#include "replace.h"
+#include "system/time.h"
+#include "system/wait.h"
+#include "system/filesys.h"
+#include "tdb.h"
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+
+#define REOPEN_PROB 30
+#define DELETE_PROB 8
+#define STORE_PROB 4
+#define APPEND_PROB 6
+#define TRANSACTION_PROB 10
+#define LOCKSTORE_PROB 5
+#define TRAVERSE_PROB 20
+#define TRAVERSE_READ_PROB 20
+#define CULL_PROB 100
+#define KEYLEN 3
+#define DATALEN 100
+
+static struct tdb_context *db;
+static int in_transaction;
+static int error_count;
+
+#ifdef PRINTF_ATTRIBUTE
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...)
+{
+ va_list ap;
+
+ error_count++;
+
+ va_start(ap, format);
+ vfprintf(stdout, format, ap);
+ va_end(ap);
+ fflush(stdout);
+#if 0
+ {
+ char *ptr;
+ asprintf(&ptr,"xterm -e gdb /proc/%d/exe %d", getpid(), getpid());
+ system(ptr);
+ free(ptr);
+ }
+#endif
+}
+
+static void fatal(const char *why)
+{
+ perror(why);
+ error_count++;
+}
+
+static char *randbuf(int len)
+{
+ char *buf;
+ int i;
+ buf = (char *)malloc(len+1);
+
+ for (i=0;i<len;i++) {
+ buf[i] = 'a' + (rand() % 26);
+ }
+ buf[i] = 0;
+ return buf;
+}
+
+static int cull_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
+ void *state)
+{
+#if CULL_PROB
+ if (random() % CULL_PROB == 0) {
+ tdb_delete(tdb, key);
+ }
+#endif
+ return 0;
+}
+
+static void addrec_db(void)
+{
+ int klen, dlen;
+ char *k, *d;
+ TDB_DATA key, data;
+
+ klen = 1 + (rand() % KEYLEN);
+ dlen = 1 + (rand() % DATALEN);
+
+ k = randbuf(klen);
+ d = randbuf(dlen);
+
+ key.dptr = (unsigned char *)k;
+ key.dsize = klen+1;
+
+ data.dptr = (unsigned char *)d;
+ data.dsize = dlen+1;
+
+#if TRANSACTION_PROB
+ if (in_transaction == 0 && random() % TRANSACTION_PROB == 0) {
+ if (tdb_transaction_start(db) != 0) {
+ fatal("tdb_transaction_start failed");
+ }
+ in_transaction++;
+ goto next;
+ }
+ if (in_transaction && random() % TRANSACTION_PROB == 0) {
+ if (tdb_transaction_commit(db) != 0) {
+ fatal("tdb_transaction_commit failed");
+ }
+ in_transaction--;
+ goto next;
+ }
+ if (in_transaction && random() % TRANSACTION_PROB == 0) {
+ if (tdb_transaction_cancel(db) != 0) {
+ fatal("tdb_transaction_cancel failed");
+ }
+ in_transaction--;
+ goto next;
+ }
+#endif
+
+#if REOPEN_PROB
+ if (in_transaction == 0 && random() % REOPEN_PROB == 0) {
+ tdb_reopen_all(0);
+ goto next;
+ }
+#endif
+
+#if DELETE_PROB
+ if (random() % DELETE_PROB == 0) {
+ tdb_delete(db, key);
+ goto next;
+ }
+#endif
+
+#if STORE_PROB
+ if (random() % STORE_PROB == 0) {
+ if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+ fatal("tdb_store failed");
+ }
+ goto next;
+ }
+#endif
+
+#if APPEND_PROB
+ if (random() % APPEND_PROB == 0) {
+ if (tdb_append(db, key, data) != 0) {
+ fatal("tdb_append failed");
+ }
+ goto next;
+ }
+#endif
+
+#if LOCKSTORE_PROB
+ if (random() % LOCKSTORE_PROB == 0) {
+ tdb_chainlock(db, key);
+ data = tdb_fetch(db, key);
+ if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+ fatal("tdb_store failed");
+ }
+ if (data.dptr) free(data.dptr);
+ tdb_chainunlock(db, key);
+ goto next;
+ }
+#endif
+
+#if TRAVERSE_PROB
+ if (random() % TRAVERSE_PROB == 0) {
+ tdb_traverse(db, cull_traverse, NULL);
+ goto next;
+ }
+#endif
+
+#if TRAVERSE_READ_PROB
+ if (random() % TRAVERSE_READ_PROB == 0) {
+ tdb_traverse_read(db, NULL, NULL);
+ goto next;
+ }
+#endif
+
+ data = tdb_fetch(db, key);
+ if (data.dptr) free(data.dptr);
+
+next:
+ free(k);
+ free(d);
+}
+
+static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
+ void *state)
+{
+ tdb_delete(tdb, key);
+ return 0;
+}
+
+static void usage(void)
+{
+ printf("Usage: tdbtorture [-n NUM_PROCS] [-l NUM_LOOPS] [-s SEED] [-H HASH_SIZE]\n");
+ exit(0);
+}
+
+ int main(int argc, char * const *argv)
+{
+ int i, seed = -1;
+ int num_procs = 3;
+ int num_loops = 5000;
+ int hash_size = 2;
+ int c;
+ extern char *optarg;
+ pid_t *pids;
+
+ struct tdb_logging_context log_ctx;
+ log_ctx.log_fn = tdb_log;
+
+ while ((c = getopt(argc, argv, "n:l:s:H:h")) != -1) {
+ switch (c) {
+ case 'n':
+ num_procs = strtol(optarg, NULL, 0);
+ break;
+ case 'l':
+ num_loops = strtol(optarg, NULL, 0);
+ break;
+ case 'H':
+ hash_size = strtol(optarg, NULL, 0);
+ break;
+ case 's':
+ seed = strtol(optarg, NULL, 0);
+ break;
+ default:
+ usage();
+ }
+ }
+
+ unlink("torture.tdb");
+
+ pids = (pid_t *)calloc(sizeof(pid_t), num_procs);
+ pids[0] = getpid();
+
+ for (i=0;i<num_procs-1;i++) {
+ if ((pids[i+1]=fork()) == 0) break;
+ }
+
+ db = tdb_open_ex("torture.tdb", hash_size, TDB_CLEAR_IF_FIRST,
+ O_RDWR | O_CREAT, 0600, &log_ctx, NULL);
+ if (!db) {
+ fatal("db open failed");
+ }
+
+ if (seed == -1) {
+ seed = (getpid() + time(NULL)) & 0x7FFFFFFF;
+ }
+
+ if (i == 0) {
+ printf("testing with %d processes, %d loops, %d hash_size, seed=%d\n",
+ num_procs, num_loops, hash_size, seed);
+ }
+
+ srand(seed + i);
+ srandom(seed + i);
+
+ for (i=0;i<num_loops && error_count == 0;i++) {
+ addrec_db();
+ }
+
+ if (error_count == 0) {
+ tdb_traverse_read(db, NULL, NULL);
+ tdb_traverse(db, traverse_fn, NULL);
+ tdb_traverse(db, traverse_fn, NULL);
+ }
+
+ tdb_close(db);
+
+ if (getpid() != pids[0]) {
+ return error_count;
+ }
+
+ for (i=1;i<num_procs;i++) {
+ int status, j;
+ pid_t pid;
+ if (error_count != 0) {
+ /* try and stop the test on any failure */
+ for (j=1;j<num_procs;j++) {
+ if (pids[j] != 0) {
+ kill(pids[j], SIGTERM);
+ }
+ }
+ }
+ pid = waitpid(-1, &status, 0);
+ if (pid == -1) {
+ perror("failed to wait for child\n");
+ exit(1);
+ }
+ for (j=1;j<num_procs;j++) {
+ if (pids[j] == pid) break;
+ }
+ if (j == num_procs) {
+ printf("unknown child %d exited!?\n", (int)pid);
+ exit(1);
+ }
+ if (WEXITSTATUS(status) != 0) {
+ printf("child %d exited with status %d\n",
+ (int)pid, WEXITSTATUS(status));
+ error_count++;
+ }
+ pids[j] = 0;
+ }
+
+ if (error_count == 0) {
+ printf("OK\n");
+ }
+
+ return error_count;
+}
diff --git a/source3/lib/tdb/web/index.html b/source3/lib/tdb/web/index.html
new file mode 100644
index 0000000000..a53da6b8f7
--- /dev/null
+++ b/source3/lib/tdb/web/index.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+<TITLE>ldb</TITLE>
+</HEAD>
+<BODY BGCOLOR="#ffffff" TEXT="#000000" VLINK="#292555" LINK="#292555" ALINK="#cc0033">
+
+<h1>tdb</h1>
+
+TDB is a Trivial Database. In concept, it is very much like GDBM, and BSD's DB
+except that it allows multiple simultaneous writers and uses locking
+internally to keep writers from trampling on each other. TDB is also extremely
+small.
+
+<h2>Discussion and bug reports</h2>
+
+tdb does not currently have its own mailing list or bug tracking
+system. For now, please use the <a
+href="https://lists.samba.org/mailman/listinfo/samba-technical">samba-technical</a>
+mailing list, and the <a href="http://bugzilla.samba.org/">Samba
+bugzilla</a> bug tracking system.
+
+<h2>Download</h2>
+
+You can download the latest release either via rsync or git.<br>
+<br>
+To fetch via git see the following guide:<br>
+<a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development">Using Git for Samba Development</a><br>
+Once you have cloned the tree switch to the v4-0-test branch and cd into the source/lib/tdb directory.<br>
+<br>
+To fetch via rsync use these commands:
+
+<pre>
+ rsync -Pavz samba.org::ftp/unpacked/tdb .
+ rsync -Pavz samba.org::ftp/unpacked/libreplace .
+</pre>
+
+and build in tdb. It will find the replace library in the directory
+above automatically.
+
+</BODY>
+</HTML>
diff --git a/source3/lib/time.c b/source3/lib/time.c
new file mode 100644
index 0000000000..8cefef6e23
--- /dev/null
+++ b/source3/lib/time.c
@@ -0,0 +1,1505 @@
+/*
+ Unix SMB/CIFS implementation.
+ time handling functions
+
+ Copyright (C) Andrew Tridgell 1992-2004
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Jeremy Allison 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/**
+ * @file
+ * @brief time handling functions
+ */
+
+
+#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
+
+#define NTTIME_INFINITY (NTTIME)0x8000000000000000LL
+
+/***************************************************************************
+ External access to time_t_min and time_t_max.
+****************************************************************************/
+
+time_t get_time_t_max(void)
+{
+ return TIME_T_MAX;
+}
+
+/***************************************************************************
+ A gettimeofday wrapper.
+****************************************************************************/
+
+void GetTimeOfDay(struct timeval *tval)
+{
+#ifdef HAVE_GETTIMEOFDAY_TZ
+ gettimeofday(tval,NULL);
+#else
+ gettimeofday(tval);
+#endif
+}
+
+#if (SIZEOF_LONG == 8)
+#define TIME_FIXUP_CONSTANT_INT 11644473600L
+#elif (SIZEOF_LONG_LONG == 8)
+#define TIME_FIXUP_CONSTANT_INT 11644473600LL
+#endif
+
+/****************************************************************************
+ Interpret an 8 byte "filetime" structure to a time_t
+ It's originally in "100ns units since jan 1st 1601"
+
+ An 8 byte value of 0xffffffffffffffff will be returned as a timespec of
+
+ tv_sec = 0
+ tv_nsec = 0;
+
+ Returns GMT.
+****************************************************************************/
+
+time_t nt_time_to_unix(NTTIME nt)
+{
+ return convert_timespec_to_time_t(nt_time_to_unix_timespec(&nt));
+}
+
+/****************************************************************************
+ Put a 8 byte filetime from a time_t. Uses GMT.
+****************************************************************************/
+
+void unix_to_nt_time(NTTIME *nt, time_t t)
+{
+ uint64_t t2;
+
+ if (t == (time_t)-1) {
+ *nt = (NTTIME)-1LL;
+ return;
+ }
+
+ if (t == TIME_T_MAX) {
+ *nt = 0x7fffffffffffffffLL;
+ return;
+ }
+
+ if (t == 0) {
+ *nt = 0;
+ return;
+ }
+
+ t2 = t;
+ t2 += TIME_FIXUP_CONSTANT_INT;
+ t2 *= 1000*1000*10;
+
+ *nt = t2;
+}
+
+/****************************************************************************
+ Check if it's a null unix time.
+****************************************************************************/
+
+bool null_time(time_t t)
+{
+ return t == 0 ||
+ t == (time_t)0xFFFFFFFF ||
+ t == (time_t)-1;
+}
+
+/****************************************************************************
+ Check if it's a null NTTIME.
+****************************************************************************/
+
+bool null_nttime(NTTIME t)
+{
+ return t == 0 || t == (NTTIME)-1;
+}
+
+/****************************************************************************
+ Check if it's a null timespec.
+****************************************************************************/
+
+bool null_timespec(struct timespec ts)
+{
+ return ts.tv_sec == 0 ||
+ ts.tv_sec == (time_t)0xFFFFFFFF ||
+ ts.tv_sec == (time_t)-1;
+}
+
+/*******************************************************************
+ create a 16 bit dos packed date
+********************************************************************/
+static uint16_t make_dos_date1(struct tm *t)
+{
+ uint16_t ret=0;
+ ret = (((unsigned int)(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_t make_dos_time1(struct tm *t)
+{
+ uint16_t ret=0;
+ ret = ((((unsigned int)t->tm_min >> 3)&0x7) | (((unsigned int)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_t make_dos_date(time_t unixdate, int zone_offset)
+{
+ struct tm *t;
+ uint32_t ret=0;
+
+ if (unixdate == 0) {
+ return 0;
+ }
+
+ unixdate -= zone_offset;
+
+ t = gmtime(&unixdate);
+ if (!t) {
+ return 0xFFFFFFFF;
+ }
+
+ ret = make_dos_date1(t);
+ ret = ((ret&0xFFFF)<<16) | make_dos_time1(t);
+
+ return ret;
+}
+
+/**
+put a dos date into a buffer (time/date format)
+This takes GMT time and puts local time in the buffer
+**/
+void push_dos_date(uint8_t *buf, int offset, time_t unixdate, int zone_offset)
+{
+ uint32_t x = make_dos_date(unixdate, zone_offset);
+ 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 push_dos_date2(uint8_t *buf,int offset,time_t unixdate, int zone_offset)
+{
+ uint32_t x;
+ x = make_dos_date(unixdate, zone_offset);
+ 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 push_dos_date3(uint8_t *buf,int offset,time_t unixdate, int zone_offset)
+{
+ if (!null_time(unixdate)) {
+ unixdate -= zone_offset;
+ }
+ SIVAL(buf,offset,unixdate);
+}
+
+/*******************************************************************
+ interpret a 32 bit dos packed date/time to some parameters
+********************************************************************/
+static void interpret_dos_date(uint32_t date,int *year,int *month,int *day,int *hour,int *minute,int *second)
+{
+ uint32_t 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 pull_dos_date(const uint8_t *date_ptr, int zone_offset)
+{
+ uint32_t dos_date=0;
+ struct tm t;
+ time_t ret;
+
+ dos_date = IVAL(date_ptr,0);
+
+ if (dos_date == 0) return (time_t)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;
+
+ ret = timegm(&t);
+
+ ret += zone_offset;
+
+ return ret;
+}
+
+/**
+like make_unix_date() but the words are reversed
+**/
+time_t pull_dos_date2(const uint8_t *date_ptr, int zone_offset)
+{
+ uint32_t x,x2;
+
+ x = IVAL(date_ptr,0);
+ x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+ SIVAL(&x,0,x2);
+
+ return pull_dos_date((const uint8_t *)&x, zone_offset);
+}
+
+/**
+ 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 pull_dos_date3(const uint8_t *date_ptr, int zone_offset)
+{
+ time_t t = (time_t)IVAL(date_ptr,0);
+ if (!null_time(t)) {
+ t += zone_offset;
+ }
+ return t;
+}
+
+/***************************************************************************
+ Return a HTTP/1.0 time string.
+***************************************************************************/
+
+char *http_timestring(time_t t)
+{
+ fstring buf;
+ struct tm *tm = localtime(&t);
+
+ if (t == TIME_T_MAX) {
+ fstrcpy(buf, "never");
+ } else if (!tm) {
+ fstr_sprintf(buf, "%ld seconds since the Epoch", (long)t);
+ } else {
+#ifndef HAVE_STRFTIME
+ const char *asct = asctime(tm);
+ fstrcpy(buf, asct ? asct : "unknown");
+ }
+ if(buf[strlen(buf)-1] == '\n') {
+ buf[strlen(buf)-1] = 0;
+#else /* !HAVE_STRFTIME */
+ strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S %Z", tm);
+#endif /* !HAVE_STRFTIME */
+ }
+ return talloc_strdup(talloc_tos(), buf);
+}
+
+
+/**
+ Return the date and time as a string
+**/
+char *timestring(TALLOC_CTX *mem_ctx, time_t t)
+{
+ char *TimeBuf;
+ char tempTime[80];
+ struct tm *tm;
+
+ tm = localtime(&t);
+ if (!tm) {
+ return talloc_asprintf(mem_ctx,
+ "%ld seconds since the Epoch",
+ (long)t);
+ }
+
+#ifdef HAVE_STRFTIME
+ /* some versions of gcc complain about using %c. This is a bug
+ in the gcc warning, not a bug in this code. See a recent
+ strftime() manual page for details.
+ */
+ strftime(tempTime,sizeof(tempTime)-1,"%c %Z",tm);
+ TimeBuf = talloc_strdup(mem_ctx, tempTime);
+#else
+ TimeBuf = talloc_strdup(mem_ctx, asctime(tm));
+#endif
+
+ return TimeBuf;
+}
+
+/**
+ return a talloced string representing a NTTIME for human consumption
+*/
+const char *nt_time_string(TALLOC_CTX *mem_ctx, NTTIME nt)
+{
+ time_t t;
+ if (nt == 0) {
+ return "NTTIME(0)";
+ }
+ t = nt_time_to_unix(nt);
+ return timestring(mem_ctx, t);
+}
+
+
+/**
+ parse a nttime as a large integer in a string and return a NTTIME
+*/
+NTTIME nttime_from_string(const char *s)
+{
+ return strtoull(s, NULL, 0);
+}
+
+/**
+ return (tv1 - tv2) in microseconds
+*/
+int64_t usec_time_diff(struct timeval *tv1, struct timeval *tv2)
+{
+ int64_t sec_diff = tv1->tv_sec - tv2->tv_sec;
+ return (sec_diff * 1000000) + (int64_t)(tv1->tv_usec - tv2->tv_usec);
+}
+
+
+/**
+ return a zero timeval
+*/
+struct timeval timeval_zero(void)
+{
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ return tv;
+}
+
+/**
+ return True if a timeval is zero
+*/
+bool timeval_is_zero(const struct timeval *tv)
+{
+ return tv->tv_sec == 0 && tv->tv_usec == 0;
+}
+
+/**
+ return a timeval for the current time
+*/
+struct timeval timeval_current(void)
+{
+ struct timeval tv;
+ GetTimeOfDay(&tv);
+ return tv;
+}
+
+/**
+ return a timeval struct with the given elements
+*/
+struct timeval timeval_set(uint32_t secs, uint32_t usecs)
+{
+ struct timeval tv;
+ tv.tv_sec = secs;
+ tv.tv_usec = usecs;
+ return tv;
+}
+
+
+/**
+ return a timeval ofs microseconds after tv
+*/
+struct timeval timeval_add(const struct timeval *tv,
+ uint32_t secs, uint32_t usecs)
+{
+ struct timeval tv2 = *tv;
+ const unsigned int million = 1000000;
+ tv2.tv_sec += secs;
+ tv2.tv_usec += usecs;
+ tv2.tv_sec += tv2.tv_usec / million;
+ tv2.tv_usec = tv2.tv_usec % million;
+ return tv2;
+}
+
+/**
+ return the sum of two timeval structures
+*/
+struct timeval timeval_sum(const struct timeval *tv1,
+ const struct timeval *tv2)
+{
+ return timeval_add(tv1, tv2->tv_sec, tv2->tv_usec);
+}
+
+/**
+ return a timeval secs/usecs into the future
+*/
+struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs)
+{
+ struct timeval tv = timeval_current();
+ return timeval_add(&tv, secs, usecs);
+}
+
+/**
+ compare two timeval structures.
+ Return -1 if tv1 < tv2
+ Return 0 if tv1 == tv2
+ Return 1 if tv1 > tv2
+*/
+int timeval_compare(const struct timeval *tv1, const struct timeval *tv2)
+{
+ if (tv1->tv_sec > tv2->tv_sec) return 1;
+ if (tv1->tv_sec < tv2->tv_sec) return -1;
+ if (tv1->tv_usec > tv2->tv_usec) return 1;
+ if (tv1->tv_usec < tv2->tv_usec) return -1;
+ return 0;
+}
+
+/**
+ return True if a timer is in the past
+*/
+bool timeval_expired(const struct timeval *tv)
+{
+ struct timeval tv2 = timeval_current();
+ if (tv2.tv_sec > tv->tv_sec) return True;
+ if (tv2.tv_sec < tv->tv_sec) return False;
+ return (tv2.tv_usec >= tv->tv_usec);
+}
+
+/**
+ return the number of seconds elapsed between two times
+*/
+double timeval_elapsed2(const struct timeval *tv1, const struct timeval *tv2)
+{
+ return (tv2->tv_sec - tv1->tv_sec) +
+ (tv2->tv_usec - tv1->tv_usec)*1.0e-6;
+}
+
+/**
+ return the number of seconds elapsed since a given time
+*/
+double timeval_elapsed(const struct timeval *tv)
+{
+ struct timeval tv2 = timeval_current();
+ return timeval_elapsed2(tv, &tv2);
+}
+
+/**
+ return the lesser of two timevals
+*/
+struct timeval timeval_min(const struct timeval *tv1,
+ const struct timeval *tv2)
+{
+ if (tv1->tv_sec < tv2->tv_sec) return *tv1;
+ if (tv1->tv_sec > tv2->tv_sec) return *tv2;
+ if (tv1->tv_usec < tv2->tv_usec) return *tv1;
+ return *tv2;
+}
+
+/**
+ return the greater of two timevals
+*/
+struct timeval timeval_max(const struct timeval *tv1,
+ const struct timeval *tv2)
+{
+ if (tv1->tv_sec > tv2->tv_sec) return *tv1;
+ if (tv1->tv_sec < tv2->tv_sec) return *tv2;
+ if (tv1->tv_usec > tv2->tv_usec) return *tv1;
+ return *tv2;
+}
+
+/**
+ return the difference between two timevals as a timeval
+ if tv1 comes after tv2, then return a zero timeval
+ (this is *tv2 - *tv1)
+*/
+struct timeval timeval_until(const struct timeval *tv1,
+ const struct timeval *tv2)
+{
+ struct timeval t;
+ if (timeval_compare(tv1, tv2) >= 0) {
+ return timeval_zero();
+ }
+ t.tv_sec = tv2->tv_sec - tv1->tv_sec;
+ if (tv1->tv_usec > tv2->tv_usec) {
+ t.tv_sec--;
+ t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec);
+ } else {
+ t.tv_usec = tv2->tv_usec - tv1->tv_usec;
+ }
+ return t;
+}
+
+
+/**
+ convert a timeval to a NTTIME
+*/
+NTTIME timeval_to_nttime(const struct timeval *tv)
+{
+ return 10*(tv->tv_usec +
+ ((TIME_FIXUP_CONSTANT_INT + (uint64_t)tv->tv_sec) * 1000000));
+}
+
+/**************************************************************
+ Handle conversions between time_t and uint32, taking care to
+ preserve the "special" values.
+**************************************************************/
+
+uint32 convert_time_t_to_uint32(time_t t)
+{
+#if (defined(SIZEOF_TIME_T) && (SIZEOF_TIME_T == 8))
+ /* time_t is 64-bit. */
+ if (t == 0x8000000000000000LL) {
+ return 0x80000000;
+ } else if (t == 0x7FFFFFFFFFFFFFFFLL) {
+ return 0x7FFFFFFF;
+ }
+#endif
+ return (uint32)t;
+}
+
+time_t convert_uint32_to_time_t(uint32 u)
+{
+#if (defined(SIZEOF_TIME_T) && (SIZEOF_TIME_T == 8))
+ /* time_t is 64-bit. */
+ if (u == 0x80000000) {
+ return (time_t)0x8000000000000000LL;
+ } else if (u == 0x7FFFFFFF) {
+ return (time_t)0x7FFFFFFFFFFFFFFFLL;
+ }
+#endif
+ return (time_t)u;
+}
+
+/*******************************************************************
+ 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 + (1900 - 1);
+ int by = b->tm_year + (1900 - 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;
+}
+
+int extra_time_offset=0;
+
+/*******************************************************************
+ Return the UTC offset in seconds west of UTC, or 0 if it cannot be determined.
+********************************************************************/
+
+int get_time_zone(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)+60*extra_time_offset;
+}
+
+/****************************************************************************
+ Check if NTTIME is 0.
+****************************************************************************/
+
+bool nt_time_is_zero(const NTTIME *nt)
+{
+ return (*nt == 0);
+}
+
+/****************************************************************************
+ Convert ASN.1 GeneralizedTime string to unix-time.
+ Returns 0 on failure; Currently ignores timezone.
+****************************************************************************/
+
+time_t generalized_to_unix_time(const char *str)
+{
+ struct tm tm;
+
+ ZERO_STRUCT(tm);
+
+ if (sscanf(str, "%4d%2d%2d%2d%2d%2d",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
+ return 0;
+ }
+ tm.tm_year -= 1900;
+ tm.tm_mon -= 1;
+
+ return timegm(&tm);
+}
+
+/*******************************************************************
+ Accessor function for the server time zone offset.
+ set_server_zone_offset() must have been called first.
+******************************************************************/
+
+static int server_zone_offset;
+
+int get_server_zone_offset(void)
+{
+ return server_zone_offset;
+}
+
+/*******************************************************************
+ Initialize the server time zone offset. Called when a client connects.
+******************************************************************/
+
+int set_server_zone_offset(time_t t)
+{
+ server_zone_offset = get_time_zone(t);
+ return server_zone_offset;
+}
+
+/****************************************************************************
+ Return the date and time as a string
+****************************************************************************/
+
+char *current_timestring(TALLOC_CTX *ctx, bool hires)
+{
+ fstring TimeBuf;
+ struct timeval tp;
+ time_t t;
+ struct tm *tm;
+
+ if (hires) {
+ GetTimeOfDay(&tp);
+ t = (time_t)tp.tv_sec;
+ } else {
+ t = time(NULL);
+ }
+ tm = localtime(&t);
+ if (!tm) {
+ if (hires) {
+ slprintf(TimeBuf,
+ sizeof(TimeBuf)-1,
+ "%ld.%06ld seconds since the Epoch",
+ (long)tp.tv_sec,
+ (long)tp.tv_usec);
+ } else {
+ slprintf(TimeBuf,
+ sizeof(TimeBuf)-1,
+ "%ld seconds since the Epoch",
+ (long)t);
+ }
+ } else {
+#ifdef HAVE_STRFTIME
+ if (hires) {
+ strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm);
+ slprintf(TimeBuf+strlen(TimeBuf),
+ sizeof(TimeBuf)-1 - strlen(TimeBuf),
+ ".%06ld",
+ (long)tp.tv_usec);
+ } else {
+ strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm);
+ }
+#else
+ if (hires) {
+ const char *asct = asctime(tm);
+ slprintf(TimeBuf,
+ sizeof(TimeBuf)-1,
+ "%s.%06ld",
+ asct ? asct : "unknown",
+ (long)tp.tv_usec);
+ } else {
+ const char *asct = asctime(tm);
+ fstrcpy(TimeBuf, asct ? asct : "unknown");
+ }
+#endif
+ }
+ return talloc_strdup(ctx, TimeBuf);
+}
+
+
+/*******************************************************************
+ Put a dos date into a buffer (time/date format).
+ This takes GMT time and puts local time in the buffer.
+********************************************************************/
+
+static void put_dos_date(char *buf,int offset,time_t unixdate, int zone_offset)
+{
+ uint32 x = make_dos_date(unixdate, zone_offset);
+ 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.
+********************************************************************/
+
+static void put_dos_date2(char *buf,int offset,time_t unixdate, int zone_offset)
+{
+ uint32 x = make_dos_date(unixdate, zone_offset);
+ 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)
+********************************************************************/
+
+static void put_dos_date3(char *buf,int offset,time_t unixdate, int zone_offset)
+{
+ if (!null_mtime(unixdate)) {
+ unixdate -= zone_offset;
+ }
+ SIVAL(buf,offset,unixdate);
+}
+
+
+/***************************************************************************
+ Server versions of the above functions.
+***************************************************************************/
+
+void srv_put_dos_date(char *buf,int offset,time_t unixdate)
+{
+ put_dos_date(buf, offset, unixdate, server_zone_offset);
+}
+
+void srv_put_dos_date2(char *buf,int offset, time_t unixdate)
+{
+ put_dos_date2(buf, offset, unixdate, server_zone_offset);
+}
+
+void srv_put_dos_date3(char *buf,int offset,time_t unixdate)
+{
+ put_dos_date3(buf, offset, unixdate, server_zone_offset);
+}
+
+/****************************************************************************
+ Take a Unix time and convert to an NTTIME structure and place in buffer
+ pointed to by p.
+****************************************************************************/
+
+void put_long_date_timespec(char *p, struct timespec ts)
+{
+ NTTIME nt;
+ unix_timespec_to_nt_time(&nt, ts);
+ SIVAL(p, 0, nt & 0xFFFFFFFF);
+ SIVAL(p, 4, nt >> 32);
+}
+
+void put_long_date(char *p, time_t t)
+{
+ struct timespec ts;
+ ts.tv_sec = t;
+ ts.tv_nsec = 0;
+ put_long_date_timespec(p, ts);
+}
+
+/****************************************************************************
+ Return the best approximation to a 'create time' under UNIX from a stat
+ structure.
+****************************************************************************/
+
+static time_t calc_create_time(const SMB_STRUCT_STAT *st)
+{
+ time_t ret, ret1;
+
+ 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;
+}
+
+/****************************************************************************
+ Return the 'create time' from a stat struct if it exists (birthtime) or else
+ use the best approximation.
+****************************************************************************/
+
+struct timespec get_create_timespec(const SMB_STRUCT_STAT *pst,bool fake_dirs)
+{
+ struct timespec ret;
+
+ if(S_ISDIR(pst->st_mode) && fake_dirs) {
+ ret.tv_sec = 315493200L; /* 1/1/1980 */
+ ret.tv_nsec = 0;
+ return ret;
+ }
+
+#if defined(HAVE_STAT_ST_BIRTHTIMESPEC)
+ ret = pst->st_birthtimespec;
+#elif defined(HAVE_STAT_ST_BIRTHTIMENSEC)
+ ret.tv_sec = pst->st_birthtime;
+ ret.tv_nsec = pst->st_birthtimenspec;
+#elif defined(HAVE_STAT_ST_BIRTHTIME)
+ ret.tv_sec = pst->st_birthtime;
+ ret.tv_nsec = 0;
+#else
+ ret.tv_sec = calc_create_time(pst);
+ ret.tv_nsec = 0;
+#endif
+
+ /* Deal with systems that don't initialize birthtime correctly.
+ * Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
+ */
+ if (null_timespec(ret)) {
+ ret.tv_sec = calc_create_time(pst);
+ ret.tv_nsec = 0;
+ }
+ return ret;
+}
+
+/****************************************************************************
+ Get/Set all the possible time fields from a stat struct as a timespec.
+****************************************************************************/
+
+struct timespec get_atimespec(const SMB_STRUCT_STAT *pst)
+{
+#if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
+ struct timespec ret;
+
+ /* Old system - no ns timestamp. */
+ ret.tv_sec = pst->st_atime;
+ ret.tv_nsec = 0;
+ return ret;
+#else
+#if defined(HAVE_STAT_ST_ATIM)
+ return pst->st_atim;
+#elif defined(HAVE_STAT_ST_ATIMENSEC)
+ struct timespec ret;
+ ret.tv_sec = pst->st_atime;
+ ret.tv_nsec = pst->st_atimensec;
+ return ret;
+#else
+#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
+#endif
+#endif
+}
+
+void set_atimespec(SMB_STRUCT_STAT *pst, struct timespec ts)
+{
+#if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
+ /* Old system - no ns timestamp. */
+ pst->st_atime = ts.tv_sec;
+#else
+#if defined(HAVE_STAT_ST_ATIM)
+ pst->st_atim = ts;
+#elif defined(HAVE_STAT_ST_ATIMENSEC)
+ pst->st_atime = ts.tv_sec;
+ pst->st_atimensec = ts.tv_nsec
+#else
+#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
+#endif
+#endif
+}
+
+struct timespec get_mtimespec(const SMB_STRUCT_STAT *pst)
+{
+#if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
+ struct timespec ret;
+
+ /* Old system - no ns timestamp. */
+ ret.tv_sec = pst->st_mtime;
+ ret.tv_nsec = 0;
+ return ret;
+#else
+#if defined(HAVE_STAT_ST_MTIM)
+ return pst->st_mtim;
+#elif defined(HAVE_STAT_ST_MTIMENSEC)
+ struct timespec ret;
+ ret.tv_sec = pst->st_mtime;
+ ret.tv_nsec = pst->st_mtimensec;
+ return ret;
+#else
+#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
+#endif
+#endif
+}
+
+void set_mtimespec(SMB_STRUCT_STAT *pst, struct timespec ts)
+{
+#if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
+ /* Old system - no ns timestamp. */
+ pst->st_mtime = ts.tv_sec;
+#else
+#if defined(HAVE_STAT_ST_MTIM)
+ pst->st_mtim = ts;
+#elif defined(HAVE_STAT_ST_MTIMENSEC)
+ pst->st_mtime = ts.tv_sec;
+ pst->st_mtimensec = ts.tv_nsec
+#else
+#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
+#endif
+#endif
+}
+
+struct timespec get_ctimespec(const SMB_STRUCT_STAT *pst)
+{
+#if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
+ struct timespec ret;
+
+ /* Old system - no ns timestamp. */
+ ret.tv_sec = pst->st_ctime;
+ ret.tv_nsec = 0;
+ return ret;
+#else
+#if defined(HAVE_STAT_ST_CTIM)
+ return pst->st_ctim;
+#elif defined(HAVE_STAT_ST_CTIMENSEC)
+ struct timespec ret;
+ ret.tv_sec = pst->st_ctime;
+ ret.tv_nsec = pst->st_ctimensec;
+ return ret;
+#else
+#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
+#endif
+#endif
+}
+
+void set_ctimespec(SMB_STRUCT_STAT *pst, struct timespec ts)
+{
+#if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
+ /* Old system - no ns timestamp. */
+ pst->st_ctime = ts.tv_sec;
+#else
+#if defined(HAVE_STAT_ST_CTIM)
+ pst->st_ctim = ts;
+#elif defined(HAVE_STAT_ST_CTIMENSEC)
+ pst->st_ctime = ts.tv_sec;
+ pst->st_ctimensec = ts.tv_nsec
+#else
+#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
+#endif
+#endif
+}
+
+void dos_filetime_timespec(struct timespec *tsp)
+{
+ tsp->tv_sec &= ~1;
+ tsp->tv_nsec = 0;
+}
+
+/*******************************************************************
+ Create a unix date (int GMT) from a dos date (which is actually in
+ localtime).
+********************************************************************/
+
+static time_t make_unix_date(const void *date_ptr, int zone_offset)
+{
+ 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;
+
+ ret = timegm(&t);
+
+ ret += zone_offset;
+
+ return(ret);
+}
+
+/*******************************************************************
+ Like make_unix_date() but the words are reversed.
+********************************************************************/
+
+static time_t make_unix_date2(const void *date_ptr, int zone_offset)
+{
+ uint32 x,x2;
+
+ x = IVAL(date_ptr,0);
+ x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+ SIVAL(&x,0,x2);
+
+ return(make_unix_date((const void *)&x, zone_offset));
+}
+
+/*******************************************************************
+ Create a unix GMT date from a dos date in 32 bit "unix like" format
+ these generally arrive as localtimes, with corresponding DST.
+******************************************************************/
+
+static time_t make_unix_date3(const void *date_ptr, int zone_offset)
+{
+ time_t t = (time_t)IVAL(date_ptr,0);
+ if (!null_mtime(t)) {
+ t += zone_offset;
+ }
+ return(t);
+}
+
+time_t srv_make_unix_date(const void *date_ptr)
+{
+ return make_unix_date(date_ptr, server_zone_offset);
+}
+
+time_t srv_make_unix_date2(const void *date_ptr)
+{
+ return make_unix_date2(date_ptr, server_zone_offset);
+}
+
+time_t srv_make_unix_date3(const void *date_ptr)
+{
+ return make_unix_date3(date_ptr, server_zone_offset);
+}
+
+time_t convert_timespec_to_time_t(struct timespec ts)
+{
+ /* 1 ns == 1,000,000,000 - one thousand millionths of a second.
+ increment if it's greater than 500 millionth of a second. */
+ if (ts.tv_nsec > 500000000) {
+ return ts.tv_sec + 1;
+ }
+ return ts.tv_sec;
+}
+
+struct timespec convert_time_t_to_timespec(time_t t)
+{
+ struct timespec ts;
+ ts.tv_sec = t;
+ ts.tv_nsec = 0;
+ return ts;
+}
+
+/****************************************************************************
+ Convert a normalized timeval to a timespec.
+****************************************************************************/
+
+struct timespec convert_timeval_to_timespec(const struct timeval tv)
+{
+ struct timespec ts;
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ return ts;
+}
+
+/****************************************************************************
+ Convert a normalized timespec to a timeval.
+****************************************************************************/
+
+struct timeval convert_timespec_to_timeval(const struct timespec ts)
+{
+ struct timeval tv;
+ tv.tv_sec = ts.tv_sec;
+ tv.tv_usec = ts.tv_nsec / 1000;
+ return tv;
+}
+
+/****************************************************************************
+ Return a timespec for the current time
+****************************************************************************/
+
+struct timespec timespec_current(void)
+{
+ struct timeval tv;
+ struct timespec ts;
+ GetTimeOfDay(&tv);
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ return ts;
+}
+
+/****************************************************************************
+ Return the lesser of two timespecs.
+****************************************************************************/
+
+struct timespec timespec_min(const struct timespec *ts1,
+ const struct timespec *ts2)
+{
+ if (ts1->tv_sec < ts2->tv_sec) return *ts1;
+ if (ts1->tv_sec > ts2->tv_sec) return *ts2;
+ if (ts1->tv_nsec < ts2->tv_nsec) return *ts1;
+ return *ts2;
+}
+
+/****************************************************************************
+ compare two timespec structures.
+ Return -1 if ts1 < ts2
+ Return 0 if ts1 == ts2
+ Return 1 if ts1 > ts2
+****************************************************************************/
+
+int timespec_compare(const struct timespec *ts1, const struct timespec *ts2)
+{
+ if (ts1->tv_sec > ts2->tv_sec) return 1;
+ if (ts1->tv_sec < ts2->tv_sec) return -1;
+ if (ts1->tv_nsec > ts2->tv_nsec) return 1;
+ if (ts1->tv_nsec < ts2->tv_nsec) return -1;
+ return 0;
+}
+
+/****************************************************************************
+ Interprets an nt time into a unix struct timespec.
+ Differs from nt_time_to_unix in that an 8 byte value of 0xffffffffffffffff
+ will be returned as (time_t)-1, whereas nt_time_to_unix returns 0 in this case.
+****************************************************************************/
+
+struct timespec interpret_long_date(const char *p)
+{
+ NTTIME nt;
+ nt = IVAL(p,0) + ((uint64_t)IVAL(p,4) << 32);
+ if (nt == (uint64_t)-1) {
+ struct timespec ret;
+ ret.tv_sec = (time_t)-1;
+ ret.tv_nsec = 0;
+ return ret;
+ }
+ return nt_time_to_unix_timespec(&nt);
+}
+
+/***************************************************************************
+ Client versions of the above functions.
+***************************************************************************/
+
+void cli_put_dos_date(struct cli_state *cli, char *buf, int offset, time_t unixdate)
+{
+ put_dos_date(buf, offset, unixdate, cli->serverzone);
+}
+
+void cli_put_dos_date2(struct cli_state *cli, char *buf, int offset, time_t unixdate)
+{
+ put_dos_date2(buf, offset, unixdate, cli->serverzone);
+}
+
+void cli_put_dos_date3(struct cli_state *cli, char *buf, int offset, time_t unixdate)
+{
+ put_dos_date3(buf, offset, unixdate, cli->serverzone);
+}
+
+time_t cli_make_unix_date(struct cli_state *cli, const void *date_ptr)
+{
+ return make_unix_date(date_ptr, cli->serverzone);
+}
+
+time_t cli_make_unix_date2(struct cli_state *cli, const void *date_ptr)
+{
+ return make_unix_date2(date_ptr, cli->serverzone);
+}
+
+time_t cli_make_unix_date3(struct cli_state *cli, const void *date_ptr)
+{
+ return make_unix_date3(date_ptr, cli->serverzone);
+}
+
+/* Large integer version. */
+struct timespec nt_time_to_unix_timespec(NTTIME *nt)
+{
+ int64 d;
+ struct timespec ret;
+
+ if (*nt == 0 || *nt == (int64)-1) {
+ ret.tv_sec = 0;
+ ret.tv_nsec = 0;
+ return ret;
+ }
+
+ d = (int64)*nt;
+ /* d is now in 100ns units, since jan 1st 1601".
+ Save off the ns fraction. */
+
+ /*
+ * Take the last seven decimal digits and multiply by 100.
+ * to convert from 100ns units to 1ns units.
+ */
+ ret.tv_nsec = (long) ((d % (1000 * 1000 * 10)) * 100);
+
+ /* Convert to seconds */
+ d /= 1000*1000*10;
+
+ /* Now adjust by 369 years to make the secs since 1970 */
+ d -= TIME_FIXUP_CONSTANT_INT;
+
+ if (d <= (int64)TIME_T_MIN) {
+ ret.tv_sec = TIME_T_MIN;
+ ret.tv_nsec = 0;
+ return ret;
+ }
+
+ if (d >= (int64)TIME_T_MAX) {
+ ret.tv_sec = TIME_T_MAX;
+ ret.tv_nsec = 0;
+ return ret;
+ }
+
+ ret.tv_sec = (time_t)d;
+ return ret;
+}
+/****************************************************************************
+ Check if two NTTIMEs are the same.
+****************************************************************************/
+
+bool nt_time_equals(const NTTIME *nt1, const NTTIME *nt2)
+{
+ return (*nt1 == *nt2);
+}
+
+/*******************************************************************
+ Re-read the smb serverzone value.
+******************************************************************/
+
+static struct timeval start_time_hires;
+
+void TimeInit(void)
+{
+ set_server_zone_offset(time(NULL));
+
+ DEBUG(4,("TimeInit: Serverzone is %d\n", server_zone_offset));
+
+ /* Save the start time of this process. */
+ if (start_time_hires.tv_sec == 0 && start_time_hires.tv_usec == 0) {
+ GetTimeOfDay(&start_time_hires);
+ }
+}
+
+/**********************************************************************
+ Return a timeval struct of the uptime of this process. As TimeInit is
+ done before a daemon fork then this is the start time from the parent
+ daemon start. JRA.
+***********************************************************************/
+
+void get_process_uptime(struct timeval *ret_time)
+{
+ struct timeval time_now_hires;
+
+ GetTimeOfDay(&time_now_hires);
+ ret_time->tv_sec = time_now_hires.tv_sec - start_time_hires.tv_sec;
+ if (time_now_hires.tv_usec < start_time_hires.tv_usec) {
+ ret_time->tv_sec -= 1;
+ ret_time->tv_usec = 1000000 + (time_now_hires.tv_usec - start_time_hires.tv_usec);
+ } else {
+ ret_time->tv_usec = time_now_hires.tv_usec - start_time_hires.tv_usec;
+ }
+}
+
+/****************************************************************************
+ Convert a NTTIME structure to a time_t.
+ It's originally in "100ns units".
+
+ This is an absolute version of the one above.
+ By absolute I mean, it doesn't adjust from 1/1/1601 to 1/1/1970
+ if the NTTIME was 5 seconds, the time_t is 5 seconds. JFM
+****************************************************************************/
+
+time_t nt_time_to_unix_abs(const NTTIME *nt)
+{
+ uint64 d;
+
+ if (*nt == 0) {
+ return (time_t)0;
+ }
+
+ if (*nt == (uint64)-1) {
+ return (time_t)-1;
+ }
+
+ if (*nt == NTTIME_INFINITY) {
+ return (time_t)-1;
+ }
+
+ /* reverse the time */
+ /* it's a negative value, turn it to positive */
+ d=~*nt;
+
+ d += 1000*1000*10/2;
+ d /= 1000*1000*10;
+
+ if (!(TIME_T_MIN <= ((time_t)d) && ((time_t)d) <= TIME_T_MAX)) {
+ return (time_t)0;
+ }
+
+ return (time_t)d;
+}
+
+time_t uint64s_nt_time_to_unix_abs(const uint64_t *src)
+{
+ NTTIME nttime;
+ nttime = *src;
+ return nt_time_to_unix_abs(&nttime);
+}
+
+/****************************************************************************
+ Put a 8 byte filetime from a struct timespec. Uses GMT.
+****************************************************************************/
+
+void unix_timespec_to_nt_time(NTTIME *nt, struct timespec ts)
+{
+ uint64 d;
+
+ if (ts.tv_sec ==0 && ts.tv_nsec == 0) {
+ *nt = 0;
+ return;
+ }
+ if (ts.tv_sec == TIME_T_MAX) {
+ *nt = 0x7fffffffffffffffLL;
+ return;
+ }
+ if (ts.tv_sec == (time_t)-1) {
+ *nt = (uint64)-1;
+ return;
+ }
+
+ d = ts.tv_sec;
+ d += TIME_FIXUP_CONSTANT_INT;
+ d *= 1000*1000*10;
+ /* d is now in 100ns units. */
+ d += (ts.tv_nsec / 100);
+
+ *nt = d;
+}
+
+/****************************************************************************
+ Convert a time_t to a NTTIME structure
+
+ This is an absolute version of the one above.
+ By absolute I mean, it doesn't adjust from 1/1/1970 to 1/1/1601
+ If the time_t was 5 seconds, the NTTIME is 5 seconds. JFM
+****************************************************************************/
+
+void unix_to_nt_time_abs(NTTIME *nt, time_t t)
+{
+ double d;
+
+ if (t==0) {
+ *nt = 0;
+ return;
+ }
+
+ if (t == TIME_T_MAX) {
+ *nt = 0x7fffffffffffffffLL;
+ return;
+ }
+
+ if (t == (time_t)-1) {
+ /* that's what NT uses for infinite */
+ *nt = NTTIME_INFINITY;
+ return;
+ }
+
+ d = (double)(t);
+ d *= 1.0e7;
+
+ *nt = (NTTIME)d;
+
+ /* convert to a negative value */
+ *nt=~*nt;
+}
+
+
+/****************************************************************************
+ Check if it's a null mtime.
+****************************************************************************/
+
+bool null_mtime(time_t mtime)
+{
+ if (mtime == 0 || mtime == (time_t)0xFFFFFFFF || mtime == (time_t)-1)
+ return(True);
+ return(False);
+}
+
+/****************************************************************************
+ Utility function that always returns a const string even if localtime
+ and asctime fail.
+****************************************************************************/
+
+const char *time_to_asc(const time_t t)
+{
+ const char *asct;
+ struct tm *lt = localtime(&t);
+
+ if (!lt) {
+ return "unknown time";
+ }
+
+ asct = asctime(lt);
+ if (!asct) {
+ return "unknown time";
+ }
+ return asct;
+}
+
+const char *display_time(NTTIME nttime)
+{
+ float high;
+ float low;
+ int sec;
+ int days, hours, mins, secs;
+
+ if (nttime==0)
+ return "Now";
+
+ if (nttime==NTTIME_INFINITY)
+ return "Never";
+
+ high = 65536;
+ high = high/10000;
+ high = high*65536;
+ high = high/1000;
+ high = high * (~(nttime >> 32));
+
+ low = ~(nttime & 0xFFFFFFFF);
+ low = low/(1000*1000*10);
+
+ sec=(int)(high+low);
+
+ days=sec/(60*60*24);
+ hours=(sec - (days*60*60*24)) / (60*60);
+ mins=(sec - (days*60*60*24) - (hours*60*60) ) / 60;
+ secs=sec - (days*60*60*24) - (hours*60*60) - (mins*60);
+
+ return talloc_asprintf(talloc_tos(), "%u days, %u hours, %u minutes, "
+ "%u seconds", days, hours, mins, secs);
+}
+
+bool nt_time_is_set(const NTTIME *nt)
+{
+ if (*nt == 0x7FFFFFFFFFFFFFFFLL) {
+ return False;
+ }
+
+ if (*nt == NTTIME_INFINITY) {
+ return False;
+ }
+
+ return True;
+}
diff --git a/source3/lib/ufc.c b/source3/lib/ufc.c
new file mode 100644
index 0000000000..89329808c9
--- /dev/null
+++ b/source3/lib/ufc.c
@@ -0,0 +1,770 @@
+/*
+ This bit of code was derived from the UFC-crypt package which
+ carries the following copyright
+
+ Modified for use by Samba by Andrew Tridgell, October 1994
+
+ Note that this routine is only faster on some machines. Under Linux 1.1.51
+ libc 4.5.26 I actually found this routine to be slightly slower.
+
+ Under SunOS I found a huge speedup by using these routines
+ (a factor of 20 or so)
+
+ Warning: I've had a report from Steve Kennedy <steve@gbnet.org>
+ that this crypt routine may sometimes get the wrong answer. Only
+ use UFC_CRYT if you really need it.
+
+*/
+
+#include "includes.h"
+
+#ifndef HAVE_CRYPT
+
+/*
+ * UFC-crypt: ultra fast crypt(3) implementation
+ *
+ * Copyright (C) 1991-1998, Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 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 Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * @(#)crypt_util.c 2.31 02/08/92
+ *
+ * Support routines
+ *
+ */
+
+
+#ifndef long32
+#define long32 int32
+#endif
+
+#ifndef long64
+#define long64 int64
+#endif
+
+#ifndef ufc_long
+#define ufc_long unsigned
+#endif
+
+#ifndef _UFC_64_
+#define _UFC_32_
+#endif
+
+/*
+ * Permutation done once on the 56 bit
+ * key derived from the original 8 byte ASCII key.
+ */
+static int pc1[56] = {
+ 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
+ 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
+};
+
+/*
+ * How much to rotate each 28 bit half of the pc1 permutated
+ * 56 bit key before using pc2 to give the i' key
+ */
+static int rots[16] = {
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+};
+
+/*
+ * Permutation giving the key
+ * of the i' DES round
+ */
+static int pc2[48] = {
+ 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
+};
+
+/*
+ * The E expansion table which selects
+ * bits from the 32 bit intermediate result.
+ */
+static int esel[48] = {
+ 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9,
+ 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
+ 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
+ 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1
+};
+static int e_inverse[64];
+
+/*
+ * Permutation done on the
+ * result of sbox lookups
+ */
+static int perm32[32] = {
+ 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
+ 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
+};
+
+/*
+ * The sboxes
+ */
+static int sbox[8][4][16]= {
+ { { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 },
+ { 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 },
+ { 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0 },
+ { 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 }
+ },
+
+ { { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 },
+ { 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 },
+ { 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15 },
+ { 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 }
+ },
+
+ { { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 },
+ { 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 },
+ { 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7 },
+ { 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 }
+ },
+
+ { { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 },
+ { 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 },
+ { 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4 },
+ { 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 }
+ },
+
+ { { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 },
+ { 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 },
+ { 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14 },
+ { 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 }
+ },
+
+ { { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 },
+ { 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 },
+ { 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6 },
+ { 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 }
+ },
+
+ { { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 },
+ { 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 },
+ { 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2 },
+ { 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 }
+ },
+
+ { { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 },
+ { 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 },
+ { 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 },
+ { 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 }
+ }
+};
+
+/*
+ * This is the final
+ * permutation matrix
+ */
+static int final_perm[64] = {
+ 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
+ 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
+ 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
+ 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25
+};
+
+/*
+ * The 16 DES keys in BITMASK format
+ */
+#ifdef _UFC_32_
+long32 _ufc_keytab[16][2];
+#endif
+
+#ifdef _UFC_64_
+long64 _ufc_keytab[16];
+#endif
+
+
+#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.')
+#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
+
+/* Macro to set a bit (0..23) */
+#define BITMASK(i) ( (1<<(11-(i)%12+3)) << ((i)<12?16:0) )
+
+/*
+ * sb arrays:
+ *
+ * Workhorses of the inner loop of the DES implementation.
+ * They do sbox lookup, shifting of this value, 32 bit
+ * permutation and E permutation for the next round.
+ *
+ * Kept in 'BITMASK' format.
+ */
+
+#ifdef _UFC_32_
+long32 _ufc_sb0[8192], _ufc_sb1[8192], _ufc_sb2[8192], _ufc_sb3[8192];
+static long32 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3};
+#endif
+
+#ifdef _UFC_64_
+long64 _ufc_sb0[4096], _ufc_sb1[4096], _ufc_sb2[4096], _ufc_sb3[4096];
+static long64 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3};
+#endif
+
+/*
+ * eperm32tab: do 32 bit permutation and E selection
+ *
+ * The first index is the byte number in the 32 bit value to be permuted
+ * - second - is the value of this byte
+ * - third - selects the two 32 bit values
+ *
+ * The table is used and generated internally in init_des to speed it up
+ */
+static ufc_long eperm32tab[4][256][2];
+
+/*
+ * do_pc1: permform pc1 permutation in the key schedule generation.
+ *
+ * The first index is the byte number in the 8 byte ASCII key
+ * - second - - the two 28 bits halfs of the result
+ * - third - selects the 7 bits actually used of each byte
+ *
+ * The result is kept with 28 bit per 32 bit with the 4 most significant
+ * bits zero.
+ */
+static ufc_long do_pc1[8][2][128];
+
+/*
+ * do_pc2: permform pc2 permutation in the key schedule generation.
+ *
+ * The first index is the septet number in the two 28 bit intermediate values
+ * - second - - - septet values
+ *
+ * Knowledge of the structure of the pc2 permutation is used.
+ *
+ * The result is kept with 28 bit per 32 bit with the 4 most significant
+ * bits zero.
+ */
+static ufc_long do_pc2[8][128];
+
+/*
+ * efp: undo an extra e selection and do final
+ * permutation giving the DES result.
+ *
+ * Invoked 6 bit a time on two 48 bit values
+ * giving two 32 bit longs.
+ */
+static ufc_long efp[16][64][2];
+
+static unsigned char bytemask[8] = {
+ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
+};
+
+static ufc_long longmask[32] = {
+ 0x80000000, 0x40000000, 0x20000000, 0x10000000,
+ 0x08000000, 0x04000000, 0x02000000, 0x01000000,
+ 0x00800000, 0x00400000, 0x00200000, 0x00100000,
+ 0x00080000, 0x00040000, 0x00020000, 0x00010000,
+ 0x00008000, 0x00004000, 0x00002000, 0x00001000,
+ 0x00000800, 0x00000400, 0x00000200, 0x00000100,
+ 0x00000080, 0x00000040, 0x00000020, 0x00000010,
+ 0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+
+/*
+ * Silly rewrite of 'bzero'. I do so
+ * because some machines don't have
+ * bzero and some don't have memset.
+ */
+
+static void clearmem(char *start, int cnt)
+ { while(cnt--)
+ *start++ = '\0';
+ }
+
+static int initialized = 0;
+
+/* lookup a 6 bit value in sbox */
+
+#define s_lookup(i,s) sbox[(i)][(((s)>>4) & 0x2)|((s) & 0x1)][((s)>>1) & 0xf];
+
+/*
+ * Initialize unit - may be invoked directly
+ * by fcrypt users.
+ */
+
+static void ufc_init_des(void)
+ { int comes_from_bit;
+ int bit, sg;
+ ufc_long j;
+ ufc_long mask1, mask2;
+
+ /*
+ * Create the do_pc1 table used
+ * to affect pc1 permutation
+ * when generating keys
+ */
+ for(bit = 0; bit < 56; bit++) {
+ comes_from_bit = pc1[bit] - 1;
+ mask1 = bytemask[comes_from_bit % 8 + 1];
+ mask2 = longmask[bit % 28 + 4];
+ for(j = 0; j < 128; j++) {
+ if(j & mask1)
+ do_pc1[comes_from_bit / 8][bit / 28][j] |= mask2;
+ }
+ }
+
+ /*
+ * Create the do_pc2 table used
+ * to affect pc2 permutation when
+ * generating keys
+ */
+ for(bit = 0; bit < 48; bit++) {
+ comes_from_bit = pc2[bit] - 1;
+ mask1 = bytemask[comes_from_bit % 7 + 1];
+ mask2 = BITMASK(bit % 24);
+ for(j = 0; j < 128; j++) {
+ if(j & mask1)
+ do_pc2[comes_from_bit / 7][j] |= mask2;
+ }
+ }
+
+ /*
+ * Now generate the table used to do combined
+ * 32 bit permutation and e expansion
+ *
+ * We use it because we have to permute 16384 32 bit
+ * longs into 48 bit in order to initialize sb.
+ *
+ * Looping 48 rounds per permutation becomes
+ * just too slow...
+ *
+ */
+
+ clearmem((char*)eperm32tab, sizeof(eperm32tab));
+
+ for(bit = 0; bit < 48; bit++) {
+ ufc_long inner_mask1,comes_from;
+
+ comes_from = perm32[esel[bit]-1]-1;
+ inner_mask1 = bytemask[comes_from % 8];
+
+ for(j = 256; j--;) {
+ if(j & inner_mask1)
+ eperm32tab[comes_from / 8][j][bit / 24] |= BITMASK(bit % 24);
+ }
+ }
+
+ /*
+ * Create the sb tables:
+ *
+ * For each 12 bit segment of an 48 bit intermediate
+ * result, the sb table precomputes the two 4 bit
+ * values of the sbox lookups done with the two 6
+ * bit halves, shifts them to their proper place,
+ * sends them through perm32 and finally E expands
+ * them so that they are ready for the next
+ * DES round.
+ *
+ */
+ for(sg = 0; sg < 4; sg++) {
+ int j1, j2;
+ int s1, s2;
+
+ for(j1 = 0; j1 < 64; j1++) {
+ s1 = s_lookup(2 * sg, j1);
+ for(j2 = 0; j2 < 64; j2++) {
+ ufc_long to_permute, inx;
+
+ s2 = s_lookup(2 * sg + 1, j2);
+ to_permute = ((s1 << 4) | s2) << (24 - 8 * sg);
+
+#ifdef _UFC_32_
+ inx = ((j1 << 6) | j2) << 1;
+ sb[sg][inx ] = eperm32tab[0][(to_permute >> 24) & 0xff][0];
+ sb[sg][inx+1] = eperm32tab[0][(to_permute >> 24) & 0xff][1];
+ sb[sg][inx ] |= eperm32tab[1][(to_permute >> 16) & 0xff][0];
+ sb[sg][inx+1] |= eperm32tab[1][(to_permute >> 16) & 0xff][1];
+ sb[sg][inx ] |= eperm32tab[2][(to_permute >> 8) & 0xff][0];
+ sb[sg][inx+1] |= eperm32tab[2][(to_permute >> 8) & 0xff][1];
+ sb[sg][inx ] |= eperm32tab[3][(to_permute) & 0xff][0];
+ sb[sg][inx+1] |= eperm32tab[3][(to_permute) & 0xff][1];
+#endif
+#ifdef _UFC_64_
+ inx = ((j1 << 6) | j2);
+ sb[sg][inx] =
+ ((long64)eperm32tab[0][(to_permute >> 24) & 0xff][0] << 32) |
+ (long64)eperm32tab[0][(to_permute >> 24) & 0xff][1];
+ sb[sg][inx] |=
+ ((long64)eperm32tab[1][(to_permute >> 16) & 0xff][0] << 32) |
+ (long64)eperm32tab[1][(to_permute >> 16) & 0xff][1];
+ sb[sg][inx] |=
+ ((long64)eperm32tab[2][(to_permute >> 8) & 0xff][0] << 32) |
+ (long64)eperm32tab[2][(to_permute >> 8) & 0xff][1];
+ sb[sg][inx] |=
+ ((long64)eperm32tab[3][(to_permute) & 0xff][0] << 32) |
+ (long64)eperm32tab[3][(to_permute) & 0xff][1];
+#endif
+ }
+ }
+ }
+
+ /*
+ * Create an inverse matrix for esel telling
+ * where to plug out bits if undoing it
+ */
+ for(bit=48; bit--;) {
+ e_inverse[esel[bit] - 1 ] = bit;
+ e_inverse[esel[bit] - 1 + 32] = bit + 48;
+ }
+
+ /*
+ * create efp: the matrix used to
+ * undo the E expansion and effect final permutation
+ */
+ clearmem((char*)efp, sizeof efp);
+ for(bit = 0; bit < 64; bit++) {
+ int o_bit, o_long;
+ ufc_long word_value, inner_mask1, inner_mask2;
+ int comes_from_f_bit, comes_from_e_bit;
+ int comes_from_word, bit_within_word;
+
+ /* See where bit i belongs in the two 32 bit long's */
+ o_long = bit / 32; /* 0..1 */
+ o_bit = bit % 32; /* 0..31 */
+
+ /*
+ * And find a bit in the e permutated value setting this bit.
+ *
+ * Note: the e selection may have selected the same bit several
+ * times. By the initialization of e_inverse, we only look
+ * for one specific instance.
+ */
+ comes_from_f_bit = final_perm[bit] - 1; /* 0..63 */
+ comes_from_e_bit = e_inverse[comes_from_f_bit]; /* 0..95 */
+ comes_from_word = comes_from_e_bit / 6; /* 0..15 */
+ bit_within_word = comes_from_e_bit % 6; /* 0..5 */
+
+ inner_mask1 = longmask[bit_within_word + 26];
+ inner_mask2 = longmask[o_bit];
+
+ for(word_value = 64; word_value--;) {
+ if(word_value & inner_mask1)
+ efp[comes_from_word][word_value][o_long] |= inner_mask2;
+ }
+ }
+ initialized++;
+ }
+
+/*
+ * Process the elements of the sb table permuting the
+ * bits swapped in the expansion by the current salt.
+ */
+
+#ifdef _UFC_32_
+static void shuffle_sb(long32 *k, ufc_long saltbits)
+ { ufc_long j;
+ long32 x;
+ for(j=4096; j--;) {
+ x = (k[0] ^ k[1]) & (long32)saltbits;
+ *k++ ^= x;
+ *k++ ^= x;
+ }
+ }
+#endif
+
+#ifdef _UFC_64_
+static void shuffle_sb(long64 *k, ufc_long saltbits)
+ { ufc_long j;
+ long64 x;
+ for(j=4096; j--;) {
+ x = ((*k >> 32) ^ *k) & (long64)saltbits;
+ *k++ ^= (x << 32) | x;
+ }
+ }
+#endif
+
+/*
+ * Setup the unit for a new salt
+ * Hopefully we'll not see a new salt in each crypt call.
+ */
+
+static unsigned char current_salt[3] = "&&"; /* invalid value */
+static ufc_long current_saltbits = 0;
+static int direction = 0;
+
+static void setup_salt(const char *s1)
+ { ufc_long i, j, saltbits;
+ const unsigned char *s2 = (const unsigned char *)s1;
+
+ if(!initialized)
+ ufc_init_des();
+
+ if(s2[0] == current_salt[0] && s2[1] == current_salt[1])
+ return;
+ current_salt[0] = s2[0]; current_salt[1] = s2[1];
+
+ /*
+ * This is the only crypt change to DES:
+ * entries are swapped in the expansion table
+ * according to the bits set in the salt.
+ */
+ saltbits = 0;
+ for(i = 0; i < 2; i++) {
+ long c=ascii_to_bin(s2[i]);
+ if(c < 0 || c > 63)
+ c = 0;
+ for(j = 0; j < 6; j++) {
+ if((c >> j) & 0x1)
+ saltbits |= BITMASK(6 * i + j);
+ }
+ }
+
+ /*
+ * Permute the sb table values
+ * to reflect the changed e
+ * selection table
+ */
+ shuffle_sb(_ufc_sb0, current_saltbits ^ saltbits);
+ shuffle_sb(_ufc_sb1, current_saltbits ^ saltbits);
+ shuffle_sb(_ufc_sb2, current_saltbits ^ saltbits);
+ shuffle_sb(_ufc_sb3, current_saltbits ^ saltbits);
+
+ current_saltbits = saltbits;
+ }
+
+static void ufc_mk_keytab(char *key)
+ { ufc_long v1, v2, *k1;
+ int i;
+#ifdef _UFC_32_
+ long32 v, *k2 = &_ufc_keytab[0][0];
+#endif
+#ifdef _UFC_64_
+ long64 v, *k2 = &_ufc_keytab[0];
+#endif
+
+ v1 = v2 = 0; k1 = &do_pc1[0][0][0];
+ for(i = 8; i--;) {
+ v1 |= k1[*key & 0x7f]; k1 += 128;
+ v2 |= k1[*key++ & 0x7f]; k1 += 128;
+ }
+
+ for(i = 0; i < 16; i++) {
+ k1 = &do_pc2[0][0];
+
+ v1 = (v1 << rots[i]) | (v1 >> (28 - rots[i]));
+ v = k1[(v1 >> 21) & 0x7f]; k1 += 128;
+ v |= k1[(v1 >> 14) & 0x7f]; k1 += 128;
+ v |= k1[(v1 >> 7) & 0x7f]; k1 += 128;
+ v |= k1[(v1 ) & 0x7f]; k1 += 128;
+
+#ifdef _UFC_32_
+ *k2++ = v;
+ v = 0;
+#endif
+#ifdef _UFC_64_
+ v <<= 32;
+#endif
+
+ v2 = (v2 << rots[i]) | (v2 >> (28 - rots[i]));
+ v |= k1[(v2 >> 21) & 0x7f]; k1 += 128;
+ v |= k1[(v2 >> 14) & 0x7f]; k1 += 128;
+ v |= k1[(v2 >> 7) & 0x7f]; k1 += 128;
+ v |= k1[(v2 ) & 0x7f];
+
+ *k2++ = v;
+ }
+
+ direction = 0;
+ }
+
+/*
+ * Undo an extra E selection and do final permutations
+ */
+
+ufc_long *_ufc_dofinalperm(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2)
+ { ufc_long v1, v2, x;
+ static ufc_long ary[2];
+
+ x = (l1 ^ l2) & current_saltbits; l1 ^= x; l2 ^= x;
+ x = (r1 ^ r2) & current_saltbits; r1 ^= x; r2 ^= x;
+
+ v1=v2=0; l1 >>= 3; l2 >>= 3; r1 >>= 3; r2 >>= 3;
+
+ v1 |= efp[15][ r2 & 0x3f][0]; v2 |= efp[15][ r2 & 0x3f][1];
+ v1 |= efp[14][(r2 >>= 6) & 0x3f][0]; v2 |= efp[14][ r2 & 0x3f][1];
+ v1 |= efp[13][(r2 >>= 10) & 0x3f][0]; v2 |= efp[13][ r2 & 0x3f][1];
+ v1 |= efp[12][(r2 >>= 6) & 0x3f][0]; v2 |= efp[12][ r2 & 0x3f][1];
+
+ v1 |= efp[11][ r1 & 0x3f][0]; v2 |= efp[11][ r1 & 0x3f][1];
+ v1 |= efp[10][(r1 >>= 6) & 0x3f][0]; v2 |= efp[10][ r1 & 0x3f][1];
+ v1 |= efp[ 9][(r1 >>= 10) & 0x3f][0]; v2 |= efp[ 9][ r1 & 0x3f][1];
+ v1 |= efp[ 8][(r1 >>= 6) & 0x3f][0]; v2 |= efp[ 8][ r1 & 0x3f][1];
+
+ v1 |= efp[ 7][ l2 & 0x3f][0]; v2 |= efp[ 7][ l2 & 0x3f][1];
+ v1 |= efp[ 6][(l2 >>= 6) & 0x3f][0]; v2 |= efp[ 6][ l2 & 0x3f][1];
+ v1 |= efp[ 5][(l2 >>= 10) & 0x3f][0]; v2 |= efp[ 5][ l2 & 0x3f][1];
+ v1 |= efp[ 4][(l2 >>= 6) & 0x3f][0]; v2 |= efp[ 4][ l2 & 0x3f][1];
+
+ v1 |= efp[ 3][ l1 & 0x3f][0]; v2 |= efp[ 3][ l1 & 0x3f][1];
+ v1 |= efp[ 2][(l1 >>= 6) & 0x3f][0]; v2 |= efp[ 2][ l1 & 0x3f][1];
+ v1 |= efp[ 1][(l1 >>= 10) & 0x3f][0]; v2 |= efp[ 1][ l1 & 0x3f][1];
+ v1 |= efp[ 0][(l1 >>= 6) & 0x3f][0]; v2 |= efp[ 0][ l1 & 0x3f][1];
+
+ ary[0] = v1; ary[1] = v2;
+ return ary;
+ }
+
+/*
+ * crypt only: convert from 64 bit to 11 bit ASCII
+ * prefixing with the salt
+ */
+
+static char *output_conversion(ufc_long v1, ufc_long v2, const char *salt)
+ { static char outbuf[14];
+ int i, s;
+
+ outbuf[0] = salt[0];
+ outbuf[1] = salt[1] ? salt[1] : salt[0];
+
+ for(i = 0; i < 5; i++)
+ outbuf[i + 2] = bin_to_ascii((v1 >> (26 - 6 * i)) & 0x3f);
+
+ s = (v2 & 0xf) << 2;
+ v2 = (v2 >> 2) | ((v1 & 0x3) << 30);
+
+ for(i = 5; i < 10; i++)
+ outbuf[i + 2] = bin_to_ascii((v2 >> (56 - 6 * i)) & 0x3f);
+
+ outbuf[12] = bin_to_ascii(s);
+ outbuf[13] = 0;
+
+ return outbuf;
+ }
+
+/*
+ * UNIX crypt function
+ */
+
+static ufc_long *_ufc_doit(ufc_long , ufc_long, ufc_long, ufc_long, ufc_long);
+
+char *ufc_crypt(const char *key,const char *salt)
+ { ufc_long *s;
+ char ktab[9];
+
+ /*
+ * Hack DES tables according to salt
+ */
+ setup_salt(salt);
+
+ /*
+ * Setup key schedule
+ */
+ clearmem(ktab, sizeof ktab);
+ StrnCpy(ktab, key, 8);
+ ufc_mk_keytab(ktab);
+
+ /*
+ * Go for the 25 DES encryptions
+ */
+ s = _ufc_doit((ufc_long)0, (ufc_long)0,
+ (ufc_long)0, (ufc_long)0, (ufc_long)25);
+
+ /*
+ * And convert back to 6 bit ASCII
+ */
+ return output_conversion(s[0], s[1], salt);
+ }
+
+
+#ifdef _UFC_32_
+
+/*
+ * 32 bit version
+ */
+
+extern long32 _ufc_keytab[16][2];
+extern long32 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[];
+
+#define SBA(sb, v) (*(long32*)((char*)(sb)+(v)))
+
+static ufc_long *_ufc_doit(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2, ufc_long itr)
+ { int i;
+ long32 s, *k;
+
+ while(itr--) {
+ k = &_ufc_keytab[0][0];
+ for(i=8; i--; ) {
+ s = *k++ ^ r1;
+ l1 ^= SBA(_ufc_sb1, s & 0xffff); l2 ^= SBA(_ufc_sb1, (s & 0xffff)+4);
+ l1 ^= SBA(_ufc_sb0, s >>= 16); l2 ^= SBA(_ufc_sb0, (s) +4);
+ s = *k++ ^ r2;
+ l1 ^= SBA(_ufc_sb3, s & 0xffff); l2 ^= SBA(_ufc_sb3, (s & 0xffff)+4);
+ l1 ^= SBA(_ufc_sb2, s >>= 16); l2 ^= SBA(_ufc_sb2, (s) +4);
+
+ s = *k++ ^ l1;
+ r1 ^= SBA(_ufc_sb1, s & 0xffff); r2 ^= SBA(_ufc_sb1, (s & 0xffff)+4);
+ r1 ^= SBA(_ufc_sb0, s >>= 16); r2 ^= SBA(_ufc_sb0, (s) +4);
+ s = *k++ ^ l2;
+ r1 ^= SBA(_ufc_sb3, s & 0xffff); r2 ^= SBA(_ufc_sb3, (s & 0xffff)+4);
+ r1 ^= SBA(_ufc_sb2, s >>= 16); r2 ^= SBA(_ufc_sb2, (s) +4);
+ }
+ s=l1; l1=r1; r1=s; s=l2; l2=r2; r2=s;
+ }
+ return _ufc_dofinalperm(l1, l2, r1, r2);
+ }
+
+#endif
+
+#ifdef _UFC_64_
+
+/*
+ * 64 bit version
+ */
+
+extern long64 _ufc_keytab[16];
+extern long64 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[];
+
+#define SBA(sb, v) (*(long64*)((char*)(sb)+(v)))
+
+static ufc_long *_ufc_doit(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2, ufc_long itr)
+ { int i;
+ long64 l, r, s, *k;
+
+ l = (((long64)l1) << 32) | ((long64)l2);
+ r = (((long64)r1) << 32) | ((long64)r2);
+
+ while(itr--) {
+ k = &_ufc_keytab[0];
+ for(i=8; i--; ) {
+ s = *k++ ^ r;
+ l ^= SBA(_ufc_sb3, (s >> 0) & 0xffff);
+ l ^= SBA(_ufc_sb2, (s >> 16) & 0xffff);
+ l ^= SBA(_ufc_sb1, (s >> 32) & 0xffff);
+ l ^= SBA(_ufc_sb0, (s >> 48) & 0xffff);
+
+ s = *k++ ^ l;
+ r ^= SBA(_ufc_sb3, (s >> 0) & 0xffff);
+ r ^= SBA(_ufc_sb2, (s >> 16) & 0xffff);
+ r ^= SBA(_ufc_sb1, (s >> 32) & 0xffff);
+ r ^= SBA(_ufc_sb0, (s >> 48) & 0xffff);
+ }
+ s=l; l=r; r=s;
+ }
+
+ l1 = l >> 32; l2 = l & 0xffffffff;
+ r1 = r >> 32; r2 = r & 0xffffffff;
+ return _ufc_dofinalperm(l1, l2, r1, r2);
+ }
+
+#endif
+
+
+#else
+ int ufc_dummy_procedure(void);
+ int ufc_dummy_procedure(void) {return 0;}
+#endif
diff --git a/source3/lib/username.c b/source3/lib/username.c
new file mode 100644
index 0000000000..3087bac0f4
--- /dev/null
+++ b/source3/lib/username.c
@@ -0,0 +1,196 @@
+/*
+ Unix SMB/CIFS implementation.
+ Username handling
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1997-2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* internal functions */
+static struct passwd *uname_string_combinations(char *s, TALLOC_CTX *mem_ctx,
+ struct passwd * (*fn) (TALLOC_CTX *mem_ctx, const char *),
+ int N);
+static struct passwd *uname_string_combinations2(char *s, TALLOC_CTX *mem_ctx, int offset,
+ struct passwd * (*fn) (TALLOC_CTX *mem_ctx, const char *),
+ int N);
+
+/****************************************************************************
+ Get a users home directory.
+****************************************************************************/
+
+char *get_user_home_dir(TALLOC_CTX *mem_ctx, const char *user)
+{
+ struct passwd *pass;
+ char *result;
+
+ /* Ensure the user exists. */
+
+ pass = Get_Pwnam_alloc(mem_ctx, user);
+
+ if (!pass)
+ return(NULL);
+
+ /* Return home directory from struct passwd. */
+
+ result = talloc_move(mem_ctx, &pass->pw_dir);
+
+ TALLOC_FREE(pass);
+ return result;
+}
+
+/****************************************************************************
+ * A wrapper for sys_getpwnam(). The following variations are tried:
+ * - as transmitted
+ * - in all lower case if this differs from transmitted
+ * - in all upper case if this differs from transmitted
+ * - using lp_usernamelevel() for permutations.
+****************************************************************************/
+
+static struct passwd *Get_Pwnam_internals(TALLOC_CTX *mem_ctx,
+ const char *user, char *user2)
+{
+ struct passwd *ret = NULL;
+
+ if (!user2 || !(*user2))
+ return(NULL);
+
+ if (!user || !(*user))
+ return(NULL);
+
+ /* Try in all lower case first as this is the most
+ common case on UNIX systems */
+ strlower_m(user2);
+ DEBUG(5,("Trying _Get_Pwnam(), username as lowercase is %s\n",user2));
+ ret = getpwnam_alloc(mem_ctx, user2);
+ if(ret)
+ goto done;
+
+ /* Try as given, if username wasn't originally lowercase */
+ if(strcmp(user, user2) != 0) {
+ DEBUG(5,("Trying _Get_Pwnam(), username as given is %s\n",
+ user));
+ ret = getpwnam_alloc(mem_ctx, user);
+ if(ret)
+ goto done;
+ }
+
+ /* Try as uppercase, if username wasn't originally uppercase */
+ strupper_m(user2);
+ if(strcmp(user, user2) != 0) {
+ DEBUG(5,("Trying _Get_Pwnam(), username as uppercase is %s\n",
+ user2));
+ ret = getpwnam_alloc(mem_ctx, user2);
+ if(ret)
+ goto done;
+ }
+
+ /* Try all combinations up to usernamelevel */
+ strlower_m(user2);
+ DEBUG(5,("Checking combinations of %d uppercase letters in %s\n",
+ lp_usernamelevel(), user2));
+ ret = uname_string_combinations(user2, mem_ctx, getpwnam_alloc,
+ lp_usernamelevel());
+
+done:
+ DEBUG(5,("Get_Pwnam_internals %s find user [%s]!\n",ret ?
+ "did":"didn't", user));
+
+ return ret;
+}
+
+/****************************************************************************
+ Get_Pwnam wrapper without modification.
+ NOTE: This with NOT modify 'user'!
+ This will return an allocated structure
+****************************************************************************/
+
+struct passwd *Get_Pwnam_alloc(TALLOC_CTX *mem_ctx, const char *user)
+{
+ fstring user2;
+ struct passwd *ret;
+
+ if ( *user == '\0' ) {
+ DEBUG(10,("Get_Pwnam: empty username!\n"));
+ return NULL;
+ }
+
+ fstrcpy(user2, user);
+
+ DEBUG(5,("Finding user %s\n", user));
+
+ ret = Get_Pwnam_internals(mem_ctx, user, user2);
+
+ return ret;
+}
+
+/* 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, TALLOC_CTX *mem_ctx,
+ int offset,
+ struct passwd *(*fn)(TALLOC_CTX *mem_ctx, const char *),
+ int N)
+{
+ ssize_t len = (ssize_t)strlen(s);
+ int i;
+ struct passwd *ret;
+
+ if (N <= 0 || offset >= len)
+ return(fn(mem_ctx, s));
+
+ for (i=offset;i<(len-(N-1));i++) {
+ char c = s[i];
+ if (!islower_ascii((int)c))
+ continue;
+ s[i] = toupper_ascii(c);
+ ret = uname_string_combinations2(s, mem_ctx, i+1, fn, N-1);
+ if(ret)
+ return(ret);
+ s[i] = c;
+ }
+ return(NULL);
+}
+
+/****************************************************************************
+ Apply a function to upper/lower case combinations
+ of a string and return true if one of them returns true.
+ Try all combinations with up to N uppercase letters.
+ offset is the first char to try and change (start with 0)
+ it assumes the string starts lowercased
+****************************************************************************/
+
+static struct passwd * uname_string_combinations(char *s, TALLOC_CTX *mem_ctx,
+ struct passwd * (*fn)(TALLOC_CTX *mem_ctx, const char *),
+ int N)
+{
+ int n;
+ struct passwd *ret;
+
+ for (n=1;n<=N;n++) {
+ ret = uname_string_combinations2(s,mem_ctx,0,fn,n);
+ if(ret)
+ return(ret);
+ }
+ return(NULL);
+}
+
diff --git a/source3/lib/util.c b/source3/lib/util.c
new file mode 100644
index 0000000000..ec43ea7037
--- /dev/null
+++ b/source3/lib/util.c
@@ -0,0 +1,3523 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2001-2007
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+ Copyright (C) James Peach 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern char *global_clobber_region_function;
+extern unsigned int global_clobber_region_line;
+
+/* Max allowable allococation - 256mb - 0x10000000 */
+#define MAX_ALLOC_SIZE (1024*1024*256)
+
+#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
+#ifdef WITH_NISPLUS_HOME
+#ifdef BROKEN_NISPLUS_INCLUDE_FILES
+/*
+ * The following lines are needed due to buggy include files
+ * in Solaris 2.6 which define GROUP in both /usr/include/sys/acl.h and
+ * also in /usr/include/rpcsvc/nis.h. The definitions conflict. JRA.
+ * Also GROUP_OBJ is defined as 0x4 in /usr/include/sys/acl.h and as
+ * an enum in /usr/include/rpcsvc/nis.h.
+ */
+
+#if defined(GROUP)
+#undef GROUP
+#endif
+
+#if defined(GROUP_OBJ)
+#undef GROUP_OBJ
+#endif
+
+#endif /* BROKEN_NISPLUS_INCLUDE_FILES */
+
+#include <rpcsvc/nis.h>
+
+#endif /* WITH_NISPLUS_HOME */
+#endif /* HAVE_NETGROUP && WITH_AUTOMOUNT */
+
+enum protocol_types Protocol = PROTOCOL_COREPLUS;
+
+/* this is used by the chaining code */
+int chain_size = 0;
+
+static enum remote_arch_types ra_type = RA_UNKNOWN;
+
+/***********************************************************************
+ Definitions for all names.
+***********************************************************************/
+
+static char *smb_myname;
+static char *smb_myworkgroup;
+static char *smb_scope;
+static int smb_num_netbios_names;
+static char **smb_my_netbios_names;
+
+/***********************************************************************
+ Allocate and set myname. Ensure upper case.
+***********************************************************************/
+
+bool set_global_myname(const char *myname)
+{
+ SAFE_FREE(smb_myname);
+ smb_myname = SMB_STRDUP(myname);
+ if (!smb_myname)
+ return False;
+ strupper_m(smb_myname);
+ return True;
+}
+
+const char *global_myname(void)
+{
+ return smb_myname;
+}
+
+/***********************************************************************
+ Allocate and set myworkgroup. Ensure upper case.
+***********************************************************************/
+
+bool set_global_myworkgroup(const char *myworkgroup)
+{
+ SAFE_FREE(smb_myworkgroup);
+ smb_myworkgroup = SMB_STRDUP(myworkgroup);
+ if (!smb_myworkgroup)
+ return False;
+ strupper_m(smb_myworkgroup);
+ return True;
+}
+
+const char *lp_workgroup(void)
+{
+ return smb_myworkgroup;
+}
+
+/***********************************************************************
+ Allocate and set scope. Ensure upper case.
+***********************************************************************/
+
+bool set_global_scope(const char *scope)
+{
+ SAFE_FREE(smb_scope);
+ smb_scope = SMB_STRDUP(scope);
+ if (!smb_scope)
+ return False;
+ strupper_m(smb_scope);
+ return True;
+}
+
+/*********************************************************************
+ Ensure scope is never null string.
+*********************************************************************/
+
+const char *global_scope(void)
+{
+ if (!smb_scope)
+ set_global_scope("");
+ return smb_scope;
+}
+
+static void free_netbios_names_array(void)
+{
+ int i;
+
+ for (i = 0; i < smb_num_netbios_names; i++)
+ SAFE_FREE(smb_my_netbios_names[i]);
+
+ SAFE_FREE(smb_my_netbios_names);
+ smb_num_netbios_names = 0;
+}
+
+static bool allocate_my_netbios_names_array(size_t number)
+{
+ free_netbios_names_array();
+
+ smb_num_netbios_names = number + 1;
+ smb_my_netbios_names = SMB_MALLOC_ARRAY( char *, smb_num_netbios_names );
+
+ if (!smb_my_netbios_names)
+ return False;
+
+ memset(smb_my_netbios_names, '\0', sizeof(char *) * smb_num_netbios_names);
+ return True;
+}
+
+static bool set_my_netbios_names(const char *name, int i)
+{
+ SAFE_FREE(smb_my_netbios_names[i]);
+
+ smb_my_netbios_names[i] = SMB_STRDUP(name);
+ if (!smb_my_netbios_names[i])
+ return False;
+ strupper_m(smb_my_netbios_names[i]);
+ return True;
+}
+
+/***********************************************************************
+ Free memory allocated to global objects
+***********************************************************************/
+
+void gfree_names(void)
+{
+ SAFE_FREE( smb_myname );
+ SAFE_FREE( smb_myworkgroup );
+ SAFE_FREE( smb_scope );
+ free_netbios_names_array();
+ free_local_machine_name();
+}
+
+void gfree_all( void )
+{
+ gfree_names();
+ gfree_loadparm();
+ gfree_case_tables();
+ gfree_charcnv();
+ gfree_interfaces();
+ gfree_debugsyms();
+}
+
+const char *my_netbios_names(int i)
+{
+ return smb_my_netbios_names[i];
+}
+
+bool set_netbios_aliases(const char **str_array)
+{
+ size_t namecount;
+
+ /* Work out the max number of netbios aliases that we have */
+ for( namecount=0; str_array && (str_array[namecount] != NULL); namecount++ )
+ ;
+
+ if ( global_myname() && *global_myname())
+ namecount++;
+
+ /* Allocate space for the netbios aliases */
+ if (!allocate_my_netbios_names_array(namecount))
+ return False;
+
+ /* Use the global_myname string first */
+ namecount=0;
+ if ( global_myname() && *global_myname()) {
+ set_my_netbios_names( global_myname(), namecount );
+ namecount++;
+ }
+
+ if (str_array) {
+ size_t i;
+ for ( i = 0; str_array[i] != NULL; i++) {
+ size_t n;
+ bool duplicate = False;
+
+ /* Look for duplicates */
+ for( n=0; n<namecount; n++ ) {
+ if( strequal( str_array[i], my_netbios_names(n) ) ) {
+ duplicate = True;
+ break;
+ }
+ }
+ if (!duplicate) {
+ if (!set_my_netbios_names(str_array[i], namecount))
+ return False;
+ namecount++;
+ }
+ }
+ }
+ return True;
+}
+
+/****************************************************************************
+ Common name initialization code.
+****************************************************************************/
+
+bool init_names(void)
+{
+ int n;
+
+ if (global_myname() == NULL || *global_myname() == '\0') {
+ if (!set_global_myname(myhostname())) {
+ DEBUG( 0, ( "init_structs: malloc fail.\n" ) );
+ return False;
+ }
+ }
+
+ if (!set_netbios_aliases(lp_netbios_aliases())) {
+ DEBUG( 0, ( "init_structs: malloc fail.\n" ) );
+ return False;
+ }
+
+ set_local_machine_name(global_myname(),false);
+
+ 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 );
+}
+
+/**************************************************************************n
+ Code to cope with username/password auth options from the commandline.
+ Used mainly in client tools.
+****************************************************************************/
+
+static struct user_auth_info cmdline_auth_info = {
+ NULL, /* username */
+ NULL, /* password */
+ false, /* got_pass */
+ false, /* use_kerberos */
+ Undefined, /* signing state */
+ false, /* smb_encrypt */
+ false /* use machine account */
+};
+
+const char *get_cmdline_auth_info_username(void)
+{
+ if (!cmdline_auth_info.username) {
+ return "";
+ }
+ return cmdline_auth_info.username;
+}
+
+void set_cmdline_auth_info_username(const char *username)
+{
+ SAFE_FREE(cmdline_auth_info.username);
+ cmdline_auth_info.username = SMB_STRDUP(username);
+ if (!cmdline_auth_info.username) {
+ exit(ENOMEM);
+ }
+}
+
+const char *get_cmdline_auth_info_password(void)
+{
+ if (!cmdline_auth_info.password) {
+ return "";
+ }
+ return cmdline_auth_info.password;
+}
+
+void set_cmdline_auth_info_password(const char *password)
+{
+ SAFE_FREE(cmdline_auth_info.password);
+ cmdline_auth_info.password = SMB_STRDUP(password);
+ if (!cmdline_auth_info.password) {
+ exit(ENOMEM);
+ }
+ cmdline_auth_info.got_pass = true;
+}
+
+bool set_cmdline_auth_info_signing_state(const char *arg)
+{
+ cmdline_auth_info.signing_state = -1;
+ if (strequal(arg, "off") || strequal(arg, "no") ||
+ strequal(arg, "false")) {
+ cmdline_auth_info.signing_state = false;
+ } else if (strequal(arg, "on") || strequal(arg, "yes") ||
+ strequal(arg, "true") || strequal(arg, "auto")) {
+ cmdline_auth_info.signing_state = true;
+ } else if (strequal(arg, "force") || strequal(arg, "required") ||
+ strequal(arg, "forced")) {
+ cmdline_auth_info.signing_state = Required;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+int get_cmdline_auth_info_signing_state(void)
+{
+ return cmdline_auth_info.signing_state;
+}
+
+void set_cmdline_auth_info_use_kerberos(bool b)
+{
+ cmdline_auth_info.use_kerberos = b;
+}
+
+bool get_cmdline_auth_info_use_kerberos(void)
+{
+ return cmdline_auth_info.use_kerberos;
+}
+
+/* This should only be used by lib/popt_common.c JRA */
+void set_cmdline_auth_info_use_krb5_ticket(void)
+{
+ cmdline_auth_info.use_kerberos = true;
+ cmdline_auth_info.got_pass = true;
+}
+
+/* This should only be used by lib/popt_common.c JRA */
+void set_cmdline_auth_info_smb_encrypt(void)
+{
+ cmdline_auth_info.smb_encrypt = true;
+}
+
+void set_cmdline_auth_info_use_machine_account(void)
+{
+ cmdline_auth_info.use_machine_account = true;
+}
+
+bool get_cmdline_auth_info_got_pass(void)
+{
+ return cmdline_auth_info.got_pass;
+}
+
+bool get_cmdline_auth_info_smb_encrypt(void)
+{
+ return cmdline_auth_info.smb_encrypt;
+}
+
+bool get_cmdline_auth_info_use_machine_account(void)
+{
+ return cmdline_auth_info.use_machine_account;
+}
+
+bool get_cmdline_auth_info_copy(struct user_auth_info *info)
+{
+ *info = cmdline_auth_info;
+ /* Now re-alloc the strings. */
+ info->username = SMB_STRDUP(get_cmdline_auth_info_username());
+ info->password = SMB_STRDUP(get_cmdline_auth_info_password());
+ if (!info->username || !info->password) {
+ return false;
+ }
+ return true;
+}
+
+bool set_cmdline_auth_info_machine_account_creds(void)
+{
+ char *pass = NULL;
+ char *account = NULL;
+
+ if (!get_cmdline_auth_info_use_machine_account()) {
+ return false;
+ }
+
+ if (!secrets_init()) {
+ d_printf("ERROR: Unable to open secrets database\n");
+ return false;
+ }
+
+ if (asprintf(&account, "%s$@%s", global_myname(), lp_realm()) < 0) {
+ return false;
+ }
+
+ pass = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
+ if (!pass) {
+ d_printf("ERROR: Unable to fetch machine password for "
+ "%s in domain %s\n",
+ account, lp_workgroup());
+ SAFE_FREE(account);
+ return false;
+ }
+
+ set_cmdline_auth_info_username(account);
+ set_cmdline_auth_info_password(pass);
+
+ SAFE_FREE(account);
+ SAFE_FREE(pass);
+
+ return true;
+}
+
+/**************************************************************************n
+ Find a suitable temporary directory. The result should be copied immediately
+ as it may be overwritten by a subsequent call.
+****************************************************************************/
+
+const char *tmpdir(void)
+{
+ char *p;
+ if ((p = getenv("TMPDIR")))
+ return p;
+ return "/tmp";
+}
+
+/****************************************************************************
+ Add a gid to an array of gids if it's not already there.
+****************************************************************************/
+
+bool add_gid_to_array_unique(TALLOC_CTX *mem_ctx, gid_t gid,
+ gid_t **gids, size_t *num_gids)
+{
+ int i;
+
+ if ((*num_gids != 0) && (*gids == NULL)) {
+ /*
+ * A former call to this routine has failed to allocate memory
+ */
+ return False;
+ }
+
+ for (i=0; i<*num_gids; i++) {
+ if ((*gids)[i] == gid) {
+ return True;
+ }
+ }
+
+ *gids = TALLOC_REALLOC_ARRAY(mem_ctx, *gids, gid_t, *num_gids+1);
+ if (*gids == NULL) {
+ *num_gids = 0;
+ return False;
+ }
+
+ (*gids)[*num_gids] = gid;
+ *num_gids += 1;
+ return True;
+}
+
+/****************************************************************************
+ Like atoi but gets the value up to the separator character.
+****************************************************************************/
+
+static const char *Atoic(const char *p, int *n, const char *c)
+{
+ if (!isdigit((int)*p)) {
+ DEBUG(5, ("Atoic: malformed number\n"));
+ return NULL;
+ }
+
+ (*n) = atoi(p);
+
+ while ((*p) && isdigit((int)*p))
+ p++;
+
+ if (strchr_m(c, *p) == NULL) {
+ DEBUG(5, ("Atoic: no separator characters (%s) not found\n", c));
+ return NULL;
+ }
+
+ return p;
+}
+
+/*************************************************************************
+ Reads a list of numbers.
+ *************************************************************************/
+
+const char *get_numlist(const char *p, uint32 **num, int *count)
+{
+ int val;
+
+ if (num == NULL || count == NULL)
+ return NULL;
+
+ (*count) = 0;
+ (*num ) = NULL;
+
+ while ((p = Atoic(p, &val, ":,")) != NULL && (*p) != ':') {
+ *num = SMB_REALLOC_ARRAY((*num), uint32, (*count)+1);
+ if (!(*num)) {
+ return NULL;
+ }
+ (*num)[(*count)] = val;
+ (*count)++;
+ p++;
+ }
+
+ return p;
+}
+
+/*******************************************************************
+ Check if a file exists - call vfs_file_exist for samba files.
+********************************************************************/
+
+bool file_exist(const char *fname,SMB_STRUCT_STAT *sbuf)
+{
+ SMB_STRUCT_STAT st;
+ if (!sbuf)
+ sbuf = &st;
+
+ if (sys_stat(fname,sbuf) != 0)
+ return(False);
+
+ return((S_ISREG(sbuf->st_mode)) || (S_ISFIFO(sbuf->st_mode)));
+}
+
+/*******************************************************************
+ Check if a unix domain socket exists - call vfs_file_exist for samba files.
+********************************************************************/
+
+bool socket_exist(const char *fname)
+{
+ SMB_STRUCT_STAT st;
+ if (sys_stat(fname,&st) != 0)
+ return(False);
+
+ return S_ISSOCK(st.st_mode);
+}
+
+/*******************************************************************
+ Check a files mod time.
+********************************************************************/
+
+time_t file_modtime(const char *fname)
+{
+ SMB_STRUCT_STAT st;
+
+ if (sys_stat(fname,&st) != 0)
+ return(0);
+
+ return(st.st_mtime);
+}
+
+/*******************************************************************
+ Check if a directory exists.
+********************************************************************/
+
+bool directory_exist(char *dname,SMB_STRUCT_STAT *st)
+{
+ SMB_STRUCT_STAT st2;
+ bool ret;
+
+ if (!st)
+ st = &st2;
+
+ if (sys_stat(dname,st) != 0)
+ return(False);
+
+ ret = S_ISDIR(st->st_mode);
+ if(!ret)
+ errno = ENOTDIR;
+ return ret;
+}
+
+/*******************************************************************
+ Returns the size in bytes of the named file.
+********************************************************************/
+
+SMB_OFF_T get_file_size(char *file_name)
+{
+ SMB_STRUCT_STAT buf;
+ buf.st_size = 0;
+ if(sys_stat(file_name,&buf) != 0)
+ return (SMB_OFF_T)-1;
+ return(buf.st_size);
+}
+
+/*******************************************************************
+ Return a string representing an attribute for a file.
+********************************************************************/
+
+char *attrib_string(uint16 mode)
+{
+ fstring attrstr;
+
+ attrstr[0] = 0;
+
+ 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 talloc_strdup(talloc_tos(), attrstr);
+}
+
+/*******************************************************************
+ Show a smb message structure.
+********************************************************************/
+
+void show_msg(char *buf)
+{
+ int i;
+ int bcc=0;
+
+ if (!DEBUGLVL(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)));
+ DEBUGADD(5,("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\n",
+ (int)SVAL(buf,smb_tid),
+ (int)SVAL(buf,smb_pid),
+ (int)SVAL(buf,smb_uid),
+ (int)SVAL(buf,smb_mid)));
+ DEBUGADD(5,("smt_wct=%d\n",(int)CVAL(buf,smb_wct)));
+
+ for (i=0;i<(int)CVAL(buf,smb_wct);i++)
+ DEBUGADD(5,("smb_vwv[%2d]=%5d (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)));
+
+ DEBUGADD(5,("smb_bcc=%d\n",bcc));
+
+ if (DEBUGLEVEL < 10)
+ return;
+
+ if (DEBUGLEVEL < 50)
+ bcc = MIN(bcc, 512);
+
+ dump_data(10, (uint8 *)smb_buf(buf), bcc);
+}
+
+/*******************************************************************
+ Set the length and marker of an encrypted smb packet.
+********************************************************************/
+
+void smb_set_enclen(char *buf,int len,uint16 enc_ctx_num)
+{
+ _smb_setlen(buf,len);
+
+ SCVAL(buf,4,0xFF);
+ SCVAL(buf,5,'E');
+ SSVAL(buf,6,enc_ctx_num);
+}
+
+/*******************************************************************
+ Set the length and marker of an smb packet.
+********************************************************************/
+
+void smb_setlen(char *buf,int len)
+{
+ _smb_setlen(buf,len);
+
+ SCVAL(buf,4,0xFF);
+ SCVAL(buf,5,'S');
+ SCVAL(buf,6,'M');
+ SCVAL(buf,7,'B');
+}
+
+/*******************************************************************
+ Setup only the byte count for a smb message.
+********************************************************************/
+
+int set_message_bcc(char *buf,int num_bytes)
+{
+ int num_words = CVAL(buf,smb_wct);
+ SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
+ _smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
+ return (smb_size + num_words*2 + num_bytes);
+}
+
+/*******************************************************************
+ Add a data blob to the end of a smb_buf, adjusting bcc and smb_len.
+ Return the bytes added
+********************************************************************/
+
+ssize_t message_push_blob(uint8 **outbuf, DATA_BLOB blob)
+{
+ size_t newlen = smb_len(*outbuf) + 4 + blob.length;
+ uint8 *tmp;
+
+ if (!(tmp = TALLOC_REALLOC_ARRAY(NULL, *outbuf, uint8, newlen))) {
+ DEBUG(0, ("talloc failed\n"));
+ return -1;
+ }
+ *outbuf = tmp;
+
+ memcpy(tmp + smb_len(tmp) + 4, blob.data, blob.length);
+ set_message_bcc((char *)tmp, smb_buflen(tmp) + blob.length);
+ return blob.length;
+}
+
+/*******************************************************************
+ Reduce a file name, removing .. elements.
+********************************************************************/
+
+static char *dos_clean_name(TALLOC_CTX *ctx, const char *s)
+{
+ char *p = NULL;
+ char *str = NULL;
+
+ DEBUG(3,("dos_clean_name [%s]\n",s));
+
+ /* remove any double slashes */
+ str = talloc_all_string_sub(ctx, s, "\\\\", "\\");
+ if (!str) {
+ return NULL;
+ }
+
+ /* Remove leading .\\ characters */
+ if(strncmp(str, ".\\", 2) == 0) {
+ trim_string(str, ".\\", NULL);
+ if(*str == 0) {
+ str = talloc_strdup(ctx, ".\\");
+ if (!str) {
+ return NULL;
+ }
+ }
+ }
+
+ while ((p = strstr_m(str,"\\..\\")) != NULL) {
+ char *s1;
+
+ *p = 0;
+ s1 = p+3;
+
+ if ((p=strrchr_m(str,'\\')) != NULL) {
+ *p = 0;
+ } else {
+ *str = 0;
+ }
+ str = talloc_asprintf(ctx,
+ "%s%s",
+ str,
+ s1);
+ if (!str) {
+ return NULL;
+ }
+ }
+
+ trim_string(str,NULL,"\\..");
+ return talloc_all_string_sub(ctx, str, "\\.\\", "\\");
+}
+
+/*******************************************************************
+ Reduce a file name, removing .. elements.
+********************************************************************/
+
+char *unix_clean_name(TALLOC_CTX *ctx, const char *s)
+{
+ char *p = NULL;
+ char *str = NULL;
+
+ DEBUG(3,("unix_clean_name [%s]\n",s));
+
+ /* remove any double slashes */
+ str = talloc_all_string_sub(ctx, s, "//","/");
+ if (!str) {
+ return NULL;
+ }
+
+ /* Remove leading ./ characters */
+ if(strncmp(str, "./", 2) == 0) {
+ trim_string(str, "./", NULL);
+ if(*str == 0) {
+ str = talloc_strdup(ctx, "./");
+ if (!str) {
+ return NULL;
+ }
+ }
+ }
+
+ while ((p = strstr_m(str,"/../")) != NULL) {
+ char *s1;
+
+ *p = 0;
+ s1 = p+3;
+
+ if ((p=strrchr_m(str,'/')) != NULL) {
+ *p = 0;
+ } else {
+ *str = 0;
+ }
+ str = talloc_asprintf(ctx,
+ "%s%s",
+ str,
+ s1);
+ if (!str) {
+ return NULL;
+ }
+ }
+
+ trim_string(str,NULL,"/..");
+ return talloc_all_string_sub(ctx, str, "/./", "/");
+}
+
+char *clean_name(TALLOC_CTX *ctx, const char *s)
+{
+ char *str = dos_clean_name(ctx, s);
+ if (!str) {
+ return NULL;
+ }
+ return unix_clean_name(ctx, str);
+}
+
+/*******************************************************************
+ Close the low 3 fd's and open dev/null in their place.
+********************************************************************/
+
+void close_low_fds(bool stderr_too)
+{
+#ifndef VALGRIND
+ int fd;
+ int i;
+
+ close(0);
+ close(1);
+
+ if (stderr_too)
+ close(2);
+
+ /* try and use up these file descriptors, so silly
+ library routines writing to stdout etc won't cause havoc */
+ for (i=0;i<3;i++) {
+ if (i == 2 && !stderr_too)
+ continue;
+
+ fd = sys_open("/dev/null",O_RDWR,0);
+ if (fd < 0)
+ fd = sys_open("/dev/null",O_WRONLY,0);
+ if (fd < 0) {
+ DEBUG(0,("Can't open /dev/null\n"));
+ return;
+ }
+ if (fd != i) {
+ DEBUG(0,("Didn't get file descriptor %d\n",i));
+ return;
+ }
+ }
+#endif
+}
+
+/*******************************************************************
+ Write data into an fd at a given offset. Ignore seek errors.
+********************************************************************/
+
+ssize_t write_data_at_offset(int fd, const char *buffer, size_t N, SMB_OFF_T pos)
+{
+ size_t total=0;
+ ssize_t ret;
+
+ if (pos == (SMB_OFF_T)-1) {
+ return write_data(fd, buffer, N);
+ }
+#if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
+ while (total < N) {
+ ret = sys_pwrite(fd,buffer + total,N - total, pos);
+ if (ret == -1 && errno == ESPIPE) {
+ return write_data(fd, buffer + total,N - total);
+ }
+ if (ret == -1) {
+ DEBUG(0,("write_data_at_offset: write failure. Error = %s\n", strerror(errno) ));
+ return -1;
+ }
+ if (ret == 0) {
+ return total;
+ }
+ total += ret;
+ pos += ret;
+ }
+ return (ssize_t)total;
+#else
+ /* Use lseek and write_data. */
+ if (sys_lseek(fd, pos, SEEK_SET) == -1) {
+ if (errno != ESPIPE) {
+ return -1;
+ }
+ }
+ return write_data(fd, buffer, N);
+#endif
+}
+
+/****************************************************************************
+ 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)
+{
+ int val;
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+
+ if((val = sys_fcntl_long(fd, F_GETFL, 0)) == -1)
+ return -1;
+ if(set) /* Turn blocking on - ie. clear nonblock flag */
+ val &= ~FLAG_TO_SET;
+ else
+ val |= FLAG_TO_SET;
+ return sys_fcntl_long( fd, F_SETFL, val);
+#undef FLAG_TO_SET
+}
+
+/*******************************************************************
+ Sleep for a specified number of milliseconds.
+********************************************************************/
+
+void smb_msleep(unsigned int t)
+{
+#if defined(HAVE_NANOSLEEP)
+ struct timespec tval;
+ int ret;
+
+ tval.tv_sec = t/1000;
+ tval.tv_nsec = 1000000*(t%1000);
+
+ do {
+ errno = 0;
+ ret = nanosleep(&tval, &tval);
+ } while (ret < 0 && errno == EINTR && (tval.tv_sec > 0 || tval.tv_nsec > 0));
+#else
+ unsigned int tdiff=0;
+ struct timeval tval,t1,t2;
+ fd_set fds;
+
+ GetTimeOfDay(&t1);
+ t2 = t1;
+
+ while (tdiff < t) {
+ tval.tv_sec = (t-tdiff)/1000;
+ tval.tv_usec = 1000*((t-tdiff)%1000);
+
+ /* Never wait for more than 1 sec. */
+ if (tval.tv_sec > 1) {
+ tval.tv_sec = 1;
+ tval.tv_usec = 0;
+ }
+
+ FD_ZERO(&fds);
+ errno = 0;
+ sys_select_intr(0,&fds,NULL,NULL,&tval);
+
+ GetTimeOfDay(&t2);
+ if (t2.tv_sec < t1.tv_sec) {
+ /* Someone adjusted time... */
+ t1 = t2;
+ }
+
+ tdiff = TvalDiff(&t1,&t2);
+ }
+#endif
+}
+
+/****************************************************************************
+ Become a daemon, discarding the controlling terminal.
+****************************************************************************/
+
+void become_daemon(bool Fork, bool no_process_group)
+{
+ if (Fork) {
+ if (sys_fork()) {
+ _exit(0);
+ }
+ }
+
+ /* detach from the terminal */
+#ifdef HAVE_SETSID
+ if (!no_process_group) setsid();
+#elif defined(TIOCNOTTY)
+ if (!no_process_group) {
+ int i = sys_open("/dev/tty", O_RDWR, 0);
+ 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(False); /* Don't close stderr, let the debug system
+ attach it to the logfile */
+}
+
+bool reinit_after_fork(struct messaging_context *msg_ctx,
+ bool parent_longlived)
+{
+ NTSTATUS status;
+
+ /* Reset the state of the random
+ * number generation system, so
+ * children do not get the same random
+ * numbers as each other */
+ set_need_random_reseed();
+
+ /* tdb needs special fork handling */
+ if (tdb_reopen_all(parent_longlived ? 1 : 0) == -1) {
+ DEBUG(0,("tdb_reopen_all failed.\n"));
+ return false;
+ }
+
+ /*
+ * For clustering, we need to re-init our ctdbd connection after the
+ * fork
+ */
+ status = messaging_reinit(msg_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("messaging_reinit() failed: %s\n",
+ nt_errstr(status)));
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************************
+ Put up a yes/no prompt.
+****************************************************************************/
+
+bool yesno(const char *p)
+{
+ char ans[20];
+ printf("%s",p);
+
+ if (!fgets(ans,sizeof(ans)-1,stdin))
+ return(False);
+
+ if (*ans == 'y' || *ans == 'Y')
+ return(True);
+
+ return(False);
+}
+
+#if defined(PARANOID_MALLOC_CHECKER)
+
+/****************************************************************************
+ Internal malloc wrapper. Externally visible.
+****************************************************************************/
+
+void *malloc_(size_t size)
+{
+ if (size == 0) {
+ return NULL;
+ }
+#undef malloc
+ return malloc(size);
+#define malloc(s) __ERROR_DONT_USE_MALLOC_DIRECTLY
+}
+
+/****************************************************************************
+ Internal calloc wrapper. Not externally visible.
+****************************************************************************/
+
+static void *calloc_(size_t count, size_t size)
+{
+ if (size == 0 || count == 0) {
+ return NULL;
+ }
+#undef calloc
+ return calloc(count, size);
+#define calloc(n,s) __ERROR_DONT_USE_CALLOC_DIRECTLY
+}
+
+/****************************************************************************
+ Internal realloc wrapper. Not externally visible.
+****************************************************************************/
+
+static void *realloc_(void *ptr, size_t size)
+{
+#undef realloc
+ return realloc(ptr, size);
+#define realloc(p,s) __ERROR_DONT_USE_RELLOC_DIRECTLY
+}
+
+#endif /* PARANOID_MALLOC_CHECKER */
+
+/****************************************************************************
+ Type-safe malloc.
+****************************************************************************/
+
+void *malloc_array(size_t el_size, unsigned int count)
+{
+ if (count >= MAX_ALLOC_SIZE/el_size) {
+ return NULL;
+ }
+
+ if (el_size == 0 || count == 0) {
+ return NULL;
+ }
+#if defined(PARANOID_MALLOC_CHECKER)
+ return malloc_(el_size*count);
+#else
+ return malloc(el_size*count);
+#endif
+}
+
+/****************************************************************************
+ Type-safe memalign
+****************************************************************************/
+
+void *memalign_array(size_t el_size, size_t align, unsigned int count)
+{
+ if (count >= MAX_ALLOC_SIZE/el_size) {
+ return NULL;
+ }
+
+ return sys_memalign(align, el_size*count);
+}
+
+/****************************************************************************
+ Type-safe calloc.
+****************************************************************************/
+
+void *calloc_array(size_t size, size_t nmemb)
+{
+ if (nmemb >= MAX_ALLOC_SIZE/size) {
+ return NULL;
+ }
+ if (size == 0 || nmemb == 0) {
+ return NULL;
+ }
+#if defined(PARANOID_MALLOC_CHECKER)
+ return calloc_(nmemb, size);
+#else
+ return calloc(nmemb, size);
+#endif
+}
+
+/****************************************************************************
+ Expand a pointer to be a particular size.
+ Note that this version of Realloc has an extra parameter that decides
+ whether to free the passed in storage on allocation failure or if the
+ new size is zero.
+
+ This is designed for use in the typical idiom of :
+
+ p = SMB_REALLOC(p, size)
+ if (!p) {
+ return error;
+ }
+
+ and not to have to keep track of the old 'p' contents to free later, nor
+ to worry if the size parameter was zero. In the case where NULL is returned
+ we guarentee that p has been freed.
+
+ If free later semantics are desired, then pass 'free_old_on_error' as False which
+ guarentees that the old contents are not freed on error, even if size == 0. To use
+ this idiom use :
+
+ tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size);
+ if (!tmp) {
+ SAFE_FREE(p);
+ return error;
+ } else {
+ p = tmp;
+ }
+
+ Changes were instigated by Coverity error checking. JRA.
+****************************************************************************/
+
+void *Realloc(void *p, size_t size, bool free_old_on_error)
+{
+ void *ret=NULL;
+
+ if (size == 0) {
+ if (free_old_on_error) {
+ SAFE_FREE(p);
+ }
+ DEBUG(2,("Realloc asked for 0 bytes\n"));
+ return NULL;
+ }
+
+#if defined(PARANOID_MALLOC_CHECKER)
+ if (!p) {
+ ret = (void *)malloc_(size);
+ } else {
+ ret = (void *)realloc_(p,size);
+ }
+#else
+ if (!p) {
+ ret = (void *)malloc(size);
+ } else {
+ ret = (void *)realloc(p,size);
+ }
+#endif
+
+ if (!ret) {
+ if (free_old_on_error && p) {
+ SAFE_FREE(p);
+ }
+ DEBUG(0,("Memory allocation error: failed to expand to %d bytes\n",(int)size));
+ }
+
+ return(ret);
+}
+
+/****************************************************************************
+ Type-safe realloc.
+****************************************************************************/
+
+void *realloc_array(void *p, size_t el_size, unsigned int count, bool free_old_on_error)
+{
+ if (count >= MAX_ALLOC_SIZE/el_size) {
+ if (free_old_on_error) {
+ SAFE_FREE(p);
+ }
+ return NULL;
+ }
+ return Realloc(p, el_size*count, free_old_on_error);
+}
+
+/****************************************************************************
+ (Hopefully) efficient array append.
+****************************************************************************/
+
+void add_to_large_array(TALLOC_CTX *mem_ctx, size_t element_size,
+ void *element, void *_array, uint32 *num_elements,
+ ssize_t *array_size)
+{
+ void **array = (void **)_array;
+
+ if (*array_size < 0) {
+ return;
+ }
+
+ if (*array == NULL) {
+ if (*array_size == 0) {
+ *array_size = 128;
+ }
+
+ if (*array_size >= MAX_ALLOC_SIZE/element_size) {
+ goto error;
+ }
+
+ *array = TALLOC(mem_ctx, element_size * (*array_size));
+ if (*array == NULL) {
+ goto error;
+ }
+ }
+
+ if (*num_elements == *array_size) {
+ *array_size *= 2;
+
+ if (*array_size >= MAX_ALLOC_SIZE/element_size) {
+ goto error;
+ }
+
+ *array = TALLOC_REALLOC(mem_ctx, *array,
+ element_size * (*array_size));
+
+ if (*array == NULL) {
+ goto error;
+ }
+ }
+
+ memcpy((char *)(*array) + element_size*(*num_elements),
+ element, element_size);
+ *num_elements += 1;
+
+ return;
+
+ error:
+ *num_elements = 0;
+ *array_size = -1;
+}
+
+/****************************************************************************
+ Free memory, checks for NULL.
+ Use directly SAFE_FREE()
+ Exists only because we need to pass a function pointer somewhere --SSS
+****************************************************************************/
+
+void safe_free(void *p)
+{
+ SAFE_FREE(p);
+}
+
+/****************************************************************************
+ Get my own name and IP.
+****************************************************************************/
+
+char *get_myname(TALLOC_CTX *ctx)
+{
+ char *p;
+ char hostname[HOST_NAME_MAX];
+
+ *hostname = 0;
+
+ /* get my host name */
+ if (gethostname(hostname, sizeof(hostname)) == -1) {
+ DEBUG(0,("gethostname failed\n"));
+ return False;
+ }
+
+ /* Ensure null termination. */
+ hostname[sizeof(hostname)-1] = '\0';
+
+ /* split off any parts after an initial . */
+ p = strchr_m(hostname,'.');
+ if (p) {
+ *p = 0;
+ }
+
+ return talloc_strdup(ctx, hostname);
+}
+
+/****************************************************************************
+ Get my own domain name, or "" if we have none.
+****************************************************************************/
+
+char *get_mydnsdomname(TALLOC_CTX *ctx)
+{
+ const char *domname;
+ char *p;
+
+ domname = get_mydnsfullname();
+ if (!domname) {
+ return NULL;
+ }
+
+ p = strchr_m(domname, '.');
+ if (p) {
+ p++;
+ return talloc_strdup(ctx, p);
+ } else {
+ return talloc_strdup(ctx, "");
+ }
+}
+
+/****************************************************************************
+ Interpret a protocol description string, with a default.
+****************************************************************************/
+
+int interpret_protocol(const char *str,int def)
+{
+ if (strequal(str,"NT1"))
+ return(PROTOCOL_NT1);
+ if (strequal(str,"LANMAN2"))
+ return(PROTOCOL_LANMAN2);
+ if (strequal(str,"LANMAN1"))
+ return(PROTOCOL_LANMAN1);
+ if (strequal(str,"CORE"))
+ return(PROTOCOL_CORE);
+ if (strequal(str,"COREPLUS"))
+ return(PROTOCOL_COREPLUS);
+ if (strequal(str,"CORE+"))
+ return(PROTOCOL_COREPLUS);
+
+ DEBUG(0,("Unrecognised protocol level %s\n",str));
+
+ return(def);
+}
+
+
+#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>.
+ Returns a malloc'ed string.
+*******************************************************************/
+
+static char *strip_mount_options(TALLOC_CTX *ctx, const char *str)
+{
+ if (*str == '-') {
+ const char *p = str;
+ while(*p && !isspace(*p))
+ p++;
+ while(*p && isspace(*p))
+ p++;
+ if(*p) {
+ return talloc_strdup(ctx, p);
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************
+ Patch from jkf@soton.ac.uk
+ Split Luke's automount_server into YP lookup and string splitter
+ so can easily implement automount_path().
+ Returns a malloc'ed string.
+*******************************************************************/
+
+#ifdef WITH_NISPLUS_HOME
+char *automount_lookup(TALLOC_CTX *ctx, const char *user_name)
+{
+ char *value = NULL;
+
+ char *nis_map = (char *)lp_nis_home_map_name();
+
+ char buffer[NIS_MAXATTRVAL + 1];
+ nis_result *result;
+ nis_object *object;
+ entry_obj *entry;
+
+ snprintf(buffer, sizeof(buffer), "[key=%s],%s", user_name, nis_map);
+ DEBUG(5, ("NIS+ querystring: %s\n", buffer));
+
+ if (result = nis_list(buffer, FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP, NULL, NULL)) {
+ if (result->status != NIS_SUCCESS) {
+ DEBUG(3, ("NIS+ query failed: %s\n", nis_sperrno(result->status)));
+ } 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));
+
+ value = talloc_strdup(ctx,
+ entry->en_cols.en_cols_val[1].ec_value.ec_value_val);
+ if (!value) {
+ nis_freeresult(result);
+ return NULL;
+ }
+ value = talloc_string_sub(ctx,
+ value,
+ "&",
+ user_name);
+ }
+ }
+ }
+ nis_freeresult(result);
+
+ if (value) {
+ value = strip_mount_options(ctx, value);
+ DEBUG(4, ("NIS+ Lookup: %s resulted in %s\n",
+ user_name, value));
+ }
+ return value;
+}
+#else /* WITH_NISPLUS_HOME */
+
+char *automount_lookup(TALLOC_CTX *ctx, const char *user_name)
+{
+ char *value = NULL;
+
+ int nis_error; /* returned by yp all functions */
+ char *nis_result; /* yp_match inits this */
+ int nis_result_len; /* and set this */
+ char *nis_domain; /* yp_get_default_domain inits this */
+ char *nis_map = (char *)lp_nis_home_map_name();
+
+ if ((nis_error = yp_get_default_domain(&nis_domain)) != 0) {
+ DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error)));
+ return NULL;
+ }
+
+ DEBUG(5, ("NIS Domain: %s\n", nis_domain));
+
+ if ((nis_error = yp_match(nis_domain, nis_map, user_name,
+ strlen(user_name), &nis_result,
+ &nis_result_len)) == 0) {
+ value = talloc_strdup(ctx, nis_result);
+ if (!value) {
+ return NULL;
+ }
+ value = strip_mount_options(ctx, value);
+ } else if(nis_error == YPERR_KEY) {
+ DEBUG(3, ("YP Key not found: while looking up \"%s\" in map \"%s\"\n",
+ user_name, nis_map));
+ DEBUG(3, ("using defaults for server and home directory\n"));
+ } else {
+ DEBUG(3, ("YP Error: \"%s\" while looking up \"%s\" in map \"%s\"\n",
+ yperr_string(nis_error), user_name, nis_map));
+ }
+
+ if (value) {
+ DEBUG(4, ("YP Lookup: %s resulted in %s\n", user_name, value));
+ }
+ return value;
+}
+#endif /* WITH_NISPLUS_HOME */
+#endif
+
+/****************************************************************************
+ Check if a process exists. Does this work on all unixes?
+****************************************************************************/
+
+bool process_exists(const struct server_id pid)
+{
+ if (procid_is_me(&pid)) {
+ return True;
+ }
+
+ if (procid_is_local(&pid)) {
+ return (kill(pid.pid,0) == 0 || errno != ESRCH);
+ }
+
+#ifdef CLUSTER_SUPPORT
+ return ctdbd_process_exists(messaging_ctdbd_connection(), pid.vnn,
+ pid.pid);
+#else
+ return False;
+#endif
+}
+
+bool process_exists_by_pid(pid_t pid)
+{
+ /* Doing kill with a non-positive pid causes messages to be
+ * sent to places we don't want. */
+ SMB_ASSERT(pid > 0);
+ return(kill(pid,0) == 0 || errno != ESRCH);
+}
+
+/*******************************************************************
+ Convert a uid into a user name.
+********************************************************************/
+
+const char *uidtoname(uid_t uid)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *name = NULL;
+ struct passwd *pass = NULL;
+
+ pass = getpwuid_alloc(ctx,uid);
+ if (pass) {
+ name = talloc_strdup(ctx,pass->pw_name);
+ TALLOC_FREE(pass);
+ } else {
+ name = talloc_asprintf(ctx,
+ "%ld",
+ (long int)uid);
+ }
+ return name;
+}
+
+/*******************************************************************
+ Convert a gid into a group name.
+********************************************************************/
+
+char *gidtoname(gid_t gid)
+{
+ struct group *grp;
+
+ grp = getgrgid(gid);
+ if (grp) {
+ return talloc_strdup(talloc_tos(), grp->gr_name);
+ }
+ else {
+ return talloc_asprintf(talloc_tos(),
+ "%d",
+ (int)gid);
+ }
+}
+
+/*******************************************************************
+ Convert a user name into a uid.
+********************************************************************/
+
+uid_t nametouid(const char *name)
+{
+ struct passwd *pass;
+ char *p;
+ uid_t u;
+
+ pass = getpwnam_alloc(NULL, name);
+ if (pass) {
+ u = pass->pw_uid;
+ TALLOC_FREE(pass);
+ return u;
+ }
+
+ u = (uid_t)strtol(name, &p, 0);
+ if ((p != name) && (*p == '\0'))
+ return u;
+
+ return (uid_t)-1;
+}
+
+/*******************************************************************
+ Convert a name to a gid_t if possible. Return -1 if not a group.
+********************************************************************/
+
+gid_t nametogid(const char *name)
+{
+ struct group *grp;
+ char *p;
+ gid_t g;
+
+ g = (gid_t)strtol(name, &p, 0);
+ if ((p != name) && (*p == '\0'))
+ return g;
+
+ grp = sys_getgrnam(name);
+ if (grp)
+ return(grp->gr_gid);
+ return (gid_t)-1;
+}
+
+/*******************************************************************
+ Something really nasty happened - panic !
+********************************************************************/
+
+void smb_panic(const char *const why)
+{
+ char *cmd;
+ int result;
+
+#ifdef DEVELOPER
+ {
+
+ if (global_clobber_region_function) {
+ DEBUG(0,("smb_panic: clobber_region() last called from [%s(%u)]\n",
+ global_clobber_region_function,
+ global_clobber_region_line));
+ }
+ }
+#endif
+
+ DEBUG(0,("PANIC (pid %llu): %s\n",
+ (unsigned long long)sys_getpid(), why));
+ log_stack_trace();
+
+ cmd = lp_panic_action();
+ if (cmd && *cmd) {
+ DEBUG(0, ("smb_panic(): calling panic action [%s]\n", cmd));
+ result = system(cmd);
+
+ if (result == -1)
+ DEBUG(0, ("smb_panic(): fork failed in panic action: %s\n",
+ strerror(errno)));
+ else
+ DEBUG(0, ("smb_panic(): action returned status %d\n",
+ WEXITSTATUS(result)));
+ }
+
+ dump_core();
+}
+
+/*******************************************************************
+ Print a backtrace of the stack to the debug log. This function
+ DELIBERATELY LEAKS MEMORY. The expectation is that you should
+ exit shortly after calling it.
+********************************************************************/
+
+#ifdef HAVE_LIBUNWIND_H
+#include <libunwind.h>
+#endif
+
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
+
+#ifdef HAVE_LIBEXC_H
+#include <libexc.h>
+#endif
+
+void log_stack_trace(void)
+{
+#ifdef HAVE_LIBUNWIND
+ /* Try to use libunwind before any other technique since on ia64
+ * libunwind correctly walks the stack in more circumstances than
+ * backtrace.
+ */
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ unsigned i = 0;
+
+ char procname[256];
+ unw_word_t ip, sp, off;
+
+ procname[sizeof(procname) - 1] = '\0';
+
+ if (unw_getcontext(&uc) != 0) {
+ goto libunwind_failed;
+ }
+
+ if (unw_init_local(&cursor, &uc) != 0) {
+ goto libunwind_failed;
+ }
+
+ DEBUG(0, ("BACKTRACE:\n"));
+
+ do {
+ ip = sp = 0;
+ unw_get_reg(&cursor, UNW_REG_IP, &ip);
+ unw_get_reg(&cursor, UNW_REG_SP, &sp);
+
+ switch (unw_get_proc_name(&cursor,
+ procname, sizeof(procname) - 1, &off) ) {
+ case 0:
+ /* Name found. */
+ case -UNW_ENOMEM:
+ /* Name truncated. */
+ DEBUGADD(0, (" #%u %s + %#llx [ip=%#llx] [sp=%#llx]\n",
+ i, procname, (long long)off,
+ (long long)ip, (long long) sp));
+ break;
+ default:
+ /* case -UNW_ENOINFO: */
+ /* case -UNW_EUNSPEC: */
+ /* No symbol name found. */
+ DEBUGADD(0, (" #%u %s [ip=%#llx] [sp=%#llx]\n",
+ i, "<unknown symbol>",
+ (long long)ip, (long long) sp));
+ }
+ ++i;
+ } while (unw_step(&cursor) > 0);
+
+ return;
+
+libunwind_failed:
+ DEBUG(0, ("unable to produce a stack trace with libunwind\n"));
+
+#elif HAVE_BACKTRACE_SYMBOLS
+ void *backtrace_stack[BACKTRACE_STACK_SIZE];
+ size_t backtrace_size;
+ char **backtrace_strings;
+
+ /* get the backtrace (stack frames) */
+ backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE);
+ backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size);
+
+ DEBUG(0, ("BACKTRACE: %lu stack frames:\n",
+ (unsigned long)backtrace_size));
+
+ if (backtrace_strings) {
+ int i;
+
+ for (i = 0; i < backtrace_size; i++)
+ DEBUGADD(0, (" #%u %s\n", i, backtrace_strings[i]));
+
+ /* Leak the backtrace_strings, rather than risk what free() might do */
+ }
+
+#elif HAVE_LIBEXC
+
+ /* The IRIX libexc library provides an API for unwinding the stack. See
+ * libexc(3) for details. Apparantly trace_back_stack leaks memory, but
+ * since we are about to abort anyway, it hardly matters.
+ */
+
+#define NAMESIZE 32 /* Arbitrary */
+
+ __uint64_t addrs[BACKTRACE_STACK_SIZE];
+ char * names[BACKTRACE_STACK_SIZE];
+ char namebuf[BACKTRACE_STACK_SIZE * NAMESIZE];
+
+ int i;
+ int levels;
+
+ ZERO_ARRAY(addrs);
+ ZERO_ARRAY(names);
+ ZERO_ARRAY(namebuf);
+
+ /* We need to be root so we can open our /proc entry to walk
+ * our stack. It also helps when we want to dump core.
+ */
+ become_root();
+
+ for (i = 0; i < BACKTRACE_STACK_SIZE; i++) {
+ names[i] = namebuf + (i * NAMESIZE);
+ }
+
+ levels = trace_back_stack(0, addrs, names,
+ BACKTRACE_STACK_SIZE, NAMESIZE - 1);
+
+ DEBUG(0, ("BACKTRACE: %d stack frames:\n", levels));
+ for (i = 0; i < levels; i++) {
+ DEBUGADD(0, (" #%d 0x%llx %s\n", i, addrs[i], names[i]));
+ }
+#undef NAMESIZE
+
+#else
+ DEBUG(0, ("unable to produce a stack trace on this platform\n"));
+#endif
+}
+
+/*******************************************************************
+ A readdir wrapper which just returns the file name.
+ ********************************************************************/
+
+const char *readdirname(SMB_STRUCT_DIR *p)
+{
+ SMB_STRUCT_DIRENT *ptr;
+ char *dname;
+
+ if (!p)
+ return(NULL);
+
+ ptr = (SMB_STRUCT_DIRENT *)sys_readdir(p);
+ if (!ptr)
+ return(NULL);
+
+ dname = ptr->d_name;
+
+#ifdef NEXT2
+ if (telldir(p) < 0)
+ return(NULL);
+#endif
+
+#ifdef HAVE_BROKEN_READDIR_NAME
+ /* using /usr/ucb/cc is BAD */
+ dname = dname - 2;
+#endif
+
+ return talloc_strdup(talloc_tos(), dname);
+}
+
+/*******************************************************************
+ Utility function used to decide if the last component
+ of a path matches a (possibly wildcarded) entry in a namelist.
+********************************************************************/
+
+bool is_in_path(const char *name, name_compare_entry *namelist, bool case_sensitive)
+{
+ const char *last_component;
+
+ /* if we have no list it's obviously not in the path */
+ if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL))) {
+ return False;
+ }
+
+ DEBUG(8, ("is_in_path: %s\n", name));
+
+ /* Get the last component of the unix name. */
+ last_component = strrchr_m(name, '/');
+ if (!last_component) {
+ last_component = name;
+ } else {
+ last_component++; /* Go past '/' */
+ }
+
+ for(; namelist->name != NULL; namelist++) {
+ if(namelist->is_wild) {
+ if (mask_match(last_component, namelist->name, case_sensitive)) {
+ DEBUG(8,("is_in_path: mask match succeeded\n"));
+ return True;
+ }
+ } else {
+ if((case_sensitive && (strcmp(last_component, namelist->name) == 0))||
+ (!case_sensitive && (StrCaseCmp(last_component, namelist->name) == 0))) {
+ DEBUG(8,("is_in_path: match succeeded\n"));
+ return True;
+ }
+ }
+ }
+ DEBUG(8,("is_in_path: match not found\n"));
+ return False;
+}
+
+/*******************************************************************
+ 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, const char *namelist)
+{
+ char *name_end;
+ const 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_m(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) = SMB_MALLOC_ARRAY(name_compare_entry, num_entries + 1)) == NULL) {
+ DEBUG(0,("set_namearray: malloc fail\n"));
+ return;
+ }
+
+ /* Now copy out the names */
+ nameptr = namelist;
+ i = 0;
+ while(*nameptr) {
+ if ( *nameptr == '/' ) {
+ /* cope with multiple (useless) /s) */
+ nameptr++;
+ continue;
+ }
+ /* find the next / */
+ if ((name_end = strchr_m(nameptr, '/')) != NULL)
+ *name_end = 0;
+
+ /* oops - the last check for a / didn't find one. */
+ if(name_end == NULL)
+ break;
+
+ (*ppname_array)[i].is_wild = ms_has_wild(nameptr);
+ if(((*ppname_array)[i].name = SMB_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;
+
+ return;
+}
+
+/****************************************************************************
+ Routine to free a namearray.
+****************************************************************************/
+
+void free_namearray(name_compare_entry *name_array)
+{
+ int i;
+
+ if(name_array == NULL)
+ return;
+
+ for(i=0; name_array[i].name!=NULL; i++)
+ SAFE_FREE(name_array[i].name);
+ SAFE_FREE(name_array);
+}
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_LOCKING
+
+/****************************************************************************
+ Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping
+ is dealt with in posix.c
+ Returns True if the lock was granted, False otherwise.
+****************************************************************************/
+
+bool fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
+{
+ SMB_STRUCT_FLOCK lock;
+ int ret;
+
+ DEBUG(8,("fcntl_lock fd=%d op=%d offset=%.0f count=%.0f type=%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;
+
+ ret = sys_fcntl_ptr(fd,op,&lock);
+
+ if (ret == -1) {
+ int sav = errno;
+ DEBUG(3,("fcntl_lock: lock failed at offset %.0f count %.0f op %d type %d (%s)\n",
+ (double)offset,(double)count,op,type,strerror(errno)));
+ errno = sav;
+ return False;
+ }
+
+ /* everything went OK */
+ DEBUG(8,("fcntl_lock: Lock call successful\n"));
+
+ return True;
+}
+
+/****************************************************************************
+ Simple routine to query existing file locks. Cruft in NFS and 64->32 bit mapping
+ is dealt with in posix.c
+ Returns True if we have information regarding this lock region (and returns
+ F_UNLCK in *ptype if the region is unlocked). False if the call failed.
+****************************************************************************/
+
+bool fcntl_getlock(int fd, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
+{
+ SMB_STRUCT_FLOCK lock;
+ int ret;
+
+ DEBUG(8,("fcntl_getlock fd=%d offset=%.0f count=%.0f type=%d\n",
+ fd,(double)*poffset,(double)*pcount,*ptype));
+
+ lock.l_type = *ptype;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = *poffset;
+ lock.l_len = *pcount;
+ lock.l_pid = 0;
+
+ ret = sys_fcntl_ptr(fd,SMB_F_GETLK,&lock);
+
+ if (ret == -1) {
+ int sav = errno;
+ DEBUG(3,("fcntl_getlock: lock request failed at offset %.0f count %.0f type %d (%s)\n",
+ (double)*poffset,(double)*pcount,*ptype,strerror(errno)));
+ errno = sav;
+ return False;
+ }
+
+ *ptype = lock.l_type;
+ *poffset = lock.l_start;
+ *pcount = lock.l_len;
+ *ppid = lock.l_pid;
+
+ DEBUG(3,("fcntl_getlock: fd %d is returned info %d pid %u\n",
+ fd, (int)lock.l_type, (unsigned int)lock.l_pid));
+ return True;
+}
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_ALL
+
+/*******************************************************************
+ Is the name specified one of my netbios names.
+ Returns true if it is equal, false otherwise.
+********************************************************************/
+
+bool is_myname(const char *s)
+{
+ int n;
+ bool ret = False;
+
+ for (n=0; my_netbios_names(n); n++) {
+ if (strequal(my_netbios_names(n), s)) {
+ ret=True;
+ break;
+ }
+ }
+ DEBUG(8, ("is_myname(\"%s\") returns %d\n", s, ret));
+ return(ret);
+}
+
+/*******************************************************************
+ Is the name specified our workgroup/domain.
+ Returns true if it is equal, false otherwise.
+********************************************************************/
+
+bool is_myworkgroup(const char *s)
+{
+ bool ret = False;
+
+ if (strequal(s, lp_workgroup())) {
+ ret=True;
+ }
+
+ DEBUG(8, ("is_myworkgroup(\"%s\") returns %d\n", s, ret));
+ return(ret);
+}
+
+/*******************************************************************
+ we distinguish between 2K and XP by the "Native Lan Manager" string
+ WinXP => "Windows 2002 5.1"
+ WinXP 64bit => "Windows XP 5.2"
+ Win2k => "Windows 2000 5.0"
+ NT4 => "Windows NT 4.0"
+ Win9x => "Windows 4.0"
+ Windows 2003 doesn't set the native lan manager string but
+ they do set the domain to "Windows 2003 5.2" (probably a bug).
+********************************************************************/
+
+void ra_lanman_string( const char *native_lanman )
+{
+ if ( strcmp( native_lanman, "Windows 2002 5.1" ) == 0 )
+ set_remote_arch( RA_WINXP );
+ else if ( strcmp( native_lanman, "Windows XP 5.2" ) == 0 )
+ set_remote_arch( RA_WINXP64 );
+ else if ( strcmp( native_lanman, "Windows Server 2003 5.2" ) == 0 )
+ set_remote_arch( RA_WIN2K3 );
+}
+
+static const char *remote_arch_str;
+
+const char *get_remote_arch_str(void)
+{
+ if (!remote_arch_str) {
+ return "UNKNOWN";
+ }
+ return remote_arch_str;
+}
+
+/*******************************************************************
+ 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:
+ remote_arch_str = "WfWg";
+ break;
+ case RA_OS2:
+ remote_arch_str = "OS2";
+ break;
+ case RA_WIN95:
+ remote_arch_str = "Win95";
+ break;
+ case RA_WINNT:
+ remote_arch_str = "WinNT";
+ break;
+ case RA_WIN2K:
+ remote_arch_str = "Win2K";
+ break;
+ case RA_WINXP:
+ remote_arch_str = "WinXP";
+ break;
+ case RA_WINXP64:
+ remote_arch_str = "WinXP64";
+ break;
+ case RA_WIN2K3:
+ remote_arch_str = "Win2K3";
+ break;
+ case RA_VISTA:
+ remote_arch_str = "Vista";
+ break;
+ case RA_SAMBA:
+ remote_arch_str = "Samba";
+ break;
+ case RA_CIFSFS:
+ remote_arch_str = "CIFSFS";
+ break;
+ default:
+ ra_type = RA_UNKNOWN;
+ remote_arch_str = "UNKNOWN";
+ break;
+ }
+
+ DEBUG(10,("set_remote_arch: Client arch is \'%s\'\n",
+ remote_arch_str));
+}
+
+/*******************************************************************
+ Get the remote_arch type.
+********************************************************************/
+
+enum remote_arch_types get_remote_arch(void)
+{
+ return ra_type;
+}
+
+void print_asc(int level, const unsigned char *buf,int len)
+{
+ int i;
+ for (i=0;i<len;i++)
+ DEBUG(level,("%c", isprint(buf[i])?buf[i]:'.'));
+}
+
+void dump_data(int level, const unsigned char *buf1,int len)
+{
+ const unsigned char *buf = (const unsigned char *)buf1;
+ int i=0;
+ if (len<=0) return;
+
+ if (!DEBUGLVL(level)) return;
+
+ DEBUGADD(level,("[%03X] ",i));
+ for (i=0;i<len;) {
+ DEBUGADD(level,("%02X ",(int)buf[i]));
+ i++;
+ if (i%8 == 0) DEBUGADD(level,(" "));
+ if (i%16 == 0) {
+ print_asc(level,&buf[i-16],8); DEBUGADD(level,(" "));
+ print_asc(level,&buf[i-8],8); DEBUGADD(level,("\n"));
+ if (i<len) DEBUGADD(level,("[%03X] ",i));
+ }
+ }
+ if (i%16) {
+ int n;
+ n = 16 - (i%16);
+ DEBUGADD(level,(" "));
+ if (n>8) DEBUGADD(level,(" "));
+ while (n--) DEBUGADD(level,(" "));
+ n = MIN(8,i%16);
+ print_asc(level,&buf[i-(i%16)],n); DEBUGADD(level,( " " ));
+ n = (i%16) - n;
+ if (n>0) print_asc(level,&buf[i-n],n);
+ DEBUGADD(level,("\n"));
+ }
+}
+
+void dump_data_pw(const char *msg, const uchar * data, size_t len)
+{
+#ifdef DEBUG_PASSWORD
+ DEBUG(11, ("%s", msg));
+ if (data != NULL && len > 0)
+ {
+ dump_data(11, data, len);
+ }
+#endif
+}
+
+const char *tab_depth(int level, int depth)
+{
+ if( CHECK_DEBUGLVL(level) ) {
+ dbgtext("%*s", depth*4, "");
+ }
+ return "";
+}
+
+/*****************************************************************************
+ Provide a checksum on a string
+
+ Input: s - the null-terminated character string for which the checksum
+ will be calculated.
+
+ Output: The checksum value calculated for s.
+*****************************************************************************/
+
+int str_checksum(const char *s)
+{
+ int res = 0;
+ int c;
+ int i=0;
+
+ while(*s) {
+ c = *s;
+ res ^= (c << (i % 15)) ^ (c >> (15-(i%15)));
+ s++;
+ i++;
+ }
+ return(res);
+}
+
+/*****************************************************************
+ Zero a memory area then free it. Used to catch bugs faster.
+*****************************************************************/
+
+void zero_free(void *p, size_t size)
+{
+ memset(p, 0, size);
+ SAFE_FREE(p);
+}
+
+/*****************************************************************
+ Set our open file limit to a requested max and return the limit.
+*****************************************************************/
+
+int set_maxfiles(int requested_max)
+{
+#if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
+ struct rlimit rlp;
+ int saved_current_limit;
+
+ if(getrlimit(RLIMIT_NOFILE, &rlp)) {
+ DEBUG(0,("set_maxfiles: getrlimit (1) for RLIMIT_NOFILE failed with error %s\n",
+ strerror(errno) ));
+ /* just guess... */
+ return requested_max;
+ }
+
+ /*
+ * Set the fd limit to be real_max_open_files + MAX_OPEN_FUDGEFACTOR to
+ * account for the extra fd we need
+ * as well as the log files and standard
+ * handles etc. Save the limit we want to set in case
+ * we are running on an OS that doesn't support this limit (AIX)
+ * which always returns RLIM_INFINITY for rlp.rlim_max.
+ */
+
+ /* Try raising the hard (max) limit to the requested amount. */
+
+#if defined(RLIM_INFINITY)
+ if (rlp.rlim_max != RLIM_INFINITY) {
+ int orig_max = rlp.rlim_max;
+
+ if ( rlp.rlim_max < requested_max )
+ rlp.rlim_max = requested_max;
+
+ /* This failing is not an error - many systems (Linux) don't
+ support our default request of 10,000 open files. JRA. */
+
+ if(setrlimit(RLIMIT_NOFILE, &rlp)) {
+ DEBUG(3,("set_maxfiles: setrlimit for RLIMIT_NOFILE for %d max files failed with error %s\n",
+ (int)rlp.rlim_max, strerror(errno) ));
+
+ /* Set failed - restore original value from get. */
+ rlp.rlim_max = orig_max;
+ }
+ }
+#endif
+
+ /* Now try setting the soft (current) limit. */
+
+ saved_current_limit = rlp.rlim_cur = MIN(requested_max,rlp.rlim_max);
+
+ if(setrlimit(RLIMIT_NOFILE, &rlp)) {
+ DEBUG(0,("set_maxfiles: setrlimit for RLIMIT_NOFILE for %d files failed with error %s\n",
+ (int)rlp.rlim_cur, strerror(errno) ));
+ /* just guess... */
+ return saved_current_limit;
+ }
+
+ if(getrlimit(RLIMIT_NOFILE, &rlp)) {
+ DEBUG(0,("set_maxfiles: getrlimit (2) for RLIMIT_NOFILE failed with error %s\n",
+ strerror(errno) ));
+ /* just guess... */
+ return saved_current_limit;
+ }
+
+#if defined(RLIM_INFINITY)
+ if(rlp.rlim_cur == RLIM_INFINITY)
+ return saved_current_limit;
+#endif
+
+ if((int)rlp.rlim_cur > saved_current_limit)
+ return saved_current_limit;
+
+ return rlp.rlim_cur;
+#else /* !defined(HAVE_GETRLIMIT) || !defined(RLIMIT_NOFILE) */
+ /*
+ * No way to know - just guess...
+ */
+ return requested_max;
+#endif
+}
+
+/*****************************************************************
+ Possibly replace mkstemp if it is broken.
+*****************************************************************/
+
+int smb_mkstemp(char *name_template)
+{
+#if HAVE_SECURE_MKSTEMP
+ return mkstemp(name_template);
+#else
+ /* have a reasonable go at emulating it. Hope that
+ the system mktemp() isn't completly hopeless */
+ char *p = mktemp(name_template);
+ if (!p)
+ return -1;
+ return open(p, O_CREAT|O_EXCL|O_RDWR, 0600);
+#endif
+}
+
+/*****************************************************************
+ malloc that aborts with smb_panic on fail or zero size.
+ *****************************************************************/
+
+void *smb_xmalloc_array(size_t size, unsigned int count)
+{
+ void *p;
+ if (size == 0) {
+ smb_panic("smb_xmalloc_array: called with zero size");
+ }
+ if (count >= MAX_ALLOC_SIZE/size) {
+ smb_panic("smb_xmalloc_array: alloc size too large");
+ }
+ if ((p = SMB_MALLOC(size*count)) == NULL) {
+ DEBUG(0, ("smb_xmalloc_array failed to allocate %lu * %lu bytes\n",
+ (unsigned long)size, (unsigned long)count));
+ smb_panic("smb_xmalloc_array: malloc failed");
+ }
+ return p;
+}
+
+/**
+ Memdup with smb_panic on fail.
+**/
+
+void *smb_xmemdup(const void *p, size_t size)
+{
+ void *p2;
+ p2 = SMB_XMALLOC_ARRAY(unsigned char,size);
+ memcpy(p2, p, size);
+ return p2;
+}
+
+/**
+ strdup that aborts on malloc fail.
+**/
+
+char *smb_xstrdup(const char *s)
+{
+#if defined(PARANOID_MALLOC_CHECKER)
+#ifdef strdup
+#undef strdup
+#endif
+#endif
+
+#ifndef HAVE_STRDUP
+#define strdup rep_strdup
+#endif
+
+ char *s1 = strdup(s);
+#if defined(PARANOID_MALLOC_CHECKER)
+#ifdef strdup
+#undef strdup
+#endif
+#define strdup(s) __ERROR_DONT_USE_STRDUP_DIRECTLY
+#endif
+ if (!s1) {
+ smb_panic("smb_xstrdup: malloc failed");
+ }
+ return s1;
+
+}
+
+/**
+ strndup that aborts on malloc fail.
+**/
+
+char *smb_xstrndup(const char *s, size_t n)
+{
+#if defined(PARANOID_MALLOC_CHECKER)
+#ifdef strndup
+#undef strndup
+#endif
+#endif
+
+#if (defined(BROKEN_STRNDUP) || !defined(HAVE_STRNDUP))
+#undef HAVE_STRNDUP
+#define strndup rep_strndup
+#endif
+
+ char *s1 = strndup(s, n);
+#if defined(PARANOID_MALLOC_CHECKER)
+#ifdef strndup
+#undef strndup
+#endif
+#define strndup(s,n) __ERROR_DONT_USE_STRNDUP_DIRECTLY
+#endif
+ if (!s1) {
+ smb_panic("smb_xstrndup: malloc failed");
+ }
+ return s1;
+}
+
+/*
+ vasprintf that aborts on malloc fail
+*/
+
+ int smb_xvasprintf(char **ptr, const char *format, va_list ap)
+{
+ int n;
+ va_list ap2;
+
+ VA_COPY(ap2, ap);
+
+ n = vasprintf(ptr, format, ap2);
+ if (n == -1 || ! *ptr) {
+ smb_panic("smb_xvasprintf: out of memory");
+ }
+ va_end(ap2);
+ return n;
+}
+
+/*****************************************************************
+ Like strdup but for memory.
+*****************************************************************/
+
+void *memdup(const void *p, size_t size)
+{
+ void *p2;
+ if (size == 0)
+ return NULL;
+ p2 = SMB_MALLOC(size);
+ if (!p2)
+ return NULL;
+ memcpy(p2, p, size);
+ return p2;
+}
+
+/*****************************************************************
+ Get local hostname and cache result.
+*****************************************************************/
+
+char *myhostname(void)
+{
+ static char *ret;
+ if (ret == NULL) {
+ /* This is cached forever so
+ * use NULL talloc ctx. */
+ ret = get_myname(NULL);
+ }
+ return ret;
+}
+
+/*****************************************************************
+ A useful function for returning a path in the Samba pid directory.
+*****************************************************************/
+
+static char *xx_path(const char *name, const char *rootpath)
+{
+ char *fname = NULL;
+
+ fname = talloc_strdup(talloc_tos(), rootpath);
+ if (!fname) {
+ return NULL;
+ }
+ trim_string(fname,"","/");
+
+ if (!directory_exist(fname,NULL)) {
+ mkdir(fname,0755);
+ }
+
+ return talloc_asprintf(talloc_tos(),
+ "%s/%s",
+ fname,
+ name);
+}
+
+/*****************************************************************
+ A useful function for returning a path in the Samba lock directory.
+*****************************************************************/
+
+char *lock_path(const char *name)
+{
+ return xx_path(name, lp_lockdir());
+}
+
+/*****************************************************************
+ A useful function for returning a path in the Samba pid directory.
+*****************************************************************/
+
+char *pid_path(const char *name)
+{
+ return xx_path(name, lp_piddir());
+}
+
+/**
+ * @brief Returns an absolute path to a file in the Samba lib directory.
+ *
+ * @param name File to find, relative to LIBDIR.
+ *
+ * @retval Pointer to a string containing the full path.
+ **/
+
+char *lib_path(const char *name)
+{
+ return talloc_asprintf(talloc_tos(), "%s/%s", get_dyn_LIBDIR(), name);
+}
+
+/**
+ * @brief Returns an absolute path to a file in the Samba modules directory.
+ *
+ * @param name File to find, relative to MODULESDIR.
+ *
+ * @retval Pointer to a string containing the full path.
+ **/
+
+char *modules_path(const char *name)
+{
+ return talloc_asprintf(talloc_tos(), "%s/%s", get_dyn_MODULESDIR(), name);
+}
+
+/**
+ * @brief Returns an absolute path to a file in the Samba data directory.
+ *
+ * @param name File to find, relative to CODEPAGEDIR.
+ *
+ * @retval Pointer to a talloc'ed string containing the full path.
+ **/
+
+char *data_path(const char *name)
+{
+ return talloc_asprintf(talloc_tos(), "%s/%s", get_dyn_CODEPAGEDIR(), name);
+}
+
+/*****************************************************************
+a useful function for returning a path in the Samba state directory
+ *****************************************************************/
+
+char *state_path(const char *name)
+{
+ return xx_path(name, get_dyn_STATEDIR());
+}
+
+/**
+ * @brief Returns the platform specific shared library extension.
+ *
+ * @retval Pointer to a const char * containing the extension.
+ **/
+
+const char *shlib_ext(void)
+{
+ return get_dyn_SHLIBEXT();
+}
+
+/*******************************************************************
+ Given a filename - get its directory name
+ NB: Returned in static storage. Caveats:
+ o If caller wishes to preserve, they should copy.
+********************************************************************/
+
+char *parent_dirname(const char *path)
+{
+ char *parent;
+
+ if (!parent_dirname_talloc(talloc_tos(), path, &parent, NULL)) {
+ return NULL;
+ }
+
+ return parent;
+}
+
+bool parent_dirname_talloc(TALLOC_CTX *mem_ctx, const char *dir,
+ char **parent, const char **name)
+{
+ char *p;
+ ptrdiff_t len;
+
+ p = strrchr_m(dir, '/'); /* Find final '/', if any */
+
+ if (p == NULL) {
+ if (!(*parent = talloc_strdup(mem_ctx, "."))) {
+ return False;
+ }
+ if (name) {
+ *name = "";
+ }
+ return True;
+ }
+
+ len = p-dir;
+
+ if (!(*parent = TALLOC_ARRAY(mem_ctx, char, len+1))) {
+ return False;
+ }
+ memcpy(*parent, dir, len);
+ (*parent)[len] = '\0';
+
+ if (name) {
+ *name = p+1;
+ }
+ return True;
+}
+
+/*******************************************************************
+ Determine if a pattern contains any Microsoft wildcard characters.
+*******************************************************************/
+
+bool ms_has_wild(const char *s)
+{
+ char c;
+
+ if (lp_posix_pathnames()) {
+ /* With posix pathnames no characters are wild. */
+ return False;
+ }
+
+ while ((c = *s++)) {
+ switch (c) {
+ case '*':
+ case '?':
+ case '<':
+ case '>':
+ case '"':
+ return True;
+ }
+ }
+ return False;
+}
+
+bool ms_has_wild_w(const smb_ucs2_t *s)
+{
+ smb_ucs2_t c;
+ if (!s) return False;
+ while ((c = *s++)) {
+ switch (c) {
+ case UCS2_CHAR('*'):
+ case UCS2_CHAR('?'):
+ case UCS2_CHAR('<'):
+ case UCS2_CHAR('>'):
+ case UCS2_CHAR('"'):
+ return True;
+ }
+ }
+ return False;
+}
+
+/*******************************************************************
+ A wrapper that handles case sensitivity and the special handling
+ of the ".." name.
+*******************************************************************/
+
+bool mask_match(const char *string, const char *pattern, bool is_case_sensitive)
+{
+ if (strcmp(string,"..") == 0)
+ string = ".";
+ if (strcmp(pattern,".") == 0)
+ return False;
+
+ return ms_fnmatch(pattern, string, Protocol <= PROTOCOL_LANMAN2, is_case_sensitive) == 0;
+}
+
+/*******************************************************************
+ A wrapper that handles case sensitivity and the special handling
+ of the ".." name. Varient that is only called by old search code which requires
+ pattern translation.
+*******************************************************************/
+
+bool mask_match_search(const char *string, const char *pattern, bool is_case_sensitive)
+{
+ if (strcmp(string,"..") == 0)
+ string = ".";
+ if (strcmp(pattern,".") == 0)
+ return False;
+
+ return ms_fnmatch(pattern, string, True, is_case_sensitive) == 0;
+}
+
+/*******************************************************************
+ A wrapper that handles a list of patters and calls mask_match()
+ on each. Returns True if any of the patterns match.
+*******************************************************************/
+
+bool mask_match_list(const char *string, char **list, int listLen, bool is_case_sensitive)
+{
+ while (listLen-- > 0) {
+ if (mask_match(string, *list++, is_case_sensitive))
+ return True;
+ }
+ return False;
+}
+
+/*********************************************************
+ Recursive routine that is called by unix_wild_match.
+*********************************************************/
+
+static bool unix_do_match(const char *regexp, const char *str)
+{
+ const char *p;
+
+ for( p = regexp; *p && *str; ) {
+
+ switch(*p) {
+ case '?':
+ str++;
+ p++;
+ break;
+
+ case '*':
+
+ /*
+ * Look for a character matching
+ * the one after the '*'.
+ */
+ p++;
+ if(!*p)
+ return true; /* Automatic match */
+ while(*str) {
+
+ while(*str && (*p != *str))
+ str++;
+
+ /*
+ * Patch from weidel@multichart.de. In the case of the regexp
+ * '*XX*' we want to ensure there are at least 2 'X' characters
+ * in the string after the '*' for a match to be made.
+ */
+
+ {
+ int matchcount=0;
+
+ /*
+ * Eat all the characters that match, but count how many there were.
+ */
+
+ while(*str && (*p == *str)) {
+ str++;
+ matchcount++;
+ }
+
+ /*
+ * Now check that if the regexp had n identical characters that
+ * matchcount had at least that many matches.
+ */
+
+ while ( *(p+1) && (*(p+1) == *p)) {
+ p++;
+ matchcount--;
+ }
+
+ if ( matchcount <= 0 )
+ return false;
+ }
+
+ str--; /* We've eaten the match char after the '*' */
+
+ if(unix_do_match(p, str))
+ return true;
+
+ if(!*str)
+ return false;
+ else
+ str++;
+ }
+ return false;
+
+ default:
+ if(*str != *p)
+ return false;
+ str++;
+ p++;
+ break;
+ }
+ }
+
+ if(!*p && !*str)
+ return true;
+
+ if (!*p && str[0] == '.' && str[1] == 0)
+ return true;
+
+ if (!*str && *p == '?') {
+ while (*p == '?')
+ p++;
+ return(!*p);
+ }
+
+ if(!*str && (*p == '*' && p[1] == '\0'))
+ return true;
+
+ return false;
+}
+
+/*******************************************************************
+ Simple case insensitive interface to a UNIX wildcard matcher.
+ Returns True if match, False if not.
+*******************************************************************/
+
+bool unix_wild_match(const char *pattern, const char *string)
+{
+ TALLOC_CTX *ctx = talloc_stackframe();
+ char *p2;
+ char *s2;
+ char *p;
+ bool ret = false;
+
+ p2 = talloc_strdup(ctx,pattern);
+ s2 = talloc_strdup(ctx,string);
+ if (!p2 || !s2) {
+ TALLOC_FREE(ctx);
+ return false;
+ }
+ strlower_m(p2);
+ strlower_m(s2);
+
+ /* Remove any *? and ** from the pattern as they are meaningless */
+ for(p = p2; *p; p++) {
+ while( *p == '*' && (p[1] == '?' ||p[1] == '*')) {
+ memmove(&p[1], &p[2], strlen(&p[2])+1);
+ }
+ }
+
+ if (strequal(p2,"*")) {
+ TALLOC_FREE(ctx);
+ return true;
+ }
+
+ ret = unix_do_match(p2, s2);
+ TALLOC_FREE(ctx);
+ return ret;
+}
+
+/**********************************************************************
+ Converts a name to a fully qualified domain name.
+ Returns true if lookup succeeded, false if not (then fqdn is set to name)
+ Note we deliberately use gethostbyname here, not getaddrinfo as we want
+ to examine the h_aliases and I don't know how to do that with getaddrinfo.
+***********************************************************************/
+
+bool name_to_fqdn(fstring fqdn, const char *name)
+{
+ char *full = NULL;
+ struct hostent *hp = gethostbyname(name);
+
+ if (!hp || !hp->h_name || !*hp->h_name) {
+ DEBUG(10,("name_to_fqdn: lookup for %s failed.\n", name));
+ fstrcpy(fqdn, name);
+ return false;
+ }
+
+ /* Find out if the fqdn is returned as an alias
+ * to cope with /etc/hosts files where the first
+ * name is not the fqdn but the short name */
+ if (hp->h_aliases && (! strchr_m(hp->h_name, '.'))) {
+ int i;
+ for (i = 0; hp->h_aliases[i]; i++) {
+ if (strchr_m(hp->h_aliases[i], '.')) {
+ full = hp->h_aliases[i];
+ break;
+ }
+ }
+ }
+ if (full && (StrCaseCmp(full, "localhost.localdomain") == 0)) {
+ DEBUG(1, ("WARNING: your /etc/hosts file may be broken!\n"));
+ DEBUGADD(1, (" Specifing the machine hostname for address 127.0.0.1 may lead\n"));
+ DEBUGADD(1, (" to Kerberos authentication problems as localhost.localdomain\n"));
+ DEBUGADD(1, (" may end up being used instead of the real machine FQDN.\n"));
+ full = hp->h_name;
+ }
+ if (!full) {
+ full = hp->h_name;
+ }
+
+ DEBUG(10,("name_to_fqdn: lookup for %s -> %s.\n", name, full));
+ fstrcpy(fqdn, full);
+ return true;
+}
+
+/**********************************************************************
+ Extension to talloc_get_type: Abort on type mismatch
+***********************************************************************/
+
+void *talloc_check_name_abort(const void *ptr, const char *name)
+{
+ void *result;
+
+ result = talloc_check_name(ptr, name);
+ if (result != NULL)
+ return result;
+
+ DEBUG(0, ("Talloc type mismatch, expected %s, got %s\n",
+ name, talloc_get_name(ptr)));
+ smb_panic("talloc type mismatch");
+ /* Keep the compiler happy */
+ return NULL;
+}
+
+/**********************************************************************
+ Append a DATA_BLOB to a talloc'ed object
+***********************************************************************/
+
+void *talloc_append_blob(TALLOC_CTX *mem_ctx, void *buf, DATA_BLOB blob)
+{
+ size_t old_size = 0;
+ char *result;
+
+ if (blob.length == 0) {
+ return buf;
+ }
+
+ if (buf != NULL) {
+ old_size = talloc_get_size(buf);
+ }
+
+ result = (char *)TALLOC_REALLOC(mem_ctx, buf, old_size + blob.length);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ memcpy(result + old_size, blob.data, blob.length);
+ return result;
+}
+
+uint32 map_share_mode_to_deny_mode(uint32 share_access, uint32 private_options)
+{
+ switch (share_access & ~FILE_SHARE_DELETE) {
+ case FILE_SHARE_NONE:
+ return DENY_ALL;
+ case FILE_SHARE_READ:
+ return DENY_WRITE;
+ case FILE_SHARE_WRITE:
+ return DENY_READ;
+ case FILE_SHARE_READ|FILE_SHARE_WRITE:
+ return DENY_NONE;
+ }
+ if (private_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS) {
+ return DENY_DOS;
+ } else if (private_options & NTCREATEX_OPTIONS_PRIVATE_DENY_FCB) {
+ return DENY_FCB;
+ }
+
+ return (uint32)-1;
+}
+
+pid_t procid_to_pid(const struct server_id *proc)
+{
+ return proc->pid;
+}
+
+static uint32 my_vnn = NONCLUSTER_VNN;
+
+void set_my_vnn(uint32 vnn)
+{
+ DEBUG(10, ("vnn pid %d = %u\n", (int)sys_getpid(), (unsigned int)vnn));
+ my_vnn = vnn;
+}
+
+uint32 get_my_vnn(void)
+{
+ return my_vnn;
+}
+
+struct server_id pid_to_procid(pid_t pid)
+{
+ struct server_id result;
+ result.pid = pid;
+#ifdef CLUSTER_SUPPORT
+ result.vnn = my_vnn;
+#endif
+ return result;
+}
+
+struct server_id procid_self(void)
+{
+ return pid_to_procid(sys_getpid());
+}
+
+struct server_id server_id_self(void)
+{
+ return procid_self();
+}
+
+bool procid_equal(const struct server_id *p1, const struct server_id *p2)
+{
+ if (p1->pid != p2->pid)
+ return False;
+#ifdef CLUSTER_SUPPORT
+ if (p1->vnn != p2->vnn)
+ return False;
+#endif
+ return True;
+}
+
+bool cluster_id_equal(const struct server_id *id1,
+ const struct server_id *id2)
+{
+ return procid_equal(id1, id2);
+}
+
+bool procid_is_me(const struct server_id *pid)
+{
+ if (pid->pid != sys_getpid())
+ return False;
+#ifdef CLUSTER_SUPPORT
+ if (pid->vnn != my_vnn)
+ return False;
+#endif
+ return True;
+}
+
+struct server_id interpret_pid(const char *pid_string)
+{
+#ifdef CLUSTER_SUPPORT
+ unsigned int vnn, pid;
+ struct server_id result;
+ if (sscanf(pid_string, "%u:%u", &vnn, &pid) == 2) {
+ result.vnn = vnn;
+ result.pid = pid;
+ }
+ else if (sscanf(pid_string, "%u", &pid) == 1) {
+ result.vnn = get_my_vnn();
+ result.pid = pid;
+ }
+ else {
+ result.vnn = NONCLUSTER_VNN;
+ result.pid = -1;
+ }
+ return result;
+#else
+ return pid_to_procid(atoi(pid_string));
+#endif
+}
+
+char *procid_str(TALLOC_CTX *mem_ctx, const struct server_id *pid)
+{
+#ifdef CLUSTER_SUPPORT
+ if (pid->vnn == NONCLUSTER_VNN) {
+ return talloc_asprintf(mem_ctx,
+ "%d",
+ (int)pid->pid);
+ }
+ else {
+ return talloc_asprintf(mem_ctx,
+ "%u:%d",
+ (unsigned)pid->vnn,
+ (int)pid->pid);
+ }
+#else
+ return talloc_asprintf(mem_ctx,
+ "%d",
+ (int)pid->pid);
+#endif
+}
+
+char *procid_str_static(const struct server_id *pid)
+{
+ return procid_str(talloc_tos(), pid);
+}
+
+bool procid_valid(const struct server_id *pid)
+{
+ return (pid->pid != -1);
+}
+
+bool procid_is_local(const struct server_id *pid)
+{
+#ifdef CLUSTER_SUPPORT
+ return pid->vnn == my_vnn;
+#else
+ return True;
+#endif
+}
+
+int this_is_smp(void)
+{
+#if defined(HAVE_SYSCONF)
+
+#if defined(SYSCONF_SC_NPROC_ONLN)
+ return (sysconf(_SC_NPROC_ONLN) > 1) ? 1 : 0;
+#elif defined(SYSCONF_SC_NPROCESSORS_ONLN)
+ return (sysconf(_SC_NPROCESSORS_ONLN) > 1) ? 1 : 0;
+#else
+ return 0;
+#endif
+
+#else
+ return 0;
+#endif
+}
+
+/****************************************************************
+ Check if an offset into a buffer is safe.
+ If this returns True it's safe to indirect into the byte at
+ pointer ptr+off.
+****************************************************************/
+
+bool is_offset_safe(const char *buf_base, size_t buf_len, char *ptr, size_t off)
+{
+ const char *end_base = buf_base + buf_len;
+ char *end_ptr = ptr + off;
+
+ if (!buf_base || !ptr) {
+ return False;
+ }
+
+ if (end_base < buf_base || end_ptr < ptr) {
+ return False; /* wrap. */
+ }
+
+ if (end_ptr < end_base) {
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************
+ Return a safe pointer into a buffer, or NULL.
+****************************************************************/
+
+char *get_safe_ptr(const char *buf_base, size_t buf_len, char *ptr, size_t off)
+{
+ return is_offset_safe(buf_base, buf_len, ptr, off) ?
+ ptr + off : NULL;
+}
+
+/****************************************************************
+ Return a safe pointer into a string within a buffer, or NULL.
+****************************************************************/
+
+char *get_safe_str_ptr(const char *buf_base, size_t buf_len, char *ptr, size_t off)
+{
+ if (!is_offset_safe(buf_base, buf_len, ptr, off)) {
+ return NULL;
+ }
+ /* Check if a valid string exists at this offset. */
+ if (skip_string(buf_base,buf_len, ptr + off) == NULL) {
+ return NULL;
+ }
+ return ptr + off;
+}
+
+/****************************************************************
+ Return an SVAL at a pointer, or failval if beyond the end.
+****************************************************************/
+
+int get_safe_SVAL(const char *buf_base, size_t buf_len, char *ptr, size_t off, int failval)
+{
+ /*
+ * Note we use off+1 here, not off+2 as SVAL accesses ptr[0] and ptr[1],
+ * NOT ptr[2].
+ */
+ if (!is_offset_safe(buf_base, buf_len, ptr, off+1)) {
+ return failval;
+ }
+ return SVAL(ptr,off);
+}
+
+/****************************************************************
+ Return an IVAL at a pointer, or failval if beyond the end.
+****************************************************************/
+
+int get_safe_IVAL(const char *buf_base, size_t buf_len, char *ptr, size_t off, int failval)
+{
+ /*
+ * Note we use off+3 here, not off+4 as IVAL accesses
+ * ptr[0] ptr[1] ptr[2] ptr[3] NOT ptr[4].
+ */
+ if (!is_offset_safe(buf_base, buf_len, ptr, off+3)) {
+ return failval;
+ }
+ return IVAL(ptr,off);
+}
+
+/****************************************************************
+ Split DOM\user into DOM and user. Do not mix with winbind variants of that
+ call (they take care of winbind separator and other winbind specific settings).
+****************************************************************/
+
+void split_domain_user(TALLOC_CTX *mem_ctx,
+ const char *full_name,
+ char **domain,
+ char **user)
+{
+ const char *p = NULL;
+
+ p = strchr_m(full_name, '\\');
+
+ if (p != NULL) {
+ *domain = talloc_strndup(mem_ctx, full_name,
+ PTR_DIFF(p, full_name));
+ *user = talloc_strdup(mem_ctx, p+1);
+ } else {
+ *domain = talloc_strdup(mem_ctx, "");
+ *user = talloc_strdup(mem_ctx, full_name);
+ }
+}
+
+#if 0
+
+Disable these now we have checked all code paths and ensured
+NULL returns on zero request. JRA.
+
+/****************************************************************
+ talloc wrapper functions that guarentee a null pointer return
+ if size == 0.
+****************************************************************/
+
+#ifndef MAX_TALLOC_SIZE
+#define MAX_TALLOC_SIZE 0x10000000
+#endif
+
+/*
+ * talloc and zero memory.
+ * - returns NULL if size is zero.
+ */
+
+void *_talloc_zero_zeronull(const void *ctx, size_t size, const char *name)
+{
+ void *p;
+
+ if (size == 0) {
+ return NULL;
+ }
+
+ p = talloc_named_const(ctx, size, name);
+
+ if (p) {
+ memset(p, '\0', size);
+ }
+
+ return p;
+}
+
+/*
+ * memdup with a talloc.
+ * - returns NULL if size is zero.
+ */
+
+void *_talloc_memdup_zeronull(const void *t, const void *p, size_t size, const char *name)
+{
+ void *newp;
+
+ if (size == 0) {
+ return NULL;
+ }
+
+ newp = talloc_named_const(t, size, name);
+ if (newp) {
+ memcpy(newp, p, size);
+ }
+
+ return newp;
+}
+
+/*
+ * alloc an array, checking for integer overflow in the array size.
+ * - returns NULL if count or el_size are zero.
+ */
+
+void *_talloc_array_zeronull(const void *ctx, size_t el_size, unsigned count, const char *name)
+{
+ if (count >= MAX_TALLOC_SIZE/el_size) {
+ return NULL;
+ }
+
+ if (el_size == 0 || count == 0) {
+ return NULL;
+ }
+
+ return talloc_named_const(ctx, el_size * count, name);
+}
+
+/*
+ * alloc an zero array, checking for integer overflow in the array size
+ * - returns NULL if count or el_size are zero.
+ */
+
+void *_talloc_zero_array_zeronull(const void *ctx, size_t el_size, unsigned count, const char *name)
+{
+ if (count >= MAX_TALLOC_SIZE/el_size) {
+ return NULL;
+ }
+
+ if (el_size == 0 || count == 0) {
+ return NULL;
+ }
+
+ return _talloc_zero(ctx, el_size * count, name);
+}
+
+/*
+ * Talloc wrapper that returns NULL if size == 0.
+ */
+void *talloc_zeronull(const void *context, size_t size, const char *name)
+{
+ if (size == 0) {
+ return NULL;
+ }
+ return talloc_named_const(context, size, name);
+}
+#endif
+
+/* Split a path name into filename and stream name components. Canonicalise
+ * such that an implicit $DATA token is always explicit.
+ *
+ * The "specification" of this function can be found in the
+ * run_local_stream_name() function in torture.c, I've tried those
+ * combinations against a W2k3 server.
+ */
+
+NTSTATUS split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname,
+ char **pbase, char **pstream)
+{
+ char *base = NULL;
+ char *stream = NULL;
+ char *sname; /* stream name */
+ const char *stype; /* stream type */
+
+ DEBUG(10, ("split_ntfs_stream_name called for [%s]\n", fname));
+
+ sname = strchr_m(fname, ':');
+
+ if (lp_posix_pathnames() || (sname == NULL)) {
+ if (pbase != NULL) {
+ base = talloc_strdup(mem_ctx, fname);
+ NT_STATUS_HAVE_NO_MEMORY(base);
+ }
+ goto done;
+ }
+
+ if (pbase != NULL) {
+ base = talloc_strndup(mem_ctx, fname, PTR_DIFF(sname, fname));
+ NT_STATUS_HAVE_NO_MEMORY(base);
+ }
+
+ sname += 1;
+
+ stype = strchr_m(sname, ':');
+
+ if (stype == NULL) {
+ sname = talloc_strdup(mem_ctx, sname);
+ stype = "$DATA";
+ }
+ else {
+ if (StrCaseCmp(stype, ":$DATA") != 0) {
+ /*
+ * If there is an explicit stream type, so far we only
+ * allow $DATA. Is there anything else allowed? -- vl
+ */
+ DEBUG(10, ("[%s] is an invalid stream type\n", stype));
+ TALLOC_FREE(base);
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+ sname = talloc_strndup(mem_ctx, sname, PTR_DIFF(stype, sname));
+ stype += 1;
+ }
+
+ if (sname == NULL) {
+ TALLOC_FREE(base);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (sname[0] == '\0') {
+ /*
+ * no stream name, so no stream
+ */
+ goto done;
+ }
+
+ if (pstream != NULL) {
+ stream = talloc_asprintf(mem_ctx, "%s:%s", sname, stype);
+ if (stream == NULL) {
+ TALLOC_FREE(sname);
+ TALLOC_FREE(base);
+ return NT_STATUS_NO_MEMORY;
+ }
+ /*
+ * upper-case the type field
+ */
+ strupper_m(strchr_m(stream, ':')+1);
+ }
+
+ done:
+ if (pbase != NULL) {
+ *pbase = base;
+ }
+ if (pstream != NULL) {
+ *pstream = stream;
+ }
+ return NT_STATUS_OK;
+}
+
+bool is_valid_policy_hnd(const POLICY_HND *hnd)
+{
+ POLICY_HND tmp;
+ ZERO_STRUCT(tmp);
+ return (memcmp(&tmp, hnd, sizeof(tmp)) != 0);
+}
+
+bool policy_hnd_equal(const struct policy_handle *hnd1,
+ const struct policy_handle *hnd2)
+{
+ if (!hnd1 || !hnd2) {
+ return false;
+ }
+
+ return (memcmp(hnd1, hnd2, sizeof(*hnd1)) == 0);
+}
+
+/****************************************************************
+ strip off leading '\\' from a hostname
+****************************************************************/
+
+const char *strip_hostname(const char *s)
+{
+ if (!s) {
+ return NULL;
+ }
+
+ if (strlen_m(s) < 3) {
+ return s;
+ }
+
+ if (s[0] == '\\') s++;
+ if (s[0] == '\\') s++;
+
+ return s;
+}
diff --git a/source3/lib/util_file.c b/source3/lib/util_file.c
new file mode 100644
index 0000000000..b628b06cc6
--- /dev/null
+++ b/source3/lib/util_file.c
@@ -0,0 +1,424 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * 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 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+/****************************************************************************
+ Read a line from a file with possible \ continuation chars.
+ Blanks at the start or end of a line are stripped.
+ The string will be allocated if s2 is NULL.
+****************************************************************************/
+
+char *fgets_slash(char *s2,int maxlen,XFILE *f)
+{
+ char *s=s2;
+ int len = 0;
+ int c;
+ bool start_of_line = True;
+
+ if (x_feof(f)) {
+ return(NULL);
+ }
+
+ if (maxlen <2) {
+ return(NULL);
+ }
+
+ if (!s2) {
+ maxlen = MIN(maxlen,8);
+ s = (char *)SMB_MALLOC(maxlen);
+ }
+
+ if (!s) {
+ return(NULL);
+ }
+
+ *s = 0;
+
+ while (len < maxlen-1) {
+ c = x_getc(f);
+ switch (c) {
+ case '\r':
+ break;
+ case '\n':
+ while (len > 0 && s[len-1] == ' ') {
+ s[--len] = 0;
+ }
+ if (len > 0 && s[len-1] == '\\') {
+ s[--len] = 0;
+ start_of_line = True;
+ break;
+ }
+ return(s);
+ case EOF:
+ if (len <= 0 && !s2) {
+ SAFE_FREE(s);
+ }
+ return(len>0?s:NULL);
+ case ' ':
+ if (start_of_line) {
+ break;
+ }
+ default:
+ start_of_line = False;
+ s[len++] = c;
+ s[len] = 0;
+ }
+
+ if (!s2 && len > maxlen-3) {
+ maxlen *= 2;
+ s = (char *)SMB_REALLOC(s,maxlen);
+ if (!s) {
+ DEBUG(0,("fgets_slash: failed to expand buffer!\n"));
+ return(NULL);
+ }
+ }
+ }
+ return(s);
+}
+
+/****************************************************************************
+ Load from a pipe into memory.
+****************************************************************************/
+
+static char *file_pload(char *syscmd, size_t *size)
+{
+ int fd, n;
+ char *p;
+ char buf[1024];
+ size_t total;
+
+ fd = sys_popen(syscmd);
+ if (fd == -1) {
+ return NULL;
+ }
+
+ p = NULL;
+ total = 0;
+
+ while ((n = read(fd, buf, sizeof(buf))) > 0) {
+ p = (char *)SMB_REALLOC(p, total + n + 1);
+ if (!p) {
+ DEBUG(0,("file_pload: failed to expand buffer!\n"));
+ close(fd);
+ return NULL;
+ }
+ memcpy(p+total, buf, n);
+ total += n;
+ }
+
+ if (p) {
+ p[total] = 0;
+ }
+
+ /* FIXME: Perhaps ought to check that the command completed
+ * successfully (returned 0); if not the data may be
+ * truncated. */
+ sys_pclose(fd);
+
+ if (size) {
+ *size = total;
+ }
+
+ return p;
+}
+
+/****************************************************************************
+ Load a file into memory from a fd.
+ Truncate at maxsize. If maxsize == 0 - no limit.
+****************************************************************************/
+
+char *fd_load(int fd, size_t *psize, size_t maxsize)
+{
+ SMB_STRUCT_STAT sbuf;
+ size_t size;
+ char *p;
+
+ if (sys_fstat(fd, &sbuf) != 0) {
+ return NULL;
+ }
+
+ size = sbuf.st_size;
+ if (maxsize) {
+ size = MIN(size, maxsize);
+ }
+
+ p = (char *)SMB_MALLOC(size+1);
+ if (!p) {
+ return NULL;
+ }
+
+ if (read(fd, p, size) != size) {
+ SAFE_FREE(p);
+ return NULL;
+ }
+ p[size] = 0;
+
+ if (psize) {
+ *psize = size;
+ }
+
+ return p;
+}
+
+/****************************************************************************
+ Load a file into memory.
+****************************************************************************/
+
+char *file_load(const char *fname, size_t *size, size_t maxsize)
+{
+ int fd;
+ char *p;
+
+ if (!fname || !*fname) {
+ return NULL;
+ }
+
+ fd = open(fname,O_RDONLY);
+ if (fd == -1) {
+ return NULL;
+ }
+
+ p = fd_load(fd, size, maxsize);
+ close(fd);
+ return p;
+}
+
+/*******************************************************************
+ unmap or free memory
+*******************************************************************/
+
+bool unmap_file(void* start, size_t size)
+{
+#ifdef HAVE_MMAP
+ if ( munmap( start, size ) != 0 ) {
+ DEBUG( 1, ("map_file: Failed to unmap address %p "
+ "of size %u - %s\n",
+ start, (unsigned int)size, strerror(errno) ));
+ return False;
+ }
+ return True;
+#else
+ SAFE_FREE( start );
+ return True;
+#endif
+}
+
+/*******************************************************************
+ mmap (if possible) or read a file.
+********************************************************************/
+
+void *map_file(char *fname, size_t size)
+{
+ size_t s2 = 0;
+ void *p = NULL;
+#ifdef HAVE_MMAP
+ int fd;
+ fd = open(fname, O_RDONLY, 0);
+ if (fd == -1) {
+ DEBUG(2,("map_file: Failed to load %s - %s\n", fname, strerror(errno)));
+ return NULL;
+ }
+ p = mmap(NULL, size, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
+ close(fd);
+ if (p == MAP_FAILED) {
+ DEBUG(1,("map_file: Failed to mmap %s - %s\n", fname, strerror(errno)));
+ return NULL;
+ }
+#endif
+ if (!p) {
+ p = file_load(fname, &s2, 0);
+ if (!p) {
+ return NULL;
+ }
+ if (s2 != size) {
+ DEBUG(1,("map_file: incorrect size for %s - got %lu expected %lu\n",
+ fname, (unsigned long)s2, (unsigned long)size));
+ SAFE_FREE(p);
+ return NULL;
+ }
+ }
+ return p;
+}
+
+/****************************************************************************
+ Parse a buffer into lines.
+****************************************************************************/
+
+static char **file_lines_parse(char *p, size_t size, int *numlines)
+{
+ int i;
+ char *s, **ret;
+
+ if (!p) {
+ return NULL;
+ }
+
+ for (s = p, i=0; s < p+size; s++) {
+ if (s[0] == '\n') i++;
+ }
+
+ ret = SMB_MALLOC_ARRAY(char *, i+2);
+ if (!ret) {
+ SAFE_FREE(p);
+ return NULL;
+ }
+ memset(ret, 0, sizeof(ret[0])*(i+2));
+
+ ret[0] = p;
+ for (s = p, i=0; s < p+size; s++) {
+ if (s[0] == '\n') {
+ s[0] = 0;
+ i++;
+ ret[i] = s+1;
+ }
+ if (s[0] == '\r') {
+ s[0] = 0;
+ }
+ }
+
+ /* remove any blank lines at the end */
+ while (i > 0 && ret[i-1][0] == 0) {
+ i--;
+ }
+
+ if (numlines) {
+ *numlines = i;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Load a file into memory and return an array of pointers to lines in the file
+ must be freed with file_lines_free().
+****************************************************************************/
+
+char **file_lines_load(const char *fname, int *numlines, size_t maxsize)
+{
+ char *p;
+ size_t size = 0;
+
+ p = file_load(fname, &size, maxsize);
+ if (!p) {
+ return NULL;
+ }
+
+ return file_lines_parse(p, size, numlines);
+}
+
+/****************************************************************************
+ Load a fd into memory and return an array of pointers to lines in the file
+ must be freed with file_lines_free(). If convert is true calls unix_to_dos on
+ the list.
+****************************************************************************/
+
+char **fd_lines_load(int fd, int *numlines, size_t maxsize)
+{
+ char *p;
+ size_t size;
+
+ p = fd_load(fd, &size, maxsize);
+ if (!p) {
+ return NULL;
+ }
+
+ return file_lines_parse(p, size, numlines);
+}
+
+/****************************************************************************
+ Load a pipe into memory and return an array of pointers to lines in the data
+ must be freed with file_lines_free().
+****************************************************************************/
+
+char **file_lines_pload(char *syscmd, int *numlines)
+{
+ char *p;
+ size_t size;
+
+ p = file_pload(syscmd, &size);
+ if (!p) {
+ return NULL;
+ }
+
+ return file_lines_parse(p, size, numlines);
+}
+
+/****************************************************************************
+ Free lines loaded with file_lines_load.
+****************************************************************************/
+
+void file_lines_free(char **lines)
+{
+ if (!lines) {
+ return;
+ }
+ SAFE_FREE(lines[0]);
+ SAFE_FREE(lines);
+}
+
+/****************************************************************************
+ Take a list of lines and modify them to produce a list where \ continues
+ a line.
+****************************************************************************/
+
+void file_lines_slashcont(char **lines)
+{
+ int i, j;
+
+ for (i=0; lines[i];) {
+ int len = strlen(lines[i]);
+ if (lines[i][len-1] == '\\') {
+ lines[i][len-1] = ' ';
+ if (lines[i+1]) {
+ char *p = &lines[i][len];
+ while (p < lines[i+1]) {
+ *p++ = ' ';
+ }
+ for (j = i+1; lines[j]; j++) {
+ lines[j] = lines[j+1];
+ }
+ }
+ } else {
+ i++;
+ }
+ }
+}
+
+/****************************************************************************
+ Save a lump of data into a file. Mostly used for debugging.
+****************************************************************************/
+
+bool file_save(const char *fname, void *packet, size_t length)
+{
+ int fd;
+ fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (fd == -1) {
+ return False;
+ }
+ if (write(fd, packet, length) != (size_t)length) {
+ return False;
+ }
+ close(fd);
+ return True;
+}
diff --git a/source3/lib/util_nscd.c b/source3/lib/util_nscd.c
new file mode 100644
index 0000000000..f019bdd70b
--- /dev/null
+++ b/source3/lib/util_nscd.c
@@ -0,0 +1,41 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Guenther Deschner 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static void smb_nscd_flush_cache(const char *service)
+{
+#ifdef HAVE_NSCD_FLUSH_CACHE
+ if (!nscd_flush_cache(service)) {
+ DEBUG(10,("failed to flush nscd cache for '%s' service: %s. "
+ "Is nscd running?\n",
+ service, strerror(errno)));
+ }
+#endif
+}
+
+void smb_nscd_flush_user_cache(void)
+{
+ smb_nscd_flush_cache("passwd");
+}
+
+void smb_nscd_flush_group_cache(void)
+{
+ smb_nscd_flush_cache("group");
+}
diff --git a/source3/lib/util_nttoken.c b/source3/lib/util_nttoken.c
new file mode 100644
index 0000000000..774ef498b7
--- /dev/null
+++ b/source3/lib/util_nttoken.c
@@ -0,0 +1,117 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Authentication utility functions
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Andrew Bartlett 2001
+ * Copyright (C) Jeremy Allison 2000-2001
+ * Copyright (C) Rafal Szczesniak 2002
+ * Copyright (C) Volker Lendecke 2006
+ * Copyright (C) Michael Adam 2007
+ * Copyright (C) Guenther Deschner 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* function(s) moved from auth/auth_util.c to minimize linker deps */
+
+#include "includes.h"
+
+/****************************************************************************
+ Duplicate a SID token.
+****************************************************************************/
+
+NT_USER_TOKEN *dup_nt_token(TALLOC_CTX *mem_ctx, const NT_USER_TOKEN *ptoken)
+{
+ NT_USER_TOKEN *token;
+
+ if (!ptoken)
+ return NULL;
+
+ token = TALLOC_ZERO_P(mem_ctx, NT_USER_TOKEN);
+ if (token == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ if (ptoken->user_sids && ptoken->num_sids) {
+ token->user_sids = (DOM_SID *)talloc_memdup(
+ token, ptoken->user_sids, sizeof(DOM_SID) * ptoken->num_sids );
+
+ if (token->user_sids == NULL) {
+ DEBUG(0, ("talloc_memdup failed\n"));
+ TALLOC_FREE(token);
+ return NULL;
+ }
+ token->num_sids = ptoken->num_sids;
+ }
+
+ /* copy the privileges; don't consider failure to be critical here */
+
+ if ( !se_priv_copy( &token->privileges, &ptoken->privileges ) ) {
+ DEBUG(0,("dup_nt_token: Failure to copy SE_PRIV!. "
+ "Continuing with 0 privileges assigned.\n"));
+ }
+
+ return token;
+}
+
+/****************************************************************************
+ merge NT tokens
+****************************************************************************/
+
+NTSTATUS merge_nt_token(TALLOC_CTX *mem_ctx,
+ const struct nt_user_token *token_1,
+ const struct nt_user_token *token_2,
+ struct nt_user_token **token_out)
+{
+ struct nt_user_token *token = NULL;
+ NTSTATUS status;
+ int i;
+
+ if (!token_1 || !token_2 || !token_out) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ token = TALLOC_ZERO_P(mem_ctx, struct nt_user_token);
+ NT_STATUS_HAVE_NO_MEMORY(token);
+
+ for (i=0; i < token_1->num_sids; i++) {
+ status = add_sid_to_array_unique(mem_ctx,
+ &token_1->user_sids[i],
+ &token->user_sids,
+ &token->num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(token);
+ return status;
+ }
+ }
+
+ for (i=0; i < token_2->num_sids; i++) {
+ status = add_sid_to_array_unique(mem_ctx,
+ &token_2->user_sids[i],
+ &token->user_sids,
+ &token->num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(token);
+ return status;
+ }
+ }
+
+ se_priv_add(&token->privileges, &token_1->privileges);
+ se_priv_add(&token->privileges, &token_2->privileges);
+
+ *token_out = token;
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/lib/util_pw.c b/source3/lib/util_pw.c
new file mode 100644
index 0000000000..428378505f
--- /dev/null
+++ b/source3/lib/util_pw.c
@@ -0,0 +1,89 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Safe versions of getpw* calls
+
+ Copyright (C) Andrew Bartlett 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+struct passwd *tcopy_passwd(TALLOC_CTX *mem_ctx, const struct passwd *from)
+{
+ struct passwd *ret = TALLOC_P(mem_ctx, struct passwd);
+ if (!ret) {
+ return NULL;
+ }
+ ret->pw_name = talloc_strdup(ret, from->pw_name);
+ ret->pw_passwd = talloc_strdup(ret, from->pw_passwd);
+ ret->pw_uid = from->pw_uid;
+ ret->pw_gid = from->pw_gid;
+ ret->pw_gecos = talloc_strdup(ret, from->pw_gecos);
+ ret->pw_dir = talloc_strdup(ret, from->pw_dir);
+ ret->pw_shell = talloc_strdup(ret, from->pw_shell);
+ return ret;
+}
+
+void flush_pwnam_cache(void)
+{
+ memcache_flush(NULL, GETPWNAM_CACHE);
+}
+
+struct passwd *getpwnam_alloc(TALLOC_CTX *mem_ctx, const char *name)
+{
+ struct passwd *temp, *cached;
+
+ temp = (struct passwd *)memcache_lookup_talloc(
+ NULL, GETPWNAM_CACHE, data_blob_string_const(name));
+ if (temp != NULL) {
+ return tcopy_passwd(mem_ctx, temp);
+ }
+
+ temp = sys_getpwnam(name);
+ if (temp == NULL) {
+ return NULL;
+ }
+
+ cached = tcopy_passwd(NULL, temp);
+ if (cached == NULL) {
+ /*
+ * Just don't add this into the cache, ignore the failure
+ */
+ return temp;
+ }
+
+ memcache_add_talloc(NULL, GETPWNAM_CACHE, data_blob_string_const(name),
+ cached);
+ return tcopy_passwd(mem_ctx, temp);
+}
+
+struct passwd *getpwuid_alloc(TALLOC_CTX *mem_ctx, uid_t uid)
+{
+ struct passwd *temp;
+
+ temp = sys_getpwuid(uid);
+
+ if (!temp) {
+#if 0
+ if (errno == ENOMEM) {
+ /* what now? */
+ }
+#endif
+ return NULL;
+ }
+
+ return tcopy_passwd(mem_ctx, temp);
+}
diff --git a/source3/lib/util_reg.c b/source3/lib/util_reg.c
new file mode 100644
index 0000000000..6570bb072d
--- /dev/null
+++ b/source3/lib/util_reg.c
@@ -0,0 +1,112 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Registry helper routines
+ * Copyright (C) Volker Lendecke 2006
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+extern REGISTRY_OPS smbconf_reg_ops;
+
+const char *reg_type_lookup(enum winreg_Type type)
+{
+ const char *result;
+
+ switch(type) {
+ case REG_NONE:
+ result = "REG_NONE";
+ break;
+ case REG_SZ:
+ result = "REG_SZ";
+ break;
+ case REG_EXPAND_SZ:
+ result = "REG_EXPAND_SZ";
+ break;
+ case REG_BINARY:
+ result = "REG_BINARY";
+ break;
+ case REG_DWORD:
+ result = "REG_DWORD";
+ break;
+ case REG_DWORD_BIG_ENDIAN:
+ result = "REG_DWORD_BIG_ENDIAN";
+ break;
+ case REG_LINK:
+ result = "REG_LINK";
+ break;
+ case REG_MULTI_SZ:
+ result = "REG_MULTI_SZ";
+ break;
+ case REG_RESOURCE_LIST:
+ result = "REG_RESOURCE_LIST";
+ break;
+ case REG_FULL_RESOURCE_DESCRIPTOR:
+ result = "REG_FULL_RESOURCE_DESCRIPTOR";
+ break;
+ case REG_RESOURCE_REQUIREMENTS_LIST:
+ result = "REG_RESOURCE_REQUIREMENTS_LIST";
+ break;
+ case REG_QWORD:
+ result = "REG_QWORD";
+ break;
+ default:
+ result = "REG TYPE IS UNKNOWN";
+ break;
+ }
+ return result;
+}
+
+WERROR reg_pull_multi_sz(TALLOC_CTX *mem_ctx, const void *buf, size_t len,
+ uint32 *num_values, char ***values)
+{
+ const smb_ucs2_t *p = (const smb_ucs2_t *)buf;
+ *num_values = 0;
+
+ /*
+ * Make sure that a talloc context for the strings retrieved exists
+ */
+
+ if (!(*values = TALLOC_ARRAY(mem_ctx, char *, 1))) {
+ return WERR_NOMEM;
+ }
+
+ len /= 2; /* buf is a set of UCS2 strings */
+
+ while (len > 0) {
+ char *val;
+ size_t dstlen, thislen;
+
+ thislen = strnlen_w(p, len) + 1;
+ if (!convert_string_allocate(*values, CH_UTF16LE, CH_UNIX,
+ p, thislen*2, (void *)&val, &dstlen, true)) {
+ TALLOC_FREE(*values);
+ return WERR_NOMEM;
+ }
+
+ ADD_TO_ARRAY(*values, char *, val, values, num_values);
+ if (*values == NULL) {
+ return WERR_NOMEM;
+ }
+
+ p += thislen;
+ len -= thislen;
+ }
+
+ return WERR_OK;
+}
diff --git a/source3/lib/util_reg_api.c b/source3/lib/util_reg_api.c
new file mode 100644
index 0000000000..8f28e9c282
--- /dev/null
+++ b/source3/lib/util_reg_api.c
@@ -0,0 +1,223 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Registry helper routines
+ * Copyright (C) Volker Lendecke 2006
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+WERROR registry_pull_value(TALLOC_CTX *mem_ctx,
+ struct registry_value **pvalue,
+ enum winreg_Type type, uint8 *data,
+ uint32 size, uint32 length)
+{
+ struct registry_value *value;
+ WERROR err;
+
+ if (!(value = TALLOC_ZERO_P(mem_ctx, struct registry_value))) {
+ return WERR_NOMEM;
+ }
+
+ value->type = type;
+
+ switch (type) {
+ case REG_DWORD:
+ if ((size != 4) || (length != 4)) {
+ err = WERR_INVALID_PARAM;
+ goto error;
+ }
+ value->v.dword = IVAL(data, 0);
+ break;
+ case REG_SZ:
+ case REG_EXPAND_SZ:
+ {
+ /*
+ * Make sure we get a NULL terminated string for
+ * convert_string_talloc().
+ */
+
+ smb_ucs2_t *tmp;
+
+ if (length == 1) {
+ /* win2k regedit gives us a string of 1 byte when
+ * creating a new value of type REG_SZ. this workaround
+ * replaces the input by using the same string as
+ * winxp delivers. */
+ length = 2;
+ if (!(tmp = SMB_MALLOC_ARRAY(smb_ucs2_t, 2))) {
+ err = WERR_NOMEM;
+ goto error;
+ }
+ tmp[0] = 0;
+ tmp[1] = 0;
+ DEBUG(10, ("got REG_SZ value of length 1 - workaround "
+ "activated.\n"));
+ }
+ else if ((length % 2) != 0) {
+ err = WERR_INVALID_PARAM;
+ goto error;
+ }
+ else {
+ uint32 num_ucs2 = length / 2;
+ if (!(tmp = SMB_MALLOC_ARRAY(smb_ucs2_t, num_ucs2+1))) {
+ err = WERR_NOMEM;
+ goto error;
+ }
+
+ memcpy((void *)tmp, (const void *)data, length);
+ tmp[num_ucs2] = 0;
+ }
+
+ if (length + 2 < length) {
+ /* Integer wrap. */
+ SAFE_FREE(tmp);
+ err = WERR_INVALID_PARAM;
+ goto error;
+ }
+
+ if (!convert_string_talloc(value, CH_UTF16LE, CH_UNIX, tmp,
+ length+2, &value->v.sz.str,
+ &value->v.sz.len, False)) {
+ SAFE_FREE(tmp);
+ err = WERR_INVALID_PARAM;
+ goto error;
+ }
+
+ SAFE_FREE(tmp);
+ break;
+ }
+ case REG_MULTI_SZ:
+ err = reg_pull_multi_sz(value, (void *)data, length,
+ &value->v.multi_sz.num_strings,
+ &value->v.multi_sz.strings);
+ if (!(W_ERROR_IS_OK(err))) {
+ goto error;
+ }
+ break;
+ case REG_BINARY:
+ value->v.binary = data_blob_talloc(mem_ctx, data, length);
+ break;
+ default:
+ err = WERR_INVALID_PARAM;
+ goto error;
+ }
+
+ *pvalue = value;
+ return WERR_OK;
+
+ error:
+ TALLOC_FREE(value);
+ return err;
+}
+
+WERROR registry_push_value(TALLOC_CTX *mem_ctx,
+ const struct registry_value *value,
+ DATA_BLOB *presult)
+{
+ switch (value->type) {
+ case REG_DWORD: {
+ char buf[4];
+ SIVAL(buf, 0, value->v.dword);
+ *presult = data_blob_talloc(mem_ctx, (void *)buf, 4);
+ if (presult->data == NULL) {
+ return WERR_NOMEM;
+ }
+ break;
+ }
+ case REG_SZ:
+ case REG_EXPAND_SZ: {
+ if (!convert_string_talloc(mem_ctx, CH_UNIX, CH_UTF16LE,
+ value->v.sz.str,
+ MIN(value->v.sz.len,
+ strlen(value->v.sz.str)+1),
+ (void *)&(presult->data),
+ &presult->length, False))
+ {
+ return WERR_NOMEM;
+ }
+ break;
+ }
+ case REG_MULTI_SZ: {
+ uint32_t count;
+ size_t len = 0;
+ char **strings;
+ size_t *string_lengths;
+ uint32_t ofs;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ strings = TALLOC_ARRAY(tmp_ctx, char *,
+ value->v.multi_sz.num_strings);
+ if (strings == NULL) {
+ return WERR_NOMEM;
+ }
+
+ string_lengths = TALLOC_ARRAY(tmp_ctx, size_t,
+ value->v.multi_sz.num_strings);
+ if (string_lengths == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return WERR_NOMEM;
+ }
+
+ /* convert the single strings */
+ for (count = 0; count < value->v.multi_sz.num_strings; count++)
+ {
+ if (!convert_string_talloc(strings, CH_UNIX,
+ CH_UTF16LE, value->v.multi_sz.strings[count],
+ strlen(value->v.multi_sz.strings[count])+1,
+ (void *)&strings[count],
+ &string_lengths[count], false))
+ {
+
+ TALLOC_FREE(tmp_ctx);
+ return WERR_NOMEM;
+ }
+ len += string_lengths[count];
+ }
+
+ /* now concatenate all into the data blob */
+ presult->data = TALLOC_ARRAY(mem_ctx, uint8_t, len);
+ if (presult->data == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return WERR_NOMEM;
+ }
+ for (count = 0, ofs = 0;
+ count < value->v.multi_sz.num_strings;
+ count++)
+ {
+ memcpy(presult->data + ofs, strings[count],
+ string_lengths[count]);
+ ofs += string_lengths[count];
+ }
+ presult->length = len;
+
+ TALLOC_FREE(tmp_ctx);
+
+ break;
+ }
+ case REG_BINARY:
+ *presult = data_blob_talloc(mem_ctx,
+ value->v.binary.data,
+ value->v.binary.length);
+ break;
+ default:
+ return WERR_INVALID_PARAM;
+ }
+
+ return WERR_OK;
+}
diff --git a/source3/lib/util_seaccess.c b/source3/lib/util_seaccess.c
new file mode 100644
index 0000000000..87e70bb95b
--- /dev/null
+++ b/source3/lib/util_seaccess.c
@@ -0,0 +1,359 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000.
+ Copyright (C) Tim Potter 2000.
+ Copyright (C) Re-written by Jeremy Allison 2000.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern NT_USER_TOKEN anonymous_token;
+
+/*********************************************************************************
+ Check an ACE against a SID. We return the remaining needed permission
+ bits not yet granted. Zero means permission allowed (no more needed bits).
+**********************************************************************************/
+
+static uint32 check_ace(SEC_ACE *ace, const NT_USER_TOKEN *token, uint32 acc_desired,
+ NTSTATUS *status)
+{
+ uint32 mask = ace->access_mask;
+
+ /*
+ * Inherit only is ignored.
+ */
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ return acc_desired;
+ }
+
+ /*
+ * If this ACE has no SID in common with the token,
+ * ignore it as it cannot be used to make an access
+ * determination.
+ */
+
+ if (!token_sid_in_ace( token, ace))
+ return acc_desired;
+
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ /*
+ * This is explicitly allowed.
+ * Remove the bits from the remaining
+ * access required. Return the remaining
+ * bits needed.
+ */
+ acc_desired &= ~mask;
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ /*
+ * This is explicitly denied.
+ * If any bits match terminate here,
+ * we are denied.
+ */
+ if (acc_desired & mask) {
+ *status = NT_STATUS_ACCESS_DENIED;
+ return 0xFFFFFFFF;
+ }
+ break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM:
+ case SEC_ACE_TYPE_SYSTEM_AUDIT:
+ *status = NT_STATUS_NOT_IMPLEMENTED;
+ return 0xFFFFFFFF;
+ default:
+ *status = NT_STATUS_INVALID_PARAMETER;
+ return 0xFFFFFFFF;
+ }
+
+ return acc_desired;
+}
+
+/*********************************************************************************
+ Maximum access was requested. Calculate the max possible. Fail if it doesn't
+ include other bits requested.
+**********************************************************************************/
+
+static bool get_max_access( SEC_ACL *the_acl, const NT_USER_TOKEN *token, uint32 *granted,
+ uint32 desired,
+ NTSTATUS *status)
+{
+ uint32 acc_denied = 0;
+ uint32 acc_granted = 0;
+ size_t i;
+
+ for ( i = 0 ; i < the_acl->num_aces; i++) {
+ SEC_ACE *ace = &the_acl->aces[i];
+ uint32 mask = ace->access_mask;
+
+ if (!token_sid_in_ace( token, ace))
+ continue;
+
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ acc_granted |= (mask & ~acc_denied);
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ acc_denied |= (mask & ~acc_granted);
+ break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM:
+ case SEC_ACE_TYPE_SYSTEM_AUDIT:
+ *status = NT_STATUS_NOT_IMPLEMENTED;
+ *granted = 0;
+ return False;
+ default:
+ *status = NT_STATUS_INVALID_PARAMETER;
+ *granted = 0;
+ return False;
+ }
+ }
+
+ /*
+ * If we were granted no access, or we desired bits that we
+ * didn't get, then deny.
+ */
+
+ if ((acc_granted == 0) || ((acc_granted & desired) != desired)) {
+ *status = NT_STATUS_ACCESS_DENIED;
+ *granted = 0;
+ return False;
+ }
+
+ /*
+ * Return the access we did get.
+ */
+
+ *granted = acc_granted;
+ *status = NT_STATUS_OK;
+ return True;
+}
+
+/* Map generic access rights to object specific rights. This technique is
+ used to give meaning to assigning read, write, execute and all access to
+ objects. Each type of object has its own mapping of generic to object
+ specific access rights. */
+
+void se_map_generic(uint32 *access_mask, const struct generic_mapping *mapping)
+{
+ uint32 old_mask = *access_mask;
+
+ if (*access_mask & GENERIC_READ_ACCESS) {
+ *access_mask &= ~GENERIC_READ_ACCESS;
+ *access_mask |= mapping->generic_read;
+ }
+
+ if (*access_mask & GENERIC_WRITE_ACCESS) {
+ *access_mask &= ~GENERIC_WRITE_ACCESS;
+ *access_mask |= mapping->generic_write;
+ }
+
+ if (*access_mask & GENERIC_EXECUTE_ACCESS) {
+ *access_mask &= ~GENERIC_EXECUTE_ACCESS;
+ *access_mask |= mapping->generic_execute;
+ }
+
+ if (*access_mask & GENERIC_ALL_ACCESS) {
+ *access_mask &= ~GENERIC_ALL_ACCESS;
+ *access_mask |= mapping->generic_all;
+ }
+
+ if (old_mask != *access_mask) {
+ DEBUG(10, ("se_map_generic(): mapped mask 0x%08x to 0x%08x\n",
+ old_mask, *access_mask));
+ }
+}
+
+/* Map standard access rights to object specific rights. This technique is
+ used to give meaning to assigning read, write, execute and all access to
+ objects. Each type of object has its own mapping of standard to object
+ specific access rights. */
+
+void se_map_standard(uint32 *access_mask, struct standard_mapping *mapping)
+{
+ uint32 old_mask = *access_mask;
+
+ if (*access_mask & READ_CONTROL_ACCESS) {
+ *access_mask &= ~READ_CONTROL_ACCESS;
+ *access_mask |= mapping->std_read;
+ }
+
+ if (*access_mask & (DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|SYNCHRONIZE_ACCESS)) {
+ *access_mask &= ~(DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|SYNCHRONIZE_ACCESS);
+ *access_mask |= mapping->std_all;
+ }
+
+ if (old_mask != *access_mask) {
+ DEBUG(10, ("se_map_standard(): mapped mask 0x%08x to 0x%08x\n",
+ old_mask, *access_mask));
+ }
+}
+
+/*****************************************************************************
+ Check access rights of a user against a security descriptor. Look at
+ each ACE in the security descriptor until an access denied ACE denies
+ any of the desired rights to the user or any of the users groups, or one
+ or more ACEs explicitly grant all requested access rights. See
+ "Access-Checking" document in MSDN.
+*****************************************************************************/
+
+bool se_access_check(const SEC_DESC *sd, const NT_USER_TOKEN *token,
+ uint32 acc_desired, uint32 *acc_granted,
+ NTSTATUS *status)
+{
+ size_t i;
+ SEC_ACL *the_acl;
+ uint32 tmp_acc_desired = acc_desired;
+
+ if (!status || !acc_granted)
+ return False;
+
+ if (!token)
+ token = &anonymous_token;
+
+ *status = NT_STATUS_OK;
+ *acc_granted = 0;
+
+ DEBUG(10,("se_access_check: requested access 0x%08x, for NT token "
+ "with %u entries and first sid %s.\n",
+ (unsigned int)acc_desired, (unsigned int)token->num_sids,
+ sid_string_dbg(&token->user_sids[0])));
+
+ /*
+ * No security descriptor or security descriptor with no DACL
+ * present allows all access.
+ */
+
+ /* ACL must have something in it */
+
+ if (!sd || (sd && (!(sd->type & SEC_DESC_DACL_PRESENT) || sd->dacl == NULL))) {
+ *status = NT_STATUS_OK;
+ *acc_granted = acc_desired;
+ DEBUG(5, ("se_access_check: no sd or blank DACL, access allowed\n"));
+ return True;
+ }
+
+ /* The user sid is the first in the token */
+ if (DEBUGLVL(3)) {
+ DEBUG(3, ("se_access_check: user sid is %s\n",
+ sid_string_dbg(
+ &token->user_sids[PRIMARY_USER_SID_INDEX])));
+
+ for (i = 1; i < token->num_sids; i++) {
+ DEBUGADD(3, ("se_access_check: also %s\n",
+ sid_string_dbg(&token->user_sids[i])));
+ }
+ }
+
+ /* Is the token the owner of the SID ? */
+
+ if (sd->owner_sid) {
+ for (i = 0; i < token->num_sids; i++) {
+ if (sid_equal(&token->user_sids[i], sd->owner_sid)) {
+ /*
+ * The owner always has SEC_RIGHTS_WRITE_DAC & READ_CONTROL.
+ */
+ if (tmp_acc_desired & WRITE_DAC_ACCESS)
+ tmp_acc_desired &= ~WRITE_DAC_ACCESS;
+ if (tmp_acc_desired & READ_CONTROL_ACCESS)
+ tmp_acc_desired &= ~READ_CONTROL_ACCESS;
+ }
+ }
+ }
+
+ the_acl = sd->dacl;
+
+ if (tmp_acc_desired & MAXIMUM_ALLOWED_ACCESS) {
+ tmp_acc_desired &= ~MAXIMUM_ALLOWED_ACCESS;
+ return get_max_access( the_acl, token, acc_granted, tmp_acc_desired,
+ status);
+ }
+
+ for ( i = 0 ; i < the_acl->num_aces && tmp_acc_desired != 0; i++) {
+ SEC_ACE *ace = &the_acl->aces[i];
+
+ DEBUGADD(10,("se_access_check: ACE %u: type %d, flags = "
+ "0x%02x, SID = %s mask = %x, current desired "
+ "= %x\n", (unsigned int)i, ace->type, ace->flags,
+ sid_string_dbg(&ace->trustee),
+ (unsigned int) ace->access_mask,
+ (unsigned int)tmp_acc_desired ));
+
+ tmp_acc_desired = check_ace( ace, token, tmp_acc_desired, status);
+ if (NT_STATUS_V(*status)) {
+ *acc_granted = 0;
+ DEBUG(5,("se_access_check: ACE %u denied with status %s.\n", (unsigned int)i, nt_errstr(*status)));
+ return False;
+ }
+ }
+
+ /*
+ * If there are no more desired permissions left then
+ * access was allowed.
+ */
+
+ if (tmp_acc_desired == 0) {
+ *acc_granted = acc_desired;
+ *status = NT_STATUS_OK;
+ DEBUG(5,("se_access_check: access (%x) granted.\n", (unsigned int)acc_desired ));
+ return True;
+ }
+
+ *acc_granted = 0;
+ *status = NT_STATUS_ACCESS_DENIED;
+ DEBUG(5,("se_access_check: access (%x) denied.\n", (unsigned int)acc_desired ));
+ return False;
+}
+
+
+/*******************************************************************
+ samr_make_sam_obj_sd
+ ********************************************************************/
+
+NTSTATUS samr_make_sam_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd_size)
+{
+ DOM_SID adm_sid;
+ DOM_SID act_sid;
+
+ SEC_ACE ace[3];
+ SEC_ACCESS mask;
+
+ SEC_ACL *psa = NULL;
+
+ sid_copy(&adm_sid, &global_sid_Builtin);
+ sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
+
+ sid_copy(&act_sid, &global_sid_Builtin);
+ sid_append_rid(&act_sid, BUILTIN_ALIAS_RID_ACCOUNT_OPS);
+
+ /*basic access for every one*/
+ init_sec_access(&mask, GENERIC_RIGHTS_SAM_EXECUTE | GENERIC_RIGHTS_SAM_READ);
+ init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ /*full access for builtin aliases Administrators and Account Operators*/
+ init_sec_access(&mask, GENERIC_RIGHTS_SAM_ALL_ACCESS);
+ init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+ init_sec_ace(&ace[2], &act_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if ((*psd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
+ SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL,
+ psa, sd_size)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/lib/util_sec.c b/source3/lib/util_sec.c
new file mode 100644
index 0000000000..d7984ac999
--- /dev/null
+++ b/source3/lib/util_sec.c
@@ -0,0 +1,482 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Jeremy Allison 1998.
+ rewritten for version 2.0.6 by Tridge
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef AUTOCONF_TEST
+#include "includes.h"
+#else
+/* we are running this code in autoconf test mode to see which type of setuid
+ function works */
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_PRIV_H
+#include <sys/priv.h>
+#endif
+#ifdef HAVE_SYS_ID_H
+#include <sys/id.h>
+#endif
+
+#define DEBUG(x, y) printf y
+#define smb_panic(x) exit(1)
+#define bool int
+#endif
+
+/* are we running as non-root? This is used by the regresison test code,
+ and potentially also for sites that want non-root smbd */
+static uid_t initial_uid;
+static gid_t initial_gid;
+
+/****************************************************************************
+remember what uid we got started as - this allows us to run correctly
+as non-root while catching trapdoor systems
+****************************************************************************/
+
+void sec_init(void)
+{
+ static int initialized;
+
+ if (!initialized) {
+ initial_uid = geteuid();
+ initial_gid = getegid();
+ initialized = 1;
+ }
+}
+
+/****************************************************************************
+some code (eg. winbindd) needs to know what uid we started as
+****************************************************************************/
+uid_t sec_initial_uid(void)
+{
+ return initial_uid;
+}
+
+/****************************************************************************
+some code (eg. winbindd, profiling shm) needs to know what gid we started as
+****************************************************************************/
+gid_t sec_initial_gid(void)
+{
+ return initial_gid;
+}
+
+/****************************************************************************
+are we running in non-root mode?
+****************************************************************************/
+bool non_root_mode(void)
+{
+ return (initial_uid != (uid_t)0);
+}
+
+/****************************************************************************
+abort if we haven't set the uid correctly
+****************************************************************************/
+static void assert_uid(uid_t ruid, uid_t euid)
+{
+ if ((euid != (uid_t)-1 && geteuid() != euid) ||
+ (ruid != (uid_t)-1 && getuid() != ruid)) {
+ if (!non_root_mode()) {
+ DEBUG(0,("Failed to set uid privileges to (%d,%d) now set to (%d,%d)\n",
+ (int)ruid, (int)euid,
+ (int)getuid(), (int)geteuid()));
+ smb_panic("failed to set uid\n");
+ exit(1);
+ }
+ }
+}
+
+/****************************************************************************
+abort if we haven't set the gid correctly
+****************************************************************************/
+static void assert_gid(gid_t rgid, gid_t egid)
+{
+ if ((egid != (gid_t)-1 && getegid() != egid) ||
+ (rgid != (gid_t)-1 && getgid() != rgid)) {
+ if (!non_root_mode()) {
+ DEBUG(0,("Failed to set gid privileges to (%d,%d) now set to (%d,%d) uid=(%d,%d)\n",
+ (int)rgid, (int)egid,
+ (int)getgid(), (int)getegid(),
+ (int)getuid(), (int)geteuid()));
+ smb_panic("failed to set gid\n");
+ exit(1);
+ }
+ }
+}
+
+/****************************************************************************
+ Gain root privilege before doing something.
+ We want to end up with ruid==euid==0
+****************************************************************************/
+void gain_root_privilege(void)
+{
+#if USE_SETRESUID
+ setresuid(0,0,0);
+#endif
+
+#if USE_SETEUID
+ seteuid(0);
+#endif
+
+#if USE_SETREUID
+ setreuid(0, 0);
+#endif
+
+#if USE_SETUIDX
+ setuidx(ID_EFFECTIVE, 0);
+ setuidx(ID_REAL, 0);
+#endif
+
+ /* this is needed on some systems */
+ setuid(0);
+
+ assert_uid(0, 0);
+}
+
+
+/****************************************************************************
+ Ensure our real and effective groups are zero.
+ we want to end up with rgid==egid==0
+****************************************************************************/
+void gain_root_group_privilege(void)
+{
+#if USE_SETRESUID
+ setresgid(0,0,0);
+#endif
+
+#if USE_SETREUID
+ setregid(0,0);
+#endif
+
+#if USE_SETEUID
+ setegid(0);
+#endif
+
+#if USE_SETUIDX
+ setgidx(ID_EFFECTIVE, 0);
+ setgidx(ID_REAL, 0);
+#endif
+
+ setgid(0);
+
+ assert_gid(0, 0);
+}
+
+
+/****************************************************************************
+ Set effective uid, and possibly the real uid too.
+ We want to end up with either:
+
+ ruid==uid and euid==uid
+
+ or
+
+ ruid==0 and euid==uid
+
+ depending on what the local OS will allow us to regain root from.
+****************************************************************************/
+void set_effective_uid(uid_t uid)
+{
+#if USE_SETRESUID
+ /* Set the effective as well as the real uid. */
+ if (setresuid(uid,uid,-1) == -1) {
+ if (errno == EAGAIN) {
+ DEBUG(0, ("setresuid failed with EAGAIN. uid(%d) "
+ "might be over its NPROC limit\n",
+ (int)uid));
+ }
+ }
+#endif
+
+#if USE_SETREUID
+ setreuid(-1,uid);
+#endif
+
+#if USE_SETEUID
+ seteuid(uid);
+#endif
+
+#if USE_SETUIDX
+ setuidx(ID_EFFECTIVE, uid);
+#endif
+
+ assert_uid(-1, uid);
+}
+
+/****************************************************************************
+ Set *only* the effective gid.
+ we want to end up with rgid==0 and egid==gid
+****************************************************************************/
+void set_effective_gid(gid_t gid)
+{
+#if USE_SETRESUID
+ setresgid(-1,gid,-1);
+#endif
+
+#if USE_SETREUID
+ setregid(-1,gid);
+#endif
+
+#if USE_SETEUID
+ setegid(gid);
+#endif
+
+#if USE_SETUIDX
+ setgidx(ID_EFFECTIVE, gid);
+#endif
+
+ assert_gid(-1, gid);
+}
+
+static uid_t saved_euid, saved_ruid;
+static gid_t saved_egid, saved_rgid;
+
+/****************************************************************************
+ save the real and effective uid for later restoration. Used by the quotas
+ code
+****************************************************************************/
+void save_re_uid(void)
+{
+ saved_ruid = getuid();
+ saved_euid = geteuid();
+}
+
+
+/****************************************************************************
+ and restore them!
+****************************************************************************/
+
+void restore_re_uid_fromroot(void)
+{
+#if USE_SETRESUID
+ setresuid(saved_ruid, saved_euid, -1);
+#elif USE_SETREUID
+ setreuid(saved_ruid, -1);
+ setreuid(-1,saved_euid);
+#elif USE_SETUIDX
+ setuidx(ID_REAL, saved_ruid);
+ setuidx(ID_EFFECTIVE, saved_euid);
+#else
+ set_effective_uid(saved_euid);
+ if (getuid() != saved_ruid)
+ setuid(saved_ruid);
+ set_effective_uid(saved_euid);
+#endif
+
+ assert_uid(saved_ruid, saved_euid);
+}
+
+void restore_re_uid(void)
+{
+ set_effective_uid(0);
+ restore_re_uid_fromroot();
+}
+
+/****************************************************************************
+ save the real and effective gid for later restoration. Used by the
+ getgroups code
+****************************************************************************/
+void save_re_gid(void)
+{
+ saved_rgid = getgid();
+ saved_egid = getegid();
+}
+
+/****************************************************************************
+ and restore them!
+****************************************************************************/
+void restore_re_gid(void)
+{
+#if USE_SETRESUID
+ setresgid(saved_rgid, saved_egid, -1);
+#elif USE_SETREUID
+ setregid(saved_rgid, -1);
+ setregid(-1,saved_egid);
+#elif USE_SETUIDX
+ setgidx(ID_REAL, saved_rgid);
+ setgidx(ID_EFFECTIVE, saved_egid);
+#else
+ set_effective_gid(saved_egid);
+ if (getgid() != saved_rgid)
+ setgid(saved_rgid);
+ set_effective_gid(saved_egid);
+#endif
+
+ assert_gid(saved_rgid, saved_egid);
+}
+
+
+/****************************************************************************
+ set the real AND effective uid to the current effective uid in a way that
+ allows root to be regained.
+ This is only possible on some platforms.
+****************************************************************************/
+int set_re_uid(void)
+{
+ uid_t uid = geteuid();
+
+#if USE_SETRESUID
+ setresuid(geteuid(), -1, -1);
+#endif
+
+#if USE_SETREUID
+ setreuid(0, 0);
+ setreuid(uid, -1);
+ setreuid(-1, uid);
+#endif
+
+#if USE_SETEUID
+ /* can't be done */
+ return -1;
+#endif
+
+#if USE_SETUIDX
+ /* can't be done */
+ return -1;
+#endif
+
+ assert_uid(uid, uid);
+ return 0;
+}
+
+
+/****************************************************************************
+ Become the specified uid and gid - permanently !
+ there should be no way back if possible
+****************************************************************************/
+void become_user_permanently(uid_t uid, gid_t gid)
+{
+ /*
+ * First - gain root privilege. We do this to ensure
+ * we can lose it again.
+ */
+
+ gain_root_privilege();
+ gain_root_group_privilege();
+
+#if USE_SETRESUID
+ setresgid(gid,gid,gid);
+ setgid(gid);
+ setresuid(uid,uid,uid);
+ setuid(uid);
+#endif
+
+#if USE_SETREUID
+ setregid(gid,gid);
+ setgid(gid);
+ setreuid(uid,uid);
+ setuid(uid);
+#endif
+
+#if USE_SETEUID
+ setegid(gid);
+ setgid(gid);
+ setuid(uid);
+ seteuid(uid);
+ setuid(uid);
+#endif
+
+#if USE_SETUIDX
+ setgidx(ID_REAL, gid);
+ setgidx(ID_EFFECTIVE, gid);
+ setgid(gid);
+ setuidx(ID_REAL, uid);
+ setuidx(ID_EFFECTIVE, uid);
+ setuid(uid);
+#endif
+
+ assert_uid(uid, uid);
+ assert_gid(gid, gid);
+}
+
+#ifdef AUTOCONF_TEST
+
+/****************************************************************************
+this function just checks that we don't get ENOSYS back
+****************************************************************************/
+static int have_syscall(void)
+{
+ errno = 0;
+
+#if USE_SETRESUID
+ setresuid(-1,-1,-1);
+#endif
+
+#if USE_SETREUID
+ setreuid(-1,-1);
+#endif
+
+#if USE_SETEUID
+ seteuid(-1);
+#endif
+
+#if USE_SETUIDX
+ setuidx(ID_EFFECTIVE, -1);
+#endif
+
+ if (errno == ENOSYS) return -1;
+
+ return 0;
+}
+
+main()
+{
+ if (getuid() != 0) {
+#if (defined(AIX) && defined(USE_SETREUID))
+ /* setreuid is badly broken on AIX 4.1, we avoid it completely */
+ fprintf(stderr,"avoiding possibly broken setreuid\n");
+ exit(1);
+#endif
+
+ /* if not running as root then at least check to see if we get ENOSYS - this
+ handles Linux 2.0.x with glibc 2.1 */
+ fprintf(stderr,"not running as root: checking for ENOSYS\n");
+ exit(have_syscall());
+ }
+
+ gain_root_privilege();
+ gain_root_group_privilege();
+ set_effective_gid(1);
+ set_effective_uid(1);
+ save_re_uid();
+ restore_re_uid();
+ gain_root_privilege();
+ gain_root_group_privilege();
+ become_user_permanently(1, 1);
+ setuid(0);
+ if (getuid() == 0) {
+ fprintf(stderr,"uid not set permanently\n");
+ exit(1);
+ }
+
+ printf("OK\n");
+
+ exit(0);
+}
+#endif
+
+/****************************************************************************
+Check if we are setuid root. Used in libsmb and smbpasswd paranoia checks.
+****************************************************************************/
+bool is_setuid_root(void)
+{
+ return (geteuid() == (uid_t)0) && (getuid() != (uid_t)0);
+}
diff --git a/source3/lib/util_sid.c b/source3/lib/util_sid.c
new file mode 100644
index 0000000000..53614ed1ac
--- /dev/null
+++ b/source3/lib/util_sid.c
@@ -0,0 +1,751 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Luke Kenneth Caseson Leighton 1998-1999
+ Copyright (C) Jeremy Allison 1999
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Simo Sorce 2002
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*
+ * Some useful sids, more well known sids can be found at
+ * http://support.microsoft.com/kb/243330/EN-US/
+ */
+
+
+const DOM_SID global_sid_World_Domain = /* Everyone domain */
+{ 1, 0, {0,0,0,0,0,1}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_World = /* Everyone */
+{ 1, 1, {0,0,0,0,0,1}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_Creator_Owner_Domain = /* Creator Owner domain */
+{ 1, 0, {0,0,0,0,0,3}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_NT_Authority = /* NT Authority */
+{ 1, 0, {0,0,0,0,0,5}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_System = /* System */
+{ 1, 1, {0,0,0,0,0,5}, {18,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_NULL = /* NULL sid */
+{ 1, 1, {0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_Authenticated_Users = /* All authenticated rids */
+{ 1, 1, {0,0,0,0,0,5}, {11,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+#if 0
+/* for documentation */
+const DOM_SID global_sid_Restriced = /* Restriced Code */
+{ 1, 1, {0,0,0,0,0,5}, {12,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+#endif
+const DOM_SID global_sid_Network = /* Network rids */
+{ 1, 1, {0,0,0,0,0,5}, {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+
+const DOM_SID global_sid_Creator_Owner = /* Creator Owner */
+{ 1, 1, {0,0,0,0,0,3}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_Creator_Group = /* Creator Group */
+{ 1, 1, {0,0,0,0,0,3}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_Anonymous = /* Anonymous login */
+{ 1, 1, {0,0,0,0,0,5}, {7,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+
+const DOM_SID global_sid_Builtin = /* Local well-known domain */
+{ 1, 1, {0,0,0,0,0,5}, {32,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_Builtin_Administrators = /* Builtin administrators */
+{ 1, 2, {0,0,0,0,0,5}, {32,544,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_Builtin_Users = /* Builtin users */
+{ 1, 2, {0,0,0,0,0,5}, {32,545,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_Builtin_Guests = /* Builtin guest users */
+{ 1, 2, {0,0,0,0,0,5}, {32,546,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_Builtin_Power_Users = /* Builtin power users */
+{ 1, 2, {0,0,0,0,0,5}, {32,547,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_Builtin_Account_Operators = /* Builtin account operators */
+{ 1, 2, {0,0,0,0,0,5}, {32,548,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_Builtin_Server_Operators = /* Builtin server operators */
+{ 1, 2, {0,0,0,0,0,5}, {32,549,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_Builtin_Print_Operators = /* Builtin print operators */
+{ 1, 2, {0,0,0,0,0,5}, {32,550,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_Builtin_Backup_Operators = /* Builtin backup operators */
+{ 1, 2, {0,0,0,0,0,5}, {32,551,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_Builtin_Replicator = /* Builtin replicator */
+{ 1, 2, {0,0,0,0,0,5}, {32,552,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_Builtin_PreWin2kAccess = /* Builtin pre win2k access */
+{ 1, 2, {0,0,0,0,0,5}, {32,554,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+
+const DOM_SID global_sid_Unix_Users = /* Unmapped Unix users */
+{ 1, 1, {0,0,0,0,0,22}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const DOM_SID global_sid_Unix_Groups = /* Unmapped Unix groups */
+{ 1, 1, {0,0,0,0,0,22}, {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+
+/* Unused, left here for documentary purposes */
+#if 0
+#define SECURITY_NULL_SID_AUTHORITY 0
+#define SECURITY_WORLD_SID_AUTHORITY 1
+#define SECURITY_LOCAL_SID_AUTHORITY 2
+#define SECURITY_CREATOR_SID_AUTHORITY 3
+#define SECURITY_NT_AUTHORITY 5
+#endif
+
+/*
+ * An NT compatible anonymous token.
+ */
+
+static DOM_SID anon_sid_array[3] =
+{ { 1, 1, {0,0,0,0,0,1}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}},
+ { 1, 1, {0,0,0,0,0,5}, {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0}},
+ { 1, 1, {0,0,0,0,0,5}, {7,0,0,0,0,0,0,0,0,0,0,0,0,0,0}} };
+NT_USER_TOKEN anonymous_token = { 3, anon_sid_array, SE_NONE };
+
+static DOM_SID system_sid_array[1] =
+{ { 1, 1, {0,0,0,0,0,5}, {18,0,0,0,0,0,0,0,0,0,0,0,0,0,0}} };
+NT_USER_TOKEN system_token = { 1, system_sid_array, SE_ALL_PRIVS };
+
+/****************************************************************************
+ Lookup string names for SID types.
+****************************************************************************/
+
+static const struct {
+ enum lsa_SidType sid_type;
+ const char *string;
+} sid_name_type[] = {
+ {SID_NAME_USER, "User"},
+ {SID_NAME_DOM_GRP, "Domain Group"},
+ {SID_NAME_DOMAIN, "Domain"},
+ {SID_NAME_ALIAS, "Local Group"},
+ {SID_NAME_WKN_GRP, "Well-known Group"},
+ {SID_NAME_DELETED, "Deleted Account"},
+ {SID_NAME_INVALID, "Invalid Account"},
+ {SID_NAME_UNKNOWN, "UNKNOWN"},
+ {SID_NAME_COMPUTER, "Computer"},
+
+ {(enum lsa_SidType)0, NULL}
+};
+
+const char *sid_type_lookup(uint32 sid_type)
+{
+ int i = 0;
+
+ /* Look through list */
+ while(sid_name_type[i].sid_type != 0) {
+ if (sid_name_type[i].sid_type == sid_type)
+ return sid_name_type[i].string;
+ i++;
+ }
+
+ /* Default return */
+ return "SID *TYPE* is INVALID";
+}
+
+/**************************************************************************
+ Create the SYSTEM token.
+***************************************************************************/
+
+NT_USER_TOKEN *get_system_token(void)
+{
+ return &system_token;
+}
+
+/******************************************************************
+ get the default domain/netbios name to be used when dealing
+ with our passdb list of accounts
+******************************************************************/
+
+const char *get_global_sam_name(void)
+{
+ if ((lp_server_role() == ROLE_DOMAIN_PDC) || (lp_server_role() == ROLE_DOMAIN_BDC)) {
+ return lp_workgroup();
+ }
+ return global_myname();
+}
+
+/*****************************************************************
+ Convert a SID to an ascii string.
+*****************************************************************/
+
+char *sid_to_fstring(fstring sidstr_out, const DOM_SID *sid)
+{
+ char *str = sid_string_talloc(talloc_tos(), sid);
+ fstrcpy(sidstr_out, str);
+ TALLOC_FREE(str);
+ return sidstr_out;
+}
+
+/*****************************************************************
+ Essentially a renamed dom_sid_string from librpc/ndr with a
+ panic if it didn't work
+
+ This introduces a dependency on librpc/ndr/sid.o which can easily
+ be turned around if necessary
+*****************************************************************/
+
+char *sid_string_talloc(TALLOC_CTX *mem_ctx, const DOM_SID *sid)
+{
+ char *result = dom_sid_string(mem_ctx, sid);
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+/*****************************************************************
+ Useful function for debug lines.
+*****************************************************************/
+
+char *sid_string_dbg(const DOM_SID *sid)
+{
+ return sid_string_talloc(debug_ctx(), sid);
+}
+
+/*****************************************************************
+ Use with care!
+*****************************************************************/
+
+char *sid_string_tos(const DOM_SID *sid)
+{
+ return sid_string_talloc(talloc_tos(), sid);
+}
+
+/*****************************************************************
+ Convert a string to a SID. Returns True on success, False on fail.
+*****************************************************************/
+
+bool string_to_sid(DOM_SID *sidout, const char *sidstr)
+{
+ const char *p;
+ char *q;
+ /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
+ uint32 conv;
+
+ if ((sidstr[0] != 'S' && sidstr[0] != 's') || sidstr[1] != '-') {
+ DEBUG(3,("string_to_sid: Sid %s does not start with 'S-'.\n", sidstr));
+ return False;
+ }
+
+ ZERO_STRUCTP(sidout);
+
+ /* Get the revision number. */
+ p = sidstr + 2;
+ conv = (uint32) strtoul(p, &q, 10);
+ if (!q || (*q != '-')) {
+ DEBUG(3,("string_to_sid: Sid %s is not in a valid format.\n", sidstr));
+ return False;
+ }
+ sidout->sid_rev_num = (uint8) conv;
+ q++;
+
+ /* get identauth */
+ conv = (uint32) strtoul(q, &q, 10);
+ if (!q || (*q != '-')) {
+ DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr));
+ return False;
+ }
+ /* identauth in decimal should be < 2^32 */
+ /* NOTE - the conv value is in big-endian format. */
+ sidout->id_auth[0] = 0;
+ sidout->id_auth[1] = 0;
+ sidout->id_auth[2] = (conv & 0xff000000) >> 24;
+ sidout->id_auth[3] = (conv & 0x00ff0000) >> 16;
+ sidout->id_auth[4] = (conv & 0x0000ff00) >> 8;
+ sidout->id_auth[5] = (conv & 0x000000ff);
+
+ q++;
+ sidout->num_auths = 0;
+
+ for(conv = (uint32) strtoul(q, &q, 10);
+ q && (*q =='-' || *q =='\0') && (sidout->num_auths < MAXSUBAUTHS);
+ conv = (uint32) strtoul(q, &q, 10)) {
+ sid_append_rid(sidout, conv);
+ if (*q == '\0')
+ break;
+ q++;
+ }
+
+ return True;
+}
+
+DOM_SID *string_sid_talloc(TALLOC_CTX *mem_ctx, const char *sidstr)
+{
+ DOM_SID *result = TALLOC_P(mem_ctx, DOM_SID);
+
+ if (result == NULL)
+ return NULL;
+
+ if (!string_to_sid(result, sidstr))
+ return NULL;
+
+ return result;
+}
+
+/*****************************************************************
+ Add a rid to the end of a sid
+*****************************************************************/
+
+bool sid_append_rid(DOM_SID *sid, uint32 rid)
+{
+ if (sid->num_auths < MAXSUBAUTHS) {
+ sid->sub_auths[sid->num_auths++] = rid;
+ return True;
+ }
+ return False;
+}
+
+bool sid_compose(DOM_SID *dst, const DOM_SID *domain_sid, uint32 rid)
+{
+ sid_copy(dst, domain_sid);
+ return sid_append_rid(dst, rid);
+}
+
+/*****************************************************************
+ Removes the last rid from the end of a sid
+*****************************************************************/
+
+bool sid_split_rid(DOM_SID *sid, uint32 *rid)
+{
+ if (sid->num_auths > 0) {
+ sid->num_auths--;
+ *rid = sid->sub_auths[sid->num_auths];
+ return True;
+ }
+ return False;
+}
+
+/*****************************************************************
+ Return the last rid from the end of a sid
+*****************************************************************/
+
+bool sid_peek_rid(const DOM_SID *sid, uint32 *rid)
+{
+ if (!sid || !rid)
+ return False;
+
+ if (sid->num_auths > 0) {
+ *rid = sid->sub_auths[sid->num_auths - 1];
+ return True;
+ }
+ return False;
+}
+
+/*****************************************************************
+ Return the last rid from the end of a sid
+ and check the sid against the exp_dom_sid
+*****************************************************************/
+
+bool sid_peek_check_rid(const DOM_SID *exp_dom_sid, const DOM_SID *sid, uint32 *rid)
+{
+ if (!exp_dom_sid || !sid || !rid)
+ return False;
+
+ if (sid->num_auths != (exp_dom_sid->num_auths+1)) {
+ return False;
+ }
+
+ if (sid_compare_domain(exp_dom_sid, sid)!=0){
+ *rid=(-1);
+ return False;
+ }
+
+ return sid_peek_rid(sid, rid);
+}
+
+/*****************************************************************
+ Copies a sid
+*****************************************************************/
+
+void sid_copy(DOM_SID *dst, const DOM_SID *src)
+{
+ int i;
+
+ ZERO_STRUCTP(dst);
+
+ dst->sid_rev_num = src->sid_rev_num;
+ dst->num_auths = src->num_auths;
+
+ memcpy(&dst->id_auth[0], &src->id_auth[0], sizeof(src->id_auth));
+
+ for (i = 0; i < src->num_auths; i++)
+ dst->sub_auths[i] = src->sub_auths[i];
+}
+
+/*****************************************************************
+ Write a sid out into on-the-wire format.
+*****************************************************************/
+
+bool sid_linearize(char *outbuf, size_t len, const DOM_SID *sid)
+{
+ size_t i;
+
+ if (len < ndr_size_dom_sid(sid, 0))
+ return False;
+
+ SCVAL(outbuf,0,sid->sid_rev_num);
+ SCVAL(outbuf,1,sid->num_auths);
+ memcpy(&outbuf[2], sid->id_auth, 6);
+ for(i = 0; i < sid->num_auths; i++)
+ SIVAL(outbuf, 8 + (i*4), sid->sub_auths[i]);
+
+ return True;
+}
+
+/*****************************************************************
+ Parse a on-the-wire SID to a DOM_SID.
+*****************************************************************/
+
+bool sid_parse(const char *inbuf, size_t len, DOM_SID *sid)
+{
+ int i;
+ if (len < 8)
+ return False;
+
+ ZERO_STRUCTP(sid);
+
+ sid->sid_rev_num = CVAL(inbuf, 0);
+ sid->num_auths = CVAL(inbuf, 1);
+ memcpy(sid->id_auth, inbuf+2, 6);
+ if (len < 8 + sid->num_auths*4)
+ return False;
+ for (i=0;i<sid->num_auths;i++)
+ sid->sub_auths[i] = IVAL(inbuf, 8+i*4);
+ return True;
+}
+
+/*****************************************************************
+ Compare the auth portion of two sids.
+*****************************************************************/
+
+static int sid_compare_auth(const DOM_SID *sid1, const DOM_SID *sid2)
+{
+ int i;
+
+ if (sid1 == sid2)
+ return 0;
+ if (!sid1)
+ return -1;
+ if (!sid2)
+ return 1;
+
+ if (sid1->sid_rev_num != sid2->sid_rev_num)
+ return sid1->sid_rev_num - sid2->sid_rev_num;
+
+ for (i = 0; i < 6; i++)
+ if (sid1->id_auth[i] != sid2->id_auth[i])
+ return sid1->id_auth[i] - sid2->id_auth[i];
+
+ return 0;
+}
+
+/*****************************************************************
+ Compare two sids.
+*****************************************************************/
+
+int sid_compare(const DOM_SID *sid1, const DOM_SID *sid2)
+{
+ int i;
+
+ if (sid1 == sid2)
+ return 0;
+ if (!sid1)
+ return -1;
+ if (!sid2)
+ return 1;
+
+ /* Compare most likely different rids, first: i.e start at end */
+ if (sid1->num_auths != sid2->num_auths)
+ return sid1->num_auths - sid2->num_auths;
+
+ for (i = sid1->num_auths-1; i >= 0; --i)
+ if (sid1->sub_auths[i] != sid2->sub_auths[i])
+ return sid1->sub_auths[i] - sid2->sub_auths[i];
+
+ return sid_compare_auth(sid1, sid2);
+}
+
+/*****************************************************************
+ See if 2 SIDs are in the same domain
+ this just compares the leading sub-auths
+*****************************************************************/
+
+int sid_compare_domain(const DOM_SID *sid1, const DOM_SID *sid2)
+{
+ int n, i;
+
+ n = MIN(sid1->num_auths, sid2->num_auths);
+
+ for (i = n-1; i >= 0; --i)
+ if (sid1->sub_auths[i] != sid2->sub_auths[i])
+ return sid1->sub_auths[i] - sid2->sub_auths[i];
+
+ return sid_compare_auth(sid1, sid2);
+}
+
+/*****************************************************************
+ Compare two sids.
+*****************************************************************/
+
+bool sid_equal(const DOM_SID *sid1, const DOM_SID *sid2)
+{
+ return sid_compare(sid1, sid2) == 0;
+}
+
+/*****************************************************************
+ Returns true if SID is internal (and non-mappable).
+*****************************************************************/
+
+bool non_mappable_sid(DOM_SID *sid)
+{
+ DOM_SID dom;
+ uint32 rid;
+
+ sid_copy(&dom, sid);
+ sid_split_rid(&dom, &rid);
+
+ if (sid_equal(&dom, &global_sid_Builtin))
+ return True;
+
+ if (sid_equal(&dom, &global_sid_NT_Authority))
+ return True;
+
+ return False;
+}
+
+/*****************************************************************
+ Return the binary string representation of a DOM_SID.
+ Caller must free.
+*****************************************************************/
+
+char *sid_binstring(const DOM_SID *sid)
+{
+ char *buf, *s;
+ int len = ndr_size_dom_sid(sid, 0);
+ buf = (char *)SMB_MALLOC(len);
+ if (!buf)
+ return NULL;
+ sid_linearize(buf, len, sid);
+ s = binary_string_rfc2254(buf, len);
+ free(buf);
+ return s;
+}
+
+/*****************************************************************
+ Return the binary string representation of a DOM_SID.
+ Caller must free.
+*****************************************************************/
+
+char *sid_binstring_hex(const DOM_SID *sid)
+{
+ char *buf, *s;
+ int len = ndr_size_dom_sid(sid, 0);
+ buf = (char *)SMB_MALLOC(len);
+ if (!buf)
+ return NULL;
+ sid_linearize(buf, len, sid);
+ s = binary_string(buf, len);
+ free(buf);
+ return s;
+}
+
+/*******************************************************************
+ Tallocs a duplicate SID.
+********************************************************************/
+
+DOM_SID *sid_dup_talloc(TALLOC_CTX *ctx, const DOM_SID *src)
+{
+ DOM_SID *dst;
+
+ if(!src)
+ return NULL;
+
+ if((dst = TALLOC_ZERO_P(ctx, DOM_SID)) != NULL) {
+ sid_copy( dst, src);
+ }
+
+ return dst;
+}
+
+/********************************************************************
+ Add SID to an array SIDs
+********************************************************************/
+
+NTSTATUS add_sid_to_array(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ DOM_SID **sids, size_t *num)
+{
+ *sids = TALLOC_REALLOC_ARRAY(mem_ctx, *sids, DOM_SID,
+ (*num)+1);
+ if (*sids == NULL) {
+ *num = 0;
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ sid_copy(&((*sids)[*num]), sid);
+ *num += 1;
+
+ return NT_STATUS_OK;
+}
+
+
+/********************************************************************
+ Add SID to an array SIDs ensuring that it is not already there
+********************************************************************/
+
+NTSTATUS add_sid_to_array_unique(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ DOM_SID **sids, size_t *num_sids)
+{
+ size_t i;
+
+ for (i=0; i<(*num_sids); i++) {
+ if (sid_compare(sid, &(*sids)[i]) == 0)
+ return NT_STATUS_OK;
+ }
+
+ return add_sid_to_array(mem_ctx, sid, sids, num_sids);
+}
+
+/********************************************************************
+ Remove SID from an array
+********************************************************************/
+
+void del_sid_from_array(const DOM_SID *sid, DOM_SID **sids, size_t *num)
+{
+ DOM_SID *sid_list = *sids;
+ size_t i;
+
+ for ( i=0; i<*num; i++ ) {
+
+ /* if we find the SID, then decrement the count
+ and break out of the loop */
+
+ if ( sid_equal(sid, &sid_list[i]) ) {
+ *num -= 1;
+ break;
+ }
+ }
+
+ /* This loop will copy the remainder of the array
+ if i < num of sids ni the array */
+
+ for ( ; i<*num; i++ )
+ sid_copy( &sid_list[i], &sid_list[i+1] );
+
+ return;
+}
+
+bool add_rid_to_array_unique(TALLOC_CTX *mem_ctx,
+ uint32 rid, uint32 **pp_rids, size_t *p_num)
+{
+ size_t i;
+
+ for (i=0; i<*p_num; i++) {
+ if ((*pp_rids)[i] == rid)
+ return True;
+ }
+
+ *pp_rids = TALLOC_REALLOC_ARRAY(mem_ctx, *pp_rids, uint32, *p_num+1);
+
+ if (*pp_rids == NULL) {
+ *p_num = 0;
+ return False;
+ }
+
+ (*pp_rids)[*p_num] = rid;
+ *p_num += 1;
+ return True;
+}
+
+bool is_null_sid(const DOM_SID *sid)
+{
+ static const DOM_SID null_sid = {0};
+ return sid_equal(sid, &null_sid);
+}
+
+NTSTATUS sid_array_from_info3(TALLOC_CTX *mem_ctx,
+ const struct netr_SamInfo3 *info3,
+ DOM_SID **user_sids,
+ size_t *num_user_sids,
+ bool include_user_group_rid,
+ bool skip_ressource_groups)
+{
+ NTSTATUS status;
+ DOM_SID sid;
+ DOM_SID *sid_array = NULL;
+ size_t num_sids = 0;
+ int i;
+
+ if (include_user_group_rid) {
+ if (!sid_compose(&sid, info3->base.domain_sid, info3->base.rid)) {
+ DEBUG(3, ("could not compose user SID from rid 0x%x\n",
+ info3->base.rid));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ status = add_sid_to_array(mem_ctx, &sid, &sid_array, &num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("could not append user SID from rid 0x%x\n",
+ info3->base.rid));
+ return status;
+ }
+ }
+
+ if (!sid_compose(&sid, info3->base.domain_sid, info3->base.primary_gid)) {
+ DEBUG(3, ("could not compose group SID from rid 0x%x\n",
+ info3->base.primary_gid));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ status = add_sid_to_array(mem_ctx, &sid, &sid_array, &num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("could not append group SID from rid 0x%x\n",
+ info3->base.rid));
+ return status;
+ }
+
+ for (i = 0; i < info3->base.groups.count; i++) {
+ /* Don't add the primary group sid twice. */
+ if (info3->base.primary_gid == info3->base.groups.rids[i].rid) {
+ continue;
+ }
+ if (!sid_compose(&sid, info3->base.domain_sid,
+ info3->base.groups.rids[i].rid)) {
+ DEBUG(3, ("could not compose SID from additional group "
+ "rid 0x%x\n", info3->base.groups.rids[i].rid));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ status = add_sid_to_array(mem_ctx, &sid, &sid_array, &num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("could not append SID from additional group "
+ "rid 0x%x\n", info3->base.groups.rids[i].rid));
+ return status;
+ }
+ }
+
+ /* Copy 'other' sids. We need to do sid filtering here to
+ prevent possible elevation of privileges. See:
+
+ http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
+ */
+
+ for (i = 0; i < info3->sidcount; i++) {
+
+ if (skip_ressource_groups &&
+ (info3->sids[i].attributes & SE_GROUP_RESOURCE)) {
+ continue;
+ }
+
+ status = add_sid_to_array(mem_ctx, info3->sids[i].sid,
+ &sid_array, &num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("could not add SID to array: %s\n",
+ sid_string_dbg(info3->sids[i].sid)));
+ return status;
+ }
+ }
+
+ *user_sids = sid_array;
+ *num_user_sids = num_sids;
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c
new file mode 100644
index 0000000000..e20768ed89
--- /dev/null
+++ b/source3/lib/util_sock.c
@@ -0,0 +1,2104 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Tim Potter 2000-2001
+ Copyright (C) Jeremy Allison 1992-2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Return true if a string could be an IPv4 address.
+****************************************************************************/
+
+bool is_ipaddress_v4(const char *str)
+{
+ int ret = -1;
+ struct in_addr dest;
+
+ ret = inet_pton(AF_INET, str, &dest);
+ if (ret > 0) {
+ return true;
+ }
+ return false;
+}
+
+/****************************************************************************
+ Return true if a string could be an IPv4 or IPv6 address.
+****************************************************************************/
+
+bool is_ipaddress(const char *str)
+{
+#if defined(HAVE_IPV6)
+ int ret = -1;
+
+ if (strchr_m(str, ':')) {
+ char addr[INET6_ADDRSTRLEN];
+ struct in6_addr dest6;
+ const char *sp = str;
+ char *p = strchr_m(str, '%');
+
+ /*
+ * Cope with link-local.
+ * This is IP:v6:addr%ifname.
+ */
+
+ if (p && (p > str) && (if_nametoindex(p+1) != 0)) {
+ strlcpy(addr, str,
+ MIN(PTR_DIFF(p,str)+1,
+ sizeof(addr)));
+ sp = addr;
+ }
+ ret = inet_pton(AF_INET6, sp, &dest6);
+ if (ret > 0) {
+ return true;
+ }
+ }
+#endif
+ return is_ipaddress_v4(str);
+}
+
+/****************************************************************************
+ Is a sockaddr_storage a broadcast address ?
+****************************************************************************/
+
+bool is_broadcast_addr(const struct sockaddr_storage *pss)
+{
+#if defined(HAVE_IPV6)
+ if (pss->ss_family == AF_INET6) {
+ const struct in6_addr *sin6 =
+ &((const struct sockaddr_in6 *)pss)->sin6_addr;
+ return IN6_IS_ADDR_MULTICAST(sin6);
+ }
+#endif
+ if (pss->ss_family == AF_INET) {
+ uint32_t addr =
+ ntohl(((const struct sockaddr_in *)pss)->sin_addr.s_addr);
+ return addr == INADDR_BROADCAST;
+ }
+ return false;
+}
+
+/*******************************************************************
+ Wrap getaddrinfo...
+******************************************************************/
+
+static bool interpret_string_addr_internal(struct addrinfo **ppres,
+ const char *str, int flags)
+{
+ int ret;
+ struct addrinfo hints;
+
+ memset(&hints, '\0', sizeof(hints));
+ /* By default make sure it supports TCP. */
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = flags;
+
+ /* Linux man page on getaddinfo() says port will be
+ uninitialized when service string in NULL */
+
+ ret = getaddrinfo(str, NULL,
+ &hints,
+ ppres);
+
+ if (ret) {
+ DEBUG(3,("interpret_string_addr_internal: getaddrinfo failed "
+ "for name %s [%s]\n",
+ str,
+ gai_strerror(ret) ));
+ return false;
+ }
+ return true;
+}
+
+/****************************************************************************
+ Interpret an internet address or name into an IP address in 4 byte form.
+ RETURNS IN NETWORK BYTE ORDER (big endian).
+****************************************************************************/
+
+uint32 interpret_addr(const char *str)
+{
+ uint32 ret;
+
+ /* If it's in the form of an IP address then
+ * get the lib to interpret it */
+ if (is_ipaddress_v4(str)) {
+ struct in_addr dest;
+
+ if (inet_pton(AF_INET, str, &dest) <= 0) {
+ /* Error - this shouldn't happen ! */
+ DEBUG(0,("interpret_addr: inet_pton failed "
+ "host %s\n",
+ str));
+ return 0;
+ }
+ ret = dest.s_addr; /* NETWORK BYTE ORDER ! */
+ } else {
+ /* Otherwise assume it's a network name of some sort and use
+ getadddrinfo. */
+ struct addrinfo *res = NULL;
+ struct addrinfo *res_list = NULL;
+ if (!interpret_string_addr_internal(&res_list,
+ str,
+ AI_ADDRCONFIG)) {
+ DEBUG(3,("interpret_addr: Unknown host. %s\n",str));
+ return 0;
+ }
+
+ /* Find the first IPv4 address. */
+ for (res = res_list; res; res = res->ai_next) {
+ if (res->ai_family != AF_INET) {
+ continue;
+ }
+ if (res->ai_addr == NULL) {
+ continue;
+ }
+ break;
+ }
+ if(res == NULL) {
+ DEBUG(3,("interpret_addr: host address is "
+ "invalid for host %s\n",str));
+ if (res_list) {
+ freeaddrinfo(res_list);
+ }
+ return 0;
+ }
+ putip((char *)&ret,
+ &((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr);
+ if (res_list) {
+ freeaddrinfo(res_list);
+ }
+ }
+
+ /* This is so bogus - all callers need fixing... JRA. */
+ if (ret == (uint32)-1) {
+ return 0;
+ }
+
+ return ret;
+}
+
+/*******************************************************************
+ A convenient addition to interpret_addr().
+******************************************************************/
+
+struct in_addr *interpret_addr2(struct in_addr *ip, const char *str)
+{
+ uint32 a = interpret_addr(str);
+ ip->s_addr = a;
+ return ip;
+}
+
+/*******************************************************************
+ Map a text hostname or IP address (IPv4 or IPv6) into a
+ struct sockaddr_storage.
+******************************************************************/
+
+bool interpret_string_addr(struct sockaddr_storage *pss,
+ const char *str,
+ int flags)
+{
+ struct addrinfo *res = NULL;
+#if defined(HAVE_IPV6)
+ char addr[INET6_ADDRSTRLEN];
+ unsigned int scope_id = 0;
+
+ if (strchr_m(str, ':')) {
+ char *p = strchr_m(str, '%');
+
+ /*
+ * Cope with link-local.
+ * This is IP:v6:addr%ifname.
+ */
+
+ if (p && (p > str) && ((scope_id = if_nametoindex(p+1)) != 0)) {
+ strlcpy(addr, str,
+ MIN(PTR_DIFF(p,str)+1,
+ sizeof(addr)));
+ str = addr;
+ }
+ }
+#endif
+
+ zero_addr(pss);
+
+ if (!interpret_string_addr_internal(&res, str, flags|AI_ADDRCONFIG)) {
+ return false;
+ }
+ if (!res) {
+ return false;
+ }
+ /* Copy the first sockaddr. */
+ memcpy(pss, res->ai_addr, res->ai_addrlen);
+
+#if defined(HAVE_IPV6)
+ if (pss->ss_family == AF_INET6 && scope_id) {
+ struct sockaddr_in6 *ps6 = (struct sockaddr_in6 *)pss;
+ if (IN6_IS_ADDR_LINKLOCAL(&ps6->sin6_addr) &&
+ ps6->sin6_scope_id == 0) {
+ ps6->sin6_scope_id = scope_id;
+ }
+ }
+#endif
+
+ freeaddrinfo(res);
+ return true;
+}
+
+/*******************************************************************
+ Check if an IPv7 is 127.0.0.1
+******************************************************************/
+
+bool is_loopback_ip_v4(struct in_addr ip)
+{
+ struct in_addr a;
+ a.s_addr = htonl(INADDR_LOOPBACK);
+ return(ip.s_addr == a.s_addr);
+}
+
+/*******************************************************************
+ Check if a struct sockaddr_storage is the loopback address.
+******************************************************************/
+
+bool is_loopback_addr(const struct sockaddr_storage *pss)
+{
+#if defined(HAVE_IPV6)
+ if (pss->ss_family == AF_INET6) {
+ struct in6_addr *pin6 =
+ &((struct sockaddr_in6 *)pss)->sin6_addr;
+ return IN6_IS_ADDR_LOOPBACK(pin6);
+ }
+#endif
+ if (pss->ss_family == AF_INET) {
+ struct in_addr *pin = &((struct sockaddr_in *)pss)->sin_addr;
+ return is_loopback_ip_v4(*pin);
+ }
+ return false;
+}
+
+/*******************************************************************
+ Check if an IPv4 is 0.0.0.0.
+******************************************************************/
+
+bool is_zero_ip_v4(struct in_addr ip)
+{
+ uint32 a;
+ putip((char *)&a,(char *)&ip);
+ return(a == 0);
+}
+
+/*******************************************************************
+ Check if a struct sockaddr_storage has an unspecified address.
+******************************************************************/
+
+bool is_zero_addr(const struct sockaddr_storage *pss)
+{
+#if defined(HAVE_IPV6)
+ if (pss->ss_family == AF_INET6) {
+ struct in6_addr *pin6 =
+ &((struct sockaddr_in6 *)pss)->sin6_addr;
+ return IN6_IS_ADDR_UNSPECIFIED(pin6);
+ }
+#endif
+ if (pss->ss_family == AF_INET) {
+ struct in_addr *pin = &((struct sockaddr_in *)pss)->sin_addr;
+ return is_zero_ip_v4(*pin);
+ }
+ return false;
+}
+
+/*******************************************************************
+ Set an IP to 0.0.0.0.
+******************************************************************/
+
+void zero_ip_v4(struct in_addr *ip)
+{
+ memset(ip, '\0', sizeof(struct in_addr));
+}
+
+/*******************************************************************
+ Set an address to INADDR_ANY.
+******************************************************************/
+
+void zero_addr(struct sockaddr_storage *pss)
+{
+ memset(pss, '\0', sizeof(*pss));
+ /* Ensure we're at least a valid sockaddr-storage. */
+ pss->ss_family = AF_INET;
+}
+
+/*******************************************************************
+ Are two IPs on the same subnet - IPv4 version ?
+********************************************************************/
+
+bool same_net_v4(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));
+}
+
+/*******************************************************************
+ Convert an IPv4 struct in_addr to a struct sockaddr_storage.
+********************************************************************/
+
+void in_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
+ struct in_addr ip)
+{
+ struct sockaddr_in *sa = (struct sockaddr_in *)ss;
+ memset(ss, '\0', sizeof(*ss));
+ sa->sin_family = AF_INET;
+ sa->sin_addr = ip;
+}
+
+#if defined(HAVE_IPV6)
+/*******************************************************************
+ Convert an IPv6 struct in_addr to a struct sockaddr_storage.
+********************************************************************/
+
+ void in6_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
+ struct in6_addr ip)
+{
+ struct sockaddr_in6 *sa = (struct sockaddr_in6 *)ss;
+ memset(ss, '\0', sizeof(*ss));
+ sa->sin6_family = AF_INET6;
+ sa->sin6_addr = ip;
+}
+#endif
+
+/*******************************************************************
+ Are two IPs on the same subnet?
+********************************************************************/
+
+bool same_net(const struct sockaddr_storage *ip1,
+ const struct sockaddr_storage *ip2,
+ const struct sockaddr_storage *mask)
+{
+ if (ip1->ss_family != ip2->ss_family) {
+ /* Never on the same net. */
+ return false;
+ }
+
+#if defined(HAVE_IPV6)
+ if (ip1->ss_family == AF_INET6) {
+ struct sockaddr_in6 ip1_6 = *(struct sockaddr_in6 *)ip1;
+ struct sockaddr_in6 ip2_6 = *(struct sockaddr_in6 *)ip2;
+ struct sockaddr_in6 mask_6 = *(struct sockaddr_in6 *)mask;
+ char *p1 = (char *)&ip1_6.sin6_addr;
+ char *p2 = (char *)&ip2_6.sin6_addr;
+ char *m = (char *)&mask_6.sin6_addr;
+ int i;
+
+ for (i = 0; i < sizeof(struct in6_addr); i++) {
+ *p1++ &= *m;
+ *p2++ &= *m;
+ m++;
+ }
+ return (memcmp(&ip1_6.sin6_addr,
+ &ip2_6.sin6_addr,
+ sizeof(struct in6_addr)) == 0);
+ }
+#endif
+ if (ip1->ss_family == AF_INET) {
+ return same_net_v4(((const struct sockaddr_in *)ip1)->sin_addr,
+ ((const struct sockaddr_in *)ip2)->sin_addr,
+ ((const struct sockaddr_in *)mask)->sin_addr);
+ }
+ return false;
+}
+
+/*******************************************************************
+ Are two sockaddr_storage's the same family and address ? Ignore port etc.
+********************************************************************/
+
+bool addr_equal(const struct sockaddr_storage *ip1,
+ const struct sockaddr_storage *ip2)
+{
+ if (ip1->ss_family != ip2->ss_family) {
+ /* Never the same. */
+ return false;
+ }
+
+#if defined(HAVE_IPV6)
+ if (ip1->ss_family == AF_INET6) {
+ return (memcmp(&((const struct sockaddr_in6 *)ip1)->sin6_addr,
+ &((const struct sockaddr_in6 *)ip2)->sin6_addr,
+ sizeof(struct in6_addr)) == 0);
+ }
+#endif
+ if (ip1->ss_family == AF_INET) {
+ return (memcmp(&((const struct sockaddr_in *)ip1)->sin_addr,
+ &((const struct sockaddr_in *)ip2)->sin_addr,
+ sizeof(struct in_addr)) == 0);
+ }
+ return false;
+}
+
+/****************************************************************************
+ Is an IP address the INADDR_ANY or in6addr_any value ?
+****************************************************************************/
+
+bool is_address_any(const struct sockaddr_storage *psa)
+{
+#if defined(HAVE_IPV6)
+ if (psa->ss_family == AF_INET6) {
+ struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)psa;
+ if (memcmp(&in6addr_any,
+ &si6->sin6_addr,
+ sizeof(in6addr_any)) == 0) {
+ return true;
+ }
+ return false;
+ }
+#endif
+ if (psa->ss_family == AF_INET) {
+ struct sockaddr_in *si = (struct sockaddr_in *)psa;
+ if (si->sin_addr.s_addr == INADDR_ANY) {
+ return true;
+ }
+ return false;
+ }
+ return false;
+}
+
+/****************************************************************************
+ Get a port number in host byte order from a sockaddr_storage.
+****************************************************************************/
+
+uint16_t get_sockaddr_port(const struct sockaddr_storage *pss)
+{
+ uint16_t port = 0;
+
+ if (pss->ss_family != AF_INET) {
+#if defined(HAVE_IPV6)
+ /* IPv6 */
+ const struct sockaddr_in6 *sa6 =
+ (const struct sockaddr_in6 *)pss;
+ port = ntohs(sa6->sin6_port);
+#endif
+ } else {
+ const struct sockaddr_in *sa =
+ (const struct sockaddr_in *)pss;
+ port = ntohs(sa->sin_port);
+ }
+ return port;
+}
+
+/****************************************************************************
+ Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
+****************************************************************************/
+
+static char *print_sockaddr_len(char *dest,
+ size_t destlen,
+ const struct sockaddr_storage *psa,
+ socklen_t psalen)
+{
+ if (destlen > 0) {
+ dest[0] = '\0';
+ }
+ (void)sys_getnameinfo((const struct sockaddr *)psa,
+ psalen,
+ dest, destlen,
+ NULL, 0,
+ NI_NUMERICHOST);
+ return dest;
+}
+
+/****************************************************************************
+ Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
+****************************************************************************/
+
+char *print_sockaddr(char *dest,
+ size_t destlen,
+ const struct sockaddr_storage *psa)
+{
+ return print_sockaddr_len(dest, destlen, psa,
+ sizeof(struct sockaddr_storage));
+}
+
+/****************************************************************************
+ Print out a canonical IPv4 or IPv6 address from a struct sockaddr_storage.
+****************************************************************************/
+
+char *print_canonical_sockaddr(TALLOC_CTX *ctx,
+ const struct sockaddr_storage *pss)
+{
+ char addr[INET6_ADDRSTRLEN];
+ char *dest = NULL;
+ int ret;
+
+ /* Linux getnameinfo() man pages says port is unitialized if
+ service name is NULL. */
+
+ ret = sys_getnameinfo((const struct sockaddr *)pss,
+ sizeof(struct sockaddr_storage),
+ addr, sizeof(addr),
+ NULL, 0,
+ NI_NUMERICHOST);
+ if (ret != 0) {
+ return NULL;
+ }
+
+ if (pss->ss_family != AF_INET) {
+#if defined(HAVE_IPV6)
+ dest = talloc_asprintf(ctx, "[%s]", addr);
+#else
+ return NULL;
+#endif
+ } else {
+ dest = talloc_asprintf(ctx, "%s", addr);
+ }
+
+ return dest;
+}
+
+/****************************************************************************
+ Return the string of an IP address (IPv4 or IPv6).
+****************************************************************************/
+
+static const char *get_socket_addr(int fd, char *addr_buf, size_t addr_len)
+{
+ struct sockaddr_storage sa;
+ socklen_t length = sizeof(sa);
+
+ /* Ok, returning a hard coded IPv4 address
+ * is bogus, but it's just as bogus as a
+ * zero IPv6 address. No good choice here.
+ */
+
+ strlcpy(addr_buf, "0.0.0.0", addr_len);
+
+ if (fd == -1) {
+ return addr_buf;
+ }
+
+ if (getsockname(fd, (struct sockaddr *)&sa, &length) < 0) {
+ DEBUG(0,("getsockname failed. Error was %s\n",
+ strerror(errno) ));
+ return addr_buf;
+ }
+
+ return print_sockaddr_len(addr_buf, addr_len, &sa, length);
+}
+
+#if 0
+/* Not currently used. JRA. */
+/****************************************************************************
+ Return the port number we've bound to on a socket.
+****************************************************************************/
+
+static int get_socket_port(int fd)
+{
+ struct sockaddr_storage sa;
+ socklen_t length = sizeof(sa);
+
+ if (fd == -1) {
+ return -1;
+ }
+
+ if (getsockname(fd, (struct sockaddr *)&sa, &length) < 0) {
+ DEBUG(0,("getpeername failed. Error was %s\n",
+ strerror(errno) ));
+ return -1;
+ }
+
+#if defined(HAVE_IPV6)
+ if (sa.ss_family == AF_INET6) {
+ return ntohs(((struct sockaddr_in6 *)&sa)->sin6_port);
+ }
+#endif
+ if (sa.ss_family == AF_INET) {
+ return ntohs(((struct sockaddr_in *)&sa)->sin_port);
+ }
+ return -1;
+}
+#endif
+
+void set_sockaddr_port(struct sockaddr_storage *psa, uint16 port)
+{
+#if defined(HAVE_IPV6)
+ if (psa->ss_family == AF_INET6) {
+ ((struct sockaddr_in6 *)psa)->sin6_port = htons(port);
+ }
+#endif
+ if (psa->ss_family == AF_INET) {
+ ((struct sockaddr_in *)psa)->sin_port = htons(port);
+ }
+}
+
+const char *client_name(int fd)
+{
+ return get_peer_name(fd,false);
+}
+
+const char *client_addr(int fd, char *addr, size_t addrlen)
+{
+ return get_peer_addr(fd,addr,addrlen);
+}
+
+const char *client_socket_addr(int fd, char *addr, size_t addr_len)
+{
+ return get_socket_addr(fd, addr, addr_len);
+}
+
+#if 0
+/* Not currently used. JRA. */
+int client_socket_port(int fd)
+{
+ return get_socket_port(fd);
+}
+#endif
+
+/****************************************************************************
+ Accessor functions to make thread-safe code easier later...
+****************************************************************************/
+
+void set_smb_read_error(enum smb_read_errors *pre,
+ enum smb_read_errors newerr)
+{
+ if (pre) {
+ *pre = newerr;
+ }
+}
+
+void cond_set_smb_read_error(enum smb_read_errors *pre,
+ enum smb_read_errors newerr)
+{
+ if (pre && *pre == SMB_READ_OK) {
+ *pre = newerr;
+ }
+}
+
+/****************************************************************************
+ Determine if a file descriptor is in fact a socket.
+****************************************************************************/
+
+bool is_a_socket(int fd)
+{
+ int v;
+ socklen_t l;
+ l = sizeof(int);
+ return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
+}
+
+enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
+
+typedef struct smb_socket_option {
+ const char *name;
+ int level;
+ int option;
+ int value;
+ int opttype;
+} smb_socket_option;
+
+static const smb_socket_option socket_options[] = {
+ {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
+ {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
+ {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
+#ifdef TCP_NODELAY
+ {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
+#endif
+#ifdef TCP_KEEPCNT
+ {"TCP_KEEPCNT", IPPROTO_TCP, TCP_KEEPCNT, 0, OPT_INT},
+#endif
+#ifdef TCP_KEEPIDLE
+ {"TCP_KEEPIDLE", IPPROTO_TCP, TCP_KEEPIDLE, 0, OPT_INT},
+#endif
+#ifdef TCP_KEEPINTVL
+ {"TCP_KEEPINTVL", IPPROTO_TCP, TCP_KEEPINTVL, 0, OPT_INT},
+#endif
+#ifdef IPTOS_LOWDELAY
+ {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
+#endif
+#ifdef IPTOS_THROUGHPUT
+ {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
+#endif
+#ifdef SO_REUSEPORT
+ {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
+#endif
+#ifdef SO_SNDBUF
+ {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
+#endif
+#ifdef SO_RCVBUF
+ {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
+#endif
+#ifdef SO_SNDLOWAT
+ {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
+#endif
+#ifdef SO_RCVLOWAT
+ {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
+#endif
+#ifdef SO_SNDTIMEO
+ {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
+#endif
+#ifdef SO_RCVTIMEO
+ {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
+#endif
+#ifdef TCP_FASTACK
+ {"TCP_FASTACK", IPPROTO_TCP, TCP_FASTACK, 0, OPT_INT},
+#endif
+ {NULL,0,0,0,0}};
+
+/****************************************************************************
+ Print socket options.
+****************************************************************************/
+
+static void print_socket_options(int s)
+{
+ int value;
+ socklen_t vlen = 4;
+ const smb_socket_option *p = &socket_options[0];
+
+ /* wrapped in if statement to prevent streams
+ * leak in SCO Openserver 5.0 */
+ /* reported on samba-technical --jerry */
+ if ( DEBUGLEVEL >= 5 ) {
+ for (; p->name != NULL; p++) {
+ if (getsockopt(s, p->level, p->option,
+ (void *)&value, &vlen) == -1) {
+ DEBUG(5,("Could not test socket option %s.\n",
+ p->name));
+ } else {
+ DEBUG(5,("socket option %s = %d\n",
+ p->name,value));
+ }
+ }
+ }
+ }
+
+/****************************************************************************
+ Set user socket options.
+****************************************************************************/
+
+void set_socket_options(int fd, const char *options)
+{
+ TALLOC_CTX *ctx = talloc_stackframe();
+ char *tok;
+
+ while (next_token_talloc(ctx, &options, &tok," \t,")) {
+ int ret=0,i;
+ int value = 1;
+ char *p;
+ bool got_value = false;
+
+ if ((p = strchr_m(tok,'='))) {
+ *p = 0;
+ value = atoi(p+1);
+ got_value = true;
+ }
+
+ for (i=0;socket_options[i].name;i++)
+ if (strequal(socket_options[i].name,tok))
+ break;
+
+ if (!socket_options[i].name) {
+ DEBUG(0,("Unknown socket option %s\n",tok));
+ continue;
+ }
+
+ switch (socket_options[i].opttype) {
+ case OPT_BOOL:
+ case OPT_INT:
+ ret = setsockopt(fd,socket_options[i].level,
+ socket_options[i].option,
+ (char *)&value,sizeof(int));
+ break;
+
+ case OPT_ON:
+ if (got_value)
+ DEBUG(0,("syntax error - %s "
+ "does not take a value\n",tok));
+
+ {
+ int on = socket_options[i].value;
+ ret = setsockopt(fd,socket_options[i].level,
+ socket_options[i].option,
+ (char *)&on,sizeof(int));
+ }
+ break;
+ }
+
+ if (ret != 0) {
+ /* be aware that some systems like Solaris return
+ * EINVAL to a setsockopt() call when the client
+ * sent a RST previously - no need to worry */
+ DEBUG(2,("Failed to set socket option %s (Error %s)\n",
+ tok, strerror(errno) ));
+ }
+ }
+
+ TALLOC_FREE(ctx);
+ print_socket_options(fd);
+}
+
+/****************************************************************************
+ Read from a socket.
+****************************************************************************/
+
+ssize_t read_udp_v4_socket(int fd,
+ char *buf,
+ size_t len,
+ struct sockaddr_storage *psa)
+{
+ ssize_t ret;
+ socklen_t socklen = sizeof(*psa);
+ struct sockaddr_in *si = (struct sockaddr_in *)psa;
+
+ memset((char *)psa,'\0',socklen);
+
+ ret = (ssize_t)sys_recvfrom(fd,buf,len,0,
+ (struct sockaddr *)psa,&socklen);
+ if (ret <= 0) {
+ /* Don't print a low debug error for a non-blocking socket. */
+ if (errno == EAGAIN) {
+ DEBUG(10,("read_udp_v4_socket: returned EAGAIN\n"));
+ } else {
+ DEBUG(2,("read_udp_v4_socket: failed. errno=%s\n",
+ strerror(errno)));
+ }
+ return 0;
+ }
+
+ if (psa->ss_family != AF_INET) {
+ DEBUG(2,("read_udp_v4_socket: invalid address family %d "
+ "(not IPv4)\n", (int)psa->ss_family));
+ return 0;
+ }
+
+ DEBUG(10,("read_udp_v4_socket: ip %s port %d read: %lu\n",
+ inet_ntoa(si->sin_addr),
+ si->sin_port,
+ (unsigned long)ret));
+
+ return ret;
+}
+
+/****************************************************************************
+ Read data from a socket with a timout in msec.
+ mincount = if timeout, minimum to read before returning
+ maxcount = number to be read.
+ time_out = timeout in milliseconds
+****************************************************************************/
+
+NTSTATUS read_socket_with_timeout(int fd, char *buf,
+ size_t mincnt, size_t maxcnt,
+ unsigned int time_out,
+ size_t *size_ret)
+{
+ fd_set fds;
+ int selrtn;
+ ssize_t readret;
+ size_t nread = 0;
+ struct timeval timeout;
+ char addr[INET6_ADDRSTRLEN];
+
+ /* just checking .... */
+ if (maxcnt <= 0)
+ return NT_STATUS_OK;
+
+ /* Blocking read */
+ if (time_out == 0) {
+ if (mincnt == 0) {
+ mincnt = maxcnt;
+ }
+
+ while (nread < mincnt) {
+ readret = sys_read(fd, buf + nread, maxcnt - nread);
+
+ if (readret == 0) {
+ DEBUG(5,("read_socket_with_timeout: "
+ "blocking read. EOF from client.\n"));
+ return NT_STATUS_END_OF_FILE;
+ }
+
+ if (readret == -1) {
+ if (fd == get_client_fd()) {
+ /* Try and give an error message
+ * saying what client failed. */
+ DEBUG(0,("read_socket_with_timeout: "
+ "client %s read error = %s.\n",
+ get_peer_addr(fd,addr,sizeof(addr)),
+ strerror(errno) ));
+ } else {
+ DEBUG(0,("read_socket_with_timeout: "
+ "read error = %s.\n",
+ strerror(errno) ));
+ }
+ return map_nt_error_from_unix(errno);
+ }
+ nread += readret;
+ }
+ goto done;
+ }
+
+ /* Most difficult - timeout read */
+ /* If this is ever called on a disk file and
+ mincnt is greater then the filesize then
+ system performance will suffer severely as
+ select always returns true on disk files */
+
+ /* Set initial timeout */
+ timeout.tv_sec = (time_t)(time_out / 1000);
+ timeout.tv_usec = (long)(1000 * (time_out % 1000));
+
+ for (nread=0; nread < mincnt; ) {
+ FD_ZERO(&fds);
+ FD_SET(fd,&fds);
+
+ selrtn = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout);
+
+ /* Check if error */
+ if (selrtn == -1) {
+ /* something is wrong. Maybe the socket is dead? */
+ if (fd == get_client_fd()) {
+ /* Try and give an error message saying
+ * what client failed. */
+ DEBUG(0,("read_socket_with_timeout: timeout "
+ "read for client %s. select error = %s.\n",
+ get_peer_addr(fd,addr,sizeof(addr)),
+ strerror(errno) ));
+ } else {
+ DEBUG(0,("read_socket_with_timeout: timeout "
+ "read. select error = %s.\n",
+ strerror(errno) ));
+ }
+ return map_nt_error_from_unix(errno);
+ }
+
+ /* Did we timeout ? */
+ if (selrtn == 0) {
+ DEBUG(10,("read_socket_with_timeout: timeout read. "
+ "select timed out.\n"));
+ return NT_STATUS_IO_TIMEOUT;
+ }
+
+ readret = sys_read(fd, buf+nread, maxcnt-nread);
+
+ if (readret == 0) {
+ /* we got EOF on the file descriptor */
+ DEBUG(5,("read_socket_with_timeout: timeout read. "
+ "EOF from client.\n"));
+ return NT_STATUS_END_OF_FILE;
+ }
+
+ if (readret == -1) {
+ /* the descriptor is probably dead */
+ if (fd == get_client_fd()) {
+ /* Try and give an error message
+ * saying what client failed. */
+ DEBUG(0,("read_socket_with_timeout: timeout "
+ "read to client %s. read error = %s.\n",
+ get_peer_addr(fd,addr,sizeof(addr)),
+ strerror(errno) ));
+ } else {
+ DEBUG(0,("read_socket_with_timeout: timeout "
+ "read. read error = %s.\n",
+ strerror(errno) ));
+ }
+ return map_nt_error_from_unix(errno);
+ }
+
+ nread += readret;
+ }
+
+ done:
+ /* Return the number we got */
+ if (size_ret) {
+ *size_ret = nread;
+ }
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Read data from the client, reading exactly N bytes.
+****************************************************************************/
+
+NTSTATUS read_data(int fd, char *buffer, size_t N)
+{
+ return read_socket_with_timeout(fd, buffer, N, N, 0, NULL);
+}
+
+/****************************************************************************
+ Write data to a fd.
+****************************************************************************/
+
+ssize_t write_data(int fd, const char *buffer, size_t N)
+{
+ size_t total=0;
+ ssize_t ret;
+ char addr[INET6_ADDRSTRLEN];
+
+ while (total < N) {
+ ret = sys_write(fd,buffer + total,N - total);
+
+ if (ret == -1) {
+ if (fd == get_client_fd()) {
+ /* Try and give an error message saying
+ * what client failed. */
+ DEBUG(0,("write_data: write failure in "
+ "writing to client %s. Error %s\n",
+ get_peer_addr(fd,addr,sizeof(addr)),
+ strerror(errno) ));
+ } else {
+ DEBUG(0,("write_data: write failure. "
+ "Error = %s\n", strerror(errno) ));
+ }
+ return -1;
+ }
+
+ if (ret == 0) {
+ return total;
+ }
+
+ total += ret;
+ }
+ return (ssize_t)total;
+}
+
+/****************************************************************************
+ Send a keepalive packet (rfc1002).
+****************************************************************************/
+
+bool send_keepalive(int client)
+{
+ unsigned char buf[4];
+
+ buf[0] = SMBkeepalive;
+ buf[1] = buf[2] = buf[3] = 0;
+
+ return(write_data(client,(char *)buf,4) == 4);
+}
+
+/****************************************************************************
+ Read 4 bytes of a smb packet and return the smb length of the packet.
+ Store the result in the buffer.
+ This version of the function will return a length of zero on receiving
+ a keepalive packet.
+ Timeout is in milliseconds.
+****************************************************************************/
+
+NTSTATUS read_smb_length_return_keepalive(int fd, char *inbuf,
+ unsigned int timeout,
+ size_t *len)
+{
+ int msg_type;
+ NTSTATUS status;
+
+ status = read_socket_with_timeout(fd, inbuf, 4, 4, timeout, NULL);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ *len = smb_len(inbuf);
+ msg_type = CVAL(inbuf,0);
+
+ if (msg_type == SMBkeepalive) {
+ DEBUG(5,("Got keepalive packet\n"));
+ }
+
+ DEBUG(10,("got smb length of %lu\n",(unsigned long)(*len)));
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ 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.
+****************************************************************************/
+
+NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
+ size_t *len)
+{
+ uint8_t msgtype = SMBkeepalive;
+
+ while (msgtype == SMBkeepalive) {
+ NTSTATUS status;
+
+ status = read_smb_length_return_keepalive(fd, inbuf, timeout,
+ len);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ msgtype = CVAL(inbuf, 0);
+ }
+
+ DEBUG(10,("read_smb_length: got smb length of %lu\n",
+ (unsigned long)len));
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Read an smb from a fd.
+ The timeout is in milliseconds.
+ This function will return on receipt of a session keepalive packet.
+ maxlen is the max number of bytes to return, not including the 4 byte
+ length. If zero it means buflen limit.
+ Doesn't check the MAC on signed packets.
+****************************************************************************/
+
+NTSTATUS receive_smb_raw(int fd, char *buffer, size_t buflen, unsigned int timeout,
+ size_t maxlen, size_t *p_len)
+{
+ size_t len;
+ NTSTATUS status;
+
+ status = read_smb_length_return_keepalive(fd,buffer,timeout,&len);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("receive_smb_raw: %s!\n", nt_errstr(status)));
+ return status;
+ }
+
+ if (len > buflen) {
+ DEBUG(0,("Invalid packet length! (%lu bytes).\n",
+ (unsigned long)len));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if(len > 0) {
+ if (maxlen) {
+ len = MIN(len,maxlen);
+ }
+
+ status = read_socket_with_timeout(
+ fd, buffer+4, len, len, timeout, &len);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* not all of samba3 properly checks for packet-termination
+ * of strings. This ensures that we don't run off into
+ * empty space. */
+ SSVAL(buffer+4,len, 0);
+ }
+
+ *p_len = len;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Open a socket of the specified type, port, and address for incoming data.
+****************************************************************************/
+
+int open_socket_in(int type,
+ uint16_t port,
+ int dlevel,
+ const struct sockaddr_storage *psock,
+ bool rebind)
+{
+ struct sockaddr_storage sock;
+ int res;
+ socklen_t slen = sizeof(struct sockaddr_in);
+
+ sock = *psock;
+
+#if defined(HAVE_IPV6)
+ if (sock.ss_family == AF_INET6) {
+ ((struct sockaddr_in6 *)&sock)->sin6_port = htons(port);
+ slen = sizeof(struct sockaddr_in6);
+ }
+#endif
+ if (sock.ss_family == AF_INET) {
+ ((struct sockaddr_in *)&sock)->sin_port = htons(port);
+ }
+
+ res = socket(sock.ss_family, type, 0 );
+ if( res == -1 ) {
+ if( DEBUGLVL(0) ) {
+ dbgtext( "open_socket_in(): socket() call failed: " );
+ dbgtext( "%s\n", strerror( errno ) );
+ }
+ return -1;
+ }
+
+ /* This block sets/clears the SO_REUSEADDR and possibly SO_REUSEPORT. */
+ {
+ int val = rebind ? 1 : 0;
+ if( setsockopt(res,SOL_SOCKET,SO_REUSEADDR,
+ (char *)&val,sizeof(val)) == -1 ) {
+ if( DEBUGLVL( dlevel ) ) {
+ dbgtext( "open_socket_in(): setsockopt: " );
+ dbgtext( "SO_REUSEADDR = %s ",
+ val?"true":"false" );
+ dbgtext( "on port %d failed ", port );
+ dbgtext( "with error = %s\n", strerror(errno) );
+ }
+ }
+#ifdef SO_REUSEPORT
+ if( setsockopt(res,SOL_SOCKET,SO_REUSEPORT,
+ (char *)&val,sizeof(val)) == -1 ) {
+ if( DEBUGLVL( dlevel ) ) {
+ dbgtext( "open_socket_in(): setsockopt: ");
+ dbgtext( "SO_REUSEPORT = %s ",
+ val?"true":"false");
+ dbgtext( "on port %d failed ", port);
+ dbgtext( "with error = %s\n", strerror(errno));
+ }
+ }
+#endif /* SO_REUSEPORT */
+ }
+
+ /* now we've got a socket - we need to bind it */
+ if (bind(res, (struct sockaddr *)&sock, slen) == -1 ) {
+ if( DEBUGLVL(dlevel) && (port == SMB_PORT1 ||
+ port == SMB_PORT2 || port == NMB_PORT) ) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr),
+ &sock);
+ dbgtext( "bind failed on port %d ", port);
+ dbgtext( "socket_addr = %s.\n", addr);
+ dbgtext( "Error = %s\n", strerror(errno));
+ }
+ close(res);
+ return -1;
+ }
+
+ DEBUG( 10, ( "bind succeeded on port %d\n", port ) );
+ return( res );
+ }
+
+/****************************************************************************
+ Create an outgoing socket. timeout is in milliseconds.
+**************************************************************************/
+
+int open_socket_out(int type,
+ const struct sockaddr_storage *pss,
+ uint16_t port,
+ int timeout)
+{
+ char addr[INET6_ADDRSTRLEN];
+ struct sockaddr_storage sock_out = *pss;
+ int res,ret;
+ int connect_loop = 10;
+ int increment = 10;
+
+ /* create a socket to write to */
+ res = socket(pss->ss_family, type, 0);
+ if (res == -1) {
+ DEBUG(0,("socket error (%s)\n", strerror(errno)));
+ return -1;
+ }
+
+ if (type != SOCK_STREAM) {
+ return res;
+ }
+
+#if defined(HAVE_IPV6)
+ if (pss->ss_family == AF_INET6) {
+ struct sockaddr_in6 *psa6 = (struct sockaddr_in6 *)&sock_out;
+ psa6->sin6_port = htons(port);
+ if (psa6->sin6_scope_id == 0 &&
+ IN6_IS_ADDR_LINKLOCAL(&psa6->sin6_addr)) {
+ setup_linklocal_scope_id(&sock_out);
+ }
+ }
+#endif
+ if (pss->ss_family == AF_INET) {
+ struct sockaddr_in *psa = (struct sockaddr_in *)&sock_out;
+ psa->sin_port = htons(port);
+ }
+
+ /* set it non-blocking */
+ set_blocking(res,false);
+
+ print_sockaddr(addr, sizeof(addr), &sock_out);
+ DEBUG(3,("Connecting to %s at port %u\n",
+ addr,
+ (unsigned int)port));
+
+ /* and connect it to the destination */
+ connect_again:
+
+ ret = sys_connect(res, (struct sockaddr *)&sock_out);
+
+ /* Some systems return EAGAIN when they mean EINPROGRESS */
+ if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+ errno == EAGAIN) && (connect_loop < timeout) ) {
+ smb_msleep(connect_loop);
+ timeout -= connect_loop;
+ connect_loop += increment;
+ if (increment < 250) {
+ /* After 8 rounds we end up at a max of 255 msec */
+ increment *= 1.5;
+ }
+ goto connect_again;
+ }
+
+ if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+ errno == EAGAIN)) {
+ DEBUG(1,("timeout connecting to %s:%u\n",
+ addr,
+ (unsigned int)port));
+ close(res);
+ return -1;
+ }
+
+#ifdef EISCONN
+ if (ret < 0 && errno == EISCONN) {
+ errno = 0;
+ ret = 0;
+ }
+#endif
+
+ if (ret < 0) {
+ DEBUG(2,("error connecting to %s:%d (%s)\n",
+ addr,
+ (unsigned int)port,
+ strerror(errno)));
+ close(res);
+ return -1;
+ }
+
+ /* set it blocking again */
+ set_blocking(res,true);
+
+ return res;
+}
+
+/*******************************************************************
+ Create an outgoing TCP socket to the first addr that connects.
+
+ This is for simultaneous connection attempts to port 445 and 139 of a host
+ or for simultatneous connection attempts to multiple DCs at once. We return
+ a socket fd of the first successful connection.
+
+ @param[in] addrs list of Internet addresses and ports to connect to
+ @param[in] num_addrs number of address/port pairs in the addrs list
+ @param[in] timeout time after which we stop waiting for a socket connection
+ to succeed, given in milliseconds
+ @param[out] fd_index the entry in addrs which we successfully connected to
+ @param[out] fd fd of the open and connected socket
+ @return true on a successful connection, false if all connection attempts
+ failed or we timed out
+*******************************************************************/
+
+bool open_any_socket_out(struct sockaddr_storage *addrs, int num_addrs,
+ int timeout, int *fd_index, int *fd)
+{
+ int i, resulting_index, res;
+ int *sockets;
+ bool good_connect;
+
+ fd_set r_fds, wr_fds;
+ struct timeval tv;
+ int maxfd;
+
+ int connect_loop = 10000; /* 10 milliseconds */
+
+ timeout *= 1000; /* convert to microseconds */
+
+ sockets = SMB_MALLOC_ARRAY(int, num_addrs);
+
+ if (sockets == NULL)
+ return false;
+
+ resulting_index = -1;
+
+ for (i=0; i<num_addrs; i++)
+ sockets[i] = -1;
+
+ for (i=0; i<num_addrs; i++) {
+ sockets[i] = socket(addrs[i].ss_family, SOCK_STREAM, 0);
+ if (sockets[i] < 0)
+ goto done;
+ set_blocking(sockets[i], false);
+ }
+
+ connect_again:
+ good_connect = false;
+
+ for (i=0; i<num_addrs; i++) {
+ const struct sockaddr * a =
+ (const struct sockaddr *)&(addrs[i]);
+
+ if (sockets[i] == -1)
+ continue;
+
+ if (sys_connect(sockets[i], a) == 0) {
+ /* Rather unlikely as we are non-blocking, but it
+ * might actually happen. */
+ resulting_index = i;
+ goto done;
+ }
+
+ if (errno == EINPROGRESS || errno == EALREADY ||
+#ifdef EISCONN
+ errno == EISCONN ||
+#endif
+ errno == EAGAIN || errno == EINTR) {
+ /* These are the error messages that something is
+ progressing. */
+ good_connect = true;
+ } else if (errno != 0) {
+ /* There was a direct error */
+ close(sockets[i]);
+ sockets[i] = -1;
+ }
+ }
+
+ if (!good_connect) {
+ /* All of the connect's resulted in real error conditions */
+ goto done;
+ }
+
+ /* Lets see if any of the connect attempts succeeded */
+
+ maxfd = 0;
+ FD_ZERO(&wr_fds);
+ FD_ZERO(&r_fds);
+
+ for (i=0; i<num_addrs; i++) {
+ if (sockets[i] == -1)
+ continue;
+ FD_SET(sockets[i], &wr_fds);
+ FD_SET(sockets[i], &r_fds);
+ if (sockets[i]>maxfd)
+ maxfd = sockets[i];
+ }
+
+ tv.tv_sec = 0;
+ tv.tv_usec = connect_loop;
+
+ res = sys_select_intr(maxfd+1, &r_fds, &wr_fds, NULL, &tv);
+
+ if (res < 0)
+ goto done;
+
+ if (res == 0)
+ goto next_round;
+
+ for (i=0; i<num_addrs; i++) {
+
+ if (sockets[i] == -1)
+ continue;
+
+ /* Stevens, Network Programming says that if there's a
+ * successful connect, the socket is only writable. Upon an
+ * error, it's both readable and writable. */
+
+ if (FD_ISSET(sockets[i], &r_fds) &&
+ FD_ISSET(sockets[i], &wr_fds)) {
+ /* readable and writable, so it's an error */
+ close(sockets[i]);
+ sockets[i] = -1;
+ continue;
+ }
+
+ if (!FD_ISSET(sockets[i], &r_fds) &&
+ FD_ISSET(sockets[i], &wr_fds)) {
+ /* Only writable, so it's connected */
+ resulting_index = i;
+ goto done;
+ }
+ }
+
+ next_round:
+
+ timeout -= connect_loop;
+ if (timeout <= 0)
+ goto done;
+ connect_loop *= 1.5;
+ if (connect_loop > timeout)
+ connect_loop = timeout;
+ goto connect_again;
+
+ done:
+ for (i=0; i<num_addrs; i++) {
+ if (i == resulting_index)
+ continue;
+ if (sockets[i] >= 0)
+ close(sockets[i]);
+ }
+
+ if (resulting_index >= 0) {
+ *fd_index = resulting_index;
+ *fd = sockets[*fd_index];
+ set_blocking(*fd, true);
+ }
+
+ free(sockets);
+
+ return (resulting_index >= 0);
+}
+/****************************************************************************
+ Open a connected UDP socket to host on port
+**************************************************************************/
+
+int open_udp_socket(const char *host, int port)
+{
+ int type = SOCK_DGRAM;
+ struct sockaddr_in sock_out;
+ int res;
+ struct in_addr addr;
+
+ (void)interpret_addr2(&addr, host);
+
+ res = socket(PF_INET, type, 0);
+ if (res == -1) {
+ return -1;
+ }
+
+ memset((char *)&sock_out,'\0',sizeof(sock_out));
+ putip((char *)&sock_out.sin_addr,(char *)&addr);
+ sock_out.sin_port = htons(port);
+ sock_out.sin_family = PF_INET;
+
+ if (sys_connect(res,(struct sockaddr *)&sock_out)) {
+ close(res);
+ return -1;
+ }
+
+ return res;
+}
+
+/*******************************************************************
+ Return the IP addr of the remote end of a socket as a string.
+ Optionally return the struct sockaddr_storage.
+ ******************************************************************/
+
+static const char *get_peer_addr_internal(int fd,
+ char *addr_buf,
+ size_t addr_buf_len,
+ struct sockaddr_storage *pss,
+ socklen_t *plength)
+{
+ struct sockaddr_storage ss;
+ socklen_t length = sizeof(ss);
+
+ strlcpy(addr_buf,"0.0.0.0",addr_buf_len);
+
+ if (fd == -1) {
+ return addr_buf;
+ }
+
+ if (pss == NULL) {
+ pss = &ss;
+ }
+ if (plength == NULL) {
+ plength = &length;
+ }
+
+ if (getpeername(fd, (struct sockaddr *)pss, plength) < 0) {
+ DEBUG(0,("getpeername failed. Error was %s\n",
+ strerror(errno) ));
+ return addr_buf;
+ }
+
+ print_sockaddr_len(addr_buf,
+ addr_buf_len,
+ pss,
+ *plength);
+ return addr_buf;
+}
+
+/*******************************************************************
+ Matchname - determine if host name matches IP address. Used to
+ confirm a hostname lookup to prevent spoof attacks.
+******************************************************************/
+
+static bool matchname(const char *remotehost,
+ const struct sockaddr_storage *pss,
+ socklen_t len)
+{
+ struct addrinfo *res = NULL;
+ struct addrinfo *ailist = NULL;
+ char addr_buf[INET6_ADDRSTRLEN];
+ bool ret = interpret_string_addr_internal(&ailist,
+ remotehost,
+ AI_ADDRCONFIG|AI_CANONNAME);
+
+ if (!ret || ailist == NULL) {
+ DEBUG(3,("matchname: getaddrinfo failed for "
+ "name %s [%s]\n",
+ remotehost,
+ gai_strerror(ret) ));
+ return false;
+ }
+
+ /*
+ * Make sure that getaddrinfo() returns the "correct" host name.
+ */
+
+ if (ailist->ai_canonname == NULL ||
+ (!strequal(remotehost, ailist->ai_canonname) &&
+ !strequal(remotehost, "localhost"))) {
+ DEBUG(0,("matchname: host name/name mismatch: %s != %s\n",
+ remotehost,
+ ailist->ai_canonname ?
+ ailist->ai_canonname : "(NULL)"));
+ freeaddrinfo(ailist);
+ return false;
+ }
+
+ /* Look up the host address in the address list we just got. */
+ for (res = ailist; res; res = res->ai_next) {
+ if (!res->ai_addr) {
+ continue;
+ }
+ if (addr_equal((const struct sockaddr_storage *)res->ai_addr,
+ pss)) {
+ freeaddrinfo(ailist);
+ 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,("matchname: host name/address mismatch: %s != %s\n",
+ print_sockaddr_len(addr_buf,
+ sizeof(addr_buf),
+ pss,
+ len),
+ ailist->ai_canonname ? ailist->ai_canonname : "(NULL)"));
+
+ if (ailist) {
+ freeaddrinfo(ailist);
+ }
+ return false;
+}
+
+/*******************************************************************
+ Deal with the singleton cache.
+******************************************************************/
+
+struct name_addr_pair {
+ struct sockaddr_storage ss;
+ const char *name;
+};
+
+/*******************************************************************
+ Lookup a name/addr pair. Returns memory allocated from memcache.
+******************************************************************/
+
+static bool lookup_nc(struct name_addr_pair *nc)
+{
+ DATA_BLOB tmp;
+
+ ZERO_STRUCTP(nc);
+
+ if (!memcache_lookup(
+ NULL, SINGLETON_CACHE,
+ data_blob_string_const("get_peer_name"),
+ &tmp)) {
+ return false;
+ }
+
+ memcpy(&nc->ss, tmp.data, sizeof(nc->ss));
+ nc->name = (const char *)tmp.data + sizeof(nc->ss);
+ return true;
+}
+
+/*******************************************************************
+ Save a name/addr pair.
+******************************************************************/
+
+static void store_nc(const struct name_addr_pair *nc)
+{
+ DATA_BLOB tmp;
+ size_t namelen = strlen(nc->name);
+
+ tmp = data_blob(NULL, sizeof(nc->ss) + namelen + 1);
+ if (!tmp.data) {
+ return;
+ }
+ memcpy(tmp.data, &nc->ss, sizeof(nc->ss));
+ memcpy(tmp.data+sizeof(nc->ss), nc->name, namelen+1);
+
+ memcache_add(NULL, SINGLETON_CACHE,
+ data_blob_string_const("get_peer_name"),
+ tmp);
+ data_blob_free(&tmp);
+}
+
+/*******************************************************************
+ Return the DNS name of the remote end of a socket.
+******************************************************************/
+
+const char *get_peer_name(int fd, bool force_lookup)
+{
+ struct name_addr_pair nc;
+ char addr_buf[INET6_ADDRSTRLEN];
+ struct sockaddr_storage ss;
+ socklen_t length = sizeof(ss);
+ const char *p;
+ int ret;
+ char name_buf[MAX_DNS_NAME_LENGTH];
+ char tmp_name[MAX_DNS_NAME_LENGTH];
+
+ /* reverse lookups can be *very* expensive, and in many
+ situations won't work because many networks don't link dhcp
+ with dns. To avoid the delay we avoid the lookup if
+ possible */
+ if (!lp_hostname_lookups() && (force_lookup == false)) {
+ length = sizeof(nc.ss);
+ nc.name = get_peer_addr_internal(fd, addr_buf, sizeof(addr_buf),
+ &nc.ss, &length);
+ store_nc(&nc);
+ lookup_nc(&nc);
+ return nc.name ? nc.name : "UNKNOWN";
+ }
+
+ lookup_nc(&nc);
+
+ memset(&ss, '\0', sizeof(ss));
+ p = get_peer_addr_internal(fd, addr_buf, sizeof(addr_buf), &ss, &length);
+
+ /* it might be the same as the last one - save some DNS work */
+ if (addr_equal(&ss, &nc.ss)) {
+ return nc.name ? nc.name : "UNKNOWN";
+ }
+
+ /* Not the same. We need to lookup. */
+ if (fd == -1) {
+ return "UNKNOWN";
+ }
+
+ /* Look up the remote host name. */
+ ret = sys_getnameinfo((struct sockaddr *)&ss,
+ length,
+ name_buf,
+ sizeof(name_buf),
+ NULL,
+ 0,
+ 0);
+
+ if (ret) {
+ DEBUG(1,("get_peer_name: getnameinfo failed "
+ "for %s with error %s\n",
+ p,
+ gai_strerror(ret)));
+ strlcpy(name_buf, p, sizeof(name_buf));
+ } else {
+ if (!matchname(name_buf, &ss, length)) {
+ DEBUG(0,("Matchname failed on %s %s\n",name_buf,p));
+ strlcpy(name_buf,"UNKNOWN",sizeof(name_buf));
+ }
+ }
+
+ /* can't pass the same source and dest strings in when you
+ use --enable-developer or the clobber_region() call will
+ get you */
+
+ strlcpy(tmp_name, name_buf, sizeof(tmp_name));
+ alpha_strcpy(name_buf, tmp_name, "_-.", sizeof(name_buf));
+ if (strstr(name_buf,"..")) {
+ strlcpy(name_buf, "UNKNOWN", sizeof(name_buf));
+ }
+
+ nc.name = name_buf;
+ nc.ss = ss;
+
+ store_nc(&nc);
+ lookup_nc(&nc);
+ return nc.name ? nc.name : "UNKNOWN";
+}
+
+/*******************************************************************
+ Return the IP addr of the remote end of a socket as a string.
+ ******************************************************************/
+
+const char *get_peer_addr(int fd, char *addr, size_t addr_len)
+{
+ return get_peer_addr_internal(fd, addr, addr_len, NULL, NULL);
+}
+
+/*******************************************************************
+ Create protected unix domain socket.
+
+ Some unixes cannot set permissions on a ux-dom-sock, so we
+ have to make sure that the directory contains the protection
+ permissions instead.
+ ******************************************************************/
+
+int create_pipe_sock(const char *socket_dir,
+ const char *socket_name,
+ mode_t dir_perms)
+{
+#ifdef HAVE_UNIXSOCKET
+ struct sockaddr_un sunaddr;
+ struct stat st;
+ int sock;
+ mode_t old_umask;
+ char *path = NULL;
+
+ old_umask = umask(0);
+
+ /* Create the socket directory or reuse the existing one */
+
+ if (lstat(socket_dir, &st) == -1) {
+ if (errno == ENOENT) {
+ /* Create directory */
+ if (mkdir(socket_dir, dir_perms) == -1) {
+ DEBUG(0, ("error creating socket directory "
+ "%s: %s\n", socket_dir,
+ strerror(errno)));
+ goto out_umask;
+ }
+ } else {
+ DEBUG(0, ("lstat failed on socket directory %s: %s\n",
+ socket_dir, strerror(errno)));
+ goto out_umask;
+ }
+ } else {
+ /* Check ownership and permission on existing directory */
+ if (!S_ISDIR(st.st_mode)) {
+ DEBUG(0, ("socket directory %s isn't a directory\n",
+ socket_dir));
+ goto out_umask;
+ }
+ if ((st.st_uid != sec_initial_uid()) ||
+ ((st.st_mode & 0777) != dir_perms)) {
+ DEBUG(0, ("invalid permissions on socket directory "
+ "%s\n", socket_dir));
+ goto out_umask;
+ }
+ }
+
+ /* Create the socket file */
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+
+ if (sock == -1) {
+ DEBUG(0, ("create_pipe_sock: socket error %s\n",
+ strerror(errno) ));
+ goto out_close;
+ }
+
+ if (asprintf(&path, "%s/%s", socket_dir, socket_name) == -1) {
+ goto out_close;
+ }
+
+ unlink(path);
+ memset(&sunaddr, 0, sizeof(sunaddr));
+ sunaddr.sun_family = AF_UNIX;
+ strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path));
+
+ if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
+ DEBUG(0, ("bind failed on pipe socket %s: %s\n", path,
+ strerror(errno)));
+ goto out_close;
+ }
+
+ if (listen(sock, 5) == -1) {
+ DEBUG(0, ("listen failed on pipe socket %s: %s\n", path,
+ strerror(errno)));
+ goto out_close;
+ }
+
+ SAFE_FREE(path);
+
+ umask(old_umask);
+ return sock;
+
+out_close:
+ SAFE_FREE(path);
+ if (sock != -1)
+ close(sock);
+
+out_umask:
+ umask(old_umask);
+ return -1;
+
+#else
+ DEBUG(0, ("create_pipe_sock: No Unix sockets on this system\n"));
+ return -1;
+#endif /* HAVE_UNIXSOCKET */
+}
+
+/****************************************************************************
+ Get my own canonical name, including domain.
+****************************************************************************/
+
+const char *get_mydnsfullname(void)
+{
+ struct addrinfo *res = NULL;
+ char my_hostname[HOST_NAME_MAX];
+ bool ret;
+ DATA_BLOB tmp;
+
+ if (memcache_lookup(NULL, SINGLETON_CACHE,
+ data_blob_string_const("get_mydnsfullname"),
+ &tmp)) {
+ SMB_ASSERT(tmp.length > 0);
+ return (const char *)tmp.data;
+ }
+
+ /* get my host name */
+ if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
+ DEBUG(0,("get_mydnsfullname: gethostname failed\n"));
+ return NULL;
+ }
+
+ /* Ensure null termination. */
+ my_hostname[sizeof(my_hostname)-1] = '\0';
+
+ ret = interpret_string_addr_internal(&res,
+ my_hostname,
+ AI_ADDRCONFIG|AI_CANONNAME);
+
+ if (!ret || res == NULL) {
+ DEBUG(3,("get_mydnsfullname: getaddrinfo failed for "
+ "name %s [%s]\n",
+ my_hostname,
+ gai_strerror(ret) ));
+ return NULL;
+ }
+
+ /*
+ * Make sure that getaddrinfo() returns the "correct" host name.
+ */
+
+ if (res->ai_canonname == NULL) {
+ DEBUG(3,("get_mydnsfullname: failed to get "
+ "canonical name for %s\n",
+ my_hostname));
+ freeaddrinfo(res);
+ return NULL;
+ }
+
+ /* This copies the data, so we must do a lookup
+ * afterwards to find the value to return.
+ */
+
+ memcache_add(NULL, SINGLETON_CACHE,
+ data_blob_string_const("get_mydnsfullname"),
+ data_blob_string_const(res->ai_canonname));
+
+ if (!memcache_lookup(NULL, SINGLETON_CACHE,
+ data_blob_string_const("get_mydnsfullname"),
+ &tmp)) {
+ tmp = data_blob_talloc(talloc_tos(), res->ai_canonname,
+ strlen(res->ai_canonname) + 1);
+ }
+
+ freeaddrinfo(res);
+
+ return (const char *)tmp.data;
+}
+
+/************************************************************
+ Is this my name ?
+************************************************************/
+
+bool is_myname_or_ipaddr(const char *s)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *name = NULL;
+ const char *dnsname;
+ char *servername = NULL;
+
+ if (!s) {
+ return false;
+ }
+
+ /* Santize the string from '\\name' */
+ name = talloc_strdup(ctx, s);
+ if (!name) {
+ return false;
+ }
+
+ servername = strrchr_m(name, '\\' );
+ if (!servername) {
+ servername = name;
+ } else {
+ servername++;
+ }
+
+ /* Optimize for the common case */
+ if (strequal(servername, global_myname())) {
+ return true;
+ }
+
+ /* Check for an alias */
+ if (is_myname(servername)) {
+ return true;
+ }
+
+ /* Check for loopback */
+ if (strequal(servername, "127.0.0.1") ||
+ strequal(servername, "::1")) {
+ return true;
+ }
+
+ if (strequal(servername, "localhost")) {
+ return true;
+ }
+
+ /* Maybe it's my dns name */
+ dnsname = get_mydnsfullname();
+ if (dnsname && strequal(servername, dnsname)) {
+ return true;
+ }
+
+ /* Handle possible CNAME records - convert to an IP addr. */
+ if (!is_ipaddress(servername)) {
+ /* Use DNS to resolve the name, but only the first address */
+ struct sockaddr_storage ss;
+ if (interpret_string_addr(&ss, servername,0)) {
+ print_sockaddr(name,
+ sizeof(name),
+ &ss);
+ servername = name;
+ }
+ }
+
+ /* Maybe its an IP address? */
+ if (is_ipaddress(servername)) {
+ struct sockaddr_storage ss;
+ struct iface_struct *nics;
+ int i, n;
+
+ if (!interpret_string_addr(&ss, servername, AI_NUMERICHOST)) {
+ return false;
+ }
+
+ if (is_zero_addr(&ss) || is_loopback_addr(&ss)) {
+ return false;
+ }
+
+ nics = TALLOC_ARRAY(ctx, struct iface_struct,
+ MAX_INTERFACES);
+ if (!nics) {
+ return false;
+ }
+ n = get_interfaces(nics, MAX_INTERFACES);
+ for (i=0; i<n; i++) {
+ if (addr_equal(&nics[i].ip, &ss)) {
+ TALLOC_FREE(nics);
+ return true;
+ }
+ }
+ TALLOC_FREE(nics);
+ }
+
+ /* No match */
+ return false;
+}
diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c
new file mode 100644
index 0000000000..9f952abf10
--- /dev/null
+++ b/source3/lib/util_str.c
@@ -0,0 +1,2897 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Simo Sorce 2001-2002
+ Copyright (C) Martin Pool 2003
+ Copyright (C) James Peach 2006
+ Copyright (C) Jeremy Allison 1992-2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+char toupper_ascii_fast_table[128] = {
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
+};
+
+/**
+ * @file
+ * @brief String utilities.
+ **/
+
+static bool next_token_internal_talloc(TALLOC_CTX *ctx,
+ const char **ptr,
+ char **pp_buff,
+ const char *sep,
+ bool ltrim)
+{
+ char *s;
+ char *saved_s;
+ char *pbuf;
+ bool quoted;
+ size_t len=1;
+
+ *pp_buff = NULL;
+ if (!ptr) {
+ return(false);
+ }
+
+ s = (char *)*ptr;
+
+ /* default to simple separators */
+ if (!sep) {
+ sep = " \t\n\r";
+ }
+
+ /* find the first non sep char, if left-trimming is requested */
+ if (ltrim) {
+ while (*s && strchr_m(sep,*s)) {
+ s++;
+ }
+ }
+
+ /* nothing left? */
+ if (!*s) {
+ return false;
+ }
+
+ /* When restarting we need to go from here. */
+ saved_s = s;
+
+ /* Work out the length needed. */
+ for (quoted = false; *s &&
+ (quoted || !strchr_m(sep,*s)); s++) {
+ if (*s == '\"') {
+ quoted = !quoted;
+ } else {
+ len++;
+ }
+ }
+
+ /* We started with len = 1 so we have space for the nul. */
+ *pp_buff = TALLOC_ARRAY(ctx, char, len);
+ if (!*pp_buff) {
+ return false;
+ }
+
+ /* copy over the token */
+ pbuf = *pp_buff;
+ s = saved_s;
+ for (quoted = false; *s &&
+ (quoted || !strchr_m(sep,*s)); s++) {
+ if ( *s == '\"' ) {
+ quoted = !quoted;
+ } else {
+ *pbuf++ = *s;
+ }
+ }
+
+ *ptr = (*s) ? s+1 : s;
+ *pbuf = 0;
+
+ return true;
+}
+
+#if 0
+/*
+ * Get the next token from a string, return false if none found. Handles
+ * double-quotes. This version trims leading separator characters before
+ * looking for a token.
+ */
+bool next_token(const char **ptr, char *buff, const char *sep, size_t bufsize)
+{
+ return next_token_internal(ptr, buff, sep, bufsize, true);
+}
+#endif
+
+bool next_token_talloc(TALLOC_CTX *ctx,
+ const char **ptr,
+ char **pp_buff,
+ const char *sep)
+{
+ return next_token_internal_talloc(ctx, ptr, pp_buff, sep, true);
+}
+
+/*
+ * Get the next token from a string, return false if none found. Handles
+ * double-quotes. This version does not trim leading separator characters
+ * before looking for a token.
+ */
+
+bool next_token_no_ltrim_talloc(TALLOC_CTX *ctx,
+ const char **ptr,
+ char **pp_buff,
+ const char *sep)
+{
+ return next_token_internal_talloc(ctx, ptr, pp_buff, sep, false);
+}
+
+/**
+ * Case insensitive string compararison.
+ *
+ * iconv does not directly give us a way to compare strings in
+ * arbitrary unix character sets -- all we can is convert and then
+ * compare. This is expensive.
+ *
+ * As an optimization, we do a first pass that considers only the
+ * prefix of the strings that is entirely 7-bit. Within this, we
+ * check whether they have the same value.
+ *
+ * Hopefully this will often give the answer without needing to copy.
+ * In particular it should speed comparisons to literal ascii strings
+ * or comparisons of strings that are "obviously" different.
+ *
+ * If we find a non-ascii character we fall back to converting via
+ * iconv.
+ *
+ * This should never be slower than convering the whole thing, and
+ * often faster.
+ *
+ * A different optimization would be to compare for bitwise equality
+ * in the binary encoding. (It would be possible thought hairy to do
+ * both simultaneously.) But in that case if they turn out to be
+ * different, we'd need to restart the whole thing.
+ *
+ * Even better is to implement strcasecmp for each encoding and use a
+ * function pointer.
+ **/
+int StrCaseCmp(const char *s, const char *t)
+{
+
+ const char *ps, *pt;
+ size_t size;
+ smb_ucs2_t *buffer_s, *buffer_t;
+ int ret;
+
+ for (ps = s, pt = t; ; ps++, pt++) {
+ char us, ut;
+
+ if (!*ps && !*pt)
+ return 0; /* both ended */
+ else if (!*ps)
+ return -1; /* s is a prefix */
+ else if (!*pt)
+ return +1; /* t is a prefix */
+ else if ((*ps & 0x80) || (*pt & 0x80))
+ /* not ascii anymore, do it the hard way
+ * from here on in */
+ break;
+
+ us = toupper_ascii_fast(*ps);
+ ut = toupper_ascii_fast(*pt);
+ if (us == ut)
+ continue;
+ else if (us < ut)
+ return -1;
+ else if (us > ut)
+ return +1;
+ }
+
+ if (!push_ucs2_allocate(&buffer_s, ps, &size)) {
+ return strcmp(ps, pt);
+ /* Not quite the right answer, but finding the right one
+ under this failure case is expensive, and it's pretty
+ close */
+ }
+
+ if (!push_ucs2_allocate(&buffer_t, pt, &size)) {
+ SAFE_FREE(buffer_s);
+ return strcmp(ps, pt);
+ /* Not quite the right answer, but finding the right one
+ under this failure case is expensive, and it's pretty
+ close */
+ }
+
+ ret = strcasecmp_w(buffer_s, buffer_t);
+ SAFE_FREE(buffer_s);
+ SAFE_FREE(buffer_t);
+ return ret;
+}
+
+
+/**
+ Case insensitive string compararison, length limited.
+**/
+int StrnCaseCmp(const char *s, const char *t, size_t len)
+{
+ size_t n = 0;
+ const char *ps, *pt;
+ size_t size;
+ smb_ucs2_t *buffer_s, *buffer_t;
+ int ret;
+
+ for (ps = s, pt = t; n < len ; ps++, pt++, n++) {
+ char us, ut;
+
+ if (!*ps && !*pt)
+ return 0; /* both ended */
+ else if (!*ps)
+ return -1; /* s is a prefix */
+ else if (!*pt)
+ return +1; /* t is a prefix */
+ else if ((*ps & 0x80) || (*pt & 0x80))
+ /* not ascii anymore, do it the
+ * hard way from here on in */
+ break;
+
+ us = toupper_ascii_fast(*ps);
+ ut = toupper_ascii_fast(*pt);
+ if (us == ut)
+ continue;
+ else if (us < ut)
+ return -1;
+ else if (us > ut)
+ return +1;
+ }
+
+ if (n == len) {
+ return 0;
+ }
+
+ if (!push_ucs2_allocate(&buffer_s, ps, &size)) {
+ return strncmp(ps, pt, len-n);
+ /* Not quite the right answer, but finding the right one
+ under this failure case is expensive,
+ and it's pretty close */
+ }
+
+ if (!push_ucs2_allocate(&buffer_t, pt, &size)) {
+ SAFE_FREE(buffer_s);
+ return strncmp(ps, pt, len-n);
+ /* Not quite the right answer, but finding the right one
+ under this failure case is expensive,
+ and it's pretty close */
+ }
+
+ ret = strncasecmp_w(buffer_s, buffer_t, len-n);
+ SAFE_FREE(buffer_s);
+ SAFE_FREE(buffer_t);
+ return ret;
+}
+
+/**
+ * Compare 2 strings.
+ *
+ * @note The comparison is case-insensitive.
+ **/
+bool strequal(const char *s1, const char *s2)
+{
+ if (s1 == s2)
+ return(true);
+ if (!s1 || !s2)
+ return(false);
+
+ return(StrCaseCmp(s1,s2)==0);
+}
+
+/**
+ * Compare 2 strings up to and including the nth char.
+ *
+ * @note The comparison is case-insensitive.
+ **/
+bool strnequal(const char *s1,const char *s2,size_t n)
+{
+ if (s1 == s2)
+ return(true);
+ if (!s1 || !s2 || !n)
+ return(false);
+
+ return(StrnCaseCmp(s1,s2,n)==0);
+}
+
+/**
+ Compare 2 strings (case sensitive).
+**/
+
+bool strcsequal(const char *s1,const char *s2)
+{
+ if (s1 == s2)
+ return(true);
+ if (!s1 || !s2)
+ return(false);
+
+ return(strcmp(s1,s2)==0);
+}
+
+/**
+Do a case-insensitive, whitespace-ignoring string compare.
+**/
+
+int strwicmp(const char *psz1, const char *psz2)
+{
+ /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
+ /* appropriate value. */
+ if (psz1 == psz2)
+ return (0);
+ else if (psz1 == NULL)
+ return (-1);
+ else if (psz2 == NULL)
+ return (1);
+
+ /* sync the strings on first non-whitespace */
+ while (1) {
+ while (isspace((int)*psz1))
+ psz1++;
+ while (isspace((int)*psz2))
+ psz2++;
+ if (toupper_ascii(*psz1) != toupper_ascii(*psz2) ||
+ *psz1 == '\0' || *psz2 == '\0')
+ break;
+ psz1++;
+ psz2++;
+ }
+ return (*psz1 - *psz2);
+}
+
+/**
+ Convert a string to "normal" form.
+**/
+
+void strnorm(char *s, int case_default)
+{
+ if (case_default == CASE_UPPER)
+ strupper_m(s);
+ else
+ strlower_m(s);
+}
+
+/**
+ Check if a string is in "normal" case.
+**/
+
+bool strisnormal(const char *s, int case_default)
+{
+ if (case_default == CASE_UPPER)
+ return(!strhaslower(s));
+
+ return(!strhasupper(s));
+}
+
+
+/**
+ String replace.
+ NOTE: oldc and newc must be 7 bit characters
+**/
+void string_replace( char *s, char oldc, char newc )
+{
+ char *p;
+
+ /* this is quite a common operation, so we want it to be
+ fast. We optimise for the ascii case, knowing that all our
+ supported multi-byte character sets are ascii-compatible
+ (ie. they match for the first 128 chars) */
+
+ for (p = s; *p; p++) {
+ if (*p & 0x80) /* mb string - slow path. */
+ break;
+ if (*p == oldc) {
+ *p = newc;
+ }
+ }
+
+ if (!*p)
+ return;
+
+ /* Slow (mb) path. */
+#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
+ /* With compose characters we must restart from the beginning. JRA. */
+ p = s;
+#endif
+
+ while (*p) {
+ size_t c_size;
+ next_codepoint(p, &c_size);
+
+ if (c_size == 1) {
+ if (*p == oldc) {
+ *p = newc;
+ }
+ }
+ p += c_size;
+ }
+}
+
+/**
+ * Skip past some strings in a buffer - old version - no checks.
+ * **/
+
+char *push_skip_string(char *buf)
+{
+ buf += strlen(buf) + 1;
+ return(buf);
+}
+
+/**
+ Skip past a string in a buffer. Buffer may not be
+ null terminated. end_ptr points to the first byte after
+ then end of the buffer.
+**/
+
+char *skip_string(const char *base, size_t len, char *buf)
+{
+ const char *end_ptr = base + len;
+
+ if (end_ptr < base || !base || !buf || buf >= end_ptr) {
+ return NULL;
+ }
+
+ /* Skip the string */
+ while (*buf) {
+ buf++;
+ if (buf >= end_ptr) {
+ return NULL;
+ }
+ }
+ /* Skip the '\0' */
+ buf++;
+ return buf;
+}
+
+/**
+ Count the number of characters in a string. Normally this will
+ be the same as the number of bytes in a string for single byte strings,
+ but will be different for multibyte.
+**/
+
+size_t str_charnum(const char *s)
+{
+ size_t ret, converted_size;
+ smb_ucs2_t *tmpbuf2 = NULL;
+ if (!push_ucs2_allocate(&tmpbuf2, s, &converted_size)) {
+ return 0;
+ }
+ ret = strlen_w(tmpbuf2);
+ SAFE_FREE(tmpbuf2);
+ return ret;
+}
+
+/**
+ Count the number of characters in a string. Normally this will
+ be the same as the number of bytes in a string for single byte strings,
+ but will be different for multibyte.
+**/
+
+size_t str_ascii_charnum(const char *s)
+{
+ size_t ret, converted_size;
+ char *tmpbuf2 = NULL;
+ if (!push_ascii_allocate(&tmpbuf2, s, &converted_size)) {
+ return 0;
+ }
+ ret = strlen(tmpbuf2);
+ SAFE_FREE(tmpbuf2);
+ return ret;
+}
+
+bool trim_char(char *s,char cfront,char cback)
+{
+ bool ret = false;
+ char *ep;
+ char *fp = s;
+
+ /* Ignore null or empty strings. */
+ if (!s || (s[0] == '\0'))
+ return false;
+
+ if (cfront) {
+ while (*fp && *fp == cfront)
+ fp++;
+ if (!*fp) {
+ /* We ate the string. */
+ s[0] = '\0';
+ return true;
+ }
+ if (fp != s)
+ ret = true;
+ }
+
+ ep = fp + strlen(fp) - 1;
+ if (cback) {
+ /* Attempt ascii only. Bail for mb strings. */
+ while ((ep >= fp) && (*ep == cback)) {
+ ret = true;
+ if ((ep > fp) && (((unsigned char)ep[-1]) & 0x80)) {
+ /* Could be mb... bail back to tim_string. */
+ char fs[2], bs[2];
+ if (cfront) {
+ fs[0] = cfront;
+ fs[1] = '\0';
+ }
+ bs[0] = cback;
+ bs[1] = '\0';
+ return trim_string(s, cfront ? fs : NULL, bs);
+ } else {
+ ep--;
+ }
+ }
+ if (ep < fp) {
+ /* We ate the string. */
+ s[0] = '\0';
+ return true;
+ }
+ }
+
+ ep[1] = '\0';
+ memmove(s, fp, ep-fp+2);
+ return ret;
+}
+
+/**
+ Trim the specified elements off the front and back of a string.
+**/
+
+bool trim_string(char *s,const char *front,const char *back)
+{
+ bool ret = false;
+ size_t front_len;
+ size_t back_len;
+ size_t len;
+
+ /* Ignore null or empty strings. */
+ if (!s || (s[0] == '\0'))
+ return false;
+
+ front_len = front? strlen(front) : 0;
+ back_len = back? strlen(back) : 0;
+
+ len = strlen(s);
+
+ if (front_len) {
+ while (len && strncmp(s, front, front_len)==0) {
+ /* Must use memmove here as src & dest can
+ * easily overlap. Found by valgrind. JRA. */
+ memmove(s, s+front_len, (len-front_len)+1);
+ len -= front_len;
+ ret=true;
+ }
+ }
+
+ if (back_len) {
+ while ((len >= back_len) &&
+ strncmp(s+len-back_len,back,back_len)==0) {
+ s[len-back_len]='\0';
+ len -= back_len;
+ ret=true;
+ }
+ }
+ return ret;
+}
+
+/**
+ Does a string have any uppercase chars in it?
+**/
+
+bool strhasupper(const char *s)
+{
+ smb_ucs2_t *tmp, *p;
+ bool ret;
+ size_t converted_size;
+
+ if (!push_ucs2_allocate(&tmp, s, &converted_size)) {
+ return false;
+ }
+
+ for(p = tmp; *p != 0; p++) {
+ if(isupper_w(*p)) {
+ break;
+ }
+ }
+
+ ret = (*p != 0);
+ SAFE_FREE(tmp);
+ return ret;
+}
+
+/**
+ Does a string have any lowercase chars in it?
+**/
+
+bool strhaslower(const char *s)
+{
+ smb_ucs2_t *tmp, *p;
+ bool ret;
+ size_t converted_size;
+
+ if (!push_ucs2_allocate(&tmp, s, &converted_size)) {
+ return false;
+ }
+
+ for(p = tmp; *p != 0; p++) {
+ if(islower_w(*p)) {
+ break;
+ }
+ }
+
+ ret = (*p != 0);
+ SAFE_FREE(tmp);
+ return ret;
+}
+
+/**
+ Find the number of 'c' chars in a string
+**/
+
+size_t count_chars(const char *s,char c)
+{
+ smb_ucs2_t *ptr;
+ int count;
+ smb_ucs2_t *alloc_tmpbuf = NULL;
+ size_t converted_size;
+
+ if (!push_ucs2_allocate(&alloc_tmpbuf, s, &converted_size)) {
+ return 0;
+ }
+
+ for(count=0,ptr=alloc_tmpbuf;*ptr;ptr++)
+ if(*ptr==UCS2_CHAR(c))
+ count++;
+
+ SAFE_FREE(alloc_tmpbuf);
+ return(count);
+}
+
+/**
+ Safe string copy into a known length string. maxlength does not
+ include the terminating zero.
+**/
+
+char *safe_strcpy_fn(const char *fn,
+ int line,
+ char *dest,
+ const char *src,
+ size_t maxlength)
+{
+ size_t len;
+
+ if (!dest) {
+ DEBUG(0,("ERROR: NULL dest in safe_strcpy, "
+ "called from [%s][%d]\n", fn, line));
+ return NULL;
+ }
+
+#ifdef DEVELOPER
+ clobber_region(fn,line,dest, maxlength+1);
+#endif
+
+ if (!src) {
+ *dest = 0;
+ return dest;
+ }
+
+ len = strnlen(src, maxlength+1);
+
+ if (len > maxlength) {
+ DEBUG(0,("ERROR: string overflow by "
+ "%lu (%lu - %lu) in safe_strcpy [%.50s]\n",
+ (unsigned long)(len-maxlength), (unsigned long)len,
+ (unsigned long)maxlength, src));
+ len = maxlength;
+ }
+
+ memmove(dest, src, len);
+ dest[len] = 0;
+ return dest;
+}
+
+/**
+ Safe string cat into a string. maxlength does not
+ include the terminating zero.
+**/
+char *safe_strcat_fn(const char *fn,
+ int line,
+ char *dest,
+ const char *src,
+ size_t maxlength)
+{
+ size_t src_len, dest_len;
+
+ if (!dest) {
+ DEBUG(0,("ERROR: NULL dest in safe_strcat, "
+ "called from [%s][%d]\n", fn, line));
+ return NULL;
+ }
+
+ if (!src)
+ return dest;
+
+ src_len = strnlen(src, maxlength + 1);
+ dest_len = strnlen(dest, maxlength + 1);
+
+#ifdef DEVELOPER
+ clobber_region(fn, line, dest + dest_len, maxlength + 1 - dest_len);
+#endif
+
+ if (src_len + dest_len > maxlength) {
+ DEBUG(0,("ERROR: string overflow by %d "
+ "in safe_strcat [%.50s]\n",
+ (int)(src_len + dest_len - maxlength), src));
+ if (maxlength > dest_len) {
+ memcpy(&dest[dest_len], src, maxlength - dest_len);
+ }
+ dest[maxlength] = 0;
+ return NULL;
+ }
+
+ memcpy(&dest[dest_len], src, src_len);
+ dest[dest_len + src_len] = 0;
+ return dest;
+}
+
+/**
+ Paranoid strcpy into a buffer of given length (includes terminating
+ zero. Strips out all but 'a-Z0-9' and the character in other_safe_chars
+ and replaces with '_'. Deliberately does *NOT* check for multibyte
+ characters. Don't change it !
+**/
+
+char *alpha_strcpy_fn(const char *fn,
+ int line,
+ char *dest,
+ const char *src,
+ const char *other_safe_chars,
+ size_t maxlength)
+{
+ size_t len, i;
+
+#ifdef DEVELOPER
+ clobber_region(fn, line, dest, maxlength);
+#endif
+
+ if (!dest) {
+ DEBUG(0,("ERROR: NULL dest in alpha_strcpy, "
+ "called from [%s][%d]\n", fn, line));
+ return NULL;
+ }
+
+ if (!src) {
+ *dest = 0;
+ return dest;
+ }
+
+ len = strlen(src);
+ if (len >= maxlength)
+ len = maxlength - 1;
+
+ if (!other_safe_chars)
+ other_safe_chars = "";
+
+ for(i = 0; i < len; i++) {
+ int val = (src[i] & 0xff);
+ if (isupper_ascii(val) || islower_ascii(val) ||
+ isdigit(val) || strchr_m(other_safe_chars, val))
+ dest[i] = src[i];
+ else
+ dest[i] = '_';
+ }
+
+ dest[i] = '\0';
+
+ return dest;
+}
+
+/**
+ Like strncpy but always null terminates. Make sure there is room!
+ The variable n should always be one less than the available size.
+**/
+char *StrnCpy_fn(const char *fn, int line,char *dest,const char *src,size_t n)
+{
+ char *d = dest;
+
+#ifdef DEVELOPER
+ clobber_region(fn, line, dest, n+1);
+#endif
+
+ if (!dest) {
+ DEBUG(0,("ERROR: NULL dest in StrnCpy, "
+ "called from [%s][%d]\n", fn, line));
+ return(NULL);
+ }
+
+ if (!src) {
+ *dest = 0;
+ return(dest);
+ }
+
+ while (n-- && (*d = *src)) {
+ d++;
+ src++;
+ }
+
+ *d = 0;
+ return(dest);
+}
+
+#if 0
+/**
+ Like strncpy but copies up to the character marker. always null terminates.
+ returns a pointer to the character marker in the source string (src).
+**/
+
+static char *strncpyn(char *dest, const char *src, size_t n, char c)
+{
+ char *p;
+ size_t str_len;
+
+#ifdef DEVELOPER
+ clobber_region(dest, n+1);
+#endif
+ p = strchr_m(src, c);
+ if (p == NULL) {
+ DEBUG(5, ("strncpyn: separator character (%c) not found\n", c));
+ return NULL;
+ }
+
+ str_len = PTR_DIFF(p, src);
+ strncpy(dest, src, MIN(n, str_len));
+ dest[str_len] = '\0';
+
+ return p;
+}
+#endif
+
+/**
+ Routine to get hex characters and turn them into a 16 byte array.
+ the array can be variable length, and any non-hex-numeric
+ characters are skipped. "0xnn" or "0Xnn" is specially catered
+ for.
+
+ valid examples: "0A5D15"; "0x15, 0x49, 0xa2"; "59\ta9\te3\n"
+
+**/
+
+size_t strhex_to_str(char *buf, size_t buf_len, const char *strhex, size_t strhex_len)
+{
+ size_t i;
+ size_t num_chars = 0;
+ unsigned char lonybble, hinybble;
+ const char *hexchars = "0123456789ABCDEF";
+ char *p1 = NULL, *p2 = NULL;
+
+ for (i = 0; i < strhex_len && strhex[i] != 0; i++) {
+ if (strnequal(hexchars, "0x", 2)) {
+ i++; /* skip two chars */
+ continue;
+ }
+
+ if (!(p1 = strchr_m(hexchars, toupper_ascii(strhex[i]))))
+ break;
+
+ i++; /* next hex digit */
+
+ if (!(p2 = strchr_m(hexchars, toupper_ascii(strhex[i]))))
+ break;
+
+ /* get the two nybbles */
+ hinybble = PTR_DIFF(p1, hexchars);
+ lonybble = PTR_DIFF(p2, hexchars);
+
+ if (num_chars >= buf_len) {
+ break;
+ }
+ buf[num_chars] = (hinybble << 4) | lonybble;
+ num_chars++;
+
+ p1 = NULL;
+ p2 = NULL;
+ }
+ return num_chars;
+}
+
+DATA_BLOB strhex_to_data_blob(TALLOC_CTX *mem_ctx, const char *strhex)
+{
+ DATA_BLOB ret_blob;
+
+ if (mem_ctx != NULL)
+ ret_blob = data_blob_talloc(mem_ctx, NULL, strlen(strhex)/2+1);
+ else
+ ret_blob = data_blob(NULL, strlen(strhex)/2+1);
+
+ ret_blob.length = strhex_to_str((char*)ret_blob.data,
+ ret_blob.length,
+ strhex,
+ strlen(strhex));
+
+ return ret_blob;
+}
+
+/**
+ * Routine to print a buffer as HEX digits, into an allocated string.
+ */
+
+char *hex_encode(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len)
+{
+ int i;
+ char *hex_buffer;
+
+ hex_buffer = TALLOC_ARRAY(mem_ctx, char, (len*2)+1);
+
+ for (i = 0; i < len; i++)
+ slprintf(&hex_buffer[i*2], 3, "%02X", buff_in[i]);
+
+ return hex_buffer;
+}
+
+/**
+ Check if a string is part of a list.
+**/
+
+bool in_list(const char *s, const char *list, bool casesensitive)
+{
+ char *tok = NULL;
+ bool ret = false;
+ TALLOC_CTX *frame;
+
+ if (!list) {
+ return false;
+ }
+
+ frame = talloc_stackframe();
+ while (next_token_talloc(frame, &list, &tok,LIST_SEP)) {
+ if (casesensitive) {
+ if (strcmp(tok,s) == 0) {
+ ret = true;
+ break;
+ }
+ } else {
+ if (StrCaseCmp(tok,s) == 0) {
+ ret = true;
+ break;
+ }
+ }
+ }
+ TALLOC_FREE(frame);
+ return ret;
+}
+
+/* this is used to prevent lots of mallocs of size 1 */
+static const char null_string[] = "";
+
+/**
+ Set a string value, allocing the space for the string
+**/
+
+static bool string_init(char **dest,const char *src)
+{
+ size_t l;
+
+ if (!src)
+ src = "";
+
+ l = strlen(src);
+
+ if (l == 0) {
+ *dest = CONST_DISCARD(char*, null_string);
+ } else {
+ (*dest) = SMB_STRDUP(src);
+ if ((*dest) == NULL) {
+ DEBUG(0,("Out of memory in string_init\n"));
+ return false;
+ }
+ }
+ return(true);
+}
+
+/**
+ Free a string value.
+**/
+
+void string_free(char **s)
+{
+ if (!s || !(*s))
+ return;
+ if (*s == null_string)
+ *s = NULL;
+ SAFE_FREE(*s);
+}
+
+/**
+ Set a string value, deallocating any existing space, and allocing the space
+ for the string
+**/
+
+bool string_set(char **dest,const char *src)
+{
+ string_free(dest);
+ return(string_init(dest,src));
+}
+
+/**
+ Substitute a string for a pattern in another string. Make sure there is
+ enough room!
+
+ This routine looks for pattern in s and replaces it with
+ insert. It may do multiple replacements or just one.
+
+ Any of " ; ' $ or ` in the insert string are replaced with _
+ if len==0 then the string cannot be extended. This is different from the old
+ use of len==0 which was for no length checks to be done.
+**/
+
+void string_sub2(char *s,const char *pattern, const char *insert, size_t len,
+ bool remove_unsafe_characters, bool replace_once,
+ bool allow_trailing_dollar)
+{
+ char *p;
+ ssize_t ls,lp,li, i;
+
+ if (!insert || !pattern || !*pattern || !s)
+ return;
+
+ ls = (ssize_t)strlen(s);
+ lp = (ssize_t)strlen(pattern);
+ li = (ssize_t)strlen(insert);
+
+ if (len == 0)
+ len = ls + 1; /* len is number of *bytes* */
+
+ while (lp <= ls && (p = strstr_m(s,pattern))) {
+ if (ls + (li-lp) >= len) {
+ DEBUG(0,("ERROR: string overflow by "
+ "%d in string_sub(%.50s, %d)\n",
+ (int)(ls + (li-lp) - len),
+ pattern, (int)len));
+ break;
+ }
+ if (li != lp) {
+ memmove(p+li,p+lp,strlen(p+lp)+1);
+ }
+ for (i=0;i<li;i++) {
+ switch (insert[i]) {
+ case '`':
+ case '"':
+ case '\'':
+ case ';':
+ case '$':
+ /* allow a trailing $
+ * (as in machine accounts) */
+ if (allow_trailing_dollar && (i == li - 1 )) {
+ p[i] = insert[i];
+ break;
+ }
+ case '%':
+ case '\r':
+ case '\n':
+ if ( remove_unsafe_characters ) {
+ p[i] = '_';
+ /* yes this break should be here
+ * since we want to fall throw if
+ * not replacing unsafe chars */
+ break;
+ }
+ default:
+ p[i] = insert[i];
+ }
+ }
+ s = p + li;
+ ls += (li-lp);
+
+ if (replace_once)
+ break;
+ }
+}
+
+void string_sub_once(char *s, const char *pattern,
+ const char *insert, size_t len)
+{
+ string_sub2( s, pattern, insert, len, true, true, false );
+}
+
+void string_sub(char *s,const char *pattern, const char *insert, size_t len)
+{
+ string_sub2( s, pattern, insert, len, true, false, false );
+}
+
+void fstring_sub(char *s,const char *pattern,const char *insert)
+{
+ string_sub(s, pattern, insert, sizeof(fstring));
+}
+
+/**
+ Similar to string_sub2, but it will accept only allocated strings
+ and may realloc them so pay attention at what you pass on no
+ pointers inside strings, no const may be passed
+ as string.
+**/
+
+char *realloc_string_sub2(char *string,
+ const char *pattern,
+ const char *insert,
+ bool remove_unsafe_characters,
+ bool allow_trailing_dollar)
+{
+ char *p, *in;
+ char *s;
+ ssize_t ls,lp,li,ld, i;
+
+ if (!insert || !pattern || !*pattern || !string || !*string)
+ return NULL;
+
+ s = string;
+
+ in = SMB_STRDUP(insert);
+ if (!in) {
+ DEBUG(0, ("realloc_string_sub: out of memory!\n"));
+ return NULL;
+ }
+ ls = (ssize_t)strlen(s);
+ lp = (ssize_t)strlen(pattern);
+ li = (ssize_t)strlen(insert);
+ ld = li - lp;
+ for (i=0;i<li;i++) {
+ switch (in[i]) {
+ case '`':
+ case '"':
+ case '\'':
+ case ';':
+ case '$':
+ /* allow a trailing $
+ * (as in machine accounts) */
+ if (allow_trailing_dollar && (i == li - 1 )) {
+ break;
+ }
+ case '%':
+ case '\r':
+ case '\n':
+ if ( remove_unsafe_characters ) {
+ in[i] = '_';
+ break;
+ }
+ default:
+ /* ok */
+ break;
+ }
+ }
+
+ while ((p = strstr_m(s,pattern))) {
+ if (ld > 0) {
+ int offset = PTR_DIFF(s,string);
+ string = (char *)SMB_REALLOC(string, ls + ld + 1);
+ if (!string) {
+ DEBUG(0, ("realloc_string_sub: "
+ "out of memory!\n"));
+ SAFE_FREE(in);
+ return NULL;
+ }
+ p = string + offset + (p - s);
+ }
+ if (li != lp) {
+ memmove(p+li,p+lp,strlen(p+lp)+1);
+ }
+ memcpy(p, in, li);
+ s = p + li;
+ ls += ld;
+ }
+ SAFE_FREE(in);
+ return string;
+}
+
+char *realloc_string_sub(char *string,
+ const char *pattern,
+ const char *insert)
+{
+ return realloc_string_sub2(string, pattern, insert, true, false);
+}
+
+/*
+ * Internal guts of talloc_string_sub and talloc_all_string_sub.
+ * talloc version of string_sub2.
+ */
+
+char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
+ const char *pattern,
+ const char *insert,
+ bool remove_unsafe_characters,
+ bool replace_once,
+ bool allow_trailing_dollar)
+{
+ char *p, *in;
+ char *s;
+ char *string;
+ ssize_t ls,lp,li,ld, i;
+
+ if (!insert || !pattern || !*pattern || !src) {
+ return NULL;
+ }
+
+ string = talloc_strdup(mem_ctx, src);
+ if (string == NULL) {
+ DEBUG(0, ("talloc_string_sub2: "
+ "talloc_strdup failed\n"));
+ return NULL;
+ }
+
+ s = string;
+
+ in = SMB_STRDUP(insert);
+ if (!in) {
+ DEBUG(0, ("talloc_string_sub2: ENOMEM\n"));
+ return NULL;
+ }
+ ls = (ssize_t)strlen(s);
+ lp = (ssize_t)strlen(pattern);
+ li = (ssize_t)strlen(insert);
+ ld = li - lp;
+
+ for (i=0;i<li;i++) {
+ switch (in[i]) {
+ case '`':
+ case '"':
+ case '\'':
+ case ';':
+ case '$':
+ /* allow a trailing $
+ * (as in machine accounts) */
+ if (allow_trailing_dollar && (i == li - 1 )) {
+ break;
+ }
+ case '%':
+ case '\r':
+ case '\n':
+ if (remove_unsafe_characters) {
+ in[i] = '_';
+ break;
+ }
+ default:
+ /* ok */
+ break;
+ }
+ }
+
+ while ((p = strstr_m(s,pattern))) {
+ if (ld > 0) {
+ int offset = PTR_DIFF(s,string);
+ string = (char *)TALLOC_REALLOC(mem_ctx, string,
+ ls + ld + 1);
+ if (!string) {
+ DEBUG(0, ("talloc_string_sub: out of "
+ "memory!\n"));
+ SAFE_FREE(in);
+ return NULL;
+ }
+ p = string + offset + (p - s);
+ }
+ if (li != lp) {
+ memmove(p+li,p+lp,strlen(p+lp)+1);
+ }
+ memcpy(p, in, li);
+ s = p + li;
+ ls += ld;
+
+ if (replace_once) {
+ break;
+ }
+ }
+ SAFE_FREE(in);
+ return string;
+}
+
+/* Same as string_sub, but returns a talloc'ed string */
+
+char *talloc_string_sub(TALLOC_CTX *mem_ctx,
+ const char *src,
+ const char *pattern,
+ const char *insert)
+{
+ return talloc_string_sub2(mem_ctx, src, pattern, insert,
+ true, false, false);
+}
+
+/**
+ Similar to string_sub() but allows for any character to be substituted.
+ Use with caution!
+ if len==0 then the string cannot be extended. This is different from the old
+ use of len==0 which was for no length checks to be done.
+**/
+
+void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
+{
+ char *p;
+ ssize_t ls,lp,li;
+
+ if (!insert || !pattern || !s)
+ return;
+
+ ls = (ssize_t)strlen(s);
+ lp = (ssize_t)strlen(pattern);
+ li = (ssize_t)strlen(insert);
+
+ if (!*pattern)
+ return;
+
+ if (len == 0)
+ len = ls + 1; /* len is number of *bytes* */
+
+ while (lp <= ls && (p = strstr_m(s,pattern))) {
+ if (ls + (li-lp) >= len) {
+ DEBUG(0,("ERROR: string overflow by "
+ "%d in all_string_sub(%.50s, %d)\n",
+ (int)(ls + (li-lp) - len),
+ pattern, (int)len));
+ break;
+ }
+ if (li != lp) {
+ memmove(p+li,p+lp,strlen(p+lp)+1);
+ }
+ memcpy(p, insert, li);
+ s = p + li;
+ ls += (li-lp);
+ }
+}
+
+char *talloc_all_string_sub(TALLOC_CTX *ctx,
+ const char *src,
+ const char *pattern,
+ const char *insert)
+{
+ return talloc_string_sub2(ctx, src, pattern, insert,
+ false, false, false);
+}
+
+/**
+ Write an octal as a string.
+**/
+
+char *octal_string(int i)
+{
+ char *result;
+ if (i == -1) {
+ result = talloc_strdup(talloc_tos(), "-1");
+ }
+ else {
+ result = talloc_asprintf(talloc_tos(), "0%o", i);
+ }
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+
+/**
+ Truncate a string at a specified length.
+**/
+
+char *string_truncate(char *s, unsigned int length)
+{
+ if (s && strlen(s) > length)
+ s[length] = 0;
+ return s;
+}
+
+/**
+ Strchr and strrchr_m are very hard to do on general multi-byte strings.
+ We convert via ucs2 for now.
+**/
+
+char *strchr_m(const char *src, char c)
+{
+ smb_ucs2_t *ws = NULL;
+ char *s2 = NULL;
+ smb_ucs2_t *p;
+ const char *s;
+ char *ret;
+ size_t converted_size;
+
+ /* characters below 0x3F are guaranteed to not appear in
+ non-initial position in multi-byte charsets */
+ if ((c & 0xC0) == 0) {
+ return strchr(src, c);
+ }
+
+ /* this is quite a common operation, so we want it to be
+ fast. We optimise for the ascii case, knowing that all our
+ supported multi-byte character sets are ascii-compatible
+ (ie. they match for the first 128 chars) */
+
+ for (s = src; *s && !(((unsigned char)s[0]) & 0x80); s++) {
+ if (*s == c)
+ return (char *)s;
+ }
+
+ if (!*s)
+ return NULL;
+
+#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
+ /* With compose characters we must restart from the beginning. JRA. */
+ s = src;
+#endif
+
+ if (!push_ucs2_allocate(&ws, s, &converted_size)) {
+ /* Wrong answer, but what can we do... */
+ return strchr(src, c);
+ }
+ p = strchr_w(ws, UCS2_CHAR(c));
+ if (!p) {
+ SAFE_FREE(ws);
+ return NULL;
+ }
+ *p = 0;
+ if (!pull_ucs2_allocate(&s2, ws, &converted_size)) {
+ SAFE_FREE(ws);
+ /* Wrong answer, but what can we do... */
+ return strchr(src, c);
+ }
+ ret = (char *)(s+strlen(s2));
+ SAFE_FREE(ws);
+ SAFE_FREE(s2);
+ return ret;
+}
+
+char *strrchr_m(const char *s, char c)
+{
+ /* characters below 0x3F are guaranteed to not appear in
+ non-initial position in multi-byte charsets */
+ if ((c & 0xC0) == 0) {
+ return strrchr(s, c);
+ }
+
+ /* this is quite a common operation, so we want it to be
+ fast. We optimise for the ascii case, knowing that all our
+ supported multi-byte character sets are ascii-compatible
+ (ie. they match for the first 128 chars). Also, in Samba
+ we only search for ascii characters in 'c' and that
+ in all mb character sets with a compound character
+ containing c, if 'c' is not a match at position
+ p, then p[-1] > 0x7f. JRA. */
+
+ {
+ size_t len = strlen(s);
+ const char *cp = s;
+ bool got_mb = false;
+
+ if (len == 0)
+ return NULL;
+ cp += (len - 1);
+ do {
+ if (c == *cp) {
+ /* Could be a match. Part of a multibyte ? */
+ if ((cp > s) &&
+ (((unsigned char)cp[-1]) & 0x80)) {
+ /* Yep - go slow :-( */
+ got_mb = true;
+ break;
+ }
+ /* No - we have a match ! */
+ return (char *)cp;
+ }
+ } while (cp-- != s);
+ if (!got_mb)
+ return NULL;
+ }
+
+ /* String contained a non-ascii char. Slow path. */
+ {
+ smb_ucs2_t *ws = NULL;
+ char *s2 = NULL;
+ smb_ucs2_t *p;
+ char *ret;
+ size_t converted_size;
+
+ if (!push_ucs2_allocate(&ws, s, &converted_size)) {
+ /* Wrong answer, but what can we do. */
+ return strrchr(s, c);
+ }
+ p = strrchr_w(ws, UCS2_CHAR(c));
+ if (!p) {
+ SAFE_FREE(ws);
+ return NULL;
+ }
+ *p = 0;
+ if (!pull_ucs2_allocate(&s2, ws, &converted_size)) {
+ SAFE_FREE(ws);
+ /* Wrong answer, but what can we do. */
+ return strrchr(s, c);
+ }
+ ret = (char *)(s+strlen(s2));
+ SAFE_FREE(ws);
+ SAFE_FREE(s2);
+ return ret;
+ }
+}
+
+/***********************************************************************
+ Return the equivalent of doing strrchr 'n' times - always going
+ backwards.
+***********************************************************************/
+
+char *strnrchr_m(const char *s, char c, unsigned int n)
+{
+ smb_ucs2_t *ws = NULL;
+ char *s2 = NULL;
+ smb_ucs2_t *p;
+ char *ret;
+ size_t converted_size;
+
+ if (!push_ucs2_allocate(&ws, s, &converted_size)) {
+ /* Too hard to try and get right. */
+ return NULL;
+ }
+ p = strnrchr_w(ws, UCS2_CHAR(c), n);
+ if (!p) {
+ SAFE_FREE(ws);
+ return NULL;
+ }
+ *p = 0;
+ if (!pull_ucs2_allocate(&s2, ws, &converted_size)) {
+ SAFE_FREE(ws);
+ /* Too hard to try and get right. */
+ return NULL;
+ }
+ ret = (char *)(s+strlen(s2));
+ SAFE_FREE(ws);
+ SAFE_FREE(s2);
+ return ret;
+}
+
+/***********************************************************************
+ strstr_m - We convert via ucs2 for now.
+***********************************************************************/
+
+char *strstr_m(const char *src, const char *findstr)
+{
+ smb_ucs2_t *p;
+ smb_ucs2_t *src_w, *find_w;
+ const char *s;
+ char *s2;
+ char *retp;
+
+ size_t converted_size, findstr_len = 0;
+
+ /* for correctness */
+ if (!findstr[0]) {
+ return (char*)src;
+ }
+
+ /* Samba does single character findstr calls a *lot*. */
+ if (findstr[1] == '\0')
+ return strchr_m(src, *findstr);
+
+ /* We optimise for the ascii case, knowing that all our
+ supported multi-byte character sets are ascii-compatible
+ (ie. they match for the first 128 chars) */
+
+ for (s = src; *s && !(((unsigned char)s[0]) & 0x80); s++) {
+ if (*s == *findstr) {
+ if (!findstr_len)
+ findstr_len = strlen(findstr);
+
+ if (strncmp(s, findstr, findstr_len) == 0) {
+ return (char *)s;
+ }
+ }
+ }
+
+ if (!*s)
+ return NULL;
+
+#if 1 /* def BROKEN_UNICODE_COMPOSE_CHARACTERS */
+ /* 'make check' fails unless we do this */
+
+ /* With compose characters we must restart from the beginning. JRA. */
+ s = src;
+#endif
+
+ if (!push_ucs2_allocate(&src_w, src, &converted_size)) {
+ DEBUG(0,("strstr_m: src malloc fail\n"));
+ return NULL;
+ }
+
+ if (!push_ucs2_allocate(&find_w, findstr, &converted_size)) {
+ SAFE_FREE(src_w);
+ DEBUG(0,("strstr_m: find malloc fail\n"));
+ return NULL;
+ }
+
+ p = strstr_w(src_w, find_w);
+
+ if (!p) {
+ SAFE_FREE(src_w);
+ SAFE_FREE(find_w);
+ return NULL;
+ }
+
+ *p = 0;
+ if (!pull_ucs2_allocate(&s2, src_w, &converted_size)) {
+ SAFE_FREE(src_w);
+ SAFE_FREE(find_w);
+ DEBUG(0,("strstr_m: dest malloc fail\n"));
+ return NULL;
+ }
+ retp = (char *)(s+strlen(s2));
+ SAFE_FREE(src_w);
+ SAFE_FREE(find_w);
+ SAFE_FREE(s2);
+ return retp;
+}
+
+/**
+ Convert a string to lower case.
+**/
+
+void strlower_m(char *s)
+{
+ size_t len;
+ int errno_save;
+
+ /* this is quite a common operation, so we want it to be
+ fast. We optimise for the ascii case, knowing that all our
+ supported multi-byte character sets are ascii-compatible
+ (ie. they match for the first 128 chars) */
+
+ while (*s && !(((unsigned char)s[0]) & 0x80)) {
+ *s = tolower_ascii((unsigned char)*s);
+ s++;
+ }
+
+ if (!*s)
+ return;
+
+ /* I assume that lowercased string takes the same number of bytes
+ * as source string even in UTF-8 encoding. (VIV) */
+ len = strlen(s) + 1;
+ errno_save = errno;
+ errno = 0;
+ unix_strlower(s,len,s,len);
+ /* Catch mb conversion errors that may not terminate. */
+ if (errno)
+ s[len-1] = '\0';
+ errno = errno_save;
+}
+
+/**
+ Convert a string to upper case.
+**/
+
+void strupper_m(char *s)
+{
+ size_t len;
+ int errno_save;
+
+ /* this is quite a common operation, so we want it to be
+ fast. We optimise for the ascii case, knowing that all our
+ supported multi-byte character sets are ascii-compatible
+ (ie. they match for the first 128 chars) */
+
+ while (*s && !(((unsigned char)s[0]) & 0x80)) {
+ *s = toupper_ascii_fast((unsigned char)*s);
+ s++;
+ }
+
+ if (!*s)
+ return;
+
+ /* I assume that lowercased string takes the same number of bytes
+ * as source string even in multibyte encoding. (VIV) */
+ len = strlen(s) + 1;
+ errno_save = errno;
+ errno = 0;
+ unix_strupper(s,len,s,len);
+ /* Catch mb conversion errors that may not terminate. */
+ if (errno)
+ s[len-1] = '\0';
+ errno = errno_save;
+}
+
+/**
+ Count the number of UCS2 characters in a string. Normally this will
+ be the same as the number of bytes in a string for single byte strings,
+ but will be different for multibyte.
+**/
+
+size_t strlen_m(const char *s)
+{
+ size_t count = 0;
+
+ if (!s) {
+ return 0;
+ }
+
+ while (*s && !(((uint8_t)*s) & 0x80)) {
+ s++;
+ count++;
+ }
+
+ if (!*s) {
+ return count;
+ }
+
+ while (*s) {
+ size_t c_size;
+ codepoint_t c = next_codepoint(s, &c_size);
+ if (c < 0x10000) {
+ /* Unicode char fits into 16 bits. */
+ count += 1;
+ } else {
+ /* Double-width unicode char - 32 bits. */
+ count += 2;
+ }
+ s += c_size;
+ }
+
+ return count;
+}
+
+/**
+ Count the number of UCS2 characters in a string including the null
+ terminator.
+**/
+
+size_t strlen_m_term(const char *s)
+{
+ if (!s) {
+ return 0;
+ }
+ return strlen_m(s) + 1;
+}
+
+/*
+ * Weird helper routine for the winreg pipe: If nothing is around, return 0,
+ * if a string is there, include the terminator.
+ */
+
+size_t strlen_m_term_null(const char *s)
+{
+ size_t len;
+ if (!s) {
+ return 0;
+ }
+ len = strlen_m(s);
+ if (len == 0) {
+ return 0;
+ }
+
+ return len+1;
+}
+/**
+ Return a RFC2254 binary string representation of a buffer.
+ Used in LDAP filters.
+ Caller must free.
+**/
+
+char *binary_string_rfc2254(char *buf, int len)
+{
+ char *s;
+ int i, j;
+ const char *hex = "0123456789ABCDEF";
+ s = (char *)SMB_MALLOC(len * 3 + 1);
+ if (!s)
+ return NULL;
+ for (j=i=0;i<len;i++) {
+ s[j] = '\\';
+ s[j+1] = hex[((unsigned char)buf[i]) >> 4];
+ s[j+2] = hex[((unsigned char)buf[i]) & 0xF];
+ j += 3;
+ }
+ s[j] = 0;
+ return s;
+}
+
+char *binary_string(char *buf, int len)
+{
+ char *s;
+ int i, j;
+ const char *hex = "0123456789ABCDEF";
+ s = (char *)SMB_MALLOC(len * 2 + 1);
+ if (!s)
+ return NULL;
+ for (j=i=0;i<len;i++) {
+ s[j] = hex[((unsigned char)buf[i]) >> 4];
+ s[j+1] = hex[((unsigned char)buf[i]) & 0xF];
+ j += 2;
+ }
+ s[j] = 0;
+ return s;
+}
+
+/**
+ Just a typesafety wrapper for snprintf into a fstring.
+**/
+
+int fstr_sprintf(fstring s, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(s, FSTRING_LEN, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+/**
+ List of Strings manipulation functions
+**/
+
+#define S_LIST_ABS 16 /* List Allocation Block Size */
+
+char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
+{
+ char **list;
+ const char *str;
+ char *s;
+ int num, lsize;
+ char *tok;
+
+ if (!string || !*string)
+ return NULL;
+
+ list = TALLOC_ARRAY(mem_ctx, char *, S_LIST_ABS+1);
+ if (list == NULL) {
+ return NULL;
+ }
+ lsize = S_LIST_ABS;
+
+ s = talloc_strdup(list, string);
+ if (s == NULL) {
+ DEBUG(0,("str_list_make: Unable to allocate memory"));
+ TALLOC_FREE(list);
+ return NULL;
+ }
+ if (!sep) sep = LIST_SEP;
+
+ num = 0;
+ str = s;
+
+ while (next_token_talloc(list, &str, &tok, sep)) {
+
+ if (num == lsize) {
+ char **tmp;
+
+ lsize += S_LIST_ABS;
+
+ tmp = TALLOC_REALLOC_ARRAY(mem_ctx, list, char *,
+ lsize + 1);
+ if (tmp == NULL) {
+ DEBUG(0,("str_list_make: "
+ "Unable to allocate memory"));
+ TALLOC_FREE(list);
+ return NULL;
+ }
+
+ list = tmp;
+
+ memset (&list[num], 0,
+ ((sizeof(char**)) * (S_LIST_ABS +1)));
+ }
+
+ list[num] = tok;
+ num += 1;
+ }
+
+ list[num] = NULL;
+
+ TALLOC_FREE(s);
+ return list;
+}
+
+bool str_list_copy(TALLOC_CTX *mem_ctx, char ***dest, const char **src)
+{
+ char **list;
+ int i, num;
+
+ *dest = NULL;
+ if (!src)
+ return false;
+
+ num = 0;
+ while (src[num] != NULL) {
+ num += 1;
+ }
+
+ list = TALLOC_ARRAY(mem_ctx, char *, num+1);
+ if (list == NULL) {
+ return false;
+ }
+
+ for (i=0; i<num; i++) {
+ list[i] = talloc_strdup(list, src[i]);
+ if (list[i] == NULL) {
+ TALLOC_FREE(list);
+ return false;
+ }
+ }
+ list[i] = NULL;
+ *dest = list;
+ return true;
+}
+
+/**
+ * Return true if all the elements of the list match exactly.
+ **/
+bool str_list_compare(char **list1, char **list2)
+{
+ int num;
+
+ if (!list1 || !list2)
+ return (list1 == list2);
+
+ for (num = 0; list1[num]; num++) {
+ if (!list2[num])
+ return false;
+ if (!strcsequal(list1[num], list2[num]))
+ return false;
+ }
+ if (list2[num])
+ return false; /* if list2 has more elements than list1 fail */
+
+ return true;
+}
+
+/******************************************************************************
+ *****************************************************************************/
+
+int str_list_count( const char **list )
+{
+ int i = 0;
+
+ if ( ! list )
+ return 0;
+
+ /* count the number of list members */
+
+ for ( i=0; *list; i++, list++ );
+
+ return i;
+}
+
+/******************************************************************************
+ version of standard_sub_basic() for string lists; uses talloc_sub_basic()
+ for the work
+ *****************************************************************************/
+
+bool str_list_sub_basic( char **list, const char *smb_name,
+ const char *domain_name )
+{
+ TALLOC_CTX *ctx = list;
+ char *s, *tmpstr;
+
+ while ( *list ) {
+ s = *list;
+ tmpstr = talloc_sub_basic(ctx, smb_name, domain_name, s);
+ if ( !tmpstr ) {
+ DEBUG(0,("str_list_sub_basic: "
+ "alloc_sub_basic() return NULL!\n"));
+ return false;
+ }
+
+ TALLOC_FREE(*list);
+ *list = tmpstr;
+
+ list++;
+ }
+
+ return true;
+}
+
+/******************************************************************************
+ substritute a specific pattern in a string list
+ *****************************************************************************/
+
+bool str_list_substitute(char **list, const char *pattern, const char *insert)
+{
+ TALLOC_CTX *ctx = list;
+ char *p, *s, *t;
+ ssize_t ls, lp, li, ld, i, d;
+
+ if (!list)
+ return false;
+ if (!pattern)
+ return false;
+ if (!insert)
+ return false;
+
+ lp = (ssize_t)strlen(pattern);
+ li = (ssize_t)strlen(insert);
+ ld = li -lp;
+
+ while (*list) {
+ s = *list;
+ ls = (ssize_t)strlen(s);
+
+ while ((p = strstr_m(s, pattern))) {
+ t = *list;
+ d = p -t;
+ if (ld) {
+ t = TALLOC_ARRAY(ctx, char, ls +ld +1);
+ if (!t) {
+ DEBUG(0,("str_list_substitute: "
+ "Unable to allocate memory"));
+ return false;
+ }
+ memcpy(t, *list, d);
+ memcpy(t +d +li, p +lp, ls -d -lp +1);
+ TALLOC_FREE(*list);
+ *list = t;
+ ls += ld;
+ s = t +d +li;
+ }
+
+ for (i = 0; i < li; i++) {
+ switch (insert[i]) {
+ case '`':
+ case '"':
+ case '\'':
+ case ';':
+ case '$':
+ case '%':
+ case '\r':
+ case '\n':
+ t[d +i] = '_';
+ break;
+ default:
+ t[d +i] = insert[i];
+ }
+ }
+ }
+
+ list++;
+ }
+
+ return true;
+}
+
+
+#define IPSTR_LIST_SEP ","
+#define IPSTR_LIST_CHAR ','
+
+/**
+ * Add ip string representation to ipstr list. Used also
+ * as part of @function ipstr_list_make
+ *
+ * @param ipstr_list pointer to string containing ip list;
+ * MUST BE already allocated and IS reallocated if necessary
+ * @param ipstr_size pointer to current size of ipstr_list (might be changed
+ * as a result of reallocation)
+ * @param ip IP address which is to be added to list
+ * @return pointer to string appended with new ip and possibly
+ * reallocated to new length
+ **/
+
+static char *ipstr_list_add(char **ipstr_list, const struct ip_service *service)
+{
+ char *new_ipstr = NULL;
+ char addr_buf[INET6_ADDRSTRLEN];
+ int ret;
+
+ /* arguments checking */
+ if (!ipstr_list || !service) {
+ return NULL;
+ }
+
+ print_sockaddr(addr_buf,
+ sizeof(addr_buf),
+ &service->ss);
+
+ /* attempt to convert ip to a string and append colon separator to it */
+ if (*ipstr_list) {
+ if (service->ss.ss_family == AF_INET) {
+ /* IPv4 */
+ ret = asprintf(&new_ipstr, "%s%s%s:%d", *ipstr_list,
+ IPSTR_LIST_SEP, addr_buf,
+ service->port);
+ } else {
+ /* IPv6 */
+ ret = asprintf(&new_ipstr, "%s%s[%s]:%d", *ipstr_list,
+ IPSTR_LIST_SEP, addr_buf,
+ service->port);
+ }
+ SAFE_FREE(*ipstr_list);
+ } else {
+ if (service->ss.ss_family == AF_INET) {
+ /* IPv4 */
+ ret = asprintf(&new_ipstr, "%s:%d", addr_buf,
+ service->port);
+ } else {
+ /* IPv6 */
+ ret = asprintf(&new_ipstr, "[%s]:%d", addr_buf,
+ service->port);
+ }
+ }
+ if (ret == -1) {
+ return NULL;
+ }
+ *ipstr_list = new_ipstr;
+ return *ipstr_list;
+}
+
+/**
+ * Allocate and initialise an ipstr list using ip adresses
+ * passed as arguments.
+ *
+ * @param ipstr_list pointer to string meant to be allocated and set
+ * @param ip_list array of ip addresses to place in the list
+ * @param ip_count number of addresses stored in ip_list
+ * @return pointer to allocated ip string
+ **/
+
+char *ipstr_list_make(char **ipstr_list,
+ const struct ip_service *ip_list,
+ int ip_count)
+{
+ int i;
+
+ /* arguments checking */
+ if (!ip_list || !ipstr_list) {
+ return 0;
+ }
+
+ *ipstr_list = NULL;
+
+ /* process ip addresses given as arguments */
+ for (i = 0; i < ip_count; i++) {
+ *ipstr_list = ipstr_list_add(ipstr_list, &ip_list[i]);
+ }
+
+ return (*ipstr_list);
+}
+
+
+/**
+ * Parse given ip string list into array of ip addresses
+ * (as ip_service structures)
+ * e.g. [IPv6]:port,192.168.1.100:389,192.168.1.78, ...
+ *
+ * @param ipstr ip string list to be parsed
+ * @param ip_list pointer to array of ip addresses which is
+ * allocated by this function and must be freed by caller
+ * @return number of successfully parsed addresses
+ **/
+
+int ipstr_list_parse(const char *ipstr_list, struct ip_service **ip_list)
+{
+ TALLOC_CTX *frame;
+ char *token_str = NULL;
+ size_t count;
+ int i;
+
+ if (!ipstr_list || !ip_list)
+ return 0;
+
+ count = count_chars(ipstr_list, IPSTR_LIST_CHAR) + 1;
+ if ( (*ip_list = SMB_MALLOC_ARRAY(struct ip_service, count)) == NULL ) {
+ DEBUG(0,("ipstr_list_parse: malloc failed for %lu entries\n",
+ (unsigned long)count));
+ return 0;
+ }
+
+ frame = talloc_stackframe();
+ for ( i=0; next_token_talloc(frame, &ipstr_list, &token_str,
+ IPSTR_LIST_SEP) && i<count; i++ ) {
+ char *s = token_str;
+ char *p = strrchr(token_str, ':');
+
+ if (p) {
+ *p = 0;
+ (*ip_list)[i].port = atoi(p+1);
+ }
+
+ /* convert single token to ip address */
+ if (token_str[0] == '[') {
+ /* IPv6 address. */
+ s++;
+ p = strchr(token_str, ']');
+ if (!p) {
+ continue;
+ }
+ *p = '\0';
+ }
+ if (!interpret_string_addr(&(*ip_list)[i].ss,
+ s,
+ AI_NUMERICHOST)) {
+ continue;
+ }
+ }
+ TALLOC_FREE(frame);
+ return count;
+}
+
+/**
+ * Safely free ip string list
+ *
+ * @param ipstr_list ip string list to be freed
+ **/
+
+void ipstr_list_free(char* ipstr_list)
+{
+ SAFE_FREE(ipstr_list);
+}
+
+/**
+ Unescape a URL encoded string, in place.
+**/
+
+void rfc1738_unescape(char *buf)
+{
+ char *p=buf;
+
+ while (p && *p && (p=strchr_m(p,'%'))) {
+ int c1 = p[1];
+ int c2 = p[2];
+
+ if (c1 >= '0' && c1 <= '9')
+ c1 = c1 - '0';
+ else if (c1 >= 'A' && c1 <= 'F')
+ c1 = 10 + c1 - 'A';
+ else if (c1 >= 'a' && c1 <= 'f')
+ c1 = 10 + c1 - 'a';
+ else {p++; continue;}
+
+ if (c2 >= '0' && c2 <= '9')
+ c2 = c2 - '0';
+ else if (c2 >= 'A' && c2 <= 'F')
+ c2 = 10 + c2 - 'A';
+ else if (c2 >= 'a' && c2 <= 'f')
+ c2 = 10 + c2 - 'a';
+ else {p++; continue;}
+
+ *p = (c1<<4) | c2;
+
+ memmove(p+1, p+3, strlen(p+3)+1);
+ p++;
+ }
+}
+
+static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * Decode a base64 string into a DATA_BLOB - simple and slow algorithm
+ **/
+DATA_BLOB base64_decode_data_blob(const char *s)
+{
+ int bit_offset, byte_offset, idx, i, n;
+ DATA_BLOB decoded = data_blob(s, strlen(s)+1);
+ unsigned char *d = decoded.data;
+ char *p;
+
+ n=i=0;
+
+ while (*s && (p=strchr_m(b64,*s))) {
+ idx = (int)(p - b64);
+ byte_offset = (i*6)/8;
+ bit_offset = (i*6)%8;
+ d[byte_offset] &= ~((1<<(8-bit_offset))-1);
+ if (bit_offset < 3) {
+ d[byte_offset] |= (idx << (2-bit_offset));
+ n = byte_offset+1;
+ } else {
+ d[byte_offset] |= (idx >> (bit_offset-2));
+ d[byte_offset+1] = 0;
+ d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
+ n = byte_offset+2;
+ }
+ s++; i++;
+ }
+
+ if ((n > 0) && (*s == '=')) {
+ n -= 1;
+ }
+
+ /* fix up length */
+ decoded.length = n;
+ return decoded;
+}
+
+/**
+ * Decode a base64 string in-place - wrapper for the above
+ **/
+void base64_decode_inplace(char *s)
+{
+ DATA_BLOB decoded = base64_decode_data_blob(s);
+
+ if ( decoded.length != 0 ) {
+ memcpy(s, decoded.data, decoded.length);
+
+ /* null terminate */
+ s[decoded.length] = '\0';
+ } else {
+ *s = '\0';
+ }
+
+ data_blob_free(&decoded);
+}
+
+/**
+ * Encode a base64 string into a talloc()ed string caller to free.
+ *
+ * From SQUID: adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c
+ * with adjustments
+ **/
+
+char *base64_encode_data_blob(TALLOC_CTX *mem_ctx, DATA_BLOB data)
+{
+ int bits = 0;
+ int char_count = 0;
+ size_t out_cnt, len, output_len;
+ char *result;
+
+ if (!data.length || !data.data)
+ return NULL;
+
+ out_cnt = 0;
+ len = data.length;
+ output_len = data.length * 2 + 4; /* Account for closing bytes. 4 is
+ * random but should be enough for
+ * the = and \0 */
+ result = TALLOC_ARRAY(mem_ctx, char, output_len); /* get us plenty of space */
+ SMB_ASSERT(result != NULL);
+
+ while (len-- && out_cnt < (data.length * 2) - 5) {
+ int c = (unsigned char) *(data.data++);
+ bits += c;
+ char_count++;
+ if (char_count == 3) {
+ result[out_cnt++] = b64[bits >> 18];
+ result[out_cnt++] = b64[(bits >> 12) & 0x3f];
+ result[out_cnt++] = b64[(bits >> 6) & 0x3f];
+ result[out_cnt++] = b64[bits & 0x3f];
+ bits = 0;
+ char_count = 0;
+ } else {
+ bits <<= 8;
+ }
+ }
+ if (char_count != 0) {
+ bits <<= 16 - (8 * char_count);
+ result[out_cnt++] = b64[bits >> 18];
+ result[out_cnt++] = b64[(bits >> 12) & 0x3f];
+ if (char_count == 1) {
+ result[out_cnt++] = '=';
+ result[out_cnt++] = '=';
+ } else {
+ result[out_cnt++] = b64[(bits >> 6) & 0x3f];
+ result[out_cnt++] = '=';
+ }
+ }
+ result[out_cnt] = '\0'; /* terminate */
+ return result;
+}
+
+/* read a SMB_BIG_UINT from a string */
+SMB_BIG_UINT STR_TO_SMB_BIG_UINT(const char *nptr, const char **entptr)
+{
+
+ SMB_BIG_UINT val = -1;
+ const char *p = nptr;
+
+ if (!p) {
+ if (entptr) {
+ *entptr = p;
+ }
+ return val;
+ }
+
+ while (*p && isspace(*p))
+ p++;
+
+#ifdef LARGE_SMB_OFF_T
+ sscanf(p,"%llu",&val);
+#else /* LARGE_SMB_OFF_T */
+ sscanf(p,"%lu",&val);
+#endif /* LARGE_SMB_OFF_T */
+ if (entptr) {
+ while (*p && isdigit(*p))
+ p++;
+ *entptr = p;
+ }
+
+ return val;
+}
+
+/* Convert a size specification to a count of bytes. We accept the following
+ * suffixes:
+ * bytes if there is no suffix
+ * kK kibibytes
+ * mM mebibytes
+ * gG gibibytes
+ * tT tibibytes
+ * pP whatever the ISO name for petabytes is
+ *
+ * Returns 0 if the string can't be converted.
+ */
+SMB_OFF_T conv_str_size(const char * str)
+{
+ SMB_OFF_T lval;
+ char * end;
+
+ if (str == NULL || *str == '\0') {
+ return 0;
+ }
+
+#ifdef HAVE_STRTOULL
+ if (sizeof(SMB_OFF_T) == 8) {
+ lval = strtoull(str, &end, 10 /* base */);
+ } else {
+ lval = strtoul(str, &end, 10 /* base */);
+ }
+#else
+ lval = strtoul(str, &end, 10 /* base */);
+#endif
+
+ if (end == NULL || end == str) {
+ return 0;
+ }
+
+ if (*end) {
+ SMB_OFF_T lval_orig = lval;
+
+ if (strwicmp(end, "K") == 0) {
+ lval *= (SMB_OFF_T)1024;
+ } else if (strwicmp(end, "M") == 0) {
+ lval *= ((SMB_OFF_T)1024 * (SMB_OFF_T)1024);
+ } else if (strwicmp(end, "G") == 0) {
+ lval *= ((SMB_OFF_T)1024 * (SMB_OFF_T)1024 *
+ (SMB_OFF_T)1024);
+ } else if (strwicmp(end, "T") == 0) {
+ lval *= ((SMB_OFF_T)1024 * (SMB_OFF_T)1024 *
+ (SMB_OFF_T)1024 * (SMB_OFF_T)1024);
+ } else if (strwicmp(end, "P") == 0) {
+ lval *= ((SMB_OFF_T)1024 * (SMB_OFF_T)1024 *
+ (SMB_OFF_T)1024 * (SMB_OFF_T)1024 *
+ (SMB_OFF_T)1024);
+ } else {
+ return 0;
+ }
+
+ /* Primitive attempt to detect wrapping on platforms with
+ * 4-byte SMB_OFF_T. It's better to let the caller handle
+ * a failure than some random number.
+ */
+ if (lval_orig <= lval) {
+ return 0;
+ }
+ }
+
+ return lval;
+}
+
+void string_append(char **left, const char *right)
+{
+ int new_len = strlen(right) + 1;
+
+ if (*left == NULL) {
+ *left = (char *)SMB_MALLOC(new_len);
+ *left[0] = '\0';
+ } else {
+ new_len += strlen(*left);
+ *left = (char *)SMB_REALLOC(*left, new_len);
+ }
+
+ if (*left == NULL) {
+ return;
+ }
+
+ safe_strcat(*left, right, new_len-1);
+}
+
+bool add_string_to_array(TALLOC_CTX *mem_ctx,
+ const char *str, const char ***strings,
+ int *num)
+{
+ char *dup_str = talloc_strdup(mem_ctx, str);
+
+ *strings = TALLOC_REALLOC_ARRAY(mem_ctx, *strings,
+ const char *, (*num)+1);
+
+ if ((*strings == NULL) || (dup_str == NULL)) {
+ *num = 0;
+ return false;
+ }
+
+ (*strings)[*num] = dup_str;
+ *num += 1;
+ return true;
+}
+
+/* Append an sprintf'ed string. Double buffer size on demand. Usable without
+ * error checking in between. The indiation that something weird happened is
+ * string==NULL */
+
+void sprintf_append(TALLOC_CTX *mem_ctx, char **string, ssize_t *len,
+ size_t *bufsize, const char *fmt, ...)
+{
+ va_list ap;
+ char *newstr;
+ int ret;
+ bool increased;
+
+ /* len<0 is an internal marker that something failed */
+ if (*len < 0)
+ goto error;
+
+ if (*string == NULL) {
+ if (*bufsize == 0)
+ *bufsize = 128;
+
+ *string = TALLOC_ARRAY(mem_ctx, char, *bufsize);
+ if (*string == NULL)
+ goto error;
+ }
+
+ va_start(ap, fmt);
+ ret = vasprintf(&newstr, fmt, ap);
+ va_end(ap);
+
+ if (ret < 0)
+ goto error;
+
+ increased = false;
+
+ while ((*len)+ret >= *bufsize) {
+ increased = true;
+ *bufsize *= 2;
+ if (*bufsize >= (1024*1024*256))
+ goto error;
+ }
+
+ if (increased) {
+ *string = TALLOC_REALLOC_ARRAY(mem_ctx, *string, char,
+ *bufsize);
+ if (*string == NULL) {
+ goto error;
+ }
+ }
+
+ StrnCpy((*string)+(*len), newstr, ret);
+ (*len) += ret;
+ free(newstr);
+ return;
+
+ error:
+ *len = -1;
+ *string = NULL;
+}
+
+/*
+ * asprintf into a string and strupper_m it after that.
+ */
+
+int asprintf_strupper_m(char **strp, const char *fmt, ...)
+{
+ va_list ap;
+ char *result;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vasprintf(&result, fmt, ap);
+ va_end(ap);
+
+ if (ret == -1)
+ return -1;
+
+ strupper_m(result);
+ *strp = result;
+ return ret;
+}
+
+char *talloc_asprintf_strupper_m(TALLOC_CTX *t, const char *fmt, ...)
+{
+ va_list ap;
+ char *ret;
+
+ va_start(ap, fmt);
+ ret = talloc_vasprintf(t, fmt, ap);
+ va_end(ap);
+
+ if (ret == NULL) {
+ return NULL;
+ }
+ strupper_m(ret);
+ return ret;
+}
+
+char *talloc_asprintf_strlower_m(TALLOC_CTX *t, const char *fmt, ...)
+{
+ va_list ap;
+ char *ret;
+
+ va_start(ap, fmt);
+ ret = talloc_vasprintf(t, fmt, ap);
+ va_end(ap);
+
+ if (ret == NULL) {
+ return NULL;
+ }
+ strlower_m(ret);
+ return ret;
+}
+
+
+/*
+ Returns the substring from src between the first occurrence of
+ the char "front" and the first occurence of the char "back".
+ Mallocs the return string which must be freed. Not for use
+ with wide character strings.
+*/
+char *sstring_sub(const char *src, char front, char back)
+{
+ char *temp1, *temp2, *temp3;
+ ptrdiff_t len;
+
+ temp1 = strchr(src, front);
+ if (temp1 == NULL) return NULL;
+ temp2 = strchr(src, back);
+ if (temp2 == NULL) return NULL;
+ len = temp2 - temp1;
+ if (len <= 0) return NULL;
+ temp3 = (char*)SMB_MALLOC(len);
+ if (temp3 == NULL) {
+ DEBUG(1,("Malloc failure in sstring_sub\n"));
+ return NULL;
+ }
+ memcpy(temp3, temp1+1, len-1);
+ temp3[len-1] = '\0';
+ return temp3;
+}
+
+/********************************************************************
+ Check a string for any occurrences of a specified list of invalid
+ characters.
+********************************************************************/
+
+bool validate_net_name( const char *name,
+ const char *invalid_chars,
+ int max_len)
+{
+ int i;
+
+ for ( i=0; i<max_len && name[i]; i++ ) {
+ /* fail if strchr_m() finds one of the invalid characters */
+ if ( name[i] && strchr_m( invalid_chars, name[i] ) ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+/**
+return the number of bytes occupied by a buffer in ASCII format
+the result includes the null termination
+limited by 'n' bytes
+**/
+size_t ascii_len_n(const char *src, size_t n)
+{
+ size_t len;
+
+ len = strnlen(src, n);
+ if (len+1 <= n) {
+ len += 1;
+ }
+
+ return len;
+}
+
+/**
+return the number of bytes occupied by a buffer in CH_UTF16 format
+the result includes the null termination
+**/
+size_t utf16_len(const void *buf)
+{
+ size_t len;
+
+ for (len = 0; SVAL(buf,len); len += 2) ;
+
+ return len + 2;
+}
+
+/**
+return the number of bytes occupied by a buffer in CH_UTF16 format
+the result includes the null termination
+limited by 'n' bytes
+**/
+size_t utf16_len_n(const void *src, size_t n)
+{
+ size_t len;
+
+ for (len = 0; (len+2 < n) && SVAL(src, len); len += 2) ;
+
+ if (len+2 <= n) {
+ len += 2;
+ }
+
+ return len;
+}
+
+/*******************************************************************
+ Add a shell escape character '\' to any character not in a known list
+ of characters. UNIX charset format.
+*******************************************************************/
+
+#define INCLUDE_LIST "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_/ \t.,"
+#define INSIDE_DQUOTE_LIST "$`\n\"\\"
+
+char *escape_shell_string(const char *src)
+{
+ size_t srclen = strlen(src);
+ char *ret = SMB_MALLOC_ARRAY(char, (srclen * 2) + 1);
+ char *dest = ret;
+ bool in_s_quote = false;
+ bool in_d_quote = false;
+ bool next_escaped = false;
+
+ if (!ret) {
+ return NULL;
+ }
+
+ while (*src) {
+ size_t c_size;
+ codepoint_t c = next_codepoint(src, &c_size);
+
+ if (c == INVALID_CODEPOINT) {
+ SAFE_FREE(ret);
+ return NULL;
+ }
+
+ if (c_size > 1) {
+ memcpy(dest, src, c_size);
+ src += c_size;
+ dest += c_size;
+ next_escaped = false;
+ continue;
+ }
+
+ /*
+ * Deal with backslash escaped state.
+ * This only lasts for one character.
+ */
+
+ if (next_escaped) {
+ *dest++ = *src++;
+ next_escaped = false;
+ continue;
+ }
+
+ /*
+ * Deal with single quote state. The
+ * only thing we care about is exiting
+ * this state.
+ */
+
+ if (in_s_quote) {
+ if (*src == '\'') {
+ in_s_quote = false;
+ }
+ *dest++ = *src++;
+ continue;
+ }
+
+ /*
+ * Deal with double quote state. The most
+ * complex state. We must cope with \, meaning
+ * possibly escape next char (depending what it
+ * is), ", meaning exit this state, and possibly
+ * add an \ escape to any unprotected character
+ * (listed in INSIDE_DQUOTE_LIST).
+ */
+
+ if (in_d_quote) {
+ if (*src == '\\') {
+ /*
+ * Next character might be escaped.
+ * We have to peek. Inside double
+ * quotes only INSIDE_DQUOTE_LIST
+ * characters are escaped by a \.
+ */
+
+ char nextchar;
+
+ c = next_codepoint(&src[1], &c_size);
+ if (c == INVALID_CODEPOINT) {
+ SAFE_FREE(ret);
+ return NULL;
+ }
+ if (c_size > 1) {
+ /*
+ * Don't escape the next char.
+ * Just copy the \.
+ */
+ *dest++ = *src++;
+ continue;
+ }
+
+ nextchar = src[1];
+
+ if (nextchar && strchr(INSIDE_DQUOTE_LIST,
+ (int)nextchar)) {
+ next_escaped = true;
+ }
+ *dest++ = *src++;
+ continue;
+ }
+
+ if (*src == '\"') {
+ /* Exit double quote state. */
+ in_d_quote = false;
+ *dest++ = *src++;
+ continue;
+ }
+
+ /*
+ * We know the character isn't \ or ",
+ * so escape it if it's any of the other
+ * possible unprotected characters.
+ */
+
+ if (strchr(INSIDE_DQUOTE_LIST, (int)*src)) {
+ *dest++ = '\\';
+ }
+ *dest++ = *src++;
+ continue;
+ }
+
+ /*
+ * From here to the end of the loop we're
+ * not in the single or double quote state.
+ */
+
+ if (*src == '\\') {
+ /* Next character must be escaped. */
+ next_escaped = true;
+ *dest++ = *src++;
+ continue;
+ }
+
+ if (*src == '\'') {
+ /* Go into single quote state. */
+ in_s_quote = true;
+ *dest++ = *src++;
+ continue;
+ }
+
+ if (*src == '\"') {
+ /* Go into double quote state. */
+ in_d_quote = true;
+ *dest++ = *src++;
+ continue;
+ }
+
+ /* Check if we need to escape the character. */
+
+ if (!strchr(INCLUDE_LIST, (int)*src)) {
+ *dest++ = '\\';
+ }
+ *dest++ = *src++;
+ }
+ *dest++ = '\0';
+ return ret;
+}
diff --git a/source3/lib/util_tdb.c b/source3/lib/util_tdb.c
new file mode 100644
index 0000000000..8257232667
--- /dev/null
+++ b/source3/lib/util_tdb.c
@@ -0,0 +1,1481 @@
+/*
+ Unix SMB/CIFS implementation.
+ tdb utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Rafal Szczesniak 2002
+ Copyright (C) Michael Adam 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#undef malloc
+#undef realloc
+#undef calloc
+#undef strdup
+
+/* these are little tdb utility functions that are meant to make
+ dealing with a tdb database a little less cumbersome in Samba */
+
+static SIG_ATOMIC_T gotalarm;
+
+/***************************************************************
+ Signal function to tell us we timed out.
+****************************************************************/
+
+static void gotalarm_sig(void)
+{
+ gotalarm = 1;
+}
+
+/***************************************************************
+ Make a TDB_DATA and keep the const warning in one place
+****************************************************************/
+
+TDB_DATA make_tdb_data(const uint8 *dptr, size_t dsize)
+{
+ TDB_DATA ret;
+ ret.dptr = CONST_DISCARD(uint8 *, dptr);
+ ret.dsize = dsize;
+ return ret;
+}
+
+TDB_DATA string_tdb_data(const char *string)
+{
+ return make_tdb_data((const uint8 *)string, string ? strlen(string) : 0 );
+}
+
+TDB_DATA string_term_tdb_data(const char *string)
+{
+ return make_tdb_data((const uint8 *)string, string ? strlen(string) + 1 : 0);
+}
+
+/****************************************************************************
+ Lock a chain with timeout (in seconds).
+****************************************************************************/
+
+static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout, int rw_type)
+{
+ /* Allow tdb_chainlock to be interrupted by an alarm. */
+ int ret;
+ gotalarm = 0;
+
+ if (timeout) {
+ CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+ tdb_setalarm_sigptr(tdb, &gotalarm);
+ alarm(timeout);
+ }
+
+ if (rw_type == F_RDLCK)
+ ret = tdb_chainlock_read(tdb, key);
+ else
+ ret = tdb_chainlock(tdb, key);
+
+ if (timeout) {
+ alarm(0);
+ tdb_setalarm_sigptr(tdb, NULL);
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
+ if (gotalarm) {
+ DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
+ timeout, key.dptr, tdb_name(tdb)));
+ /* TODO: If we time out waiting for a lock, it might
+ * be nice to use F_GETLK to get the pid of the
+ * process currently holding the lock and print that
+ * as part of the debugging message. -- mbp */
+ return -1;
+ }
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Write lock a chain. Return -1 if timeout or lock failed.
+****************************************************************************/
+
+int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout)
+{
+ return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
+}
+
+/****************************************************************************
+ Lock a chain by string. Return -1 if timeout or lock failed.
+****************************************************************************/
+
+int tdb_lock_bystring(TDB_CONTEXT *tdb, const char *keyval)
+{
+ TDB_DATA key = string_term_tdb_data(keyval);
+
+ return tdb_chainlock(tdb, key);
+}
+
+int tdb_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval,
+ int timeout)
+{
+ TDB_DATA key = string_term_tdb_data(keyval);
+
+ return tdb_chainlock_with_timeout(tdb, key, timeout);
+}
+
+/****************************************************************************
+ Unlock a chain by string.
+****************************************************************************/
+
+void tdb_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
+{
+ TDB_DATA key = string_term_tdb_data(keyval);
+
+ tdb_chainunlock(tdb, key);
+}
+
+/****************************************************************************
+ Read lock a chain by string. Return -1 if timeout or lock failed.
+****************************************************************************/
+
+int tdb_read_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval, unsigned int timeout)
+{
+ TDB_DATA key = string_term_tdb_data(keyval);
+
+ return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK);
+}
+
+/****************************************************************************
+ Read unlock a chain by string.
+****************************************************************************/
+
+void tdb_read_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
+{
+ TDB_DATA key = string_term_tdb_data(keyval);
+
+ tdb_chainunlock_read(tdb, key);
+}
+
+
+/****************************************************************************
+ Fetch a int32 value by a arbitrary blob key, return -1 if not found.
+ Output is int32 in native byte order.
+****************************************************************************/
+
+int32 tdb_fetch_int32_byblob(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ TDB_DATA data;
+ int32 ret;
+
+ data = tdb_fetch(tdb, key);
+ if (!data.dptr || data.dsize != sizeof(int32)) {
+ SAFE_FREE(data.dptr);
+ return -1;
+ }
+
+ ret = IVAL(data.dptr,0);
+ SAFE_FREE(data.dptr);
+ return ret;
+}
+
+/****************************************************************************
+ Fetch a int32 value by string key, return -1 if not found.
+ Output is int32 in native byte order.
+****************************************************************************/
+
+int32 tdb_fetch_int32(TDB_CONTEXT *tdb, const char *keystr)
+{
+ TDB_DATA key = string_term_tdb_data(keystr);
+
+ return tdb_fetch_int32_byblob(tdb, key);
+}
+
+/****************************************************************************
+ Store a int32 value by an arbitary blob key, return 0 on success, -1 on failure.
+ Input is int32 in native byte order. Output in tdb is in little-endian.
+****************************************************************************/
+
+int tdb_store_int32_byblob(TDB_CONTEXT *tdb, TDB_DATA key, int32 v)
+{
+ TDB_DATA data;
+ int32 v_store;
+
+ SIVAL(&v_store,0,v);
+ data.dptr = (uint8 *)&v_store;
+ data.dsize = sizeof(int32);
+
+ return tdb_store(tdb, key, data, TDB_REPLACE);
+}
+
+/****************************************************************************
+ Store a int32 value by string key, return 0 on success, -1 on failure.
+ Input is int32 in native byte order. Output in tdb is in little-endian.
+****************************************************************************/
+
+int tdb_store_int32(TDB_CONTEXT *tdb, const char *keystr, int32 v)
+{
+ TDB_DATA key = string_term_tdb_data(keystr);
+
+ return tdb_store_int32_byblob(tdb, key, v);
+}
+
+/****************************************************************************
+ Fetch a uint32 value by a arbitrary blob key, return -1 if not found.
+ Output is uint32 in native byte order.
+****************************************************************************/
+
+bool tdb_fetch_uint32_byblob(TDB_CONTEXT *tdb, TDB_DATA key, uint32 *value)
+{
+ TDB_DATA data;
+
+ data = tdb_fetch(tdb, key);
+ if (!data.dptr || data.dsize != sizeof(uint32)) {
+ SAFE_FREE(data.dptr);
+ return False;
+ }
+
+ *value = IVAL(data.dptr,0);
+ SAFE_FREE(data.dptr);
+ return True;
+}
+
+/****************************************************************************
+ Fetch a uint32 value by string key, return -1 if not found.
+ Output is uint32 in native byte order.
+****************************************************************************/
+
+bool tdb_fetch_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32 *value)
+{
+ TDB_DATA key = string_term_tdb_data(keystr);
+
+ return tdb_fetch_uint32_byblob(tdb, key, value);
+}
+
+/****************************************************************************
+ Store a uint32 value by an arbitary blob key, return 0 on success, -1 on failure.
+ Input is uint32 in native byte order. Output in tdb is in little-endian.
+****************************************************************************/
+
+bool tdb_store_uint32_byblob(TDB_CONTEXT *tdb, TDB_DATA key, uint32 value)
+{
+ TDB_DATA data;
+ uint32 v_store;
+ bool ret = True;
+
+ SIVAL(&v_store, 0, value);
+ data.dptr = (uint8 *)&v_store;
+ data.dsize = sizeof(uint32);
+
+ if (tdb_store(tdb, key, data, TDB_REPLACE) == -1)
+ ret = False;
+
+ return ret;
+}
+
+/****************************************************************************
+ Store a uint32 value by string key, return 0 on success, -1 on failure.
+ Input is uint32 in native byte order. Output in tdb is in little-endian.
+****************************************************************************/
+
+bool tdb_store_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32 value)
+{
+ TDB_DATA key = string_term_tdb_data(keystr);
+
+ return tdb_store_uint32_byblob(tdb, key, value);
+}
+/****************************************************************************
+ Store a buffer by a null terminated string key. Return 0 on success, -1
+ on failure.
+****************************************************************************/
+
+int tdb_store_bystring(TDB_CONTEXT *tdb, const char *keystr, TDB_DATA data, int flags)
+{
+ TDB_DATA key = string_term_tdb_data(keystr);
+
+ return tdb_store(tdb, key, data, flags);
+}
+
+int tdb_trans_store_bystring(TDB_CONTEXT *tdb, const char *keystr,
+ TDB_DATA data, int flags)
+{
+ TDB_DATA key = string_term_tdb_data(keystr);
+
+ return tdb_trans_store(tdb, key, data, flags);
+}
+
+/****************************************************************************
+ Fetch a buffer using a null terminated string key. Don't forget to call
+ free() on the result dptr.
+****************************************************************************/
+
+TDB_DATA tdb_fetch_bystring(TDB_CONTEXT *tdb, const char *keystr)
+{
+ TDB_DATA key = string_term_tdb_data(keystr);
+
+ return tdb_fetch(tdb, key);
+}
+
+/****************************************************************************
+ Delete an entry using a null terminated string key.
+****************************************************************************/
+
+int tdb_delete_bystring(TDB_CONTEXT *tdb, const char *keystr)
+{
+ TDB_DATA key = string_term_tdb_data(keystr);
+
+ return tdb_delete(tdb, key);
+}
+
+/****************************************************************************
+ Atomic integer change. Returns old value. To create, set initial value in *oldval.
+****************************************************************************/
+
+int32 tdb_change_int32_atomic(TDB_CONTEXT *tdb, const char *keystr, int32 *oldval, int32 change_val)
+{
+ int32 val;
+ int32 ret = -1;
+
+ if (tdb_lock_bystring(tdb, keystr) == -1)
+ return -1;
+
+ if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
+ /* The lookup failed */
+ if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
+ /* but not because it didn't exist */
+ goto err_out;
+ }
+
+ /* Start with 'old' value */
+ val = *oldval;
+
+ } else {
+ /* It worked, set return value (oldval) to tdb data */
+ *oldval = val;
+ }
+
+ /* Increment value for storage and return next time */
+ val += change_val;
+
+ if (tdb_store_int32(tdb, keystr, val) == -1)
+ goto err_out;
+
+ ret = 0;
+
+ err_out:
+
+ tdb_unlock_bystring(tdb, keystr);
+ return ret;
+}
+
+/****************************************************************************
+ Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval.
+****************************************************************************/
+
+bool tdb_change_uint32_atomic(TDB_CONTEXT *tdb, const char *keystr, uint32 *oldval, uint32 change_val)
+{
+ uint32 val;
+ bool ret = False;
+
+ if (tdb_lock_bystring(tdb, keystr) == -1)
+ return False;
+
+ if (!tdb_fetch_uint32(tdb, keystr, &val)) {
+ /* It failed */
+ if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
+ /* and not because it didn't exist */
+ goto err_out;
+ }
+
+ /* Start with 'old' value */
+ val = *oldval;
+
+ } else {
+ /* it worked, set return value (oldval) to tdb data */
+ *oldval = val;
+
+ }
+
+ /* get a new value to store */
+ val += change_val;
+
+ if (!tdb_store_uint32(tdb, keystr, val))
+ goto err_out;
+
+ ret = True;
+
+ err_out:
+
+ tdb_unlock_bystring(tdb, keystr);
+ return ret;
+}
+
+/****************************************************************************
+ Useful pair of routines for packing/unpacking data consisting of
+ integers and strings.
+****************************************************************************/
+
+static size_t tdb_pack_va(uint8 *buf, int bufsize, const char *fmt, va_list ap)
+{
+ uint8 bt;
+ uint16 w;
+ uint32 d;
+ int i;
+ void *p;
+ int len;
+ char *s;
+ char c;
+ uint8 *buf0 = buf;
+ const char *fmt0 = fmt;
+ int bufsize0 = bufsize;
+
+ while (*fmt) {
+ switch ((c = *fmt++)) {
+ case 'b': /* unsigned 8-bit integer */
+ len = 1;
+ bt = (uint8)va_arg(ap, int);
+ if (bufsize && bufsize >= len)
+ SSVAL(buf, 0, bt);
+ break;
+ case 'w': /* unsigned 16-bit integer */
+ len = 2;
+ w = (uint16)va_arg(ap, int);
+ if (bufsize && bufsize >= len)
+ SSVAL(buf, 0, w);
+ break;
+ case 'd': /* signed 32-bit integer (standard int in most systems) */
+ len = 4;
+ d = va_arg(ap, uint32);
+ if (bufsize && bufsize >= len)
+ SIVAL(buf, 0, d);
+ break;
+ case 'p': /* pointer */
+ len = 4;
+ p = va_arg(ap, void *);
+ d = p?1:0;
+ if (bufsize && bufsize >= len)
+ SIVAL(buf, 0, d);
+ break;
+ case 'P': /* null-terminated string */
+ s = va_arg(ap,char *);
+ w = strlen(s);
+ len = w + 1;
+ if (bufsize && bufsize >= len)
+ memcpy(buf, s, len);
+ break;
+ case 'f': /* null-terminated string */
+ s = va_arg(ap,char *);
+ w = strlen(s);
+ len = w + 1;
+ if (bufsize && bufsize >= len)
+ memcpy(buf, s, len);
+ break;
+ case 'B': /* fixed-length string */
+ i = va_arg(ap, int);
+ s = va_arg(ap, char *);
+ len = 4+i;
+ if (bufsize && bufsize >= len) {
+ SIVAL(buf, 0, i);
+ memcpy(buf+4, s, i);
+ }
+ break;
+ default:
+ DEBUG(0,("Unknown tdb_pack format %c in %s\n",
+ c, fmt));
+ len = 0;
+ break;
+ }
+
+ buf += len;
+ if (bufsize)
+ bufsize -= len;
+ if (bufsize < 0)
+ bufsize = 0;
+ }
+
+ DEBUG(18,("tdb_pack_va(%s, %d) -> %d\n",
+ fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
+
+ return PTR_DIFF(buf, buf0);
+}
+
+size_t tdb_pack(uint8 *buf, int bufsize, const char *fmt, ...)
+{
+ va_list ap;
+ size_t result;
+
+ va_start(ap, fmt);
+ result = tdb_pack_va(buf, bufsize, fmt, ap);
+ va_end(ap);
+ return result;
+}
+
+bool tdb_pack_append(TALLOC_CTX *mem_ctx, uint8 **buf, size_t *len,
+ const char *fmt, ...)
+{
+ va_list ap;
+ size_t len1, len2;
+
+ va_start(ap, fmt);
+ len1 = tdb_pack_va(NULL, 0, fmt, ap);
+ va_end(ap);
+
+ if (mem_ctx != NULL) {
+ *buf = TALLOC_REALLOC_ARRAY(mem_ctx, *buf, uint8,
+ (*len) + len1);
+ } else {
+ *buf = SMB_REALLOC_ARRAY(*buf, uint8, (*len) + len1);
+ }
+
+ if (*buf == NULL) {
+ return False;
+ }
+
+ va_start(ap, fmt);
+ len2 = tdb_pack_va((*buf)+(*len), len1, fmt, ap);
+ va_end(ap);
+
+ if (len1 != len2) {
+ return False;
+ }
+
+ *len += len2;
+
+ return True;
+}
+
+/****************************************************************************
+ Useful pair of routines for packing/unpacking data consisting of
+ integers and strings.
+****************************************************************************/
+
+int tdb_unpack(const uint8 *buf, int bufsize, const char *fmt, ...)
+{
+ va_list ap;
+ uint8 *bt;
+ uint16 *w;
+ uint32 *d;
+ int len;
+ int *i;
+ void **p;
+ char *s, **b, **ps;
+ char c;
+ const uint8 *buf0 = buf;
+ const char *fmt0 = fmt;
+ int bufsize0 = bufsize;
+
+ va_start(ap, fmt);
+
+ while (*fmt) {
+ switch ((c=*fmt++)) {
+ case 'b':
+ len = 1;
+ bt = va_arg(ap, uint8 *);
+ if (bufsize < len)
+ goto no_space;
+ *bt = SVAL(buf, 0);
+ break;
+ case 'w':
+ len = 2;
+ w = va_arg(ap, uint16 *);
+ if (bufsize < len)
+ goto no_space;
+ *w = SVAL(buf, 0);
+ break;
+ case 'd':
+ len = 4;
+ d = va_arg(ap, uint32 *);
+ if (bufsize < len)
+ goto no_space;
+ *d = IVAL(buf, 0);
+ break;
+ case 'p':
+ len = 4;
+ p = va_arg(ap, void **);
+ if (bufsize < len)
+ goto no_space;
+ /*
+ * This isn't a real pointer - only a token (1 or 0)
+ * to mark the fact a pointer is present.
+ */
+
+ *p = (void *)(IVAL(buf, 0) ? (void *)1 : NULL);
+ break;
+ case 'P':
+ /* Return malloc'ed string. */
+ ps = va_arg(ap,char **);
+ len = strlen((const char *)buf) + 1;
+ *ps = SMB_STRDUP((const char *)buf);
+ break;
+ case 'f':
+ s = va_arg(ap,char *);
+ len = strlen((const char *)buf) + 1;
+ if (bufsize < len || len > sizeof(fstring))
+ goto no_space;
+ memcpy(s, buf, len);
+ break;
+ case 'B':
+ i = va_arg(ap, int *);
+ b = va_arg(ap, char **);
+ len = 4;
+ if (bufsize < len)
+ goto no_space;
+ *i = IVAL(buf, 0);
+ if (! *i) {
+ *b = NULL;
+ break;
+ }
+ len += *i;
+ if (bufsize < len)
+ goto no_space;
+ *b = (char *)SMB_MALLOC(*i);
+ if (! *b)
+ goto no_space;
+ memcpy(*b, buf+4, *i);
+ break;
+ default:
+ DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
+ c, fmt));
+
+ len = 0;
+ break;
+ }
+
+ buf += len;
+ bufsize -= len;
+ }
+
+ va_end(ap);
+
+ DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
+ fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
+
+ return PTR_DIFF(buf, buf0);
+
+ no_space:
+ va_end(ap);
+ return -1;
+}
+
+
+/****************************************************************************
+ Log tdb messages via DEBUG().
+****************************************************************************/
+
+static void tdb_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, const char *format, ...)
+{
+ va_list ap;
+ char *ptr = NULL;
+ int ret;
+
+ va_start(ap, format);
+ ret = vasprintf(&ptr, format, ap);
+ va_end(ap);
+
+ if ((ret == -1) || !*ptr)
+ return;
+
+ DEBUG((int)level, ("tdb(%s): %s", tdb_name(tdb) ? tdb_name(tdb) : "unnamed", ptr));
+ SAFE_FREE(ptr);
+}
+
+/****************************************************************************
+ Like tdb_open() but also setup a logging function that redirects to
+ the samba DEBUG() system.
+****************************************************************************/
+
+TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode)
+{
+ TDB_CONTEXT *tdb;
+ struct tdb_logging_context log_ctx;
+
+ if (!lp_use_mmap())
+ tdb_flags |= TDB_NOMMAP;
+
+ log_ctx.log_fn = tdb_log;
+ log_ctx.log_private = NULL;
+
+ if ((hash_size == 0) && (name != NULL)) {
+ const char *base = strrchr_m(name, '/');
+ if (base != NULL) {
+ base += 1;
+ }
+ else {
+ base = name;
+ }
+ hash_size = lp_parm_int(-1, "tdb_hashsize", base, 0);
+ }
+
+ tdb = tdb_open_ex(name, hash_size, tdb_flags,
+ open_flags, mode, &log_ctx, NULL);
+ if (!tdb)
+ return NULL;
+
+ return tdb;
+}
+
+
+/**
+ * Search across the whole tdb for keys that match the given pattern
+ * return the result as a list of keys
+ *
+ * @param tdb pointer to opened tdb file context
+ * @param pattern searching pattern used by fnmatch(3) functions
+ *
+ * @return list of keys found by looking up with given pattern
+ **/
+TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern)
+{
+ TDB_DATA key, next;
+ TDB_LIST_NODE *list = NULL;
+ TDB_LIST_NODE *rec = NULL;
+
+ for (key = tdb_firstkey(tdb); key.dptr; key = next) {
+ /* duplicate key string to ensure null-termination */
+ char *key_str = SMB_STRNDUP((const char *)key.dptr, key.dsize);
+ if (!key_str) {
+ DEBUG(0, ("tdb_search_keys: strndup() failed!\n"));
+ smb_panic("strndup failed!\n");
+ }
+
+ DEBUG(18, ("checking %s for match to pattern %s\n", key_str, pattern));
+
+ next = tdb_nextkey(tdb, key);
+
+ /* do the pattern checking */
+ if (fnmatch(pattern, key_str, 0) == 0) {
+ rec = SMB_MALLOC_P(TDB_LIST_NODE);
+ ZERO_STRUCTP(rec);
+
+ rec->node_key = key;
+
+ DLIST_ADD_END(list, rec, TDB_LIST_NODE *);
+
+ DEBUG(18, ("checking %s matched pattern %s\n", key_str, pattern));
+ } else {
+ free(key.dptr);
+ }
+
+ /* free duplicated key string */
+ free(key_str);
+ }
+
+ return list;
+
+}
+
+
+/**
+ * Free the list returned by tdb_search_keys
+ *
+ * @param node list of results found by tdb_search_keys
+ **/
+void tdb_search_list_free(TDB_LIST_NODE* node)
+{
+ TDB_LIST_NODE *next_node;
+
+ while (node) {
+ next_node = node->next;
+ SAFE_FREE(node->node_key.dptr);
+ SAFE_FREE(node);
+ node = next_node;
+ };
+}
+
+/****************************************************************************
+ tdb_store, wrapped in a transaction. This way we make sure that a process
+ that dies within writing does not leave a corrupt tdb behind.
+****************************************************************************/
+
+int tdb_trans_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
+ int flag)
+{
+ int res;
+
+ if ((res = tdb_transaction_start(tdb)) != 0) {
+ DEBUG(5, ("tdb_transaction_start failed\n"));
+ return res;
+ }
+
+ if ((res = tdb_store(tdb, key, dbuf, flag)) != 0) {
+ DEBUG(10, ("tdb_store failed\n"));
+ if (tdb_transaction_cancel(tdb) != 0) {
+ smb_panic("Cancelling transaction failed");
+ }
+ return res;
+ }
+
+ if ((res = tdb_transaction_commit(tdb)) != 0) {
+ DEBUG(5, ("tdb_transaction_commit failed\n"));
+ }
+
+ return res;
+}
+
+/****************************************************************************
+ tdb_delete, wrapped in a transaction. This way we make sure that a process
+ that dies within deleting does not leave a corrupt tdb behind.
+****************************************************************************/
+
+int tdb_trans_delete(struct tdb_context *tdb, TDB_DATA key)
+{
+ int res;
+
+ if ((res = tdb_transaction_start(tdb)) != 0) {
+ DEBUG(5, ("tdb_transaction_start failed\n"));
+ return res;
+ }
+
+ if ((res = tdb_delete(tdb, key)) != 0) {
+ DEBUG(10, ("tdb_delete failed\n"));
+ if (tdb_transaction_cancel(tdb) != 0) {
+ smb_panic("Cancelling transaction failed");
+ }
+ return res;
+ }
+
+ if ((res = tdb_transaction_commit(tdb)) != 0) {
+ DEBUG(5, ("tdb_transaction_commit failed\n"));
+ }
+
+ return res;
+}
+
+/*
+ Log tdb messages via DEBUG().
+*/
+static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level,
+ const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+
+static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level,
+ const char *format, ...)
+{
+ va_list ap;
+ char *ptr = NULL;
+ int debuglevel = 0;
+ int ret;
+
+ switch (level) {
+ case TDB_DEBUG_FATAL:
+ debuglevel = 0;
+ break;
+ case TDB_DEBUG_ERROR:
+ debuglevel = 1;
+ break;
+ case TDB_DEBUG_WARNING:
+ debuglevel = 2;
+ break;
+ case TDB_DEBUG_TRACE:
+ debuglevel = 5;
+ break;
+ default:
+ debuglevel = 0;
+ }
+
+ va_start(ap, format);
+ ret = vasprintf(&ptr, format, ap);
+ va_end(ap);
+
+ if (ret != -1) {
+ const char *name = tdb_name(tdb);
+ DEBUG(debuglevel, ("tdb(%s): %s", name ? name : "unnamed", ptr));
+ free(ptr);
+ }
+}
+
+static struct tdb_wrap *tdb_list;
+
+/* destroy the last connection to a tdb */
+static int tdb_wrap_destructor(struct tdb_wrap *w)
+{
+ tdb_close(w->tdb);
+ DLIST_REMOVE(tdb_list, w);
+ return 0;
+}
+
+/*
+ wrapped connection to a tdb database
+ to close just talloc_free() the tdb_wrap pointer
+ */
+struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx,
+ const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode)
+{
+ struct tdb_wrap *w;
+ struct tdb_logging_context log_ctx;
+ log_ctx.log_fn = tdb_wrap_log;
+
+ if (!lp_use_mmap())
+ tdb_flags |= TDB_NOMMAP;
+
+ for (w=tdb_list;w;w=w->next) {
+ if (strcmp(name, w->name) == 0) {
+ /*
+ * Yes, talloc_reference is exactly what we want
+ * here. Otherwise we would have to implement our own
+ * reference counting.
+ */
+ return talloc_reference(mem_ctx, w);
+ }
+ }
+
+ w = talloc(mem_ctx, struct tdb_wrap);
+ if (w == NULL) {
+ return NULL;
+ }
+
+ if (!(w->name = talloc_strdup(w, name))) {
+ talloc_free(w);
+ return NULL;
+ }
+
+ if ((hash_size == 0) && (name != NULL)) {
+ const char *base = strrchr_m(name, '/');
+ if (base != NULL) {
+ base += 1;
+ }
+ else {
+ base = name;
+ }
+ hash_size = lp_parm_int(-1, "tdb_hashsize", base, 0);
+ }
+
+ w->tdb = tdb_open_ex(name, hash_size, tdb_flags,
+ open_flags, mode, &log_ctx, NULL);
+ if (w->tdb == NULL) {
+ talloc_free(w);
+ return NULL;
+ }
+
+ talloc_set_destructor(w, tdb_wrap_destructor);
+
+ DLIST_ADD(tdb_list, w);
+
+ return w;
+}
+
+NTSTATUS map_nt_error_from_tdb(enum TDB_ERROR err)
+{
+ struct { enum TDB_ERROR err; NTSTATUS status; } map[] =
+ { { TDB_SUCCESS, NT_STATUS_OK },
+ { TDB_ERR_CORRUPT, NT_STATUS_INTERNAL_DB_CORRUPTION },
+ { TDB_ERR_IO, NT_STATUS_UNEXPECTED_IO_ERROR },
+ { TDB_ERR_OOM, NT_STATUS_NO_MEMORY },
+ { TDB_ERR_EXISTS, NT_STATUS_OBJECT_NAME_COLLISION },
+
+ /*
+ * TDB_ERR_LOCK is very broad, we could for example
+ * distinguish between fcntl locks and invalid lock
+ * sequences. So NT_STATUS_FILE_LOCK_CONFLICT is a
+ * compromise.
+ */
+ { TDB_ERR_LOCK, NT_STATUS_FILE_LOCK_CONFLICT },
+ /*
+ * The next two ones in the enum are not actually used
+ */
+ { TDB_ERR_NOLOCK, NT_STATUS_FILE_LOCK_CONFLICT },
+ { TDB_ERR_LOCK_TIMEOUT, NT_STATUS_FILE_LOCK_CONFLICT },
+ { TDB_ERR_NOEXIST, NT_STATUS_NOT_FOUND },
+ { TDB_ERR_EINVAL, NT_STATUS_INVALID_PARAMETER },
+ { TDB_ERR_RDONLY, NT_STATUS_ACCESS_DENIED }
+ };
+
+ int i;
+
+ for (i=0; i < sizeof(map) / sizeof(map[0]); i++) {
+ if (err == map[i].err) {
+ return map[i].status;
+ }
+ }
+
+ return NT_STATUS_INTERNAL_ERROR;
+}
+
+
+/*********************************************************************
+ * the following is a generic validation mechanism for tdbs.
+ *********************************************************************/
+
+/*
+ * internal validation function, executed by the child.
+ */
+static int tdb_validate_child(struct tdb_context *tdb,
+ tdb_validate_data_func validate_fn)
+{
+ int ret = 1;
+ int num_entries = 0;
+ struct tdb_validation_status v_status;
+
+ v_status.tdb_error = False;
+ v_status.bad_freelist = False;
+ v_status.bad_entry = False;
+ v_status.unknown_key = False;
+ v_status.success = True;
+
+ if (!tdb) {
+ v_status.tdb_error = True;
+ v_status.success = False;
+ goto out;
+ }
+
+ /* Check if the tdb's freelist is good. */
+ if (tdb_validate_freelist(tdb, &num_entries) == -1) {
+ v_status.bad_freelist = True;
+ v_status.success = False;
+ goto out;
+ }
+
+ DEBUG(10,("tdb_validate_child: tdb %s freelist has %d entries\n",
+ tdb_name(tdb), num_entries));
+
+ /* Now traverse the tdb to validate it. */
+ num_entries = tdb_traverse(tdb, validate_fn, (void *)&v_status);
+ if (!v_status.success) {
+ goto out;
+ } else if (num_entries == -1) {
+ v_status.tdb_error = True;
+ v_status.success = False;
+ goto out;
+ }
+
+ DEBUG(10,("tdb_validate_child: tdb %s is good with %d entries\n",
+ tdb_name(tdb), num_entries));
+ ret = 0; /* Cache is good. */
+
+out:
+ DEBUG(10, ("tdb_validate_child: summary of validation status:\n"));
+ DEBUGADD(10,(" * tdb error: %s\n", v_status.tdb_error ? "yes" : "no"));
+ DEBUGADD(10,(" * bad freelist: %s\n",v_status.bad_freelist?"yes":"no"));
+ DEBUGADD(10,(" * bad entry: %s\n", v_status.bad_entry ? "yes" : "no"));
+ DEBUGADD(10,(" * unknown key: %s\n", v_status.unknown_key?"yes":"no"));
+ DEBUGADD(10,(" => overall success: %s\n", v_status.success?"yes":"no"));
+
+ return ret;
+}
+
+/*
+ * tdb validation function.
+ * returns 0 if tdb is ok, != 0 if it isn't.
+ * this function expects an opened tdb.
+ */
+int tdb_validate(struct tdb_context *tdb, tdb_validate_data_func validate_fn)
+{
+ pid_t child_pid = -1;
+ int child_status = 0;
+ int wait_pid = 0;
+ int ret = 1;
+
+ if (tdb == NULL) {
+ DEBUG(1, ("Error: tdb_validate called with tdb == NULL\n"));
+ return ret;
+ }
+
+ DEBUG(5, ("tdb_validate called for tdb '%s'\n", tdb_name(tdb)));
+
+ /* fork and let the child do the validation.
+ * benefit: no need to twist signal handlers and panic functions.
+ * just let the child panic. we catch the signal. */
+
+ DEBUG(10, ("tdb_validate: forking to let child do validation.\n"));
+ child_pid = sys_fork();
+ if (child_pid == 0) {
+ /* child code */
+ DEBUG(10, ("tdb_validate (validation child): created\n"));
+ DEBUG(10, ("tdb_validate (validation child): "
+ "calling tdb_validate_child\n"));
+ exit(tdb_validate_child(tdb, validate_fn));
+ }
+ else if (child_pid < 0) {
+ DEBUG(1, ("tdb_validate: fork for validation failed.\n"));
+ goto done;
+ }
+
+ /* parent */
+
+ DEBUG(10, ("tdb_validate: fork succeeded, child PID = %d\n",child_pid));
+
+ DEBUG(10, ("tdb_validate: waiting for child to finish...\n"));
+ while ((wait_pid = sys_waitpid(child_pid, &child_status, 0)) < 0) {
+ if (errno == EINTR) {
+ DEBUG(10, ("tdb_validate: got signal during waitpid, "
+ "retrying\n"));
+ errno = 0;
+ continue;
+ }
+ DEBUG(1, ("tdb_validate: waitpid failed with error '%s'.\n",
+ strerror(errno)));
+ goto done;
+ }
+ if (wait_pid != child_pid) {
+ DEBUG(1, ("tdb_validate: waitpid returned pid %d, "
+ "but %d was expected\n", wait_pid, child_pid));
+ goto done;
+ }
+
+ DEBUG(10, ("tdb_validate: validating child returned.\n"));
+ if (WIFEXITED(child_status)) {
+ DEBUG(10, ("tdb_validate: child exited, code %d.\n",
+ WEXITSTATUS(child_status)));
+ ret = WEXITSTATUS(child_status);
+ }
+ if (WIFSIGNALED(child_status)) {
+ DEBUG(10, ("tdb_validate: child terminated by signal %d\n",
+ WTERMSIG(child_status)));
+#ifdef WCOREDUMP
+ if (WCOREDUMP(child_status)) {
+ DEBUGADD(10, ("core dumped\n"));
+ }
+#endif
+ ret = WTERMSIG(child_status);
+ }
+ if (WIFSTOPPED(child_status)) {
+ DEBUG(10, ("tdb_validate: child was stopped by signal %d\n",
+ WSTOPSIG(child_status)));
+ ret = WSTOPSIG(child_status);
+ }
+
+done:
+ DEBUG(5, ("tdb_validate returning code '%d' for tdb '%s'\n", ret,
+ tdb_name(tdb)));
+
+ return ret;
+}
+
+/*
+ * tdb validation function.
+ * returns 0 if tdb is ok, != 0 if it isn't.
+ * this is a wrapper around the actual validation function that opens and closes
+ * the tdb.
+ */
+int tdb_validate_open(const char *tdb_path, tdb_validate_data_func validate_fn)
+{
+ TDB_CONTEXT *tdb = NULL;
+ int ret = 1;
+
+ DEBUG(5, ("tdb_validate_open called for tdb '%s'\n", tdb_path));
+
+ tdb = tdb_open_log(tdb_path, 0, TDB_DEFAULT, O_RDONLY, 0);
+ if (!tdb) {
+ DEBUG(1, ("Error opening tdb %s\n", tdb_path));
+ return ret;
+ }
+
+ ret = tdb_validate(tdb, validate_fn);
+ tdb_close(tdb);
+ return ret;
+}
+
+/*
+ * tdb backup function and helpers for tdb_validate wrapper with backup
+ * handling.
+ */
+
+/* this structure eliminates the need for a global overall status for
+ * the traverse-copy */
+struct tdb_copy_data {
+ struct tdb_context *dst;
+ bool success;
+};
+
+static int traverse_copy_fn(struct tdb_context *tdb, TDB_DATA key,
+ TDB_DATA dbuf, void *private_data)
+{
+ struct tdb_copy_data *data = (struct tdb_copy_data *)private_data;
+
+ if (tdb_store(data->dst, key, dbuf, TDB_INSERT) != 0) {
+ DEBUG(4, ("Failed to insert into %s: %s\n", tdb_name(data->dst),
+ strerror(errno)));
+ data->success = False;
+ return 1;
+ }
+ return 0;
+}
+
+static int tdb_copy(struct tdb_context *src, struct tdb_context *dst)
+{
+ struct tdb_copy_data data;
+ int count;
+
+ data.dst = dst;
+ data.success = True;
+
+ count = tdb_traverse(src, traverse_copy_fn, (void *)(&data));
+ if ((count < 0) || (data.success == False)) {
+ return -1;
+ }
+ return count;
+}
+
+static int tdb_verify_basic(struct tdb_context *tdb)
+{
+ return tdb_traverse(tdb, NULL, NULL);
+}
+
+/* this backup function is essentially taken from lib/tdb/tools/tdbbackup.tdb
+ */
+static int tdb_backup(TALLOC_CTX *ctx, const char *src_path,
+ const char *dst_path, int hash_size)
+{
+ struct tdb_context *src_tdb = NULL;
+ struct tdb_context *dst_tdb = NULL;
+ char *tmp_path = NULL;
+ struct stat st;
+ int count1, count2;
+ int saved_errno = 0;
+ int ret = -1;
+
+ if (stat(src_path, &st) != 0) {
+ DEBUG(3, ("Could not stat '%s': %s\n", src_path,
+ strerror(errno)));
+ goto done;
+ }
+
+ /* open old tdb RDWR - so we can lock it */
+ src_tdb = tdb_open_log(src_path, 0, TDB_DEFAULT, O_RDWR, 0);
+ if (src_tdb == NULL) {
+ DEBUG(3, ("Failed to open tdb '%s'\n", src_path));
+ goto done;
+ }
+
+ if (tdb_lockall(src_tdb) != 0) {
+ DEBUG(3, ("Failed to lock tdb '%s'\n", src_path));
+ goto done;
+ }
+
+ tmp_path = talloc_asprintf(ctx, "%s%s", dst_path, ".tmp");
+ unlink(tmp_path);
+ dst_tdb = tdb_open_log(tmp_path,
+ hash_size ? hash_size : tdb_hash_size(src_tdb),
+ TDB_DEFAULT, O_RDWR | O_CREAT | O_EXCL,
+ st.st_mode & 0777);
+ if (dst_tdb == NULL) {
+ DEBUG(3, ("Error creating tdb '%s': %s\n", tmp_path,
+ strerror(errno)));
+ saved_errno = errno;
+ unlink(tmp_path);
+ goto done;
+ }
+
+ count1 = tdb_copy(src_tdb, dst_tdb);
+ if (count1 < 0) {
+ DEBUG(3, ("Failed to copy tdb '%s': %s\n", src_path,
+ strerror(errno)));
+ tdb_close(dst_tdb);
+ goto done;
+ }
+
+ /* reopen ro and do basic verification */
+ tdb_close(dst_tdb);
+ dst_tdb = tdb_open_log(tmp_path, 0, TDB_DEFAULT, O_RDONLY, 0);
+ if (!dst_tdb) {
+ DEBUG(3, ("Failed to reopen tdb '%s': %s\n", tmp_path,
+ strerror(errno)));
+ goto done;
+ }
+ count2 = tdb_verify_basic(dst_tdb);
+ if (count2 != count1) {
+ DEBUG(3, ("Failed to verify result of copying tdb '%s'.\n",
+ src_path));
+ tdb_close(dst_tdb);
+ goto done;
+ }
+
+ DEBUG(10, ("tdb_backup: successfully copied %d entries\n", count1));
+
+ /* make sure the new tdb has reached stable storage
+ * then rename it to its destination */
+ fsync(tdb_fd(dst_tdb));
+ tdb_close(dst_tdb);
+ unlink(dst_path);
+ if (rename(tmp_path, dst_path) != 0) {
+ DEBUG(3, ("Failed to rename '%s' to '%s': %s\n",
+ tmp_path, dst_path, strerror(errno)));
+ goto done;
+ }
+
+ /* success */
+ ret = 0;
+
+done:
+ if (src_tdb != NULL) {
+ tdb_close(src_tdb);
+ }
+ if (tmp_path != NULL) {
+ unlink(tmp_path);
+ TALLOC_FREE(tmp_path);
+ }
+ if (saved_errno != 0) {
+ errno = saved_errno;
+ }
+ return ret;
+}
+
+static int rename_file_with_suffix(TALLOC_CTX *ctx, const char *path,
+ const char *suffix)
+{
+ int ret = -1;
+ char *dst_path;
+
+ dst_path = talloc_asprintf(ctx, "%s%s", path, suffix);
+
+ ret = (rename(path, dst_path) != 0);
+
+ if (ret == 0) {
+ DEBUG(5, ("moved '%s' to '%s'\n", path, dst_path));
+ } else if (errno == ENOENT) {
+ DEBUG(3, ("file '%s' does not exist - so not moved\n", path));
+ ret = 0;
+ } else {
+ DEBUG(3, ("error renaming %s to %s: %s\n", path, dst_path,
+ strerror(errno)));
+ }
+
+ TALLOC_FREE(dst_path);
+ return ret;
+}
+
+/*
+ * do a backup of a tdb, moving the destination out of the way first
+ */
+static int tdb_backup_with_rotate(TALLOC_CTX *ctx, const char *src_path,
+ const char *dst_path, int hash_size,
+ const char *rotate_suffix,
+ bool retry_norotate_if_nospc,
+ bool rename_as_last_resort_if_nospc)
+{
+ int ret;
+
+ rename_file_with_suffix(ctx, dst_path, rotate_suffix);
+
+ ret = tdb_backup(ctx, src_path, dst_path, hash_size);
+
+ if (ret != 0) {
+ DEBUG(10, ("backup of %s failed: %s\n", src_path, strerror(errno)));
+ }
+ if ((ret != 0) && (errno == ENOSPC) && retry_norotate_if_nospc)
+ {
+ char *rotate_path = talloc_asprintf(ctx, "%s%s", dst_path,
+ rotate_suffix);
+ DEBUG(10, ("backup of %s failed due to lack of space\n",
+ src_path));
+ DEBUGADD(10, ("trying to free some space by removing rotated "
+ "dst %s\n", rotate_path));
+ if (unlink(rotate_path) == -1) {
+ DEBUG(10, ("unlink of %s failed: %s\n", rotate_path,
+ strerror(errno)));
+ } else {
+ ret = tdb_backup(ctx, src_path, dst_path, hash_size);
+ }
+ TALLOC_FREE(rotate_path);
+ }
+
+ if ((ret != 0) && (errno == ENOSPC) && rename_as_last_resort_if_nospc)
+ {
+ DEBUG(10, ("backup of %s failed due to lack of space\n",
+ src_path));
+ DEBUGADD(10, ("using 'rename' as a last resort\n"));
+ ret = rename(src_path, dst_path);
+ }
+
+ return ret;
+}
+
+/*
+ * validation function with backup handling:
+ *
+ * - calls tdb_validate
+ * - if the tdb is ok, create a backup "name.bak", possibly moving
+ * existing backup to name.bak.old,
+ * return 0 (success) even if the backup fails
+ * - if the tdb is corrupt:
+ * - move the tdb to "name.corrupt"
+ * - check if there is valid backup.
+ * if so, restore the backup.
+ * if restore is successful, return 0 (success),
+ * - otherwise return -1 (failure)
+ */
+int tdb_validate_and_backup(const char *tdb_path,
+ tdb_validate_data_func validate_fn)
+{
+ int ret = -1;
+ const char *backup_suffix = ".bak";
+ const char *corrupt_suffix = ".corrupt";
+ const char *rotate_suffix = ".old";
+ char *tdb_path_backup;
+ struct stat st;
+ TALLOC_CTX *ctx = NULL;
+
+ ctx = talloc_new(NULL);
+ if (ctx == NULL) {
+ DEBUG(0, ("tdb_validate_and_backup: out of memory\n"));
+ goto done;
+ }
+
+ tdb_path_backup = talloc_asprintf(ctx, "%s%s", tdb_path, backup_suffix);
+
+ ret = tdb_validate_open(tdb_path, validate_fn);
+
+ if (ret == 0) {
+ DEBUG(1, ("tdb '%s' is valid\n", tdb_path));
+ ret = tdb_backup_with_rotate(ctx, tdb_path, tdb_path_backup, 0,
+ rotate_suffix, True, False);
+ if (ret != 0) {
+ DEBUG(1, ("Error creating backup of tdb '%s'\n",
+ tdb_path));
+ /* the actual validation was successful: */
+ ret = 0;
+ } else {
+ DEBUG(1, ("Created backup '%s' of tdb '%s'\n",
+ tdb_path_backup, tdb_path));
+ }
+ } else {
+ DEBUG(1, ("tdb '%s' is invalid\n", tdb_path));
+
+ ret =stat(tdb_path_backup, &st);
+ if (ret != 0) {
+ DEBUG(5, ("Could not stat '%s': %s\n", tdb_path_backup,
+ strerror(errno)));
+ DEBUG(1, ("No backup found.\n"));
+ } else {
+ DEBUG(1, ("backup '%s' found.\n", tdb_path_backup));
+ ret = tdb_validate_open(tdb_path_backup, validate_fn);
+ if (ret != 0) {
+ DEBUG(1, ("Backup '%s' is invalid.\n",
+ tdb_path_backup));
+ }
+ }
+
+ if (ret != 0) {
+ int renamed = rename_file_with_suffix(ctx, tdb_path,
+ corrupt_suffix);
+ if (renamed != 0) {
+ DEBUG(1, ("Error moving tdb to '%s%s'\n",
+ tdb_path, corrupt_suffix));
+ } else {
+ DEBUG(1, ("Corrupt tdb stored as '%s%s'\n",
+ tdb_path, corrupt_suffix));
+ }
+ goto done;
+ }
+
+ DEBUG(1, ("valid backup '%s' found\n", tdb_path_backup));
+ ret = tdb_backup_with_rotate(ctx, tdb_path_backup, tdb_path, 0,
+ corrupt_suffix, True, True);
+ if (ret != 0) {
+ DEBUG(1, ("Error restoring backup from '%s'\n",
+ tdb_path_backup));
+ } else {
+ DEBUG(1, ("Restored tdb backup from '%s'\n",
+ tdb_path_backup));
+ }
+ }
+
+done:
+ TALLOC_FREE(ctx);
+ return ret;
+}
diff --git a/source3/lib/util_transfer_file.c b/source3/lib/util_transfer_file.c
new file mode 100644
index 0000000000..1e3b76fc77
--- /dev/null
+++ b/source3/lib/util_transfer_file.c
@@ -0,0 +1,110 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Utility functions to transfer files.
+ *
+ * Copyright (C) Jeremy Allison 2001-2002
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <includes.h>
+
+/****************************************************************************
+ Transfer some data between two fd's.
+****************************************************************************/
+
+#ifndef TRANSFER_BUF_SIZE
+#define TRANSFER_BUF_SIZE 65536
+#endif
+
+
+ssize_t transfer_file_internal(void *in_file,
+ void *out_file,
+ size_t n,
+ ssize_t (*read_fn)(void *, void *, size_t),
+ ssize_t (*write_fn)(void *, const void *, size_t))
+{
+ char *buf;
+ size_t total = 0;
+ ssize_t read_ret;
+ ssize_t write_ret;
+ size_t num_to_read_thistime;
+ size_t num_written = 0;
+
+ if ((buf = SMB_MALLOC_ARRAY(char, TRANSFER_BUF_SIZE)) == NULL) {
+ return -1;
+ }
+
+ while (total < n) {
+ num_to_read_thistime = MIN((n - total), TRANSFER_BUF_SIZE);
+
+ read_ret = (*read_fn)(in_file, buf, num_to_read_thistime);
+ if (read_ret == -1) {
+ DEBUG(0,("transfer_file_internal: read failure. "
+ "Error = %s\n", strerror(errno) ));
+ SAFE_FREE(buf);
+ return -1;
+ }
+ if (read_ret == 0) {
+ break;
+ }
+
+ num_written = 0;
+
+ while (num_written < read_ret) {
+ write_ret = (*write_fn)(out_file, buf + num_written,
+ read_ret - num_written);
+
+ if (write_ret == -1) {
+ DEBUG(0,("transfer_file_internal: "
+ "write failure. Error = %s\n",
+ strerror(errno) ));
+ SAFE_FREE(buf);
+ return -1;
+ }
+ if (write_ret == 0) {
+ return (ssize_t)total;
+ }
+
+ num_written += (size_t)write_ret;
+ }
+
+ total += (size_t)read_ret;
+ }
+
+ SAFE_FREE(buf);
+ return (ssize_t)total;
+}
+
+static ssize_t sys_read_fn(void *file, void *buf, size_t len)
+{
+ int *fd = (int *)file;
+
+ return sys_read(*fd, buf, len);
+}
+
+static ssize_t sys_write_fn(void *file, const void *buf, size_t len)
+{
+ int *fd = (int *)file;
+
+ return sys_write(*fd, buf, len);
+}
+
+SMB_OFF_T transfer_file(int infd, int outfd, SMB_OFF_T n)
+{
+ return (SMB_OFF_T)transfer_file_internal(&infd, &outfd, (size_t)n,
+ sys_read_fn, sys_write_fn);
+}
diff --git a/source3/lib/util_unistr.c b/source3/lib/util_unistr.c
new file mode 100644
index 0000000000..4e78d1b064
--- /dev/null
+++ b/source3/lib/util_unistr.c
@@ -0,0 +1,1104 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Jeremy Allison 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifndef MAXUNI
+#define MAXUNI 1024
+#endif
+
+/* these 3 tables define the unicode case handling. They are loaded
+ at startup either via mmap() or read() from the lib directory */
+static smb_ucs2_t *upcase_table;
+static smb_ucs2_t *lowcase_table;
+static uint8 *valid_table;
+static bool upcase_table_use_unmap;
+static bool lowcase_table_use_unmap;
+static bool valid_table_use_unmap;
+static bool initialized;
+
+/**
+ * Destroy global objects allocated by load_case_tables()
+ **/
+void gfree_case_tables(void)
+{
+ if ( upcase_table ) {
+ if ( upcase_table_use_unmap )
+ unmap_file(upcase_table, 0x20000);
+ else
+ SAFE_FREE(upcase_table);
+ }
+
+ if ( lowcase_table ) {
+ if ( lowcase_table_use_unmap )
+ unmap_file(lowcase_table, 0x20000);
+ else
+ SAFE_FREE(lowcase_table);
+ }
+
+ if ( valid_table ) {
+ if ( valid_table_use_unmap )
+ unmap_file(valid_table, 0x10000);
+ else
+ SAFE_FREE(valid_table);
+ }
+ initialized = false;
+}
+
+/**
+ * Load or generate the case handling tables.
+ *
+ * The case tables are defined in UCS2 and don't depend on any
+ * configured parameters, so they never need to be reloaded.
+ **/
+
+void load_case_tables(void)
+{
+ char *old_locale = NULL, *saved_locale = NULL;
+ int i;
+ TALLOC_CTX *frame = NULL;
+
+ if (initialized) {
+ return;
+ }
+ initialized = true;
+
+ frame = talloc_stackframe();
+
+ upcase_table = (smb_ucs2_t *)map_file(data_path("upcase.dat"),
+ 0x20000);
+ upcase_table_use_unmap = ( upcase_table != NULL );
+
+ lowcase_table = (smb_ucs2_t *)map_file(data_path("lowcase.dat"),
+ 0x20000);
+ lowcase_table_use_unmap = ( lowcase_table != NULL );
+
+#ifdef HAVE_SETLOCALE
+ /* Get the name of the current locale. */
+ old_locale = setlocale(LC_ALL, NULL);
+
+ if (old_locale) {
+ /* Save it as it is in static storage. */
+ saved_locale = SMB_STRDUP(old_locale);
+ }
+
+ /* We set back the locale to C to get ASCII-compatible toupper/lower functions. */
+ setlocale(LC_ALL, "C");
+#endif
+
+ /* we would like Samba to limp along even if these tables are
+ not available */
+ if (!upcase_table) {
+ DEBUG(1,("creating lame upcase table\n"));
+ upcase_table = (smb_ucs2_t *)SMB_MALLOC(0x20000);
+ for (i=0;i<0x10000;i++) {
+ smb_ucs2_t v;
+ SSVAL(&v, 0, i);
+ upcase_table[v] = i;
+ }
+ for (i=0;i<256;i++) {
+ smb_ucs2_t v;
+ SSVAL(&v, 0, UCS2_CHAR(i));
+ upcase_table[v] = UCS2_CHAR(islower(i)?toupper(i):i);
+ }
+ }
+
+ if (!lowcase_table) {
+ DEBUG(1,("creating lame lowcase table\n"));
+ lowcase_table = (smb_ucs2_t *)SMB_MALLOC(0x20000);
+ for (i=0;i<0x10000;i++) {
+ smb_ucs2_t v;
+ SSVAL(&v, 0, i);
+ lowcase_table[v] = i;
+ }
+ for (i=0;i<256;i++) {
+ smb_ucs2_t v;
+ SSVAL(&v, 0, UCS2_CHAR(i));
+ lowcase_table[v] = UCS2_CHAR(isupper(i)?tolower(i):i);
+ }
+ }
+
+#ifdef HAVE_SETLOCALE
+ /* Restore the old locale. */
+ if (saved_locale) {
+ setlocale (LC_ALL, saved_locale);
+ SAFE_FREE(saved_locale);
+ }
+#endif
+ TALLOC_FREE(frame);
+}
+
+static int check_dos_char_slowly(smb_ucs2_t c)
+{
+ char buf[10];
+ smb_ucs2_t c2 = 0;
+ int len1, len2;
+
+ len1 = convert_string(CH_UTF16LE, CH_DOS, &c, 2, buf, sizeof(buf),False);
+ if (len1 == 0) {
+ return 0;
+ }
+ len2 = convert_string(CH_DOS, CH_UTF16LE, buf, len1, &c2, 2,False);
+ if (len2 != 2) {
+ return 0;
+ }
+ return (c == c2);
+}
+
+/**
+ * Load the valid character map table from <tt>valid.dat</tt> or
+ * create from the configured codepage.
+ *
+ * This function is called whenever the configuration is reloaded.
+ * However, the valid character table is not changed if it's loaded
+ * from a file, because we can't unmap files.
+ **/
+
+void init_valid_table(void)
+{
+ static int mapped_file;
+ int i;
+ const char *allowed = ".!#$%&'()_-@^`~";
+ uint8 *valid_file;
+
+ if (mapped_file) {
+ /* Can't unmap files, so stick with what we have */
+ return;
+ }
+
+ valid_file = (uint8 *)map_file(data_path("valid.dat"), 0x10000);
+ if (valid_file) {
+ valid_table = valid_file;
+ mapped_file = 1;
+ valid_table_use_unmap = True;
+ return;
+ }
+
+ /* Otherwise, we're using a dynamically created valid_table.
+ * It might need to be regenerated if the code page changed.
+ * We know that we're not using a mapped file, so we can
+ * free() the old one. */
+ SAFE_FREE(valid_table);
+
+ /* use free rather than unmap */
+ valid_table_use_unmap = False;
+
+ DEBUG(2,("creating default valid table\n"));
+ valid_table = (uint8 *)SMB_MALLOC(0x10000);
+ SMB_ASSERT(valid_table != NULL);
+ for (i=0;i<128;i++) {
+ valid_table[i] = isalnum(i) || strchr(allowed,i);
+ }
+
+ lazy_initialize_conv();
+
+ for (;i<0x10000;i++) {
+ smb_ucs2_t c;
+ SSVAL(&c, 0, i);
+ valid_table[i] = check_dos_char_slowly(c);
+ }
+}
+
+/*******************************************************************
+ Write a string in (little-endian) unicode format. src is in
+ the current DOS codepage. len is the length in bytes of the
+ string pointed to by dst.
+
+ if null_terminate is True then null terminate the packet (adds 2 bytes)
+
+ the return value is the length in bytes consumed by the string, including the
+ null termination if applied
+********************************************************************/
+
+size_t dos_PutUniCode(char *dst,const char *src, size_t len, bool null_terminate)
+{
+ int flags = null_terminate ? STR_UNICODE|STR_NOALIGN|STR_TERMINATE
+ : STR_UNICODE|STR_NOALIGN;
+ return push_ucs2(NULL, dst, src, len, flags);
+}
+
+
+/*******************************************************************
+ Skip past a unicode string, but not more than len. Always move
+ past a terminating zero if found.
+********************************************************************/
+
+char *skip_unibuf(char *src, size_t len)
+{
+ char *srcend = src + len;
+
+ while (src < srcend && SVAL(src,0)) {
+ src += 2;
+ }
+
+ if(!SVAL(src,0)) {
+ src += 2;
+ }
+
+ return src;
+}
+
+/* Copy a string from little-endian or big-endian unicode source (depending
+ * on flags) to internal samba format destination
+ */
+
+int rpcstr_pull(char* dest, void *src, int dest_len, int src_len, int flags)
+{
+ if (!src) {
+ dest[0] = 0;
+ return 0;
+ }
+ if(dest_len==-1) {
+ dest_len=MAXUNI-3;
+ }
+ return pull_ucs2(NULL, dest, src, dest_len, src_len, flags|STR_UNICODE|STR_NOALIGN);
+}
+
+/* Copy a string from little-endian or big-endian unicode source (depending
+ * on flags) to internal samba format destination. Allocates on talloc ctx.
+ */
+
+int rpcstr_pull_talloc(TALLOC_CTX *ctx,
+ char **dest,
+ void *src,
+ int src_len,
+ int flags)
+{
+ return pull_ucs2_base_talloc(ctx,
+ NULL,
+ dest,
+ src,
+ src_len,
+ flags|STR_UNICODE|STR_NOALIGN);
+
+}
+
+/* Copy a string from a unistr2 source to internal samba format
+ destination. Use this instead of direct calls to rpcstr_pull() to avoid
+ having to determine whether the source string is null terminated. */
+
+int rpcstr_pull_unistr2_fstring(char *dest, UNISTR2 *src)
+{
+ return pull_ucs2(NULL, dest, src->buffer, sizeof(fstring),
+ src->uni_str_len * 2, 0);
+}
+
+/* Helper function to return a talloc'ed string. I have implemented it with a
+ * copy because I don't really know how pull_ucs2 and friends calculate the
+ * target size. If this turns out to be a major bottleneck someone with deeper
+ * multi-byte knowledge needs to revisit this.
+ * I just did (JRA :-). No longer uses copy.
+ * My (VL) use is dsr_getdcname, which returns 6 strings, the alternative would
+ * have been to manually talloc_strdup them in rpc_client/cli_netlogon.c.
+ */
+
+char *rpcstr_pull_unistr2_talloc(TALLOC_CTX *ctx, const UNISTR2 *src)
+{
+ char *dest = NULL;
+ size_t dest_len;
+
+ if (!convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX, src->buffer,
+ src->uni_str_len * 2, (void *)&dest,
+ &dest_len, true))
+ {
+ return NULL;
+ }
+
+ /* Ensure we're returning a null terminated string. */
+ if (dest_len) {
+ /* Did we already process the terminating zero ? */
+ if (dest[dest_len-1] != 0) {
+ size_t size = talloc_get_size(dest);
+ /* Have we got space to append the '\0' ? */
+ if (size <= dest_len) {
+ /* No, realloc. */
+ dest = TALLOC_REALLOC_ARRAY(ctx, dest, char,
+ dest_len+1);
+ if (!dest) {
+ /* talloc fail. */
+ dest_len = (size_t)-1;
+ return NULL;
+ }
+ }
+ /* Yay - space ! */
+ dest[dest_len] = '\0';
+ dest_len++;
+ }
+ } else if (dest) {
+ dest[0] = 0;
+ }
+
+ return dest;
+}
+
+/* Converts a string from internal samba format to unicode
+ */
+
+int rpcstr_push(void *dest, const char *src, size_t dest_len, int flags)
+{
+ return push_ucs2(NULL, dest, src, dest_len, flags|STR_UNICODE|STR_NOALIGN);
+}
+
+/* Converts a string from internal samba format to unicode. Always terminates.
+ * Actually just a wrapper round push_ucs2_talloc().
+ */
+
+int rpcstr_push_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src)
+{
+ size_t size;
+ if (push_ucs2_talloc(ctx, dest, src, &size))
+ return size;
+ else
+ return -1;
+}
+
+/*******************************************************************
+ Convert a (little-endian) UNISTR2 structure to an ASCII string.
+********************************************************************/
+
+void unistr2_to_ascii(char *dest, const UNISTR2 *str, size_t maxlen)
+{
+ if ((str == NULL) || (str->uni_str_len == 0)) {
+ *dest='\0';
+ return;
+ }
+ pull_ucs2(NULL, dest, str->buffer, maxlen, str->uni_str_len*2, STR_NOALIGN);
+}
+
+#if 0
+/*******************************************************************
+ Convert a (little-endian) UNISTR3 structure to an ASCII string.
+********************************************************************/
+
+void unistr3_to_ascii(char *dest, const UNISTR3 *str, size_t maxlen)
+{
+ if ((str == NULL) || (str->uni_str_len == 0)) {
+ *dest='\0';
+ return;
+ }
+ pull_ucs2(NULL, dest, str->str.buffer, maxlen, str->uni_str_len*2,
+ STR_NOALIGN);
+}
+#endif
+
+/*******************************************************************
+ Duplicate a UNISTR2 string into a null terminated char*
+ using a talloc context.
+********************************************************************/
+
+char *unistr2_to_ascii_talloc(TALLOC_CTX *ctx, const UNISTR2 *str)
+{
+ char *s = NULL;
+
+ if (!str || !str->buffer) {
+ return NULL;
+ }
+ if (pull_ucs2_base_talloc(ctx,
+ NULL,
+ &s,
+ str->buffer,
+ str->uni_str_len*2,
+ STR_NOALIGN) == (size_t)-1) {
+ return NULL;
+ }
+ return s;
+}
+
+/*******************************************************************
+ Return a string for displaying a UNISTR2. Guarentees to return a
+ valid string - "" if nothing else.
+ Changed to use talloc_tos() under the covers.... JRA.
+********************************************************************/
+
+const char *unistr2_static(const UNISTR2 *str)
+{
+ char *dest = NULL;
+
+ if ((str == NULL) || (str->uni_str_len == 0)) {
+ return "";
+ }
+
+ dest = unistr2_to_ascii_talloc(talloc_tos(), str);
+ if (!dest) {
+ return "";
+ }
+
+ return dest;
+}
+
+/*******************************************************************
+ Convert a wchar to upper case.
+********************************************************************/
+
+smb_ucs2_t toupper_w(smb_ucs2_t val)
+{
+ return upcase_table[SVAL(&val,0)];
+}
+
+/*******************************************************************
+ Convert a wchar to lower case.
+********************************************************************/
+
+smb_ucs2_t tolower_w( smb_ucs2_t val )
+{
+ return lowcase_table[SVAL(&val,0)];
+}
+
+/*******************************************************************
+ Determine if a character is lowercase.
+********************************************************************/
+
+bool islower_w(smb_ucs2_t c)
+{
+ return upcase_table[SVAL(&c,0)] != c;
+}
+
+/*******************************************************************
+ Determine if a character is uppercase.
+********************************************************************/
+
+bool isupper_w(smb_ucs2_t c)
+{
+ return lowcase_table[SVAL(&c,0)] != c;
+}
+
+/*******************************************************************
+ Determine if a character is valid in a 8.3 name.
+********************************************************************/
+
+bool isvalid83_w(smb_ucs2_t c)
+{
+ return valid_table[SVAL(&c,0)] != 0;
+}
+
+/*******************************************************************
+ Count the number of characters in a smb_ucs2_t string.
+********************************************************************/
+
+size_t strlen_w(const smb_ucs2_t *src)
+{
+ size_t len;
+ smb_ucs2_t c;
+
+ for(len = 0; *(COPY_UCS2_CHAR(&c,src)); src++, len++) {
+ ;
+ }
+
+ return len;
+}
+
+/*******************************************************************
+ Count up to max number of characters in a smb_ucs2_t string.
+********************************************************************/
+
+size_t strnlen_w(const smb_ucs2_t *src, size_t max)
+{
+ size_t len;
+ smb_ucs2_t c;
+
+ for(len = 0; (len < max) && *(COPY_UCS2_CHAR(&c,src)); src++, len++) {
+ ;
+ }
+
+ return len;
+}
+
+/*******************************************************************
+ Wide strchr().
+********************************************************************/
+
+smb_ucs2_t *strchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
+{
+ smb_ucs2_t cp;
+ while (*(COPY_UCS2_CHAR(&cp,s))) {
+ if (c == cp) {
+ return (smb_ucs2_t *)s;
+ }
+ s++;
+ }
+ if (c == cp) {
+ return (smb_ucs2_t *)s;
+ }
+
+ return NULL;
+}
+
+smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c)
+{
+ return strchr_w(s, UCS2_CHAR(c));
+}
+
+/*******************************************************************
+ Wide strrchr().
+********************************************************************/
+
+smb_ucs2_t *strrchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
+{
+ smb_ucs2_t cp;
+ const smb_ucs2_t *p = s;
+ int len = strlen_w(s);
+
+ if (len == 0) {
+ return NULL;
+ }
+ p += (len - 1);
+ do {
+ if (c == *(COPY_UCS2_CHAR(&cp,p))) {
+ return (smb_ucs2_t *)p;
+ }
+ } while (p-- != s);
+ return NULL;
+}
+
+/*******************************************************************
+ Wide version of strrchr that returns after doing strrchr 'n' times.
+********************************************************************/
+
+smb_ucs2_t *strnrchr_w(const smb_ucs2_t *s, smb_ucs2_t c, unsigned int n)
+{
+ smb_ucs2_t cp;
+ const smb_ucs2_t *p = s;
+ int len = strlen_w(s);
+
+ if (len == 0 || !n) {
+ return NULL;
+ }
+ p += (len - 1);
+ do {
+ if (c == *(COPY_UCS2_CHAR(&cp,p))) {
+ n--;
+ }
+
+ if (!n) {
+ return (smb_ucs2_t *)p;
+ }
+ } while (p-- != s);
+ return NULL;
+}
+
+/*******************************************************************
+ Wide strstr().
+********************************************************************/
+
+smb_ucs2_t *strstr_w(const smb_ucs2_t *s, const smb_ucs2_t *ins)
+{
+ smb_ucs2_t *r;
+ size_t inslen;
+
+ if (!s || !*s || !ins || !*ins) {
+ return NULL;
+ }
+
+ inslen = strlen_w(ins);
+ r = (smb_ucs2_t *)s;
+
+ while ((r = strchr_w(r, *ins))) {
+ if (strncmp_w(r, ins, inslen) == 0) {
+ return r;
+ }
+ r++;
+ }
+
+ return NULL;
+}
+
+/*******************************************************************
+ Convert a string to lower case.
+ return True if any char is converted
+********************************************************************/
+
+bool strlower_w(smb_ucs2_t *s)
+{
+ smb_ucs2_t cp;
+ bool ret = False;
+
+ while (*(COPY_UCS2_CHAR(&cp,s))) {
+ smb_ucs2_t v = tolower_w(cp);
+ if (v != cp) {
+ COPY_UCS2_CHAR(s,&v);
+ ret = True;
+ }
+ s++;
+ }
+ return ret;
+}
+
+/*******************************************************************
+ Convert a string to upper case.
+ return True if any char is converted
+********************************************************************/
+
+bool strupper_w(smb_ucs2_t *s)
+{
+ smb_ucs2_t cp;
+ bool ret = False;
+ while (*(COPY_UCS2_CHAR(&cp,s))) {
+ smb_ucs2_t v = toupper_w(cp);
+ if (v != cp) {
+ COPY_UCS2_CHAR(s,&v);
+ ret = True;
+ }
+ s++;
+ }
+ return ret;
+}
+
+/*******************************************************************
+ Convert a string to "normal" form.
+********************************************************************/
+
+void strnorm_w(smb_ucs2_t *s, int case_default)
+{
+ if (case_default == CASE_UPPER) {
+ strupper_w(s);
+ } else {
+ strlower_w(s);
+ }
+}
+
+int strcmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
+{
+ smb_ucs2_t cpa, cpb;
+
+ while ((*(COPY_UCS2_CHAR(&cpb,b))) && (*(COPY_UCS2_CHAR(&cpa,a)) == cpb)) {
+ a++;
+ b++;
+ }
+ return (*(COPY_UCS2_CHAR(&cpa,a)) - *(COPY_UCS2_CHAR(&cpb,b)));
+ /* warning: if *a != *b and both are not 0 we return a random
+ greater or lesser than 0 number not realted to which
+ string is longer */
+}
+
+int strncmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len)
+{
+ smb_ucs2_t cpa, cpb;
+ size_t n = 0;
+
+ while ((n < len) && (*(COPY_UCS2_CHAR(&cpb,b))) && (*(COPY_UCS2_CHAR(&cpa,a)) == cpb)) {
+ a++;
+ b++;
+ n++;
+ }
+ return (len - n)?(*(COPY_UCS2_CHAR(&cpa,a)) - *(COPY_UCS2_CHAR(&cpb,b))):0;
+}
+
+/*******************************************************************
+ Case insensitive string comparison.
+********************************************************************/
+
+int strcasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
+{
+ smb_ucs2_t cpa, cpb;
+
+ while ((*COPY_UCS2_CHAR(&cpb,b)) && toupper_w(*(COPY_UCS2_CHAR(&cpa,a))) == toupper_w(cpb)) {
+ a++;
+ b++;
+ }
+ return (tolower_w(*(COPY_UCS2_CHAR(&cpa,a))) - tolower_w(*(COPY_UCS2_CHAR(&cpb,b))));
+}
+
+/*******************************************************************
+ Case insensitive string comparison, length limited.
+********************************************************************/
+
+int strncasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len)
+{
+ smb_ucs2_t cpa, cpb;
+ size_t n = 0;
+
+ while ((n < len) && *COPY_UCS2_CHAR(&cpb,b) && (toupper_w(*(COPY_UCS2_CHAR(&cpa,a))) == toupper_w(cpb))) {
+ a++;
+ b++;
+ n++;
+ }
+ return (len - n)?(tolower_w(*(COPY_UCS2_CHAR(&cpa,a))) - tolower_w(*(COPY_UCS2_CHAR(&cpb,b)))):0;
+}
+
+/*******************************************************************
+ Compare 2 strings.
+********************************************************************/
+
+bool strequal_w(const smb_ucs2_t *s1, const smb_ucs2_t *s2)
+{
+ if (s1 == s2) {
+ return(True);
+ }
+ if (!s1 || !s2) {
+ return(False);
+ }
+
+ return(strcasecmp_w(s1,s2)==0);
+}
+
+/*******************************************************************
+ Compare 2 strings up to and including the nth char.
+******************************************************************/
+
+bool strnequal_w(const smb_ucs2_t *s1,const smb_ucs2_t *s2,size_t n)
+{
+ if (s1 == s2) {
+ return(True);
+ }
+ if (!s1 || !s2 || !n) {
+ return(False);
+ }
+
+ return(strncasecmp_w(s1,s2,n)==0);
+}
+
+/*******************************************************************
+ Duplicate string.
+********************************************************************/
+
+smb_ucs2_t *strdup_w(const smb_ucs2_t *src)
+{
+ return strndup_w(src, 0);
+}
+
+/* if len == 0 then duplicate the whole string */
+
+smb_ucs2_t *strndup_w(const smb_ucs2_t *src, size_t len)
+{
+ smb_ucs2_t *dest;
+
+ if (!len) {
+ len = strlen_w(src);
+ }
+ dest = SMB_MALLOC_ARRAY(smb_ucs2_t, len + 1);
+ if (!dest) {
+ DEBUG(0,("strdup_w: out of memory!\n"));
+ return NULL;
+ }
+
+ memcpy(dest, src, len * sizeof(smb_ucs2_t));
+ dest[len] = 0;
+ return dest;
+}
+
+/*******************************************************************
+ Copy a string with max len.
+********************************************************************/
+
+smb_ucs2_t *strncpy_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
+{
+ smb_ucs2_t cp;
+ size_t len;
+
+ if (!dest || !src) {
+ return NULL;
+ }
+
+ for (len = 0; (*COPY_UCS2_CHAR(&cp,(src+len))) && (len < max); len++) {
+ cp = *COPY_UCS2_CHAR(dest+len,src+len);
+ }
+ cp = 0;
+ for ( /*nothing*/ ; len < max; len++ ) {
+ cp = *COPY_UCS2_CHAR(dest+len,&cp);
+ }
+
+ return dest;
+}
+
+/*******************************************************************
+ Append a string of len bytes and add a terminator.
+********************************************************************/
+
+smb_ucs2_t *strncat_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
+{
+ size_t start;
+ size_t len;
+ smb_ucs2_t z = 0;
+
+ if (!dest || !src) {
+ return NULL;
+ }
+
+ start = strlen_w(dest);
+ len = strnlen_w(src, max);
+
+ memcpy(&dest[start], src, len*sizeof(smb_ucs2_t));
+ z = *COPY_UCS2_CHAR(dest+start+len,&z);
+
+ return dest;
+}
+
+smb_ucs2_t *strcat_w(smb_ucs2_t *dest, const smb_ucs2_t *src)
+{
+ size_t start;
+ size_t len;
+ smb_ucs2_t z = 0;
+
+ if (!dest || !src) {
+ return NULL;
+ }
+
+ start = strlen_w(dest);
+ len = strlen_w(src);
+
+ memcpy(&dest[start], src, len*sizeof(smb_ucs2_t));
+ z = *COPY_UCS2_CHAR(dest+start+len,&z);
+
+ return dest;
+}
+
+
+/*******************************************************************
+ Replace any occurence of oldc with newc in unicode string.
+********************************************************************/
+
+void string_replace_w(smb_ucs2_t *s, smb_ucs2_t oldc, smb_ucs2_t newc)
+{
+ smb_ucs2_t cp;
+
+ for(;*(COPY_UCS2_CHAR(&cp,s));s++) {
+ if(cp==oldc) {
+ COPY_UCS2_CHAR(s,&newc);
+ }
+ }
+}
+
+/*******************************************************************
+ Trim unicode string.
+********************************************************************/
+
+bool trim_string_w(smb_ucs2_t *s, const smb_ucs2_t *front,
+ const smb_ucs2_t *back)
+{
+ bool ret = False;
+ size_t len, front_len, back_len;
+
+ if (!s) {
+ return False;
+ }
+
+ len = strlen_w(s);
+
+ if (front && *front) {
+ front_len = strlen_w(front);
+ while (len && strncmp_w(s, front, front_len) == 0) {
+ memmove(s, (s + front_len), (len - front_len + 1) * sizeof(smb_ucs2_t));
+ len -= front_len;
+ ret = True;
+ }
+ }
+
+ if (back && *back) {
+ back_len = strlen_w(back);
+ while (len && strncmp_w((s + (len - back_len)), back, back_len) == 0) {
+ s[len - back_len] = 0;
+ len -= back_len;
+ ret = True;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ The *_wa() functions take a combination of 7 bit ascii
+ and wide characters They are used so that you can use string
+ functions combining C string constants with ucs2 strings
+
+ The char* arguments must NOT be multibyte - to be completely sure
+ of this only pass string constants */
+
+int strcmp_wa(const smb_ucs2_t *a, const char *b)
+{
+ smb_ucs2_t cp = 0;
+
+ while (*b && *(COPY_UCS2_CHAR(&cp,a)) == UCS2_CHAR(*b)) {
+ a++;
+ b++;
+ }
+ return (*(COPY_UCS2_CHAR(&cp,a)) - UCS2_CHAR(*b));
+}
+
+int strncmp_wa(const smb_ucs2_t *a, const char *b, size_t len)
+{
+ smb_ucs2_t cp = 0;
+ size_t n = 0;
+
+ while ((n < len) && *b && *(COPY_UCS2_CHAR(&cp,a)) == UCS2_CHAR(*b)) {
+ a++;
+ b++;
+ n++;
+ }
+ return (len - n)?(*(COPY_UCS2_CHAR(&cp,a)) - UCS2_CHAR(*b)):0;
+}
+
+smb_ucs2_t *strpbrk_wa(const smb_ucs2_t *s, const char *p)
+{
+ smb_ucs2_t cp;
+
+ while (*(COPY_UCS2_CHAR(&cp,s))) {
+ int i;
+ for (i=0; p[i] && cp != UCS2_CHAR(p[i]); i++)
+ ;
+ if (p[i]) {
+ return (smb_ucs2_t *)s;
+ }
+ s++;
+ }
+ return NULL;
+}
+
+smb_ucs2_t *strstr_wa(const smb_ucs2_t *s, const char *ins)
+{
+ smb_ucs2_t *r;
+ size_t inslen;
+
+ if (!s || !ins) {
+ return NULL;
+ }
+
+ inslen = strlen(ins);
+ r = (smb_ucs2_t *)s;
+
+ while ((r = strchr_w(r, UCS2_CHAR(*ins)))) {
+ if (strncmp_wa(r, ins, inslen) == 0)
+ return r;
+ r++;
+ }
+
+ return NULL;
+}
+
+/*******************************************************************
+ Returns the length in number of wide characters.
+******************************************************************/
+
+int unistrlen(uint16 *s)
+{
+ int len;
+
+ if (!s) {
+ return -1;
+ }
+
+ for (len=0; SVAL(s,0); s++,len++) {
+ ;
+ }
+
+ return len;
+}
+
+/*******************************************************************
+ Strcpy for unicode strings. Returns length (in num of wide chars).
+ Not odd align safe.
+********************************************************************/
+
+int unistrcpy(uint16 *dst, uint16 *src)
+{
+ int num_wchars = 0;
+
+ while (SVAL(src,0)) {
+ *dst++ = *src++;
+ num_wchars++;
+ }
+ *dst = 0;
+
+ return num_wchars;
+}
+
+/**
+ * Samba ucs2 type to UNISTR2 conversion
+ *
+ * @param ctx Talloc context to create the dst strcture (if null) and the
+ * contents of the unicode string.
+ * @param dst UNISTR2 destination. If equals null, then it's allocated.
+ * @param src smb_ucs2_t source.
+ * @param max_len maximum number of unicode characters to copy. If equals
+ * null, then null-termination of src is taken
+ *
+ * @return copied UNISTR2 destination
+ **/
+
+UNISTR2* ucs2_to_unistr2(TALLOC_CTX *ctx, UNISTR2* dst, smb_ucs2_t* src)
+{
+ size_t len;
+
+ if (!src) {
+ return NULL;
+ }
+
+ len = strlen_w(src);
+
+ /* allocate UNISTR2 destination if not given */
+ if (!dst) {
+ dst = TALLOC_P(ctx, UNISTR2);
+ if (!dst)
+ return NULL;
+ }
+ if (!dst->buffer) {
+ dst->buffer = TALLOC_ARRAY(ctx, uint16, len + 1);
+ if (!dst->buffer)
+ return NULL;
+ }
+
+ /* set UNISTR2 parameters */
+ dst->uni_max_len = len + 1;
+ dst->offset = 0;
+ dst->uni_str_len = len;
+
+ /* copy the actual unicode string */
+ strncpy_w(dst->buffer, src, dst->uni_max_len);
+
+ return dst;
+}
+
+/*************************************************************
+ ascii only toupper - saves the need for smbd to be in C locale.
+*************************************************************/
+
+int toupper_ascii(int c)
+{
+ smb_ucs2_t uc = toupper_w(UCS2_CHAR(c));
+ return UCS2_TO_CHAR(uc);
+}
+
+/*************************************************************
+ ascii only tolower - saves the need for smbd to be in C locale.
+*************************************************************/
+
+int tolower_ascii(int c)
+{
+ smb_ucs2_t uc = tolower_w(UCS2_CHAR(c));
+ return UCS2_TO_CHAR(uc);
+}
+
+/*************************************************************
+ ascii only isupper - saves the need for smbd to be in C locale.
+*************************************************************/
+
+int isupper_ascii(int c)
+{
+ return isupper_w(UCS2_CHAR(c));
+}
+
+/*************************************************************
+ ascii only islower - saves the need for smbd to be in C locale.
+*************************************************************/
+
+int islower_ascii(int c)
+{
+ return islower_w(UCS2_CHAR(c));
+}
diff --git a/source3/lib/util_uuid.c b/source3/lib/util_uuid.c
new file mode 100644
index 0000000000..3a8f7b3f4f
--- /dev/null
+++ b/source3/lib/util_uuid.c
@@ -0,0 +1,131 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * UUID server routines
+ * Copyright (C) Theodore Ts'o 1996, 1997,
+ * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002, 2003
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/*
+ * Offset between 15-Oct-1582 and 1-Jan-70
+ */
+#define TIME_OFFSET_HIGH 0x01B21DD2
+#define TIME_OFFSET_LOW 0x13814000
+
+void smb_uuid_pack(const struct GUID uu, UUID_FLAT *ptr)
+{
+ SIVAL(ptr->info, 0, uu.time_low);
+ SSVAL(ptr->info, 4, uu.time_mid);
+ SSVAL(ptr->info, 6, uu.time_hi_and_version);
+ memcpy(ptr->info+8, uu.clock_seq, 2);
+ memcpy(ptr->info+10, uu.node, 6);
+}
+
+void smb_uuid_unpack(const UUID_FLAT in, struct GUID *uu)
+{
+ uu->time_low = IVAL(in.info, 0);
+ uu->time_mid = SVAL(in.info, 4);
+ uu->time_hi_and_version = SVAL(in.info, 6);
+ memcpy(uu->clock_seq, in.info+8, 2);
+ memcpy(uu->node, in.info+10, 6);
+}
+
+void smb_uuid_generate_random(struct GUID *uu)
+{
+ UUID_FLAT tmp;
+
+ generate_random_buffer(tmp.info, sizeof(tmp.info));
+ smb_uuid_unpack(tmp, uu);
+
+ uu->clock_seq[0] = (uu->clock_seq[0] & 0x3F) | 0x80;
+ uu->time_hi_and_version = (uu->time_hi_and_version & 0x0FFF) | 0x4000;
+}
+
+const char *smb_uuid_string(TALLOC_CTX *mem_ctx, const struct GUID uu)
+{
+ char *result;
+
+ result = talloc_asprintf(
+ mem_ctx,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ uu.time_low, uu.time_mid, uu.time_hi_and_version,
+ uu.clock_seq[0], uu.clock_seq[1],
+ uu.node[0], uu.node[1], uu.node[2],
+ uu.node[3], uu.node[4], uu.node[5]);
+
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+bool smb_string_to_uuid(const char *in, struct GUID* uu)
+{
+ bool ret = False;
+ const char *ptr = in;
+ char *end = (char *)in;
+ int i;
+ unsigned v1, v2;
+
+ if (!in || !uu) goto out;
+
+ uu->time_low = strtoul(ptr, &end, 16);
+ if ((end - ptr) != 8 || *end != '-') goto out;
+ ptr = (end + 1);
+
+ uu->time_mid = strtoul(ptr, &end, 16);
+ if ((end - ptr) != 4 || *end != '-') goto out;
+ ptr = (end + 1);
+
+ uu->time_hi_and_version = strtoul(ptr, &end, 16);
+ if ((end - ptr) != 4 || *end != '-') goto out;
+ ptr = (end + 1);
+
+ if (sscanf(ptr, "%02x%02x", &v1, &v2) != 2) {
+ goto out;
+ }
+ uu->clock_seq[0] = v1;
+ uu->clock_seq[1] = v2;
+ ptr += 4;
+
+ if (*ptr != '-') goto out;
+ ptr++;
+
+ for (i = 0; i < 6; i++) {
+ if (sscanf(ptr, "%02x", &v1) != 1) {
+ goto out;
+ }
+ uu->node[i] = v1;
+ ptr += 2;
+ }
+
+ ret = True;
+out:
+ return ret;
+}
+
+/*****************************************************************
+ Return the binary string representation of a GUID.
+ Caller must free.
+*****************************************************************/
+
+char *guid_binstring(const struct GUID *guid)
+{
+ UUID_FLAT guid_flat;
+
+ smb_uuid_pack(*guid, &guid_flat);
+
+ return binary_string_rfc2254((char *)guid_flat.info, UUID_FLAT_SIZE);
+}
diff --git a/source3/lib/version.c b/source3/lib/version.c
new file mode 100644
index 0000000000..55fb53c5db
--- /dev/null
+++ b/source3/lib/version.c
@@ -0,0 +1,27 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba Version functions
+
+ Copyright (C) Stefan Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <assert.h>
+
+const char *samba_version_string(void)
+{
+ return SAMBA_VERSION_STRING;
+}
diff --git a/source3/lib/winbind_util.c b/source3/lib/winbind_util.c
new file mode 100644
index 0000000000..14356b09cf
--- /dev/null
+++ b/source3/lib/winbind_util.c
@@ -0,0 +1,321 @@
+/*
+ Unix SMB/CIFS implementation.
+ Winbind Utility functions
+
+ Copyright (C) Gerald (Jerry) Carter 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#if defined(WITH_WINBIND)
+
+#include "nsswitch/libwbclient/wbclient.h"
+
+/* Call winbindd to convert a name to a sid */
+
+bool winbind_lookup_name(const char *dom_name, const char *name, DOM_SID *sid,
+ enum lsa_SidType *name_type)
+{
+ struct wbcDomainSid dom_sid;
+ wbcErr result;
+ enum wbcSidType type;
+
+ result = wbcLookupName(dom_name, name, &dom_sid, &type);
+ if (result != WBC_ERR_SUCCESS)
+ return false;
+
+ memcpy(sid, &dom_sid, sizeof(DOM_SID));
+ *name_type = (enum lsa_SidType)type;
+
+ return true;
+}
+
+/* Call winbindd to convert sid to name */
+
+bool winbind_lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ const char **domain, const char **name,
+ enum lsa_SidType *name_type)
+{
+ struct wbcDomainSid dom_sid;
+ wbcErr result;
+ enum wbcSidType type;
+ char *domain_name = NULL;
+ char *account_name = NULL;
+
+ memcpy(&dom_sid, sid, sizeof(dom_sid));
+
+ result = wbcLookupSid(&dom_sid, &domain_name, &account_name, &type);
+ if (result != WBC_ERR_SUCCESS)
+ return false;
+
+ /* Copy out result */
+
+ if (domain) {
+ *domain = talloc_strdup(mem_ctx, domain_name);
+ }
+ if (name) {
+ *name = talloc_strdup(mem_ctx, account_name);
+ }
+ *name_type = (enum lsa_SidType)type;
+
+ DEBUG(10, ("winbind_lookup_sid: SUCCESS: SID %s -> %s %s\n",
+ sid_string_dbg(sid), domain_name, account_name));
+
+ wbcFreeMemory(domain_name);
+ wbcFreeMemory(account_name);
+
+ if ((domain && !*domain) || (name && !*name)) {
+ DEBUG(0,("winbind_lookup_sid: talloc() failed!\n"));
+ return false;
+ }
+
+
+ return true;
+}
+
+/* Ping winbindd to see it is alive */
+
+bool winbind_ping(void)
+{
+ wbcErr result = wbcPing();
+
+ return (result == WBC_ERR_SUCCESS);
+}
+
+/* Call winbindd to convert SID to uid */
+
+bool winbind_sid_to_uid(uid_t *puid, const DOM_SID *sid)
+{
+ struct wbcDomainSid dom_sid;
+ wbcErr result;
+
+ memcpy(&dom_sid, sid, sizeof(dom_sid));
+
+ result = wbcSidToUid(&dom_sid, puid);
+
+ return (result == WBC_ERR_SUCCESS);
+}
+
+/* Call winbindd to convert uid to sid */
+
+bool winbind_uid_to_sid(DOM_SID *sid, uid_t uid)
+{
+ struct wbcDomainSid dom_sid;
+ wbcErr result;
+
+ result = wbcUidToSid(uid, &dom_sid);
+ if (result == WBC_ERR_SUCCESS) {
+ memcpy(sid, &dom_sid, sizeof(DOM_SID));
+ } else {
+ sid_copy(sid, &global_sid_NULL);
+ }
+
+ return (result == WBC_ERR_SUCCESS);
+}
+
+/* Call winbindd to convert SID to gid */
+
+bool winbind_sid_to_gid(gid_t *pgid, const DOM_SID *sid)
+{
+ struct wbcDomainSid dom_sid;
+ wbcErr result;
+
+ memcpy(&dom_sid, sid, sizeof(dom_sid));
+
+ result = wbcSidToGid(&dom_sid, pgid);
+
+ return (result == WBC_ERR_SUCCESS);
+}
+
+/* Call winbindd to convert gid to sid */
+
+bool winbind_gid_to_sid(DOM_SID *sid, gid_t gid)
+{
+ struct wbcDomainSid dom_sid;
+ wbcErr result;
+
+ result = wbcGidToSid(gid, &dom_sid);
+ if (result == WBC_ERR_SUCCESS) {
+ memcpy(sid, &dom_sid, sizeof(DOM_SID));
+ } else {
+ sid_copy(sid, &global_sid_NULL);
+ }
+
+ return (result == WBC_ERR_SUCCESS);
+}
+
+/* Check for a trusted domain */
+
+wbcErr wb_is_trusted_domain(const char *domain)
+{
+ wbcErr result;
+ struct wbcDomainInfo *info = NULL;
+
+ result = wbcDomainInfo(domain, &info);
+
+ if (WBC_ERROR_IS_OK(result)) {
+ wbcFreeMemory(info);
+ }
+
+ return result;
+}
+
+/* Lookup a set of rids in a given domain */
+
+bool winbind_lookup_rids(TALLOC_CTX *mem_ctx,
+ const DOM_SID *domain_sid,
+ int num_rids, uint32 *rids,
+ const char **domain_name,
+ const char ***names, enum lsa_SidType **types)
+{
+ const char *dom_name = NULL;
+ const char **namelist = NULL;
+ enum wbcSidType *name_types = NULL;
+ struct wbcDomainSid dom_sid;
+ wbcErr ret;
+ int i;
+
+ memcpy(&dom_sid, domain_sid, sizeof(struct wbcDomainSid));
+
+ ret = wbcLookupRids(&dom_sid, num_rids, rids,
+ &dom_name, &namelist, &name_types);
+ if (ret != WBC_ERR_SUCCESS) {
+ return false;
+ }
+
+ *domain_name = talloc_strdup(mem_ctx, dom_name);
+ *names = TALLOC_ARRAY(mem_ctx, const char*, num_rids);
+ *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
+
+ for(i=0; i<num_rids; i++) {
+ (*names)[i] = talloc_strdup(*names, namelist[i]);
+ (*types)[i] = (enum lsa_SidType)name_types[i];
+ }
+
+ wbcFreeMemory(CONST_DISCARD(char*, dom_name));
+ wbcFreeMemory(namelist);
+ wbcFreeMemory(name_types);
+
+ return true;
+}
+
+/* Ask Winbind to allocate a new uid for us */
+
+bool winbind_allocate_uid(uid_t *uid)
+{
+ wbcErr ret;
+
+ ret = wbcAllocateUid(uid);
+
+ return (ret == WBC_ERR_SUCCESS);
+}
+
+/* Ask Winbind to allocate a new gid for us */
+
+bool winbind_allocate_gid(gid_t *gid)
+{
+ wbcErr ret;
+
+ ret = wbcAllocateGid(gid);
+
+ return (ret == WBC_ERR_SUCCESS);
+}
+
+#else /* WITH_WINBIND */
+
+bool winbind_lookup_name(const char *dom_name, const char *name, DOM_SID *sid,
+ enum lsa_SidType *name_type)
+{
+ return false;
+}
+
+/* Call winbindd to convert sid to name */
+
+bool winbind_lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ const char **domain, const char **name,
+ enum lsa_SidType *name_type)
+{
+ return false;
+}
+
+/* Ping winbindd to see it is alive */
+
+bool winbind_ping(void)
+{
+ return false;
+}
+
+/* Call winbindd to convert SID to uid */
+
+bool winbind_sid_to_uid(uid_t *puid, const DOM_SID *sid)
+{
+ return false;
+}
+
+/* Call winbindd to convert uid to sid */
+
+bool winbind_uid_to_sid(DOM_SID *sid, uid_t uid)
+{
+ return false;
+}
+
+/* Call winbindd to convert SID to gid */
+
+bool winbind_sid_to_gid(gid_t *pgid, const DOM_SID *sid)
+{
+ return false;
+}
+
+/* Call winbindd to convert gid to sid */
+
+bool winbind_gid_to_sid(DOM_SID *sid, gid_t gid)
+{
+ return false;
+}
+
+/* Check for a trusted domain */
+
+wbcErr wb_is_trusted_domain(const char *domain)
+{
+ return WBC_ERR_UNKNOWN_FAILURE;
+}
+
+/* Lookup a set of rids in a given domain */
+
+bool winbind_lookup_rids(TALLOC_CTX *mem_ctx,
+ const DOM_SID *domain_sid,
+ int num_rids, uint32 *rids,
+ const char **domain_name,
+ const char ***names, enum lsa_SidType **types)
+{
+ return false;
+}
+
+/* Ask Winbind to allocate a new uid for us */
+
+bool winbind_allocate_uid(uid_t *uid)
+{
+ return false;
+}
+
+/* Ask Winbind to allocate a new gid for us */
+
+bool winbind_allocate_gid(gid_t *gid)
+{
+ return false;
+}
+
+#endif /* WITH_WINBIND */
diff --git a/source3/lib/wins_srv.c b/source3/lib/wins_srv.c
new file mode 100644
index 0000000000..0e184a6b7c
--- /dev/null
+++ b/source3/lib/wins_srv.c
@@ -0,0 +1,361 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba wins server helper functions
+ Copyright (C) Andrew Tridgell 1992-2002
+ Copyright (C) Christopher R. Hertel 2000
+ Copyright (C) Tim Potter 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*
+ This is pretty much a complete rewrite of the earlier code. The main
+ aim of the rewrite is to add support for having multiple wins server
+ lists, so Samba can register with multiple groups of wins servers
+ and each group has a failover list of wins servers.
+
+ Central to the way it all works is the idea of a wins server
+ 'tag'. A wins tag is a label for a group of wins servers. For
+ example if you use
+
+ wins server = fred:192.168.2.10 mary:192.168.3.199 fred:192.168.2.61
+
+ then you would have two groups of wins servers, one tagged with the
+ name 'fred' and the other with the name 'mary'. I would usually
+ recommend using interface names instead of 'fred' and 'mary' but
+ they can be any alpha string.
+
+ Now, how does it all work. Well, nmbd needs to register each of its
+ IPs with each of its names once with each group of wins servers. So
+ it tries registering with the first one mentioned in the list, then
+ if that fails it marks that WINS server dead and moves onto the next
+ one.
+
+ In the client code things are a bit different. As each of the groups
+ of wins servers is a separate name space we need to try each of the
+ groups until we either succeed or we run out of wins servers to
+ try. If we get a negative response from a wins server then that
+ means the name doesn't exist in that group, so we give up on that
+ group and move to the next group. If we don't get a response at all
+ then maybe the wins server is down, in which case we need to
+ failover to the next one for that group.
+
+ confused yet? (tridge)
+*/
+
+/* how long a server is marked dead for */
+#define DEATH_TIME 600
+
+/* The list of dead wins servers is stored in gencache.tdb. Each server is
+ marked dead from the point of view of a given source address. We keep a
+ separate dead list for each src address to cope with multiple interfaces
+ that are not routable to each other.
+ */
+
+#define WINS_SRV_FMT "WINS_SRV_DEAD/%s,%s" /* wins_ip,src_ip */
+
+static char *wins_srv_keystr(struct in_addr wins_ip, struct in_addr src_ip)
+{
+ char *keystr = NULL, *wins_ip_addr = NULL, *src_ip_addr = NULL;
+
+ wins_ip_addr = SMB_STRDUP(inet_ntoa(wins_ip));
+ src_ip_addr = SMB_STRDUP(inet_ntoa(src_ip));
+
+ if ( !wins_ip_addr || !src_ip_addr ) {
+ DEBUG(0,("wins_srv_keystr: malloc error\n"));
+ goto done;
+ }
+
+ if (asprintf(&keystr, WINS_SRV_FMT, wins_ip_addr, src_ip_addr) == -1) {
+ DEBUG(0, (": ns_srv_keystr: malloc error for key string\n"));
+ }
+
+done:
+ SAFE_FREE(wins_ip_addr);
+ SAFE_FREE(src_ip_addr);
+
+ return keystr;
+}
+
+/*
+ see if an ip is on the dead list
+*/
+
+bool wins_srv_is_dead(struct in_addr wins_ip, struct in_addr src_ip)
+{
+ char *keystr = wins_srv_keystr(wins_ip, src_ip);
+ bool result;
+
+ /* If the key exists then the WINS server has been marked as dead */
+
+ result = gencache_get(keystr, NULL, NULL);
+ SAFE_FREE(keystr);
+
+ DEBUG(4, ("wins_srv_is_dead: %s is %s\n", inet_ntoa(wins_ip),
+ result ? "dead" : "alive"));
+
+ return result;
+}
+
+
+/*
+ mark a wins server as being alive (for the moment)
+*/
+void wins_srv_alive(struct in_addr wins_ip, struct in_addr src_ip)
+{
+ char *keystr = wins_srv_keystr(wins_ip, src_ip);
+
+ gencache_del(keystr);
+ SAFE_FREE(keystr);
+
+ DEBUG(4, ("wins_srv_alive: marking wins server %s alive\n",
+ inet_ntoa(wins_ip)));
+}
+
+/*
+ mark a wins server as temporarily dead
+*/
+void wins_srv_died(struct in_addr wins_ip, struct in_addr src_ip)
+{
+ char *keystr;
+
+ if (is_zero_ip_v4(wins_ip) || wins_srv_is_dead(wins_ip, src_ip))
+ return;
+
+ keystr = wins_srv_keystr(wins_ip, src_ip);
+
+ gencache_set(keystr, "DOWN", time(NULL) + DEATH_TIME);
+
+ SAFE_FREE(keystr);
+
+ DEBUG(4,("Marking wins server %s dead for %u seconds from source %s\n",
+ inet_ntoa(wins_ip), DEATH_TIME, inet_ntoa(src_ip)));
+}
+
+/*
+ return the total number of wins servers, dead or not
+*/
+unsigned wins_srv_count(void)
+{
+ const char **list;
+ int count = 0;
+
+ if (lp_wins_support()) {
+ /* simple - just talk to ourselves */
+ return 1;
+ }
+
+ list = lp_wins_server_list();
+ for (count=0; list && list[count]; count++)
+ /* nop */ ;
+
+ return count;
+}
+
+/* an internal convenience structure for an IP with a short string tag
+ attached */
+struct tagged_ip {
+ fstring tag;
+ struct in_addr ip;
+};
+
+/*
+ parse an IP string that might be in tagged format
+ the result is a tagged_ip structure containing the tag
+ and the ip in in_addr format. If there is no tag then
+ use the tag '*'
+*/
+static void parse_ip(struct tagged_ip *ip, const char *str)
+{
+ char *s = strchr(str, ':');
+ if (!s) {
+ fstrcpy(ip->tag, "*");
+ (void)interpret_addr2(&ip->ip,str);
+ return;
+ }
+
+ (void)interpret_addr2(&ip->ip,s+1);
+ fstrcpy(ip->tag, str);
+ s = strchr(ip->tag, ':');
+ if (s) {
+ *s = 0;
+ }
+}
+
+
+
+/*
+ return the list of wins server tags. A 'tag' is used to distinguish
+ wins server as either belonging to the same name space or a separate
+ name space. Usually you would setup your 'wins server' option to
+ list one or more wins server per interface and use the interface
+ name as your tag, but you are free to use any tag you like.
+*/
+char **wins_srv_tags(void)
+{
+ char **ret = NULL;
+ int count=0, i, j;
+ const char **list;
+
+ if (lp_wins_support()) {
+ /* give the caller something to chew on. This makes
+ the rest of the logic simpler (ie. less special cases) */
+ ret = SMB_MALLOC_ARRAY(char *, 2);
+ if (!ret) return NULL;
+ ret[0] = SMB_STRDUP("*");
+ ret[1] = NULL;
+ return ret;
+ }
+
+ list = lp_wins_server_list();
+ if (!list)
+ return NULL;
+
+ /* yes, this is O(n^2) but n is very small */
+ for (i=0;list[i];i++) {
+ struct tagged_ip t_ip;
+
+ parse_ip(&t_ip, list[i]);
+
+ /* see if we already have it */
+ for (j=0;j<count;j++) {
+ if (strcmp(ret[j], t_ip.tag) == 0) {
+ break;
+ }
+ }
+
+ if (j != count) {
+ /* we already have it. Move along */
+ continue;
+ }
+
+ /* add it to the list */
+ ret = SMB_REALLOC_ARRAY(ret, char *, count+2);
+ if (!ret) {
+ return NULL;
+ }
+ ret[count] = SMB_STRDUP(t_ip.tag);
+ if (!ret[count]) break;
+ count++;
+ }
+
+ if (count) {
+ /* make sure we null terminate */
+ ret[count] = NULL;
+ }
+
+ return ret;
+}
+
+/* free a list of wins server tags given by wins_srv_tags */
+void wins_srv_tags_free(char **list)
+{
+ int i;
+ if (!list) return;
+ for (i=0; list[i]; i++) {
+ free(list[i]);
+ }
+ free(list);
+}
+
+
+/*
+ return the IP of the currently active wins server for the given tag,
+ or the zero IP otherwise
+*/
+struct in_addr wins_srv_ip_tag(const char *tag, struct in_addr src_ip)
+{
+ const char **list;
+ int i;
+ struct tagged_ip t_ip;
+
+ /* if we are a wins server then we always just talk to ourselves */
+ if (lp_wins_support()) {
+ struct in_addr loopback_ip;
+ loopback_ip.s_addr = htonl(INADDR_LOOPBACK);
+ return loopback_ip;
+ }
+
+ list = lp_wins_server_list();
+ if (!list || !list[0]) {
+ struct in_addr ip;
+ zero_ip_v4(&ip);
+ return ip;
+ }
+
+ /* find the first live one for this tag */
+ for (i=0; list[i]; i++) {
+ parse_ip(&t_ip, list[i]);
+ if (strcmp(tag, t_ip.tag) != 0) {
+ /* not for the right tag. Move along */
+ continue;
+ }
+ if (!wins_srv_is_dead(t_ip.ip, src_ip)) {
+ fstring src_name;
+ fstrcpy(src_name, inet_ntoa(src_ip));
+ DEBUG(6,("Current wins server for tag '%s' with source %s is %s\n",
+ tag,
+ src_name,
+ inet_ntoa(t_ip.ip)));
+ return t_ip.ip;
+ }
+ }
+
+ /* they're all dead - try the first one until they revive */
+ for (i=0; list[i]; i++) {
+ parse_ip(&t_ip, list[i]);
+ if (strcmp(tag, t_ip.tag) != 0) {
+ continue;
+ }
+ return t_ip.ip;
+ }
+
+ /* this can't happen?? */
+ zero_ip_v4(&t_ip.ip);
+ return t_ip.ip;
+}
+
+
+/*
+ return a count of the number of IPs for a particular tag, including
+ dead ones
+*/
+unsigned wins_srv_count_tag(const char *tag)
+{
+ const char **list;
+ int i, count=0;
+
+ /* if we are a wins server then we always just talk to ourselves */
+ if (lp_wins_support()) {
+ return 1;
+ }
+
+ list = lp_wins_server_list();
+ if (!list || !list[0]) {
+ return 0;
+ }
+
+ /* find the first live one for this tag */
+ for (i=0; list[i]; i++) {
+ struct tagged_ip t_ip;
+ parse_ip(&t_ip, list[i]);
+ if (strcmp(tag, t_ip.tag) == 0) {
+ count++;
+ }
+ }
+
+ return count;
+}
diff --git a/source3/lib/xfile.c b/source3/lib/xfile.c
new file mode 100644
index 0000000000..e44a92d34d
--- /dev/null
+++ b/source3/lib/xfile.c
@@ -0,0 +1,417 @@
+/*
+ Unix SMB/CIFS implementation.
+ stdio replacement
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ stdio is very convenient, but on some systems the file descriptor
+ in FILE* is 8 bits, so it fails when more than 255 files are open.
+
+ XFILE replaces stdio. It is less efficient, but at least it works
+ when you have lots of files open
+
+ The main restriction on XFILE is that it doesn't support seeking,
+ and doesn't support O_RDWR. That keeps the code simple.
+*/
+
+#include "includes.h"
+
+#define XBUFSIZE BUFSIZ
+
+static XFILE _x_stdin = { 0, NULL, NULL, XBUFSIZE, 0, O_RDONLY, X_IOFBF, 0 };
+static XFILE _x_stdout = { 1, NULL, NULL, XBUFSIZE, 0, O_WRONLY, X_IOLBF, 0 };
+static XFILE _x_stderr = { 2, NULL, NULL, 0, 0, O_WRONLY, X_IONBF, 0 };
+
+XFILE *x_stdin = &_x_stdin;
+XFILE *x_stdout = &_x_stdout;
+XFILE *x_stderr = &_x_stderr;
+
+#define X_FLAG_EOF 1
+#define X_FLAG_ERROR 2
+#define X_FLAG_EINVAL 3
+
+/* simulate setvbuf() */
+int x_setvbuf(XFILE *f, char *buf, int mode, size_t size)
+{
+ if (x_fflush(f) != 0) return -1;
+ if (f->bufused) return -1;
+
+ /* on files being read full buffering is the only option */
+ if ((f->open_flags & O_ACCMODE) == O_RDONLY) {
+ mode = X_IOFBF;
+ }
+
+ /* destroy any earlier buffer */
+ SAFE_FREE(f->buf);
+ f->buf = 0;
+ f->bufsize = 0;
+ f->next = NULL;
+ f->bufused = 0;
+ f->buftype = mode;
+
+ if (f->buftype == X_IONBF) return 0;
+
+ /* if buffering then we need some size */
+ if (size == 0) size = XBUFSIZE;
+
+ f->bufsize = size;
+ f->bufused = 0;
+
+ return 0;
+}
+
+/* allocate the buffer */
+static int x_allocate_buffer(XFILE *f)
+{
+ if (f->buf) return 1;
+ if (f->bufsize == 0) return 0;
+ f->buf = (char *)SMB_MALLOC(f->bufsize);
+ if (!f->buf) return 0;
+ f->next = f->buf;
+ return 1;
+}
+
+
+/* this looks more like open() than fopen(), but that is quite deliberate.
+ I want programmers to *think* about O_EXCL, O_CREAT etc not just
+ get them magically added
+*/
+XFILE *x_fopen(const char *fname, int flags, mode_t mode)
+{
+ XFILE *ret;
+
+ ret = SMB_MALLOC_P(XFILE);
+ if (!ret) {
+ return NULL;
+ }
+
+ memset(ret, 0, sizeof(XFILE));
+
+ if ((flags & O_ACCMODE) == O_RDWR) {
+ /* we don't support RDWR in XFILE - use file
+ descriptors instead */
+ SAFE_FREE(ret);
+ errno = EINVAL;
+ return NULL;
+ }
+
+ ret->open_flags = flags;
+
+ ret->fd = sys_open(fname, flags, mode);
+ if (ret->fd == -1) {
+ SAFE_FREE(ret);
+ return NULL;
+ }
+
+ x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
+
+ return ret;
+}
+
+XFILE *x_fdup(const XFILE *f)
+{
+ XFILE *ret;
+ int fd;
+
+ fd = dup(x_fileno(f));
+ if (fd < 0) {
+ return NULL;
+ }
+
+ ret = SMB_CALLOC_ARRAY(XFILE, 1);
+ if (!ret) {
+ close(fd);
+ return NULL;
+ }
+
+ ret->fd = fd;
+ ret->open_flags = f->open_flags;
+ x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
+ return ret;
+}
+
+/* simulate fclose() */
+int x_fclose(XFILE *f)
+{
+ int ret;
+
+ /* make sure we flush any buffered data */
+ (void)x_fflush(f);
+
+ ret = close(f->fd);
+ f->fd = -1;
+ if (f->buf) {
+ /* make sure data can't leak into a later malloc */
+ memset(f->buf, 0, f->bufsize);
+ SAFE_FREE(f->buf);
+ }
+ /* check the file descriptor given to the function is NOT one of the static
+ * descriptor of this libreary or we will free unallocated memory
+ * --sss */
+ if (f != x_stdin && f != x_stdout && f != x_stderr) {
+ SAFE_FREE(f);
+ }
+ return ret;
+}
+
+/* simulate fwrite() */
+size_t x_fwrite(const void *p, size_t size, size_t nmemb, XFILE *f)
+{
+ ssize_t ret;
+ size_t total=0;
+
+ /* we might be writing unbuffered */
+ if (f->buftype == X_IONBF ||
+ (!f->buf && !x_allocate_buffer(f))) {
+ ret = write(f->fd, p, size*nmemb);
+ if (ret == -1) return -1;
+ return ret/size;
+ }
+
+
+ while (total < size*nmemb) {
+ size_t n = f->bufsize - f->bufused;
+ n = MIN(n, (size*nmemb)-total);
+
+ if (n == 0) {
+ /* it's full, flush it */
+ if (x_fflush(f) != 0) {
+ return -1;
+ }
+ continue;
+ }
+
+ memcpy(f->buf + f->bufused, total+(const char *)p, n);
+ f->bufused += n;
+ total += n;
+ }
+
+ /* when line buffered we need to flush at the last linefeed. This can
+ flush a bit more than necessary, but that is harmless */
+ if (f->buftype == X_IOLBF && f->bufused) {
+ int i;
+ for (i=(size*nmemb)-1; i>=0; i--) {
+ if (*(i+(const char *)p) == '\n') {
+ if (x_fflush(f) != 0) {
+ return -1;
+ }
+ break;
+ }
+ }
+ }
+
+ return total/size;
+}
+
+/* thank goodness for asprintf() */
+ int x_vfprintf(XFILE *f, const char *format, va_list ap)
+{
+ char *p;
+ int len, ret;
+ va_list ap2;
+
+ VA_COPY(ap2, ap);
+
+ len = vasprintf(&p, format, ap2);
+ if (len <= 0) {
+ va_end(ap2);
+ return len;
+ }
+ ret = x_fwrite(p, 1, len, f);
+ SAFE_FREE(p);
+
+ va_end(ap2);
+
+ return ret;
+}
+
+ int x_fprintf(XFILE *f, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = x_vfprintf(f, format, ap);
+ va_end(ap);
+ return ret;
+}
+
+/* at least fileno() is simple! */
+int x_fileno(const XFILE *f)
+{
+ return f->fd;
+}
+
+/* simulate fflush() */
+int x_fflush(XFILE *f)
+{
+ int ret;
+
+ if (f->flags & X_FLAG_ERROR) return -1;
+
+ if (f->bufused == 0 || !f->buf) return 0;
+
+ if ((f->open_flags & O_ACCMODE) != O_WRONLY) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = write(f->fd, f->buf, f->bufused);
+ if (ret == -1) return -1;
+
+ f->bufused -= ret;
+ if (f->bufused > 0) {
+ f->flags |= X_FLAG_ERROR;
+ memmove(f->buf, ret + (char *)f->buf, f->bufused);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* simulate setbuffer() */
+void x_setbuffer(XFILE *f, char *buf, size_t size)
+{
+ x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, size);
+}
+
+/* simulate setbuf() */
+void x_setbuf(XFILE *f, char *buf)
+{
+ x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, XBUFSIZE);
+}
+
+/* simulate setlinebuf() */
+void x_setlinebuf(XFILE *f)
+{
+ x_setvbuf(f, NULL, X_IOLBF, 0);
+}
+
+
+/* simulate feof() */
+int x_feof(XFILE *f)
+{
+ if (f->flags & X_FLAG_EOF) return 1;
+ return 0;
+}
+
+/* simulate ferror() */
+int x_ferror(XFILE *f)
+{
+ if (f->flags & X_FLAG_ERROR) return 1;
+ return 0;
+}
+
+/* fill the read buffer */
+static void x_fillbuf(XFILE *f)
+{
+ int n;
+
+ if (f->bufused) return;
+
+ if (!f->buf && !x_allocate_buffer(f)) return;
+
+ n = read(f->fd, f->buf, f->bufsize);
+ if (n <= 0) return;
+ f->bufused = n;
+ f->next = f->buf;
+}
+
+/* simulate fgetc() */
+int x_fgetc(XFILE *f)
+{
+ int ret;
+
+ if (f->flags & (X_FLAG_EOF | X_FLAG_ERROR)) return EOF;
+
+ if (f->bufused == 0) x_fillbuf(f);
+
+ if (f->bufused == 0) {
+ f->flags |= X_FLAG_EOF;
+ return EOF;
+ }
+
+ ret = *(unsigned char *)(f->next);
+ f->next++;
+ f->bufused--;
+ return ret;
+}
+
+/* simulate fread */
+size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
+{
+ size_t total = 0;
+ while (total < size*nmemb) {
+ int c = x_fgetc(f);
+ if (c == EOF) break;
+ (total+(char *)p)[0] = (char)c;
+ total++;
+ }
+ return total/size;
+}
+
+/* simulate fgets() */
+char *x_fgets(char *s, int size, XFILE *stream)
+{
+ char *s0 = s;
+ int l = size;
+ while (l>1) {
+ int c = x_fgetc(stream);
+ if (c == EOF) break;
+ *s++ = (char)c;
+ l--;
+ if (c == '\n') break;
+ }
+ if (l==size || x_ferror(stream)) {
+ return 0;
+ }
+ *s = 0;
+ return s0;
+}
+
+/* trivial seek, works only for SEEK_SET and SEEK_END if SEEK_CUR is
+ * set then an error is returned */
+off_t x_tseek(XFILE *f, off_t offset, int whence)
+{
+ if (f->flags & X_FLAG_ERROR)
+ return -1;
+
+ /* only SEEK_SET and SEEK_END are supported */
+ /* SEEK_CUR needs internal offset counter */
+ if (whence != SEEK_SET && whence != SEEK_END) {
+ f->flags |= X_FLAG_EINVAL;
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* empty the buffer */
+ switch (f->open_flags & O_ACCMODE) {
+ case O_RDONLY:
+ f->bufused = 0;
+ break;
+ case O_WRONLY:
+ if (x_fflush(f) != 0)
+ return -1;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ f->flags &= ~X_FLAG_EOF;
+ return (off_t)sys_lseek(f->fd, offset, whence);
+}
diff --git a/source3/libaddns/addns.h b/source3/libaddns/addns.h
new file mode 100644
index 0000000000..6ef9329df8
--- /dev/null
+++ b/source3/libaddns/addns.h
@@ -0,0 +1,30 @@
+/*
+ Public Interface file for Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _ADDNS_H
+#define _ADDNS_H
+
+
+#endif /* _ADDNS_H */
+
diff --git a/source3/libaddns/dns.h b/source3/libaddns/dns.h
new file mode 100644
index 0000000000..2eaeaf7608
--- /dev/null
+++ b/source3/libaddns/dns.h
@@ -0,0 +1,535 @@
+/*
+ Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _DNS_H
+#define _DNS_H
+
+#include "lib/replace/replace.h"
+#include "system/network.h"
+
+/* make sure we have included the correct config.h */
+#ifndef NO_CONFIG_H /* for some tests */
+#ifndef CONFIG_H_IS_FROM_SAMBA
+#error "make sure you have removed all config.h files from standalone builds!"
+#error "the included config.h isn't from samba!"
+#endif
+#endif /* NO_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdarg.h>
+
+#ifdef HAVE_UUID_UUID_H
+#include <uuid/uuid.h>
+#endif
+
+#ifdef HAVE_KRB5_H
+#include <krb5.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+
+#ifndef int16
+#define int16 int16_t
+#endif
+
+#ifndef uint16
+#define uint16 uint16_t
+#endif
+
+#ifndef int32
+#define int32 int32_t
+#endif
+
+#ifndef uint32
+#define uint32 uint32_t
+#endif
+#endif
+
+#ifdef HAVE_KRB5_H
+#include <krb5.h>
+#endif
+
+#if HAVE_GSSAPI_H
+#include <gssapi.h>
+#elif HAVE_GSSAPI_GSSAPI_H
+#include <gssapi/gssapi.h>
+#elif HAVE_GSSAPI_GSSAPI_GENERIC_H
+#include <gssapi/gssapi_generic.h>
+#endif
+
+#if defined(HAVE_GSSAPI_H) || defined(HAVE_GSSAPI_GSSAPI_H) || defined(HAVE_GSSAPI_GSSAPI_GENERIC_H)
+#define HAVE_GSSAPI_SUPPORT 1
+#endif
+
+#include <talloc.h>
+
+#if 0
+
+Disable these now we have checked all code paths and ensured
+NULL returns on zero request. JRA.
+
+void *_talloc_zero_zeronull(const void *ctx, size_t size, const char *name);
+void *_talloc_memdup_zeronull(const void *t, const void *p, size_t size, const char *name);
+void *_talloc_array_zeronull(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *_talloc_zero_array_zeronull(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *talloc_zeronull(const void *context, size_t size, const char *name);
+
+#define TALLOC(ctx, size) talloc_zeronull(ctx, size, __location__)
+#define TALLOC_P(ctx, type) (type *)talloc_zeronull(ctx, sizeof(type), #type)
+#define TALLOC_ARRAY(ctx, type, count) (type *)_talloc_array_zeronull(ctx, sizeof(type), count, #type)
+#define TALLOC_MEMDUP(ctx, ptr, size) _talloc_memdup_zeronull(ctx, ptr, size, __location__)
+#define TALLOC_ZERO(ctx, size) _talloc_zero_zeronull(ctx, size, __location__)
+#define TALLOC_ZERO_P(ctx, type) (type *)_talloc_zero_zeronull(ctx, sizeof(type), #type)
+#define TALLOC_ZERO_ARRAY(ctx, type, count) (type *)_talloc_zero_array_zeronull(ctx, sizeof(type), count, #type)
+#define TALLOC_SIZE(ctx, size) talloc_zeronull(ctx, size, __location__)
+#define TALLOC_ZERO_SIZE(ctx, size) _talloc_zero_zeronull(ctx, size, __location__)
+
+#else
+
+#define TALLOC(ctx, size) talloc_named_const(ctx, size, __location__)
+#define TALLOC_P(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
+#define TALLOC_ARRAY(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
+#define TALLOC_MEMDUP(ctx, ptr, size) _talloc_memdup(ctx, ptr, size, __location__)
+#define TALLOC_ZERO(ctx, size) _talloc_zero(ctx, size, __location__)
+#define TALLOC_ZERO_P(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
+#define TALLOC_ZERO_ARRAY(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type)
+#define TALLOC_SIZE(ctx, size) talloc_named_const(ctx, size, __location__)
+#define TALLOC_ZERO_SIZE(ctx, size) _talloc_zero(ctx, size, __location__)
+
+#endif
+
+#define TALLOC_REALLOC(ctx, ptr, count) _talloc_realloc(ctx, ptr, count, __location__)
+#define TALLOC_REALLOC_ARRAY(ctx, ptr, type, count) (type *)_talloc_realloc_array(ctx, ptr, sizeof(type), count, #type)
+#define talloc_destroy(ctx) talloc_free(ctx)
+#define TALLOC_FREE(ctx) do { if ((ctx) != NULL) {talloc_free(ctx); ctx=NULL;} } while(0)
+
+/*******************************************************************
+ Type definitions for int16, int32, uint16 and uint32. Needed
+ for Samba coding style
+*******************************************************************/
+
+#ifndef uint8
+# define uint8 unsigned char
+#endif
+
+#if !defined(int16) && !defined(HAVE_INT16_FROM_RPC_RPC_H)
+# if (SIZEOF_SHORT == 4)
+# define int16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16;
+# else /* SIZEOF_SHORT != 4 */
+# define int16 short
+# endif /* SIZEOF_SHORT != 4 */
+ /* needed to work around compile issue on HP-UX 11.x */
+# define _INT16 1
+#endif
+
+/*
+ * Note we duplicate the size tests in the unsigned
+ * case as int16 may be a typedef from rpc/rpc.h
+ */
+
+#if !defined(uint16) && !defined(HAVE_UINT16_FROM_RPC_RPC_H)
+# if (SIZEOF_SHORT == 4)
+# define uint16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16;
+# else /* SIZEOF_SHORT != 4 */
+# define uint16 unsigned short
+# endif /* SIZEOF_SHORT != 4 */
+#endif
+
+#if !defined(int32) && !defined(HAVE_INT32_FROM_RPC_RPC_H)
+# if (SIZEOF_INT == 4)
+# define int32 int
+# elif (SIZEOF_LONG == 4)
+# define int32 long
+# elif (SIZEOF_SHORT == 4)
+# define int32 short
+# else
+ /* uggh - no 32 bit type?? probably a CRAY. just hope this works ... */
+# define int32 int
+# endif
+ /* needed to work around compile issue on HP-UX 11.x */
+# define _INT32 1
+#endif
+
+/*
+ * Note we duplicate the size tests in the unsigned
+ * case as int32 may be a typedef from rpc/rpc.h
+ */
+
+#if !defined(uint32) && !defined(HAVE_UINT32_FROM_RPC_RPC_H)
+# if (SIZEOF_INT == 4)
+# define uint32 unsigned int
+# elif (SIZEOF_LONG == 4)
+# define uint32 unsigned long
+# elif (SIZEOF_SHORT == 4)
+# define uint32 unsigned short
+# else
+ /* uggh - no 32 bit type?? probably a CRAY. just hope this works ... */
+# define uint32 unsigned
+# endif
+#endif
+
+/*
+ * check for 8 byte long long
+ */
+
+#if !defined(uint64)
+# if (SIZEOF_LONG == 8)
+# define uint64 unsigned long
+# elif (SIZEOF_LONG_LONG == 8)
+# define uint64 unsigned long long
+# endif /* don't lie. If we don't have it, then don't use it */
+#endif
+
+/* needed on Sun boxes */
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xFFFFFFFF
+#endif
+
+#include "dnserr.h"
+
+
+#define DNS_TCP 1
+#define DNS_UDP 2
+
+#define DNS_OPCODE_UPDATE 1
+
+/* DNS Class Types */
+
+#define DNS_CLASS_IN 1
+#define DNS_CLASS_ANY 255
+#define DNS_CLASS_NONE 254
+
+/* DNS RR Types */
+
+#define DNS_RR_A 1
+
+#define DNS_TCP_PORT 53
+#define DNS_UDP_PORT 53
+
+#define QTYPE_A 1
+#define QTYPE_NS 2
+#define QTYPE_MD 3
+#define QTYPE_CNAME 5
+#define QTYPE_SOA 6
+#define QTYPE_ANY 255
+#define QTYPE_TKEY 249
+#define QTYPE_TSIG 250
+
+/*
+MF 4 a mail forwarder (Obsolete - use MX)
+CNAME 5 the canonical name for an alias
+SOA 6 marks the start of a zone of authority
+MB 7 a mailbox domain name (EXPERIMENTAL)
+MG 8 a mail group member (EXPERIMENTAL)
+MR 9 a mail rename domain name (EXPERIMENTAL)
+NULL 10 a null RR (EXPERIMENTAL)
+WKS 11 a well known service description
+PTR 12 a domain name pointer
+HINFO 13 host information
+MINFO 14 mailbox or mail list information
+MX 15 mail exchange
+TXT 16 text strings
+*/
+
+#define QR_QUERY 0x0000
+#define QR_RESPONSE 0x0001
+
+#define OPCODE_QUERY 0x00
+#define OPCODE_IQUERY 0x01
+#define OPCODE_STATUS 0x02
+
+#define AA 1
+
+#define RECURSION_DESIRED 0x01
+
+#define RCODE_NOERROR 0
+#define RCODE_FORMATERROR 1
+#define RCODE_SERVER_FAILURE 2
+#define RCODE_NAME_ERROR 3
+#define RCODE_NOTIMPLEMENTED 4
+#define RCODE_REFUSED 5
+
+#define SENDBUFFER_SIZE 65536
+#define RECVBUFFER_SIZE 65536
+
+/*
+ * TKEY Modes from rfc2930
+ */
+
+#define DNS_TKEY_MODE_SERVER 1
+#define DNS_TKEY_MODE_DH 2
+#define DNS_TKEY_MODE_GSSAPI 3
+#define DNS_TKEY_MODE_RESOLVER 4
+#define DNS_TKEY_MODE_DELETE 5
+
+
+#define DNS_ONE_DAY_IN_SECS 86400
+#define DNS_TEN_HOURS_IN_SECS 36000
+
+#define SOCKET_ERROR -1
+#define INVALID_SOCKET -1
+
+#define DNS_NO_ERROR 0
+#define DNS_FORMAT_ERROR 1
+#define DNS_SERVER_FAILURE 2
+#define DNS_NAME_ERROR 3
+#define DNS_NOT_IMPLEMENTED 4
+#define DNS_REFUSED 5
+
+typedef long HANDLE;
+
+enum dns_ServerType { DNS_SRV_ANY, DNS_SRV_WIN2000, DNS_SRV_WIN2003 };
+
+struct dns_domain_label {
+ struct dns_domain_label *next;
+ char *label;
+ size_t len;
+};
+
+struct dns_domain_name {
+ struct dns_domain_label *pLabelList;
+};
+
+struct dns_question {
+ struct dns_domain_name *name;
+ uint16 q_type;
+ uint16 q_class;
+};
+
+/*
+ * Before changing the definition of dns_zone, look
+ * dns_marshall_update_request(), we rely on this being the same as
+ * dns_question right now.
+ */
+
+struct dns_zone {
+ struct dns_domain_name *name;
+ uint16 z_type;
+ uint16 z_class;
+};
+
+struct dns_rrec {
+ struct dns_domain_name *name;
+ uint16 type;
+ uint16 r_class;
+ uint32 ttl;
+ uint16 data_length;
+ uint8 *data;
+};
+
+struct dns_tkey_record {
+ struct dns_domain_name *algorithm;
+ time_t inception;
+ time_t expiration;
+ uint16 mode;
+ uint16 error;
+ uint16 key_length;
+ uint8 *key;
+};
+
+struct dns_request {
+ uint16 id;
+ uint16 flags;
+ uint16 num_questions;
+ uint16 num_answers;
+ uint16 num_auths;
+ uint16 num_additionals;
+ struct dns_question **questions;
+ struct dns_rrec **answers;
+ struct dns_rrec **auths;
+ struct dns_rrec **additionals;
+};
+
+/*
+ * Before changing the definition of dns_update_request, look
+ * dns_marshall_update_request(), we rely on this being the same as
+ * dns_request right now.
+ */
+
+struct dns_update_request {
+ uint16 id;
+ uint16 flags;
+ uint16 num_zones;
+ uint16 num_preqs;
+ uint16 num_updates;
+ uint16 num_additionals;
+ struct dns_zone **zones;
+ struct dns_rrec **preqs;
+ struct dns_rrec **updates;
+ struct dns_rrec **additionals;
+};
+
+struct dns_connection {
+ int32 hType;
+ int s;
+ struct sockaddr RecvAddr;
+};
+
+struct dns_buffer {
+ uint8 *data;
+ size_t size;
+ size_t offset;
+ DNS_ERROR error;
+};
+
+/* from dnsutils.c */
+
+DNS_ERROR dns_domain_name_from_string( TALLOC_CTX *mem_ctx,
+ const char *pszDomainName,
+ struct dns_domain_name **presult );
+char *dns_generate_keyname( TALLOC_CTX *mem_ctx );
+
+/* from dnsrecord.c */
+
+DNS_ERROR dns_create_query( TALLOC_CTX *mem_ctx, const char *name,
+ uint16 q_type, uint16 q_class,
+ struct dns_request **preq );
+DNS_ERROR dns_create_update( TALLOC_CTX *mem_ctx, const char *name,
+ struct dns_update_request **preq );
+DNS_ERROR dns_create_probe(TALLOC_CTX *mem_ctx, const char *zone,
+ const char *host, int num_ips,
+ const struct sockaddr_storage *sslist,
+ struct dns_update_request **preq);
+DNS_ERROR dns_create_rrec(TALLOC_CTX *mem_ctx, const char *name,
+ uint16 type, uint16 r_class, uint32 ttl,
+ uint16 data_length, uint8 *data,
+ struct dns_rrec **prec);
+DNS_ERROR dns_add_rrec(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
+ uint16 *num_records, struct dns_rrec ***records);
+DNS_ERROR dns_create_tkey_record(TALLOC_CTX *mem_ctx, const char *keyname,
+ const char *algorithm_name, time_t inception,
+ time_t expiration, uint16 mode, uint16 error,
+ uint16 key_length, const uint8 *key,
+ struct dns_rrec **prec);
+DNS_ERROR dns_create_name_in_use_record(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const struct sockaddr_storage *ip,
+ struct dns_rrec **prec);
+DNS_ERROR dns_create_delete_record(TALLOC_CTX *mem_ctx, const char *name,
+ uint16 type, uint16 r_class,
+ struct dns_rrec **prec);
+DNS_ERROR dns_create_name_not_in_use_record(TALLOC_CTX *mem_ctx,
+ const char *name, uint32 type,
+ struct dns_rrec **prec);
+DNS_ERROR dns_create_a_record(TALLOC_CTX *mem_ctx, const char *host,
+ uint32 ttl, const struct sockaddr_storage *pss,
+ struct dns_rrec **prec);
+DNS_ERROR dns_unmarshall_tkey_record(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
+ struct dns_tkey_record **ptkey);
+DNS_ERROR dns_create_tsig_record(TALLOC_CTX *mem_ctx, const char *keyname,
+ const char *algorithm_name,
+ time_t time_signed, uint16 fudge,
+ uint16 mac_length, const uint8 *mac,
+ uint16 original_id, uint16 error,
+ struct dns_rrec **prec);
+DNS_ERROR dns_add_rrec(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
+ uint16 *num_records, struct dns_rrec ***records);
+DNS_ERROR dns_create_update_request(TALLOC_CTX *mem_ctx,
+ const char *domainname,
+ const char *hostname,
+ const struct sockaddr_storage *ip_addr,
+ size_t num_adds,
+ struct dns_update_request **preq);
+
+/* from dnssock.c */
+
+DNS_ERROR dns_open_connection( const char *nameserver, int32 dwType,
+ TALLOC_CTX *mem_ctx,
+ struct dns_connection **conn );
+DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf);
+DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
+ struct dns_buffer **presult);
+DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
+ const struct dns_request *req,
+ struct dns_request **resp);
+DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
+ struct dns_connection *conn,
+ struct dns_update_request *up_req,
+ struct dns_update_request **up_resp);
+
+/* from dnsmarshall.c */
+
+struct dns_buffer *dns_create_buffer(TALLOC_CTX *mem_ctx);
+void dns_marshall_buffer(struct dns_buffer *buf, const uint8 *data,
+ size_t len);
+void dns_marshall_uint16(struct dns_buffer *buf, uint16 val);
+void dns_marshall_uint32(struct dns_buffer *buf, uint32 val);
+void dns_unmarshall_buffer(struct dns_buffer *buf, uint8 *data,
+ size_t len);
+void dns_unmarshall_uint16(struct dns_buffer *buf, uint16 *val);
+void dns_unmarshall_uint32(struct dns_buffer *buf, uint32 *val);
+void dns_unmarshall_domain_name(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_domain_name **pname);
+void dns_marshall_domain_name(struct dns_buffer *buf,
+ const struct dns_domain_name *name);
+void dns_unmarshall_domain_name(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_domain_name **pname);
+DNS_ERROR dns_marshall_request(TALLOC_CTX *mem_ctx,
+ const struct dns_request *req,
+ struct dns_buffer **pbuf);
+DNS_ERROR dns_unmarshall_request(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_request **preq);
+DNS_ERROR dns_marshall_update_request(TALLOC_CTX *mem_ctx,
+ struct dns_update_request *update,
+ struct dns_buffer **pbuf);
+DNS_ERROR dns_unmarshall_update_request(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_update_request **pupreq);
+struct dns_request *dns_update2request(struct dns_update_request *update);
+struct dns_update_request *dns_request2update(struct dns_request *request);
+uint16 dns_response_code(uint16 flags);
+
+/* from dnsgss.c */
+
+#ifdef HAVE_GSSAPI_SUPPORT
+
+void display_status( const char *msg, OM_uint32 maj_stat, OM_uint32 min_stat );
+DNS_ERROR dns_negotiate_sec_ctx( const char *target_realm,
+ const char *servername,
+ const char *keyname,
+ gss_ctx_id_t *gss_ctx,
+ enum dns_ServerType srv_type );
+DNS_ERROR dns_sign_update(struct dns_update_request *req,
+ gss_ctx_id_t gss_ctx,
+ const char *keyname,
+ const char *algorithmname,
+ time_t time_signed, uint16 fudge);
+
+#endif /* HAVE_GSSAPI_SUPPORT */
+
+#endif /* _DNS_H */
diff --git a/source3/libaddns/dnserr.h b/source3/libaddns/dnserr.h
new file mode 100644
index 0000000000..9e049ac3a9
--- /dev/null
+++ b/source3/libaddns/dnserr.h
@@ -0,0 +1,87 @@
+/*
+ Error codes for Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _DNSERR_H
+#define _DNSERR_H
+
+
+/* The Splint code analysis tool (http://www.splint.org.) doesn't
+ like immediate structures. */
+
+#ifdef _SPLINT_
+#undef HAVE_IMMEDIATE_STRUCTURES
+#endif
+
+/* Setup the DNS_ERROR typedef. Technique takes from nt_status.h */
+
+#if defined(HAVE_IMMEDIATE_STRUCTURES)
+typedef struct {uint32 v;} DNS_ERROR;
+#define ERROR_DNS(x) ((DNS_ERROR) { x })
+#define ERROR_DNS_V(x) ((x).v)
+#else
+typedef uint32 DNS_ERROR;
+#define ERROR_DNS(x) (x)
+#define ERROR_DNS_V(x) (x)
+#endif
+
+#define ERR_DNS_IS_OK(x) (ERROR_DNS_V(x) == 0)
+#define ERR_DNS_EQUAL(x,y) (ERROR_DNS_V(x) == ERROR_DNS_V(y))
+
+/*************************************************
+ * Define the error codes here
+ *************************************************/
+
+#define ERROR_DNS_SUCCESS ERROR_DNS(0)
+#define ERROR_DNS_RECORD_NOT_FOUND ERROR_DNS(1)
+#define ERROR_DNS_BAD_RESPONSE ERROR_DNS(2)
+#define ERROR_DNS_INVALID_PARAMETER ERROR_DNS(3)
+#define ERROR_DNS_NO_MEMORY ERROR_DNS(4)
+#define ERROR_DNS_INVALID_NAME_SERVER ERROR_DNS(5)
+#define ERROR_DNS_CONNECTION_FAILED ERROR_DNS(6)
+#define ERROR_DNS_GSS_ERROR ERROR_DNS(7)
+#define ERROR_DNS_INVALID_NAME ERROR_DNS(8)
+#define ERROR_DNS_INVALID_MESSAGE ERROR_DNS(9)
+#define ERROR_DNS_SOCKET_ERROR ERROR_DNS(10)
+#define ERROR_DNS_UPDATE_FAILED ERROR_DNS(11)
+
+/*
+ * About to be removed, transitional error
+ */
+#define ERROR_DNS_UNSUCCESSFUL ERROR_DNS(999)
+
+
+#define ERROR_BAD_RESPONSE 1
+#define ERROR_RECORD_NOT_FOUND 2
+#define ERROR_OUTOFMEMORY 8
+#if !defined(ERROR_INVALID_PARAMETER)
+#define ERROR_INVALID_PARAMETER 87
+#endif
+
+/*
+ * About to be removed, transitional error
+ */
+#define ERROR_UNSUCCESSFUL 999
+
+#endif /* _DNSERR_H */
+
diff --git a/source3/libaddns/dnsgss.c b/source3/libaddns/dnsgss.c
new file mode 100644
index 0000000000..e7ea041847
--- /dev/null
+++ b/source3/libaddns/dnsgss.c
@@ -0,0 +1,332 @@
+/*
+ Public Interface file for Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dns.h"
+#include <ctype.h>
+
+
+#ifdef HAVE_GSSAPI_SUPPORT
+
+/*********************************************************************
+*********************************************************************/
+
+static int strupr( char *szDomainName )
+{
+ if ( !szDomainName ) {
+ return ( 0 );
+ }
+ while ( *szDomainName != '\0' ) {
+ *szDomainName = toupper( *szDomainName );
+ szDomainName++;
+ }
+ return ( 0 );
+}
+
+#if 0
+/*********************************************************************
+*********************************************************************/
+
+static void display_status_1( const char *m, OM_uint32 code, int type )
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_desc msg;
+ OM_uint32 msg_ctx;
+
+ msg_ctx = 0;
+ while ( 1 ) {
+ maj_stat = gss_display_status( &min_stat, code,
+ type, GSS_C_NULL_OID,
+ &msg_ctx, &msg );
+ fprintf( stdout, "GSS-API error %s: %s\n", m,
+ ( char * ) msg.value );
+ ( void ) gss_release_buffer( &min_stat, &msg );
+
+ if ( !msg_ctx )
+ break;
+ }
+}
+
+/*********************************************************************
+*********************************************************************/
+
+void display_status( const char *msg, OM_uint32 maj_stat, OM_uint32 min_stat )
+{
+ display_status_1( msg, maj_stat, GSS_C_GSS_CODE );
+ display_status_1( msg, min_stat, GSS_C_MECH_CODE );
+}
+#endif
+
+static DNS_ERROR dns_negotiate_gss_ctx_int( TALLOC_CTX *mem_ctx,
+ struct dns_connection *conn,
+ const char *keyname,
+ const gss_name_t target_name,
+ gss_ctx_id_t *ctx,
+ enum dns_ServerType srv_type )
+{
+ struct gss_buffer_desc_struct input_desc, *input_ptr, output_desc;
+ OM_uint32 major, minor;
+ OM_uint32 ret_flags;
+ DNS_ERROR err;
+
+ gss_OID_desc krb5_oid_desc =
+ { 9, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
+
+ *ctx = GSS_C_NO_CONTEXT;
+ input_ptr = NULL;
+
+ do {
+ major = gss_init_sec_context(
+ &minor, NULL, ctx, target_name, &krb5_oid_desc,
+ GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG |
+ GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG |
+ GSS_C_INTEG_FLAG | GSS_C_DELEG_FLAG,
+ 0, NULL, input_ptr, NULL, &output_desc,
+ &ret_flags, NULL );
+
+ if (input_ptr != NULL) {
+ TALLOC_FREE(input_desc.value);
+ }
+
+ if (output_desc.length != 0) {
+
+ struct dns_request *req;
+ struct dns_rrec *rec;
+ struct dns_buffer *buf;
+
+ time_t t = time(NULL);
+
+ err = dns_create_query(mem_ctx, keyname, QTYPE_TKEY,
+ DNS_CLASS_IN, &req);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_create_tkey_record(
+ req, keyname, "gss.microsoft.com", t,
+ t + 86400, DNS_TKEY_MODE_GSSAPI, 0,
+ output_desc.length, (uint8 *)output_desc.value,
+ &rec );
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ /* Windows 2000 DNS is broken and requires the
+ TKEY payload in the Answer section instead
+ of the Additional seciton like Windows 2003 */
+
+ if ( srv_type == DNS_SRV_WIN2000 ) {
+ err = dns_add_rrec(req, rec, &req->num_answers,
+ &req->answers);
+ } else {
+ err = dns_add_rrec(req, rec, &req->num_additionals,
+ &req->additionals);
+ }
+
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_marshall_request(req, req, &buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_send(conn, buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ TALLOC_FREE(req);
+ }
+
+ gss_release_buffer(&minor, &output_desc);
+
+ if ((major != GSS_S_COMPLETE) &&
+ (major != GSS_S_CONTINUE_NEEDED)) {
+ return ERROR_DNS_GSS_ERROR;
+ }
+
+ if (major == GSS_S_CONTINUE_NEEDED) {
+
+ struct dns_request *resp;
+ struct dns_buffer *buf;
+ struct dns_tkey_record *tkey;
+
+ err = dns_receive(mem_ctx, conn, &buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_unmarshall_request(buf, buf, &resp);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ /*
+ * TODO: Compare id and keyname
+ */
+
+ if ((resp->num_additionals != 1) ||
+ (resp->num_answers == 0) ||
+ (resp->answers[0]->type != QTYPE_TKEY)) {
+ err = ERROR_DNS_INVALID_MESSAGE;
+ goto error;
+ }
+
+ err = dns_unmarshall_tkey_record(
+ mem_ctx, resp->answers[0], &tkey);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ input_desc.length = tkey->key_length;
+ input_desc.value = talloc_move(mem_ctx, &tkey->key);
+
+ input_ptr = &input_desc;
+
+ TALLOC_FREE(buf);
+ }
+
+ } while ( major == GSS_S_CONTINUE_NEEDED );
+
+ /* If we arrive here, we have a valid security context */
+
+ err = ERROR_DNS_SUCCESS;
+
+ error:
+
+ return err;
+}
+
+DNS_ERROR dns_negotiate_sec_ctx( const char *target_realm,
+ const char *servername,
+ const char *keyname,
+ gss_ctx_id_t *gss_ctx,
+ enum dns_ServerType srv_type )
+{
+ OM_uint32 major, minor;
+
+ char *upcaserealm, *targetname;
+ DNS_ERROR err;
+
+ gss_buffer_desc input_name;
+ struct dns_connection *conn;
+
+ gss_name_t targ_name;
+
+ gss_OID_desc nt_host_oid_desc =
+ {10, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01"};
+
+ TALLOC_CTX *mem_ctx;
+
+ if (!(mem_ctx = talloc_init("dns_negotiate_sec_ctx"))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = dns_open_connection( servername, DNS_TCP, mem_ctx, &conn );
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ if (!(upcaserealm = talloc_strdup(mem_ctx, target_realm))) {
+ err = ERROR_DNS_NO_MEMORY;
+ goto error;
+ }
+
+ strupr(upcaserealm);
+
+ if (!(targetname = talloc_asprintf(mem_ctx, "dns/%s@%s",
+ servername, upcaserealm))) {
+ err = ERROR_DNS_NO_MEMORY;
+ goto error;
+ }
+
+ input_name.value = targetname;
+ input_name.length = strlen(targetname);
+
+ major = gss_import_name( &minor, &input_name,
+ &nt_host_oid_desc, &targ_name );
+
+ if (major) {
+ err = ERROR_DNS_GSS_ERROR;
+ goto error;
+ }
+
+ err = dns_negotiate_gss_ctx_int(mem_ctx, conn, keyname,
+ targ_name, gss_ctx, srv_type );
+
+ gss_release_name( &minor, &targ_name );
+
+ error:
+ TALLOC_FREE(mem_ctx);
+
+ return err;
+}
+
+DNS_ERROR dns_sign_update(struct dns_update_request *req,
+ gss_ctx_id_t gss_ctx,
+ const char *keyname,
+ const char *algorithmname,
+ time_t time_signed, uint16 fudge)
+{
+ struct dns_buffer *buf;
+ DNS_ERROR err;
+ struct dns_domain_name *key, *algorithm;
+ struct gss_buffer_desc_struct msg, mic;
+ OM_uint32 major, minor;
+ struct dns_rrec *rec;
+
+ err = dns_marshall_update_request(req, req, &buf);
+ if (!ERR_DNS_IS_OK(err)) return err;
+
+ err = dns_domain_name_from_string(buf, keyname, &key);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_domain_name_from_string(buf, algorithmname, &algorithm);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ dns_marshall_domain_name(buf, key);
+ dns_marshall_uint16(buf, DNS_CLASS_ANY);
+ dns_marshall_uint32(buf, 0); /* TTL */
+ dns_marshall_domain_name(buf, algorithm);
+ dns_marshall_uint16(buf, 0); /* Time prefix for 48-bit time_t */
+ dns_marshall_uint32(buf, time_signed);
+ dns_marshall_uint16(buf, fudge);
+ dns_marshall_uint16(buf, 0); /* error */
+ dns_marshall_uint16(buf, 0); /* other len */
+
+ err = buf->error;
+ if (!ERR_DNS_IS_OK(buf->error)) goto error;
+
+ msg.value = (void *)buf->data;
+ msg.length = buf->offset;
+
+ major = gss_get_mic(&minor, gss_ctx, 0, &msg, &mic);
+ if (major != 0) {
+ err = ERROR_DNS_GSS_ERROR;
+ goto error;
+ }
+
+ if (mic.length > 0xffff) {
+ gss_release_buffer(&minor, &mic);
+ err = ERROR_DNS_GSS_ERROR;
+ goto error;
+ }
+
+ err = dns_create_tsig_record(buf, keyname, algorithmname, time_signed,
+ fudge, mic.length, (uint8 *)mic.value,
+ req->id, 0, &rec);
+ gss_release_buffer(&minor, &mic);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_additionals, &req->additionals);
+
+ error:
+ TALLOC_FREE(buf);
+ return err;
+}
+
+#endif /* HAVE_GSSAPI_SUPPORT */
diff --git a/source3/libaddns/dnsmarshall.c b/source3/libaddns/dnsmarshall.c
new file mode 100644
index 0000000000..8c3389eb9b
--- /dev/null
+++ b/source3/libaddns/dnsmarshall.c
@@ -0,0 +1,529 @@
+/*
+ Linux DNS client library implementation
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dns.h"
+#include "assert.h"
+
+struct dns_buffer *dns_create_buffer(TALLOC_CTX *mem_ctx)
+{
+ struct dns_buffer *result;
+
+ if (!(result = talloc(mem_ctx, struct dns_buffer))) {
+ return NULL;
+ }
+
+ result->offset = 0;
+ result->error = ERROR_DNS_SUCCESS;
+
+ /*
+ * Small inital size to excercise the realloc code
+ */
+ result->size = 2;
+
+ if (!(result->data = TALLOC_ARRAY(result, uint8, result->size))) {
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+void dns_marshall_buffer(struct dns_buffer *buf, const uint8 *data,
+ size_t len)
+{
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ if (buf->offset + len < buf->offset) {
+ /*
+ * Wraparound!
+ */
+ buf->error = ERROR_DNS_INVALID_PARAMETER;
+ return;
+ }
+
+ if ((buf->offset + len) > 0xffff) {
+ /*
+ * Only 64k possible
+ */
+ buf->error = ERROR_DNS_INVALID_PARAMETER;
+ return;
+ }
+
+ if (buf->offset + len > buf->size) {
+ size_t new_size = buf->offset + len;
+ uint8 *new_data;
+
+ /*
+ * Don't do too many reallocs, round up to some multiple
+ */
+
+ new_size += (64 - (new_size % 64));
+
+ if (!(new_data = TALLOC_REALLOC_ARRAY(buf, buf->data, uint8,
+ new_size))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+
+ buf->size = new_size;
+ buf->data = new_data;
+ }
+
+ memcpy(buf->data + buf->offset, data, len);
+ buf->offset += len;
+ return;
+}
+
+void dns_marshall_uint16(struct dns_buffer *buf, uint16 val)
+{
+ uint16 n_val = htons(val);
+ dns_marshall_buffer(buf, (uint8 *)&n_val, sizeof(n_val));
+}
+
+void dns_marshall_uint32(struct dns_buffer *buf, uint32 val)
+{
+ uint32 n_val = htonl(val);
+ dns_marshall_buffer(buf, (uint8 *)&n_val, sizeof(n_val));
+}
+
+void dns_unmarshall_buffer(struct dns_buffer *buf, uint8 *data,
+ size_t len)
+{
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ if ((len > buf->size) || (buf->offset + len > buf->size)) {
+ buf->error = ERROR_DNS_INVALID_MESSAGE;
+ return;
+ }
+
+ memcpy((void *)data, (const void *)(buf->data + buf->offset), len);
+ buf->offset += len;
+
+ return;
+}
+
+void dns_unmarshall_uint16(struct dns_buffer *buf, uint16 *val)
+{
+ uint16 n_val;
+
+ dns_unmarshall_buffer(buf, (uint8 *)&n_val, sizeof(n_val));
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ *val = ntohs(n_val);
+}
+
+void dns_unmarshall_uint32(struct dns_buffer *buf, uint32 *val)
+{
+ uint32 n_val;
+
+ dns_unmarshall_buffer(buf, (uint8 *)&n_val, sizeof(n_val));
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ *val = ntohl(n_val);
+}
+
+void dns_marshall_domain_name(struct dns_buffer *buf,
+ const struct dns_domain_name *name)
+{
+ struct dns_domain_label *label;
+ char end_char = '\0';
+
+ /*
+ * TODO: Implement DNS compression
+ */
+
+ for (label = name->pLabelList; label != NULL; label = label->next) {
+ uint8 len = label->len;
+
+ dns_marshall_buffer(buf, (uint8 *)&len, sizeof(len));
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ dns_marshall_buffer(buf, (uint8 *)label->label, len);
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+ }
+
+ dns_marshall_buffer(buf, (uint8 *)&end_char, 1);
+}
+
+static void dns_unmarshall_label(TALLOC_CTX *mem_ctx,
+ int level,
+ struct dns_buffer *buf,
+ struct dns_domain_label **plabel)
+{
+ struct dns_domain_label *label;
+ uint8 len;
+
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ if (level > 128) {
+ /*
+ * Protect against recursion
+ */
+ buf->error = ERROR_DNS_INVALID_MESSAGE;
+ return;
+ }
+
+ dns_unmarshall_buffer(buf, &len, sizeof(len));
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ if (len == 0) {
+ *plabel = NULL;
+ return;
+ }
+
+ if ((len & 0xc0) == 0xc0) {
+ /*
+ * We've got a compressed name. Build up a new "fake" buffer
+ * and using the calculated offset.
+ */
+ struct dns_buffer new_buf;
+ uint8 low;
+
+ dns_unmarshall_buffer(buf, &low, sizeof(low));
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ new_buf = *buf;
+ new_buf.offset = len & 0x3f;
+ new_buf.offset <<= 8;
+ new_buf.offset |= low;
+
+ dns_unmarshall_label(mem_ctx, level+1, &new_buf, plabel);
+ buf->error = new_buf.error;
+ return;
+ }
+
+ if ((len & 0xc0) != 0) {
+ buf->error = ERROR_DNS_INVALID_NAME;
+ return;
+ }
+
+ if (!(label = talloc(mem_ctx, struct dns_domain_label))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+
+ label->len = len;
+
+ if (!(label->label = TALLOC_ARRAY(label, char, len+1))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ goto error;
+ }
+
+ dns_unmarshall_buffer(buf, (uint8 *)label->label, len);
+ if (!ERR_DNS_IS_OK(buf->error)) goto error;
+
+ dns_unmarshall_label(label, level+1, buf, &label->next);
+ if (!ERR_DNS_IS_OK(buf->error)) goto error;
+
+ *plabel = label;
+ return;
+
+ error:
+ TALLOC_FREE(label);
+ return;
+}
+
+void dns_unmarshall_domain_name(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_domain_name **pname)
+{
+ struct dns_domain_name *name;
+
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ if (!(name = talloc(mem_ctx, struct dns_domain_name))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ }
+
+ dns_unmarshall_label(name, 0, buf, &name->pLabelList);
+
+ if (!ERR_DNS_IS_OK(buf->error)) {
+ return;
+ }
+
+ *pname = name;
+ return;
+}
+
+static void dns_marshall_question(struct dns_buffer *buf,
+ const struct dns_question *q)
+{
+ dns_marshall_domain_name(buf, q->name);
+ dns_marshall_uint16(buf, q->q_type);
+ dns_marshall_uint16(buf, q->q_class);
+}
+
+static void dns_unmarshall_question(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_question **pq)
+{
+ struct dns_question *q;
+
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ if (!(q = talloc(mem_ctx, struct dns_question))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+
+ dns_unmarshall_domain_name(q, buf, &q->name);
+ dns_unmarshall_uint16(buf, &q->q_type);
+ dns_unmarshall_uint16(buf, &q->q_class);
+
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ *pq = q;
+}
+
+static void dns_marshall_rr(struct dns_buffer *buf,
+ const struct dns_rrec *r)
+{
+ dns_marshall_domain_name(buf, r->name);
+ dns_marshall_uint16(buf, r->type);
+ dns_marshall_uint16(buf, r->r_class);
+ dns_marshall_uint32(buf, r->ttl);
+ dns_marshall_uint16(buf, r->data_length);
+ dns_marshall_buffer(buf, r->data, r->data_length);
+}
+
+static void dns_unmarshall_rr(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_rrec **pr)
+{
+ struct dns_rrec *r;
+
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ if (!(r = talloc(mem_ctx, struct dns_rrec))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+
+ dns_unmarshall_domain_name(r, buf, &r->name);
+ dns_unmarshall_uint16(buf, &r->type);
+ dns_unmarshall_uint16(buf, &r->r_class);
+ dns_unmarshall_uint32(buf, &r->ttl);
+ dns_unmarshall_uint16(buf, &r->data_length);
+ r->data = NULL;
+
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ if (r->data_length != 0) {
+ if (!(r->data = TALLOC_ARRAY(r, uint8, r->data_length))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+ dns_unmarshall_buffer(buf, r->data, r->data_length);
+ }
+
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ *pr = r;
+}
+
+DNS_ERROR dns_marshall_request(TALLOC_CTX *mem_ctx,
+ const struct dns_request *req,
+ struct dns_buffer **pbuf)
+{
+ struct dns_buffer *buf;
+ uint16 i;
+
+ if (!(buf = dns_create_buffer(mem_ctx))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ dns_marshall_uint16(buf, req->id);
+ dns_marshall_uint16(buf, req->flags);
+ dns_marshall_uint16(buf, req->num_questions);
+ dns_marshall_uint16(buf, req->num_answers);
+ dns_marshall_uint16(buf, req->num_auths);
+ dns_marshall_uint16(buf, req->num_additionals);
+
+ for (i=0; i<req->num_questions; i++) {
+ dns_marshall_question(buf, req->questions[i]);
+ }
+ for (i=0; i<req->num_answers; i++) {
+ dns_marshall_rr(buf, req->answers[i]);
+ }
+ for (i=0; i<req->num_auths; i++) {
+ dns_marshall_rr(buf, req->auths[i]);
+ }
+ for (i=0; i<req->num_additionals; i++) {
+ dns_marshall_rr(buf, req->additionals[i]);
+ }
+
+ if (!ERR_DNS_IS_OK(buf->error)) {
+ DNS_ERROR err = buf->error;
+ TALLOC_FREE(buf);
+ return err;
+ }
+
+ *pbuf = buf;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_unmarshall_request(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_request **preq)
+{
+ struct dns_request *req;
+ uint16 i;
+ DNS_ERROR err;
+
+ if (!(req = TALLOC_ZERO_P(mem_ctx, struct dns_request))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ dns_unmarshall_uint16(buf, &req->id);
+ dns_unmarshall_uint16(buf, &req->flags);
+ dns_unmarshall_uint16(buf, &req->num_questions);
+ dns_unmarshall_uint16(buf, &req->num_answers);
+ dns_unmarshall_uint16(buf, &req->num_auths);
+ dns_unmarshall_uint16(buf, &req->num_additionals);
+
+ if (!ERR_DNS_IS_OK(buf->error)) goto error;
+
+ err = ERROR_DNS_NO_MEMORY;
+
+ if ((req->num_questions != 0) &&
+ !(req->questions = TALLOC_ARRAY(req, struct dns_question *,
+ req->num_questions))) {
+ goto error;
+ }
+ if ((req->num_answers != 0) &&
+ !(req->answers = TALLOC_ARRAY(req, struct dns_rrec *,
+ req->num_answers))) {
+ goto error;
+ }
+ if ((req->num_auths != 0) &&
+ !(req->auths = TALLOC_ARRAY(req, struct dns_rrec *,
+ req->num_auths))) {
+ goto error;
+ }
+ if ((req->num_additionals != 0) &&
+ !(req->additionals = TALLOC_ARRAY(req, struct dns_rrec *,
+ req->num_additionals))) {
+ goto error;
+ }
+
+ for (i=0; i<req->num_questions; i++) {
+ dns_unmarshall_question(req->questions, buf,
+ &req->questions[i]);
+ }
+ for (i=0; i<req->num_answers; i++) {
+ dns_unmarshall_rr(req->answers, buf,
+ &req->answers[i]);
+ }
+ for (i=0; i<req->num_auths; i++) {
+ dns_unmarshall_rr(req->auths, buf,
+ &req->auths[i]);
+ }
+ for (i=0; i<req->num_additionals; i++) {
+ dns_unmarshall_rr(req->additionals, buf,
+ &req->additionals[i]);
+ }
+
+ if (!ERR_DNS_IS_OK(buf->error)) {
+ err = buf->error;
+ goto error;
+ }
+
+ *preq = req;
+ return ERROR_DNS_SUCCESS;
+
+ error:
+ err = buf->error;
+ TALLOC_FREE(req);
+ return err;
+}
+
+struct dns_request *dns_update2request(struct dns_update_request *update)
+{
+ struct dns_request *req;
+
+ /*
+ * This is a non-specified construct that happens to work on Linux/gcc
+ * and I would expect it to work everywhere else. dns_request and
+ * dns_update_request are essentially the same structures with
+ * different names, so any difference would mean that the compiler
+ * applied two different variations of padding given the same types in
+ * the structures.
+ */
+
+ req = (struct dns_request *)(void *)update;
+
+ /*
+ * The assert statement here looks like we could do the equivalent
+ * assignments to get portable, but it would mean that we have to
+ * allocate the dns_question record for the dns_zone records. We
+ * assume that if this assert works then the same holds true for
+ * dns_zone<>dns_question as well.
+ */
+
+#ifdef DEVELOPER
+ assert((req->id == update->id) && (req->flags == update->flags) &&
+ (req->num_questions == update->num_zones) &&
+ (req->num_answers == update->num_preqs) &&
+ (req->num_auths == update->num_updates) &&
+ (req->num_additionals == update->num_additionals) &&
+ (req->questions ==
+ (struct dns_question **)(void *)update->zones) &&
+ (req->answers == update->preqs) &&
+ (req->auths == update->updates) &&
+ (req->additionals == update->additionals));
+#endif
+
+ return req;
+}
+
+struct dns_update_request *dns_request2update(struct dns_request *request)
+{
+ /*
+ * For portability concerns see dns_update2request;
+ */
+ return (struct dns_update_request *)(void *)request;
+}
+
+DNS_ERROR dns_marshall_update_request(TALLOC_CTX *mem_ctx,
+ struct dns_update_request *update,
+ struct dns_buffer **pbuf)
+{
+ return dns_marshall_request(mem_ctx, dns_update2request(update), pbuf);
+}
+
+DNS_ERROR dns_unmarshall_update_request(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_update_request **pupreq)
+{
+ /*
+ * See comments above about portability. If the above works, this will
+ * as well.
+ */
+
+ return dns_unmarshall_request(mem_ctx, buf,
+ (struct dns_request **)(void *)pupreq);
+}
+
+uint16 dns_response_code(uint16 flags)
+{
+ return flags & 0xF;
+}
diff --git a/source3/libaddns/dnsrecord.c b/source3/libaddns/dnsrecord.c
new file mode 100644
index 0000000000..500cbd6681
--- /dev/null
+++ b/source3/libaddns/dnsrecord.c
@@ -0,0 +1,422 @@
+/*
+ Linux DNS client library implementation
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dns.h"
+
+DNS_ERROR dns_create_query( TALLOC_CTX *mem_ctx, const char *name,
+ uint16 q_type, uint16 q_class,
+ struct dns_request **preq )
+{
+ struct dns_request *req;
+ struct dns_question *q;
+ DNS_ERROR err;
+
+ if (!(req = TALLOC_ZERO_P(mem_ctx, struct dns_request)) ||
+ !(req->questions = TALLOC_ARRAY(req, struct dns_question *, 1)) ||
+ !(req->questions[0] = talloc(req->questions,
+ struct dns_question))) {
+ TALLOC_FREE(req);
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ req->id = random();
+
+ req->num_questions = 1;
+ q = req->questions[0];
+
+ err = dns_domain_name_from_string(q, name, &q->name);
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(req);
+ return err;
+ }
+
+ q->q_type = q_type;
+ q->q_class = q_class;
+
+ *preq = req;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_create_update( TALLOC_CTX *mem_ctx, const char *name,
+ struct dns_update_request **preq )
+{
+ struct dns_update_request *req;
+ struct dns_zone *z;
+ DNS_ERROR err;
+
+ if (!(req = TALLOC_ZERO_P(mem_ctx, struct dns_update_request)) ||
+ !(req->zones = TALLOC_ARRAY(req, struct dns_zone *, 1)) ||
+ !(req->zones[0] = talloc(req->zones, struct dns_zone))) {
+ TALLOC_FREE(req);
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ req->id = random();
+ req->flags = 0x2800; /* Dynamic update */
+
+ req->num_zones = 1;
+ z = req->zones[0];
+
+ err = dns_domain_name_from_string(z, name, &z->name);
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(req);
+ return err;
+ }
+
+ z->z_type = QTYPE_SOA;
+ z->z_class = DNS_CLASS_IN;
+
+ *preq = req;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_create_rrec(TALLOC_CTX *mem_ctx, const char *name,
+ uint16 type, uint16 r_class, uint32 ttl,
+ uint16 data_length, uint8 *data,
+ struct dns_rrec **prec)
+{
+ struct dns_rrec *rec;
+ DNS_ERROR err;
+
+ if (!(rec = talloc(mem_ctx, struct dns_rrec))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = dns_domain_name_from_string(rec, name, &rec->name);
+ if (!(ERR_DNS_IS_OK(err))) {
+ TALLOC_FREE(rec);
+ return err;
+ }
+
+ rec->type = type;
+ rec->r_class = r_class;
+ rec->ttl = ttl;
+ rec->data_length = data_length;
+ rec->data = talloc_move(rec, &data);
+
+ *prec = rec;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_create_a_record(TALLOC_CTX *mem_ctx, const char *host,
+ uint32 ttl, const struct sockaddr_storage *pss,
+ struct dns_rrec **prec)
+{
+ uint8 *data;
+ DNS_ERROR err;
+ struct in_addr ip;
+
+ if (pss->ss_family != AF_INET) {
+ /* Silently ignore this. */
+ return ERROR_DNS_SUCCESS;
+ }
+
+ ip = ((struct sockaddr_in *)pss)->sin_addr;
+ if (!(data = (uint8 *)TALLOC_MEMDUP(mem_ctx, (const void *)&ip.s_addr,
+ sizeof(ip.s_addr)))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = dns_create_rrec(mem_ctx, host, QTYPE_A, DNS_CLASS_IN, ttl,
+ sizeof(ip.s_addr), data, prec);
+
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(data);
+ }
+
+ return err;
+}
+
+DNS_ERROR dns_create_name_in_use_record(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const struct sockaddr_storage *ss,
+ struct dns_rrec **prec)
+{
+ if (ss != NULL) {
+ return dns_create_a_record(mem_ctx, name, 0, ss, prec);
+ }
+
+ return dns_create_rrec(mem_ctx, name, QTYPE_ANY, DNS_CLASS_IN, 0, 0,
+ NULL, prec);
+}
+
+DNS_ERROR dns_create_name_not_in_use_record(TALLOC_CTX *mem_ctx,
+ const char *name, uint32 type,
+ struct dns_rrec **prec)
+{
+ return dns_create_rrec(mem_ctx, name, type, DNS_CLASS_NONE, 0,
+ 0, NULL, prec);
+}
+
+DNS_ERROR dns_create_delete_record(TALLOC_CTX *mem_ctx, const char *name,
+ uint16 type, uint16 r_class,
+ struct dns_rrec **prec)
+{
+ return dns_create_rrec(mem_ctx, name, type, r_class, 0, 0, NULL, prec);
+}
+
+DNS_ERROR dns_create_tkey_record(TALLOC_CTX *mem_ctx, const char *keyname,
+ const char *algorithm_name, time_t inception,
+ time_t expiration, uint16 mode, uint16 error,
+ uint16 key_length, const uint8 *key,
+ struct dns_rrec **prec)
+{
+ struct dns_buffer *buf;
+ struct dns_domain_name *algorithm;
+ DNS_ERROR err;
+
+ if (!(buf = dns_create_buffer(mem_ctx))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ dns_marshall_domain_name(buf, algorithm);
+ dns_marshall_uint32(buf, inception);
+ dns_marshall_uint32(buf, expiration);
+ dns_marshall_uint16(buf, mode);
+ dns_marshall_uint16(buf, error);
+ dns_marshall_uint16(buf, key_length);
+ dns_marshall_buffer(buf, key, key_length);
+ dns_marshall_uint16(buf, 0); /* Other Size */
+
+ if (!ERR_DNS_IS_OK(buf->error)) {
+ err = buf->error;
+ goto error;
+ }
+
+ err = dns_create_rrec(mem_ctx, keyname, QTYPE_TKEY, DNS_CLASS_ANY, 0,
+ buf->offset, buf->data, prec);
+
+ error:
+ TALLOC_FREE(buf);
+ return err;
+}
+
+DNS_ERROR dns_unmarshall_tkey_record(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
+ struct dns_tkey_record **ptkey)
+{
+ struct dns_tkey_record *tkey;
+ struct dns_buffer buf;
+ uint32 tmp_inception, tmp_expiration;
+
+ if (!(tkey = talloc(mem_ctx, struct dns_tkey_record))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ buf.data = rec->data;
+ buf.size = rec->data_length;
+ buf.offset = 0;
+ buf.error = ERROR_DNS_SUCCESS;
+
+ dns_unmarshall_domain_name(tkey, &buf, &tkey->algorithm);
+ dns_unmarshall_uint32(&buf, &tmp_inception);
+ dns_unmarshall_uint32(&buf, &tmp_expiration);
+ dns_unmarshall_uint16(&buf, &tkey->mode);
+ dns_unmarshall_uint16(&buf, &tkey->error);
+ dns_unmarshall_uint16(&buf, &tkey->key_length);
+
+ if (!ERR_DNS_IS_OK(buf.error)) goto error;
+
+ if (tkey->key_length) {
+ if (!(tkey->key = TALLOC_ARRAY(tkey, uint8, tkey->key_length))) {
+ buf.error = ERROR_DNS_NO_MEMORY;
+ goto error;
+ }
+ } else {
+ tkey->key = NULL;
+ }
+
+ dns_unmarshall_buffer(&buf, tkey->key, tkey->key_length);
+ if (!ERR_DNS_IS_OK(buf.error)) goto error;
+
+ tkey->inception = (time_t)tmp_inception;
+ tkey->expiration = (time_t)tmp_expiration;
+
+ *ptkey = tkey;
+ return ERROR_DNS_SUCCESS;
+
+ error:
+ TALLOC_FREE(tkey);
+ return buf.error;
+}
+
+DNS_ERROR dns_create_tsig_record(TALLOC_CTX *mem_ctx, const char *keyname,
+ const char *algorithm_name,
+ time_t time_signed, uint16 fudge,
+ uint16 mac_length, const uint8 *mac,
+ uint16 original_id, uint16 error,
+ struct dns_rrec **prec)
+{
+ struct dns_buffer *buf;
+ struct dns_domain_name *algorithm;
+ DNS_ERROR err;
+
+ if (!(buf = dns_create_buffer(mem_ctx))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ dns_marshall_domain_name(buf, algorithm);
+ dns_marshall_uint16(buf, 0); /* time prefix */
+ dns_marshall_uint32(buf, time_signed);
+ dns_marshall_uint16(buf, fudge);
+ dns_marshall_uint16(buf, mac_length);
+ dns_marshall_buffer(buf, mac, mac_length);
+ dns_marshall_uint16(buf, original_id);
+ dns_marshall_uint16(buf, error);
+ dns_marshall_uint16(buf, 0); /* Other Size */
+
+ if (!ERR_DNS_IS_OK(buf->error)) {
+ err = buf->error;
+ goto error;
+ }
+
+ err = dns_create_rrec(mem_ctx, keyname, QTYPE_TSIG, DNS_CLASS_ANY, 0,
+ buf->offset, buf->data, prec);
+
+ error:
+ TALLOC_FREE(buf);
+ return err;
+}
+
+DNS_ERROR dns_add_rrec(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
+ uint16 *num_records, struct dns_rrec ***records)
+{
+ struct dns_rrec **new_records;
+
+ if (!(new_records = TALLOC_REALLOC_ARRAY(mem_ctx, *records,
+ struct dns_rrec *,
+ (*num_records)+1))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ new_records[*num_records] = talloc_move(new_records, &rec);
+
+ *num_records += 1;
+ *records = new_records;
+ return ERROR_DNS_SUCCESS;
+}
+
+/*
+ * Create a request that probes a server whether the list of IP addresses
+ * provides meets our expectations
+ */
+
+DNS_ERROR dns_create_probe(TALLOC_CTX *mem_ctx, const char *zone,
+ const char *host, int num_ips,
+ const struct sockaddr_storage *sslist,
+ struct dns_update_request **preq)
+{
+ struct dns_update_request *req;
+ struct dns_rrec *rec;
+ DNS_ERROR err;
+ uint16 i;
+
+ err = dns_create_update(mem_ctx, zone, &req);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_create_name_not_in_use_record(req, host, QTYPE_CNAME, &rec);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ for (i=0; i<num_ips; i++) {
+ err = dns_create_name_in_use_record(req, host,
+ &sslist[i], &rec);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+ }
+
+ *preq = req;
+ return ERROR_DNS_SUCCESS;
+
+ error:
+ TALLOC_FREE(req);
+ return err;
+}
+
+DNS_ERROR dns_create_update_request(TALLOC_CTX *mem_ctx,
+ const char *domainname,
+ const char *hostname,
+ const struct sockaddr_storage *ss_addrs,
+ size_t num_addrs,
+ struct dns_update_request **preq)
+{
+ struct dns_update_request *req;
+ struct dns_rrec *rec;
+ DNS_ERROR err;
+ size_t i;
+
+ err = dns_create_update(mem_ctx, domainname, &req);
+ if (!ERR_DNS_IS_OK(err)) return err;
+
+ /*
+ * The zone must be used at all
+ */
+
+ err = dns_create_rrec(req, domainname, QTYPE_ANY, DNS_CLASS_ANY,
+ 0, 0, NULL, &rec);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ /*
+ * Delete any existing A records
+ */
+
+ err = dns_create_delete_record(req, hostname, QTYPE_A, DNS_CLASS_ANY,
+ &rec);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ /*
+ * .. and add our IPs
+ */
+
+ for ( i=0; i<num_addrs; i++ ) {
+ err = dns_create_a_record(req, hostname, 3600, &ss_addrs[i], &rec);
+ if (!ERR_DNS_IS_OK(err))
+ goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
+ if (!ERR_DNS_IS_OK(err))
+ goto error;
+ }
+
+ *preq = req;
+ return ERROR_DNS_SUCCESS;
+
+ error:
+ TALLOC_FREE(req);
+ return err;
+}
diff --git a/source3/libaddns/dnssock.c b/source3/libaddns/dnssock.c
new file mode 100644
index 0000000000..7c8bd418e5
--- /dev/null
+++ b/source3/libaddns/dnssock.c
@@ -0,0 +1,377 @@
+/*
+ Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dns.h"
+#include <sys/time.h>
+#include <unistd.h>
+
+static int destroy_dns_connection(struct dns_connection *conn)
+{
+ return close(conn->s);
+}
+
+/********************************************************************
+********************************************************************/
+
+static DNS_ERROR dns_tcp_open( const char *nameserver,
+ TALLOC_CTX *mem_ctx,
+ struct dns_connection **result )
+{
+ uint32_t ulAddress;
+ struct hostent *pHost;
+ struct sockaddr_in s_in;
+ struct dns_connection *conn;
+ int res;
+
+ if (!(conn = talloc(mem_ctx, struct dns_connection))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) {
+ if ( (pHost = gethostbyname( nameserver )) == NULL ) {
+ TALLOC_FREE(conn);
+ return ERROR_DNS_INVALID_NAME_SERVER;
+ }
+ memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
+ }
+
+ conn->s = socket( PF_INET, SOCK_STREAM, 0 );
+ if (conn->s == -1) {
+ TALLOC_FREE(conn);
+ return ERROR_DNS_CONNECTION_FAILED;
+ }
+
+ talloc_set_destructor(conn, destroy_dns_connection);
+
+ s_in.sin_family = AF_INET;
+ s_in.sin_addr.s_addr = ulAddress;
+ s_in.sin_port = htons( DNS_TCP_PORT );
+
+ res = connect(conn->s, (struct sockaddr*)&s_in, sizeof( s_in ));
+ if (res == -1) {
+ TALLOC_FREE(conn);
+ return ERROR_DNS_CONNECTION_FAILED;
+ }
+
+ conn->hType = DNS_TCP;
+
+ *result = conn;
+ return ERROR_DNS_SUCCESS;
+}
+
+/********************************************************************
+********************************************************************/
+
+static DNS_ERROR dns_udp_open( const char *nameserver,
+ TALLOC_CTX *mem_ctx,
+ struct dns_connection **result )
+{
+ unsigned long ulAddress;
+ struct hostent *pHost;
+ struct sockaddr_in RecvAddr;
+ struct dns_connection *conn;
+
+ if (!(conn = talloc(NULL, struct dns_connection))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) {
+ if ( (pHost = gethostbyname( nameserver )) == NULL ) {
+ TALLOC_FREE(conn);
+ return ERROR_DNS_INVALID_NAME_SERVER;
+ }
+ memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
+ }
+
+ /* Create a socket for sending data */
+
+ conn->s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
+ if (conn->s == -1) {
+ TALLOC_FREE(conn);
+ return ERROR_DNS_CONNECTION_FAILED;
+ }
+
+ talloc_set_destructor(conn, destroy_dns_connection);
+
+ /* Set up the RecvAddr structure with the IP address of
+ the receiver (in this example case "123.456.789.1")
+ and the specified port number. */
+
+ ZERO_STRUCT(RecvAddr);
+ RecvAddr.sin_family = AF_INET;
+ RecvAddr.sin_port = htons( DNS_UDP_PORT );
+ RecvAddr.sin_addr.s_addr = ulAddress;
+
+ conn->hType = DNS_UDP;
+ memcpy( &conn->RecvAddr, &RecvAddr, sizeof( struct sockaddr_in ) );
+
+ *result = conn;
+ return ERROR_DNS_SUCCESS;
+}
+
+/********************************************************************
+********************************************************************/
+
+DNS_ERROR dns_open_connection( const char *nameserver, int32 dwType,
+ TALLOC_CTX *mem_ctx,
+ struct dns_connection **conn )
+{
+ switch ( dwType ) {
+ case DNS_TCP:
+ return dns_tcp_open( nameserver, mem_ctx, conn );
+ case DNS_UDP:
+ return dns_udp_open( nameserver, mem_ctx, conn );
+ }
+
+ return ERROR_DNS_INVALID_PARAMETER;
+}
+
+static DNS_ERROR write_all(int fd, uint8 *data, size_t len)
+{
+ size_t total = 0;
+
+ while (total < len) {
+
+ ssize_t ret = write(fd, data + total, len - total);
+
+ if (ret <= 0) {
+ /*
+ * EOF or error
+ */
+ return ERROR_DNS_SOCKET_ERROR;
+ }
+
+ total += ret;
+ }
+
+ return ERROR_DNS_SUCCESS;
+}
+
+static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
+ const struct dns_buffer *buf)
+{
+ uint16 len = htons(buf->offset);
+ DNS_ERROR err;
+
+ err = write_all(conn->s, (uint8 *)&len, sizeof(len));
+ if (!ERR_DNS_IS_OK(err)) return err;
+
+ return write_all(conn->s, buf->data, buf->offset);
+}
+
+static DNS_ERROR dns_send_udp(struct dns_connection *conn,
+ const struct dns_buffer *buf)
+{
+ ssize_t ret;
+
+ ret = sendto(conn->s, buf->data, buf->offset, 0,
+ (struct sockaddr *)&conn->RecvAddr,
+ sizeof(conn->RecvAddr));
+
+ if (ret != buf->offset) {
+ return ERROR_DNS_SOCKET_ERROR;
+ }
+
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
+{
+ if (conn->hType == DNS_TCP) {
+ return dns_send_tcp(conn, buf);
+ }
+
+ if (conn->hType == DNS_UDP) {
+ return dns_send_udp(conn, buf);
+ }
+
+ return ERROR_DNS_INVALID_PARAMETER;
+}
+
+static DNS_ERROR read_all(int fd, uint8 *data, size_t len)
+{
+ size_t total = 0;
+ fd_set rfds;
+ struct timeval tv;
+
+ while (total < len) {
+ ssize_t ret;
+ int fd_ready;
+
+ FD_ZERO( &rfds );
+ FD_SET( fd, &rfds );
+
+ /* 10 second timeout */
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+
+ fd_ready = select( fd+1, &rfds, NULL, NULL, &tv );
+ if ( fd_ready == 0 ) {
+ /* read timeout */
+ return ERROR_DNS_SOCKET_ERROR;
+ }
+
+ ret = read(fd, data + total, len - total);
+ if (ret <= 0) {
+ /* EOF or error */
+ return ERROR_DNS_SOCKET_ERROR;
+ }
+
+ total += ret;
+ }
+
+ return ERROR_DNS_SUCCESS;
+}
+
+static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
+ struct dns_connection *conn,
+ struct dns_buffer **presult)
+{
+ struct dns_buffer *buf;
+ DNS_ERROR err;
+ uint16 len;
+
+ if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = read_all(conn->s, (uint8 *)&len, sizeof(len));
+ if (!ERR_DNS_IS_OK(err)) {
+ return err;
+ }
+
+ buf->size = ntohs(len);
+
+ if (buf->size) {
+ if (!(buf->data = TALLOC_ARRAY(buf, uint8, buf->size))) {
+ TALLOC_FREE(buf);
+ return ERROR_DNS_NO_MEMORY;
+ }
+ } else {
+ buf->data = NULL;
+ }
+
+ err = read_all(conn->s, buf->data, buf->size);
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(buf);
+ return err;
+ }
+
+ *presult = buf;
+ return ERROR_DNS_SUCCESS;
+}
+
+static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
+ struct dns_connection *conn,
+ struct dns_buffer **presult)
+{
+ struct dns_buffer *buf;
+ ssize_t received;
+
+ if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ /*
+ * UDP based DNS can only be 512 bytes
+ */
+
+ if (!(buf->data = TALLOC_ARRAY(buf, uint8, 512))) {
+ TALLOC_FREE(buf);
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ received = recv(conn->s, (void *)buf->data, 512, 0);
+
+ if (received == -1) {
+ TALLOC_FREE(buf);
+ return ERROR_DNS_SOCKET_ERROR;
+ }
+
+ if (received > 512) {
+ TALLOC_FREE(buf);
+ return ERROR_DNS_BAD_RESPONSE;
+ }
+
+ buf->size = received;
+ buf->offset = 0;
+
+ *presult = buf;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
+ struct dns_buffer **presult)
+{
+ if (conn->hType == DNS_TCP) {
+ return dns_receive_tcp(mem_ctx, conn, presult);
+ }
+
+ if (conn->hType == DNS_UDP) {
+ return dns_receive_udp(mem_ctx, conn, presult);
+ }
+
+ return ERROR_DNS_INVALID_PARAMETER;
+}
+
+DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
+ const struct dns_request *req,
+ struct dns_request **resp)
+{
+ struct dns_buffer *buf = NULL;
+ DNS_ERROR err;
+
+ err = dns_marshall_request(conn, req, &buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_send(conn, buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+ TALLOC_FREE(buf);
+
+ err = dns_receive(mem_ctx, conn, &buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_unmarshall_request(mem_ctx, buf, resp);
+
+ error:
+ TALLOC_FREE(buf);
+ return err;
+}
+
+DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
+ struct dns_connection *conn,
+ struct dns_update_request *up_req,
+ struct dns_update_request **up_resp)
+{
+ struct dns_request *resp;
+ DNS_ERROR err;
+
+ err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
+ &resp);
+
+ if (!ERR_DNS_IS_OK(err)) return err;
+
+ *up_resp = dns_request2update(resp);
+ return ERROR_DNS_SUCCESS;
+}
diff --git a/source3/libaddns/dnsutils.c b/source3/libaddns/dnsutils.c
new file mode 100644
index 0000000000..37b862c7f0
--- /dev/null
+++ b/source3/libaddns/dnsutils.c
@@ -0,0 +1,151 @@
+/*
+ Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dns.h"
+#include <ctype.h>
+
+static DNS_ERROR LabelList( TALLOC_CTX *mem_ctx,
+ const char *name,
+ struct dns_domain_label **presult )
+{
+ struct dns_domain_label *result;
+ const char *dot;
+
+ for (dot = name; *dot != '\0'; dot += 1) {
+ char c = *dot;
+
+ if (c == '.')
+ break;
+
+ if (c == '-') continue;
+ if ((c >= 'a') && (c <= 'z')) continue;
+ if ((c >= 'A') && (c <= 'Z')) continue;
+ if ((c >= '0') && (c <= '9')) continue;
+
+ return ERROR_DNS_INVALID_NAME;
+ }
+
+ if ((dot - name) > 63) {
+ /*
+ * DNS labels can only be 63 chars long
+ */
+ return ERROR_DNS_INVALID_NAME;
+ }
+
+ if (!(result = TALLOC_ZERO_P(mem_ctx, struct dns_domain_label))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ if (*dot == '\0') {
+ /*
+ * No dot around, so this is the last component
+ */
+
+ if (!(result->label = talloc_strdup(result, name))) {
+ TALLOC_FREE(result);
+ return ERROR_DNS_NO_MEMORY;
+ }
+ result->len = strlen(result->label);
+ *presult = result;
+ return ERROR_DNS_SUCCESS;
+ }
+
+ if (dot[1] == '.') {
+ /*
+ * Two dots in a row, reject
+ */
+
+ TALLOC_FREE(result);
+ return ERROR_DNS_INVALID_NAME;
+ }
+
+ if (dot[1] != '\0') {
+ /*
+ * Something follows, get the rest
+ */
+
+ DNS_ERROR err = LabelList(result, dot+1, &result->next);
+
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(result);
+ return err;
+ }
+ }
+
+ result->len = (dot - name);
+
+ if (!(result->label = talloc_strndup(result, name, result->len))) {
+ TALLOC_FREE(result);
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ *presult = result;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_domain_name_from_string( TALLOC_CTX *mem_ctx,
+ const char *pszDomainName,
+ struct dns_domain_name **presult )
+{
+ struct dns_domain_name *result;
+ DNS_ERROR err;
+
+ if (!(result = talloc(mem_ctx, struct dns_domain_name))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = LabelList( result, pszDomainName, &result->pLabelList );
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(result);
+ return err;
+ }
+
+ *presult = result;
+ return ERROR_DNS_SUCCESS;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+char *dns_generate_keyname( TALLOC_CTX *mem_ctx )
+{
+ char *result = NULL;
+#if defined(WITH_DNS_UPDATES)
+
+ uuid_t uuid;
+
+ /*
+ * uuid_unparse gives 36 bytes plus '\0'
+ */
+ if (!(result = TALLOC_ARRAY(mem_ctx, char, 37))) {
+ return NULL;
+ }
+
+ uuid_generate( uuid );
+ uuid_unparse( uuid, result );
+
+#endif
+
+ return result;
+}
diff --git a/source3/libads/ads_status.c b/source3/libads/ads_status.c
new file mode 100644
index 0000000000..29148e8543
--- /dev/null
+++ b/source3/libads/ads_status.c
@@ -0,0 +1,152 @@
+/*
+ Unix SMB/CIFS implementation.
+ ads (active directory) utility library
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Remus Koos 2001
+ Copyright (C) Andrew Bartlett 2001
+
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*
+ build a ADS_STATUS structure
+*/
+ADS_STATUS ads_build_error(enum ads_error_type etype,
+ int rc, int minor_status)
+{
+ ADS_STATUS ret;
+
+ if (etype == ENUM_ADS_ERROR_NT) {
+ DEBUG(0,("don't use ads_build_error with ENUM_ADS_ERROR_NT!\n"));
+ ret.err.rc = -1;
+ ret.error_type = ENUM_ADS_ERROR_SYSTEM;
+ ret.minor_status = 0;
+ return ret;
+ }
+
+ ret.err.rc = rc;
+ ret.error_type = etype;
+ ret.minor_status = minor_status;
+ return ret;
+}
+
+ADS_STATUS ads_build_nt_error(enum ads_error_type etype,
+ NTSTATUS nt_status)
+{
+ ADS_STATUS ret;
+
+ if (etype != ENUM_ADS_ERROR_NT) {
+ DEBUG(0,("don't use ads_build_nt_error without ENUM_ADS_ERROR_NT!\n"));
+ ret.err.rc = -1;
+ ret.error_type = ENUM_ADS_ERROR_SYSTEM;
+ ret.minor_status = 0;
+ return ret;
+ }
+ ret.err.nt_status = nt_status;
+ ret.error_type = etype;
+ ret.minor_status = 0;
+ return ret;
+}
+
+/*
+ do a rough conversion between ads error codes and NT status codes
+ we'll need to fill this in more
+*/
+NTSTATUS ads_ntstatus(ADS_STATUS status)
+{
+ switch (status.error_type) {
+ case ENUM_ADS_ERROR_NT:
+ return status.err.nt_status;
+ case ENUM_ADS_ERROR_SYSTEM:
+ return map_nt_error_from_unix(status.err.rc);
+#ifdef HAVE_LDAP
+ case ENUM_ADS_ERROR_LDAP:
+ if (status.err.rc == LDAP_SUCCESS) {
+ return NT_STATUS_OK;
+ }
+ return NT_STATUS_LDAP(status.err.rc);
+#endif
+#ifdef HAVE_KRB5
+ case ENUM_ADS_ERROR_KRB5:
+ return krb5_to_nt_status(status.err.rc);
+#endif
+ default:
+ break;
+ }
+
+ if (ADS_ERR_OK(status)) {
+ return NT_STATUS_OK;
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/*
+ return a string for an error from a ads routine
+*/
+const char *ads_errstr(ADS_STATUS status)
+{
+ switch (status.error_type) {
+ case ENUM_ADS_ERROR_SYSTEM:
+ return strerror(status.err.rc);
+#ifdef HAVE_LDAP
+ case ENUM_ADS_ERROR_LDAP:
+ return ldap_err2string(status.err.rc);
+#endif
+#ifdef HAVE_KRB5
+ case ENUM_ADS_ERROR_KRB5:
+ return error_message(status.err.rc);
+#endif
+#ifdef HAVE_GSSAPI
+ case ENUM_ADS_ERROR_GSS:
+ {
+ char *ret;
+ uint32 msg_ctx;
+ uint32 minor;
+ gss_buffer_desc msg1, msg2;
+
+ msg_ctx = 0;
+
+ msg1.value = NULL;
+ msg2.value = NULL;
+ gss_display_status(&minor, status.err.rc, GSS_C_GSS_CODE,
+ GSS_C_NULL_OID, &msg_ctx, &msg1);
+ gss_display_status(&minor, status.minor_status, GSS_C_MECH_CODE,
+ GSS_C_NULL_OID, &msg_ctx, &msg2);
+ ret = talloc_asprintf(talloc_tos(), "%s : %s",
+ (char *)msg1.value, (char *)msg2.value);
+ SMB_ASSERT(ret != NULL);
+ gss_release_buffer(&minor, &msg1);
+ gss_release_buffer(&minor, &msg2);
+ return ret;
+ }
+#endif
+ case ENUM_ADS_ERROR_NT:
+ return get_friendly_nt_error_msg(ads_ntstatus(status));
+ default:
+ return "Unknown ADS error type!? (not compiled in?)";
+ }
+}
+
+#ifdef HAVE_GSSAPI
+NTSTATUS gss_err_to_ntstatus(uint32 maj, uint32 min)
+{
+ ADS_STATUS adss = ADS_ERROR_GSS(maj, min);
+ DEBUG(10,("gss_err_to_ntstatus: Error %s\n",
+ ads_errstr(adss) ));
+ return ads_ntstatus(adss);
+}
+#endif
diff --git a/source3/libads/ads_struct.c b/source3/libads/ads_struct.c
new file mode 100644
index 0000000000..8cc2f1215e
--- /dev/null
+++ b/source3/libads/ads_struct.c
@@ -0,0 +1,183 @@
+/*
+ Unix SMB/CIFS implementation.
+ ads (active directory) utility library
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* return a ldap dn path from a string, given separators and field name
+ caller must free
+*/
+char *ads_build_path(const char *realm, const char *sep, const char *field, int reverse)
+{
+ char *p, *r;
+ int numbits = 0;
+ char *ret;
+ int len;
+ char *saveptr;
+
+ r = SMB_STRDUP(realm);
+
+ if (!r || !*r) {
+ return r;
+ }
+
+ for (p=r; *p; p++) {
+ if (strchr(sep, *p)) {
+ numbits++;
+ }
+ }
+
+ len = (numbits+1)*(strlen(field)+1) + strlen(r) + 1;
+
+ ret = (char *)SMB_MALLOC(len);
+ if (!ret) {
+ free(r);
+ return NULL;
+ }
+
+ strlcpy(ret,field, len);
+ p=strtok_r(r, sep, &saveptr);
+ if (p) {
+ strlcat(ret, p, len);
+
+ while ((p=strtok_r(NULL, sep, &saveptr)) != NULL) {
+ char *s;
+ if (reverse)
+ asprintf(&s, "%s%s,%s", field, p, ret);
+ else
+ asprintf(&s, "%s,%s%s", ret, field, p);
+ free(ret);
+ ret = SMB_STRDUP(s);
+ free(s);
+ }
+ }
+
+ free(r);
+ return ret;
+}
+
+/* return a dn of the form "dc=AA,dc=BB,dc=CC" from a
+ realm of the form AA.BB.CC
+ caller must free
+*/
+char *ads_build_dn(const char *realm)
+{
+ return ads_build_path(realm, ".", "dc=", 0);
+}
+
+/* return a DNS name in the for aa.bb.cc from the DN
+ "dc=AA,dc=BB,dc=CC". caller must free
+*/
+char *ads_build_domain(const char *dn)
+{
+ char *dnsdomain = NULL;
+
+ /* result should always be shorter than the DN */
+
+ if ( (dnsdomain = SMB_STRDUP( dn )) == NULL ) {
+ DEBUG(0,("ads_build_domain: malloc() failed!\n"));
+ return NULL;
+ }
+
+ strlower_m( dnsdomain );
+ all_string_sub( dnsdomain, "dc=", "", 0);
+ all_string_sub( dnsdomain, ",", ".", 0 );
+
+ return dnsdomain;
+}
+
+
+
+#ifndef LDAP_PORT
+#define LDAP_PORT 389
+#endif
+
+/*
+ initialise a ADS_STRUCT, ready for some ads_ ops
+*/
+ADS_STRUCT *ads_init(const char *realm,
+ const char *workgroup,
+ const char *ldap_server)
+{
+ ADS_STRUCT *ads;
+ int wrap_flags;
+
+ ads = SMB_XMALLOC_P(ADS_STRUCT);
+ ZERO_STRUCTP(ads);
+
+ ads->server.realm = realm? SMB_STRDUP(realm) : NULL;
+ ads->server.workgroup = workgroup ? SMB_STRDUP(workgroup) : NULL;
+ ads->server.ldap_server = ldap_server? SMB_STRDUP(ldap_server) : NULL;
+
+ /* we need to know if this is a foreign realm */
+ if (realm && *realm && !strequal(lp_realm(), realm)) {
+ ads->server.foreign = 1;
+ }
+ if (workgroup && *workgroup && !strequal(lp_workgroup(), workgroup)) {
+ ads->server.foreign = 1;
+ }
+
+ /* the caller will own the memory by default */
+ ads->is_mine = 1;
+
+ wrap_flags = lp_client_ldap_sasl_wrapping();
+ if (wrap_flags == -1) {
+ wrap_flags = 0;
+ }
+
+ ads->auth.flags = wrap_flags;
+
+ return ads;
+}
+
+/*
+ free the memory used by the ADS structure initialized with 'ads_init(...)'
+*/
+void ads_destroy(ADS_STRUCT **ads)
+{
+ if (ads && *ads) {
+ bool is_mine;
+
+ is_mine = (*ads)->is_mine;
+#if HAVE_LDAP
+ ads_disconnect(*ads);
+#endif
+ SAFE_FREE((*ads)->server.realm);
+ SAFE_FREE((*ads)->server.workgroup);
+ SAFE_FREE((*ads)->server.ldap_server);
+
+ SAFE_FREE((*ads)->auth.realm);
+ SAFE_FREE((*ads)->auth.password);
+ SAFE_FREE((*ads)->auth.user_name);
+ SAFE_FREE((*ads)->auth.kdc_server);
+
+ SAFE_FREE((*ads)->config.realm);
+ SAFE_FREE((*ads)->config.bind_path);
+ SAFE_FREE((*ads)->config.ldap_server_name);
+ SAFE_FREE((*ads)->config.server_site_name);
+ SAFE_FREE((*ads)->config.client_site_name);
+ SAFE_FREE((*ads)->config.schema_path);
+ SAFE_FREE((*ads)->config.config_path);
+
+ ZERO_STRUCTP(*ads);
+
+ if ( is_mine )
+ SAFE_FREE(*ads);
+ }
+}
diff --git a/source3/libads/ads_utils.c b/source3/libads/ads_utils.c
new file mode 100644
index 0000000000..68efd69db9
--- /dev/null
+++ b/source3/libads/ads_utils.c
@@ -0,0 +1,150 @@
+/*
+ Unix SMB/CIFS implementation.
+ ads (active directory) utility library
+
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*
+translated the ACB_CTRL Flags to UserFlags (userAccountControl)
+*/
+uint32 ads_acb2uf(uint32 acb)
+{
+ uint32 uf = 0x00000000;
+
+ if (acb & ACB_DISABLED) uf |= UF_ACCOUNTDISABLE;
+ if (acb & ACB_HOMDIRREQ) uf |= UF_HOMEDIR_REQUIRED;
+ if (acb & ACB_PWNOTREQ) uf |= UF_PASSWD_NOTREQD;
+ if (acb & ACB_TEMPDUP) uf |= UF_TEMP_DUPLICATE_ACCOUNT;
+ if (acb & ACB_NORMAL) uf |= UF_NORMAL_ACCOUNT;
+ if (acb & ACB_MNS) uf |= UF_MNS_LOGON_ACCOUNT;
+ if (acb & ACB_DOMTRUST) uf |= UF_INTERDOMAIN_TRUST_ACCOUNT;
+ if (acb & ACB_WSTRUST) uf |= UF_WORKSTATION_TRUST_ACCOUNT;
+ if (acb & ACB_SVRTRUST) uf |= UF_SERVER_TRUST_ACCOUNT;
+ if (acb & ACB_PWNOEXP) uf |= UF_DONT_EXPIRE_PASSWD;
+ if (acb & ACB_AUTOLOCK) uf |= UF_LOCKOUT;
+ if (acb & ACB_USE_DES_KEY_ONLY) uf |= UF_USE_DES_KEY_ONLY;
+ if (acb & ACB_SMARTCARD_REQUIRED) uf |= UF_SMARTCARD_REQUIRED;
+ if (acb & ACB_TRUSTED_FOR_DELEGATION) uf |= UF_TRUSTED_FOR_DELEGATION;
+ if (acb & ACB_DONT_REQUIRE_PREAUTH) uf |= UF_DONT_REQUIRE_PREAUTH;
+ if (acb & ACB_NO_AUTH_DATA_REQD) uf |= UF_NO_AUTH_DATA_REQUIRED;
+ if (acb & ACB_NOT_DELEGATED) uf |= UF_NOT_DELEGATED;
+ if (acb & ACB_ENC_TXT_PWD_ALLOWED) uf |= UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED;
+
+ return uf;
+}
+
+/*
+translated the UserFlags (userAccountControl) to ACB_CTRL Flags
+*/
+uint32 ads_uf2acb(uint32 uf)
+{
+ uint32 acb = 0x00000000;
+
+ if (uf & UF_ACCOUNTDISABLE) acb |= ACB_DISABLED;
+ if (uf & UF_HOMEDIR_REQUIRED) acb |= ACB_HOMDIRREQ;
+ if (uf & UF_PASSWD_NOTREQD) acb |= ACB_PWNOTREQ;
+ if (uf & UF_MNS_LOGON_ACCOUNT) acb |= ACB_MNS;
+ if (uf & UF_DONT_EXPIRE_PASSWD) acb |= ACB_PWNOEXP;
+ if (uf & UF_LOCKOUT) acb |= ACB_AUTOLOCK;
+ if (uf & UF_USE_DES_KEY_ONLY) acb |= ACB_USE_DES_KEY_ONLY;
+ if (uf & UF_SMARTCARD_REQUIRED) acb |= ACB_SMARTCARD_REQUIRED;
+ if (uf & UF_TRUSTED_FOR_DELEGATION) acb |= ACB_TRUSTED_FOR_DELEGATION;
+ if (uf & UF_DONT_REQUIRE_PREAUTH) acb |= ACB_DONT_REQUIRE_PREAUTH;
+ if (uf & UF_NO_AUTH_DATA_REQUIRED) acb |= ACB_NO_AUTH_DATA_REQD;
+ if (uf & UF_NOT_DELEGATED) acb |= ACB_NOT_DELEGATED;
+ if (uf & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED) acb |= ACB_ENC_TXT_PWD_ALLOWED;
+
+ switch (uf & UF_ACCOUNT_TYPE_MASK)
+ {
+ case UF_TEMP_DUPLICATE_ACCOUNT: acb |= ACB_TEMPDUP;break;
+ case UF_NORMAL_ACCOUNT: acb |= ACB_NORMAL;break;
+ case UF_INTERDOMAIN_TRUST_ACCOUNT: acb |= ACB_DOMTRUST;break;
+ case UF_WORKSTATION_TRUST_ACCOUNT: acb |= ACB_WSTRUST;break;
+ case UF_SERVER_TRUST_ACCOUNT: acb |= ACB_SVRTRUST;break;
+ /*Fix Me: what should we do here? */
+ default: acb |= ACB_NORMAL;break;
+ }
+
+ return acb;
+}
+
+/*
+get the accountType from the UserFlags
+*/
+uint32 ads_uf2atype(uint32 uf)
+{
+ uint32 atype = 0x00000000;
+
+ if (uf & UF_NORMAL_ACCOUNT) atype = ATYPE_NORMAL_ACCOUNT;
+ else if (uf & UF_TEMP_DUPLICATE_ACCOUNT) atype = ATYPE_NORMAL_ACCOUNT;
+ else if (uf & UF_SERVER_TRUST_ACCOUNT) atype = ATYPE_WORKSTATION_TRUST;
+ else if (uf & UF_WORKSTATION_TRUST_ACCOUNT) atype = ATYPE_WORKSTATION_TRUST;
+ else if (uf & UF_INTERDOMAIN_TRUST_ACCOUNT) atype = ATYPE_INTERDOMAIN_TRUST;
+
+ return atype;
+}
+
+/*
+get the accountType from the groupType
+*/
+uint32 ads_gtype2atype(uint32 gtype)
+{
+ uint32 atype = 0x00000000;
+
+ switch(gtype) {
+ case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
+ atype = ATYPE_SECURITY_LOCAL_GROUP;
+ break;
+ case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
+ atype = ATYPE_SECURITY_LOCAL_GROUP;
+ break;
+ case GTYPE_SECURITY_GLOBAL_GROUP:
+ atype = ATYPE_SECURITY_GLOBAL_GROUP;
+ break;
+
+ case GTYPE_DISTRIBUTION_GLOBAL_GROUP:
+ atype = ATYPE_DISTRIBUTION_GLOBAL_GROUP;
+ break;
+ case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP:
+ atype = ATYPE_DISTRIBUTION_UNIVERSAL_GROUP;
+ break;
+ case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP:
+ atype = ATYPE_DISTRIBUTION_LOCAL_GROUP;
+ break;
+ }
+
+ return atype;
+}
+
+/* turn a sAMAccountType into a SID_NAME_USE */
+enum lsa_SidType ads_atype_map(uint32 atype)
+{
+ switch (atype & 0xF0000000) {
+ case ATYPE_GLOBAL_GROUP:
+ return SID_NAME_DOM_GRP;
+ case ATYPE_SECURITY_LOCAL_GROUP:
+ return SID_NAME_ALIAS;
+ case ATYPE_ACCOUNT:
+ return SID_NAME_USER;
+ default:
+ DEBUG(1,("hmm, need to map account type 0x%x\n", atype));
+ }
+ return SID_NAME_UNKNOWN;
+}
diff --git a/source3/libads/authdata.c b/source3/libads/authdata.c
new file mode 100644
index 0000000000..0bde3e6984
--- /dev/null
+++ b/source3/libads/authdata.c
@@ -0,0 +1,563 @@
+/*
+ Unix SMB/CIFS implementation.
+ kerberos authorization data (PAC) utility library
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Luke Howard 2002-2003
+ Copyright (C) Stefan Metzmacher 2004-2005
+ Copyright (C) Guenther Deschner 2005,2007,2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_KRB5
+
+/****************************************************************
+****************************************************************/
+
+static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx,
+ DATA_BLOB pac_data,
+ struct PAC_SIGNATURE_DATA *sig,
+ krb5_context context,
+ krb5_keyblock *keyblock)
+{
+ krb5_error_code ret;
+ krb5_checksum cksum;
+ krb5_keyusage usage = 0;
+
+ smb_krb5_checksum_from_pac_sig(&cksum, sig);
+
+#ifdef HAVE_KRB5_KU_OTHER_CKSUM /* Heimdal */
+ usage = KRB5_KU_OTHER_CKSUM;
+#elif defined(HAVE_KRB5_KEYUSAGE_APP_DATA_CKSUM) /* MIT */
+ usage = KRB5_KEYUSAGE_APP_DATA_CKSUM;
+#else
+#error UNKNOWN_KRB5_KEYUSAGE
+#endif
+
+ ret = smb_krb5_verify_checksum(context,
+ keyblock,
+ usage,
+ &cksum,
+ pac_data.data,
+ pac_data.length);
+
+ if (ret) {
+ DEBUG(2,("check_pac_checksum: PAC Verification failed: %s (%d)\n",
+ error_message(ret), ret));
+ return ret;
+ }
+
+ return ret;
+}
+
+/****************************************************************
+****************************************************************/
+
+ NTSTATUS decode_pac_data(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pac_data_blob,
+ krb5_context context,
+ krb5_keyblock *service_keyblock,
+ krb5_const_principal client_principal,
+ time_t tgs_authtime,
+ struct PAC_DATA **pac_data_out)
+{
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ krb5_error_code ret;
+ DATA_BLOB modified_pac_blob;
+
+ NTTIME tgs_authtime_nttime;
+ krb5_principal client_principal_pac = NULL;
+ int i;
+
+ struct PAC_SIGNATURE_DATA *srv_sig_ptr = NULL;
+ struct PAC_SIGNATURE_DATA *kdc_sig_ptr = NULL;
+ struct PAC_SIGNATURE_DATA *srv_sig_wipe = NULL;
+ struct PAC_SIGNATURE_DATA *kdc_sig_wipe = NULL;
+ struct PAC_LOGON_NAME *logon_name = NULL;
+ struct PAC_LOGON_INFO *logon_info = NULL;
+ struct PAC_DATA *pac_data = NULL;
+ struct PAC_DATA_RAW *pac_data_raw = NULL;
+
+ DATA_BLOB *srv_sig_blob = NULL;
+ DATA_BLOB *kdc_sig_blob = NULL;
+
+ *pac_data_out = NULL;
+
+ pac_data = TALLOC_ZERO_P(mem_ctx, struct PAC_DATA);
+ pac_data_raw = TALLOC_ZERO_P(mem_ctx, struct PAC_DATA_RAW);
+ kdc_sig_wipe = TALLOC_ZERO_P(mem_ctx, struct PAC_SIGNATURE_DATA);
+ srv_sig_wipe = TALLOC_ZERO_P(mem_ctx, struct PAC_SIGNATURE_DATA);
+ if (!pac_data_raw || !pac_data || !kdc_sig_wipe || !srv_sig_wipe) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ndr_err = ndr_pull_struct_blob(pac_data_blob, pac_data,
+ pac_data,
+ (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(0,("can't parse the PAC: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ if (pac_data->num_buffers < 4) {
+ /* we need logon_ingo, service_key and kdc_key */
+ DEBUG(0,("less than 4 PAC buffers\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ndr_err = ndr_pull_struct_blob(pac_data_blob, pac_data_raw,
+ pac_data_raw,
+ (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA_RAW);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(0,("can't parse the PAC: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ if (pac_data_raw->num_buffers < 4) {
+ /* we need logon_ingo, service_key and kdc_key */
+ DEBUG(0,("less than 4 PAC buffers\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (pac_data->num_buffers != pac_data_raw->num_buffers) {
+ /* we need logon_ingo, service_key and kdc_key */
+ DEBUG(0,("misparse! PAC_DATA has %d buffers while PAC_DATA_RAW has %d\n",
+ pac_data->num_buffers, pac_data_raw->num_buffers));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ for (i=0; i < pac_data->num_buffers; i++) {
+ if (pac_data->buffers[i].type != pac_data_raw->buffers[i].type) {
+ DEBUG(0,("misparse! PAC_DATA buffer %d has type %d while PAC_DATA_RAW has %d\n",
+ i, pac_data->buffers[i].type, pac_data->buffers[i].type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ switch (pac_data->buffers[i].type) {
+ case PAC_TYPE_LOGON_INFO:
+ if (!pac_data->buffers[i].info) {
+ break;
+ }
+ logon_info = pac_data->buffers[i].info->logon_info.info;
+ break;
+ case PAC_TYPE_SRV_CHECKSUM:
+ if (!pac_data->buffers[i].info) {
+ break;
+ }
+ srv_sig_ptr = &pac_data->buffers[i].info->srv_cksum;
+ srv_sig_blob = &pac_data_raw->buffers[i].info->remaining;
+ break;
+ case PAC_TYPE_KDC_CHECKSUM:
+ if (!pac_data->buffers[i].info) {
+ break;
+ }
+ kdc_sig_ptr = &pac_data->buffers[i].info->kdc_cksum;
+ kdc_sig_blob = &pac_data_raw->buffers[i].info->remaining;
+ break;
+ case PAC_TYPE_LOGON_NAME:
+ logon_name = &pac_data->buffers[i].info->logon_name;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!logon_info) {
+ DEBUG(0,("PAC no logon_info\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!logon_name) {
+ DEBUG(0,("PAC no logon_name\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!srv_sig_ptr || !srv_sig_blob) {
+ DEBUG(0,("PAC no srv_key\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!kdc_sig_ptr || !kdc_sig_blob) {
+ DEBUG(0,("PAC no kdc_key\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Find and zero out the signatures, as required by the signing algorithm */
+
+ /* We find the data blobs above, now we parse them to get at the exact portion we should zero */
+ ndr_err = ndr_pull_struct_blob(kdc_sig_blob, kdc_sig_wipe,
+ kdc_sig_wipe,
+ (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(0,("can't parse the KDC signature: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ ndr_err = ndr_pull_struct_blob(srv_sig_blob, srv_sig_wipe,
+ srv_sig_wipe,
+ (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(0,("can't parse the SRV signature: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ /* Now zero the decoded structure */
+ memset(kdc_sig_wipe->signature.data, '\0', kdc_sig_wipe->signature.length);
+ memset(srv_sig_wipe->signature.data, '\0', srv_sig_wipe->signature.length);
+
+ /* and reencode, back into the same place it came from */
+ ndr_err = ndr_push_struct_blob(kdc_sig_blob, pac_data_raw,
+ kdc_sig_wipe,
+ (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(0,("can't repack the KDC signature: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+ ndr_err = ndr_push_struct_blob(srv_sig_blob, pac_data_raw,
+ srv_sig_wipe,
+ (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(0,("can't repack the SRV signature: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ /* push out the whole structure, but now with zero'ed signatures */
+ ndr_err = ndr_push_struct_blob(&modified_pac_blob, pac_data_raw,
+ pac_data_raw,
+ (ndr_push_flags_fn_t)ndr_push_PAC_DATA_RAW);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(0,("can't repack the RAW PAC: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ /* verify by service_key */
+ ret = check_pac_checksum(mem_ctx,
+ modified_pac_blob, srv_sig_ptr,
+ context,
+ service_keyblock);
+ if (ret) {
+ DEBUG(1, ("PAC Decode: Failed to verify the service signature: %s\n",
+ error_message(ret)));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* Convert to NT time, so as not to loose accuracy in comparison */
+ unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime);
+
+ if (tgs_authtime_nttime != logon_name->logon_time) {
+ DEBUG(2, ("PAC Decode: Logon time mismatch between ticket and PAC!\n"));
+ DEBUG(2, ("PAC Decode: PAC: %s\n", nt_time_string(mem_ctx, logon_name->logon_time)));
+ DEBUG(2, ("PAC Decode: Ticket: %s\n", nt_time_string(mem_ctx, tgs_authtime_nttime)));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ ret = smb_krb5_parse_name_norealm(context, logon_name->account_name,
+ &client_principal_pac);
+ if (ret) {
+ DEBUG(2, ("Could not parse name from incoming PAC: [%s]: %s\n",
+ logon_name->account_name,
+ error_message(ret)));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!smb_krb5_principal_compare_any_realm(context, client_principal, client_principal_pac)) {
+ DEBUG(2, ("Name in PAC [%s] does not match principal name in ticket\n",
+ logon_name->account_name));
+ krb5_free_principal(context, client_principal_pac);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ DEBUG(3,("Found account name from PAC: %s [%s]\n",
+ logon_info->info3.base.account_name.string,
+ logon_info->info3.base.full_name.string));
+
+ DEBUG(10,("Successfully validated Kerberos PAC\n"));
+
+ if (DEBUGLEVEL >= 10) {
+ const char *s;
+ s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_DATA, pac_data);
+ if (s) {
+ DEBUGADD(10,("%s\n", s));
+ }
+ }
+
+ *pac_data_out = pac_data;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+struct PAC_LOGON_INFO *get_logon_info_from_pac(struct PAC_DATA *pac_data)
+{
+ int i;
+
+ for (i=0; i < pac_data->num_buffers; i++) {
+
+ if (pac_data->buffers[i].type != PAC_TYPE_LOGON_INFO) {
+ continue;
+ }
+
+ return pac_data->buffers[i].info->logon_info.info;
+ }
+
+ return NULL;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS kerberos_return_pac(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const char *pass,
+ time_t time_offset,
+ time_t *expire_time,
+ time_t *renew_till_time,
+ const char *cache_name,
+ bool request_pac,
+ bool add_netbios_addr,
+ time_t renewable_time,
+ struct PAC_DATA **pac_ret)
+{
+ krb5_error_code ret;
+ NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
+ DATA_BLOB tkt, ap_rep, sesskey1, sesskey2;
+ struct PAC_DATA *pac_data = NULL;
+ char *client_princ_out = NULL;
+ const char *auth_princ = NULL;
+ const char *local_service = NULL;
+ const char *cc = "MEMORY:kerberos_return_pac";
+
+ ZERO_STRUCT(tkt);
+ ZERO_STRUCT(ap_rep);
+ ZERO_STRUCT(sesskey1);
+ ZERO_STRUCT(sesskey2);
+
+ if (!name || !pass) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (cache_name) {
+ cc = cache_name;
+ }
+
+ if (!strchr_m(name, '@')) {
+ auth_princ = talloc_asprintf(mem_ctx, "%s@%s", name,
+ lp_realm());
+ } else {
+ auth_princ = name;
+ }
+ NT_STATUS_HAVE_NO_MEMORY(auth_princ);
+
+ local_service = talloc_asprintf(mem_ctx, "%s$@%s",
+ global_myname(), lp_realm());
+ NT_STATUS_HAVE_NO_MEMORY(local_service);
+
+ ret = kerberos_kinit_password_ext(auth_princ,
+ pass,
+ time_offset,
+ expire_time,
+ renew_till_time,
+ cc,
+ request_pac,
+ add_netbios_addr,
+ renewable_time,
+ &status);
+ if (ret) {
+ DEBUG(1,("kinit failed for '%s' with: %s (%d)\n",
+ auth_princ, error_message(ret), ret));
+ /* status already set */
+ goto out;
+ }
+
+ DEBUG(10,("got TGT for %s in %s\n", auth_princ, cc));
+ if (expire_time) {
+ DEBUGADD(10,("\tvalid until: %s (%d)\n",
+ http_timestring(*expire_time),
+ (int)*expire_time));
+ }
+ if (renew_till_time) {
+ DEBUGADD(10,("\trenewable till: %s (%d)\n",
+ http_timestring(*renew_till_time),
+ (int)*renew_till_time));
+ }
+
+ /* we cannot continue with krb5 when UF_DONT_REQUIRE_PREAUTH is set,
+ * in that case fallback to NTLM - gd */
+
+ if (expire_time && renew_till_time &&
+ (*expire_time == 0) && (*renew_till_time == 0)) {
+ return NT_STATUS_INVALID_LOGON_TYPE;
+ }
+
+
+ ret = cli_krb5_get_ticket(local_service,
+ time_offset,
+ &tkt,
+ &sesskey1,
+ 0,
+ cc,
+ NULL);
+ if (ret) {
+ DEBUG(1,("failed to get ticket for %s: %s\n",
+ local_service, error_message(ret)));
+ status = krb5_to_nt_status(ret);
+ goto out;
+ }
+
+ status = ads_verify_ticket(mem_ctx,
+ lp_realm(),
+ time_offset,
+ &tkt,
+ &client_princ_out,
+ &pac_data,
+ &ap_rep,
+ &sesskey2,
+ False);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1,("ads_verify_ticket failed: %s\n",
+ nt_errstr(status)));
+ goto out;
+ }
+
+ if (!pac_data) {
+ DEBUG(1,("no PAC\n"));
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ *pac_ret = pac_data;
+
+out:
+ if (cc != cache_name) {
+ ads_kdestroy(cc);
+ }
+
+ data_blob_free(&tkt);
+ data_blob_free(&ap_rep);
+ data_blob_free(&sesskey1);
+ data_blob_free(&sesskey2);
+
+ SAFE_FREE(client_princ_out);
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS kerberos_return_pac_logon_info(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const char *pass,
+ time_t time_offset,
+ time_t *expire_time,
+ time_t *renew_till_time,
+ const char *cache_name,
+ bool request_pac,
+ bool add_netbios_addr,
+ time_t renewable_time,
+ struct PAC_LOGON_INFO **logon_info)
+{
+ NTSTATUS status;
+ struct PAC_DATA *pac_data = NULL;
+ struct PAC_LOGON_INFO *info = NULL;
+
+ status = kerberos_return_pac(mem_ctx,
+ name,
+ pass,
+ time_offset,
+ expire_time,
+ renew_till_time,
+ cache_name,
+ request_pac,
+ add_netbios_addr,
+ renewable_time,
+ &pac_data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (!pac_data) {
+ DEBUG(3,("no pac\n"));
+ return NT_STATUS_INVALID_USER_BUFFER;
+ }
+
+ info = get_logon_info_from_pac(pac_data);
+ if (!info) {
+ DEBUG(1,("no logon_info\n"));
+ return NT_STATUS_INVALID_USER_BUFFER;
+ }
+
+ *logon_info = info;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS kerberos_return_info3_from_pac(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const char *pass,
+ time_t time_offset,
+ time_t *expire_time,
+ time_t *renew_till_time,
+ const char *cache_name,
+ bool request_pac,
+ bool add_netbios_addr,
+ time_t renewable_time,
+ struct netr_SamInfo3 **info3)
+{
+ NTSTATUS status;
+ struct PAC_LOGON_INFO *logon_info = NULL;
+
+ status = kerberos_return_pac_logon_info(mem_ctx,
+ name,
+ pass,
+ time_offset,
+ expire_time,
+ renew_till_time,
+ cache_name,
+ request_pac,
+ add_netbios_addr,
+ renewable_time,
+ &logon_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ *info3 = &logon_info->info3;
+
+ return NT_STATUS_OK;
+}
+#endif
diff --git a/source3/libads/cldap.c b/source3/libads/cldap.c
new file mode 100644
index 0000000000..11565065af
--- /dev/null
+++ b/source3/libads/cldap.c
@@ -0,0 +1,368 @@
+/*
+ Samba Unix/Linux SMB client library
+ net ads cldap functions
+ Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+ Copyright (C) 2003 Jim McDonough (jmcd@us.ibm.com)
+ Copyright (C) 2008 Guenther Deschner (gd@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*
+ do a cldap netlogon query
+*/
+static int send_cldap_netlogon(int sock, const char *domain,
+ const char *hostname, unsigned ntversion)
+{
+ ASN1_DATA data;
+ char ntver[4];
+#ifdef CLDAP_USER_QUERY
+ char aac[4];
+
+ SIVAL(aac, 0, 0x00000180);
+#endif
+ SIVAL(ntver, 0, ntversion);
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_push_tag(&data,ASN1_SEQUENCE(0));
+ asn1_write_Integer(&data, 4);
+ asn1_push_tag(&data, ASN1_APPLICATION(3));
+ asn1_write_OctetString(&data, NULL, 0);
+ asn1_write_enumerated(&data, 0);
+ asn1_write_enumerated(&data, 0);
+ asn1_write_Integer(&data, 0);
+ asn1_write_Integer(&data, 0);
+ asn1_write_BOOLEAN2(&data, False);
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+
+ if (domain) {
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, "DnsDomain", 9);
+ asn1_write_OctetString(&data, domain, strlen(domain));
+ asn1_pop_tag(&data);
+ }
+
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, "Host", 4);
+ asn1_write_OctetString(&data, hostname, strlen(hostname));
+ asn1_pop_tag(&data);
+
+#ifdef CLDAP_USER_QUERY
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, "User", 4);
+ asn1_write_OctetString(&data, "SAMBA$", 6);
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, "AAC", 4);
+ asn1_write_OctetString(&data, aac, 4);
+ asn1_pop_tag(&data);
+#endif
+
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, "NtVer", 5);
+ asn1_write_OctetString(&data, ntver, 4);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data,ASN1_SEQUENCE(0));
+ asn1_write_OctetString(&data, "NetLogon", 8);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(2,("Failed to build cldap netlogon at offset %d\n", (int)data.ofs));
+ asn1_free(&data);
+ return -1;
+ }
+
+ if (write(sock, data.data, data.length) != (ssize_t)data.length) {
+ DEBUG(2,("failed to send cldap query (%s)\n", strerror(errno)));
+ asn1_free(&data);
+ return -1;
+ }
+
+ asn1_free(&data);
+
+ return 0;
+}
+
+static SIG_ATOMIC_T gotalarm;
+
+/***************************************************************
+ Signal function to tell us we timed out.
+****************************************************************/
+
+static void gotalarm_sig(void)
+{
+ gotalarm = 1;
+}
+
+/*
+ receive a cldap netlogon reply
+*/
+static int recv_cldap_netlogon(TALLOC_CTX *mem_ctx,
+ int sock,
+ uint32_t *nt_version,
+ union nbt_cldap_netlogon **reply)
+{
+ int ret;
+ ASN1_DATA data;
+ DATA_BLOB blob = data_blob_null;
+ DATA_BLOB os1 = data_blob_null;
+ DATA_BLOB os2 = data_blob_null;
+ DATA_BLOB os3 = data_blob_null;
+ int i1;
+ /* half the time of a regular ldap timeout, not less than 3 seconds. */
+ unsigned int al_secs = MAX(3,lp_ldap_timeout()/2);
+ union nbt_cldap_netlogon *r = NULL;
+
+ blob = data_blob(NULL, 8192);
+ if (blob.data == NULL) {
+ DEBUG(1, ("data_blob failed\n"));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* Setup timeout */
+ gotalarm = 0;
+ CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+ alarm(al_secs);
+ /* End setup timeout. */
+
+ ret = read(sock, blob.data, blob.length);
+
+ /* Teardown timeout. */
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
+ alarm(0);
+
+ if (ret <= 0) {
+ DEBUG(1,("no reply received to cldap netlogon\n"));
+ data_blob_free(&blob);
+ return -1;
+ }
+ blob.length = ret;
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_read_Integer(&data, &i1);
+ asn1_start_tag(&data, ASN1_APPLICATION(4));
+ asn1_read_OctetString(&data, &os1);
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_read_OctetString(&data, &os2);
+ asn1_start_tag(&data, ASN1_SET);
+ asn1_read_OctetString(&data, &os3);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ if (data.has_error) {
+ data_blob_free(&blob);
+ data_blob_free(&os1);
+ data_blob_free(&os2);
+ data_blob_free(&os3);
+ asn1_free(&data);
+ DEBUG(1,("Failed to parse cldap reply\n"));
+ return -1;
+ }
+
+ r = TALLOC_ZERO_P(mem_ctx, union nbt_cldap_netlogon);
+ if (!r) {
+ errno = ENOMEM;
+ data_blob_free(&os1);
+ data_blob_free(&os2);
+ data_blob_free(&os3);
+ data_blob_free(&blob);
+ return -1;
+ }
+
+ if (!pull_mailslot_cldap_reply(mem_ctx, &os3, r, nt_version)) {
+ data_blob_free(&os1);
+ data_blob_free(&os2);
+ data_blob_free(&os3);
+ data_blob_free(&blob);
+ TALLOC_FREE(r);
+ return -1;
+ }
+
+ data_blob_free(&os1);
+ data_blob_free(&os2);
+ data_blob_free(&os3);
+ data_blob_free(&blob);
+
+ asn1_free(&data);
+
+ if (reply) {
+ *reply = r;
+ } else {
+ TALLOC_FREE(r);
+ }
+
+ return 0;
+}
+
+/*******************************************************************
+ do a cldap netlogon query. Always 389/udp
+*******************************************************************/
+
+bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
+ const char *server,
+ const char *realm,
+ uint32_t *nt_version,
+ union nbt_cldap_netlogon **reply)
+{
+ int sock;
+ int ret;
+
+ sock = open_udp_socket(server, LDAP_PORT );
+ if (sock == -1) {
+ DEBUG(2,("ads_cldap_netlogon: Failed to open udp socket to %s\n",
+ server));
+ return False;
+ }
+
+ ret = send_cldap_netlogon(sock, realm, global_myname(), *nt_version);
+ if (ret != 0) {
+ close(sock);
+ return False;
+ }
+ ret = recv_cldap_netlogon(mem_ctx, sock, nt_version, reply);
+ close(sock);
+
+ if (ret == -1) {
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ do a cldap netlogon query. Always 389/udp
+*******************************************************************/
+
+bool ads_cldap_netlogon_5(TALLOC_CTX *mem_ctx,
+ const char *server,
+ const char *realm,
+ struct nbt_cldap_netlogon_5 *reply5)
+{
+ uint32_t nt_version = NETLOGON_VERSION_5 | NETLOGON_VERSION_5EX;
+ union nbt_cldap_netlogon *reply = NULL;
+ bool ret;
+
+ ret = ads_cldap_netlogon(mem_ctx, server, realm, &nt_version, &reply);
+ if (!ret) {
+ return false;
+ }
+
+ if (nt_version != (NETLOGON_VERSION_5 | NETLOGON_VERSION_5EX)) {
+ return false;
+ }
+
+ *reply5 = reply->logon5;
+
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+bool pull_mailslot_cldap_reply(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob,
+ union nbt_cldap_netlogon *r,
+ uint32_t *nt_version)
+{
+ enum ndr_err_code ndr_err;
+ uint32_t nt_version_query = ((*nt_version) & 0x0000001f);
+ uint16_t command = 0;
+
+ ndr_err = ndr_pull_struct_blob(blob, mem_ctx, &command,
+ (ndr_pull_flags_fn_t)ndr_pull_uint16);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+
+ switch (command) {
+ case 0x13: /* 19 */
+ case 0x15: /* 21 */
+ case 0x17: /* 23 */
+ case 0x19: /* 25 */
+ break;
+ default:
+ DEBUG(1,("got unexpected command: %d (0x%08x)\n",
+ command, command));
+ return false;
+ }
+
+ ndr_err = ndr_pull_union_blob_all(blob, mem_ctx, r, nt_version_query,
+ (ndr_pull_flags_fn_t)ndr_pull_nbt_cldap_netlogon);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto done;
+ }
+
+ /* when the caller requested just those nt_version bits that the server
+ * was able to reply to, we are fine and all done. otherwise we need to
+ * assume downgraded replies which are painfully parsed here - gd */
+
+ if (nt_version_query & NETLOGON_VERSION_WITH_CLOSEST_SITE) {
+ nt_version_query &= ~NETLOGON_VERSION_WITH_CLOSEST_SITE;
+ }
+ ndr_err = ndr_pull_union_blob_all(blob, mem_ctx, r, nt_version_query,
+ (ndr_pull_flags_fn_t)ndr_pull_nbt_cldap_netlogon);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto done;
+ }
+ if (nt_version_query & NETLOGON_VERSION_5EX_WITH_IP) {
+ nt_version_query &= ~NETLOGON_VERSION_5EX_WITH_IP;
+ }
+ ndr_err = ndr_pull_union_blob_all(blob, mem_ctx, r, nt_version_query,
+ (ndr_pull_flags_fn_t)ndr_pull_nbt_cldap_netlogon);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto done;
+ }
+ if (nt_version_query & NETLOGON_VERSION_5EX) {
+ nt_version_query &= ~NETLOGON_VERSION_5EX;
+ }
+ ndr_err = ndr_pull_union_blob_all(blob, mem_ctx, r, nt_version_query,
+ (ndr_pull_flags_fn_t)ndr_pull_nbt_cldap_netlogon);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto done;
+ }
+ if (nt_version_query & NETLOGON_VERSION_5) {
+ nt_version_query &= ~NETLOGON_VERSION_5;
+ }
+ ndr_err = ndr_pull_union_blob_all(blob, mem_ctx, r, nt_version_query,
+ (ndr_pull_flags_fn_t)ndr_pull_nbt_cldap_netlogon);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto done;
+ }
+
+ return false;
+
+ done:
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_UNION_DEBUG(nbt_cldap_netlogon, nt_version_query, r);
+ }
+
+ *nt_version = nt_version_query;
+
+ return true;
+}
diff --git a/source3/libads/disp_sec.c b/source3/libads/disp_sec.c
new file mode 100644
index 0000000000..f4c68638df
--- /dev/null
+++ b/source3/libads/disp_sec.c
@@ -0,0 +1,237 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions. ADS stuff
+ Copyright (C) Alexey Kotovich 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_LDAP
+
+static struct perm_mask_str {
+ uint32 mask;
+ const char *str;
+} perms[] = {
+ {SEC_RIGHTS_FULL_CTRL, "[Full Control]"},
+
+ {SEC_RIGHTS_LIST_CONTENTS, "[List Contents]"},
+ {SEC_RIGHTS_LIST_OBJECT, "[List Object]"},
+
+ {SEC_RIGHTS_READ_ALL_PROP, "[Read All Properties]"},
+ {SEC_RIGHTS_READ_PERMS, "[Read Permissions]"},
+
+ {SEC_RIGHTS_WRITE_ALL_VALID, "[All validate writes]"},
+ {SEC_RIGHTS_WRITE_ALL_PROP, "[Write All Properties]"},
+
+ {SEC_RIGHTS_MODIFY_PERMS, "[Modify Permissions]"},
+ {SEC_RIGHTS_MODIFY_OWNER, "[Modify Owner]"},
+
+ {SEC_RIGHTS_CREATE_CHILD, "[Create All Child Objects]"},
+
+ {SEC_RIGHTS_DELETE, "[Delete]"},
+ {SEC_RIGHTS_DELETE_SUBTREE, "[Delete Subtree]"},
+ {SEC_RIGHTS_DELETE_CHILD, "[Delete All Child Objects]"},
+
+ {SEC_RIGHTS_CHANGE_PASSWD, "[Change Password]"},
+ {SEC_RIGHTS_RESET_PASSWD, "[Reset Password]"},
+
+ {0, 0}
+};
+
+/* convert a security permissions into a string */
+static void ads_disp_perms(uint32 type)
+{
+ int i = 0;
+ int j = 0;
+
+ printf("Permissions: ");
+
+ if (type == SEC_RIGHTS_FULL_CTRL) {
+ printf("%s\n", perms[j].str);
+ return;
+ }
+
+ for (i = 0; i < 32; i++) {
+ if (type & (1 << i)) {
+ for (j = 1; perms[j].str; j ++) {
+ if (perms[j].mask == (((unsigned) 1) << i)) {
+ printf("\n\t%s (0x%08x)", perms[j].str, perms[j].mask);
+ }
+ }
+ type &= ~(1 << i);
+ }
+ }
+
+ /* remaining bits get added on as-is */
+ if (type != 0) {
+ printf("[%08x]", type);
+ }
+ puts("");
+}
+
+static const char *ads_interprete_guid_from_object(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const struct GUID *guid)
+{
+ const char *ret = NULL;
+
+ if (!ads || !mem_ctx) {
+ return NULL;
+ }
+
+ ret = ads_get_attrname_by_guid(ads, ads->config.schema_path,
+ mem_ctx, guid);
+ if (ret) {
+ return talloc_asprintf(mem_ctx, "LDAP attribute: \"%s\"", ret);
+ }
+
+ ret = ads_get_extended_right_name_by_guid(ads, ads->config.config_path,
+ mem_ctx, guid);
+
+ if (ret) {
+ return talloc_asprintf(mem_ctx, "Extended right: \"%s\"", ret);
+ }
+
+ return ret;
+}
+
+static void ads_disp_sec_ace_object(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ struct security_ace_object *object)
+{
+ if (object->flags & SEC_ACE_OBJECT_PRESENT) {
+ printf("Object type: SEC_ACE_OBJECT_PRESENT\n");
+ printf("Object GUID: %s (%s)\n", smb_uuid_string(mem_ctx,
+ object->type.type),
+ ads_interprete_guid_from_object(ads, mem_ctx,
+ &object->type.type));
+ }
+ if (object->flags & SEC_ACE_OBJECT_INHERITED_PRESENT) {
+ printf("Object type: SEC_ACE_OBJECT_INHERITED_PRESENT\n");
+ printf("Object GUID: %s (%s)\n", smb_uuid_string(mem_ctx,
+ object->inherited_type.inherited_type),
+ ads_interprete_guid_from_object(ads, mem_ctx,
+ &object->inherited_type.inherited_type));
+ }
+}
+
+/* display ACE */
+static void ads_disp_ace(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, SEC_ACE *sec_ace)
+{
+ const char *access_type = "UNKNOWN";
+
+ if (!sec_ace_object(sec_ace->type)) {
+ printf("------- ACE (type: 0x%02x, flags: 0x%02x, size: 0x%02x, mask: 0x%x)\n",
+ sec_ace->type,
+ sec_ace->flags,
+ sec_ace->size,
+ sec_ace->access_mask);
+ } else {
+ printf("------- ACE (type: 0x%02x, flags: 0x%02x, size: 0x%02x, mask: 0x%x, object flags: 0x%x)\n",
+ sec_ace->type,
+ sec_ace->flags,
+ sec_ace->size,
+ sec_ace->access_mask,
+ sec_ace->object.object.flags);
+ }
+
+ if (sec_ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) {
+ access_type = "ALLOWED";
+ } else if (sec_ace->type == SEC_ACE_TYPE_ACCESS_DENIED) {
+ access_type = "DENIED";
+ } else if (sec_ace->type == SEC_ACE_TYPE_SYSTEM_AUDIT) {
+ access_type = "SYSTEM AUDIT";
+ } else if (sec_ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT) {
+ access_type = "ALLOWED OBJECT";
+ } else if (sec_ace->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT) {
+ access_type = "DENIED OBJECT";
+ } else if (sec_ace->type == SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT) {
+ access_type = "AUDIT OBJECT";
+ }
+
+ printf("access SID: %s\naccess type: %s\n",
+ sid_string_talloc(mem_ctx, &sec_ace->trustee), access_type);
+
+ if (sec_ace_object(sec_ace->type)) {
+ ads_disp_sec_ace_object(ads, mem_ctx, &sec_ace->object.object);
+ }
+
+ ads_disp_perms(sec_ace->access_mask);
+}
+
+/* display ACL */
+static void ads_disp_acl(SEC_ACL *sec_acl, const char *type)
+{
+ if (!sec_acl)
+ printf("------- (%s) ACL not present\n", type);
+ else {
+ printf("------- (%s) ACL (revision: %d, size: %d, number of ACEs: %d)\n",
+ type,
+ sec_acl->revision,
+ sec_acl->size,
+ sec_acl->num_aces);
+ }
+}
+
+/* display SD */
+void ads_disp_sd(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, SEC_DESC *sd)
+{
+ int i;
+ char *tmp_path = NULL;
+
+ if (!sd) {
+ return;
+ }
+
+ if (ads && !ads->config.schema_path) {
+ if (ADS_ERR_OK(ads_schema_path(ads, mem_ctx, &tmp_path))) {
+ ads->config.schema_path = SMB_STRDUP(tmp_path);
+ }
+ }
+
+ if (ads && !ads->config.config_path) {
+ if (ADS_ERR_OK(ads_config_path(ads, mem_ctx, &tmp_path))) {
+ ads->config.config_path = SMB_STRDUP(tmp_path);
+ }
+ }
+
+ printf("-------------- Security Descriptor (revision: %d, type: 0x%02x)\n",
+ sd->revision,
+ sd->type);
+
+ printf("owner SID: %s\n", sd->owner_sid ?
+ sid_string_talloc(mem_ctx, sd->owner_sid) : "(null)");
+ printf("group SID: %s\n", sd->group_sid ?
+ sid_string_talloc(mem_ctx, sd->group_sid) : "(null)");
+
+ ads_disp_acl(sd->sacl, "system");
+ if (sd->sacl) {
+ for (i = 0; i < sd->sacl->num_aces; i ++) {
+ ads_disp_ace(ads, mem_ctx, &sd->sacl->aces[i]);
+ }
+ }
+
+ ads_disp_acl(sd->dacl, "user");
+ if (sd->dacl) {
+ for (i = 0; i < sd->dacl->num_aces; i ++) {
+ ads_disp_ace(ads, mem_ctx, &sd->dacl->aces[i]);
+ }
+ }
+
+ printf("-------------- End Of Security Descriptor\n");
+}
+
+#endif
diff --git a/source3/libads/dns.c b/source3/libads/dns.c
new file mode 100644
index 0000000000..3a9e849668
--- /dev/null
+++ b/source3/libads/dns.c
@@ -0,0 +1,1011 @@
+/*
+ Unix SMB/CIFS implementation.
+ DNS utility library
+ Copyright (C) Gerald (Jerry) Carter 2006.
+ Copyright (C) Jeremy Allison 2007.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* AIX resolv.h uses 'class' in struct ns_rr */
+
+#if defined(AIX)
+# if defined(class)
+# undef class
+# endif
+#endif /* AIX */
+
+/* resolver headers */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h>
+
+#define MAX_DNS_PACKET_SIZE 0xffff
+
+#ifdef NS_HFIXEDSZ /* Bind 8/9 interface */
+#if !defined(C_IN) /* AIX 5.3 already defines C_IN */
+# define C_IN ns_c_in
+#endif
+#if !defined(T_A) /* AIX 5.3 already defines T_A */
+# define T_A ns_t_a
+#endif
+
+#if defined(HAVE_IPV6)
+#if !defined(T_AAAA)
+# define T_AAAA ns_t_aaaa
+#endif
+#endif
+
+# define T_SRV ns_t_srv
+#if !defined(T_NS) /* AIX 5.3 already defines T_NS */
+# define T_NS ns_t_ns
+#endif
+#else
+# ifdef HFIXEDSZ
+# define NS_HFIXEDSZ HFIXEDSZ
+# else
+# define NS_HFIXEDSZ sizeof(HEADER)
+# endif /* HFIXEDSZ */
+# ifdef PACKETSZ
+# define NS_PACKETSZ PACKETSZ
+# else /* 512 is usually the default */
+# define NS_PACKETSZ 512
+# endif /* PACKETSZ */
+# define T_SRV 33
+#endif
+
+/*********************************************************************
+*********************************************************************/
+
+static bool ads_dns_parse_query( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
+ uint8 **ptr, struct dns_query *q )
+{
+ uint8 *p = *ptr;
+ char hostname[MAX_DNS_NAME_LENGTH];
+ int namelen;
+
+ ZERO_STRUCTP( q );
+
+ if ( !start || !end || !q || !*ptr)
+ return False;
+
+ /* See RFC 1035 for details. If this fails, then return. */
+
+ namelen = dn_expand( start, end, p, hostname, sizeof(hostname) );
+ if ( namelen < 0 ) {
+ return False;
+ }
+ p += namelen;
+ q->hostname = talloc_strdup( ctx, hostname );
+
+ /* check that we have space remaining */
+
+ if ( PTR_DIFF(p+4, end) > 0 )
+ return False;
+
+ q->type = RSVAL( p, 0 );
+ q->in_class = RSVAL( p, 2 );
+ p += 4;
+
+ *ptr = p;
+
+ return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool ads_dns_parse_rr( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
+ uint8 **ptr, struct dns_rr *rr )
+{
+ uint8 *p = *ptr;
+ char hostname[MAX_DNS_NAME_LENGTH];
+ int namelen;
+
+ if ( !start || !end || !rr || !*ptr)
+ return -1;
+
+ ZERO_STRUCTP( rr );
+ /* pull the name from the answer */
+
+ namelen = dn_expand( start, end, p, hostname, sizeof(hostname) );
+ if ( namelen < 0 ) {
+ return -1;
+ }
+ p += namelen;
+ rr->hostname = talloc_strdup( ctx, hostname );
+
+ /* check that we have space remaining */
+
+ if ( PTR_DIFF(p+10, end) > 0 )
+ return False;
+
+ /* pull some values and then skip onto the string */
+
+ rr->type = RSVAL(p, 0);
+ rr->in_class = RSVAL(p, 2);
+ rr->ttl = RIVAL(p, 4);
+ rr->rdatalen = RSVAL(p, 8);
+
+ p += 10;
+
+ /* sanity check the available space */
+
+ if ( PTR_DIFF(p+rr->rdatalen, end ) > 0 ) {
+ return False;
+
+ }
+
+ /* save a point to the rdata for this section */
+
+ rr->rdata = p;
+ p += rr->rdatalen;
+
+ *ptr = p;
+
+ return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool ads_dns_parse_rr_srv( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
+ uint8 **ptr, struct dns_rr_srv *srv )
+{
+ struct dns_rr rr;
+ uint8 *p;
+ char dcname[MAX_DNS_NAME_LENGTH];
+ int namelen;
+
+ if ( !start || !end || !srv || !*ptr)
+ return -1;
+
+ /* Parse the RR entry. Coming out of the this, ptr is at the beginning
+ of the next record */
+
+ if ( !ads_dns_parse_rr( ctx, start, end, ptr, &rr ) ) {
+ DEBUG(1,("ads_dns_parse_rr_srv: Failed to parse RR record\n"));
+ return False;
+ }
+
+ if ( rr.type != T_SRV ) {
+ DEBUG(1,("ads_dns_parse_rr_srv: Bad answer type (%d)\n",
+ rr.type));
+ return False;
+ }
+
+ p = rr.rdata;
+
+ srv->priority = RSVAL(p, 0);
+ srv->weight = RSVAL(p, 2);
+ srv->port = RSVAL(p, 4);
+
+ p += 6;
+
+ namelen = dn_expand( start, end, p, dcname, sizeof(dcname) );
+ if ( namelen < 0 ) {
+ DEBUG(1,("ads_dns_parse_rr_srv: Failed to uncompress name!\n"));
+ return False;
+ }
+
+ srv->hostname = talloc_strdup( ctx, dcname );
+
+ DEBUG(10,("ads_dns_parse_rr_srv: Parsed %s [%u, %u, %u]\n",
+ srv->hostname,
+ srv->priority,
+ srv->weight,
+ srv->port));
+
+ return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool ads_dns_parse_rr_ns( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
+ uint8 **ptr, struct dns_rr_ns *nsrec )
+{
+ struct dns_rr rr;
+ uint8 *p;
+ char nsname[MAX_DNS_NAME_LENGTH];
+ int namelen;
+
+ if ( !start || !end || !nsrec || !*ptr)
+ return -1;
+
+ /* Parse the RR entry. Coming out of the this, ptr is at the beginning
+ of the next record */
+
+ if ( !ads_dns_parse_rr( ctx, start, end, ptr, &rr ) ) {
+ DEBUG(1,("ads_dns_parse_rr_ns: Failed to parse RR record\n"));
+ return False;
+ }
+
+ if ( rr.type != T_NS ) {
+ DEBUG(1,("ads_dns_parse_rr_ns: Bad answer type (%d)\n",
+ rr.type));
+ return False;
+ }
+
+ p = rr.rdata;
+
+ /* ame server hostname */
+
+ namelen = dn_expand( start, end, p, nsname, sizeof(nsname) );
+ if ( namelen < 0 ) {
+ DEBUG(1,("ads_dns_parse_rr_ns: Failed to uncompress name!\n"));
+ return False;
+ }
+ nsrec->hostname = talloc_strdup( ctx, nsname );
+
+ return True;
+}
+
+/*********************************************************************
+ Sort SRV record list based on weight and priority. See RFC 2782.
+*********************************************************************/
+
+static int dnssrvcmp( struct dns_rr_srv *a, struct dns_rr_srv *b )
+{
+ if ( a->priority == b->priority ) {
+
+ /* randomize entries with an equal weight and priority */
+ if ( a->weight == b->weight )
+ return 0;
+
+ /* higher weights should be sorted lower */
+ if ( a->weight > b->weight )
+ return -1;
+ else
+ return 1;
+ }
+
+ if ( a->priority < b->priority )
+ return -1;
+
+ return 1;
+}
+
+/*********************************************************************
+ Simple wrapper for a DNS query
+*********************************************************************/
+
+#define DNS_FAILED_WAITTIME 30
+
+static NTSTATUS dns_send_req( TALLOC_CTX *ctx, const char *name, int q_type,
+ uint8 **buf, int *resp_length )
+{
+ uint8 *buffer = NULL;
+ size_t buf_len = 0;
+ int resp_len = NS_PACKETSZ;
+ static time_t last_dns_check = 0;
+ static NTSTATUS last_dns_status = NT_STATUS_OK;
+ time_t now = time(NULL);
+
+ /* Try to prevent bursts of DNS lookups if the server is down */
+
+ /* Protect against large clock changes */
+
+ if ( last_dns_check > now )
+ last_dns_check = 0;
+
+ /* IF we had a DNS timeout or a bad server and we are still
+ in the 30 second cache window, just return the previous
+ status and save the network timeout. */
+
+ if ( (NT_STATUS_EQUAL(last_dns_status,NT_STATUS_IO_TIMEOUT) ||
+ NT_STATUS_EQUAL(last_dns_status,NT_STATUS_CONNECTION_REFUSED)) &&
+ (last_dns_check+DNS_FAILED_WAITTIME) > now )
+ {
+ DEBUG(10,("last_dns_check: Returning cached status (%s)\n",
+ nt_errstr(last_dns_status) ));
+ return last_dns_status;
+ }
+
+ /* Send the Query */
+ do {
+ if ( buffer )
+ TALLOC_FREE( buffer );
+
+ buf_len = resp_len * sizeof(uint8);
+
+ if (buf_len) {
+ if ((buffer = TALLOC_ARRAY(ctx, uint8, buf_len))
+ == NULL ) {
+ DEBUG(0,("ads_dns_lookup_srv: "
+ "talloc() failed!\n"));
+ last_dns_status = NT_STATUS_NO_MEMORY;
+ last_dns_check = time(NULL);
+ return last_dns_status;
+ }
+ }
+
+ if ((resp_len = res_query(name, C_IN, q_type, buffer, buf_len))
+ < 0 ) {
+ DEBUG(3,("ads_dns_lookup_srv: "
+ "Failed to resolve %s (%s)\n",
+ name, strerror(errno)));
+ TALLOC_FREE( buffer );
+ last_dns_status = NT_STATUS_UNSUCCESSFUL;
+
+ if (errno == ETIMEDOUT) {
+ last_dns_status = NT_STATUS_IO_TIMEOUT;
+ }
+ if (errno == ECONNREFUSED) {
+ last_dns_status = NT_STATUS_CONNECTION_REFUSED;
+ }
+ last_dns_check = time(NULL);
+ return last_dns_status;
+ }
+
+ /* On AIX, Solaris, and possibly some older glibc systems (e.g. SLES8)
+ truncated replies never give back a resp_len > buflen
+ which ends up causing DNS resolve failures on large tcp DNS replies */
+
+ if (buf_len == resp_len) {
+ if (resp_len == MAX_DNS_PACKET_SIZE) {
+ DEBUG(1,("dns_send_req: DNS reply too large when resolving %s\n",
+ name));
+ TALLOC_FREE( buffer );
+ last_dns_status = NT_STATUS_BUFFER_TOO_SMALL;
+ last_dns_check = time(NULL);
+ return last_dns_status;
+ }
+
+ resp_len = MIN(resp_len*2, MAX_DNS_PACKET_SIZE);
+ }
+
+
+ } while ( buf_len < resp_len && resp_len <= MAX_DNS_PACKET_SIZE );
+
+ *buf = buffer;
+ *resp_length = resp_len;
+
+ last_dns_check = time(NULL);
+ last_dns_status = NT_STATUS_OK;
+ return last_dns_status;
+}
+
+/*********************************************************************
+ Simple wrapper for a DNS SRV query
+*********************************************************************/
+
+static NTSTATUS ads_dns_lookup_srv( TALLOC_CTX *ctx,
+ const char *name,
+ struct dns_rr_srv **dclist,
+ int *numdcs)
+{
+ uint8 *buffer = NULL;
+ int resp_len = 0;
+ struct dns_rr_srv *dcs = NULL;
+ int query_count, answer_count, auth_count, additional_count;
+ uint8 *p = buffer;
+ int rrnum;
+ int idx = 0;
+ NTSTATUS status;
+
+ if ( !ctx || !name || !dclist ) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Send the request. May have to loop several times in case
+ of large replies */
+
+ status = dns_send_req( ctx, name, T_SRV, &buffer, &resp_len );
+ if ( !NT_STATUS_IS_OK(status) ) {
+ DEBUG(3,("ads_dns_lookup_srv: Failed to send DNS query (%s)\n",
+ nt_errstr(status)));
+ return status;
+ }
+ p = buffer;
+
+ /* For some insane reason, the ns_initparse() et. al. routines are only
+ available in libresolv.a, and not the shared lib. Who knows why....
+ So we have to parse the DNS reply ourselves */
+
+ /* Pull the answer RR's count from the header.
+ * Use the NMB ordering macros */
+
+ query_count = RSVAL( p, 4 );
+ answer_count = RSVAL( p, 6 );
+ auth_count = RSVAL( p, 8 );
+ additional_count = RSVAL( p, 10 );
+
+ DEBUG(4,("ads_dns_lookup_srv: "
+ "%d records returned in the answer section.\n",
+ answer_count));
+
+ if (answer_count) {
+ if ((dcs = TALLOC_ZERO_ARRAY(ctx, struct dns_rr_srv,
+ answer_count)) == NULL ) {
+ DEBUG(0,("ads_dns_lookup_srv: "
+ "talloc() failure for %d char*'s\n",
+ answer_count));
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ dcs = NULL;
+ }
+
+ /* now skip the header */
+
+ p += NS_HFIXEDSZ;
+
+ /* parse the query section */
+
+ for ( rrnum=0; rrnum<query_count; rrnum++ ) {
+ struct dns_query q;
+
+ if (!ads_dns_parse_query(ctx, buffer,
+ buffer+resp_len, &p, &q)) {
+ DEBUG(1,("ads_dns_lookup_srv: "
+ "Failed to parse query record [%d]!\n", rrnum));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ /* now we are at the answer section */
+
+ for ( rrnum=0; rrnum<answer_count; rrnum++ ) {
+ if (!ads_dns_parse_rr_srv(ctx, buffer, buffer+resp_len,
+ &p, &dcs[rrnum])) {
+ DEBUG(1,("ads_dns_lookup_srv: "
+ "Failed to parse answer recordi [%d]!\n", rrnum));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+ idx = rrnum;
+
+ /* Parse the authority section */
+ /* just skip these for now */
+
+ for ( rrnum=0; rrnum<auth_count; rrnum++ ) {
+ struct dns_rr rr;
+
+ if (!ads_dns_parse_rr( ctx, buffer,
+ buffer+resp_len, &p, &rr)) {
+ DEBUG(1,("ads_dns_lookup_srv: "
+ "Failed to parse authority record! [%d]\n", rrnum));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ /* Parse the additional records section */
+
+ for ( rrnum=0; rrnum<additional_count; rrnum++ ) {
+ struct dns_rr rr;
+ int i;
+
+ if (!ads_dns_parse_rr(ctx, buffer, buffer+resp_len,
+ &p, &rr)) {
+ DEBUG(1,("ads_dns_lookup_srv: Failed "
+ "to parse additional records section! [%d]\n", rrnum));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* Only interested in A or AAAA records as a shortcut for having
+ * to come back later and lookup the name. For multi-homed
+ * hosts, the number of additional records and exceed the
+ * number of answer records. */
+
+ if (rr.type != T_A || rr.rdatalen != 4) {
+#if defined(HAVE_IPV6)
+ /* FIXME. RFC2874 defines A6 records. This
+ * requires recusive and horribly complex lookups.
+ * Bastards. Ignore this for now.... JRA.
+ */
+ if (rr.type != T_AAAA || rr.rdatalen != 16)
+#endif
+ continue;
+ }
+
+ for ( i=0; i<idx; i++ ) {
+ if ( strcmp( rr.hostname, dcs[i].hostname ) == 0 ) {
+ int num_ips = dcs[i].num_ips;
+ struct sockaddr_storage *tmp_ss_s;
+
+ /* allocate new memory */
+
+ if (dcs[i].num_ips == 0) {
+ if ((dcs[i].ss_s = TALLOC_ARRAY(dcs,
+ struct sockaddr_storage, 1 ))
+ == NULL ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ if ((tmp_ss_s = TALLOC_REALLOC_ARRAY(dcs,
+ dcs[i].ss_s,
+ struct sockaddr_storage,
+ dcs[i].num_ips+1))
+ == NULL ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ dcs[i].ss_s = tmp_ss_s;
+ }
+ dcs[i].num_ips++;
+
+ /* copy the new IP address */
+ if (rr.type == T_A) {
+ struct in_addr ip;
+ memcpy(&ip, rr.rdata, 4);
+ in_addr_to_sockaddr_storage(
+ &dcs[i].ss_s[num_ips],
+ ip);
+ }
+#if defined(HAVE_IPV6)
+ if (rr.type == T_AAAA) {
+ struct in6_addr ip6;
+ memcpy(&ip6, rr.rdata, rr.rdatalen);
+ in6_addr_to_sockaddr_storage(
+ &dcs[i].ss_s[num_ips],
+ ip6);
+ }
+#endif
+ }
+ }
+ }
+
+ qsort( dcs, idx, sizeof(struct dns_rr_srv), QSORT_CAST dnssrvcmp );
+
+ *dclist = dcs;
+ *numdcs = idx;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Simple wrapper for a DNS NS query
+*********************************************************************/
+
+NTSTATUS ads_dns_lookup_ns(TALLOC_CTX *ctx,
+ const char *dnsdomain,
+ struct dns_rr_ns **nslist,
+ int *numns)
+{
+ uint8 *buffer = NULL;
+ int resp_len = 0;
+ struct dns_rr_ns *nsarray = NULL;
+ int query_count, answer_count, auth_count, additional_count;
+ uint8 *p;
+ int rrnum;
+ int idx = 0;
+ NTSTATUS status;
+
+ if ( !ctx || !dnsdomain || !nslist ) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Send the request. May have to loop several times in case
+ of large replies */
+
+ status = dns_send_req( ctx, dnsdomain, T_NS, &buffer, &resp_len );
+ if ( !NT_STATUS_IS_OK(status) ) {
+ DEBUG(3,("ads_dns_lookup_ns: Failed to send DNS query (%s)\n",
+ nt_errstr(status)));
+ return status;
+ }
+ p = buffer;
+
+ /* For some insane reason, the ns_initparse() et. al. routines are only
+ available in libresolv.a, and not the shared lib. Who knows why....
+ So we have to parse the DNS reply ourselves */
+
+ /* Pull the answer RR's count from the header.
+ * Use the NMB ordering macros */
+
+ query_count = RSVAL( p, 4 );
+ answer_count = RSVAL( p, 6 );
+ auth_count = RSVAL( p, 8 );
+ additional_count = RSVAL( p, 10 );
+
+ DEBUG(4,("ads_dns_lookup_ns: "
+ "%d records returned in the answer section.\n",
+ answer_count));
+
+ if (answer_count) {
+ if ((nsarray = TALLOC_ARRAY(ctx, struct dns_rr_ns,
+ answer_count)) == NULL ) {
+ DEBUG(0,("ads_dns_lookup_ns: "
+ "talloc() failure for %d char*'s\n",
+ answer_count));
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ nsarray = NULL;
+ }
+
+ /* now skip the header */
+
+ p += NS_HFIXEDSZ;
+
+ /* parse the query section */
+
+ for ( rrnum=0; rrnum<query_count; rrnum++ ) {
+ struct dns_query q;
+
+ if (!ads_dns_parse_query(ctx, buffer, buffer+resp_len,
+ &p, &q)) {
+ DEBUG(1,("ads_dns_lookup_ns: "
+ " Failed to parse query record!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ /* now we are at the answer section */
+
+ for ( rrnum=0; rrnum<answer_count; rrnum++ ) {
+ if (!ads_dns_parse_rr_ns(ctx, buffer, buffer+resp_len,
+ &p, &nsarray[rrnum])) {
+ DEBUG(1,("ads_dns_lookup_ns: "
+ "Failed to parse answer record!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+ idx = rrnum;
+
+ /* Parse the authority section */
+ /* just skip these for now */
+
+ for ( rrnum=0; rrnum<auth_count; rrnum++ ) {
+ struct dns_rr rr;
+
+ if ( !ads_dns_parse_rr(ctx, buffer, buffer+resp_len,
+ &p, &rr)) {
+ DEBUG(1,("ads_dns_lookup_ns: "
+ "Failed to parse authority record!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ /* Parse the additional records section */
+
+ for ( rrnum=0; rrnum<additional_count; rrnum++ ) {
+ struct dns_rr rr;
+ int i;
+
+ if (!ads_dns_parse_rr(ctx, buffer, buffer+resp_len,
+ &p, &rr)) {
+ DEBUG(1,("ads_dns_lookup_ns: Failed "
+ "to parse additional records section!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* only interested in A records as a shortcut for having to come
+ back later and lookup the name */
+
+ if (rr.type != T_A || rr.rdatalen != 4) {
+#if defined(HAVE_IPV6)
+ if (rr.type != T_AAAA || rr.rdatalen != 16)
+#endif
+ continue;
+ }
+
+ for ( i=0; i<idx; i++ ) {
+ if (strcmp(rr.hostname, nsarray[i].hostname) == 0) {
+ if (rr.type == T_A) {
+ struct in_addr ip;
+ memcpy(&ip, rr.rdata, 4);
+ in_addr_to_sockaddr_storage(
+ &nsarray[i].ss,
+ ip);
+ }
+#if defined(HAVE_IPV6)
+ if (rr.type == T_AAAA) {
+ struct in6_addr ip6;
+ memcpy(&ip6, rr.rdata, rr.rdatalen);
+ in6_addr_to_sockaddr_storage(
+ &nsarray[i].ss,
+ ip6);
+ }
+#endif
+ }
+ }
+ }
+
+ *nslist = nsarray;
+ *numns = idx;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Store and fetch the AD client sitename.
+****************************************************************************/
+
+#define SITENAME_KEY "AD_SITENAME/DOMAIN/%s"
+
+static char *sitename_key(const char *realm)
+{
+ char *keystr;
+
+ if (asprintf_strupper_m(&keystr, SITENAME_KEY, realm) == -1) {
+ return NULL;
+ }
+
+ return keystr;
+}
+
+
+/****************************************************************************
+ Store the AD client sitename.
+ We store indefinately as every new CLDAP query will re-write this.
+****************************************************************************/
+
+bool sitename_store(const char *realm, const char *sitename)
+{
+ time_t expire;
+ bool ret = False;
+ char *key;
+
+ if (!gencache_init()) {
+ return False;
+ }
+
+ if (!realm || (strlen(realm) == 0)) {
+ DEBUG(0,("sitename_store: no realm\n"));
+ return False;
+ }
+
+ key = sitename_key(realm);
+
+ if (!sitename || (sitename && !*sitename)) {
+ DEBUG(5,("sitename_store: deleting empty sitename!\n"));
+ ret = gencache_del(key);
+ SAFE_FREE(key);
+ return ret;
+ }
+
+ expire = get_time_t_max(); /* Store indefinately. */
+
+ DEBUG(10,("sitename_store: realm = [%s], sitename = [%s], expire = [%u]\n",
+ realm, sitename, (unsigned int)expire ));
+
+ ret = gencache_set( key, sitename, expire );
+ SAFE_FREE(key);
+ return ret;
+}
+
+/****************************************************************************
+ Fetch the AD client sitename.
+ Caller must free.
+****************************************************************************/
+
+char *sitename_fetch(const char *realm)
+{
+ char *sitename = NULL;
+ time_t timeout;
+ bool ret = False;
+ const char *query_realm;
+ char *key;
+
+ if (!gencache_init()) {
+ return NULL;
+ }
+
+ if (!realm || (strlen(realm) == 0)) {
+ query_realm = lp_realm();
+ } else {
+ query_realm = realm;
+ }
+
+ key = sitename_key(query_realm);
+
+ ret = gencache_get( key, &sitename, &timeout );
+ SAFE_FREE(key);
+ if ( !ret ) {
+ DEBUG(5,("sitename_fetch: No stored sitename for %s\n",
+ query_realm));
+ } else {
+ DEBUG(5,("sitename_fetch: Returning sitename for %s: \"%s\"\n",
+ query_realm, sitename ));
+ }
+ return sitename;
+}
+
+/****************************************************************************
+ Did the sitename change ?
+****************************************************************************/
+
+bool stored_sitename_changed(const char *realm, const char *sitename)
+{
+ bool ret = False;
+
+ char *new_sitename;
+
+ if (!realm || (strlen(realm) == 0)) {
+ DEBUG(0,("stored_sitename_changed: no realm\n"));
+ return False;
+ }
+
+ new_sitename = sitename_fetch(realm);
+
+ if (sitename && new_sitename && !strequal(sitename, new_sitename)) {
+ ret = True;
+ } else if ((sitename && !new_sitename) ||
+ (!sitename && new_sitename)) {
+ ret = True;
+ }
+ SAFE_FREE(new_sitename);
+ return ret;
+}
+
+/********************************************************************
+ Query with optional sitename.
+********************************************************************/
+
+static NTSTATUS ads_dns_query_internal(TALLOC_CTX *ctx,
+ const char *servicename,
+ const char *dc_pdc_gc_domains,
+ const char *realm,
+ const char *sitename,
+ struct dns_rr_srv **dclist,
+ int *numdcs )
+{
+ char *name;
+ if (sitename) {
+ name = talloc_asprintf(ctx, "%s._tcp.%s._sites.%s._msdcs.%s",
+ servicename, sitename,
+ dc_pdc_gc_domains, realm);
+ } else {
+ name = talloc_asprintf(ctx, "%s._tcp.%s._msdcs.%s",
+ servicename, dc_pdc_gc_domains, realm);
+ }
+ if (!name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return ads_dns_lookup_srv( ctx, name, dclist, numdcs );
+}
+
+/********************************************************************
+ Query for AD DC's.
+********************************************************************/
+
+NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx,
+ const char *realm,
+ const char *sitename,
+ struct dns_rr_srv **dclist,
+ int *numdcs )
+{
+ NTSTATUS status;
+
+ status = ads_dns_query_internal(ctx, "_ldap", "dc", realm, sitename,
+ dclist, numdcs);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
+ return status;
+ }
+
+ if (sitename &&
+ ((!NT_STATUS_IS_OK(status)) ||
+ (NT_STATUS_IS_OK(status) && (numdcs == 0)))) {
+ /* Sitename DNS query may have failed. Try without. */
+ status = ads_dns_query_internal(ctx, "_ldap", "dc", realm,
+ NULL, dclist, numdcs);
+ }
+ return status;
+}
+
+/********************************************************************
+ Query for AD GC's.
+********************************************************************/
+
+NTSTATUS ads_dns_query_gcs(TALLOC_CTX *ctx,
+ const char *realm,
+ const char *sitename,
+ struct dns_rr_srv **dclist,
+ int *numdcs )
+{
+ NTSTATUS status;
+
+ status = ads_dns_query_internal(ctx, "_ldap", "gc", realm, sitename,
+ dclist, numdcs);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
+ return status;
+ }
+
+ if (sitename &&
+ ((!NT_STATUS_IS_OK(status)) ||
+ (NT_STATUS_IS_OK(status) && (numdcs == 0)))) {
+ /* Sitename DNS query may have failed. Try without. */
+ status = ads_dns_query_internal(ctx, "_ldap", "gc", realm,
+ NULL, dclist, numdcs);
+ }
+ return status;
+}
+
+/********************************************************************
+ Query for AD KDC's.
+ Even if our underlying kerberos libraries are UDP only, this
+ is pretty safe as it's unlikely that a KDC supports TCP and not UDP.
+********************************************************************/
+
+NTSTATUS ads_dns_query_kdcs(TALLOC_CTX *ctx,
+ const char *dns_forest_name,
+ const char *sitename,
+ struct dns_rr_srv **dclist,
+ int *numdcs )
+{
+ NTSTATUS status;
+
+ status = ads_dns_query_internal(ctx, "_kerberos", "dc",
+ dns_forest_name, sitename, dclist,
+ numdcs);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
+ return status;
+ }
+
+ if (sitename &&
+ ((!NT_STATUS_IS_OK(status)) ||
+ (NT_STATUS_IS_OK(status) && (numdcs == 0)))) {
+ /* Sitename DNS query may have failed. Try without. */
+ status = ads_dns_query_internal(ctx, "_kerberos", "dc",
+ dns_forest_name, NULL,
+ dclist, numdcs);
+ }
+ return status;
+}
+
+/********************************************************************
+ Query for AD PDC. Sitename is obsolete here.
+********************************************************************/
+
+NTSTATUS ads_dns_query_pdc(TALLOC_CTX *ctx,
+ const char *dns_domain_name,
+ struct dns_rr_srv **dclist,
+ int *numdcs )
+{
+ return ads_dns_query_internal(ctx, "_ldap", "pdc", dns_domain_name,
+ NULL, dclist, numdcs);
+}
+
+/********************************************************************
+ Query for AD DC by guid. Sitename is obsolete here.
+********************************************************************/
+
+NTSTATUS ads_dns_query_dcs_guid(TALLOC_CTX *ctx,
+ const char *dns_forest_name,
+ const struct GUID *domain_guid,
+ struct dns_rr_srv **dclist,
+ int *numdcs )
+{
+ /*_ldap._tcp.DomainGuid.domains._msdcs.DnsForestName */
+
+ const char *domains;
+ const char *guid_string;
+
+ guid_string = GUID_string(ctx, domain_guid);
+ if (!guid_string) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* little hack */
+ domains = talloc_asprintf(ctx, "%s.domains", guid_string);
+ if (!domains) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return ads_dns_query_internal(ctx, "_ldap", domains, dns_forest_name,
+ NULL, dclist, numdcs);
+}
diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c
new file mode 100644
index 0000000000..501ef010fd
--- /dev/null
+++ b/source3/libads/kerberos.c
@@ -0,0 +1,1019 @@
+/*
+ Unix SMB/CIFS implementation.
+ kerberos utility library
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Remus Koos 2001
+ Copyright (C) Nalin Dahyabhai <nalin@redhat.com> 2004.
+ Copyright (C) Jeremy Allison 2004.
+ Copyright (C) Gerald Carter 2006.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_KRB5
+
+#define DEFAULT_KRB5_PORT 88
+
+#define LIBADS_CCACHE_NAME "MEMORY:libads"
+
+/*
+ we use a prompter to avoid a crash bug in the kerberos libs when
+ dealing with empty passwords
+ this prompter is just a string copy ...
+*/
+static krb5_error_code
+kerb_prompter(krb5_context ctx, void *data,
+ const char *name,
+ const char *banner,
+ int num_prompts,
+ krb5_prompt prompts[])
+{
+ if (num_prompts == 0) return 0;
+
+ memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
+ if (prompts[0].reply->length > 0) {
+ if (data) {
+ strncpy(prompts[0].reply->data, (const char *)data,
+ prompts[0].reply->length-1);
+ prompts[0].reply->length = strlen(prompts[0].reply->data);
+ } else {
+ prompts[0].reply->length = 0;
+ }
+ }
+ return 0;
+}
+
+static bool smb_krb5_err_io_nstatus(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *edata_blob,
+ KRB5_EDATA_NTSTATUS *edata)
+{
+ bool ret = False;
+ prs_struct ps;
+
+ if (!mem_ctx || !edata_blob || !edata)
+ return False;
+
+ if (!prs_init(&ps, edata_blob->length, mem_ctx, UNMARSHALL))
+ return False;
+
+ if (!prs_copy_data_in(&ps, (char *)edata_blob->data, edata_blob->length))
+ goto out;
+
+ prs_set_offset(&ps, 0);
+
+ if (!prs_ntstatus("ntstatus", &ps, 1, &edata->ntstatus))
+ goto out;
+
+ if (!prs_uint32("unknown1", &ps, 1, &edata->unknown1))
+ goto out;
+
+ if (!prs_uint32("unknown2", &ps, 1, &edata->unknown2)) /* only seen 00000001 here */
+ goto out;
+
+ ret = True;
+ out:
+ prs_mem_free(&ps);
+
+ return ret;
+}
+
+ static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error *error,
+ NTSTATUS *nt_status)
+{
+ DATA_BLOB edata;
+ DATA_BLOB unwrapped_edata;
+ TALLOC_CTX *mem_ctx;
+ KRB5_EDATA_NTSTATUS parsed_edata;
+
+#ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
+ edata = data_blob(error->e_data->data, error->e_data->length);
+#else
+ edata = data_blob(error->e_data.data, error->e_data.length);
+#endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
+
+#ifdef DEVELOPER
+ dump_data(10, edata.data, edata.length);
+#endif /* DEVELOPER */
+
+ mem_ctx = talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
+ if (mem_ctx == NULL) {
+ data_blob_free(&edata);
+ return False;
+ }
+
+ if (!unwrap_edata_ntstatus(mem_ctx, &edata, &unwrapped_edata)) {
+ data_blob_free(&edata);
+ TALLOC_FREE(mem_ctx);
+ return False;
+ }
+
+ data_blob_free(&edata);
+
+ if (!smb_krb5_err_io_nstatus(mem_ctx, &unwrapped_edata, &parsed_edata)) {
+ data_blob_free(&unwrapped_edata);
+ TALLOC_FREE(mem_ctx);
+ return False;
+ }
+
+ data_blob_free(&unwrapped_edata);
+
+ if (nt_status) {
+ *nt_status = parsed_edata.ntstatus;
+ }
+
+ TALLOC_FREE(mem_ctx);
+
+ return True;
+}
+
+ static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx,
+ krb5_get_init_creds_opt *opt,
+ NTSTATUS *nt_status)
+{
+ bool ret = False;
+ krb5_error *error = NULL;
+
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
+ ret = krb5_get_init_creds_opt_get_error(ctx, opt, &error);
+ if (ret) {
+ DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n",
+ error_message(ret)));
+ return False;
+ }
+#endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
+
+ if (!error) {
+ DEBUG(1,("no krb5_error\n"));
+ return False;
+ }
+
+#ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
+ if (!error->e_data) {
+#else
+ if (error->e_data.data == NULL) {
+#endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
+ DEBUG(1,("no edata in krb5_error\n"));
+ krb5_free_error(ctx, error);
+ return False;
+ }
+
+ ret = smb_krb5_get_ntstatus_from_krb5_error(error, nt_status);
+
+ krb5_free_error(ctx, error);
+
+ return ret;
+}
+
+/*
+ simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
+ place in default cache location.
+ remus@snapserver.com
+*/
+int kerberos_kinit_password_ext(const char *principal,
+ const char *password,
+ int time_offset,
+ time_t *expire_time,
+ time_t *renew_till_time,
+ const char *cache_name,
+ bool request_pac,
+ bool add_netbios_addr,
+ time_t renewable_time,
+ NTSTATUS *ntstatus)
+{
+ krb5_context ctx = NULL;
+ krb5_error_code code = 0;
+ krb5_ccache cc = NULL;
+ krb5_principal me = NULL;
+ krb5_creds my_creds;
+ krb5_get_init_creds_opt *opt = NULL;
+ smb_krb5_addresses *addr = NULL;
+
+ ZERO_STRUCT(my_creds);
+
+ initialize_krb5_error_table();
+ if ((code = krb5_init_context(&ctx)))
+ goto out;
+
+ if (time_offset != 0) {
+ krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
+ }
+
+ DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
+ principal,
+ cache_name ? cache_name: krb5_cc_default_name(ctx),
+ getenv("KRB5_CONFIG")));
+
+ if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
+ goto out;
+ }
+
+ if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
+ goto out;
+ }
+
+ if ((code = smb_krb5_get_init_creds_opt_alloc(ctx, &opt))) {
+ goto out;
+ }
+
+ krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
+ krb5_get_init_creds_opt_set_forwardable(opt, True);
+#if 0
+ /* insane testing */
+ krb5_get_init_creds_opt_set_tkt_life(opt, 60);
+#endif
+
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
+ if (request_pac) {
+ if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
+ goto out;
+ }
+ }
+#endif
+ if (add_netbios_addr) {
+ if ((code = smb_krb5_gen_netbios_krb5_address(&addr))) {
+ goto out;
+ }
+ krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
+ }
+
+ if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password),
+ kerb_prompter, CONST_DISCARD(char *,password),
+ 0, NULL, opt))) {
+ goto out;
+ }
+
+ if ((code = krb5_cc_initialize(ctx, cc, me))) {
+ goto out;
+ }
+
+ if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
+ goto out;
+ }
+
+ if (expire_time) {
+ *expire_time = (time_t) my_creds.times.endtime;
+ }
+
+ if (renew_till_time) {
+ *renew_till_time = (time_t) my_creds.times.renew_till;
+ }
+ out:
+ if (ntstatus) {
+
+ NTSTATUS status;
+
+ /* fast path */
+ if (code == 0) {
+ *ntstatus = NT_STATUS_OK;
+ goto cleanup;
+ }
+
+ /* try to get ntstatus code out of krb5_error when we have it
+ * inside the krb5_get_init_creds_opt - gd */
+
+ if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
+ *ntstatus = status;
+ goto cleanup;
+ }
+
+ /* fall back to self-made-mapping */
+ *ntstatus = krb5_to_nt_status(code);
+ }
+
+ cleanup:
+ krb5_free_cred_contents(ctx, &my_creds);
+ if (me) {
+ krb5_free_principal(ctx, me);
+ }
+ if (addr) {
+ smb_krb5_free_addresses(ctx, addr);
+ }
+ if (opt) {
+ smb_krb5_get_init_creds_opt_free(ctx, opt);
+ }
+ if (cc) {
+ krb5_cc_close(ctx, cc);
+ }
+ if (ctx) {
+ krb5_free_context(ctx);
+ }
+ return code;
+}
+
+
+
+/* run kinit to setup our ccache */
+int ads_kinit_password(ADS_STRUCT *ads)
+{
+ char *s;
+ int ret;
+ const char *account_name;
+ fstring acct_name;
+
+ if (ads->auth.flags & ADS_AUTH_USER_CREDS) {
+ account_name = ads->auth.user_name;
+ goto got_accountname;
+ }
+
+ if ( IS_DC ) {
+ /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
+ account_name = lp_workgroup();
+ } else {
+ /* always use the sAMAccountName for security = domain */
+ /* global_myname()$@REA.LM */
+ if ( lp_security() == SEC_DOMAIN ) {
+ fstr_sprintf( acct_name, "%s$", global_myname() );
+ account_name = acct_name;
+ }
+ else
+ /* This looks like host/global_myname()@REA.LM */
+ account_name = ads->auth.user_name;
+ }
+
+ got_accountname:
+ if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
+ return KRB5_CC_NOMEM;
+ }
+
+ if (!ads->auth.password) {
+ SAFE_FREE(s);
+ return KRB5_LIBOS_CANTREADPWD;
+ }
+
+ ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
+ &ads->auth.tgt_expire, NULL, NULL, False, False, ads->auth.renewable,
+ NULL);
+
+ if (ret) {
+ DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
+ s, error_message(ret)));
+ }
+ SAFE_FREE(s);
+ return ret;
+}
+
+int ads_kdestroy(const char *cc_name)
+{
+ krb5_error_code code;
+ krb5_context ctx = NULL;
+ krb5_ccache cc = NULL;
+
+ initialize_krb5_error_table();
+ if ((code = krb5_init_context (&ctx))) {
+ DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
+ error_message(code)));
+ return code;
+ }
+
+ if (!cc_name) {
+ if ((code = krb5_cc_default(ctx, &cc))) {
+ krb5_free_context(ctx);
+ return code;
+ }
+ } else {
+ if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
+ DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
+ error_message(code)));
+ krb5_free_context(ctx);
+ return code;
+ }
+ }
+
+ if ((code = krb5_cc_destroy (ctx, cc))) {
+ DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
+ error_message(code)));
+ }
+
+ krb5_free_context (ctx);
+ return code;
+}
+
+/************************************************************************
+ Routine to fetch the salting principal for a service. Active
+ Directory may use a non-obvious principal name to generate the salt
+ when it determines the key to use for encrypting tickets for a service,
+ and hopefully we detected that when we joined the domain.
+ ************************************************************************/
+
+static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
+{
+ char *key = NULL;
+ char *ret = NULL;
+
+ if (asprintf(&key, "%s/%s/enctype=%d",
+ SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
+ return NULL;
+ }
+ ret = (char *)secrets_fetch(key, NULL);
+ SAFE_FREE(key);
+ return ret;
+}
+
+/************************************************************************
+ Return the standard DES salt key
+************************************************************************/
+
+char* kerberos_standard_des_salt( void )
+{
+ fstring salt;
+
+ fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
+ strlower_m( salt );
+ fstrcat( salt, lp_realm() );
+
+ return SMB_STRDUP( salt );
+}
+
+/************************************************************************
+************************************************************************/
+
+static char* des_salt_key( void )
+{
+ char *key;
+
+ if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
+ lp_realm()) == -1) {
+ return NULL;
+ }
+
+ return key;
+}
+
+/************************************************************************
+************************************************************************/
+
+bool kerberos_secrets_store_des_salt( const char* salt )
+{
+ char* key;
+ bool ret;
+
+ if ( (key = des_salt_key()) == NULL ) {
+ DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
+ return False;
+ }
+
+ if ( !salt ) {
+ DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
+ secrets_delete( key );
+ return True;
+ }
+
+ DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
+
+ ret = secrets_store( key, salt, strlen(salt)+1 );
+
+ SAFE_FREE( key );
+
+ return ret;
+}
+
+/************************************************************************
+************************************************************************/
+
+char* kerberos_secrets_fetch_des_salt( void )
+{
+ char *salt, *key;
+
+ if ( (key = des_salt_key()) == NULL ) {
+ DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
+ return False;
+ }
+
+ salt = (char*)secrets_fetch( key, NULL );
+
+ SAFE_FREE( key );
+
+ return salt;
+}
+
+/************************************************************************
+ Routine to get the default realm from the kerberos credentials cache.
+ Caller must free if the return value is not NULL.
+************************************************************************/
+
+char *kerberos_get_default_realm_from_ccache( void )
+{
+ char *realm = NULL;
+ krb5_context ctx = NULL;
+ krb5_ccache cc = NULL;
+ krb5_principal princ = NULL;
+
+ initialize_krb5_error_table();
+ if (krb5_init_context(&ctx)) {
+ return NULL;
+ }
+
+ DEBUG(5,("kerberos_get_default_realm_from_ccache: "
+ "Trying to read krb5 cache: %s\n",
+ krb5_cc_default_name(ctx)));
+ if (krb5_cc_default(ctx, &cc)) {
+ DEBUG(0,("kerberos_get_default_realm_from_ccache: "
+ "failed to read default cache\n"));
+ goto out;
+ }
+ if (krb5_cc_get_principal(ctx, cc, &princ)) {
+ DEBUG(0,("kerberos_get_default_realm_from_ccache: "
+ "failed to get default principal\n"));
+ goto out;
+ }
+
+#if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
+ realm = SMB_STRDUP(krb5_principal_get_realm(ctx, princ));
+#elif defined(HAVE_KRB5_PRINC_REALM)
+ {
+ krb5_data *realm_data = krb5_princ_realm(ctx, princ);
+ realm = SMB_STRNDUP(realm_data->data, realm_data->length);
+ }
+#endif
+
+ out:
+
+ if (princ) {
+ krb5_free_principal(ctx, princ);
+ }
+ if (cc) {
+ krb5_cc_close(ctx, cc);
+ }
+ if (ctx) {
+ krb5_free_context(ctx);
+ }
+
+ return realm;
+}
+
+
+/************************************************************************
+ Routine to get the salting principal for this service. This is
+ maintained for backwards compatibilty with releases prior to 3.0.24.
+ Since we store the salting principal string only at join, we may have
+ to look for the older tdb keys. Caller must free if return is not null.
+ ************************************************************************/
+
+krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
+ krb5_principal host_princ,
+ int enctype)
+{
+ char *unparsed_name = NULL, *salt_princ_s = NULL;
+ krb5_principal ret_princ = NULL;
+
+ /* lookup new key first */
+
+ if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
+
+ /* look under the old key. If this fails, just use the standard key */
+
+ if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
+ return (krb5_principal)NULL;
+ }
+ if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
+ /* fall back to host/machine.realm@REALM */
+ salt_princ_s = kerberos_standard_des_salt();
+ }
+ }
+
+ if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
+ ret_princ = NULL;
+ }
+
+ SAFE_FREE(unparsed_name);
+ SAFE_FREE(salt_princ_s);
+
+ return ret_princ;
+}
+
+/************************************************************************
+ Routine to set the salting principal for this service. Active
+ Directory may use a non-obvious principal name to generate the salt
+ when it determines the key to use for encrypting tickets for a service,
+ and hopefully we detected that when we joined the domain.
+ Setting principal to NULL deletes this entry.
+ ************************************************************************/
+
+bool kerberos_secrets_store_salting_principal(const char *service,
+ int enctype,
+ const char *principal)
+{
+ char *key = NULL;
+ bool ret = False;
+ krb5_context context = NULL;
+ krb5_principal princ = NULL;
+ char *princ_s = NULL;
+ char *unparsed_name = NULL;
+ krb5_error_code code;
+
+ if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
+ DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
+ error_message(code)));
+ return False;
+ }
+ if (strchr_m(service, '@')) {
+ if (asprintf(&princ_s, "%s", service) == -1) {
+ goto out;
+ }
+ } else {
+ if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
+ goto out;
+ }
+ }
+
+ if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
+ goto out;
+
+ }
+ if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
+ goto out;
+ }
+
+ if (asprintf(&key, "%s/%s/enctype=%d",
+ SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
+ == -1) {
+ goto out;
+ }
+
+ if ((principal != NULL) && (strlen(principal) > 0)) {
+ ret = secrets_store(key, principal, strlen(principal) + 1);
+ } else {
+ ret = secrets_delete(key);
+ }
+
+ out:
+
+ SAFE_FREE(key);
+ SAFE_FREE(princ_s);
+ SAFE_FREE(unparsed_name);
+
+ if (princ) {
+ krb5_free_principal(context, princ);
+ }
+
+ if (context) {
+ krb5_free_context(context);
+ }
+
+ return ret;
+}
+
+
+/************************************************************************
+************************************************************************/
+
+int kerberos_kinit_password(const char *principal,
+ const char *password,
+ int time_offset,
+ const char *cache_name)
+{
+ return kerberos_kinit_password_ext(principal,
+ password,
+ time_offset,
+ 0,
+ 0,
+ cache_name,
+ False,
+ False,
+ 0,
+ NULL);
+}
+
+/************************************************************************
+************************************************************************/
+
+static char *print_kdc_line(char *mem_ctx,
+ const char *prev_line,
+ const struct sockaddr_storage *pss)
+{
+ char *kdc_str = NULL;
+
+ if (pss->ss_family == AF_INET) {
+ kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
+ prev_line,
+ print_canonical_sockaddr(mem_ctx, pss));
+ } else {
+ char addr[INET6_ADDRSTRLEN];
+ uint16_t port = get_sockaddr_port(pss);
+
+ if (port != 0 && port != DEFAULT_KRB5_PORT) {
+ /* Currently for IPv6 we can't specify a non-default
+ krb5 port with an address, as this requires a ':'.
+ Resolve to a name. */
+ char hostname[MAX_DNS_NAME_LENGTH];
+ int ret = sys_getnameinfo((const struct sockaddr *)pss,
+ sizeof(*pss),
+ hostname, sizeof(hostname),
+ NULL, 0,
+ NI_NAMEREQD);
+ if (ret) {
+ DEBUG(0,("print_kdc_line: can't resolve name "
+ "for kdc with non-default port %s. "
+ "Error %s\n.",
+ print_canonical_sockaddr(mem_ctx, pss),
+ gai_strerror(ret)));
+ }
+ /* Success, use host:port */
+ kdc_str = talloc_asprintf(mem_ctx,
+ "%s\tkdc = %s:%u\n",
+ prev_line,
+ hostname,
+ (unsigned int)port);
+ } else {
+ kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
+ prev_line,
+ print_sockaddr(addr,
+ sizeof(addr),
+ pss));
+ }
+ }
+ return kdc_str;
+}
+
+/************************************************************************
+ Create a string list of available kdc's, possibly searching by sitename.
+ Does DNS queries.
+
+ If "sitename" is given, the DC's in that site are listed first.
+
+************************************************************************/
+
+static char *get_kdc_ip_string(char *mem_ctx,
+ const char *realm,
+ const char *sitename,
+ struct sockaddr_storage *pss)
+{
+ int i;
+ struct ip_service *ip_srv_site = NULL;
+ struct ip_service *ip_srv_nonsite = NULL;
+ int count_site = 0;
+ int count_nonsite;
+ char *kdc_str = print_kdc_line(mem_ctx, "", pss);
+
+ if (kdc_str == NULL) {
+ return NULL;
+ }
+
+ /*
+ * First get the KDC's only in this site, the rest will be
+ * appended later
+ */
+
+ if (sitename) {
+
+ get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
+
+ for (i = 0; i < count_site; i++) {
+ if (addr_equal(&ip_srv_site[i].ss, pss)) {
+ continue;
+ }
+ /* Append to the string - inefficient
+ * but not done often. */
+ kdc_str = print_kdc_line(mem_ctx,
+ kdc_str,
+ &ip_srv_site[i].ss);
+ if (!kdc_str) {
+ SAFE_FREE(ip_srv_site);
+ return NULL;
+ }
+ }
+ }
+
+ /* Get all KDC's. */
+
+ get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
+
+ for (i = 0; i < count_nonsite; i++) {
+ int j;
+
+ if (addr_equal(&ip_srv_nonsite[i].ss, pss)) {
+ continue;
+ }
+
+ /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
+ for (j = 0; j < count_site; j++) {
+ if (addr_equal(&ip_srv_nonsite[i].ss,
+ &ip_srv_site[j].ss)) {
+ break;
+ }
+ /* As the lists are sorted we can break early if nonsite > site. */
+ if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
+ break;
+ }
+ }
+ if (j != i) {
+ continue;
+ }
+
+ /* Append to the string - inefficient but not done often. */
+ kdc_str = print_kdc_line(mem_ctx,
+ kdc_str,
+ &ip_srv_nonsite[i].ss);
+ if (!kdc_str) {
+ SAFE_FREE(ip_srv_site);
+ SAFE_FREE(ip_srv_nonsite);
+ return NULL;
+ }
+ }
+
+
+ SAFE_FREE(ip_srv_site);
+ SAFE_FREE(ip_srv_nonsite);
+
+ DEBUG(10,("get_kdc_ip_string: Returning %s\n",
+ kdc_str ));
+
+ return kdc_str;
+}
+
+/************************************************************************
+ Create a specific krb5.conf file in the private directory pointing
+ at a specific kdc for a realm. Keyed off domain name. Sets
+ KRB5_CONFIG environment variable to point to this file. Must be
+ run as root or will fail (which is a good thing :-).
+************************************************************************/
+
+bool create_local_private_krb5_conf_for_domain(const char *realm,
+ const char *domain,
+ const char *sitename,
+ struct sockaddr_storage *pss)
+{
+ char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir());
+ char *tmpname = NULL;
+ char *fname = NULL;
+ char *file_contents = NULL;
+ char *kdc_ip_string = NULL;
+ size_t flen = 0;
+ ssize_t ret;
+ int fd;
+ char *realm_upper = NULL;
+
+ if (!dname) {
+ return False;
+ }
+ if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
+ DEBUG(0,("create_local_private_krb5_conf_for_domain: "
+ "failed to create directory %s. Error was %s\n",
+ dname, strerror(errno) ));
+ TALLOC_FREE(dname);
+ return False;
+ }
+
+ tmpname = talloc_asprintf(dname, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
+ if (!tmpname) {
+ TALLOC_FREE(dname);
+ return False;
+ }
+
+ fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
+ if (!fname) {
+ TALLOC_FREE(dname);
+ return False;
+ }
+
+ DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
+ fname, realm, domain ));
+
+ realm_upper = talloc_strdup(fname, realm);
+ strupper_m(realm_upper);
+
+ kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
+ if (!kdc_ip_string) {
+ TALLOC_FREE(dname);
+ return False;
+ }
+
+ file_contents = talloc_asprintf(fname,
+ "[libdefaults]\n\tdefault_realm = %s\n"
+ "\tdefault_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
+ "\tdefault_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
+ "\tpreferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
+ "[realms]\n\t%s = {\n"
+ "\t%s\t}\n",
+ realm_upper, realm_upper, kdc_ip_string);
+
+ if (!file_contents) {
+ TALLOC_FREE(dname);
+ return False;
+ }
+
+ flen = strlen(file_contents);
+
+ fd = smb_mkstemp(tmpname);
+ if (fd == -1) {
+ DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
+ " for file %s. Errno %s\n",
+ tmpname, strerror(errno) ));
+ TALLOC_FREE(dname);
+ return false;
+ }
+
+ if (fchmod(fd, 0644)==-1) {
+ DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
+ " Errno %s\n",
+ tmpname, strerror(errno) ));
+ unlink(tmpname);
+ close(fd);
+ TALLOC_FREE(dname);
+ return False;
+ }
+
+ ret = write(fd, file_contents, flen);
+ if (flen != ret) {
+ DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
+ " returned %d (should be %u). Errno %s\n",
+ (int)ret, (unsigned int)flen, strerror(errno) ));
+ unlink(tmpname);
+ close(fd);
+ TALLOC_FREE(dname);
+ return False;
+ }
+ if (close(fd)==-1) {
+ DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
+ " Errno %s\n", strerror(errno) ));
+ unlink(tmpname);
+ TALLOC_FREE(dname);
+ return False;
+ }
+
+ if (rename(tmpname, fname) == -1) {
+ DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
+ "of %s to %s failed. Errno %s\n",
+ tmpname, fname, strerror(errno) ));
+ unlink(tmpname);
+ TALLOC_FREE(dname);
+ return False;
+ }
+
+ DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
+ "file %s with realm %s KDC list = %s\n",
+ fname, realm_upper, kdc_ip_string));
+
+ /* Set the environment variable to this file. */
+ setenv("KRB5_CONFIG", fname, 1);
+
+#if defined(OVERWRITE_SYSTEM_KRB5_CONF)
+
+#define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
+ /* Insanity, sheer insanity..... */
+
+ if (strequal(realm, lp_realm())) {
+ char linkpath[PATH_MAX+1];
+ int lret;
+
+ lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
+ if (lret != -1) {
+ linkpath[lret] = '\0';
+ }
+
+ if (lret != -1 || strcmp(linkpath, fname) == 0) {
+ /* Symlink already exists. */
+ TALLOC_FREE(dname);
+ return True;
+ }
+
+ /* Try and replace with a symlink. */
+ if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
+ const char *newpath = SYSTEM_KRB5_CONF_PATH ## ".saved";
+ if (errno != EEXIST) {
+ DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
+ "of %s to %s failed. Errno %s\n",
+ fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
+ TALLOC_FREE(dname);
+ return True; /* Not a fatal error. */
+ }
+
+ /* Yes, this is a race conditon... too bad. */
+ if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
+ DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
+ "of %s to %s failed. Errno %s\n",
+ SYSTEM_KRB5_CONF_PATH, newpath,
+ strerror(errno) ));
+ TALLOC_FREE(dname);
+ return True; /* Not a fatal error. */
+ }
+
+ if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
+ DEBUG(0,("create_local_private_krb5_conf_for_domain: "
+ "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
+ fname, strerror(errno) ));
+ TALLOC_FREE(dname);
+ return True; /* Not a fatal error. */
+ }
+ }
+ }
+#endif
+
+ TALLOC_FREE(dname);
+
+ return True;
+}
+#endif
diff --git a/source3/libads/kerberos_keytab.c b/source3/libads/kerberos_keytab.c
new file mode 100644
index 0000000000..883f582445
--- /dev/null
+++ b/source3/libads/kerberos_keytab.c
@@ -0,0 +1,777 @@
+/*
+ Unix SMB/CIFS implementation.
+ kerberos keytab utility library
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Remus Koos 2001
+ Copyright (C) Luke Howard 2003
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003
+ Copyright (C) Guenther Deschner 2003
+ Copyright (C) Rakesh Patel 2004
+ Copyright (C) Dan Perry 2004
+ Copyright (C) Jeremy Allison 2004
+ Copyright (C) Gerald Carter 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_KRB5
+
+/**********************************************************************
+**********************************************************************/
+
+int smb_krb5_kt_add_entry_ext(krb5_context context,
+ krb5_keytab keytab,
+ krb5_kvno kvno,
+ const char *princ_s,
+ krb5_enctype *enctypes,
+ krb5_data password,
+ bool no_salt,
+ bool keep_old_entries)
+{
+ krb5_error_code ret = 0;
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry kt_entry;
+ krb5_principal princ = NULL;
+ int i;
+ char *ktprinc = NULL;
+
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(cursor);
+
+ ret = smb_krb5_parse_name(context, princ_s, &princ);
+ if (ret) {
+ DEBUG(1,("smb_krb5_kt_add_entry_ext: smb_krb5_parse_name(%s) failed (%s)\n", princ_s, error_message(ret)));
+ goto out;
+ }
+
+ /* Seek and delete old keytab entries */
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret != KRB5_KT_END && ret != ENOENT ) {
+ DEBUG(3,("smb_krb5_kt_add_entry_ext: Will try to delete old keytab entries\n"));
+ while(!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
+ bool compare_name_ok = False;
+
+ ret = smb_krb5_unparse_name(context, kt_entry.principal, &ktprinc);
+ if (ret) {
+ DEBUG(1,("smb_krb5_kt_add_entry_ext: smb_krb5_unparse_name failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+
+ /*---------------------------------------------------------------------------
+ * Save the entries with kvno - 1. This is what microsoft does
+ * to allow people with existing sessions that have kvno - 1 to still
+ * work. Otherwise, when the password for the machine changes, all
+ * kerberizied sessions will 'break' until either the client reboots or
+ * the client's session key expires and they get a new session ticket
+ * with the new kvno.
+ */
+
+#ifdef HAVE_KRB5_KT_COMPARE
+ compare_name_ok = (krb5_kt_compare(context, &kt_entry, princ, 0, 0) == True);
+#else
+ compare_name_ok = (strcmp(ktprinc, princ_s) == 0);
+#endif
+
+ if (!compare_name_ok) {
+ DEBUG(10,("smb_krb5_kt_add_entry_ext: ignoring keytab entry principal %s, kvno = %d\n",
+ ktprinc, kt_entry.vno));
+ }
+
+ SAFE_FREE(ktprinc);
+
+ if (compare_name_ok) {
+ if (kt_entry.vno == kvno - 1) {
+ DEBUG(5,("smb_krb5_kt_add_entry_ext: Saving previous (kvno %d) entry for principal: %s.\n",
+ kvno - 1, princ_s));
+ } else if (!keep_old_entries) {
+ DEBUG(5,("smb_krb5_kt_add_entry_ext: Found old entry for principal: %s (kvno %d) - trying to remove it.\n",
+ princ_s, kt_entry.vno));
+ ret = krb5_kt_end_seq_get(context, keytab, &cursor);
+ ZERO_STRUCT(cursor);
+ if (ret) {
+ DEBUG(1,("smb_krb5_kt_add_entry_ext: krb5_kt_end_seq_get() failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+ ret = krb5_kt_remove_entry(context, keytab, &kt_entry);
+ if (ret) {
+ DEBUG(1,("smb_krb5_kt_add_entry_ext: krb5_kt_remove_entry failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+
+ DEBUG(5,("smb_krb5_kt_add_entry_ext: removed old entry for principal: %s (kvno %d).\n",
+ princ_s, kt_entry.vno));
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret) {
+ DEBUG(1,("smb_krb5_kt_add_entry_ext: krb5_kt_start_seq failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+ ret = smb_krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
+ if (ret) {
+ DEBUG(1,("smb_krb5_kt_add_entry_ext: krb5_kt_remove_entry failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+ continue;
+ }
+ }
+
+ /* Not a match, just free this entry and continue. */
+ ret = smb_krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
+ if (ret) {
+ DEBUG(1,("smb_krb5_kt_add_entry_ext: smb_krb5_kt_free_entry failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+ }
+
+ ret = krb5_kt_end_seq_get(context, keytab, &cursor);
+ ZERO_STRUCT(cursor);
+ if (ret) {
+ DEBUG(1,("smb_krb5_kt_add_entry_ext: krb5_kt_end_seq_get failed (%s)\n",error_message(ret)));
+ goto out;
+ }
+ }
+
+ /* Ensure we don't double free. */
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(cursor);
+
+ /* If we get here, we have deleted all the old entries with kvno's not equal to the current kvno-1. */
+
+ /* Now add keytab entries for all encryption types */
+ for (i = 0; enctypes[i]; i++) {
+ krb5_keyblock *keyp;
+
+ keyp = KRB5_KT_KEY(&kt_entry);
+
+ if (create_kerberos_key_from_string(context, princ, &password, keyp, enctypes[i], no_salt)) {
+ continue;
+ }
+
+ kt_entry.principal = princ;
+ kt_entry.vno = kvno;
+
+ DEBUG(3,("smb_krb5_kt_add_entry_ext: adding keytab entry for (%s) with encryption type (%d) and version (%d)\n",
+ princ_s, enctypes[i], kt_entry.vno));
+ ret = krb5_kt_add_entry(context, keytab, &kt_entry);
+ krb5_free_keyblock_contents(context, keyp);
+ ZERO_STRUCT(kt_entry);
+ if (ret) {
+ DEBUG(1,("smb_krb5_kt_add_entry_ext: adding entry to keytab failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+ }
+
+
+out:
+ {
+ krb5_keytab_entry zero_kt_entry;
+ ZERO_STRUCT(zero_kt_entry);
+ if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
+ smb_krb5_kt_free_entry(context, &kt_entry);
+ }
+ }
+ if (princ) {
+ krb5_free_principal(context, princ);
+ }
+
+ {
+ krb5_kt_cursor zero_csr;
+ ZERO_STRUCT(zero_csr);
+ if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ }
+ }
+
+ return (int)ret;
+}
+
+static int smb_krb5_kt_add_entry(krb5_context context,
+ krb5_keytab keytab,
+ krb5_kvno kvno,
+ const char *princ_s,
+ krb5_enctype *enctypes,
+ krb5_data password)
+{
+ return smb_krb5_kt_add_entry_ext(context,
+ keytab,
+ kvno,
+ princ_s,
+ enctypes,
+ password,
+ false,
+ false);
+}
+
+/**********************************************************************
+ Adds a single service principal, i.e. 'host' to the system keytab
+***********************************************************************/
+
+int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
+{
+ krb5_error_code ret = 0;
+ krb5_context context = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_data password;
+ krb5_kvno kvno;
+ krb5_enctype enctypes[4] = { ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD5, 0, 0 };
+ char *princ_s = NULL, *short_princ_s = NULL;
+ char *password_s = NULL;
+ char *my_fqdn;
+ TALLOC_CTX *ctx = NULL;
+ char *machine_name;
+
+#if defined(ENCTYPE_ARCFOUR_HMAC)
+ enctypes[2] = ENCTYPE_ARCFOUR_HMAC;
+#endif
+
+ initialize_krb5_error_table();
+ ret = krb5_init_context(&context);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: could not krb5_init_context: %s\n",error_message(ret)));
+ return -1;
+ }
+
+ ret = smb_krb5_open_keytab(context, NULL, True, &keytab);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: smb_krb5_open_keytab failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+ /* retrieve the password */
+ if (!secrets_init()) {
+ DEBUG(1,("ads_keytab_add_entry: secrets_init failed\n"));
+ ret = -1;
+ goto out;
+ }
+ password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
+ if (!password_s) {
+ DEBUG(1,("ads_keytab_add_entry: failed to fetch machine password\n"));
+ ret = -1;
+ goto out;
+ }
+ ZERO_STRUCT(password);
+ password.data = password_s;
+ password.length = strlen(password_s);
+
+ /* we need the dNSHostName value here */
+
+ if ( (ctx = talloc_init("ads_keytab_add_entry")) == NULL ) {
+ DEBUG(0,("ads_keytab_add_entry: talloc() failed!\n"));
+ ret = -1;
+ goto out;
+ }
+
+ if ( (my_fqdn = ads_get_dnshostname( ads, ctx, global_myname())) == NULL ) {
+ DEBUG(0,("ads_keytab_add_entry: unable to determine machine account's dns name in AD!\n"));
+ ret = -1;
+ goto out;
+ }
+
+ if ( (machine_name = ads_get_samaccountname( ads, ctx, global_myname())) == NULL ) {
+ DEBUG(0,("ads_keytab_add_entry: unable to determine machine account's short name in AD!\n"));
+ ret = -1;
+ goto out;
+ }
+ /*strip the trailing '$' */
+ machine_name[strlen(machine_name)-1] = '\0';
+
+ /* Construct our principal */
+
+ if (strchr_m(srvPrinc, '@')) {
+ /* It's a fully-named principal. */
+ asprintf(&princ_s, "%s", srvPrinc);
+ } else if (srvPrinc[strlen(srvPrinc)-1] == '$') {
+ /* It's the machine account, as used by smbclient clients. */
+ asprintf(&princ_s, "%s@%s", srvPrinc, lp_realm());
+ } else {
+ /* It's a normal service principal. Add the SPN now so that we
+ * can obtain credentials for it and double-check the salt value
+ * used to generate the service's keys. */
+
+ asprintf(&princ_s, "%s/%s@%s", srvPrinc, my_fqdn, lp_realm());
+ asprintf(&short_princ_s, "%s/%s@%s", srvPrinc, machine_name, lp_realm());
+
+ /* According to http://support.microsoft.com/kb/326985/en-us,
+ certain principal names are automatically mapped to the host/...
+ principal in the AD account. So only create these in the
+ keytab, not in AD. --jerry */
+
+ if ( !strequal( srvPrinc, "cifs" ) && !strequal(srvPrinc, "host" ) ) {
+ DEBUG(3,("ads_keytab_add_entry: Attempting to add/update '%s'\n", princ_s));
+
+ if (!ADS_ERR_OK(ads_add_service_principal_name(ads, global_myname(), my_fqdn, srvPrinc))) {
+ DEBUG(1,("ads_keytab_add_entry: ads_add_service_principal_name failed.\n"));
+ goto out;
+ }
+ }
+ }
+
+ kvno = (krb5_kvno) ads_get_machine_kvno(ads, global_myname());
+ if (kvno == -1) { /* -1 indicates failure, everything else is OK */
+ DEBUG(1,("ads_keytab_add_entry: ads_get_machine_kvno failed to determine the system's kvno.\n"));
+ ret = -1;
+ goto out;
+ }
+
+ /* add the fqdn principal to the keytab */
+
+ ret = smb_krb5_kt_add_entry( context, keytab, kvno, princ_s, enctypes, password );
+ if ( ret ) {
+ DEBUG(1,("ads_keytab_add_entry: Failed to add entry to keytab file\n"));
+ goto out;
+ }
+
+ /* add the short principal name if we have one */
+
+ if ( short_princ_s ) {
+ ret = smb_krb5_kt_add_entry( context, keytab, kvno, short_princ_s, enctypes, password );
+ if ( ret ) {
+ DEBUG(1,("ads_keytab_add_entry: Failed to add short entry to keytab file\n"));
+ goto out;
+ }
+ }
+
+out:
+ SAFE_FREE( princ_s );
+ SAFE_FREE( short_princ_s );
+ TALLOC_FREE( ctx );
+
+ if (keytab) {
+ krb5_kt_close(context, keytab);
+ }
+ if (context) {
+ krb5_free_context(context);
+ }
+ return (int)ret;
+}
+
+/**********************************************************************
+ Flushes all entries from the system keytab.
+***********************************************************************/
+
+int ads_keytab_flush(ADS_STRUCT *ads)
+{
+ krb5_error_code ret = 0;
+ krb5_context context = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry kt_entry;
+ krb5_kvno kvno;
+
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(cursor);
+
+ initialize_krb5_error_table();
+ ret = krb5_init_context(&context);
+ if (ret) {
+ DEBUG(1,("ads_keytab_flush: could not krb5_init_context: %s\n",error_message(ret)));
+ return ret;
+ }
+
+ ret = smb_krb5_open_keytab(context, NULL, True, &keytab);
+ if (ret) {
+ DEBUG(1,("ads_keytab_flush: smb_krb5_open_keytab failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+ kvno = (krb5_kvno) ads_get_machine_kvno(ads, global_myname());
+ if (kvno == -1) { /* -1 indicates a failure */
+ DEBUG(1,("ads_keytab_flush: Error determining the system's kvno.\n"));
+ goto out;
+ }
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret != KRB5_KT_END && ret != ENOENT) {
+ while (!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
+ ret = krb5_kt_end_seq_get(context, keytab, &cursor);
+ ZERO_STRUCT(cursor);
+ if (ret) {
+ DEBUG(1,("ads_keytab_flush: krb5_kt_end_seq_get() failed (%s)\n",error_message(ret)));
+ goto out;
+ }
+ ret = krb5_kt_remove_entry(context, keytab, &kt_entry);
+ if (ret) {
+ DEBUG(1,("ads_keytab_flush: krb5_kt_remove_entry failed (%s)\n",error_message(ret)));
+ goto out;
+ }
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret) {
+ DEBUG(1,("ads_keytab_flush: krb5_kt_start_seq failed (%s)\n",error_message(ret)));
+ goto out;
+ }
+ ret = smb_krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
+ if (ret) {
+ DEBUG(1,("ads_keytab_flush: krb5_kt_remove_entry failed (%s)\n",error_message(ret)));
+ goto out;
+ }
+ }
+ }
+
+ /* Ensure we don't double free. */
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(cursor);
+
+ if (!ADS_ERR_OK(ads_clear_service_principal_names(ads, global_myname()))) {
+ DEBUG(1,("ads_keytab_flush: Error while clearing service principal listings in LDAP.\n"));
+ goto out;
+ }
+
+out:
+
+ {
+ krb5_keytab_entry zero_kt_entry;
+ ZERO_STRUCT(zero_kt_entry);
+ if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
+ smb_krb5_kt_free_entry(context, &kt_entry);
+ }
+ }
+ {
+ krb5_kt_cursor zero_csr;
+ ZERO_STRUCT(zero_csr);
+ if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ }
+ }
+ if (keytab) {
+ krb5_kt_close(context, keytab);
+ }
+ if (context) {
+ krb5_free_context(context);
+ }
+ return ret;
+}
+
+/**********************************************************************
+ Adds all the required service principals to the system keytab.
+***********************************************************************/
+
+int ads_keytab_create_default(ADS_STRUCT *ads)
+{
+ krb5_error_code ret = 0;
+ krb5_context context = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry kt_entry;
+ krb5_kvno kvno;
+ int i, found = 0;
+ char *sam_account_name, *upn;
+ char **oldEntries = NULL, *princ_s[26];
+ TALLOC_CTX *ctx = NULL;
+ fstring machine_name;
+
+ memset(princ_s, '\0', sizeof(princ_s));
+
+ fstrcpy( machine_name, global_myname() );
+
+ /* these are the main ones we need */
+
+ if ( (ret = ads_keytab_add_entry(ads, "host") ) != 0 ) {
+ DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding 'host'.\n"));
+ return ret;
+ }
+
+
+#if 0 /* don't create the CIFS/... keytab entries since no one except smbd
+ really needs them and we will fall back to verifying against secrets.tdb */
+
+ if ( (ret = ads_keytab_add_entry(ads, "cifs")) != 0 ) {
+ DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding 'cifs'.\n"));
+ return ret;
+ }
+#endif
+
+ if ( (ctx = talloc_init("ads_keytab_create_default")) == NULL ) {
+ DEBUG(0,("ads_keytab_create_default: talloc() failed!\n"));
+ return -1;
+ }
+
+ /* now add the userPrincipalName and sAMAccountName entries */
+
+ if ( (sam_account_name = ads_get_samaccountname( ads, ctx, machine_name)) == NULL ) {
+ DEBUG(0,("ads_keytab_add_entry: unable to determine machine account's name in AD!\n"));
+ TALLOC_FREE( ctx );
+ return -1;
+ }
+
+ /* upper case the sAMAccountName to make it easier for apps to
+ know what case to use in the keytab file */
+
+ strupper_m( sam_account_name );
+
+ if ( (ret = ads_keytab_add_entry(ads, sam_account_name )) != 0 ) {
+ DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding sAMAccountName (%s)\n",
+ sam_account_name));
+ return ret;
+ }
+
+ /* remember that not every machine account will have a upn */
+
+ upn = ads_get_upn( ads, ctx, machine_name);
+ if ( upn ) {
+ if ( (ret = ads_keytab_add_entry(ads, upn)) != 0 ) {
+ DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding UPN (%s)\n",
+ upn));
+ TALLOC_FREE( ctx );
+ return ret;
+ }
+ }
+
+ TALLOC_FREE( ctx );
+
+ /* Now loop through the keytab and update any other existing entries... */
+
+ kvno = (krb5_kvno) ads_get_machine_kvno(ads, machine_name);
+ if (kvno == -1) {
+ DEBUG(1,("ads_keytab_create_default: ads_get_machine_kvno failed to determine the system's kvno.\n"));
+ return -1;
+ }
+
+ DEBUG(3,("ads_keytab_create_default: Searching for keytab entries to "
+ "preserve and update.\n"));
+
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(cursor);
+
+ initialize_krb5_error_table();
+ ret = krb5_init_context(&context);
+ if (ret) {
+ DEBUG(1,("ads_keytab_create_default: could not krb5_init_context: %s\n",error_message(ret)));
+ return ret;
+ }
+
+ ret = smb_krb5_open_keytab(context, NULL, True, &keytab);
+ if (ret) {
+ DEBUG(1,("ads_keytab_create_default: smb_krb5_open_keytab failed (%s)\n", error_message(ret)));
+ goto done;
+ }
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret != KRB5_KT_END && ret != ENOENT ) {
+ while ((ret = krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) == 0) {
+ smb_krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
+ found++;
+ }
+ }
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ ZERO_STRUCT(cursor);
+
+ /*
+ * Hmmm. There is no "rewind" function for the keytab. This means we have a race condition
+ * where someone else could add entries after we've counted them. Re-open asap to minimise
+ * the race. JRA.
+ */
+
+ DEBUG(3, ("ads_keytab_create_default: Found %d entries in the keytab.\n", found));
+ if (!found) {
+ goto done;
+ }
+ oldEntries = SMB_MALLOC_ARRAY(char *, found );
+ if (!oldEntries) {
+ DEBUG(1,("ads_keytab_create_default: Failed to allocate space to store the old keytab entries (malloc failed?).\n"));
+ ret = -1;
+ goto done;
+ }
+ memset(oldEntries, '\0', found * sizeof(char *));
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret != KRB5_KT_END && ret != ENOENT ) {
+ while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0) {
+ if (kt_entry.vno != kvno) {
+ char *ktprinc = NULL;
+ char *p;
+
+ /* This returns a malloc'ed string in ktprinc. */
+ ret = smb_krb5_unparse_name(context, kt_entry.principal, &ktprinc);
+ if (ret) {
+ DEBUG(1,("smb_krb5_unparse_name failed (%s)\n", error_message(ret)));
+ goto done;
+ }
+ /*
+ * From looking at the krb5 source they don't seem to take locale
+ * or mb strings into account. Maybe this is because they assume utf8 ?
+ * In this case we may need to convert from utf8 to mb charset here ? JRA.
+ */
+ p = strchr_m(ktprinc, '@');
+ if (p) {
+ *p = '\0';
+ }
+
+ p = strchr_m(ktprinc, '/');
+ if (p) {
+ *p = '\0';
+ }
+ for (i = 0; i < found; i++) {
+ if (!oldEntries[i]) {
+ oldEntries[i] = ktprinc;
+ break;
+ }
+ if (!strcmp(oldEntries[i], ktprinc)) {
+ SAFE_FREE(ktprinc);
+ break;
+ }
+ }
+ if (i == found) {
+ SAFE_FREE(ktprinc);
+ }
+ }
+ smb_krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
+ }
+ ret = 0;
+ for (i = 0; oldEntries[i]; i++) {
+ ret |= ads_keytab_add_entry(ads, oldEntries[i]);
+ SAFE_FREE(oldEntries[i]);
+ }
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ }
+ ZERO_STRUCT(cursor);
+
+done:
+
+ SAFE_FREE(oldEntries);
+
+ {
+ krb5_keytab_entry zero_kt_entry;
+ ZERO_STRUCT(zero_kt_entry);
+ if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
+ smb_krb5_kt_free_entry(context, &kt_entry);
+ }
+ }
+ {
+ krb5_kt_cursor zero_csr;
+ ZERO_STRUCT(zero_csr);
+ if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ }
+ }
+ if (keytab) {
+ krb5_kt_close(context, keytab);
+ }
+ if (context) {
+ krb5_free_context(context);
+ }
+ return ret;
+}
+
+/**********************************************************************
+ List system keytab.
+***********************************************************************/
+
+int ads_keytab_list(const char *keytab_name)
+{
+ krb5_error_code ret = 0;
+ krb5_context context = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry kt_entry;
+
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(cursor);
+
+ initialize_krb5_error_table();
+ ret = krb5_init_context(&context);
+ if (ret) {
+ DEBUG(1,("ads_keytab_list: could not krb5_init_context: %s\n",error_message(ret)));
+ return ret;
+ }
+
+ ret = smb_krb5_open_keytab(context, keytab_name, False, &keytab);
+ if (ret) {
+ DEBUG(1,("ads_keytab_list: smb_krb5_open_keytab failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret) {
+ goto out;
+ }
+
+ printf("Vno Type Principal\n");
+
+ while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0) {
+
+ char *princ_s = NULL;
+ char *etype_s = NULL;
+ krb5_enctype enctype = 0;
+
+ ret = smb_krb5_unparse_name(context, kt_entry.principal, &princ_s);
+ if (ret) {
+ goto out;
+ }
+
+ enctype = smb_get_enctype_from_kt_entry(&kt_entry);
+
+ ret = smb_krb5_enctype_to_string(context, enctype, &etype_s);
+ if (ret) {
+ SAFE_FREE(princ_s);
+ goto out;
+ }
+
+ printf("%3d %s\t\t %s\n", kt_entry.vno, etype_s, princ_s);
+
+ SAFE_FREE(princ_s);
+ SAFE_FREE(etype_s);
+
+ ret = smb_krb5_kt_free_entry(context, &kt_entry);
+ if (ret) {
+ goto out;
+ }
+ }
+
+ ret = krb5_kt_end_seq_get(context, keytab, &cursor);
+ if (ret) {
+ goto out;
+ }
+
+ /* Ensure we don't double free. */
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(cursor);
+out:
+
+ {
+ krb5_keytab_entry zero_kt_entry;
+ ZERO_STRUCT(zero_kt_entry);
+ if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
+ smb_krb5_kt_free_entry(context, &kt_entry);
+ }
+ }
+ {
+ krb5_kt_cursor zero_csr;
+ ZERO_STRUCT(zero_csr);
+ if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ }
+ }
+
+ if (keytab) {
+ krb5_kt_close(context, keytab);
+ }
+ if (context) {
+ krb5_free_context(context);
+ }
+ return ret;
+}
+
+#endif /* HAVE_KRB5 */
diff --git a/source3/libads/kerberos_verify.c b/source3/libads/kerberos_verify.c
new file mode 100644
index 0000000000..c667181642
--- /dev/null
+++ b/source3/libads/kerberos_verify.c
@@ -0,0 +1,576 @@
+/*
+ Unix SMB/CIFS implementation.
+ kerberos utility library
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Remus Koos 2001
+ Copyright (C) Luke Howard 2003
+ Copyright (C) Guenther Deschner 2003, 2005
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
+ Copyright (C) Jeremy Allison 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_KRB5
+
+#if !defined(HAVE_KRB5_PRINC_COMPONENT)
+const krb5_data *krb5_princ_component(krb5_context, krb5_principal, int );
+#endif
+
+/**********************************************************************************
+ Try to verify a ticket using the system keytab... the system keytab has kvno -1 entries, so
+ it's more like what microsoft does... see comment in utils/net_ads.c in the
+ ads_keytab_add_entry function for details.
+***********************************************************************************/
+
+static bool ads_keytab_verify_ticket(krb5_context context,
+ krb5_auth_context auth_context,
+ const DATA_BLOB *ticket,
+ krb5_ticket **pp_tkt,
+ krb5_keyblock **keyblock,
+ krb5_error_code *perr)
+{
+ krb5_error_code ret = 0;
+ bool auth_ok = False;
+ krb5_keytab keytab = NULL;
+ krb5_kt_cursor kt_cursor;
+ krb5_keytab_entry kt_entry;
+ char *valid_princ_formats[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+ char *entry_princ_s = NULL;
+ fstring my_name, my_fqdn;
+ int i;
+ int number_matched_principals = 0;
+ krb5_data packet;
+
+ *pp_tkt = NULL;
+ *keyblock = NULL;
+ *perr = 0;
+
+ /* Generate the list of principal names which we expect
+ * clients might want to use for authenticating to the file
+ * service. We allow name$,{host,cifs}/{name,fqdn,name.REALM}. */
+
+ fstrcpy(my_name, global_myname());
+
+ my_fqdn[0] = '\0';
+ name_to_fqdn(my_fqdn, global_myname());
+
+ asprintf(&valid_princ_formats[0], "%s$@%s", my_name, lp_realm());
+ asprintf(&valid_princ_formats[1], "host/%s@%s", my_name, lp_realm());
+ asprintf(&valid_princ_formats[2], "host/%s@%s", my_fqdn, lp_realm());
+ asprintf(&valid_princ_formats[3], "host/%s.%s@%s", my_name, lp_realm(), lp_realm());
+ asprintf(&valid_princ_formats[4], "cifs/%s@%s", my_name, lp_realm());
+ asprintf(&valid_princ_formats[5], "cifs/%s@%s", my_fqdn, lp_realm());
+ asprintf(&valid_princ_formats[6], "cifs/%s.%s@%s", my_name, lp_realm(), lp_realm());
+
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(kt_cursor);
+
+ ret = smb_krb5_open_keytab(context, NULL, False, &keytab);
+ if (ret) {
+ DEBUG(1, ("ads_keytab_verify_ticket: smb_krb5_open_keytab failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+ /* Iterate through the keytab. For each key, if the principal
+ * name case-insensitively matches one of the allowed formats,
+ * try verifying the ticket using that principal. */
+
+ ret = krb5_kt_start_seq_get(context, keytab, &kt_cursor);
+ if (ret) {
+ DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_start_seq_get failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+ while (!auth_ok && (krb5_kt_next_entry(context, keytab, &kt_entry, &kt_cursor) == 0)) {
+ ret = smb_krb5_unparse_name(context, kt_entry.principal, &entry_princ_s);
+ if (ret) {
+ DEBUG(1, ("ads_keytab_verify_ticket: smb_krb5_unparse_name failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) {
+
+ if (!strequal(entry_princ_s, valid_princ_formats[i])) {
+ continue;
+ }
+
+ number_matched_principals++;
+ packet.length = ticket->length;
+ packet.data = (char *)ticket->data;
+ *pp_tkt = NULL;
+
+ ret = krb5_rd_req_return_keyblock_from_keytab(context, &auth_context, &packet,
+ kt_entry.principal, keytab,
+ NULL, pp_tkt, keyblock);
+
+ if (ret) {
+ DEBUG(10,("ads_keytab_verify_ticket: "
+ "krb5_rd_req_return_keyblock_from_keytab(%s) failed: %s\n",
+ entry_princ_s, error_message(ret)));
+
+ /* workaround for MIT:
+ * as krb5_ktfile_get_entry will explicitly
+ * close the krb5_keytab as soon as krb5_rd_req
+ * has successfully decrypted the ticket but the
+ * ticket is not valid yet (due to clockskew)
+ * there is no point in querying more keytab
+ * entries - Guenther */
+
+ if (ret == KRB5KRB_AP_ERR_TKT_NYV ||
+ ret == KRB5KRB_AP_ERR_TKT_EXPIRED ||
+ ret == KRB5KRB_AP_ERR_SKEW) {
+ break;
+ }
+ } else {
+ DEBUG(3,("ads_keytab_verify_ticket: "
+ "krb5_rd_req_return_keyblock_from_keytab succeeded for principal %s\n",
+ entry_princ_s));
+ auth_ok = True;
+ break;
+ }
+ }
+
+ /* Free the name we parsed. */
+ SAFE_FREE(entry_princ_s);
+
+ /* Free the entry we just read. */
+ smb_krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
+ }
+ krb5_kt_end_seq_get(context, keytab, &kt_cursor);
+
+ ZERO_STRUCT(kt_cursor);
+
+ out:
+
+ for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) {
+ SAFE_FREE(valid_princ_formats[i]);
+ }
+
+ if (!auth_ok) {
+ if (!number_matched_principals) {
+ DEBUG(3, ("ads_keytab_verify_ticket: no keytab principals matched expected file service name.\n"));
+ } else {
+ DEBUG(3, ("ads_keytab_verify_ticket: krb5_rd_req failed for all %d matched keytab principals\n",
+ number_matched_principals));
+ }
+ }
+
+ SAFE_FREE(entry_princ_s);
+
+ {
+ krb5_keytab_entry zero_kt_entry;
+ ZERO_STRUCT(zero_kt_entry);
+ if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
+ smb_krb5_kt_free_entry(context, &kt_entry);
+ }
+ }
+
+ {
+ krb5_kt_cursor zero_csr;
+ ZERO_STRUCT(zero_csr);
+ if ((memcmp(&kt_cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
+ krb5_kt_end_seq_get(context, keytab, &kt_cursor);
+ }
+ }
+
+ if (keytab) {
+ krb5_kt_close(context, keytab);
+ }
+ *perr = ret;
+ return auth_ok;
+}
+
+/**********************************************************************************
+ Try to verify a ticket using the secrets.tdb.
+***********************************************************************************/
+
+static krb5_error_code ads_secrets_verify_ticket(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_principal host_princ,
+ const DATA_BLOB *ticket,
+ krb5_ticket **pp_tkt,
+ krb5_keyblock **keyblock,
+ krb5_error_code *perr)
+{
+ krb5_error_code ret = 0;
+ bool auth_ok = False;
+ char *password_s = NULL;
+ krb5_data password;
+ krb5_enctype enctypes[] = {
+#if defined(ENCTYPE_ARCFOUR_HMAC)
+ ENCTYPE_ARCFOUR_HMAC,
+#endif
+ ENCTYPE_DES_CBC_CRC,
+ ENCTYPE_DES_CBC_MD5,
+ ENCTYPE_NULL
+ };
+ krb5_data packet;
+ int i;
+
+ *pp_tkt = NULL;
+ *keyblock = NULL;
+ *perr = 0;
+
+
+ if (!secrets_init()) {
+ DEBUG(1,("ads_secrets_verify_ticket: secrets_init failed\n"));
+ *perr = KRB5_CONFIG_CANTOPEN;
+ return False;
+ }
+
+ password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
+ if (!password_s) {
+ DEBUG(1,("ads_secrets_verify_ticket: failed to fetch machine password\n"));
+ *perr = KRB5_LIBOS_CANTREADPWD;
+ return False;
+ }
+
+ password.data = password_s;
+ password.length = strlen(password_s);
+
+ /* CIFS doesn't use addresses in tickets. This would break NAT. JRA */
+
+ packet.length = ticket->length;
+ packet.data = (char *)ticket->data;
+
+ /* We need to setup a auth context with each possible encoding type in turn. */
+ for (i=0;enctypes[i];i++) {
+ krb5_keyblock *key = NULL;
+
+ if (!(key = SMB_MALLOC_P(krb5_keyblock))) {
+ ret = ENOMEM;
+ goto out;
+ }
+
+ if (create_kerberos_key_from_string(context, host_princ, &password, key, enctypes[i], false)) {
+ SAFE_FREE(key);
+ continue;
+ }
+
+ krb5_auth_con_setuseruserkey(context, auth_context, key);
+
+ if (!(ret = krb5_rd_req(context, &auth_context, &packet,
+ NULL,
+ NULL, NULL, pp_tkt))) {
+ DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n",
+ (unsigned int)enctypes[i] ));
+ auth_ok = True;
+ krb5_copy_keyblock(context, key, keyblock);
+ krb5_free_keyblock(context, key);
+ break;
+ }
+
+ DEBUG((ret != KRB5_BAD_ENCTYPE) ? 3 : 10,
+ ("ads_secrets_verify_ticket: enc type [%u] failed to decrypt with error %s\n",
+ (unsigned int)enctypes[i], error_message(ret)));
+
+ /* successfully decrypted but ticket is just not valid at the moment */
+ if (ret == KRB5KRB_AP_ERR_TKT_NYV ||
+ ret == KRB5KRB_AP_ERR_TKT_EXPIRED ||
+ ret == KRB5KRB_AP_ERR_SKEW) {
+ krb5_free_keyblock(context, key);
+ break;
+ }
+
+ krb5_free_keyblock(context, key);
+
+ }
+
+ out:
+ SAFE_FREE(password_s);
+ *perr = ret;
+ return auth_ok;
+}
+
+/**********************************************************************************
+ Verify an incoming ticket and parse out the principal name and
+ authorization_data if available.
+***********************************************************************************/
+
+NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
+ const char *realm,
+ time_t time_offset,
+ const DATA_BLOB *ticket,
+ char **principal,
+ struct PAC_DATA **pac_data,
+ DATA_BLOB *ap_rep,
+ DATA_BLOB *session_key,
+ bool use_replay_cache)
+{
+ NTSTATUS sret = NT_STATUS_LOGON_FAILURE;
+ NTSTATUS pac_ret;
+ DATA_BLOB auth_data;
+ krb5_context context = NULL;
+ krb5_auth_context auth_context = NULL;
+ krb5_data packet;
+ krb5_ticket *tkt = NULL;
+ krb5_rcache rcache = NULL;
+ krb5_keyblock *keyblock = NULL;
+ time_t authtime;
+ krb5_error_code ret = 0;
+ int flags = 0;
+ krb5_principal host_princ = NULL;
+ krb5_const_principal client_principal = NULL;
+ char *host_princ_s = NULL;
+ bool auth_ok = False;
+ bool got_auth_data = False;
+ struct named_mutex *mutex = NULL;
+
+ ZERO_STRUCT(packet);
+ ZERO_STRUCT(auth_data);
+
+ *principal = NULL;
+ *pac_data = NULL;
+ *ap_rep = data_blob_null;
+ *session_key = data_blob_null;
+
+ initialize_krb5_error_table();
+ ret = krb5_init_context(&context);
+ if (ret) {
+ DEBUG(1,("ads_verify_ticket: krb5_init_context failed (%s)\n", error_message(ret)));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ if (time_offset != 0) {
+ krb5_set_real_time(context, time(NULL) + time_offset, 0);
+ }
+
+ ret = krb5_set_default_realm(context, realm);
+ if (ret) {
+ DEBUG(1,("ads_verify_ticket: krb5_set_default_realm failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+ /* This whole process is far more complex than I would
+ like. We have to go through all this to allow us to store
+ the secret internally, instead of using /etc/krb5.keytab */
+
+ ret = krb5_auth_con_init(context, &auth_context);
+ if (ret) {
+ DEBUG(1,("ads_verify_ticket: krb5_auth_con_init failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+ krb5_auth_con_getflags( context, auth_context, &flags );
+ if ( !use_replay_cache ) {
+ /* Disable default use of a replay cache */
+ flags &= ~KRB5_AUTH_CONTEXT_DO_TIME;
+ krb5_auth_con_setflags( context, auth_context, flags );
+ }
+
+ asprintf(&host_princ_s, "%s$", global_myname());
+ if (!host_princ_s) {
+ goto out;
+ }
+
+ strlower_m(host_princ_s);
+ ret = smb_krb5_parse_name(context, host_princ_s, &host_princ);
+ if (ret) {
+ DEBUG(1,("ads_verify_ticket: smb_krb5_parse_name(%s) failed (%s)\n",
+ host_princ_s, error_message(ret)));
+ goto out;
+ }
+
+
+ if ( use_replay_cache ) {
+
+ /* Lock a mutex surrounding the replay as there is no
+ locking in the MIT krb5 code surrounding the replay
+ cache... */
+
+ mutex = grab_named_mutex(talloc_tos(), "replay cache mutex",
+ 10);
+ if (mutex == NULL) {
+ DEBUG(1,("ads_verify_ticket: unable to protect "
+ "replay cache with mutex.\n"));
+ ret = KRB5_CC_IO;
+ goto out;
+ }
+
+ /* JRA. We must set the rcache here. This will prevent
+ replay attacks. */
+
+ ret = krb5_get_server_rcache(context,
+ krb5_princ_component(context, host_princ, 0),
+ &rcache);
+ if (ret) {
+ DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache "
+ "failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+ ret = krb5_auth_con_setrcache(context, auth_context, rcache);
+ if (ret) {
+ DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache "
+ "failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+ }
+
+ /* Try secrets.tdb first and fallback to the krb5.keytab if
+ necessary */
+
+ auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ,
+ ticket, &tkt, &keyblock, &ret);
+
+ if (!auth_ok &&
+ (ret == KRB5KRB_AP_ERR_TKT_NYV ||
+ ret == KRB5KRB_AP_ERR_TKT_EXPIRED ||
+ ret == KRB5KRB_AP_ERR_SKEW)) {
+ goto auth_failed;
+ }
+
+ if (!auth_ok && lp_use_kerberos_keytab()) {
+ auth_ok = ads_keytab_verify_ticket(context, auth_context,
+ ticket, &tkt, &keyblock, &ret);
+ }
+
+ if ( use_replay_cache ) {
+ TALLOC_FREE(mutex);
+#if 0
+ /* Heimdal leaks here, if we fix the leak, MIT crashes */
+ if (rcache) {
+ krb5_rc_close(context, rcache);
+ }
+#endif
+ }
+
+ auth_failed:
+ if (!auth_ok) {
+ DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n",
+ error_message(ret)));
+ /* Try map the error return in case it's something like
+ * a clock skew error.
+ */
+ sret = krb5_to_nt_status(ret);
+ if (NT_STATUS_IS_OK(sret) || NT_STATUS_EQUAL(sret,NT_STATUS_UNSUCCESSFUL)) {
+ sret = NT_STATUS_LOGON_FAILURE;
+ }
+ DEBUG(10,("ads_verify_ticket: returning error %s\n",
+ nt_errstr(sret) ));
+ goto out;
+ }
+
+ authtime = get_authtime_from_tkt(tkt);
+ client_principal = get_principal_from_tkt(tkt);
+
+ ret = krb5_mk_rep(context, auth_context, &packet);
+ if (ret) {
+ DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+
+ *ap_rep = data_blob(packet.data, packet.length);
+ if (packet.data) {
+ kerberos_free_data_contents(context, &packet);
+ ZERO_STRUCT(packet);
+ }
+
+ get_krb5_smb_session_key(context, auth_context, session_key, True);
+ dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length);
+
+#if 0
+ file_save("/tmp/ticket.dat", ticket->data, ticket->length);
+#endif
+
+ /* continue when no PAC is retrieved or we couldn't decode the PAC
+ (like accounts that have the UF_NO_AUTH_DATA_REQUIRED flag set, or
+ Kerberos tickets encrypted using a DES key) - Guenther */
+
+ got_auth_data = get_auth_data_from_tkt(mem_ctx, &auth_data, tkt);
+ if (!got_auth_data) {
+ DEBUG(3,("ads_verify_ticket: did not retrieve auth data. continuing without PAC\n"));
+ }
+
+ if (got_auth_data) {
+ pac_ret = decode_pac_data(mem_ctx, &auth_data, context, keyblock, client_principal, authtime, pac_data);
+ if (!NT_STATUS_IS_OK(pac_ret)) {
+ DEBUG(3,("ads_verify_ticket: failed to decode PAC_DATA: %s\n", nt_errstr(pac_ret)));
+ *pac_data = NULL;
+ }
+ data_blob_free(&auth_data);
+ }
+
+#if 0
+#if defined(HAVE_KRB5_TKT_ENC_PART2)
+ /* MIT */
+ if (tkt->enc_part2) {
+ file_save("/tmp/authdata.dat",
+ tkt->enc_part2->authorization_data[0]->contents,
+ tkt->enc_part2->authorization_data[0]->length);
+ }
+#else
+ /* Heimdal */
+ if (tkt->ticket.authorization_data) {
+ file_save("/tmp/authdata.dat",
+ tkt->ticket.authorization_data->val->ad_data.data,
+ tkt->ticket.authorization_data->val->ad_data.length);
+ }
+#endif
+#endif
+
+ if ((ret = smb_krb5_unparse_name(context, client_principal, principal))) {
+ DEBUG(3,("ads_verify_ticket: smb_krb5_unparse_name failed (%s)\n",
+ error_message(ret)));
+ sret = NT_STATUS_LOGON_FAILURE;
+ goto out;
+ }
+
+ sret = NT_STATUS_OK;
+
+ out:
+
+ TALLOC_FREE(mutex);
+
+ if (!NT_STATUS_IS_OK(sret)) {
+ data_blob_free(&auth_data);
+ }
+
+ if (!NT_STATUS_IS_OK(sret)) {
+ data_blob_free(ap_rep);
+ }
+
+ if (host_princ) {
+ krb5_free_principal(context, host_princ);
+ }
+
+ if (keyblock) {
+ krb5_free_keyblock(context, keyblock);
+ }
+
+ if (tkt != NULL) {
+ krb5_free_ticket(context, tkt);
+ }
+
+ SAFE_FREE(host_princ_s);
+
+ if (auth_context) {
+ krb5_auth_con_free(context, auth_context);
+ }
+
+ if (context) {
+ krb5_free_context(context);
+ }
+
+ return sret;
+}
+
+#endif /* HAVE_KRB5 */
diff --git a/source3/libads/krb5_errs.c b/source3/libads/krb5_errs.c
new file mode 100644
index 0000000000..53023cc75a
--- /dev/null
+++ b/source3/libads/krb5_errs.c
@@ -0,0 +1,116 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Kerberos error mapping functions
+ * Copyright (C) Guenther Deschner 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#ifdef HAVE_KRB5
+
+static const struct {
+ krb5_error_code krb5_code;
+ NTSTATUS ntstatus;
+} krb5_to_nt_status_map[] = {
+ {KRB5_CC_IO, NT_STATUS_UNEXPECTED_IO_ERROR},
+ {KRB5KDC_ERR_BADOPTION, NT_STATUS_INVALID_PARAMETER},
+ {KRB5KDC_ERR_CLIENT_REVOKED, NT_STATUS_ACCESS_DENIED},
+ {KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN, NT_STATUS_INVALID_ACCOUNT_NAME},
+ {KRB5KDC_ERR_ETYPE_NOSUPP, NT_STATUS_LOGON_FAILURE},
+#if defined(KRB5KDC_ERR_KEY_EXPIRED) /* Heimdal */
+ {KRB5KDC_ERR_KEY_EXPIRED, NT_STATUS_PASSWORD_EXPIRED},
+#elif defined(KRB5KDC_ERR_KEY_EXP) /* MIT */
+ {KRB5KDC_ERR_KEY_EXP, NT_STATUS_PASSWORD_EXPIRED},
+#else
+#error Neither KRB5KDC_ERR_KEY_EXPIRED nor KRB5KDC_ERR_KEY_EXP available
+#endif
+ {25, NT_STATUS_PASSWORD_EXPIRED}, /* FIXME: bug in heimdal 0.7 krb5_get_init_creds_password (Inappropriate ioctl for device (25)) */
+ {KRB5KDC_ERR_NULL_KEY, NT_STATUS_LOGON_FAILURE},
+ {KRB5KDC_ERR_POLICY, NT_STATUS_INVALID_WORKSTATION},
+ {KRB5KDC_ERR_PREAUTH_FAILED, NT_STATUS_LOGON_FAILURE},
+ {KRB5KDC_ERR_SERVICE_REVOKED, NT_STATUS_ACCESS_DENIED},
+ {KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN, NT_STATUS_INVALID_ACCOUNT_NAME},
+ {KRB5KDC_ERR_SUMTYPE_NOSUPP, NT_STATUS_LOGON_FAILURE},
+ {KRB5KDC_ERR_TGT_REVOKED, NT_STATUS_ACCESS_DENIED},
+ {KRB5_KDC_UNREACH, NT_STATUS_NO_LOGON_SERVERS},
+ {KRB5KRB_AP_ERR_BAD_INTEGRITY, NT_STATUS_LOGON_FAILURE},
+ {KRB5KRB_AP_ERR_MODIFIED, NT_STATUS_LOGON_FAILURE},
+ {KRB5KRB_AP_ERR_SKEW, NT_STATUS_TIME_DIFFERENCE_AT_DC},
+ {KRB5_KDCREP_SKEW, NT_STATUS_TIME_DIFFERENCE_AT_DC},
+ {KRB5KRB_AP_ERR_TKT_EXPIRED, NT_STATUS_LOGON_FAILURE},
+ {KRB5KRB_ERR_GENERIC, NT_STATUS_UNSUCCESSFUL},
+#if defined(KRB5KRB_ERR_RESPONSE_TOO_BIG)
+ {KRB5KRB_ERR_RESPONSE_TOO_BIG, NT_STATUS_PROTOCOL_UNREACHABLE},
+#endif
+ {KRB5_CC_NOTFOUND, NT_STATUS_NO_SUCH_FILE},
+ {KRB5_FCC_NOFILE, NT_STATUS_NO_SUCH_FILE},
+ {KRB5_RC_MALLOC, NT_STATUS_NO_MEMORY},
+ {ENOMEM, NT_STATUS_NO_MEMORY},
+ {KRB5_REALM_CANT_RESOLVE, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND},
+
+ /* Must be last entry */
+ {KRB5KDC_ERR_NONE, NT_STATUS_OK}
+};
+
+static const struct {
+ NTSTATUS ntstatus;
+ krb5_error_code krb5_code;
+} nt_status_to_krb5_map[] = {
+ {NT_STATUS_LOGON_FAILURE, KRB5KDC_ERR_PREAUTH_FAILED},
+ {NT_STATUS_NO_LOGON_SERVERS, KRB5_KDC_UNREACH},
+ {NT_STATUS_OK, 0}
+};
+
+/*****************************************************************************
+convert a KRB5 error to a NT status32 code
+ *****************************************************************************/
+ NTSTATUS krb5_to_nt_status(krb5_error_code kerberos_error)
+{
+ int i;
+
+ if (kerberos_error == 0) {
+ return NT_STATUS_OK;
+ }
+
+ for (i=0; NT_STATUS_V(krb5_to_nt_status_map[i].ntstatus); i++) {
+ if (kerberos_error == krb5_to_nt_status_map[i].krb5_code)
+ return krb5_to_nt_status_map[i].ntstatus;
+ }
+
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/*****************************************************************************
+convert an NT status32 code to a KRB5 error
+ *****************************************************************************/
+ krb5_error_code nt_status_to_krb5(NTSTATUS nt_status)
+{
+ int i;
+
+ if NT_STATUS_IS_OK(nt_status) {
+ return 0;
+ }
+
+ for (i=0; NT_STATUS_V(nt_status_to_krb5_map[i].ntstatus); i++) {
+ if (NT_STATUS_EQUAL(nt_status,nt_status_to_krb5_map[i].ntstatus))
+ return nt_status_to_krb5_map[i].krb5_code;
+ }
+
+ return KRB5KRB_ERR_GENERIC;
+}
+
+#endif
+
diff --git a/source3/libads/krb5_setpw.c b/source3/libads/krb5_setpw.c
new file mode 100644
index 0000000000..719f3bd3ec
--- /dev/null
+++ b/source3/libads/krb5_setpw.c
@@ -0,0 +1,819 @@
+/*
+ Unix SMB/CIFS implementation.
+ krb5 set password implementation
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Remus Koos 2001 (remuskoos@yahoo.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_KRB5
+
+#define DEFAULT_KPASSWD_PORT 464
+
+#define KRB5_KPASSWD_VERS_CHANGEPW 1
+
+#define KRB5_KPASSWD_VERS_SETPW 0xff80
+#define KRB5_KPASSWD_VERS_SETPW_ALT 2
+
+#define KRB5_KPASSWD_SUCCESS 0
+#define KRB5_KPASSWD_MALFORMED 1
+#define KRB5_KPASSWD_HARDERROR 2
+#define KRB5_KPASSWD_AUTHERROR 3
+#define KRB5_KPASSWD_SOFTERROR 4
+#define KRB5_KPASSWD_ACCESSDENIED 5
+#define KRB5_KPASSWD_BAD_VERSION 6
+#define KRB5_KPASSWD_INITIAL_FLAG_NEEDED 7
+
+/* Those are defined by kerberos-set-passwd-02.txt and are probably
+ * not supported by M$ implementation */
+#define KRB5_KPASSWD_POLICY_REJECT 8
+#define KRB5_KPASSWD_BAD_PRINCIPAL 9
+#define KRB5_KPASSWD_ETYPE_NOSUPP 10
+
+/*
+ * we've got to be able to distinguish KRB_ERRORs from other
+ * requests - valid response for CHPW v2 replies.
+ */
+
+#define krb5_is_krb_error(packet) \
+ ( packet && packet->length && (((char *)packet->data)[0] == 0x7e || ((char *)packet->data)[0] == 0x5e))
+
+/* This implements kerberos password change protocol as specified in
+ * kerb-chg-password-02.txt and kerberos-set-passwd-02.txt
+ * as well as microsoft version of the protocol
+ * as specified in kerberos-set-passwd-00.txt
+ */
+static DATA_BLOB encode_krb5_setpw(const char *principal, const char *password)
+{
+ char* princ_part1 = NULL;
+ char* princ_part2 = NULL;
+ char* realm = NULL;
+ char* c;
+ char* princ;
+
+ ASN1_DATA req;
+ DATA_BLOB ret;
+
+
+ princ = SMB_STRDUP(principal);
+
+ if ((c = strchr_m(princ, '/')) == NULL) {
+ c = princ;
+ } else {
+ *c = '\0';
+ c++;
+ princ_part1 = princ;
+ }
+
+ princ_part2 = c;
+
+ if ((c = strchr_m(c, '@')) != NULL) {
+ *c = '\0';
+ c++;
+ realm = c;
+ } else {
+ /* We must have a realm component. */
+ return data_blob_null;
+ }
+
+ memset(&req, 0, sizeof(req));
+
+ asn1_push_tag(&req, ASN1_SEQUENCE(0));
+ asn1_push_tag(&req, ASN1_CONTEXT(0));
+ asn1_write_OctetString(&req, password, strlen(password));
+ asn1_pop_tag(&req);
+
+ asn1_push_tag(&req, ASN1_CONTEXT(1));
+ asn1_push_tag(&req, ASN1_SEQUENCE(0));
+
+ asn1_push_tag(&req, ASN1_CONTEXT(0));
+ asn1_write_Integer(&req, 1);
+ asn1_pop_tag(&req);
+
+ asn1_push_tag(&req, ASN1_CONTEXT(1));
+ asn1_push_tag(&req, ASN1_SEQUENCE(0));
+
+ if (princ_part1) {
+ asn1_write_GeneralString(&req, princ_part1);
+ }
+
+ asn1_write_GeneralString(&req, princ_part2);
+ asn1_pop_tag(&req);
+ asn1_pop_tag(&req);
+ asn1_pop_tag(&req);
+ asn1_pop_tag(&req);
+
+ asn1_push_tag(&req, ASN1_CONTEXT(2));
+ asn1_write_GeneralString(&req, realm);
+ asn1_pop_tag(&req);
+ asn1_pop_tag(&req);
+
+ ret = data_blob(req.data, req.length);
+ asn1_free(&req);
+
+ free(princ);
+
+ return ret;
+}
+
+static krb5_error_code build_kpasswd_request(uint16 pversion,
+ krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_data *ap_req,
+ const char *princ,
+ const char *passwd,
+ bool use_tcp,
+ krb5_data *packet)
+{
+ krb5_error_code ret;
+ krb5_data cipherpw;
+ krb5_data encoded_setpw;
+ krb5_replay_data replay;
+ char *p, *msg_start;
+ DATA_BLOB setpw;
+ unsigned int msg_length;
+
+ ret = krb5_auth_con_setflags(context,
+ auth_context,KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+ if (ret) {
+ DEBUG(1,("krb5_auth_con_setflags failed (%s)\n",
+ error_message(ret)));
+ return ret;
+ }
+
+ /* handle protocol differences in chpw and setpw */
+ if (pversion == KRB5_KPASSWD_VERS_CHANGEPW)
+ setpw = data_blob(passwd, strlen(passwd));
+ else if (pversion == KRB5_KPASSWD_VERS_SETPW ||
+ pversion == KRB5_KPASSWD_VERS_SETPW_ALT)
+ setpw = encode_krb5_setpw(princ, passwd);
+ else
+ return EINVAL;
+
+ if (setpw.data == NULL || setpw.length == 0) {
+ return EINVAL;
+ }
+
+ encoded_setpw.data = (char *)setpw.data;
+ encoded_setpw.length = setpw.length;
+
+ ret = krb5_mk_priv(context, auth_context,
+ &encoded_setpw, &cipherpw, &replay);
+
+ data_blob_free(&setpw); /*from 'encode_krb5_setpw(...)' */
+
+ if (ret) {
+ DEBUG(1,("krb5_mk_priv failed (%s)\n", error_message(ret)));
+ return ret;
+ }
+
+ packet->data = (char *)SMB_MALLOC(ap_req->length + cipherpw.length + (use_tcp ? 10 : 6 ));
+ if (!packet->data)
+ return -1;
+
+
+
+ /* see the RFC for details */
+
+ msg_start = p = ((char *)packet->data) + (use_tcp ? 4 : 0);
+ p += 2;
+ RSSVAL(p, 0, pversion);
+ p += 2;
+ RSSVAL(p, 0, ap_req->length);
+ p += 2;
+ memcpy(p, ap_req->data, ap_req->length);
+ p += ap_req->length;
+ memcpy(p, cipherpw.data, cipherpw.length);
+ p += cipherpw.length;
+ packet->length = PTR_DIFF(p,packet->data);
+ msg_length = PTR_DIFF(p,msg_start);
+
+ if (use_tcp) {
+ RSIVAL(packet->data, 0, msg_length);
+ }
+ RSSVAL(msg_start, 0, msg_length);
+
+ free(cipherpw.data); /* from 'krb5_mk_priv(...)' */
+
+ return 0;
+}
+
+static const struct kpasswd_errors {
+ int result_code;
+ const char *error_string;
+} kpasswd_errors[] = {
+ {KRB5_KPASSWD_MALFORMED, "Malformed request error"},
+ {KRB5_KPASSWD_HARDERROR, "Server error"},
+ {KRB5_KPASSWD_AUTHERROR, "Authentication error"},
+ {KRB5_KPASSWD_SOFTERROR, "Password change rejected"},
+ {KRB5_KPASSWD_ACCESSDENIED, "Client does not have proper authorization"},
+ {KRB5_KPASSWD_BAD_VERSION, "Protocol version not supported"},
+ {KRB5_KPASSWD_INITIAL_FLAG_NEEDED, "Authorization ticket must have initial flag set"},
+ {KRB5_KPASSWD_POLICY_REJECT, "Password rejected due to policy requirements"},
+ {KRB5_KPASSWD_BAD_PRINCIPAL, "Target principal does not exist"},
+ {KRB5_KPASSWD_ETYPE_NOSUPP, "Unsupported encryption type"},
+ {0, NULL}
+};
+
+static krb5_error_code setpw_result_code_string(krb5_context context,
+ int result_code,
+ const char **code_string)
+{
+ unsigned int idx = 0;
+
+ while (kpasswd_errors[idx].error_string != NULL) {
+ if (kpasswd_errors[idx].result_code ==
+ result_code) {
+ *code_string = kpasswd_errors[idx].error_string;
+ return 0;
+ }
+ idx++;
+ }
+ *code_string = "Password change failed";
+ return (0);
+}
+
+ krb5_error_code kpasswd_err_to_krb5_err(krb5_error_code res_code)
+{
+ switch(res_code) {
+ case KRB5_KPASSWD_ACCESSDENIED:
+ return KRB5KDC_ERR_BADOPTION;
+ case KRB5_KPASSWD_INITIAL_FLAG_NEEDED:
+ return KRB5KDC_ERR_BADOPTION;
+ /* return KV5M_ALT_METHOD; MIT-only define */
+ case KRB5_KPASSWD_ETYPE_NOSUPP:
+ return KRB5KDC_ERR_ETYPE_NOSUPP;
+ case KRB5_KPASSWD_BAD_PRINCIPAL:
+ return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+ case KRB5_KPASSWD_POLICY_REJECT:
+ case KRB5_KPASSWD_SOFTERROR:
+ return KRB5KDC_ERR_POLICY;
+ default:
+ return KRB5KRB_ERR_GENERIC;
+ }
+}
+static krb5_error_code parse_setpw_reply(krb5_context context,
+ bool use_tcp,
+ krb5_auth_context auth_context,
+ krb5_data *packet)
+{
+ krb5_data ap_rep;
+ char *p;
+ int vnum, ret, res_code;
+ krb5_data cipherresult;
+ krb5_data clearresult;
+ krb5_ap_rep_enc_part *ap_rep_enc;
+ krb5_replay_data replay;
+ unsigned int msg_length = packet->length;
+
+
+ if (packet->length < (use_tcp ? 8 : 4)) {
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ p = packet->data;
+ /*
+ ** see if it is an error
+ */
+ if (krb5_is_krb_error(packet)) {
+
+ ret = handle_krberror_packet(context, packet);
+ if (ret) {
+ return ret;
+ }
+ }
+
+
+ /* tcp... */
+ if (use_tcp) {
+ msg_length -= 4;
+ if (RIVAL(p, 0) != msg_length) {
+ DEBUG(1,("Bad TCP packet length (%d/%d) from kpasswd server\n",
+ RIVAL(p, 0), msg_length));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ p += 4;
+ }
+
+ if (RSVAL(p, 0) != msg_length) {
+ DEBUG(1,("Bad packet length (%d/%d) from kpasswd server\n",
+ RSVAL(p, 0), msg_length));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ p += 2;
+
+ vnum = RSVAL(p, 0); p += 2;
+
+ /* FIXME: According to standard there is only one type of reply */
+ if (vnum != KRB5_KPASSWD_VERS_SETPW &&
+ vnum != KRB5_KPASSWD_VERS_SETPW_ALT &&
+ vnum != KRB5_KPASSWD_VERS_CHANGEPW) {
+ DEBUG(1,("Bad vnum (%d) from kpasswd server\n", vnum));
+ return KRB5KDC_ERR_BAD_PVNO;
+ }
+
+ ap_rep.length = RSVAL(p, 0); p += 2;
+
+ if (p + ap_rep.length >= (char *)packet->data + packet->length) {
+ DEBUG(1,("ptr beyond end of packet from kpasswd server\n"));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ if (ap_rep.length == 0) {
+ DEBUG(1,("got unencrypted setpw result?!\n"));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ /* verify ap_rep */
+ ap_rep.data = p;
+ p += ap_rep.length;
+
+ ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
+ if (ret) {
+ DEBUG(1,("failed to rd setpw reply (%s)\n", error_message(ret)));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ krb5_free_ap_rep_enc_part(context, ap_rep_enc);
+
+ cipherresult.data = p;
+ cipherresult.length = ((char *)packet->data + packet->length) - p;
+
+ ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
+ &replay);
+ if (ret) {
+ DEBUG(1,("failed to decrypt setpw reply (%s)\n", error_message(ret)));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ if (clearresult.length < 2) {
+ free(clearresult.data);
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ p = clearresult.data;
+
+ res_code = RSVAL(p, 0);
+
+ free(clearresult.data);
+
+ if ((res_code < KRB5_KPASSWD_SUCCESS) ||
+ (res_code > KRB5_KPASSWD_ETYPE_NOSUPP)) {
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ if (res_code == KRB5_KPASSWD_SUCCESS) {
+ return 0;
+ } else {
+ const char *errstr;
+ setpw_result_code_string(context, res_code, &errstr);
+ DEBUG(1, ("Error changing password: %s (%d)\n", errstr, res_code));
+
+ return kpasswd_err_to_krb5_err(res_code);
+ }
+}
+
+static ADS_STATUS do_krb5_kpasswd_request(krb5_context context,
+ const char *kdc_host,
+ uint16 pversion,
+ krb5_creds *credsp,
+ const char *princ,
+ const char *newpw)
+{
+ krb5_auth_context auth_context = NULL;
+ krb5_data ap_req, chpw_req, chpw_rep;
+ int ret, sock;
+ socklen_t addr_len;
+ struct sockaddr_storage remote_addr, local_addr;
+ struct sockaddr_storage addr;
+ krb5_address local_kaddr, remote_kaddr;
+ bool use_tcp = False;
+
+
+ if (!interpret_string_addr(&addr, kdc_host, 0)) {
+ }
+
+ ret = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY,
+ NULL, credsp, &ap_req);
+ if (ret) {
+ DEBUG(1,("krb5_mk_req_extended failed (%s)\n", error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ do {
+
+ if (!use_tcp) {
+
+ sock = open_udp_socket(kdc_host, DEFAULT_KPASSWD_PORT);
+
+ } else {
+
+ sock = open_socket_out(SOCK_STREAM, &addr, DEFAULT_KPASSWD_PORT,
+ LONG_CONNECT_TIMEOUT);
+ }
+
+ if (sock == -1) {
+ int rc = errno;
+ SAFE_FREE(ap_req.data);
+ krb5_auth_con_free(context, auth_context);
+ DEBUG(1,("failed to open kpasswd socket to %s (%s)\n",
+ kdc_host, strerror(errno)));
+ return ADS_ERROR_SYSTEM(rc);
+ }
+ addr_len = sizeof(remote_addr);
+ if (getpeername(sock, (struct sockaddr *)&remote_addr, &addr_len) != 0) {
+ close(sock);
+ SAFE_FREE(ap_req.data);
+ krb5_auth_con_free(context, auth_context);
+ DEBUG(1,("getpeername() failed (%s)\n", error_message(errno)));
+ return ADS_ERROR_SYSTEM(errno);
+ }
+ addr_len = sizeof(local_addr);
+ if (getsockname(sock, (struct sockaddr *)&local_addr, &addr_len) != 0) {
+ close(sock);
+ SAFE_FREE(ap_req.data);
+ krb5_auth_con_free(context, auth_context);
+ DEBUG(1,("getsockname() failed (%s)\n", error_message(errno)));
+ return ADS_ERROR_SYSTEM(errno);
+ }
+ if (!setup_kaddr(&remote_kaddr, &remote_addr) ||
+ !setup_kaddr(&local_kaddr, &local_addr)) {
+ DEBUG(1,("do_krb5_kpasswd_request: "
+ "Failed to setup addresses.\n"));
+ close(sock);
+ SAFE_FREE(ap_req.data);
+ krb5_auth_con_free(context, auth_context);
+ errno = EINVAL;
+ return ADS_ERROR_SYSTEM(EINVAL);
+ }
+
+ ret = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, NULL);
+ if (ret) {
+ close(sock);
+ SAFE_FREE(ap_req.data);
+ krb5_auth_con_free(context, auth_context);
+ DEBUG(1,("krb5_auth_con_setaddrs failed (%s)\n", error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ ret = build_kpasswd_request(pversion, context, auth_context, &ap_req,
+ princ, newpw, use_tcp, &chpw_req);
+ if (ret) {
+ close(sock);
+ SAFE_FREE(ap_req.data);
+ krb5_auth_con_free(context, auth_context);
+ DEBUG(1,("build_setpw_request failed (%s)\n", error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ ret = write(sock, chpw_req.data, chpw_req.length);
+
+ if (ret != chpw_req.length) {
+ close(sock);
+ SAFE_FREE(chpw_req.data);
+ SAFE_FREE(ap_req.data);
+ krb5_auth_con_free(context, auth_context);
+ DEBUG(1,("send of chpw failed (%s)\n", strerror(errno)));
+ return ADS_ERROR_SYSTEM(errno);
+ }
+
+ SAFE_FREE(chpw_req.data);
+
+ chpw_rep.length = 1500;
+ chpw_rep.data = (char *) SMB_MALLOC(chpw_rep.length);
+ if (!chpw_rep.data) {
+ close(sock);
+ SAFE_FREE(ap_req.data);
+ krb5_auth_con_free(context, auth_context);
+ DEBUG(1,("send of chpw failed (%s)\n", strerror(errno)));
+ errno = ENOMEM;
+ return ADS_ERROR_SYSTEM(errno);
+ }
+
+ ret = read(sock, chpw_rep.data, chpw_rep.length);
+ if (ret < 0) {
+ close(sock);
+ SAFE_FREE(chpw_rep.data);
+ SAFE_FREE(ap_req.data);
+ krb5_auth_con_free(context, auth_context);
+ DEBUG(1,("recv of chpw reply failed (%s)\n", strerror(errno)));
+ return ADS_ERROR_SYSTEM(errno);
+ }
+
+ close(sock);
+ chpw_rep.length = ret;
+
+ ret = krb5_auth_con_setaddrs(context, auth_context, NULL,&remote_kaddr);
+ if (ret) {
+ SAFE_FREE(chpw_rep.data);
+ SAFE_FREE(ap_req.data);
+ krb5_auth_con_free(context, auth_context);
+ DEBUG(1,("krb5_auth_con_setaddrs on reply failed (%s)\n",
+ error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ ret = parse_setpw_reply(context, use_tcp, auth_context, &chpw_rep);
+ SAFE_FREE(chpw_rep.data);
+
+ if (ret) {
+
+ if (ret == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) {
+ DEBUG(5, ("Trying setpw with TCP!!!\n"));
+ use_tcp = True;
+ continue;
+ }
+
+ SAFE_FREE(ap_req.data);
+ krb5_auth_con_free(context, auth_context);
+ DEBUG(1,("parse_setpw_reply failed (%s)\n",
+ error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ SAFE_FREE(ap_req.data);
+ krb5_auth_con_free(context, auth_context);
+ } while ( ret );
+
+ return ADS_SUCCESS;
+}
+
+ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ,
+ const char *newpw, int time_offset)
+{
+
+ ADS_STATUS aret;
+ krb5_error_code ret = 0;
+ krb5_context context = NULL;
+ krb5_principal principal = NULL;
+ char *princ_name = NULL;
+ char *realm = NULL;
+ krb5_creds creds, *credsp = NULL;
+#if KRB5_PRINC_REALM_RETURNS_REALM
+ krb5_realm orig_realm;
+#else
+ krb5_data orig_realm;
+#endif
+ krb5_ccache ccache = NULL;
+
+ ZERO_STRUCT(creds);
+
+ initialize_krb5_error_table();
+ ret = krb5_init_context(&context);
+ if (ret) {
+ DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ if (time_offset != 0) {
+ krb5_set_real_time(context, time(NULL) + time_offset, 0);
+ }
+
+ ret = krb5_cc_default(context, &ccache);
+ if (ret) {
+ krb5_free_context(context);
+ DEBUG(1,("Failed to get default creds (%s)\n", error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ realm = strchr_m(princ, '@');
+ if (!realm) {
+ krb5_cc_close(context, ccache);
+ krb5_free_context(context);
+ DEBUG(1,("Failed to get realm\n"));
+ return ADS_ERROR_KRB5(-1);
+ }
+ realm++;
+
+ asprintf(&princ_name, "kadmin/changepw@%s", realm);
+ ret = smb_krb5_parse_name(context, princ_name, &creds.server);
+ if (ret) {
+ krb5_cc_close(context, ccache);
+ krb5_free_context(context);
+ DEBUG(1,("Failed to parse kadmin/changepw (%s)\n", error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ /* parse the principal we got as a function argument */
+ ret = smb_krb5_parse_name(context, princ, &principal);
+ if (ret) {
+ krb5_cc_close(context, ccache);
+ krb5_free_principal(context, creds.server);
+ krb5_free_context(context);
+ DEBUG(1,("Failed to parse %s (%s)\n", princ_name, error_message(ret)));
+ free(princ_name);
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ free(princ_name);
+
+ /* The creds.server principal takes ownership of this memory.
+ Remember to set back to original value before freeing. */
+ orig_realm = *krb5_princ_realm(context, creds.server);
+ krb5_princ_set_realm(context, creds.server, krb5_princ_realm(context, principal));
+
+ ret = krb5_cc_get_principal(context, ccache, &creds.client);
+ if (ret) {
+ krb5_cc_close(context, ccache);
+ krb5_princ_set_realm(context, creds.server, &orig_realm);
+ krb5_free_principal(context, creds.server);
+ krb5_free_principal(context, principal);
+ krb5_free_context(context);
+ DEBUG(1,("Failed to get principal from ccache (%s)\n",
+ error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
+ if (ret) {
+ krb5_cc_close(context, ccache);
+ krb5_free_principal(context, creds.client);
+ krb5_princ_set_realm(context, creds.server, &orig_realm);
+ krb5_free_principal(context, creds.server);
+ krb5_free_principal(context, principal);
+ krb5_free_context(context);
+ DEBUG(1,("krb5_get_credentials failed (%s)\n", error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ /* we might have to call krb5_free_creds(...) from now on ... */
+
+ aret = do_krb5_kpasswd_request(context, kdc_host,
+ KRB5_KPASSWD_VERS_SETPW,
+ credsp, princ, newpw);
+
+ krb5_free_creds(context, credsp);
+ krb5_free_principal(context, creds.client);
+ krb5_princ_set_realm(context, creds.server, &orig_realm);
+ krb5_free_principal(context, creds.server);
+ krb5_free_principal(context, principal);
+ krb5_cc_close(context, ccache);
+ krb5_free_context(context);
+
+ return aret;
+}
+
+/*
+ we use a prompter to avoid a crash bug in the kerberos libs when
+ dealing with empty passwords
+ this prompter is just a string copy ...
+*/
+static krb5_error_code
+kerb_prompter(krb5_context ctx, void *data,
+ const char *name,
+ const char *banner,
+ int num_prompts,
+ krb5_prompt prompts[])
+{
+ if (num_prompts == 0) return 0;
+
+ memset(prompts[0].reply->data, 0, prompts[0].reply->length);
+ if (prompts[0].reply->length > 0) {
+ if (data) {
+ strncpy(prompts[0].reply->data,
+ (const char *)data,
+ prompts[0].reply->length-1);
+ prompts[0].reply->length = strlen(prompts[0].reply->data);
+ } else {
+ prompts[0].reply->length = 0;
+ }
+ }
+ return 0;
+}
+
+static ADS_STATUS ads_krb5_chg_password(const char *kdc_host,
+ const char *principal,
+ const char *oldpw,
+ const char *newpw,
+ int time_offset)
+{
+ ADS_STATUS aret;
+ krb5_error_code ret;
+ krb5_context context = NULL;
+ krb5_principal princ;
+ krb5_get_init_creds_opt opts;
+ krb5_creds creds;
+ char *chpw_princ = NULL, *password;
+
+ initialize_krb5_error_table();
+ ret = krb5_init_context(&context);
+ if (ret) {
+ DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ if ((ret = smb_krb5_parse_name(context, principal,
+ &princ))) {
+ krb5_free_context(context);
+ DEBUG(1,("Failed to parse %s (%s)\n", principal, error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ krb5_get_init_creds_opt_init(&opts);
+ krb5_get_init_creds_opt_set_tkt_life(&opts, 5*60);
+ krb5_get_init_creds_opt_set_renew_life(&opts, 0);
+ krb5_get_init_creds_opt_set_forwardable(&opts, 0);
+ krb5_get_init_creds_opt_set_proxiable(&opts, 0);
+
+ /* We have to obtain an INITIAL changepw ticket for changing password */
+ asprintf(&chpw_princ, "kadmin/changepw@%s",
+ (char *) krb5_princ_realm(context, princ));
+ password = SMB_STRDUP(oldpw);
+ ret = krb5_get_init_creds_password(context, &creds, princ, password,
+ kerb_prompter, NULL,
+ 0, chpw_princ, &opts);
+ SAFE_FREE(chpw_princ);
+ SAFE_FREE(password);
+
+ if (ret) {
+ if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
+ DEBUG(1,("Password incorrect while getting initial ticket"));
+ else
+ DEBUG(1,("krb5_get_init_creds_password failed (%s)\n", error_message(ret)));
+
+ krb5_free_principal(context, princ);
+ krb5_free_context(context);
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ aret = do_krb5_kpasswd_request(context, kdc_host,
+ KRB5_KPASSWD_VERS_CHANGEPW,
+ &creds, principal, newpw);
+
+ krb5_free_principal(context, princ);
+ krb5_free_context(context);
+
+ return aret;
+}
+
+
+ADS_STATUS kerberos_set_password(const char *kpasswd_server,
+ const char *auth_principal, const char *auth_password,
+ const char *target_principal, const char *new_password,
+ int time_offset)
+{
+ int ret;
+
+ if ((ret = kerberos_kinit_password(auth_principal, auth_password, time_offset, NULL))) {
+ DEBUG(1,("Failed kinit for principal %s (%s)\n", auth_principal, error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ if (!strcmp(auth_principal, target_principal))
+ return ads_krb5_chg_password(kpasswd_server, target_principal,
+ auth_password, new_password, time_offset);
+ else
+ return ads_krb5_set_password(kpasswd_server, target_principal,
+ new_password, time_offset);
+}
+
+
+/**
+ * Set the machine account password
+ * @param ads connection to ads server
+ * @param hostname machine whose password is being set
+ * @param password new password
+ * @return status of password change
+ **/
+ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
+ const char *machine_account,
+ const char *password)
+{
+ ADS_STATUS status;
+ char *principal = NULL;
+
+ /*
+ we need to use the '$' form of the name here (the machine account name),
+ as otherwise the server might end up setting the password for a user
+ instead
+ */
+ asprintf(&principal, "%s@%s", machine_account, ads->config.realm);
+
+ status = ads_krb5_set_password(ads->auth.kdc_server, principal,
+ password, ads->auth.time_offset);
+
+ free(principal);
+
+ return status;
+}
+
+
+
+#endif
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
new file mode 100644
index 0000000000..eb45e3a0dd
--- /dev/null
+++ b/source3/libads/ldap.c
@@ -0,0 +1,3824 @@
+/*
+ Unix SMB/CIFS implementation.
+ ads (active directory) utility library
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Remus Koos 2001
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
+ Copyright (C) Guenther Deschner 2005
+ Copyright (C) Gerald Carter 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/ldb/include/includes.h"
+
+#ifdef HAVE_LDAP
+
+/**
+ * @file ldap.c
+ * @brief basic ldap client-side routines for ads server communications
+ *
+ * The routines contained here should do the necessary ldap calls for
+ * ads setups.
+ *
+ * Important note: attribute names passed into ads_ routines must
+ * already be in UTF-8 format. We do not convert them because in almost
+ * all cases, they are just ascii (which is represented with the same
+ * codepoints in UTF-8). This may have to change at some point
+ **/
+
+
+#define LDAP_SERVER_TREE_DELETE_OID "1.2.840.113556.1.4.805"
+
+static SIG_ATOMIC_T gotalarm;
+
+/***************************************************************
+ Signal function to tell us we timed out.
+****************************************************************/
+
+static void gotalarm_sig(void)
+{
+ gotalarm = 1;
+}
+
+ LDAP *ldap_open_with_timeout(const char *server, int port, unsigned int to)
+{
+ LDAP *ldp = NULL;
+
+
+ DEBUG(10, ("Opening connection to LDAP server '%s:%d', timeout "
+ "%u seconds\n", server, port, to));
+
+ /* Setup timeout */
+ gotalarm = 0;
+ CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+ alarm(to);
+ /* End setup timeout. */
+
+ ldp = ldap_open(server, port);
+
+ if (ldp == NULL) {
+ DEBUG(2,("Could not open connection to LDAP server %s:%d: %s\n",
+ server, port, strerror(errno)));
+ } else {
+ DEBUG(10, ("Connected to LDAP server '%s:%d'\n", server, port));
+ }
+
+ /* Teardown timeout. */
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
+ alarm(0);
+
+ return ldp;
+}
+
+static int ldap_search_with_timeout(LDAP *ld,
+ LDAP_CONST char *base,
+ int scope,
+ LDAP_CONST char *filter,
+ char **attrs,
+ int attrsonly,
+ LDAPControl **sctrls,
+ LDAPControl **cctrls,
+ int sizelimit,
+ LDAPMessage **res )
+{
+ struct timeval timeout;
+ int result;
+
+ /* Setup timeout for the ldap_search_ext_s call - local and remote. */
+ timeout.tv_sec = lp_ldap_timeout();
+ timeout.tv_usec = 0;
+
+ /* Setup alarm timeout.... Do we need both of these ? JRA. */
+ gotalarm = 0;
+ CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+ alarm(lp_ldap_timeout());
+ /* End setup timeout. */
+
+ result = ldap_search_ext_s(ld, base, scope, filter, attrs,
+ attrsonly, sctrls, cctrls, &timeout,
+ sizelimit, res);
+
+ /* Teardown timeout. */
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
+ alarm(0);
+
+ if (gotalarm != 0)
+ return LDAP_TIMELIMIT_EXCEEDED;
+
+ return result;
+}
+
+/**********************************************
+ Do client and server sitename match ?
+**********************************************/
+
+bool ads_sitename_match(ADS_STRUCT *ads)
+{
+ if (ads->config.server_site_name == NULL &&
+ ads->config.client_site_name == NULL ) {
+ DEBUG(10,("ads_sitename_match: both null\n"));
+ return True;
+ }
+ if (ads->config.server_site_name &&
+ ads->config.client_site_name &&
+ strequal(ads->config.server_site_name,
+ ads->config.client_site_name)) {
+ DEBUG(10,("ads_sitename_match: name %s match\n", ads->config.server_site_name));
+ return True;
+ }
+ DEBUG(10,("ads_sitename_match: no match between server: %s and client: %s\n",
+ ads->config.server_site_name ? ads->config.server_site_name : "NULL",
+ ads->config.client_site_name ? ads->config.client_site_name : "NULL"));
+ return False;
+}
+
+/**********************************************
+ Is this the closest DC ?
+**********************************************/
+
+bool ads_closest_dc(ADS_STRUCT *ads)
+{
+ if (ads->config.flags & NBT_SERVER_CLOSEST) {
+ DEBUG(10,("ads_closest_dc: NBT_SERVER_CLOSEST flag set\n"));
+ return True;
+ }
+
+ /* not sure if this can ever happen */
+ if (ads_sitename_match(ads)) {
+ DEBUG(10,("ads_closest_dc: NBT_SERVER_CLOSEST flag not set but sites match\n"));
+ return True;
+ }
+
+ DEBUG(10,("ads_closest_dc: %s is not the closest DC\n",
+ ads->config.ldap_server_name));
+
+ return False;
+}
+
+
+/*
+ try a connection to a given ldap server, returning True and setting the servers IP
+ in the ads struct if successful
+ */
+static bool ads_try_connect(ADS_STRUCT *ads, const char *server, bool gc)
+{
+ char *srv;
+ struct nbt_cldap_netlogon_5 cldap_reply;
+ TALLOC_CTX *mem_ctx = NULL;
+ bool ret = false;
+
+ if (!server || !*server) {
+ return False;
+ }
+
+ DEBUG(5,("ads_try_connect: sending CLDAP request to %s (realm: %s)\n",
+ server, ads->server.realm));
+
+ mem_ctx = talloc_init("ads_try_connect");
+ if (!mem_ctx) {
+ DEBUG(0,("out of memory\n"));
+ return false;
+ }
+
+ /* this copes with inet_ntoa brokenness */
+
+ srv = SMB_STRDUP(server);
+
+ ZERO_STRUCT( cldap_reply );
+
+ if ( !ads_cldap_netlogon_5(mem_ctx, srv, ads->server.realm, &cldap_reply ) ) {
+ DEBUG(3,("ads_try_connect: CLDAP request %s failed.\n", srv));
+ ret = false;
+ goto out;
+ }
+
+ /* Check the CLDAP reply flags */
+
+ if ( !(cldap_reply.server_type & NBT_SERVER_LDAP) ) {
+ DEBUG(1,("ads_try_connect: %s's CLDAP reply says it is not an LDAP server!\n",
+ srv));
+ ret = false;
+ goto out;
+ }
+
+ /* Fill in the ads->config values */
+
+ SAFE_FREE(ads->config.realm);
+ SAFE_FREE(ads->config.bind_path);
+ SAFE_FREE(ads->config.ldap_server_name);
+ SAFE_FREE(ads->config.server_site_name);
+ SAFE_FREE(ads->config.client_site_name);
+ SAFE_FREE(ads->server.workgroup);
+
+ ads->config.flags = cldap_reply.server_type;
+ ads->config.ldap_server_name = SMB_STRDUP(cldap_reply.pdc_dns_name);
+ ads->config.realm = SMB_STRDUP(cldap_reply.dns_domain);
+ strupper_m(ads->config.realm);
+ ads->config.bind_path = ads_build_dn(ads->config.realm);
+ if (*cldap_reply.server_site) {
+ ads->config.server_site_name =
+ SMB_STRDUP(cldap_reply.server_site);
+ }
+ if (*cldap_reply.client_site) {
+ ads->config.client_site_name =
+ SMB_STRDUP(cldap_reply.client_site);
+ }
+ ads->server.workgroup = SMB_STRDUP(cldap_reply.domain);
+
+ ads->ldap.port = gc ? LDAP_GC_PORT : LDAP_PORT;
+ if (!interpret_string_addr(&ads->ldap.ss, srv, 0)) {
+ DEBUG(1,("ads_try_connect: unable to convert %s "
+ "to an address\n",
+ srv));
+ ret = false;
+ goto out;
+ }
+
+ /* Store our site name. */
+ sitename_store( cldap_reply.domain, cldap_reply.client_site);
+ sitename_store( cldap_reply.dns_domain, cldap_reply.client_site);
+
+ ret = true;
+ out:
+ SAFE_FREE(srv);
+ TALLOC_FREE(mem_ctx);
+
+ return ret;
+}
+
+/**********************************************************************
+ Try to find an AD dc using our internal name resolution routines
+ Try the realm first and then then workgroup name if netbios is not
+ disabled
+**********************************************************************/
+
+static NTSTATUS ads_find_dc(ADS_STRUCT *ads)
+{
+ const char *c_realm;
+ int count, i=0;
+ struct ip_service *ip_list;
+ const char *realm;
+ bool got_realm = False;
+ bool use_own_domain = False;
+ char *sitename;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+ /* if the realm and workgroup are both empty, assume they are ours */
+
+ /* realm */
+ c_realm = ads->server.realm;
+
+ if ( !c_realm || !*c_realm ) {
+ /* special case where no realm and no workgroup means our own */
+ if ( !ads->server.workgroup || !*ads->server.workgroup ) {
+ use_own_domain = True;
+ c_realm = lp_realm();
+ }
+ }
+
+ if (c_realm && *c_realm)
+ got_realm = True;
+
+ /* we need to try once with the realm name and fallback to the
+ netbios domain name if we fail (if netbios has not been disabled */
+
+ if ( !got_realm && !lp_disable_netbios() ) {
+ c_realm = ads->server.workgroup;
+ if (!c_realm || !*c_realm) {
+ if ( use_own_domain )
+ c_realm = lp_workgroup();
+ }
+
+ if ( !c_realm || !*c_realm ) {
+ DEBUG(0,("ads_find_dc: no realm or workgroup! Don't know what to do\n"));
+ return NT_STATUS_INVALID_PARAMETER; /* rather need MISSING_PARAMETER ... */
+ }
+ }
+
+ realm = c_realm;
+
+ sitename = sitename_fetch(realm);
+
+ again:
+
+ DEBUG(6,("ads_find_dc: looking for %s '%s'\n",
+ (got_realm ? "realm" : "domain"), realm));
+
+ status = get_sorted_dc_list(realm, sitename, &ip_list, &count, got_realm);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* fall back to netbios if we can */
+ if ( got_realm && !lp_disable_netbios() ) {
+ got_realm = False;
+ goto again;
+ }
+
+ SAFE_FREE(sitename);
+ return status;
+ }
+
+ /* if we fail this loop, then giveup since all the IP addresses returned were dead */
+ for ( i=0; i<count; i++ ) {
+ char server[INET6_ADDRSTRLEN];
+
+ print_sockaddr(server, sizeof(server), &ip_list[i].ss);
+
+ if ( !NT_STATUS_IS_OK(check_negative_conn_cache(realm, server)) )
+ continue;
+
+ if (!got_realm) {
+ /* realm in this case is a workgroup name. We need
+ to ignore any IP addresses in the negative connection
+ cache that match ip addresses returned in the ad realm
+ case. It sucks that I have to reproduce the logic above... */
+ c_realm = ads->server.realm;
+ if ( !c_realm || !*c_realm ) {
+ if ( !ads->server.workgroup || !*ads->server.workgroup ) {
+ c_realm = lp_realm();
+ }
+ }
+ if (c_realm && *c_realm &&
+ !NT_STATUS_IS_OK(check_negative_conn_cache(c_realm, server))) {
+ /* Ensure we add the workgroup name for this
+ IP address as negative too. */
+ add_failed_connection_entry( realm, server, NT_STATUS_UNSUCCESSFUL );
+ continue;
+ }
+ }
+
+ if ( ads_try_connect(ads, server, false) ) {
+ SAFE_FREE(ip_list);
+ SAFE_FREE(sitename);
+ return NT_STATUS_OK;
+ }
+
+ /* keep track of failures */
+ add_failed_connection_entry( realm, server, NT_STATUS_UNSUCCESSFUL );
+ }
+
+ SAFE_FREE(ip_list);
+
+ /* In case we failed to contact one of our closest DC on our site we
+ * need to try to find another DC, retry with a site-less SRV DNS query
+ * - Guenther */
+
+ if (sitename) {
+ DEBUG(1,("ads_find_dc: failed to find a valid DC on our site (%s), "
+ "trying to find another DC\n", sitename));
+ SAFE_FREE(sitename);
+ namecache_delete(realm, 0x1C);
+ goto again;
+ }
+
+ return NT_STATUS_NO_LOGON_SERVERS;
+}
+
+/*********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ads_lookup_site(void)
+{
+ ADS_STRUCT *ads = NULL;
+ ADS_STATUS ads_status;
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+
+ ads = ads_init(lp_realm(), NULL, NULL);
+ if (!ads) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* The NO_BIND here will find a DC and set the client site
+ but not establish the TCP connection */
+
+ ads->auth.flags = ADS_AUTH_NO_BIND;
+ ads_status = ads_connect(ads);
+ if (!ADS_ERR_OK(ads_status)) {
+ DEBUG(4, ("ads_lookup_site: ads_connect to our realm failed! (%s)\n",
+ ads_errstr(ads_status)));
+ }
+ nt_status = ads_ntstatus(ads_status);
+
+ if (ads) {
+ ads_destroy(&ads);
+ }
+
+ return nt_status;
+}
+
+/*********************************************************************
+ *********************************************************************/
+
+static const char* host_dns_domain(const char *fqdn)
+{
+ const char *p = fqdn;
+
+ /* go to next char following '.' */
+
+ if ((p = strchr_m(fqdn, '.')) != NULL) {
+ p++;
+ }
+
+ return p;
+}
+
+
+/**
+ * Connect to the Global Catalog server
+ * @param ads Pointer to an existing ADS_STRUCT
+ * @return status of connection
+ *
+ * Simple wrapper around ads_connect() that fills in the
+ * GC ldap server information
+ **/
+
+ADS_STATUS ads_connect_gc(ADS_STRUCT *ads)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct dns_rr_srv *gcs_list;
+ int num_gcs;
+ char *realm = ads->server.realm;
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+ int i;
+ bool done = false;
+ char *sitename = NULL;
+
+ if (!realm)
+ realm = lp_realm();
+
+ if ((sitename = sitename_fetch(realm)) == NULL) {
+ ads_lookup_site();
+ sitename = sitename_fetch(realm);
+ }
+
+ do {
+ /* We try once with a sitename and once without
+ (unless we don't have a sitename and then we're
+ done */
+
+ if (sitename == NULL)
+ done = true;
+
+ nt_status = ads_dns_query_gcs(frame, realm, sitename,
+ &gcs_list, &num_gcs);
+
+ SAFE_FREE(sitename);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ ads_status = ADS_ERROR_NT(nt_status);
+ goto done;
+ }
+
+ /* Loop until we get a successful connection or have gone
+ through them all. When connecting a GC server, make sure that
+ the realm is the server's DNS name and not the forest root */
+
+ for (i=0; i<num_gcs; i++) {
+ ads->server.gc = true;
+ ads->server.ldap_server = SMB_STRDUP(gcs_list[i].hostname);
+ ads->server.realm = SMB_STRDUP(host_dns_domain(ads->server.ldap_server));
+ ads_status = ads_connect(ads);
+ if (ADS_ERR_OK(ads_status)) {
+ /* Reset the bind_dn to "". A Global Catalog server
+ may host multiple domain trees in a forest.
+ Windows 2003 GC server will accept "" as the search
+ path to imply search all domain trees in the forest */
+
+ SAFE_FREE(ads->config.bind_path);
+ ads->config.bind_path = SMB_STRDUP("");
+
+
+ goto done;
+ }
+ SAFE_FREE(ads->server.ldap_server);
+ SAFE_FREE(ads->server.realm);
+ }
+
+ TALLOC_FREE(gcs_list);
+ num_gcs = 0;
+ } while (!done);
+
+done:
+ SAFE_FREE(sitename);
+ talloc_destroy(frame);
+
+ return ads_status;
+}
+
+
+/**
+ * Connect to the LDAP server
+ * @param ads Pointer to an existing ADS_STRUCT
+ * @return status of connection
+ **/
+ADS_STATUS ads_connect(ADS_STRUCT *ads)
+{
+ int version = LDAP_VERSION3;
+ ADS_STATUS status;
+ NTSTATUS ntstatus;
+ char addr[INET6_ADDRSTRLEN];
+
+ ZERO_STRUCT(ads->ldap);
+ ads->ldap.last_attempt = time(NULL);
+ ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
+
+ /* try with a user specified server */
+
+ if (DEBUGLEVEL >= 11) {
+ char *s = NDR_PRINT_STRUCT_STRING(talloc_tos(), ads_struct, ads);
+ DEBUG(11,("ads_connect: entering\n"));
+ DEBUGADD(11,("%s\n", s));
+ TALLOC_FREE(s);
+ }
+
+ if (ads->server.ldap_server &&
+ ads_try_connect(ads, ads->server.ldap_server, ads->server.gc)) {
+ goto got_connection;
+ }
+
+ ntstatus = ads_find_dc(ads);
+ if (NT_STATUS_IS_OK(ntstatus)) {
+ goto got_connection;
+ }
+
+ status = ADS_ERROR_NT(ntstatus);
+ goto out;
+
+got_connection:
+
+ print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
+ DEBUG(3,("Successfully contacted LDAP server %s\n", addr));
+
+ if (!ads->auth.user_name) {
+ /* Must use the userPrincipalName value here or sAMAccountName
+ and not servicePrincipalName; found by Guenther Deschner */
+
+ asprintf(&ads->auth.user_name, "%s$", global_myname() );
+ }
+
+ if (!ads->auth.realm) {
+ ads->auth.realm = SMB_STRDUP(ads->config.realm);
+ }
+
+ if (!ads->auth.kdc_server) {
+ print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
+ ads->auth.kdc_server = SMB_STRDUP(addr);
+ }
+
+#if KRB5_DNS_HACK
+ /* this is a really nasty hack to avoid ADS DNS problems. It needs a patch
+ to MIT kerberos to work (tridge) */
+ {
+ char *env;
+ asprintf(&env, "KRB5_KDC_ADDRESS_%s", ads->config.realm);
+ setenv(env, ads->auth.kdc_server, 1);
+ free(env);
+ }
+#endif
+
+ /* If the caller() requested no LDAP bind, then we are done */
+
+ if (ads->auth.flags & ADS_AUTH_NO_BIND) {
+ status = ADS_SUCCESS;
+ goto out;
+ }
+
+ ads->ldap.mem_ctx = talloc_init("ads LDAP connection memory");
+ if (!ads->ldap.mem_ctx) {
+ status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ goto out;
+ }
+
+ /* Otherwise setup the TCP LDAP session */
+
+ ads->ldap.ld = ldap_open_with_timeout(ads->config.ldap_server_name,
+ ads->ldap.port, lp_ldap_timeout());
+ if (ads->ldap.ld == NULL) {
+ status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
+ goto out;
+ }
+ DEBUG(3,("Connected to LDAP server %s\n", ads->config.ldap_server_name));
+
+ /* cache the successful connection for workgroup and realm */
+ if (ads_closest_dc(ads)) {
+ print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
+ saf_store( ads->server.workgroup, addr);
+ saf_store( ads->server.realm, addr);
+ }
+
+ ldap_set_option(ads->ldap.ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+
+ status = ADS_ERROR(smb_ldap_start_tls(ads->ldap.ld, version));
+ if (!ADS_ERR_OK(status)) {
+ goto out;
+ }
+
+ /* fill in the current time and offsets */
+
+ status = ads_current_time( ads );
+ if ( !ADS_ERR_OK(status) ) {
+ goto out;
+ }
+
+ /* Now do the bind */
+
+ if (ads->auth.flags & ADS_AUTH_ANON_BIND) {
+ status = ADS_ERROR(ldap_simple_bind_s(ads->ldap.ld, NULL, NULL));
+ goto out;
+ }
+
+ if (ads->auth.flags & ADS_AUTH_SIMPLE_BIND) {
+ status = ADS_ERROR(ldap_simple_bind_s(ads->ldap.ld, ads->auth.user_name, ads->auth.password));
+ goto out;
+ }
+
+ status = ads_sasl_bind(ads);
+
+ out:
+ if (DEBUGLEVEL >= 11) {
+ char *s = NDR_PRINT_STRUCT_STRING(talloc_tos(), ads_struct, ads);
+ DEBUG(11,("ads_connect: leaving with: %s\n",
+ ads_errstr(status)));
+ DEBUGADD(11,("%s\n", s));
+ TALLOC_FREE(s);
+ }
+
+ return status;
+}
+
+/**
+ * Connect to the LDAP server using given credentials
+ * @param ads Pointer to an existing ADS_STRUCT
+ * @return status of connection
+ **/
+ADS_STATUS ads_connect_user_creds(ADS_STRUCT *ads)
+{
+ ads->auth.flags |= ADS_AUTH_USER_CREDS;
+
+ return ads_connect(ads);
+}
+
+/**
+ * Disconnect the LDAP server
+ * @param ads Pointer to an existing ADS_STRUCT
+ **/
+void ads_disconnect(ADS_STRUCT *ads)
+{
+ if (ads->ldap.ld) {
+ ldap_unbind(ads->ldap.ld);
+ ads->ldap.ld = NULL;
+ }
+ if (ads->ldap.wrap_ops && ads->ldap.wrap_ops->disconnect) {
+ ads->ldap.wrap_ops->disconnect(ads);
+ }
+ if (ads->ldap.mem_ctx) {
+ talloc_free(ads->ldap.mem_ctx);
+ }
+ ZERO_STRUCT(ads->ldap);
+}
+
+/*
+ Duplicate a struct berval into talloc'ed memory
+ */
+static struct berval *dup_berval(TALLOC_CTX *ctx, const struct berval *in_val)
+{
+ struct berval *value;
+
+ if (!in_val) return NULL;
+
+ value = TALLOC_ZERO_P(ctx, struct berval);
+ if (value == NULL)
+ return NULL;
+ if (in_val->bv_len == 0) return value;
+
+ value->bv_len = in_val->bv_len;
+ value->bv_val = (char *)TALLOC_MEMDUP(ctx, in_val->bv_val,
+ in_val->bv_len);
+ return value;
+}
+
+/*
+ Make a values list out of an array of (struct berval *)
+ */
+static struct berval **ads_dup_values(TALLOC_CTX *ctx,
+ const struct berval **in_vals)
+{
+ struct berval **values;
+ int i;
+
+ if (!in_vals) return NULL;
+ for (i=0; in_vals[i]; i++)
+ ; /* count values */
+ values = TALLOC_ZERO_ARRAY(ctx, struct berval *, i+1);
+ if (!values) return NULL;
+
+ for (i=0; in_vals[i]; i++) {
+ values[i] = dup_berval(ctx, in_vals[i]);
+ }
+ return values;
+}
+
+/*
+ UTF8-encode a values list out of an array of (char *)
+ */
+static char **ads_push_strvals(TALLOC_CTX *ctx, const char **in_vals)
+{
+ char **values;
+ int i;
+ size_t size;
+
+ if (!in_vals) return NULL;
+ for (i=0; in_vals[i]; i++)
+ ; /* count values */
+ values = TALLOC_ZERO_ARRAY(ctx, char *, i+1);
+ if (!values) return NULL;
+
+ for (i=0; in_vals[i]; i++) {
+ if (!push_utf8_talloc(ctx, &values[i], in_vals[i], &size)) {
+ TALLOC_FREE(values);
+ return NULL;
+ }
+ }
+ return values;
+}
+
+/*
+ Pull a (char *) array out of a UTF8-encoded values list
+ */
+static char **ads_pull_strvals(TALLOC_CTX *ctx, const char **in_vals)
+{
+ char **values;
+ int i;
+ size_t converted_size;
+
+ if (!in_vals) return NULL;
+ for (i=0; in_vals[i]; i++)
+ ; /* count values */
+ values = TALLOC_ZERO_ARRAY(ctx, char *, i+1);
+ if (!values) return NULL;
+
+ for (i=0; in_vals[i]; i++) {
+ if (!pull_utf8_talloc(ctx, &values[i], in_vals[i],
+ &converted_size)) {
+ DEBUG(0,("ads_pull_strvals: pull_utf8_talloc failed: "
+ "%s", strerror(errno)));
+ }
+ }
+ return values;
+}
+
+/**
+ * Do a search with paged results. cookie must be null on the first
+ * call, and then returned on each subsequent call. It will be null
+ * again when the entire search is complete
+ * @param ads connection to ads server
+ * @param bind_path Base dn for the search
+ * @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
+ * @param expr Search expression - specified in local charset
+ * @param attrs Attributes to retrieve - specified in utf8 or ascii
+ * @param res ** which will contain results - free res* with ads_msgfree()
+ * @param count Number of entries retrieved on this page
+ * @param cookie The paged results cookie to be returned on subsequent calls
+ * @return status of search
+ **/
+static ADS_STATUS ads_do_paged_search_args(ADS_STRUCT *ads,
+ const char *bind_path,
+ int scope, const char *expr,
+ const char **attrs, void *args,
+ LDAPMessage **res,
+ int *count, struct berval **cookie)
+{
+ int rc, i, version;
+ char *utf8_expr, *utf8_path, **search_attrs;
+ size_t converted_size;
+ LDAPControl PagedResults, NoReferrals, ExternalCtrl, *controls[4], **rcontrols;
+ BerElement *cookie_be = NULL;
+ struct berval *cookie_bv= NULL;
+ BerElement *ext_be = NULL;
+ struct berval *ext_bv= NULL;
+
+ TALLOC_CTX *ctx;
+ ads_control *external_control = (ads_control *) args;
+
+ *res = NULL;
+
+ if (!(ctx = talloc_init("ads_do_paged_search_args")))
+ return ADS_ERROR(LDAP_NO_MEMORY);
+
+ /* 0 means the conversion worked but the result was empty
+ so we only fail if it's -1. In any case, it always
+ at least nulls out the dest */
+ if (!push_utf8_talloc(ctx, &utf8_expr, expr, &converted_size) ||
+ !push_utf8_talloc(ctx, &utf8_path, bind_path, &converted_size))
+ {
+ rc = LDAP_NO_MEMORY;
+ goto done;
+ }
+
+ if (!attrs || !(*attrs))
+ search_attrs = NULL;
+ else {
+ /* This would be the utf8-encoded version...*/
+ /* if (!(search_attrs = ads_push_strvals(ctx, attrs))) */
+ if (!(str_list_copy(talloc_tos(), &search_attrs, attrs))) {
+ rc = LDAP_NO_MEMORY;
+ goto done;
+ }
+ }
+
+ /* Paged results only available on ldap v3 or later */
+ ldap_get_option(ads->ldap.ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+ if (version < LDAP_VERSION3) {
+ rc = LDAP_NOT_SUPPORTED;
+ goto done;
+ }
+
+ cookie_be = ber_alloc_t(LBER_USE_DER);
+ if (*cookie) {
+ ber_printf(cookie_be, "{iO}", (ber_int_t) 1000, *cookie);
+ ber_bvfree(*cookie); /* don't need it from last time */
+ *cookie = NULL;
+ } else {
+ ber_printf(cookie_be, "{io}", (ber_int_t) 1000, "", 0);
+ }
+ ber_flatten(cookie_be, &cookie_bv);
+ PagedResults.ldctl_oid = CONST_DISCARD(char *, ADS_PAGE_CTL_OID);
+ PagedResults.ldctl_iscritical = (char) 1;
+ PagedResults.ldctl_value.bv_len = cookie_bv->bv_len;
+ PagedResults.ldctl_value.bv_val = cookie_bv->bv_val;
+
+ NoReferrals.ldctl_oid = CONST_DISCARD(char *, ADS_NO_REFERRALS_OID);
+ NoReferrals.ldctl_iscritical = (char) 0;
+ NoReferrals.ldctl_value.bv_len = 0;
+ NoReferrals.ldctl_value.bv_val = CONST_DISCARD(char *, "");
+
+ if (external_control &&
+ (strequal(external_control->control, ADS_EXTENDED_DN_OID) ||
+ strequal(external_control->control, ADS_SD_FLAGS_OID))) {
+
+ ExternalCtrl.ldctl_oid = CONST_DISCARD(char *, external_control->control);
+ ExternalCtrl.ldctl_iscritical = (char) external_control->critical;
+
+ /* win2k does not accept a ldctl_value beeing passed in */
+
+ if (external_control->val != 0) {
+
+ if ((ext_be = ber_alloc_t(LBER_USE_DER)) == NULL ) {
+ rc = LDAP_NO_MEMORY;
+ goto done;
+ }
+
+ if ((ber_printf(ext_be, "{i}", (ber_int_t) external_control->val)) == -1) {
+ rc = LDAP_NO_MEMORY;
+ goto done;
+ }
+ if ((ber_flatten(ext_be, &ext_bv)) == -1) {
+ rc = LDAP_NO_MEMORY;
+ goto done;
+ }
+
+ ExternalCtrl.ldctl_value.bv_len = ext_bv->bv_len;
+ ExternalCtrl.ldctl_value.bv_val = ext_bv->bv_val;
+
+ } else {
+ ExternalCtrl.ldctl_value.bv_len = 0;
+ ExternalCtrl.ldctl_value.bv_val = NULL;
+ }
+
+ controls[0] = &NoReferrals;
+ controls[1] = &PagedResults;
+ controls[2] = &ExternalCtrl;
+ controls[3] = NULL;
+
+ } else {
+ controls[0] = &NoReferrals;
+ controls[1] = &PagedResults;
+ controls[2] = NULL;
+ }
+
+ /* we need to disable referrals as the openldap libs don't
+ handle them and paged results at the same time. Using them
+ together results in the result record containing the server
+ page control being removed from the result list (tridge/jmcd)
+
+ leaving this in despite the control that says don't generate
+ referrals, in case the server doesn't support it (jmcd)
+ */
+ ldap_set_option(ads->ldap.ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
+
+ rc = ldap_search_with_timeout(ads->ldap.ld, utf8_path, scope, utf8_expr,
+ search_attrs, 0, controls,
+ NULL, LDAP_NO_LIMIT,
+ (LDAPMessage **)res);
+
+ ber_free(cookie_be, 1);
+ ber_bvfree(cookie_bv);
+
+ if (rc) {
+ DEBUG(3,("ads_do_paged_search_args: ldap_search_with_timeout(%s) -> %s\n", expr,
+ ldap_err2string(rc)));
+ goto done;
+ }
+
+ rc = ldap_parse_result(ads->ldap.ld, *res, NULL, NULL, NULL,
+ NULL, &rcontrols, 0);
+
+ if (!rcontrols) {
+ goto done;
+ }
+
+ for (i=0; rcontrols[i]; i++) {
+ if (strcmp(ADS_PAGE_CTL_OID, rcontrols[i]->ldctl_oid) == 0) {
+ cookie_be = ber_init(&rcontrols[i]->ldctl_value);
+ ber_scanf(cookie_be,"{iO}", (ber_int_t *) count,
+ &cookie_bv);
+ /* the berval is the cookie, but must be freed when
+ it is all done */
+ if (cookie_bv->bv_len) /* still more to do */
+ *cookie=ber_bvdup(cookie_bv);
+ else
+ *cookie=NULL;
+ ber_bvfree(cookie_bv);
+ ber_free(cookie_be, 1);
+ break;
+ }
+ }
+ ldap_controls_free(rcontrols);
+
+done:
+ talloc_destroy(ctx);
+
+ if (ext_be) {
+ ber_free(ext_be, 1);
+ }
+
+ if (ext_bv) {
+ ber_bvfree(ext_bv);
+ }
+
+ /* if/when we decide to utf8-encode attrs, take out this next line */
+ TALLOC_FREE(search_attrs);
+
+ return ADS_ERROR(rc);
+}
+
+static ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path,
+ int scope, const char *expr,
+ const char **attrs, LDAPMessage **res,
+ int *count, struct berval **cookie)
+{
+ return ads_do_paged_search_args(ads, bind_path, scope, expr, attrs, NULL, res, count, cookie);
+}
+
+
+/**
+ * Get all results for a search. This uses ads_do_paged_search() to return
+ * all entries in a large search.
+ * @param ads connection to ads server
+ * @param bind_path Base dn for the search
+ * @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
+ * @param expr Search expression
+ * @param attrs Attributes to retrieve
+ * @param res ** which will contain results - free res* with ads_msgfree()
+ * @return status of search
+ **/
+ ADS_STATUS ads_do_search_all_args(ADS_STRUCT *ads, const char *bind_path,
+ int scope, const char *expr,
+ const char **attrs, void *args,
+ LDAPMessage **res)
+{
+ struct berval *cookie = NULL;
+ int count = 0;
+ ADS_STATUS status;
+
+ *res = NULL;
+ status = ads_do_paged_search_args(ads, bind_path, scope, expr, attrs, args, res,
+ &count, &cookie);
+
+ if (!ADS_ERR_OK(status))
+ return status;
+
+#ifdef HAVE_LDAP_ADD_RESULT_ENTRY
+ while (cookie) {
+ LDAPMessage *res2 = NULL;
+ ADS_STATUS status2;
+ LDAPMessage *msg, *next;
+
+ status2 = ads_do_paged_search_args(ads, bind_path, scope, expr,
+ attrs, args, &res2, &count, &cookie);
+
+ if (!ADS_ERR_OK(status2)) break;
+
+ /* this relies on the way that ldap_add_result_entry() works internally. I hope
+ that this works on all ldap libs, but I have only tested with openldap */
+ for (msg = ads_first_message(ads, res2); msg; msg = next) {
+ next = ads_next_message(ads, msg);
+ ldap_add_result_entry((LDAPMessage **)res, msg);
+ }
+ /* note that we do not free res2, as the memory is now
+ part of the main returned list */
+ }
+#else
+ DEBUG(0, ("no ldap_add_result_entry() support in LDAP libs!\n"));
+ status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+#endif
+
+ return status;
+}
+
+ ADS_STATUS ads_do_search_all(ADS_STRUCT *ads, const char *bind_path,
+ int scope, const char *expr,
+ const char **attrs, LDAPMessage **res)
+{
+ return ads_do_search_all_args(ads, bind_path, scope, expr, attrs, NULL, res);
+}
+
+ ADS_STATUS ads_do_search_all_sd_flags(ADS_STRUCT *ads, const char *bind_path,
+ int scope, const char *expr,
+ const char **attrs, uint32 sd_flags,
+ LDAPMessage **res)
+{
+ ads_control args;
+
+ args.control = ADS_SD_FLAGS_OID;
+ args.val = sd_flags;
+ args.critical = True;
+
+ return ads_do_search_all_args(ads, bind_path, scope, expr, attrs, &args, res);
+}
+
+
+/**
+ * Run a function on all results for a search. Uses ads_do_paged_search() and
+ * runs the function as each page is returned, using ads_process_results()
+ * @param ads connection to ads server
+ * @param bind_path Base dn for the search
+ * @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
+ * @param expr Search expression - specified in local charset
+ * @param attrs Attributes to retrieve - specified in UTF-8 or ascii
+ * @param fn Function which takes attr name, values list, and data_area
+ * @param data_area Pointer which is passed to function on each call
+ * @return status of search
+ **/
+ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path,
+ int scope, const char *expr, const char **attrs,
+ bool (*fn)(ADS_STRUCT *, char *, void **, void *),
+ void *data_area)
+{
+ struct berval *cookie = NULL;
+ int count = 0;
+ ADS_STATUS status;
+ LDAPMessage *res;
+
+ status = ads_do_paged_search(ads, bind_path, scope, expr, attrs, &res,
+ &count, &cookie);
+
+ if (!ADS_ERR_OK(status)) return status;
+
+ ads_process_results(ads, res, fn, data_area);
+ ads_msgfree(ads, res);
+
+ while (cookie) {
+ status = ads_do_paged_search(ads, bind_path, scope, expr, attrs,
+ &res, &count, &cookie);
+
+ if (!ADS_ERR_OK(status)) break;
+
+ ads_process_results(ads, res, fn, data_area);
+ ads_msgfree(ads, res);
+ }
+
+ return status;
+}
+
+/**
+ * Do a search with a timeout.
+ * @param ads connection to ads server
+ * @param bind_path Base dn for the search
+ * @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
+ * @param expr Search expression
+ * @param attrs Attributes to retrieve
+ * @param res ** which will contain results - free res* with ads_msgfree()
+ * @return status of search
+ **/
+ ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope,
+ const char *expr,
+ const char **attrs, LDAPMessage **res)
+{
+ int rc;
+ char *utf8_expr, *utf8_path, **search_attrs = NULL;
+ size_t converted_size;
+ TALLOC_CTX *ctx;
+
+ *res = NULL;
+ if (!(ctx = talloc_init("ads_do_search"))) {
+ DEBUG(1,("ads_do_search: talloc_init() failed!"));
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ /* 0 means the conversion worked but the result was empty
+ so we only fail if it's negative. In any case, it always
+ at least nulls out the dest */
+ if (!push_utf8_talloc(ctx, &utf8_expr, expr, &converted_size) ||
+ !push_utf8_talloc(ctx, &utf8_path, bind_path, &converted_size))
+ {
+ DEBUG(1,("ads_do_search: push_utf8_talloc() failed!"));
+ rc = LDAP_NO_MEMORY;
+ goto done;
+ }
+
+ if (!attrs || !(*attrs))
+ search_attrs = NULL;
+ else {
+ /* This would be the utf8-encoded version...*/
+ /* if (!(search_attrs = ads_push_strvals(ctx, attrs))) */
+ if (!(str_list_copy(talloc_tos(), &search_attrs, attrs)))
+ {
+ DEBUG(1,("ads_do_search: str_list_copy() failed!"));
+ rc = LDAP_NO_MEMORY;
+ goto done;
+ }
+ }
+
+ /* see the note in ads_do_paged_search - we *must* disable referrals */
+ ldap_set_option(ads->ldap.ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
+
+ rc = ldap_search_with_timeout(ads->ldap.ld, utf8_path, scope, utf8_expr,
+ search_attrs, 0, NULL, NULL,
+ LDAP_NO_LIMIT,
+ (LDAPMessage **)res);
+
+ if (rc == LDAP_SIZELIMIT_EXCEEDED) {
+ DEBUG(3,("Warning! sizelimit exceeded in ldap. Truncating.\n"));
+ rc = 0;
+ }
+
+ done:
+ talloc_destroy(ctx);
+ /* if/when we decide to utf8-encode attrs, take out this next line */
+ TALLOC_FREE(search_attrs);
+ return ADS_ERROR(rc);
+}
+/**
+ * Do a general ADS search
+ * @param ads connection to ads server
+ * @param res ** which will contain results - free res* with ads_msgfree()
+ * @param expr Search expression
+ * @param attrs Attributes to retrieve
+ * @return status of search
+ **/
+ ADS_STATUS ads_search(ADS_STRUCT *ads, LDAPMessage **res,
+ const char *expr, const char **attrs)
+{
+ return ads_do_search(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE,
+ expr, attrs, res);
+}
+
+/**
+ * Do a search on a specific DistinguishedName
+ * @param ads connection to ads server
+ * @param res ** which will contain results - free res* with ads_msgfree()
+ * @param dn DistinguishName to search
+ * @param attrs Attributes to retrieve
+ * @return status of search
+ **/
+ ADS_STATUS ads_search_dn(ADS_STRUCT *ads, LDAPMessage **res,
+ const char *dn, const char **attrs)
+{
+ return ads_do_search(ads, dn, LDAP_SCOPE_BASE, "(objectclass=*)",
+ attrs, res);
+}
+
+/**
+ * Free up memory from a ads_search
+ * @param ads connection to ads server
+ * @param msg Search results to free
+ **/
+ void ads_msgfree(ADS_STRUCT *ads, LDAPMessage *msg)
+{
+ if (!msg) return;
+ ldap_msgfree(msg);
+}
+
+/**
+ * Free up memory from various ads requests
+ * @param ads connection to ads server
+ * @param mem Area to free
+ **/
+void ads_memfree(ADS_STRUCT *ads, void *mem)
+{
+ SAFE_FREE(mem);
+}
+
+/**
+ * Get a dn from search results
+ * @param ads connection to ads server
+ * @param msg Search result
+ * @return dn string
+ **/
+ char *ads_get_dn(ADS_STRUCT *ads, LDAPMessage *msg)
+{
+ char *utf8_dn, *unix_dn;
+ size_t converted_size;
+
+ utf8_dn = ldap_get_dn(ads->ldap.ld, msg);
+
+ if (!utf8_dn) {
+ DEBUG (5, ("ads_get_dn: ldap_get_dn failed\n"));
+ return NULL;
+ }
+
+ if (!pull_utf8_allocate(&unix_dn, utf8_dn, &converted_size)) {
+ DEBUG(0,("ads_get_dn: string conversion failure utf8 [%s]\n",
+ utf8_dn ));
+ return NULL;
+ }
+ ldap_memfree(utf8_dn);
+ return unix_dn;
+}
+
+/**
+ * Get the parent from a dn
+ * @param dn the dn to return the parent from
+ * @return parent dn string
+ **/
+char *ads_parent_dn(const char *dn)
+{
+ char *p;
+
+ if (dn == NULL) {
+ return NULL;
+ }
+
+ p = strchr(dn, ',');
+
+ if (p == NULL) {
+ return NULL;
+ }
+
+ return p+1;
+}
+
+/**
+ * Find a machine account given a hostname
+ * @param ads connection to ads server
+ * @param res ** which will contain results - free res* with ads_msgfree()
+ * @param host Hostname to search for
+ * @return status of search
+ **/
+ ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, LDAPMessage **res,
+ const char *machine)
+{
+ ADS_STATUS status;
+ char *expr;
+ const char *attrs[] = {"*", "nTSecurityDescriptor", NULL};
+
+ *res = NULL;
+
+ /* the easiest way to find a machine account anywhere in the tree
+ is to look for hostname$ */
+ if (asprintf(&expr, "(samAccountName=%s$)", machine) == -1) {
+ DEBUG(1, ("asprintf failed!\n"));
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ status = ads_search(ads, res, expr, attrs);
+ SAFE_FREE(expr);
+ return status;
+}
+
+/**
+ * Initialize a list of mods to be used in a modify request
+ * @param ctx An initialized TALLOC_CTX
+ * @return allocated ADS_MODLIST
+ **/
+ADS_MODLIST ads_init_mods(TALLOC_CTX *ctx)
+{
+#define ADS_MODLIST_ALLOC_SIZE 10
+ LDAPMod **mods;
+
+ if ((mods = TALLOC_ZERO_ARRAY(ctx, LDAPMod *, ADS_MODLIST_ALLOC_SIZE + 1)))
+ /* -1 is safety to make sure we don't go over the end.
+ need to reset it to NULL before doing ldap modify */
+ mods[ADS_MODLIST_ALLOC_SIZE] = (LDAPMod *) -1;
+
+ return (ADS_MODLIST)mods;
+}
+
+
+/*
+ add an attribute to the list, with values list already constructed
+*/
+static ADS_STATUS ads_modlist_add(TALLOC_CTX *ctx, ADS_MODLIST *mods,
+ int mod_op, const char *name,
+ const void *_invals)
+{
+ const void **invals = (const void **)_invals;
+ int curmod;
+ LDAPMod **modlist = (LDAPMod **) *mods;
+ struct berval **ber_values = NULL;
+ char **char_values = NULL;
+
+ if (!invals) {
+ mod_op = LDAP_MOD_DELETE;
+ } else {
+ if (mod_op & LDAP_MOD_BVALUES)
+ ber_values = ads_dup_values(ctx,
+ (const struct berval **)invals);
+ else
+ char_values = ads_push_strvals(ctx,
+ (const char **) invals);
+ }
+
+ /* find the first empty slot */
+ for (curmod=0; modlist[curmod] && modlist[curmod] != (LDAPMod *) -1;
+ curmod++);
+ if (modlist[curmod] == (LDAPMod *) -1) {
+ if (!(modlist = TALLOC_REALLOC_ARRAY(ctx, modlist, LDAPMod *,
+ curmod+ADS_MODLIST_ALLOC_SIZE+1)))
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ memset(&modlist[curmod], 0,
+ ADS_MODLIST_ALLOC_SIZE*sizeof(LDAPMod *));
+ modlist[curmod+ADS_MODLIST_ALLOC_SIZE] = (LDAPMod *) -1;
+ *mods = (ADS_MODLIST)modlist;
+ }
+
+ if (!(modlist[curmod] = TALLOC_ZERO_P(ctx, LDAPMod)))
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ modlist[curmod]->mod_type = talloc_strdup(ctx, name);
+ if (mod_op & LDAP_MOD_BVALUES) {
+ modlist[curmod]->mod_bvalues = ber_values;
+ } else if (mod_op & LDAP_MOD_DELETE) {
+ modlist[curmod]->mod_values = NULL;
+ } else {
+ modlist[curmod]->mod_values = char_values;
+ }
+
+ modlist[curmod]->mod_op = mod_op;
+ return ADS_ERROR(LDAP_SUCCESS);
+}
+
+/**
+ * Add a single string value to a mod list
+ * @param ctx An initialized TALLOC_CTX
+ * @param mods An initialized ADS_MODLIST
+ * @param name The attribute name to add
+ * @param val The value to add - NULL means DELETE
+ * @return ADS STATUS indicating success of add
+ **/
+ADS_STATUS ads_mod_str(TALLOC_CTX *ctx, ADS_MODLIST *mods,
+ const char *name, const char *val)
+{
+ const char *values[2];
+
+ values[0] = val;
+ values[1] = NULL;
+
+ if (!val)
+ return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL);
+ return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE, name, values);
+}
+
+/**
+ * Add an array of string values to a mod list
+ * @param ctx An initialized TALLOC_CTX
+ * @param mods An initialized ADS_MODLIST
+ * @param name The attribute name to add
+ * @param vals The array of string values to add - NULL means DELETE
+ * @return ADS STATUS indicating success of add
+ **/
+ADS_STATUS ads_mod_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
+ const char *name, const char **vals)
+{
+ if (!vals)
+ return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL);
+ return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE,
+ name, (const void **) vals);
+}
+
+#if 0
+/**
+ * Add a single ber-encoded value to a mod list
+ * @param ctx An initialized TALLOC_CTX
+ * @param mods An initialized ADS_MODLIST
+ * @param name The attribute name to add
+ * @param val The value to add - NULL means DELETE
+ * @return ADS STATUS indicating success of add
+ **/
+static ADS_STATUS ads_mod_ber(TALLOC_CTX *ctx, ADS_MODLIST *mods,
+ const char *name, const struct berval *val)
+{
+ const struct berval *values[2];
+
+ values[0] = val;
+ values[1] = NULL;
+ if (!val)
+ return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL);
+ return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE|LDAP_MOD_BVALUES,
+ name, (const void **) values);
+}
+#endif
+
+/**
+ * Perform an ldap modify
+ * @param ads connection to ads server
+ * @param mod_dn DistinguishedName to modify
+ * @param mods list of modifications to perform
+ * @return status of modify
+ **/
+ADS_STATUS ads_gen_mod(ADS_STRUCT *ads, const char *mod_dn, ADS_MODLIST mods)
+{
+ int ret,i;
+ char *utf8_dn = NULL;
+ size_t converted_size;
+ /*
+ this control is needed to modify that contains a currently
+ non-existent attribute (but allowable for the object) to run
+ */
+ LDAPControl PermitModify = {
+ CONST_DISCARD(char *, ADS_PERMIT_MODIFY_OID),
+ {0, NULL},
+ (char) 1};
+ LDAPControl *controls[2];
+
+ controls[0] = &PermitModify;
+ controls[1] = NULL;
+
+ if (!push_utf8_allocate(&utf8_dn, mod_dn, &converted_size)) {
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ /* find the end of the list, marked by NULL or -1 */
+ for(i=0;(mods[i]!=0)&&(mods[i]!=(LDAPMod *) -1);i++);
+ /* make sure the end of the list is NULL */
+ mods[i] = NULL;
+ ret = ldap_modify_ext_s(ads->ldap.ld, utf8_dn,
+ (LDAPMod **) mods, controls, NULL);
+ SAFE_FREE(utf8_dn);
+ return ADS_ERROR(ret);
+}
+
+/**
+ * Perform an ldap add
+ * @param ads connection to ads server
+ * @param new_dn DistinguishedName to add
+ * @param mods list of attributes and values for DN
+ * @return status of add
+ **/
+ADS_STATUS ads_gen_add(ADS_STRUCT *ads, const char *new_dn, ADS_MODLIST mods)
+{
+ int ret, i;
+ char *utf8_dn = NULL;
+ size_t converted_size;
+
+ if (!push_utf8_allocate(&utf8_dn, new_dn, &converted_size)) {
+ DEBUG(1, ("ads_gen_add: push_utf8_allocate failed!"));
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ /* find the end of the list, marked by NULL or -1 */
+ for(i=0;(mods[i]!=0)&&(mods[i]!=(LDAPMod *) -1);i++);
+ /* make sure the end of the list is NULL */
+ mods[i] = NULL;
+
+ ret = ldap_add_s(ads->ldap.ld, utf8_dn, (LDAPMod**)mods);
+ SAFE_FREE(utf8_dn);
+ return ADS_ERROR(ret);
+}
+
+/**
+ * Delete a DistinguishedName
+ * @param ads connection to ads server
+ * @param new_dn DistinguishedName to delete
+ * @return status of delete
+ **/
+ADS_STATUS ads_del_dn(ADS_STRUCT *ads, char *del_dn)
+{
+ int ret;
+ char *utf8_dn = NULL;
+ size_t converted_size;
+ if (!push_utf8_allocate(&utf8_dn, del_dn, &converted_size)) {
+ DEBUG(1, ("ads_del_dn: push_utf8_allocate failed!"));
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ ret = ldap_delete_s(ads->ldap.ld, utf8_dn);
+ SAFE_FREE(utf8_dn);
+ return ADS_ERROR(ret);
+}
+
+/**
+ * Build an org unit string
+ * if org unit is Computers or blank then assume a container, otherwise
+ * assume a / separated list of organisational units.
+ * jmcd: '\' is now used for escapes so certain chars can be in the ou (e.g. #)
+ * @param ads connection to ads server
+ * @param org_unit Organizational unit
+ * @return org unit string - caller must free
+ **/
+char *ads_ou_string(ADS_STRUCT *ads, const char *org_unit)
+{
+ char *ret = NULL;
+
+ if (!org_unit || !*org_unit) {
+
+ ret = ads_default_ou_string(ads, WELL_KNOWN_GUID_COMPUTERS);
+
+ /* samba4 might not yet respond to a wellknownobject-query */
+ return ret ? ret : SMB_STRDUP("cn=Computers");
+ }
+
+ if (strequal(org_unit, "Computers")) {
+ return SMB_STRDUP("cn=Computers");
+ }
+
+ /* jmcd: removed "\\" from the separation chars, because it is
+ needed as an escape for chars like '#' which are valid in an
+ OU name */
+ return ads_build_path(org_unit, "/", "ou=", 1);
+}
+
+/**
+ * Get a org unit string for a well-known GUID
+ * @param ads connection to ads server
+ * @param wknguid Well known GUID
+ * @return org unit string - caller must free
+ **/
+char *ads_default_ou_string(ADS_STRUCT *ads, const char *wknguid)
+{
+ ADS_STATUS status;
+ LDAPMessage *res = NULL;
+ char *base, *wkn_dn = NULL, *ret = NULL, **wkn_dn_exp = NULL,
+ **bind_dn_exp = NULL;
+ const char *attrs[] = {"distinguishedName", NULL};
+ int new_ln, wkn_ln, bind_ln, i;
+
+ if (wknguid == NULL) {
+ return NULL;
+ }
+
+ if (asprintf(&base, "<WKGUID=%s,%s>", wknguid, ads->config.bind_path ) == -1) {
+ DEBUG(1, ("asprintf failed!\n"));
+ return NULL;
+ }
+
+ status = ads_search_dn(ads, &res, base, attrs);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(1,("Failed while searching for: %s\n", base));
+ goto out;
+ }
+
+ if (ads_count_replies(ads, res) != 1) {
+ goto out;
+ }
+
+ /* substitute the bind-path from the well-known-guid-search result */
+ wkn_dn = ads_get_dn(ads, res);
+ if (!wkn_dn) {
+ goto out;
+ }
+
+ wkn_dn_exp = ldap_explode_dn(wkn_dn, 0);
+ if (!wkn_dn_exp) {
+ goto out;
+ }
+
+ bind_dn_exp = ldap_explode_dn(ads->config.bind_path, 0);
+ if (!bind_dn_exp) {
+ goto out;
+ }
+
+ for (wkn_ln=0; wkn_dn_exp[wkn_ln]; wkn_ln++)
+ ;
+ for (bind_ln=0; bind_dn_exp[bind_ln]; bind_ln++)
+ ;
+
+ new_ln = wkn_ln - bind_ln;
+
+ ret = SMB_STRDUP(wkn_dn_exp[0]);
+ if (!ret) {
+ goto out;
+ }
+
+ for (i=1; i < new_ln; i++) {
+ char *s = NULL;
+
+ if (asprintf(&s, "%s,%s", ret, wkn_dn_exp[i]) == -1) {
+ SAFE_FREE(ret);
+ goto out;
+ }
+
+ SAFE_FREE(ret);
+ ret = SMB_STRDUP(s);
+ free(s);
+ if (!ret) {
+ goto out;
+ }
+ }
+
+ out:
+ SAFE_FREE(base);
+ ads_msgfree(ads, res);
+ ads_memfree(ads, wkn_dn);
+ if (wkn_dn_exp) {
+ ldap_value_free(wkn_dn_exp);
+ }
+ if (bind_dn_exp) {
+ ldap_value_free(bind_dn_exp);
+ }
+
+ return ret;
+}
+
+/**
+ * Adds (appends) an item to an attribute array, rather then
+ * replacing the whole list
+ * @param ctx An initialized TALLOC_CTX
+ * @param mods An initialized ADS_MODLIST
+ * @param name name of the ldap attribute to append to
+ * @param vals an array of values to add
+ * @return status of addition
+ **/
+
+ADS_STATUS ads_add_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
+ const char *name, const char **vals)
+{
+ return ads_modlist_add(ctx, mods, LDAP_MOD_ADD, name,
+ (const void *) vals);
+}
+
+/**
+ * Determines the an account's current KVNO via an LDAP lookup
+ * @param ads An initialized ADS_STRUCT
+ * @param account_name the NT samaccountname.
+ * @return the kvno for the account, or -1 in case of a failure.
+ **/
+
+uint32 ads_get_kvno(ADS_STRUCT *ads, const char *account_name)
+{
+ LDAPMessage *res = NULL;
+ uint32 kvno = (uint32)-1; /* -1 indicates a failure */
+ char *filter;
+ const char *attrs[] = {"msDS-KeyVersionNumber", NULL};
+ char *dn_string = NULL;
+ ADS_STATUS ret = ADS_ERROR(LDAP_SUCCESS);
+
+ DEBUG(5,("ads_get_kvno: Searching for account %s\n", account_name));
+ if (asprintf(&filter, "(samAccountName=%s)", account_name) == -1) {
+ return kvno;
+ }
+ ret = ads_search(ads, &res, filter, attrs);
+ SAFE_FREE(filter);
+ if (!ADS_ERR_OK(ret) || (ads_count_replies(ads, res) != 1)) {
+ DEBUG(1,("ads_get_kvno: Account for %s not found.\n", account_name));
+ ads_msgfree(ads, res);
+ return kvno;
+ }
+
+ dn_string = ads_get_dn(ads, res);
+ if (!dn_string) {
+ DEBUG(0,("ads_get_kvno: out of memory.\n"));
+ ads_msgfree(ads, res);
+ return kvno;
+ }
+ DEBUG(5,("ads_get_kvno: Using: %s\n", dn_string));
+ ads_memfree(ads, dn_string);
+
+ /* ---------------------------------------------------------
+ * 0 is returned as a default KVNO from this point on...
+ * This is done because Windows 2000 does not support key
+ * version numbers. Chances are that a failure in the next
+ * step is simply due to Windows 2000 being used for a
+ * domain controller. */
+ kvno = 0;
+
+ if (!ads_pull_uint32(ads, res, "msDS-KeyVersionNumber", &kvno)) {
+ DEBUG(3,("ads_get_kvno: Error Determining KVNO!\n"));
+ DEBUG(3,("ads_get_kvno: Windows 2000 does not support KVNO's, so this may be normal.\n"));
+ ads_msgfree(ads, res);
+ return kvno;
+ }
+
+ /* Success */
+ DEBUG(5,("ads_get_kvno: Looked Up KVNO of: %d\n", kvno));
+ ads_msgfree(ads, res);
+ return kvno;
+}
+
+/**
+ * Determines the computer account's current KVNO via an LDAP lookup
+ * @param ads An initialized ADS_STRUCT
+ * @param machine_name the NetBIOS name of the computer, which is used to identify the computer account.
+ * @return the kvno for the computer account, or -1 in case of a failure.
+ **/
+
+uint32_t ads_get_machine_kvno(ADS_STRUCT *ads, const char *machine_name)
+{
+ char *computer_account = NULL;
+ uint32_t kvno = -1;
+
+ if (asprintf(&computer_account, "%s$", machine_name) < 0) {
+ return kvno;
+ }
+
+ kvno = ads_get_kvno(ads, computer_account);
+ free(computer_account);
+
+ return kvno;
+}
+
+/**
+ * This clears out all registered spn's for a given hostname
+ * @param ads An initilaized ADS_STRUCT
+ * @param machine_name the NetBIOS name of the computer.
+ * @return 0 upon success, non-zero otherwise.
+ **/
+
+ADS_STATUS ads_clear_service_principal_names(ADS_STRUCT *ads, const char *machine_name)
+{
+ TALLOC_CTX *ctx;
+ LDAPMessage *res = NULL;
+ ADS_MODLIST mods;
+ const char *servicePrincipalName[1] = {NULL};
+ ADS_STATUS ret = ADS_ERROR(LDAP_SUCCESS);
+ char *dn_string = NULL;
+
+ ret = ads_find_machine_acct(ads, &res, machine_name);
+ if (!ADS_ERR_OK(ret) || ads_count_replies(ads, res) != 1) {
+ DEBUG(5,("ads_clear_service_principal_names: WARNING: Host Account for %s not found... skipping operation.\n", machine_name));
+ DEBUG(5,("ads_clear_service_principal_names: WARNING: Service Principals for %s have NOT been cleared.\n", machine_name));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ DEBUG(5,("ads_clear_service_principal_names: Host account for %s found\n", machine_name));
+ ctx = talloc_init("ads_clear_service_principal_names");
+ if (!ctx) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ if (!(mods = ads_init_mods(ctx))) {
+ talloc_destroy(ctx);
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ ret = ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
+ if (!ADS_ERR_OK(ret)) {
+ DEBUG(1,("ads_clear_service_principal_names: Error creating strlist.\n"));
+ ads_msgfree(ads, res);
+ talloc_destroy(ctx);
+ return ret;
+ }
+ dn_string = ads_get_dn(ads, res);
+ if (!dn_string) {
+ talloc_destroy(ctx);
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ ret = ads_gen_mod(ads, dn_string, mods);
+ ads_memfree(ads,dn_string);
+ if (!ADS_ERR_OK(ret)) {
+ DEBUG(1,("ads_clear_service_principal_names: Error: Updating Service Principals for machine %s in LDAP\n",
+ machine_name));
+ ads_msgfree(ads, res);
+ talloc_destroy(ctx);
+ return ret;
+ }
+
+ ads_msgfree(ads, res);
+ talloc_destroy(ctx);
+ return ret;
+}
+
+/**
+ * This adds a service principal name to an existing computer account
+ * (found by hostname) in AD.
+ * @param ads An initialized ADS_STRUCT
+ * @param machine_name the NetBIOS name of the computer, which is used to identify the computer account.
+ * @param my_fqdn The fully qualified DNS name of the machine
+ * @param spn A string of the service principal to add, i.e. 'host'
+ * @return 0 upon sucess, or non-zero if a failure occurs
+ **/
+
+ADS_STATUS ads_add_service_principal_name(ADS_STRUCT *ads, const char *machine_name,
+ const char *my_fqdn, const char *spn)
+{
+ ADS_STATUS ret;
+ TALLOC_CTX *ctx;
+ LDAPMessage *res = NULL;
+ char *psp1, *psp2;
+ ADS_MODLIST mods;
+ char *dn_string = NULL;
+ const char *servicePrincipalName[3] = {NULL, NULL, NULL};
+
+ ret = ads_find_machine_acct(ads, &res, machine_name);
+ if (!ADS_ERR_OK(ret) || ads_count_replies(ads, res) != 1) {
+ DEBUG(1,("ads_add_service_principal_name: WARNING: Host Account for %s not found... skipping operation.\n",
+ machine_name));
+ DEBUG(1,("ads_add_service_principal_name: WARNING: Service Principal '%s/%s@%s' has NOT been added.\n",
+ spn, machine_name, ads->config.realm));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ DEBUG(1,("ads_add_service_principal_name: Host account for %s found\n", machine_name));
+ if (!(ctx = talloc_init("ads_add_service_principal_name"))) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ /* add short name spn */
+
+ if ( (psp1 = talloc_asprintf(ctx, "%s/%s", spn, machine_name)) == NULL ) {
+ talloc_destroy(ctx);
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ strupper_m(psp1);
+ strlower_m(&psp1[strlen(spn)]);
+ servicePrincipalName[0] = psp1;
+
+ DEBUG(5,("ads_add_service_principal_name: INFO: Adding %s to host %s\n",
+ psp1, machine_name));
+
+
+ /* add fully qualified spn */
+
+ if ( (psp2 = talloc_asprintf(ctx, "%s/%s", spn, my_fqdn)) == NULL ) {
+ ret = ADS_ERROR(LDAP_NO_MEMORY);
+ goto out;
+ }
+ strupper_m(psp2);
+ strlower_m(&psp2[strlen(spn)]);
+ servicePrincipalName[1] = psp2;
+
+ DEBUG(5,("ads_add_service_principal_name: INFO: Adding %s to host %s\n",
+ psp2, machine_name));
+
+ if ( (mods = ads_init_mods(ctx)) == NULL ) {
+ ret = ADS_ERROR(LDAP_NO_MEMORY);
+ goto out;
+ }
+
+ ret = ads_add_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
+ if (!ADS_ERR_OK(ret)) {
+ DEBUG(1,("ads_add_service_principal_name: Error: Updating Service Principals in LDAP\n"));
+ goto out;
+ }
+
+ if ( (dn_string = ads_get_dn(ads, res)) == NULL ) {
+ ret = ADS_ERROR(LDAP_NO_MEMORY);
+ goto out;
+ }
+
+ ret = ads_gen_mod(ads, dn_string, mods);
+ ads_memfree(ads,dn_string);
+ if (!ADS_ERR_OK(ret)) {
+ DEBUG(1,("ads_add_service_principal_name: Error: Updating Service Principals in LDAP\n"));
+ goto out;
+ }
+
+ out:
+ TALLOC_FREE( ctx );
+ ads_msgfree(ads, res);
+ return ret;
+}
+
+/**
+ * adds a machine account to the ADS server
+ * @param ads An intialized ADS_STRUCT
+ * @param machine_name - the NetBIOS machine name of this account.
+ * @param account_type A number indicating the type of account to create
+ * @param org_unit The LDAP path in which to place this account
+ * @return 0 upon success, or non-zero otherwise
+**/
+
+ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name,
+ const char *org_unit)
+{
+ ADS_STATUS ret;
+ char *samAccountName, *controlstr;
+ TALLOC_CTX *ctx;
+ ADS_MODLIST mods;
+ char *machine_escaped = NULL;
+ char *new_dn;
+ const char *objectClass[] = {"top", "person", "organizationalPerson",
+ "user", "computer", NULL};
+ LDAPMessage *res = NULL;
+ uint32 acct_control = ( UF_WORKSTATION_TRUST_ACCOUNT |\
+ UF_DONT_EXPIRE_PASSWD |\
+ UF_ACCOUNTDISABLE );
+
+ if (!(ctx = talloc_init("ads_add_machine_acct")))
+ return ADS_ERROR(LDAP_NO_MEMORY);
+
+ ret = ADS_ERROR(LDAP_NO_MEMORY);
+
+ machine_escaped = escape_rdn_val_string_alloc(machine_name);
+ if (!machine_escaped) {
+ goto done;
+ }
+
+ new_dn = talloc_asprintf(ctx, "cn=%s,%s", machine_escaped, org_unit);
+ samAccountName = talloc_asprintf(ctx, "%s$", machine_name);
+
+ if ( !new_dn || !samAccountName ) {
+ goto done;
+ }
+
+#ifndef ENCTYPE_ARCFOUR_HMAC
+ acct_control |= UF_USE_DES_KEY_ONLY;
+#endif
+
+ if (!(controlstr = talloc_asprintf(ctx, "%u", acct_control))) {
+ goto done;
+ }
+
+ if (!(mods = ads_init_mods(ctx))) {
+ goto done;
+ }
+
+ ads_mod_str(ctx, &mods, "cn", machine_name);
+ ads_mod_str(ctx, &mods, "sAMAccountName", samAccountName);
+ ads_mod_strlist(ctx, &mods, "objectClass", objectClass);
+ ads_mod_str(ctx, &mods, "userAccountControl", controlstr);
+
+ ret = ads_gen_add(ads, new_dn, mods);
+
+done:
+ SAFE_FREE(machine_escaped);
+ ads_msgfree(ads, res);
+ talloc_destroy(ctx);
+
+ return ret;
+}
+
+/**
+ * move a machine account to another OU on the ADS server
+ * @param ads - An intialized ADS_STRUCT
+ * @param machine_name - the NetBIOS machine name of this account.
+ * @param org_unit - The LDAP path in which to place this account
+ * @param moved - whether we moved the machine account (optional)
+ * @return 0 upon success, or non-zero otherwise
+**/
+
+ADS_STATUS ads_move_machine_acct(ADS_STRUCT *ads, const char *machine_name,
+ const char *org_unit, bool *moved)
+{
+ ADS_STATUS rc;
+ int ldap_status;
+ LDAPMessage *res = NULL;
+ char *filter = NULL;
+ char *computer_dn = NULL;
+ char *parent_dn;
+ char *computer_rdn = NULL;
+ bool need_move = False;
+
+ if (asprintf(&filter, "(samAccountName=%s$)", machine_name) == -1) {
+ rc = ADS_ERROR(LDAP_NO_MEMORY);
+ goto done;
+ }
+
+ /* Find pre-existing machine */
+ rc = ads_search(ads, &res, filter, NULL);
+ if (!ADS_ERR_OK(rc)) {
+ goto done;
+ }
+
+ computer_dn = ads_get_dn(ads, res);
+ if (!computer_dn) {
+ rc = ADS_ERROR(LDAP_NO_MEMORY);
+ goto done;
+ }
+
+ parent_dn = ads_parent_dn(computer_dn);
+ if (strequal(parent_dn, org_unit)) {
+ goto done;
+ }
+
+ need_move = True;
+
+ if (asprintf(&computer_rdn, "CN=%s", machine_name) == -1) {
+ rc = ADS_ERROR(LDAP_NO_MEMORY);
+ goto done;
+ }
+
+ ldap_status = ldap_rename_s(ads->ldap.ld, computer_dn, computer_rdn,
+ org_unit, 1, NULL, NULL);
+ rc = ADS_ERROR(ldap_status);
+
+done:
+ ads_msgfree(ads, res);
+ SAFE_FREE(filter);
+ SAFE_FREE(computer_dn);
+ SAFE_FREE(computer_rdn);
+
+ if (!ADS_ERR_OK(rc)) {
+ need_move = False;
+ }
+
+ if (moved) {
+ *moved = need_move;
+ }
+
+ return rc;
+}
+
+/*
+ dump a binary result from ldap
+*/
+static void dump_binary(ADS_STRUCT *ads, const char *field, struct berval **values)
+{
+ int i, j;
+ for (i=0; values[i]; i++) {
+ printf("%s: ", field);
+ for (j=0; j<values[i]->bv_len; j++) {
+ printf("%02X", (unsigned char)values[i]->bv_val[j]);
+ }
+ printf("\n");
+ }
+}
+
+static void dump_guid(ADS_STRUCT *ads, const char *field, struct berval **values)
+{
+ int i;
+ for (i=0; values[i]; i++) {
+
+ UUID_FLAT guid;
+ struct GUID tmp;
+
+ memcpy(guid.info, values[i]->bv_val, sizeof(guid.info));
+ smb_uuid_unpack(guid, &tmp);
+ printf("%s: %s\n", field, smb_uuid_string(talloc_tos(), tmp));
+ }
+}
+
+/*
+ dump a sid result from ldap
+*/
+static void dump_sid(ADS_STRUCT *ads, const char *field, struct berval **values)
+{
+ int i;
+ for (i=0; values[i]; i++) {
+ DOM_SID sid;
+ fstring tmp;
+ sid_parse(values[i]->bv_val, values[i]->bv_len, &sid);
+ printf("%s: %s\n", field, sid_to_fstring(tmp, &sid));
+ }
+}
+
+/*
+ dump ntSecurityDescriptor
+*/
+static void dump_sd(ADS_STRUCT *ads, const char *filed, struct berval **values)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct security_descriptor *psd;
+ NTSTATUS status;
+
+ status = unmarshall_sec_desc(talloc_tos(), (uint8 *)values[0]->bv_val,
+ values[0]->bv_len, &psd);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("unmarshall_sec_desc failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(frame);
+ return;
+ }
+
+ if (psd) {
+ ads_disp_sd(ads, talloc_tos(), psd);
+ }
+
+ TALLOC_FREE(frame);
+}
+
+/*
+ dump a string result from ldap
+*/
+static void dump_string(const char *field, char **values)
+{
+ int i;
+ for (i=0; values[i]; i++) {
+ printf("%s: %s\n", field, values[i]);
+ }
+}
+
+/*
+ dump a field from LDAP on stdout
+ used for debugging
+*/
+
+static bool ads_dump_field(ADS_STRUCT *ads, char *field, void **values, void *data_area)
+{
+ const struct {
+ const char *name;
+ bool string;
+ void (*handler)(ADS_STRUCT *, const char *, struct berval **);
+ } handlers[] = {
+ {"objectGUID", False, dump_guid},
+ {"netbootGUID", False, dump_guid},
+ {"nTSecurityDescriptor", False, dump_sd},
+ {"dnsRecord", False, dump_binary},
+ {"objectSid", False, dump_sid},
+ {"tokenGroups", False, dump_sid},
+ {"tokenGroupsNoGCAcceptable", False, dump_sid},
+ {"tokengroupsGlobalandUniversal", False, dump_sid},
+ {"mS-DS-CreatorSID", False, dump_sid},
+ {"msExchMailboxGuid", False, dump_guid},
+ {NULL, True, NULL}
+ };
+ int i;
+
+ if (!field) { /* must be end of an entry */
+ printf("\n");
+ return False;
+ }
+
+ for (i=0; handlers[i].name; i++) {
+ if (StrCaseCmp(handlers[i].name, field) == 0) {
+ if (!values) /* first time, indicate string or not */
+ return handlers[i].string;
+ handlers[i].handler(ads, field, (struct berval **) values);
+ break;
+ }
+ }
+ if (!handlers[i].name) {
+ if (!values) /* first time, indicate string conversion */
+ return True;
+ dump_string(field, (char **)values);
+ }
+ return False;
+}
+
+/**
+ * Dump a result from LDAP on stdout
+ * used for debugging
+ * @param ads connection to ads server
+ * @param res Results to dump
+ **/
+
+ void ads_dump(ADS_STRUCT *ads, LDAPMessage *res)
+{
+ ads_process_results(ads, res, ads_dump_field, NULL);
+}
+
+/**
+ * Walk through results, calling a function for each entry found.
+ * The function receives a field name, a berval * array of values,
+ * and a data area passed through from the start. The function is
+ * called once with null for field and values at the end of each
+ * entry.
+ * @param ads connection to ads server
+ * @param res Results to process
+ * @param fn Function for processing each result
+ * @param data_area user-defined area to pass to function
+ **/
+ void ads_process_results(ADS_STRUCT *ads, LDAPMessage *res,
+ bool (*fn)(ADS_STRUCT *, char *, void **, void *),
+ void *data_area)
+{
+ LDAPMessage *msg;
+ TALLOC_CTX *ctx;
+ size_t converted_size;
+
+ if (!(ctx = talloc_init("ads_process_results")))
+ return;
+
+ for (msg = ads_first_entry(ads, res); msg;
+ msg = ads_next_entry(ads, msg)) {
+ char *utf8_field;
+ BerElement *b;
+
+ for (utf8_field=ldap_first_attribute(ads->ldap.ld,
+ (LDAPMessage *)msg,&b);
+ utf8_field;
+ utf8_field=ldap_next_attribute(ads->ldap.ld,
+ (LDAPMessage *)msg,b)) {
+ struct berval **ber_vals;
+ char **str_vals, **utf8_vals;
+ char *field;
+ bool string;
+
+ if (!pull_utf8_talloc(ctx, &field, utf8_field,
+ &converted_size))
+ {
+ DEBUG(0,("ads_process_results: "
+ "pull_utf8_talloc failed: %s",
+ strerror(errno)));
+ }
+
+ string = fn(ads, field, NULL, data_area);
+
+ if (string) {
+ utf8_vals = ldap_get_values(ads->ldap.ld,
+ (LDAPMessage *)msg, field);
+ str_vals = ads_pull_strvals(ctx,
+ (const char **) utf8_vals);
+ fn(ads, field, (void **) str_vals, data_area);
+ ldap_value_free(utf8_vals);
+ } else {
+ ber_vals = ldap_get_values_len(ads->ldap.ld,
+ (LDAPMessage *)msg, field);
+ fn(ads, field, (void **) ber_vals, data_area);
+
+ ldap_value_free_len(ber_vals);
+ }
+ ldap_memfree(utf8_field);
+ }
+ ber_free(b, 0);
+ talloc_free_children(ctx);
+ fn(ads, NULL, NULL, data_area); /* completed an entry */
+
+ }
+ talloc_destroy(ctx);
+}
+
+/**
+ * count how many replies are in a LDAPMessage
+ * @param ads connection to ads server
+ * @param res Results to count
+ * @return number of replies
+ **/
+int ads_count_replies(ADS_STRUCT *ads, void *res)
+{
+ return ldap_count_entries(ads->ldap.ld, (LDAPMessage *)res);
+}
+
+/**
+ * pull the first entry from a ADS result
+ * @param ads connection to ads server
+ * @param res Results of search
+ * @return first entry from result
+ **/
+ LDAPMessage *ads_first_entry(ADS_STRUCT *ads, LDAPMessage *res)
+{
+ return ldap_first_entry(ads->ldap.ld, res);
+}
+
+/**
+ * pull the next entry from a ADS result
+ * @param ads connection to ads server
+ * @param res Results of search
+ * @return next entry from result
+ **/
+ LDAPMessage *ads_next_entry(ADS_STRUCT *ads, LDAPMessage *res)
+{
+ return ldap_next_entry(ads->ldap.ld, res);
+}
+
+/**
+ * pull the first message from a ADS result
+ * @param ads connection to ads server
+ * @param res Results of search
+ * @return first message from result
+ **/
+ LDAPMessage *ads_first_message(ADS_STRUCT *ads, LDAPMessage *res)
+{
+ return ldap_first_message(ads->ldap.ld, res);
+}
+
+/**
+ * pull the next message from a ADS result
+ * @param ads connection to ads server
+ * @param res Results of search
+ * @return next message from result
+ **/
+ LDAPMessage *ads_next_message(ADS_STRUCT *ads, LDAPMessage *res)
+{
+ return ldap_next_message(ads->ldap.ld, res);
+}
+
+/**
+ * pull a single string from a ADS result
+ * @param ads connection to ads server
+ * @param mem_ctx TALLOC_CTX to use for allocating result string
+ * @param msg Results of search
+ * @param field Attribute to retrieve
+ * @return Result string in talloc context
+ **/
+ char *ads_pull_string(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, LDAPMessage *msg,
+ const char *field)
+{
+ char **values;
+ char *ret = NULL;
+ char *ux_string;
+ size_t converted_size;
+
+ values = ldap_get_values(ads->ldap.ld, msg, field);
+ if (!values)
+ return NULL;
+
+ if (values[0] && pull_utf8_talloc(mem_ctx, &ux_string, values[0],
+ &converted_size))
+ {
+ ret = ux_string;
+ }
+ ldap_value_free(values);
+ return ret;
+}
+
+/**
+ * pull an array of strings from a ADS result
+ * @param ads connection to ads server
+ * @param mem_ctx TALLOC_CTX to use for allocating result string
+ * @param msg Results of search
+ * @param field Attribute to retrieve
+ * @return Result strings in talloc context
+ **/
+ char **ads_pull_strings(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ LDAPMessage *msg, const char *field,
+ size_t *num_values)
+{
+ char **values;
+ char **ret = NULL;
+ int i;
+ size_t converted_size;
+
+ values = ldap_get_values(ads->ldap.ld, msg, field);
+ if (!values)
+ return NULL;
+
+ *num_values = ldap_count_values(values);
+
+ ret = TALLOC_ARRAY(mem_ctx, char *, *num_values + 1);
+ if (!ret) {
+ ldap_value_free(values);
+ return NULL;
+ }
+
+ for (i=0;i<*num_values;i++) {
+ if (!pull_utf8_talloc(mem_ctx, &ret[i], values[i],
+ &converted_size))
+ {
+ ldap_value_free(values);
+ return NULL;
+ }
+ }
+ ret[i] = NULL;
+
+ ldap_value_free(values);
+ return ret;
+}
+
+/**
+ * pull an array of strings from a ADS result
+ * (handle large multivalue attributes with range retrieval)
+ * @param ads connection to ads server
+ * @param mem_ctx TALLOC_CTX to use for allocating result string
+ * @param msg Results of search
+ * @param field Attribute to retrieve
+ * @param current_strings strings returned by a previous call to this function
+ * @param next_attribute The next query should ask for this attribute
+ * @param num_values How many values did we get this time?
+ * @param more_values Are there more values to get?
+ * @return Result strings in talloc context
+ **/
+ char **ads_pull_strings_range(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ LDAPMessage *msg, const char *field,
+ char **current_strings,
+ const char **next_attribute,
+ size_t *num_strings,
+ bool *more_strings)
+{
+ char *attr;
+ char *expected_range_attrib, *range_attr;
+ BerElement *ptr = NULL;
+ char **strings;
+ char **new_strings;
+ size_t num_new_strings;
+ unsigned long int range_start;
+ unsigned long int range_end;
+
+ /* we might have been given the whole lot anyway */
+ if ((strings = ads_pull_strings(ads, mem_ctx, msg, field, num_strings))) {
+ *more_strings = False;
+ return strings;
+ }
+
+ expected_range_attrib = talloc_asprintf(mem_ctx, "%s;Range=", field);
+
+ /* look for Range result */
+ for (attr = ldap_first_attribute(ads->ldap.ld, (LDAPMessage *)msg, &ptr);
+ attr;
+ attr = ldap_next_attribute(ads->ldap.ld, (LDAPMessage *)msg, ptr)) {
+ /* we ignore the fact that this is utf8, as all attributes are ascii... */
+ if (strnequal(attr, expected_range_attrib, strlen(expected_range_attrib))) {
+ range_attr = attr;
+ break;
+ }
+ ldap_memfree(attr);
+ }
+ if (!attr) {
+ ber_free(ptr, 0);
+ /* nothing here - this field is just empty */
+ *more_strings = False;
+ return NULL;
+ }
+
+ if (sscanf(&range_attr[strlen(expected_range_attrib)], "%lu-%lu",
+ &range_start, &range_end) == 2) {
+ *more_strings = True;
+ } else {
+ if (sscanf(&range_attr[strlen(expected_range_attrib)], "%lu-*",
+ &range_start) == 1) {
+ *more_strings = False;
+ } else {
+ DEBUG(1, ("ads_pull_strings_range: Cannot parse Range attriubte (%s)\n",
+ range_attr));
+ ldap_memfree(range_attr);
+ *more_strings = False;
+ return NULL;
+ }
+ }
+
+ if ((*num_strings) != range_start) {
+ DEBUG(1, ("ads_pull_strings_range: Range attribute (%s) doesn't start at %u, but at %lu"
+ " - aborting range retreival\n",
+ range_attr, (unsigned int)(*num_strings) + 1, range_start));
+ ldap_memfree(range_attr);
+ *more_strings = False;
+ return NULL;
+ }
+
+ new_strings = ads_pull_strings(ads, mem_ctx, msg, range_attr, &num_new_strings);
+
+ if (*more_strings && ((*num_strings + num_new_strings) != (range_end + 1))) {
+ DEBUG(1, ("ads_pull_strings_range: Range attribute (%s) tells us we have %lu "
+ "strings in this bunch, but we only got %lu - aborting range retreival\n",
+ range_attr, (unsigned long int)range_end - range_start + 1,
+ (unsigned long int)num_new_strings));
+ ldap_memfree(range_attr);
+ *more_strings = False;
+ return NULL;
+ }
+
+ strings = TALLOC_REALLOC_ARRAY(mem_ctx, current_strings, char *,
+ *num_strings + num_new_strings);
+
+ if (strings == NULL) {
+ ldap_memfree(range_attr);
+ *more_strings = False;
+ return NULL;
+ }
+
+ if (new_strings && num_new_strings) {
+ memcpy(&strings[*num_strings], new_strings,
+ sizeof(*new_strings) * num_new_strings);
+ }
+
+ (*num_strings) += num_new_strings;
+
+ if (*more_strings) {
+ *next_attribute = talloc_asprintf(mem_ctx,
+ "%s;range=%d-*",
+ field,
+ (int)*num_strings);
+
+ if (!*next_attribute) {
+ DEBUG(1, ("talloc_asprintf for next attribute failed!\n"));
+ ldap_memfree(range_attr);
+ *more_strings = False;
+ return NULL;
+ }
+ }
+
+ ldap_memfree(range_attr);
+
+ return strings;
+}
+
+/**
+ * pull a single uint32 from a ADS result
+ * @param ads connection to ads server
+ * @param msg Results of search
+ * @param field Attribute to retrieve
+ * @param v Pointer to int to store result
+ * @return boolean inidicating success
+*/
+ bool ads_pull_uint32(ADS_STRUCT *ads, LDAPMessage *msg, const char *field,
+ uint32 *v)
+{
+ char **values;
+
+ values = ldap_get_values(ads->ldap.ld, msg, field);
+ if (!values)
+ return False;
+ if (!values[0]) {
+ ldap_value_free(values);
+ return False;
+ }
+
+ *v = atoi(values[0]);
+ ldap_value_free(values);
+ return True;
+}
+
+/**
+ * pull a single objectGUID from an ADS result
+ * @param ads connection to ADS server
+ * @param msg results of search
+ * @param guid 37-byte area to receive text guid
+ * @return boolean indicating success
+ **/
+ bool ads_pull_guid(ADS_STRUCT *ads, LDAPMessage *msg, struct GUID *guid)
+{
+ char **values;
+ UUID_FLAT flat_guid;
+
+ values = ldap_get_values(ads->ldap.ld, msg, "objectGUID");
+ if (!values)
+ return False;
+
+ if (values[0]) {
+ memcpy(&flat_guid.info, values[0], sizeof(UUID_FLAT));
+ smb_uuid_unpack(flat_guid, guid);
+ ldap_value_free(values);
+ return True;
+ }
+ ldap_value_free(values);
+ return False;
+
+}
+
+
+/**
+ * pull a single DOM_SID from a ADS result
+ * @param ads connection to ads server
+ * @param msg Results of search
+ * @param field Attribute to retrieve
+ * @param sid Pointer to sid to store result
+ * @return boolean inidicating success
+*/
+ bool ads_pull_sid(ADS_STRUCT *ads, LDAPMessage *msg, const char *field,
+ DOM_SID *sid)
+{
+ struct berval **values;
+ bool ret = False;
+
+ values = ldap_get_values_len(ads->ldap.ld, msg, field);
+
+ if (!values)
+ return False;
+
+ if (values[0])
+ ret = sid_parse(values[0]->bv_val, values[0]->bv_len, sid);
+
+ ldap_value_free_len(values);
+ return ret;
+}
+
+/**
+ * pull an array of DOM_SIDs from a ADS result
+ * @param ads connection to ads server
+ * @param mem_ctx TALLOC_CTX for allocating sid array
+ * @param msg Results of search
+ * @param field Attribute to retrieve
+ * @param sids pointer to sid array to allocate
+ * @return the count of SIDs pulled
+ **/
+ int ads_pull_sids(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ LDAPMessage *msg, const char *field, DOM_SID **sids)
+{
+ struct berval **values;
+ bool ret;
+ int count, i;
+
+ values = ldap_get_values_len(ads->ldap.ld, msg, field);
+
+ if (!values)
+ return 0;
+
+ for (i=0; values[i]; i++)
+ /* nop */ ;
+
+ if (i) {
+ (*sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, i);
+ if (!(*sids)) {
+ ldap_value_free_len(values);
+ return 0;
+ }
+ } else {
+ (*sids) = NULL;
+ }
+
+ count = 0;
+ for (i=0; values[i]; i++) {
+ ret = sid_parse(values[i]->bv_val, values[i]->bv_len, &(*sids)[count]);
+ if (ret) {
+ DEBUG(10, ("pulling SID: %s\n",
+ sid_string_dbg(&(*sids)[count])));
+ count++;
+ }
+ }
+
+ ldap_value_free_len(values);
+ return count;
+}
+
+/**
+ * pull a SEC_DESC from a ADS result
+ * @param ads connection to ads server
+ * @param mem_ctx TALLOC_CTX for allocating sid array
+ * @param msg Results of search
+ * @param field Attribute to retrieve
+ * @param sd Pointer to *SEC_DESC to store result (talloc()ed)
+ * @return boolean inidicating success
+*/
+ bool ads_pull_sd(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ LDAPMessage *msg, const char *field, SEC_DESC **sd)
+{
+ struct berval **values;
+ bool ret = true;
+
+ values = ldap_get_values_len(ads->ldap.ld, msg, field);
+
+ if (!values) return false;
+
+ if (values[0]) {
+ NTSTATUS status;
+ status = unmarshall_sec_desc(mem_ctx,
+ (uint8 *)values[0]->bv_val,
+ values[0]->bv_len, sd);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("unmarshall_sec_desc failed: %s\n",
+ nt_errstr(status)));
+ ret = false;
+ }
+ }
+
+ ldap_value_free_len(values);
+ return ret;
+}
+
+/*
+ * in order to support usernames longer than 21 characters we need to
+ * use both the sAMAccountName and the userPrincipalName attributes
+ * It seems that not all users have the userPrincipalName attribute set
+ *
+ * @param ads connection to ads server
+ * @param mem_ctx TALLOC_CTX for allocating sid array
+ * @param msg Results of search
+ * @return the username
+ */
+ char *ads_pull_username(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ LDAPMessage *msg)
+{
+#if 0 /* JERRY */
+ char *ret, *p;
+
+ /* lookup_name() only works on the sAMAccountName to
+ returning the username portion of userPrincipalName
+ breaks winbindd_getpwnam() */
+
+ ret = ads_pull_string(ads, mem_ctx, msg, "userPrincipalName");
+ if (ret && (p = strchr_m(ret, '@'))) {
+ *p = 0;
+ return ret;
+ }
+#endif
+ return ads_pull_string(ads, mem_ctx, msg, "sAMAccountName");
+}
+
+
+/**
+ * find the update serial number - this is the core of the ldap cache
+ * @param ads connection to ads server
+ * @param ads connection to ADS server
+ * @param usn Pointer to retrieved update serial number
+ * @return status of search
+ **/
+ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32 *usn)
+{
+ const char *attrs[] = {"highestCommittedUSN", NULL};
+ ADS_STATUS status;
+ LDAPMessage *res;
+
+ status = ads_do_search_retry(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
+ if (!ADS_ERR_OK(status))
+ return status;
+
+ if (ads_count_replies(ads, res) != 1) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ }
+
+ if (!ads_pull_uint32(ads, res, "highestCommittedUSN", usn)) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ }
+
+ ads_msgfree(ads, res);
+ return ADS_SUCCESS;
+}
+
+/* parse a ADS timestring - typical string is
+ '20020917091222.0Z0' which means 09:12.22 17th September
+ 2002, timezone 0 */
+static time_t ads_parse_time(const char *str)
+{
+ struct tm tm;
+
+ ZERO_STRUCT(tm);
+
+ if (sscanf(str, "%4d%2d%2d%2d%2d%2d",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
+ return 0;
+ }
+ tm.tm_year -= 1900;
+ tm.tm_mon -= 1;
+
+ return timegm(&tm);
+}
+
+/********************************************************************
+********************************************************************/
+
+ADS_STATUS ads_current_time(ADS_STRUCT *ads)
+{
+ const char *attrs[] = {"currentTime", NULL};
+ ADS_STATUS status;
+ LDAPMessage *res;
+ char *timestr;
+ TALLOC_CTX *ctx;
+ ADS_STRUCT *ads_s = ads;
+
+ if (!(ctx = talloc_init("ads_current_time"))) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ /* establish a new ldap tcp session if necessary */
+
+ if ( !ads->ldap.ld ) {
+ if ( (ads_s = ads_init( ads->server.realm, ads->server.workgroup,
+ ads->server.ldap_server )) == NULL )
+ {
+ goto done;
+ }
+ ads_s->auth.flags = ADS_AUTH_ANON_BIND;
+ status = ads_connect( ads_s );
+ if ( !ADS_ERR_OK(status))
+ goto done;
+ }
+
+ status = ads_do_search(ads_s, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
+ if (!ADS_ERR_OK(status)) {
+ goto done;
+ }
+
+ timestr = ads_pull_string(ads_s, ctx, res, "currentTime");
+ if (!timestr) {
+ ads_msgfree(ads_s, res);
+ status = ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ goto done;
+ }
+
+ /* but save the time and offset in the original ADS_STRUCT */
+
+ ads->config.current_time = ads_parse_time(timestr);
+
+ if (ads->config.current_time != 0) {
+ ads->auth.time_offset = ads->config.current_time - time(NULL);
+ DEBUG(4,("time offset is %d seconds\n", ads->auth.time_offset));
+ }
+
+ ads_msgfree(ads, res);
+
+ status = ADS_SUCCESS;
+
+done:
+ /* free any temporary ads connections */
+ if ( ads_s != ads ) {
+ ads_destroy( &ads_s );
+ }
+ talloc_destroy(ctx);
+
+ return status;
+}
+
+/********************************************************************
+********************************************************************/
+
+ADS_STATUS ads_domain_func_level(ADS_STRUCT *ads, uint32 *val)
+{
+ const char *attrs[] = {"domainFunctionality", NULL};
+ ADS_STATUS status;
+ LDAPMessage *res;
+ ADS_STRUCT *ads_s = ads;
+
+ *val = DS_DOMAIN_FUNCTION_2000;
+
+ /* establish a new ldap tcp session if necessary */
+
+ if ( !ads->ldap.ld ) {
+ if ( (ads_s = ads_init( ads->server.realm, ads->server.workgroup,
+ ads->server.ldap_server )) == NULL )
+ {
+ goto done;
+ }
+ ads_s->auth.flags = ADS_AUTH_ANON_BIND;
+ status = ads_connect( ads_s );
+ if ( !ADS_ERR_OK(status))
+ goto done;
+ }
+
+ /* If the attribute does not exist assume it is a Windows 2000
+ functional domain */
+
+ status = ads_do_search(ads_s, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
+ if (!ADS_ERR_OK(status)) {
+ if ( status.err.rc == LDAP_NO_SUCH_ATTRIBUTE ) {
+ status = ADS_SUCCESS;
+ }
+ goto done;
+ }
+
+ if ( !ads_pull_uint32(ads_s, res, "domainFunctionality", val) ) {
+ DEBUG(5,("ads_domain_func_level: Failed to pull the domainFunctionality attribute.\n"));
+ }
+ DEBUG(3,("ads_domain_func_level: %d\n", *val));
+
+
+ ads_msgfree(ads, res);
+
+done:
+ /* free any temporary ads connections */
+ if ( ads_s != ads ) {
+ ads_destroy( &ads_s );
+ }
+
+ return status;
+}
+
+/**
+ * find the domain sid for our domain
+ * @param ads connection to ads server
+ * @param sid Pointer to domain sid
+ * @return status of search
+ **/
+ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, DOM_SID *sid)
+{
+ const char *attrs[] = {"objectSid", NULL};
+ LDAPMessage *res;
+ ADS_STATUS rc;
+
+ rc = ads_do_search_retry(ads, ads->config.bind_path, LDAP_SCOPE_BASE, "(objectclass=*)",
+ attrs, &res);
+ if (!ADS_ERR_OK(rc)) return rc;
+ if (!ads_pull_sid(ads, res, "objectSid", sid)) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR_SYSTEM(ENOENT);
+ }
+ ads_msgfree(ads, res);
+
+ return ADS_SUCCESS;
+}
+
+/**
+ * find our site name
+ * @param ads connection to ads server
+ * @param mem_ctx Pointer to talloc context
+ * @param site_name Pointer to the sitename
+ * @return status of search
+ **/
+ADS_STATUS ads_site_dn(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char **site_name)
+{
+ ADS_STATUS status;
+ LDAPMessage *res;
+ const char *dn, *service_name;
+ const char *attrs[] = { "dsServiceName", NULL };
+
+ status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ service_name = ads_pull_string(ads, mem_ctx, res, "dsServiceName");
+ if (service_name == NULL) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ }
+
+ ads_msgfree(ads, res);
+
+ /* go up three levels */
+ dn = ads_parent_dn(ads_parent_dn(ads_parent_dn(service_name)));
+ if (dn == NULL) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ *site_name = talloc_strdup(mem_ctx, dn);
+ if (*site_name == NULL) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ return status;
+ /*
+ dsServiceName: CN=NTDS Settings,CN=W2K3DC,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=ber,DC=suse,DC=de
+ */
+}
+
+/**
+ * find the site dn where a machine resides
+ * @param ads connection to ads server
+ * @param mem_ctx Pointer to talloc context
+ * @param computer_name name of the machine
+ * @param site_name Pointer to the sitename
+ * @return status of search
+ **/
+ADS_STATUS ads_site_dn_for_machine(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char *computer_name, const char **site_dn)
+{
+ ADS_STATUS status;
+ LDAPMessage *res;
+ const char *parent, *filter;
+ char *config_context = NULL;
+ char *dn;
+
+ /* shortcut a query */
+ if (strequal(computer_name, ads->config.ldap_server_name)) {
+ return ads_site_dn(ads, mem_ctx, site_dn);
+ }
+
+ status = ads_config_path(ads, mem_ctx, &config_context);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ filter = talloc_asprintf(mem_ctx, "(cn=%s)", computer_name);
+ if (filter == NULL) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ status = ads_do_search(ads, config_context, LDAP_SCOPE_SUBTREE,
+ filter, NULL, &res);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ if (ads_count_replies(ads, res) != 1) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ dn = ads_get_dn(ads, res);
+ if (dn == NULL) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ /* go up three levels */
+ parent = ads_parent_dn(ads_parent_dn(ads_parent_dn(dn)));
+ if (parent == NULL) {
+ ads_msgfree(ads, res);
+ ads_memfree(ads, dn);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ *site_dn = talloc_strdup(mem_ctx, parent);
+ if (*site_dn == NULL) {
+ ads_msgfree(ads, res);
+ ads_memfree(ads, dn);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ ads_memfree(ads, dn);
+ ads_msgfree(ads, res);
+
+ return status;
+}
+
+/**
+ * get the upn suffixes for a domain
+ * @param ads connection to ads server
+ * @param mem_ctx Pointer to talloc context
+ * @param suffixes Pointer to an array of suffixes
+ * @param num_suffixes Pointer to the number of suffixes
+ * @return status of search
+ **/
+ADS_STATUS ads_upn_suffixes(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char ***suffixes, size_t *num_suffixes)
+{
+ ADS_STATUS status;
+ LDAPMessage *res;
+ const char *base;
+ char *config_context = NULL;
+ const char *attrs[] = { "uPNSuffixes", NULL };
+
+ status = ads_config_path(ads, mem_ctx, &config_context);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ base = talloc_asprintf(mem_ctx, "cn=Partitions,%s", config_context);
+ if (base == NULL) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ status = ads_search_dn(ads, &res, base, attrs);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ if (ads_count_replies(ads, res) != 1) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ (*suffixes) = ads_pull_strings(ads, mem_ctx, res, "uPNSuffixes", num_suffixes);
+ if ((*suffixes) == NULL) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ ads_msgfree(ads, res);
+
+ return status;
+}
+
+/**
+ * get the joinable ous for a domain
+ * @param ads connection to ads server
+ * @param mem_ctx Pointer to talloc context
+ * @param ous Pointer to an array of ous
+ * @param num_ous Pointer to the number of ous
+ * @return status of search
+ **/
+ADS_STATUS ads_get_joinable_ous(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ char ***ous,
+ size_t *num_ous)
+{
+ ADS_STATUS status;
+ LDAPMessage *res = NULL;
+ LDAPMessage *msg = NULL;
+ const char *attrs[] = { "dn", NULL };
+ int count = 0;
+
+ status = ads_search(ads, &res,
+ "(|(objectClass=domain)(objectclass=organizationalUnit))",
+ attrs);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ count = ads_count_replies(ads, res);
+ if (count < 1) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ }
+
+ for (msg = ads_first_entry(ads, res); msg;
+ msg = ads_next_entry(ads, msg)) {
+
+ char *dn = NULL;
+
+ dn = ads_get_dn(ads, msg);
+ if (!dn) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ if (!add_string_to_array(mem_ctx, dn,
+ (const char ***)ous,
+ (int *)num_ous)) {
+ ads_memfree(ads, dn);
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ ads_memfree(ads, dn);
+ }
+
+ ads_msgfree(ads, res);
+
+ return status;
+}
+
+
+/**
+ * pull a DOM_SID from an extended dn string
+ * @param mem_ctx TALLOC_CTX
+ * @param extended_dn string
+ * @param flags string type of extended_dn
+ * @param sid pointer to a DOM_SID
+ * @return boolean inidicating success
+ **/
+bool ads_get_sid_from_extended_dn(TALLOC_CTX *mem_ctx,
+ const char *extended_dn,
+ enum ads_extended_dn_flags flags,
+ DOM_SID *sid)
+{
+ char *p, *q, *dn;
+
+ if (!extended_dn) {
+ return False;
+ }
+
+ /* otherwise extended_dn gets stripped off */
+ if ((dn = talloc_strdup(mem_ctx, extended_dn)) == NULL) {
+ return False;
+ }
+ /*
+ * ADS_EXTENDED_DN_HEX_STRING:
+ * <GUID=238e1963cb390f4bb032ba0105525a29>;<SID=010500000000000515000000bb68c8fd6b61b427572eb04556040000>;CN=gd,OU=berlin,OU=suse,DC=ber,DC=suse,DC=de
+ *
+ * ADS_EXTENDED_DN_STRING (only with w2k3):
+ <GUID=63198e23-39cb-4b0f-b032-ba0105525a29>;<SID=S-1-5-21-4257769659-666132843-1169174103-1110>;CN=gd,OU=berlin,OU=suse,DC=ber,DC=suse,DC=de
+ */
+
+ p = strchr(dn, ';');
+ if (!p) {
+ return False;
+ }
+
+ if (strncmp(p, ";<SID=", strlen(";<SID=")) != 0) {
+ return False;
+ }
+
+ p += strlen(";<SID=");
+
+ q = strchr(p, '>');
+ if (!q) {
+ return False;
+ }
+
+ *q = '\0';
+
+ DEBUG(100,("ads_get_sid_from_extended_dn: sid string is %s\n", p));
+
+ switch (flags) {
+
+ case ADS_EXTENDED_DN_STRING:
+ if (!string_to_sid(sid, p)) {
+ return False;
+ }
+ break;
+ case ADS_EXTENDED_DN_HEX_STRING: {
+ fstring buf;
+ size_t buf_len;
+
+ buf_len = strhex_to_str(buf, sizeof(buf), p, strlen(p));
+ if (buf_len == 0) {
+ return False;
+ }
+
+ if (!sid_parse(buf, buf_len, sid)) {
+ DEBUG(10,("failed to parse sid\n"));
+ return False;
+ }
+ break;
+ }
+ default:
+ DEBUG(10,("unknown extended dn format\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/**
+ * pull an array of DOM_SIDs from a ADS result
+ * @param ads connection to ads server
+ * @param mem_ctx TALLOC_CTX for allocating sid array
+ * @param msg Results of search
+ * @param field Attribute to retrieve
+ * @param flags string type of extended_dn
+ * @param sids pointer to sid array to allocate
+ * @return the count of SIDs pulled
+ **/
+ int ads_pull_sids_from_extendeddn(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ LDAPMessage *msg,
+ const char *field,
+ enum ads_extended_dn_flags flags,
+ DOM_SID **sids)
+{
+ int i;
+ size_t dn_count;
+ char **dn_strings;
+
+ if ((dn_strings = ads_pull_strings(ads, mem_ctx, msg, field,
+ &dn_count)) == NULL) {
+ return 0;
+ }
+
+ (*sids) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, dn_count + 1);
+ if (!(*sids)) {
+ TALLOC_FREE(dn_strings);
+ return 0;
+ }
+
+ for (i=0; i<dn_count; i++) {
+
+ if (!ads_get_sid_from_extended_dn(mem_ctx, dn_strings[i],
+ flags, &(*sids)[i])) {
+ TALLOC_FREE(*sids);
+ TALLOC_FREE(dn_strings);
+ return 0;
+ }
+ }
+
+ TALLOC_FREE(dn_strings);
+
+ return dn_count;
+}
+
+/********************************************************************
+********************************************************************/
+
+char* ads_get_dnshostname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name )
+{
+ LDAPMessage *res = NULL;
+ ADS_STATUS status;
+ int count = 0;
+ char *name = NULL;
+
+ status = ads_find_machine_acct(ads, &res, global_myname());
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0,("ads_get_dnshostname: Failed to find account for %s\n",
+ global_myname()));
+ goto out;
+ }
+
+ if ( (count = ads_count_replies(ads, res)) != 1 ) {
+ DEBUG(1,("ads_get_dnshostname: %d entries returned!\n", count));
+ goto out;
+ }
+
+ if ( (name = ads_pull_string(ads, ctx, res, "dNSHostName")) == NULL ) {
+ DEBUG(0,("ads_get_dnshostname: No dNSHostName attribute!\n"));
+ }
+
+out:
+ ads_msgfree(ads, res);
+
+ return name;
+}
+
+/********************************************************************
+********************************************************************/
+
+char* ads_get_upn( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name )
+{
+ LDAPMessage *res = NULL;
+ ADS_STATUS status;
+ int count = 0;
+ char *name = NULL;
+
+ status = ads_find_machine_acct(ads, &res, machine_name);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0,("ads_get_upn: Failed to find account for %s\n",
+ global_myname()));
+ goto out;
+ }
+
+ if ( (count = ads_count_replies(ads, res)) != 1 ) {
+ DEBUG(1,("ads_get_upn: %d entries returned!\n", count));
+ goto out;
+ }
+
+ if ( (name = ads_pull_string(ads, ctx, res, "userPrincipalName")) == NULL ) {
+ DEBUG(2,("ads_get_upn: No userPrincipalName attribute!\n"));
+ }
+
+out:
+ ads_msgfree(ads, res);
+
+ return name;
+}
+
+/********************************************************************
+********************************************************************/
+
+char* ads_get_samaccountname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name )
+{
+ LDAPMessage *res = NULL;
+ ADS_STATUS status;
+ int count = 0;
+ char *name = NULL;
+
+ status = ads_find_machine_acct(ads, &res, global_myname());
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0,("ads_get_dnshostname: Failed to find account for %s\n",
+ global_myname()));
+ goto out;
+ }
+
+ if ( (count = ads_count_replies(ads, res)) != 1 ) {
+ DEBUG(1,("ads_get_dnshostname: %d entries returned!\n", count));
+ goto out;
+ }
+
+ if ( (name = ads_pull_string(ads, ctx, res, "sAMAccountName")) == NULL ) {
+ DEBUG(0,("ads_get_dnshostname: No sAMAccountName attribute!\n"));
+ }
+
+out:
+ ads_msgfree(ads, res);
+
+ return name;
+}
+
+#if 0
+
+ SAVED CODE - we used to join via ldap - remember how we did this. JRA.
+
+/**
+ * Join a machine to a realm
+ * Creates the machine account and sets the machine password
+ * @param ads connection to ads server
+ * @param machine name of host to add
+ * @param org_unit Organizational unit to place machine in
+ * @return status of join
+ **/
+ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *machine_name,
+ uint32 account_type, const char *org_unit)
+{
+ ADS_STATUS status;
+ LDAPMessage *res = NULL;
+ char *machine;
+
+ /* machine name must be lowercase */
+ machine = SMB_STRDUP(machine_name);
+ strlower_m(machine);
+
+ /*
+ status = ads_find_machine_acct(ads, (void **)&res, machine);
+ if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
+ DEBUG(0, ("Host account for %s already exists - deleting old account\n", machine));
+ status = ads_leave_realm(ads, machine);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0, ("Failed to delete host '%s' from the '%s' realm.\n",
+ machine, ads->config.realm));
+ return status;
+ }
+ }
+ */
+ status = ads_add_machine_acct(ads, machine, account_type, org_unit);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0, ("ads_join_realm: ads_add_machine_acct failed (%s): %s\n", machine, ads_errstr(status)));
+ SAFE_FREE(machine);
+ return status;
+ }
+
+ status = ads_find_machine_acct(ads, (void **)(void *)&res, machine);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0, ("ads_join_realm: Host account test failed for machine %s\n", machine));
+ SAFE_FREE(machine);
+ return status;
+ }
+
+ SAFE_FREE(machine);
+ ads_msgfree(ads, res);
+
+ return status;
+}
+#endif
+
+/**
+ * Delete a machine from the realm
+ * @param ads connection to ads server
+ * @param hostname Machine to remove
+ * @return status of delete
+ **/
+ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
+{
+ ADS_STATUS status;
+ void *msg;
+ LDAPMessage *res;
+ char *hostnameDN, *host;
+ int rc;
+ LDAPControl ldap_control;
+ LDAPControl * pldap_control[2] = {NULL, NULL};
+
+ pldap_control[0] = &ldap_control;
+ memset(&ldap_control, 0, sizeof(LDAPControl));
+ ldap_control.ldctl_oid = (char *)LDAP_SERVER_TREE_DELETE_OID;
+
+ /* hostname must be lowercase */
+ host = SMB_STRDUP(hostname);
+ strlower_m(host);
+
+ status = ads_find_machine_acct(ads, &res, host);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0, ("Host account for %s does not exist.\n", host));
+ SAFE_FREE(host);
+ return status;
+ }
+
+ msg = ads_first_entry(ads, res);
+ if (!msg) {
+ SAFE_FREE(host);
+ return ADS_ERROR_SYSTEM(ENOENT);
+ }
+
+ hostnameDN = ads_get_dn(ads, (LDAPMessage *)msg);
+
+ rc = ldap_delete_ext_s(ads->ldap.ld, hostnameDN, pldap_control, NULL);
+ if (rc) {
+ DEBUG(3,("ldap_delete_ext_s failed with error code %d\n", rc));
+ }else {
+ DEBUG(3,("ldap_delete_ext_s succeeded with error code %d\n", rc));
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ const char *attrs[] = { "cn", NULL };
+ LDAPMessage *msg_sub;
+
+ /* we only search with scope ONE, we do not expect any further
+ * objects to be created deeper */
+
+ status = ads_do_search_retry(ads, hostnameDN,
+ LDAP_SCOPE_ONELEVEL,
+ "(objectclass=*)", attrs, &res);
+
+ if (!ADS_ERR_OK(status)) {
+ SAFE_FREE(host);
+ ads_memfree(ads, hostnameDN);
+ return status;
+ }
+
+ for (msg_sub = ads_first_entry(ads, res); msg_sub;
+ msg_sub = ads_next_entry(ads, msg_sub)) {
+
+ char *dn = NULL;
+
+ if ((dn = ads_get_dn(ads, msg_sub)) == NULL) {
+ SAFE_FREE(host);
+ ads_memfree(ads, hostnameDN);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ status = ads_del_dn(ads, dn);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(3,("failed to delete dn %s: %s\n", dn, ads_errstr(status)));
+ SAFE_FREE(host);
+ ads_memfree(ads, dn);
+ ads_memfree(ads, hostnameDN);
+ return status;
+ }
+
+ ads_memfree(ads, dn);
+ }
+
+ /* there should be no subordinate objects anymore */
+ status = ads_do_search_retry(ads, hostnameDN,
+ LDAP_SCOPE_ONELEVEL,
+ "(objectclass=*)", attrs, &res);
+
+ if (!ADS_ERR_OK(status) || ( (ads_count_replies(ads, res)) > 0 ) ) {
+ SAFE_FREE(host);
+ ads_memfree(ads, hostnameDN);
+ return status;
+ }
+
+ /* delete hostnameDN now */
+ status = ads_del_dn(ads, hostnameDN);
+ if (!ADS_ERR_OK(status)) {
+ SAFE_FREE(host);
+ DEBUG(3,("failed to delete dn %s: %s\n", hostnameDN, ads_errstr(status)));
+ ads_memfree(ads, hostnameDN);
+ return status;
+ }
+ }
+
+ ads_memfree(ads, hostnameDN);
+
+ status = ads_find_machine_acct(ads, &res, host);
+ if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
+ DEBUG(3, ("Failed to remove host account.\n"));
+ SAFE_FREE(host);
+ return status;
+ }
+
+ SAFE_FREE(host);
+ return status;
+}
+
+/**
+ * pull all token-sids from an LDAP dn
+ * @param ads connection to ads server
+ * @param mem_ctx TALLOC_CTX for allocating sid array
+ * @param dn of LDAP object
+ * @param user_sid pointer to DOM_SID (objectSid)
+ * @param primary_group_sid pointer to DOM_SID (self composed)
+ * @param sids pointer to sid array to allocate
+ * @param num_sids counter of SIDs pulled
+ * @return status of token query
+ **/
+ ADS_STATUS ads_get_tokensids(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *dn,
+ DOM_SID *user_sid,
+ DOM_SID *primary_group_sid,
+ DOM_SID **sids,
+ size_t *num_sids)
+{
+ ADS_STATUS status;
+ LDAPMessage *res = NULL;
+ int count = 0;
+ size_t tmp_num_sids;
+ DOM_SID *tmp_sids;
+ DOM_SID tmp_user_sid;
+ DOM_SID tmp_primary_group_sid;
+ uint32 pgid;
+ const char *attrs[] = {
+ "objectSid",
+ "tokenGroups",
+ "primaryGroupID",
+ NULL
+ };
+
+ status = ads_search_retry_dn(ads, &res, dn, attrs);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ count = ads_count_replies(ads, res);
+ if (count != 1) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
+ }
+
+ if (!ads_pull_sid(ads, res, "objectSid", &tmp_user_sid)) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+
+ if (!ads_pull_uint32(ads, res, "primaryGroupID", &pgid)) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+
+ {
+ /* hack to compose the primary group sid without knowing the
+ * domsid */
+
+ DOM_SID domsid;
+ uint32 dummy_rid;
+
+ sid_copy(&domsid, &tmp_user_sid);
+
+ if (!sid_split_rid(&domsid, &dummy_rid)) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+
+ if (!sid_compose(&tmp_primary_group_sid, &domsid, pgid)) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+ }
+
+ tmp_num_sids = ads_pull_sids(ads, mem_ctx, res, "tokenGroups", &tmp_sids);
+
+ if (tmp_num_sids == 0 || !tmp_sids) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+
+ if (num_sids) {
+ *num_sids = tmp_num_sids;
+ }
+
+ if (sids) {
+ *sids = tmp_sids;
+ }
+
+ if (user_sid) {
+ *user_sid = tmp_user_sid;
+ }
+
+ if (primary_group_sid) {
+ *primary_group_sid = tmp_primary_group_sid;
+ }
+
+ DEBUG(10,("ads_get_tokensids: returned %d sids\n", (int)tmp_num_sids + 2));
+
+ ads_msgfree(ads, res);
+ return ADS_ERROR_LDAP(LDAP_SUCCESS);
+}
+
+/**
+ * Find a sAMAccoutName in LDAP
+ * @param ads connection to ads server
+ * @param mem_ctx TALLOC_CTX for allocating sid array
+ * @param samaccountname to search
+ * @param uac_ret uint32 pointer userAccountControl attribute value
+ * @param dn_ret pointer to dn
+ * @return status of token query
+ **/
+ADS_STATUS ads_find_samaccount(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *samaccountname,
+ uint32 *uac_ret,
+ const char **dn_ret)
+{
+ ADS_STATUS status;
+ const char *attrs[] = { "userAccountControl", NULL };
+ const char *filter;
+ LDAPMessage *res = NULL;
+ char *dn = NULL;
+ uint32 uac = 0;
+
+ filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)(sAMAccountName=%s))",
+ samaccountname);
+ if (filter == NULL) {
+ status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ goto out;
+ }
+
+ status = ads_do_search_all(ads, ads->config.bind_path,
+ LDAP_SCOPE_SUBTREE,
+ filter, attrs, &res);
+
+ if (!ADS_ERR_OK(status)) {
+ goto out;
+ }
+
+ if (ads_count_replies(ads, res) != 1) {
+ status = ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ goto out;
+ }
+
+ dn = ads_get_dn(ads, res);
+ if (dn == NULL) {
+ status = ADS_ERROR(LDAP_NO_MEMORY);
+ goto out;
+ }
+
+ if (!ads_pull_uint32(ads, res, "userAccountControl", &uac)) {
+ status = ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ goto out;
+ }
+
+ if (uac_ret) {
+ *uac_ret = uac;
+ }
+
+ if (dn_ret) {
+ *dn_ret = talloc_strdup(mem_ctx, dn);
+ if (!*dn_ret) {
+ status = ADS_ERROR(LDAP_NO_MEMORY);
+ goto out;
+ }
+ }
+ out:
+ ads_memfree(ads, dn);
+ ads_msgfree(ads, res);
+
+ return status;
+}
+
+/**
+ * find our configuration path
+ * @param ads connection to ads server
+ * @param mem_ctx Pointer to talloc context
+ * @param config_path Pointer to the config path
+ * @return status of search
+ **/
+ADS_STATUS ads_config_path(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ char **config_path)
+{
+ ADS_STATUS status;
+ LDAPMessage *res = NULL;
+ const char *config_context = NULL;
+ const char *attrs[] = { "configurationNamingContext", NULL };
+
+ status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
+ "(objectclass=*)", attrs, &res);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ config_context = ads_pull_string(ads, mem_ctx, res,
+ "configurationNamingContext");
+ ads_msgfree(ads, res);
+ if (!config_context) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ if (config_path) {
+ *config_path = talloc_strdup(mem_ctx, config_context);
+ if (!*config_path) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ }
+
+ return ADS_ERROR(LDAP_SUCCESS);
+}
+
+/**
+ * find the displayName of an extended right
+ * @param ads connection to ads server
+ * @param config_path The config path
+ * @param mem_ctx Pointer to talloc context
+ * @param GUID struct of the rightsGUID
+ * @return status of search
+ **/
+const char *ads_get_extended_right_name_by_guid(ADS_STRUCT *ads,
+ const char *config_path,
+ TALLOC_CTX *mem_ctx,
+ const struct GUID *rights_guid)
+{
+ ADS_STATUS rc;
+ LDAPMessage *res = NULL;
+ char *expr = NULL;
+ const char *attrs[] = { "displayName", NULL };
+ const char *result = NULL;
+ const char *path;
+
+ if (!ads || !mem_ctx || !rights_guid) {
+ goto done;
+ }
+
+ expr = talloc_asprintf(mem_ctx, "(rightsGuid=%s)",
+ smb_uuid_string(mem_ctx, *rights_guid));
+ if (!expr) {
+ goto done;
+ }
+
+ path = talloc_asprintf(mem_ctx, "cn=Extended-Rights,%s", config_path);
+ if (!path) {
+ goto done;
+ }
+
+ rc = ads_do_search_retry(ads, path, LDAP_SCOPE_SUBTREE,
+ expr, attrs, &res);
+ if (!ADS_ERR_OK(rc)) {
+ goto done;
+ }
+
+ if (ads_count_replies(ads, res) != 1) {
+ goto done;
+ }
+
+ result = ads_pull_string(ads, mem_ctx, res, "displayName");
+
+ done:
+ ads_msgfree(ads, res);
+ return result;
+
+}
+
+/**
+ * verify or build and verify an account ou
+ * @param mem_ctx Pointer to talloc context
+ * @param ads connection to ads server
+ * @param account_ou
+ * @return status of search
+ **/
+
+ADS_STATUS ads_check_ou_dn(TALLOC_CTX *mem_ctx,
+ ADS_STRUCT *ads,
+ const char **account_ou)
+{
+ struct ldb_dn *name_dn = NULL;
+ const char *name = NULL;
+ char *ou_string = NULL;
+
+ name_dn = ldb_dn_explode(mem_ctx, *account_ou);
+ if (name_dn) {
+ return ADS_SUCCESS;
+ }
+
+ ou_string = ads_ou_string(ads, *account_ou);
+ if (!ou_string) {
+ return ADS_ERROR_LDAP(LDAP_INVALID_DN_SYNTAX);
+ }
+
+ name = talloc_asprintf(mem_ctx, "%s,%s", ou_string,
+ ads->config.bind_path);
+ SAFE_FREE(ou_string);
+ if (!name) {
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+
+ name_dn = ldb_dn_explode(mem_ctx, name);
+ if (!name_dn) {
+ return ADS_ERROR_LDAP(LDAP_INVALID_DN_SYNTAX);
+ }
+
+ *account_ou = talloc_strdup(mem_ctx, name);
+ if (!*account_ou) {
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+
+ return ADS_SUCCESS;
+}
+
+#endif
diff --git a/source3/libads/ldap_printer.c b/source3/libads/ldap_printer.c
new file mode 100644
index 0000000000..9935e2311a
--- /dev/null
+++ b/source3/libads/ldap_printer.c
@@ -0,0 +1,373 @@
+/*
+ Unix SMB/CIFS implementation.
+ ads (active directory) printer utility library
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_ADS
+
+/*
+ find a printer given the name and the hostname
+ Note that results "res" may be allocated on return so that the
+ results can be used. It should be freed using ads_msgfree.
+*/
+ ADS_STATUS ads_find_printer_on_server(ADS_STRUCT *ads, LDAPMessage **res,
+ const char *printer,
+ const char *servername)
+{
+ ADS_STATUS status;
+ char *srv_dn, **srv_cn, *s;
+ const char *attrs[] = {"*", "nTSecurityDescriptor", NULL};
+
+ status = ads_find_machine_acct(ads, res, servername);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(1, ("ads_find_printer_on_server: cannot find host %s in ads\n",
+ servername));
+ return status;
+ }
+ if (ads_count_replies(ads, *res) != 1) {
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+ srv_dn = ldap_get_dn(ads->ldap.ld, *res);
+ if (srv_dn == NULL) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ srv_cn = ldap_explode_dn(srv_dn, 1);
+ if (srv_cn == NULL) {
+ ldap_memfree(srv_dn);
+ return ADS_ERROR(LDAP_INVALID_DN_SYNTAX);
+ }
+ ads_msgfree(ads, *res);
+
+ asprintf(&s, "(cn=%s-%s)", srv_cn[0], printer);
+ status = ads_search(ads, res, s, attrs);
+
+ ldap_memfree(srv_dn);
+ ldap_value_free(srv_cn);
+ free(s);
+ return status;
+}
+
+ ADS_STATUS ads_find_printers(ADS_STRUCT *ads, LDAPMessage **res)
+{
+ const char *ldap_expr;
+ const char *attrs[] = { "objectClass", "printerName", "location", "driverName",
+ "serverName", "description", NULL };
+
+ /* For the moment only display all printers */
+
+ ldap_expr = "(&(!(showInAdvancedViewOnly=TRUE))(uncName=*)"
+ "(objectCategory=printQueue))";
+
+ return ads_search(ads, res, ldap_expr, attrs);
+}
+
+/*
+ modify a printer entry in the directory
+*/
+ADS_STATUS ads_mod_printer_entry(ADS_STRUCT *ads, char *prt_dn,
+ TALLOC_CTX *ctx, const ADS_MODLIST *mods)
+{
+ return ads_gen_mod(ads, prt_dn, *mods);
+}
+
+/*
+ add a printer to the directory
+*/
+ADS_STATUS ads_add_printer_entry(ADS_STRUCT *ads, char *prt_dn,
+ TALLOC_CTX *ctx, ADS_MODLIST *mods)
+{
+ ads_mod_str(ctx, mods, "objectClass", "printQueue");
+ return ads_gen_add(ads, prt_dn, *mods);
+}
+
+/*
+ map a REG_SZ to an ldap mod
+*/
+static bool map_sz(TALLOC_CTX *ctx, ADS_MODLIST *mods,
+ const REGISTRY_VALUE *value)
+{
+ char *str_value = NULL;
+ size_t converted_size;
+ ADS_STATUS status;
+
+ if (value->type != REG_SZ)
+ return false;
+
+ if (value->size && *((smb_ucs2_t *) value->data_p)) {
+ if (!pull_ucs2_talloc(ctx, &str_value,
+ (const smb_ucs2_t *) value->data_p,
+ &converted_size))
+ {
+ return false;
+ }
+ status = ads_mod_str(ctx, mods, value->valuename, str_value);
+ return ADS_ERR_OK(status);
+ }
+ return true;
+
+}
+
+/*
+ map a REG_DWORD to an ldap mod
+*/
+static bool map_dword(TALLOC_CTX *ctx, ADS_MODLIST *mods,
+ const REGISTRY_VALUE *value)
+{
+ char *str_value = NULL;
+ ADS_STATUS status;
+
+ if (value->type != REG_DWORD)
+ return False;
+ str_value = talloc_asprintf(ctx, "%d", *((uint32 *) value->data_p));
+ if (!str_value) {
+ return False;
+ }
+ status = ads_mod_str(ctx, mods, value->valuename, str_value);
+ return ADS_ERR_OK(status);
+}
+
+/*
+ map a boolean REG_BINARY to an ldap mod
+*/
+static bool map_bool(TALLOC_CTX *ctx, ADS_MODLIST *mods,
+ const REGISTRY_VALUE *value)
+{
+ char *str_value;
+ ADS_STATUS status;
+
+ if ((value->type != REG_BINARY) || (value->size != 1))
+ return False;
+ str_value = talloc_asprintf(ctx, "%s",
+ *(value->data_p) ? "TRUE" : "FALSE");
+ if (!str_value) {
+ return False;
+ }
+ status = ads_mod_str(ctx, mods, value->valuename, str_value);
+ return ADS_ERR_OK(status);
+}
+
+/*
+ map a REG_MULTI_SZ to an ldap mod
+*/
+static bool map_multi_sz(TALLOC_CTX *ctx, ADS_MODLIST *mods,
+ const REGISTRY_VALUE *value)
+{
+ char **str_values = NULL;
+ size_t converted_size;
+ smb_ucs2_t *cur_str = (smb_ucs2_t *) value->data_p;
+ uint32 size = 0, num_vals = 0, i=0;
+ ADS_STATUS status;
+
+ if (value->type != REG_MULTI_SZ)
+ return False;
+
+ while(cur_str && *cur_str && (size < value->size)) {
+ size += 2 * (strlen_w(cur_str) + 1);
+ cur_str += strlen_w(cur_str) + 1;
+ num_vals++;
+ };
+
+ if (num_vals) {
+ str_values = TALLOC_ARRAY(ctx, char *, num_vals + 1);
+ if (!str_values) {
+ return False;
+ }
+ memset(str_values, '\0',
+ (num_vals + 1) * sizeof(char *));
+
+ cur_str = (smb_ucs2_t *) value->data_p;
+ for (i=0; i < num_vals; i++) {
+ cur_str += pull_ucs2_talloc(ctx, &str_values[i],
+ cur_str, &converted_size) ?
+ converted_size : (size_t)-1;
+ }
+
+ status = ads_mod_strlist(ctx, mods, value->valuename,
+ (const char **) str_values);
+ return ADS_ERR_OK(status);
+ }
+ return True;
+}
+
+struct valmap_to_ads {
+ const char *valname;
+ bool (*fn)(TALLOC_CTX *, ADS_MODLIST *, const REGISTRY_VALUE *);
+};
+
+/*
+ map a REG_SZ to an ldap mod
+*/
+static void map_regval_to_ads(TALLOC_CTX *ctx, ADS_MODLIST *mods,
+ REGISTRY_VALUE *value)
+{
+ const struct valmap_to_ads map[] = {
+ {SPOOL_REG_ASSETNUMBER, map_sz},
+ {SPOOL_REG_BYTESPERMINUTE, map_dword},
+ {SPOOL_REG_DEFAULTPRIORITY, map_dword},
+ {SPOOL_REG_DESCRIPTION, map_sz},
+ {SPOOL_REG_DRIVERNAME, map_sz},
+ {SPOOL_REG_DRIVERVERSION, map_dword},
+ {SPOOL_REG_FLAGS, map_dword},
+ {SPOOL_REG_LOCATION, map_sz},
+ {SPOOL_REG_OPERATINGSYSTEM, map_sz},
+ {SPOOL_REG_OPERATINGSYSTEMHOTFIX, map_sz},
+ {SPOOL_REG_OPERATINGSYSTEMSERVICEPACK, map_sz},
+ {SPOOL_REG_OPERATINGSYSTEMVERSION, map_sz},
+ {SPOOL_REG_PORTNAME, map_multi_sz},
+ {SPOOL_REG_PRINTATTRIBUTES, map_dword},
+ {SPOOL_REG_PRINTBINNAMES, map_multi_sz},
+ {SPOOL_REG_PRINTCOLLATE, map_bool},
+ {SPOOL_REG_PRINTCOLOR, map_bool},
+ {SPOOL_REG_PRINTDUPLEXSUPPORTED, map_bool},
+ {SPOOL_REG_PRINTENDTIME, map_dword},
+ {SPOOL_REG_PRINTFORMNAME, map_sz},
+ {SPOOL_REG_PRINTKEEPPRINTEDJOBS, map_bool},
+ {SPOOL_REG_PRINTLANGUAGE, map_multi_sz},
+ {SPOOL_REG_PRINTMACADDRESS, map_sz},
+ {SPOOL_REG_PRINTMAXCOPIES, map_sz},
+ {SPOOL_REG_PRINTMAXRESOLUTIONSUPPORTED, map_dword},
+ {SPOOL_REG_PRINTMAXXEXTENT, map_dword},
+ {SPOOL_REG_PRINTMAXYEXTENT, map_dword},
+ {SPOOL_REG_PRINTMEDIAREADY, map_multi_sz},
+ {SPOOL_REG_PRINTMEDIASUPPORTED, map_multi_sz},
+ {SPOOL_REG_PRINTMEMORY, map_dword},
+ {SPOOL_REG_PRINTMINXEXTENT, map_dword},
+ {SPOOL_REG_PRINTMINYEXTENT, map_dword},
+ {SPOOL_REG_PRINTNETWORKADDRESS, map_sz},
+ {SPOOL_REG_PRINTNOTIFY, map_sz},
+ {SPOOL_REG_PRINTNUMBERUP, map_dword},
+ {SPOOL_REG_PRINTORIENTATIONSSUPPORTED, map_multi_sz},
+ {SPOOL_REG_PRINTOWNER, map_sz},
+ {SPOOL_REG_PRINTPAGESPERMINUTE, map_dword},
+ {SPOOL_REG_PRINTRATE, map_dword},
+ {SPOOL_REG_PRINTRATEUNIT, map_sz},
+ {SPOOL_REG_PRINTSEPARATORFILE, map_sz},
+ {SPOOL_REG_PRINTSHARENAME, map_sz},
+ {SPOOL_REG_PRINTSPOOLING, map_sz},
+ {SPOOL_REG_PRINTSTAPLINGSUPPORTED, map_bool},
+ {SPOOL_REG_PRINTSTARTTIME, map_dword},
+ {SPOOL_REG_PRINTSTATUS, map_sz},
+ {SPOOL_REG_PRIORITY, map_dword},
+ {SPOOL_REG_SERVERNAME, map_sz},
+ {SPOOL_REG_SHORTSERVERNAME, map_sz},
+ {SPOOL_REG_UNCNAME, map_sz},
+ {SPOOL_REG_URL, map_sz},
+ {SPOOL_REG_VERSIONNUMBER, map_dword},
+ {NULL, NULL}
+ };
+ int i;
+
+ for (i=0; map[i].valname; i++) {
+ if (StrCaseCmp(map[i].valname, value->valuename) == 0) {
+ if (!map[i].fn(ctx, mods, value)) {
+ DEBUG(5, ("Add of value %s to modlist failed\n", value->valuename));
+ } else {
+ DEBUG(7, ("Mapped value %s\n", value->valuename));
+ }
+
+ }
+ }
+}
+
+
+WERROR get_remote_printer_publishing_data(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ ADS_MODLIST *mods,
+ const char *printer)
+{
+ WERROR result;
+ char *printername, *servername;
+ REGVAL_CTR *dsdriver_ctr, *dsspooler_ctr;
+ uint32 i;
+ POLICY_HND pol;
+
+ if ((asprintf(&servername, "\\\\%s", cli->desthost) == -1)
+ || (asprintf(&printername, "%s\\%s", servername, printer) == -1)) {
+ DEBUG(3, ("Insufficient memory\n"));
+ return WERR_NOMEM;
+ }
+
+ result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
+ "", MAXIMUM_ALLOWED_ACCESS,
+ servername, cli->auth->user_name,
+ &pol);
+ if (!W_ERROR_IS_OK(result)) {
+ DEBUG(3, ("Unable to open printer %s, error is %s.\n",
+ printername, dos_errstr(result)));
+ return result;
+ }
+
+ if ( !(dsdriver_ctr = TALLOC_ZERO_P( mem_ctx, REGVAL_CTR )) )
+ return WERR_NOMEM;
+
+ result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &pol, SPOOL_DSDRIVER_KEY, dsdriver_ctr);
+
+ if (!W_ERROR_IS_OK(result)) {
+ DEBUG(3, ("Unable to do enumdataex on %s, error is %s.\n",
+ printername, dos_errstr(result)));
+ } else {
+ uint32 num_values = regval_ctr_numvals( dsdriver_ctr );
+
+ /* Have the data we need now, so start building */
+ for (i=0; i < num_values; i++) {
+ map_regval_to_ads(mem_ctx, mods, dsdriver_ctr->values[i]);
+ }
+ }
+
+ if ( !(dsspooler_ctr = TALLOC_ZERO_P( mem_ctx, REGVAL_CTR )) )
+ return WERR_NOMEM;
+
+ result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &pol, SPOOL_DSSPOOLER_KEY, dsspooler_ctr);
+
+ if (!W_ERROR_IS_OK(result)) {
+ DEBUG(3, ("Unable to do enumdataex on %s, error is %s.\n",
+ printername, dos_errstr(result)));
+ } else {
+ uint32 num_values = regval_ctr_numvals( dsspooler_ctr );
+
+ for (i=0; i<num_values; i++) {
+ map_regval_to_ads(mem_ctx, mods, dsspooler_ctr->values[i]);
+ }
+ }
+
+ ads_mod_str(mem_ctx, mods, SPOOL_REG_PRINTERNAME, printer);
+
+ TALLOC_FREE( dsdriver_ctr );
+ TALLOC_FREE( dsspooler_ctr );
+
+ rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
+
+ return result;
+}
+
+bool get_local_printer_publishing_data(TALLOC_CTX *mem_ctx,
+ ADS_MODLIST *mods,
+ NT_PRINTER_DATA *data)
+{
+ uint32 key,val;
+
+ for (key=0; key < data->num_keys; key++) {
+ REGVAL_CTR *ctr = data->keys[key].values;
+ for (val=0; val < ctr->num_values; val++)
+ map_regval_to_ads(mem_ctx, mods, ctr->values[val]);
+ }
+ return True;
+}
+
+#endif
diff --git a/source3/libads/ldap_schema.c b/source3/libads/ldap_schema.c
new file mode 100644
index 0000000000..ff41ccc861
--- /dev/null
+++ b/source3/libads/ldap_schema.c
@@ -0,0 +1,384 @@
+/*
+ Unix SMB/CIFS implementation.
+ ads (active directory) utility library
+ Copyright (C) Guenther Deschner 2005-2007
+ Copyright (C) Gerald (Jerry) Carter 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_LDAP
+
+ADS_STATUS ads_get_attrnames_by_oids(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ const char *schema_path,
+ const char **OIDs, size_t num_OIDs,
+ char ***OIDs_out, char ***names, size_t *count)
+{
+ ADS_STATUS status;
+ LDAPMessage *res = NULL;
+ LDAPMessage *msg;
+ char *expr = NULL;
+ const char *attrs[] = { "lDAPDisplayName", "attributeId", NULL };
+ int i = 0, p = 0;
+
+ if (!ads || !mem_ctx || !names || !count || !OIDs || !OIDs_out) {
+ return ADS_ERROR(LDAP_PARAM_ERROR);
+ }
+
+ if (num_OIDs == 0 || OIDs[0] == NULL) {
+ return ADS_ERROR_NT(NT_STATUS_NONE_MAPPED);
+ }
+
+ if ((expr = talloc_asprintf(mem_ctx, "(|")) == NULL) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ for (i=0; i<num_OIDs; i++) {
+
+ if ((expr = talloc_asprintf_append_buffer(expr, "(attributeId=%s)",
+ OIDs[i])) == NULL) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ }
+
+ if ((expr = talloc_asprintf_append_buffer(expr, ")")) == NULL) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ status = ads_do_search_retry(ads, schema_path,
+ LDAP_SCOPE_SUBTREE, expr, attrs, &res);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ *count = ads_count_replies(ads, res);
+ if (*count == 0 || !res) {
+ status = ADS_ERROR_NT(NT_STATUS_NONE_MAPPED);
+ goto out;
+ }
+
+ if (((*names) = TALLOC_ARRAY(mem_ctx, char *, *count)) == NULL) {
+ status = ADS_ERROR(LDAP_NO_MEMORY);
+ goto out;
+ }
+ if (((*OIDs_out) = TALLOC_ARRAY(mem_ctx, char *, *count)) == NULL) {
+ status = ADS_ERROR(LDAP_NO_MEMORY);
+ goto out;
+ }
+
+ for (msg = ads_first_entry(ads, res); msg != NULL;
+ msg = ads_next_entry(ads, msg)) {
+
+ (*names)[p] = ads_pull_string(ads, mem_ctx, msg,
+ "lDAPDisplayName");
+ (*OIDs_out)[p] = ads_pull_string(ads, mem_ctx, msg,
+ "attributeId");
+ if (((*names)[p] == NULL) || ((*OIDs_out)[p] == NULL)) {
+ status = ADS_ERROR(LDAP_NO_MEMORY);
+ goto out;
+ }
+
+ p++;
+ }
+
+ if (*count < num_OIDs) {
+ status = ADS_ERROR_NT(STATUS_SOME_UNMAPPED);
+ goto out;
+ }
+
+ status = ADS_ERROR(LDAP_SUCCESS);
+out:
+ ads_msgfree(ads, res);
+
+ return status;
+}
+
+const char *ads_get_attrname_by_guid(ADS_STRUCT *ads,
+ const char *schema_path,
+ TALLOC_CTX *mem_ctx,
+ const struct GUID *schema_guid)
+{
+ ADS_STATUS rc;
+ LDAPMessage *res = NULL;
+ char *expr = NULL;
+ const char *attrs[] = { "lDAPDisplayName", NULL };
+ const char *result = NULL;
+ char *guid_bin = NULL;
+
+ if (!ads || !mem_ctx || !schema_guid) {
+ goto done;
+ }
+
+ guid_bin = guid_binstring(schema_guid);
+ if (!guid_bin) {
+ goto done;
+ }
+
+ expr = talloc_asprintf(mem_ctx, "(schemaIDGUID=%s)", guid_bin);
+ if (!expr) {
+ goto done;
+ }
+
+ rc = ads_do_search_retry(ads, schema_path, LDAP_SCOPE_SUBTREE,
+ expr, attrs, &res);
+ if (!ADS_ERR_OK(rc)) {
+ goto done;
+ }
+
+ if (ads_count_replies(ads, res) != 1) {
+ goto done;
+ }
+
+ result = ads_pull_string(ads, mem_ctx, res, "lDAPDisplayName");
+
+ done:
+ SAFE_FREE(guid_bin);
+ ads_msgfree(ads, res);
+ return result;
+
+}
+
+const char *ads_get_attrname_by_oid(ADS_STRUCT *ads, const char *schema_path, TALLOC_CTX *mem_ctx, const char * OID)
+{
+ ADS_STATUS rc;
+ int count = 0;
+ LDAPMessage *res = NULL;
+ char *expr = NULL;
+ const char *attrs[] = { "lDAPDisplayName", NULL };
+ char *result;
+
+ if (ads == NULL || mem_ctx == NULL || OID == NULL) {
+ goto failed;
+ }
+
+ expr = talloc_asprintf(mem_ctx, "(attributeId=%s)", OID);
+ if (expr == NULL) {
+ goto failed;
+ }
+
+ rc = ads_do_search_retry(ads, schema_path, LDAP_SCOPE_SUBTREE,
+ expr, attrs, &res);
+ if (!ADS_ERR_OK(rc)) {
+ goto failed;
+ }
+
+ count = ads_count_replies(ads, res);
+ if (count == 0 || !res) {
+ goto failed;
+ }
+
+ result = ads_pull_string(ads, mem_ctx, res, "lDAPDisplayName");
+ ads_msgfree(ads, res);
+
+ return result;
+
+failed:
+ DEBUG(0,("ads_get_attrname_by_oid: failed to retrieve name for oid: %s\n",
+ OID));
+
+ ads_msgfree(ads, res);
+ return NULL;
+}
+/*********************************************************************
+*********************************************************************/
+
+ADS_STATUS ads_schema_path(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char **schema_path)
+{
+ ADS_STATUS status;
+ LDAPMessage *res;
+ const char *schema;
+ const char *attrs[] = { "schemaNamingContext", NULL };
+
+ status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ if ( (schema = ads_pull_string(ads, mem_ctx, res, "schemaNamingContext")) == NULL ) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ }
+
+ if ( (*schema_path = talloc_strdup(mem_ctx, schema)) == NULL ) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ ads_msgfree(ads, res);
+
+ return status;
+}
+
+/**
+ * Check for "Services for Unix" or rfc2307 Schema and load some attributes into the ADS_STRUCT
+ * @param ads connection to ads server
+ * @param enum mapping type
+ * @return ADS_STATUS status of search (False if one or more attributes couldn't be
+ * found in Active Directory)
+ **/
+ADS_STATUS ads_check_posix_schema_mapping(TALLOC_CTX *mem_ctx,
+ ADS_STRUCT *ads,
+ enum wb_posix_mapping map_type,
+ struct posix_schema **s )
+{
+ TALLOC_CTX *ctx = NULL;
+ ADS_STATUS status;
+ char **oids_out, **names_out;
+ size_t num_names;
+ char *schema_path = NULL;
+ int i;
+ struct posix_schema *schema = NULL;
+
+ const char *oids_sfu[] = { ADS_ATTR_SFU_UIDNUMBER_OID,
+ ADS_ATTR_SFU_GIDNUMBER_OID,
+ ADS_ATTR_SFU_HOMEDIR_OID,
+ ADS_ATTR_SFU_SHELL_OID,
+ ADS_ATTR_SFU_GECOS_OID};
+
+ const char *oids_sfu20[] = { ADS_ATTR_SFU20_UIDNUMBER_OID,
+ ADS_ATTR_SFU20_GIDNUMBER_OID,
+ ADS_ATTR_SFU20_HOMEDIR_OID,
+ ADS_ATTR_SFU20_SHELL_OID,
+ ADS_ATTR_SFU20_GECOS_OID};
+
+ const char *oids_rfc2307[] = { ADS_ATTR_RFC2307_UIDNUMBER_OID,
+ ADS_ATTR_RFC2307_GIDNUMBER_OID,
+ ADS_ATTR_RFC2307_HOMEDIR_OID,
+ ADS_ATTR_RFC2307_SHELL_OID,
+ ADS_ATTR_RFC2307_GECOS_OID };
+
+ DEBUG(10,("ads_check_posix_schema_mapping for schema mode: %d\n", map_type));
+
+ switch (map_type) {
+
+ case WB_POSIX_MAP_TEMPLATE:
+ case WB_POSIX_MAP_UNIXINFO:
+ DEBUG(10,("ads_check_posix_schema_mapping: nothing to do\n"));
+ return ADS_ERROR(LDAP_SUCCESS);
+
+ case WB_POSIX_MAP_SFU:
+ case WB_POSIX_MAP_SFU20:
+ case WB_POSIX_MAP_RFC2307:
+ break;
+
+ default:
+ DEBUG(0,("ads_check_posix_schema_mapping: "
+ "unknown enum %d\n", map_type));
+ return ADS_ERROR(LDAP_PARAM_ERROR);
+ }
+
+ if ( (ctx = talloc_init("ads_check_posix_schema_mapping")) == NULL ) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ if ( (schema = TALLOC_P(mem_ctx, struct posix_schema)) == NULL ) {
+ TALLOC_FREE( ctx );
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ status = ads_schema_path(ads, ctx, &schema_path);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(3,("ads_check_posix_mapping: Unable to retrieve schema DN!\n"));
+ goto done;
+ }
+
+ switch (map_type) {
+ case WB_POSIX_MAP_SFU:
+ status = ads_get_attrnames_by_oids(ads, ctx, schema_path, oids_sfu,
+ ARRAY_SIZE(oids_sfu),
+ &oids_out, &names_out, &num_names);
+ break;
+ case WB_POSIX_MAP_SFU20:
+ status = ads_get_attrnames_by_oids(ads, ctx, schema_path, oids_sfu20,
+ ARRAY_SIZE(oids_sfu20),
+ &oids_out, &names_out, &num_names);
+ break;
+ case WB_POSIX_MAP_RFC2307:
+ status = ads_get_attrnames_by_oids(ads, ctx, schema_path, oids_rfc2307,
+ ARRAY_SIZE(oids_rfc2307),
+ &oids_out, &names_out, &num_names);
+ break;
+ default:
+ status = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ break;
+ }
+
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(3,("ads_check_posix_schema_mapping: failed %s\n",
+ ads_errstr(status)));
+ goto done;
+ }
+
+ for (i=0; i<num_names; i++) {
+
+ DEBUGADD(10,("\tOID %s has name: %s\n", oids_out[i], names_out[i]));
+
+ if (strequal(ADS_ATTR_RFC2307_UIDNUMBER_OID, oids_out[i]) ||
+ strequal(ADS_ATTR_SFU_UIDNUMBER_OID, oids_out[i]) ||
+ strequal(ADS_ATTR_SFU20_UIDNUMBER_OID, oids_out[i])) {
+ schema->posix_uidnumber_attr = talloc_strdup(schema, names_out[i]);
+ continue;
+ }
+
+ if (strequal(ADS_ATTR_RFC2307_GIDNUMBER_OID, oids_out[i]) ||
+ strequal(ADS_ATTR_SFU_GIDNUMBER_OID, oids_out[i]) ||
+ strequal(ADS_ATTR_SFU20_GIDNUMBER_OID, oids_out[i])) {
+ schema->posix_gidnumber_attr = talloc_strdup(schema, names_out[i]);
+ continue;
+ }
+
+ if (strequal(ADS_ATTR_RFC2307_HOMEDIR_OID, oids_out[i]) ||
+ strequal(ADS_ATTR_SFU_HOMEDIR_OID, oids_out[i]) ||
+ strequal(ADS_ATTR_SFU20_HOMEDIR_OID, oids_out[i])) {
+ schema->posix_homedir_attr = talloc_strdup(schema, names_out[i]);
+ continue;
+ }
+
+ if (strequal(ADS_ATTR_RFC2307_SHELL_OID, oids_out[i]) ||
+ strequal(ADS_ATTR_SFU_SHELL_OID, oids_out[i]) ||
+ strequal(ADS_ATTR_SFU20_SHELL_OID, oids_out[i])) {
+ schema->posix_shell_attr = talloc_strdup(schema, names_out[i]);
+ continue;
+ }
+
+ if (strequal(ADS_ATTR_RFC2307_GECOS_OID, oids_out[i]) ||
+ strequal(ADS_ATTR_SFU_GECOS_OID, oids_out[i]) ||
+ strequal(ADS_ATTR_SFU20_GECOS_OID, oids_out[i])) {
+ schema->posix_gecos_attr = talloc_strdup(schema, names_out[i]);
+ }
+ }
+
+ if (!schema->posix_uidnumber_attr ||
+ !schema->posix_gidnumber_attr ||
+ !schema->posix_homedir_attr ||
+ !schema->posix_shell_attr ||
+ !schema->posix_gecos_attr) {
+ status = ADS_ERROR(LDAP_NO_MEMORY);
+ TALLOC_FREE( schema );
+ goto done;
+ }
+
+ *s = schema;
+
+ status = ADS_ERROR(LDAP_SUCCESS);
+
+done:
+ TALLOC_FREE(ctx);
+
+ return status;
+}
+
+#endif
diff --git a/source3/libads/ldap_user.c b/source3/libads/ldap_user.c
new file mode 100644
index 0000000000..bef2c91292
--- /dev/null
+++ b/source3/libads/ldap_user.c
@@ -0,0 +1,127 @@
+/*
+ Unix SMB/CIFS implementation.
+ ads (active directory) utility library
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_ADS
+
+/*
+ find a user account
+*/
+ ADS_STATUS ads_find_user_acct(ADS_STRUCT *ads, LDAPMessage **res,
+ const char *user)
+{
+ ADS_STATUS status;
+ char *ldap_exp;
+ const char *attrs[] = {"*", NULL};
+ char *escaped_user = escape_ldap_string_alloc(user);
+ if (!escaped_user) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ asprintf(&ldap_exp, "(samAccountName=%s)", escaped_user);
+ status = ads_search(ads, res, ldap_exp, attrs);
+ SAFE_FREE(ldap_exp);
+ SAFE_FREE(escaped_user);
+ return status;
+}
+
+ADS_STATUS ads_add_user_acct(ADS_STRUCT *ads, const char *user,
+ const char *container, const char *fullname)
+{
+ TALLOC_CTX *ctx;
+ ADS_MODLIST mods;
+ ADS_STATUS status;
+ const char *upn, *new_dn, *name, *controlstr;
+ char *name_escaped = NULL;
+ const char *objectClass[] = {"top", "person", "organizationalPerson",
+ "user", NULL};
+
+ if (fullname && *fullname) name = fullname;
+ else name = user;
+
+ if (!(ctx = talloc_init("ads_add_user_acct")))
+ return ADS_ERROR(LDAP_NO_MEMORY);
+
+ status = ADS_ERROR(LDAP_NO_MEMORY);
+
+ if (!(upn = talloc_asprintf(ctx, "%s@%s", user, ads->config.realm)))
+ goto done;
+ if (!(name_escaped = escape_rdn_val_string_alloc(name)))
+ goto done;
+ if (!(new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", name_escaped, container,
+ ads->config.bind_path)))
+ goto done;
+ if (!(controlstr = talloc_asprintf(ctx, "%u", (UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE))))
+ goto done;
+ if (!(mods = ads_init_mods(ctx)))
+ goto done;
+
+ ads_mod_str(ctx, &mods, "cn", name);
+ ads_mod_strlist(ctx, &mods, "objectClass", objectClass);
+ ads_mod_str(ctx, &mods, "userPrincipalName", upn);
+ ads_mod_str(ctx, &mods, "name", name);
+ ads_mod_str(ctx, &mods, "displayName", name);
+ ads_mod_str(ctx, &mods, "sAMAccountName", user);
+ ads_mod_str(ctx, &mods, "userAccountControl", controlstr);
+ status = ads_gen_add(ads, new_dn, mods);
+
+ done:
+ SAFE_FREE(name_escaped);
+ talloc_destroy(ctx);
+ return status;
+}
+
+ADS_STATUS ads_add_group_acct(ADS_STRUCT *ads, const char *group,
+ const char *container, const char *comment)
+{
+ TALLOC_CTX *ctx;
+ ADS_MODLIST mods;
+ ADS_STATUS status;
+ char *new_dn;
+ char *name_escaped = NULL;
+ const char *objectClass[] = {"top", "group", NULL};
+
+ if (!(ctx = talloc_init("ads_add_group_acct")))
+ return ADS_ERROR(LDAP_NO_MEMORY);
+
+ status = ADS_ERROR(LDAP_NO_MEMORY);
+
+ if (!(name_escaped = escape_rdn_val_string_alloc(group)))
+ goto done;
+ if (!(new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", name_escaped, container,
+ ads->config.bind_path)))
+ goto done;
+ if (!(mods = ads_init_mods(ctx)))
+ goto done;
+
+ ads_mod_str(ctx, &mods, "cn", group);
+ ads_mod_strlist(ctx, &mods, "objectClass",objectClass);
+ ads_mod_str(ctx, &mods, "name", group);
+ if (comment && *comment)
+ ads_mod_str(ctx, &mods, "description", comment);
+ ads_mod_str(ctx, &mods, "sAMAccountName", group);
+ status = ads_gen_add(ads, new_dn, mods);
+
+ done:
+ SAFE_FREE(name_escaped);
+ talloc_destroy(ctx);
+ return status;
+}
+#endif
diff --git a/source3/libads/ldap_utils.c b/source3/libads/ldap_utils.c
new file mode 100644
index 0000000000..871449a81a
--- /dev/null
+++ b/source3/libads/ldap_utils.c
@@ -0,0 +1,373 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Some Helpful wrappers on LDAP
+
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Guenther Deschner 2006,2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_LDAP
+/*
+ a wrapper around ldap_search_s that retries depending on the error code
+ this is supposed to catch dropped connections and auto-reconnect
+*/
+static ADS_STATUS ads_do_search_retry_internal(ADS_STRUCT *ads, const char *bind_path, int scope,
+ const char *expr,
+ const char **attrs, void *args,
+ LDAPMessage **res)
+{
+ ADS_STATUS status = ADS_SUCCESS;
+ int count = 3;
+ char *bp;
+
+ *res = NULL;
+
+ if (!ads->ldap.ld &&
+ time(NULL) - ads->ldap.last_attempt < ADS_RECONNECT_TIME) {
+ return ADS_ERROR(LDAP_SERVER_DOWN);
+ }
+
+ bp = SMB_STRDUP(bind_path);
+
+ if (!bp) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ *res = NULL;
+
+ /* when binding anonymously, we cannot use the paged search LDAP
+ * control - Guenther */
+
+ if (ads->auth.flags & ADS_AUTH_ANON_BIND) {
+ status = ads_do_search(ads, bp, scope, expr, attrs, res);
+ } else {
+ status = ads_do_search_all_args(ads, bp, scope, expr, attrs, args, res);
+ }
+ if (ADS_ERR_OK(status)) {
+ DEBUG(5,("Search for %s in <%s> gave %d replies\n",
+ expr, bp, ads_count_replies(ads, *res)));
+ SAFE_FREE(bp);
+ return status;
+ }
+
+ while (--count) {
+
+ if (*res)
+ ads_msgfree(ads, *res);
+ *res = NULL;
+
+ DEBUG(3,("Reopening ads connection to realm '%s' after error %s\n",
+ ads->config.realm, ads_errstr(status)));
+
+ ads_disconnect(ads);
+ status = ads_connect(ads);
+
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(1,("ads_search_retry: failed to reconnect (%s)\n",
+ ads_errstr(status)));
+ ads_destroy(&ads);
+ SAFE_FREE(bp);
+ return status;
+ }
+
+ *res = NULL;
+
+ /* when binding anonymously, we cannot use the paged search LDAP
+ * control - Guenther */
+
+ if (ads->auth.flags & ADS_AUTH_ANON_BIND) {
+ status = ads_do_search(ads, bp, scope, expr, attrs, res);
+ } else {
+ status = ads_do_search_all_args(ads, bp, scope, expr, attrs, args, res);
+ }
+
+ if (ADS_ERR_OK(status)) {
+ DEBUG(5,("Search for filter: %s, base: %s gave %d replies\n",
+ expr, bp, ads_count_replies(ads, *res)));
+ SAFE_FREE(bp);
+ return status;
+ }
+ }
+ SAFE_FREE(bp);
+
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(1,("ads reopen failed after error %s\n",
+ ads_errstr(status)));
+ }
+ return status;
+}
+
+ ADS_STATUS ads_do_search_retry(ADS_STRUCT *ads, const char *bind_path,
+ int scope, const char *expr,
+ const char **attrs, LDAPMessage **res)
+{
+ return ads_do_search_retry_internal(ads, bind_path, scope, expr, attrs, NULL, res);
+}
+
+ ADS_STATUS ads_do_search_retry_args(ADS_STRUCT *ads, const char *bind_path,
+ int scope, const char *expr,
+ const char **attrs, void *args,
+ LDAPMessage **res)
+{
+ return ads_do_search_retry_internal(ads, bind_path, scope, expr, attrs, args, res);
+}
+
+
+ ADS_STATUS ads_search_retry(ADS_STRUCT *ads, LDAPMessage **res,
+ const char *expr, const char **attrs)
+{
+ return ads_do_search_retry(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE,
+ expr, attrs, res);
+}
+
+ ADS_STATUS ads_search_retry_dn(ADS_STRUCT *ads, LDAPMessage **res,
+ const char *dn,
+ const char **attrs)
+{
+ return ads_do_search_retry(ads, dn, LDAP_SCOPE_BASE,
+ "(objectclass=*)", attrs, res);
+}
+
+ ADS_STATUS ads_search_retry_extended_dn(ADS_STRUCT *ads, LDAPMessage **res,
+ const char *dn,
+ const char **attrs,
+ enum ads_extended_dn_flags flags)
+{
+ ads_control args;
+
+ args.control = ADS_EXTENDED_DN_OID;
+ args.val = flags;
+ args.critical = True;
+
+ return ads_do_search_retry_args(ads, dn, LDAP_SCOPE_BASE,
+ "(objectclass=*)", attrs, &args, res);
+}
+
+ ADS_STATUS ads_search_retry_dn_sd_flags(ADS_STRUCT *ads, LDAPMessage **res,
+ uint32 sd_flags,
+ const char *dn,
+ const char **attrs)
+{
+ ads_control args;
+
+ args.control = ADS_SD_FLAGS_OID;
+ args.val = sd_flags;
+ args.critical = True;
+
+ return ads_do_search_retry_args(ads, dn, LDAP_SCOPE_BASE,
+ "(objectclass=*)", attrs, &args, res);
+}
+
+ ADS_STATUS ads_search_retry_extended_dn_ranged(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ const char *dn,
+ const char **attrs,
+ enum ads_extended_dn_flags flags,
+ char ***strings,
+ size_t *num_strings)
+{
+ ads_control args;
+
+ args.control = ADS_EXTENDED_DN_OID;
+ args.val = flags;
+ args.critical = True;
+
+ /* we can only range process one attribute */
+ if (!attrs || !attrs[0] || attrs[1]) {
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ return ads_ranged_search(ads, mem_ctx, LDAP_SCOPE_BASE, dn,
+ "(objectclass=*)", &args, attrs[0],
+ strings, num_strings);
+
+}
+
+ ADS_STATUS ads_search_retry_sid(ADS_STRUCT *ads, LDAPMessage **res,
+ const DOM_SID *sid,
+ const char **attrs)
+{
+ char *dn, *sid_string;
+ ADS_STATUS status;
+
+ sid_string = sid_binstring_hex(sid);
+ if (sid_string == NULL) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ if (!asprintf(&dn, "<SID=%s>", sid_string)) {
+ SAFE_FREE(sid_string);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ status = ads_do_search_retry(ads, dn, LDAP_SCOPE_BASE,
+ "(objectclass=*)", attrs, res);
+ SAFE_FREE(dn);
+ SAFE_FREE(sid_string);
+ return status;
+}
+
+ADS_STATUS ads_ranged_search(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ int scope,
+ const char *base,
+ const char *filter,
+ void *args,
+ const char *range_attr,
+ char ***strings,
+ size_t *num_strings)
+{
+ ADS_STATUS status;
+ uint32 first_usn;
+ int num_retries = 0;
+ const char **attrs;
+ bool more_values = False;
+
+ *num_strings = 0;
+ *strings = NULL;
+
+ attrs = TALLOC_ARRAY(mem_ctx, const char *, 3);
+ ADS_ERROR_HAVE_NO_MEMORY(attrs);
+
+ attrs[0] = talloc_strdup(mem_ctx, range_attr);
+ attrs[1] = talloc_strdup(mem_ctx, "usnChanged");
+ attrs[2] = NULL;
+
+ ADS_ERROR_HAVE_NO_MEMORY(attrs[0]);
+ ADS_ERROR_HAVE_NO_MEMORY(attrs[1]);
+
+ do {
+ status = ads_ranged_search_internal(ads, mem_ctx,
+ scope, base, filter,
+ attrs, args, range_attr,
+ strings, num_strings,
+ &first_usn, &num_retries,
+ &more_values);
+
+ if (NT_STATUS_EQUAL(STATUS_MORE_ENTRIES, ads_ntstatus(status))) {
+ continue;
+ }
+
+ if (!ADS_ERR_OK(status)) {
+ *num_strings = 0;
+ strings = NULL;
+ goto done;
+ }
+
+ } while (more_values);
+
+ done:
+ DEBUG(10,("returning with %d strings\n", (int)*num_strings));
+
+ return status;
+}
+
+ADS_STATUS ads_ranged_search_internal(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ int scope,
+ const char *base,
+ const char *filter,
+ const char **attrs,
+ void *args,
+ const char *range_attr,
+ char ***strings,
+ size_t *num_strings,
+ uint32 *first_usn,
+ int *num_retries,
+ bool *more_values)
+{
+ LDAPMessage *res = NULL;
+ ADS_STATUS status;
+ int count;
+ uint32 current_usn;
+
+ DEBUG(10, ("Searching for attrs[0] = %s, attrs[1] = %s\n", attrs[0], attrs[1]));
+
+ *more_values = False;
+
+ status = ads_do_search_retry_internal(ads, base, scope, filter, attrs, args, &res);
+
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(1,("ads_search: %s\n",
+ ads_errstr(status)));
+ return status;
+ }
+
+ if (!res) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ count = ads_count_replies(ads, res);
+ if (count == 0) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_SUCCESS);
+ }
+
+ if (*num_strings == 0) {
+ if (!ads_pull_uint32(ads, res, "usnChanged", first_usn)) {
+ DEBUG(1, ("could not pull first usnChanged!\n"));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ }
+
+ if (!ads_pull_uint32(ads, res, "usnChanged", &current_usn)) {
+ DEBUG(1, ("could not pull current usnChanged!\n"));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ if (*first_usn != current_usn) {
+ DEBUG(5, ("USN on this record changed"
+ " - restarting search\n"));
+ if (*num_retries < 5) {
+ (*num_retries)++;
+ *num_strings = 0;
+ ads_msgfree(ads, res);
+ return ADS_ERROR_NT(STATUS_MORE_ENTRIES);
+ } else {
+ DEBUG(5, ("USN on this record changed"
+ " - restarted search too many times, aborting!\n"));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ }
+
+ *strings = ads_pull_strings_range(ads, mem_ctx, res,
+ range_attr,
+ *strings,
+ &attrs[0],
+ num_strings,
+ more_values);
+
+ ads_msgfree(ads, res);
+
+ /* paranoia checks */
+ if (*strings == NULL && *more_values) {
+ DEBUG(0,("no strings found but more values???\n"));
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ if (*num_strings == 0 && *more_values) {
+ DEBUG(0,("no strings found but more values???\n"));
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ return (*more_values) ? ADS_ERROR_NT(STATUS_MORE_ENTRIES) : ADS_ERROR(LDAP_SUCCESS);
+}
+
+#endif
diff --git a/source3/libads/ndr.c b/source3/libads/ndr.c
new file mode 100644
index 0000000000..6324a22041
--- /dev/null
+++ b/source3/libads/ndr.c
@@ -0,0 +1,118 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ debug print helpers
+
+ Copyright (C) Guenther Deschner 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+void ndr_print_ads_auth_flags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ADS_AUTH_DISABLE_KERBEROS", ADS_AUTH_DISABLE_KERBEROS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ADS_AUTH_NO_BIND", ADS_AUTH_NO_BIND, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ADS_AUTH_ANON_BIND", ADS_AUTH_ANON_BIND, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ADS_AUTH_SIMPLE_BIND", ADS_AUTH_SIMPLE_BIND, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ADS_AUTH_ALLOW_NTLMSSP", ADS_AUTH_ALLOW_NTLMSSP, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ADS_AUTH_SASL_SIGN", ADS_AUTH_SASL_SIGN, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ADS_AUTH_SASL_SEAL", ADS_AUTH_SASL_SEAL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ADS_AUTH_SASL_FORCE", ADS_AUTH_SASL_FORCE, r);
+ ndr->depth--;
+}
+
+void ndr_print_ads_struct(struct ndr_print *ndr, const char *name, const struct ads_struct *r)
+{
+ if (!r) { return; }
+
+ ndr_print_struct(ndr, name, "ads_struct");
+ ndr->depth++;
+ ndr_print_bool(ndr, "is_mine", r->is_mine);
+ ndr_print_struct(ndr, name, "server");
+ ndr->depth++;
+ ndr_print_string(ndr, "realm", r->server.realm);
+ ndr_print_string(ndr, "workgroup", r->server.workgroup);
+ ndr_print_string(ndr, "ldap_server", r->server.ldap_server);
+ ndr_print_bool(ndr, "foreign", r->server.foreign);
+ ndr->depth--;
+ ndr_print_struct(ndr, name, "auth");
+ ndr->depth++;
+ ndr_print_string(ndr, "realm", r->auth.realm);
+#ifdef DEBUG_PASSWORD
+ ndr_print_string(ndr, "password", r->auth.password);
+#else
+ ndr_print_string(ndr, "password", "(PASSWORD ommited)");
+#endif
+ ndr_print_string(ndr, "user_name", r->auth.user_name);
+ ndr_print_string(ndr, "kdc_server", r->auth.kdc_server);
+ ndr_print_ads_auth_flags(ndr, "flags", r->auth.flags);
+ ndr_print_uint32(ndr, "time_offset", r->auth.time_offset);
+ ndr_print_time_t(ndr, "tgt_expire", r->auth.tgt_expire);
+ ndr_print_time_t(ndr, "tgs_expire", r->auth.tgs_expire);
+ ndr_print_time_t(ndr, "renewable", r->auth.renewable);
+ ndr->depth--;
+ ndr_print_struct(ndr, name, "config");
+ ndr->depth++;
+ ndr_print_netr_DsR_DcFlags(ndr, "flags", r->config.flags);
+ ndr_print_string(ndr, "realm", r->config.realm);
+ ndr_print_string(ndr, "bind_path", r->config.bind_path);
+ ndr_print_string(ndr, "ldap_server_name", r->config.ldap_server_name);
+ ndr_print_string(ndr, "server_site_name", r->config.server_site_name);
+ ndr_print_string(ndr, "client_site_name", r->config.client_site_name);
+ ndr_print_time_t(ndr, "current_time", r->config.current_time);
+ ndr_print_bool(ndr, "tried_closest_dc", r->config.tried_closest_dc);
+ ndr_print_string(ndr, "schema_path", r->config.schema_path);
+ ndr_print_string(ndr, "config_path", r->config.config_path);
+ ndr->depth--;
+#ifdef HAVE_LDAP
+ ndr_print_struct(ndr, name, "ldap");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "ld", r->ldap.ld);
+ ndr_print_sockaddr_storage(ndr, "ss", &r->ldap.ss);
+ ndr_print_time_t(ndr, "last_attempt", r->ldap.last_attempt);
+ ndr_print_uint32(ndr, "port", r->ldap.port);
+ ndr_print_uint16(ndr, "wrap_type", r->ldap.wrap_type);
+#ifdef HAVE_LDAP_SASL_WRAPPING
+ ndr_print_ptr(ndr, "sbiod", r->ldap.sbiod);
+#endif /* HAVE_LDAP_SASL_WRAPPING */
+ ndr_print_ptr(ndr, "mem_ctx", r->ldap.mem_ctx);
+ ndr_print_ptr(ndr, "wrap_ops", r->ldap.wrap_ops);
+ ndr_print_ptr(ndr, "wrap_private_data", r->ldap.wrap_private_data);
+ ndr_print_struct(ndr, name, "in");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "ofs", r->ldap.in.ofs);
+ ndr_print_uint32(ndr, "needed", r->ldap.in.needed);
+ ndr_print_uint32(ndr, "left", r->ldap.in.left);
+ ndr_print_uint32(ndr, "max_wrapped", r->ldap.in.max_wrapped);
+ ndr_print_uint32(ndr, "min_wrapped", r->ldap.in.min_wrapped);
+ ndr_print_uint32(ndr, "size", r->ldap.in.size);
+ ndr_print_array_uint8(ndr, "buf", r->ldap.in.buf, r->ldap.in.size);
+ ndr->depth--;
+ ndr_print_struct(ndr, name, "out");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "ofs", r->ldap.out.ofs);
+ ndr_print_uint32(ndr, "left", r->ldap.out.left);
+ ndr_print_uint32(ndr, "max_unwrapped", r->ldap.out.max_unwrapped);
+ ndr_print_uint32(ndr, "sig_size", r->ldap.out.sig_size);
+ ndr_print_uint32(ndr, "size", r->ldap.out.size);
+ ndr_print_array_uint8(ndr, "buf", r->ldap.out.buf, r->ldap.out.size);
+ ndr->depth--;
+ ndr->depth--;
+#endif /* HAVE_LDAP */
+ ndr->depth--;
+}
diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c
new file mode 100644
index 0000000000..55bc16a1be
--- /dev/null
+++ b/source3/libads/sasl.c
@@ -0,0 +1,1127 @@
+/*
+ Unix SMB/CIFS implementation.
+ ads sasl code
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_LDAP
+
+static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
+{
+ struct ntlmssp_state *ntlmssp_state =
+ (struct ntlmssp_state *)ads->ldap.wrap_private_data;
+ ADS_STATUS status;
+ NTSTATUS nt_status;
+ DATA_BLOB sig;
+ uint8 *dptr = ads->ldap.out.buf + (4 + NTLMSSP_SIG_SIZE);
+
+ /* copy the data to the right location */
+ memcpy(dptr, buf, len);
+
+ /* create the signature and may encrypt the data */
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
+ nt_status = ntlmssp_seal_packet(ntlmssp_state,
+ dptr, len,
+ dptr, len,
+ &sig);
+ } else {
+ nt_status = ntlmssp_sign_packet(ntlmssp_state,
+ dptr, len,
+ dptr, len,
+ &sig);
+ }
+ status = ADS_ERROR_NT(nt_status);
+ if (!ADS_ERR_OK(status)) return status;
+
+ /* copy the signature to the right location */
+ memcpy(ads->ldap.out.buf + 4,
+ sig.data, NTLMSSP_SIG_SIZE);
+
+ data_blob_free(&sig);
+
+ /* set how many bytes must be written to the underlying socket */
+ ads->ldap.out.left = 4 + NTLMSSP_SIG_SIZE + len;
+
+ return ADS_SUCCESS;
+}
+
+static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
+{
+ struct ntlmssp_state *ntlmssp_state =
+ (struct ntlmssp_state *)ads->ldap.wrap_private_data;
+ ADS_STATUS status;
+ NTSTATUS nt_status;
+ DATA_BLOB sig;
+ uint8 *dptr = ads->ldap.in.buf + (4 + NTLMSSP_SIG_SIZE);
+ uint32 dlen = ads->ldap.in.ofs - (4 + NTLMSSP_SIG_SIZE);
+
+ /* wrap the signature into a DATA_BLOB */
+ sig = data_blob_const(ads->ldap.in.buf + 4, NTLMSSP_SIG_SIZE);
+
+ /* verify the signature and maybe decrypt the data */
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
+ nt_status = ntlmssp_unseal_packet(ntlmssp_state,
+ dptr, dlen,
+ dptr, dlen,
+ &sig);
+ } else {
+ nt_status = ntlmssp_check_packet(ntlmssp_state,
+ dptr, dlen,
+ dptr, dlen,
+ &sig);
+ }
+ status = ADS_ERROR_NT(nt_status);
+ if (!ADS_ERR_OK(status)) return status;
+
+ /* set the amount of bytes for the upper layer and set the ofs to the data */
+ ads->ldap.in.left = dlen;
+ ads->ldap.in.ofs = 4 + NTLMSSP_SIG_SIZE;
+
+ return ADS_SUCCESS;
+}
+
+static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
+{
+ struct ntlmssp_state *ntlmssp_state =
+ (struct ntlmssp_state *)ads->ldap.wrap_private_data;
+
+ ntlmssp_end(&ntlmssp_state);
+
+ ads->ldap.wrap_ops = NULL;
+ ads->ldap.wrap_private_data = NULL;
+}
+
+static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
+ .name = "ntlmssp",
+ .wrap = ads_sasl_ntlmssp_wrap,
+ .unwrap = ads_sasl_ntlmssp_unwrap,
+ .disconnect = ads_sasl_ntlmssp_disconnect
+};
+
+/*
+ perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
+ we fit on one socket??)
+*/
+static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
+{
+ DATA_BLOB msg1 = data_blob_null;
+ DATA_BLOB blob = data_blob_null;
+ DATA_BLOB blob_in = data_blob_null;
+ DATA_BLOB blob_out = data_blob_null;
+ struct berval cred, *scred = NULL;
+ int rc;
+ NTSTATUS nt_status;
+ ADS_STATUS status;
+ int turn = 1;
+ uint32 features = 0;
+
+ struct ntlmssp_state *ntlmssp_state;
+
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
+ return ADS_ERROR_NT(nt_status);
+ }
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
+
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, ads->auth.user_name))) {
+ return ADS_ERROR_NT(nt_status);
+ }
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, ads->auth.realm))) {
+ return ADS_ERROR_NT(nt_status);
+ }
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, ads->auth.password))) {
+ return ADS_ERROR_NT(nt_status);
+ }
+
+ switch (ads->ldap.wrap_type) {
+ case ADS_SASLWRAP_TYPE_SEAL:
+ features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
+ break;
+ case ADS_SASLWRAP_TYPE_SIGN:
+ if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
+ features = NTLMSSP_FEATURE_SIGN;
+ } else {
+ /*
+ * windows servers are broken with sign only,
+ * so we need to use seal here too
+ */
+ features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
+ ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
+ }
+ break;
+ case ADS_SASLWRAP_TYPE_PLAIN:
+ break;
+ }
+
+ ntlmssp_want_feature(ntlmssp_state, features);
+
+ blob_in = data_blob_null;
+
+ do {
+ nt_status = ntlmssp_update(ntlmssp_state,
+ blob_in, &blob_out);
+ data_blob_free(&blob_in);
+ if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
+ || NT_STATUS_IS_OK(nt_status))
+ && blob_out.length) {
+ if (turn == 1) {
+ /* and wrap it in a SPNEGO wrapper */
+ msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
+ } else {
+ /* wrap it in SPNEGO */
+ msg1 = spnego_gen_auth(blob_out);
+ }
+
+ data_blob_free(&blob_out);
+
+ cred.bv_val = (char *)msg1.data;
+ cred.bv_len = msg1.length;
+ scred = NULL;
+ rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
+ data_blob_free(&msg1);
+ if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
+ if (scred) {
+ ber_bvfree(scred);
+ }
+
+ ntlmssp_end(&ntlmssp_state);
+ return ADS_ERROR(rc);
+ }
+ if (scred) {
+ blob = data_blob(scred->bv_val, scred->bv_len);
+ ber_bvfree(scred);
+ } else {
+ blob = data_blob_null;
+ }
+
+ } else {
+
+ ntlmssp_end(&ntlmssp_state);
+ data_blob_free(&blob_out);
+ return ADS_ERROR_NT(nt_status);
+ }
+
+ if ((turn == 1) &&
+ (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
+ DATA_BLOB tmp_blob = data_blob_null;
+ /* the server might give us back two challenges */
+ if (!spnego_parse_challenge(blob, &blob_in,
+ &tmp_blob)) {
+
+ ntlmssp_end(&ntlmssp_state);
+ data_blob_free(&blob);
+ DEBUG(3,("Failed to parse challenges\n"));
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+ data_blob_free(&tmp_blob);
+ } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
+ if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP,
+ &blob_in)) {
+
+ ntlmssp_end(&ntlmssp_state);
+ data_blob_free(&blob);
+ DEBUG(3,("Failed to parse auth response\n"));
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+ }
+ data_blob_free(&blob);
+ data_blob_free(&blob_out);
+ turn++;
+ } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
+
+ /* we have a reference conter on ntlmssp_state, if we are signing
+ then the state will be kept by the signing engine */
+
+ if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
+ ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - NTLMSSP_SIG_SIZE;
+ ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
+ ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
+ ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
+ status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
+ ads_errstr(status)));
+ ntlmssp_end(&ntlmssp_state);
+ return status;
+ }
+ } else {
+ ntlmssp_end(&ntlmssp_state);
+ }
+
+ return ADS_ERROR(rc);
+}
+
+#ifdef HAVE_GSSAPI
+static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
+{
+ gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
+ ADS_STATUS status;
+ int gss_rc;
+ uint32 minor_status;
+ gss_buffer_desc unwrapped, wrapped;
+ int conf_req_flag, conf_state;
+
+ unwrapped.value = buf;
+ unwrapped.length = len;
+
+ /* for now request sign and seal */
+ conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
+
+ gss_rc = gss_wrap(&minor_status, context_handle,
+ conf_req_flag, GSS_C_QOP_DEFAULT,
+ &unwrapped, &conf_state,
+ &wrapped);
+ status = ADS_ERROR_GSS(gss_rc, minor_status);
+ if (!ADS_ERR_OK(status)) return status;
+
+ if (conf_req_flag && conf_state == 0) {
+ return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
+ }
+
+ if ((ads->ldap.out.size - 4) < wrapped.length) {
+ return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
+ }
+
+ /* copy the wrapped blob to the right location */
+ memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
+
+ /* set how many bytes must be written to the underlying socket */
+ ads->ldap.out.left = 4 + wrapped.length;
+
+ gss_release_buffer(&minor_status, &wrapped);
+
+ return ADS_SUCCESS;
+}
+
+static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
+{
+ gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
+ ADS_STATUS status;
+ int gss_rc;
+ uint32 minor_status;
+ gss_buffer_desc unwrapped, wrapped;
+ int conf_state;
+
+ wrapped.value = ads->ldap.in.buf + 4;
+ wrapped.length = ads->ldap.in.ofs - 4;
+
+ gss_rc = gss_unwrap(&minor_status, context_handle,
+ &wrapped, &unwrapped,
+ &conf_state, GSS_C_QOP_DEFAULT);
+ status = ADS_ERROR_GSS(gss_rc, minor_status);
+ if (!ADS_ERR_OK(status)) return status;
+
+ if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
+ return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
+ }
+
+ if (wrapped.length < unwrapped.length) {
+ return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
+ }
+
+ /* copy the wrapped blob to the right location */
+ memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
+
+ /* set how many bytes must be written to the underlying socket */
+ ads->ldap.in.left = unwrapped.length;
+ ads->ldap.in.ofs = 4;
+
+ gss_release_buffer(&minor_status, &unwrapped);
+
+ return ADS_SUCCESS;
+}
+
+static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
+{
+ gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
+ uint32 minor_status;
+
+ gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
+
+ ads->ldap.wrap_ops = NULL;
+ ads->ldap.wrap_private_data = NULL;
+}
+
+static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
+ .name = "gssapi",
+ .wrap = ads_sasl_gssapi_wrap,
+ .unwrap = ads_sasl_gssapi_unwrap,
+ .disconnect = ads_sasl_gssapi_disconnect
+};
+
+/*
+ perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
+*/
+static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
+{
+ ADS_STATUS status;
+ bool ok;
+ uint32 minor_status;
+ int gss_rc, rc;
+ gss_OID_desc krb5_mech_type =
+ {9, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
+ gss_OID mech_type = &krb5_mech_type;
+ gss_OID actual_mech_type = GSS_C_NULL_OID;
+ const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
+ gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
+ gss_buffer_desc input_token, output_token;
+ uint32 req_flags, ret_flags;
+ uint32 req_tmp, ret_tmp;
+ DATA_BLOB unwrapped;
+ DATA_BLOB wrapped;
+ struct berval cred, *scred = NULL;
+
+ input_token.value = NULL;
+ input_token.length = 0;
+
+ req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
+ switch (ads->ldap.wrap_type) {
+ case ADS_SASLWRAP_TYPE_SEAL:
+ req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
+ break;
+ case ADS_SASLWRAP_TYPE_SIGN:
+ req_flags |= GSS_C_INTEG_FLAG;
+ break;
+ case ADS_SASLWRAP_TYPE_PLAIN:
+ break;
+ }
+
+ /* Note: here we explicit ask for the krb5 mech_type */
+ gss_rc = gss_init_sec_context(&minor_status,
+ GSS_C_NO_CREDENTIAL,
+ &context_handle,
+ serv_name,
+ mech_type,
+ req_flags,
+ 0,
+ NULL,
+ &input_token,
+ &actual_mech_type,
+ &output_token,
+ &ret_flags,
+ NULL);
+ if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
+ status = ADS_ERROR_GSS(gss_rc, minor_status);
+ goto failed;
+ }
+
+ /*
+ * As some gssapi krb5 mech implementations
+ * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
+ * to req_flags internaly, it's not possible to
+ * use plain or signing only connection via
+ * the gssapi interface.
+ *
+ * Because of this we need to check it the ret_flags
+ * has more flags as req_flags and correct the value
+ * of ads->ldap.wrap_type.
+ *
+ * I ads->auth.flags has ADS_AUTH_SASL_FORCE
+ * we need to give an error.
+ */
+ req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
+ ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
+
+ if (req_tmp == ret_tmp) {
+ /* everythings fine... */
+
+ } else if (req_flags & GSS_C_CONF_FLAG) {
+ /*
+ * here we wanted sealing but didn't got it
+ * from the gssapi library
+ */
+ status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+ goto failed;
+
+ } else if ((req_flags & GSS_C_INTEG_FLAG) &&
+ !(ret_flags & GSS_C_INTEG_FLAG)) {
+ /*
+ * here we wanted siging but didn't got it
+ * from the gssapi library
+ */
+ status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+ goto failed;
+
+ } else if (ret_flags & GSS_C_CONF_FLAG) {
+ /*
+ * here we didn't want sealing
+ * but the gssapi library forces it
+ * so correct the needed wrap_type if
+ * the caller didn't forced siging only
+ */
+ if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
+ status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+ goto failed;
+ }
+
+ ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
+ req_flags = ret_flags;
+
+ } else if (ret_flags & GSS_C_INTEG_FLAG) {
+ /*
+ * here we didn't want signing
+ * but the gssapi library forces it
+ * so correct the needed wrap_type if
+ * the caller didn't forced plain
+ */
+ if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
+ status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+ goto failed;
+ }
+
+ ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
+ req_flags = ret_flags;
+ } else {
+ /*
+ * This could (should?) not happen
+ */
+ status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
+ goto failed;
+
+ }
+
+ /* and wrap that in a shiny SPNEGO wrapper */
+ unwrapped = data_blob_const(output_token.value, output_token.length);
+ wrapped = gen_negTokenTarg(spnego_mechs, unwrapped);
+ gss_release_buffer(&minor_status, &output_token);
+ if (unwrapped.length > wrapped.length) {
+ status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ goto failed;
+ }
+
+ cred.bv_val = (char *)wrapped.data;
+ cred.bv_len = wrapped.length;
+
+ rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL,
+ &scred);
+ data_blob_free(&wrapped);
+ if (rc != LDAP_SUCCESS) {
+ status = ADS_ERROR(rc);
+ goto failed;
+ }
+
+ if (scred) {
+ wrapped = data_blob_const(scred->bv_val, scred->bv_len);
+ } else {
+ wrapped = data_blob_null;
+ }
+
+ ok = spnego_parse_auth_response(wrapped, NT_STATUS_OK,
+ OID_KERBEROS5_OLD,
+ &unwrapped);
+ if (scred) ber_bvfree(scred);
+ if (!ok) {
+ status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
+ goto failed;
+ }
+
+ input_token.value = unwrapped.data;
+ input_token.length = unwrapped.length;
+
+ /*
+ * As we asked for mutal authentication
+ * we need to pass the servers response
+ * to gssapi
+ */
+ gss_rc = gss_init_sec_context(&minor_status,
+ GSS_C_NO_CREDENTIAL,
+ &context_handle,
+ serv_name,
+ mech_type,
+ req_flags,
+ 0,
+ NULL,
+ &input_token,
+ &actual_mech_type,
+ &output_token,
+ &ret_flags,
+ NULL);
+ data_blob_free(&unwrapped);
+ if (gss_rc) {
+ status = ADS_ERROR_GSS(gss_rc, minor_status);
+ goto failed;
+ }
+
+ gss_release_buffer(&minor_status, &output_token);
+
+ /*
+ * If we the sign and seal options
+ * doesn't match after getting the response
+ * from the server, we don't want to use the connection
+ */
+ req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
+ ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
+
+ if (req_tmp != ret_tmp) {
+ /* everythings fine... */
+ status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
+ goto failed;
+ }
+
+ if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
+ uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
+
+ gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
+ (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
+ GSS_C_QOP_DEFAULT,
+ max_msg_size, &ads->ldap.out.max_unwrapped);
+ if (gss_rc) {
+ status = ADS_ERROR_GSS(gss_rc, minor_status);
+ goto failed;
+ }
+
+ ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
+ ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
+ ads->ldap.in.max_wrapped = max_msg_size;
+ status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
+ ads_errstr(status)));
+ goto failed;
+ }
+ /* make sure we don't free context_handle */
+ context_handle = GSS_C_NO_CONTEXT;
+ }
+
+ status = ADS_SUCCESS;
+
+failed:
+ if (context_handle != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
+ return status;
+}
+
+#endif /* HAVE_GSSAPI */
+
+#ifdef HAVE_KRB5
+struct ads_service_principal {
+ char *string;
+#ifdef HAVE_GSSAPI
+ gss_name_t name;
+#endif
+};
+
+static void ads_free_service_principal(struct ads_service_principal *p)
+{
+ SAFE_FREE(p->string);
+
+#ifdef HAVE_GSSAPI
+ if (p->name) {
+ uint32 minor_status;
+ gss_release_name(&minor_status, &p->name);
+ }
+#endif
+ ZERO_STRUCTP(p);
+}
+
+static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
+ const char *given_principal,
+ struct ads_service_principal *p)
+{
+ ADS_STATUS status;
+#ifdef HAVE_GSSAPI
+ gss_buffer_desc input_name;
+ /* GSS_KRB5_NT_PRINCIPAL_NAME */
+ gss_OID_desc nt_principal =
+ {10, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
+ uint32 minor_status;
+ int gss_rc;
+#endif
+
+ ZERO_STRUCTP(p);
+
+ /* I've seen a child Windows 2000 domain not send
+ the principal name back in the first round of
+ the SASL bind reply. So we guess based on server
+ name and realm. --jerry */
+ /* Also try best guess when we get the w2k8 ignore
+ principal back - gd */
+
+ if (!given_principal ||
+ strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
+
+ status = ads_guess_service_principal(ads, &p->string);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+ } else {
+ p->string = SMB_STRDUP(given_principal);
+ if (!p->string) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ }
+
+#ifdef HAVE_GSSAPI
+ input_name.value = p->string;
+ input_name.length = strlen(p->string);
+
+ gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
+ if (gss_rc) {
+ ads_free_service_principal(p);
+ return ADS_ERROR_GSS(gss_rc, minor_status);
+ }
+#endif
+
+ return ADS_SUCCESS;
+}
+
+/*
+ perform a LDAP/SASL/SPNEGO/KRB5 bind
+*/
+static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
+{
+ DATA_BLOB blob = data_blob_null;
+ struct berval cred, *scred = NULL;
+ DATA_BLOB session_key = data_blob_null;
+ int rc;
+
+ if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
+ return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+ }
+
+ rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0,
+ &ads->auth.tgs_expire);
+
+ if (rc) {
+ return ADS_ERROR_KRB5(rc);
+ }
+
+ /* now send the auth packet and we should be done */
+ cred.bv_val = (char *)blob.data;
+ cred.bv_len = blob.length;
+
+ rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
+
+ data_blob_free(&blob);
+ data_blob_free(&session_key);
+ if(scred)
+ ber_bvfree(scred);
+
+ return ADS_ERROR(rc);
+}
+
+static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
+ struct ads_service_principal *p)
+{
+#ifdef HAVE_GSSAPI
+ /*
+ * we only use the gsskrb5 based implementation
+ * when sasl sign or seal is requested.
+ *
+ * This has the following reasons:
+ * - it's likely that the gssapi krb5 mech implementation
+ * doesn't support to negotiate plain connections
+ * - the ads_sasl_spnego_rawkrb5_bind is more robust
+ * against clock skew errors
+ */
+ if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
+ return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
+ }
+#endif
+ return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
+}
+#endif /* HAVE_KRB5 */
+
+/*
+ this performs a SASL/SPNEGO bind
+*/
+static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
+{
+ struct berval *scred=NULL;
+ int rc, i;
+ ADS_STATUS status;
+ DATA_BLOB blob;
+ char *given_principal = NULL;
+ char *OIDs[ASN1_MAX_OIDS];
+#ifdef HAVE_KRB5
+ bool got_kerberos_mechanism = False;
+#endif
+
+ rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
+
+ if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
+ status = ADS_ERROR(rc);
+ goto failed;
+ }
+
+ blob = data_blob(scred->bv_val, scred->bv_len);
+
+ ber_bvfree(scred);
+
+#if 0
+ file_save("sasl_spnego.dat", blob.data, blob.length);
+#endif
+
+ /* the server sent us the first part of the SPNEGO exchange in the negprot
+ reply */
+ if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) {
+ data_blob_free(&blob);
+ status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
+ goto failed;
+ }
+ data_blob_free(&blob);
+
+ /* make sure the server understands kerberos */
+ for (i=0;OIDs[i];i++) {
+ DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
+#ifdef HAVE_KRB5
+ if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
+ strcmp(OIDs[i], OID_KERBEROS5) == 0) {
+ got_kerberos_mechanism = True;
+ }
+#endif
+ free(OIDs[i]);
+ }
+ DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
+
+#ifdef HAVE_KRB5
+ if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
+ got_kerberos_mechanism)
+ {
+ struct ads_service_principal p;
+
+ status = ads_generate_service_principal(ads, given_principal, &p);
+ SAFE_FREE(given_principal);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ status = ads_sasl_spnego_krb5_bind(ads, &p);
+ if (ADS_ERR_OK(status)) {
+ ads_free_service_principal(&p);
+ return status;
+ }
+
+ DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
+ "calling kinit\n", ads_errstr(status)));
+
+ status = ADS_ERROR_KRB5(ads_kinit_password(ads));
+
+ if (ADS_ERR_OK(status)) {
+ status = ads_sasl_spnego_krb5_bind(ads, &p);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0,("kinit succeeded but "
+ "ads_sasl_spnego_krb5_bind failed: %s\n",
+ ads_errstr(status)));
+ }
+ }
+
+ ads_free_service_principal(&p);
+
+ /* only fallback to NTLMSSP if allowed */
+ if (ADS_ERR_OK(status) ||
+ !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
+ return status;
+ }
+ } else
+#endif
+ {
+ SAFE_FREE(given_principal);
+ }
+
+ /* lets do NTLMSSP ... this has the big advantage that we don't need
+ to sync clocks, and we don't rely on special versions of the krb5
+ library for HMAC_MD4 encryption */
+ return ads_sasl_spnego_ntlmssp_bind(ads);
+
+failed:
+ return status;
+}
+
+#ifdef HAVE_GSSAPI
+#define MAX_GSS_PASSES 3
+
+/* this performs a SASL/gssapi bind
+ we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
+ is very dependent on correctly configured DNS whereas
+ this routine is much less fragile
+ see RFC2078 and RFC2222 for details
+*/
+static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
+{
+ uint32 minor_status;
+ gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
+ gss_OID mech_type = GSS_C_NULL_OID;
+ gss_buffer_desc output_token, input_token;
+ uint32 req_flags, ret_flags;
+ int conf_state;
+ struct berval cred;
+ struct berval *scred = NULL;
+ int i=0;
+ int gss_rc, rc;
+ uint8 *p;
+ uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
+ uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
+ ADS_STATUS status;
+
+ input_token.value = NULL;
+ input_token.length = 0;
+
+ /*
+ * Note: here we always ask the gssapi for sign and seal
+ * as this is negotiated later after the mutal
+ * authentication
+ */
+ req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
+
+ for (i=0; i < MAX_GSS_PASSES; i++) {
+ gss_rc = gss_init_sec_context(&minor_status,
+ GSS_C_NO_CREDENTIAL,
+ &context_handle,
+ serv_name,
+ mech_type,
+ req_flags,
+ 0,
+ NULL,
+ &input_token,
+ NULL,
+ &output_token,
+ &ret_flags,
+ NULL);
+ if (scred) {
+ ber_bvfree(scred);
+ scred = NULL;
+ }
+ if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
+ status = ADS_ERROR_GSS(gss_rc, minor_status);
+ goto failed;
+ }
+
+ cred.bv_val = (char *)output_token.value;
+ cred.bv_len = output_token.length;
+
+ rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
+ &scred);
+ if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
+ status = ADS_ERROR(rc);
+ goto failed;
+ }
+
+ if (output_token.value) {
+ gss_release_buffer(&minor_status, &output_token);
+ }
+
+ if (scred) {
+ input_token.value = scred->bv_val;
+ input_token.length = scred->bv_len;
+ } else {
+ input_token.value = NULL;
+ input_token.length = 0;
+ }
+
+ if (gss_rc == 0) break;
+ }
+
+ gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
+ &conf_state,NULL);
+ if (scred) {
+ ber_bvfree(scred);
+ scred = NULL;
+ }
+ if (gss_rc) {
+ status = ADS_ERROR_GSS(gss_rc, minor_status);
+ goto failed;
+ }
+
+ p = (uint8 *)output_token.value;
+
+#if 0
+ file_save("sasl_gssapi.dat", output_token.value, output_token.length);
+#endif
+
+ if (p) {
+ wrap_type = CVAL(p,0);
+ SCVAL(p,0,0);
+ max_msg_size = RIVAL(p,0);
+ }
+
+ gss_release_buffer(&minor_status, &output_token);
+
+ if (!(wrap_type & ads->ldap.wrap_type)) {
+ /*
+ * the server doesn't supports the wrap
+ * type we want :-(
+ */
+ DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
+ ads->ldap.wrap_type, wrap_type));
+ DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
+ status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+ goto failed;
+ }
+
+ /* 0x58 is the minimum windows accepts */
+ if (max_msg_size < 0x58) {
+ max_msg_size = 0x58;
+ }
+
+ output_token.length = 4;
+ output_token.value = SMB_MALLOC(output_token.length);
+ p = (uint8 *)output_token.value;
+
+ RSIVAL(p,0,max_msg_size);
+ SCVAL(p,0,ads->ldap.wrap_type);
+
+ /*
+ * we used to add sprintf("dn:%s", ads->config.bind_path) here.
+ * but using ads->config.bind_path is the wrong! It should be
+ * the DN of the user object!
+ *
+ * w2k3 gives an error when we send an incorrect DN, but sending nothing
+ * is ok and matches the information flow used in GSS-SPNEGO.
+ */
+
+ gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
+ &output_token, &conf_state,
+ &input_token);
+ if (gss_rc) {
+ status = ADS_ERROR_GSS(gss_rc, minor_status);
+ goto failed;
+ }
+
+ free(output_token.value);
+
+ cred.bv_val = (char *)input_token.value;
+ cred.bv_len = input_token.length;
+
+ rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
+ &scred);
+ gss_release_buffer(&minor_status, &input_token);
+ status = ADS_ERROR(rc);
+ if (!ADS_ERR_OK(status)) {
+ goto failed;
+ }
+
+ if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
+ gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
+ (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
+ GSS_C_QOP_DEFAULT,
+ max_msg_size, &ads->ldap.out.max_unwrapped);
+ if (gss_rc) {
+ status = ADS_ERROR_GSS(gss_rc, minor_status);
+ goto failed;
+ }
+
+ ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
+ ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
+ ads->ldap.in.max_wrapped = max_msg_size;
+ status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
+ ads_errstr(status)));
+ goto failed;
+ }
+ /* make sure we don't free context_handle */
+ context_handle = GSS_C_NO_CONTEXT;
+ }
+
+failed:
+
+ if (context_handle != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
+
+ if(scred)
+ ber_bvfree(scred);
+ return status;
+}
+
+static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
+{
+ ADS_STATUS status;
+ struct ads_service_principal p;
+
+ status = ads_generate_service_principal(ads, NULL, &p);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ status = ads_sasl_gssapi_do_bind(ads, p.name);
+ if (ADS_ERR_OK(status)) {
+ ads_free_service_principal(&p);
+ return status;
+ }
+
+ DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
+ "calling kinit\n", ads_errstr(status)));
+
+ status = ADS_ERROR_KRB5(ads_kinit_password(ads));
+
+ if (ADS_ERR_OK(status)) {
+ status = ads_sasl_gssapi_do_bind(ads, p.name);
+ }
+
+ ads_free_service_principal(&p);
+
+ return status;
+}
+
+#endif /* HAVE_GSSAPI */
+
+/* mapping between SASL mechanisms and functions */
+static struct {
+ const char *name;
+ ADS_STATUS (*fn)(ADS_STRUCT *);
+} sasl_mechanisms[] = {
+ {"GSS-SPNEGO", ads_sasl_spnego_bind},
+#ifdef HAVE_GSSAPI
+ {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
+#endif
+ {NULL, NULL}
+};
+
+ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
+{
+ const char *attrs[] = {"supportedSASLMechanisms", NULL};
+ char **values;
+ ADS_STATUS status;
+ int i, j;
+ LDAPMessage *res;
+
+ /* get a list of supported SASL mechanisms */
+ status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
+ if (!ADS_ERR_OK(status)) return status;
+
+ values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
+
+ if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
+ ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
+ } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
+ ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
+ } else {
+ ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
+ }
+
+ /* try our supported mechanisms in order */
+ for (i=0;sasl_mechanisms[i].name;i++) {
+ /* see if the server supports it */
+ for (j=0;values && values[j];j++) {
+ if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
+ DEBUG(4,("Found SASL mechanism %s\n", values[j]));
+ status = sasl_mechanisms[i].fn(ads);
+ ldap_value_free(values);
+ ldap_msgfree(res);
+ return status;
+ }
+ }
+ }
+
+ ldap_value_free(values);
+ ldap_msgfree(res);
+ return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
+}
+
+#endif /* HAVE_LDAP */
+
diff --git a/source3/libads/sasl_wrapping.c b/source3/libads/sasl_wrapping.c
new file mode 100644
index 0000000000..2bfa079235
--- /dev/null
+++ b/source3/libads/sasl_wrapping.c
@@ -0,0 +1,312 @@
+/*
+ Unix SMB/CIFS implementation.
+ ads sasl wrapping code
+ Copyright (C) Stefan Metzmacher 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_LDAP_SASL_WRAPPING
+
+static int ads_saslwrap_setup(Sockbuf_IO_Desc *sbiod, void *arg)
+{
+ ADS_STRUCT *ads = (ADS_STRUCT *)arg;
+
+ ads->ldap.sbiod = sbiod;
+
+ sbiod->sbiod_pvt = ads;
+
+ return 0;
+}
+
+static int ads_saslwrap_remove(Sockbuf_IO_Desc *sbiod)
+{
+ return 0;
+}
+
+static ber_slen_t ads_saslwrap_prepare_inbuf(ADS_STRUCT *ads)
+{
+ ads->ldap.in.ofs = 0;
+ ads->ldap.in.needed = 0;
+ ads->ldap.in.left = 0;
+ ads->ldap.in.size = 4 + ads->ldap.in.min_wrapped;
+ ads->ldap.in.buf = talloc_array(ads->ldap.mem_ctx,
+ uint8, ads->ldap.in.size);
+ if (!ads->ldap.in.buf) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static ber_slen_t ads_saslwrap_grow_inbuf(ADS_STRUCT *ads)
+{
+ if (ads->ldap.in.size == (4 + ads->ldap.in.needed)) {
+ return 0;
+ }
+
+ ads->ldap.in.size = 4 + ads->ldap.in.needed;
+ ads->ldap.in.buf = talloc_realloc(ads->ldap.mem_ctx,
+ ads->ldap.in.buf,
+ uint8, ads->ldap.in.size);
+ if (!ads->ldap.in.buf) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static void ads_saslwrap_shrink_inbuf(ADS_STRUCT *ads)
+{
+ talloc_free(ads->ldap.in.buf);
+
+ ads->ldap.in.buf = NULL;
+ ads->ldap.in.size = 0;
+ ads->ldap.in.ofs = 0;
+ ads->ldap.in.needed = 0;
+ ads->ldap.in.left = 0;
+}
+
+static ber_slen_t ads_saslwrap_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+ ADS_STRUCT *ads = (ADS_STRUCT *)sbiod->sbiod_pvt;
+ ber_slen_t ret;
+
+ /* If ofs < 4 it means we don't have read the length header yet */
+ if (ads->ldap.in.ofs < 4) {
+ ret = ads_saslwrap_prepare_inbuf(ads);
+ if (ret < 0) return ret;
+
+ ret = LBER_SBIOD_READ_NEXT(sbiod,
+ ads->ldap.in.buf + ads->ldap.in.ofs,
+ 4 - ads->ldap.in.ofs);
+ if (ret <= 0) return ret;
+ ads->ldap.in.ofs += ret;
+
+ if (ads->ldap.in.ofs < 4) goto eagain;
+
+ ads->ldap.in.needed = RIVAL(ads->ldap.in.buf, 0);
+ if (ads->ldap.in.needed > ads->ldap.in.max_wrapped) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (ads->ldap.in.needed < ads->ldap.in.min_wrapped) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = ads_saslwrap_grow_inbuf(ads);
+ if (ret < 0) return ret;
+ }
+
+ /*
+ * if there's more data needed from the remote end,
+ * we need to read more
+ */
+ if (ads->ldap.in.needed > 0) {
+ ret = LBER_SBIOD_READ_NEXT(sbiod,
+ ads->ldap.in.buf + ads->ldap.in.ofs,
+ ads->ldap.in.needed);
+ if (ret <= 0) return ret;
+ ads->ldap.in.ofs += ret;
+ ads->ldap.in.needed -= ret;
+
+ if (ads->ldap.in.needed > 0) goto eagain;
+ }
+
+ /*
+ * if we have a complete packet and have not yet unwrapped it
+ * we need to call the mech specific unwrap() hook
+ */
+ if (ads->ldap.in.needed == 0 && ads->ldap.in.left == 0) {
+ ADS_STATUS status;
+ status = ads->ldap.wrap_ops->unwrap(ads);
+ if (!ADS_ERR_OK(status)) {
+ errno = EACCES;
+ return -1;
+ }
+ }
+
+ /*
+ * if we have unwrapped data give it to the caller
+ */
+ if (ads->ldap.in.left > 0) {
+ ret = MIN(ads->ldap.in.left, len);
+ memcpy(buf, ads->ldap.in.buf + ads->ldap.in.ofs, ret);
+ ads->ldap.in.ofs += ret;
+ ads->ldap.in.left -= ret;
+
+ /*
+ * if no more is left shrink the inbuf,
+ * this will trigger reading a new SASL packet
+ * from the remote stream in the next call
+ */
+ if (ads->ldap.in.left == 0) {
+ ads_saslwrap_shrink_inbuf(ads);
+ }
+
+ return ret;
+ }
+
+ /*
+ * if we don't have anything for the caller yet,
+ * tell him to ask again
+ */
+eagain:
+ errno = EAGAIN;
+ return -1;
+}
+
+static ber_slen_t ads_saslwrap_prepare_outbuf(ADS_STRUCT *ads, uint32 len)
+{
+ ads->ldap.out.ofs = 0;
+ ads->ldap.out.left = 0;
+ ads->ldap.out.size = 4 + ads->ldap.out.sig_size + len;
+ ads->ldap.out.buf = talloc_array(ads->ldap.mem_ctx,
+ uint8, ads->ldap.out.size);
+ if (!ads->ldap.out.buf) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static void ads_saslwrap_shrink_outbuf(ADS_STRUCT *ads)
+{
+ talloc_free(ads->ldap.out.buf);
+
+ ads->ldap.out.buf = NULL;
+ ads->ldap.out.size = 0;
+ ads->ldap.out.ofs = 0;
+ ads->ldap.out.left = 0;
+}
+
+static ber_slen_t ads_saslwrap_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+ ADS_STRUCT *ads = (ADS_STRUCT *)sbiod->sbiod_pvt;
+ ber_slen_t ret, rlen;
+
+ /* if the buffer is empty, we need to wrap in incoming buffer */
+ if (ads->ldap.out.left == 0) {
+ ADS_STATUS status;
+
+ if (len == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ rlen = MIN(len, ads->ldap.out.max_unwrapped);
+
+ ret = ads_saslwrap_prepare_outbuf(ads, rlen);
+ if (ret < 0) return ret;
+
+ status = ads->ldap.wrap_ops->wrap(ads, (uint8 *)buf, rlen);
+ if (!ADS_ERR_OK(status)) {
+ errno = EACCES;
+ return -1;
+ }
+
+ RSIVAL(ads->ldap.out.buf, 0, ads->ldap.out.left - 4);
+ } else {
+ rlen = -1;
+ }
+
+ ret = LBER_SBIOD_WRITE_NEXT(sbiod,
+ ads->ldap.out.buf + ads->ldap.out.ofs,
+ ads->ldap.out.left);
+ if (ret <= 0) return ret;
+ ads->ldap.out.ofs += ret;
+ ads->ldap.out.left -= ret;
+
+ if (ads->ldap.out.left == 0) {
+ ads_saslwrap_shrink_outbuf(ads);
+ }
+
+ if (rlen > 0) return rlen;
+
+ errno = EAGAIN;
+ return -1;
+}
+
+static int ads_saslwrap_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
+{
+ ADS_STRUCT *ads = (ADS_STRUCT *)sbiod->sbiod_pvt;
+ int ret;
+
+ switch (opt) {
+ case LBER_SB_OPT_DATA_READY:
+ if (ads->ldap.in.left > 0) {
+ return 1;
+ }
+ ret = LBER_SBIOD_CTRL_NEXT(sbiod, opt, arg);
+ break;
+ default:
+ ret = LBER_SBIOD_CTRL_NEXT(sbiod, opt, arg);
+ break;
+ }
+
+ return ret;
+}
+
+static int ads_saslwrap_close(Sockbuf_IO_Desc *sbiod)
+{
+ return 0;
+}
+
+static const Sockbuf_IO ads_saslwrap_sockbuf_io = {
+ ads_saslwrap_setup, /* sbi_setup */
+ ads_saslwrap_remove, /* sbi_remove */
+ ads_saslwrap_ctrl, /* sbi_ctrl */
+ ads_saslwrap_read, /* sbi_read */
+ ads_saslwrap_write, /* sbi_write */
+ ads_saslwrap_close /* sbi_close */
+};
+
+ADS_STATUS ads_setup_sasl_wrapping(ADS_STRUCT *ads,
+ const struct ads_saslwrap_ops *ops,
+ void *private_data)
+{
+ ADS_STATUS status;
+ Sockbuf *sb;
+ Sockbuf_IO *io = discard_const_p(Sockbuf_IO, &ads_saslwrap_sockbuf_io);
+ int rc;
+
+ rc = ldap_get_option(ads->ldap.ld, LDAP_OPT_SOCKBUF, &sb);
+ status = ADS_ERROR_LDAP(rc);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ /* setup the real wrapping callbacks */
+ rc = ber_sockbuf_add_io(sb, io, LBER_SBIOD_LEVEL_TRANSPORT, ads);
+ status = ADS_ERROR_LDAP(rc);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ ads->ldap.wrap_ops = ops;
+ ads->ldap.wrap_private_data = private_data;
+
+ return ADS_SUCCESS;
+}
+#else
+ADS_STATUS ads_setup_sasl_wrapping(ADS_STRUCT *ads,
+ const struct ads_saslwrap_ops *ops,
+ void *private_data)
+{
+ return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+}
+#endif /* HAVE_LDAP_SASL_WRAPPING */
diff --git a/source3/libads/util.c b/source3/libads/util.c
new file mode 100644
index 0000000000..72f5dee80c
--- /dev/null
+++ b/source3/libads/util.c
@@ -0,0 +1,113 @@
+/*
+ Unix SMB/CIFS implementation.
+ krb5 set password implementation
+ Copyright (C) Remus Koos 2001 (remuskoos@yahoo.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_KRB5
+
+ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_principal)
+{
+ char *password;
+ char *new_password;
+ ADS_STATUS ret;
+ uint32 sec_channel_type;
+
+ if ((password = secrets_fetch_machine_password(lp_workgroup(), NULL, &sec_channel_type)) == NULL) {
+ DEBUG(1,("Failed to retrieve password for principal %s\n", host_principal));
+ return ADS_ERROR_SYSTEM(ENOENT);
+ }
+
+ new_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
+
+ ret = kerberos_set_password(ads->auth.kdc_server, host_principal, password, host_principal, new_password, ads->auth.time_offset);
+
+ if (!ADS_ERR_OK(ret)) {
+ goto failed;
+ }
+
+ if (!secrets_store_machine_password(new_password, lp_workgroup(), sec_channel_type)) {
+ DEBUG(1,("Failed to save machine password\n"));
+ ret = ADS_ERROR_SYSTEM(EACCES);
+ goto failed;
+ }
+
+failed:
+ SAFE_FREE(password);
+ return ret;
+}
+
+ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
+ char **returned_principal)
+{
+ char *princ = NULL;
+
+ if (ads->server.realm && ads->server.ldap_server) {
+ char *server, *server_realm;
+
+ server = SMB_STRDUP(ads->server.ldap_server);
+ server_realm = SMB_STRDUP(ads->server.realm);
+
+ if (!server || !server_realm) {
+ SAFE_FREE(server);
+ SAFE_FREE(server_realm);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ strlower_m(server);
+ strupper_m(server_realm);
+ asprintf(&princ, "ldap/%s@%s", server, server_realm);
+
+ SAFE_FREE(server);
+ SAFE_FREE(server_realm);
+
+ if (!princ) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ } else if (ads->config.realm && ads->config.ldap_server_name) {
+ char *server, *server_realm;
+
+ server = SMB_STRDUP(ads->config.ldap_server_name);
+ server_realm = SMB_STRDUP(ads->config.realm);
+
+ if (!server || !server_realm) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ strlower_m(server);
+ strupper_m(server_realm);
+ asprintf(&princ, "ldap/%s@%s", server, server_realm);
+
+ SAFE_FREE(server);
+ SAFE_FREE(server_realm);
+
+ if (!princ) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ }
+
+ if (!princ) {
+ return ADS_ERROR(LDAP_PARAM_ERROR);
+ }
+
+ *returned_principal = princ;
+
+ return ADS_SUCCESS;
+}
+
+#endif
diff --git a/source3/libcli/nbt/libnbt.h b/source3/libcli/nbt/libnbt.h
new file mode 100644
index 0000000000..d37a17c192
--- /dev/null
+++ b/source3/libcli/nbt/libnbt.h
@@ -0,0 +1,353 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ a raw async NBT library
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __LIBNBT_H__
+#define __LIBNBT_H__
+
+#include "librpc/gen_ndr/nbt.h"
+#include "librpc/ndr/libndr.h"
+
+/*
+ possible states for pending requests
+*/
+enum nbt_request_state {NBT_REQUEST_SEND,
+ NBT_REQUEST_WAIT,
+ NBT_REQUEST_DONE,
+ NBT_REQUEST_TIMEOUT,
+ NBT_REQUEST_ERROR};
+
+/*
+ a nbt name request
+*/
+struct nbt_name_request {
+ struct nbt_name_request *next, *prev;
+
+ enum nbt_request_state state;
+
+ NTSTATUS status;
+
+ /* the socket this was on */
+ struct nbt_name_socket *nbtsock;
+
+ /* where to send the request */
+ struct socket_address *dest;
+
+ /* timeout between retries */
+ int timeout;
+
+ /* how many retries to send on timeout */
+ int num_retries;
+
+ /* whether we have received a WACK */
+ bool received_wack;
+
+ /* the timeout event */
+ struct timed_event *te;
+
+ /* the name transaction id */
+ uint16_t name_trn_id;
+
+ /* is it a reply? */
+ bool is_reply;
+
+ /* the encoded request */
+ DATA_BLOB encoded;
+
+ /* shall we allow multiple replies? */
+ bool allow_multiple_replies;
+
+ unsigned int num_replies;
+ struct nbt_name_reply {
+ struct nbt_name_packet *packet;
+ struct socket_address *dest;
+ } *replies;
+
+ /* information on what to do on completion */
+ struct {
+ void (*fn)(struct nbt_name_request *);
+ void *_private;
+ } async;
+};
+
+
+
+/*
+ context structure for operations on name queries
+*/
+struct nbt_name_socket {
+ struct socket_context *sock;
+ struct event_context *event_ctx;
+/*
+ struct smb_iconv_convenience *iconv_convenience;
+*/
+ /* a queue of requests pending to be sent */
+ struct nbt_name_request *send_queue;
+
+ /* the fd event */
+ struct fd_event *fde;
+
+ /* mapping from name_trn_id to pending event */
+ struct idr_context *idr;
+
+ /* how many requests are waiting for a reply */
+ uint16_t num_pending;
+
+ /* what to do with incoming request packets */
+ struct {
+ void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
+ struct socket_address *);
+ void *_private;
+ } incoming;
+
+ /* what to do with unexpected replies */
+ struct {
+ void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
+ struct socket_address *);
+ void *_private;
+ } unexpected;
+};
+
+
+/* a simple name query */
+struct nbt_name_query {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ bool broadcast;
+ bool wins_lookup;
+ int timeout; /* in seconds */
+ int retries;
+ } in;
+ struct {
+ const char *reply_from;
+ struct nbt_name name;
+ int16_t num_addrs;
+ const char **reply_addrs;
+ } out;
+};
+
+/* a simple name status query */
+struct nbt_name_status {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ int timeout; /* in seconds */
+ int retries;
+ } in;
+ struct {
+ const char *reply_from;
+ struct nbt_name name;
+ struct nbt_rdata_status status;
+ } out;
+};
+
+/* a name registration request */
+struct nbt_name_register {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ const char *address;
+ uint16_t nb_flags;
+ bool register_demand;
+ bool broadcast;
+ bool multi_homed;
+ uint32_t ttl;
+ int timeout; /* in seconds */
+ int retries;
+ } in;
+ struct {
+ const char *reply_from;
+ struct nbt_name name;
+ const char *reply_addr;
+ uint8_t rcode;
+ } out;
+};
+
+/* a send 3 times then demand name broadcast name registration */
+struct nbt_name_register_bcast {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ const char *address;
+ uint16_t nb_flags;
+ uint32_t ttl;
+ } in;
+};
+
+
+/* wins name register with multiple wins servers to try and multiple
+ addresses to register */
+struct nbt_name_register_wins {
+ struct {
+ struct nbt_name name;
+ const char **wins_servers;
+ uint16_t wins_port;
+ const char **addresses;
+ uint16_t nb_flags;
+ uint32_t ttl;
+ } in;
+ struct {
+ const char *wins_server;
+ uint8_t rcode;
+ } out;
+};
+
+
+
+/* a name refresh request */
+struct nbt_name_refresh {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ const char *address;
+ uint16_t nb_flags;
+ bool broadcast;
+ uint32_t ttl;
+ int timeout; /* in seconds */
+ int retries;
+ } in;
+ struct {
+ const char *reply_from;
+ struct nbt_name name;
+ const char *reply_addr;
+ uint8_t rcode;
+ } out;
+};
+
+/* wins name refresh with multiple wins servers to try and multiple
+ addresses to register */
+struct nbt_name_refresh_wins {
+ struct {
+ struct nbt_name name;
+ const char **wins_servers;
+ uint16_t wins_port;
+ const char **addresses;
+ uint16_t nb_flags;
+ uint32_t ttl;
+ } in;
+ struct {
+ const char *wins_server;
+ uint8_t rcode;
+ } out;
+};
+
+
+/* a name release request */
+struct nbt_name_release {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ const char *address;
+ uint16_t nb_flags;
+ bool broadcast;
+ int timeout; /* in seconds */
+ int retries;
+ } in;
+ struct {
+ const char *reply_from;
+ struct nbt_name name;
+ const char *reply_addr;
+ uint8_t rcode;
+ } out;
+};
+
+struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx,
+ struct event_context *event_ctx);
+ /*,
+ struct smb_iconv_convenience *iconv_convenience);*/
+struct nbt_name_request *nbt_name_query_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_query *io);
+NTSTATUS nbt_name_query_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_query *io);
+NTSTATUS nbt_name_query(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_query *io);
+struct nbt_name_request *nbt_name_status_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_status *io);
+NTSTATUS nbt_name_status_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_status *io);
+NTSTATUS nbt_name_status(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_status *io);
+
+NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx, struct nbt_name *name, struct nbt_name *newname);
+NTSTATUS nbt_name_to_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct nbt_name *name);
+NTSTATUS nbt_name_from_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, struct nbt_name *name);
+void nbt_choose_called_name(TALLOC_CTX *mem_ctx, struct nbt_name *n, const char *name, int type);
+char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name);
+NTSTATUS nbt_name_register(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_register *io);
+NTSTATUS nbt_name_refresh(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_refresh *io);
+NTSTATUS nbt_name_release(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_release *io);
+NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_register_wins *io);
+NTSTATUS nbt_name_refresh_wins(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_refresh_wins *io);
+NTSTATUS nbt_name_register_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_register *io);
+struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_register *io);
+NTSTATUS nbt_name_release_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_release *io);
+
+struct nbt_name_request *nbt_name_release_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_release *io);
+
+NTSTATUS nbt_name_refresh_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_refresh *io);
+
+NTSTATUS nbt_set_incoming_handler(struct nbt_name_socket *nbtsock,
+ void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
+ struct socket_address *),
+ void *_private);
+NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock,
+ struct socket_address *dest,
+ struct nbt_name_packet *request);
+
+
+NDR_SCALAR_PROTO(wrepl_nbt_name, const struct nbt_name *);
+NDR_SCALAR_PROTO(nbt_string, const char *);
+NDR_BUFFER_PROTO(nbt_name, struct nbt_name);
+NTSTATUS nbt_rcode_to_ntstatus(uint8_t rcode);
+
+struct composite_context;
+struct composite_context *nbt_name_register_bcast_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_register_bcast *io);
+NTSTATUS nbt_name_register_bcast_recv(struct composite_context *c);
+struct composite_context *nbt_name_register_wins_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_register_wins *io);
+NTSTATUS nbt_name_refresh_wins_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
+ struct nbt_name_refresh_wins *io);
+struct composite_context *nbt_name_refresh_wins_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_refresh_wins *io);
+NTSTATUS nbt_name_register_wins_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
+ struct nbt_name_register_wins *io);
+
+
+#endif /* __LIBNBT_H__ */
diff --git a/source3/libcli/nbt/nbtname.c b/source3/libcli/nbt/nbtname.c
new file mode 100644
index 0000000000..fbb9550655
--- /dev/null
+++ b/source3/libcli/nbt/nbtname.c
@@ -0,0 +1,626 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ manipulate nbt name structures
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ see rfc1002 for the detailed format of compressed names
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+
+/* don't allow an unlimited number of name components */
+#define MAX_COMPONENTS 10
+
+/**
+ print a nbt string
+*/
+_PUBLIC_ void ndr_print_nbt_string(struct ndr_print *ndr, const char *name, const char *s)
+{
+ ndr_print_string(ndr, name, s);
+}
+
+/*
+ pull one component of a nbt_string
+*/
+static enum ndr_err_code ndr_pull_component(struct ndr_pull *ndr,
+ uint8_t **component,
+ uint32_t *offset,
+ uint32_t *max_offset)
+{
+ uint8_t len;
+ uint_t loops = 0;
+ while (loops < 5) {
+ if (*offset >= ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "BAD NBT NAME component");
+ }
+ len = ndr->data[*offset];
+ if (len == 0) {
+ *offset += 1;
+ *max_offset = MAX(*max_offset, *offset);
+ *component = NULL;
+ return NDR_ERR_SUCCESS;
+ }
+ if ((len & 0xC0) == 0xC0) {
+ /* its a label pointer */
+ if (1 + *offset >= ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "BAD NBT NAME component");
+ }
+ *max_offset = MAX(*max_offset, *offset + 2);
+ *offset = ((len&0x3F)<<8) | ndr->data[1 + *offset];
+ *max_offset = MAX(*max_offset, *offset);
+ loops++;
+ continue;
+ }
+ if ((len & 0xC0) != 0) {
+ /* its a reserved length field */
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "BAD NBT NAME component");
+ }
+ if (*offset + len + 2 > ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "BAD NBT NAME component");
+ }
+ *component = (uint8_t*)talloc_strndup(ndr, (const char *)&ndr->data[1 + *offset], len);
+ NDR_ERR_HAVE_NO_MEMORY(*component);
+ *offset += len + 1;
+ *max_offset = MAX(*max_offset, *offset);
+ return NDR_ERR_SUCCESS;
+ }
+
+ /* too many pointers */
+ return ndr_pull_error(ndr, NDR_ERR_STRING, "BAD NBT NAME component");
+}
+
+/**
+ pull a nbt_string from the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_string(struct ndr_pull *ndr, int ndr_flags, const char **s)
+{
+ uint32_t offset = ndr->offset;
+ uint32_t max_offset = offset;
+ unsigned num_components;
+ char *name;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ name = NULL;
+
+ /* break up name into a list of components */
+ for (num_components=0;num_components<MAX_COMPONENTS;num_components++) {
+ uint8_t *component = NULL;
+ NDR_CHECK(ndr_pull_component(ndr, &component, &offset, &max_offset));
+ if (component == NULL) break;
+ if (name) {
+ name = talloc_asprintf_append_buffer(name, ".%s", component);
+ NDR_ERR_HAVE_NO_MEMORY(name);
+ } else {
+ name = (char *)component;
+ }
+ }
+ if (num_components == MAX_COMPONENTS) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "BAD NBT NAME too many components");
+ }
+ if (num_components == 0) {
+ name = talloc_strdup(ndr, "");
+ NDR_ERR_HAVE_NO_MEMORY(name);
+ }
+
+ (*s) = name;
+ ndr->offset = max_offset;
+
+ return NDR_ERR_SUCCESS;
+}
+
+/**
+ push a nbt string to the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_string(struct ndr_push *ndr, int ndr_flags, const char *s)
+{
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ while (s && *s) {
+ enum ndr_err_code ndr_err;
+ char *compname;
+ size_t complen;
+ uint32_t offset;
+
+ /* see if we have pushed the remaing string allready,
+ * if so we use a label pointer to this string
+ */
+ ndr_err = ndr_token_retrieve_cmp_fn(&ndr->nbt_string_list, s, &offset, (comparison_fn_t)strcmp, false);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ uint8_t b[2];
+
+ if (offset > 0x3FFF) {
+ return ndr_push_error(ndr, NDR_ERR_STRING,
+ "offset for nbt string label pointer %u[%08X] > 0x00003FFF",
+ offset, offset);
+ }
+
+ b[0] = 0xC0 | (offset>>8);
+ b[1] = (offset & 0xFF);
+
+ return ndr_push_bytes(ndr, b, 2);
+ }
+
+ complen = strcspn(s, ".");
+
+ /* we need to make sure the length fits into 6 bytes */
+ if (complen >= 0x3F) {
+ return ndr_push_error(ndr, NDR_ERR_STRING,
+ "component length %u[%08X] > 0x00003F",
+ (unsigned)complen, (unsigned)complen);
+ }
+
+ compname = talloc_asprintf(ndr, "%c%*.*s",
+ (unsigned char)complen,
+ (unsigned char)complen,
+ (unsigned char)complen, s);
+ NDR_ERR_HAVE_NO_MEMORY(compname);
+
+ /* remember the current componemt + the rest of the string
+ * so it can be reused later
+ */
+ NDR_CHECK(ndr_token_store(ndr, &ndr->nbt_string_list, s, ndr->offset));
+
+ /* push just this component into the blob */
+ NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)compname, complen+1));
+ talloc_free(compname);
+
+ s += complen;
+ if (*s == '.') s++;
+ }
+
+ /* if we reach the end of the string and have pushed the last component
+ * without using a label pointer, we need to terminate the string
+ */
+ return ndr_push_bytes(ndr, (const uint8_t *)"", 1);
+}
+
+
+/*
+ decompress a 'compressed' name component
+ */
+static bool decompress_name(char *name, enum nbt_name_type *type)
+{
+ int i;
+ for (i=0;name[2*i];i++) {
+ uint8_t c1 = name[2*i];
+ uint8_t c2 = name[1+(2*i)];
+ if (c1 < 'A' || c1 > 'P' ||
+ c2 < 'A' || c2 > 'P') {
+ return false;
+ }
+ name[i] = ((c1-'A')<<4) | (c2-'A');
+ }
+ name[i] = 0;
+ if (i == 16) {
+ *type = (enum nbt_name_type)(name[15]);
+ name[15] = 0;
+ i--;
+ } else {
+ *type = NBT_NAME_CLIENT;
+ }
+
+ /* trim trailing spaces */
+ for (;i>0 && name[i-1]==' ';i--) {
+ name[i-1] = 0;
+ }
+
+ return true;
+}
+
+
+/*
+ compress a name component
+ */
+static uint8_t *compress_name(TALLOC_CTX *mem_ctx,
+ const uint8_t *name, enum nbt_name_type type)
+{
+ uint8_t *cname;
+ int i;
+ uint8_t pad_char;
+
+ if (strlen((const char *)name) > 15) {
+ return NULL;
+ }
+
+ cname = talloc_array(mem_ctx, uint8_t, 33);
+ if (cname == NULL) return NULL;
+
+ for (i=0;name[i];i++) {
+ cname[2*i] = 'A' + (name[i]>>4);
+ cname[1+2*i] = 'A' + (name[i]&0xF);
+ }
+ if (strcmp((const char *)name, "*") == 0) {
+ pad_char = 0;
+ } else {
+ pad_char = ' ';
+ }
+ for (;i<15;i++) {
+ cname[2*i] = 'A' + (pad_char>>4);
+ cname[1+2*i] = 'A' + (pad_char&0xF);
+ }
+
+ pad_char = type;
+ cname[2*i] = 'A' + (pad_char>>4);
+ cname[1+2*i] = 'A' + (pad_char&0xF);
+
+ cname[32] = 0;
+ return cname;
+}
+
+
+/**
+ pull a nbt name from the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_name(struct ndr_pull *ndr, int ndr_flags, struct nbt_name *r)
+{
+ uint8_t *scope;
+ char *cname;
+ const char *s;
+ bool ok;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ NDR_CHECK(ndr_pull_nbt_string(ndr, ndr_flags, &s));
+
+ scope = (uint8_t *)strchr(s, '.');
+ if (scope) {
+ *scope = 0;
+ r->scope = talloc_strdup(ndr->current_mem_ctx, (const char *)&scope[1]);
+ NDR_ERR_HAVE_NO_MEMORY(r->scope);
+ } else {
+ r->scope = NULL;
+ }
+
+ cname = discard_const_p(char, s);
+
+ /* the first component is limited to 16 bytes in the DOS charset,
+ which is 32 in the 'compressed' form */
+ if (strlen(cname) > 32) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "NBT NAME cname > 32");
+ }
+
+ /* decompress the first component */
+ ok = decompress_name(cname, &r->type);
+ if (!ok) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "NBT NAME failed to decompress");
+ }
+
+ r->name = talloc_strdup(ndr->current_mem_ctx, cname);
+ NDR_ERR_HAVE_NO_MEMORY(r->name);
+
+ talloc_free(cname);
+
+ return NDR_ERR_SUCCESS;
+}
+
+/**
+ push a nbt name to the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_name(struct ndr_push *ndr, int ndr_flags, const struct nbt_name *r)
+{
+ uint8_t *cname, *fullname;
+ enum ndr_err_code ndr_err;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (strlen(r->name) > 15) {
+ return ndr_push_error(ndr, NDR_ERR_STRING,
+ "nbt_name longer as 15 chars: %s",
+ r->name);
+ }
+
+ cname = compress_name(ndr, (const uint8_t *)r->name, r->type);
+ NDR_ERR_HAVE_NO_MEMORY(cname);
+
+ if (r->scope) {
+ fullname = (uint8_t *)talloc_asprintf(ndr, "%s.%s", cname, r->scope);
+ NDR_ERR_HAVE_NO_MEMORY(fullname);
+ talloc_free(cname);
+ } else {
+ fullname = cname;
+ }
+
+ ndr_err = ndr_push_nbt_string(ndr, ndr_flags, (const char *)fullname);
+
+ return ndr_err;
+}
+
+
+/**
+ copy a nbt name structure
+*/
+_PUBLIC_ NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx, struct nbt_name *name, struct nbt_name *newname)
+{
+ *newname = *name;
+ newname->name = talloc_strdup(mem_ctx, newname->name);
+ NT_STATUS_HAVE_NO_MEMORY(newname->name);
+ newname->scope = talloc_strdup(mem_ctx, newname->scope);
+ if (name->scope) {
+ NT_STATUS_HAVE_NO_MEMORY(newname->scope);
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ push a nbt name into a blob
+*/
+_PUBLIC_ NTSTATUS nbt_name_to_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct nbt_name *name)
+{
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_push_struct_blob(blob, mem_ctx, name, (ndr_push_flags_fn_t)ndr_push_nbt_name);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ pull a nbt name from a blob
+*/
+_PUBLIC_ NTSTATUS nbt_name_from_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, struct nbt_name *name)
+{
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_pull_struct_blob(blob, mem_ctx, name,
+ (ndr_pull_flags_fn_t)ndr_pull_nbt_name);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/**
+ choose a name to use when calling a server in a NBT session request.
+ we use heuristics to see if the name we have been given is a IP
+ address, or a too-long name. If it is then use *SMBSERVER, or a
+ truncated name
+*/
+_PUBLIC_ void nbt_choose_called_name(TALLOC_CTX *mem_ctx,
+ struct nbt_name *n, const char *name, int type)
+{
+ n->scope = NULL;
+ n->type = type;
+
+ if ((name == NULL) || is_ipaddress(name)) {
+ n->name = "*SMBSERVER";
+ return;
+ }
+ if (strlen(name) > 15) {
+ const char *p = strchr(name, '.');
+ char *s;
+ if (p - name > 15) {
+ n->name = "*SMBSERVER";
+ return;
+ }
+ s = talloc_strndup(mem_ctx, name, PTR_DIFF(p, name));
+ n->name = talloc_strdup_upper(mem_ctx, s);
+ return;
+ }
+
+ n->name = talloc_strdup_upper(mem_ctx, name);
+}
+
+
+/*
+ escape a string into a form containing only a small set of characters,
+ the rest is hex encoded. This is similar to URL encoding
+*/
+static const char *nbt_hex_encode(TALLOC_CTX *mem_ctx, const char *s)
+{
+ int i, len;
+ char *ret;
+ const char *valid_chars = "_-.$@ ";
+#define NBT_CHAR_ALLOW(c) (isalnum((unsigned char)c) || strchr(valid_chars, c))
+
+ for (len=i=0;s[i];i++,len++) {
+ if (!NBT_CHAR_ALLOW(s[i])) {
+ len += 2;
+ }
+ }
+
+ ret = talloc_array(mem_ctx, char, len+1);
+ if (ret == NULL) return NULL;
+
+ for (len=i=0;s[i];i++) {
+ if (NBT_CHAR_ALLOW(s[i])) {
+ ret[len++] = s[i];
+ } else {
+ snprintf(&ret[len], 4, "%%%02x", (unsigned char)s[i]);
+ len += 3;
+ }
+ }
+ ret[len] = 0;
+
+ return ret;
+}
+
+
+/**
+ form a string for a NBT name
+*/
+_PUBLIC_ char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ char *ret;
+ if (name->scope) {
+ ret = talloc_asprintf(mem_ctx, "%s<%02x>-%s",
+ nbt_hex_encode(tmp_ctx, name->name),
+ name->type,
+ nbt_hex_encode(tmp_ctx, name->scope));
+ } else {
+ ret = talloc_asprintf(mem_ctx, "%s<%02x>",
+ nbt_hex_encode(tmp_ctx, name->name),
+ name->type);
+ }
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+/**
+ pull a nbt name, WINS Replication uses another on wire format for nbt name
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_wrepl_nbt_name(struct ndr_pull *ndr, int ndr_flags, const struct nbt_name **_r)
+{
+ struct nbt_name *r;
+ uint8_t *namebuf;
+ uint32_t namebuf_len;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &namebuf_len));
+ if (namebuf_len < 1 || namebuf_len > 255) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "value out of range");
+ }
+ NDR_PULL_ALLOC_N(ndr, namebuf, namebuf_len);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, namebuf, namebuf_len));
+
+ NDR_PULL_ALLOC(ndr, r);
+
+ /* oh wow, what a nasty bug in windows ... */
+ if (namebuf[0] == 0x1b && namebuf_len >= 16) {
+ namebuf[0] = namebuf[15];
+ namebuf[15] = 0x1b;
+ }
+
+ if (namebuf_len < 17) {
+ r->type = 0x00;
+
+ r->name = talloc_strndup(r, (char *)namebuf, namebuf_len);
+ if (!r->name) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory");
+
+ r->scope= NULL;
+
+ talloc_free(namebuf);
+ *_r = r;
+ return NDR_ERR_SUCCESS;
+ }
+
+ r->type = namebuf[15];
+
+ namebuf[15] = '\0';
+ trim_string((char *)namebuf, NULL, " ");
+ r->name = talloc_strdup(r, (char *)namebuf);
+ if (!r->name) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory");
+
+ if (namebuf_len > 18) {
+ r->scope = talloc_strndup(r, (char *)(namebuf+17), namebuf_len-17);
+ if (!r->scope) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory");
+ } else {
+ r->scope = NULL;
+ }
+
+ talloc_free(namebuf);
+ *_r = r;
+ return NDR_ERR_SUCCESS;
+}
+
+/**
+ push a nbt name, WINS Replication uses another on wire format for nbt name
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_wrepl_nbt_name(struct ndr_push *ndr, int ndr_flags, const struct nbt_name *r)
+{
+ uint8_t *namebuf;
+ uint32_t namebuf_len;
+ uint32_t _name_len;
+ uint32_t scope_len = 0;
+
+ if (r == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER,
+ "wrepl_nbt_name NULL pointer");
+ }
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ _name_len = strlen(r->name);
+ if (_name_len > 15) {
+ return ndr_push_error(ndr, NDR_ERR_STRING,
+ "wrepl_nbt_name longer as 15 chars: %s",
+ r->name);
+ }
+
+ if (r->scope) {
+ scope_len = strlen(r->scope);
+ }
+ if (scope_len > 238) {
+ return ndr_push_error(ndr, NDR_ERR_STRING,
+ "wrepl_nbt_name scope longer as 238 chars: %s",
+ r->scope);
+ }
+
+ namebuf = (uint8_t *)talloc_asprintf(ndr, "%-15s%c%s",
+ r->name, 'X',
+ (r->scope?r->scope:""));
+ if (!namebuf) return ndr_push_error(ndr, NDR_ERR_ALLOC, "out of memory");
+
+ namebuf_len = strlen((char *)namebuf) + 1;
+
+ /*
+ * we need to set the type here, and use a place-holder in the talloc_asprintf()
+ * as the type can be 0x00, and then the namebuf_len = strlen(namebuf); would give wrong results
+ */
+ namebuf[15] = r->type;
+
+ /* oh wow, what a nasty bug in windows ... */
+ if (r->type == 0x1b) {
+ namebuf[15] = namebuf[0];
+ namebuf[0] = 0x1b;
+ }
+
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, namebuf_len));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, namebuf, namebuf_len));
+
+ talloc_free(namebuf);
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wrepl_nbt_name(struct ndr_print *ndr, const char *name, const struct nbt_name *r)
+{
+ char *s = nbt_name_string(ndr, r);
+ ndr_print_string(ndr, name, s);
+ talloc_free(s);
+}
diff --git a/source3/libgpo/gpext/gpext.c b/source3/libgpo/gpext/gpext.c
new file mode 100644
index 0000000000..2ae9e2cebf
--- /dev/null
+++ b/source3/libgpo/gpext/gpext.c
@@ -0,0 +1,746 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Support
+ * Copyright (C) Guenther Deschner 2007-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+static struct gp_extension *extensions = NULL;
+
+/****************************************************************
+****************************************************************/
+
+struct gp_extension *get_gp_extension_list(void)
+{
+ return extensions;
+}
+
+/****************************************************************
+****************************************************************/
+
+/* see http://support.microsoft.com/kb/216358/en-us/ for more info */
+
+struct gp_extension_reg_table gpext_reg_vals[] = {
+ { "DllName", REG_EXPAND_SZ },
+ { "ProcessGroupPolicy", REG_SZ },
+ { "NoMachinePolicy", REG_DWORD },
+ { "NoUserPolicy", REG_DWORD },
+ { "NoSlowLink", REG_DWORD },
+ { "NoBackgroundPolicy", REG_DWORD },
+ { "NoGPOListChanges", REG_DWORD },
+ { "PerUserLocalSettings", REG_DWORD },
+ { "RequiresSuccessfulRegistry", REG_DWORD },
+ { "EnableAsynchronousProcessing", REG_DWORD },
+ { "ExtensionDebugLevel", REG_DWORD },
+ /* new */
+ { "GenerateGroupPolicy", REG_SZ }, /* not supported on w2k */
+ { "NotifyLinkTransition", REG_DWORD },
+ { "ProcessGroupPolicyEx", REG_SZ }, /* not supported on w2k */
+ { "ExtensionEventSource", REG_MULTI_SZ }, /* not supported on w2k */
+ { "GenerateGroupPolicy", REG_SZ },
+ { "MaxNoGPOListChangesInterval", REG_DWORD },
+ { NULL, REG_NONE }
+};
+
+/****************************************************************
+****************************************************************/
+
+static struct gp_extension *get_extension_by_name(struct gp_extension *be,
+ const char *name)
+{
+ struct gp_extension *b;
+
+ for (b = be; b; b = b->next) {
+ if (strequal(b->name, name)) {
+ return b;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************
+****************************************************************/
+
+static struct gp_extension_methods *get_methods_by_name(struct gp_extension *be,
+ const char *name)
+{
+ struct gp_extension *b;
+
+ for (b = be; b; b = b->next) {
+ if (strequal(b->name, name)) {
+ return b->methods;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS unregister_gp_extension(const char *name)
+{
+ struct gp_extension *ext;
+
+ ext = get_extension_by_name(extensions, name);
+ if (!ext) {
+ return NT_STATUS_OK;
+ }
+
+ DLIST_REMOVE(extensions, ext);
+ TALLOC_FREE(ext);
+
+ DEBUG(2,("Successfully removed GP extension '%s'\n", name));
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS register_gp_extension(TALLOC_CTX *gpext_ctx,
+ int version,
+ const char *name,
+ const char *guid,
+ struct gp_extension_methods *methods)
+{
+ struct gp_extension_methods *test;
+ struct gp_extension *entry;
+ NTSTATUS status;
+
+ if (!gpext_ctx) {
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ if ((version != SMB_GPEXT_INTERFACE_VERSION)) {
+ DEBUG(0,("Failed to register gp extension.\n"
+ "The module was compiled against "
+ "SMB_GPEXT_INTERFACE_VERSION %d,\n"
+ "current SMB_GPEXT_INTERFACE_VERSION is %d.\n"
+ "Please recompile against the current "
+ "version of samba!\n",
+ version, SMB_GPEXT_INTERFACE_VERSION));
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ if (!guid || !name || !name[0] || !methods) {
+ DEBUG(0,("Called with NULL pointer or empty name!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ test = get_methods_by_name(extensions, name);
+ if (test) {
+ DEBUG(0,("GP extension module %s already registered!\n",
+ name));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ entry = TALLOC_ZERO_P(gpext_ctx, struct gp_extension);
+ NT_STATUS_HAVE_NO_MEMORY(entry);
+
+ entry->name = talloc_strdup(gpext_ctx, name);
+ NT_STATUS_HAVE_NO_MEMORY(entry->name);
+
+ entry->guid = TALLOC_ZERO_P(gpext_ctx, struct GUID);
+ NT_STATUS_HAVE_NO_MEMORY(entry->guid);
+ status = GUID_from_string(guid, entry->guid);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ entry->methods = methods;
+ DLIST_ADD(extensions, entry);
+
+ DEBUG(2,("Successfully added GP extension '%s' %s\n",
+ name, GUID_string2(gpext_ctx, entry->guid)));
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS gp_extension_init_module(TALLOC_CTX *mem_ctx,
+ const char *name,
+ struct gp_extension **gpext)
+{
+ NTSTATUS status;
+ struct gp_extension *ext = NULL;
+
+ ext = TALLOC_ZERO_P(mem_ctx, struct gp_extension);
+ NT_STATUS_HAVE_NO_MEMORY(gpext);
+
+ ext->methods = get_methods_by_name(extensions, name);
+ if (!ext->methods) {
+
+ status = smb_probe_module(SAMBA_SUBSYSTEM_GPEXT,
+ name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ext->methods = get_methods_by_name(extensions, name);
+ if (!ext->methods) {
+ return NT_STATUS_DLL_INIT_FAILED;
+ }
+ }
+
+ *gpext = ext;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool add_gp_extension_reg_entry_to_array(TALLOC_CTX *mem_ctx,
+ struct gp_extension_reg_entry *entry,
+ struct gp_extension_reg_entry **entries,
+ size_t *num)
+{
+ *entries = TALLOC_REALLOC_ARRAY(mem_ctx, *entries,
+ struct gp_extension_reg_entry,
+ (*num)+1);
+ if (*entries == NULL) {
+ *num = 0;
+ return false;
+ }
+
+ (*entries)[*num].value = entry->value;
+ (*entries)[*num].data = entry->data;
+
+ *num += 1;
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool add_gp_extension_reg_info_entry_to_array(TALLOC_CTX *mem_ctx,
+ struct gp_extension_reg_info_entry *entry,
+ struct gp_extension_reg_info_entry **entries,
+ size_t *num)
+{
+ *entries = TALLOC_REALLOC_ARRAY(mem_ctx, *entries,
+ struct gp_extension_reg_info_entry,
+ (*num)+1);
+ if (*entries == NULL) {
+ *num = 0;
+ return false;
+ }
+
+ (*entries)[*num].guid = entry->guid;
+ (*entries)[*num].num_entries = entry->num_entries;
+ (*entries)[*num].entries = entry->entries;
+
+ *num += 1;
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS gp_ext_info_add_reg(TALLOC_CTX *mem_ctx,
+ struct gp_extension_reg_info_entry *entry,
+ const char *value,
+ enum winreg_Type type,
+ const char *data_s)
+{
+ struct gp_extension_reg_entry *reg_entry = NULL;
+ struct registry_value *data = NULL;
+
+ reg_entry = TALLOC_ZERO_P(mem_ctx, struct gp_extension_reg_entry);
+ NT_STATUS_HAVE_NO_MEMORY(reg_entry);
+
+ data = TALLOC_ZERO_P(mem_ctx, struct registry_value);
+ NT_STATUS_HAVE_NO_MEMORY(data);
+
+ data->type = type;
+
+ switch (type) {
+ case REG_SZ:
+ case REG_EXPAND_SZ:
+ data->v.sz.str = talloc_strdup(mem_ctx, data_s);
+ NT_STATUS_HAVE_NO_MEMORY(data->v.sz.str);
+ data->v.sz.len = strlen(data_s);
+ break;
+ case REG_DWORD:
+ data->v.dword = atoi(data_s);
+ break;
+ default:
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ reg_entry->value = value;
+ reg_entry->data = data;
+
+ if (!add_gp_extension_reg_entry_to_array(mem_ctx, reg_entry,
+ &entry->entries,
+ &entry->num_entries)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS gp_ext_info_add_reg_table(TALLOC_CTX *mem_ctx,
+ const char *module,
+ struct gp_extension_reg_info_entry *entry,
+ struct gp_extension_reg_table *table)
+{
+ NTSTATUS status;
+ const char *module_name = NULL;
+ int i;
+
+ module_name = talloc_asprintf(mem_ctx, "%s.%s", module, shlib_ext());
+ NT_STATUS_HAVE_NO_MEMORY(module_name);
+
+ status = gp_ext_info_add_reg(mem_ctx, entry,
+ "DllName", REG_EXPAND_SZ, module_name);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ for (i=0; table[i].val; i++) {
+ status = gp_ext_info_add_reg(mem_ctx, entry,
+ table[i].val,
+ table[i].type,
+ table[i].data);
+ NT_STATUS_NOT_OK_RETURN(status);
+ }
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gp_ext_info_add_entry(TALLOC_CTX *mem_ctx,
+ const char *module,
+ const char *ext_guid,
+ struct gp_extension_reg_table *table,
+ struct gp_extension_reg_info *info)
+{
+ NTSTATUS status;
+ struct gp_extension_reg_info_entry *entry = NULL;
+
+ entry = TALLOC_ZERO_P(mem_ctx, struct gp_extension_reg_info_entry);
+ NT_STATUS_HAVE_NO_MEMORY(entry);
+
+ status = GUID_from_string(ext_guid, &entry->guid);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ status = gp_ext_info_add_reg_table(mem_ctx, module, entry, table);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ if (!add_gp_extension_reg_info_entry_to_array(mem_ctx, entry,
+ &info->entries,
+ &info->num_entries)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool gp_extension_reg_info_verify_entry(struct gp_extension_reg_entry *entry)
+{
+ int i;
+
+ for (i=0; gpext_reg_vals[i].val; i++) {
+
+ if ((strequal(entry->value, gpext_reg_vals[i].val)) &&
+ (entry->data->type == gpext_reg_vals[i].type)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool gp_extension_reg_info_verify(struct gp_extension_reg_info_entry *entry)
+{
+ int i;
+
+ for (i=0; i < entry->num_entries; i++) {
+ if (!gp_extension_reg_info_verify_entry(&entry->entries[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_extension_store_reg_vals(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ struct gp_extension_reg_info_entry *entry)
+{
+ WERROR werr = WERR_OK;
+ size_t i;
+
+ for (i=0; i < entry->num_entries; i++) {
+
+ werr = reg_setvalue(key,
+ entry->entries[i].value,
+ entry->entries[i].data);
+ W_ERROR_NOT_OK_RETURN(werr);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_extension_store_reg_entry(TALLOC_CTX *mem_ctx,
+ struct gp_registry_context *reg_ctx,
+ struct gp_extension_reg_info_entry *entry)
+{
+ WERROR werr;
+ struct registry_key *key = NULL;
+ const char *subkeyname = NULL;
+
+ if (!gp_extension_reg_info_verify(entry)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ subkeyname = GUID_string2(mem_ctx, &entry->guid);
+ W_ERROR_HAVE_NO_MEMORY(subkeyname);
+
+ strupper_m(CONST_DISCARD(char *,subkeyname));
+
+ werr = gp_store_reg_subkey(mem_ctx,
+ subkeyname,
+ reg_ctx->curr_key,
+ &key);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_extension_store_reg_vals(mem_ctx,
+ key,
+ entry);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_extension_store_reg(TALLOC_CTX *mem_ctx,
+ struct gp_registry_context *reg_ctx,
+ struct gp_extension_reg_info *info)
+{
+ WERROR werr = WERR_OK;
+ int i;
+
+ if (!info) {
+ return WERR_OK;
+ }
+
+ for (i=0; i < info->num_entries; i++) {
+ werr = gp_extension_store_reg_entry(mem_ctx,
+ reg_ctx,
+ &info->entries[i]);
+ W_ERROR_NOT_OK_RETURN(werr);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS gp_glob_ext_list(TALLOC_CTX *mem_ctx,
+ const char ***ext_list,
+ size_t *ext_list_len)
+{
+ SMB_STRUCT_DIR *dir = NULL;
+ SMB_STRUCT_DIRENT *dirent = NULL;
+
+ dir = sys_opendir(modules_path(SAMBA_SUBSYSTEM_GPEXT));
+ if (!dir) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ while ((dirent = sys_readdir(dir))) {
+
+ fstring name; /* forgive me... */
+ char *p;
+
+ if ((strequal(dirent->d_name, ".")) ||
+ (strequal(dirent->d_name, ".."))) {
+ continue;
+ }
+
+ p = strrchr(dirent->d_name, '.');
+ if (!p) {
+ sys_closedir(dir);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!strcsequal(p+1, shlib_ext())) {
+ DEBUG(10,("gp_glob_ext_list: not a *.so file: %s\n",
+ dirent->d_name));
+ continue;
+ }
+
+ fstrcpy(name, dirent->d_name);
+ name[PTR_DIFF(p, dirent->d_name)] = 0;
+
+ if (!add_string_to_array(mem_ctx, name, ext_list,
+ (int *)ext_list_len)) {
+ sys_closedir(dir);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ sys_closedir(dir);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS shutdown_gp_extensions(void)
+{
+ struct gp_extension *ext = NULL;
+
+ for (ext = extensions; ext; ext = ext->next) {
+ if (ext->methods && ext->methods->shutdown) {
+ ext->methods->shutdown();
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS init_gp_extensions(TALLOC_CTX *mem_ctx)
+{
+ NTSTATUS status;
+ WERROR werr;
+ int i = 0;
+ const char **ext_array = NULL;
+ size_t ext_array_len = 0;
+ struct gp_extension *gpext = NULL;
+ struct gp_registry_context *reg_ctx = NULL;
+
+ if (get_gp_extension_list()) {
+ return NT_STATUS_OK;
+ }
+
+ status = gp_glob_ext_list(mem_ctx, &ext_array, &ext_array_len);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ for (i=0; i<ext_array_len; i++) {
+
+ struct gp_extension_reg_info *info = NULL;
+
+ status = gp_extension_init_module(mem_ctx, ext_array[i],
+ &gpext);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ if (gpext->methods->get_reg_config) {
+
+ status = gpext->methods->initialize(mem_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ gpext->methods->shutdown();
+ goto out;
+ }
+
+ status = gpext->methods->get_reg_config(mem_ctx,
+ &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ gpext->methods->shutdown();
+ goto out;
+ }
+
+ if (!reg_ctx) {
+ struct nt_user_token *token;
+
+ token = registry_create_system_token(mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(token);
+
+ werr = gp_init_reg_ctx(mem_ctx,
+ KEY_WINLOGON_GPEXT_PATH,
+ REG_KEY_WRITE,
+ token,
+ &reg_ctx);
+ if (!W_ERROR_IS_OK(werr)) {
+ status = werror_to_ntstatus(werr);
+ gpext->methods->shutdown();
+ goto out;
+ }
+ }
+
+ werr = gp_extension_store_reg(mem_ctx, reg_ctx, info);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(1,("gp_extension_store_reg failed: %s\n",
+ dos_errstr(werr)));
+ TALLOC_FREE(info);
+ gpext->methods->shutdown();
+ status = werror_to_ntstatus(werr);
+ goto out;
+ }
+ TALLOC_FREE(info);
+ }
+
+ }
+
+ out:
+ TALLOC_FREE(reg_ctx);
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS free_gp_extensions(void)
+{
+ struct gp_extension *ext, *ext_next = NULL;
+
+ for (ext = extensions; ext; ext = ext_next) {
+ ext_next = ext->next;
+ DLIST_REMOVE(extensions, ext);
+ TALLOC_FREE(ext);
+ }
+
+ extensions = NULL;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+void debug_gpext_header(int lvl,
+ const char *name,
+ uint32_t flags,
+ struct GROUP_POLICY_OBJECT *gpo,
+ const char *extension_guid,
+ const char *snapin_guid)
+{
+ char *flags_str = NULL;
+
+ DEBUG(lvl,("%s\n", name));
+ DEBUGADD(lvl,("\tgpo: %s (%s)\n", gpo->name,
+ gpo->display_name));
+ DEBUGADD(lvl,("\tcse extension: %s (%s)\n", extension_guid,
+ cse_gpo_guid_string_to_name(extension_guid)));
+ DEBUGADD(lvl,("\tgplink: %s\n", gpo->link));
+ DEBUGADD(lvl,("\tsnapin: %s (%s)\n", snapin_guid,
+ cse_snapin_gpo_guid_string_to_name(snapin_guid)));
+
+ flags_str = gpo_flag_str(flags);
+ DEBUGADD(lvl,("\tflags: 0x%08x %s\n", flags, flags_str));
+ SAFE_FREE(flags_str);
+}
+
+NTSTATUS process_gpo_list_with_extension(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const struct nt_user_token *token,
+ struct GROUP_POLICY_OBJECT *gpo_list,
+ const char *extension_guid,
+ const char *snapin_guid)
+{
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gpext_process_extension(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const struct nt_user_token *token,
+ struct registry_key *root_key,
+ struct GROUP_POLICY_OBJECT *gpo,
+ const char *extension_guid,
+ const char *snapin_guid)
+{
+ NTSTATUS status;
+ struct gp_extension *ext = NULL;
+ struct GUID guid;
+ bool cse_found = false;
+
+ status = init_gp_extensions(mem_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1,("init_gp_extensions failed: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ status = GUID_from_string(extension_guid, &guid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ for (ext = extensions; ext; ext = ext->next) {
+
+ if (GUID_equal(ext->guid, &guid)) {
+ cse_found = true;
+ break;
+ }
+ }
+
+ if (!cse_found) {
+ goto no_ext;
+ }
+
+ status = ext->methods->initialize(mem_ctx);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ status = ext->methods->process_group_policy(ads,
+ mem_ctx,
+ flags,
+ root_key,
+ token,
+ gpo,
+ extension_guid,
+ snapin_guid);
+ if (!NT_STATUS_IS_OK(status)) {
+ ext->methods->shutdown();
+ }
+
+ return status;
+
+ no_ext:
+ if (flags & GPO_INFO_FLAG_VERBOSE) {
+ DEBUG(0,("process_extension: no extension available for:\n"));
+ DEBUGADD(0,("%s (%s) (snapin: %s)\n",
+ extension_guid,
+ cse_gpo_guid_string_to_name(extension_guid),
+ snapin_guid));
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/libgpo/gpext/gpext.h b/source3/libgpo/gpext/gpext.h
new file mode 100644
index 0000000000..0f0445701d
--- /dev/null
+++ b/source3/libgpo/gpext/gpext.h
@@ -0,0 +1,79 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Support
+ * Copyright (C) Guenther Deschner 2007-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define KEY_WINLOGON_GPEXT_PATH "HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\GPExtensions"
+
+#define SAMBA_SUBSYSTEM_GPEXT "gpext"
+
+#define SMB_GPEXT_INTERFACE_VERSION 1
+
+struct gp_extension {
+ struct GUID *guid;
+ const char *name;
+ struct gp_extension_methods *methods;
+ struct gp_extension *prev, *next;
+};
+
+struct gp_extension_reg_table {
+ const char *val;
+ enum winreg_Type type;
+ const char *data;
+};
+
+struct gp_extension_reg_entry {
+ const char *value;
+ struct registry_value *data;
+};
+
+struct gp_extension_reg_info_entry {
+ struct GUID guid;
+ size_t num_entries;
+ struct gp_extension_reg_entry *entries;
+};
+
+struct gp_extension_reg_info {
+ size_t num_entries;
+ struct gp_extension_reg_info_entry *entries;
+};
+
+struct gp_extension_methods {
+
+ NTSTATUS (*initialize)(TALLOC_CTX *mem_ctx);
+
+ NTSTATUS (*process_group_policy)(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct registry_key *root_key,
+ const struct nt_user_token *token,
+ struct GROUP_POLICY_OBJECT *gpo,
+ const char *extension_guid,
+ const char *snapin_guid);
+
+ NTSTATUS (*process_group_policy2)(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const struct nt_user_token *token,
+ struct GROUP_POLICY_OBJECT *gpo_list,
+ const char *extension_guid);
+
+ NTSTATUS (*get_reg_config)(TALLOC_CTX *mem_ctx,
+ struct gp_extension_reg_info **info);
+
+ NTSTATUS (*shutdown)(void);
+};
diff --git a/source3/libgpo/gpext/registry.c b/source3/libgpo/gpext/registry.c
new file mode 100644
index 0000000000..188a48ab49
--- /dev/null
+++ b/source3/libgpo/gpext/registry.c
@@ -0,0 +1,643 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Support
+ * Copyright (C) Guenther Deschner 2007-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#define GP_EXT_NAME "registry"
+
+/* more info can be found at:
+ * http://msdn2.microsoft.com/en-us/library/aa374407.aspx */
+
+#define GP_REGPOL_FILE "Registry.pol"
+
+#define GP_REGPOL_FILE_SIGNATURE 0x67655250 /* 'PReg' */
+#define GP_REGPOL_FILE_VERSION 1
+
+static TALLOC_CTX *ctx = NULL;
+
+struct gp_registry_file_header {
+ uint32_t signature;
+ uint32_t version;
+};
+
+struct gp_registry_file_entry {
+ UNISTR key;
+ UNISTR value;
+ enum winreg_Type type;
+ size_t size;
+ uint8_t *data;
+};
+
+struct gp_registry_file {
+ struct gp_registry_file_header header;
+ size_t num_entries;
+ struct gp_registry_entry *entries;
+};
+
+/****************************************************************
+****************************************************************/
+
+static bool reg_parse_header(const char *desc,
+ struct gp_registry_file_header *header,
+ prs_struct *ps,
+ int depth)
+{
+ if (!header)
+ return false;
+
+ prs_debug(ps, depth, desc, "reg_parse_header");
+ depth++;
+
+ if (!prs_uint32("signature", ps, depth, &header->signature))
+ return false;
+
+ if (!prs_uint32("version", ps, depth, &header->version))
+ return false;
+
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool reg_parse_and_verify_ucs2_char(const char *desc,
+ char character,
+ prs_struct *ps,
+ int depth)
+{
+ uint16_t tmp;
+
+ if (!prs_uint16(desc, ps, depth, &tmp))
+ return false;
+
+ if (tmp != UCS2_CHAR(character))
+ return false;
+
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool reg_parse_init(prs_struct *ps, int depth)
+{
+ return reg_parse_and_verify_ucs2_char("initiator '['", '[',
+ ps, depth);
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool reg_parse_sep(prs_struct *ps, int depth)
+{
+ return reg_parse_and_verify_ucs2_char("separator ';'", ';',
+ ps, depth);
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool reg_parse_term(prs_struct *ps, int depth)
+{
+ return reg_parse_and_verify_ucs2_char("terminator ']'", ']',
+ ps, depth);
+}
+
+
+/****************************************************************
+* [key;value;type;size;data]
+****************************************************************/
+
+static bool reg_parse_entry(TALLOC_CTX *mem_ctx,
+ const char *desc,
+ struct gp_registry_file_entry *entry,
+ prs_struct *ps,
+ int depth)
+{
+ uint32_t size = 0;
+
+ if (!entry)
+ return false;
+
+ prs_debug(ps, depth, desc, "reg_parse_entry");
+ depth++;
+
+ ZERO_STRUCTP(entry);
+
+ if (!reg_parse_init(ps, depth))
+ return false;
+
+ if (!prs_unistr("key", ps, depth, &entry->key))
+ return false;
+
+ if (!reg_parse_sep(ps, depth))
+ return false;
+
+ if (!prs_unistr("value", ps, depth, &entry->value))
+ return false;
+
+ if (!reg_parse_sep(ps, depth))
+ return false;
+
+ if (!prs_uint32("type", ps, depth, &entry->type))
+ return false;
+
+ if (!reg_parse_sep(ps, depth))
+ return false;
+
+ if (!prs_uint32("size", ps, depth, &size))
+ return false;
+
+ entry->size = size;
+
+ if (!reg_parse_sep(ps, depth))
+ return false;
+
+ if (entry->size) {
+ entry->data = TALLOC_ZERO_ARRAY(mem_ctx, uint8, entry->size);
+ if (!entry->data)
+ return false;
+ }
+
+ if (!prs_uint8s(false, "data", ps, depth, entry->data, entry->size))
+ return false;
+
+ if (!reg_parse_term(ps, depth))
+ return false;
+
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool reg_parse_value(TALLOC_CTX *mem_ctx,
+ char **value,
+ enum gp_reg_action *action)
+{
+ if (!*value) {
+ *action = GP_REG_ACTION_ADD_KEY;
+ return true;
+ }
+
+ if (strncmp(*value, "**", 2) != 0) {
+ *action = GP_REG_ACTION_ADD_VALUE;
+ return true;
+ }
+
+ if (strnequal(*value, "**DelVals.", 10)) {
+ *action = GP_REG_ACTION_DEL_ALL_VALUES;
+ return true;
+ }
+
+ if (strnequal(*value, "**Del.", 6)) {
+ *value = talloc_strdup(mem_ctx, *value + 6);
+ *action = GP_REG_ACTION_DEL_VALUE;
+ return true;
+ }
+
+ if (strnequal(*value, "**SecureKey", 11)) {
+ if (strnequal(*value, "**SecureKey=1", 13)) {
+ *action = GP_REG_ACTION_SEC_KEY_SET;
+ return true;
+ }
+
+ /*************** not tested from here on ***************/
+ if (strnequal(*value, "**SecureKey=0", 13)) {
+ smb_panic("not supported: **SecureKey=0");
+ *action = GP_REG_ACTION_SEC_KEY_RESET;
+ return true;
+ }
+ DEBUG(0,("unknown: SecureKey: %s\n", *value));
+ smb_panic("not supported SecureKey method");
+ return false;
+ }
+
+ if (strnequal(*value, "**DeleteValues", strlen("**DeleteValues"))) {
+ smb_panic("not supported: **DeleteValues");
+ *action = GP_REG_ACTION_DEL_VALUES;
+ return false;
+ }
+
+ if (strnequal(*value, "**DeleteKeys", strlen("**DeleteKeys"))) {
+ smb_panic("not supported: **DeleteKeys");
+ *action = GP_REG_ACTION_DEL_KEYS;
+ return false;
+ }
+
+ DEBUG(0,("unknown value: %s\n", *value));
+ smb_panic(*value);
+ return false;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool gp_reg_entry_from_file_entry(TALLOC_CTX *mem_ctx,
+ struct gp_registry_file_entry *file_entry,
+ struct gp_registry_entry **reg_entry)
+{
+ struct registry_value *data = NULL;
+ struct gp_registry_entry *entry = NULL;
+ char *key = NULL;
+ char *value = NULL;
+ enum gp_reg_action action = GP_REG_ACTION_NONE;
+ size_t converted_size;
+
+ ZERO_STRUCTP(*reg_entry);
+
+ data = TALLOC_ZERO_P(mem_ctx, struct registry_value);
+ if (!data)
+ return false;
+
+ if (strlen_w((const smb_ucs2_t *)file_entry->key.buffer) <= 0)
+ return false;
+
+ if (!pull_ucs2_talloc(mem_ctx, &key, file_entry->key.buffer,
+ &converted_size))
+ {
+ return false;
+ }
+
+ if (strlen_w((const smb_ucs2_t *)file_entry->value.buffer) > 0 &&
+ !pull_ucs2_talloc(mem_ctx, &value, file_entry->value.buffer,
+ &converted_size))
+ {
+ return false;
+ }
+
+ if (!reg_parse_value(mem_ctx, &value, &action))
+ return false;
+
+ data->type = file_entry->type;
+
+ switch (data->type) {
+ case REG_DWORD:
+ data->v.dword = atoi((char *)file_entry->data);
+ break;
+ case REG_BINARY:
+ data->v.binary = data_blob_talloc(mem_ctx,
+ file_entry->data,
+ file_entry->size);
+ break;
+ case REG_NONE:
+ break;
+ case REG_SZ:
+ if (!pull_ucs2_talloc(mem_ctx, &data->v.sz.str,
+ (const smb_ucs2_t *)
+ file_entry->data,
+ &data->v.sz.len)) {
+ data->v.sz.len = -1;
+ }
+
+ break;
+ case REG_DWORD_BIG_ENDIAN:
+ case REG_EXPAND_SZ:
+ case REG_LINK:
+ case REG_MULTI_SZ:
+ case REG_QWORD:
+/* case REG_DWORD_LITTLE_ENDIAN: */
+/* case REG_QWORD_LITTLE_ENDIAN: */
+ printf("not yet implemented: %d\n", data->type);
+ return false;
+ default:
+ printf("invalid reg type defined: %d\n", data->type);
+ return false;
+
+ }
+
+ entry = TALLOC_ZERO_P(mem_ctx, struct gp_registry_entry);
+ if (!entry)
+ return false;
+
+ entry->key = key;
+ entry->value = value;
+ entry->data = data;
+ entry->action = action;
+
+ *reg_entry = entry;
+
+ return true;
+}
+
+/****************************************************************
+* [key;value;type;size;data][key;value;type;size;data]...
+****************************************************************/
+
+static bool reg_parse_entries(TALLOC_CTX *mem_ctx,
+ const char *desc,
+ struct gp_registry_entry **entries,
+ size_t *num_entries,
+ prs_struct *ps,
+ int depth)
+{
+
+ if (!entries || !num_entries)
+ return false;
+
+ prs_debug(ps, depth, desc, "reg_parse_entries");
+ depth++;
+
+ *entries = NULL;
+ *num_entries = 0;
+
+ while (ps->buffer_size > ps->data_offset) {
+
+ struct gp_registry_file_entry f_entry;
+ struct gp_registry_entry *r_entry = NULL;
+
+ if (!reg_parse_entry(mem_ctx, desc, &f_entry,
+ ps, depth))
+ return false;
+
+ if (!gp_reg_entry_from_file_entry(mem_ctx,
+ &f_entry,
+ &r_entry))
+ return false;
+
+ if (!add_gp_registry_entry_to_array(mem_ctx,
+ r_entry,
+ entries,
+ num_entries))
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS reg_parse_registry(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const char *filename,
+ struct gp_registry_entry **entries,
+ size_t *num_entries)
+{
+ uint16_t *buf = NULL;
+ size_t n = 0;
+ NTSTATUS status;
+ prs_struct ps;
+ struct gp_registry_file *reg_file;
+ const char *real_filename = NULL;
+
+ reg_file = TALLOC_ZERO_P(mem_ctx, struct gp_registry_file);
+ NT_STATUS_HAVE_NO_MEMORY(reg_file);
+
+ status = gp_find_file(mem_ctx,
+ flags,
+ filename,
+ GP_REGPOL_FILE,
+ &real_filename);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(reg_file);
+ return status;
+ }
+
+ buf = (uint16 *)file_load(real_filename, &n, 0);
+ if (!buf) {
+ TALLOC_FREE(reg_file);
+ return NT_STATUS_CANNOT_LOAD_REGISTRY_FILE;
+ }
+
+ if (!prs_init(&ps, n, mem_ctx, UNMARSHALL)) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ if (!prs_copy_data_in(&ps, (char *)buf, n)) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ prs_set_offset(&ps, 0);
+
+ if (!reg_parse_header("header", &reg_file->header, &ps, 0)) {
+ status = NT_STATUS_REGISTRY_IO_FAILED;
+ goto out;
+ }
+
+ if (reg_file->header.signature != GP_REGPOL_FILE_SIGNATURE) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ if (reg_file->header.version != GP_REGPOL_FILE_VERSION) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ if (!reg_parse_entries(mem_ctx, "entries", &reg_file->entries,
+ &reg_file->num_entries, &ps, 0)) {
+ status = NT_STATUS_REGISTRY_IO_FAILED;
+ goto out;
+ }
+
+ *entries = reg_file->entries;
+ *num_entries = reg_file->num_entries;
+
+ status = NT_STATUS_OK;
+
+ out:
+ SAFE_FREE(buf);
+ prs_mem_free(&ps);
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR reg_apply_registry(TALLOC_CTX *mem_ctx,
+ const struct nt_user_token *token,
+ struct registry_key *root_key,
+ uint32_t flags,
+ struct gp_registry_entry *entries,
+ size_t num_entries)
+{
+ struct gp_registry_context *reg_ctx = NULL;
+ WERROR werr;
+ size_t i;
+
+ if (num_entries == 0) {
+ return WERR_OK;
+ }
+
+#if 0
+ if (flags & GPO_LIST_FLAG_MACHINE) {
+ werr = gp_init_reg_ctx(mem_ctx, KEY_HKLM, REG_KEY_WRITE,
+ get_system_token(),
+ &reg_ctx);
+ } else {
+ werr = gp_init_reg_ctx(mem_ctx, KEY_HKCU, REG_KEY_WRITE,
+ token,
+ &reg_ctx);
+ }
+ W_ERROR_NOT_OK_RETURN(werr);
+#endif
+ for (i=0; i<num_entries; i++) {
+
+ /* FIXME: maybe we should check here if we attempt to go beyond
+ * the 4 allowed reg keys */
+
+ werr = reg_apply_registry_entry(mem_ctx, root_key,
+ reg_ctx,
+ &(entries)[i],
+ token, flags);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("failed to apply registry: %s\n",
+ dos_errstr(werr)));
+ goto done;
+ }
+ }
+
+done:
+ gp_free_reg_ctx(reg_ctx);
+ return werr;
+}
+
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS registry_process_group_policy(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct registry_key *root_key,
+ const struct nt_user_token *token,
+ struct GROUP_POLICY_OBJECT *gpo,
+ const char *extension_guid,
+ const char *snapin_guid)
+{
+ NTSTATUS status;
+ WERROR werr;
+ struct gp_registry_entry *entries = NULL;
+ size_t num_entries = 0;
+ char *unix_path = NULL;
+
+ debug_gpext_header(0, "registry_process_group_policy", flags, gpo,
+ extension_guid, snapin_guid);
+
+ status = gpo_get_unix_path(mem_ctx, gpo, &unix_path);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ status = reg_parse_registry(mem_ctx,
+ flags,
+ unix_path,
+ &entries,
+ &num_entries);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("failed to parse registry: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ dump_reg_entries(flags, "READ", entries, num_entries);
+
+ werr = reg_apply_registry(mem_ctx, token, root_key, flags,
+ entries, num_entries);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("failed to apply registry: %s\n",
+ dos_errstr(werr)));
+ return werror_to_ntstatus(werr);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS registry_get_reg_config(TALLOC_CTX *mem_ctx,
+ struct gp_extension_reg_info **reg_info)
+{
+ NTSTATUS status;
+ struct gp_extension_reg_info *info = NULL;
+ struct gp_extension_reg_table table[] = {
+ { "ProcessGroupPolicy", REG_SZ, "registry_process_group_policy" },
+ { NULL, REG_NONE, NULL }
+ };
+
+ info = TALLOC_ZERO_P(mem_ctx, struct gp_extension_reg_info);
+ NT_STATUS_HAVE_NO_MEMORY(info);
+
+ status = gp_ext_info_add_entry(mem_ctx, GP_EXT_NAME,
+ GP_EXT_GUID_REGISTRY,
+ table, info);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *reg_info = info;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS registry_initialize(TALLOC_CTX *mem_ctx)
+{
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS registry_shutdown(void)
+{
+ NTSTATUS status;
+
+ status = unregister_gp_extension(GP_EXT_NAME);
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ TALLOC_FREE(ctx);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static struct gp_extension_methods registry_methods = {
+ .initialize = registry_initialize,
+ .process_group_policy = registry_process_group_policy,
+ .get_reg_config = registry_get_reg_config,
+ .shutdown = registry_shutdown
+};
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gpext_registry_init(void)
+{
+ NTSTATUS status;
+
+ ctx = talloc_init("gpext_registry_init");
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ status = register_gp_extension(ctx, SMB_GPEXT_INTERFACE_VERSION,
+ GP_EXT_NAME, GP_EXT_GUID_REGISTRY,
+ &registry_methods);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(ctx);
+ }
+
+ return status;
+}
diff --git a/source3/libgpo/gpext/scripts.c b/source3/libgpo/gpext/scripts.c
new file mode 100644
index 0000000000..c07407c3f0
--- /dev/null
+++ b/source3/libgpo/gpext/scripts.c
@@ -0,0 +1,443 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Support
+ * Copyright (C) Guenther Deschner 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "libgpo/gpo_ini.h"
+
+#define GP_EXT_NAME "scripts"
+
+#define KEY_GP_SCRIPTS "Software\\Policies\\Microsoft\\Windows\\System\\Scripts"
+
+#define GP_SCRIPTS_INI "Scripts/scripts.ini"
+
+#define GP_SCRIPTS_INI_STARTUP "Startup"
+#define GP_SCRIPTS_INI_SHUTDOWN "Shutdown"
+#define GP_SCRIPTS_INI_LOGON "Logon"
+#define GP_SCRIPTS_INI_LOGOFF "Logoff"
+
+#define GP_SCRIPTS_SECTION_CMDLINE "cmdline"
+#define GP_SCRIPTS_SECTION_PARAMETERS "parameters"
+
+#define GP_SCRIPTS_REG_VAL_SCRIPT "Script"
+#define GP_SCRIPTS_REG_VAL_PARAMETERS "Parameters"
+#define GP_SCRIPTS_REG_VAL_EXECTIME "ExecTime"
+
+static TALLOC_CTX *ctx = NULL;
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS scripts_get_reg_config(TALLOC_CTX *mem_ctx,
+ struct gp_extension_reg_info **reg_info)
+{
+ NTSTATUS status;
+ struct gp_extension_reg_info *info = NULL;
+
+ struct gp_extension_reg_table table[] = {
+ { "ProcessGroupPolicy", REG_SZ, "scripts_process_group_policy" },
+ { "NoGPOListChanges", REG_DWORD, "1" },
+ { "NoSlowLink", REG_DWORD, "1" },
+ { "NotifyLinkTransition", REG_DWORD, "1" },
+ { NULL, REG_NONE, NULL },
+ };
+
+ info = TALLOC_ZERO_P(mem_ctx, struct gp_extension_reg_info);
+ NT_STATUS_HAVE_NO_MEMORY(info);
+
+ status = gp_ext_info_add_entry(mem_ctx, GP_EXT_NAME,
+ GP_EXT_GUID_SCRIPTS,
+ table, info);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *reg_info = info;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS generate_gp_registry_entry(TALLOC_CTX *mem_ctx,
+ const char *key,
+ const char *value,
+ uint32_t data_type,
+ const void *data_p,
+ enum gp_reg_action action,
+ struct gp_registry_entry **entry_out)
+{
+ struct gp_registry_entry *entry = NULL;
+ struct registry_value *data = NULL;
+
+ entry = TALLOC_ZERO_P(mem_ctx, struct gp_registry_entry);
+ NT_STATUS_HAVE_NO_MEMORY(entry);
+
+ data = TALLOC_ZERO_P(mem_ctx, struct registry_value);
+ NT_STATUS_HAVE_NO_MEMORY(data);
+
+ data->type = data_type;
+ switch (data->type) {
+ case REG_QWORD:
+ data->v.qword = (uint64_t)data_p;
+ break;
+ case REG_SZ:
+ data->v.sz.str = talloc_strdup(mem_ctx, (char *)data_p);
+ data->v.sz.len = strlen(data->v.sz.str);
+ break;
+ default:
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ entry->key = key;
+ entry->data = data;
+ entry->action = action;
+ entry->value = talloc_strdup(mem_ctx, value);
+ NT_STATUS_HAVE_NO_MEMORY(entry->value);
+
+ *entry_out = entry;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS scripts_parse_ini_section(struct gp_inifile_context *ini_ctx,
+ uint32_t flags,
+ const char *section,
+ struct gp_registry_entry **entries,
+ size_t *num_entries)
+{
+ NTSTATUS status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ int i = 0;
+
+ while (1) {
+
+ const char *key = NULL;
+ const char *script = NULL;
+ const char *count = NULL;
+ const char *parameters = NULL;
+
+ count = talloc_asprintf(ini_ctx->mem_ctx, "%d", i);
+ NT_STATUS_HAVE_NO_MEMORY(count);
+
+ key = talloc_asprintf(ini_ctx->mem_ctx, "%s:%s%s",
+ section, count,
+ GP_SCRIPTS_SECTION_CMDLINE);
+ NT_STATUS_HAVE_NO_MEMORY(key);
+
+ script = iniparser_getstring(ini_ctx->dict, key, NULL);
+ if (!script) {
+ break;
+ }
+
+ key = talloc_asprintf(ini_ctx->mem_ctx, "%s:%s%s",
+ section, count,
+ GP_SCRIPTS_SECTION_PARAMETERS);
+ NT_STATUS_HAVE_NO_MEMORY(key);
+
+ parameters = iniparser_getstring(ini_ctx->dict, key, NULL);
+
+ {
+ struct gp_registry_entry *entry = NULL;
+ status = generate_gp_registry_entry(ini_ctx->mem_ctx,
+ count,
+ GP_SCRIPTS_REG_VAL_SCRIPT,
+ REG_SZ,
+ script,
+ GP_REG_ACTION_ADD_VALUE,
+ &entry);
+ NT_STATUS_NOT_OK_RETURN(status);
+ if (!add_gp_registry_entry_to_array(ini_ctx->mem_ctx,
+ entry,
+ entries,
+ num_entries)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ {
+ struct gp_registry_entry *entry = NULL;
+ status = generate_gp_registry_entry(ini_ctx->mem_ctx,
+ count,
+ GP_SCRIPTS_REG_VAL_PARAMETERS,
+ REG_SZ,
+ parameters,
+ GP_REG_ACTION_ADD_VALUE,
+ &entry);
+ NT_STATUS_NOT_OK_RETURN(status);
+ if (!add_gp_registry_entry_to_array(ini_ctx->mem_ctx,
+ entry,
+ entries,
+ num_entries)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ {
+ struct gp_registry_entry *entry = NULL;
+ status = generate_gp_registry_entry(ini_ctx->mem_ctx,
+ count,
+ GP_SCRIPTS_REG_VAL_EXECTIME,
+ REG_QWORD,
+ 0,
+ GP_REG_ACTION_ADD_VALUE,
+ &entry);
+ NT_STATUS_NOT_OK_RETURN(status);
+ if (!add_gp_registry_entry_to_array(ini_ctx->mem_ctx,
+ entry,
+ entries,
+ num_entries)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ status = NT_STATUS_OK;
+ i++;
+ }
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR scripts_store_reg_gpovals(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ struct GROUP_POLICY_OBJECT *gpo)
+{
+ WERROR werr;
+
+ if (!key || !gpo) {
+ return WERR_INVALID_PARAM;
+ }
+
+ werr = gp_store_reg_val_sz(mem_ctx, key, "DisplayName",
+ gpo->display_name);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_sz(mem_ctx, key, "FileSysPath",
+ gpo->file_sys_path);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_sz(mem_ctx, key, "GPO-ID",
+ gpo->ds_path);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_sz(mem_ctx, key, "GPOName",
+ gpo->name);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_sz(mem_ctx, key, "SOM-ID",
+ gpo->link);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR scripts_apply(TALLOC_CTX *mem_ctx,
+ const struct nt_user_token *token,
+ struct registry_key *root_key,
+ uint32_t flags,
+ const char *section,
+ struct GROUP_POLICY_OBJECT *gpo,
+ struct gp_registry_entry *entries,
+ size_t num_entries)
+{
+ struct gp_registry_context *reg_ctx = NULL;
+ WERROR werr;
+ size_t i;
+ const char *keystr = NULL;
+ int count = 0;
+
+ if (num_entries == 0) {
+ return WERR_OK;
+ }
+
+#if 0
+ if (flags & GPO_INFO_FLAG_MACHINE) {
+ struct nt_user_token *tmp_token;
+
+ tmp_token = registry_create_system_token(mem_ctx);
+ W_ERROR_HAVE_NO_MEMORY(tmp_token);
+
+ werr = gp_init_reg_ctx(mem_ctx, KEY_HKLM, REG_KEY_WRITE,
+ tmp_token,
+ &reg_ctx);
+ } else {
+ werr = gp_init_reg_ctx(mem_ctx, KEY_HKCU, REG_KEY_WRITE,
+ token,
+ &reg_ctx);
+ }
+ W_ERROR_NOT_OK_RETURN(werr);
+#endif
+
+ keystr = talloc_asprintf(mem_ctx, "%s\\%s\\%d", KEY_GP_SCRIPTS,
+ section, count++);
+ W_ERROR_HAVE_NO_MEMORY(keystr);
+
+ reg_deletekey_recursive(mem_ctx, root_key, keystr);
+
+ werr = gp_store_reg_subkey(mem_ctx, keystr,
+ root_key, &root_key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = scripts_store_reg_gpovals(mem_ctx, root_key, gpo);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ for (i=0; i<num_entries; i++) {
+
+ werr = reg_apply_registry_entry(mem_ctx, root_key, reg_ctx,
+ &(entries)[i],
+ token, flags);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("failed to apply registry: %s\n",
+ dos_errstr(werr)));
+ goto done;
+ }
+ }
+
+ done:
+ gp_free_reg_ctx(reg_ctx);
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS scripts_process_group_policy(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct registry_key *root_key,
+ const struct nt_user_token *token,
+ struct GROUP_POLICY_OBJECT *gpo,
+ const char *extension_guid,
+ const char *snapin_guid)
+{
+ NTSTATUS status;
+ WERROR werr;
+ int i = 0;
+ char *unix_path = NULL;
+ struct gp_inifile_context *ini_ctx = NULL;
+ struct gp_registry_entry *entries = NULL;
+ size_t num_entries = 0;
+ const char *list[] = {
+ GP_SCRIPTS_INI_STARTUP,
+ GP_SCRIPTS_INI_SHUTDOWN,
+ GP_SCRIPTS_INI_LOGON,
+ GP_SCRIPTS_INI_LOGOFF
+ };
+
+ debug_gpext_header(0, "scripts_process_group_policy", flags, gpo,
+ extension_guid, snapin_guid);
+
+ status = gpo_get_unix_path(mem_ctx, gpo, &unix_path);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ status = gp_inifile_init_context(mem_ctx, flags, unix_path,
+ GP_SCRIPTS_INI, &ini_ctx);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ for (i = 0; i < ARRAY_SIZE(list); i++) {
+
+ TALLOC_FREE(entries);
+ num_entries = 0;
+
+ status = scripts_parse_ini_section(ini_ctx, flags, list[i],
+ &entries, &num_entries);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ continue;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ dump_reg_entries(flags, "READ", entries, num_entries);
+
+ werr = scripts_apply(ini_ctx->mem_ctx, token, root_key,
+ flags, list[i], gpo, entries, num_entries);
+ if (!W_ERROR_IS_OK(werr)) {
+ continue; /* FIXME: finally fix storing emtpy strings and REG_QWORD! */
+ TALLOC_FREE(ini_ctx);
+ return werror_to_ntstatus(werr);
+ }
+ }
+
+ TALLOC_FREE(ini_ctx);
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS scripts_initialize(TALLOC_CTX *mem_ctx)
+{
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS scripts_shutdown(void)
+{
+ NTSTATUS status;
+
+ status = unregister_gp_extension(GP_EXT_NAME);
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ TALLOC_FREE(ctx);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static struct gp_extension_methods scripts_methods = {
+ .initialize = scripts_initialize,
+ .process_group_policy = scripts_process_group_policy,
+ .get_reg_config = scripts_get_reg_config,
+ .shutdown = scripts_shutdown
+};
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gpext_scripts_init(void)
+{
+ NTSTATUS status;
+
+ ctx = talloc_init("gpext_scripts_init");
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ status = register_gp_extension(ctx, SMB_GPEXT_INTERFACE_VERSION,
+ GP_EXT_NAME, GP_EXT_GUID_SCRIPTS,
+ &scripts_methods);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(ctx);
+ }
+
+ return status;
+}
diff --git a/source3/libgpo/gpo_fetch.c b/source3/libgpo/gpo_fetch.c
new file mode 100644
index 0000000000..2ec066425b
--- /dev/null
+++ b/source3/libgpo/gpo_fetch.c
@@ -0,0 +1,187 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Object Support
+ * Copyright (C) Guenther Deschner 2005-2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/****************************************************************
+ explode the GPO CIFS URI into their components
+****************************************************************/
+
+NTSTATUS gpo_explode_filesyspath(TALLOC_CTX *mem_ctx,
+ const char *file_sys_path,
+ char **server,
+ char **service,
+ char **nt_path,
+ char **unix_path)
+{
+ char *path = NULL;
+
+ *server = NULL;
+ *service = NULL;
+ *nt_path = NULL;
+ *unix_path = NULL;
+
+ if (!file_sys_path) {
+ return NT_STATUS_OK;
+ }
+
+ if (!next_token_talloc(mem_ctx, &file_sys_path, server, "\\")) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ NT_STATUS_HAVE_NO_MEMORY(*server);
+
+ if (!next_token_talloc(mem_ctx, &file_sys_path, service, "\\")) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ NT_STATUS_HAVE_NO_MEMORY(*service);
+
+ if ((*nt_path = talloc_asprintf(mem_ctx, "\\%s", file_sys_path))
+ == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ NT_STATUS_HAVE_NO_MEMORY(*nt_path);
+
+ if ((path = talloc_asprintf(mem_ctx,
+ "%s/%s",
+ lock_path(GPO_CACHE_DIR),
+ file_sys_path)) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ path = talloc_string_sub(mem_ctx, path, "\\", "/");
+ if (!path) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *unix_path = talloc_strdup(mem_ctx, path);
+ NT_STATUS_HAVE_NO_MEMORY(*unix_path);
+
+ TALLOC_FREE(path);
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+ prepare the local disc storage for "unix_path"
+****************************************************************/
+
+static NTSTATUS gpo_prepare_local_store(TALLOC_CTX *mem_ctx,
+ const char *unix_path)
+{
+ const char *top_dir = lock_path(GPO_CACHE_DIR);
+ char *current_dir;
+ char *tok;
+
+ current_dir = talloc_strdup(mem_ctx, top_dir);
+ NT_STATUS_HAVE_NO_MEMORY(current_dir);
+
+ if ((mkdir(top_dir, 0644)) < 0 && errno != EEXIST) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ while (next_token_talloc(mem_ctx, &unix_path, &tok, "/")) {
+ if (strequal(tok, GPO_CACHE_DIR)) {
+ break;
+ }
+ }
+
+ while (next_token_talloc(mem_ctx, &unix_path, &tok, "/")) {
+ current_dir = talloc_asprintf_append_buffer(current_dir, "/%s", tok);
+ NT_STATUS_HAVE_NO_MEMORY(current_dir);
+
+ if ((mkdir(current_dir, 0644)) < 0 && errno != EEXIST) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+ download a full GPO via CIFS
+****************************************************************/
+
+NTSTATUS gpo_fetch_files(TALLOC_CTX *mem_ctx,
+ struct cli_state *cli,
+ struct GROUP_POLICY_OBJECT *gpo)
+{
+ NTSTATUS result;
+ char *server, *service, *nt_path, *unix_path;
+ char *nt_ini_path, *unix_ini_path;
+
+ result = gpo_explode_filesyspath(mem_ctx, gpo->file_sys_path,
+ &server, &service, &nt_path,
+ &unix_path);
+ NT_STATUS_NOT_OK_RETURN(result);
+
+ result = gpo_prepare_local_store(mem_ctx, unix_path);
+ NT_STATUS_NOT_OK_RETURN(result);
+
+ unix_ini_path = talloc_asprintf(mem_ctx, "%s/%s", unix_path, GPT_INI);
+ nt_ini_path = talloc_asprintf(mem_ctx, "%s\\%s", nt_path, GPT_INI);
+ NT_STATUS_HAVE_NO_MEMORY(unix_ini_path);
+ NT_STATUS_HAVE_NO_MEMORY(nt_ini_path);
+
+ result = gpo_copy_file(mem_ctx, cli, nt_ini_path, unix_ini_path);
+ NT_STATUS_NOT_OK_RETURN(result);
+
+ result = gpo_sync_directories(mem_ctx, cli, nt_path, unix_path);
+ NT_STATUS_NOT_OK_RETURN(result);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+ get the locally stored gpt.ini version number
+****************************************************************/
+
+NTSTATUS gpo_get_sysvol_gpt_version(TALLOC_CTX *mem_ctx,
+ const char *unix_path,
+ uint32_t *sysvol_version,
+ char **display_name)
+{
+ NTSTATUS status;
+ uint32_t version = 0;
+ char *local_path = NULL;
+ char *name = NULL;
+
+ if (!unix_path) {
+ return NT_STATUS_OK;
+ }
+
+ local_path = talloc_asprintf(mem_ctx, "%s/%s", unix_path, GPT_INI);
+ NT_STATUS_HAVE_NO_MEMORY(local_path);
+
+ status = parse_gpt_ini(mem_ctx, local_path, &version, &name);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("gpo_get_sysvol_gpt_version: "
+ "failed to parse ini [%s]: %s\n",
+ local_path, nt_errstr(status)));
+ return status;
+ }
+
+ if (sysvol_version) {
+ *sysvol_version = version;
+ }
+
+ if (name && *display_name) {
+ *display_name = talloc_strdup(mem_ctx, name);
+ NT_STATUS_HAVE_NO_MEMORY(*display_name);
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/libgpo/gpo_filesync.c b/source3/libgpo/gpo_filesync.c
new file mode 100644
index 0000000000..6d64d7b968
--- /dev/null
+++ b/source3/libgpo/gpo_filesync.c
@@ -0,0 +1,238 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Object Support
+ * Copyright (C) Guenther Deschner 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+struct sync_context {
+ TALLOC_CTX *mem_ctx;
+ struct cli_state *cli;
+ char *remote_path;
+ char *local_path;
+ char *mask;
+ uint16_t attribute;
+};
+
+static void gpo_sync_func(const char *mnt,
+ file_info *info,
+ const char *mask,
+ void *state);
+
+NTSTATUS gpo_copy_file(TALLOC_CTX *mem_ctx,
+ struct cli_state *cli,
+ const char *nt_path,
+ const char *unix_path)
+{
+ NTSTATUS result;
+ int fnum;
+ int fd = 0;
+ char *data = NULL;
+ static int io_bufsize = 64512;
+ int read_size = io_bufsize;
+ off_t nread = 0;
+
+ if ((fnum = cli_open(cli, nt_path, O_RDONLY, DENY_NONE)) == -1) {
+ result = NT_STATUS_NO_SUCH_FILE;
+ goto out;
+ }
+
+ if ((fd = sys_open(unix_path, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
+ result = map_nt_error_from_unix(errno);
+ goto out;
+ }
+
+ if ((data = (char *)SMB_MALLOC(read_size)) == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ while (1) {
+
+ int n = cli_read(cli, fnum, data, nread, read_size);
+
+ if (n <= 0)
+ break;
+
+ if (write(fd, data, n) != n) {
+ break;
+ }
+
+ nread += n;
+ }
+
+ result = NT_STATUS_OK;
+
+ out:
+ SAFE_FREE(data);
+ if (fnum) {
+ cli_close(cli, fnum);
+ }
+ if (fd) {
+ close(fd);
+ }
+
+ return result;
+}
+
+/****************************************************************
+ copy dir
+****************************************************************/
+
+static NTSTATUS gpo_copy_dir(const char *unix_path)
+{
+ if ((mkdir(unix_path, 0644)) < 0 && errno != EEXIST) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+ sync files
+****************************************************************/
+
+static bool gpo_sync_files(struct sync_context *ctx)
+{
+ DEBUG(3,("calling cli_list with mask: %s\n", ctx->mask));
+
+ if (cli_list(ctx->cli,
+ ctx->mask,
+ ctx->attribute,
+ gpo_sync_func,
+ ctx) == -1) {
+ DEBUG(1,("listing [%s] failed with error: %s\n",
+ ctx->mask, cli_errstr(ctx->cli)));
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************
+ syncronisation call back
+****************************************************************/
+
+static void gpo_sync_func(const char *mnt,
+ file_info *info,
+ const char *mask,
+ void *state)
+{
+ NTSTATUS result;
+ struct sync_context *ctx;
+ fstring nt_filename, unix_filename;
+ fstring nt_dir, unix_dir;
+ char *old_nt_dir, *old_unix_dir;
+
+ ctx = (struct sync_context *)state;
+
+ if (strequal(info->name, ".") || strequal(info->name, "..")) {
+ return;
+ }
+
+ DEBUG(5,("gpo_sync_func: got mask: [%s], name: [%s]\n",
+ mask, info->name));
+
+ if (info->mode & aDIR) {
+
+ DEBUG(3,("got dir: [%s]\n", info->name));
+
+ fstrcpy(nt_dir, ctx->remote_path);
+ fstrcat(nt_dir, "\\");
+ fstrcat(nt_dir, info->name);
+
+ fstrcpy(unix_dir, ctx->local_path);
+ fstrcat(unix_dir, "/");
+ fstrcat(unix_dir, info->name);
+
+ result = gpo_copy_dir(unix_dir);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(1,("failed to copy dir: %s\n",
+ nt_errstr(result)));
+ }
+
+ old_nt_dir = ctx->remote_path;
+ ctx->remote_path = talloc_strdup(ctx->mem_ctx, nt_dir);
+
+ old_unix_dir = ctx->local_path;
+ ctx->local_path = talloc_strdup(ctx->mem_ctx, unix_dir);
+
+ ctx->mask = talloc_asprintf(ctx->mem_ctx,
+ "%s\\*",
+ nt_dir);
+ if (!ctx->local_path || !ctx->mask || !ctx->remote_path) {
+ DEBUG(0,("gpo_sync_func: ENOMEM\n"));
+ return;
+ }
+ if (!gpo_sync_files(ctx)) {
+ DEBUG(0,("could not sync files\n"));
+ }
+
+ ctx->remote_path = old_nt_dir;
+ ctx->local_path = old_unix_dir;
+ return;
+ }
+
+ DEBUG(3,("got file: [%s]\n", info->name));
+
+ fstrcpy(nt_filename, ctx->remote_path);
+ fstrcat(nt_filename, "\\");
+ fstrcat(nt_filename, info->name);
+
+ fstrcpy(unix_filename, ctx->local_path);
+ fstrcat(unix_filename, "/");
+ fstrcat(unix_filename, info->name);
+
+ result = gpo_copy_file(ctx->mem_ctx, ctx->cli,
+ nt_filename, unix_filename);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(1,("failed to copy file: %s\n",
+ nt_errstr(result)));
+ }
+}
+
+
+/****************************************************************
+ list a remote directory and download recursivly
+****************************************************************/
+
+NTSTATUS gpo_sync_directories(TALLOC_CTX *mem_ctx,
+ struct cli_state *cli,
+ const char *nt_path,
+ const char *local_path)
+{
+ struct sync_context ctx;
+
+ ctx.mem_ctx = mem_ctx;
+ ctx.cli = cli;
+ ctx.remote_path = CONST_DISCARD(char *, nt_path);
+ ctx.local_path = CONST_DISCARD(char *, local_path);
+ ctx.attribute = (aSYSTEM | aHIDDEN | aDIR);
+
+ ctx.mask = talloc_asprintf(mem_ctx,
+ "%s\\*",
+ nt_path);
+ if (!ctx.mask) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!gpo_sync_files(&ctx)) {
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/libgpo/gpo_ini.c b/source3/libgpo/gpo_ini.c
new file mode 100644
index 0000000000..54aaffa477
--- /dev/null
+++ b/source3/libgpo/gpo_ini.c
@@ -0,0 +1,245 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Support
+ * Copyright (C) Guenther Deschner 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "gpo_ini.h"
+
+/****************************************************************
+****************************************************************/
+
+static int gp_inifile_free_context(struct gp_inifile_context *ctx)
+{
+ if (!ctx) {
+ return 0;
+ }
+
+ if (ctx->generated_filename) {
+ unlink(ctx->generated_filename);
+ ctx->generated_filename = NULL;
+ }
+
+ if (ctx->dict) {
+ iniparser_freedict(ctx->dict);
+ ctx->dict = NULL;
+ }
+
+ ctx = NULL;
+
+ return 0;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS convert_file_from_ucs2(TALLOC_CTX *mem_ctx,
+ const char *filename_in,
+ char **filename_out)
+{
+ int tmp_fd = -1;
+ uint8 *data_in = NULL;
+ uint8 *data_out = NULL;
+ char *tmp_name = NULL;
+ NTSTATUS status;
+ size_t n = 0;
+ size_t converted_size;
+
+ if (!filename_out) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ data_in = (uint8 *)file_load(filename_in, &n, 0);
+ if (!data_in) {
+ status = NT_STATUS_NO_SUCH_FILE;
+ goto out;
+ }
+
+ tmp_name = talloc_asprintf(mem_ctx, "%s/convert_file_from_ucs2.XXXXXX",
+ tmpdir());
+ if (!tmp_name) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ tmp_fd = smb_mkstemp(tmp_name);
+ if (tmp_fd == -1) {
+ status = NT_STATUS_ACCESS_DENIED;
+ goto out;
+ }
+
+ if (!convert_string_talloc(mem_ctx, CH_UTF16LE, CH_UNIX, data_in, n,
+ &data_out, &converted_size, False))
+ {
+ status = NT_STATUS_INVALID_BUFFER_SIZE;
+ goto out;
+ }
+
+ /* skip utf8 BOM */
+ DEBUG(11,("convert_file_from_ucs2: "
+ "data_out[0]: 0x%x, data_out[1]: 0x%x, data_out[2]: 0x%x\n",
+ data_out[0], data_out[1], data_out[2]));
+
+ if ((data_out[0] == 0xef) && (data_out[1] == 0xbb) &&
+ (data_out[2] == 0xbf)) {
+ DEBUG(11,("convert_file_from_ucs2: "
+ "%s skipping utf8 BOM\n", tmp_name));
+ data_out += 3;
+ converted_size -= 3;
+ }
+
+ if (sys_write(tmp_fd, data_out, converted_size) != converted_size) {
+ status = map_nt_error_from_unix(errno);
+ goto out;
+ }
+
+ *filename_out = tmp_name;
+
+ status = NT_STATUS_OK;
+
+ out:
+ if (tmp_fd != -1) {
+ close(tmp_fd);
+ }
+
+ SAFE_FREE(data_in);
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+ NTSTATUS gp_inifile_init_context(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const char *unix_path,
+ const char *suffix,
+ struct gp_inifile_context **ctx_ret)
+{
+ struct gp_inifile_context *ctx = NULL;
+ NTSTATUS status;
+ dictionary *dict = NULL;
+ char *tmp_filename = NULL;
+ const char *ini_filename = NULL;
+
+ if (!unix_path || !ctx_ret) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ctx = TALLOC_ZERO_P(mem_ctx, struct gp_inifile_context);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ talloc_set_destructor(ctx, gp_inifile_free_context);
+
+ status = gp_find_file(mem_ctx, flags, unix_path, suffix,
+ &ini_filename);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ status = convert_file_from_ucs2(mem_ctx, ini_filename,
+ &tmp_filename);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ dict = iniparser_load(tmp_filename);
+ if (!dict) {
+ status = NT_STATUS_NO_SUCH_FILE;
+ goto failed;
+ }
+
+ ctx->generated_filename = tmp_filename;
+ ctx->dict = dict;
+ ctx->mem_ctx = mem_ctx;
+
+ *ctx_ret = ctx;
+
+ return NT_STATUS_OK;
+
+ failed:
+
+ DEBUG(1,("gp_inifile_init_context failed: %s\n",
+ nt_errstr(status)));
+
+ TALLOC_FREE(ctx);
+
+ return status;
+}
+
+/****************************************************************
+ parse the local gpt.ini file
+****************************************************************/
+
+#define GPT_INI_SECTION_GENERAL "General"
+#define GPT_INI_PARAMETER_VERSION "Version"
+#define GPT_INI_PARAMETER_DISPLAYNAME "displayName"
+
+NTSTATUS parse_gpt_ini(TALLOC_CTX *mem_ctx,
+ const char *filename,
+ uint32_t *version,
+ char **display_name)
+{
+ NTSTATUS result;
+ uint32_t v = 0;
+ char *name = NULL;
+ dictionary *dict = NULL;
+
+ if (!filename) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ dict = iniparser_load(filename);
+ if (!dict) {
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+ if ((name = iniparser_getstring(dict, GPT_INI_SECTION_GENERAL
+ ":"GPT_INI_PARAMETER_DISPLAYNAME, NULL)) == NULL) {
+ /* the default domain policy and the default domain controller
+ * policy never have a displayname in their gpt.ini file */
+ DEBUG(10,("parse_gpt_ini: no name in %s\n", filename));
+ }
+
+ if (name && display_name) {
+ *display_name = talloc_strdup(mem_ctx, name);
+ if (*display_name == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+ }
+
+ if ((v = iniparser_getint(dict, GPT_INI_SECTION_GENERAL
+ ":"GPT_INI_PARAMETER_VERSION, Undefined)) == Undefined) {
+ DEBUG(10,("parse_gpt_ini: no version\n"));
+ result = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto out;
+ }
+
+ if (version) {
+ *version = v;
+ }
+
+ result = NT_STATUS_OK;
+ out:
+ if (dict) {
+ iniparser_freedict(dict);
+ }
+
+ return result;
+}
diff --git a/source3/libgpo/gpo_ini.h b/source3/libgpo/gpo_ini.h
new file mode 100644
index 0000000000..fa03dbaaaa
--- /dev/null
+++ b/source3/libgpo/gpo_ini.h
@@ -0,0 +1,33 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Support
+ * Copyright (C) Guenther Deschner 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* FIXME: get rid of iniparser */
+#include <iniparser.h>
+
+struct gp_inifile_context {
+ TALLOC_CTX *mem_ctx;
+ dictionary *dict;
+ const char *generated_filename;
+};
+
+/* prototypes */
+
+NTSTATUS gp_inifile_init_context(TALLOC_CTX *mem_ctx, uint32_t flags,
+ const char *unix_path, const char *suffix,
+ struct gp_inifile_context **ctx_ret);
diff --git a/source3/libgpo/gpo_ldap.c b/source3/libgpo/gpo_ldap.c
new file mode 100644
index 0000000000..0e77f0a856
--- /dev/null
+++ b/source3/libgpo/gpo_ldap.c
@@ -0,0 +1,866 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Object Support
+ * Copyright (C) Guenther Deschner 2005,2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/****************************************************************
+ parse the raw extension string into a GP_EXT structure
+****************************************************************/
+
+bool ads_parse_gp_ext(TALLOC_CTX *mem_ctx,
+ const char *extension_raw,
+ struct GP_EXT **gp_ext)
+{
+ bool ret = false;
+ struct GP_EXT *ext = NULL;
+ char **ext_list = NULL;
+ char **ext_strings = NULL;
+ int i;
+
+ if (!extension_raw) {
+ goto parse_error;
+ }
+
+ DEBUG(20,("ads_parse_gp_ext: %s\n", extension_raw));
+
+ ext = TALLOC_ZERO_P(mem_ctx, struct GP_EXT);
+ if (!ext) {
+ goto parse_error;
+ }
+
+ ext_list = str_list_make(mem_ctx, extension_raw, "]");
+ if (!ext_list) {
+ goto parse_error;
+ }
+
+ for (i = 0; ext_list[i] != NULL; i++) {
+ /* no op */
+ }
+
+ ext->num_exts = i;
+
+ if (ext->num_exts) {
+ ext->extensions = TALLOC_ZERO_ARRAY(mem_ctx, char *,
+ ext->num_exts);
+ ext->extensions_guid = TALLOC_ZERO_ARRAY(mem_ctx, char *,
+ ext->num_exts);
+ ext->snapins = TALLOC_ZERO_ARRAY(mem_ctx, char *,
+ ext->num_exts);
+ ext->snapins_guid = TALLOC_ZERO_ARRAY(mem_ctx, char *,
+ ext->num_exts);
+ }
+
+ ext->gp_extension = talloc_strdup(mem_ctx, extension_raw);
+
+ if (!ext->extensions || !ext->extensions_guid ||
+ !ext->snapins || !ext->snapins_guid ||
+ !ext->gp_extension) {
+ goto parse_error;
+ }
+
+ for (i = 0; ext_list[i] != NULL; i++) {
+
+ int k;
+ char *p, *q;
+
+ DEBUGADD(10,("extension #%d\n", i));
+
+ p = ext_list[i];
+
+ if (p[0] == '[') {
+ p++;
+ }
+
+ ext_strings = str_list_make(mem_ctx, p, "}");
+ if (ext_strings == NULL) {
+ goto parse_error;
+ }
+
+ for (k = 0; ext_strings[k] != NULL; k++) {
+ /* no op */
+ }
+
+ q = ext_strings[0];
+
+ if (q[0] == '{') {
+ q++;
+ }
+
+ ext->extensions[i] = talloc_strdup(mem_ctx,
+ cse_gpo_guid_string_to_name(q));
+ ext->extensions_guid[i] = talloc_strdup(mem_ctx, q);
+
+ /* we might have no name for the guid */
+ if (ext->extensions_guid[i] == NULL) {
+ goto parse_error;
+ }
+
+ for (k = 1; ext_strings[k] != NULL; k++) {
+
+ char *m = ext_strings[k];
+
+ if (m[0] == '{') {
+ m++;
+ }
+
+ /* FIXME: theoretically there could be more than one
+ * snapin per extension */
+ ext->snapins[i] = talloc_strdup(mem_ctx,
+ cse_snapin_gpo_guid_string_to_name(m));
+ ext->snapins_guid[i] = talloc_strdup(mem_ctx, m);
+
+ /* we might have no name for the guid */
+ if (ext->snapins_guid[i] == NULL) {
+ goto parse_error;
+ }
+ }
+ }
+
+ *gp_ext = ext;
+
+ ret = true;
+
+ parse_error:
+ TALLOC_FREE(ext_list);
+ TALLOC_FREE(ext_strings);
+
+ return ret;
+}
+
+#ifdef HAVE_LDAP
+
+/****************************************************************
+ parse the raw link string into a GP_LINK structure
+****************************************************************/
+
+static ADS_STATUS gpo_parse_gplink(TALLOC_CTX *mem_ctx,
+ const char *gp_link_raw,
+ uint32_t options,
+ struct GP_LINK *gp_link)
+{
+ ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ char **link_list;
+ int i;
+
+ ZERO_STRUCTP(gp_link);
+
+ DEBUG(10,("gpo_parse_gplink: gPLink: %s\n", gp_link_raw));
+
+ link_list = str_list_make(mem_ctx, gp_link_raw, "]");
+ if (!link_list) {
+ goto parse_error;
+ }
+
+ for (i = 0; link_list[i] != NULL; i++) {
+ /* no op */
+ }
+
+ gp_link->gp_opts = options;
+ gp_link->num_links = i;
+
+ if (gp_link->num_links) {
+ gp_link->link_names = TALLOC_ZERO_ARRAY(mem_ctx, char *,
+ gp_link->num_links);
+ gp_link->link_opts = TALLOC_ZERO_ARRAY(mem_ctx, uint32_t,
+ gp_link->num_links);
+ }
+
+ gp_link->gp_link = talloc_strdup(mem_ctx, gp_link_raw);
+
+ if (!gp_link->link_names || !gp_link->link_opts || !gp_link->gp_link) {
+ goto parse_error;
+ }
+
+ for (i = 0; link_list[i] != NULL; i++) {
+
+ char *p, *q;
+
+ DEBUGADD(10,("gpo_parse_gplink: processing link #%d\n", i));
+
+ q = link_list[i];
+ if (q[0] == '[') {
+ q++;
+ };
+
+ p = strchr(q, ';');
+
+ if (p == NULL) {
+ goto parse_error;
+ }
+
+ gp_link->link_names[i] = talloc_strdup(mem_ctx, q);
+ if (gp_link->link_names[i] == NULL) {
+ goto parse_error;
+ }
+ gp_link->link_names[i][PTR_DIFF(p, q)] = 0;
+
+ gp_link->link_opts[i] = atoi(p + 1);
+
+ DEBUGADD(10,("gpo_parse_gplink: link: %s\n",
+ gp_link->link_names[i]));
+ DEBUGADD(10,("gpo_parse_gplink: opt: %d\n",
+ gp_link->link_opts[i]));
+
+ }
+
+ status = ADS_SUCCESS;
+
+ parse_error:
+ TALLOC_FREE(link_list);
+
+ return status;
+}
+
+/****************************************************************
+ helper call to get a GP_LINK structure from a linkdn
+****************************************************************/
+
+ADS_STATUS ads_get_gpo_link(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *link_dn,
+ struct GP_LINK *gp_link_struct)
+{
+ ADS_STATUS status;
+ const char *attrs[] = {"gPLink", "gPOptions", NULL};
+ LDAPMessage *res = NULL;
+ const char *gp_link;
+ uint32_t gp_options;
+
+ ZERO_STRUCTP(gp_link_struct);
+
+ status = ads_search_dn(ads, &res, link_dn, attrs);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(10,("ads_get_gpo_link: search failed with %s\n",
+ ads_errstr(status)));
+ return status;
+ }
+
+ if (ads_count_replies(ads, res) != 1) {
+ DEBUG(10,("ads_get_gpo_link: no result\n"));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink");
+ if (gp_link == NULL) {
+ DEBUG(10,("ads_get_gpo_link: no 'gPLink' attribute found\n"));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ }
+
+ /* perfectly legal to have no options */
+ if (!ads_pull_uint32(ads, res, "gPOptions", &gp_options)) {
+ DEBUG(10,("ads_get_gpo_link: "
+ "no 'gPOptions' attribute found\n"));
+ gp_options = 0;
+ }
+
+ ads_msgfree(ads, res);
+
+ return gpo_parse_gplink(mem_ctx, gp_link, gp_options, gp_link_struct);
+}
+
+/****************************************************************
+ helper call to add a gp link
+****************************************************************/
+
+ADS_STATUS ads_add_gpo_link(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *link_dn,
+ const char *gpo_dn,
+ uint32_t gpo_opt)
+{
+ ADS_STATUS status;
+ const char *attrs[] = {"gPLink", NULL};
+ LDAPMessage *res = NULL;
+ const char *gp_link, *gp_link_new;
+ ADS_MODLIST mods;
+
+ /* although ADS allows to set anything here, we better check here if
+ * the gpo_dn is sane */
+
+ if (!strnequal(gpo_dn, "LDAP://CN={", strlen("LDAP://CN={")) != 0) {
+ return ADS_ERROR(LDAP_INVALID_DN_SYNTAX);
+ }
+
+ status = ads_search_dn(ads, &res, link_dn, attrs);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(10,("ads_add_gpo_link: search failed with %s\n",
+ ads_errstr(status)));
+ return status;
+ }
+
+ if (ads_count_replies(ads, res) != 1) {
+ DEBUG(10,("ads_add_gpo_link: no result\n"));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink");
+ if (gp_link == NULL) {
+ gp_link_new = talloc_asprintf(mem_ctx, "[%s;%d]",
+ gpo_dn, gpo_opt);
+ } else {
+ gp_link_new = talloc_asprintf(mem_ctx, "%s[%s;%d]",
+ gp_link, gpo_dn, gpo_opt);
+ }
+
+ ads_msgfree(ads, res);
+ ADS_ERROR_HAVE_NO_MEMORY(gp_link_new);
+
+ mods = ads_init_mods(mem_ctx);
+ ADS_ERROR_HAVE_NO_MEMORY(mods);
+
+ status = ads_mod_str(mem_ctx, &mods, "gPLink", gp_link_new);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ return ads_gen_mod(ads, link_dn, mods);
+}
+
+/****************************************************************
+ helper call to delete add a gp link
+****************************************************************/
+
+/* untested & broken */
+ADS_STATUS ads_delete_gpo_link(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *link_dn,
+ const char *gpo_dn)
+{
+ ADS_STATUS status;
+ const char *attrs[] = {"gPLink", NULL};
+ LDAPMessage *res = NULL;
+ const char *gp_link, *gp_link_new = NULL;
+ ADS_MODLIST mods;
+
+ /* check for a sane gpo_dn */
+ if (gpo_dn[0] != '[') {
+ DEBUG(10,("ads_delete_gpo_link: first char not: [\n"));
+ return ADS_ERROR(LDAP_INVALID_DN_SYNTAX);
+ }
+
+ if (gpo_dn[strlen(gpo_dn)] != ']') {
+ DEBUG(10,("ads_delete_gpo_link: last char not: ]\n"));
+ return ADS_ERROR(LDAP_INVALID_DN_SYNTAX);
+ }
+
+ status = ads_search_dn(ads, &res, link_dn, attrs);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(10,("ads_delete_gpo_link: search failed with %s\n",
+ ads_errstr(status)));
+ return status;
+ }
+
+ if (ads_count_replies(ads, res) != 1) {
+ DEBUG(10,("ads_delete_gpo_link: no result\n"));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink");
+ if (gp_link == NULL) {
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ }
+
+ /* find link to delete */
+ /* gp_link_new = talloc_asprintf(mem_ctx, "%s[%s;%d]", gp_link,
+ gpo_dn, gpo_opt); */
+
+ ads_msgfree(ads, res);
+ ADS_ERROR_HAVE_NO_MEMORY(gp_link_new);
+
+ mods = ads_init_mods(mem_ctx);
+ ADS_ERROR_HAVE_NO_MEMORY(mods);
+
+ status = ads_mod_str(mem_ctx, &mods, "gPLink", gp_link_new);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ return ads_gen_mod(ads, link_dn, mods);
+}
+
+/****************************************************************
+ parse a GROUP_POLICY_OBJECT structure from an LDAPMessage result
+****************************************************************/
+
+ ADS_STATUS ads_parse_gpo(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ LDAPMessage *res,
+ const char *gpo_dn,
+ struct GROUP_POLICY_OBJECT *gpo)
+{
+ ZERO_STRUCTP(gpo);
+
+ ADS_ERROR_HAVE_NO_MEMORY(res);
+
+ if (gpo_dn) {
+ gpo->ds_path = talloc_strdup(mem_ctx, gpo_dn);
+ } else {
+ gpo->ds_path = ads_get_dn(ads, res);
+ }
+
+ ADS_ERROR_HAVE_NO_MEMORY(gpo->ds_path);
+
+ if (!ads_pull_uint32(ads, res, "versionNumber", &gpo->version)) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ if (!ads_pull_uint32(ads, res, "flags", &gpo->options)) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ gpo->file_sys_path = ads_pull_string(ads, mem_ctx, res,
+ "gPCFileSysPath");
+ ADS_ERROR_HAVE_NO_MEMORY(gpo->file_sys_path);
+
+ gpo->display_name = ads_pull_string(ads, mem_ctx, res,
+ "displayName");
+ ADS_ERROR_HAVE_NO_MEMORY(gpo->display_name);
+
+ gpo->name = ads_pull_string(ads, mem_ctx, res,
+ "name");
+ ADS_ERROR_HAVE_NO_MEMORY(gpo->name);
+
+ gpo->machine_extensions = ads_pull_string(ads, mem_ctx, res,
+ "gPCMachineExtensionNames");
+ gpo->user_extensions = ads_pull_string(ads, mem_ctx, res,
+ "gPCUserExtensionNames");
+
+ ads_pull_sd(ads, mem_ctx, res, "ntSecurityDescriptor",
+ &gpo->security_descriptor);
+ ADS_ERROR_HAVE_NO_MEMORY(gpo->security_descriptor);
+
+ return ADS_ERROR(LDAP_SUCCESS);
+}
+
+/****************************************************************
+ get a GROUP_POLICY_OBJECT structure based on different input paramters
+****************************************************************/
+
+ADS_STATUS ads_get_gpo(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *gpo_dn,
+ const char *display_name,
+ const char *guid_name,
+ struct GROUP_POLICY_OBJECT *gpo)
+{
+ ADS_STATUS status;
+ LDAPMessage *res = NULL;
+ char *dn;
+ const char *filter;
+ const char *attrs[] = {
+ "cn",
+ "displayName",
+ "flags",
+ "gPCFileSysPath",
+ "gPCFunctionalityVersion",
+ "gPCMachineExtensionNames",
+ "gPCUserExtensionNames",
+ "gPCWQLFilter",
+ "name",
+ "ntSecurityDescriptor",
+ "versionNumber",
+ NULL};
+ uint32_t sd_flags = DACL_SECURITY_INFORMATION;
+
+ ZERO_STRUCTP(gpo);
+
+ if (!gpo_dn && !display_name && !guid_name) {
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ if (gpo_dn) {
+
+ if (strnequal(gpo_dn, "LDAP://", strlen("LDAP://")) != 0) {
+ gpo_dn = gpo_dn + strlen("LDAP://");
+ }
+
+ status = ads_search_retry_dn_sd_flags(ads, &res,
+ sd_flags,
+ gpo_dn, attrs);
+
+ } else if (display_name || guid_name) {
+
+ filter = talloc_asprintf(mem_ctx,
+ "(&(objectclass=groupPolicyContainer)(%s=%s))",
+ display_name ? "displayName" : "name",
+ display_name ? display_name : guid_name);
+ ADS_ERROR_HAVE_NO_MEMORY(filter);
+
+ status = ads_do_search_all_sd_flags(ads, ads->config.bind_path,
+ LDAP_SCOPE_SUBTREE, filter,
+ attrs, sd_flags, &res);
+ }
+
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(10,("ads_get_gpo: search failed with %s\n",
+ ads_errstr(status)));
+ return status;
+ }
+
+ if (ads_count_replies(ads, res) != 1) {
+ DEBUG(10,("ads_get_gpo: no result\n"));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ dn = ads_get_dn(ads, res);
+ if (dn == NULL) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ status = ads_parse_gpo(ads, mem_ctx, res, dn, gpo);
+ ads_msgfree(ads, res);
+ ads_memfree(ads, dn);
+
+ return status;
+}
+
+/****************************************************************
+ add a gplink to the GROUP_POLICY_OBJECT linked list
+****************************************************************/
+
+static ADS_STATUS add_gplink_to_gpo_list(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ struct GROUP_POLICY_OBJECT **gpo_list,
+ const char *link_dn,
+ struct GP_LINK *gp_link,
+ enum GPO_LINK_TYPE link_type,
+ bool only_add_forced_gpos,
+ const struct nt_user_token *token)
+{
+ ADS_STATUS status;
+ int i;
+
+ for (i = 0; i < gp_link->num_links; i++) {
+
+ struct GROUP_POLICY_OBJECT *new_gpo = NULL;
+
+ if (gp_link->link_opts[i] & GPO_LINK_OPT_DISABLED) {
+ DEBUG(10,("skipping disabled GPO\n"));
+ continue;
+ }
+
+ if (only_add_forced_gpos) {
+
+ if (!(gp_link->link_opts[i] & GPO_LINK_OPT_ENFORCED)) {
+ DEBUG(10,("skipping nonenforced GPO link "
+ "because GPOPTIONS_BLOCK_INHERITANCE "
+ "has been set\n"));
+ continue;
+ } else {
+ DEBUG(10,("adding enforced GPO link although "
+ "the GPOPTIONS_BLOCK_INHERITANCE "
+ "has been set\n"));
+ }
+ }
+
+ new_gpo = TALLOC_ZERO_P(mem_ctx, struct GROUP_POLICY_OBJECT);
+ ADS_ERROR_HAVE_NO_MEMORY(new_gpo);
+
+ status = ads_get_gpo(ads, mem_ctx, gp_link->link_names[i],
+ NULL, NULL, new_gpo);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(10,("failed to get gpo: %s\n",
+ gp_link->link_names[i]));
+ return status;
+ }
+
+ status = ADS_ERROR_NT(gpo_apply_security_filtering(new_gpo,
+ token));
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(10,("skipping GPO \"%s\" as object "
+ "has no access to it\n",
+ new_gpo->display_name));
+ TALLOC_FREE(new_gpo);
+ continue;
+ }
+
+ new_gpo->link = link_dn;
+ new_gpo->link_type = link_type;
+
+ DLIST_ADD(*gpo_list, new_gpo);
+
+ DEBUG(10,("add_gplink_to_gplist: added GPLINK #%d %s "
+ "to GPO list\n", i, gp_link->link_names[i]));
+ }
+
+ return ADS_ERROR(LDAP_SUCCESS);
+}
+
+/****************************************************************
+****************************************************************/
+
+ADS_STATUS ads_get_sid_token(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *dn,
+ struct nt_user_token **token)
+{
+ ADS_STATUS status;
+ DOM_SID object_sid;
+ DOM_SID primary_group_sid;
+ DOM_SID *ad_token_sids;
+ size_t num_ad_token_sids = 0;
+ DOM_SID *token_sids;
+ size_t num_token_sids = 0;
+ struct nt_user_token *new_token = NULL;
+ int i;
+
+ status = ads_get_tokensids(ads, mem_ctx, dn,
+ &object_sid, &primary_group_sid,
+ &ad_token_sids, &num_ad_token_sids);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ token_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, 1);
+ ADS_ERROR_HAVE_NO_MEMORY(token_sids);
+
+ status = ADS_ERROR_NT(add_sid_to_array_unique(mem_ctx,
+ &primary_group_sid,
+ &token_sids,
+ &num_token_sids));
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ for (i = 0; i < num_ad_token_sids; i++) {
+
+ if (sid_check_is_in_builtin(&ad_token_sids[i])) {
+ continue;
+ }
+
+ status = ADS_ERROR_NT(add_sid_to_array_unique(mem_ctx,
+ &ad_token_sids[i],
+ &token_sids,
+ &num_token_sids));
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+ }
+
+ new_token = create_local_nt_token(mem_ctx, &object_sid, false,
+ num_token_sids, token_sids);
+ ADS_ERROR_HAVE_NO_MEMORY(new_token);
+
+ *token = new_token;
+
+ debug_nt_user_token(DBGC_CLASS, 5, *token);
+
+ return ADS_ERROR_LDAP(LDAP_SUCCESS);
+}
+
+/****************************************************************
+****************************************************************/
+
+static ADS_STATUS add_local_policy_to_gpo_list(TALLOC_CTX *mem_ctx,
+ struct GROUP_POLICY_OBJECT **gpo_list,
+ enum GPO_LINK_TYPE link_type)
+{
+ struct GROUP_POLICY_OBJECT *gpo = NULL;
+
+ ADS_ERROR_HAVE_NO_MEMORY(gpo_list);
+
+ gpo = TALLOC_ZERO_P(mem_ctx, struct GROUP_POLICY_OBJECT);
+ ADS_ERROR_HAVE_NO_MEMORY(gpo);
+
+ gpo->name = talloc_strdup(mem_ctx, "Local Policy");
+ ADS_ERROR_HAVE_NO_MEMORY(gpo->name);
+
+ gpo->display_name = talloc_strdup(mem_ctx, "Local Policy");
+ ADS_ERROR_HAVE_NO_MEMORY(gpo->display_name);
+
+ gpo->link_type = link_type;
+
+ DLIST_ADD(*gpo_list, gpo);
+
+ return ADS_ERROR_NT(NT_STATUS_OK);
+}
+
+/****************************************************************
+ get the full list of GROUP_POLICY_OBJECTs for a given dn
+****************************************************************/
+
+ADS_STATUS ads_get_gpo_list(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *dn,
+ uint32_t flags,
+ const struct nt_user_token *token,
+ struct GROUP_POLICY_OBJECT **gpo_list)
+{
+ /* (L)ocal (S)ite (D)omain (O)rganizational(U)nit */
+
+ ADS_STATUS status;
+ struct GP_LINK gp_link;
+ const char *parent_dn, *site_dn, *tmp_dn;
+ bool add_only_forced_gpos = false;
+
+ ZERO_STRUCTP(gpo_list);
+
+ if (!dn) {
+ return ADS_ERROR(LDAP_PARAM_ERROR);
+ }
+
+ DEBUG(10,("ads_get_gpo_list: getting GPO list for [%s]\n", dn));
+
+ /* (L)ocal */
+ status = add_local_policy_to_gpo_list(mem_ctx, gpo_list,
+ GP_LINK_LOCAL);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ /* (S)ite */
+
+ /* are site GPOs valid for users as well ??? */
+ if (flags & GPO_LIST_FLAG_MACHINE) {
+
+ status = ads_site_dn_for_machine(ads, mem_ctx,
+ ads->config.ldap_server_name,
+ &site_dn);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ DEBUG(10,("ads_get_gpo_list: query SITE: [%s] for GPOs\n",
+ site_dn));
+
+ status = ads_get_gpo_link(ads, mem_ctx, site_dn, &gp_link);
+ if (ADS_ERR_OK(status)) {
+
+ if (DEBUGLEVEL >= 100) {
+ dump_gplink(ads, mem_ctx, &gp_link);
+ }
+
+ status = add_gplink_to_gpo_list(ads, mem_ctx, gpo_list,
+ site_dn, &gp_link,
+ GP_LINK_SITE,
+ add_only_forced_gpos,
+ token);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ if (flags & GPO_LIST_FLAG_SITEONLY) {
+ return ADS_ERROR(LDAP_SUCCESS);
+ }
+
+ /* inheritance can't be blocked at the site level */
+ }
+ }
+
+ tmp_dn = dn;
+
+ while ((parent_dn = ads_parent_dn(tmp_dn)) &&
+ (!strequal(parent_dn, ads_parent_dn(ads->config.bind_path)))) {
+
+ /* (D)omain */
+
+ /* An account can just be a member of one domain */
+ if (strncmp(parent_dn, "DC=", strlen("DC=")) == 0) {
+
+ DEBUG(10,("ads_get_gpo_list: query DC: [%s] for GPOs\n",
+ parent_dn));
+
+ status = ads_get_gpo_link(ads, mem_ctx, parent_dn,
+ &gp_link);
+ if (ADS_ERR_OK(status)) {
+
+ if (DEBUGLEVEL >= 100) {
+ dump_gplink(ads, mem_ctx, &gp_link);
+ }
+
+ /* block inheritance from now on */
+ if (gp_link.gp_opts &
+ GPOPTIONS_BLOCK_INHERITANCE) {
+ add_only_forced_gpos = true;
+ }
+
+ status = add_gplink_to_gpo_list(ads,
+ mem_ctx,
+ gpo_list,
+ parent_dn,
+ &gp_link,
+ GP_LINK_DOMAIN,
+ add_only_forced_gpos,
+ token);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+ }
+ }
+
+ tmp_dn = parent_dn;
+ }
+
+ /* reset dn again */
+ tmp_dn = dn;
+
+ while ((parent_dn = ads_parent_dn(tmp_dn)) &&
+ (!strequal(parent_dn, ads_parent_dn(ads->config.bind_path)))) {
+
+
+ /* (O)rganizational(U)nit */
+
+ /* An account can be a member of more OUs */
+ if (strncmp(parent_dn, "OU=", strlen("OU=")) == 0) {
+
+ DEBUG(10,("ads_get_gpo_list: query OU: [%s] for GPOs\n",
+ parent_dn));
+
+ status = ads_get_gpo_link(ads, mem_ctx, parent_dn,
+ &gp_link);
+ if (ADS_ERR_OK(status)) {
+
+ if (DEBUGLEVEL >= 100) {
+ dump_gplink(ads, mem_ctx, &gp_link);
+ }
+
+ /* block inheritance from now on */
+ if (gp_link.gp_opts &
+ GPOPTIONS_BLOCK_INHERITANCE) {
+ add_only_forced_gpos = true;
+ }
+
+ status = add_gplink_to_gpo_list(ads,
+ mem_ctx,
+ gpo_list,
+ parent_dn,
+ &gp_link,
+ GP_LINK_OU,
+ add_only_forced_gpos,
+ token);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+ }
+ }
+
+ tmp_dn = parent_dn;
+
+ };
+
+ return ADS_ERROR(LDAP_SUCCESS);
+}
+
+#endif /* HAVE_LDAP */
diff --git a/source3/libgpo/gpo_reg.c b/source3/libgpo/gpo_reg.c
new file mode 100644
index 0000000000..920deeb189
--- /dev/null
+++ b/source3/libgpo/gpo_reg.c
@@ -0,0 +1,1009 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Object Support
+ * Copyright (C) Guenther Deschner 2007-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+
+/****************************************************************
+****************************************************************/
+
+struct nt_user_token *registry_create_system_token(TALLOC_CTX *mem_ctx)
+{
+ struct nt_user_token *token = NULL;
+
+ token = TALLOC_ZERO_P(mem_ctx, struct nt_user_token);
+ if (!token) {
+ DEBUG(1,("talloc failed\n"));
+ return NULL;
+ }
+
+ token->privileges = se_priv_all;
+
+ if (!NT_STATUS_IS_OK(add_sid_to_array(token, &global_sid_System,
+ &token->user_sids, &token->num_sids))) {
+ DEBUG(1,("Error adding nt-authority system sid to token\n"));
+ return NULL;
+ }
+
+ return token;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_init_reg_ctx(TALLOC_CTX *mem_ctx,
+ const char *initial_path,
+ uint32_t desired_access,
+ const struct nt_user_token *token,
+ struct gp_registry_context **reg_ctx)
+{
+ struct gp_registry_context *tmp_ctx;
+ WERROR werr;
+
+ if (!reg_ctx) {
+ return WERR_INVALID_PARAM;
+ }
+
+ werr = registry_init_basic();
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ tmp_ctx = TALLOC_ZERO_P(mem_ctx, struct gp_registry_context);
+ W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
+
+ if (token) {
+ tmp_ctx->token = token;
+ } else {
+ tmp_ctx->token = registry_create_system_token(mem_ctx);
+ }
+ if (!tmp_ctx->token) {
+ TALLOC_FREE(tmp_ctx);
+ return WERR_NOMEM;
+ }
+
+ werr = regdb_open();
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ if (initial_path) {
+ tmp_ctx->path = talloc_strdup(mem_ctx, initial_path);
+ if (!tmp_ctx->path) {
+ TALLOC_FREE(tmp_ctx);
+ return WERR_NOMEM;
+ }
+
+ werr = reg_open_path(mem_ctx, tmp_ctx->path, desired_access,
+ tmp_ctx->token, &tmp_ctx->curr_key);
+ if (!W_ERROR_IS_OK(werr)) {
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+ }
+ }
+
+ *reg_ctx = tmp_ctx;
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+void gp_free_reg_ctx(struct gp_registry_context *reg_ctx)
+{
+ TALLOC_FREE(reg_ctx);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_store_reg_subkey(TALLOC_CTX *mem_ctx,
+ const char *subkeyname,
+ struct registry_key *curr_key,
+ struct registry_key **new_key)
+{
+ enum winreg_CreateAction action = REG_ACTION_NONE;
+ WERROR werr;
+
+ werr = reg_createkey(mem_ctx, curr_key, subkeyname,
+ REG_KEY_WRITE, new_key, &action);
+ if (W_ERROR_IS_OK(werr) && (action != REG_CREATED_NEW_KEY)) {
+ return WERR_OK;
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_read_reg_subkey(TALLOC_CTX *mem_ctx,
+ struct gp_registry_context *reg_ctx,
+ const char *subkeyname,
+ struct registry_key **key)
+{
+ const char *tmp = NULL;
+
+ if (!reg_ctx || !subkeyname || !key) {
+ return WERR_INVALID_PARAM;
+ }
+
+ tmp = talloc_asprintf(mem_ctx, "%s\\%s", reg_ctx->path, subkeyname);
+ W_ERROR_HAVE_NO_MEMORY(tmp);
+
+ return reg_open_path(mem_ctx, tmp, REG_KEY_READ,
+ reg_ctx->token, key);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_store_reg_val_sz(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ const char *val_name,
+ const char *val)
+{
+ struct registry_value reg_val;
+ ZERO_STRUCT(reg_val);
+
+ /* FIXME: hack */
+ val = val ? val : " ";
+
+ reg_val.type = REG_SZ;
+ reg_val.v.sz.len = strlen(val);
+ reg_val.v.sz.str = talloc_strdup(mem_ctx, val);
+ W_ERROR_HAVE_NO_MEMORY(reg_val.v.sz.str);
+
+ return reg_setvalue(key, val_name, &reg_val);
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_store_reg_val_dword(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ const char *val_name,
+ uint32_t val)
+{
+ struct registry_value reg_val;
+ ZERO_STRUCT(reg_val);
+
+ reg_val.type = REG_DWORD;
+ reg_val.v.dword = val;
+
+ return reg_setvalue(key, val_name, &reg_val);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_read_reg_val_sz(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ const char *val_name,
+ const char **val)
+{
+ WERROR werr;
+ struct registry_value *reg_val = NULL;
+
+ werr = reg_queryvalue(mem_ctx, key, val_name, &reg_val);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ if (reg_val->type != REG_SZ) {
+ return WERR_INVALID_DATATYPE;
+ }
+
+ *val = talloc_strdup(mem_ctx, reg_val->v.sz.str);
+ W_ERROR_HAVE_NO_MEMORY(*val);
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_read_reg_val_dword(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ const char *val_name,
+ uint32_t *val)
+{
+ WERROR werr;
+ struct registry_value *reg_val = NULL;
+
+ werr = reg_queryvalue(mem_ctx, key, val_name, &reg_val);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ if (reg_val->type != REG_DWORD) {
+ return WERR_INVALID_DATATYPE;
+ }
+
+ *val = reg_val->v.dword;
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_store_reg_gpovals(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ struct GROUP_POLICY_OBJECT *gpo)
+{
+ WERROR werr;
+
+ if (!key || !gpo) {
+ return WERR_INVALID_PARAM;
+ }
+
+ werr = gp_store_reg_val_dword(mem_ctx, key, "Version",
+ gpo->version);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_dword(mem_ctx, key, "WQLFilterPass",
+ true); /* fake */
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_dword(mem_ctx, key, "AccessDenied",
+ false); /* fake */
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_dword(mem_ctx, key, "GPO-Disabled",
+ (gpo->options & GPO_FLAG_DISABLE));
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_dword(mem_ctx, key, "Options",
+ gpo->options);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_sz(mem_ctx, key, "GPOID",
+ gpo->name);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_sz(mem_ctx, key, "SOM",
+ gpo->link);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_sz(mem_ctx, key, "DisplayName",
+ gpo->display_name);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_sz(mem_ctx, key, "WQL-Id",
+ NULL);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static const char *gp_reg_groupmembership_path(TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ uint32_t flags)
+{
+ if (flags & GPO_LIST_FLAG_MACHINE) {
+ return "GroupMembership";
+ }
+
+ return talloc_asprintf(mem_ctx, "%s\\%s", sid_string_tos(sid),
+ "GroupMembership");
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_reg_del_groupmembership(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ const struct nt_user_token *token,
+ uint32_t flags)
+{
+ const char *path = NULL;
+
+ path = gp_reg_groupmembership_path(mem_ctx, &token->user_sids[0],
+ flags);
+ W_ERROR_HAVE_NO_MEMORY(path);
+
+ return reg_deletekey_recursive(mem_ctx, key, path);
+
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_reg_store_groupmembership(TALLOC_CTX *mem_ctx,
+ struct gp_registry_context *reg_ctx,
+ const struct nt_user_token *token,
+ uint32_t flags)
+{
+ struct registry_key *key = NULL;
+ WERROR werr;
+ int i = 0;
+ const char *valname = NULL;
+ const char *path = NULL;
+ const char *val = NULL;
+ int count = 0;
+
+ path = gp_reg_groupmembership_path(mem_ctx, &token->user_sids[0],
+ flags);
+ W_ERROR_HAVE_NO_MEMORY(path);
+
+ gp_reg_del_groupmembership(mem_ctx, reg_ctx->curr_key, token, flags);
+
+ werr = gp_store_reg_subkey(mem_ctx, path,
+ reg_ctx->curr_key, &key);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ for (i=0; i<token->num_sids; i++) {
+
+ valname = talloc_asprintf(mem_ctx, "Group%d", count++);
+ W_ERROR_HAVE_NO_MEMORY(valname);
+
+ val = sid_string_talloc(mem_ctx, &token->user_sids[i]);
+ W_ERROR_HAVE_NO_MEMORY(val);
+ werr = gp_store_reg_val_sz(mem_ctx, key, valname, val);
+ W_ERROR_NOT_OK_RETURN(werr);
+ }
+
+ werr = gp_store_reg_val_dword(mem_ctx, key, "Count", count);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+#if 0
+/* not used yet */
+static WERROR gp_reg_read_groupmembership(TALLOC_CTX *mem_ctx,
+ struct gp_registry_context *reg_ctx,
+ const DOM_SID *object_sid,
+ struct nt_user_token **token,
+ uint32_t flags)
+{
+ struct registry_key *key = NULL;
+ WERROR werr;
+ int i = 0;
+ const char *valname = NULL;
+ const char *val = NULL;
+ const char *path = NULL;
+ uint32_t count = 0;
+ int num_token_sids = 0;
+ struct nt_user_token *tmp_token = NULL;
+
+ tmp_token = TALLOC_ZERO_P(mem_ctx, struct nt_user_token);
+ W_ERROR_HAVE_NO_MEMORY(tmp_token);
+
+ path = gp_reg_groupmembership_path(mem_ctx, object_sid, flags);
+ W_ERROR_HAVE_NO_MEMORY(path);
+
+ werr = gp_read_reg_subkey(mem_ctx, reg_ctx, path, &key);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_read_reg_val_dword(mem_ctx, key, "Count", &count);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ for (i=0; i<count; i++) {
+
+ valname = talloc_asprintf(mem_ctx, "Group%d", i);
+ W_ERROR_HAVE_NO_MEMORY(valname);
+
+ werr = gp_read_reg_val_sz(mem_ctx, key, valname, &val);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ if (!string_to_sid(&tmp_token->user_sids[num_token_sids++],
+ val)) {
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+ }
+
+ tmp_token->num_sids = num_token_sids;
+
+ *token = tmp_token;
+
+ return WERR_OK;
+}
+#endif
+/****************************************************************
+****************************************************************/
+
+static const char *gp_req_state_path(TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ uint32_t flags)
+{
+ if (flags & GPO_LIST_FLAG_MACHINE) {
+ return GPO_REG_STATE_MACHINE;
+ }
+
+ return talloc_asprintf(mem_ctx, "%s\\%s", "State", sid_string_tos(sid));
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_del_reg_state(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ const char *path)
+{
+ return reg_deletesubkeys_recursive(mem_ctx, key, path);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_reg_state_store(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const char *dn,
+ const struct nt_user_token *token,
+ struct GROUP_POLICY_OBJECT *gpo_list)
+{
+ struct gp_registry_context *reg_ctx = NULL;
+ WERROR werr = WERR_GENERAL_FAILURE;
+ const char *subkeyname = NULL;
+ struct GROUP_POLICY_OBJECT *gpo;
+ int count = 0;
+ struct registry_key *key;
+
+ werr = gp_init_reg_ctx(mem_ctx, KEY_GROUP_POLICY, REG_KEY_WRITE,
+ token, &reg_ctx);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_secure_key(mem_ctx, flags, reg_ctx->curr_key,
+ &token->user_sids[0]);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("failed to secure key: %s\n", dos_errstr(werr)));
+ goto done;
+ }
+
+ werr = gp_reg_store_groupmembership(mem_ctx, reg_ctx, token, flags);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("failed to store group membership: %s\n", dos_errstr(werr)));
+ goto done;
+ }
+
+ subkeyname = gp_req_state_path(mem_ctx, &token->user_sids[0], flags);
+ if (!subkeyname) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ werr = gp_del_reg_state(mem_ctx, reg_ctx->curr_key, subkeyname);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("failed to delete old state: %s\n", dos_errstr(werr)));
+ /* goto done; */
+ }
+
+ werr = gp_store_reg_subkey(mem_ctx, subkeyname,
+ reg_ctx->curr_key, &reg_ctx->curr_key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = gp_store_reg_val_sz(mem_ctx, reg_ctx->curr_key,
+ "Distinguished-Name", dn);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ /* store link list */
+
+ werr = gp_store_reg_subkey(mem_ctx, "GPLink-List",
+ reg_ctx->curr_key, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ /* store gpo list */
+
+ werr = gp_store_reg_subkey(mem_ctx, "GPO-List",
+ reg_ctx->curr_key, &reg_ctx->curr_key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ for (gpo = gpo_list; gpo; gpo = gpo->next) {
+
+ subkeyname = talloc_asprintf(mem_ctx, "%d", count++);
+ if (!subkeyname) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ werr = gp_store_reg_subkey(mem_ctx, subkeyname,
+ reg_ctx->curr_key, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = gp_store_reg_gpovals(mem_ctx, key, gpo);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("gp_reg_state_store: "
+ "gpo_store_reg_gpovals failed for %s: %s\n",
+ gpo->display_name, dos_errstr(werr)));
+ goto done;
+ }
+ }
+ done:
+ gp_free_reg_ctx(reg_ctx);
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_read_reg_gpovals(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ struct GROUP_POLICY_OBJECT *gpo)
+{
+ WERROR werr;
+
+ if (!key || !gpo) {
+ return WERR_INVALID_PARAM;
+ }
+
+ werr = gp_read_reg_val_dword(mem_ctx, key, "Version",
+ &gpo->version);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_read_reg_val_dword(mem_ctx, key, "Options",
+ &gpo->options);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_read_reg_val_sz(mem_ctx, key, "GPOID",
+ &gpo->name);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_read_reg_val_sz(mem_ctx, key, "SOM",
+ &gpo->link);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_read_reg_val_sz(mem_ctx, key, "DisplayName",
+ &gpo->display_name);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_read_reg_gpo(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ struct GROUP_POLICY_OBJECT **gpo_ret)
+{
+ struct GROUP_POLICY_OBJECT *gpo = NULL;
+ WERROR werr;
+
+ if (!gpo_ret || !key) {
+ return WERR_INVALID_PARAM;
+ }
+
+ gpo = TALLOC_ZERO_P(mem_ctx, struct GROUP_POLICY_OBJECT);
+ W_ERROR_HAVE_NO_MEMORY(gpo);
+
+ werr = gp_read_reg_gpovals(mem_ctx, key, gpo);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ *gpo_ret = gpo;
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_reg_state_read(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const DOM_SID *sid,
+ struct GROUP_POLICY_OBJECT **gpo_list)
+{
+ struct gp_registry_context *reg_ctx = NULL;
+ WERROR werr = WERR_GENERAL_FAILURE;
+ const char *subkeyname = NULL;
+ struct GROUP_POLICY_OBJECT *gpo = NULL;
+ int count = 0;
+ struct registry_key *key = NULL;
+ const char *path = NULL;
+ const char *gp_state_path = NULL;
+
+ if (!gpo_list) {
+ return WERR_INVALID_PARAM;
+ }
+
+ ZERO_STRUCTP(gpo_list);
+
+ gp_state_path = gp_req_state_path(mem_ctx, sid, flags);
+ if (!gp_state_path) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ path = talloc_asprintf(mem_ctx, "%s\\%s\\%s",
+ KEY_GROUP_POLICY,
+ gp_state_path,
+ "GPO-List");
+ if (!path) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ werr = gp_init_reg_ctx(mem_ctx, path, REG_KEY_READ, NULL, &reg_ctx);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ while (1) {
+
+ subkeyname = talloc_asprintf(mem_ctx, "%d", count++);
+ if (!subkeyname) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ werr = gp_read_reg_subkey(mem_ctx, reg_ctx, subkeyname, &key);
+ if (W_ERROR_EQUAL(werr, WERR_BADFILE)) {
+ werr = WERR_OK;
+ break;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("gp_reg_state_read: "
+ "gp_read_reg_subkey gave: %s\n",
+ dos_errstr(werr)));
+ goto done;
+ }
+
+ werr = gp_read_reg_gpo(mem_ctx, key, &gpo);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ DLIST_ADD(*gpo_list, gpo);
+ }
+
+ done:
+ gp_free_reg_ctx(reg_ctx);
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_reg_generate_sd(TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ struct security_descriptor **sd,
+ size_t *sd_size)
+{
+ SEC_ACE ace[6];
+ SEC_ACCESS mask;
+
+ SEC_ACL *acl = NULL;
+
+ uint8_t inherit_flags;
+
+ init_sec_access(&mask, REG_KEY_ALL);
+ init_sec_ace(&ace[0],
+ &global_sid_System,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ mask, 0);
+
+ init_sec_access(&mask, REG_KEY_ALL);
+ init_sec_ace(&ace[1],
+ &global_sid_Builtin_Administrators,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ mask, 0);
+
+ init_sec_access(&mask, REG_KEY_READ);
+ init_sec_ace(&ace[2],
+ sid ? sid : &global_sid_Authenticated_Users,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ mask, 0);
+
+ inherit_flags = SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT |
+ SEC_ACE_FLAG_INHERIT_ONLY;
+
+ init_sec_access(&mask, REG_KEY_ALL);
+ init_sec_ace(&ace[3],
+ &global_sid_System,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ mask, inherit_flags);
+
+ init_sec_access(&mask, REG_KEY_ALL);
+ init_sec_ace(&ace[4],
+ &global_sid_Builtin_Administrators,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ mask, inherit_flags);
+
+ init_sec_access(&mask, REG_KEY_READ);
+ init_sec_ace(&ace[5],
+ sid ? sid : &global_sid_Authenticated_Users,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ mask, inherit_flags);
+
+ acl = make_sec_acl(mem_ctx, NT4_ACL_REVISION, 6, ace);
+ W_ERROR_HAVE_NO_MEMORY(acl);
+
+ *sd = make_sec_desc(mem_ctx, SEC_DESC_REVISION,
+ SEC_DESC_SELF_RELATIVE |
+ SEC_DESC_DACL_AUTO_INHERITED | /* really ? */
+ SEC_DESC_DACL_AUTO_INHERIT_REQ, /* really ? */
+ NULL, NULL, NULL,
+ acl, sd_size);
+ W_ERROR_HAVE_NO_MEMORY(*sd);
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_secure_key(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct registry_key *key,
+ const DOM_SID *sid)
+{
+ struct security_descriptor *sd = NULL;
+ size_t sd_size = 0;
+ const DOM_SID *sd_sid = NULL;
+ WERROR werr;
+
+ if (!(flags & GPO_LIST_FLAG_MACHINE)) {
+ sd_sid = sid;
+ }
+
+ werr = gp_reg_generate_sd(mem_ctx, sd_sid, &sd, &sd_size);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ return reg_setkeysecurity(key, sd);
+}
+
+/****************************************************************
+****************************************************************/
+
+void dump_reg_val(int lvl, const char *direction,
+ const char *key, const char *subkey,
+ struct registry_value *val)
+{
+ int i = 0;
+ const char *type_str = NULL;
+
+ if (!val) {
+ DEBUG(lvl,("no val!\n"));
+ return;
+ }
+
+ type_str = reg_type_lookup(val->type);
+
+ DEBUG(lvl,("\tdump_reg_val:\t%s '%s'\n\t\t\t'%s' %s: ",
+ direction, key, subkey, type_str));
+
+ switch (val->type) {
+ case REG_DWORD:
+ DEBUG(lvl,("%d (0x%08x)\n",
+ (int)val->v.dword, val->v.dword));
+ break;
+ case REG_QWORD:
+ DEBUG(lvl,("%d (0x%016llx)\n",
+ (int)val->v.qword,
+ (unsigned long long)val->v.qword));
+ break;
+ case REG_SZ:
+ DEBUG(lvl,("%s (length: %d)\n",
+ val->v.sz.str,
+ (int)val->v.sz.len));
+ break;
+ case REG_MULTI_SZ:
+ DEBUG(lvl,("(num_strings: %d)\n",
+ val->v.multi_sz.num_strings));
+ for (i=0; i < val->v.multi_sz.num_strings; i++) {
+ DEBUGADD(lvl,("\t%s\n",
+ val->v.multi_sz.strings[i]));
+ }
+ break;
+ case REG_NONE:
+ DEBUG(lvl,("\n"));
+ break;
+ case REG_BINARY:
+ dump_data(lvl, val->v.binary.data,
+ val->v.binary.length);
+ break;
+ default:
+ DEBUG(lvl,("unsupported type: %d\n", val->type));
+ break;
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+void dump_reg_entry(uint32_t flags,
+ const char *dir,
+ struct gp_registry_entry *entry)
+{
+ if (!(flags & GPO_INFO_FLAG_VERBOSE))
+ return;
+
+ dump_reg_val(1, dir,
+ entry->key,
+ entry->value,
+ entry->data);
+}
+
+/****************************************************************
+****************************************************************/
+
+void dump_reg_entries(uint32_t flags,
+ const char *dir,
+ struct gp_registry_entry *entries,
+ size_t num_entries)
+{
+ size_t i;
+
+ if (!(flags & GPO_INFO_FLAG_VERBOSE))
+ return;
+
+ for (i=0; i < num_entries; i++) {
+ dump_reg_entry(flags, dir, &entries[i]);
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+bool add_gp_registry_entry_to_array(TALLOC_CTX *mem_ctx,
+ struct gp_registry_entry *entry,
+ struct gp_registry_entry **entries,
+ size_t *num)
+{
+ *entries = TALLOC_REALLOC_ARRAY(mem_ctx, *entries,
+ struct gp_registry_entry,
+ (*num)+1);
+
+ if (*entries == NULL) {
+ *num = 0;
+ return false;
+ }
+
+ (*entries)[*num].action = entry->action;
+ (*entries)[*num].key = entry->key;
+ (*entries)[*num].value = entry->value;
+ (*entries)[*num].data = entry->data;
+
+ *num += 1;
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static const char *gp_reg_action_str(enum gp_reg_action action)
+{
+ switch (action) {
+ case GP_REG_ACTION_NONE:
+ return "GP_REG_ACTION_NONE";
+ case GP_REG_ACTION_ADD_VALUE:
+ return "GP_REG_ACTION_ADD_VALUE";
+ case GP_REG_ACTION_ADD_KEY:
+ return "GP_REG_ACTION_ADD_KEY";
+ case GP_REG_ACTION_DEL_VALUES:
+ return "GP_REG_ACTION_DEL_VALUES";
+ case GP_REG_ACTION_DEL_VALUE:
+ return "GP_REG_ACTION_DEL_VALUE";
+ case GP_REG_ACTION_DEL_ALL_VALUES:
+ return "GP_REG_ACTION_DEL_ALL_VALUES";
+ case GP_REG_ACTION_DEL_KEYS:
+ return "GP_REG_ACTION_DEL_KEYS";
+ case GP_REG_ACTION_SEC_KEY_SET:
+ return "GP_REG_ACTION_SEC_KEY_SET";
+ case GP_REG_ACTION_SEC_KEY_RESET:
+ return "GP_REG_ACTION_SEC_KEY_RESET";
+ default:
+ return "unknown";
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR reg_apply_registry_entry(TALLOC_CTX *mem_ctx,
+ struct registry_key *root_key,
+ struct gp_registry_context *reg_ctx,
+ struct gp_registry_entry *entry,
+ const struct nt_user_token *token,
+ uint32_t flags)
+{
+ WERROR werr;
+ struct registry_key *key = NULL;
+
+ if (flags & GPO_INFO_FLAG_VERBOSE) {
+ printf("about to store key: [%s]\n", entry->key);
+ printf(" value: [%s]\n", entry->value);
+ printf(" data: [%s]\n", reg_type_lookup(entry->data->type));
+ printf(" action: [%s]\n", gp_reg_action_str(entry->action));
+ }
+
+ werr = gp_store_reg_subkey(mem_ctx, entry->key,
+ root_key, &key);
+ /* reg_ctx->curr_key, &key); */
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("gp_store_reg_subkey failed: %s\n", dos_errstr(werr)));
+ return werr;
+ }
+
+ switch (entry->action) {
+ case GP_REG_ACTION_NONE:
+ case GP_REG_ACTION_ADD_KEY:
+ return WERR_OK;
+
+ case GP_REG_ACTION_SEC_KEY_SET:
+ werr = gp_secure_key(mem_ctx, flags,
+ key,
+ &token->user_sids[0]);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("reg_apply_registry_entry: "
+ "gp_secure_key failed: %s\n",
+ dos_errstr(werr)));
+ return werr;
+ }
+ break;
+ case GP_REG_ACTION_ADD_VALUE:
+ werr = reg_setvalue(key, entry->value, entry->data);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("reg_apply_registry_entry: "
+ "reg_setvalue failed: %s\n",
+ dos_errstr(werr)));
+ dump_reg_entry(flags, "STORE", entry);
+ return werr;
+ }
+ break;
+ case GP_REG_ACTION_DEL_VALUE:
+ werr = reg_deletevalue(key, entry->value);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("reg_apply_registry_entry: "
+ "reg_deletevalue failed: %s\n",
+ dos_errstr(werr)));
+ dump_reg_entry(flags, "STORE", entry);
+ return werr;
+ }
+ break;
+ case GP_REG_ACTION_DEL_ALL_VALUES:
+ werr = reg_deleteallvalues(key);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("reg_apply_registry_entry: "
+ "reg_deleteallvalues failed: %s\n",
+ dos_errstr(werr)));
+ dump_reg_entry(flags, "STORE", entry);
+ return werr;
+ }
+ break;
+ case GP_REG_ACTION_DEL_VALUES:
+ case GP_REG_ACTION_DEL_KEYS:
+ case GP_REG_ACTION_SEC_KEY_RESET:
+ DEBUG(0,("reg_apply_registry_entry: "
+ "not yet supported: %s (%d)\n",
+ gp_reg_action_str(entry->action),
+ entry->action));
+ return WERR_NOT_SUPPORTED;
+ default:
+ DEBUG(0,("invalid action: %d\n", entry->action));
+ return WERR_INVALID_PARAM;
+ }
+
+ return werr;
+}
+
diff --git a/source3/libgpo/gpo_sec.c b/source3/libgpo/gpo_sec.c
new file mode 100644
index 0000000000..42ab72a99b
--- /dev/null
+++ b/source3/libgpo/gpo_sec.c
@@ -0,0 +1,186 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Object Support
+ * Copyright (C) Guenther Deschner 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/****************************************************************
+****************************************************************/
+
+static bool gpo_sd_check_agp_object_guid(const struct security_ace_object *object)
+{
+ struct GUID ext_right_apg_guid;
+ NTSTATUS status;
+
+ if (!object) {
+ return false;
+ }
+
+ status = GUID_from_string(ADS_EXTENDED_RIGHT_APPLY_GROUP_POLICY,
+ &ext_right_apg_guid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ switch (object->flags) {
+ case SEC_ACE_OBJECT_PRESENT:
+ if (GUID_equal(&object->type.type,
+ &ext_right_apg_guid)) {
+ return True;
+ }
+ case SEC_ACE_OBJECT_INHERITED_PRESENT:
+ if (GUID_equal(&object->inherited_type.inherited_type,
+ &ext_right_apg_guid)) {
+ return True;
+ }
+ default:
+ break;
+ }
+
+ return false;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool gpo_sd_check_agp_object(const SEC_ACE *ace)
+{
+ if (!sec_ace_object(ace->type)) {
+ return false;
+ }
+
+ return gpo_sd_check_agp_object_guid(&ace->object.object);
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool gpo_sd_check_agp_access_bits(uint32_t access_mask)
+{
+ return (access_mask & SEC_RIGHTS_EXTENDED);
+}
+
+#if 0
+/****************************************************************
+****************************************************************/
+
+static bool gpo_sd_check_read_access_bits(uint32_t access_mask)
+{
+ uint32_t read_bits = SEC_RIGHTS_LIST_CONTENTS |
+ SEC_RIGHTS_READ_ALL_PROP |
+ SEC_RIGHTS_READ_PERMS;
+
+ return (read_bits == (access_mask & read_bits));
+}
+#endif
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS gpo_sd_check_ace_denied_object(const SEC_ACE *ace,
+ const struct nt_user_token *token)
+{
+ if (gpo_sd_check_agp_object(ace) &&
+ gpo_sd_check_agp_access_bits(ace->access_mask) &&
+ nt_token_check_sid(&ace->trustee, token)) {
+ DEBUG(10,("gpo_sd_check_ace_denied_object: "
+ "Access denied as of ace for %s\n",
+ sid_string_dbg(&ace->trustee)));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return STATUS_MORE_ENTRIES;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS gpo_sd_check_ace_allowed_object(const SEC_ACE *ace,
+ const struct nt_user_token *token)
+{
+ if (gpo_sd_check_agp_object(ace) &&
+ gpo_sd_check_agp_access_bits(ace->access_mask) &&
+ nt_token_check_sid(&ace->trustee, token)) {
+ DEBUG(10,("gpo_sd_check_ace_allowed_object: "
+ "Access granted as of ace for %s\n",
+ sid_string_dbg(&ace->trustee)));
+ return NT_STATUS_OK;
+ }
+
+ return STATUS_MORE_ENTRIES;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS gpo_sd_check_ace(const SEC_ACE *ace,
+ const struct nt_user_token *token)
+{
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+ return gpo_sd_check_ace_denied_object(ace, token);
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
+ return gpo_sd_check_ace_allowed_object(ace, token);
+ default:
+ return STATUS_MORE_ENTRIES;
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gpo_apply_security_filtering(const struct GROUP_POLICY_OBJECT *gpo,
+ const struct nt_user_token *token)
+{
+ SEC_DESC *sd = gpo->security_descriptor;
+ SEC_ACL *dacl = NULL;
+ NTSTATUS status = NT_STATUS_ACCESS_DENIED;
+ int i;
+
+ if (!token) {
+ return NT_STATUS_INVALID_USER_BUFFER;
+ }
+
+ if (!sd) {
+ return NT_STATUS_INVALID_SECURITY_DESCR;
+ }
+
+ dacl = sd->dacl;
+ if (!dacl) {
+ return NT_STATUS_INVALID_SECURITY_DESCR;
+ }
+
+ /* check all aces and only return NT_STATUS_OK (== Access granted) or
+ * NT_STATUS_ACCESS_DENIED ( == Access denied) - the default is to
+ * deny access */
+
+ for (i = 0; i < dacl->num_aces; i ++) {
+
+ status = gpo_sd_check_ace(&dacl->aces[i], token);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ return status;
+ } else if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ continue;
+ }
+
+ return NT_STATUS_ACCESS_DENIED;
+}
diff --git a/source3/libgpo/gpo_util.c b/source3/libgpo/gpo_util.c
new file mode 100644
index 0000000000..04597b3b57
--- /dev/null
+++ b/source3/libgpo/gpo_util.c
@@ -0,0 +1,870 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Object Support
+ * Copyright (C) Guenther Deschner 2005-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#define DEFAULT_DOMAIN_POLICY "Default Domain Policy"
+#define DEFAULT_DOMAIN_CONTROLLERS_POLICY "Default Domain Controllers Policy"
+
+/* should we store a parsed guid ? */
+struct gp_table {
+ const char *name;
+ const char *guid_string;
+};
+
+#if 0 /* unused */
+static struct gp_table gpo_default_policy[] = {
+ { DEFAULT_DOMAIN_POLICY,
+ "31B2F340-016D-11D2-945F-00C04FB984F9" },
+ { DEFAULT_DOMAIN_CONTROLLERS_POLICY,
+ "6AC1786C-016F-11D2-945F-00C04fB984F9" },
+ { NULL, NULL }
+};
+#endif
+
+/* the following is seen in gPCMachineExtensionNames / gPCUserExtensionNames */
+
+static struct gp_table gpo_cse_extensions[] = {
+ /* used to be "Administrative Templates Extension" */
+ /* "Registry Settings"
+ (http://support.microsoft.com/kb/216357/EN-US/) */
+ { "Registry Settings",
+ GP_EXT_GUID_REGISTRY },
+ { "Microsoft Disc Quota",
+ "3610EDA5-77EF-11D2-8DC5-00C04FA31A66" },
+ { "EFS recovery",
+ "B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A" },
+ { "Folder Redirection",
+ "25537BA6-77A8-11D2-9B6C-0000F8080861" },
+ { "IP Security",
+ "E437BC1C-AA7D-11D2-A382-00C04F991E27" },
+ { "Internet Explorer Branding",
+ "A2E30F80-D7DE-11d2-BBDE-00C04F86AE3B" },
+ { "QoS Packet Scheduler",
+ "426031c0-0b47-4852-b0ca-ac3d37bfcb39" },
+ { "Scripts",
+ GP_EXT_GUID_SCRIPTS },
+ { "Security",
+ GP_EXT_GUID_SECURITY },
+ { "Software Installation",
+ "C6DC5466-785A-11D2-84D0-00C04FB169F7" },
+ { "Wireless Group Policy",
+ "0ACDD40C-75AC-BAA0-BF6DE7E7FE63" },
+ { "Application Management",
+ "C6DC5466-785A-11D2-84D0-00C04FB169F7" },
+ { "unknown",
+ "3060E8D0-7020-11D2-842D-00C04FA372D4" },
+ { NULL, NULL }
+};
+
+/* guess work */
+static struct gp_table gpo_cse_snapin_extensions[] = {
+ { "Administrative Templates",
+ "0F6B957D-509E-11D1-A7CC-0000F87571E3" },
+ { "Certificates",
+ "53D6AB1D-2488-11D1-A28C-00C04FB94F17" },
+ { "EFS recovery policy processing",
+ "B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A" },
+ { "Folder Redirection policy processing",
+ "25537BA6-77A8-11D2-9B6C-0000F8080861" },
+ { "Folder Redirection",
+ "88E729D6-BDC1-11D1-BD2A-00C04FB9603F" },
+ { "Registry policy processing",
+ "35378EAC-683F-11D2-A89A-00C04FBBCFA2" },
+ { "Remote Installation Services",
+ "3060E8CE-7020-11D2-842D-00C04FA372D4" },
+ { "Security Settings",
+ "803E14A0-B4FB-11D0-A0D0-00A0C90F574B" },
+ { "Security policy processing",
+ "827D319E-6EAC-11D2-A4EA-00C04F79F83A" },
+ { "unknown",
+ "3060E8D0-7020-11D2-842D-00C04FA372D4" },
+ { "unknown2",
+ "53D6AB1B-2488-11D1-A28C-00C04FB94F17" },
+ { NULL, NULL }
+};
+
+/****************************************************************
+****************************************************************/
+
+static const char *name_to_guid_string(const char *name,
+ struct gp_table *table)
+{
+ int i;
+
+ for (i = 0; table[i].name; i++) {
+ if (strequal(name, table[i].name)) {
+ return table[i].guid_string;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************
+****************************************************************/
+
+static const char *guid_string_to_name(const char *guid_string,
+ struct gp_table *table)
+{
+ int i;
+
+ for (i = 0; table[i].guid_string; i++) {
+ if (strequal(guid_string, table[i].guid_string)) {
+ return table[i].name;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************
+****************************************************************/
+
+static const char *snapin_guid_string_to_name(const char *guid_string,
+ struct gp_table *table)
+{
+ int i;
+ for (i = 0; table[i].guid_string; i++) {
+ if (strequal(guid_string, table[i].guid_string)) {
+ return table[i].name;
+ }
+ }
+ return NULL;
+}
+
+#if 0 /* unused */
+static const char *default_gpo_name_to_guid_string(const char *name)
+{
+ return name_to_guid_string(name, gpo_default_policy);
+}
+
+static const char *default_gpo_guid_string_to_name(const char *guid)
+{
+ return guid_string_to_name(guid, gpo_default_policy);
+}
+#endif
+
+/****************************************************************
+****************************************************************/
+
+const char *cse_gpo_guid_string_to_name(const char *guid)
+{
+ return guid_string_to_name(guid, gpo_cse_extensions);
+}
+
+/****************************************************************
+****************************************************************/
+
+const char *cse_gpo_name_to_guid_string(const char *name)
+{
+ return name_to_guid_string(name, gpo_cse_extensions);
+}
+
+/****************************************************************
+****************************************************************/
+
+const char *cse_snapin_gpo_guid_string_to_name(const char *guid)
+{
+ return snapin_guid_string_to_name(guid, gpo_cse_snapin_extensions);
+}
+
+/****************************************************************
+****************************************************************/
+
+void dump_gp_ext(struct GP_EXT *gp_ext, int debuglevel)
+{
+ int lvl = debuglevel;
+ int i;
+
+ if (gp_ext == NULL) {
+ return;
+ }
+
+ DEBUG(lvl,("\t---------------------\n\n"));
+ DEBUGADD(lvl,("\tname:\t\t\t%s\n", gp_ext->gp_extension));
+
+ for (i=0; i< gp_ext->num_exts; i++) {
+
+ DEBUGADD(lvl,("\textension:\t\t\t%s\n",
+ gp_ext->extensions_guid[i]));
+ DEBUGADD(lvl,("\textension (name):\t\t\t%s\n",
+ gp_ext->extensions[i]));
+
+ DEBUGADD(lvl,("\tsnapin:\t\t\t%s\n",
+ gp_ext->snapins_guid[i]));
+ DEBUGADD(lvl,("\tsnapin (name):\t\t\t%s\n",
+ gp_ext->snapins[i]));
+ }
+}
+
+#ifdef HAVE_LDAP
+
+/****************************************************************
+****************************************************************/
+
+void dump_gpo(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ struct GROUP_POLICY_OBJECT *gpo,
+ int debuglevel)
+{
+ int lvl = debuglevel;
+
+ if (gpo == NULL) {
+ return;
+ }
+
+ DEBUG(lvl,("---------------------\n\n"));
+
+ DEBUGADD(lvl,("name:\t\t\t%s\n", gpo->name));
+ DEBUGADD(lvl,("displayname:\t\t%s\n", gpo->display_name));
+ DEBUGADD(lvl,("version:\t\t%d (0x%08x)\n", gpo->version, gpo->version));
+ DEBUGADD(lvl,("version_user:\t\t%d (0x%04x)\n",
+ GPO_VERSION_USER(gpo->version),
+ GPO_VERSION_USER(gpo->version)));
+ DEBUGADD(lvl,("version_machine:\t%d (0x%04x)\n",
+ GPO_VERSION_MACHINE(gpo->version),
+ GPO_VERSION_MACHINE(gpo->version)));
+ DEBUGADD(lvl,("filesyspath:\t\t%s\n", gpo->file_sys_path));
+ DEBUGADD(lvl,("dspath:\t\t%s\n", gpo->ds_path));
+
+ DEBUGADD(lvl,("options:\t\t%d ", gpo->options));
+ switch (gpo->options) {
+ case GPFLAGS_ALL_ENABLED:
+ DEBUGADD(lvl,("GPFLAGS_ALL_ENABLED\n"));
+ break;
+ case GPFLAGS_USER_SETTINGS_DISABLED:
+ DEBUGADD(lvl,("GPFLAGS_USER_SETTINGS_DISABLED\n"));
+ break;
+ case GPFLAGS_MACHINE_SETTINGS_DISABLED:
+ DEBUGADD(lvl,("GPFLAGS_MACHINE_SETTINGS_DISABLED\n"));
+ break;
+ case GPFLAGS_ALL_DISABLED:
+ DEBUGADD(lvl,("GPFLAGS_ALL_DISABLED\n"));
+ break;
+ default:
+ DEBUGADD(lvl,("unknown option: %d\n", gpo->options));
+ break;
+ }
+
+ DEBUGADD(lvl,("link:\t\t\t%s\n", gpo->link));
+ DEBUGADD(lvl,("link_type:\t\t%d ", gpo->link_type));
+ switch (gpo->link_type) {
+ case GP_LINK_UNKOWN:
+ DEBUGADD(lvl,("GP_LINK_UNKOWN\n"));
+ break;
+ case GP_LINK_OU:
+ DEBUGADD(lvl,("GP_LINK_OU\n"));
+ break;
+ case GP_LINK_DOMAIN:
+ DEBUGADD(lvl,("GP_LINK_DOMAIN\n"));
+ break;
+ case GP_LINK_SITE:
+ DEBUGADD(lvl,("GP_LINK_SITE\n"));
+ break;
+ case GP_LINK_MACHINE:
+ DEBUGADD(lvl,("GP_LINK_MACHINE\n"));
+ break;
+ default:
+ break;
+ }
+
+ DEBUGADD(lvl,("machine_extensions:\t%s\n", gpo->machine_extensions));
+
+ if (gpo->machine_extensions) {
+
+ struct GP_EXT *gp_ext = NULL;
+
+ if (!ads_parse_gp_ext(mem_ctx, gpo->machine_extensions,
+ &gp_ext)) {
+ return;
+ }
+ dump_gp_ext(gp_ext, lvl);
+ }
+
+ DEBUGADD(lvl,("user_extensions:\t%s\n", gpo->user_extensions));
+
+ if (gpo->user_extensions) {
+
+ struct GP_EXT *gp_ext = NULL;
+
+ if (!ads_parse_gp_ext(mem_ctx, gpo->user_extensions,
+ &gp_ext)) {
+ return;
+ }
+ dump_gp_ext(gp_ext, lvl);
+ }
+
+ DEBUGADD(lvl,("security descriptor:\n"));
+
+ ads_disp_sd(ads, mem_ctx, gpo->security_descriptor);
+}
+
+/****************************************************************
+****************************************************************/
+
+void dump_gpo_list(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ struct GROUP_POLICY_OBJECT *gpo_list,
+ int debuglevel)
+{
+ struct GROUP_POLICY_OBJECT *gpo = NULL;
+
+ for (gpo = gpo_list; gpo; gpo = gpo->next) {
+ dump_gpo(ads, mem_ctx, gpo, debuglevel);
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+void dump_gplink(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, struct GP_LINK *gp_link)
+{
+ ADS_STATUS status;
+ int i;
+ int lvl = 10;
+
+ if (gp_link == NULL) {
+ return;
+ }
+
+ DEBUG(lvl,("---------------------\n\n"));
+
+ DEBUGADD(lvl,("gplink: %s\n", gp_link->gp_link));
+ DEBUGADD(lvl,("gpopts: %d ", gp_link->gp_opts));
+ switch (gp_link->gp_opts) {
+ case GPOPTIONS_INHERIT:
+ DEBUGADD(lvl,("GPOPTIONS_INHERIT\n"));
+ break;
+ case GPOPTIONS_BLOCK_INHERITANCE:
+ DEBUGADD(lvl,("GPOPTIONS_BLOCK_INHERITANCE\n"));
+ break;
+ default:
+ break;
+ }
+
+ DEBUGADD(lvl,("num links: %d\n", gp_link->num_links));
+
+ for (i = 0; i < gp_link->num_links; i++) {
+
+ DEBUGADD(lvl,("---------------------\n\n"));
+
+ DEBUGADD(lvl,("link: #%d\n", i + 1));
+ DEBUGADD(lvl,("name: %s\n", gp_link->link_names[i]));
+
+ DEBUGADD(lvl,("opt: %d ", gp_link->link_opts[i]));
+ if (gp_link->link_opts[i] & GPO_LINK_OPT_ENFORCED) {
+ DEBUGADD(lvl,("GPO_LINK_OPT_ENFORCED "));
+ }
+ if (gp_link->link_opts[i] & GPO_LINK_OPT_DISABLED) {
+ DEBUGADD(lvl,("GPO_LINK_OPT_DISABLED"));
+ }
+ DEBUGADD(lvl,("\n"));
+
+ if (ads != NULL && mem_ctx != NULL) {
+
+ struct GROUP_POLICY_OBJECT gpo;
+
+ status = ads_get_gpo(ads, mem_ctx,
+ gp_link->link_names[i],
+ NULL, NULL, &gpo);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(lvl,("get gpo for %s failed: %s\n",
+ gp_link->link_names[i],
+ ads_errstr(status)));
+ return;
+ }
+ dump_gpo(ads, mem_ctx, &gpo, lvl);
+ }
+ }
+}
+
+#endif /* HAVE_LDAP */
+
+/****************************************************************
+****************************************************************/
+
+static bool gpo_get_gp_ext_from_gpo(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct GROUP_POLICY_OBJECT *gpo,
+ struct GP_EXT **gp_ext)
+{
+ ZERO_STRUCTP(*gp_ext);
+
+ if (flags & GPO_INFO_FLAG_MACHINE) {
+
+ if (gpo->machine_extensions) {
+
+ if (!ads_parse_gp_ext(mem_ctx, gpo->machine_extensions,
+ gp_ext)) {
+ return false;
+ }
+ }
+ } else {
+
+ if (gpo->user_extensions) {
+
+ if (!ads_parse_gp_ext(mem_ctx, gpo->user_extensions,
+ gp_ext)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+ADS_STATUS gpo_process_a_gpo(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const struct nt_user_token *token,
+ struct registry_key *root_key,
+ struct GROUP_POLICY_OBJECT *gpo,
+ const char *extension_guid_filter,
+ uint32_t flags)
+{
+ struct GP_EXT *gp_ext = NULL;
+ int i;
+
+ DEBUG(10,("gpo_process_a_gpo: processing gpo %s (%s)\n",
+ gpo->name, gpo->display_name));
+ if (extension_guid_filter) {
+ DEBUGADD(10,("gpo_process_a_gpo: using filter %s (%s)\n",
+ extension_guid_filter,
+ cse_gpo_guid_string_to_name(extension_guid_filter)));
+ }
+
+ if (!gpo_get_gp_ext_from_gpo(mem_ctx, flags, gpo, &gp_ext)) {
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ if (!gp_ext || !gp_ext->num_exts) {
+ if (flags & GPO_INFO_FLAG_VERBOSE) {
+ DEBUG(0,("gpo_process_a_gpo: "
+ "no policies in %s (%s) for this extension\n",
+ gpo->name, gpo->display_name));
+ }
+ return ADS_SUCCESS;
+ }
+
+ for (i=0; i<gp_ext->num_exts; i++) {
+
+ NTSTATUS ntstatus;
+
+ if (extension_guid_filter &&
+ !strequal(extension_guid_filter,
+ gp_ext->extensions_guid[i])) {
+ continue;
+ }
+
+ ntstatus = gpext_process_extension(ads, mem_ctx,
+ flags, token, root_key, gpo,
+ gp_ext->extensions_guid[i],
+ gp_ext->snapins_guid[i]);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ ADS_ERROR_NT(ntstatus);
+ }
+ }
+
+ return ADS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+static ADS_STATUS gpo_process_gpo_list_by_ext(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const struct nt_user_token *token,
+ struct registry_key *root_key,
+ struct GROUP_POLICY_OBJECT *gpo_list,
+ const char *extensions_guid,
+ uint32_t flags)
+{
+ ADS_STATUS status;
+ struct GROUP_POLICY_OBJECT *gpo;
+
+ for (gpo = gpo_list; gpo; gpo = gpo->next) {
+
+ if (gpo->link_type == GP_LINK_LOCAL) {
+ continue;
+ }
+
+
+ /* FIXME: we need to pass down the *list* down to the
+ * extension, otherwise we cannot store the e.g. the *list* of
+ * logon-scripts correctly (for more then one GPO) */
+
+ status = gpo_process_a_gpo(ads, mem_ctx, token, root_key,
+ gpo, extensions_guid, flags);
+
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0,("failed to process gpo by ext: %s\n",
+ ads_errstr(status)));
+ return status;
+ }
+ }
+
+ return ADS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+ADS_STATUS gpo_process_gpo_list(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const struct nt_user_token *token,
+ struct GROUP_POLICY_OBJECT *gpo_list,
+ const char *extensions_guid_filter,
+ uint32_t flags)
+{
+ ADS_STATUS status = ADS_SUCCESS;
+ struct gp_extension *gp_ext_list = NULL;
+ struct gp_extension *gp_ext = NULL;
+ struct registry_key *root_key = NULL;
+ struct gp_registry_context *reg_ctx = NULL;
+ WERROR werr;
+
+ status = ADS_ERROR_NT(init_gp_extensions(mem_ctx));
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ gp_ext_list = get_gp_extension_list();
+ if (!gp_ext_list) {
+ return ADS_ERROR_NT(NT_STATUS_DLL_INIT_FAILED);
+ }
+
+ /* get the key here */
+ if (flags & GPO_LIST_FLAG_MACHINE) {
+ werr = gp_init_reg_ctx(mem_ctx, KEY_HKLM, REG_KEY_WRITE,
+ get_system_token(),
+ &reg_ctx);
+ } else {
+ werr = gp_init_reg_ctx(mem_ctx, KEY_HKCU, REG_KEY_WRITE,
+ token,
+ &reg_ctx);
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ gp_free_reg_ctx(reg_ctx);
+ return ADS_ERROR_NT(werror_to_ntstatus(werr));
+ }
+
+ root_key = reg_ctx->curr_key;
+
+ for (gp_ext = gp_ext_list; gp_ext; gp_ext = gp_ext->next) {
+
+ const char *guid_str = NULL;
+
+ guid_str = GUID_string(mem_ctx, gp_ext->guid);
+ if (!guid_str) {
+ status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ goto done;
+ }
+
+ if (extensions_guid_filter &&
+ (!strequal(guid_str, extensions_guid_filter))) {
+ continue;
+ }
+
+ DEBUG(0,("-------------------------------------------------\n"));
+ DEBUG(0,("gpo_process_gpo_list: processing ext: %s {%s}\n",
+ gp_ext->name, guid_str));
+
+
+ status = gpo_process_gpo_list_by_ext(ads, mem_ctx, token,
+ root_key, gpo_list,
+ guid_str, flags);
+ if (!ADS_ERR_OK(status)) {
+ goto done;
+ }
+ }
+
+ done:
+ gp_free_reg_ctx(reg_ctx);
+ TALLOC_FREE(root_key);
+ free_gp_extensions();
+
+ return status;
+}
+
+
+/****************************************************************
+ check wether the version number in a GROUP_POLICY_OBJECT match those of the
+ locally stored version. If not, fetch the required policy via CIFS
+****************************************************************/
+
+NTSTATUS check_refresh_gpo(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct GROUP_POLICY_OBJECT *gpo,
+ struct cli_state **cli_out)
+{
+ NTSTATUS result;
+ char *server = NULL;
+ char *share = NULL;
+ char *nt_path = NULL;
+ char *unix_path = NULL;
+ uint32_t sysvol_gpt_version = 0;
+ char *display_name = NULL;
+ struct cli_state *cli = NULL;
+
+ result = gpo_explode_filesyspath(mem_ctx, gpo->file_sys_path,
+ &server, &share, &nt_path, &unix_path);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto out;
+ }
+
+ result = gpo_get_sysvol_gpt_version(mem_ctx,
+ unix_path,
+ &sysvol_gpt_version,
+ &display_name);
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_FILE)) {
+ DEBUG(10,("check_refresh_gpo: "
+ "failed to get local gpt version: %s\n",
+ nt_errstr(result)));
+ goto out;
+ }
+
+ DEBUG(10,("check_refresh_gpo: versions gpo %d sysvol %d\n",
+ gpo->version, sysvol_gpt_version));
+
+ /* FIXME: handle GPO_INFO_FLAG_FORCED_REFRESH from flags */
+
+ while (gpo->version > sysvol_gpt_version) {
+
+ DEBUG(1,("check_refresh_gpo: need to refresh GPO\n"));
+
+ if (*cli_out == NULL) {
+
+ result = cli_full_connection(&cli,
+ global_myname(),
+ ads->config.ldap_server_name,
+ /* server */
+ NULL, 0,
+ share, "A:",
+ ads->auth.user_name, NULL,
+ ads->auth.password,
+ CLI_FULL_CONNECTION_USE_KERBEROS |
+ CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS,
+ Undefined, NULL);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("check_refresh_gpo: "
+ "failed to connect: %s\n",
+ nt_errstr(result)));
+ goto out;
+ }
+
+ *cli_out = cli;
+ }
+
+ result = gpo_fetch_files(mem_ctx, *cli_out, gpo);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto out;
+ }
+
+ result = gpo_get_sysvol_gpt_version(mem_ctx,
+ unix_path,
+ &sysvol_gpt_version,
+ &display_name);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("check_refresh_gpo: "
+ "failed to get local gpt version: %s\n",
+ nt_errstr(result)));
+ goto out;
+ }
+
+ if (gpo->version == sysvol_gpt_version) {
+ break;
+ }
+ }
+
+ DEBUG(10,("Name:\t\t\t%s (%s)\n", gpo->display_name, gpo->name));
+ DEBUGADD(10,("sysvol GPT version:\t%d (user: %d, machine: %d)\n",
+ sysvol_gpt_version,
+ GPO_VERSION_USER(sysvol_gpt_version),
+ GPO_VERSION_MACHINE(sysvol_gpt_version)));
+ DEBUGADD(10,("LDAP GPO version:\t%d (user: %d, machine: %d)\n",
+ gpo->version,
+ GPO_VERSION_USER(gpo->version),
+ GPO_VERSION_MACHINE(gpo->version)));
+ DEBUGADD(10,("LDAP GPO link:\t\t%s\n", gpo->link));
+
+ result = NT_STATUS_OK;
+
+ out:
+ return result;
+
+}
+
+/****************************************************************
+ check wether the version numbers in the gpo_list match the locally stored, if
+ not, go and get each required GPO via CIFS
+ ****************************************************************/
+
+NTSTATUS check_refresh_gpo_list(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct GROUP_POLICY_OBJECT *gpo_list)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct cli_state *cli = NULL;
+ struct GROUP_POLICY_OBJECT *gpo;
+
+ if (!gpo_list) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ for (gpo = gpo_list; gpo; gpo = gpo->next) {
+
+ result = check_refresh_gpo(ads, mem_ctx, flags, gpo, &cli);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto out;
+ }
+ }
+
+ result = NT_STATUS_OK;
+
+ out:
+ if (cli) {
+ cli_shutdown(cli);
+ }
+
+ return result;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gpo_get_unix_path(TALLOC_CTX *mem_ctx,
+ struct GROUP_POLICY_OBJECT *gpo,
+ char **unix_path)
+{
+ char *server, *share, *nt_path;
+ return gpo_explode_filesyspath(mem_ctx, gpo->file_sys_path,
+ &server, &share, &nt_path, unix_path);
+}
+
+/****************************************************************
+****************************************************************/
+
+char *gpo_flag_str(uint32_t flags)
+{
+ fstring str = "";
+
+ if (flags == 0) {
+ return NULL;
+ }
+
+ if (flags & GPO_INFO_FLAG_SLOWLINK)
+ fstrcat(str, "GPO_INFO_FLAG_SLOWLINK ");
+ if (flags & GPO_INFO_FLAG_VERBOSE)
+ fstrcat(str, "GPO_INFO_FLAG_VERBOSE ");
+ if (flags & GPO_INFO_FLAG_SAFEMODE_BOOT)
+ fstrcat(str, "GPO_INFO_FLAG_SAFEMODE_BOOT ");
+ if (flags & GPO_INFO_FLAG_NOCHANGES)
+ fstrcat(str, "GPO_INFO_FLAG_NOCHANGES ");
+ if (flags & GPO_INFO_FLAG_MACHINE)
+ fstrcat(str, "GPO_INFO_FLAG_MACHINE ");
+ if (flags & GPO_INFO_FLAG_LOGRSOP_TRANSITION)
+ fstrcat(str, "GPO_INFO_FLAG_LOGRSOP_TRANSITION ");
+ if (flags & GPO_INFO_FLAG_LINKTRANSITION)
+ fstrcat(str, "GPO_INFO_FLAG_LINKTRANSITION ");
+ if (flags & GPO_INFO_FLAG_FORCED_REFRESH)
+ fstrcat(str, "GPO_INFO_FLAG_FORCED_REFRESH ");
+ if (flags & GPO_INFO_FLAG_BACKGROUND)
+ fstrcat(str, "GPO_INFO_FLAG_BACKGROUND ");
+
+ return SMB_STRDUP(str);
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gp_find_file(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const char *filename,
+ const char *suffix,
+ const char **filename_out)
+{
+ const char *tmp = NULL;
+ SMB_STRUCT_STAT sbuf;
+ const char *path = NULL;
+
+ if (flags & GPO_LIST_FLAG_MACHINE) {
+ path = "Machine";
+ } else {
+ path = "User";
+ }
+
+ tmp = talloc_asprintf(mem_ctx, "%s/%s/%s", filename,
+ path, suffix);
+ NT_STATUS_HAVE_NO_MEMORY(tmp);
+
+ if (sys_stat(tmp, &sbuf) == 0) {
+ *filename_out = tmp;
+ return NT_STATUS_OK;
+ }
+
+ path = talloc_strdup_upper(mem_ctx, path);
+ NT_STATUS_HAVE_NO_MEMORY(path);
+
+ tmp = talloc_asprintf(mem_ctx, "%s/%s/%s", filename,
+ path, suffix);
+ NT_STATUS_HAVE_NO_MEMORY(tmp);
+
+ if (sys_stat(tmp, &sbuf) == 0) {
+ *filename_out = tmp;
+ return NT_STATUS_OK;
+ }
+
+ return NT_STATUS_NO_SUCH_FILE;
+}
+
+/****************************************************************
+****************************************************************/
+
+ADS_STATUS gp_get_machine_token(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *dn,
+ struct nt_user_token **token)
+{
+ struct nt_user_token *ad_token = NULL;
+ ADS_STATUS status;
+ NTSTATUS ntstatus;
+
+#ifndef HAVE_ADS
+ return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+#endif
+ status = ads_get_sid_token(ads, mem_ctx, dn, &ad_token);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ ntstatus = merge_nt_token(mem_ctx, ad_token, get_system_token(),
+ token);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ return ADS_ERROR_NT(ntstatus);
+ }
+
+ return ADS_SUCCESS;
+}
diff --git a/source3/libnet/libnet.h b/source3/libnet/libnet.h
new file mode 100644
index 0000000000..570009c6f6
--- /dev/null
+++ b/source3/libnet/libnet.h
@@ -0,0 +1,29 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libnet Support
+ * Copyright (C) Guenther Deschner 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIBNET_H__
+#define __LIBNET_H__
+
+#include "libnet/libnet_keytab.h"
+#include "libnet/libnet_samsync.h"
+#include "libnet/libnet_dssync.h"
+#include "librpc/gen_ndr/libnet_join.h"
+#include "libnet/libnet_proto.h"
+
+#endif
diff --git a/source3/libnet/libnet_dssync.c b/source3/libnet/libnet_dssync.c
new file mode 100644
index 0000000000..bae03effed
--- /dev/null
+++ b/source3/libnet/libnet_dssync.c
@@ -0,0 +1,720 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan (metze) Metzmacher 2005
+ Copyright (C) Guenther Deschner 2008
+ Copyright (C) Michael Adam 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+#include "libnet/libnet.h"
+
+/****************************************************************
+****************************************************************/
+
+static int libnet_dssync_free_context(struct dssync_context *ctx)
+{
+ if (!ctx) {
+ return 0;
+ }
+
+ if (is_valid_policy_hnd(&ctx->bind_handle) && ctx->cli) {
+ rpccli_drsuapi_DsUnbind(ctx->cli, ctx, &ctx->bind_handle, NULL);
+ }
+
+ return 0;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS libnet_dssync_init_context(TALLOC_CTX *mem_ctx,
+ struct dssync_context **ctx_p)
+{
+ struct dssync_context *ctx;
+
+ ctx = TALLOC_ZERO_P(mem_ctx, struct dssync_context);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ talloc_set_destructor(ctx, libnet_dssync_free_context);
+ ctx->clean_old_entries = false;
+
+ *ctx_p = ctx;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static DATA_BLOB *decrypt_attr_val(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *session_key,
+ uint32_t rid,
+ enum drsuapi_DsAttributeId id,
+ DATA_BLOB *raw_data)
+{
+ bool rcrypt = false;
+ DATA_BLOB out_data;
+
+ ZERO_STRUCT(out_data);
+
+ switch (id) {
+ case DRSUAPI_ATTRIBUTE_dBCSPwd:
+ case DRSUAPI_ATTRIBUTE_unicodePwd:
+ case DRSUAPI_ATTRIBUTE_ntPwdHistory:
+ case DRSUAPI_ATTRIBUTE_lmPwdHistory:
+ rcrypt = true;
+ break;
+ case DRSUAPI_ATTRIBUTE_supplementalCredentials:
+ case DRSUAPI_ATTRIBUTE_priorValue:
+ case DRSUAPI_ATTRIBUTE_currentValue:
+ case DRSUAPI_ATTRIBUTE_trustAuthOutgoing:
+ case DRSUAPI_ATTRIBUTE_trustAuthIncoming:
+ case DRSUAPI_ATTRIBUTE_initialAuthOutgoing:
+ case DRSUAPI_ATTRIBUTE_initialAuthIncoming:
+ break;
+ default:
+ return raw_data;
+ }
+
+ out_data = decrypt_drsuapi_blob(mem_ctx, session_key, rcrypt,
+ rid, raw_data);
+
+ if (out_data.length) {
+ return (DATA_BLOB *)talloc_memdup(mem_ctx, &out_data, sizeof(DATA_BLOB));
+ }
+
+ return raw_data;
+}
+
+/****************************************************************
+****************************************************************/
+
+static void parse_obj_identifier(struct drsuapi_DsReplicaObjectIdentifier *id,
+ uint32_t *rid)
+{
+ if (!id || !rid) {
+ return;
+ }
+
+ *rid = 0;
+
+ if (id->sid.num_auths > 0) {
+ *rid = id->sid.sub_auths[id->sid.num_auths - 1];
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+static void parse_obj_attribute(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *session_key,
+ uint32_t rid,
+ struct drsuapi_DsReplicaAttribute *attr)
+{
+ int i = 0;
+
+ for (i=0; i<attr->value_ctr.num_values; i++) {
+
+ DATA_BLOB *plain_data = NULL;
+
+ plain_data = decrypt_attr_val(mem_ctx,
+ session_key,
+ rid,
+ attr->attid,
+ attr->value_ctr.values[i].blob);
+
+ attr->value_ctr.values[i].blob = plain_data;
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+static void libnet_dssync_decrypt_attributes(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *session_key,
+ struct drsuapi_DsReplicaObjectListItemEx *cur)
+{
+ for (; cur; cur = cur->next_object) {
+
+ uint32_t i;
+ uint32_t rid = 0;
+
+ parse_obj_identifier(cur->object.identifier, &rid);
+
+ for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
+
+ struct drsuapi_DsReplicaAttribute *attr;
+
+ attr = &cur->object.attribute_ctr.attributes[i];
+
+ if (attr->value_ctr.num_values < 1) {
+ continue;
+ }
+
+ if (!attr->value_ctr.values[0].blob) {
+ continue;
+ }
+
+ parse_obj_attribute(mem_ctx,
+ session_key,
+ rid,
+ attr);
+ }
+ }
+}
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS libnet_dssync_bind(TALLOC_CTX *mem_ctx,
+ struct dssync_context *ctx)
+{
+ NTSTATUS status;
+ WERROR werr;
+
+ struct GUID bind_guid;
+ struct drsuapi_DsBindInfoCtr bind_info;
+ struct drsuapi_DsBindInfo28 info28;
+
+ ZERO_STRUCT(info28);
+
+ GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);
+
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
+ info28.site_guid = GUID_zero();
+ info28.pid = 508;
+ info28.repl_epoch = 0;
+
+ bind_info.length = 28;
+ bind_info.info.info28 = info28;
+
+ status = rpccli_drsuapi_DsBind(ctx->cli, mem_ctx,
+ &bind_guid,
+ &bind_info,
+ &ctx->bind_handle,
+ &werr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (!W_ERROR_IS_OK(werr)) {
+ return werror_to_ntstatus(werr);
+ }
+
+ ZERO_STRUCT(ctx->remote_info28);
+ switch (bind_info.length) {
+ case 24: {
+ struct drsuapi_DsBindInfo24 *info24;
+ info24 = &bind_info.info.info24;
+ ctx->remote_info28.site_guid = info24->site_guid;
+ ctx->remote_info28.supported_extensions = info24->supported_extensions;
+ ctx->remote_info28.pid = info24->pid;
+ ctx->remote_info28.repl_epoch = 0;
+ break;
+ }
+ case 28:
+ ctx->remote_info28 = bind_info.info.info28;
+ break;
+ case 48: {
+ struct drsuapi_DsBindInfo48 *info48;
+ info48 = &bind_info.info.info48;
+ ctx->remote_info28.site_guid = info48->site_guid;
+ ctx->remote_info28.supported_extensions = info48->supported_extensions;
+ ctx->remote_info28.pid = info48->pid;
+ ctx->remote_info28.repl_epoch = info48->repl_epoch;
+ break;
+ }
+ default:
+ DEBUG(1, ("Warning: invalid info length in bind info: %d\n",
+ bind_info.length));
+ break;
+ }
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS libnet_dssync_lookup_nc(TALLOC_CTX *mem_ctx,
+ struct dssync_context *ctx)
+{
+ NTSTATUS status;
+ WERROR werr;
+ int32_t level = 1;
+ union drsuapi_DsNameRequest req;
+ int32_t level_out;
+ struct drsuapi_DsNameString names[1];
+ union drsuapi_DsNameCtr ctr;
+
+ names[0].str = talloc_asprintf(mem_ctx, "%s\\", ctx->domain_name);
+ NT_STATUS_HAVE_NO_MEMORY(names[0].str);
+
+ req.req1.codepage = 1252; /* german */
+ req.req1.language = 0x00000407; /* german */
+ req.req1.count = 1;
+ req.req1.names = names;
+ req.req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS;
+ req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_UKNOWN;
+ req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
+
+ status = rpccli_drsuapi_DsCrackNames(ctx->cli, mem_ctx,
+ &ctx->bind_handle,
+ level,
+ &req,
+ &level_out,
+ &ctr,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ ctx->error_message = talloc_asprintf(ctx,
+ "Failed to lookup DN for domain name: %s",
+ get_friendly_werror_msg(werr));
+ return status;
+ }
+
+ if (!W_ERROR_IS_OK(werr)) {
+ return werror_to_ntstatus(werr);
+ }
+
+ if (ctr.ctr1->count != 1) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ctx->nc_dn = talloc_strdup(mem_ctx, ctr.ctr1->array[0].result_name);
+ NT_STATUS_HAVE_NO_MEMORY(ctx->nc_dn);
+
+ if (!ctx->dns_domain_name) {
+ ctx->dns_domain_name = talloc_strdup_upper(mem_ctx,
+ ctr.ctr1->array[0].dns_domain_name);
+ NT_STATUS_HAVE_NO_MEMORY(ctx->dns_domain_name);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS libnet_dssync_init(TALLOC_CTX *mem_ctx,
+ struct dssync_context *ctx)
+{
+ NTSTATUS status;
+
+ status = libnet_dssync_bind(mem_ctx, ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (!ctx->nc_dn) {
+ status = libnet_dssync_lookup_nc(mem_ctx, ctx);
+ }
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS libnet_dssync_build_request(TALLOC_CTX *mem_ctx,
+ struct dssync_context *ctx,
+ const char *dn,
+ struct replUpToDateVectorBlob *utdv,
+ int32_t *plevel,
+ union drsuapi_DsGetNCChangesRequest *preq)
+{
+ NTSTATUS status;
+ uint32_t count;
+ int32_t level;
+ union drsuapi_DsGetNCChangesRequest req;
+ struct dom_sid null_sid;
+ enum drsuapi_DsExtendedOperation extended_op;
+ struct drsuapi_DsReplicaObjectIdentifier *nc = NULL;
+ struct drsuapi_DsReplicaCursorCtrEx *cursors = NULL;
+
+ uint32_t replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE |
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP |
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS |
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS |
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED;
+
+ ZERO_STRUCT(null_sid);
+ ZERO_STRUCT(req);
+
+ if (ctx->remote_info28.supported_extensions
+ & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8)
+ {
+ level = 8;
+ } else {
+ level = 5;
+ }
+
+ nc = TALLOC_ZERO_P(mem_ctx, struct drsuapi_DsReplicaObjectIdentifier);
+ if (!nc) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ nc->dn = dn;
+ nc->guid = GUID_zero();
+ nc->sid = null_sid;
+
+ if (!ctx->single_object_replication &&
+ !ctx->force_full_replication && utdv)
+ {
+ cursors = TALLOC_ZERO_P(mem_ctx,
+ struct drsuapi_DsReplicaCursorCtrEx);
+ if (!cursors) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ switch (utdv->version) {
+ case 1:
+ cursors->count = utdv->ctr.ctr1.count;
+ cursors->cursors = utdv->ctr.ctr1.cursors;
+ break;
+ case 2:
+ cursors->count = utdv->ctr.ctr2.count;
+ cursors->cursors = talloc_array(cursors,
+ struct drsuapi_DsReplicaCursor,
+ cursors->count);
+ if (!cursors->cursors) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ for (count = 0; count < cursors->count; count++) {
+ cursors->cursors[count].source_dsa_invocation_id =
+ utdv->ctr.ctr2.cursors[count].source_dsa_invocation_id;
+ cursors->cursors[count].highest_usn =
+ utdv->ctr.ctr2.cursors[count].highest_usn;
+ }
+ break;
+ }
+ }
+
+ if (ctx->single_object_replication) {
+ extended_op = DRSUAPI_EXOP_REPL_OBJ;
+ } else {
+ extended_op = DRSUAPI_EXOP_NONE;
+ }
+
+ if (level == 8) {
+ req.req8.naming_context = nc;
+ req.req8.replica_flags = replica_flags;
+ req.req8.max_object_count = 402;
+ req.req8.max_ndr_size = 402116;
+ req.req8.uptodateness_vector = cursors;
+ req.req8.extended_op = extended_op;
+ } else if (level == 5) {
+ req.req5.naming_context = nc;
+ req.req5.replica_flags = replica_flags;
+ req.req5.max_object_count = 402;
+ req.req5.max_ndr_size = 402116;
+ req.req5.uptodateness_vector = cursors;
+ req.req5.extended_op = extended_op;
+ } else {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ if (plevel) {
+ *plevel = level;
+ }
+
+ if (preq) {
+ *preq = req;
+ }
+
+ return NT_STATUS_OK;
+
+fail:
+ TALLOC_FREE(nc);
+ TALLOC_FREE(cursors);
+ return status;
+}
+
+static NTSTATUS libnet_dssync_getncchanges(TALLOC_CTX *mem_ctx,
+ struct dssync_context *ctx,
+ int32_t level,
+ union drsuapi_DsGetNCChangesRequest *req,
+ struct replUpToDateVectorBlob **pnew_utdv)
+{
+ NTSTATUS status;
+ WERROR werr;
+ union drsuapi_DsGetNCChangesCtr ctr;
+ struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
+ struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
+ struct replUpToDateVectorBlob *new_utdv = NULL;
+ int32_t level_out = 0;
+ int32_t out_level = 0;
+ int y;
+ bool last_query;
+
+ if (!ctx->single_object_replication) {
+ new_utdv = TALLOC_ZERO_P(mem_ctx, struct replUpToDateVectorBlob);
+ if (!new_utdv) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+ }
+
+ for (y=0, last_query = false; !last_query; y++) {
+ struct drsuapi_DsReplicaObjectListItemEx *first_object = NULL;
+ struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr = NULL;
+
+ if (level == 8) {
+ DEBUG(1,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y,
+ (long long)req->req8.highwatermark.tmp_highest_usn,
+ (long long)req->req8.highwatermark.highest_usn));
+ } else if (level == 5) {
+ DEBUG(1,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y,
+ (long long)req->req5.highwatermark.tmp_highest_usn,
+ (long long)req->req5.highwatermark.highest_usn));
+ }
+
+ status = rpccli_drsuapi_DsGetNCChanges(ctx->cli, mem_ctx,
+ &ctx->bind_handle,
+ level,
+ req,
+ &level_out,
+ &ctr,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ ctx->error_message = talloc_asprintf(ctx,
+ "Failed to get NC Changes: %s",
+ get_friendly_werror_msg(werr));
+ goto out;
+ }
+
+ if (!W_ERROR_IS_OK(werr)) {
+ status = werror_to_ntstatus(werr);
+ goto out;
+ }
+
+ if (level_out == 1) {
+ out_level = 1;
+ ctr1 = &ctr.ctr1;
+ } else if (level_out == 2) {
+ out_level = 1;
+ ctr1 = ctr.ctr2.ctr.mszip1.ctr1;
+ } else if (level_out == 6) {
+ out_level = 6;
+ ctr6 = &ctr.ctr6;
+ } else if (level_out == 7
+ && ctr.ctr7.level == 6
+ && ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP) {
+ out_level = 6;
+ ctr6 = ctr.ctr7.ctr.mszip6.ctr6;
+ }
+
+ if (out_level == 1) {
+ DEBUG(1,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y,
+ (long long)ctr1->new_highwatermark.tmp_highest_usn,
+ (long long)ctr1->new_highwatermark.highest_usn));
+
+ first_object = ctr1->first_object;
+ mapping_ctr = &ctr1->mapping_ctr;
+
+ if (ctr1->more_data) {
+ req->req5.highwatermark = ctr1->new_highwatermark;
+ } else {
+ last_query = true;
+ if (ctr1->uptodateness_vector &&
+ !ctx->single_object_replication)
+ {
+ new_utdv->version = 1;
+ new_utdv->ctr.ctr1.count =
+ ctr1->uptodateness_vector->count;
+ new_utdv->ctr.ctr1.cursors =
+ ctr1->uptodateness_vector->cursors;
+ }
+ }
+ } else if (out_level == 6) {
+ DEBUG(1,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y,
+ (long long)ctr6->new_highwatermark.tmp_highest_usn,
+ (long long)ctr6->new_highwatermark.highest_usn));
+
+ first_object = ctr6->first_object;
+ mapping_ctr = &ctr6->mapping_ctr;
+
+ if (ctr6->more_data) {
+ req->req8.highwatermark = ctr6->new_highwatermark;
+ } else {
+ last_query = true;
+ if (ctr6->uptodateness_vector &&
+ !ctx->single_object_replication)
+ {
+ new_utdv->version = 2;
+ new_utdv->ctr.ctr2.count =
+ ctr6->uptodateness_vector->count;
+ new_utdv->ctr.ctr2.cursors =
+ ctr6->uptodateness_vector->cursors;
+ }
+ }
+ }
+
+ status = cli_get_session_key(mem_ctx, ctx->cli, &ctx->session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ ctx->error_message = talloc_asprintf(ctx,
+ "Failed to get Session Key: %s",
+ nt_errstr(status));
+ goto out;
+ }
+
+ libnet_dssync_decrypt_attributes(mem_ctx,
+ &ctx->session_key,
+ first_object);
+
+ if (ctx->ops->process_objects) {
+ status = ctx->ops->process_objects(ctx, mem_ctx,
+ first_object,
+ mapping_ctr);
+ if (!NT_STATUS_IS_OK(status)) {
+ ctx->error_message = talloc_asprintf(ctx,
+ "Failed to call processing function: %s",
+ nt_errstr(status));
+ goto out;
+ }
+ }
+ }
+
+ *pnew_utdv = new_utdv;
+
+out:
+ return status;
+}
+
+static NTSTATUS libnet_dssync_process(TALLOC_CTX *mem_ctx,
+ struct dssync_context *ctx)
+{
+ NTSTATUS status;
+
+ int32_t level = 0;
+ union drsuapi_DsGetNCChangesRequest req;
+ struct replUpToDateVectorBlob *old_utdv = NULL;
+ struct replUpToDateVectorBlob *pnew_utdv = NULL;
+ const char **dns;
+ uint32_t dn_count;
+ uint32_t count;
+
+ status = ctx->ops->startup(ctx, mem_ctx, &old_utdv);
+ if (!NT_STATUS_IS_OK(status)) {
+ ctx->error_message = talloc_asprintf(ctx,
+ "Failed to call startup operation: %s",
+ nt_errstr(status));
+ goto out;
+ }
+
+ if (ctx->single_object_replication && ctx->object_dns) {
+ dns = ctx->object_dns;
+ dn_count = ctx->object_count;
+ } else {
+ dns = &ctx->nc_dn;
+ dn_count = 1;
+ }
+
+ for (count=0; count < dn_count; count++) {
+ status = libnet_dssync_build_request(mem_ctx, ctx,
+ dns[count],
+ old_utdv, &level,
+ &req);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ status = libnet_dssync_getncchanges(mem_ctx, ctx, level, &req,
+ &pnew_utdv);
+ if (!NT_STATUS_IS_OK(status)) {
+ ctx->error_message = talloc_asprintf(ctx,
+ "Failed to call DsGetNCCHanges: %s",
+ nt_errstr(status));
+ goto out;
+ }
+ }
+
+ status = ctx->ops->finish(ctx, mem_ctx, pnew_utdv);
+ if (!NT_STATUS_IS_OK(status)) {
+ ctx->error_message = talloc_asprintf(ctx,
+ "Failed to call finishing operation: %s",
+ nt_errstr(status));
+ goto out;
+ }
+
+ out:
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS libnet_dssync(TALLOC_CTX *mem_ctx,
+ struct dssync_context *ctx)
+{
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (!tmp_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = libnet_dssync_init(tmp_ctx, ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ status = libnet_dssync_process(tmp_ctx, ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ out:
+ TALLOC_FREE(tmp_ctx);
+ return status;
+}
+
diff --git a/source3/libnet/libnet_dssync.h b/source3/libnet/libnet_dssync.h
new file mode 100644
index 0000000000..a5a00742c5
--- /dev/null
+++ b/source3/libnet/libnet_dssync.h
@@ -0,0 +1,57 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libnet Support
+ * Copyright (C) Guenther Deschner 2008
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+struct dssync_context;
+
+struct dssync_ops {
+ NTSTATUS (*startup)(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
+ struct replUpToDateVectorBlob **pold_utdv);
+ NTSTATUS (*process_objects)(struct dssync_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaObjectListItemEx *objects,
+ struct drsuapi_DsReplicaOIDMapping_Ctr *mappings);
+ NTSTATUS (*finish)(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
+ struct replUpToDateVectorBlob *new_utdv);
+};
+
+struct dssync_context {
+ const char *domain_name;
+ const char *dns_domain_name;
+ struct rpc_pipe_client *cli;
+ const char *nc_dn;
+ bool single_object_replication;
+ bool force_full_replication;
+ bool clean_old_entries;
+ uint32_t object_count;
+ const char **object_dns;
+ struct policy_handle bind_handle;
+ DATA_BLOB session_key;
+ const char *output_filename;
+ struct drsuapi_DsBindInfo28 remote_info28;
+
+ void *private_data;
+
+ const struct dssync_ops *ops;
+
+ char *result_message;
+ char *error_message;
+};
+
+extern const struct dssync_ops libnet_dssync_keytab_ops;
diff --git a/source3/libnet/libnet_dssync_keytab.c b/source3/libnet/libnet_dssync_keytab.c
new file mode 100644
index 0000000000..6ba2c3aa41
--- /dev/null
+++ b/source3/libnet/libnet_dssync_keytab.c
@@ -0,0 +1,641 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Guenther Deschner <gd@samba.org> 2008
+ Copyright (C) Michael Adam 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+
+#if defined(HAVE_ADS) && defined(ENCTYPE_ARCFOUR_HMAC)
+
+/**
+ * Internal helper function to add data to the list
+ * of keytab entries. It builds the prefix from the input.
+ */
+static NTSTATUS add_to_keytab_entries(TALLOC_CTX *mem_ctx,
+ struct libnet_keytab_context *ctx,
+ uint32_t kvno,
+ const char *name,
+ const char *prefix,
+ const krb5_enctype enctype,
+ DATA_BLOB blob)
+{
+ struct libnet_keytab_entry entry;
+
+ entry.kvno = kvno;
+ entry.name = talloc_strdup(mem_ctx, name);
+ entry.principal = talloc_asprintf(mem_ctx, "%s%s%s@%s",
+ prefix ? prefix : "",
+ prefix ? "/" : "",
+ name, ctx->dns_domain_name);
+ entry.enctype = enctype;
+ entry.password = blob;
+ NT_STATUS_HAVE_NO_MEMORY(entry.name);
+ NT_STATUS_HAVE_NO_MEMORY(entry.principal);
+ NT_STATUS_HAVE_NO_MEMORY(entry.password.data);
+
+ ADD_TO_ARRAY(mem_ctx, struct libnet_keytab_entry, entry,
+ &ctx->entries, &ctx->count);
+ NT_STATUS_HAVE_NO_MEMORY(ctx->entries);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS keytab_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
+ struct replUpToDateVectorBlob **pold_utdv)
+{
+ krb5_error_code ret = 0;
+ struct libnet_keytab_context *keytab_ctx;
+ struct libnet_keytab_entry *entry;
+ struct replUpToDateVectorBlob *old_utdv = NULL;
+ char *principal;
+
+ ret = libnet_keytab_init(mem_ctx, ctx->output_filename, &keytab_ctx);
+ if (ret) {
+ return krb5_to_nt_status(ret);
+ }
+
+ keytab_ctx->dns_domain_name = ctx->dns_domain_name;
+ keytab_ctx->clean_old_entries = ctx->clean_old_entries;
+ ctx->private_data = keytab_ctx;
+
+ principal = talloc_asprintf(mem_ctx, "UTDV/%s@%s",
+ ctx->nc_dn, ctx->dns_domain_name);
+ NT_STATUS_HAVE_NO_MEMORY(principal);
+
+ entry = libnet_keytab_search(keytab_ctx, principal, 0, ENCTYPE_NULL,
+ mem_ctx);
+ if (entry) {
+ enum ndr_err_code ndr_err;
+ old_utdv = talloc(mem_ctx, struct replUpToDateVectorBlob);
+
+ ndr_err = ndr_pull_struct_blob(&entry->password, old_utdv,
+ old_utdv,
+ (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
+ ctx->error_message = talloc_asprintf(ctx,
+ "Failed to pull UpToDateVector: %s",
+ nt_errstr(status));
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(replUpToDateVectorBlob, old_utdv);
+ }
+ }
+
+ if (pold_utdv) {
+ *pold_utdv = old_utdv;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS keytab_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
+ struct replUpToDateVectorBlob *new_utdv)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ krb5_error_code ret = 0;
+ struct libnet_keytab_context *keytab_ctx =
+ (struct libnet_keytab_context *)ctx->private_data;
+
+ if (new_utdv) {
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(replUpToDateVectorBlob, new_utdv);
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob, mem_ctx, new_utdv,
+ (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ ctx->error_message = talloc_asprintf(ctx,
+ "Failed to push UpToDateVector: %s",
+ nt_errstr(status));
+ goto done;
+ }
+
+ status = add_to_keytab_entries(mem_ctx, keytab_ctx, 0,
+ ctx->nc_dn, "UTDV",
+ ENCTYPE_NULL,
+ blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ }
+
+ ret = libnet_keytab_add(keytab_ctx);
+ if (ret) {
+ status = krb5_to_nt_status(ret);
+ ctx->error_message = talloc_asprintf(ctx,
+ "Failed to add entries to keytab %s: %s",
+ keytab_ctx->keytab_name, error_message(ret));
+ goto done;
+ }
+
+ ctx->result_message = talloc_asprintf(ctx,
+ "Vampired %d accounts to keytab %s",
+ keytab_ctx->count,
+ keytab_ctx->keytab_name);
+
+done:
+ TALLOC_FREE(keytab_ctx);
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS parse_supplemental_credentials(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob,
+ struct package_PrimaryKerberosCtr3 **pkb3,
+ struct package_PrimaryKerberosCtr4 **pkb4)
+{
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ struct supplementalCredentialsBlob scb;
+ struct supplementalCredentialsPackage *scpk = NULL;
+ DATA_BLOB scpk_blob;
+ struct package_PrimaryKerberosBlob *pkb;
+ bool newer_keys = false;
+ uint32_t j;
+
+ ndr_err = ndr_pull_struct_blob_all(blob, mem_ctx, &scb,
+ (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ goto done;
+ }
+ if (scb.sub.signature !=
+ SUPPLEMENTAL_CREDENTIALS_SIGNATURE)
+ {
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(supplementalCredentialsBlob, &scb);
+ }
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+ for (j=0; j < scb.sub.num_packages; j++) {
+ if (strcmp("Primary:Kerberos-Newer-Keys",
+ scb.sub.packages[j].name) == 0)
+ {
+ scpk = &scb.sub.packages[j];
+ if (!scpk->data || !scpk->data[0]) {
+ scpk = NULL;
+ continue;
+ }
+ newer_keys = true;
+ break;
+ } else if (strcmp("Primary:Kerberos",
+ scb.sub.packages[j].name) == 0)
+ {
+ /*
+ * grab this but don't break here:
+ * there might still be newer-keys ...
+ */
+ scpk = &scb.sub.packages[j];
+ if (!scpk->data || !scpk->data[0]) {
+ scpk = NULL;
+ }
+ }
+ }
+
+ if (!scpk) {
+ /* no data */
+ status = NT_STATUS_OK;
+ goto done;
+ }
+
+ scpk_blob = strhex_to_data_blob(mem_ctx, scpk->data);
+ if (!scpk_blob.data) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ pkb = TALLOC_ZERO_P(mem_ctx, struct package_PrimaryKerberosBlob);
+ if (!pkb) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ ndr_err = ndr_pull_struct_blob(&scpk_blob, mem_ctx, pkb,
+ (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ goto done;
+ }
+
+ if (!newer_keys && pkb->version != 3) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if (newer_keys && pkb->version != 4) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if (pkb->version == 4 && pkb4) {
+ *pkb4 = &pkb->ctr.ctr4;
+ } else if (pkb->version == 3 && pkb3) {
+ *pkb3 = &pkb->ctr.ctr3;
+ }
+
+ status = NT_STATUS_OK;
+
+done:
+ return status;
+}
+
+static NTSTATUS parse_object(TALLOC_CTX *mem_ctx,
+ struct libnet_keytab_context *ctx,
+ struct drsuapi_DsReplicaObjectListItemEx *cur)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ uchar nt_passwd[16];
+ DATA_BLOB *blob;
+ int i = 0;
+ struct drsuapi_DsReplicaAttribute *attr;
+ bool got_pwd = false;
+
+ struct package_PrimaryKerberosCtr3 *pkb3 = NULL;
+ struct package_PrimaryKerberosCtr4 *pkb4 = NULL;
+
+ char *object_dn = NULL;
+ char *upn = NULL;
+ char **spn = NULL;
+ uint32_t num_spns = 0;
+ char *name = NULL;
+ uint32_t kvno = 0;
+ uint32_t uacc = 0;
+ uint32_t sam_type = 0;
+
+ uint32_t pwd_history_len = 0;
+ uint8_t *pwd_history = NULL;
+
+ ZERO_STRUCT(nt_passwd);
+
+ object_dn = talloc_strdup(mem_ctx, cur->object.identifier->dn);
+ if (!object_dn) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(3, ("parsing object '%s'\n", object_dn));
+
+ for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
+
+ attr = &cur->object.attribute_ctr.attributes[i];
+
+ if (attr->attid == DRSUAPI_ATTRIBUTE_servicePrincipalName) {
+ uint32_t count;
+ num_spns = attr->value_ctr.num_values;
+ spn = TALLOC_ARRAY(mem_ctx, char *, num_spns);
+ for (count = 0; count < num_spns; count++) {
+ blob = attr->value_ctr.values[count].blob;
+ pull_string_talloc(spn, NULL, 0,
+ &spn[count],
+ blob->data, blob->length,
+ STR_UNICODE);
+ }
+ }
+
+ if (attr->value_ctr.num_values != 1) {
+ continue;
+ }
+
+ if (!attr->value_ctr.values[0].blob) {
+ continue;
+ }
+
+ blob = attr->value_ctr.values[0].blob;
+
+ switch (attr->attid) {
+ case DRSUAPI_ATTRIBUTE_unicodePwd:
+
+ if (blob->length != 16) {
+ break;
+ }
+
+ memcpy(&nt_passwd, blob->data, 16);
+ got_pwd = true;
+
+ /* pick the kvno from the meta_data version,
+ * thanks, metze, for explaining this */
+
+ if (!cur->meta_data_ctr) {
+ break;
+ }
+ if (cur->meta_data_ctr->count !=
+ cur->object.attribute_ctr.num_attributes) {
+ break;
+ }
+ kvno = cur->meta_data_ctr->meta_data[i].version;
+ break;
+ case DRSUAPI_ATTRIBUTE_ntPwdHistory:
+ pwd_history_len = blob->length / 16;
+ pwd_history = blob->data;
+ break;
+ case DRSUAPI_ATTRIBUTE_userPrincipalName:
+ pull_string_talloc(mem_ctx, NULL, 0, &upn,
+ blob->data, blob->length,
+ STR_UNICODE);
+ break;
+ case DRSUAPI_ATTRIBUTE_sAMAccountName:
+ pull_string_talloc(mem_ctx, NULL, 0, &name,
+ blob->data, blob->length,
+ STR_UNICODE);
+ break;
+ case DRSUAPI_ATTRIBUTE_sAMAccountType:
+ sam_type = IVAL(blob->data, 0);
+ break;
+ case DRSUAPI_ATTRIBUTE_userAccountControl:
+ uacc = IVAL(blob->data, 0);
+ break;
+ case DRSUAPI_ATTRIBUTE_supplementalCredentials:
+ status = parse_supplemental_credentials(mem_ctx,
+ blob,
+ &pkb3,
+ &pkb4);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(2, ("parsing of supplemental "
+ "credentials failed: %s\n",
+ nt_errstr(status)));
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!got_pwd) {
+ DEBUG(10, ("no password (unicodePwd) found - skipping.\n"));
+ return NT_STATUS_OK;
+ }
+
+ if (name) {
+ status = add_to_keytab_entries(mem_ctx, ctx, 0, object_dn,
+ "SAMACCOUNTNAME",
+ ENCTYPE_NULL,
+ data_blob_talloc(mem_ctx, name,
+ strlen(name) + 1));
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ } else {
+ /* look into keytab ... */
+ struct libnet_keytab_entry *entry = NULL;
+ char *principal = NULL;
+
+ DEBUG(10, ("looking for SAMACCOUNTNAME/%s@%s in keytayb...\n",
+ object_dn, ctx->dns_domain_name));
+
+ principal = talloc_asprintf(mem_ctx, "%s/%s@%s",
+ "SAMACCOUNTNAME",
+ object_dn,
+ ctx->dns_domain_name);
+ if (!principal) {
+ DEBUG(1, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ entry = libnet_keytab_search(ctx, principal, 0, ENCTYPE_NULL,
+ mem_ctx);
+ if (entry) {
+ name = (char *)TALLOC_MEMDUP(mem_ctx,
+ entry->password.data,
+ entry->password.length);
+ if (!name) {
+ DEBUG(1, ("talloc failed!"));
+ return NT_STATUS_NO_MEMORY;
+ } else {
+ DEBUG(10, ("found name %s\n", name));
+ }
+ TALLOC_FREE(entry);
+ } else {
+ DEBUG(10, ("entry not found\n"));
+ }
+ TALLOC_FREE(principal);
+ }
+
+ if (!name) {
+ DEBUG(10, ("no name (sAMAccountName) found - skipping.\n"));
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(1,("#%02d: %s:%d, ", ctx->count, name, kvno));
+ DEBUGADD(1,("sAMAccountType: 0x%08x, userAccountControl: 0x%08x",
+ sam_type, uacc));
+ if (upn) {
+ DEBUGADD(1,(", upn: %s", upn));
+ }
+ if (num_spns > 0) {
+ DEBUGADD(1, (", spns: ["));
+ for (i = 0; i < num_spns; i++) {
+ DEBUGADD(1, ("%s%s", spn[i],
+ (i+1 == num_spns)?"]":", "));
+ }
+ }
+ DEBUGADD(1,("\n"));
+
+ status = add_to_keytab_entries(mem_ctx, ctx, kvno, name, NULL,
+ ENCTYPE_ARCFOUR_HMAC,
+ data_blob_talloc(mem_ctx, nt_passwd, 16));
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* add kerberos keys (if any) */
+
+ if (pkb4) {
+ for (i=0; i < pkb4->num_keys; i++) {
+ if (!pkb4->keys[i].value) {
+ continue;
+ }
+ status = add_to_keytab_entries(mem_ctx, ctx, kvno,
+ name,
+ NULL,
+ pkb4->keys[i].keytype,
+ *pkb4->keys[i].value);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ for (i=0; i < pkb4->num_old_keys; i++) {
+ if (!pkb4->old_keys[i].value) {
+ continue;
+ }
+ status = add_to_keytab_entries(mem_ctx, ctx, kvno - 1,
+ name,
+ NULL,
+ pkb4->old_keys[i].keytype,
+ *pkb4->old_keys[i].value);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ for (i=0; i < pkb4->num_older_keys; i++) {
+ if (!pkb4->older_keys[i].value) {
+ continue;
+ }
+ status = add_to_keytab_entries(mem_ctx, ctx, kvno - 2,
+ name,
+ NULL,
+ pkb4->older_keys[i].keytype,
+ *pkb4->older_keys[i].value);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ }
+
+ if (pkb3) {
+ for (i=0; i < pkb3->num_keys; i++) {
+ if (!pkb3->keys[i].value) {
+ continue;
+ }
+ status = add_to_keytab_entries(mem_ctx, ctx, kvno, name,
+ NULL,
+ pkb3->keys[i].keytype,
+ *pkb3->keys[i].value);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ for (i=0; i < pkb3->num_old_keys; i++) {
+ if (!pkb3->old_keys[i].value) {
+ continue;
+ }
+ status = add_to_keytab_entries(mem_ctx, ctx, kvno - 1,
+ name,
+ NULL,
+ pkb3->old_keys[i].keytype,
+ *pkb3->old_keys[i].value);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ }
+
+ if ((kvno < 0) && (kvno < pwd_history_len)) {
+ return status;
+ }
+
+ /* add password history */
+
+ /* skip first entry */
+ if (got_pwd) {
+ kvno--;
+ i = 1;
+ } else {
+ i = 0;
+ }
+
+ for (; i<pwd_history_len; i++) {
+ status = add_to_keytab_entries(mem_ctx, ctx, kvno--, name, NULL,
+ ENCTYPE_ARCFOUR_HMAC,
+ data_blob_talloc(mem_ctx, &pwd_history[i*16], 16));
+ if (!NT_STATUS_IS_OK(status)) {
+ break;
+ }
+ }
+
+ return status;
+}
+
+static bool dn_is_in_object_list(struct dssync_context *ctx,
+ const char *dn)
+{
+ uint32_t count;
+
+ if (ctx->object_count == 0) {
+ return true;
+ }
+
+ for (count = 0; count < ctx->object_count; count++) {
+ if (strequal(ctx->object_dns[count], dn)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS keytab_process_objects(struct dssync_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaObjectListItemEx *cur,
+ struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ struct libnet_keytab_context *keytab_ctx =
+ (struct libnet_keytab_context *)ctx->private_data;
+
+ for (; cur; cur = cur->next_object) {
+ /*
+ * When not in single object replication mode,
+ * the object_dn list is used as a positive write filter.
+ */
+ if (!ctx->single_object_replication &&
+ !dn_is_in_object_list(ctx, cur->object.identifier->dn))
+ {
+ continue;
+ }
+
+ status = parse_object(mem_ctx, keytab_ctx, cur);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+ }
+
+ out:
+ return status;
+}
+
+#else
+
+static NTSTATUS keytab_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
+ struct replUpToDateVectorBlob **pold_utdv)
+{
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+static NTSTATUS keytab_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
+ struct replUpToDateVectorBlob *new_utdv)
+{
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+static NTSTATUS keytab_process_objects(struct dssync_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsReplicaObjectListItemEx *cur,
+ struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
+{
+ return NT_STATUS_NOT_SUPPORTED;
+}
+#endif /* defined(HAVE_ADS) && defined(ENCTYPE_ARCFOUR_HMAC) */
+
+const struct dssync_ops libnet_dssync_keytab_ops = {
+ .startup = keytab_startup,
+ .process_objects = keytab_process_objects,
+ .finish = keytab_finish,
+};
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
new file mode 100644
index 0000000000..a39dee676f
--- /dev/null
+++ b/source3/libnet/libnet_join.c
@@ -0,0 +1,2018 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libnet Join Support
+ * Copyright (C) Gerald (Jerry) Carter 2006
+ * Copyright (C) Guenther Deschner 2007-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "libnet/libnet.h"
+
+/****************************************************************
+****************************************************************/
+
+#define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
+ do { \
+ char *str = NULL; \
+ str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
+ DEBUG(1,("libnet_Join:\n%s", str)); \
+ TALLOC_FREE(str); \
+ } while (0)
+
+#define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
+ LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
+#define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
+ LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
+
+#define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
+ do { \
+ char *str = NULL; \
+ str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
+ DEBUG(1,("libnet_Unjoin:\n%s", str)); \
+ TALLOC_FREE(str); \
+ } while (0)
+
+#define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
+ LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
+#define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
+ LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
+
+#define W_ERROR_NOT_OK_GOTO_DONE(x) do { \
+ if (!W_ERROR_IS_OK(x)) {\
+ goto done;\
+ }\
+} while (0)
+
+/****************************************************************
+****************************************************************/
+
+static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r,
+ const char *format, ...)
+{
+ va_list args;
+
+ if (r->out.error_string) {
+ return;
+ }
+
+ va_start(args, format);
+ r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
+ va_end(args);
+}
+
+/****************************************************************
+****************************************************************/
+
+static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
+ struct libnet_UnjoinCtx *r,
+ const char *format, ...)
+{
+ va_list args;
+
+ if (r->out.error_string) {
+ return;
+ }
+
+ va_start(args, format);
+ r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
+ va_end(args);
+}
+
+#ifdef WITH_ADS
+
+/****************************************************************
+****************************************************************/
+
+static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
+ const char *netbios_domain_name,
+ const char *dc_name,
+ const char *user_name,
+ const char *password,
+ ADS_STRUCT **ads)
+{
+ ADS_STATUS status;
+ ADS_STRUCT *my_ads = NULL;
+
+ my_ads = ads_init(dns_domain_name,
+ netbios_domain_name,
+ dc_name);
+ if (!my_ads) {
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+
+ if (user_name) {
+ SAFE_FREE(my_ads->auth.user_name);
+ my_ads->auth.user_name = SMB_STRDUP(user_name);
+ }
+
+ if (password) {
+ SAFE_FREE(my_ads->auth.password);
+ my_ads->auth.password = SMB_STRDUP(password);
+ }
+
+ status = ads_connect_user_creds(my_ads);
+ if (!ADS_ERR_OK(status)) {
+ ads_destroy(&my_ads);
+ return status;
+ }
+
+ *ads = my_ads;
+ return ADS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ ADS_STATUS status;
+
+ status = libnet_connect_ads(r->out.dns_domain_name,
+ r->out.netbios_domain_name,
+ r->in.dc_name,
+ r->in.admin_account,
+ r->in.admin_password,
+ &r->in.ads);
+ if (!ADS_ERR_OK(status)) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "failed to connect to AD: %s",
+ ads_errstr(status));
+ return status;
+ }
+
+ if (!r->out.netbios_domain_name) {
+ r->out.netbios_domain_name = talloc_strdup(mem_ctx,
+ r->in.ads->server.workgroup);
+ ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
+ }
+
+ if (!r->out.dns_domain_name) {
+ r->out.dns_domain_name = talloc_strdup(mem_ctx,
+ r->in.ads->config.realm);
+ ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
+ }
+
+ r->out.domain_is_ad = true;
+
+ return ADS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
+ struct libnet_UnjoinCtx *r)
+{
+ ADS_STATUS status;
+
+ status = libnet_connect_ads(r->in.domain_name,
+ r->in.domain_name,
+ r->in.dc_name,
+ r->in.admin_account,
+ r->in.admin_password,
+ &r->in.ads);
+ if (!ADS_ERR_OK(status)) {
+ libnet_unjoin_set_error_string(mem_ctx, r,
+ "failed to connect to AD: %s",
+ ads_errstr(status));
+ }
+
+ return status;
+}
+
+/****************************************************************
+ join a domain using ADS (LDAP mods)
+****************************************************************/
+
+static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ ADS_STATUS status;
+ LDAPMessage *res = NULL;
+ const char *attrs[] = { "dn", NULL };
+ bool moved = false;
+
+ status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ if (ads_count_replies(r->in.ads, res) != 1) {
+ ads_msgfree(r->in.ads, res);
+ return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
+ }
+
+ ads_msgfree(r->in.ads, res);
+
+ /* Attempt to create the machine account and bail if this fails.
+ Assume that the admin wants exactly what they requested */
+
+ status = ads_create_machine_acct(r->in.ads,
+ r->in.machine_name,
+ r->in.account_ou);
+
+ if (ADS_ERR_OK(status)) {
+ DEBUG(1,("machine account creation created\n"));
+ return status;
+ } else if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
+ (status.err.rc == LDAP_ALREADY_EXISTS)) {
+ status = ADS_SUCCESS;
+ }
+
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(1,("machine account creation failed\n"));
+ return status;
+ }
+
+ status = ads_move_machine_acct(r->in.ads,
+ r->in.machine_name,
+ r->in.account_ou,
+ &moved);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(1,("failure to locate/move pre-existing "
+ "machine account\n"));
+ return status;
+ }
+
+ DEBUG(1,("The machine account %s the specified OU.\n",
+ moved ? "was moved into" : "already exists in"));
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
+ struct libnet_UnjoinCtx *r)
+{
+ ADS_STATUS status;
+
+ if (!r->in.ads) {
+ return libnet_unjoin_connect_ads(mem_ctx, r);
+ }
+
+ status = ads_leave_realm(r->in.ads, r->in.machine_name);
+ if (!ADS_ERR_OK(status)) {
+ libnet_unjoin_set_error_string(mem_ctx, r,
+ "failed to leave realm: %s",
+ ads_errstr(status));
+ return status;
+ }
+
+ return ADS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ ADS_STATUS status;
+ LDAPMessage *res = NULL;
+ char *dn = NULL;
+
+ if (!r->in.machine_name) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ status = ads_find_machine_acct(r->in.ads,
+ &res,
+ r->in.machine_name);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ if (ads_count_replies(r->in.ads, res) != 1) {
+ status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ goto done;
+ }
+
+ dn = ads_get_dn(r->in.ads, res);
+ if (!dn) {
+ status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ goto done;
+ }
+
+ r->out.dn = talloc_strdup(mem_ctx, dn);
+ if (!r->out.dn) {
+ status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ goto done;
+ }
+
+ done:
+ ads_msgfree(r->in.ads, res);
+ ads_memfree(r->in.ads, dn);
+
+ return status;
+}
+
+/****************************************************************
+ Set a machines dNSHostName and servicePrincipalName attributes
+****************************************************************/
+
+static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ ADS_STATUS status;
+ ADS_MODLIST mods;
+ fstring my_fqdn;
+ const char *spn_array[3] = {NULL, NULL, NULL};
+ char *spn = NULL;
+
+ /* Find our DN */
+
+ status = libnet_join_find_machine_acct(mem_ctx, r);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ /* Windows only creates HOST/shortname & HOST/fqdn. */
+
+ spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
+ if (!spn) {
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+ strupper_m(spn);
+ spn_array[0] = spn;
+
+ if (name_to_fqdn(my_fqdn, r->in.machine_name) &&
+ !strequal(my_fqdn, r->in.machine_name)) {
+
+ strlower_m(my_fqdn);
+ spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
+ if (!spn) {
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+ spn_array[1] = spn;
+ }
+
+ mods = ads_init_mods(mem_ctx);
+ if (!mods) {
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+
+ /* fields of primary importance */
+
+ status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
+ if (!ADS_ERR_OK(status)) {
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+
+ status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
+ spn_array);
+ if (!ADS_ERR_OK(status)) {
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+
+ return ads_gen_mod(r->in.ads, r->out.dn, mods);
+}
+
+/****************************************************************
+****************************************************************/
+
+static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ ADS_STATUS status;
+ ADS_MODLIST mods;
+
+ if (!r->in.create_upn) {
+ return ADS_SUCCESS;
+ }
+
+ /* Find our DN */
+
+ status = libnet_join_find_machine_acct(mem_ctx, r);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ if (!r->in.upn) {
+ r->in.upn = talloc_asprintf(mem_ctx,
+ "host/%s@%s",
+ r->in.machine_name,
+ r->out.dns_domain_name);
+ if (!r->in.upn) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ }
+
+ /* now do the mods */
+
+ mods = ads_init_mods(mem_ctx);
+ if (!mods) {
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+
+ /* fields of primary importance */
+
+ status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
+ if (!ADS_ERR_OK(status)) {
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+
+ return ads_gen_mod(r->in.ads, r->out.dn, mods);
+}
+
+
+/****************************************************************
+****************************************************************/
+
+static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ ADS_STATUS status;
+ ADS_MODLIST mods;
+ char *os_sp = NULL;
+
+ if (!r->in.os_name || !r->in.os_version ) {
+ return ADS_SUCCESS;
+ }
+
+ /* Find our DN */
+
+ status = libnet_join_find_machine_acct(mem_ctx, r);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ /* now do the mods */
+
+ mods = ads_init_mods(mem_ctx);
+ if (!mods) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ os_sp = talloc_asprintf(mem_ctx, "Samba %s", SAMBA_VERSION_STRING);
+ if (!os_sp) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ /* fields of primary importance */
+
+ status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
+ r->in.os_name);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
+ r->in.os_version);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
+ os_sp);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ return ads_gen_mod(r->in.ads, r->out.dn, mods);
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ if (!lp_use_kerberos_keytab()) {
+ return true;
+ }
+
+ if (ads_keytab_create_default(r->in.ads) != 0) {
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ uint32_t domain_func;
+ ADS_STATUS status;
+ const char *salt = NULL;
+ char *std_salt = NULL;
+
+ status = ads_domain_func_level(r->in.ads, &domain_func);
+ if (!ADS_ERR_OK(status)) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "failed to determine domain functional level: %s",
+ ads_errstr(status));
+ return false;
+ }
+
+ /* go ahead and setup the default salt */
+
+ std_salt = kerberos_standard_des_salt();
+ if (!std_salt) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "failed to obtain standard DES salt");
+ return false;
+ }
+
+ salt = talloc_strdup(mem_ctx, std_salt);
+ if (!salt) {
+ return false;
+ }
+
+ SAFE_FREE(std_salt);
+
+ /* if it's a Windows functional domain, we have to look for the UPN */
+
+ if (domain_func == DS_DOMAIN_FUNCTION_2000) {
+ char *upn;
+
+ upn = ads_get_upn(r->in.ads, mem_ctx,
+ r->in.machine_name);
+ if (upn) {
+ salt = talloc_strdup(mem_ctx, upn);
+ if (!salt) {
+ return false;
+ }
+ }
+ }
+
+ return kerberos_secrets_store_des_salt(salt);
+}
+
+/****************************************************************
+****************************************************************/
+
+static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ ADS_STATUS status;
+
+ if (!r->in.ads) {
+ status = libnet_join_connect_ads(mem_ctx, r);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+ }
+
+ status = libnet_join_set_machine_spn(mem_ctx, r);
+ if (!ADS_ERR_OK(status)) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "failed to set machine spn: %s",
+ ads_errstr(status));
+ return status;
+ }
+
+ status = libnet_join_set_os_attributes(mem_ctx, r);
+ if (!ADS_ERR_OK(status)) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "failed to set machine os attributes: %s",
+ ads_errstr(status));
+ return status;
+ }
+
+ status = libnet_join_set_machine_upn(mem_ctx, r);
+ if (!ADS_ERR_OK(status)) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "failed to set machine upn: %s",
+ ads_errstr(status));
+ return status;
+ }
+
+ if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
+ return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+ }
+
+ if (!libnet_join_create_keytab(mem_ctx, r)) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "failed to create kerberos keytab");
+ return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+ }
+
+ return ADS_SUCCESS;
+}
+#endif /* WITH_ADS */
+
+/****************************************************************
+ Store the machine password and domain SID
+****************************************************************/
+
+static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ if (!secrets_store_domain_sid(r->out.netbios_domain_name,
+ r->out.domain_sid))
+ {
+ DEBUG(1,("Failed to save domain sid\n"));
+ return false;
+ }
+
+ if (!secrets_store_machine_password(r->in.machine_password,
+ r->out.netbios_domain_name,
+ r->in.secure_channel_type))
+ {
+ DEBUG(1,("Failed to save machine password\n"));
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************
+ Connect dc's IPC$ share
+****************************************************************/
+
+static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
+ const char *user,
+ const char *pass,
+ bool use_kerberos,
+ struct cli_state **cli)
+{
+ int flags = 0;
+
+ if (use_kerberos) {
+ flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
+ }
+
+ if (use_kerberos && pass) {
+ flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
+ }
+
+ return cli_full_connection(cli, NULL,
+ dc,
+ NULL, 0,
+ "IPC$", "IPC",
+ user,
+ NULL,
+ pass,
+ flags,
+ Undefined, NULL);
+}
+
+/****************************************************************
+ Lookup domain dc's info
+****************************************************************/
+
+static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r,
+ struct cli_state **cli)
+{
+ struct rpc_pipe_client *pipe_hnd = NULL;
+ POLICY_HND lsa_pol;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ union lsa_PolicyInformation *info = NULL;
+
+ status = libnet_join_connect_dc_ipc(r->in.dc_name,
+ r->in.admin_account,
+ r->in.admin_password,
+ r->in.use_kerberos,
+ cli);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc.syntax_id,
+ &pipe_hnd);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = rpccli_lsa_QueryInfoPolicy2(pipe_hnd, mem_ctx,
+ &lsa_pol,
+ LSA_POLICY_INFO_DNS,
+ &info);
+ if (NT_STATUS_IS_OK(status)) {
+ r->out.domain_is_ad = true;
+ r->out.netbios_domain_name = info->dns.name.string;
+ r->out.dns_domain_name = info->dns.dns_domain.string;
+ r->out.forest_name = info->dns.dns_forest.string;
+ r->out.domain_sid = sid_dup_talloc(mem_ctx, info->dns.sid);
+ NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ status = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
+ &lsa_pol,
+ LSA_POLICY_INFO_ACCOUNT_DOMAIN,
+ &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ r->out.netbios_domain_name = info->account_domain.name.string;
+ r->out.domain_sid = sid_dup_talloc(mem_ctx, info->account_domain.sid);
+ NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
+ }
+
+ rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
+ TALLOC_FREE(pipe_hnd);
+
+ done:
+ return status;
+}
+
+/****************************************************************
+ Do the domain join
+****************************************************************/
+
+static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r,
+ struct cli_state *cli)
+{
+ struct rpc_pipe_client *pipe_hnd = NULL;
+ POLICY_HND sam_pol, domain_pol, user_pol;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ char *acct_name;
+ struct lsa_String lsa_acct_name;
+ uint32_t user_rid;
+ uint32_t acct_flags = ACB_WSTRUST;
+ uchar md4_trust_password[16];
+ struct samr_Ids user_rids;
+ struct samr_Ids name_types;
+ union samr_UserInfo user_info;
+
+ struct samr_CryptPassword crypt_pwd;
+ struct samr_CryptPasswordEx crypt_pwd_ex;
+
+ ZERO_STRUCT(sam_pol);
+ ZERO_STRUCT(domain_pol);
+ ZERO_STRUCT(user_pol);
+
+ if (!r->in.machine_password) {
+ r->in.machine_password = talloc_strdup(mem_ctx, generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH));
+ NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
+ }
+
+ /* Open the domain */
+
+ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
+ &pipe_hnd);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &sam_pol);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &sam_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ r->out.domain_sid,
+ &domain_pol);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ /* Create domain user */
+
+ acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
+ strlower_m(acct_name);
+
+ init_lsa_String(&lsa_acct_name, acct_name);
+
+ if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
+ uint32_t access_desired =
+ SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
+ SEC_STD_WRITE_DAC | SEC_STD_DELETE |
+ SAMR_USER_ACCESS_SET_PASSWORD |
+ SAMR_USER_ACCESS_GET_ATTRIBUTES |
+ SAMR_USER_ACCESS_SET_ATTRIBUTES;
+ uint32_t access_granted = 0;
+
+ /* Don't try to set any acct_flags flags other than ACB_WSTRUST */
+
+ DEBUG(10,("Creating account with desired access mask: %d\n",
+ access_desired));
+
+ status = rpccli_samr_CreateUser2(pipe_hnd, mem_ctx,
+ &domain_pol,
+ &lsa_acct_name,
+ ACB_WSTRUST,
+ access_desired,
+ &user_pol,
+ &access_granted,
+ &user_rid);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
+
+ DEBUG(10,("Creation of workstation account failed: %s\n",
+ nt_errstr(status)));
+
+ /* If NT_STATUS_ACCESS_DENIED then we have a valid
+ username/password combo but the user does not have
+ administrator access. */
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "User specified does not have "
+ "administrator privileges");
+ }
+
+ goto done;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
+ if (!(r->in.join_flags &
+ WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
+ goto done;
+ }
+ }
+
+ /* We *must* do this.... don't ask... */
+
+ if (NT_STATUS_IS_OK(status)) {
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
+ }
+ }
+
+ status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 1,
+ &lsa_acct_name,
+ &user_rids,
+ &name_types);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (name_types.ids[0] != SID_NAME_USER) {
+ DEBUG(0,("%s is not a user account (type=%d)\n",
+ acct_name, name_types.ids[0]));
+ status = NT_STATUS_INVALID_WORKSTATION;
+ goto done;
+ }
+
+ user_rid = user_rids.ids[0];
+
+ /* Open handle on user */
+
+ status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
+ &domain_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ user_rid,
+ &user_pol);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ /* Create a random machine account password and generate the hash */
+
+ E_md4hash(r->in.machine_password, md4_trust_password);
+
+ init_samr_CryptPasswordEx(r->in.machine_password,
+ &cli->user_session_key,
+ &crypt_pwd_ex);
+
+ /* Fill in the additional account flags now */
+
+ acct_flags |= ACB_PWNOEXP;
+ if (r->out.domain_is_ad) {
+#if !defined(ENCTYPE_ARCFOUR_HMAC)
+ acct_flags |= ACB_USE_DES_KEY_ONLY;
+#endif
+ ;;
+ }
+
+ /* Set password and account flags on machine account */
+
+ ZERO_STRUCT(user_info.info25);
+
+ user_info.info25.info.fields_present = ACCT_NT_PWD_SET |
+ ACCT_LM_PWD_SET |
+ SAMR_FIELD_ACCT_FLAGS;
+
+ user_info.info25.info.acct_flags = acct_flags;
+ memcpy(&user_info.info25.password.data, crypt_pwd_ex.data,
+ sizeof(crypt_pwd_ex.data));
+
+ status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
+ &user_pol,
+ 25,
+ &user_info);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS(DCERPC_FAULT_INVALID_TAG))) {
+
+ /* retry with level 24 */
+
+ init_samr_CryptPassword(r->in.machine_password,
+ &cli->user_session_key,
+ &crypt_pwd);
+
+ init_samr_user_info24(&user_info.info24, crypt_pwd.data, 24);
+
+ status = rpccli_samr_SetUserInfo2(pipe_hnd, mem_ctx,
+ &user_pol,
+ 24,
+ &user_info);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+
+ rpccli_samr_DeleteUser(pipe_hnd, mem_ctx,
+ &user_pol);
+
+ libnet_join_set_error_string(mem_ctx, r,
+ "Failed to set password for machine account (%s)\n",
+ nt_errstr(status));
+ goto done;
+ }
+
+ status = NT_STATUS_OK;
+
+ done:
+ if (!pipe_hnd) {
+ return status;
+ }
+
+ if (is_valid_policy_hnd(&sam_pol)) {
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol);
+ }
+ if (is_valid_policy_hnd(&domain_pol)) {
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
+ }
+ if (is_valid_policy_hnd(&user_pol)) {
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
+ }
+ TALLOC_FREE(pipe_hnd);
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS libnet_join_ok(const char *netbios_domain_name,
+ const char *machine_name,
+ const char *dc_name)
+{
+ uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_hnd = NULL;
+ struct rpc_pipe_client *netlogon_pipe = NULL;
+ NTSTATUS status;
+ char *machine_password = NULL;
+ char *machine_account = NULL;
+
+ if (!dc_name) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!secrets_init()) {
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ machine_password = secrets_fetch_machine_password(netbios_domain_name,
+ NULL, NULL);
+ if (!machine_password) {
+ return NT_STATUS_NO_TRUST_LSA_SECRET;
+ }
+
+ asprintf(&machine_account, "%s$", machine_name);
+ if (!machine_account) {
+ SAFE_FREE(machine_password);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = cli_full_connection(&cli, NULL,
+ dc_name,
+ NULL, 0,
+ "IPC$", "IPC",
+ machine_account,
+ NULL,
+ machine_password,
+ 0,
+ Undefined, NULL);
+ free(machine_account);
+ free(machine_password);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ status = cli_full_connection(&cli, NULL,
+ dc_name,
+ NULL, 0,
+ "IPC$", "IPC",
+ "",
+ NULL,
+ "",
+ 0,
+ Undefined, NULL);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = get_schannel_session_key(cli, netbios_domain_name,
+ &neg_flags, &netlogon_pipe);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_NETWORK_RESPONSE)) {
+ cli_shutdown(cli);
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(0,("libnet_join_ok: failed to get schannel session "
+ "key from server %s for domain %s. Error was %s\n",
+ cli->desthost, netbios_domain_name, nt_errstr(status)));
+ cli_shutdown(cli);
+ return status;
+ }
+
+ if (!lp_client_schannel()) {
+ cli_shutdown(cli);
+ return NT_STATUS_OK;
+ }
+
+ status = cli_rpc_pipe_open_schannel_with_key(
+ cli, &ndr_table_netlogon.syntax_id, PIPE_AUTH_LEVEL_PRIVACY,
+ netbios_domain_name, netlogon_pipe->dc, &pipe_hnd);
+
+ cli_shutdown(cli);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("libnet_join_ok: failed to open schannel session "
+ "on netlogon pipe to server %s for domain %s. "
+ "Error was %s\n",
+ cli->desthost, netbios_domain_name, nt_errstr(status)));
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ NTSTATUS status;
+
+ status = libnet_join_ok(r->out.netbios_domain_name,
+ r->in.machine_name,
+ r->in.dc_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "failed to verify domain membership after joining: %s",
+ get_friendly_nt_error_msg(status));
+ return WERR_SETUP_NOT_JOINED;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
+ struct libnet_UnjoinCtx *r)
+{
+ if (!secrets_delete_machine_password_ex(lp_workgroup())) {
+ return false;
+ }
+
+ if (!secrets_delete_domain_sid(lp_workgroup())) {
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
+ struct libnet_UnjoinCtx *r)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_hnd = NULL;
+ POLICY_HND sam_pol, domain_pol, user_pol;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ char *acct_name;
+ uint32_t user_rid;
+ struct lsa_String lsa_acct_name;
+ struct samr_Ids user_rids;
+ struct samr_Ids name_types;
+ union samr_UserInfo *info = NULL;
+
+ ZERO_STRUCT(sam_pol);
+ ZERO_STRUCT(domain_pol);
+ ZERO_STRUCT(user_pol);
+
+ status = libnet_join_connect_dc_ipc(r->in.dc_name,
+ r->in.admin_account,
+ r->in.admin_password,
+ r->in.use_kerberos,
+ &cli);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ /* Open the domain */
+
+ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
+ &pipe_hnd);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &sam_pol);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &sam_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ r->in.domain_sid,
+ &domain_pol);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ /* Create domain user */
+
+ acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
+ strlower_m(acct_name);
+
+ init_lsa_String(&lsa_acct_name, acct_name);
+
+ status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 1,
+ &lsa_acct_name,
+ &user_rids,
+ &name_types);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (name_types.ids[0] != SID_NAME_USER) {
+ DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
+ name_types.ids[0]));
+ status = NT_STATUS_INVALID_WORKSTATION;
+ goto done;
+ }
+
+ user_rid = user_rids.ids[0];
+
+ /* Open handle on user */
+
+ status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
+ &domain_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ user_rid,
+ &user_pol);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ /* Get user info */
+
+ status = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
+ &user_pol,
+ 16,
+ &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
+ goto done;
+ }
+
+ /* now disable and setuser info */
+
+ info->info16.acct_flags |= ACB_DISABLED;
+
+ status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
+ &user_pol,
+ 16,
+ info);
+
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
+
+done:
+ if (pipe_hnd) {
+ if (is_valid_policy_hnd(&domain_pol)) {
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
+ }
+ if (is_valid_policy_hnd(&sam_pol)) {
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol);
+ }
+ TALLOC_FREE(pipe_hnd);
+ }
+
+ if (cli) {
+ cli_shutdown(cli);
+ }
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
+{
+ WERROR werr;
+ struct smbconf_ctx *ctx;
+
+ werr = smbconf_init_reg(r, &ctx, NULL);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
+
+ werr = smbconf_set_global_parameter(ctx, "security", "user");
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
+
+ werr = smbconf_set_global_parameter(ctx, "workgroup",
+ r->in.domain_name);
+
+ smbconf_delete_global_parameter(ctx, "realm");
+ goto done;
+ }
+
+ werr = smbconf_set_global_parameter(ctx, "security", "domain");
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
+
+ werr = smbconf_set_global_parameter(ctx, "workgroup",
+ r->out.netbios_domain_name);
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
+
+ if (r->out.domain_is_ad) {
+ werr = smbconf_set_global_parameter(ctx, "security", "ads");
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
+
+ werr = smbconf_set_global_parameter(ctx, "realm",
+ r->out.dns_domain_name);
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
+ }
+
+ done:
+ smbconf_shutdown(ctx);
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
+{
+ WERROR werr = WERR_OK;
+ struct smbconf_ctx *ctx;
+
+ werr = smbconf_init_reg(r, &ctx, NULL);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
+
+ werr = smbconf_set_global_parameter(ctx, "security", "user");
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
+
+ werr = smbconf_delete_global_parameter(ctx, "workgroup");
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
+
+ smbconf_delete_global_parameter(ctx, "realm");
+ }
+
+ done:
+ smbconf_shutdown(ctx);
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
+{
+ WERROR werr;
+
+ if (!W_ERROR_IS_OK(r->out.result)) {
+ return r->out.result;
+ }
+
+ if (!r->in.modify_config) {
+ return WERR_OK;
+ }
+
+ werr = do_join_modify_vals_config(r);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
+
+ r->out.modified_config = true;
+ r->out.result = werr;
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
+{
+ WERROR werr;
+
+ if (!W_ERROR_IS_OK(r->out.result)) {
+ return r->out.result;
+ }
+
+ if (!r->in.modify_config) {
+ return WERR_OK;
+ }
+
+ werr = do_unjoin_modify_vals_config(r);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
+
+ r->out.modified_config = true;
+ r->out.result = werr;
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
+ const char *domain_str,
+ const char **domain_p,
+ const char **dc_p)
+{
+ char *domain = NULL;
+ char *dc = NULL;
+ const char *p = NULL;
+
+ if (!domain_str || !domain_p || !dc_p) {
+ return false;
+ }
+
+ p = strchr_m(domain_str, '\\');
+
+ if (p != NULL) {
+ domain = talloc_strndup(mem_ctx, domain_str,
+ PTR_DIFF(p, domain_str));
+ dc = talloc_strdup(mem_ctx, p+1);
+ if (!dc) {
+ return false;
+ }
+ } else {
+ domain = talloc_strdup(mem_ctx, domain_str);
+ dc = NULL;
+ }
+ if (!domain) {
+ return false;
+ }
+
+ *domain_p = domain;
+
+ if (!*dc_p && dc) {
+ *dc_p = dc;
+ }
+
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ if (!r->in.domain_name) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "No domain name defined");
+ return WERR_INVALID_PARAM;
+ }
+
+ if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
+ &r->in.domain_name,
+ &r->in.dc_name)) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "Failed to parse domain name");
+ return WERR_INVALID_PARAM;
+ }
+
+ if (IS_DC) {
+ return WERR_SETUP_DOMAIN_CONTROLLER;
+ }
+
+ if (!secrets_init()) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "Unable to open secrets database");
+ return WERR_CAN_NOT_COMPLETE;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
+{
+ NTSTATUS status;
+
+ /* Try adding dom admins to builtin\admins. Only log failures. */
+ status = create_builtin_administrators(domain_sid);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
+ DEBUG(10,("Unable to auto-add domain administrators to "
+ "BUILTIN\\Administrators during join because "
+ "winbindd must be running."));
+ } else if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("Failed to auto-add domain administrators to "
+ "BUILTIN\\Administrators during join: %s\n",
+ nt_errstr(status)));
+ }
+
+ /* Try adding dom users to builtin\users. Only log failures. */
+ status = create_builtin_users(domain_sid);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
+ DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
+ "during join because winbindd must be running."));
+ } else if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("Failed to auto-add domain administrators to "
+ "BUILTIN\\Administrators during join: %s\n",
+ nt_errstr(status)));
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ WERROR werr;
+
+ if (!W_ERROR_IS_OK(r->out.result)) {
+ return r->out.result;
+ }
+
+ werr = do_JoinConfig(r);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
+ return WERR_OK;
+ }
+
+ saf_store(r->in.domain_name, r->in.dc_name);
+
+#ifdef WITH_ADS
+ if (r->out.domain_is_ad) {
+ ADS_STATUS ads_status;
+
+ ads_status = libnet_join_post_processing_ads(mem_ctx, r);
+ if (!ADS_ERR_OK(ads_status)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ }
+#endif /* WITH_ADS */
+
+ libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
+{
+ const char *krb5_cc_env = NULL;
+
+ if (r->in.ads) {
+ ads_destroy(&r->in.ads);
+ }
+
+ krb5_cc_env = getenv(KRB5_ENV_CCNAME);
+ if (krb5_cc_env && StrCaseCmp(krb5_cc_env, "MEMORY:libnetjoin")) {
+ unsetenv(KRB5_ENV_CCNAME);
+ }
+
+ return 0;
+}
+
+/****************************************************************
+****************************************************************/
+
+static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
+{
+ const char *krb5_cc_env = NULL;
+
+ if (r->in.ads) {
+ ads_destroy(&r->in.ads);
+ }
+
+ krb5_cc_env = getenv(KRB5_ENV_CCNAME);
+ if (krb5_cc_env && StrCaseCmp(krb5_cc_env, "MEMORY:libnetjoin")) {
+ unsetenv(KRB5_ENV_CCNAME);
+ }
+
+ return 0;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx **r)
+{
+ struct libnet_JoinCtx *ctx;
+ const char *krb5_cc_env = NULL;
+
+ ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
+ if (!ctx) {
+ return WERR_NOMEM;
+ }
+
+ talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
+
+ ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
+ W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
+
+ krb5_cc_env = getenv(KRB5_ENV_CCNAME);
+ if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) {
+ krb5_cc_env = talloc_strdup(mem_ctx, "MEMORY:libnetjoin");
+ W_ERROR_HAVE_NO_MEMORY(krb5_cc_env);
+ setenv(KRB5_ENV_CCNAME, krb5_cc_env, 1);
+ }
+
+ ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
+
+ *r = ctx;
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
+ struct libnet_UnjoinCtx **r)
+{
+ struct libnet_UnjoinCtx *ctx;
+ const char *krb5_cc_env = NULL;
+
+ ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
+ if (!ctx) {
+ return WERR_NOMEM;
+ }
+
+ talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
+
+ ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
+ W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
+
+ krb5_cc_env = getenv(KRB5_ENV_CCNAME);
+ if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) {
+ krb5_cc_env = talloc_strdup(mem_ctx, "MEMORY:libnetjoin");
+ W_ERROR_HAVE_NO_MEMORY(krb5_cc_env);
+ setenv(KRB5_ENV_CCNAME, krb5_cc_env, 1);
+ }
+
+ *r = ctx;
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ /* check if configuration is already set correctly */
+
+ switch (r->out.domain_is_ad) {
+ case false:
+ if ((strequal(lp_workgroup(),
+ r->out.netbios_domain_name)) &&
+ (lp_security() == SEC_DOMAIN)) {
+ /* nothing to be done */
+ return WERR_OK;
+ }
+ break;
+ case true:
+ if ((strequal(lp_workgroup(),
+ r->out.netbios_domain_name)) &&
+ (strequal(lp_realm(),
+ r->out.dns_domain_name)) &&
+ ((lp_security() == SEC_ADS) ||
+ (lp_security() == SEC_DOMAIN))) {
+ /* nothing to be done */
+ return WERR_OK;
+ }
+ break;
+ }
+
+ /* check if we are supposed to manipulate configuration */
+
+ if (!r->in.modify_config) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "Invalid configuration and configuration modification "
+ "was not requested");
+ return WERR_CAN_NOT_COMPLETE;
+ }
+
+ /* check if we are able to manipulate configuration */
+
+ if (!lp_config_backend_is_registry()) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "Configuration manipulation requested but not "
+ "supported by backend");
+ return WERR_NOT_SUPPORTED;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ NTSTATUS status;
+ WERROR werr;
+ struct cli_state *cli = NULL;
+#ifdef WITH_ADS
+ ADS_STATUS ads_status;
+#endif /* WITH_ADS */
+
+ if (!r->in.dc_name) {
+ struct netr_DsRGetDCNameInfo *info;
+ const char *dc;
+ status = dsgetdcname(mem_ctx,
+ r->in.msg_ctx,
+ r->in.domain_name,
+ NULL,
+ NULL,
+ DS_DIRECTORY_SERVICE_REQUIRED |
+ DS_WRITABLE_REQUIRED |
+ DS_RETURN_DNS_NAME,
+ &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "failed to find DC for domain %s",
+ r->in.domain_name,
+ get_friendly_nt_error_msg(status));
+ return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
+ }
+
+ dc = strip_hostname(info->dc_unc);
+ r->in.dc_name = talloc_strdup(mem_ctx, dc);
+ W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
+ }
+
+ status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
+ if (!NT_STATUS_IS_OK(status)) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "failed to lookup DC info for domain '%s' over rpc: %s",
+ r->in.domain_name, get_friendly_nt_error_msg(status));
+ return ntstatus_to_werror(status);
+ }
+
+ werr = libnet_join_check_config(mem_ctx, r);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+#ifdef WITH_ADS
+ if (r->out.domain_is_ad && r->in.account_ou) {
+
+ ads_status = libnet_join_connect_ads(mem_ctx, r);
+ if (!ADS_ERR_OK(ads_status)) {
+ return WERR_DEFAULT_JOIN_REQUIRED;
+ }
+
+ ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
+ if (!ADS_ERR_OK(ads_status)) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "failed to precreate account in ou %s: %s",
+ r->in.account_ou,
+ ads_errstr(ads_status));
+ return WERR_DEFAULT_JOIN_REQUIRED;
+ }
+
+ r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
+ }
+#endif /* WITH_ADS */
+
+ status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
+ if (!NT_STATUS_IS_OK(status)) {
+ libnet_join_set_error_string(mem_ctx, r,
+ "failed to join domain '%s' over rpc: %s",
+ r->in.domain_name, get_friendly_nt_error_msg(status));
+ if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
+ return WERR_SETUP_ALREADY_JOINED;
+ }
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
+ werr = WERR_SETUP_NOT_JOINED;
+ goto done;
+ }
+
+ werr = WERR_OK;
+
+ done:
+ if (cli) {
+ cli_shutdown(cli);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ WERROR werr;
+ struct libnet_UnjoinCtx *u = NULL;
+
+ werr = libnet_init_UnjoinCtx(mem_ctx, &u);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ u->in.debug = r->in.debug;
+ u->in.dc_name = r->in.dc_name;
+ u->in.domain_name = r->in.domain_name;
+ u->in.admin_account = r->in.admin_account;
+ u->in.admin_password = r->in.admin_password;
+ u->in.modify_config = r->in.modify_config;
+ u->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
+ WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
+
+ werr = libnet_Unjoin(mem_ctx, u);
+ TALLOC_FREE(u);
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR libnet_Join(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r)
+{
+ WERROR werr;
+
+ if (r->in.debug) {
+ LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
+ }
+
+ werr = libnet_join_pre_processing(mem_ctx, r);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
+ werr = libnet_DomainJoin(mem_ctx, r);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ }
+
+ werr = libnet_join_post_processing(mem_ctx, r);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
+ werr = libnet_join_post_verify(mem_ctx, r);
+ if (!W_ERROR_IS_OK(werr)) {
+ libnet_join_rollback(mem_ctx, r);
+ }
+ }
+
+ done:
+ r->out.result = werr;
+
+ if (r->in.debug) {
+ LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
+ }
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
+ struct libnet_UnjoinCtx *r)
+{
+ NTSTATUS status;
+
+ if (!r->in.domain_sid) {
+ struct dom_sid sid;
+ if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
+ libnet_unjoin_set_error_string(mem_ctx, r,
+ "Unable to fetch domain sid: are we joined?");
+ return WERR_SETUP_NOT_JOINED;
+ }
+ r->in.domain_sid = sid_dup_talloc(mem_ctx, &sid);
+ W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
+ }
+
+ if (!r->in.dc_name) {
+ struct netr_DsRGetDCNameInfo *info;
+ const char *dc;
+ status = dsgetdcname(mem_ctx,
+ r->in.msg_ctx,
+ r->in.domain_name,
+ NULL,
+ NULL,
+ DS_DIRECTORY_SERVICE_REQUIRED |
+ DS_WRITABLE_REQUIRED |
+ DS_RETURN_DNS_NAME,
+ &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ libnet_unjoin_set_error_string(mem_ctx, r,
+ "failed to find DC for domain %s",
+ r->in.domain_name,
+ get_friendly_nt_error_msg(status));
+ return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
+ }
+
+ dc = strip_hostname(info->dc_unc);
+ r->in.dc_name = talloc_strdup(mem_ctx, dc);
+ W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
+ }
+
+ status = libnet_join_unjoindomain_rpc(mem_ctx, r);
+ if (!NT_STATUS_IS_OK(status)) {
+ libnet_unjoin_set_error_string(mem_ctx, r,
+ "failed to disable machine account via rpc: %s",
+ get_friendly_nt_error_msg(status));
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
+ return WERR_SETUP_NOT_JOINED;
+ }
+ return ntstatus_to_werror(status);
+ }
+
+ r->out.disabled_machine_account = true;
+
+#ifdef WITH_ADS
+ if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
+ ADS_STATUS ads_status;
+ libnet_unjoin_connect_ads(mem_ctx, r);
+ ads_status = libnet_unjoin_remove_machine_acct(mem_ctx, r);
+ if (!ADS_ERR_OK(ads_status)) {
+ libnet_unjoin_set_error_string(mem_ctx, r,
+ "failed to remove machine account from AD: %s",
+ ads_errstr(ads_status));
+ } else {
+ r->out.deleted_machine_account = true;
+ /* dirty hack */
+ r->out.dns_domain_name = talloc_strdup(mem_ctx,
+ r->in.ads->server.realm);
+ W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
+ }
+ }
+#endif /* WITH_ADS */
+
+ libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
+ struct libnet_UnjoinCtx *r)
+{
+ if (!r->in.domain_name) {
+ libnet_unjoin_set_error_string(mem_ctx, r,
+ "No domain name defined");
+ return WERR_INVALID_PARAM;
+ }
+
+ if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
+ &r->in.domain_name,
+ &r->in.dc_name)) {
+ libnet_unjoin_set_error_string(mem_ctx, r,
+ "Failed to parse domain name");
+ return WERR_INVALID_PARAM;
+ }
+
+ if (IS_DC) {
+ return WERR_SETUP_DOMAIN_CONTROLLER;
+ }
+
+ if (!secrets_init()) {
+ libnet_unjoin_set_error_string(mem_ctx, r,
+ "Unable to open secrets database");
+ return WERR_CAN_NOT_COMPLETE;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
+ struct libnet_UnjoinCtx *r)
+{
+ saf_delete(r->out.netbios_domain_name);
+ saf_delete(r->out.dns_domain_name);
+
+ return libnet_unjoin_config(r);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
+ struct libnet_UnjoinCtx *r)
+{
+ WERROR werr;
+
+ if (r->in.debug) {
+ LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
+ }
+
+ werr = libnet_unjoin_pre_processing(mem_ctx, r);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
+ werr = libnet_DomainUnjoin(mem_ctx, r);
+ if (!W_ERROR_IS_OK(werr)) {
+ libnet_unjoin_config(r);
+ goto done;
+ }
+ }
+
+ werr = libnet_unjoin_post_processing(mem_ctx, r);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ done:
+ r->out.result = werr;
+
+ if (r->in.debug) {
+ LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);
+ }
+
+ return werr;
+}
diff --git a/source3/libnet/libnet_keytab.c b/source3/libnet/libnet_keytab.c
new file mode 100644
index 0000000000..46c17b219c
--- /dev/null
+++ b/source3/libnet/libnet_keytab.c
@@ -0,0 +1,404 @@
+/*
+ Unix SMB/CIFS implementation.
+ dump the remote SAM using rpc samsync operations
+
+ Copyright (C) Guenther Deschner 2008.
+ Copyright (C) Michael Adam 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libnet/libnet.h"
+
+#ifdef HAVE_KRB5
+
+/****************************************************************
+****************************************************************/
+
+static int keytab_close(struct libnet_keytab_context *ctx)
+{
+ if (!ctx) {
+ return 0;
+ }
+
+ if (ctx->keytab && ctx->context) {
+ krb5_kt_close(ctx->context, ctx->keytab);
+ }
+
+ if (ctx->context) {
+ krb5_free_context(ctx->context);
+ }
+
+ if (ctx->ads) {
+ ads_destroy(&ctx->ads);
+ }
+
+ TALLOC_FREE(ctx);
+
+ return 0;
+}
+
+/****************************************************************
+****************************************************************/
+
+krb5_error_code libnet_keytab_init(TALLOC_CTX *mem_ctx,
+ const char *keytab_name,
+ struct libnet_keytab_context **ctx)
+{
+ krb5_error_code ret = 0;
+ krb5_context context = NULL;
+ krb5_keytab keytab = NULL;
+ const char *keytab_string = NULL;
+
+ struct libnet_keytab_context *r;
+
+ r = TALLOC_ZERO_P(mem_ctx, struct libnet_keytab_context);
+ if (!r) {
+ return ENOMEM;
+ }
+
+ talloc_set_destructor(r, keytab_close);
+
+ initialize_krb5_error_table();
+ ret = krb5_init_context(&context);
+ if (ret) {
+ DEBUG(1,("keytab_init: could not krb5_init_context: %s\n",
+ error_message(ret)));
+ return ret;
+ }
+
+ ret = smb_krb5_open_keytab(context, keytab_name, true, &keytab);
+ if (ret) {
+ DEBUG(1,("keytab_init: smb_krb5_open_keytab failed (%s)\n",
+ error_message(ret)));
+ krb5_free_context(context);
+ return ret;
+ }
+
+ ret = smb_krb5_keytab_name(mem_ctx, context, keytab, &keytab_string);
+ if (ret) {
+ krb5_kt_close(context, keytab);
+ krb5_free_context(context);
+ return ret;
+ }
+
+ r->context = context;
+ r->keytab = keytab;
+ r->keytab_name = keytab_string;
+ r->clean_old_entries = false;
+
+ *ctx = r;
+
+ return 0;
+}
+
+/****************************************************************
+****************************************************************/
+
+/**
+ * Remove all entries that have the given principal, kvno and enctype.
+ */
+static krb5_error_code libnet_keytab_remove_entries(krb5_context context,
+ krb5_keytab keytab,
+ const char *principal,
+ int kvno,
+ const krb5_enctype enctype,
+ bool ignore_kvno)
+{
+ krb5_error_code ret;
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry kt_entry;
+
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(cursor);
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret) {
+ return 0;
+ }
+
+ while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0)
+ {
+ krb5_keyblock *keyp;
+ char *princ_s = NULL;
+
+ if (kt_entry.vno != kvno && !ignore_kvno) {
+ goto cont;
+ }
+
+ keyp = KRB5_KT_KEY(&kt_entry);
+
+ if (KRB5_KEY_TYPE(keyp) != enctype) {
+ goto cont;
+ }
+
+ ret = smb_krb5_unparse_name(context, kt_entry.principal,
+ &princ_s);
+ if (ret) {
+ DEBUG(5, ("smb_krb5_unparse_name failed (%s)\n",
+ error_message(ret)));
+ goto cont;
+ }
+
+ if (strcmp(principal, princ_s) != 0) {
+ goto cont;
+ }
+
+ /* match found - remove */
+
+ DEBUG(10, ("found entry for principal %s, kvno %d, "
+ "enctype %d - trying to remove it\n",
+ princ_s, kt_entry.vno, KRB5_KEY_TYPE(keyp)));
+
+ ret = krb5_kt_end_seq_get(context, keytab, &cursor);
+ ZERO_STRUCT(cursor);
+ if (ret) {
+ DEBUG(5, ("krb5_kt_end_seq_get failed (%s)\n",
+ error_message(ret)));
+ goto cont;
+ }
+
+ ret = krb5_kt_remove_entry(context, keytab,
+ &kt_entry);
+ if (ret) {
+ DEBUG(5, ("krb5_kt_remove_entry failed (%s)\n",
+ error_message(ret)));
+ goto cont;
+ }
+ DEBUG(10, ("removed entry for principal %s, kvno %d, "
+ "enctype %d\n", princ_s, kt_entry.vno,
+ KRB5_KEY_TYPE(keyp)));
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret) {
+ DEBUG(5, ("krb5_kt_start_seq_get failed (%s)\n",
+ error_message(ret)));
+ goto cont;
+ }
+
+cont:
+ smb_krb5_kt_free_entry(context, &kt_entry);
+ SAFE_FREE(princ_s);
+ }
+
+ ret = krb5_kt_end_seq_get(context, keytab, &cursor);
+ if (ret) {
+ DEBUG(5, ("krb5_kt_end_seq_get failed (%s)\n",
+ error_message(ret)));
+ }
+
+ return ret;
+}
+
+static krb5_error_code libnet_keytab_add_entry(krb5_context context,
+ krb5_keytab keytab,
+ krb5_kvno kvno,
+ const char *princ_s,
+ krb5_enctype enctype,
+ krb5_data password)
+{
+ krb5_keyblock *keyp;
+ krb5_keytab_entry kt_entry;
+ krb5_error_code ret;
+
+ /* remove duplicates first ... */
+ ret = libnet_keytab_remove_entries(context, keytab, princ_s, kvno,
+ enctype, false);
+ if (ret) {
+ DEBUG(1, ("libnet_keytab_remove_entries failed: %s\n",
+ error_message(ret)));
+ }
+
+ ZERO_STRUCT(kt_entry);
+
+ kt_entry.vno = kvno;
+
+ ret = smb_krb5_parse_name(context, princ_s, &kt_entry.principal);
+ if (ret) {
+ DEBUG(1, ("smb_krb5_parse_name(%s) failed (%s)\n",
+ princ_s, error_message(ret)));
+ return ret;
+ }
+
+ keyp = KRB5_KT_KEY(&kt_entry);
+
+ if (create_kerberos_key_from_string(context, kt_entry.principal,
+ &password, keyp, enctype, true))
+ {
+ ret = KRB5KRB_ERR_GENERIC;
+ goto done;
+ }
+
+ ret = krb5_kt_add_entry(context, keytab, &kt_entry);
+ if (ret) {
+ DEBUG(1, ("adding entry to keytab failed (%s)\n",
+ error_message(ret)));
+ }
+
+done:
+ krb5_free_keyblock_contents(context, keyp);
+ krb5_free_principal(context, kt_entry.principal);
+ ZERO_STRUCT(kt_entry);
+ smb_krb5_kt_free_entry(context, &kt_entry);
+
+ return ret;
+}
+
+krb5_error_code libnet_keytab_add(struct libnet_keytab_context *ctx)
+{
+ krb5_error_code ret = 0;
+ uint32_t i;
+
+
+ if (ctx->clean_old_entries) {
+ DEBUG(0, ("cleaning old entries...\n"));
+ for (i=0; i < ctx->count; i++) {
+ struct libnet_keytab_entry *entry = &ctx->entries[i];
+
+ ret = libnet_keytab_remove_entries(ctx->context,
+ ctx->keytab,
+ entry->principal,
+ 0,
+ entry->enctype,
+ true);
+ if (ret) {
+ DEBUG(1,("libnet_keytab_add: Failed to remove "
+ "old entries for %s (enctype %u): %s\n",
+ entry->principal, entry->enctype,
+ error_message(ret)));
+ return ret;
+ }
+ }
+ }
+
+ for (i=0; i<ctx->count; i++) {
+
+ struct libnet_keytab_entry *entry = &ctx->entries[i];
+ krb5_data password;
+
+ ZERO_STRUCT(password);
+ password.data = (char *)entry->password.data;
+ password.length = entry->password.length;
+
+ ret = libnet_keytab_add_entry(ctx->context,
+ ctx->keytab,
+ entry->kvno,
+ entry->principal,
+ entry->enctype,
+ password);
+ if (ret) {
+ DEBUG(1,("libnet_keytab_add: "
+ "Failed to add entry to keytab file\n"));
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+struct libnet_keytab_entry *libnet_keytab_search(struct libnet_keytab_context *ctx,
+ const char *principal,
+ int kvno,
+ const krb5_enctype enctype,
+ TALLOC_CTX *mem_ctx)
+{
+ krb5_error_code ret = 0;
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry kt_entry;
+ struct libnet_keytab_entry *entry = NULL;
+
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(cursor);
+
+ ret = krb5_kt_start_seq_get(ctx->context, ctx->keytab, &cursor);
+ if (ret) {
+ DEBUG(10, ("krb5_kt_start_seq_get failed: %s",
+ error_message(ret)));
+ return NULL;
+ }
+
+ while (krb5_kt_next_entry(ctx->context, ctx->keytab, &kt_entry, &cursor) == 0)
+ {
+ krb5_keyblock *keyp;
+ char *princ_s = NULL;
+
+ if (kt_entry.vno != kvno) {
+ goto cont;
+ }
+
+ keyp = KRB5_KT_KEY(&kt_entry);
+
+ if (KRB5_KEY_TYPE(keyp) != enctype) {
+ goto cont;
+ }
+
+ ret = smb_krb5_unparse_name(ctx->context, kt_entry.principal,
+ &princ_s);
+ if (ret) {
+ goto cont;
+ }
+
+ if (strcmp(principal, princ_s) != 0) {
+ goto cont;
+ }
+
+ entry = talloc_zero(mem_ctx, struct libnet_keytab_entry);
+ if (!entry) {
+ DEBUG(3, ("talloc failed\n"));
+ goto fail;
+ }
+
+ entry->name = talloc_strdup(entry, princ_s);
+ if (!entry->name) {
+ DEBUG(3, ("talloc_strdup_failed\n"));
+ goto fail;
+ }
+
+ entry->principal = talloc_strdup(entry, princ_s);
+ if (!entry->principal) {
+ DEBUG(3, ("talloc_strdup_failed\n"));
+ goto fail;
+ }
+
+ entry->password = data_blob_talloc(entry, KRB5_KEY_DATA(keyp),
+ KRB5_KEY_LENGTH(keyp));
+ if (!entry->password.data) {
+ DEBUG(3, ("data_blob_talloc failed\n"));
+ goto fail;
+ }
+
+ DEBUG(10, ("found entry\n"));
+
+ smb_krb5_kt_free_entry(ctx->context, &kt_entry);
+ SAFE_FREE(princ_s);
+ break;
+
+fail:
+ smb_krb5_kt_free_entry(ctx->context, &kt_entry);
+ SAFE_FREE(princ_s);
+ TALLOC_FREE(entry);
+ break;
+
+cont:
+ smb_krb5_kt_free_entry(ctx->context, &kt_entry);
+ SAFE_FREE(princ_s);
+ continue;
+ }
+
+ krb5_kt_end_seq_get(ctx->context, ctx->keytab, &cursor);
+ return entry;
+}
+
+#endif /* HAVE_KRB5 */
diff --git a/source3/libnet/libnet_keytab.h b/source3/libnet/libnet_keytab.h
new file mode 100644
index 0000000000..4d311a48e0
--- /dev/null
+++ b/source3/libnet/libnet_keytab.h
@@ -0,0 +1,42 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libnet Support
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_KRB5
+
+struct libnet_keytab_entry {
+ const char *name;
+ const char *principal;
+ DATA_BLOB password;
+ uint32_t kvno;
+ krb5_enctype enctype;
+};
+
+struct libnet_keytab_context {
+ krb5_context context;
+ krb5_keytab keytab;
+ const char *keytab_name;
+ ADS_STRUCT *ads;
+ const char *dns_domain_name;
+ uint8_t zero_buf[16];
+ uint32_t count;
+ struct libnet_keytab_entry *entries;
+ bool clean_old_entries;
+};
+
+#endif /* HAVE_KRB5 */
diff --git a/source3/libnet/libnet_proto.h b/source3/libnet/libnet_proto.h
new file mode 100644
index 0000000000..43046a44c0
--- /dev/null
+++ b/source3/libnet/libnet_proto.h
@@ -0,0 +1,78 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * collected prototypes header
+ *
+ * frozen from "make proto" in May 2008
+ *
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _LIBNET_PROTO_H_
+#define _LIBNET_PROTO_H_
+
+
+/* The following definitions come from libnet/libnet_join.c */
+
+NTSTATUS libnet_join_ok(const char *netbios_domain_name,
+ const char *machine_name,
+ const char *dc_name);
+WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx **r);
+WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
+ struct libnet_UnjoinCtx **r);
+WERROR libnet_Join(TALLOC_CTX *mem_ctx,
+ struct libnet_JoinCtx *r);
+WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
+ struct libnet_UnjoinCtx *r);
+
+/* The following definitions come from librpc/gen_ndr/ndr_libnet_join.c */
+
+_PUBLIC_ void ndr_print_libnet_JoinCtx(struct ndr_print *ndr, const char *name, int flags, const struct libnet_JoinCtx *r);
+_PUBLIC_ void ndr_print_libnet_UnjoinCtx(struct ndr_print *ndr, const char *name, int flags, const struct libnet_UnjoinCtx *r);
+
+/* The following definitions come from libnet/libnet_keytab.c */
+
+#ifdef HAVE_KRB5
+krb5_error_code libnet_keytab_init(TALLOC_CTX *mem_ctx,
+ const char *keytab_name,
+ struct libnet_keytab_context **ctx);
+krb5_error_code libnet_keytab_add(struct libnet_keytab_context *ctx);
+
+struct libnet_keytab_entry *libnet_keytab_search(struct libnet_keytab_context *ctx,
+ const char *principal, int kvno,
+ const const krb5_enctype enctype,
+ TALLOC_CTX *mem_ctx);
+#endif
+
+/* The following definitions come from libnet/libnet_samsync.c */
+
+NTSTATUS libnet_samsync_init_context(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *domain_sid,
+ struct samsync_context **ctx_p);
+NTSTATUS libnet_samsync(enum netr_SamDatabaseID database_id,
+ struct samsync_context *ctx);
+NTSTATUS pull_netr_AcctLockStr(TALLOC_CTX *mem_ctx,
+ struct lsa_BinaryString *r,
+ struct netr_AcctLockStr **str_p);
+
+/* The following definitions come from libnet/libnet_dssync.c */
+
+NTSTATUS libnet_dssync_init_context(TALLOC_CTX *mem_ctx,
+ struct dssync_context **ctx_p);
+NTSTATUS libnet_dssync(TALLOC_CTX *mem_ctx,
+ struct dssync_context *ctx);
+
+#endif /* _LIBNET_PROTO_H_ */
diff --git a/source3/libnet/libnet_samsync.c b/source3/libnet/libnet_samsync.c
new file mode 100644
index 0000000000..daf27ffb51
--- /dev/null
+++ b/source3/libnet/libnet_samsync.c
@@ -0,0 +1,411 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Extract the user/system database from a remote SamSync server
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
+ Copyright (C) Guenther Deschner <gd@samba.org> 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+#include "libnet/libnet.h"
+
+/**
+ * Decrypt and extract the user's passwords.
+ *
+ * The writes decrypted (no longer 'RID encrypted' or arcfour encrypted)
+ * passwords back into the structure
+ */
+
+static NTSTATUS fix_user(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *session_key,
+ bool rid_crypt,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM *delta)
+{
+
+ uint32_t rid = delta->delta_id_union.rid;
+ struct netr_DELTA_USER *user = delta->delta_union.user;
+ struct samr_Password lm_hash;
+ struct samr_Password nt_hash;
+
+ if (rid_crypt) {
+ if (user->lm_password_present) {
+ sam_pwd_hash(rid, user->lmpassword.hash, lm_hash.hash, 0);
+ user->lmpassword = lm_hash;
+ }
+
+ if (user->nt_password_present) {
+ sam_pwd_hash(rid, user->ntpassword.hash, nt_hash.hash, 0);
+ user->ntpassword = nt_hash;
+ }
+ }
+
+ if (user->user_private_info.SensitiveData) {
+ DATA_BLOB data;
+ struct netr_USER_KEYS keys;
+ enum ndr_err_code ndr_err;
+ data.data = user->user_private_info.SensitiveData;
+ data.length = user->user_private_info.DataLength;
+ SamOEMhashBlob(data.data, data.length, session_key);
+ user->user_private_info.SensitiveData = data.data;
+ user->user_private_info.DataLength = data.length;
+
+ ndr_err = ndr_pull_struct_blob(&data, mem_ctx, &keys,
+ (ndr_pull_flags_fn_t)ndr_pull_netr_USER_KEYS);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ dump_data(10, data.data, data.length);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ if (keys.keys.keys2.lmpassword.length == 16) {
+ if (rid_crypt) {
+ sam_pwd_hash(rid,
+ keys.keys.keys2.lmpassword.pwd.hash,
+ lm_hash.hash, 0);
+ user->lmpassword = lm_hash;
+ } else {
+ user->lmpassword = keys.keys.keys2.lmpassword.pwd;
+ }
+ user->lm_password_present = true;
+ }
+ if (keys.keys.keys2.ntpassword.length == 16) {
+ if (rid_crypt) {
+ sam_pwd_hash(rid,
+ keys.keys.keys2.ntpassword.pwd.hash,
+ nt_hash.hash, 0);
+ user->ntpassword = nt_hash;
+ } else {
+ user->ntpassword = keys.keys.keys2.ntpassword.pwd;
+ }
+ user->nt_password_present = true;
+ }
+ /* TODO: rid decrypt history fields */
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ * Decrypt and extract the secrets
+ *
+ * The writes decrypted secrets back into the structure
+ */
+static NTSTATUS fix_secret(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *session_key,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM *delta)
+{
+ struct netr_DELTA_SECRET *secret = delta->delta_union.secret;
+
+ SamOEMhashBlob(secret->current_cipher.cipher_data,
+ secret->current_cipher.maxlen,
+ session_key);
+
+ SamOEMhashBlob(secret->old_cipher.cipher_data,
+ secret->old_cipher.maxlen,
+ session_key);
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Fix up the delta, dealing with encryption issues so that the final
+ * callback need only do the printing or application logic
+ */
+
+static NTSTATUS samsync_fix_delta(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *session_key,
+ bool rid_crypt,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM *delta)
+{
+ NTSTATUS status = NT_STATUS_OK;
+
+ switch (delta->delta_type) {
+ case NETR_DELTA_USER:
+
+ status = fix_user(mem_ctx,
+ session_key,
+ rid_crypt,
+ database_id,
+ delta);
+ break;
+ case NETR_DELTA_SECRET:
+
+ status = fix_secret(mem_ctx,
+ session_key,
+ database_id,
+ delta);
+ break;
+ default:
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * Fix up the delta, dealing with encryption issues so that the final
+ * callback need only do the printing or application logic
+ */
+
+static NTSTATUS samsync_fix_delta_array(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *session_key,
+ bool rid_crypt,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM_ARRAY *r)
+{
+ NTSTATUS status;
+ int i;
+
+ for (i = 0; i < r->num_deltas; i++) {
+
+ status = samsync_fix_delta(mem_ctx,
+ session_key,
+ rid_crypt,
+ database_id,
+ &r->delta_enum[i]);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * libnet_samsync_init_context
+ */
+
+NTSTATUS libnet_samsync_init_context(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *domain_sid,
+ struct samsync_context **ctx_p)
+{
+ struct samsync_context *ctx;
+
+ *ctx_p = NULL;
+
+ ctx = TALLOC_ZERO_P(mem_ctx, struct samsync_context);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ if (domain_sid) {
+ ctx->domain_sid = sid_dup_talloc(mem_ctx, domain_sid);
+ NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid);
+
+ ctx->domain_sid_str = sid_string_talloc(mem_ctx, ctx->domain_sid);
+ NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid_str);
+ }
+
+ *ctx_p = ctx;
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * samsync_database_str
+ */
+
+static const char *samsync_database_str(enum netr_SamDatabaseID database_id)
+{
+
+ switch (database_id) {
+ case SAM_DATABASE_DOMAIN:
+ return "DOMAIN";
+ case SAM_DATABASE_BUILTIN:
+ return "BUILTIN";
+ case SAM_DATABASE_PRIVS:
+ return "PRIVS";
+ default:
+ return "unknown";
+ }
+}
+
+/**
+ * samsync_debug_str
+ */
+
+static const char *samsync_debug_str(TALLOC_CTX *mem_ctx,
+ enum net_samsync_mode mode,
+ enum netr_SamDatabaseID database_id)
+{
+ const char *action = NULL;
+
+ switch (mode) {
+ case NET_SAMSYNC_MODE_DUMP:
+ action = "Dumping (to stdout)";
+ break;
+ case NET_SAMSYNC_MODE_FETCH_PASSDB:
+ action = "Fetching (to passdb)";
+ break;
+ case NET_SAMSYNC_MODE_FETCH_LDIF:
+ action = "Fetching (to ldif)";
+ break;
+ case NET_SAMSYNC_MODE_FETCH_KEYTAB:
+ action = "Fetching (to keytab)";
+ break;
+ default:
+ action = "Unknown";
+ break;
+ }
+
+ return talloc_asprintf(mem_ctx, "%s %s database",
+ action, samsync_database_str(database_id));
+}
+
+/**
+ * libnet_samsync
+ */
+
+NTSTATUS libnet_samsync(enum netr_SamDatabaseID database_id,
+ struct samsync_context *ctx)
+{
+ NTSTATUS result;
+ TALLOC_CTX *mem_ctx;
+ const char *logon_server = ctx->cli->desthost;
+ const char *computername = global_myname();
+ struct netr_Authenticator credential;
+ struct netr_Authenticator return_authenticator;
+ uint16_t restart_state = 0;
+ uint32_t sync_context = 0;
+ const char *debug_str;
+ DATA_BLOB session_key;
+
+ ZERO_STRUCT(return_authenticator);
+
+ if (!(mem_ctx = talloc_init("libnet_samsync"))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ debug_str = samsync_debug_str(mem_ctx, ctx->mode, database_id);
+ if (debug_str) {
+ d_fprintf(stderr, "%s\n", debug_str);
+ }
+
+ do {
+ struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
+ NTSTATUS callback_status;
+
+ netlogon_creds_client_step(ctx->cli->dc, &credential);
+
+ result = rpccli_netr_DatabaseSync2(ctx->cli, mem_ctx,
+ logon_server,
+ computername,
+ &credential,
+ &return_authenticator,
+ database_id,
+ restart_state,
+ &sync_context,
+ &delta_enum_array,
+ 0xffff);
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) {
+ return result;
+ }
+
+ /* Check returned credentials. */
+ if (!netlogon_creds_client_check(ctx->cli->dc,
+ &return_authenticator.cred)) {
+ DEBUG(0,("credentials chain check failed\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (NT_STATUS_IS_ERR(result)) {
+ break;
+ }
+
+ session_key = data_blob_const(ctx->cli->dc->sess_key, 16);
+
+ samsync_fix_delta_array(mem_ctx,
+ &session_key,
+ false,
+ database_id,
+ delta_enum_array);
+
+ /* Process results */
+ callback_status = ctx->delta_fn(mem_ctx, database_id,
+ delta_enum_array,
+ NT_STATUS_IS_OK(result), ctx);
+ if (!NT_STATUS_IS_OK(callback_status)) {
+ result = callback_status;
+ goto out;
+ }
+
+ TALLOC_FREE(delta_enum_array);
+
+ /* Increment sync_context */
+ sync_context += 1;
+
+ } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
+
+ out:
+ if (NT_STATUS_IS_ERR(result) && !ctx->error_message) {
+
+ ctx->error_message = talloc_asprintf(ctx,
+ "Failed to fetch %s database: %s",
+ samsync_database_str(database_id),
+ nt_errstr(result));
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) {
+
+ ctx->error_message =
+ talloc_asprintf_append(ctx->error_message,
+ "\nPerhaps %s is a Windows native mode domain?",
+ ctx->domain_name);
+ }
+ }
+
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
+
+/**
+ * pull_netr_AcctLockStr
+ */
+
+NTSTATUS pull_netr_AcctLockStr(TALLOC_CTX *mem_ctx,
+ struct lsa_BinaryString *r,
+ struct netr_AcctLockStr **str_p)
+{
+ struct netr_AcctLockStr *str;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+
+ if (!mem_ctx || !r || !str_p) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ *str_p = NULL;
+
+ str = TALLOC_ZERO_P(mem_ctx, struct netr_AcctLockStr);
+ if (!str) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ blob = data_blob_const(r->array, r->length);
+
+ ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, str,
+ (ndr_pull_flags_fn_t)ndr_pull_netr_AcctLockStr);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ *str_p = str;
+
+ return NT_STATUS_OK;
+}
+
diff --git a/source3/libnet/libnet_samsync.h b/source3/libnet/libnet_samsync.h
new file mode 100644
index 0000000000..1f10d2c1c0
--- /dev/null
+++ b/source3/libnet/libnet_samsync.h
@@ -0,0 +1,73 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libnet Support
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+enum net_samsync_mode {
+ NET_SAMSYNC_MODE_FETCH_PASSDB = 0,
+ NET_SAMSYNC_MODE_FETCH_LDIF = 1,
+ NET_SAMSYNC_MODE_FETCH_KEYTAB = 2,
+ NET_SAMSYNC_MODE_DUMP = 3
+};
+
+struct samsync_context;
+
+typedef NTSTATUS (*samsync_delta_fn_t)(TALLOC_CTX *,
+ enum netr_SamDatabaseID,
+ struct netr_DELTA_ENUM_ARRAY *,
+ bool,
+ struct samsync_context *);
+
+struct samsync_context {
+ enum net_samsync_mode mode;
+ const struct dom_sid *domain_sid;
+ const char *domain_sid_str;
+ const char *domain_name;
+ const char *output_filename;
+
+ const char *username;
+ const char *password;
+
+ char *result_message;
+ char *error_message;
+
+ struct rpc_pipe_client *cli;
+ samsync_delta_fn_t delta_fn;
+ void *private_data;
+};
+
+NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM_ARRAY *r,
+ bool last_query,
+ struct samsync_context *ctx);
+NTSTATUS fetch_sam_entries(TALLOC_CTX *mem_ctx,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM_ARRAY *r,
+ bool last_query,
+ struct samsync_context *ctx);
+NTSTATUS display_sam_entries(TALLOC_CTX *mem_ctx,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM_ARRAY *r,
+ bool last_query,
+ struct samsync_context *ctx);
+NTSTATUS fetch_sam_entries_keytab(TALLOC_CTX *mem_ctx,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM_ARRAY *r,
+ bool last_query,
+ struct samsync_context *ctx);
diff --git a/source3/libnet/libnet_samsync_display.c b/source3/libnet/libnet_samsync_display.c
new file mode 100644
index 0000000000..6f7ae4e7aa
--- /dev/null
+++ b/source3/libnet/libnet_samsync_display.c
@@ -0,0 +1,303 @@
+/*
+ Unix SMB/CIFS implementation.
+ dump the remote SAM using rpc samsync operations
+
+ Copyright (C) Andrew Tridgell 2002
+ Copyright (C) Tim Potter 2001,2002
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
+ Modified by Volker Lendecke 2002
+ Copyright (C) Jeremy Allison 2005.
+ Copyright (C) Guenther Deschner 2008.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libnet/libnet.h"
+
+static void display_group_mem_info(uint32_t rid,
+ struct netr_DELTA_GROUP_MEMBER *r)
+{
+ int i;
+ d_printf("Group mem %u: ", rid);
+ for (i=0; i< r->num_rids; i++) {
+ d_printf("%u ", r->rids[i]);
+ }
+ d_printf("\n");
+}
+
+static void display_alias_info(uint32_t rid,
+ struct netr_DELTA_ALIAS *r)
+{
+ d_printf("Alias '%s' ", r->alias_name.string);
+ d_printf("desc='%s' rid=%u\n", r->description.string, r->rid);
+}
+
+static void display_alias_mem(uint32_t rid,
+ struct netr_DELTA_ALIAS_MEMBER *r)
+{
+ int i;
+ d_printf("Alias rid %u: ", rid);
+ for (i=0; i< r->sids.num_sids; i++) {
+ d_printf("%s ", sid_string_tos(r->sids.sids[i].sid));
+ }
+ d_printf("\n");
+}
+
+static void display_account_info(uint32_t rid,
+ struct netr_DELTA_USER *r)
+{
+ fstring hex_nt_passwd, hex_lm_passwd;
+ uchar lm_passwd[16], nt_passwd[16];
+ static uchar zero_buf[16];
+
+ /* Decode hashes from password hash (if they are not NULL) */
+
+ if (memcmp(r->lmpassword.hash, zero_buf, 16) != 0) {
+ sam_pwd_hash(r->rid, r->lmpassword.hash, lm_passwd, 0);
+ pdb_sethexpwd(hex_lm_passwd, lm_passwd, r->acct_flags);
+ } else {
+ pdb_sethexpwd(hex_lm_passwd, NULL, 0);
+ }
+
+ if (memcmp(r->ntpassword.hash, zero_buf, 16) != 0) {
+ sam_pwd_hash(r->rid, r->ntpassword.hash, nt_passwd, 0);
+ pdb_sethexpwd(hex_nt_passwd, nt_passwd, r->acct_flags);
+ } else {
+ pdb_sethexpwd(hex_nt_passwd, NULL, 0);
+ }
+
+ printf("%s:%d:%s:%s:%s:LCT-0\n",
+ r->account_name.string,
+ r->rid, hex_lm_passwd, hex_nt_passwd,
+ pdb_encode_acct_ctrl(r->acct_flags, NEW_PW_FORMAT_SPACE_PADDED_LEN));
+}
+
+static void display_domain_info(struct netr_DELTA_DOMAIN *r)
+{
+ time_t u_logout;
+ struct netr_AcctLockStr *lockstr = NULL;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_tos();
+
+ status = pull_netr_AcctLockStr(mem_ctx, &r->account_lockout,
+ &lockstr);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("failed to pull account lockout string: %s\n",
+ nt_errstr(status));
+ }
+
+ u_logout = uint64s_nt_time_to_unix_abs((const uint64 *)&r->force_logoff_time);
+
+ d_printf("Domain name: %s\n", r->domain_name.string);
+
+ d_printf("Minimal Password Length: %d\n", r->min_password_length);
+ d_printf("Password History Length: %d\n", r->password_history_length);
+
+ d_printf("Force Logoff: %d\n", (int)u_logout);
+
+ d_printf("Max Password Age: %s\n", display_time(r->max_password_age));
+ d_printf("Min Password Age: %s\n", display_time(r->min_password_age));
+
+ if (lockstr) {
+ d_printf("Lockout Time: %s\n", display_time((NTTIME)lockstr->lockout_duration));
+ d_printf("Lockout Reset Time: %s\n", display_time((NTTIME)lockstr->reset_count));
+ d_printf("Bad Attempt Lockout: %d\n", lockstr->bad_attempt_lockout);
+ }
+
+ d_printf("User must logon to change password: %d\n", r->logon_to_chgpass);
+}
+
+static void display_group_info(uint32_t rid, struct netr_DELTA_GROUP *r)
+{
+ d_printf("Group '%s' ", r->group_name.string);
+ d_printf("desc='%s', rid=%u\n", r->description.string, rid);
+}
+
+static void display_delete_group(uint32_t rid)
+{
+ d_printf("Delete Group '%d' ", rid);
+}
+
+static void display_rename_group(uint32_t rid, struct netr_DELTA_RENAME *r)
+{
+ d_printf("Rename Group '%d' ", rid);
+ d_printf("Rename Group: %s -> %s\n",
+ r->OldName.string, r->NewName.string);
+}
+
+static void display_delete_user(uint32_t rid)
+{
+ d_printf("Delete User '%d' ", rid);
+}
+
+static void display_rename_user(uint32_t rid, struct netr_DELTA_RENAME *r)
+{
+ d_printf("Rename User '%d' ", rid);
+ d_printf("Rename User: %s -> %s\n",
+ r->OldName.string, r->NewName.string);
+}
+
+static void display_delete_alias(uint32_t rid)
+{
+ d_printf("Delete Alias '%d' ", rid);
+}
+
+static void display_rename_alias(uint32_t rid, struct netr_DELTA_RENAME *r)
+{
+ d_printf("Rename Alias '%d' ", rid);
+ d_printf("Rename Alias: %s -> %s\n",
+ r->OldName.string, r->NewName.string);
+}
+
+static NTSTATUS display_sam_entry(TALLOC_CTX *mem_ctx,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM *r,
+ bool last_query,
+ struct samsync_context *ctx)
+{
+ union netr_DELTA_UNION u = r->delta_union;
+ union netr_DELTA_ID_UNION id = r->delta_id_union;
+
+ switch (r->delta_type) {
+ case NETR_DELTA_DOMAIN:
+ display_domain_info(u.domain);
+ break;
+ case NETR_DELTA_GROUP:
+ display_group_info(id.rid, u.group);
+ break;
+ case NETR_DELTA_DELETE_GROUP:
+ display_delete_group(id.rid);
+ break;
+ case NETR_DELTA_RENAME_GROUP:
+ display_rename_group(id.rid, u.rename_group);
+ break;
+ case NETR_DELTA_USER:
+ display_account_info(id.rid, u.user);
+ break;
+ case NETR_DELTA_DELETE_USER:
+ display_delete_user(id.rid);
+ break;
+ case NETR_DELTA_RENAME_USER:
+ display_rename_user(id.rid, u.rename_user);
+ break;
+ case NETR_DELTA_GROUP_MEMBER:
+ display_group_mem_info(id.rid, u.group_member);
+ break;
+ case NETR_DELTA_ALIAS:
+ display_alias_info(id.rid, u.alias);
+ break;
+ case NETR_DELTA_DELETE_ALIAS:
+ display_delete_alias(id.rid);
+ break;
+ case NETR_DELTA_RENAME_ALIAS:
+ display_rename_alias(id.rid, u.rename_alias);
+ break;
+ case NETR_DELTA_ALIAS_MEMBER:
+ display_alias_mem(id.rid, u.alias_member);
+ break;
+ case NETR_DELTA_POLICY:
+ printf("Policy\n");
+ break;
+ case NETR_DELTA_TRUSTED_DOMAIN:
+ printf("Trusted Domain: %s\n",
+ u.trusted_domain->domain_name.string);
+ break;
+ case NETR_DELTA_DELETE_TRUST:
+ printf("Delete Trust: %d\n",
+ u.delete_trust.unknown);
+ break;
+ case NETR_DELTA_ACCOUNT:
+ printf("Account\n");
+ break;
+ case NETR_DELTA_DELETE_ACCOUNT:
+ printf("Delete Account: %d\n",
+ u.delete_account.unknown);
+ break;
+ case NETR_DELTA_SECRET:
+ printf("Secret\n");
+ break;
+ case NETR_DELTA_DELETE_SECRET:
+ printf("Delete Secret: %d\n",
+ u.delete_secret.unknown);
+ break;
+ case NETR_DELTA_DELETE_GROUP2:
+ printf("Delete Group2: %s\n",
+ u.delete_group->account_name);
+ break;
+ case NETR_DELTA_DELETE_USER2:
+ printf("Delete User2: %s\n",
+ u.delete_user->account_name);
+ break;
+ case NETR_DELTA_MODIFY_COUNT:
+ printf("sam sequence update: 0x%016llx\n",
+ (unsigned long long) *u.modified_count);
+ break;
+#if 0
+ /* The following types are recognised but not handled */
+ case NETR_DELTA_POLICY:
+ d_printf("NETR_DELTA_POLICY not handled\n");
+ break;
+ case NETR_DELTA_TRUSTED_DOMAIN:
+ d_printf("NETR_DELTA_TRUSTED_DOMAIN not handled\n");
+ break;
+ case NETR_DELTA_ACCOUNT:
+ d_printf("NETR_DELTA_ACCOUNT not handled\n");
+ break;
+ case NETR_DELTA_SECRET:
+ d_printf("NETR_DELTA_SECRET not handled\n");
+ break;
+ case NETR_DELTA_MODIFY_COUNT:
+ d_printf("NETR_DELTA_MODIFY_COUNT not handled\n");
+ break;
+ case NETR_DELTA_DELETE_TRUST:
+ d_printf("NETR_DELTA_DELETE_TRUST not handled\n");
+ break;
+ case NETR_DELTA_DELETE_ACCOUNT:
+ d_printf("NETR_DELTA_DELETE_ACCOUNT not handled\n");
+ break;
+ case NETR_DELTA_DELETE_SECRET:
+ d_printf("NETR_DELTA_DELETE_SECRET not handled\n");
+ break;
+ case NETR_DELTA_DELETE_GROUP2:
+ d_printf("NETR_DELTA_DELETE_GROUP2 not handled\n");
+ break;
+ case NETR_DELTA_DELETE_USER2:
+ d_printf("NETR_DELTA_DELETE_USER2 not handled\n");
+ break;
+#endif
+ default:
+ printf("unknown delta type 0x%02x\n",
+ r->delta_type);
+ break;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS display_sam_entries(TALLOC_CTX *mem_ctx,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM_ARRAY *r,
+ bool last_query,
+ struct samsync_context *ctx)
+{
+ int i;
+
+ for (i = 0; i < r->num_deltas; i++) {
+ display_sam_entry(mem_ctx, database_id, &r->delta_enum[i],
+ last_query, ctx);
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/libnet/libnet_samsync_keytab.c b/source3/libnet/libnet_samsync_keytab.c
new file mode 100644
index 0000000000..f284f08ad9
--- /dev/null
+++ b/source3/libnet/libnet_samsync_keytab.c
@@ -0,0 +1,193 @@
+/*
+ Unix SMB/CIFS implementation.
+ dump the remote SAM using rpc samsync operations
+
+ Copyright (C) Guenther Deschner 2008.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libnet/libnet.h"
+
+#if defined(HAVE_ADS) && defined(ENCTYPE_ARCFOUR_HMAC)
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS keytab_ad_connect(TALLOC_CTX *mem_ctx,
+ const char *domain_name,
+ const char *username,
+ const char *password,
+ struct libnet_keytab_context *ctx)
+{
+ NTSTATUS status;
+ ADS_STATUS ad_status;
+ ADS_STRUCT *ads;
+ struct netr_DsRGetDCNameInfo *info = NULL;
+ const char *dc;
+
+ status = dsgetdcname(mem_ctx, NULL, domain_name, NULL, NULL, 0, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ dc = strip_hostname(info->dc_unc);
+
+ ads = ads_init(NULL, domain_name, dc);
+ NT_STATUS_HAVE_NO_MEMORY(ads);
+
+ if (getenv(KRB5_ENV_CCNAME) == NULL) {
+ setenv(KRB5_ENV_CCNAME, "MEMORY:libnet_samsync_keytab", 1);
+ }
+
+ ads->auth.user_name = SMB_STRDUP(username);
+ ads->auth.password = SMB_STRDUP(password);
+
+ ad_status = ads_connect_user_creds(ads);
+ if (!ADS_ERR_OK(ad_status)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ctx->ads = ads;
+
+ ctx->dns_domain_name = talloc_strdup_upper(mem_ctx, ads->config.realm);
+ NT_STATUS_HAVE_NO_MEMORY(ctx->dns_domain_name);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS fetch_sam_entry_keytab(TALLOC_CTX *mem_ctx,
+ enum netr_SamDatabaseID database_id,
+ uint32_t rid,
+ struct netr_DELTA_USER *r,
+ bool last_query,
+ struct libnet_keytab_context *ctx)
+{
+ uchar nt_passwd[16];
+ struct libnet_keytab_entry entry;
+
+ if (memcmp(r->ntpassword.hash, ctx->zero_buf, 16) == 0) {
+ return NT_STATUS_OK;
+ }
+
+ sam_pwd_hash(rid, r->ntpassword.hash, nt_passwd, 0);
+
+ entry.name = talloc_strdup(mem_ctx, r->account_name.string);
+ entry.principal = talloc_asprintf(mem_ctx, "%s@%s",
+ r->account_name.string,
+ ctx->dns_domain_name);
+ entry.password = data_blob_talloc(mem_ctx, nt_passwd, 16);
+ entry.kvno = ads_get_kvno(ctx->ads, entry.name);
+
+ NT_STATUS_HAVE_NO_MEMORY(entry.name);
+ NT_STATUS_HAVE_NO_MEMORY(entry.principal);
+ NT_STATUS_HAVE_NO_MEMORY(entry.password.data);
+
+
+ ADD_TO_ARRAY(mem_ctx, struct libnet_keytab_entry, entry,
+ &ctx->entries, &ctx->count);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS fetch_sam_entries_keytab(TALLOC_CTX *mem_ctx,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM_ARRAY *r,
+ bool last_query,
+ struct samsync_context *ctx)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ krb5_error_code ret = 0;
+ static struct libnet_keytab_context *keytab_ctx = NULL;
+ int i;
+
+ if (!keytab_ctx) {
+ ret = libnet_keytab_init(mem_ctx, ctx->output_filename,
+ &keytab_ctx);
+ if (ret) {
+ status = krb5_to_nt_status(ret);
+ goto out;
+ }
+ }
+
+ status = keytab_ad_connect(mem_ctx,
+ ctx->domain_name,
+ ctx->username,
+ ctx->password,
+ keytab_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ for (i = 0; i < r->num_deltas; i++) {
+
+ if (r->delta_enum[i].delta_type != NETR_DELTA_USER) {
+ continue;
+ }
+
+ status = fetch_sam_entry_keytab(mem_ctx, database_id,
+ r->delta_enum[i].delta_id_union.rid,
+ r->delta_enum[i].delta_union.user,
+ last_query,
+ keytab_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+ }
+
+ if (last_query) {
+
+ ret = libnet_keytab_add(keytab_ctx);
+ if (ret) {
+ status = krb5_to_nt_status(ret);
+ ctx->error_message = talloc_asprintf(mem_ctx,
+ "Failed to add entries to keytab %s: %s",
+ keytab_ctx->keytab_name, error_message(ret));
+ goto out;
+ }
+
+ ctx->result_message = talloc_asprintf(mem_ctx,
+ "Vampired %d accounts to keytab %s",
+ keytab_ctx->count,
+ keytab_ctx->keytab_name);
+
+ TALLOC_FREE(keytab_ctx);
+ }
+
+ return NT_STATUS_OK;
+ out:
+ TALLOC_FREE(keytab_ctx);
+
+ return status;
+}
+
+#else
+
+NTSTATUS fetch_sam_entries_keytab(TALLOC_CTX *mem_ctx,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM_ARRAY *r,
+ bool last_query,
+ struct samsync_context *ctx)
+{
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+#endif /* defined(HAVE_ADS) && defined(ENCTYPE_ARCFOUR_HMAC) */
diff --git a/source3/libnet/libnet_samsync_ldif.c b/source3/libnet/libnet_samsync_ldif.c
new file mode 100644
index 0000000000..cbae22aad3
--- /dev/null
+++ b/source3/libnet/libnet_samsync_ldif.c
@@ -0,0 +1,1229 @@
+/*
+ Unix SMB/CIFS implementation.
+ dump the remote SAM using rpc samsync operations
+
+ Copyright (C) Andrew Tridgell 2002
+ Copyright (C) Tim Potter 2001,2002
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
+ Modified by Volker Lendecke 2002
+ Copyright (C) Jeremy Allison 2005.
+ Copyright (C) Guenther Deschner 2008.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libnet/libnet_samsync.h"
+
+#ifdef HAVE_LDAP
+
+/* uid's and gid's for writing deltas to ldif */
+static uint32 ldif_gid = 999;
+static uint32 ldif_uid = 999;
+
+/* Structure for mapping accounts to groups */
+/* Array element is the group rid */
+typedef struct _groupmap {
+ uint32_t rid;
+ uint32_t gidNumber;
+ const char *sambaSID;
+ const char *group_dn;
+} GROUPMAP;
+
+typedef struct _accountmap {
+ uint32_t rid;
+ const char *cn;
+} ACCOUNTMAP;
+
+struct samsync_ldif_context {
+ GROUPMAP *groupmap;
+ ACCOUNTMAP *accountmap;
+ bool initialized;
+ const char *add_template;
+ const char *mod_template;
+ char *add_name;
+ char *mod_name;
+ FILE *add_file;
+ FILE *mod_file;
+ FILE *ldif_file;
+ const char *suffix;
+ int num_alloced;
+};
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS populate_ldap_for_ldif(const char *sid,
+ const char *suffix,
+ const char *builtin_sid,
+ FILE *add_fd)
+{
+ const char *user_suffix, *group_suffix, *machine_suffix, *idmap_suffix;
+ char *user_attr=NULL, *group_attr=NULL;
+ char *suffix_attr;
+ int len;
+
+ /* Get the suffix attribute */
+ suffix_attr = sstring_sub(suffix, '=', ',');
+ if (suffix_attr == NULL) {
+ len = strlen(suffix);
+ suffix_attr = (char*)SMB_MALLOC(len+1);
+ memcpy(suffix_attr, suffix, len);
+ suffix_attr[len] = '\0';
+ }
+
+ /* Write the base */
+ fprintf(add_fd, "# %s\n", suffix);
+ fprintf(add_fd, "dn: %s\n", suffix);
+ fprintf(add_fd, "objectClass: dcObject\n");
+ fprintf(add_fd, "objectClass: organization\n");
+ fprintf(add_fd, "o: %s\n", suffix_attr);
+ fprintf(add_fd, "dc: %s\n", suffix_attr);
+ fprintf(add_fd, "\n");
+ fflush(add_fd);
+
+ user_suffix = lp_ldap_user_suffix();
+ if (user_suffix == NULL) {
+ SAFE_FREE(suffix_attr);
+ return NT_STATUS_NO_MEMORY;
+ }
+ /* If it exists and is distinct from other containers,
+ Write the Users entity */
+ if (*user_suffix && strcmp(user_suffix, suffix)) {
+ user_attr = sstring_sub(lp_ldap_user_suffix(), '=', ',');
+ fprintf(add_fd, "# %s\n", user_suffix);
+ fprintf(add_fd, "dn: %s\n", user_suffix);
+ fprintf(add_fd, "objectClass: organizationalUnit\n");
+ fprintf(add_fd, "ou: %s\n", user_attr);
+ fprintf(add_fd, "\n");
+ fflush(add_fd);
+ }
+
+
+ group_suffix = lp_ldap_group_suffix();
+ if (group_suffix == NULL) {
+ SAFE_FREE(suffix_attr);
+ SAFE_FREE(user_attr);
+ return NT_STATUS_NO_MEMORY;
+ }
+ /* If it exists and is distinct from other containers,
+ Write the Groups entity */
+ if (*group_suffix && strcmp(group_suffix, suffix)) {
+ group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
+ fprintf(add_fd, "# %s\n", group_suffix);
+ fprintf(add_fd, "dn: %s\n", group_suffix);
+ fprintf(add_fd, "objectClass: organizationalUnit\n");
+ fprintf(add_fd, "ou: %s\n", group_attr);
+ fprintf(add_fd, "\n");
+ fflush(add_fd);
+ }
+
+ /* If it exists and is distinct from other containers,
+ Write the Computers entity */
+ machine_suffix = lp_ldap_machine_suffix();
+ if (machine_suffix == NULL) {
+ SAFE_FREE(suffix_attr);
+ SAFE_FREE(user_attr);
+ SAFE_FREE(group_attr);
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (*machine_suffix && strcmp(machine_suffix, user_suffix) &&
+ strcmp(machine_suffix, suffix)) {
+ char *machine_ou = NULL;
+ fprintf(add_fd, "# %s\n", machine_suffix);
+ fprintf(add_fd, "dn: %s\n", machine_suffix);
+ fprintf(add_fd, "objectClass: organizationalUnit\n");
+ /* this isn't totally correct as it assumes that
+ there _must_ be an ou. just fixing memleak now. jmcd */
+ machine_ou = sstring_sub(lp_ldap_machine_suffix(), '=', ',');
+ fprintf(add_fd, "ou: %s\n", machine_ou);
+ SAFE_FREE(machine_ou);
+ fprintf(add_fd, "\n");
+ fflush(add_fd);
+ }
+
+ /* If it exists and is distinct from other containers,
+ Write the IdMap entity */
+ idmap_suffix = lp_ldap_idmap_suffix();
+ if (idmap_suffix == NULL) {
+ SAFE_FREE(suffix_attr);
+ SAFE_FREE(user_attr);
+ SAFE_FREE(group_attr);
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (*idmap_suffix &&
+ strcmp(idmap_suffix, user_suffix) &&
+ strcmp(idmap_suffix, suffix)) {
+ char *s;
+ fprintf(add_fd, "# %s\n", idmap_suffix);
+ fprintf(add_fd, "dn: %s\n", idmap_suffix);
+ fprintf(add_fd, "ObjectClass: organizationalUnit\n");
+ s = sstring_sub(lp_ldap_idmap_suffix(), '=', ',');
+ fprintf(add_fd, "ou: %s\n", s);
+ SAFE_FREE(s);
+ fprintf(add_fd, "\n");
+ fflush(add_fd);
+ }
+
+ /* Write the domain entity */
+ fprintf(add_fd, "# %s, %s\n", lp_workgroup(), suffix);
+ fprintf(add_fd, "dn: sambaDomainName=%s,%s\n", lp_workgroup(),
+ suffix);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_DOMINFO);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_IDPOOL);
+ fprintf(add_fd, "sambaDomainName: %s\n", lp_workgroup());
+ fprintf(add_fd, "sambaSID: %s\n", sid);
+ fprintf(add_fd, "uidNumber: %d\n", ++ldif_uid);
+ fprintf(add_fd, "gidNumber: %d\n", ++ldif_gid);
+ fprintf(add_fd, "\n");
+ fflush(add_fd);
+
+ /* Write the Domain Admins entity */
+ fprintf(add_fd, "# Domain Admins, %s, %s\n", group_attr,
+ suffix);
+ fprintf(add_fd, "dn: cn=Domain Admins,ou=%s,%s\n", group_attr,
+ suffix);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
+ fprintf(add_fd, "cn: Domain Admins\n");
+ fprintf(add_fd, "memberUid: Administrator\n");
+ fprintf(add_fd, "description: Netbios Domain Administrators\n");
+ fprintf(add_fd, "gidNumber: 512\n");
+ fprintf(add_fd, "sambaSID: %s-512\n", sid);
+ fprintf(add_fd, "sambaGroupType: 2\n");
+ fprintf(add_fd, "displayName: Domain Admins\n");
+ fprintf(add_fd, "\n");
+ fflush(add_fd);
+
+ /* Write the Domain Users entity */
+ fprintf(add_fd, "# Domain Users, %s, %s\n", group_attr,
+ suffix);
+ fprintf(add_fd, "dn: cn=Domain Users,ou=%s,%s\n", group_attr,
+ suffix);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
+ fprintf(add_fd, "cn: Domain Users\n");
+ fprintf(add_fd, "description: Netbios Domain Users\n");
+ fprintf(add_fd, "gidNumber: 513\n");
+ fprintf(add_fd, "sambaSID: %s-513\n", sid);
+ fprintf(add_fd, "sambaGroupType: 2\n");
+ fprintf(add_fd, "displayName: Domain Users\n");
+ fprintf(add_fd, "\n");
+ fflush(add_fd);
+
+ /* Write the Domain Guests entity */
+ fprintf(add_fd, "# Domain Guests, %s, %s\n", group_attr,
+ suffix);
+ fprintf(add_fd, "dn: cn=Domain Guests,ou=%s,%s\n", group_attr,
+ suffix);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
+ fprintf(add_fd, "cn: Domain Guests\n");
+ fprintf(add_fd, "description: Netbios Domain Guests\n");
+ fprintf(add_fd, "gidNumber: 514\n");
+ fprintf(add_fd, "sambaSID: %s-514\n", sid);
+ fprintf(add_fd, "sambaGroupType: 2\n");
+ fprintf(add_fd, "displayName: Domain Guests\n");
+ fprintf(add_fd, "\n");
+ fflush(add_fd);
+
+ /* Write the Domain Computers entity */
+ fprintf(add_fd, "# Domain Computers, %s, %s\n", group_attr,
+ suffix);
+ fprintf(add_fd, "dn: cn=Domain Computers,ou=%s,%s\n",
+ group_attr, suffix);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
+ fprintf(add_fd, "gidNumber: 515\n");
+ fprintf(add_fd, "cn: Domain Computers\n");
+ fprintf(add_fd, "description: Netbios Domain Computers accounts\n");
+ fprintf(add_fd, "sambaSID: %s-515\n", sid);
+ fprintf(add_fd, "sambaGroupType: 2\n");
+ fprintf(add_fd, "displayName: Domain Computers\n");
+ fprintf(add_fd, "\n");
+ fflush(add_fd);
+
+ /* Write the Admininistrators Groups entity */
+ fprintf(add_fd, "# Administrators, %s, %s\n", group_attr,
+ suffix);
+ fprintf(add_fd, "dn: cn=Administrators,ou=%s,%s\n", group_attr,
+ suffix);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
+ fprintf(add_fd, "gidNumber: 544\n");
+ fprintf(add_fd, "cn: Administrators\n");
+ fprintf(add_fd, "description: Netbios Domain Members can fully administer the computer/sambaDomainName\n");
+ fprintf(add_fd, "sambaSID: %s-544\n", builtin_sid);
+ fprintf(add_fd, "sambaGroupType: 5\n");
+ fprintf(add_fd, "displayName: Administrators\n");
+ fprintf(add_fd, "\n");
+
+ /* Write the Print Operator entity */
+ fprintf(add_fd, "# Print Operators, %s, %s\n", group_attr,
+ suffix);
+ fprintf(add_fd, "dn: cn=Print Operators,ou=%s,%s\n",
+ group_attr, suffix);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
+ fprintf(add_fd, "gidNumber: 550\n");
+ fprintf(add_fd, "cn: Print Operators\n");
+ fprintf(add_fd, "description: Netbios Domain Print Operators\n");
+ fprintf(add_fd, "sambaSID: %s-550\n", builtin_sid);
+ fprintf(add_fd, "sambaGroupType: 5\n");
+ fprintf(add_fd, "displayName: Print Operators\n");
+ fprintf(add_fd, "\n");
+ fflush(add_fd);
+
+ /* Write the Backup Operators entity */
+ fprintf(add_fd, "# Backup Operators, %s, %s\n", group_attr,
+ suffix);
+ fprintf(add_fd, "dn: cn=Backup Operators,ou=%s,%s\n",
+ group_attr, suffix);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
+ fprintf(add_fd, "gidNumber: 551\n");
+ fprintf(add_fd, "cn: Backup Operators\n");
+ fprintf(add_fd, "description: Netbios Domain Members can bypass file security to back up files\n");
+ fprintf(add_fd, "sambaSID: %s-551\n", builtin_sid);
+ fprintf(add_fd, "sambaGroupType: 5\n");
+ fprintf(add_fd, "displayName: Backup Operators\n");
+ fprintf(add_fd, "\n");
+ fflush(add_fd);
+
+ /* Write the Replicators entity */
+ fprintf(add_fd, "# Replicators, %s, %s\n", group_attr, suffix);
+ fprintf(add_fd, "dn: cn=Replicators,ou=%s,%s\n", group_attr,
+ suffix);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
+ fprintf(add_fd, "gidNumber: 552\n");
+ fprintf(add_fd, "cn: Replicators\n");
+ fprintf(add_fd, "description: Netbios Domain Supports file replication in a sambaDomainName\n");
+ fprintf(add_fd, "sambaSID: %s-552\n", builtin_sid);
+ fprintf(add_fd, "sambaGroupType: 5\n");
+ fprintf(add_fd, "displayName: Replicators\n");
+ fprintf(add_fd, "\n");
+ fflush(add_fd);
+
+ /* Deallocate memory, and return */
+ SAFE_FREE(suffix_attr);
+ SAFE_FREE(user_attr);
+ SAFE_FREE(group_attr);
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS map_populate_groups(TALLOC_CTX *mem_ctx,
+ GROUPMAP *groupmap,
+ ACCOUNTMAP *accountmap,
+ const char *sid,
+ const char *suffix,
+ const char *builtin_sid)
+{
+ char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
+
+ /* Map the groups created by populate_ldap_for_ldif */
+ groupmap[0].rid = 512;
+ groupmap[0].gidNumber = 512;
+ groupmap[0].sambaSID = talloc_asprintf(mem_ctx, "%s-512", sid);
+ groupmap[0].group_dn = talloc_asprintf(mem_ctx,
+ "cn=Domain Admins,ou=%s,%s", group_attr, suffix);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap[0].sambaSID);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap[0].group_dn);
+
+ accountmap[0].rid = 512;
+ accountmap[0].cn = talloc_strdup(mem_ctx, "Domain Admins");
+ NT_STATUS_HAVE_NO_MEMORY(accountmap[0].cn);
+
+ groupmap[1].rid = 513;
+ groupmap[1].gidNumber = 513;
+ groupmap[1].sambaSID = talloc_asprintf(mem_ctx, "%s-513", sid);
+ groupmap[1].group_dn = talloc_asprintf(mem_ctx,
+ "cn=Domain Users,ou=%s,%s", group_attr, suffix);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap[1].sambaSID);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap[1].group_dn);
+
+ accountmap[1].rid = 513;
+ accountmap[1].cn = talloc_strdup(mem_ctx, "Domain Users");
+ NT_STATUS_HAVE_NO_MEMORY(accountmap[1].cn);
+
+ groupmap[2].rid = 514;
+ groupmap[2].gidNumber = 514;
+ groupmap[2].sambaSID = talloc_asprintf(mem_ctx, "%s-514", sid);
+ groupmap[2].group_dn = talloc_asprintf(mem_ctx,
+ "cn=Domain Guests,ou=%s,%s", group_attr, suffix);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap[2].sambaSID);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap[2].group_dn);
+
+ accountmap[2].rid = 514;
+ accountmap[2].cn = talloc_strdup(mem_ctx, "Domain Guests");
+ NT_STATUS_HAVE_NO_MEMORY(accountmap[2].cn);
+
+ groupmap[3].rid = 515;
+ groupmap[3].gidNumber = 515;
+ groupmap[3].sambaSID = talloc_asprintf(mem_ctx, "%s-515", sid);
+ groupmap[3].group_dn = talloc_asprintf(mem_ctx,
+ "cn=Domain Computers,ou=%s,%s", group_attr, suffix);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap[3].sambaSID);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap[3].group_dn);
+
+ accountmap[3].rid = 515;
+ accountmap[3].cn = talloc_strdup(mem_ctx, "Domain Computers");
+ NT_STATUS_HAVE_NO_MEMORY(accountmap[3].cn);
+
+ groupmap[4].rid = 544;
+ groupmap[4].gidNumber = 544;
+ groupmap[4].sambaSID = talloc_asprintf(mem_ctx, "%s-544", builtin_sid);
+ groupmap[4].group_dn = talloc_asprintf(mem_ctx,
+ "cn=Administrators,ou=%s,%s", group_attr, suffix);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap[4].sambaSID);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap[4].group_dn);
+
+ accountmap[4].rid = 515;
+ accountmap[4].cn = talloc_strdup(mem_ctx, "Administrators");
+ NT_STATUS_HAVE_NO_MEMORY(accountmap[4].cn);
+
+ groupmap[5].rid = 550;
+ groupmap[5].gidNumber = 550;
+ groupmap[5].sambaSID = talloc_asprintf(mem_ctx, "%s-550", builtin_sid);
+ groupmap[5].group_dn = talloc_asprintf(mem_ctx,
+ "cn=Print Operators,ou=%s,%s", group_attr, suffix);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap[5].sambaSID);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap[5].group_dn);
+
+ accountmap[5].rid = 550;
+ accountmap[5].cn = talloc_strdup(mem_ctx, "Print Operators");
+ NT_STATUS_HAVE_NO_MEMORY(accountmap[5].cn);
+
+ groupmap[6].rid = 551;
+ groupmap[6].gidNumber = 551;
+ groupmap[6].sambaSID = talloc_asprintf(mem_ctx, "%s-551", builtin_sid);
+ groupmap[6].group_dn = talloc_asprintf(mem_ctx,
+ "cn=Backup Operators,ou=%s,%s", group_attr, suffix);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap[6].sambaSID);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap[6].group_dn);
+
+ accountmap[6].rid = 551;
+ accountmap[6].cn = talloc_strdup(mem_ctx, "Backup Operators");
+ NT_STATUS_HAVE_NO_MEMORY(accountmap[6].cn);
+
+ groupmap[7].rid = 552;
+ groupmap[7].gidNumber = 552;
+ groupmap[7].sambaSID = talloc_asprintf(mem_ctx, "%s-552", builtin_sid);
+ groupmap[7].group_dn = talloc_asprintf(mem_ctx,
+ "cn=Replicators,ou=%s,%s", group_attr, suffix);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap[7].sambaSID);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap[7].group_dn);
+
+ accountmap[7].rid = 551;
+ accountmap[7].cn = talloc_strdup(mem_ctx, "Replicators");
+ NT_STATUS_HAVE_NO_MEMORY(accountmap[7].cn);
+
+ SAFE_FREE(group_attr);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * This is a crap routine, but I think it's the quickest way to solve the
+ * UTF8->base64 problem.
+ */
+
+static int fprintf_attr(FILE *add_fd, const char *attr_name,
+ const char *fmt, ...)
+{
+ va_list ap;
+ char *value, *p, *base64;
+ DATA_BLOB base64_blob;
+ bool do_base64 = false;
+ int res;
+
+ va_start(ap, fmt);
+ value = talloc_vasprintf(NULL, fmt, ap);
+ va_end(ap);
+
+ SMB_ASSERT(value != NULL);
+
+ for (p=value; *p; p++) {
+ if (*p & 0x80) {
+ do_base64 = true;
+ break;
+ }
+ }
+
+ if (!do_base64) {
+ bool only_whitespace = true;
+ for (p=value; *p; p++) {
+ /*
+ * I know that this not multibyte safe, but we break
+ * on the first non-whitespace character anyway.
+ */
+ if (!isspace(*p)) {
+ only_whitespace = false;
+ break;
+ }
+ }
+ if (only_whitespace) {
+ do_base64 = true;
+ }
+ }
+
+ if (!do_base64) {
+ res = fprintf(add_fd, "%s: %s\n", attr_name, value);
+ TALLOC_FREE(value);
+ return res;
+ }
+
+ base64_blob.data = (unsigned char *)value;
+ base64_blob.length = strlen(value);
+
+ base64 = base64_encode_data_blob(value, base64_blob);
+ SMB_ASSERT(base64 != NULL);
+
+ res = fprintf(add_fd, "%s:: %s\n", attr_name, base64);
+ TALLOC_FREE(value);
+ return res;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS fetch_group_info_to_ldif(TALLOC_CTX *mem_ctx,
+ struct netr_DELTA_GROUP *r,
+ GROUPMAP *groupmap,
+ FILE *add_fd,
+ const char *sid,
+ const char *suffix)
+{
+ const char *groupname = r->group_name.string;
+ uint32 grouptype = 0, g_rid = 0;
+ char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
+
+ /* Set up the group type (always 2 for group info) */
+ grouptype = 2;
+
+ /* These groups are entered by populate_ldap_for_ldif */
+ if (strcmp(groupname, "Domain Admins") == 0 ||
+ strcmp(groupname, "Domain Users") == 0 ||
+ strcmp(groupname, "Domain Guests") == 0 ||
+ strcmp(groupname, "Domain Computers") == 0 ||
+ strcmp(groupname, "Administrators") == 0 ||
+ strcmp(groupname, "Print Operators") == 0 ||
+ strcmp(groupname, "Backup Operators") == 0 ||
+ strcmp(groupname, "Replicators") == 0) {
+ SAFE_FREE(group_attr);
+ return NT_STATUS_OK;
+ } else {
+ /* Increment the gid for the new group */
+ ldif_gid++;
+ }
+
+ /* Map the group rid, gid, and dn */
+ g_rid = r->rid;
+ groupmap->rid = g_rid;
+ groupmap->gidNumber = ldif_gid;
+ groupmap->sambaSID = talloc_asprintf(mem_ctx, "%s-%d", sid, g_rid);
+ groupmap->group_dn = talloc_asprintf(mem_ctx,
+ "cn=%s,ou=%s,%s", groupname, group_attr, suffix);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap->sambaSID);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap->group_dn);
+
+ /* Write the data to the temporary add ldif file */
+ fprintf(add_fd, "# %s, %s, %s\n", groupname, group_attr,
+ suffix);
+ fprintf_attr(add_fd, "dn", "cn=%s,ou=%s,%s", groupname, group_attr,
+ suffix);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
+ fprintf_attr(add_fd, "cn", "%s", groupname);
+ fprintf(add_fd, "gidNumber: %d\n", ldif_gid);
+ fprintf(add_fd, "sambaSID: %s\n", groupmap->sambaSID);
+ fprintf(add_fd, "sambaGroupType: %d\n", grouptype);
+ fprintf_attr(add_fd, "displayName", "%s", groupname);
+ fprintf(add_fd, "\n");
+ fflush(add_fd);
+
+ SAFE_FREE(group_attr);
+ /* Return */
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS fetch_account_info_to_ldif(TALLOC_CTX *mem_ctx,
+ struct netr_DELTA_USER *r,
+ GROUPMAP *groupmap,
+ ACCOUNTMAP *accountmap,
+ FILE *add_fd,
+ const char *sid,
+ const char *suffix,
+ int alloced)
+{
+ fstring username, logonscript, homedrive, homepath = "", homedir = "";
+ fstring hex_nt_passwd, hex_lm_passwd;
+ fstring description, profilepath, fullname, sambaSID;
+ uchar lm_passwd[16], nt_passwd[16];
+ char *flags, *user_rdn;
+ const char *ou;
+ const char* nopasswd = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
+ static uchar zero_buf[16];
+ uint32 rid = 0, group_rid = 0, gidNumber = 0;
+ time_t unix_time;
+ int i;
+
+ /* Get the username */
+ fstrcpy(username, r->account_name.string);
+
+ /* Get the rid */
+ rid = r->rid;
+
+ /* Map the rid and username for group member info later */
+ accountmap->rid = rid;
+ accountmap->cn = talloc_strdup(mem_ctx, username);
+ NT_STATUS_HAVE_NO_MEMORY(accountmap->cn);
+
+ /* Get the home directory */
+ if (r->acct_flags & ACB_NORMAL) {
+ fstrcpy(homedir, r->home_directory.string);
+ if (!*homedir) {
+ snprintf(homedir, sizeof(homedir), "/home/%s", username);
+ } else {
+ snprintf(homedir, sizeof(homedir), "/nobodyshomedir");
+ }
+ ou = lp_ldap_user_suffix();
+ } else {
+ ou = lp_ldap_machine_suffix();
+ snprintf(homedir, sizeof(homedir), "/machinehomedir");
+ }
+
+ /* Get the logon script */
+ fstrcpy(logonscript, r->logon_script.string);
+
+ /* Get the home drive */
+ fstrcpy(homedrive, r->home_drive.string);
+
+ /* Get the home path */
+ fstrcpy(homepath, r->home_directory.string);
+
+ /* Get the description */
+ fstrcpy(description, r->description.string);
+
+ /* Get the display name */
+ fstrcpy(fullname, r->full_name.string);
+
+ /* Get the profile path */
+ fstrcpy(profilepath, r->profile_path.string);
+
+ /* Get lm and nt password data */
+ if (memcmp(r->lmpassword.hash, zero_buf, 16) != 0) {
+ sam_pwd_hash(r->rid, r->lmpassword.hash, lm_passwd, 0);
+ pdb_sethexpwd(hex_lm_passwd, lm_passwd, r->acct_flags);
+ } else {
+ pdb_sethexpwd(hex_lm_passwd, NULL, 0);
+ }
+ if (memcmp(r->ntpassword.hash, zero_buf, 16) != 0) {
+ sam_pwd_hash(r->rid, r->ntpassword.hash, nt_passwd, 0);
+ pdb_sethexpwd(hex_nt_passwd, nt_passwd, r->acct_flags);
+ } else {
+ pdb_sethexpwd(hex_nt_passwd, NULL, 0);
+ }
+ unix_time = nt_time_to_unix(r->last_password_change);
+
+ /* Increment the uid for the new user */
+ ldif_uid++;
+
+ /* Set up group id and sambaSID for the user */
+ group_rid = r->primary_gid;
+ for (i=0; i<alloced; i++) {
+ if (groupmap[i].rid == group_rid) break;
+ }
+ if (i == alloced){
+ DEBUG(1, ("Could not find rid %d in groupmap array\n",
+ group_rid));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ gidNumber = groupmap[i].gidNumber;
+ snprintf(sambaSID, sizeof(sambaSID), groupmap[i].sambaSID);
+
+ /* Set up sambaAcctFlags */
+ flags = pdb_encode_acct_ctrl(r->acct_flags,
+ NEW_PW_FORMAT_SPACE_PADDED_LEN);
+
+ /* Add the user to the temporary add ldif file */
+ /* this isn't quite right...we can't assume there's just OU=. jmcd */
+ user_rdn = sstring_sub(ou, '=', ',');
+ fprintf(add_fd, "# %s, %s, %s\n", username, user_rdn, suffix);
+ fprintf_attr(add_fd, "dn", "uid=%s,ou=%s,%s", username, user_rdn,
+ suffix);
+ SAFE_FREE(user_rdn);
+ fprintf(add_fd, "ObjectClass: top\n");
+ fprintf(add_fd, "objectClass: inetOrgPerson\n");
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXACCOUNT);
+ fprintf(add_fd, "objectClass: shadowAccount\n");
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_SAMBASAMACCOUNT);
+ fprintf_attr(add_fd, "cn", "%s", username);
+ fprintf_attr(add_fd, "sn", "%s", username);
+ fprintf_attr(add_fd, "uid", "%s", username);
+ fprintf(add_fd, "uidNumber: %d\n", ldif_uid);
+ fprintf(add_fd, "gidNumber: %d\n", gidNumber);
+ fprintf_attr(add_fd, "homeDirectory", "%s", homedir);
+ if (*homepath)
+ fprintf_attr(add_fd, "sambaHomePath", "%s", homepath);
+ if (*homedrive)
+ fprintf_attr(add_fd, "sambaHomeDrive", "%s", homedrive);
+ if (*logonscript)
+ fprintf_attr(add_fd, "sambaLogonScript", "%s", logonscript);
+ fprintf(add_fd, "loginShell: %s\n",
+ ((r->acct_flags & ACB_NORMAL) ?
+ "/bin/bash" : "/bin/false"));
+ fprintf(add_fd, "gecos: System User\n");
+ if (*description)
+ fprintf_attr(add_fd, "description", "%s", description);
+ fprintf(add_fd, "sambaSID: %s-%d\n", sid, rid);
+ fprintf(add_fd, "sambaPrimaryGroupSID: %s\n", sambaSID);
+ if(*fullname)
+ fprintf_attr(add_fd, "displayName", "%s", fullname);
+ if(*profilepath)
+ fprintf_attr(add_fd, "sambaProfilePath", "%s", profilepath);
+ if (strcmp(nopasswd, hex_lm_passwd) != 0)
+ fprintf(add_fd, "sambaLMPassword: %s\n", hex_lm_passwd);
+ if (strcmp(nopasswd, hex_nt_passwd) != 0)
+ fprintf(add_fd, "sambaNTPassword: %s\n", hex_nt_passwd);
+ fprintf(add_fd, "sambaPwdLastSet: %d\n", (int)unix_time);
+ fprintf(add_fd, "sambaAcctFlags: %s\n", flags);
+ fprintf(add_fd, "\n");
+ fflush(add_fd);
+
+ /* Return */
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS fetch_alias_info_to_ldif(TALLOC_CTX *mem_ctx,
+ struct netr_DELTA_ALIAS *r,
+ GROUPMAP *groupmap,
+ FILE *add_fd,
+ const char *sid,
+ const char *suffix,
+ enum netr_SamDatabaseID database_id)
+{
+ fstring aliasname, description;
+ uint32 grouptype = 0, g_rid = 0;
+ char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
+
+ /* Get the alias name */
+ fstrcpy(aliasname, r->alias_name.string);
+
+ /* Get the alias description */
+ fstrcpy(description, r->description.string);
+
+ /* Set up the group type */
+ switch (database_id) {
+ case SAM_DATABASE_DOMAIN:
+ grouptype = 4;
+ break;
+ case SAM_DATABASE_BUILTIN:
+ grouptype = 5;
+ break;
+ default:
+ grouptype = 4;
+ break;
+ }
+
+ /*
+ These groups are entered by populate_ldap_for_ldif
+ Note that populate creates a group called Relicators,
+ but NT returns a group called Replicator
+ */
+ if (strcmp(aliasname, "Domain Admins") == 0 ||
+ strcmp(aliasname, "Domain Users") == 0 ||
+ strcmp(aliasname, "Domain Guests") == 0 ||
+ strcmp(aliasname, "Domain Computers") == 0 ||
+ strcmp(aliasname, "Administrators") == 0 ||
+ strcmp(aliasname, "Print Operators") == 0 ||
+ strcmp(aliasname, "Backup Operators") == 0 ||
+ strcmp(aliasname, "Replicator") == 0) {
+ SAFE_FREE(group_attr);
+ return NT_STATUS_OK;
+ } else {
+ /* Increment the gid for the new group */
+ ldif_gid++;
+ }
+
+ /* Map the group rid and gid */
+ g_rid = r->rid;
+ groupmap->gidNumber = ldif_gid;
+ groupmap->sambaSID = talloc_asprintf(mem_ctx, "%s-%d", sid, g_rid);
+ NT_STATUS_HAVE_NO_MEMORY(groupmap->sambaSID);
+
+ /* Write the data to the temporary add ldif file */
+ fprintf(add_fd, "# %s, %s, %s\n", aliasname, group_attr,
+ suffix);
+ fprintf_attr(add_fd, "dn", "cn=%s,ou=%s,%s", aliasname, group_attr,
+ suffix);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
+ fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
+ fprintf(add_fd, "cn: %s\n", aliasname);
+ fprintf(add_fd, "gidNumber: %d\n", ldif_gid);
+ fprintf(add_fd, "sambaSID: %s\n", groupmap->sambaSID);
+ fprintf(add_fd, "sambaGroupType: %d\n", grouptype);
+ fprintf_attr(add_fd, "displayName", "%s", aliasname);
+ if (description[0])
+ fprintf_attr(add_fd, "description", "%s", description);
+ fprintf(add_fd, "\n");
+ fflush(add_fd);
+
+ SAFE_FREE(group_attr);
+ /* Return */
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS fetch_groupmem_info_to_ldif(struct netr_DELTA_GROUP_MEMBER *r,
+ uint32_t id_rid,
+ GROUPMAP *groupmap,
+ ACCOUNTMAP *accountmap,
+ FILE *mod_fd, int alloced)
+{
+ fstring group_dn;
+ uint32 group_rid = 0, rid = 0;
+ int i, j, k;
+
+ /* Get the dn for the group */
+ if (r->num_rids > 0) {
+ group_rid = id_rid;
+ for (j=0; j<alloced; j++) {
+ if (groupmap[j].rid == group_rid) break;
+ }
+ if (j == alloced){
+ DEBUG(1, ("Could not find rid %d in groupmap array\n",
+ group_rid));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ snprintf(group_dn, sizeof(group_dn), "%s", groupmap[j].group_dn);
+ fprintf(mod_fd, "dn: %s\n", group_dn);
+
+ /* Get the cn for each member */
+ for (i=0; i < r->num_rids; i++) {
+ rid = r->rids[i];
+ for (k=0; k<alloced; k++) {
+ if (accountmap[k].rid == rid) break;
+ }
+ if (k == alloced){
+ DEBUG(1, ("Could not find rid %d in "
+ "accountmap array\n", rid));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ fprintf(mod_fd, "memberUid: %s\n", accountmap[k].cn);
+ }
+ fprintf(mod_fd, "\n");
+ }
+ fflush(mod_fd);
+
+ /* Return */
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS ldif_init_context(TALLOC_CTX *mem_ctx,
+ enum netr_SamDatabaseID database_id,
+ const char *ldif_filename,
+ const char *domain_sid_str,
+ struct samsync_ldif_context **ctx)
+{
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ struct samsync_ldif_context *r;
+ const char *add_template = "/tmp/add.ldif.XXXXXX";
+ const char *mod_template = "/tmp/mod.ldif.XXXXXX";
+ const char *builtin_sid = "S-1-5-32";
+
+ /* Get other smb.conf data */
+ if (!(lp_workgroup()) || !*(lp_workgroup())) {
+ DEBUG(0,("workgroup missing from smb.conf--exiting\n"));
+ exit(1);
+ }
+
+ /* Get the ldap suffix */
+ if (!(lp_ldap_suffix()) || !*(lp_ldap_suffix())) {
+ DEBUG(0,("ldap suffix missing from smb.conf--exiting\n"));
+ exit(1);
+ }
+
+ if (*ctx && (*ctx)->initialized) {
+ return NT_STATUS_OK;
+ }
+
+ r = TALLOC_ZERO_P(mem_ctx, struct samsync_ldif_context);
+ NT_STATUS_HAVE_NO_MEMORY(r);
+
+ /* Get the ldap suffix */
+ r->suffix = lp_ldap_suffix();
+
+ /* Ensure we have an output file */
+ if (ldif_filename) {
+ r->ldif_file = fopen(ldif_filename, "a");
+ } else {
+ r->ldif_file = stdout;
+ }
+
+ if (!r->ldif_file) {
+ fprintf(stderr, "Could not open %s\n", ldif_filename);
+ DEBUG(1, ("Could not open %s\n", ldif_filename));
+ status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ r->add_template = talloc_strdup(mem_ctx, add_template);
+ r->mod_template = talloc_strdup(mem_ctx, mod_template);
+ if (!r->add_template || !r->mod_template) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ r->add_name = talloc_strdup(mem_ctx, add_template);
+ r->mod_name = talloc_strdup(mem_ctx, mod_template);
+ if (!r->add_name || !r->mod_name) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ /* Open the add and mod ldif files */
+ if (!(r->add_file = fdopen(smb_mkstemp(r->add_name),"w"))) {
+ DEBUG(1, ("Could not open %s\n", r->add_name));
+ status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ if (!(r->mod_file = fdopen(smb_mkstemp(r->mod_name),"w"))) {
+ DEBUG(1, ("Could not open %s\n", r->mod_name));
+ status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Allocate initial memory for groupmap and accountmap arrays */
+ r->groupmap = TALLOC_ZERO_ARRAY(mem_ctx, GROUPMAP, 8);
+ r->accountmap = TALLOC_ZERO_ARRAY(mem_ctx, ACCOUNTMAP, 8);
+ if (r->groupmap == NULL || r->accountmap == NULL) {
+ DEBUG(1,("GROUPMAP talloc failed\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ /* Remember how many we malloced */
+ r->num_alloced = 8;
+
+ /* Initial database population */
+ if (database_id == SAM_DATABASE_DOMAIN) {
+
+ status = populate_ldap_for_ldif(domain_sid_str,
+ r->suffix,
+ builtin_sid,
+ r->add_file);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = map_populate_groups(mem_ctx,
+ r->groupmap,
+ r->accountmap,
+ domain_sid_str,
+ r->suffix,
+ builtin_sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ }
+
+ r->initialized = true;
+
+ *ctx = r;
+
+ return NT_STATUS_OK;
+ done:
+ TALLOC_FREE(r);
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+static void ldif_free_context(struct samsync_ldif_context *r)
+{
+ if (!r) {
+ return;
+ }
+
+ /* Close and delete the ldif files */
+ if (r->add_file) {
+ fclose(r->add_file);
+ }
+
+ if ((r->add_name != NULL) &&
+ strcmp(r->add_name, r->add_template) && (unlink(r->add_name))) {
+ DEBUG(1,("unlink(%s) failed, error was (%s)\n",
+ r->add_name, strerror(errno)));
+ }
+
+ if (r->mod_file) {
+ fclose(r->mod_file);
+ }
+
+ if ((r->mod_name != NULL) &&
+ strcmp(r->mod_name, r->mod_template) && (unlink(r->mod_name))) {
+ DEBUG(1,("unlink(%s) failed, error was (%s)\n",
+ r->mod_name, strerror(errno)));
+ }
+
+ if (r->ldif_file && (r->ldif_file != stdout)) {
+ fclose(r->ldif_file);
+ }
+
+ TALLOC_FREE(r);
+}
+
+/****************************************************************
+****************************************************************/
+
+static void ldif_write_output(enum netr_SamDatabaseID database_id,
+ struct samsync_ldif_context *l)
+{
+ /* Write ldif data to the user's file */
+ if (database_id == SAM_DATABASE_DOMAIN) {
+ fprintf(l->ldif_file,
+ "# SAM_DATABASE_DOMAIN: ADD ENTITIES\n");
+ fprintf(l->ldif_file,
+ "# =================================\n\n");
+ fflush(l->ldif_file);
+ } else if (database_id == SAM_DATABASE_BUILTIN) {
+ fprintf(l->ldif_file,
+ "# SAM_DATABASE_BUILTIN: ADD ENTITIES\n");
+ fprintf(l->ldif_file,
+ "# ==================================\n\n");
+ fflush(l->ldif_file);
+ }
+ fseek(l->add_file, 0, SEEK_SET);
+ transfer_file(fileno(l->add_file), fileno(l->ldif_file), (size_t) -1);
+
+ if (database_id == SAM_DATABASE_DOMAIN) {
+ fprintf(l->ldif_file,
+ "# SAM_DATABASE_DOMAIN: MODIFY ENTITIES\n");
+ fprintf(l->ldif_file,
+ "# ====================================\n\n");
+ fflush(l->ldif_file);
+ } else if (database_id == SAM_DATABASE_BUILTIN) {
+ fprintf(l->ldif_file,
+ "# SAM_DATABASE_BUILTIN: MODIFY ENTITIES\n");
+ fprintf(l->ldif_file,
+ "# =====================================\n\n");
+ fflush(l->ldif_file);
+ }
+ fseek(l->mod_file, 0, SEEK_SET);
+ transfer_file(fileno(l->mod_file), fileno(l->ldif_file), (size_t) -1);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS fetch_sam_entry_ldif(TALLOC_CTX *mem_ctx,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM *r,
+ struct samsync_context *ctx,
+ uint32_t *a_index,
+ uint32_t *g_index)
+{
+ union netr_DELTA_UNION u = r->delta_union;
+ union netr_DELTA_ID_UNION id = r->delta_id_union;
+ struct samsync_ldif_context *l =
+ talloc_get_type_abort(ctx->private_data, struct samsync_ldif_context);
+
+ switch (r->delta_type) {
+ case NETR_DELTA_DOMAIN:
+ break;
+
+ case NETR_DELTA_GROUP:
+ fetch_group_info_to_ldif(mem_ctx,
+ u.group,
+ &l->groupmap[*g_index],
+ l->add_file,
+ ctx->domain_sid_str,
+ l->suffix);
+ (*g_index)++;
+ break;
+
+ case NETR_DELTA_USER:
+ fetch_account_info_to_ldif(mem_ctx,
+ u.user,
+ l->groupmap,
+ &l->accountmap[*a_index],
+ l->add_file,
+ ctx->domain_sid_str,
+ l->suffix,
+ l->num_alloced);
+ (*a_index)++;
+ break;
+
+ case NETR_DELTA_ALIAS:
+ fetch_alias_info_to_ldif(mem_ctx,
+ u.alias,
+ &l->groupmap[*g_index],
+ l->add_file,
+ ctx->domain_sid_str,
+ l->suffix,
+ database_id);
+ (*g_index)++;
+ break;
+
+ case NETR_DELTA_GROUP_MEMBER:
+ fetch_groupmem_info_to_ldif(u.group_member,
+ id.rid,
+ l->groupmap,
+ l->accountmap,
+ l->mod_file,
+ l->num_alloced);
+ break;
+
+ case NETR_DELTA_ALIAS_MEMBER:
+ case NETR_DELTA_POLICY:
+ case NETR_DELTA_ACCOUNT:
+ case NETR_DELTA_TRUSTED_DOMAIN:
+ case NETR_DELTA_SECRET:
+ case NETR_DELTA_RENAME_GROUP:
+ case NETR_DELTA_RENAME_USER:
+ case NETR_DELTA_RENAME_ALIAS:
+ case NETR_DELTA_DELETE_GROUP:
+ case NETR_DELTA_DELETE_USER:
+ case NETR_DELTA_MODIFY_COUNT:
+ default:
+ break;
+ } /* end of switch */
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS ldif_realloc_maps(TALLOC_CTX *mem_ctx,
+ struct samsync_ldif_context *l,
+ uint32_t num_entries)
+{
+ /* Re-allocate memory for groupmap and accountmap arrays */
+ l->groupmap = TALLOC_REALLOC_ARRAY(mem_ctx,
+ l->groupmap,
+ GROUPMAP,
+ num_entries + l->num_alloced);
+
+ l->accountmap = TALLOC_REALLOC_ARRAY(mem_ctx,
+ l->accountmap,
+ ACCOUNTMAP,
+ num_entries + l->num_alloced);
+
+ if (l->groupmap == NULL || l->accountmap == NULL) {
+ DEBUG(1,("GROUPMAP talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Initialize the new records */
+ memset(&(l->groupmap[l->num_alloced]), 0,
+ sizeof(GROUPMAP) * num_entries);
+ memset(&(l->accountmap[l->num_alloced]), 0,
+ sizeof(ACCOUNTMAP) * num_entries);
+
+ /* Remember how many we alloced this time */
+ l->num_alloced += num_entries;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM_ARRAY *r,
+ bool last_query,
+ struct samsync_context *ctx)
+{
+ NTSTATUS status;
+ int i;
+ uint32_t g_index = 0, a_index = 0;
+ struct samsync_ldif_context *ldif_ctx =
+ (struct samsync_ldif_context *)ctx->private_data;
+
+ status = ldif_init_context(mem_ctx,
+ database_id,
+ ctx->output_filename,
+ ctx->domain_sid_str,
+ &ldif_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ ctx->private_data = ldif_ctx;
+
+ status = ldif_realloc_maps(mem_ctx, ldif_ctx, r->num_deltas);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ for (i = 0; i < r->num_deltas; i++) {
+ status = fetch_sam_entry_ldif(mem_ctx, database_id,
+ &r->delta_enum[i], ctx,
+ &a_index, &g_index);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+ }
+
+ /* This was the last query */
+ if (last_query) {
+ ldif_write_output(database_id, ldif_ctx);
+ if (ldif_ctx->ldif_file != stdout) {
+ ctx->result_message = talloc_asprintf(mem_ctx,
+ "Vampired %d accounts and %d groups to %s",
+ a_index, g_index, ctx->output_filename);
+ }
+ ldif_free_context(ldif_ctx);
+ ctx->private_data = NULL;
+ }
+
+ return NT_STATUS_OK;
+
+ failed:
+ ldif_free_context(ldif_ctx);
+ ctx->private_data = NULL;
+
+ return status;
+}
+
+#else /* HAVE_LDAP */
+
+NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM_ARRAY *r,
+ bool last_query,
+ struct samsync_context *ctx)
+{
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+#endif
diff --git a/source3/libnet/libnet_samsync_passdb.c b/source3/libnet/libnet_samsync_passdb.c
new file mode 100644
index 0000000000..7d07bcb791
--- /dev/null
+++ b/source3/libnet/libnet_samsync_passdb.c
@@ -0,0 +1,789 @@
+/*
+ Unix SMB/CIFS implementation.
+ dump the remote SAM using rpc samsync operations
+
+ Copyright (C) Andrew Tridgell 2002
+ Copyright (C) Tim Potter 2001,2002
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
+ Modified by Volker Lendecke 2002
+ Copyright (C) Jeremy Allison 2005.
+ Copyright (C) Guenther Deschner 2008.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libnet/libnet.h"
+
+/* Convert a struct samu_DELTA to a struct samu. */
+#define STRING_CHANGED (old_string && !new_string) ||\
+ (!old_string && new_string) ||\
+ (old_string && new_string && (strcmp(old_string, new_string) != 0))
+
+#define STRING_CHANGED_NC(s1,s2) ((s1) && !(s2)) ||\
+ (!(s1) && (s2)) ||\
+ ((s1) && (s2) && (strcmp((s1), (s2)) != 0))
+
+static NTSTATUS sam_account_from_delta(struct samu *account,
+ struct netr_DELTA_USER *r)
+{
+ const char *old_string, *new_string;
+ time_t unix_time, stored_time;
+ uchar lm_passwd[16], nt_passwd[16];
+ static uchar zero_buf[16];
+
+ /* Username, fullname, home dir, dir drive, logon script, acct
+ desc, workstations, profile. */
+
+ if (r->account_name.string) {
+ old_string = pdb_get_nt_username(account);
+ new_string = r->account_name.string;
+
+ if (STRING_CHANGED) {
+ pdb_set_nt_username(account, new_string, PDB_CHANGED);
+ }
+
+ /* Unix username is the same - for sanity */
+ old_string = pdb_get_username( account );
+ if (STRING_CHANGED) {
+ pdb_set_username(account, new_string, PDB_CHANGED);
+ }
+ }
+
+ if (r->full_name.string) {
+ old_string = pdb_get_fullname(account);
+ new_string = r->full_name.string;
+
+ if (STRING_CHANGED)
+ pdb_set_fullname(account, new_string, PDB_CHANGED);
+ }
+
+ if (r->home_directory.string) {
+ old_string = pdb_get_homedir(account);
+ new_string = r->home_directory.string;
+
+ if (STRING_CHANGED)
+ pdb_set_homedir(account, new_string, PDB_CHANGED);
+ }
+
+ if (r->home_drive.string) {
+ old_string = pdb_get_dir_drive(account);
+ new_string = r->home_drive.string;
+
+ if (STRING_CHANGED)
+ pdb_set_dir_drive(account, new_string, PDB_CHANGED);
+ }
+
+ if (r->logon_script.string) {
+ old_string = pdb_get_logon_script(account);
+ new_string = r->logon_script.string;
+
+ if (STRING_CHANGED)
+ pdb_set_logon_script(account, new_string, PDB_CHANGED);
+ }
+
+ if (r->description.string) {
+ old_string = pdb_get_acct_desc(account);
+ new_string = r->description.string;
+
+ if (STRING_CHANGED)
+ pdb_set_acct_desc(account, new_string, PDB_CHANGED);
+ }
+
+ if (r->workstations.string) {
+ old_string = pdb_get_workstations(account);
+ new_string = r->workstations.string;
+
+ if (STRING_CHANGED)
+ pdb_set_workstations(account, new_string, PDB_CHANGED);
+ }
+
+ if (r->profile_path.string) {
+ old_string = pdb_get_profile_path(account);
+ new_string = r->profile_path.string;
+
+ if (STRING_CHANGED)
+ pdb_set_profile_path(account, new_string, PDB_CHANGED);
+ }
+
+ if (r->parameters.string) {
+ DATA_BLOB mung;
+ char *newstr;
+ old_string = pdb_get_munged_dial(account);
+ mung.length = r->parameters.length;
+ mung.data = (uint8 *) r->parameters.string;
+ newstr = (mung.length == 0) ? NULL :
+ base64_encode_data_blob(talloc_tos(), mung);
+
+ if (STRING_CHANGED_NC(old_string, newstr))
+ pdb_set_munged_dial(account, newstr, PDB_CHANGED);
+ TALLOC_FREE(newstr);
+ }
+
+ /* User and group sid */
+ if (pdb_get_user_rid(account) != r->rid)
+ pdb_set_user_sid_from_rid(account, r->rid, PDB_CHANGED);
+ if (pdb_get_group_rid(account) != r->primary_gid)
+ pdb_set_group_sid_from_rid(account, r->primary_gid, PDB_CHANGED);
+
+ /* Logon and password information */
+ if (!nt_time_is_zero(&r->last_logon)) {
+ unix_time = nt_time_to_unix(r->last_logon);
+ stored_time = pdb_get_logon_time(account);
+ if (stored_time != unix_time)
+ pdb_set_logon_time(account, unix_time, PDB_CHANGED);
+ }
+
+ if (!nt_time_is_zero(&r->last_logoff)) {
+ unix_time = nt_time_to_unix(r->last_logoff);
+ stored_time = pdb_get_logoff_time(account);
+ if (stored_time != unix_time)
+ pdb_set_logoff_time(account, unix_time,PDB_CHANGED);
+ }
+
+ /* Logon Divs */
+ if (pdb_get_logon_divs(account) != r->logon_hours.units_per_week)
+ pdb_set_logon_divs(account, r->logon_hours.units_per_week, PDB_CHANGED);
+
+#if 0
+ /* no idea what to do with this one - gd */
+ /* Max Logon Hours */
+ if (delta->unknown1 != pdb_get_unknown_6(account)) {
+ pdb_set_unknown_6(account, delta->unknown1, PDB_CHANGED);
+ }
+#endif
+ /* Logon Hours Len */
+ if (r->logon_hours.units_per_week/8 != pdb_get_hours_len(account)) {
+ pdb_set_hours_len(account, r->logon_hours.units_per_week/8, PDB_CHANGED);
+ }
+
+ /* Logon Hours */
+ if (r->logon_hours.bits) {
+ char oldstr[44], newstr[44];
+ pdb_sethexhours(oldstr, pdb_get_hours(account));
+ pdb_sethexhours(newstr, r->logon_hours.bits);
+ if (!strequal(oldstr, newstr))
+ pdb_set_hours(account, r->logon_hours.bits, PDB_CHANGED);
+ }
+
+ if (pdb_get_bad_password_count(account) != r->bad_password_count)
+ pdb_set_bad_password_count(account, r->bad_password_count, PDB_CHANGED);
+
+ if (pdb_get_logon_count(account) != r->logon_count)
+ pdb_set_logon_count(account, r->logon_count, PDB_CHANGED);
+
+ if (!nt_time_is_zero(&r->last_password_change)) {
+ unix_time = nt_time_to_unix(r->last_password_change);
+ stored_time = pdb_get_pass_last_set_time(account);
+ if (stored_time != unix_time)
+ pdb_set_pass_last_set_time(account, unix_time, PDB_CHANGED);
+ } else {
+ /* no last set time, make it now */
+ pdb_set_pass_last_set_time(account, time(NULL), PDB_CHANGED);
+ }
+
+ if (!nt_time_is_zero(&r->acct_expiry)) {
+ unix_time = nt_time_to_unix(r->acct_expiry);
+ stored_time = pdb_get_kickoff_time(account);
+ if (stored_time != unix_time)
+ pdb_set_kickoff_time(account, unix_time, PDB_CHANGED);
+ }
+
+ /* Decode hashes from password hash
+ Note that win2000 may send us all zeros for the hashes if it doesn't
+ think this channel is secure enough - don't set the passwords at all
+ in that case
+ */
+ if (memcmp(r->ntpassword.hash, zero_buf, 16) != 0) {
+ sam_pwd_hash(r->rid, r->ntpassword.hash, lm_passwd, 0);
+ pdb_set_lanman_passwd(account, lm_passwd, PDB_CHANGED);
+ }
+
+ if (memcmp(r->lmpassword.hash, zero_buf, 16) != 0) {
+ sam_pwd_hash(r->rid, r->lmpassword.hash, nt_passwd, 0);
+ pdb_set_nt_passwd(account, nt_passwd, PDB_CHANGED);
+ }
+
+ /* TODO: account expiry time */
+
+ pdb_set_acct_ctrl(account, r->acct_flags, PDB_CHANGED);
+
+ pdb_set_domain(account, lp_workgroup(), PDB_CHANGED);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS fetch_account_info(uint32_t rid,
+ struct netr_DELTA_USER *r)
+{
+
+ NTSTATUS nt_ret = NT_STATUS_UNSUCCESSFUL;
+ fstring account;
+ char *add_script = NULL;
+ struct samu *sam_account=NULL;
+ GROUP_MAP map;
+ struct group *grp;
+ DOM_SID user_sid;
+ DOM_SID group_sid;
+ struct passwd *passwd;
+ fstring sid_string;
+
+ fstrcpy(account, r->account_name.string);
+ d_printf("Creating account: %s\n", account);
+
+ if ( !(sam_account = samu_new( NULL )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!(passwd = Get_Pwnam_alloc(sam_account, account))) {
+ /* Create appropriate user */
+ if (r->acct_flags & ACB_NORMAL) {
+ add_script = talloc_strdup(sam_account,
+ lp_adduser_script());
+ } else if ( (r->acct_flags & ACB_WSTRUST) ||
+ (r->acct_flags & ACB_SVRTRUST) ||
+ (r->acct_flags & ACB_DOMTRUST) ) {
+ add_script = talloc_strdup(sam_account,
+ lp_addmachine_script());
+ } else {
+ DEBUG(1, ("Unknown user type: %s\n",
+ pdb_encode_acct_ctrl(r->acct_flags, NEW_PW_FORMAT_SPACE_PADDED_LEN)));
+ nt_ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ if (!add_script) {
+ nt_ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ if (*add_script) {
+ int add_ret;
+ add_script = talloc_all_string_sub(sam_account,
+ add_script,
+ "%u",
+ account);
+ if (!add_script) {
+ nt_ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ add_ret = smbrun(add_script,NULL);
+ DEBUG(add_ret ? 0 : 1,("fetch_account: Running the command `%s' "
+ "gave %d\n", add_script, add_ret));
+ if (add_ret == 0) {
+ smb_nscd_flush_user_cache();
+ }
+ }
+
+ /* try and find the possible unix account again */
+ if ( !(passwd = Get_Pwnam_alloc(sam_account, account)) ) {
+ d_fprintf(stderr, "Could not create posix account info for '%s'\n", account);
+ nt_ret = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ }
+ }
+
+ sid_copy(&user_sid, get_global_sam_sid());
+ sid_append_rid(&user_sid, r->rid);
+
+ DEBUG(3, ("Attempting to find SID %s for user %s in the passdb\n",
+ sid_to_fstring(sid_string, &user_sid), account));
+ if (!pdb_getsampwsid(sam_account, &user_sid)) {
+ sam_account_from_delta(sam_account, r);
+ DEBUG(3, ("Attempting to add user SID %s for user %s in the passdb\n",
+ sid_to_fstring(sid_string, &user_sid),
+ pdb_get_username(sam_account)));
+ if (!NT_STATUS_IS_OK(pdb_add_sam_account(sam_account))) {
+ DEBUG(1, ("SAM Account for %s failed to be added to the passdb!\n",
+ account));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ } else {
+ sam_account_from_delta(sam_account, r);
+ DEBUG(3, ("Attempting to update user SID %s for user %s in the passdb\n",
+ sid_to_fstring(sid_string, &user_sid),
+ pdb_get_username(sam_account)));
+ if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_account))) {
+ DEBUG(1, ("SAM Account for %s failed to be updated in the passdb!\n",
+ account));
+ TALLOC_FREE(sam_account);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ if (pdb_get_group_sid(sam_account) == NULL) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ group_sid = *pdb_get_group_sid(sam_account);
+
+ if (!pdb_getgrsid(&map, group_sid)) {
+ DEBUG(0, ("Primary group of %s has no mapping!\n",
+ pdb_get_username(sam_account)));
+ } else {
+ if (map.gid != passwd->pw_gid) {
+ if (!(grp = getgrgid(map.gid))) {
+ DEBUG(0, ("Could not find unix group %lu for user %s (group SID=%s)\n",
+ (unsigned long)map.gid, pdb_get_username(sam_account), sid_string_tos(&group_sid)));
+ } else {
+ smb_set_primary_group(grp->gr_name, pdb_get_username(sam_account));
+ }
+ }
+ }
+
+ if ( !passwd ) {
+ DEBUG(1, ("No unix user for this account (%s), cannot adjust mappings\n",
+ pdb_get_username(sam_account)));
+ }
+
+ done:
+ TALLOC_FREE(sam_account);
+ return nt_ret;
+}
+
+static NTSTATUS fetch_group_info(uint32_t rid,
+ struct netr_DELTA_GROUP *r)
+{
+ fstring name;
+ fstring comment;
+ struct group *grp = NULL;
+ DOM_SID group_sid;
+ fstring sid_string;
+ GROUP_MAP map;
+ bool insert = true;
+
+ fstrcpy(name, r->group_name.string);
+ fstrcpy(comment, r->description.string);
+
+ /* add the group to the mapping table */
+ sid_copy(&group_sid, get_global_sam_sid());
+ sid_append_rid(&group_sid, rid);
+ sid_to_fstring(sid_string, &group_sid);
+
+ if (pdb_getgrsid(&map, group_sid)) {
+ if ( map.gid != -1 )
+ grp = getgrgid(map.gid);
+ insert = false;
+ }
+
+ if (grp == NULL) {
+ gid_t gid;
+
+ /* No group found from mapping, find it from its name. */
+ if ((grp = getgrnam(name)) == NULL) {
+
+ /* No appropriate group found, create one */
+
+ d_printf("Creating unix group: '%s'\n", name);
+
+ if (smb_create_group(name, &gid) != 0)
+ return NT_STATUS_ACCESS_DENIED;
+
+ if ((grp = getgrnam(name)) == NULL)
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ map.gid = grp->gr_gid;
+ map.sid = group_sid;
+ map.sid_name_use = SID_NAME_DOM_GRP;
+ fstrcpy(map.nt_name, name);
+ if (r->description.string) {
+ fstrcpy(map.comment, comment);
+ } else {
+ fstrcpy(map.comment, "");
+ }
+
+ if (insert)
+ pdb_add_group_mapping_entry(&map);
+ else
+ pdb_update_group_mapping_entry(&map);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS fetch_group_mem_info(uint32_t rid,
+ struct netr_DELTA_GROUP_MEMBER *r)
+{
+ int i;
+ TALLOC_CTX *t = NULL;
+ char **nt_members = NULL;
+ char **unix_members;
+ DOM_SID group_sid;
+ GROUP_MAP map;
+ struct group *grp;
+
+ if (r->num_rids == 0) {
+ return NT_STATUS_OK;
+ }
+
+ sid_copy(&group_sid, get_global_sam_sid());
+ sid_append_rid(&group_sid, rid);
+
+ if (!get_domain_group_from_sid(group_sid, &map)) {
+ DEBUG(0, ("Could not find global group %d\n", rid));
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ if (!(grp = getgrgid(map.gid))) {
+ DEBUG(0, ("Could not find unix group %lu\n", (unsigned long)map.gid));
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ d_printf("Group members of %s: ", grp->gr_name);
+
+ if (!(t = talloc_init("fetch_group_mem_info"))) {
+ DEBUG(0, ("could not talloc_init\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (r->num_rids) {
+ if ((nt_members = TALLOC_ZERO_ARRAY(t, char *, r->num_rids)) == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ talloc_free(t);
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ nt_members = NULL;
+ }
+
+ for (i=0; i < r->num_rids; i++) {
+ struct samu *member = NULL;
+ DOM_SID member_sid;
+
+ if ( !(member = samu_new(t)) ) {
+ talloc_destroy(t);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ sid_copy(&member_sid, get_global_sam_sid());
+ sid_append_rid(&member_sid, r->rids[i]);
+
+ if (!pdb_getsampwsid(member, &member_sid)) {
+ DEBUG(1, ("Found bogus group member: %d (member_sid=%s group=%s)\n",
+ r->rids[i], sid_string_tos(&member_sid), grp->gr_name));
+ TALLOC_FREE(member);
+ continue;
+ }
+
+ if (pdb_get_group_rid(member) == rid) {
+ d_printf("%s(primary),", pdb_get_username(member));
+ TALLOC_FREE(member);
+ continue;
+ }
+
+ d_printf("%s,", pdb_get_username(member));
+ nt_members[i] = talloc_strdup(t, pdb_get_username(member));
+ TALLOC_FREE(member);
+ }
+
+ d_printf("\n");
+
+ unix_members = grp->gr_mem;
+
+ while (*unix_members) {
+ bool is_nt_member = false;
+ for (i=0; i < r->num_rids; i++) {
+ if (nt_members[i] == NULL) {
+ /* This was a primary group */
+ continue;
+ }
+
+ if (strcmp(*unix_members, nt_members[i]) == 0) {
+ is_nt_member = true;
+ break;
+ }
+ }
+ if (!is_nt_member) {
+ /* We look at a unix group member that is not
+ an nt group member. So, remove it. NT is
+ boss here. */
+ smb_delete_user_group(grp->gr_name, *unix_members);
+ }
+ unix_members += 1;
+ }
+
+ for (i=0; i < r->num_rids; i++) {
+ bool is_unix_member = false;
+
+ if (nt_members[i] == NULL) {
+ /* This was the primary group */
+ continue;
+ }
+
+ unix_members = grp->gr_mem;
+
+ while (*unix_members) {
+ if (strcmp(*unix_members, nt_members[i]) == 0) {
+ is_unix_member = true;
+ break;
+ }
+ unix_members += 1;
+ }
+
+ if (!is_unix_member) {
+ /* We look at a nt group member that is not a
+ unix group member currently. So, add the nt
+ group member. */
+ smb_add_user_group(grp->gr_name, nt_members[i]);
+ }
+ }
+
+ talloc_destroy(t);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS fetch_alias_info(uint32_t rid,
+ struct netr_DELTA_ALIAS *r,
+ const DOM_SID *dom_sid)
+{
+ fstring name;
+ fstring comment;
+ struct group *grp = NULL;
+ DOM_SID alias_sid;
+ fstring sid_string;
+ GROUP_MAP map;
+ bool insert = true;
+
+ fstrcpy(name, r->alias_name.string);
+ fstrcpy(comment, r->description.string);
+
+ /* Find out whether the group is already mapped */
+ sid_copy(&alias_sid, dom_sid);
+ sid_append_rid(&alias_sid, rid);
+ sid_to_fstring(sid_string, &alias_sid);
+
+ if (pdb_getgrsid(&map, alias_sid)) {
+ grp = getgrgid(map.gid);
+ insert = false;
+ }
+
+ if (grp == NULL) {
+ gid_t gid;
+
+ /* No group found from mapping, find it from its name. */
+ if ((grp = getgrnam(name)) == NULL) {
+ /* No appropriate group found, create one */
+ d_printf("Creating unix group: '%s'\n", name);
+ if (smb_create_group(name, &gid) != 0)
+ return NT_STATUS_ACCESS_DENIED;
+ if ((grp = getgrgid(gid)) == NULL)
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ map.gid = grp->gr_gid;
+ map.sid = alias_sid;
+
+ if (sid_equal(dom_sid, &global_sid_Builtin))
+ map.sid_name_use = SID_NAME_WKN_GRP;
+ else
+ map.sid_name_use = SID_NAME_ALIAS;
+
+ fstrcpy(map.nt_name, name);
+ fstrcpy(map.comment, comment);
+
+ if (insert)
+ pdb_add_group_mapping_entry(&map);
+ else
+ pdb_update_group_mapping_entry(&map);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS fetch_alias_mem(uint32_t rid,
+ struct netr_DELTA_ALIAS_MEMBER *r,
+ const DOM_SID *dom_sid)
+{
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS fetch_domain_info(uint32_t rid,
+ struct netr_DELTA_DOMAIN *r)
+{
+ time_t u_max_age, u_min_age, u_logout;
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ const char *domname;
+ struct netr_AcctLockStr *lockstr = NULL;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_tos();
+
+ status = pull_netr_AcctLockStr(mem_ctx, &r->account_lockout,
+ &lockstr);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("failed to pull account lockout string: %s\n",
+ nt_errstr(status));
+ }
+
+ u_max_age = uint64s_nt_time_to_unix_abs((uint64 *)&r->max_password_age);
+ u_min_age = uint64s_nt_time_to_unix_abs((uint64 *)&r->min_password_age);
+ u_logout = uint64s_nt_time_to_unix_abs((uint64 *)&r->force_logoff_time);
+
+ domname = r->domain_name.string;
+ if (!domname) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* we don't handle BUILTIN account policies */
+ if (!strequal(domname, get_global_sam_name())) {
+ printf("skipping SAM_DOMAIN_INFO delta for '%s' (is not my domain)\n", domname);
+ return NT_STATUS_OK;
+ }
+
+
+ if (!pdb_set_account_policy(AP_PASSWORD_HISTORY,
+ r->password_history_length))
+ return nt_status;
+
+ if (!pdb_set_account_policy(AP_MIN_PASSWORD_LEN,
+ r->min_password_length))
+ return nt_status;
+
+ if (!pdb_set_account_policy(AP_MAX_PASSWORD_AGE, (uint32)u_max_age))
+ return nt_status;
+
+ if (!pdb_set_account_policy(AP_MIN_PASSWORD_AGE, (uint32)u_min_age))
+ return nt_status;
+
+ if (!pdb_set_account_policy(AP_TIME_TO_LOGOUT, (uint32)u_logout))
+ return nt_status;
+
+ if (lockstr) {
+ time_t u_lockoutreset, u_lockouttime;
+
+ u_lockoutreset = uint64s_nt_time_to_unix_abs(&lockstr->reset_count);
+ u_lockouttime = uint64s_nt_time_to_unix_abs((uint64_t *)&lockstr->lockout_duration);
+
+ if (!pdb_set_account_policy(AP_BAD_ATTEMPT_LOCKOUT,
+ lockstr->bad_attempt_lockout))
+ return nt_status;
+
+ if (!pdb_set_account_policy(AP_RESET_COUNT_TIME, (uint32_t)u_lockoutreset/60))
+ return nt_status;
+
+ if (u_lockouttime != -1)
+ u_lockouttime /= 60;
+
+ if (!pdb_set_account_policy(AP_LOCK_ACCOUNT_DURATION, (uint32_t)u_lockouttime))
+ return nt_status;
+ }
+
+ if (!pdb_set_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS,
+ r->logon_to_chgpass))
+ return nt_status;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS fetch_sam_entry(TALLOC_CTX *mem_ctx,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM *r,
+ struct samsync_context *ctx)
+{
+ switch(r->delta_type) {
+ case NETR_DELTA_USER:
+ fetch_account_info(r->delta_id_union.rid,
+ r->delta_union.user);
+ break;
+ case NETR_DELTA_GROUP:
+ fetch_group_info(r->delta_id_union.rid,
+ r->delta_union.group);
+ break;
+ case NETR_DELTA_GROUP_MEMBER:
+ fetch_group_mem_info(r->delta_id_union.rid,
+ r->delta_union.group_member);
+ break;
+ case NETR_DELTA_ALIAS:
+ fetch_alias_info(r->delta_id_union.rid,
+ r->delta_union.alias,
+ ctx->domain_sid);
+ break;
+ case NETR_DELTA_ALIAS_MEMBER:
+ fetch_alias_mem(r->delta_id_union.rid,
+ r->delta_union.alias_member,
+ ctx->domain_sid);
+ break;
+ case NETR_DELTA_DOMAIN:
+ fetch_domain_info(r->delta_id_union.rid,
+ r->delta_union.domain);
+ break;
+ /* The following types are recognised but not handled */
+ case NETR_DELTA_RENAME_GROUP:
+ d_printf("NETR_DELTA_RENAME_GROUP not handled\n");
+ break;
+ case NETR_DELTA_RENAME_USER:
+ d_printf("NETR_DELTA_RENAME_USER not handled\n");
+ break;
+ case NETR_DELTA_RENAME_ALIAS:
+ d_printf("NETR_DELTA_RENAME_ALIAS not handled\n");
+ break;
+ case NETR_DELTA_POLICY:
+ d_printf("NETR_DELTA_POLICY not handled\n");
+ break;
+ case NETR_DELTA_TRUSTED_DOMAIN:
+ d_printf("NETR_DELTA_TRUSTED_DOMAIN not handled\n");
+ break;
+ case NETR_DELTA_ACCOUNT:
+ d_printf("NETR_DELTA_ACCOUNT not handled\n");
+ break;
+ case NETR_DELTA_SECRET:
+ d_printf("NETR_DELTA_SECRET not handled\n");
+ break;
+ case NETR_DELTA_DELETE_GROUP:
+ d_printf("NETR_DELTA_DELETE_GROUP not handled\n");
+ break;
+ case NETR_DELTA_DELETE_USER:
+ d_printf("NETR_DELTA_DELETE_USER not handled\n");
+ break;
+ case NETR_DELTA_MODIFY_COUNT:
+ d_printf("NETR_DELTA_MODIFY_COUNT not handled\n");
+ break;
+ case NETR_DELTA_DELETE_ALIAS:
+ d_printf("NETR_DELTA_DELETE_ALIAS not handled\n");
+ break;
+ case NETR_DELTA_DELETE_TRUST:
+ d_printf("NETR_DELTA_DELETE_TRUST not handled\n");
+ break;
+ case NETR_DELTA_DELETE_ACCOUNT:
+ d_printf("NETR_DELTA_DELETE_ACCOUNT not handled\n");
+ break;
+ case NETR_DELTA_DELETE_SECRET:
+ d_printf("NETR_DELTA_DELETE_SECRET not handled\n");
+ break;
+ case NETR_DELTA_DELETE_GROUP2:
+ d_printf("NETR_DELTA_DELETE_GROUP2 not handled\n");
+ break;
+ case NETR_DELTA_DELETE_USER2:
+ d_printf("NETR_DELTA_DELETE_USER2 not handled\n");
+ break;
+ default:
+ d_printf("Unknown delta record type %d\n", r->delta_type);
+ break;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS fetch_sam_entries(TALLOC_CTX *mem_ctx,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM_ARRAY *r,
+ bool last_query,
+ struct samsync_context *ctx)
+{
+ int i;
+
+ for (i = 0; i < r->num_deltas; i++) {
+ fetch_sam_entry(mem_ctx, database_id, &r->delta_enum[i], ctx);
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/librpc/gen_ndr/cli_dfs.c b/source3/librpc/gen_ndr/cli_dfs.c
new file mode 100644
index 0000000000..81ec14694a
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_dfs.c
@@ -0,0 +1,1099 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * client auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/cli_dfs.h"
+
+NTSTATUS rpccli_dfs_GetManagerVersion(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ enum dfs_ManagerVersion *version /* [out] [ref] */)
+{
+ struct dfs_GetManagerVersion r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_GetManagerVersion, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_GETMANAGERVERSION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_GetManagerVersion, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *version = *r.out.version;
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_dfs_Add(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *path /* [in] [ref,charset(UTF16)] */,
+ const char *server /* [in] [ref,charset(UTF16)] */,
+ const char *share /* [in] [unique,charset(UTF16)] */,
+ const char *comment /* [in] [unique,charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror)
+{
+ struct dfs_Add r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.path = path;
+ r.in.server = server;
+ r.in.share = share;
+ r.in.comment = comment;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_Add, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_ADD,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_Add, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_Remove(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *dfs_entry_path /* [in] [ref,charset(UTF16)] */,
+ const char *servername /* [in] [unique,charset(UTF16)] */,
+ const char *sharename /* [in] [unique,charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct dfs_Remove r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.dfs_entry_path = dfs_entry_path;
+ r.in.servername = servername;
+ r.in.sharename = sharename;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_Remove, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_REMOVE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_Remove, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_SetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *dfs_entry_path /* [in] [charset(UTF16)] */,
+ const char *servername /* [in] [unique,charset(UTF16)] */,
+ const char *sharename /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union dfs_Info *info /* [in] [ref,switch_is(level)] */,
+ WERROR *werror)
+{
+ struct dfs_SetInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.dfs_entry_path = dfs_entry_path;
+ r.in.servername = servername;
+ r.in.sharename = sharename;
+ r.in.level = level;
+ r.in.info = info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_SetInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_SETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_SetInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_GetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *dfs_entry_path /* [in] [charset(UTF16)] */,
+ const char *servername /* [in] [unique,charset(UTF16)] */,
+ const char *sharename /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union dfs_Info *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror)
+{
+ struct dfs_GetInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.dfs_entry_path = dfs_entry_path;
+ r.in.servername = servername;
+ r.in.sharename = sharename;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_GetInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_GETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_GetInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_Enum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t level /* [in] */,
+ uint32_t bufsize /* [in] */,
+ struct dfs_EnumStruct *info /* [in,out] [unique] */,
+ uint32_t *total /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct dfs_Enum r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.level = level;
+ r.in.bufsize = bufsize;
+ r.in.info = info;
+ r.in.total = total;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_Enum, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_ENUM,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_Enum, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (info && r.out.info) {
+ *info = *r.out.info;
+ }
+ if (total && r.out.total) {
+ *total = *r.out.total;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_Rename(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dfs_Rename r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_Rename, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_RENAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_Rename, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_Move(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dfs_Move r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_Move, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_MOVE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_Move, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_ManagerGetConfigInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dfs_ManagerGetConfigInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_ManagerGetConfigInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_MANAGERGETCONFIGINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_ManagerGetConfigInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_ManagerSendSiteInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dfs_ManagerSendSiteInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_ManagerSendSiteInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_MANAGERSENDSITEINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_ManagerSendSiteInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_AddFtRoot(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [charset(UTF16)] */,
+ const char *dns_servername /* [in] [charset(UTF16)] */,
+ const char *dfsname /* [in] [charset(UTF16)] */,
+ const char *rootshare /* [in] [charset(UTF16)] */,
+ const char *comment /* [in] [charset(UTF16)] */,
+ const char *dfs_config_dn /* [in] [charset(UTF16)] */,
+ uint8_t unknown1 /* [in] */,
+ uint32_t flags /* [in] */,
+ struct dfs_UnknownStruct **unknown2 /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct dfs_AddFtRoot r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.servername = servername;
+ r.in.dns_servername = dns_servername;
+ r.in.dfsname = dfsname;
+ r.in.rootshare = rootshare;
+ r.in.comment = comment;
+ r.in.dfs_config_dn = dfs_config_dn;
+ r.in.unknown1 = unknown1;
+ r.in.flags = flags;
+ r.in.unknown2 = unknown2;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_AddFtRoot, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_ADDFTROOT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_AddFtRoot, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (unknown2 && r.out.unknown2) {
+ *unknown2 = *r.out.unknown2;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_RemoveFtRoot(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [charset(UTF16)] */,
+ const char *dns_servername /* [in] [charset(UTF16)] */,
+ const char *dfsname /* [in] [charset(UTF16)] */,
+ const char *rootshare /* [in] [charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ struct dfs_UnknownStruct **unknown /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct dfs_RemoveFtRoot r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.servername = servername;
+ r.in.dns_servername = dns_servername;
+ r.in.dfsname = dfsname;
+ r.in.rootshare = rootshare;
+ r.in.flags = flags;
+ r.in.unknown = unknown;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_RemoveFtRoot, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_REMOVEFTROOT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_RemoveFtRoot, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (unknown && r.out.unknown) {
+ *unknown = *r.out.unknown;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_AddStdRoot(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [charset(UTF16)] */,
+ const char *rootshare /* [in] [charset(UTF16)] */,
+ const char *comment /* [in] [charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror)
+{
+ struct dfs_AddStdRoot r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.servername = servername;
+ r.in.rootshare = rootshare;
+ r.in.comment = comment;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_AddStdRoot, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_ADDSTDROOT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_AddStdRoot, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_RemoveStdRoot(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [charset(UTF16)] */,
+ const char *rootshare /* [in] [charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror)
+{
+ struct dfs_RemoveStdRoot r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.servername = servername;
+ r.in.rootshare = rootshare;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_RemoveStdRoot, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_REMOVESTDROOT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_RemoveStdRoot, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_ManagerInitialize(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [ref,charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror)
+{
+ struct dfs_ManagerInitialize r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.servername = servername;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_ManagerInitialize, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_MANAGERINITIALIZE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_ManagerInitialize, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_AddStdRootForced(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [charset(UTF16)] */,
+ const char *rootshare /* [in] [charset(UTF16)] */,
+ const char *comment /* [in] [charset(UTF16)] */,
+ const char *store /* [in] [charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct dfs_AddStdRootForced r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.servername = servername;
+ r.in.rootshare = rootshare;
+ r.in.comment = comment;
+ r.in.store = store;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_AddStdRootForced, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_ADDSTDROOTFORCED,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_AddStdRootForced, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_GetDcAddress(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [charset(UTF16)] */,
+ const char **server_fullname /* [in,out] [ref,charset(UTF16)] */,
+ uint8_t *is_root /* [in,out] [ref] */,
+ uint32_t *ttl /* [in,out] [ref] */,
+ WERROR *werror)
+{
+ struct dfs_GetDcAddress r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.servername = servername;
+ r.in.server_fullname = server_fullname;
+ r.in.is_root = is_root;
+ r.in.ttl = ttl;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_GetDcAddress, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_GETDCADDRESS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_GetDcAddress, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *server_fullname = *r.out.server_fullname;
+ *is_root = *r.out.is_root;
+ *ttl = *r.out.ttl;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_SetDcAddress(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [charset(UTF16)] */,
+ const char *server_fullname /* [in] [charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ uint32_t ttl /* [in] */,
+ WERROR *werror)
+{
+ struct dfs_SetDcAddress r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.servername = servername;
+ r.in.server_fullname = server_fullname;
+ r.in.flags = flags;
+ r.in.ttl = ttl;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_SetDcAddress, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_SETDCADDRESS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_SetDcAddress, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_FlushFtTable(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [charset(UTF16)] */,
+ const char *rootshare /* [in] [charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct dfs_FlushFtTable r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.servername = servername;
+ r.in.rootshare = rootshare;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_FlushFtTable, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_FLUSHFTTABLE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_FlushFtTable, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_Add2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dfs_Add2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_Add2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_ADD2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_Add2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_Remove2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dfs_Remove2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_Remove2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_REMOVE2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_Remove2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_EnumEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *dfs_name /* [in] [charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ uint32_t bufsize /* [in] */,
+ struct dfs_EnumStruct *info /* [in,out] [unique] */,
+ uint32_t *total /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct dfs_EnumEx r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.dfs_name = dfs_name;
+ r.in.level = level;
+ r.in.bufsize = bufsize;
+ r.in.info = info;
+ r.in.total = total;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_EnumEx, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_ENUMEX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_EnumEx, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (info && r.out.info) {
+ *info = *r.out.info;
+ }
+ if (total && r.out.total) {
+ *total = *r.out.total;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dfs_SetInfo2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dfs_SetInfo2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_SetInfo2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netdfs,
+ NDR_DFS_SETINFO2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_SetInfo2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
diff --git a/source3/librpc/gen_ndr/cli_dfs.h b/source3/librpc/gen_ndr/cli_dfs.h
new file mode 100644
index 0000000000..0c862099bf
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_dfs.h
@@ -0,0 +1,138 @@
+#include "librpc/gen_ndr/ndr_dfs.h"
+#ifndef __CLI_NETDFS__
+#define __CLI_NETDFS__
+NTSTATUS rpccli_dfs_GetManagerVersion(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ enum dfs_ManagerVersion *version /* [out] [ref] */);
+NTSTATUS rpccli_dfs_Add(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *path /* [in] [ref,charset(UTF16)] */,
+ const char *server /* [in] [ref,charset(UTF16)] */,
+ const char *share /* [in] [unique,charset(UTF16)] */,
+ const char *comment /* [in] [unique,charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_Remove(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *dfs_entry_path /* [in] [ref,charset(UTF16)] */,
+ const char *servername /* [in] [unique,charset(UTF16)] */,
+ const char *sharename /* [in] [unique,charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_SetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *dfs_entry_path /* [in] [charset(UTF16)] */,
+ const char *servername /* [in] [unique,charset(UTF16)] */,
+ const char *sharename /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union dfs_Info *info /* [in] [ref,switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_GetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *dfs_entry_path /* [in] [charset(UTF16)] */,
+ const char *servername /* [in] [unique,charset(UTF16)] */,
+ const char *sharename /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union dfs_Info *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_Enum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t level /* [in] */,
+ uint32_t bufsize /* [in] */,
+ struct dfs_EnumStruct *info /* [in,out] [unique] */,
+ uint32_t *total /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_Rename(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_Move(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_ManagerGetConfigInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_ManagerSendSiteInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_AddFtRoot(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [charset(UTF16)] */,
+ const char *dns_servername /* [in] [charset(UTF16)] */,
+ const char *dfsname /* [in] [charset(UTF16)] */,
+ const char *rootshare /* [in] [charset(UTF16)] */,
+ const char *comment /* [in] [charset(UTF16)] */,
+ const char *dfs_config_dn /* [in] [charset(UTF16)] */,
+ uint8_t unknown1 /* [in] */,
+ uint32_t flags /* [in] */,
+ struct dfs_UnknownStruct **unknown2 /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_RemoveFtRoot(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [charset(UTF16)] */,
+ const char *dns_servername /* [in] [charset(UTF16)] */,
+ const char *dfsname /* [in] [charset(UTF16)] */,
+ const char *rootshare /* [in] [charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ struct dfs_UnknownStruct **unknown /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_AddStdRoot(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [charset(UTF16)] */,
+ const char *rootshare /* [in] [charset(UTF16)] */,
+ const char *comment /* [in] [charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_RemoveStdRoot(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [charset(UTF16)] */,
+ const char *rootshare /* [in] [charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_ManagerInitialize(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [ref,charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_AddStdRootForced(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [charset(UTF16)] */,
+ const char *rootshare /* [in] [charset(UTF16)] */,
+ const char *comment /* [in] [charset(UTF16)] */,
+ const char *store /* [in] [charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_GetDcAddress(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [charset(UTF16)] */,
+ const char **server_fullname /* [in,out] [ref,charset(UTF16)] */,
+ uint8_t *is_root /* [in,out] [ref] */,
+ uint32_t *ttl /* [in,out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_SetDcAddress(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [charset(UTF16)] */,
+ const char *server_fullname /* [in] [charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ uint32_t ttl /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_FlushFtTable(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *servername /* [in] [charset(UTF16)] */,
+ const char *rootshare /* [in] [charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_Add2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_Remove2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_EnumEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *dfs_name /* [in] [charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ uint32_t bufsize /* [in] */,
+ struct dfs_EnumStruct *info /* [in,out] [unique] */,
+ uint32_t *total /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_dfs_SetInfo2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+#endif /* __CLI_NETDFS__ */
diff --git a/source3/librpc/gen_ndr/cli_drsuapi.c b/source3/librpc/gen_ndr/cli_drsuapi.c
new file mode 100644
index 0000000000..57d7a25d9c
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_drsuapi.c
@@ -0,0 +1,1167 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * client auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/cli_drsuapi.h"
+
+NTSTATUS rpccli_drsuapi_DsBind(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct GUID *bind_guid /* [in] [unique] */,
+ struct drsuapi_DsBindInfoCtr *bind_info /* [in,out] [unique] */,
+ struct policy_handle *bind_handle /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct drsuapi_DsBind r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.bind_guid = bind_guid;
+ r.in.bind_info = bind_info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(drsuapi_DsBind, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_DSBIND,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(drsuapi_DsBind, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (bind_info && r.out.bind_info) {
+ *bind_info = *r.out.bind_info;
+ }
+ *bind_handle = *r.out.bind_handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_drsuapi_DsUnbind(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in,out] [ref] */,
+ WERROR *werror)
+{
+ struct drsuapi_DsUnbind r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.bind_handle = bind_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(drsuapi_DsUnbind, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_DSUNBIND,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(drsuapi_DsUnbind, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *bind_handle = *r.out.bind_handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_drsuapi_DsReplicaSync(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsReplicaSyncRequest req /* [in] [switch_is(level)] */,
+ WERROR *werror)
+{
+ struct drsuapi_DsReplicaSync r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.bind_handle = bind_handle;
+ r.in.level = level;
+ r.in.req = req;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(drsuapi_DsReplicaSync, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_DSREPLICASYNC,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaSync, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_drsuapi_DsGetNCChanges(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsGetNCChangesRequest *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsGetNCChangesCtr *ctr /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror)
+{
+ struct drsuapi_DsGetNCChanges r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.bind_handle = bind_handle;
+ r.in.level = level;
+ r.in.req = req;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_DSGETNCCHANGES,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *level_out = *r.out.level_out;
+ *ctr = *r.out.ctr;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_drsuapi_DsReplicaUpdateRefs(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsReplicaUpdateRefsRequest req /* [in] [switch_is(level)] */,
+ WERROR *werror)
+{
+ struct drsuapi_DsReplicaUpdateRefs r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.bind_handle = bind_handle;
+ r.in.level = level;
+ r.in.req = req;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(drsuapi_DsReplicaUpdateRefs, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_DSREPLICAUPDATEREFS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaUpdateRefs, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_DRSUAPI_REPLICA_ADD(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct DRSUAPI_REPLICA_ADD r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(DRSUAPI_REPLICA_ADD, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_REPLICA_ADD,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(DRSUAPI_REPLICA_ADD, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_DRSUAPI_REPLICA_DEL(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct DRSUAPI_REPLICA_DEL r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(DRSUAPI_REPLICA_DEL, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_REPLICA_DEL,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(DRSUAPI_REPLICA_DEL, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_DRSUAPI_REPLICA_MODIFY(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct DRSUAPI_REPLICA_MODIFY r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(DRSUAPI_REPLICA_MODIFY, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_REPLICA_MODIFY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(DRSUAPI_REPLICA_MODIFY, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_DRSUAPI_VERIFY_NAMES(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct DRSUAPI_VERIFY_NAMES r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(DRSUAPI_VERIFY_NAMES, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_VERIFY_NAMES,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(DRSUAPI_VERIFY_NAMES, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_drsuapi_DsGetMemberships(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsGetMembershipsRequest *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsGetMembershipsCtr *ctr /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror)
+{
+ struct drsuapi_DsGetMemberships r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.bind_handle = bind_handle;
+ r.in.level = level;
+ r.in.req = req;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(drsuapi_DsGetMemberships, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_DSGETMEMBERSHIPS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(drsuapi_DsGetMemberships, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *level_out = *r.out.level_out;
+ *ctr = *r.out.ctr;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_DRSUAPI_INTER_DOMAIN_MOVE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct DRSUAPI_INTER_DOMAIN_MOVE r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(DRSUAPI_INTER_DOMAIN_MOVE, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_INTER_DOMAIN_MOVE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(DRSUAPI_INTER_DOMAIN_MOVE, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_drsuapi_DsGetNT4ChangeLog(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ uint32_t level /* [in] */,
+ union drsuapi_DsGetNT4ChangeLogRequest *req /* [in] [ref,switch_is(level)] */,
+ uint32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsGetNT4ChangeLogInfo *info /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror)
+{
+ struct drsuapi_DsGetNT4ChangeLog r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.bind_handle = bind_handle;
+ r.in.level = level;
+ r.in.req = req;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(drsuapi_DsGetNT4ChangeLog, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_DSGETNT4CHANGELOG,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNT4ChangeLog, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *level_out = *r.out.level_out;
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_drsuapi_DsCrackNames(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsNameRequest *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsNameCtr *ctr /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror)
+{
+ struct drsuapi_DsCrackNames r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.bind_handle = bind_handle;
+ r.in.level = level;
+ r.in.req = req;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(drsuapi_DsCrackNames, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_DSCRACKNAMES,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(drsuapi_DsCrackNames, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *level_out = *r.out.level_out;
+ *ctr = *r.out.ctr;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_drsuapi_DsWriteAccountSpn(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsWriteAccountSpnRequest *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsWriteAccountSpnResult *res /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror)
+{
+ struct drsuapi_DsWriteAccountSpn r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.bind_handle = bind_handle;
+ r.in.level = level;
+ r.in.req = req;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(drsuapi_DsWriteAccountSpn, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_DSWRITEACCOUNTSPN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(drsuapi_DsWriteAccountSpn, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *level_out = *r.out.level_out;
+ *res = *r.out.res;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_drsuapi_DsRemoveDSServer(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsRemoveDSServerRequest *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsRemoveDSServerResult *res /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror)
+{
+ struct drsuapi_DsRemoveDSServer r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.bind_handle = bind_handle;
+ r.in.level = level;
+ r.in.req = req;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(drsuapi_DsRemoveDSServer, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_DSREMOVEDSSERVER,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(drsuapi_DsRemoveDSServer, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *level_out = *r.out.level_out;
+ *res = *r.out.res;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_DRSUAPI_REMOVE_DS_DOMAIN(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct DRSUAPI_REMOVE_DS_DOMAIN r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(DRSUAPI_REMOVE_DS_DOMAIN, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_REMOVE_DS_DOMAIN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(DRSUAPI_REMOVE_DS_DOMAIN, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_drsuapi_DsGetDomainControllerInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsGetDCInfoRequest *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsGetDCInfoCtr *ctr /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror)
+{
+ struct drsuapi_DsGetDomainControllerInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.bind_handle = bind_handle;
+ r.in.level = level;
+ r.in.req = req;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(drsuapi_DsGetDomainControllerInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_DSGETDOMAINCONTROLLERINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(drsuapi_DsGetDomainControllerInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *level_out = *r.out.level_out;
+ *ctr = *r.out.ctr;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_drsuapi_DsAddEntry(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsAddEntryRequest *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsAddEntryCtr *ctr /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror)
+{
+ struct drsuapi_DsAddEntry r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.bind_handle = bind_handle;
+ r.in.level = level;
+ r.in.req = req;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(drsuapi_DsAddEntry, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_DSADDENTRY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(drsuapi_DsAddEntry, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *level_out = *r.out.level_out;
+ *ctr = *r.out.ctr;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_DRSUAPI_EXECUTE_KCC(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct DRSUAPI_EXECUTE_KCC r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(DRSUAPI_EXECUTE_KCC, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_EXECUTE_KCC,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(DRSUAPI_EXECUTE_KCC, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_drsuapi_DsReplicaGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ enum drsuapi_DsReplicaGetInfoLevel level /* [in] */,
+ union drsuapi_DsReplicaGetInfoRequest *req /* [in] [ref,switch_is(level)] */,
+ enum drsuapi_DsReplicaInfoType *info_type /* [out] [ref] */,
+ union drsuapi_DsReplicaInfo *info /* [out] [ref,switch_is(*info_type)] */,
+ WERROR *werror)
+{
+ struct drsuapi_DsReplicaGetInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.bind_handle = bind_handle;
+ r.in.level = level;
+ r.in.req = req;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(drsuapi_DsReplicaGetInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_DSREPLICAGETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaGetInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info_type = *r.out.info_type;
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_DRSUAPI_ADD_SID_HISTORY(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct DRSUAPI_ADD_SID_HISTORY r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(DRSUAPI_ADD_SID_HISTORY, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_ADD_SID_HISTORY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(DRSUAPI_ADD_SID_HISTORY, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_drsuapi_DsGetMemberships2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsGetMemberships2Request *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsGetMemberships2Ctr *ctr /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror)
+{
+ struct drsuapi_DsGetMemberships2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.bind_handle = bind_handle;
+ r.in.level = level;
+ r.in.req = req;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(drsuapi_DsGetMemberships2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_DSGETMEMBERSHIPS2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(drsuapi_DsGetMemberships2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *level_out = *r.out.level_out;
+ *ctr = *r.out.ctr;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_DRSUAPI_REPLICA_VERIFY_OBJECTS(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct DRSUAPI_REPLICA_VERIFY_OBJECTS r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(DRSUAPI_REPLICA_VERIFY_OBJECTS, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_REPLICA_VERIFY_OBJECTS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(DRSUAPI_REPLICA_VERIFY_OBJECTS, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_DRSUAPI_GET_OBJECT_EXISTENCE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct DRSUAPI_GET_OBJECT_EXISTENCE r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(DRSUAPI_GET_OBJECT_EXISTENCE, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_GET_OBJECT_EXISTENCE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(DRSUAPI_GET_OBJECT_EXISTENCE, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_drsuapi_QuerySitesByCost(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_QuerySitesByCostRequest *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_QuerySitesByCostCtr *ctr /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror)
+{
+ struct drsuapi_QuerySitesByCost r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.bind_handle = bind_handle;
+ r.in.level = level;
+ r.in.req = req;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(drsuapi_QuerySitesByCost, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_drsuapi,
+ NDR_DRSUAPI_QUERYSITESBYCOST,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(drsuapi_QuerySitesByCost, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *level_out = *r.out.level_out;
+ *ctr = *r.out.ctr;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
diff --git a/source3/librpc/gen_ndr/cli_drsuapi.h b/source3/librpc/gen_ndr/cli_drsuapi.h
new file mode 100644
index 0000000000..ab7375f4ca
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_drsuapi.h
@@ -0,0 +1,144 @@
+#include "librpc/gen_ndr/ndr_drsuapi.h"
+#ifndef __CLI_DRSUAPI__
+#define __CLI_DRSUAPI__
+NTSTATUS rpccli_drsuapi_DsBind(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct GUID *bind_guid /* [in] [unique] */,
+ struct drsuapi_DsBindInfoCtr *bind_info /* [in,out] [unique] */,
+ struct policy_handle *bind_handle /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_drsuapi_DsUnbind(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in,out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_drsuapi_DsReplicaSync(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsReplicaSyncRequest req /* [in] [switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_drsuapi_DsGetNCChanges(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsGetNCChangesRequest *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsGetNCChangesCtr *ctr /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror);
+NTSTATUS rpccli_drsuapi_DsReplicaUpdateRefs(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsReplicaUpdateRefsRequest req /* [in] [switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_DRSUAPI_REPLICA_ADD(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_DRSUAPI_REPLICA_DEL(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_DRSUAPI_REPLICA_MODIFY(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_DRSUAPI_VERIFY_NAMES(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_drsuapi_DsGetMemberships(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsGetMembershipsRequest *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsGetMembershipsCtr *ctr /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror);
+NTSTATUS rpccli_DRSUAPI_INTER_DOMAIN_MOVE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_drsuapi_DsGetNT4ChangeLog(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ uint32_t level /* [in] */,
+ union drsuapi_DsGetNT4ChangeLogRequest *req /* [in] [ref,switch_is(level)] */,
+ uint32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsGetNT4ChangeLogInfo *info /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror);
+NTSTATUS rpccli_drsuapi_DsCrackNames(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsNameRequest *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsNameCtr *ctr /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror);
+NTSTATUS rpccli_drsuapi_DsWriteAccountSpn(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsWriteAccountSpnRequest *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsWriteAccountSpnResult *res /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror);
+NTSTATUS rpccli_drsuapi_DsRemoveDSServer(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsRemoveDSServerRequest *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsRemoveDSServerResult *res /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror);
+NTSTATUS rpccli_DRSUAPI_REMOVE_DS_DOMAIN(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_drsuapi_DsGetDomainControllerInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsGetDCInfoRequest *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsGetDCInfoCtr *ctr /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror);
+NTSTATUS rpccli_drsuapi_DsAddEntry(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsAddEntryRequest *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsAddEntryCtr *ctr /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror);
+NTSTATUS rpccli_DRSUAPI_EXECUTE_KCC(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_drsuapi_DsReplicaGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ enum drsuapi_DsReplicaGetInfoLevel level /* [in] */,
+ union drsuapi_DsReplicaGetInfoRequest *req /* [in] [ref,switch_is(level)] */,
+ enum drsuapi_DsReplicaInfoType *info_type /* [out] [ref] */,
+ union drsuapi_DsReplicaInfo *info /* [out] [ref,switch_is(*info_type)] */,
+ WERROR *werror);
+NTSTATUS rpccli_DRSUAPI_ADD_SID_HISTORY(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_drsuapi_DsGetMemberships2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_DsGetMemberships2Request *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_DsGetMemberships2Ctr *ctr /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror);
+NTSTATUS rpccli_DRSUAPI_REPLICA_VERIFY_OBJECTS(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_DRSUAPI_GET_OBJECT_EXISTENCE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_drsuapi_QuerySitesByCost(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle /* [in] [ref] */,
+ int32_t level /* [in] */,
+ union drsuapi_QuerySitesByCostRequest *req /* [in] [ref,switch_is(level)] */,
+ int32_t *level_out /* [out] [ref] */,
+ union drsuapi_QuerySitesByCostCtr *ctr /* [out] [ref,switch_is(*level_out)] */,
+ WERROR *werror);
+#endif /* __CLI_DRSUAPI__ */
diff --git a/source3/librpc/gen_ndr/cli_dssetup.c b/source3/librpc/gen_ndr/cli_dssetup.c
new file mode 100644
index 0000000000..5526f8d59b
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_dssetup.c
@@ -0,0 +1,465 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * client auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/cli_dssetup.h"
+
+NTSTATUS rpccli_dssetup_DsRoleGetPrimaryDomainInformation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ enum dssetup_DsRoleInfoLevel level /* [in] */,
+ union dssetup_DsRoleInfo *info /* [out] [unique,switch_is(level)] */,
+ WERROR *werror)
+{
+ struct dssetup_DsRoleGetPrimaryDomainInformation r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleGetPrimaryDomainInformation, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_dssetup,
+ NDR_DSSETUP_DSROLEGETPRIMARYDOMAININFORMATION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleGetPrimaryDomainInformation, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (info && r.out.info) {
+ *info = *r.out.info;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dssetup_DsRoleDnsNameToFlatName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dssetup_DsRoleDnsNameToFlatName r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleDnsNameToFlatName, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_dssetup,
+ NDR_DSSETUP_DSROLEDNSNAMETOFLATNAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleDnsNameToFlatName, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dssetup_DsRoleDcAsDc(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dssetup_DsRoleDcAsDc r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleDcAsDc, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_dssetup,
+ NDR_DSSETUP_DSROLEDCASDC,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleDcAsDc, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dssetup_DsRoleDcAsReplica(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dssetup_DsRoleDcAsReplica r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleDcAsReplica, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_dssetup,
+ NDR_DSSETUP_DSROLEDCASREPLICA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleDcAsReplica, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dssetup_DsRoleDemoteDc(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dssetup_DsRoleDemoteDc r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleDemoteDc, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_dssetup,
+ NDR_DSSETUP_DSROLEDEMOTEDC,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleDemoteDc, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dssetup_DsRoleGetDcOperationProgress(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dssetup_DsRoleGetDcOperationProgress r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleGetDcOperationProgress, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_dssetup,
+ NDR_DSSETUP_DSROLEGETDCOPERATIONPROGRESS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleGetDcOperationProgress, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dssetup_DsRoleGetDcOperationResults(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dssetup_DsRoleGetDcOperationResults r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleGetDcOperationResults, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_dssetup,
+ NDR_DSSETUP_DSROLEGETDCOPERATIONRESULTS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleGetDcOperationResults, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dssetup_DsRoleCancel(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dssetup_DsRoleCancel r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleCancel, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_dssetup,
+ NDR_DSSETUP_DSROLECANCEL,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleCancel, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dssetup_DsRoleServerSaveStateForUpgrade(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dssetup_DsRoleServerSaveStateForUpgrade r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleServerSaveStateForUpgrade, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_dssetup,
+ NDR_DSSETUP_DSROLESERVERSAVESTATEFORUPGRADE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleServerSaveStateForUpgrade, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dssetup_DsRoleUpgradeDownlevelServer(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dssetup_DsRoleUpgradeDownlevelServer r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleUpgradeDownlevelServer, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_dssetup,
+ NDR_DSSETUP_DSROLEUPGRADEDOWNLEVELSERVER,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleUpgradeDownlevelServer, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_dssetup_DsRoleAbortDownlevelServerUpgrade(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct dssetup_DsRoleAbortDownlevelServerUpgrade r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleAbortDownlevelServerUpgrade, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_dssetup,
+ NDR_DSSETUP_DSROLEABORTDOWNLEVELSERVERUPGRADE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleAbortDownlevelServerUpgrade, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
diff --git a/source3/librpc/gen_ndr/cli_dssetup.h b/source3/librpc/gen_ndr/cli_dssetup.h
new file mode 100644
index 0000000000..e2dca43360
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_dssetup.h
@@ -0,0 +1,39 @@
+#include "librpc/gen_ndr/ndr_dssetup.h"
+#ifndef __CLI_DSSETUP__
+#define __CLI_DSSETUP__
+NTSTATUS rpccli_dssetup_DsRoleGetPrimaryDomainInformation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ enum dssetup_DsRoleInfoLevel level /* [in] */,
+ union dssetup_DsRoleInfo *info /* [out] [unique,switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_dssetup_DsRoleDnsNameToFlatName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_dssetup_DsRoleDcAsDc(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_dssetup_DsRoleDcAsReplica(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_dssetup_DsRoleDemoteDc(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_dssetup_DsRoleGetDcOperationProgress(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_dssetup_DsRoleGetDcOperationResults(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_dssetup_DsRoleCancel(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_dssetup_DsRoleServerSaveStateForUpgrade(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_dssetup_DsRoleUpgradeDownlevelServer(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_dssetup_DsRoleAbortDownlevelServerUpgrade(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+#endif /* __CLI_DSSETUP__ */
diff --git a/source3/librpc/gen_ndr/cli_echo.c b/source3/librpc/gen_ndr/cli_echo.c
new file mode 100644
index 0000000000..a775825f5f
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_echo.c
@@ -0,0 +1,410 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * client auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/cli_echo.h"
+
+NTSTATUS rpccli_echo_AddOne(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t in_data /* [in] */,
+ uint32_t *out_data /* [out] [ref] */)
+{
+ struct echo_AddOne r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.in_data = in_data;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_AddOne, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_rpcecho,
+ NDR_ECHO_ADDONE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_AddOne, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *out_data = *r.out.out_data;
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_echo_EchoData(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t len /* [in] */,
+ uint8_t *in_data /* [in] [size_is(len)] */,
+ uint8_t *out_data /* [out] [size_is(len)] */)
+{
+ struct echo_EchoData r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.len = len;
+ r.in.in_data = in_data;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_EchoData, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_rpcecho,
+ NDR_ECHO_ECHODATA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_EchoData, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ memcpy(out_data, r.out.out_data, r.in.len * sizeof(*out_data));
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_echo_SinkData(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t len /* [in] */,
+ uint8_t *data /* [in] [size_is(len)] */)
+{
+ struct echo_SinkData r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.len = len;
+ r.in.data = data;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_SinkData, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_rpcecho,
+ NDR_ECHO_SINKDATA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_SinkData, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_echo_SourceData(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t len /* [in] */,
+ uint8_t *data /* [out] [size_is(len)] */)
+{
+ struct echo_SourceData r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.len = len;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_SourceData, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_rpcecho,
+ NDR_ECHO_SOURCEDATA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_SourceData, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ memcpy(data, r.out.data, r.in.len * sizeof(*data));
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_echo_TestCall(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *s1 /* [in] [ref,charset(UTF16)] */,
+ const char **s2 /* [out] [ref,charset(UTF16)] */)
+{
+ struct echo_TestCall r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.s1 = s1;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_TestCall, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_rpcecho,
+ NDR_ECHO_TESTCALL,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_TestCall, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *s2 = *r.out.s2;
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_echo_TestCall2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t level /* [in] */,
+ union echo_Info *info /* [out] [ref,switch_is(level)] */)
+{
+ struct echo_TestCall2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_TestCall2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_rpcecho,
+ NDR_ECHO_TESTCALL2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_TestCall2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_echo_TestSleep(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t seconds /* [in] */)
+{
+ struct echo_TestSleep r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.seconds = seconds;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_TestSleep, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_rpcecho,
+ NDR_ECHO_TESTSLEEP,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_TestSleep, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_echo_TestEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ enum echo_Enum1 *foo1 /* [in,out] [ref] */,
+ struct echo_Enum2 *foo2 /* [in,out] [ref] */,
+ union echo_Enum3 *foo3 /* [in,out] [ref,switch_is(*foo1)] */)
+{
+ struct echo_TestEnum r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.foo1 = foo1;
+ r.in.foo2 = foo2;
+ r.in.foo3 = foo3;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_TestEnum, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_rpcecho,
+ NDR_ECHO_TESTENUM,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_TestEnum, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *foo1 = *r.out.foo1;
+ *foo2 = *r.out.foo2;
+ *foo3 = *r.out.foo3;
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_echo_TestSurrounding(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct echo_Surrounding *data /* [in,out] [ref] */)
+{
+ struct echo_TestSurrounding r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.data = data;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_TestSurrounding, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_rpcecho,
+ NDR_ECHO_TESTSURROUNDING,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_TestSurrounding, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *data = *r.out.data;
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_echo_TestDoublePointer(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t ***data /* [in] [ref] */)
+{
+ struct echo_TestDoublePointer r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.data = data;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_TestDoublePointer, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_rpcecho,
+ NDR_ECHO_TESTDOUBLEPOINTER,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_TestDoublePointer, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
diff --git a/source3/librpc/gen_ndr/cli_echo.h b/source3/librpc/gen_ndr/cli_echo.h
new file mode 100644
index 0000000000..9da13e97f6
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_echo.h
@@ -0,0 +1,43 @@
+#include "librpc/gen_ndr/ndr_echo.h"
+#ifndef __CLI_RPCECHO__
+#define __CLI_RPCECHO__
+NTSTATUS rpccli_echo_AddOne(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t in_data /* [in] */,
+ uint32_t *out_data /* [out] [ref] */);
+NTSTATUS rpccli_echo_EchoData(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t len /* [in] */,
+ uint8_t *in_data /* [in] [size_is(len)] */,
+ uint8_t *out_data /* [out] [size_is(len)] */);
+NTSTATUS rpccli_echo_SinkData(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t len /* [in] */,
+ uint8_t *data /* [in] [size_is(len)] */);
+NTSTATUS rpccli_echo_SourceData(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t len /* [in] */,
+ uint8_t *data /* [out] [size_is(len)] */);
+NTSTATUS rpccli_echo_TestCall(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *s1 /* [in] [ref,charset(UTF16)] */,
+ const char **s2 /* [out] [ref,charset(UTF16)] */);
+NTSTATUS rpccli_echo_TestCall2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t level /* [in] */,
+ union echo_Info *info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_echo_TestSleep(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t seconds /* [in] */);
+NTSTATUS rpccli_echo_TestEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ enum echo_Enum1 *foo1 /* [in,out] [ref] */,
+ struct echo_Enum2 *foo2 /* [in,out] [ref] */,
+ union echo_Enum3 *foo3 /* [in,out] [ref,switch_is(*foo1)] */);
+NTSTATUS rpccli_echo_TestSurrounding(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct echo_Surrounding *data /* [in,out] [ref] */);
+NTSTATUS rpccli_echo_TestDoublePointer(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t ***data /* [in] [ref] */);
+#endif /* __CLI_RPCECHO__ */
diff --git a/source3/librpc/gen_ndr/cli_epmapper.c b/source3/librpc/gen_ndr/cli_epmapper.c
new file mode 100644
index 0000000000..19673ab659
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_epmapper.c
@@ -0,0 +1,347 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * client auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/cli_epmapper.h"
+
+NTSTATUS rpccli_epm_Insert(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t num_ents /* [in] */,
+ struct epm_entry_t *entries /* [in] [size_is(num_ents)] */,
+ uint32_t replace /* [in] */)
+{
+ struct epm_Insert r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.num_ents = num_ents;
+ r.in.entries = entries;
+ r.in.replace = replace;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(epm_Insert, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_epmapper,
+ NDR_EPM_INSERT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(epm_Insert, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_epm_Delete(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t num_ents /* [in] */,
+ struct epm_entry_t *entries /* [in] [size_is(num_ents)] */)
+{
+ struct epm_Delete r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.num_ents = num_ents;
+ r.in.entries = entries;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(epm_Delete, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_epmapper,
+ NDR_EPM_DELETE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(epm_Delete, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_epm_Lookup(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t inquiry_type /* [in] */,
+ struct GUID *object /* [in] [ptr] */,
+ struct rpc_if_id_t *interface_id /* [in] [ptr] */,
+ uint32_t vers_option /* [in] */,
+ struct policy_handle *entry_handle /* [in,out] [ref] */,
+ uint32_t max_ents /* [in] */,
+ uint32_t *num_ents /* [out] [ref] */,
+ struct epm_entry_t *entries /* [out] [length_is(*num_ents),size_is(max_ents)] */)
+{
+ struct epm_Lookup r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.inquiry_type = inquiry_type;
+ r.in.object = object;
+ r.in.interface_id = interface_id;
+ r.in.vers_option = vers_option;
+ r.in.entry_handle = entry_handle;
+ r.in.max_ents = max_ents;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(epm_Lookup, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_epmapper,
+ NDR_EPM_LOOKUP,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(epm_Lookup, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *entry_handle = *r.out.entry_handle;
+ *num_ents = *r.out.num_ents;
+ memcpy(entries, r.out.entries, r.in.max_ents * sizeof(*entries));
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_epm_Map(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct GUID *object /* [in] [ptr] */,
+ struct epm_twr_t *map_tower /* [in] [ptr] */,
+ struct policy_handle *entry_handle /* [in,out] [ref] */,
+ uint32_t max_towers /* [in] */,
+ uint32_t *num_towers /* [out] [ref] */,
+ struct epm_twr_p_t *towers /* [out] [length_is(*num_towers),size_is(max_towers)] */)
+{
+ struct epm_Map r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.object = object;
+ r.in.map_tower = map_tower;
+ r.in.entry_handle = entry_handle;
+ r.in.max_towers = max_towers;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(epm_Map, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_epmapper,
+ NDR_EPM_MAP,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(epm_Map, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *entry_handle = *r.out.entry_handle;
+ *num_towers = *r.out.num_towers;
+ memcpy(towers, r.out.towers, r.in.max_towers * sizeof(*towers));
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_epm_LookupHandleFree(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *entry_handle /* [in,out] [ref] */)
+{
+ struct epm_LookupHandleFree r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.entry_handle = entry_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(epm_LookupHandleFree, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_epmapper,
+ NDR_EPM_LOOKUPHANDLEFREE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(epm_LookupHandleFree, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *entry_handle = *r.out.entry_handle;
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_epm_InqObject(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct GUID *epm_object /* [in] [ref] */)
+{
+ struct epm_InqObject r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.epm_object = epm_object;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(epm_InqObject, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_epmapper,
+ NDR_EPM_INQOBJECT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(epm_InqObject, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_epm_MgmtDelete(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t object_speced /* [in] */,
+ struct GUID *object /* [in] [ptr] */,
+ struct epm_twr_t *tower /* [in] [ptr] */)
+{
+ struct epm_MgmtDelete r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.object_speced = object_speced;
+ r.in.object = object;
+ r.in.tower = tower;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(epm_MgmtDelete, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_epmapper,
+ NDR_EPM_MGMTDELETE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(epm_MgmtDelete, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpccli_epm_MapAuth(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct epm_MapAuth r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(epm_MapAuth, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_epmapper,
+ NDR_EPM_MAPAUTH,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(epm_MapAuth, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return NT_STATUS_OK;
+}
+
diff --git a/source3/librpc/gen_ndr/cli_epmapper.h b/source3/librpc/gen_ndr/cli_epmapper.h
new file mode 100644
index 0000000000..44884fad7e
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_epmapper.h
@@ -0,0 +1,44 @@
+#include "librpc/gen_ndr/ndr_epmapper.h"
+#ifndef __CLI_EPMAPPER__
+#define __CLI_EPMAPPER__
+NTSTATUS rpccli_epm_Insert(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t num_ents /* [in] */,
+ struct epm_entry_t *entries /* [in] [size_is(num_ents)] */,
+ uint32_t replace /* [in] */);
+NTSTATUS rpccli_epm_Delete(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t num_ents /* [in] */,
+ struct epm_entry_t *entries /* [in] [size_is(num_ents)] */);
+NTSTATUS rpccli_epm_Lookup(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t inquiry_type /* [in] */,
+ struct GUID *object /* [in] [ptr] */,
+ struct rpc_if_id_t *interface_id /* [in] [ptr] */,
+ uint32_t vers_option /* [in] */,
+ struct policy_handle *entry_handle /* [in,out] [ref] */,
+ uint32_t max_ents /* [in] */,
+ uint32_t *num_ents /* [out] [ref] */,
+ struct epm_entry_t *entries /* [out] [length_is(*num_ents),size_is(max_ents)] */);
+NTSTATUS rpccli_epm_Map(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct GUID *object /* [in] [ptr] */,
+ struct epm_twr_t *map_tower /* [in] [ptr] */,
+ struct policy_handle *entry_handle /* [in,out] [ref] */,
+ uint32_t max_towers /* [in] */,
+ uint32_t *num_towers /* [out] [ref] */,
+ struct epm_twr_p_t *towers /* [out] [length_is(*num_towers),size_is(max_towers)] */);
+NTSTATUS rpccli_epm_LookupHandleFree(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *entry_handle /* [in,out] [ref] */);
+NTSTATUS rpccli_epm_InqObject(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct GUID *epm_object /* [in] [ref] */);
+NTSTATUS rpccli_epm_MgmtDelete(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t object_speced /* [in] */,
+ struct GUID *object /* [in] [ptr] */,
+ struct epm_twr_t *tower /* [in] [ptr] */);
+NTSTATUS rpccli_epm_MapAuth(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+#endif /* __CLI_EPMAPPER__ */
diff --git a/source3/librpc/gen_ndr/cli_eventlog.c b/source3/librpc/gen_ndr/cli_eventlog.c
new file mode 100644
index 0000000000..08456fc994
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_eventlog.c
@@ -0,0 +1,915 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * client auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/cli_eventlog.h"
+
+NTSTATUS rpccli_eventlog_ClearEventLogW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String *backupfile /* [in] [unique] */)
+{
+ struct eventlog_ClearEventLogW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.backupfile = backupfile;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_ClearEventLogW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_CLEAREVENTLOGW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_ClearEventLogW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_BackupEventLogW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_BackupEventLogW r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_BackupEventLogW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_BACKUPEVENTLOGW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_BackupEventLogW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_CloseEventLog(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in,out] [ref] */)
+{
+ struct eventlog_CloseEventLog r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_CloseEventLog, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_CLOSEEVENTLOG,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_CloseEventLog, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_DeregisterEventSource(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_DeregisterEventSource r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_DeregisterEventSource, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_DEREGISTEREVENTSOURCE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_DeregisterEventSource, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_GetNumRecords(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t *number /* [out] [ref] */)
+{
+ struct eventlog_GetNumRecords r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_GetNumRecords, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_GETNUMRECORDS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_GetNumRecords, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *number = *r.out.number;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_GetOldestRecord(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t *oldest_entry /* [out] [ref] */)
+{
+ struct eventlog_GetOldestRecord r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_GetOldestRecord, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_GETOLDESTRECORD,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_GetOldestRecord, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *oldest_entry = *r.out.oldest_entry;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_ChangeNotify(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_ChangeNotify r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_ChangeNotify, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_CHANGENOTIFY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_ChangeNotify, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_OpenEventLogW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct eventlog_OpenUnknown0 *unknown0 /* [in] [unique] */,
+ struct lsa_String *logname /* [in] [ref] */,
+ struct lsa_String *servername /* [in] [ref] */,
+ uint32_t unknown2 /* [in] */,
+ uint32_t unknown3 /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */)
+{
+ struct eventlog_OpenEventLogW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.unknown0 = unknown0;
+ r.in.logname = logname;
+ r.in.servername = servername;
+ r.in.unknown2 = unknown2;
+ r.in.unknown3 = unknown3;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_OpenEventLogW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_OPENEVENTLOGW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_OpenEventLogW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_RegisterEventSourceW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_RegisterEventSourceW r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_RegisterEventSourceW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_REGISTEREVENTSOURCEW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_RegisterEventSourceW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_OpenBackupEventLogW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_OpenBackupEventLogW r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_OpenBackupEventLogW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_OPENBACKUPEVENTLOGW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_OpenBackupEventLogW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_ReadEventLogW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t flags /* [in] */,
+ uint32_t offset /* [in] */,
+ uint32_t number_of_bytes /* [in] [range(0,0x7FFFF)] */,
+ uint8_t *data /* [out] [ref,size_is(number_of_bytes)] */,
+ uint32_t *sent_size /* [out] [ref] */,
+ uint32_t *real_size /* [out] [ref] */)
+{
+ struct eventlog_ReadEventLogW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.flags = flags;
+ r.in.offset = offset;
+ r.in.number_of_bytes = number_of_bytes;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_ReadEventLogW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_READEVENTLOGW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_ReadEventLogW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ memcpy(data, r.out.data, r.in.number_of_bytes * sizeof(*data));
+ *sent_size = *r.out.sent_size;
+ *real_size = *r.out.real_size;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_ReportEventW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_ReportEventW r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_ReportEventW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_REPORTEVENTW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_ReportEventW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_ClearEventLogA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_ClearEventLogA r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_ClearEventLogA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_CLEAREVENTLOGA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_ClearEventLogA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_BackupEventLogA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_BackupEventLogA r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_BackupEventLogA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_BACKUPEVENTLOGA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_BackupEventLogA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_OpenEventLogA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_OpenEventLogA r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_OpenEventLogA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_OPENEVENTLOGA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_OpenEventLogA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_RegisterEventSourceA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_RegisterEventSourceA r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_RegisterEventSourceA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_REGISTEREVENTSOURCEA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_RegisterEventSourceA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_OpenBackupEventLogA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_OpenBackupEventLogA r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_OpenBackupEventLogA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_OPENBACKUPEVENTLOGA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_OpenBackupEventLogA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_ReadEventLogA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_ReadEventLogA r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_ReadEventLogA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_READEVENTLOGA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_ReadEventLogA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_ReportEventA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_ReportEventA r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_ReportEventA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_REPORTEVENTA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_ReportEventA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_RegisterClusterSvc(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_RegisterClusterSvc r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_RegisterClusterSvc, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_REGISTERCLUSTERSVC,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_RegisterClusterSvc, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_DeregisterClusterSvc(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_DeregisterClusterSvc r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_DeregisterClusterSvc, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_DEREGISTERCLUSTERSVC,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_DeregisterClusterSvc, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_WriteClusterEvents(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_WriteClusterEvents r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_WriteClusterEvents, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_WRITECLUSTEREVENTS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_WriteClusterEvents, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_GetLogIntormation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct eventlog_GetLogIntormation r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_GetLogIntormation, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_GETLOGINTORMATION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_GetLogIntormation, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_eventlog_FlushEventLog(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */)
+{
+ struct eventlog_FlushEventLog r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_FlushEventLog, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_eventlog,
+ NDR_EVENTLOG_FLUSHEVENTLOG,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_FlushEventLog, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
diff --git a/source3/librpc/gen_ndr/cli_eventlog.h b/source3/librpc/gen_ndr/cli_eventlog.h
new file mode 100644
index 0000000000..6945683340
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_eventlog.h
@@ -0,0 +1,73 @@
+#include "librpc/gen_ndr/ndr_eventlog.h"
+#ifndef __CLI_EVENTLOG__
+#define __CLI_EVENTLOG__
+NTSTATUS rpccli_eventlog_ClearEventLogW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String *backupfile /* [in] [unique] */);
+NTSTATUS rpccli_eventlog_BackupEventLogW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_CloseEventLog(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in,out] [ref] */);
+NTSTATUS rpccli_eventlog_DeregisterEventSource(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_GetNumRecords(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t *number /* [out] [ref] */);
+NTSTATUS rpccli_eventlog_GetOldestRecord(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t *oldest_entry /* [out] [ref] */);
+NTSTATUS rpccli_eventlog_ChangeNotify(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_OpenEventLogW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct eventlog_OpenUnknown0 *unknown0 /* [in] [unique] */,
+ struct lsa_String *logname /* [in] [ref] */,
+ struct lsa_String *servername /* [in] [ref] */,
+ uint32_t unknown2 /* [in] */,
+ uint32_t unknown3 /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */);
+NTSTATUS rpccli_eventlog_RegisterEventSourceW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_OpenBackupEventLogW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_ReadEventLogW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t flags /* [in] */,
+ uint32_t offset /* [in] */,
+ uint32_t number_of_bytes /* [in] [range(0,0x7FFFF)] */,
+ uint8_t *data /* [out] [ref,size_is(number_of_bytes)] */,
+ uint32_t *sent_size /* [out] [ref] */,
+ uint32_t *real_size /* [out] [ref] */);
+NTSTATUS rpccli_eventlog_ReportEventW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_ClearEventLogA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_BackupEventLogA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_OpenEventLogA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_RegisterEventSourceA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_OpenBackupEventLogA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_ReadEventLogA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_ReportEventA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_RegisterClusterSvc(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_DeregisterClusterSvc(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_WriteClusterEvents(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_GetLogIntormation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_eventlog_FlushEventLog(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */);
+#endif /* __CLI_EVENTLOG__ */
diff --git a/source3/librpc/gen_ndr/cli_initshutdown.c b/source3/librpc/gen_ndr/cli_initshutdown.c
new file mode 100644
index 0000000000..ab48623ee1
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_initshutdown.c
@@ -0,0 +1,155 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * client auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/cli_initshutdown.h"
+
+NTSTATUS rpccli_initshutdown_Init(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *hostname /* [in] [unique] */,
+ struct initshutdown_String *message /* [in] [unique] */,
+ uint32_t timeout /* [in] */,
+ uint8_t force_apps /* [in] */,
+ uint8_t do_reboot /* [in] */,
+ WERROR *werror)
+{
+ struct initshutdown_Init r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.hostname = hostname;
+ r.in.message = message;
+ r.in.timeout = timeout;
+ r.in.force_apps = force_apps;
+ r.in.do_reboot = do_reboot;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(initshutdown_Init, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_initshutdown,
+ NDR_INITSHUTDOWN_INIT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(initshutdown_Init, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_initshutdown_Abort(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *server /* [in] [unique] */,
+ WERROR *werror)
+{
+ struct initshutdown_Abort r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server = server;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(initshutdown_Abort, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_initshutdown,
+ NDR_INITSHUTDOWN_ABORT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(initshutdown_Abort, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_initshutdown_InitEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *hostname /* [in] [unique] */,
+ struct initshutdown_String *message /* [in] [unique] */,
+ uint32_t timeout /* [in] */,
+ uint8_t force_apps /* [in] */,
+ uint8_t do_reboot /* [in] */,
+ uint32_t reason /* [in] */,
+ WERROR *werror)
+{
+ struct initshutdown_InitEx r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.hostname = hostname;
+ r.in.message = message;
+ r.in.timeout = timeout;
+ r.in.force_apps = force_apps;
+ r.in.do_reboot = do_reboot;
+ r.in.reason = reason;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(initshutdown_InitEx, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_initshutdown,
+ NDR_INITSHUTDOWN_INITEX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(initshutdown_InitEx, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
diff --git a/source3/librpc/gen_ndr/cli_initshutdown.h b/source3/librpc/gen_ndr/cli_initshutdown.h
new file mode 100644
index 0000000000..c7d2cad664
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_initshutdown.h
@@ -0,0 +1,25 @@
+#include "librpc/gen_ndr/ndr_initshutdown.h"
+#ifndef __CLI_INITSHUTDOWN__
+#define __CLI_INITSHUTDOWN__
+NTSTATUS rpccli_initshutdown_Init(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *hostname /* [in] [unique] */,
+ struct initshutdown_String *message /* [in] [unique] */,
+ uint32_t timeout /* [in] */,
+ uint8_t force_apps /* [in] */,
+ uint8_t do_reboot /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_initshutdown_Abort(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *server /* [in] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_initshutdown_InitEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *hostname /* [in] [unique] */,
+ struct initshutdown_String *message /* [in] [unique] */,
+ uint32_t timeout /* [in] */,
+ uint8_t force_apps /* [in] */,
+ uint8_t do_reboot /* [in] */,
+ uint32_t reason /* [in] */,
+ WERROR *werror);
+#endif /* __CLI_INITSHUTDOWN__ */
diff --git a/source3/librpc/gen_ndr/cli_lsa.c b/source3/librpc/gen_ndr/cli_lsa.c
new file mode 100644
index 0000000000..4ab27ed04b
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_lsa.c
@@ -0,0 +1,3401 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * client auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/cli_lsa.h"
+
+NTSTATUS rpccli_lsa_Close(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in,out] [ref] */)
+{
+ struct lsa_Close r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_Close, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CLOSE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_Close, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_Delete(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */)
+{
+ struct lsa_Delete r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_Delete, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_DELETE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_Delete, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_EnumPrivs(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */,
+ struct lsa_PrivArray *privs /* [out] [ref] */,
+ uint32_t max_count /* [in] */)
+{
+ struct lsa_EnumPrivs r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.resume_handle = resume_handle;
+ r.in.max_count = max_count;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_EnumPrivs, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_ENUMPRIVS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_EnumPrivs, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *resume_handle = *r.out.resume_handle;
+ *privs = *r.out.privs;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_QuerySecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t sec_info /* [in] */,
+ struct sec_desc_buf **sdbuf /* [out] [ref] */)
+{
+ struct lsa_QuerySecurity r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.sec_info = sec_info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_QuerySecurity, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_QUERYSECURITY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_QuerySecurity, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *sdbuf = *r.out.sdbuf;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_SetSecObj(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t sec_info /* [in] */,
+ struct sec_desc_buf *sdbuf /* [in] [ref] */)
+{
+ struct lsa_SetSecObj r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.sec_info = sec_info;
+ r.in.sdbuf = sdbuf;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetSecObj, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_SETSECOBJ,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetSecObj, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_ChangePassword(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_ChangePassword r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_ChangePassword, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CHANGEPASSWORD,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_ChangePassword, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_OpenPolicy(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ struct lsa_ObjectAttribute *attr /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */)
+{
+ struct lsa_OpenPolicy r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.attr = attr;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_OpenPolicy, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_OPENPOLICY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_OpenPolicy, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_QueryInfoPolicy(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ enum lsa_PolicyInfo level /* [in] */,
+ union lsa_PolicyInformation **info /* [out] [ref,switch_is(level)] */)
+{
+ struct lsa_QueryInfoPolicy r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_QueryInfoPolicy, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_QUERYINFOPOLICY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_QueryInfoPolicy, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_SetInfoPolicy(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ enum lsa_PolicyInfo level /* [in] */,
+ union lsa_PolicyInformation *info /* [in] [ref,switch_is(level)] */)
+{
+ struct lsa_SetInfoPolicy r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.level = level;
+ r.in.info = info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetInfoPolicy, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_SETINFOPOLICY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetInfoPolicy, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_ClearAuditLog(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_ClearAuditLog r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_ClearAuditLog, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CLEARAUDITLOG,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_ClearAuditLog, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_CreateAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *acct_handle /* [out] [ref] */)
+{
+ struct lsa_CreateAccount r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.sid = sid;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CreateAccount, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CREATEACCOUNT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CreateAccount, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *acct_handle = *r.out.acct_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_EnumAccounts(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */,
+ struct lsa_SidArray *sids /* [out] [ref] */,
+ uint32_t num_entries /* [in] [range(0,8192)] */)
+{
+ struct lsa_EnumAccounts r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.resume_handle = resume_handle;
+ r.in.num_entries = num_entries;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_EnumAccounts, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_ENUMACCOUNTS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_EnumAccounts, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *resume_handle = *r.out.resume_handle;
+ *sids = *r.out.sids;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_CreateTrustedDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_DomainInfo *info /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *trustdom_handle /* [out] [ref] */)
+{
+ struct lsa_CreateTrustedDomain r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.info = info;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CreateTrustedDomain, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CREATETRUSTEDDOMAIN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CreateTrustedDomain, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *trustdom_handle = *r.out.trustdom_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_EnumTrustDom(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */,
+ struct lsa_DomainList *domains /* [out] [ref] */,
+ uint32_t max_size /* [in] */)
+{
+ struct lsa_EnumTrustDom r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.resume_handle = resume_handle;
+ r.in.max_size = max_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_EnumTrustDom, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_ENUMTRUSTDOM,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_EnumTrustDom, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *resume_handle = *r.out.resume_handle;
+ *domains = *r.out.domains;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LookupNames(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t num_names /* [in] [range(0,1000)] */,
+ struct lsa_String *names /* [in] [size_is(num_names)] */,
+ struct lsa_RefDomainList **domains /* [out] [ref] */,
+ struct lsa_TransSidArray *sids /* [in,out] [ref] */,
+ enum lsa_LookupNamesLevel level /* [in] */,
+ uint32_t *count /* [in,out] [ref] */)
+{
+ struct lsa_LookupNames r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.num_names = num_names;
+ r.in.names = names;
+ r.in.sids = sids;
+ r.in.level = level;
+ r.in.count = count;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupNames, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LOOKUPNAMES,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupNames, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *domains = *r.out.domains;
+ *sids = *r.out.sids;
+ *count = *r.out.count;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LookupSids(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_SidArray *sids /* [in] [ref] */,
+ struct lsa_RefDomainList **domains /* [out] [ref] */,
+ struct lsa_TransNameArray *names /* [in,out] [ref] */,
+ uint16_t level /* [in] */,
+ uint32_t *count /* [in,out] [ref] */)
+{
+ struct lsa_LookupSids r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.sids = sids;
+ r.in.names = names;
+ r.in.level = level;
+ r.in.count = count;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupSids, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LOOKUPSIDS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupSids, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *domains = *r.out.domains;
+ *names = *r.out.names;
+ *count = *r.out.count;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_CreateSecret(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String name /* [in] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *sec_handle /* [out] [ref] */)
+{
+ struct lsa_CreateSecret r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.name = name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CreateSecret, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CREATESECRET,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CreateSecret, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *sec_handle = *r.out.sec_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_OpenAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *acct_handle /* [out] [ref] */)
+{
+ struct lsa_OpenAccount r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.sid = sid;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_OpenAccount, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_OPENACCOUNT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_OpenAccount, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *acct_handle = *r.out.acct_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_EnumPrivsAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_PrivilegeSet **privs /* [out] [ref] */)
+{
+ struct lsa_EnumPrivsAccount r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_EnumPrivsAccount, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_ENUMPRIVSACCOUNT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_EnumPrivsAccount, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *privs = *r.out.privs;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_AddPrivilegesToAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_PrivilegeSet *privs /* [in] [ref] */)
+{
+ struct lsa_AddPrivilegesToAccount r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.privs = privs;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_AddPrivilegesToAccount, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_ADDPRIVILEGESTOACCOUNT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_AddPrivilegesToAccount, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_RemovePrivilegesFromAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint8_t remove_all /* [in] */,
+ struct lsa_PrivilegeSet *privs /* [in] [unique] */)
+{
+ struct lsa_RemovePrivilegesFromAccount r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.remove_all = remove_all;
+ r.in.privs = privs;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_RemovePrivilegesFromAccount, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_REMOVEPRIVILEGESFROMACCOUNT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_RemovePrivilegesFromAccount, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_GetQuotasForAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_GetQuotasForAccount r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_GetQuotasForAccount, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_GETQUOTASFORACCOUNT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_GetQuotasForAccount, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_SetQuotasForAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_SetQuotasForAccount r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetQuotasForAccount, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_SETQUOTASFORACCOUNT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetQuotasForAccount, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_GetSystemAccessAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t *access_mask /* [out] [ref] */)
+{
+ struct lsa_GetSystemAccessAccount r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_GetSystemAccessAccount, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_GETSYSTEMACCESSACCOUNT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_GetSystemAccessAccount, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *access_mask = *r.out.access_mask;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_SetSystemAccessAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t access_mask /* [in] */)
+{
+ struct lsa_SetSystemAccessAccount r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetSystemAccessAccount, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_SETSYSTEMACCESSACCOUNT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetSystemAccessAccount, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_OpenTrustedDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *trustdom_handle /* [out] [ref] */)
+{
+ struct lsa_OpenTrustedDomain r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.sid = sid;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_OpenTrustedDomain, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_OPENTRUSTEDDOMAIN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_OpenTrustedDomain, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *trustdom_handle = *r.out.trustdom_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_QueryTrustedDomainInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *trustdom_handle /* [in] [ref] */,
+ enum lsa_TrustDomInfoEnum level /* [in] */,
+ union lsa_TrustedDomainInfo **info /* [out] [ref,switch_is(level)] */)
+{
+ struct lsa_QueryTrustedDomainInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.trustdom_handle = trustdom_handle;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_QueryTrustedDomainInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_QUERYTRUSTEDDOMAININFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_QueryTrustedDomainInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_SetInformationTrustedDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_SetInformationTrustedDomain r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetInformationTrustedDomain, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_SETINFORMATIONTRUSTEDDOMAIN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetInformationTrustedDomain, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_OpenSecret(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String name /* [in] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *sec_handle /* [out] [ref] */)
+{
+ struct lsa_OpenSecret r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.name = name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_OpenSecret, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_OPENSECRET,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_OpenSecret, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *sec_handle = *r.out.sec_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_SetSecret(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *sec_handle /* [in] [ref] */,
+ struct lsa_DATA_BUF *new_val /* [in] [unique] */,
+ struct lsa_DATA_BUF *old_val /* [in] [unique] */)
+{
+ struct lsa_SetSecret r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.sec_handle = sec_handle;
+ r.in.new_val = new_val;
+ r.in.old_val = old_val;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetSecret, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_SETSECRET,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetSecret, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_QuerySecret(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *sec_handle /* [in] [ref] */,
+ struct lsa_DATA_BUF_PTR *new_val /* [in,out] [unique] */,
+ NTTIME *new_mtime /* [in,out] [unique] */,
+ struct lsa_DATA_BUF_PTR *old_val /* [in,out] [unique] */,
+ NTTIME *old_mtime /* [in,out] [unique] */)
+{
+ struct lsa_QuerySecret r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.sec_handle = sec_handle;
+ r.in.new_val = new_val;
+ r.in.new_mtime = new_mtime;
+ r.in.old_val = old_val;
+ r.in.old_mtime = old_mtime;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_QuerySecret, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_QUERYSECRET,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_QuerySecret, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (new_val && r.out.new_val) {
+ *new_val = *r.out.new_val;
+ }
+ if (new_mtime && r.out.new_mtime) {
+ *new_mtime = *r.out.new_mtime;
+ }
+ if (old_val && r.out.old_val) {
+ *old_val = *r.out.old_val;
+ }
+ if (old_mtime && r.out.old_mtime) {
+ *old_mtime = *r.out.old_mtime;
+ }
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LookupPrivValue(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String *name /* [in] [ref] */,
+ struct lsa_LUID *luid /* [out] [ref] */)
+{
+ struct lsa_LookupPrivValue r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.name = name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupPrivValue, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LOOKUPPRIVVALUE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupPrivValue, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *luid = *r.out.luid;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LookupPrivName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_LUID *luid /* [in] [ref] */,
+ struct lsa_StringLarge **name /* [out] [ref] */)
+{
+ struct lsa_LookupPrivName r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.luid = luid;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupPrivName, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LOOKUPPRIVNAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupPrivName, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *name = *r.out.name;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LookupPrivDisplayName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String *name /* [in] [ref] */,
+ uint16_t language_id /* [in] */,
+ uint16_t language_id_sys /* [in] */,
+ struct lsa_StringLarge **disp_name /* [out] [ref] */,
+ uint16_t *returned_language_id /* [out] [ref] */)
+{
+ struct lsa_LookupPrivDisplayName r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.name = name;
+ r.in.language_id = language_id;
+ r.in.language_id_sys = language_id_sys;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupPrivDisplayName, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LOOKUPPRIVDISPLAYNAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupPrivDisplayName, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *disp_name = *r.out.disp_name;
+ *returned_language_id = *r.out.returned_language_id;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_DeleteObject(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in,out] [ref] */)
+{
+ struct lsa_DeleteObject r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_DeleteObject, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_DELETEOBJECT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_DeleteObject, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_EnumAccountsWithUserRight(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String *name /* [in] [unique] */,
+ struct lsa_SidArray *sids /* [out] [ref] */)
+{
+ struct lsa_EnumAccountsWithUserRight r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.name = name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_EnumAccountsWithUserRight, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_ENUMACCOUNTSWITHUSERRIGHT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_EnumAccountsWithUserRight, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *sids = *r.out.sids;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_EnumAccountRights(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */,
+ struct lsa_RightSet *rights /* [out] [ref] */)
+{
+ struct lsa_EnumAccountRights r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.sid = sid;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_EnumAccountRights, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_ENUMACCOUNTRIGHTS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_EnumAccountRights, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *rights = *r.out.rights;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_AddAccountRights(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */,
+ struct lsa_RightSet *rights /* [in] [ref] */)
+{
+ struct lsa_AddAccountRights r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.sid = sid;
+ r.in.rights = rights;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_AddAccountRights, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_ADDACCOUNTRIGHTS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_AddAccountRights, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_RemoveAccountRights(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */,
+ uint8_t remove_all /* [in] */,
+ struct lsa_RightSet *rights /* [in] [ref] */)
+{
+ struct lsa_RemoveAccountRights r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.sid = sid;
+ r.in.remove_all = remove_all;
+ r.in.rights = rights;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_RemoveAccountRights, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_REMOVEACCOUNTRIGHTS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_RemoveAccountRights, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_QueryTrustedDomainInfoBySid(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct dom_sid2 *dom_sid /* [in] [ref] */,
+ enum lsa_TrustDomInfoEnum level /* [in] */,
+ union lsa_TrustedDomainInfo **info /* [out] [ref,switch_is(level)] */)
+{
+ struct lsa_QueryTrustedDomainInfoBySid r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.dom_sid = dom_sid;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_QueryTrustedDomainInfoBySid, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_QUERYTRUSTEDDOMAININFOBYSID,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_QueryTrustedDomainInfoBySid, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_SetTrustedDomainInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_SetTrustedDomainInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetTrustedDomainInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_SETTRUSTEDDOMAININFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetTrustedDomainInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_DeleteTrustedDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct dom_sid2 *dom_sid /* [in] [ref] */)
+{
+ struct lsa_DeleteTrustedDomain r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.dom_sid = dom_sid;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_DeleteTrustedDomain, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_DELETETRUSTEDDOMAIN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_DeleteTrustedDomain, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_StorePrivateData(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_StorePrivateData r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_StorePrivateData, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_STOREPRIVATEDATA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_StorePrivateData, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_RetrievePrivateData(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_RetrievePrivateData r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_RetrievePrivateData, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_RETRIEVEPRIVATEDATA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_RetrievePrivateData, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_OpenPolicy2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *system_name /* [in] [unique,charset(UTF16)] */,
+ struct lsa_ObjectAttribute *attr /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */)
+{
+ struct lsa_OpenPolicy2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.attr = attr;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_OpenPolicy2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_OPENPOLICY2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_OpenPolicy2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_GetUserName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *system_name /* [in] [unique,charset(UTF16)] */,
+ struct lsa_String **account_name /* [in,out] [ref] */,
+ struct lsa_String **authority_name /* [in,out] [unique] */)
+{
+ struct lsa_GetUserName r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.account_name = account_name;
+ r.in.authority_name = authority_name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_GetUserName, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_GETUSERNAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_GetUserName, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *account_name = *r.out.account_name;
+ if (authority_name && r.out.authority_name) {
+ *authority_name = *r.out.authority_name;
+ }
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_QueryInfoPolicy2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ enum lsa_PolicyInfo level /* [in] */,
+ union lsa_PolicyInformation **info /* [out] [ref,switch_is(level)] */)
+{
+ struct lsa_QueryInfoPolicy2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_QueryInfoPolicy2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_QUERYINFOPOLICY2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_QueryInfoPolicy2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_SetInfoPolicy2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ enum lsa_PolicyInfo level /* [in] */,
+ union lsa_PolicyInformation *info /* [in] [ref,switch_is(level)] */)
+{
+ struct lsa_SetInfoPolicy2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.level = level;
+ r.in.info = info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetInfoPolicy2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_SETINFOPOLICY2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetInfoPolicy2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_QueryTrustedDomainInfoByName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String *trusted_domain /* [in] [ref] */,
+ enum lsa_TrustDomInfoEnum level /* [in] */,
+ union lsa_TrustedDomainInfo **info /* [out] [ref,switch_is(level)] */)
+{
+ struct lsa_QueryTrustedDomainInfoByName r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.trusted_domain = trusted_domain;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_QueryTrustedDomainInfoByName, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_QUERYTRUSTEDDOMAININFOBYNAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_QueryTrustedDomainInfoByName, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_SetTrustedDomainInfoByName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String trusted_domain /* [in] */,
+ enum lsa_TrustDomInfoEnum level /* [in] */,
+ union lsa_TrustedDomainInfo *info /* [in] [unique,switch_is(level)] */)
+{
+ struct lsa_SetTrustedDomainInfoByName r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.trusted_domain = trusted_domain;
+ r.in.level = level;
+ r.in.info = info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetTrustedDomainInfoByName, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_SETTRUSTEDDOMAININFOBYNAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetTrustedDomainInfoByName, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_EnumTrustedDomainsEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */,
+ struct lsa_DomainListEx *domains /* [out] [ref] */,
+ uint32_t max_size /* [in] */)
+{
+ struct lsa_EnumTrustedDomainsEx r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.resume_handle = resume_handle;
+ r.in.max_size = max_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_EnumTrustedDomainsEx, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_ENUMTRUSTEDDOMAINSEX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_EnumTrustedDomainsEx, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *resume_handle = *r.out.resume_handle;
+ *domains = *r.out.domains;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_CreateTrustedDomainEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_CreateTrustedDomainEx r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CreateTrustedDomainEx, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CREATETRUSTEDDOMAINEX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CreateTrustedDomainEx, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_CloseTrustedDomainEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in,out] [ref] */)
+{
+ struct lsa_CloseTrustedDomainEx r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CloseTrustedDomainEx, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CLOSETRUSTEDDOMAINEX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CloseTrustedDomainEx, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_QueryDomainInformationPolicy(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union lsa_DomainInformationPolicy **info /* [out] [ref,switch_is(level)] */)
+{
+ struct lsa_QueryDomainInformationPolicy r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_QueryDomainInformationPolicy, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_QUERYDOMAININFORMATIONPOLICY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_QueryDomainInformationPolicy, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_SetDomainInformationPolicy(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union lsa_DomainInformationPolicy *info /* [in] [unique,switch_is(level)] */)
+{
+ struct lsa_SetDomainInformationPolicy r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.level = level;
+ r.in.info = info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetDomainInformationPolicy, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_SETDOMAININFORMATIONPOLICY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetDomainInformationPolicy, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_OpenTrustedDomainByName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String name /* [in] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *trustdom_handle /* [out] [ref] */)
+{
+ struct lsa_OpenTrustedDomainByName r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.name = name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_OpenTrustedDomainByName, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_OPENTRUSTEDDOMAINBYNAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_OpenTrustedDomainByName, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *trustdom_handle = *r.out.trustdom_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_TestCall(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_TestCall r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_TestCall, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_TESTCALL,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_TestCall, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LookupSids2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_SidArray *sids /* [in] [ref] */,
+ struct lsa_RefDomainList **domains /* [out] [ref] */,
+ struct lsa_TransNameArray2 *names /* [in,out] [ref] */,
+ uint16_t level /* [in] */,
+ uint32_t *count /* [in,out] [ref] */,
+ uint32_t unknown1 /* [in] */,
+ uint32_t unknown2 /* [in] */)
+{
+ struct lsa_LookupSids2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.sids = sids;
+ r.in.names = names;
+ r.in.level = level;
+ r.in.count = count;
+ r.in.unknown1 = unknown1;
+ r.in.unknown2 = unknown2;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupSids2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LOOKUPSIDS2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupSids2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *domains = *r.out.domains;
+ *names = *r.out.names;
+ *count = *r.out.count;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LookupNames2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t num_names /* [in] [range(0,1000)] */,
+ struct lsa_String *names /* [in] [size_is(num_names)] */,
+ struct lsa_RefDomainList **domains /* [out] [ref] */,
+ struct lsa_TransSidArray2 *sids /* [in,out] [ref] */,
+ enum lsa_LookupNamesLevel level /* [in] */,
+ uint32_t *count /* [in,out] [ref] */,
+ uint32_t unknown1 /* [in] */,
+ uint32_t unknown2 /* [in] */)
+{
+ struct lsa_LookupNames2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.num_names = num_names;
+ r.in.names = names;
+ r.in.sids = sids;
+ r.in.level = level;
+ r.in.count = count;
+ r.in.unknown1 = unknown1;
+ r.in.unknown2 = unknown2;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupNames2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LOOKUPNAMES2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupNames2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *domains = *r.out.domains;
+ *sids = *r.out.sids;
+ *count = *r.out.count;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_CreateTrustedDomainEx2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_CreateTrustedDomainEx2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CreateTrustedDomainEx2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CREATETRUSTEDDOMAINEX2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CreateTrustedDomainEx2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_CREDRWRITE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_CREDRWRITE r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRWRITE, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CREDRWRITE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRWRITE, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_CREDRREAD(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_CREDRREAD r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRREAD, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CREDRREAD,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRREAD, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_CREDRENUMERATE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_CREDRENUMERATE r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRENUMERATE, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CREDRENUMERATE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRENUMERATE, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_CREDRWRITEDOMAINCREDENTIALS(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_CREDRWRITEDOMAINCREDENTIALS r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRWRITEDOMAINCREDENTIALS, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CREDRWRITEDOMAINCREDENTIALS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRWRITEDOMAINCREDENTIALS, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_CREDRREADDOMAINCREDENTIALS(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_CREDRREADDOMAINCREDENTIALS r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRREADDOMAINCREDENTIALS, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CREDRREADDOMAINCREDENTIALS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRREADDOMAINCREDENTIALS, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_CREDRDELETE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_CREDRDELETE r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRDELETE, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CREDRDELETE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRDELETE, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_CREDRGETTARGETINFO(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_CREDRGETTARGETINFO r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRGETTARGETINFO, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CREDRGETTARGETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRGETTARGETINFO, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_CREDRPROFILELOADED(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_CREDRPROFILELOADED r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRPROFILELOADED, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CREDRPROFILELOADED,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRPROFILELOADED, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LookupNames3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t num_names /* [in] [range(0,1000)] */,
+ struct lsa_String *names /* [in] [size_is(num_names)] */,
+ struct lsa_RefDomainList **domains /* [out] [ref] */,
+ struct lsa_TransSidArray3 *sids /* [in,out] [ref] */,
+ enum lsa_LookupNamesLevel level /* [in] */,
+ uint32_t *count /* [in,out] [ref] */,
+ uint32_t unknown1 /* [in] */,
+ uint32_t unknown2 /* [in] */)
+{
+ struct lsa_LookupNames3 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.num_names = num_names;
+ r.in.names = names;
+ r.in.sids = sids;
+ r.in.level = level;
+ r.in.count = count;
+ r.in.unknown1 = unknown1;
+ r.in.unknown2 = unknown2;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupNames3, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LOOKUPNAMES3,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupNames3, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *domains = *r.out.domains;
+ *sids = *r.out.sids;
+ *count = *r.out.count;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_CREDRGETSESSIONTYPES(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_CREDRGETSESSIONTYPES r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRGETSESSIONTYPES, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CREDRGETSESSIONTYPES,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRGETSESSIONTYPES, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LSARREGISTERAUDITEVENT(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_LSARREGISTERAUDITEVENT r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LSARREGISTERAUDITEVENT, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LSARREGISTERAUDITEVENT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LSARREGISTERAUDITEVENT, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LSARGENAUDITEVENT(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_LSARGENAUDITEVENT r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LSARGENAUDITEVENT, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LSARGENAUDITEVENT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LSARGENAUDITEVENT, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LSARUNREGISTERAUDITEVENT(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_LSARUNREGISTERAUDITEVENT r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LSARUNREGISTERAUDITEVENT, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LSARUNREGISTERAUDITEVENT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LSARUNREGISTERAUDITEVENT, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_lsaRQueryForestTrustInformation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String *trusted_domain_name /* [in] [ref] */,
+ uint16_t unknown /* [in] */,
+ struct lsa_ForestTrustInformation **forest_trust_info /* [out] [ref] */)
+{
+ struct lsa_lsaRQueryForestTrustInformation r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.trusted_domain_name = trusted_domain_name;
+ r.in.unknown = unknown;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_lsaRQueryForestTrustInformation, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LSARQUERYFORESTTRUSTINFORMATION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_lsaRQueryForestTrustInformation, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *forest_trust_info = *r.out.forest_trust_info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LSARSETFORESTTRUSTINFORMATION(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_LSARSETFORESTTRUSTINFORMATION r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LSARSETFORESTTRUSTINFORMATION, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LSARSETFORESTTRUSTINFORMATION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LSARSETFORESTTRUSTINFORMATION, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_CREDRRENAME(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_CREDRRENAME r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRRENAME, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_CREDRRENAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRRENAME, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LookupSids3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_SidArray *sids /* [in] [ref] */,
+ struct lsa_RefDomainList **domains /* [out] [ref] */,
+ struct lsa_TransNameArray2 *names /* [in,out] [ref] */,
+ uint16_t level /* [in] */,
+ uint32_t *count /* [in,out] [ref] */,
+ uint32_t unknown1 /* [in] */,
+ uint32_t unknown2 /* [in] */)
+{
+ struct lsa_LookupSids3 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.sids = sids;
+ r.in.names = names;
+ r.in.level = level;
+ r.in.count = count;
+ r.in.unknown1 = unknown1;
+ r.in.unknown2 = unknown2;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupSids3, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LOOKUPSIDS3,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupSids3, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *domains = *r.out.domains;
+ *names = *r.out.names;
+ *count = *r.out.count;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LookupNames4(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t num_names /* [in] [range(0,1000)] */,
+ struct lsa_String *names /* [in] [size_is(num_names)] */,
+ struct lsa_RefDomainList **domains /* [out] [ref] */,
+ struct lsa_TransSidArray3 *sids /* [in,out] [ref] */,
+ enum lsa_LookupNamesLevel level /* [in] */,
+ uint32_t *count /* [in,out] [ref] */,
+ uint32_t unknown1 /* [in] */,
+ uint32_t unknown2 /* [in] */)
+{
+ struct lsa_LookupNames4 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.num_names = num_names;
+ r.in.names = names;
+ r.in.sids = sids;
+ r.in.level = level;
+ r.in.count = count;
+ r.in.unknown1 = unknown1;
+ r.in.unknown2 = unknown2;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupNames4, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LOOKUPNAMES4,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupNames4, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *domains = *r.out.domains;
+ *sids = *r.out.sids;
+ *count = *r.out.count;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LSAROPENPOLICYSCE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_LSAROPENPOLICYSCE r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LSAROPENPOLICYSCE, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LSAROPENPOLICYSCE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LSAROPENPOLICYSCE, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LSARADTREGISTERSECURITYEVENTSOURCE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LSARADTREGISTERSECURITYEVENTSOURCE, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LSARADTREGISTERSECURITYEVENTSOURCE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LSARADTREGISTERSECURITYEVENTSOURCE, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LSARADTUNREGISTERSECURITYEVENTSOURCE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_lsa_LSARADTREPORTSECURITYEVENT(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+ struct lsa_LSARADTREPORTSECURITYEVENT r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LSARADTREPORTSECURITYEVENT, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_lsarpc,
+ NDR_LSA_LSARADTREPORTSECURITYEVENT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LSARADTREPORTSECURITYEVENT, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
diff --git a/source3/librpc/gen_ndr/cli_lsa.h b/source3/librpc/gen_ndr/cli_lsa.h
new file mode 100644
index 0000000000..f3333a091b
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_lsa.h
@@ -0,0 +1,370 @@
+#include "librpc/gen_ndr/ndr_lsa.h"
+#ifndef __CLI_LSARPC__
+#define __CLI_LSARPC__
+NTSTATUS rpccli_lsa_Close(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in,out] [ref] */);
+NTSTATUS rpccli_lsa_Delete(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */);
+NTSTATUS rpccli_lsa_EnumPrivs(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */,
+ struct lsa_PrivArray *privs /* [out] [ref] */,
+ uint32_t max_count /* [in] */);
+NTSTATUS rpccli_lsa_QuerySecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t sec_info /* [in] */,
+ struct sec_desc_buf **sdbuf /* [out] [ref] */);
+NTSTATUS rpccli_lsa_SetSecObj(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t sec_info /* [in] */,
+ struct sec_desc_buf *sdbuf /* [in] [ref] */);
+NTSTATUS rpccli_lsa_ChangePassword(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_OpenPolicy(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ struct lsa_ObjectAttribute *attr /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */);
+NTSTATUS rpccli_lsa_QueryInfoPolicy(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ enum lsa_PolicyInfo level /* [in] */,
+ union lsa_PolicyInformation **info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_lsa_SetInfoPolicy(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ enum lsa_PolicyInfo level /* [in] */,
+ union lsa_PolicyInformation *info /* [in] [ref,switch_is(level)] */);
+NTSTATUS rpccli_lsa_ClearAuditLog(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_CreateAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *acct_handle /* [out] [ref] */);
+NTSTATUS rpccli_lsa_EnumAccounts(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */,
+ struct lsa_SidArray *sids /* [out] [ref] */,
+ uint32_t num_entries /* [in] [range(0,8192)] */);
+NTSTATUS rpccli_lsa_CreateTrustedDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_DomainInfo *info /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *trustdom_handle /* [out] [ref] */);
+NTSTATUS rpccli_lsa_EnumTrustDom(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */,
+ struct lsa_DomainList *domains /* [out] [ref] */,
+ uint32_t max_size /* [in] */);
+NTSTATUS rpccli_lsa_LookupNames(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t num_names /* [in] [range(0,1000)] */,
+ struct lsa_String *names /* [in] [size_is(num_names)] */,
+ struct lsa_RefDomainList **domains /* [out] [ref] */,
+ struct lsa_TransSidArray *sids /* [in,out] [ref] */,
+ enum lsa_LookupNamesLevel level /* [in] */,
+ uint32_t *count /* [in,out] [ref] */);
+NTSTATUS rpccli_lsa_LookupSids(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_SidArray *sids /* [in] [ref] */,
+ struct lsa_RefDomainList **domains /* [out] [ref] */,
+ struct lsa_TransNameArray *names /* [in,out] [ref] */,
+ uint16_t level /* [in] */,
+ uint32_t *count /* [in,out] [ref] */);
+NTSTATUS rpccli_lsa_CreateSecret(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String name /* [in] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *sec_handle /* [out] [ref] */);
+NTSTATUS rpccli_lsa_OpenAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *acct_handle /* [out] [ref] */);
+NTSTATUS rpccli_lsa_EnumPrivsAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_PrivilegeSet **privs /* [out] [ref] */);
+NTSTATUS rpccli_lsa_AddPrivilegesToAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_PrivilegeSet *privs /* [in] [ref] */);
+NTSTATUS rpccli_lsa_RemovePrivilegesFromAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint8_t remove_all /* [in] */,
+ struct lsa_PrivilegeSet *privs /* [in] [unique] */);
+NTSTATUS rpccli_lsa_GetQuotasForAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_SetQuotasForAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_GetSystemAccessAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t *access_mask /* [out] [ref] */);
+NTSTATUS rpccli_lsa_SetSystemAccessAccount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t access_mask /* [in] */);
+NTSTATUS rpccli_lsa_OpenTrustedDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *trustdom_handle /* [out] [ref] */);
+NTSTATUS rpccli_lsa_QueryTrustedDomainInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *trustdom_handle /* [in] [ref] */,
+ enum lsa_TrustDomInfoEnum level /* [in] */,
+ union lsa_TrustedDomainInfo **info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_lsa_SetInformationTrustedDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_OpenSecret(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String name /* [in] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *sec_handle /* [out] [ref] */);
+NTSTATUS rpccli_lsa_SetSecret(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *sec_handle /* [in] [ref] */,
+ struct lsa_DATA_BUF *new_val /* [in] [unique] */,
+ struct lsa_DATA_BUF *old_val /* [in] [unique] */);
+NTSTATUS rpccli_lsa_QuerySecret(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *sec_handle /* [in] [ref] */,
+ struct lsa_DATA_BUF_PTR *new_val /* [in,out] [unique] */,
+ NTTIME *new_mtime /* [in,out] [unique] */,
+ struct lsa_DATA_BUF_PTR *old_val /* [in,out] [unique] */,
+ NTTIME *old_mtime /* [in,out] [unique] */);
+NTSTATUS rpccli_lsa_LookupPrivValue(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String *name /* [in] [ref] */,
+ struct lsa_LUID *luid /* [out] [ref] */);
+NTSTATUS rpccli_lsa_LookupPrivName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_LUID *luid /* [in] [ref] */,
+ struct lsa_StringLarge **name /* [out] [ref] */);
+NTSTATUS rpccli_lsa_LookupPrivDisplayName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String *name /* [in] [ref] */,
+ uint16_t language_id /* [in] */,
+ uint16_t language_id_sys /* [in] */,
+ struct lsa_StringLarge **disp_name /* [out] [ref] */,
+ uint16_t *returned_language_id /* [out] [ref] */);
+NTSTATUS rpccli_lsa_DeleteObject(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in,out] [ref] */);
+NTSTATUS rpccli_lsa_EnumAccountsWithUserRight(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String *name /* [in] [unique] */,
+ struct lsa_SidArray *sids /* [out] [ref] */);
+NTSTATUS rpccli_lsa_EnumAccountRights(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */,
+ struct lsa_RightSet *rights /* [out] [ref] */);
+NTSTATUS rpccli_lsa_AddAccountRights(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */,
+ struct lsa_RightSet *rights /* [in] [ref] */);
+NTSTATUS rpccli_lsa_RemoveAccountRights(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */,
+ uint8_t remove_all /* [in] */,
+ struct lsa_RightSet *rights /* [in] [ref] */);
+NTSTATUS rpccli_lsa_QueryTrustedDomainInfoBySid(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct dom_sid2 *dom_sid /* [in] [ref] */,
+ enum lsa_TrustDomInfoEnum level /* [in] */,
+ union lsa_TrustedDomainInfo **info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_lsa_SetTrustedDomainInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_DeleteTrustedDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct dom_sid2 *dom_sid /* [in] [ref] */);
+NTSTATUS rpccli_lsa_StorePrivateData(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_RetrievePrivateData(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_OpenPolicy2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *system_name /* [in] [unique,charset(UTF16)] */,
+ struct lsa_ObjectAttribute *attr /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */);
+NTSTATUS rpccli_lsa_GetUserName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *system_name /* [in] [unique,charset(UTF16)] */,
+ struct lsa_String **account_name /* [in,out] [ref] */,
+ struct lsa_String **authority_name /* [in,out] [unique] */);
+NTSTATUS rpccli_lsa_QueryInfoPolicy2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ enum lsa_PolicyInfo level /* [in] */,
+ union lsa_PolicyInformation **info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_lsa_SetInfoPolicy2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ enum lsa_PolicyInfo level /* [in] */,
+ union lsa_PolicyInformation *info /* [in] [ref,switch_is(level)] */);
+NTSTATUS rpccli_lsa_QueryTrustedDomainInfoByName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String *trusted_domain /* [in] [ref] */,
+ enum lsa_TrustDomInfoEnum level /* [in] */,
+ union lsa_TrustedDomainInfo **info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_lsa_SetTrustedDomainInfoByName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String trusted_domain /* [in] */,
+ enum lsa_TrustDomInfoEnum level /* [in] */,
+ union lsa_TrustedDomainInfo *info /* [in] [unique,switch_is(level)] */);
+NTSTATUS rpccli_lsa_EnumTrustedDomainsEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */,
+ struct lsa_DomainListEx *domains /* [out] [ref] */,
+ uint32_t max_size /* [in] */);
+NTSTATUS rpccli_lsa_CreateTrustedDomainEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_CloseTrustedDomainEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in,out] [ref] */);
+NTSTATUS rpccli_lsa_QueryDomainInformationPolicy(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union lsa_DomainInformationPolicy **info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_lsa_SetDomainInformationPolicy(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union lsa_DomainInformationPolicy *info /* [in] [unique,switch_is(level)] */);
+NTSTATUS rpccli_lsa_OpenTrustedDomainByName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String name /* [in] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *trustdom_handle /* [out] [ref] */);
+NTSTATUS rpccli_lsa_TestCall(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_LookupSids2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_SidArray *sids /* [in] [ref] */,
+ struct lsa_RefDomainList **domains /* [out] [ref] */,
+ struct lsa_TransNameArray2 *names /* [in,out] [ref] */,
+ uint16_t level /* [in] */,
+ uint32_t *count /* [in,out] [ref] */,
+ uint32_t unknown1 /* [in] */,
+ uint32_t unknown2 /* [in] */);
+NTSTATUS rpccli_lsa_LookupNames2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t num_names /* [in] [range(0,1000)] */,
+ struct lsa_String *names /* [in] [size_is(num_names)] */,
+ struct lsa_RefDomainList **domains /* [out] [ref] */,
+ struct lsa_TransSidArray2 *sids /* [in,out] [ref] */,
+ enum lsa_LookupNamesLevel level /* [in] */,
+ uint32_t *count /* [in,out] [ref] */,
+ uint32_t unknown1 /* [in] */,
+ uint32_t unknown2 /* [in] */);
+NTSTATUS rpccli_lsa_CreateTrustedDomainEx2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_CREDRWRITE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_CREDRREAD(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_CREDRENUMERATE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_CREDRWRITEDOMAINCREDENTIALS(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_CREDRREADDOMAINCREDENTIALS(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_CREDRDELETE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_CREDRGETTARGETINFO(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_CREDRPROFILELOADED(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_LookupNames3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t num_names /* [in] [range(0,1000)] */,
+ struct lsa_String *names /* [in] [size_is(num_names)] */,
+ struct lsa_RefDomainList **domains /* [out] [ref] */,
+ struct lsa_TransSidArray3 *sids /* [in,out] [ref] */,
+ enum lsa_LookupNamesLevel level /* [in] */,
+ uint32_t *count /* [in,out] [ref] */,
+ uint32_t unknown1 /* [in] */,
+ uint32_t unknown2 /* [in] */);
+NTSTATUS rpccli_lsa_CREDRGETSESSIONTYPES(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_LSARREGISTERAUDITEVENT(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_LSARGENAUDITEVENT(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_LSARUNREGISTERAUDITEVENT(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_lsaRQueryForestTrustInformation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct lsa_String *trusted_domain_name /* [in] [ref] */,
+ uint16_t unknown /* [in] */,
+ struct lsa_ForestTrustInformation **forest_trust_info /* [out] [ref] */);
+NTSTATUS rpccli_lsa_LSARSETFORESTTRUSTINFORMATION(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_CREDRRENAME(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_LookupSids3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_SidArray *sids /* [in] [ref] */,
+ struct lsa_RefDomainList **domains /* [out] [ref] */,
+ struct lsa_TransNameArray2 *names /* [in,out] [ref] */,
+ uint16_t level /* [in] */,
+ uint32_t *count /* [in,out] [ref] */,
+ uint32_t unknown1 /* [in] */,
+ uint32_t unknown2 /* [in] */);
+NTSTATUS rpccli_lsa_LookupNames4(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t num_names /* [in] [range(0,1000)] */,
+ struct lsa_String *names /* [in] [size_is(num_names)] */,
+ struct lsa_RefDomainList **domains /* [out] [ref] */,
+ struct lsa_TransSidArray3 *sids /* [in,out] [ref] */,
+ enum lsa_LookupNamesLevel level /* [in] */,
+ uint32_t *count /* [in,out] [ref] */,
+ uint32_t unknown1 /* [in] */,
+ uint32_t unknown2 /* [in] */);
+NTSTATUS rpccli_lsa_LSAROPENPOLICYSCE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_LSARADTREGISTERSECURITYEVENTSOURCE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+NTSTATUS rpccli_lsa_LSARADTREPORTSECURITYEVENT(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx);
+#endif /* __CLI_LSARPC__ */
diff --git a/source3/librpc/gen_ndr/cli_netlogon.c b/source3/librpc/gen_ndr/cli_netlogon.c
new file mode 100644
index 0000000000..d6ac8b9ede
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_netlogon.c
@@ -0,0 +1,2338 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * client auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/cli_netlogon.h"
+
+NTSTATUS rpccli_netr_LogonUasLogon(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ const char *workstation /* [in] [charset(UTF16)] */,
+ struct netr_UasInfo *info /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct netr_LogonUasLogon r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.account_name = account_name;
+ r.in.workstation = workstation;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonUasLogon, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_LOGONUASLOGON,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonUasLogon, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_LogonUasLogoff(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ const char *workstation /* [in] [charset(UTF16)] */,
+ struct netr_UasLogoffInfo *info /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct netr_LogonUasLogoff r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.account_name = account_name;
+ r.in.workstation = workstation;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonUasLogoff, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_LOGONUASLOGOFF,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonUasLogoff, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_LogonSamLogon(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *computer_name /* [in] [unique,charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [unique] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [unique] */,
+ enum netr_LogonLevel logon_level /* [in] */,
+ union netr_LogonInfo *logon /* [in] [ref,switch_is(logon_level)] */,
+ uint16_t validation_level /* [in] */,
+ union netr_Validation *validation /* [out] [ref,switch_is(validation_level)] */,
+ uint8_t *authoritative /* [out] [ref] */)
+{
+ struct netr_LogonSamLogon r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.computer_name = computer_name;
+ r.in.credential = credential;
+ r.in.return_authenticator = return_authenticator;
+ r.in.logon_level = logon_level;
+ r.in.logon = logon;
+ r.in.validation_level = validation_level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonSamLogon, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_LOGONSAMLOGON,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonSamLogon, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (return_authenticator && r.out.return_authenticator) {
+ *return_authenticator = *r.out.return_authenticator;
+ }
+ *validation = *r.out.validation;
+ *authoritative = *r.out.authoritative;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_LogonSamLogoff(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *computer_name /* [in] [unique,charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [unique] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [unique] */,
+ enum netr_LogonLevel logon_level /* [in] */,
+ union netr_LogonInfo logon /* [in] [switch_is(logon_level)] */)
+{
+ struct netr_LogonSamLogoff r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.computer_name = computer_name;
+ r.in.credential = credential;
+ r.in.return_authenticator = return_authenticator;
+ r.in.logon_level = logon_level;
+ r.in.logon = logon;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonSamLogoff, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_LOGONSAMLOGOFF,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonSamLogoff, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (return_authenticator && r.out.return_authenticator) {
+ *return_authenticator = *r.out.return_authenticator;
+ }
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_ServerReqChallenge(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ struct netr_Credential *credentials /* [in] [ref] */,
+ struct netr_Credential *return_credentials /* [out] [ref] */)
+{
+ struct netr_ServerReqChallenge r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.computer_name = computer_name;
+ r.in.credentials = credentials;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_ServerReqChallenge, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_SERVERREQCHALLENGE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_ServerReqChallenge, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *return_credentials = *r.out.return_credentials;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_ServerAuthenticate(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ enum netr_SchannelType secure_channel_type /* [in] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ struct netr_Credential *credentials /* [in] [ref] */,
+ struct netr_Credential *return_credentials /* [out] [ref] */)
+{
+ struct netr_ServerAuthenticate r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.account_name = account_name;
+ r.in.secure_channel_type = secure_channel_type;
+ r.in.computer_name = computer_name;
+ r.in.credentials = credentials;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_ServerAuthenticate, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_SERVERAUTHENTICATE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_ServerAuthenticate, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *return_credentials = *r.out.return_credentials;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_ServerPasswordSet(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ enum netr_SchannelType secure_channel_type /* [in] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [ref] */,
+ struct netr_Authenticator *return_authenticator /* [out] [ref] */,
+ struct samr_Password *new_password /* [in] [ref] */)
+{
+ struct netr_ServerPasswordSet r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.account_name = account_name;
+ r.in.secure_channel_type = secure_channel_type;
+ r.in.computer_name = computer_name;
+ r.in.credential = credential;
+ r.in.new_password = new_password;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_ServerPasswordSet, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_SERVERPASSWORDSET,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_ServerPasswordSet, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *return_authenticator = *r.out.return_authenticator;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_DatabaseDeltas(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [charset(UTF16)] */,
+ const char *computername /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [ref] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [ref] */,
+ enum netr_SamDatabaseID database_id /* [in] */,
+ uint64_t *sequence_num /* [in,out] [ref] */,
+ struct netr_DELTA_ENUM_ARRAY **delta_enum_array /* [out] [ref] */,
+ uint32_t preferredmaximumlength /* [in] */)
+{
+ struct netr_DatabaseDeltas r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.logon_server = logon_server;
+ r.in.computername = computername;
+ r.in.credential = credential;
+ r.in.return_authenticator = return_authenticator;
+ r.in.database_id = database_id;
+ r.in.sequence_num = sequence_num;
+ r.in.preferredmaximumlength = preferredmaximumlength;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DatabaseDeltas, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_DATABASEDELTAS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DatabaseDeltas, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *return_authenticator = *r.out.return_authenticator;
+ *sequence_num = *r.out.sequence_num;
+ *delta_enum_array = *r.out.delta_enum_array;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_DatabaseSync(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [charset(UTF16)] */,
+ const char *computername /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator credential /* [in] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [ref] */,
+ enum netr_SamDatabaseID database_id /* [in] */,
+ uint32_t *sync_context /* [in,out] [ref] */,
+ uint32_t preferredmaximumlength /* [in] */,
+ struct netr_DELTA_ENUM_ARRAY *delta_enum_array /* [out] [ref] */)
+{
+ struct netr_DatabaseSync r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.logon_server = logon_server;
+ r.in.computername = computername;
+ r.in.credential = credential;
+ r.in.return_authenticator = return_authenticator;
+ r.in.database_id = database_id;
+ r.in.sync_context = sync_context;
+ r.in.preferredmaximumlength = preferredmaximumlength;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DatabaseSync, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_DATABASESYNC,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DatabaseSync, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *return_authenticator = *r.out.return_authenticator;
+ *sync_context = *r.out.sync_context;
+ *delta_enum_array = *r.out.delta_enum_array;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_AccountDeltas(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [unique,charset(UTF16)] */,
+ const char *computername /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator credential /* [in] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [ref] */,
+ struct netr_UAS_INFO_0 uas /* [in] */,
+ uint32_t count /* [in] */,
+ uint32_t level /* [in] */,
+ uint32_t buffersize /* [in] */,
+ struct netr_AccountBuffer *buffer /* [out] [ref,subcontext(4)] */,
+ uint32_t *count_returned /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ struct netr_UAS_INFO_0 *recordid /* [out] [ref] */)
+{
+ struct netr_AccountDeltas r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.logon_server = logon_server;
+ r.in.computername = computername;
+ r.in.credential = credential;
+ r.in.return_authenticator = return_authenticator;
+ r.in.uas = uas;
+ r.in.count = count;
+ r.in.level = level;
+ r.in.buffersize = buffersize;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_AccountDeltas, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_ACCOUNTDELTAS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_AccountDeltas, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *return_authenticator = *r.out.return_authenticator;
+ *buffer = *r.out.buffer;
+ *count_returned = *r.out.count_returned;
+ *total_entries = *r.out.total_entries;
+ *recordid = *r.out.recordid;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_AccountSync(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [unique,charset(UTF16)] */,
+ const char *computername /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator credential /* [in] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [ref] */,
+ uint32_t reference /* [in] */,
+ uint32_t level /* [in] */,
+ uint32_t buffersize /* [in] */,
+ struct netr_AccountBuffer *buffer /* [out] [ref,subcontext(4)] */,
+ uint32_t *count_returned /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *next_reference /* [out] [ref] */,
+ struct netr_UAS_INFO_0 *recordid /* [in,out] [ref] */)
+{
+ struct netr_AccountSync r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.logon_server = logon_server;
+ r.in.computername = computername;
+ r.in.credential = credential;
+ r.in.return_authenticator = return_authenticator;
+ r.in.reference = reference;
+ r.in.level = level;
+ r.in.buffersize = buffersize;
+ r.in.recordid = recordid;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_AccountSync, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_ACCOUNTSYNC,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_AccountSync, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *return_authenticator = *r.out.return_authenticator;
+ *buffer = *r.out.buffer;
+ *count_returned = *r.out.count_returned;
+ *total_entries = *r.out.total_entries;
+ *next_reference = *r.out.next_reference;
+ *recordid = *r.out.recordid;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_GetDcName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [charset(UTF16)] */,
+ const char *domainname /* [in] [unique,charset(UTF16)] */,
+ const char **dcname /* [out] [ref,charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct netr_GetDcName r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.logon_server = logon_server;
+ r.in.domainname = domainname;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_GetDcName, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_GETDCNAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_GetDcName, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *dcname = *r.out.dcname;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_LogonControl(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [unique,charset(UTF16)] */,
+ enum netr_LogonControlCode function_code /* [in] */,
+ uint32_t level /* [in] */,
+ union netr_CONTROL_QUERY_INFORMATION *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror)
+{
+ struct netr_LogonControl r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.logon_server = logon_server;
+ r.in.function_code = function_code;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonControl, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_LOGONCONTROL,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonControl, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_GetAnyDCName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [unique,charset(UTF16)] */,
+ const char *domainname /* [in] [unique,charset(UTF16)] */,
+ const char **dcname /* [out] [ref,charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct netr_GetAnyDCName r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.logon_server = logon_server;
+ r.in.domainname = domainname;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_GetAnyDCName, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_GETANYDCNAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_GetAnyDCName, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *dcname = *r.out.dcname;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_LogonControl2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [unique,charset(UTF16)] */,
+ enum netr_LogonControlCode function_code /* [in] */,
+ uint32_t level /* [in] */,
+ union netr_CONTROL_DATA_INFORMATION *data /* [in] [ref,switch_is(function_code)] */,
+ union netr_CONTROL_QUERY_INFORMATION *query /* [out] [ref,switch_is(level)] */,
+ WERROR *werror)
+{
+ struct netr_LogonControl2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.logon_server = logon_server;
+ r.in.function_code = function_code;
+ r.in.level = level;
+ r.in.data = data;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonControl2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_LOGONCONTROL2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonControl2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *query = *r.out.query;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_ServerAuthenticate2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ enum netr_SchannelType secure_channel_type /* [in] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ struct netr_Credential *credentials /* [in] [ref] */,
+ struct netr_Credential *return_credentials /* [out] [ref] */,
+ uint32_t *negotiate_flags /* [in,out] [ref] */)
+{
+ struct netr_ServerAuthenticate2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.account_name = account_name;
+ r.in.secure_channel_type = secure_channel_type;
+ r.in.computer_name = computer_name;
+ r.in.credentials = credentials;
+ r.in.negotiate_flags = negotiate_flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_ServerAuthenticate2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_SERVERAUTHENTICATE2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_ServerAuthenticate2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *return_credentials = *r.out.return_credentials;
+ *negotiate_flags = *r.out.negotiate_flags;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_DatabaseSync2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [charset(UTF16)] */,
+ const char *computername /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [ref] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [ref] */,
+ enum netr_SamDatabaseID database_id /* [in] */,
+ uint16_t restart_state /* [in] */,
+ uint32_t *sync_context /* [in,out] [ref] */,
+ struct netr_DELTA_ENUM_ARRAY **delta_enum_array /* [out] [ref] */,
+ uint32_t preferredmaximumlength /* [in] */)
+{
+ struct netr_DatabaseSync2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.logon_server = logon_server;
+ r.in.computername = computername;
+ r.in.credential = credential;
+ r.in.return_authenticator = return_authenticator;
+ r.in.database_id = database_id;
+ r.in.restart_state = restart_state;
+ r.in.sync_context = sync_context;
+ r.in.preferredmaximumlength = preferredmaximumlength;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DatabaseSync2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_DATABASESYNC2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DatabaseSync2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *return_authenticator = *r.out.return_authenticator;
+ *sync_context = *r.out.sync_context;
+ *delta_enum_array = *r.out.delta_enum_array;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_DatabaseRedo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [charset(UTF16)] */,
+ const char *computername /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator credential /* [in] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [ref] */,
+ uint8_t *change_log_entry /* [in] [unique,size_is(change_log_entry_size)] */,
+ uint32_t change_log_entry_size /* [in] */,
+ struct netr_DELTA_ENUM_ARRAY *delta_enum_array /* [out] [ref] */)
+{
+ struct netr_DatabaseRedo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.logon_server = logon_server;
+ r.in.computername = computername;
+ r.in.credential = credential;
+ r.in.return_authenticator = return_authenticator;
+ r.in.change_log_entry = change_log_entry;
+ r.in.change_log_entry_size = change_log_entry_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DatabaseRedo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_DATABASEREDO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DatabaseRedo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *return_authenticator = *r.out.return_authenticator;
+ *delta_enum_array = *r.out.delta_enum_array;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_LogonControl2Ex(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [unique,charset(UTF16)] */,
+ uint32_t function_code /* [in] */,
+ uint32_t level /* [in] */,
+ union netr_CONTROL_DATA_INFORMATION data /* [in] [switch_is(function_code)] */,
+ union netr_CONTROL_QUERY_INFORMATION *query /* [out] [ref,switch_is(level)] */,
+ WERROR *werror)
+{
+ struct netr_LogonControl2Ex r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.logon_server = logon_server;
+ r.in.function_code = function_code;
+ r.in.level = level;
+ r.in.data = data;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonControl2Ex, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_LOGONCONTROL2EX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonControl2Ex, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *query = *r.out.query;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_NetrEnumerateTrustedDomains(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ struct netr_Blob *trusted_domains_blob /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct netr_NetrEnumerateTrustedDomains r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NetrEnumerateTrustedDomains, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_NETRENUMERATETRUSTEDDOMAINS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NetrEnumerateTrustedDomains, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *trusted_domains_blob = *r.out.trusted_domains_blob;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_DsRGetDCName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *domain_name /* [in] [unique,charset(UTF16)] */,
+ struct GUID *domain_guid /* [in] [unique] */,
+ struct GUID *site_guid /* [in] [unique] */,
+ uint32_t flags /* [in] */,
+ struct netr_DsRGetDCNameInfo **info /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct netr_DsRGetDCName r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.domain_name = domain_name;
+ r.in.domain_guid = domain_guid;
+ r.in.site_guid = site_guid;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsRGetDCName, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_DSRGETDCNAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsRGetDCName, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_NETRLOGONDUMMYROUTINE1(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct netr_NETRLOGONDUMMYROUTINE1 r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NETRLOGONDUMMYROUTINE1, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_NETRLOGONDUMMYROUTINE1,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NETRLOGONDUMMYROUTINE1, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_NETRLOGONSETSERVICEBITS(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct netr_NETRLOGONSETSERVICEBITS r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NETRLOGONSETSERVICEBITS, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_NETRLOGONSETSERVICEBITS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NETRLOGONSETSERVICEBITS, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_LogonGetTrustRid(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *domain_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t *rid /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct netr_LogonGetTrustRid r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.domain_name = domain_name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonGetTrustRid, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_LOGONGETTRUSTRID,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonGetTrustRid, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *rid = *r.out.rid;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_NETRLOGONCOMPUTESERVERDIGEST(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct netr_NETRLOGONCOMPUTESERVERDIGEST r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NETRLOGONCOMPUTESERVERDIGEST, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_NETRLOGONCOMPUTESERVERDIGEST,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NETRLOGONCOMPUTESERVERDIGEST, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_NETRLOGONCOMPUTECLIENTDIGEST(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct netr_NETRLOGONCOMPUTECLIENTDIGEST r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NETRLOGONCOMPUTECLIENTDIGEST, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_NETRLOGONCOMPUTECLIENTDIGEST,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NETRLOGONCOMPUTECLIENTDIGEST, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_ServerAuthenticate3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ enum netr_SchannelType secure_channel_type /* [in] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ struct netr_Credential *credentials /* [in,out] [ref] */,
+ uint32_t *negotiate_flags /* [in,out] [ref] */,
+ uint32_t *rid /* [out] [ref] */)
+{
+ struct netr_ServerAuthenticate3 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.account_name = account_name;
+ r.in.secure_channel_type = secure_channel_type;
+ r.in.computer_name = computer_name;
+ r.in.credentials = credentials;
+ r.in.negotiate_flags = negotiate_flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_ServerAuthenticate3, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_SERVERAUTHENTICATE3,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_ServerAuthenticate3, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *credentials = *r.out.credentials;
+ *negotiate_flags = *r.out.negotiate_flags;
+ *rid = *r.out.rid;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_DsRGetDCNameEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *domain_name /* [in] [unique,charset(UTF16)] */,
+ struct GUID *domain_guid /* [in] [unique] */,
+ const char *site_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ struct netr_DsRGetDCNameInfo **info /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct netr_DsRGetDCNameEx r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.domain_name = domain_name;
+ r.in.domain_guid = domain_guid;
+ r.in.site_name = site_name;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsRGetDCNameEx, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_DSRGETDCNAMEEX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsRGetDCNameEx, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_DsRGetSiteName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *computer_name /* [in] [unique,charset(UTF16)] */,
+ const char **site /* [out] [ref,charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct netr_DsRGetSiteName r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.computer_name = computer_name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsRGetSiteName, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_DSRGETSITENAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsRGetSiteName, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *site = *r.out.site;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_LogonGetDomainInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [charset(UTF16)] */,
+ const char *computer_name /* [in] [unique,charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [ref] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [ref] */,
+ uint32_t level /* [in] */,
+ union netr_DomainQuery query /* [in] [switch_is(level)] */,
+ union netr_DomainInfo *info /* [out] [ref,switch_is(level)] */)
+{
+ struct netr_LogonGetDomainInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.computer_name = computer_name;
+ r.in.credential = credential;
+ r.in.return_authenticator = return_authenticator;
+ r.in.level = level;
+ r.in.query = query;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonGetDomainInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_LOGONGETDOMAININFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonGetDomainInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *return_authenticator = *r.out.return_authenticator;
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_ServerPasswordSet2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ enum netr_SchannelType secure_channel_type /* [in] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [ref] */,
+ struct netr_Authenticator *return_authenticator /* [out] [ref] */,
+ struct netr_CryptPassword *new_password /* [in] [ref] */)
+{
+ struct netr_ServerPasswordSet2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.account_name = account_name;
+ r.in.secure_channel_type = secure_channel_type;
+ r.in.computer_name = computer_name;
+ r.in.credential = credential;
+ r.in.new_password = new_password;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_ServerPasswordSet2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_SERVERPASSWORDSET2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_ServerPasswordSet2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *return_authenticator = *r.out.return_authenticator;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_ServerPasswordGet(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ enum netr_SchannelType secure_channel_type /* [in] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [ref] */,
+ struct netr_Authenticator *return_authenticator /* [out] [ref] */,
+ struct samr_Password *password /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct netr_ServerPasswordGet r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.account_name = account_name;
+ r.in.secure_channel_type = secure_channel_type;
+ r.in.computer_name = computer_name;
+ r.in.credential = credential;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_ServerPasswordGet, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_SERVERPASSWORDGET,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_ServerPasswordGet, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *return_authenticator = *r.out.return_authenticator;
+ *password = *r.out.password;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_NETRLOGONSENDTOSAM(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct netr_NETRLOGONSENDTOSAM r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NETRLOGONSENDTOSAM, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_NETRLOGONSENDTOSAM,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NETRLOGONSENDTOSAM, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_DsRAddressToSitenamesW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t count /* [in] [range(0,32000)] */,
+ struct netr_DsRAddress *addresses /* [in] [ref,size_is(count)] */,
+ struct netr_DsRAddressToSitenamesWCtr **ctr /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct netr_DsRAddressToSitenamesW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.count = count;
+ r.in.addresses = addresses;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsRAddressToSitenamesW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_DSRADDRESSTOSITENAMESW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsRAddressToSitenamesW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *ctr = *r.out.ctr;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_DsRGetDCNameEx2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *client_account /* [in] [unique,charset(UTF16)] */,
+ uint32_t mask /* [in] */,
+ const char *domain_name /* [in] [unique,charset(UTF16)] */,
+ struct GUID *domain_guid /* [in] [unique] */,
+ const char *site_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ struct netr_DsRGetDCNameInfo **info /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct netr_DsRGetDCNameEx2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.client_account = client_account;
+ r.in.mask = mask;
+ r.in.domain_name = domain_name;
+ r.in.domain_guid = domain_guid;
+ r.in.site_name = site_name;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsRGetDCNameEx2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_DSRGETDCNAMEEX2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsRGetDCNameEx2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_NETRLOGONGETTIMESERVICEPARENTDOMAIN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_NetrEnumerateTrustedDomainsEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ struct netr_DomainTrustList *dom_trust_list /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct netr_NetrEnumerateTrustedDomainsEx r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NetrEnumerateTrustedDomainsEx, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_NETRENUMERATETRUSTEDDOMAINSEX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NetrEnumerateTrustedDomainsEx, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *dom_trust_list = *r.out.dom_trust_list;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_DsRAddressToSitenamesExW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t count /* [in] [range(0,32000)] */,
+ struct netr_DsRAddress *addresses /* [in] [ref,size_is(count)] */,
+ struct netr_DsRAddressToSitenamesExWCtr **ctr /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct netr_DsRAddressToSitenamesExW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.count = count;
+ r.in.addresses = addresses;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsRAddressToSitenamesExW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_DSRADDRESSTOSITENAMESEXW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsRAddressToSitenamesExW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *ctr = *r.out.ctr;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_DsrGetDcSiteCoverageW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ struct DcSitesCtr *ctr /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct netr_DsrGetDcSiteCoverageW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsrGetDcSiteCoverageW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_DSRGETDCSITECOVERAGEW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsrGetDcSiteCoverageW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *ctr = *r.out.ctr;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_LogonSamLogonEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *computer_name /* [in] [unique,charset(UTF16)] */,
+ enum netr_LogonLevel logon_level /* [in] */,
+ union netr_LogonInfo *logon /* [in] [ref,switch_is(logon_level)] */,
+ uint16_t validation_level /* [in] */,
+ union netr_Validation *validation /* [out] [ref,switch_is(validation_level)] */,
+ uint8_t *authoritative /* [out] [ref] */,
+ uint32_t *flags /* [in,out] [ref] */)
+{
+ struct netr_LogonSamLogonEx r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.computer_name = computer_name;
+ r.in.logon_level = logon_level;
+ r.in.logon = logon;
+ r.in.validation_level = validation_level;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonSamLogonEx, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_LOGONSAMLOGONEX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonSamLogonEx, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *validation = *r.out.validation;
+ *authoritative = *r.out.authoritative;
+ *flags = *r.out.flags;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_DsrEnumerateDomainTrusts(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t trust_flags /* [in] */,
+ struct netr_DomainTrustList *trusts /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct netr_DsrEnumerateDomainTrusts r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.trust_flags = trust_flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsrEnumerateDomainTrusts, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_DSRENUMERATEDOMAINTRUSTS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsrEnumerateDomainTrusts, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *trusts = *r.out.trusts;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_DsrDeregisterDNSHostRecords(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *domain /* [in] [unique,charset(UTF16)] */,
+ struct GUID *domain_guid /* [in] [unique] */,
+ struct GUID *dsa_guid /* [in] [unique] */,
+ const char *dns_host /* [in] [ref,charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct netr_DsrDeregisterDNSHostRecords r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.domain = domain;
+ r.in.domain_guid = domain_guid;
+ r.in.dsa_guid = dsa_guid;
+ r.in.dns_host = dns_host;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsrDeregisterDNSHostRecords, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_DSRDEREGISTERDNSHOSTRECORDS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsrDeregisterDNSHostRecords, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_ServerTrustPasswordsGet(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ enum netr_SchannelType secure_channel_type /* [in] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [ref] */,
+ struct netr_Authenticator *return_authenticator /* [out] [ref] */,
+ struct samr_Password *password /* [out] [ref] */,
+ struct samr_Password *password2 /* [out] [ref] */)
+{
+ struct netr_ServerTrustPasswordsGet r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.account_name = account_name;
+ r.in.secure_channel_type = secure_channel_type;
+ r.in.computer_name = computer_name;
+ r.in.credential = credential;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_ServerTrustPasswordsGet, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_SERVERTRUSTPASSWORDSGET,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_ServerTrustPasswordsGet, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *return_authenticator = *r.out.return_authenticator;
+ *password = *r.out.password;
+ *password2 = *r.out.password2;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_DsRGetForestTrustInformation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *trusted_domain_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ struct lsa_ForestTrustInformation **forest_trust_info /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct netr_DsRGetForestTrustInformation r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.trusted_domain_name = trusted_domain_name;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsRGetForestTrustInformation, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_DSRGETFORESTTRUSTINFORMATION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsRGetForestTrustInformation, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *forest_trust_info = *r.out.forest_trust_info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_GetForestTrustInformation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *trusted_domain_name /* [in] [ref,charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [ref] */,
+ struct netr_Authenticator *return_authenticator /* [out] [ref] */,
+ uint32_t flags /* [in] */,
+ struct lsa_ForestTrustInformation **forest_trust_info /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct netr_GetForestTrustInformation r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.trusted_domain_name = trusted_domain_name;
+ r.in.credential = credential;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_GetForestTrustInformation, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_GETFORESTTRUSTINFORMATION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_GetForestTrustInformation, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *return_authenticator = *r.out.return_authenticator;
+ *forest_trust_info = *r.out.forest_trust_info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_netr_LogonSamLogonWithFlags(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *computer_name /* [in] [unique,charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [unique] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [unique] */,
+ enum netr_LogonLevel logon_level /* [in] */,
+ union netr_LogonInfo logon /* [in] [switch_is(logon_level)] */,
+ uint16_t validation_level /* [in] */,
+ union netr_Validation *validation /* [out] [ref,switch_is(validation_level)] */,
+ uint8_t *authoritative /* [out] [ref] */,
+ uint32_t *flags /* [in,out] [ref] */)
+{
+ struct netr_LogonSamLogonWithFlags r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.computer_name = computer_name;
+ r.in.credential = credential;
+ r.in.return_authenticator = return_authenticator;
+ r.in.logon_level = logon_level;
+ r.in.logon = logon;
+ r.in.validation_level = validation_level;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonSamLogonWithFlags, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_LOGONSAMLOGONWITHFLAGS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonSamLogonWithFlags, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (return_authenticator && r.out.return_authenticator) {
+ *return_authenticator = *r.out.return_authenticator;
+ }
+ *validation = *r.out.validation;
+ *authoritative = *r.out.authoritative;
+ *flags = *r.out.flags;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_netr_NETRSERVERGETTRUSTINFO(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct netr_NETRSERVERGETTRUSTINFO r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NETRSERVERGETTRUSTINFO, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_netlogon,
+ NDR_NETR_NETRSERVERGETTRUSTINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NETRSERVERGETTRUSTINFO, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
diff --git a/source3/librpc/gen_ndr/cli_netlogon.h b/source3/librpc/gen_ndr/cli_netlogon.h
new file mode 100644
index 0000000000..2033315a5d
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_netlogon.h
@@ -0,0 +1,361 @@
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#ifndef __CLI_NETLOGON__
+#define __CLI_NETLOGON__
+NTSTATUS rpccli_netr_LogonUasLogon(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ const char *workstation /* [in] [charset(UTF16)] */,
+ struct netr_UasInfo *info /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_LogonUasLogoff(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ const char *workstation /* [in] [charset(UTF16)] */,
+ struct netr_UasLogoffInfo *info /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_LogonSamLogon(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *computer_name /* [in] [unique,charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [unique] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [unique] */,
+ enum netr_LogonLevel logon_level /* [in] */,
+ union netr_LogonInfo *logon /* [in] [ref,switch_is(logon_level)] */,
+ uint16_t validation_level /* [in] */,
+ union netr_Validation *validation /* [out] [ref,switch_is(validation_level)] */,
+ uint8_t *authoritative /* [out] [ref] */);
+NTSTATUS rpccli_netr_LogonSamLogoff(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *computer_name /* [in] [unique,charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [unique] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [unique] */,
+ enum netr_LogonLevel logon_level /* [in] */,
+ union netr_LogonInfo logon /* [in] [switch_is(logon_level)] */);
+NTSTATUS rpccli_netr_ServerReqChallenge(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ struct netr_Credential *credentials /* [in] [ref] */,
+ struct netr_Credential *return_credentials /* [out] [ref] */);
+NTSTATUS rpccli_netr_ServerAuthenticate(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ enum netr_SchannelType secure_channel_type /* [in] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ struct netr_Credential *credentials /* [in] [ref] */,
+ struct netr_Credential *return_credentials /* [out] [ref] */);
+NTSTATUS rpccli_netr_ServerPasswordSet(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ enum netr_SchannelType secure_channel_type /* [in] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [ref] */,
+ struct netr_Authenticator *return_authenticator /* [out] [ref] */,
+ struct samr_Password *new_password /* [in] [ref] */);
+NTSTATUS rpccli_netr_DatabaseDeltas(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [charset(UTF16)] */,
+ const char *computername /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [ref] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [ref] */,
+ enum netr_SamDatabaseID database_id /* [in] */,
+ uint64_t *sequence_num /* [in,out] [ref] */,
+ struct netr_DELTA_ENUM_ARRAY **delta_enum_array /* [out] [ref] */,
+ uint32_t preferredmaximumlength /* [in] */);
+NTSTATUS rpccli_netr_DatabaseSync(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [charset(UTF16)] */,
+ const char *computername /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator credential /* [in] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [ref] */,
+ enum netr_SamDatabaseID database_id /* [in] */,
+ uint32_t *sync_context /* [in,out] [ref] */,
+ uint32_t preferredmaximumlength /* [in] */,
+ struct netr_DELTA_ENUM_ARRAY *delta_enum_array /* [out] [ref] */);
+NTSTATUS rpccli_netr_AccountDeltas(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [unique,charset(UTF16)] */,
+ const char *computername /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator credential /* [in] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [ref] */,
+ struct netr_UAS_INFO_0 uas /* [in] */,
+ uint32_t count /* [in] */,
+ uint32_t level /* [in] */,
+ uint32_t buffersize /* [in] */,
+ struct netr_AccountBuffer *buffer /* [out] [ref,subcontext(4)] */,
+ uint32_t *count_returned /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ struct netr_UAS_INFO_0 *recordid /* [out] [ref] */);
+NTSTATUS rpccli_netr_AccountSync(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [unique,charset(UTF16)] */,
+ const char *computername /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator credential /* [in] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [ref] */,
+ uint32_t reference /* [in] */,
+ uint32_t level /* [in] */,
+ uint32_t buffersize /* [in] */,
+ struct netr_AccountBuffer *buffer /* [out] [ref,subcontext(4)] */,
+ uint32_t *count_returned /* [out] [ref] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *next_reference /* [out] [ref] */,
+ struct netr_UAS_INFO_0 *recordid /* [in,out] [ref] */);
+NTSTATUS rpccli_netr_GetDcName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [charset(UTF16)] */,
+ const char *domainname /* [in] [unique,charset(UTF16)] */,
+ const char **dcname /* [out] [ref,charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_LogonControl(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [unique,charset(UTF16)] */,
+ enum netr_LogonControlCode function_code /* [in] */,
+ uint32_t level /* [in] */,
+ union netr_CONTROL_QUERY_INFORMATION *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_GetAnyDCName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [unique,charset(UTF16)] */,
+ const char *domainname /* [in] [unique,charset(UTF16)] */,
+ const char **dcname /* [out] [ref,charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_LogonControl2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [unique,charset(UTF16)] */,
+ enum netr_LogonControlCode function_code /* [in] */,
+ uint32_t level /* [in] */,
+ union netr_CONTROL_DATA_INFORMATION *data /* [in] [ref,switch_is(function_code)] */,
+ union netr_CONTROL_QUERY_INFORMATION *query /* [out] [ref,switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_ServerAuthenticate2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ enum netr_SchannelType secure_channel_type /* [in] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ struct netr_Credential *credentials /* [in] [ref] */,
+ struct netr_Credential *return_credentials /* [out] [ref] */,
+ uint32_t *negotiate_flags /* [in,out] [ref] */);
+NTSTATUS rpccli_netr_DatabaseSync2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [charset(UTF16)] */,
+ const char *computername /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [ref] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [ref] */,
+ enum netr_SamDatabaseID database_id /* [in] */,
+ uint16_t restart_state /* [in] */,
+ uint32_t *sync_context /* [in,out] [ref] */,
+ struct netr_DELTA_ENUM_ARRAY **delta_enum_array /* [out] [ref] */,
+ uint32_t preferredmaximumlength /* [in] */);
+NTSTATUS rpccli_netr_DatabaseRedo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [charset(UTF16)] */,
+ const char *computername /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator credential /* [in] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [ref] */,
+ uint8_t *change_log_entry /* [in] [unique,size_is(change_log_entry_size)] */,
+ uint32_t change_log_entry_size /* [in] */,
+ struct netr_DELTA_ENUM_ARRAY *delta_enum_array /* [out] [ref] */);
+NTSTATUS rpccli_netr_LogonControl2Ex(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *logon_server /* [in] [unique,charset(UTF16)] */,
+ uint32_t function_code /* [in] */,
+ uint32_t level /* [in] */,
+ union netr_CONTROL_DATA_INFORMATION data /* [in] [switch_is(function_code)] */,
+ union netr_CONTROL_QUERY_INFORMATION *query /* [out] [ref,switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_NetrEnumerateTrustedDomains(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ struct netr_Blob *trusted_domains_blob /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_DsRGetDCName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *domain_name /* [in] [unique,charset(UTF16)] */,
+ struct GUID *domain_guid /* [in] [unique] */,
+ struct GUID *site_guid /* [in] [unique] */,
+ uint32_t flags /* [in] */,
+ struct netr_DsRGetDCNameInfo **info /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_NETRLOGONDUMMYROUTINE1(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_netr_NETRLOGONSETSERVICEBITS(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_netr_LogonGetTrustRid(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *domain_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t *rid /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_NETRLOGONCOMPUTESERVERDIGEST(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_netr_NETRLOGONCOMPUTECLIENTDIGEST(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_netr_ServerAuthenticate3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ enum netr_SchannelType secure_channel_type /* [in] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ struct netr_Credential *credentials /* [in,out] [ref] */,
+ uint32_t *negotiate_flags /* [in,out] [ref] */,
+ uint32_t *rid /* [out] [ref] */);
+NTSTATUS rpccli_netr_DsRGetDCNameEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *domain_name /* [in] [unique,charset(UTF16)] */,
+ struct GUID *domain_guid /* [in] [unique] */,
+ const char *site_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ struct netr_DsRGetDCNameInfo **info /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_DsRGetSiteName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *computer_name /* [in] [unique,charset(UTF16)] */,
+ const char **site /* [out] [ref,charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_LogonGetDomainInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [charset(UTF16)] */,
+ const char *computer_name /* [in] [unique,charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [ref] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [ref] */,
+ uint32_t level /* [in] */,
+ union netr_DomainQuery query /* [in] [switch_is(level)] */,
+ union netr_DomainInfo *info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_netr_ServerPasswordSet2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ enum netr_SchannelType secure_channel_type /* [in] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [ref] */,
+ struct netr_Authenticator *return_authenticator /* [out] [ref] */,
+ struct netr_CryptPassword *new_password /* [in] [ref] */);
+NTSTATUS rpccli_netr_ServerPasswordGet(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ enum netr_SchannelType secure_channel_type /* [in] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [ref] */,
+ struct netr_Authenticator *return_authenticator /* [out] [ref] */,
+ struct samr_Password *password /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_NETRLOGONSENDTOSAM(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_netr_DsRAddressToSitenamesW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t count /* [in] [range(0,32000)] */,
+ struct netr_DsRAddress *addresses /* [in] [ref,size_is(count)] */,
+ struct netr_DsRAddressToSitenamesWCtr **ctr /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_DsRGetDCNameEx2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *client_account /* [in] [unique,charset(UTF16)] */,
+ uint32_t mask /* [in] */,
+ const char *domain_name /* [in] [unique,charset(UTF16)] */,
+ struct GUID *domain_guid /* [in] [unique] */,
+ const char *site_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ struct netr_DsRGetDCNameInfo **info /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_netr_NetrEnumerateTrustedDomainsEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ struct netr_DomainTrustList *dom_trust_list /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_DsRAddressToSitenamesExW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t count /* [in] [range(0,32000)] */,
+ struct netr_DsRAddress *addresses /* [in] [ref,size_is(count)] */,
+ struct netr_DsRAddressToSitenamesExWCtr **ctr /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_DsrGetDcSiteCoverageW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ struct DcSitesCtr *ctr /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_LogonSamLogonEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *computer_name /* [in] [unique,charset(UTF16)] */,
+ enum netr_LogonLevel logon_level /* [in] */,
+ union netr_LogonInfo *logon /* [in] [ref,switch_is(logon_level)] */,
+ uint16_t validation_level /* [in] */,
+ union netr_Validation *validation /* [out] [ref,switch_is(validation_level)] */,
+ uint8_t *authoritative /* [out] [ref] */,
+ uint32_t *flags /* [in,out] [ref] */);
+NTSTATUS rpccli_netr_DsrEnumerateDomainTrusts(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t trust_flags /* [in] */,
+ struct netr_DomainTrustList *trusts /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_DsrDeregisterDNSHostRecords(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *domain /* [in] [unique,charset(UTF16)] */,
+ struct GUID *domain_guid /* [in] [unique] */,
+ struct GUID *dsa_guid /* [in] [unique] */,
+ const char *dns_host /* [in] [ref,charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_ServerTrustPasswordsGet(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account_name /* [in] [charset(UTF16)] */,
+ enum netr_SchannelType secure_channel_type /* [in] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [ref] */,
+ struct netr_Authenticator *return_authenticator /* [out] [ref] */,
+ struct samr_Password *password /* [out] [ref] */,
+ struct samr_Password *password2 /* [out] [ref] */);
+NTSTATUS rpccli_netr_DsRGetForestTrustInformation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *trusted_domain_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ struct lsa_ForestTrustInformation **forest_trust_info /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_GetForestTrustInformation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *trusted_domain_name /* [in] [ref,charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [ref] */,
+ struct netr_Authenticator *return_authenticator /* [out] [ref] */,
+ uint32_t flags /* [in] */,
+ struct lsa_ForestTrustInformation **forest_trust_info /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_netr_LogonSamLogonWithFlags(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *computer_name /* [in] [unique,charset(UTF16)] */,
+ struct netr_Authenticator *credential /* [in] [unique] */,
+ struct netr_Authenticator *return_authenticator /* [in,out] [unique] */,
+ enum netr_LogonLevel logon_level /* [in] */,
+ union netr_LogonInfo logon /* [in] [switch_is(logon_level)] */,
+ uint16_t validation_level /* [in] */,
+ union netr_Validation *validation /* [out] [ref,switch_is(validation_level)] */,
+ uint8_t *authoritative /* [out] [ref] */,
+ uint32_t *flags /* [in,out] [ref] */);
+NTSTATUS rpccli_netr_NETRSERVERGETTRUSTINFO(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+#endif /* __CLI_NETLOGON__ */
diff --git a/source3/librpc/gen_ndr/cli_ntsvcs.c b/source3/librpc/gen_ndr/cli_ntsvcs.c
new file mode 100644
index 0000000000..bc5dba4d91
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_ntsvcs.c
@@ -0,0 +1,2735 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * client auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/cli_ntsvcs.h"
+
+NTSTATUS rpccli_PNP_Disconnect(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_Disconnect r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_Disconnect, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_DISCONNECT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_Disconnect, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_Connect(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_Connect r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_Connect, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_CONNECT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_Connect, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetVersion(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *version /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct PNP_GetVersion r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetVersion, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETVERSION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetVersion, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *version = *r.out.version;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetGlobalState(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetGlobalState r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetGlobalState, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETGLOBALSTATE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetGlobalState, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_InitDetection(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_InitDetection r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_InitDetection, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_INITDETECTION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_InitDetection, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_ReportLogOn(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_ReportLogOn r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_ReportLogOn, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_REPORTLOGON,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_ReportLogOn, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_ValidateDeviceInstance(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *devicepath /* [in] [ref,charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror)
+{
+ struct PNP_ValidateDeviceInstance r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.devicepath = devicepath;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_ValidateDeviceInstance, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_VALIDATEDEVICEINSTANCE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_ValidateDeviceInstance, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetRootDeviceInstance(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetRootDeviceInstance r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetRootDeviceInstance, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETROOTDEVICEINSTANCE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetRootDeviceInstance, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetRelatedDeviceInstance(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetRelatedDeviceInstance r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetRelatedDeviceInstance, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETRELATEDDEVICEINSTANCE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetRelatedDeviceInstance, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_EnumerateSubKeys(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_EnumerateSubKeys r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_EnumerateSubKeys, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_ENUMERATESUBKEYS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_EnumerateSubKeys, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetDeviceList(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetDeviceList r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetDeviceList, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETDEVICELIST,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetDeviceList, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetDeviceListSize(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *devicename /* [in] [unique,charset(UTF16)] */,
+ uint32_t *size /* [out] [ref] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror)
+{
+ struct PNP_GetDeviceListSize r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.devicename = devicename;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetDeviceListSize, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETDEVICELISTSIZE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetDeviceListSize, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *size = *r.out.size;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetDepth(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetDepth r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetDepth, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETDEPTH,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetDepth, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetDeviceRegProp(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *devicepath /* [in] [ref,charset(UTF16)] */,
+ uint32_t property /* [in] */,
+ uint32_t *unknown1 /* [in,out] [ref] */,
+ uint8_t *buffer /* [out] [ref,length_is(*buffer_size),size_is(*buffer_size)] */,
+ uint32_t *buffer_size /* [in,out] [ref] */,
+ uint32_t *needed /* [in,out] [ref] */,
+ uint32_t unknown3 /* [in] */,
+ WERROR *werror)
+{
+ struct PNP_GetDeviceRegProp r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.devicepath = devicepath;
+ r.in.property = property;
+ r.in.unknown1 = unknown1;
+ r.in.buffer_size = buffer_size;
+ r.in.needed = needed;
+ r.in.unknown3 = unknown3;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetDeviceRegProp, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETDEVICEREGPROP,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetDeviceRegProp, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *unknown1 = *r.out.unknown1;
+ memcpy(buffer, r.out.buffer, *r.in.buffer_size * sizeof(*buffer));
+ *buffer_size = *r.out.buffer_size;
+ *needed = *r.out.needed;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_SetDeviceRegProp(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_SetDeviceRegProp r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_SetDeviceRegProp, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_SETDEVICEREGPROP,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_SetDeviceRegProp, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetClassInstance(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetClassInstance r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetClassInstance, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETCLASSINSTANCE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetClassInstance, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_CreateKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_CreateKey r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_CreateKey, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_CREATEKEY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_CreateKey, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_DeleteRegistryKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_DeleteRegistryKey r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_DeleteRegistryKey, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_DELETEREGISTRYKEY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_DeleteRegistryKey, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetClassCount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetClassCount r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetClassCount, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETCLASSCOUNT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetClassCount, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetClassName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetClassName r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetClassName, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETCLASSNAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetClassName, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_DeleteClassKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_DeleteClassKey r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_DeleteClassKey, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_DELETECLASSKEY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_DeleteClassKey, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetInterfaceDeviceAlias(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetInterfaceDeviceAlias r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetInterfaceDeviceAlias, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETINTERFACEDEVICEALIAS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetInterfaceDeviceAlias, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetInterfaceDeviceList(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetInterfaceDeviceList r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetInterfaceDeviceList, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETINTERFACEDEVICELIST,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetInterfaceDeviceList, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetInterfaceDeviceListSize(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetInterfaceDeviceListSize r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetInterfaceDeviceListSize, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETINTERFACEDEVICELISTSIZE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetInterfaceDeviceListSize, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_RegisterDeviceClassAssociation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_RegisterDeviceClassAssociation r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_RegisterDeviceClassAssociation, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_REGISTERDEVICECLASSASSOCIATION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_RegisterDeviceClassAssociation, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_UnregisterDeviceClassAssociation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_UnregisterDeviceClassAssociation r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_UnregisterDeviceClassAssociation, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_UNREGISTERDEVICECLASSASSOCIATION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_UnregisterDeviceClassAssociation, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetClassRegProp(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetClassRegProp r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetClassRegProp, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETCLASSREGPROP,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetClassRegProp, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_SetClassRegProp(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_SetClassRegProp r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_SetClassRegProp, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_SETCLASSREGPROP,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_SetClassRegProp, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_CreateDevInst(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_CreateDevInst r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_CreateDevInst, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_CREATEDEVINST,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_CreateDevInst, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_DeviceInstanceAction(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_DeviceInstanceAction r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_DeviceInstanceAction, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_DEVICEINSTANCEACTION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_DeviceInstanceAction, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetDeviceStatus(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetDeviceStatus r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetDeviceStatus, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETDEVICESTATUS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetDeviceStatus, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_SetDeviceProblem(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_SetDeviceProblem r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_SetDeviceProblem, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_SETDEVICEPROBLEM,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_SetDeviceProblem, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_DisableDevInst(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_DisableDevInst r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_DisableDevInst, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_DISABLEDEVINST,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_DisableDevInst, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_UninstallDevInst(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_UninstallDevInst r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_UninstallDevInst, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_UNINSTALLDEVINST,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_UninstallDevInst, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_AddID(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_AddID r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_AddID, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_ADDID,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_AddID, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_RegisterDriver(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_RegisterDriver r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_RegisterDriver, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_REGISTERDRIVER,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_RegisterDriver, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_QueryRemove(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_QueryRemove r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_QueryRemove, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_QUERYREMOVE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_QueryRemove, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_RequestDeviceEject(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_RequestDeviceEject r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_RequestDeviceEject, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_REQUESTDEVICEEJECT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_RequestDeviceEject, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_IsDockStationPresent(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_IsDockStationPresent r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_IsDockStationPresent, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_ISDOCKSTATIONPRESENT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_IsDockStationPresent, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_RequestEjectPC(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_RequestEjectPC r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_RequestEjectPC, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_REQUESTEJECTPC,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_RequestEjectPC, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_HwProfFlags(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t unknown1 /* [in] */,
+ const char *devicepath /* [in] [ref,charset(UTF16)] */,
+ uint32_t unknown2 /* [in] */,
+ uint32_t *unknown3 /* [in,out] [ref] */,
+ uint16_t *unknown4 /* [in,out] [unique] */,
+ const char *unknown5 /* [in] [unique,charset(UTF16)] */,
+ const char **unknown5a /* [out] [unique,charset(UTF16)] */,
+ uint32_t unknown6 /* [in] */,
+ uint32_t unknown7 /* [in] */,
+ WERROR *werror)
+{
+ struct PNP_HwProfFlags r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.unknown1 = unknown1;
+ r.in.devicepath = devicepath;
+ r.in.unknown2 = unknown2;
+ r.in.unknown3 = unknown3;
+ r.in.unknown4 = unknown4;
+ r.in.unknown5 = unknown5;
+ r.in.unknown6 = unknown6;
+ r.in.unknown7 = unknown7;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_HwProfFlags, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_HWPROFFLAGS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_HwProfFlags, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *unknown3 = *r.out.unknown3;
+ if (unknown4 && r.out.unknown4) {
+ *unknown4 = *r.out.unknown4;
+ }
+ if (unknown5a && r.out.unknown5a) {
+ *unknown5a = *r.out.unknown5a;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetHwProfInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t idx /* [in] */,
+ struct PNP_HwProfInfo *info /* [in,out] [ref] */,
+ uint32_t unknown1 /* [in] */,
+ uint32_t unknown2 /* [in] */,
+ WERROR *werror)
+{
+ struct PNP_GetHwProfInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.idx = idx;
+ r.in.info = info;
+ r.in.unknown1 = unknown1;
+ r.in.unknown2 = unknown2;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetHwProfInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETHWPROFINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetHwProfInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_AddEmptyLogConf(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_AddEmptyLogConf r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_AddEmptyLogConf, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_ADDEMPTYLOGCONF,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_AddEmptyLogConf, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_FreeLogConf(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_FreeLogConf r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_FreeLogConf, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_FREELOGCONF,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_FreeLogConf, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetFirstLogConf(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetFirstLogConf r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetFirstLogConf, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETFIRSTLOGCONF,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetFirstLogConf, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetNextLogConf(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetNextLogConf r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetNextLogConf, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETNEXTLOGCONF,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetNextLogConf, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetLogConfPriority(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetLogConfPriority r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetLogConfPriority, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETLOGCONFPRIORITY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetLogConfPriority, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_AddResDes(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_AddResDes r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_AddResDes, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_ADDRESDES,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_AddResDes, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_FreeResDes(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_FreeResDes r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_FreeResDes, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_FREERESDES,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_FreeResDes, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetNextResDes(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetNextResDes r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetNextResDes, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETNEXTRESDES,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetNextResDes, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetResDesData(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetResDesData r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetResDesData, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETRESDESDATA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetResDesData, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetResDesDataSize(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetResDesDataSize r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetResDesDataSize, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETRESDESDATASIZE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetResDesDataSize, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_ModifyResDes(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_ModifyResDes r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_ModifyResDes, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_MODIFYRESDES,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_ModifyResDes, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_DetectResourceLimit(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_DetectResourceLimit r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_DetectResourceLimit, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_DETECTRESOURCELIMIT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_DetectResourceLimit, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_QueryResConfList(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_QueryResConfList r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_QueryResConfList, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_QUERYRESCONFLIST,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_QueryResConfList, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_SetHwProf(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_SetHwProf r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_SetHwProf, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_SETHWPROF,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_SetHwProf, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_QueryArbitratorFreeData(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_QueryArbitratorFreeData r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_QueryArbitratorFreeData, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_QUERYARBITRATORFREEDATA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_QueryArbitratorFreeData, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_QueryArbitratorFreeSize(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_QueryArbitratorFreeSize r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_QueryArbitratorFreeSize, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_QUERYARBITRATORFREESIZE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_QueryArbitratorFreeSize, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_RunDetection(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_RunDetection r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_RunDetection, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_RUNDETECTION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_RunDetection, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_RegisterNotification(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_RegisterNotification r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_RegisterNotification, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_REGISTERNOTIFICATION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_RegisterNotification, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_UnregisterNotification(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_UnregisterNotification r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_UnregisterNotification, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_UNREGISTERNOTIFICATION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_UnregisterNotification, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetCustomDevProp(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetCustomDevProp r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetCustomDevProp, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETCUSTOMDEVPROP,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetCustomDevProp, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetVersionInternal(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetVersionInternal r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetVersionInternal, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETVERSIONINTERNAL,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetVersionInternal, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetBlockedDriverInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetBlockedDriverInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetBlockedDriverInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETBLOCKEDDRIVERINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetBlockedDriverInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_PNP_GetServerSideDeviceInstallFlags(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct PNP_GetServerSideDeviceInstallFlags r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetServerSideDeviceInstallFlags, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_ntsvcs,
+ NDR_PNP_GETSERVERSIDEDEVICEINSTALLFLAGS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetServerSideDeviceInstallFlags, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
diff --git a/source3/librpc/gen_ndr/cli_ntsvcs.h b/source3/librpc/gen_ndr/cli_ntsvcs.h
new file mode 100644
index 0000000000..a52a79ecc5
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_ntsvcs.h
@@ -0,0 +1,225 @@
+#include "librpc/gen_ndr/ndr_ntsvcs.h"
+#ifndef __CLI_NTSVCS__
+#define __CLI_NTSVCS__
+NTSTATUS rpccli_PNP_Disconnect(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_Connect(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetVersion(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *version /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetGlobalState(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_InitDetection(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_ReportLogOn(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_ValidateDeviceInstance(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *devicepath /* [in] [ref,charset(UTF16)] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetRootDeviceInstance(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetRelatedDeviceInstance(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_EnumerateSubKeys(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetDeviceList(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetDeviceListSize(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *devicename /* [in] [unique,charset(UTF16)] */,
+ uint32_t *size /* [out] [ref] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetDepth(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetDeviceRegProp(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *devicepath /* [in] [ref,charset(UTF16)] */,
+ uint32_t property /* [in] */,
+ uint32_t *unknown1 /* [in,out] [ref] */,
+ uint8_t *buffer /* [out] [ref,length_is(*buffer_size),size_is(*buffer_size)] */,
+ uint32_t *buffer_size /* [in,out] [ref] */,
+ uint32_t *needed /* [in,out] [ref] */,
+ uint32_t unknown3 /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_SetDeviceRegProp(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetClassInstance(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_CreateKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_DeleteRegistryKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetClassCount(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetClassName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_DeleteClassKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetInterfaceDeviceAlias(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetInterfaceDeviceList(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetInterfaceDeviceListSize(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_RegisterDeviceClassAssociation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_UnregisterDeviceClassAssociation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetClassRegProp(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_SetClassRegProp(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_CreateDevInst(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_DeviceInstanceAction(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetDeviceStatus(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_SetDeviceProblem(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_DisableDevInst(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_UninstallDevInst(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_AddID(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_RegisterDriver(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_QueryRemove(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_RequestDeviceEject(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_IsDockStationPresent(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_RequestEjectPC(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_HwProfFlags(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t unknown1 /* [in] */,
+ const char *devicepath /* [in] [ref,charset(UTF16)] */,
+ uint32_t unknown2 /* [in] */,
+ uint32_t *unknown3 /* [in,out] [ref] */,
+ uint16_t *unknown4 /* [in,out] [unique] */,
+ const char *unknown5 /* [in] [unique,charset(UTF16)] */,
+ const char **unknown5a /* [out] [unique,charset(UTF16)] */,
+ uint32_t unknown6 /* [in] */,
+ uint32_t unknown7 /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetHwProfInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t idx /* [in] */,
+ struct PNP_HwProfInfo *info /* [in,out] [ref] */,
+ uint32_t unknown1 /* [in] */,
+ uint32_t unknown2 /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_AddEmptyLogConf(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_FreeLogConf(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetFirstLogConf(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetNextLogConf(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetLogConfPriority(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_AddResDes(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_FreeResDes(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetNextResDes(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetResDesData(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetResDesDataSize(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_ModifyResDes(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_DetectResourceLimit(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_QueryResConfList(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_SetHwProf(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_QueryArbitratorFreeData(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_QueryArbitratorFreeSize(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_RunDetection(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_RegisterNotification(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_UnregisterNotification(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetCustomDevProp(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetVersionInternal(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetBlockedDriverInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_PNP_GetServerSideDeviceInstallFlags(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+#endif /* __CLI_NTSVCS__ */
diff --git a/source3/librpc/gen_ndr/cli_samr.c b/source3/librpc/gen_ndr/cli_samr.c
new file mode 100644
index 0000000000..dc0a2dfa65
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_samr.c
@@ -0,0 +1,2962 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * client auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/cli_samr.h"
+
+NTSTATUS rpccli_samr_Connect(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *connect_handle /* [out] [ref] */)
+{
+ struct samr_Connect r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_Connect, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_CONNECT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_Connect, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *connect_handle = *r.out.connect_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_Close(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in,out] [ref] */)
+{
+ struct samr_Close r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_Close, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_CLOSE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_Close, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_SetSecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t sec_info /* [in] */,
+ struct sec_desc_buf *sdbuf /* [in] [ref] */)
+{
+ struct samr_SetSecurity r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.sec_info = sec_info;
+ r.in.sdbuf = sdbuf;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetSecurity, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_SETSECURITY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetSecurity, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_QuerySecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t sec_info /* [in] */,
+ struct sec_desc_buf **sdbuf /* [out] [ref] */)
+{
+ struct samr_QuerySecurity r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.sec_info = sec_info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QuerySecurity, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_QUERYSECURITY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QuerySecurity, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *sdbuf = *r.out.sdbuf;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_Shutdown(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *connect_handle /* [in] [ref] */)
+{
+ struct samr_Shutdown r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.connect_handle = connect_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_Shutdown, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_SHUTDOWN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_Shutdown, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_LookupDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *connect_handle /* [in] [ref] */,
+ struct lsa_String *domain_name /* [in] [ref] */,
+ struct dom_sid2 **sid /* [out] [ref] */)
+{
+ struct samr_LookupDomain r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.connect_handle = connect_handle;
+ r.in.domain_name = domain_name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_LookupDomain, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_LOOKUPDOMAIN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_LookupDomain, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *sid = *r.out.sid;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_EnumDomains(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *connect_handle /* [in] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */,
+ struct samr_SamArray **sam /* [out] [ref] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *num_entries /* [out] [ref] */)
+{
+ struct samr_EnumDomains r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.connect_handle = connect_handle;
+ r.in.resume_handle = resume_handle;
+ r.in.buf_size = buf_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_EnumDomains, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_ENUMDOMAINS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_EnumDomains, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *resume_handle = *r.out.resume_handle;
+ *sam = *r.out.sam;
+ *num_entries = *r.out.num_entries;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_OpenDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *connect_handle /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct dom_sid2 *sid /* [in] [ref] */,
+ struct policy_handle *domain_handle /* [out] [ref] */)
+{
+ struct samr_OpenDomain r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.connect_handle = connect_handle;
+ r.in.access_mask = access_mask;
+ r.in.sid = sid;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_OpenDomain, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_OPENDOMAIN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_OpenDomain, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *domain_handle = *r.out.domain_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_QueryDomainInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union samr_DomainInfo **info /* [out] [ref,switch_is(level)] */)
+{
+ struct samr_QueryDomainInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryDomainInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_QUERYDOMAININFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryDomainInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_SetDomainInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union samr_DomainInfo *info /* [in] [ref,switch_is(level)] */)
+{
+ struct samr_SetDomainInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.level = level;
+ r.in.info = info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetDomainInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_SETDOMAININFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetDomainInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_CreateDomainGroup(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ struct lsa_String *name /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *group_handle /* [out] [ref] */,
+ uint32_t *rid /* [out] [ref] */)
+{
+ struct samr_CreateDomainGroup r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.name = name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_CreateDomainGroup, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_CREATEDOMAINGROUP,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_CreateDomainGroup, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *group_handle = *r.out.group_handle;
+ *rid = *r.out.rid;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_EnumDomainGroups(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */,
+ struct samr_SamArray **sam /* [out] [ref] */,
+ uint32_t max_size /* [in] */,
+ uint32_t *num_entries /* [out] [ref] */)
+{
+ struct samr_EnumDomainGroups r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.resume_handle = resume_handle;
+ r.in.max_size = max_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_EnumDomainGroups, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_ENUMDOMAINGROUPS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_EnumDomainGroups, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *resume_handle = *r.out.resume_handle;
+ *sam = *r.out.sam;
+ *num_entries = *r.out.num_entries;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_CreateUser(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ struct lsa_String *account_name /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *user_handle /* [out] [ref] */,
+ uint32_t *rid /* [out] [ref] */)
+{
+ struct samr_CreateUser r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.account_name = account_name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_CreateUser, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_CREATEUSER,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_CreateUser, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *user_handle = *r.out.user_handle;
+ *rid = *r.out.rid;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_EnumDomainUsers(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */,
+ uint32_t acct_flags /* [in] */,
+ struct samr_SamArray **sam /* [out] [ref] */,
+ uint32_t max_size /* [in] */,
+ uint32_t *num_entries /* [out] [ref] */)
+{
+ struct samr_EnumDomainUsers r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.resume_handle = resume_handle;
+ r.in.acct_flags = acct_flags;
+ r.in.max_size = max_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_EnumDomainUsers, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_ENUMDOMAINUSERS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_EnumDomainUsers, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *resume_handle = *r.out.resume_handle;
+ *sam = *r.out.sam;
+ *num_entries = *r.out.num_entries;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_CreateDomAlias(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ struct lsa_String *alias_name /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *alias_handle /* [out] [ref] */,
+ uint32_t *rid /* [out] [ref] */)
+{
+ struct samr_CreateDomAlias r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.alias_name = alias_name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_CreateDomAlias, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_CREATEDOMALIAS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_CreateDomAlias, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *alias_handle = *r.out.alias_handle;
+ *rid = *r.out.rid;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_EnumDomainAliases(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */,
+ struct samr_SamArray **sam /* [out] [ref] */,
+ uint32_t max_size /* [in] */,
+ uint32_t *num_entries /* [out] [ref] */)
+{
+ struct samr_EnumDomainAliases r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.resume_handle = resume_handle;
+ r.in.max_size = max_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_EnumDomainAliases, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_ENUMDOMAINALIASES,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_EnumDomainAliases, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *resume_handle = *r.out.resume_handle;
+ *sam = *r.out.sam;
+ *num_entries = *r.out.num_entries;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_GetAliasMembership(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ struct lsa_SidArray *sids /* [in] [ref] */,
+ struct samr_Ids *rids /* [out] [ref] */)
+{
+ struct samr_GetAliasMembership r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.sids = sids;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_GetAliasMembership, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_GETALIASMEMBERSHIP,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_GetAliasMembership, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *rids = *r.out.rids;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_LookupNames(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t num_names /* [in] [range(0,1000)] */,
+ struct lsa_String *names /* [in] [length_is(num_names),size_is(1000)] */,
+ struct samr_Ids *rids /* [out] [ref] */,
+ struct samr_Ids *types /* [out] [ref] */)
+{
+ struct samr_LookupNames r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.num_names = num_names;
+ r.in.names = names;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_LookupNames, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_LOOKUPNAMES,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_LookupNames, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *rids = *r.out.rids;
+ *types = *r.out.types;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_LookupRids(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t num_rids /* [in] [range(0,1000)] */,
+ uint32_t *rids /* [in] [length_is(num_rids),size_is(1000)] */,
+ struct lsa_Strings *names /* [out] [ref] */,
+ struct samr_Ids *types /* [out] [ref] */)
+{
+ struct samr_LookupRids r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.num_rids = num_rids;
+ r.in.rids = rids;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_LookupRids, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_LOOKUPRIDS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_LookupRids, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *names = *r.out.names;
+ *types = *r.out.types;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_OpenGroup(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ uint32_t rid /* [in] */,
+ struct policy_handle *group_handle /* [out] [ref] */)
+{
+ struct samr_OpenGroup r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.access_mask = access_mask;
+ r.in.rid = rid;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_OpenGroup, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_OPENGROUP,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_OpenGroup, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *group_handle = *r.out.group_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_QueryGroupInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *group_handle /* [in] [ref] */,
+ enum samr_GroupInfoEnum level /* [in] */,
+ union samr_GroupInfo **info /* [out] [ref,switch_is(level)] */)
+{
+ struct samr_QueryGroupInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.group_handle = group_handle;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryGroupInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_QUERYGROUPINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryGroupInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_SetGroupInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *group_handle /* [in] [ref] */,
+ enum samr_GroupInfoEnum level /* [in] */,
+ union samr_GroupInfo *info /* [in] [ref,switch_is(level)] */)
+{
+ struct samr_SetGroupInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.group_handle = group_handle;
+ r.in.level = level;
+ r.in.info = info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetGroupInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_SETGROUPINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetGroupInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_AddGroupMember(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *group_handle /* [in] [ref] */,
+ uint32_t rid /* [in] */,
+ uint32_t flags /* [in] */)
+{
+ struct samr_AddGroupMember r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.group_handle = group_handle;
+ r.in.rid = rid;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_AddGroupMember, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_ADDGROUPMEMBER,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_AddGroupMember, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_DeleteDomainGroup(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *group_handle /* [in,out] [ref] */)
+{
+ struct samr_DeleteDomainGroup r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.group_handle = group_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_DeleteDomainGroup, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_DELETEDOMAINGROUP,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_DeleteDomainGroup, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *group_handle = *r.out.group_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_DeleteGroupMember(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *group_handle /* [in] [ref] */,
+ uint32_t rid /* [in] */)
+{
+ struct samr_DeleteGroupMember r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.group_handle = group_handle;
+ r.in.rid = rid;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_DeleteGroupMember, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_DELETEGROUPMEMBER,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_DeleteGroupMember, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_QueryGroupMember(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *group_handle /* [in] [ref] */,
+ struct samr_RidTypeArray **rids /* [out] [ref] */)
+{
+ struct samr_QueryGroupMember r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.group_handle = group_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryGroupMember, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_QUERYGROUPMEMBER,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryGroupMember, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *rids = *r.out.rids;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_SetMemberAttributesOfGroup(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *group_handle /* [in] [ref] */,
+ uint32_t unknown1 /* [in] */,
+ uint32_t unknown2 /* [in] */)
+{
+ struct samr_SetMemberAttributesOfGroup r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.group_handle = group_handle;
+ r.in.unknown1 = unknown1;
+ r.in.unknown2 = unknown2;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetMemberAttributesOfGroup, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_SETMEMBERATTRIBUTESOFGROUP,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetMemberAttributesOfGroup, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_OpenAlias(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ uint32_t rid /* [in] */,
+ struct policy_handle *alias_handle /* [out] [ref] */)
+{
+ struct samr_OpenAlias r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.access_mask = access_mask;
+ r.in.rid = rid;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_OpenAlias, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_OPENALIAS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_OpenAlias, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *alias_handle = *r.out.alias_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_QueryAliasInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *alias_handle /* [in] [ref] */,
+ enum samr_AliasInfoEnum level /* [in] */,
+ union samr_AliasInfo **info /* [out] [ref,switch_is(level)] */)
+{
+ struct samr_QueryAliasInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.alias_handle = alias_handle;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryAliasInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_QUERYALIASINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryAliasInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_SetAliasInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *alias_handle /* [in] [ref] */,
+ enum samr_AliasInfoEnum level /* [in] */,
+ union samr_AliasInfo *info /* [in] [ref,switch_is(level)] */)
+{
+ struct samr_SetAliasInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.alias_handle = alias_handle;
+ r.in.level = level;
+ r.in.info = info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetAliasInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_SETALIASINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetAliasInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_DeleteDomAlias(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *alias_handle /* [in,out] [ref] */)
+{
+ struct samr_DeleteDomAlias r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.alias_handle = alias_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_DeleteDomAlias, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_DELETEDOMALIAS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_DeleteDomAlias, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *alias_handle = *r.out.alias_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_AddAliasMember(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *alias_handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */)
+{
+ struct samr_AddAliasMember r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.alias_handle = alias_handle;
+ r.in.sid = sid;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_AddAliasMember, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_ADDALIASMEMBER,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_AddAliasMember, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_DeleteAliasMember(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *alias_handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */)
+{
+ struct samr_DeleteAliasMember r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.alias_handle = alias_handle;
+ r.in.sid = sid;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_DeleteAliasMember, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_DELETEALIASMEMBER,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_DeleteAliasMember, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_GetMembersInAlias(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *alias_handle /* [in] [ref] */,
+ struct lsa_SidArray *sids /* [out] [ref] */)
+{
+ struct samr_GetMembersInAlias r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.alias_handle = alias_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_GetMembersInAlias, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_GETMEMBERSINALIAS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_GetMembersInAlias, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *sids = *r.out.sids;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_OpenUser(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ uint32_t rid /* [in] */,
+ struct policy_handle *user_handle /* [out] [ref] */)
+{
+ struct samr_OpenUser r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.access_mask = access_mask;
+ r.in.rid = rid;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_OpenUser, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_OPENUSER,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_OpenUser, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *user_handle = *r.out.user_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_DeleteUser(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in,out] [ref] */)
+{
+ struct samr_DeleteUser r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.user_handle = user_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_DeleteUser, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_DELETEUSER,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_DeleteUser, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *user_handle = *r.out.user_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_QueryUserInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union samr_UserInfo **info /* [out] [ref,switch_is(level)] */)
+{
+ struct samr_QueryUserInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.user_handle = user_handle;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryUserInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_QUERYUSERINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryUserInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_SetUserInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union samr_UserInfo *info /* [in] [ref,switch_is(level)] */)
+{
+ struct samr_SetUserInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.user_handle = user_handle;
+ r.in.level = level;
+ r.in.info = info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetUserInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_SETUSERINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetUserInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_ChangePasswordUser(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in] [ref] */,
+ uint8_t lm_present /* [in] */,
+ struct samr_Password *old_lm_crypted /* [in] [unique] */,
+ struct samr_Password *new_lm_crypted /* [in] [unique] */,
+ uint8_t nt_present /* [in] */,
+ struct samr_Password *old_nt_crypted /* [in] [unique] */,
+ struct samr_Password *new_nt_crypted /* [in] [unique] */,
+ uint8_t cross1_present /* [in] */,
+ struct samr_Password *nt_cross /* [in] [unique] */,
+ uint8_t cross2_present /* [in] */,
+ struct samr_Password *lm_cross /* [in] [unique] */)
+{
+ struct samr_ChangePasswordUser r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.user_handle = user_handle;
+ r.in.lm_present = lm_present;
+ r.in.old_lm_crypted = old_lm_crypted;
+ r.in.new_lm_crypted = new_lm_crypted;
+ r.in.nt_present = nt_present;
+ r.in.old_nt_crypted = old_nt_crypted;
+ r.in.new_nt_crypted = new_nt_crypted;
+ r.in.cross1_present = cross1_present;
+ r.in.nt_cross = nt_cross;
+ r.in.cross2_present = cross2_present;
+ r.in.lm_cross = lm_cross;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_ChangePasswordUser, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_CHANGEPASSWORDUSER,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_ChangePasswordUser, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_GetGroupsForUser(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in] [ref] */,
+ struct samr_RidWithAttributeArray **rids /* [out] [ref] */)
+{
+ struct samr_GetGroupsForUser r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.user_handle = user_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_GetGroupsForUser, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_GETGROUPSFORUSER,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_GetGroupsForUser, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *rids = *r.out.rids;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_QueryDisplayInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ uint32_t start_idx /* [in] */,
+ uint32_t max_entries /* [in] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *total_size /* [out] [ref] */,
+ uint32_t *returned_size /* [out] [ref] */,
+ union samr_DispInfo *info /* [out] [ref,switch_is(level)] */)
+{
+ struct samr_QueryDisplayInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.level = level;
+ r.in.start_idx = start_idx;
+ r.in.max_entries = max_entries;
+ r.in.buf_size = buf_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryDisplayInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_QUERYDISPLAYINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryDisplayInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *total_size = *r.out.total_size;
+ *returned_size = *r.out.returned_size;
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_GetDisplayEnumerationIndex(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ struct lsa_String *name /* [in] [ref] */,
+ uint32_t *idx /* [out] [ref] */)
+{
+ struct samr_GetDisplayEnumerationIndex r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.level = level;
+ r.in.name = name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_GetDisplayEnumerationIndex, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_GETDISPLAYENUMERATIONINDEX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_GetDisplayEnumerationIndex, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *idx = *r.out.idx;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_TestPrivateFunctionsDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */)
+{
+ struct samr_TestPrivateFunctionsDomain r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_TestPrivateFunctionsDomain, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_TESTPRIVATEFUNCTIONSDOMAIN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_TestPrivateFunctionsDomain, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_TestPrivateFunctionsUser(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in] [ref] */)
+{
+ struct samr_TestPrivateFunctionsUser r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.user_handle = user_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_TestPrivateFunctionsUser, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_TESTPRIVATEFUNCTIONSUSER,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_TestPrivateFunctionsUser, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_GetUserPwInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in] [ref] */,
+ struct samr_PwInfo *info /* [out] [ref] */)
+{
+ struct samr_GetUserPwInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.user_handle = user_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_GetUserPwInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_GETUSERPWINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_GetUserPwInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_RemoveMemberFromForeignDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */)
+{
+ struct samr_RemoveMemberFromForeignDomain r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.sid = sid;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_RemoveMemberFromForeignDomain, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_REMOVEMEMBERFROMFOREIGNDOMAIN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_RemoveMemberFromForeignDomain, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_QueryDomainInfo2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union samr_DomainInfo **info /* [out] [ref,switch_is(level)] */)
+{
+ struct samr_QueryDomainInfo2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryDomainInfo2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_QUERYDOMAININFO2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryDomainInfo2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_QueryUserInfo2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union samr_UserInfo *info /* [out] [ref,switch_is(level)] */)
+{
+ struct samr_QueryUserInfo2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.user_handle = user_handle;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryUserInfo2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_QUERYUSERINFO2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryUserInfo2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_QueryDisplayInfo2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ uint32_t start_idx /* [in] */,
+ uint32_t max_entries /* [in] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *total_size /* [out] [ref] */,
+ uint32_t *returned_size /* [out] [ref] */,
+ union samr_DispInfo *info /* [out] [ref,switch_is(level)] */)
+{
+ struct samr_QueryDisplayInfo2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.level = level;
+ r.in.start_idx = start_idx;
+ r.in.max_entries = max_entries;
+ r.in.buf_size = buf_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryDisplayInfo2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_QUERYDISPLAYINFO2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryDisplayInfo2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *total_size = *r.out.total_size;
+ *returned_size = *r.out.returned_size;
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_GetDisplayEnumerationIndex2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ struct lsa_String *name /* [in] [ref] */,
+ uint32_t *idx /* [out] [ref] */)
+{
+ struct samr_GetDisplayEnumerationIndex2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.level = level;
+ r.in.name = name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_GetDisplayEnumerationIndex2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_GETDISPLAYENUMERATIONINDEX2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_GetDisplayEnumerationIndex2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *idx = *r.out.idx;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_CreateUser2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ struct lsa_String *account_name /* [in] [ref] */,
+ uint32_t acct_flags /* [in] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *user_handle /* [out] [ref] */,
+ uint32_t *access_granted /* [out] [ref] */,
+ uint32_t *rid /* [out] [ref] */)
+{
+ struct samr_CreateUser2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.account_name = account_name;
+ r.in.acct_flags = acct_flags;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_CreateUser2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_CREATEUSER2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_CreateUser2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *user_handle = *r.out.user_handle;
+ *access_granted = *r.out.access_granted;
+ *rid = *r.out.rid;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_QueryDisplayInfo3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ uint32_t start_idx /* [in] */,
+ uint32_t max_entries /* [in] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *total_size /* [out] [ref] */,
+ uint32_t *returned_size /* [out] [ref] */,
+ union samr_DispInfo *info /* [out] [ref,switch_is(level)] */)
+{
+ struct samr_QueryDisplayInfo3 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.level = level;
+ r.in.start_idx = start_idx;
+ r.in.max_entries = max_entries;
+ r.in.buf_size = buf_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryDisplayInfo3, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_QUERYDISPLAYINFO3,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryDisplayInfo3, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *total_size = *r.out.total_size;
+ *returned_size = *r.out.returned_size;
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_AddMultipleMembersToAlias(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *alias_handle /* [in] [ref] */,
+ struct lsa_SidArray *sids /* [in] [ref] */)
+{
+ struct samr_AddMultipleMembersToAlias r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.alias_handle = alias_handle;
+ r.in.sids = sids;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_AddMultipleMembersToAlias, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_ADDMULTIPLEMEMBERSTOALIAS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_AddMultipleMembersToAlias, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_RemoveMultipleMembersFromAlias(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *alias_handle /* [in] [ref] */,
+ struct lsa_SidArray *sids /* [in] [ref] */)
+{
+ struct samr_RemoveMultipleMembersFromAlias r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.alias_handle = alias_handle;
+ r.in.sids = sids;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_RemoveMultipleMembersFromAlias, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_REMOVEMULTIPLEMEMBERSFROMALIAS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_RemoveMultipleMembersFromAlias, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_OemChangePasswordUser2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_AsciiString *server /* [in] [unique] */,
+ struct lsa_AsciiString *account /* [in] [ref] */,
+ struct samr_CryptPassword *password /* [in] [unique] */,
+ struct samr_Password *hash /* [in] [unique] */)
+{
+ struct samr_OemChangePasswordUser2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server = server;
+ r.in.account = account;
+ r.in.password = password;
+ r.in.hash = hash;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_OemChangePasswordUser2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_OEMCHANGEPASSWORDUSER2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_OemChangePasswordUser2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_ChangePasswordUser2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_String *server /* [in] [unique] */,
+ struct lsa_String *account /* [in] [ref] */,
+ struct samr_CryptPassword *nt_password /* [in] [unique] */,
+ struct samr_Password *nt_verifier /* [in] [unique] */,
+ uint8_t lm_change /* [in] */,
+ struct samr_CryptPassword *lm_password /* [in] [unique] */,
+ struct samr_Password *lm_verifier /* [in] [unique] */)
+{
+ struct samr_ChangePasswordUser2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server = server;
+ r.in.account = account;
+ r.in.nt_password = nt_password;
+ r.in.nt_verifier = nt_verifier;
+ r.in.lm_change = lm_change;
+ r.in.lm_password = lm_password;
+ r.in.lm_verifier = lm_verifier;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_ChangePasswordUser2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_CHANGEPASSWORDUSER2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_ChangePasswordUser2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_GetDomPwInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_String *domain_name /* [in] [unique] */,
+ struct samr_PwInfo *info /* [out] [ref] */)
+{
+ struct samr_GetDomPwInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_name = domain_name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_GetDomPwInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_GETDOMPWINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_GetDomPwInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_Connect2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *system_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *connect_handle /* [out] [ref] */)
+{
+ struct samr_Connect2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_Connect2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_CONNECT2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_Connect2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *connect_handle = *r.out.connect_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_SetUserInfo2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union samr_UserInfo *info /* [in] [ref,switch_is(level)] */)
+{
+ struct samr_SetUserInfo2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.user_handle = user_handle;
+ r.in.level = level;
+ r.in.info = info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetUserInfo2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_SETUSERINFO2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetUserInfo2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_SetBootKeyInformation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *connect_handle /* [in] [ref] */,
+ uint32_t unknown1 /* [in] */,
+ uint32_t unknown2 /* [in] */,
+ uint32_t unknown3 /* [in] */)
+{
+ struct samr_SetBootKeyInformation r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.connect_handle = connect_handle;
+ r.in.unknown1 = unknown1;
+ r.in.unknown2 = unknown2;
+ r.in.unknown3 = unknown3;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetBootKeyInformation, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_SETBOOTKEYINFORMATION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetBootKeyInformation, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_GetBootKeyInformation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t *unknown /* [out] [ref] */)
+{
+ struct samr_GetBootKeyInformation r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_GetBootKeyInformation, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_GETBOOTKEYINFORMATION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_GetBootKeyInformation, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *unknown = *r.out.unknown;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_Connect3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *system_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t unknown /* [in] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *connect_handle /* [out] [ref] */)
+{
+ struct samr_Connect3 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.unknown = unknown;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_Connect3, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_CONNECT3,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_Connect3, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *connect_handle = *r.out.connect_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_Connect4(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *system_name /* [in] [unique,charset(UTF16)] */,
+ enum samr_ConnectVersion client_version /* [in] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *connect_handle /* [out] [ref] */)
+{
+ struct samr_Connect4 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.client_version = client_version;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_Connect4, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_CONNECT4,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_Connect4, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *connect_handle = *r.out.connect_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_ChangePasswordUser3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_String *server /* [in] [unique] */,
+ struct lsa_String *account /* [in] [ref] */,
+ struct samr_CryptPassword *nt_password /* [in] [unique] */,
+ struct samr_Password *nt_verifier /* [in] [unique] */,
+ uint8_t lm_change /* [in] */,
+ struct samr_CryptPassword *lm_password /* [in] [unique] */,
+ struct samr_Password *lm_verifier /* [in] [unique] */,
+ struct samr_CryptPassword *password3 /* [in] [unique] */,
+ struct samr_DomInfo1 **dominfo /* [out] [ref] */,
+ struct samr_ChangeReject **reject /* [out] [ref] */)
+{
+ struct samr_ChangePasswordUser3 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server = server;
+ r.in.account = account;
+ r.in.nt_password = nt_password;
+ r.in.nt_verifier = nt_verifier;
+ r.in.lm_change = lm_change;
+ r.in.lm_password = lm_password;
+ r.in.lm_verifier = lm_verifier;
+ r.in.password3 = password3;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_ChangePasswordUser3, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_CHANGEPASSWORDUSER3,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_ChangePasswordUser3, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *dominfo = *r.out.dominfo;
+ *reject = *r.out.reject;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_Connect5(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *system_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t access_mask /* [in] */,
+ uint32_t level_in /* [in] */,
+ union samr_ConnectInfo *info_in /* [in] [ref,switch_is(level_in)] */,
+ uint32_t *level_out /* [out] [ref] */,
+ union samr_ConnectInfo *info_out /* [out] [ref,switch_is(*level_out)] */,
+ struct policy_handle *connect_handle /* [out] [ref] */)
+{
+ struct samr_Connect5 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.access_mask = access_mask;
+ r.in.level_in = level_in;
+ r.in.info_in = info_in;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_Connect5, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_CONNECT5,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_Connect5, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *level_out = *r.out.level_out;
+ *info_out = *r.out.info_out;
+ *connect_handle = *r.out.connect_handle;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_RidToSid(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t rid /* [in] */,
+ struct dom_sid2 *sid /* [out] [ref] */)
+{
+ struct samr_RidToSid r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_handle = domain_handle;
+ r.in.rid = rid;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_RidToSid, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_RIDTOSID,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_RidToSid, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *sid = *r.out.sid;
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_SetDsrmPassword(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_String *name /* [in] [unique] */,
+ uint32_t unknown /* [in] */,
+ struct samr_Password *hash /* [in] [unique] */)
+{
+ struct samr_SetDsrmPassword r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.name = name;
+ r.in.unknown = unknown;
+ r.in.hash = hash;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetDsrmPassword, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_SETDSRMPASSWORD,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetDsrmPassword, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ return r.out.result;
+}
+
+NTSTATUS rpccli_samr_ValidatePassword(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ enum samr_ValidatePasswordLevel level /* [in] */,
+ union samr_ValidatePasswordReq req /* [in] [switch_is(level)] */,
+ union samr_ValidatePasswordRep *rep /* [out] [ref,switch_is(level)] */)
+{
+ struct samr_ValidatePassword r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.level = level;
+ r.in.req = req;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_ValidatePassword, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_samr,
+ NDR_SAMR_VALIDATEPASSWORD,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_ValidatePassword, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *rep = *r.out.rep;
+
+ /* Return result */
+ return r.out.result;
+}
+
diff --git a/source3/librpc/gen_ndr/cli_samr.h b/source3/librpc/gen_ndr/cli_samr.h
new file mode 100644
index 0000000000..4c7a30ef63
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_samr.h
@@ -0,0 +1,389 @@
+#include "librpc/gen_ndr/ndr_samr.h"
+#ifndef __CLI_SAMR__
+#define __CLI_SAMR__
+NTSTATUS rpccli_samr_Connect(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *connect_handle /* [out] [ref] */);
+NTSTATUS rpccli_samr_Close(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in,out] [ref] */);
+NTSTATUS rpccli_samr_SetSecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t sec_info /* [in] */,
+ struct sec_desc_buf *sdbuf /* [in] [ref] */);
+NTSTATUS rpccli_samr_QuerySecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t sec_info /* [in] */,
+ struct sec_desc_buf **sdbuf /* [out] [ref] */);
+NTSTATUS rpccli_samr_Shutdown(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *connect_handle /* [in] [ref] */);
+NTSTATUS rpccli_samr_LookupDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *connect_handle /* [in] [ref] */,
+ struct lsa_String *domain_name /* [in] [ref] */,
+ struct dom_sid2 **sid /* [out] [ref] */);
+NTSTATUS rpccli_samr_EnumDomains(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *connect_handle /* [in] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */,
+ struct samr_SamArray **sam /* [out] [ref] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *num_entries /* [out] [ref] */);
+NTSTATUS rpccli_samr_OpenDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *connect_handle /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct dom_sid2 *sid /* [in] [ref] */,
+ struct policy_handle *domain_handle /* [out] [ref] */);
+NTSTATUS rpccli_samr_QueryDomainInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union samr_DomainInfo **info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_samr_SetDomainInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union samr_DomainInfo *info /* [in] [ref,switch_is(level)] */);
+NTSTATUS rpccli_samr_CreateDomainGroup(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ struct lsa_String *name /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *group_handle /* [out] [ref] */,
+ uint32_t *rid /* [out] [ref] */);
+NTSTATUS rpccli_samr_EnumDomainGroups(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */,
+ struct samr_SamArray **sam /* [out] [ref] */,
+ uint32_t max_size /* [in] */,
+ uint32_t *num_entries /* [out] [ref] */);
+NTSTATUS rpccli_samr_CreateUser(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ struct lsa_String *account_name /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *user_handle /* [out] [ref] */,
+ uint32_t *rid /* [out] [ref] */);
+NTSTATUS rpccli_samr_EnumDomainUsers(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */,
+ uint32_t acct_flags /* [in] */,
+ struct samr_SamArray **sam /* [out] [ref] */,
+ uint32_t max_size /* [in] */,
+ uint32_t *num_entries /* [out] [ref] */);
+NTSTATUS rpccli_samr_CreateDomAlias(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ struct lsa_String *alias_name /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *alias_handle /* [out] [ref] */,
+ uint32_t *rid /* [out] [ref] */);
+NTSTATUS rpccli_samr_EnumDomainAliases(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t *resume_handle /* [in,out] [ref] */,
+ struct samr_SamArray **sam /* [out] [ref] */,
+ uint32_t max_size /* [in] */,
+ uint32_t *num_entries /* [out] [ref] */);
+NTSTATUS rpccli_samr_GetAliasMembership(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ struct lsa_SidArray *sids /* [in] [ref] */,
+ struct samr_Ids *rids /* [out] [ref] */);
+NTSTATUS rpccli_samr_LookupNames(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t num_names /* [in] [range(0,1000)] */,
+ struct lsa_String *names /* [in] [length_is(num_names),size_is(1000)] */,
+ struct samr_Ids *rids /* [out] [ref] */,
+ struct samr_Ids *types /* [out] [ref] */);
+NTSTATUS rpccli_samr_LookupRids(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t num_rids /* [in] [range(0,1000)] */,
+ uint32_t *rids /* [in] [length_is(num_rids),size_is(1000)] */,
+ struct lsa_Strings *names /* [out] [ref] */,
+ struct samr_Ids *types /* [out] [ref] */);
+NTSTATUS rpccli_samr_OpenGroup(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ uint32_t rid /* [in] */,
+ struct policy_handle *group_handle /* [out] [ref] */);
+NTSTATUS rpccli_samr_QueryGroupInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *group_handle /* [in] [ref] */,
+ enum samr_GroupInfoEnum level /* [in] */,
+ union samr_GroupInfo **info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_samr_SetGroupInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *group_handle /* [in] [ref] */,
+ enum samr_GroupInfoEnum level /* [in] */,
+ union samr_GroupInfo *info /* [in] [ref,switch_is(level)] */);
+NTSTATUS rpccli_samr_AddGroupMember(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *group_handle /* [in] [ref] */,
+ uint32_t rid /* [in] */,
+ uint32_t flags /* [in] */);
+NTSTATUS rpccli_samr_DeleteDomainGroup(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *group_handle /* [in,out] [ref] */);
+NTSTATUS rpccli_samr_DeleteGroupMember(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *group_handle /* [in] [ref] */,
+ uint32_t rid /* [in] */);
+NTSTATUS rpccli_samr_QueryGroupMember(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *group_handle /* [in] [ref] */,
+ struct samr_RidTypeArray **rids /* [out] [ref] */);
+NTSTATUS rpccli_samr_SetMemberAttributesOfGroup(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *group_handle /* [in] [ref] */,
+ uint32_t unknown1 /* [in] */,
+ uint32_t unknown2 /* [in] */);
+NTSTATUS rpccli_samr_OpenAlias(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ uint32_t rid /* [in] */,
+ struct policy_handle *alias_handle /* [out] [ref] */);
+NTSTATUS rpccli_samr_QueryAliasInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *alias_handle /* [in] [ref] */,
+ enum samr_AliasInfoEnum level /* [in] */,
+ union samr_AliasInfo **info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_samr_SetAliasInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *alias_handle /* [in] [ref] */,
+ enum samr_AliasInfoEnum level /* [in] */,
+ union samr_AliasInfo *info /* [in] [ref,switch_is(level)] */);
+NTSTATUS rpccli_samr_DeleteDomAlias(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *alias_handle /* [in,out] [ref] */);
+NTSTATUS rpccli_samr_AddAliasMember(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *alias_handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */);
+NTSTATUS rpccli_samr_DeleteAliasMember(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *alias_handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */);
+NTSTATUS rpccli_samr_GetMembersInAlias(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *alias_handle /* [in] [ref] */,
+ struct lsa_SidArray *sids /* [out] [ref] */);
+NTSTATUS rpccli_samr_OpenUser(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ uint32_t rid /* [in] */,
+ struct policy_handle *user_handle /* [out] [ref] */);
+NTSTATUS rpccli_samr_DeleteUser(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in,out] [ref] */);
+NTSTATUS rpccli_samr_QueryUserInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union samr_UserInfo **info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_samr_SetUserInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union samr_UserInfo *info /* [in] [ref,switch_is(level)] */);
+NTSTATUS rpccli_samr_ChangePasswordUser(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in] [ref] */,
+ uint8_t lm_present /* [in] */,
+ struct samr_Password *old_lm_crypted /* [in] [unique] */,
+ struct samr_Password *new_lm_crypted /* [in] [unique] */,
+ uint8_t nt_present /* [in] */,
+ struct samr_Password *old_nt_crypted /* [in] [unique] */,
+ struct samr_Password *new_nt_crypted /* [in] [unique] */,
+ uint8_t cross1_present /* [in] */,
+ struct samr_Password *nt_cross /* [in] [unique] */,
+ uint8_t cross2_present /* [in] */,
+ struct samr_Password *lm_cross /* [in] [unique] */);
+NTSTATUS rpccli_samr_GetGroupsForUser(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in] [ref] */,
+ struct samr_RidWithAttributeArray **rids /* [out] [ref] */);
+NTSTATUS rpccli_samr_QueryDisplayInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ uint32_t start_idx /* [in] */,
+ uint32_t max_entries /* [in] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *total_size /* [out] [ref] */,
+ uint32_t *returned_size /* [out] [ref] */,
+ union samr_DispInfo *info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_samr_GetDisplayEnumerationIndex(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ struct lsa_String *name /* [in] [ref] */,
+ uint32_t *idx /* [out] [ref] */);
+NTSTATUS rpccli_samr_TestPrivateFunctionsDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */);
+NTSTATUS rpccli_samr_TestPrivateFunctionsUser(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in] [ref] */);
+NTSTATUS rpccli_samr_GetUserPwInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in] [ref] */,
+ struct samr_PwInfo *info /* [out] [ref] */);
+NTSTATUS rpccli_samr_RemoveMemberFromForeignDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ struct dom_sid2 *sid /* [in] [ref] */);
+NTSTATUS rpccli_samr_QueryDomainInfo2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union samr_DomainInfo **info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_samr_QueryUserInfo2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union samr_UserInfo *info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_samr_QueryDisplayInfo2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ uint32_t start_idx /* [in] */,
+ uint32_t max_entries /* [in] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *total_size /* [out] [ref] */,
+ uint32_t *returned_size /* [out] [ref] */,
+ union samr_DispInfo *info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_samr_GetDisplayEnumerationIndex2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ struct lsa_String *name /* [in] [ref] */,
+ uint32_t *idx /* [out] [ref] */);
+NTSTATUS rpccli_samr_CreateUser2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ struct lsa_String *account_name /* [in] [ref] */,
+ uint32_t acct_flags /* [in] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *user_handle /* [out] [ref] */,
+ uint32_t *access_granted /* [out] [ref] */,
+ uint32_t *rid /* [out] [ref] */);
+NTSTATUS rpccli_samr_QueryDisplayInfo3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ uint32_t start_idx /* [in] */,
+ uint32_t max_entries /* [in] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *total_size /* [out] [ref] */,
+ uint32_t *returned_size /* [out] [ref] */,
+ union samr_DispInfo *info /* [out] [ref,switch_is(level)] */);
+NTSTATUS rpccli_samr_AddMultipleMembersToAlias(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *alias_handle /* [in] [ref] */,
+ struct lsa_SidArray *sids /* [in] [ref] */);
+NTSTATUS rpccli_samr_RemoveMultipleMembersFromAlias(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *alias_handle /* [in] [ref] */,
+ struct lsa_SidArray *sids /* [in] [ref] */);
+NTSTATUS rpccli_samr_OemChangePasswordUser2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_AsciiString *server /* [in] [unique] */,
+ struct lsa_AsciiString *account /* [in] [ref] */,
+ struct samr_CryptPassword *password /* [in] [unique] */,
+ struct samr_Password *hash /* [in] [unique] */);
+NTSTATUS rpccli_samr_ChangePasswordUser2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_String *server /* [in] [unique] */,
+ struct lsa_String *account /* [in] [ref] */,
+ struct samr_CryptPassword *nt_password /* [in] [unique] */,
+ struct samr_Password *nt_verifier /* [in] [unique] */,
+ uint8_t lm_change /* [in] */,
+ struct samr_CryptPassword *lm_password /* [in] [unique] */,
+ struct samr_Password *lm_verifier /* [in] [unique] */);
+NTSTATUS rpccli_samr_GetDomPwInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_String *domain_name /* [in] [unique] */,
+ struct samr_PwInfo *info /* [out] [ref] */);
+NTSTATUS rpccli_samr_Connect2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *system_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *connect_handle /* [out] [ref] */);
+NTSTATUS rpccli_samr_SetUserInfo2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle /* [in] [ref] */,
+ uint16_t level /* [in] */,
+ union samr_UserInfo *info /* [in] [ref,switch_is(level)] */);
+NTSTATUS rpccli_samr_SetBootKeyInformation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *connect_handle /* [in] [ref] */,
+ uint32_t unknown1 /* [in] */,
+ uint32_t unknown2 /* [in] */,
+ uint32_t unknown3 /* [in] */);
+NTSTATUS rpccli_samr_GetBootKeyInformation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t *unknown /* [out] [ref] */);
+NTSTATUS rpccli_samr_Connect3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *system_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t unknown /* [in] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *connect_handle /* [out] [ref] */);
+NTSTATUS rpccli_samr_Connect4(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *system_name /* [in] [unique,charset(UTF16)] */,
+ enum samr_ConnectVersion client_version /* [in] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *connect_handle /* [out] [ref] */);
+NTSTATUS rpccli_samr_ChangePasswordUser3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_String *server /* [in] [unique] */,
+ struct lsa_String *account /* [in] [ref] */,
+ struct samr_CryptPassword *nt_password /* [in] [unique] */,
+ struct samr_Password *nt_verifier /* [in] [unique] */,
+ uint8_t lm_change /* [in] */,
+ struct samr_CryptPassword *lm_password /* [in] [unique] */,
+ struct samr_Password *lm_verifier /* [in] [unique] */,
+ struct samr_CryptPassword *password3 /* [in] [unique] */,
+ struct samr_DomInfo1 **dominfo /* [out] [ref] */,
+ struct samr_ChangeReject **reject /* [out] [ref] */);
+NTSTATUS rpccli_samr_Connect5(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *system_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t access_mask /* [in] */,
+ uint32_t level_in /* [in] */,
+ union samr_ConnectInfo *info_in /* [in] [ref,switch_is(level_in)] */,
+ uint32_t *level_out /* [out] [ref] */,
+ union samr_ConnectInfo *info_out /* [out] [ref,switch_is(*level_out)] */,
+ struct policy_handle *connect_handle /* [out] [ref] */);
+NTSTATUS rpccli_samr_RidToSid(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle /* [in] [ref] */,
+ uint32_t rid /* [in] */,
+ struct dom_sid2 *sid /* [out] [ref] */);
+NTSTATUS rpccli_samr_SetDsrmPassword(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_String *name /* [in] [unique] */,
+ uint32_t unknown /* [in] */,
+ struct samr_Password *hash /* [in] [unique] */);
+NTSTATUS rpccli_samr_ValidatePassword(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ enum samr_ValidatePasswordLevel level /* [in] */,
+ union samr_ValidatePasswordReq req /* [in] [switch_is(level)] */,
+ union samr_ValidatePasswordRep *rep /* [out] [ref,switch_is(level)] */);
+#endif /* __CLI_SAMR__ */
diff --git a/source3/librpc/gen_ndr/cli_srvsvc.c b/source3/librpc/gen_ndr/cli_srvsvc.c
new file mode 100644
index 0000000000..fbf981365c
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_srvsvc.c
@@ -0,0 +1,2641 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * client auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/cli_srvsvc.h"
+
+NTSTATUS rpccli_srvsvc_NetCharDevEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t *level /* [in,out] [ref] */,
+ union srvsvc_NetCharDevCtr *ctr /* [in,out] [ref,switch_is(*level)] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetCharDevEnum r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.level = level;
+ r.in.ctr = ctr;
+ r.in.max_buffer = max_buffer;
+ r.in.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetCharDevEnum, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETCHARDEVENUM,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetCharDevEnum, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *level = *r.out.level;
+ *ctr = *r.out.ctr;
+ *totalentries = *r.out.totalentries;
+ if (resume_handle && r.out.resume_handle) {
+ *resume_handle = *r.out.resume_handle;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetCharDevGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *device_name /* [in] [charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetCharDevInfo *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetCharDevGetInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.device_name = device_name;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetCharDevGetInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETCHARDEVGETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetCharDevGetInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetCharDevControl(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *device_name /* [in] [charset(UTF16)] */,
+ uint32_t opcode /* [in] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetCharDevControl r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.device_name = device_name;
+ r.in.opcode = opcode;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetCharDevControl, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETCHARDEVCONTROL,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetCharDevControl, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetCharDevQEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *user /* [in] [unique,charset(UTF16)] */,
+ uint32_t *level /* [in,out] [ref] */,
+ union srvsvc_NetCharDevQCtr *ctr /* [in,out] [ref,switch_is(*level)] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetCharDevQEnum r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.user = user;
+ r.in.level = level;
+ r.in.ctr = ctr;
+ r.in.max_buffer = max_buffer;
+ r.in.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetCharDevQEnum, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETCHARDEVQENUM,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetCharDevQEnum, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *level = *r.out.level;
+ *ctr = *r.out.ctr;
+ *totalentries = *r.out.totalentries;
+ if (resume_handle && r.out.resume_handle) {
+ *resume_handle = *r.out.resume_handle;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetCharDevQGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *queue_name /* [in] [charset(UTF16)] */,
+ const char *user /* [in] [charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetCharDevQInfo *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetCharDevQGetInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.queue_name = queue_name;
+ r.in.user = user;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetCharDevQGetInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETCHARDEVQGETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetCharDevQGetInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetCharDevQSetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *queue_name /* [in] [charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetCharDevQInfo info /* [in] [switch_is(level)] */,
+ uint32_t *parm_error /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetCharDevQSetInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.queue_name = queue_name;
+ r.in.level = level;
+ r.in.info = info;
+ r.in.parm_error = parm_error;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetCharDevQSetInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETCHARDEVQSETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetCharDevQSetInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (parm_error && r.out.parm_error) {
+ *parm_error = *r.out.parm_error;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetCharDevQPurge(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *queue_name /* [in] [charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetCharDevQPurge r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.queue_name = queue_name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetCharDevQPurge, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETCHARDEVQPURGE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetCharDevQPurge, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetCharDevQPurgeSelf(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *queue_name /* [in] [charset(UTF16)] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetCharDevQPurgeSelf r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.queue_name = queue_name;
+ r.in.computer_name = computer_name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetCharDevQPurgeSelf, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETCHARDEVQPURGESELF,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetCharDevQPurgeSelf, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetConnEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *path /* [in] [unique,charset(UTF16)] */,
+ struct srvsvc_NetConnInfoCtr *info_ctr /* [in,out] [ref] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetConnEnum r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.path = path;
+ r.in.info_ctr = info_ctr;
+ r.in.max_buffer = max_buffer;
+ r.in.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetConnEnum, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETCONNENUM,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetConnEnum, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info_ctr = *r.out.info_ctr;
+ *totalentries = *r.out.totalentries;
+ if (resume_handle && r.out.resume_handle) {
+ *resume_handle = *r.out.resume_handle;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetFileEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *path /* [in] [unique,charset(UTF16)] */,
+ const char *user /* [in] [unique,charset(UTF16)] */,
+ struct srvsvc_NetFileInfoCtr *info_ctr /* [in,out] [ref] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetFileEnum r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.path = path;
+ r.in.user = user;
+ r.in.info_ctr = info_ctr;
+ r.in.max_buffer = max_buffer;
+ r.in.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetFileEnum, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETFILEENUM,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetFileEnum, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info_ctr = *r.out.info_ctr;
+ *totalentries = *r.out.totalentries;
+ if (resume_handle && r.out.resume_handle) {
+ *resume_handle = *r.out.resume_handle;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetFileGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t fid /* [in] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetFileInfo *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetFileGetInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.fid = fid;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetFileGetInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETFILEGETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetFileGetInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetFileClose(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t fid /* [in] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetFileClose r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.fid = fid;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetFileClose, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETFILECLOSE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetFileClose, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetSessEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *client /* [in] [unique,charset(UTF16)] */,
+ const char *user /* [in] [unique,charset(UTF16)] */,
+ struct srvsvc_NetSessInfoCtr *info_ctr /* [in,out] [ref] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetSessEnum r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.client = client;
+ r.in.user = user;
+ r.in.info_ctr = info_ctr;
+ r.in.max_buffer = max_buffer;
+ r.in.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetSessEnum, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSESSENUM,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetSessEnum, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info_ctr = *r.out.info_ctr;
+ *totalentries = *r.out.totalentries;
+ if (resume_handle && r.out.resume_handle) {
+ *resume_handle = *r.out.resume_handle;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetSessDel(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *client /* [in] [unique,charset(UTF16)] */,
+ const char *user /* [in] [unique,charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetSessDel r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.client = client;
+ r.in.user = user;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetSessDel, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSESSDEL,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetSessDel, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetShareAdd(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetShareInfo *info /* [in] [ref,switch_is(level)] */,
+ uint32_t *parm_error /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetShareAdd r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.level = level;
+ r.in.info = info;
+ r.in.parm_error = parm_error;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareAdd, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSHAREADD,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareAdd, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (parm_error && r.out.parm_error) {
+ *parm_error = *r.out.parm_error;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetShareEnumAll(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ struct srvsvc_NetShareInfoCtr *info_ctr /* [in,out] [ref] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetShareEnumAll r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.info_ctr = info_ctr;
+ r.in.max_buffer = max_buffer;
+ r.in.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareEnumAll, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSHAREENUMALL,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareEnumAll, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info_ctr = *r.out.info_ctr;
+ *totalentries = *r.out.totalentries;
+ if (resume_handle && r.out.resume_handle) {
+ *resume_handle = *r.out.resume_handle;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetShareGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *share_name /* [in] [charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetShareInfo *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetShareGetInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.share_name = share_name;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareGetInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSHAREGETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareGetInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetShareSetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *share_name /* [in] [charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetShareInfo *info /* [in] [ref,switch_is(level)] */,
+ uint32_t *parm_error /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetShareSetInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.share_name = share_name;
+ r.in.level = level;
+ r.in.info = info;
+ r.in.parm_error = parm_error;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareSetInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSHARESETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareSetInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (parm_error && r.out.parm_error) {
+ *parm_error = *r.out.parm_error;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetShareDel(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *share_name /* [in] [charset(UTF16)] */,
+ uint32_t reserved /* [in] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetShareDel r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.share_name = share_name;
+ r.in.reserved = reserved;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareDel, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSHAREDEL,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareDel, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetShareDelSticky(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *share_name /* [in] [charset(UTF16)] */,
+ uint32_t reserved /* [in] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetShareDelSticky r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.share_name = share_name;
+ r.in.reserved = reserved;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareDelSticky, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSHAREDELSTICKY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareDelSticky, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetShareCheck(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *device_name /* [in] [charset(UTF16)] */,
+ enum srvsvc_ShareType *type /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetShareCheck r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.device_name = device_name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareCheck, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSHARECHECK,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareCheck, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *type = *r.out.type;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetSrvGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetSrvInfo *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetSrvGetInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetSrvGetInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSRVGETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetSrvGetInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetSrvSetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetSrvInfo *info /* [in] [ref,switch_is(level)] */,
+ uint32_t *parm_error /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetSrvSetInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.level = level;
+ r.in.info = info;
+ r.in.parm_error = parm_error;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetSrvSetInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSRVSETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetSrvSetInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (parm_error && r.out.parm_error) {
+ *parm_error = *r.out.parm_error;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetDiskEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ struct srvsvc_NetDiskInfo *info /* [in,out] [ref] */,
+ uint32_t maxlen /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetDiskEnum r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.level = level;
+ r.in.info = info;
+ r.in.maxlen = maxlen;
+ r.in.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetDiskEnum, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETDISKENUM,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetDiskEnum, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+ *totalentries = *r.out.totalentries;
+ if (resume_handle && r.out.resume_handle) {
+ *resume_handle = *r.out.resume_handle;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetServerStatisticsGet(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *service /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ uint32_t options /* [in] */,
+ struct srvsvc_Statistics *stats /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetServerStatisticsGet r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.service = service;
+ r.in.level = level;
+ r.in.options = options;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetServerStatisticsGet, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSERVERSTATISTICSGET,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetServerStatisticsGet, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *stats = *r.out.stats;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetTransportAdd(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetTransportInfo info /* [in] [switch_is(level)] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetTransportAdd r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.level = level;
+ r.in.info = info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetTransportAdd, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETTRANSPORTADD,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetTransportAdd, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetTransportEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t *level /* [in,out] [ref] */,
+ union srvsvc_NetTransportCtr *transports /* [in,out] [ref,switch_is(*level)] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetTransportEnum r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.level = level;
+ r.in.transports = transports;
+ r.in.max_buffer = max_buffer;
+ r.in.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetTransportEnum, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETTRANSPORTENUM,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetTransportEnum, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *level = *r.out.level;
+ *transports = *r.out.transports;
+ *totalentries = *r.out.totalentries;
+ if (resume_handle && r.out.resume_handle) {
+ *resume_handle = *r.out.resume_handle;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetTransportDel(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t unknown /* [in] */,
+ struct srvsvc_NetTransportInfo0 transport /* [in] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetTransportDel r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.unknown = unknown;
+ r.in.transport = transport;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetTransportDel, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETTRANSPORTDEL,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetTransportDel, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetRemoteTOD(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ struct srvsvc_NetRemoteTODInfo **info /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetRemoteTOD r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetRemoteTOD, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETREMOTETOD,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetRemoteTOD, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetSetServiceBits(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *transport /* [in] [unique,charset(UTF16)] */,
+ uint32_t servicebits /* [in] */,
+ uint32_t updateimmediately /* [in] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetSetServiceBits r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.transport = transport;
+ r.in.servicebits = servicebits;
+ r.in.updateimmediately = updateimmediately;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetSetServiceBits, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSETSERVICEBITS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetSetServiceBits, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetPathType(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *path /* [in] [charset(UTF16)] */,
+ uint32_t pathflags /* [in] */,
+ uint32_t *pathtype /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetPathType r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.path = path;
+ r.in.pathflags = pathflags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetPathType, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETPATHTYPE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetPathType, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *pathtype = *r.out.pathtype;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetPathCanonicalize(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *path /* [in] [charset(UTF16)] */,
+ uint8_t *can_path /* [out] [size_is(maxbuf)] */,
+ uint32_t maxbuf /* [in] */,
+ const char *prefix /* [in] [charset(UTF16)] */,
+ uint32_t *pathtype /* [in,out] [ref] */,
+ uint32_t pathflags /* [in] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetPathCanonicalize r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.path = path;
+ r.in.maxbuf = maxbuf;
+ r.in.prefix = prefix;
+ r.in.pathtype = pathtype;
+ r.in.pathflags = pathflags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetPathCanonicalize, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETPATHCANONICALIZE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetPathCanonicalize, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ memcpy(can_path, r.out.can_path, r.in.maxbuf * sizeof(*can_path));
+ *pathtype = *r.out.pathtype;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetPathCompare(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *path1 /* [in] [charset(UTF16)] */,
+ const char *path2 /* [in] [charset(UTF16)] */,
+ uint32_t pathtype /* [in] */,
+ uint32_t pathflags /* [in] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetPathCompare r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.path1 = path1;
+ r.in.path2 = path2;
+ r.in.pathtype = pathtype;
+ r.in.pathflags = pathflags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetPathCompare, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETPATHCOMPARE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetPathCompare, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetNameValidate(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *name /* [in] [charset(UTF16)] */,
+ uint32_t name_type /* [in] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetNameValidate r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.name = name;
+ r.in.name_type = name_type;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetNameValidate, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETNAMEVALIDATE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetNameValidate, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NETRPRNAMECANONICALIZE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct srvsvc_NETRPRNAMECANONICALIZE r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRPRNAMECANONICALIZE, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETRPRNAMECANONICALIZE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRPRNAMECANONICALIZE, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetPRNameCompare(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *name1 /* [in] [charset(UTF16)] */,
+ const char *name2 /* [in] [charset(UTF16)] */,
+ uint32_t name_type /* [in] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetPRNameCompare r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.name1 = name1;
+ r.in.name2 = name2;
+ r.in.name_type = name_type;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetPRNameCompare, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETPRNAMECOMPARE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetPRNameCompare, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetShareEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ struct srvsvc_NetShareInfoCtr *info_ctr /* [in,out] [ref] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetShareEnum r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.info_ctr = info_ctr;
+ r.in.max_buffer = max_buffer;
+ r.in.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareEnum, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSHAREENUM,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareEnum, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info_ctr = *r.out.info_ctr;
+ *totalentries = *r.out.totalentries;
+ if (resume_handle && r.out.resume_handle) {
+ *resume_handle = *r.out.resume_handle;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetShareDelStart(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *share /* [in] [charset(UTF16)] */,
+ uint32_t reserved /* [in] */,
+ struct policy_handle *hnd /* [out] [unique] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetShareDelStart r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.share = share;
+ r.in.reserved = reserved;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareDelStart, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSHAREDELSTART,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareDelStart, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (hnd && r.out.hnd) {
+ *hnd = *r.out.hnd;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetShareDelCommit(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *hnd /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetShareDelCommit r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.hnd = hnd;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareDelCommit, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSHAREDELCOMMIT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareDelCommit, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (hnd && r.out.hnd) {
+ *hnd = *r.out.hnd;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetGetFileSecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *share /* [in] [unique,charset(UTF16)] */,
+ const char *file /* [in] [charset(UTF16)] */,
+ uint32_t securityinformation /* [in] */,
+ struct sec_desc_buf **sd_buf /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetGetFileSecurity r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.share = share;
+ r.in.file = file;
+ r.in.securityinformation = securityinformation;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetGetFileSecurity, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETGETFILESECURITY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetGetFileSecurity, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *sd_buf = *r.out.sd_buf;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetSetFileSecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *share /* [in] [unique,charset(UTF16)] */,
+ const char *file /* [in] [charset(UTF16)] */,
+ uint32_t securityinformation /* [in] */,
+ struct sec_desc_buf *sd_buf /* [in] [ref] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetSetFileSecurity r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.share = share;
+ r.in.file = file;
+ r.in.securityinformation = securityinformation;
+ r.in.sd_buf = sd_buf;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetSetFileSecurity, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSETFILESECURITY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetSetFileSecurity, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetServerTransportAddEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetTransportInfo info /* [in] [switch_is(level)] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetServerTransportAddEx r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.level = level;
+ r.in.info = info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetServerTransportAddEx, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSERVERTRANSPORTADDEX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetServerTransportAddEx, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NetServerSetServiceBitsEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *emulated_server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *transport /* [in] [unique,charset(UTF16)] */,
+ uint32_t servicebitsofinterest /* [in] */,
+ uint32_t servicebits /* [in] */,
+ uint32_t updateimmediately /* [in] */,
+ WERROR *werror)
+{
+ struct srvsvc_NetServerSetServiceBitsEx r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_unc = server_unc;
+ r.in.emulated_server_unc = emulated_server_unc;
+ r.in.transport = transport;
+ r.in.servicebitsofinterest = servicebitsofinterest;
+ r.in.servicebits = servicebits;
+ r.in.updateimmediately = updateimmediately;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetServerSetServiceBitsEx, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETSERVERSETSERVICEBITSEX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetServerSetServiceBitsEx, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NETRDFSGETVERSION(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct srvsvc_NETRDFSGETVERSION r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSGETVERSION, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETRDFSGETVERSION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSGETVERSION, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NETRDFSCREATELOCALPARTITION(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct srvsvc_NETRDFSCREATELOCALPARTITION r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSCREATELOCALPARTITION, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETRDFSCREATELOCALPARTITION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSCREATELOCALPARTITION, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NETRDFSDELETELOCALPARTITION(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct srvsvc_NETRDFSDELETELOCALPARTITION r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSDELETELOCALPARTITION, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETRDFSDELETELOCALPARTITION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSDELETELOCALPARTITION, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NETRDFSSETLOCALVOLUMESTATE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct srvsvc_NETRDFSSETLOCALVOLUMESTATE r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSSETLOCALVOLUMESTATE, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETRDFSSETLOCALVOLUMESTATE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSSETLOCALVOLUMESTATE, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NETRDFSSETSERVERINFO(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct srvsvc_NETRDFSSETSERVERINFO r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSSETSERVERINFO, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETRDFSSETSERVERINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSSETSERVERINFO, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NETRDFSCREATEEXITPOINT(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct srvsvc_NETRDFSCREATEEXITPOINT r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSCREATEEXITPOINT, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETRDFSCREATEEXITPOINT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSCREATEEXITPOINT, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NETRDFSDELETEEXITPOINT(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct srvsvc_NETRDFSDELETEEXITPOINT r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSDELETEEXITPOINT, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETRDFSDELETEEXITPOINT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSDELETEEXITPOINT, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NETRDFSMODIFYPREFIX(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct srvsvc_NETRDFSMODIFYPREFIX r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSMODIFYPREFIX, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETRDFSMODIFYPREFIX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSMODIFYPREFIX, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NETRDFSFIXLOCALVOLUME(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct srvsvc_NETRDFSFIXLOCALVOLUME r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSFIXLOCALVOLUME, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETRDFSFIXLOCALVOLUME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSFIXLOCALVOLUME, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NETRDFSMANAGERREPORTSITEINFO(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct srvsvc_NETRDFSMANAGERREPORTSITEINFO r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSMANAGERREPORTSITEINFO, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETRDFSMANAGERREPORTSITEINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSMANAGERREPORTSITEINFO, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_srvsvc_NETRSERVERTRANSPORTDELEX(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct srvsvc_NETRSERVERTRANSPORTDELEX r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRSERVERTRANSPORTDELEX, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_srvsvc,
+ NDR_SRVSVC_NETRSERVERTRANSPORTDELEX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRSERVERTRANSPORTDELEX, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
diff --git a/source3/librpc/gen_ndr/cli_srvsvc.h b/source3/librpc/gen_ndr/cli_srvsvc.h
new file mode 100644
index 0000000000..4ab4734de5
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_srvsvc.h
@@ -0,0 +1,347 @@
+#include "librpc/gen_ndr/ndr_srvsvc.h"
+#ifndef __CLI_SRVSVC__
+#define __CLI_SRVSVC__
+NTSTATUS rpccli_srvsvc_NetCharDevEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t *level /* [in,out] [ref] */,
+ union srvsvc_NetCharDevCtr *ctr /* [in,out] [ref,switch_is(*level)] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetCharDevGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *device_name /* [in] [charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetCharDevInfo *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetCharDevControl(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *device_name /* [in] [charset(UTF16)] */,
+ uint32_t opcode /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetCharDevQEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *user /* [in] [unique,charset(UTF16)] */,
+ uint32_t *level /* [in,out] [ref] */,
+ union srvsvc_NetCharDevQCtr *ctr /* [in,out] [ref,switch_is(*level)] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetCharDevQGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *queue_name /* [in] [charset(UTF16)] */,
+ const char *user /* [in] [charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetCharDevQInfo *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetCharDevQSetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *queue_name /* [in] [charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetCharDevQInfo info /* [in] [switch_is(level)] */,
+ uint32_t *parm_error /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetCharDevQPurge(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *queue_name /* [in] [charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetCharDevQPurgeSelf(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *queue_name /* [in] [charset(UTF16)] */,
+ const char *computer_name /* [in] [charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetConnEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *path /* [in] [unique,charset(UTF16)] */,
+ struct srvsvc_NetConnInfoCtr *info_ctr /* [in,out] [ref] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetFileEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *path /* [in] [unique,charset(UTF16)] */,
+ const char *user /* [in] [unique,charset(UTF16)] */,
+ struct srvsvc_NetFileInfoCtr *info_ctr /* [in,out] [ref] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetFileGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t fid /* [in] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetFileInfo *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetFileClose(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t fid /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetSessEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *client /* [in] [unique,charset(UTF16)] */,
+ const char *user /* [in] [unique,charset(UTF16)] */,
+ struct srvsvc_NetSessInfoCtr *info_ctr /* [in,out] [ref] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetSessDel(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *client /* [in] [unique,charset(UTF16)] */,
+ const char *user /* [in] [unique,charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetShareAdd(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetShareInfo *info /* [in] [ref,switch_is(level)] */,
+ uint32_t *parm_error /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetShareEnumAll(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ struct srvsvc_NetShareInfoCtr *info_ctr /* [in,out] [ref] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetShareGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *share_name /* [in] [charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetShareInfo *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetShareSetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *share_name /* [in] [charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetShareInfo *info /* [in] [ref,switch_is(level)] */,
+ uint32_t *parm_error /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetShareDel(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *share_name /* [in] [charset(UTF16)] */,
+ uint32_t reserved /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetShareDelSticky(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *share_name /* [in] [charset(UTF16)] */,
+ uint32_t reserved /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetShareCheck(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *device_name /* [in] [charset(UTF16)] */,
+ enum srvsvc_ShareType *type /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetSrvGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetSrvInfo *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetSrvSetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetSrvInfo *info /* [in] [ref,switch_is(level)] */,
+ uint32_t *parm_error /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetDiskEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ struct srvsvc_NetDiskInfo *info /* [in,out] [ref] */,
+ uint32_t maxlen /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetServerStatisticsGet(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *service /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ uint32_t options /* [in] */,
+ struct srvsvc_Statistics *stats /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetTransportAdd(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetTransportInfo info /* [in] [switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetTransportEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t *level /* [in,out] [ref] */,
+ union srvsvc_NetTransportCtr *transports /* [in,out] [ref,switch_is(*level)] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetTransportDel(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t unknown /* [in] */,
+ struct srvsvc_NetTransportInfo0 transport /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetRemoteTOD(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ struct srvsvc_NetRemoteTODInfo **info /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetSetServiceBits(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *transport /* [in] [unique,charset(UTF16)] */,
+ uint32_t servicebits /* [in] */,
+ uint32_t updateimmediately /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetPathType(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *path /* [in] [charset(UTF16)] */,
+ uint32_t pathflags /* [in] */,
+ uint32_t *pathtype /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetPathCanonicalize(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *path /* [in] [charset(UTF16)] */,
+ uint8_t *can_path /* [out] [size_is(maxbuf)] */,
+ uint32_t maxbuf /* [in] */,
+ const char *prefix /* [in] [charset(UTF16)] */,
+ uint32_t *pathtype /* [in,out] [ref] */,
+ uint32_t pathflags /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetPathCompare(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *path1 /* [in] [charset(UTF16)] */,
+ const char *path2 /* [in] [charset(UTF16)] */,
+ uint32_t pathtype /* [in] */,
+ uint32_t pathflags /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetNameValidate(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *name /* [in] [charset(UTF16)] */,
+ uint32_t name_type /* [in] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NETRPRNAMECANONICALIZE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetPRNameCompare(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *name1 /* [in] [charset(UTF16)] */,
+ const char *name2 /* [in] [charset(UTF16)] */,
+ uint32_t name_type /* [in] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetShareEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ struct srvsvc_NetShareInfoCtr *info_ctr /* [in,out] [ref] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *totalentries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetShareDelStart(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *share /* [in] [charset(UTF16)] */,
+ uint32_t reserved /* [in] */,
+ struct policy_handle *hnd /* [out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetShareDelCommit(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *hnd /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetGetFileSecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *share /* [in] [unique,charset(UTF16)] */,
+ const char *file /* [in] [charset(UTF16)] */,
+ uint32_t securityinformation /* [in] */,
+ struct sec_desc_buf **sd_buf /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetSetFileSecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *share /* [in] [unique,charset(UTF16)] */,
+ const char *file /* [in] [charset(UTF16)] */,
+ uint32_t securityinformation /* [in] */,
+ struct sec_desc_buf *sd_buf /* [in] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetServerTransportAddEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union srvsvc_NetTransportInfo info /* [in] [switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NetServerSetServiceBitsEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *emulated_server_unc /* [in] [unique,charset(UTF16)] */,
+ const char *transport /* [in] [unique,charset(UTF16)] */,
+ uint32_t servicebitsofinterest /* [in] */,
+ uint32_t servicebits /* [in] */,
+ uint32_t updateimmediately /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NETRDFSGETVERSION(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NETRDFSCREATELOCALPARTITION(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NETRDFSDELETELOCALPARTITION(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NETRDFSSETLOCALVOLUMESTATE(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NETRDFSSETSERVERINFO(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NETRDFSCREATEEXITPOINT(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NETRDFSDELETEEXITPOINT(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NETRDFSMODIFYPREFIX(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NETRDFSFIXLOCALVOLUME(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NETRDFSMANAGERREPORTSITEINFO(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_srvsvc_NETRSERVERTRANSPORTDELEX(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+#endif /* __CLI_SRVSVC__ */
diff --git a/source3/librpc/gen_ndr/cli_svcctl.c b/source3/librpc/gen_ndr/cli_svcctl.c
new file mode 100644
index 0000000000..c996c761d5
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_svcctl.c
@@ -0,0 +1,2245 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * client auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/cli_svcctl.h"
+
+NTSTATUS rpccli_svcctl_CloseServiceHandle(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in,out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_CloseServiceHandle r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_CloseServiceHandle, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_CLOSESERVICEHANDLE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_CloseServiceHandle, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_ControlService(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t control /* [in] */,
+ struct SERVICE_STATUS *service_status /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_ControlService r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.control = control;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_ControlService, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_CONTROLSERVICE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_ControlService, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *service_status = *r.out.service_status;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_DeleteService(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_DeleteService r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_DeleteService, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_DELETESERVICE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_DeleteService, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_LockServiceDatabase(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct policy_handle *lock /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_LockServiceDatabase r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_LockServiceDatabase, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_LOCKSERVICEDATABASE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_LockServiceDatabase, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *lock = *r.out.lock;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_QueryServiceObjectSecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t security_flags /* [in] */,
+ uint8_t *buffer /* [out] [ref,size_is(buffer_size)] */,
+ uint32_t buffer_size /* [in] [range(0,0x40000)] */,
+ uint32_t *needed /* [out] [ref,range(0,0x40000)] */,
+ WERROR *werror)
+{
+ struct svcctl_QueryServiceObjectSecurity r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.security_flags = security_flags;
+ r.in.buffer_size = buffer_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceObjectSecurity, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_QUERYSERVICEOBJECTSECURITY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceObjectSecurity, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ memcpy(buffer, r.out.buffer, r.in.buffer_size * sizeof(*buffer));
+ *needed = *r.out.needed;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_SetServiceObjectSecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t security_flags /* [in] */,
+ uint8_t *buffer /* [in] [ref,size_is(buffer_size)] */,
+ uint32_t buffer_size /* [in] */,
+ WERROR *werror)
+{
+ struct svcctl_SetServiceObjectSecurity r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.security_flags = security_flags;
+ r.in.buffer = buffer;
+ r.in.buffer_size = buffer_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_SetServiceObjectSecurity, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_SETSERVICEOBJECTSECURITY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_SetServiceObjectSecurity, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_QueryServiceStatus(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct SERVICE_STATUS *service_status /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_QueryServiceStatus r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceStatus, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_QUERYSERVICESTATUS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceStatus, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *service_status = *r.out.service_status;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_SetServiceStatus(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct svcctl_SetServiceStatus r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_SetServiceStatus, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_SETSERVICESTATUS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_SetServiceStatus, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_UnlockServiceDatabase(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *lock /* [in,out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_UnlockServiceDatabase r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.lock = lock;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_UnlockServiceDatabase, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_UNLOCKSERVICEDATABASE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_UnlockServiceDatabase, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *lock = *r.out.lock;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_NotifyBootConfigStatus(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct svcctl_NotifyBootConfigStatus r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_NotifyBootConfigStatus, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_NOTIFYBOOTCONFIGSTATUS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_NotifyBootConfigStatus, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_SCSetServiceBitsW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t bits /* [in] */,
+ uint32_t bitson /* [in] */,
+ uint32_t immediate /* [in] */,
+ WERROR *werror)
+{
+ struct svcctl_SCSetServiceBitsW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.bits = bits;
+ r.in.bitson = bitson;
+ r.in.immediate = immediate;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_SCSetServiceBitsW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_SCSETSERVICEBITSW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_SCSetServiceBitsW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_ChangeServiceConfigW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t type /* [in] */,
+ uint32_t start /* [in] */,
+ uint32_t error /* [in] */,
+ const char *binary_path /* [in] [unique,charset(UTF16)] */,
+ const char *load_order_group /* [in] [unique,charset(UTF16)] */,
+ uint32_t *tag_id /* [out] [ref] */,
+ const char *dependencies /* [in] [unique,charset(UTF16)] */,
+ const char *service_start_name /* [in] [unique,charset(UTF16)] */,
+ const char *password /* [in] [unique,charset(UTF16)] */,
+ const char *display_name /* [in] [unique,charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct svcctl_ChangeServiceConfigW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.type = type;
+ r.in.start = start;
+ r.in.error = error;
+ r.in.binary_path = binary_path;
+ r.in.load_order_group = load_order_group;
+ r.in.dependencies = dependencies;
+ r.in.service_start_name = service_start_name;
+ r.in.password = password;
+ r.in.display_name = display_name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_ChangeServiceConfigW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_CHANGESERVICECONFIGW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_ChangeServiceConfigW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *tag_id = *r.out.tag_id;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_CreateServiceW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *scmanager_handle /* [in] [ref] */,
+ const char *ServiceName /* [in] [charset(UTF16)] */,
+ const char *DisplayName /* [in] [unique,charset(UTF16)] */,
+ uint32_t desired_access /* [in] */,
+ uint32_t type /* [in] */,
+ uint32_t start_type /* [in] */,
+ uint32_t error_control /* [in] */,
+ const char *binary_path /* [in] [charset(UTF16)] */,
+ const char *LoadOrderGroupKey /* [in] [unique,charset(UTF16)] */,
+ uint32_t *TagId /* [in,out] [unique] */,
+ uint8_t *dependencies /* [in] [unique,size_is(dependencies_size)] */,
+ uint32_t dependencies_size /* [in] */,
+ const char *service_start_name /* [in] [unique,charset(UTF16)] */,
+ uint8_t *password /* [in] [unique,size_is(password_size)] */,
+ uint32_t password_size /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_CreateServiceW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.scmanager_handle = scmanager_handle;
+ r.in.ServiceName = ServiceName;
+ r.in.DisplayName = DisplayName;
+ r.in.desired_access = desired_access;
+ r.in.type = type;
+ r.in.start_type = start_type;
+ r.in.error_control = error_control;
+ r.in.binary_path = binary_path;
+ r.in.LoadOrderGroupKey = LoadOrderGroupKey;
+ r.in.TagId = TagId;
+ r.in.dependencies = dependencies;
+ r.in.dependencies_size = dependencies_size;
+ r.in.service_start_name = service_start_name;
+ r.in.password = password;
+ r.in.password_size = password_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_CreateServiceW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_CREATESERVICEW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_CreateServiceW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (TagId && r.out.TagId) {
+ *TagId = *r.out.TagId;
+ }
+ *handle = *r.out.handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_EnumDependentServicesW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *service /* [in] [ref] */,
+ uint32_t state /* [in] */,
+ uint8_t *service_status /* [out] [ref,size_is(buf_size)] */,
+ uint32_t buf_size /* [in] [range(0,0x40000)] */,
+ uint32_t *bytes_needed /* [out] [ref,range(0,0x40000)] */,
+ uint32_t *services_returned /* [out] [ref,range(0,0x40000)] */,
+ WERROR *werror)
+{
+ struct svcctl_EnumDependentServicesW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.service = service;
+ r.in.state = state;
+ r.in.buf_size = buf_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_EnumDependentServicesW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_ENUMDEPENDENTSERVICESW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_EnumDependentServicesW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ memcpy(service_status, r.out.service_status, r.in.buf_size * sizeof(*service_status));
+ *bytes_needed = *r.out.bytes_needed;
+ *services_returned = *r.out.services_returned;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_EnumServicesStatusW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t type /* [in] */,
+ uint32_t state /* [in] */,
+ uint32_t buf_size /* [in] */,
+ uint8_t *service /* [out] [size_is(buf_size)] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ uint32_t *services_returned /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct svcctl_EnumServicesStatusW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.type = type;
+ r.in.state = state;
+ r.in.buf_size = buf_size;
+ r.in.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_EnumServicesStatusW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_ENUMSERVICESSTATUSW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_EnumServicesStatusW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ memcpy(service, r.out.service, r.in.buf_size * sizeof(*service));
+ *bytes_needed = *r.out.bytes_needed;
+ *services_returned = *r.out.services_returned;
+ if (resume_handle && r.out.resume_handle) {
+ *resume_handle = *r.out.resume_handle;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_OpenSCManagerW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *MachineName /* [in] [unique,charset(UTF16)] */,
+ const char *DatabaseName /* [in] [unique,charset(UTF16)] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_OpenSCManagerW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.MachineName = MachineName;
+ r.in.DatabaseName = DatabaseName;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_OpenSCManagerW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_OPENSCMANAGERW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_OpenSCManagerW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_OpenServiceW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *scmanager_handle /* [in] [ref] */,
+ const char *ServiceName /* [in] [charset(UTF16)] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_OpenServiceW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.scmanager_handle = scmanager_handle;
+ r.in.ServiceName = ServiceName;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_OpenServiceW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_OPENSERVICEW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_OpenServiceW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_QueryServiceConfigW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint8_t *query /* [out] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_QueryServiceConfigW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.buf_size = buf_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceConfigW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_QUERYSERVICECONFIGW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceConfigW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ memcpy(query, r.out.query, r.in.buf_size * sizeof(*query));
+ *bytes_needed = *r.out.bytes_needed;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_QueryServiceLockStatusW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t buf_size /* [in] */,
+ struct SERVICE_LOCK_STATUS *lock_status /* [out] [ref] */,
+ uint32_t *required_buf_size /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_QueryServiceLockStatusW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.buf_size = buf_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceLockStatusW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_QUERYSERVICELOCKSTATUSW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceLockStatusW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *lock_status = *r.out.lock_status;
+ *required_buf_size = *r.out.required_buf_size;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_StartServiceW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t NumArgs /* [in] */,
+ const char *Arguments /* [in] [unique,charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct svcctl_StartServiceW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.NumArgs = NumArgs;
+ r.in.Arguments = Arguments;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_StartServiceW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_STARTSERVICEW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_StartServiceW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_GetServiceDisplayNameW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ const char *service_name /* [in] [unique,charset(UTF16)] */,
+ const char **display_name /* [out] [ref,charset(UTF16)] */,
+ uint32_t *display_name_length /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct svcctl_GetServiceDisplayNameW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.service_name = service_name;
+ r.in.display_name_length = display_name_length;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_GetServiceDisplayNameW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_GETSERVICEDISPLAYNAMEW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_GetServiceDisplayNameW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *display_name = *r.out.display_name;
+ if (display_name_length && r.out.display_name_length) {
+ *display_name_length = *r.out.display_name_length;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_GetServiceKeyNameW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ const char *service_name /* [in] [unique,charset(UTF16)] */,
+ const char **key_name /* [out] [ref,charset(UTF16)] */,
+ uint32_t *display_name_length /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct svcctl_GetServiceKeyNameW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.service_name = service_name;
+ r.in.display_name_length = display_name_length;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_GetServiceKeyNameW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_GETSERVICEKEYNAMEW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_GetServiceKeyNameW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *key_name = *r.out.key_name;
+ if (display_name_length && r.out.display_name_length) {
+ *display_name_length = *r.out.display_name_length;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_SCSetServiceBitsA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t bits /* [in] */,
+ uint32_t bitson /* [in] */,
+ uint32_t immediate /* [in] */,
+ WERROR *werror)
+{
+ struct svcctl_SCSetServiceBitsA r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.bits = bits;
+ r.in.bitson = bitson;
+ r.in.immediate = immediate;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_SCSetServiceBitsA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_SCSETSERVICEBITSA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_SCSetServiceBitsA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_ChangeServiceConfigA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t type /* [in] */,
+ uint32_t start /* [in] */,
+ uint32_t error /* [in] */,
+ const char *binary_path /* [in] [unique,charset(UTF16)] */,
+ const char *load_order_group /* [in] [unique,charset(UTF16)] */,
+ uint32_t *tag_id /* [out] [ref] */,
+ const char *dependencies /* [in] [unique,charset(UTF16)] */,
+ const char *service_start_name /* [in] [unique,charset(UTF16)] */,
+ const char *password /* [in] [unique,charset(UTF16)] */,
+ const char *display_name /* [in] [unique,charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct svcctl_ChangeServiceConfigA r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.type = type;
+ r.in.start = start;
+ r.in.error = error;
+ r.in.binary_path = binary_path;
+ r.in.load_order_group = load_order_group;
+ r.in.dependencies = dependencies;
+ r.in.service_start_name = service_start_name;
+ r.in.password = password;
+ r.in.display_name = display_name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_ChangeServiceConfigA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_CHANGESERVICECONFIGA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_ChangeServiceConfigA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *tag_id = *r.out.tag_id;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_CreateServiceA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ const char *ServiceName /* [in] [unique,charset(UTF16)] */,
+ const char *DisplayName /* [in] [unique,charset(UTF16)] */,
+ uint32_t desired_access /* [in] */,
+ uint32_t type /* [in] */,
+ uint32_t start_type /* [in] */,
+ uint32_t error_control /* [in] */,
+ const char *binary_path /* [in] [unique,charset(UTF16)] */,
+ const char *LoadOrderGroupKey /* [in] [unique,charset(UTF16)] */,
+ uint32_t *TagId /* [out] [unique] */,
+ const char *dependencies /* [in] [unique,charset(UTF16)] */,
+ const char *service_start_name /* [in] [unique,charset(UTF16)] */,
+ const char *password /* [in] [unique,charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct svcctl_CreateServiceA r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.ServiceName = ServiceName;
+ r.in.DisplayName = DisplayName;
+ r.in.desired_access = desired_access;
+ r.in.type = type;
+ r.in.start_type = start_type;
+ r.in.error_control = error_control;
+ r.in.binary_path = binary_path;
+ r.in.LoadOrderGroupKey = LoadOrderGroupKey;
+ r.in.dependencies = dependencies;
+ r.in.service_start_name = service_start_name;
+ r.in.password = password;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_CreateServiceA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_CREATESERVICEA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_CreateServiceA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (TagId && r.out.TagId) {
+ *TagId = *r.out.TagId;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_EnumDependentServicesA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *service /* [in] [ref] */,
+ uint32_t state /* [in] */,
+ struct ENUM_SERVICE_STATUS *service_status /* [out] [unique] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ uint32_t *services_returned /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_EnumDependentServicesA r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.service = service;
+ r.in.state = state;
+ r.in.buf_size = buf_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_EnumDependentServicesA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_ENUMDEPENDENTSERVICESA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_EnumDependentServicesA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (service_status && r.out.service_status) {
+ *service_status = *r.out.service_status;
+ }
+ *bytes_needed = *r.out.bytes_needed;
+ *services_returned = *r.out.services_returned;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_EnumServicesStatusA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t type /* [in] */,
+ uint32_t state /* [in] */,
+ uint32_t buf_size /* [in] */,
+ uint8_t *service /* [out] [size_is(buf_size)] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ uint32_t *services_returned /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct svcctl_EnumServicesStatusA r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.type = type;
+ r.in.state = state;
+ r.in.buf_size = buf_size;
+ r.in.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_EnumServicesStatusA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_ENUMSERVICESSTATUSA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_EnumServicesStatusA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ memcpy(service, r.out.service, r.in.buf_size * sizeof(*service));
+ *bytes_needed = *r.out.bytes_needed;
+ *services_returned = *r.out.services_returned;
+ if (resume_handle && r.out.resume_handle) {
+ *resume_handle = *r.out.resume_handle;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_OpenSCManagerA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *MachineName /* [in] [unique,charset(UTF16)] */,
+ const char *DatabaseName /* [in] [unique,charset(UTF16)] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_OpenSCManagerA r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.MachineName = MachineName;
+ r.in.DatabaseName = DatabaseName;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_OpenSCManagerA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_OPENSCMANAGERA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_OpenSCManagerA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_OpenServiceA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *scmanager_handle /* [in] [ref] */,
+ const char *ServiceName /* [in] [unique,charset(UTF16)] */,
+ uint32_t access_mask /* [in] */,
+ WERROR *werror)
+{
+ struct svcctl_OpenServiceA r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.scmanager_handle = scmanager_handle;
+ r.in.ServiceName = ServiceName;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_OpenServiceA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_OPENSERVICEA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_OpenServiceA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_QueryServiceConfigA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint8_t *query /* [out] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_QueryServiceConfigA r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.buf_size = buf_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceConfigA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_QUERYSERVICECONFIGA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceConfigA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ memcpy(query, r.out.query, r.in.buf_size * sizeof(*query));
+ *bytes_needed = *r.out.bytes_needed;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_QueryServiceLockStatusA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t buf_size /* [in] */,
+ struct SERVICE_LOCK_STATUS *lock_status /* [out] [ref] */,
+ uint32_t *required_buf_size /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_QueryServiceLockStatusA r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.buf_size = buf_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceLockStatusA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_QUERYSERVICELOCKSTATUSA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceLockStatusA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *lock_status = *r.out.lock_status;
+ *required_buf_size = *r.out.required_buf_size;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_StartServiceA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t NumArgs /* [in] */,
+ const char *Arguments /* [in] [unique,charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct svcctl_StartServiceA r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.NumArgs = NumArgs;
+ r.in.Arguments = Arguments;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_StartServiceA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_STARTSERVICEA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_StartServiceA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_GetServiceDisplayNameA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ const char *service_name /* [in] [unique,charset(UTF16)] */,
+ const char **display_name /* [out] [ref,charset(UTF16)] */,
+ uint32_t *display_name_length /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct svcctl_GetServiceDisplayNameA r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.service_name = service_name;
+ r.in.display_name_length = display_name_length;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_GetServiceDisplayNameA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_GETSERVICEDISPLAYNAMEA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_GetServiceDisplayNameA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *display_name = *r.out.display_name;
+ if (display_name_length && r.out.display_name_length) {
+ *display_name_length = *r.out.display_name_length;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_GetServiceKeyNameA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ const char *service_name /* [in] [unique,charset(UTF16)] */,
+ const char **key_name /* [out] [ref,charset(UTF16)] */,
+ uint32_t *display_name_length /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct svcctl_GetServiceKeyNameA r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.service_name = service_name;
+ r.in.display_name_length = display_name_length;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_GetServiceKeyNameA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_GETSERVICEKEYNAMEA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_GetServiceKeyNameA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *key_name = *r.out.key_name;
+ if (display_name_length && r.out.display_name_length) {
+ *display_name_length = *r.out.display_name_length;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_GetCurrentGroupeStateW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct svcctl_GetCurrentGroupeStateW r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_GetCurrentGroupeStateW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_GETCURRENTGROUPESTATEW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_GetCurrentGroupeStateW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_EnumServiceGroupW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct svcctl_EnumServiceGroupW r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_EnumServiceGroupW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_ENUMSERVICEGROUPW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_EnumServiceGroupW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_ChangeServiceConfig2A(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t info_level /* [in] */,
+ uint8_t *info /* [in] [unique] */,
+ WERROR *werror)
+{
+ struct svcctl_ChangeServiceConfig2A r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.info_level = info_level;
+ r.in.info = info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_ChangeServiceConfig2A, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_CHANGESERVICECONFIG2A,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_ChangeServiceConfig2A, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_ChangeServiceConfig2W(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t info_level /* [in] */,
+ uint8_t *info /* [in] [unique] */,
+ WERROR *werror)
+{
+ struct svcctl_ChangeServiceConfig2W r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.info_level = info_level;
+ r.in.info = info;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_ChangeServiceConfig2W, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_CHANGESERVICECONFIG2W,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_ChangeServiceConfig2W, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_QueryServiceConfig2A(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t info_level /* [in] */,
+ uint8_t *buffer /* [out] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_QueryServiceConfig2A r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.info_level = info_level;
+ r.in.buf_size = buf_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceConfig2A, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_QUERYSERVICECONFIG2A,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceConfig2A, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ memcpy(buffer, r.out.buffer, r.in.buf_size * sizeof(*buffer));
+ *bytes_needed = *r.out.bytes_needed;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_QueryServiceConfig2W(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t info_level /* [in] */,
+ uint8_t *buffer /* [out] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_QueryServiceConfig2W r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.info_level = info_level;
+ r.in.buf_size = buf_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceConfig2W, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_QUERYSERVICECONFIG2W,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceConfig2W, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ memcpy(buffer, r.out.buffer, r.in.buf_size * sizeof(*buffer));
+ *bytes_needed = *r.out.bytes_needed;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_QueryServiceStatusEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t info_level /* [in] */,
+ uint8_t *buffer /* [out] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct svcctl_QueryServiceStatusEx r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.info_level = info_level;
+ r.in.buf_size = buf_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceStatusEx, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_QUERYSERVICESTATUSEX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceStatusEx, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ memcpy(buffer, r.out.buffer, r.in.buf_size * sizeof(*buffer));
+ *bytes_needed = *r.out.bytes_needed;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_EnumServicesStatusExA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *scmanager /* [in] [ref] */,
+ uint32_t info_level /* [in] */,
+ uint32_t type /* [in] */,
+ uint32_t state /* [in] */,
+ uint8_t *services /* [out] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ uint32_t *service_returned /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ const char **group_name /* [out] [ref,charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct EnumServicesStatusExA r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.scmanager = scmanager;
+ r.in.info_level = info_level;
+ r.in.type = type;
+ r.in.state = state;
+ r.in.buf_size = buf_size;
+ r.in.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(EnumServicesStatusExA, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_ENUMSERVICESSTATUSEXA,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(EnumServicesStatusExA, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ memcpy(services, r.out.services, r.in.buf_size * sizeof(*services));
+ *bytes_needed = *r.out.bytes_needed;
+ *service_returned = *r.out.service_returned;
+ if (resume_handle && r.out.resume_handle) {
+ *resume_handle = *r.out.resume_handle;
+ }
+ *group_name = *r.out.group_name;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_EnumServicesStatusExW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *scmanager /* [in] [ref] */,
+ uint32_t info_level /* [in] */,
+ uint32_t type /* [in] */,
+ uint32_t state /* [in] */,
+ uint8_t *services /* [out] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ uint32_t *service_returned /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ const char **group_name /* [out] [ref,charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct EnumServicesStatusExW r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.scmanager = scmanager;
+ r.in.info_level = info_level;
+ r.in.type = type;
+ r.in.state = state;
+ r.in.buf_size = buf_size;
+ r.in.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(EnumServicesStatusExW, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_ENUMSERVICESSTATUSEXW,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(EnumServicesStatusExW, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ memcpy(services, r.out.services, r.in.buf_size * sizeof(*services));
+ *bytes_needed = *r.out.bytes_needed;
+ *service_returned = *r.out.service_returned;
+ if (resume_handle && r.out.resume_handle) {
+ *resume_handle = *r.out.resume_handle;
+ }
+ *group_name = *r.out.group_name;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_svcctl_SCSendTSMessage(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct svcctl_SCSendTSMessage r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_SCSendTSMessage, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_svcctl,
+ NDR_SVCCTL_SCSENDTSMESSAGE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_SCSendTSMessage, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
diff --git a/source3/librpc/gen_ndr/cli_svcctl.h b/source3/librpc/gen_ndr/cli_svcctl.h
new file mode 100644
index 0000000000..56f0a2b0e7
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_svcctl.h
@@ -0,0 +1,336 @@
+#include "librpc/gen_ndr/ndr_svcctl.h"
+#ifndef __CLI_SVCCTL__
+#define __CLI_SVCCTL__
+NTSTATUS rpccli_svcctl_CloseServiceHandle(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in,out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_ControlService(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t control /* [in] */,
+ struct SERVICE_STATUS *service_status /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_DeleteService(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_LockServiceDatabase(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct policy_handle *lock /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_QueryServiceObjectSecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t security_flags /* [in] */,
+ uint8_t *buffer /* [out] [ref,size_is(buffer_size)] */,
+ uint32_t buffer_size /* [in] [range(0,0x40000)] */,
+ uint32_t *needed /* [out] [ref,range(0,0x40000)] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_SetServiceObjectSecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t security_flags /* [in] */,
+ uint8_t *buffer /* [in] [ref,size_is(buffer_size)] */,
+ uint32_t buffer_size /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_QueryServiceStatus(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct SERVICE_STATUS *service_status /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_SetServiceStatus(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_UnlockServiceDatabase(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *lock /* [in,out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_NotifyBootConfigStatus(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_SCSetServiceBitsW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t bits /* [in] */,
+ uint32_t bitson /* [in] */,
+ uint32_t immediate /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_ChangeServiceConfigW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t type /* [in] */,
+ uint32_t start /* [in] */,
+ uint32_t error /* [in] */,
+ const char *binary_path /* [in] [unique,charset(UTF16)] */,
+ const char *load_order_group /* [in] [unique,charset(UTF16)] */,
+ uint32_t *tag_id /* [out] [ref] */,
+ const char *dependencies /* [in] [unique,charset(UTF16)] */,
+ const char *service_start_name /* [in] [unique,charset(UTF16)] */,
+ const char *password /* [in] [unique,charset(UTF16)] */,
+ const char *display_name /* [in] [unique,charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_CreateServiceW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *scmanager_handle /* [in] [ref] */,
+ const char *ServiceName /* [in] [charset(UTF16)] */,
+ const char *DisplayName /* [in] [unique,charset(UTF16)] */,
+ uint32_t desired_access /* [in] */,
+ uint32_t type /* [in] */,
+ uint32_t start_type /* [in] */,
+ uint32_t error_control /* [in] */,
+ const char *binary_path /* [in] [charset(UTF16)] */,
+ const char *LoadOrderGroupKey /* [in] [unique,charset(UTF16)] */,
+ uint32_t *TagId /* [in,out] [unique] */,
+ uint8_t *dependencies /* [in] [unique,size_is(dependencies_size)] */,
+ uint32_t dependencies_size /* [in] */,
+ const char *service_start_name /* [in] [unique,charset(UTF16)] */,
+ uint8_t *password /* [in] [unique,size_is(password_size)] */,
+ uint32_t password_size /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_EnumDependentServicesW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *service /* [in] [ref] */,
+ uint32_t state /* [in] */,
+ uint8_t *service_status /* [out] [ref,size_is(buf_size)] */,
+ uint32_t buf_size /* [in] [range(0,0x40000)] */,
+ uint32_t *bytes_needed /* [out] [ref,range(0,0x40000)] */,
+ uint32_t *services_returned /* [out] [ref,range(0,0x40000)] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_EnumServicesStatusW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t type /* [in] */,
+ uint32_t state /* [in] */,
+ uint32_t buf_size /* [in] */,
+ uint8_t *service /* [out] [size_is(buf_size)] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ uint32_t *services_returned /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_OpenSCManagerW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *MachineName /* [in] [unique,charset(UTF16)] */,
+ const char *DatabaseName /* [in] [unique,charset(UTF16)] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_OpenServiceW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *scmanager_handle /* [in] [ref] */,
+ const char *ServiceName /* [in] [charset(UTF16)] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_QueryServiceConfigW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint8_t *query /* [out] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_QueryServiceLockStatusW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t buf_size /* [in] */,
+ struct SERVICE_LOCK_STATUS *lock_status /* [out] [ref] */,
+ uint32_t *required_buf_size /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_StartServiceW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t NumArgs /* [in] */,
+ const char *Arguments /* [in] [unique,charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_GetServiceDisplayNameW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ const char *service_name /* [in] [unique,charset(UTF16)] */,
+ const char **display_name /* [out] [ref,charset(UTF16)] */,
+ uint32_t *display_name_length /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_GetServiceKeyNameW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ const char *service_name /* [in] [unique,charset(UTF16)] */,
+ const char **key_name /* [out] [ref,charset(UTF16)] */,
+ uint32_t *display_name_length /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_SCSetServiceBitsA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t bits /* [in] */,
+ uint32_t bitson /* [in] */,
+ uint32_t immediate /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_ChangeServiceConfigA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t type /* [in] */,
+ uint32_t start /* [in] */,
+ uint32_t error /* [in] */,
+ const char *binary_path /* [in] [unique,charset(UTF16)] */,
+ const char *load_order_group /* [in] [unique,charset(UTF16)] */,
+ uint32_t *tag_id /* [out] [ref] */,
+ const char *dependencies /* [in] [unique,charset(UTF16)] */,
+ const char *service_start_name /* [in] [unique,charset(UTF16)] */,
+ const char *password /* [in] [unique,charset(UTF16)] */,
+ const char *display_name /* [in] [unique,charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_CreateServiceA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ const char *ServiceName /* [in] [unique,charset(UTF16)] */,
+ const char *DisplayName /* [in] [unique,charset(UTF16)] */,
+ uint32_t desired_access /* [in] */,
+ uint32_t type /* [in] */,
+ uint32_t start_type /* [in] */,
+ uint32_t error_control /* [in] */,
+ const char *binary_path /* [in] [unique,charset(UTF16)] */,
+ const char *LoadOrderGroupKey /* [in] [unique,charset(UTF16)] */,
+ uint32_t *TagId /* [out] [unique] */,
+ const char *dependencies /* [in] [unique,charset(UTF16)] */,
+ const char *service_start_name /* [in] [unique,charset(UTF16)] */,
+ const char *password /* [in] [unique,charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_EnumDependentServicesA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *service /* [in] [ref] */,
+ uint32_t state /* [in] */,
+ struct ENUM_SERVICE_STATUS *service_status /* [out] [unique] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ uint32_t *services_returned /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_EnumServicesStatusA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t type /* [in] */,
+ uint32_t state /* [in] */,
+ uint32_t buf_size /* [in] */,
+ uint8_t *service /* [out] [size_is(buf_size)] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ uint32_t *services_returned /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_OpenSCManagerA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *MachineName /* [in] [unique,charset(UTF16)] */,
+ const char *DatabaseName /* [in] [unique,charset(UTF16)] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_OpenServiceA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *scmanager_handle /* [in] [ref] */,
+ const char *ServiceName /* [in] [unique,charset(UTF16)] */,
+ uint32_t access_mask /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_QueryServiceConfigA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint8_t *query /* [out] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_QueryServiceLockStatusA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t buf_size /* [in] */,
+ struct SERVICE_LOCK_STATUS *lock_status /* [out] [ref] */,
+ uint32_t *required_buf_size /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_StartServiceA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t NumArgs /* [in] */,
+ const char *Arguments /* [in] [unique,charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_GetServiceDisplayNameA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ const char *service_name /* [in] [unique,charset(UTF16)] */,
+ const char **display_name /* [out] [ref,charset(UTF16)] */,
+ uint32_t *display_name_length /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_GetServiceKeyNameA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ const char *service_name /* [in] [unique,charset(UTF16)] */,
+ const char **key_name /* [out] [ref,charset(UTF16)] */,
+ uint32_t *display_name_length /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_GetCurrentGroupeStateW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_EnumServiceGroupW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_ChangeServiceConfig2A(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t info_level /* [in] */,
+ uint8_t *info /* [in] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_ChangeServiceConfig2W(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t info_level /* [in] */,
+ uint8_t *info /* [in] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_QueryServiceConfig2A(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t info_level /* [in] */,
+ uint8_t *buffer /* [out] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_QueryServiceConfig2W(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t info_level /* [in] */,
+ uint8_t *buffer /* [out] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_QueryServiceStatusEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t info_level /* [in] */,
+ uint8_t *buffer /* [out] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_EnumServicesStatusExA(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *scmanager /* [in] [ref] */,
+ uint32_t info_level /* [in] */,
+ uint32_t type /* [in] */,
+ uint32_t state /* [in] */,
+ uint8_t *services /* [out] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ uint32_t *service_returned /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ const char **group_name /* [out] [ref,charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_EnumServicesStatusExW(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *scmanager /* [in] [ref] */,
+ uint32_t info_level /* [in] */,
+ uint32_t type /* [in] */,
+ uint32_t state /* [in] */,
+ uint8_t *services /* [out] */,
+ uint32_t buf_size /* [in] */,
+ uint32_t *bytes_needed /* [out] [ref] */,
+ uint32_t *service_returned /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ const char **group_name /* [out] [ref,charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_svcctl_SCSendTSMessage(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+#endif /* __CLI_SVCCTL__ */
diff --git a/source3/librpc/gen_ndr/cli_winreg.c b/source3/librpc/gen_ndr/cli_winreg.c
new file mode 100644
index 0000000000..29f7e50c45
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_winreg.c
@@ -0,0 +1,1726 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * client auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/cli_winreg.h"
+
+NTSTATUS rpccli_winreg_OpenHKCR(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_OpenHKCR r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKCR, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_OPENHKCR,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKCR, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_OpenHKCU(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_OpenHKCU r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKCU, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_OPENHKCU,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKCU, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_OpenHKLM(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_OpenHKLM r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKLM, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_OPENHKLM,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKLM, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_OpenHKPD(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_OpenHKPD r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKPD, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_OPENHKPD,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKPD, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_OpenHKU(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_OpenHKU r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKU, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_OPENHKU,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKU, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_CloseKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in,out] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_CloseKey r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_CloseKey, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_CLOSEKEY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_CloseKey, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_CreateKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String name /* [in] */,
+ struct winreg_String keyclass /* [in] */,
+ uint32_t options /* [in] */,
+ uint32_t access_mask /* [in] */,
+ struct winreg_SecBuf *secdesc /* [in] [unique] */,
+ struct policy_handle *new_handle /* [out] [ref] */,
+ enum winreg_CreateAction *action_taken /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct winreg_CreateKey r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.name = name;
+ r.in.keyclass = keyclass;
+ r.in.options = options;
+ r.in.access_mask = access_mask;
+ r.in.secdesc = secdesc;
+ r.in.action_taken = action_taken;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_CreateKey, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_CREATEKEY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_CreateKey, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *new_handle = *r.out.new_handle;
+ if (action_taken && r.out.action_taken) {
+ *action_taken = *r.out.action_taken;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_DeleteKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String key /* [in] */,
+ WERROR *werror)
+{
+ struct winreg_DeleteKey r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.key = key;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_DeleteKey, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_DELETEKEY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_DeleteKey, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_DeleteValue(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String value /* [in] */,
+ WERROR *werror)
+{
+ struct winreg_DeleteValue r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.value = value;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_DeleteValue, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_DELETEVALUE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_DeleteValue, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_EnumKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t enum_index /* [in] */,
+ struct winreg_StringBuf *name /* [in,out] [ref] */,
+ struct winreg_StringBuf *keyclass /* [in,out] [unique] */,
+ NTTIME *last_changed_time /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct winreg_EnumKey r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.enum_index = enum_index;
+ r.in.name = name;
+ r.in.keyclass = keyclass;
+ r.in.last_changed_time = last_changed_time;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_EnumKey, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_ENUMKEY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_EnumKey, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *name = *r.out.name;
+ if (keyclass && r.out.keyclass) {
+ *keyclass = *r.out.keyclass;
+ }
+ if (last_changed_time && r.out.last_changed_time) {
+ *last_changed_time = *r.out.last_changed_time;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_EnumValue(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t enum_index /* [in] */,
+ struct winreg_ValNameBuf *name /* [in,out] [ref] */,
+ enum winreg_Type *type /* [in,out] [unique] */,
+ uint8_t *value /* [in,out] [unique,length_is(*length),size_is(*size)] */,
+ uint32_t *size /* [in,out] [unique] */,
+ uint32_t *length /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct winreg_EnumValue r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.enum_index = enum_index;
+ r.in.name = name;
+ r.in.type = type;
+ r.in.value = value;
+ r.in.size = size;
+ r.in.length = length;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_EnumValue, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_ENUMVALUE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_EnumValue, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *name = *r.out.name;
+ if (type && r.out.type) {
+ *type = *r.out.type;
+ }
+ if (value && r.out.value) {
+ memcpy(value, r.out.value, *r.in.size * sizeof(*value));
+ }
+ if (size && r.out.size) {
+ *size = *r.out.size;
+ }
+ if (length && r.out.length) {
+ *length = *r.out.length;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_FlushKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_FlushKey r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_FlushKey, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_FLUSHKEY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_FlushKey, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_GetKeySecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t sec_info /* [in] */,
+ struct KeySecurityData *sd /* [in,out] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_GetKeySecurity r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.sec_info = sec_info;
+ r.in.sd = sd;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_GetKeySecurity, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_GETKEYSECURITY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_GetKeySecurity, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *sd = *r.out.sd;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_LoadKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String *keyname /* [in] [unique] */,
+ struct winreg_String *filename /* [in] [unique] */,
+ WERROR *werror)
+{
+ struct winreg_LoadKey r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.keyname = keyname;
+ r.in.filename = filename;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_LoadKey, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_LOADKEY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_LoadKey, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_NotifyChangeKeyValue(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint8_t watch_subtree /* [in] */,
+ uint32_t notify_filter /* [in] */,
+ uint32_t unknown /* [in] */,
+ struct winreg_String string1 /* [in] */,
+ struct winreg_String string2 /* [in] */,
+ uint32_t unknown2 /* [in] */,
+ WERROR *werror)
+{
+ struct winreg_NotifyChangeKeyValue r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.watch_subtree = watch_subtree;
+ r.in.notify_filter = notify_filter;
+ r.in.unknown = unknown;
+ r.in.string1 = string1;
+ r.in.string2 = string2;
+ r.in.unknown2 = unknown2;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_NotifyChangeKeyValue, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_NOTIFYCHANGEKEYVALUE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_NotifyChangeKeyValue, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_OpenKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *parent_handle /* [in] [ref] */,
+ struct winreg_String keyname /* [in] */,
+ uint32_t unknown /* [in] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_OpenKey r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.parent_handle = parent_handle;
+ r.in.keyname = keyname;
+ r.in.unknown = unknown;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenKey, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_OPENKEY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenKey, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_QueryInfoKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String *classname /* [in,out] [ref] */,
+ uint32_t *num_subkeys /* [out] [ref] */,
+ uint32_t *max_subkeylen /* [out] [ref] */,
+ uint32_t *max_classlen /* [out] [ref] */,
+ uint32_t *num_values /* [out] [ref] */,
+ uint32_t *max_valnamelen /* [out] [ref] */,
+ uint32_t *max_valbufsize /* [out] [ref] */,
+ uint32_t *secdescsize /* [out] [ref] */,
+ NTTIME *last_changed_time /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_QueryInfoKey r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.classname = classname;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_QueryInfoKey, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_QUERYINFOKEY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_QueryInfoKey, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *classname = *r.out.classname;
+ *num_subkeys = *r.out.num_subkeys;
+ *max_subkeylen = *r.out.max_subkeylen;
+ *max_classlen = *r.out.max_classlen;
+ *num_values = *r.out.num_values;
+ *max_valnamelen = *r.out.max_valnamelen;
+ *max_valbufsize = *r.out.max_valbufsize;
+ *secdescsize = *r.out.secdescsize;
+ *last_changed_time = *r.out.last_changed_time;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_QueryValue(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String *value_name /* [in] [ref] */,
+ enum winreg_Type *type /* [in,out] [unique] */,
+ uint8_t *data /* [in,out] [unique,length_is(*value_length),size_is(*data_size)] */,
+ uint32_t *data_size /* [in,out] [unique] */,
+ uint32_t *value_length /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct winreg_QueryValue r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.value_name = value_name;
+ r.in.type = type;
+ r.in.data = data;
+ r.in.data_size = data_size;
+ r.in.value_length = value_length;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_QueryValue, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_QUERYVALUE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_QueryValue, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (type && r.out.type) {
+ *type = *r.out.type;
+ }
+ if (data && r.out.data) {
+ memcpy(data, r.out.data, *r.in.data_size * sizeof(*data));
+ }
+ if (data_size && r.out.data_size) {
+ *data_size = *r.out.data_size;
+ }
+ if (value_length && r.out.value_length) {
+ *value_length = *r.out.value_length;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_ReplaceKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct winreg_ReplaceKey r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_ReplaceKey, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_REPLACEKEY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_ReplaceKey, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_RestoreKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String *filename /* [in] [ref] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror)
+{
+ struct winreg_RestoreKey r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.filename = filename;
+ r.in.flags = flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_RestoreKey, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_RESTOREKEY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_RestoreKey, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_SaveKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String *filename /* [in] [ref] */,
+ struct KeySecurityAttribute *sec_attrib /* [in] [unique] */,
+ WERROR *werror)
+{
+ struct winreg_SaveKey r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.filename = filename;
+ r.in.sec_attrib = sec_attrib;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_SaveKey, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_SAVEKEY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_SaveKey, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_SetKeySecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct KeySecurityData *sd /* [in] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_SetKeySecurity r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.access_mask = access_mask;
+ r.in.sd = sd;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_SetKeySecurity, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_SETKEYSECURITY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_SetKeySecurity, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_SetValue(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String name /* [in] */,
+ enum winreg_Type type /* [in] */,
+ uint8_t *data /* [in] [ref,size_is(size)] */,
+ uint32_t size /* [in] */,
+ WERROR *werror)
+{
+ struct winreg_SetValue r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+ r.in.name = name;
+ r.in.type = type;
+ r.in.data = data;
+ r.in.size = size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_SetValue, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_SETVALUE,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_SetValue, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_UnLoadKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct winreg_UnLoadKey r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_UnLoadKey, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_UNLOADKEY,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_UnLoadKey, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_InitiateSystemShutdown(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *hostname /* [in] [unique] */,
+ struct initshutdown_String *message /* [in] [unique] */,
+ uint32_t timeout /* [in] */,
+ uint8_t force_apps /* [in] */,
+ uint8_t do_reboot /* [in] */,
+ WERROR *werror)
+{
+ struct winreg_InitiateSystemShutdown r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.hostname = hostname;
+ r.in.message = message;
+ r.in.timeout = timeout;
+ r.in.force_apps = force_apps;
+ r.in.do_reboot = do_reboot;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_InitiateSystemShutdown, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_INITIATESYSTEMSHUTDOWN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_InitiateSystemShutdown, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_AbortSystemShutdown(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *server /* [in] [unique] */,
+ WERROR *werror)
+{
+ struct winreg_AbortSystemShutdown r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server = server;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_AbortSystemShutdown, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_ABORTSYSTEMSHUTDOWN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_AbortSystemShutdown, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_GetVersion(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t *version /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_GetVersion r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.handle = handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_GetVersion, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_GETVERSION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_GetVersion, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *version = *r.out.version;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_OpenHKCC(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_OpenHKCC r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKCC, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_OPENHKCC,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKCC, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_OpenHKDD(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_OpenHKDD r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKDD, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_OPENHKDD,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKDD, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_QueryMultipleValues(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *key_handle /* [in] [ref] */,
+ struct QueryMultipleValue *values /* [in,out] [ref,length_is(num_values),size_is(num_values)] */,
+ uint32_t num_values /* [in] */,
+ uint8_t *buffer /* [in,out] [unique,length_is(*buffer_size),size_is(*buffer_size)] */,
+ uint32_t *buffer_size /* [in,out] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_QueryMultipleValues r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.key_handle = key_handle;
+ r.in.values = values;
+ r.in.num_values = num_values;
+ r.in.buffer = buffer;
+ r.in.buffer_size = buffer_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_QueryMultipleValues, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_QUERYMULTIPLEVALUES,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_QueryMultipleValues, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ memcpy(values, r.out.values, r.in.num_values * sizeof(*values));
+ if (buffer && r.out.buffer) {
+ memcpy(buffer, r.out.buffer, *r.in.buffer_size * sizeof(*buffer));
+ }
+ *buffer_size = *r.out.buffer_size;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_InitiateSystemShutdownEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *hostname /* [in] [unique] */,
+ struct initshutdown_String *message /* [in] [unique] */,
+ uint32_t timeout /* [in] */,
+ uint8_t force_apps /* [in] */,
+ uint8_t do_reboot /* [in] */,
+ uint32_t reason /* [in] */,
+ WERROR *werror)
+{
+ struct winreg_InitiateSystemShutdownEx r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.hostname = hostname;
+ r.in.message = message;
+ r.in.timeout = timeout;
+ r.in.force_apps = force_apps;
+ r.in.do_reboot = do_reboot;
+ r.in.reason = reason;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_InitiateSystemShutdownEx, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_INITIATESYSTEMSHUTDOWNEX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_InitiateSystemShutdownEx, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_SaveKeyEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct winreg_SaveKeyEx r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_SaveKeyEx, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_SAVEKEYEX,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_SaveKeyEx, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_OpenHKPT(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_OpenHKPT r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKPT, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_OPENHKPT,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKPT, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_OpenHKPN(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct winreg_OpenHKPN r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.system_name = system_name;
+ r.in.access_mask = access_mask;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKPN, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_OPENHKPN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKPN, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *handle = *r.out.handle;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_winreg_QueryMultipleValues2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+ struct winreg_QueryMultipleValues2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_QueryMultipleValues2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_winreg,
+ NDR_WINREG_QUERYMULTIPLEVALUES2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_QueryMultipleValues2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
diff --git a/source3/librpc/gen_ndr/cli_winreg.h b/source3/librpc/gen_ndr/cli_winreg.h
new file mode 100644
index 0000000000..793a4ffc5b
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_winreg.h
@@ -0,0 +1,229 @@
+#include "librpc/gen_ndr/ndr_winreg.h"
+#ifndef __CLI_WINREG__
+#define __CLI_WINREG__
+NTSTATUS rpccli_winreg_OpenHKCR(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_OpenHKCU(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_OpenHKLM(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_OpenHKPD(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_OpenHKU(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_CloseKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in,out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_CreateKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String name /* [in] */,
+ struct winreg_String keyclass /* [in] */,
+ uint32_t options /* [in] */,
+ uint32_t access_mask /* [in] */,
+ struct winreg_SecBuf *secdesc /* [in] [unique] */,
+ struct policy_handle *new_handle /* [out] [ref] */,
+ enum winreg_CreateAction *action_taken /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_DeleteKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String key /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_DeleteValue(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String value /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_EnumKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t enum_index /* [in] */,
+ struct winreg_StringBuf *name /* [in,out] [ref] */,
+ struct winreg_StringBuf *keyclass /* [in,out] [unique] */,
+ NTTIME *last_changed_time /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_EnumValue(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t enum_index /* [in] */,
+ struct winreg_ValNameBuf *name /* [in,out] [ref] */,
+ enum winreg_Type *type /* [in,out] [unique] */,
+ uint8_t *value /* [in,out] [unique,length_is(*length),size_is(*size)] */,
+ uint32_t *size /* [in,out] [unique] */,
+ uint32_t *length /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_FlushKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_GetKeySecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t sec_info /* [in] */,
+ struct KeySecurityData *sd /* [in,out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_LoadKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String *keyname /* [in] [unique] */,
+ struct winreg_String *filename /* [in] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_NotifyChangeKeyValue(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint8_t watch_subtree /* [in] */,
+ uint32_t notify_filter /* [in] */,
+ uint32_t unknown /* [in] */,
+ struct winreg_String string1 /* [in] */,
+ struct winreg_String string2 /* [in] */,
+ uint32_t unknown2 /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_OpenKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *parent_handle /* [in] [ref] */,
+ struct winreg_String keyname /* [in] */,
+ uint32_t unknown /* [in] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_QueryInfoKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String *classname /* [in,out] [ref] */,
+ uint32_t *num_subkeys /* [out] [ref] */,
+ uint32_t *max_subkeylen /* [out] [ref] */,
+ uint32_t *max_classlen /* [out] [ref] */,
+ uint32_t *num_values /* [out] [ref] */,
+ uint32_t *max_valnamelen /* [out] [ref] */,
+ uint32_t *max_valbufsize /* [out] [ref] */,
+ uint32_t *secdescsize /* [out] [ref] */,
+ NTTIME *last_changed_time /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_QueryValue(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String *value_name /* [in] [ref] */,
+ enum winreg_Type *type /* [in,out] [unique] */,
+ uint8_t *data /* [in,out] [unique,length_is(*value_length),size_is(*data_size)] */,
+ uint32_t *data_size /* [in,out] [unique] */,
+ uint32_t *value_length /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_ReplaceKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_RestoreKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String *filename /* [in] [ref] */,
+ uint32_t flags /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_SaveKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String *filename /* [in] [ref] */,
+ struct KeySecurityAttribute *sec_attrib /* [in] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_SetKeySecurity(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t access_mask /* [in] */,
+ struct KeySecurityData *sd /* [in] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_SetValue(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ struct winreg_String name /* [in] */,
+ enum winreg_Type type /* [in] */,
+ uint8_t *data /* [in] [ref,size_is(size)] */,
+ uint32_t size /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_UnLoadKey(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_InitiateSystemShutdown(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *hostname /* [in] [unique] */,
+ struct initshutdown_String *message /* [in] [unique] */,
+ uint32_t timeout /* [in] */,
+ uint8_t force_apps /* [in] */,
+ uint8_t do_reboot /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_AbortSystemShutdown(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *server /* [in] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_GetVersion(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle /* [in] [ref] */,
+ uint32_t *version /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_OpenHKCC(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_OpenHKDD(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_QueryMultipleValues(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *key_handle /* [in] [ref] */,
+ struct QueryMultipleValue *values /* [in,out] [ref,length_is(num_values),size_is(num_values)] */,
+ uint32_t num_values /* [in] */,
+ uint8_t *buffer /* [in,out] [unique,length_is(*buffer_size),size_is(*buffer_size)] */,
+ uint32_t *buffer_size /* [in,out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_InitiateSystemShutdownEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *hostname /* [in] [unique] */,
+ struct initshutdown_String *message /* [in] [unique] */,
+ uint32_t timeout /* [in] */,
+ uint8_t force_apps /* [in] */,
+ uint8_t do_reboot /* [in] */,
+ uint32_t reason /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_SaveKeyEx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_OpenHKPT(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_OpenHKPN(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *system_name /* [in] [unique] */,
+ uint32_t access_mask /* [in] */,
+ struct policy_handle *handle /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_winreg_QueryMultipleValues2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror);
+#endif /* __CLI_WINREG__ */
diff --git a/source3/librpc/gen_ndr/cli_wkssvc.c b/source3/librpc/gen_ndr/cli_wkssvc.c
new file mode 100644
index 0000000000..b82e95311f
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_wkssvc.c
@@ -0,0 +1,1570 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * client auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/cli_wkssvc.h"
+
+NTSTATUS rpccli_wkssvc_NetWkstaGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union wkssvc_NetWkstaInfo *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetWkstaGetInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetWkstaGetInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETWKSTAGETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetWkstaGetInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetWkstaSetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union wkssvc_NetWkstaInfo *info /* [in] [ref,switch_is(level)] */,
+ uint32_t *parm_error /* [in,out] [ref] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetWkstaSetInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+ r.in.info = info;
+ r.in.parm_error = parm_error;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetWkstaSetInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETWKSTASETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetWkstaSetInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *parm_error = *r.out.parm_error;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetWkstaEnumUsers(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_NetWkstaEnumUsersInfo *info /* [in,out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetWkstaEnumUsers r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.info = info;
+ r.in.prefmaxlen = prefmaxlen;
+ r.in.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetWkstaEnumUsers, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETWKSTAENUMUSERS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetWkstaEnumUsers, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+ *entries_read = *r.out.entries_read;
+ if (resume_handle && r.out.resume_handle) {
+ *resume_handle = *r.out.resume_handle;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrWkstaUserGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *unknown /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union wkssvc_NetrWkstaUserInfo *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrWkstaUserGetInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.unknown = unknown;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrWkstaUserGetInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRWKSTAUSERGETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrWkstaUserGetInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrWkstaUserSetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *unknown /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union wkssvc_NetrWkstaUserInfo *info /* [in] [ref,switch_is(level)] */,
+ uint32_t *parm_err /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrWkstaUserSetInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.unknown = unknown;
+ r.in.level = level;
+ r.in.info = info;
+ r.in.parm_err = parm_err;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrWkstaUserSetInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRWKSTAUSERSETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrWkstaUserSetInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (parm_err && r.out.parm_err) {
+ *parm_err = *r.out.parm_err;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetWkstaTransportEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_NetWkstaTransportInfo *info /* [in,out] [ref] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetWkstaTransportEnum r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.info = info;
+ r.in.max_buffer = max_buffer;
+ r.in.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetWkstaTransportEnum, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETWKSTATRANSPORTENUM,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetWkstaTransportEnum, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+ *total_entries = *r.out.total_entries;
+ if (resume_handle && r.out.resume_handle) {
+ *resume_handle = *r.out.resume_handle;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrWkstaTransportAdd(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ struct wkssvc_NetWkstaTransportInfo0 *info0 /* [in] [ref] */,
+ uint32_t *parm_err /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrWkstaTransportAdd r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+ r.in.info0 = info0;
+ r.in.parm_err = parm_err;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrWkstaTransportAdd, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRWKSTATRANSPORTADD,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrWkstaTransportAdd, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (parm_err && r.out.parm_err) {
+ *parm_err = *r.out.parm_err;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrWkstaTransportDel(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *transport_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t unknown3 /* [in] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrWkstaTransportDel r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.transport_name = transport_name;
+ r.in.unknown3 = unknown3;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrWkstaTransportDel, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRWKSTATRANSPORTDEL,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrWkstaTransportDel, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrUseAdd(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union wkssvc_NetrUseGetInfoCtr *ctr /* [in] [ref,switch_is(level)] */,
+ uint32_t *parm_err /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrUseAdd r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.level = level;
+ r.in.ctr = ctr;
+ r.in.parm_err = parm_err;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrUseAdd, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRUSEADD,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrUseAdd, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ if (parm_err && r.out.parm_err) {
+ *parm_err = *r.out.parm_err;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrUseGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *use_name /* [in] [ref,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union wkssvc_NetrUseGetInfoCtr *ctr /* [out] [ref,switch_is(level)] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrUseGetInfo r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.use_name = use_name;
+ r.in.level = level;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrUseGetInfo, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRUSEGETINFO,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrUseGetInfo, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *ctr = *r.out.ctr;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrUseDel(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *use_name /* [in] [ref,charset(UTF16)] */,
+ uint32_t force_cond /* [in] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrUseDel r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.use_name = use_name;
+ r.in.force_cond = force_cond;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrUseDel, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRUSEDEL,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrUseDel, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrUseEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_NetrUseEnumInfo *info /* [in,out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrUseEnum r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.info = info;
+ r.in.prefmaxlen = prefmaxlen;
+ r.in.resume_handle = resume_handle;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrUseEnum, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRUSEENUM,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrUseEnum, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+ *entries_read = *r.out.entries_read;
+ if (resume_handle && r.out.resume_handle) {
+ *resume_handle = *r.out.resume_handle;
+ }
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrMessageBufferSend(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *message_name /* [in] [ref,charset(UTF16)] */,
+ const char *message_sender_name /* [in] [unique,charset(UTF16)] */,
+ uint8_t *message_buffer /* [in] [ref,size_is(message_size)] */,
+ uint32_t message_size /* [in] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrMessageBufferSend r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.message_name = message_name;
+ r.in.message_sender_name = message_sender_name;
+ r.in.message_buffer = message_buffer;
+ r.in.message_size = message_size;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrMessageBufferSend, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRMESSAGEBUFFERSEND,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrMessageBufferSend, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrWorkstationStatisticsGet(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *unknown2 /* [in] [unique,charset(UTF16)] */,
+ uint32_t unknown3 /* [in] */,
+ uint32_t unknown4 /* [in] */,
+ struct wkssvc_NetrWorkstationStatistics **info /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrWorkstationStatisticsGet r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.unknown2 = unknown2;
+ r.in.unknown3 = unknown3;
+ r.in.unknown4 = unknown4;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrWorkstationStatisticsGet, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRWORKSTATIONSTATISTICSGET,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrWorkstationStatisticsGet, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *info = *r.out.info;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrLogonDomainNameAdd(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *domain_name /* [in] [ref,charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrLogonDomainNameAdd r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_name = domain_name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrLogonDomainNameAdd, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRLOGONDOMAINNAMEADD,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrLogonDomainNameAdd, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrLogonDomainNameDel(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *domain_name /* [in] [ref,charset(UTF16)] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrLogonDomainNameDel r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.domain_name = domain_name;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrLogonDomainNameDel, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRLOGONDOMAINNAMEDEL,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrLogonDomainNameDel, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrJoinDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *domain_name /* [in] [ref,charset(UTF16)] */,
+ const char *account_ou /* [in] [unique,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ const char *password /* [in] [unique,charset(UTF16)] */,
+ uint32_t join_flags /* [in] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrJoinDomain r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.domain_name = domain_name;
+ r.in.account_ou = account_ou;
+ r.in.Account = Account;
+ r.in.password = password;
+ r.in.join_flags = join_flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrJoinDomain, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRJOINDOMAIN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrJoinDomain, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrUnjoinDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ const char *password /* [in] [unique,charset(UTF16)] */,
+ uint32_t unjoin_flags /* [in] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrUnjoinDomain r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.Account = Account;
+ r.in.password = password;
+ r.in.unjoin_flags = unjoin_flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrUnjoinDomain, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRUNJOINDOMAIN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrUnjoinDomain, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrRenameMachineInDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *NewMachineName /* [in] [unique,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ const char *password /* [in] [unique,charset(UTF16)] */,
+ uint32_t RenameOptions /* [in] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrRenameMachineInDomain r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.NewMachineName = NewMachineName;
+ r.in.Account = Account;
+ r.in.password = password;
+ r.in.RenameOptions = RenameOptions;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrRenameMachineInDomain, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRRENAMEMACHINEINDOMAIN,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrRenameMachineInDomain, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrValidateName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *name /* [in] [ref,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ const char *Password /* [in] [unique,charset(UTF16)] */,
+ enum wkssvc_NetValidateNameType name_type /* [in] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrValidateName r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.name = name;
+ r.in.Account = Account;
+ r.in.Password = Password;
+ r.in.name_type = name_type;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrValidateName, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRVALIDATENAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrValidateName, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrGetJoinInformation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char **name_buffer /* [in,out] [ref,charset(UTF16)] */,
+ enum wkssvc_NetJoinStatus *name_type /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrGetJoinInformation r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.name_buffer = name_buffer;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrGetJoinInformation, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRGETJOININFORMATION,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrGetJoinInformation, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *name_buffer = *r.out.name_buffer;
+ *name_type = *r.out.name_type;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrGetJoinableOus(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *domain_name /* [in] [ref,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ const char *unknown /* [in] [unique,charset(UTF16)] */,
+ uint32_t *num_ous /* [in,out] [ref] */,
+ const char ***ous /* [out] [ref,charset(UTF16),size_is(,*num_ous)] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrGetJoinableOus r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.domain_name = domain_name;
+ r.in.Account = Account;
+ r.in.unknown = unknown;
+ r.in.num_ous = num_ous;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrGetJoinableOus, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRGETJOINABLEOUS,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrGetJoinableOus, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *num_ous = *r.out.num_ous;
+ *ous = *r.out.ous;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrJoinDomain2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *domain_name /* [in] [ref,charset(UTF16)] */,
+ const char *account_ou /* [in] [unique,charset(UTF16)] */,
+ const char *admin_account /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_PasswordBuffer *encrypted_password /* [in] [unique] */,
+ uint32_t join_flags /* [in] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrJoinDomain2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.domain_name = domain_name;
+ r.in.account_ou = account_ou;
+ r.in.admin_account = admin_account;
+ r.in.encrypted_password = encrypted_password;
+ r.in.join_flags = join_flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrJoinDomain2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRJOINDOMAIN2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrJoinDomain2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrUnjoinDomain2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_PasswordBuffer *encrypted_password /* [in] [unique] */,
+ uint32_t unjoin_flags /* [in] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrUnjoinDomain2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.account = account;
+ r.in.encrypted_password = encrypted_password;
+ r.in.unjoin_flags = unjoin_flags;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrUnjoinDomain2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRUNJOINDOMAIN2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrUnjoinDomain2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrRenameMachineInDomain2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *NewMachineName /* [in] [unique,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_PasswordBuffer *EncryptedPassword /* [in] [unique] */,
+ uint32_t RenameOptions /* [in] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrRenameMachineInDomain2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.NewMachineName = NewMachineName;
+ r.in.Account = Account;
+ r.in.EncryptedPassword = EncryptedPassword;
+ r.in.RenameOptions = RenameOptions;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrRenameMachineInDomain2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRRENAMEMACHINEINDOMAIN2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrRenameMachineInDomain2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrValidateName2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *name /* [in] [ref,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_PasswordBuffer *EncryptedPassword /* [in] [unique] */,
+ enum wkssvc_NetValidateNameType name_type /* [in] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrValidateName2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.name = name;
+ r.in.Account = Account;
+ r.in.EncryptedPassword = EncryptedPassword;
+ r.in.name_type = name_type;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrValidateName2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRVALIDATENAME2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrValidateName2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrGetJoinableOus2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *domain_name /* [in] [ref,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_PasswordBuffer *EncryptedPassword /* [in] [unique] */,
+ uint32_t *num_ous /* [in,out] [ref] */,
+ const char ***ous /* [out] [ref,charset(UTF16),size_is(,*num_ous)] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrGetJoinableOus2 r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.domain_name = domain_name;
+ r.in.Account = Account;
+ r.in.EncryptedPassword = EncryptedPassword;
+ r.in.num_ous = num_ous;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrGetJoinableOus2, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRGETJOINABLEOUS2,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrGetJoinableOus2, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *num_ous = *r.out.num_ous;
+ *ous = *r.out.ous;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrAddAlternateComputerName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *NewAlternateMachineName /* [in] [unique,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_PasswordBuffer *EncryptedPassword /* [in] [unique] */,
+ uint32_t Reserved /* [in] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrAddAlternateComputerName r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.NewAlternateMachineName = NewAlternateMachineName;
+ r.in.Account = Account;
+ r.in.EncryptedPassword = EncryptedPassword;
+ r.in.Reserved = Reserved;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrAddAlternateComputerName, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRADDALTERNATECOMPUTERNAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrAddAlternateComputerName, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrRemoveAlternateComputerName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *AlternateMachineNameToRemove /* [in] [unique,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_PasswordBuffer *EncryptedPassword /* [in] [unique] */,
+ uint32_t Reserved /* [in] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrRemoveAlternateComputerName r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.AlternateMachineNameToRemove = AlternateMachineNameToRemove;
+ r.in.Account = Account;
+ r.in.EncryptedPassword = EncryptedPassword;
+ r.in.Reserved = Reserved;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrRemoveAlternateComputerName, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRREMOVEALTERNATECOMPUTERNAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrRemoveAlternateComputerName, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrSetPrimaryComputername(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *primary_name /* [in] [unique,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_PasswordBuffer *EncryptedPassword /* [in] [unique] */,
+ uint32_t Reserved /* [in] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrSetPrimaryComputername r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.primary_name = primary_name;
+ r.in.Account = Account;
+ r.in.EncryptedPassword = EncryptedPassword;
+ r.in.Reserved = Reserved;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrSetPrimaryComputername, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRSETPRIMARYCOMPUTERNAME,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrSetPrimaryComputername, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
+NTSTATUS rpccli_wkssvc_NetrEnumerateComputerNames(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ enum wkssvc_ComputerNameType name_type /* [in] */,
+ uint32_t Reserved /* [in] */,
+ struct wkssvc_ComputerNamesCtr **ctr /* [out] [ref] */,
+ WERROR *werror)
+{
+ struct wkssvc_NetrEnumerateComputerNames r;
+ NTSTATUS status;
+
+ /* In parameters */
+ r.in.server_name = server_name;
+ r.in.name_type = name_type;
+ r.in.Reserved = Reserved;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrEnumerateComputerNames, &r);
+ }
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_wkssvc,
+ NDR_WKSSVC_NETRENUMERATECOMPUTERNAMES,
+ &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrEnumerateComputerNames, &r);
+ }
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ /* Return variables */
+ *ctr = *r.out.ctr;
+
+ /* Return result */
+ if (werror) {
+ *werror = r.out.result;
+ }
+
+ return werror_to_ntstatus(r.out.result);
+}
+
diff --git a/source3/librpc/gen_ndr/cli_wkssvc.h b/source3/librpc/gen_ndr/cli_wkssvc.h
new file mode 100644
index 0000000000..0d360abfeb
--- /dev/null
+++ b/source3/librpc/gen_ndr/cli_wkssvc.h
@@ -0,0 +1,230 @@
+#include "librpc/gen_ndr/ndr_wkssvc.h"
+#ifndef __CLI_WKSSVC__
+#define __CLI_WKSSVC__
+NTSTATUS rpccli_wkssvc_NetWkstaGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union wkssvc_NetWkstaInfo *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetWkstaSetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union wkssvc_NetWkstaInfo *info /* [in] [ref,switch_is(level)] */,
+ uint32_t *parm_error /* [in,out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetWkstaEnumUsers(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_NetWkstaEnumUsersInfo *info /* [in,out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrWkstaUserGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *unknown /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union wkssvc_NetrWkstaUserInfo *info /* [out] [ref,switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrWkstaUserSetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *unknown /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union wkssvc_NetrWkstaUserInfo *info /* [in] [ref,switch_is(level)] */,
+ uint32_t *parm_err /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetWkstaTransportEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_NetWkstaTransportInfo *info /* [in,out] [ref] */,
+ uint32_t max_buffer /* [in] */,
+ uint32_t *total_entries /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrWkstaTransportAdd(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ struct wkssvc_NetWkstaTransportInfo0 *info0 /* [in] [ref] */,
+ uint32_t *parm_err /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrWkstaTransportDel(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *transport_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t unknown3 /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrUseAdd(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union wkssvc_NetrUseGetInfoCtr *ctr /* [in] [ref,switch_is(level)] */,
+ uint32_t *parm_err /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrUseGetInfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *use_name /* [in] [ref,charset(UTF16)] */,
+ uint32_t level /* [in] */,
+ union wkssvc_NetrUseGetInfoCtr *ctr /* [out] [ref,switch_is(level)] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrUseDel(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *use_name /* [in] [ref,charset(UTF16)] */,
+ uint32_t force_cond /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrUseEnum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_NetrUseEnumInfo *info /* [in,out] [ref] */,
+ uint32_t prefmaxlen /* [in] */,
+ uint32_t *entries_read /* [out] [ref] */,
+ uint32_t *resume_handle /* [in,out] [unique] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrMessageBufferSend(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *message_name /* [in] [ref,charset(UTF16)] */,
+ const char *message_sender_name /* [in] [unique,charset(UTF16)] */,
+ uint8_t *message_buffer /* [in] [ref,size_is(message_size)] */,
+ uint32_t message_size /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrWorkstationStatisticsGet(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *unknown2 /* [in] [unique,charset(UTF16)] */,
+ uint32_t unknown3 /* [in] */,
+ uint32_t unknown4 /* [in] */,
+ struct wkssvc_NetrWorkstationStatistics **info /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrLogonDomainNameAdd(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *domain_name /* [in] [ref,charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrLogonDomainNameDel(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *domain_name /* [in] [ref,charset(UTF16)] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrJoinDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *domain_name /* [in] [ref,charset(UTF16)] */,
+ const char *account_ou /* [in] [unique,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ const char *password /* [in] [unique,charset(UTF16)] */,
+ uint32_t join_flags /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrUnjoinDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ const char *password /* [in] [unique,charset(UTF16)] */,
+ uint32_t unjoin_flags /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrRenameMachineInDomain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *NewMachineName /* [in] [unique,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ const char *password /* [in] [unique,charset(UTF16)] */,
+ uint32_t RenameOptions /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrValidateName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *name /* [in] [ref,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ const char *Password /* [in] [unique,charset(UTF16)] */,
+ enum wkssvc_NetValidateNameType name_type /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrGetJoinInformation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char **name_buffer /* [in,out] [ref,charset(UTF16)] */,
+ enum wkssvc_NetJoinStatus *name_type /* [out] [ref] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrGetJoinableOus(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *domain_name /* [in] [ref,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ const char *unknown /* [in] [unique,charset(UTF16)] */,
+ uint32_t *num_ous /* [in,out] [ref] */,
+ const char ***ous /* [out] [ref,charset(UTF16),size_is(,*num_ous)] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrJoinDomain2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *domain_name /* [in] [ref,charset(UTF16)] */,
+ const char *account_ou /* [in] [unique,charset(UTF16)] */,
+ const char *admin_account /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_PasswordBuffer *encrypted_password /* [in] [unique] */,
+ uint32_t join_flags /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrUnjoinDomain2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *account /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_PasswordBuffer *encrypted_password /* [in] [unique] */,
+ uint32_t unjoin_flags /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrRenameMachineInDomain2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *NewMachineName /* [in] [unique,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_PasswordBuffer *EncryptedPassword /* [in] [unique] */,
+ uint32_t RenameOptions /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrValidateName2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *name /* [in] [ref,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_PasswordBuffer *EncryptedPassword /* [in] [unique] */,
+ enum wkssvc_NetValidateNameType name_type /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrGetJoinableOus2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *domain_name /* [in] [ref,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_PasswordBuffer *EncryptedPassword /* [in] [unique] */,
+ uint32_t *num_ous /* [in,out] [ref] */,
+ const char ***ous /* [out] [ref,charset(UTF16),size_is(,*num_ous)] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrAddAlternateComputerName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *NewAlternateMachineName /* [in] [unique,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_PasswordBuffer *EncryptedPassword /* [in] [unique] */,
+ uint32_t Reserved /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrRemoveAlternateComputerName(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *AlternateMachineNameToRemove /* [in] [unique,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_PasswordBuffer *EncryptedPassword /* [in] [unique] */,
+ uint32_t Reserved /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrSetPrimaryComputername(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ const char *primary_name /* [in] [unique,charset(UTF16)] */,
+ const char *Account /* [in] [unique,charset(UTF16)] */,
+ struct wkssvc_PasswordBuffer *EncryptedPassword /* [in] [unique] */,
+ uint32_t Reserved /* [in] */,
+ WERROR *werror);
+NTSTATUS rpccli_wkssvc_NetrEnumerateComputerNames(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *server_name /* [in] [unique,charset(UTF16)] */,
+ enum wkssvc_ComputerNameType name_type /* [in] */,
+ uint32_t Reserved /* [in] */,
+ struct wkssvc_ComputerNamesCtr **ctr /* [out] [ref] */,
+ WERROR *werror);
+#endif /* __CLI_WKSSVC__ */
diff --git a/source3/librpc/gen_ndr/dfs.h b/source3/librpc/gen_ndr/dfs.h
new file mode 100644
index 0000000000..8957eaef56
--- /dev/null
+++ b/source3/librpc/gen_ndr/dfs.h
@@ -0,0 +1,581 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#ifndef _HEADER_netdfs
+#define _HEADER_netdfs
+
+#define DFS_STORAGE_STATES ( 0xf )
+enum dfs_ManagerVersion
+#ifndef USE_UINT_ENUMS
+ {
+ DFS_MANAGER_VERSION_NT4=1,
+ DFS_MANAGER_VERSION_W2K=2,
+ DFS_MANAGER_VERSION_W2K3=4,
+ DFS_MANAGER_VERSION_W2K8=6
+}
+#else
+ { __donnot_use_enum_dfs_ManagerVersion=0x7FFFFFFF}
+#define DFS_MANAGER_VERSION_NT4 ( 1 )
+#define DFS_MANAGER_VERSION_W2K ( 2 )
+#define DFS_MANAGER_VERSION_W2K3 ( 4 )
+#define DFS_MANAGER_VERSION_W2K8 ( 6 )
+#endif
+;
+
+struct dfs_Info0 {
+ char _empty_;
+};
+
+struct dfs_Info1 {
+ const char *path;/* [unique,charset(UTF16)] */
+};
+
+/* bitmap dfs_VolumeState */
+#define DFS_VOLUME_STATE_OK ( 0x1 )
+#define DFS_VOLUME_STATE_INCONSISTENT ( 0x2 )
+#define DFS_VOLUME_STATE_OFFLINE ( 0x3 )
+#define DFS_VOLUME_STATE_ONLINE ( 0x4 )
+#define DFS_VOLUME_STATE_STANDALONE ( DFS_VOLUME_FLAVOR_STANDALONE )
+#define DFS_VOLUME_STATE_AD_BLOB ( DFS_VOLUME_FLAVOR_AD_BLOB )
+
+struct dfs_Info2 {
+ const char *path;/* [unique,charset(UTF16)] */
+ const char *comment;/* [unique,charset(UTF16)] */
+ uint32_t state;
+ uint32_t num_stores;
+};
+
+/* bitmap dfs_StorageState */
+#define DFS_STORAGE_STATE_OFFLINE ( 1 )
+#define DFS_STORAGE_STATE_ONLINE ( 2 )
+#define DFS_STORAGE_STATE_ACTIVE ( 4 )
+
+struct dfs_StorageInfo {
+ uint32_t state;
+ const char *server;/* [unique,charset(UTF16)] */
+ const char *share;/* [unique,charset(UTF16)] */
+};
+
+struct dfs_Info3 {
+ const char *path;/* [unique,charset(UTF16)] */
+ const char *comment;/* [unique,charset(UTF16)] */
+ uint32_t state;
+ uint32_t num_stores;
+ struct dfs_StorageInfo *stores;/* [unique,size_is(num_stores)] */
+};
+
+struct dfs_Info4 {
+ const char *path;/* [unique,charset(UTF16)] */
+ const char *comment;/* [unique,charset(UTF16)] */
+ uint32_t state;
+ uint32_t timeout;
+ struct GUID guid;
+ uint32_t num_stores;
+ struct dfs_StorageInfo *stores;/* [unique,size_is(num_stores)] */
+};
+
+/* bitmap dfs_PropertyFlags */
+#define DFS_PROPERTY_FLAG_INSITE_REFERRALS ( 0x01 )
+#define DFS_PROPERTY_FLAG_ROOT_SCALABILITY ( 0x02 )
+#define DFS_PROPERTY_FLAG_SITE_COSTING ( 0x04 )
+#define DFS_PROPERTY_FLAG_TARGET_FAILBACK ( 0x08 )
+#define DFS_PROPERTY_FLAG_CLUSTER_ENABLED ( 0x10 )
+
+struct dfs_Info5 {
+ const char *path;/* [unique,charset(UTF16)] */
+ const char *comment;/* [unique,charset(UTF16)] */
+ uint32_t state;
+ uint32_t timeout;
+ struct GUID guid;
+ uint32_t flags;
+ uint32_t pktsize;
+ uint32_t num_stores;
+};
+
+enum dfs_Target_PriorityClass
+#ifndef USE_UINT_ENUMS
+ {
+ DFS_INVALID_PRIORITY_CLASS=-1,
+ DFS_SITE_COST_NORMAL_PRIORITY_CLASS=0,
+ DFS_GLOBAL_HIGH_PRIORITY_CLASS=1,
+ DFS_SITE_COST_HIGH_PRIORITY_CLASS=2,
+ DFS_SITE_COST_LOW_PRIORITY_CLASS=3,
+ DFS_GLOBAL_LOW_PRIORITY_CLASS=4
+}
+#else
+ { __donnot_use_enum_dfs_Target_PriorityClass=0x7FFFFFFF}
+#define DFS_INVALID_PRIORITY_CLASS ( -1 )
+#define DFS_SITE_COST_NORMAL_PRIORITY_CLASS ( 0 )
+#define DFS_GLOBAL_HIGH_PRIORITY_CLASS ( 1 )
+#define DFS_SITE_COST_HIGH_PRIORITY_CLASS ( 2 )
+#define DFS_SITE_COST_LOW_PRIORITY_CLASS ( 3 )
+#define DFS_GLOBAL_LOW_PRIORITY_CLASS ( 4 )
+#endif
+;
+
+struct dfs_Target_Priority {
+ enum dfs_Target_PriorityClass target_priority_class;
+ uint16_t target_priority_rank;
+ uint16_t reserved;
+};
+
+struct dfs_StorageInfo2 {
+ struct dfs_StorageInfo info;
+ struct dfs_Target_Priority target_priority;
+};
+
+struct dfs_Info6 {
+ const char *entry_path;/* [unique,charset(UTF16)] */
+ const char *comment;/* [unique,charset(UTF16)] */
+ uint32_t state;
+ uint32_t timeout;
+ struct GUID guid;
+ uint32_t flags;
+ uint32_t pktsize;
+ uint16_t num_stores;
+ struct dfs_StorageInfo2 *stores;/* [unique,size_is(num_stores)] */
+};
+
+struct dfs_Info7 {
+ struct GUID generation_guid;
+};
+
+struct dfs_Info100 {
+ const char *comment;/* [unique,charset(UTF16)] */
+};
+
+struct dfs_Info101 {
+ uint32_t state;
+};
+
+struct dfs_Info102 {
+ uint32_t timeout;
+};
+
+struct dfs_Info103 {
+ uint32_t flags;
+};
+
+struct dfs_Info104 {
+ struct dfs_Target_Priority priority;
+};
+
+struct dfs_Info105 {
+ const char *comment;/* [unique,charset(UTF16)] */
+ uint32_t state;
+ uint32_t timeout;
+ uint32_t property_flag_mask;
+ uint32_t property_flags;
+};
+
+struct dfs_Info106 {
+ uint32_t state;
+ struct dfs_Target_Priority priority;
+};
+
+struct dfs_Info200 {
+ const char *dom_root;/* [unique,charset(UTF16)] */
+};
+
+enum dfs_VolumeFlavor
+#ifndef USE_UINT_ENUMS
+ {
+ DFS_VOLUME_FLAVOR_STANDALONE=0x100,
+ DFS_VOLUME_FLAVOR_AD_BLOB=0x200
+}
+#else
+ { __donnot_use_enum_dfs_VolumeFlavor=0x7FFFFFFF}
+#define DFS_VOLUME_FLAVOR_STANDALONE ( 0x100 )
+#define DFS_VOLUME_FLAVOR_AD_BLOB ( 0x200 )
+#endif
+;
+
+struct dfs_Info300 {
+ enum dfs_VolumeFlavor flavor;
+ const char *dom_root;/* [unique,charset(UTF16)] */
+};
+
+union dfs_Info {
+ struct dfs_Info0 *info0;/* [unique,case(0)] */
+ struct dfs_Info1 *info1;/* [unique,case] */
+ struct dfs_Info2 *info2;/* [unique,case(2)] */
+ struct dfs_Info3 *info3;/* [unique,case(3)] */
+ struct dfs_Info4 *info4;/* [unique,case(4)] */
+ struct dfs_Info5 *info5;/* [unique,case(5)] */
+ struct dfs_Info6 *info6;/* [unique,case(6)] */
+ struct dfs_Info7 *info7;/* [unique,case(7)] */
+ struct dfs_Info100 *info100;/* [unique,case(100)] */
+ struct dfs_Info101 *info101;/* [unique,case(101)] */
+ struct dfs_Info102 *info102;/* [unique,case(102)] */
+ struct dfs_Info103 *info103;/* [unique,case(103)] */
+ struct dfs_Info104 *info104;/* [unique,case(104)] */
+ struct dfs_Info105 *info105;/* [unique,case(105)] */
+ struct dfs_Info106 *info106;/* [unique,case(106)] */
+};
+
+struct dfs_EnumArray1 {
+ uint32_t count;
+ struct dfs_Info1 *s;/* [unique,size_is(count)] */
+};
+
+struct dfs_EnumArray2 {
+ uint32_t count;
+ struct dfs_Info2 *s;/* [unique,size_is(count)] */
+};
+
+struct dfs_EnumArray3 {
+ uint32_t count;
+ struct dfs_Info3 *s;/* [unique,size_is(count)] */
+};
+
+struct dfs_EnumArray4 {
+ uint32_t count;
+ struct dfs_Info4 *s;/* [unique,size_is(count)] */
+};
+
+struct dfs_EnumArray5 {
+ uint32_t count;
+ struct dfs_Info5 *s;/* [unique,size_is(count)] */
+};
+
+struct dfs_EnumArray6 {
+ uint32_t count;
+ struct dfs_Info6 *s;/* [unique,size_is(count)] */
+};
+
+struct dfs_EnumArray200 {
+ uint32_t count;
+ struct dfs_Info200 *s;/* [unique,size_is(count)] */
+};
+
+struct dfs_EnumArray300 {
+ uint32_t count;
+ struct dfs_Info300 *s;/* [unique,size_is(count)] */
+};
+
+union dfs_EnumInfo {
+ struct dfs_EnumArray1 *info1;/* [unique,case] */
+ struct dfs_EnumArray2 *info2;/* [unique,case(2)] */
+ struct dfs_EnumArray3 *info3;/* [unique,case(3)] */
+ struct dfs_EnumArray4 *info4;/* [unique,case(4)] */
+ struct dfs_EnumArray5 *info5;/* [unique,case(5)] */
+ struct dfs_EnumArray6 *info6;/* [unique,case(6)] */
+ struct dfs_EnumArray200 *info200;/* [unique,case(200)] */
+ struct dfs_EnumArray300 *info300;/* [unique,case(300)] */
+};
+
+struct dfs_EnumStruct {
+ uint32_t level;
+ union dfs_EnumInfo e;/* [switch_is(level)] */
+};
+
+struct dfs_UnknownStruct {
+ uint32_t unknown1;
+ const char *unknown2;/* [unique,charset(UTF16)] */
+};
+
+
+struct dfs_GetManagerVersion {
+ struct {
+ enum dfs_ManagerVersion *version;/* [ref] */
+ } out;
+
+};
+
+
+struct dfs_Add {
+ struct {
+ const char *path;/* [ref,charset(UTF16)] */
+ const char *server;/* [ref,charset(UTF16)] */
+ const char *share;/* [unique,charset(UTF16)] */
+ const char *comment;/* [unique,charset(UTF16)] */
+ uint32_t flags;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_Remove {
+ struct {
+ const char *dfs_entry_path;/* [ref,charset(UTF16)] */
+ const char *servername;/* [unique,charset(UTF16)] */
+ const char *sharename;/* [unique,charset(UTF16)] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_SetInfo {
+ struct {
+ const char *dfs_entry_path;/* [charset(UTF16)] */
+ const char *servername;/* [unique,charset(UTF16)] */
+ const char *sharename;/* [unique,charset(UTF16)] */
+ uint32_t level;
+ union dfs_Info *info;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_GetInfo {
+ struct {
+ const char *dfs_entry_path;/* [charset(UTF16)] */
+ const char *servername;/* [unique,charset(UTF16)] */
+ const char *sharename;/* [unique,charset(UTF16)] */
+ uint32_t level;
+ } in;
+
+ struct {
+ union dfs_Info *info;/* [ref,switch_is(level)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_Enum {
+ struct {
+ uint32_t level;
+ uint32_t bufsize;
+ struct dfs_EnumStruct *info;/* [unique] */
+ uint32_t *total;/* [unique] */
+ } in;
+
+ struct {
+ struct dfs_EnumStruct *info;/* [unique] */
+ uint32_t *total;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_Rename {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_Move {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_ManagerGetConfigInfo {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_ManagerSendSiteInfo {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_AddFtRoot {
+ struct {
+ const char *servername;/* [charset(UTF16)] */
+ const char *dns_servername;/* [charset(UTF16)] */
+ const char *dfsname;/* [charset(UTF16)] */
+ const char *rootshare;/* [charset(UTF16)] */
+ const char *comment;/* [charset(UTF16)] */
+ const char *dfs_config_dn;/* [charset(UTF16)] */
+ uint8_t unknown1;
+ uint32_t flags;
+ struct dfs_UnknownStruct **unknown2;/* [unique] */
+ } in;
+
+ struct {
+ struct dfs_UnknownStruct **unknown2;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_RemoveFtRoot {
+ struct {
+ const char *servername;/* [charset(UTF16)] */
+ const char *dns_servername;/* [charset(UTF16)] */
+ const char *dfsname;/* [charset(UTF16)] */
+ const char *rootshare;/* [charset(UTF16)] */
+ uint32_t flags;
+ struct dfs_UnknownStruct **unknown;/* [unique] */
+ } in;
+
+ struct {
+ struct dfs_UnknownStruct **unknown;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_AddStdRoot {
+ struct {
+ const char *servername;/* [charset(UTF16)] */
+ const char *rootshare;/* [charset(UTF16)] */
+ const char *comment;/* [charset(UTF16)] */
+ uint32_t flags;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_RemoveStdRoot {
+ struct {
+ const char *servername;/* [charset(UTF16)] */
+ const char *rootshare;/* [charset(UTF16)] */
+ uint32_t flags;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_ManagerInitialize {
+ struct {
+ const char *servername;/* [ref,charset(UTF16)] */
+ uint32_t flags;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_AddStdRootForced {
+ struct {
+ const char *servername;/* [charset(UTF16)] */
+ const char *rootshare;/* [charset(UTF16)] */
+ const char *comment;/* [charset(UTF16)] */
+ const char *store;/* [charset(UTF16)] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_GetDcAddress {
+ struct {
+ const char *servername;/* [charset(UTF16)] */
+ const char **server_fullname;/* [ref,charset(UTF16)] */
+ uint8_t *is_root;/* [ref] */
+ uint32_t *ttl;/* [ref] */
+ } in;
+
+ struct {
+ const char **server_fullname;/* [ref,charset(UTF16)] */
+ uint8_t *is_root;/* [ref] */
+ uint32_t *ttl;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_SetDcAddress {
+ struct {
+ const char *servername;/* [charset(UTF16)] */
+ const char *server_fullname;/* [charset(UTF16)] */
+ uint32_t flags;
+ uint32_t ttl;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_FlushFtTable {
+ struct {
+ const char *servername;/* [charset(UTF16)] */
+ const char *rootshare;/* [charset(UTF16)] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_Add2 {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_Remove2 {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_EnumEx {
+ struct {
+ const char *dfs_name;/* [charset(UTF16)] */
+ uint32_t level;
+ uint32_t bufsize;
+ struct dfs_EnumStruct *info;/* [unique] */
+ uint32_t *total;/* [unique] */
+ } in;
+
+ struct {
+ struct dfs_EnumStruct *info;/* [unique] */
+ uint32_t *total;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct dfs_SetInfo2 {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+#endif /* _HEADER_netdfs */
diff --git a/source3/librpc/gen_ndr/drsblobs.h b/source3/librpc/gen_ndr/drsblobs.h
new file mode 100644
index 0000000000..b0ab9aea2a
--- /dev/null
+++ b/source3/librpc/gen_ndr/drsblobs.h
@@ -0,0 +1,427 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#include "librpc/gen_ndr/drsuapi.h"
+#include "librpc/gen_ndr/misc.h"
+#ifndef _HEADER_drsblobs
+#define _HEADER_drsblobs
+
+#define SUPPLEMENTAL_CREDENTIALS_PREFIX ( " " )
+enum drsuapi_DsAttributeId;
+
+struct replPropertyMetaData1 {
+ enum drsuapi_DsAttributeId attid;
+ uint32_t version;
+ NTTIME originating_change_time;
+ struct GUID originating_invocation_id;
+ uint64_t originating_usn;
+ uint64_t local_usn;
+};
+
+struct replPropertyMetaDataCtr1 {
+ uint32_t count;
+ uint32_t reserved;
+ struct replPropertyMetaData1 *array;
+};
+
+union replPropertyMetaDataCtr {
+ struct replPropertyMetaDataCtr1 ctr1;/* [case] */
+}/* [nodiscriminant] */;
+
+struct replPropertyMetaDataBlob {
+ uint32_t version;
+ uint32_t reserved;
+ union replPropertyMetaDataCtr ctr;/* [switch_is(version)] */
+}/* [public] */;
+
+struct replUpToDateVectorCtr1 {
+ uint32_t count;
+ uint32_t reserved;
+ struct drsuapi_DsReplicaCursor *cursors;
+};
+
+struct replUpToDateVectorCtr2 {
+ uint32_t count;
+ uint32_t reserved;
+ struct drsuapi_DsReplicaCursor2 *cursors;
+};
+
+union replUpToDateVectorCtr {
+ struct replUpToDateVectorCtr1 ctr1;/* [case] */
+ struct replUpToDateVectorCtr2 ctr2;/* [case(2)] */
+}/* [nodiscriminant] */;
+
+struct replUpToDateVectorBlob {
+ uint32_t version;
+ uint32_t reserved;
+ union replUpToDateVectorCtr ctr;/* [switch_is(version)] */
+}/* [public] */;
+
+struct repsFromTo1OtherInfo {
+ uint32_t __dns_name_size;/* [value(strlen(dns_name)+1)] */
+ const char *dns_name;/* [charset(DOS)] */
+}/* [gensize,public] */;
+
+struct repsFromTo1 {
+ uint32_t blobsize;/* [value(ndr_size_repsFromTo1(this,ndr->flags)+8)] */
+ uint32_t consecutive_sync_failures;
+ NTTIME last_success;
+ NTTIME last_attempt;
+ WERROR result_last_attempt;
+ struct repsFromTo1OtherInfo *other_info;/* [relative] */
+ uint32_t other_info_length;/* [value(ndr_size_repsFromTo1OtherInfo(other_info,ndr->flags))] */
+ uint32_t replica_flags;
+ uint8_t schedule[84];
+ uint32_t reserved;
+ struct drsuapi_DsReplicaHighWaterMark highwatermark;
+ struct GUID source_dsa_obj_guid;
+ struct GUID source_dsa_invocation_id;
+ struct GUID transport_guid;
+}/* [gensize,public,flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+union repsFromTo {
+ struct repsFromTo1 ctr1;/* [case] */
+}/* [nodiscriminant] */;
+
+struct repsFromToBlob {
+ uint32_t version;
+ uint32_t reserved;
+ union repsFromTo ctr;/* [switch_is(version)] */
+}/* [public] */;
+
+struct partialAttributeSetCtr1 {
+ uint32_t count;
+ enum drsuapi_DsAttributeId *array;
+};
+
+union partialAttributeSetCtr {
+ struct partialAttributeSetCtr1 ctr1;/* [case] */
+}/* [nodiscriminant] */;
+
+struct partialAttributeSetBlob {
+ uint32_t version;
+ uint32_t reserved;
+ union partialAttributeSetCtr ctr;/* [switch_is(version)] */
+}/* [public] */;
+
+enum prefixMapVersion
+#ifndef USE_UINT_ENUMS
+ {
+ PREFIX_MAP_VERSION_DSDB=0x44534442
+}
+#else
+ { __donnot_use_enum_prefixMapVersion=0x7FFFFFFF}
+#define PREFIX_MAP_VERSION_DSDB ( 0x44534442 )
+#endif
+;
+
+union prefixMapCtr {
+ struct drsuapi_DsReplicaOIDMapping_Ctr dsdb;/* [case(PREFIX_MAP_VERSION_DSDB)] */
+}/* [nodiscriminant] */;
+
+struct prefixMapBlob {
+ enum prefixMapVersion version;
+ uint32_t reserved;
+ union prefixMapCtr ctr;/* [switch_is(version)] */
+}/* [public] */;
+
+union ldapControlDirSyncExtra {
+ struct replUpToDateVectorBlob uptodateness_vector;/* [default] */
+}/* [gensize,nodiscriminant] */;
+
+struct ldapControlDirSyncBlob {
+ uint32_t u1;/* [value(3)] */
+ NTTIME time;
+ uint32_t u2;
+ uint32_t u3;
+ uint32_t extra_length;/* [value(ndr_size_ldapControlDirSyncExtra(&extra,extra.uptodateness_vector.version,0))] */
+ struct drsuapi_DsReplicaHighWaterMark highwatermark;
+ struct GUID guid1;
+ union ldapControlDirSyncExtra extra;/* [switch_is(extra_length)] */
+};
+
+struct ldapControlDirSyncCookie {
+ const char *msds;/* [value("MSDS"),charset(DOS)] */
+ struct ldapControlDirSyncBlob blob;/* [subcontext(0)] */
+}/* [relative_base,public] */;
+
+struct supplementalCredentialsPackage {
+ uint16_t name_len;/* [value(2*strlen_m(name))] */
+ uint16_t data_len;/* [value(strlen(data))] */
+ uint16_t reserved;
+ const char *name;/* [charset(UTF16)] */
+ const char *data;/* [charset(DOS)] */
+};
+
+enum supplementalCredentialsSignature
+#ifndef USE_UINT_ENUMS
+ {
+ SUPPLEMENTAL_CREDENTIALS_SIGNATURE=0x0050
+}
+#else
+ { __donnot_use_enum_supplementalCredentialsSignature=0x7FFFFFFF}
+#define SUPPLEMENTAL_CREDENTIALS_SIGNATURE ( 0x0050 )
+#endif
+;
+
+struct supplementalCredentialsSubBlob {
+ const char *prefix;/* [value(SUPPLEMENTAL_CREDENTIALS_PREFIX),charset(UTF16)] */
+ enum supplementalCredentialsSignature signature;/* [value(SUPPLEMENTAL_CREDENTIALS_SIGNATURE)] */
+ uint16_t num_packages;
+ struct supplementalCredentialsPackage *packages;
+}/* [gensize] */;
+
+struct supplementalCredentialsBlob {
+ uint32_t unknown1;/* [value(0)] */
+ uint32_t __ndr_size;/* [value(ndr_size_supplementalCredentialsSubBlob(&sub,ndr->flags))] */
+ uint32_t unknown2;/* [value(0)] */
+ struct supplementalCredentialsSubBlob sub;/* [subcontext_size(__ndr_size),subcontext(0)] */
+ uint8_t unknown3;/* [value(0)] */
+}/* [public] */;
+
+struct package_PackagesBlob {
+ const char ** names;/* [flag(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING)] */
+}/* [public] */;
+
+struct package_PrimaryKerberosString {
+ uint16_t length;/* [value(2*strlen_m(string))] */
+ uint16_t size;/* [value(2*strlen_m(string))] */
+ const char * string;/* [relative,subcontext_size(size),subcontext(0),flag(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING)] */
+};
+
+struct package_PrimaryKerberosKey3 {
+ uint16_t reserved1;/* [value(0)] */
+ uint16_t reserved2;/* [value(0)] */
+ uint32_t reserved3;/* [value(0)] */
+ uint32_t keytype;
+ uint32_t value_len;/* [value((value?value->length:0))] */
+ DATA_BLOB *value;/* [relative,subcontext_size(value_len),subcontext(0),flag(LIBNDR_FLAG_REMAINING)] */
+};
+
+struct package_PrimaryKerberosCtr3 {
+ uint16_t num_keys;
+ uint16_t num_old_keys;
+ struct package_PrimaryKerberosString salt;
+ struct package_PrimaryKerberosKey3 *keys;
+ struct package_PrimaryKerberosKey3 *old_keys;
+ uint32_t padding1;/* [value(0)] */
+ uint32_t padding2;/* [value(0)] */
+ uint32_t padding3;/* [value(0)] */
+ uint32_t padding4;/* [value(0)] */
+ uint32_t padding5;/* [value(0)] */
+};
+
+struct package_PrimaryKerberosKey4 {
+ uint16_t reserved1;/* [value(0)] */
+ uint16_t reserved2;/* [value(0)] */
+ uint32_t reserved3;/* [value(0)] */
+ uint32_t iteration_count;
+ uint32_t keytype;
+ uint32_t value_len;/* [value((value?value->length:0))] */
+ DATA_BLOB *value;/* [relative,subcontext_size(value_len),subcontext(0),flag(LIBNDR_FLAG_REMAINING)] */
+};
+
+struct package_PrimaryKerberosCtr4 {
+ uint16_t num_keys;
+ uint16_t num_service_keys;/* [value(0)] */
+ uint16_t num_old_keys;
+ uint16_t num_older_keys;
+ struct package_PrimaryKerberosString salt;
+ uint32_t default_iteration_count;
+ struct package_PrimaryKerberosKey4 *keys;
+ struct package_PrimaryKerberosKey4 *service_keys;
+ struct package_PrimaryKerberosKey4 *old_keys;
+ struct package_PrimaryKerberosKey4 *older_keys;
+};
+
+union package_PrimaryKerberosCtr {
+ struct package_PrimaryKerberosCtr3 ctr3;/* [case(3)] */
+ struct package_PrimaryKerberosCtr4 ctr4;/* [case(4)] */
+}/* [nodiscriminant] */;
+
+struct package_PrimaryKerberosBlob {
+ uint16_t version;
+ uint16_t flags;/* [value(0)] */
+ union package_PrimaryKerberosCtr ctr;/* [switch_is(version)] */
+}/* [public] */;
+
+struct package_PrimaryCLEARTEXTBlob {
+ const char * cleartext;/* [flag(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING)] */
+}/* [public] */;
+
+struct package_PrimaryWDigestHash {
+ uint8_t hash[16];
+}/* [flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+struct package_PrimaryWDigestBlob {
+ uint16_t unknown1;/* [value(0x31)] */
+ uint8_t unknown2;/* [value(0x01)] */
+ uint8_t num_hashes;
+ uint32_t unknown3;/* [value(0)] */
+ uint64_t uuknown4;/* [value(0)] */
+ struct package_PrimaryWDigestHash *hashes;
+}/* [public] */;
+
+struct trustAuthInOutSecret1 {
+ NTTIME time1;
+ uint32_t unknown1;
+ DATA_BLOB value;
+ DATA_BLOB _pad;/* [flag(LIBNDR_FLAG_ALIGN4)] */
+};
+
+struct trustAuthInOutCtr1 {
+ struct trustAuthInOutSecret1 *value1;/* [relative] */
+ struct trustAuthInOutSecret1 *value2;/* [relative] */
+};
+
+struct trustAuthInOutSecret2V1 {
+ NTTIME time1;
+ uint32_t unknown1;
+ DATA_BLOB value;
+ NTTIME time2;
+ uint32_t unknown2;
+ uint32_t unknown3;
+ uint32_t unknown4;
+ DATA_BLOB _pad;/* [flag(LIBNDR_FLAG_ALIGN4)] */
+};
+
+struct trustAuthInOutSecret2V2 {
+ NTTIME time1;
+ uint32_t unknown1;
+ DATA_BLOB value;
+ NTTIME time2;
+ uint32_t unknown2;
+ uint32_t unknown3;
+ DATA_BLOB _pad;/* [flag(LIBNDR_FLAG_ALIGN4)] */
+};
+
+struct trustAuthInOutCtr2 {
+ struct trustAuthInOutSecret2V1 *value1;/* [relative] */
+ struct trustAuthInOutSecret2V2 *value2;/* [relative] */
+};
+
+union trustAuthInOutCtr {
+ struct trustAuthInOutCtr1 ctr1;/* [case] */
+ struct trustAuthInOutCtr2 ctr2;/* [case(2)] */
+}/* [nodiscriminant] */;
+
+struct trustAuthInOutBlob {
+ uint32_t version;
+ union trustAuthInOutCtr ctr;/* [switch_is(version)] */
+}/* [public] */;
+
+struct DsCompressedChunk {
+ uint32_t marker;
+ DATA_BLOB data;
+}/* [public] */;
+
+struct DsCompressedBlob {
+ struct DsCompressedChunk chunks[5];
+}/* [public] */;
+
+
+struct decode_replPropertyMetaData {
+ struct {
+ struct replPropertyMetaDataBlob blob;
+ } in;
+
+};
+
+
+struct decode_replUpToDateVector {
+ struct {
+ struct replUpToDateVectorBlob blob;
+ } in;
+
+};
+
+
+struct decode_repsFromTo {
+ struct {
+ struct repsFromToBlob blob;
+ } in;
+
+};
+
+
+struct decode_partialAttributeSet {
+ struct {
+ struct partialAttributeSetBlob blob;
+ } in;
+
+};
+
+
+struct decode_prefixMap {
+ struct {
+ struct prefixMapBlob blob;
+ } in;
+
+};
+
+
+struct decode_ldapControlDirSync {
+ struct {
+ struct ldapControlDirSyncCookie cookie;
+ } in;
+
+};
+
+
+struct decode_supplementalCredentials {
+ struct {
+ struct supplementalCredentialsBlob blob;
+ } in;
+
+};
+
+
+struct decode_Packages {
+ struct {
+ struct package_PackagesBlob blob;
+ } in;
+
+};
+
+
+struct decode_PrimaryKerberos {
+ struct {
+ struct package_PrimaryKerberosBlob blob;
+ } in;
+
+};
+
+
+struct decode_PrimaryCLEARTEXT {
+ struct {
+ struct package_PrimaryCLEARTEXTBlob blob;
+ } in;
+
+};
+
+
+struct decode_PrimaryWDigest {
+ struct {
+ struct package_PrimaryWDigestBlob blob;
+ } in;
+
+};
+
+
+struct decode_trustAuthInOut {
+ struct {
+ struct trustAuthInOutBlob blob;
+ } in;
+
+};
+
+
+struct decode_DsCompressed {
+ struct {
+ struct DsCompressedBlob blob;
+ } in;
+
+};
+
+#endif /* _HEADER_drsblobs */
diff --git a/source3/librpc/gen_ndr/drsuapi.h b/source3/librpc/gen_ndr/drsuapi.h
new file mode 100644
index 0000000000..049c2bf4b1
--- /dev/null
+++ b/source3/librpc/gen_ndr/drsuapi.h
@@ -0,0 +1,1762 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#include "librpc/gen_ndr/security.h"
+#include "librpc/gen_ndr/misc.h"
+#include "librpc/gen_ndr/samr.h"
+#ifndef _HEADER_drsuapi
+#define _HEADER_drsuapi
+
+#define DRSUAPI_DS_BIND_GUID ( "e24d201a-4fd6-11d1-a3da-0000f875ae0d" )
+#define DRSUAPI_DS_BIND_GUID_W2K ( "6abec3d1-3054-41c8-a362-5a0c5b7d5d71" )
+#define DRSUAPI_DS_BIND_GUID_W2K3 ( "6afab99c-6e26-464a-975f-f58f105218bc" )
+#define DRSUAPI_DS_MEMBERSHIP_FLAG_GROUP_ATTR ( 0x1 )
+#define DRSUAPI_NTDSDSA_KRB5_SERVICE_GUID ( "E3514235-4B06-11D1-AB04-00C04FC2DCD2" )
+/* bitmap drsuapi_SupportedExtensions */
+#define DRSUAPI_SUPPORTED_EXTENSION_BASE ( 0x00000001 )
+#define DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION ( 0x00000002 )
+#define DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI ( 0x00000004 )
+#define DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2 ( 0x00000008 )
+#define DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS ( 0x00000010 )
+#define DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1 ( 0x00000020 )
+#define DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION ( 0x00000040 )
+#define DRSUAPI_SUPPORTED_EXTENSION_00000080 ( 0x00000080 )
+#define DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE ( 0x00000100 )
+#define DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2 ( 0x00000200 )
+#define DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION ( 0x00000400 )
+#define DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2 ( 0x00000800 )
+#define DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD ( 0x00001000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND ( 0x00002000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO ( 0x00004000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION ( 0x00008000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01 ( 0x00010000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP ( 0x00020000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY ( 0x00040000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3 ( 0x00080000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_00100000 ( 0x00100000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2 ( 0x00200000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6 ( 0x00400000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS ( 0x00800000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8 ( 0x01000000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5 ( 0x02000000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6 ( 0x04000000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3 ( 0x08000000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7 ( 0x08000000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT ( 0x08000000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS ( 0x10000000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_20000000 ( 0x20000000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_40000000 ( 0x40000000 )
+#define DRSUAPI_SUPPORTED_EXTENSION_80000000 ( 0x80000000 )
+
+/* bitmap drsuapi_SupportedExtensionsExt */
+#define DRSUAPI_SUPPORTED_EXTENSION_ADAM ( 0x00000001 )
+#define DRSUAPI_SUPPORTED_EXTENSION_LH_BETA2 ( 0x00000002 )
+
+struct drsuapi_DsBindInfo24 {
+ uint32_t supported_extensions;
+ struct GUID site_guid;
+ uint32_t pid;
+};
+
+struct drsuapi_DsBindInfo28 {
+ uint32_t supported_extensions;
+ struct GUID site_guid;
+ uint32_t pid;
+ uint32_t repl_epoch;
+};
+
+struct drsuapi_DsBindInfo48 {
+ uint32_t supported_extensions;
+ struct GUID site_guid;
+ uint32_t pid;
+ uint32_t repl_epoch;
+ uint32_t supported_extensions_ext;
+ struct GUID config_dn_guid;
+};
+
+struct drsuapi_DsBindInfoFallBack {
+ DATA_BLOB info;/* [flag(LIBNDR_FLAG_REMAINING)] */
+};
+
+union drsuapi_DsBindInfo {
+ struct drsuapi_DsBindInfo24 info24;/* [subcontext(4),case(24)] */
+ struct drsuapi_DsBindInfo28 info28;/* [subcontext(4),case(28)] */
+ struct drsuapi_DsBindInfo48 info48;/* [subcontext(4),case(48)] */
+ struct drsuapi_DsBindInfoFallBack FallBack;/* [subcontext(4),default] */
+}/* [nodiscriminant] */;
+
+struct drsuapi_DsBindInfoCtr {
+ uint32_t length;/* [range(1,10000)] */
+ union drsuapi_DsBindInfo info;/* [switch_is(length)] */
+};
+
+struct drsuapi_DsReplicaObjectIdentifier {
+ uint32_t __ndr_size;/* [value(ndr_size_drsuapi_DsReplicaObjectIdentifier(r,ndr->flags)-4)] */
+ uint32_t __ndr_size_sid;/* [value(ndr_size_dom_sid28(&sid,ndr->flags))] */
+ struct GUID guid;
+ struct dom_sid28 sid;
+ uint32_t __ndr_size_dn;/* [value(strlen_m(dn))] */
+ const char *dn;/* [charset(UTF16),size_is(__ndr_size_dn+1)] */
+}/* [gensize,public] */;
+
+/* bitmap drsuapi_DsReplicaSyncOptions */
+#define DRSUAPI_DS_REPLICA_SYNC_ASYNCHRONOUS_OPERATION ( 0x00000001 )
+#define DRSUAPI_DS_REPLICA_SYNC_WRITEABLE ( 0x00000002 )
+#define DRSUAPI_DS_REPLICA_SYNC_PERIODIC ( 0x00000004 )
+#define DRSUAPI_DS_REPLICA_SYNC_INTERSITE_MESSAGING ( 0x00000008 )
+#define DRSUAPI_DS_REPLICA_SYNC_ALL_SOURCES ( 0x00000010 )
+#define DRSUAPI_DS_REPLICA_SYNC_FULL ( 0x00000020 )
+#define DRSUAPI_DS_REPLICA_SYNC_URGENT ( 0x00000040 )
+#define DRSUAPI_DS_REPLICA_SYNC_NO_DISCARD ( 0x00000080 )
+#define DRSUAPI_DS_REPLICA_SYNC_FORCE ( 0x00000100 )
+#define DRSUAPI_DS_REPLICA_SYNC_ADD_REFERENCE ( 0x00000200 )
+#define DRSUAPI_DS_REPLICA_SYNC_NEVER_COMPLETED ( 0x00000400 )
+#define DRSUAPI_DS_REPLICA_SYNC_TWO_WAY ( 0x00000800 )
+#define DRSUAPI_DS_REPLICA_SYNC_NEVER_NOTIFY ( 0x00001000 )
+#define DRSUAPI_DS_REPLICA_SYNC_INITIAL ( 0x00002000 )
+#define DRSUAPI_DS_REPLICA_SYNC_USE_COMPRESSION ( 0x00004000 )
+#define DRSUAPI_DS_REPLICA_SYNC_ABANDONED ( 0x00008000 )
+#define DRSUAPI_DS_REPLICA_SYNC_INITIAL_IN_PROGRESS ( 0x00010000 )
+#define DRSUAPI_DS_REPLICA_SYNC_PARTIAL_ATTRIBUTE_SET ( 0x00020000 )
+#define DRSUAPI_DS_REPLICA_SYNC_REQUEUE ( 0x00040000 )
+#define DRSUAPI_DS_REPLICA_SYNC_NOTIFICATION ( 0x00080000 )
+#define DRSUAPI_DS_REPLICA_SYNC_ASYNCHRONOUS_REPLICA ( 0x00100000 )
+#define DRSUAPI_DS_REPLICA_SYNC_CRITICAL ( 0x00200000 )
+#define DRSUAPI_DS_REPLICA_SYNC_FULL_IN_PROGRESS ( 0x00400000 )
+#define DRSUAPI_DS_REPLICA_SYNC_PREEMPTED ( 0x00800000 )
+
+struct drsuapi_DsReplicaSyncRequest1 {
+ struct drsuapi_DsReplicaObjectIdentifier *naming_context;/* [unique] */
+ struct GUID source_dsa_guid;
+ const char * other_info;/* [unique,flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+ uint32_t options;
+};
+
+union drsuapi_DsReplicaSyncRequest {
+ struct drsuapi_DsReplicaSyncRequest1 req1;/* [case] */
+}/* [switch_type(int32)] */;
+
+struct drsuapi_DsReplicaHighWaterMark {
+ uint64_t tmp_highest_usn;
+ uint64_t reserved_usn;
+ uint64_t highest_usn;
+}/* [public] */;
+
+struct drsuapi_DsReplicaCursor {
+ struct GUID source_dsa_invocation_id;
+ uint64_t highest_usn;
+}/* [public] */;
+
+struct drsuapi_DsReplicaCursorCtrEx {
+ uint32_t version;/* [value] */
+ uint32_t reserved1;/* [value(0)] */
+ uint32_t count;/* [range(0,0x100000)] */
+ uint32_t reserved2;/* [value(0)] */
+ struct drsuapi_DsReplicaCursor *cursors;/* [size_is(count)] */
+};
+
+/* bitmap drsuapi_DsReplicaNeighbourFlags */
+#define DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE ( 0x00000010 )
+#define DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP ( 0x00000020 )
+#define DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS ( 0x00000040 )
+#define DRSUAPI_DS_REPLICA_NEIGHBOUR_USE_ASYNC_INTERSIDE_TRANSPORT ( 0x00000080 )
+#define DRSUAPI_DS_REPLICA_NEIGHBOUR_TWO_WAY_SYNC ( 0x00000200 )
+#define DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS ( 0x00000800 )
+#define DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS ( 0x00001000 )
+#define DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_NEXT_PACKET ( 0x00002000 )
+#define DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED ( 0x00200000 )
+#define DRSUAPI_DS_REPLICA_NEIGHBOUR_PREEMPTED ( 0x01000000 )
+#define DRSUAPI_DS_REPLICA_NEIGHBOUR_IGNORE_CHANGE_NOTIFICATIONS ( 0x04000000 )
+#define DRSUAPI_DS_REPLICA_NEIGHBOUR_DISABLE_SCHEDULED_SYNC ( 0x08000000 )
+#define DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES ( 0x10000000 )
+#define DRSUAPI_DS_REPLICA_NEIGHBOUR_NO_CHANGE_NOTIFICATIONS ( 0x20000000 )
+#define DRSUAPI_DS_REPLICA_NEIGHBOUR_PARTIAL_ATTRIBUTE_SET ( 0x40000000 )
+
+enum drsuapi_DsExtendedOperation
+#ifndef USE_UINT_ENUMS
+ {
+ DRSUAPI_EXOP_NONE=0x00000000,
+ DRSUAPI_EXOP_FSMO_REQ_ROLE=0x00000001,
+ DRSUAPI_EXOP_FSMO_RID_ALLOC=0x00000002,
+ DRSUAPI_EXOP_FSMO_RID_REQ_ROLE=0x00000003,
+ DRSUAPI_EXOP_FSMO_REQ_PDC=0x00000004,
+ DRSUAPI_EXOP_FSMO_ABANDON_ROLE=0x00000005,
+ DRSUAPI_EXOP_REPL_OBJ=0x00000006,
+ DRSUAPI_EXOP_REPL_SECRET=0x00000007
+}
+#else
+ { __donnot_use_enum_drsuapi_DsExtendedOperation=0x7FFFFFFF}
+#define DRSUAPI_EXOP_NONE ( 0x00000000 )
+#define DRSUAPI_EXOP_FSMO_REQ_ROLE ( 0x00000001 )
+#define DRSUAPI_EXOP_FSMO_RID_ALLOC ( 0x00000002 )
+#define DRSUAPI_EXOP_FSMO_RID_REQ_ROLE ( 0x00000003 )
+#define DRSUAPI_EXOP_FSMO_REQ_PDC ( 0x00000004 )
+#define DRSUAPI_EXOP_FSMO_ABANDON_ROLE ( 0x00000005 )
+#define DRSUAPI_EXOP_REPL_OBJ ( 0x00000006 )
+#define DRSUAPI_EXOP_REPL_SECRET ( 0x00000007 )
+#endif
+;
+
+enum drsuapi_DsExtendedError
+#ifndef USE_UINT_ENUMS
+ {
+ DRSUAPI_EXOP_ERR_NONE=0x00000000,
+ DRSUAPI_EXOP_ERR_SUCCESS=0x00000001,
+ DRSUAPI_EXOP_ERR_UNKNOWN_OP=0x00000002,
+ DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER=0x00000003,
+ DRSUAPI_EXOP_ERR_UPDATE_ERR=0x00000004,
+ DRSUAPI_EXOP_ERR_EXCEPTION=0x00000005,
+ DRSUAPI_EXOP_ERR_UNKNOWN_CALLER=0x00000006,
+ DRSUAPI_EXOP_ERR_RID_ALLOC=0x00000007,
+ DRSUAPI_EXOP_ERR_FSMO_OWNER_DELETED=0x00000008,
+ DRSUAPI_EXOP_ERR_FMSO_PENDING_OP=0x00000009,
+ DRSUAPI_EXOP_ERR_MISMATCH=0x0000000A,
+ DRSUAPI_EXOP_ERR_COULDNT_CONTACT=0x0000000B,
+ DRSUAPI_EXOP_ERR_FSMO_REFUSING_ROLES=0x0000000C,
+ DRSUAPI_EXOP_ERR_DIR_ERROR=0x0000000D,
+ DRSUAPI_EXOP_ERR_FSMO_MISSING_SETTINGS=0x0000000E,
+ DRSUAPI_EXOP_ERR_ACCESS_DENIED=0x0000000F,
+ DRSUAPI_EXOP_ERR_PARAM_ERROR=0x00000010
+}
+#else
+ { __donnot_use_enum_drsuapi_DsExtendedError=0x7FFFFFFF}
+#define DRSUAPI_EXOP_ERR_NONE ( 0x00000000 )
+#define DRSUAPI_EXOP_ERR_SUCCESS ( 0x00000001 )
+#define DRSUAPI_EXOP_ERR_UNKNOWN_OP ( 0x00000002 )
+#define DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER ( 0x00000003 )
+#define DRSUAPI_EXOP_ERR_UPDATE_ERR ( 0x00000004 )
+#define DRSUAPI_EXOP_ERR_EXCEPTION ( 0x00000005 )
+#define DRSUAPI_EXOP_ERR_UNKNOWN_CALLER ( 0x00000006 )
+#define DRSUAPI_EXOP_ERR_RID_ALLOC ( 0x00000007 )
+#define DRSUAPI_EXOP_ERR_FSMO_OWNER_DELETED ( 0x00000008 )
+#define DRSUAPI_EXOP_ERR_FMSO_PENDING_OP ( 0x00000009 )
+#define DRSUAPI_EXOP_ERR_MISMATCH ( 0x0000000A )
+#define DRSUAPI_EXOP_ERR_COULDNT_CONTACT ( 0x0000000B )
+#define DRSUAPI_EXOP_ERR_FSMO_REFUSING_ROLES ( 0x0000000C )
+#define DRSUAPI_EXOP_ERR_DIR_ERROR ( 0x0000000D )
+#define DRSUAPI_EXOP_ERR_FSMO_MISSING_SETTINGS ( 0x0000000E )
+#define DRSUAPI_EXOP_ERR_ACCESS_DENIED ( 0x0000000F )
+#define DRSUAPI_EXOP_ERR_PARAM_ERROR ( 0x00000010 )
+#endif
+;
+
+struct drsuapi_DsGetNCChangesRequest5 {
+ struct GUID destination_dsa_guid;
+ struct GUID source_dsa_invocation_id;
+ struct drsuapi_DsReplicaObjectIdentifier *naming_context;/* [ref] */
+ struct drsuapi_DsReplicaHighWaterMark highwatermark;
+ struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;/* [unique] */
+ uint32_t replica_flags;
+ uint32_t max_object_count;
+ uint32_t max_ndr_size;
+ enum drsuapi_DsExtendedOperation extended_op;
+ uint64_t fsmo_info;
+};
+
+struct drsuapi_DsReplicaOID {
+ uint32_t __ndr_size;/* [value(ndr_size_drsuapi_DsReplicaOID_oid(oid,0)),range(0,10000)] */
+ const char *oid;/* [unique,charset(DOS),size_is(__ndr_size)] */
+}/* [nopush,nopull] */;
+
+struct drsuapi_DsReplicaOIDMapping {
+ uint32_t id_prefix;
+ struct drsuapi_DsReplicaOID oid;
+};
+
+struct drsuapi_DsReplicaOIDMapping_Ctr {
+ uint32_t num_mappings;/* [range(0,0x100000)] */
+ struct drsuapi_DsReplicaOIDMapping *mappings;/* [unique,size_is(num_mappings)] */
+}/* [public] */;
+
+enum drsuapi_DsObjectClassId
+#ifndef USE_UINT_ENUMS
+ {
+ DRSUAPI_OBJECTCLASS_top=0x00010000,
+ DRSUAPI_OBJECTCLASS_classSchema=0x0003000d,
+ DRSUAPI_OBJECTCLASS_attributeSchema=0x0003000e
+}
+#else
+ { __donnot_use_enum_drsuapi_DsObjectClassId=0x7FFFFFFF}
+#define DRSUAPI_OBJECTCLASS_top ( 0x00010000 )
+#define DRSUAPI_OBJECTCLASS_classSchema ( 0x0003000d )
+#define DRSUAPI_OBJECTCLASS_attributeSchema ( 0x0003000e )
+#endif
+;
+
+enum drsuapi_DsAttributeId
+#ifndef USE_UINT_ENUMS
+ {
+ DRSUAPI_ATTRIBUTE_objectClass=0x00000000,
+ DRSUAPI_ATTRIBUTE_description=0x0000000d,
+ DRSUAPI_ATTRIBUTE_member=0x0000001f,
+ DRSUAPI_ATTRIBUTE_instanceType=0x00020001,
+ DRSUAPI_ATTRIBUTE_whenCreated=0x00020002,
+ DRSUAPI_ATTRIBUTE_hasMasterNCs=0x0002000e,
+ DRSUAPI_ATTRIBUTE_governsID=0x00020016,
+ DRSUAPI_ATTRIBUTE_attributeID=0x0002001e,
+ DRSUAPI_ATTRIBUTE_attributeSyntax=0x00020020,
+ DRSUAPI_ATTRIBUTE_isSingleValued=0x00020021,
+ DRSUAPI_ATTRIBUTE_rangeLower=0x00020022,
+ DRSUAPI_ATTRIBUTE_rangeUpper=0x00020023,
+ DRSUAPI_ATTRIBUTE_dMDLocation=0x00020024,
+ DRSUAPI_ATTRIBUTE_objectVersion=0x0002004c,
+ DRSUAPI_ATTRIBUTE_invocationId=0x00020073,
+ DRSUAPI_ATTRIBUTE_showInAdvancedViewOnly=0x000200a9,
+ DRSUAPI_ATTRIBUTE_adminDisplayName=0x000200c2,
+ DRSUAPI_ATTRIBUTE_adminDescription=0x000200e2,
+ DRSUAPI_ATTRIBUTE_oMSyntax=0x000200e7,
+ DRSUAPI_ATTRIBUTE_ntSecurityDescriptor=0x00020119,
+ DRSUAPI_ATTRIBUTE_searchFlags=0x0002014e,
+ DRSUAPI_ATTRIBUTE_lDAPDisplayName=0x000201cc,
+ DRSUAPI_ATTRIBUTE_name=0x00090001,
+ DRSUAPI_ATTRIBUTE_userAccountControl=0x00090008,
+ DRSUAPI_ATTRIBUTE_currentValue=0x0009001b,
+ DRSUAPI_ATTRIBUTE_homeDirectory=0x0009002c,
+ DRSUAPI_ATTRIBUTE_homeDrive=0x0009002d,
+ DRSUAPI_ATTRIBUTE_scriptPath=0x0009003e,
+ DRSUAPI_ATTRIBUTE_profilePath=0x0009008b,
+ DRSUAPI_ATTRIBUTE_objectSid=0x00090092,
+ DRSUAPI_ATTRIBUTE_schemaIDGUID=0x00090094,
+ DRSUAPI_ATTRIBUTE_dBCSPwd=0x00090037,
+ DRSUAPI_ATTRIBUTE_logonHours=0x00090040,
+ DRSUAPI_ATTRIBUTE_userWorkstations=0x00090056,
+ DRSUAPI_ATTRIBUTE_unicodePwd=0x0009005a,
+ DRSUAPI_ATTRIBUTE_ntPwdHistory=0x0009005e,
+ DRSUAPI_ATTRIBUTE_priorValue=0x00090064,
+ DRSUAPI_ATTRIBUTE_supplementalCredentials=0x0009007d,
+ DRSUAPI_ATTRIBUTE_trustAuthIncoming=0x00090081,
+ DRSUAPI_ATTRIBUTE_trustAuthOutgoing=0x00090087,
+ DRSUAPI_ATTRIBUTE_lmPwdHistory=0x000900a0,
+ DRSUAPI_ATTRIBUTE_sAMAccountName=0x000900dd,
+ DRSUAPI_ATTRIBUTE_sAMAccountType=0x0009012e,
+ DRSUAPI_ATTRIBUTE_fSMORoleOwner=0x00090171,
+ DRSUAPI_ATTRIBUTE_systemFlags=0x00090177,
+ DRSUAPI_ATTRIBUTE_serverReference=0x00090203,
+ DRSUAPI_ATTRIBUTE_serverReferenceBL=0x00090204,
+ DRSUAPI_ATTRIBUTE_initialAuthIncoming=0x0009021b,
+ DRSUAPI_ATTRIBUTE_initialAuthOutgoing=0x0009021c,
+ DRSUAPI_ATTRIBUTE_wellKnownObjects=0x0009026a,
+ DRSUAPI_ATTRIBUTE_dNSHostName=0x0009026b,
+ DRSUAPI_ATTRIBUTE_isMemberOfPartialAttributeSet=0x0009027f,
+ DRSUAPI_ATTRIBUTE_userPrincipalName=0x00090290,
+ DRSUAPI_ATTRIBUTE_groupType=0x000902ee,
+ DRSUAPI_ATTRIBUTE_servicePrincipalName=0x00090303,
+ DRSUAPI_ATTRIBUTE_objectCategory=0x0009030e,
+ DRSUAPI_ATTRIBUTE_gPLink=0x0009037b,
+ DRSUAPI_ATTRIBUTE_msDS_Behavior_Version=0x000905b3,
+ DRSUAPI_ATTRIBUTE_msDS_KeyVersionNumber=0x000906f6,
+ DRSUAPI_ATTRIBUTE_msDS_HasDomainNCs=0x0009071c,
+ DRSUAPI_ATTRIBUTE_msDS_hasMasterNCs=0x0009072c
+}
+#else
+ { __donnot_use_enum_drsuapi_DsAttributeId=0x7FFFFFFF}
+#define DRSUAPI_ATTRIBUTE_objectClass ( 0x00000000 )
+#define DRSUAPI_ATTRIBUTE_description ( 0x0000000d )
+#define DRSUAPI_ATTRIBUTE_member ( 0x0000001f )
+#define DRSUAPI_ATTRIBUTE_instanceType ( 0x00020001 )
+#define DRSUAPI_ATTRIBUTE_whenCreated ( 0x00020002 )
+#define DRSUAPI_ATTRIBUTE_hasMasterNCs ( 0x0002000e )
+#define DRSUAPI_ATTRIBUTE_governsID ( 0x00020016 )
+#define DRSUAPI_ATTRIBUTE_attributeID ( 0x0002001e )
+#define DRSUAPI_ATTRIBUTE_attributeSyntax ( 0x00020020 )
+#define DRSUAPI_ATTRIBUTE_isSingleValued ( 0x00020021 )
+#define DRSUAPI_ATTRIBUTE_rangeLower ( 0x00020022 )
+#define DRSUAPI_ATTRIBUTE_rangeUpper ( 0x00020023 )
+#define DRSUAPI_ATTRIBUTE_dMDLocation ( 0x00020024 )
+#define DRSUAPI_ATTRIBUTE_objectVersion ( 0x0002004c )
+#define DRSUAPI_ATTRIBUTE_invocationId ( 0x00020073 )
+#define DRSUAPI_ATTRIBUTE_showInAdvancedViewOnly ( 0x000200a9 )
+#define DRSUAPI_ATTRIBUTE_adminDisplayName ( 0x000200c2 )
+#define DRSUAPI_ATTRIBUTE_adminDescription ( 0x000200e2 )
+#define DRSUAPI_ATTRIBUTE_oMSyntax ( 0x000200e7 )
+#define DRSUAPI_ATTRIBUTE_ntSecurityDescriptor ( 0x00020119 )
+#define DRSUAPI_ATTRIBUTE_searchFlags ( 0x0002014e )
+#define DRSUAPI_ATTRIBUTE_lDAPDisplayName ( 0x000201cc )
+#define DRSUAPI_ATTRIBUTE_name ( 0x00090001 )
+#define DRSUAPI_ATTRIBUTE_userAccountControl ( 0x00090008 )
+#define DRSUAPI_ATTRIBUTE_currentValue ( 0x0009001b )
+#define DRSUAPI_ATTRIBUTE_homeDirectory ( 0x0009002c )
+#define DRSUAPI_ATTRIBUTE_homeDrive ( 0x0009002d )
+#define DRSUAPI_ATTRIBUTE_scriptPath ( 0x0009003e )
+#define DRSUAPI_ATTRIBUTE_profilePath ( 0x0009008b )
+#define DRSUAPI_ATTRIBUTE_objectSid ( 0x00090092 )
+#define DRSUAPI_ATTRIBUTE_schemaIDGUID ( 0x00090094 )
+#define DRSUAPI_ATTRIBUTE_dBCSPwd ( 0x00090037 )
+#define DRSUAPI_ATTRIBUTE_logonHours ( 0x00090040 )
+#define DRSUAPI_ATTRIBUTE_userWorkstations ( 0x00090056 )
+#define DRSUAPI_ATTRIBUTE_unicodePwd ( 0x0009005a )
+#define DRSUAPI_ATTRIBUTE_ntPwdHistory ( 0x0009005e )
+#define DRSUAPI_ATTRIBUTE_priorValue ( 0x00090064 )
+#define DRSUAPI_ATTRIBUTE_supplementalCredentials ( 0x0009007d )
+#define DRSUAPI_ATTRIBUTE_trustAuthIncoming ( 0x00090081 )
+#define DRSUAPI_ATTRIBUTE_trustAuthOutgoing ( 0x00090087 )
+#define DRSUAPI_ATTRIBUTE_lmPwdHistory ( 0x000900a0 )
+#define DRSUAPI_ATTRIBUTE_sAMAccountName ( 0x000900dd )
+#define DRSUAPI_ATTRIBUTE_sAMAccountType ( 0x0009012e )
+#define DRSUAPI_ATTRIBUTE_fSMORoleOwner ( 0x00090171 )
+#define DRSUAPI_ATTRIBUTE_systemFlags ( 0x00090177 )
+#define DRSUAPI_ATTRIBUTE_serverReference ( 0x00090203 )
+#define DRSUAPI_ATTRIBUTE_serverReferenceBL ( 0x00090204 )
+#define DRSUAPI_ATTRIBUTE_initialAuthIncoming ( 0x0009021b )
+#define DRSUAPI_ATTRIBUTE_initialAuthOutgoing ( 0x0009021c )
+#define DRSUAPI_ATTRIBUTE_wellKnownObjects ( 0x0009026a )
+#define DRSUAPI_ATTRIBUTE_dNSHostName ( 0x0009026b )
+#define DRSUAPI_ATTRIBUTE_isMemberOfPartialAttributeSet ( 0x0009027f )
+#define DRSUAPI_ATTRIBUTE_userPrincipalName ( 0x00090290 )
+#define DRSUAPI_ATTRIBUTE_groupType ( 0x000902ee )
+#define DRSUAPI_ATTRIBUTE_servicePrincipalName ( 0x00090303 )
+#define DRSUAPI_ATTRIBUTE_objectCategory ( 0x0009030e )
+#define DRSUAPI_ATTRIBUTE_gPLink ( 0x0009037b )
+#define DRSUAPI_ATTRIBUTE_msDS_Behavior_Version ( 0x000905b3 )
+#define DRSUAPI_ATTRIBUTE_msDS_KeyVersionNumber ( 0x000906f6 )
+#define DRSUAPI_ATTRIBUTE_msDS_HasDomainNCs ( 0x0009071c )
+#define DRSUAPI_ATTRIBUTE_msDS_hasMasterNCs ( 0x0009072c )
+#endif
+;
+
+struct drsuapi_DsPartialAttributeSet {
+ uint32_t version;/* [value] */
+ uint32_t reserved1;/* [value(0)] */
+ uint32_t num_attids;/* [range(1,0x100000)] */
+ enum drsuapi_DsAttributeId *attids;/* [size_is(num_attids)] */
+};
+
+struct drsuapi_DsGetNCChangesRequest8 {
+ struct GUID destination_dsa_guid;
+ struct GUID source_dsa_invocation_id;
+ struct drsuapi_DsReplicaObjectIdentifier *naming_context;/* [ref] */
+ struct drsuapi_DsReplicaHighWaterMark highwatermark;
+ struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;/* [unique] */
+ uint32_t replica_flags;
+ uint32_t max_object_count;
+ uint32_t max_ndr_size;
+ enum drsuapi_DsExtendedOperation extended_op;
+ uint64_t fsmo_info;
+ struct drsuapi_DsPartialAttributeSet *partial_attribute_set;/* [unique] */
+ struct drsuapi_DsPartialAttributeSet *partial_attribute_set_ex;/* [unique] */
+ struct drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr;
+};
+
+union drsuapi_DsGetNCChangesRequest {
+ struct drsuapi_DsGetNCChangesRequest5 req5;/* [case(5)] */
+ struct drsuapi_DsGetNCChangesRequest8 req8;/* [case(8)] */
+}/* [switch_type(int32)] */;
+
+struct drsuapi_DsReplicaCursor2 {
+ struct GUID source_dsa_invocation_id;
+ uint64_t highest_usn;
+ NTTIME last_sync_success;
+}/* [public] */;
+
+struct drsuapi_DsReplicaCursor2CtrEx {
+ uint32_t version;/* [value(2)] */
+ uint32_t reserved1;/* [value(0)] */
+ uint32_t count;/* [range(0,0x100000)] */
+ uint32_t reserved2;/* [value(0)] */
+ struct drsuapi_DsReplicaCursor2 *cursors;/* [size_is(count)] */
+};
+
+struct drsuapi_DsAttributeValue {
+ uint32_t __ndr_size;/* [value(ndr_size_DATA_BLOB(0,blob,0)),range(0,10485760)] */
+ DATA_BLOB *blob;/* [unique] */
+};
+
+struct drsuapi_DsAttributeValueCtr {
+ uint32_t num_values;/* [range(0,10485760)] */
+ struct drsuapi_DsAttributeValue *values;/* [unique,size_is(num_values)] */
+};
+
+struct drsuapi_DsReplicaObjectIdentifier3 {
+ uint32_t __ndr_size;/* [value(ndr_size_drsuapi_DsReplicaObjectIdentifier3(r,ndr->flags))] */
+ uint32_t __ndr_size_sid;/* [value(ndr_size_dom_sid28(&sid,ndr->flags))] */
+ struct GUID guid;
+ struct dom_sid28 sid;
+ uint32_t __ndr_size_dn;/* [value(strlen_m(dn))] */
+ const char *dn;/* [charset(UTF16)] */
+}/* [gensize,public] */;
+
+struct drsuapi_DsReplicaObjectIdentifier3Binary {
+ uint32_t __ndr_size;/* [value(ndr_size_drsuapi_DsReplicaObjectIdentifier3Binary(r,ndr->flags))] */
+ uint32_t __ndr_size_sid;/* [value(ndr_size_dom_sid28(&sid,ndr->flags))] */
+ struct GUID guid;
+ struct dom_sid28 sid;
+ uint32_t __ndr_size_dn;/* [value(strlen_m(dn))] */
+ const char *dn;/* [charset(UTF16)] */
+ uint32_t __ndr_size_binary;/* [value(binary.length+4)] */
+ DATA_BLOB binary;/* [flag(LIBNDR_FLAG_REMAINING)] */
+}/* [gensize,public] */;
+
+struct drsuapi_DsReplicaAttribute {
+ enum drsuapi_DsAttributeId attid;
+ struct drsuapi_DsAttributeValueCtr value_ctr;
+}/* [public] */;
+
+struct drsuapi_DsReplicaAttributeCtr {
+ uint32_t num_attributes;/* [range(0,1048576)] */
+ struct drsuapi_DsReplicaAttribute *attributes;/* [unique,size_is(num_attributes)] */
+};
+
+/* bitmap drsuapi_DsReplicaObjectFlags */
+#define DRSUAPI_DS_REPLICA_OBJECT_FROM_MASTER ( 0x00000001 )
+#define DRSUAPI_DS_REPLICA_OBJECT_DYNAMIC ( 0x00000002 )
+#define DRSUAPI_DS_REPLICA_OBJECT_REMOTE_MODIFY ( 0x00010000 )
+
+struct drsuapi_DsReplicaObject {
+ struct drsuapi_DsReplicaObjectIdentifier *identifier;/* [unique] */
+ uint32_t flags;
+ struct drsuapi_DsReplicaAttributeCtr attribute_ctr;
+}/* [public] */;
+
+struct drsuapi_DsReplicaMetaData {
+ uint32_t version;
+ NTTIME originating_change_time;
+ struct GUID originating_invocation_id;
+ uint64_t originating_usn;
+};
+
+struct drsuapi_DsReplicaMetaDataCtr {
+ uint32_t count;/* [range(0,1048576)] */
+ struct drsuapi_DsReplicaMetaData *meta_data;/* [size_is(count)] */
+}/* [public] */;
+
+struct drsuapi_DsReplicaObjectListItemEx {
+ struct drsuapi_DsReplicaObjectListItemEx *next_object;/* [unique] */
+ struct drsuapi_DsReplicaObject object;
+ uint32_t is_nc_prefix;
+ struct GUID *parent_object_guid;/* [unique] */
+ struct drsuapi_DsReplicaMetaDataCtr *meta_data_ctr;/* [unique] */
+}/* [noprint,public] */;
+
+struct drsuapi_DsGetNCChangesCtr1 {
+ struct GUID source_dsa_guid;
+ struct GUID source_dsa_invocation_id;
+ struct drsuapi_DsReplicaObjectIdentifier *naming_context;/* [unique] */
+ struct drsuapi_DsReplicaHighWaterMark old_highwatermark;
+ struct drsuapi_DsReplicaHighWaterMark new_highwatermark;
+ struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;/* [unique] */
+ struct drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr;
+ enum drsuapi_DsExtendedError extended_ret;
+ uint32_t object_count;
+ uint32_t __ndr_size;/* [value(ndr_size_drsuapi_DsGetNCChangesCtr1(r,ndr->flags)+55)] */
+ struct drsuapi_DsReplicaObjectListItemEx *first_object;/* [unique] */
+ uint32_t more_data;
+}/* [gensize,public] */;
+
+/* bitmap drsuapi_DsLinkedAttributeFlags */
+#define DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE ( 0x00000001 )
+
+struct drsuapi_DsReplicaLinkedAttribute {
+ struct drsuapi_DsReplicaObjectIdentifier *identifier;/* [unique] */
+ enum drsuapi_DsAttributeId attid;
+ struct drsuapi_DsAttributeValue value;
+ uint32_t flags;
+ NTTIME originating_add_time;
+ struct drsuapi_DsReplicaMetaData meta_data;
+}/* [public] */;
+
+struct drsuapi_DsGetNCChangesCtr6 {
+ struct GUID source_dsa_guid;
+ struct GUID source_dsa_invocation_id;
+ struct drsuapi_DsReplicaObjectIdentifier *naming_context;/* [unique] */
+ struct drsuapi_DsReplicaHighWaterMark old_highwatermark;
+ struct drsuapi_DsReplicaHighWaterMark new_highwatermark;
+ struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;/* [unique] */
+ struct drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr;
+ enum drsuapi_DsExtendedError extended_ret;
+ uint32_t object_count;
+ uint32_t __ndr_size;/* [value(ndr_size_drsuapi_DsGetNCChangesCtr6(r,ndr->flags)+55)] */
+ struct drsuapi_DsReplicaObjectListItemEx *first_object;/* [unique] */
+ uint32_t more_data;
+ uint32_t nc_object_count;
+ uint32_t nc_linked_attributes_count;
+ uint32_t linked_attributes_count;/* [range(0,1048576)] */
+ struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;/* [unique,size_is(linked_attributes_count)] */
+ WERROR drs_error;
+}/* [gensize,public] */;
+
+struct drsuapi_DsGetNCChangesMSZIPCtr1 {
+ uint32_t decompressed_length;
+ uint32_t compressed_length;
+ struct drsuapi_DsGetNCChangesCtr1 *ctr1;/* [unique,compression(NDR_COMPRESSION_MSZIP,compressed_length,decompressed_length),subcontext_size(compressed_length),subcontext(4)] */
+};
+
+struct drsuapi_DsGetNCChangesMSZIPCtr6 {
+ uint32_t decompressed_length;
+ uint32_t compressed_length;
+ struct drsuapi_DsGetNCChangesCtr6 *ctr6;/* [unique,compression(NDR_COMPRESSION_MSZIP,compressed_length,decompressed_length),subcontext_size(compressed_length),subcontext(4)] */
+};
+
+struct drsuapi_DsGetNCChangesXPRESSCtr1 {
+ uint32_t decompressed_length;
+ uint32_t compressed_length;
+ struct drsuapi_DsGetNCChangesCtr1 *ctr1;/* [unique,compression(NDR_COMPRESSION_XPRESS,compressed_length,decompressed_length),subcontext_size(compressed_length),subcontext(4)] */
+};
+
+struct drsuapi_DsGetNCChangesXPRESSCtr6 {
+ uint32_t decompressed_length;
+ uint32_t compressed_length;
+ struct drsuapi_DsGetNCChangesCtr6 *ctr6;/* [unique,compression(NDR_COMPRESSION_XPRESS,compressed_length,decompressed_length),subcontext_size(compressed_length),subcontext(4)] */
+};
+
+enum drsuapi_DsGetNCChangesCompressionType
+#ifndef USE_UINT_ENUMS
+ {
+ DRSUAPI_COMPRESSION_TYPE_MSZIP=2,
+ DRSUAPI_COMPRESSION_TYPE_XPRESS=3
+}
+#else
+ { __donnot_use_enum_drsuapi_DsGetNCChangesCompressionType=0x7FFFFFFF}
+#define DRSUAPI_COMPRESSION_TYPE_MSZIP ( 2 )
+#define DRSUAPI_COMPRESSION_TYPE_XPRESS ( 3 )
+#endif
+;
+
+union drsuapi_DsGetNCChangesCompressedCtr {
+ struct drsuapi_DsGetNCChangesMSZIPCtr1 mszip1;/* [case(1|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16))] */
+ struct drsuapi_DsGetNCChangesMSZIPCtr6 mszip6;/* [case(6|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16))] */
+ struct drsuapi_DsGetNCChangesXPRESSCtr1 xpress1;/* [case(1|(DRSUAPI_COMPRESSION_TYPE_XPRESS<<16))] */
+ struct drsuapi_DsGetNCChangesXPRESSCtr6 xpress6;/* [case(6|(DRSUAPI_COMPRESSION_TYPE_XPRESS<<16))] */
+}/* [nodiscriminant,flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+struct drsuapi_DsGetNCChangesCtr2 {
+ union drsuapi_DsGetNCChangesCompressedCtr ctr;/* [switch_is(1|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16))] */
+};
+
+struct drsuapi_DsGetNCChangesCtr7 {
+ int32_t level;/* [range(0,6)] */
+ enum drsuapi_DsGetNCChangesCompressionType type;/* [range(2,3)] */
+ union drsuapi_DsGetNCChangesCompressedCtr ctr;/* [switch_is(level|(type<<16))] */
+};
+
+union drsuapi_DsGetNCChangesCtr {
+ struct drsuapi_DsGetNCChangesCtr1 ctr1;/* [case] */
+ struct drsuapi_DsGetNCChangesCtr2 ctr2;/* [case(2)] */
+ struct drsuapi_DsGetNCChangesCtr6 ctr6;/* [case(6)] */
+ struct drsuapi_DsGetNCChangesCtr7 ctr7;/* [case(7)] */
+}/* [switch_type(int32)] */;
+
+/* bitmap drsuapi_DsReplicaUpdateRefsOptions */
+#define DRSUAPI_DS_REPLICA_UPDATE_ASYNCHRONOUS_OPERATION ( 0x00000001 )
+#define DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE ( 0x00000002 )
+#define DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE ( 0x00000004 )
+#define DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE ( 0x00000008 )
+#define DRSUAPI_DS_REPLICA_UPDATE_0x00000010 ( 0x00000010 )
+
+struct drsuapi_DsReplicaUpdateRefsRequest1 {
+ struct drsuapi_DsReplicaObjectIdentifier *naming_context;/* [ref] */
+ const char *dest_dsa_dns_name;/* [ref,charset(DOS)] */
+ struct GUID dest_dsa_guid;
+ uint32_t options;
+};
+
+union drsuapi_DsReplicaUpdateRefsRequest {
+ struct drsuapi_DsReplicaUpdateRefsRequest1 req1;/* [case] */
+}/* [switch_type(int32)] */;
+
+/* bitmap drsuapi_DsReplicaAddOptions */
+#define DRSUAPI_DS_REPLICA_ADD_ASYNCHRONOUS_OPERATION ( 0x00000001 )
+#define DRSUAPI_DS_REPLICA_ADD_WRITEABLE ( 0x00000002 )
+
+/* bitmap drsuapi_DsReplicaDeleteOptions */
+#define DRSUAPI_DS_REPLICA_DELETE_ASYNCHRONOUS_OPERATION ( 0x00000001 )
+#define DRSUAPI_DS_REPLICA_DELETE_WRITEABLE ( 0x00000002 )
+
+/* bitmap drsuapi_DsReplicaModifyOptions */
+#define DRSUAPI_DS_REPLICA_MODIFY_ASYNCHRONOUS_OPERATION ( 0x00000001 )
+#define DRSUAPI_DS_REPLICA_MODIFY_WRITEABLE ( 0x00000002 )
+
+enum drsuapi_DsMembershipType
+#ifndef USE_UINT_ENUMS
+ {
+ DRSUAPI_DS_MEMBERSHIP_TYPE_UNIVERSAL_AND_DOMAIN_GROUPS=1,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_LOCAL_GROUPS=2,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_GROUPS=3,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_LOCAL_GROUPS2=4,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_UNIVERSAL_GROUPS=5,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_GROUPMEMBERS=6,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_GROUPS2=7
+}
+#else
+ { __donnot_use_enum_drsuapi_DsMembershipType=0x7FFFFFFF}
+#define DRSUAPI_DS_MEMBERSHIP_TYPE_UNIVERSAL_AND_DOMAIN_GROUPS ( 1 )
+#define DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_LOCAL_GROUPS ( 2 )
+#define DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_GROUPS ( 3 )
+#define DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_LOCAL_GROUPS2 ( 4 )
+#define DRSUAPI_DS_MEMBERSHIP_TYPE_UNIVERSAL_GROUPS ( 5 )
+#define DRSUAPI_DS_MEMBERSHIP_TYPE_GROUPMEMBERS ( 6 )
+#define DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_GROUPS2 ( 7 )
+#endif
+;
+
+struct drsuapi_DsGetMembershipsCtr1 {
+ NTSTATUS status;
+ uint32_t num_memberships;/* [range(0,10000)] */
+ uint32_t num_sids;/* [range(0,10000)] */
+ struct drsuapi_DsReplicaObjectIdentifier **info_array;/* [unique,size_is(num_memberships)] */
+ uint32_t *group_attrs;/* [unique,size_is(num_memberships)] */
+ struct dom_sid28 **sids;/* [unique,size_is(num_sids)] */
+};
+
+union drsuapi_DsGetMembershipsCtr {
+ struct drsuapi_DsGetMembershipsCtr1 ctr1;/* [case] */
+}/* [switch_type(int32)] */;
+
+struct drsuapi_DsGetMembershipsRequest1 {
+ uint32_t count;/* [range(1,10000)] */
+ struct drsuapi_DsReplicaObjectIdentifier **info_array;/* [unique,size_is(count)] */
+ uint32_t flags;
+ enum drsuapi_DsMembershipType type;
+ struct drsuapi_DsReplicaObjectIdentifier *domain;/* [unique] */
+};
+
+union drsuapi_DsGetMembershipsRequest {
+ struct drsuapi_DsGetMembershipsRequest1 req1;/* [case] */
+}/* [switch_type(int32)] */;
+
+struct drsuapi_DsGetNT4ChangeLogRequest1 {
+ uint32_t unknown1;
+ uint32_t unknown2;
+ uint32_t length;/* [range(0,0x00A00000)] */
+ uint8_t *data;/* [unique,size_is(length)] */
+};
+
+union drsuapi_DsGetNT4ChangeLogRequest {
+ struct drsuapi_DsGetNT4ChangeLogRequest1 req1;/* [case] */
+}/* [switch_type(uint32)] */;
+
+struct drsuapi_DsGetNT4ChangeLogInfo1 {
+ uint32_t length1;/* [range(0,0x00A00000)] */
+ uint32_t length2;/* [range(0,0x00A00000)] */
+ uint64_t unknown1;
+ NTTIME time2;
+ uint64_t unknown3;
+ NTTIME time4;
+ uint64_t unknown5;
+ NTTIME time6;
+ NTSTATUS status;
+ uint8_t *data1;/* [unique,size_is(length1)] */
+ uint8_t *data2;/* [unique,size_is(length2)] */
+};
+
+union drsuapi_DsGetNT4ChangeLogInfo {
+ struct drsuapi_DsGetNT4ChangeLogInfo1 info1;/* [case] */
+}/* [switch_type(uint32)] */;
+
+enum drsuapi_DsNameStatus
+#ifndef USE_UINT_ENUMS
+ {
+ DRSUAPI_DS_NAME_STATUS_OK=0,
+ DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR=1,
+ DRSUAPI_DS_NAME_STATUS_NOT_FOUND=2,
+ DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE=3,
+ DRSUAPI_DS_NAME_STATUS_NO_MAPPING=4,
+ DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY=5,
+ DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING=6,
+ DRSUAPI_DS_NAME_STATUS_TRUST_REFERRAL=7
+}
+#else
+ { __donnot_use_enum_drsuapi_DsNameStatus=0x7FFFFFFF}
+#define DRSUAPI_DS_NAME_STATUS_OK ( 0 )
+#define DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR ( 1 )
+#define DRSUAPI_DS_NAME_STATUS_NOT_FOUND ( 2 )
+#define DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE ( 3 )
+#define DRSUAPI_DS_NAME_STATUS_NO_MAPPING ( 4 )
+#define DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY ( 5 )
+#define DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING ( 6 )
+#define DRSUAPI_DS_NAME_STATUS_TRUST_REFERRAL ( 7 )
+#endif
+;
+
+enum drsuapi_DsNameFlags
+#ifndef USE_UINT_ENUMS
+ {
+ DRSUAPI_DS_NAME_FLAG_NO_FLAGS=0x0,
+ DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY=0x1,
+ DRSUAPI_DS_NAME_FLAG_EVAL_AT_DC=0x2,
+ DRSUAPI_DS_NAME_FLAG_GCVERIFY=0x4,
+ DRSUAPI_DS_NAME_FLAG_TRUST_REFERRAL=0x8
+}
+#else
+ { __donnot_use_enum_drsuapi_DsNameFlags=0x7FFFFFFF}
+#define DRSUAPI_DS_NAME_FLAG_NO_FLAGS ( 0x0 )
+#define DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY ( 0x1 )
+#define DRSUAPI_DS_NAME_FLAG_EVAL_AT_DC ( 0x2 )
+#define DRSUAPI_DS_NAME_FLAG_GCVERIFY ( 0x4 )
+#define DRSUAPI_DS_NAME_FLAG_TRUST_REFERRAL ( 0x8 )
+#endif
+;
+
+enum drsuapi_DsNameFormat
+#ifndef USE_UINT_ENUMS
+ {
+ DRSUAPI_DS_NAME_FORMAT_UKNOWN=0,
+ DRSUAPI_DS_NAME_FORMAT_FQDN_1779=1,
+ DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT=2,
+ DRSUAPI_DS_NAME_FORMAT_DISPLAY=3,
+ DRSUAPI_DS_NAME_FORMAT_GUID=6,
+ DRSUAPI_DS_NAME_FORMAT_CANONICAL=7,
+ DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL=8,
+ DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX=9,
+ DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL=10,
+ DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY=11,
+ DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN=12
+}
+#else
+ { __donnot_use_enum_drsuapi_DsNameFormat=0x7FFFFFFF}
+#define DRSUAPI_DS_NAME_FORMAT_UKNOWN ( 0 )
+#define DRSUAPI_DS_NAME_FORMAT_FQDN_1779 ( 1 )
+#define DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT ( 2 )
+#define DRSUAPI_DS_NAME_FORMAT_DISPLAY ( 3 )
+#define DRSUAPI_DS_NAME_FORMAT_GUID ( 6 )
+#define DRSUAPI_DS_NAME_FORMAT_CANONICAL ( 7 )
+#define DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL ( 8 )
+#define DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX ( 9 )
+#define DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL ( 10 )
+#define DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY ( 11 )
+#define DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN ( 12 )
+#endif
+;
+
+struct drsuapi_DsNameString {
+ const char *str;/* [unique,charset(UTF16)] */
+};
+
+struct drsuapi_DsNameRequest1 {
+ uint32_t codepage;
+ uint32_t language;
+ enum drsuapi_DsNameFlags format_flags;
+ enum drsuapi_DsNameFormat format_offered;
+ enum drsuapi_DsNameFormat format_desired;
+ uint32_t count;/* [range(1,10000)] */
+ struct drsuapi_DsNameString *names;/* [unique,size_is(count)] */
+};
+
+union drsuapi_DsNameRequest {
+ struct drsuapi_DsNameRequest1 req1;/* [case] */
+}/* [switch_type(int32)] */;
+
+struct drsuapi_DsNameInfo1 {
+ enum drsuapi_DsNameStatus status;
+ const char *dns_domain_name;/* [unique,charset(UTF16)] */
+ const char *result_name;/* [unique,charset(UTF16)] */
+};
+
+struct drsuapi_DsNameCtr1 {
+ uint32_t count;
+ struct drsuapi_DsNameInfo1 *array;/* [unique,size_is(count)] */
+};
+
+union drsuapi_DsNameCtr {
+ struct drsuapi_DsNameCtr1 *ctr1;/* [unique,case] */
+}/* [switch_type(int32)] */;
+
+enum drsuapi_DsSpnOperation
+#ifndef USE_UINT_ENUMS
+ {
+ DRSUAPI_DS_SPN_OPERATION_ADD=0,
+ DRSUAPI_DS_SPN_OPERATION_REPLACE=1,
+ DRSUAPI_DS_SPN_OPERATION_DELETE=2
+}
+#else
+ { __donnot_use_enum_drsuapi_DsSpnOperation=0x7FFFFFFF}
+#define DRSUAPI_DS_SPN_OPERATION_ADD ( 0 )
+#define DRSUAPI_DS_SPN_OPERATION_REPLACE ( 1 )
+#define DRSUAPI_DS_SPN_OPERATION_DELETE ( 2 )
+#endif
+;
+
+struct drsuapi_DsWriteAccountSpnRequest1 {
+ enum drsuapi_DsSpnOperation operation;
+ uint32_t unknown1;
+ const char *object_dn;/* [unique,charset(UTF16)] */
+ uint32_t count;/* [range(0,10000)] */
+ struct drsuapi_DsNameString *spn_names;/* [unique,size_is(count)] */
+};
+
+union drsuapi_DsWriteAccountSpnRequest {
+ struct drsuapi_DsWriteAccountSpnRequest1 req1;/* [case] */
+}/* [switch_type(int32)] */;
+
+struct drsuapi_DsWriteAccountSpnResult1 {
+ WERROR status;
+};
+
+union drsuapi_DsWriteAccountSpnResult {
+ struct drsuapi_DsWriteAccountSpnResult1 res1;/* [case] */
+}/* [switch_type(int32)] */;
+
+struct drsuapi_DsRemoveDSServerRequest1 {
+ const char *server_dn;/* [unique,charset(UTF16)] */
+ const char *domain_dn;/* [unique,charset(UTF16)] */
+ uint32_t unknown;
+};
+
+union drsuapi_DsRemoveDSServerRequest {
+ struct drsuapi_DsRemoveDSServerRequest1 req1;/* [case] */
+}/* [switch_type(int32)] */;
+
+struct drsuapi_DsRemoveDSServerResult1 {
+ WERROR status;
+};
+
+union drsuapi_DsRemoveDSServerResult {
+ struct drsuapi_DsRemoveDSServerResult1 res1;/* [case] */
+}/* [switch_type(int32)] */;
+
+struct drsuapi_DsGetDCInfoRequest1 {
+ const char *domain_name;/* [unique,charset(UTF16)] */
+ int32_t level;
+};
+
+union drsuapi_DsGetDCInfoRequest {
+ struct drsuapi_DsGetDCInfoRequest1 req1;/* [case] */
+}/* [switch_type(int32)] */;
+
+struct drsuapi_DsGetDCInfo1 {
+ const char *netbios_name;/* [unique,charset(UTF16)] */
+ const char *dns_name;/* [unique,charset(UTF16)] */
+ const char *site_name;/* [unique,charset(UTF16)] */
+ const char *computer_dn;/* [unique,charset(UTF16)] */
+ const char *server_dn;/* [unique,charset(UTF16)] */
+ uint32_t is_pdc;
+ uint32_t is_enabled;
+};
+
+struct drsuapi_DsGetDCInfoCtr1 {
+ uint32_t count;/* [range(0,10000)] */
+ struct drsuapi_DsGetDCInfo1 *array;/* [unique,size_is(count)] */
+};
+
+struct drsuapi_DsGetDCInfo2 {
+ const char *netbios_name;/* [unique,charset(UTF16)] */
+ const char *dns_name;/* [unique,charset(UTF16)] */
+ const char *site_name;/* [unique,charset(UTF16)] */
+ const char *site_dn;/* [unique,charset(UTF16)] */
+ const char *computer_dn;/* [unique,charset(UTF16)] */
+ const char *server_dn;/* [unique,charset(UTF16)] */
+ const char *ntds_dn;/* [unique,charset(UTF16)] */
+ uint32_t is_pdc;
+ uint32_t is_enabled;
+ uint32_t is_gc;
+ struct GUID site_guid;
+ struct GUID computer_guid;
+ struct GUID server_guid;
+ struct GUID ntds_guid;
+};
+
+struct drsuapi_DsGetDCInfoCtr2 {
+ uint32_t count;/* [range(0,10000)] */
+ struct drsuapi_DsGetDCInfo2 *array;/* [unique,size_is(count)] */
+};
+
+struct drsuapi_DsGetDCInfo3 {
+ const char *netbios_name;/* [unique,charset(UTF16)] */
+ const char *dns_name;/* [unique,charset(UTF16)] */
+ const char *site_name;/* [unique,charset(UTF16)] */
+ const char *site_dn;/* [unique,charset(UTF16)] */
+ const char *computer_dn;/* [unique,charset(UTF16)] */
+ const char *server_dn;/* [unique,charset(UTF16)] */
+ const char *ntds_dn;/* [unique,charset(UTF16)] */
+ uint32_t is_pdc;
+ uint32_t is_enabled;
+ uint32_t is_gc;
+ uint32_t is_rodc;
+ struct GUID site_guid;
+ struct GUID computer_guid;
+ struct GUID server_guid;
+ struct GUID ntds_guid;
+};
+
+struct drsuapi_DsGetDCInfoCtr3 {
+ uint32_t count;/* [range(0,10000)] */
+ struct drsuapi_DsGetDCInfo3 *array;/* [unique,size_is(count)] */
+};
+
+struct drsuapi_DsGetDCConnection01 {
+ const char * client_ip_address;/* [flag(LIBNDR_FLAG_BIGENDIAN)] */
+ uint32_t unknown2;
+ uint32_t connection_time;
+ uint32_t unknown4;
+ uint32_t unknown5;
+ uint32_t unknown6;
+ const char *client_account;/* [unique,charset(UTF16)] */
+};
+
+struct drsuapi_DsGetDCConnectionCtr01 {
+ uint32_t count;/* [range(0,10000)] */
+ struct drsuapi_DsGetDCConnection01 *array;/* [unique,size_is(count)] */
+};
+
+enum drsuapi_DsGetDCInfoCtrLevels
+#ifndef USE_UINT_ENUMS
+ {
+ DRSUAPI_DC_INFO_CTR_1=1,
+ DRSUAPI_DC_INFO_CTR_2=2,
+ DRSUAPI_DC_INFO_CTR_3=3,
+ DRSUAPI_DC_CONNECTION_CTR_01=-1
+}
+#else
+ { __donnot_use_enum_drsuapi_DsGetDCInfoCtrLevels=0x7FFFFFFF}
+#define DRSUAPI_DC_INFO_CTR_1 ( 1 )
+#define DRSUAPI_DC_INFO_CTR_2 ( 2 )
+#define DRSUAPI_DC_INFO_CTR_3 ( 3 )
+#define DRSUAPI_DC_CONNECTION_CTR_01 ( -1 )
+#endif
+;
+
+union drsuapi_DsGetDCInfoCtr {
+ struct drsuapi_DsGetDCInfoCtr1 ctr1;/* [case(DRSUAPI_DC_INFO_CTR_1)] */
+ struct drsuapi_DsGetDCInfoCtr2 ctr2;/* [case(DRSUAPI_DC_INFO_CTR_2)] */
+ struct drsuapi_DsGetDCInfoCtr3 ctr3;/* [case(DRSUAPI_DC_INFO_CTR_3)] */
+ struct drsuapi_DsGetDCConnectionCtr01 ctr01;/* [case(DRSUAPI_DC_CONNECTION_CTR_01)] */
+}/* [switch_type(int32)] */;
+
+struct drsuapi_DsReplicaObjectListItem {
+ struct drsuapi_DsReplicaObjectListItem *next_object;/* [unique] */
+ struct drsuapi_DsReplicaObject object;
+}/* [noprint,public] */;
+
+struct drsuapi_DsAddEntryRequest2 {
+ struct drsuapi_DsReplicaObjectListItem first_object;
+};
+
+union drsuapi_DsAddEntryRequest {
+ struct drsuapi_DsAddEntryRequest2 req2;/* [case(2)] */
+}/* [switch_type(int32)] */;
+
+struct drsuapi_DsAddEntryErrorInfoX {
+ uint32_t unknown1;
+ WERROR status;
+ uint32_t unknown2;
+ uint16_t unknown3;
+};
+
+struct drsuapi_DsAddEntryExtraErrorBuffer {
+ uint32_t size;/* [range(0,10485760)] */
+ uint8_t *data;/* [unique,size_is(size)] */
+};
+
+struct drsuapi_DsAddEntryExtraError1 {
+ struct drsuapi_DsAddEntryErrorInfoX error;
+ enum drsuapi_DsAttributeId attid;
+ uint32_t unknown2;
+ struct drsuapi_DsAddEntryExtraErrorBuffer buffer;
+};
+
+struct drsuapi_DsAddEntryErrorListItem1 {
+ struct drsuapi_DsAddEntryErrorListItem1 *next;/* [unique] */
+ struct drsuapi_DsAddEntryExtraError1 error;
+};
+
+struct drsuapi_DsAddEntryErrorInfo1 {
+ struct drsuapi_DsReplicaObjectIdentifier *id;/* [unique] */
+ WERROR status;
+ struct drsuapi_DsAddEntryErrorListItem1 first;
+};
+
+union drsuapi_DsAddEntryErrorInfo {
+ struct drsuapi_DsAddEntryErrorInfo1 error1;/* [case] */
+ struct drsuapi_DsAddEntryErrorInfoX errorX;/* [case(4)] */
+}/* [switch_type(uint32)] */;
+
+struct drsuapi_DsAddEntryError1 {
+ WERROR status;
+ uint32_t level;
+ union drsuapi_DsAddEntryErrorInfo *info;/* [unique,switch_is(level)] */
+};
+
+union drsuapi_DsAddEntryError {
+ struct drsuapi_DsAddEntryError1 info1;/* [case] */
+}/* [switch_type(uint32)] */;
+
+struct drsuapi_DsReplicaObjectIdentifier2 {
+ struct GUID guid;
+ struct dom_sid28 sid;
+};
+
+struct drsuapi_DsAddEntryCtr2 {
+ struct drsuapi_DsReplicaObjectIdentifier *id;/* [unique] */
+ uint32_t unknown1;
+ struct drsuapi_DsAddEntryErrorInfoX error;
+ uint32_t count;/* [range(0,10000)] */
+ struct drsuapi_DsReplicaObjectIdentifier2 *objects;/* [unique,size_is(count)] */
+};
+
+struct drsuapi_DsAddEntryCtr3 {
+ struct drsuapi_DsReplicaObjectIdentifier *id;/* [unique] */
+ uint32_t level;
+ union drsuapi_DsAddEntryError *error;/* [unique,switch_is(level)] */
+ uint32_t count;/* [range(0,10000)] */
+ struct drsuapi_DsReplicaObjectIdentifier2 *objects;/* [unique,size_is(count)] */
+};
+
+union drsuapi_DsAddEntryCtr {
+ struct drsuapi_DsAddEntryCtr2 ctr2;/* [case(2)] */
+ struct drsuapi_DsAddEntryCtr3 ctr3;/* [case(3)] */
+}/* [switch_type(int32)] */;
+
+enum drsuapi_DsReplicaGetInfoLevel
+#ifndef USE_UINT_ENUMS
+ {
+ DRSUAPI_DS_REPLICA_GET_INFO=1,
+ DRSUAPI_DS_REPLICA_GET_INFO2=2
+}
+#else
+ { __donnot_use_enum_drsuapi_DsReplicaGetInfoLevel=0x7FFFFFFF}
+#define DRSUAPI_DS_REPLICA_GET_INFO ( 1 )
+#define DRSUAPI_DS_REPLICA_GET_INFO2 ( 2 )
+#endif
+;
+
+enum drsuapi_DsReplicaInfoType
+#ifndef USE_UINT_ENUMS
+ {
+ DRSUAPI_DS_REPLICA_INFO_NEIGHBORS=0,
+ DRSUAPI_DS_REPLICA_INFO_CURSORS=1,
+ DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA=2,
+ DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES=3,
+ DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES=4,
+ DRSUAPI_DS_REPLICA_INFO_PENDING_OPS=5,
+ DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA=6,
+ DRSUAPI_DS_REPLICA_INFO_CURSORS2=7,
+ DRSUAPI_DS_REPLICA_INFO_CURSORS3=8,
+ DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2=9,
+ DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2=10,
+ DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02=-2,
+ DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04=-4,
+ DRSUAPI_DS_REPLICA_INFO_CURSORS05=-5,
+ DRSUAPI_DS_REPLICA_INFO_06=-6
+}
+#else
+ { __donnot_use_enum_drsuapi_DsReplicaInfoType=0x7FFFFFFF}
+#define DRSUAPI_DS_REPLICA_INFO_NEIGHBORS ( 0 )
+#define DRSUAPI_DS_REPLICA_INFO_CURSORS ( 1 )
+#define DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA ( 2 )
+#define DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES ( 3 )
+#define DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES ( 4 )
+#define DRSUAPI_DS_REPLICA_INFO_PENDING_OPS ( 5 )
+#define DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA ( 6 )
+#define DRSUAPI_DS_REPLICA_INFO_CURSORS2 ( 7 )
+#define DRSUAPI_DS_REPLICA_INFO_CURSORS3 ( 8 )
+#define DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2 ( 9 )
+#define DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2 ( 10 )
+#define DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02 ( -2 )
+#define DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04 ( -4 )
+#define DRSUAPI_DS_REPLICA_INFO_CURSORS05 ( -5 )
+#define DRSUAPI_DS_REPLICA_INFO_06 ( -6 )
+#endif
+;
+
+struct drsuapi_DsReplicaGetInfoRequest1 {
+ enum drsuapi_DsReplicaInfoType info_type;
+ const char *object_dn;/* [unique,charset(UTF16)] */
+ struct GUID guid1;
+};
+
+struct drsuapi_DsReplicaGetInfoRequest2 {
+ enum drsuapi_DsReplicaInfoType info_type;
+ const char *object_dn;/* [unique,charset(UTF16)] */
+ struct GUID guid1;
+ uint32_t unknown1;
+ const char *string1;/* [unique,charset(UTF16)] */
+ const char *string2;/* [unique,charset(UTF16)] */
+ uint32_t unknown2;
+};
+
+union drsuapi_DsReplicaGetInfoRequest {
+ struct drsuapi_DsReplicaGetInfoRequest1 req1;/* [case(DRSUAPI_DS_REPLICA_GET_INFO)] */
+ struct drsuapi_DsReplicaGetInfoRequest2 req2;/* [case(DRSUAPI_DS_REPLICA_GET_INFO2)] */
+}/* [switch_type(drsuapi_DsReplicaGetInfoLevel)] */;
+
+struct drsuapi_DsReplicaNeighbour {
+ const char *naming_context_dn;/* [unique,charset(UTF16)] */
+ const char *source_dsa_obj_dn;/* [unique,charset(UTF16)] */
+ const char *source_dsa_address;/* [unique,charset(UTF16)] */
+ const char *transport_obj_dn;/* [unique,charset(UTF16)] */
+ uint32_t replica_flags;
+ uint32_t reserved;
+ struct GUID naming_context_obj_guid;
+ struct GUID source_dsa_obj_guid;
+ struct GUID source_dsa_invocation_id;
+ struct GUID transport_obj_guid;
+ uint64_t tmp_highest_usn;
+ uint64_t highest_usn;
+ NTTIME last_success;
+ NTTIME last_attempt;
+ WERROR result_last_attempt;
+ uint32_t consecutive_sync_failures;
+};
+
+struct drsuapi_DsReplicaNeighbourCtr {
+ uint32_t count;
+ uint32_t reserved;
+ struct drsuapi_DsReplicaNeighbour *array;/* [size_is(count)] */
+};
+
+struct drsuapi_DsReplicaCursorCtr {
+ uint32_t count;
+ uint32_t reserved;
+ struct drsuapi_DsReplicaCursor *array;/* [size_is(count)] */
+};
+
+struct drsuapi_DsReplicaObjMetaData {
+ const char *attribute_name;/* [unique,charset(UTF16)] */
+ uint32_t version;
+ NTTIME originating_change_time;
+ struct GUID originating_invocation_id;
+ uint64_t originating_usn;
+ uint64_t local_usn;
+};
+
+struct drsuapi_DsReplicaObjMetaDataCtr {
+ uint32_t count;
+ uint32_t reserved;
+ struct drsuapi_DsReplicaObjMetaData *array;/* [size_is(count)] */
+};
+
+struct drsuapi_DsReplicaKccDsaFailure {
+ const char *dsa_obj_dn;/* [unique,charset(UTF16)] */
+ struct GUID dsa_obj_guid;
+ NTTIME first_failure;
+ uint32_t num_failures;
+ WERROR last_result;
+};
+
+struct drsuapi_DsReplicaKccDsaFailuresCtr {
+ uint32_t count;
+ uint32_t reserved;
+ struct drsuapi_DsReplicaKccDsaFailure *array;/* [size_is(count)] */
+};
+
+enum drsuapi_DsReplicaOpType
+#ifndef USE_UINT_ENUMS
+ {
+ DRSUAPI_DS_REPLICA_OP_TYPE_SYNC=0,
+ DRSUAPI_DS_REPLICA_OP_TYPE_ADD=1,
+ DRSUAPI_DS_REPLICA_OP_TYPE_DELETE=2,
+ DRSUAPI_DS_REPLICA_OP_TYPE_MODIFY=3,
+ DRSUAPI_DS_REPLICA_OP_TYPE_UPDATE_REFS=4
+}
+#else
+ { __donnot_use_enum_drsuapi_DsReplicaOpType=0x7FFFFFFF}
+#define DRSUAPI_DS_REPLICA_OP_TYPE_SYNC ( 0 )
+#define DRSUAPI_DS_REPLICA_OP_TYPE_ADD ( 1 )
+#define DRSUAPI_DS_REPLICA_OP_TYPE_DELETE ( 2 )
+#define DRSUAPI_DS_REPLICA_OP_TYPE_MODIFY ( 3 )
+#define DRSUAPI_DS_REPLICA_OP_TYPE_UPDATE_REFS ( 4 )
+#endif
+;
+
+union drsuapi_DsRplicaOpOptions {
+ uint32_t sync;/* [case(DRSUAPI_DS_REPLICA_OP_TYPE_SYNC)] */
+ uint32_t add;/* [case(DRSUAPI_DS_REPLICA_OP_TYPE_ADD)] */
+ uint32_t op_delete;/* [case(DRSUAPI_DS_REPLICA_OP_TYPE_DELETE)] */
+ uint32_t modify;/* [case(DRSUAPI_DS_REPLICA_OP_TYPE_MODIFY)] */
+ uint32_t update_refs;/* [case(DRSUAPI_DS_REPLICA_OP_TYPE_UPDATE_REFS)] */
+ uint32_t unknown;/* [default] */
+}/* [switch_type(drsuapi_DsReplicaOpType)] */;
+
+struct drsuapi_DsReplicaOp {
+ NTTIME operation_start;
+ uint32_t serial_num;
+ uint32_t priority;
+ enum drsuapi_DsReplicaOpType operation_type;
+ union drsuapi_DsRplicaOpOptions options;/* [switch_is(operation_type)] */
+ const char *nc_dn;/* [unique,charset(UTF16)] */
+ const char *remote_dsa_obj_dn;/* [unique,charset(UTF16)] */
+ const char *remote_dsa_address;/* [unique,charset(UTF16)] */
+ struct GUID nc_obj_guid;
+ struct GUID remote_dsa_obj_guid;
+};
+
+struct drsuapi_DsReplicaOpCtr {
+ NTTIME time;
+ uint32_t count;
+ struct drsuapi_DsReplicaOp *array;/* [size_is(count)] */
+};
+
+struct drsuapi_DsReplicaAttrValMetaData {
+ const char *attribute_name;/* [unique,charset(UTF16)] */
+ const char *object_dn;/* [unique,charset(UTF16)] */
+ uint32_t __ndr_size_binary;/* [value(ndr_size_DATA_BLOB(0,binary,0))] */
+ DATA_BLOB *binary;/* [unique] */
+ NTTIME deleted;
+ NTTIME created;
+ uint32_t version;
+ NTTIME originating_change_time;
+ struct GUID originating_invocation_id;
+ uint64_t originating_usn;
+ uint64_t local_usn;
+};
+
+struct drsuapi_DsReplicaAttrValMetaDataCtr {
+ uint32_t count;
+ int32_t enumeration_context;
+ struct drsuapi_DsReplicaAttrValMetaData *array;/* [size_is(count)] */
+};
+
+struct drsuapi_DsReplicaCursor2Ctr {
+ uint32_t count;
+ int32_t enumeration_context;
+ struct drsuapi_DsReplicaCursor2 *array;/* [size_is(count)] */
+};
+
+struct drsuapi_DsReplicaCursor3 {
+ struct GUID source_dsa_invocation_id;
+ uint64_t highest_usn;
+ NTTIME last_sync_success;
+ const char *source_dsa_obj_dn;/* [unique,charset(UTF16)] */
+};
+
+struct drsuapi_DsReplicaCursor3Ctr {
+ uint32_t count;
+ int32_t enumeration_context;
+ struct drsuapi_DsReplicaCursor3 *array;/* [size_is(count)] */
+};
+
+struct drsuapi_DsReplicaObjMetaData2 {
+ const char *attribute_name;/* [unique,charset(UTF16)] */
+ uint32_t version;
+ NTTIME originating_change_time;
+ struct GUID originating_invocation_id;
+ uint64_t originating_usn;
+ uint64_t local_usn;
+ const char *originating_dsa_dn;/* [unique,charset(UTF16)] */
+};
+
+struct drsuapi_DsReplicaObjMetaData2Ctr {
+ uint32_t count;
+ int32_t enumeration_context;
+ struct drsuapi_DsReplicaObjMetaData2 *array;/* [size_is(count)] */
+};
+
+struct drsuapi_DsReplicaAttrValMetaData2 {
+ const char *attribute_name;/* [unique,charset(UTF16)] */
+ const char *object_dn;/* [unique,charset(UTF16)] */
+ uint32_t __ndr_size_binary;/* [value(ndr_size_DATA_BLOB(0,binary,0))] */
+ DATA_BLOB *binary;/* [unique] */
+ NTTIME deleted;
+ NTTIME created;
+ uint32_t version;
+ NTTIME originating_change_time;
+ struct GUID originating_invocation_id;
+ uint64_t originating_usn;
+ uint64_t local_usn;
+ const char *originating_dsa_dn;/* [unique,charset(UTF16)] */
+};
+
+struct drsuapi_DsReplicaAttrValMetaData2Ctr {
+ uint32_t count;
+ int32_t enumeration_context;
+ struct drsuapi_DsReplicaAttrValMetaData2 *array;/* [size_is(count)] */
+};
+
+struct drsuapi_DsReplicaConnection04 {
+ uint64_t u1;
+ uint32_t u2;
+ uint32_t u3;
+ struct GUID bind_guid;
+ NTTIME bind_time;
+ const char * client_ip_address;/* [flag(LIBNDR_FLAG_BIGENDIAN)] */
+ uint32_t u5;
+};
+
+struct drsuapi_DsReplicaConnection04Ctr {
+ uint32_t count;/* [range(0,10000)] */
+ uint32_t reserved;
+ struct drsuapi_DsReplicaConnection04 *array;/* [size_is(count)] */
+};
+
+struct drsuapi_DsReplica06 {
+ const char *str1;/* [unique,charset(UTF16)] */
+ uint32_t u1;
+ uint32_t u2;
+ uint32_t u3;
+ uint32_t u4;
+ uint32_t u5;
+ uint64_t u6;
+ uint32_t u7;
+};
+
+struct drsuapi_DsReplica06Ctr {
+ uint32_t count;/* [range(0,256)] */
+ uint32_t reserved;
+ struct drsuapi_DsReplica06 *array;/* [size_is(count)] */
+};
+
+union drsuapi_DsReplicaInfo {
+ struct drsuapi_DsReplicaNeighbourCtr *neighbours;/* [unique,case(DRSUAPI_DS_REPLICA_INFO_NEIGHBORS)] */
+ struct drsuapi_DsReplicaCursorCtr *cursors;/* [unique,case(DRSUAPI_DS_REPLICA_INFO_CURSORS)] */
+ struct drsuapi_DsReplicaObjMetaDataCtr *objmetadata;/* [unique,case(DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA)] */
+ struct drsuapi_DsReplicaKccDsaFailuresCtr *connectfailures;/* [unique,case(DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES)] */
+ struct drsuapi_DsReplicaKccDsaFailuresCtr *linkfailures;/* [unique,case(DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES)] */
+ struct drsuapi_DsReplicaOpCtr *pendingops;/* [unique,case(DRSUAPI_DS_REPLICA_INFO_PENDING_OPS)] */
+ struct drsuapi_DsReplicaAttrValMetaDataCtr *attrvalmetadata;/* [unique,case(DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA)] */
+ struct drsuapi_DsReplicaCursor2Ctr *cursors2;/* [unique,case(DRSUAPI_DS_REPLICA_INFO_CURSORS2)] */
+ struct drsuapi_DsReplicaCursor3Ctr *cursors3;/* [unique,case(DRSUAPI_DS_REPLICA_INFO_CURSORS3)] */
+ struct drsuapi_DsReplicaObjMetaData2Ctr *objmetadata2;/* [unique,case(DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2)] */
+ struct drsuapi_DsReplicaAttrValMetaData2Ctr *attrvalmetadata2;/* [unique,case(DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2)] */
+ struct drsuapi_DsReplicaNeighbourCtr *neighbours02;/* [unique,case(DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02)] */
+ struct drsuapi_DsReplicaConnection04Ctr *connections04;/* [unique,case(DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04)] */
+ struct drsuapi_DsReplicaCursorCtrEx *cursors05;/* [unique,case(DRSUAPI_DS_REPLICA_INFO_CURSORS05)] */
+ struct drsuapi_DsReplica06Ctr *i06;/* [unique,case(DRSUAPI_DS_REPLICA_INFO_06)] */
+}/* [switch_type(drsuapi_DsReplicaInfoType)] */;
+
+struct drsuapi_DsGetMemberships2Ctr1 {
+ uint32_t num_entries;/* [range(0,10000)] */
+ struct drsuapi_DsGetMembershipsCtr1 **ctrl_array;/* [unique,size_is(num_entries)] */
+};
+
+union drsuapi_DsGetMemberships2Ctr {
+ struct drsuapi_DsGetMembershipsCtr1 ctr1;/* [case] */
+}/* [switch_type(int32)] */;
+
+struct drsuapi_DsGetMemberships2Request1 {
+ uint32_t num_req;/* [range(1,10000)] */
+ struct drsuapi_DsGetMembershipsRequest1 **req_array;/* [unique,size_is(num_req)] */
+};
+
+union drsuapi_DsGetMemberships2Request {
+ struct drsuapi_DsGetMemberships2Request1 req1;/* [case] */
+}/* [switch_type(int32)] */;
+
+struct drsuapi_DsSiteCostInfo {
+ WERROR error_code;
+ uint32_t site_cost;
+};
+
+struct drsuapi_QuerySitesByCostCtr1 {
+ uint32_t num_info;/* [range(0,10000)] */
+ struct drsuapi_DsSiteCostInfo *info;/* [unique,size_is(num_info)] */
+ uint32_t unknown;
+};
+
+union drsuapi_QuerySitesByCostCtr {
+ struct drsuapi_QuerySitesByCostCtr1 ctr1;/* [case] */
+}/* [switch_type(int32)] */;
+
+struct drsuapi_QuerySitesByCostRequest1 {
+ const char *site_from;/* [unique,charset(UTF16)] */
+ uint32_t num_req;/* [range(1,10000)] */
+ const char **site_to;/* [unique,charset(UTF16),size_is(num_req)] */
+ uint32_t flags;
+};
+
+union drsuapi_QuerySitesByCostRequest {
+ struct drsuapi_QuerySitesByCostRequest1 req1;/* [case] */
+}/* [switch_type(int32)] */;
+
+
+struct drsuapi_DsBind {
+ struct {
+ struct GUID *bind_guid;/* [unique] */
+ struct drsuapi_DsBindInfoCtr *bind_info;/* [unique] */
+ } in;
+
+ struct {
+ struct policy_handle *bind_handle;/* [ref] */
+ struct drsuapi_DsBindInfoCtr *bind_info;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct drsuapi_DsUnbind {
+ struct {
+ struct policy_handle *bind_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct policy_handle *bind_handle;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct drsuapi_DsReplicaSync {
+ struct {
+ struct policy_handle *bind_handle;/* [ref] */
+ int32_t level;
+ union drsuapi_DsReplicaSyncRequest req;/* [switch_is(level)] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct drsuapi_DsGetNCChanges {
+ struct {
+ struct policy_handle *bind_handle;/* [ref] */
+ int32_t level;
+ union drsuapi_DsGetNCChangesRequest *req;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ int32_t *level_out;/* [ref] */
+ union drsuapi_DsGetNCChangesCtr *ctr;/* [ref,switch_is(*level_out)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct drsuapi_DsReplicaUpdateRefs {
+ struct {
+ struct policy_handle *bind_handle;/* [ref] */
+ int32_t level;
+ union drsuapi_DsReplicaUpdateRefsRequest req;/* [switch_is(level)] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct DRSUAPI_REPLICA_ADD {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct DRSUAPI_REPLICA_DEL {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct DRSUAPI_REPLICA_MODIFY {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct DRSUAPI_VERIFY_NAMES {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct drsuapi_DsGetMemberships {
+ struct {
+ struct policy_handle *bind_handle;/* [ref] */
+ int32_t level;
+ union drsuapi_DsGetMembershipsRequest *req;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ int32_t *level_out;/* [ref] */
+ union drsuapi_DsGetMembershipsCtr *ctr;/* [ref,switch_is(*level_out)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct DRSUAPI_INTER_DOMAIN_MOVE {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct drsuapi_DsGetNT4ChangeLog {
+ struct {
+ struct policy_handle *bind_handle;/* [ref] */
+ uint32_t level;
+ union drsuapi_DsGetNT4ChangeLogRequest *req;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ uint32_t *level_out;/* [ref] */
+ union drsuapi_DsGetNT4ChangeLogInfo *info;/* [ref,switch_is(*level_out)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct drsuapi_DsCrackNames {
+ struct {
+ struct policy_handle *bind_handle;/* [ref] */
+ int32_t level;
+ union drsuapi_DsNameRequest *req;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ int32_t *level_out;/* [ref] */
+ union drsuapi_DsNameCtr *ctr;/* [ref,switch_is(*level_out)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct drsuapi_DsWriteAccountSpn {
+ struct {
+ struct policy_handle *bind_handle;/* [ref] */
+ int32_t level;
+ union drsuapi_DsWriteAccountSpnRequest *req;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ int32_t *level_out;/* [ref] */
+ union drsuapi_DsWriteAccountSpnResult *res;/* [ref,switch_is(*level_out)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct drsuapi_DsRemoveDSServer {
+ struct {
+ struct policy_handle *bind_handle;/* [ref] */
+ int32_t level;
+ union drsuapi_DsRemoveDSServerRequest *req;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ int32_t *level_out;/* [ref] */
+ union drsuapi_DsRemoveDSServerResult *res;/* [ref,switch_is(*level_out)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct DRSUAPI_REMOVE_DS_DOMAIN {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct drsuapi_DsGetDomainControllerInfo {
+ struct {
+ struct policy_handle *bind_handle;/* [ref] */
+ int32_t level;
+ union drsuapi_DsGetDCInfoRequest *req;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ int32_t *level_out;/* [ref] */
+ union drsuapi_DsGetDCInfoCtr *ctr;/* [ref,switch_is(*level_out)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct drsuapi_DsAddEntry {
+ struct {
+ struct policy_handle *bind_handle;/* [ref] */
+ int32_t level;
+ union drsuapi_DsAddEntryRequest *req;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ int32_t *level_out;/* [ref] */
+ union drsuapi_DsAddEntryCtr *ctr;/* [ref,switch_is(*level_out)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct DRSUAPI_EXECUTE_KCC {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct drsuapi_DsReplicaGetInfo {
+ struct {
+ struct policy_handle *bind_handle;/* [ref] */
+ enum drsuapi_DsReplicaGetInfoLevel level;
+ union drsuapi_DsReplicaGetInfoRequest *req;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ enum drsuapi_DsReplicaInfoType *info_type;/* [ref] */
+ union drsuapi_DsReplicaInfo *info;/* [ref,switch_is(*info_type)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct DRSUAPI_ADD_SID_HISTORY {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct drsuapi_DsGetMemberships2 {
+ struct {
+ struct policy_handle *bind_handle;/* [ref] */
+ int32_t level;
+ union drsuapi_DsGetMemberships2Request *req;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ int32_t *level_out;/* [ref] */
+ union drsuapi_DsGetMemberships2Ctr *ctr;/* [ref,switch_is(*level_out)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct DRSUAPI_REPLICA_VERIFY_OBJECTS {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct DRSUAPI_GET_OBJECT_EXISTENCE {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct drsuapi_QuerySitesByCost {
+ struct {
+ struct policy_handle *bind_handle;/* [ref] */
+ int32_t level;
+ union drsuapi_QuerySitesByCostRequest *req;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ int32_t *level_out;/* [ref] */
+ union drsuapi_QuerySitesByCostCtr *ctr;/* [ref,switch_is(*level_out)] */
+ WERROR result;
+ } out;
+
+};
+
+#endif /* _HEADER_drsuapi */
diff --git a/source3/librpc/gen_ndr/dssetup.h b/source3/librpc/gen_ndr/dssetup.h
new file mode 100644
index 0000000000..d284a63375
--- /dev/null
+++ b/source3/librpc/gen_ndr/dssetup.h
@@ -0,0 +1,211 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#include "librpc/gen_ndr/misc.h"
+#ifndef _HEADER_dssetup
+#define _HEADER_dssetup
+
+enum dssetup_DsRole
+#ifndef USE_UINT_ENUMS
+ {
+ DS_ROLE_STANDALONE_WORKSTATION=0,
+ DS_ROLE_MEMBER_WORKSTATION=1,
+ DS_ROLE_STANDALONE_SERVER=2,
+ DS_ROLE_MEMBER_SERVER=3,
+ DS_ROLE_BACKUP_DC=4,
+ DS_ROLE_PRIMARY_DC=5
+}
+#else
+ { __donnot_use_enum_dssetup_DsRole=0x7FFFFFFF}
+#define DS_ROLE_STANDALONE_WORKSTATION ( 0 )
+#define DS_ROLE_MEMBER_WORKSTATION ( 1 )
+#define DS_ROLE_STANDALONE_SERVER ( 2 )
+#define DS_ROLE_MEMBER_SERVER ( 3 )
+#define DS_ROLE_BACKUP_DC ( 4 )
+#define DS_ROLE_PRIMARY_DC ( 5 )
+#endif
+;
+
+/* bitmap dssetup_DsRoleFlags */
+#define DS_ROLE_PRIMARY_DS_RUNNING ( 0x00000001 )
+#define DS_ROLE_PRIMARY_DS_MIXED_MODE ( 0x00000002 )
+#define DS_ROLE_UPGRADE_IN_PROGRESS ( 0x00000004 )
+#define DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT ( 0x01000000 )
+
+struct dssetup_DsRolePrimaryDomInfoBasic {
+ enum dssetup_DsRole role;
+ uint32_t flags;
+ const char *domain;/* [unique,charset(UTF16)] */
+ const char *dns_domain;/* [unique,charset(UTF16)] */
+ const char *forest;/* [unique,charset(UTF16)] */
+ struct GUID domain_guid;
+};
+
+enum dssetup_DsUpgrade
+#ifndef USE_UINT_ENUMS
+ {
+ DS_ROLE_NOT_UPGRADING=0,
+ DS_ROLE_UPGRADING=1
+}
+#else
+ { __donnot_use_enum_dssetup_DsUpgrade=0x7FFFFFFF}
+#define DS_ROLE_NOT_UPGRADING ( 0 )
+#define DS_ROLE_UPGRADING ( 1 )
+#endif
+;
+
+enum dssetup_DsPrevious
+#ifndef USE_UINT_ENUMS
+ {
+ DS_ROLE_PREVIOUS_UNKNOWN=0,
+ DS_ROLE_PREVIOUS_PRIMARY=1,
+ DS_ROLE_PREVIOUS_BACKUP=2
+}
+#else
+ { __donnot_use_enum_dssetup_DsPrevious=0x7FFFFFFF}
+#define DS_ROLE_PREVIOUS_UNKNOWN ( 0 )
+#define DS_ROLE_PREVIOUS_PRIMARY ( 1 )
+#define DS_ROLE_PREVIOUS_BACKUP ( 2 )
+#endif
+;
+
+struct dssetup_DsRoleUpgradeStatus {
+ enum dssetup_DsUpgrade upgrading;
+ enum dssetup_DsPrevious previous_role;
+};
+
+enum dssetup_DsRoleOp
+#ifndef USE_UINT_ENUMS
+ {
+ DS_ROLE_OP_IDLE=0,
+ DS_ROLE_OP_ACTIVE=1,
+ DS_ROLE_OP_NEEDS_REBOOT=2
+}
+#else
+ { __donnot_use_enum_dssetup_DsRoleOp=0x7FFFFFFF}
+#define DS_ROLE_OP_IDLE ( 0 )
+#define DS_ROLE_OP_ACTIVE ( 1 )
+#define DS_ROLE_OP_NEEDS_REBOOT ( 2 )
+#endif
+;
+
+struct dssetup_DsRoleOpStatus {
+ enum dssetup_DsRoleOp status;
+};
+
+enum dssetup_DsRoleInfoLevel
+#ifndef USE_UINT_ENUMS
+ {
+ DS_ROLE_BASIC_INFORMATION=1,
+ DS_ROLE_UPGRADE_STATUS=2,
+ DS_ROLE_OP_STATUS=3
+}
+#else
+ { __donnot_use_enum_dssetup_DsRoleInfoLevel=0x7FFFFFFF}
+#define DS_ROLE_BASIC_INFORMATION ( 1 )
+#define DS_ROLE_UPGRADE_STATUS ( 2 )
+#define DS_ROLE_OP_STATUS ( 3 )
+#endif
+;
+
+union dssetup_DsRoleInfo {
+ struct dssetup_DsRolePrimaryDomInfoBasic basic;/* [case(DS_ROLE_BASIC_INFORMATION)] */
+ struct dssetup_DsRoleUpgradeStatus upgrade;/* [case(DS_ROLE_UPGRADE_STATUS)] */
+ struct dssetup_DsRoleOpStatus opstatus;/* [case(DS_ROLE_OP_STATUS)] */
+}/* [switch_type(dssetup_DsRoleInfoLevel)] */;
+
+
+struct dssetup_DsRoleGetPrimaryDomainInformation {
+ struct {
+ enum dssetup_DsRoleInfoLevel level;
+ } in;
+
+ struct {
+ union dssetup_DsRoleInfo *info;/* [unique,switch_is(level)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct dssetup_DsRoleDnsNameToFlatName {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dssetup_DsRoleDcAsDc {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dssetup_DsRoleDcAsReplica {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dssetup_DsRoleDemoteDc {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dssetup_DsRoleGetDcOperationProgress {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dssetup_DsRoleGetDcOperationResults {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dssetup_DsRoleCancel {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dssetup_DsRoleServerSaveStateForUpgrade {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dssetup_DsRoleUpgradeDownlevelServer {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct dssetup_DsRoleAbortDownlevelServerUpgrade {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+#endif /* _HEADER_dssetup */
diff --git a/source3/librpc/gen_ndr/echo.h b/source3/librpc/gen_ndr/echo.h
new file mode 100644
index 0000000000..c8b5b86422
--- /dev/null
+++ b/source3/librpc/gen_ndr/echo.h
@@ -0,0 +1,213 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#ifndef _HEADER_rpcecho
+#define _HEADER_rpcecho
+
+struct echo_info1 {
+ uint8_t v;
+};
+
+struct echo_info2 {
+ uint16_t v;
+};
+
+struct echo_info3 {
+ uint32_t v;
+};
+
+struct echo_info4 {
+ uint64_t v;
+};
+
+struct echo_info5 {
+ uint8_t v1;
+ uint64_t v2;
+};
+
+struct echo_info6 {
+ uint8_t v1;
+ struct echo_info1 info1;
+};
+
+struct echo_info7 {
+ uint8_t v1;
+ struct echo_info4 info4;
+};
+
+union echo_Info {
+ struct echo_info1 info1;/* [case] */
+ struct echo_info2 info2;/* [case(2)] */
+ struct echo_info3 info3;/* [case(3)] */
+ struct echo_info4 info4;/* [case(4)] */
+ struct echo_info5 info5;/* [case(5)] */
+ struct echo_info6 info6;/* [case(6)] */
+ struct echo_info7 info7;/* [case(7)] */
+}/* [switch_type(uint16)] */;
+
+enum echo_Enum1
+#ifndef USE_UINT_ENUMS
+ {
+ ECHO_ENUM1=1,
+ ECHO_ENUM2=2
+}
+#else
+ { __donnot_use_enum_echo_Enum1=0x7FFFFFFF}
+#define ECHO_ENUM1 ( 1 )
+#define ECHO_ENUM2 ( 2 )
+#endif
+;
+
+enum echo_Enum1_32
+#ifndef USE_UINT_ENUMS
+ {
+ ECHO_ENUM1_32=1,
+ ECHO_ENUM2_32=2
+}
+#else
+ { __donnot_use_enum_echo_Enum1_32=0x7FFFFFFF}
+#define ECHO_ENUM1_32 ( 1 )
+#define ECHO_ENUM2_32 ( 2 )
+#endif
+;
+
+struct echo_Enum2 {
+ enum echo_Enum1 e1;
+ enum echo_Enum1_32 e2;
+};
+
+union echo_Enum3 {
+ enum echo_Enum1 e1;/* [case(ECHO_ENUM1)] */
+ struct echo_Enum2 e2;/* [case(ECHO_ENUM2)] */
+}/* [switch_type(uint16)] */;
+
+struct echo_Surrounding {
+ uint32_t x;
+ uint16_t *surrounding;/* [size_is(x)] */
+};
+
+
+struct echo_AddOne {
+ struct {
+ uint32_t in_data;
+ } in;
+
+ struct {
+ uint32_t *out_data;/* [ref] */
+ } out;
+
+};
+
+
+struct echo_EchoData {
+ struct {
+ uint32_t len;
+ uint8_t *in_data;/* [size_is(len)] */
+ } in;
+
+ struct {
+ uint8_t *out_data;/* [size_is(len)] */
+ } out;
+
+};
+
+
+struct echo_SinkData {
+ struct {
+ uint32_t len;
+ uint8_t *data;/* [size_is(len)] */
+ } in;
+
+};
+
+
+struct echo_SourceData {
+ struct {
+ uint32_t len;
+ } in;
+
+ struct {
+ uint8_t *data;/* [size_is(len)] */
+ } out;
+
+};
+
+
+struct echo_TestCall {
+ struct {
+ const char *s1;/* [ref,charset(UTF16)] */
+ } in;
+
+ struct {
+ const char **s2;/* [ref,charset(UTF16)] */
+ } out;
+
+};
+
+
+struct echo_TestCall2 {
+ struct {
+ uint16_t level;
+ } in;
+
+ struct {
+ union echo_Info *info;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct echo_TestSleep {
+ struct {
+ uint32_t seconds;
+ } in;
+
+ struct {
+ uint32_t result;
+ } out;
+
+};
+
+
+struct echo_TestEnum {
+ struct {
+ enum echo_Enum1 *foo1;/* [ref] */
+ struct echo_Enum2 *foo2;/* [ref] */
+ union echo_Enum3 *foo3;/* [ref,switch_is(*foo1)] */
+ } in;
+
+ struct {
+ enum echo_Enum1 *foo1;/* [ref] */
+ struct echo_Enum2 *foo2;/* [ref] */
+ union echo_Enum3 *foo3;/* [ref,switch_is(*foo1)] */
+ } out;
+
+};
+
+
+struct echo_TestSurrounding {
+ struct {
+ struct echo_Surrounding *data;/* [ref] */
+ } in;
+
+ struct {
+ struct echo_Surrounding *data;/* [ref] */
+ } out;
+
+};
+
+
+struct echo_TestDoublePointer {
+ struct {
+ uint16_t ***data;/* [ref] */
+ } in;
+
+ struct {
+ uint16_t result;
+ } out;
+
+};
+
+#endif /* _HEADER_rpcecho */
diff --git a/source3/librpc/gen_ndr/epmapper.h b/source3/librpc/gen_ndr/epmapper.h
new file mode 100644
index 0000000000..d39269b32b
--- /dev/null
+++ b/source3/librpc/gen_ndr/epmapper.h
@@ -0,0 +1,354 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#ifndef _HEADER_epmapper
+#define _HEADER_epmapper
+
+#define EPMAPPER_STATUS_NO_MORE_ENTRIES ( 0x16c9a0d6 )
+#define EPMAPPER_STATUS_NO_MEMORY ( 0x16C9A012 )
+#define EPMAPPER_STATUS_OK ( 0 )
+enum epm_protocol
+#ifndef USE_UINT_ENUMS
+ {
+ EPM_PROTOCOL_DNET_NSP=0x04,
+ EPM_PROTOCOL_OSI_TP4=0x05,
+ EPM_PROTOCOL_OSI_CLNS=0x06,
+ EPM_PROTOCOL_TCP=0x07,
+ EPM_PROTOCOL_UDP=0x08,
+ EPM_PROTOCOL_IP=0x09,
+ EPM_PROTOCOL_NCADG=0x0a,
+ EPM_PROTOCOL_NCACN=0x0b,
+ EPM_PROTOCOL_NCALRPC=0x0c,
+ EPM_PROTOCOL_UUID=0x0d,
+ EPM_PROTOCOL_IPX=0x0e,
+ EPM_PROTOCOL_SMB=0x0f,
+ EPM_PROTOCOL_PIPE=0x10,
+ EPM_PROTOCOL_NETBIOS=0x11,
+ EPM_PROTOCOL_NETBEUI=0x12,
+ EPM_PROTOCOL_SPX=0x13,
+ EPM_PROTOCOL_NB_IPX=0x14,
+ EPM_PROTOCOL_DSP=0x16,
+ EPM_PROTOCOL_DDP=0x17,
+ EPM_PROTOCOL_APPLETALK=0x18,
+ EPM_PROTOCOL_VINES_SPP=0x1a,
+ EPM_PROTOCOL_VINES_IPC=0x1b,
+ EPM_PROTOCOL_STREETTALK=0x1c,
+ EPM_PROTOCOL_HTTP=0x1f,
+ EPM_PROTOCOL_UNIX_DS=0x20,
+ EPM_PROTOCOL_NULL=0x21
+}
+#else
+ { __donnot_use_enum_epm_protocol=0x7FFFFFFF}
+#define EPM_PROTOCOL_DNET_NSP ( 0x04 )
+#define EPM_PROTOCOL_OSI_TP4 ( 0x05 )
+#define EPM_PROTOCOL_OSI_CLNS ( 0x06 )
+#define EPM_PROTOCOL_TCP ( 0x07 )
+#define EPM_PROTOCOL_UDP ( 0x08 )
+#define EPM_PROTOCOL_IP ( 0x09 )
+#define EPM_PROTOCOL_NCADG ( 0x0a )
+#define EPM_PROTOCOL_NCACN ( 0x0b )
+#define EPM_PROTOCOL_NCALRPC ( 0x0c )
+#define EPM_PROTOCOL_UUID ( 0x0d )
+#define EPM_PROTOCOL_IPX ( 0x0e )
+#define EPM_PROTOCOL_SMB ( 0x0f )
+#define EPM_PROTOCOL_PIPE ( 0x10 )
+#define EPM_PROTOCOL_NETBIOS ( 0x11 )
+#define EPM_PROTOCOL_NETBEUI ( 0x12 )
+#define EPM_PROTOCOL_SPX ( 0x13 )
+#define EPM_PROTOCOL_NB_IPX ( 0x14 )
+#define EPM_PROTOCOL_DSP ( 0x16 )
+#define EPM_PROTOCOL_DDP ( 0x17 )
+#define EPM_PROTOCOL_APPLETALK ( 0x18 )
+#define EPM_PROTOCOL_VINES_SPP ( 0x1a )
+#define EPM_PROTOCOL_VINES_IPC ( 0x1b )
+#define EPM_PROTOCOL_STREETTALK ( 0x1c )
+#define EPM_PROTOCOL_HTTP ( 0x1f )
+#define EPM_PROTOCOL_UNIX_DS ( 0x20 )
+#define EPM_PROTOCOL_NULL ( 0x21 )
+#endif
+;
+
+struct epm_rhs_dnet_nsp {
+ char _empty_;
+};
+
+struct epm_rhs_osi_tp4 {
+ char _empty_;
+};
+
+struct epm_rhs_osi_clns {
+ char _empty_;
+};
+
+struct epm_rhs_udp {
+ uint16_t port;
+};
+
+struct epm_rhs_tcp {
+ uint16_t port;
+};
+
+struct epm_rhs_ip {
+ const char * ipaddr;
+};
+
+struct epm_rhs_ncadg {
+ uint16_t minor_version;
+};
+
+struct epm_rhs_ncacn {
+ uint16_t minor_version;
+};
+
+struct epm_rhs_uuid {
+ DATA_BLOB unknown;/* [flag(LIBNDR_FLAG_REMAINING)] */
+};
+
+struct epm_rhs_ipx {
+ char _empty_;
+};
+
+struct epm_rhs_smb {
+ const char * unc;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+};
+
+struct epm_rhs_pipe {
+ const char * path;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+};
+
+struct epm_rhs_netbios {
+ const char * name;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+};
+
+struct epm_rhs_netbeui {
+ char _empty_;
+};
+
+struct epm_rhs_spx {
+ char _empty_;
+};
+
+struct epm_rhs_nb_ipx {
+ char _empty_;
+};
+
+struct epm_rhs_http {
+ uint16_t port;
+};
+
+struct epm_rhs_unix_ds {
+ const char * path;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+};
+
+struct epm_rhs_null {
+ char _empty_;
+};
+
+struct epm_rhs_ncalrpc {
+ uint16_t minor_version;
+};
+
+struct epm_rhs_appletalk {
+ char _empty_;
+};
+
+struct epm_rhs_atalk_stream {
+ char _empty_;
+};
+
+struct epm_rhs_atalk_datagram {
+ char _empty_;
+};
+
+struct epm_rhs_vines_spp {
+ uint16_t port;
+};
+
+struct epm_rhs_vines_ipc {
+ uint16_t port;
+};
+
+struct epm_rhs_streettalk {
+ const char * streettalk;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+};
+
+union epm_rhs {
+ struct epm_rhs_dnet_nsp dnet_nsp;/* [case(EPM_PROTOCOL_DNET_NSP)] */
+ struct epm_rhs_osi_tp4 osi_tp4;/* [case(EPM_PROTOCOL_OSI_TP4)] */
+ struct epm_rhs_osi_clns osi_clns;/* [case(EPM_PROTOCOL_OSI_CLNS)] */
+ struct epm_rhs_tcp tcp;/* [case(EPM_PROTOCOL_TCP)] */
+ struct epm_rhs_udp udp;/* [case(EPM_PROTOCOL_UDP)] */
+ struct epm_rhs_ip ip;/* [case(EPM_PROTOCOL_IP)] */
+ struct epm_rhs_ncadg ncadg;/* [case(EPM_PROTOCOL_NCADG)] */
+ struct epm_rhs_ncacn ncacn;/* [case(EPM_PROTOCOL_NCACN)] */
+ struct epm_rhs_ncalrpc ncalrpc;/* [case(EPM_PROTOCOL_NCALRPC)] */
+ struct epm_rhs_uuid uuid;/* [case(EPM_PROTOCOL_UUID)] */
+ struct epm_rhs_ipx ipx;/* [case(EPM_PROTOCOL_IPX)] */
+ struct epm_rhs_smb smb;/* [case(EPM_PROTOCOL_SMB)] */
+ struct epm_rhs_pipe pipe;/* [case(EPM_PROTOCOL_PIPE)] */
+ struct epm_rhs_netbios netbios;/* [case(EPM_PROTOCOL_NETBIOS)] */
+ struct epm_rhs_netbeui netbeui;/* [case(EPM_PROTOCOL_NETBEUI)] */
+ struct epm_rhs_spx spx;/* [case(EPM_PROTOCOL_SPX)] */
+ struct epm_rhs_nb_ipx nb_ipx;/* [case(EPM_PROTOCOL_NB_IPX)] */
+ struct epm_rhs_atalk_stream atalk_stream;/* [case(EPM_PROTOCOL_DSP)] */
+ struct epm_rhs_atalk_datagram atalk_datagram;/* [case(EPM_PROTOCOL_DDP)] */
+ struct epm_rhs_appletalk appletalk;/* [case(EPM_PROTOCOL_APPLETALK)] */
+ struct epm_rhs_vines_spp vines_spp;/* [case(EPM_PROTOCOL_VINES_SPP)] */
+ struct epm_rhs_vines_ipc vines_ipc;/* [case(EPM_PROTOCOL_VINES_IPC)] */
+ struct epm_rhs_streettalk streettalk;/* [case(EPM_PROTOCOL_STREETTALK)] */
+ struct epm_rhs_http http;/* [case(EPM_PROTOCOL_HTTP)] */
+ struct epm_rhs_unix_ds unix_ds;/* [case(EPM_PROTOCOL_UNIX_DS)] */
+ struct epm_rhs_null null;/* [case(EPM_PROTOCOL_NULL)] */
+ DATA_BLOB unknown;/* [default,flag(LIBNDR_FLAG_REMAINING)] */
+}/* [nodiscriminant,flag(LIBNDR_FLAG_BIGENDIAN)] */;
+
+struct epm_lhs {
+ enum epm_protocol protocol;
+ DATA_BLOB lhs_data;/* [flag(LIBNDR_FLAG_REMAINING)] */
+};
+
+struct epm_floor {
+ struct epm_lhs lhs;/* [subcontext(2)] */
+ union epm_rhs rhs;/* [subcontext(2),switch_is(lhs.protocol)] */
+};
+
+struct epm_tower {
+ uint16_t num_floors;
+ struct epm_floor *floors;
+}/* [gensize,flag(LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_LITTLE_ENDIAN)] */;
+
+struct epm_twr_t {
+ uint32_t tower_length;/* [value(ndr_size_epm_tower(&tower,ndr->flags))] */
+ struct epm_tower tower;/* [subcontext(4)] */
+};
+
+struct epm_entry_t {
+ struct GUID object;
+ struct epm_twr_t *tower;/* [ptr] */
+ const char * annotation;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_LEN4)] */
+};
+
+struct rpc_if_id_t {
+ struct GUID uuid;
+ uint16_t vers_major;
+ uint16_t vers_minor;
+};
+
+struct epm_twr_p_t {
+ struct epm_twr_t *twr;/* [ptr] */
+};
+
+
+struct epm_Insert {
+ struct {
+ uint32_t num_ents;
+ struct epm_entry_t *entries;/* [size_is(num_ents)] */
+ uint32_t replace;
+ } in;
+
+ struct {
+ uint32_t result;
+ } out;
+
+};
+
+
+struct epm_Delete {
+ struct {
+ uint32_t num_ents;
+ struct epm_entry_t *entries;/* [size_is(num_ents)] */
+ } in;
+
+ struct {
+ uint32_t result;
+ } out;
+
+};
+
+
+struct epm_Lookup {
+ struct {
+ uint32_t inquiry_type;
+ struct GUID *object;/* [ptr] */
+ struct rpc_if_id_t *interface_id;/* [ptr] */
+ uint32_t vers_option;
+ uint32_t max_ents;
+ struct policy_handle *entry_handle;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *num_ents;/* [ref] */
+ struct epm_entry_t *entries;/* [length_is(*num_ents),size_is(max_ents)] */
+ struct policy_handle *entry_handle;/* [ref] */
+ uint32_t result;
+ } out;
+
+};
+
+
+struct epm_Map {
+ struct {
+ struct GUID *object;/* [ptr] */
+ struct epm_twr_t *map_tower;/* [ptr] */
+ uint32_t max_towers;
+ struct policy_handle *entry_handle;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *num_towers;/* [ref] */
+ struct epm_twr_p_t *towers;/* [length_is(*num_towers),size_is(max_towers)] */
+ struct policy_handle *entry_handle;/* [ref] */
+ uint32_t result;
+ } out;
+
+};
+
+
+struct epm_LookupHandleFree {
+ struct {
+ struct policy_handle *entry_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct policy_handle *entry_handle;/* [ref] */
+ uint32_t result;
+ } out;
+
+};
+
+
+struct epm_InqObject {
+ struct {
+ struct GUID *epm_object;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t result;
+ } out;
+
+};
+
+
+struct epm_MgmtDelete {
+ struct {
+ uint32_t object_speced;
+ struct GUID *object;/* [ptr] */
+ struct epm_twr_t *tower;/* [ptr] */
+ } in;
+
+ struct {
+ uint32_t result;
+ } out;
+
+};
+
+
+struct epm_MapAuth {
+ struct {
+ uint32_t result;
+ } out;
+
+};
+
+#endif /* _HEADER_epmapper */
diff --git a/source3/librpc/gen_ndr/eventlog.h b/source3/librpc/gen_ndr/eventlog.h
new file mode 100644
index 0000000000..0fd929dd99
--- /dev/null
+++ b/source3/librpc/gen_ndr/eventlog.h
@@ -0,0 +1,287 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#include "librpc/gen_ndr/lsa.h"
+#include "librpc/gen_ndr/security.h"
+#ifndef _HEADER_eventlog
+#define _HEADER_eventlog
+
+/* bitmap eventlogReadFlags */
+#define EVENTLOG_SEQUENTIAL_READ ( 0x0001 )
+#define EVENTLOG_SEEK_READ ( 0x0002 )
+#define EVENTLOG_FORWARDS_READ ( 0x0004 )
+#define EVENTLOG_BACKWARDS_READ ( 0x0008 )
+
+/* bitmap eventlogEventTypes */
+#define EVENTLOG_SUCCESS ( 0x0000 )
+#define EVENTLOG_ERROR_TYPE ( 0x0001 )
+#define EVENTLOG_WARNING_TYPE ( 0x0002 )
+#define EVENTLOG_INFORMATION_TYPE ( 0x0004 )
+#define EVENTLOG_AUDIT_SUCCESS ( 0x0008 )
+#define EVENTLOG_AUDIT_FAILURE ( 0x0010 )
+
+struct eventlog_OpenUnknown0 {
+ uint16_t unknown0;
+ uint16_t unknown1;
+};
+
+struct eventlog_Record {
+ uint32_t size;
+ uint32_t reserved;
+ uint32_t record_number;
+ uint32_t time_generated;
+ uint32_t time_written;
+ uint32_t event_id;
+ uint16_t event_type;
+ uint16_t num_of_strings;
+ uint16_t event_category;
+ uint16_t reserved_flags;
+ uint32_t closing_record_number;
+ uint32_t stringoffset;
+ uint32_t sid_length;
+ uint32_t sid_offset;
+ uint32_t data_length;
+ uint32_t data_offset;
+ const char * source_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * computer_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * *strings;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * raw_data;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+}/* [public] */;
+
+
+struct eventlog_ClearEventLogW {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct lsa_String *backupfile;/* [unique] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_BackupEventLogW {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_CloseEventLog {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_DeregisterEventSource {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_GetNumRecords {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *number;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_GetOldestRecord {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *oldest_entry;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_ChangeNotify {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_OpenEventLogW {
+ struct {
+ struct eventlog_OpenUnknown0 *unknown0;/* [unique] */
+ struct lsa_String *logname;/* [ref] */
+ struct lsa_String *servername;/* [ref] */
+ uint32_t unknown2;
+ uint32_t unknown3;
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_RegisterEventSourceW {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_OpenBackupEventLogW {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_ReadEventLogW {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t flags;
+ uint32_t offset;
+ uint32_t number_of_bytes;/* [range(0,0x7FFFF)] */
+ } in;
+
+ struct {
+ uint8_t *data;/* [ref,size_is(number_of_bytes)] */
+ uint32_t *sent_size;/* [ref] */
+ uint32_t *real_size;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_ReportEventW {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_ClearEventLogA {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_BackupEventLogA {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_OpenEventLogA {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_RegisterEventSourceA {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_OpenBackupEventLogA {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_ReadEventLogA {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_ReportEventA {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_RegisterClusterSvc {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_DeregisterClusterSvc {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_WriteClusterEvents {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_GetLogIntormation {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct eventlog_FlushEventLog {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+#endif /* _HEADER_eventlog */
diff --git a/source3/librpc/gen_ndr/initshutdown.h b/source3/librpc/gen_ndr/initshutdown.h
new file mode 100644
index 0000000000..366f017c97
--- /dev/null
+++ b/source3/librpc/gen_ndr/initshutdown.h
@@ -0,0 +1,64 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#ifndef _HEADER_initshutdown
+#define _HEADER_initshutdown
+
+struct initshutdown_String_sub {
+ uint32_t name_size;/* [value(strlen_m_term(name))] */
+ const char * name;/* [flag(LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM)] */
+};
+
+struct initshutdown_String {
+ uint16_t name_len;/* [value(strlen_m(name->name)*2)] */
+ uint16_t name_size;/* [value(strlen_m_term(name->name)*2)] */
+ struct initshutdown_String_sub *name;/* [unique] */
+}/* [public] */;
+
+
+struct initshutdown_Init {
+ struct {
+ uint16_t *hostname;/* [unique] */
+ struct initshutdown_String *message;/* [unique] */
+ uint32_t timeout;
+ uint8_t force_apps;
+ uint8_t do_reboot;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct initshutdown_Abort {
+ struct {
+ uint16_t *server;/* [unique] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct initshutdown_InitEx {
+ struct {
+ uint16_t *hostname;/* [unique] */
+ struct initshutdown_String *message;/* [unique] */
+ uint32_t timeout;
+ uint8_t force_apps;
+ uint8_t do_reboot;
+ uint32_t reason;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+#endif /* _HEADER_initshutdown */
diff --git a/source3/librpc/gen_ndr/krb5pac.h b/source3/librpc/gen_ndr/krb5pac.h
new file mode 100644
index 0000000000..b3b29e5b2f
--- /dev/null
+++ b/source3/librpc/gen_ndr/krb5pac.h
@@ -0,0 +1,137 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#include "librpc/gen_ndr/security.h"
+#include "librpc/gen_ndr/netlogon.h"
+#include "librpc/gen_ndr/samr.h"
+#ifndef _HEADER_krb5pac
+#define _HEADER_krb5pac
+
+struct PAC_LOGON_NAME {
+ NTTIME logon_time;
+ uint16_t size;/* [value(2*strlen_m(account_name))] */
+ const char *account_name;/* [charset(UTF16)] */
+};
+
+struct PAC_SIGNATURE_DATA {
+ uint32_t type;
+ DATA_BLOB signature;/* [flag(LIBNDR_FLAG_REMAINING)] */
+}/* [public,flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+struct PAC_LOGON_INFO {
+ struct netr_SamInfo3 info3;
+ struct dom_sid2 *res_group_dom_sid;/* [unique] */
+ struct samr_RidWithAttributeArray res_groups;
+}/* [gensize] */;
+
+struct PAC_UNKNOWN_12 {
+ uint16_t upn_size;/* [value(2*strlen_m(upn_name))] */
+ uint16_t upn_offset;
+ uint16_t domain_size;/* [value(2*strlen_m(domain_name))] */
+ uint16_t domain_offset;
+ uint16_t unknown3;
+ uint16_t unknown4;
+ uint32_t unknown5;
+ const char *upn_name;/* [charset(UTF16)] */
+ const char *domain_name;/* [charset(UTF16)] */
+ uint32_t unknown6;
+};
+
+struct PAC_LOGON_INFO_CTR {
+ uint32_t unknown1;/* [value(0x00081001)] */
+ uint32_t unknown2;/* [value(0xCCCCCCCC)] */
+ uint32_t _ndr_size;/* [value(NDR_ROUND(ndr_size_PAC_LOGON_INFO(info,ndr->flags)+4,8))] */
+ uint32_t unknown3;/* [value(0x00000000)] */
+ struct PAC_LOGON_INFO *info;/* [unique] */
+}/* [public] */;
+
+enum PAC_TYPE
+#ifndef USE_UINT_ENUMS
+ {
+ PAC_TYPE_LOGON_INFO=1,
+ PAC_TYPE_SRV_CHECKSUM=6,
+ PAC_TYPE_KDC_CHECKSUM=7,
+ PAC_TYPE_LOGON_NAME=10,
+ PAC_TYPE_CONSTRAINED_DELEGATION=11,
+ PAC_TYPE_UNKNOWN_12=12
+}
+#else
+ { __donnot_use_enum_PAC_TYPE=0x7FFFFFFF}
+#define PAC_TYPE_LOGON_INFO ( 1 )
+#define PAC_TYPE_SRV_CHECKSUM ( 6 )
+#define PAC_TYPE_KDC_CHECKSUM ( 7 )
+#define PAC_TYPE_LOGON_NAME ( 10 )
+#define PAC_TYPE_CONSTRAINED_DELEGATION ( 11 )
+#define PAC_TYPE_UNKNOWN_12 ( 12 )
+#endif
+;
+
+struct DATA_BLOB_REM {
+ DATA_BLOB remaining;/* [flag(LIBNDR_FLAG_REMAINING)] */
+};
+
+union PAC_INFO {
+ struct PAC_LOGON_INFO_CTR logon_info;/* [case(PAC_TYPE_LOGON_INFO)] */
+ struct PAC_SIGNATURE_DATA srv_cksum;/* [case(PAC_TYPE_SRV_CHECKSUM)] */
+ struct PAC_SIGNATURE_DATA kdc_cksum;/* [case(PAC_TYPE_KDC_CHECKSUM)] */
+ struct PAC_LOGON_NAME logon_name;/* [case(PAC_TYPE_LOGON_NAME)] */
+ struct DATA_BLOB_REM unknown;/* [subcontext(0),default] */
+}/* [gensize,nodiscriminant,public] */;
+
+struct PAC_BUFFER {
+ enum PAC_TYPE type;
+ uint32_t _ndr_size;/* [value(_ndr_size_PAC_INFO(info,type,0))] */
+ union PAC_INFO *info;/* [relative,subcontext_size(_subcontext_size_PAC_INFO(r,ndr->flags)),subcontext(0),switch_is(type),flag(LIBNDR_FLAG_ALIGN8)] */
+ uint32_t _pad;/* [value(0)] */
+}/* [noprint,nopull,public,nopush] */;
+
+struct PAC_DATA {
+ uint32_t num_buffers;
+ uint32_t version;
+ struct PAC_BUFFER *buffers;
+}/* [public] */;
+
+struct PAC_BUFFER_RAW {
+ enum PAC_TYPE type;
+ uint32_t ndr_size;
+ struct DATA_BLOB_REM *info;/* [relative,subcontext_size(NDR_ROUND(ndr_size,8)),subcontext(0),flag(LIBNDR_FLAG_ALIGN8)] */
+ uint32_t _pad;/* [value(0)] */
+}/* [public] */;
+
+struct PAC_DATA_RAW {
+ uint32_t num_buffers;
+ uint32_t version;
+ struct PAC_BUFFER_RAW *buffers;
+}/* [public] */;
+
+struct netsamlogoncache_entry {
+ time_t timestamp;
+ struct netr_SamInfo3 info3;
+}/* [public] */;
+
+
+struct decode_pac {
+ struct {
+ struct PAC_DATA pac;
+ } in;
+
+};
+
+
+struct decode_pac_raw {
+ struct {
+ struct PAC_DATA_RAW pac;
+ } in;
+
+};
+
+
+struct decode_login_info {
+ struct {
+ struct PAC_LOGON_INFO logon_info;
+ } in;
+
+};
+
+#endif /* _HEADER_krb5pac */
diff --git a/source3/librpc/gen_ndr/libnet_join.h b/source3/librpc/gen_ndr/libnet_join.h
new file mode 100644
index 0000000000..ed49062a78
--- /dev/null
+++ b/source3/librpc/gen_ndr/libnet_join.h
@@ -0,0 +1,82 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#include "librpc/gen_ndr/wkssvc.h"
+#include "librpc/gen_ndr/security.h"
+#ifndef _HEADER_libnetjoin
+#define _HEADER_libnetjoin
+
+enum netr_SchannelType;
+
+
+struct libnet_JoinCtx {
+ struct {
+ const char * dc_name;
+ const char * machine_name;
+ const char * domain_name;/* [ref] */
+ const char * account_ou;
+ const char * admin_account;
+ const char * admin_password;
+ const char * machine_password;
+ uint32_t join_flags;
+ const char * os_version;
+ const char * os_name;
+ uint8_t create_upn;
+ const char * upn;
+ uint8_t modify_config;
+ struct ads_struct *ads;/* [ref] */
+ uint8_t debug;
+ uint8_t use_kerberos;
+ enum netr_SchannelType secure_channel_type;
+ struct messaging_context *msg_ctx;/* [noprint,ref] */
+ } in;
+
+ struct {
+ const char * account_name;
+ const char * netbios_domain_name;
+ const char * dns_domain_name;
+ const char * forest_name;
+ const char * dn;
+ struct dom_sid *domain_sid;/* [ref] */
+ uint8_t modified_config;
+ const char * error_string;
+ uint8_t domain_is_ad;
+ WERROR result;
+ } out;
+
+};
+
+
+struct libnet_UnjoinCtx {
+ struct {
+ const char * dc_name;
+ const char * machine_name;
+ const char * domain_name;
+ const char * account_ou;
+ const char * admin_account;
+ const char * admin_password;
+ const char * machine_password;
+ uint32_t unjoin_flags;
+ uint8_t modify_config;
+ struct dom_sid *domain_sid;/* [ref] */
+ struct ads_struct *ads;/* [ref] */
+ uint8_t debug;
+ uint8_t use_kerberos;
+ struct messaging_context *msg_ctx;/* [noprint,ref] */
+ } in;
+
+ struct {
+ const char * netbios_domain_name;
+ const char * dns_domain_name;
+ const char * forest_name;
+ uint8_t modified_config;
+ const char * error_string;
+ uint8_t disabled_machine_account;
+ uint8_t deleted_machine_account;
+ WERROR result;
+ } out;
+
+};
+
+#endif /* _HEADER_libnetjoin */
diff --git a/source3/librpc/gen_ndr/libnetapi.h b/source3/librpc/gen_ndr/libnetapi.h
new file mode 100644
index 0000000000..98da9e12ea
--- /dev/null
+++ b/source3/librpc/gen_ndr/libnetapi.h
@@ -0,0 +1,1457 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#define LIBNETAPI_LOCAL_SERVER(x) (!x || is_myname_or_ipaddr(x))
+#ifndef MAXSUBAUTHS
+#define MAXSUBAUTHS 15 /* max sub authorities in a SID */
+#endif
+#ifndef _HEADER_libnetapi
+#define _HEADER_libnetapi
+
+#define ERROR_MORE_DATA ( 234L )
+#define USER_PRIV_GUEST ( 0 )
+#define USER_PRIV_USER ( 1 )
+#define USER_PRIV_ADMIN ( 2 )
+#define AF_OP_PRINT ( 0x1 )
+#define AF_OP_COMM ( 0x2 )
+#define AF_OP_SERVER ( 0x4 )
+#define AF_OP_ACCOUNTS ( 0x8 )
+#define AF_SETTABLE_BITS ( (AF_OP_PRINT|AF_OP_COMM|AF_OP_SERVER|AF_OP_ACCOUNTS) )
+#define USER_MAXSTORAGE_UNLIMITED ( (uint32_t)-1L )
+#define ENCRYPTED_PWLEN ( 16 )
+#define FILTER_TEMP_DUPLICATE_ACCOUNT ( 0x0001 )
+#define FILTER_NORMAL_ACCOUNT ( 0x0002 )
+#define FILTER_INTERDOMAIN_TRUST_ACCOUNT ( 0x0008 )
+#define FILTER_WORKSTATION_TRUST_ACCOUNT ( 0x0010 )
+#define FILTER_SERVER_TRUST_ACCOUNT ( 0x0020 )
+#define LG_INCLUDE_INDIRECT ( 0x0001 )
+#define TIMEQ_FOREVER ( (uint32_t)-1L )
+#define CSC_MASK ( 0x30 )
+enum NET_API_STATUS
+#ifndef USE_UINT_ENUMS
+ {
+ NERR_Success=0
+}
+#else
+ { __donnot_use_enum_NET_API_STATUS=0x7FFFFFFF}
+#define NERR_Success ( 0 )
+#endif
+;
+
+struct domsid {
+ uint8_t sid_rev_num;
+ uint8_t num_auths;
+ uint8_t id_auth[6];
+ uint32_t *sub_auths;
+};
+
+/* bitmap NetJoinFlags */
+#define NETSETUP_JOIN_DOMAIN ( 0x00000001 )
+#define NETSETUP_ACCT_CREATE ( 0x00000002 )
+#define NETSETUP_ACCT_DELETE ( 0x00000004 )
+#define NETSETUP_WIN9X_UPGRADE ( 0x00000010 )
+#define NETSETUP_DOMAIN_JOIN_IF_JOINED ( 0x00000020 )
+#define NETSETUP_JOIN_UNSECURE ( 0x00000040 )
+#define NETSETUP_MACHINE_PWD_PASSED ( 0x00000080 )
+#define NETSETUP_DEFER_SPN_SET ( 0x00000100 )
+#define NETSETUP_JOIN_DC_ACCOUNT ( 0x00000200 )
+#define NETSETUP_JOIN_WITH_NEW_NAME ( 0x00000400 )
+#define NETSETUP_INSTALL_INVOCATION ( 0x00040000 )
+#define NETSETUP_IGNORE_UNSUPPORTED_FLAGS ( 0x10000000 )
+
+enum NETSETUP_JOIN_STATUS
+#ifndef USE_UINT_ENUMS
+ {
+ NetSetupUnknownStatus=0,
+ NetSetupUnjoined=1,
+ NetSetupWorkgroupName=2,
+ NetSetupDomainName=3
+}
+#else
+ { __donnot_use_enum_NETSETUP_JOIN_STATUS=0x7FFFFFFF}
+#define NetSetupUnknownStatus ( 0 )
+#define NetSetupUnjoined ( 1 )
+#define NetSetupWorkgroupName ( 2 )
+#define NetSetupDomainName ( 3 )
+#endif
+;
+
+struct SERVER_INFO_100 {
+ uint32_t sv100_platform_id;
+ const char * sv100_name;
+};
+
+struct SERVER_INFO_101 {
+ uint32_t sv101_platform_id;
+ const char * sv101_name;
+ uint32_t sv101_version_major;
+ uint32_t sv101_version_minor;
+ uint32_t sv101_type;
+ const char * sv101_comment;
+};
+
+struct SERVER_INFO_102 {
+ uint32_t sv102_platform_id;
+ const char * sv102_name;
+ uint32_t sv102_version_major;
+ uint32_t sv102_version_minor;
+ uint32_t sv102_type;
+ const char * sv102_comment;
+ uint32_t sv102_users;
+ uint32_t sv102_disc;
+ uint8_t sv102_hidden;
+ uint32_t sv102_announce;
+ uint32_t sv102_anndelta;
+ uint32_t sv102_licenses;
+ const char * sv102_userpath;
+};
+
+struct SERVER_INFO_1005 {
+ const char * sv1005_comment;
+};
+
+struct DOMAIN_CONTROLLER_INFO {
+ const char * domain_controller_name;
+ const char * domain_controller_address;
+ uint32_t domain_controller_address_type;
+ struct GUID domain_guid;
+ const char * domain_name;
+ const char * dns_forest_name;
+ uint32_t flags;
+ const char * dc_site_name;
+ const char * client_site_name;
+};
+
+struct USER_INFO_0 {
+ const char * usri0_name;
+};
+
+struct USER_INFO_1 {
+ const char * usri1_name;
+ const char * usri1_password;
+ uint32_t usri1_password_age;
+ uint32_t usri1_priv;
+ const char * usri1_home_dir;
+ const char * usri1_comment;
+ uint32_t usri1_flags;
+ const char * usri1_script_path;
+};
+
+struct USER_INFO_2 {
+ const char * usri2_name;
+ const char * usri2_password;
+ uint32_t usri2_password_age;
+ uint32_t usri2_priv;
+ const char * usri2_home_dir;
+ const char * usri2_comment;
+ uint32_t usri2_flags;
+ const char * usri2_script_path;
+ uint32_t usri2_auth_flags;
+ const char * usri2_full_name;
+ const char * usri2_usr_comment;
+ const char * usri2_parms;
+ const char * usri2_workstations;
+ uint32_t usri2_last_logon;
+ uint32_t usri2_last_logoff;
+ uint32_t usri2_acct_expires;
+ uint32_t usri2_max_storage;
+ uint32_t usri2_units_per_week;
+ uint8_t *usri2_logon_hours;/* [unique] */
+ uint32_t usri2_bad_pw_count;
+ uint32_t usri2_num_logons;
+ const char * usri2_logon_server;
+ uint32_t usri2_country_code;
+ uint32_t usri2_code_page;
+};
+
+struct USER_INFO_3 {
+ const char * usri3_name;
+ uint32_t usri3_password_age;
+ uint32_t usri3_priv;
+ const char * usri3_home_dir;
+ const char * usri3_comment;
+ uint32_t usri3_flags;
+ const char * usri3_script_path;
+ uint32_t usri3_auth_flags;
+ const char * usri3_full_name;
+ const char * usri3_usr_comment;
+ const char * usri3_parms;
+ const char * usri3_workstations;
+ uint32_t usri3_last_logon;
+ uint32_t usri3_last_logoff;
+ uint32_t usri3_acct_expires;
+ uint32_t usri3_max_storage;
+ uint32_t usri3_units_per_week;
+ uint8_t *usri3_logon_hours;/* [unique] */
+ uint32_t usri3_bad_pw_count;
+ uint32_t usri3_num_logons;
+ const char * usri3_logon_server;
+ uint32_t usri3_country_code;
+ uint32_t usri3_code_page;
+ uint32_t usri3_user_id;
+ uint32_t usri3_primary_group_id;
+ const char * usri3_profile;
+ const char * usri3_home_dir_drive;
+ uint32_t usri3_password_expired;
+};
+
+struct USER_INFO_4 {
+ const char * usri4_name;
+ const char * usri4_password;
+ uint32_t usri4_password_age;
+ uint32_t usri4_priv;
+ const char * usri4_home_dir;
+ const char * usri4_comment;
+ uint32_t usri4_flags;
+ const char * usri4_script_path;
+ uint32_t usri4_auth_flags;
+ const char * usri4_full_name;
+ const char * usri4_usr_comment;
+ const char * usri4_parms;
+ const char * usri4_workstations;
+ uint32_t usri4_last_logon;
+ uint32_t usri4_last_logoff;
+ uint32_t usri4_acct_expires;
+ uint32_t usri4_max_storage;
+ uint32_t usri4_units_per_week;
+ uint8_t *usri4_logon_hours;/* [unique] */
+ uint32_t usri4_bad_pw_count;
+ uint32_t usri4_num_logons;
+ const char * usri4_logon_server;
+ uint32_t usri4_country_code;
+ uint32_t usri4_code_page;
+ struct domsid *usri4_user_sid;/* [unique] */
+ uint32_t usri4_primary_group_id;
+ const char * usri4_profile;
+ const char * usri4_home_dir_drive;
+ uint32_t usri4_password_expired;
+};
+
+struct USER_INFO_10 {
+ const char * usri10_name;
+ const char * usri10_comment;
+ const char * usri10_usr_comment;
+ const char * usri10_full_name;
+};
+
+struct USER_INFO_11 {
+ const char * usri11_name;
+ const char * usri11_comment;
+ const char * usri11_usr_comment;
+ const char * usri11_full_name;
+ uint32_t usri11_priv;
+ uint32_t usri11_auth_flags;
+ uint32_t usri11_password_age;
+ const char * usri11_home_dir;
+ const char * usri11_parms;
+ uint32_t usri11_last_logon;
+ uint32_t usri11_last_logoff;
+ uint32_t usri11_bad_pw_count;
+ uint32_t usri11_num_logons;
+ const char * usri11_logon_server;
+ uint32_t usri11_country_code;
+ const char * usri11_workstations;
+ uint32_t usri11_max_storage;
+ uint32_t usri11_units_per_week;
+ uint8_t *usri11_logon_hours;/* [unique] */
+ uint32_t usri11_code_page;
+};
+
+struct USER_INFO_20 {
+ const char * usri20_name;
+ const char * usri20_full_name;
+ const char * usri20_comment;
+ uint32_t usri20_flags;
+ uint32_t usri20_user_id;
+};
+
+struct USER_INFO_21 {
+ uint8_t *usri21_password;
+};
+
+struct USER_INFO_22 {
+ const char * usri22_name;
+ uint8_t *usri22_password;
+ uint32_t usri22_password_age;
+ uint32_t usri22_priv;
+ const char * usri22_home_dir;
+ const char * usri22_comment;
+ uint32_t usri22_flags;
+ uint32_t usri22_script_path;
+ uint32_t usri22_auth_flags;
+ const char * usri22_full_name;
+ const char * usri22_usr_comment;
+ const char * usri22_parms;
+ const char * usri22_workstations;
+ uint32_t usri22_last_logon;
+ uint32_t usri22_last_logoff;
+ uint32_t usri22_acct_expires;
+ uint32_t usri22_max_storage;
+ uint32_t usri22_units_per_week;
+ uint8_t *usri22_logon_hours;/* [unique] */
+ uint32_t usri22_bad_pw_count;
+ uint32_t usri22_num_logons;
+ const char * usri22_logon_server;
+ uint32_t usri22_country_code;
+ uint32_t usri22_code_page;
+};
+
+struct USER_INFO_23 {
+ const char * usri23_name;
+ const char * usri23_full_name;
+ const char * usri23_comment;
+ uint32_t usri23_flags;
+ struct domsid *usri23_user_sid;/* [unique] */
+};
+
+struct USER_INFO_1003 {
+ const char * usri1003_password;
+};
+
+struct USER_INFO_1005 {
+ uint32_t usri1005_priv;
+};
+
+struct USER_INFO_1006 {
+ const char * usri1006_home_dir;
+};
+
+struct USER_INFO_1007 {
+ const char * usri1007_comment;
+};
+
+struct USER_INFO_1008 {
+ uint32_t usri1008_flags;
+};
+
+struct USER_INFO_1009 {
+ const char * usri1009_script_path;
+};
+
+struct USER_INFO_1010 {
+ uint32_t usri1010_auth_flags;
+};
+
+struct USER_INFO_1011 {
+ const char * usri1011_full_name;
+};
+
+struct USER_INFO_1012 {
+ const char * usri1012_usr_comment;
+};
+
+struct USER_INFO_1013 {
+ const char * usri1013_parms;
+};
+
+struct USER_INFO_1014 {
+ const char * usri1014_workstations;
+};
+
+struct USER_INFO_1017 {
+ uint32_t usri1017_acct_expires;
+};
+
+struct USER_INFO_1018 {
+ uint32_t usri1018_max_storage;
+};
+
+struct USER_INFO_1020 {
+ uint32_t usri1020_units_per_week;
+ uint8_t *usri1020_logon_hours;/* [unique] */
+};
+
+struct USER_INFO_1023 {
+ const char * usri1023_logon_server;
+};
+
+struct USER_INFO_1024 {
+ uint32_t usri1024_country_code;
+};
+
+struct USER_INFO_1025 {
+ uint32_t usri1025_code_page;
+};
+
+struct USER_INFO_1051 {
+ uint32_t usri1051_primary_group_id;
+};
+
+struct USER_INFO_1052 {
+ const char * usri1052_profile;
+};
+
+struct USER_INFO_1053 {
+ const char * usri1053_home_dir_drive;
+};
+
+struct USER_INFO_X {
+ const char * usriX_name;
+ const char * usriX_password;
+ uint32_t usriX_password_age;
+ uint32_t usriX_priv;
+ const char * usriX_home_dir;
+ const char * usriX_comment;
+ uint32_t usriX_flags;
+ const char * usriX_script_path;
+ uint32_t usriX_auth_flags;
+ const char * usriX_full_name;
+ const char * usriX_usr_comment;
+ const char * usriX_parms;
+ const char * usriX_workstations;
+ uint32_t usriX_last_logon;
+ uint32_t usriX_last_logoff;
+ uint32_t usriX_acct_expires;
+ uint32_t usriX_max_storage;
+ uint32_t usriX_units_per_week;
+ uint8_t *usriX_logon_hours;/* [unique] */
+ uint32_t usriX_bad_pw_count;
+ uint32_t usriX_num_logons;
+ const char * usriX_logon_server;
+ uint32_t usriX_country_code;
+ uint32_t usriX_code_page;
+ const char * usriX_profile;
+ const char * usriX_home_dir_drive;
+ uint32_t usriX_primary_group_id;
+};
+
+struct GROUP_USERS_INFO_0 {
+ const char * grui0_name;
+};
+
+struct GROUP_USERS_INFO_1 {
+ const char * grui1_name;
+ uint32_t grui1_attributes;
+};
+
+struct LOCALGROUP_USERS_INFO_0 {
+ const char * lgrui0_name;
+};
+
+struct USER_MODALS_INFO_0 {
+ uint32_t usrmod0_min_passwd_len;
+ uint32_t usrmod0_max_passwd_age;
+ uint32_t usrmod0_min_passwd_age;
+ uint32_t usrmod0_force_logoff;
+ uint32_t usrmod0_password_hist_len;
+};
+
+struct USER_MODALS_INFO_1 {
+ uint32_t usrmod1_role;
+ const char * usrmod1_primary;
+};
+
+struct USER_MODALS_INFO_2 {
+ const char * usrmod2_domain_name;
+ struct domsid *usrmod2_domain_id;/* [unique] */
+};
+
+struct USER_MODALS_INFO_3 {
+ uint32_t usrmod3_lockout_duration;
+ uint32_t usrmod3_lockout_observation_window;
+ uint32_t usrmod3_lockout_threshold;
+};
+
+struct USER_MODALS_INFO_1001 {
+ uint32_t usrmod1001_min_passwd_len;
+};
+
+struct USER_MODALS_INFO_1002 {
+ uint32_t usrmod1002_max_passwd_age;
+};
+
+struct USER_MODALS_INFO_1003 {
+ uint32_t usrmod1003_min_passwd_age;
+};
+
+struct USER_MODALS_INFO_1004 {
+ uint32_t usrmod1004_force_logoff;
+};
+
+struct USER_MODALS_INFO_1005 {
+ uint32_t usrmod1005_password_hist_len;
+};
+
+struct USER_MODALS_INFO_1006 {
+ uint32_t usrmod1006_role;
+};
+
+struct USER_MODALS_INFO_1007 {
+ const char * usrmod1007_primary;
+};
+
+struct NET_DISPLAY_USER {
+ const char * usri1_name;
+ const char * usri1_comment;
+ uint32_t usri1_flags;
+ const char * usri1_full_name;
+ uint32_t usri1_user_id;
+ uint32_t usri1_next_index;
+};
+
+struct NET_DISPLAY_MACHINE {
+ const char * usri2_name;
+ const char * usri2_comment;
+ uint32_t usri2_flags;
+ uint32_t usri2_user_id;
+ uint32_t usri2_next_index;
+};
+
+struct NET_DISPLAY_GROUP {
+ const char * grpi3_name;
+ const char * grpi3_comment;
+ uint32_t grpi3_group_id;
+ uint32_t grpi3_attributes;
+ uint32_t grpi3_next_index;
+};
+
+struct GROUP_INFO_0 {
+ const char * grpi0_name;
+};
+
+struct GROUP_INFO_1 {
+ const char * grpi1_name;
+ const char * grpi1_comment;
+};
+
+struct GROUP_INFO_2 {
+ const char * grpi2_name;
+ const char * grpi2_comment;
+ uint32_t grpi2_group_id;
+ uint32_t grpi2_attributes;
+};
+
+struct GROUP_INFO_3 {
+ const char * grpi3_name;
+ const char * grpi3_comment;
+ struct domsid *grpi3_group_sid;/* [unique] */
+ uint32_t grpi3_attributes;
+};
+
+struct GROUP_INFO_1002 {
+ const char * grpi1002_comment;
+};
+
+struct GROUP_INFO_1005 {
+ uint32_t grpi1005_attributes;
+};
+
+struct LOCALGROUP_INFO_0 {
+ const char * lgrpi0_name;
+};
+
+struct LOCALGROUP_INFO_1 {
+ const char * lgrpi1_name;
+ const char * lgrpi1_comment;
+};
+
+struct LOCALGROUP_INFO_1002 {
+ const char * lgrpi1002_comment;
+};
+
+enum SID_NAME_USE
+#ifndef USE_UINT_ENUMS
+ {
+ SidTypeUser=1,
+ SidTypeGroup=2,
+ SidTypeDomain=3,
+ SidTypeAlias=4,
+ SidTypeWellKnownGroup=5,
+ SidTypeDeletedAccount=6,
+ SidTypeInvalid=7,
+ SidTypeUnknown=8,
+ SidTypeComputer=9,
+ SidTypeLabel=10
+}
+#else
+ { __donnot_use_enum_SID_NAME_USE=0x7FFFFFFF}
+#define SidTypeUser ( 1 )
+#define SidTypeGroup ( 2 )
+#define SidTypeDomain ( 3 )
+#define SidTypeAlias ( 4 )
+#define SidTypeWellKnownGroup ( 5 )
+#define SidTypeDeletedAccount ( 6 )
+#define SidTypeInvalid ( 7 )
+#define SidTypeUnknown ( 8 )
+#define SidTypeComputer ( 9 )
+#define SidTypeLabel ( 10 )
+#endif
+;
+
+struct LOCALGROUP_MEMBERS_INFO_0 {
+ struct domsid *lgrmi0_sid;/* [unique] */
+};
+
+struct LOCALGROUP_MEMBERS_INFO_1 {
+ struct domsid *lgrmi1_sid;/* [unique] */
+ enum SID_NAME_USE lgrmi1_sidusage;
+ const char * lgrmi1_name;
+};
+
+struct LOCALGROUP_MEMBERS_INFO_2 {
+ struct domsid *lgrmi2_sid;/* [unique] */
+ enum SID_NAME_USE lgrmi2_sidusage;
+ const char * lgrmi2_domainandname;
+};
+
+struct LOCALGROUP_MEMBERS_INFO_3 {
+ const char * lgrmi3_domainandname;
+};
+
+struct TIME_OF_DAY_INFO {
+ uint32_t tod_elapsedt;
+ uint32_t tod_msecs;
+ uint32_t tod_hours;
+ uint32_t tod_mins;
+ uint32_t tod_secs;
+ uint32_t tod_hunds;
+ int32_t tod_timezone;
+ uint32_t tod_tinterval;
+ uint32_t tod_day;
+ uint32_t tod_month;
+ uint32_t tod_year;
+ uint32_t tod_weekday;
+};
+
+struct SHARE_INFO_0 {
+ const char * shi0_netname;
+};
+
+struct SHARE_INFO_1 {
+ const char * shi1_netname;
+ uint32_t shi1_type;
+ const char * shi1_remark;
+};
+
+struct SHARE_INFO_2 {
+ const char * shi2_netname;
+ uint32_t shi2_type;
+ const char * shi2_remark;
+ uint32_t shi2_permissions;
+ uint32_t shi2_max_uses;
+ uint32_t shi2_current_uses;
+ const char * shi2_path;
+ const char * shi2_passwd;
+};
+
+struct SHARE_INFO_501 {
+ const char * shi501_netname;
+ uint32_t shi501_type;
+ const char * shi501_remark;
+ uint32_t shi501_flags;
+};
+
+struct SHARE_INFO_1004 {
+ const char * shi1004_remark;
+};
+
+/* bitmap SHARE_INFO_1005_FLAGS */
+#define SHI1005_FLAGS_DFS ( 0x01 )
+#define SHI1005_FLAGS_DFS_ROOT ( 0x02 )
+#define CSC_CACHE_MANUAL_REINT ( 0x00 )
+#define CSC_CACHE_AUTO_REINT ( 0x10 )
+#define CSC_CACHE_VDO ( 0x20 )
+#define CSC_CACHE_NONE ( 0x30 )
+#define SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS ( 0x0100 )
+#define SHI1005_FLAGS_FORCE_SHARED_DELETE ( 0x0200 )
+#define SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING ( 0x0400 )
+#define SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM ( 0x0800 )
+
+struct SHARE_INFO_1005 {
+ uint32_t shi1005_flags;
+};
+
+struct SHARE_INFO_1006 {
+ uint32_t shi1006_max_uses;
+};
+
+struct FILE_INFO_2 {
+ uint32_t fi2_id;
+};
+
+struct FILE_INFO_3 {
+ uint32_t fi3_id;
+ uint32_t fi3_permissions;
+ uint32_t fi3_num_locks;
+ const char * fi3_pathname;
+ const char * fi3_username;
+};
+
+
+struct NetJoinDomain {
+ struct {
+ const char * server;/* [unique] */
+ const char * domain;/* [ref] */
+ const char * account_ou;/* [unique] */
+ const char * account;/* [unique] */
+ const char * password;/* [unique] */
+ uint32_t join_flags;
+ } in;
+
+ struct {
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetUnjoinDomain {
+ struct {
+ const char * server_name;/* [unique] */
+ const char * account;/* [unique] */
+ const char * password;/* [unique] */
+ uint32_t unjoin_flags;
+ } in;
+
+ struct {
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetGetJoinInformation {
+ struct {
+ const char * server_name;/* [unique] */
+ } in;
+
+ struct {
+ const char * *name_buffer;/* [ref] */
+ uint16_t *name_type;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetGetJoinableOUs {
+ struct {
+ const char * server_name;/* [unique] */
+ const char * domain;/* [ref] */
+ const char * account;/* [unique] */
+ const char * password;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *ou_count;/* [ref] */
+ const char * **ous;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetRenameMachineInDomain {
+ struct {
+ const char * server_name;
+ const char * new_machine_name;
+ const char * account;
+ const char * password;
+ uint32_t rename_options;
+ } in;
+
+ struct {
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetServerGetInfo {
+ struct {
+ const char * server_name;/* [unique] */
+ uint32_t level;
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetServerSetInfo {
+ struct {
+ const char * server_name;/* [unique] */
+ uint32_t level;
+ uint8_t *buffer;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *parm_error;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetGetDCName {
+ struct {
+ const char * server_name;/* [unique] */
+ const char * domain_name;/* [unique] */
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetGetAnyDCName {
+ struct {
+ const char * server_name;/* [unique] */
+ const char * domain_name;/* [unique] */
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct DsGetDcName {
+ struct {
+ const char * server_name;/* [unique] */
+ const char * domain_name;/* [ref] */
+ struct GUID *domain_guid;/* [unique] */
+ const char * site_name;/* [unique] */
+ uint32_t flags;
+ } in;
+
+ struct {
+ struct DOMAIN_CONTROLLER_INFO **dc_info;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetUserAdd {
+ struct {
+ const char * server_name;/* [unique] */
+ uint32_t level;
+ uint8_t *buffer;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *parm_error;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetUserDel {
+ struct {
+ const char * server_name;/* [unique] */
+ const char * user_name;/* [ref] */
+ } in;
+
+ struct {
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetUserEnum {
+ struct {
+ const char * server_name;/* [unique] */
+ uint32_t level;
+ uint32_t filter;
+ uint32_t prefmaxlen;
+ uint32_t *resume_handle;/* [ref] */
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ uint32_t *entries_read;/* [ref] */
+ uint32_t *total_entries;/* [ref] */
+ uint32_t *resume_handle;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetUserChangePassword {
+ struct {
+ const char * domain_name;
+ const char * user_name;
+ const char * old_password;
+ const char * new_password;
+ } in;
+
+ struct {
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetUserGetInfo {
+ struct {
+ const char * server_name;
+ const char * user_name;
+ uint32_t level;
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetUserSetInfo {
+ struct {
+ const char * server_name;
+ const char * user_name;
+ uint32_t level;
+ uint8_t *buffer;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *parm_err;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetUserGetGroups {
+ struct {
+ const char * server_name;
+ const char * user_name;
+ uint32_t level;
+ uint32_t prefmaxlen;
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ uint32_t *entries_read;/* [ref] */
+ uint32_t *total_entries;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetUserSetGroups {
+ struct {
+ const char * server_name;
+ const char * user_name;
+ uint32_t level;
+ uint8_t *buffer;/* [ref] */
+ uint32_t num_entries;
+ } in;
+
+ struct {
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetUserGetLocalGroups {
+ struct {
+ const char * server_name;
+ const char * user_name;
+ uint32_t level;
+ uint32_t flags;
+ uint32_t prefmaxlen;
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ uint32_t *entries_read;/* [ref] */
+ uint32_t *total_entries;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetUserModalsGet {
+ struct {
+ const char * server_name;
+ uint32_t level;
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetUserModalsSet {
+ struct {
+ const char * server_name;
+ uint32_t level;
+ uint8_t *buffer;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *parm_err;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetQueryDisplayInformation {
+ struct {
+ const char * server_name;/* [unique] */
+ uint32_t level;
+ uint32_t idx;
+ uint32_t entries_requested;
+ uint32_t prefmaxlen;
+ } in;
+
+ struct {
+ uint32_t *entries_read;/* [ref] */
+ void **buffer;/* [noprint,ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetGroupAdd {
+ struct {
+ const char * server_name;
+ uint32_t level;
+ uint8_t *buffer;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *parm_err;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetGroupDel {
+ struct {
+ const char * server_name;
+ const char * group_name;
+ } in;
+
+ struct {
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetGroupEnum {
+ struct {
+ const char * server_name;
+ uint32_t level;
+ uint32_t prefmaxlen;
+ uint32_t *resume_handle;/* [ref] */
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ uint32_t *entries_read;/* [ref] */
+ uint32_t *total_entries;/* [ref] */
+ uint32_t *resume_handle;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetGroupSetInfo {
+ struct {
+ const char * server_name;
+ const char * group_name;
+ uint32_t level;
+ uint8_t *buffer;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *parm_err;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetGroupGetInfo {
+ struct {
+ const char * server_name;
+ const char * group_name;
+ uint32_t level;
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetGroupAddUser {
+ struct {
+ const char * server_name;
+ const char * group_name;
+ const char * user_name;
+ } in;
+
+ struct {
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetGroupDelUser {
+ struct {
+ const char * server_name;
+ const char * group_name;
+ const char * user_name;
+ } in;
+
+ struct {
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetGroupGetUsers {
+ struct {
+ const char * server_name;
+ const char * group_name;
+ uint32_t level;
+ uint32_t prefmaxlen;
+ uint32_t *resume_handle;/* [ref] */
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ uint32_t *entries_read;/* [ref] */
+ uint32_t *total_entries;/* [ref] */
+ uint32_t *resume_handle;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetGroupSetUsers {
+ struct {
+ const char * server_name;
+ const char * group_name;
+ uint32_t level;
+ uint8_t *buffer;/* [ref] */
+ uint32_t num_entries;
+ } in;
+
+ struct {
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetLocalGroupAdd {
+ struct {
+ const char * server_name;
+ uint32_t level;
+ uint8_t *buffer;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *parm_err;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetLocalGroupDel {
+ struct {
+ const char * server_name;
+ const char * group_name;
+ } in;
+
+ struct {
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetLocalGroupGetInfo {
+ struct {
+ const char * server_name;
+ const char * group_name;
+ uint32_t level;
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetLocalGroupSetInfo {
+ struct {
+ const char * server_name;
+ const char * group_name;
+ uint32_t level;
+ uint8_t *buffer;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *parm_err;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetLocalGroupEnum {
+ struct {
+ const char * server_name;
+ uint32_t level;
+ uint32_t prefmaxlen;
+ uint32_t *resume_handle;/* [ref] */
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ uint32_t *entries_read;/* [ref] */
+ uint32_t *total_entries;/* [ref] */
+ uint32_t *resume_handle;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetLocalGroupAddMembers {
+ struct {
+ const char * server_name;
+ const char * group_name;
+ uint32_t level;
+ uint8_t *buffer;/* [ref] */
+ uint32_t total_entries;
+ } in;
+
+ struct {
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetLocalGroupDelMembers {
+ struct {
+ const char * server_name;
+ const char * group_name;
+ uint32_t level;
+ uint8_t *buffer;/* [ref] */
+ uint32_t total_entries;
+ } in;
+
+ struct {
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetLocalGroupGetMembers {
+ struct {
+ const char * server_name;
+ const char * local_group_name;
+ uint32_t level;
+ uint32_t prefmaxlen;
+ uint32_t *resume_handle;/* [ref] */
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ uint32_t *entries_read;/* [ref] */
+ uint32_t *total_entries;/* [ref] */
+ uint32_t *resume_handle;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetLocalGroupSetMembers {
+ struct {
+ const char * server_name;
+ const char * group_name;
+ uint32_t level;
+ uint8_t *buffer;/* [ref] */
+ uint32_t total_entries;
+ } in;
+
+ struct {
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetRemoteTOD {
+ struct {
+ const char * server_name;
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetShareAdd {
+ struct {
+ const char * server_name;
+ uint32_t level;
+ uint8_t *buffer;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *parm_err;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetShareDel {
+ struct {
+ const char * server_name;
+ const char * net_name;
+ uint32_t reserved;
+ } in;
+
+ struct {
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetShareEnum {
+ struct {
+ const char * server_name;
+ uint32_t level;
+ uint32_t prefmaxlen;
+ uint32_t *resume_handle;/* [ref] */
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ uint32_t *entries_read;/* [ref] */
+ uint32_t *total_entries;/* [ref] */
+ uint32_t *resume_handle;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetShareGetInfo {
+ struct {
+ const char * server_name;
+ const char * net_name;
+ uint32_t level;
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetShareSetInfo {
+ struct {
+ const char * server_name;
+ const char * net_name;
+ uint32_t level;
+ uint8_t *buffer;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *parm_err;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetFileClose {
+ struct {
+ const char * server_name;
+ uint32_t fileid;
+ } in;
+
+ struct {
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetFileGetInfo {
+ struct {
+ const char * server_name;
+ uint32_t fileid;
+ uint32_t level;
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+
+struct NetFileEnum {
+ struct {
+ const char * server_name;
+ const char * base_path;
+ const char * user_name;
+ uint32_t level;
+ uint32_t prefmaxlen;
+ uint32_t *resume_handle;/* [ref] */
+ } in;
+
+ struct {
+ uint8_t **buffer;/* [ref] */
+ uint32_t *entries_read;/* [ref] */
+ uint32_t *total_entries;/* [ref] */
+ uint32_t *resume_handle;/* [ref] */
+ enum NET_API_STATUS result;
+ } out;
+
+};
+
+#endif /* _HEADER_libnetapi */
diff --git a/source3/librpc/gen_ndr/lsa.h b/source3/librpc/gen_ndr/lsa.h
new file mode 100644
index 0000000000..1e3d3162b2
--- /dev/null
+++ b/source3/librpc/gen_ndr/lsa.h
@@ -0,0 +1,1647 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#include "librpc/gen_ndr/security.h"
+#ifndef _HEADER_lsarpc
+#define _HEADER_lsarpc
+
+#define LSA_ENUM_TRUST_DOMAIN_MULTIPLIER ( 60 )
+#define LSA_REF_DOMAIN_LIST_MULTIPLIER ( 32 )
+#define MAX_REF_DOMAINS ( LSA_REF_DOMAIN_LIST_MULTIPLIER )
+#define MAX_LOOKUP_SIDS ( 0x5000 )
+#define LSA_ENUM_TRUST_DOMAIN_EX_MULTIPLIER ( 82 )
+struct lsa_String {
+ uint16_t length;/* [value(2*strlen_m(string))] */
+ uint16_t size;/* [value(2*strlen_m(string))] */
+ const char *string;/* [unique,charset(UTF16),length_is(length/2),size_is(size/2)] */
+}/* [public,noejs] */;
+
+struct lsa_StringLarge {
+ uint16_t length;/* [value(2*strlen_m(string))] */
+ uint16_t size;/* [value(2*strlen_m_term(string))] */
+ const char *string;/* [unique,charset(UTF16),length_is(length/2),size_is(size/2)] */
+}/* [public] */;
+
+struct lsa_Strings {
+ uint32_t count;
+ struct lsa_String *names;/* [unique,size_is(count)] */
+}/* [public] */;
+
+struct lsa_AsciiString {
+ uint16_t length;/* [value(strlen_m(string))] */
+ uint16_t size;/* [value(strlen_m(string))] */
+ const char *string;/* [unique,charset(DOS),length_is(length),size_is(size)] */
+}/* [public] */;
+
+struct lsa_AsciiStringLarge {
+ uint16_t length;/* [value(strlen_m(string))] */
+ uint16_t size;/* [value(strlen_m_term(string))] */
+ const char *string;/* [unique,charset(DOS),length_is(length),size_is(size)] */
+}/* [public] */;
+
+struct lsa_BinaryString {
+ uint16_t length;
+ uint16_t size;
+ uint16_t *array;/* [unique,length_is(length/2),size_is(size/2)] */
+}/* [public] */;
+
+struct lsa_LUID {
+ uint32_t low;
+ uint32_t high;
+};
+
+struct lsa_PrivEntry {
+ struct lsa_StringLarge name;
+ struct lsa_LUID luid;
+};
+
+struct lsa_PrivArray {
+ uint32_t count;
+ struct lsa_PrivEntry *privs;/* [unique,size_is(count)] */
+};
+
+struct lsa_QosInfo {
+ uint32_t len;
+ uint16_t impersonation_level;
+ uint8_t context_mode;
+ uint8_t effective_only;
+};
+
+struct lsa_ObjectAttribute {
+ uint32_t len;
+ uint8_t *root_dir;/* [unique] */
+ const char *object_name;/* [unique,charset(UTF16)] */
+ uint32_t attributes;
+ struct security_descriptor *sec_desc;/* [unique] */
+ struct lsa_QosInfo *sec_qos;/* [unique] */
+};
+
+/* bitmap lsa_PolicyAccessMask */
+#define LSA_POLICY_VIEW_LOCAL_INFORMATION ( 0x00000001 )
+#define LSA_POLICY_VIEW_AUDIT_INFORMATION ( 0x00000002 )
+#define LSA_POLICY_GET_PRIVATE_INFORMATION ( 0x00000004 )
+#define LSA_POLICY_TRUST_ADMIN ( 0x00000008 )
+#define LSA_POLICY_CREATE_ACCOUNT ( 0x00000010 )
+#define LSA_POLICY_CREATE_SECRET ( 0x00000020 )
+#define LSA_POLICY_CREATE_PRIVILEGE ( 0x00000040 )
+#define LSA_POLICY_SET_DEFAULT_QUOTA_LIMITS ( 0x00000080 )
+#define LSA_POLICY_SET_AUDIT_REQUIREMENTS ( 0x00000100 )
+#define LSA_POLICY_AUDIT_LOG_ADMIN ( 0x00000200 )
+#define LSA_POLICY_SERVER_ADMIN ( 0x00000400 )
+#define LSA_POLICY_LOOKUP_NAMES ( 0x00000800 )
+
+struct lsa_AuditLogInfo {
+ uint32_t percent_full;
+ uint32_t log_size;
+ NTTIME retention_time;
+ uint8_t shutdown_in_progress;
+ NTTIME time_to_shutdown;
+ uint32_t next_audit_record;
+ uint32_t unknown;
+};
+
+enum lsa_PolicyAuditPolicy
+#ifndef USE_UINT_ENUMS
+ {
+ LSA_AUDIT_POLICY_NONE=0,
+ LSA_AUDIT_POLICY_SUCCESS=1,
+ LSA_AUDIT_POLICY_FAILURE=2,
+ LSA_AUDIT_POLICY_ALL=(LSA_AUDIT_POLICY_SUCCESS|LSA_AUDIT_POLICY_FAILURE),
+ LSA_AUDIT_POLICY_CLEAR=4
+}
+#else
+ { __donnot_use_enum_lsa_PolicyAuditPolicy=0x7FFFFFFF}
+#define LSA_AUDIT_POLICY_NONE ( 0 )
+#define LSA_AUDIT_POLICY_SUCCESS ( 1 )
+#define LSA_AUDIT_POLICY_FAILURE ( 2 )
+#define LSA_AUDIT_POLICY_ALL ( (LSA_AUDIT_POLICY_SUCCESS|LSA_AUDIT_POLICY_FAILURE) )
+#define LSA_AUDIT_POLICY_CLEAR ( 4 )
+#endif
+;
+
+enum lsa_PolicyAuditEventType
+#ifndef USE_UINT_ENUMS
+ {
+ LSA_AUDIT_CATEGORY_SYSTEM=0,
+ LSA_AUDIT_CATEGORY_LOGON=1,
+ LSA_AUDIT_CATEGORY_FILE_AND_OBJECT_ACCESS=2,
+ LSA_AUDIT_CATEGORY_USE_OF_USER_RIGHTS=3,
+ LSA_AUDIT_CATEGORY_PROCCESS_TRACKING=4,
+ LSA_AUDIT_CATEGORY_SECURITY_POLICY_CHANGES=5,
+ LSA_AUDIT_CATEGORY_ACCOUNT_MANAGEMENT=6,
+ LSA_AUDIT_CATEGORY_DIRECTORY_SERVICE_ACCESS=7,
+ LSA_AUDIT_CATEGORY_ACCOUNT_LOGON=8
+}
+#else
+ { __donnot_use_enum_lsa_PolicyAuditEventType=0x7FFFFFFF}
+#define LSA_AUDIT_CATEGORY_SYSTEM ( 0 )
+#define LSA_AUDIT_CATEGORY_LOGON ( 1 )
+#define LSA_AUDIT_CATEGORY_FILE_AND_OBJECT_ACCESS ( 2 )
+#define LSA_AUDIT_CATEGORY_USE_OF_USER_RIGHTS ( 3 )
+#define LSA_AUDIT_CATEGORY_PROCCESS_TRACKING ( 4 )
+#define LSA_AUDIT_CATEGORY_SECURITY_POLICY_CHANGES ( 5 )
+#define LSA_AUDIT_CATEGORY_ACCOUNT_MANAGEMENT ( 6 )
+#define LSA_AUDIT_CATEGORY_DIRECTORY_SERVICE_ACCESS ( 7 )
+#define LSA_AUDIT_CATEGORY_ACCOUNT_LOGON ( 8 )
+#endif
+;
+
+struct lsa_AuditEventsInfo {
+ uint32_t auditing_mode;
+ enum lsa_PolicyAuditPolicy *settings;/* [unique,size_is(count)] */
+ uint32_t count;
+};
+
+struct lsa_DomainInfo {
+ struct lsa_StringLarge name;
+ struct dom_sid2 *sid;/* [unique] */
+};
+
+struct lsa_PDAccountInfo {
+ struct lsa_String name;
+};
+
+struct lsa_ServerRole {
+ uint16_t unknown;
+ uint16_t role;
+};
+
+struct lsa_ReplicaSourceInfo {
+ struct lsa_String source;
+ struct lsa_String account;
+};
+
+struct lsa_DefaultQuotaInfo {
+ uint32_t paged_pool;
+ uint32_t non_paged_pool;
+ uint32_t min_wss;
+ uint32_t max_wss;
+ uint32_t pagefile;
+ uint64_t unknown;
+};
+
+struct lsa_ModificationInfo {
+ uint64_t modified_id;
+ NTTIME db_create_time;
+};
+
+struct lsa_AuditFullSetInfo {
+ uint8_t shutdown_on_full;
+};
+
+struct lsa_AuditFullQueryInfo {
+ uint16_t unknown;
+ uint8_t shutdown_on_full;
+ uint8_t log_is_full;
+};
+
+struct lsa_DnsDomainInfo {
+ struct lsa_StringLarge name;
+ struct lsa_StringLarge dns_domain;
+ struct lsa_StringLarge dns_forest;
+ struct GUID domain_guid;
+ struct dom_sid2 *sid;/* [unique] */
+};
+
+enum lsa_PolicyInfo
+#ifndef USE_UINT_ENUMS
+ {
+ LSA_POLICY_INFO_AUDIT_LOG=1,
+ LSA_POLICY_INFO_AUDIT_EVENTS=2,
+ LSA_POLICY_INFO_DOMAIN=3,
+ LSA_POLICY_INFO_PD=4,
+ LSA_POLICY_INFO_ACCOUNT_DOMAIN=5,
+ LSA_POLICY_INFO_ROLE=6,
+ LSA_POLICY_INFO_REPLICA=7,
+ LSA_POLICY_INFO_QUOTA=8,
+ LSA_POLICY_INFO_DB=9,
+ LSA_POLICY_INFO_AUDIT_FULL_SET=10,
+ LSA_POLICY_INFO_AUDIT_FULL_QUERY=11,
+ LSA_POLICY_INFO_DNS=12
+}
+#else
+ { __donnot_use_enum_lsa_PolicyInfo=0x7FFFFFFF}
+#define LSA_POLICY_INFO_AUDIT_LOG ( 1 )
+#define LSA_POLICY_INFO_AUDIT_EVENTS ( 2 )
+#define LSA_POLICY_INFO_DOMAIN ( 3 )
+#define LSA_POLICY_INFO_PD ( 4 )
+#define LSA_POLICY_INFO_ACCOUNT_DOMAIN ( 5 )
+#define LSA_POLICY_INFO_ROLE ( 6 )
+#define LSA_POLICY_INFO_REPLICA ( 7 )
+#define LSA_POLICY_INFO_QUOTA ( 8 )
+#define LSA_POLICY_INFO_DB ( 9 )
+#define LSA_POLICY_INFO_AUDIT_FULL_SET ( 10 )
+#define LSA_POLICY_INFO_AUDIT_FULL_QUERY ( 11 )
+#define LSA_POLICY_INFO_DNS ( 12 )
+#endif
+;
+
+union lsa_PolicyInformation {
+ struct lsa_AuditLogInfo audit_log;/* [case(LSA_POLICY_INFO_AUDIT_LOG)] */
+ struct lsa_AuditEventsInfo audit_events;/* [case(LSA_POLICY_INFO_AUDIT_EVENTS)] */
+ struct lsa_DomainInfo domain;/* [case(LSA_POLICY_INFO_DOMAIN)] */
+ struct lsa_PDAccountInfo pd;/* [case(LSA_POLICY_INFO_PD)] */
+ struct lsa_DomainInfo account_domain;/* [case(LSA_POLICY_INFO_ACCOUNT_DOMAIN)] */
+ struct lsa_ServerRole role;/* [case(LSA_POLICY_INFO_ROLE)] */
+ struct lsa_ReplicaSourceInfo replica;/* [case(LSA_POLICY_INFO_REPLICA)] */
+ struct lsa_DefaultQuotaInfo quota;/* [case(LSA_POLICY_INFO_QUOTA)] */
+ struct lsa_ModificationInfo db;/* [case(LSA_POLICY_INFO_DB)] */
+ struct lsa_AuditFullSetInfo auditfullset;/* [case(LSA_POLICY_INFO_AUDIT_FULL_SET)] */
+ struct lsa_AuditFullQueryInfo auditfullquery;/* [case(LSA_POLICY_INFO_AUDIT_FULL_QUERY)] */
+ struct lsa_DnsDomainInfo dns;/* [case(LSA_POLICY_INFO_DNS)] */
+}/* [switch_type(uint16)] */;
+
+struct lsa_SidPtr {
+ struct dom_sid2 *sid;/* [unique] */
+};
+
+struct lsa_SidArray {
+ uint32_t num_sids;/* [range(0,1000)] */
+ struct lsa_SidPtr *sids;/* [unique,size_is(num_sids)] */
+}/* [public] */;
+
+struct lsa_DomainList {
+ uint32_t count;
+ struct lsa_DomainInfo *domains;/* [unique,size_is(count)] */
+};
+
+enum lsa_SidType
+#ifndef USE_UINT_ENUMS
+ {
+ SID_NAME_USE_NONE=0,
+ SID_NAME_USER=1,
+ SID_NAME_DOM_GRP=2,
+ SID_NAME_DOMAIN=3,
+ SID_NAME_ALIAS=4,
+ SID_NAME_WKN_GRP=5,
+ SID_NAME_DELETED=6,
+ SID_NAME_INVALID=7,
+ SID_NAME_UNKNOWN=8,
+ SID_NAME_COMPUTER=9
+}
+#else
+ { __donnot_use_enum_lsa_SidType=0x7FFFFFFF}
+#define SID_NAME_USE_NONE ( 0 )
+#define SID_NAME_USER ( 1 )
+#define SID_NAME_DOM_GRP ( 2 )
+#define SID_NAME_DOMAIN ( 3 )
+#define SID_NAME_ALIAS ( 4 )
+#define SID_NAME_WKN_GRP ( 5 )
+#define SID_NAME_DELETED ( 6 )
+#define SID_NAME_INVALID ( 7 )
+#define SID_NAME_UNKNOWN ( 8 )
+#define SID_NAME_COMPUTER ( 9 )
+#endif
+;
+
+struct lsa_TranslatedSid {
+ enum lsa_SidType sid_type;
+ uint32_t rid;
+ uint32_t sid_index;
+};
+
+struct lsa_TransSidArray {
+ uint32_t count;/* [range(0,1000)] */
+ struct lsa_TranslatedSid *sids;/* [unique,size_is(count)] */
+};
+
+struct lsa_RefDomainList {
+ uint32_t count;/* [range(0,1000)] */
+ struct lsa_DomainInfo *domains;/* [unique,size_is(count)] */
+ uint32_t max_size;
+};
+
+enum lsa_LookupNamesLevel
+#ifndef USE_UINT_ENUMS
+ {
+ LSA_LOOKUP_NAMES_ALL=1,
+ LSA_LOOKUP_NAMES_DOMAINS_ONLY=2,
+ LSA_LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY=3,
+ LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY=4,
+ LSA_LOOKUP_NAMES_FOREST_TRUSTS_ONLY=5,
+ LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2=6
+}
+#else
+ { __donnot_use_enum_lsa_LookupNamesLevel=0x7FFFFFFF}
+#define LSA_LOOKUP_NAMES_ALL ( 1 )
+#define LSA_LOOKUP_NAMES_DOMAINS_ONLY ( 2 )
+#define LSA_LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY ( 3 )
+#define LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY ( 4 )
+#define LSA_LOOKUP_NAMES_FOREST_TRUSTS_ONLY ( 5 )
+#define LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2 ( 6 )
+#endif
+;
+
+struct lsa_TranslatedName {
+ enum lsa_SidType sid_type;
+ struct lsa_String name;
+ uint32_t sid_index;
+};
+
+struct lsa_TransNameArray {
+ uint32_t count;/* [range(0,1000)] */
+ struct lsa_TranslatedName *names;/* [unique,size_is(count)] */
+};
+
+struct lsa_LUIDAttribute {
+ struct lsa_LUID luid;
+ uint32_t attribute;
+};
+
+struct lsa_PrivilegeSet {
+ uint32_t count;/* [range(0,1000)] */
+ uint32_t unknown;
+ struct lsa_LUIDAttribute *set;/* [size_is(count)] */
+};
+
+struct lsa_DATA_BUF {
+ uint32_t length;
+ uint32_t size;
+ uint8_t *data;/* [unique,length_is(length),size_is(size)] */
+}/* [flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+struct lsa_DATA_BUF2 {
+ uint32_t size;/* [range(0,65536)] */
+ uint8_t *data;/* [unique,size_is(size)] */
+}/* [flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+enum lsa_TrustDomInfoEnum
+#ifndef USE_UINT_ENUMS
+ {
+ LSA_TRUSTED_DOMAIN_INFO_NAME=1,
+ LSA_TRUSTED_DOMAIN_INFO_CONTROLLERS_INFO=2,
+ LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET=3,
+ LSA_TRUSTED_DOMAIN_INFO_PASSWORD=4,
+ LSA_TRUSTED_DOMAIN_INFO_BASIC=5,
+ LSA_TRUSTED_DOMAIN_INFO_INFO_EX=6,
+ LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO=7,
+ LSA_TRUSTED_DOMAIN_INFO_FULL_INFO=8,
+ LSA_TRUSTED_DOMAIN_INFO_11=11,
+ LSA_TRUSTED_DOMAIN_INFO_INFO_ALL=12
+}
+#else
+ { __donnot_use_enum_lsa_TrustDomInfoEnum=0x7FFFFFFF}
+#define LSA_TRUSTED_DOMAIN_INFO_NAME ( 1 )
+#define LSA_TRUSTED_DOMAIN_INFO_CONTROLLERS_INFO ( 2 )
+#define LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET ( 3 )
+#define LSA_TRUSTED_DOMAIN_INFO_PASSWORD ( 4 )
+#define LSA_TRUSTED_DOMAIN_INFO_BASIC ( 5 )
+#define LSA_TRUSTED_DOMAIN_INFO_INFO_EX ( 6 )
+#define LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO ( 7 )
+#define LSA_TRUSTED_DOMAIN_INFO_FULL_INFO ( 8 )
+#define LSA_TRUSTED_DOMAIN_INFO_11 ( 11 )
+#define LSA_TRUSTED_DOMAIN_INFO_INFO_ALL ( 12 )
+#endif
+;
+
+struct lsa_TrustDomainInfoName {
+ struct lsa_StringLarge netbios_name;
+};
+
+struct lsa_TrustDomainInfoPosixOffset {
+ uint32_t posix_offset;
+};
+
+struct lsa_TrustDomainInfoPassword {
+ struct lsa_DATA_BUF *password;/* [unique] */
+ struct lsa_DATA_BUF *old_password;/* [unique] */
+};
+
+struct lsa_TrustDomainInfoBasic {
+ struct lsa_String netbios_name;
+ struct dom_sid2 *sid;/* [unique] */
+};
+
+struct lsa_TrustDomainInfoInfoEx {
+ struct lsa_StringLarge domain_name;
+ struct lsa_StringLarge netbios_name;
+ struct dom_sid2 *sid;/* [unique] */
+ uint32_t trust_direction;
+ uint32_t trust_type;
+ uint32_t trust_attributes;
+};
+
+struct lsa_TrustDomainInfoBuffer {
+ NTTIME last_update_time;
+ uint32_t secret_type;
+ struct lsa_DATA_BUF2 data;
+};
+
+struct lsa_TrustDomainInfoAuthInfo {
+ uint32_t incoming_count;
+ struct lsa_TrustDomainInfoBuffer *incoming_current_auth_info;/* [unique] */
+ struct lsa_TrustDomainInfoBuffer *incoming_previous_auth_info;/* [unique] */
+ uint32_t outgoing_count;
+ struct lsa_TrustDomainInfoBuffer *outgoing_current_auth_info;/* [unique] */
+ struct lsa_TrustDomainInfoBuffer *outgoing_previous_auth_info;/* [unique] */
+};
+
+struct lsa_TrustDomainInfoFullInfo {
+ struct lsa_TrustDomainInfoInfoEx info_ex;
+ struct lsa_TrustDomainInfoPosixOffset posix_offset;
+ struct lsa_TrustDomainInfoAuthInfo auth_info;
+};
+
+struct lsa_TrustDomainInfo11 {
+ struct lsa_TrustDomainInfoInfoEx info_ex;
+ struct lsa_DATA_BUF2 data1;
+};
+
+struct lsa_TrustDomainInfoInfoAll {
+ struct lsa_TrustDomainInfoInfoEx info_ex;
+ struct lsa_DATA_BUF2 data1;
+ struct lsa_TrustDomainInfoPosixOffset posix_offset;
+ struct lsa_TrustDomainInfoAuthInfo auth_info;
+};
+
+union lsa_TrustedDomainInfo {
+ struct lsa_TrustDomainInfoName name;/* [case(LSA_TRUSTED_DOMAIN_INFO_NAME)] */
+ struct lsa_TrustDomainInfoPosixOffset posix_offset;/* [case(LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET)] */
+ struct lsa_TrustDomainInfoPassword password;/* [case(LSA_TRUSTED_DOMAIN_INFO_PASSWORD)] */
+ struct lsa_TrustDomainInfoBasic info_basic;/* [case(LSA_TRUSTED_DOMAIN_INFO_BASIC)] */
+ struct lsa_TrustDomainInfoInfoEx info_ex;/* [case(LSA_TRUSTED_DOMAIN_INFO_INFO_EX)] */
+ struct lsa_TrustDomainInfoAuthInfo auth_info;/* [case(LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO)] */
+ struct lsa_TrustDomainInfoFullInfo full_info;/* [case(LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)] */
+ struct lsa_TrustDomainInfo11 info11;/* [case(LSA_TRUSTED_DOMAIN_INFO_11)] */
+ struct lsa_TrustDomainInfoInfoAll info_all;/* [case(LSA_TRUSTED_DOMAIN_INFO_INFO_ALL)] */
+}/* [switch_type(lsa_TrustDomInfoEnum)] */;
+
+struct lsa_DATA_BUF_PTR {
+ struct lsa_DATA_BUF *buf;/* [unique] */
+};
+
+struct lsa_RightAttribute {
+ const char *name;/* [unique,charset(UTF16)] */
+};
+
+struct lsa_RightSet {
+ uint32_t count;/* [range(0,256)] */
+ struct lsa_StringLarge *names;/* [unique,size_is(count)] */
+};
+
+struct lsa_DomainListEx {
+ uint32_t count;
+ struct lsa_TrustDomainInfoInfoEx *domains;/* [unique,size_is(count)] */
+};
+
+struct lsa_DomainInfoKerberos {
+ uint32_t enforce_restrictions;
+ uint64_t service_tkt_lifetime;
+ uint64_t user_tkt_lifetime;
+ uint64_t user_tkt_renewaltime;
+ uint64_t clock_skew;
+ uint64_t unknown6;
+};
+
+struct lsa_DomainInfoEfs {
+ uint32_t blob_size;
+ uint8_t *efs_blob;/* [unique,size_is(blob_size)] */
+};
+
+enum lsa_DomainInfoEnum
+#ifndef USE_UINT_ENUMS
+ {
+ LSA_DOMAIN_INFO_POLICY_EFS=2,
+ LSA_DOMAIN_INFO_POLICY_KERBEROS=3
+}
+#else
+ { __donnot_use_enum_lsa_DomainInfoEnum=0x7FFFFFFF}
+#define LSA_DOMAIN_INFO_POLICY_EFS ( 2 )
+#define LSA_DOMAIN_INFO_POLICY_KERBEROS ( 3 )
+#endif
+;
+
+union lsa_DomainInformationPolicy {
+ struct lsa_DomainInfoEfs efs_info;/* [case(LSA_DOMAIN_INFO_POLICY_EFS)] */
+ struct lsa_DomainInfoKerberos kerberos_info;/* [case(LSA_DOMAIN_INFO_POLICY_KERBEROS)] */
+}/* [switch_type(uint16)] */;
+
+struct lsa_TranslatedName2 {
+ enum lsa_SidType sid_type;
+ struct lsa_String name;
+ uint32_t sid_index;
+ uint32_t unknown;
+};
+
+struct lsa_TransNameArray2 {
+ uint32_t count;/* [range(0,1000)] */
+ struct lsa_TranslatedName2 *names;/* [unique,size_is(count)] */
+};
+
+struct lsa_TranslatedSid2 {
+ enum lsa_SidType sid_type;
+ uint32_t rid;
+ uint32_t sid_index;
+ uint32_t unknown;
+};
+
+struct lsa_TransSidArray2 {
+ uint32_t count;/* [range(0,1000)] */
+ struct lsa_TranslatedSid2 *sids;/* [unique,size_is(count)] */
+};
+
+struct lsa_TranslatedSid3 {
+ enum lsa_SidType sid_type;
+ struct dom_sid2 *sid;/* [unique] */
+ uint32_t sid_index;
+ uint32_t unknown;
+};
+
+struct lsa_TransSidArray3 {
+ uint32_t count;/* [range(0,1000)] */
+ struct lsa_TranslatedSid3 *sids;/* [unique,size_is(count)] */
+};
+
+struct lsa_ForestTrustBinaryData {
+ uint32_t length;/* [range(0,131072)] */
+ uint8_t *data;/* [unique,size_is(length)] */
+};
+
+struct lsa_ForestTrustDomainInfo {
+ struct dom_sid2 *domain_sid;/* [unique] */
+ struct lsa_StringLarge dns_domain_name;
+ struct lsa_StringLarge netbios_domain_name;
+};
+
+union lsa_ForestTrustData {
+ struct lsa_String top_level_name;/* [case(LSA_FOREST_TRUST_TOP_LEVEL_NAME)] */
+ struct lsa_StringLarge top_level_name_ex;/* [case(LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX)] */
+ struct lsa_ForestTrustDomainInfo domain_info;/* [case(LSA_FOREST_TRUST_DOMAIN_INFO)] */
+ struct lsa_ForestTrustBinaryData data;/* [default] */
+}/* [switch_type(uint32)] */;
+
+enum lsa_ForestTrustRecordType
+#ifndef USE_UINT_ENUMS
+ {
+ LSA_FOREST_TRUST_TOP_LEVEL_NAME=0,
+ LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX=1,
+ LSA_FOREST_TRUST_DOMAIN_INFO=2,
+ LSA_FOREST_TRUST_RECORD_TYPE_LAST=3
+}
+#else
+ { __donnot_use_enum_lsa_ForestTrustRecordType=0x7FFFFFFF}
+#define LSA_FOREST_TRUST_TOP_LEVEL_NAME ( 0 )
+#define LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX ( 1 )
+#define LSA_FOREST_TRUST_DOMAIN_INFO ( 2 )
+#define LSA_FOREST_TRUST_RECORD_TYPE_LAST ( 3 )
+#endif
+;
+
+struct lsa_ForestTrustRecord {
+ uint32_t flags;
+ enum lsa_ForestTrustRecordType level;
+ uint64_t unknown;
+ union lsa_ForestTrustData forest_trust_data;/* [switch_is(level)] */
+};
+
+struct lsa_ForestTrustInformation {
+ uint32_t count;/* [range(0,4000)] */
+ struct lsa_ForestTrustRecord **entries;/* [unique,size_is(count)] */
+}/* [public] */;
+
+
+struct lsa_Close {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_Delete {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_EnumPrivs {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t max_count;
+ uint32_t *resume_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct lsa_PrivArray *privs;/* [ref] */
+ uint32_t *resume_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_QuerySecurity {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t sec_info;
+ } in;
+
+ struct {
+ struct sec_desc_buf **sdbuf;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_SetSecObj {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t sec_info;
+ struct sec_desc_buf *sdbuf;/* [ref] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_ChangePassword {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_OpenPolicy {
+ struct {
+ uint16_t *system_name;/* [unique] */
+ struct lsa_ObjectAttribute *attr;/* [ref] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_QueryInfoPolicy {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ enum lsa_PolicyInfo level;
+ } in;
+
+ struct {
+ union lsa_PolicyInformation **info;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_SetInfoPolicy {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ enum lsa_PolicyInfo level;
+ union lsa_PolicyInformation *info;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_ClearAuditLog {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_CreateAccount {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct dom_sid2 *sid;/* [ref] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *acct_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_EnumAccounts {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t num_entries;/* [range(0,8192)] */
+ uint32_t *resume_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct lsa_SidArray *sids;/* [ref] */
+ uint32_t *resume_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_CreateTrustedDomain {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct lsa_DomainInfo *info;/* [ref] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *trustdom_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_EnumTrustDom {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t max_size;
+ uint32_t *resume_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct lsa_DomainList *domains;/* [ref] */
+ uint32_t *resume_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LookupNames {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t num_names;/* [range(0,1000)] */
+ struct lsa_String *names;/* [size_is(num_names)] */
+ enum lsa_LookupNamesLevel level;
+ struct lsa_TransSidArray *sids;/* [ref] */
+ uint32_t *count;/* [ref] */
+ } in;
+
+ struct {
+ struct lsa_RefDomainList **domains;/* [ref] */
+ struct lsa_TransSidArray *sids;/* [ref] */
+ uint32_t *count;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LookupSids {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct lsa_SidArray *sids;/* [ref] */
+ uint16_t level;
+ struct lsa_TransNameArray *names;/* [ref] */
+ uint32_t *count;/* [ref] */
+ } in;
+
+ struct {
+ struct lsa_RefDomainList **domains;/* [ref] */
+ struct lsa_TransNameArray *names;/* [ref] */
+ uint32_t *count;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_CreateSecret {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct lsa_String name;
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *sec_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_OpenAccount {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct dom_sid2 *sid;/* [ref] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *acct_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_EnumPrivsAccount {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ struct lsa_PrivilegeSet **privs;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_AddPrivilegesToAccount {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct lsa_PrivilegeSet *privs;/* [ref] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_RemovePrivilegesFromAccount {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint8_t remove_all;
+ struct lsa_PrivilegeSet *privs;/* [unique] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_GetQuotasForAccount {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_SetQuotasForAccount {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_GetSystemAccessAccount {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *access_mask;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_SetSystemAccessAccount {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_OpenTrustedDomain {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct dom_sid2 *sid;/* [ref] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *trustdom_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_QueryTrustedDomainInfo {
+ struct {
+ struct policy_handle *trustdom_handle;/* [ref] */
+ enum lsa_TrustDomInfoEnum level;
+ } in;
+
+ struct {
+ union lsa_TrustedDomainInfo **info;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_SetInformationTrustedDomain {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_OpenSecret {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct lsa_String name;
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *sec_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_SetSecret {
+ struct {
+ struct policy_handle *sec_handle;/* [ref] */
+ struct lsa_DATA_BUF *new_val;/* [unique] */
+ struct lsa_DATA_BUF *old_val;/* [unique] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_QuerySecret {
+ struct {
+ struct policy_handle *sec_handle;/* [ref] */
+ struct lsa_DATA_BUF_PTR *new_val;/* [unique] */
+ NTTIME *new_mtime;/* [unique] */
+ struct lsa_DATA_BUF_PTR *old_val;/* [unique] */
+ NTTIME *old_mtime;/* [unique] */
+ } in;
+
+ struct {
+ struct lsa_DATA_BUF_PTR *new_val;/* [unique] */
+ NTTIME *new_mtime;/* [unique] */
+ struct lsa_DATA_BUF_PTR *old_val;/* [unique] */
+ NTTIME *old_mtime;/* [unique] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LookupPrivValue {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct lsa_String *name;/* [ref] */
+ } in;
+
+ struct {
+ struct lsa_LUID *luid;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LookupPrivName {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct lsa_LUID *luid;/* [ref] */
+ } in;
+
+ struct {
+ struct lsa_StringLarge **name;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LookupPrivDisplayName {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct lsa_String *name;/* [ref] */
+ uint16_t language_id;
+ uint16_t language_id_sys;
+ } in;
+
+ struct {
+ struct lsa_StringLarge **disp_name;/* [ref] */
+ uint16_t *returned_language_id;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_DeleteObject {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_EnumAccountsWithUserRight {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct lsa_String *name;/* [unique] */
+ } in;
+
+ struct {
+ struct lsa_SidArray *sids;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_EnumAccountRights {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct dom_sid2 *sid;/* [ref] */
+ } in;
+
+ struct {
+ struct lsa_RightSet *rights;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_AddAccountRights {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct dom_sid2 *sid;/* [ref] */
+ struct lsa_RightSet *rights;/* [ref] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_RemoveAccountRights {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct dom_sid2 *sid;/* [ref] */
+ uint8_t remove_all;
+ struct lsa_RightSet *rights;/* [ref] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_QueryTrustedDomainInfoBySid {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct dom_sid2 *dom_sid;/* [ref] */
+ enum lsa_TrustDomInfoEnum level;
+ } in;
+
+ struct {
+ union lsa_TrustedDomainInfo **info;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_SetTrustedDomainInfo {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_DeleteTrustedDomain {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct dom_sid2 *dom_sid;/* [ref] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_StorePrivateData {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_RetrievePrivateData {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_OpenPolicy2 {
+ struct {
+ const char *system_name;/* [unique,charset(UTF16)] */
+ struct lsa_ObjectAttribute *attr;/* [ref] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_GetUserName {
+ struct {
+ const char *system_name;/* [unique,charset(UTF16)] */
+ struct lsa_String **account_name;/* [ref] */
+ struct lsa_String **authority_name;/* [unique] */
+ } in;
+
+ struct {
+ struct lsa_String **account_name;/* [ref] */
+ struct lsa_String **authority_name;/* [unique] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_QueryInfoPolicy2 {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ enum lsa_PolicyInfo level;
+ } in;
+
+ struct {
+ union lsa_PolicyInformation **info;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_SetInfoPolicy2 {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ enum lsa_PolicyInfo level;
+ union lsa_PolicyInformation *info;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_QueryTrustedDomainInfoByName {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct lsa_String *trusted_domain;/* [ref] */
+ enum lsa_TrustDomInfoEnum level;
+ } in;
+
+ struct {
+ union lsa_TrustedDomainInfo **info;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_SetTrustedDomainInfoByName {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct lsa_String trusted_domain;
+ enum lsa_TrustDomInfoEnum level;
+ union lsa_TrustedDomainInfo *info;/* [unique,switch_is(level)] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_EnumTrustedDomainsEx {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t max_size;
+ uint32_t *resume_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct lsa_DomainListEx *domains;/* [ref] */
+ uint32_t *resume_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_CreateTrustedDomainEx {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_CloseTrustedDomainEx {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_QueryDomainInformationPolicy {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint16_t level;
+ } in;
+
+ struct {
+ union lsa_DomainInformationPolicy **info;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_SetDomainInformationPolicy {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint16_t level;
+ union lsa_DomainInformationPolicy *info;/* [unique,switch_is(level)] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_OpenTrustedDomainByName {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct lsa_String name;
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *trustdom_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_TestCall {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LookupSids2 {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct lsa_SidArray *sids;/* [ref] */
+ uint16_t level;
+ uint32_t unknown1;
+ uint32_t unknown2;
+ struct lsa_TransNameArray2 *names;/* [ref] */
+ uint32_t *count;/* [ref] */
+ } in;
+
+ struct {
+ struct lsa_RefDomainList **domains;/* [ref] */
+ struct lsa_TransNameArray2 *names;/* [ref] */
+ uint32_t *count;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LookupNames2 {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t num_names;/* [range(0,1000)] */
+ struct lsa_String *names;/* [size_is(num_names)] */
+ enum lsa_LookupNamesLevel level;
+ uint32_t unknown1;
+ uint32_t unknown2;
+ struct lsa_TransSidArray2 *sids;/* [ref] */
+ uint32_t *count;/* [ref] */
+ } in;
+
+ struct {
+ struct lsa_RefDomainList **domains;/* [ref] */
+ struct lsa_TransSidArray2 *sids;/* [ref] */
+ uint32_t *count;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_CreateTrustedDomainEx2 {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_CREDRWRITE {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_CREDRREAD {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_CREDRENUMERATE {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_CREDRWRITEDOMAINCREDENTIALS {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_CREDRREADDOMAINCREDENTIALS {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_CREDRDELETE {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_CREDRGETTARGETINFO {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_CREDRPROFILELOADED {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LookupNames3 {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t num_names;/* [range(0,1000)] */
+ struct lsa_String *names;/* [size_is(num_names)] */
+ enum lsa_LookupNamesLevel level;
+ uint32_t unknown1;
+ uint32_t unknown2;
+ struct lsa_TransSidArray3 *sids;/* [ref] */
+ uint32_t *count;/* [ref] */
+ } in;
+
+ struct {
+ struct lsa_RefDomainList **domains;/* [ref] */
+ struct lsa_TransSidArray3 *sids;/* [ref] */
+ uint32_t *count;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_CREDRGETSESSIONTYPES {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LSARREGISTERAUDITEVENT {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LSARGENAUDITEVENT {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LSARUNREGISTERAUDITEVENT {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_lsaRQueryForestTrustInformation {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct lsa_String *trusted_domain_name;/* [ref] */
+ uint16_t unknown;
+ } in;
+
+ struct {
+ struct lsa_ForestTrustInformation **forest_trust_info;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LSARSETFORESTTRUSTINFORMATION {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_CREDRRENAME {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LookupSids3 {
+ struct {
+ struct lsa_SidArray *sids;/* [ref] */
+ uint16_t level;
+ uint32_t unknown1;
+ uint32_t unknown2;
+ struct lsa_TransNameArray2 *names;/* [ref] */
+ uint32_t *count;/* [ref] */
+ } in;
+
+ struct {
+ struct lsa_RefDomainList **domains;/* [ref] */
+ struct lsa_TransNameArray2 *names;/* [ref] */
+ uint32_t *count;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LookupNames4 {
+ struct {
+ uint32_t num_names;/* [range(0,1000)] */
+ struct lsa_String *names;/* [size_is(num_names)] */
+ enum lsa_LookupNamesLevel level;
+ uint32_t unknown1;
+ uint32_t unknown2;
+ struct lsa_TransSidArray3 *sids;/* [ref] */
+ uint32_t *count;/* [ref] */
+ } in;
+
+ struct {
+ struct lsa_RefDomainList **domains;/* [ref] */
+ struct lsa_TransSidArray3 *sids;/* [ref] */
+ uint32_t *count;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LSAROPENPOLICYSCE {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct lsa_LSARADTREPORTSECURITYEVENT {
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+#endif /* _HEADER_lsarpc */
diff --git a/source3/librpc/gen_ndr/messaging.h b/source3/librpc/gen_ndr/messaging.h
new file mode 100644
index 0000000000..3324160938
--- /dev/null
+++ b/source3/librpc/gen_ndr/messaging.h
@@ -0,0 +1,146 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#ifndef _HEADER_messaging
+#define _HEADER_messaging
+
+#define MSG_TYPE_MASK ( 0xFFFF )
+enum messaging_type
+#ifndef USE_UINT_ENUMS
+ {
+ MSG_DEBUG=0x0001,
+ MSG_PING=0x0002,
+ MSG_PONG=0x0003,
+ MSG_PROFILE=0x0004,
+ MSG_REQ_DEBUGLEVEL=0x0005,
+ MSG_DEBUGLEVEL=0x0006,
+ MSG_REQ_PROFILELEVEL=0x0007,
+ MSG_PROFILELEVEL=0x0008,
+ MSG_REQ_POOL_USAGE=0x0009,
+ MSG_POOL_USAGE=0x000A,
+ MSG_REQ_DMALLOC_MARK=0x000B,
+ MSG_REQ_DMALLOC_LOG_CHANGED=0x000C,
+ MSG_SHUTDOWN=0x000D,
+ MSG_FORCE_ELECTION=0x0101,
+ MSG_WINS_NEW_ENTRY=0x0102,
+ MSG_SEND_PACKET=0x0103,
+ MSG_PRINTER_NOTIFY=0x2001,
+ MSG_PRINTER_NOTIFY2=0x0202,
+ MSG_PRINTER_DRVUPGRADE=0x0203,
+ MSG_PRINTERDATA_INIT_RESET=0x0204,
+ MSG_PRINTER_UPDATE=0x0205,
+ MSG_PRINTER_MOD=0x0206,
+ MSG_SMB_CONF_UPDATED=0x0301,
+ MSG_SMB_FORCE_TDIS=0x0302,
+ MSG_SMB_SAM_SYNC=0x0303,
+ MSG_SMB_SAM_REPL=0x0304,
+ MSG_SMB_UNLOCK=0x0305,
+ MSG_SMB_BREAK_REQUEST=0x0306,
+ MSG_SMB_BREAK_RESPONSE=0x0307,
+ MSG_SMB_ASYNC_LEVEL2_BREAK=0x0308,
+ MSG_SMB_OPEN_RETRY=0x0309,
+ MSG_SMB_KERNEL_BREAK=0x030A,
+ MSG_SMB_FILE_RENAME=0x030B,
+ MSG_SMB_INJECT_FAULT=0x030C,
+ MSG_SMB_BLOCKING_LOCK_CANCEL=0x030D,
+ MSG_SMB_NOTIFY=0x030E,
+ MSG_SMB_STAT_CACHE_DELETE=0x030F,
+ MSG_PVFS_NOTIFY=0x0310,
+ MSG_SMB_BRL_VALIDATE=0x0311,
+ MSG_SMB_RELEASE_IP=0x0312,
+ MSG_SMB_CLOSE_FILE=0x0313,
+ MSG_WINBIND_FINISHED=0x0401,
+ MSG_WINBIND_FORGET_STATE=0x0402,
+ MSG_WINBIND_ONLINE=0x0403,
+ MSG_WINBIND_OFFLINE=0x0404,
+ MSG_WINBIND_ONLINESTATUS=0x0405,
+ MSG_WINBIND_TRY_TO_GO_ONLINE=0x0406,
+ MSG_WINBIND_FAILED_TO_GO_ONLINE=0x0407,
+ MSG_WINBIND_VALIDATE_CACHE=0x0408,
+ MSG_WINBIND_DUMP_DOMAIN_LIST=0x0409,
+ MSG_DUMP_EVENT_LIST=0x0500,
+ MSG_DBWRAP_TDB2_CHANGES=4001
+}
+#else
+ { __donnot_use_enum_messaging_type=0x7FFFFFFF}
+#define MSG_DEBUG ( 0x0001 )
+#define MSG_PING ( 0x0002 )
+#define MSG_PONG ( 0x0003 )
+#define MSG_PROFILE ( 0x0004 )
+#define MSG_REQ_DEBUGLEVEL ( 0x0005 )
+#define MSG_DEBUGLEVEL ( 0x0006 )
+#define MSG_REQ_PROFILELEVEL ( 0x0007 )
+#define MSG_PROFILELEVEL ( 0x0008 )
+#define MSG_REQ_POOL_USAGE ( 0x0009 )
+#define MSG_POOL_USAGE ( 0x000A )
+#define MSG_REQ_DMALLOC_MARK ( 0x000B )
+#define MSG_REQ_DMALLOC_LOG_CHANGED ( 0x000C )
+#define MSG_SHUTDOWN ( 0x000D )
+#define MSG_FORCE_ELECTION ( 0x0101 )
+#define MSG_WINS_NEW_ENTRY ( 0x0102 )
+#define MSG_SEND_PACKET ( 0x0103 )
+#define MSG_PRINTER_NOTIFY ( 0x2001 )
+#define MSG_PRINTER_NOTIFY2 ( 0x0202 )
+#define MSG_PRINTER_DRVUPGRADE ( 0x0203 )
+#define MSG_PRINTERDATA_INIT_RESET ( 0x0204 )
+#define MSG_PRINTER_UPDATE ( 0x0205 )
+#define MSG_PRINTER_MOD ( 0x0206 )
+#define MSG_SMB_CONF_UPDATED ( 0x0301 )
+#define MSG_SMB_FORCE_TDIS ( 0x0302 )
+#define MSG_SMB_SAM_SYNC ( 0x0303 )
+#define MSG_SMB_SAM_REPL ( 0x0304 )
+#define MSG_SMB_UNLOCK ( 0x0305 )
+#define MSG_SMB_BREAK_REQUEST ( 0x0306 )
+#define MSG_SMB_BREAK_RESPONSE ( 0x0307 )
+#define MSG_SMB_ASYNC_LEVEL2_BREAK ( 0x0308 )
+#define MSG_SMB_OPEN_RETRY ( 0x0309 )
+#define MSG_SMB_KERNEL_BREAK ( 0x030A )
+#define MSG_SMB_FILE_RENAME ( 0x030B )
+#define MSG_SMB_INJECT_FAULT ( 0x030C )
+#define MSG_SMB_BLOCKING_LOCK_CANCEL ( 0x030D )
+#define MSG_SMB_NOTIFY ( 0x030E )
+#define MSG_SMB_STAT_CACHE_DELETE ( 0x030F )
+#define MSG_PVFS_NOTIFY ( 0x0310 )
+#define MSG_SMB_BRL_VALIDATE ( 0x0311 )
+#define MSG_SMB_RELEASE_IP ( 0x0312 )
+#define MSG_SMB_CLOSE_FILE ( 0x0313 )
+#define MSG_WINBIND_FINISHED ( 0x0401 )
+#define MSG_WINBIND_FORGET_STATE ( 0x0402 )
+#define MSG_WINBIND_ONLINE ( 0x0403 )
+#define MSG_WINBIND_OFFLINE ( 0x0404 )
+#define MSG_WINBIND_ONLINESTATUS ( 0x0405 )
+#define MSG_WINBIND_TRY_TO_GO_ONLINE ( 0x0406 )
+#define MSG_WINBIND_FAILED_TO_GO_ONLINE ( 0x0407 )
+#define MSG_WINBIND_VALIDATE_CACHE ( 0x0408 )
+#define MSG_WINBIND_DUMP_DOMAIN_LIST ( 0x0409 )
+#define MSG_DUMP_EVENT_LIST ( 0x0500 )
+#define MSG_DBWRAP_TDB2_CHANGES ( 4001 )
+#endif
+;
+
+struct messaging_rec {
+ uint32_t msg_version;
+ enum messaging_type msg_type;
+ struct server_id dest;
+ struct server_id src;
+ DATA_BLOB buf;
+}/* [public] */;
+
+struct messaging_array {
+ uint32_t num_messages;
+ struct messaging_rec *messages;
+}/* [public] */;
+
+struct dbwrap_tdb2_changes {
+ const char *magic_string;/* [value("TDB2"),charset(DOS)] */
+ uint32_t magic_version;/* [value] */
+ const char *name;/* [charset(UTF8)] */
+ uint32_t old_seqnum;
+ uint32_t new_seqnum;
+ uint32_t num_changes;
+ uint32_t num_keys;
+ DATA_BLOB *keys;
+}/* [public] */;
+
+#endif /* _HEADER_messaging */
diff --git a/source3/librpc/gen_ndr/misc.h b/source3/librpc/gen_ndr/misc.h
new file mode 100644
index 0000000000..4fa7415db7
--- /dev/null
+++ b/source3/librpc/gen_ndr/misc.h
@@ -0,0 +1,73 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#ifndef _HEADER_misc
+#define _HEADER_misc
+
+struct GUID {
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_hi_and_version;
+ uint8_t clock_seq[2];
+ uint8_t node[6];
+}/* [noprint,gensize,public,noejs] */;
+
+struct ndr_syntax_id {
+ struct GUID uuid;
+ uint32_t if_version;
+}/* [public] */;
+
+struct policy_handle {
+ uint32_t handle_type;
+ struct GUID uuid;
+}/* [public] */;
+
+enum netr_SchannelType
+#ifndef USE_UINT_ENUMS
+ {
+ SEC_CHAN_WKSTA=2,
+ SEC_CHAN_DOMAIN=4,
+ SEC_CHAN_BDC=6
+}
+#else
+ { __donnot_use_enum_netr_SchannelType=0x7FFFFFFF}
+#define SEC_CHAN_WKSTA ( 2 )
+#define SEC_CHAN_DOMAIN ( 4 )
+#define SEC_CHAN_BDC ( 6 )
+#endif
+;
+
+enum netr_SamDatabaseID
+#ifndef USE_UINT_ENUMS
+ {
+ SAM_DATABASE_DOMAIN=0,
+ SAM_DATABASE_BUILTIN=1,
+ SAM_DATABASE_PRIVS=2
+}
+#else
+ { __donnot_use_enum_netr_SamDatabaseID=0x7FFFFFFF}
+#define SAM_DATABASE_DOMAIN ( 0 )
+#define SAM_DATABASE_BUILTIN ( 1 )
+#define SAM_DATABASE_PRIVS ( 2 )
+#endif
+;
+
+enum samr_RejectReason
+#ifndef USE_UINT_ENUMS
+ {
+ SAMR_REJECT_OTHER=0,
+ SAMR_REJECT_TOO_SHORT=1,
+ SAMR_REJECT_IN_HISTORY=2,
+ SAMR_REJECT_COMPLEXITY=5
+}
+#else
+ { __donnot_use_enum_samr_RejectReason=0x7FFFFFFF}
+#define SAMR_REJECT_OTHER ( 0 )
+#define SAMR_REJECT_TOO_SHORT ( 1 )
+#define SAMR_REJECT_IN_HISTORY ( 2 )
+#define SAMR_REJECT_COMPLEXITY ( 5 )
+#endif
+;
+
+#endif /* _HEADER_misc */
diff --git a/source3/librpc/gen_ndr/nbt.h b/source3/librpc/gen_ndr/nbt.h
new file mode 100644
index 0000000000..62ad524a91
--- /dev/null
+++ b/source3/librpc/gen_ndr/nbt.h
@@ -0,0 +1,820 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#include "librpc/gen_ndr/misc.h"
+#include "librpc/gen_ndr/security.h"
+#include "librpc/gen_ndr/svcctl.h"
+#include "librpc/gen_ndr/samr.h"
+#ifndef _HEADER_nbt
+#define _HEADER_nbt
+
+#define NBT_NAME_SERVICE_PORT ( 137 )
+#define NBT_DGRAM_SERVICE_PORT ( 138 )
+#define NBT_MAILSLOT_NETLOGON ( "\\MAILSLOT\\NET\\NETLOGON" )
+#define NBT_MAILSLOT_NTLOGON ( "\\MAILSLOT\\NET\\NTLOGON" )
+#define NBT_MAILSLOT_GETDC ( "\\MAILSLOT\\NET\\GETDC" )
+#define NBT_MAILSLOT_BROWSE ( "\\MAILSLOT\\BROWSE" )
+#define DGRAM_SMB ( 0xff534d42 )
+/* bitmap nbt_operation */
+#define NBT_RCODE ( 0x000F )
+#define NBT_FLAG_BROADCAST ( 0x0010 )
+#define NBT_FLAG_RECURSION_AVAIL ( 0x0080 )
+#define NBT_FLAG_RECURSION_DESIRED ( 0x0100 )
+#define NBT_FLAG_TRUNCATION ( 0x0200 )
+#define NBT_FLAG_AUTHORITIVE ( 0x0400 )
+#define NBT_OPCODE ( 0x7800 )
+#define NBT_FLAG_REPLY ( 0x8000 )
+
+enum nbt_opcode
+#ifndef USE_UINT_ENUMS
+ {
+ NBT_OPCODE_QUERY=(0x0<<11),
+ NBT_OPCODE_REGISTER=(0x5<<11),
+ NBT_OPCODE_RELEASE=(0x6<<11),
+ NBT_OPCODE_WACK=(0x7<<11),
+ NBT_OPCODE_REFRESH=(0x8<<11),
+ NBT_OPCODE_REFRESH2=(0x9<<11),
+ NBT_OPCODE_MULTI_HOME_REG=(0xf<<11)
+}
+#else
+ { __donnot_use_enum_nbt_opcode=0x7FFFFFFF}
+#define NBT_OPCODE_QUERY ( (0x0<<11) )
+#define NBT_OPCODE_REGISTER ( (0x5<<11) )
+#define NBT_OPCODE_RELEASE ( (0x6<<11) )
+#define NBT_OPCODE_WACK ( (0x7<<11) )
+#define NBT_OPCODE_REFRESH ( (0x8<<11) )
+#define NBT_OPCODE_REFRESH2 ( (0x9<<11) )
+#define NBT_OPCODE_MULTI_HOME_REG ( (0xf<<11) )
+#endif
+;
+
+enum nbt_rcode
+#ifndef USE_UINT_ENUMS
+ {
+ NBT_RCODE_OK=0x0,
+ NBT_RCODE_FMT=0x1,
+ NBT_RCODE_SVR=0x2,
+ NBT_RCODE_NAM=0x3,
+ NBT_RCODE_IMP=0x4,
+ NBT_RCODE_RFS=0x5,
+ NBT_RCODE_ACT=0x6,
+ NBT_RCODE_CFT=0x7
+}
+#else
+ { __donnot_use_enum_nbt_rcode=0x7FFFFFFF}
+#define NBT_RCODE_OK ( 0x0 )
+#define NBT_RCODE_FMT ( 0x1 )
+#define NBT_RCODE_SVR ( 0x2 )
+#define NBT_RCODE_NAM ( 0x3 )
+#define NBT_RCODE_IMP ( 0x4 )
+#define NBT_RCODE_RFS ( 0x5 )
+#define NBT_RCODE_ACT ( 0x6 )
+#define NBT_RCODE_CFT ( 0x7 )
+#endif
+;
+
+enum nbt_name_type
+#ifndef USE_UINT_ENUMS
+ {
+ NBT_NAME_CLIENT=0x00,
+ NBT_NAME_MS=0x01,
+ NBT_NAME_USER=0x03,
+ NBT_NAME_SERVER=0x20,
+ NBT_NAME_PDC=0x1B,
+ NBT_NAME_LOGON=0x1C,
+ NBT_NAME_MASTER=0x1D,
+ NBT_NAME_BROWSER=0x1E
+}
+#else
+ { __donnot_use_enum_nbt_name_type=0x7FFFFFFF}
+#define NBT_NAME_CLIENT ( 0x00 )
+#define NBT_NAME_MS ( 0x01 )
+#define NBT_NAME_USER ( 0x03 )
+#define NBT_NAME_SERVER ( 0x20 )
+#define NBT_NAME_PDC ( 0x1B )
+#define NBT_NAME_LOGON ( 0x1C )
+#define NBT_NAME_MASTER ( 0x1D )
+#define NBT_NAME_BROWSER ( 0x1E )
+#endif
+;
+
+struct nbt_name {
+ const char * name;
+ const char * scope;
+ enum nbt_name_type type;
+}/* [nopull,public,nopush] */;
+
+enum nbt_qclass
+#ifndef USE_UINT_ENUMS
+ {
+ NBT_QCLASS_IP=0x01
+}
+#else
+ { __donnot_use_enum_nbt_qclass=0x7FFFFFFF}
+#define NBT_QCLASS_IP ( 0x01 )
+#endif
+;
+
+enum nbt_qtype
+#ifndef USE_UINT_ENUMS
+ {
+ NBT_QTYPE_ADDRESS=0x0001,
+ NBT_QTYPE_NAMESERVICE=0x0002,
+ NBT_QTYPE_NULL=0x000A,
+ NBT_QTYPE_NETBIOS=0x0020,
+ NBT_QTYPE_STATUS=0x0021
+}
+#else
+ { __donnot_use_enum_nbt_qtype=0x7FFFFFFF}
+#define NBT_QTYPE_ADDRESS ( 0x0001 )
+#define NBT_QTYPE_NAMESERVICE ( 0x0002 )
+#define NBT_QTYPE_NULL ( 0x000A )
+#define NBT_QTYPE_NETBIOS ( 0x0020 )
+#define NBT_QTYPE_STATUS ( 0x0021 )
+#endif
+;
+
+struct nbt_name_question {
+ struct nbt_name name;
+ enum nbt_qtype question_type;
+ enum nbt_qclass question_class;
+};
+
+enum nbt_node_type
+#ifndef USE_UINT_ENUMS
+ {
+ NBT_NODE_B=0x0000,
+ NBT_NODE_P=0x2000,
+ NBT_NODE_M=0x4000,
+ NBT_NODE_H=0x6000
+}
+#else
+ { __donnot_use_enum_nbt_node_type=0x7FFFFFFF}
+#define NBT_NODE_B ( 0x0000 )
+#define NBT_NODE_P ( 0x2000 )
+#define NBT_NODE_M ( 0x4000 )
+#define NBT_NODE_H ( 0x6000 )
+#endif
+;
+
+/* bitmap nb_flags */
+#define NBT_NM_PERMANENT ( 0x0200 )
+#define NBT_NM_ACTIVE ( 0x0400 )
+#define NBT_NM_CONFLICT ( 0x0800 )
+#define NBT_NM_DEREGISTER ( 0x1000 )
+#define NBT_NM_OWNER_TYPE ( 0x6000 )
+#define NBT_NM_GROUP ( 0x8000 )
+
+struct nbt_rdata_address {
+ uint16_t nb_flags;
+ const char * ipaddr;
+};
+
+struct nbt_rdata_netbios {
+ uint16_t length;
+ struct nbt_rdata_address *addresses;
+};
+
+struct nbt_statistics {
+ uint8_t unit_id[6];
+ uint8_t jumpers;
+ uint8_t test_result;
+ uint16_t version_number;
+ uint16_t period_of_statistics;
+ uint16_t number_of_crcs;
+ uint16_t number_alignment_errors;
+ uint16_t number_of_collisions;
+ uint16_t number_send_aborts;
+ uint32_t number_good_sends;
+ uint32_t number_good_receives;
+ uint16_t number_retransmits;
+ uint16_t number_no_resource_conditions;
+ uint16_t number_free_command_blocks;
+ uint16_t total_number_command_blocks;
+ uint16_t max_total_number_command_blocks;
+ uint16_t number_pending_sessions;
+ uint16_t max_number_pending_sessions;
+ uint16_t max_total_sessions_possible;
+ uint16_t session_data_packet_size;
+};
+
+struct nbt_status_name {
+ const char *name;/* [charset(DOS)] */
+ enum nbt_name_type type;
+ uint16_t nb_flags;
+};
+
+struct nbt_rdata_status {
+ uint16_t length;/* [value(num_names*18+47)] */
+ uint8_t num_names;
+ struct nbt_status_name *names;
+ struct nbt_statistics statistics;
+};
+
+struct nbt_rdata_data {
+ uint16_t length;
+ uint8_t *data;
+};
+
+union nbt_rdata {
+ struct nbt_rdata_netbios netbios;/* [case(NBT_QTYPE_NETBIOS)] */
+ struct nbt_rdata_status status;/* [case(NBT_QTYPE_STATUS)] */
+ struct nbt_rdata_data data;/* [default] */
+}/* [nodiscriminant] */;
+
+struct nbt_res_rec {
+ struct nbt_name name;
+ enum nbt_qtype rr_type;
+ enum nbt_qclass rr_class;
+ uint32_t ttl;
+ union nbt_rdata rdata;/* [switch_is(((((rr_type)==NBT_QTYPE_NETBIOS)&&talloc_check_name(ndr,"struct ndr_push")&&((rdata).data.length==2))?0:rr_type))] */
+}/* [flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+struct nbt_name_packet {
+ uint16_t name_trn_id;
+ uint16_t operation;
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+ struct nbt_name_question *questions;
+ struct nbt_res_rec *answers;
+ struct nbt_res_rec *nsrecs;
+ struct nbt_res_rec *additional;
+ DATA_BLOB padding;/* [flag(LIBNDR_FLAG_REMAINING)] */
+}/* [public,flag(LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_BIGENDIAN|LIBNDR_PRINT_ARRAY_HEX)] */;
+
+enum dgram_msg_type
+#ifndef USE_UINT_ENUMS
+ {
+ DGRAM_DIRECT_UNIQUE=0x10,
+ DGRAM_DIRECT_GROUP=0x11,
+ DGRAM_BCAST=0x12,
+ DGRAM_ERROR=0x13,
+ DGRAM_QUERY=0x14,
+ DGRAM_QUERY_POSITIVE=0x15,
+ DGRAM_QUERY_NEGATIVE=0x16
+}
+#else
+ { __donnot_use_enum_dgram_msg_type=0x7FFFFFFF}
+#define DGRAM_DIRECT_UNIQUE ( 0x10 )
+#define DGRAM_DIRECT_GROUP ( 0x11 )
+#define DGRAM_BCAST ( 0x12 )
+#define DGRAM_ERROR ( 0x13 )
+#define DGRAM_QUERY ( 0x14 )
+#define DGRAM_QUERY_POSITIVE ( 0x15 )
+#define DGRAM_QUERY_NEGATIVE ( 0x16 )
+#endif
+;
+
+/* bitmap dgram_flags */
+#define DGRAM_FLAG_MORE ( 0x01 )
+#define DGRAM_FLAG_FIRST ( 0x02 )
+#define DGRAM_FLAG_NODE_TYPE ( 0x0C )
+
+enum dgram_node_type
+#ifndef USE_UINT_ENUMS
+ {
+ DGRAM_NODE_B=0x00,
+ DGRAM_NODE_P=0x04,
+ DGRAM_NODE_M=0x08,
+ DGRAM_NODE_NBDD=0x0C
+}
+#else
+ { __donnot_use_enum_dgram_node_type=0x7FFFFFFF}
+#define DGRAM_NODE_B ( 0x00 )
+#define DGRAM_NODE_P ( 0x04 )
+#define DGRAM_NODE_M ( 0x08 )
+#define DGRAM_NODE_NBDD ( 0x0C )
+#endif
+;
+
+enum smb_command
+#ifndef USE_UINT_ENUMS
+ {
+ SMB_TRANSACTION=0x25
+}
+#else
+ { __donnot_use_enum_smb_command=0x7FFFFFFF}
+#define SMB_TRANSACTION ( 0x25 )
+#endif
+;
+
+struct smb_trans_body {
+ uint8_t wct;/* [value(17),range(17,17)] */
+ uint16_t total_param_count;
+ uint16_t total_data_count;
+ uint16_t max_param_count;
+ uint16_t max_data_count;
+ uint8_t max_setup_count;
+ uint8_t pad;
+ uint16_t trans_flags;
+ uint32_t timeout;
+ uint16_t reserved;
+ uint16_t param_count;
+ uint16_t param_offset;
+ uint16_t data_count;
+ uint16_t data_offset;
+ uint8_t setup_count;/* [value(3),range(3,3)] */
+ uint8_t pad2;
+ uint16_t opcode;
+ uint16_t priority;
+ uint16_t _class;
+ uint16_t byte_count;/* [value(strlen(mailslot_name)+1+data.length)] */
+ const char * mailslot_name;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+ DATA_BLOB data;/* [flag(LIBNDR_FLAG_REMAINING)] */
+};
+
+union smb_body {
+ struct smb_trans_body trans;/* [case(SMB_TRANSACTION)] */
+}/* [nodiscriminant] */;
+
+struct dgram_smb_packet {
+ enum smb_command smb_command;
+ uint8_t err_class;
+ uint8_t pad;
+ uint16_t err_code;
+ uint8_t flags;
+ uint16_t flags2;
+ uint16_t pid_high;
+ uint8_t signature[8];
+ uint16_t reserved;
+ uint16_t tid;
+ uint16_t pid;
+ uint16_t vuid;
+ uint16_t mid;
+ union smb_body body;/* [switch_is(smb_command)] */
+}/* [public,flag(LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_PRINT_ARRAY_HEX)] */;
+
+union dgram_message_body {
+ struct dgram_smb_packet smb;/* [case(DGRAM_SMB)] */
+}/* [nodiscriminant] */;
+
+struct dgram_message {
+ uint16_t length;
+ uint16_t offset;
+ struct nbt_name source_name;
+ struct nbt_name dest_name;
+ uint32_t dgram_body_type;
+ union dgram_message_body body;/* [switch_is(dgram_body_type)] */
+};
+
+enum dgram_err_code
+#ifndef USE_UINT_ENUMS
+ {
+ DGRAM_ERROR_NAME_NOT_PRESENT=0x82,
+ DGRAM_ERROR_INVALID_SOURCE=0x83,
+ DGRAM_ERROR_INVALID_DEST=0x84
+}
+#else
+ { __donnot_use_enum_dgram_err_code=0x7FFFFFFF}
+#define DGRAM_ERROR_NAME_NOT_PRESENT ( 0x82 )
+#define DGRAM_ERROR_INVALID_SOURCE ( 0x83 )
+#define DGRAM_ERROR_INVALID_DEST ( 0x84 )
+#endif
+;
+
+union dgram_data {
+ struct dgram_message msg;/* [case(DGRAM_DIRECT_UNIQUE)] */
+ enum dgram_err_code error;/* [case(DGRAM_ERROR)] */
+ struct nbt_name dest_name;/* [case(DGRAM_QUERY)] */
+}/* [nodiscriminant] */;
+
+struct nbt_dgram_packet {
+ enum dgram_msg_type msg_type;
+ uint8_t flags;
+ uint16_t dgram_id;
+ const char * src_addr;
+ uint16_t src_port;
+ union dgram_data data;/* [switch_is(msg_type)] */
+}/* [public,flag(LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_BIGENDIAN|LIBNDR_PRINT_ARRAY_HEX)] */;
+
+enum nbt_netlogon_command
+#ifndef USE_UINT_ENUMS
+ {
+ NETLOGON_QUERY_FOR_PDC=0x7,
+ NETLOGON_ANNOUNCE_UAS=0xa,
+ NETLOGON_RESPONSE_FROM_PDC=0xc,
+ NETLOGON_QUERY_FOR_PDC2=0x12,
+ NETLOGON_RESPONSE_FROM_PDC2=0x17,
+ NETLOGON_RESPONSE_FROM_PDC_USER=0x19
+}
+#else
+ { __donnot_use_enum_nbt_netlogon_command=0x7FFFFFFF}
+#define NETLOGON_QUERY_FOR_PDC ( 0x7 )
+#define NETLOGON_ANNOUNCE_UAS ( 0xa )
+#define NETLOGON_RESPONSE_FROM_PDC ( 0xc )
+#define NETLOGON_QUERY_FOR_PDC2 ( 0x12 )
+#define NETLOGON_RESPONSE_FROM_PDC2 ( 0x17 )
+#define NETLOGON_RESPONSE_FROM_PDC_USER ( 0x19 )
+#endif
+;
+
+/* bitmap nbt_netlogon_version */
+#define NETLOGON_VERSION_1 ( 0x00000001 )
+#define NETLOGON_VERSION_5 ( 0x00000002 )
+#define NETLOGON_VERSION_5EX ( 0x00000004 )
+#define NETLOGON_VERSION_5EX_WITH_IP ( 0x00000008 )
+#define NETLOGON_VERSION_WITH_CLOSEST_SITE ( 0x00000010 )
+#define NETLOGON_VERSION_AVOID_NT4_EMUL ( 0x01000000 )
+#define NETLOGON_VERSION_PDC ( 0x10000000 )
+#define NETLOGON_VERSION_IP ( 0x20000000 )
+#define NETLOGON_VERSION_LOCAL ( 0x40000000 )
+#define NETLOGON_VERSION_GC ( 0x80000000 )
+
+struct nbt_netlogon_query_for_pdc {
+ const char * computer_name;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * mailslot_name;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+ DATA_BLOB _pad;/* [flag(LIBNDR_FLAG_ALIGN2)] */
+ const char * unicode_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ uint32_t nt_version;
+ uint16_t lmnt_token;
+ uint16_t lm20_token;
+};
+
+struct nbt_netlogon_query_for_pdc2 {
+ uint16_t request_count;
+ const char * computer_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * user_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * mailslot_name;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+ uint32_t unknown[2];
+ uint32_t nt_version;
+ uint16_t lmnt_token;
+ uint16_t lm20_token;
+};
+
+struct nbt_netlogon_response_from_pdc {
+ const char * pdc_name;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+ DATA_BLOB _pad;/* [flag(LIBNDR_FLAG_ALIGN2)] */
+ const char * unicode_pdc_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * domain_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ uint32_t nt_version;
+ uint16_t lmnt_token;
+ uint16_t lm20_token;
+};
+
+/* bitmap nbt_server_type */
+#define NBT_SERVER_PDC ( 0x00000001 )
+#define NBT_SERVER_GC ( 0x00000004 )
+#define NBT_SERVER_LDAP ( 0x00000008 )
+#define NBT_SERVER_DS ( 0x00000010 )
+#define NBT_SERVER_KDC ( 0x00000020 )
+#define NBT_SERVER_TIMESERV ( 0x00000040 )
+#define NBT_SERVER_CLOSEST ( 0x00000080 )
+#define NBT_SERVER_WRITABLE ( 0x00000100 )
+#define NBT_SERVER_GOOD_TIMESERV ( 0x00000200 )
+#define NBT_SERVER_NDNC ( 0x00000400 )
+#define NBT_SERVER_SELECT_SECRET_DOMAIN_6 ( 0x00000800 )
+#define NBT_SERVER_FULL_SECRET_DOMAIN_6 ( 0x00001000 )
+
+struct nbt_dc_sock_addr {
+ uint32_t family;
+ const char * pdc_ip;/* [flag(LIBNDR_FLAG_BIGENDIAN)] */
+ DATA_BLOB remaining;/* [flag(LIBNDR_FLAG_REMAINING)] */
+};
+
+struct nbt_netlogon_response_from_pdc2 {
+ DATA_BLOB _pad;/* [flag(LIBNDR_FLAG_ALIGN4)] */
+ uint32_t server_type;
+ struct GUID domain_uuid;
+ const char * forest;
+ const char * dns_domain;
+ const char * pdc_dns_name;
+ const char * domain;
+ const char * pdc_name;
+ const char * user_name;
+ const char * server_site;
+ const char * client_site;
+ uint8_t dc_sock_addr_size;
+ struct nbt_dc_sock_addr dc_sock_addr;/* [subcontext_size(dc_sock_addr_size),subcontext(0)] */
+ uint32_t nt_version;
+ uint16_t lmnt_token;
+ uint16_t lm20_token;
+};
+
+enum netr_SamDatabaseID;
+
+struct nbt_db_change {
+ enum netr_SamDatabaseID db_index;
+ uint64_t serial;
+ NTTIME timestamp;
+};
+
+struct nbt_netlogon_announce_uas {
+ uint32_t serial_lo;
+ time_t timestamp;
+ uint32_t pulse;
+ uint32_t random;
+ const char * pdc_name;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * domain;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+ DATA_BLOB _pad;/* [flag(LIBNDR_FLAG_ALIGN2)] */
+ const char * unicode_pdc_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * unicode_domain;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ uint32_t db_count;
+ struct nbt_db_change *dbchange;
+ uint32_t sid_size;/* [value(ndr_size_dom_sid0(&sid,ndr->flags))] */
+ struct dom_sid0 sid;/* [subcontext_size(sid_size),subcontext(0)] */
+ uint32_t nt_version;
+ uint16_t lmnt_token;
+ uint16_t lm20_token;
+};
+
+union nbt_netlogon_request {
+ struct nbt_netlogon_query_for_pdc pdc;/* [case(NETLOGON_QUERY_FOR_PDC)] */
+ struct nbt_netlogon_query_for_pdc2 pdc2;/* [case(NETLOGON_QUERY_FOR_PDC2)] */
+ struct nbt_netlogon_announce_uas uas;/* [case(NETLOGON_ANNOUNCE_UAS)] */
+ struct nbt_netlogon_response_from_pdc response;/* [case(NETLOGON_RESPONSE_FROM_PDC)] */
+ struct nbt_netlogon_response_from_pdc2 response2;/* [case(NETLOGON_RESPONSE_FROM_PDC2)] */
+}/* [nodiscriminant] */;
+
+struct nbt_netlogon_packet {
+ enum nbt_netlogon_command command;
+ union nbt_netlogon_request req;/* [switch_is(command)] */
+}/* [public,flag(LIBNDR_FLAG_NOALIGN)] */;
+
+struct nbt_cldap_netlogon_1 {
+ enum nbt_netlogon_command type;
+ const char * pdc_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * user_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * domain_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ uint32_t nt_version;/* [value] */
+ uint16_t lmnt_token;
+ uint16_t lm20_token;
+};
+
+struct nbt_cldap_netlogon_3 {
+ enum nbt_netlogon_command type;
+ const char * pdc_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * user_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * domain_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ struct GUID domain_uuid;
+ struct GUID unknown_uuid;
+ const char * forest;
+ const char * dns_domain;
+ const char * pdc_dns_name;
+ const char * pdc_ip;
+ uint32_t server_type;
+ uint32_t nt_version;/* [value(3)] */
+ uint16_t lmnt_token;
+ uint16_t lm20_token;
+};
+
+struct nbt_cldap_netlogon_5 {
+ enum nbt_netlogon_command type;
+ uint16_t sbz;
+ uint32_t server_type;
+ struct GUID domain_uuid;
+ const char * forest;
+ const char * dns_domain;
+ const char * pdc_dns_name;
+ const char * domain;
+ const char * pdc_name;
+ const char * user_name;
+ const char * server_site;
+ const char * client_site;
+ uint32_t nt_version;/* [value(5)] */
+ uint16_t lmnt_token;
+ uint16_t lm20_token;
+}/* [public] */;
+
+struct nbt_cldap_netlogon_13 {
+ enum nbt_netlogon_command type;
+ uint16_t sbz;
+ uint32_t server_type;
+ struct GUID domain_uuid;
+ const char * forest;
+ const char * dns_domain;
+ const char * pdc_dns_name;
+ const char * domain;
+ const char * pdc_name;
+ const char * user_name;
+ const char * server_site;
+ const char * client_site;
+ uint8_t dc_sock_addr_size;
+ struct nbt_dc_sock_addr dc_sock_addr;/* [subcontext_size(dc_sock_addr_size),subcontext(0)] */
+ uint32_t nt_version;/* [value(13)] */
+ uint16_t lmnt_token;
+ uint16_t lm20_token;
+};
+
+struct nbt_cldap_netlogon_15 {
+ enum nbt_netlogon_command type;
+ uint16_t sbz;
+ uint32_t server_type;
+ struct GUID domain_uuid;
+ const char * forest;
+ const char * dns_domain;
+ const char * pdc_dns_name;
+ const char * domain;
+ const char * pdc_name;
+ const char * user_name;
+ const char * server_site;
+ const char * client_site;
+ const char * next_closest_site;
+ uint32_t nt_version;/* [value(15)] */
+ uint16_t lmnt_token;
+ uint16_t lm20_token;
+}/* [public] */;
+
+struct nbt_cldap_netlogon_29 {
+ enum nbt_netlogon_command type;
+ uint16_t sbz;
+ uint32_t server_type;
+ struct GUID domain_uuid;
+ const char * forest;
+ const char * dns_domain;
+ const char * pdc_dns_name;
+ const char * domain;
+ const char * pdc_name;
+ const char * user_name;
+ const char * server_site;
+ const char * client_site;
+ uint8_t dc_sock_addr_size;
+ struct nbt_dc_sock_addr dc_sock_addr;/* [subcontext_size(dc_sock_addr_size),subcontext(0)] */
+ const char * next_closest_site;
+ uint32_t nt_version;/* [value(29)] */
+ uint16_t lmnt_token;
+ uint16_t lm20_token;
+}/* [public] */;
+
+union nbt_cldap_netlogon {
+ struct nbt_cldap_netlogon_1 logon1;/* [case(0)] */
+ struct nbt_cldap_netlogon_3 logon3;/* [case(2)] */
+ struct nbt_cldap_netlogon_5 logon5;/* [case(4)] */
+ struct nbt_cldap_netlogon_13 logon13;/* [case(8)] */
+ struct nbt_cldap_netlogon_15 logon15;/* [case(20)] */
+ struct nbt_cldap_netlogon_29 logon29;/* [case(29)] */
+}/* [public,nodiscriminant,flag(LIBNDR_FLAG_NOALIGN)] */;
+
+enum nbt_ntlogon_command
+#ifndef USE_UINT_ENUMS
+ {
+ NTLOGON_SAM_LOGON=0x12,
+ NTLOGON_SAM_LOGON_REPLY=0x13,
+ NTLOGON_SAM_LOGON_REPLY15=0x15,
+ NTLOGON_RESPONSE_FROM_PDC2=0x17
+}
+#else
+ { __donnot_use_enum_nbt_ntlogon_command=0x7FFFFFFF}
+#define NTLOGON_SAM_LOGON ( 0x12 )
+#define NTLOGON_SAM_LOGON_REPLY ( 0x13 )
+#define NTLOGON_SAM_LOGON_REPLY15 ( 0x15 )
+#define NTLOGON_RESPONSE_FROM_PDC2 ( 0x17 )
+#endif
+;
+
+struct nbt_ntlogon_sam_logon {
+ uint16_t request_count;
+ const char * computer_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * user_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * mailslot_name;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+ uint32_t acct_control;
+ uint32_t sid_size;/* [value(ndr_size_dom_sid0(&sid,ndr->flags))] */
+ struct dom_sid0 sid;/* [subcontext_size(sid_size),subcontext(0)] */
+ uint32_t nt_version;
+ uint16_t lmnt_token;
+ uint16_t lm20_token;
+};
+
+struct nbt_ntlogon_sam_logon_reply {
+ const char * server;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * user_name;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * domain;/* [flag(LIBNDR_FLAG_STR_NULLTERM)] */
+ uint32_t nt_version;
+ uint16_t lmnt_token;
+ uint16_t lm20_token;
+};
+
+union nbt_ntlogon_request {
+ struct nbt_ntlogon_sam_logon logon;/* [case(NTLOGON_SAM_LOGON)] */
+ struct nbt_ntlogon_sam_logon_reply reply;/* [case(NTLOGON_SAM_LOGON_REPLY)] */
+ struct nbt_netlogon_response_from_pdc2 reply2;/* [case(NTLOGON_RESPONSE_FROM_PDC2)] */
+}/* [nodiscriminant] */;
+
+struct nbt_ntlogon_packet {
+ enum nbt_ntlogon_command command;
+ union nbt_ntlogon_request req;/* [switch_is(command)] */
+}/* [public,flag(LIBNDR_FLAG_NOALIGN)] */;
+
+enum nbt_browse_opcode
+#ifndef USE_UINT_ENUMS
+ {
+ HostAnnouncement=1,
+ AnnouncementRequest=2,
+ Election=8,
+ GetBackupListReq=9,
+ GetBackupListResp=10,
+ BecomeBackup=11,
+ DomainAnnouncement=12,
+ MasterAnnouncement=13,
+ ResetBrowserState=14,
+ LocalMasterAnnouncement=15
+}
+#else
+ { __donnot_use_enum_nbt_browse_opcode=0x7FFFFFFF}
+#define HostAnnouncement ( 1 )
+#define AnnouncementRequest ( 2 )
+#define Election ( 8 )
+#define GetBackupListReq ( 9 )
+#define GetBackupListResp ( 10 )
+#define BecomeBackup ( 11 )
+#define DomainAnnouncement ( 12 )
+#define MasterAnnouncement ( 13 )
+#define ResetBrowserState ( 14 )
+#define LocalMasterAnnouncement ( 15 )
+#endif
+;
+
+struct nbt_browse_host_announcement {
+ uint8_t UpdateCount;
+ uint32_t Periodicity;
+ const char *ServerName;/* [charset(DOS)] */
+ uint8_t OSMajor;
+ uint8_t OSMinor;
+ uint32_t ServerType;
+ uint8_t BroMajorVer;
+ uint8_t BroMinorVer;
+ uint16_t Signature;
+ const char * Comment;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+};
+
+struct nbt_browse_announcement_request {
+ uint8_t Unused;
+ const char * ResponseName;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+};
+
+struct nbt_browse_election_request {
+ uint8_t Version;
+ uint32_t Criteria;
+ uint32_t UpTime;
+ uint32_t Reserved;
+ const char * ServerName;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+};
+
+struct nbt_browse_backup_list_request {
+ uint8_t ReqCount;
+ uint32_t Token;
+};
+
+struct nbt_browse_backup_list_response {
+ uint8_t BackupCount;
+ uint32_t Token;
+ struct nbt_name *BackupServerList;
+};
+
+struct nbt_browse_become_backup {
+ const char * BrowserName;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+};
+
+struct nbt_browse_domain_announcement {
+ uint8_t UpdateCount;
+ uint32_t Periodicity;
+ const char *ServerName;/* [charset(DOS)] */
+ uint8_t OSMajor;
+ uint8_t OSMinor;
+ uint32_t ServerType;
+ uint32_t MysteriousField;
+ const char * Comment;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+};
+
+struct nbt_browse_master_announcement {
+ const char * ServerName;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+};
+
+struct nbt_browse_reset_state {
+ uint8_t Command;
+};
+
+struct nbt_browse_local_master_announcement {
+ uint8_t UpdateCount;
+ uint32_t Periodicity;
+ const char *ServerName;/* [charset(DOS)] */
+ uint8_t OSMajor;
+ uint8_t OSMinor;
+ uint32_t ServerType;
+ uint8_t BroMajorVer;
+ uint8_t BroMinorVer;
+ uint16_t Signature;
+ const char * Comment;/* [flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+};
+
+union nbt_browse_payload {
+ struct nbt_browse_host_announcement host_annoucement;/* [case(HostAnnouncement)] */
+ struct nbt_browse_announcement_request announcement_request;/* [case(AnnouncementRequest)] */
+ struct nbt_browse_election_request election_request;/* [case(Election)] */
+ struct nbt_browse_backup_list_request backup_list_request;/* [case(GetBackupListReq)] */
+ struct nbt_browse_backup_list_response backup_list_response;/* [case(GetBackupListResp)] */
+ struct nbt_browse_become_backup become_backup;/* [case(BecomeBackup)] */
+ struct nbt_browse_domain_announcement domain_announcement;/* [case(DomainAnnouncement)] */
+ struct nbt_browse_master_announcement master_announcement;/* [case(MasterAnnouncement)] */
+ struct nbt_browse_reset_state reset_browser_state;/* [case(ResetBrowserState)] */
+ struct nbt_browse_local_master_announcement local_master_announcement;/* [case(LocalMasterAnnouncement)] */
+}/* [nodiscriminant] */;
+
+struct nbt_browse_packet {
+ enum nbt_browse_opcode opcode;
+ union nbt_browse_payload payload;/* [switch_is(opcode)] */
+}/* [public,flag(LIBNDR_FLAG_NOALIGN)] */;
+
+#endif /* _HEADER_nbt */
diff --git a/source3/librpc/gen_ndr/ndr_dfs.c b/source3/librpc/gen_ndr/ndr_dfs.c
new file mode 100644
index 0000000000..de3ac48c00
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_dfs.c
@@ -0,0 +1,5802 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_dfs.h"
+
+static enum ndr_err_code ndr_push_dfs_ManagerVersion(struct ndr_push *ndr, int ndr_flags, enum dfs_ManagerVersion r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_ManagerVersion(struct ndr_pull *ndr, int ndr_flags, enum dfs_ManagerVersion *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_ManagerVersion(struct ndr_print *ndr, const char *name, enum dfs_ManagerVersion r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DFS_MANAGER_VERSION_NT4: val = "DFS_MANAGER_VERSION_NT4"; break;
+ case DFS_MANAGER_VERSION_W2K: val = "DFS_MANAGER_VERSION_W2K"; break;
+ case DFS_MANAGER_VERSION_W2K3: val = "DFS_MANAGER_VERSION_W2K3"; break;
+ case DFS_MANAGER_VERSION_W2K8: val = "DFS_MANAGER_VERSION_W2K8"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_dfs_Info0(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info0(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info0(struct ndr_print *ndr, const char *name, const struct dfs_Info0 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Info0");
+ ndr->depth++;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Info1(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->path));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->path) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->path, ndr_charset_length(r->path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info1(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info1 *r)
+{
+ uint32_t _ptr_path;
+ TALLOC_CTX *_mem_save_path_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_path));
+ if (_ptr_path) {
+ NDR_PULL_ALLOC(ndr, r->path);
+ } else {
+ r->path = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->path) {
+ _mem_save_path_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->path, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->path));
+ if (ndr_get_array_length(ndr, &r->path) > ndr_get_array_size(ndr, &r->path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->path), ndr_get_array_length(ndr, &r->path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->path, ndr_get_array_length(ndr, &r->path), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_path_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info1(struct ndr_print *ndr, const char *name, const struct dfs_Info1 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Info1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "path", r->path);
+ ndr->depth++;
+ if (r->path) {
+ ndr_print_string(ndr, "path", r->path);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_dfs_VolumeState(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_dfs_VolumeState(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_VolumeState(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DFS_VOLUME_STATE_OK", DFS_VOLUME_STATE_OK, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DFS_VOLUME_STATE_INCONSISTENT", DFS_VOLUME_STATE_INCONSISTENT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DFS_VOLUME_STATE_OFFLINE", DFS_VOLUME_STATE_OFFLINE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DFS_VOLUME_STATE_ONLINE", DFS_VOLUME_STATE_ONLINE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DFS_VOLUME_STATE_STANDALONE", DFS_VOLUME_STATE_STANDALONE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DFS_VOLUME_STATE_AD_BLOB", DFS_VOLUME_STATE_AD_BLOB, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Info2(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->path));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->comment));
+ NDR_CHECK(ndr_push_dfs_VolumeState(ndr, NDR_SCALARS, r->state));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_stores));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->path) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->path, ndr_charset_length(r->path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->comment) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->comment, ndr_charset_length(r->comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info2(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info2 *r)
+{
+ uint32_t _ptr_path;
+ TALLOC_CTX *_mem_save_path_0;
+ uint32_t _ptr_comment;
+ TALLOC_CTX *_mem_save_comment_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_path));
+ if (_ptr_path) {
+ NDR_PULL_ALLOC(ndr, r->path);
+ } else {
+ r->path = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_comment));
+ if (_ptr_comment) {
+ NDR_PULL_ALLOC(ndr, r->comment);
+ } else {
+ r->comment = NULL;
+ }
+ NDR_CHECK(ndr_pull_dfs_VolumeState(ndr, NDR_SCALARS, &r->state));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_stores));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->path) {
+ _mem_save_path_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->path, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->path));
+ if (ndr_get_array_length(ndr, &r->path) > ndr_get_array_size(ndr, &r->path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->path), ndr_get_array_length(ndr, &r->path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->path, ndr_get_array_length(ndr, &r->path), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_path_0, 0);
+ }
+ if (r->comment) {
+ _mem_save_comment_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->comment, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->comment));
+ if (ndr_get_array_length(ndr, &r->comment) > ndr_get_array_size(ndr, &r->comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->comment), ndr_get_array_length(ndr, &r->comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->comment, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_comment_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info2(struct ndr_print *ndr, const char *name, const struct dfs_Info2 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Info2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "path", r->path);
+ ndr->depth++;
+ if (r->path) {
+ ndr_print_string(ndr, "path", r->path);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "comment", r->comment);
+ ndr->depth++;
+ if (r->comment) {
+ ndr_print_string(ndr, "comment", r->comment);
+ }
+ ndr->depth--;
+ ndr_print_dfs_VolumeState(ndr, "state", r->state);
+ ndr_print_uint32(ndr, "num_stores", r->num_stores);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_dfs_StorageState(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_dfs_StorageState(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_StorageState(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DFS_STORAGE_STATE_OFFLINE", DFS_STORAGE_STATE_OFFLINE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DFS_STORAGE_STATE_ONLINE", DFS_STORAGE_STATE_ONLINE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DFS_STORAGE_STATE_ACTIVE", DFS_STORAGE_STATE_ACTIVE, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_StorageInfo(struct ndr_push *ndr, int ndr_flags, const struct dfs_StorageInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_dfs_StorageState(ndr, NDR_SCALARS, r->state));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->server));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->share));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->server) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->server, ndr_charset_length(r->server, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->share) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->share, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->share, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->share, ndr_charset_length(r->share, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_StorageInfo(struct ndr_pull *ndr, int ndr_flags, struct dfs_StorageInfo *r)
+{
+ uint32_t _ptr_server;
+ TALLOC_CTX *_mem_save_server_0;
+ uint32_t _ptr_share;
+ TALLOC_CTX *_mem_save_share_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_dfs_StorageState(ndr, NDR_SCALARS, &r->state));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server));
+ if (_ptr_server) {
+ NDR_PULL_ALLOC(ndr, r->server);
+ } else {
+ r->server = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_share));
+ if (_ptr_share) {
+ NDR_PULL_ALLOC(ndr, r->share);
+ } else {
+ r->share = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->server) {
+ _mem_save_server_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->server, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->server));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->server));
+ if (ndr_get_array_length(ndr, &r->server) > ndr_get_array_size(ndr, &r->server)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->server), ndr_get_array_length(ndr, &r->server));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->server), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->server, ndr_get_array_length(ndr, &r->server), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_0, 0);
+ }
+ if (r->share) {
+ _mem_save_share_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->share, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->share));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->share));
+ if (ndr_get_array_length(ndr, &r->share) > ndr_get_array_size(ndr, &r->share)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->share), ndr_get_array_length(ndr, &r->share));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->share), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->share, ndr_get_array_length(ndr, &r->share), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_share_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_StorageInfo(struct ndr_print *ndr, const char *name, const struct dfs_StorageInfo *r)
+{
+ ndr_print_struct(ndr, name, "dfs_StorageInfo");
+ ndr->depth++;
+ ndr_print_dfs_StorageState(ndr, "state", r->state);
+ ndr_print_ptr(ndr, "server", r->server);
+ ndr->depth++;
+ if (r->server) {
+ ndr_print_string(ndr, "server", r->server);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "share", r->share);
+ ndr->depth++;
+ if (r->share) {
+ ndr_print_string(ndr, "share", r->share);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Info3(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info3 *r)
+{
+ uint32_t cntr_stores_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->path));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->comment));
+ NDR_CHECK(ndr_push_dfs_VolumeState(ndr, NDR_SCALARS, r->state));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_stores));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->stores));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->path) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->path, ndr_charset_length(r->path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->comment) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->comment, ndr_charset_length(r->comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->stores) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_stores));
+ for (cntr_stores_1 = 0; cntr_stores_1 < r->num_stores; cntr_stores_1++) {
+ NDR_CHECK(ndr_push_dfs_StorageInfo(ndr, NDR_SCALARS, &r->stores[cntr_stores_1]));
+ }
+ for (cntr_stores_1 = 0; cntr_stores_1 < r->num_stores; cntr_stores_1++) {
+ NDR_CHECK(ndr_push_dfs_StorageInfo(ndr, NDR_BUFFERS, &r->stores[cntr_stores_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info3(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info3 *r)
+{
+ uint32_t _ptr_path;
+ TALLOC_CTX *_mem_save_path_0;
+ uint32_t _ptr_comment;
+ TALLOC_CTX *_mem_save_comment_0;
+ uint32_t _ptr_stores;
+ uint32_t cntr_stores_1;
+ TALLOC_CTX *_mem_save_stores_0;
+ TALLOC_CTX *_mem_save_stores_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_path));
+ if (_ptr_path) {
+ NDR_PULL_ALLOC(ndr, r->path);
+ } else {
+ r->path = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_comment));
+ if (_ptr_comment) {
+ NDR_PULL_ALLOC(ndr, r->comment);
+ } else {
+ r->comment = NULL;
+ }
+ NDR_CHECK(ndr_pull_dfs_VolumeState(ndr, NDR_SCALARS, &r->state));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_stores));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_stores));
+ if (_ptr_stores) {
+ NDR_PULL_ALLOC(ndr, r->stores);
+ } else {
+ r->stores = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->path) {
+ _mem_save_path_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->path, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->path));
+ if (ndr_get_array_length(ndr, &r->path) > ndr_get_array_size(ndr, &r->path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->path), ndr_get_array_length(ndr, &r->path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->path, ndr_get_array_length(ndr, &r->path), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_path_0, 0);
+ }
+ if (r->comment) {
+ _mem_save_comment_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->comment, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->comment));
+ if (ndr_get_array_length(ndr, &r->comment) > ndr_get_array_size(ndr, &r->comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->comment), ndr_get_array_length(ndr, &r->comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->comment, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_comment_0, 0);
+ }
+ if (r->stores) {
+ _mem_save_stores_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->stores, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->stores));
+ NDR_PULL_ALLOC_N(ndr, r->stores, ndr_get_array_size(ndr, &r->stores));
+ _mem_save_stores_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->stores, 0);
+ for (cntr_stores_1 = 0; cntr_stores_1 < r->num_stores; cntr_stores_1++) {
+ NDR_CHECK(ndr_pull_dfs_StorageInfo(ndr, NDR_SCALARS, &r->stores[cntr_stores_1]));
+ }
+ for (cntr_stores_1 = 0; cntr_stores_1 < r->num_stores; cntr_stores_1++) {
+ NDR_CHECK(ndr_pull_dfs_StorageInfo(ndr, NDR_BUFFERS, &r->stores[cntr_stores_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_stores_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_stores_0, 0);
+ }
+ if (r->stores) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->stores, r->num_stores));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info3(struct ndr_print *ndr, const char *name, const struct dfs_Info3 *r)
+{
+ uint32_t cntr_stores_1;
+ ndr_print_struct(ndr, name, "dfs_Info3");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "path", r->path);
+ ndr->depth++;
+ if (r->path) {
+ ndr_print_string(ndr, "path", r->path);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "comment", r->comment);
+ ndr->depth++;
+ if (r->comment) {
+ ndr_print_string(ndr, "comment", r->comment);
+ }
+ ndr->depth--;
+ ndr_print_dfs_VolumeState(ndr, "state", r->state);
+ ndr_print_uint32(ndr, "num_stores", r->num_stores);
+ ndr_print_ptr(ndr, "stores", r->stores);
+ ndr->depth++;
+ if (r->stores) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "stores", (int)r->num_stores);
+ ndr->depth++;
+ for (cntr_stores_1=0;cntr_stores_1<r->num_stores;cntr_stores_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_stores_1) != -1) {
+ ndr_print_dfs_StorageInfo(ndr, "stores", &r->stores[cntr_stores_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Info4(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info4 *r)
+{
+ uint32_t cntr_stores_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->path));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->comment));
+ NDR_CHECK(ndr_push_dfs_VolumeState(ndr, NDR_SCALARS, r->state));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->timeout));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->guid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_stores));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->stores));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->path) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->path, ndr_charset_length(r->path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->comment) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->comment, ndr_charset_length(r->comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_BUFFERS, &r->guid));
+ if (r->stores) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_stores));
+ for (cntr_stores_1 = 0; cntr_stores_1 < r->num_stores; cntr_stores_1++) {
+ NDR_CHECK(ndr_push_dfs_StorageInfo(ndr, NDR_SCALARS, &r->stores[cntr_stores_1]));
+ }
+ for (cntr_stores_1 = 0; cntr_stores_1 < r->num_stores; cntr_stores_1++) {
+ NDR_CHECK(ndr_push_dfs_StorageInfo(ndr, NDR_BUFFERS, &r->stores[cntr_stores_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info4(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info4 *r)
+{
+ uint32_t _ptr_path;
+ TALLOC_CTX *_mem_save_path_0;
+ uint32_t _ptr_comment;
+ TALLOC_CTX *_mem_save_comment_0;
+ uint32_t _ptr_stores;
+ uint32_t cntr_stores_1;
+ TALLOC_CTX *_mem_save_stores_0;
+ TALLOC_CTX *_mem_save_stores_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_path));
+ if (_ptr_path) {
+ NDR_PULL_ALLOC(ndr, r->path);
+ } else {
+ r->path = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_comment));
+ if (_ptr_comment) {
+ NDR_PULL_ALLOC(ndr, r->comment);
+ } else {
+ r->comment = NULL;
+ }
+ NDR_CHECK(ndr_pull_dfs_VolumeState(ndr, NDR_SCALARS, &r->state));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->timeout));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->guid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_stores));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_stores));
+ if (_ptr_stores) {
+ NDR_PULL_ALLOC(ndr, r->stores);
+ } else {
+ r->stores = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->path) {
+ _mem_save_path_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->path, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->path));
+ if (ndr_get_array_length(ndr, &r->path) > ndr_get_array_size(ndr, &r->path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->path), ndr_get_array_length(ndr, &r->path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->path, ndr_get_array_length(ndr, &r->path), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_path_0, 0);
+ }
+ if (r->comment) {
+ _mem_save_comment_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->comment, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->comment));
+ if (ndr_get_array_length(ndr, &r->comment) > ndr_get_array_size(ndr, &r->comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->comment), ndr_get_array_length(ndr, &r->comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->comment, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_comment_0, 0);
+ }
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_BUFFERS, &r->guid));
+ if (r->stores) {
+ _mem_save_stores_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->stores, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->stores));
+ NDR_PULL_ALLOC_N(ndr, r->stores, ndr_get_array_size(ndr, &r->stores));
+ _mem_save_stores_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->stores, 0);
+ for (cntr_stores_1 = 0; cntr_stores_1 < r->num_stores; cntr_stores_1++) {
+ NDR_CHECK(ndr_pull_dfs_StorageInfo(ndr, NDR_SCALARS, &r->stores[cntr_stores_1]));
+ }
+ for (cntr_stores_1 = 0; cntr_stores_1 < r->num_stores; cntr_stores_1++) {
+ NDR_CHECK(ndr_pull_dfs_StorageInfo(ndr, NDR_BUFFERS, &r->stores[cntr_stores_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_stores_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_stores_0, 0);
+ }
+ if (r->stores) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->stores, r->num_stores));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info4(struct ndr_print *ndr, const char *name, const struct dfs_Info4 *r)
+{
+ uint32_t cntr_stores_1;
+ ndr_print_struct(ndr, name, "dfs_Info4");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "path", r->path);
+ ndr->depth++;
+ if (r->path) {
+ ndr_print_string(ndr, "path", r->path);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "comment", r->comment);
+ ndr->depth++;
+ if (r->comment) {
+ ndr_print_string(ndr, "comment", r->comment);
+ }
+ ndr->depth--;
+ ndr_print_dfs_VolumeState(ndr, "state", r->state);
+ ndr_print_uint32(ndr, "timeout", r->timeout);
+ ndr_print_GUID(ndr, "guid", &r->guid);
+ ndr_print_uint32(ndr, "num_stores", r->num_stores);
+ ndr_print_ptr(ndr, "stores", r->stores);
+ ndr->depth++;
+ if (r->stores) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "stores", (int)r->num_stores);
+ ndr->depth++;
+ for (cntr_stores_1=0;cntr_stores_1<r->num_stores;cntr_stores_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_stores_1) != -1) {
+ ndr_print_dfs_StorageInfo(ndr, "stores", &r->stores[cntr_stores_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_dfs_PropertyFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_dfs_PropertyFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_PropertyFlags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DFS_PROPERTY_FLAG_INSITE_REFERRALS", DFS_PROPERTY_FLAG_INSITE_REFERRALS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DFS_PROPERTY_FLAG_ROOT_SCALABILITY", DFS_PROPERTY_FLAG_ROOT_SCALABILITY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DFS_PROPERTY_FLAG_SITE_COSTING", DFS_PROPERTY_FLAG_SITE_COSTING, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DFS_PROPERTY_FLAG_TARGET_FAILBACK", DFS_PROPERTY_FLAG_TARGET_FAILBACK, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DFS_PROPERTY_FLAG_CLUSTER_ENABLED", DFS_PROPERTY_FLAG_CLUSTER_ENABLED, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Info5(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info5 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->path));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->comment));
+ NDR_CHECK(ndr_push_dfs_VolumeState(ndr, NDR_SCALARS, r->state));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->timeout));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->guid));
+ NDR_CHECK(ndr_push_dfs_PropertyFlags(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pktsize));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_stores));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->path) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->path, ndr_charset_length(r->path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->comment) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->comment, ndr_charset_length(r->comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_BUFFERS, &r->guid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info5(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info5 *r)
+{
+ uint32_t _ptr_path;
+ TALLOC_CTX *_mem_save_path_0;
+ uint32_t _ptr_comment;
+ TALLOC_CTX *_mem_save_comment_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_path));
+ if (_ptr_path) {
+ NDR_PULL_ALLOC(ndr, r->path);
+ } else {
+ r->path = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_comment));
+ if (_ptr_comment) {
+ NDR_PULL_ALLOC(ndr, r->comment);
+ } else {
+ r->comment = NULL;
+ }
+ NDR_CHECK(ndr_pull_dfs_VolumeState(ndr, NDR_SCALARS, &r->state));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->timeout));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->guid));
+ NDR_CHECK(ndr_pull_dfs_PropertyFlags(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pktsize));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_stores));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->path) {
+ _mem_save_path_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->path, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->path));
+ if (ndr_get_array_length(ndr, &r->path) > ndr_get_array_size(ndr, &r->path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->path), ndr_get_array_length(ndr, &r->path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->path, ndr_get_array_length(ndr, &r->path), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_path_0, 0);
+ }
+ if (r->comment) {
+ _mem_save_comment_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->comment, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->comment));
+ if (ndr_get_array_length(ndr, &r->comment) > ndr_get_array_size(ndr, &r->comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->comment), ndr_get_array_length(ndr, &r->comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->comment, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_comment_0, 0);
+ }
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_BUFFERS, &r->guid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info5(struct ndr_print *ndr, const char *name, const struct dfs_Info5 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Info5");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "path", r->path);
+ ndr->depth++;
+ if (r->path) {
+ ndr_print_string(ndr, "path", r->path);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "comment", r->comment);
+ ndr->depth++;
+ if (r->comment) {
+ ndr_print_string(ndr, "comment", r->comment);
+ }
+ ndr->depth--;
+ ndr_print_dfs_VolumeState(ndr, "state", r->state);
+ ndr_print_uint32(ndr, "timeout", r->timeout);
+ ndr_print_GUID(ndr, "guid", &r->guid);
+ ndr_print_dfs_PropertyFlags(ndr, "flags", r->flags);
+ ndr_print_uint32(ndr, "pktsize", r->pktsize);
+ ndr_print_uint32(ndr, "num_stores", r->num_stores);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Target_PriorityClass(struct ndr_push *ndr, int ndr_flags, enum dfs_Target_PriorityClass r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Target_PriorityClass(struct ndr_pull *ndr, int ndr_flags, enum dfs_Target_PriorityClass *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Target_PriorityClass(struct ndr_print *ndr, const char *name, enum dfs_Target_PriorityClass r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DFS_INVALID_PRIORITY_CLASS: val = "DFS_INVALID_PRIORITY_CLASS"; break;
+ case DFS_SITE_COST_NORMAL_PRIORITY_CLASS: val = "DFS_SITE_COST_NORMAL_PRIORITY_CLASS"; break;
+ case DFS_GLOBAL_HIGH_PRIORITY_CLASS: val = "DFS_GLOBAL_HIGH_PRIORITY_CLASS"; break;
+ case DFS_SITE_COST_HIGH_PRIORITY_CLASS: val = "DFS_SITE_COST_HIGH_PRIORITY_CLASS"; break;
+ case DFS_SITE_COST_LOW_PRIORITY_CLASS: val = "DFS_SITE_COST_LOW_PRIORITY_CLASS"; break;
+ case DFS_GLOBAL_LOW_PRIORITY_CLASS: val = "DFS_GLOBAL_LOW_PRIORITY_CLASS"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_dfs_Target_Priority(struct ndr_push *ndr, int ndr_flags, const struct dfs_Target_Priority *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_dfs_Target_PriorityClass(ndr, NDR_SCALARS, r->target_priority_class));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->target_priority_rank));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->reserved));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Target_Priority(struct ndr_pull *ndr, int ndr_flags, struct dfs_Target_Priority *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_dfs_Target_PriorityClass(ndr, NDR_SCALARS, &r->target_priority_class));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->target_priority_rank));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->reserved));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Target_Priority(struct ndr_print *ndr, const char *name, const struct dfs_Target_Priority *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Target_Priority");
+ ndr->depth++;
+ ndr_print_dfs_Target_PriorityClass(ndr, "target_priority_class", r->target_priority_class);
+ ndr_print_uint16(ndr, "target_priority_rank", r->target_priority_rank);
+ ndr_print_uint16(ndr, "reserved", r->reserved);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_StorageInfo2(struct ndr_push *ndr, int ndr_flags, const struct dfs_StorageInfo2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_dfs_StorageInfo(ndr, NDR_SCALARS, &r->info));
+ NDR_CHECK(ndr_push_dfs_Target_Priority(ndr, NDR_SCALARS, &r->target_priority));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_dfs_StorageInfo(ndr, NDR_BUFFERS, &r->info));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_StorageInfo2(struct ndr_pull *ndr, int ndr_flags, struct dfs_StorageInfo2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_dfs_StorageInfo(ndr, NDR_SCALARS, &r->info));
+ NDR_CHECK(ndr_pull_dfs_Target_Priority(ndr, NDR_SCALARS, &r->target_priority));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_dfs_StorageInfo(ndr, NDR_BUFFERS, &r->info));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_StorageInfo2(struct ndr_print *ndr, const char *name, const struct dfs_StorageInfo2 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_StorageInfo2");
+ ndr->depth++;
+ ndr_print_dfs_StorageInfo(ndr, "info", &r->info);
+ ndr_print_dfs_Target_Priority(ndr, "target_priority", &r->target_priority);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Info6(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info6 *r)
+{
+ uint32_t cntr_stores_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->entry_path));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->comment));
+ NDR_CHECK(ndr_push_dfs_VolumeState(ndr, NDR_SCALARS, r->state));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->timeout));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->guid));
+ NDR_CHECK(ndr_push_dfs_PropertyFlags(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pktsize));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->num_stores));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->stores));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->entry_path) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->entry_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->entry_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->entry_path, ndr_charset_length(r->entry_path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->comment) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->comment, ndr_charset_length(r->comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_BUFFERS, &r->guid));
+ if (r->stores) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_stores));
+ for (cntr_stores_1 = 0; cntr_stores_1 < r->num_stores; cntr_stores_1++) {
+ NDR_CHECK(ndr_push_dfs_StorageInfo2(ndr, NDR_SCALARS, &r->stores[cntr_stores_1]));
+ }
+ for (cntr_stores_1 = 0; cntr_stores_1 < r->num_stores; cntr_stores_1++) {
+ NDR_CHECK(ndr_push_dfs_StorageInfo2(ndr, NDR_BUFFERS, &r->stores[cntr_stores_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info6(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info6 *r)
+{
+ uint32_t _ptr_entry_path;
+ TALLOC_CTX *_mem_save_entry_path_0;
+ uint32_t _ptr_comment;
+ TALLOC_CTX *_mem_save_comment_0;
+ uint32_t _ptr_stores;
+ uint32_t cntr_stores_1;
+ TALLOC_CTX *_mem_save_stores_0;
+ TALLOC_CTX *_mem_save_stores_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_entry_path));
+ if (_ptr_entry_path) {
+ NDR_PULL_ALLOC(ndr, r->entry_path);
+ } else {
+ r->entry_path = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_comment));
+ if (_ptr_comment) {
+ NDR_PULL_ALLOC(ndr, r->comment);
+ } else {
+ r->comment = NULL;
+ }
+ NDR_CHECK(ndr_pull_dfs_VolumeState(ndr, NDR_SCALARS, &r->state));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->timeout));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->guid));
+ NDR_CHECK(ndr_pull_dfs_PropertyFlags(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pktsize));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->num_stores));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_stores));
+ if (_ptr_stores) {
+ NDR_PULL_ALLOC(ndr, r->stores);
+ } else {
+ r->stores = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->entry_path) {
+ _mem_save_entry_path_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->entry_path, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->entry_path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->entry_path));
+ if (ndr_get_array_length(ndr, &r->entry_path) > ndr_get_array_size(ndr, &r->entry_path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->entry_path), ndr_get_array_length(ndr, &r->entry_path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->entry_path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->entry_path, ndr_get_array_length(ndr, &r->entry_path), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entry_path_0, 0);
+ }
+ if (r->comment) {
+ _mem_save_comment_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->comment, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->comment));
+ if (ndr_get_array_length(ndr, &r->comment) > ndr_get_array_size(ndr, &r->comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->comment), ndr_get_array_length(ndr, &r->comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->comment, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_comment_0, 0);
+ }
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_BUFFERS, &r->guid));
+ if (r->stores) {
+ _mem_save_stores_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->stores, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->stores));
+ NDR_PULL_ALLOC_N(ndr, r->stores, ndr_get_array_size(ndr, &r->stores));
+ _mem_save_stores_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->stores, 0);
+ for (cntr_stores_1 = 0; cntr_stores_1 < r->num_stores; cntr_stores_1++) {
+ NDR_CHECK(ndr_pull_dfs_StorageInfo2(ndr, NDR_SCALARS, &r->stores[cntr_stores_1]));
+ }
+ for (cntr_stores_1 = 0; cntr_stores_1 < r->num_stores; cntr_stores_1++) {
+ NDR_CHECK(ndr_pull_dfs_StorageInfo2(ndr, NDR_BUFFERS, &r->stores[cntr_stores_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_stores_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_stores_0, 0);
+ }
+ if (r->stores) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->stores, r->num_stores));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info6(struct ndr_print *ndr, const char *name, const struct dfs_Info6 *r)
+{
+ uint32_t cntr_stores_1;
+ ndr_print_struct(ndr, name, "dfs_Info6");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "entry_path", r->entry_path);
+ ndr->depth++;
+ if (r->entry_path) {
+ ndr_print_string(ndr, "entry_path", r->entry_path);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "comment", r->comment);
+ ndr->depth++;
+ if (r->comment) {
+ ndr_print_string(ndr, "comment", r->comment);
+ }
+ ndr->depth--;
+ ndr_print_dfs_VolumeState(ndr, "state", r->state);
+ ndr_print_uint32(ndr, "timeout", r->timeout);
+ ndr_print_GUID(ndr, "guid", &r->guid);
+ ndr_print_dfs_PropertyFlags(ndr, "flags", r->flags);
+ ndr_print_uint32(ndr, "pktsize", r->pktsize);
+ ndr_print_uint16(ndr, "num_stores", r->num_stores);
+ ndr_print_ptr(ndr, "stores", r->stores);
+ ndr->depth++;
+ if (r->stores) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "stores", (int)r->num_stores);
+ ndr->depth++;
+ for (cntr_stores_1=0;cntr_stores_1<r->num_stores;cntr_stores_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_stores_1) != -1) {
+ ndr_print_dfs_StorageInfo2(ndr, "stores", &r->stores[cntr_stores_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Info7(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info7 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->generation_guid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_BUFFERS, &r->generation_guid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info7(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info7 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->generation_guid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_BUFFERS, &r->generation_guid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info7(struct ndr_print *ndr, const char *name, const struct dfs_Info7 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Info7");
+ ndr->depth++;
+ ndr_print_GUID(ndr, "generation_guid", &r->generation_guid);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Info100(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info100 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->comment) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->comment, ndr_charset_length(r->comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info100(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info100 *r)
+{
+ uint32_t _ptr_comment;
+ TALLOC_CTX *_mem_save_comment_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_comment));
+ if (_ptr_comment) {
+ NDR_PULL_ALLOC(ndr, r->comment);
+ } else {
+ r->comment = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->comment) {
+ _mem_save_comment_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->comment, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->comment));
+ if (ndr_get_array_length(ndr, &r->comment) > ndr_get_array_size(ndr, &r->comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->comment), ndr_get_array_length(ndr, &r->comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->comment, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_comment_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info100(struct ndr_print *ndr, const char *name, const struct dfs_Info100 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Info100");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "comment", r->comment);
+ ndr->depth++;
+ if (r->comment) {
+ ndr_print_string(ndr, "comment", r->comment);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Info101(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info101 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_dfs_StorageState(ndr, NDR_SCALARS, r->state));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info101(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info101 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_dfs_StorageState(ndr, NDR_SCALARS, &r->state));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info101(struct ndr_print *ndr, const char *name, const struct dfs_Info101 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Info101");
+ ndr->depth++;
+ ndr_print_dfs_StorageState(ndr, "state", r->state);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Info102(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info102 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->timeout));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info102(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info102 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->timeout));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info102(struct ndr_print *ndr, const char *name, const struct dfs_Info102 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Info102");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "timeout", r->timeout);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Info103(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info103 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_dfs_PropertyFlags(ndr, NDR_SCALARS, r->flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info103(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info103 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_dfs_PropertyFlags(ndr, NDR_SCALARS, &r->flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info103(struct ndr_print *ndr, const char *name, const struct dfs_Info103 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Info103");
+ ndr->depth++;
+ ndr_print_dfs_PropertyFlags(ndr, "flags", r->flags);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Info104(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info104 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_dfs_Target_Priority(ndr, NDR_SCALARS, &r->priority));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info104(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info104 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_dfs_Target_Priority(ndr, NDR_SCALARS, &r->priority));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info104(struct ndr_print *ndr, const char *name, const struct dfs_Info104 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Info104");
+ ndr->depth++;
+ ndr_print_dfs_Target_Priority(ndr, "priority", &r->priority);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Info105(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info105 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->comment));
+ NDR_CHECK(ndr_push_dfs_VolumeState(ndr, NDR_SCALARS, r->state));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->timeout));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->property_flag_mask));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->property_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->comment) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->comment, ndr_charset_length(r->comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info105(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info105 *r)
+{
+ uint32_t _ptr_comment;
+ TALLOC_CTX *_mem_save_comment_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_comment));
+ if (_ptr_comment) {
+ NDR_PULL_ALLOC(ndr, r->comment);
+ } else {
+ r->comment = NULL;
+ }
+ NDR_CHECK(ndr_pull_dfs_VolumeState(ndr, NDR_SCALARS, &r->state));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->timeout));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->property_flag_mask));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->property_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->comment) {
+ _mem_save_comment_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->comment, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->comment));
+ if (ndr_get_array_length(ndr, &r->comment) > ndr_get_array_size(ndr, &r->comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->comment), ndr_get_array_length(ndr, &r->comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->comment, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_comment_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info105(struct ndr_print *ndr, const char *name, const struct dfs_Info105 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Info105");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "comment", r->comment);
+ ndr->depth++;
+ if (r->comment) {
+ ndr_print_string(ndr, "comment", r->comment);
+ }
+ ndr->depth--;
+ ndr_print_dfs_VolumeState(ndr, "state", r->state);
+ ndr_print_uint32(ndr, "timeout", r->timeout);
+ ndr_print_uint32(ndr, "property_flag_mask", r->property_flag_mask);
+ ndr_print_uint32(ndr, "property_flags", r->property_flags);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Info106(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info106 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_dfs_StorageState(ndr, NDR_SCALARS, r->state));
+ NDR_CHECK(ndr_push_dfs_Target_Priority(ndr, NDR_SCALARS, &r->priority));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info106(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info106 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_dfs_StorageState(ndr, NDR_SCALARS, &r->state));
+ NDR_CHECK(ndr_pull_dfs_Target_Priority(ndr, NDR_SCALARS, &r->priority));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info106(struct ndr_print *ndr, const char *name, const struct dfs_Info106 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Info106");
+ ndr->depth++;
+ ndr_print_dfs_StorageState(ndr, "state", r->state);
+ ndr_print_dfs_Target_Priority(ndr, "priority", &r->priority);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Info200(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info200 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->dom_root));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->dom_root) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dom_root, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dom_root, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dom_root, ndr_charset_length(r->dom_root, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info200(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info200 *r)
+{
+ uint32_t _ptr_dom_root;
+ TALLOC_CTX *_mem_save_dom_root_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dom_root));
+ if (_ptr_dom_root) {
+ NDR_PULL_ALLOC(ndr, r->dom_root);
+ } else {
+ r->dom_root = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->dom_root) {
+ _mem_save_dom_root_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->dom_root, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->dom_root));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->dom_root));
+ if (ndr_get_array_length(ndr, &r->dom_root) > ndr_get_array_size(ndr, &r->dom_root)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->dom_root), ndr_get_array_length(ndr, &r->dom_root));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->dom_root), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dom_root, ndr_get_array_length(ndr, &r->dom_root), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dom_root_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info200(struct ndr_print *ndr, const char *name, const struct dfs_Info200 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Info200");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "dom_root", r->dom_root);
+ ndr->depth++;
+ if (r->dom_root) {
+ ndr_print_string(ndr, "dom_root", r->dom_root);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_VolumeFlavor(struct ndr_push *ndr, int ndr_flags, enum dfs_VolumeFlavor r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_VolumeFlavor(struct ndr_pull *ndr, int ndr_flags, enum dfs_VolumeFlavor *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_VolumeFlavor(struct ndr_print *ndr, const char *name, enum dfs_VolumeFlavor r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DFS_VOLUME_FLAVOR_STANDALONE: val = "DFS_VOLUME_FLAVOR_STANDALONE"; break;
+ case DFS_VOLUME_FLAVOR_AD_BLOB: val = "DFS_VOLUME_FLAVOR_AD_BLOB"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_dfs_Info300(struct ndr_push *ndr, int ndr_flags, const struct dfs_Info300 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_dfs_VolumeFlavor(ndr, NDR_SCALARS, r->flavor));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->dom_root));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->dom_root) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dom_root, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dom_root, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dom_root, ndr_charset_length(r->dom_root, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info300(struct ndr_pull *ndr, int ndr_flags, struct dfs_Info300 *r)
+{
+ uint32_t _ptr_dom_root;
+ TALLOC_CTX *_mem_save_dom_root_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_dfs_VolumeFlavor(ndr, NDR_SCALARS, &r->flavor));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dom_root));
+ if (_ptr_dom_root) {
+ NDR_PULL_ALLOC(ndr, r->dom_root);
+ } else {
+ r->dom_root = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->dom_root) {
+ _mem_save_dom_root_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->dom_root, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->dom_root));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->dom_root));
+ if (ndr_get_array_length(ndr, &r->dom_root) > ndr_get_array_size(ndr, &r->dom_root)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->dom_root), ndr_get_array_length(ndr, &r->dom_root));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->dom_root), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dom_root, ndr_get_array_length(ndr, &r->dom_root), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dom_root_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info300(struct ndr_print *ndr, const char *name, const struct dfs_Info300 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Info300");
+ ndr->depth++;
+ ndr_print_dfs_VolumeFlavor(ndr, "flavor", r->flavor);
+ ndr_print_ptr(ndr, "dom_root", r->dom_root);
+ ndr->depth++;
+ if (r->dom_root) {
+ ndr_print_string(ndr, "dom_root", r->dom_root);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Info(struct ndr_push *ndr, int ndr_flags, const union dfs_Info *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info0));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info3));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info4));
+ break; }
+
+ case 5: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info5));
+ break; }
+
+ case 6: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info6));
+ break; }
+
+ case 7: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info7));
+ break; }
+
+ case 100: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info100));
+ break; }
+
+ case 101: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info101));
+ break; }
+
+ case 102: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info102));
+ break; }
+
+ case 103: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info103));
+ break; }
+
+ case 104: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info104));
+ break; }
+
+ case 105: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info105));
+ break; }
+
+ case 106: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info106));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ if (r->info0) {
+ NDR_CHECK(ndr_push_dfs_Info0(ndr, NDR_SCALARS, r->info0));
+ }
+ break;
+
+ case 1:
+ if (r->info1) {
+ NDR_CHECK(ndr_push_dfs_Info1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ }
+ break;
+
+ case 2:
+ if (r->info2) {
+ NDR_CHECK(ndr_push_dfs_Info2(ndr, NDR_SCALARS|NDR_BUFFERS, r->info2));
+ }
+ break;
+
+ case 3:
+ if (r->info3) {
+ NDR_CHECK(ndr_push_dfs_Info3(ndr, NDR_SCALARS|NDR_BUFFERS, r->info3));
+ }
+ break;
+
+ case 4:
+ if (r->info4) {
+ NDR_CHECK(ndr_push_dfs_Info4(ndr, NDR_SCALARS|NDR_BUFFERS, r->info4));
+ }
+ break;
+
+ case 5:
+ if (r->info5) {
+ NDR_CHECK(ndr_push_dfs_Info5(ndr, NDR_SCALARS|NDR_BUFFERS, r->info5));
+ }
+ break;
+
+ case 6:
+ if (r->info6) {
+ NDR_CHECK(ndr_push_dfs_Info6(ndr, NDR_SCALARS|NDR_BUFFERS, r->info6));
+ }
+ break;
+
+ case 7:
+ if (r->info7) {
+ NDR_CHECK(ndr_push_dfs_Info7(ndr, NDR_SCALARS|NDR_BUFFERS, r->info7));
+ }
+ break;
+
+ case 100:
+ if (r->info100) {
+ NDR_CHECK(ndr_push_dfs_Info100(ndr, NDR_SCALARS|NDR_BUFFERS, r->info100));
+ }
+ break;
+
+ case 101:
+ if (r->info101) {
+ NDR_CHECK(ndr_push_dfs_Info101(ndr, NDR_SCALARS, r->info101));
+ }
+ break;
+
+ case 102:
+ if (r->info102) {
+ NDR_CHECK(ndr_push_dfs_Info102(ndr, NDR_SCALARS, r->info102));
+ }
+ break;
+
+ case 103:
+ if (r->info103) {
+ NDR_CHECK(ndr_push_dfs_Info103(ndr, NDR_SCALARS, r->info103));
+ }
+ break;
+
+ case 104:
+ if (r->info104) {
+ NDR_CHECK(ndr_push_dfs_Info104(ndr, NDR_SCALARS, r->info104));
+ }
+ break;
+
+ case 105:
+ if (r->info105) {
+ NDR_CHECK(ndr_push_dfs_Info105(ndr, NDR_SCALARS|NDR_BUFFERS, r->info105));
+ }
+ break;
+
+ case 106:
+ if (r->info106) {
+ NDR_CHECK(ndr_push_dfs_Info106(ndr, NDR_SCALARS, r->info106));
+ }
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Info(struct ndr_pull *ndr, int ndr_flags, union dfs_Info *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_info0_0;
+ TALLOC_CTX *_mem_save_info1_0;
+ TALLOC_CTX *_mem_save_info2_0;
+ TALLOC_CTX *_mem_save_info3_0;
+ TALLOC_CTX *_mem_save_info4_0;
+ TALLOC_CTX *_mem_save_info5_0;
+ TALLOC_CTX *_mem_save_info6_0;
+ TALLOC_CTX *_mem_save_info7_0;
+ TALLOC_CTX *_mem_save_info100_0;
+ TALLOC_CTX *_mem_save_info101_0;
+ TALLOC_CTX *_mem_save_info102_0;
+ TALLOC_CTX *_mem_save_info103_0;
+ TALLOC_CTX *_mem_save_info104_0;
+ TALLOC_CTX *_mem_save_info105_0;
+ TALLOC_CTX *_mem_save_info106_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 0: {
+ uint32_t _ptr_info0;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info0));
+ if (_ptr_info0) {
+ NDR_PULL_ALLOC(ndr, r->info0);
+ } else {
+ r->info0 = NULL;
+ }
+ break; }
+
+ case 1: {
+ uint32_t _ptr_info1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1));
+ if (_ptr_info1) {
+ NDR_PULL_ALLOC(ndr, r->info1);
+ } else {
+ r->info1 = NULL;
+ }
+ break; }
+
+ case 2: {
+ uint32_t _ptr_info2;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info2));
+ if (_ptr_info2) {
+ NDR_PULL_ALLOC(ndr, r->info2);
+ } else {
+ r->info2 = NULL;
+ }
+ break; }
+
+ case 3: {
+ uint32_t _ptr_info3;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info3));
+ if (_ptr_info3) {
+ NDR_PULL_ALLOC(ndr, r->info3);
+ } else {
+ r->info3 = NULL;
+ }
+ break; }
+
+ case 4: {
+ uint32_t _ptr_info4;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info4));
+ if (_ptr_info4) {
+ NDR_PULL_ALLOC(ndr, r->info4);
+ } else {
+ r->info4 = NULL;
+ }
+ break; }
+
+ case 5: {
+ uint32_t _ptr_info5;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info5));
+ if (_ptr_info5) {
+ NDR_PULL_ALLOC(ndr, r->info5);
+ } else {
+ r->info5 = NULL;
+ }
+ break; }
+
+ case 6: {
+ uint32_t _ptr_info6;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info6));
+ if (_ptr_info6) {
+ NDR_PULL_ALLOC(ndr, r->info6);
+ } else {
+ r->info6 = NULL;
+ }
+ break; }
+
+ case 7: {
+ uint32_t _ptr_info7;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info7));
+ if (_ptr_info7) {
+ NDR_PULL_ALLOC(ndr, r->info7);
+ } else {
+ r->info7 = NULL;
+ }
+ break; }
+
+ case 100: {
+ uint32_t _ptr_info100;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info100));
+ if (_ptr_info100) {
+ NDR_PULL_ALLOC(ndr, r->info100);
+ } else {
+ r->info100 = NULL;
+ }
+ break; }
+
+ case 101: {
+ uint32_t _ptr_info101;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info101));
+ if (_ptr_info101) {
+ NDR_PULL_ALLOC(ndr, r->info101);
+ } else {
+ r->info101 = NULL;
+ }
+ break; }
+
+ case 102: {
+ uint32_t _ptr_info102;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info102));
+ if (_ptr_info102) {
+ NDR_PULL_ALLOC(ndr, r->info102);
+ } else {
+ r->info102 = NULL;
+ }
+ break; }
+
+ case 103: {
+ uint32_t _ptr_info103;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info103));
+ if (_ptr_info103) {
+ NDR_PULL_ALLOC(ndr, r->info103);
+ } else {
+ r->info103 = NULL;
+ }
+ break; }
+
+ case 104: {
+ uint32_t _ptr_info104;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info104));
+ if (_ptr_info104) {
+ NDR_PULL_ALLOC(ndr, r->info104);
+ } else {
+ r->info104 = NULL;
+ }
+ break; }
+
+ case 105: {
+ uint32_t _ptr_info105;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info105));
+ if (_ptr_info105) {
+ NDR_PULL_ALLOC(ndr, r->info105);
+ } else {
+ r->info105 = NULL;
+ }
+ break; }
+
+ case 106: {
+ uint32_t _ptr_info106;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info106));
+ if (_ptr_info106) {
+ NDR_PULL_ALLOC(ndr, r->info106);
+ } else {
+ r->info106 = NULL;
+ }
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ if (r->info0) {
+ _mem_save_info0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info0, 0);
+ NDR_CHECK(ndr_pull_dfs_Info0(ndr, NDR_SCALARS, r->info0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info0_0, 0);
+ }
+ break;
+
+ case 1:
+ if (r->info1) {
+ _mem_save_info1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1, 0);
+ NDR_CHECK(ndr_pull_dfs_Info1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1_0, 0);
+ }
+ break;
+
+ case 2:
+ if (r->info2) {
+ _mem_save_info2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info2, 0);
+ NDR_CHECK(ndr_pull_dfs_Info2(ndr, NDR_SCALARS|NDR_BUFFERS, r->info2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info2_0, 0);
+ }
+ break;
+
+ case 3:
+ if (r->info3) {
+ _mem_save_info3_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info3, 0);
+ NDR_CHECK(ndr_pull_dfs_Info3(ndr, NDR_SCALARS|NDR_BUFFERS, r->info3));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info3_0, 0);
+ }
+ break;
+
+ case 4:
+ if (r->info4) {
+ _mem_save_info4_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info4, 0);
+ NDR_CHECK(ndr_pull_dfs_Info4(ndr, NDR_SCALARS|NDR_BUFFERS, r->info4));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info4_0, 0);
+ }
+ break;
+
+ case 5:
+ if (r->info5) {
+ _mem_save_info5_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info5, 0);
+ NDR_CHECK(ndr_pull_dfs_Info5(ndr, NDR_SCALARS|NDR_BUFFERS, r->info5));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info5_0, 0);
+ }
+ break;
+
+ case 6:
+ if (r->info6) {
+ _mem_save_info6_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info6, 0);
+ NDR_CHECK(ndr_pull_dfs_Info6(ndr, NDR_SCALARS|NDR_BUFFERS, r->info6));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info6_0, 0);
+ }
+ break;
+
+ case 7:
+ if (r->info7) {
+ _mem_save_info7_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info7, 0);
+ NDR_CHECK(ndr_pull_dfs_Info7(ndr, NDR_SCALARS|NDR_BUFFERS, r->info7));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info7_0, 0);
+ }
+ break;
+
+ case 100:
+ if (r->info100) {
+ _mem_save_info100_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info100, 0);
+ NDR_CHECK(ndr_pull_dfs_Info100(ndr, NDR_SCALARS|NDR_BUFFERS, r->info100));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info100_0, 0);
+ }
+ break;
+
+ case 101:
+ if (r->info101) {
+ _mem_save_info101_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info101, 0);
+ NDR_CHECK(ndr_pull_dfs_Info101(ndr, NDR_SCALARS, r->info101));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info101_0, 0);
+ }
+ break;
+
+ case 102:
+ if (r->info102) {
+ _mem_save_info102_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info102, 0);
+ NDR_CHECK(ndr_pull_dfs_Info102(ndr, NDR_SCALARS, r->info102));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info102_0, 0);
+ }
+ break;
+
+ case 103:
+ if (r->info103) {
+ _mem_save_info103_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info103, 0);
+ NDR_CHECK(ndr_pull_dfs_Info103(ndr, NDR_SCALARS, r->info103));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info103_0, 0);
+ }
+ break;
+
+ case 104:
+ if (r->info104) {
+ _mem_save_info104_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info104, 0);
+ NDR_CHECK(ndr_pull_dfs_Info104(ndr, NDR_SCALARS, r->info104));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info104_0, 0);
+ }
+ break;
+
+ case 105:
+ if (r->info105) {
+ _mem_save_info105_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info105, 0);
+ NDR_CHECK(ndr_pull_dfs_Info105(ndr, NDR_SCALARS|NDR_BUFFERS, r->info105));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info105_0, 0);
+ }
+ break;
+
+ case 106:
+ if (r->info106) {
+ _mem_save_info106_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info106, 0);
+ NDR_CHECK(ndr_pull_dfs_Info106(ndr, NDR_SCALARS, r->info106));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info106_0, 0);
+ }
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Info(struct ndr_print *ndr, const char *name, const union dfs_Info *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "dfs_Info");
+ switch (level) {
+ case 0:
+ ndr_print_ptr(ndr, "info0", r->info0);
+ ndr->depth++;
+ if (r->info0) {
+ ndr_print_dfs_Info0(ndr, "info0", r->info0);
+ }
+ ndr->depth--;
+ break;
+
+ case 1:
+ ndr_print_ptr(ndr, "info1", r->info1);
+ ndr->depth++;
+ if (r->info1) {
+ ndr_print_dfs_Info1(ndr, "info1", r->info1);
+ }
+ ndr->depth--;
+ break;
+
+ case 2:
+ ndr_print_ptr(ndr, "info2", r->info2);
+ ndr->depth++;
+ if (r->info2) {
+ ndr_print_dfs_Info2(ndr, "info2", r->info2);
+ }
+ ndr->depth--;
+ break;
+
+ case 3:
+ ndr_print_ptr(ndr, "info3", r->info3);
+ ndr->depth++;
+ if (r->info3) {
+ ndr_print_dfs_Info3(ndr, "info3", r->info3);
+ }
+ ndr->depth--;
+ break;
+
+ case 4:
+ ndr_print_ptr(ndr, "info4", r->info4);
+ ndr->depth++;
+ if (r->info4) {
+ ndr_print_dfs_Info4(ndr, "info4", r->info4);
+ }
+ ndr->depth--;
+ break;
+
+ case 5:
+ ndr_print_ptr(ndr, "info5", r->info5);
+ ndr->depth++;
+ if (r->info5) {
+ ndr_print_dfs_Info5(ndr, "info5", r->info5);
+ }
+ ndr->depth--;
+ break;
+
+ case 6:
+ ndr_print_ptr(ndr, "info6", r->info6);
+ ndr->depth++;
+ if (r->info6) {
+ ndr_print_dfs_Info6(ndr, "info6", r->info6);
+ }
+ ndr->depth--;
+ break;
+
+ case 7:
+ ndr_print_ptr(ndr, "info7", r->info7);
+ ndr->depth++;
+ if (r->info7) {
+ ndr_print_dfs_Info7(ndr, "info7", r->info7);
+ }
+ ndr->depth--;
+ break;
+
+ case 100:
+ ndr_print_ptr(ndr, "info100", r->info100);
+ ndr->depth++;
+ if (r->info100) {
+ ndr_print_dfs_Info100(ndr, "info100", r->info100);
+ }
+ ndr->depth--;
+ break;
+
+ case 101:
+ ndr_print_ptr(ndr, "info101", r->info101);
+ ndr->depth++;
+ if (r->info101) {
+ ndr_print_dfs_Info101(ndr, "info101", r->info101);
+ }
+ ndr->depth--;
+ break;
+
+ case 102:
+ ndr_print_ptr(ndr, "info102", r->info102);
+ ndr->depth++;
+ if (r->info102) {
+ ndr_print_dfs_Info102(ndr, "info102", r->info102);
+ }
+ ndr->depth--;
+ break;
+
+ case 103:
+ ndr_print_ptr(ndr, "info103", r->info103);
+ ndr->depth++;
+ if (r->info103) {
+ ndr_print_dfs_Info103(ndr, "info103", r->info103);
+ }
+ ndr->depth--;
+ break;
+
+ case 104:
+ ndr_print_ptr(ndr, "info104", r->info104);
+ ndr->depth++;
+ if (r->info104) {
+ ndr_print_dfs_Info104(ndr, "info104", r->info104);
+ }
+ ndr->depth--;
+ break;
+
+ case 105:
+ ndr_print_ptr(ndr, "info105", r->info105);
+ ndr->depth++;
+ if (r->info105) {
+ ndr_print_dfs_Info105(ndr, "info105", r->info105);
+ }
+ ndr->depth--;
+ break;
+
+ case 106:
+ ndr_print_ptr(ndr, "info106", r->info106);
+ ndr->depth++;
+ if (r->info106) {
+ ndr_print_dfs_Info106(ndr, "info106", r->info106);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_dfs_EnumArray1(struct ndr_push *ndr, int ndr_flags, const struct dfs_EnumArray1 *r)
+{
+ uint32_t cntr_s_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->s));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->s) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_push_dfs_Info1(ndr, NDR_SCALARS, &r->s[cntr_s_1]));
+ }
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_push_dfs_Info1(ndr, NDR_BUFFERS, &r->s[cntr_s_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_EnumArray1(struct ndr_pull *ndr, int ndr_flags, struct dfs_EnumArray1 *r)
+{
+ uint32_t _ptr_s;
+ uint32_t cntr_s_1;
+ TALLOC_CTX *_mem_save_s_0;
+ TALLOC_CTX *_mem_save_s_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_s));
+ if (_ptr_s) {
+ NDR_PULL_ALLOC(ndr, r->s);
+ } else {
+ r->s = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->s) {
+ _mem_save_s_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->s, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->s));
+ NDR_PULL_ALLOC_N(ndr, r->s, ndr_get_array_size(ndr, &r->s));
+ _mem_save_s_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->s, 0);
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_pull_dfs_Info1(ndr, NDR_SCALARS, &r->s[cntr_s_1]));
+ }
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_pull_dfs_Info1(ndr, NDR_BUFFERS, &r->s[cntr_s_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s_0, 0);
+ }
+ if (r->s) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->s, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_EnumArray1(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray1 *r)
+{
+ uint32_t cntr_s_1;
+ ndr_print_struct(ndr, name, "dfs_EnumArray1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "s", r->s);
+ ndr->depth++;
+ if (r->s) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "s", (int)r->count);
+ ndr->depth++;
+ for (cntr_s_1=0;cntr_s_1<r->count;cntr_s_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_s_1) != -1) {
+ ndr_print_dfs_Info1(ndr, "s", &r->s[cntr_s_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_EnumArray2(struct ndr_push *ndr, int ndr_flags, const struct dfs_EnumArray2 *r)
+{
+ uint32_t cntr_s_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->s));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->s) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_push_dfs_Info2(ndr, NDR_SCALARS, &r->s[cntr_s_1]));
+ }
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_push_dfs_Info2(ndr, NDR_BUFFERS, &r->s[cntr_s_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_EnumArray2(struct ndr_pull *ndr, int ndr_flags, struct dfs_EnumArray2 *r)
+{
+ uint32_t _ptr_s;
+ uint32_t cntr_s_1;
+ TALLOC_CTX *_mem_save_s_0;
+ TALLOC_CTX *_mem_save_s_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_s));
+ if (_ptr_s) {
+ NDR_PULL_ALLOC(ndr, r->s);
+ } else {
+ r->s = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->s) {
+ _mem_save_s_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->s, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->s));
+ NDR_PULL_ALLOC_N(ndr, r->s, ndr_get_array_size(ndr, &r->s));
+ _mem_save_s_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->s, 0);
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_pull_dfs_Info2(ndr, NDR_SCALARS, &r->s[cntr_s_1]));
+ }
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_pull_dfs_Info2(ndr, NDR_BUFFERS, &r->s[cntr_s_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s_0, 0);
+ }
+ if (r->s) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->s, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_EnumArray2(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray2 *r)
+{
+ uint32_t cntr_s_1;
+ ndr_print_struct(ndr, name, "dfs_EnumArray2");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "s", r->s);
+ ndr->depth++;
+ if (r->s) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "s", (int)r->count);
+ ndr->depth++;
+ for (cntr_s_1=0;cntr_s_1<r->count;cntr_s_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_s_1) != -1) {
+ ndr_print_dfs_Info2(ndr, "s", &r->s[cntr_s_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_EnumArray3(struct ndr_push *ndr, int ndr_flags, const struct dfs_EnumArray3 *r)
+{
+ uint32_t cntr_s_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->s));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->s) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_push_dfs_Info3(ndr, NDR_SCALARS, &r->s[cntr_s_1]));
+ }
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_push_dfs_Info3(ndr, NDR_BUFFERS, &r->s[cntr_s_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_EnumArray3(struct ndr_pull *ndr, int ndr_flags, struct dfs_EnumArray3 *r)
+{
+ uint32_t _ptr_s;
+ uint32_t cntr_s_1;
+ TALLOC_CTX *_mem_save_s_0;
+ TALLOC_CTX *_mem_save_s_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_s));
+ if (_ptr_s) {
+ NDR_PULL_ALLOC(ndr, r->s);
+ } else {
+ r->s = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->s) {
+ _mem_save_s_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->s, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->s));
+ NDR_PULL_ALLOC_N(ndr, r->s, ndr_get_array_size(ndr, &r->s));
+ _mem_save_s_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->s, 0);
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_pull_dfs_Info3(ndr, NDR_SCALARS, &r->s[cntr_s_1]));
+ }
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_pull_dfs_Info3(ndr, NDR_BUFFERS, &r->s[cntr_s_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s_0, 0);
+ }
+ if (r->s) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->s, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_EnumArray3(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray3 *r)
+{
+ uint32_t cntr_s_1;
+ ndr_print_struct(ndr, name, "dfs_EnumArray3");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "s", r->s);
+ ndr->depth++;
+ if (r->s) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "s", (int)r->count);
+ ndr->depth++;
+ for (cntr_s_1=0;cntr_s_1<r->count;cntr_s_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_s_1) != -1) {
+ ndr_print_dfs_Info3(ndr, "s", &r->s[cntr_s_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_EnumArray4(struct ndr_push *ndr, int ndr_flags, const struct dfs_EnumArray4 *r)
+{
+ uint32_t cntr_s_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->s));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->s) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_push_dfs_Info4(ndr, NDR_SCALARS, &r->s[cntr_s_1]));
+ }
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_push_dfs_Info4(ndr, NDR_BUFFERS, &r->s[cntr_s_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_EnumArray4(struct ndr_pull *ndr, int ndr_flags, struct dfs_EnumArray4 *r)
+{
+ uint32_t _ptr_s;
+ uint32_t cntr_s_1;
+ TALLOC_CTX *_mem_save_s_0;
+ TALLOC_CTX *_mem_save_s_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_s));
+ if (_ptr_s) {
+ NDR_PULL_ALLOC(ndr, r->s);
+ } else {
+ r->s = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->s) {
+ _mem_save_s_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->s, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->s));
+ NDR_PULL_ALLOC_N(ndr, r->s, ndr_get_array_size(ndr, &r->s));
+ _mem_save_s_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->s, 0);
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_pull_dfs_Info4(ndr, NDR_SCALARS, &r->s[cntr_s_1]));
+ }
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_pull_dfs_Info4(ndr, NDR_BUFFERS, &r->s[cntr_s_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s_0, 0);
+ }
+ if (r->s) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->s, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_EnumArray4(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray4 *r)
+{
+ uint32_t cntr_s_1;
+ ndr_print_struct(ndr, name, "dfs_EnumArray4");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "s", r->s);
+ ndr->depth++;
+ if (r->s) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "s", (int)r->count);
+ ndr->depth++;
+ for (cntr_s_1=0;cntr_s_1<r->count;cntr_s_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_s_1) != -1) {
+ ndr_print_dfs_Info4(ndr, "s", &r->s[cntr_s_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_EnumArray5(struct ndr_push *ndr, int ndr_flags, const struct dfs_EnumArray5 *r)
+{
+ uint32_t cntr_s_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->s));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->s) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_push_dfs_Info5(ndr, NDR_SCALARS, &r->s[cntr_s_1]));
+ }
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_push_dfs_Info5(ndr, NDR_BUFFERS, &r->s[cntr_s_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_EnumArray5(struct ndr_pull *ndr, int ndr_flags, struct dfs_EnumArray5 *r)
+{
+ uint32_t _ptr_s;
+ uint32_t cntr_s_1;
+ TALLOC_CTX *_mem_save_s_0;
+ TALLOC_CTX *_mem_save_s_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_s));
+ if (_ptr_s) {
+ NDR_PULL_ALLOC(ndr, r->s);
+ } else {
+ r->s = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->s) {
+ _mem_save_s_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->s, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->s));
+ NDR_PULL_ALLOC_N(ndr, r->s, ndr_get_array_size(ndr, &r->s));
+ _mem_save_s_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->s, 0);
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_pull_dfs_Info5(ndr, NDR_SCALARS, &r->s[cntr_s_1]));
+ }
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_pull_dfs_Info5(ndr, NDR_BUFFERS, &r->s[cntr_s_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s_0, 0);
+ }
+ if (r->s) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->s, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_EnumArray5(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray5 *r)
+{
+ uint32_t cntr_s_1;
+ ndr_print_struct(ndr, name, "dfs_EnumArray5");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "s", r->s);
+ ndr->depth++;
+ if (r->s) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "s", (int)r->count);
+ ndr->depth++;
+ for (cntr_s_1=0;cntr_s_1<r->count;cntr_s_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_s_1) != -1) {
+ ndr_print_dfs_Info5(ndr, "s", &r->s[cntr_s_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_EnumArray6(struct ndr_push *ndr, int ndr_flags, const struct dfs_EnumArray6 *r)
+{
+ uint32_t cntr_s_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->s));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->s) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_push_dfs_Info6(ndr, NDR_SCALARS, &r->s[cntr_s_1]));
+ }
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_push_dfs_Info6(ndr, NDR_BUFFERS, &r->s[cntr_s_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_EnumArray6(struct ndr_pull *ndr, int ndr_flags, struct dfs_EnumArray6 *r)
+{
+ uint32_t _ptr_s;
+ uint32_t cntr_s_1;
+ TALLOC_CTX *_mem_save_s_0;
+ TALLOC_CTX *_mem_save_s_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_s));
+ if (_ptr_s) {
+ NDR_PULL_ALLOC(ndr, r->s);
+ } else {
+ r->s = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->s) {
+ _mem_save_s_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->s, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->s));
+ NDR_PULL_ALLOC_N(ndr, r->s, ndr_get_array_size(ndr, &r->s));
+ _mem_save_s_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->s, 0);
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_pull_dfs_Info6(ndr, NDR_SCALARS, &r->s[cntr_s_1]));
+ }
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_pull_dfs_Info6(ndr, NDR_BUFFERS, &r->s[cntr_s_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s_0, 0);
+ }
+ if (r->s) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->s, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_EnumArray6(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray6 *r)
+{
+ uint32_t cntr_s_1;
+ ndr_print_struct(ndr, name, "dfs_EnumArray6");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "s", r->s);
+ ndr->depth++;
+ if (r->s) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "s", (int)r->count);
+ ndr->depth++;
+ for (cntr_s_1=0;cntr_s_1<r->count;cntr_s_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_s_1) != -1) {
+ ndr_print_dfs_Info6(ndr, "s", &r->s[cntr_s_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_EnumArray200(struct ndr_push *ndr, int ndr_flags, const struct dfs_EnumArray200 *r)
+{
+ uint32_t cntr_s_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->s));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->s) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_push_dfs_Info200(ndr, NDR_SCALARS, &r->s[cntr_s_1]));
+ }
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_push_dfs_Info200(ndr, NDR_BUFFERS, &r->s[cntr_s_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_EnumArray200(struct ndr_pull *ndr, int ndr_flags, struct dfs_EnumArray200 *r)
+{
+ uint32_t _ptr_s;
+ uint32_t cntr_s_1;
+ TALLOC_CTX *_mem_save_s_0;
+ TALLOC_CTX *_mem_save_s_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_s));
+ if (_ptr_s) {
+ NDR_PULL_ALLOC(ndr, r->s);
+ } else {
+ r->s = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->s) {
+ _mem_save_s_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->s, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->s));
+ NDR_PULL_ALLOC_N(ndr, r->s, ndr_get_array_size(ndr, &r->s));
+ _mem_save_s_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->s, 0);
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_pull_dfs_Info200(ndr, NDR_SCALARS, &r->s[cntr_s_1]));
+ }
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_pull_dfs_Info200(ndr, NDR_BUFFERS, &r->s[cntr_s_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s_0, 0);
+ }
+ if (r->s) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->s, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_EnumArray200(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray200 *r)
+{
+ uint32_t cntr_s_1;
+ ndr_print_struct(ndr, name, "dfs_EnumArray200");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "s", r->s);
+ ndr->depth++;
+ if (r->s) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "s", (int)r->count);
+ ndr->depth++;
+ for (cntr_s_1=0;cntr_s_1<r->count;cntr_s_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_s_1) != -1) {
+ ndr_print_dfs_Info200(ndr, "s", &r->s[cntr_s_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_EnumArray300(struct ndr_push *ndr, int ndr_flags, const struct dfs_EnumArray300 *r)
+{
+ uint32_t cntr_s_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->s));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->s) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_push_dfs_Info300(ndr, NDR_SCALARS, &r->s[cntr_s_1]));
+ }
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_push_dfs_Info300(ndr, NDR_BUFFERS, &r->s[cntr_s_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_EnumArray300(struct ndr_pull *ndr, int ndr_flags, struct dfs_EnumArray300 *r)
+{
+ uint32_t _ptr_s;
+ uint32_t cntr_s_1;
+ TALLOC_CTX *_mem_save_s_0;
+ TALLOC_CTX *_mem_save_s_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_s));
+ if (_ptr_s) {
+ NDR_PULL_ALLOC(ndr, r->s);
+ } else {
+ r->s = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->s) {
+ _mem_save_s_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->s, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->s));
+ NDR_PULL_ALLOC_N(ndr, r->s, ndr_get_array_size(ndr, &r->s));
+ _mem_save_s_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->s, 0);
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_pull_dfs_Info300(ndr, NDR_SCALARS, &r->s[cntr_s_1]));
+ }
+ for (cntr_s_1 = 0; cntr_s_1 < r->count; cntr_s_1++) {
+ NDR_CHECK(ndr_pull_dfs_Info300(ndr, NDR_BUFFERS, &r->s[cntr_s_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s_0, 0);
+ }
+ if (r->s) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->s, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_EnumArray300(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray300 *r)
+{
+ uint32_t cntr_s_1;
+ ndr_print_struct(ndr, name, "dfs_EnumArray300");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "s", r->s);
+ ndr->depth++;
+ if (r->s) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "s", (int)r->count);
+ ndr->depth++;
+ for (cntr_s_1=0;cntr_s_1<r->count;cntr_s_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_s_1) != -1) {
+ ndr_print_dfs_Info300(ndr, "s", &r->s[cntr_s_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_EnumInfo(struct ndr_push *ndr, int ndr_flags, const union dfs_EnumInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info3));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info4));
+ break; }
+
+ case 5: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info5));
+ break; }
+
+ case 6: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info6));
+ break; }
+
+ case 200: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info200));
+ break; }
+
+ case 300: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info300));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ if (r->info1) {
+ NDR_CHECK(ndr_push_dfs_EnumArray1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ }
+ break;
+
+ case 2:
+ if (r->info2) {
+ NDR_CHECK(ndr_push_dfs_EnumArray2(ndr, NDR_SCALARS|NDR_BUFFERS, r->info2));
+ }
+ break;
+
+ case 3:
+ if (r->info3) {
+ NDR_CHECK(ndr_push_dfs_EnumArray3(ndr, NDR_SCALARS|NDR_BUFFERS, r->info3));
+ }
+ break;
+
+ case 4:
+ if (r->info4) {
+ NDR_CHECK(ndr_push_dfs_EnumArray4(ndr, NDR_SCALARS|NDR_BUFFERS, r->info4));
+ }
+ break;
+
+ case 5:
+ if (r->info5) {
+ NDR_CHECK(ndr_push_dfs_EnumArray5(ndr, NDR_SCALARS|NDR_BUFFERS, r->info5));
+ }
+ break;
+
+ case 6:
+ if (r->info6) {
+ NDR_CHECK(ndr_push_dfs_EnumArray6(ndr, NDR_SCALARS|NDR_BUFFERS, r->info6));
+ }
+ break;
+
+ case 200:
+ if (r->info200) {
+ NDR_CHECK(ndr_push_dfs_EnumArray200(ndr, NDR_SCALARS|NDR_BUFFERS, r->info200));
+ }
+ break;
+
+ case 300:
+ if (r->info300) {
+ NDR_CHECK(ndr_push_dfs_EnumArray300(ndr, NDR_SCALARS|NDR_BUFFERS, r->info300));
+ }
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_EnumInfo(struct ndr_pull *ndr, int ndr_flags, union dfs_EnumInfo *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_info1_0;
+ TALLOC_CTX *_mem_save_info2_0;
+ TALLOC_CTX *_mem_save_info3_0;
+ TALLOC_CTX *_mem_save_info4_0;
+ TALLOC_CTX *_mem_save_info5_0;
+ TALLOC_CTX *_mem_save_info6_0;
+ TALLOC_CTX *_mem_save_info200_0;
+ TALLOC_CTX *_mem_save_info300_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ uint32_t _ptr_info1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1));
+ if (_ptr_info1) {
+ NDR_PULL_ALLOC(ndr, r->info1);
+ } else {
+ r->info1 = NULL;
+ }
+ break; }
+
+ case 2: {
+ uint32_t _ptr_info2;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info2));
+ if (_ptr_info2) {
+ NDR_PULL_ALLOC(ndr, r->info2);
+ } else {
+ r->info2 = NULL;
+ }
+ break; }
+
+ case 3: {
+ uint32_t _ptr_info3;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info3));
+ if (_ptr_info3) {
+ NDR_PULL_ALLOC(ndr, r->info3);
+ } else {
+ r->info3 = NULL;
+ }
+ break; }
+
+ case 4: {
+ uint32_t _ptr_info4;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info4));
+ if (_ptr_info4) {
+ NDR_PULL_ALLOC(ndr, r->info4);
+ } else {
+ r->info4 = NULL;
+ }
+ break; }
+
+ case 5: {
+ uint32_t _ptr_info5;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info5));
+ if (_ptr_info5) {
+ NDR_PULL_ALLOC(ndr, r->info5);
+ } else {
+ r->info5 = NULL;
+ }
+ break; }
+
+ case 6: {
+ uint32_t _ptr_info6;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info6));
+ if (_ptr_info6) {
+ NDR_PULL_ALLOC(ndr, r->info6);
+ } else {
+ r->info6 = NULL;
+ }
+ break; }
+
+ case 200: {
+ uint32_t _ptr_info200;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info200));
+ if (_ptr_info200) {
+ NDR_PULL_ALLOC(ndr, r->info200);
+ } else {
+ r->info200 = NULL;
+ }
+ break; }
+
+ case 300: {
+ uint32_t _ptr_info300;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info300));
+ if (_ptr_info300) {
+ NDR_PULL_ALLOC(ndr, r->info300);
+ } else {
+ r->info300 = NULL;
+ }
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ if (r->info1) {
+ _mem_save_info1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1, 0);
+ NDR_CHECK(ndr_pull_dfs_EnumArray1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1_0, 0);
+ }
+ break;
+
+ case 2:
+ if (r->info2) {
+ _mem_save_info2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info2, 0);
+ NDR_CHECK(ndr_pull_dfs_EnumArray2(ndr, NDR_SCALARS|NDR_BUFFERS, r->info2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info2_0, 0);
+ }
+ break;
+
+ case 3:
+ if (r->info3) {
+ _mem_save_info3_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info3, 0);
+ NDR_CHECK(ndr_pull_dfs_EnumArray3(ndr, NDR_SCALARS|NDR_BUFFERS, r->info3));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info3_0, 0);
+ }
+ break;
+
+ case 4:
+ if (r->info4) {
+ _mem_save_info4_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info4, 0);
+ NDR_CHECK(ndr_pull_dfs_EnumArray4(ndr, NDR_SCALARS|NDR_BUFFERS, r->info4));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info4_0, 0);
+ }
+ break;
+
+ case 5:
+ if (r->info5) {
+ _mem_save_info5_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info5, 0);
+ NDR_CHECK(ndr_pull_dfs_EnumArray5(ndr, NDR_SCALARS|NDR_BUFFERS, r->info5));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info5_0, 0);
+ }
+ break;
+
+ case 6:
+ if (r->info6) {
+ _mem_save_info6_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info6, 0);
+ NDR_CHECK(ndr_pull_dfs_EnumArray6(ndr, NDR_SCALARS|NDR_BUFFERS, r->info6));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info6_0, 0);
+ }
+ break;
+
+ case 200:
+ if (r->info200) {
+ _mem_save_info200_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info200, 0);
+ NDR_CHECK(ndr_pull_dfs_EnumArray200(ndr, NDR_SCALARS|NDR_BUFFERS, r->info200));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info200_0, 0);
+ }
+ break;
+
+ case 300:
+ if (r->info300) {
+ _mem_save_info300_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info300, 0);
+ NDR_CHECK(ndr_pull_dfs_EnumArray300(ndr, NDR_SCALARS|NDR_BUFFERS, r->info300));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info300_0, 0);
+ }
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_EnumInfo(struct ndr_print *ndr, const char *name, const union dfs_EnumInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "dfs_EnumInfo");
+ switch (level) {
+ case 1:
+ ndr_print_ptr(ndr, "info1", r->info1);
+ ndr->depth++;
+ if (r->info1) {
+ ndr_print_dfs_EnumArray1(ndr, "info1", r->info1);
+ }
+ ndr->depth--;
+ break;
+
+ case 2:
+ ndr_print_ptr(ndr, "info2", r->info2);
+ ndr->depth++;
+ if (r->info2) {
+ ndr_print_dfs_EnumArray2(ndr, "info2", r->info2);
+ }
+ ndr->depth--;
+ break;
+
+ case 3:
+ ndr_print_ptr(ndr, "info3", r->info3);
+ ndr->depth++;
+ if (r->info3) {
+ ndr_print_dfs_EnumArray3(ndr, "info3", r->info3);
+ }
+ ndr->depth--;
+ break;
+
+ case 4:
+ ndr_print_ptr(ndr, "info4", r->info4);
+ ndr->depth++;
+ if (r->info4) {
+ ndr_print_dfs_EnumArray4(ndr, "info4", r->info4);
+ }
+ ndr->depth--;
+ break;
+
+ case 5:
+ ndr_print_ptr(ndr, "info5", r->info5);
+ ndr->depth++;
+ if (r->info5) {
+ ndr_print_dfs_EnumArray5(ndr, "info5", r->info5);
+ }
+ ndr->depth--;
+ break;
+
+ case 6:
+ ndr_print_ptr(ndr, "info6", r->info6);
+ ndr->depth++;
+ if (r->info6) {
+ ndr_print_dfs_EnumArray6(ndr, "info6", r->info6);
+ }
+ ndr->depth--;
+ break;
+
+ case 200:
+ ndr_print_ptr(ndr, "info200", r->info200);
+ ndr->depth++;
+ if (r->info200) {
+ ndr_print_dfs_EnumArray200(ndr, "info200", r->info200);
+ }
+ ndr->depth--;
+ break;
+
+ case 300:
+ ndr_print_ptr(ndr, "info300", r->info300);
+ ndr->depth++;
+ if (r->info300) {
+ ndr_print_dfs_EnumArray300(ndr, "info300", r->info300);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_dfs_EnumStruct(struct ndr_push *ndr, int ndr_flags, const struct dfs_EnumStruct *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->e, r->level));
+ NDR_CHECK(ndr_push_dfs_EnumInfo(ndr, NDR_SCALARS, &r->e));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_dfs_EnumInfo(ndr, NDR_BUFFERS, &r->e));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_EnumStruct(struct ndr_pull *ndr, int ndr_flags, struct dfs_EnumStruct *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->e, r->level));
+ NDR_CHECK(ndr_pull_dfs_EnumInfo(ndr, NDR_SCALARS, &r->e));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_dfs_EnumInfo(ndr, NDR_BUFFERS, &r->e));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_EnumStruct(struct ndr_print *ndr, const char *name, const struct dfs_EnumStruct *r)
+{
+ ndr_print_struct(ndr, name, "dfs_EnumStruct");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level", r->level);
+ ndr_print_set_switch_value(ndr, &r->e, r->level);
+ ndr_print_dfs_EnumInfo(ndr, "e", &r->e);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_UnknownStruct(struct ndr_push *ndr, int ndr_flags, const struct dfs_UnknownStruct *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->unknown2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->unknown2) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->unknown2, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->unknown2, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->unknown2, ndr_charset_length(r->unknown2, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_UnknownStruct(struct ndr_pull *ndr, int ndr_flags, struct dfs_UnknownStruct *r)
+{
+ uint32_t _ptr_unknown2;
+ TALLOC_CTX *_mem_save_unknown2_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown2));
+ if (_ptr_unknown2) {
+ NDR_PULL_ALLOC(ndr, r->unknown2);
+ } else {
+ r->unknown2 = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->unknown2) {
+ _mem_save_unknown2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->unknown2, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->unknown2));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->unknown2));
+ if (ndr_get_array_length(ndr, &r->unknown2) > ndr_get_array_size(ndr, &r->unknown2)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->unknown2), ndr_get_array_length(ndr, &r->unknown2));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->unknown2), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->unknown2, ndr_get_array_length(ndr, &r->unknown2), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown2_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_UnknownStruct(struct ndr_print *ndr, const char *name, const struct dfs_UnknownStruct *r)
+{
+ ndr_print_struct(ndr, name, "dfs_UnknownStruct");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "unknown1", r->unknown1);
+ ndr_print_ptr(ndr, "unknown2", r->unknown2);
+ ndr->depth++;
+ if (r->unknown2) {
+ ndr_print_string(ndr, "unknown2", r->unknown2);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_dfs_GetManagerVersion(struct ndr_push *ndr, int flags, const struct dfs_GetManagerVersion *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.version == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_dfs_ManagerVersion(ndr, NDR_SCALARS, *r->out.version));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_dfs_GetManagerVersion(struct ndr_pull *ndr, int flags, struct dfs_GetManagerVersion *r)
+{
+ TALLOC_CTX *_mem_save_version_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_PULL_ALLOC(ndr, r->out.version);
+ ZERO_STRUCTP(r->out.version);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.version);
+ }
+ _mem_save_version_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.version, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_dfs_ManagerVersion(ndr, NDR_SCALARS, r->out.version));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_version_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_GetManagerVersion(struct ndr_print *ndr, const char *name, int flags, const struct dfs_GetManagerVersion *r)
+{
+ ndr_print_struct(ndr, name, "dfs_GetManagerVersion");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_GetManagerVersion");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_GetManagerVersion");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "version", r->out.version);
+ ndr->depth++;
+ ndr_print_dfs_ManagerVersion(ndr, "version", *r->out.version);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Add(struct ndr_push *ndr, int flags, const struct dfs_Add *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.path == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.path, ndr_charset_length(r->in.path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ if (r->in.server == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server, ndr_charset_length(r->in.server, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.share));
+ if (r->in.share) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.share, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.share, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.share, ndr_charset_length(r->in.share, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.comment));
+ if (r->in.comment) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.comment, ndr_charset_length(r->in.comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Add(struct ndr_pull *ndr, int flags, struct dfs_Add *r)
+{
+ uint32_t _ptr_share;
+ uint32_t _ptr_comment;
+ TALLOC_CTX *_mem_save_share_0;
+ TALLOC_CTX *_mem_save_comment_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.path));
+ if (ndr_get_array_length(ndr, &r->in.path) > ndr_get_array_size(ndr, &r->in.path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.path), ndr_get_array_length(ndr, &r->in.path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.path, ndr_get_array_length(ndr, &r->in.path), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server));
+ if (ndr_get_array_length(ndr, &r->in.server) > ndr_get_array_size(ndr, &r->in.server)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server), ndr_get_array_length(ndr, &r->in.server));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server, ndr_get_array_length(ndr, &r->in.server), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_share));
+ if (_ptr_share) {
+ NDR_PULL_ALLOC(ndr, r->in.share);
+ } else {
+ r->in.share = NULL;
+ }
+ if (r->in.share) {
+ _mem_save_share_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.share, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.share));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.share));
+ if (ndr_get_array_length(ndr, &r->in.share) > ndr_get_array_size(ndr, &r->in.share)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.share), ndr_get_array_length(ndr, &r->in.share));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.share), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.share, ndr_get_array_length(ndr, &r->in.share), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_share_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_comment));
+ if (_ptr_comment) {
+ NDR_PULL_ALLOC(ndr, r->in.comment);
+ } else {
+ r->in.comment = NULL;
+ }
+ if (r->in.comment) {
+ _mem_save_comment_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.comment, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.comment));
+ if (ndr_get_array_length(ndr, &r->in.comment) > ndr_get_array_size(ndr, &r->in.comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.comment), ndr_get_array_length(ndr, &r->in.comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.comment, ndr_get_array_length(ndr, &r->in.comment), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_comment_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Add(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Add *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Add");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_Add");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "path", r->in.path);
+ ndr->depth++;
+ ndr_print_string(ndr, "path", r->in.path);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "server", r->in.server);
+ ndr->depth++;
+ ndr_print_string(ndr, "server", r->in.server);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "share", r->in.share);
+ ndr->depth++;
+ if (r->in.share) {
+ ndr_print_string(ndr, "share", r->in.share);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "comment", r->in.comment);
+ ndr->depth++;
+ if (r->in.comment) {
+ ndr_print_string(ndr, "comment", r->in.comment);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_Add");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Remove(struct ndr_push *ndr, int flags, const struct dfs_Remove *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.dfs_entry_path == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dfs_entry_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dfs_entry_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.dfs_entry_path, ndr_charset_length(r->in.dfs_entry_path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.servername));
+ if (r->in.servername) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.servername, ndr_charset_length(r->in.servername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.sharename));
+ if (r->in.sharename) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.sharename, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.sharename, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.sharename, ndr_charset_length(r->in.sharename, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Remove(struct ndr_pull *ndr, int flags, struct dfs_Remove *r)
+{
+ uint32_t _ptr_servername;
+ uint32_t _ptr_sharename;
+ TALLOC_CTX *_mem_save_servername_0;
+ TALLOC_CTX *_mem_save_sharename_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.dfs_entry_path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.dfs_entry_path));
+ if (ndr_get_array_length(ndr, &r->in.dfs_entry_path) > ndr_get_array_size(ndr, &r->in.dfs_entry_path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.dfs_entry_path), ndr_get_array_length(ndr, &r->in.dfs_entry_path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.dfs_entry_path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.dfs_entry_path, ndr_get_array_length(ndr, &r->in.dfs_entry_path), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_servername));
+ if (_ptr_servername) {
+ NDR_PULL_ALLOC(ndr, r->in.servername);
+ } else {
+ r->in.servername = NULL;
+ }
+ if (r->in.servername) {
+ _mem_save_servername_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.servername, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.servername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.servername));
+ if (ndr_get_array_length(ndr, &r->in.servername) > ndr_get_array_size(ndr, &r->in.servername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.servername), ndr_get_array_length(ndr, &r->in.servername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.servername, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_servername_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sharename));
+ if (_ptr_sharename) {
+ NDR_PULL_ALLOC(ndr, r->in.sharename);
+ } else {
+ r->in.sharename = NULL;
+ }
+ if (r->in.sharename) {
+ _mem_save_sharename_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sharename, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.sharename));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.sharename));
+ if (ndr_get_array_length(ndr, &r->in.sharename) > ndr_get_array_size(ndr, &r->in.sharename)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.sharename), ndr_get_array_length(ndr, &r->in.sharename));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.sharename), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.sharename, ndr_get_array_length(ndr, &r->in.sharename), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sharename_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Remove(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Remove *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Remove");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_Remove");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "dfs_entry_path", r->in.dfs_entry_path);
+ ndr->depth++;
+ ndr_print_string(ndr, "dfs_entry_path", r->in.dfs_entry_path);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "servername", r->in.servername);
+ ndr->depth++;
+ if (r->in.servername) {
+ ndr_print_string(ndr, "servername", r->in.servername);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sharename", r->in.sharename);
+ ndr->depth++;
+ if (r->in.sharename) {
+ ndr_print_string(ndr, "sharename", r->in.sharename);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_Remove");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_SetInfo(struct ndr_push *ndr, int flags, const struct dfs_SetInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dfs_entry_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dfs_entry_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.dfs_entry_path, ndr_charset_length(r->in.dfs_entry_path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.servername));
+ if (r->in.servername) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.servername, ndr_charset_length(r->in.servername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.sharename));
+ if (r->in.sharename) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.sharename, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.sharename, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.sharename, ndr_charset_length(r->in.sharename, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_dfs_Info(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_SetInfo(struct ndr_pull *ndr, int flags, struct dfs_SetInfo *r)
+{
+ uint32_t _ptr_servername;
+ uint32_t _ptr_sharename;
+ TALLOC_CTX *_mem_save_servername_0;
+ TALLOC_CTX *_mem_save_sharename_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.dfs_entry_path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.dfs_entry_path));
+ if (ndr_get_array_length(ndr, &r->in.dfs_entry_path) > ndr_get_array_size(ndr, &r->in.dfs_entry_path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.dfs_entry_path), ndr_get_array_length(ndr, &r->in.dfs_entry_path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.dfs_entry_path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.dfs_entry_path, ndr_get_array_length(ndr, &r->in.dfs_entry_path), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_servername));
+ if (_ptr_servername) {
+ NDR_PULL_ALLOC(ndr, r->in.servername);
+ } else {
+ r->in.servername = NULL;
+ }
+ if (r->in.servername) {
+ _mem_save_servername_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.servername, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.servername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.servername));
+ if (ndr_get_array_length(ndr, &r->in.servername) > ndr_get_array_size(ndr, &r->in.servername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.servername), ndr_get_array_length(ndr, &r->in.servername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.servername, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_servername_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sharename));
+ if (_ptr_sharename) {
+ NDR_PULL_ALLOC(ndr, r->in.sharename);
+ } else {
+ r->in.sharename = NULL;
+ }
+ if (r->in.sharename) {
+ _mem_save_sharename_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sharename, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.sharename));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.sharename));
+ if (ndr_get_array_length(ndr, &r->in.sharename) > ndr_get_array_size(ndr, &r->in.sharename)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.sharename), ndr_get_array_length(ndr, &r->in.sharename));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.sharename), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.sharename, ndr_get_array_length(ndr, &r->in.sharename), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sharename_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_dfs_Info(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_SetInfo(struct ndr_print *ndr, const char *name, int flags, const struct dfs_SetInfo *r)
+{
+ ndr_print_struct(ndr, name, "dfs_SetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_SetInfo");
+ ndr->depth++;
+ ndr_print_string(ndr, "dfs_entry_path", r->in.dfs_entry_path);
+ ndr_print_ptr(ndr, "servername", r->in.servername);
+ ndr->depth++;
+ if (r->in.servername) {
+ ndr_print_string(ndr, "servername", r->in.servername);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sharename", r->in.sharename);
+ ndr->depth++;
+ if (r->in.sharename) {
+ ndr_print_string(ndr, "sharename", r->in.sharename);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.info, r->in.level);
+ ndr_print_dfs_Info(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_SetInfo");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_GetInfo(struct ndr_push *ndr, int flags, const struct dfs_GetInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dfs_entry_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dfs_entry_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.dfs_entry_path, ndr_charset_length(r->in.dfs_entry_path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.servername));
+ if (r->in.servername) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.servername, ndr_charset_length(r->in.servername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.sharename));
+ if (r->in.sharename) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.sharename, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.sharename, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.sharename, ndr_charset_length(r->in.sharename, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_dfs_Info(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_GetInfo(struct ndr_pull *ndr, int flags, struct dfs_GetInfo *r)
+{
+ uint32_t _ptr_servername;
+ uint32_t _ptr_sharename;
+ TALLOC_CTX *_mem_save_servername_0;
+ TALLOC_CTX *_mem_save_sharename_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.dfs_entry_path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.dfs_entry_path));
+ if (ndr_get_array_length(ndr, &r->in.dfs_entry_path) > ndr_get_array_size(ndr, &r->in.dfs_entry_path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.dfs_entry_path), ndr_get_array_length(ndr, &r->in.dfs_entry_path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.dfs_entry_path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.dfs_entry_path, ndr_get_array_length(ndr, &r->in.dfs_entry_path), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_servername));
+ if (_ptr_servername) {
+ NDR_PULL_ALLOC(ndr, r->in.servername);
+ } else {
+ r->in.servername = NULL;
+ }
+ if (r->in.servername) {
+ _mem_save_servername_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.servername, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.servername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.servername));
+ if (ndr_get_array_length(ndr, &r->in.servername) > ndr_get_array_size(ndr, &r->in.servername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.servername), ndr_get_array_length(ndr, &r->in.servername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.servername, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_servername_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sharename));
+ if (_ptr_sharename) {
+ NDR_PULL_ALLOC(ndr, r->in.sharename);
+ } else {
+ r->in.sharename = NULL;
+ }
+ if (r->in.sharename) {
+ _mem_save_sharename_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sharename, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.sharename));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.sharename));
+ if (ndr_get_array_length(ndr, &r->in.sharename) > ndr_get_array_size(ndr, &r->in.sharename)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.sharename), ndr_get_array_length(ndr, &r->in.sharename));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.sharename), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.sharename, ndr_get_array_length(ndr, &r->in.sharename), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sharename_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_dfs_Info(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_GetInfo(struct ndr_print *ndr, const char *name, int flags, const struct dfs_GetInfo *r)
+{
+ ndr_print_struct(ndr, name, "dfs_GetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_GetInfo");
+ ndr->depth++;
+ ndr_print_string(ndr, "dfs_entry_path", r->in.dfs_entry_path);
+ ndr_print_ptr(ndr, "servername", r->in.servername);
+ ndr->depth++;
+ if (r->in.servername) {
+ ndr_print_string(ndr, "servername", r->in.servername);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sharename", r->in.sharename);
+ ndr->depth++;
+ if (r->in.sharename) {
+ ndr_print_string(ndr, "sharename", r->in.sharename);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_GetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, r->in.level);
+ ndr_print_dfs_Info(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Enum(struct ndr_push *ndr, int flags, const struct dfs_Enum *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.bufsize));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.info));
+ if (r->in.info) {
+ NDR_CHECK(ndr_push_dfs_EnumStruct(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.total));
+ if (r->in.total) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.total));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.info));
+ if (r->out.info) {
+ NDR_CHECK(ndr_push_dfs_EnumStruct(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.total));
+ if (r->out.total) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.total));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Enum(struct ndr_pull *ndr, int flags, struct dfs_Enum *r)
+{
+ uint32_t _ptr_info;
+ uint32_t _ptr_total;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_total_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.bufsize));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ } else {
+ r->in.info = NULL;
+ }
+ if (r->in.info) {
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, 0);
+ NDR_CHECK(ndr_pull_dfs_EnumStruct(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_total));
+ if (_ptr_total) {
+ NDR_PULL_ALLOC(ndr, r->in.total);
+ } else {
+ r->in.total = NULL;
+ }
+ if (r->in.total) {
+ _mem_save_total_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.total, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.total));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_total_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ } else {
+ r->out.info = NULL;
+ }
+ if (r->out.info) {
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, 0);
+ NDR_CHECK(ndr_pull_dfs_EnumStruct(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_total));
+ if (_ptr_total) {
+ NDR_PULL_ALLOC(ndr, r->out.total);
+ } else {
+ r->out.total = NULL;
+ }
+ if (r->out.total) {
+ _mem_save_total_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.total, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.total));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_total_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Enum(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Enum *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Enum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_Enum");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "bufsize", r->in.bufsize);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ if (r->in.info) {
+ ndr_print_dfs_EnumStruct(ndr, "info", r->in.info);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "total", r->in.total);
+ ndr->depth++;
+ if (r->in.total) {
+ ndr_print_uint32(ndr, "total", *r->in.total);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_Enum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ if (r->out.info) {
+ ndr_print_dfs_EnumStruct(ndr, "info", r->out.info);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "total", r->out.total);
+ ndr->depth++;
+ if (r->out.total) {
+ ndr_print_uint32(ndr, "total", *r->out.total);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Rename(struct ndr_push *ndr, int flags, const struct dfs_Rename *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Rename(struct ndr_pull *ndr, int flags, struct dfs_Rename *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Rename(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Rename *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Rename");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_Rename");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_Rename");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Move(struct ndr_push *ndr, int flags, const struct dfs_Move *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Move(struct ndr_pull *ndr, int flags, struct dfs_Move *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Move(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Move *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Move");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_Move");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_Move");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_ManagerGetConfigInfo(struct ndr_push *ndr, int flags, const struct dfs_ManagerGetConfigInfo *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_ManagerGetConfigInfo(struct ndr_pull *ndr, int flags, struct dfs_ManagerGetConfigInfo *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_ManagerGetConfigInfo(struct ndr_print *ndr, const char *name, int flags, const struct dfs_ManagerGetConfigInfo *r)
+{
+ ndr_print_struct(ndr, name, "dfs_ManagerGetConfigInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_ManagerGetConfigInfo");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_ManagerGetConfigInfo");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_ManagerSendSiteInfo(struct ndr_push *ndr, int flags, const struct dfs_ManagerSendSiteInfo *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_ManagerSendSiteInfo(struct ndr_pull *ndr, int flags, struct dfs_ManagerSendSiteInfo *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_ManagerSendSiteInfo(struct ndr_print *ndr, const char *name, int flags, const struct dfs_ManagerSendSiteInfo *r)
+{
+ ndr_print_struct(ndr, name, "dfs_ManagerSendSiteInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_ManagerSendSiteInfo");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_ManagerSendSiteInfo");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_AddFtRoot(struct ndr_push *ndr, int flags, const struct dfs_AddFtRoot *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.servername, ndr_charset_length(r->in.servername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dns_servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dns_servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.dns_servername, ndr_charset_length(r->in.dns_servername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dfsname, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dfsname, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.dfsname, ndr_charset_length(r->in.dfsname, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.rootshare, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.rootshare, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.rootshare, ndr_charset_length(r->in.rootshare, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.comment, ndr_charset_length(r->in.comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dfs_config_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dfs_config_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.dfs_config_dn, ndr_charset_length(r->in.dfs_config_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.unknown1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.flags));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.unknown2));
+ if (r->in.unknown2) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->in.unknown2));
+ if (*r->in.unknown2) {
+ NDR_CHECK(ndr_push_dfs_UnknownStruct(ndr, NDR_SCALARS|NDR_BUFFERS, *r->in.unknown2));
+ }
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.unknown2));
+ if (r->out.unknown2) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.unknown2));
+ if (*r->out.unknown2) {
+ NDR_CHECK(ndr_push_dfs_UnknownStruct(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.unknown2));
+ }
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_AddFtRoot(struct ndr_pull *ndr, int flags, struct dfs_AddFtRoot *r)
+{
+ uint32_t _ptr_unknown2;
+ TALLOC_CTX *_mem_save_unknown2_0;
+ TALLOC_CTX *_mem_save_unknown2_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.servername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.servername));
+ if (ndr_get_array_length(ndr, &r->in.servername) > ndr_get_array_size(ndr, &r->in.servername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.servername), ndr_get_array_length(ndr, &r->in.servername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.servername, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.dns_servername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.dns_servername));
+ if (ndr_get_array_length(ndr, &r->in.dns_servername) > ndr_get_array_size(ndr, &r->in.dns_servername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.dns_servername), ndr_get_array_length(ndr, &r->in.dns_servername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.dns_servername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.dns_servername, ndr_get_array_length(ndr, &r->in.dns_servername), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.dfsname));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.dfsname));
+ if (ndr_get_array_length(ndr, &r->in.dfsname) > ndr_get_array_size(ndr, &r->in.dfsname)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.dfsname), ndr_get_array_length(ndr, &r->in.dfsname));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.dfsname), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.dfsname, ndr_get_array_length(ndr, &r->in.dfsname), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.rootshare));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.rootshare));
+ if (ndr_get_array_length(ndr, &r->in.rootshare) > ndr_get_array_size(ndr, &r->in.rootshare)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.rootshare), ndr_get_array_length(ndr, &r->in.rootshare));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.rootshare), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.rootshare, ndr_get_array_length(ndr, &r->in.rootshare), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.comment));
+ if (ndr_get_array_length(ndr, &r->in.comment) > ndr_get_array_size(ndr, &r->in.comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.comment), ndr_get_array_length(ndr, &r->in.comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.comment, ndr_get_array_length(ndr, &r->in.comment), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.dfs_config_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.dfs_config_dn));
+ if (ndr_get_array_length(ndr, &r->in.dfs_config_dn) > ndr_get_array_size(ndr, &r->in.dfs_config_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.dfs_config_dn), ndr_get_array_length(ndr, &r->in.dfs_config_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.dfs_config_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.dfs_config_dn, ndr_get_array_length(ndr, &r->in.dfs_config_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.flags));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown2));
+ if (_ptr_unknown2) {
+ NDR_PULL_ALLOC(ndr, r->in.unknown2);
+ } else {
+ r->in.unknown2 = NULL;
+ }
+ if (r->in.unknown2) {
+ _mem_save_unknown2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.unknown2, 0);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown2));
+ if (_ptr_unknown2) {
+ NDR_PULL_ALLOC(ndr, *r->in.unknown2);
+ } else {
+ *r->in.unknown2 = NULL;
+ }
+ if (*r->in.unknown2) {
+ _mem_save_unknown2_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->in.unknown2, 0);
+ NDR_CHECK(ndr_pull_dfs_UnknownStruct(ndr, NDR_SCALARS|NDR_BUFFERS, *r->in.unknown2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown2_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown2_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown2));
+ if (_ptr_unknown2) {
+ NDR_PULL_ALLOC(ndr, r->out.unknown2);
+ } else {
+ r->out.unknown2 = NULL;
+ }
+ if (r->out.unknown2) {
+ _mem_save_unknown2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.unknown2, 0);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown2));
+ if (_ptr_unknown2) {
+ NDR_PULL_ALLOC(ndr, *r->out.unknown2);
+ } else {
+ *r->out.unknown2 = NULL;
+ }
+ if (*r->out.unknown2) {
+ _mem_save_unknown2_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.unknown2, 0);
+ NDR_CHECK(ndr_pull_dfs_UnknownStruct(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.unknown2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown2_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown2_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_AddFtRoot(struct ndr_print *ndr, const char *name, int flags, const struct dfs_AddFtRoot *r)
+{
+ ndr_print_struct(ndr, name, "dfs_AddFtRoot");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_AddFtRoot");
+ ndr->depth++;
+ ndr_print_string(ndr, "servername", r->in.servername);
+ ndr_print_string(ndr, "dns_servername", r->in.dns_servername);
+ ndr_print_string(ndr, "dfsname", r->in.dfsname);
+ ndr_print_string(ndr, "rootshare", r->in.rootshare);
+ ndr_print_string(ndr, "comment", r->in.comment);
+ ndr_print_string(ndr, "dfs_config_dn", r->in.dfs_config_dn);
+ ndr_print_uint8(ndr, "unknown1", r->in.unknown1);
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr_print_ptr(ndr, "unknown2", r->in.unknown2);
+ ndr->depth++;
+ if (r->in.unknown2) {
+ ndr_print_ptr(ndr, "unknown2", *r->in.unknown2);
+ ndr->depth++;
+ if (*r->in.unknown2) {
+ ndr_print_dfs_UnknownStruct(ndr, "unknown2", *r->in.unknown2);
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_AddFtRoot");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "unknown2", r->out.unknown2);
+ ndr->depth++;
+ if (r->out.unknown2) {
+ ndr_print_ptr(ndr, "unknown2", *r->out.unknown2);
+ ndr->depth++;
+ if (*r->out.unknown2) {
+ ndr_print_dfs_UnknownStruct(ndr, "unknown2", *r->out.unknown2);
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_RemoveFtRoot(struct ndr_push *ndr, int flags, const struct dfs_RemoveFtRoot *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.servername, ndr_charset_length(r->in.servername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dns_servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dns_servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.dns_servername, ndr_charset_length(r->in.dns_servername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dfsname, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dfsname, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.dfsname, ndr_charset_length(r->in.dfsname, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.rootshare, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.rootshare, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.rootshare, ndr_charset_length(r->in.rootshare, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.flags));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.unknown));
+ if (r->in.unknown) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->in.unknown));
+ if (*r->in.unknown) {
+ NDR_CHECK(ndr_push_dfs_UnknownStruct(ndr, NDR_SCALARS|NDR_BUFFERS, *r->in.unknown));
+ }
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.unknown));
+ if (r->out.unknown) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.unknown));
+ if (*r->out.unknown) {
+ NDR_CHECK(ndr_push_dfs_UnknownStruct(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.unknown));
+ }
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_RemoveFtRoot(struct ndr_pull *ndr, int flags, struct dfs_RemoveFtRoot *r)
+{
+ uint32_t _ptr_unknown;
+ TALLOC_CTX *_mem_save_unknown_0;
+ TALLOC_CTX *_mem_save_unknown_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.servername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.servername));
+ if (ndr_get_array_length(ndr, &r->in.servername) > ndr_get_array_size(ndr, &r->in.servername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.servername), ndr_get_array_length(ndr, &r->in.servername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.servername, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.dns_servername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.dns_servername));
+ if (ndr_get_array_length(ndr, &r->in.dns_servername) > ndr_get_array_size(ndr, &r->in.dns_servername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.dns_servername), ndr_get_array_length(ndr, &r->in.dns_servername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.dns_servername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.dns_servername, ndr_get_array_length(ndr, &r->in.dns_servername), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.dfsname));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.dfsname));
+ if (ndr_get_array_length(ndr, &r->in.dfsname) > ndr_get_array_size(ndr, &r->in.dfsname)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.dfsname), ndr_get_array_length(ndr, &r->in.dfsname));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.dfsname), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.dfsname, ndr_get_array_length(ndr, &r->in.dfsname), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.rootshare));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.rootshare));
+ if (ndr_get_array_length(ndr, &r->in.rootshare) > ndr_get_array_size(ndr, &r->in.rootshare)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.rootshare), ndr_get_array_length(ndr, &r->in.rootshare));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.rootshare), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.rootshare, ndr_get_array_length(ndr, &r->in.rootshare), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.flags));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown));
+ if (_ptr_unknown) {
+ NDR_PULL_ALLOC(ndr, r->in.unknown);
+ } else {
+ r->in.unknown = NULL;
+ }
+ if (r->in.unknown) {
+ _mem_save_unknown_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.unknown, 0);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown));
+ if (_ptr_unknown) {
+ NDR_PULL_ALLOC(ndr, *r->in.unknown);
+ } else {
+ *r->in.unknown = NULL;
+ }
+ if (*r->in.unknown) {
+ _mem_save_unknown_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->in.unknown, 0);
+ NDR_CHECK(ndr_pull_dfs_UnknownStruct(ndr, NDR_SCALARS|NDR_BUFFERS, *r->in.unknown));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown));
+ if (_ptr_unknown) {
+ NDR_PULL_ALLOC(ndr, r->out.unknown);
+ } else {
+ r->out.unknown = NULL;
+ }
+ if (r->out.unknown) {
+ _mem_save_unknown_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.unknown, 0);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown));
+ if (_ptr_unknown) {
+ NDR_PULL_ALLOC(ndr, *r->out.unknown);
+ } else {
+ *r->out.unknown = NULL;
+ }
+ if (*r->out.unknown) {
+ _mem_save_unknown_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.unknown, 0);
+ NDR_CHECK(ndr_pull_dfs_UnknownStruct(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.unknown));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_RemoveFtRoot(struct ndr_print *ndr, const char *name, int flags, const struct dfs_RemoveFtRoot *r)
+{
+ ndr_print_struct(ndr, name, "dfs_RemoveFtRoot");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_RemoveFtRoot");
+ ndr->depth++;
+ ndr_print_string(ndr, "servername", r->in.servername);
+ ndr_print_string(ndr, "dns_servername", r->in.dns_servername);
+ ndr_print_string(ndr, "dfsname", r->in.dfsname);
+ ndr_print_string(ndr, "rootshare", r->in.rootshare);
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr_print_ptr(ndr, "unknown", r->in.unknown);
+ ndr->depth++;
+ if (r->in.unknown) {
+ ndr_print_ptr(ndr, "unknown", *r->in.unknown);
+ ndr->depth++;
+ if (*r->in.unknown) {
+ ndr_print_dfs_UnknownStruct(ndr, "unknown", *r->in.unknown);
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_RemoveFtRoot");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "unknown", r->out.unknown);
+ ndr->depth++;
+ if (r->out.unknown) {
+ ndr_print_ptr(ndr, "unknown", *r->out.unknown);
+ ndr->depth++;
+ if (*r->out.unknown) {
+ ndr_print_dfs_UnknownStruct(ndr, "unknown", *r->out.unknown);
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_AddStdRoot(struct ndr_push *ndr, int flags, const struct dfs_AddStdRoot *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.servername, ndr_charset_length(r->in.servername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.rootshare, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.rootshare, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.rootshare, ndr_charset_length(r->in.rootshare, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.comment, ndr_charset_length(r->in.comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_AddStdRoot(struct ndr_pull *ndr, int flags, struct dfs_AddStdRoot *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.servername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.servername));
+ if (ndr_get_array_length(ndr, &r->in.servername) > ndr_get_array_size(ndr, &r->in.servername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.servername), ndr_get_array_length(ndr, &r->in.servername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.servername, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.rootshare));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.rootshare));
+ if (ndr_get_array_length(ndr, &r->in.rootshare) > ndr_get_array_size(ndr, &r->in.rootshare)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.rootshare), ndr_get_array_length(ndr, &r->in.rootshare));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.rootshare), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.rootshare, ndr_get_array_length(ndr, &r->in.rootshare), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.comment));
+ if (ndr_get_array_length(ndr, &r->in.comment) > ndr_get_array_size(ndr, &r->in.comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.comment), ndr_get_array_length(ndr, &r->in.comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.comment, ndr_get_array_length(ndr, &r->in.comment), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_AddStdRoot(struct ndr_print *ndr, const char *name, int flags, const struct dfs_AddStdRoot *r)
+{
+ ndr_print_struct(ndr, name, "dfs_AddStdRoot");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_AddStdRoot");
+ ndr->depth++;
+ ndr_print_string(ndr, "servername", r->in.servername);
+ ndr_print_string(ndr, "rootshare", r->in.rootshare);
+ ndr_print_string(ndr, "comment", r->in.comment);
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_AddStdRoot");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_RemoveStdRoot(struct ndr_push *ndr, int flags, const struct dfs_RemoveStdRoot *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.servername, ndr_charset_length(r->in.servername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.rootshare, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.rootshare, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.rootshare, ndr_charset_length(r->in.rootshare, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_RemoveStdRoot(struct ndr_pull *ndr, int flags, struct dfs_RemoveStdRoot *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.servername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.servername));
+ if (ndr_get_array_length(ndr, &r->in.servername) > ndr_get_array_size(ndr, &r->in.servername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.servername), ndr_get_array_length(ndr, &r->in.servername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.servername, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.rootshare));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.rootshare));
+ if (ndr_get_array_length(ndr, &r->in.rootshare) > ndr_get_array_size(ndr, &r->in.rootshare)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.rootshare), ndr_get_array_length(ndr, &r->in.rootshare));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.rootshare), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.rootshare, ndr_get_array_length(ndr, &r->in.rootshare), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_RemoveStdRoot(struct ndr_print *ndr, const char *name, int flags, const struct dfs_RemoveStdRoot *r)
+{
+ ndr_print_struct(ndr, name, "dfs_RemoveStdRoot");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_RemoveStdRoot");
+ ndr->depth++;
+ ndr_print_string(ndr, "servername", r->in.servername);
+ ndr_print_string(ndr, "rootshare", r->in.rootshare);
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_RemoveStdRoot");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_ManagerInitialize(struct ndr_push *ndr, int flags, const struct dfs_ManagerInitialize *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.servername == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.servername, ndr_charset_length(r->in.servername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_ManagerInitialize(struct ndr_pull *ndr, int flags, struct dfs_ManagerInitialize *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.servername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.servername));
+ if (ndr_get_array_length(ndr, &r->in.servername) > ndr_get_array_size(ndr, &r->in.servername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.servername), ndr_get_array_length(ndr, &r->in.servername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.servername, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_ManagerInitialize(struct ndr_print *ndr, const char *name, int flags, const struct dfs_ManagerInitialize *r)
+{
+ ndr_print_struct(ndr, name, "dfs_ManagerInitialize");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_ManagerInitialize");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "servername", r->in.servername);
+ ndr->depth++;
+ ndr_print_string(ndr, "servername", r->in.servername);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_ManagerInitialize");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_AddStdRootForced(struct ndr_push *ndr, int flags, const struct dfs_AddStdRootForced *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.servername, ndr_charset_length(r->in.servername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.rootshare, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.rootshare, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.rootshare, ndr_charset_length(r->in.rootshare, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.comment, ndr_charset_length(r->in.comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.store, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.store, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.store, ndr_charset_length(r->in.store, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_AddStdRootForced(struct ndr_pull *ndr, int flags, struct dfs_AddStdRootForced *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.servername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.servername));
+ if (ndr_get_array_length(ndr, &r->in.servername) > ndr_get_array_size(ndr, &r->in.servername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.servername), ndr_get_array_length(ndr, &r->in.servername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.servername, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.rootshare));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.rootshare));
+ if (ndr_get_array_length(ndr, &r->in.rootshare) > ndr_get_array_size(ndr, &r->in.rootshare)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.rootshare), ndr_get_array_length(ndr, &r->in.rootshare));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.rootshare), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.rootshare, ndr_get_array_length(ndr, &r->in.rootshare), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.comment));
+ if (ndr_get_array_length(ndr, &r->in.comment) > ndr_get_array_size(ndr, &r->in.comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.comment), ndr_get_array_length(ndr, &r->in.comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.comment, ndr_get_array_length(ndr, &r->in.comment), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.store));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.store));
+ if (ndr_get_array_length(ndr, &r->in.store) > ndr_get_array_size(ndr, &r->in.store)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.store), ndr_get_array_length(ndr, &r->in.store));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.store), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.store, ndr_get_array_length(ndr, &r->in.store), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_AddStdRootForced(struct ndr_print *ndr, const char *name, int flags, const struct dfs_AddStdRootForced *r)
+{
+ ndr_print_struct(ndr, name, "dfs_AddStdRootForced");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_AddStdRootForced");
+ ndr->depth++;
+ ndr_print_string(ndr, "servername", r->in.servername);
+ ndr_print_string(ndr, "rootshare", r->in.rootshare);
+ ndr_print_string(ndr, "comment", r->in.comment);
+ ndr_print_string(ndr, "store", r->in.store);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_AddStdRootForced");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_GetDcAddress(struct ndr_push *ndr, int flags, const struct dfs_GetDcAddress *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.servername, ndr_charset_length(r->in.servername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ if (r->in.server_fullname == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->in.server_fullname));
+ if (*r->in.server_fullname) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->in.server_fullname, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->in.server_fullname, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, *r->in.server_fullname, ndr_charset_length(*r->in.server_fullname, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.is_root == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, *r->in.is_root));
+ if (r->in.ttl == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.ttl));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.server_fullname == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.server_fullname));
+ if (*r->out.server_fullname) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.server_fullname, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.server_fullname, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, *r->out.server_fullname, ndr_charset_length(*r->out.server_fullname, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->out.is_root == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, *r->out.is_root));
+ if (r->out.ttl == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.ttl));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_GetDcAddress(struct ndr_pull *ndr, int flags, struct dfs_GetDcAddress *r)
+{
+ uint32_t _ptr_server_fullname;
+ TALLOC_CTX *_mem_save_server_fullname_0;
+ TALLOC_CTX *_mem_save_server_fullname_1;
+ TALLOC_CTX *_mem_save_is_root_0;
+ TALLOC_CTX *_mem_save_ttl_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.servername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.servername));
+ if (ndr_get_array_length(ndr, &r->in.servername) > ndr_get_array_size(ndr, &r->in.servername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.servername), ndr_get_array_length(ndr, &r->in.servername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.servername, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t), CH_UTF16));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.server_fullname);
+ }
+ _mem_save_server_fullname_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_fullname, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_fullname));
+ if (_ptr_server_fullname) {
+ NDR_PULL_ALLOC(ndr, *r->in.server_fullname);
+ } else {
+ *r->in.server_fullname = NULL;
+ }
+ if (*r->in.server_fullname) {
+ _mem_save_server_fullname_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->in.server_fullname, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->in.server_fullname));
+ NDR_CHECK(ndr_pull_array_length(ndr, r->in.server_fullname));
+ if (ndr_get_array_length(ndr, r->in.server_fullname) > ndr_get_array_size(ndr, r->in.server_fullname)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, r->in.server_fullname), ndr_get_array_length(ndr, r->in.server_fullname));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, r->in.server_fullname), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, r->in.server_fullname, ndr_get_array_length(ndr, r->in.server_fullname), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_fullname_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_fullname_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.is_root);
+ }
+ _mem_save_is_root_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.is_root, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, r->in.is_root));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_is_root_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.ttl);
+ }
+ _mem_save_ttl_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.ttl, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.ttl));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ttl_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.server_fullname);
+ *r->out.server_fullname = *r->in.server_fullname;
+ NDR_PULL_ALLOC(ndr, r->out.is_root);
+ *r->out.is_root = *r->in.is_root;
+ NDR_PULL_ALLOC(ndr, r->out.ttl);
+ *r->out.ttl = *r->in.ttl;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.server_fullname);
+ }
+ _mem_save_server_fullname_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.server_fullname, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_fullname));
+ if (_ptr_server_fullname) {
+ NDR_PULL_ALLOC(ndr, *r->out.server_fullname);
+ } else {
+ *r->out.server_fullname = NULL;
+ }
+ if (*r->out.server_fullname) {
+ _mem_save_server_fullname_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.server_fullname, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->out.server_fullname));
+ NDR_CHECK(ndr_pull_array_length(ndr, r->out.server_fullname));
+ if (ndr_get_array_length(ndr, r->out.server_fullname) > ndr_get_array_size(ndr, r->out.server_fullname)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, r->out.server_fullname), ndr_get_array_length(ndr, r->out.server_fullname));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, r->out.server_fullname), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, r->out.server_fullname, ndr_get_array_length(ndr, r->out.server_fullname), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_fullname_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_fullname_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.is_root);
+ }
+ _mem_save_is_root_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.is_root, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, r->out.is_root));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_is_root_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ttl);
+ }
+ _mem_save_ttl_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ttl, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.ttl));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ttl_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_GetDcAddress(struct ndr_print *ndr, const char *name, int flags, const struct dfs_GetDcAddress *r)
+{
+ ndr_print_struct(ndr, name, "dfs_GetDcAddress");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_GetDcAddress");
+ ndr->depth++;
+ ndr_print_string(ndr, "servername", r->in.servername);
+ ndr_print_ptr(ndr, "server_fullname", r->in.server_fullname);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_fullname", *r->in.server_fullname);
+ ndr->depth++;
+ if (*r->in.server_fullname) {
+ ndr_print_string(ndr, "server_fullname", *r->in.server_fullname);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "is_root", r->in.is_root);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "is_root", *r->in.is_root);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ttl", r->in.ttl);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "ttl", *r->in.ttl);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_GetDcAddress");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_fullname", r->out.server_fullname);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_fullname", *r->out.server_fullname);
+ ndr->depth++;
+ if (*r->out.server_fullname) {
+ ndr_print_string(ndr, "server_fullname", *r->out.server_fullname);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "is_root", r->out.is_root);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "is_root", *r->out.is_root);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ttl", r->out.ttl);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "ttl", *r->out.ttl);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_SetDcAddress(struct ndr_push *ndr, int flags, const struct dfs_SetDcAddress *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.servername, ndr_charset_length(r->in.servername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_fullname, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_fullname, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_fullname, ndr_charset_length(r->in.server_fullname, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.ttl));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_SetDcAddress(struct ndr_pull *ndr, int flags, struct dfs_SetDcAddress *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.servername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.servername));
+ if (ndr_get_array_length(ndr, &r->in.servername) > ndr_get_array_size(ndr, &r->in.servername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.servername), ndr_get_array_length(ndr, &r->in.servername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.servername, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_fullname));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_fullname));
+ if (ndr_get_array_length(ndr, &r->in.server_fullname) > ndr_get_array_size(ndr, &r->in.server_fullname)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_fullname), ndr_get_array_length(ndr, &r->in.server_fullname));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_fullname), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_fullname, ndr_get_array_length(ndr, &r->in.server_fullname), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.ttl));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_SetDcAddress(struct ndr_print *ndr, const char *name, int flags, const struct dfs_SetDcAddress *r)
+{
+ ndr_print_struct(ndr, name, "dfs_SetDcAddress");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_SetDcAddress");
+ ndr->depth++;
+ ndr_print_string(ndr, "servername", r->in.servername);
+ ndr_print_string(ndr, "server_fullname", r->in.server_fullname);
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr_print_uint32(ndr, "ttl", r->in.ttl);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_SetDcAddress");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_FlushFtTable(struct ndr_push *ndr, int flags, const struct dfs_FlushFtTable *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.servername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.servername, ndr_charset_length(r->in.servername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.rootshare, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.rootshare, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.rootshare, ndr_charset_length(r->in.rootshare, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_FlushFtTable(struct ndr_pull *ndr, int flags, struct dfs_FlushFtTable *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.servername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.servername));
+ if (ndr_get_array_length(ndr, &r->in.servername) > ndr_get_array_size(ndr, &r->in.servername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.servername), ndr_get_array_length(ndr, &r->in.servername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.servername, ndr_get_array_length(ndr, &r->in.servername), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.rootshare));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.rootshare));
+ if (ndr_get_array_length(ndr, &r->in.rootshare) > ndr_get_array_size(ndr, &r->in.rootshare)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.rootshare), ndr_get_array_length(ndr, &r->in.rootshare));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.rootshare), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.rootshare, ndr_get_array_length(ndr, &r->in.rootshare), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_FlushFtTable(struct ndr_print *ndr, const char *name, int flags, const struct dfs_FlushFtTable *r)
+{
+ ndr_print_struct(ndr, name, "dfs_FlushFtTable");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_FlushFtTable");
+ ndr->depth++;
+ ndr_print_string(ndr, "servername", r->in.servername);
+ ndr_print_string(ndr, "rootshare", r->in.rootshare);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_FlushFtTable");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Add2(struct ndr_push *ndr, int flags, const struct dfs_Add2 *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Add2(struct ndr_pull *ndr, int flags, struct dfs_Add2 *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Add2(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Add2 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Add2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_Add2");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_Add2");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_Remove2(struct ndr_push *ndr, int flags, const struct dfs_Remove2 *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_Remove2(struct ndr_pull *ndr, int flags, struct dfs_Remove2 *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_Remove2(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Remove2 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_Remove2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_Remove2");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_Remove2");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_dfs_EnumEx(struct ndr_push *ndr, int flags, const struct dfs_EnumEx *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dfs_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dfs_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.dfs_name, ndr_charset_length(r->in.dfs_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.bufsize));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.info));
+ if (r->in.info) {
+ NDR_CHECK(ndr_push_dfs_EnumStruct(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.total));
+ if (r->in.total) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.total));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.info));
+ if (r->out.info) {
+ NDR_CHECK(ndr_push_dfs_EnumStruct(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.total));
+ if (r->out.total) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.total));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_dfs_EnumEx(struct ndr_pull *ndr, int flags, struct dfs_EnumEx *r)
+{
+ uint32_t _ptr_info;
+ uint32_t _ptr_total;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_total_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.dfs_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.dfs_name));
+ if (ndr_get_array_length(ndr, &r->in.dfs_name) > ndr_get_array_size(ndr, &r->in.dfs_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.dfs_name), ndr_get_array_length(ndr, &r->in.dfs_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.dfs_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.dfs_name, ndr_get_array_length(ndr, &r->in.dfs_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.bufsize));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ } else {
+ r->in.info = NULL;
+ }
+ if (r->in.info) {
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, 0);
+ NDR_CHECK(ndr_pull_dfs_EnumStruct(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_total));
+ if (_ptr_total) {
+ NDR_PULL_ALLOC(ndr, r->in.total);
+ } else {
+ r->in.total = NULL;
+ }
+ if (r->in.total) {
+ _mem_save_total_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.total, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.total));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_total_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ } else {
+ r->out.info = NULL;
+ }
+ if (r->out.info) {
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, 0);
+ NDR_CHECK(ndr_pull_dfs_EnumStruct(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_total));
+ if (_ptr_total) {
+ NDR_PULL_ALLOC(ndr, r->out.total);
+ } else {
+ r->out.total = NULL;
+ }
+ if (r->out.total) {
+ _mem_save_total_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.total, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.total));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_total_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_EnumEx(struct ndr_print *ndr, const char *name, int flags, const struct dfs_EnumEx *r)
+{
+ ndr_print_struct(ndr, name, "dfs_EnumEx");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_EnumEx");
+ ndr->depth++;
+ ndr_print_string(ndr, "dfs_name", r->in.dfs_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "bufsize", r->in.bufsize);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ if (r->in.info) {
+ ndr_print_dfs_EnumStruct(ndr, "info", r->in.info);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "total", r->in.total);
+ ndr->depth++;
+ if (r->in.total) {
+ ndr_print_uint32(ndr, "total", *r->in.total);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_EnumEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ if (r->out.info) {
+ ndr_print_dfs_EnumStruct(ndr, "info", r->out.info);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "total", r->out.total);
+ ndr->depth++;
+ if (r->out.total) {
+ ndr_print_uint32(ndr, "total", *r->out.total);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dfs_SetInfo2(struct ndr_push *ndr, int flags, const struct dfs_SetInfo2 *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dfs_SetInfo2(struct ndr_pull *ndr, int flags, struct dfs_SetInfo2 *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dfs_SetInfo2(struct ndr_print *ndr, const char *name, int flags, const struct dfs_SetInfo2 *r)
+{
+ ndr_print_struct(ndr, name, "dfs_SetInfo2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dfs_SetInfo2");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dfs_SetInfo2");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call netdfs_calls[] = {
+ {
+ "dfs_GetManagerVersion",
+ sizeof(struct dfs_GetManagerVersion),
+ (ndr_push_flags_fn_t) ndr_push_dfs_GetManagerVersion,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_GetManagerVersion,
+ (ndr_print_function_t) ndr_print_dfs_GetManagerVersion,
+ false,
+ },
+ {
+ "dfs_Add",
+ sizeof(struct dfs_Add),
+ (ndr_push_flags_fn_t) ndr_push_dfs_Add,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_Add,
+ (ndr_print_function_t) ndr_print_dfs_Add,
+ false,
+ },
+ {
+ "dfs_Remove",
+ sizeof(struct dfs_Remove),
+ (ndr_push_flags_fn_t) ndr_push_dfs_Remove,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_Remove,
+ (ndr_print_function_t) ndr_print_dfs_Remove,
+ false,
+ },
+ {
+ "dfs_SetInfo",
+ sizeof(struct dfs_SetInfo),
+ (ndr_push_flags_fn_t) ndr_push_dfs_SetInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_SetInfo,
+ (ndr_print_function_t) ndr_print_dfs_SetInfo,
+ false,
+ },
+ {
+ "dfs_GetInfo",
+ sizeof(struct dfs_GetInfo),
+ (ndr_push_flags_fn_t) ndr_push_dfs_GetInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_GetInfo,
+ (ndr_print_function_t) ndr_print_dfs_GetInfo,
+ false,
+ },
+ {
+ "dfs_Enum",
+ sizeof(struct dfs_Enum),
+ (ndr_push_flags_fn_t) ndr_push_dfs_Enum,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_Enum,
+ (ndr_print_function_t) ndr_print_dfs_Enum,
+ false,
+ },
+ {
+ "dfs_Rename",
+ sizeof(struct dfs_Rename),
+ (ndr_push_flags_fn_t) ndr_push_dfs_Rename,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_Rename,
+ (ndr_print_function_t) ndr_print_dfs_Rename,
+ false,
+ },
+ {
+ "dfs_Move",
+ sizeof(struct dfs_Move),
+ (ndr_push_flags_fn_t) ndr_push_dfs_Move,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_Move,
+ (ndr_print_function_t) ndr_print_dfs_Move,
+ false,
+ },
+ {
+ "dfs_ManagerGetConfigInfo",
+ sizeof(struct dfs_ManagerGetConfigInfo),
+ (ndr_push_flags_fn_t) ndr_push_dfs_ManagerGetConfigInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_ManagerGetConfigInfo,
+ (ndr_print_function_t) ndr_print_dfs_ManagerGetConfigInfo,
+ false,
+ },
+ {
+ "dfs_ManagerSendSiteInfo",
+ sizeof(struct dfs_ManagerSendSiteInfo),
+ (ndr_push_flags_fn_t) ndr_push_dfs_ManagerSendSiteInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_ManagerSendSiteInfo,
+ (ndr_print_function_t) ndr_print_dfs_ManagerSendSiteInfo,
+ false,
+ },
+ {
+ "dfs_AddFtRoot",
+ sizeof(struct dfs_AddFtRoot),
+ (ndr_push_flags_fn_t) ndr_push_dfs_AddFtRoot,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_AddFtRoot,
+ (ndr_print_function_t) ndr_print_dfs_AddFtRoot,
+ false,
+ },
+ {
+ "dfs_RemoveFtRoot",
+ sizeof(struct dfs_RemoveFtRoot),
+ (ndr_push_flags_fn_t) ndr_push_dfs_RemoveFtRoot,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_RemoveFtRoot,
+ (ndr_print_function_t) ndr_print_dfs_RemoveFtRoot,
+ false,
+ },
+ {
+ "dfs_AddStdRoot",
+ sizeof(struct dfs_AddStdRoot),
+ (ndr_push_flags_fn_t) ndr_push_dfs_AddStdRoot,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_AddStdRoot,
+ (ndr_print_function_t) ndr_print_dfs_AddStdRoot,
+ false,
+ },
+ {
+ "dfs_RemoveStdRoot",
+ sizeof(struct dfs_RemoveStdRoot),
+ (ndr_push_flags_fn_t) ndr_push_dfs_RemoveStdRoot,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_RemoveStdRoot,
+ (ndr_print_function_t) ndr_print_dfs_RemoveStdRoot,
+ false,
+ },
+ {
+ "dfs_ManagerInitialize",
+ sizeof(struct dfs_ManagerInitialize),
+ (ndr_push_flags_fn_t) ndr_push_dfs_ManagerInitialize,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_ManagerInitialize,
+ (ndr_print_function_t) ndr_print_dfs_ManagerInitialize,
+ false,
+ },
+ {
+ "dfs_AddStdRootForced",
+ sizeof(struct dfs_AddStdRootForced),
+ (ndr_push_flags_fn_t) ndr_push_dfs_AddStdRootForced,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_AddStdRootForced,
+ (ndr_print_function_t) ndr_print_dfs_AddStdRootForced,
+ false,
+ },
+ {
+ "dfs_GetDcAddress",
+ sizeof(struct dfs_GetDcAddress),
+ (ndr_push_flags_fn_t) ndr_push_dfs_GetDcAddress,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_GetDcAddress,
+ (ndr_print_function_t) ndr_print_dfs_GetDcAddress,
+ false,
+ },
+ {
+ "dfs_SetDcAddress",
+ sizeof(struct dfs_SetDcAddress),
+ (ndr_push_flags_fn_t) ndr_push_dfs_SetDcAddress,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_SetDcAddress,
+ (ndr_print_function_t) ndr_print_dfs_SetDcAddress,
+ false,
+ },
+ {
+ "dfs_FlushFtTable",
+ sizeof(struct dfs_FlushFtTable),
+ (ndr_push_flags_fn_t) ndr_push_dfs_FlushFtTable,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_FlushFtTable,
+ (ndr_print_function_t) ndr_print_dfs_FlushFtTable,
+ false,
+ },
+ {
+ "dfs_Add2",
+ sizeof(struct dfs_Add2),
+ (ndr_push_flags_fn_t) ndr_push_dfs_Add2,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_Add2,
+ (ndr_print_function_t) ndr_print_dfs_Add2,
+ false,
+ },
+ {
+ "dfs_Remove2",
+ sizeof(struct dfs_Remove2),
+ (ndr_push_flags_fn_t) ndr_push_dfs_Remove2,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_Remove2,
+ (ndr_print_function_t) ndr_print_dfs_Remove2,
+ false,
+ },
+ {
+ "dfs_EnumEx",
+ sizeof(struct dfs_EnumEx),
+ (ndr_push_flags_fn_t) ndr_push_dfs_EnumEx,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_EnumEx,
+ (ndr_print_function_t) ndr_print_dfs_EnumEx,
+ false,
+ },
+ {
+ "dfs_SetInfo2",
+ sizeof(struct dfs_SetInfo2),
+ (ndr_push_flags_fn_t) ndr_push_dfs_SetInfo2,
+ (ndr_pull_flags_fn_t) ndr_pull_dfs_SetInfo2,
+ (ndr_print_function_t) ndr_print_dfs_SetInfo2,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const netdfs_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\netdfs]",
+ "ncacn_ip_tcp:",
+ "ncalrpc:",
+};
+
+static const struct ndr_interface_string_array netdfs_endpoints = {
+ .count = 3,
+ .names = netdfs_endpoint_strings
+};
+
+static const char * const netdfs_authservice_strings[] = {
+ "host",
+};
+
+static const struct ndr_interface_string_array netdfs_authservices = {
+ .count = 1,
+ .names = netdfs_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_netdfs = {
+ .name = "netdfs",
+ .syntax_id = {
+ {0x4fc742e0,0x4a10,0x11cf,{0x82,0x73},{0x00,0xaa,0x00,0x4a,0xe6,0x73}},
+ NDR_NETDFS_VERSION
+ },
+ .helpstring = NDR_NETDFS_HELPSTRING,
+ .num_calls = 23,
+ .calls = netdfs_calls,
+ .endpoints = &netdfs_endpoints,
+ .authservices = &netdfs_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_dfs.h b/source3/librpc/gen_ndr/ndr_dfs.h
new file mode 100644
index 0000000000..a7c66f9693
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_dfs.h
@@ -0,0 +1,132 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/dfs.h"
+
+#ifndef _HEADER_NDR_netdfs
+#define _HEADER_NDR_netdfs
+
+#define NDR_NETDFS_UUID "4fc742e0-4a10-11cf-8273-00aa004ae673"
+#define NDR_NETDFS_VERSION 3.0
+#define NDR_NETDFS_NAME "netdfs"
+#define NDR_NETDFS_HELPSTRING "Settings for Microsoft Distributed File System"
+extern const struct ndr_interface_table ndr_table_netdfs;
+#define NDR_DFS_GETMANAGERVERSION (0x00)
+
+#define NDR_DFS_ADD (0x01)
+
+#define NDR_DFS_REMOVE (0x02)
+
+#define NDR_DFS_SETINFO (0x03)
+
+#define NDR_DFS_GETINFO (0x04)
+
+#define NDR_DFS_ENUM (0x05)
+
+#define NDR_DFS_RENAME (0x06)
+
+#define NDR_DFS_MOVE (0x07)
+
+#define NDR_DFS_MANAGERGETCONFIGINFO (0x08)
+
+#define NDR_DFS_MANAGERSENDSITEINFO (0x09)
+
+#define NDR_DFS_ADDFTROOT (0x0a)
+
+#define NDR_DFS_REMOVEFTROOT (0x0b)
+
+#define NDR_DFS_ADDSTDROOT (0x0c)
+
+#define NDR_DFS_REMOVESTDROOT (0x0d)
+
+#define NDR_DFS_MANAGERINITIALIZE (0x0e)
+
+#define NDR_DFS_ADDSTDROOTFORCED (0x0f)
+
+#define NDR_DFS_GETDCADDRESS (0x10)
+
+#define NDR_DFS_SETDCADDRESS (0x11)
+
+#define NDR_DFS_FLUSHFTTABLE (0x12)
+
+#define NDR_DFS_ADD2 (0x13)
+
+#define NDR_DFS_REMOVE2 (0x14)
+
+#define NDR_DFS_ENUMEX (0x15)
+
+#define NDR_DFS_SETINFO2 (0x16)
+
+#define NDR_NETDFS_CALL_COUNT (23)
+void ndr_print_dfs_ManagerVersion(struct ndr_print *ndr, const char *name, enum dfs_ManagerVersion r);
+void ndr_print_dfs_Info0(struct ndr_print *ndr, const char *name, const struct dfs_Info0 *r);
+void ndr_print_dfs_Info1(struct ndr_print *ndr, const char *name, const struct dfs_Info1 *r);
+enum ndr_err_code ndr_push_dfs_VolumeState(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_dfs_VolumeState(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_dfs_VolumeState(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_dfs_Info2(struct ndr_print *ndr, const char *name, const struct dfs_Info2 *r);
+enum ndr_err_code ndr_push_dfs_StorageState(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_dfs_StorageState(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_dfs_StorageState(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_dfs_StorageInfo(struct ndr_print *ndr, const char *name, const struct dfs_StorageInfo *r);
+void ndr_print_dfs_Info3(struct ndr_print *ndr, const char *name, const struct dfs_Info3 *r);
+void ndr_print_dfs_Info4(struct ndr_print *ndr, const char *name, const struct dfs_Info4 *r);
+enum ndr_err_code ndr_push_dfs_PropertyFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_dfs_PropertyFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_dfs_PropertyFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_dfs_Info5(struct ndr_print *ndr, const char *name, const struct dfs_Info5 *r);
+void ndr_print_dfs_Target_PriorityClass(struct ndr_print *ndr, const char *name, enum dfs_Target_PriorityClass r);
+void ndr_print_dfs_Target_Priority(struct ndr_print *ndr, const char *name, const struct dfs_Target_Priority *r);
+void ndr_print_dfs_StorageInfo2(struct ndr_print *ndr, const char *name, const struct dfs_StorageInfo2 *r);
+void ndr_print_dfs_Info6(struct ndr_print *ndr, const char *name, const struct dfs_Info6 *r);
+void ndr_print_dfs_Info7(struct ndr_print *ndr, const char *name, const struct dfs_Info7 *r);
+void ndr_print_dfs_Info100(struct ndr_print *ndr, const char *name, const struct dfs_Info100 *r);
+void ndr_print_dfs_Info101(struct ndr_print *ndr, const char *name, const struct dfs_Info101 *r);
+void ndr_print_dfs_Info102(struct ndr_print *ndr, const char *name, const struct dfs_Info102 *r);
+void ndr_print_dfs_Info103(struct ndr_print *ndr, const char *name, const struct dfs_Info103 *r);
+void ndr_print_dfs_Info104(struct ndr_print *ndr, const char *name, const struct dfs_Info104 *r);
+void ndr_print_dfs_Info105(struct ndr_print *ndr, const char *name, const struct dfs_Info105 *r);
+void ndr_print_dfs_Info106(struct ndr_print *ndr, const char *name, const struct dfs_Info106 *r);
+void ndr_print_dfs_Info200(struct ndr_print *ndr, const char *name, const struct dfs_Info200 *r);
+void ndr_print_dfs_VolumeFlavor(struct ndr_print *ndr, const char *name, enum dfs_VolumeFlavor r);
+void ndr_print_dfs_Info300(struct ndr_print *ndr, const char *name, const struct dfs_Info300 *r);
+void ndr_print_dfs_Info(struct ndr_print *ndr, const char *name, const union dfs_Info *r);
+void ndr_print_dfs_EnumArray1(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray1 *r);
+void ndr_print_dfs_EnumArray2(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray2 *r);
+void ndr_print_dfs_EnumArray3(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray3 *r);
+void ndr_print_dfs_EnumArray4(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray4 *r);
+void ndr_print_dfs_EnumArray5(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray5 *r);
+void ndr_print_dfs_EnumArray6(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray6 *r);
+void ndr_print_dfs_EnumArray200(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray200 *r);
+void ndr_print_dfs_EnumArray300(struct ndr_print *ndr, const char *name, const struct dfs_EnumArray300 *r);
+void ndr_print_dfs_EnumInfo(struct ndr_print *ndr, const char *name, const union dfs_EnumInfo *r);
+void ndr_print_dfs_EnumStruct(struct ndr_print *ndr, const char *name, const struct dfs_EnumStruct *r);
+void ndr_print_dfs_UnknownStruct(struct ndr_print *ndr, const char *name, const struct dfs_UnknownStruct *r);
+enum ndr_err_code ndr_push_dfs_GetManagerVersion(struct ndr_push *ndr, int flags, const struct dfs_GetManagerVersion *r);
+enum ndr_err_code ndr_pull_dfs_GetManagerVersion(struct ndr_pull *ndr, int flags, struct dfs_GetManagerVersion *r);
+void ndr_print_dfs_GetManagerVersion(struct ndr_print *ndr, const char *name, int flags, const struct dfs_GetManagerVersion *r);
+void ndr_print_dfs_Add(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Add *r);
+void ndr_print_dfs_Remove(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Remove *r);
+void ndr_print_dfs_SetInfo(struct ndr_print *ndr, const char *name, int flags, const struct dfs_SetInfo *r);
+void ndr_print_dfs_GetInfo(struct ndr_print *ndr, const char *name, int flags, const struct dfs_GetInfo *r);
+void ndr_print_dfs_Enum(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Enum *r);
+void ndr_print_dfs_Rename(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Rename *r);
+void ndr_print_dfs_Move(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Move *r);
+void ndr_print_dfs_ManagerGetConfigInfo(struct ndr_print *ndr, const char *name, int flags, const struct dfs_ManagerGetConfigInfo *r);
+void ndr_print_dfs_ManagerSendSiteInfo(struct ndr_print *ndr, const char *name, int flags, const struct dfs_ManagerSendSiteInfo *r);
+void ndr_print_dfs_AddFtRoot(struct ndr_print *ndr, const char *name, int flags, const struct dfs_AddFtRoot *r);
+void ndr_print_dfs_RemoveFtRoot(struct ndr_print *ndr, const char *name, int flags, const struct dfs_RemoveFtRoot *r);
+void ndr_print_dfs_AddStdRoot(struct ndr_print *ndr, const char *name, int flags, const struct dfs_AddStdRoot *r);
+void ndr_print_dfs_RemoveStdRoot(struct ndr_print *ndr, const char *name, int flags, const struct dfs_RemoveStdRoot *r);
+void ndr_print_dfs_ManagerInitialize(struct ndr_print *ndr, const char *name, int flags, const struct dfs_ManagerInitialize *r);
+void ndr_print_dfs_AddStdRootForced(struct ndr_print *ndr, const char *name, int flags, const struct dfs_AddStdRootForced *r);
+void ndr_print_dfs_GetDcAddress(struct ndr_print *ndr, const char *name, int flags, const struct dfs_GetDcAddress *r);
+void ndr_print_dfs_SetDcAddress(struct ndr_print *ndr, const char *name, int flags, const struct dfs_SetDcAddress *r);
+void ndr_print_dfs_FlushFtTable(struct ndr_print *ndr, const char *name, int flags, const struct dfs_FlushFtTable *r);
+void ndr_print_dfs_Add2(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Add2 *r);
+void ndr_print_dfs_Remove2(struct ndr_print *ndr, const char *name, int flags, const struct dfs_Remove2 *r);
+enum ndr_err_code ndr_push_dfs_EnumEx(struct ndr_push *ndr, int flags, const struct dfs_EnumEx *r);
+enum ndr_err_code ndr_pull_dfs_EnumEx(struct ndr_pull *ndr, int flags, struct dfs_EnumEx *r);
+void ndr_print_dfs_EnumEx(struct ndr_print *ndr, const char *name, int flags, const struct dfs_EnumEx *r);
+void ndr_print_dfs_SetInfo2(struct ndr_print *ndr, const char *name, int flags, const struct dfs_SetInfo2 *r);
+#endif /* _HEADER_NDR_netdfs */
diff --git a/source3/librpc/gen_ndr/ndr_drsblobs.c b/source3/librpc/gen_ndr/ndr_drsblobs.c
new file mode 100644
index 0000000000..41a448cbe3
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_drsblobs.c
@@ -0,0 +1,3534 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+
+#include "librpc/gen_ndr/ndr_drsuapi.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+static enum ndr_err_code ndr_push_replPropertyMetaData1(struct ndr_push *ndr, int ndr_flags, const struct replPropertyMetaData1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_drsuapi_DsAttributeId(ndr, NDR_SCALARS, r->attid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version));
+ NDR_CHECK(ndr_push_NTTIME_1sec(ndr, NDR_SCALARS, r->originating_change_time));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->originating_invocation_id));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->originating_usn));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->local_usn));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_replPropertyMetaData1(struct ndr_pull *ndr, int ndr_flags, struct replPropertyMetaData1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_drsuapi_DsAttributeId(ndr, NDR_SCALARS, &r->attid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_NTTIME_1sec(ndr, NDR_SCALARS, &r->originating_change_time));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->originating_invocation_id));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->originating_usn));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->local_usn));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_replPropertyMetaData1(struct ndr_print *ndr, const char *name, const struct replPropertyMetaData1 *r)
+{
+ ndr_print_struct(ndr, name, "replPropertyMetaData1");
+ ndr->depth++;
+ ndr_print_drsuapi_DsAttributeId(ndr, "attid", r->attid);
+ ndr_print_uint32(ndr, "version", r->version);
+ ndr_print_NTTIME_1sec(ndr, "originating_change_time", r->originating_change_time);
+ ndr_print_GUID(ndr, "originating_invocation_id", &r->originating_invocation_id);
+ ndr_print_hyper(ndr, "originating_usn", r->originating_usn);
+ ndr_print_hyper(ndr, "local_usn", r->local_usn);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_replPropertyMetaDataCtr1(struct ndr_push *ndr, int ndr_flags, const struct replPropertyMetaDataCtr1 *r)
+{
+ uint32_t cntr_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_replPropertyMetaData1(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_replPropertyMetaDataCtr1(struct ndr_pull *ndr, int ndr_flags, struct replPropertyMetaDataCtr1 *r)
+{
+ uint32_t cntr_array_0;
+ TALLOC_CTX *_mem_save_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_PULL_ALLOC_N(ndr, r->array, r->count);
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_replPropertyMetaData1(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_replPropertyMetaDataCtr1(struct ndr_print *ndr, const char *name, const struct replPropertyMetaDataCtr1 *r)
+{
+ uint32_t cntr_array_0;
+ ndr_print_struct(ndr, name, "replPropertyMetaDataCtr1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_0=0;cntr_array_0<r->count;cntr_array_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_array_0) != -1) {
+ ndr_print_replPropertyMetaData1(ndr, "array", &r->array[cntr_array_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_replPropertyMetaDataCtr(struct ndr_push *ndr, int ndr_flags, const union replPropertyMetaDataCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_replPropertyMetaDataCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_replPropertyMetaDataCtr(struct ndr_pull *ndr, int ndr_flags, union replPropertyMetaDataCtr *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_replPropertyMetaDataCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_replPropertyMetaDataCtr(struct ndr_print *ndr, const char *name, const union replPropertyMetaDataCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "replPropertyMetaDataCtr");
+ switch (level) {
+ case 1:
+ ndr_print_replPropertyMetaDataCtr1(ndr, "ctr1", &r->ctr1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_replPropertyMetaDataBlob(struct ndr_push *ndr, int ndr_flags, const struct replPropertyMetaDataBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->ctr, r->version));
+ NDR_CHECK(ndr_push_replPropertyMetaDataCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_replPropertyMetaDataBlob(struct ndr_pull *ndr, int ndr_flags, struct replPropertyMetaDataBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->ctr, r->version));
+ NDR_CHECK(ndr_pull_replPropertyMetaDataCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_replPropertyMetaDataBlob(struct ndr_print *ndr, const char *name, const struct replPropertyMetaDataBlob *r)
+{
+ ndr_print_struct(ndr, name, "replPropertyMetaDataBlob");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "version", r->version);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr_print_set_switch_value(ndr, &r->ctr, r->version);
+ ndr_print_replPropertyMetaDataCtr(ndr, "ctr", &r->ctr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_replUpToDateVectorCtr1(struct ndr_push *ndr, int ndr_flags, const struct replUpToDateVectorCtr1 *r)
+{
+ uint32_t cntr_cursors_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ for (cntr_cursors_0 = 0; cntr_cursors_0 < r->count; cntr_cursors_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaCursor(ndr, NDR_SCALARS, &r->cursors[cntr_cursors_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_replUpToDateVectorCtr1(struct ndr_pull *ndr, int ndr_flags, struct replUpToDateVectorCtr1 *r)
+{
+ uint32_t cntr_cursors_0;
+ TALLOC_CTX *_mem_save_cursors_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_PULL_ALLOC_N(ndr, r->cursors, r->count);
+ _mem_save_cursors_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->cursors, 0);
+ for (cntr_cursors_0 = 0; cntr_cursors_0 < r->count; cntr_cursors_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaCursor(ndr, NDR_SCALARS, &r->cursors[cntr_cursors_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cursors_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_replUpToDateVectorCtr1(struct ndr_print *ndr, const char *name, const struct replUpToDateVectorCtr1 *r)
+{
+ uint32_t cntr_cursors_0;
+ ndr_print_struct(ndr, name, "replUpToDateVectorCtr1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr->print(ndr, "%s: ARRAY(%d)", "cursors", (int)r->count);
+ ndr->depth++;
+ for (cntr_cursors_0=0;cntr_cursors_0<r->count;cntr_cursors_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_cursors_0) != -1) {
+ ndr_print_drsuapi_DsReplicaCursor(ndr, "cursors", &r->cursors[cntr_cursors_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_replUpToDateVectorCtr2(struct ndr_push *ndr, int ndr_flags, const struct replUpToDateVectorCtr2 *r)
+{
+ uint32_t cntr_cursors_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ for (cntr_cursors_0 = 0; cntr_cursors_0 < r->count; cntr_cursors_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaCursor2(ndr, NDR_SCALARS, &r->cursors[cntr_cursors_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_replUpToDateVectorCtr2(struct ndr_pull *ndr, int ndr_flags, struct replUpToDateVectorCtr2 *r)
+{
+ uint32_t cntr_cursors_0;
+ TALLOC_CTX *_mem_save_cursors_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_PULL_ALLOC_N(ndr, r->cursors, r->count);
+ _mem_save_cursors_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->cursors, 0);
+ for (cntr_cursors_0 = 0; cntr_cursors_0 < r->count; cntr_cursors_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaCursor2(ndr, NDR_SCALARS, &r->cursors[cntr_cursors_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cursors_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_replUpToDateVectorCtr2(struct ndr_print *ndr, const char *name, const struct replUpToDateVectorCtr2 *r)
+{
+ uint32_t cntr_cursors_0;
+ ndr_print_struct(ndr, name, "replUpToDateVectorCtr2");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr->print(ndr, "%s: ARRAY(%d)", "cursors", (int)r->count);
+ ndr->depth++;
+ for (cntr_cursors_0=0;cntr_cursors_0<r->count;cntr_cursors_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_cursors_0) != -1) {
+ ndr_print_drsuapi_DsReplicaCursor2(ndr, "cursors", &r->cursors[cntr_cursors_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_replUpToDateVectorCtr(struct ndr_push *ndr, int ndr_flags, const union replUpToDateVectorCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_replUpToDateVectorCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_replUpToDateVectorCtr2(ndr, NDR_SCALARS, &r->ctr2));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ break;
+
+ case 2:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_replUpToDateVectorCtr(struct ndr_pull *ndr, int ndr_flags, union replUpToDateVectorCtr *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_replUpToDateVectorCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_pull_replUpToDateVectorCtr2(ndr, NDR_SCALARS, &r->ctr2));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ break;
+
+ case 2:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_replUpToDateVectorCtr(struct ndr_print *ndr, const char *name, const union replUpToDateVectorCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "replUpToDateVectorCtr");
+ switch (level) {
+ case 1:
+ ndr_print_replUpToDateVectorCtr1(ndr, "ctr1", &r->ctr1);
+ break;
+
+ case 2:
+ ndr_print_replUpToDateVectorCtr2(ndr, "ctr2", &r->ctr2);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_replUpToDateVectorBlob(struct ndr_push *ndr, int ndr_flags, const struct replUpToDateVectorBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->ctr, r->version));
+ NDR_CHECK(ndr_push_replUpToDateVectorCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_replUpToDateVectorBlob(struct ndr_pull *ndr, int ndr_flags, struct replUpToDateVectorBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->ctr, r->version));
+ NDR_CHECK(ndr_pull_replUpToDateVectorCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_replUpToDateVectorBlob(struct ndr_print *ndr, const char *name, const struct replUpToDateVectorBlob *r)
+{
+ ndr_print_struct(ndr, name, "replUpToDateVectorBlob");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "version", r->version);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr_print_set_switch_value(ndr, &r->ctr, r->version);
+ ndr_print_replUpToDateVectorCtr(ndr, "ctr", &r->ctr);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_repsFromTo1OtherInfo(struct ndr_push *ndr, int ndr_flags, const struct repsFromTo1OtherInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, strlen(r->dns_name) + 1));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dns_name, strlen(r->dns_name) + 1, sizeof(uint8_t), CH_DOS));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_repsFromTo1OtherInfo(struct ndr_pull *ndr, int ndr_flags, struct repsFromTo1OtherInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__dns_name_size));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dns_name, r->__dns_name_size, sizeof(uint8_t), CH_DOS));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_repsFromTo1OtherInfo(struct ndr_print *ndr, const char *name, const struct repsFromTo1OtherInfo *r)
+{
+ ndr_print_struct(ndr, name, "repsFromTo1OtherInfo");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "__dns_name_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen(r->dns_name) + 1:r->__dns_name_size);
+ ndr_print_string(ndr, "dns_name", r->dns_name);
+ ndr->depth--;
+}
+
+_PUBLIC_ size_t ndr_size_repsFromTo1OtherInfo(const struct repsFromTo1OtherInfo *r, int flags)
+{
+ return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_repsFromTo1OtherInfo);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_repsFromTo1(struct ndr_push *ndr, int ndr_flags, const struct repsFromTo1 *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_repsFromTo1(r, ndr->flags) + 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->consecutive_sync_failures));
+ NDR_CHECK(ndr_push_NTTIME_1sec(ndr, NDR_SCALARS, r->last_success));
+ NDR_CHECK(ndr_push_NTTIME_1sec(ndr, NDR_SCALARS, r->last_attempt));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->result_last_attempt));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->other_info));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_repsFromTo1OtherInfo(r->other_info, ndr->flags)));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaNeighbourFlags(ndr, NDR_SCALARS, r->replica_flags));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->schedule, 84));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaHighWaterMark(ndr, NDR_SCALARS, &r->highwatermark));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->source_dsa_obj_guid));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->transport_guid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->other_info) {
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, r->other_info));
+ NDR_CHECK(ndr_push_repsFromTo1OtherInfo(ndr, NDR_SCALARS, r->other_info));
+ }
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_repsFromTo1(struct ndr_pull *ndr, int ndr_flags, struct repsFromTo1 *r)
+{
+ uint32_t _ptr_other_info;
+ TALLOC_CTX *_mem_save_other_info_0;
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->blobsize));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->consecutive_sync_failures));
+ NDR_CHECK(ndr_pull_NTTIME_1sec(ndr, NDR_SCALARS, &r->last_success));
+ NDR_CHECK(ndr_pull_NTTIME_1sec(ndr, NDR_SCALARS, &r->last_attempt));
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->result_last_attempt));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_other_info));
+ if (_ptr_other_info) {
+ NDR_PULL_ALLOC(ndr, r->other_info);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->other_info, _ptr_other_info));
+ } else {
+ r->other_info = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->other_info_length));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaNeighbourFlags(ndr, NDR_SCALARS, &r->replica_flags));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->schedule, 84));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaHighWaterMark(ndr, NDR_SCALARS, &r->highwatermark));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->source_dsa_obj_guid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->transport_guid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->other_info) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->other_info));
+ _mem_save_other_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->other_info, 0);
+ NDR_CHECK(ndr_pull_repsFromTo1OtherInfo(ndr, NDR_SCALARS, r->other_info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_other_info_0, 0);
+ ndr->offset = _relative_save_offset;
+ }
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_repsFromTo1(struct ndr_print *ndr, const char *name, const struct repsFromTo1 *r)
+{
+ ndr_print_struct(ndr, name, "repsFromTo1");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "blobsize", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_repsFromTo1(r, ndr->flags) + 8:r->blobsize);
+ ndr_print_uint32(ndr, "consecutive_sync_failures", r->consecutive_sync_failures);
+ ndr_print_NTTIME_1sec(ndr, "last_success", r->last_success);
+ ndr_print_NTTIME_1sec(ndr, "last_attempt", r->last_attempt);
+ ndr_print_WERROR(ndr, "result_last_attempt", r->result_last_attempt);
+ ndr_print_ptr(ndr, "other_info", r->other_info);
+ ndr->depth++;
+ if (r->other_info) {
+ ndr_print_repsFromTo1OtherInfo(ndr, "other_info", r->other_info);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "other_info_length", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_repsFromTo1OtherInfo(r->other_info, ndr->flags):r->other_info_length);
+ ndr_print_drsuapi_DsReplicaNeighbourFlags(ndr, "replica_flags", r->replica_flags);
+ ndr_print_array_uint8(ndr, "schedule", r->schedule, 84);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr_print_drsuapi_DsReplicaHighWaterMark(ndr, "highwatermark", &r->highwatermark);
+ ndr_print_GUID(ndr, "source_dsa_obj_guid", &r->source_dsa_obj_guid);
+ ndr_print_GUID(ndr, "source_dsa_invocation_id", &r->source_dsa_invocation_id);
+ ndr_print_GUID(ndr, "transport_guid", &r->transport_guid);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+_PUBLIC_ size_t ndr_size_repsFromTo1(const struct repsFromTo1 *r, int flags)
+{
+ flags |= LIBNDR_PRINT_ARRAY_HEX;
+ return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_repsFromTo1);
+}
+
+static enum ndr_err_code ndr_push_repsFromTo(struct ndr_push *ndr, int ndr_flags, const union repsFromTo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_repsFromTo1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_repsFromTo1(ndr, NDR_BUFFERS, &r->ctr1));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_repsFromTo(struct ndr_pull *ndr, int ndr_flags, union repsFromTo *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_repsFromTo1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_repsFromTo1(ndr, NDR_BUFFERS, &r->ctr1));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_repsFromTo(struct ndr_print *ndr, const char *name, const union repsFromTo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "repsFromTo");
+ switch (level) {
+ case 1:
+ ndr_print_repsFromTo1(ndr, "ctr1", &r->ctr1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_repsFromToBlob(struct ndr_push *ndr, int ndr_flags, const struct repsFromToBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->ctr, r->version));
+ NDR_CHECK(ndr_push_repsFromTo(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_repsFromTo(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_repsFromToBlob(struct ndr_pull *ndr, int ndr_flags, struct repsFromToBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->ctr, r->version));
+ NDR_CHECK(ndr_pull_repsFromTo(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_repsFromTo(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_repsFromToBlob(struct ndr_print *ndr, const char *name, const struct repsFromToBlob *r)
+{
+ ndr_print_struct(ndr, name, "repsFromToBlob");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "version", r->version);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr_print_set_switch_value(ndr, &r->ctr, r->version);
+ ndr_print_repsFromTo(ndr, "ctr", &r->ctr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_partialAttributeSetCtr1(struct ndr_push *ndr, int ndr_flags, const struct partialAttributeSetCtr1 *r)
+{
+ uint32_t cntr_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsAttributeId(ndr, NDR_SCALARS, r->array[cntr_array_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_partialAttributeSetCtr1(struct ndr_pull *ndr, int ndr_flags, struct partialAttributeSetCtr1 *r)
+{
+ uint32_t cntr_array_0;
+ TALLOC_CTX *_mem_save_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_PULL_ALLOC_N(ndr, r->array, r->count);
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsAttributeId(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_partialAttributeSetCtr1(struct ndr_print *ndr, const char *name, const struct partialAttributeSetCtr1 *r)
+{
+ uint32_t cntr_array_0;
+ ndr_print_struct(ndr, name, "partialAttributeSetCtr1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_0=0;cntr_array_0<r->count;cntr_array_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_array_0) != -1) {
+ ndr_print_drsuapi_DsAttributeId(ndr, "array", r->array[cntr_array_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_partialAttributeSetCtr(struct ndr_push *ndr, int ndr_flags, const union partialAttributeSetCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_partialAttributeSetCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_partialAttributeSetCtr(struct ndr_pull *ndr, int ndr_flags, union partialAttributeSetCtr *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_partialAttributeSetCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_partialAttributeSetCtr(struct ndr_print *ndr, const char *name, const union partialAttributeSetCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "partialAttributeSetCtr");
+ switch (level) {
+ case 1:
+ ndr_print_partialAttributeSetCtr1(ndr, "ctr1", &r->ctr1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_partialAttributeSetBlob(struct ndr_push *ndr, int ndr_flags, const struct partialAttributeSetBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->ctr, r->version));
+ NDR_CHECK(ndr_push_partialAttributeSetCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_partialAttributeSetBlob(struct ndr_pull *ndr, int ndr_flags, struct partialAttributeSetBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->ctr, r->version));
+ NDR_CHECK(ndr_pull_partialAttributeSetCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_partialAttributeSetBlob(struct ndr_print *ndr, const char *name, const struct partialAttributeSetBlob *r)
+{
+ ndr_print_struct(ndr, name, "partialAttributeSetBlob");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "version", r->version);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr_print_set_switch_value(ndr, &r->ctr, r->version);
+ ndr_print_partialAttributeSetCtr(ndr, "ctr", &r->ctr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_prefixMapVersion(struct ndr_push *ndr, int ndr_flags, enum prefixMapVersion r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_prefixMapVersion(struct ndr_pull *ndr, int ndr_flags, enum prefixMapVersion *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_prefixMapVersion(struct ndr_print *ndr, const char *name, enum prefixMapVersion r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case PREFIX_MAP_VERSION_DSDB: val = "PREFIX_MAP_VERSION_DSDB"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_prefixMapCtr(struct ndr_push *ndr, int ndr_flags, const union prefixMapCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case PREFIX_MAP_VERSION_DSDB: {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOIDMapping_Ctr(ndr, NDR_SCALARS, &r->dsdb));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case PREFIX_MAP_VERSION_DSDB:
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOIDMapping_Ctr(ndr, NDR_BUFFERS, &r->dsdb));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_prefixMapCtr(struct ndr_pull *ndr, int ndr_flags, union prefixMapCtr *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case PREFIX_MAP_VERSION_DSDB: {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaOIDMapping_Ctr(ndr, NDR_SCALARS, &r->dsdb));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case PREFIX_MAP_VERSION_DSDB:
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaOIDMapping_Ctr(ndr, NDR_BUFFERS, &r->dsdb));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_prefixMapCtr(struct ndr_print *ndr, const char *name, const union prefixMapCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "prefixMapCtr");
+ switch (level) {
+ case PREFIX_MAP_VERSION_DSDB:
+ ndr_print_drsuapi_DsReplicaOIDMapping_Ctr(ndr, "dsdb", &r->dsdb);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_prefixMapBlob(struct ndr_push *ndr, int ndr_flags, const struct prefixMapBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_prefixMapVersion(ndr, NDR_SCALARS, r->version));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->ctr, r->version));
+ NDR_CHECK(ndr_push_prefixMapCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_prefixMapCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_prefixMapBlob(struct ndr_pull *ndr, int ndr_flags, struct prefixMapBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_prefixMapVersion(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->ctr, r->version));
+ NDR_CHECK(ndr_pull_prefixMapCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_prefixMapCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_prefixMapBlob(struct ndr_print *ndr, const char *name, const struct prefixMapBlob *r)
+{
+ ndr_print_struct(ndr, name, "prefixMapBlob");
+ ndr->depth++;
+ ndr_print_prefixMapVersion(ndr, "version", r->version);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr_print_set_switch_value(ndr, &r->ctr, r->version);
+ ndr_print_prefixMapCtr(ndr, "ctr", &r->ctr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_ldapControlDirSyncExtra(struct ndr_push *ndr, int ndr_flags, const union ldapControlDirSyncExtra *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0: {
+ break; }
+
+ default: {
+ NDR_CHECK(ndr_push_replUpToDateVectorBlob(ndr, NDR_SCALARS, &r->uptodateness_vector));
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_ldapControlDirSyncExtra(struct ndr_pull *ndr, int ndr_flags, union ldapControlDirSyncExtra *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case 0: {
+ break; }
+
+ default: {
+ NDR_CHECK(ndr_pull_replUpToDateVectorBlob(ndr, NDR_SCALARS, &r->uptodateness_vector));
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_ldapControlDirSyncExtra(struct ndr_print *ndr, const char *name, const union ldapControlDirSyncExtra *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "ldapControlDirSyncExtra");
+ switch (level) {
+ case 0:
+ break;
+
+ default:
+ ndr_print_replUpToDateVectorBlob(ndr, "uptodateness_vector", &r->uptodateness_vector);
+ break;
+
+ }
+}
+
+static size_t ndr_size_ldapControlDirSyncExtra(const union ldapControlDirSyncExtra *r, uint32_t level, int flags)
+{
+ return ndr_size_union(r, flags, level, (ndr_push_flags_fn_t)ndr_push_ldapControlDirSyncExtra);
+}
+
+static enum ndr_err_code ndr_push_ldapControlDirSyncBlob(struct ndr_push *ndr, int ndr_flags, const struct ldapControlDirSyncBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 3));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->u2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->u3));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_ldapControlDirSyncExtra(&r->extra, r->extra.uptodateness_vector.version, 0)));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaHighWaterMark(ndr, NDR_SCALARS, &r->highwatermark));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->guid1));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->extra, ndr_size_ldapControlDirSyncExtra(&r->extra, r->extra.uptodateness_vector.version, 0)));
+ NDR_CHECK(ndr_push_ldapControlDirSyncExtra(ndr, NDR_SCALARS, &r->extra));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_ldapControlDirSyncExtra(ndr, NDR_BUFFERS, &r->extra));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_ldapControlDirSyncBlob(struct ndr_pull *ndr, int ndr_flags, struct ldapControlDirSyncBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->u1));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->u2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->u3));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->extra_length));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaHighWaterMark(ndr, NDR_SCALARS, &r->highwatermark));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->guid1));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->extra, r->extra_length));
+ NDR_CHECK(ndr_pull_ldapControlDirSyncExtra(ndr, NDR_SCALARS, &r->extra));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_ldapControlDirSyncExtra(ndr, NDR_BUFFERS, &r->extra));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_ldapControlDirSyncBlob(struct ndr_print *ndr, const char *name, const struct ldapControlDirSyncBlob *r)
+{
+ ndr_print_struct(ndr, name, "ldapControlDirSyncBlob");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "u1", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?3:r->u1);
+ ndr_print_NTTIME(ndr, "time", r->time);
+ ndr_print_uint32(ndr, "u2", r->u2);
+ ndr_print_uint32(ndr, "u3", r->u3);
+ ndr_print_uint32(ndr, "extra_length", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_ldapControlDirSyncExtra(&r->extra, r->extra.uptodateness_vector.version, 0):r->extra_length);
+ ndr_print_drsuapi_DsReplicaHighWaterMark(ndr, "highwatermark", &r->highwatermark);
+ ndr_print_GUID(ndr, "guid1", &r->guid1);
+ ndr_print_set_switch_value(ndr, &r->extra, r->extra_length);
+ ndr_print_ldapControlDirSyncExtra(ndr, "extra", &r->extra);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_ldapControlDirSyncCookie(struct ndr_push *ndr, int ndr_flags, const struct ldapControlDirSyncCookie *r)
+{
+ uint32_t _save_relative_base_offset = ndr_push_get_relative_base_offset(ndr);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_setup_relative_base_offset1(ndr, r, ndr->offset));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, "MSDS", 4, sizeof(uint8_t), CH_DOS));
+ {
+ struct ndr_push *_ndr_blob;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_blob, 0, -1));
+ NDR_CHECK(ndr_push_ldapControlDirSyncBlob(_ndr_blob, NDR_SCALARS|NDR_BUFFERS, &r->blob));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_blob, 0, -1));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_setup_relative_base_offset2(ndr, r));
+ }
+ ndr_push_restore_relative_base_offset(ndr, _save_relative_base_offset);
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_ldapControlDirSyncCookie(struct ndr_pull *ndr, int ndr_flags, struct ldapControlDirSyncCookie *r)
+{
+ uint32_t _save_relative_base_offset = ndr_pull_get_relative_base_offset(ndr);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_setup_relative_base_offset1(ndr, r, ndr->offset));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->msds, 4, sizeof(uint8_t), CH_DOS));
+ {
+ struct ndr_pull *_ndr_blob;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_blob, 0, -1));
+ NDR_CHECK(ndr_pull_ldapControlDirSyncBlob(_ndr_blob, NDR_SCALARS|NDR_BUFFERS, &r->blob));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_blob, 0, -1));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_setup_relative_base_offset2(ndr, r));
+ }
+ ndr_pull_restore_relative_base_offset(ndr, _save_relative_base_offset);
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_ldapControlDirSyncCookie(struct ndr_print *ndr, const char *name, const struct ldapControlDirSyncCookie *r)
+{
+ ndr_print_struct(ndr, name, "ldapControlDirSyncCookie");
+ ndr->depth++;
+ ndr_print_string(ndr, "msds", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?"MSDS":r->msds);
+ ndr_print_ldapControlDirSyncBlob(ndr, "blob", &r->blob);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_supplementalCredentialsPackage(struct ndr_push *ndr, int ndr_flags, const struct supplementalCredentialsPackage *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 2 * strlen_m(r->name)));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, strlen(r->data)));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->reserved));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, 2 * strlen_m(r->name), sizeof(uint8_t), CH_UTF16));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->data, strlen(r->data), sizeof(uint8_t), CH_DOS));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_supplementalCredentialsPackage(struct ndr_pull *ndr, int ndr_flags, struct supplementalCredentialsPackage *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->name_len));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->data_len));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->reserved));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, r->name_len, sizeof(uint8_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->data, r->data_len, sizeof(uint8_t), CH_DOS));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_supplementalCredentialsPackage(struct ndr_print *ndr, const char *name, const struct supplementalCredentialsPackage *r)
+{
+ ndr_print_struct(ndr, name, "supplementalCredentialsPackage");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "name_len", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?2 * strlen_m(r->name):r->name_len);
+ ndr_print_uint16(ndr, "data_len", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen(r->data):r->data_len);
+ ndr_print_uint16(ndr, "reserved", r->reserved);
+ ndr_print_string(ndr, "name", r->name);
+ ndr_print_string(ndr, "data", r->data);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_supplementalCredentialsSignature(struct ndr_push *ndr, int ndr_flags, enum supplementalCredentialsSignature r)
+{
+ {
+ uint32_t _flags_save_ENUM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ ndr->flags = _flags_save_ENUM;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_supplementalCredentialsSignature(struct ndr_pull *ndr, int ndr_flags, enum supplementalCredentialsSignature *r)
+{
+ uint16_t v;
+ {
+ uint32_t _flags_save_ENUM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ ndr->flags = _flags_save_ENUM;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_supplementalCredentialsSignature(struct ndr_print *ndr, const char *name, enum supplementalCredentialsSignature r)
+{
+ const char *val = NULL;
+
+ {
+ uint32_t _flags_save_ENUM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ switch (r) {
+ case SUPPLEMENTAL_CREDENTIALS_SIGNATURE: val = "SUPPLEMENTAL_CREDENTIALS_SIGNATURE"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+ ndr->flags = _flags_save_ENUM;
+ }
+}
+
+static enum ndr_err_code ndr_push_supplementalCredentialsSubBlob(struct ndr_push *ndr, int ndr_flags, const struct supplementalCredentialsSubBlob *r)
+{
+ uint32_t cntr_packages_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, SUPPLEMENTAL_CREDENTIALS_PREFIX, 0x30, sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_supplementalCredentialsSignature(ndr, NDR_SCALARS, SUPPLEMENTAL_CREDENTIALS_SIGNATURE));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->num_packages));
+ for (cntr_packages_0 = 0; cntr_packages_0 < r->num_packages; cntr_packages_0++) {
+ NDR_CHECK(ndr_push_supplementalCredentialsPackage(ndr, NDR_SCALARS, &r->packages[cntr_packages_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_supplementalCredentialsSubBlob(struct ndr_pull *ndr, int ndr_flags, struct supplementalCredentialsSubBlob *r)
+{
+ uint32_t cntr_packages_0;
+ TALLOC_CTX *_mem_save_packages_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->prefix, 0x30, sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_supplementalCredentialsSignature(ndr, NDR_SCALARS, &r->signature));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->num_packages));
+ NDR_PULL_ALLOC_N(ndr, r->packages, r->num_packages);
+ _mem_save_packages_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->packages, 0);
+ for (cntr_packages_0 = 0; cntr_packages_0 < r->num_packages; cntr_packages_0++) {
+ NDR_CHECK(ndr_pull_supplementalCredentialsPackage(ndr, NDR_SCALARS, &r->packages[cntr_packages_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_packages_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_supplementalCredentialsSubBlob(struct ndr_print *ndr, const char *name, const struct supplementalCredentialsSubBlob *r)
+{
+ uint32_t cntr_packages_0;
+ ndr_print_struct(ndr, name, "supplementalCredentialsSubBlob");
+ ndr->depth++;
+ ndr_print_string(ndr, "prefix", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?SUPPLEMENTAL_CREDENTIALS_PREFIX:r->prefix);
+ ndr_print_supplementalCredentialsSignature(ndr, "signature", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?SUPPLEMENTAL_CREDENTIALS_SIGNATURE:r->signature);
+ ndr_print_uint16(ndr, "num_packages", r->num_packages);
+ ndr->print(ndr, "%s: ARRAY(%d)", "packages", (int)r->num_packages);
+ ndr->depth++;
+ for (cntr_packages_0=0;cntr_packages_0<r->num_packages;cntr_packages_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_packages_0) != -1) {
+ ndr_print_supplementalCredentialsPackage(ndr, "packages", &r->packages[cntr_packages_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static size_t ndr_size_supplementalCredentialsSubBlob(const struct supplementalCredentialsSubBlob *r, int flags)
+{
+ return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsSubBlob);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_supplementalCredentialsBlob(struct ndr_push *ndr, int ndr_flags, const struct supplementalCredentialsBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_supplementalCredentialsSubBlob(&r->sub, ndr->flags)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ {
+ struct ndr_push *_ndr_sub;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_sub, 0, ndr_size_supplementalCredentialsSubBlob(&r->sub, ndr->flags)));
+ NDR_CHECK(ndr_push_supplementalCredentialsSubBlob(_ndr_sub, NDR_SCALARS, &r->sub));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_sub, 0, ndr_size_supplementalCredentialsSubBlob(&r->sub, ndr->flags)));
+ }
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 0));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_supplementalCredentialsBlob(struct ndr_pull *ndr, int ndr_flags, struct supplementalCredentialsBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ {
+ struct ndr_pull *_ndr_sub;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_sub, 0, r->__ndr_size));
+ NDR_CHECK(ndr_pull_supplementalCredentialsSubBlob(_ndr_sub, NDR_SCALARS, &r->sub));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_sub, 0, r->__ndr_size));
+ }
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->unknown3));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_supplementalCredentialsBlob(struct ndr_print *ndr, const char *name, const struct supplementalCredentialsBlob *r)
+{
+ ndr_print_struct(ndr, name, "supplementalCredentialsBlob");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "unknown1", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->unknown1);
+ ndr_print_uint32(ndr, "__ndr_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_supplementalCredentialsSubBlob(&r->sub, ndr->flags):r->__ndr_size);
+ ndr_print_uint32(ndr, "unknown2", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->unknown2);
+ ndr_print_supplementalCredentialsSubBlob(ndr, "sub", &r->sub);
+ ndr_print_uint8(ndr, "unknown3", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->unknown3);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_package_PackagesBlob(struct ndr_push *ndr, int ndr_flags, const struct package_PackagesBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_string_array = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_string_array(ndr, NDR_SCALARS, r->names));
+ ndr->flags = _flags_save_string_array;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_package_PackagesBlob(struct ndr_pull *ndr, int ndr_flags, struct package_PackagesBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_string_array = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_string_array(ndr, NDR_SCALARS, &r->names));
+ ndr->flags = _flags_save_string_array;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_package_PackagesBlob(struct ndr_print *ndr, const char *name, const struct package_PackagesBlob *r)
+{
+ ndr_print_struct(ndr, name, "package_PackagesBlob");
+ ndr->depth++;
+ ndr_print_string_array(ndr, "names", r->names);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_package_PrimaryKerberosString(struct ndr_push *ndr, int ndr_flags, const struct package_PrimaryKerberosString *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 2 * strlen_m(r->string)));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 2 * strlen_m(r->string)));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->string));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
+ if (r->string) {
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, r->string));
+ {
+ struct ndr_push *_ndr_string;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_string, 0, 2 * strlen_m(r->string)));
+ NDR_CHECK(ndr_push_string(_ndr_string, NDR_SCALARS, r->string));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_string, 0, 2 * strlen_m(r->string)));
+ }
+ }
+ ndr->flags = _flags_save_string;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_package_PrimaryKerberosString(struct ndr_pull *ndr, int ndr_flags, struct package_PrimaryKerberosString *r)
+{
+ uint32_t _ptr_string;
+ TALLOC_CTX *_mem_save_string_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_string));
+ if (_ptr_string) {
+ NDR_PULL_ALLOC(ndr, r->string);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->string, _ptr_string));
+ } else {
+ r->string = NULL;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
+ if (r->string) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->string));
+ _mem_save_string_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->string, 0);
+ {
+ struct ndr_pull *_ndr_string;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_string, 0, r->size));
+ NDR_CHECK(ndr_pull_string(_ndr_string, NDR_SCALARS, &r->string));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_string, 0, r->size));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_string_0, 0);
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_package_PrimaryKerberosString(struct ndr_print *ndr, const char *name, const struct package_PrimaryKerberosString *r)
+{
+ ndr_print_struct(ndr, name, "package_PrimaryKerberosString");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "length", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?2 * strlen_m(r->string):r->length);
+ ndr_print_uint16(ndr, "size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?2 * strlen_m(r->string):r->size);
+ ndr_print_ptr(ndr, "string", r->string);
+ ndr->depth++;
+ if (r->string) {
+ ndr_print_string(ndr, "string", r->string);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_package_PrimaryKerberosKey3(struct ndr_push *ndr, int ndr_flags, const struct package_PrimaryKerberosKey3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->keytype));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, (r->value?r->value->length:0)));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->value));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ if (r->value) {
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, r->value));
+ {
+ struct ndr_push *_ndr_value;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_value, 0, (r->value?r->value->length:0)));
+ NDR_CHECK(ndr_push_DATA_BLOB(_ndr_value, NDR_SCALARS, *r->value));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_value, 0, (r->value?r->value->length:0)));
+ }
+ }
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_package_PrimaryKerberosKey3(struct ndr_pull *ndr, int ndr_flags, struct package_PrimaryKerberosKey3 *r)
+{
+ uint32_t _ptr_value;
+ TALLOC_CTX *_mem_save_value_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->reserved1));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->reserved2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved3));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->keytype));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->value_len));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_value));
+ if (_ptr_value) {
+ NDR_PULL_ALLOC(ndr, r->value);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->value, _ptr_value));
+ } else {
+ r->value = NULL;
+ }
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ if (r->value) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->value));
+ _mem_save_value_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->value, 0);
+ {
+ struct ndr_pull *_ndr_value;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_value, 0, r->value_len));
+ NDR_CHECK(ndr_pull_DATA_BLOB(_ndr_value, NDR_SCALARS, r->value));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_value, 0, r->value_len));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_value_0, 0);
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_package_PrimaryKerberosKey3(struct ndr_print *ndr, const char *name, const struct package_PrimaryKerberosKey3 *r)
+{
+ ndr_print_struct(ndr, name, "package_PrimaryKerberosKey3");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "reserved1", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->reserved1);
+ ndr_print_uint16(ndr, "reserved2", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->reserved2);
+ ndr_print_uint32(ndr, "reserved3", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->reserved3);
+ ndr_print_uint32(ndr, "keytype", r->keytype);
+ ndr_print_uint32(ndr, "value_len", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?(r->value?r->value->length:0):r->value_len);
+ ndr_print_ptr(ndr, "value", r->value);
+ ndr->depth++;
+ if (r->value) {
+ ndr_print_DATA_BLOB(ndr, "value", *r->value);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_package_PrimaryKerberosCtr3(struct ndr_push *ndr, int ndr_flags, const struct package_PrimaryKerberosCtr3 *r)
+{
+ uint32_t cntr_keys_0;
+ uint32_t cntr_old_keys_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->num_keys));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->num_old_keys));
+ NDR_CHECK(ndr_push_package_PrimaryKerberosString(ndr, NDR_SCALARS, &r->salt));
+ for (cntr_keys_0 = 0; cntr_keys_0 < r->num_keys; cntr_keys_0++) {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosKey3(ndr, NDR_SCALARS, &r->keys[cntr_keys_0]));
+ }
+ for (cntr_old_keys_0 = 0; cntr_old_keys_0 < r->num_old_keys; cntr_old_keys_0++) {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosKey3(ndr, NDR_SCALARS, &r->old_keys[cntr_old_keys_0]));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosString(ndr, NDR_BUFFERS, &r->salt));
+ for (cntr_keys_0 = 0; cntr_keys_0 < r->num_keys; cntr_keys_0++) {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosKey3(ndr, NDR_BUFFERS, &r->keys[cntr_keys_0]));
+ }
+ for (cntr_old_keys_0 = 0; cntr_old_keys_0 < r->num_old_keys; cntr_old_keys_0++) {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosKey3(ndr, NDR_BUFFERS, &r->old_keys[cntr_old_keys_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_package_PrimaryKerberosCtr3(struct ndr_pull *ndr, int ndr_flags, struct package_PrimaryKerberosCtr3 *r)
+{
+ uint32_t cntr_keys_0;
+ TALLOC_CTX *_mem_save_keys_0;
+ uint32_t cntr_old_keys_0;
+ TALLOC_CTX *_mem_save_old_keys_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->num_keys));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->num_old_keys));
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosString(ndr, NDR_SCALARS, &r->salt));
+ NDR_PULL_ALLOC_N(ndr, r->keys, r->num_keys);
+ _mem_save_keys_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->keys, 0);
+ for (cntr_keys_0 = 0; cntr_keys_0 < r->num_keys; cntr_keys_0++) {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosKey3(ndr, NDR_SCALARS, &r->keys[cntr_keys_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_keys_0, 0);
+ NDR_PULL_ALLOC_N(ndr, r->old_keys, r->num_old_keys);
+ _mem_save_old_keys_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->old_keys, 0);
+ for (cntr_old_keys_0 = 0; cntr_old_keys_0 < r->num_old_keys; cntr_old_keys_0++) {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosKey3(ndr, NDR_SCALARS, &r->old_keys[cntr_old_keys_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_old_keys_0, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->padding1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->padding2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->padding3));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->padding4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->padding5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosString(ndr, NDR_BUFFERS, &r->salt));
+ _mem_save_keys_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->keys, 0);
+ for (cntr_keys_0 = 0; cntr_keys_0 < r->num_keys; cntr_keys_0++) {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosKey3(ndr, NDR_BUFFERS, &r->keys[cntr_keys_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_keys_0, 0);
+ _mem_save_old_keys_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->old_keys, 0);
+ for (cntr_old_keys_0 = 0; cntr_old_keys_0 < r->num_old_keys; cntr_old_keys_0++) {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosKey3(ndr, NDR_BUFFERS, &r->old_keys[cntr_old_keys_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_old_keys_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_package_PrimaryKerberosCtr3(struct ndr_print *ndr, const char *name, const struct package_PrimaryKerberosCtr3 *r)
+{
+ uint32_t cntr_keys_0;
+ uint32_t cntr_old_keys_0;
+ ndr_print_struct(ndr, name, "package_PrimaryKerberosCtr3");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "num_keys", r->num_keys);
+ ndr_print_uint16(ndr, "num_old_keys", r->num_old_keys);
+ ndr_print_package_PrimaryKerberosString(ndr, "salt", &r->salt);
+ ndr->print(ndr, "%s: ARRAY(%d)", "keys", (int)r->num_keys);
+ ndr->depth++;
+ for (cntr_keys_0=0;cntr_keys_0<r->num_keys;cntr_keys_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_keys_0) != -1) {
+ ndr_print_package_PrimaryKerberosKey3(ndr, "keys", &r->keys[cntr_keys_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->print(ndr, "%s: ARRAY(%d)", "old_keys", (int)r->num_old_keys);
+ ndr->depth++;
+ for (cntr_old_keys_0=0;cntr_old_keys_0<r->num_old_keys;cntr_old_keys_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_old_keys_0) != -1) {
+ ndr_print_package_PrimaryKerberosKey3(ndr, "old_keys", &r->old_keys[cntr_old_keys_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "padding1", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->padding1);
+ ndr_print_uint32(ndr, "padding2", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->padding2);
+ ndr_print_uint32(ndr, "padding3", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->padding3);
+ ndr_print_uint32(ndr, "padding4", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->padding4);
+ ndr_print_uint32(ndr, "padding5", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->padding5);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_package_PrimaryKerberosKey4(struct ndr_push *ndr, int ndr_flags, const struct package_PrimaryKerberosKey4 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->iteration_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->keytype));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, (r->value?r->value->length:0)));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->value));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ if (r->value) {
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, r->value));
+ {
+ struct ndr_push *_ndr_value;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_value, 0, (r->value?r->value->length:0)));
+ NDR_CHECK(ndr_push_DATA_BLOB(_ndr_value, NDR_SCALARS, *r->value));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_value, 0, (r->value?r->value->length:0)));
+ }
+ }
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_package_PrimaryKerberosKey4(struct ndr_pull *ndr, int ndr_flags, struct package_PrimaryKerberosKey4 *r)
+{
+ uint32_t _ptr_value;
+ TALLOC_CTX *_mem_save_value_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->reserved1));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->reserved2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved3));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->iteration_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->keytype));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->value_len));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_value));
+ if (_ptr_value) {
+ NDR_PULL_ALLOC(ndr, r->value);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->value, _ptr_value));
+ } else {
+ r->value = NULL;
+ }
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ if (r->value) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->value));
+ _mem_save_value_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->value, 0);
+ {
+ struct ndr_pull *_ndr_value;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_value, 0, r->value_len));
+ NDR_CHECK(ndr_pull_DATA_BLOB(_ndr_value, NDR_SCALARS, r->value));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_value, 0, r->value_len));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_value_0, 0);
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_package_PrimaryKerberosKey4(struct ndr_print *ndr, const char *name, const struct package_PrimaryKerberosKey4 *r)
+{
+ ndr_print_struct(ndr, name, "package_PrimaryKerberosKey4");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "reserved1", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->reserved1);
+ ndr_print_uint16(ndr, "reserved2", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->reserved2);
+ ndr_print_uint32(ndr, "reserved3", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->reserved3);
+ ndr_print_uint32(ndr, "iteration_count", r->iteration_count);
+ ndr_print_uint32(ndr, "keytype", r->keytype);
+ ndr_print_uint32(ndr, "value_len", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?(r->value?r->value->length:0):r->value_len);
+ ndr_print_ptr(ndr, "value", r->value);
+ ndr->depth++;
+ if (r->value) {
+ ndr_print_DATA_BLOB(ndr, "value", *r->value);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_package_PrimaryKerberosCtr4(struct ndr_push *ndr, int ndr_flags, const struct package_PrimaryKerberosCtr4 *r)
+{
+ uint32_t cntr_keys_0;
+ uint32_t cntr_service_keys_0;
+ uint32_t cntr_old_keys_0;
+ uint32_t cntr_older_keys_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->num_keys));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->num_old_keys));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->num_older_keys));
+ NDR_CHECK(ndr_push_package_PrimaryKerberosString(ndr, NDR_SCALARS, &r->salt));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->default_iteration_count));
+ for (cntr_keys_0 = 0; cntr_keys_0 < r->num_keys; cntr_keys_0++) {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosKey4(ndr, NDR_SCALARS, &r->keys[cntr_keys_0]));
+ }
+ for (cntr_service_keys_0 = 0; cntr_service_keys_0 < 0; cntr_service_keys_0++) {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosKey4(ndr, NDR_SCALARS, &r->service_keys[cntr_service_keys_0]));
+ }
+ for (cntr_old_keys_0 = 0; cntr_old_keys_0 < r->num_old_keys; cntr_old_keys_0++) {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosKey4(ndr, NDR_SCALARS, &r->old_keys[cntr_old_keys_0]));
+ }
+ for (cntr_older_keys_0 = 0; cntr_older_keys_0 < r->num_older_keys; cntr_older_keys_0++) {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosKey4(ndr, NDR_SCALARS, &r->older_keys[cntr_older_keys_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosString(ndr, NDR_BUFFERS, &r->salt));
+ for (cntr_keys_0 = 0; cntr_keys_0 < r->num_keys; cntr_keys_0++) {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosKey4(ndr, NDR_BUFFERS, &r->keys[cntr_keys_0]));
+ }
+ for (cntr_service_keys_0 = 0; cntr_service_keys_0 < 0; cntr_service_keys_0++) {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosKey4(ndr, NDR_BUFFERS, &r->service_keys[cntr_service_keys_0]));
+ }
+ for (cntr_old_keys_0 = 0; cntr_old_keys_0 < r->num_old_keys; cntr_old_keys_0++) {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosKey4(ndr, NDR_BUFFERS, &r->old_keys[cntr_old_keys_0]));
+ }
+ for (cntr_older_keys_0 = 0; cntr_older_keys_0 < r->num_older_keys; cntr_older_keys_0++) {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosKey4(ndr, NDR_BUFFERS, &r->older_keys[cntr_older_keys_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_package_PrimaryKerberosCtr4(struct ndr_pull *ndr, int ndr_flags, struct package_PrimaryKerberosCtr4 *r)
+{
+ uint32_t cntr_keys_0;
+ TALLOC_CTX *_mem_save_keys_0;
+ uint32_t cntr_service_keys_0;
+ TALLOC_CTX *_mem_save_service_keys_0;
+ uint32_t cntr_old_keys_0;
+ TALLOC_CTX *_mem_save_old_keys_0;
+ uint32_t cntr_older_keys_0;
+ TALLOC_CTX *_mem_save_older_keys_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->num_keys));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->num_service_keys));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->num_old_keys));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->num_older_keys));
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosString(ndr, NDR_SCALARS, &r->salt));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->default_iteration_count));
+ NDR_PULL_ALLOC_N(ndr, r->keys, r->num_keys);
+ _mem_save_keys_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->keys, 0);
+ for (cntr_keys_0 = 0; cntr_keys_0 < r->num_keys; cntr_keys_0++) {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosKey4(ndr, NDR_SCALARS, &r->keys[cntr_keys_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_keys_0, 0);
+ NDR_PULL_ALLOC_N(ndr, r->service_keys, r->num_service_keys);
+ _mem_save_service_keys_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->service_keys, 0);
+ for (cntr_service_keys_0 = 0; cntr_service_keys_0 < r->num_service_keys; cntr_service_keys_0++) {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosKey4(ndr, NDR_SCALARS, &r->service_keys[cntr_service_keys_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_keys_0, 0);
+ NDR_PULL_ALLOC_N(ndr, r->old_keys, r->num_old_keys);
+ _mem_save_old_keys_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->old_keys, 0);
+ for (cntr_old_keys_0 = 0; cntr_old_keys_0 < r->num_old_keys; cntr_old_keys_0++) {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosKey4(ndr, NDR_SCALARS, &r->old_keys[cntr_old_keys_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_old_keys_0, 0);
+ NDR_PULL_ALLOC_N(ndr, r->older_keys, r->num_older_keys);
+ _mem_save_older_keys_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->older_keys, 0);
+ for (cntr_older_keys_0 = 0; cntr_older_keys_0 < r->num_older_keys; cntr_older_keys_0++) {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosKey4(ndr, NDR_SCALARS, &r->older_keys[cntr_older_keys_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_older_keys_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosString(ndr, NDR_BUFFERS, &r->salt));
+ _mem_save_keys_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->keys, 0);
+ for (cntr_keys_0 = 0; cntr_keys_0 < r->num_keys; cntr_keys_0++) {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosKey4(ndr, NDR_BUFFERS, &r->keys[cntr_keys_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_keys_0, 0);
+ _mem_save_service_keys_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->service_keys, 0);
+ for (cntr_service_keys_0 = 0; cntr_service_keys_0 < r->num_service_keys; cntr_service_keys_0++) {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosKey4(ndr, NDR_BUFFERS, &r->service_keys[cntr_service_keys_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_keys_0, 0);
+ _mem_save_old_keys_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->old_keys, 0);
+ for (cntr_old_keys_0 = 0; cntr_old_keys_0 < r->num_old_keys; cntr_old_keys_0++) {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosKey4(ndr, NDR_BUFFERS, &r->old_keys[cntr_old_keys_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_old_keys_0, 0);
+ _mem_save_older_keys_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->older_keys, 0);
+ for (cntr_older_keys_0 = 0; cntr_older_keys_0 < r->num_older_keys; cntr_older_keys_0++) {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosKey4(ndr, NDR_BUFFERS, &r->older_keys[cntr_older_keys_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_older_keys_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_package_PrimaryKerberosCtr4(struct ndr_print *ndr, const char *name, const struct package_PrimaryKerberosCtr4 *r)
+{
+ uint32_t cntr_keys_0;
+ uint32_t cntr_service_keys_0;
+ uint32_t cntr_old_keys_0;
+ uint32_t cntr_older_keys_0;
+ ndr_print_struct(ndr, name, "package_PrimaryKerberosCtr4");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "num_keys", r->num_keys);
+ ndr_print_uint16(ndr, "num_service_keys", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->num_service_keys);
+ ndr_print_uint16(ndr, "num_old_keys", r->num_old_keys);
+ ndr_print_uint16(ndr, "num_older_keys", r->num_older_keys);
+ ndr_print_package_PrimaryKerberosString(ndr, "salt", &r->salt);
+ ndr_print_uint32(ndr, "default_iteration_count", r->default_iteration_count);
+ ndr->print(ndr, "%s: ARRAY(%d)", "keys", (int)r->num_keys);
+ ndr->depth++;
+ for (cntr_keys_0=0;cntr_keys_0<r->num_keys;cntr_keys_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_keys_0) != -1) {
+ ndr_print_package_PrimaryKerberosKey4(ndr, "keys", &r->keys[cntr_keys_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->print(ndr, "%s: ARRAY(%d)", "service_keys", (int)r->num_service_keys);
+ ndr->depth++;
+ for (cntr_service_keys_0=0;cntr_service_keys_0<r->num_service_keys;cntr_service_keys_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_service_keys_0) != -1) {
+ ndr_print_package_PrimaryKerberosKey4(ndr, "service_keys", &r->service_keys[cntr_service_keys_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->print(ndr, "%s: ARRAY(%d)", "old_keys", (int)r->num_old_keys);
+ ndr->depth++;
+ for (cntr_old_keys_0=0;cntr_old_keys_0<r->num_old_keys;cntr_old_keys_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_old_keys_0) != -1) {
+ ndr_print_package_PrimaryKerberosKey4(ndr, "old_keys", &r->old_keys[cntr_old_keys_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->print(ndr, "%s: ARRAY(%d)", "older_keys", (int)r->num_older_keys);
+ ndr->depth++;
+ for (cntr_older_keys_0=0;cntr_older_keys_0<r->num_older_keys;cntr_older_keys_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_older_keys_0) != -1) {
+ ndr_print_package_PrimaryKerberosKey4(ndr, "older_keys", &r->older_keys[cntr_older_keys_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_package_PrimaryKerberosCtr(struct ndr_push *ndr, int ndr_flags, const union package_PrimaryKerberosCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 3: {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosCtr3(ndr, NDR_SCALARS, &r->ctr3));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosCtr4(ndr, NDR_SCALARS, &r->ctr4));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 3:
+ NDR_CHECK(ndr_push_package_PrimaryKerberosCtr3(ndr, NDR_BUFFERS, &r->ctr3));
+ break;
+
+ case 4:
+ NDR_CHECK(ndr_push_package_PrimaryKerberosCtr4(ndr, NDR_BUFFERS, &r->ctr4));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_package_PrimaryKerberosCtr(struct ndr_pull *ndr, int ndr_flags, union package_PrimaryKerberosCtr *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case 3: {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosCtr3(ndr, NDR_SCALARS, &r->ctr3));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosCtr4(ndr, NDR_SCALARS, &r->ctr4));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 3:
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosCtr3(ndr, NDR_BUFFERS, &r->ctr3));
+ break;
+
+ case 4:
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosCtr4(ndr, NDR_BUFFERS, &r->ctr4));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_package_PrimaryKerberosCtr(struct ndr_print *ndr, const char *name, const union package_PrimaryKerberosCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "package_PrimaryKerberosCtr");
+ switch (level) {
+ case 3:
+ ndr_print_package_PrimaryKerberosCtr3(ndr, "ctr3", &r->ctr3);
+ break;
+
+ case 4:
+ ndr_print_package_PrimaryKerberosCtr4(ndr, "ctr4", &r->ctr4);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_package_PrimaryKerberosBlob(struct ndr_push *ndr, int ndr_flags, const struct package_PrimaryKerberosBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->version));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->ctr, r->version));
+ NDR_CHECK(ndr_push_package_PrimaryKerberosCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_package_PrimaryKerberosBlob(struct ndr_pull *ndr, int ndr_flags, struct package_PrimaryKerberosBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->ctr, r->version));
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_package_PrimaryKerberosBlob(struct ndr_print *ndr, const char *name, const struct package_PrimaryKerberosBlob *r)
+{
+ ndr_print_struct(ndr, name, "package_PrimaryKerberosBlob");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "version", r->version);
+ ndr_print_uint16(ndr, "flags", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->flags);
+ ndr_print_set_switch_value(ndr, &r->ctr, r->version);
+ ndr_print_package_PrimaryKerberosCtr(ndr, "ctr", &r->ctr);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_package_PrimaryCLEARTEXTBlob(struct ndr_push *ndr, int ndr_flags, const struct package_PrimaryCLEARTEXTBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->cleartext));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_package_PrimaryCLEARTEXTBlob(struct ndr_pull *ndr, int ndr_flags, struct package_PrimaryCLEARTEXTBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->cleartext));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_package_PrimaryCLEARTEXTBlob(struct ndr_print *ndr, const char *name, const struct package_PrimaryCLEARTEXTBlob *r)
+{
+ ndr_print_struct(ndr, name, "package_PrimaryCLEARTEXTBlob");
+ ndr->depth++;
+ ndr_print_string(ndr, "cleartext", r->cleartext);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_package_PrimaryWDigestHash(struct ndr_push *ndr, int ndr_flags, const struct package_PrimaryWDigestHash *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->hash, 16));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_package_PrimaryWDigestHash(struct ndr_pull *ndr, int ndr_flags, struct package_PrimaryWDigestHash *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->hash, 16));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_package_PrimaryWDigestHash(struct ndr_print *ndr, const char *name, const struct package_PrimaryWDigestHash *r)
+{
+ ndr_print_struct(ndr, name, "package_PrimaryWDigestHash");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "hash", r->hash, 16);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_package_PrimaryWDigestBlob(struct ndr_push *ndr, int ndr_flags, const struct package_PrimaryWDigestBlob *r)
+{
+ uint32_t cntr_hashes_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0x31));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 0x01));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->num_hashes));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_udlong(ndr, NDR_SCALARS, 0));
+ for (cntr_hashes_0 = 0; cntr_hashes_0 < r->num_hashes; cntr_hashes_0++) {
+ NDR_CHECK(ndr_push_package_PrimaryWDigestHash(ndr, NDR_SCALARS, &r->hashes[cntr_hashes_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_package_PrimaryWDigestBlob(struct ndr_pull *ndr, int ndr_flags, struct package_PrimaryWDigestBlob *r)
+{
+ uint32_t cntr_hashes_0;
+ TALLOC_CTX *_mem_save_hashes_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->num_hashes));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_udlong(ndr, NDR_SCALARS, &r->uuknown4));
+ NDR_PULL_ALLOC_N(ndr, r->hashes, r->num_hashes);
+ _mem_save_hashes_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->hashes, 0);
+ for (cntr_hashes_0 = 0; cntr_hashes_0 < r->num_hashes; cntr_hashes_0++) {
+ NDR_CHECK(ndr_pull_package_PrimaryWDigestHash(ndr, NDR_SCALARS, &r->hashes[cntr_hashes_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_hashes_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_package_PrimaryWDigestBlob(struct ndr_print *ndr, const char *name, const struct package_PrimaryWDigestBlob *r)
+{
+ uint32_t cntr_hashes_0;
+ ndr_print_struct(ndr, name, "package_PrimaryWDigestBlob");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "unknown1", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0x31:r->unknown1);
+ ndr_print_uint8(ndr, "unknown2", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0x01:r->unknown2);
+ ndr_print_uint8(ndr, "num_hashes", r->num_hashes);
+ ndr_print_uint32(ndr, "unknown3", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->unknown3);
+ ndr_print_udlong(ndr, "uuknown4", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->uuknown4);
+ ndr->print(ndr, "%s: ARRAY(%d)", "hashes", (int)r->num_hashes);
+ ndr->depth++;
+ for (cntr_hashes_0=0;cntr_hashes_0<r->num_hashes;cntr_hashes_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_hashes_0) != -1) {
+ ndr_print_package_PrimaryWDigestHash(ndr, "hashes", &r->hashes[cntr_hashes_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_trustAuthInOutSecret1(struct ndr_push *ndr, int ndr_flags, const struct trustAuthInOutSecret1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->time1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->value));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_trustAuthInOutSecret1(struct ndr_pull *ndr, int ndr_flags, struct trustAuthInOutSecret1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->time1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->value));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_trustAuthInOutSecret1(struct ndr_print *ndr, const char *name, const struct trustAuthInOutSecret1 *r)
+{
+ ndr_print_struct(ndr, name, "trustAuthInOutSecret1");
+ ndr->depth++;
+ ndr_print_NTTIME(ndr, "time1", r->time1);
+ ndr_print_uint32(ndr, "unknown1", r->unknown1);
+ ndr_print_DATA_BLOB(ndr, "value", r->value);
+ ndr_print_DATA_BLOB(ndr, "_pad", r->_pad);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_trustAuthInOutCtr1(struct ndr_push *ndr, int ndr_flags, const struct trustAuthInOutCtr1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->value1));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->value2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->value1) {
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, r->value1));
+ NDR_CHECK(ndr_push_trustAuthInOutSecret1(ndr, NDR_SCALARS, r->value1));
+ }
+ if (r->value2) {
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, r->value2));
+ NDR_CHECK(ndr_push_trustAuthInOutSecret1(ndr, NDR_SCALARS, r->value2));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_trustAuthInOutCtr1(struct ndr_pull *ndr, int ndr_flags, struct trustAuthInOutCtr1 *r)
+{
+ uint32_t _ptr_value1;
+ TALLOC_CTX *_mem_save_value1_0;
+ uint32_t _ptr_value2;
+ TALLOC_CTX *_mem_save_value2_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_value1));
+ if (_ptr_value1) {
+ NDR_PULL_ALLOC(ndr, r->value1);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->value1, _ptr_value1));
+ } else {
+ r->value1 = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_value2));
+ if (_ptr_value2) {
+ NDR_PULL_ALLOC(ndr, r->value2);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->value2, _ptr_value2));
+ } else {
+ r->value2 = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->value1) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->value1));
+ _mem_save_value1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->value1, 0);
+ NDR_CHECK(ndr_pull_trustAuthInOutSecret1(ndr, NDR_SCALARS, r->value1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_value1_0, 0);
+ ndr->offset = _relative_save_offset;
+ }
+ if (r->value2) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->value2));
+ _mem_save_value2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->value2, 0);
+ NDR_CHECK(ndr_pull_trustAuthInOutSecret1(ndr, NDR_SCALARS, r->value2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_value2_0, 0);
+ ndr->offset = _relative_save_offset;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_trustAuthInOutCtr1(struct ndr_print *ndr, const char *name, const struct trustAuthInOutCtr1 *r)
+{
+ ndr_print_struct(ndr, name, "trustAuthInOutCtr1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "value1", r->value1);
+ ndr->depth++;
+ if (r->value1) {
+ ndr_print_trustAuthInOutSecret1(ndr, "value1", r->value1);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "value2", r->value2);
+ ndr->depth++;
+ if (r->value2) {
+ ndr_print_trustAuthInOutSecret1(ndr, "value2", r->value2);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_trustAuthInOutSecret2V1(struct ndr_push *ndr, int ndr_flags, const struct trustAuthInOutSecret2V1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->time1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->value));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->time2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown3));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown4));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_trustAuthInOutSecret2V1(struct ndr_pull *ndr, int ndr_flags, struct trustAuthInOutSecret2V1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->time1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->value));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->time2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown4));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_trustAuthInOutSecret2V1(struct ndr_print *ndr, const char *name, const struct trustAuthInOutSecret2V1 *r)
+{
+ ndr_print_struct(ndr, name, "trustAuthInOutSecret2V1");
+ ndr->depth++;
+ ndr_print_NTTIME(ndr, "time1", r->time1);
+ ndr_print_uint32(ndr, "unknown1", r->unknown1);
+ ndr_print_DATA_BLOB(ndr, "value", r->value);
+ ndr_print_NTTIME(ndr, "time2", r->time2);
+ ndr_print_uint32(ndr, "unknown2", r->unknown2);
+ ndr_print_uint32(ndr, "unknown3", r->unknown3);
+ ndr_print_uint32(ndr, "unknown4", r->unknown4);
+ ndr_print_DATA_BLOB(ndr, "_pad", r->_pad);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_trustAuthInOutSecret2V2(struct ndr_push *ndr, int ndr_flags, const struct trustAuthInOutSecret2V2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->time1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->value));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->time2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown3));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_trustAuthInOutSecret2V2(struct ndr_pull *ndr, int ndr_flags, struct trustAuthInOutSecret2V2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->time1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->value));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->time2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown3));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_trustAuthInOutSecret2V2(struct ndr_print *ndr, const char *name, const struct trustAuthInOutSecret2V2 *r)
+{
+ ndr_print_struct(ndr, name, "trustAuthInOutSecret2V2");
+ ndr->depth++;
+ ndr_print_NTTIME(ndr, "time1", r->time1);
+ ndr_print_uint32(ndr, "unknown1", r->unknown1);
+ ndr_print_DATA_BLOB(ndr, "value", r->value);
+ ndr_print_NTTIME(ndr, "time2", r->time2);
+ ndr_print_uint32(ndr, "unknown2", r->unknown2);
+ ndr_print_uint32(ndr, "unknown3", r->unknown3);
+ ndr_print_DATA_BLOB(ndr, "_pad", r->_pad);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_trustAuthInOutCtr2(struct ndr_push *ndr, int ndr_flags, const struct trustAuthInOutCtr2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->value1));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->value2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->value1) {
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, r->value1));
+ NDR_CHECK(ndr_push_trustAuthInOutSecret2V1(ndr, NDR_SCALARS, r->value1));
+ }
+ if (r->value2) {
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, r->value2));
+ NDR_CHECK(ndr_push_trustAuthInOutSecret2V2(ndr, NDR_SCALARS, r->value2));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_trustAuthInOutCtr2(struct ndr_pull *ndr, int ndr_flags, struct trustAuthInOutCtr2 *r)
+{
+ uint32_t _ptr_value1;
+ TALLOC_CTX *_mem_save_value1_0;
+ uint32_t _ptr_value2;
+ TALLOC_CTX *_mem_save_value2_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_value1));
+ if (_ptr_value1) {
+ NDR_PULL_ALLOC(ndr, r->value1);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->value1, _ptr_value1));
+ } else {
+ r->value1 = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_value2));
+ if (_ptr_value2) {
+ NDR_PULL_ALLOC(ndr, r->value2);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->value2, _ptr_value2));
+ } else {
+ r->value2 = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->value1) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->value1));
+ _mem_save_value1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->value1, 0);
+ NDR_CHECK(ndr_pull_trustAuthInOutSecret2V1(ndr, NDR_SCALARS, r->value1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_value1_0, 0);
+ ndr->offset = _relative_save_offset;
+ }
+ if (r->value2) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->value2));
+ _mem_save_value2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->value2, 0);
+ NDR_CHECK(ndr_pull_trustAuthInOutSecret2V2(ndr, NDR_SCALARS, r->value2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_value2_0, 0);
+ ndr->offset = _relative_save_offset;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_trustAuthInOutCtr2(struct ndr_print *ndr, const char *name, const struct trustAuthInOutCtr2 *r)
+{
+ ndr_print_struct(ndr, name, "trustAuthInOutCtr2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "value1", r->value1);
+ ndr->depth++;
+ if (r->value1) {
+ ndr_print_trustAuthInOutSecret2V1(ndr, "value1", r->value1);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "value2", r->value2);
+ ndr->depth++;
+ if (r->value2) {
+ ndr_print_trustAuthInOutSecret2V2(ndr, "value2", r->value2);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_trustAuthInOutCtr(struct ndr_push *ndr, int ndr_flags, const union trustAuthInOutCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_trustAuthInOutCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_trustAuthInOutCtr2(ndr, NDR_SCALARS, &r->ctr2));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_trustAuthInOutCtr1(ndr, NDR_BUFFERS, &r->ctr1));
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_push_trustAuthInOutCtr2(ndr, NDR_BUFFERS, &r->ctr2));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_trustAuthInOutCtr(struct ndr_pull *ndr, int ndr_flags, union trustAuthInOutCtr *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_trustAuthInOutCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_pull_trustAuthInOutCtr2(ndr, NDR_SCALARS, &r->ctr2));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_trustAuthInOutCtr1(ndr, NDR_BUFFERS, &r->ctr1));
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_pull_trustAuthInOutCtr2(ndr, NDR_BUFFERS, &r->ctr2));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_trustAuthInOutCtr(struct ndr_print *ndr, const char *name, const union trustAuthInOutCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "trustAuthInOutCtr");
+ switch (level) {
+ case 1:
+ ndr_print_trustAuthInOutCtr1(ndr, "ctr1", &r->ctr1);
+ break;
+
+ case 2:
+ ndr_print_trustAuthInOutCtr2(ndr, "ctr2", &r->ctr2);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_trustAuthInOutBlob(struct ndr_push *ndr, int ndr_flags, const struct trustAuthInOutBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->ctr, r->version));
+ NDR_CHECK(ndr_push_trustAuthInOutCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_trustAuthInOutCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_trustAuthInOutBlob(struct ndr_pull *ndr, int ndr_flags, struct trustAuthInOutBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->ctr, r->version));
+ NDR_CHECK(ndr_pull_trustAuthInOutCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_trustAuthInOutCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_trustAuthInOutBlob(struct ndr_print *ndr, const char *name, const struct trustAuthInOutBlob *r)
+{
+ ndr_print_struct(ndr, name, "trustAuthInOutBlob");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "version", r->version);
+ ndr_print_set_switch_value(ndr, &r->ctr, r->version);
+ ndr_print_trustAuthInOutCtr(ndr, "ctr", &r->ctr);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_DsCompressedChunk(struct ndr_push *ndr, int ndr_flags, const struct DsCompressedChunk *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->marker));
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_DsCompressedChunk(struct ndr_pull *ndr, int ndr_flags, struct DsCompressedChunk *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->marker));
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_DsCompressedChunk(struct ndr_print *ndr, const char *name, const struct DsCompressedChunk *r)
+{
+ ndr_print_struct(ndr, name, "DsCompressedChunk");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "marker", r->marker);
+ ndr_print_DATA_BLOB(ndr, "data", r->data);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_DsCompressedBlob(struct ndr_push *ndr, int ndr_flags, const struct DsCompressedBlob *r)
+{
+ uint32_t cntr_chunks_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ for (cntr_chunks_0 = 0; cntr_chunks_0 < 5; cntr_chunks_0++) {
+ NDR_CHECK(ndr_push_DsCompressedChunk(ndr, NDR_SCALARS, &r->chunks[cntr_chunks_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_DsCompressedBlob(struct ndr_pull *ndr, int ndr_flags, struct DsCompressedBlob *r)
+{
+ uint32_t cntr_chunks_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ for (cntr_chunks_0 = 0; cntr_chunks_0 < 5; cntr_chunks_0++) {
+ NDR_CHECK(ndr_pull_DsCompressedChunk(ndr, NDR_SCALARS, &r->chunks[cntr_chunks_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_DsCompressedBlob(struct ndr_print *ndr, const char *name, const struct DsCompressedBlob *r)
+{
+ uint32_t cntr_chunks_0;
+ ndr_print_struct(ndr, name, "DsCompressedBlob");
+ ndr->depth++;
+ ndr->print(ndr, "%s: ARRAY(%d)", "chunks", (int)5);
+ ndr->depth++;
+ for (cntr_chunks_0=0;cntr_chunks_0<5;cntr_chunks_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_chunks_0) != -1) {
+ ndr_print_DsCompressedChunk(ndr, "chunks", &r->chunks[cntr_chunks_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_decode_replPropertyMetaData(struct ndr_push *ndr, int flags, const struct decode_replPropertyMetaData *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_replPropertyMetaDataBlob(ndr, NDR_SCALARS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_decode_replPropertyMetaData(struct ndr_pull *ndr, int flags, struct decode_replPropertyMetaData *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_replPropertyMetaDataBlob(ndr, NDR_SCALARS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_decode_replPropertyMetaData(struct ndr_print *ndr, const char *name, int flags, const struct decode_replPropertyMetaData *r)
+{
+ ndr_print_struct(ndr, name, "decode_replPropertyMetaData");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "decode_replPropertyMetaData");
+ ndr->depth++;
+ ndr_print_replPropertyMetaDataBlob(ndr, "blob", &r->in.blob);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "decode_replPropertyMetaData");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_decode_replUpToDateVector(struct ndr_push *ndr, int flags, const struct decode_replUpToDateVector *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_replUpToDateVectorBlob(ndr, NDR_SCALARS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_decode_replUpToDateVector(struct ndr_pull *ndr, int flags, struct decode_replUpToDateVector *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_replUpToDateVectorBlob(ndr, NDR_SCALARS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_decode_replUpToDateVector(struct ndr_print *ndr, const char *name, int flags, const struct decode_replUpToDateVector *r)
+{
+ ndr_print_struct(ndr, name, "decode_replUpToDateVector");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "decode_replUpToDateVector");
+ ndr->depth++;
+ ndr_print_replUpToDateVectorBlob(ndr, "blob", &r->in.blob);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "decode_replUpToDateVector");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_decode_repsFromTo(struct ndr_push *ndr, int flags, const struct decode_repsFromTo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_repsFromToBlob(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_decode_repsFromTo(struct ndr_pull *ndr, int flags, struct decode_repsFromTo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_repsFromToBlob(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_decode_repsFromTo(struct ndr_print *ndr, const char *name, int flags, const struct decode_repsFromTo *r)
+{
+ ndr_print_struct(ndr, name, "decode_repsFromTo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "decode_repsFromTo");
+ ndr->depth++;
+ ndr_print_repsFromToBlob(ndr, "blob", &r->in.blob);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "decode_repsFromTo");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_decode_partialAttributeSet(struct ndr_push *ndr, int flags, const struct decode_partialAttributeSet *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_partialAttributeSetBlob(ndr, NDR_SCALARS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_decode_partialAttributeSet(struct ndr_pull *ndr, int flags, struct decode_partialAttributeSet *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_partialAttributeSetBlob(ndr, NDR_SCALARS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_decode_partialAttributeSet(struct ndr_print *ndr, const char *name, int flags, const struct decode_partialAttributeSet *r)
+{
+ ndr_print_struct(ndr, name, "decode_partialAttributeSet");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "decode_partialAttributeSet");
+ ndr->depth++;
+ ndr_print_partialAttributeSetBlob(ndr, "blob", &r->in.blob);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "decode_partialAttributeSet");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_decode_prefixMap(struct ndr_push *ndr, int flags, const struct decode_prefixMap *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_prefixMapBlob(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_decode_prefixMap(struct ndr_pull *ndr, int flags, struct decode_prefixMap *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_prefixMapBlob(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_decode_prefixMap(struct ndr_print *ndr, const char *name, int flags, const struct decode_prefixMap *r)
+{
+ ndr_print_struct(ndr, name, "decode_prefixMap");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "decode_prefixMap");
+ ndr->depth++;
+ ndr_print_prefixMapBlob(ndr, "blob", &r->in.blob);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "decode_prefixMap");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_decode_ldapControlDirSync(struct ndr_push *ndr, int flags, const struct decode_ldapControlDirSync *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_ldapControlDirSyncCookie(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.cookie));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_decode_ldapControlDirSync(struct ndr_pull *ndr, int flags, struct decode_ldapControlDirSync *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_ldapControlDirSyncCookie(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.cookie));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_decode_ldapControlDirSync(struct ndr_print *ndr, const char *name, int flags, const struct decode_ldapControlDirSync *r)
+{
+ ndr_print_struct(ndr, name, "decode_ldapControlDirSync");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "decode_ldapControlDirSync");
+ ndr->depth++;
+ ndr_print_ldapControlDirSyncCookie(ndr, "cookie", &r->in.cookie);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "decode_ldapControlDirSync");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_decode_supplementalCredentials(struct ndr_push *ndr, int flags, const struct decode_supplementalCredentials *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_supplementalCredentialsBlob(ndr, NDR_SCALARS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_decode_supplementalCredentials(struct ndr_pull *ndr, int flags, struct decode_supplementalCredentials *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_supplementalCredentialsBlob(ndr, NDR_SCALARS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_decode_supplementalCredentials(struct ndr_print *ndr, const char *name, int flags, const struct decode_supplementalCredentials *r)
+{
+ ndr_print_struct(ndr, name, "decode_supplementalCredentials");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "decode_supplementalCredentials");
+ ndr->depth++;
+ ndr_print_supplementalCredentialsBlob(ndr, "blob", &r->in.blob);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "decode_supplementalCredentials");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_decode_Packages(struct ndr_push *ndr, int flags, const struct decode_Packages *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_package_PackagesBlob(ndr, NDR_SCALARS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_decode_Packages(struct ndr_pull *ndr, int flags, struct decode_Packages *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_package_PackagesBlob(ndr, NDR_SCALARS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_decode_Packages(struct ndr_print *ndr, const char *name, int flags, const struct decode_Packages *r)
+{
+ ndr_print_struct(ndr, name, "decode_Packages");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "decode_Packages");
+ ndr->depth++;
+ ndr_print_package_PackagesBlob(ndr, "blob", &r->in.blob);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "decode_Packages");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_decode_PrimaryKerberos(struct ndr_push *ndr, int flags, const struct decode_PrimaryKerberos *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_package_PrimaryKerberosBlob(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_decode_PrimaryKerberos(struct ndr_pull *ndr, int flags, struct decode_PrimaryKerberos *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_package_PrimaryKerberosBlob(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_decode_PrimaryKerberos(struct ndr_print *ndr, const char *name, int flags, const struct decode_PrimaryKerberos *r)
+{
+ ndr_print_struct(ndr, name, "decode_PrimaryKerberos");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "decode_PrimaryKerberos");
+ ndr->depth++;
+ ndr_print_package_PrimaryKerberosBlob(ndr, "blob", &r->in.blob);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "decode_PrimaryKerberos");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_decode_PrimaryCLEARTEXT(struct ndr_push *ndr, int flags, const struct decode_PrimaryCLEARTEXT *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_package_PrimaryCLEARTEXTBlob(ndr, NDR_SCALARS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_decode_PrimaryCLEARTEXT(struct ndr_pull *ndr, int flags, struct decode_PrimaryCLEARTEXT *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_package_PrimaryCLEARTEXTBlob(ndr, NDR_SCALARS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_decode_PrimaryCLEARTEXT(struct ndr_print *ndr, const char *name, int flags, const struct decode_PrimaryCLEARTEXT *r)
+{
+ ndr_print_struct(ndr, name, "decode_PrimaryCLEARTEXT");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "decode_PrimaryCLEARTEXT");
+ ndr->depth++;
+ ndr_print_package_PrimaryCLEARTEXTBlob(ndr, "blob", &r->in.blob);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "decode_PrimaryCLEARTEXT");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_decode_PrimaryWDigest(struct ndr_push *ndr, int flags, const struct decode_PrimaryWDigest *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_package_PrimaryWDigestBlob(ndr, NDR_SCALARS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_decode_PrimaryWDigest(struct ndr_pull *ndr, int flags, struct decode_PrimaryWDigest *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_package_PrimaryWDigestBlob(ndr, NDR_SCALARS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_decode_PrimaryWDigest(struct ndr_print *ndr, const char *name, int flags, const struct decode_PrimaryWDigest *r)
+{
+ ndr_print_struct(ndr, name, "decode_PrimaryWDigest");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "decode_PrimaryWDigest");
+ ndr->depth++;
+ ndr_print_package_PrimaryWDigestBlob(ndr, "blob", &r->in.blob);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "decode_PrimaryWDigest");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_decode_trustAuthInOut(struct ndr_push *ndr, int flags, const struct decode_trustAuthInOut *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_trustAuthInOutBlob(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_decode_trustAuthInOut(struct ndr_pull *ndr, int flags, struct decode_trustAuthInOut *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_trustAuthInOutBlob(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_decode_trustAuthInOut(struct ndr_print *ndr, const char *name, int flags, const struct decode_trustAuthInOut *r)
+{
+ ndr_print_struct(ndr, name, "decode_trustAuthInOut");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "decode_trustAuthInOut");
+ ndr->depth++;
+ ndr_print_trustAuthInOutBlob(ndr, "blob", &r->in.blob);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "decode_trustAuthInOut");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_decode_DsCompressed(struct ndr_push *ndr, int flags, const struct decode_DsCompressed *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_DsCompressedBlob(ndr, NDR_SCALARS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_decode_DsCompressed(struct ndr_pull *ndr, int flags, struct decode_DsCompressed *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_DsCompressedBlob(ndr, NDR_SCALARS, &r->in.blob));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_decode_DsCompressed(struct ndr_print *ndr, const char *name, int flags, const struct decode_DsCompressed *r)
+{
+ ndr_print_struct(ndr, name, "decode_DsCompressed");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "decode_DsCompressed");
+ ndr->depth++;
+ ndr_print_DsCompressedBlob(ndr, "blob", &r->in.blob);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "decode_DsCompressed");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call drsblobs_calls[] = {
+ {
+ "decode_replPropertyMetaData",
+ sizeof(struct decode_replPropertyMetaData),
+ (ndr_push_flags_fn_t) ndr_push_decode_replPropertyMetaData,
+ (ndr_pull_flags_fn_t) ndr_pull_decode_replPropertyMetaData,
+ (ndr_print_function_t) ndr_print_decode_replPropertyMetaData,
+ false,
+ },
+ {
+ "decode_replUpToDateVector",
+ sizeof(struct decode_replUpToDateVector),
+ (ndr_push_flags_fn_t) ndr_push_decode_replUpToDateVector,
+ (ndr_pull_flags_fn_t) ndr_pull_decode_replUpToDateVector,
+ (ndr_print_function_t) ndr_print_decode_replUpToDateVector,
+ false,
+ },
+ {
+ "decode_repsFromTo",
+ sizeof(struct decode_repsFromTo),
+ (ndr_push_flags_fn_t) ndr_push_decode_repsFromTo,
+ (ndr_pull_flags_fn_t) ndr_pull_decode_repsFromTo,
+ (ndr_print_function_t) ndr_print_decode_repsFromTo,
+ false,
+ },
+ {
+ "decode_partialAttributeSet",
+ sizeof(struct decode_partialAttributeSet),
+ (ndr_push_flags_fn_t) ndr_push_decode_partialAttributeSet,
+ (ndr_pull_flags_fn_t) ndr_pull_decode_partialAttributeSet,
+ (ndr_print_function_t) ndr_print_decode_partialAttributeSet,
+ false,
+ },
+ {
+ "decode_prefixMap",
+ sizeof(struct decode_prefixMap),
+ (ndr_push_flags_fn_t) ndr_push_decode_prefixMap,
+ (ndr_pull_flags_fn_t) ndr_pull_decode_prefixMap,
+ (ndr_print_function_t) ndr_print_decode_prefixMap,
+ false,
+ },
+ {
+ "decode_ldapControlDirSync",
+ sizeof(struct decode_ldapControlDirSync),
+ (ndr_push_flags_fn_t) ndr_push_decode_ldapControlDirSync,
+ (ndr_pull_flags_fn_t) ndr_pull_decode_ldapControlDirSync,
+ (ndr_print_function_t) ndr_print_decode_ldapControlDirSync,
+ false,
+ },
+ {
+ "decode_supplementalCredentials",
+ sizeof(struct decode_supplementalCredentials),
+ (ndr_push_flags_fn_t) ndr_push_decode_supplementalCredentials,
+ (ndr_pull_flags_fn_t) ndr_pull_decode_supplementalCredentials,
+ (ndr_print_function_t) ndr_print_decode_supplementalCredentials,
+ false,
+ },
+ {
+ "decode_Packages",
+ sizeof(struct decode_Packages),
+ (ndr_push_flags_fn_t) ndr_push_decode_Packages,
+ (ndr_pull_flags_fn_t) ndr_pull_decode_Packages,
+ (ndr_print_function_t) ndr_print_decode_Packages,
+ false,
+ },
+ {
+ "decode_PrimaryKerberos",
+ sizeof(struct decode_PrimaryKerberos),
+ (ndr_push_flags_fn_t) ndr_push_decode_PrimaryKerberos,
+ (ndr_pull_flags_fn_t) ndr_pull_decode_PrimaryKerberos,
+ (ndr_print_function_t) ndr_print_decode_PrimaryKerberos,
+ false,
+ },
+ {
+ "decode_PrimaryCLEARTEXT",
+ sizeof(struct decode_PrimaryCLEARTEXT),
+ (ndr_push_flags_fn_t) ndr_push_decode_PrimaryCLEARTEXT,
+ (ndr_pull_flags_fn_t) ndr_pull_decode_PrimaryCLEARTEXT,
+ (ndr_print_function_t) ndr_print_decode_PrimaryCLEARTEXT,
+ false,
+ },
+ {
+ "decode_PrimaryWDigest",
+ sizeof(struct decode_PrimaryWDigest),
+ (ndr_push_flags_fn_t) ndr_push_decode_PrimaryWDigest,
+ (ndr_pull_flags_fn_t) ndr_pull_decode_PrimaryWDigest,
+ (ndr_print_function_t) ndr_print_decode_PrimaryWDigest,
+ false,
+ },
+ {
+ "decode_trustAuthInOut",
+ sizeof(struct decode_trustAuthInOut),
+ (ndr_push_flags_fn_t) ndr_push_decode_trustAuthInOut,
+ (ndr_pull_flags_fn_t) ndr_pull_decode_trustAuthInOut,
+ (ndr_print_function_t) ndr_print_decode_trustAuthInOut,
+ false,
+ },
+ {
+ "decode_DsCompressed",
+ sizeof(struct decode_DsCompressed),
+ (ndr_push_flags_fn_t) ndr_push_decode_DsCompressed,
+ (ndr_pull_flags_fn_t) ndr_pull_decode_DsCompressed,
+ (ndr_print_function_t) ndr_print_decode_DsCompressed,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const drsblobs_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\drsblobs]",
+};
+
+static const struct ndr_interface_string_array drsblobs_endpoints = {
+ .count = 1,
+ .names = drsblobs_endpoint_strings
+};
+
+static const char * const drsblobs_authservice_strings[] = {
+ "host",
+};
+
+static const struct ndr_interface_string_array drsblobs_authservices = {
+ .count = 1,
+ .names = drsblobs_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_drsblobs = {
+ .name = "drsblobs",
+ .syntax_id = {
+ {0x12345778,0x1234,0xabcd,{0x00,0x01},{0x00,0x00,0x00,0x01}},
+ NDR_DRSBLOBS_VERSION
+ },
+ .helpstring = NDR_DRSBLOBS_HELPSTRING,
+ .num_calls = 13,
+ .calls = drsblobs_calls,
+ .endpoints = &drsblobs_endpoints,
+ .authservices = &drsblobs_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_drsblobs.h b/source3/librpc/gen_ndr/ndr_drsblobs.h
new file mode 100644
index 0000000000..171e7e25a1
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_drsblobs.h
@@ -0,0 +1,133 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/drsblobs.h"
+
+#ifndef _HEADER_NDR_drsblobs
+#define _HEADER_NDR_drsblobs
+
+#define NDR_DRSBLOBS_UUID "12345778-1234-abcd-0001-00000001"
+#define NDR_DRSBLOBS_VERSION 0.0
+#define NDR_DRSBLOBS_NAME "drsblobs"
+#define NDR_DRSBLOBS_HELPSTRING "Active Directory Replication LDAP Blobs"
+extern const struct ndr_interface_table ndr_table_drsblobs;
+#define NDR_DECODE_REPLPROPERTYMETADATA (0x00)
+
+#define NDR_DECODE_REPLUPTODATEVECTOR (0x01)
+
+#define NDR_DECODE_REPSFROMTO (0x02)
+
+#define NDR_DECODE_PARTIALATTRIBUTESET (0x03)
+
+#define NDR_DECODE_PREFIXMAP (0x04)
+
+#define NDR_DECODE_LDAPCONTROLDIRSYNC (0x05)
+
+#define NDR_DECODE_SUPPLEMENTALCREDENTIALS (0x06)
+
+#define NDR_DECODE_PACKAGES (0x07)
+
+#define NDR_DECODE_PRIMARYKERBEROS (0x08)
+
+#define NDR_DECODE_PRIMARYCLEARTEXT (0x09)
+
+#define NDR_DECODE_PRIMARYWDIGEST (0x0a)
+
+#define NDR_DECODE_TRUSTAUTHINOUT (0x0b)
+
+#define NDR_DECODE_DSCOMPRESSED (0x0c)
+
+#define NDR_DRSBLOBS_CALL_COUNT (13)
+void ndr_print_replPropertyMetaData1(struct ndr_print *ndr, const char *name, const struct replPropertyMetaData1 *r);
+void ndr_print_replPropertyMetaDataCtr1(struct ndr_print *ndr, const char *name, const struct replPropertyMetaDataCtr1 *r);
+void ndr_print_replPropertyMetaDataCtr(struct ndr_print *ndr, const char *name, const union replPropertyMetaDataCtr *r);
+enum ndr_err_code ndr_push_replPropertyMetaDataBlob(struct ndr_push *ndr, int ndr_flags, const struct replPropertyMetaDataBlob *r);
+enum ndr_err_code ndr_pull_replPropertyMetaDataBlob(struct ndr_pull *ndr, int ndr_flags, struct replPropertyMetaDataBlob *r);
+void ndr_print_replPropertyMetaDataBlob(struct ndr_print *ndr, const char *name, const struct replPropertyMetaDataBlob *r);
+void ndr_print_replUpToDateVectorCtr1(struct ndr_print *ndr, const char *name, const struct replUpToDateVectorCtr1 *r);
+void ndr_print_replUpToDateVectorCtr2(struct ndr_print *ndr, const char *name, const struct replUpToDateVectorCtr2 *r);
+void ndr_print_replUpToDateVectorCtr(struct ndr_print *ndr, const char *name, const union replUpToDateVectorCtr *r);
+enum ndr_err_code ndr_push_replUpToDateVectorBlob(struct ndr_push *ndr, int ndr_flags, const struct replUpToDateVectorBlob *r);
+enum ndr_err_code ndr_pull_replUpToDateVectorBlob(struct ndr_pull *ndr, int ndr_flags, struct replUpToDateVectorBlob *r);
+void ndr_print_replUpToDateVectorBlob(struct ndr_print *ndr, const char *name, const struct replUpToDateVectorBlob *r);
+enum ndr_err_code ndr_push_repsFromTo1OtherInfo(struct ndr_push *ndr, int ndr_flags, const struct repsFromTo1OtherInfo *r);
+enum ndr_err_code ndr_pull_repsFromTo1OtherInfo(struct ndr_pull *ndr, int ndr_flags, struct repsFromTo1OtherInfo *r);
+void ndr_print_repsFromTo1OtherInfo(struct ndr_print *ndr, const char *name, const struct repsFromTo1OtherInfo *r);
+size_t ndr_size_repsFromTo1OtherInfo(const struct repsFromTo1OtherInfo *r, int flags);
+enum ndr_err_code ndr_push_repsFromTo1(struct ndr_push *ndr, int ndr_flags, const struct repsFromTo1 *r);
+enum ndr_err_code ndr_pull_repsFromTo1(struct ndr_pull *ndr, int ndr_flags, struct repsFromTo1 *r);
+void ndr_print_repsFromTo1(struct ndr_print *ndr, const char *name, const struct repsFromTo1 *r);
+size_t ndr_size_repsFromTo1(const struct repsFromTo1 *r, int flags);
+void ndr_print_repsFromTo(struct ndr_print *ndr, const char *name, const union repsFromTo *r);
+enum ndr_err_code ndr_push_repsFromToBlob(struct ndr_push *ndr, int ndr_flags, const struct repsFromToBlob *r);
+enum ndr_err_code ndr_pull_repsFromToBlob(struct ndr_pull *ndr, int ndr_flags, struct repsFromToBlob *r);
+void ndr_print_repsFromToBlob(struct ndr_print *ndr, const char *name, const struct repsFromToBlob *r);
+void ndr_print_partialAttributeSetCtr1(struct ndr_print *ndr, const char *name, const struct partialAttributeSetCtr1 *r);
+void ndr_print_partialAttributeSetCtr(struct ndr_print *ndr, const char *name, const union partialAttributeSetCtr *r);
+enum ndr_err_code ndr_push_partialAttributeSetBlob(struct ndr_push *ndr, int ndr_flags, const struct partialAttributeSetBlob *r);
+enum ndr_err_code ndr_pull_partialAttributeSetBlob(struct ndr_pull *ndr, int ndr_flags, struct partialAttributeSetBlob *r);
+void ndr_print_partialAttributeSetBlob(struct ndr_print *ndr, const char *name, const struct partialAttributeSetBlob *r);
+void ndr_print_prefixMapVersion(struct ndr_print *ndr, const char *name, enum prefixMapVersion r);
+void ndr_print_prefixMapCtr(struct ndr_print *ndr, const char *name, const union prefixMapCtr *r);
+enum ndr_err_code ndr_push_prefixMapBlob(struct ndr_push *ndr, int ndr_flags, const struct prefixMapBlob *r);
+enum ndr_err_code ndr_pull_prefixMapBlob(struct ndr_pull *ndr, int ndr_flags, struct prefixMapBlob *r);
+void ndr_print_prefixMapBlob(struct ndr_print *ndr, const char *name, const struct prefixMapBlob *r);
+void ndr_print_ldapControlDirSyncExtra(struct ndr_print *ndr, const char *name, const union ldapControlDirSyncExtra *r);
+void ndr_print_ldapControlDirSyncBlob(struct ndr_print *ndr, const char *name, const struct ldapControlDirSyncBlob *r);
+enum ndr_err_code ndr_push_ldapControlDirSyncCookie(struct ndr_push *ndr, int ndr_flags, const struct ldapControlDirSyncCookie *r);
+enum ndr_err_code ndr_pull_ldapControlDirSyncCookie(struct ndr_pull *ndr, int ndr_flags, struct ldapControlDirSyncCookie *r);
+void ndr_print_ldapControlDirSyncCookie(struct ndr_print *ndr, const char *name, const struct ldapControlDirSyncCookie *r);
+void ndr_print_supplementalCredentialsPackage(struct ndr_print *ndr, const char *name, const struct supplementalCredentialsPackage *r);
+void ndr_print_supplementalCredentialsSignature(struct ndr_print *ndr, const char *name, enum supplementalCredentialsSignature r);
+void ndr_print_supplementalCredentialsSubBlob(struct ndr_print *ndr, const char *name, const struct supplementalCredentialsSubBlob *r);
+enum ndr_err_code ndr_push_supplementalCredentialsBlob(struct ndr_push *ndr, int ndr_flags, const struct supplementalCredentialsBlob *r);
+enum ndr_err_code ndr_pull_supplementalCredentialsBlob(struct ndr_pull *ndr, int ndr_flags, struct supplementalCredentialsBlob *r);
+void ndr_print_supplementalCredentialsBlob(struct ndr_print *ndr, const char *name, const struct supplementalCredentialsBlob *r);
+enum ndr_err_code ndr_push_package_PackagesBlob(struct ndr_push *ndr, int ndr_flags, const struct package_PackagesBlob *r);
+enum ndr_err_code ndr_pull_package_PackagesBlob(struct ndr_pull *ndr, int ndr_flags, struct package_PackagesBlob *r);
+void ndr_print_package_PackagesBlob(struct ndr_print *ndr, const char *name, const struct package_PackagesBlob *r);
+void ndr_print_package_PrimaryKerberosString(struct ndr_print *ndr, const char *name, const struct package_PrimaryKerberosString *r);
+void ndr_print_package_PrimaryKerberosKey3(struct ndr_print *ndr, const char *name, const struct package_PrimaryKerberosKey3 *r);
+void ndr_print_package_PrimaryKerberosCtr3(struct ndr_print *ndr, const char *name, const struct package_PrimaryKerberosCtr3 *r);
+void ndr_print_package_PrimaryKerberosKey4(struct ndr_print *ndr, const char *name, const struct package_PrimaryKerberosKey4 *r);
+void ndr_print_package_PrimaryKerberosCtr4(struct ndr_print *ndr, const char *name, const struct package_PrimaryKerberosCtr4 *r);
+void ndr_print_package_PrimaryKerberosCtr(struct ndr_print *ndr, const char *name, const union package_PrimaryKerberosCtr *r);
+enum ndr_err_code ndr_push_package_PrimaryKerberosBlob(struct ndr_push *ndr, int ndr_flags, const struct package_PrimaryKerberosBlob *r);
+enum ndr_err_code ndr_pull_package_PrimaryKerberosBlob(struct ndr_pull *ndr, int ndr_flags, struct package_PrimaryKerberosBlob *r);
+void ndr_print_package_PrimaryKerberosBlob(struct ndr_print *ndr, const char *name, const struct package_PrimaryKerberosBlob *r);
+enum ndr_err_code ndr_push_package_PrimaryCLEARTEXTBlob(struct ndr_push *ndr, int ndr_flags, const struct package_PrimaryCLEARTEXTBlob *r);
+enum ndr_err_code ndr_pull_package_PrimaryCLEARTEXTBlob(struct ndr_pull *ndr, int ndr_flags, struct package_PrimaryCLEARTEXTBlob *r);
+void ndr_print_package_PrimaryCLEARTEXTBlob(struct ndr_print *ndr, const char *name, const struct package_PrimaryCLEARTEXTBlob *r);
+void ndr_print_package_PrimaryWDigestHash(struct ndr_print *ndr, const char *name, const struct package_PrimaryWDigestHash *r);
+enum ndr_err_code ndr_push_package_PrimaryWDigestBlob(struct ndr_push *ndr, int ndr_flags, const struct package_PrimaryWDigestBlob *r);
+enum ndr_err_code ndr_pull_package_PrimaryWDigestBlob(struct ndr_pull *ndr, int ndr_flags, struct package_PrimaryWDigestBlob *r);
+void ndr_print_package_PrimaryWDigestBlob(struct ndr_print *ndr, const char *name, const struct package_PrimaryWDigestBlob *r);
+void ndr_print_trustAuthInOutSecret1(struct ndr_print *ndr, const char *name, const struct trustAuthInOutSecret1 *r);
+void ndr_print_trustAuthInOutCtr1(struct ndr_print *ndr, const char *name, const struct trustAuthInOutCtr1 *r);
+void ndr_print_trustAuthInOutSecret2V1(struct ndr_print *ndr, const char *name, const struct trustAuthInOutSecret2V1 *r);
+void ndr_print_trustAuthInOutSecret2V2(struct ndr_print *ndr, const char *name, const struct trustAuthInOutSecret2V2 *r);
+void ndr_print_trustAuthInOutCtr2(struct ndr_print *ndr, const char *name, const struct trustAuthInOutCtr2 *r);
+void ndr_print_trustAuthInOutCtr(struct ndr_print *ndr, const char *name, const union trustAuthInOutCtr *r);
+enum ndr_err_code ndr_push_trustAuthInOutBlob(struct ndr_push *ndr, int ndr_flags, const struct trustAuthInOutBlob *r);
+enum ndr_err_code ndr_pull_trustAuthInOutBlob(struct ndr_pull *ndr, int ndr_flags, struct trustAuthInOutBlob *r);
+void ndr_print_trustAuthInOutBlob(struct ndr_print *ndr, const char *name, const struct trustAuthInOutBlob *r);
+enum ndr_err_code ndr_push_DsCompressedChunk(struct ndr_push *ndr, int ndr_flags, const struct DsCompressedChunk *r);
+enum ndr_err_code ndr_pull_DsCompressedChunk(struct ndr_pull *ndr, int ndr_flags, struct DsCompressedChunk *r);
+void ndr_print_DsCompressedChunk(struct ndr_print *ndr, const char *name, const struct DsCompressedChunk *r);
+enum ndr_err_code ndr_push_DsCompressedBlob(struct ndr_push *ndr, int ndr_flags, const struct DsCompressedBlob *r);
+enum ndr_err_code ndr_pull_DsCompressedBlob(struct ndr_pull *ndr, int ndr_flags, struct DsCompressedBlob *r);
+void ndr_print_DsCompressedBlob(struct ndr_print *ndr, const char *name, const struct DsCompressedBlob *r);
+void ndr_print_decode_replPropertyMetaData(struct ndr_print *ndr, const char *name, int flags, const struct decode_replPropertyMetaData *r);
+void ndr_print_decode_replUpToDateVector(struct ndr_print *ndr, const char *name, int flags, const struct decode_replUpToDateVector *r);
+void ndr_print_decode_repsFromTo(struct ndr_print *ndr, const char *name, int flags, const struct decode_repsFromTo *r);
+void ndr_print_decode_partialAttributeSet(struct ndr_print *ndr, const char *name, int flags, const struct decode_partialAttributeSet *r);
+void ndr_print_decode_prefixMap(struct ndr_print *ndr, const char *name, int flags, const struct decode_prefixMap *r);
+void ndr_print_decode_ldapControlDirSync(struct ndr_print *ndr, const char *name, int flags, const struct decode_ldapControlDirSync *r);
+void ndr_print_decode_supplementalCredentials(struct ndr_print *ndr, const char *name, int flags, const struct decode_supplementalCredentials *r);
+void ndr_print_decode_Packages(struct ndr_print *ndr, const char *name, int flags, const struct decode_Packages *r);
+void ndr_print_decode_PrimaryKerberos(struct ndr_print *ndr, const char *name, int flags, const struct decode_PrimaryKerberos *r);
+void ndr_print_decode_PrimaryCLEARTEXT(struct ndr_print *ndr, const char *name, int flags, const struct decode_PrimaryCLEARTEXT *r);
+void ndr_print_decode_PrimaryWDigest(struct ndr_print *ndr, const char *name, int flags, const struct decode_PrimaryWDigest *r);
+void ndr_print_decode_trustAuthInOut(struct ndr_print *ndr, const char *name, int flags, const struct decode_trustAuthInOut *r);
+void ndr_print_decode_DsCompressed(struct ndr_print *ndr, const char *name, int flags, const struct decode_DsCompressed *r);
+#endif /* _HEADER_NDR_drsblobs */
diff --git a/source3/librpc/gen_ndr/ndr_drsuapi.c b/source3/librpc/gen_ndr/ndr_drsuapi.c
new file mode 100644
index 0000000000..38b88f643c
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_drsuapi.c
@@ -0,0 +1,14559 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_drsuapi.h"
+
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/ndr_samr.h"
+#include "librpc/ndr/ndr_compression.h"
+static enum ndr_err_code ndr_push_drsuapi_SupportedExtensions(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_SupportedExtensions(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_SupportedExtensions(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_BASE", DRSUAPI_SUPPORTED_EXTENSION_BASE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION", DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI", DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2", DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS", DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1", DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION", DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_00000080", DRSUAPI_SUPPORTED_EXTENSION_00000080, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE", DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2", DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION", DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2", DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD", DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND", DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO", DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION", DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01", DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP", DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY", DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3", DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_00100000", DRSUAPI_SUPPORTED_EXTENSION_00100000, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2", DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6", DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS", DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8", DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5", DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6", DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3", DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7", DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT", DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS", DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_20000000", DRSUAPI_SUPPORTED_EXTENSION_20000000, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_40000000", DRSUAPI_SUPPORTED_EXTENSION_40000000, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_80000000", DRSUAPI_SUPPORTED_EXTENSION_80000000, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_SupportedExtensionsExt(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_SupportedExtensionsExt(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_SupportedExtensionsExt(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_ADAM", DRSUAPI_SUPPORTED_EXTENSION_ADAM, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_SUPPORTED_EXTENSION_LH_BETA2", DRSUAPI_SUPPORTED_EXTENSION_LH_BETA2, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsBindInfo24(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsBindInfo24 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_drsuapi_SupportedExtensions(ndr, NDR_SCALARS, r->supported_extensions));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->site_guid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsBindInfo24(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsBindInfo24 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_drsuapi_SupportedExtensions(ndr, NDR_SCALARS, &r->supported_extensions));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->site_guid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsBindInfo24(struct ndr_print *ndr, const char *name, const struct drsuapi_DsBindInfo24 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsBindInfo24");
+ ndr->depth++;
+ ndr_print_drsuapi_SupportedExtensions(ndr, "supported_extensions", r->supported_extensions);
+ ndr_print_GUID(ndr, "site_guid", &r->site_guid);
+ ndr_print_uint32(ndr, "pid", r->pid);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsBindInfo28(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsBindInfo28 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_drsuapi_SupportedExtensions(ndr, NDR_SCALARS, r->supported_extensions));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->site_guid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->repl_epoch));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsBindInfo28(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsBindInfo28 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_drsuapi_SupportedExtensions(ndr, NDR_SCALARS, &r->supported_extensions));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->site_guid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->repl_epoch));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsBindInfo28(struct ndr_print *ndr, const char *name, const struct drsuapi_DsBindInfo28 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsBindInfo28");
+ ndr->depth++;
+ ndr_print_drsuapi_SupportedExtensions(ndr, "supported_extensions", r->supported_extensions);
+ ndr_print_GUID(ndr, "site_guid", &r->site_guid);
+ ndr_print_uint32(ndr, "pid", r->pid);
+ ndr_print_uint32(ndr, "repl_epoch", r->repl_epoch);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsBindInfo48(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsBindInfo48 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_drsuapi_SupportedExtensions(ndr, NDR_SCALARS, r->supported_extensions));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->site_guid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->repl_epoch));
+ NDR_CHECK(ndr_push_drsuapi_SupportedExtensionsExt(ndr, NDR_SCALARS, r->supported_extensions_ext));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->config_dn_guid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsBindInfo48(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsBindInfo48 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_drsuapi_SupportedExtensions(ndr, NDR_SCALARS, &r->supported_extensions));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->site_guid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->repl_epoch));
+ NDR_CHECK(ndr_pull_drsuapi_SupportedExtensionsExt(ndr, NDR_SCALARS, &r->supported_extensions_ext));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->config_dn_guid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsBindInfo48(struct ndr_print *ndr, const char *name, const struct drsuapi_DsBindInfo48 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsBindInfo48");
+ ndr->depth++;
+ ndr_print_drsuapi_SupportedExtensions(ndr, "supported_extensions", r->supported_extensions);
+ ndr_print_GUID(ndr, "site_guid", &r->site_guid);
+ ndr_print_uint32(ndr, "pid", r->pid);
+ ndr_print_uint32(ndr, "repl_epoch", r->repl_epoch);
+ ndr_print_drsuapi_SupportedExtensionsExt(ndr, "supported_extensions_ext", r->supported_extensions_ext);
+ ndr_print_GUID(ndr, "config_dn_guid", &r->config_dn_guid);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsBindInfoFallBack(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsBindInfoFallBack *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->info));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsBindInfoFallBack(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsBindInfoFallBack *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->info));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsBindInfoFallBack(struct ndr_print *ndr, const char *name, const struct drsuapi_DsBindInfoFallBack *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsBindInfoFallBack");
+ ndr->depth++;
+ ndr_print_DATA_BLOB(ndr, "info", r->info);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsBindInfo(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsBindInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 24: {
+ {
+ struct ndr_push *_ndr_info24;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info24, 4, -1));
+ NDR_CHECK(ndr_push_drsuapi_DsBindInfo24(_ndr_info24, NDR_SCALARS, &r->info24));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_info24, 4, -1));
+ }
+ break; }
+
+ case 28: {
+ {
+ struct ndr_push *_ndr_info28;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info28, 4, -1));
+ NDR_CHECK(ndr_push_drsuapi_DsBindInfo28(_ndr_info28, NDR_SCALARS, &r->info28));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_info28, 4, -1));
+ }
+ break; }
+
+ case 48: {
+ {
+ struct ndr_push *_ndr_info48;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info48, 4, -1));
+ NDR_CHECK(ndr_push_drsuapi_DsBindInfo48(_ndr_info48, NDR_SCALARS, &r->info48));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_info48, 4, -1));
+ }
+ break; }
+
+ default: {
+ {
+ struct ndr_push *_ndr_FallBack;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_FallBack, 4, -1));
+ NDR_CHECK(ndr_push_drsuapi_DsBindInfoFallBack(_ndr_FallBack, NDR_SCALARS, &r->FallBack));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_FallBack, 4, -1));
+ }
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 24:
+ break;
+
+ case 28:
+ break;
+
+ case 48:
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsBindInfo(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsBindInfo *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case 24: {
+ {
+ struct ndr_pull *_ndr_info24;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info24, 4, -1));
+ NDR_CHECK(ndr_pull_drsuapi_DsBindInfo24(_ndr_info24, NDR_SCALARS, &r->info24));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info24, 4, -1));
+ }
+ break; }
+
+ case 28: {
+ {
+ struct ndr_pull *_ndr_info28;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info28, 4, -1));
+ NDR_CHECK(ndr_pull_drsuapi_DsBindInfo28(_ndr_info28, NDR_SCALARS, &r->info28));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info28, 4, -1));
+ }
+ break; }
+
+ case 48: {
+ {
+ struct ndr_pull *_ndr_info48;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info48, 4, -1));
+ NDR_CHECK(ndr_pull_drsuapi_DsBindInfo48(_ndr_info48, NDR_SCALARS, &r->info48));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info48, 4, -1));
+ }
+ break; }
+
+ default: {
+ {
+ struct ndr_pull *_ndr_FallBack;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_FallBack, 4, -1));
+ NDR_CHECK(ndr_pull_drsuapi_DsBindInfoFallBack(_ndr_FallBack, NDR_SCALARS, &r->FallBack));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_FallBack, 4, -1));
+ }
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 24:
+ break;
+
+ case 28:
+ break;
+
+ case 48:
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsBindInfo(struct ndr_print *ndr, const char *name, const union drsuapi_DsBindInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsBindInfo");
+ switch (level) {
+ case 24:
+ ndr_print_drsuapi_DsBindInfo24(ndr, "info24", &r->info24);
+ break;
+
+ case 28:
+ ndr_print_drsuapi_DsBindInfo28(ndr, "info28", &r->info28);
+ break;
+
+ case 48:
+ ndr_print_drsuapi_DsBindInfo48(ndr, "info48", &r->info48);
+ break;
+
+ default:
+ ndr_print_drsuapi_DsBindInfoFallBack(ndr, "FallBack", &r->FallBack);
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsBindInfoCtr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsBindInfoCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->info, r->length));
+ NDR_CHECK(ndr_push_drsuapi_DsBindInfo(ndr, NDR_SCALARS, &r->info));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsBindInfoCtr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsBindInfoCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->length));
+ if (r->length < 1 || r->length > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->info, r->length));
+ NDR_CHECK(ndr_pull_drsuapi_DsBindInfo(ndr, NDR_SCALARS, &r->info));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsBindInfoCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsBindInfoCtr *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsBindInfoCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "length", r->length);
+ ndr_print_set_switch_value(ndr, &r->info, r->length);
+ ndr_print_drsuapi_DsBindInfo(ndr, "info", &r->info);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsReplicaObjectIdentifier(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObjectIdentifier *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, strlen_m(r->dn) + 1));
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_drsuapi_DsReplicaObjectIdentifier(r, ndr->flags) - 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_dom_sid28(&r->sid, ndr->flags)));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->guid));
+ NDR_CHECK(ndr_push_dom_sid28(ndr, NDR_SCALARS, &r->sid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, strlen_m(r->dn)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dn, strlen_m(r->dn) + 1, sizeof(uint16_t), CH_UTF16));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_dom_sid28(ndr, NDR_BUFFERS, &r->sid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjectIdentifier(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObjectIdentifier *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->dn));
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size_sid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->guid));
+ NDR_CHECK(ndr_pull_dom_sid28(ndr, NDR_SCALARS, &r->sid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size_dn));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dn, ndr_get_array_size(ndr, &r->dn), sizeof(uint16_t), CH_UTF16));
+ if (r->dn) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->dn, r->__ndr_size_dn + 1));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_dom_sid28(ndr, NDR_BUFFERS, &r->sid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaObjectIdentifier(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjectIdentifier *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaObjectIdentifier");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "__ndr_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_drsuapi_DsReplicaObjectIdentifier(r, ndr->flags) - 4:r->__ndr_size);
+ ndr_print_uint32(ndr, "__ndr_size_sid", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_dom_sid28(&r->sid, ndr->flags):r->__ndr_size_sid);
+ ndr_print_GUID(ndr, "guid", &r->guid);
+ ndr_print_dom_sid28(ndr, "sid", &r->sid);
+ ndr_print_uint32(ndr, "__ndr_size_dn", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen_m(r->dn):r->__ndr_size_dn);
+ ndr_print_string(ndr, "dn", r->dn);
+ ndr->depth--;
+}
+
+_PUBLIC_ size_t ndr_size_drsuapi_DsReplicaObjectIdentifier(const struct drsuapi_DsReplicaObjectIdentifier *r, int flags)
+{
+ return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsReplicaSyncOptions(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsReplicaSyncOptions(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaSyncOptions(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_ASYNCHRONOUS_OPERATION", DRSUAPI_DS_REPLICA_SYNC_ASYNCHRONOUS_OPERATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_WRITEABLE", DRSUAPI_DS_REPLICA_SYNC_WRITEABLE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_PERIODIC", DRSUAPI_DS_REPLICA_SYNC_PERIODIC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_INTERSITE_MESSAGING", DRSUAPI_DS_REPLICA_SYNC_INTERSITE_MESSAGING, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_ALL_SOURCES", DRSUAPI_DS_REPLICA_SYNC_ALL_SOURCES, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_FULL", DRSUAPI_DS_REPLICA_SYNC_FULL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_URGENT", DRSUAPI_DS_REPLICA_SYNC_URGENT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_NO_DISCARD", DRSUAPI_DS_REPLICA_SYNC_NO_DISCARD, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_FORCE", DRSUAPI_DS_REPLICA_SYNC_FORCE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_ADD_REFERENCE", DRSUAPI_DS_REPLICA_SYNC_ADD_REFERENCE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_NEVER_COMPLETED", DRSUAPI_DS_REPLICA_SYNC_NEVER_COMPLETED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_TWO_WAY", DRSUAPI_DS_REPLICA_SYNC_TWO_WAY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_NEVER_NOTIFY", DRSUAPI_DS_REPLICA_SYNC_NEVER_NOTIFY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_INITIAL", DRSUAPI_DS_REPLICA_SYNC_INITIAL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_USE_COMPRESSION", DRSUAPI_DS_REPLICA_SYNC_USE_COMPRESSION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_ABANDONED", DRSUAPI_DS_REPLICA_SYNC_ABANDONED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_INITIAL_IN_PROGRESS", DRSUAPI_DS_REPLICA_SYNC_INITIAL_IN_PROGRESS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_PARTIAL_ATTRIBUTE_SET", DRSUAPI_DS_REPLICA_SYNC_PARTIAL_ATTRIBUTE_SET, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_REQUEUE", DRSUAPI_DS_REPLICA_SYNC_REQUEUE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_NOTIFICATION", DRSUAPI_DS_REPLICA_SYNC_NOTIFICATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_ASYNCHRONOUS_REPLICA", DRSUAPI_DS_REPLICA_SYNC_ASYNCHRONOUS_REPLICA, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_CRITICAL", DRSUAPI_DS_REPLICA_SYNC_CRITICAL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_FULL_IN_PROGRESS", DRSUAPI_DS_REPLICA_SYNC_FULL_IN_PROGRESS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_SYNC_PREEMPTED", DRSUAPI_DS_REPLICA_SYNC_PREEMPTED, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaSyncRequest1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaSyncRequest1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->naming_context));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->source_dsa_guid));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->other_info));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaSyncOptions(ndr, NDR_SCALARS, r->options));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->naming_context) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->naming_context));
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ if (r->other_info) {
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->other_info));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaSyncRequest1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaSyncRequest1 *r)
+{
+ uint32_t _ptr_naming_context;
+ TALLOC_CTX *_mem_save_naming_context_0;
+ uint32_t _ptr_other_info;
+ TALLOC_CTX *_mem_save_other_info_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_naming_context));
+ if (_ptr_naming_context) {
+ NDR_PULL_ALLOC(ndr, r->naming_context);
+ } else {
+ r->naming_context = NULL;
+ }
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->source_dsa_guid));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_other_info));
+ if (_ptr_other_info) {
+ NDR_PULL_ALLOC(ndr, r->other_info);
+ } else {
+ r->other_info = NULL;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaSyncOptions(ndr, NDR_SCALARS, &r->options));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->naming_context) {
+ _mem_save_naming_context_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->naming_context, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->naming_context));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_naming_context_0, 0);
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ if (r->other_info) {
+ _mem_save_other_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->other_info, 0);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->other_info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_other_info_0, 0);
+ }
+ ndr->flags = _flags_save_string;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaSyncRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaSyncRequest1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaSyncRequest1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "naming_context", r->naming_context);
+ ndr->depth++;
+ if (r->naming_context) {
+ ndr_print_drsuapi_DsReplicaObjectIdentifier(ndr, "naming_context", r->naming_context);
+ }
+ ndr->depth--;
+ ndr_print_GUID(ndr, "source_dsa_guid", &r->source_dsa_guid);
+ ndr_print_ptr(ndr, "other_info", r->other_info);
+ ndr->depth++;
+ if (r->other_info) {
+ ndr_print_string(ndr, "other_info", r->other_info);
+ }
+ ndr->depth--;
+ ndr_print_drsuapi_DsReplicaSyncOptions(ndr, "options", r->options);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaSyncRequest(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsReplicaSyncRequest *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaSyncRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaSyncRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaSyncRequest(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsReplicaSyncRequest *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaSyncRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaSyncRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaSyncRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsReplicaSyncRequest *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsReplicaSyncRequest");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsReplicaSyncRequest1(ndr, "req1", &r->req1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsReplicaHighWaterMark(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaHighWaterMark *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->tmp_highest_usn));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->reserved_usn));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->highest_usn));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsReplicaHighWaterMark(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaHighWaterMark *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->tmp_highest_usn));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->reserved_usn));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->highest_usn));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaHighWaterMark(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaHighWaterMark *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaHighWaterMark");
+ ndr->depth++;
+ ndr_print_hyper(ndr, "tmp_highest_usn", r->tmp_highest_usn);
+ ndr_print_hyper(ndr, "reserved_usn", r->reserved_usn);
+ ndr_print_hyper(ndr, "highest_usn", r->highest_usn);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsReplicaCursor(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaCursor *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->highest_usn));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsReplicaCursor(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaCursor *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->highest_usn));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaCursor(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaCursor *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaCursor");
+ ndr->depth++;
+ ndr_print_GUID(ndr, "source_dsa_invocation_id", &r->source_dsa_invocation_id);
+ ndr_print_hyper(ndr, "highest_usn", r->highest_usn);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaCursorCtrEx(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaCursorCtrEx *r)
+{
+ uint32_t cntr_cursors_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ for (cntr_cursors_0 = 0; cntr_cursors_0 < r->count; cntr_cursors_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaCursor(ndr, NDR_SCALARS, &r->cursors[cntr_cursors_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaCursorCtrEx(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaCursorCtrEx *r)
+{
+ uint32_t cntr_cursors_0;
+ TALLOC_CTX *_mem_save_cursors_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->cursors));
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 0x100000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved2));
+ NDR_PULL_ALLOC_N(ndr, r->cursors, ndr_get_array_size(ndr, &r->cursors));
+ _mem_save_cursors_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->cursors, 0);
+ for (cntr_cursors_0 = 0; cntr_cursors_0 < r->count; cntr_cursors_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaCursor(ndr, NDR_SCALARS, &r->cursors[cntr_cursors_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cursors_0, 0);
+ if (r->cursors) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->cursors, r->count));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaCursorCtrEx(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaCursorCtrEx *r)
+{
+ uint32_t cntr_cursors_0;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaCursorCtrEx");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "version", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?1:r->version);
+ ndr_print_uint32(ndr, "reserved1", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->reserved1);
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_uint32(ndr, "reserved2", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->reserved2);
+ ndr->print(ndr, "%s: ARRAY(%d)", "cursors", (int)r->count);
+ ndr->depth++;
+ for (cntr_cursors_0=0;cntr_cursors_0<r->count;cntr_cursors_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_cursors_0) != -1) {
+ ndr_print_drsuapi_DsReplicaCursor(ndr, "cursors", &r->cursors[cntr_cursors_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsReplicaNeighbourFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsReplicaNeighbourFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaNeighbourFlags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE", DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP", DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS", DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_NEIGHBOUR_USE_ASYNC_INTERSIDE_TRANSPORT", DRSUAPI_DS_REPLICA_NEIGHBOUR_USE_ASYNC_INTERSIDE_TRANSPORT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_NEIGHBOUR_TWO_WAY_SYNC", DRSUAPI_DS_REPLICA_NEIGHBOUR_TWO_WAY_SYNC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS", DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS", DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_NEXT_PACKET", DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_NEXT_PACKET, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED", DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_NEIGHBOUR_PREEMPTED", DRSUAPI_DS_REPLICA_NEIGHBOUR_PREEMPTED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_NEIGHBOUR_IGNORE_CHANGE_NOTIFICATIONS", DRSUAPI_DS_REPLICA_NEIGHBOUR_IGNORE_CHANGE_NOTIFICATIONS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_NEIGHBOUR_DISABLE_SCHEDULED_SYNC", DRSUAPI_DS_REPLICA_NEIGHBOUR_DISABLE_SCHEDULED_SYNC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES", DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_NEIGHBOUR_NO_CHANGE_NOTIFICATIONS", DRSUAPI_DS_REPLICA_NEIGHBOUR_NO_CHANGE_NOTIFICATIONS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_NEIGHBOUR_PARTIAL_ATTRIBUTE_SET", DRSUAPI_DS_REPLICA_NEIGHBOUR_PARTIAL_ATTRIBUTE_SET, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsExtendedOperation(struct ndr_push *ndr, int ndr_flags, enum drsuapi_DsExtendedOperation r)
+{
+ {
+ uint32_t _flags_save_ENUM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ ndr->flags = _flags_save_ENUM;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsExtendedOperation(struct ndr_pull *ndr, int ndr_flags, enum drsuapi_DsExtendedOperation *r)
+{
+ uint32_t v;
+ {
+ uint32_t _flags_save_ENUM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ ndr->flags = _flags_save_ENUM;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsExtendedOperation(struct ndr_print *ndr, const char *name, enum drsuapi_DsExtendedOperation r)
+{
+ const char *val = NULL;
+
+ {
+ uint32_t _flags_save_ENUM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ switch (r) {
+ case DRSUAPI_EXOP_NONE: val = "DRSUAPI_EXOP_NONE"; break;
+ case DRSUAPI_EXOP_FSMO_REQ_ROLE: val = "DRSUAPI_EXOP_FSMO_REQ_ROLE"; break;
+ case DRSUAPI_EXOP_FSMO_RID_ALLOC: val = "DRSUAPI_EXOP_FSMO_RID_ALLOC"; break;
+ case DRSUAPI_EXOP_FSMO_RID_REQ_ROLE: val = "DRSUAPI_EXOP_FSMO_RID_REQ_ROLE"; break;
+ case DRSUAPI_EXOP_FSMO_REQ_PDC: val = "DRSUAPI_EXOP_FSMO_REQ_PDC"; break;
+ case DRSUAPI_EXOP_FSMO_ABANDON_ROLE: val = "DRSUAPI_EXOP_FSMO_ABANDON_ROLE"; break;
+ case DRSUAPI_EXOP_REPL_OBJ: val = "DRSUAPI_EXOP_REPL_OBJ"; break;
+ case DRSUAPI_EXOP_REPL_SECRET: val = "DRSUAPI_EXOP_REPL_SECRET"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+ ndr->flags = _flags_save_ENUM;
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsExtendedError(struct ndr_push *ndr, int ndr_flags, enum drsuapi_DsExtendedError r)
+{
+ {
+ uint32_t _flags_save_ENUM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ ndr->flags = _flags_save_ENUM;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsExtendedError(struct ndr_pull *ndr, int ndr_flags, enum drsuapi_DsExtendedError *r)
+{
+ uint32_t v;
+ {
+ uint32_t _flags_save_ENUM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ ndr->flags = _flags_save_ENUM;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsExtendedError(struct ndr_print *ndr, const char *name, enum drsuapi_DsExtendedError r)
+{
+ const char *val = NULL;
+
+ {
+ uint32_t _flags_save_ENUM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ switch (r) {
+ case DRSUAPI_EXOP_ERR_NONE: val = "DRSUAPI_EXOP_ERR_NONE"; break;
+ case DRSUAPI_EXOP_ERR_SUCCESS: val = "DRSUAPI_EXOP_ERR_SUCCESS"; break;
+ case DRSUAPI_EXOP_ERR_UNKNOWN_OP: val = "DRSUAPI_EXOP_ERR_UNKNOWN_OP"; break;
+ case DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER: val = "DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER"; break;
+ case DRSUAPI_EXOP_ERR_UPDATE_ERR: val = "DRSUAPI_EXOP_ERR_UPDATE_ERR"; break;
+ case DRSUAPI_EXOP_ERR_EXCEPTION: val = "DRSUAPI_EXOP_ERR_EXCEPTION"; break;
+ case DRSUAPI_EXOP_ERR_UNKNOWN_CALLER: val = "DRSUAPI_EXOP_ERR_UNKNOWN_CALLER"; break;
+ case DRSUAPI_EXOP_ERR_RID_ALLOC: val = "DRSUAPI_EXOP_ERR_RID_ALLOC"; break;
+ case DRSUAPI_EXOP_ERR_FSMO_OWNER_DELETED: val = "DRSUAPI_EXOP_ERR_FSMO_OWNER_DELETED"; break;
+ case DRSUAPI_EXOP_ERR_FMSO_PENDING_OP: val = "DRSUAPI_EXOP_ERR_FMSO_PENDING_OP"; break;
+ case DRSUAPI_EXOP_ERR_MISMATCH: val = "DRSUAPI_EXOP_ERR_MISMATCH"; break;
+ case DRSUAPI_EXOP_ERR_COULDNT_CONTACT: val = "DRSUAPI_EXOP_ERR_COULDNT_CONTACT"; break;
+ case DRSUAPI_EXOP_ERR_FSMO_REFUSING_ROLES: val = "DRSUAPI_EXOP_ERR_FSMO_REFUSING_ROLES"; break;
+ case DRSUAPI_EXOP_ERR_DIR_ERROR: val = "DRSUAPI_EXOP_ERR_DIR_ERROR"; break;
+ case DRSUAPI_EXOP_ERR_FSMO_MISSING_SETTINGS: val = "DRSUAPI_EXOP_ERR_FSMO_MISSING_SETTINGS"; break;
+ case DRSUAPI_EXOP_ERR_ACCESS_DENIED: val = "DRSUAPI_EXOP_ERR_ACCESS_DENIED"; break;
+ case DRSUAPI_EXOP_ERR_PARAM_ERROR: val = "DRSUAPI_EXOP_ERR_PARAM_ERROR"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+ ndr->flags = _flags_save_ENUM;
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesRequest5(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNCChangesRequest5 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->destination_dsa_guid));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ if (r->naming_context == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_ref_ptr(ndr));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaHighWaterMark(ndr, NDR_SCALARS, &r->highwatermark));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->uptodateness_vector));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaNeighbourFlags(ndr, NDR_SCALARS, r->replica_flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_object_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_ndr_size));
+ NDR_CHECK(ndr_push_drsuapi_DsExtendedOperation(ndr, NDR_SCALARS, r->extended_op));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->fsmo_info));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->naming_context));
+ if (r->uptodateness_vector) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaCursorCtrEx(ndr, NDR_SCALARS, r->uptodateness_vector));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNCChangesRequest5(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetNCChangesRequest5 *r)
+{
+ uint32_t _ptr_naming_context;
+ TALLOC_CTX *_mem_save_naming_context_0;
+ uint32_t _ptr_uptodateness_vector;
+ TALLOC_CTX *_mem_save_uptodateness_vector_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->destination_dsa_guid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ NDR_CHECK(ndr_pull_ref_ptr(ndr, &_ptr_naming_context));
+ if (_ptr_naming_context) {
+ NDR_PULL_ALLOC(ndr, r->naming_context);
+ } else {
+ r->naming_context = NULL;
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaHighWaterMark(ndr, NDR_SCALARS, &r->highwatermark));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_uptodateness_vector));
+ if (_ptr_uptodateness_vector) {
+ NDR_PULL_ALLOC(ndr, r->uptodateness_vector);
+ } else {
+ r->uptodateness_vector = NULL;
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaNeighbourFlags(ndr, NDR_SCALARS, &r->replica_flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_object_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_ndr_size));
+ NDR_CHECK(ndr_pull_drsuapi_DsExtendedOperation(ndr, NDR_SCALARS, &r->extended_op));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->fsmo_info));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_naming_context_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->naming_context, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->naming_context));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_naming_context_0, 0);
+ if (r->uptodateness_vector) {
+ _mem_save_uptodateness_vector_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->uptodateness_vector, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaCursorCtrEx(ndr, NDR_SCALARS, r->uptodateness_vector));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_uptodateness_vector_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNCChangesRequest5(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesRequest5 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetNCChangesRequest5");
+ ndr->depth++;
+ ndr_print_GUID(ndr, "destination_dsa_guid", &r->destination_dsa_guid);
+ ndr_print_GUID(ndr, "source_dsa_invocation_id", &r->source_dsa_invocation_id);
+ ndr_print_ptr(ndr, "naming_context", r->naming_context);
+ ndr->depth++;
+ ndr_print_drsuapi_DsReplicaObjectIdentifier(ndr, "naming_context", r->naming_context);
+ ndr->depth--;
+ ndr_print_drsuapi_DsReplicaHighWaterMark(ndr, "highwatermark", &r->highwatermark);
+ ndr_print_ptr(ndr, "uptodateness_vector", r->uptodateness_vector);
+ ndr->depth++;
+ if (r->uptodateness_vector) {
+ ndr_print_drsuapi_DsReplicaCursorCtrEx(ndr, "uptodateness_vector", r->uptodateness_vector);
+ }
+ ndr->depth--;
+ ndr_print_drsuapi_DsReplicaNeighbourFlags(ndr, "replica_flags", r->replica_flags);
+ ndr_print_uint32(ndr, "max_object_count", r->max_object_count);
+ ndr_print_uint32(ndr, "max_ndr_size", r->max_ndr_size);
+ ndr_print_drsuapi_DsExtendedOperation(ndr, "extended_op", r->extended_op);
+ ndr_print_hyper(ndr, "fsmo_info", r->fsmo_info);
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaOID(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaOID *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaOID");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "__ndr_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_drsuapi_DsReplicaOID_oid(r->oid, 0):r->__ndr_size);
+ ndr_print_ptr(ndr, "oid", r->oid);
+ ndr->depth++;
+ if (r->oid) {
+ ndr_print_string(ndr, "oid", r->oid);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaOIDMapping(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaOIDMapping *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->id_prefix));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOID(ndr, NDR_SCALARS, &r->oid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOID(ndr, NDR_BUFFERS, &r->oid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaOIDMapping(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaOIDMapping *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->id_prefix));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaOID(ndr, NDR_SCALARS, &r->oid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaOID(ndr, NDR_BUFFERS, &r->oid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaOIDMapping(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaOIDMapping *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaOIDMapping");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "id_prefix", r->id_prefix);
+ ndr_print_drsuapi_DsReplicaOID(ndr, "oid", &r->oid);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsReplicaOIDMapping_Ctr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaOIDMapping_Ctr *r)
+{
+ uint32_t cntr_mappings_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_mappings));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->mappings));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->mappings) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_mappings));
+ for (cntr_mappings_1 = 0; cntr_mappings_1 < r->num_mappings; cntr_mappings_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOIDMapping(ndr, NDR_SCALARS, &r->mappings[cntr_mappings_1]));
+ }
+ for (cntr_mappings_1 = 0; cntr_mappings_1 < r->num_mappings; cntr_mappings_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOIDMapping(ndr, NDR_BUFFERS, &r->mappings[cntr_mappings_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsReplicaOIDMapping_Ctr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaOIDMapping_Ctr *r)
+{
+ uint32_t _ptr_mappings;
+ uint32_t cntr_mappings_1;
+ TALLOC_CTX *_mem_save_mappings_0;
+ TALLOC_CTX *_mem_save_mappings_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_mappings));
+ if (r->num_mappings < 0 || r->num_mappings > 0x100000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_mappings));
+ if (_ptr_mappings) {
+ NDR_PULL_ALLOC(ndr, r->mappings);
+ } else {
+ r->mappings = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->mappings) {
+ _mem_save_mappings_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->mappings, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->mappings));
+ NDR_PULL_ALLOC_N(ndr, r->mappings, ndr_get_array_size(ndr, &r->mappings));
+ _mem_save_mappings_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->mappings, 0);
+ for (cntr_mappings_1 = 0; cntr_mappings_1 < r->num_mappings; cntr_mappings_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaOIDMapping(ndr, NDR_SCALARS, &r->mappings[cntr_mappings_1]));
+ }
+ for (cntr_mappings_1 = 0; cntr_mappings_1 < r->num_mappings; cntr_mappings_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaOIDMapping(ndr, NDR_BUFFERS, &r->mappings[cntr_mappings_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_mappings_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_mappings_0, 0);
+ }
+ if (r->mappings) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->mappings, r->num_mappings));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaOIDMapping_Ctr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaOIDMapping_Ctr *r)
+{
+ uint32_t cntr_mappings_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaOIDMapping_Ctr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_mappings", r->num_mappings);
+ ndr_print_ptr(ndr, "mappings", r->mappings);
+ ndr->depth++;
+ if (r->mappings) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "mappings", (int)r->num_mappings);
+ ndr->depth++;
+ for (cntr_mappings_1=0;cntr_mappings_1<r->num_mappings;cntr_mappings_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_mappings_1) != -1) {
+ ndr_print_drsuapi_DsReplicaOIDMapping(ndr, "mappings", &r->mappings[cntr_mappings_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsAttributeId(struct ndr_push *ndr, int ndr_flags, enum drsuapi_DsAttributeId r)
+{
+ {
+ uint32_t _flags_save_ENUM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ ndr->flags = _flags_save_ENUM;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsAttributeId(struct ndr_pull *ndr, int ndr_flags, enum drsuapi_DsAttributeId *r)
+{
+ uint32_t v;
+ {
+ uint32_t _flags_save_ENUM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ ndr->flags = _flags_save_ENUM;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAttributeId(struct ndr_print *ndr, const char *name, enum drsuapi_DsAttributeId r)
+{
+ const char *val = NULL;
+
+ {
+ uint32_t _flags_save_ENUM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ switch (r) {
+ case DRSUAPI_ATTRIBUTE_objectClass: val = "DRSUAPI_ATTRIBUTE_objectClass"; break;
+ case DRSUAPI_ATTRIBUTE_description: val = "DRSUAPI_ATTRIBUTE_description"; break;
+ case DRSUAPI_ATTRIBUTE_member: val = "DRSUAPI_ATTRIBUTE_member"; break;
+ case DRSUAPI_ATTRIBUTE_instanceType: val = "DRSUAPI_ATTRIBUTE_instanceType"; break;
+ case DRSUAPI_ATTRIBUTE_whenCreated: val = "DRSUAPI_ATTRIBUTE_whenCreated"; break;
+ case DRSUAPI_ATTRIBUTE_hasMasterNCs: val = "DRSUAPI_ATTRIBUTE_hasMasterNCs"; break;
+ case DRSUAPI_ATTRIBUTE_governsID: val = "DRSUAPI_ATTRIBUTE_governsID"; break;
+ case DRSUAPI_ATTRIBUTE_attributeID: val = "DRSUAPI_ATTRIBUTE_attributeID"; break;
+ case DRSUAPI_ATTRIBUTE_attributeSyntax: val = "DRSUAPI_ATTRIBUTE_attributeSyntax"; break;
+ case DRSUAPI_ATTRIBUTE_isSingleValued: val = "DRSUAPI_ATTRIBUTE_isSingleValued"; break;
+ case DRSUAPI_ATTRIBUTE_rangeLower: val = "DRSUAPI_ATTRIBUTE_rangeLower"; break;
+ case DRSUAPI_ATTRIBUTE_rangeUpper: val = "DRSUAPI_ATTRIBUTE_rangeUpper"; break;
+ case DRSUAPI_ATTRIBUTE_dMDLocation: val = "DRSUAPI_ATTRIBUTE_dMDLocation"; break;
+ case DRSUAPI_ATTRIBUTE_objectVersion: val = "DRSUAPI_ATTRIBUTE_objectVersion"; break;
+ case DRSUAPI_ATTRIBUTE_invocationId: val = "DRSUAPI_ATTRIBUTE_invocationId"; break;
+ case DRSUAPI_ATTRIBUTE_showInAdvancedViewOnly: val = "DRSUAPI_ATTRIBUTE_showInAdvancedViewOnly"; break;
+ case DRSUAPI_ATTRIBUTE_adminDisplayName: val = "DRSUAPI_ATTRIBUTE_adminDisplayName"; break;
+ case DRSUAPI_ATTRIBUTE_adminDescription: val = "DRSUAPI_ATTRIBUTE_adminDescription"; break;
+ case DRSUAPI_ATTRIBUTE_oMSyntax: val = "DRSUAPI_ATTRIBUTE_oMSyntax"; break;
+ case DRSUAPI_ATTRIBUTE_ntSecurityDescriptor: val = "DRSUAPI_ATTRIBUTE_ntSecurityDescriptor"; break;
+ case DRSUAPI_ATTRIBUTE_searchFlags: val = "DRSUAPI_ATTRIBUTE_searchFlags"; break;
+ case DRSUAPI_ATTRIBUTE_lDAPDisplayName: val = "DRSUAPI_ATTRIBUTE_lDAPDisplayName"; break;
+ case DRSUAPI_ATTRIBUTE_name: val = "DRSUAPI_ATTRIBUTE_name"; break;
+ case DRSUAPI_ATTRIBUTE_userAccountControl: val = "DRSUAPI_ATTRIBUTE_userAccountControl"; break;
+ case DRSUAPI_ATTRIBUTE_currentValue: val = "DRSUAPI_ATTRIBUTE_currentValue"; break;
+ case DRSUAPI_ATTRIBUTE_homeDirectory: val = "DRSUAPI_ATTRIBUTE_homeDirectory"; break;
+ case DRSUAPI_ATTRIBUTE_homeDrive: val = "DRSUAPI_ATTRIBUTE_homeDrive"; break;
+ case DRSUAPI_ATTRIBUTE_scriptPath: val = "DRSUAPI_ATTRIBUTE_scriptPath"; break;
+ case DRSUAPI_ATTRIBUTE_profilePath: val = "DRSUAPI_ATTRIBUTE_profilePath"; break;
+ case DRSUAPI_ATTRIBUTE_objectSid: val = "DRSUAPI_ATTRIBUTE_objectSid"; break;
+ case DRSUAPI_ATTRIBUTE_schemaIDGUID: val = "DRSUAPI_ATTRIBUTE_schemaIDGUID"; break;
+ case DRSUAPI_ATTRIBUTE_dBCSPwd: val = "DRSUAPI_ATTRIBUTE_dBCSPwd"; break;
+ case DRSUAPI_ATTRIBUTE_logonHours: val = "DRSUAPI_ATTRIBUTE_logonHours"; break;
+ case DRSUAPI_ATTRIBUTE_userWorkstations: val = "DRSUAPI_ATTRIBUTE_userWorkstations"; break;
+ case DRSUAPI_ATTRIBUTE_unicodePwd: val = "DRSUAPI_ATTRIBUTE_unicodePwd"; break;
+ case DRSUAPI_ATTRIBUTE_ntPwdHistory: val = "DRSUAPI_ATTRIBUTE_ntPwdHistory"; break;
+ case DRSUAPI_ATTRIBUTE_priorValue: val = "DRSUAPI_ATTRIBUTE_priorValue"; break;
+ case DRSUAPI_ATTRIBUTE_supplementalCredentials: val = "DRSUAPI_ATTRIBUTE_supplementalCredentials"; break;
+ case DRSUAPI_ATTRIBUTE_trustAuthIncoming: val = "DRSUAPI_ATTRIBUTE_trustAuthIncoming"; break;
+ case DRSUAPI_ATTRIBUTE_trustAuthOutgoing: val = "DRSUAPI_ATTRIBUTE_trustAuthOutgoing"; break;
+ case DRSUAPI_ATTRIBUTE_lmPwdHistory: val = "DRSUAPI_ATTRIBUTE_lmPwdHistory"; break;
+ case DRSUAPI_ATTRIBUTE_sAMAccountName: val = "DRSUAPI_ATTRIBUTE_sAMAccountName"; break;
+ case DRSUAPI_ATTRIBUTE_sAMAccountType: val = "DRSUAPI_ATTRIBUTE_sAMAccountType"; break;
+ case DRSUAPI_ATTRIBUTE_fSMORoleOwner: val = "DRSUAPI_ATTRIBUTE_fSMORoleOwner"; break;
+ case DRSUAPI_ATTRIBUTE_systemFlags: val = "DRSUAPI_ATTRIBUTE_systemFlags"; break;
+ case DRSUAPI_ATTRIBUTE_serverReference: val = "DRSUAPI_ATTRIBUTE_serverReference"; break;
+ case DRSUAPI_ATTRIBUTE_serverReferenceBL: val = "DRSUAPI_ATTRIBUTE_serverReferenceBL"; break;
+ case DRSUAPI_ATTRIBUTE_initialAuthIncoming: val = "DRSUAPI_ATTRIBUTE_initialAuthIncoming"; break;
+ case DRSUAPI_ATTRIBUTE_initialAuthOutgoing: val = "DRSUAPI_ATTRIBUTE_initialAuthOutgoing"; break;
+ case DRSUAPI_ATTRIBUTE_wellKnownObjects: val = "DRSUAPI_ATTRIBUTE_wellKnownObjects"; break;
+ case DRSUAPI_ATTRIBUTE_dNSHostName: val = "DRSUAPI_ATTRIBUTE_dNSHostName"; break;
+ case DRSUAPI_ATTRIBUTE_isMemberOfPartialAttributeSet: val = "DRSUAPI_ATTRIBUTE_isMemberOfPartialAttributeSet"; break;
+ case DRSUAPI_ATTRIBUTE_userPrincipalName: val = "DRSUAPI_ATTRIBUTE_userPrincipalName"; break;
+ case DRSUAPI_ATTRIBUTE_groupType: val = "DRSUAPI_ATTRIBUTE_groupType"; break;
+ case DRSUAPI_ATTRIBUTE_servicePrincipalName: val = "DRSUAPI_ATTRIBUTE_servicePrincipalName"; break;
+ case DRSUAPI_ATTRIBUTE_objectCategory: val = "DRSUAPI_ATTRIBUTE_objectCategory"; break;
+ case DRSUAPI_ATTRIBUTE_gPLink: val = "DRSUAPI_ATTRIBUTE_gPLink"; break;
+ case DRSUAPI_ATTRIBUTE_msDS_Behavior_Version: val = "DRSUAPI_ATTRIBUTE_msDS_Behavior_Version"; break;
+ case DRSUAPI_ATTRIBUTE_msDS_KeyVersionNumber: val = "DRSUAPI_ATTRIBUTE_msDS_KeyVersionNumber"; break;
+ case DRSUAPI_ATTRIBUTE_msDS_HasDomainNCs: val = "DRSUAPI_ATTRIBUTE_msDS_HasDomainNCs"; break;
+ case DRSUAPI_ATTRIBUTE_msDS_hasMasterNCs: val = "DRSUAPI_ATTRIBUTE_msDS_hasMasterNCs"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+ ndr->flags = _flags_save_ENUM;
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsPartialAttributeSet(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsPartialAttributeSet *r)
+{
+ uint32_t cntr_attids_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_attids));
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_attids));
+ for (cntr_attids_0 = 0; cntr_attids_0 < r->num_attids; cntr_attids_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsAttributeId(ndr, NDR_SCALARS, r->attids[cntr_attids_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsPartialAttributeSet(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsPartialAttributeSet *r)
+{
+ uint32_t cntr_attids_0;
+ TALLOC_CTX *_mem_save_attids_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->attids));
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_attids));
+ if (r->num_attids < 1 || r->num_attids > 0x100000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_PULL_ALLOC_N(ndr, r->attids, ndr_get_array_size(ndr, &r->attids));
+ _mem_save_attids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->attids, 0);
+ for (cntr_attids_0 = 0; cntr_attids_0 < r->num_attids; cntr_attids_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsAttributeId(ndr, NDR_SCALARS, &r->attids[cntr_attids_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_attids_0, 0);
+ if (r->attids) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->attids, r->num_attids));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsPartialAttributeSet(struct ndr_print *ndr, const char *name, const struct drsuapi_DsPartialAttributeSet *r)
+{
+ uint32_t cntr_attids_0;
+ ndr_print_struct(ndr, name, "drsuapi_DsPartialAttributeSet");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "version", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?1:r->version);
+ ndr_print_uint32(ndr, "reserved1", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->reserved1);
+ ndr_print_uint32(ndr, "num_attids", r->num_attids);
+ ndr->print(ndr, "%s: ARRAY(%d)", "attids", (int)r->num_attids);
+ ndr->depth++;
+ for (cntr_attids_0=0;cntr_attids_0<r->num_attids;cntr_attids_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_attids_0) != -1) {
+ ndr_print_drsuapi_DsAttributeId(ndr, "attids", r->attids[cntr_attids_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesRequest8(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNCChangesRequest8 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->destination_dsa_guid));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ if (r->naming_context == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_ref_ptr(ndr));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaHighWaterMark(ndr, NDR_SCALARS, &r->highwatermark));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->uptodateness_vector));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaNeighbourFlags(ndr, NDR_SCALARS, r->replica_flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_object_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_ndr_size));
+ NDR_CHECK(ndr_push_drsuapi_DsExtendedOperation(ndr, NDR_SCALARS, r->extended_op));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->fsmo_info));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->partial_attribute_set));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->partial_attribute_set_ex));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOIDMapping_Ctr(ndr, NDR_SCALARS, &r->mapping_ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->naming_context));
+ if (r->uptodateness_vector) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaCursorCtrEx(ndr, NDR_SCALARS, r->uptodateness_vector));
+ }
+ if (r->partial_attribute_set) {
+ NDR_CHECK(ndr_push_drsuapi_DsPartialAttributeSet(ndr, NDR_SCALARS, r->partial_attribute_set));
+ }
+ if (r->partial_attribute_set_ex) {
+ NDR_CHECK(ndr_push_drsuapi_DsPartialAttributeSet(ndr, NDR_SCALARS, r->partial_attribute_set_ex));
+ }
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOIDMapping_Ctr(ndr, NDR_BUFFERS, &r->mapping_ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNCChangesRequest8(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetNCChangesRequest8 *r)
+{
+ uint32_t _ptr_naming_context;
+ TALLOC_CTX *_mem_save_naming_context_0;
+ uint32_t _ptr_uptodateness_vector;
+ TALLOC_CTX *_mem_save_uptodateness_vector_0;
+ uint32_t _ptr_partial_attribute_set;
+ TALLOC_CTX *_mem_save_partial_attribute_set_0;
+ uint32_t _ptr_partial_attribute_set_ex;
+ TALLOC_CTX *_mem_save_partial_attribute_set_ex_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->destination_dsa_guid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ NDR_CHECK(ndr_pull_ref_ptr(ndr, &_ptr_naming_context));
+ if (_ptr_naming_context) {
+ NDR_PULL_ALLOC(ndr, r->naming_context);
+ } else {
+ r->naming_context = NULL;
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaHighWaterMark(ndr, NDR_SCALARS, &r->highwatermark));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_uptodateness_vector));
+ if (_ptr_uptodateness_vector) {
+ NDR_PULL_ALLOC(ndr, r->uptodateness_vector);
+ } else {
+ r->uptodateness_vector = NULL;
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaNeighbourFlags(ndr, NDR_SCALARS, &r->replica_flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_object_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_ndr_size));
+ NDR_CHECK(ndr_pull_drsuapi_DsExtendedOperation(ndr, NDR_SCALARS, &r->extended_op));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->fsmo_info));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_partial_attribute_set));
+ if (_ptr_partial_attribute_set) {
+ NDR_PULL_ALLOC(ndr, r->partial_attribute_set);
+ } else {
+ r->partial_attribute_set = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_partial_attribute_set_ex));
+ if (_ptr_partial_attribute_set_ex) {
+ NDR_PULL_ALLOC(ndr, r->partial_attribute_set_ex);
+ } else {
+ r->partial_attribute_set_ex = NULL;
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaOIDMapping_Ctr(ndr, NDR_SCALARS, &r->mapping_ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_naming_context_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->naming_context, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->naming_context));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_naming_context_0, 0);
+ if (r->uptodateness_vector) {
+ _mem_save_uptodateness_vector_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->uptodateness_vector, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaCursorCtrEx(ndr, NDR_SCALARS, r->uptodateness_vector));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_uptodateness_vector_0, 0);
+ }
+ if (r->partial_attribute_set) {
+ _mem_save_partial_attribute_set_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->partial_attribute_set, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsPartialAttributeSet(ndr, NDR_SCALARS, r->partial_attribute_set));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_partial_attribute_set_0, 0);
+ }
+ if (r->partial_attribute_set_ex) {
+ _mem_save_partial_attribute_set_ex_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->partial_attribute_set_ex, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsPartialAttributeSet(ndr, NDR_SCALARS, r->partial_attribute_set_ex));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_partial_attribute_set_ex_0, 0);
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaOIDMapping_Ctr(ndr, NDR_BUFFERS, &r->mapping_ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNCChangesRequest8(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesRequest8 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetNCChangesRequest8");
+ ndr->depth++;
+ ndr_print_GUID(ndr, "destination_dsa_guid", &r->destination_dsa_guid);
+ ndr_print_GUID(ndr, "source_dsa_invocation_id", &r->source_dsa_invocation_id);
+ ndr_print_ptr(ndr, "naming_context", r->naming_context);
+ ndr->depth++;
+ ndr_print_drsuapi_DsReplicaObjectIdentifier(ndr, "naming_context", r->naming_context);
+ ndr->depth--;
+ ndr_print_drsuapi_DsReplicaHighWaterMark(ndr, "highwatermark", &r->highwatermark);
+ ndr_print_ptr(ndr, "uptodateness_vector", r->uptodateness_vector);
+ ndr->depth++;
+ if (r->uptodateness_vector) {
+ ndr_print_drsuapi_DsReplicaCursorCtrEx(ndr, "uptodateness_vector", r->uptodateness_vector);
+ }
+ ndr->depth--;
+ ndr_print_drsuapi_DsReplicaNeighbourFlags(ndr, "replica_flags", r->replica_flags);
+ ndr_print_uint32(ndr, "max_object_count", r->max_object_count);
+ ndr_print_uint32(ndr, "max_ndr_size", r->max_ndr_size);
+ ndr_print_drsuapi_DsExtendedOperation(ndr, "extended_op", r->extended_op);
+ ndr_print_hyper(ndr, "fsmo_info", r->fsmo_info);
+ ndr_print_ptr(ndr, "partial_attribute_set", r->partial_attribute_set);
+ ndr->depth++;
+ if (r->partial_attribute_set) {
+ ndr_print_drsuapi_DsPartialAttributeSet(ndr, "partial_attribute_set", r->partial_attribute_set);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "partial_attribute_set_ex", r->partial_attribute_set_ex);
+ ndr->depth++;
+ if (r->partial_attribute_set_ex) {
+ ndr_print_drsuapi_DsPartialAttributeSet(ndr, "partial_attribute_set_ex", r->partial_attribute_set_ex);
+ }
+ ndr->depth--;
+ ndr_print_drsuapi_DsReplicaOIDMapping_Ctr(ndr, "mapping_ctr", &r->mapping_ctr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesRequest(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsGetNCChangesRequest *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 5: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesRequest5(ndr, NDR_SCALARS, &r->req5));
+ break; }
+
+ case 8: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesRequest8(ndr, NDR_SCALARS, &r->req8));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 5:
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesRequest5(ndr, NDR_BUFFERS, &r->req5));
+ break;
+
+ case 8:
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesRequest8(ndr, NDR_BUFFERS, &r->req8));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNCChangesRequest(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsGetNCChangesRequest *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 5: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesRequest5(ndr, NDR_SCALARS, &r->req5));
+ break; }
+
+ case 8: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesRequest8(ndr, NDR_SCALARS, &r->req8));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 5:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesRequest5(ndr, NDR_BUFFERS, &r->req5));
+ break;
+
+ case 8:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesRequest8(ndr, NDR_BUFFERS, &r->req8));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNCChangesRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetNCChangesRequest *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsGetNCChangesRequest");
+ switch (level) {
+ case 5:
+ ndr_print_drsuapi_DsGetNCChangesRequest5(ndr, "req5", &r->req5);
+ break;
+
+ case 8:
+ ndr_print_drsuapi_DsGetNCChangesRequest8(ndr, "req8", &r->req8);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsReplicaCursor2(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaCursor2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->highest_usn));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_sync_success));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsReplicaCursor2(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaCursor2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->highest_usn));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_sync_success));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaCursor2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaCursor2 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaCursor2");
+ ndr->depth++;
+ ndr_print_GUID(ndr, "source_dsa_invocation_id", &r->source_dsa_invocation_id);
+ ndr_print_hyper(ndr, "highest_usn", r->highest_usn);
+ ndr_print_NTTIME(ndr, "last_sync_success", r->last_sync_success);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaCursor2CtrEx(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaCursor2CtrEx *r)
+{
+ uint32_t cntr_cursors_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ for (cntr_cursors_0 = 0; cntr_cursors_0 < r->count; cntr_cursors_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaCursor2(ndr, NDR_SCALARS, &r->cursors[cntr_cursors_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaCursor2CtrEx(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaCursor2CtrEx *r)
+{
+ uint32_t cntr_cursors_0;
+ TALLOC_CTX *_mem_save_cursors_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->cursors));
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 0x100000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved2));
+ NDR_PULL_ALLOC_N(ndr, r->cursors, ndr_get_array_size(ndr, &r->cursors));
+ _mem_save_cursors_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->cursors, 0);
+ for (cntr_cursors_0 = 0; cntr_cursors_0 < r->count; cntr_cursors_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaCursor2(ndr, NDR_SCALARS, &r->cursors[cntr_cursors_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cursors_0, 0);
+ if (r->cursors) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->cursors, r->count));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaCursor2CtrEx(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaCursor2CtrEx *r)
+{
+ uint32_t cntr_cursors_0;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaCursor2CtrEx");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "version", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?2:r->version);
+ ndr_print_uint32(ndr, "reserved1", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->reserved1);
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_uint32(ndr, "reserved2", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->reserved2);
+ ndr->print(ndr, "%s: ARRAY(%d)", "cursors", (int)r->count);
+ ndr->depth++;
+ for (cntr_cursors_0=0;cntr_cursors_0<r->count;cntr_cursors_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_cursors_0) != -1) {
+ ndr_print_drsuapi_DsReplicaCursor2(ndr, "cursors", &r->cursors[cntr_cursors_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsAttributeValue(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsAttributeValue *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_DATA_BLOB(0, r->blob, 0)));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->blob));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->blob) {
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, *r->blob));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsAttributeValue(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsAttributeValue *r)
+{
+ uint32_t _ptr_blob;
+ TALLOC_CTX *_mem_save_blob_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size));
+ if (r->__ndr_size < 0 || r->__ndr_size > 10485760) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_blob));
+ if (_ptr_blob) {
+ NDR_PULL_ALLOC(ndr, r->blob);
+ } else {
+ r->blob = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->blob) {
+ _mem_save_blob_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->blob, 0);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, r->blob));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_blob_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAttributeValue(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAttributeValue *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsAttributeValue");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "__ndr_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_DATA_BLOB(0, r->blob, 0):r->__ndr_size);
+ ndr_print_ptr(ndr, "blob", r->blob);
+ ndr->depth++;
+ if (r->blob) {
+ ndr_print_DATA_BLOB(ndr, "blob", *r->blob);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsAttributeValueCtr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsAttributeValueCtr *r)
+{
+ uint32_t cntr_values_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_values));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->values));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->values) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_values));
+ for (cntr_values_1 = 0; cntr_values_1 < r->num_values; cntr_values_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsAttributeValue(ndr, NDR_SCALARS, &r->values[cntr_values_1]));
+ }
+ for (cntr_values_1 = 0; cntr_values_1 < r->num_values; cntr_values_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsAttributeValue(ndr, NDR_BUFFERS, &r->values[cntr_values_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsAttributeValueCtr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsAttributeValueCtr *r)
+{
+ uint32_t _ptr_values;
+ uint32_t cntr_values_1;
+ TALLOC_CTX *_mem_save_values_0;
+ TALLOC_CTX *_mem_save_values_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_values));
+ if (r->num_values < 0 || r->num_values > 10485760) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_values));
+ if (_ptr_values) {
+ NDR_PULL_ALLOC(ndr, r->values);
+ } else {
+ r->values = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->values) {
+ _mem_save_values_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->values, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->values));
+ NDR_PULL_ALLOC_N(ndr, r->values, ndr_get_array_size(ndr, &r->values));
+ _mem_save_values_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->values, 0);
+ for (cntr_values_1 = 0; cntr_values_1 < r->num_values; cntr_values_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsAttributeValue(ndr, NDR_SCALARS, &r->values[cntr_values_1]));
+ }
+ for (cntr_values_1 = 0; cntr_values_1 < r->num_values; cntr_values_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsAttributeValue(ndr, NDR_BUFFERS, &r->values[cntr_values_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_values_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_values_0, 0);
+ }
+ if (r->values) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->values, r->num_values));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAttributeValueCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAttributeValueCtr *r)
+{
+ uint32_t cntr_values_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsAttributeValueCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_values", r->num_values);
+ ndr_print_ptr(ndr, "values", r->values);
+ ndr->depth++;
+ if (r->values) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "values", (int)r->num_values);
+ ndr->depth++;
+ for (cntr_values_1=0;cntr_values_1<r->num_values;cntr_values_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_values_1) != -1) {
+ ndr_print_drsuapi_DsAttributeValue(ndr, "values", &r->values[cntr_values_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsReplicaObjectIdentifier3(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObjectIdentifier3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_drsuapi_DsReplicaObjectIdentifier3(r, ndr->flags)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_dom_sid28(&r->sid, ndr->flags)));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->guid));
+ NDR_CHECK(ndr_push_dom_sid28(ndr, NDR_SCALARS, &r->sid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, strlen_m(r->dn)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dn, strlen_m(r->dn) + 1, sizeof(uint16_t), CH_UTF16));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_dom_sid28(ndr, NDR_BUFFERS, &r->sid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjectIdentifier3(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObjectIdentifier3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size_sid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->guid));
+ NDR_CHECK(ndr_pull_dom_sid28(ndr, NDR_SCALARS, &r->sid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size_dn));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dn, r->__ndr_size_dn + 1, sizeof(uint16_t), CH_UTF16));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_dom_sid28(ndr, NDR_BUFFERS, &r->sid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaObjectIdentifier3(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjectIdentifier3 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaObjectIdentifier3");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "__ndr_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_drsuapi_DsReplicaObjectIdentifier3(r, ndr->flags):r->__ndr_size);
+ ndr_print_uint32(ndr, "__ndr_size_sid", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_dom_sid28(&r->sid, ndr->flags):r->__ndr_size_sid);
+ ndr_print_GUID(ndr, "guid", &r->guid);
+ ndr_print_dom_sid28(ndr, "sid", &r->sid);
+ ndr_print_uint32(ndr, "__ndr_size_dn", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen_m(r->dn):r->__ndr_size_dn);
+ ndr_print_string(ndr, "dn", r->dn);
+ ndr->depth--;
+}
+
+_PUBLIC_ size_t ndr_size_drsuapi_DsReplicaObjectIdentifier3(const struct drsuapi_DsReplicaObjectIdentifier3 *r, int flags)
+{
+ return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsReplicaObjectIdentifier3Binary(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObjectIdentifier3Binary *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_drsuapi_DsReplicaObjectIdentifier3Binary(r, ndr->flags)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_dom_sid28(&r->sid, ndr->flags)));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->guid));
+ NDR_CHECK(ndr_push_dom_sid28(ndr, NDR_SCALARS, &r->sid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, strlen_m(r->dn)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dn, strlen_m(r->dn) + 1, sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->binary.length + 4));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->binary));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_dom_sid28(ndr, NDR_BUFFERS, &r->sid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjectIdentifier3Binary(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObjectIdentifier3Binary *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size_sid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->guid));
+ NDR_CHECK(ndr_pull_dom_sid28(ndr, NDR_SCALARS, &r->sid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size_dn));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dn, r->__ndr_size_dn + 1, sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size_binary));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->binary));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_dom_sid28(ndr, NDR_BUFFERS, &r->sid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaObjectIdentifier3Binary(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjectIdentifier3Binary *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaObjectIdentifier3Binary");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "__ndr_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_drsuapi_DsReplicaObjectIdentifier3Binary(r, ndr->flags):r->__ndr_size);
+ ndr_print_uint32(ndr, "__ndr_size_sid", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_dom_sid28(&r->sid, ndr->flags):r->__ndr_size_sid);
+ ndr_print_GUID(ndr, "guid", &r->guid);
+ ndr_print_dom_sid28(ndr, "sid", &r->sid);
+ ndr_print_uint32(ndr, "__ndr_size_dn", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen_m(r->dn):r->__ndr_size_dn);
+ ndr_print_string(ndr, "dn", r->dn);
+ ndr_print_uint32(ndr, "__ndr_size_binary", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?r->binary.length + 4:r->__ndr_size_binary);
+ ndr_print_DATA_BLOB(ndr, "binary", r->binary);
+ ndr->depth--;
+}
+
+_PUBLIC_ size_t ndr_size_drsuapi_DsReplicaObjectIdentifier3Binary(const struct drsuapi_DsReplicaObjectIdentifier3Binary *r, int flags)
+{
+ return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3Binary);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsReplicaAttribute(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaAttribute *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_drsuapi_DsAttributeId(ndr, NDR_SCALARS, r->attid));
+ NDR_CHECK(ndr_push_drsuapi_DsAttributeValueCtr(ndr, NDR_SCALARS, &r->value_ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_drsuapi_DsAttributeValueCtr(ndr, NDR_BUFFERS, &r->value_ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsReplicaAttribute(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaAttribute *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_drsuapi_DsAttributeId(ndr, NDR_SCALARS, &r->attid));
+ NDR_CHECK(ndr_pull_drsuapi_DsAttributeValueCtr(ndr, NDR_SCALARS, &r->value_ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_drsuapi_DsAttributeValueCtr(ndr, NDR_BUFFERS, &r->value_ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaAttribute(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaAttribute *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaAttribute");
+ ndr->depth++;
+ ndr_print_drsuapi_DsAttributeId(ndr, "attid", r->attid);
+ ndr_print_drsuapi_DsAttributeValueCtr(ndr, "value_ctr", &r->value_ctr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaAttributeCtr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaAttributeCtr *r)
+{
+ uint32_t cntr_attributes_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_attributes));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->attributes));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->attributes) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_attributes));
+ for (cntr_attributes_1 = 0; cntr_attributes_1 < r->num_attributes; cntr_attributes_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaAttribute(ndr, NDR_SCALARS, &r->attributes[cntr_attributes_1]));
+ }
+ for (cntr_attributes_1 = 0; cntr_attributes_1 < r->num_attributes; cntr_attributes_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaAttribute(ndr, NDR_BUFFERS, &r->attributes[cntr_attributes_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaAttributeCtr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaAttributeCtr *r)
+{
+ uint32_t _ptr_attributes;
+ uint32_t cntr_attributes_1;
+ TALLOC_CTX *_mem_save_attributes_0;
+ TALLOC_CTX *_mem_save_attributes_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_attributes));
+ if (r->num_attributes < 0 || r->num_attributes > 1048576) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_attributes));
+ if (_ptr_attributes) {
+ NDR_PULL_ALLOC(ndr, r->attributes);
+ } else {
+ r->attributes = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->attributes) {
+ _mem_save_attributes_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->attributes, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->attributes));
+ NDR_PULL_ALLOC_N(ndr, r->attributes, ndr_get_array_size(ndr, &r->attributes));
+ _mem_save_attributes_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->attributes, 0);
+ for (cntr_attributes_1 = 0; cntr_attributes_1 < r->num_attributes; cntr_attributes_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaAttribute(ndr, NDR_SCALARS, &r->attributes[cntr_attributes_1]));
+ }
+ for (cntr_attributes_1 = 0; cntr_attributes_1 < r->num_attributes; cntr_attributes_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaAttribute(ndr, NDR_BUFFERS, &r->attributes[cntr_attributes_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_attributes_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_attributes_0, 0);
+ }
+ if (r->attributes) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->attributes, r->num_attributes));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaAttributeCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaAttributeCtr *r)
+{
+ uint32_t cntr_attributes_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaAttributeCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_attributes", r->num_attributes);
+ ndr_print_ptr(ndr, "attributes", r->attributes);
+ ndr->depth++;
+ if (r->attributes) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "attributes", (int)r->num_attributes);
+ ndr->depth++;
+ for (cntr_attributes_1=0;cntr_attributes_1<r->num_attributes;cntr_attributes_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_attributes_1) != -1) {
+ ndr_print_drsuapi_DsReplicaAttribute(ndr, "attributes", &r->attributes[cntr_attributes_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsReplicaObjectFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjectFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaObjectFlags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_OBJECT_FROM_MASTER", DRSUAPI_DS_REPLICA_OBJECT_FROM_MASTER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_OBJECT_DYNAMIC", DRSUAPI_DS_REPLICA_OBJECT_DYNAMIC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_OBJECT_REMOTE_MODIFY", DRSUAPI_DS_REPLICA_OBJECT_REMOTE_MODIFY, r);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsReplicaObject(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObject *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->identifier));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectFlags(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaAttributeCtr(ndr, NDR_SCALARS, &r->attribute_ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->identifier) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->identifier));
+ }
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaAttributeCtr(ndr, NDR_BUFFERS, &r->attribute_ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsReplicaObject(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObject *r)
+{
+ uint32_t _ptr_identifier;
+ TALLOC_CTX *_mem_save_identifier_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_identifier));
+ if (_ptr_identifier) {
+ NDR_PULL_ALLOC(ndr, r->identifier);
+ } else {
+ r->identifier = NULL;
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectFlags(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaAttributeCtr(ndr, NDR_SCALARS, &r->attribute_ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->identifier) {
+ _mem_save_identifier_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->identifier, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->identifier));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_identifier_0, 0);
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaAttributeCtr(ndr, NDR_BUFFERS, &r->attribute_ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaObject(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObject *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaObject");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "identifier", r->identifier);
+ ndr->depth++;
+ if (r->identifier) {
+ ndr_print_drsuapi_DsReplicaObjectIdentifier(ndr, "identifier", r->identifier);
+ }
+ ndr->depth--;
+ ndr_print_drsuapi_DsReplicaObjectFlags(ndr, "flags", r->flags);
+ ndr_print_drsuapi_DsReplicaAttributeCtr(ndr, "attribute_ctr", &r->attribute_ctr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaMetaData(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaMetaData *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version));
+ NDR_CHECK(ndr_push_NTTIME_1sec(ndr, NDR_SCALARS, r->originating_change_time));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->originating_invocation_id));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->originating_usn));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaMetaData(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaMetaData *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_NTTIME_1sec(ndr, NDR_SCALARS, &r->originating_change_time));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->originating_invocation_id));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->originating_usn));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaMetaData(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaMetaData *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaMetaData");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "version", r->version);
+ ndr_print_NTTIME_1sec(ndr, "originating_change_time", r->originating_change_time);
+ ndr_print_GUID(ndr, "originating_invocation_id", &r->originating_invocation_id);
+ ndr_print_hyper(ndr, "originating_usn", r->originating_usn);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsReplicaMetaDataCtr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaMetaDataCtr *r)
+{
+ uint32_t cntr_meta_data_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_meta_data_0 = 0; cntr_meta_data_0 < r->count; cntr_meta_data_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaMetaData(ndr, NDR_SCALARS, &r->meta_data[cntr_meta_data_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsReplicaMetaDataCtr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaMetaDataCtr *r)
+{
+ uint32_t cntr_meta_data_0;
+ TALLOC_CTX *_mem_save_meta_data_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->meta_data));
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 1048576) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_PULL_ALLOC_N(ndr, r->meta_data, ndr_get_array_size(ndr, &r->meta_data));
+ _mem_save_meta_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->meta_data, 0);
+ for (cntr_meta_data_0 = 0; cntr_meta_data_0 < r->count; cntr_meta_data_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaMetaData(ndr, NDR_SCALARS, &r->meta_data[cntr_meta_data_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_meta_data_0, 0);
+ if (r->meta_data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->meta_data, r->count));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaMetaDataCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaMetaDataCtr *r)
+{
+ uint32_t cntr_meta_data_0;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaMetaDataCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr->print(ndr, "%s: ARRAY(%d)", "meta_data", (int)r->count);
+ ndr->depth++;
+ for (cntr_meta_data_0=0;cntr_meta_data_0<r->count;cntr_meta_data_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_meta_data_0) != -1) {
+ ndr_print_drsuapi_DsReplicaMetaData(ndr, "meta_data", &r->meta_data[cntr_meta_data_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsReplicaObjectListItemEx(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObjectListItemEx *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->next_object));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObject(ndr, NDR_SCALARS, &r->object));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->is_nc_prefix));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->parent_object_guid));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->meta_data_ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->next_object) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectListItemEx(ndr, NDR_SCALARS|NDR_BUFFERS, r->next_object));
+ }
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObject(ndr, NDR_BUFFERS, &r->object));
+ if (r->parent_object_guid) {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, r->parent_object_guid));
+ }
+ if (r->meta_data_ctr) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaMetaDataCtr(ndr, NDR_SCALARS, r->meta_data_ctr));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjectListItemEx(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObjectListItemEx *r)
+{
+ uint32_t _ptr_next_object;
+ TALLOC_CTX *_mem_save_next_object_0;
+ uint32_t _ptr_parent_object_guid;
+ TALLOC_CTX *_mem_save_parent_object_guid_0;
+ uint32_t _ptr_meta_data_ctr;
+ TALLOC_CTX *_mem_save_meta_data_ctr_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_next_object));
+ if (_ptr_next_object) {
+ NDR_PULL_ALLOC(ndr, r->next_object);
+ } else {
+ r->next_object = NULL;
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObject(ndr, NDR_SCALARS, &r->object));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->is_nc_prefix));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_parent_object_guid));
+ if (_ptr_parent_object_guid) {
+ NDR_PULL_ALLOC(ndr, r->parent_object_guid);
+ } else {
+ r->parent_object_guid = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_meta_data_ctr));
+ if (_ptr_meta_data_ctr) {
+ NDR_PULL_ALLOC(ndr, r->meta_data_ctr);
+ } else {
+ r->meta_data_ctr = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->next_object) {
+ _mem_save_next_object_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->next_object, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectListItemEx(ndr, NDR_SCALARS|NDR_BUFFERS, r->next_object));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_next_object_0, 0);
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObject(ndr, NDR_BUFFERS, &r->object));
+ if (r->parent_object_guid) {
+ _mem_save_parent_object_guid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->parent_object_guid, 0);
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, r->parent_object_guid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parent_object_guid_0, 0);
+ }
+ if (r->meta_data_ctr) {
+ _mem_save_meta_data_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->meta_data_ctr, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaMetaDataCtr(ndr, NDR_SCALARS, r->meta_data_ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_meta_data_ctr_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesCtr1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNCChangesCtr1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->source_dsa_guid));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->naming_context));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaHighWaterMark(ndr, NDR_SCALARS, &r->old_highwatermark));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaHighWaterMark(ndr, NDR_SCALARS, &r->new_highwatermark));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->uptodateness_vector));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOIDMapping_Ctr(ndr, NDR_SCALARS, &r->mapping_ctr));
+ NDR_CHECK(ndr_push_drsuapi_DsExtendedError(ndr, NDR_SCALARS, r->extended_ret));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->object_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_drsuapi_DsGetNCChangesCtr1(r, ndr->flags) + 55));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->first_object));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->more_data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->naming_context) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->naming_context));
+ }
+ if (r->uptodateness_vector) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaCursorCtrEx(ndr, NDR_SCALARS, r->uptodateness_vector));
+ }
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOIDMapping_Ctr(ndr, NDR_BUFFERS, &r->mapping_ctr));
+ if (r->first_object) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectListItemEx(ndr, NDR_SCALARS|NDR_BUFFERS, r->first_object));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsGetNCChangesCtr1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetNCChangesCtr1 *r)
+{
+ uint32_t _ptr_naming_context;
+ TALLOC_CTX *_mem_save_naming_context_0;
+ uint32_t _ptr_uptodateness_vector;
+ TALLOC_CTX *_mem_save_uptodateness_vector_0;
+ uint32_t _ptr_first_object;
+ TALLOC_CTX *_mem_save_first_object_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->source_dsa_guid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_naming_context));
+ if (_ptr_naming_context) {
+ NDR_PULL_ALLOC(ndr, r->naming_context);
+ } else {
+ r->naming_context = NULL;
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaHighWaterMark(ndr, NDR_SCALARS, &r->old_highwatermark));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaHighWaterMark(ndr, NDR_SCALARS, &r->new_highwatermark));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_uptodateness_vector));
+ if (_ptr_uptodateness_vector) {
+ NDR_PULL_ALLOC(ndr, r->uptodateness_vector);
+ } else {
+ r->uptodateness_vector = NULL;
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaOIDMapping_Ctr(ndr, NDR_SCALARS, &r->mapping_ctr));
+ NDR_CHECK(ndr_pull_drsuapi_DsExtendedError(ndr, NDR_SCALARS, &r->extended_ret));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->object_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_first_object));
+ if (_ptr_first_object) {
+ NDR_PULL_ALLOC(ndr, r->first_object);
+ } else {
+ r->first_object = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->more_data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->naming_context) {
+ _mem_save_naming_context_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->naming_context, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->naming_context));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_naming_context_0, 0);
+ }
+ if (r->uptodateness_vector) {
+ _mem_save_uptodateness_vector_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->uptodateness_vector, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaCursorCtrEx(ndr, NDR_SCALARS, r->uptodateness_vector));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_uptodateness_vector_0, 0);
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaOIDMapping_Ctr(ndr, NDR_BUFFERS, &r->mapping_ctr));
+ if (r->first_object) {
+ _mem_save_first_object_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->first_object, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectListItemEx(ndr, NDR_SCALARS|NDR_BUFFERS, r->first_object));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_first_object_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNCChangesCtr1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesCtr1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetNCChangesCtr1");
+ ndr->depth++;
+ ndr_print_GUID(ndr, "source_dsa_guid", &r->source_dsa_guid);
+ ndr_print_GUID(ndr, "source_dsa_invocation_id", &r->source_dsa_invocation_id);
+ ndr_print_ptr(ndr, "naming_context", r->naming_context);
+ ndr->depth++;
+ if (r->naming_context) {
+ ndr_print_drsuapi_DsReplicaObjectIdentifier(ndr, "naming_context", r->naming_context);
+ }
+ ndr->depth--;
+ ndr_print_drsuapi_DsReplicaHighWaterMark(ndr, "old_highwatermark", &r->old_highwatermark);
+ ndr_print_drsuapi_DsReplicaHighWaterMark(ndr, "new_highwatermark", &r->new_highwatermark);
+ ndr_print_ptr(ndr, "uptodateness_vector", r->uptodateness_vector);
+ ndr->depth++;
+ if (r->uptodateness_vector) {
+ ndr_print_drsuapi_DsReplicaCursorCtrEx(ndr, "uptodateness_vector", r->uptodateness_vector);
+ }
+ ndr->depth--;
+ ndr_print_drsuapi_DsReplicaOIDMapping_Ctr(ndr, "mapping_ctr", &r->mapping_ctr);
+ ndr_print_drsuapi_DsExtendedError(ndr, "extended_ret", r->extended_ret);
+ ndr_print_uint32(ndr, "object_count", r->object_count);
+ ndr_print_uint32(ndr, "__ndr_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_drsuapi_DsGetNCChangesCtr1(r, ndr->flags) + 55:r->__ndr_size);
+ ndr_print_ptr(ndr, "first_object", r->first_object);
+ ndr->depth++;
+ if (r->first_object) {
+ ndr_print_drsuapi_DsReplicaObjectListItemEx(ndr, "first_object", r->first_object);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "more_data", r->more_data);
+ ndr->depth--;
+}
+
+_PUBLIC_ size_t ndr_size_drsuapi_DsGetNCChangesCtr1(const struct drsuapi_DsGetNCChangesCtr1 *r, int flags)
+{
+ return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_drsuapi_DsGetNCChangesCtr1);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsLinkedAttributeFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsLinkedAttributeFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsLinkedAttributeFlags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE", DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE, r);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsReplicaLinkedAttribute(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaLinkedAttribute *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->identifier));
+ NDR_CHECK(ndr_push_drsuapi_DsAttributeId(ndr, NDR_SCALARS, r->attid));
+ NDR_CHECK(ndr_push_drsuapi_DsAttributeValue(ndr, NDR_SCALARS, &r->value));
+ NDR_CHECK(ndr_push_drsuapi_DsLinkedAttributeFlags(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_NTTIME_1sec(ndr, NDR_SCALARS, r->originating_add_time));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaMetaData(ndr, NDR_SCALARS, &r->meta_data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->identifier) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->identifier));
+ }
+ NDR_CHECK(ndr_push_drsuapi_DsAttributeValue(ndr, NDR_BUFFERS, &r->value));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsReplicaLinkedAttribute(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaLinkedAttribute *r)
+{
+ uint32_t _ptr_identifier;
+ TALLOC_CTX *_mem_save_identifier_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_identifier));
+ if (_ptr_identifier) {
+ NDR_PULL_ALLOC(ndr, r->identifier);
+ } else {
+ r->identifier = NULL;
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsAttributeId(ndr, NDR_SCALARS, &r->attid));
+ NDR_CHECK(ndr_pull_drsuapi_DsAttributeValue(ndr, NDR_SCALARS, &r->value));
+ NDR_CHECK(ndr_pull_drsuapi_DsLinkedAttributeFlags(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_NTTIME_1sec(ndr, NDR_SCALARS, &r->originating_add_time));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaMetaData(ndr, NDR_SCALARS, &r->meta_data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->identifier) {
+ _mem_save_identifier_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->identifier, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->identifier));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_identifier_0, 0);
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsAttributeValue(ndr, NDR_BUFFERS, &r->value));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaLinkedAttribute(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaLinkedAttribute *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaLinkedAttribute");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "identifier", r->identifier);
+ ndr->depth++;
+ if (r->identifier) {
+ ndr_print_drsuapi_DsReplicaObjectIdentifier(ndr, "identifier", r->identifier);
+ }
+ ndr->depth--;
+ ndr_print_drsuapi_DsAttributeId(ndr, "attid", r->attid);
+ ndr_print_drsuapi_DsAttributeValue(ndr, "value", &r->value);
+ ndr_print_drsuapi_DsLinkedAttributeFlags(ndr, "flags", r->flags);
+ ndr_print_NTTIME_1sec(ndr, "originating_add_time", r->originating_add_time);
+ ndr_print_drsuapi_DsReplicaMetaData(ndr, "meta_data", &r->meta_data);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesCtr6(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNCChangesCtr6 *r)
+{
+ uint32_t cntr_linked_attributes_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->source_dsa_guid));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->naming_context));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaHighWaterMark(ndr, NDR_SCALARS, &r->old_highwatermark));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaHighWaterMark(ndr, NDR_SCALARS, &r->new_highwatermark));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->uptodateness_vector));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOIDMapping_Ctr(ndr, NDR_SCALARS, &r->mapping_ctr));
+ NDR_CHECK(ndr_push_drsuapi_DsExtendedError(ndr, NDR_SCALARS, r->extended_ret));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->object_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_drsuapi_DsGetNCChangesCtr6(r, ndr->flags) + 55));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->first_object));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->more_data));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->nc_object_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->nc_linked_attributes_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->linked_attributes_count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->linked_attributes));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->drs_error));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->naming_context) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->naming_context));
+ }
+ if (r->uptodateness_vector) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaCursor2CtrEx(ndr, NDR_SCALARS, r->uptodateness_vector));
+ }
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOIDMapping_Ctr(ndr, NDR_BUFFERS, &r->mapping_ctr));
+ if (r->first_object) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectListItemEx(ndr, NDR_SCALARS|NDR_BUFFERS, r->first_object));
+ }
+ if (r->linked_attributes) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->linked_attributes_count));
+ for (cntr_linked_attributes_1 = 0; cntr_linked_attributes_1 < r->linked_attributes_count; cntr_linked_attributes_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaLinkedAttribute(ndr, NDR_SCALARS, &r->linked_attributes[cntr_linked_attributes_1]));
+ }
+ for (cntr_linked_attributes_1 = 0; cntr_linked_attributes_1 < r->linked_attributes_count; cntr_linked_attributes_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaLinkedAttribute(ndr, NDR_BUFFERS, &r->linked_attributes[cntr_linked_attributes_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsGetNCChangesCtr6(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetNCChangesCtr6 *r)
+{
+ uint32_t _ptr_naming_context;
+ TALLOC_CTX *_mem_save_naming_context_0;
+ uint32_t _ptr_uptodateness_vector;
+ TALLOC_CTX *_mem_save_uptodateness_vector_0;
+ uint32_t _ptr_first_object;
+ TALLOC_CTX *_mem_save_first_object_0;
+ uint32_t _ptr_linked_attributes;
+ uint32_t cntr_linked_attributes_1;
+ TALLOC_CTX *_mem_save_linked_attributes_0;
+ TALLOC_CTX *_mem_save_linked_attributes_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->source_dsa_guid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_naming_context));
+ if (_ptr_naming_context) {
+ NDR_PULL_ALLOC(ndr, r->naming_context);
+ } else {
+ r->naming_context = NULL;
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaHighWaterMark(ndr, NDR_SCALARS, &r->old_highwatermark));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaHighWaterMark(ndr, NDR_SCALARS, &r->new_highwatermark));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_uptodateness_vector));
+ if (_ptr_uptodateness_vector) {
+ NDR_PULL_ALLOC(ndr, r->uptodateness_vector);
+ } else {
+ r->uptodateness_vector = NULL;
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaOIDMapping_Ctr(ndr, NDR_SCALARS, &r->mapping_ctr));
+ NDR_CHECK(ndr_pull_drsuapi_DsExtendedError(ndr, NDR_SCALARS, &r->extended_ret));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->object_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_first_object));
+ if (_ptr_first_object) {
+ NDR_PULL_ALLOC(ndr, r->first_object);
+ } else {
+ r->first_object = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->more_data));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->nc_object_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->nc_linked_attributes_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->linked_attributes_count));
+ if (r->linked_attributes_count < 0 || r->linked_attributes_count > 1048576) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_linked_attributes));
+ if (_ptr_linked_attributes) {
+ NDR_PULL_ALLOC(ndr, r->linked_attributes);
+ } else {
+ r->linked_attributes = NULL;
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->drs_error));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->naming_context) {
+ _mem_save_naming_context_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->naming_context, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->naming_context));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_naming_context_0, 0);
+ }
+ if (r->uptodateness_vector) {
+ _mem_save_uptodateness_vector_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->uptodateness_vector, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaCursor2CtrEx(ndr, NDR_SCALARS, r->uptodateness_vector));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_uptodateness_vector_0, 0);
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaOIDMapping_Ctr(ndr, NDR_BUFFERS, &r->mapping_ctr));
+ if (r->first_object) {
+ _mem_save_first_object_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->first_object, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectListItemEx(ndr, NDR_SCALARS|NDR_BUFFERS, r->first_object));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_first_object_0, 0);
+ }
+ if (r->linked_attributes) {
+ _mem_save_linked_attributes_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->linked_attributes, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->linked_attributes));
+ NDR_PULL_ALLOC_N(ndr, r->linked_attributes, ndr_get_array_size(ndr, &r->linked_attributes));
+ _mem_save_linked_attributes_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->linked_attributes, 0);
+ for (cntr_linked_attributes_1 = 0; cntr_linked_attributes_1 < r->linked_attributes_count; cntr_linked_attributes_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaLinkedAttribute(ndr, NDR_SCALARS, &r->linked_attributes[cntr_linked_attributes_1]));
+ }
+ for (cntr_linked_attributes_1 = 0; cntr_linked_attributes_1 < r->linked_attributes_count; cntr_linked_attributes_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaLinkedAttribute(ndr, NDR_BUFFERS, &r->linked_attributes[cntr_linked_attributes_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_linked_attributes_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_linked_attributes_0, 0);
+ }
+ if (r->linked_attributes) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->linked_attributes, r->linked_attributes_count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNCChangesCtr6(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesCtr6 *r)
+{
+ uint32_t cntr_linked_attributes_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsGetNCChangesCtr6");
+ ndr->depth++;
+ ndr_print_GUID(ndr, "source_dsa_guid", &r->source_dsa_guid);
+ ndr_print_GUID(ndr, "source_dsa_invocation_id", &r->source_dsa_invocation_id);
+ ndr_print_ptr(ndr, "naming_context", r->naming_context);
+ ndr->depth++;
+ if (r->naming_context) {
+ ndr_print_drsuapi_DsReplicaObjectIdentifier(ndr, "naming_context", r->naming_context);
+ }
+ ndr->depth--;
+ ndr_print_drsuapi_DsReplicaHighWaterMark(ndr, "old_highwatermark", &r->old_highwatermark);
+ ndr_print_drsuapi_DsReplicaHighWaterMark(ndr, "new_highwatermark", &r->new_highwatermark);
+ ndr_print_ptr(ndr, "uptodateness_vector", r->uptodateness_vector);
+ ndr->depth++;
+ if (r->uptodateness_vector) {
+ ndr_print_drsuapi_DsReplicaCursor2CtrEx(ndr, "uptodateness_vector", r->uptodateness_vector);
+ }
+ ndr->depth--;
+ ndr_print_drsuapi_DsReplicaOIDMapping_Ctr(ndr, "mapping_ctr", &r->mapping_ctr);
+ ndr_print_drsuapi_DsExtendedError(ndr, "extended_ret", r->extended_ret);
+ ndr_print_uint32(ndr, "object_count", r->object_count);
+ ndr_print_uint32(ndr, "__ndr_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_drsuapi_DsGetNCChangesCtr6(r, ndr->flags) + 55:r->__ndr_size);
+ ndr_print_ptr(ndr, "first_object", r->first_object);
+ ndr->depth++;
+ if (r->first_object) {
+ ndr_print_drsuapi_DsReplicaObjectListItemEx(ndr, "first_object", r->first_object);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "more_data", r->more_data);
+ ndr_print_uint32(ndr, "nc_object_count", r->nc_object_count);
+ ndr_print_uint32(ndr, "nc_linked_attributes_count", r->nc_linked_attributes_count);
+ ndr_print_uint32(ndr, "linked_attributes_count", r->linked_attributes_count);
+ ndr_print_ptr(ndr, "linked_attributes", r->linked_attributes);
+ ndr->depth++;
+ if (r->linked_attributes) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "linked_attributes", (int)r->linked_attributes_count);
+ ndr->depth++;
+ for (cntr_linked_attributes_1=0;cntr_linked_attributes_1<r->linked_attributes_count;cntr_linked_attributes_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_linked_attributes_1) != -1) {
+ ndr_print_drsuapi_DsReplicaLinkedAttribute(ndr, "linked_attributes", &r->linked_attributes[cntr_linked_attributes_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "drs_error", r->drs_error);
+ ndr->depth--;
+}
+
+_PUBLIC_ size_t ndr_size_drsuapi_DsGetNCChangesCtr6(const struct drsuapi_DsGetNCChangesCtr6 *r, int flags)
+{
+ return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_drsuapi_DsGetNCChangesCtr6);
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesMSZIPCtr1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNCChangesMSZIPCtr1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->decompressed_length));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->compressed_length));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->ctr1) {
+ {
+ struct ndr_push *_ndr_ctr1;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ctr1, 4, r->compressed_length));
+ {
+ struct ndr_push *_ndr_ctr1_compressed;
+ NDR_CHECK(ndr_push_compression_start(_ndr_ctr1, &_ndr_ctr1_compressed, NDR_COMPRESSION_MSZIP, r->decompressed_length));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr1(_ndr_ctr1_compressed, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ NDR_CHECK(ndr_push_compression_end(_ndr_ctr1, _ndr_ctr1_compressed, NDR_COMPRESSION_MSZIP, r->decompressed_length));
+ }
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_ctr1, 4, r->compressed_length));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNCChangesMSZIPCtr1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetNCChangesMSZIPCtr1 *r)
+{
+ uint32_t _ptr_ctr1;
+ TALLOC_CTX *_mem_save_ctr1_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->decompressed_length));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->compressed_length));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr1));
+ if (_ptr_ctr1) {
+ NDR_PULL_ALLOC(ndr, r->ctr1);
+ } else {
+ r->ctr1 = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->ctr1) {
+ _mem_save_ctr1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr1, 0);
+ {
+ struct ndr_pull *_ndr_ctr1;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_ctr1, 4, r->compressed_length));
+ {
+ struct ndr_pull *_ndr_ctr1_compressed;
+ NDR_CHECK(ndr_pull_compression_start(_ndr_ctr1, &_ndr_ctr1_compressed, NDR_COMPRESSION_MSZIP, r->decompressed_length));
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCtr1(_ndr_ctr1_compressed, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ NDR_CHECK(ndr_pull_compression_end(_ndr_ctr1, _ndr_ctr1_compressed, NDR_COMPRESSION_MSZIP, r->decompressed_length));
+ }
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_ctr1, 4, r->compressed_length));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr1_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNCChangesMSZIPCtr1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesMSZIPCtr1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetNCChangesMSZIPCtr1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "decompressed_length", r->decompressed_length);
+ ndr_print_uint32(ndr, "compressed_length", r->compressed_length);
+ ndr_print_ptr(ndr, "ctr1", r->ctr1);
+ ndr->depth++;
+ if (r->ctr1) {
+ ndr_print_drsuapi_DsGetNCChangesCtr1(ndr, "ctr1", r->ctr1);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesMSZIPCtr6(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNCChangesMSZIPCtr6 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->decompressed_length));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->compressed_length));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr6));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->ctr6) {
+ {
+ struct ndr_push *_ndr_ctr6;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ctr6, 4, r->compressed_length));
+ {
+ struct ndr_push *_ndr_ctr6_compressed;
+ NDR_CHECK(ndr_push_compression_start(_ndr_ctr6, &_ndr_ctr6_compressed, NDR_COMPRESSION_MSZIP, r->decompressed_length));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr6(_ndr_ctr6_compressed, NDR_SCALARS|NDR_BUFFERS, r->ctr6));
+ NDR_CHECK(ndr_push_compression_end(_ndr_ctr6, _ndr_ctr6_compressed, NDR_COMPRESSION_MSZIP, r->decompressed_length));
+ }
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_ctr6, 4, r->compressed_length));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNCChangesMSZIPCtr6(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetNCChangesMSZIPCtr6 *r)
+{
+ uint32_t _ptr_ctr6;
+ TALLOC_CTX *_mem_save_ctr6_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->decompressed_length));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->compressed_length));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr6));
+ if (_ptr_ctr6) {
+ NDR_PULL_ALLOC(ndr, r->ctr6);
+ } else {
+ r->ctr6 = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->ctr6) {
+ _mem_save_ctr6_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr6, 0);
+ {
+ struct ndr_pull *_ndr_ctr6;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_ctr6, 4, r->compressed_length));
+ {
+ struct ndr_pull *_ndr_ctr6_compressed;
+ NDR_CHECK(ndr_pull_compression_start(_ndr_ctr6, &_ndr_ctr6_compressed, NDR_COMPRESSION_MSZIP, r->decompressed_length));
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCtr6(_ndr_ctr6_compressed, NDR_SCALARS|NDR_BUFFERS, r->ctr6));
+ NDR_CHECK(ndr_pull_compression_end(_ndr_ctr6, _ndr_ctr6_compressed, NDR_COMPRESSION_MSZIP, r->decompressed_length));
+ }
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_ctr6, 4, r->compressed_length));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr6_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNCChangesMSZIPCtr6(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesMSZIPCtr6 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetNCChangesMSZIPCtr6");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "decompressed_length", r->decompressed_length);
+ ndr_print_uint32(ndr, "compressed_length", r->compressed_length);
+ ndr_print_ptr(ndr, "ctr6", r->ctr6);
+ ndr->depth++;
+ if (r->ctr6) {
+ ndr_print_drsuapi_DsGetNCChangesCtr6(ndr, "ctr6", r->ctr6);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesXPRESSCtr1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNCChangesXPRESSCtr1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->decompressed_length));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->compressed_length));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->ctr1) {
+ {
+ struct ndr_push *_ndr_ctr1;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ctr1, 4, r->compressed_length));
+ {
+ struct ndr_push *_ndr_ctr1_compressed;
+ NDR_CHECK(ndr_push_compression_start(_ndr_ctr1, &_ndr_ctr1_compressed, NDR_COMPRESSION_XPRESS, r->decompressed_length));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr1(_ndr_ctr1_compressed, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ NDR_CHECK(ndr_push_compression_end(_ndr_ctr1, _ndr_ctr1_compressed, NDR_COMPRESSION_XPRESS, r->decompressed_length));
+ }
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_ctr1, 4, r->compressed_length));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNCChangesXPRESSCtr1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetNCChangesXPRESSCtr1 *r)
+{
+ uint32_t _ptr_ctr1;
+ TALLOC_CTX *_mem_save_ctr1_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->decompressed_length));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->compressed_length));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr1));
+ if (_ptr_ctr1) {
+ NDR_PULL_ALLOC(ndr, r->ctr1);
+ } else {
+ r->ctr1 = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->ctr1) {
+ _mem_save_ctr1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr1, 0);
+ {
+ struct ndr_pull *_ndr_ctr1;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_ctr1, 4, r->compressed_length));
+ {
+ struct ndr_pull *_ndr_ctr1_compressed;
+ NDR_CHECK(ndr_pull_compression_start(_ndr_ctr1, &_ndr_ctr1_compressed, NDR_COMPRESSION_XPRESS, r->decompressed_length));
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCtr1(_ndr_ctr1_compressed, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ NDR_CHECK(ndr_pull_compression_end(_ndr_ctr1, _ndr_ctr1_compressed, NDR_COMPRESSION_XPRESS, r->decompressed_length));
+ }
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_ctr1, 4, r->compressed_length));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr1_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNCChangesXPRESSCtr1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesXPRESSCtr1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetNCChangesXPRESSCtr1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "decompressed_length", r->decompressed_length);
+ ndr_print_uint32(ndr, "compressed_length", r->compressed_length);
+ ndr_print_ptr(ndr, "ctr1", r->ctr1);
+ ndr->depth++;
+ if (r->ctr1) {
+ ndr_print_drsuapi_DsGetNCChangesCtr1(ndr, "ctr1", r->ctr1);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesXPRESSCtr6(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNCChangesXPRESSCtr6 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->decompressed_length));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->compressed_length));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr6));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->ctr6) {
+ {
+ struct ndr_push *_ndr_ctr6;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ctr6, 4, r->compressed_length));
+ {
+ struct ndr_push *_ndr_ctr6_compressed;
+ NDR_CHECK(ndr_push_compression_start(_ndr_ctr6, &_ndr_ctr6_compressed, NDR_COMPRESSION_XPRESS, r->decompressed_length));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr6(_ndr_ctr6_compressed, NDR_SCALARS|NDR_BUFFERS, r->ctr6));
+ NDR_CHECK(ndr_push_compression_end(_ndr_ctr6, _ndr_ctr6_compressed, NDR_COMPRESSION_XPRESS, r->decompressed_length));
+ }
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_ctr6, 4, r->compressed_length));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNCChangesXPRESSCtr6(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetNCChangesXPRESSCtr6 *r)
+{
+ uint32_t _ptr_ctr6;
+ TALLOC_CTX *_mem_save_ctr6_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->decompressed_length));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->compressed_length));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr6));
+ if (_ptr_ctr6) {
+ NDR_PULL_ALLOC(ndr, r->ctr6);
+ } else {
+ r->ctr6 = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->ctr6) {
+ _mem_save_ctr6_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr6, 0);
+ {
+ struct ndr_pull *_ndr_ctr6;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_ctr6, 4, r->compressed_length));
+ {
+ struct ndr_pull *_ndr_ctr6_compressed;
+ NDR_CHECK(ndr_pull_compression_start(_ndr_ctr6, &_ndr_ctr6_compressed, NDR_COMPRESSION_XPRESS, r->decompressed_length));
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCtr6(_ndr_ctr6_compressed, NDR_SCALARS|NDR_BUFFERS, r->ctr6));
+ NDR_CHECK(ndr_pull_compression_end(_ndr_ctr6, _ndr_ctr6_compressed, NDR_COMPRESSION_XPRESS, r->decompressed_length));
+ }
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_ctr6, 4, r->compressed_length));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr6_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNCChangesXPRESSCtr6(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesXPRESSCtr6 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetNCChangesXPRESSCtr6");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "decompressed_length", r->decompressed_length);
+ ndr_print_uint32(ndr, "compressed_length", r->compressed_length);
+ ndr_print_ptr(ndr, "ctr6", r->ctr6);
+ ndr->depth++;
+ if (r->ctr6) {
+ ndr_print_drsuapi_DsGetNCChangesCtr6(ndr, "ctr6", r->ctr6);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesCompressionType(struct ndr_push *ndr, int ndr_flags, enum drsuapi_DsGetNCChangesCompressionType r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNCChangesCompressionType(struct ndr_pull *ndr, int ndr_flags, enum drsuapi_DsGetNCChangesCompressionType *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNCChangesCompressionType(struct ndr_print *ndr, const char *name, enum drsuapi_DsGetNCChangesCompressionType r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DRSUAPI_COMPRESSION_TYPE_MSZIP: val = "DRSUAPI_COMPRESSION_TYPE_MSZIP"; break;
+ case DRSUAPI_COMPRESSION_TYPE_XPRESS: val = "DRSUAPI_COMPRESSION_TYPE_XPRESS"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesCompressedCtr(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsGetNCChangesCompressedCtr *r)
+{
+ {
+ uint32_t _flags_save_UNION = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16): {
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesMSZIPCtr1(ndr, NDR_SCALARS, &r->mszip1));
+ break; }
+
+ case 6|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16): {
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesMSZIPCtr6(ndr, NDR_SCALARS, &r->mszip6));
+ break; }
+
+ case 1|(DRSUAPI_COMPRESSION_TYPE_XPRESS<<16): {
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesXPRESSCtr1(ndr, NDR_SCALARS, &r->xpress1));
+ break; }
+
+ case 6|(DRSUAPI_COMPRESSION_TYPE_XPRESS<<16): {
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesXPRESSCtr6(ndr, NDR_SCALARS, &r->xpress6));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16):
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesMSZIPCtr1(ndr, NDR_BUFFERS, &r->mszip1));
+ break;
+
+ case 6|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16):
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesMSZIPCtr6(ndr, NDR_BUFFERS, &r->mszip6));
+ break;
+
+ case 1|(DRSUAPI_COMPRESSION_TYPE_XPRESS<<16):
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesXPRESSCtr1(ndr, NDR_BUFFERS, &r->xpress1));
+ break;
+
+ case 6|(DRSUAPI_COMPRESSION_TYPE_XPRESS<<16):
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesXPRESSCtr6(ndr, NDR_BUFFERS, &r->xpress6));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ ndr->flags = _flags_save_UNION;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNCChangesCompressedCtr(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsGetNCChangesCompressedCtr *r)
+{
+ int level;
+ {
+ uint32_t _flags_save_UNION = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case 1|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16): {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesMSZIPCtr1(ndr, NDR_SCALARS, &r->mszip1));
+ break; }
+
+ case 6|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16): {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesMSZIPCtr6(ndr, NDR_SCALARS, &r->mszip6));
+ break; }
+
+ case 1|(DRSUAPI_COMPRESSION_TYPE_XPRESS<<16): {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesXPRESSCtr1(ndr, NDR_SCALARS, &r->xpress1));
+ break; }
+
+ case 6|(DRSUAPI_COMPRESSION_TYPE_XPRESS<<16): {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesXPRESSCtr6(ndr, NDR_SCALARS, &r->xpress6));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16):
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesMSZIPCtr1(ndr, NDR_BUFFERS, &r->mszip1));
+ break;
+
+ case 6|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16):
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesMSZIPCtr6(ndr, NDR_BUFFERS, &r->mszip6));
+ break;
+
+ case 1|(DRSUAPI_COMPRESSION_TYPE_XPRESS<<16):
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesXPRESSCtr1(ndr, NDR_BUFFERS, &r->xpress1));
+ break;
+
+ case 6|(DRSUAPI_COMPRESSION_TYPE_XPRESS<<16):
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesXPRESSCtr6(ndr, NDR_BUFFERS, &r->xpress6));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ ndr->flags = _flags_save_UNION;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNCChangesCompressedCtr(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetNCChangesCompressedCtr *r)
+{
+ int level;
+ {
+ uint32_t _flags_save_UNION = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsGetNCChangesCompressedCtr");
+ switch (level) {
+ case 1|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16):
+ ndr_print_drsuapi_DsGetNCChangesMSZIPCtr1(ndr, "mszip1", &r->mszip1);
+ break;
+
+ case 6|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16):
+ ndr_print_drsuapi_DsGetNCChangesMSZIPCtr6(ndr, "mszip6", &r->mszip6);
+ break;
+
+ case 1|(DRSUAPI_COMPRESSION_TYPE_XPRESS<<16):
+ ndr_print_drsuapi_DsGetNCChangesXPRESSCtr1(ndr, "xpress1", &r->xpress1);
+ break;
+
+ case 6|(DRSUAPI_COMPRESSION_TYPE_XPRESS<<16):
+ ndr_print_drsuapi_DsGetNCChangesXPRESSCtr6(ndr, "xpress6", &r->xpress6);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+ ndr->flags = _flags_save_UNION;
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesCtr2(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNCChangesCtr2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->ctr, 1 | (DRSUAPI_COMPRESSION_TYPE_MSZIP << 16)));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCompressedCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCompressedCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNCChangesCtr2(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetNCChangesCtr2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->ctr, 1 | (DRSUAPI_COMPRESSION_TYPE_MSZIP << 16)));
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCompressedCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCompressedCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNCChangesCtr2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesCtr2 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetNCChangesCtr2");
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, &r->ctr, 1 | (DRSUAPI_COMPRESSION_TYPE_MSZIP << 16));
+ ndr_print_drsuapi_DsGetNCChangesCompressedCtr(ndr, "ctr", &r->ctr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesCtr7(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNCChangesCtr7 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->level));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCompressionType(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->ctr, r->level | (r->type << 16)));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCompressedCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCompressedCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNCChangesCtr7(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetNCChangesCtr7 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->level));
+ if (r->level < 0 || r->level > 6) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCompressionType(ndr, NDR_SCALARS, &r->type));
+ if (r->type < 2 || r->type > 3) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->ctr, r->level | (r->type << 16)));
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCompressedCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCompressedCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNCChangesCtr7(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesCtr7 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetNCChangesCtr7");
+ ndr->depth++;
+ ndr_print_int32(ndr, "level", r->level);
+ ndr_print_drsuapi_DsGetNCChangesCompressionType(ndr, "type", r->type);
+ ndr_print_set_switch_value(ndr, &r->ctr, r->level | (r->type << 16));
+ ndr_print_drsuapi_DsGetNCChangesCompressedCtr(ndr, "ctr", &r->ctr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesCtr(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsGetNCChangesCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr2(ndr, NDR_SCALARS, &r->ctr2));
+ break; }
+
+ case 6: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr6(ndr, NDR_SCALARS, &r->ctr6));
+ break; }
+
+ case 7: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr7(ndr, NDR_SCALARS, &r->ctr7));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr1(ndr, NDR_BUFFERS, &r->ctr1));
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr2(ndr, NDR_BUFFERS, &r->ctr2));
+ break;
+
+ case 6:
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr6(ndr, NDR_BUFFERS, &r->ctr6));
+ break;
+
+ case 7:
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr7(ndr, NDR_BUFFERS, &r->ctr7));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNCChangesCtr(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsGetNCChangesCtr *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCtr2(ndr, NDR_SCALARS, &r->ctr2));
+ break; }
+
+ case 6: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCtr6(ndr, NDR_SCALARS, &r->ctr6));
+ break; }
+
+ case 7: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCtr7(ndr, NDR_SCALARS, &r->ctr7));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCtr1(ndr, NDR_BUFFERS, &r->ctr1));
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCtr2(ndr, NDR_BUFFERS, &r->ctr2));
+ break;
+
+ case 6:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCtr6(ndr, NDR_BUFFERS, &r->ctr6));
+ break;
+
+ case 7:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCtr7(ndr, NDR_BUFFERS, &r->ctr7));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNCChangesCtr(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetNCChangesCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsGetNCChangesCtr");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsGetNCChangesCtr1(ndr, "ctr1", &r->ctr1);
+ break;
+
+ case 2:
+ ndr_print_drsuapi_DsGetNCChangesCtr2(ndr, "ctr2", &r->ctr2);
+ break;
+
+ case 6:
+ ndr_print_drsuapi_DsGetNCChangesCtr6(ndr, "ctr6", &r->ctr6);
+ break;
+
+ case 7:
+ ndr_print_drsuapi_DsGetNCChangesCtr7(ndr, "ctr7", &r->ctr7);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaUpdateRefsOptions(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaUpdateRefsOptions(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaUpdateRefsOptions(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_UPDATE_ASYNCHRONOUS_OPERATION", DRSUAPI_DS_REPLICA_UPDATE_ASYNCHRONOUS_OPERATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE", DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE", DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE", DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_UPDATE_0x00000010", DRSUAPI_DS_REPLICA_UPDATE_0x00000010, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaUpdateRefsRequest1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaUpdateRefsRequest1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ if (r->naming_context == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_ref_ptr(ndr));
+ if (r->dest_dsa_dns_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_ref_ptr(ndr));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->dest_dsa_guid));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaUpdateRefsOptions(ndr, NDR_SCALARS, r->options));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->naming_context));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dest_dsa_dns_name, CH_DOS)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dest_dsa_dns_name, CH_DOS)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dest_dsa_dns_name, ndr_charset_length(r->dest_dsa_dns_name, CH_DOS), sizeof(uint8_t), CH_DOS));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaUpdateRefsRequest1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaUpdateRefsRequest1 *r)
+{
+ uint32_t _ptr_naming_context;
+ TALLOC_CTX *_mem_save_naming_context_0;
+ uint32_t _ptr_dest_dsa_dns_name;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_ref_ptr(ndr, &_ptr_naming_context));
+ if (_ptr_naming_context) {
+ NDR_PULL_ALLOC(ndr, r->naming_context);
+ } else {
+ r->naming_context = NULL;
+ }
+ NDR_CHECK(ndr_pull_ref_ptr(ndr, &_ptr_dest_dsa_dns_name));
+ if (_ptr_dest_dsa_dns_name) {
+ NDR_PULL_ALLOC(ndr, r->dest_dsa_dns_name);
+ } else {
+ r->dest_dsa_dns_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->dest_dsa_guid));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaUpdateRefsOptions(ndr, NDR_SCALARS, &r->options));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_naming_context_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->naming_context, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->naming_context));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_naming_context_0, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->dest_dsa_dns_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->dest_dsa_dns_name));
+ if (ndr_get_array_length(ndr, &r->dest_dsa_dns_name) > ndr_get_array_size(ndr, &r->dest_dsa_dns_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->dest_dsa_dns_name), ndr_get_array_length(ndr, &r->dest_dsa_dns_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->dest_dsa_dns_name), sizeof(uint8_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dest_dsa_dns_name, ndr_get_array_length(ndr, &r->dest_dsa_dns_name), sizeof(uint8_t), CH_DOS));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaUpdateRefsRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaUpdateRefsRequest1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaUpdateRefsRequest1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "naming_context", r->naming_context);
+ ndr->depth++;
+ ndr_print_drsuapi_DsReplicaObjectIdentifier(ndr, "naming_context", r->naming_context);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "dest_dsa_dns_name", r->dest_dsa_dns_name);
+ ndr->depth++;
+ ndr_print_string(ndr, "dest_dsa_dns_name", r->dest_dsa_dns_name);
+ ndr->depth--;
+ ndr_print_GUID(ndr, "dest_dsa_guid", &r->dest_dsa_guid);
+ ndr_print_drsuapi_DsReplicaUpdateRefsOptions(ndr, "options", r->options);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaUpdateRefsRequest(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsReplicaUpdateRefsRequest *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaUpdateRefsRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaUpdateRefsRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaUpdateRefsRequest(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsReplicaUpdateRefsRequest *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaUpdateRefsRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaUpdateRefsRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaUpdateRefsRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsReplicaUpdateRefsRequest *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsReplicaUpdateRefsRequest");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsReplicaUpdateRefsRequest1(ndr, "req1", &r->req1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaAddOptions(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaAddOptions(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaAddOptions(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_ADD_ASYNCHRONOUS_OPERATION", DRSUAPI_DS_REPLICA_ADD_ASYNCHRONOUS_OPERATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_ADD_WRITEABLE", DRSUAPI_DS_REPLICA_ADD_WRITEABLE, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaDeleteOptions(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaDeleteOptions(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaDeleteOptions(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_DELETE_ASYNCHRONOUS_OPERATION", DRSUAPI_DS_REPLICA_DELETE_ASYNCHRONOUS_OPERATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_DELETE_WRITEABLE", DRSUAPI_DS_REPLICA_DELETE_WRITEABLE, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaModifyOptions(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaModifyOptions(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaModifyOptions(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_MODIFY_ASYNCHRONOUS_OPERATION", DRSUAPI_DS_REPLICA_MODIFY_ASYNCHRONOUS_OPERATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DRSUAPI_DS_REPLICA_MODIFY_WRITEABLE", DRSUAPI_DS_REPLICA_MODIFY_WRITEABLE, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsMembershipType(struct ndr_push *ndr, int ndr_flags, enum drsuapi_DsMembershipType r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsMembershipType(struct ndr_pull *ndr, int ndr_flags, enum drsuapi_DsMembershipType *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsMembershipType(struct ndr_print *ndr, const char *name, enum drsuapi_DsMembershipType r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DRSUAPI_DS_MEMBERSHIP_TYPE_UNIVERSAL_AND_DOMAIN_GROUPS: val = "DRSUAPI_DS_MEMBERSHIP_TYPE_UNIVERSAL_AND_DOMAIN_GROUPS"; break;
+ case DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_LOCAL_GROUPS: val = "DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_LOCAL_GROUPS"; break;
+ case DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_GROUPS: val = "DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_GROUPS"; break;
+ case DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_LOCAL_GROUPS2: val = "DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_LOCAL_GROUPS2"; break;
+ case DRSUAPI_DS_MEMBERSHIP_TYPE_UNIVERSAL_GROUPS: val = "DRSUAPI_DS_MEMBERSHIP_TYPE_UNIVERSAL_GROUPS"; break;
+ case DRSUAPI_DS_MEMBERSHIP_TYPE_GROUPMEMBERS: val = "DRSUAPI_DS_MEMBERSHIP_TYPE_GROUPMEMBERS"; break;
+ case DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_GROUPS2: val = "DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_GROUPS2"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetMembershipsCtr1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetMembershipsCtr1 *r)
+{
+ uint32_t cntr_info_array_1;
+ uint32_t cntr_group_attrs_1;
+ uint32_t cntr_sids_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->status));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_memberships));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_sids));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info_array));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->group_attrs));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sids));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->info_array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_memberships));
+ for (cntr_info_array_1 = 0; cntr_info_array_1 < r->num_memberships; cntr_info_array_1++) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info_array[cntr_info_array_1]));
+ }
+ for (cntr_info_array_1 = 0; cntr_info_array_1 < r->num_memberships; cntr_info_array_1++) {
+ if (r->info_array[cntr_info_array_1]) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->info_array[cntr_info_array_1]));
+ }
+ }
+ }
+ if (r->group_attrs) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_memberships));
+ for (cntr_group_attrs_1 = 0; cntr_group_attrs_1 < r->num_memberships; cntr_group_attrs_1++) {
+ NDR_CHECK(ndr_push_samr_GroupAttrs(ndr, NDR_SCALARS, r->group_attrs[cntr_group_attrs_1]));
+ }
+ }
+ if (r->sids) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_sids));
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->num_sids; cntr_sids_1++) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sids[cntr_sids_1]));
+ }
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->num_sids; cntr_sids_1++) {
+ if (r->sids[cntr_sids_1]) {
+ NDR_CHECK(ndr_push_dom_sid28(ndr, NDR_SCALARS|NDR_BUFFERS, r->sids[cntr_sids_1]));
+ }
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetMembershipsCtr1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetMembershipsCtr1 *r)
+{
+ uint32_t _ptr_info_array;
+ uint32_t cntr_info_array_1;
+ TALLOC_CTX *_mem_save_info_array_0;
+ TALLOC_CTX *_mem_save_info_array_1;
+ TALLOC_CTX *_mem_save_info_array_2;
+ uint32_t _ptr_group_attrs;
+ uint32_t cntr_group_attrs_1;
+ TALLOC_CTX *_mem_save_group_attrs_0;
+ TALLOC_CTX *_mem_save_group_attrs_1;
+ uint32_t _ptr_sids;
+ uint32_t cntr_sids_1;
+ TALLOC_CTX *_mem_save_sids_0;
+ TALLOC_CTX *_mem_save_sids_1;
+ TALLOC_CTX *_mem_save_sids_2;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->status));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_memberships));
+ if (r->num_memberships < 0 || r->num_memberships > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_sids));
+ if (r->num_sids < 0 || r->num_sids > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info_array));
+ if (_ptr_info_array) {
+ NDR_PULL_ALLOC(ndr, r->info_array);
+ } else {
+ r->info_array = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_group_attrs));
+ if (_ptr_group_attrs) {
+ NDR_PULL_ALLOC(ndr, r->group_attrs);
+ } else {
+ r->group_attrs = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sids));
+ if (_ptr_sids) {
+ NDR_PULL_ALLOC(ndr, r->sids);
+ } else {
+ r->sids = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->info_array) {
+ _mem_save_info_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info_array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->info_array));
+ NDR_PULL_ALLOC_N(ndr, r->info_array, ndr_get_array_size(ndr, &r->info_array));
+ _mem_save_info_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info_array, 0);
+ for (cntr_info_array_1 = 0; cntr_info_array_1 < r->num_memberships; cntr_info_array_1++) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info_array));
+ if (_ptr_info_array) {
+ NDR_PULL_ALLOC(ndr, r->info_array[cntr_info_array_1]);
+ } else {
+ r->info_array[cntr_info_array_1] = NULL;
+ }
+ }
+ for (cntr_info_array_1 = 0; cntr_info_array_1 < r->num_memberships; cntr_info_array_1++) {
+ if (r->info_array[cntr_info_array_1]) {
+ _mem_save_info_array_2 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info_array[cntr_info_array_1], 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->info_array[cntr_info_array_1]));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_array_2, 0);
+ }
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_array_0, 0);
+ }
+ if (r->group_attrs) {
+ _mem_save_group_attrs_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->group_attrs, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->group_attrs));
+ NDR_PULL_ALLOC_N(ndr, r->group_attrs, ndr_get_array_size(ndr, &r->group_attrs));
+ _mem_save_group_attrs_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->group_attrs, 0);
+ for (cntr_group_attrs_1 = 0; cntr_group_attrs_1 < r->num_memberships; cntr_group_attrs_1++) {
+ NDR_CHECK(ndr_pull_samr_GroupAttrs(ndr, NDR_SCALARS, &r->group_attrs[cntr_group_attrs_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_attrs_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_attrs_0, 0);
+ }
+ if (r->sids) {
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->sids));
+ NDR_PULL_ALLOC_N(ndr, r->sids, ndr_get_array_size(ndr, &r->sids));
+ _mem_save_sids_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids, 0);
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->num_sids; cntr_sids_1++) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sids));
+ if (_ptr_sids) {
+ NDR_PULL_ALLOC(ndr, r->sids[cntr_sids_1]);
+ } else {
+ r->sids[cntr_sids_1] = NULL;
+ }
+ }
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->num_sids; cntr_sids_1++) {
+ if (r->sids[cntr_sids_1]) {
+ _mem_save_sids_2 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids[cntr_sids_1], 0);
+ NDR_CHECK(ndr_pull_dom_sid28(ndr, NDR_SCALARS|NDR_BUFFERS, r->sids[cntr_sids_1]));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_2, 0);
+ }
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, 0);
+ }
+ if (r->info_array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->info_array, r->num_memberships));
+ }
+ if (r->group_attrs) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->group_attrs, r->num_memberships));
+ }
+ if (r->sids) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->sids, r->num_sids));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetMembershipsCtr1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetMembershipsCtr1 *r)
+{
+ uint32_t cntr_info_array_1;
+ uint32_t cntr_group_attrs_1;
+ uint32_t cntr_sids_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsGetMembershipsCtr1");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "status", r->status);
+ ndr_print_uint32(ndr, "num_memberships", r->num_memberships);
+ ndr_print_uint32(ndr, "num_sids", r->num_sids);
+ ndr_print_ptr(ndr, "info_array", r->info_array);
+ ndr->depth++;
+ if (r->info_array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "info_array", (int)r->num_memberships);
+ ndr->depth++;
+ for (cntr_info_array_1=0;cntr_info_array_1<r->num_memberships;cntr_info_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_info_array_1) != -1) {
+ ndr_print_ptr(ndr, "info_array", r->info_array[cntr_info_array_1]);
+ ndr->depth++;
+ if (r->info_array[cntr_info_array_1]) {
+ ndr_print_drsuapi_DsReplicaObjectIdentifier(ndr, "info_array", r->info_array[cntr_info_array_1]);
+ }
+ ndr->depth--;
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "group_attrs", r->group_attrs);
+ ndr->depth++;
+ if (r->group_attrs) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "group_attrs", (int)r->num_memberships);
+ ndr->depth++;
+ for (cntr_group_attrs_1=0;cntr_group_attrs_1<r->num_memberships;cntr_group_attrs_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_group_attrs_1) != -1) {
+ ndr_print_samr_GroupAttrs(ndr, "group_attrs", r->group_attrs[cntr_group_attrs_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sids", r->sids);
+ ndr->depth++;
+ if (r->sids) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "sids", (int)r->num_sids);
+ ndr->depth++;
+ for (cntr_sids_1=0;cntr_sids_1<r->num_sids;cntr_sids_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_sids_1) != -1) {
+ ndr_print_ptr(ndr, "sids", r->sids[cntr_sids_1]);
+ ndr->depth++;
+ if (r->sids[cntr_sids_1]) {
+ ndr_print_dom_sid28(ndr, "sids", r->sids[cntr_sids_1]);
+ }
+ ndr->depth--;
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetMembershipsCtr(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsGetMembershipsCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetMembershipsCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_DsGetMembershipsCtr1(ndr, NDR_BUFFERS, &r->ctr1));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetMembershipsCtr(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsGetMembershipsCtr *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetMembershipsCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetMembershipsCtr1(ndr, NDR_BUFFERS, &r->ctr1));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetMembershipsCtr(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetMembershipsCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsGetMembershipsCtr");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsGetMembershipsCtr1(ndr, "ctr1", &r->ctr1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetMembershipsRequest1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetMembershipsRequest1 *r)
+{
+ uint32_t cntr_info_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info_array));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_drsuapi_DsMembershipType(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->info_array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_info_array_1 = 0; cntr_info_array_1 < r->count; cntr_info_array_1++) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info_array[cntr_info_array_1]));
+ }
+ for (cntr_info_array_1 = 0; cntr_info_array_1 < r->count; cntr_info_array_1++) {
+ if (r->info_array[cntr_info_array_1]) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->info_array[cntr_info_array_1]));
+ }
+ }
+ }
+ if (r->domain) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->domain));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetMembershipsRequest1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetMembershipsRequest1 *r)
+{
+ uint32_t _ptr_info_array;
+ uint32_t cntr_info_array_1;
+ TALLOC_CTX *_mem_save_info_array_0;
+ TALLOC_CTX *_mem_save_info_array_1;
+ TALLOC_CTX *_mem_save_info_array_2;
+ uint32_t _ptr_domain;
+ TALLOC_CTX *_mem_save_domain_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 1 || r->count > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info_array));
+ if (_ptr_info_array) {
+ NDR_PULL_ALLOC(ndr, r->info_array);
+ } else {
+ r->info_array = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_drsuapi_DsMembershipType(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain));
+ if (_ptr_domain) {
+ NDR_PULL_ALLOC(ndr, r->domain);
+ } else {
+ r->domain = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->info_array) {
+ _mem_save_info_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info_array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->info_array));
+ NDR_PULL_ALLOC_N(ndr, r->info_array, ndr_get_array_size(ndr, &r->info_array));
+ _mem_save_info_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info_array, 0);
+ for (cntr_info_array_1 = 0; cntr_info_array_1 < r->count; cntr_info_array_1++) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info_array));
+ if (_ptr_info_array) {
+ NDR_PULL_ALLOC(ndr, r->info_array[cntr_info_array_1]);
+ } else {
+ r->info_array[cntr_info_array_1] = NULL;
+ }
+ }
+ for (cntr_info_array_1 = 0; cntr_info_array_1 < r->count; cntr_info_array_1++) {
+ if (r->info_array[cntr_info_array_1]) {
+ _mem_save_info_array_2 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info_array[cntr_info_array_1], 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->info_array[cntr_info_array_1]));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_array_2, 0);
+ }
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_array_0, 0);
+ }
+ if (r->domain) {
+ _mem_save_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->domain));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_0, 0);
+ }
+ if (r->info_array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->info_array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetMembershipsRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetMembershipsRequest1 *r)
+{
+ uint32_t cntr_info_array_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsGetMembershipsRequest1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "info_array", r->info_array);
+ ndr->depth++;
+ if (r->info_array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "info_array", (int)r->count);
+ ndr->depth++;
+ for (cntr_info_array_1=0;cntr_info_array_1<r->count;cntr_info_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_info_array_1) != -1) {
+ ndr_print_ptr(ndr, "info_array", r->info_array[cntr_info_array_1]);
+ ndr->depth++;
+ if (r->info_array[cntr_info_array_1]) {
+ ndr_print_drsuapi_DsReplicaObjectIdentifier(ndr, "info_array", r->info_array[cntr_info_array_1]);
+ }
+ ndr->depth--;
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "flags", r->flags);
+ ndr_print_drsuapi_DsMembershipType(ndr, "type", r->type);
+ ndr_print_ptr(ndr, "domain", r->domain);
+ ndr->depth++;
+ if (r->domain) {
+ ndr_print_drsuapi_DsReplicaObjectIdentifier(ndr, "domain", r->domain);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetMembershipsRequest(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsGetMembershipsRequest *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetMembershipsRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_DsGetMembershipsRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetMembershipsRequest(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsGetMembershipsRequest *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetMembershipsRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetMembershipsRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetMembershipsRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetMembershipsRequest *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsGetMembershipsRequest");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsGetMembershipsRequest1(ndr, "req1", &r->req1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNT4ChangeLogRequest1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNT4ChangeLogRequest1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data, r->length));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNT4ChangeLogRequest1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetNT4ChangeLogRequest1 *r)
+{
+ uint32_t _ptr_data;
+ TALLOC_CTX *_mem_save_data_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->length));
+ if (r->length < 0 || r->length > 0x00A00000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data));
+ if (_ptr_data) {
+ NDR_PULL_ALLOC(ndr, r->data);
+ } else {
+ r->data = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->data, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->data));
+ NDR_PULL_ALLOC_N(ndr, r->data, ndr_get_array_size(ndr, &r->data));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data, ndr_get_array_size(ndr, &r->data)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, 0);
+ }
+ if (r->data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->data, r->length));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNT4ChangeLogRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNT4ChangeLogRequest1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetNT4ChangeLogRequest1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "unknown1", r->unknown1);
+ ndr_print_uint32(ndr, "unknown2", r->unknown2);
+ ndr_print_uint32(ndr, "length", r->length);
+ ndr_print_ptr(ndr, "data", r->data);
+ ndr->depth++;
+ if (r->data) {
+ ndr_print_array_uint8(ndr, "data", r->data, r->length);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNT4ChangeLogRequest(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsGetNT4ChangeLogRequest *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetNT4ChangeLogRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_DsGetNT4ChangeLogRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNT4ChangeLogRequest(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsGetNT4ChangeLogRequest *r)
+{
+ int level;
+ uint32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNT4ChangeLogRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNT4ChangeLogRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNT4ChangeLogRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetNT4ChangeLogRequest *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsGetNT4ChangeLogRequest");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsGetNT4ChangeLogRequest1(ndr, "req1", &r->req1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNT4ChangeLogInfo1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNT4ChangeLogInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length2));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->time2));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown3));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->time4));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown5));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->time6));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->status));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->data1));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->data2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data1) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length1));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data1, r->length1));
+ }
+ if (r->data2) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length2));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data2, r->length2));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNT4ChangeLogInfo1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetNT4ChangeLogInfo1 *r)
+{
+ uint32_t _ptr_data1;
+ TALLOC_CTX *_mem_save_data1_0;
+ uint32_t _ptr_data2;
+ TALLOC_CTX *_mem_save_data2_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->length1));
+ if (r->length1 < 0 || r->length1 > 0x00A00000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->length2));
+ if (r->length2 < 0 || r->length2 > 0x00A00000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->time2));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->time4));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown5));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->time6));
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->status));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data1));
+ if (_ptr_data1) {
+ NDR_PULL_ALLOC(ndr, r->data1);
+ } else {
+ r->data1 = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data2));
+ if (_ptr_data2) {
+ NDR_PULL_ALLOC(ndr, r->data2);
+ } else {
+ r->data2 = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data1) {
+ _mem_save_data1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->data1, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->data1));
+ NDR_PULL_ALLOC_N(ndr, r->data1, ndr_get_array_size(ndr, &r->data1));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data1, ndr_get_array_size(ndr, &r->data1)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data1_0, 0);
+ }
+ if (r->data2) {
+ _mem_save_data2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->data2, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->data2));
+ NDR_PULL_ALLOC_N(ndr, r->data2, ndr_get_array_size(ndr, &r->data2));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data2, ndr_get_array_size(ndr, &r->data2)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data2_0, 0);
+ }
+ if (r->data1) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->data1, r->length1));
+ }
+ if (r->data2) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->data2, r->length2));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNT4ChangeLogInfo1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNT4ChangeLogInfo1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetNT4ChangeLogInfo1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "length1", r->length1);
+ ndr_print_uint32(ndr, "length2", r->length2);
+ ndr_print_hyper(ndr, "unknown1", r->unknown1);
+ ndr_print_NTTIME(ndr, "time2", r->time2);
+ ndr_print_hyper(ndr, "unknown3", r->unknown3);
+ ndr_print_NTTIME(ndr, "time4", r->time4);
+ ndr_print_hyper(ndr, "unknown5", r->unknown5);
+ ndr_print_NTTIME(ndr, "time6", r->time6);
+ ndr_print_NTSTATUS(ndr, "status", r->status);
+ ndr_print_ptr(ndr, "data1", r->data1);
+ ndr->depth++;
+ if (r->data1) {
+ ndr_print_array_uint8(ndr, "data1", r->data1, r->length1);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "data2", r->data2);
+ ndr->depth++;
+ if (r->data2) {
+ ndr_print_array_uint8(ndr, "data2", r->data2, r->length2);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNT4ChangeLogInfo(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsGetNT4ChangeLogInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetNT4ChangeLogInfo1(ndr, NDR_SCALARS, &r->info1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_DsGetNT4ChangeLogInfo1(ndr, NDR_BUFFERS, &r->info1));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNT4ChangeLogInfo(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsGetNT4ChangeLogInfo *r)
+{
+ int level;
+ uint32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNT4ChangeLogInfo1(ndr, NDR_SCALARS, &r->info1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNT4ChangeLogInfo1(ndr, NDR_BUFFERS, &r->info1));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNT4ChangeLogInfo(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetNT4ChangeLogInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsGetNT4ChangeLogInfo");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsGetNT4ChangeLogInfo1(ndr, "info1", &r->info1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsNameStatus(struct ndr_push *ndr, int ndr_flags, enum drsuapi_DsNameStatus r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsNameStatus(struct ndr_pull *ndr, int ndr_flags, enum drsuapi_DsNameStatus *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsNameStatus(struct ndr_print *ndr, const char *name, enum drsuapi_DsNameStatus r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DRSUAPI_DS_NAME_STATUS_OK: val = "DRSUAPI_DS_NAME_STATUS_OK"; break;
+ case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR: val = "DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR"; break;
+ case DRSUAPI_DS_NAME_STATUS_NOT_FOUND: val = "DRSUAPI_DS_NAME_STATUS_NOT_FOUND"; break;
+ case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE: val = "DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE"; break;
+ case DRSUAPI_DS_NAME_STATUS_NO_MAPPING: val = "DRSUAPI_DS_NAME_STATUS_NO_MAPPING"; break;
+ case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY: val = "DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY"; break;
+ case DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING: val = "DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING"; break;
+ case DRSUAPI_DS_NAME_STATUS_TRUST_REFERRAL: val = "DRSUAPI_DS_NAME_STATUS_TRUST_REFERRAL"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsNameFlags(struct ndr_push *ndr, int ndr_flags, enum drsuapi_DsNameFlags r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsNameFlags(struct ndr_pull *ndr, int ndr_flags, enum drsuapi_DsNameFlags *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsNameFlags(struct ndr_print *ndr, const char *name, enum drsuapi_DsNameFlags r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DRSUAPI_DS_NAME_FLAG_NO_FLAGS: val = "DRSUAPI_DS_NAME_FLAG_NO_FLAGS"; break;
+ case DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY: val = "DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY"; break;
+ case DRSUAPI_DS_NAME_FLAG_EVAL_AT_DC: val = "DRSUAPI_DS_NAME_FLAG_EVAL_AT_DC"; break;
+ case DRSUAPI_DS_NAME_FLAG_GCVERIFY: val = "DRSUAPI_DS_NAME_FLAG_GCVERIFY"; break;
+ case DRSUAPI_DS_NAME_FLAG_TRUST_REFERRAL: val = "DRSUAPI_DS_NAME_FLAG_TRUST_REFERRAL"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsNameFormat(struct ndr_push *ndr, int ndr_flags, enum drsuapi_DsNameFormat r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsNameFormat(struct ndr_pull *ndr, int ndr_flags, enum drsuapi_DsNameFormat *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsNameFormat(struct ndr_print *ndr, const char *name, enum drsuapi_DsNameFormat r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DRSUAPI_DS_NAME_FORMAT_UKNOWN: val = "DRSUAPI_DS_NAME_FORMAT_UKNOWN"; break;
+ case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: val = "DRSUAPI_DS_NAME_FORMAT_FQDN_1779"; break;
+ case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: val = "DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT"; break;
+ case DRSUAPI_DS_NAME_FORMAT_DISPLAY: val = "DRSUAPI_DS_NAME_FORMAT_DISPLAY"; break;
+ case DRSUAPI_DS_NAME_FORMAT_GUID: val = "DRSUAPI_DS_NAME_FORMAT_GUID"; break;
+ case DRSUAPI_DS_NAME_FORMAT_CANONICAL: val = "DRSUAPI_DS_NAME_FORMAT_CANONICAL"; break;
+ case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: val = "DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL"; break;
+ case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: val = "DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX"; break;
+ case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: val = "DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL"; break;
+ case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: val = "DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY"; break;
+ case DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN: val = "DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsNameString(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsNameString *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->str));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->str) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->str, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->str, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->str, ndr_charset_length(r->str, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsNameString(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsNameString *r)
+{
+ uint32_t _ptr_str;
+ TALLOC_CTX *_mem_save_str_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_str));
+ if (_ptr_str) {
+ NDR_PULL_ALLOC(ndr, r->str);
+ } else {
+ r->str = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->str) {
+ _mem_save_str_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->str, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->str));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->str));
+ if (ndr_get_array_length(ndr, &r->str) > ndr_get_array_size(ndr, &r->str)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->str), ndr_get_array_length(ndr, &r->str));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->str), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->str, ndr_get_array_length(ndr, &r->str), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_str_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsNameString(struct ndr_print *ndr, const char *name, const struct drsuapi_DsNameString *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsNameString");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "str", r->str);
+ ndr->depth++;
+ if (r->str) {
+ ndr_print_string(ndr, "str", r->str);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsNameRequest1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsNameRequest1 *r)
+{
+ uint32_t cntr_names_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->codepage));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->language));
+ NDR_CHECK(ndr_push_drsuapi_DsNameFlags(ndr, NDR_SCALARS, r->format_flags));
+ NDR_CHECK(ndr_push_drsuapi_DsNameFormat(ndr, NDR_SCALARS, r->format_offered));
+ NDR_CHECK(ndr_push_drsuapi_DsNameFormat(ndr, NDR_SCALARS, r->format_desired));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->names));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->names) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsNameString(ndr, NDR_SCALARS, &r->names[cntr_names_1]));
+ }
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsNameString(ndr, NDR_BUFFERS, &r->names[cntr_names_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsNameRequest1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsNameRequest1 *r)
+{
+ uint32_t _ptr_names;
+ uint32_t cntr_names_1;
+ TALLOC_CTX *_mem_save_names_0;
+ TALLOC_CTX *_mem_save_names_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->codepage));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->language));
+ NDR_CHECK(ndr_pull_drsuapi_DsNameFlags(ndr, NDR_SCALARS, &r->format_flags));
+ NDR_CHECK(ndr_pull_drsuapi_DsNameFormat(ndr, NDR_SCALARS, &r->format_offered));
+ NDR_CHECK(ndr_pull_drsuapi_DsNameFormat(ndr, NDR_SCALARS, &r->format_desired));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 1 || r->count > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_names));
+ if (_ptr_names) {
+ NDR_PULL_ALLOC(ndr, r->names);
+ } else {
+ r->names = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->names) {
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->names, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->names));
+ NDR_PULL_ALLOC_N(ndr, r->names, ndr_get_array_size(ndr, &r->names));
+ _mem_save_names_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->names, 0);
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsNameString(ndr, NDR_SCALARS, &r->names[cntr_names_1]));
+ }
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsNameString(ndr, NDR_BUFFERS, &r->names[cntr_names_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, 0);
+ }
+ if (r->names) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->names, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsNameRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsNameRequest1 *r)
+{
+ uint32_t cntr_names_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsNameRequest1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "codepage", r->codepage);
+ ndr_print_uint32(ndr, "language", r->language);
+ ndr_print_drsuapi_DsNameFlags(ndr, "format_flags", r->format_flags);
+ ndr_print_drsuapi_DsNameFormat(ndr, "format_offered", r->format_offered);
+ ndr_print_drsuapi_DsNameFormat(ndr, "format_desired", r->format_desired);
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "names", r->names);
+ ndr->depth++;
+ if (r->names) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "names", (int)r->count);
+ ndr->depth++;
+ for (cntr_names_1=0;cntr_names_1<r->count;cntr_names_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_names_1) != -1) {
+ ndr_print_drsuapi_DsNameString(ndr, "names", &r->names[cntr_names_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsNameRequest(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsNameRequest *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsNameRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_DsNameRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsNameRequest(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsNameRequest *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsNameRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_DsNameRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsNameRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsNameRequest *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsNameRequest");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsNameRequest1(ndr, "req1", &r->req1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsNameInfo1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsNameInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_drsuapi_DsNameStatus(ndr, NDR_SCALARS, r->status));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->dns_domain_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->result_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->dns_domain_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dns_domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dns_domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dns_domain_name, ndr_charset_length(r->dns_domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->result_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->result_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->result_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->result_name, ndr_charset_length(r->result_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsNameInfo1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsNameInfo1 *r)
+{
+ uint32_t _ptr_dns_domain_name;
+ TALLOC_CTX *_mem_save_dns_domain_name_0;
+ uint32_t _ptr_result_name;
+ TALLOC_CTX *_mem_save_result_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_drsuapi_DsNameStatus(ndr, NDR_SCALARS, &r->status));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dns_domain_name));
+ if (_ptr_dns_domain_name) {
+ NDR_PULL_ALLOC(ndr, r->dns_domain_name);
+ } else {
+ r->dns_domain_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_result_name));
+ if (_ptr_result_name) {
+ NDR_PULL_ALLOC(ndr, r->result_name);
+ } else {
+ r->result_name = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->dns_domain_name) {
+ _mem_save_dns_domain_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->dns_domain_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->dns_domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->dns_domain_name));
+ if (ndr_get_array_length(ndr, &r->dns_domain_name) > ndr_get_array_size(ndr, &r->dns_domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->dns_domain_name), ndr_get_array_length(ndr, &r->dns_domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->dns_domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dns_domain_name, ndr_get_array_length(ndr, &r->dns_domain_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dns_domain_name_0, 0);
+ }
+ if (r->result_name) {
+ _mem_save_result_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->result_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->result_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->result_name));
+ if (ndr_get_array_length(ndr, &r->result_name) > ndr_get_array_size(ndr, &r->result_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->result_name), ndr_get_array_length(ndr, &r->result_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->result_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->result_name, ndr_get_array_length(ndr, &r->result_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_result_name_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsNameInfo1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsNameInfo1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsNameInfo1");
+ ndr->depth++;
+ ndr_print_drsuapi_DsNameStatus(ndr, "status", r->status);
+ ndr_print_ptr(ndr, "dns_domain_name", r->dns_domain_name);
+ ndr->depth++;
+ if (r->dns_domain_name) {
+ ndr_print_string(ndr, "dns_domain_name", r->dns_domain_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "result_name", r->result_name);
+ ndr->depth++;
+ if (r->result_name) {
+ ndr_print_string(ndr, "result_name", r->result_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsNameCtr1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsNameCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsNameInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsNameInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsNameCtr1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsNameCtr1 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsNameInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsNameInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsNameCtr1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsNameCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsNameCtr1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_drsuapi_DsNameInfo1(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsNameCtr(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsNameCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ if (r->ctr1) {
+ NDR_CHECK(ndr_push_drsuapi_DsNameCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ }
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsNameCtr(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsNameCtr *r)
+{
+ int level;
+ int32_t _level;
+ TALLOC_CTX *_mem_save_ctr1_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ uint32_t _ptr_ctr1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr1));
+ if (_ptr_ctr1) {
+ NDR_PULL_ALLOC(ndr, r->ctr1);
+ } else {
+ r->ctr1 = NULL;
+ }
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ if (r->ctr1) {
+ _mem_save_ctr1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr1, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsNameCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr1_0, 0);
+ }
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsNameCtr(struct ndr_print *ndr, const char *name, const union drsuapi_DsNameCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsNameCtr");
+ switch (level) {
+ case 1:
+ ndr_print_ptr(ndr, "ctr1", r->ctr1);
+ ndr->depth++;
+ if (r->ctr1) {
+ ndr_print_drsuapi_DsNameCtr1(ndr, "ctr1", r->ctr1);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsSpnOperation(struct ndr_push *ndr, int ndr_flags, enum drsuapi_DsSpnOperation r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsSpnOperation(struct ndr_pull *ndr, int ndr_flags, enum drsuapi_DsSpnOperation *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsSpnOperation(struct ndr_print *ndr, const char *name, enum drsuapi_DsSpnOperation r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DRSUAPI_DS_SPN_OPERATION_ADD: val = "DRSUAPI_DS_SPN_OPERATION_ADD"; break;
+ case DRSUAPI_DS_SPN_OPERATION_REPLACE: val = "DRSUAPI_DS_SPN_OPERATION_REPLACE"; break;
+ case DRSUAPI_DS_SPN_OPERATION_DELETE: val = "DRSUAPI_DS_SPN_OPERATION_DELETE"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsWriteAccountSpnRequest1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsWriteAccountSpnRequest1 *r)
+{
+ uint32_t cntr_spn_names_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_drsuapi_DsSpnOperation(ndr, NDR_SCALARS, r->operation));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->object_dn));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->spn_names));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->object_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->object_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->object_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->object_dn, ndr_charset_length(r->object_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->spn_names) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_spn_names_1 = 0; cntr_spn_names_1 < r->count; cntr_spn_names_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsNameString(ndr, NDR_SCALARS, &r->spn_names[cntr_spn_names_1]));
+ }
+ for (cntr_spn_names_1 = 0; cntr_spn_names_1 < r->count; cntr_spn_names_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsNameString(ndr, NDR_BUFFERS, &r->spn_names[cntr_spn_names_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsWriteAccountSpnRequest1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsWriteAccountSpnRequest1 *r)
+{
+ uint32_t _ptr_object_dn;
+ TALLOC_CTX *_mem_save_object_dn_0;
+ uint32_t _ptr_spn_names;
+ uint32_t cntr_spn_names_1;
+ TALLOC_CTX *_mem_save_spn_names_0;
+ TALLOC_CTX *_mem_save_spn_names_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_drsuapi_DsSpnOperation(ndr, NDR_SCALARS, &r->operation));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_object_dn));
+ if (_ptr_object_dn) {
+ NDR_PULL_ALLOC(ndr, r->object_dn);
+ } else {
+ r->object_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_spn_names));
+ if (_ptr_spn_names) {
+ NDR_PULL_ALLOC(ndr, r->spn_names);
+ } else {
+ r->spn_names = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->object_dn) {
+ _mem_save_object_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->object_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->object_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->object_dn));
+ if (ndr_get_array_length(ndr, &r->object_dn) > ndr_get_array_size(ndr, &r->object_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->object_dn), ndr_get_array_length(ndr, &r->object_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->object_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->object_dn, ndr_get_array_length(ndr, &r->object_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_object_dn_0, 0);
+ }
+ if (r->spn_names) {
+ _mem_save_spn_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->spn_names, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->spn_names));
+ NDR_PULL_ALLOC_N(ndr, r->spn_names, ndr_get_array_size(ndr, &r->spn_names));
+ _mem_save_spn_names_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->spn_names, 0);
+ for (cntr_spn_names_1 = 0; cntr_spn_names_1 < r->count; cntr_spn_names_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsNameString(ndr, NDR_SCALARS, &r->spn_names[cntr_spn_names_1]));
+ }
+ for (cntr_spn_names_1 = 0; cntr_spn_names_1 < r->count; cntr_spn_names_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsNameString(ndr, NDR_BUFFERS, &r->spn_names[cntr_spn_names_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_spn_names_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_spn_names_0, 0);
+ }
+ if (r->spn_names) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->spn_names, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsWriteAccountSpnRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsWriteAccountSpnRequest1 *r)
+{
+ uint32_t cntr_spn_names_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsWriteAccountSpnRequest1");
+ ndr->depth++;
+ ndr_print_drsuapi_DsSpnOperation(ndr, "operation", r->operation);
+ ndr_print_uint32(ndr, "unknown1", r->unknown1);
+ ndr_print_ptr(ndr, "object_dn", r->object_dn);
+ ndr->depth++;
+ if (r->object_dn) {
+ ndr_print_string(ndr, "object_dn", r->object_dn);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "spn_names", r->spn_names);
+ ndr->depth++;
+ if (r->spn_names) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "spn_names", (int)r->count);
+ ndr->depth++;
+ for (cntr_spn_names_1=0;cntr_spn_names_1<r->count;cntr_spn_names_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_spn_names_1) != -1) {
+ ndr_print_drsuapi_DsNameString(ndr, "spn_names", &r->spn_names[cntr_spn_names_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsWriteAccountSpnRequest(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsWriteAccountSpnRequest *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsWriteAccountSpnRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_DsWriteAccountSpnRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsWriteAccountSpnRequest(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsWriteAccountSpnRequest *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsWriteAccountSpnRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_DsWriteAccountSpnRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsWriteAccountSpnRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsWriteAccountSpnRequest *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsWriteAccountSpnRequest");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsWriteAccountSpnRequest1(ndr, "req1", &r->req1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsWriteAccountSpnResult1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsWriteAccountSpnResult1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->status));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsWriteAccountSpnResult1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsWriteAccountSpnResult1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->status));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsWriteAccountSpnResult1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsWriteAccountSpnResult1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsWriteAccountSpnResult1");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "status", r->status);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsWriteAccountSpnResult(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsWriteAccountSpnResult *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsWriteAccountSpnResult1(ndr, NDR_SCALARS, &r->res1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsWriteAccountSpnResult(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsWriteAccountSpnResult *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsWriteAccountSpnResult1(ndr, NDR_SCALARS, &r->res1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsWriteAccountSpnResult(struct ndr_print *ndr, const char *name, const union drsuapi_DsWriteAccountSpnResult *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsWriteAccountSpnResult");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsWriteAccountSpnResult1(ndr, "res1", &r->res1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsRemoveDSServerRequest1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsRemoveDSServerRequest1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->server_dn));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain_dn));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->server_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->server_dn, ndr_charset_length(r->server_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->domain_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain_dn, ndr_charset_length(r->domain_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsRemoveDSServerRequest1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsRemoveDSServerRequest1 *r)
+{
+ uint32_t _ptr_server_dn;
+ TALLOC_CTX *_mem_save_server_dn_0;
+ uint32_t _ptr_domain_dn;
+ TALLOC_CTX *_mem_save_domain_dn_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_dn));
+ if (_ptr_server_dn) {
+ NDR_PULL_ALLOC(ndr, r->server_dn);
+ } else {
+ r->server_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_dn));
+ if (_ptr_domain_dn) {
+ NDR_PULL_ALLOC(ndr, r->domain_dn);
+ } else {
+ r->domain_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->server_dn) {
+ _mem_save_server_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->server_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->server_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->server_dn));
+ if (ndr_get_array_length(ndr, &r->server_dn) > ndr_get_array_size(ndr, &r->server_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->server_dn), ndr_get_array_length(ndr, &r->server_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->server_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->server_dn, ndr_get_array_length(ndr, &r->server_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_dn_0, 0);
+ }
+ if (r->domain_dn) {
+ _mem_save_domain_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain_dn));
+ if (ndr_get_array_length(ndr, &r->domain_dn) > ndr_get_array_size(ndr, &r->domain_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain_dn), ndr_get_array_length(ndr, &r->domain_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain_dn, ndr_get_array_length(ndr, &r->domain_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_dn_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsRemoveDSServerRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsRemoveDSServerRequest1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsRemoveDSServerRequest1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_dn", r->server_dn);
+ ndr->depth++;
+ if (r->server_dn) {
+ ndr_print_string(ndr, "server_dn", r->server_dn);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_dn", r->domain_dn);
+ ndr->depth++;
+ if (r->domain_dn) {
+ ndr_print_string(ndr, "domain_dn", r->domain_dn);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown", r->unknown);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsRemoveDSServerRequest(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsRemoveDSServerRequest *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsRemoveDSServerRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_DsRemoveDSServerRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsRemoveDSServerRequest(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsRemoveDSServerRequest *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsRemoveDSServerRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_DsRemoveDSServerRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsRemoveDSServerRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsRemoveDSServerRequest *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsRemoveDSServerRequest");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsRemoveDSServerRequest1(ndr, "req1", &r->req1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsRemoveDSServerResult1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsRemoveDSServerResult1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->status));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsRemoveDSServerResult1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsRemoveDSServerResult1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->status));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsRemoveDSServerResult1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsRemoveDSServerResult1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsRemoveDSServerResult1");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "status", r->status);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsRemoveDSServerResult(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsRemoveDSServerResult *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsRemoveDSServerResult1(ndr, NDR_SCALARS, &r->res1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsRemoveDSServerResult(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsRemoveDSServerResult *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsRemoveDSServerResult1(ndr, NDR_SCALARS, &r->res1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsRemoveDSServerResult(struct ndr_print *ndr, const char *name, const union drsuapi_DsRemoveDSServerResult *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsRemoveDSServerResult");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsRemoveDSServerResult1(ndr, "res1", &r->res1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetDCInfoRequest1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetDCInfoRequest1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain_name));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->level));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->domain_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain_name, ndr_charset_length(r->domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetDCInfoRequest1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetDCInfoRequest1 *r)
+{
+ uint32_t _ptr_domain_name;
+ TALLOC_CTX *_mem_save_domain_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_name));
+ if (_ptr_domain_name) {
+ NDR_PULL_ALLOC(ndr, r->domain_name);
+ } else {
+ r->domain_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->level));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->domain_name) {
+ _mem_save_domain_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain_name));
+ if (ndr_get_array_length(ndr, &r->domain_name) > ndr_get_array_size(ndr, &r->domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain_name), ndr_get_array_length(ndr, &r->domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain_name, ndr_get_array_length(ndr, &r->domain_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_name_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetDCInfoRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCInfoRequest1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetDCInfoRequest1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_name", r->domain_name);
+ ndr->depth++;
+ if (r->domain_name) {
+ ndr_print_string(ndr, "domain_name", r->domain_name);
+ }
+ ndr->depth--;
+ ndr_print_int32(ndr, "level", r->level);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetDCInfoRequest(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsGetDCInfoRequest *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCInfoRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCInfoRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetDCInfoRequest(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsGetDCInfoRequest *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCInfoRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCInfoRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetDCInfoRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetDCInfoRequest *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsGetDCInfoRequest");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsGetDCInfoRequest1(ndr, "req1", &r->req1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetDCInfo1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetDCInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->netbios_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->dns_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->site_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->computer_dn));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->server_dn));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->is_pdc));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->is_enabled));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->netbios_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->netbios_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->netbios_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->netbios_name, ndr_charset_length(r->netbios_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->dns_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dns_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dns_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dns_name, ndr_charset_length(r->dns_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->site_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->site_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->site_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->site_name, ndr_charset_length(r->site_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->computer_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->computer_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->computer_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->computer_dn, ndr_charset_length(r->computer_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->server_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->server_dn, ndr_charset_length(r->server_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetDCInfo1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetDCInfo1 *r)
+{
+ uint32_t _ptr_netbios_name;
+ TALLOC_CTX *_mem_save_netbios_name_0;
+ uint32_t _ptr_dns_name;
+ TALLOC_CTX *_mem_save_dns_name_0;
+ uint32_t _ptr_site_name;
+ TALLOC_CTX *_mem_save_site_name_0;
+ uint32_t _ptr_computer_dn;
+ TALLOC_CTX *_mem_save_computer_dn_0;
+ uint32_t _ptr_server_dn;
+ TALLOC_CTX *_mem_save_server_dn_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_netbios_name));
+ if (_ptr_netbios_name) {
+ NDR_PULL_ALLOC(ndr, r->netbios_name);
+ } else {
+ r->netbios_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dns_name));
+ if (_ptr_dns_name) {
+ NDR_PULL_ALLOC(ndr, r->dns_name);
+ } else {
+ r->dns_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_site_name));
+ if (_ptr_site_name) {
+ NDR_PULL_ALLOC(ndr, r->site_name);
+ } else {
+ r->site_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_computer_dn));
+ if (_ptr_computer_dn) {
+ NDR_PULL_ALLOC(ndr, r->computer_dn);
+ } else {
+ r->computer_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_dn));
+ if (_ptr_server_dn) {
+ NDR_PULL_ALLOC(ndr, r->server_dn);
+ } else {
+ r->server_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->is_pdc));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->is_enabled));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->netbios_name) {
+ _mem_save_netbios_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->netbios_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->netbios_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->netbios_name));
+ if (ndr_get_array_length(ndr, &r->netbios_name) > ndr_get_array_size(ndr, &r->netbios_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->netbios_name), ndr_get_array_length(ndr, &r->netbios_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->netbios_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->netbios_name, ndr_get_array_length(ndr, &r->netbios_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_netbios_name_0, 0);
+ }
+ if (r->dns_name) {
+ _mem_save_dns_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->dns_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->dns_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->dns_name));
+ if (ndr_get_array_length(ndr, &r->dns_name) > ndr_get_array_size(ndr, &r->dns_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->dns_name), ndr_get_array_length(ndr, &r->dns_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->dns_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dns_name, ndr_get_array_length(ndr, &r->dns_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dns_name_0, 0);
+ }
+ if (r->site_name) {
+ _mem_save_site_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->site_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->site_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->site_name));
+ if (ndr_get_array_length(ndr, &r->site_name) > ndr_get_array_size(ndr, &r->site_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->site_name), ndr_get_array_length(ndr, &r->site_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->site_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->site_name, ndr_get_array_length(ndr, &r->site_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_site_name_0, 0);
+ }
+ if (r->computer_dn) {
+ _mem_save_computer_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->computer_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->computer_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->computer_dn));
+ if (ndr_get_array_length(ndr, &r->computer_dn) > ndr_get_array_size(ndr, &r->computer_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->computer_dn), ndr_get_array_length(ndr, &r->computer_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->computer_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->computer_dn, ndr_get_array_length(ndr, &r->computer_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_computer_dn_0, 0);
+ }
+ if (r->server_dn) {
+ _mem_save_server_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->server_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->server_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->server_dn));
+ if (ndr_get_array_length(ndr, &r->server_dn) > ndr_get_array_size(ndr, &r->server_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->server_dn), ndr_get_array_length(ndr, &r->server_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->server_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->server_dn, ndr_get_array_length(ndr, &r->server_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_dn_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetDCInfo1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCInfo1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetDCInfo1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "netbios_name", r->netbios_name);
+ ndr->depth++;
+ if (r->netbios_name) {
+ ndr_print_string(ndr, "netbios_name", r->netbios_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "dns_name", r->dns_name);
+ ndr->depth++;
+ if (r->dns_name) {
+ ndr_print_string(ndr, "dns_name", r->dns_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "site_name", r->site_name);
+ ndr->depth++;
+ if (r->site_name) {
+ ndr_print_string(ndr, "site_name", r->site_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "computer_dn", r->computer_dn);
+ ndr->depth++;
+ if (r->computer_dn) {
+ ndr_print_string(ndr, "computer_dn", r->computer_dn);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "server_dn", r->server_dn);
+ ndr->depth++;
+ if (r->server_dn) {
+ ndr_print_string(ndr, "server_dn", r->server_dn);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "is_pdc", r->is_pdc);
+ ndr_print_uint32(ndr, "is_enabled", r->is_enabled);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetDCInfoCtr1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetDCInfoCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetDCInfoCtr1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetDCInfoCtr1 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetDCInfoCtr1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCInfoCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsGetDCInfoCtr1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_drsuapi_DsGetDCInfo1(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetDCInfo2(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetDCInfo2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->netbios_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->dns_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->site_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->site_dn));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->computer_dn));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->server_dn));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ntds_dn));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->is_pdc));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->is_enabled));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->is_gc));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->site_guid));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->computer_guid));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->server_guid));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->ntds_guid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->netbios_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->netbios_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->netbios_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->netbios_name, ndr_charset_length(r->netbios_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->dns_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dns_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dns_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dns_name, ndr_charset_length(r->dns_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->site_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->site_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->site_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->site_name, ndr_charset_length(r->site_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->site_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->site_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->site_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->site_dn, ndr_charset_length(r->site_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->computer_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->computer_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->computer_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->computer_dn, ndr_charset_length(r->computer_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->server_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->server_dn, ndr_charset_length(r->server_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->ntds_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->ntds_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->ntds_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->ntds_dn, ndr_charset_length(r->ntds_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetDCInfo2(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetDCInfo2 *r)
+{
+ uint32_t _ptr_netbios_name;
+ TALLOC_CTX *_mem_save_netbios_name_0;
+ uint32_t _ptr_dns_name;
+ TALLOC_CTX *_mem_save_dns_name_0;
+ uint32_t _ptr_site_name;
+ TALLOC_CTX *_mem_save_site_name_0;
+ uint32_t _ptr_site_dn;
+ TALLOC_CTX *_mem_save_site_dn_0;
+ uint32_t _ptr_computer_dn;
+ TALLOC_CTX *_mem_save_computer_dn_0;
+ uint32_t _ptr_server_dn;
+ TALLOC_CTX *_mem_save_server_dn_0;
+ uint32_t _ptr_ntds_dn;
+ TALLOC_CTX *_mem_save_ntds_dn_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_netbios_name));
+ if (_ptr_netbios_name) {
+ NDR_PULL_ALLOC(ndr, r->netbios_name);
+ } else {
+ r->netbios_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dns_name));
+ if (_ptr_dns_name) {
+ NDR_PULL_ALLOC(ndr, r->dns_name);
+ } else {
+ r->dns_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_site_name));
+ if (_ptr_site_name) {
+ NDR_PULL_ALLOC(ndr, r->site_name);
+ } else {
+ r->site_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_site_dn));
+ if (_ptr_site_dn) {
+ NDR_PULL_ALLOC(ndr, r->site_dn);
+ } else {
+ r->site_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_computer_dn));
+ if (_ptr_computer_dn) {
+ NDR_PULL_ALLOC(ndr, r->computer_dn);
+ } else {
+ r->computer_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_dn));
+ if (_ptr_server_dn) {
+ NDR_PULL_ALLOC(ndr, r->server_dn);
+ } else {
+ r->server_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ntds_dn));
+ if (_ptr_ntds_dn) {
+ NDR_PULL_ALLOC(ndr, r->ntds_dn);
+ } else {
+ r->ntds_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->is_pdc));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->is_enabled));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->is_gc));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->site_guid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->computer_guid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->server_guid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->ntds_guid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->netbios_name) {
+ _mem_save_netbios_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->netbios_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->netbios_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->netbios_name));
+ if (ndr_get_array_length(ndr, &r->netbios_name) > ndr_get_array_size(ndr, &r->netbios_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->netbios_name), ndr_get_array_length(ndr, &r->netbios_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->netbios_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->netbios_name, ndr_get_array_length(ndr, &r->netbios_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_netbios_name_0, 0);
+ }
+ if (r->dns_name) {
+ _mem_save_dns_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->dns_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->dns_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->dns_name));
+ if (ndr_get_array_length(ndr, &r->dns_name) > ndr_get_array_size(ndr, &r->dns_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->dns_name), ndr_get_array_length(ndr, &r->dns_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->dns_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dns_name, ndr_get_array_length(ndr, &r->dns_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dns_name_0, 0);
+ }
+ if (r->site_name) {
+ _mem_save_site_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->site_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->site_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->site_name));
+ if (ndr_get_array_length(ndr, &r->site_name) > ndr_get_array_size(ndr, &r->site_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->site_name), ndr_get_array_length(ndr, &r->site_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->site_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->site_name, ndr_get_array_length(ndr, &r->site_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_site_name_0, 0);
+ }
+ if (r->site_dn) {
+ _mem_save_site_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->site_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->site_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->site_dn));
+ if (ndr_get_array_length(ndr, &r->site_dn) > ndr_get_array_size(ndr, &r->site_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->site_dn), ndr_get_array_length(ndr, &r->site_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->site_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->site_dn, ndr_get_array_length(ndr, &r->site_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_site_dn_0, 0);
+ }
+ if (r->computer_dn) {
+ _mem_save_computer_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->computer_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->computer_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->computer_dn));
+ if (ndr_get_array_length(ndr, &r->computer_dn) > ndr_get_array_size(ndr, &r->computer_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->computer_dn), ndr_get_array_length(ndr, &r->computer_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->computer_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->computer_dn, ndr_get_array_length(ndr, &r->computer_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_computer_dn_0, 0);
+ }
+ if (r->server_dn) {
+ _mem_save_server_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->server_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->server_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->server_dn));
+ if (ndr_get_array_length(ndr, &r->server_dn) > ndr_get_array_size(ndr, &r->server_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->server_dn), ndr_get_array_length(ndr, &r->server_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->server_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->server_dn, ndr_get_array_length(ndr, &r->server_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_dn_0, 0);
+ }
+ if (r->ntds_dn) {
+ _mem_save_ntds_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ntds_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->ntds_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->ntds_dn));
+ if (ndr_get_array_length(ndr, &r->ntds_dn) > ndr_get_array_size(ndr, &r->ntds_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->ntds_dn), ndr_get_array_length(ndr, &r->ntds_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->ntds_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->ntds_dn, ndr_get_array_length(ndr, &r->ntds_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ntds_dn_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetDCInfo2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCInfo2 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetDCInfo2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "netbios_name", r->netbios_name);
+ ndr->depth++;
+ if (r->netbios_name) {
+ ndr_print_string(ndr, "netbios_name", r->netbios_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "dns_name", r->dns_name);
+ ndr->depth++;
+ if (r->dns_name) {
+ ndr_print_string(ndr, "dns_name", r->dns_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "site_name", r->site_name);
+ ndr->depth++;
+ if (r->site_name) {
+ ndr_print_string(ndr, "site_name", r->site_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "site_dn", r->site_dn);
+ ndr->depth++;
+ if (r->site_dn) {
+ ndr_print_string(ndr, "site_dn", r->site_dn);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "computer_dn", r->computer_dn);
+ ndr->depth++;
+ if (r->computer_dn) {
+ ndr_print_string(ndr, "computer_dn", r->computer_dn);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "server_dn", r->server_dn);
+ ndr->depth++;
+ if (r->server_dn) {
+ ndr_print_string(ndr, "server_dn", r->server_dn);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ntds_dn", r->ntds_dn);
+ ndr->depth++;
+ if (r->ntds_dn) {
+ ndr_print_string(ndr, "ntds_dn", r->ntds_dn);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "is_pdc", r->is_pdc);
+ ndr_print_uint32(ndr, "is_enabled", r->is_enabled);
+ ndr_print_uint32(ndr, "is_gc", r->is_gc);
+ ndr_print_GUID(ndr, "site_guid", &r->site_guid);
+ ndr_print_GUID(ndr, "computer_guid", &r->computer_guid);
+ ndr_print_GUID(ndr, "server_guid", &r->server_guid);
+ ndr_print_GUID(ndr, "ntds_guid", &r->ntds_guid);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetDCInfoCtr2(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetDCInfoCtr2 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCInfo2(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCInfo2(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetDCInfoCtr2(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetDCInfoCtr2 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCInfo2(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCInfo2(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetDCInfoCtr2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCInfoCtr2 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsGetDCInfoCtr2");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_drsuapi_DsGetDCInfo2(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetDCInfo3(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetDCInfo3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->netbios_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->dns_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->site_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->site_dn));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->computer_dn));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->server_dn));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ntds_dn));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->is_pdc));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->is_enabled));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->is_gc));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->is_rodc));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->site_guid));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->computer_guid));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->server_guid));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->ntds_guid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->netbios_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->netbios_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->netbios_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->netbios_name, ndr_charset_length(r->netbios_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->dns_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dns_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dns_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dns_name, ndr_charset_length(r->dns_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->site_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->site_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->site_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->site_name, ndr_charset_length(r->site_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->site_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->site_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->site_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->site_dn, ndr_charset_length(r->site_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->computer_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->computer_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->computer_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->computer_dn, ndr_charset_length(r->computer_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->server_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->server_dn, ndr_charset_length(r->server_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->ntds_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->ntds_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->ntds_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->ntds_dn, ndr_charset_length(r->ntds_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetDCInfo3(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetDCInfo3 *r)
+{
+ uint32_t _ptr_netbios_name;
+ TALLOC_CTX *_mem_save_netbios_name_0;
+ uint32_t _ptr_dns_name;
+ TALLOC_CTX *_mem_save_dns_name_0;
+ uint32_t _ptr_site_name;
+ TALLOC_CTX *_mem_save_site_name_0;
+ uint32_t _ptr_site_dn;
+ TALLOC_CTX *_mem_save_site_dn_0;
+ uint32_t _ptr_computer_dn;
+ TALLOC_CTX *_mem_save_computer_dn_0;
+ uint32_t _ptr_server_dn;
+ TALLOC_CTX *_mem_save_server_dn_0;
+ uint32_t _ptr_ntds_dn;
+ TALLOC_CTX *_mem_save_ntds_dn_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_netbios_name));
+ if (_ptr_netbios_name) {
+ NDR_PULL_ALLOC(ndr, r->netbios_name);
+ } else {
+ r->netbios_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dns_name));
+ if (_ptr_dns_name) {
+ NDR_PULL_ALLOC(ndr, r->dns_name);
+ } else {
+ r->dns_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_site_name));
+ if (_ptr_site_name) {
+ NDR_PULL_ALLOC(ndr, r->site_name);
+ } else {
+ r->site_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_site_dn));
+ if (_ptr_site_dn) {
+ NDR_PULL_ALLOC(ndr, r->site_dn);
+ } else {
+ r->site_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_computer_dn));
+ if (_ptr_computer_dn) {
+ NDR_PULL_ALLOC(ndr, r->computer_dn);
+ } else {
+ r->computer_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_dn));
+ if (_ptr_server_dn) {
+ NDR_PULL_ALLOC(ndr, r->server_dn);
+ } else {
+ r->server_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ntds_dn));
+ if (_ptr_ntds_dn) {
+ NDR_PULL_ALLOC(ndr, r->ntds_dn);
+ } else {
+ r->ntds_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->is_pdc));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->is_enabled));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->is_gc));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->is_rodc));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->site_guid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->computer_guid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->server_guid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->ntds_guid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->netbios_name) {
+ _mem_save_netbios_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->netbios_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->netbios_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->netbios_name));
+ if (ndr_get_array_length(ndr, &r->netbios_name) > ndr_get_array_size(ndr, &r->netbios_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->netbios_name), ndr_get_array_length(ndr, &r->netbios_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->netbios_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->netbios_name, ndr_get_array_length(ndr, &r->netbios_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_netbios_name_0, 0);
+ }
+ if (r->dns_name) {
+ _mem_save_dns_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->dns_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->dns_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->dns_name));
+ if (ndr_get_array_length(ndr, &r->dns_name) > ndr_get_array_size(ndr, &r->dns_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->dns_name), ndr_get_array_length(ndr, &r->dns_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->dns_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dns_name, ndr_get_array_length(ndr, &r->dns_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dns_name_0, 0);
+ }
+ if (r->site_name) {
+ _mem_save_site_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->site_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->site_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->site_name));
+ if (ndr_get_array_length(ndr, &r->site_name) > ndr_get_array_size(ndr, &r->site_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->site_name), ndr_get_array_length(ndr, &r->site_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->site_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->site_name, ndr_get_array_length(ndr, &r->site_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_site_name_0, 0);
+ }
+ if (r->site_dn) {
+ _mem_save_site_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->site_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->site_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->site_dn));
+ if (ndr_get_array_length(ndr, &r->site_dn) > ndr_get_array_size(ndr, &r->site_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->site_dn), ndr_get_array_length(ndr, &r->site_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->site_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->site_dn, ndr_get_array_length(ndr, &r->site_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_site_dn_0, 0);
+ }
+ if (r->computer_dn) {
+ _mem_save_computer_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->computer_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->computer_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->computer_dn));
+ if (ndr_get_array_length(ndr, &r->computer_dn) > ndr_get_array_size(ndr, &r->computer_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->computer_dn), ndr_get_array_length(ndr, &r->computer_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->computer_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->computer_dn, ndr_get_array_length(ndr, &r->computer_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_computer_dn_0, 0);
+ }
+ if (r->server_dn) {
+ _mem_save_server_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->server_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->server_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->server_dn));
+ if (ndr_get_array_length(ndr, &r->server_dn) > ndr_get_array_size(ndr, &r->server_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->server_dn), ndr_get_array_length(ndr, &r->server_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->server_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->server_dn, ndr_get_array_length(ndr, &r->server_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_dn_0, 0);
+ }
+ if (r->ntds_dn) {
+ _mem_save_ntds_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ntds_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->ntds_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->ntds_dn));
+ if (ndr_get_array_length(ndr, &r->ntds_dn) > ndr_get_array_size(ndr, &r->ntds_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->ntds_dn), ndr_get_array_length(ndr, &r->ntds_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->ntds_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->ntds_dn, ndr_get_array_length(ndr, &r->ntds_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ntds_dn_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetDCInfo3(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCInfo3 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetDCInfo3");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "netbios_name", r->netbios_name);
+ ndr->depth++;
+ if (r->netbios_name) {
+ ndr_print_string(ndr, "netbios_name", r->netbios_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "dns_name", r->dns_name);
+ ndr->depth++;
+ if (r->dns_name) {
+ ndr_print_string(ndr, "dns_name", r->dns_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "site_name", r->site_name);
+ ndr->depth++;
+ if (r->site_name) {
+ ndr_print_string(ndr, "site_name", r->site_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "site_dn", r->site_dn);
+ ndr->depth++;
+ if (r->site_dn) {
+ ndr_print_string(ndr, "site_dn", r->site_dn);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "computer_dn", r->computer_dn);
+ ndr->depth++;
+ if (r->computer_dn) {
+ ndr_print_string(ndr, "computer_dn", r->computer_dn);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "server_dn", r->server_dn);
+ ndr->depth++;
+ if (r->server_dn) {
+ ndr_print_string(ndr, "server_dn", r->server_dn);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ntds_dn", r->ntds_dn);
+ ndr->depth++;
+ if (r->ntds_dn) {
+ ndr_print_string(ndr, "ntds_dn", r->ntds_dn);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "is_pdc", r->is_pdc);
+ ndr_print_uint32(ndr, "is_enabled", r->is_enabled);
+ ndr_print_uint32(ndr, "is_gc", r->is_gc);
+ ndr_print_uint32(ndr, "is_rodc", r->is_rodc);
+ ndr_print_GUID(ndr, "site_guid", &r->site_guid);
+ ndr_print_GUID(ndr, "computer_guid", &r->computer_guid);
+ ndr_print_GUID(ndr, "server_guid", &r->server_guid);
+ ndr_print_GUID(ndr, "ntds_guid", &r->ntds_guid);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetDCInfoCtr3(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetDCInfoCtr3 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCInfo3(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCInfo3(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetDCInfoCtr3(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetDCInfoCtr3 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCInfo3(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCInfo3(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetDCInfoCtr3(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCInfoCtr3 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsGetDCInfoCtr3");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_drsuapi_DsGetDCInfo3(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetDCConnection01(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetDCConnection01 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_ipv4address = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
+ NDR_CHECK(ndr_push_ipv4address(ndr, NDR_SCALARS, r->client_ip_address));
+ ndr->flags = _flags_save_ipv4address;
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->connection_time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown5));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown6));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->client_account));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->client_account) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client_account, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client_account, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->client_account, ndr_charset_length(r->client_account, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetDCConnection01(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetDCConnection01 *r)
+{
+ uint32_t _ptr_client_account;
+ TALLOC_CTX *_mem_save_client_account_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_ipv4address = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
+ NDR_CHECK(ndr_pull_ipv4address(ndr, NDR_SCALARS, &r->client_ip_address));
+ ndr->flags = _flags_save_ipv4address;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->connection_time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown5));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown6));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_client_account));
+ if (_ptr_client_account) {
+ NDR_PULL_ALLOC(ndr, r->client_account);
+ } else {
+ r->client_account = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->client_account) {
+ _mem_save_client_account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->client_account, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->client_account));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->client_account));
+ if (ndr_get_array_length(ndr, &r->client_account) > ndr_get_array_size(ndr, &r->client_account)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->client_account), ndr_get_array_length(ndr, &r->client_account));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->client_account), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->client_account, ndr_get_array_length(ndr, &r->client_account), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_client_account_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetDCConnection01(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCConnection01 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetDCConnection01");
+ ndr->depth++;
+ ndr_print_ipv4address(ndr, "client_ip_address", r->client_ip_address);
+ ndr_print_uint32(ndr, "unknown2", r->unknown2);
+ ndr_print_uint32(ndr, "connection_time", r->connection_time);
+ ndr_print_uint32(ndr, "unknown4", r->unknown4);
+ ndr_print_uint32(ndr, "unknown5", r->unknown5);
+ ndr_print_uint32(ndr, "unknown6", r->unknown6);
+ ndr_print_ptr(ndr, "client_account", r->client_account);
+ ndr->depth++;
+ if (r->client_account) {
+ ndr_print_string(ndr, "client_account", r->client_account);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetDCConnectionCtr01(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetDCConnectionCtr01 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCConnection01(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCConnection01(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetDCConnectionCtr01(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetDCConnectionCtr01 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCConnection01(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCConnection01(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetDCConnectionCtr01(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCConnectionCtr01 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsGetDCConnectionCtr01");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_drsuapi_DsGetDCConnection01(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetDCInfoCtr(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsGetDCInfoCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case DRSUAPI_DC_INFO_CTR_1: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCInfoCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ case DRSUAPI_DC_INFO_CTR_2: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCInfoCtr2(ndr, NDR_SCALARS, &r->ctr2));
+ break; }
+
+ case DRSUAPI_DC_INFO_CTR_3: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCInfoCtr3(ndr, NDR_SCALARS, &r->ctr3));
+ break; }
+
+ case DRSUAPI_DC_CONNECTION_CTR_01: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCConnectionCtr01(ndr, NDR_SCALARS, &r->ctr01));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case DRSUAPI_DC_INFO_CTR_1:
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCInfoCtr1(ndr, NDR_BUFFERS, &r->ctr1));
+ break;
+
+ case DRSUAPI_DC_INFO_CTR_2:
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCInfoCtr2(ndr, NDR_BUFFERS, &r->ctr2));
+ break;
+
+ case DRSUAPI_DC_INFO_CTR_3:
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCInfoCtr3(ndr, NDR_BUFFERS, &r->ctr3));
+ break;
+
+ case DRSUAPI_DC_CONNECTION_CTR_01:
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCConnectionCtr01(ndr, NDR_BUFFERS, &r->ctr01));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetDCInfoCtr(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsGetDCInfoCtr *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case DRSUAPI_DC_INFO_CTR_1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCInfoCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ case DRSUAPI_DC_INFO_CTR_2: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCInfoCtr2(ndr, NDR_SCALARS, &r->ctr2));
+ break; }
+
+ case DRSUAPI_DC_INFO_CTR_3: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCInfoCtr3(ndr, NDR_SCALARS, &r->ctr3));
+ break; }
+
+ case DRSUAPI_DC_CONNECTION_CTR_01: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCConnectionCtr01(ndr, NDR_SCALARS, &r->ctr01));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case DRSUAPI_DC_INFO_CTR_1:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCInfoCtr1(ndr, NDR_BUFFERS, &r->ctr1));
+ break;
+
+ case DRSUAPI_DC_INFO_CTR_2:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCInfoCtr2(ndr, NDR_BUFFERS, &r->ctr2));
+ break;
+
+ case DRSUAPI_DC_INFO_CTR_3:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCInfoCtr3(ndr, NDR_BUFFERS, &r->ctr3));
+ break;
+
+ case DRSUAPI_DC_CONNECTION_CTR_01:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCConnectionCtr01(ndr, NDR_BUFFERS, &r->ctr01));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetDCInfoCtr(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetDCInfoCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsGetDCInfoCtr");
+ switch (level) {
+ case DRSUAPI_DC_INFO_CTR_1:
+ ndr_print_drsuapi_DsGetDCInfoCtr1(ndr, "ctr1", &r->ctr1);
+ break;
+
+ case DRSUAPI_DC_INFO_CTR_2:
+ ndr_print_drsuapi_DsGetDCInfoCtr2(ndr, "ctr2", &r->ctr2);
+ break;
+
+ case DRSUAPI_DC_INFO_CTR_3:
+ ndr_print_drsuapi_DsGetDCInfoCtr3(ndr, "ctr3", &r->ctr3);
+ break;
+
+ case DRSUAPI_DC_CONNECTION_CTR_01:
+ ndr_print_drsuapi_DsGetDCConnectionCtr01(ndr, "ctr01", &r->ctr01);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsReplicaObjectListItem(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObjectListItem *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->next_object));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObject(ndr, NDR_SCALARS, &r->object));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->next_object) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectListItem(ndr, NDR_SCALARS|NDR_BUFFERS, r->next_object));
+ }
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObject(ndr, NDR_BUFFERS, &r->object));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjectListItem(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObjectListItem *r)
+{
+ uint32_t _ptr_next_object;
+ TALLOC_CTX *_mem_save_next_object_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_next_object));
+ if (_ptr_next_object) {
+ NDR_PULL_ALLOC(ndr, r->next_object);
+ } else {
+ r->next_object = NULL;
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObject(ndr, NDR_SCALARS, &r->object));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->next_object) {
+ _mem_save_next_object_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->next_object, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectListItem(ndr, NDR_SCALARS|NDR_BUFFERS, r->next_object));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_next_object_0, 0);
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObject(ndr, NDR_BUFFERS, &r->object));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsAddEntryRequest2(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsAddEntryRequest2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectListItem(ndr, NDR_SCALARS, &r->first_object));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectListItem(ndr, NDR_BUFFERS, &r->first_object));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsAddEntryRequest2(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsAddEntryRequest2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectListItem(ndr, NDR_SCALARS, &r->first_object));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectListItem(ndr, NDR_BUFFERS, &r->first_object));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAddEntryRequest2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryRequest2 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsAddEntryRequest2");
+ ndr->depth++;
+ ndr_print_drsuapi_DsReplicaObjectListItem(ndr, "first_object", &r->first_object);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsAddEntryRequest(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsAddEntryRequest *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 2: {
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryRequest2(ndr, NDR_SCALARS, &r->req2));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 2:
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryRequest2(ndr, NDR_BUFFERS, &r->req2));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsAddEntryRequest(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsAddEntryRequest *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 2: {
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryRequest2(ndr, NDR_SCALARS, &r->req2));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 2:
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryRequest2(ndr, NDR_BUFFERS, &r->req2));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAddEntryRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsAddEntryRequest *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsAddEntryRequest");
+ switch (level) {
+ case 2:
+ ndr_print_drsuapi_DsAddEntryRequest2(ndr, "req2", &r->req2);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsAddEntryErrorInfoX(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsAddEntryErrorInfoX *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->status));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->unknown3));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsAddEntryErrorInfoX(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsAddEntryErrorInfoX *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->status));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->unknown3));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAddEntryErrorInfoX(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryErrorInfoX *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsAddEntryErrorInfoX");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "unknown1", r->unknown1);
+ ndr_print_WERROR(ndr, "status", r->status);
+ ndr_print_uint32(ndr, "unknown2", r->unknown2);
+ ndr_print_uint16(ndr, "unknown3", r->unknown3);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsAddEntryExtraErrorBuffer(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsAddEntryExtraErrorBuffer *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data, r->size));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsAddEntryExtraErrorBuffer(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsAddEntryExtraErrorBuffer *r)
+{
+ uint32_t _ptr_data;
+ TALLOC_CTX *_mem_save_data_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->size));
+ if (r->size < 0 || r->size > 10485760) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data));
+ if (_ptr_data) {
+ NDR_PULL_ALLOC(ndr, r->data);
+ } else {
+ r->data = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->data, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->data));
+ NDR_PULL_ALLOC_N(ndr, r->data, ndr_get_array_size(ndr, &r->data));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data, ndr_get_array_size(ndr, &r->data)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, 0);
+ }
+ if (r->data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->data, r->size));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAddEntryExtraErrorBuffer(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryExtraErrorBuffer *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsAddEntryExtraErrorBuffer");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "size", r->size);
+ ndr_print_ptr(ndr, "data", r->data);
+ ndr->depth++;
+ if (r->data) {
+ ndr_print_array_uint8(ndr, "data", r->data, r->size);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsAddEntryExtraError1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsAddEntryExtraError1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryErrorInfoX(ndr, NDR_SCALARS, &r->error));
+ NDR_CHECK(ndr_push_drsuapi_DsAttributeId(ndr, NDR_SCALARS, r->attid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown2));
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryExtraErrorBuffer(ndr, NDR_SCALARS, &r->buffer));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryExtraErrorBuffer(ndr, NDR_BUFFERS, &r->buffer));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsAddEntryExtraError1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsAddEntryExtraError1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryErrorInfoX(ndr, NDR_SCALARS, &r->error));
+ NDR_CHECK(ndr_pull_drsuapi_DsAttributeId(ndr, NDR_SCALARS, &r->attid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryExtraErrorBuffer(ndr, NDR_SCALARS, &r->buffer));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryExtraErrorBuffer(ndr, NDR_BUFFERS, &r->buffer));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAddEntryExtraError1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryExtraError1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsAddEntryExtraError1");
+ ndr->depth++;
+ ndr_print_drsuapi_DsAddEntryErrorInfoX(ndr, "error", &r->error);
+ ndr_print_drsuapi_DsAttributeId(ndr, "attid", r->attid);
+ ndr_print_uint32(ndr, "unknown2", r->unknown2);
+ ndr_print_drsuapi_DsAddEntryExtraErrorBuffer(ndr, "buffer", &r->buffer);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsAddEntryErrorListItem1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsAddEntryErrorListItem1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->next));
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryExtraError1(ndr, NDR_SCALARS, &r->error));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->next) {
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryErrorListItem1(ndr, NDR_SCALARS|NDR_BUFFERS, r->next));
+ }
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryExtraError1(ndr, NDR_BUFFERS, &r->error));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsAddEntryErrorListItem1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsAddEntryErrorListItem1 *r)
+{
+ uint32_t _ptr_next;
+ TALLOC_CTX *_mem_save_next_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_next));
+ if (_ptr_next) {
+ NDR_PULL_ALLOC(ndr, r->next);
+ } else {
+ r->next = NULL;
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryExtraError1(ndr, NDR_SCALARS, &r->error));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->next) {
+ _mem_save_next_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->next, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryErrorListItem1(ndr, NDR_SCALARS|NDR_BUFFERS, r->next));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_next_0, 0);
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryExtraError1(ndr, NDR_BUFFERS, &r->error));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAddEntryErrorListItem1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryErrorListItem1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsAddEntryErrorListItem1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "next", r->next);
+ ndr->depth++;
+ if (r->next) {
+ ndr_print_drsuapi_DsAddEntryErrorListItem1(ndr, "next", r->next);
+ }
+ ndr->depth--;
+ ndr_print_drsuapi_DsAddEntryExtraError1(ndr, "error", &r->error);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsAddEntryErrorInfo1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsAddEntryErrorInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->id));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->status));
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryErrorListItem1(ndr, NDR_SCALARS, &r->first));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->id) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->id));
+ }
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryErrorListItem1(ndr, NDR_BUFFERS, &r->first));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsAddEntryErrorInfo1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsAddEntryErrorInfo1 *r)
+{
+ uint32_t _ptr_id;
+ TALLOC_CTX *_mem_save_id_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_id));
+ if (_ptr_id) {
+ NDR_PULL_ALLOC(ndr, r->id);
+ } else {
+ r->id = NULL;
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->status));
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryErrorListItem1(ndr, NDR_SCALARS, &r->first));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->id) {
+ _mem_save_id_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->id, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->id));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_id_0, 0);
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryErrorListItem1(ndr, NDR_BUFFERS, &r->first));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAddEntryErrorInfo1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryErrorInfo1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsAddEntryErrorInfo1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "id", r->id);
+ ndr->depth++;
+ if (r->id) {
+ ndr_print_drsuapi_DsReplicaObjectIdentifier(ndr, "id", r->id);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "status", r->status);
+ ndr_print_drsuapi_DsAddEntryErrorListItem1(ndr, "first", &r->first);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsAddEntryErrorInfo(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsAddEntryErrorInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryErrorInfo1(ndr, NDR_SCALARS, &r->error1));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryErrorInfoX(ndr, NDR_SCALARS, &r->errorX));
+ break; }
+
+ case 5: {
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryErrorInfoX(ndr, NDR_SCALARS, &r->errorX));
+ break; }
+
+ case 6: {
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryErrorInfoX(ndr, NDR_SCALARS, &r->errorX));
+ break; }
+
+ case 7: {
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryErrorInfoX(ndr, NDR_SCALARS, &r->errorX));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryErrorInfo1(ndr, NDR_BUFFERS, &r->error1));
+ break;
+
+ case 4:
+ break;
+
+ case 5:
+ break;
+
+ case 6:
+ break;
+
+ case 7:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsAddEntryErrorInfo(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsAddEntryErrorInfo *r)
+{
+ int level;
+ uint32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryErrorInfo1(ndr, NDR_SCALARS, &r->error1));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryErrorInfoX(ndr, NDR_SCALARS, &r->errorX));
+ break; }
+
+ case 5: {
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryErrorInfoX(ndr, NDR_SCALARS, &r->errorX));
+ break; }
+
+ case 6: {
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryErrorInfoX(ndr, NDR_SCALARS, &r->errorX));
+ break; }
+
+ case 7: {
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryErrorInfoX(ndr, NDR_SCALARS, &r->errorX));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryErrorInfo1(ndr, NDR_BUFFERS, &r->error1));
+ break;
+
+ case 4:
+ break;
+
+ case 5:
+ break;
+
+ case 6:
+ break;
+
+ case 7:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAddEntryErrorInfo(struct ndr_print *ndr, const char *name, const union drsuapi_DsAddEntryErrorInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsAddEntryErrorInfo");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsAddEntryErrorInfo1(ndr, "error1", &r->error1);
+ break;
+
+ case 4:
+ ndr_print_drsuapi_DsAddEntryErrorInfoX(ndr, "errorX", &r->errorX);
+ break;
+
+ case 5:
+ ndr_print_drsuapi_DsAddEntryErrorInfoX(ndr, "errorX", &r->errorX);
+ break;
+
+ case 6:
+ ndr_print_drsuapi_DsAddEntryErrorInfoX(ndr, "errorX", &r->errorX);
+ break;
+
+ case 7:
+ ndr_print_drsuapi_DsAddEntryErrorInfoX(ndr, "errorX", &r->errorX);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsAddEntryError1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsAddEntryError1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->status));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->level));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->info) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->info, r->level));
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryErrorInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->info));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsAddEntryError1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsAddEntryError1 *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_info_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->status));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->level));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, r->info);
+ } else {
+ r->info = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->info) {
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info, 0);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->info, r->level));
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryErrorInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAddEntryError1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryError1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsAddEntryError1");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "status", r->status);
+ ndr_print_uint32(ndr, "level", r->level);
+ ndr_print_ptr(ndr, "info", r->info);
+ ndr->depth++;
+ if (r->info) {
+ ndr_print_set_switch_value(ndr, r->info, r->level);
+ ndr_print_drsuapi_DsAddEntryErrorInfo(ndr, "info", r->info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsAddEntryError(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsAddEntryError *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryError1(ndr, NDR_SCALARS, &r->info1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryError1(ndr, NDR_BUFFERS, &r->info1));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsAddEntryError(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsAddEntryError *r)
+{
+ int level;
+ uint32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryError1(ndr, NDR_SCALARS, &r->info1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryError1(ndr, NDR_BUFFERS, &r->info1));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAddEntryError(struct ndr_print *ndr, const char *name, const union drsuapi_DsAddEntryError *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsAddEntryError");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsAddEntryError1(ndr, "info1", &r->info1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaObjectIdentifier2(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObjectIdentifier2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->guid));
+ NDR_CHECK(ndr_push_dom_sid28(ndr, NDR_SCALARS, &r->sid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_dom_sid28(ndr, NDR_BUFFERS, &r->sid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjectIdentifier2(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObjectIdentifier2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->guid));
+ NDR_CHECK(ndr_pull_dom_sid28(ndr, NDR_SCALARS, &r->sid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_dom_sid28(ndr, NDR_BUFFERS, &r->sid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaObjectIdentifier2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjectIdentifier2 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaObjectIdentifier2");
+ ndr->depth++;
+ ndr_print_GUID(ndr, "guid", &r->guid);
+ ndr_print_dom_sid28(ndr, "sid", &r->sid);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsAddEntryCtr2(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsAddEntryCtr2 *r)
+{
+ uint32_t cntr_objects_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->id));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryErrorInfoX(ndr, NDR_SCALARS, &r->error));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->objects));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->id) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->id));
+ }
+ if (r->objects) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_objects_1 = 0; cntr_objects_1 < r->count; cntr_objects_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier2(ndr, NDR_SCALARS, &r->objects[cntr_objects_1]));
+ }
+ for (cntr_objects_1 = 0; cntr_objects_1 < r->count; cntr_objects_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier2(ndr, NDR_BUFFERS, &r->objects[cntr_objects_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsAddEntryCtr2(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsAddEntryCtr2 *r)
+{
+ uint32_t _ptr_id;
+ TALLOC_CTX *_mem_save_id_0;
+ uint32_t _ptr_objects;
+ uint32_t cntr_objects_1;
+ TALLOC_CTX *_mem_save_objects_0;
+ TALLOC_CTX *_mem_save_objects_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_id));
+ if (_ptr_id) {
+ NDR_PULL_ALLOC(ndr, r->id);
+ } else {
+ r->id = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryErrorInfoX(ndr, NDR_SCALARS, &r->error));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_objects));
+ if (_ptr_objects) {
+ NDR_PULL_ALLOC(ndr, r->objects);
+ } else {
+ r->objects = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->id) {
+ _mem_save_id_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->id, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->id));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_id_0, 0);
+ }
+ if (r->objects) {
+ _mem_save_objects_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->objects, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->objects));
+ NDR_PULL_ALLOC_N(ndr, r->objects, ndr_get_array_size(ndr, &r->objects));
+ _mem_save_objects_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->objects, 0);
+ for (cntr_objects_1 = 0; cntr_objects_1 < r->count; cntr_objects_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier2(ndr, NDR_SCALARS, &r->objects[cntr_objects_1]));
+ }
+ for (cntr_objects_1 = 0; cntr_objects_1 < r->count; cntr_objects_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier2(ndr, NDR_BUFFERS, &r->objects[cntr_objects_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_objects_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_objects_0, 0);
+ }
+ if (r->objects) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->objects, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAddEntryCtr2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryCtr2 *r)
+{
+ uint32_t cntr_objects_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsAddEntryCtr2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "id", r->id);
+ ndr->depth++;
+ if (r->id) {
+ ndr_print_drsuapi_DsReplicaObjectIdentifier(ndr, "id", r->id);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown1", r->unknown1);
+ ndr_print_drsuapi_DsAddEntryErrorInfoX(ndr, "error", &r->error);
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "objects", r->objects);
+ ndr->depth++;
+ if (r->objects) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "objects", (int)r->count);
+ ndr->depth++;
+ for (cntr_objects_1=0;cntr_objects_1<r->count;cntr_objects_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_objects_1) != -1) {
+ ndr_print_drsuapi_DsReplicaObjectIdentifier2(ndr, "objects", &r->objects[cntr_objects_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsAddEntryCtr3(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsAddEntryCtr3 *r)
+{
+ uint32_t cntr_objects_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->id));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->level));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->error));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->objects));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->id) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->id));
+ }
+ if (r->error) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->error, r->level));
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryError(ndr, NDR_SCALARS|NDR_BUFFERS, r->error));
+ }
+ if (r->objects) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_objects_1 = 0; cntr_objects_1 < r->count; cntr_objects_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier2(ndr, NDR_SCALARS, &r->objects[cntr_objects_1]));
+ }
+ for (cntr_objects_1 = 0; cntr_objects_1 < r->count; cntr_objects_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjectIdentifier2(ndr, NDR_BUFFERS, &r->objects[cntr_objects_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsAddEntryCtr3(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsAddEntryCtr3 *r)
+{
+ uint32_t _ptr_id;
+ TALLOC_CTX *_mem_save_id_0;
+ uint32_t _ptr_error;
+ TALLOC_CTX *_mem_save_error_0;
+ uint32_t _ptr_objects;
+ uint32_t cntr_objects_1;
+ TALLOC_CTX *_mem_save_objects_0;
+ TALLOC_CTX *_mem_save_objects_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_id));
+ if (_ptr_id) {
+ NDR_PULL_ALLOC(ndr, r->id);
+ } else {
+ r->id = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->level));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_error));
+ if (_ptr_error) {
+ NDR_PULL_ALLOC(ndr, r->error);
+ } else {
+ r->error = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_objects));
+ if (_ptr_objects) {
+ NDR_PULL_ALLOC(ndr, r->objects);
+ } else {
+ r->objects = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->id) {
+ _mem_save_id_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->id, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier(ndr, NDR_SCALARS|NDR_BUFFERS, r->id));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_id_0, 0);
+ }
+ if (r->error) {
+ _mem_save_error_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->error, 0);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->error, r->level));
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryError(ndr, NDR_SCALARS|NDR_BUFFERS, r->error));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_error_0, 0);
+ }
+ if (r->objects) {
+ _mem_save_objects_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->objects, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->objects));
+ NDR_PULL_ALLOC_N(ndr, r->objects, ndr_get_array_size(ndr, &r->objects));
+ _mem_save_objects_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->objects, 0);
+ for (cntr_objects_1 = 0; cntr_objects_1 < r->count; cntr_objects_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier2(ndr, NDR_SCALARS, &r->objects[cntr_objects_1]));
+ }
+ for (cntr_objects_1 = 0; cntr_objects_1 < r->count; cntr_objects_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjectIdentifier2(ndr, NDR_BUFFERS, &r->objects[cntr_objects_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_objects_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_objects_0, 0);
+ }
+ if (r->objects) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->objects, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAddEntryCtr3(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryCtr3 *r)
+{
+ uint32_t cntr_objects_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsAddEntryCtr3");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "id", r->id);
+ ndr->depth++;
+ if (r->id) {
+ ndr_print_drsuapi_DsReplicaObjectIdentifier(ndr, "id", r->id);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->level);
+ ndr_print_ptr(ndr, "error", r->error);
+ ndr->depth++;
+ if (r->error) {
+ ndr_print_set_switch_value(ndr, r->error, r->level);
+ ndr_print_drsuapi_DsAddEntryError(ndr, "error", r->error);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "objects", r->objects);
+ ndr->depth++;
+ if (r->objects) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "objects", (int)r->count);
+ ndr->depth++;
+ for (cntr_objects_1=0;cntr_objects_1<r->count;cntr_objects_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_objects_1) != -1) {
+ ndr_print_drsuapi_DsReplicaObjectIdentifier2(ndr, "objects", &r->objects[cntr_objects_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsAddEntryCtr(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsAddEntryCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 2: {
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryCtr2(ndr, NDR_SCALARS, &r->ctr2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryCtr3(ndr, NDR_SCALARS, &r->ctr3));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 2:
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryCtr2(ndr, NDR_BUFFERS, &r->ctr2));
+ break;
+
+ case 3:
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryCtr3(ndr, NDR_BUFFERS, &r->ctr3));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsAddEntryCtr(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsAddEntryCtr *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 2: {
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryCtr2(ndr, NDR_SCALARS, &r->ctr2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryCtr3(ndr, NDR_SCALARS, &r->ctr3));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 2:
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryCtr2(ndr, NDR_BUFFERS, &r->ctr2));
+ break;
+
+ case 3:
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryCtr3(ndr, NDR_BUFFERS, &r->ctr3));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAddEntryCtr(struct ndr_print *ndr, const char *name, const union drsuapi_DsAddEntryCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsAddEntryCtr");
+ switch (level) {
+ case 2:
+ ndr_print_drsuapi_DsAddEntryCtr2(ndr, "ctr2", &r->ctr2);
+ break;
+
+ case 3:
+ ndr_print_drsuapi_DsAddEntryCtr3(ndr, "ctr3", &r->ctr3);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaGetInfoLevel(struct ndr_push *ndr, int ndr_flags, enum drsuapi_DsReplicaGetInfoLevel r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaGetInfoLevel(struct ndr_pull *ndr, int ndr_flags, enum drsuapi_DsReplicaGetInfoLevel *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaGetInfoLevel(struct ndr_print *ndr, const char *name, enum drsuapi_DsReplicaGetInfoLevel r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DRSUAPI_DS_REPLICA_GET_INFO: val = "DRSUAPI_DS_REPLICA_GET_INFO"; break;
+ case DRSUAPI_DS_REPLICA_GET_INFO2: val = "DRSUAPI_DS_REPLICA_GET_INFO2"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaInfoType(struct ndr_push *ndr, int ndr_flags, enum drsuapi_DsReplicaInfoType r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaInfoType(struct ndr_pull *ndr, int ndr_flags, enum drsuapi_DsReplicaInfoType *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaInfoType(struct ndr_print *ndr, const char *name, enum drsuapi_DsReplicaInfoType r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS: val = "DRSUAPI_DS_REPLICA_INFO_NEIGHBORS"; break;
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS: val = "DRSUAPI_DS_REPLICA_INFO_CURSORS"; break;
+ case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA: val = "DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA"; break;
+ case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES: val = "DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES"; break;
+ case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES: val = "DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES"; break;
+ case DRSUAPI_DS_REPLICA_INFO_PENDING_OPS: val = "DRSUAPI_DS_REPLICA_INFO_PENDING_OPS"; break;
+ case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA: val = "DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA"; break;
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS2: val = "DRSUAPI_DS_REPLICA_INFO_CURSORS2"; break;
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS3: val = "DRSUAPI_DS_REPLICA_INFO_CURSORS3"; break;
+ case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2: val = "DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2"; break;
+ case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2: val = "DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2"; break;
+ case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02: val = "DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02"; break;
+ case DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04: val = "DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04"; break;
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS05: val = "DRSUAPI_DS_REPLICA_INFO_CURSORS05"; break;
+ case DRSUAPI_DS_REPLICA_INFO_06: val = "DRSUAPI_DS_REPLICA_INFO_06"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaGetInfoRequest1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaGetInfoRequest1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaInfoType(ndr, NDR_SCALARS, r->info_type));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->object_dn));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->guid1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->object_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->object_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->object_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->object_dn, ndr_charset_length(r->object_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaGetInfoRequest1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaGetInfoRequest1 *r)
+{
+ uint32_t _ptr_object_dn;
+ TALLOC_CTX *_mem_save_object_dn_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaInfoType(ndr, NDR_SCALARS, &r->info_type));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_object_dn));
+ if (_ptr_object_dn) {
+ NDR_PULL_ALLOC(ndr, r->object_dn);
+ } else {
+ r->object_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->guid1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->object_dn) {
+ _mem_save_object_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->object_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->object_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->object_dn));
+ if (ndr_get_array_length(ndr, &r->object_dn) > ndr_get_array_size(ndr, &r->object_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->object_dn), ndr_get_array_length(ndr, &r->object_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->object_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->object_dn, ndr_get_array_length(ndr, &r->object_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_object_dn_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaGetInfoRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaGetInfoRequest1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaGetInfoRequest1");
+ ndr->depth++;
+ ndr_print_drsuapi_DsReplicaInfoType(ndr, "info_type", r->info_type);
+ ndr_print_ptr(ndr, "object_dn", r->object_dn);
+ ndr->depth++;
+ if (r->object_dn) {
+ ndr_print_string(ndr, "object_dn", r->object_dn);
+ }
+ ndr->depth--;
+ ndr_print_GUID(ndr, "guid1", &r->guid1);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaGetInfoRequest2(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaGetInfoRequest2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaInfoType(ndr, NDR_SCALARS, r->info_type));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->object_dn));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->guid1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->string1));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->string2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->object_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->object_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->object_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->object_dn, ndr_charset_length(r->object_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->string1) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->string1, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->string1, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->string1, ndr_charset_length(r->string1, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->string2) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->string2, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->string2, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->string2, ndr_charset_length(r->string2, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaGetInfoRequest2(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaGetInfoRequest2 *r)
+{
+ uint32_t _ptr_object_dn;
+ TALLOC_CTX *_mem_save_object_dn_0;
+ uint32_t _ptr_string1;
+ TALLOC_CTX *_mem_save_string1_0;
+ uint32_t _ptr_string2;
+ TALLOC_CTX *_mem_save_string2_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaInfoType(ndr, NDR_SCALARS, &r->info_type));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_object_dn));
+ if (_ptr_object_dn) {
+ NDR_PULL_ALLOC(ndr, r->object_dn);
+ } else {
+ r->object_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->guid1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_string1));
+ if (_ptr_string1) {
+ NDR_PULL_ALLOC(ndr, r->string1);
+ } else {
+ r->string1 = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_string2));
+ if (_ptr_string2) {
+ NDR_PULL_ALLOC(ndr, r->string2);
+ } else {
+ r->string2 = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->object_dn) {
+ _mem_save_object_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->object_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->object_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->object_dn));
+ if (ndr_get_array_length(ndr, &r->object_dn) > ndr_get_array_size(ndr, &r->object_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->object_dn), ndr_get_array_length(ndr, &r->object_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->object_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->object_dn, ndr_get_array_length(ndr, &r->object_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_object_dn_0, 0);
+ }
+ if (r->string1) {
+ _mem_save_string1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->string1, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->string1));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->string1));
+ if (ndr_get_array_length(ndr, &r->string1) > ndr_get_array_size(ndr, &r->string1)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->string1), ndr_get_array_length(ndr, &r->string1));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->string1), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->string1, ndr_get_array_length(ndr, &r->string1), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_string1_0, 0);
+ }
+ if (r->string2) {
+ _mem_save_string2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->string2, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->string2));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->string2));
+ if (ndr_get_array_length(ndr, &r->string2) > ndr_get_array_size(ndr, &r->string2)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->string2), ndr_get_array_length(ndr, &r->string2));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->string2), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->string2, ndr_get_array_length(ndr, &r->string2), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_string2_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaGetInfoRequest2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaGetInfoRequest2 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaGetInfoRequest2");
+ ndr->depth++;
+ ndr_print_drsuapi_DsReplicaInfoType(ndr, "info_type", r->info_type);
+ ndr_print_ptr(ndr, "object_dn", r->object_dn);
+ ndr->depth++;
+ if (r->object_dn) {
+ ndr_print_string(ndr, "object_dn", r->object_dn);
+ }
+ ndr->depth--;
+ ndr_print_GUID(ndr, "guid1", &r->guid1);
+ ndr_print_uint32(ndr, "unknown1", r->unknown1);
+ ndr_print_ptr(ndr, "string1", r->string1);
+ ndr->depth++;
+ if (r->string1) {
+ ndr_print_string(ndr, "string1", r->string1);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "string2", r->string2);
+ ndr->depth++;
+ if (r->string2) {
+ ndr_print_string(ndr, "string2", r->string2);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown2", r->unknown2);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaGetInfoRequest(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsReplicaGetInfoRequest *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaGetInfoLevel(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case DRSUAPI_DS_REPLICA_GET_INFO: {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaGetInfoRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_GET_INFO2: {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaGetInfoRequest2(ndr, NDR_SCALARS, &r->req2));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case DRSUAPI_DS_REPLICA_GET_INFO:
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaGetInfoRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ case DRSUAPI_DS_REPLICA_GET_INFO2:
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaGetInfoRequest2(ndr, NDR_BUFFERS, &r->req2));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaGetInfoRequest(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsReplicaGetInfoRequest *r)
+{
+ int level;
+ uint32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case DRSUAPI_DS_REPLICA_GET_INFO: {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaGetInfoRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_GET_INFO2: {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaGetInfoRequest2(ndr, NDR_SCALARS, &r->req2));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case DRSUAPI_DS_REPLICA_GET_INFO:
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaGetInfoRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ case DRSUAPI_DS_REPLICA_GET_INFO2:
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaGetInfoRequest2(ndr, NDR_BUFFERS, &r->req2));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaGetInfoRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsReplicaGetInfoRequest *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsReplicaGetInfoRequest");
+ switch (level) {
+ case DRSUAPI_DS_REPLICA_GET_INFO:
+ ndr_print_drsuapi_DsReplicaGetInfoRequest1(ndr, "req1", &r->req1);
+ break;
+
+ case DRSUAPI_DS_REPLICA_GET_INFO2:
+ ndr_print_drsuapi_DsReplicaGetInfoRequest2(ndr, "req2", &r->req2);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaNeighbour(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaNeighbour *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->naming_context_dn));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->source_dsa_obj_dn));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->source_dsa_address));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->transport_obj_dn));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaNeighbourFlags(ndr, NDR_SCALARS, r->replica_flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->naming_context_obj_guid));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->source_dsa_obj_guid));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->transport_obj_guid));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->tmp_highest_usn));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->highest_usn));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_success));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_attempt));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->result_last_attempt));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->consecutive_sync_failures));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->naming_context_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->naming_context_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->naming_context_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->naming_context_dn, ndr_charset_length(r->naming_context_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->source_dsa_obj_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->source_dsa_obj_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->source_dsa_obj_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->source_dsa_obj_dn, ndr_charset_length(r->source_dsa_obj_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->source_dsa_address) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->source_dsa_address, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->source_dsa_address, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->source_dsa_address, ndr_charset_length(r->source_dsa_address, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->transport_obj_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->transport_obj_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->transport_obj_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->transport_obj_dn, ndr_charset_length(r->transport_obj_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaNeighbour(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaNeighbour *r)
+{
+ uint32_t _ptr_naming_context_dn;
+ TALLOC_CTX *_mem_save_naming_context_dn_0;
+ uint32_t _ptr_source_dsa_obj_dn;
+ TALLOC_CTX *_mem_save_source_dsa_obj_dn_0;
+ uint32_t _ptr_source_dsa_address;
+ TALLOC_CTX *_mem_save_source_dsa_address_0;
+ uint32_t _ptr_transport_obj_dn;
+ TALLOC_CTX *_mem_save_transport_obj_dn_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_naming_context_dn));
+ if (_ptr_naming_context_dn) {
+ NDR_PULL_ALLOC(ndr, r->naming_context_dn);
+ } else {
+ r->naming_context_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_source_dsa_obj_dn));
+ if (_ptr_source_dsa_obj_dn) {
+ NDR_PULL_ALLOC(ndr, r->source_dsa_obj_dn);
+ } else {
+ r->source_dsa_obj_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_source_dsa_address));
+ if (_ptr_source_dsa_address) {
+ NDR_PULL_ALLOC(ndr, r->source_dsa_address);
+ } else {
+ r->source_dsa_address = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_transport_obj_dn));
+ if (_ptr_transport_obj_dn) {
+ NDR_PULL_ALLOC(ndr, r->transport_obj_dn);
+ } else {
+ r->transport_obj_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaNeighbourFlags(ndr, NDR_SCALARS, &r->replica_flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->naming_context_obj_guid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->source_dsa_obj_guid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->transport_obj_guid));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->tmp_highest_usn));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->highest_usn));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_success));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_attempt));
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->result_last_attempt));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->consecutive_sync_failures));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->naming_context_dn) {
+ _mem_save_naming_context_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->naming_context_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->naming_context_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->naming_context_dn));
+ if (ndr_get_array_length(ndr, &r->naming_context_dn) > ndr_get_array_size(ndr, &r->naming_context_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->naming_context_dn), ndr_get_array_length(ndr, &r->naming_context_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->naming_context_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->naming_context_dn, ndr_get_array_length(ndr, &r->naming_context_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_naming_context_dn_0, 0);
+ }
+ if (r->source_dsa_obj_dn) {
+ _mem_save_source_dsa_obj_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->source_dsa_obj_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->source_dsa_obj_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->source_dsa_obj_dn));
+ if (ndr_get_array_length(ndr, &r->source_dsa_obj_dn) > ndr_get_array_size(ndr, &r->source_dsa_obj_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->source_dsa_obj_dn), ndr_get_array_length(ndr, &r->source_dsa_obj_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->source_dsa_obj_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->source_dsa_obj_dn, ndr_get_array_length(ndr, &r->source_dsa_obj_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_source_dsa_obj_dn_0, 0);
+ }
+ if (r->source_dsa_address) {
+ _mem_save_source_dsa_address_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->source_dsa_address, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->source_dsa_address));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->source_dsa_address));
+ if (ndr_get_array_length(ndr, &r->source_dsa_address) > ndr_get_array_size(ndr, &r->source_dsa_address)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->source_dsa_address), ndr_get_array_length(ndr, &r->source_dsa_address));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->source_dsa_address), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->source_dsa_address, ndr_get_array_length(ndr, &r->source_dsa_address), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_source_dsa_address_0, 0);
+ }
+ if (r->transport_obj_dn) {
+ _mem_save_transport_obj_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->transport_obj_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->transport_obj_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->transport_obj_dn));
+ if (ndr_get_array_length(ndr, &r->transport_obj_dn) > ndr_get_array_size(ndr, &r->transport_obj_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->transport_obj_dn), ndr_get_array_length(ndr, &r->transport_obj_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->transport_obj_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->transport_obj_dn, ndr_get_array_length(ndr, &r->transport_obj_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_transport_obj_dn_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaNeighbour(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaNeighbour *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaNeighbour");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "naming_context_dn", r->naming_context_dn);
+ ndr->depth++;
+ if (r->naming_context_dn) {
+ ndr_print_string(ndr, "naming_context_dn", r->naming_context_dn);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "source_dsa_obj_dn", r->source_dsa_obj_dn);
+ ndr->depth++;
+ if (r->source_dsa_obj_dn) {
+ ndr_print_string(ndr, "source_dsa_obj_dn", r->source_dsa_obj_dn);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "source_dsa_address", r->source_dsa_address);
+ ndr->depth++;
+ if (r->source_dsa_address) {
+ ndr_print_string(ndr, "source_dsa_address", r->source_dsa_address);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "transport_obj_dn", r->transport_obj_dn);
+ ndr->depth++;
+ if (r->transport_obj_dn) {
+ ndr_print_string(ndr, "transport_obj_dn", r->transport_obj_dn);
+ }
+ ndr->depth--;
+ ndr_print_drsuapi_DsReplicaNeighbourFlags(ndr, "replica_flags", r->replica_flags);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr_print_GUID(ndr, "naming_context_obj_guid", &r->naming_context_obj_guid);
+ ndr_print_GUID(ndr, "source_dsa_obj_guid", &r->source_dsa_obj_guid);
+ ndr_print_GUID(ndr, "source_dsa_invocation_id", &r->source_dsa_invocation_id);
+ ndr_print_GUID(ndr, "transport_obj_guid", &r->transport_obj_guid);
+ ndr_print_hyper(ndr, "tmp_highest_usn", r->tmp_highest_usn);
+ ndr_print_hyper(ndr, "highest_usn", r->highest_usn);
+ ndr_print_NTTIME(ndr, "last_success", r->last_success);
+ ndr_print_NTTIME(ndr, "last_attempt", r->last_attempt);
+ ndr_print_WERROR(ndr, "result_last_attempt", r->result_last_attempt);
+ ndr_print_uint32(ndr, "consecutive_sync_failures", r->consecutive_sync_failures);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaNeighbourCtr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaNeighbourCtr *r)
+{
+ uint32_t cntr_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaNeighbour(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaNeighbour(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaNeighbourCtr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaNeighbourCtr *r)
+{
+ uint32_t cntr_array_0;
+ TALLOC_CTX *_mem_save_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaNeighbour(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaNeighbour(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaNeighbourCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaNeighbourCtr *r)
+{
+ uint32_t cntr_array_0;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaNeighbourCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_0=0;cntr_array_0<r->count;cntr_array_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_array_0) != -1) {
+ ndr_print_drsuapi_DsReplicaNeighbour(ndr, "array", &r->array[cntr_array_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaCursorCtr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaCursorCtr *r)
+{
+ uint32_t cntr_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaCursor(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaCursorCtr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaCursorCtr *r)
+{
+ uint32_t cntr_array_0;
+ TALLOC_CTX *_mem_save_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaCursor(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaCursorCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaCursorCtr *r)
+{
+ uint32_t cntr_array_0;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaCursorCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_0=0;cntr_array_0<r->count;cntr_array_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_array_0) != -1) {
+ ndr_print_drsuapi_DsReplicaCursor(ndr, "array", &r->array[cntr_array_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaObjMetaData(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObjMetaData *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->attribute_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->originating_change_time));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->originating_invocation_id));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->originating_usn));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->local_usn));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->attribute_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->attribute_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->attribute_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->attribute_name, ndr_charset_length(r->attribute_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjMetaData(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObjMetaData *r)
+{
+ uint32_t _ptr_attribute_name;
+ TALLOC_CTX *_mem_save_attribute_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_attribute_name));
+ if (_ptr_attribute_name) {
+ NDR_PULL_ALLOC(ndr, r->attribute_name);
+ } else {
+ r->attribute_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->originating_change_time));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->originating_invocation_id));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->originating_usn));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->local_usn));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->attribute_name) {
+ _mem_save_attribute_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->attribute_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->attribute_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->attribute_name));
+ if (ndr_get_array_length(ndr, &r->attribute_name) > ndr_get_array_size(ndr, &r->attribute_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->attribute_name), ndr_get_array_length(ndr, &r->attribute_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->attribute_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->attribute_name, ndr_get_array_length(ndr, &r->attribute_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_attribute_name_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaObjMetaData(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjMetaData *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaObjMetaData");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "attribute_name", r->attribute_name);
+ ndr->depth++;
+ if (r->attribute_name) {
+ ndr_print_string(ndr, "attribute_name", r->attribute_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "version", r->version);
+ ndr_print_NTTIME(ndr, "originating_change_time", r->originating_change_time);
+ ndr_print_GUID(ndr, "originating_invocation_id", &r->originating_invocation_id);
+ ndr_print_hyper(ndr, "originating_usn", r->originating_usn);
+ ndr_print_hyper(ndr, "local_usn", r->local_usn);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaObjMetaDataCtr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObjMetaDataCtr *r)
+{
+ uint32_t cntr_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjMetaData(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjMetaData(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjMetaDataCtr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObjMetaDataCtr *r)
+{
+ uint32_t cntr_array_0;
+ TALLOC_CTX *_mem_save_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjMetaData(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjMetaData(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaObjMetaDataCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjMetaDataCtr *r)
+{
+ uint32_t cntr_array_0;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaObjMetaDataCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_0=0;cntr_array_0<r->count;cntr_array_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_array_0) != -1) {
+ ndr_print_drsuapi_DsReplicaObjMetaData(ndr, "array", &r->array[cntr_array_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaKccDsaFailure(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaKccDsaFailure *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->dsa_obj_dn));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->dsa_obj_guid));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->first_failure));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_failures));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->last_result));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->dsa_obj_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dsa_obj_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dsa_obj_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dsa_obj_dn, ndr_charset_length(r->dsa_obj_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaKccDsaFailure(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaKccDsaFailure *r)
+{
+ uint32_t _ptr_dsa_obj_dn;
+ TALLOC_CTX *_mem_save_dsa_obj_dn_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dsa_obj_dn));
+ if (_ptr_dsa_obj_dn) {
+ NDR_PULL_ALLOC(ndr, r->dsa_obj_dn);
+ } else {
+ r->dsa_obj_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->dsa_obj_guid));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->first_failure));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_failures));
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->last_result));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->dsa_obj_dn) {
+ _mem_save_dsa_obj_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->dsa_obj_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->dsa_obj_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->dsa_obj_dn));
+ if (ndr_get_array_length(ndr, &r->dsa_obj_dn) > ndr_get_array_size(ndr, &r->dsa_obj_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->dsa_obj_dn), ndr_get_array_length(ndr, &r->dsa_obj_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->dsa_obj_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dsa_obj_dn, ndr_get_array_length(ndr, &r->dsa_obj_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dsa_obj_dn_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaKccDsaFailure(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaKccDsaFailure *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaKccDsaFailure");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "dsa_obj_dn", r->dsa_obj_dn);
+ ndr->depth++;
+ if (r->dsa_obj_dn) {
+ ndr_print_string(ndr, "dsa_obj_dn", r->dsa_obj_dn);
+ }
+ ndr->depth--;
+ ndr_print_GUID(ndr, "dsa_obj_guid", &r->dsa_obj_guid);
+ ndr_print_NTTIME(ndr, "first_failure", r->first_failure);
+ ndr_print_uint32(ndr, "num_failures", r->num_failures);
+ ndr_print_WERROR(ndr, "last_result", r->last_result);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaKccDsaFailuresCtr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaKccDsaFailuresCtr *r)
+{
+ uint32_t cntr_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaKccDsaFailure(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaKccDsaFailure(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaKccDsaFailuresCtr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaKccDsaFailuresCtr *r)
+{
+ uint32_t cntr_array_0;
+ TALLOC_CTX *_mem_save_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaKccDsaFailure(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaKccDsaFailure(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaKccDsaFailuresCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaKccDsaFailuresCtr *r)
+{
+ uint32_t cntr_array_0;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaKccDsaFailuresCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_0=0;cntr_array_0<r->count;cntr_array_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_array_0) != -1) {
+ ndr_print_drsuapi_DsReplicaKccDsaFailure(ndr, "array", &r->array[cntr_array_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaOpType(struct ndr_push *ndr, int ndr_flags, enum drsuapi_DsReplicaOpType r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaOpType(struct ndr_pull *ndr, int ndr_flags, enum drsuapi_DsReplicaOpType *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaOpType(struct ndr_print *ndr, const char *name, enum drsuapi_DsReplicaOpType r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DRSUAPI_DS_REPLICA_OP_TYPE_SYNC: val = "DRSUAPI_DS_REPLICA_OP_TYPE_SYNC"; break;
+ case DRSUAPI_DS_REPLICA_OP_TYPE_ADD: val = "DRSUAPI_DS_REPLICA_OP_TYPE_ADD"; break;
+ case DRSUAPI_DS_REPLICA_OP_TYPE_DELETE: val = "DRSUAPI_DS_REPLICA_OP_TYPE_DELETE"; break;
+ case DRSUAPI_DS_REPLICA_OP_TYPE_MODIFY: val = "DRSUAPI_DS_REPLICA_OP_TYPE_MODIFY"; break;
+ case DRSUAPI_DS_REPLICA_OP_TYPE_UPDATE_REFS: val = "DRSUAPI_DS_REPLICA_OP_TYPE_UPDATE_REFS"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsRplicaOpOptions(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsRplicaOpOptions *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOpType(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case DRSUAPI_DS_REPLICA_OP_TYPE_SYNC: {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaSyncOptions(ndr, NDR_SCALARS, r->sync));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_ADD: {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaAddOptions(ndr, NDR_SCALARS, r->add));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_DELETE: {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaDeleteOptions(ndr, NDR_SCALARS, r->op_delete));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_MODIFY: {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaModifyOptions(ndr, NDR_SCALARS, r->modify));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_UPDATE_REFS: {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaUpdateRefsOptions(ndr, NDR_SCALARS, r->update_refs));
+ break; }
+
+ default: {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown));
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case DRSUAPI_DS_REPLICA_OP_TYPE_SYNC:
+ break;
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_ADD:
+ break;
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_DELETE:
+ break;
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_MODIFY:
+ break;
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_UPDATE_REFS:
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsRplicaOpOptions(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsRplicaOpOptions *r)
+{
+ int level;
+ uint16_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case DRSUAPI_DS_REPLICA_OP_TYPE_SYNC: {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaSyncOptions(ndr, NDR_SCALARS, &r->sync));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_ADD: {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaAddOptions(ndr, NDR_SCALARS, &r->add));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_DELETE: {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaDeleteOptions(ndr, NDR_SCALARS, &r->op_delete));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_MODIFY: {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaModifyOptions(ndr, NDR_SCALARS, &r->modify));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_UPDATE_REFS: {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaUpdateRefsOptions(ndr, NDR_SCALARS, &r->update_refs));
+ break; }
+
+ default: {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown));
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case DRSUAPI_DS_REPLICA_OP_TYPE_SYNC:
+ break;
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_ADD:
+ break;
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_DELETE:
+ break;
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_MODIFY:
+ break;
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_UPDATE_REFS:
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsRplicaOpOptions(struct ndr_print *ndr, const char *name, const union drsuapi_DsRplicaOpOptions *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsRplicaOpOptions");
+ switch (level) {
+ case DRSUAPI_DS_REPLICA_OP_TYPE_SYNC:
+ ndr_print_drsuapi_DsReplicaSyncOptions(ndr, "sync", r->sync);
+ break;
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_ADD:
+ ndr_print_drsuapi_DsReplicaAddOptions(ndr, "add", r->add);
+ break;
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_DELETE:
+ ndr_print_drsuapi_DsReplicaDeleteOptions(ndr, "op_delete", r->op_delete);
+ break;
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_MODIFY:
+ ndr_print_drsuapi_DsReplicaModifyOptions(ndr, "modify", r->modify);
+ break;
+
+ case DRSUAPI_DS_REPLICA_OP_TYPE_UPDATE_REFS:
+ ndr_print_drsuapi_DsReplicaUpdateRefsOptions(ndr, "update_refs", r->update_refs);
+ break;
+
+ default:
+ ndr_print_uint32(ndr, "unknown", r->unknown);
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaOp(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaOp *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->operation_start));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->serial_num));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->priority));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOpType(ndr, NDR_SCALARS, r->operation_type));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->options, r->operation_type));
+ NDR_CHECK(ndr_push_drsuapi_DsRplicaOpOptions(ndr, NDR_SCALARS, &r->options));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->nc_dn));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->remote_dsa_obj_dn));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->remote_dsa_address));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->nc_obj_guid));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->remote_dsa_obj_guid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->nc_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->nc_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->nc_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->nc_dn, ndr_charset_length(r->nc_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->remote_dsa_obj_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->remote_dsa_obj_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->remote_dsa_obj_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->remote_dsa_obj_dn, ndr_charset_length(r->remote_dsa_obj_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->remote_dsa_address) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->remote_dsa_address, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->remote_dsa_address, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->remote_dsa_address, ndr_charset_length(r->remote_dsa_address, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaOp(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaOp *r)
+{
+ uint32_t _ptr_nc_dn;
+ TALLOC_CTX *_mem_save_nc_dn_0;
+ uint32_t _ptr_remote_dsa_obj_dn;
+ TALLOC_CTX *_mem_save_remote_dsa_obj_dn_0;
+ uint32_t _ptr_remote_dsa_address;
+ TALLOC_CTX *_mem_save_remote_dsa_address_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->operation_start));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->serial_num));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->priority));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaOpType(ndr, NDR_SCALARS, &r->operation_type));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->options, r->operation_type));
+ NDR_CHECK(ndr_pull_drsuapi_DsRplicaOpOptions(ndr, NDR_SCALARS, &r->options));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_nc_dn));
+ if (_ptr_nc_dn) {
+ NDR_PULL_ALLOC(ndr, r->nc_dn);
+ } else {
+ r->nc_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_remote_dsa_obj_dn));
+ if (_ptr_remote_dsa_obj_dn) {
+ NDR_PULL_ALLOC(ndr, r->remote_dsa_obj_dn);
+ } else {
+ r->remote_dsa_obj_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_remote_dsa_address));
+ if (_ptr_remote_dsa_address) {
+ NDR_PULL_ALLOC(ndr, r->remote_dsa_address);
+ } else {
+ r->remote_dsa_address = NULL;
+ }
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->nc_obj_guid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->remote_dsa_obj_guid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->nc_dn) {
+ _mem_save_nc_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->nc_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->nc_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->nc_dn));
+ if (ndr_get_array_length(ndr, &r->nc_dn) > ndr_get_array_size(ndr, &r->nc_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->nc_dn), ndr_get_array_length(ndr, &r->nc_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->nc_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->nc_dn, ndr_get_array_length(ndr, &r->nc_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_nc_dn_0, 0);
+ }
+ if (r->remote_dsa_obj_dn) {
+ _mem_save_remote_dsa_obj_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->remote_dsa_obj_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->remote_dsa_obj_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->remote_dsa_obj_dn));
+ if (ndr_get_array_length(ndr, &r->remote_dsa_obj_dn) > ndr_get_array_size(ndr, &r->remote_dsa_obj_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->remote_dsa_obj_dn), ndr_get_array_length(ndr, &r->remote_dsa_obj_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->remote_dsa_obj_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->remote_dsa_obj_dn, ndr_get_array_length(ndr, &r->remote_dsa_obj_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_remote_dsa_obj_dn_0, 0);
+ }
+ if (r->remote_dsa_address) {
+ _mem_save_remote_dsa_address_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->remote_dsa_address, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->remote_dsa_address));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->remote_dsa_address));
+ if (ndr_get_array_length(ndr, &r->remote_dsa_address) > ndr_get_array_size(ndr, &r->remote_dsa_address)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->remote_dsa_address), ndr_get_array_length(ndr, &r->remote_dsa_address));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->remote_dsa_address), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->remote_dsa_address, ndr_get_array_length(ndr, &r->remote_dsa_address), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_remote_dsa_address_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaOp(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaOp *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaOp");
+ ndr->depth++;
+ ndr_print_NTTIME(ndr, "operation_start", r->operation_start);
+ ndr_print_uint32(ndr, "serial_num", r->serial_num);
+ ndr_print_uint32(ndr, "priority", r->priority);
+ ndr_print_drsuapi_DsReplicaOpType(ndr, "operation_type", r->operation_type);
+ ndr_print_set_switch_value(ndr, &r->options, r->operation_type);
+ ndr_print_drsuapi_DsRplicaOpOptions(ndr, "options", &r->options);
+ ndr_print_ptr(ndr, "nc_dn", r->nc_dn);
+ ndr->depth++;
+ if (r->nc_dn) {
+ ndr_print_string(ndr, "nc_dn", r->nc_dn);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "remote_dsa_obj_dn", r->remote_dsa_obj_dn);
+ ndr->depth++;
+ if (r->remote_dsa_obj_dn) {
+ ndr_print_string(ndr, "remote_dsa_obj_dn", r->remote_dsa_obj_dn);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "remote_dsa_address", r->remote_dsa_address);
+ ndr->depth++;
+ if (r->remote_dsa_address) {
+ ndr_print_string(ndr, "remote_dsa_address", r->remote_dsa_address);
+ }
+ ndr->depth--;
+ ndr_print_GUID(ndr, "nc_obj_guid", &r->nc_obj_guid);
+ ndr_print_GUID(ndr, "remote_dsa_obj_guid", &r->remote_dsa_obj_guid);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaOpCtr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaOpCtr *r)
+{
+ uint32_t cntr_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOp(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOp(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaOpCtr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaOpCtr *r)
+{
+ uint32_t cntr_array_0;
+ TALLOC_CTX *_mem_save_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaOp(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaOp(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaOpCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaOpCtr *r)
+{
+ uint32_t cntr_array_0;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaOpCtr");
+ ndr->depth++;
+ ndr_print_NTTIME(ndr, "time", r->time);
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_0=0;cntr_array_0<r->count;cntr_array_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_array_0) != -1) {
+ ndr_print_drsuapi_DsReplicaOp(ndr, "array", &r->array[cntr_array_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaAttrValMetaData(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaAttrValMetaData *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->attribute_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->object_dn));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_DATA_BLOB(0, r->binary, 0)));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->binary));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->deleted));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->created));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->originating_change_time));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->originating_invocation_id));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->originating_usn));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->local_usn));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->attribute_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->attribute_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->attribute_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->attribute_name, ndr_charset_length(r->attribute_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->object_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->object_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->object_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->object_dn, ndr_charset_length(r->object_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->binary) {
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, *r->binary));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaAttrValMetaData(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaAttrValMetaData *r)
+{
+ uint32_t _ptr_attribute_name;
+ TALLOC_CTX *_mem_save_attribute_name_0;
+ uint32_t _ptr_object_dn;
+ TALLOC_CTX *_mem_save_object_dn_0;
+ uint32_t _ptr_binary;
+ TALLOC_CTX *_mem_save_binary_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_attribute_name));
+ if (_ptr_attribute_name) {
+ NDR_PULL_ALLOC(ndr, r->attribute_name);
+ } else {
+ r->attribute_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_object_dn));
+ if (_ptr_object_dn) {
+ NDR_PULL_ALLOC(ndr, r->object_dn);
+ } else {
+ r->object_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size_binary));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_binary));
+ if (_ptr_binary) {
+ NDR_PULL_ALLOC(ndr, r->binary);
+ } else {
+ r->binary = NULL;
+ }
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->deleted));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->created));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->originating_change_time));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->originating_invocation_id));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->originating_usn));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->local_usn));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->attribute_name) {
+ _mem_save_attribute_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->attribute_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->attribute_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->attribute_name));
+ if (ndr_get_array_length(ndr, &r->attribute_name) > ndr_get_array_size(ndr, &r->attribute_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->attribute_name), ndr_get_array_length(ndr, &r->attribute_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->attribute_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->attribute_name, ndr_get_array_length(ndr, &r->attribute_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_attribute_name_0, 0);
+ }
+ if (r->object_dn) {
+ _mem_save_object_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->object_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->object_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->object_dn));
+ if (ndr_get_array_length(ndr, &r->object_dn) > ndr_get_array_size(ndr, &r->object_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->object_dn), ndr_get_array_length(ndr, &r->object_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->object_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->object_dn, ndr_get_array_length(ndr, &r->object_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_object_dn_0, 0);
+ }
+ if (r->binary) {
+ _mem_save_binary_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->binary, 0);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, r->binary));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_binary_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaAttrValMetaData(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaAttrValMetaData *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaAttrValMetaData");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "attribute_name", r->attribute_name);
+ ndr->depth++;
+ if (r->attribute_name) {
+ ndr_print_string(ndr, "attribute_name", r->attribute_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "object_dn", r->object_dn);
+ ndr->depth++;
+ if (r->object_dn) {
+ ndr_print_string(ndr, "object_dn", r->object_dn);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "__ndr_size_binary", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_DATA_BLOB(0, r->binary, 0):r->__ndr_size_binary);
+ ndr_print_ptr(ndr, "binary", r->binary);
+ ndr->depth++;
+ if (r->binary) {
+ ndr_print_DATA_BLOB(ndr, "binary", *r->binary);
+ }
+ ndr->depth--;
+ ndr_print_NTTIME(ndr, "deleted", r->deleted);
+ ndr_print_NTTIME(ndr, "created", r->created);
+ ndr_print_uint32(ndr, "version", r->version);
+ ndr_print_NTTIME(ndr, "originating_change_time", r->originating_change_time);
+ ndr_print_GUID(ndr, "originating_invocation_id", &r->originating_invocation_id);
+ ndr_print_hyper(ndr, "originating_usn", r->originating_usn);
+ ndr_print_hyper(ndr, "local_usn", r->local_usn);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaAttrValMetaDataCtr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaAttrValMetaDataCtr *r)
+{
+ uint32_t cntr_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->enumeration_context));
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaAttrValMetaData(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaAttrValMetaData(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaAttrValMetaDataCtr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaAttrValMetaDataCtr *r)
+{
+ uint32_t cntr_array_0;
+ TALLOC_CTX *_mem_save_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->enumeration_context));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaAttrValMetaData(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaAttrValMetaData(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaAttrValMetaDataCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaAttrValMetaDataCtr *r)
+{
+ uint32_t cntr_array_0;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaAttrValMetaDataCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_int32(ndr, "enumeration_context", r->enumeration_context);
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_0=0;cntr_array_0<r->count;cntr_array_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_array_0) != -1) {
+ ndr_print_drsuapi_DsReplicaAttrValMetaData(ndr, "array", &r->array[cntr_array_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaCursor2Ctr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaCursor2Ctr *r)
+{
+ uint32_t cntr_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->enumeration_context));
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaCursor2(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaCursor2Ctr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaCursor2Ctr *r)
+{
+ uint32_t cntr_array_0;
+ TALLOC_CTX *_mem_save_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->enumeration_context));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaCursor2(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaCursor2Ctr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaCursor2Ctr *r)
+{
+ uint32_t cntr_array_0;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaCursor2Ctr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_int32(ndr, "enumeration_context", r->enumeration_context);
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_0=0;cntr_array_0<r->count;cntr_array_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_array_0) != -1) {
+ ndr_print_drsuapi_DsReplicaCursor2(ndr, "array", &r->array[cntr_array_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaCursor3(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaCursor3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->highest_usn));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_sync_success));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->source_dsa_obj_dn));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->source_dsa_obj_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->source_dsa_obj_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->source_dsa_obj_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->source_dsa_obj_dn, ndr_charset_length(r->source_dsa_obj_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaCursor3(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaCursor3 *r)
+{
+ uint32_t _ptr_source_dsa_obj_dn;
+ TALLOC_CTX *_mem_save_source_dsa_obj_dn_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->source_dsa_invocation_id));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->highest_usn));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_sync_success));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_source_dsa_obj_dn));
+ if (_ptr_source_dsa_obj_dn) {
+ NDR_PULL_ALLOC(ndr, r->source_dsa_obj_dn);
+ } else {
+ r->source_dsa_obj_dn = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->source_dsa_obj_dn) {
+ _mem_save_source_dsa_obj_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->source_dsa_obj_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->source_dsa_obj_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->source_dsa_obj_dn));
+ if (ndr_get_array_length(ndr, &r->source_dsa_obj_dn) > ndr_get_array_size(ndr, &r->source_dsa_obj_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->source_dsa_obj_dn), ndr_get_array_length(ndr, &r->source_dsa_obj_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->source_dsa_obj_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->source_dsa_obj_dn, ndr_get_array_length(ndr, &r->source_dsa_obj_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_source_dsa_obj_dn_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaCursor3(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaCursor3 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaCursor3");
+ ndr->depth++;
+ ndr_print_GUID(ndr, "source_dsa_invocation_id", &r->source_dsa_invocation_id);
+ ndr_print_hyper(ndr, "highest_usn", r->highest_usn);
+ ndr_print_NTTIME(ndr, "last_sync_success", r->last_sync_success);
+ ndr_print_ptr(ndr, "source_dsa_obj_dn", r->source_dsa_obj_dn);
+ ndr->depth++;
+ if (r->source_dsa_obj_dn) {
+ ndr_print_string(ndr, "source_dsa_obj_dn", r->source_dsa_obj_dn);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaCursor3Ctr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaCursor3Ctr *r)
+{
+ uint32_t cntr_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->enumeration_context));
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaCursor3(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaCursor3(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaCursor3Ctr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaCursor3Ctr *r)
+{
+ uint32_t cntr_array_0;
+ TALLOC_CTX *_mem_save_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->enumeration_context));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaCursor3(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaCursor3(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaCursor3Ctr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaCursor3Ctr *r)
+{
+ uint32_t cntr_array_0;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaCursor3Ctr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_int32(ndr, "enumeration_context", r->enumeration_context);
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_0=0;cntr_array_0<r->count;cntr_array_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_array_0) != -1) {
+ ndr_print_drsuapi_DsReplicaCursor3(ndr, "array", &r->array[cntr_array_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaObjMetaData2(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObjMetaData2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->attribute_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->originating_change_time));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->originating_invocation_id));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->originating_usn));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->local_usn));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->originating_dsa_dn));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->attribute_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->attribute_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->attribute_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->attribute_name, ndr_charset_length(r->attribute_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->originating_dsa_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->originating_dsa_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->originating_dsa_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->originating_dsa_dn, ndr_charset_length(r->originating_dsa_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjMetaData2(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObjMetaData2 *r)
+{
+ uint32_t _ptr_attribute_name;
+ TALLOC_CTX *_mem_save_attribute_name_0;
+ uint32_t _ptr_originating_dsa_dn;
+ TALLOC_CTX *_mem_save_originating_dsa_dn_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_attribute_name));
+ if (_ptr_attribute_name) {
+ NDR_PULL_ALLOC(ndr, r->attribute_name);
+ } else {
+ r->attribute_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->originating_change_time));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->originating_invocation_id));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->originating_usn));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->local_usn));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_originating_dsa_dn));
+ if (_ptr_originating_dsa_dn) {
+ NDR_PULL_ALLOC(ndr, r->originating_dsa_dn);
+ } else {
+ r->originating_dsa_dn = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->attribute_name) {
+ _mem_save_attribute_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->attribute_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->attribute_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->attribute_name));
+ if (ndr_get_array_length(ndr, &r->attribute_name) > ndr_get_array_size(ndr, &r->attribute_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->attribute_name), ndr_get_array_length(ndr, &r->attribute_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->attribute_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->attribute_name, ndr_get_array_length(ndr, &r->attribute_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_attribute_name_0, 0);
+ }
+ if (r->originating_dsa_dn) {
+ _mem_save_originating_dsa_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->originating_dsa_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->originating_dsa_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->originating_dsa_dn));
+ if (ndr_get_array_length(ndr, &r->originating_dsa_dn) > ndr_get_array_size(ndr, &r->originating_dsa_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->originating_dsa_dn), ndr_get_array_length(ndr, &r->originating_dsa_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->originating_dsa_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->originating_dsa_dn, ndr_get_array_length(ndr, &r->originating_dsa_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_originating_dsa_dn_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaObjMetaData2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjMetaData2 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaObjMetaData2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "attribute_name", r->attribute_name);
+ ndr->depth++;
+ if (r->attribute_name) {
+ ndr_print_string(ndr, "attribute_name", r->attribute_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "version", r->version);
+ ndr_print_NTTIME(ndr, "originating_change_time", r->originating_change_time);
+ ndr_print_GUID(ndr, "originating_invocation_id", &r->originating_invocation_id);
+ ndr_print_hyper(ndr, "originating_usn", r->originating_usn);
+ ndr_print_hyper(ndr, "local_usn", r->local_usn);
+ ndr_print_ptr(ndr, "originating_dsa_dn", r->originating_dsa_dn);
+ ndr->depth++;
+ if (r->originating_dsa_dn) {
+ ndr_print_string(ndr, "originating_dsa_dn", r->originating_dsa_dn);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaObjMetaData2Ctr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObjMetaData2Ctr *r)
+{
+ uint32_t cntr_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->enumeration_context));
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjMetaData2(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjMetaData2(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjMetaData2Ctr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObjMetaData2Ctr *r)
+{
+ uint32_t cntr_array_0;
+ TALLOC_CTX *_mem_save_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->enumeration_context));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjMetaData2(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjMetaData2(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaObjMetaData2Ctr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjMetaData2Ctr *r)
+{
+ uint32_t cntr_array_0;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaObjMetaData2Ctr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_int32(ndr, "enumeration_context", r->enumeration_context);
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_0=0;cntr_array_0<r->count;cntr_array_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_array_0) != -1) {
+ ndr_print_drsuapi_DsReplicaObjMetaData2(ndr, "array", &r->array[cntr_array_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaAttrValMetaData2(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaAttrValMetaData2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->attribute_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->object_dn));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_DATA_BLOB(0, r->binary, 0)));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->binary));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->deleted));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->created));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->originating_change_time));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->originating_invocation_id));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->originating_usn));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->local_usn));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->originating_dsa_dn));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->attribute_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->attribute_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->attribute_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->attribute_name, ndr_charset_length(r->attribute_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->object_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->object_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->object_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->object_dn, ndr_charset_length(r->object_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->binary) {
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, *r->binary));
+ }
+ if (r->originating_dsa_dn) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->originating_dsa_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->originating_dsa_dn, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->originating_dsa_dn, ndr_charset_length(r->originating_dsa_dn, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaAttrValMetaData2(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaAttrValMetaData2 *r)
+{
+ uint32_t _ptr_attribute_name;
+ TALLOC_CTX *_mem_save_attribute_name_0;
+ uint32_t _ptr_object_dn;
+ TALLOC_CTX *_mem_save_object_dn_0;
+ uint32_t _ptr_binary;
+ TALLOC_CTX *_mem_save_binary_0;
+ uint32_t _ptr_originating_dsa_dn;
+ TALLOC_CTX *_mem_save_originating_dsa_dn_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_attribute_name));
+ if (_ptr_attribute_name) {
+ NDR_PULL_ALLOC(ndr, r->attribute_name);
+ } else {
+ r->attribute_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_object_dn));
+ if (_ptr_object_dn) {
+ NDR_PULL_ALLOC(ndr, r->object_dn);
+ } else {
+ r->object_dn = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size_binary));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_binary));
+ if (_ptr_binary) {
+ NDR_PULL_ALLOC(ndr, r->binary);
+ } else {
+ r->binary = NULL;
+ }
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->deleted));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->created));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->originating_change_time));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->originating_invocation_id));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->originating_usn));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->local_usn));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_originating_dsa_dn));
+ if (_ptr_originating_dsa_dn) {
+ NDR_PULL_ALLOC(ndr, r->originating_dsa_dn);
+ } else {
+ r->originating_dsa_dn = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->attribute_name) {
+ _mem_save_attribute_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->attribute_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->attribute_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->attribute_name));
+ if (ndr_get_array_length(ndr, &r->attribute_name) > ndr_get_array_size(ndr, &r->attribute_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->attribute_name), ndr_get_array_length(ndr, &r->attribute_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->attribute_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->attribute_name, ndr_get_array_length(ndr, &r->attribute_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_attribute_name_0, 0);
+ }
+ if (r->object_dn) {
+ _mem_save_object_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->object_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->object_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->object_dn));
+ if (ndr_get_array_length(ndr, &r->object_dn) > ndr_get_array_size(ndr, &r->object_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->object_dn), ndr_get_array_length(ndr, &r->object_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->object_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->object_dn, ndr_get_array_length(ndr, &r->object_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_object_dn_0, 0);
+ }
+ if (r->binary) {
+ _mem_save_binary_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->binary, 0);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, r->binary));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_binary_0, 0);
+ }
+ if (r->originating_dsa_dn) {
+ _mem_save_originating_dsa_dn_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->originating_dsa_dn, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->originating_dsa_dn));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->originating_dsa_dn));
+ if (ndr_get_array_length(ndr, &r->originating_dsa_dn) > ndr_get_array_size(ndr, &r->originating_dsa_dn)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->originating_dsa_dn), ndr_get_array_length(ndr, &r->originating_dsa_dn));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->originating_dsa_dn), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->originating_dsa_dn, ndr_get_array_length(ndr, &r->originating_dsa_dn), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_originating_dsa_dn_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaAttrValMetaData2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaAttrValMetaData2 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaAttrValMetaData2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "attribute_name", r->attribute_name);
+ ndr->depth++;
+ if (r->attribute_name) {
+ ndr_print_string(ndr, "attribute_name", r->attribute_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "object_dn", r->object_dn);
+ ndr->depth++;
+ if (r->object_dn) {
+ ndr_print_string(ndr, "object_dn", r->object_dn);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "__ndr_size_binary", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_DATA_BLOB(0, r->binary, 0):r->__ndr_size_binary);
+ ndr_print_ptr(ndr, "binary", r->binary);
+ ndr->depth++;
+ if (r->binary) {
+ ndr_print_DATA_BLOB(ndr, "binary", *r->binary);
+ }
+ ndr->depth--;
+ ndr_print_NTTIME(ndr, "deleted", r->deleted);
+ ndr_print_NTTIME(ndr, "created", r->created);
+ ndr_print_uint32(ndr, "version", r->version);
+ ndr_print_NTTIME(ndr, "originating_change_time", r->originating_change_time);
+ ndr_print_GUID(ndr, "originating_invocation_id", &r->originating_invocation_id);
+ ndr_print_hyper(ndr, "originating_usn", r->originating_usn);
+ ndr_print_hyper(ndr, "local_usn", r->local_usn);
+ ndr_print_ptr(ndr, "originating_dsa_dn", r->originating_dsa_dn);
+ ndr->depth++;
+ if (r->originating_dsa_dn) {
+ ndr_print_string(ndr, "originating_dsa_dn", r->originating_dsa_dn);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaAttrValMetaData2Ctr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaAttrValMetaData2Ctr *r)
+{
+ uint32_t cntr_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->enumeration_context));
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaAttrValMetaData2(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaAttrValMetaData2(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaAttrValMetaData2Ctr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaAttrValMetaData2Ctr *r)
+{
+ uint32_t cntr_array_0;
+ TALLOC_CTX *_mem_save_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->enumeration_context));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaAttrValMetaData2(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaAttrValMetaData2(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaAttrValMetaData2Ctr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaAttrValMetaData2Ctr *r)
+{
+ uint32_t cntr_array_0;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaAttrValMetaData2Ctr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_int32(ndr, "enumeration_context", r->enumeration_context);
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_0=0;cntr_array_0<r->count;cntr_array_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_array_0) != -1) {
+ ndr_print_drsuapi_DsReplicaAttrValMetaData2(ndr, "array", &r->array[cntr_array_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaConnection04(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaConnection04 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->u1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->u2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->u3));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->bind_guid));
+ NDR_CHECK(ndr_push_NTTIME_1sec(ndr, NDR_SCALARS, r->bind_time));
+ {
+ uint32_t _flags_save_ipv4address = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
+ NDR_CHECK(ndr_push_ipv4address(ndr, NDR_SCALARS, r->client_ip_address));
+ ndr->flags = _flags_save_ipv4address;
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->u5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaConnection04(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaConnection04 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->u1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->u2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->u3));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->bind_guid));
+ NDR_CHECK(ndr_pull_NTTIME_1sec(ndr, NDR_SCALARS, &r->bind_time));
+ {
+ uint32_t _flags_save_ipv4address = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
+ NDR_CHECK(ndr_pull_ipv4address(ndr, NDR_SCALARS, &r->client_ip_address));
+ ndr->flags = _flags_save_ipv4address;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->u5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaConnection04(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaConnection04 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaConnection04");
+ ndr->depth++;
+ ndr_print_hyper(ndr, "u1", r->u1);
+ ndr_print_uint32(ndr, "u2", r->u2);
+ ndr_print_uint32(ndr, "u3", r->u3);
+ ndr_print_GUID(ndr, "bind_guid", &r->bind_guid);
+ ndr_print_NTTIME_1sec(ndr, "bind_time", r->bind_time);
+ ndr_print_ipv4address(ndr, "client_ip_address", r->client_ip_address);
+ ndr_print_uint32(ndr, "u5", r->u5);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaConnection04Ctr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaConnection04Ctr *r)
+{
+ uint32_t cntr_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaConnection04(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaConnection04Ctr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaConnection04Ctr *r)
+{
+ uint32_t cntr_array_0;
+ TALLOC_CTX *_mem_save_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaConnection04(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaConnection04Ctr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaConnection04Ctr *r)
+{
+ uint32_t cntr_array_0;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaConnection04Ctr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_0=0;cntr_array_0<r->count;cntr_array_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_array_0) != -1) {
+ ndr_print_drsuapi_DsReplicaConnection04(ndr, "array", &r->array[cntr_array_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplica06(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplica06 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->str1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->u1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->u2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->u3));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->u4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->u5));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->u6));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->u7));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->str1) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->str1, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->str1, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->str1, ndr_charset_length(r->str1, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplica06(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplica06 *r)
+{
+ uint32_t _ptr_str1;
+ TALLOC_CTX *_mem_save_str1_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_str1));
+ if (_ptr_str1) {
+ NDR_PULL_ALLOC(ndr, r->str1);
+ } else {
+ r->str1 = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->u1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->u2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->u3));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->u4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->u5));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->u6));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->u7));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->str1) {
+ _mem_save_str1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->str1, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->str1));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->str1));
+ if (ndr_get_array_length(ndr, &r->str1) > ndr_get_array_size(ndr, &r->str1)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->str1), ndr_get_array_length(ndr, &r->str1));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->str1), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->str1, ndr_get_array_length(ndr, &r->str1), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_str1_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplica06(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplica06 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplica06");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "str1", r->str1);
+ ndr->depth++;
+ if (r->str1) {
+ ndr_print_string(ndr, "str1", r->str1);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "u1", r->u1);
+ ndr_print_uint32(ndr, "u2", r->u2);
+ ndr_print_uint32(ndr, "u3", r->u3);
+ ndr_print_uint32(ndr, "u4", r->u4);
+ ndr_print_uint32(ndr, "u5", r->u5);
+ ndr_print_hyper(ndr, "u6", r->u6);
+ ndr_print_uint32(ndr, "u7", r->u7);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplica06Ctr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplica06Ctr *r)
+{
+ uint32_t cntr_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplica06(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplica06(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplica06Ctr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplica06Ctr *r)
+{
+ uint32_t cntr_array_0;
+ TALLOC_CTX *_mem_save_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 256) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplica06(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsReplica06(ndr, NDR_BUFFERS, &r->array[cntr_array_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplica06Ctr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplica06Ctr *r)
+{
+ uint32_t cntr_array_0;
+ ndr_print_struct(ndr, name, "drsuapi_DsReplica06Ctr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_0=0;cntr_array_0<r->count;cntr_array_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_array_0) != -1) {
+ ndr_print_drsuapi_DsReplica06(ndr, "array", &r->array[cntr_array_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaInfo(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsReplicaInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaInfoType(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->neighbours));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->cursors));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->objmetadata));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->connectfailures));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->linkfailures));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_PENDING_OPS: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->pendingops));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->attrvalmetadata));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->cursors2));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS3: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->cursors3));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->objmetadata2));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->attrvalmetadata2));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->neighbours02));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->connections04));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS05: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->cursors05));
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_06: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->i06));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS:
+ if (r->neighbours) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaNeighbourCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->neighbours));
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS:
+ if (r->cursors) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaCursorCtr(ndr, NDR_SCALARS, r->cursors));
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA:
+ if (r->objmetadata) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjMetaDataCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->objmetadata));
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES:
+ if (r->connectfailures) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaKccDsaFailuresCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->connectfailures));
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES:
+ if (r->linkfailures) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaKccDsaFailuresCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->linkfailures));
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_PENDING_OPS:
+ if (r->pendingops) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaOpCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->pendingops));
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA:
+ if (r->attrvalmetadata) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaAttrValMetaDataCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->attrvalmetadata));
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS2:
+ if (r->cursors2) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaCursor2Ctr(ndr, NDR_SCALARS, r->cursors2));
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS3:
+ if (r->cursors3) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaCursor3Ctr(ndr, NDR_SCALARS|NDR_BUFFERS, r->cursors3));
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2:
+ if (r->objmetadata2) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaObjMetaData2Ctr(ndr, NDR_SCALARS|NDR_BUFFERS, r->objmetadata2));
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2:
+ if (r->attrvalmetadata2) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaAttrValMetaData2Ctr(ndr, NDR_SCALARS|NDR_BUFFERS, r->attrvalmetadata2));
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02:
+ if (r->neighbours02) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaNeighbourCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->neighbours02));
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04:
+ if (r->connections04) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaConnection04Ctr(ndr, NDR_SCALARS, r->connections04));
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS05:
+ if (r->cursors05) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaCursorCtrEx(ndr, NDR_SCALARS, r->cursors05));
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_06:
+ if (r->i06) {
+ NDR_CHECK(ndr_push_drsuapi_DsReplica06Ctr(ndr, NDR_SCALARS|NDR_BUFFERS, r->i06));
+ }
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaInfo(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsReplicaInfo *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_neighbours_0;
+ TALLOC_CTX *_mem_save_cursors_0;
+ TALLOC_CTX *_mem_save_objmetadata_0;
+ TALLOC_CTX *_mem_save_connectfailures_0;
+ TALLOC_CTX *_mem_save_linkfailures_0;
+ TALLOC_CTX *_mem_save_pendingops_0;
+ TALLOC_CTX *_mem_save_attrvalmetadata_0;
+ TALLOC_CTX *_mem_save_cursors2_0;
+ TALLOC_CTX *_mem_save_cursors3_0;
+ TALLOC_CTX *_mem_save_objmetadata2_0;
+ TALLOC_CTX *_mem_save_attrvalmetadata2_0;
+ TALLOC_CTX *_mem_save_neighbours02_0;
+ TALLOC_CTX *_mem_save_connections04_0;
+ TALLOC_CTX *_mem_save_cursors05_0;
+ TALLOC_CTX *_mem_save_i06_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS: {
+ uint32_t _ptr_neighbours;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_neighbours));
+ if (_ptr_neighbours) {
+ NDR_PULL_ALLOC(ndr, r->neighbours);
+ } else {
+ r->neighbours = NULL;
+ }
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS: {
+ uint32_t _ptr_cursors;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_cursors));
+ if (_ptr_cursors) {
+ NDR_PULL_ALLOC(ndr, r->cursors);
+ } else {
+ r->cursors = NULL;
+ }
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA: {
+ uint32_t _ptr_objmetadata;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_objmetadata));
+ if (_ptr_objmetadata) {
+ NDR_PULL_ALLOC(ndr, r->objmetadata);
+ } else {
+ r->objmetadata = NULL;
+ }
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES: {
+ uint32_t _ptr_connectfailures;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_connectfailures));
+ if (_ptr_connectfailures) {
+ NDR_PULL_ALLOC(ndr, r->connectfailures);
+ } else {
+ r->connectfailures = NULL;
+ }
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES: {
+ uint32_t _ptr_linkfailures;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_linkfailures));
+ if (_ptr_linkfailures) {
+ NDR_PULL_ALLOC(ndr, r->linkfailures);
+ } else {
+ r->linkfailures = NULL;
+ }
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_PENDING_OPS: {
+ uint32_t _ptr_pendingops;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_pendingops));
+ if (_ptr_pendingops) {
+ NDR_PULL_ALLOC(ndr, r->pendingops);
+ } else {
+ r->pendingops = NULL;
+ }
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA: {
+ uint32_t _ptr_attrvalmetadata;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_attrvalmetadata));
+ if (_ptr_attrvalmetadata) {
+ NDR_PULL_ALLOC(ndr, r->attrvalmetadata);
+ } else {
+ r->attrvalmetadata = NULL;
+ }
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS2: {
+ uint32_t _ptr_cursors2;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_cursors2));
+ if (_ptr_cursors2) {
+ NDR_PULL_ALLOC(ndr, r->cursors2);
+ } else {
+ r->cursors2 = NULL;
+ }
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS3: {
+ uint32_t _ptr_cursors3;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_cursors3));
+ if (_ptr_cursors3) {
+ NDR_PULL_ALLOC(ndr, r->cursors3);
+ } else {
+ r->cursors3 = NULL;
+ }
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2: {
+ uint32_t _ptr_objmetadata2;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_objmetadata2));
+ if (_ptr_objmetadata2) {
+ NDR_PULL_ALLOC(ndr, r->objmetadata2);
+ } else {
+ r->objmetadata2 = NULL;
+ }
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2: {
+ uint32_t _ptr_attrvalmetadata2;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_attrvalmetadata2));
+ if (_ptr_attrvalmetadata2) {
+ NDR_PULL_ALLOC(ndr, r->attrvalmetadata2);
+ } else {
+ r->attrvalmetadata2 = NULL;
+ }
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02: {
+ uint32_t _ptr_neighbours02;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_neighbours02));
+ if (_ptr_neighbours02) {
+ NDR_PULL_ALLOC(ndr, r->neighbours02);
+ } else {
+ r->neighbours02 = NULL;
+ }
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04: {
+ uint32_t _ptr_connections04;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_connections04));
+ if (_ptr_connections04) {
+ NDR_PULL_ALLOC(ndr, r->connections04);
+ } else {
+ r->connections04 = NULL;
+ }
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS05: {
+ uint32_t _ptr_cursors05;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_cursors05));
+ if (_ptr_cursors05) {
+ NDR_PULL_ALLOC(ndr, r->cursors05);
+ } else {
+ r->cursors05 = NULL;
+ }
+ break; }
+
+ case DRSUAPI_DS_REPLICA_INFO_06: {
+ uint32_t _ptr_i06;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_i06));
+ if (_ptr_i06) {
+ NDR_PULL_ALLOC(ndr, r->i06);
+ } else {
+ r->i06 = NULL;
+ }
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS:
+ if (r->neighbours) {
+ _mem_save_neighbours_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->neighbours, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaNeighbourCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->neighbours));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_neighbours_0, 0);
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS:
+ if (r->cursors) {
+ _mem_save_cursors_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->cursors, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaCursorCtr(ndr, NDR_SCALARS, r->cursors));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cursors_0, 0);
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA:
+ if (r->objmetadata) {
+ _mem_save_objmetadata_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->objmetadata, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjMetaDataCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->objmetadata));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_objmetadata_0, 0);
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES:
+ if (r->connectfailures) {
+ _mem_save_connectfailures_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->connectfailures, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaKccDsaFailuresCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->connectfailures));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_connectfailures_0, 0);
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES:
+ if (r->linkfailures) {
+ _mem_save_linkfailures_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->linkfailures, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaKccDsaFailuresCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->linkfailures));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_linkfailures_0, 0);
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_PENDING_OPS:
+ if (r->pendingops) {
+ _mem_save_pendingops_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->pendingops, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaOpCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->pendingops));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_pendingops_0, 0);
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA:
+ if (r->attrvalmetadata) {
+ _mem_save_attrvalmetadata_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->attrvalmetadata, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaAttrValMetaDataCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->attrvalmetadata));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_attrvalmetadata_0, 0);
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS2:
+ if (r->cursors2) {
+ _mem_save_cursors2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->cursors2, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaCursor2Ctr(ndr, NDR_SCALARS, r->cursors2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cursors2_0, 0);
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS3:
+ if (r->cursors3) {
+ _mem_save_cursors3_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->cursors3, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaCursor3Ctr(ndr, NDR_SCALARS|NDR_BUFFERS, r->cursors3));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cursors3_0, 0);
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2:
+ if (r->objmetadata2) {
+ _mem_save_objmetadata2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->objmetadata2, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaObjMetaData2Ctr(ndr, NDR_SCALARS|NDR_BUFFERS, r->objmetadata2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_objmetadata2_0, 0);
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2:
+ if (r->attrvalmetadata2) {
+ _mem_save_attrvalmetadata2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->attrvalmetadata2, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaAttrValMetaData2Ctr(ndr, NDR_SCALARS|NDR_BUFFERS, r->attrvalmetadata2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_attrvalmetadata2_0, 0);
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02:
+ if (r->neighbours02) {
+ _mem_save_neighbours02_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->neighbours02, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaNeighbourCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->neighbours02));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_neighbours02_0, 0);
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04:
+ if (r->connections04) {
+ _mem_save_connections04_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->connections04, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaConnection04Ctr(ndr, NDR_SCALARS, r->connections04));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_connections04_0, 0);
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS05:
+ if (r->cursors05) {
+ _mem_save_cursors05_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->cursors05, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaCursorCtrEx(ndr, NDR_SCALARS, r->cursors05));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cursors05_0, 0);
+ }
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_06:
+ if (r->i06) {
+ _mem_save_i06_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->i06, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplica06Ctr(ndr, NDR_SCALARS|NDR_BUFFERS, r->i06));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_i06_0, 0);
+ }
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaInfo(struct ndr_print *ndr, const char *name, const union drsuapi_DsReplicaInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsReplicaInfo");
+ switch (level) {
+ case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS:
+ ndr_print_ptr(ndr, "neighbours", r->neighbours);
+ ndr->depth++;
+ if (r->neighbours) {
+ ndr_print_drsuapi_DsReplicaNeighbourCtr(ndr, "neighbours", r->neighbours);
+ }
+ ndr->depth--;
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS:
+ ndr_print_ptr(ndr, "cursors", r->cursors);
+ ndr->depth++;
+ if (r->cursors) {
+ ndr_print_drsuapi_DsReplicaCursorCtr(ndr, "cursors", r->cursors);
+ }
+ ndr->depth--;
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA:
+ ndr_print_ptr(ndr, "objmetadata", r->objmetadata);
+ ndr->depth++;
+ if (r->objmetadata) {
+ ndr_print_drsuapi_DsReplicaObjMetaDataCtr(ndr, "objmetadata", r->objmetadata);
+ }
+ ndr->depth--;
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES:
+ ndr_print_ptr(ndr, "connectfailures", r->connectfailures);
+ ndr->depth++;
+ if (r->connectfailures) {
+ ndr_print_drsuapi_DsReplicaKccDsaFailuresCtr(ndr, "connectfailures", r->connectfailures);
+ }
+ ndr->depth--;
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES:
+ ndr_print_ptr(ndr, "linkfailures", r->linkfailures);
+ ndr->depth++;
+ if (r->linkfailures) {
+ ndr_print_drsuapi_DsReplicaKccDsaFailuresCtr(ndr, "linkfailures", r->linkfailures);
+ }
+ ndr->depth--;
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_PENDING_OPS:
+ ndr_print_ptr(ndr, "pendingops", r->pendingops);
+ ndr->depth++;
+ if (r->pendingops) {
+ ndr_print_drsuapi_DsReplicaOpCtr(ndr, "pendingops", r->pendingops);
+ }
+ ndr->depth--;
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA:
+ ndr_print_ptr(ndr, "attrvalmetadata", r->attrvalmetadata);
+ ndr->depth++;
+ if (r->attrvalmetadata) {
+ ndr_print_drsuapi_DsReplicaAttrValMetaDataCtr(ndr, "attrvalmetadata", r->attrvalmetadata);
+ }
+ ndr->depth--;
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS2:
+ ndr_print_ptr(ndr, "cursors2", r->cursors2);
+ ndr->depth++;
+ if (r->cursors2) {
+ ndr_print_drsuapi_DsReplicaCursor2Ctr(ndr, "cursors2", r->cursors2);
+ }
+ ndr->depth--;
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS3:
+ ndr_print_ptr(ndr, "cursors3", r->cursors3);
+ ndr->depth++;
+ if (r->cursors3) {
+ ndr_print_drsuapi_DsReplicaCursor3Ctr(ndr, "cursors3", r->cursors3);
+ }
+ ndr->depth--;
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2:
+ ndr_print_ptr(ndr, "objmetadata2", r->objmetadata2);
+ ndr->depth++;
+ if (r->objmetadata2) {
+ ndr_print_drsuapi_DsReplicaObjMetaData2Ctr(ndr, "objmetadata2", r->objmetadata2);
+ }
+ ndr->depth--;
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2:
+ ndr_print_ptr(ndr, "attrvalmetadata2", r->attrvalmetadata2);
+ ndr->depth++;
+ if (r->attrvalmetadata2) {
+ ndr_print_drsuapi_DsReplicaAttrValMetaData2Ctr(ndr, "attrvalmetadata2", r->attrvalmetadata2);
+ }
+ ndr->depth--;
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02:
+ ndr_print_ptr(ndr, "neighbours02", r->neighbours02);
+ ndr->depth++;
+ if (r->neighbours02) {
+ ndr_print_drsuapi_DsReplicaNeighbourCtr(ndr, "neighbours02", r->neighbours02);
+ }
+ ndr->depth--;
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04:
+ ndr_print_ptr(ndr, "connections04", r->connections04);
+ ndr->depth++;
+ if (r->connections04) {
+ ndr_print_drsuapi_DsReplicaConnection04Ctr(ndr, "connections04", r->connections04);
+ }
+ ndr->depth--;
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_CURSORS05:
+ ndr_print_ptr(ndr, "cursors05", r->cursors05);
+ ndr->depth++;
+ if (r->cursors05) {
+ ndr_print_drsuapi_DsReplicaCursorCtrEx(ndr, "cursors05", r->cursors05);
+ }
+ ndr->depth--;
+ break;
+
+ case DRSUAPI_DS_REPLICA_INFO_06:
+ ndr_print_ptr(ndr, "i06", r->i06);
+ ndr->depth++;
+ if (r->i06) {
+ ndr_print_drsuapi_DsReplica06Ctr(ndr, "i06", r->i06);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetMemberships2Ctr(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsGetMemberships2Ctr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetMembershipsCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_DsGetMembershipsCtr1(ndr, NDR_BUFFERS, &r->ctr1));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetMemberships2Ctr(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsGetMemberships2Ctr *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetMembershipsCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetMembershipsCtr1(ndr, NDR_BUFFERS, &r->ctr1));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetMemberships2Ctr(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetMemberships2Ctr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsGetMemberships2Ctr");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsGetMembershipsCtr1(ndr, "ctr1", &r->ctr1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetMemberships2Request1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetMemberships2Request1 *r)
+{
+ uint32_t cntr_req_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_req));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->req_array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->req_array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_req));
+ for (cntr_req_array_1 = 0; cntr_req_array_1 < r->num_req; cntr_req_array_1++) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->req_array[cntr_req_array_1]));
+ }
+ for (cntr_req_array_1 = 0; cntr_req_array_1 < r->num_req; cntr_req_array_1++) {
+ if (r->req_array[cntr_req_array_1]) {
+ NDR_CHECK(ndr_push_drsuapi_DsGetMembershipsRequest1(ndr, NDR_SCALARS|NDR_BUFFERS, r->req_array[cntr_req_array_1]));
+ }
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetMemberships2Request1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetMemberships2Request1 *r)
+{
+ uint32_t _ptr_req_array;
+ uint32_t cntr_req_array_1;
+ TALLOC_CTX *_mem_save_req_array_0;
+ TALLOC_CTX *_mem_save_req_array_1;
+ TALLOC_CTX *_mem_save_req_array_2;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_req));
+ if (r->num_req < 1 || r->num_req > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_req_array));
+ if (_ptr_req_array) {
+ NDR_PULL_ALLOC(ndr, r->req_array);
+ } else {
+ r->req_array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->req_array) {
+ _mem_save_req_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->req_array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->req_array));
+ NDR_PULL_ALLOC_N(ndr, r->req_array, ndr_get_array_size(ndr, &r->req_array));
+ _mem_save_req_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->req_array, 0);
+ for (cntr_req_array_1 = 0; cntr_req_array_1 < r->num_req; cntr_req_array_1++) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_req_array));
+ if (_ptr_req_array) {
+ NDR_PULL_ALLOC(ndr, r->req_array[cntr_req_array_1]);
+ } else {
+ r->req_array[cntr_req_array_1] = NULL;
+ }
+ }
+ for (cntr_req_array_1 = 0; cntr_req_array_1 < r->num_req; cntr_req_array_1++) {
+ if (r->req_array[cntr_req_array_1]) {
+ _mem_save_req_array_2 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->req_array[cntr_req_array_1], 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsGetMembershipsRequest1(ndr, NDR_SCALARS|NDR_BUFFERS, r->req_array[cntr_req_array_1]));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_req_array_2, 0);
+ }
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_req_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_req_array_0, 0);
+ }
+ if (r->req_array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->req_array, r->num_req));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetMemberships2Request1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetMemberships2Request1 *r)
+{
+ uint32_t cntr_req_array_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsGetMemberships2Request1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_req", r->num_req);
+ ndr_print_ptr(ndr, "req_array", r->req_array);
+ ndr->depth++;
+ if (r->req_array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "req_array", (int)r->num_req);
+ ndr->depth++;
+ for (cntr_req_array_1=0;cntr_req_array_1<r->num_req;cntr_req_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_req_array_1) != -1) {
+ ndr_print_ptr(ndr, "req_array", r->req_array[cntr_req_array_1]);
+ ndr->depth++;
+ if (r->req_array[cntr_req_array_1]) {
+ ndr_print_drsuapi_DsGetMembershipsRequest1(ndr, "req_array", r->req_array[cntr_req_array_1]);
+ }
+ ndr->depth--;
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetMemberships2Request(struct ndr_push *ndr, int ndr_flags, const union drsuapi_DsGetMemberships2Request *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_DsGetMemberships2Request1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_DsGetMemberships2Request1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetMemberships2Request(struct ndr_pull *ndr, int ndr_flags, union drsuapi_DsGetMemberships2Request *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_DsGetMemberships2Request1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_DsGetMemberships2Request1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetMemberships2Request(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetMemberships2Request *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsGetMemberships2Request");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_DsGetMemberships2Request1(ndr, "req1", &r->req1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsSiteCostInfo(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsSiteCostInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->error_code));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->site_cost));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsSiteCostInfo(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsSiteCostInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->error_code));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->site_cost));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsSiteCostInfo(struct ndr_print *ndr, const char *name, const struct drsuapi_DsSiteCostInfo *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsSiteCostInfo");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "error_code", r->error_code);
+ ndr_print_uint32(ndr, "site_cost", r->site_cost);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_QuerySitesByCostCtr1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_QuerySitesByCostCtr1 *r)
+{
+ uint32_t cntr_info_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_info));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->info) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_info));
+ for (cntr_info_1 = 0; cntr_info_1 < r->num_info; cntr_info_1++) {
+ NDR_CHECK(ndr_push_drsuapi_DsSiteCostInfo(ndr, NDR_SCALARS, &r->info[cntr_info_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_QuerySitesByCostCtr1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_QuerySitesByCostCtr1 *r)
+{
+ uint32_t _ptr_info;
+ uint32_t cntr_info_1;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_info));
+ if (r->num_info < 0 || r->num_info > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, r->info);
+ } else {
+ r->info = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->info) {
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->info));
+ NDR_PULL_ALLOC_N(ndr, r->info, ndr_get_array_size(ndr, &r->info));
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info, 0);
+ for (cntr_info_1 = 0; cntr_info_1 < r->num_info; cntr_info_1++) {
+ NDR_CHECK(ndr_pull_drsuapi_DsSiteCostInfo(ndr, NDR_SCALARS, &r->info[cntr_info_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0);
+ }
+ if (r->info) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->info, r->num_info));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_QuerySitesByCostCtr1(struct ndr_print *ndr, const char *name, const struct drsuapi_QuerySitesByCostCtr1 *r)
+{
+ uint32_t cntr_info_1;
+ ndr_print_struct(ndr, name, "drsuapi_QuerySitesByCostCtr1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_info", r->num_info);
+ ndr_print_ptr(ndr, "info", r->info);
+ ndr->depth++;
+ if (r->info) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "info", (int)r->num_info);
+ ndr->depth++;
+ for (cntr_info_1=0;cntr_info_1<r->num_info;cntr_info_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_info_1) != -1) {
+ ndr_print_drsuapi_DsSiteCostInfo(ndr, "info", &r->info[cntr_info_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown", r->unknown);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_QuerySitesByCostCtr(struct ndr_push *ndr, int ndr_flags, const union drsuapi_QuerySitesByCostCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_QuerySitesByCostCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_QuerySitesByCostCtr1(ndr, NDR_BUFFERS, &r->ctr1));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_QuerySitesByCostCtr(struct ndr_pull *ndr, int ndr_flags, union drsuapi_QuerySitesByCostCtr *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_QuerySitesByCostCtr1(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_QuerySitesByCostCtr1(ndr, NDR_BUFFERS, &r->ctr1));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_QuerySitesByCostCtr(struct ndr_print *ndr, const char *name, const union drsuapi_QuerySitesByCostCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_QuerySitesByCostCtr");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_QuerySitesByCostCtr1(ndr, "ctr1", &r->ctr1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_drsuapi_QuerySitesByCostRequest1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_QuerySitesByCostRequest1 *r)
+{
+ uint32_t cntr_site_to_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->site_from));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_req));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->site_to));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->site_from) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->site_from, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->site_from, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->site_from, ndr_charset_length(r->site_from, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->site_to) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_req));
+ for (cntr_site_to_1 = 0; cntr_site_to_1 < r->num_req; cntr_site_to_1++) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->site_to[cntr_site_to_1]));
+ }
+ for (cntr_site_to_1 = 0; cntr_site_to_1 < r->num_req; cntr_site_to_1++) {
+ if (r->site_to[cntr_site_to_1]) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->site_to[cntr_site_to_1], CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->site_to[cntr_site_to_1], CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->site_to[cntr_site_to_1], ndr_charset_length(r->site_to[cntr_site_to_1], CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_QuerySitesByCostRequest1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_QuerySitesByCostRequest1 *r)
+{
+ uint32_t _ptr_site_from;
+ TALLOC_CTX *_mem_save_site_from_0;
+ uint32_t _ptr_site_to;
+ uint32_t cntr_site_to_1;
+ TALLOC_CTX *_mem_save_site_to_0;
+ TALLOC_CTX *_mem_save_site_to_1;
+ TALLOC_CTX *_mem_save_site_to_2;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_site_from));
+ if (_ptr_site_from) {
+ NDR_PULL_ALLOC(ndr, r->site_from);
+ } else {
+ r->site_from = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_req));
+ if (r->num_req < 1 || r->num_req > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_site_to));
+ if (_ptr_site_to) {
+ NDR_PULL_ALLOC(ndr, r->site_to);
+ } else {
+ r->site_to = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->site_from) {
+ _mem_save_site_from_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->site_from, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->site_from));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->site_from));
+ if (ndr_get_array_length(ndr, &r->site_from) > ndr_get_array_size(ndr, &r->site_from)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->site_from), ndr_get_array_length(ndr, &r->site_from));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->site_from), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->site_from, ndr_get_array_length(ndr, &r->site_from), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_site_from_0, 0);
+ }
+ if (r->site_to) {
+ _mem_save_site_to_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->site_to, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->site_to));
+ NDR_PULL_ALLOC_N(ndr, r->site_to, ndr_get_array_size(ndr, &r->site_to));
+ _mem_save_site_to_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->site_to, 0);
+ for (cntr_site_to_1 = 0; cntr_site_to_1 < r->num_req; cntr_site_to_1++) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_site_to));
+ if (_ptr_site_to) {
+ NDR_PULL_ALLOC(ndr, r->site_to[cntr_site_to_1]);
+ } else {
+ r->site_to[cntr_site_to_1] = NULL;
+ }
+ }
+ for (cntr_site_to_1 = 0; cntr_site_to_1 < r->num_req; cntr_site_to_1++) {
+ if (r->site_to[cntr_site_to_1]) {
+ _mem_save_site_to_2 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->site_to[cntr_site_to_1], 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->site_to[cntr_site_to_1]));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->site_to[cntr_site_to_1]));
+ if (ndr_get_array_length(ndr, &r->site_to[cntr_site_to_1]) > ndr_get_array_size(ndr, &r->site_to[cntr_site_to_1])) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->site_to[cntr_site_to_1]), ndr_get_array_length(ndr, &r->site_to[cntr_site_to_1]));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->site_to[cntr_site_to_1]), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->site_to[cntr_site_to_1], ndr_get_array_length(ndr, &r->site_to[cntr_site_to_1]), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_site_to_2, 0);
+ }
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_site_to_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_site_to_0, 0);
+ }
+ if (r->site_to) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->site_to, r->num_req));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_QuerySitesByCostRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_QuerySitesByCostRequest1 *r)
+{
+ uint32_t cntr_site_to_1;
+ ndr_print_struct(ndr, name, "drsuapi_QuerySitesByCostRequest1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "site_from", r->site_from);
+ ndr->depth++;
+ if (r->site_from) {
+ ndr_print_string(ndr, "site_from", r->site_from);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "num_req", r->num_req);
+ ndr_print_ptr(ndr, "site_to", r->site_to);
+ ndr->depth++;
+ if (r->site_to) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "site_to", (int)r->num_req);
+ ndr->depth++;
+ for (cntr_site_to_1=0;cntr_site_to_1<r->num_req;cntr_site_to_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_site_to_1) != -1) {
+ ndr_print_ptr(ndr, "site_to", r->site_to[cntr_site_to_1]);
+ ndr->depth++;
+ if (r->site_to[cntr_site_to_1]) {
+ ndr_print_string(ndr, "site_to", r->site_to[cntr_site_to_1]);
+ }
+ ndr->depth--;
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "flags", r->flags);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_QuerySitesByCostRequest(struct ndr_push *ndr, int ndr_flags, const union drsuapi_QuerySitesByCostRequest *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_drsuapi_QuerySitesByCostRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_drsuapi_QuerySitesByCostRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_QuerySitesByCostRequest(struct ndr_pull *ndr, int ndr_flags, union drsuapi_QuerySitesByCostRequest *r)
+{
+ int level;
+ int32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_drsuapi_QuerySitesByCostRequest1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_drsuapi_QuerySitesByCostRequest1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_QuerySitesByCostRequest(struct ndr_print *ndr, const char *name, const union drsuapi_QuerySitesByCostRequest *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_QuerySitesByCostRequest");
+ switch (level) {
+ case 1:
+ ndr_print_drsuapi_QuerySitesByCostRequest1(ndr, "req1", &r->req1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsBind(struct ndr_push *ndr, int flags, const struct drsuapi_DsBind *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.bind_guid));
+ if (r->in.bind_guid) {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, r->in.bind_guid));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.bind_info));
+ if (r->in.bind_info) {
+ NDR_CHECK(ndr_push_drsuapi_DsBindInfoCtr(ndr, NDR_SCALARS, r->in.bind_info));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.bind_info));
+ if (r->out.bind_info) {
+ NDR_CHECK(ndr_push_drsuapi_DsBindInfoCtr(ndr, NDR_SCALARS, r->out.bind_info));
+ }
+ if (r->out.bind_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.bind_handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsBind(struct ndr_pull *ndr, int flags, struct drsuapi_DsBind *r)
+{
+ uint32_t _ptr_bind_guid;
+ uint32_t _ptr_bind_info;
+ TALLOC_CTX *_mem_save_bind_guid_0;
+ TALLOC_CTX *_mem_save_bind_info_0;
+ TALLOC_CTX *_mem_save_bind_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_bind_guid));
+ if (_ptr_bind_guid) {
+ NDR_PULL_ALLOC(ndr, r->in.bind_guid);
+ } else {
+ r->in.bind_guid = NULL;
+ }
+ if (r->in.bind_guid) {
+ _mem_save_bind_guid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.bind_guid, 0);
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, r->in.bind_guid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_guid_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_bind_info));
+ if (_ptr_bind_info) {
+ NDR_PULL_ALLOC(ndr, r->in.bind_info);
+ } else {
+ r->in.bind_info = NULL;
+ }
+ if (r->in.bind_info) {
+ _mem_save_bind_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.bind_info, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsBindInfoCtr(ndr, NDR_SCALARS, r->in.bind_info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_info_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.bind_handle);
+ ZERO_STRUCTP(r->out.bind_handle);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_bind_info));
+ if (_ptr_bind_info) {
+ NDR_PULL_ALLOC(ndr, r->out.bind_info);
+ } else {
+ r->out.bind_info = NULL;
+ }
+ if (r->out.bind_info) {
+ _mem_save_bind_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.bind_info, 0);
+ NDR_CHECK(ndr_pull_drsuapi_DsBindInfoCtr(ndr, NDR_SCALARS, r->out.bind_info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_info_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.bind_handle);
+ }
+ _mem_save_bind_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.bind_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.bind_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsBind(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsBind *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsBind");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "drsuapi_DsBind");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_guid", r->in.bind_guid);
+ ndr->depth++;
+ if (r->in.bind_guid) {
+ ndr_print_GUID(ndr, "bind_guid", r->in.bind_guid);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "bind_info", r->in.bind_info);
+ ndr->depth++;
+ if (r->in.bind_info) {
+ ndr_print_drsuapi_DsBindInfoCtr(ndr, "bind_info", r->in.bind_info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "drsuapi_DsBind");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_info", r->out.bind_info);
+ ndr->depth++;
+ if (r->out.bind_info) {
+ ndr_print_drsuapi_DsBindInfoCtr(ndr, "bind_info", r->out.bind_info);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "bind_handle", r->out.bind_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "bind_handle", r->out.bind_handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsUnbind(struct ndr_push *ndr, int flags, const struct drsuapi_DsUnbind *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.bind_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.bind_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.bind_handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsUnbind(struct ndr_pull *ndr, int flags, struct drsuapi_DsUnbind *r)
+{
+ TALLOC_CTX *_mem_save_bind_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.bind_handle);
+ }
+ _mem_save_bind_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.bind_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.bind_handle);
+ *r->out.bind_handle = *r->in.bind_handle;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.bind_handle);
+ }
+ _mem_save_bind_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.bind_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.bind_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsUnbind(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsUnbind *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsUnbind");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "drsuapi_DsUnbind");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "drsuapi_DsUnbind");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_handle", r->out.bind_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "bind_handle", r->out.bind_handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaSync(struct ndr_push *ndr, int flags, const struct drsuapi_DsReplicaSync *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.bind_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->in.req, r->in.level));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaSyncRequest(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.req));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaSync(struct ndr_pull *ndr, int flags, struct drsuapi_DsReplicaSync *r)
+{
+ TALLOC_CTX *_mem_save_bind_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.bind_handle);
+ }
+ _mem_save_bind_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.bind_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->in.req, r->in.level));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaSyncRequest(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.req));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaSync(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsReplicaSync *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaSync");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "drsuapi_DsReplicaSync");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth--;
+ ndr_print_int32(ndr, "level", r->in.level);
+ ndr_print_set_switch_value(ndr, &r->in.req, r->in.level);
+ ndr_print_drsuapi_DsReplicaSyncRequest(ndr, "req", &r->in.req);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "drsuapi_DsReplicaSync");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNCChanges(struct ndr_push *ndr, int flags, const struct drsuapi_DsGetNCChanges *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.bind_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.req == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.level_out == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, *r->out.level_out));
+ if (r->out.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.ctr, *r->out.level_out));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNCChanges(struct ndr_pull *ndr, int flags, struct drsuapi_DsGetNCChanges *r)
+{
+ TALLOC_CTX *_mem_save_bind_handle_0;
+ TALLOC_CTX *_mem_save_req_0;
+ TALLOC_CTX *_mem_save_level_out_0;
+ TALLOC_CTX *_mem_save_ctr_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.bind_handle);
+ }
+ _mem_save_bind_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.bind_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.req);
+ }
+ _mem_save_req_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.req, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_req_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ ZERO_STRUCTP(r->out.level_out);
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ ZERO_STRUCTP(r->out.ctr);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ }
+ _mem_save_level_out_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.level_out, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, r->out.level_out));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_out_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.ctr, *r->out.level_out));
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNCChangesCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNCChanges(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsGetNCChanges *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetNCChanges");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "drsuapi_DsGetNCChanges");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth--;
+ ndr_print_int32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "req", r->in.req);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.req, r->in.level);
+ ndr_print_drsuapi_DsGetNCChangesRequest(ndr, "req", r->in.req);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "drsuapi_DsGetNCChanges");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "level_out", r->out.level_out);
+ ndr->depth++;
+ ndr_print_int32(ndr, "level_out", *r->out.level_out);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ctr", r->out.ctr);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.ctr, *r->out.level_out);
+ ndr_print_drsuapi_DsGetNCChangesCtr(ndr, "ctr", r->out.ctr);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaUpdateRefs(struct ndr_push *ndr, int flags, const struct drsuapi_DsReplicaUpdateRefs *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.bind_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->in.req, r->in.level));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaUpdateRefsRequest(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.req));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaUpdateRefs(struct ndr_pull *ndr, int flags, struct drsuapi_DsReplicaUpdateRefs *r)
+{
+ TALLOC_CTX *_mem_save_bind_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.bind_handle);
+ }
+ _mem_save_bind_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.bind_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->in.req, r->in.level));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaUpdateRefsRequest(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.req));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaUpdateRefs(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsReplicaUpdateRefs *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaUpdateRefs");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "drsuapi_DsReplicaUpdateRefs");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth--;
+ ndr_print_int32(ndr, "level", r->in.level);
+ ndr_print_set_switch_value(ndr, &r->in.req, r->in.level);
+ ndr_print_drsuapi_DsReplicaUpdateRefsRequest(ndr, "req", &r->in.req);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "drsuapi_DsReplicaUpdateRefs");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_DRSUAPI_REPLICA_ADD(struct ndr_push *ndr, int flags, const struct DRSUAPI_REPLICA_ADD *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_DRSUAPI_REPLICA_ADD(struct ndr_pull *ndr, int flags, struct DRSUAPI_REPLICA_ADD *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_DRSUAPI_REPLICA_ADD(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_REPLICA_ADD *r)
+{
+ ndr_print_struct(ndr, name, "DRSUAPI_REPLICA_ADD");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "DRSUAPI_REPLICA_ADD");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "DRSUAPI_REPLICA_ADD");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_DRSUAPI_REPLICA_DEL(struct ndr_push *ndr, int flags, const struct DRSUAPI_REPLICA_DEL *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_DRSUAPI_REPLICA_DEL(struct ndr_pull *ndr, int flags, struct DRSUAPI_REPLICA_DEL *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_DRSUAPI_REPLICA_DEL(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_REPLICA_DEL *r)
+{
+ ndr_print_struct(ndr, name, "DRSUAPI_REPLICA_DEL");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "DRSUAPI_REPLICA_DEL");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "DRSUAPI_REPLICA_DEL");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_DRSUAPI_REPLICA_MODIFY(struct ndr_push *ndr, int flags, const struct DRSUAPI_REPLICA_MODIFY *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_DRSUAPI_REPLICA_MODIFY(struct ndr_pull *ndr, int flags, struct DRSUAPI_REPLICA_MODIFY *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_DRSUAPI_REPLICA_MODIFY(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_REPLICA_MODIFY *r)
+{
+ ndr_print_struct(ndr, name, "DRSUAPI_REPLICA_MODIFY");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "DRSUAPI_REPLICA_MODIFY");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "DRSUAPI_REPLICA_MODIFY");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_DRSUAPI_VERIFY_NAMES(struct ndr_push *ndr, int flags, const struct DRSUAPI_VERIFY_NAMES *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_DRSUAPI_VERIFY_NAMES(struct ndr_pull *ndr, int flags, struct DRSUAPI_VERIFY_NAMES *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_DRSUAPI_VERIFY_NAMES(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_VERIFY_NAMES *r)
+{
+ ndr_print_struct(ndr, name, "DRSUAPI_VERIFY_NAMES");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "DRSUAPI_VERIFY_NAMES");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "DRSUAPI_VERIFY_NAMES");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetMemberships(struct ndr_push *ndr, int flags, const struct drsuapi_DsGetMemberships *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.bind_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.req == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_push_drsuapi_DsGetMembershipsRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.level_out == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, *r->out.level_out));
+ if (r->out.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.ctr, *r->out.level_out));
+ NDR_CHECK(ndr_push_drsuapi_DsGetMembershipsCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetMemberships(struct ndr_pull *ndr, int flags, struct drsuapi_DsGetMemberships *r)
+{
+ TALLOC_CTX *_mem_save_bind_handle_0;
+ TALLOC_CTX *_mem_save_req_0;
+ TALLOC_CTX *_mem_save_level_out_0;
+ TALLOC_CTX *_mem_save_ctr_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.bind_handle);
+ }
+ _mem_save_bind_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.bind_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.req);
+ }
+ _mem_save_req_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.req, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_pull_drsuapi_DsGetMembershipsRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_req_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ ZERO_STRUCTP(r->out.level_out);
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ ZERO_STRUCTP(r->out.ctr);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ }
+ _mem_save_level_out_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.level_out, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, r->out.level_out));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_out_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.ctr, *r->out.level_out));
+ NDR_CHECK(ndr_pull_drsuapi_DsGetMembershipsCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetMemberships(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsGetMemberships *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetMemberships");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "drsuapi_DsGetMemberships");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth--;
+ ndr_print_int32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "req", r->in.req);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.req, r->in.level);
+ ndr_print_drsuapi_DsGetMembershipsRequest(ndr, "req", r->in.req);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "drsuapi_DsGetMemberships");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "level_out", r->out.level_out);
+ ndr->depth++;
+ ndr_print_int32(ndr, "level_out", *r->out.level_out);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ctr", r->out.ctr);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.ctr, *r->out.level_out);
+ ndr_print_drsuapi_DsGetMembershipsCtr(ndr, "ctr", r->out.ctr);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_DRSUAPI_INTER_DOMAIN_MOVE(struct ndr_push *ndr, int flags, const struct DRSUAPI_INTER_DOMAIN_MOVE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_DRSUAPI_INTER_DOMAIN_MOVE(struct ndr_pull *ndr, int flags, struct DRSUAPI_INTER_DOMAIN_MOVE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_DRSUAPI_INTER_DOMAIN_MOVE(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_INTER_DOMAIN_MOVE *r)
+{
+ ndr_print_struct(ndr, name, "DRSUAPI_INTER_DOMAIN_MOVE");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "DRSUAPI_INTER_DOMAIN_MOVE");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "DRSUAPI_INTER_DOMAIN_MOVE");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetNT4ChangeLog(struct ndr_push *ndr, int flags, const struct drsuapi_DsGetNT4ChangeLog *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.bind_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.req == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNT4ChangeLogRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.level_out == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.level_out));
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, *r->out.level_out));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNT4ChangeLogInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetNT4ChangeLog(struct ndr_pull *ndr, int flags, struct drsuapi_DsGetNT4ChangeLog *r)
+{
+ TALLOC_CTX *_mem_save_bind_handle_0;
+ TALLOC_CTX *_mem_save_req_0;
+ TALLOC_CTX *_mem_save_level_out_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.bind_handle);
+ }
+ _mem_save_bind_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.bind_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.req);
+ }
+ _mem_save_req_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.req, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNT4ChangeLogRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_req_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ ZERO_STRUCTP(r->out.level_out);
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ }
+ _mem_save_level_out_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.level_out, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.level_out));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_out_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, *r->out.level_out));
+ NDR_CHECK(ndr_pull_drsuapi_DsGetNT4ChangeLogInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetNT4ChangeLog(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsGetNT4ChangeLog *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetNT4ChangeLog");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "drsuapi_DsGetNT4ChangeLog");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "req", r->in.req);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.req, r->in.level);
+ ndr_print_drsuapi_DsGetNT4ChangeLogRequest(ndr, "req", r->in.req);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "drsuapi_DsGetNT4ChangeLog");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "level_out", r->out.level_out);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level_out", *r->out.level_out);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, *r->out.level_out);
+ ndr_print_drsuapi_DsGetNT4ChangeLogInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsCrackNames(struct ndr_push *ndr, int flags, const struct drsuapi_DsCrackNames *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.bind_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.req == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_push_drsuapi_DsNameRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.level_out == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, *r->out.level_out));
+ if (r->out.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.ctr, *r->out.level_out));
+ NDR_CHECK(ndr_push_drsuapi_DsNameCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsCrackNames(struct ndr_pull *ndr, int flags, struct drsuapi_DsCrackNames *r)
+{
+ TALLOC_CTX *_mem_save_bind_handle_0;
+ TALLOC_CTX *_mem_save_req_0;
+ TALLOC_CTX *_mem_save_level_out_0;
+ TALLOC_CTX *_mem_save_ctr_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.bind_handle);
+ }
+ _mem_save_bind_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.bind_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.req);
+ }
+ _mem_save_req_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.req, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_pull_drsuapi_DsNameRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_req_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ ZERO_STRUCTP(r->out.level_out);
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ ZERO_STRUCTP(r->out.ctr);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ }
+ _mem_save_level_out_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.level_out, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, r->out.level_out));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_out_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.ctr, *r->out.level_out));
+ NDR_CHECK(ndr_pull_drsuapi_DsNameCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsCrackNames(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsCrackNames *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsCrackNames");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "drsuapi_DsCrackNames");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth--;
+ ndr_print_int32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "req", r->in.req);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.req, r->in.level);
+ ndr_print_drsuapi_DsNameRequest(ndr, "req", r->in.req);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "drsuapi_DsCrackNames");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "level_out", r->out.level_out);
+ ndr->depth++;
+ ndr_print_int32(ndr, "level_out", *r->out.level_out);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ctr", r->out.ctr);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.ctr, *r->out.level_out);
+ ndr_print_drsuapi_DsNameCtr(ndr, "ctr", r->out.ctr);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsWriteAccountSpn(struct ndr_push *ndr, int flags, const struct drsuapi_DsWriteAccountSpn *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.bind_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.req == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_push_drsuapi_DsWriteAccountSpnRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.level_out == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, *r->out.level_out));
+ if (r->out.res == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.res, *r->out.level_out));
+ NDR_CHECK(ndr_push_drsuapi_DsWriteAccountSpnResult(ndr, NDR_SCALARS, r->out.res));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsWriteAccountSpn(struct ndr_pull *ndr, int flags, struct drsuapi_DsWriteAccountSpn *r)
+{
+ TALLOC_CTX *_mem_save_bind_handle_0;
+ TALLOC_CTX *_mem_save_req_0;
+ TALLOC_CTX *_mem_save_level_out_0;
+ TALLOC_CTX *_mem_save_res_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.bind_handle);
+ }
+ _mem_save_bind_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.bind_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.req);
+ }
+ _mem_save_req_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.req, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_pull_drsuapi_DsWriteAccountSpnRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_req_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ ZERO_STRUCTP(r->out.level_out);
+ NDR_PULL_ALLOC(ndr, r->out.res);
+ ZERO_STRUCTP(r->out.res);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ }
+ _mem_save_level_out_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.level_out, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, r->out.level_out));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_out_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.res);
+ }
+ _mem_save_res_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.res, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.res, *r->out.level_out));
+ NDR_CHECK(ndr_pull_drsuapi_DsWriteAccountSpnResult(ndr, NDR_SCALARS, r->out.res));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_res_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsWriteAccountSpn(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsWriteAccountSpn *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsWriteAccountSpn");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "drsuapi_DsWriteAccountSpn");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth--;
+ ndr_print_int32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "req", r->in.req);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.req, r->in.level);
+ ndr_print_drsuapi_DsWriteAccountSpnRequest(ndr, "req", r->in.req);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "drsuapi_DsWriteAccountSpn");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "level_out", r->out.level_out);
+ ndr->depth++;
+ ndr_print_int32(ndr, "level_out", *r->out.level_out);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "res", r->out.res);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.res, *r->out.level_out);
+ ndr_print_drsuapi_DsWriteAccountSpnResult(ndr, "res", r->out.res);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsRemoveDSServer(struct ndr_push *ndr, int flags, const struct drsuapi_DsRemoveDSServer *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.bind_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.req == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_push_drsuapi_DsRemoveDSServerRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.level_out == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, *r->out.level_out));
+ if (r->out.res == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.res, *r->out.level_out));
+ NDR_CHECK(ndr_push_drsuapi_DsRemoveDSServerResult(ndr, NDR_SCALARS, r->out.res));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsRemoveDSServer(struct ndr_pull *ndr, int flags, struct drsuapi_DsRemoveDSServer *r)
+{
+ TALLOC_CTX *_mem_save_bind_handle_0;
+ TALLOC_CTX *_mem_save_req_0;
+ TALLOC_CTX *_mem_save_level_out_0;
+ TALLOC_CTX *_mem_save_res_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.bind_handle);
+ }
+ _mem_save_bind_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.bind_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.req);
+ }
+ _mem_save_req_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.req, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_pull_drsuapi_DsRemoveDSServerRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_req_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ ZERO_STRUCTP(r->out.level_out);
+ NDR_PULL_ALLOC(ndr, r->out.res);
+ ZERO_STRUCTP(r->out.res);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ }
+ _mem_save_level_out_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.level_out, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, r->out.level_out));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_out_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.res);
+ }
+ _mem_save_res_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.res, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.res, *r->out.level_out));
+ NDR_CHECK(ndr_pull_drsuapi_DsRemoveDSServerResult(ndr, NDR_SCALARS, r->out.res));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_res_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsRemoveDSServer(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsRemoveDSServer *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsRemoveDSServer");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "drsuapi_DsRemoveDSServer");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth--;
+ ndr_print_int32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "req", r->in.req);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.req, r->in.level);
+ ndr_print_drsuapi_DsRemoveDSServerRequest(ndr, "req", r->in.req);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "drsuapi_DsRemoveDSServer");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "level_out", r->out.level_out);
+ ndr->depth++;
+ ndr_print_int32(ndr, "level_out", *r->out.level_out);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "res", r->out.res);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.res, *r->out.level_out);
+ ndr_print_drsuapi_DsRemoveDSServerResult(ndr, "res", r->out.res);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_DRSUAPI_REMOVE_DS_DOMAIN(struct ndr_push *ndr, int flags, const struct DRSUAPI_REMOVE_DS_DOMAIN *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_DRSUAPI_REMOVE_DS_DOMAIN(struct ndr_pull *ndr, int flags, struct DRSUAPI_REMOVE_DS_DOMAIN *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_DRSUAPI_REMOVE_DS_DOMAIN(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_REMOVE_DS_DOMAIN *r)
+{
+ ndr_print_struct(ndr, name, "DRSUAPI_REMOVE_DS_DOMAIN");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "DRSUAPI_REMOVE_DS_DOMAIN");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "DRSUAPI_REMOVE_DS_DOMAIN");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetDomainControllerInfo(struct ndr_push *ndr, int flags, const struct drsuapi_DsGetDomainControllerInfo *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.bind_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.req == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCInfoRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.level_out == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, *r->out.level_out));
+ if (r->out.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.ctr, *r->out.level_out));
+ NDR_CHECK(ndr_push_drsuapi_DsGetDCInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetDomainControllerInfo(struct ndr_pull *ndr, int flags, struct drsuapi_DsGetDomainControllerInfo *r)
+{
+ TALLOC_CTX *_mem_save_bind_handle_0;
+ TALLOC_CTX *_mem_save_req_0;
+ TALLOC_CTX *_mem_save_level_out_0;
+ TALLOC_CTX *_mem_save_ctr_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.bind_handle);
+ }
+ _mem_save_bind_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.bind_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.req);
+ }
+ _mem_save_req_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.req, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCInfoRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_req_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ ZERO_STRUCTP(r->out.level_out);
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ ZERO_STRUCTP(r->out.ctr);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ }
+ _mem_save_level_out_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.level_out, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, r->out.level_out));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_out_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.ctr, *r->out.level_out));
+ NDR_CHECK(ndr_pull_drsuapi_DsGetDCInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetDomainControllerInfo(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsGetDomainControllerInfo *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetDomainControllerInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "drsuapi_DsGetDomainControllerInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth--;
+ ndr_print_int32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "req", r->in.req);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.req, r->in.level);
+ ndr_print_drsuapi_DsGetDCInfoRequest(ndr, "req", r->in.req);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "drsuapi_DsGetDomainControllerInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "level_out", r->out.level_out);
+ ndr->depth++;
+ ndr_print_int32(ndr, "level_out", *r->out.level_out);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ctr", r->out.ctr);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.ctr, *r->out.level_out);
+ ndr_print_drsuapi_DsGetDCInfoCtr(ndr, "ctr", r->out.ctr);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_drsuapi_DsAddEntry(struct ndr_push *ndr, int flags, const struct drsuapi_DsAddEntry *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.bind_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.req == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.level_out == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, *r->out.level_out));
+ if (r->out.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.ctr, *r->out.level_out));
+ NDR_CHECK(ndr_push_drsuapi_DsAddEntryCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_drsuapi_DsAddEntry(struct ndr_pull *ndr, int flags, struct drsuapi_DsAddEntry *r)
+{
+ TALLOC_CTX *_mem_save_bind_handle_0;
+ TALLOC_CTX *_mem_save_req_0;
+ TALLOC_CTX *_mem_save_level_out_0;
+ TALLOC_CTX *_mem_save_ctr_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.bind_handle);
+ }
+ _mem_save_bind_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.bind_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.req);
+ }
+ _mem_save_req_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.req, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_req_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ ZERO_STRUCTP(r->out.level_out);
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ ZERO_STRUCTP(r->out.ctr);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ }
+ _mem_save_level_out_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.level_out, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, r->out.level_out));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_out_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.ctr, *r->out.level_out));
+ NDR_CHECK(ndr_pull_drsuapi_DsAddEntryCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAddEntry(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsAddEntry *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsAddEntry");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "drsuapi_DsAddEntry");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth--;
+ ndr_print_int32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "req", r->in.req);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.req, r->in.level);
+ ndr_print_drsuapi_DsAddEntryRequest(ndr, "req", r->in.req);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "drsuapi_DsAddEntry");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "level_out", r->out.level_out);
+ ndr->depth++;
+ ndr_print_int32(ndr, "level_out", *r->out.level_out);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ctr", r->out.ctr);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.ctr, *r->out.level_out);
+ ndr_print_drsuapi_DsAddEntryCtr(ndr, "ctr", r->out.ctr);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_DRSUAPI_EXECUTE_KCC(struct ndr_push *ndr, int flags, const struct DRSUAPI_EXECUTE_KCC *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_DRSUAPI_EXECUTE_KCC(struct ndr_pull *ndr, int flags, struct DRSUAPI_EXECUTE_KCC *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_DRSUAPI_EXECUTE_KCC(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_EXECUTE_KCC *r)
+{
+ ndr_print_struct(ndr, name, "DRSUAPI_EXECUTE_KCC");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "DRSUAPI_EXECUTE_KCC");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "DRSUAPI_EXECUTE_KCC");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsReplicaGetInfo(struct ndr_push *ndr, int flags, const struct drsuapi_DsReplicaGetInfo *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.bind_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaGetInfoLevel(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.req == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaGetInfoRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info_type == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaInfoType(ndr, NDR_SCALARS, *r->out.info_type));
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, *r->out.info_type));
+ NDR_CHECK(ndr_push_drsuapi_DsReplicaInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsReplicaGetInfo(struct ndr_pull *ndr, int flags, struct drsuapi_DsReplicaGetInfo *r)
+{
+ TALLOC_CTX *_mem_save_bind_handle_0;
+ TALLOC_CTX *_mem_save_req_0;
+ TALLOC_CTX *_mem_save_info_type_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.bind_handle);
+ }
+ _mem_save_bind_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.bind_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaGetInfoLevel(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.req);
+ }
+ _mem_save_req_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.req, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaGetInfoRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_req_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.info_type);
+ ZERO_STRUCTP(r->out.info_type);
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info_type);
+ }
+ _mem_save_info_type_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info_type, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaInfoType(ndr, NDR_SCALARS, r->out.info_type));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_type_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, *r->out.info_type));
+ NDR_CHECK(ndr_pull_drsuapi_DsReplicaInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsReplicaGetInfo *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaGetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "drsuapi_DsReplicaGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth--;
+ ndr_print_drsuapi_DsReplicaGetInfoLevel(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "req", r->in.req);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.req, r->in.level);
+ ndr_print_drsuapi_DsReplicaGetInfoRequest(ndr, "req", r->in.req);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "drsuapi_DsReplicaGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info_type", r->out.info_type);
+ ndr->depth++;
+ ndr_print_drsuapi_DsReplicaInfoType(ndr, "info_type", *r->out.info_type);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, *r->out.info_type);
+ ndr_print_drsuapi_DsReplicaInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_DRSUAPI_ADD_SID_HISTORY(struct ndr_push *ndr, int flags, const struct DRSUAPI_ADD_SID_HISTORY *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_DRSUAPI_ADD_SID_HISTORY(struct ndr_pull *ndr, int flags, struct DRSUAPI_ADD_SID_HISTORY *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_DRSUAPI_ADD_SID_HISTORY(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_ADD_SID_HISTORY *r)
+{
+ ndr_print_struct(ndr, name, "DRSUAPI_ADD_SID_HISTORY");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "DRSUAPI_ADD_SID_HISTORY");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "DRSUAPI_ADD_SID_HISTORY");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_DsGetMemberships2(struct ndr_push *ndr, int flags, const struct drsuapi_DsGetMemberships2 *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.bind_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.req == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_push_drsuapi_DsGetMemberships2Request(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.level_out == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, *r->out.level_out));
+ if (r->out.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.ctr, *r->out.level_out));
+ NDR_CHECK(ndr_push_drsuapi_DsGetMemberships2Ctr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_DsGetMemberships2(struct ndr_pull *ndr, int flags, struct drsuapi_DsGetMemberships2 *r)
+{
+ TALLOC_CTX *_mem_save_bind_handle_0;
+ TALLOC_CTX *_mem_save_req_0;
+ TALLOC_CTX *_mem_save_level_out_0;
+ TALLOC_CTX *_mem_save_ctr_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.bind_handle);
+ }
+ _mem_save_bind_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.bind_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.req);
+ }
+ _mem_save_req_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.req, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_pull_drsuapi_DsGetMemberships2Request(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_req_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ ZERO_STRUCTP(r->out.level_out);
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ ZERO_STRUCTP(r->out.ctr);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ }
+ _mem_save_level_out_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.level_out, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, r->out.level_out));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_out_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.ctr, *r->out.level_out));
+ NDR_CHECK(ndr_pull_drsuapi_DsGetMemberships2Ctr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsGetMemberships2(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsGetMemberships2 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsGetMemberships2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "drsuapi_DsGetMemberships2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth--;
+ ndr_print_int32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "req", r->in.req);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.req, r->in.level);
+ ndr_print_drsuapi_DsGetMemberships2Request(ndr, "req", r->in.req);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "drsuapi_DsGetMemberships2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "level_out", r->out.level_out);
+ ndr->depth++;
+ ndr_print_int32(ndr, "level_out", *r->out.level_out);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ctr", r->out.ctr);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.ctr, *r->out.level_out);
+ ndr_print_drsuapi_DsGetMemberships2Ctr(ndr, "ctr", r->out.ctr);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_DRSUAPI_REPLICA_VERIFY_OBJECTS(struct ndr_push *ndr, int flags, const struct DRSUAPI_REPLICA_VERIFY_OBJECTS *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_DRSUAPI_REPLICA_VERIFY_OBJECTS(struct ndr_pull *ndr, int flags, struct DRSUAPI_REPLICA_VERIFY_OBJECTS *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_DRSUAPI_REPLICA_VERIFY_OBJECTS(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_REPLICA_VERIFY_OBJECTS *r)
+{
+ ndr_print_struct(ndr, name, "DRSUAPI_REPLICA_VERIFY_OBJECTS");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "DRSUAPI_REPLICA_VERIFY_OBJECTS");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "DRSUAPI_REPLICA_VERIFY_OBJECTS");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_DRSUAPI_GET_OBJECT_EXISTENCE(struct ndr_push *ndr, int flags, const struct DRSUAPI_GET_OBJECT_EXISTENCE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_DRSUAPI_GET_OBJECT_EXISTENCE(struct ndr_pull *ndr, int flags, struct DRSUAPI_GET_OBJECT_EXISTENCE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_DRSUAPI_GET_OBJECT_EXISTENCE(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_GET_OBJECT_EXISTENCE *r)
+{
+ ndr_print_struct(ndr, name, "DRSUAPI_GET_OBJECT_EXISTENCE");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "DRSUAPI_GET_OBJECT_EXISTENCE");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "DRSUAPI_GET_OBJECT_EXISTENCE");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_drsuapi_QuerySitesByCost(struct ndr_push *ndr, int flags, const struct drsuapi_QuerySitesByCost *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.bind_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.req == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_push_drsuapi_QuerySitesByCostRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.level_out == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, *r->out.level_out));
+ if (r->out.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.ctr, *r->out.level_out));
+ NDR_CHECK(ndr_push_drsuapi_QuerySitesByCostCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_drsuapi_QuerySitesByCost(struct ndr_pull *ndr, int flags, struct drsuapi_QuerySitesByCost *r)
+{
+ TALLOC_CTX *_mem_save_bind_handle_0;
+ TALLOC_CTX *_mem_save_req_0;
+ TALLOC_CTX *_mem_save_level_out_0;
+ TALLOC_CTX *_mem_save_ctr_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.bind_handle);
+ }
+ _mem_save_bind_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.bind_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.bind_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bind_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.req);
+ }
+ _mem_save_req_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.req, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.req, r->in.level));
+ NDR_CHECK(ndr_pull_drsuapi_QuerySitesByCostRequest(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.req));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_req_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ ZERO_STRUCTP(r->out.level_out);
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ ZERO_STRUCTP(r->out.ctr);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ }
+ _mem_save_level_out_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.level_out, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, r->out.level_out));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_out_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.ctr, *r->out.level_out));
+ NDR_CHECK(ndr_pull_drsuapi_QuerySitesByCostCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_QuerySitesByCost(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_QuerySitesByCost *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_QuerySitesByCost");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "drsuapi_QuerySitesByCost");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "bind_handle", r->in.bind_handle);
+ ndr->depth--;
+ ndr_print_int32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "req", r->in.req);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.req, r->in.level);
+ ndr_print_drsuapi_QuerySitesByCostRequest(ndr, "req", r->in.req);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "drsuapi_QuerySitesByCost");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "level_out", r->out.level_out);
+ ndr->depth++;
+ ndr_print_int32(ndr, "level_out", *r->out.level_out);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ctr", r->out.ctr);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.ctr, *r->out.level_out);
+ ndr_print_drsuapi_QuerySitesByCostCtr(ndr, "ctr", r->out.ctr);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call drsuapi_calls[] = {
+ {
+ "drsuapi_DsBind",
+ sizeof(struct drsuapi_DsBind),
+ (ndr_push_flags_fn_t) ndr_push_drsuapi_DsBind,
+ (ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsBind,
+ (ndr_print_function_t) ndr_print_drsuapi_DsBind,
+ false,
+ },
+ {
+ "drsuapi_DsUnbind",
+ sizeof(struct drsuapi_DsUnbind),
+ (ndr_push_flags_fn_t) ndr_push_drsuapi_DsUnbind,
+ (ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsUnbind,
+ (ndr_print_function_t) ndr_print_drsuapi_DsUnbind,
+ false,
+ },
+ {
+ "drsuapi_DsReplicaSync",
+ sizeof(struct drsuapi_DsReplicaSync),
+ (ndr_push_flags_fn_t) ndr_push_drsuapi_DsReplicaSync,
+ (ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsReplicaSync,
+ (ndr_print_function_t) ndr_print_drsuapi_DsReplicaSync,
+ false,
+ },
+ {
+ "drsuapi_DsGetNCChanges",
+ sizeof(struct drsuapi_DsGetNCChanges),
+ (ndr_push_flags_fn_t) ndr_push_drsuapi_DsGetNCChanges,
+ (ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsGetNCChanges,
+ (ndr_print_function_t) ndr_print_drsuapi_DsGetNCChanges,
+ false,
+ },
+ {
+ "drsuapi_DsReplicaUpdateRefs",
+ sizeof(struct drsuapi_DsReplicaUpdateRefs),
+ (ndr_push_flags_fn_t) ndr_push_drsuapi_DsReplicaUpdateRefs,
+ (ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsReplicaUpdateRefs,
+ (ndr_print_function_t) ndr_print_drsuapi_DsReplicaUpdateRefs,
+ false,
+ },
+ {
+ "DRSUAPI_REPLICA_ADD",
+ sizeof(struct DRSUAPI_REPLICA_ADD),
+ (ndr_push_flags_fn_t) ndr_push_DRSUAPI_REPLICA_ADD,
+ (ndr_pull_flags_fn_t) ndr_pull_DRSUAPI_REPLICA_ADD,
+ (ndr_print_function_t) ndr_print_DRSUAPI_REPLICA_ADD,
+ false,
+ },
+ {
+ "DRSUAPI_REPLICA_DEL",
+ sizeof(struct DRSUAPI_REPLICA_DEL),
+ (ndr_push_flags_fn_t) ndr_push_DRSUAPI_REPLICA_DEL,
+ (ndr_pull_flags_fn_t) ndr_pull_DRSUAPI_REPLICA_DEL,
+ (ndr_print_function_t) ndr_print_DRSUAPI_REPLICA_DEL,
+ false,
+ },
+ {
+ "DRSUAPI_REPLICA_MODIFY",
+ sizeof(struct DRSUAPI_REPLICA_MODIFY),
+ (ndr_push_flags_fn_t) ndr_push_DRSUAPI_REPLICA_MODIFY,
+ (ndr_pull_flags_fn_t) ndr_pull_DRSUAPI_REPLICA_MODIFY,
+ (ndr_print_function_t) ndr_print_DRSUAPI_REPLICA_MODIFY,
+ false,
+ },
+ {
+ "DRSUAPI_VERIFY_NAMES",
+ sizeof(struct DRSUAPI_VERIFY_NAMES),
+ (ndr_push_flags_fn_t) ndr_push_DRSUAPI_VERIFY_NAMES,
+ (ndr_pull_flags_fn_t) ndr_pull_DRSUAPI_VERIFY_NAMES,
+ (ndr_print_function_t) ndr_print_DRSUAPI_VERIFY_NAMES,
+ false,
+ },
+ {
+ "drsuapi_DsGetMemberships",
+ sizeof(struct drsuapi_DsGetMemberships),
+ (ndr_push_flags_fn_t) ndr_push_drsuapi_DsGetMemberships,
+ (ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsGetMemberships,
+ (ndr_print_function_t) ndr_print_drsuapi_DsGetMemberships,
+ false,
+ },
+ {
+ "DRSUAPI_INTER_DOMAIN_MOVE",
+ sizeof(struct DRSUAPI_INTER_DOMAIN_MOVE),
+ (ndr_push_flags_fn_t) ndr_push_DRSUAPI_INTER_DOMAIN_MOVE,
+ (ndr_pull_flags_fn_t) ndr_pull_DRSUAPI_INTER_DOMAIN_MOVE,
+ (ndr_print_function_t) ndr_print_DRSUAPI_INTER_DOMAIN_MOVE,
+ false,
+ },
+ {
+ "drsuapi_DsGetNT4ChangeLog",
+ sizeof(struct drsuapi_DsGetNT4ChangeLog),
+ (ndr_push_flags_fn_t) ndr_push_drsuapi_DsGetNT4ChangeLog,
+ (ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsGetNT4ChangeLog,
+ (ndr_print_function_t) ndr_print_drsuapi_DsGetNT4ChangeLog,
+ false,
+ },
+ {
+ "drsuapi_DsCrackNames",
+ sizeof(struct drsuapi_DsCrackNames),
+ (ndr_push_flags_fn_t) ndr_push_drsuapi_DsCrackNames,
+ (ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsCrackNames,
+ (ndr_print_function_t) ndr_print_drsuapi_DsCrackNames,
+ false,
+ },
+ {
+ "drsuapi_DsWriteAccountSpn",
+ sizeof(struct drsuapi_DsWriteAccountSpn),
+ (ndr_push_flags_fn_t) ndr_push_drsuapi_DsWriteAccountSpn,
+ (ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsWriteAccountSpn,
+ (ndr_print_function_t) ndr_print_drsuapi_DsWriteAccountSpn,
+ false,
+ },
+ {
+ "drsuapi_DsRemoveDSServer",
+ sizeof(struct drsuapi_DsRemoveDSServer),
+ (ndr_push_flags_fn_t) ndr_push_drsuapi_DsRemoveDSServer,
+ (ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsRemoveDSServer,
+ (ndr_print_function_t) ndr_print_drsuapi_DsRemoveDSServer,
+ false,
+ },
+ {
+ "DRSUAPI_REMOVE_DS_DOMAIN",
+ sizeof(struct DRSUAPI_REMOVE_DS_DOMAIN),
+ (ndr_push_flags_fn_t) ndr_push_DRSUAPI_REMOVE_DS_DOMAIN,
+ (ndr_pull_flags_fn_t) ndr_pull_DRSUAPI_REMOVE_DS_DOMAIN,
+ (ndr_print_function_t) ndr_print_DRSUAPI_REMOVE_DS_DOMAIN,
+ false,
+ },
+ {
+ "drsuapi_DsGetDomainControllerInfo",
+ sizeof(struct drsuapi_DsGetDomainControllerInfo),
+ (ndr_push_flags_fn_t) ndr_push_drsuapi_DsGetDomainControllerInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsGetDomainControllerInfo,
+ (ndr_print_function_t) ndr_print_drsuapi_DsGetDomainControllerInfo,
+ false,
+ },
+ {
+ "drsuapi_DsAddEntry",
+ sizeof(struct drsuapi_DsAddEntry),
+ (ndr_push_flags_fn_t) ndr_push_drsuapi_DsAddEntry,
+ (ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsAddEntry,
+ (ndr_print_function_t) ndr_print_drsuapi_DsAddEntry,
+ false,
+ },
+ {
+ "DRSUAPI_EXECUTE_KCC",
+ sizeof(struct DRSUAPI_EXECUTE_KCC),
+ (ndr_push_flags_fn_t) ndr_push_DRSUAPI_EXECUTE_KCC,
+ (ndr_pull_flags_fn_t) ndr_pull_DRSUAPI_EXECUTE_KCC,
+ (ndr_print_function_t) ndr_print_DRSUAPI_EXECUTE_KCC,
+ false,
+ },
+ {
+ "drsuapi_DsReplicaGetInfo",
+ sizeof(struct drsuapi_DsReplicaGetInfo),
+ (ndr_push_flags_fn_t) ndr_push_drsuapi_DsReplicaGetInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsReplicaGetInfo,
+ (ndr_print_function_t) ndr_print_drsuapi_DsReplicaGetInfo,
+ false,
+ },
+ {
+ "DRSUAPI_ADD_SID_HISTORY",
+ sizeof(struct DRSUAPI_ADD_SID_HISTORY),
+ (ndr_push_flags_fn_t) ndr_push_DRSUAPI_ADD_SID_HISTORY,
+ (ndr_pull_flags_fn_t) ndr_pull_DRSUAPI_ADD_SID_HISTORY,
+ (ndr_print_function_t) ndr_print_DRSUAPI_ADD_SID_HISTORY,
+ false,
+ },
+ {
+ "drsuapi_DsGetMemberships2",
+ sizeof(struct drsuapi_DsGetMemberships2),
+ (ndr_push_flags_fn_t) ndr_push_drsuapi_DsGetMemberships2,
+ (ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsGetMemberships2,
+ (ndr_print_function_t) ndr_print_drsuapi_DsGetMemberships2,
+ false,
+ },
+ {
+ "DRSUAPI_REPLICA_VERIFY_OBJECTS",
+ sizeof(struct DRSUAPI_REPLICA_VERIFY_OBJECTS),
+ (ndr_push_flags_fn_t) ndr_push_DRSUAPI_REPLICA_VERIFY_OBJECTS,
+ (ndr_pull_flags_fn_t) ndr_pull_DRSUAPI_REPLICA_VERIFY_OBJECTS,
+ (ndr_print_function_t) ndr_print_DRSUAPI_REPLICA_VERIFY_OBJECTS,
+ false,
+ },
+ {
+ "DRSUAPI_GET_OBJECT_EXISTENCE",
+ sizeof(struct DRSUAPI_GET_OBJECT_EXISTENCE),
+ (ndr_push_flags_fn_t) ndr_push_DRSUAPI_GET_OBJECT_EXISTENCE,
+ (ndr_pull_flags_fn_t) ndr_pull_DRSUAPI_GET_OBJECT_EXISTENCE,
+ (ndr_print_function_t) ndr_print_DRSUAPI_GET_OBJECT_EXISTENCE,
+ false,
+ },
+ {
+ "drsuapi_QuerySitesByCost",
+ sizeof(struct drsuapi_QuerySitesByCost),
+ (ndr_push_flags_fn_t) ndr_push_drsuapi_QuerySitesByCost,
+ (ndr_pull_flags_fn_t) ndr_pull_drsuapi_QuerySitesByCost,
+ (ndr_print_function_t) ndr_print_drsuapi_QuerySitesByCost,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const drsuapi_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\lsass]",
+ "ncacn_np:[\\pipe\\protected_storage]",
+ "ncacn_ip_tcp:",
+ "ncalrpc:",
+};
+
+static const struct ndr_interface_string_array drsuapi_endpoints = {
+ .count = 4,
+ .names = drsuapi_endpoint_strings
+};
+
+static const char * const drsuapi_authservice_strings[] = {
+ "ldap",
+};
+
+static const struct ndr_interface_string_array drsuapi_authservices = {
+ .count = 1,
+ .names = drsuapi_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_drsuapi = {
+ .name = "drsuapi",
+ .syntax_id = {
+ {0xe3514235,0x4b06,0x11d1,{0xab,0x04},{0x00,0xc0,0x4f,0xc2,0xdc,0xd2}},
+ NDR_DRSUAPI_VERSION
+ },
+ .helpstring = NDR_DRSUAPI_HELPSTRING,
+ .num_calls = 25,
+ .calls = drsuapi_calls,
+ .endpoints = &drsuapi_endpoints,
+ .authservices = &drsuapi_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_drsuapi.h b/source3/librpc/gen_ndr/ndr_drsuapi.h
new file mode 100644
index 0000000000..6b6a0b5670
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_drsuapi.h
@@ -0,0 +1,291 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/drsuapi.h"
+
+#ifndef _HEADER_NDR_drsuapi
+#define _HEADER_NDR_drsuapi
+
+#include "librpc/ndr/ndr_drsuapi.h"
+#define NDR_DRSUAPI_UUID "e3514235-4b06-11d1-ab04-00c04fc2dcd2"
+#define NDR_DRSUAPI_VERSION 4.0
+#define NDR_DRSUAPI_NAME "drsuapi"
+#define NDR_DRSUAPI_HELPSTRING "Active Directory Replication"
+extern const struct ndr_interface_table ndr_table_drsuapi;
+#define NDR_DRSUAPI_DSBIND (0x00)
+
+#define NDR_DRSUAPI_DSUNBIND (0x01)
+
+#define NDR_DRSUAPI_DSREPLICASYNC (0x02)
+
+#define NDR_DRSUAPI_DSGETNCCHANGES (0x03)
+
+#define NDR_DRSUAPI_DSREPLICAUPDATEREFS (0x04)
+
+#define NDR_DRSUAPI_REPLICA_ADD (0x05)
+
+#define NDR_DRSUAPI_REPLICA_DEL (0x06)
+
+#define NDR_DRSUAPI_REPLICA_MODIFY (0x07)
+
+#define NDR_DRSUAPI_VERIFY_NAMES (0x08)
+
+#define NDR_DRSUAPI_DSGETMEMBERSHIPS (0x09)
+
+#define NDR_DRSUAPI_INTER_DOMAIN_MOVE (0x0a)
+
+#define NDR_DRSUAPI_DSGETNT4CHANGELOG (0x0b)
+
+#define NDR_DRSUAPI_DSCRACKNAMES (0x0c)
+
+#define NDR_DRSUAPI_DSWRITEACCOUNTSPN (0x0d)
+
+#define NDR_DRSUAPI_DSREMOVEDSSERVER (0x0e)
+
+#define NDR_DRSUAPI_REMOVE_DS_DOMAIN (0x0f)
+
+#define NDR_DRSUAPI_DSGETDOMAINCONTROLLERINFO (0x10)
+
+#define NDR_DRSUAPI_DSADDENTRY (0x11)
+
+#define NDR_DRSUAPI_EXECUTE_KCC (0x12)
+
+#define NDR_DRSUAPI_DSREPLICAGETINFO (0x13)
+
+#define NDR_DRSUAPI_ADD_SID_HISTORY (0x14)
+
+#define NDR_DRSUAPI_DSGETMEMBERSHIPS2 (0x15)
+
+#define NDR_DRSUAPI_REPLICA_VERIFY_OBJECTS (0x16)
+
+#define NDR_DRSUAPI_GET_OBJECT_EXISTENCE (0x17)
+
+#define NDR_DRSUAPI_QUERYSITESBYCOST (0x18)
+
+#define NDR_DRSUAPI_CALL_COUNT (25)
+void ndr_print_drsuapi_SupportedExtensions(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_drsuapi_SupportedExtensionsExt(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_drsuapi_DsBindInfo24(struct ndr_print *ndr, const char *name, const struct drsuapi_DsBindInfo24 *r);
+void ndr_print_drsuapi_DsBindInfo28(struct ndr_print *ndr, const char *name, const struct drsuapi_DsBindInfo28 *r);
+void ndr_print_drsuapi_DsBindInfo48(struct ndr_print *ndr, const char *name, const struct drsuapi_DsBindInfo48 *r);
+void ndr_print_drsuapi_DsBindInfoFallBack(struct ndr_print *ndr, const char *name, const struct drsuapi_DsBindInfoFallBack *r);
+void ndr_print_drsuapi_DsBindInfo(struct ndr_print *ndr, const char *name, const union drsuapi_DsBindInfo *r);
+void ndr_print_drsuapi_DsBindInfoCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsBindInfoCtr *r);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaObjectIdentifier(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObjectIdentifier *r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjectIdentifier(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObjectIdentifier *r);
+void ndr_print_drsuapi_DsReplicaObjectIdentifier(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjectIdentifier *r);
+size_t ndr_size_drsuapi_DsReplicaObjectIdentifier(const struct drsuapi_DsReplicaObjectIdentifier *r, int flags);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaSyncOptions(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaSyncOptions(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_drsuapi_DsReplicaSyncOptions(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_drsuapi_DsReplicaSyncRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaSyncRequest1 *r);
+void ndr_print_drsuapi_DsReplicaSyncRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsReplicaSyncRequest *r);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaHighWaterMark(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaHighWaterMark *r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaHighWaterMark(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaHighWaterMark *r);
+void ndr_print_drsuapi_DsReplicaHighWaterMark(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaHighWaterMark *r);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaCursor(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaCursor *r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaCursor(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaCursor *r);
+void ndr_print_drsuapi_DsReplicaCursor(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaCursor *r);
+void ndr_print_drsuapi_DsReplicaCursorCtrEx(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaCursorCtrEx *r);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaNeighbourFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaNeighbourFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_drsuapi_DsReplicaNeighbourFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_drsuapi_DsExtendedOperation(struct ndr_print *ndr, const char *name, enum drsuapi_DsExtendedOperation r);
+void ndr_print_drsuapi_DsExtendedError(struct ndr_print *ndr, const char *name, enum drsuapi_DsExtendedError r);
+void ndr_print_drsuapi_DsGetNCChangesRequest5(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesRequest5 *r);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaOID(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaOID *r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaOID(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaOID *r);
+void ndr_print_drsuapi_DsReplicaOID(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaOID *r);
+void ndr_print_drsuapi_DsReplicaOIDMapping(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaOIDMapping *r);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaOIDMapping_Ctr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaOIDMapping_Ctr *r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaOIDMapping_Ctr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaOIDMapping_Ctr *r);
+void ndr_print_drsuapi_DsReplicaOIDMapping_Ctr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaOIDMapping_Ctr *r);
+enum ndr_err_code ndr_push_drsuapi_DsAttributeId(struct ndr_push *ndr, int ndr_flags, enum drsuapi_DsAttributeId r);
+enum ndr_err_code ndr_pull_drsuapi_DsAttributeId(struct ndr_pull *ndr, int ndr_flags, enum drsuapi_DsAttributeId *r);
+void ndr_print_drsuapi_DsAttributeId(struct ndr_print *ndr, const char *name, enum drsuapi_DsAttributeId r);
+void ndr_print_drsuapi_DsPartialAttributeSet(struct ndr_print *ndr, const char *name, const struct drsuapi_DsPartialAttributeSet *r);
+void ndr_print_drsuapi_DsGetNCChangesRequest8(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesRequest8 *r);
+void ndr_print_drsuapi_DsGetNCChangesRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetNCChangesRequest *r);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaCursor2(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaCursor2 *r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaCursor2(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaCursor2 *r);
+void ndr_print_drsuapi_DsReplicaCursor2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaCursor2 *r);
+void ndr_print_drsuapi_DsReplicaCursor2CtrEx(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaCursor2CtrEx *r);
+void ndr_print_drsuapi_DsAttributeValue(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAttributeValue *r);
+void ndr_print_drsuapi_DsAttributeValueCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAttributeValueCtr *r);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaObjectIdentifier3(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObjectIdentifier3 *r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjectIdentifier3(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObjectIdentifier3 *r);
+void ndr_print_drsuapi_DsReplicaObjectIdentifier3(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjectIdentifier3 *r);
+size_t ndr_size_drsuapi_DsReplicaObjectIdentifier3(const struct drsuapi_DsReplicaObjectIdentifier3 *r, int flags);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaObjectIdentifier3Binary(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObjectIdentifier3Binary *r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjectIdentifier3Binary(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObjectIdentifier3Binary *r);
+void ndr_print_drsuapi_DsReplicaObjectIdentifier3Binary(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjectIdentifier3Binary *r);
+size_t ndr_size_drsuapi_DsReplicaObjectIdentifier3Binary(const struct drsuapi_DsReplicaObjectIdentifier3Binary *r, int flags);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaAttribute(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaAttribute *r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaAttribute(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaAttribute *r);
+void ndr_print_drsuapi_DsReplicaAttribute(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaAttribute *r);
+void ndr_print_drsuapi_DsReplicaAttributeCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaAttributeCtr *r);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaObjectFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjectFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_drsuapi_DsReplicaObjectFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaObject(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObject *r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaObject(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObject *r);
+void ndr_print_drsuapi_DsReplicaObject(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObject *r);
+void ndr_print_drsuapi_DsReplicaMetaData(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaMetaData *r);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaMetaDataCtr(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaMetaDataCtr *r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaMetaDataCtr(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaMetaDataCtr *r);
+void ndr_print_drsuapi_DsReplicaMetaDataCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaMetaDataCtr *r);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaObjectListItemEx(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObjectListItemEx *r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjectListItemEx(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObjectListItemEx *r);
+void ndr_print_drsuapi_DsReplicaObjectListItemEx(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjectListItemEx *r);
+enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesCtr1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNCChangesCtr1 *r);
+enum ndr_err_code ndr_pull_drsuapi_DsGetNCChangesCtr1(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetNCChangesCtr1 *r);
+void ndr_print_drsuapi_DsGetNCChangesCtr1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesCtr1 *r);
+size_t ndr_size_drsuapi_DsGetNCChangesCtr1(const struct drsuapi_DsGetNCChangesCtr1 *r, int flags);
+enum ndr_err_code ndr_push_drsuapi_DsLinkedAttributeFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_drsuapi_DsLinkedAttributeFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_drsuapi_DsLinkedAttributeFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaLinkedAttribute(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaLinkedAttribute *r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaLinkedAttribute(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaLinkedAttribute *r);
+void ndr_print_drsuapi_DsReplicaLinkedAttribute(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaLinkedAttribute *r);
+enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesCtr6(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNCChangesCtr6 *r);
+enum ndr_err_code ndr_pull_drsuapi_DsGetNCChangesCtr6(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsGetNCChangesCtr6 *r);
+void ndr_print_drsuapi_DsGetNCChangesCtr6(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesCtr6 *r);
+size_t ndr_size_drsuapi_DsGetNCChangesCtr6(const struct drsuapi_DsGetNCChangesCtr6 *r, int flags);
+void ndr_print_drsuapi_DsGetNCChangesMSZIPCtr1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesMSZIPCtr1 *r);
+void ndr_print_drsuapi_DsGetNCChangesMSZIPCtr6(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesMSZIPCtr6 *r);
+void ndr_print_drsuapi_DsGetNCChangesXPRESSCtr1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesXPRESSCtr1 *r);
+void ndr_print_drsuapi_DsGetNCChangesXPRESSCtr6(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesXPRESSCtr6 *r);
+void ndr_print_drsuapi_DsGetNCChangesCompressionType(struct ndr_print *ndr, const char *name, enum drsuapi_DsGetNCChangesCompressionType r);
+void ndr_print_drsuapi_DsGetNCChangesCompressedCtr(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetNCChangesCompressedCtr *r);
+void ndr_print_drsuapi_DsGetNCChangesCtr2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesCtr2 *r);
+void ndr_print_drsuapi_DsGetNCChangesCtr7(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNCChangesCtr7 *r);
+void ndr_print_drsuapi_DsGetNCChangesCtr(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetNCChangesCtr *r);
+void ndr_print_drsuapi_DsReplicaUpdateRefsOptions(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_drsuapi_DsReplicaUpdateRefsRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaUpdateRefsRequest1 *r);
+void ndr_print_drsuapi_DsReplicaUpdateRefsRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsReplicaUpdateRefsRequest *r);
+void ndr_print_drsuapi_DsReplicaAddOptions(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_drsuapi_DsReplicaDeleteOptions(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_drsuapi_DsReplicaModifyOptions(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_drsuapi_DsMembershipType(struct ndr_print *ndr, const char *name, enum drsuapi_DsMembershipType r);
+void ndr_print_drsuapi_DsGetMembershipsCtr1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetMembershipsCtr1 *r);
+void ndr_print_drsuapi_DsGetMembershipsCtr(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetMembershipsCtr *r);
+void ndr_print_drsuapi_DsGetMembershipsRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetMembershipsRequest1 *r);
+void ndr_print_drsuapi_DsGetMembershipsRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetMembershipsRequest *r);
+void ndr_print_drsuapi_DsGetNT4ChangeLogRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNT4ChangeLogRequest1 *r);
+void ndr_print_drsuapi_DsGetNT4ChangeLogRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetNT4ChangeLogRequest *r);
+void ndr_print_drsuapi_DsGetNT4ChangeLogInfo1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetNT4ChangeLogInfo1 *r);
+void ndr_print_drsuapi_DsGetNT4ChangeLogInfo(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetNT4ChangeLogInfo *r);
+void ndr_print_drsuapi_DsNameStatus(struct ndr_print *ndr, const char *name, enum drsuapi_DsNameStatus r);
+void ndr_print_drsuapi_DsNameFlags(struct ndr_print *ndr, const char *name, enum drsuapi_DsNameFlags r);
+void ndr_print_drsuapi_DsNameFormat(struct ndr_print *ndr, const char *name, enum drsuapi_DsNameFormat r);
+void ndr_print_drsuapi_DsNameString(struct ndr_print *ndr, const char *name, const struct drsuapi_DsNameString *r);
+void ndr_print_drsuapi_DsNameRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsNameRequest1 *r);
+void ndr_print_drsuapi_DsNameRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsNameRequest *r);
+void ndr_print_drsuapi_DsNameInfo1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsNameInfo1 *r);
+void ndr_print_drsuapi_DsNameCtr1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsNameCtr1 *r);
+void ndr_print_drsuapi_DsNameCtr(struct ndr_print *ndr, const char *name, const union drsuapi_DsNameCtr *r);
+void ndr_print_drsuapi_DsSpnOperation(struct ndr_print *ndr, const char *name, enum drsuapi_DsSpnOperation r);
+void ndr_print_drsuapi_DsWriteAccountSpnRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsWriteAccountSpnRequest1 *r);
+void ndr_print_drsuapi_DsWriteAccountSpnRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsWriteAccountSpnRequest *r);
+void ndr_print_drsuapi_DsWriteAccountSpnResult1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsWriteAccountSpnResult1 *r);
+void ndr_print_drsuapi_DsWriteAccountSpnResult(struct ndr_print *ndr, const char *name, const union drsuapi_DsWriteAccountSpnResult *r);
+void ndr_print_drsuapi_DsRemoveDSServerRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsRemoveDSServerRequest1 *r);
+void ndr_print_drsuapi_DsRemoveDSServerRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsRemoveDSServerRequest *r);
+void ndr_print_drsuapi_DsRemoveDSServerResult1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsRemoveDSServerResult1 *r);
+void ndr_print_drsuapi_DsRemoveDSServerResult(struct ndr_print *ndr, const char *name, const union drsuapi_DsRemoveDSServerResult *r);
+void ndr_print_drsuapi_DsGetDCInfoRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCInfoRequest1 *r);
+void ndr_print_drsuapi_DsGetDCInfoRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetDCInfoRequest *r);
+void ndr_print_drsuapi_DsGetDCInfo1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCInfo1 *r);
+void ndr_print_drsuapi_DsGetDCInfoCtr1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCInfoCtr1 *r);
+void ndr_print_drsuapi_DsGetDCInfo2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCInfo2 *r);
+void ndr_print_drsuapi_DsGetDCInfoCtr2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCInfoCtr2 *r);
+void ndr_print_drsuapi_DsGetDCInfo3(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCInfo3 *r);
+void ndr_print_drsuapi_DsGetDCInfoCtr3(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCInfoCtr3 *r);
+void ndr_print_drsuapi_DsGetDCConnection01(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCConnection01 *r);
+void ndr_print_drsuapi_DsGetDCConnectionCtr01(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetDCConnectionCtr01 *r);
+void ndr_print_drsuapi_DsGetDCInfoCtr(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetDCInfoCtr *r);
+enum ndr_err_code ndr_push_drsuapi_DsReplicaObjectListItem(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaObjectListItem *r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaObjectListItem(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaObjectListItem *r);
+void ndr_print_drsuapi_DsReplicaObjectListItem(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjectListItem *r);
+void ndr_print_drsuapi_DsAddEntryRequest2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryRequest2 *r);
+void ndr_print_drsuapi_DsAddEntryRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsAddEntryRequest *r);
+void ndr_print_drsuapi_DsAddEntryErrorInfoX(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryErrorInfoX *r);
+void ndr_print_drsuapi_DsAddEntryExtraErrorBuffer(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryExtraErrorBuffer *r);
+void ndr_print_drsuapi_DsAddEntryExtraError1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryExtraError1 *r);
+void ndr_print_drsuapi_DsAddEntryErrorListItem1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryErrorListItem1 *r);
+void ndr_print_drsuapi_DsAddEntryErrorInfo1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryErrorInfo1 *r);
+void ndr_print_drsuapi_DsAddEntryErrorInfo(struct ndr_print *ndr, const char *name, const union drsuapi_DsAddEntryErrorInfo *r);
+void ndr_print_drsuapi_DsAddEntryError1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryError1 *r);
+void ndr_print_drsuapi_DsAddEntryError(struct ndr_print *ndr, const char *name, const union drsuapi_DsAddEntryError *r);
+void ndr_print_drsuapi_DsReplicaObjectIdentifier2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjectIdentifier2 *r);
+void ndr_print_drsuapi_DsAddEntryCtr2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryCtr2 *r);
+void ndr_print_drsuapi_DsAddEntryCtr3(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntryCtr3 *r);
+void ndr_print_drsuapi_DsAddEntryCtr(struct ndr_print *ndr, const char *name, const union drsuapi_DsAddEntryCtr *r);
+void ndr_print_drsuapi_DsReplicaGetInfoLevel(struct ndr_print *ndr, const char *name, enum drsuapi_DsReplicaGetInfoLevel r);
+void ndr_print_drsuapi_DsReplicaInfoType(struct ndr_print *ndr, const char *name, enum drsuapi_DsReplicaInfoType r);
+void ndr_print_drsuapi_DsReplicaGetInfoRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaGetInfoRequest1 *r);
+void ndr_print_drsuapi_DsReplicaGetInfoRequest2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaGetInfoRequest2 *r);
+void ndr_print_drsuapi_DsReplicaGetInfoRequest(struct ndr_print *ndr, const char *name, const union drsuapi_DsReplicaGetInfoRequest *r);
+void ndr_print_drsuapi_DsReplicaNeighbour(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaNeighbour *r);
+void ndr_print_drsuapi_DsReplicaNeighbourCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaNeighbourCtr *r);
+void ndr_print_drsuapi_DsReplicaCursorCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaCursorCtr *r);
+void ndr_print_drsuapi_DsReplicaObjMetaData(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjMetaData *r);
+void ndr_print_drsuapi_DsReplicaObjMetaDataCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjMetaDataCtr *r);
+void ndr_print_drsuapi_DsReplicaKccDsaFailure(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaKccDsaFailure *r);
+void ndr_print_drsuapi_DsReplicaKccDsaFailuresCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaKccDsaFailuresCtr *r);
+void ndr_print_drsuapi_DsReplicaOpType(struct ndr_print *ndr, const char *name, enum drsuapi_DsReplicaOpType r);
+void ndr_print_drsuapi_DsRplicaOpOptions(struct ndr_print *ndr, const char *name, const union drsuapi_DsRplicaOpOptions *r);
+void ndr_print_drsuapi_DsReplicaOp(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaOp *r);
+void ndr_print_drsuapi_DsReplicaOpCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaOpCtr *r);
+void ndr_print_drsuapi_DsReplicaAttrValMetaData(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaAttrValMetaData *r);
+void ndr_print_drsuapi_DsReplicaAttrValMetaDataCtr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaAttrValMetaDataCtr *r);
+void ndr_print_drsuapi_DsReplicaCursor2Ctr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaCursor2Ctr *r);
+void ndr_print_drsuapi_DsReplicaCursor3(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaCursor3 *r);
+void ndr_print_drsuapi_DsReplicaCursor3Ctr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaCursor3Ctr *r);
+void ndr_print_drsuapi_DsReplicaObjMetaData2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjMetaData2 *r);
+void ndr_print_drsuapi_DsReplicaObjMetaData2Ctr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjMetaData2Ctr *r);
+void ndr_print_drsuapi_DsReplicaAttrValMetaData2(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaAttrValMetaData2 *r);
+void ndr_print_drsuapi_DsReplicaAttrValMetaData2Ctr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaAttrValMetaData2Ctr *r);
+void ndr_print_drsuapi_DsReplicaConnection04(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaConnection04 *r);
+void ndr_print_drsuapi_DsReplicaConnection04Ctr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaConnection04Ctr *r);
+void ndr_print_drsuapi_DsReplica06(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplica06 *r);
+void ndr_print_drsuapi_DsReplica06Ctr(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplica06Ctr *r);
+void ndr_print_drsuapi_DsReplicaInfo(struct ndr_print *ndr, const char *name, const union drsuapi_DsReplicaInfo *r);
+void ndr_print_drsuapi_DsGetMemberships2Ctr(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetMemberships2Ctr *r);
+void ndr_print_drsuapi_DsGetMemberships2Request1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsGetMemberships2Request1 *r);
+void ndr_print_drsuapi_DsGetMemberships2Request(struct ndr_print *ndr, const char *name, const union drsuapi_DsGetMemberships2Request *r);
+void ndr_print_drsuapi_DsSiteCostInfo(struct ndr_print *ndr, const char *name, const struct drsuapi_DsSiteCostInfo *r);
+void ndr_print_drsuapi_QuerySitesByCostCtr1(struct ndr_print *ndr, const char *name, const struct drsuapi_QuerySitesByCostCtr1 *r);
+void ndr_print_drsuapi_QuerySitesByCostCtr(struct ndr_print *ndr, const char *name, const union drsuapi_QuerySitesByCostCtr *r);
+void ndr_print_drsuapi_QuerySitesByCostRequest1(struct ndr_print *ndr, const char *name, const struct drsuapi_QuerySitesByCostRequest1 *r);
+void ndr_print_drsuapi_QuerySitesByCostRequest(struct ndr_print *ndr, const char *name, const union drsuapi_QuerySitesByCostRequest *r);
+enum ndr_err_code ndr_push_drsuapi_DsBind(struct ndr_push *ndr, int flags, const struct drsuapi_DsBind *r);
+enum ndr_err_code ndr_pull_drsuapi_DsBind(struct ndr_pull *ndr, int flags, struct drsuapi_DsBind *r);
+void ndr_print_drsuapi_DsBind(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsBind *r);
+void ndr_print_drsuapi_DsUnbind(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsUnbind *r);
+void ndr_print_drsuapi_DsReplicaSync(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsReplicaSync *r);
+void ndr_print_drsuapi_DsGetNCChanges(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsGetNCChanges *r);
+void ndr_print_drsuapi_DsReplicaUpdateRefs(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsReplicaUpdateRefs *r);
+void ndr_print_DRSUAPI_REPLICA_ADD(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_REPLICA_ADD *r);
+void ndr_print_DRSUAPI_REPLICA_DEL(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_REPLICA_DEL *r);
+void ndr_print_DRSUAPI_REPLICA_MODIFY(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_REPLICA_MODIFY *r);
+void ndr_print_DRSUAPI_VERIFY_NAMES(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_VERIFY_NAMES *r);
+void ndr_print_drsuapi_DsGetMemberships(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsGetMemberships *r);
+void ndr_print_DRSUAPI_INTER_DOMAIN_MOVE(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_INTER_DOMAIN_MOVE *r);
+void ndr_print_drsuapi_DsGetNT4ChangeLog(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsGetNT4ChangeLog *r);
+void ndr_print_drsuapi_DsCrackNames(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsCrackNames *r);
+void ndr_print_drsuapi_DsWriteAccountSpn(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsWriteAccountSpn *r);
+void ndr_print_drsuapi_DsRemoveDSServer(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsRemoveDSServer *r);
+void ndr_print_DRSUAPI_REMOVE_DS_DOMAIN(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_REMOVE_DS_DOMAIN *r);
+void ndr_print_drsuapi_DsGetDomainControllerInfo(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsGetDomainControllerInfo *r);
+enum ndr_err_code ndr_push_drsuapi_DsAddEntry(struct ndr_push *ndr, int flags, const struct drsuapi_DsAddEntry *r);
+enum ndr_err_code ndr_pull_drsuapi_DsAddEntry(struct ndr_pull *ndr, int flags, struct drsuapi_DsAddEntry *r);
+void ndr_print_drsuapi_DsAddEntry(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsAddEntry *r);
+void ndr_print_DRSUAPI_EXECUTE_KCC(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_EXECUTE_KCC *r);
+void ndr_print_drsuapi_DsReplicaGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsReplicaGetInfo *r);
+void ndr_print_DRSUAPI_ADD_SID_HISTORY(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_ADD_SID_HISTORY *r);
+void ndr_print_drsuapi_DsGetMemberships2(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_DsGetMemberships2 *r);
+void ndr_print_DRSUAPI_REPLICA_VERIFY_OBJECTS(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_REPLICA_VERIFY_OBJECTS *r);
+void ndr_print_DRSUAPI_GET_OBJECT_EXISTENCE(struct ndr_print *ndr, const char *name, int flags, const struct DRSUAPI_GET_OBJECT_EXISTENCE *r);
+void ndr_print_drsuapi_QuerySitesByCost(struct ndr_print *ndr, const char *name, int flags, const struct drsuapi_QuerySitesByCost *r);
+#endif /* _HEADER_NDR_drsuapi */
diff --git a/source3/librpc/gen_ndr/ndr_dssetup.c b/source3/librpc/gen_ndr/ndr_dssetup.c
new file mode 100644
index 0000000000..0c02784db8
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_dssetup.c
@@ -0,0 +1,1082 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_dssetup.h"
+
+#include "librpc/gen_ndr/ndr_misc.h"
+static enum ndr_err_code ndr_push_dssetup_DsRole(struct ndr_push *ndr, int ndr_flags, enum dssetup_DsRole r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRole(struct ndr_pull *ndr, int ndr_flags, enum dssetup_DsRole *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRole(struct ndr_print *ndr, const char *name, enum dssetup_DsRole r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DS_ROLE_STANDALONE_WORKSTATION: val = "DS_ROLE_STANDALONE_WORKSTATION"; break;
+ case DS_ROLE_MEMBER_WORKSTATION: val = "DS_ROLE_MEMBER_WORKSTATION"; break;
+ case DS_ROLE_STANDALONE_SERVER: val = "DS_ROLE_STANDALONE_SERVER"; break;
+ case DS_ROLE_MEMBER_SERVER: val = "DS_ROLE_MEMBER_SERVER"; break;
+ case DS_ROLE_BACKUP_DC: val = "DS_ROLE_BACKUP_DC"; break;
+ case DS_ROLE_PRIMARY_DC: val = "DS_ROLE_PRIMARY_DC"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleFlags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_ROLE_PRIMARY_DS_RUNNING", DS_ROLE_PRIMARY_DS_RUNNING, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_ROLE_PRIMARY_DS_MIXED_MODE", DS_ROLE_PRIMARY_DS_MIXED_MODE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_ROLE_UPGRADE_IN_PROGRESS", DS_ROLE_UPGRADE_IN_PROGRESS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT", DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRolePrimaryDomInfoBasic(struct ndr_push *ndr, int ndr_flags, const struct dssetup_DsRolePrimaryDomInfoBasic *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_dssetup_DsRole(ndr, NDR_SCALARS, r->role));
+ NDR_CHECK(ndr_push_dssetup_DsRoleFlags(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->dns_domain));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->forest));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->domain_guid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->domain) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain, ndr_charset_length(r->domain, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->dns_domain) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dns_domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dns_domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dns_domain, ndr_charset_length(r->dns_domain, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->forest) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->forest, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->forest, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->forest, ndr_charset_length(r->forest, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRolePrimaryDomInfoBasic(struct ndr_pull *ndr, int ndr_flags, struct dssetup_DsRolePrimaryDomInfoBasic *r)
+{
+ uint32_t _ptr_domain;
+ TALLOC_CTX *_mem_save_domain_0;
+ uint32_t _ptr_dns_domain;
+ TALLOC_CTX *_mem_save_dns_domain_0;
+ uint32_t _ptr_forest;
+ TALLOC_CTX *_mem_save_forest_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_dssetup_DsRole(ndr, NDR_SCALARS, &r->role));
+ NDR_CHECK(ndr_pull_dssetup_DsRoleFlags(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain));
+ if (_ptr_domain) {
+ NDR_PULL_ALLOC(ndr, r->domain);
+ } else {
+ r->domain = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dns_domain));
+ if (_ptr_dns_domain) {
+ NDR_PULL_ALLOC(ndr, r->dns_domain);
+ } else {
+ r->dns_domain = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_forest));
+ if (_ptr_forest) {
+ NDR_PULL_ALLOC(ndr, r->forest);
+ } else {
+ r->forest = NULL;
+ }
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->domain_guid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->domain) {
+ _mem_save_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain));
+ if (ndr_get_array_length(ndr, &r->domain) > ndr_get_array_size(ndr, &r->domain)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain), ndr_get_array_length(ndr, &r->domain));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_0, 0);
+ }
+ if (r->dns_domain) {
+ _mem_save_dns_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->dns_domain, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->dns_domain));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->dns_domain));
+ if (ndr_get_array_length(ndr, &r->dns_domain) > ndr_get_array_size(ndr, &r->dns_domain)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->dns_domain), ndr_get_array_length(ndr, &r->dns_domain));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->dns_domain), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dns_domain, ndr_get_array_length(ndr, &r->dns_domain), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dns_domain_0, 0);
+ }
+ if (r->forest) {
+ _mem_save_forest_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->forest, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->forest));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->forest));
+ if (ndr_get_array_length(ndr, &r->forest) > ndr_get_array_size(ndr, &r->forest)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->forest), ndr_get_array_length(ndr, &r->forest));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->forest), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->forest, ndr_get_array_length(ndr, &r->forest), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_forest_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRolePrimaryDomInfoBasic(struct ndr_print *ndr, const char *name, const struct dssetup_DsRolePrimaryDomInfoBasic *r)
+{
+ ndr_print_struct(ndr, name, "dssetup_DsRolePrimaryDomInfoBasic");
+ ndr->depth++;
+ ndr_print_dssetup_DsRole(ndr, "role", r->role);
+ ndr_print_dssetup_DsRoleFlags(ndr, "flags", r->flags);
+ ndr_print_ptr(ndr, "domain", r->domain);
+ ndr->depth++;
+ if (r->domain) {
+ ndr_print_string(ndr, "domain", r->domain);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "dns_domain", r->dns_domain);
+ ndr->depth++;
+ if (r->dns_domain) {
+ ndr_print_string(ndr, "dns_domain", r->dns_domain);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "forest", r->forest);
+ ndr->depth++;
+ if (r->forest) {
+ ndr_print_string(ndr, "forest", r->forest);
+ }
+ ndr->depth--;
+ ndr_print_GUID(ndr, "domain_guid", &r->domain_guid);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsUpgrade(struct ndr_push *ndr, int ndr_flags, enum dssetup_DsUpgrade r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsUpgrade(struct ndr_pull *ndr, int ndr_flags, enum dssetup_DsUpgrade *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsUpgrade(struct ndr_print *ndr, const char *name, enum dssetup_DsUpgrade r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DS_ROLE_NOT_UPGRADING: val = "DS_ROLE_NOT_UPGRADING"; break;
+ case DS_ROLE_UPGRADING: val = "DS_ROLE_UPGRADING"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsPrevious(struct ndr_push *ndr, int ndr_flags, enum dssetup_DsPrevious r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsPrevious(struct ndr_pull *ndr, int ndr_flags, enum dssetup_DsPrevious *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsPrevious(struct ndr_print *ndr, const char *name, enum dssetup_DsPrevious r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DS_ROLE_PREVIOUS_UNKNOWN: val = "DS_ROLE_PREVIOUS_UNKNOWN"; break;
+ case DS_ROLE_PREVIOUS_PRIMARY: val = "DS_ROLE_PREVIOUS_PRIMARY"; break;
+ case DS_ROLE_PREVIOUS_BACKUP: val = "DS_ROLE_PREVIOUS_BACKUP"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleUpgradeStatus(struct ndr_push *ndr, int ndr_flags, const struct dssetup_DsRoleUpgradeStatus *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_dssetup_DsUpgrade(ndr, NDR_SCALARS, r->upgrading));
+ NDR_CHECK(ndr_push_dssetup_DsPrevious(ndr, NDR_SCALARS, r->previous_role));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleUpgradeStatus(struct ndr_pull *ndr, int ndr_flags, struct dssetup_DsRoleUpgradeStatus *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_dssetup_DsUpgrade(ndr, NDR_SCALARS, &r->upgrading));
+ NDR_CHECK(ndr_pull_dssetup_DsPrevious(ndr, NDR_SCALARS, &r->previous_role));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleUpgradeStatus(struct ndr_print *ndr, const char *name, const struct dssetup_DsRoleUpgradeStatus *r)
+{
+ ndr_print_struct(ndr, name, "dssetup_DsRoleUpgradeStatus");
+ ndr->depth++;
+ ndr_print_dssetup_DsUpgrade(ndr, "upgrading", r->upgrading);
+ ndr_print_dssetup_DsPrevious(ndr, "previous_role", r->previous_role);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleOp(struct ndr_push *ndr, int ndr_flags, enum dssetup_DsRoleOp r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleOp(struct ndr_pull *ndr, int ndr_flags, enum dssetup_DsRoleOp *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleOp(struct ndr_print *ndr, const char *name, enum dssetup_DsRoleOp r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DS_ROLE_OP_IDLE: val = "DS_ROLE_OP_IDLE"; break;
+ case DS_ROLE_OP_ACTIVE: val = "DS_ROLE_OP_ACTIVE"; break;
+ case DS_ROLE_OP_NEEDS_REBOOT: val = "DS_ROLE_OP_NEEDS_REBOOT"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleOpStatus(struct ndr_push *ndr, int ndr_flags, const struct dssetup_DsRoleOpStatus *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_dssetup_DsRoleOp(ndr, NDR_SCALARS, r->status));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleOpStatus(struct ndr_pull *ndr, int ndr_flags, struct dssetup_DsRoleOpStatus *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_dssetup_DsRoleOp(ndr, NDR_SCALARS, &r->status));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleOpStatus(struct ndr_print *ndr, const char *name, const struct dssetup_DsRoleOpStatus *r)
+{
+ ndr_print_struct(ndr, name, "dssetup_DsRoleOpStatus");
+ ndr->depth++;
+ ndr_print_dssetup_DsRoleOp(ndr, "status", r->status);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleInfoLevel(struct ndr_push *ndr, int ndr_flags, enum dssetup_DsRoleInfoLevel r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleInfoLevel(struct ndr_pull *ndr, int ndr_flags, enum dssetup_DsRoleInfoLevel *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleInfoLevel(struct ndr_print *ndr, const char *name, enum dssetup_DsRoleInfoLevel r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DS_ROLE_BASIC_INFORMATION: val = "DS_ROLE_BASIC_INFORMATION"; break;
+ case DS_ROLE_UPGRADE_STATUS: val = "DS_ROLE_UPGRADE_STATUS"; break;
+ case DS_ROLE_OP_STATUS: val = "DS_ROLE_OP_STATUS"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleInfo(struct ndr_push *ndr, int ndr_flags, const union dssetup_DsRoleInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_dssetup_DsRoleInfoLevel(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case DS_ROLE_BASIC_INFORMATION: {
+ NDR_CHECK(ndr_push_dssetup_DsRolePrimaryDomInfoBasic(ndr, NDR_SCALARS, &r->basic));
+ break; }
+
+ case DS_ROLE_UPGRADE_STATUS: {
+ NDR_CHECK(ndr_push_dssetup_DsRoleUpgradeStatus(ndr, NDR_SCALARS, &r->upgrade));
+ break; }
+
+ case DS_ROLE_OP_STATUS: {
+ NDR_CHECK(ndr_push_dssetup_DsRoleOpStatus(ndr, NDR_SCALARS, &r->opstatus));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case DS_ROLE_BASIC_INFORMATION:
+ NDR_CHECK(ndr_push_dssetup_DsRolePrimaryDomInfoBasic(ndr, NDR_BUFFERS, &r->basic));
+ break;
+
+ case DS_ROLE_UPGRADE_STATUS:
+ break;
+
+ case DS_ROLE_OP_STATUS:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleInfo(struct ndr_pull *ndr, int ndr_flags, union dssetup_DsRoleInfo *r)
+{
+ int level;
+ uint16_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case DS_ROLE_BASIC_INFORMATION: {
+ NDR_CHECK(ndr_pull_dssetup_DsRolePrimaryDomInfoBasic(ndr, NDR_SCALARS, &r->basic));
+ break; }
+
+ case DS_ROLE_UPGRADE_STATUS: {
+ NDR_CHECK(ndr_pull_dssetup_DsRoleUpgradeStatus(ndr, NDR_SCALARS, &r->upgrade));
+ break; }
+
+ case DS_ROLE_OP_STATUS: {
+ NDR_CHECK(ndr_pull_dssetup_DsRoleOpStatus(ndr, NDR_SCALARS, &r->opstatus));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case DS_ROLE_BASIC_INFORMATION:
+ NDR_CHECK(ndr_pull_dssetup_DsRolePrimaryDomInfoBasic(ndr, NDR_BUFFERS, &r->basic));
+ break;
+
+ case DS_ROLE_UPGRADE_STATUS:
+ break;
+
+ case DS_ROLE_OP_STATUS:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleInfo(struct ndr_print *ndr, const char *name, const union dssetup_DsRoleInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "dssetup_DsRoleInfo");
+ switch (level) {
+ case DS_ROLE_BASIC_INFORMATION:
+ ndr_print_dssetup_DsRolePrimaryDomInfoBasic(ndr, "basic", &r->basic);
+ break;
+
+ case DS_ROLE_UPGRADE_STATUS:
+ ndr_print_dssetup_DsRoleUpgradeStatus(ndr, "upgrade", &r->upgrade);
+ break;
+
+ case DS_ROLE_OP_STATUS:
+ ndr_print_dssetup_DsRoleOpStatus(ndr, "opstatus", &r->opstatus);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleGetPrimaryDomainInformation(struct ndr_push *ndr, int flags, const struct dssetup_DsRoleGetPrimaryDomainInformation *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_dssetup_DsRoleInfoLevel(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.info));
+ if (r->out.info) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_dssetup_DsRoleInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleGetPrimaryDomainInformation(struct ndr_pull *ndr, int flags, struct dssetup_DsRoleGetPrimaryDomainInformation *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_dssetup_DsRoleInfoLevel(ndr, NDR_SCALARS, &r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ } else {
+ r->out.info = NULL;
+ }
+ if (r->out.info) {
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, 0);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_dssetup_DsRoleInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleGetPrimaryDomainInformation(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleGetPrimaryDomainInformation *r)
+{
+ ndr_print_struct(ndr, name, "dssetup_DsRoleGetPrimaryDomainInformation");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dssetup_DsRoleGetPrimaryDomainInformation");
+ ndr->depth++;
+ ndr_print_dssetup_DsRoleInfoLevel(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dssetup_DsRoleGetPrimaryDomainInformation");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ if (r->out.info) {
+ ndr_print_set_switch_value(ndr, r->out.info, r->in.level);
+ ndr_print_dssetup_DsRoleInfo(ndr, "info", r->out.info);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleDnsNameToFlatName(struct ndr_push *ndr, int flags, const struct dssetup_DsRoleDnsNameToFlatName *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleDnsNameToFlatName(struct ndr_pull *ndr, int flags, struct dssetup_DsRoleDnsNameToFlatName *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleDnsNameToFlatName(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleDnsNameToFlatName *r)
+{
+ ndr_print_struct(ndr, name, "dssetup_DsRoleDnsNameToFlatName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dssetup_DsRoleDnsNameToFlatName");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dssetup_DsRoleDnsNameToFlatName");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleDcAsDc(struct ndr_push *ndr, int flags, const struct dssetup_DsRoleDcAsDc *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleDcAsDc(struct ndr_pull *ndr, int flags, struct dssetup_DsRoleDcAsDc *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleDcAsDc(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleDcAsDc *r)
+{
+ ndr_print_struct(ndr, name, "dssetup_DsRoleDcAsDc");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dssetup_DsRoleDcAsDc");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dssetup_DsRoleDcAsDc");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleDcAsReplica(struct ndr_push *ndr, int flags, const struct dssetup_DsRoleDcAsReplica *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleDcAsReplica(struct ndr_pull *ndr, int flags, struct dssetup_DsRoleDcAsReplica *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleDcAsReplica(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleDcAsReplica *r)
+{
+ ndr_print_struct(ndr, name, "dssetup_DsRoleDcAsReplica");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dssetup_DsRoleDcAsReplica");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dssetup_DsRoleDcAsReplica");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleDemoteDc(struct ndr_push *ndr, int flags, const struct dssetup_DsRoleDemoteDc *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleDemoteDc(struct ndr_pull *ndr, int flags, struct dssetup_DsRoleDemoteDc *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleDemoteDc(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleDemoteDc *r)
+{
+ ndr_print_struct(ndr, name, "dssetup_DsRoleDemoteDc");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dssetup_DsRoleDemoteDc");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dssetup_DsRoleDemoteDc");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleGetDcOperationProgress(struct ndr_push *ndr, int flags, const struct dssetup_DsRoleGetDcOperationProgress *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleGetDcOperationProgress(struct ndr_pull *ndr, int flags, struct dssetup_DsRoleGetDcOperationProgress *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleGetDcOperationProgress(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleGetDcOperationProgress *r)
+{
+ ndr_print_struct(ndr, name, "dssetup_DsRoleGetDcOperationProgress");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dssetup_DsRoleGetDcOperationProgress");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dssetup_DsRoleGetDcOperationProgress");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleGetDcOperationResults(struct ndr_push *ndr, int flags, const struct dssetup_DsRoleGetDcOperationResults *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleGetDcOperationResults(struct ndr_pull *ndr, int flags, struct dssetup_DsRoleGetDcOperationResults *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleGetDcOperationResults(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleGetDcOperationResults *r)
+{
+ ndr_print_struct(ndr, name, "dssetup_DsRoleGetDcOperationResults");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dssetup_DsRoleGetDcOperationResults");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dssetup_DsRoleGetDcOperationResults");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleCancel(struct ndr_push *ndr, int flags, const struct dssetup_DsRoleCancel *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleCancel(struct ndr_pull *ndr, int flags, struct dssetup_DsRoleCancel *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleCancel(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleCancel *r)
+{
+ ndr_print_struct(ndr, name, "dssetup_DsRoleCancel");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dssetup_DsRoleCancel");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dssetup_DsRoleCancel");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleServerSaveStateForUpgrade(struct ndr_push *ndr, int flags, const struct dssetup_DsRoleServerSaveStateForUpgrade *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleServerSaveStateForUpgrade(struct ndr_pull *ndr, int flags, struct dssetup_DsRoleServerSaveStateForUpgrade *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleServerSaveStateForUpgrade(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleServerSaveStateForUpgrade *r)
+{
+ ndr_print_struct(ndr, name, "dssetup_DsRoleServerSaveStateForUpgrade");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dssetup_DsRoleServerSaveStateForUpgrade");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dssetup_DsRoleServerSaveStateForUpgrade");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleUpgradeDownlevelServer(struct ndr_push *ndr, int flags, const struct dssetup_DsRoleUpgradeDownlevelServer *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleUpgradeDownlevelServer(struct ndr_pull *ndr, int flags, struct dssetup_DsRoleUpgradeDownlevelServer *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleUpgradeDownlevelServer(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleUpgradeDownlevelServer *r)
+{
+ ndr_print_struct(ndr, name, "dssetup_DsRoleUpgradeDownlevelServer");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dssetup_DsRoleUpgradeDownlevelServer");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dssetup_DsRoleUpgradeDownlevelServer");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dssetup_DsRoleAbortDownlevelServerUpgrade(struct ndr_push *ndr, int flags, const struct dssetup_DsRoleAbortDownlevelServerUpgrade *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dssetup_DsRoleAbortDownlevelServerUpgrade(struct ndr_pull *ndr, int flags, struct dssetup_DsRoleAbortDownlevelServerUpgrade *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dssetup_DsRoleAbortDownlevelServerUpgrade(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleAbortDownlevelServerUpgrade *r)
+{
+ ndr_print_struct(ndr, name, "dssetup_DsRoleAbortDownlevelServerUpgrade");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "dssetup_DsRoleAbortDownlevelServerUpgrade");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "dssetup_DsRoleAbortDownlevelServerUpgrade");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call dssetup_calls[] = {
+ {
+ "dssetup_DsRoleGetPrimaryDomainInformation",
+ sizeof(struct dssetup_DsRoleGetPrimaryDomainInformation),
+ (ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleGetPrimaryDomainInformation,
+ (ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleGetPrimaryDomainInformation,
+ (ndr_print_function_t) ndr_print_dssetup_DsRoleGetPrimaryDomainInformation,
+ false,
+ },
+ {
+ "dssetup_DsRoleDnsNameToFlatName",
+ sizeof(struct dssetup_DsRoleDnsNameToFlatName),
+ (ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleDnsNameToFlatName,
+ (ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleDnsNameToFlatName,
+ (ndr_print_function_t) ndr_print_dssetup_DsRoleDnsNameToFlatName,
+ false,
+ },
+ {
+ "dssetup_DsRoleDcAsDc",
+ sizeof(struct dssetup_DsRoleDcAsDc),
+ (ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleDcAsDc,
+ (ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleDcAsDc,
+ (ndr_print_function_t) ndr_print_dssetup_DsRoleDcAsDc,
+ false,
+ },
+ {
+ "dssetup_DsRoleDcAsReplica",
+ sizeof(struct dssetup_DsRoleDcAsReplica),
+ (ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleDcAsReplica,
+ (ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleDcAsReplica,
+ (ndr_print_function_t) ndr_print_dssetup_DsRoleDcAsReplica,
+ false,
+ },
+ {
+ "dssetup_DsRoleDemoteDc",
+ sizeof(struct dssetup_DsRoleDemoteDc),
+ (ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleDemoteDc,
+ (ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleDemoteDc,
+ (ndr_print_function_t) ndr_print_dssetup_DsRoleDemoteDc,
+ false,
+ },
+ {
+ "dssetup_DsRoleGetDcOperationProgress",
+ sizeof(struct dssetup_DsRoleGetDcOperationProgress),
+ (ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleGetDcOperationProgress,
+ (ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleGetDcOperationProgress,
+ (ndr_print_function_t) ndr_print_dssetup_DsRoleGetDcOperationProgress,
+ false,
+ },
+ {
+ "dssetup_DsRoleGetDcOperationResults",
+ sizeof(struct dssetup_DsRoleGetDcOperationResults),
+ (ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleGetDcOperationResults,
+ (ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleGetDcOperationResults,
+ (ndr_print_function_t) ndr_print_dssetup_DsRoleGetDcOperationResults,
+ false,
+ },
+ {
+ "dssetup_DsRoleCancel",
+ sizeof(struct dssetup_DsRoleCancel),
+ (ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleCancel,
+ (ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleCancel,
+ (ndr_print_function_t) ndr_print_dssetup_DsRoleCancel,
+ false,
+ },
+ {
+ "dssetup_DsRoleServerSaveStateForUpgrade",
+ sizeof(struct dssetup_DsRoleServerSaveStateForUpgrade),
+ (ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleServerSaveStateForUpgrade,
+ (ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleServerSaveStateForUpgrade,
+ (ndr_print_function_t) ndr_print_dssetup_DsRoleServerSaveStateForUpgrade,
+ false,
+ },
+ {
+ "dssetup_DsRoleUpgradeDownlevelServer",
+ sizeof(struct dssetup_DsRoleUpgradeDownlevelServer),
+ (ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleUpgradeDownlevelServer,
+ (ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleUpgradeDownlevelServer,
+ (ndr_print_function_t) ndr_print_dssetup_DsRoleUpgradeDownlevelServer,
+ false,
+ },
+ {
+ "dssetup_DsRoleAbortDownlevelServerUpgrade",
+ sizeof(struct dssetup_DsRoleAbortDownlevelServerUpgrade),
+ (ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleAbortDownlevelServerUpgrade,
+ (ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleAbortDownlevelServerUpgrade,
+ (ndr_print_function_t) ndr_print_dssetup_DsRoleAbortDownlevelServerUpgrade,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const dssetup_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\lsarpc]",
+ "ncacn_np:[\\pipe\\lsass]",
+ "ncacn_ip_tcp:",
+ "ncalrpc:",
+};
+
+static const struct ndr_interface_string_array dssetup_endpoints = {
+ .count = 4,
+ .names = dssetup_endpoint_strings
+};
+
+static const char * const dssetup_authservice_strings[] = {
+ "host",
+};
+
+static const struct ndr_interface_string_array dssetup_authservices = {
+ .count = 1,
+ .names = dssetup_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_dssetup = {
+ .name = "dssetup",
+ .syntax_id = {
+ {0x3919286a,0xb10c,0x11d0,{0x9b,0xa8},{0x00,0xc0,0x4f,0xd9,0x2e,0xf5}},
+ NDR_DSSETUP_VERSION
+ },
+ .helpstring = NDR_DSSETUP_HELPSTRING,
+ .num_calls = 11,
+ .calls = dssetup_calls,
+ .endpoints = &dssetup_endpoints,
+ .authservices = &dssetup_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_dssetup.h b/source3/librpc/gen_ndr/ndr_dssetup.h
new file mode 100644
index 0000000000..103ad116a3
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_dssetup.h
@@ -0,0 +1,58 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/dssetup.h"
+
+#ifndef _HEADER_NDR_dssetup
+#define _HEADER_NDR_dssetup
+
+#define NDR_DSSETUP_UUID "3919286a-b10c-11d0-9ba8-00c04fd92ef5"
+#define NDR_DSSETUP_VERSION 0.0
+#define NDR_DSSETUP_NAME "dssetup"
+#define NDR_DSSETUP_HELPSTRING "Active Directory Setup"
+extern const struct ndr_interface_table ndr_table_dssetup;
+#define NDR_DSSETUP_DSROLEGETPRIMARYDOMAININFORMATION (0x00)
+
+#define NDR_DSSETUP_DSROLEDNSNAMETOFLATNAME (0x01)
+
+#define NDR_DSSETUP_DSROLEDCASDC (0x02)
+
+#define NDR_DSSETUP_DSROLEDCASREPLICA (0x03)
+
+#define NDR_DSSETUP_DSROLEDEMOTEDC (0x04)
+
+#define NDR_DSSETUP_DSROLEGETDCOPERATIONPROGRESS (0x05)
+
+#define NDR_DSSETUP_DSROLEGETDCOPERATIONRESULTS (0x06)
+
+#define NDR_DSSETUP_DSROLECANCEL (0x07)
+
+#define NDR_DSSETUP_DSROLESERVERSAVESTATEFORUPGRADE (0x08)
+
+#define NDR_DSSETUP_DSROLEUPGRADEDOWNLEVELSERVER (0x09)
+
+#define NDR_DSSETUP_DSROLEABORTDOWNLEVELSERVERUPGRADE (0x0a)
+
+#define NDR_DSSETUP_CALL_COUNT (11)
+void ndr_print_dssetup_DsRole(struct ndr_print *ndr, const char *name, enum dssetup_DsRole r);
+void ndr_print_dssetup_DsRoleFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_dssetup_DsRolePrimaryDomInfoBasic(struct ndr_print *ndr, const char *name, const struct dssetup_DsRolePrimaryDomInfoBasic *r);
+void ndr_print_dssetup_DsUpgrade(struct ndr_print *ndr, const char *name, enum dssetup_DsUpgrade r);
+void ndr_print_dssetup_DsPrevious(struct ndr_print *ndr, const char *name, enum dssetup_DsPrevious r);
+void ndr_print_dssetup_DsRoleUpgradeStatus(struct ndr_print *ndr, const char *name, const struct dssetup_DsRoleUpgradeStatus *r);
+void ndr_print_dssetup_DsRoleOp(struct ndr_print *ndr, const char *name, enum dssetup_DsRoleOp r);
+void ndr_print_dssetup_DsRoleOpStatus(struct ndr_print *ndr, const char *name, const struct dssetup_DsRoleOpStatus *r);
+void ndr_print_dssetup_DsRoleInfoLevel(struct ndr_print *ndr, const char *name, enum dssetup_DsRoleInfoLevel r);
+void ndr_print_dssetup_DsRoleInfo(struct ndr_print *ndr, const char *name, const union dssetup_DsRoleInfo *r);
+void ndr_print_dssetup_DsRoleGetPrimaryDomainInformation(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleGetPrimaryDomainInformation *r);
+void ndr_print_dssetup_DsRoleDnsNameToFlatName(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleDnsNameToFlatName *r);
+void ndr_print_dssetup_DsRoleDcAsDc(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleDcAsDc *r);
+void ndr_print_dssetup_DsRoleDcAsReplica(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleDcAsReplica *r);
+void ndr_print_dssetup_DsRoleDemoteDc(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleDemoteDc *r);
+void ndr_print_dssetup_DsRoleGetDcOperationProgress(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleGetDcOperationProgress *r);
+void ndr_print_dssetup_DsRoleGetDcOperationResults(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleGetDcOperationResults *r);
+void ndr_print_dssetup_DsRoleCancel(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleCancel *r);
+void ndr_print_dssetup_DsRoleServerSaveStateForUpgrade(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleServerSaveStateForUpgrade *r);
+void ndr_print_dssetup_DsRoleUpgradeDownlevelServer(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleUpgradeDownlevelServer *r);
+void ndr_print_dssetup_DsRoleAbortDownlevelServerUpgrade(struct ndr_print *ndr, const char *name, int flags, const struct dssetup_DsRoleAbortDownlevelServerUpgrade *r);
+#endif /* _HEADER_NDR_dssetup */
diff --git a/source3/librpc/gen_ndr/ndr_echo.c b/source3/librpc/gen_ndr/ndr_echo.c
new file mode 100644
index 0000000000..93a8464c7b
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_echo.c
@@ -0,0 +1,1513 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_echo.h"
+
+static enum ndr_err_code ndr_push_echo_info1(struct ndr_push *ndr, int ndr_flags, const struct echo_info1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->v));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_info1(struct ndr_pull *ndr, int ndr_flags, struct echo_info1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->v));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_info1(struct ndr_print *ndr, const char *name, const struct echo_info1 *r)
+{
+ ndr_print_struct(ndr, name, "echo_info1");
+ ndr->depth++;
+ ndr_print_uint8(ndr, "v", r->v);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_info2(struct ndr_push *ndr, int ndr_flags, const struct echo_info2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->v));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_info2(struct ndr_pull *ndr, int ndr_flags, struct echo_info2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->v));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_info2(struct ndr_print *ndr, const char *name, const struct echo_info2 *r)
+{
+ ndr_print_struct(ndr, name, "echo_info2");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "v", r->v);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_info3(struct ndr_push *ndr, int ndr_flags, const struct echo_info3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->v));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_info3(struct ndr_pull *ndr, int ndr_flags, struct echo_info3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->v));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_info3(struct ndr_print *ndr, const char *name, const struct echo_info3 *r)
+{
+ ndr_print_struct(ndr, name, "echo_info3");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "v", r->v);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_STRUCT_echo_info4(struct ndr_push *ndr, int ndr_flags, const struct echo_info4 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->v));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_STRUCT_echo_info4(struct ndr_pull *ndr, int ndr_flags, struct echo_info4 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->v));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_STRUCT_echo_info4(struct ndr_print *ndr, const char *name, const struct echo_info4 *r)
+{
+ ndr_print_struct(ndr, name, "echo_info4");
+ ndr->depth++;
+ ndr_print_hyper(ndr, "v", r->v);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_info5(struct ndr_push *ndr, int ndr_flags, const struct echo_info5 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->v1));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->v2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_info5(struct ndr_pull *ndr, int ndr_flags, struct echo_info5 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->v1));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->v2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_info5(struct ndr_print *ndr, const char *name, const struct echo_info5 *r)
+{
+ ndr_print_struct(ndr, name, "echo_info5");
+ ndr->depth++;
+ ndr_print_uint8(ndr, "v1", r->v1);
+ ndr_print_hyper(ndr, "v2", r->v2);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_info6(struct ndr_push *ndr, int ndr_flags, const struct echo_info6 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->v1));
+ NDR_CHECK(ndr_push_echo_info1(ndr, NDR_SCALARS, &r->info1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_info6(struct ndr_pull *ndr, int ndr_flags, struct echo_info6 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->v1));
+ NDR_CHECK(ndr_pull_echo_info1(ndr, NDR_SCALARS, &r->info1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_info6(struct ndr_print *ndr, const char *name, const struct echo_info6 *r)
+{
+ ndr_print_struct(ndr, name, "echo_info6");
+ ndr->depth++;
+ ndr_print_uint8(ndr, "v1", r->v1);
+ ndr_print_echo_info1(ndr, "info1", &r->info1);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_info7(struct ndr_push *ndr, int ndr_flags, const struct echo_info7 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->v1));
+ NDR_CHECK(ndr_push_STRUCT_echo_info4(ndr, NDR_SCALARS, &r->info4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_info7(struct ndr_pull *ndr, int ndr_flags, struct echo_info7 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->v1));
+ NDR_CHECK(ndr_pull_STRUCT_echo_info4(ndr, NDR_SCALARS, &r->info4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_info7(struct ndr_print *ndr, const char *name, const struct echo_info7 *r)
+{
+ ndr_print_struct(ndr, name, "echo_info7");
+ ndr->depth++;
+ ndr_print_uint8(ndr, "v1", r->v1);
+ ndr_print_STRUCT_echo_info4(ndr, "info4", &r->info4);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_Info(struct ndr_push *ndr, int ndr_flags, const union echo_Info *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_echo_info1(ndr, NDR_SCALARS, &r->info1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_echo_info2(ndr, NDR_SCALARS, &r->info2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_echo_info3(ndr, NDR_SCALARS, &r->info3));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_push_STRUCT_echo_info4(ndr, NDR_SCALARS, &r->info4));
+ break; }
+
+ case 5: {
+ NDR_CHECK(ndr_push_echo_info5(ndr, NDR_SCALARS, &r->info5));
+ break; }
+
+ case 6: {
+ NDR_CHECK(ndr_push_echo_info6(ndr, NDR_SCALARS, &r->info6));
+ break; }
+
+ case 7: {
+ NDR_CHECK(ndr_push_echo_info7(ndr, NDR_SCALARS, &r->info7));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ break;
+
+ case 2:
+ break;
+
+ case 3:
+ break;
+
+ case 4:
+ break;
+
+ case 5:
+ break;
+
+ case 6:
+ break;
+
+ case 7:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_Info(struct ndr_pull *ndr, int ndr_flags, union echo_Info *r)
+{
+ int level;
+ uint16_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_echo_info1(ndr, NDR_SCALARS, &r->info1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_pull_echo_info2(ndr, NDR_SCALARS, &r->info2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_pull_echo_info3(ndr, NDR_SCALARS, &r->info3));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_pull_STRUCT_echo_info4(ndr, NDR_SCALARS, &r->info4));
+ break; }
+
+ case 5: {
+ NDR_CHECK(ndr_pull_echo_info5(ndr, NDR_SCALARS, &r->info5));
+ break; }
+
+ case 6: {
+ NDR_CHECK(ndr_pull_echo_info6(ndr, NDR_SCALARS, &r->info6));
+ break; }
+
+ case 7: {
+ NDR_CHECK(ndr_pull_echo_info7(ndr, NDR_SCALARS, &r->info7));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ break;
+
+ case 2:
+ break;
+
+ case 3:
+ break;
+
+ case 4:
+ break;
+
+ case 5:
+ break;
+
+ case 6:
+ break;
+
+ case 7:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_Info(struct ndr_print *ndr, const char *name, const union echo_Info *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "echo_Info");
+ switch (level) {
+ case 1:
+ ndr_print_echo_info1(ndr, "info1", &r->info1);
+ break;
+
+ case 2:
+ ndr_print_echo_info2(ndr, "info2", &r->info2);
+ break;
+
+ case 3:
+ ndr_print_echo_info3(ndr, "info3", &r->info3);
+ break;
+
+ case 4:
+ ndr_print_STRUCT_echo_info4(ndr, "info4", &r->info4);
+ break;
+
+ case 5:
+ ndr_print_echo_info5(ndr, "info5", &r->info5);
+ break;
+
+ case 6:
+ ndr_print_echo_info6(ndr, "info6", &r->info6);
+ break;
+
+ case 7:
+ ndr_print_echo_info7(ndr, "info7", &r->info7);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_echo_Enum1(struct ndr_push *ndr, int ndr_flags, enum echo_Enum1 r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_Enum1(struct ndr_pull *ndr, int ndr_flags, enum echo_Enum1 *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_Enum1(struct ndr_print *ndr, const char *name, enum echo_Enum1 r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case ECHO_ENUM1: val = "ECHO_ENUM1"; break;
+ case ECHO_ENUM2: val = "ECHO_ENUM2"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_echo_Enum1_32(struct ndr_push *ndr, int ndr_flags, enum echo_Enum1_32 r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_Enum1_32(struct ndr_pull *ndr, int ndr_flags, enum echo_Enum1_32 *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_Enum1_32(struct ndr_print *ndr, const char *name, enum echo_Enum1_32 r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case ECHO_ENUM1_32: val = "ECHO_ENUM1_32"; break;
+ case ECHO_ENUM2_32: val = "ECHO_ENUM2_32"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_echo_Enum2(struct ndr_push *ndr, int ndr_flags, const struct echo_Enum2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_echo_Enum1(ndr, NDR_SCALARS, r->e1));
+ NDR_CHECK(ndr_push_echo_Enum1_32(ndr, NDR_SCALARS, r->e2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_Enum2(struct ndr_pull *ndr, int ndr_flags, struct echo_Enum2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_echo_Enum1(ndr, NDR_SCALARS, &r->e1));
+ NDR_CHECK(ndr_pull_echo_Enum1_32(ndr, NDR_SCALARS, &r->e2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_Enum2(struct ndr_print *ndr, const char *name, const struct echo_Enum2 *r)
+{
+ ndr_print_struct(ndr, name, "echo_Enum2");
+ ndr->depth++;
+ ndr_print_echo_Enum1(ndr, "e1", r->e1);
+ ndr_print_echo_Enum1_32(ndr, "e2", r->e2);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_Enum3(struct ndr_push *ndr, int ndr_flags, const union echo_Enum3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case ECHO_ENUM1: {
+ NDR_CHECK(ndr_push_echo_Enum1(ndr, NDR_SCALARS, r->e1));
+ break; }
+
+ case ECHO_ENUM2: {
+ NDR_CHECK(ndr_push_echo_Enum2(ndr, NDR_SCALARS, &r->e2));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case ECHO_ENUM1:
+ break;
+
+ case ECHO_ENUM2:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_Enum3(struct ndr_pull *ndr, int ndr_flags, union echo_Enum3 *r)
+{
+ int level;
+ uint16_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case ECHO_ENUM1: {
+ NDR_CHECK(ndr_pull_echo_Enum1(ndr, NDR_SCALARS, &r->e1));
+ break; }
+
+ case ECHO_ENUM2: {
+ NDR_CHECK(ndr_pull_echo_Enum2(ndr, NDR_SCALARS, &r->e2));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case ECHO_ENUM1:
+ break;
+
+ case ECHO_ENUM2:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_Enum3(struct ndr_print *ndr, const char *name, const union echo_Enum3 *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "echo_Enum3");
+ switch (level) {
+ case ECHO_ENUM1:
+ ndr_print_echo_Enum1(ndr, "e1", r->e1);
+ break;
+
+ case ECHO_ENUM2:
+ ndr_print_echo_Enum2(ndr, "e2", &r->e2);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_echo_Surrounding(struct ndr_push *ndr, int ndr_flags, const struct echo_Surrounding *r)
+{
+ uint32_t cntr_surrounding_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->x));
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->x));
+ for (cntr_surrounding_0 = 0; cntr_surrounding_0 < r->x; cntr_surrounding_0++) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->surrounding[cntr_surrounding_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_Surrounding(struct ndr_pull *ndr, int ndr_flags, struct echo_Surrounding *r)
+{
+ uint32_t cntr_surrounding_0;
+ TALLOC_CTX *_mem_save_surrounding_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->surrounding));
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->x));
+ NDR_PULL_ALLOC_N(ndr, r->surrounding, ndr_get_array_size(ndr, &r->surrounding));
+ _mem_save_surrounding_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->surrounding, 0);
+ for (cntr_surrounding_0 = 0; cntr_surrounding_0 < r->x; cntr_surrounding_0++) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->surrounding[cntr_surrounding_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_surrounding_0, 0);
+ if (r->surrounding) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->surrounding, r->x));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_Surrounding(struct ndr_print *ndr, const char *name, const struct echo_Surrounding *r)
+{
+ uint32_t cntr_surrounding_0;
+ ndr_print_struct(ndr, name, "echo_Surrounding");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "x", r->x);
+ ndr->print(ndr, "%s: ARRAY(%d)", "surrounding", (int)r->x);
+ ndr->depth++;
+ for (cntr_surrounding_0=0;cntr_surrounding_0<r->x;cntr_surrounding_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_surrounding_0) != -1) {
+ ndr_print_uint16(ndr, "surrounding", r->surrounding[cntr_surrounding_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_AddOne(struct ndr_push *ndr, int flags, const struct echo_AddOne *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.in_data));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.out_data == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.out_data));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_AddOne(struct ndr_pull *ndr, int flags, struct echo_AddOne *r)
+{
+ TALLOC_CTX *_mem_save_out_data_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.in_data));
+ NDR_PULL_ALLOC(ndr, r->out.out_data);
+ ZERO_STRUCTP(r->out.out_data);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.out_data);
+ }
+ _mem_save_out_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.out_data, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.out_data));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_out_data_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_AddOne(struct ndr_print *ndr, const char *name, int flags, const struct echo_AddOne *r)
+{
+ ndr_print_struct(ndr, name, "echo_AddOne");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "echo_AddOne");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "in_data", r->in.in_data);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "echo_AddOne");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "out_data", r->out.out_data);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "out_data", *r->out.out_data);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_EchoData(struct ndr_push *ndr, int flags, const struct echo_EchoData *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.len));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.len));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->in.in_data, r->in.len));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.len));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.out_data, r->in.len));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_EchoData(struct ndr_pull *ndr, int flags, struct echo_EchoData *r)
+{
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.len));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.in_data));
+ NDR_PULL_ALLOC_N(ndr, r->in.in_data, ndr_get_array_size(ndr, &r->in.in_data));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->in.in_data, ndr_get_array_size(ndr, &r->in.in_data)));
+ if (r->in.in_data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.in_data, r->in.len));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->out.out_data));
+ NDR_PULL_ALLOC_N(ndr, r->out.out_data, ndr_get_array_size(ndr, &r->out.out_data));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.out_data, ndr_get_array_size(ndr, &r->out.out_data)));
+ if (r->out.out_data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->out.out_data, r->in.len));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_EchoData(struct ndr_print *ndr, const char *name, int flags, const struct echo_EchoData *r)
+{
+ ndr_print_struct(ndr, name, "echo_EchoData");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "echo_EchoData");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "len", r->in.len);
+ ndr_print_array_uint8(ndr, "in_data", r->in.in_data, r->in.len);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "echo_EchoData");
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "out_data", r->out.out_data, r->in.len);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_SinkData(struct ndr_push *ndr, int flags, const struct echo_SinkData *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.len));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.len));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->in.data, r->in.len));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_SinkData(struct ndr_pull *ndr, int flags, struct echo_SinkData *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.len));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.data));
+ NDR_PULL_ALLOC_N(ndr, r->in.data, ndr_get_array_size(ndr, &r->in.data));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->in.data, ndr_get_array_size(ndr, &r->in.data)));
+ if (r->in.data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.data, r->in.len));
+ }
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_SinkData(struct ndr_print *ndr, const char *name, int flags, const struct echo_SinkData *r)
+{
+ ndr_print_struct(ndr, name, "echo_SinkData");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "echo_SinkData");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "len", r->in.len);
+ ndr_print_array_uint8(ndr, "data", r->in.data, r->in.len);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "echo_SinkData");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_SourceData(struct ndr_push *ndr, int flags, const struct echo_SourceData *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.len));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.len));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.data, r->in.len));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_SourceData(struct ndr_pull *ndr, int flags, struct echo_SourceData *r)
+{
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.len));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->out.data));
+ NDR_PULL_ALLOC_N(ndr, r->out.data, ndr_get_array_size(ndr, &r->out.data));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.data, ndr_get_array_size(ndr, &r->out.data)));
+ if (r->out.data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->out.data, r->in.len));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_SourceData(struct ndr_print *ndr, const char *name, int flags, const struct echo_SourceData *r)
+{
+ ndr_print_struct(ndr, name, "echo_SourceData");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "echo_SourceData");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "len", r->in.len);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "echo_SourceData");
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "data", r->out.data, r->in.len);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_TestCall(struct ndr_push *ndr, int flags, const struct echo_TestCall *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.s1 == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.s1, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.s1, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.s1, ndr_charset_length(r->in.s1, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.s2 == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.s2));
+ if (*r->out.s2) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.s2, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.s2, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, *r->out.s2, ndr_charset_length(*r->out.s2, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_TestCall(struct ndr_pull *ndr, int flags, struct echo_TestCall *r)
+{
+ uint32_t _ptr_s2;
+ TALLOC_CTX *_mem_save_s2_0;
+ TALLOC_CTX *_mem_save_s2_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.s1));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.s1));
+ if (ndr_get_array_length(ndr, &r->in.s1) > ndr_get_array_size(ndr, &r->in.s1)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.s1), ndr_get_array_length(ndr, &r->in.s1));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.s1), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.s1, ndr_get_array_length(ndr, &r->in.s1), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_ALLOC(ndr, r->out.s2);
+ ZERO_STRUCTP(r->out.s2);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.s2);
+ }
+ _mem_save_s2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.s2, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_s2));
+ if (_ptr_s2) {
+ NDR_PULL_ALLOC(ndr, *r->out.s2);
+ } else {
+ *r->out.s2 = NULL;
+ }
+ if (*r->out.s2) {
+ _mem_save_s2_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.s2, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->out.s2));
+ NDR_CHECK(ndr_pull_array_length(ndr, r->out.s2));
+ if (ndr_get_array_length(ndr, r->out.s2) > ndr_get_array_size(ndr, r->out.s2)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, r->out.s2), ndr_get_array_length(ndr, r->out.s2));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, r->out.s2), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, r->out.s2, ndr_get_array_length(ndr, r->out.s2), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s2_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_s2_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_TestCall(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestCall *r)
+{
+ ndr_print_struct(ndr, name, "echo_TestCall");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "echo_TestCall");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "s1", r->in.s1);
+ ndr->depth++;
+ ndr_print_string(ndr, "s1", r->in.s1);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "echo_TestCall");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "s2", r->out.s2);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "s2", *r->out.s2);
+ ndr->depth++;
+ if (*r->out.s2) {
+ ndr_print_string(ndr, "s2", *r->out.s2);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_TestCall2(struct ndr_push *ndr, int flags, const struct echo_TestCall2 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_echo_Info(ndr, NDR_SCALARS, r->out.info));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_TestCall2(struct ndr_pull *ndr, int flags, struct echo_TestCall2 *r)
+{
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_echo_Info(ndr, NDR_SCALARS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_TestCall2(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestCall2 *r)
+{
+ ndr_print_struct(ndr, name, "echo_TestCall2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "echo_TestCall2");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "echo_TestCall2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, r->in.level);
+ ndr_print_echo_Info(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_TestSleep(struct ndr_push *ndr, int flags, const struct echo_TestSleep *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.seconds));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_TestSleep(struct ndr_pull *ndr, int flags, struct echo_TestSleep *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.seconds));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_TestSleep(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestSleep *r)
+{
+ ndr_print_struct(ndr, name, "echo_TestSleep");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "echo_TestSleep");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "seconds", r->in.seconds);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "echo_TestSleep");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_TestEnum(struct ndr_push *ndr, int flags, const struct echo_TestEnum *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.foo1 == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_echo_Enum1(ndr, NDR_SCALARS, *r->in.foo1));
+ if (r->in.foo2 == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_echo_Enum2(ndr, NDR_SCALARS, r->in.foo2));
+ if (r->in.foo3 == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.foo3, *r->in.foo1));
+ NDR_CHECK(ndr_push_echo_Enum3(ndr, NDR_SCALARS, r->in.foo3));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.foo1 == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_echo_Enum1(ndr, NDR_SCALARS, *r->out.foo1));
+ if (r->out.foo2 == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_echo_Enum2(ndr, NDR_SCALARS, r->out.foo2));
+ if (r->out.foo3 == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.foo3, *r->out.foo1));
+ NDR_CHECK(ndr_push_echo_Enum3(ndr, NDR_SCALARS, r->out.foo3));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_TestEnum(struct ndr_pull *ndr, int flags, struct echo_TestEnum *r)
+{
+ TALLOC_CTX *_mem_save_foo1_0;
+ TALLOC_CTX *_mem_save_foo2_0;
+ TALLOC_CTX *_mem_save_foo3_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.foo1);
+ }
+ _mem_save_foo1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.foo1, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_echo_Enum1(ndr, NDR_SCALARS, r->in.foo1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_foo1_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.foo2);
+ }
+ _mem_save_foo2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.foo2, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_echo_Enum2(ndr, NDR_SCALARS, r->in.foo2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_foo2_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.foo3);
+ }
+ _mem_save_foo3_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.foo3, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.foo3, *r->in.foo1));
+ NDR_CHECK(ndr_pull_echo_Enum3(ndr, NDR_SCALARS, r->in.foo3));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_foo3_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.foo1);
+ *r->out.foo1 = *r->in.foo1;
+ NDR_PULL_ALLOC(ndr, r->out.foo2);
+ *r->out.foo2 = *r->in.foo2;
+ NDR_PULL_ALLOC(ndr, r->out.foo3);
+ *r->out.foo3 = *r->in.foo3;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.foo1);
+ }
+ _mem_save_foo1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.foo1, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_echo_Enum1(ndr, NDR_SCALARS, r->out.foo1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_foo1_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.foo2);
+ }
+ _mem_save_foo2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.foo2, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_echo_Enum2(ndr, NDR_SCALARS, r->out.foo2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_foo2_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.foo3);
+ }
+ _mem_save_foo3_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.foo3, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.foo3, *r->out.foo1));
+ NDR_CHECK(ndr_pull_echo_Enum3(ndr, NDR_SCALARS, r->out.foo3));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_foo3_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_TestEnum(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestEnum *r)
+{
+ ndr_print_struct(ndr, name, "echo_TestEnum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "echo_TestEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "foo1", r->in.foo1);
+ ndr->depth++;
+ ndr_print_echo_Enum1(ndr, "foo1", *r->in.foo1);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "foo2", r->in.foo2);
+ ndr->depth++;
+ ndr_print_echo_Enum2(ndr, "foo2", r->in.foo2);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "foo3", r->in.foo3);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.foo3, *r->in.foo1);
+ ndr_print_echo_Enum3(ndr, "foo3", r->in.foo3);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "echo_TestEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "foo1", r->out.foo1);
+ ndr->depth++;
+ ndr_print_echo_Enum1(ndr, "foo1", *r->out.foo1);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "foo2", r->out.foo2);
+ ndr->depth++;
+ ndr_print_echo_Enum2(ndr, "foo2", r->out.foo2);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "foo3", r->out.foo3);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.foo3, *r->out.foo1);
+ ndr_print_echo_Enum3(ndr, "foo3", r->out.foo3);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_TestSurrounding(struct ndr_push *ndr, int flags, const struct echo_TestSurrounding *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.data == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_echo_Surrounding(ndr, NDR_SCALARS, r->in.data));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.data == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_echo_Surrounding(ndr, NDR_SCALARS, r->out.data));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_TestSurrounding(struct ndr_pull *ndr, int flags, struct echo_TestSurrounding *r)
+{
+ TALLOC_CTX *_mem_save_data_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.data);
+ }
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.data, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_echo_Surrounding(ndr, NDR_SCALARS, r->in.data));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.data);
+ *r->out.data = *r->in.data;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.data);
+ }
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.data, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_echo_Surrounding(ndr, NDR_SCALARS, r->out.data));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_TestSurrounding(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestSurrounding *r)
+{
+ ndr_print_struct(ndr, name, "echo_TestSurrounding");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "echo_TestSurrounding");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "data", r->in.data);
+ ndr->depth++;
+ ndr_print_echo_Surrounding(ndr, "data", r->in.data);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "echo_TestSurrounding");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "data", r->out.data);
+ ndr->depth++;
+ ndr_print_echo_Surrounding(ndr, "data", r->out.data);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_echo_TestDoublePointer(struct ndr_push *ndr, int flags, const struct echo_TestDoublePointer *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.data == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->in.data));
+ if (*r->in.data) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, **r->in.data));
+ if (**r->in.data) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, ***r->in.data));
+ }
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_echo_TestDoublePointer(struct ndr_pull *ndr, int flags, struct echo_TestDoublePointer *r)
+{
+ uint32_t _ptr_data;
+ TALLOC_CTX *_mem_save_data_0;
+ TALLOC_CTX *_mem_save_data_1;
+ TALLOC_CTX *_mem_save_data_2;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.data);
+ }
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.data, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data));
+ if (_ptr_data) {
+ NDR_PULL_ALLOC(ndr, *r->in.data);
+ } else {
+ *r->in.data = NULL;
+ }
+ if (*r->in.data) {
+ _mem_save_data_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->in.data, 0);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data));
+ if (_ptr_data) {
+ NDR_PULL_ALLOC(ndr, **r->in.data);
+ } else {
+ **r->in.data = NULL;
+ }
+ if (**r->in.data) {
+ _mem_save_data_2 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, **r->in.data, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, **r->in.data));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_2, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_echo_TestDoublePointer(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestDoublePointer *r)
+{
+ ndr_print_struct(ndr, name, "echo_TestDoublePointer");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "echo_TestDoublePointer");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "data", r->in.data);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "data", *r->in.data);
+ ndr->depth++;
+ if (*r->in.data) {
+ ndr_print_ptr(ndr, "data", **r->in.data);
+ ndr->depth++;
+ if (**r->in.data) {
+ ndr_print_uint16(ndr, "data", ***r->in.data);
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "echo_TestDoublePointer");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call rpcecho_calls[] = {
+ {
+ "echo_AddOne",
+ sizeof(struct echo_AddOne),
+ (ndr_push_flags_fn_t) ndr_push_echo_AddOne,
+ (ndr_pull_flags_fn_t) ndr_pull_echo_AddOne,
+ (ndr_print_function_t) ndr_print_echo_AddOne,
+ false,
+ },
+ {
+ "echo_EchoData",
+ sizeof(struct echo_EchoData),
+ (ndr_push_flags_fn_t) ndr_push_echo_EchoData,
+ (ndr_pull_flags_fn_t) ndr_pull_echo_EchoData,
+ (ndr_print_function_t) ndr_print_echo_EchoData,
+ false,
+ },
+ {
+ "echo_SinkData",
+ sizeof(struct echo_SinkData),
+ (ndr_push_flags_fn_t) ndr_push_echo_SinkData,
+ (ndr_pull_flags_fn_t) ndr_pull_echo_SinkData,
+ (ndr_print_function_t) ndr_print_echo_SinkData,
+ false,
+ },
+ {
+ "echo_SourceData",
+ sizeof(struct echo_SourceData),
+ (ndr_push_flags_fn_t) ndr_push_echo_SourceData,
+ (ndr_pull_flags_fn_t) ndr_pull_echo_SourceData,
+ (ndr_print_function_t) ndr_print_echo_SourceData,
+ false,
+ },
+ {
+ "echo_TestCall",
+ sizeof(struct echo_TestCall),
+ (ndr_push_flags_fn_t) ndr_push_echo_TestCall,
+ (ndr_pull_flags_fn_t) ndr_pull_echo_TestCall,
+ (ndr_print_function_t) ndr_print_echo_TestCall,
+ false,
+ },
+ {
+ "echo_TestCall2",
+ sizeof(struct echo_TestCall2),
+ (ndr_push_flags_fn_t) ndr_push_echo_TestCall2,
+ (ndr_pull_flags_fn_t) ndr_pull_echo_TestCall2,
+ (ndr_print_function_t) ndr_print_echo_TestCall2,
+ false,
+ },
+ {
+ "echo_TestSleep",
+ sizeof(struct echo_TestSleep),
+ (ndr_push_flags_fn_t) ndr_push_echo_TestSleep,
+ (ndr_pull_flags_fn_t) ndr_pull_echo_TestSleep,
+ (ndr_print_function_t) ndr_print_echo_TestSleep,
+ false,
+ },
+ {
+ "echo_TestEnum",
+ sizeof(struct echo_TestEnum),
+ (ndr_push_flags_fn_t) ndr_push_echo_TestEnum,
+ (ndr_pull_flags_fn_t) ndr_pull_echo_TestEnum,
+ (ndr_print_function_t) ndr_print_echo_TestEnum,
+ false,
+ },
+ {
+ "echo_TestSurrounding",
+ sizeof(struct echo_TestSurrounding),
+ (ndr_push_flags_fn_t) ndr_push_echo_TestSurrounding,
+ (ndr_pull_flags_fn_t) ndr_pull_echo_TestSurrounding,
+ (ndr_print_function_t) ndr_print_echo_TestSurrounding,
+ false,
+ },
+ {
+ "echo_TestDoublePointer",
+ sizeof(struct echo_TestDoublePointer),
+ (ndr_push_flags_fn_t) ndr_push_echo_TestDoublePointer,
+ (ndr_pull_flags_fn_t) ndr_pull_echo_TestDoublePointer,
+ (ndr_print_function_t) ndr_print_echo_TestDoublePointer,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const rpcecho_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\rpcecho]",
+ "ncacn_ip_tcp:",
+ "ncalrpc:",
+};
+
+static const struct ndr_interface_string_array rpcecho_endpoints = {
+ .count = 3,
+ .names = rpcecho_endpoint_strings
+};
+
+static const char * const rpcecho_authservice_strings[] = {
+ "host",
+};
+
+static const struct ndr_interface_string_array rpcecho_authservices = {
+ .count = 1,
+ .names = rpcecho_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_rpcecho = {
+ .name = "rpcecho",
+ .syntax_id = {
+ {0x60a15ec5,0x4de8,0x11d7,{0xa6,0x37},{0x00,0x50,0x56,0xa2,0x01,0x82}},
+ NDR_RPCECHO_VERSION
+ },
+ .helpstring = NDR_RPCECHO_HELPSTRING,
+ .num_calls = 10,
+ .calls = rpcecho_calls,
+ .endpoints = &rpcecho_endpoints,
+ .authservices = &rpcecho_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_echo.h b/source3/librpc/gen_ndr/ndr_echo.h
new file mode 100644
index 0000000000..7af1c7446b
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_echo.h
@@ -0,0 +1,58 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/echo.h"
+
+#ifndef _HEADER_NDR_rpcecho
+#define _HEADER_NDR_rpcecho
+
+#define NDR_RPCECHO_UUID "60a15ec5-4de8-11d7-a637-005056a20182"
+#define NDR_RPCECHO_VERSION 1.0
+#define NDR_RPCECHO_NAME "rpcecho"
+#define NDR_RPCECHO_HELPSTRING "Simple echo pipe"
+extern const struct ndr_interface_table ndr_table_rpcecho;
+#define NDR_ECHO_ADDONE (0x00)
+
+#define NDR_ECHO_ECHODATA (0x01)
+
+#define NDR_ECHO_SINKDATA (0x02)
+
+#define NDR_ECHO_SOURCEDATA (0x03)
+
+#define NDR_ECHO_TESTCALL (0x04)
+
+#define NDR_ECHO_TESTCALL2 (0x05)
+
+#define NDR_ECHO_TESTSLEEP (0x06)
+
+#define NDR_ECHO_TESTENUM (0x07)
+
+#define NDR_ECHO_TESTSURROUNDING (0x08)
+
+#define NDR_ECHO_TESTDOUBLEPOINTER (0x09)
+
+#define NDR_RPCECHO_CALL_COUNT (10)
+void ndr_print_echo_info1(struct ndr_print *ndr, const char *name, const struct echo_info1 *r);
+void ndr_print_echo_info2(struct ndr_print *ndr, const char *name, const struct echo_info2 *r);
+void ndr_print_echo_info3(struct ndr_print *ndr, const char *name, const struct echo_info3 *r);
+void ndr_print_STRUCT_echo_info4(struct ndr_print *ndr, const char *name, const struct echo_info4 *r);
+void ndr_print_echo_info5(struct ndr_print *ndr, const char *name, const struct echo_info5 *r);
+void ndr_print_echo_info6(struct ndr_print *ndr, const char *name, const struct echo_info6 *r);
+void ndr_print_echo_info7(struct ndr_print *ndr, const char *name, const struct echo_info7 *r);
+void ndr_print_echo_Info(struct ndr_print *ndr, const char *name, const union echo_Info *r);
+void ndr_print_echo_Enum1(struct ndr_print *ndr, const char *name, enum echo_Enum1 r);
+void ndr_print_echo_Enum1_32(struct ndr_print *ndr, const char *name, enum echo_Enum1_32 r);
+void ndr_print_echo_Enum2(struct ndr_print *ndr, const char *name, const struct echo_Enum2 *r);
+void ndr_print_echo_Enum3(struct ndr_print *ndr, const char *name, const union echo_Enum3 *r);
+void ndr_print_echo_Surrounding(struct ndr_print *ndr, const char *name, const struct echo_Surrounding *r);
+void ndr_print_echo_AddOne(struct ndr_print *ndr, const char *name, int flags, const struct echo_AddOne *r);
+void ndr_print_echo_EchoData(struct ndr_print *ndr, const char *name, int flags, const struct echo_EchoData *r);
+void ndr_print_echo_SinkData(struct ndr_print *ndr, const char *name, int flags, const struct echo_SinkData *r);
+void ndr_print_echo_SourceData(struct ndr_print *ndr, const char *name, int flags, const struct echo_SourceData *r);
+void ndr_print_echo_TestCall(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestCall *r);
+void ndr_print_echo_TestCall2(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestCall2 *r);
+void ndr_print_echo_TestSleep(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestSleep *r);
+void ndr_print_echo_TestEnum(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestEnum *r);
+void ndr_print_echo_TestSurrounding(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestSurrounding *r);
+void ndr_print_echo_TestDoublePointer(struct ndr_print *ndr, const char *name, int flags, const struct echo_TestDoublePointer *r);
+#endif /* _HEADER_NDR_rpcecho */
diff --git a/source3/librpc/gen_ndr/ndr_epmapper.c b/source3/librpc/gen_ndr/ndr_epmapper.c
new file mode 100644
index 0000000000..ab84d289cf
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_epmapper.c
@@ -0,0 +1,2699 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_epmapper.h"
+
+static enum ndr_err_code ndr_push_epm_protocol(struct ndr_push *ndr, int ndr_flags, enum epm_protocol r)
+{
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_protocol(struct ndr_pull *ndr, int ndr_flags, enum epm_protocol *r)
+{
+ uint8_t v;
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_protocol(struct ndr_print *ndr, const char *name, enum epm_protocol r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case EPM_PROTOCOL_DNET_NSP: val = "EPM_PROTOCOL_DNET_NSP"; break;
+ case EPM_PROTOCOL_OSI_TP4: val = "EPM_PROTOCOL_OSI_TP4"; break;
+ case EPM_PROTOCOL_OSI_CLNS: val = "EPM_PROTOCOL_OSI_CLNS"; break;
+ case EPM_PROTOCOL_TCP: val = "EPM_PROTOCOL_TCP"; break;
+ case EPM_PROTOCOL_UDP: val = "EPM_PROTOCOL_UDP"; break;
+ case EPM_PROTOCOL_IP: val = "EPM_PROTOCOL_IP"; break;
+ case EPM_PROTOCOL_NCADG: val = "EPM_PROTOCOL_NCADG"; break;
+ case EPM_PROTOCOL_NCACN: val = "EPM_PROTOCOL_NCACN"; break;
+ case EPM_PROTOCOL_NCALRPC: val = "EPM_PROTOCOL_NCALRPC"; break;
+ case EPM_PROTOCOL_UUID: val = "EPM_PROTOCOL_UUID"; break;
+ case EPM_PROTOCOL_IPX: val = "EPM_PROTOCOL_IPX"; break;
+ case EPM_PROTOCOL_SMB: val = "EPM_PROTOCOL_SMB"; break;
+ case EPM_PROTOCOL_PIPE: val = "EPM_PROTOCOL_PIPE"; break;
+ case EPM_PROTOCOL_NETBIOS: val = "EPM_PROTOCOL_NETBIOS"; break;
+ case EPM_PROTOCOL_NETBEUI: val = "EPM_PROTOCOL_NETBEUI"; break;
+ case EPM_PROTOCOL_SPX: val = "EPM_PROTOCOL_SPX"; break;
+ case EPM_PROTOCOL_NB_IPX: val = "EPM_PROTOCOL_NB_IPX"; break;
+ case EPM_PROTOCOL_DSP: val = "EPM_PROTOCOL_DSP"; break;
+ case EPM_PROTOCOL_DDP: val = "EPM_PROTOCOL_DDP"; break;
+ case EPM_PROTOCOL_APPLETALK: val = "EPM_PROTOCOL_APPLETALK"; break;
+ case EPM_PROTOCOL_VINES_SPP: val = "EPM_PROTOCOL_VINES_SPP"; break;
+ case EPM_PROTOCOL_VINES_IPC: val = "EPM_PROTOCOL_VINES_IPC"; break;
+ case EPM_PROTOCOL_STREETTALK: val = "EPM_PROTOCOL_STREETTALK"; break;
+ case EPM_PROTOCOL_HTTP: val = "EPM_PROTOCOL_HTTP"; break;
+ case EPM_PROTOCOL_UNIX_DS: val = "EPM_PROTOCOL_UNIX_DS"; break;
+ case EPM_PROTOCOL_NULL: val = "EPM_PROTOCOL_NULL"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_dnet_nsp(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_dnet_nsp *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_dnet_nsp(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_dnet_nsp *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_dnet_nsp(struct ndr_print *ndr, const char *name, const struct epm_rhs_dnet_nsp *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_dnet_nsp");
+ ndr->depth++;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_osi_tp4(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_osi_tp4 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_osi_tp4(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_osi_tp4 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_osi_tp4(struct ndr_print *ndr, const char *name, const struct epm_rhs_osi_tp4 *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_osi_tp4");
+ ndr->depth++;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_osi_clns(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_osi_clns *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_osi_clns(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_osi_clns *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_osi_clns(struct ndr_print *ndr, const char *name, const struct epm_rhs_osi_clns *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_osi_clns");
+ ndr->depth++;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_udp(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_udp *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->port));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_udp(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_udp *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->port));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_udp(struct ndr_print *ndr, const char *name, const struct epm_rhs_udp *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_udp");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "port", r->port);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_tcp(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_tcp *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->port));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_tcp(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_tcp *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->port));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_tcp(struct ndr_print *ndr, const char *name, const struct epm_rhs_tcp *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_tcp");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "port", r->port);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_ip(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_ip *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_ipv4address(ndr, NDR_SCALARS, r->ipaddr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_ip(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_ip *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_ipv4address(ndr, NDR_SCALARS, &r->ipaddr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_ip(struct ndr_print *ndr, const char *name, const struct epm_rhs_ip *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_ip");
+ ndr->depth++;
+ ndr_print_ipv4address(ndr, "ipaddr", r->ipaddr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_ncadg(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_ncadg *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->minor_version));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_ncadg(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_ncadg *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->minor_version));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_ncadg(struct ndr_print *ndr, const char *name, const struct epm_rhs_ncadg *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_ncadg");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "minor_version", r->minor_version);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_ncacn(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_ncacn *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->minor_version));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_ncacn(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_ncacn *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->minor_version));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_ncacn(struct ndr_print *ndr, const char *name, const struct epm_rhs_ncacn *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_ncacn");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "minor_version", r->minor_version);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_uuid(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_uuid *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->unknown));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_uuid(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_uuid *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->unknown));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_uuid(struct ndr_print *ndr, const char *name, const struct epm_rhs_uuid *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_uuid");
+ ndr->depth++;
+ ndr_print_DATA_BLOB(ndr, "unknown", r->unknown);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_ipx(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_ipx *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_ipx(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_ipx *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_ipx(struct ndr_print *ndr, const char *name, const struct epm_rhs_ipx *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_ipx");
+ ndr->depth++;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_smb(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_smb *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->unc));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_smb(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_smb *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->unc));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_smb(struct ndr_print *ndr, const char *name, const struct epm_rhs_smb *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_smb");
+ ndr->depth++;
+ ndr_print_string(ndr, "unc", r->unc);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_pipe(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_pipe *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->path));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_pipe(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_pipe *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->path));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_pipe(struct ndr_print *ndr, const char *name, const struct epm_rhs_pipe *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_pipe");
+ ndr->depth++;
+ ndr_print_string(ndr, "path", r->path);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_netbios(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_netbios *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->name));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_netbios(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_netbios *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->name));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_netbios(struct ndr_print *ndr, const char *name, const struct epm_rhs_netbios *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_netbios");
+ ndr->depth++;
+ ndr_print_string(ndr, "name", r->name);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_netbeui(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_netbeui *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_netbeui(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_netbeui *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_netbeui(struct ndr_print *ndr, const char *name, const struct epm_rhs_netbeui *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_netbeui");
+ ndr->depth++;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_spx(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_spx *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_spx(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_spx *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_spx(struct ndr_print *ndr, const char *name, const struct epm_rhs_spx *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_spx");
+ ndr->depth++;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_nb_ipx(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_nb_ipx *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_nb_ipx(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_nb_ipx *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_nb_ipx(struct ndr_print *ndr, const char *name, const struct epm_rhs_nb_ipx *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_nb_ipx");
+ ndr->depth++;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_http(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_http *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->port));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_http(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_http *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->port));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_http(struct ndr_print *ndr, const char *name, const struct epm_rhs_http *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_http");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "port", r->port);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_unix_ds(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_unix_ds *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->path));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_unix_ds(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_unix_ds *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->path));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_unix_ds(struct ndr_print *ndr, const char *name, const struct epm_rhs_unix_ds *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_unix_ds");
+ ndr->depth++;
+ ndr_print_string(ndr, "path", r->path);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_null(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_null *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_null(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_null *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_null(struct ndr_print *ndr, const char *name, const struct epm_rhs_null *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_null");
+ ndr->depth++;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_ncalrpc(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_ncalrpc *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->minor_version));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_ncalrpc(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_ncalrpc *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->minor_version));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_ncalrpc(struct ndr_print *ndr, const char *name, const struct epm_rhs_ncalrpc *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_ncalrpc");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "minor_version", r->minor_version);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_appletalk(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_appletalk *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_appletalk(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_appletalk *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_appletalk(struct ndr_print *ndr, const char *name, const struct epm_rhs_appletalk *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_appletalk");
+ ndr->depth++;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_atalk_stream(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_atalk_stream *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_atalk_stream(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_atalk_stream *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_atalk_stream(struct ndr_print *ndr, const char *name, const struct epm_rhs_atalk_stream *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_atalk_stream");
+ ndr->depth++;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_atalk_datagram(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_atalk_datagram *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_atalk_datagram(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_atalk_datagram *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_atalk_datagram(struct ndr_print *ndr, const char *name, const struct epm_rhs_atalk_datagram *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_atalk_datagram");
+ ndr->depth++;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_vines_spp(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_vines_spp *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->port));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_vines_spp(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_vines_spp *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->port));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_vines_spp(struct ndr_print *ndr, const char *name, const struct epm_rhs_vines_spp *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_vines_spp");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "port", r->port);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_vines_ipc(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_vines_ipc *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->port));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_vines_ipc(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_vines_ipc *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->port));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_vines_ipc(struct ndr_print *ndr, const char *name, const struct epm_rhs_vines_ipc *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_vines_ipc");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "port", r->port);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs_streettalk(struct ndr_push *ndr, int ndr_flags, const struct epm_rhs_streettalk *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->streettalk));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs_streettalk(struct ndr_pull *ndr, int ndr_flags, struct epm_rhs_streettalk *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->streettalk));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs_streettalk(struct ndr_print *ndr, const char *name, const struct epm_rhs_streettalk *r)
+{
+ ndr_print_struct(ndr, name, "epm_rhs_streettalk");
+ ndr->depth++;
+ ndr_print_string(ndr, "streettalk", r->streettalk);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_rhs(struct ndr_push *ndr, int ndr_flags, const union epm_rhs *r)
+{
+ {
+ uint32_t _flags_save_UNION = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case EPM_PROTOCOL_DNET_NSP: {
+ NDR_CHECK(ndr_push_epm_rhs_dnet_nsp(ndr, NDR_SCALARS, &r->dnet_nsp));
+ break; }
+
+ case EPM_PROTOCOL_OSI_TP4: {
+ NDR_CHECK(ndr_push_epm_rhs_osi_tp4(ndr, NDR_SCALARS, &r->osi_tp4));
+ break; }
+
+ case EPM_PROTOCOL_OSI_CLNS: {
+ NDR_CHECK(ndr_push_epm_rhs_osi_clns(ndr, NDR_SCALARS, &r->osi_clns));
+ break; }
+
+ case EPM_PROTOCOL_TCP: {
+ NDR_CHECK(ndr_push_epm_rhs_tcp(ndr, NDR_SCALARS, &r->tcp));
+ break; }
+
+ case EPM_PROTOCOL_UDP: {
+ NDR_CHECK(ndr_push_epm_rhs_udp(ndr, NDR_SCALARS, &r->udp));
+ break; }
+
+ case EPM_PROTOCOL_IP: {
+ NDR_CHECK(ndr_push_epm_rhs_ip(ndr, NDR_SCALARS, &r->ip));
+ break; }
+
+ case EPM_PROTOCOL_NCADG: {
+ NDR_CHECK(ndr_push_epm_rhs_ncadg(ndr, NDR_SCALARS, &r->ncadg));
+ break; }
+
+ case EPM_PROTOCOL_NCACN: {
+ NDR_CHECK(ndr_push_epm_rhs_ncacn(ndr, NDR_SCALARS, &r->ncacn));
+ break; }
+
+ case EPM_PROTOCOL_NCALRPC: {
+ NDR_CHECK(ndr_push_epm_rhs_ncalrpc(ndr, NDR_SCALARS, &r->ncalrpc));
+ break; }
+
+ case EPM_PROTOCOL_UUID: {
+ NDR_CHECK(ndr_push_epm_rhs_uuid(ndr, NDR_SCALARS, &r->uuid));
+ break; }
+
+ case EPM_PROTOCOL_IPX: {
+ NDR_CHECK(ndr_push_epm_rhs_ipx(ndr, NDR_SCALARS, &r->ipx));
+ break; }
+
+ case EPM_PROTOCOL_SMB: {
+ NDR_CHECK(ndr_push_epm_rhs_smb(ndr, NDR_SCALARS, &r->smb));
+ break; }
+
+ case EPM_PROTOCOL_PIPE: {
+ NDR_CHECK(ndr_push_epm_rhs_pipe(ndr, NDR_SCALARS, &r->pipe));
+ break; }
+
+ case EPM_PROTOCOL_NETBIOS: {
+ NDR_CHECK(ndr_push_epm_rhs_netbios(ndr, NDR_SCALARS, &r->netbios));
+ break; }
+
+ case EPM_PROTOCOL_NETBEUI: {
+ NDR_CHECK(ndr_push_epm_rhs_netbeui(ndr, NDR_SCALARS, &r->netbeui));
+ break; }
+
+ case EPM_PROTOCOL_SPX: {
+ NDR_CHECK(ndr_push_epm_rhs_spx(ndr, NDR_SCALARS, &r->spx));
+ break; }
+
+ case EPM_PROTOCOL_NB_IPX: {
+ NDR_CHECK(ndr_push_epm_rhs_nb_ipx(ndr, NDR_SCALARS, &r->nb_ipx));
+ break; }
+
+ case EPM_PROTOCOL_DSP: {
+ NDR_CHECK(ndr_push_epm_rhs_atalk_stream(ndr, NDR_SCALARS, &r->atalk_stream));
+ break; }
+
+ case EPM_PROTOCOL_DDP: {
+ NDR_CHECK(ndr_push_epm_rhs_atalk_datagram(ndr, NDR_SCALARS, &r->atalk_datagram));
+ break; }
+
+ case EPM_PROTOCOL_APPLETALK: {
+ NDR_CHECK(ndr_push_epm_rhs_appletalk(ndr, NDR_SCALARS, &r->appletalk));
+ break; }
+
+ case EPM_PROTOCOL_VINES_SPP: {
+ NDR_CHECK(ndr_push_epm_rhs_vines_spp(ndr, NDR_SCALARS, &r->vines_spp));
+ break; }
+
+ case EPM_PROTOCOL_VINES_IPC: {
+ NDR_CHECK(ndr_push_epm_rhs_vines_ipc(ndr, NDR_SCALARS, &r->vines_ipc));
+ break; }
+
+ case EPM_PROTOCOL_STREETTALK: {
+ NDR_CHECK(ndr_push_epm_rhs_streettalk(ndr, NDR_SCALARS, &r->streettalk));
+ break; }
+
+ case EPM_PROTOCOL_HTTP: {
+ NDR_CHECK(ndr_push_epm_rhs_http(ndr, NDR_SCALARS, &r->http));
+ break; }
+
+ case EPM_PROTOCOL_UNIX_DS: {
+ NDR_CHECK(ndr_push_epm_rhs_unix_ds(ndr, NDR_SCALARS, &r->unix_ds));
+ break; }
+
+ case EPM_PROTOCOL_NULL: {
+ NDR_CHECK(ndr_push_epm_rhs_null(ndr, NDR_SCALARS, &r->null));
+ break; }
+
+ default: {
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->unknown));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case EPM_PROTOCOL_DNET_NSP:
+ break;
+
+ case EPM_PROTOCOL_OSI_TP4:
+ break;
+
+ case EPM_PROTOCOL_OSI_CLNS:
+ break;
+
+ case EPM_PROTOCOL_TCP:
+ break;
+
+ case EPM_PROTOCOL_UDP:
+ break;
+
+ case EPM_PROTOCOL_IP:
+ break;
+
+ case EPM_PROTOCOL_NCADG:
+ break;
+
+ case EPM_PROTOCOL_NCACN:
+ break;
+
+ case EPM_PROTOCOL_NCALRPC:
+ break;
+
+ case EPM_PROTOCOL_UUID:
+ break;
+
+ case EPM_PROTOCOL_IPX:
+ break;
+
+ case EPM_PROTOCOL_SMB:
+ break;
+
+ case EPM_PROTOCOL_PIPE:
+ break;
+
+ case EPM_PROTOCOL_NETBIOS:
+ break;
+
+ case EPM_PROTOCOL_NETBEUI:
+ break;
+
+ case EPM_PROTOCOL_SPX:
+ break;
+
+ case EPM_PROTOCOL_NB_IPX:
+ break;
+
+ case EPM_PROTOCOL_DSP:
+ break;
+
+ case EPM_PROTOCOL_DDP:
+ break;
+
+ case EPM_PROTOCOL_APPLETALK:
+ break;
+
+ case EPM_PROTOCOL_VINES_SPP:
+ break;
+
+ case EPM_PROTOCOL_VINES_IPC:
+ break;
+
+ case EPM_PROTOCOL_STREETTALK:
+ break;
+
+ case EPM_PROTOCOL_HTTP:
+ break;
+
+ case EPM_PROTOCOL_UNIX_DS:
+ break;
+
+ case EPM_PROTOCOL_NULL:
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ ndr->flags = _flags_save_UNION;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_rhs(struct ndr_pull *ndr, int ndr_flags, union epm_rhs *r)
+{
+ int level;
+ {
+ uint32_t _flags_save_UNION = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case EPM_PROTOCOL_DNET_NSP: {
+ NDR_CHECK(ndr_pull_epm_rhs_dnet_nsp(ndr, NDR_SCALARS, &r->dnet_nsp));
+ break; }
+
+ case EPM_PROTOCOL_OSI_TP4: {
+ NDR_CHECK(ndr_pull_epm_rhs_osi_tp4(ndr, NDR_SCALARS, &r->osi_tp4));
+ break; }
+
+ case EPM_PROTOCOL_OSI_CLNS: {
+ NDR_CHECK(ndr_pull_epm_rhs_osi_clns(ndr, NDR_SCALARS, &r->osi_clns));
+ break; }
+
+ case EPM_PROTOCOL_TCP: {
+ NDR_CHECK(ndr_pull_epm_rhs_tcp(ndr, NDR_SCALARS, &r->tcp));
+ break; }
+
+ case EPM_PROTOCOL_UDP: {
+ NDR_CHECK(ndr_pull_epm_rhs_udp(ndr, NDR_SCALARS, &r->udp));
+ break; }
+
+ case EPM_PROTOCOL_IP: {
+ NDR_CHECK(ndr_pull_epm_rhs_ip(ndr, NDR_SCALARS, &r->ip));
+ break; }
+
+ case EPM_PROTOCOL_NCADG: {
+ NDR_CHECK(ndr_pull_epm_rhs_ncadg(ndr, NDR_SCALARS, &r->ncadg));
+ break; }
+
+ case EPM_PROTOCOL_NCACN: {
+ NDR_CHECK(ndr_pull_epm_rhs_ncacn(ndr, NDR_SCALARS, &r->ncacn));
+ break; }
+
+ case EPM_PROTOCOL_NCALRPC: {
+ NDR_CHECK(ndr_pull_epm_rhs_ncalrpc(ndr, NDR_SCALARS, &r->ncalrpc));
+ break; }
+
+ case EPM_PROTOCOL_UUID: {
+ NDR_CHECK(ndr_pull_epm_rhs_uuid(ndr, NDR_SCALARS, &r->uuid));
+ break; }
+
+ case EPM_PROTOCOL_IPX: {
+ NDR_CHECK(ndr_pull_epm_rhs_ipx(ndr, NDR_SCALARS, &r->ipx));
+ break; }
+
+ case EPM_PROTOCOL_SMB: {
+ NDR_CHECK(ndr_pull_epm_rhs_smb(ndr, NDR_SCALARS, &r->smb));
+ break; }
+
+ case EPM_PROTOCOL_PIPE: {
+ NDR_CHECK(ndr_pull_epm_rhs_pipe(ndr, NDR_SCALARS, &r->pipe));
+ break; }
+
+ case EPM_PROTOCOL_NETBIOS: {
+ NDR_CHECK(ndr_pull_epm_rhs_netbios(ndr, NDR_SCALARS, &r->netbios));
+ break; }
+
+ case EPM_PROTOCOL_NETBEUI: {
+ NDR_CHECK(ndr_pull_epm_rhs_netbeui(ndr, NDR_SCALARS, &r->netbeui));
+ break; }
+
+ case EPM_PROTOCOL_SPX: {
+ NDR_CHECK(ndr_pull_epm_rhs_spx(ndr, NDR_SCALARS, &r->spx));
+ break; }
+
+ case EPM_PROTOCOL_NB_IPX: {
+ NDR_CHECK(ndr_pull_epm_rhs_nb_ipx(ndr, NDR_SCALARS, &r->nb_ipx));
+ break; }
+
+ case EPM_PROTOCOL_DSP: {
+ NDR_CHECK(ndr_pull_epm_rhs_atalk_stream(ndr, NDR_SCALARS, &r->atalk_stream));
+ break; }
+
+ case EPM_PROTOCOL_DDP: {
+ NDR_CHECK(ndr_pull_epm_rhs_atalk_datagram(ndr, NDR_SCALARS, &r->atalk_datagram));
+ break; }
+
+ case EPM_PROTOCOL_APPLETALK: {
+ NDR_CHECK(ndr_pull_epm_rhs_appletalk(ndr, NDR_SCALARS, &r->appletalk));
+ break; }
+
+ case EPM_PROTOCOL_VINES_SPP: {
+ NDR_CHECK(ndr_pull_epm_rhs_vines_spp(ndr, NDR_SCALARS, &r->vines_spp));
+ break; }
+
+ case EPM_PROTOCOL_VINES_IPC: {
+ NDR_CHECK(ndr_pull_epm_rhs_vines_ipc(ndr, NDR_SCALARS, &r->vines_ipc));
+ break; }
+
+ case EPM_PROTOCOL_STREETTALK: {
+ NDR_CHECK(ndr_pull_epm_rhs_streettalk(ndr, NDR_SCALARS, &r->streettalk));
+ break; }
+
+ case EPM_PROTOCOL_HTTP: {
+ NDR_CHECK(ndr_pull_epm_rhs_http(ndr, NDR_SCALARS, &r->http));
+ break; }
+
+ case EPM_PROTOCOL_UNIX_DS: {
+ NDR_CHECK(ndr_pull_epm_rhs_unix_ds(ndr, NDR_SCALARS, &r->unix_ds));
+ break; }
+
+ case EPM_PROTOCOL_NULL: {
+ NDR_CHECK(ndr_pull_epm_rhs_null(ndr, NDR_SCALARS, &r->null));
+ break; }
+
+ default: {
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->unknown));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case EPM_PROTOCOL_DNET_NSP:
+ break;
+
+ case EPM_PROTOCOL_OSI_TP4:
+ break;
+
+ case EPM_PROTOCOL_OSI_CLNS:
+ break;
+
+ case EPM_PROTOCOL_TCP:
+ break;
+
+ case EPM_PROTOCOL_UDP:
+ break;
+
+ case EPM_PROTOCOL_IP:
+ break;
+
+ case EPM_PROTOCOL_NCADG:
+ break;
+
+ case EPM_PROTOCOL_NCACN:
+ break;
+
+ case EPM_PROTOCOL_NCALRPC:
+ break;
+
+ case EPM_PROTOCOL_UUID:
+ break;
+
+ case EPM_PROTOCOL_IPX:
+ break;
+
+ case EPM_PROTOCOL_SMB:
+ break;
+
+ case EPM_PROTOCOL_PIPE:
+ break;
+
+ case EPM_PROTOCOL_NETBIOS:
+ break;
+
+ case EPM_PROTOCOL_NETBEUI:
+ break;
+
+ case EPM_PROTOCOL_SPX:
+ break;
+
+ case EPM_PROTOCOL_NB_IPX:
+ break;
+
+ case EPM_PROTOCOL_DSP:
+ break;
+
+ case EPM_PROTOCOL_DDP:
+ break;
+
+ case EPM_PROTOCOL_APPLETALK:
+ break;
+
+ case EPM_PROTOCOL_VINES_SPP:
+ break;
+
+ case EPM_PROTOCOL_VINES_IPC:
+ break;
+
+ case EPM_PROTOCOL_STREETTALK:
+ break;
+
+ case EPM_PROTOCOL_HTTP:
+ break;
+
+ case EPM_PROTOCOL_UNIX_DS:
+ break;
+
+ case EPM_PROTOCOL_NULL:
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ ndr->flags = _flags_save_UNION;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_rhs(struct ndr_print *ndr, const char *name, const union epm_rhs *r)
+{
+ int level;
+ {
+ uint32_t _flags_save_UNION = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "epm_rhs");
+ switch (level) {
+ case EPM_PROTOCOL_DNET_NSP:
+ ndr_print_epm_rhs_dnet_nsp(ndr, "dnet_nsp", &r->dnet_nsp);
+ break;
+
+ case EPM_PROTOCOL_OSI_TP4:
+ ndr_print_epm_rhs_osi_tp4(ndr, "osi_tp4", &r->osi_tp4);
+ break;
+
+ case EPM_PROTOCOL_OSI_CLNS:
+ ndr_print_epm_rhs_osi_clns(ndr, "osi_clns", &r->osi_clns);
+ break;
+
+ case EPM_PROTOCOL_TCP:
+ ndr_print_epm_rhs_tcp(ndr, "tcp", &r->tcp);
+ break;
+
+ case EPM_PROTOCOL_UDP:
+ ndr_print_epm_rhs_udp(ndr, "udp", &r->udp);
+ break;
+
+ case EPM_PROTOCOL_IP:
+ ndr_print_epm_rhs_ip(ndr, "ip", &r->ip);
+ break;
+
+ case EPM_PROTOCOL_NCADG:
+ ndr_print_epm_rhs_ncadg(ndr, "ncadg", &r->ncadg);
+ break;
+
+ case EPM_PROTOCOL_NCACN:
+ ndr_print_epm_rhs_ncacn(ndr, "ncacn", &r->ncacn);
+ break;
+
+ case EPM_PROTOCOL_NCALRPC:
+ ndr_print_epm_rhs_ncalrpc(ndr, "ncalrpc", &r->ncalrpc);
+ break;
+
+ case EPM_PROTOCOL_UUID:
+ ndr_print_epm_rhs_uuid(ndr, "uuid", &r->uuid);
+ break;
+
+ case EPM_PROTOCOL_IPX:
+ ndr_print_epm_rhs_ipx(ndr, "ipx", &r->ipx);
+ break;
+
+ case EPM_PROTOCOL_SMB:
+ ndr_print_epm_rhs_smb(ndr, "smb", &r->smb);
+ break;
+
+ case EPM_PROTOCOL_PIPE:
+ ndr_print_epm_rhs_pipe(ndr, "pipe", &r->pipe);
+ break;
+
+ case EPM_PROTOCOL_NETBIOS:
+ ndr_print_epm_rhs_netbios(ndr, "netbios", &r->netbios);
+ break;
+
+ case EPM_PROTOCOL_NETBEUI:
+ ndr_print_epm_rhs_netbeui(ndr, "netbeui", &r->netbeui);
+ break;
+
+ case EPM_PROTOCOL_SPX:
+ ndr_print_epm_rhs_spx(ndr, "spx", &r->spx);
+ break;
+
+ case EPM_PROTOCOL_NB_IPX:
+ ndr_print_epm_rhs_nb_ipx(ndr, "nb_ipx", &r->nb_ipx);
+ break;
+
+ case EPM_PROTOCOL_DSP:
+ ndr_print_epm_rhs_atalk_stream(ndr, "atalk_stream", &r->atalk_stream);
+ break;
+
+ case EPM_PROTOCOL_DDP:
+ ndr_print_epm_rhs_atalk_datagram(ndr, "atalk_datagram", &r->atalk_datagram);
+ break;
+
+ case EPM_PROTOCOL_APPLETALK:
+ ndr_print_epm_rhs_appletalk(ndr, "appletalk", &r->appletalk);
+ break;
+
+ case EPM_PROTOCOL_VINES_SPP:
+ ndr_print_epm_rhs_vines_spp(ndr, "vines_spp", &r->vines_spp);
+ break;
+
+ case EPM_PROTOCOL_VINES_IPC:
+ ndr_print_epm_rhs_vines_ipc(ndr, "vines_ipc", &r->vines_ipc);
+ break;
+
+ case EPM_PROTOCOL_STREETTALK:
+ ndr_print_epm_rhs_streettalk(ndr, "streettalk", &r->streettalk);
+ break;
+
+ case EPM_PROTOCOL_HTTP:
+ ndr_print_epm_rhs_http(ndr, "http", &r->http);
+ break;
+
+ case EPM_PROTOCOL_UNIX_DS:
+ ndr_print_epm_rhs_unix_ds(ndr, "unix_ds", &r->unix_ds);
+ break;
+
+ case EPM_PROTOCOL_NULL:
+ ndr_print_epm_rhs_null(ndr, "null", &r->null);
+ break;
+
+ default:
+ ndr_print_DATA_BLOB(ndr, "unknown", r->unknown);
+ break;
+
+ }
+ ndr->flags = _flags_save_UNION;
+ }
+}
+
+static enum ndr_err_code ndr_push_epm_lhs(struct ndr_push *ndr, int ndr_flags, const struct epm_lhs *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_epm_protocol(ndr, NDR_SCALARS, r->protocol));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->lhs_data));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_lhs(struct ndr_pull *ndr, int ndr_flags, struct epm_lhs *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_epm_protocol(ndr, NDR_SCALARS, &r->protocol));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->lhs_data));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_lhs(struct ndr_print *ndr, const char *name, const struct epm_lhs *r)
+{
+ ndr_print_struct(ndr, name, "epm_lhs");
+ ndr->depth++;
+ ndr_print_epm_protocol(ndr, "protocol", r->protocol);
+ ndr_print_DATA_BLOB(ndr, "lhs_data", r->lhs_data);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_floor(struct ndr_push *ndr, int ndr_flags, const struct epm_floor *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ {
+ struct ndr_push *_ndr_lhs;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_lhs, 2, -1));
+ NDR_CHECK(ndr_push_epm_lhs(_ndr_lhs, NDR_SCALARS, &r->lhs));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_lhs, 2, -1));
+ }
+ {
+ struct ndr_push *_ndr_rhs;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_rhs, 2, -1));
+ NDR_CHECK(ndr_push_set_switch_value(_ndr_rhs, &r->rhs, r->lhs.protocol));
+ NDR_CHECK(ndr_push_epm_rhs(_ndr_rhs, NDR_SCALARS, &r->rhs));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_rhs, 2, -1));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_floor(struct ndr_pull *ndr, int ndr_flags, struct epm_floor *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ {
+ struct ndr_pull *_ndr_lhs;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_lhs, 2, -1));
+ NDR_CHECK(ndr_pull_epm_lhs(_ndr_lhs, NDR_SCALARS, &r->lhs));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_lhs, 2, -1));
+ }
+ {
+ struct ndr_pull *_ndr_rhs;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_rhs, 2, -1));
+ NDR_CHECK(ndr_pull_set_switch_value(_ndr_rhs, &r->rhs, r->lhs.protocol));
+ NDR_CHECK(ndr_pull_epm_rhs(_ndr_rhs, NDR_SCALARS, &r->rhs));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_rhs, 2, -1));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_floor(struct ndr_print *ndr, const char *name, const struct epm_floor *r)
+{
+ ndr_print_struct(ndr, name, "epm_floor");
+ ndr->depth++;
+ ndr_print_epm_lhs(ndr, "lhs", &r->lhs);
+ ndr_print_set_switch_value(ndr, &r->rhs, r->lhs.protocol);
+ ndr_print_epm_rhs(ndr, "rhs", &r->rhs);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_tower(struct ndr_push *ndr, int ndr_flags, const struct epm_tower *r)
+{
+ uint32_t cntr_floors_0;
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_LITTLE_ENDIAN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->num_floors));
+ for (cntr_floors_0 = 0; cntr_floors_0 < r->num_floors; cntr_floors_0++) {
+ NDR_CHECK(ndr_push_epm_floor(ndr, NDR_SCALARS, &r->floors[cntr_floors_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_tower(struct ndr_pull *ndr, int ndr_flags, struct epm_tower *r)
+{
+ uint32_t cntr_floors_0;
+ TALLOC_CTX *_mem_save_floors_0;
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_LITTLE_ENDIAN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->num_floors));
+ NDR_PULL_ALLOC_N(ndr, r->floors, r->num_floors);
+ _mem_save_floors_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->floors, 0);
+ for (cntr_floors_0 = 0; cntr_floors_0 < r->num_floors; cntr_floors_0++) {
+ NDR_CHECK(ndr_pull_epm_floor(ndr, NDR_SCALARS, &r->floors[cntr_floors_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_floors_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_tower(struct ndr_print *ndr, const char *name, const struct epm_tower *r)
+{
+ uint32_t cntr_floors_0;
+ ndr_print_struct(ndr, name, "epm_tower");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_LITTLE_ENDIAN);
+ ndr->depth++;
+ ndr_print_uint16(ndr, "num_floors", r->num_floors);
+ ndr->print(ndr, "%s: ARRAY(%d)", "floors", (int)r->num_floors);
+ ndr->depth++;
+ for (cntr_floors_0=0;cntr_floors_0<r->num_floors;cntr_floors_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_floors_0) != -1) {
+ ndr_print_epm_floor(ndr, "floors", &r->floors[cntr_floors_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static size_t ndr_size_epm_tower(const struct epm_tower *r, int flags)
+{
+ flags |= LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_LITTLE_ENDIAN;
+ return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_epm_tower);
+}
+
+static enum ndr_err_code ndr_push_epm_twr_t(struct ndr_push *ndr, int ndr_flags, const struct epm_twr_t *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_epm_tower(&r->tower, ndr->flags)));
+ {
+ struct ndr_push *_ndr_tower;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_tower, 4, -1));
+ NDR_CHECK(ndr_push_epm_tower(_ndr_tower, NDR_SCALARS, &r->tower));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_tower, 4, -1));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_twr_t(struct ndr_pull *ndr, int ndr_flags, struct epm_twr_t *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->tower_length));
+ {
+ struct ndr_pull *_ndr_tower;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_tower, 4, -1));
+ NDR_CHECK(ndr_pull_epm_tower(_ndr_tower, NDR_SCALARS, &r->tower));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_tower, 4, -1));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_twr_t(struct ndr_print *ndr, const char *name, const struct epm_twr_t *r)
+{
+ ndr_print_struct(ndr, name, "epm_twr_t");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "tower_length", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_epm_tower(&r->tower, ndr->flags):r->tower_length);
+ ndr_print_epm_tower(ndr, "tower", &r->tower);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_entry_t(struct ndr_push *ndr, int ndr_flags, const struct epm_entry_t *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->object));
+ NDR_CHECK(ndr_push_full_ptr(ndr, r->tower));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_LEN4);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->annotation));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_BUFFERS, &r->object));
+ if (r->tower) {
+ NDR_CHECK(ndr_push_epm_twr_t(ndr, NDR_SCALARS, r->tower));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_entry_t(struct ndr_pull *ndr, int ndr_flags, struct epm_entry_t *r)
+{
+ uint32_t _ptr_tower;
+ TALLOC_CTX *_mem_save_tower_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->object));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_tower));
+ if (_ptr_tower) {
+ NDR_PULL_ALLOC(ndr, r->tower);
+ } else {
+ r->tower = NULL;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_LEN4);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->annotation));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_BUFFERS, &r->object));
+ if (r->tower) {
+ _mem_save_tower_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->tower, 0);
+ NDR_CHECK(ndr_pull_epm_twr_t(ndr, NDR_SCALARS, r->tower));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_tower_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_entry_t(struct ndr_print *ndr, const char *name, const struct epm_entry_t *r)
+{
+ ndr_print_struct(ndr, name, "epm_entry_t");
+ ndr->depth++;
+ ndr_print_GUID(ndr, "object", &r->object);
+ ndr_print_ptr(ndr, "tower", r->tower);
+ ndr->depth++;
+ if (r->tower) {
+ ndr_print_epm_twr_t(ndr, "tower", r->tower);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "annotation", r->annotation);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_rpc_if_id_t(struct ndr_push *ndr, int ndr_flags, const struct rpc_if_id_t *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->uuid));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->vers_major));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->vers_minor));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_BUFFERS, &r->uuid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_rpc_if_id_t(struct ndr_pull *ndr, int ndr_flags, struct rpc_if_id_t *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->uuid));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->vers_major));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->vers_minor));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_BUFFERS, &r->uuid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_rpc_if_id_t(struct ndr_print *ndr, const char *name, const struct rpc_if_id_t *r)
+{
+ ndr_print_struct(ndr, name, "rpc_if_id_t");
+ ndr->depth++;
+ ndr_print_GUID(ndr, "uuid", &r->uuid);
+ ndr_print_uint16(ndr, "vers_major", r->vers_major);
+ ndr_print_uint16(ndr, "vers_minor", r->vers_minor);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_twr_p_t(struct ndr_push *ndr, int ndr_flags, const struct epm_twr_p_t *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_full_ptr(ndr, r->twr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->twr) {
+ NDR_CHECK(ndr_push_epm_twr_t(ndr, NDR_SCALARS, r->twr));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_twr_p_t(struct ndr_pull *ndr, int ndr_flags, struct epm_twr_p_t *r)
+{
+ uint32_t _ptr_twr;
+ TALLOC_CTX *_mem_save_twr_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_twr));
+ if (_ptr_twr) {
+ NDR_PULL_ALLOC(ndr, r->twr);
+ } else {
+ r->twr = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->twr) {
+ _mem_save_twr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->twr, 0);
+ NDR_CHECK(ndr_pull_epm_twr_t(ndr, NDR_SCALARS, r->twr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_twr_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_twr_p_t(struct ndr_print *ndr, const char *name, const struct epm_twr_p_t *r)
+{
+ ndr_print_struct(ndr, name, "epm_twr_p_t");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "twr", r->twr);
+ ndr->depth++;
+ if (r->twr) {
+ ndr_print_epm_twr_t(ndr, "twr", r->twr);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_Insert(struct ndr_push *ndr, int flags, const struct epm_Insert *r)
+{
+ uint32_t cntr_entries_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_ents));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_ents));
+ for (cntr_entries_0 = 0; cntr_entries_0 < r->in.num_ents; cntr_entries_0++) {
+ NDR_CHECK(ndr_push_epm_entry_t(ndr, NDR_SCALARS, &r->in.entries[cntr_entries_0]));
+ }
+ for (cntr_entries_0 = 0; cntr_entries_0 < r->in.num_ents; cntr_entries_0++) {
+ NDR_CHECK(ndr_push_epm_entry_t(ndr, NDR_BUFFERS, &r->in.entries[cntr_entries_0]));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.replace));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_Insert(struct ndr_pull *ndr, int flags, struct epm_Insert *r)
+{
+ uint32_t cntr_entries_0;
+ TALLOC_CTX *_mem_save_entries_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.num_ents));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.entries));
+ NDR_PULL_ALLOC_N(ndr, r->in.entries, ndr_get_array_size(ndr, &r->in.entries));
+ _mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.entries, 0);
+ for (cntr_entries_0 = 0; cntr_entries_0 < r->in.num_ents; cntr_entries_0++) {
+ NDR_CHECK(ndr_pull_epm_entry_t(ndr, NDR_SCALARS, &r->in.entries[cntr_entries_0]));
+ }
+ for (cntr_entries_0 = 0; cntr_entries_0 < r->in.num_ents; cntr_entries_0++) {
+ NDR_CHECK(ndr_pull_epm_entry_t(ndr, NDR_BUFFERS, &r->in.entries[cntr_entries_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.replace));
+ if (r->in.entries) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.entries, r->in.num_ents));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_Insert(struct ndr_print *ndr, const char *name, int flags, const struct epm_Insert *r)
+{
+ uint32_t cntr_entries_0;
+ ndr_print_struct(ndr, name, "epm_Insert");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "epm_Insert");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_ents", r->in.num_ents);
+ ndr->print(ndr, "%s: ARRAY(%d)", "entries", (int)r->in.num_ents);
+ ndr->depth++;
+ for (cntr_entries_0=0;cntr_entries_0<r->in.num_ents;cntr_entries_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_entries_0) != -1) {
+ ndr_print_epm_entry_t(ndr, "entries", &r->in.entries[cntr_entries_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "replace", r->in.replace);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "epm_Insert");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_Delete(struct ndr_push *ndr, int flags, const struct epm_Delete *r)
+{
+ uint32_t cntr_entries_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_ents));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_ents));
+ for (cntr_entries_0 = 0; cntr_entries_0 < r->in.num_ents; cntr_entries_0++) {
+ NDR_CHECK(ndr_push_epm_entry_t(ndr, NDR_SCALARS, &r->in.entries[cntr_entries_0]));
+ }
+ for (cntr_entries_0 = 0; cntr_entries_0 < r->in.num_ents; cntr_entries_0++) {
+ NDR_CHECK(ndr_push_epm_entry_t(ndr, NDR_BUFFERS, &r->in.entries[cntr_entries_0]));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_Delete(struct ndr_pull *ndr, int flags, struct epm_Delete *r)
+{
+ uint32_t cntr_entries_0;
+ TALLOC_CTX *_mem_save_entries_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.num_ents));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.entries));
+ NDR_PULL_ALLOC_N(ndr, r->in.entries, ndr_get_array_size(ndr, &r->in.entries));
+ _mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.entries, 0);
+ for (cntr_entries_0 = 0; cntr_entries_0 < r->in.num_ents; cntr_entries_0++) {
+ NDR_CHECK(ndr_pull_epm_entry_t(ndr, NDR_SCALARS, &r->in.entries[cntr_entries_0]));
+ }
+ for (cntr_entries_0 = 0; cntr_entries_0 < r->in.num_ents; cntr_entries_0++) {
+ NDR_CHECK(ndr_pull_epm_entry_t(ndr, NDR_BUFFERS, &r->in.entries[cntr_entries_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0);
+ if (r->in.entries) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.entries, r->in.num_ents));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_Delete(struct ndr_print *ndr, const char *name, int flags, const struct epm_Delete *r)
+{
+ uint32_t cntr_entries_0;
+ ndr_print_struct(ndr, name, "epm_Delete");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "epm_Delete");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_ents", r->in.num_ents);
+ ndr->print(ndr, "%s: ARRAY(%d)", "entries", (int)r->in.num_ents);
+ ndr->depth++;
+ for (cntr_entries_0=0;cntr_entries_0<r->in.num_ents;cntr_entries_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_entries_0) != -1) {
+ ndr_print_epm_entry_t(ndr, "entries", &r->in.entries[cntr_entries_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "epm_Delete");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_Lookup(struct ndr_push *ndr, int flags, const struct epm_Lookup *r)
+{
+ uint32_t cntr_entries_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.inquiry_type));
+ NDR_CHECK(ndr_push_full_ptr(ndr, r->in.object));
+ if (r->in.object) {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.object));
+ }
+ NDR_CHECK(ndr_push_full_ptr(ndr, r->in.interface_id));
+ if (r->in.interface_id) {
+ NDR_CHECK(ndr_push_rpc_if_id_t(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.interface_id));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.vers_option));
+ if (r->in.entry_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.entry_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_ents));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.entry_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.entry_handle));
+ if (r->out.num_ents == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.num_ents));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_ents));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.num_ents));
+ for (cntr_entries_0 = 0; cntr_entries_0 < *r->out.num_ents; cntr_entries_0++) {
+ NDR_CHECK(ndr_push_epm_entry_t(ndr, NDR_SCALARS, &r->out.entries[cntr_entries_0]));
+ }
+ for (cntr_entries_0 = 0; cntr_entries_0 < *r->out.num_ents; cntr_entries_0++) {
+ NDR_CHECK(ndr_push_epm_entry_t(ndr, NDR_BUFFERS, &r->out.entries[cntr_entries_0]));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_Lookup(struct ndr_pull *ndr, int flags, struct epm_Lookup *r)
+{
+ uint32_t _ptr_object;
+ uint32_t _ptr_interface_id;
+ uint32_t cntr_entries_0;
+ TALLOC_CTX *_mem_save_object_0;
+ TALLOC_CTX *_mem_save_interface_id_0;
+ TALLOC_CTX *_mem_save_entry_handle_0;
+ TALLOC_CTX *_mem_save_num_ents_0;
+ TALLOC_CTX *_mem_save_entries_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.inquiry_type));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_object));
+ if (_ptr_object) {
+ NDR_PULL_ALLOC(ndr, r->in.object);
+ } else {
+ r->in.object = NULL;
+ }
+ if (r->in.object) {
+ _mem_save_object_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.object, 0);
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.object));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_object_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_interface_id));
+ if (_ptr_interface_id) {
+ NDR_PULL_ALLOC(ndr, r->in.interface_id);
+ } else {
+ r->in.interface_id = NULL;
+ }
+ if (r->in.interface_id) {
+ _mem_save_interface_id_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.interface_id, 0);
+ NDR_CHECK(ndr_pull_rpc_if_id_t(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.interface_id));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_interface_id_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.vers_option));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.entry_handle);
+ }
+ _mem_save_entry_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.entry_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.entry_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entry_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_ents));
+ NDR_PULL_ALLOC(ndr, r->out.entry_handle);
+ *r->out.entry_handle = *r->in.entry_handle;
+ NDR_PULL_ALLOC(ndr, r->out.num_ents);
+ ZERO_STRUCTP(r->out.num_ents);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.entry_handle);
+ }
+ _mem_save_entry_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.entry_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.entry_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entry_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.num_ents);
+ }
+ _mem_save_num_ents_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.num_ents, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.num_ents));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_num_ents_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->out.entries));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->out.entries));
+ if (ndr_get_array_length(ndr, &r->out.entries) > ndr_get_array_size(ndr, &r->out.entries)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->out.entries), ndr_get_array_length(ndr, &r->out.entries));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->out.entries, ndr_get_array_size(ndr, &r->out.entries));
+ _mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.entries, 0);
+ for (cntr_entries_0 = 0; cntr_entries_0 < *r->out.num_ents; cntr_entries_0++) {
+ NDR_CHECK(ndr_pull_epm_entry_t(ndr, NDR_SCALARS, &r->out.entries[cntr_entries_0]));
+ }
+ for (cntr_entries_0 = 0; cntr_entries_0 < *r->out.num_ents; cntr_entries_0++) {
+ NDR_CHECK(ndr_pull_epm_entry_t(ndr, NDR_BUFFERS, &r->out.entries[cntr_entries_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->out.result));
+ if (r->out.entries) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->out.entries, r->in.max_ents));
+ }
+ if (r->out.entries) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->out.entries, *r->out.num_ents));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_Lookup(struct ndr_print *ndr, const char *name, int flags, const struct epm_Lookup *r)
+{
+ uint32_t cntr_entries_0;
+ ndr_print_struct(ndr, name, "epm_Lookup");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "epm_Lookup");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "inquiry_type", r->in.inquiry_type);
+ ndr_print_ptr(ndr, "object", r->in.object);
+ ndr->depth++;
+ if (r->in.object) {
+ ndr_print_GUID(ndr, "object", r->in.object);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "interface_id", r->in.interface_id);
+ ndr->depth++;
+ if (r->in.interface_id) {
+ ndr_print_rpc_if_id_t(ndr, "interface_id", r->in.interface_id);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "vers_option", r->in.vers_option);
+ ndr_print_ptr(ndr, "entry_handle", r->in.entry_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "entry_handle", r->in.entry_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_ents", r->in.max_ents);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "epm_Lookup");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "entry_handle", r->out.entry_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "entry_handle", r->out.entry_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "num_ents", r->out.num_ents);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_ents", *r->out.num_ents);
+ ndr->depth--;
+ ndr->print(ndr, "%s: ARRAY(%d)", "entries", (int)*r->out.num_ents);
+ ndr->depth++;
+ for (cntr_entries_0=0;cntr_entries_0<*r->out.num_ents;cntr_entries_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_entries_0) != -1) {
+ ndr_print_epm_entry_t(ndr, "entries", &r->out.entries[cntr_entries_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_epm_Map(struct ndr_push *ndr, int flags, const struct epm_Map *r)
+{
+ uint32_t cntr_towers_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_full_ptr(ndr, r->in.object));
+ if (r->in.object) {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.object));
+ }
+ NDR_CHECK(ndr_push_full_ptr(ndr, r->in.map_tower));
+ if (r->in.map_tower) {
+ NDR_CHECK(ndr_push_epm_twr_t(ndr, NDR_SCALARS, r->in.map_tower));
+ }
+ if (r->in.entry_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.entry_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_towers));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.entry_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.entry_handle));
+ if (r->out.num_towers == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.num_towers));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_towers));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.num_towers));
+ for (cntr_towers_0 = 0; cntr_towers_0 < *r->out.num_towers; cntr_towers_0++) {
+ NDR_CHECK(ndr_push_epm_twr_p_t(ndr, NDR_SCALARS, &r->out.towers[cntr_towers_0]));
+ }
+ for (cntr_towers_0 = 0; cntr_towers_0 < *r->out.num_towers; cntr_towers_0++) {
+ NDR_CHECK(ndr_push_epm_twr_p_t(ndr, NDR_BUFFERS, &r->out.towers[cntr_towers_0]));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_epm_Map(struct ndr_pull *ndr, int flags, struct epm_Map *r)
+{
+ uint32_t _ptr_object;
+ uint32_t _ptr_map_tower;
+ uint32_t cntr_towers_0;
+ TALLOC_CTX *_mem_save_object_0;
+ TALLOC_CTX *_mem_save_map_tower_0;
+ TALLOC_CTX *_mem_save_entry_handle_0;
+ TALLOC_CTX *_mem_save_num_towers_0;
+ TALLOC_CTX *_mem_save_towers_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_object));
+ if (_ptr_object) {
+ NDR_PULL_ALLOC(ndr, r->in.object);
+ } else {
+ r->in.object = NULL;
+ }
+ if (r->in.object) {
+ _mem_save_object_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.object, 0);
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.object));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_object_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_map_tower));
+ if (_ptr_map_tower) {
+ NDR_PULL_ALLOC(ndr, r->in.map_tower);
+ } else {
+ r->in.map_tower = NULL;
+ }
+ if (r->in.map_tower) {
+ _mem_save_map_tower_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.map_tower, 0);
+ NDR_CHECK(ndr_pull_epm_twr_t(ndr, NDR_SCALARS, r->in.map_tower));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_map_tower_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.entry_handle);
+ }
+ _mem_save_entry_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.entry_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.entry_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entry_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_towers));
+ NDR_PULL_ALLOC(ndr, r->out.entry_handle);
+ *r->out.entry_handle = *r->in.entry_handle;
+ NDR_PULL_ALLOC(ndr, r->out.num_towers);
+ ZERO_STRUCTP(r->out.num_towers);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.entry_handle);
+ }
+ _mem_save_entry_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.entry_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.entry_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entry_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.num_towers);
+ }
+ _mem_save_num_towers_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.num_towers, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.num_towers));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_num_towers_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->out.towers));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->out.towers));
+ if (ndr_get_array_length(ndr, &r->out.towers) > ndr_get_array_size(ndr, &r->out.towers)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->out.towers), ndr_get_array_length(ndr, &r->out.towers));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->out.towers, ndr_get_array_size(ndr, &r->out.towers));
+ _mem_save_towers_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.towers, 0);
+ for (cntr_towers_0 = 0; cntr_towers_0 < *r->out.num_towers; cntr_towers_0++) {
+ NDR_CHECK(ndr_pull_epm_twr_p_t(ndr, NDR_SCALARS, &r->out.towers[cntr_towers_0]));
+ }
+ for (cntr_towers_0 = 0; cntr_towers_0 < *r->out.num_towers; cntr_towers_0++) {
+ NDR_CHECK(ndr_pull_epm_twr_p_t(ndr, NDR_BUFFERS, &r->out.towers[cntr_towers_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_towers_0, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->out.result));
+ if (r->out.towers) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->out.towers, r->in.max_towers));
+ }
+ if (r->out.towers) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->out.towers, *r->out.num_towers));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_Map(struct ndr_print *ndr, const char *name, int flags, const struct epm_Map *r)
+{
+ uint32_t cntr_towers_0;
+ ndr_print_struct(ndr, name, "epm_Map");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "epm_Map");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "object", r->in.object);
+ ndr->depth++;
+ if (r->in.object) {
+ ndr_print_GUID(ndr, "object", r->in.object);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "map_tower", r->in.map_tower);
+ ndr->depth++;
+ if (r->in.map_tower) {
+ ndr_print_epm_twr_t(ndr, "map_tower", r->in.map_tower);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "entry_handle", r->in.entry_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "entry_handle", r->in.entry_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_towers", r->in.max_towers);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "epm_Map");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "entry_handle", r->out.entry_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "entry_handle", r->out.entry_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "num_towers", r->out.num_towers);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_towers", *r->out.num_towers);
+ ndr->depth--;
+ ndr->print(ndr, "%s: ARRAY(%d)", "towers", (int)*r->out.num_towers);
+ ndr->depth++;
+ for (cntr_towers_0=0;cntr_towers_0<*r->out.num_towers;cntr_towers_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_towers_0) != -1) {
+ ndr_print_epm_twr_p_t(ndr, "towers", &r->out.towers[cntr_towers_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_LookupHandleFree(struct ndr_push *ndr, int flags, const struct epm_LookupHandleFree *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.entry_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.entry_handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.entry_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.entry_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_LookupHandleFree(struct ndr_pull *ndr, int flags, struct epm_LookupHandleFree *r)
+{
+ TALLOC_CTX *_mem_save_entry_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.entry_handle);
+ }
+ _mem_save_entry_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.entry_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.entry_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entry_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.entry_handle);
+ *r->out.entry_handle = *r->in.entry_handle;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.entry_handle);
+ }
+ _mem_save_entry_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.entry_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.entry_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entry_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_LookupHandleFree(struct ndr_print *ndr, const char *name, int flags, const struct epm_LookupHandleFree *r)
+{
+ ndr_print_struct(ndr, name, "epm_LookupHandleFree");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "epm_LookupHandleFree");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "entry_handle", r->in.entry_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "entry_handle", r->in.entry_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "epm_LookupHandleFree");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "entry_handle", r->out.entry_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "entry_handle", r->out.entry_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_InqObject(struct ndr_push *ndr, int flags, const struct epm_InqObject *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.epm_object == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.epm_object));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_InqObject(struct ndr_pull *ndr, int flags, struct epm_InqObject *r)
+{
+ TALLOC_CTX *_mem_save_epm_object_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.epm_object);
+ }
+ _mem_save_epm_object_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.epm_object, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.epm_object));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_epm_object_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_InqObject(struct ndr_print *ndr, const char *name, int flags, const struct epm_InqObject *r)
+{
+ ndr_print_struct(ndr, name, "epm_InqObject");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "epm_InqObject");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "epm_object", r->in.epm_object);
+ ndr->depth++;
+ ndr_print_GUID(ndr, "epm_object", r->in.epm_object);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "epm_InqObject");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_MgmtDelete(struct ndr_push *ndr, int flags, const struct epm_MgmtDelete *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.object_speced));
+ NDR_CHECK(ndr_push_full_ptr(ndr, r->in.object));
+ if (r->in.object) {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.object));
+ }
+ NDR_CHECK(ndr_push_full_ptr(ndr, r->in.tower));
+ if (r->in.tower) {
+ NDR_CHECK(ndr_push_epm_twr_t(ndr, NDR_SCALARS, r->in.tower));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_MgmtDelete(struct ndr_pull *ndr, int flags, struct epm_MgmtDelete *r)
+{
+ uint32_t _ptr_object;
+ uint32_t _ptr_tower;
+ TALLOC_CTX *_mem_save_object_0;
+ TALLOC_CTX *_mem_save_tower_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.object_speced));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_object));
+ if (_ptr_object) {
+ NDR_PULL_ALLOC(ndr, r->in.object);
+ } else {
+ r->in.object = NULL;
+ }
+ if (r->in.object) {
+ _mem_save_object_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.object, 0);
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.object));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_object_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_tower));
+ if (_ptr_tower) {
+ NDR_PULL_ALLOC(ndr, r->in.tower);
+ } else {
+ r->in.tower = NULL;
+ }
+ if (r->in.tower) {
+ _mem_save_tower_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.tower, 0);
+ NDR_CHECK(ndr_pull_epm_twr_t(ndr, NDR_SCALARS, r->in.tower));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_tower_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_MgmtDelete(struct ndr_print *ndr, const char *name, int flags, const struct epm_MgmtDelete *r)
+{
+ ndr_print_struct(ndr, name, "epm_MgmtDelete");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "epm_MgmtDelete");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "object_speced", r->in.object_speced);
+ ndr_print_ptr(ndr, "object", r->in.object);
+ ndr->depth++;
+ if (r->in.object) {
+ ndr_print_GUID(ndr, "object", r->in.object);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "tower", r->in.tower);
+ ndr->depth++;
+ if (r->in.tower) {
+ ndr_print_epm_twr_t(ndr, "tower", r->in.tower);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "epm_MgmtDelete");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_epm_MapAuth(struct ndr_push *ndr, int flags, const struct epm_MapAuth *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_epm_MapAuth(struct ndr_pull *ndr, int flags, struct epm_MapAuth *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_epm_MapAuth(struct ndr_print *ndr, const char *name, int flags, const struct epm_MapAuth *r)
+{
+ ndr_print_struct(ndr, name, "epm_MapAuth");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "epm_MapAuth");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "epm_MapAuth");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call epmapper_calls[] = {
+ {
+ "epm_Insert",
+ sizeof(struct epm_Insert),
+ (ndr_push_flags_fn_t) ndr_push_epm_Insert,
+ (ndr_pull_flags_fn_t) ndr_pull_epm_Insert,
+ (ndr_print_function_t) ndr_print_epm_Insert,
+ false,
+ },
+ {
+ "epm_Delete",
+ sizeof(struct epm_Delete),
+ (ndr_push_flags_fn_t) ndr_push_epm_Delete,
+ (ndr_pull_flags_fn_t) ndr_pull_epm_Delete,
+ (ndr_print_function_t) ndr_print_epm_Delete,
+ false,
+ },
+ {
+ "epm_Lookup",
+ sizeof(struct epm_Lookup),
+ (ndr_push_flags_fn_t) ndr_push_epm_Lookup,
+ (ndr_pull_flags_fn_t) ndr_pull_epm_Lookup,
+ (ndr_print_function_t) ndr_print_epm_Lookup,
+ false,
+ },
+ {
+ "epm_Map",
+ sizeof(struct epm_Map),
+ (ndr_push_flags_fn_t) ndr_push_epm_Map,
+ (ndr_pull_flags_fn_t) ndr_pull_epm_Map,
+ (ndr_print_function_t) ndr_print_epm_Map,
+ false,
+ },
+ {
+ "epm_LookupHandleFree",
+ sizeof(struct epm_LookupHandleFree),
+ (ndr_push_flags_fn_t) ndr_push_epm_LookupHandleFree,
+ (ndr_pull_flags_fn_t) ndr_pull_epm_LookupHandleFree,
+ (ndr_print_function_t) ndr_print_epm_LookupHandleFree,
+ false,
+ },
+ {
+ "epm_InqObject",
+ sizeof(struct epm_InqObject),
+ (ndr_push_flags_fn_t) ndr_push_epm_InqObject,
+ (ndr_pull_flags_fn_t) ndr_pull_epm_InqObject,
+ (ndr_print_function_t) ndr_print_epm_InqObject,
+ false,
+ },
+ {
+ "epm_MgmtDelete",
+ sizeof(struct epm_MgmtDelete),
+ (ndr_push_flags_fn_t) ndr_push_epm_MgmtDelete,
+ (ndr_pull_flags_fn_t) ndr_pull_epm_MgmtDelete,
+ (ndr_print_function_t) ndr_print_epm_MgmtDelete,
+ false,
+ },
+ {
+ "epm_MapAuth",
+ sizeof(struct epm_MapAuth),
+ (ndr_push_flags_fn_t) ndr_push_epm_MapAuth,
+ (ndr_pull_flags_fn_t) ndr_pull_epm_MapAuth,
+ (ndr_print_function_t) ndr_print_epm_MapAuth,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const epmapper_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\epmapper]",
+ "ncacn_ip_tcp:[135]",
+ "ncalrpc:[EPMAPPER]",
+};
+
+static const struct ndr_interface_string_array epmapper_endpoints = {
+ .count = 3,
+ .names = epmapper_endpoint_strings
+};
+
+static const char * const epmapper_authservice_strings[] = {
+ "host",
+};
+
+static const struct ndr_interface_string_array epmapper_authservices = {
+ .count = 1,
+ .names = epmapper_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_epmapper = {
+ .name = "epmapper",
+ .syntax_id = {
+ {0xe1af8308,0x5d1f,0x11c9,{0x91,0xa4},{0x08,0x00,0x2b,0x14,0xa0,0xfa}},
+ NDR_EPMAPPER_VERSION
+ },
+ .helpstring = NDR_EPMAPPER_HELPSTRING,
+ .num_calls = 8,
+ .calls = epmapper_calls,
+ .endpoints = &epmapper_endpoints,
+ .authservices = &epmapper_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_epmapper.h b/source3/librpc/gen_ndr/ndr_epmapper.h
new file mode 100644
index 0000000000..0fac75e0af
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_epmapper.h
@@ -0,0 +1,76 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/epmapper.h"
+
+#ifndef _HEADER_NDR_epmapper
+#define _HEADER_NDR_epmapper
+
+#define NDR_EPMAPPER_UUID "e1af8308-5d1f-11c9-91a4-08002b14a0fa"
+#define NDR_EPMAPPER_VERSION 3.0
+#define NDR_EPMAPPER_NAME "epmapper"
+#define NDR_EPMAPPER_HELPSTRING "EndPoint Mapper"
+extern const struct ndr_interface_table ndr_table_epmapper;
+#define NDR_EPM_INSERT (0x00)
+
+#define NDR_EPM_DELETE (0x01)
+
+#define NDR_EPM_LOOKUP (0x02)
+
+#define NDR_EPM_MAP (0x03)
+
+#define NDR_EPM_LOOKUPHANDLEFREE (0x04)
+
+#define NDR_EPM_INQOBJECT (0x05)
+
+#define NDR_EPM_MGMTDELETE (0x06)
+
+#define NDR_EPM_MAPAUTH (0x07)
+
+#define NDR_EPMAPPER_CALL_COUNT (8)
+void ndr_print_epm_protocol(struct ndr_print *ndr, const char *name, enum epm_protocol r);
+void ndr_print_epm_rhs_dnet_nsp(struct ndr_print *ndr, const char *name, const struct epm_rhs_dnet_nsp *r);
+void ndr_print_epm_rhs_osi_tp4(struct ndr_print *ndr, const char *name, const struct epm_rhs_osi_tp4 *r);
+void ndr_print_epm_rhs_osi_clns(struct ndr_print *ndr, const char *name, const struct epm_rhs_osi_clns *r);
+void ndr_print_epm_rhs_udp(struct ndr_print *ndr, const char *name, const struct epm_rhs_udp *r);
+void ndr_print_epm_rhs_tcp(struct ndr_print *ndr, const char *name, const struct epm_rhs_tcp *r);
+void ndr_print_epm_rhs_ip(struct ndr_print *ndr, const char *name, const struct epm_rhs_ip *r);
+void ndr_print_epm_rhs_ncadg(struct ndr_print *ndr, const char *name, const struct epm_rhs_ncadg *r);
+void ndr_print_epm_rhs_ncacn(struct ndr_print *ndr, const char *name, const struct epm_rhs_ncacn *r);
+void ndr_print_epm_rhs_uuid(struct ndr_print *ndr, const char *name, const struct epm_rhs_uuid *r);
+void ndr_print_epm_rhs_ipx(struct ndr_print *ndr, const char *name, const struct epm_rhs_ipx *r);
+void ndr_print_epm_rhs_smb(struct ndr_print *ndr, const char *name, const struct epm_rhs_smb *r);
+void ndr_print_epm_rhs_pipe(struct ndr_print *ndr, const char *name, const struct epm_rhs_pipe *r);
+void ndr_print_epm_rhs_netbios(struct ndr_print *ndr, const char *name, const struct epm_rhs_netbios *r);
+void ndr_print_epm_rhs_netbeui(struct ndr_print *ndr, const char *name, const struct epm_rhs_netbeui *r);
+void ndr_print_epm_rhs_spx(struct ndr_print *ndr, const char *name, const struct epm_rhs_spx *r);
+void ndr_print_epm_rhs_nb_ipx(struct ndr_print *ndr, const char *name, const struct epm_rhs_nb_ipx *r);
+void ndr_print_epm_rhs_http(struct ndr_print *ndr, const char *name, const struct epm_rhs_http *r);
+void ndr_print_epm_rhs_unix_ds(struct ndr_print *ndr, const char *name, const struct epm_rhs_unix_ds *r);
+void ndr_print_epm_rhs_null(struct ndr_print *ndr, const char *name, const struct epm_rhs_null *r);
+void ndr_print_epm_rhs_ncalrpc(struct ndr_print *ndr, const char *name, const struct epm_rhs_ncalrpc *r);
+void ndr_print_epm_rhs_appletalk(struct ndr_print *ndr, const char *name, const struct epm_rhs_appletalk *r);
+void ndr_print_epm_rhs_atalk_stream(struct ndr_print *ndr, const char *name, const struct epm_rhs_atalk_stream *r);
+void ndr_print_epm_rhs_atalk_datagram(struct ndr_print *ndr, const char *name, const struct epm_rhs_atalk_datagram *r);
+void ndr_print_epm_rhs_vines_spp(struct ndr_print *ndr, const char *name, const struct epm_rhs_vines_spp *r);
+void ndr_print_epm_rhs_vines_ipc(struct ndr_print *ndr, const char *name, const struct epm_rhs_vines_ipc *r);
+void ndr_print_epm_rhs_streettalk(struct ndr_print *ndr, const char *name, const struct epm_rhs_streettalk *r);
+void ndr_print_epm_rhs(struct ndr_print *ndr, const char *name, const union epm_rhs *r);
+void ndr_print_epm_lhs(struct ndr_print *ndr, const char *name, const struct epm_lhs *r);
+void ndr_print_epm_floor(struct ndr_print *ndr, const char *name, const struct epm_floor *r);
+void ndr_print_epm_tower(struct ndr_print *ndr, const char *name, const struct epm_tower *r);
+void ndr_print_epm_twr_t(struct ndr_print *ndr, const char *name, const struct epm_twr_t *r);
+void ndr_print_epm_entry_t(struct ndr_print *ndr, const char *name, const struct epm_entry_t *r);
+void ndr_print_rpc_if_id_t(struct ndr_print *ndr, const char *name, const struct rpc_if_id_t *r);
+void ndr_print_epm_twr_p_t(struct ndr_print *ndr, const char *name, const struct epm_twr_p_t *r);
+void ndr_print_epm_Insert(struct ndr_print *ndr, const char *name, int flags, const struct epm_Insert *r);
+void ndr_print_epm_Delete(struct ndr_print *ndr, const char *name, int flags, const struct epm_Delete *r);
+void ndr_print_epm_Lookup(struct ndr_print *ndr, const char *name, int flags, const struct epm_Lookup *r);
+enum ndr_err_code ndr_push_epm_Map(struct ndr_push *ndr, int flags, const struct epm_Map *r);
+enum ndr_err_code ndr_pull_epm_Map(struct ndr_pull *ndr, int flags, struct epm_Map *r);
+void ndr_print_epm_Map(struct ndr_print *ndr, const char *name, int flags, const struct epm_Map *r);
+void ndr_print_epm_LookupHandleFree(struct ndr_print *ndr, const char *name, int flags, const struct epm_LookupHandleFree *r);
+void ndr_print_epm_InqObject(struct ndr_print *ndr, const char *name, int flags, const struct epm_InqObject *r);
+void ndr_print_epm_MgmtDelete(struct ndr_print *ndr, const char *name, int flags, const struct epm_MgmtDelete *r);
+void ndr_print_epm_MapAuth(struct ndr_print *ndr, const char *name, int flags, const struct epm_MapAuth *r);
+#endif /* _HEADER_NDR_epmapper */
diff --git a/source3/librpc/gen_ndr/ndr_eventlog.c b/source3/librpc/gen_ndr/ndr_eventlog.c
new file mode 100644
index 0000000000..2eb26c4bc4
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_eventlog.c
@@ -0,0 +1,1730 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_eventlog.h"
+
+#include "librpc/gen_ndr/ndr_lsa.h"
+#include "librpc/gen_ndr/ndr_security.h"
+static enum ndr_err_code ndr_push_eventlog_OpenUnknown0(struct ndr_push *ndr, int ndr_flags, const struct eventlog_OpenUnknown0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->unknown0));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->unknown1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_OpenUnknown0(struct ndr_pull *ndr, int ndr_flags, struct eventlog_OpenUnknown0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->unknown0));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->unknown1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_OpenUnknown0(struct ndr_print *ndr, const char *name, const struct eventlog_OpenUnknown0 *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_OpenUnknown0");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "unknown0", r->unknown0);
+ ndr_print_uint16(ndr, "unknown1", r->unknown1);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_eventlog_Record(struct ndr_push *ndr, int ndr_flags, const struct eventlog_Record *r)
+{
+ uint32_t cntr_strings_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->record_number));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->time_generated));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->time_written));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->event_id));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->event_type));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->num_of_strings));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->event_category));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->reserved_flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->closing_record_number));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->stringoffset));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sid_length));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sid_offset));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->data_length));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->data_offset));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->source_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->computer_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ for (cntr_strings_0 = 0; cntr_strings_0 < r->num_of_strings; cntr_strings_0++) {
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->strings[cntr_strings_0]));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->raw_data));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_eventlog_Record(struct ndr_pull *ndr, int ndr_flags, struct eventlog_Record *r)
+{
+ uint32_t cntr_strings_0;
+ TALLOC_CTX *_mem_save_strings_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->record_number));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->time_generated));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->time_written));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->event_id));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->event_type));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->num_of_strings));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->event_category));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->reserved_flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->closing_record_number));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->stringoffset));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sid_length));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sid_offset));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->data_length));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->data_offset));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->source_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->computer_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_PULL_ALLOC_N(ndr, r->strings, r->num_of_strings);
+ _mem_save_strings_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->strings, 0);
+ for (cntr_strings_0 = 0; cntr_strings_0 < r->num_of_strings; cntr_strings_0++) {
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->strings[cntr_strings_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_strings_0, 0);
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->raw_data));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_Record(struct ndr_print *ndr, const char *name, const struct eventlog_Record *r)
+{
+ uint32_t cntr_strings_0;
+ ndr_print_struct(ndr, name, "eventlog_Record");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "size", r->size);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr_print_uint32(ndr, "record_number", r->record_number);
+ ndr_print_uint32(ndr, "time_generated", r->time_generated);
+ ndr_print_uint32(ndr, "time_written", r->time_written);
+ ndr_print_uint32(ndr, "event_id", r->event_id);
+ ndr_print_uint16(ndr, "event_type", r->event_type);
+ ndr_print_uint16(ndr, "num_of_strings", r->num_of_strings);
+ ndr_print_uint16(ndr, "event_category", r->event_category);
+ ndr_print_uint16(ndr, "reserved_flags", r->reserved_flags);
+ ndr_print_uint32(ndr, "closing_record_number", r->closing_record_number);
+ ndr_print_uint32(ndr, "stringoffset", r->stringoffset);
+ ndr_print_uint32(ndr, "sid_length", r->sid_length);
+ ndr_print_uint32(ndr, "sid_offset", r->sid_offset);
+ ndr_print_uint32(ndr, "data_length", r->data_length);
+ ndr_print_uint32(ndr, "data_offset", r->data_offset);
+ ndr_print_string(ndr, "source_name", r->source_name);
+ ndr_print_string(ndr, "computer_name", r->computer_name);
+ ndr->print(ndr, "%s: ARRAY(%d)", "strings", (int)r->num_of_strings);
+ ndr->depth++;
+ for (cntr_strings_0=0;cntr_strings_0<r->num_of_strings;cntr_strings_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_strings_0) != -1) {
+ ndr_print_string(ndr, "strings", r->strings[cntr_strings_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "raw_data", r->raw_data);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_ClearEventLogW(struct ndr_push *ndr, int flags, const struct eventlog_ClearEventLogW *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.backupfile));
+ if (r->in.backupfile) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.backupfile));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_ClearEventLogW(struct ndr_pull *ndr, int flags, struct eventlog_ClearEventLogW *r)
+{
+ uint32_t _ptr_backupfile;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_backupfile_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_backupfile));
+ if (_ptr_backupfile) {
+ NDR_PULL_ALLOC(ndr, r->in.backupfile);
+ } else {
+ r->in.backupfile = NULL;
+ }
+ if (r->in.backupfile) {
+ _mem_save_backupfile_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.backupfile, 0);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.backupfile));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_backupfile_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_ClearEventLogW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ClearEventLogW *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_ClearEventLogW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_ClearEventLogW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "backupfile", r->in.backupfile);
+ ndr->depth++;
+ if (r->in.backupfile) {
+ ndr_print_lsa_String(ndr, "backupfile", r->in.backupfile);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_ClearEventLogW");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_BackupEventLogW(struct ndr_push *ndr, int flags, const struct eventlog_BackupEventLogW *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_BackupEventLogW(struct ndr_pull *ndr, int flags, struct eventlog_BackupEventLogW *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_BackupEventLogW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_BackupEventLogW *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_BackupEventLogW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_BackupEventLogW");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_BackupEventLogW");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_CloseEventLog(struct ndr_push *ndr, int flags, const struct eventlog_CloseEventLog *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_CloseEventLog(struct ndr_pull *ndr, int flags, struct eventlog_CloseEventLog *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ *r->out.handle = *r->in.handle;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_CloseEventLog(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_CloseEventLog *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_CloseEventLog");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_CloseEventLog");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_CloseEventLog");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_DeregisterEventSource(struct ndr_push *ndr, int flags, const struct eventlog_DeregisterEventSource *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_DeregisterEventSource(struct ndr_pull *ndr, int flags, struct eventlog_DeregisterEventSource *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_DeregisterEventSource(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_DeregisterEventSource *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_DeregisterEventSource");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_DeregisterEventSource");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_DeregisterEventSource");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_GetNumRecords(struct ndr_push *ndr, int flags, const struct eventlog_GetNumRecords *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.number == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.number));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_GetNumRecords(struct ndr_pull *ndr, int flags, struct eventlog_GetNumRecords *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_number_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.number);
+ ZERO_STRUCTP(r->out.number);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.number);
+ }
+ _mem_save_number_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.number, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.number));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_number_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_GetNumRecords(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_GetNumRecords *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_GetNumRecords");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_GetNumRecords");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_GetNumRecords");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "number", r->out.number);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "number", *r->out.number);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_GetOldestRecord(struct ndr_push *ndr, int flags, const struct eventlog_GetOldestRecord *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.oldest_entry == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.oldest_entry));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_GetOldestRecord(struct ndr_pull *ndr, int flags, struct eventlog_GetOldestRecord *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_oldest_entry_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.oldest_entry);
+ ZERO_STRUCTP(r->out.oldest_entry);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.oldest_entry);
+ }
+ _mem_save_oldest_entry_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.oldest_entry, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.oldest_entry));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_oldest_entry_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_GetOldestRecord(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_GetOldestRecord *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_GetOldestRecord");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_GetOldestRecord");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_GetOldestRecord");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "oldest_entry", r->out.oldest_entry);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "oldest_entry", *r->out.oldest_entry);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_ChangeNotify(struct ndr_push *ndr, int flags, const struct eventlog_ChangeNotify *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_ChangeNotify(struct ndr_pull *ndr, int flags, struct eventlog_ChangeNotify *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_ChangeNotify(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ChangeNotify *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_ChangeNotify");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_ChangeNotify");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_ChangeNotify");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_OpenEventLogW(struct ndr_push *ndr, int flags, const struct eventlog_OpenEventLogW *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.unknown0));
+ if (r->in.unknown0) {
+ NDR_CHECK(ndr_push_eventlog_OpenUnknown0(ndr, NDR_SCALARS, r->in.unknown0));
+ }
+ if (r->in.logname == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.logname));
+ if (r->in.servername == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.servername));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown3));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_OpenEventLogW(struct ndr_pull *ndr, int flags, struct eventlog_OpenEventLogW *r)
+{
+ uint32_t _ptr_unknown0;
+ TALLOC_CTX *_mem_save_unknown0_0;
+ TALLOC_CTX *_mem_save_logname_0;
+ TALLOC_CTX *_mem_save_servername_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown0));
+ if (_ptr_unknown0) {
+ NDR_PULL_ALLOC(ndr, r->in.unknown0);
+ } else {
+ r->in.unknown0 = NULL;
+ }
+ if (r->in.unknown0) {
+ _mem_save_unknown0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.unknown0, 0);
+ NDR_CHECK(ndr_pull_eventlog_OpenUnknown0(ndr, NDR_SCALARS, r->in.unknown0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown0_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.logname);
+ }
+ _mem_save_logname_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.logname, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.logname));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_logname_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.servername);
+ }
+ _mem_save_servername_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.servername, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.servername));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_servername_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown3));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_OpenEventLogW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_OpenEventLogW *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_OpenEventLogW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_OpenEventLogW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "unknown0", r->in.unknown0);
+ ndr->depth++;
+ if (r->in.unknown0) {
+ ndr_print_eventlog_OpenUnknown0(ndr, "unknown0", r->in.unknown0);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "logname", r->in.logname);
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "logname", r->in.logname);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "servername", r->in.servername);
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "servername", r->in.servername);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown2", r->in.unknown2);
+ ndr_print_uint32(ndr, "unknown3", r->in.unknown3);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_OpenEventLogW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_RegisterEventSourceW(struct ndr_push *ndr, int flags, const struct eventlog_RegisterEventSourceW *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_RegisterEventSourceW(struct ndr_pull *ndr, int flags, struct eventlog_RegisterEventSourceW *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_RegisterEventSourceW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_RegisterEventSourceW *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_RegisterEventSourceW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_RegisterEventSourceW");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_RegisterEventSourceW");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_OpenBackupEventLogW(struct ndr_push *ndr, int flags, const struct eventlog_OpenBackupEventLogW *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_OpenBackupEventLogW(struct ndr_pull *ndr, int flags, struct eventlog_OpenBackupEventLogW *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_OpenBackupEventLogW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_OpenBackupEventLogW *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_OpenBackupEventLogW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_OpenBackupEventLogW");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_OpenBackupEventLogW");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_ReadEventLogW(struct ndr_push *ndr, int flags, const struct eventlog_ReadEventLogW *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.offset));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.number_of_bytes));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.data == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.number_of_bytes));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.data, r->in.number_of_bytes));
+ if (r->out.sent_size == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.sent_size));
+ if (r->out.real_size == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.real_size));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_ReadEventLogW(struct ndr_pull *ndr, int flags, struct eventlog_ReadEventLogW *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sent_size_0;
+ TALLOC_CTX *_mem_save_real_size_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.offset));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.number_of_bytes));
+ if (r->in.number_of_bytes < 0 || r->in.number_of_bytes > 0x7FFFF) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_PULL_ALLOC_N(ndr, r->out.data, r->in.number_of_bytes);
+ memset(r->out.data, 0, (r->in.number_of_bytes) * sizeof(*r->out.data));
+ NDR_PULL_ALLOC(ndr, r->out.sent_size);
+ ZERO_STRUCTP(r->out.sent_size);
+ NDR_PULL_ALLOC(ndr, r->out.real_size);
+ ZERO_STRUCTP(r->out.real_size);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->out.data));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC_N(ndr, r->out.data, ndr_get_array_size(ndr, &r->out.data));
+ }
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.data, ndr_get_array_size(ndr, &r->out.data)));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sent_size);
+ }
+ _mem_save_sent_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sent_size, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.sent_size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sent_size_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.real_size);
+ }
+ _mem_save_real_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.real_size, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.real_size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_real_size_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ if (r->out.data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->out.data, r->in.number_of_bytes));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_ReadEventLogW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ReadEventLogW *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_ReadEventLogW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_ReadEventLogW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr_print_uint32(ndr, "offset", r->in.offset);
+ ndr_print_uint32(ndr, "number_of_bytes", r->in.number_of_bytes);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_ReadEventLogW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "data", r->out.data);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "data", r->out.data, r->in.number_of_bytes);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sent_size", r->out.sent_size);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "sent_size", *r->out.sent_size);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "real_size", r->out.real_size);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "real_size", *r->out.real_size);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_ReportEventW(struct ndr_push *ndr, int flags, const struct eventlog_ReportEventW *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_ReportEventW(struct ndr_pull *ndr, int flags, struct eventlog_ReportEventW *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_ReportEventW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ReportEventW *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_ReportEventW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_ReportEventW");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_ReportEventW");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_ClearEventLogA(struct ndr_push *ndr, int flags, const struct eventlog_ClearEventLogA *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_ClearEventLogA(struct ndr_pull *ndr, int flags, struct eventlog_ClearEventLogA *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_ClearEventLogA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ClearEventLogA *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_ClearEventLogA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_ClearEventLogA");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_ClearEventLogA");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_BackupEventLogA(struct ndr_push *ndr, int flags, const struct eventlog_BackupEventLogA *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_BackupEventLogA(struct ndr_pull *ndr, int flags, struct eventlog_BackupEventLogA *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_BackupEventLogA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_BackupEventLogA *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_BackupEventLogA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_BackupEventLogA");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_BackupEventLogA");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_OpenEventLogA(struct ndr_push *ndr, int flags, const struct eventlog_OpenEventLogA *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_OpenEventLogA(struct ndr_pull *ndr, int flags, struct eventlog_OpenEventLogA *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_OpenEventLogA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_OpenEventLogA *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_OpenEventLogA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_OpenEventLogA");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_OpenEventLogA");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_RegisterEventSourceA(struct ndr_push *ndr, int flags, const struct eventlog_RegisterEventSourceA *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_RegisterEventSourceA(struct ndr_pull *ndr, int flags, struct eventlog_RegisterEventSourceA *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_RegisterEventSourceA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_RegisterEventSourceA *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_RegisterEventSourceA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_RegisterEventSourceA");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_RegisterEventSourceA");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_OpenBackupEventLogA(struct ndr_push *ndr, int flags, const struct eventlog_OpenBackupEventLogA *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_OpenBackupEventLogA(struct ndr_pull *ndr, int flags, struct eventlog_OpenBackupEventLogA *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_OpenBackupEventLogA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_OpenBackupEventLogA *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_OpenBackupEventLogA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_OpenBackupEventLogA");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_OpenBackupEventLogA");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_ReadEventLogA(struct ndr_push *ndr, int flags, const struct eventlog_ReadEventLogA *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_ReadEventLogA(struct ndr_pull *ndr, int flags, struct eventlog_ReadEventLogA *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_ReadEventLogA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ReadEventLogA *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_ReadEventLogA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_ReadEventLogA");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_ReadEventLogA");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_ReportEventA(struct ndr_push *ndr, int flags, const struct eventlog_ReportEventA *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_ReportEventA(struct ndr_pull *ndr, int flags, struct eventlog_ReportEventA *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_ReportEventA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ReportEventA *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_ReportEventA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_ReportEventA");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_ReportEventA");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_RegisterClusterSvc(struct ndr_push *ndr, int flags, const struct eventlog_RegisterClusterSvc *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_RegisterClusterSvc(struct ndr_pull *ndr, int flags, struct eventlog_RegisterClusterSvc *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_RegisterClusterSvc(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_RegisterClusterSvc *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_RegisterClusterSvc");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_RegisterClusterSvc");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_RegisterClusterSvc");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_DeregisterClusterSvc(struct ndr_push *ndr, int flags, const struct eventlog_DeregisterClusterSvc *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_DeregisterClusterSvc(struct ndr_pull *ndr, int flags, struct eventlog_DeregisterClusterSvc *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_DeregisterClusterSvc(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_DeregisterClusterSvc *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_DeregisterClusterSvc");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_DeregisterClusterSvc");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_DeregisterClusterSvc");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_WriteClusterEvents(struct ndr_push *ndr, int flags, const struct eventlog_WriteClusterEvents *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_WriteClusterEvents(struct ndr_pull *ndr, int flags, struct eventlog_WriteClusterEvents *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_WriteClusterEvents(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_WriteClusterEvents *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_WriteClusterEvents");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_WriteClusterEvents");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_WriteClusterEvents");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_GetLogIntormation(struct ndr_push *ndr, int flags, const struct eventlog_GetLogIntormation *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_GetLogIntormation(struct ndr_pull *ndr, int flags, struct eventlog_GetLogIntormation *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_GetLogIntormation(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_GetLogIntormation *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_GetLogIntormation");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_GetLogIntormation");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_GetLogIntormation");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_eventlog_FlushEventLog(struct ndr_push *ndr, int flags, const struct eventlog_FlushEventLog *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_eventlog_FlushEventLog(struct ndr_pull *ndr, int flags, struct eventlog_FlushEventLog *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_eventlog_FlushEventLog(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_FlushEventLog *r)
+{
+ ndr_print_struct(ndr, name, "eventlog_FlushEventLog");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "eventlog_FlushEventLog");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "eventlog_FlushEventLog");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call eventlog_calls[] = {
+ {
+ "eventlog_ClearEventLogW",
+ sizeof(struct eventlog_ClearEventLogW),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_ClearEventLogW,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_ClearEventLogW,
+ (ndr_print_function_t) ndr_print_eventlog_ClearEventLogW,
+ false,
+ },
+ {
+ "eventlog_BackupEventLogW",
+ sizeof(struct eventlog_BackupEventLogW),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_BackupEventLogW,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_BackupEventLogW,
+ (ndr_print_function_t) ndr_print_eventlog_BackupEventLogW,
+ false,
+ },
+ {
+ "eventlog_CloseEventLog",
+ sizeof(struct eventlog_CloseEventLog),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_CloseEventLog,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_CloseEventLog,
+ (ndr_print_function_t) ndr_print_eventlog_CloseEventLog,
+ false,
+ },
+ {
+ "eventlog_DeregisterEventSource",
+ sizeof(struct eventlog_DeregisterEventSource),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_DeregisterEventSource,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_DeregisterEventSource,
+ (ndr_print_function_t) ndr_print_eventlog_DeregisterEventSource,
+ false,
+ },
+ {
+ "eventlog_GetNumRecords",
+ sizeof(struct eventlog_GetNumRecords),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_GetNumRecords,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_GetNumRecords,
+ (ndr_print_function_t) ndr_print_eventlog_GetNumRecords,
+ false,
+ },
+ {
+ "eventlog_GetOldestRecord",
+ sizeof(struct eventlog_GetOldestRecord),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_GetOldestRecord,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_GetOldestRecord,
+ (ndr_print_function_t) ndr_print_eventlog_GetOldestRecord,
+ false,
+ },
+ {
+ "eventlog_ChangeNotify",
+ sizeof(struct eventlog_ChangeNotify),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_ChangeNotify,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_ChangeNotify,
+ (ndr_print_function_t) ndr_print_eventlog_ChangeNotify,
+ false,
+ },
+ {
+ "eventlog_OpenEventLogW",
+ sizeof(struct eventlog_OpenEventLogW),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_OpenEventLogW,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_OpenEventLogW,
+ (ndr_print_function_t) ndr_print_eventlog_OpenEventLogW,
+ false,
+ },
+ {
+ "eventlog_RegisterEventSourceW",
+ sizeof(struct eventlog_RegisterEventSourceW),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_RegisterEventSourceW,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_RegisterEventSourceW,
+ (ndr_print_function_t) ndr_print_eventlog_RegisterEventSourceW,
+ false,
+ },
+ {
+ "eventlog_OpenBackupEventLogW",
+ sizeof(struct eventlog_OpenBackupEventLogW),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_OpenBackupEventLogW,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_OpenBackupEventLogW,
+ (ndr_print_function_t) ndr_print_eventlog_OpenBackupEventLogW,
+ false,
+ },
+ {
+ "eventlog_ReadEventLogW",
+ sizeof(struct eventlog_ReadEventLogW),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_ReadEventLogW,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_ReadEventLogW,
+ (ndr_print_function_t) ndr_print_eventlog_ReadEventLogW,
+ false,
+ },
+ {
+ "eventlog_ReportEventW",
+ sizeof(struct eventlog_ReportEventW),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_ReportEventW,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_ReportEventW,
+ (ndr_print_function_t) ndr_print_eventlog_ReportEventW,
+ false,
+ },
+ {
+ "eventlog_ClearEventLogA",
+ sizeof(struct eventlog_ClearEventLogA),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_ClearEventLogA,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_ClearEventLogA,
+ (ndr_print_function_t) ndr_print_eventlog_ClearEventLogA,
+ false,
+ },
+ {
+ "eventlog_BackupEventLogA",
+ sizeof(struct eventlog_BackupEventLogA),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_BackupEventLogA,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_BackupEventLogA,
+ (ndr_print_function_t) ndr_print_eventlog_BackupEventLogA,
+ false,
+ },
+ {
+ "eventlog_OpenEventLogA",
+ sizeof(struct eventlog_OpenEventLogA),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_OpenEventLogA,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_OpenEventLogA,
+ (ndr_print_function_t) ndr_print_eventlog_OpenEventLogA,
+ false,
+ },
+ {
+ "eventlog_RegisterEventSourceA",
+ sizeof(struct eventlog_RegisterEventSourceA),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_RegisterEventSourceA,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_RegisterEventSourceA,
+ (ndr_print_function_t) ndr_print_eventlog_RegisterEventSourceA,
+ false,
+ },
+ {
+ "eventlog_OpenBackupEventLogA",
+ sizeof(struct eventlog_OpenBackupEventLogA),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_OpenBackupEventLogA,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_OpenBackupEventLogA,
+ (ndr_print_function_t) ndr_print_eventlog_OpenBackupEventLogA,
+ false,
+ },
+ {
+ "eventlog_ReadEventLogA",
+ sizeof(struct eventlog_ReadEventLogA),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_ReadEventLogA,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_ReadEventLogA,
+ (ndr_print_function_t) ndr_print_eventlog_ReadEventLogA,
+ false,
+ },
+ {
+ "eventlog_ReportEventA",
+ sizeof(struct eventlog_ReportEventA),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_ReportEventA,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_ReportEventA,
+ (ndr_print_function_t) ndr_print_eventlog_ReportEventA,
+ false,
+ },
+ {
+ "eventlog_RegisterClusterSvc",
+ sizeof(struct eventlog_RegisterClusterSvc),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_RegisterClusterSvc,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_RegisterClusterSvc,
+ (ndr_print_function_t) ndr_print_eventlog_RegisterClusterSvc,
+ false,
+ },
+ {
+ "eventlog_DeregisterClusterSvc",
+ sizeof(struct eventlog_DeregisterClusterSvc),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_DeregisterClusterSvc,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_DeregisterClusterSvc,
+ (ndr_print_function_t) ndr_print_eventlog_DeregisterClusterSvc,
+ false,
+ },
+ {
+ "eventlog_WriteClusterEvents",
+ sizeof(struct eventlog_WriteClusterEvents),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_WriteClusterEvents,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_WriteClusterEvents,
+ (ndr_print_function_t) ndr_print_eventlog_WriteClusterEvents,
+ false,
+ },
+ {
+ "eventlog_GetLogIntormation",
+ sizeof(struct eventlog_GetLogIntormation),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_GetLogIntormation,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_GetLogIntormation,
+ (ndr_print_function_t) ndr_print_eventlog_GetLogIntormation,
+ false,
+ },
+ {
+ "eventlog_FlushEventLog",
+ sizeof(struct eventlog_FlushEventLog),
+ (ndr_push_flags_fn_t) ndr_push_eventlog_FlushEventLog,
+ (ndr_pull_flags_fn_t) ndr_pull_eventlog_FlushEventLog,
+ (ndr_print_function_t) ndr_print_eventlog_FlushEventLog,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const eventlog_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\eventlog]",
+};
+
+static const struct ndr_interface_string_array eventlog_endpoints = {
+ .count = 1,
+ .names = eventlog_endpoint_strings
+};
+
+static const char * const eventlog_authservice_strings[] = {
+ "host",
+};
+
+static const struct ndr_interface_string_array eventlog_authservices = {
+ .count = 1,
+ .names = eventlog_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_eventlog = {
+ .name = "eventlog",
+ .syntax_id = {
+ {0x82273fdc,0xe32a,0x18c3,{0x3f,0x78},{0x82,0x79,0x29,0xdc,0x23,0xea}},
+ NDR_EVENTLOG_VERSION
+ },
+ .helpstring = NDR_EVENTLOG_HELPSTRING,
+ .num_calls = 24,
+ .calls = eventlog_calls,
+ .endpoints = &eventlog_endpoints,
+ .authservices = &eventlog_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_eventlog.h b/source3/librpc/gen_ndr/ndr_eventlog.h
new file mode 100644
index 0000000000..6c6e679eca
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_eventlog.h
@@ -0,0 +1,91 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/eventlog.h"
+
+#ifndef _HEADER_NDR_eventlog
+#define _HEADER_NDR_eventlog
+
+#define NDR_EVENTLOG_UUID "82273fdc-e32a-18c3-3f78-827929dc23ea"
+#define NDR_EVENTLOG_VERSION 0.0
+#define NDR_EVENTLOG_NAME "eventlog"
+#define NDR_EVENTLOG_HELPSTRING "Event Logger"
+extern const struct ndr_interface_table ndr_table_eventlog;
+#define NDR_EVENTLOG_CLEAREVENTLOGW (0x00)
+
+#define NDR_EVENTLOG_BACKUPEVENTLOGW (0x01)
+
+#define NDR_EVENTLOG_CLOSEEVENTLOG (0x02)
+
+#define NDR_EVENTLOG_DEREGISTEREVENTSOURCE (0x03)
+
+#define NDR_EVENTLOG_GETNUMRECORDS (0x04)
+
+#define NDR_EVENTLOG_GETOLDESTRECORD (0x05)
+
+#define NDR_EVENTLOG_CHANGENOTIFY (0x06)
+
+#define NDR_EVENTLOG_OPENEVENTLOGW (0x07)
+
+#define NDR_EVENTLOG_REGISTEREVENTSOURCEW (0x08)
+
+#define NDR_EVENTLOG_OPENBACKUPEVENTLOGW (0x09)
+
+#define NDR_EVENTLOG_READEVENTLOGW (0x0a)
+
+#define NDR_EVENTLOG_REPORTEVENTW (0x0b)
+
+#define NDR_EVENTLOG_CLEAREVENTLOGA (0x0c)
+
+#define NDR_EVENTLOG_BACKUPEVENTLOGA (0x0d)
+
+#define NDR_EVENTLOG_OPENEVENTLOGA (0x0e)
+
+#define NDR_EVENTLOG_REGISTEREVENTSOURCEA (0x0f)
+
+#define NDR_EVENTLOG_OPENBACKUPEVENTLOGA (0x10)
+
+#define NDR_EVENTLOG_READEVENTLOGA (0x11)
+
+#define NDR_EVENTLOG_REPORTEVENTA (0x12)
+
+#define NDR_EVENTLOG_REGISTERCLUSTERSVC (0x13)
+
+#define NDR_EVENTLOG_DEREGISTERCLUSTERSVC (0x14)
+
+#define NDR_EVENTLOG_WRITECLUSTEREVENTS (0x15)
+
+#define NDR_EVENTLOG_GETLOGINTORMATION (0x16)
+
+#define NDR_EVENTLOG_FLUSHEVENTLOG (0x17)
+
+#define NDR_EVENTLOG_CALL_COUNT (24)
+void ndr_print_eventlog_OpenUnknown0(struct ndr_print *ndr, const char *name, const struct eventlog_OpenUnknown0 *r);
+enum ndr_err_code ndr_push_eventlog_Record(struct ndr_push *ndr, int ndr_flags, const struct eventlog_Record *r);
+enum ndr_err_code ndr_pull_eventlog_Record(struct ndr_pull *ndr, int ndr_flags, struct eventlog_Record *r);
+void ndr_print_eventlog_Record(struct ndr_print *ndr, const char *name, const struct eventlog_Record *r);
+void ndr_print_eventlog_ClearEventLogW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ClearEventLogW *r);
+void ndr_print_eventlog_BackupEventLogW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_BackupEventLogW *r);
+void ndr_print_eventlog_CloseEventLog(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_CloseEventLog *r);
+void ndr_print_eventlog_DeregisterEventSource(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_DeregisterEventSource *r);
+void ndr_print_eventlog_GetNumRecords(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_GetNumRecords *r);
+void ndr_print_eventlog_GetOldestRecord(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_GetOldestRecord *r);
+void ndr_print_eventlog_ChangeNotify(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ChangeNotify *r);
+void ndr_print_eventlog_OpenEventLogW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_OpenEventLogW *r);
+void ndr_print_eventlog_RegisterEventSourceW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_RegisterEventSourceW *r);
+void ndr_print_eventlog_OpenBackupEventLogW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_OpenBackupEventLogW *r);
+void ndr_print_eventlog_ReadEventLogW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ReadEventLogW *r);
+void ndr_print_eventlog_ReportEventW(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ReportEventW *r);
+void ndr_print_eventlog_ClearEventLogA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ClearEventLogA *r);
+void ndr_print_eventlog_BackupEventLogA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_BackupEventLogA *r);
+void ndr_print_eventlog_OpenEventLogA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_OpenEventLogA *r);
+void ndr_print_eventlog_RegisterEventSourceA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_RegisterEventSourceA *r);
+void ndr_print_eventlog_OpenBackupEventLogA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_OpenBackupEventLogA *r);
+void ndr_print_eventlog_ReadEventLogA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ReadEventLogA *r);
+void ndr_print_eventlog_ReportEventA(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_ReportEventA *r);
+void ndr_print_eventlog_RegisterClusterSvc(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_RegisterClusterSvc *r);
+void ndr_print_eventlog_DeregisterClusterSvc(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_DeregisterClusterSvc *r);
+void ndr_print_eventlog_WriteClusterEvents(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_WriteClusterEvents *r);
+void ndr_print_eventlog_GetLogIntormation(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_GetLogIntormation *r);
+void ndr_print_eventlog_FlushEventLog(struct ndr_print *ndr, const char *name, int flags, const struct eventlog_FlushEventLog *r);
+#endif /* _HEADER_NDR_eventlog */
diff --git a/source3/librpc/gen_ndr/ndr_initshutdown.c b/source3/librpc/gen_ndr/ndr_initshutdown.c
new file mode 100644
index 0000000000..5d6c0c3c08
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_initshutdown.c
@@ -0,0 +1,429 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_initshutdown.h"
+
+static enum ndr_err_code ndr_push_initshutdown_String_sub(struct ndr_push *ndr, int ndr_flags, const struct initshutdown_String_sub *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, strlen_m_term(r->name)));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->name));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_initshutdown_String_sub(struct ndr_pull *ndr, int ndr_flags, struct initshutdown_String_sub *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->name_size));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->name));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_initshutdown_String_sub(struct ndr_print *ndr, const char *name, const struct initshutdown_String_sub *r)
+{
+ ndr_print_struct(ndr, name, "initshutdown_String_sub");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "name_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen_m_term(r->name):r->name_size);
+ ndr_print_string(ndr, "name", r->name);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_initshutdown_String(struct ndr_push *ndr, int ndr_flags, const struct initshutdown_String *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, strlen_m(r->name->name) * 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, strlen_m_term(r->name->name) * 2));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ NDR_CHECK(ndr_push_initshutdown_String_sub(ndr, NDR_SCALARS, r->name));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_initshutdown_String(struct ndr_pull *ndr, int ndr_flags, struct initshutdown_String *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->name_len));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->name_size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_initshutdown_String_sub(ndr, NDR_SCALARS, r->name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_initshutdown_String(struct ndr_print *ndr, const char *name, const struct initshutdown_String *r)
+{
+ ndr_print_struct(ndr, name, "initshutdown_String");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "name_len", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen_m(r->name->name) * 2:r->name_len);
+ ndr_print_uint16(ndr, "name_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen_m_term(r->name->name) * 2:r->name_size);
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_initshutdown_String_sub(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_initshutdown_Init(struct ndr_push *ndr, int flags, const struct initshutdown_Init *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.hostname));
+ if (r->in.hostname) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.hostname));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.message));
+ if (r->in.message) {
+ NDR_CHECK(ndr_push_initshutdown_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.message));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.timeout));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.force_apps));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.do_reboot));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_initshutdown_Init(struct ndr_pull *ndr, int flags, struct initshutdown_Init *r)
+{
+ uint32_t _ptr_hostname;
+ uint32_t _ptr_message;
+ TALLOC_CTX *_mem_save_hostname_0;
+ TALLOC_CTX *_mem_save_message_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_hostname));
+ if (_ptr_hostname) {
+ NDR_PULL_ALLOC(ndr, r->in.hostname);
+ } else {
+ r->in.hostname = NULL;
+ }
+ if (r->in.hostname) {
+ _mem_save_hostname_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.hostname, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.hostname));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_hostname_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_message));
+ if (_ptr_message) {
+ NDR_PULL_ALLOC(ndr, r->in.message);
+ } else {
+ r->in.message = NULL;
+ }
+ if (r->in.message) {
+ _mem_save_message_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.message, 0);
+ NDR_CHECK(ndr_pull_initshutdown_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.message));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_message_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.timeout));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.force_apps));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.do_reboot));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_initshutdown_Init(struct ndr_print *ndr, const char *name, int flags, const struct initshutdown_Init *r)
+{
+ ndr_print_struct(ndr, name, "initshutdown_Init");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "initshutdown_Init");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "hostname", r->in.hostname);
+ ndr->depth++;
+ if (r->in.hostname) {
+ ndr_print_uint16(ndr, "hostname", *r->in.hostname);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "message", r->in.message);
+ ndr->depth++;
+ if (r->in.message) {
+ ndr_print_initshutdown_String(ndr, "message", r->in.message);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "timeout", r->in.timeout);
+ ndr_print_uint8(ndr, "force_apps", r->in.force_apps);
+ ndr_print_uint8(ndr, "do_reboot", r->in.do_reboot);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "initshutdown_Init");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_initshutdown_Abort(struct ndr_push *ndr, int flags, const struct initshutdown_Abort *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server));
+ if (r->in.server) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.server));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_initshutdown_Abort(struct ndr_pull *ndr, int flags, struct initshutdown_Abort *r)
+{
+ uint32_t _ptr_server;
+ TALLOC_CTX *_mem_save_server_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server));
+ if (_ptr_server) {
+ NDR_PULL_ALLOC(ndr, r->in.server);
+ } else {
+ r->in.server = NULL;
+ }
+ if (r->in.server) {
+ _mem_save_server_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.server));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_initshutdown_Abort(struct ndr_print *ndr, const char *name, int flags, const struct initshutdown_Abort *r)
+{
+ ndr_print_struct(ndr, name, "initshutdown_Abort");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "initshutdown_Abort");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server", r->in.server);
+ ndr->depth++;
+ if (r->in.server) {
+ ndr_print_uint16(ndr, "server", *r->in.server);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "initshutdown_Abort");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_initshutdown_InitEx(struct ndr_push *ndr, int flags, const struct initshutdown_InitEx *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.hostname));
+ if (r->in.hostname) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.hostname));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.message));
+ if (r->in.message) {
+ NDR_CHECK(ndr_push_initshutdown_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.message));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.timeout));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.force_apps));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.do_reboot));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.reason));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_initshutdown_InitEx(struct ndr_pull *ndr, int flags, struct initshutdown_InitEx *r)
+{
+ uint32_t _ptr_hostname;
+ uint32_t _ptr_message;
+ TALLOC_CTX *_mem_save_hostname_0;
+ TALLOC_CTX *_mem_save_message_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_hostname));
+ if (_ptr_hostname) {
+ NDR_PULL_ALLOC(ndr, r->in.hostname);
+ } else {
+ r->in.hostname = NULL;
+ }
+ if (r->in.hostname) {
+ _mem_save_hostname_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.hostname, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.hostname));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_hostname_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_message));
+ if (_ptr_message) {
+ NDR_PULL_ALLOC(ndr, r->in.message);
+ } else {
+ r->in.message = NULL;
+ }
+ if (r->in.message) {
+ _mem_save_message_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.message, 0);
+ NDR_CHECK(ndr_pull_initshutdown_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.message));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_message_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.timeout));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.force_apps));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.do_reboot));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.reason));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_initshutdown_InitEx(struct ndr_print *ndr, const char *name, int flags, const struct initshutdown_InitEx *r)
+{
+ ndr_print_struct(ndr, name, "initshutdown_InitEx");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "initshutdown_InitEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "hostname", r->in.hostname);
+ ndr->depth++;
+ if (r->in.hostname) {
+ ndr_print_uint16(ndr, "hostname", *r->in.hostname);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "message", r->in.message);
+ ndr->depth++;
+ if (r->in.message) {
+ ndr_print_initshutdown_String(ndr, "message", r->in.message);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "timeout", r->in.timeout);
+ ndr_print_uint8(ndr, "force_apps", r->in.force_apps);
+ ndr_print_uint8(ndr, "do_reboot", r->in.do_reboot);
+ ndr_print_uint32(ndr, "reason", r->in.reason);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "initshutdown_InitEx");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call initshutdown_calls[] = {
+ {
+ "initshutdown_Init",
+ sizeof(struct initshutdown_Init),
+ (ndr_push_flags_fn_t) ndr_push_initshutdown_Init,
+ (ndr_pull_flags_fn_t) ndr_pull_initshutdown_Init,
+ (ndr_print_function_t) ndr_print_initshutdown_Init,
+ false,
+ },
+ {
+ "initshutdown_Abort",
+ sizeof(struct initshutdown_Abort),
+ (ndr_push_flags_fn_t) ndr_push_initshutdown_Abort,
+ (ndr_pull_flags_fn_t) ndr_pull_initshutdown_Abort,
+ (ndr_print_function_t) ndr_print_initshutdown_Abort,
+ false,
+ },
+ {
+ "initshutdown_InitEx",
+ sizeof(struct initshutdown_InitEx),
+ (ndr_push_flags_fn_t) ndr_push_initshutdown_InitEx,
+ (ndr_pull_flags_fn_t) ndr_pull_initshutdown_InitEx,
+ (ndr_print_function_t) ndr_print_initshutdown_InitEx,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const initshutdown_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\InitShutdown]",
+};
+
+static const struct ndr_interface_string_array initshutdown_endpoints = {
+ .count = 1,
+ .names = initshutdown_endpoint_strings
+};
+
+static const char * const initshutdown_authservice_strings[] = {
+ "host",
+};
+
+static const struct ndr_interface_string_array initshutdown_authservices = {
+ .count = 1,
+ .names = initshutdown_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_initshutdown = {
+ .name = "initshutdown",
+ .syntax_id = {
+ {0x894de0c0,0x0d55,0x11d3,{0xa3,0x22},{0x00,0xc0,0x4f,0xa3,0x21,0xa1}},
+ NDR_INITSHUTDOWN_VERSION
+ },
+ .helpstring = NDR_INITSHUTDOWN_HELPSTRING,
+ .num_calls = 3,
+ .calls = initshutdown_calls,
+ .endpoints = &initshutdown_endpoints,
+ .authservices = &initshutdown_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_initshutdown.h b/source3/librpc/gen_ndr/ndr_initshutdown.h
new file mode 100644
index 0000000000..9a19432678
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_initshutdown.h
@@ -0,0 +1,28 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/initshutdown.h"
+
+#ifndef _HEADER_NDR_initshutdown
+#define _HEADER_NDR_initshutdown
+
+#define NDR_INITSHUTDOWN_UUID "894de0c0-0d55-11d3-a322-00c04fa321a1"
+#define NDR_INITSHUTDOWN_VERSION 1.0
+#define NDR_INITSHUTDOWN_NAME "initshutdown"
+#define NDR_INITSHUTDOWN_HELPSTRING "Init shutdown service"
+extern const struct ndr_interface_table ndr_table_initshutdown;
+#define NDR_INITSHUTDOWN_INIT (0x00)
+
+#define NDR_INITSHUTDOWN_ABORT (0x01)
+
+#define NDR_INITSHUTDOWN_INITEX (0x02)
+
+#define NDR_INITSHUTDOWN_CALL_COUNT (3)
+void ndr_print_initshutdown_String_sub(struct ndr_print *ndr, const char *name, const struct initshutdown_String_sub *r);
+enum ndr_err_code ndr_push_initshutdown_String(struct ndr_push *ndr, int ndr_flags, const struct initshutdown_String *r);
+enum ndr_err_code ndr_pull_initshutdown_String(struct ndr_pull *ndr, int ndr_flags, struct initshutdown_String *r);
+void ndr_print_initshutdown_String(struct ndr_print *ndr, const char *name, const struct initshutdown_String *r);
+void ndr_print_initshutdown_Init(struct ndr_print *ndr, const char *name, int flags, const struct initshutdown_Init *r);
+void ndr_print_initshutdown_Abort(struct ndr_print *ndr, const char *name, int flags, const struct initshutdown_Abort *r);
+void ndr_print_initshutdown_InitEx(struct ndr_print *ndr, const char *name, int flags, const struct initshutdown_InitEx *r);
+#endif /* _HEADER_NDR_initshutdown */
diff --git a/source3/librpc/gen_ndr/ndr_krb5pac.c b/source3/librpc/gen_ndr/ndr_krb5pac.c
new file mode 100644
index 0000000000..6e06f90a68
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_krb5pac.c
@@ -0,0 +1,892 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_krb5pac.h"
+
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "librpc/gen_ndr/ndr_samr.h"
+static enum ndr_err_code ndr_push_PAC_LOGON_NAME(struct ndr_push *ndr, int ndr_flags, const struct PAC_LOGON_NAME *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->logon_time));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 2 * strlen_m(r->account_name)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->account_name, 2 * strlen_m(r->account_name), sizeof(uint8_t), CH_UTF16));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PAC_LOGON_NAME(struct ndr_pull *ndr, int ndr_flags, struct PAC_LOGON_NAME *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->logon_time));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->account_name, r->size, sizeof(uint8_t), CH_UTF16));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PAC_LOGON_NAME(struct ndr_print *ndr, const char *name, const struct PAC_LOGON_NAME *r)
+{
+ ndr_print_struct(ndr, name, "PAC_LOGON_NAME");
+ ndr->depth++;
+ ndr_print_NTTIME(ndr, "logon_time", r->logon_time);
+ ndr_print_uint16(ndr, "size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?2 * strlen_m(r->account_name):r->size);
+ ndr_print_string(ndr, "account_name", r->account_name);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_PAC_SIGNATURE_DATA(struct ndr_push *ndr, int ndr_flags, const struct PAC_SIGNATURE_DATA *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->type));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->signature));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_PAC_SIGNATURE_DATA(struct ndr_pull *ndr, int ndr_flags, struct PAC_SIGNATURE_DATA *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->type));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->signature));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PAC_SIGNATURE_DATA(struct ndr_print *ndr, const char *name, const struct PAC_SIGNATURE_DATA *r)
+{
+ ndr_print_struct(ndr, name, "PAC_SIGNATURE_DATA");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "type", r->type);
+ ndr_print_DATA_BLOB(ndr, "signature", r->signature);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_PAC_LOGON_INFO(struct ndr_push *ndr, int ndr_flags, const struct PAC_LOGON_INFO *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netr_SamInfo3(ndr, NDR_SCALARS, &r->info3));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->res_group_dom_sid));
+ NDR_CHECK(ndr_push_samr_RidWithAttributeArray(ndr, NDR_SCALARS, &r->res_groups));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_netr_SamInfo3(ndr, NDR_BUFFERS, &r->info3));
+ if (r->res_group_dom_sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->res_group_dom_sid));
+ }
+ NDR_CHECK(ndr_push_samr_RidWithAttributeArray(ndr, NDR_BUFFERS, &r->res_groups));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PAC_LOGON_INFO(struct ndr_pull *ndr, int ndr_flags, struct PAC_LOGON_INFO *r)
+{
+ uint32_t _ptr_res_group_dom_sid;
+ TALLOC_CTX *_mem_save_res_group_dom_sid_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netr_SamInfo3(ndr, NDR_SCALARS, &r->info3));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_res_group_dom_sid));
+ if (_ptr_res_group_dom_sid) {
+ NDR_PULL_ALLOC(ndr, r->res_group_dom_sid);
+ } else {
+ r->res_group_dom_sid = NULL;
+ }
+ NDR_CHECK(ndr_pull_samr_RidWithAttributeArray(ndr, NDR_SCALARS, &r->res_groups));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_netr_SamInfo3(ndr, NDR_BUFFERS, &r->info3));
+ if (r->res_group_dom_sid) {
+ _mem_save_res_group_dom_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->res_group_dom_sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->res_group_dom_sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_res_group_dom_sid_0, 0);
+ }
+ NDR_CHECK(ndr_pull_samr_RidWithAttributeArray(ndr, NDR_BUFFERS, &r->res_groups));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PAC_LOGON_INFO(struct ndr_print *ndr, const char *name, const struct PAC_LOGON_INFO *r)
+{
+ ndr_print_struct(ndr, name, "PAC_LOGON_INFO");
+ ndr->depth++;
+ ndr_print_netr_SamInfo3(ndr, "info3", &r->info3);
+ ndr_print_ptr(ndr, "res_group_dom_sid", r->res_group_dom_sid);
+ ndr->depth++;
+ if (r->res_group_dom_sid) {
+ ndr_print_dom_sid2(ndr, "res_group_dom_sid", r->res_group_dom_sid);
+ }
+ ndr->depth--;
+ ndr_print_samr_RidWithAttributeArray(ndr, "res_groups", &r->res_groups);
+ ndr->depth--;
+}
+
+static size_t ndr_size_PAC_LOGON_INFO(const struct PAC_LOGON_INFO *r, int flags)
+{
+ return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_PAC_LOGON_INFO);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_PAC_LOGON_INFO_CTR(struct ndr_push *ndr, int ndr_flags, const struct PAC_LOGON_INFO_CTR *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0x00081001));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0xCCCCCCCC));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, NDR_ROUND(ndr_size_PAC_LOGON_INFO(r->info, ndr->flags) + 4, 8)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0x00000000));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->info) {
+ NDR_CHECK(ndr_push_PAC_LOGON_INFO(ndr, NDR_SCALARS|NDR_BUFFERS, r->info));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_PAC_LOGON_INFO_CTR(struct ndr_pull *ndr, int ndr_flags, struct PAC_LOGON_INFO_CTR *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_info_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->_ndr_size));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, r->info);
+ } else {
+ r->info = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->info) {
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info, 0);
+ NDR_CHECK(ndr_pull_PAC_LOGON_INFO(ndr, NDR_SCALARS|NDR_BUFFERS, r->info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PAC_LOGON_INFO_CTR(struct ndr_print *ndr, const char *name, const struct PAC_LOGON_INFO_CTR *r)
+{
+ ndr_print_struct(ndr, name, "PAC_LOGON_INFO_CTR");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "unknown1", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0x00081001:r->unknown1);
+ ndr_print_uint32(ndr, "unknown2", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0xCCCCCCCC:r->unknown2);
+ ndr_print_uint32(ndr, "_ndr_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?NDR_ROUND(ndr_size_PAC_LOGON_INFO(r->info, ndr->flags) + 4, 8):r->_ndr_size);
+ ndr_print_uint32(ndr, "unknown3", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0x00000000:r->unknown3);
+ ndr_print_ptr(ndr, "info", r->info);
+ ndr->depth++;
+ if (r->info) {
+ ndr_print_PAC_LOGON_INFO(ndr, "info", r->info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_PAC_TYPE(struct ndr_push *ndr, int ndr_flags, enum PAC_TYPE r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_PAC_TYPE(struct ndr_pull *ndr, int ndr_flags, enum PAC_TYPE *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PAC_TYPE(struct ndr_print *ndr, const char *name, enum PAC_TYPE r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case PAC_TYPE_LOGON_INFO: val = "PAC_TYPE_LOGON_INFO"; break;
+ case PAC_TYPE_SRV_CHECKSUM: val = "PAC_TYPE_SRV_CHECKSUM"; break;
+ case PAC_TYPE_KDC_CHECKSUM: val = "PAC_TYPE_KDC_CHECKSUM"; break;
+ case PAC_TYPE_LOGON_NAME: val = "PAC_TYPE_LOGON_NAME"; break;
+ case PAC_TYPE_CONSTRAINED_DELEGATION: val = "PAC_TYPE_CONSTRAINED_DELEGATION"; break;
+ case PAC_TYPE_UNKNOWN_12: val = "PAC_TYPE_UNKNOWN_12"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_DATA_BLOB_REM(struct ndr_push *ndr, int ndr_flags, const struct DATA_BLOB_REM *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->remaining));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_DATA_BLOB_REM(struct ndr_pull *ndr, int ndr_flags, struct DATA_BLOB_REM *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->remaining));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_DATA_BLOB_REM(struct ndr_print *ndr, const char *name, const struct DATA_BLOB_REM *r)
+{
+ ndr_print_struct(ndr, name, "DATA_BLOB_REM");
+ ndr->depth++;
+ ndr_print_DATA_BLOB(ndr, "remaining", r->remaining);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_PAC_INFO(struct ndr_push *ndr, int ndr_flags, const union PAC_INFO *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case PAC_TYPE_LOGON_INFO: {
+ NDR_CHECK(ndr_push_PAC_LOGON_INFO_CTR(ndr, NDR_SCALARS, &r->logon_info));
+ break; }
+
+ case PAC_TYPE_SRV_CHECKSUM: {
+ NDR_CHECK(ndr_push_PAC_SIGNATURE_DATA(ndr, NDR_SCALARS, &r->srv_cksum));
+ break; }
+
+ case PAC_TYPE_KDC_CHECKSUM: {
+ NDR_CHECK(ndr_push_PAC_SIGNATURE_DATA(ndr, NDR_SCALARS, &r->kdc_cksum));
+ break; }
+
+ case PAC_TYPE_LOGON_NAME: {
+ NDR_CHECK(ndr_push_PAC_LOGON_NAME(ndr, NDR_SCALARS, &r->logon_name));
+ break; }
+
+ default: {
+ {
+ struct ndr_push *_ndr_unknown;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_unknown, 0, -1));
+ NDR_CHECK(ndr_push_DATA_BLOB_REM(_ndr_unknown, NDR_SCALARS, &r->unknown));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_unknown, 0, -1));
+ }
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case PAC_TYPE_LOGON_INFO:
+ NDR_CHECK(ndr_push_PAC_LOGON_INFO_CTR(ndr, NDR_BUFFERS, &r->logon_info));
+ break;
+
+ case PAC_TYPE_SRV_CHECKSUM:
+ break;
+
+ case PAC_TYPE_KDC_CHECKSUM:
+ break;
+
+ case PAC_TYPE_LOGON_NAME:
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_PAC_INFO(struct ndr_pull *ndr, int ndr_flags, union PAC_INFO *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case PAC_TYPE_LOGON_INFO: {
+ NDR_CHECK(ndr_pull_PAC_LOGON_INFO_CTR(ndr, NDR_SCALARS, &r->logon_info));
+ break; }
+
+ case PAC_TYPE_SRV_CHECKSUM: {
+ NDR_CHECK(ndr_pull_PAC_SIGNATURE_DATA(ndr, NDR_SCALARS, &r->srv_cksum));
+ break; }
+
+ case PAC_TYPE_KDC_CHECKSUM: {
+ NDR_CHECK(ndr_pull_PAC_SIGNATURE_DATA(ndr, NDR_SCALARS, &r->kdc_cksum));
+ break; }
+
+ case PAC_TYPE_LOGON_NAME: {
+ NDR_CHECK(ndr_pull_PAC_LOGON_NAME(ndr, NDR_SCALARS, &r->logon_name));
+ break; }
+
+ default: {
+ {
+ struct ndr_pull *_ndr_unknown;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_unknown, 0, -1));
+ NDR_CHECK(ndr_pull_DATA_BLOB_REM(_ndr_unknown, NDR_SCALARS, &r->unknown));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_unknown, 0, -1));
+ }
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case PAC_TYPE_LOGON_INFO:
+ NDR_CHECK(ndr_pull_PAC_LOGON_INFO_CTR(ndr, NDR_BUFFERS, &r->logon_info));
+ break;
+
+ case PAC_TYPE_SRV_CHECKSUM:
+ break;
+
+ case PAC_TYPE_KDC_CHECKSUM:
+ break;
+
+ case PAC_TYPE_LOGON_NAME:
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PAC_INFO(struct ndr_print *ndr, const char *name, const union PAC_INFO *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "PAC_INFO");
+ switch (level) {
+ case PAC_TYPE_LOGON_INFO:
+ ndr_print_PAC_LOGON_INFO_CTR(ndr, "logon_info", &r->logon_info);
+ break;
+
+ case PAC_TYPE_SRV_CHECKSUM:
+ ndr_print_PAC_SIGNATURE_DATA(ndr, "srv_cksum", &r->srv_cksum);
+ break;
+
+ case PAC_TYPE_KDC_CHECKSUM:
+ ndr_print_PAC_SIGNATURE_DATA(ndr, "kdc_cksum", &r->kdc_cksum);
+ break;
+
+ case PAC_TYPE_LOGON_NAME:
+ ndr_print_PAC_LOGON_NAME(ndr, "logon_name", &r->logon_name);
+ break;
+
+ default:
+ ndr_print_DATA_BLOB_REM(ndr, "unknown", &r->unknown);
+ break;
+
+ }
+}
+
+_PUBLIC_ size_t ndr_size_PAC_INFO(const union PAC_INFO *r, uint32_t level, int flags)
+{
+ return ndr_size_union(r, flags, level, (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_PAC_DATA(struct ndr_push *ndr, int ndr_flags, const struct PAC_DATA *r)
+{
+ uint32_t cntr_buffers_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_buffers));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version));
+ for (cntr_buffers_0 = 0; cntr_buffers_0 < r->num_buffers; cntr_buffers_0++) {
+ NDR_CHECK(ndr_push_PAC_BUFFER(ndr, NDR_SCALARS, &r->buffers[cntr_buffers_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ for (cntr_buffers_0 = 0; cntr_buffers_0 < r->num_buffers; cntr_buffers_0++) {
+ NDR_CHECK(ndr_push_PAC_BUFFER(ndr, NDR_BUFFERS, &r->buffers[cntr_buffers_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_PAC_DATA(struct ndr_pull *ndr, int ndr_flags, struct PAC_DATA *r)
+{
+ uint32_t cntr_buffers_0;
+ TALLOC_CTX *_mem_save_buffers_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_buffers));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_PULL_ALLOC_N(ndr, r->buffers, r->num_buffers);
+ _mem_save_buffers_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->buffers, 0);
+ for (cntr_buffers_0 = 0; cntr_buffers_0 < r->num_buffers; cntr_buffers_0++) {
+ NDR_CHECK(ndr_pull_PAC_BUFFER(ndr, NDR_SCALARS, &r->buffers[cntr_buffers_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_buffers_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_buffers_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->buffers, 0);
+ for (cntr_buffers_0 = 0; cntr_buffers_0 < r->num_buffers; cntr_buffers_0++) {
+ NDR_CHECK(ndr_pull_PAC_BUFFER(ndr, NDR_BUFFERS, &r->buffers[cntr_buffers_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_buffers_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PAC_DATA(struct ndr_print *ndr, const char *name, const struct PAC_DATA *r)
+{
+ uint32_t cntr_buffers_0;
+ ndr_print_struct(ndr, name, "PAC_DATA");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_buffers", r->num_buffers);
+ ndr_print_uint32(ndr, "version", r->version);
+ ndr->print(ndr, "%s: ARRAY(%d)", "buffers", (int)r->num_buffers);
+ ndr->depth++;
+ for (cntr_buffers_0=0;cntr_buffers_0<r->num_buffers;cntr_buffers_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_buffers_0) != -1) {
+ ndr_print_PAC_BUFFER(ndr, "buffers", &r->buffers[cntr_buffers_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_PAC_BUFFER_RAW(struct ndr_push *ndr, int ndr_flags, const struct PAC_BUFFER_RAW *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_PAC_TYPE(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ndr_size));
+ {
+ uint32_t _flags_save_DATA_BLOB_REM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->info));
+ ndr->flags = _flags_save_DATA_BLOB_REM;
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ uint32_t _flags_save_DATA_BLOB_REM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8);
+ if (r->info) {
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, r->info));
+ {
+ struct ndr_push *_ndr_info;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info, 0, NDR_ROUND(r->ndr_size, 8)));
+ NDR_CHECK(ndr_push_DATA_BLOB_REM(_ndr_info, NDR_SCALARS, r->info));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_info, 0, NDR_ROUND(r->ndr_size, 8)));
+ }
+ }
+ ndr->flags = _flags_save_DATA_BLOB_REM;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_PAC_BUFFER_RAW(struct ndr_pull *ndr, int ndr_flags, struct PAC_BUFFER_RAW *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_info_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_PAC_TYPE(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->ndr_size));
+ {
+ uint32_t _flags_save_DATA_BLOB_REM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, r->info);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->info, _ptr_info));
+ } else {
+ r->info = NULL;
+ }
+ ndr->flags = _flags_save_DATA_BLOB_REM;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->_pad));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ uint32_t _flags_save_DATA_BLOB_REM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8);
+ if (r->info) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->info));
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info, 0);
+ {
+ struct ndr_pull *_ndr_info;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info, 0, NDR_ROUND(r->ndr_size, 8)));
+ NDR_CHECK(ndr_pull_DATA_BLOB_REM(_ndr_info, NDR_SCALARS, r->info));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info, 0, NDR_ROUND(r->ndr_size, 8)));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0);
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_DATA_BLOB_REM;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PAC_BUFFER_RAW(struct ndr_print *ndr, const char *name, const struct PAC_BUFFER_RAW *r)
+{
+ ndr_print_struct(ndr, name, "PAC_BUFFER_RAW");
+ ndr->depth++;
+ ndr_print_PAC_TYPE(ndr, "type", r->type);
+ ndr_print_uint32(ndr, "ndr_size", r->ndr_size);
+ ndr_print_ptr(ndr, "info", r->info);
+ ndr->depth++;
+ if (r->info) {
+ ndr_print_DATA_BLOB_REM(ndr, "info", r->info);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "_pad", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->_pad);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_PAC_DATA_RAW(struct ndr_push *ndr, int ndr_flags, const struct PAC_DATA_RAW *r)
+{
+ uint32_t cntr_buffers_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_buffers));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version));
+ for (cntr_buffers_0 = 0; cntr_buffers_0 < r->num_buffers; cntr_buffers_0++) {
+ NDR_CHECK(ndr_push_PAC_BUFFER_RAW(ndr, NDR_SCALARS, &r->buffers[cntr_buffers_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ for (cntr_buffers_0 = 0; cntr_buffers_0 < r->num_buffers; cntr_buffers_0++) {
+ NDR_CHECK(ndr_push_PAC_BUFFER_RAW(ndr, NDR_BUFFERS, &r->buffers[cntr_buffers_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_PAC_DATA_RAW(struct ndr_pull *ndr, int ndr_flags, struct PAC_DATA_RAW *r)
+{
+ uint32_t cntr_buffers_0;
+ TALLOC_CTX *_mem_save_buffers_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_buffers));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_PULL_ALLOC_N(ndr, r->buffers, r->num_buffers);
+ _mem_save_buffers_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->buffers, 0);
+ for (cntr_buffers_0 = 0; cntr_buffers_0 < r->num_buffers; cntr_buffers_0++) {
+ NDR_CHECK(ndr_pull_PAC_BUFFER_RAW(ndr, NDR_SCALARS, &r->buffers[cntr_buffers_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_buffers_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_buffers_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->buffers, 0);
+ for (cntr_buffers_0 = 0; cntr_buffers_0 < r->num_buffers; cntr_buffers_0++) {
+ NDR_CHECK(ndr_pull_PAC_BUFFER_RAW(ndr, NDR_BUFFERS, &r->buffers[cntr_buffers_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_buffers_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PAC_DATA_RAW(struct ndr_print *ndr, const char *name, const struct PAC_DATA_RAW *r)
+{
+ uint32_t cntr_buffers_0;
+ ndr_print_struct(ndr, name, "PAC_DATA_RAW");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_buffers", r->num_buffers);
+ ndr_print_uint32(ndr, "version", r->version);
+ ndr->print(ndr, "%s: ARRAY(%d)", "buffers", (int)r->num_buffers);
+ ndr->depth++;
+ for (cntr_buffers_0=0;cntr_buffers_0<r->num_buffers;cntr_buffers_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_buffers_0) != -1) {
+ ndr_print_PAC_BUFFER_RAW(ndr, "buffers", &r->buffers[cntr_buffers_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netsamlogoncache_entry(struct ndr_push *ndr, int ndr_flags, const struct netsamlogoncache_entry *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_time_t(ndr, NDR_SCALARS, r->timestamp));
+ NDR_CHECK(ndr_push_netr_SamInfo3(ndr, NDR_SCALARS, &r->info3));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_netr_SamInfo3(ndr, NDR_BUFFERS, &r->info3));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netsamlogoncache_entry(struct ndr_pull *ndr, int ndr_flags, struct netsamlogoncache_entry *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_time_t(ndr, NDR_SCALARS, &r->timestamp));
+ NDR_CHECK(ndr_pull_netr_SamInfo3(ndr, NDR_SCALARS, &r->info3));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_netr_SamInfo3(ndr, NDR_BUFFERS, &r->info3));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netsamlogoncache_entry(struct ndr_print *ndr, const char *name, const struct netsamlogoncache_entry *r)
+{
+ ndr_print_struct(ndr, name, "netsamlogoncache_entry");
+ ndr->depth++;
+ ndr_print_time_t(ndr, "timestamp", r->timestamp);
+ ndr_print_netr_SamInfo3(ndr, "info3", &r->info3);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_decode_pac(struct ndr_push *ndr, int flags, const struct decode_pac *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_PAC_DATA(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.pac));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_decode_pac(struct ndr_pull *ndr, int flags, struct decode_pac *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_PAC_DATA(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.pac));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_decode_pac(struct ndr_print *ndr, const char *name, int flags, const struct decode_pac *r)
+{
+ ndr_print_struct(ndr, name, "decode_pac");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "decode_pac");
+ ndr->depth++;
+ ndr_print_PAC_DATA(ndr, "pac", &r->in.pac);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "decode_pac");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_decode_pac_raw(struct ndr_push *ndr, int flags, const struct decode_pac_raw *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_PAC_DATA_RAW(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.pac));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_decode_pac_raw(struct ndr_pull *ndr, int flags, struct decode_pac_raw *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_PAC_DATA_RAW(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.pac));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_decode_pac_raw(struct ndr_print *ndr, const char *name, int flags, const struct decode_pac_raw *r)
+{
+ ndr_print_struct(ndr, name, "decode_pac_raw");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "decode_pac_raw");
+ ndr->depth++;
+ ndr_print_PAC_DATA_RAW(ndr, "pac", &r->in.pac);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "decode_pac_raw");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_decode_login_info(struct ndr_push *ndr, int flags, const struct decode_login_info *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_PAC_LOGON_INFO(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.logon_info));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_decode_login_info(struct ndr_pull *ndr, int flags, struct decode_login_info *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_PAC_LOGON_INFO(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.logon_info));
+ }
+ if (flags & NDR_OUT) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_decode_login_info(struct ndr_print *ndr, const char *name, int flags, const struct decode_login_info *r)
+{
+ ndr_print_struct(ndr, name, "decode_login_info");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "decode_login_info");
+ ndr->depth++;
+ ndr_print_PAC_LOGON_INFO(ndr, "logon_info", &r->in.logon_info);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "decode_login_info");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call krb5pac_calls[] = {
+ {
+ "decode_pac",
+ sizeof(struct decode_pac),
+ (ndr_push_flags_fn_t) ndr_push_decode_pac,
+ (ndr_pull_flags_fn_t) ndr_pull_decode_pac,
+ (ndr_print_function_t) ndr_print_decode_pac,
+ false,
+ },
+ {
+ "decode_pac_raw",
+ sizeof(struct decode_pac_raw),
+ (ndr_push_flags_fn_t) ndr_push_decode_pac_raw,
+ (ndr_pull_flags_fn_t) ndr_pull_decode_pac_raw,
+ (ndr_print_function_t) ndr_print_decode_pac_raw,
+ false,
+ },
+ {
+ "decode_login_info",
+ sizeof(struct decode_login_info),
+ (ndr_push_flags_fn_t) ndr_push_decode_login_info,
+ (ndr_pull_flags_fn_t) ndr_pull_decode_login_info,
+ (ndr_print_function_t) ndr_print_decode_login_info,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const krb5pac_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\krb5pac]",
+};
+
+static const struct ndr_interface_string_array krb5pac_endpoints = {
+ .count = 1,
+ .names = krb5pac_endpoint_strings
+};
+
+static const char * const krb5pac_authservice_strings[] = {
+ "host",
+};
+
+static const struct ndr_interface_string_array krb5pac_authservices = {
+ .count = 1,
+ .names = krb5pac_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_krb5pac = {
+ .name = "krb5pac",
+ .syntax_id = {
+ {0x12345778,0x1234,0xabcd,{0x00,0x00},{0x00,0x00,0x00,0x00}},
+ NDR_KRB5PAC_VERSION
+ },
+ .helpstring = NDR_KRB5PAC_HELPSTRING,
+ .num_calls = 3,
+ .calls = krb5pac_calls,
+ .endpoints = &krb5pac_endpoints,
+ .authservices = &krb5pac_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_krb5pac.h b/source3/librpc/gen_ndr/ndr_krb5pac.h
new file mode 100644
index 0000000000..7f03106879
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_krb5pac.h
@@ -0,0 +1,55 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/krb5pac.h"
+
+#ifndef _HEADER_NDR_krb5pac
+#define _HEADER_NDR_krb5pac
+
+#define NDR_KRB5PAC_UUID "12345778-1234-abcd-0000-00000000"
+#define NDR_KRB5PAC_VERSION 0.0
+#define NDR_KRB5PAC_NAME "krb5pac"
+#define NDR_KRB5PAC_HELPSTRING "Active Directory KRB5 PAC"
+extern const struct ndr_interface_table ndr_table_krb5pac;
+#define NDR_DECODE_PAC (0x00)
+
+#define NDR_DECODE_PAC_RAW (0x01)
+
+#define NDR_DECODE_LOGIN_INFO (0x02)
+
+#define NDR_KRB5PAC_CALL_COUNT (3)
+void ndr_print_PAC_LOGON_NAME(struct ndr_print *ndr, const char *name, const struct PAC_LOGON_NAME *r);
+enum ndr_err_code ndr_push_PAC_SIGNATURE_DATA(struct ndr_push *ndr, int ndr_flags, const struct PAC_SIGNATURE_DATA *r);
+enum ndr_err_code ndr_pull_PAC_SIGNATURE_DATA(struct ndr_pull *ndr, int ndr_flags, struct PAC_SIGNATURE_DATA *r);
+void ndr_print_PAC_SIGNATURE_DATA(struct ndr_print *ndr, const char *name, const struct PAC_SIGNATURE_DATA *r);
+void ndr_print_PAC_LOGON_INFO(struct ndr_print *ndr, const char *name, const struct PAC_LOGON_INFO *r);
+enum ndr_err_code ndr_push_PAC_LOGON_INFO_CTR(struct ndr_push *ndr, int ndr_flags, const struct PAC_LOGON_INFO_CTR *r);
+enum ndr_err_code ndr_pull_PAC_LOGON_INFO_CTR(struct ndr_pull *ndr, int ndr_flags, struct PAC_LOGON_INFO_CTR *r);
+void ndr_print_PAC_LOGON_INFO_CTR(struct ndr_print *ndr, const char *name, const struct PAC_LOGON_INFO_CTR *r);
+enum ndr_err_code ndr_push_PAC_TYPE(struct ndr_push *ndr, int ndr_flags, enum PAC_TYPE r);
+enum ndr_err_code ndr_pull_PAC_TYPE(struct ndr_pull *ndr, int ndr_flags, enum PAC_TYPE *r);
+void ndr_print_PAC_TYPE(struct ndr_print *ndr, const char *name, enum PAC_TYPE r);
+void ndr_print_DATA_BLOB_REM(struct ndr_print *ndr, const char *name, const struct DATA_BLOB_REM *r);
+enum ndr_err_code ndr_push_PAC_INFO(struct ndr_push *ndr, int ndr_flags, const union PAC_INFO *r);
+enum ndr_err_code ndr_pull_PAC_INFO(struct ndr_pull *ndr, int ndr_flags, union PAC_INFO *r);
+void ndr_print_PAC_INFO(struct ndr_print *ndr, const char *name, const union PAC_INFO *r);
+size_t ndr_size_PAC_INFO(const union PAC_INFO *r, uint32_t level, int flags);
+enum ndr_err_code ndr_push_PAC_BUFFER(struct ndr_push *ndr, int ndr_flags, const struct PAC_BUFFER *r);
+enum ndr_err_code ndr_pull_PAC_BUFFER(struct ndr_pull *ndr, int ndr_flags, struct PAC_BUFFER *r);
+void ndr_print_PAC_BUFFER(struct ndr_print *ndr, const char *name, const struct PAC_BUFFER *r);
+enum ndr_err_code ndr_push_PAC_DATA(struct ndr_push *ndr, int ndr_flags, const struct PAC_DATA *r);
+enum ndr_err_code ndr_pull_PAC_DATA(struct ndr_pull *ndr, int ndr_flags, struct PAC_DATA *r);
+void ndr_print_PAC_DATA(struct ndr_print *ndr, const char *name, const struct PAC_DATA *r);
+enum ndr_err_code ndr_push_PAC_BUFFER_RAW(struct ndr_push *ndr, int ndr_flags, const struct PAC_BUFFER_RAW *r);
+enum ndr_err_code ndr_pull_PAC_BUFFER_RAW(struct ndr_pull *ndr, int ndr_flags, struct PAC_BUFFER_RAW *r);
+void ndr_print_PAC_BUFFER_RAW(struct ndr_print *ndr, const char *name, const struct PAC_BUFFER_RAW *r);
+enum ndr_err_code ndr_push_PAC_DATA_RAW(struct ndr_push *ndr, int ndr_flags, const struct PAC_DATA_RAW *r);
+enum ndr_err_code ndr_pull_PAC_DATA_RAW(struct ndr_pull *ndr, int ndr_flags, struct PAC_DATA_RAW *r);
+void ndr_print_PAC_DATA_RAW(struct ndr_print *ndr, const char *name, const struct PAC_DATA_RAW *r);
+enum ndr_err_code ndr_push_netsamlogoncache_entry(struct ndr_push *ndr, int ndr_flags, const struct netsamlogoncache_entry *r);
+enum ndr_err_code ndr_pull_netsamlogoncache_entry(struct ndr_pull *ndr, int ndr_flags, struct netsamlogoncache_entry *r);
+void ndr_print_netsamlogoncache_entry(struct ndr_print *ndr, const char *name, const struct netsamlogoncache_entry *r);
+void ndr_print_decode_pac(struct ndr_print *ndr, const char *name, int flags, const struct decode_pac *r);
+void ndr_print_decode_pac_raw(struct ndr_print *ndr, const char *name, int flags, const struct decode_pac_raw *r);
+void ndr_print_decode_login_info(struct ndr_print *ndr, const char *name, int flags, const struct decode_login_info *r);
+#endif /* _HEADER_NDR_krb5pac */
diff --git a/source3/librpc/gen_ndr/ndr_libnet_join.c b/source3/librpc/gen_ndr/ndr_libnet_join.c
new file mode 100644
index 0000000000..79fcd16a90
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_libnet_join.c
@@ -0,0 +1,120 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_libnet_join.h"
+
+#include "librpc/gen_ndr/ndr_wkssvc.h"
+#include "librpc/gen_ndr/ndr_security.h"
+_PUBLIC_ void ndr_print_libnet_JoinCtx(struct ndr_print *ndr, const char *name, int flags, const struct libnet_JoinCtx *r)
+{
+ ndr_print_struct(ndr, name, "libnet_JoinCtx");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "libnet_JoinCtx");
+ ndr->depth++;
+ ndr_print_string(ndr, "dc_name", r->in.dc_name);
+ ndr_print_string(ndr, "machine_name", r->in.machine_name);
+ ndr_print_ptr(ndr, "domain_name", r->in.domain_name);
+ ndr->depth++;
+ ndr_print_string(ndr, "domain_name", r->in.domain_name);
+ ndr->depth--;
+ ndr_print_string(ndr, "account_ou", r->in.account_ou);
+ ndr_print_string(ndr, "admin_account", r->in.admin_account);
+#ifdef DEBUG_PASSWORD
+ ndr_print_string(ndr, "admin_password", r->in.admin_password);
+ ndr_print_string(ndr, "machine_password", r->in.machine_password);
+#else
+ ndr_print_ptr(ndr, "admin_password", r->in.admin_password);
+ ndr_print_ptr(ndr, "machine_password", r->in.machine_password);
+#endif
+ ndr_print_wkssvc_joinflags(ndr, "join_flags", r->in.join_flags);
+ ndr_print_string(ndr, "os_version", r->in.os_version);
+ ndr_print_string(ndr, "os_name", r->in.os_name);
+ ndr_print_uint8(ndr, "create_upn", r->in.create_upn);
+ ndr_print_string(ndr, "upn", r->in.upn);
+ ndr_print_uint8(ndr, "modify_config", r->in.modify_config);
+ ndr_print_ptr(ndr, "ads", r->in.ads);
+ ndr->depth++;
+ ndr_print_ads_struct(ndr, "ads", r->in.ads);
+ ndr->depth--;
+ ndr_print_uint8(ndr, "debug", r->in.debug);
+ ndr_print_uint8(ndr, "use_kerberos", r->in.use_kerberos);
+ ndr_print_netr_SchannelType(ndr, "secure_channel_type", r->in.secure_channel_type);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "libnet_JoinCtx");
+ ndr->depth++;
+ ndr_print_string(ndr, "account_name", r->out.account_name);
+ ndr_print_string(ndr, "netbios_domain_name", r->out.netbios_domain_name);
+ ndr_print_string(ndr, "dns_domain_name", r->out.dns_domain_name);
+ ndr_print_string(ndr, "forest_name", r->out.forest_name);
+ ndr_print_string(ndr, "dn", r->out.dn);
+ ndr_print_ptr(ndr, "domain_sid", r->out.domain_sid);
+ ndr->depth++;
+ ndr_print_dom_sid(ndr, "domain_sid", r->out.domain_sid);
+ ndr->depth--;
+ ndr_print_uint8(ndr, "modified_config", r->out.modified_config);
+ ndr_print_string(ndr, "error_string", r->out.error_string);
+ ndr_print_uint8(ndr, "domain_is_ad", r->out.domain_is_ad);
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_libnet_UnjoinCtx(struct ndr_print *ndr, const char *name, int flags, const struct libnet_UnjoinCtx *r)
+{
+ ndr_print_struct(ndr, name, "libnet_UnjoinCtx");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "libnet_UnjoinCtx");
+ ndr->depth++;
+ ndr_print_string(ndr, "dc_name", r->in.dc_name);
+ ndr_print_string(ndr, "machine_name", r->in.machine_name);
+ ndr_print_string(ndr, "domain_name", r->in.domain_name);
+ ndr_print_string(ndr, "account_ou", r->in.account_ou);
+ ndr_print_string(ndr, "admin_account", r->in.admin_account);
+#ifdef DEBUG_PASSWORD
+ ndr_print_string(ndr, "admin_password", r->in.admin_password);
+ ndr_print_string(ndr, "machine_password", r->in.machine_password);
+#else
+ ndr_print_ptr(ndr, "admin_password", r->in.admin_password);
+ ndr_print_ptr(ndr, "machine_password", r->in.machine_password);
+#endif
+ ndr_print_wkssvc_joinflags(ndr, "unjoin_flags", r->in.unjoin_flags);
+ ndr_print_uint8(ndr, "modify_config", r->in.modify_config);
+ ndr_print_ptr(ndr, "domain_sid", r->in.domain_sid);
+ ndr->depth++;
+ ndr_print_dom_sid(ndr, "domain_sid", r->in.domain_sid);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ads", r->in.ads);
+ ndr->depth++;
+ ndr_print_ads_struct(ndr, "ads", r->in.ads);
+ ndr->depth--;
+ ndr_print_uint8(ndr, "debug", r->in.debug);
+ ndr_print_uint8(ndr, "use_kerberos", r->in.use_kerberos);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "libnet_UnjoinCtx");
+ ndr->depth++;
+ ndr_print_string(ndr, "netbios_domain_name", r->out.netbios_domain_name);
+ ndr_print_string(ndr, "dns_domain_name", r->out.dns_domain_name);
+ ndr_print_string(ndr, "forest_name", r->out.forest_name);
+ ndr_print_uint8(ndr, "modified_config", r->out.modified_config);
+ ndr_print_string(ndr, "error_string", r->out.error_string);
+ ndr_print_uint8(ndr, "disabled_machine_account", r->out.disabled_machine_account);
+ ndr_print_uint8(ndr, "deleted_machine_account", r->out.deleted_machine_account);
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
diff --git a/source3/librpc/gen_ndr/ndr_libnet_join.h b/source3/librpc/gen_ndr/ndr_libnet_join.h
new file mode 100644
index 0000000000..14c8a863aa
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_libnet_join.h
@@ -0,0 +1,16 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/libnet_join.h"
+
+#ifndef _HEADER_NDR_libnetjoin
+#define _HEADER_NDR_libnetjoin
+
+#define NDR_LIBNETJOIN_CALL_COUNT (0)
+enum ndr_err_code ndr_push_libnet_JoinCtx(struct ndr_push *ndr, int flags, const struct libnet_JoinCtx *r);
+enum ndr_err_code ndr_pull_libnet_JoinCtx(struct ndr_pull *ndr, int flags, struct libnet_JoinCtx *r);
+void ndr_print_libnet_JoinCtx(struct ndr_print *ndr, const char *name, int flags, const struct libnet_JoinCtx *r);
+enum ndr_err_code ndr_push_libnet_UnjoinCtx(struct ndr_push *ndr, int flags, const struct libnet_UnjoinCtx *r);
+enum ndr_err_code ndr_pull_libnet_UnjoinCtx(struct ndr_pull *ndr, int flags, struct libnet_UnjoinCtx *r);
+void ndr_print_libnet_UnjoinCtx(struct ndr_print *ndr, const char *name, int flags, const struct libnet_UnjoinCtx *r);
+#endif /* _HEADER_NDR_libnetjoin */
diff --git a/source3/librpc/gen_ndr/ndr_libnetapi.c b/source3/librpc/gen_ndr/ndr_libnetapi.c
new file mode 100644
index 0000000000..a5266827b6
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_libnetapi.c
@@ -0,0 +1,3977 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_libnetapi.h"
+
+_PUBLIC_ enum ndr_err_code ndr_push_NET_API_STATUS(struct ndr_push *ndr, int ndr_flags, enum NET_API_STATUS r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_NET_API_STATUS(struct ndr_pull *ndr, int ndr_flags, enum NET_API_STATUS *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_NET_API_STATUS(struct ndr_print *ndr, const char *name, enum NET_API_STATUS r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case NERR_Success: val = "NERR_Success"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_domsid(struct ndr_push *ndr, int ndr_flags, const struct domsid *r)
+{
+ uint32_t cntr_sub_auths_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->sid_rev_num));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->num_auths));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6));
+ for (cntr_sub_auths_0 = 0; cntr_sub_auths_0 < MAXSUBAUTHS; cntr_sub_auths_0++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sub_auths[cntr_sub_auths_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_domsid(struct ndr_pull *ndr, int ndr_flags, struct domsid *r)
+{
+ uint32_t cntr_sub_auths_0;
+ TALLOC_CTX *_mem_save_sub_auths_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->sid_rev_num));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->num_auths));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6));
+ NDR_PULL_ALLOC_N(ndr, r->sub_auths, MAXSUBAUTHS);
+ _mem_save_sub_auths_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sub_auths, 0);
+ for (cntr_sub_auths_0 = 0; cntr_sub_auths_0 < MAXSUBAUTHS; cntr_sub_auths_0++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sub_auths[cntr_sub_auths_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sub_auths_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_domsid(struct ndr_print *ndr, const char *name, const struct domsid *r)
+{
+ uint32_t cntr_sub_auths_0;
+ ndr_print_struct(ndr, name, "domsid");
+ ndr->depth++;
+ ndr_print_uint8(ndr, "sid_rev_num", r->sid_rev_num);
+ ndr_print_uint8(ndr, "num_auths", r->num_auths);
+ ndr_print_array_uint8(ndr, "id_auth", r->id_auth, 6);
+ ndr->print(ndr, "%s: ARRAY(%d)", "sub_auths", (int)MAXSUBAUTHS);
+ ndr->depth++;
+ for (cntr_sub_auths_0=0;cntr_sub_auths_0<MAXSUBAUTHS;cntr_sub_auths_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_sub_auths_0) != -1) {
+ ndr_print_uint32(ndr, "sub_auths", r->sub_auths[cntr_sub_auths_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_NetJoinFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_NetJoinFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_NetJoinFlags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETSETUP_JOIN_DOMAIN", NETSETUP_JOIN_DOMAIN, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETSETUP_ACCT_CREATE", NETSETUP_ACCT_CREATE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETSETUP_ACCT_DELETE", NETSETUP_ACCT_DELETE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETSETUP_WIN9X_UPGRADE", NETSETUP_WIN9X_UPGRADE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETSETUP_DOMAIN_JOIN_IF_JOINED", NETSETUP_DOMAIN_JOIN_IF_JOINED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETSETUP_JOIN_UNSECURE", NETSETUP_JOIN_UNSECURE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETSETUP_MACHINE_PWD_PASSED", NETSETUP_MACHINE_PWD_PASSED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETSETUP_DEFER_SPN_SET", NETSETUP_DEFER_SPN_SET, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETSETUP_JOIN_DC_ACCOUNT", NETSETUP_JOIN_DC_ACCOUNT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETSETUP_JOIN_WITH_NEW_NAME", NETSETUP_JOIN_WITH_NEW_NAME, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETSETUP_INSTALL_INVOCATION", NETSETUP_INSTALL_INVOCATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETSETUP_IGNORE_UNSUPPORTED_FLAGS", NETSETUP_IGNORE_UNSUPPORTED_FLAGS, r);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_SERVER_INFO_100(struct ndr_push *ndr, int ndr_flags, const struct SERVER_INFO_100 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sv100_platform_id));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->sv100_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_SERVER_INFO_100(struct ndr_pull *ndr, int ndr_flags, struct SERVER_INFO_100 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sv100_platform_id));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->sv100_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_SERVER_INFO_100(struct ndr_print *ndr, const char *name, const struct SERVER_INFO_100 *r)
+{
+ ndr_print_struct(ndr, name, "SERVER_INFO_100");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "sv100_platform_id", r->sv100_platform_id);
+ ndr_print_string(ndr, "sv100_name", r->sv100_name);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_SERVER_INFO_101(struct ndr_push *ndr, int ndr_flags, const struct SERVER_INFO_101 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sv101_platform_id));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->sv101_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sv101_version_major));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sv101_version_minor));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sv101_type));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->sv101_comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_SERVER_INFO_101(struct ndr_pull *ndr, int ndr_flags, struct SERVER_INFO_101 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sv101_platform_id));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->sv101_name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sv101_version_major));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sv101_version_minor));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sv101_type));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->sv101_comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_SERVER_INFO_101(struct ndr_print *ndr, const char *name, const struct SERVER_INFO_101 *r)
+{
+ ndr_print_struct(ndr, name, "SERVER_INFO_101");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "sv101_platform_id", r->sv101_platform_id);
+ ndr_print_string(ndr, "sv101_name", r->sv101_name);
+ ndr_print_uint32(ndr, "sv101_version_major", r->sv101_version_major);
+ ndr_print_uint32(ndr, "sv101_version_minor", r->sv101_version_minor);
+ ndr_print_uint32(ndr, "sv101_type", r->sv101_type);
+ ndr_print_string(ndr, "sv101_comment", r->sv101_comment);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_SERVER_INFO_102(struct ndr_push *ndr, int ndr_flags, const struct SERVER_INFO_102 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sv102_platform_id));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->sv102_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sv102_version_major));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sv102_version_minor));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sv102_type));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->sv102_comment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sv102_users));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sv102_disc));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->sv102_hidden));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sv102_announce));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sv102_anndelta));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sv102_licenses));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->sv102_userpath));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_SERVER_INFO_102(struct ndr_pull *ndr, int ndr_flags, struct SERVER_INFO_102 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sv102_platform_id));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->sv102_name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sv102_version_major));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sv102_version_minor));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sv102_type));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->sv102_comment));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sv102_users));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sv102_disc));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->sv102_hidden));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sv102_announce));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sv102_anndelta));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sv102_licenses));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->sv102_userpath));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_SERVER_INFO_102(struct ndr_print *ndr, const char *name, const struct SERVER_INFO_102 *r)
+{
+ ndr_print_struct(ndr, name, "SERVER_INFO_102");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "sv102_platform_id", r->sv102_platform_id);
+ ndr_print_string(ndr, "sv102_name", r->sv102_name);
+ ndr_print_uint32(ndr, "sv102_version_major", r->sv102_version_major);
+ ndr_print_uint32(ndr, "sv102_version_minor", r->sv102_version_minor);
+ ndr_print_uint32(ndr, "sv102_type", r->sv102_type);
+ ndr_print_string(ndr, "sv102_comment", r->sv102_comment);
+ ndr_print_uint32(ndr, "sv102_users", r->sv102_users);
+ ndr_print_uint32(ndr, "sv102_disc", r->sv102_disc);
+ ndr_print_uint8(ndr, "sv102_hidden", r->sv102_hidden);
+ ndr_print_uint32(ndr, "sv102_announce", r->sv102_announce);
+ ndr_print_uint32(ndr, "sv102_anndelta", r->sv102_anndelta);
+ ndr_print_uint32(ndr, "sv102_licenses", r->sv102_licenses);
+ ndr_print_string(ndr, "sv102_userpath", r->sv102_userpath);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_SERVER_INFO_1005(struct ndr_push *ndr, int ndr_flags, const struct SERVER_INFO_1005 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->sv1005_comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_SERVER_INFO_1005(struct ndr_pull *ndr, int ndr_flags, struct SERVER_INFO_1005 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->sv1005_comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_SERVER_INFO_1005(struct ndr_print *ndr, const char *name, const struct SERVER_INFO_1005 *r)
+{
+ ndr_print_struct(ndr, name, "SERVER_INFO_1005");
+ ndr->depth++;
+ ndr_print_string(ndr, "sv1005_comment", r->sv1005_comment);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_DOMAIN_CONTROLLER_INFO(struct ndr_push *ndr, int ndr_flags, const struct DOMAIN_CONTROLLER_INFO *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->domain_controller_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->domain_controller_address));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->domain_controller_address_type));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->domain_guid));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->domain_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->dns_forest_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->dc_site_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->client_site_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_DOMAIN_CONTROLLER_INFO(struct ndr_pull *ndr, int ndr_flags, struct DOMAIN_CONTROLLER_INFO *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->domain_controller_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->domain_controller_address));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->domain_controller_address_type));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->domain_guid));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->domain_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->dns_forest_name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->dc_site_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->client_site_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_DOMAIN_CONTROLLER_INFO(struct ndr_print *ndr, const char *name, const struct DOMAIN_CONTROLLER_INFO *r)
+{
+ ndr_print_struct(ndr, name, "DOMAIN_CONTROLLER_INFO");
+ ndr->depth++;
+ ndr_print_string(ndr, "domain_controller_name", r->domain_controller_name);
+ ndr_print_string(ndr, "domain_controller_address", r->domain_controller_address);
+ ndr_print_uint32(ndr, "domain_controller_address_type", r->domain_controller_address_type);
+ ndr_print_GUID(ndr, "domain_guid", &r->domain_guid);
+ ndr_print_string(ndr, "domain_name", r->domain_name);
+ ndr_print_string(ndr, "dns_forest_name", r->dns_forest_name);
+ ndr_print_uint32(ndr, "flags", r->flags);
+ ndr_print_string(ndr, "dc_site_name", r->dc_site_name);
+ ndr_print_string(ndr, "client_site_name", r->client_site_name);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_0(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri0_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_0(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri0_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_0(struct ndr_print *ndr, const char *name, const struct USER_INFO_0 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_0");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri0_name", r->usri0_name);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1_password));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri1_password_age));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri1_priv));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1_home_dir));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1_comment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri1_flags));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1_script_path));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1_password));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri1_password_age));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri1_priv));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1_home_dir));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1_comment));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri1_flags));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1_script_path));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1(struct ndr_print *ndr, const char *name, const struct USER_INFO_1 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri1_name", r->usri1_name);
+ ndr_print_string(ndr, "usri1_password", r->usri1_password);
+ ndr_print_uint32(ndr, "usri1_password_age", r->usri1_password_age);
+ ndr_print_uint32(ndr, "usri1_priv", r->usri1_priv);
+ ndr_print_string(ndr, "usri1_home_dir", r->usri1_home_dir);
+ ndr_print_string(ndr, "usri1_comment", r->usri1_comment);
+ ndr_print_uint32(ndr, "usri1_flags", r->usri1_flags);
+ ndr_print_string(ndr, "usri1_script_path", r->usri1_script_path);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_2(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri2_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri2_password));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri2_password_age));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri2_priv));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri2_home_dir));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri2_comment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri2_flags));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri2_script_path));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri2_auth_flags));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri2_full_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri2_usr_comment));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri2_parms));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri2_workstations));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri2_last_logon));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri2_last_logoff));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri2_acct_expires));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri2_max_storage));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri2_units_per_week));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->usri2_logon_hours));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri2_bad_pw_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri2_num_logons));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri2_logon_server));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri2_country_code));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri2_code_page));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->usri2_logon_hours) {
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, *r->usri2_logon_hours));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_2(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_2 *r)
+{
+ uint32_t _ptr_usri2_logon_hours;
+ TALLOC_CTX *_mem_save_usri2_logon_hours_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri2_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri2_password));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri2_password_age));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri2_priv));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri2_home_dir));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri2_comment));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri2_flags));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri2_script_path));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri2_auth_flags));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri2_full_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri2_usr_comment));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri2_parms));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri2_workstations));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri2_last_logon));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri2_last_logoff));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri2_acct_expires));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri2_max_storage));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri2_units_per_week));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_usri2_logon_hours));
+ if (_ptr_usri2_logon_hours) {
+ NDR_PULL_ALLOC(ndr, r->usri2_logon_hours);
+ } else {
+ r->usri2_logon_hours = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri2_bad_pw_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri2_num_logons));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri2_logon_server));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri2_country_code));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri2_code_page));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->usri2_logon_hours) {
+ _mem_save_usri2_logon_hours_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->usri2_logon_hours, 0);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, r->usri2_logon_hours));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_usri2_logon_hours_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_2(struct ndr_print *ndr, const char *name, const struct USER_INFO_2 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_2");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri2_name", r->usri2_name);
+ ndr_print_string(ndr, "usri2_password", r->usri2_password);
+ ndr_print_uint32(ndr, "usri2_password_age", r->usri2_password_age);
+ ndr_print_uint32(ndr, "usri2_priv", r->usri2_priv);
+ ndr_print_string(ndr, "usri2_home_dir", r->usri2_home_dir);
+ ndr_print_string(ndr, "usri2_comment", r->usri2_comment);
+ ndr_print_uint32(ndr, "usri2_flags", r->usri2_flags);
+ ndr_print_string(ndr, "usri2_script_path", r->usri2_script_path);
+ ndr_print_uint32(ndr, "usri2_auth_flags", r->usri2_auth_flags);
+ ndr_print_string(ndr, "usri2_full_name", r->usri2_full_name);
+ ndr_print_string(ndr, "usri2_usr_comment", r->usri2_usr_comment);
+ ndr_print_string(ndr, "usri2_parms", r->usri2_parms);
+ ndr_print_string(ndr, "usri2_workstations", r->usri2_workstations);
+ ndr_print_uint32(ndr, "usri2_last_logon", r->usri2_last_logon);
+ ndr_print_uint32(ndr, "usri2_last_logoff", r->usri2_last_logoff);
+ ndr_print_uint32(ndr, "usri2_acct_expires", r->usri2_acct_expires);
+ ndr_print_uint32(ndr, "usri2_max_storage", r->usri2_max_storage);
+ ndr_print_uint32(ndr, "usri2_units_per_week", r->usri2_units_per_week);
+ ndr_print_ptr(ndr, "usri2_logon_hours", r->usri2_logon_hours);
+ ndr->depth++;
+ if (r->usri2_logon_hours) {
+ ndr_print_uint8(ndr, "usri2_logon_hours", *r->usri2_logon_hours);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "usri2_bad_pw_count", r->usri2_bad_pw_count);
+ ndr_print_uint32(ndr, "usri2_num_logons", r->usri2_num_logons);
+ ndr_print_string(ndr, "usri2_logon_server", r->usri2_logon_server);
+ ndr_print_uint32(ndr, "usri2_country_code", r->usri2_country_code);
+ ndr_print_uint32(ndr, "usri2_code_page", r->usri2_code_page);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_3(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri3_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri3_password_age));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri3_priv));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri3_home_dir));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri3_comment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri3_flags));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri3_script_path));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri3_auth_flags));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri3_full_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri3_usr_comment));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri3_parms));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri3_workstations));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri3_last_logon));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri3_last_logoff));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri3_acct_expires));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri3_max_storage));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri3_units_per_week));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->usri3_logon_hours));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri3_bad_pw_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri3_num_logons));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri3_logon_server));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri3_country_code));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri3_code_page));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri3_user_id));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri3_primary_group_id));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri3_profile));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri3_home_dir_drive));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri3_password_expired));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->usri3_logon_hours) {
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, *r->usri3_logon_hours));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_3(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_3 *r)
+{
+ uint32_t _ptr_usri3_logon_hours;
+ TALLOC_CTX *_mem_save_usri3_logon_hours_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri3_name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri3_password_age));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri3_priv));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri3_home_dir));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri3_comment));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri3_flags));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri3_script_path));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri3_auth_flags));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri3_full_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri3_usr_comment));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri3_parms));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri3_workstations));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri3_last_logon));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri3_last_logoff));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri3_acct_expires));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri3_max_storage));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri3_units_per_week));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_usri3_logon_hours));
+ if (_ptr_usri3_logon_hours) {
+ NDR_PULL_ALLOC(ndr, r->usri3_logon_hours);
+ } else {
+ r->usri3_logon_hours = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri3_bad_pw_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri3_num_logons));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri3_logon_server));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri3_country_code));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri3_code_page));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri3_user_id));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri3_primary_group_id));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri3_profile));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri3_home_dir_drive));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri3_password_expired));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->usri3_logon_hours) {
+ _mem_save_usri3_logon_hours_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->usri3_logon_hours, 0);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, r->usri3_logon_hours));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_usri3_logon_hours_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_3(struct ndr_print *ndr, const char *name, const struct USER_INFO_3 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_3");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri3_name", r->usri3_name);
+ ndr_print_uint32(ndr, "usri3_password_age", r->usri3_password_age);
+ ndr_print_uint32(ndr, "usri3_priv", r->usri3_priv);
+ ndr_print_string(ndr, "usri3_home_dir", r->usri3_home_dir);
+ ndr_print_string(ndr, "usri3_comment", r->usri3_comment);
+ ndr_print_uint32(ndr, "usri3_flags", r->usri3_flags);
+ ndr_print_string(ndr, "usri3_script_path", r->usri3_script_path);
+ ndr_print_uint32(ndr, "usri3_auth_flags", r->usri3_auth_flags);
+ ndr_print_string(ndr, "usri3_full_name", r->usri3_full_name);
+ ndr_print_string(ndr, "usri3_usr_comment", r->usri3_usr_comment);
+ ndr_print_string(ndr, "usri3_parms", r->usri3_parms);
+ ndr_print_string(ndr, "usri3_workstations", r->usri3_workstations);
+ ndr_print_uint32(ndr, "usri3_last_logon", r->usri3_last_logon);
+ ndr_print_uint32(ndr, "usri3_last_logoff", r->usri3_last_logoff);
+ ndr_print_uint32(ndr, "usri3_acct_expires", r->usri3_acct_expires);
+ ndr_print_uint32(ndr, "usri3_max_storage", r->usri3_max_storage);
+ ndr_print_uint32(ndr, "usri3_units_per_week", r->usri3_units_per_week);
+ ndr_print_ptr(ndr, "usri3_logon_hours", r->usri3_logon_hours);
+ ndr->depth++;
+ if (r->usri3_logon_hours) {
+ ndr_print_uint8(ndr, "usri3_logon_hours", *r->usri3_logon_hours);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "usri3_bad_pw_count", r->usri3_bad_pw_count);
+ ndr_print_uint32(ndr, "usri3_num_logons", r->usri3_num_logons);
+ ndr_print_string(ndr, "usri3_logon_server", r->usri3_logon_server);
+ ndr_print_uint32(ndr, "usri3_country_code", r->usri3_country_code);
+ ndr_print_uint32(ndr, "usri3_code_page", r->usri3_code_page);
+ ndr_print_uint32(ndr, "usri3_user_id", r->usri3_user_id);
+ ndr_print_uint32(ndr, "usri3_primary_group_id", r->usri3_primary_group_id);
+ ndr_print_string(ndr, "usri3_profile", r->usri3_profile);
+ ndr_print_string(ndr, "usri3_home_dir_drive", r->usri3_home_dir_drive);
+ ndr_print_uint32(ndr, "usri3_password_expired", r->usri3_password_expired);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_4(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_4 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri4_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri4_password));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri4_password_age));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri4_priv));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri4_home_dir));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri4_comment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri4_flags));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri4_script_path));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri4_auth_flags));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri4_full_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri4_usr_comment));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri4_parms));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri4_workstations));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri4_last_logon));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri4_last_logoff));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri4_acct_expires));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri4_max_storage));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri4_units_per_week));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->usri4_logon_hours));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri4_bad_pw_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri4_num_logons));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri4_logon_server));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri4_country_code));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri4_code_page));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->usri4_user_sid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri4_primary_group_id));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri4_profile));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri4_home_dir_drive));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri4_password_expired));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->usri4_logon_hours) {
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, *r->usri4_logon_hours));
+ }
+ if (r->usri4_user_sid) {
+ NDR_CHECK(ndr_push_domsid(ndr, NDR_SCALARS, r->usri4_user_sid));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_4(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_4 *r)
+{
+ uint32_t _ptr_usri4_logon_hours;
+ TALLOC_CTX *_mem_save_usri4_logon_hours_0;
+ uint32_t _ptr_usri4_user_sid;
+ TALLOC_CTX *_mem_save_usri4_user_sid_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri4_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri4_password));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri4_password_age));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri4_priv));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri4_home_dir));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri4_comment));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri4_flags));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri4_script_path));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri4_auth_flags));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri4_full_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri4_usr_comment));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri4_parms));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri4_workstations));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri4_last_logon));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri4_last_logoff));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri4_acct_expires));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri4_max_storage));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri4_units_per_week));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_usri4_logon_hours));
+ if (_ptr_usri4_logon_hours) {
+ NDR_PULL_ALLOC(ndr, r->usri4_logon_hours);
+ } else {
+ r->usri4_logon_hours = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri4_bad_pw_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri4_num_logons));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri4_logon_server));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri4_country_code));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri4_code_page));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_usri4_user_sid));
+ if (_ptr_usri4_user_sid) {
+ NDR_PULL_ALLOC(ndr, r->usri4_user_sid);
+ } else {
+ r->usri4_user_sid = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri4_primary_group_id));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri4_profile));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri4_home_dir_drive));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri4_password_expired));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->usri4_logon_hours) {
+ _mem_save_usri4_logon_hours_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->usri4_logon_hours, 0);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, r->usri4_logon_hours));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_usri4_logon_hours_0, 0);
+ }
+ if (r->usri4_user_sid) {
+ _mem_save_usri4_user_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->usri4_user_sid, 0);
+ NDR_CHECK(ndr_pull_domsid(ndr, NDR_SCALARS, r->usri4_user_sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_usri4_user_sid_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_4(struct ndr_print *ndr, const char *name, const struct USER_INFO_4 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_4");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri4_name", r->usri4_name);
+ ndr_print_string(ndr, "usri4_password", r->usri4_password);
+ ndr_print_uint32(ndr, "usri4_password_age", r->usri4_password_age);
+ ndr_print_uint32(ndr, "usri4_priv", r->usri4_priv);
+ ndr_print_string(ndr, "usri4_home_dir", r->usri4_home_dir);
+ ndr_print_string(ndr, "usri4_comment", r->usri4_comment);
+ ndr_print_uint32(ndr, "usri4_flags", r->usri4_flags);
+ ndr_print_string(ndr, "usri4_script_path", r->usri4_script_path);
+ ndr_print_uint32(ndr, "usri4_auth_flags", r->usri4_auth_flags);
+ ndr_print_string(ndr, "usri4_full_name", r->usri4_full_name);
+ ndr_print_string(ndr, "usri4_usr_comment", r->usri4_usr_comment);
+ ndr_print_string(ndr, "usri4_parms", r->usri4_parms);
+ ndr_print_string(ndr, "usri4_workstations", r->usri4_workstations);
+ ndr_print_uint32(ndr, "usri4_last_logon", r->usri4_last_logon);
+ ndr_print_uint32(ndr, "usri4_last_logoff", r->usri4_last_logoff);
+ ndr_print_uint32(ndr, "usri4_acct_expires", r->usri4_acct_expires);
+ ndr_print_uint32(ndr, "usri4_max_storage", r->usri4_max_storage);
+ ndr_print_uint32(ndr, "usri4_units_per_week", r->usri4_units_per_week);
+ ndr_print_ptr(ndr, "usri4_logon_hours", r->usri4_logon_hours);
+ ndr->depth++;
+ if (r->usri4_logon_hours) {
+ ndr_print_uint8(ndr, "usri4_logon_hours", *r->usri4_logon_hours);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "usri4_bad_pw_count", r->usri4_bad_pw_count);
+ ndr_print_uint32(ndr, "usri4_num_logons", r->usri4_num_logons);
+ ndr_print_string(ndr, "usri4_logon_server", r->usri4_logon_server);
+ ndr_print_uint32(ndr, "usri4_country_code", r->usri4_country_code);
+ ndr_print_uint32(ndr, "usri4_code_page", r->usri4_code_page);
+ ndr_print_ptr(ndr, "usri4_user_sid", r->usri4_user_sid);
+ ndr->depth++;
+ if (r->usri4_user_sid) {
+ ndr_print_domsid(ndr, "usri4_user_sid", r->usri4_user_sid);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "usri4_primary_group_id", r->usri4_primary_group_id);
+ ndr_print_string(ndr, "usri4_profile", r->usri4_profile);
+ ndr_print_string(ndr, "usri4_home_dir_drive", r->usri4_home_dir_drive);
+ ndr_print_uint32(ndr, "usri4_password_expired", r->usri4_password_expired);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_10(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_10 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri10_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri10_comment));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri10_usr_comment));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri10_full_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_10(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_10 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri10_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri10_comment));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri10_usr_comment));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri10_full_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_10(struct ndr_print *ndr, const char *name, const struct USER_INFO_10 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_10");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri10_name", r->usri10_name);
+ ndr_print_string(ndr, "usri10_comment", r->usri10_comment);
+ ndr_print_string(ndr, "usri10_usr_comment", r->usri10_usr_comment);
+ ndr_print_string(ndr, "usri10_full_name", r->usri10_full_name);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_11(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_11 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri11_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri11_comment));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri11_usr_comment));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri11_full_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri11_priv));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri11_auth_flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri11_password_age));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri11_home_dir));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri11_parms));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri11_last_logon));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri11_last_logoff));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri11_bad_pw_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri11_num_logons));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri11_logon_server));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri11_country_code));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri11_workstations));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri11_max_storage));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri11_units_per_week));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->usri11_logon_hours));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri11_code_page));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->usri11_logon_hours) {
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, *r->usri11_logon_hours));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_11(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_11 *r)
+{
+ uint32_t _ptr_usri11_logon_hours;
+ TALLOC_CTX *_mem_save_usri11_logon_hours_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri11_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri11_comment));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri11_usr_comment));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri11_full_name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri11_priv));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri11_auth_flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri11_password_age));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri11_home_dir));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri11_parms));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri11_last_logon));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri11_last_logoff));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri11_bad_pw_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri11_num_logons));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri11_logon_server));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri11_country_code));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri11_workstations));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri11_max_storage));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri11_units_per_week));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_usri11_logon_hours));
+ if (_ptr_usri11_logon_hours) {
+ NDR_PULL_ALLOC(ndr, r->usri11_logon_hours);
+ } else {
+ r->usri11_logon_hours = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri11_code_page));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->usri11_logon_hours) {
+ _mem_save_usri11_logon_hours_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->usri11_logon_hours, 0);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, r->usri11_logon_hours));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_usri11_logon_hours_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_11(struct ndr_print *ndr, const char *name, const struct USER_INFO_11 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_11");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri11_name", r->usri11_name);
+ ndr_print_string(ndr, "usri11_comment", r->usri11_comment);
+ ndr_print_string(ndr, "usri11_usr_comment", r->usri11_usr_comment);
+ ndr_print_string(ndr, "usri11_full_name", r->usri11_full_name);
+ ndr_print_uint32(ndr, "usri11_priv", r->usri11_priv);
+ ndr_print_uint32(ndr, "usri11_auth_flags", r->usri11_auth_flags);
+ ndr_print_uint32(ndr, "usri11_password_age", r->usri11_password_age);
+ ndr_print_string(ndr, "usri11_home_dir", r->usri11_home_dir);
+ ndr_print_string(ndr, "usri11_parms", r->usri11_parms);
+ ndr_print_uint32(ndr, "usri11_last_logon", r->usri11_last_logon);
+ ndr_print_uint32(ndr, "usri11_last_logoff", r->usri11_last_logoff);
+ ndr_print_uint32(ndr, "usri11_bad_pw_count", r->usri11_bad_pw_count);
+ ndr_print_uint32(ndr, "usri11_num_logons", r->usri11_num_logons);
+ ndr_print_string(ndr, "usri11_logon_server", r->usri11_logon_server);
+ ndr_print_uint32(ndr, "usri11_country_code", r->usri11_country_code);
+ ndr_print_string(ndr, "usri11_workstations", r->usri11_workstations);
+ ndr_print_uint32(ndr, "usri11_max_storage", r->usri11_max_storage);
+ ndr_print_uint32(ndr, "usri11_units_per_week", r->usri11_units_per_week);
+ ndr_print_ptr(ndr, "usri11_logon_hours", r->usri11_logon_hours);
+ ndr->depth++;
+ if (r->usri11_logon_hours) {
+ ndr_print_uint8(ndr, "usri11_logon_hours", *r->usri11_logon_hours);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "usri11_code_page", r->usri11_code_page);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_20(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_20 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri20_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri20_full_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri20_comment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri20_flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri20_user_id));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_20(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_20 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri20_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri20_full_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri20_comment));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri20_flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri20_user_id));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_20(struct ndr_print *ndr, const char *name, const struct USER_INFO_20 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_20");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri20_name", r->usri20_name);
+ ndr_print_string(ndr, "usri20_full_name", r->usri20_full_name);
+ ndr_print_string(ndr, "usri20_comment", r->usri20_comment);
+ ndr_print_uint32(ndr, "usri20_flags", r->usri20_flags);
+ ndr_print_uint32(ndr, "usri20_user_id", r->usri20_user_id);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_21(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_21 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->usri21_password, ENCRYPTED_PWLEN));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_21(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_21 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_PULL_ALLOC_N(ndr, r->usri21_password, ENCRYPTED_PWLEN);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->usri21_password, ENCRYPTED_PWLEN));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_21(struct ndr_print *ndr, const char *name, const struct USER_INFO_21 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_21");
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "usri21_password", r->usri21_password, ENCRYPTED_PWLEN);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_22(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_22 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri22_name));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->usri22_password, ENCRYPTED_PWLEN));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri22_password_age));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri22_priv));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri22_home_dir));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri22_comment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri22_flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri22_script_path));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri22_auth_flags));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri22_full_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri22_usr_comment));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri22_parms));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri22_workstations));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri22_last_logon));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri22_last_logoff));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri22_acct_expires));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri22_max_storage));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri22_units_per_week));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->usri22_logon_hours));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri22_bad_pw_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri22_num_logons));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri22_logon_server));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri22_country_code));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri22_code_page));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->usri22_logon_hours) {
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, *r->usri22_logon_hours));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_22(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_22 *r)
+{
+ uint32_t _ptr_usri22_logon_hours;
+ TALLOC_CTX *_mem_save_usri22_logon_hours_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri22_name));
+ NDR_PULL_ALLOC_N(ndr, r->usri22_password, ENCRYPTED_PWLEN);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->usri22_password, ENCRYPTED_PWLEN));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri22_password_age));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri22_priv));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri22_home_dir));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri22_comment));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri22_flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri22_script_path));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri22_auth_flags));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri22_full_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri22_usr_comment));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri22_parms));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri22_workstations));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri22_last_logon));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri22_last_logoff));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri22_acct_expires));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri22_max_storage));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri22_units_per_week));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_usri22_logon_hours));
+ if (_ptr_usri22_logon_hours) {
+ NDR_PULL_ALLOC(ndr, r->usri22_logon_hours);
+ } else {
+ r->usri22_logon_hours = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri22_bad_pw_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri22_num_logons));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri22_logon_server));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri22_country_code));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri22_code_page));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->usri22_logon_hours) {
+ _mem_save_usri22_logon_hours_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->usri22_logon_hours, 0);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, r->usri22_logon_hours));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_usri22_logon_hours_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_22(struct ndr_print *ndr, const char *name, const struct USER_INFO_22 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_22");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri22_name", r->usri22_name);
+ ndr_print_array_uint8(ndr, "usri22_password", r->usri22_password, ENCRYPTED_PWLEN);
+ ndr_print_uint32(ndr, "usri22_password_age", r->usri22_password_age);
+ ndr_print_uint32(ndr, "usri22_priv", r->usri22_priv);
+ ndr_print_string(ndr, "usri22_home_dir", r->usri22_home_dir);
+ ndr_print_string(ndr, "usri22_comment", r->usri22_comment);
+ ndr_print_uint32(ndr, "usri22_flags", r->usri22_flags);
+ ndr_print_uint32(ndr, "usri22_script_path", r->usri22_script_path);
+ ndr_print_uint32(ndr, "usri22_auth_flags", r->usri22_auth_flags);
+ ndr_print_string(ndr, "usri22_full_name", r->usri22_full_name);
+ ndr_print_string(ndr, "usri22_usr_comment", r->usri22_usr_comment);
+ ndr_print_string(ndr, "usri22_parms", r->usri22_parms);
+ ndr_print_string(ndr, "usri22_workstations", r->usri22_workstations);
+ ndr_print_uint32(ndr, "usri22_last_logon", r->usri22_last_logon);
+ ndr_print_uint32(ndr, "usri22_last_logoff", r->usri22_last_logoff);
+ ndr_print_uint32(ndr, "usri22_acct_expires", r->usri22_acct_expires);
+ ndr_print_uint32(ndr, "usri22_max_storage", r->usri22_max_storage);
+ ndr_print_uint32(ndr, "usri22_units_per_week", r->usri22_units_per_week);
+ ndr_print_ptr(ndr, "usri22_logon_hours", r->usri22_logon_hours);
+ ndr->depth++;
+ if (r->usri22_logon_hours) {
+ ndr_print_uint8(ndr, "usri22_logon_hours", *r->usri22_logon_hours);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "usri22_bad_pw_count", r->usri22_bad_pw_count);
+ ndr_print_uint32(ndr, "usri22_num_logons", r->usri22_num_logons);
+ ndr_print_string(ndr, "usri22_logon_server", r->usri22_logon_server);
+ ndr_print_uint32(ndr, "usri22_country_code", r->usri22_country_code);
+ ndr_print_uint32(ndr, "usri22_code_page", r->usri22_code_page);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_23(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_23 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri23_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri23_full_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri23_comment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri23_flags));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->usri23_user_sid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->usri23_user_sid) {
+ NDR_CHECK(ndr_push_domsid(ndr, NDR_SCALARS, r->usri23_user_sid));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_23(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_23 *r)
+{
+ uint32_t _ptr_usri23_user_sid;
+ TALLOC_CTX *_mem_save_usri23_user_sid_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri23_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri23_full_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri23_comment));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri23_flags));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_usri23_user_sid));
+ if (_ptr_usri23_user_sid) {
+ NDR_PULL_ALLOC(ndr, r->usri23_user_sid);
+ } else {
+ r->usri23_user_sid = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->usri23_user_sid) {
+ _mem_save_usri23_user_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->usri23_user_sid, 0);
+ NDR_CHECK(ndr_pull_domsid(ndr, NDR_SCALARS, r->usri23_user_sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_usri23_user_sid_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_23(struct ndr_print *ndr, const char *name, const struct USER_INFO_23 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_23");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri23_name", r->usri23_name);
+ ndr_print_string(ndr, "usri23_full_name", r->usri23_full_name);
+ ndr_print_string(ndr, "usri23_comment", r->usri23_comment);
+ ndr_print_uint32(ndr, "usri23_flags", r->usri23_flags);
+ ndr_print_ptr(ndr, "usri23_user_sid", r->usri23_user_sid);
+ ndr->depth++;
+ if (r->usri23_user_sid) {
+ ndr_print_domsid(ndr, "usri23_user_sid", r->usri23_user_sid);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1003(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1003 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1003_password));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1003(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1003 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1003_password));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1003(struct ndr_print *ndr, const char *name, const struct USER_INFO_1003 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1003");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri1003_password", r->usri1003_password);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1005(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1005 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri1005_priv));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1005(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1005 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri1005_priv));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1005(struct ndr_print *ndr, const char *name, const struct USER_INFO_1005 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1005");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "usri1005_priv", r->usri1005_priv);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1006(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1006 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1006_home_dir));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1006(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1006 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1006_home_dir));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1006(struct ndr_print *ndr, const char *name, const struct USER_INFO_1006 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1006");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri1006_home_dir", r->usri1006_home_dir);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1007(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1007 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1007_comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1007(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1007 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1007_comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1007(struct ndr_print *ndr, const char *name, const struct USER_INFO_1007 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1007");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri1007_comment", r->usri1007_comment);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1008(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1008 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri1008_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1008(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1008 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri1008_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1008(struct ndr_print *ndr, const char *name, const struct USER_INFO_1008 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1008");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "usri1008_flags", r->usri1008_flags);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1009(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1009 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1009_script_path));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1009(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1009 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1009_script_path));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1009(struct ndr_print *ndr, const char *name, const struct USER_INFO_1009 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1009");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri1009_script_path", r->usri1009_script_path);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1010(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1010 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri1010_auth_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1010(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1010 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri1010_auth_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1010(struct ndr_print *ndr, const char *name, const struct USER_INFO_1010 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1010");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "usri1010_auth_flags", r->usri1010_auth_flags);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1011(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1011 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1011_full_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1011(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1011 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1011_full_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1011(struct ndr_print *ndr, const char *name, const struct USER_INFO_1011 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1011");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri1011_full_name", r->usri1011_full_name);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1012(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1012 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1012_usr_comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1012(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1012 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1012_usr_comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1012(struct ndr_print *ndr, const char *name, const struct USER_INFO_1012 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1012");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri1012_usr_comment", r->usri1012_usr_comment);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1013(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1013 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1013_parms));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1013(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1013 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1013_parms));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1013(struct ndr_print *ndr, const char *name, const struct USER_INFO_1013 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1013");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri1013_parms", r->usri1013_parms);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1014(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1014 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1014_workstations));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1014(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1014 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1014_workstations));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1014(struct ndr_print *ndr, const char *name, const struct USER_INFO_1014 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1014");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri1014_workstations", r->usri1014_workstations);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1017(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1017 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri1017_acct_expires));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1017(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1017 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri1017_acct_expires));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1017(struct ndr_print *ndr, const char *name, const struct USER_INFO_1017 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1017");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "usri1017_acct_expires", r->usri1017_acct_expires);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1018(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1018 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri1018_max_storage));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1018(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1018 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri1018_max_storage));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1018(struct ndr_print *ndr, const char *name, const struct USER_INFO_1018 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1018");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "usri1018_max_storage", r->usri1018_max_storage);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1020(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1020 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri1020_units_per_week));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->usri1020_logon_hours));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->usri1020_logon_hours) {
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, *r->usri1020_logon_hours));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1020(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1020 *r)
+{
+ uint32_t _ptr_usri1020_logon_hours;
+ TALLOC_CTX *_mem_save_usri1020_logon_hours_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri1020_units_per_week));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_usri1020_logon_hours));
+ if (_ptr_usri1020_logon_hours) {
+ NDR_PULL_ALLOC(ndr, r->usri1020_logon_hours);
+ } else {
+ r->usri1020_logon_hours = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->usri1020_logon_hours) {
+ _mem_save_usri1020_logon_hours_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->usri1020_logon_hours, 0);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, r->usri1020_logon_hours));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_usri1020_logon_hours_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1020(struct ndr_print *ndr, const char *name, const struct USER_INFO_1020 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1020");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "usri1020_units_per_week", r->usri1020_units_per_week);
+ ndr_print_ptr(ndr, "usri1020_logon_hours", r->usri1020_logon_hours);
+ ndr->depth++;
+ if (r->usri1020_logon_hours) {
+ ndr_print_uint8(ndr, "usri1020_logon_hours", *r->usri1020_logon_hours);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1023(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1023 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1023_logon_server));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1023(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1023 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1023_logon_server));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1023(struct ndr_print *ndr, const char *name, const struct USER_INFO_1023 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1023");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri1023_logon_server", r->usri1023_logon_server);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1024(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1024 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri1024_country_code));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1024(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1024 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri1024_country_code));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1024(struct ndr_print *ndr, const char *name, const struct USER_INFO_1024 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1024");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "usri1024_country_code", r->usri1024_country_code);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1025(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1025 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri1025_code_page));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1025(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1025 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri1025_code_page));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1025(struct ndr_print *ndr, const char *name, const struct USER_INFO_1025 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1025");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "usri1025_code_page", r->usri1025_code_page);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1051(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1051 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri1051_primary_group_id));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1051(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1051 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri1051_primary_group_id));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1051(struct ndr_print *ndr, const char *name, const struct USER_INFO_1051 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1051");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "usri1051_primary_group_id", r->usri1051_primary_group_id);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1052(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1052 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1052_profile));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1052(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1052 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1052_profile));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1052(struct ndr_print *ndr, const char *name, const struct USER_INFO_1052 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1052");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri1052_profile", r->usri1052_profile);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_1053(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1053 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1053_home_dir_drive));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_1053(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1053 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1053_home_dir_drive));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_1053(struct ndr_print *ndr, const char *name, const struct USER_INFO_1053 *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_1053");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri1053_home_dir_drive", r->usri1053_home_dir_drive);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_X(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_X *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usriX_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usriX_password));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_password_age));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_priv));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usriX_home_dir));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usriX_comment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_flags));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usriX_script_path));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_auth_flags));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usriX_full_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usriX_usr_comment));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usriX_parms));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usriX_workstations));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_last_logon));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_last_logoff));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_acct_expires));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_max_storage));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_units_per_week));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->usriX_logon_hours));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_bad_pw_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_num_logons));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usriX_logon_server));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_country_code));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_code_page));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usriX_profile));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usriX_home_dir_drive));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_primary_group_id));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->usriX_logon_hours) {
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, *r->usriX_logon_hours));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_X(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_X *r)
+{
+ uint32_t _ptr_usriX_logon_hours;
+ TALLOC_CTX *_mem_save_usriX_logon_hours_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usriX_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usriX_password));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_password_age));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_priv));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usriX_home_dir));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usriX_comment));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_flags));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usriX_script_path));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_auth_flags));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usriX_full_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usriX_usr_comment));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usriX_parms));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usriX_workstations));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_last_logon));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_last_logoff));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_acct_expires));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_max_storage));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_units_per_week));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_usriX_logon_hours));
+ if (_ptr_usriX_logon_hours) {
+ NDR_PULL_ALLOC(ndr, r->usriX_logon_hours);
+ } else {
+ r->usriX_logon_hours = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_bad_pw_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_num_logons));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usriX_logon_server));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_country_code));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_code_page));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usriX_profile));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usriX_home_dir_drive));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_primary_group_id));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->usriX_logon_hours) {
+ _mem_save_usriX_logon_hours_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->usriX_logon_hours, 0);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, r->usriX_logon_hours));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_usriX_logon_hours_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_USER_INFO_X(struct ndr_print *ndr, const char *name, const struct USER_INFO_X *r)
+{
+ ndr_print_struct(ndr, name, "USER_INFO_X");
+ ndr->depth++;
+ ndr_print_string(ndr, "usriX_name", r->usriX_name);
+ ndr_print_string(ndr, "usriX_password", r->usriX_password);
+ ndr_print_uint32(ndr, "usriX_password_age", r->usriX_password_age);
+ ndr_print_uint32(ndr, "usriX_priv", r->usriX_priv);
+ ndr_print_string(ndr, "usriX_home_dir", r->usriX_home_dir);
+ ndr_print_string(ndr, "usriX_comment", r->usriX_comment);
+ ndr_print_uint32(ndr, "usriX_flags", r->usriX_flags);
+ ndr_print_string(ndr, "usriX_script_path", r->usriX_script_path);
+ ndr_print_uint32(ndr, "usriX_auth_flags", r->usriX_auth_flags);
+ ndr_print_string(ndr, "usriX_full_name", r->usriX_full_name);
+ ndr_print_string(ndr, "usriX_usr_comment", r->usriX_usr_comment);
+ ndr_print_string(ndr, "usriX_parms", r->usriX_parms);
+ ndr_print_string(ndr, "usriX_workstations", r->usriX_workstations);
+ ndr_print_uint32(ndr, "usriX_last_logon", r->usriX_last_logon);
+ ndr_print_uint32(ndr, "usriX_last_logoff", r->usriX_last_logoff);
+ ndr_print_uint32(ndr, "usriX_acct_expires", r->usriX_acct_expires);
+ ndr_print_uint32(ndr, "usriX_max_storage", r->usriX_max_storage);
+ ndr_print_uint32(ndr, "usriX_units_per_week", r->usriX_units_per_week);
+ ndr_print_ptr(ndr, "usriX_logon_hours", r->usriX_logon_hours);
+ ndr->depth++;
+ if (r->usriX_logon_hours) {
+ ndr_print_uint8(ndr, "usriX_logon_hours", *r->usriX_logon_hours);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "usriX_bad_pw_count", r->usriX_bad_pw_count);
+ ndr_print_uint32(ndr, "usriX_num_logons", r->usriX_num_logons);
+ ndr_print_string(ndr, "usriX_logon_server", r->usriX_logon_server);
+ ndr_print_uint32(ndr, "usriX_country_code", r->usriX_country_code);
+ ndr_print_uint32(ndr, "usriX_code_page", r->usriX_code_page);
+ ndr_print_string(ndr, "usriX_profile", r->usriX_profile);
+ ndr_print_string(ndr, "usriX_home_dir_drive", r->usriX_home_dir_drive);
+ ndr_print_uint32(ndr, "usriX_primary_group_id", r->usriX_primary_group_id);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_GROUP_USERS_INFO_0(struct ndr_push *ndr, int ndr_flags, const struct GROUP_USERS_INFO_0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->grui0_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_GROUP_USERS_INFO_0(struct ndr_pull *ndr, int ndr_flags, struct GROUP_USERS_INFO_0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->grui0_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_GROUP_USERS_INFO_0(struct ndr_print *ndr, const char *name, const struct GROUP_USERS_INFO_0 *r)
+{
+ ndr_print_struct(ndr, name, "GROUP_USERS_INFO_0");
+ ndr->depth++;
+ ndr_print_string(ndr, "grui0_name", r->grui0_name);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_GROUP_USERS_INFO_1(struct ndr_push *ndr, int ndr_flags, const struct GROUP_USERS_INFO_1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->grui1_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->grui1_attributes));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_GROUP_USERS_INFO_1(struct ndr_pull *ndr, int ndr_flags, struct GROUP_USERS_INFO_1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->grui1_name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->grui1_attributes));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_GROUP_USERS_INFO_1(struct ndr_print *ndr, const char *name, const struct GROUP_USERS_INFO_1 *r)
+{
+ ndr_print_struct(ndr, name, "GROUP_USERS_INFO_1");
+ ndr->depth++;
+ ndr_print_string(ndr, "grui1_name", r->grui1_name);
+ ndr_print_uint32(ndr, "grui1_attributes", r->grui1_attributes);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_NET_DISPLAY_USER(struct ndr_push *ndr, int ndr_flags, const struct NET_DISPLAY_USER *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1_comment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri1_flags));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri1_full_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri1_user_id));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri1_next_index));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_NET_DISPLAY_USER(struct ndr_pull *ndr, int ndr_flags, struct NET_DISPLAY_USER *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1_comment));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri1_flags));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri1_full_name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri1_user_id));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri1_next_index));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_NET_DISPLAY_USER(struct ndr_print *ndr, const char *name, const struct NET_DISPLAY_USER *r)
+{
+ ndr_print_struct(ndr, name, "NET_DISPLAY_USER");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri1_name", r->usri1_name);
+ ndr_print_string(ndr, "usri1_comment", r->usri1_comment);
+ ndr_print_uint32(ndr, "usri1_flags", r->usri1_flags);
+ ndr_print_string(ndr, "usri1_full_name", r->usri1_full_name);
+ ndr_print_uint32(ndr, "usri1_user_id", r->usri1_user_id);
+ ndr_print_uint32(ndr, "usri1_next_index", r->usri1_next_index);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_NET_DISPLAY_MACHINE(struct ndr_push *ndr, int ndr_flags, const struct NET_DISPLAY_MACHINE *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri2_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usri2_comment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri2_flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri2_user_id));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usri2_next_index));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_NET_DISPLAY_MACHINE(struct ndr_pull *ndr, int ndr_flags, struct NET_DISPLAY_MACHINE *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri2_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usri2_comment));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri2_flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri2_user_id));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usri2_next_index));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_NET_DISPLAY_MACHINE(struct ndr_print *ndr, const char *name, const struct NET_DISPLAY_MACHINE *r)
+{
+ ndr_print_struct(ndr, name, "NET_DISPLAY_MACHINE");
+ ndr->depth++;
+ ndr_print_string(ndr, "usri2_name", r->usri2_name);
+ ndr_print_string(ndr, "usri2_comment", r->usri2_comment);
+ ndr_print_uint32(ndr, "usri2_flags", r->usri2_flags);
+ ndr_print_uint32(ndr, "usri2_user_id", r->usri2_user_id);
+ ndr_print_uint32(ndr, "usri2_next_index", r->usri2_next_index);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_NET_DISPLAY_GROUP(struct ndr_push *ndr, int ndr_flags, const struct NET_DISPLAY_GROUP *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->grpi3_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->grpi3_comment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->grpi3_group_id));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->grpi3_attributes));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->grpi3_next_index));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_NET_DISPLAY_GROUP(struct ndr_pull *ndr, int ndr_flags, struct NET_DISPLAY_GROUP *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->grpi3_name));
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->grpi3_comment));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->grpi3_group_id));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->grpi3_attributes));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->grpi3_next_index));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_NET_DISPLAY_GROUP(struct ndr_print *ndr, const char *name, const struct NET_DISPLAY_GROUP *r)
+{
+ ndr_print_struct(ndr, name, "NET_DISPLAY_GROUP");
+ ndr->depth++;
+ ndr_print_string(ndr, "grpi3_name", r->grpi3_name);
+ ndr_print_string(ndr, "grpi3_comment", r->grpi3_comment);
+ ndr_print_uint32(ndr, "grpi3_group_id", r->grpi3_group_id);
+ ndr_print_uint32(ndr, "grpi3_attributes", r->grpi3_attributes);
+ ndr_print_uint32(ndr, "grpi3_next_index", r->grpi3_next_index);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_SHARE_INFO_1005_FLAGS(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_SHARE_INFO_1005_FLAGS(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_SHARE_INFO_1005_FLAGS(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SHI1005_FLAGS_DFS", SHI1005_FLAGS_DFS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SHI1005_FLAGS_DFS_ROOT", SHI1005_FLAGS_DFS_ROOT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "CSC_CACHE_MANUAL_REINT", CSC_CACHE_MANUAL_REINT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "CSC_CACHE_AUTO_REINT", CSC_CACHE_AUTO_REINT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "CSC_CACHE_VDO", CSC_CACHE_VDO, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "CSC_CACHE_NONE", CSC_CACHE_NONE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS", SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SHI1005_FLAGS_FORCE_SHARED_DELETE", SHI1005_FLAGS_FORCE_SHARED_DELETE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING", SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM", SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM, r);
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetJoinDomain(struct ndr_print *ndr, const char *name, int flags, const struct NetJoinDomain *r)
+{
+ ndr_print_struct(ndr, name, "NetJoinDomain");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetJoinDomain");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server", r->in.server);
+ ndr->depth++;
+ if (r->in.server) {
+ ndr_print_string(ndr, "server", r->in.server);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain", r->in.domain);
+ ndr->depth++;
+ ndr_print_string(ndr, "domain", r->in.domain);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "account_ou", r->in.account_ou);
+ ndr->depth++;
+ if (r->in.account_ou) {
+ ndr_print_string(ndr, "account_ou", r->in.account_ou);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "account", r->in.account);
+ ndr->depth++;
+ if (r->in.account) {
+ ndr_print_string(ndr, "account", r->in.account);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->in.password);
+ ndr->depth++;
+ if (r->in.password) {
+ ndr_print_string(ndr, "password", r->in.password);
+ }
+ ndr->depth--;
+ ndr_print_NetJoinFlags(ndr, "join_flags", r->in.join_flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetJoinDomain");
+ ndr->depth++;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetUnjoinDomain(struct ndr_print *ndr, const char *name, int flags, const struct NetUnjoinDomain *r)
+{
+ ndr_print_struct(ndr, name, "NetUnjoinDomain");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetUnjoinDomain");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "account", r->in.account);
+ ndr->depth++;
+ if (r->in.account) {
+ ndr_print_string(ndr, "account", r->in.account);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->in.password);
+ ndr->depth++;
+ if (r->in.password) {
+ ndr_print_string(ndr, "password", r->in.password);
+ }
+ ndr->depth--;
+ ndr_print_NetJoinFlags(ndr, "unjoin_flags", r->in.unjoin_flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetUnjoinDomain");
+ ndr->depth++;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetGetJoinInformation(struct ndr_print *ndr, const char *name, int flags, const struct NetGetJoinInformation *r)
+{
+ ndr_print_struct(ndr, name, "NetGetJoinInformation");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetGetJoinInformation");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetGetJoinInformation");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "name_buffer", r->out.name_buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "name_buffer", *r->out.name_buffer);
+ ndr->depth++;
+ if (*r->out.name_buffer) {
+ ndr_print_string(ndr, "name_buffer", *r->out.name_buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "name_type", r->out.name_type);
+ ndr->depth++;
+ ndr_print_uint16(ndr, "name_type", *r->out.name_type);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetGetJoinableOUs(struct ndr_print *ndr, const char *name, int flags, const struct NetGetJoinableOUs *r)
+{
+ ndr_print_struct(ndr, name, "NetGetJoinableOUs");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetGetJoinableOUs");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain", r->in.domain);
+ ndr->depth++;
+ ndr_print_string(ndr, "domain", r->in.domain);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "account", r->in.account);
+ ndr->depth++;
+ if (r->in.account) {
+ ndr_print_string(ndr, "account", r->in.account);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->in.password);
+ ndr->depth++;
+ if (r->in.password) {
+ ndr_print_string(ndr, "password", r->in.password);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetGetJoinableOUs");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "ou_count", r->out.ou_count);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "ou_count", *r->out.ou_count);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ous", r->out.ous);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "ous", *r->out.ous);
+ ndr->depth++;
+ if (*r->out.ous) {
+ ndr_print_ptr(ndr, "ous", **r->out.ous);
+ ndr->depth++;
+ if (**r->out.ous) {
+ ndr_print_string(ndr, "ous", **r->out.ous);
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetRenameMachineInDomain(struct ndr_print *ndr, const char *name, int flags, const struct NetRenameMachineInDomain *r)
+{
+ ndr_print_struct(ndr, name, "NetRenameMachineInDomain");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetRenameMachineInDomain");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "new_machine_name", r->in.new_machine_name);
+ ndr_print_string(ndr, "account", r->in.account);
+ ndr_print_string(ndr, "password", r->in.password);
+ ndr_print_uint32(ndr, "rename_options", r->in.rename_options);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetRenameMachineInDomain");
+ ndr->depth++;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetServerGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetServerGetInfo *r)
+{
+ ndr_print_struct(ndr, name, "NetServerGetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetServerGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetServerGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetServerSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetServerSetInfo *r)
+{
+ ndr_print_struct(ndr, name, "NetServerSetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetServerSetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "buffer", *r->in.buffer);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetServerSetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_error", r->out.parm_error);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "parm_error", *r->out.parm_error);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetGetDCName(struct ndr_print *ndr, const char *name, int flags, const struct NetGetDCName *r)
+{
+ ndr_print_struct(ndr, name, "NetGetDCName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetGetDCName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_name", r->in.domain_name);
+ ndr->depth++;
+ if (r->in.domain_name) {
+ ndr_print_string(ndr, "domain_name", r->in.domain_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetGetDCName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetGetAnyDCName(struct ndr_print *ndr, const char *name, int flags, const struct NetGetAnyDCName *r)
+{
+ ndr_print_struct(ndr, name, "NetGetAnyDCName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetGetAnyDCName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_name", r->in.domain_name);
+ ndr->depth++;
+ if (r->in.domain_name) {
+ ndr_print_string(ndr, "domain_name", r->in.domain_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetGetAnyDCName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_DsGetDcName(struct ndr_print *ndr, const char *name, int flags, const struct DsGetDcName *r)
+{
+ ndr_print_struct(ndr, name, "DsGetDcName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "DsGetDcName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_name", r->in.domain_name);
+ ndr->depth++;
+ ndr_print_string(ndr, "domain_name", r->in.domain_name);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_guid", r->in.domain_guid);
+ ndr->depth++;
+ if (r->in.domain_guid) {
+ ndr_print_GUID(ndr, "domain_guid", r->in.domain_guid);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "site_name", r->in.site_name);
+ ndr->depth++;
+ if (r->in.site_name) {
+ ndr_print_string(ndr, "site_name", r->in.site_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "DsGetDcName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "dc_info", r->out.dc_info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "dc_info", *r->out.dc_info);
+ ndr->depth++;
+ if (*r->out.dc_info) {
+ ndr_print_DOMAIN_CONTROLLER_INFO(ndr, "dc_info", *r->out.dc_info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetUserAdd(struct ndr_print *ndr, const char *name, int flags, const struct NetUserAdd *r)
+{
+ ndr_print_struct(ndr, name, "NetUserAdd");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetUserAdd");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "buffer", *r->in.buffer);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetUserAdd");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_error", r->out.parm_error);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "parm_error", *r->out.parm_error);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetUserDel(struct ndr_print *ndr, const char *name, int flags, const struct NetUserDel *r)
+{
+ ndr_print_struct(ndr, name, "NetUserDel");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetUserDel");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "user_name", r->in.user_name);
+ ndr->depth++;
+ ndr_print_string(ndr, "user_name", r->in.user_name);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetUserDel");
+ ndr->depth++;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetUserEnum(struct ndr_print *ndr, const char *name, int flags, const struct NetUserEnum *r)
+{
+ ndr_print_struct(ndr, name, "NetUserEnum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetUserEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "filter", r->in.filter);
+ ndr_print_uint32(ndr, "prefmaxlen", r->in.prefmaxlen);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetUserEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "entries_read", r->out.entries_read);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "entries_read", *r->out.entries_read);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "total_entries", r->out.total_entries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "total_entries", *r->out.total_entries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetUserChangePassword(struct ndr_print *ndr, const char *name, int flags, const struct NetUserChangePassword *r)
+{
+ ndr_print_struct(ndr, name, "NetUserChangePassword");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetUserChangePassword");
+ ndr->depth++;
+ ndr_print_string(ndr, "domain_name", r->in.domain_name);
+ ndr_print_string(ndr, "user_name", r->in.user_name);
+ ndr_print_string(ndr, "old_password", r->in.old_password);
+ ndr_print_string(ndr, "new_password", r->in.new_password);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetUserChangePassword");
+ ndr->depth++;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetUserGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetUserGetInfo *r)
+{
+ ndr_print_struct(ndr, name, "NetUserGetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetUserGetInfo");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "user_name", r->in.user_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetUserGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetUserSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetUserSetInfo *r)
+{
+ ndr_print_struct(ndr, name, "NetUserSetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetUserSetInfo");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "user_name", r->in.user_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "buffer", *r->in.buffer);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetUserSetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_err", r->out.parm_err);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "parm_err", *r->out.parm_err);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetUserGetGroups(struct ndr_print *ndr, const char *name, int flags, const struct NetUserGetGroups *r)
+{
+ ndr_print_struct(ndr, name, "NetUserGetGroups");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetUserGetGroups");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "user_name", r->in.user_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "prefmaxlen", r->in.prefmaxlen);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetUserGetGroups");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "entries_read", r->out.entries_read);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "entries_read", *r->out.entries_read);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "total_entries", r->out.total_entries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "total_entries", *r->out.total_entries);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetUserSetGroups(struct ndr_print *ndr, const char *name, int flags, const struct NetUserSetGroups *r)
+{
+ ndr_print_struct(ndr, name, "NetUserSetGroups");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetUserSetGroups");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "user_name", r->in.user_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "buffer", *r->in.buffer);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "num_entries", r->in.num_entries);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetUserSetGroups");
+ ndr->depth++;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetUserGetLocalGroups(struct ndr_print *ndr, const char *name, int flags, const struct NetUserGetLocalGroups *r)
+{
+ ndr_print_struct(ndr, name, "NetUserGetLocalGroups");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetUserGetLocalGroups");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "user_name", r->in.user_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr_print_uint32(ndr, "prefmaxlen", r->in.prefmaxlen);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetUserGetLocalGroups");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "entries_read", r->out.entries_read);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "entries_read", *r->out.entries_read);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "total_entries", r->out.total_entries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "total_entries", *r->out.total_entries);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetUserModalsGet(struct ndr_print *ndr, const char *name, int flags, const struct NetUserModalsGet *r)
+{
+ ndr_print_struct(ndr, name, "NetUserModalsGet");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetUserModalsGet");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetUserModalsGet");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetUserModalsSet(struct ndr_print *ndr, const char *name, int flags, const struct NetUserModalsSet *r)
+{
+ ndr_print_struct(ndr, name, "NetUserModalsSet");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetUserModalsSet");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "buffer", *r->in.buffer);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetUserModalsSet");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_err", r->out.parm_err);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "parm_err", *r->out.parm_err);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetQueryDisplayInformation(struct ndr_print *ndr, const char *name, int flags, const struct NetQueryDisplayInformation *r)
+{
+ ndr_print_struct(ndr, name, "NetQueryDisplayInformation");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetQueryDisplayInformation");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "idx", r->in.idx);
+ ndr_print_uint32(ndr, "entries_requested", r->in.entries_requested);
+ ndr_print_uint32(ndr, "prefmaxlen", r->in.prefmaxlen);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetQueryDisplayInformation");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "entries_read", r->out.entries_read);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "entries_read", *r->out.entries_read);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetGroupAdd(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupAdd *r)
+{
+ ndr_print_struct(ndr, name, "NetGroupAdd");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetGroupAdd");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "buffer", *r->in.buffer);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetGroupAdd");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_err", r->out.parm_err);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "parm_err", *r->out.parm_err);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetGroupDel(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupDel *r)
+{
+ ndr_print_struct(ndr, name, "NetGroupDel");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetGroupDel");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "group_name", r->in.group_name);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetGroupDel");
+ ndr->depth++;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetGroupEnum(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupEnum *r)
+{
+ ndr_print_struct(ndr, name, "NetGroupEnum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetGroupEnum");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "prefmaxlen", r->in.prefmaxlen);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetGroupEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "entries_read", r->out.entries_read);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "entries_read", *r->out.entries_read);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "total_entries", r->out.total_entries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "total_entries", *r->out.total_entries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetGroupSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupSetInfo *r)
+{
+ ndr_print_struct(ndr, name, "NetGroupSetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetGroupSetInfo");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "group_name", r->in.group_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "buffer", *r->in.buffer);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetGroupSetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_err", r->out.parm_err);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "parm_err", *r->out.parm_err);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetGroupGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupGetInfo *r)
+{
+ ndr_print_struct(ndr, name, "NetGroupGetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetGroupGetInfo");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "group_name", r->in.group_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetGroupGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetGroupAddUser(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupAddUser *r)
+{
+ ndr_print_struct(ndr, name, "NetGroupAddUser");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetGroupAddUser");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "group_name", r->in.group_name);
+ ndr_print_string(ndr, "user_name", r->in.user_name);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetGroupAddUser");
+ ndr->depth++;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetGroupDelUser(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupDelUser *r)
+{
+ ndr_print_struct(ndr, name, "NetGroupDelUser");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetGroupDelUser");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "group_name", r->in.group_name);
+ ndr_print_string(ndr, "user_name", r->in.user_name);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetGroupDelUser");
+ ndr->depth++;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetGroupGetUsers(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupGetUsers *r)
+{
+ ndr_print_struct(ndr, name, "NetGroupGetUsers");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetGroupGetUsers");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "group_name", r->in.group_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "prefmaxlen", r->in.prefmaxlen);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetGroupGetUsers");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "entries_read", r->out.entries_read);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "entries_read", *r->out.entries_read);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "total_entries", r->out.total_entries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "total_entries", *r->out.total_entries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetGroupSetUsers(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupSetUsers *r)
+{
+ ndr_print_struct(ndr, name, "NetGroupSetUsers");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetGroupSetUsers");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "group_name", r->in.group_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "buffer", *r->in.buffer);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "num_entries", r->in.num_entries);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetGroupSetUsers");
+ ndr->depth++;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetLocalGroupAdd(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupAdd *r)
+{
+ ndr_print_struct(ndr, name, "NetLocalGroupAdd");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetLocalGroupAdd");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "buffer", *r->in.buffer);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetLocalGroupAdd");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_err", r->out.parm_err);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "parm_err", *r->out.parm_err);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetLocalGroupDel(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupDel *r)
+{
+ ndr_print_struct(ndr, name, "NetLocalGroupDel");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetLocalGroupDel");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "group_name", r->in.group_name);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetLocalGroupDel");
+ ndr->depth++;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetLocalGroupGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupGetInfo *r)
+{
+ ndr_print_struct(ndr, name, "NetLocalGroupGetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetLocalGroupGetInfo");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "group_name", r->in.group_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetLocalGroupGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetLocalGroupSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupSetInfo *r)
+{
+ ndr_print_struct(ndr, name, "NetLocalGroupSetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetLocalGroupSetInfo");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "group_name", r->in.group_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "buffer", *r->in.buffer);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetLocalGroupSetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_err", r->out.parm_err);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "parm_err", *r->out.parm_err);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetLocalGroupEnum(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupEnum *r)
+{
+ ndr_print_struct(ndr, name, "NetLocalGroupEnum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetLocalGroupEnum");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "prefmaxlen", r->in.prefmaxlen);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetLocalGroupEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "entries_read", r->out.entries_read);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "entries_read", *r->out.entries_read);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "total_entries", r->out.total_entries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "total_entries", *r->out.total_entries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetLocalGroupAddMembers(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupAddMembers *r)
+{
+ ndr_print_struct(ndr, name, "NetLocalGroupAddMembers");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetLocalGroupAddMembers");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "group_name", r->in.group_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "buffer", *r->in.buffer);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "total_entries", r->in.total_entries);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetLocalGroupAddMembers");
+ ndr->depth++;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetLocalGroupDelMembers(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupDelMembers *r)
+{
+ ndr_print_struct(ndr, name, "NetLocalGroupDelMembers");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetLocalGroupDelMembers");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "group_name", r->in.group_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "buffer", *r->in.buffer);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "total_entries", r->in.total_entries);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetLocalGroupDelMembers");
+ ndr->depth++;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetLocalGroupGetMembers(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupGetMembers *r)
+{
+ ndr_print_struct(ndr, name, "NetLocalGroupGetMembers");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetLocalGroupGetMembers");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "local_group_name", r->in.local_group_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "prefmaxlen", r->in.prefmaxlen);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetLocalGroupGetMembers");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "entries_read", r->out.entries_read);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "entries_read", *r->out.entries_read);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "total_entries", r->out.total_entries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "total_entries", *r->out.total_entries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetLocalGroupSetMembers(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupSetMembers *r)
+{
+ ndr_print_struct(ndr, name, "NetLocalGroupSetMembers");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetLocalGroupSetMembers");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "group_name", r->in.group_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "buffer", *r->in.buffer);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "total_entries", r->in.total_entries);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetLocalGroupSetMembers");
+ ndr->depth++;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetRemoteTOD(struct ndr_print *ndr, const char *name, int flags, const struct NetRemoteTOD *r)
+{
+ ndr_print_struct(ndr, name, "NetRemoteTOD");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetRemoteTOD");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetRemoteTOD");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetShareAdd(struct ndr_print *ndr, const char *name, int flags, const struct NetShareAdd *r)
+{
+ ndr_print_struct(ndr, name, "NetShareAdd");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetShareAdd");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "buffer", *r->in.buffer);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetShareAdd");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_err", r->out.parm_err);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "parm_err", *r->out.parm_err);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetShareDel(struct ndr_print *ndr, const char *name, int flags, const struct NetShareDel *r)
+{
+ ndr_print_struct(ndr, name, "NetShareDel");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetShareDel");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "net_name", r->in.net_name);
+ ndr_print_uint32(ndr, "reserved", r->in.reserved);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetShareDel");
+ ndr->depth++;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetShareEnum(struct ndr_print *ndr, const char *name, int flags, const struct NetShareEnum *r)
+{
+ ndr_print_struct(ndr, name, "NetShareEnum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetShareEnum");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "prefmaxlen", r->in.prefmaxlen);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetShareEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "entries_read", r->out.entries_read);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "entries_read", *r->out.entries_read);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "total_entries", r->out.total_entries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "total_entries", *r->out.total_entries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetShareGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetShareGetInfo *r)
+{
+ ndr_print_struct(ndr, name, "NetShareGetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetShareGetInfo");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "net_name", r->in.net_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetShareGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetShareSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetShareSetInfo *r)
+{
+ ndr_print_struct(ndr, name, "NetShareSetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetShareSetInfo");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "net_name", r->in.net_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "buffer", *r->in.buffer);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetShareSetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_err", r->out.parm_err);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "parm_err", *r->out.parm_err);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetFileClose(struct ndr_print *ndr, const char *name, int flags, const struct NetFileClose *r)
+{
+ ndr_print_struct(ndr, name, "NetFileClose");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetFileClose");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_uint32(ndr, "fileid", r->in.fileid);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetFileClose");
+ ndr->depth++;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetFileGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetFileGetInfo *r)
+{
+ ndr_print_struct(ndr, name, "NetFileGetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetFileGetInfo");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_uint32(ndr, "fileid", r->in.fileid);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetFileGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_NetFileEnum(struct ndr_print *ndr, const char *name, int flags, const struct NetFileEnum *r)
+{
+ ndr_print_struct(ndr, name, "NetFileEnum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "NetFileEnum");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_string(ndr, "base_path", r->in.base_path);
+ ndr_print_string(ndr, "user_name", r->in.user_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "prefmaxlen", r->in.prefmaxlen);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "NetFileEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", *r->out.buffer);
+ ndr->depth++;
+ if (*r->out.buffer) {
+ ndr_print_uint8(ndr, "buffer", **r->out.buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "entries_read", r->out.entries_read);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "entries_read", *r->out.entries_read);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "total_entries", r->out.total_entries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "total_entries", *r->out.total_entries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ ndr->depth--;
+ ndr_print_NET_API_STATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
diff --git a/source3/librpc/gen_ndr/ndr_libnetapi.h b/source3/librpc/gen_ndr/ndr_libnetapi.h
new file mode 100644
index 0000000000..d8e8e399b2
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_libnetapi.h
@@ -0,0 +1,393 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/libnetapi.h"
+
+#ifndef _HEADER_NDR_libnetapi
+#define _HEADER_NDR_libnetapi
+
+#define NDR_NETJOINDOMAIN (0x00)
+
+#define NDR_NETUNJOINDOMAIN (0x01)
+
+#define NDR_NETGETJOININFORMATION (0x02)
+
+#define NDR_NETGETJOINABLEOUS (0x03)
+
+#define NDR_NETRENAMEMACHINEINDOMAIN (0x04)
+
+#define NDR_NETSERVERGETINFO (0x05)
+
+#define NDR_NETSERVERSETINFO (0x06)
+
+#define NDR_NETGETDCNAME (0x07)
+
+#define NDR_NETGETANYDCNAME (0x08)
+
+#define NDR_DSGETDCNAME (0x09)
+
+#define NDR_NETUSERADD (0x0a)
+
+#define NDR_NETUSERDEL (0x0b)
+
+#define NDR_NETUSERENUM (0x0c)
+
+#define NDR_NETUSERCHANGEPASSWORD (0x0d)
+
+#define NDR_NETUSERGETINFO (0x0e)
+
+#define NDR_NETUSERSETINFO (0x0f)
+
+#define NDR_NETUSERGETGROUPS (0x10)
+
+#define NDR_NETUSERSETGROUPS (0x11)
+
+#define NDR_NETUSERGETLOCALGROUPS (0x12)
+
+#define NDR_NETUSERMODALSGET (0x13)
+
+#define NDR_NETUSERMODALSSET (0x14)
+
+#define NDR_NETQUERYDISPLAYINFORMATION (0x15)
+
+#define NDR_NETGROUPADD (0x16)
+
+#define NDR_NETGROUPDEL (0x17)
+
+#define NDR_NETGROUPENUM (0x18)
+
+#define NDR_NETGROUPSETINFO (0x19)
+
+#define NDR_NETGROUPGETINFO (0x1a)
+
+#define NDR_NETGROUPADDUSER (0x1b)
+
+#define NDR_NETGROUPDELUSER (0x1c)
+
+#define NDR_NETGROUPGETUSERS (0x1d)
+
+#define NDR_NETGROUPSETUSERS (0x1e)
+
+#define NDR_NETLOCALGROUPADD (0x1f)
+
+#define NDR_NETLOCALGROUPDEL (0x20)
+
+#define NDR_NETLOCALGROUPGETINFO (0x21)
+
+#define NDR_NETLOCALGROUPSETINFO (0x22)
+
+#define NDR_NETLOCALGROUPENUM (0x23)
+
+#define NDR_NETLOCALGROUPADDMEMBERS (0x24)
+
+#define NDR_NETLOCALGROUPDELMEMBERS (0x25)
+
+#define NDR_NETLOCALGROUPGETMEMBERS (0x26)
+
+#define NDR_NETLOCALGROUPSETMEMBERS (0x27)
+
+#define NDR_NETREMOTETOD (0x28)
+
+#define NDR_NETSHAREADD (0x29)
+
+#define NDR_NETSHAREDEL (0x2a)
+
+#define NDR_NETSHAREENUM (0x2b)
+
+#define NDR_NETSHAREGETINFO (0x2c)
+
+#define NDR_NETSHARESETINFO (0x2d)
+
+#define NDR_NETFILECLOSE (0x2e)
+
+#define NDR_NETFILEGETINFO (0x2f)
+
+#define NDR_NETFILEENUM (0x30)
+
+#define NDR_LIBNETAPI_CALL_COUNT (49)
+enum ndr_err_code ndr_push_NET_API_STATUS(struct ndr_push *ndr, int ndr_flags, enum NET_API_STATUS r);
+enum ndr_err_code ndr_pull_NET_API_STATUS(struct ndr_pull *ndr, int ndr_flags, enum NET_API_STATUS *r);
+void ndr_print_NET_API_STATUS(struct ndr_print *ndr, const char *name, enum NET_API_STATUS r);
+enum ndr_err_code ndr_push_domsid(struct ndr_push *ndr, int ndr_flags, const struct domsid *r);
+enum ndr_err_code ndr_pull_domsid(struct ndr_pull *ndr, int ndr_flags, struct domsid *r);
+void ndr_print_domsid(struct ndr_print *ndr, const char *name, const struct domsid *r);
+enum ndr_err_code ndr_push_NetJoinFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_NetJoinFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_NetJoinFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+enum ndr_err_code ndr_push_SERVER_INFO_100(struct ndr_push *ndr, int ndr_flags, const struct SERVER_INFO_100 *r);
+enum ndr_err_code ndr_pull_SERVER_INFO_100(struct ndr_pull *ndr, int ndr_flags, struct SERVER_INFO_100 *r);
+void ndr_print_SERVER_INFO_100(struct ndr_print *ndr, const char *name, const struct SERVER_INFO_100 *r);
+enum ndr_err_code ndr_push_SERVER_INFO_101(struct ndr_push *ndr, int ndr_flags, const struct SERVER_INFO_101 *r);
+enum ndr_err_code ndr_pull_SERVER_INFO_101(struct ndr_pull *ndr, int ndr_flags, struct SERVER_INFO_101 *r);
+void ndr_print_SERVER_INFO_101(struct ndr_print *ndr, const char *name, const struct SERVER_INFO_101 *r);
+enum ndr_err_code ndr_push_SERVER_INFO_102(struct ndr_push *ndr, int ndr_flags, const struct SERVER_INFO_102 *r);
+enum ndr_err_code ndr_pull_SERVER_INFO_102(struct ndr_pull *ndr, int ndr_flags, struct SERVER_INFO_102 *r);
+void ndr_print_SERVER_INFO_102(struct ndr_print *ndr, const char *name, const struct SERVER_INFO_102 *r);
+enum ndr_err_code ndr_push_SERVER_INFO_1005(struct ndr_push *ndr, int ndr_flags, const struct SERVER_INFO_1005 *r);
+enum ndr_err_code ndr_pull_SERVER_INFO_1005(struct ndr_pull *ndr, int ndr_flags, struct SERVER_INFO_1005 *r);
+void ndr_print_SERVER_INFO_1005(struct ndr_print *ndr, const char *name, const struct SERVER_INFO_1005 *r);
+enum ndr_err_code ndr_push_DOMAIN_CONTROLLER_INFO(struct ndr_push *ndr, int ndr_flags, const struct DOMAIN_CONTROLLER_INFO *r);
+enum ndr_err_code ndr_pull_DOMAIN_CONTROLLER_INFO(struct ndr_pull *ndr, int ndr_flags, struct DOMAIN_CONTROLLER_INFO *r);
+void ndr_print_DOMAIN_CONTROLLER_INFO(struct ndr_print *ndr, const char *name, const struct DOMAIN_CONTROLLER_INFO *r);
+enum ndr_err_code ndr_push_USER_INFO_0(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_0 *r);
+enum ndr_err_code ndr_pull_USER_INFO_0(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_0 *r);
+void ndr_print_USER_INFO_0(struct ndr_print *ndr, const char *name, const struct USER_INFO_0 *r);
+enum ndr_err_code ndr_push_USER_INFO_1(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1 *r);
+void ndr_print_USER_INFO_1(struct ndr_print *ndr, const char *name, const struct USER_INFO_1 *r);
+enum ndr_err_code ndr_push_USER_INFO_2(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_2 *r);
+enum ndr_err_code ndr_pull_USER_INFO_2(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_2 *r);
+void ndr_print_USER_INFO_2(struct ndr_print *ndr, const char *name, const struct USER_INFO_2 *r);
+enum ndr_err_code ndr_push_USER_INFO_3(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_3 *r);
+enum ndr_err_code ndr_pull_USER_INFO_3(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_3 *r);
+void ndr_print_USER_INFO_3(struct ndr_print *ndr, const char *name, const struct USER_INFO_3 *r);
+enum ndr_err_code ndr_push_USER_INFO_4(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_4 *r);
+enum ndr_err_code ndr_pull_USER_INFO_4(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_4 *r);
+void ndr_print_USER_INFO_4(struct ndr_print *ndr, const char *name, const struct USER_INFO_4 *r);
+enum ndr_err_code ndr_push_USER_INFO_10(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_10 *r);
+enum ndr_err_code ndr_pull_USER_INFO_10(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_10 *r);
+void ndr_print_USER_INFO_10(struct ndr_print *ndr, const char *name, const struct USER_INFO_10 *r);
+enum ndr_err_code ndr_push_USER_INFO_11(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_11 *r);
+enum ndr_err_code ndr_pull_USER_INFO_11(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_11 *r);
+void ndr_print_USER_INFO_11(struct ndr_print *ndr, const char *name, const struct USER_INFO_11 *r);
+enum ndr_err_code ndr_push_USER_INFO_20(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_20 *r);
+enum ndr_err_code ndr_pull_USER_INFO_20(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_20 *r);
+void ndr_print_USER_INFO_20(struct ndr_print *ndr, const char *name, const struct USER_INFO_20 *r);
+enum ndr_err_code ndr_push_USER_INFO_21(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_21 *r);
+enum ndr_err_code ndr_pull_USER_INFO_21(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_21 *r);
+void ndr_print_USER_INFO_21(struct ndr_print *ndr, const char *name, const struct USER_INFO_21 *r);
+enum ndr_err_code ndr_push_USER_INFO_22(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_22 *r);
+enum ndr_err_code ndr_pull_USER_INFO_22(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_22 *r);
+void ndr_print_USER_INFO_22(struct ndr_print *ndr, const char *name, const struct USER_INFO_22 *r);
+enum ndr_err_code ndr_push_USER_INFO_23(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_23 *r);
+enum ndr_err_code ndr_pull_USER_INFO_23(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_23 *r);
+void ndr_print_USER_INFO_23(struct ndr_print *ndr, const char *name, const struct USER_INFO_23 *r);
+enum ndr_err_code ndr_push_USER_INFO_1003(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1003 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1003(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1003 *r);
+void ndr_print_USER_INFO_1003(struct ndr_print *ndr, const char *name, const struct USER_INFO_1003 *r);
+enum ndr_err_code ndr_push_USER_INFO_1005(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1005 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1005(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1005 *r);
+void ndr_print_USER_INFO_1005(struct ndr_print *ndr, const char *name, const struct USER_INFO_1005 *r);
+enum ndr_err_code ndr_push_USER_INFO_1006(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1006 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1006(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1006 *r);
+void ndr_print_USER_INFO_1006(struct ndr_print *ndr, const char *name, const struct USER_INFO_1006 *r);
+enum ndr_err_code ndr_push_USER_INFO_1007(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1007 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1007(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1007 *r);
+void ndr_print_USER_INFO_1007(struct ndr_print *ndr, const char *name, const struct USER_INFO_1007 *r);
+enum ndr_err_code ndr_push_USER_INFO_1008(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1008 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1008(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1008 *r);
+void ndr_print_USER_INFO_1008(struct ndr_print *ndr, const char *name, const struct USER_INFO_1008 *r);
+enum ndr_err_code ndr_push_USER_INFO_1009(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1009 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1009(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1009 *r);
+void ndr_print_USER_INFO_1009(struct ndr_print *ndr, const char *name, const struct USER_INFO_1009 *r);
+enum ndr_err_code ndr_push_USER_INFO_1010(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1010 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1010(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1010 *r);
+void ndr_print_USER_INFO_1010(struct ndr_print *ndr, const char *name, const struct USER_INFO_1010 *r);
+enum ndr_err_code ndr_push_USER_INFO_1011(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1011 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1011(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1011 *r);
+void ndr_print_USER_INFO_1011(struct ndr_print *ndr, const char *name, const struct USER_INFO_1011 *r);
+enum ndr_err_code ndr_push_USER_INFO_1012(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1012 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1012(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1012 *r);
+void ndr_print_USER_INFO_1012(struct ndr_print *ndr, const char *name, const struct USER_INFO_1012 *r);
+enum ndr_err_code ndr_push_USER_INFO_1013(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1013 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1013(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1013 *r);
+void ndr_print_USER_INFO_1013(struct ndr_print *ndr, const char *name, const struct USER_INFO_1013 *r);
+enum ndr_err_code ndr_push_USER_INFO_1014(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1014 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1014(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1014 *r);
+void ndr_print_USER_INFO_1014(struct ndr_print *ndr, const char *name, const struct USER_INFO_1014 *r);
+enum ndr_err_code ndr_push_USER_INFO_1017(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1017 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1017(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1017 *r);
+void ndr_print_USER_INFO_1017(struct ndr_print *ndr, const char *name, const struct USER_INFO_1017 *r);
+enum ndr_err_code ndr_push_USER_INFO_1018(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1018 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1018(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1018 *r);
+void ndr_print_USER_INFO_1018(struct ndr_print *ndr, const char *name, const struct USER_INFO_1018 *r);
+enum ndr_err_code ndr_push_USER_INFO_1020(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1020 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1020(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1020 *r);
+void ndr_print_USER_INFO_1020(struct ndr_print *ndr, const char *name, const struct USER_INFO_1020 *r);
+enum ndr_err_code ndr_push_USER_INFO_1023(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1023 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1023(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1023 *r);
+void ndr_print_USER_INFO_1023(struct ndr_print *ndr, const char *name, const struct USER_INFO_1023 *r);
+enum ndr_err_code ndr_push_USER_INFO_1024(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1024 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1024(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1024 *r);
+void ndr_print_USER_INFO_1024(struct ndr_print *ndr, const char *name, const struct USER_INFO_1024 *r);
+enum ndr_err_code ndr_push_USER_INFO_1025(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1025 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1025(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1025 *r);
+void ndr_print_USER_INFO_1025(struct ndr_print *ndr, const char *name, const struct USER_INFO_1025 *r);
+enum ndr_err_code ndr_push_USER_INFO_1051(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1051 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1051(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1051 *r);
+void ndr_print_USER_INFO_1051(struct ndr_print *ndr, const char *name, const struct USER_INFO_1051 *r);
+enum ndr_err_code ndr_push_USER_INFO_1052(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1052 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1052(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1052 *r);
+void ndr_print_USER_INFO_1052(struct ndr_print *ndr, const char *name, const struct USER_INFO_1052 *r);
+enum ndr_err_code ndr_push_USER_INFO_1053(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_1053 *r);
+enum ndr_err_code ndr_pull_USER_INFO_1053(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_1053 *r);
+void ndr_print_USER_INFO_1053(struct ndr_print *ndr, const char *name, const struct USER_INFO_1053 *r);
+enum ndr_err_code ndr_push_USER_INFO_X(struct ndr_push *ndr, int ndr_flags, const struct USER_INFO_X *r);
+enum ndr_err_code ndr_pull_USER_INFO_X(struct ndr_pull *ndr, int ndr_flags, struct USER_INFO_X *r);
+void ndr_print_USER_INFO_X(struct ndr_print *ndr, const char *name, const struct USER_INFO_X *r);
+enum ndr_err_code ndr_push_GROUP_USERS_INFO_0(struct ndr_push *ndr, int ndr_flags, const struct GROUP_USERS_INFO_0 *r);
+enum ndr_err_code ndr_pull_GROUP_USERS_INFO_0(struct ndr_pull *ndr, int ndr_flags, struct GROUP_USERS_INFO_0 *r);
+void ndr_print_GROUP_USERS_INFO_0(struct ndr_print *ndr, const char *name, const struct GROUP_USERS_INFO_0 *r);
+enum ndr_err_code ndr_push_GROUP_USERS_INFO_1(struct ndr_push *ndr, int ndr_flags, const struct GROUP_USERS_INFO_1 *r);
+enum ndr_err_code ndr_pull_GROUP_USERS_INFO_1(struct ndr_pull *ndr, int ndr_flags, struct GROUP_USERS_INFO_1 *r);
+void ndr_print_GROUP_USERS_INFO_1(struct ndr_print *ndr, const char *name, const struct GROUP_USERS_INFO_1 *r);
+enum ndr_err_code ndr_push_NET_DISPLAY_USER(struct ndr_push *ndr, int ndr_flags, const struct NET_DISPLAY_USER *r);
+enum ndr_err_code ndr_pull_NET_DISPLAY_USER(struct ndr_pull *ndr, int ndr_flags, struct NET_DISPLAY_USER *r);
+void ndr_print_NET_DISPLAY_USER(struct ndr_print *ndr, const char *name, const struct NET_DISPLAY_USER *r);
+enum ndr_err_code ndr_push_NET_DISPLAY_MACHINE(struct ndr_push *ndr, int ndr_flags, const struct NET_DISPLAY_MACHINE *r);
+enum ndr_err_code ndr_pull_NET_DISPLAY_MACHINE(struct ndr_pull *ndr, int ndr_flags, struct NET_DISPLAY_MACHINE *r);
+void ndr_print_NET_DISPLAY_MACHINE(struct ndr_print *ndr, const char *name, const struct NET_DISPLAY_MACHINE *r);
+enum ndr_err_code ndr_push_NET_DISPLAY_GROUP(struct ndr_push *ndr, int ndr_flags, const struct NET_DISPLAY_GROUP *r);
+enum ndr_err_code ndr_pull_NET_DISPLAY_GROUP(struct ndr_pull *ndr, int ndr_flags, struct NET_DISPLAY_GROUP *r);
+void ndr_print_NET_DISPLAY_GROUP(struct ndr_print *ndr, const char *name, const struct NET_DISPLAY_GROUP *r);
+enum ndr_err_code ndr_push_SHARE_INFO_1005_FLAGS(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_SHARE_INFO_1005_FLAGS(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_SHARE_INFO_1005_FLAGS(struct ndr_print *ndr, const char *name, uint32_t r);
+enum ndr_err_code ndr_push_NetJoinDomain(struct ndr_push *ndr, int flags, const struct NetJoinDomain *r);
+enum ndr_err_code ndr_pull_NetJoinDomain(struct ndr_pull *ndr, int flags, struct NetJoinDomain *r);
+void ndr_print_NetJoinDomain(struct ndr_print *ndr, const char *name, int flags, const struct NetJoinDomain *r);
+enum ndr_err_code ndr_push_NetUnjoinDomain(struct ndr_push *ndr, int flags, const struct NetUnjoinDomain *r);
+enum ndr_err_code ndr_pull_NetUnjoinDomain(struct ndr_pull *ndr, int flags, struct NetUnjoinDomain *r);
+void ndr_print_NetUnjoinDomain(struct ndr_print *ndr, const char *name, int flags, const struct NetUnjoinDomain *r);
+enum ndr_err_code ndr_push_NetGetJoinInformation(struct ndr_push *ndr, int flags, const struct NetGetJoinInformation *r);
+enum ndr_err_code ndr_pull_NetGetJoinInformation(struct ndr_pull *ndr, int flags, struct NetGetJoinInformation *r);
+void ndr_print_NetGetJoinInformation(struct ndr_print *ndr, const char *name, int flags, const struct NetGetJoinInformation *r);
+enum ndr_err_code ndr_push_NetGetJoinableOUs(struct ndr_push *ndr, int flags, const struct NetGetJoinableOUs *r);
+enum ndr_err_code ndr_pull_NetGetJoinableOUs(struct ndr_pull *ndr, int flags, struct NetGetJoinableOUs *r);
+void ndr_print_NetGetJoinableOUs(struct ndr_print *ndr, const char *name, int flags, const struct NetGetJoinableOUs *r);
+enum ndr_err_code ndr_push_NetRenameMachineInDomain(struct ndr_push *ndr, int flags, const struct NetRenameMachineInDomain *r);
+enum ndr_err_code ndr_pull_NetRenameMachineInDomain(struct ndr_pull *ndr, int flags, struct NetRenameMachineInDomain *r);
+void ndr_print_NetRenameMachineInDomain(struct ndr_print *ndr, const char *name, int flags, const struct NetRenameMachineInDomain *r);
+enum ndr_err_code ndr_push_NetServerGetInfo(struct ndr_push *ndr, int flags, const struct NetServerGetInfo *r);
+enum ndr_err_code ndr_pull_NetServerGetInfo(struct ndr_pull *ndr, int flags, struct NetServerGetInfo *r);
+void ndr_print_NetServerGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetServerGetInfo *r);
+enum ndr_err_code ndr_push_NetServerSetInfo(struct ndr_push *ndr, int flags, const struct NetServerSetInfo *r);
+enum ndr_err_code ndr_pull_NetServerSetInfo(struct ndr_pull *ndr, int flags, struct NetServerSetInfo *r);
+void ndr_print_NetServerSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetServerSetInfo *r);
+enum ndr_err_code ndr_push_NetGetDCName(struct ndr_push *ndr, int flags, const struct NetGetDCName *r);
+enum ndr_err_code ndr_pull_NetGetDCName(struct ndr_pull *ndr, int flags, struct NetGetDCName *r);
+void ndr_print_NetGetDCName(struct ndr_print *ndr, const char *name, int flags, const struct NetGetDCName *r);
+enum ndr_err_code ndr_push_NetGetAnyDCName(struct ndr_push *ndr, int flags, const struct NetGetAnyDCName *r);
+enum ndr_err_code ndr_pull_NetGetAnyDCName(struct ndr_pull *ndr, int flags, struct NetGetAnyDCName *r);
+void ndr_print_NetGetAnyDCName(struct ndr_print *ndr, const char *name, int flags, const struct NetGetAnyDCName *r);
+enum ndr_err_code ndr_push_DsGetDcName(struct ndr_push *ndr, int flags, const struct DsGetDcName *r);
+enum ndr_err_code ndr_pull_DsGetDcName(struct ndr_pull *ndr, int flags, struct DsGetDcName *r);
+void ndr_print_DsGetDcName(struct ndr_print *ndr, const char *name, int flags, const struct DsGetDcName *r);
+enum ndr_err_code ndr_push_NetUserAdd(struct ndr_push *ndr, int flags, const struct NetUserAdd *r);
+enum ndr_err_code ndr_pull_NetUserAdd(struct ndr_pull *ndr, int flags, struct NetUserAdd *r);
+void ndr_print_NetUserAdd(struct ndr_print *ndr, const char *name, int flags, const struct NetUserAdd *r);
+enum ndr_err_code ndr_push_NetUserDel(struct ndr_push *ndr, int flags, const struct NetUserDel *r);
+enum ndr_err_code ndr_pull_NetUserDel(struct ndr_pull *ndr, int flags, struct NetUserDel *r);
+void ndr_print_NetUserDel(struct ndr_print *ndr, const char *name, int flags, const struct NetUserDel *r);
+enum ndr_err_code ndr_push_NetUserEnum(struct ndr_push *ndr, int flags, const struct NetUserEnum *r);
+enum ndr_err_code ndr_pull_NetUserEnum(struct ndr_pull *ndr, int flags, struct NetUserEnum *r);
+void ndr_print_NetUserEnum(struct ndr_print *ndr, const char *name, int flags, const struct NetUserEnum *r);
+enum ndr_err_code ndr_push_NetUserChangePassword(struct ndr_push *ndr, int flags, const struct NetUserChangePassword *r);
+enum ndr_err_code ndr_pull_NetUserChangePassword(struct ndr_pull *ndr, int flags, struct NetUserChangePassword *r);
+void ndr_print_NetUserChangePassword(struct ndr_print *ndr, const char *name, int flags, const struct NetUserChangePassword *r);
+enum ndr_err_code ndr_push_NetUserGetInfo(struct ndr_push *ndr, int flags, const struct NetUserGetInfo *r);
+enum ndr_err_code ndr_pull_NetUserGetInfo(struct ndr_pull *ndr, int flags, struct NetUserGetInfo *r);
+void ndr_print_NetUserGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetUserGetInfo *r);
+enum ndr_err_code ndr_push_NetUserSetInfo(struct ndr_push *ndr, int flags, const struct NetUserSetInfo *r);
+enum ndr_err_code ndr_pull_NetUserSetInfo(struct ndr_pull *ndr, int flags, struct NetUserSetInfo *r);
+void ndr_print_NetUserSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetUserSetInfo *r);
+enum ndr_err_code ndr_push_NetUserGetGroups(struct ndr_push *ndr, int flags, const struct NetUserGetGroups *r);
+enum ndr_err_code ndr_pull_NetUserGetGroups(struct ndr_pull *ndr, int flags, struct NetUserGetGroups *r);
+void ndr_print_NetUserGetGroups(struct ndr_print *ndr, const char *name, int flags, const struct NetUserGetGroups *r);
+enum ndr_err_code ndr_push_NetUserSetGroups(struct ndr_push *ndr, int flags, const struct NetUserSetGroups *r);
+enum ndr_err_code ndr_pull_NetUserSetGroups(struct ndr_pull *ndr, int flags, struct NetUserSetGroups *r);
+void ndr_print_NetUserSetGroups(struct ndr_print *ndr, const char *name, int flags, const struct NetUserSetGroups *r);
+enum ndr_err_code ndr_push_NetUserGetLocalGroups(struct ndr_push *ndr, int flags, const struct NetUserGetLocalGroups *r);
+enum ndr_err_code ndr_pull_NetUserGetLocalGroups(struct ndr_pull *ndr, int flags, struct NetUserGetLocalGroups *r);
+void ndr_print_NetUserGetLocalGroups(struct ndr_print *ndr, const char *name, int flags, const struct NetUserGetLocalGroups *r);
+enum ndr_err_code ndr_push_NetUserModalsGet(struct ndr_push *ndr, int flags, const struct NetUserModalsGet *r);
+enum ndr_err_code ndr_pull_NetUserModalsGet(struct ndr_pull *ndr, int flags, struct NetUserModalsGet *r);
+void ndr_print_NetUserModalsGet(struct ndr_print *ndr, const char *name, int flags, const struct NetUserModalsGet *r);
+enum ndr_err_code ndr_push_NetUserModalsSet(struct ndr_push *ndr, int flags, const struct NetUserModalsSet *r);
+enum ndr_err_code ndr_pull_NetUserModalsSet(struct ndr_pull *ndr, int flags, struct NetUserModalsSet *r);
+void ndr_print_NetUserModalsSet(struct ndr_print *ndr, const char *name, int flags, const struct NetUserModalsSet *r);
+enum ndr_err_code ndr_push_NetQueryDisplayInformation(struct ndr_push *ndr, int flags, const struct NetQueryDisplayInformation *r);
+enum ndr_err_code ndr_pull_NetQueryDisplayInformation(struct ndr_pull *ndr, int flags, struct NetQueryDisplayInformation *r);
+void ndr_print_NetQueryDisplayInformation(struct ndr_print *ndr, const char *name, int flags, const struct NetQueryDisplayInformation *r);
+enum ndr_err_code ndr_push_NetGroupAdd(struct ndr_push *ndr, int flags, const struct NetGroupAdd *r);
+enum ndr_err_code ndr_pull_NetGroupAdd(struct ndr_pull *ndr, int flags, struct NetGroupAdd *r);
+void ndr_print_NetGroupAdd(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupAdd *r);
+enum ndr_err_code ndr_push_NetGroupDel(struct ndr_push *ndr, int flags, const struct NetGroupDel *r);
+enum ndr_err_code ndr_pull_NetGroupDel(struct ndr_pull *ndr, int flags, struct NetGroupDel *r);
+void ndr_print_NetGroupDel(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupDel *r);
+enum ndr_err_code ndr_push_NetGroupEnum(struct ndr_push *ndr, int flags, const struct NetGroupEnum *r);
+enum ndr_err_code ndr_pull_NetGroupEnum(struct ndr_pull *ndr, int flags, struct NetGroupEnum *r);
+void ndr_print_NetGroupEnum(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupEnum *r);
+enum ndr_err_code ndr_push_NetGroupSetInfo(struct ndr_push *ndr, int flags, const struct NetGroupSetInfo *r);
+enum ndr_err_code ndr_pull_NetGroupSetInfo(struct ndr_pull *ndr, int flags, struct NetGroupSetInfo *r);
+void ndr_print_NetGroupSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupSetInfo *r);
+enum ndr_err_code ndr_push_NetGroupGetInfo(struct ndr_push *ndr, int flags, const struct NetGroupGetInfo *r);
+enum ndr_err_code ndr_pull_NetGroupGetInfo(struct ndr_pull *ndr, int flags, struct NetGroupGetInfo *r);
+void ndr_print_NetGroupGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupGetInfo *r);
+enum ndr_err_code ndr_push_NetGroupAddUser(struct ndr_push *ndr, int flags, const struct NetGroupAddUser *r);
+enum ndr_err_code ndr_pull_NetGroupAddUser(struct ndr_pull *ndr, int flags, struct NetGroupAddUser *r);
+void ndr_print_NetGroupAddUser(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupAddUser *r);
+enum ndr_err_code ndr_push_NetGroupDelUser(struct ndr_push *ndr, int flags, const struct NetGroupDelUser *r);
+enum ndr_err_code ndr_pull_NetGroupDelUser(struct ndr_pull *ndr, int flags, struct NetGroupDelUser *r);
+void ndr_print_NetGroupDelUser(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupDelUser *r);
+enum ndr_err_code ndr_push_NetGroupGetUsers(struct ndr_push *ndr, int flags, const struct NetGroupGetUsers *r);
+enum ndr_err_code ndr_pull_NetGroupGetUsers(struct ndr_pull *ndr, int flags, struct NetGroupGetUsers *r);
+void ndr_print_NetGroupGetUsers(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupGetUsers *r);
+enum ndr_err_code ndr_push_NetGroupSetUsers(struct ndr_push *ndr, int flags, const struct NetGroupSetUsers *r);
+enum ndr_err_code ndr_pull_NetGroupSetUsers(struct ndr_pull *ndr, int flags, struct NetGroupSetUsers *r);
+void ndr_print_NetGroupSetUsers(struct ndr_print *ndr, const char *name, int flags, const struct NetGroupSetUsers *r);
+enum ndr_err_code ndr_push_NetLocalGroupAdd(struct ndr_push *ndr, int flags, const struct NetLocalGroupAdd *r);
+enum ndr_err_code ndr_pull_NetLocalGroupAdd(struct ndr_pull *ndr, int flags, struct NetLocalGroupAdd *r);
+void ndr_print_NetLocalGroupAdd(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupAdd *r);
+enum ndr_err_code ndr_push_NetLocalGroupDel(struct ndr_push *ndr, int flags, const struct NetLocalGroupDel *r);
+enum ndr_err_code ndr_pull_NetLocalGroupDel(struct ndr_pull *ndr, int flags, struct NetLocalGroupDel *r);
+void ndr_print_NetLocalGroupDel(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupDel *r);
+enum ndr_err_code ndr_push_NetLocalGroupGetInfo(struct ndr_push *ndr, int flags, const struct NetLocalGroupGetInfo *r);
+enum ndr_err_code ndr_pull_NetLocalGroupGetInfo(struct ndr_pull *ndr, int flags, struct NetLocalGroupGetInfo *r);
+void ndr_print_NetLocalGroupGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupGetInfo *r);
+enum ndr_err_code ndr_push_NetLocalGroupSetInfo(struct ndr_push *ndr, int flags, const struct NetLocalGroupSetInfo *r);
+enum ndr_err_code ndr_pull_NetLocalGroupSetInfo(struct ndr_pull *ndr, int flags, struct NetLocalGroupSetInfo *r);
+void ndr_print_NetLocalGroupSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupSetInfo *r);
+enum ndr_err_code ndr_push_NetLocalGroupEnum(struct ndr_push *ndr, int flags, const struct NetLocalGroupEnum *r);
+enum ndr_err_code ndr_pull_NetLocalGroupEnum(struct ndr_pull *ndr, int flags, struct NetLocalGroupEnum *r);
+void ndr_print_NetLocalGroupEnum(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupEnum *r);
+enum ndr_err_code ndr_push_NetLocalGroupAddMembers(struct ndr_push *ndr, int flags, const struct NetLocalGroupAddMembers *r);
+enum ndr_err_code ndr_pull_NetLocalGroupAddMembers(struct ndr_pull *ndr, int flags, struct NetLocalGroupAddMembers *r);
+void ndr_print_NetLocalGroupAddMembers(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupAddMembers *r);
+enum ndr_err_code ndr_push_NetLocalGroupDelMembers(struct ndr_push *ndr, int flags, const struct NetLocalGroupDelMembers *r);
+enum ndr_err_code ndr_pull_NetLocalGroupDelMembers(struct ndr_pull *ndr, int flags, struct NetLocalGroupDelMembers *r);
+void ndr_print_NetLocalGroupDelMembers(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupDelMembers *r);
+enum ndr_err_code ndr_push_NetLocalGroupGetMembers(struct ndr_push *ndr, int flags, const struct NetLocalGroupGetMembers *r);
+enum ndr_err_code ndr_pull_NetLocalGroupGetMembers(struct ndr_pull *ndr, int flags, struct NetLocalGroupGetMembers *r);
+void ndr_print_NetLocalGroupGetMembers(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupGetMembers *r);
+enum ndr_err_code ndr_push_NetLocalGroupSetMembers(struct ndr_push *ndr, int flags, const struct NetLocalGroupSetMembers *r);
+enum ndr_err_code ndr_pull_NetLocalGroupSetMembers(struct ndr_pull *ndr, int flags, struct NetLocalGroupSetMembers *r);
+void ndr_print_NetLocalGroupSetMembers(struct ndr_print *ndr, const char *name, int flags, const struct NetLocalGroupSetMembers *r);
+enum ndr_err_code ndr_push_NetRemoteTOD(struct ndr_push *ndr, int flags, const struct NetRemoteTOD *r);
+enum ndr_err_code ndr_pull_NetRemoteTOD(struct ndr_pull *ndr, int flags, struct NetRemoteTOD *r);
+void ndr_print_NetRemoteTOD(struct ndr_print *ndr, const char *name, int flags, const struct NetRemoteTOD *r);
+enum ndr_err_code ndr_push_NetShareAdd(struct ndr_push *ndr, int flags, const struct NetShareAdd *r);
+enum ndr_err_code ndr_pull_NetShareAdd(struct ndr_pull *ndr, int flags, struct NetShareAdd *r);
+void ndr_print_NetShareAdd(struct ndr_print *ndr, const char *name, int flags, const struct NetShareAdd *r);
+enum ndr_err_code ndr_push_NetShareDel(struct ndr_push *ndr, int flags, const struct NetShareDel *r);
+enum ndr_err_code ndr_pull_NetShareDel(struct ndr_pull *ndr, int flags, struct NetShareDel *r);
+void ndr_print_NetShareDel(struct ndr_print *ndr, const char *name, int flags, const struct NetShareDel *r);
+enum ndr_err_code ndr_push_NetShareEnum(struct ndr_push *ndr, int flags, const struct NetShareEnum *r);
+enum ndr_err_code ndr_pull_NetShareEnum(struct ndr_pull *ndr, int flags, struct NetShareEnum *r);
+void ndr_print_NetShareEnum(struct ndr_print *ndr, const char *name, int flags, const struct NetShareEnum *r);
+enum ndr_err_code ndr_push_NetShareGetInfo(struct ndr_push *ndr, int flags, const struct NetShareGetInfo *r);
+enum ndr_err_code ndr_pull_NetShareGetInfo(struct ndr_pull *ndr, int flags, struct NetShareGetInfo *r);
+void ndr_print_NetShareGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetShareGetInfo *r);
+enum ndr_err_code ndr_push_NetShareSetInfo(struct ndr_push *ndr, int flags, const struct NetShareSetInfo *r);
+enum ndr_err_code ndr_pull_NetShareSetInfo(struct ndr_pull *ndr, int flags, struct NetShareSetInfo *r);
+void ndr_print_NetShareSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetShareSetInfo *r);
+enum ndr_err_code ndr_push_NetFileClose(struct ndr_push *ndr, int flags, const struct NetFileClose *r);
+enum ndr_err_code ndr_pull_NetFileClose(struct ndr_pull *ndr, int flags, struct NetFileClose *r);
+void ndr_print_NetFileClose(struct ndr_print *ndr, const char *name, int flags, const struct NetFileClose *r);
+enum ndr_err_code ndr_push_NetFileGetInfo(struct ndr_push *ndr, int flags, const struct NetFileGetInfo *r);
+enum ndr_err_code ndr_pull_NetFileGetInfo(struct ndr_pull *ndr, int flags, struct NetFileGetInfo *r);
+void ndr_print_NetFileGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct NetFileGetInfo *r);
+enum ndr_err_code ndr_push_NetFileEnum(struct ndr_push *ndr, int flags, const struct NetFileEnum *r);
+enum ndr_err_code ndr_pull_NetFileEnum(struct ndr_pull *ndr, int flags, struct NetFileEnum *r);
+void ndr_print_NetFileEnum(struct ndr_print *ndr, const char *name, int flags, const struct NetFileEnum *r);
+#endif /* _HEADER_NDR_libnetapi */
diff --git a/source3/librpc/gen_ndr/ndr_lsa.c b/source3/librpc/gen_ndr/ndr_lsa.c
new file mode 100644
index 0000000000..f25410ad27
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_lsa.c
@@ -0,0 +1,12547 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_lsa.h"
+
+#include "librpc/gen_ndr/ndr_security.h"
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_String(struct ndr_push *ndr, int ndr_flags, const struct lsa_String *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 2 * strlen_m(r->string)));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 2 * strlen_m(r->string)));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->string));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->string) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 2 * strlen_m(r->string) / 2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 2 * strlen_m(r->string) / 2));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->string, 2 * strlen_m(r->string) / 2, sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_String(struct ndr_pull *ndr, int ndr_flags, struct lsa_String *r)
+{
+ uint32_t _ptr_string;
+ TALLOC_CTX *_mem_save_string_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_string));
+ if (_ptr_string) {
+ NDR_PULL_ALLOC(ndr, r->string);
+ } else {
+ r->string = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->string) {
+ _mem_save_string_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->string, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->string));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->string));
+ if (ndr_get_array_length(ndr, &r->string) > ndr_get_array_size(ndr, &r->string)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->string), ndr_get_array_length(ndr, &r->string));
+ }
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->string, ndr_get_array_length(ndr, &r->string), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_string_0, 0);
+ }
+ if (r->string) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->string, r->size / 2));
+ }
+ if (r->string) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->string, r->length / 2));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_String(struct ndr_print *ndr, const char *name, const struct lsa_String *r)
+{
+ ndr_print_struct(ndr, name, "lsa_String");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "length", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?2 * strlen_m(r->string):r->length);
+ ndr_print_uint16(ndr, "size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?2 * strlen_m(r->string):r->size);
+ ndr_print_ptr(ndr, "string", r->string);
+ ndr->depth++;
+ if (r->string) {
+ ndr_print_string(ndr, "string", r->string);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_StringLarge(struct ndr_push *ndr, int ndr_flags, const struct lsa_StringLarge *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 2 * strlen_m(r->string)));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 2 * strlen_m_term(r->string)));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->string));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->string) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 2 * strlen_m_term(r->string) / 2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 2 * strlen_m(r->string) / 2));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->string, 2 * strlen_m(r->string) / 2, sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_StringLarge(struct ndr_pull *ndr, int ndr_flags, struct lsa_StringLarge *r)
+{
+ uint32_t _ptr_string;
+ TALLOC_CTX *_mem_save_string_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_string));
+ if (_ptr_string) {
+ NDR_PULL_ALLOC(ndr, r->string);
+ } else {
+ r->string = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->string) {
+ _mem_save_string_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->string, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->string));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->string));
+ if (ndr_get_array_length(ndr, &r->string) > ndr_get_array_size(ndr, &r->string)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->string), ndr_get_array_length(ndr, &r->string));
+ }
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->string, ndr_get_array_length(ndr, &r->string), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_string_0, 0);
+ }
+ if (r->string) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->string, r->size / 2));
+ }
+ if (r->string) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->string, r->length / 2));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_StringLarge(struct ndr_print *ndr, const char *name, const struct lsa_StringLarge *r)
+{
+ ndr_print_struct(ndr, name, "lsa_StringLarge");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "length", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?2 * strlen_m(r->string):r->length);
+ ndr_print_uint16(ndr, "size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?2 * strlen_m_term(r->string):r->size);
+ ndr_print_ptr(ndr, "string", r->string);
+ ndr->depth++;
+ if (r->string) {
+ ndr_print_string(ndr, "string", r->string);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_Strings(struct ndr_push *ndr, int ndr_flags, const struct lsa_Strings *r)
+{
+ uint32_t cntr_names_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->names));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->names) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->names[cntr_names_1]));
+ }
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->names[cntr_names_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_Strings(struct ndr_pull *ndr, int ndr_flags, struct lsa_Strings *r)
+{
+ uint32_t _ptr_names;
+ uint32_t cntr_names_1;
+ TALLOC_CTX *_mem_save_names_0;
+ TALLOC_CTX *_mem_save_names_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_names));
+ if (_ptr_names) {
+ NDR_PULL_ALLOC(ndr, r->names);
+ } else {
+ r->names = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->names) {
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->names, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->names));
+ NDR_PULL_ALLOC_N(ndr, r->names, ndr_get_array_size(ndr, &r->names));
+ _mem_save_names_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->names, 0);
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->names[cntr_names_1]));
+ }
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->names[cntr_names_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, 0);
+ }
+ if (r->names) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->names, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_Strings(struct ndr_print *ndr, const char *name, const struct lsa_Strings *r)
+{
+ uint32_t cntr_names_1;
+ ndr_print_struct(ndr, name, "lsa_Strings");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "names", r->names);
+ ndr->depth++;
+ if (r->names) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "names", (int)r->count);
+ ndr->depth++;
+ for (cntr_names_1=0;cntr_names_1<r->count;cntr_names_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_names_1) != -1) {
+ ndr_print_lsa_String(ndr, "names", &r->names[cntr_names_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_AsciiString(struct ndr_push *ndr, int ndr_flags, const struct lsa_AsciiString *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, strlen_m(r->string)));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, strlen_m(r->string)));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->string));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->string) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, strlen_m(r->string)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, strlen_m(r->string)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->string, strlen_m(r->string), sizeof(uint8_t), CH_DOS));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_AsciiString(struct ndr_pull *ndr, int ndr_flags, struct lsa_AsciiString *r)
+{
+ uint32_t _ptr_string;
+ TALLOC_CTX *_mem_save_string_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_string));
+ if (_ptr_string) {
+ NDR_PULL_ALLOC(ndr, r->string);
+ } else {
+ r->string = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->string) {
+ _mem_save_string_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->string, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->string));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->string));
+ if (ndr_get_array_length(ndr, &r->string) > ndr_get_array_size(ndr, &r->string)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->string), ndr_get_array_length(ndr, &r->string));
+ }
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->string, ndr_get_array_length(ndr, &r->string), sizeof(uint8_t), CH_DOS));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_string_0, 0);
+ }
+ if (r->string) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->string, r->size));
+ }
+ if (r->string) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->string, r->length));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_AsciiString(struct ndr_print *ndr, const char *name, const struct lsa_AsciiString *r)
+{
+ ndr_print_struct(ndr, name, "lsa_AsciiString");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "length", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen_m(r->string):r->length);
+ ndr_print_uint16(ndr, "size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen_m(r->string):r->size);
+ ndr_print_ptr(ndr, "string", r->string);
+ ndr->depth++;
+ if (r->string) {
+ ndr_print_string(ndr, "string", r->string);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_AsciiStringLarge(struct ndr_push *ndr, int ndr_flags, const struct lsa_AsciiStringLarge *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, strlen_m(r->string)));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, strlen_m_term(r->string)));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->string));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->string) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, strlen_m_term(r->string)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, strlen_m(r->string)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->string, strlen_m(r->string), sizeof(uint8_t), CH_DOS));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_AsciiStringLarge(struct ndr_pull *ndr, int ndr_flags, struct lsa_AsciiStringLarge *r)
+{
+ uint32_t _ptr_string;
+ TALLOC_CTX *_mem_save_string_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_string));
+ if (_ptr_string) {
+ NDR_PULL_ALLOC(ndr, r->string);
+ } else {
+ r->string = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->string) {
+ _mem_save_string_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->string, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->string));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->string));
+ if (ndr_get_array_length(ndr, &r->string) > ndr_get_array_size(ndr, &r->string)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->string), ndr_get_array_length(ndr, &r->string));
+ }
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->string, ndr_get_array_length(ndr, &r->string), sizeof(uint8_t), CH_DOS));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_string_0, 0);
+ }
+ if (r->string) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->string, r->size));
+ }
+ if (r->string) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->string, r->length));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_AsciiStringLarge(struct ndr_print *ndr, const char *name, const struct lsa_AsciiStringLarge *r)
+{
+ ndr_print_struct(ndr, name, "lsa_AsciiStringLarge");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "length", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen_m(r->string):r->length);
+ ndr_print_uint16(ndr, "size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen_m_term(r->string):r->size);
+ ndr_print_ptr(ndr, "string", r->string);
+ ndr->depth++;
+ if (r->string) {
+ ndr_print_string(ndr, "string", r->string);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_BinaryString(struct ndr_push *ndr, int ndr_flags, const struct lsa_BinaryString *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->size));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size / 2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length / 2));
+ for (cntr_array_1 = 0; cntr_array_1 < r->length / 2; cntr_array_1++) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_BinaryString(struct ndr_pull *ndr, int ndr_flags, struct lsa_BinaryString *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->array));
+ if (ndr_get_array_length(ndr, &r->array) > ndr_get_array_size(ndr, &r->array)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->array), ndr_get_array_length(ndr, &r->array));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->length / 2; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->size / 2));
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->array, r->length / 2));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_BinaryString(struct ndr_print *ndr, const char *name, const struct lsa_BinaryString *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "lsa_BinaryString");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "length", r->length);
+ ndr_print_uint16(ndr, "size", r->size);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->length / 2);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->length / 2;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_uint16(ndr, "array", r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_LUID(struct ndr_push *ndr, int ndr_flags, const struct lsa_LUID *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->low));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->high));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_LUID(struct ndr_pull *ndr, int ndr_flags, struct lsa_LUID *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->low));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->high));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LUID(struct ndr_print *ndr, const char *name, const struct lsa_LUID *r)
+{
+ ndr_print_struct(ndr, name, "lsa_LUID");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "low", r->low);
+ ndr_print_uint32(ndr, "high", r->high);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_PrivEntry(struct ndr_push *ndr, int ndr_flags, const struct lsa_PrivEntry *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_push_lsa_LUID(ndr, NDR_SCALARS, &r->luid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_PrivEntry(struct ndr_pull *ndr, int ndr_flags, struct lsa_PrivEntry *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_pull_lsa_LUID(ndr, NDR_SCALARS, &r->luid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_PrivEntry(struct ndr_print *ndr, const char *name, const struct lsa_PrivEntry *r)
+{
+ ndr_print_struct(ndr, name, "lsa_PrivEntry");
+ ndr->depth++;
+ ndr_print_lsa_StringLarge(ndr, "name", &r->name);
+ ndr_print_lsa_LUID(ndr, "luid", &r->luid);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_PrivArray(struct ndr_push *ndr, int ndr_flags, const struct lsa_PrivArray *r)
+{
+ uint32_t cntr_privs_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->privs));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->privs) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_privs_1 = 0; cntr_privs_1 < r->count; cntr_privs_1++) {
+ NDR_CHECK(ndr_push_lsa_PrivEntry(ndr, NDR_SCALARS, &r->privs[cntr_privs_1]));
+ }
+ for (cntr_privs_1 = 0; cntr_privs_1 < r->count; cntr_privs_1++) {
+ NDR_CHECK(ndr_push_lsa_PrivEntry(ndr, NDR_BUFFERS, &r->privs[cntr_privs_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_PrivArray(struct ndr_pull *ndr, int ndr_flags, struct lsa_PrivArray *r)
+{
+ uint32_t _ptr_privs;
+ uint32_t cntr_privs_1;
+ TALLOC_CTX *_mem_save_privs_0;
+ TALLOC_CTX *_mem_save_privs_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_privs));
+ if (_ptr_privs) {
+ NDR_PULL_ALLOC(ndr, r->privs);
+ } else {
+ r->privs = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->privs) {
+ _mem_save_privs_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->privs, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->privs));
+ NDR_PULL_ALLOC_N(ndr, r->privs, ndr_get_array_size(ndr, &r->privs));
+ _mem_save_privs_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->privs, 0);
+ for (cntr_privs_1 = 0; cntr_privs_1 < r->count; cntr_privs_1++) {
+ NDR_CHECK(ndr_pull_lsa_PrivEntry(ndr, NDR_SCALARS, &r->privs[cntr_privs_1]));
+ }
+ for (cntr_privs_1 = 0; cntr_privs_1 < r->count; cntr_privs_1++) {
+ NDR_CHECK(ndr_pull_lsa_PrivEntry(ndr, NDR_BUFFERS, &r->privs[cntr_privs_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_privs_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_privs_0, 0);
+ }
+ if (r->privs) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->privs, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_PrivArray(struct ndr_print *ndr, const char *name, const struct lsa_PrivArray *r)
+{
+ uint32_t cntr_privs_1;
+ ndr_print_struct(ndr, name, "lsa_PrivArray");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "privs", r->privs);
+ ndr->depth++;
+ if (r->privs) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "privs", (int)r->count);
+ ndr->depth++;
+ for (cntr_privs_1=0;cntr_privs_1<r->count;cntr_privs_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_privs_1) != -1) {
+ ndr_print_lsa_PrivEntry(ndr, "privs", &r->privs[cntr_privs_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_QosInfo(struct ndr_push *ndr, int ndr_flags, const struct lsa_QosInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->len));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->impersonation_level));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->context_mode));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->effective_only));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_QosInfo(struct ndr_pull *ndr, int ndr_flags, struct lsa_QosInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->len));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->impersonation_level));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->context_mode));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->effective_only));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_QosInfo(struct ndr_print *ndr, const char *name, const struct lsa_QosInfo *r)
+{
+ ndr_print_struct(ndr, name, "lsa_QosInfo");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "len", r->len);
+ ndr_print_uint16(ndr, "impersonation_level", r->impersonation_level);
+ ndr_print_uint8(ndr, "context_mode", r->context_mode);
+ ndr_print_uint8(ndr, "effective_only", r->effective_only);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_ObjectAttribute(struct ndr_push *ndr, int ndr_flags, const struct lsa_ObjectAttribute *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->len));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->root_dir));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->object_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->attributes));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sec_desc));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sec_qos));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->root_dir) {
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, *r->root_dir));
+ }
+ if (r->object_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->object_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->object_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->object_name, ndr_charset_length(r->object_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->sec_desc) {
+ NDR_CHECK(ndr_push_security_descriptor(ndr, NDR_SCALARS|NDR_BUFFERS, r->sec_desc));
+ }
+ if (r->sec_qos) {
+ NDR_CHECK(ndr_push_lsa_QosInfo(ndr, NDR_SCALARS, r->sec_qos));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_ObjectAttribute(struct ndr_pull *ndr, int ndr_flags, struct lsa_ObjectAttribute *r)
+{
+ uint32_t _ptr_root_dir;
+ TALLOC_CTX *_mem_save_root_dir_0;
+ uint32_t _ptr_object_name;
+ TALLOC_CTX *_mem_save_object_name_0;
+ uint32_t _ptr_sec_desc;
+ TALLOC_CTX *_mem_save_sec_desc_0;
+ uint32_t _ptr_sec_qos;
+ TALLOC_CTX *_mem_save_sec_qos_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->len));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_root_dir));
+ if (_ptr_root_dir) {
+ NDR_PULL_ALLOC(ndr, r->root_dir);
+ } else {
+ r->root_dir = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_object_name));
+ if (_ptr_object_name) {
+ NDR_PULL_ALLOC(ndr, r->object_name);
+ } else {
+ r->object_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->attributes));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sec_desc));
+ if (_ptr_sec_desc) {
+ NDR_PULL_ALLOC(ndr, r->sec_desc);
+ } else {
+ r->sec_desc = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sec_qos));
+ if (_ptr_sec_qos) {
+ NDR_PULL_ALLOC(ndr, r->sec_qos);
+ } else {
+ r->sec_qos = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->root_dir) {
+ _mem_save_root_dir_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->root_dir, 0);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, r->root_dir));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_root_dir_0, 0);
+ }
+ if (r->object_name) {
+ _mem_save_object_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->object_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->object_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->object_name));
+ if (ndr_get_array_length(ndr, &r->object_name) > ndr_get_array_size(ndr, &r->object_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->object_name), ndr_get_array_length(ndr, &r->object_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->object_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->object_name, ndr_get_array_length(ndr, &r->object_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_object_name_0, 0);
+ }
+ if (r->sec_desc) {
+ _mem_save_sec_desc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sec_desc, 0);
+ NDR_CHECK(ndr_pull_security_descriptor(ndr, NDR_SCALARS|NDR_BUFFERS, r->sec_desc));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sec_desc_0, 0);
+ }
+ if (r->sec_qos) {
+ _mem_save_sec_qos_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sec_qos, 0);
+ NDR_CHECK(ndr_pull_lsa_QosInfo(ndr, NDR_SCALARS, r->sec_qos));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sec_qos_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_ObjectAttribute(struct ndr_print *ndr, const char *name, const struct lsa_ObjectAttribute *r)
+{
+ ndr_print_struct(ndr, name, "lsa_ObjectAttribute");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "len", r->len);
+ ndr_print_ptr(ndr, "root_dir", r->root_dir);
+ ndr->depth++;
+ if (r->root_dir) {
+ ndr_print_uint8(ndr, "root_dir", *r->root_dir);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "object_name", r->object_name);
+ ndr->depth++;
+ if (r->object_name) {
+ ndr_print_string(ndr, "object_name", r->object_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "attributes", r->attributes);
+ ndr_print_ptr(ndr, "sec_desc", r->sec_desc);
+ ndr->depth++;
+ if (r->sec_desc) {
+ ndr_print_security_descriptor(ndr, "sec_desc", r->sec_desc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sec_qos", r->sec_qos);
+ ndr->depth++;
+ if (r->sec_qos) {
+ ndr_print_lsa_QosInfo(ndr, "sec_qos", r->sec_qos);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_PolicyAccessMask(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_PolicyAccessMask(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_PolicyAccessMask(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "LSA_POLICY_VIEW_LOCAL_INFORMATION", LSA_POLICY_VIEW_LOCAL_INFORMATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "LSA_POLICY_VIEW_AUDIT_INFORMATION", LSA_POLICY_VIEW_AUDIT_INFORMATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "LSA_POLICY_GET_PRIVATE_INFORMATION", LSA_POLICY_GET_PRIVATE_INFORMATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "LSA_POLICY_TRUST_ADMIN", LSA_POLICY_TRUST_ADMIN, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "LSA_POLICY_CREATE_ACCOUNT", LSA_POLICY_CREATE_ACCOUNT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "LSA_POLICY_CREATE_SECRET", LSA_POLICY_CREATE_SECRET, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "LSA_POLICY_CREATE_PRIVILEGE", LSA_POLICY_CREATE_PRIVILEGE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "LSA_POLICY_SET_DEFAULT_QUOTA_LIMITS", LSA_POLICY_SET_DEFAULT_QUOTA_LIMITS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "LSA_POLICY_SET_AUDIT_REQUIREMENTS", LSA_POLICY_SET_AUDIT_REQUIREMENTS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "LSA_POLICY_AUDIT_LOG_ADMIN", LSA_POLICY_AUDIT_LOG_ADMIN, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "LSA_POLICY_SERVER_ADMIN", LSA_POLICY_SERVER_ADMIN, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "LSA_POLICY_LOOKUP_NAMES", LSA_POLICY_LOOKUP_NAMES, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_AuditLogInfo(struct ndr_push *ndr, int ndr_flags, const struct lsa_AuditLogInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->percent_full));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->log_size));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->retention_time));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->shutdown_in_progress));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->time_to_shutdown));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->next_audit_record));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_AuditLogInfo(struct ndr_pull *ndr, int ndr_flags, struct lsa_AuditLogInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->percent_full));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->log_size));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->retention_time));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->shutdown_in_progress));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->time_to_shutdown));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->next_audit_record));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_AuditLogInfo(struct ndr_print *ndr, const char *name, const struct lsa_AuditLogInfo *r)
+{
+ ndr_print_struct(ndr, name, "lsa_AuditLogInfo");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "percent_full", r->percent_full);
+ ndr_print_uint32(ndr, "log_size", r->log_size);
+ ndr_print_NTTIME(ndr, "retention_time", r->retention_time);
+ ndr_print_uint8(ndr, "shutdown_in_progress", r->shutdown_in_progress);
+ ndr_print_NTTIME(ndr, "time_to_shutdown", r->time_to_shutdown);
+ ndr_print_uint32(ndr, "next_audit_record", r->next_audit_record);
+ ndr_print_uint32(ndr, "unknown", r->unknown);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_PolicyAuditPolicy(struct ndr_push *ndr, int ndr_flags, enum lsa_PolicyAuditPolicy r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_PolicyAuditPolicy(struct ndr_pull *ndr, int ndr_flags, enum lsa_PolicyAuditPolicy *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_PolicyAuditPolicy(struct ndr_print *ndr, const char *name, enum lsa_PolicyAuditPolicy r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case LSA_AUDIT_POLICY_NONE: val = "LSA_AUDIT_POLICY_NONE"; break;
+ case LSA_AUDIT_POLICY_SUCCESS: val = "LSA_AUDIT_POLICY_SUCCESS"; break;
+ case LSA_AUDIT_POLICY_FAILURE: val = "LSA_AUDIT_POLICY_FAILURE"; break;
+ case LSA_AUDIT_POLICY_ALL: val = "LSA_AUDIT_POLICY_ALL"; break;
+ case LSA_AUDIT_POLICY_CLEAR: val = "LSA_AUDIT_POLICY_CLEAR"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_lsa_AuditEventsInfo(struct ndr_push *ndr, int ndr_flags, const struct lsa_AuditEventsInfo *r)
+{
+ uint32_t cntr_settings_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->auditing_mode));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->settings));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->settings) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_settings_1 = 0; cntr_settings_1 < r->count; cntr_settings_1++) {
+ NDR_CHECK(ndr_push_lsa_PolicyAuditPolicy(ndr, NDR_SCALARS, r->settings[cntr_settings_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_AuditEventsInfo(struct ndr_pull *ndr, int ndr_flags, struct lsa_AuditEventsInfo *r)
+{
+ uint32_t _ptr_settings;
+ uint32_t cntr_settings_1;
+ TALLOC_CTX *_mem_save_settings_0;
+ TALLOC_CTX *_mem_save_settings_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->auditing_mode));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_settings));
+ if (_ptr_settings) {
+ NDR_PULL_ALLOC(ndr, r->settings);
+ } else {
+ r->settings = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->settings) {
+ _mem_save_settings_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->settings, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->settings));
+ NDR_PULL_ALLOC_N(ndr, r->settings, ndr_get_array_size(ndr, &r->settings));
+ _mem_save_settings_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->settings, 0);
+ for (cntr_settings_1 = 0; cntr_settings_1 < r->count; cntr_settings_1++) {
+ NDR_CHECK(ndr_pull_lsa_PolicyAuditPolicy(ndr, NDR_SCALARS, &r->settings[cntr_settings_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_settings_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_settings_0, 0);
+ }
+ if (r->settings) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->settings, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_AuditEventsInfo(struct ndr_print *ndr, const char *name, const struct lsa_AuditEventsInfo *r)
+{
+ uint32_t cntr_settings_1;
+ ndr_print_struct(ndr, name, "lsa_AuditEventsInfo");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "auditing_mode", r->auditing_mode);
+ ndr_print_ptr(ndr, "settings", r->settings);
+ ndr->depth++;
+ if (r->settings) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "settings", (int)r->count);
+ ndr->depth++;
+ for (cntr_settings_1=0;cntr_settings_1<r->count;cntr_settings_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_settings_1) != -1) {
+ ndr_print_lsa_PolicyAuditPolicy(ndr, "settings", r->settings[cntr_settings_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_DomainInfo(struct ndr_push *ndr, int ndr_flags, const struct lsa_DomainInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->name));
+ if (r->sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_DomainInfo(struct ndr_pull *ndr, int ndr_flags, struct lsa_DomainInfo *r)
+{
+ uint32_t _ptr_sid;
+ TALLOC_CTX *_mem_save_sid_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sid));
+ if (_ptr_sid) {
+ NDR_PULL_ALLOC(ndr, r->sid);
+ } else {
+ r->sid = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->name));
+ if (r->sid) {
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_DomainInfo(struct ndr_print *ndr, const char *name, const struct lsa_DomainInfo *r)
+{
+ ndr_print_struct(ndr, name, "lsa_DomainInfo");
+ ndr->depth++;
+ ndr_print_lsa_StringLarge(ndr, "name", &r->name);
+ ndr_print_ptr(ndr, "sid", r->sid);
+ ndr->depth++;
+ if (r->sid) {
+ ndr_print_dom_sid2(ndr, "sid", r->sid);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_PDAccountInfo(struct ndr_push *ndr, int ndr_flags, const struct lsa_PDAccountInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_PDAccountInfo(struct ndr_pull *ndr, int ndr_flags, struct lsa_PDAccountInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_PDAccountInfo(struct ndr_print *ndr, const char *name, const struct lsa_PDAccountInfo *r)
+{
+ ndr_print_struct(ndr, name, "lsa_PDAccountInfo");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "name", &r->name);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_ServerRole(struct ndr_push *ndr, int ndr_flags, const struct lsa_ServerRole *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->unknown));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->role));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_ServerRole(struct ndr_pull *ndr, int ndr_flags, struct lsa_ServerRole *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->unknown));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->role));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_ServerRole(struct ndr_print *ndr, const char *name, const struct lsa_ServerRole *r)
+{
+ ndr_print_struct(ndr, name, "lsa_ServerRole");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "unknown", r->unknown);
+ ndr_print_uint16(ndr, "role", r->role);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_ReplicaSourceInfo(struct ndr_push *ndr, int ndr_flags, const struct lsa_ReplicaSourceInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->source));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->account));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->source));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->account));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_ReplicaSourceInfo(struct ndr_pull *ndr, int ndr_flags, struct lsa_ReplicaSourceInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->source));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->account));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->source));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->account));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_ReplicaSourceInfo(struct ndr_print *ndr, const char *name, const struct lsa_ReplicaSourceInfo *r)
+{
+ ndr_print_struct(ndr, name, "lsa_ReplicaSourceInfo");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "source", &r->source);
+ ndr_print_lsa_String(ndr, "account", &r->account);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_DefaultQuotaInfo(struct ndr_push *ndr, int ndr_flags, const struct lsa_DefaultQuotaInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->paged_pool));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->non_paged_pool));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->min_wss));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_wss));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pagefile));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_DefaultQuotaInfo(struct ndr_pull *ndr, int ndr_flags, struct lsa_DefaultQuotaInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->paged_pool));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->non_paged_pool));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->min_wss));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_wss));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pagefile));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_DefaultQuotaInfo(struct ndr_print *ndr, const char *name, const struct lsa_DefaultQuotaInfo *r)
+{
+ ndr_print_struct(ndr, name, "lsa_DefaultQuotaInfo");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "paged_pool", r->paged_pool);
+ ndr_print_uint32(ndr, "non_paged_pool", r->non_paged_pool);
+ ndr_print_uint32(ndr, "min_wss", r->min_wss);
+ ndr_print_uint32(ndr, "max_wss", r->max_wss);
+ ndr_print_uint32(ndr, "pagefile", r->pagefile);
+ ndr_print_hyper(ndr, "unknown", r->unknown);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_ModificationInfo(struct ndr_push *ndr, int ndr_flags, const struct lsa_ModificationInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->modified_id));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->db_create_time));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_ModificationInfo(struct ndr_pull *ndr, int ndr_flags, struct lsa_ModificationInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->modified_id));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->db_create_time));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_ModificationInfo(struct ndr_print *ndr, const char *name, const struct lsa_ModificationInfo *r)
+{
+ ndr_print_struct(ndr, name, "lsa_ModificationInfo");
+ ndr->depth++;
+ ndr_print_hyper(ndr, "modified_id", r->modified_id);
+ ndr_print_NTTIME(ndr, "db_create_time", r->db_create_time);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_AuditFullSetInfo(struct ndr_push *ndr, int ndr_flags, const struct lsa_AuditFullSetInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->shutdown_on_full));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_AuditFullSetInfo(struct ndr_pull *ndr, int ndr_flags, struct lsa_AuditFullSetInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->shutdown_on_full));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_AuditFullSetInfo(struct ndr_print *ndr, const char *name, const struct lsa_AuditFullSetInfo *r)
+{
+ ndr_print_struct(ndr, name, "lsa_AuditFullSetInfo");
+ ndr->depth++;
+ ndr_print_uint8(ndr, "shutdown_on_full", r->shutdown_on_full);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_AuditFullQueryInfo(struct ndr_push *ndr, int ndr_flags, const struct lsa_AuditFullQueryInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->unknown));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->shutdown_on_full));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->log_is_full));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_AuditFullQueryInfo(struct ndr_pull *ndr, int ndr_flags, struct lsa_AuditFullQueryInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->unknown));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->shutdown_on_full));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->log_is_full));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_AuditFullQueryInfo(struct ndr_print *ndr, const char *name, const struct lsa_AuditFullQueryInfo *r)
+{
+ ndr_print_struct(ndr, name, "lsa_AuditFullQueryInfo");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "unknown", r->unknown);
+ ndr_print_uint8(ndr, "shutdown_on_full", r->shutdown_on_full);
+ ndr_print_uint8(ndr, "log_is_full", r->log_is_full);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_DnsDomainInfo(struct ndr_push *ndr, int ndr_flags, const struct lsa_DnsDomainInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->dns_domain));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->dns_forest));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->domain_guid));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->name));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->dns_domain));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->dns_forest));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_BUFFERS, &r->domain_guid));
+ if (r->sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_DnsDomainInfo(struct ndr_pull *ndr, int ndr_flags, struct lsa_DnsDomainInfo *r)
+{
+ uint32_t _ptr_sid;
+ TALLOC_CTX *_mem_save_sid_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->dns_domain));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->dns_forest));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->domain_guid));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sid));
+ if (_ptr_sid) {
+ NDR_PULL_ALLOC(ndr, r->sid);
+ } else {
+ r->sid = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->name));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->dns_domain));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->dns_forest));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_BUFFERS, &r->domain_guid));
+ if (r->sid) {
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_DnsDomainInfo(struct ndr_print *ndr, const char *name, const struct lsa_DnsDomainInfo *r)
+{
+ ndr_print_struct(ndr, name, "lsa_DnsDomainInfo");
+ ndr->depth++;
+ ndr_print_lsa_StringLarge(ndr, "name", &r->name);
+ ndr_print_lsa_StringLarge(ndr, "dns_domain", &r->dns_domain);
+ ndr_print_lsa_StringLarge(ndr, "dns_forest", &r->dns_forest);
+ ndr_print_GUID(ndr, "domain_guid", &r->domain_guid);
+ ndr_print_ptr(ndr, "sid", r->sid);
+ ndr->depth++;
+ if (r->sid) {
+ ndr_print_dom_sid2(ndr, "sid", r->sid);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_PolicyInfo(struct ndr_push *ndr, int ndr_flags, enum lsa_PolicyInfo r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_PolicyInfo(struct ndr_pull *ndr, int ndr_flags, enum lsa_PolicyInfo *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_PolicyInfo(struct ndr_print *ndr, const char *name, enum lsa_PolicyInfo r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case LSA_POLICY_INFO_AUDIT_LOG: val = "LSA_POLICY_INFO_AUDIT_LOG"; break;
+ case LSA_POLICY_INFO_AUDIT_EVENTS: val = "LSA_POLICY_INFO_AUDIT_EVENTS"; break;
+ case LSA_POLICY_INFO_DOMAIN: val = "LSA_POLICY_INFO_DOMAIN"; break;
+ case LSA_POLICY_INFO_PD: val = "LSA_POLICY_INFO_PD"; break;
+ case LSA_POLICY_INFO_ACCOUNT_DOMAIN: val = "LSA_POLICY_INFO_ACCOUNT_DOMAIN"; break;
+ case LSA_POLICY_INFO_ROLE: val = "LSA_POLICY_INFO_ROLE"; break;
+ case LSA_POLICY_INFO_REPLICA: val = "LSA_POLICY_INFO_REPLICA"; break;
+ case LSA_POLICY_INFO_QUOTA: val = "LSA_POLICY_INFO_QUOTA"; break;
+ case LSA_POLICY_INFO_DB: val = "LSA_POLICY_INFO_DB"; break;
+ case LSA_POLICY_INFO_AUDIT_FULL_SET: val = "LSA_POLICY_INFO_AUDIT_FULL_SET"; break;
+ case LSA_POLICY_INFO_AUDIT_FULL_QUERY: val = "LSA_POLICY_INFO_AUDIT_FULL_QUERY"; break;
+ case LSA_POLICY_INFO_DNS: val = "LSA_POLICY_INFO_DNS"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_lsa_PolicyInformation(struct ndr_push *ndr, int ndr_flags, const union lsa_PolicyInformation *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case LSA_POLICY_INFO_AUDIT_LOG: {
+ NDR_CHECK(ndr_push_lsa_AuditLogInfo(ndr, NDR_SCALARS, &r->audit_log));
+ break; }
+
+ case LSA_POLICY_INFO_AUDIT_EVENTS: {
+ NDR_CHECK(ndr_push_lsa_AuditEventsInfo(ndr, NDR_SCALARS, &r->audit_events));
+ break; }
+
+ case LSA_POLICY_INFO_DOMAIN: {
+ NDR_CHECK(ndr_push_lsa_DomainInfo(ndr, NDR_SCALARS, &r->domain));
+ break; }
+
+ case LSA_POLICY_INFO_PD: {
+ NDR_CHECK(ndr_push_lsa_PDAccountInfo(ndr, NDR_SCALARS, &r->pd));
+ break; }
+
+ case LSA_POLICY_INFO_ACCOUNT_DOMAIN: {
+ NDR_CHECK(ndr_push_lsa_DomainInfo(ndr, NDR_SCALARS, &r->account_domain));
+ break; }
+
+ case LSA_POLICY_INFO_ROLE: {
+ NDR_CHECK(ndr_push_lsa_ServerRole(ndr, NDR_SCALARS, &r->role));
+ break; }
+
+ case LSA_POLICY_INFO_REPLICA: {
+ NDR_CHECK(ndr_push_lsa_ReplicaSourceInfo(ndr, NDR_SCALARS, &r->replica));
+ break; }
+
+ case LSA_POLICY_INFO_QUOTA: {
+ NDR_CHECK(ndr_push_lsa_DefaultQuotaInfo(ndr, NDR_SCALARS, &r->quota));
+ break; }
+
+ case LSA_POLICY_INFO_DB: {
+ NDR_CHECK(ndr_push_lsa_ModificationInfo(ndr, NDR_SCALARS, &r->db));
+ break; }
+
+ case LSA_POLICY_INFO_AUDIT_FULL_SET: {
+ NDR_CHECK(ndr_push_lsa_AuditFullSetInfo(ndr, NDR_SCALARS, &r->auditfullset));
+ break; }
+
+ case LSA_POLICY_INFO_AUDIT_FULL_QUERY: {
+ NDR_CHECK(ndr_push_lsa_AuditFullQueryInfo(ndr, NDR_SCALARS, &r->auditfullquery));
+ break; }
+
+ case LSA_POLICY_INFO_DNS: {
+ NDR_CHECK(ndr_push_lsa_DnsDomainInfo(ndr, NDR_SCALARS, &r->dns));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case LSA_POLICY_INFO_AUDIT_LOG:
+ break;
+
+ case LSA_POLICY_INFO_AUDIT_EVENTS:
+ NDR_CHECK(ndr_push_lsa_AuditEventsInfo(ndr, NDR_BUFFERS, &r->audit_events));
+ break;
+
+ case LSA_POLICY_INFO_DOMAIN:
+ NDR_CHECK(ndr_push_lsa_DomainInfo(ndr, NDR_BUFFERS, &r->domain));
+ break;
+
+ case LSA_POLICY_INFO_PD:
+ NDR_CHECK(ndr_push_lsa_PDAccountInfo(ndr, NDR_BUFFERS, &r->pd));
+ break;
+
+ case LSA_POLICY_INFO_ACCOUNT_DOMAIN:
+ NDR_CHECK(ndr_push_lsa_DomainInfo(ndr, NDR_BUFFERS, &r->account_domain));
+ break;
+
+ case LSA_POLICY_INFO_ROLE:
+ break;
+
+ case LSA_POLICY_INFO_REPLICA:
+ NDR_CHECK(ndr_push_lsa_ReplicaSourceInfo(ndr, NDR_BUFFERS, &r->replica));
+ break;
+
+ case LSA_POLICY_INFO_QUOTA:
+ break;
+
+ case LSA_POLICY_INFO_DB:
+ break;
+
+ case LSA_POLICY_INFO_AUDIT_FULL_SET:
+ break;
+
+ case LSA_POLICY_INFO_AUDIT_FULL_QUERY:
+ break;
+
+ case LSA_POLICY_INFO_DNS:
+ NDR_CHECK(ndr_push_lsa_DnsDomainInfo(ndr, NDR_BUFFERS, &r->dns));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_PolicyInformation(struct ndr_pull *ndr, int ndr_flags, union lsa_PolicyInformation *r)
+{
+ int level;
+ uint16_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case LSA_POLICY_INFO_AUDIT_LOG: {
+ NDR_CHECK(ndr_pull_lsa_AuditLogInfo(ndr, NDR_SCALARS, &r->audit_log));
+ break; }
+
+ case LSA_POLICY_INFO_AUDIT_EVENTS: {
+ NDR_CHECK(ndr_pull_lsa_AuditEventsInfo(ndr, NDR_SCALARS, &r->audit_events));
+ break; }
+
+ case LSA_POLICY_INFO_DOMAIN: {
+ NDR_CHECK(ndr_pull_lsa_DomainInfo(ndr, NDR_SCALARS, &r->domain));
+ break; }
+
+ case LSA_POLICY_INFO_PD: {
+ NDR_CHECK(ndr_pull_lsa_PDAccountInfo(ndr, NDR_SCALARS, &r->pd));
+ break; }
+
+ case LSA_POLICY_INFO_ACCOUNT_DOMAIN: {
+ NDR_CHECK(ndr_pull_lsa_DomainInfo(ndr, NDR_SCALARS, &r->account_domain));
+ break; }
+
+ case LSA_POLICY_INFO_ROLE: {
+ NDR_CHECK(ndr_pull_lsa_ServerRole(ndr, NDR_SCALARS, &r->role));
+ break; }
+
+ case LSA_POLICY_INFO_REPLICA: {
+ NDR_CHECK(ndr_pull_lsa_ReplicaSourceInfo(ndr, NDR_SCALARS, &r->replica));
+ break; }
+
+ case LSA_POLICY_INFO_QUOTA: {
+ NDR_CHECK(ndr_pull_lsa_DefaultQuotaInfo(ndr, NDR_SCALARS, &r->quota));
+ break; }
+
+ case LSA_POLICY_INFO_DB: {
+ NDR_CHECK(ndr_pull_lsa_ModificationInfo(ndr, NDR_SCALARS, &r->db));
+ break; }
+
+ case LSA_POLICY_INFO_AUDIT_FULL_SET: {
+ NDR_CHECK(ndr_pull_lsa_AuditFullSetInfo(ndr, NDR_SCALARS, &r->auditfullset));
+ break; }
+
+ case LSA_POLICY_INFO_AUDIT_FULL_QUERY: {
+ NDR_CHECK(ndr_pull_lsa_AuditFullQueryInfo(ndr, NDR_SCALARS, &r->auditfullquery));
+ break; }
+
+ case LSA_POLICY_INFO_DNS: {
+ NDR_CHECK(ndr_pull_lsa_DnsDomainInfo(ndr, NDR_SCALARS, &r->dns));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case LSA_POLICY_INFO_AUDIT_LOG:
+ break;
+
+ case LSA_POLICY_INFO_AUDIT_EVENTS:
+ NDR_CHECK(ndr_pull_lsa_AuditEventsInfo(ndr, NDR_BUFFERS, &r->audit_events));
+ break;
+
+ case LSA_POLICY_INFO_DOMAIN:
+ NDR_CHECK(ndr_pull_lsa_DomainInfo(ndr, NDR_BUFFERS, &r->domain));
+ break;
+
+ case LSA_POLICY_INFO_PD:
+ NDR_CHECK(ndr_pull_lsa_PDAccountInfo(ndr, NDR_BUFFERS, &r->pd));
+ break;
+
+ case LSA_POLICY_INFO_ACCOUNT_DOMAIN:
+ NDR_CHECK(ndr_pull_lsa_DomainInfo(ndr, NDR_BUFFERS, &r->account_domain));
+ break;
+
+ case LSA_POLICY_INFO_ROLE:
+ break;
+
+ case LSA_POLICY_INFO_REPLICA:
+ NDR_CHECK(ndr_pull_lsa_ReplicaSourceInfo(ndr, NDR_BUFFERS, &r->replica));
+ break;
+
+ case LSA_POLICY_INFO_QUOTA:
+ break;
+
+ case LSA_POLICY_INFO_DB:
+ break;
+
+ case LSA_POLICY_INFO_AUDIT_FULL_SET:
+ break;
+
+ case LSA_POLICY_INFO_AUDIT_FULL_QUERY:
+ break;
+
+ case LSA_POLICY_INFO_DNS:
+ NDR_CHECK(ndr_pull_lsa_DnsDomainInfo(ndr, NDR_BUFFERS, &r->dns));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_PolicyInformation(struct ndr_print *ndr, const char *name, const union lsa_PolicyInformation *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "lsa_PolicyInformation");
+ switch (level) {
+ case LSA_POLICY_INFO_AUDIT_LOG:
+ ndr_print_lsa_AuditLogInfo(ndr, "audit_log", &r->audit_log);
+ break;
+
+ case LSA_POLICY_INFO_AUDIT_EVENTS:
+ ndr_print_lsa_AuditEventsInfo(ndr, "audit_events", &r->audit_events);
+ break;
+
+ case LSA_POLICY_INFO_DOMAIN:
+ ndr_print_lsa_DomainInfo(ndr, "domain", &r->domain);
+ break;
+
+ case LSA_POLICY_INFO_PD:
+ ndr_print_lsa_PDAccountInfo(ndr, "pd", &r->pd);
+ break;
+
+ case LSA_POLICY_INFO_ACCOUNT_DOMAIN:
+ ndr_print_lsa_DomainInfo(ndr, "account_domain", &r->account_domain);
+ break;
+
+ case LSA_POLICY_INFO_ROLE:
+ ndr_print_lsa_ServerRole(ndr, "role", &r->role);
+ break;
+
+ case LSA_POLICY_INFO_REPLICA:
+ ndr_print_lsa_ReplicaSourceInfo(ndr, "replica", &r->replica);
+ break;
+
+ case LSA_POLICY_INFO_QUOTA:
+ ndr_print_lsa_DefaultQuotaInfo(ndr, "quota", &r->quota);
+ break;
+
+ case LSA_POLICY_INFO_DB:
+ ndr_print_lsa_ModificationInfo(ndr, "db", &r->db);
+ break;
+
+ case LSA_POLICY_INFO_AUDIT_FULL_SET:
+ ndr_print_lsa_AuditFullSetInfo(ndr, "auditfullset", &r->auditfullset);
+ break;
+
+ case LSA_POLICY_INFO_AUDIT_FULL_QUERY:
+ ndr_print_lsa_AuditFullQueryInfo(ndr, "auditfullquery", &r->auditfullquery);
+ break;
+
+ case LSA_POLICY_INFO_DNS:
+ ndr_print_lsa_DnsDomainInfo(ndr, "dns", &r->dns);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_lsa_SidPtr(struct ndr_push *ndr, int ndr_flags, const struct lsa_SidPtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_SidPtr(struct ndr_pull *ndr, int ndr_flags, struct lsa_SidPtr *r)
+{
+ uint32_t _ptr_sid;
+ TALLOC_CTX *_mem_save_sid_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sid));
+ if (_ptr_sid) {
+ NDR_PULL_ALLOC(ndr, r->sid);
+ } else {
+ r->sid = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sid) {
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_SidPtr(struct ndr_print *ndr, const char *name, const struct lsa_SidPtr *r)
+{
+ ndr_print_struct(ndr, name, "lsa_SidPtr");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sid", r->sid);
+ ndr->depth++;
+ if (r->sid) {
+ ndr_print_dom_sid2(ndr, "sid", r->sid);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_SidArray(struct ndr_push *ndr, int ndr_flags, const struct lsa_SidArray *r)
+{
+ uint32_t cntr_sids_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_sids));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sids));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sids) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_sids));
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->num_sids; cntr_sids_1++) {
+ NDR_CHECK(ndr_push_lsa_SidPtr(ndr, NDR_SCALARS, &r->sids[cntr_sids_1]));
+ }
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->num_sids; cntr_sids_1++) {
+ NDR_CHECK(ndr_push_lsa_SidPtr(ndr, NDR_BUFFERS, &r->sids[cntr_sids_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_SidArray(struct ndr_pull *ndr, int ndr_flags, struct lsa_SidArray *r)
+{
+ uint32_t _ptr_sids;
+ uint32_t cntr_sids_1;
+ TALLOC_CTX *_mem_save_sids_0;
+ TALLOC_CTX *_mem_save_sids_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_sids));
+ if (r->num_sids < 0 || r->num_sids > 1000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sids));
+ if (_ptr_sids) {
+ NDR_PULL_ALLOC(ndr, r->sids);
+ } else {
+ r->sids = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sids) {
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->sids));
+ NDR_PULL_ALLOC_N(ndr, r->sids, ndr_get_array_size(ndr, &r->sids));
+ _mem_save_sids_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids, 0);
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->num_sids; cntr_sids_1++) {
+ NDR_CHECK(ndr_pull_lsa_SidPtr(ndr, NDR_SCALARS, &r->sids[cntr_sids_1]));
+ }
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->num_sids; cntr_sids_1++) {
+ NDR_CHECK(ndr_pull_lsa_SidPtr(ndr, NDR_BUFFERS, &r->sids[cntr_sids_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, 0);
+ }
+ if (r->sids) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->sids, r->num_sids));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_SidArray(struct ndr_print *ndr, const char *name, const struct lsa_SidArray *r)
+{
+ uint32_t cntr_sids_1;
+ ndr_print_struct(ndr, name, "lsa_SidArray");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_sids", r->num_sids);
+ ndr_print_ptr(ndr, "sids", r->sids);
+ ndr->depth++;
+ if (r->sids) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "sids", (int)r->num_sids);
+ ndr->depth++;
+ for (cntr_sids_1=0;cntr_sids_1<r->num_sids;cntr_sids_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_sids_1) != -1) {
+ ndr_print_lsa_SidPtr(ndr, "sids", &r->sids[cntr_sids_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_DomainList(struct ndr_push *ndr, int ndr_flags, const struct lsa_DomainList *r)
+{
+ uint32_t cntr_domains_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domains));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->domains) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_domains_1 = 0; cntr_domains_1 < r->count; cntr_domains_1++) {
+ NDR_CHECK(ndr_push_lsa_DomainInfo(ndr, NDR_SCALARS, &r->domains[cntr_domains_1]));
+ }
+ for (cntr_domains_1 = 0; cntr_domains_1 < r->count; cntr_domains_1++) {
+ NDR_CHECK(ndr_push_lsa_DomainInfo(ndr, NDR_BUFFERS, &r->domains[cntr_domains_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_DomainList(struct ndr_pull *ndr, int ndr_flags, struct lsa_DomainList *r)
+{
+ uint32_t _ptr_domains;
+ uint32_t cntr_domains_1;
+ TALLOC_CTX *_mem_save_domains_0;
+ TALLOC_CTX *_mem_save_domains_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domains));
+ if (_ptr_domains) {
+ NDR_PULL_ALLOC(ndr, r->domains);
+ } else {
+ r->domains = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->domains) {
+ _mem_save_domains_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domains, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domains));
+ NDR_PULL_ALLOC_N(ndr, r->domains, ndr_get_array_size(ndr, &r->domains));
+ _mem_save_domains_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domains, 0);
+ for (cntr_domains_1 = 0; cntr_domains_1 < r->count; cntr_domains_1++) {
+ NDR_CHECK(ndr_pull_lsa_DomainInfo(ndr, NDR_SCALARS, &r->domains[cntr_domains_1]));
+ }
+ for (cntr_domains_1 = 0; cntr_domains_1 < r->count; cntr_domains_1++) {
+ NDR_CHECK(ndr_pull_lsa_DomainInfo(ndr, NDR_BUFFERS, &r->domains[cntr_domains_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_0, 0);
+ }
+ if (r->domains) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->domains, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_DomainList(struct ndr_print *ndr, const char *name, const struct lsa_DomainList *r)
+{
+ uint32_t cntr_domains_1;
+ ndr_print_struct(ndr, name, "lsa_DomainList");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "domains", r->domains);
+ ndr->depth++;
+ if (r->domains) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "domains", (int)r->count);
+ ndr->depth++;
+ for (cntr_domains_1=0;cntr_domains_1<r->count;cntr_domains_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_domains_1) != -1) {
+ ndr_print_lsa_DomainInfo(ndr, "domains", &r->domains[cntr_domains_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_SidType(struct ndr_push *ndr, int ndr_flags, enum lsa_SidType r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_SidType(struct ndr_pull *ndr, int ndr_flags, enum lsa_SidType *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_SidType(struct ndr_print *ndr, const char *name, enum lsa_SidType r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case SID_NAME_USE_NONE: val = "SID_NAME_USE_NONE"; break;
+ case SID_NAME_USER: val = "SID_NAME_USER"; break;
+ case SID_NAME_DOM_GRP: val = "SID_NAME_DOM_GRP"; break;
+ case SID_NAME_DOMAIN: val = "SID_NAME_DOMAIN"; break;
+ case SID_NAME_ALIAS: val = "SID_NAME_ALIAS"; break;
+ case SID_NAME_WKN_GRP: val = "SID_NAME_WKN_GRP"; break;
+ case SID_NAME_DELETED: val = "SID_NAME_DELETED"; break;
+ case SID_NAME_INVALID: val = "SID_NAME_INVALID"; break;
+ case SID_NAME_UNKNOWN: val = "SID_NAME_UNKNOWN"; break;
+ case SID_NAME_COMPUTER: val = "SID_NAME_COMPUTER"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_lsa_TranslatedSid(struct ndr_push *ndr, int ndr_flags, const struct lsa_TranslatedSid *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_SidType(ndr, NDR_SCALARS, r->sid_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sid_index));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TranslatedSid(struct ndr_pull *ndr, int ndr_flags, struct lsa_TranslatedSid *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_SidType(ndr, NDR_SCALARS, &r->sid_type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sid_index));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TranslatedSid(struct ndr_print *ndr, const char *name, const struct lsa_TranslatedSid *r)
+{
+ ndr_print_struct(ndr, name, "lsa_TranslatedSid");
+ ndr->depth++;
+ ndr_print_lsa_SidType(ndr, "sid_type", r->sid_type);
+ ndr_print_uint32(ndr, "rid", r->rid);
+ ndr_print_uint32(ndr, "sid_index", r->sid_index);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TransSidArray(struct ndr_push *ndr, int ndr_flags, const struct lsa_TransSidArray *r)
+{
+ uint32_t cntr_sids_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sids));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sids) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->count; cntr_sids_1++) {
+ NDR_CHECK(ndr_push_lsa_TranslatedSid(ndr, NDR_SCALARS, &r->sids[cntr_sids_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TransSidArray(struct ndr_pull *ndr, int ndr_flags, struct lsa_TransSidArray *r)
+{
+ uint32_t _ptr_sids;
+ uint32_t cntr_sids_1;
+ TALLOC_CTX *_mem_save_sids_0;
+ TALLOC_CTX *_mem_save_sids_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 1000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sids));
+ if (_ptr_sids) {
+ NDR_PULL_ALLOC(ndr, r->sids);
+ } else {
+ r->sids = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sids) {
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->sids));
+ NDR_PULL_ALLOC_N(ndr, r->sids, ndr_get_array_size(ndr, &r->sids));
+ _mem_save_sids_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids, 0);
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->count; cntr_sids_1++) {
+ NDR_CHECK(ndr_pull_lsa_TranslatedSid(ndr, NDR_SCALARS, &r->sids[cntr_sids_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, 0);
+ }
+ if (r->sids) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->sids, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TransSidArray(struct ndr_print *ndr, const char *name, const struct lsa_TransSidArray *r)
+{
+ uint32_t cntr_sids_1;
+ ndr_print_struct(ndr, name, "lsa_TransSidArray");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "sids", r->sids);
+ ndr->depth++;
+ if (r->sids) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "sids", (int)r->count);
+ ndr->depth++;
+ for (cntr_sids_1=0;cntr_sids_1<r->count;cntr_sids_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_sids_1) != -1) {
+ ndr_print_lsa_TranslatedSid(ndr, "sids", &r->sids[cntr_sids_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_RefDomainList(struct ndr_push *ndr, int ndr_flags, const struct lsa_RefDomainList *r)
+{
+ uint32_t cntr_domains_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domains));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_size));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->domains) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_domains_1 = 0; cntr_domains_1 < r->count; cntr_domains_1++) {
+ NDR_CHECK(ndr_push_lsa_DomainInfo(ndr, NDR_SCALARS, &r->domains[cntr_domains_1]));
+ }
+ for (cntr_domains_1 = 0; cntr_domains_1 < r->count; cntr_domains_1++) {
+ NDR_CHECK(ndr_push_lsa_DomainInfo(ndr, NDR_BUFFERS, &r->domains[cntr_domains_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_RefDomainList(struct ndr_pull *ndr, int ndr_flags, struct lsa_RefDomainList *r)
+{
+ uint32_t _ptr_domains;
+ uint32_t cntr_domains_1;
+ TALLOC_CTX *_mem_save_domains_0;
+ TALLOC_CTX *_mem_save_domains_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 1000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domains));
+ if (_ptr_domains) {
+ NDR_PULL_ALLOC(ndr, r->domains);
+ } else {
+ r->domains = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_size));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->domains) {
+ _mem_save_domains_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domains, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domains));
+ NDR_PULL_ALLOC_N(ndr, r->domains, ndr_get_array_size(ndr, &r->domains));
+ _mem_save_domains_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domains, 0);
+ for (cntr_domains_1 = 0; cntr_domains_1 < r->count; cntr_domains_1++) {
+ NDR_CHECK(ndr_pull_lsa_DomainInfo(ndr, NDR_SCALARS, &r->domains[cntr_domains_1]));
+ }
+ for (cntr_domains_1 = 0; cntr_domains_1 < r->count; cntr_domains_1++) {
+ NDR_CHECK(ndr_pull_lsa_DomainInfo(ndr, NDR_BUFFERS, &r->domains[cntr_domains_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_0, 0);
+ }
+ if (r->domains) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->domains, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_RefDomainList(struct ndr_print *ndr, const char *name, const struct lsa_RefDomainList *r)
+{
+ uint32_t cntr_domains_1;
+ ndr_print_struct(ndr, name, "lsa_RefDomainList");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "domains", r->domains);
+ ndr->depth++;
+ if (r->domains) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "domains", (int)r->count);
+ ndr->depth++;
+ for (cntr_domains_1=0;cntr_domains_1<r->count;cntr_domains_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_domains_1) != -1) {
+ ndr_print_lsa_DomainInfo(ndr, "domains", &r->domains[cntr_domains_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_size", r->max_size);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_LookupNamesLevel(struct ndr_push *ndr, int ndr_flags, enum lsa_LookupNamesLevel r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_LookupNamesLevel(struct ndr_pull *ndr, int ndr_flags, enum lsa_LookupNamesLevel *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LookupNamesLevel(struct ndr_print *ndr, const char *name, enum lsa_LookupNamesLevel r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case LSA_LOOKUP_NAMES_ALL: val = "LSA_LOOKUP_NAMES_ALL"; break;
+ case LSA_LOOKUP_NAMES_DOMAINS_ONLY: val = "LSA_LOOKUP_NAMES_DOMAINS_ONLY"; break;
+ case LSA_LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY: val = "LSA_LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY"; break;
+ case LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY: val = "LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY"; break;
+ case LSA_LOOKUP_NAMES_FOREST_TRUSTS_ONLY: val = "LSA_LOOKUP_NAMES_FOREST_TRUSTS_ONLY"; break;
+ case LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2: val = "LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_lsa_TranslatedName(struct ndr_push *ndr, int ndr_flags, const struct lsa_TranslatedName *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_SidType(ndr, NDR_SCALARS, r->sid_type));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sid_index));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TranslatedName(struct ndr_pull *ndr, int ndr_flags, struct lsa_TranslatedName *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_SidType(ndr, NDR_SCALARS, &r->sid_type));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sid_index));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TranslatedName(struct ndr_print *ndr, const char *name, const struct lsa_TranslatedName *r)
+{
+ ndr_print_struct(ndr, name, "lsa_TranslatedName");
+ ndr->depth++;
+ ndr_print_lsa_SidType(ndr, "sid_type", r->sid_type);
+ ndr_print_lsa_String(ndr, "name", &r->name);
+ ndr_print_uint32(ndr, "sid_index", r->sid_index);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TransNameArray(struct ndr_push *ndr, int ndr_flags, const struct lsa_TransNameArray *r)
+{
+ uint32_t cntr_names_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->names));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->names) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_push_lsa_TranslatedName(ndr, NDR_SCALARS, &r->names[cntr_names_1]));
+ }
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_push_lsa_TranslatedName(ndr, NDR_BUFFERS, &r->names[cntr_names_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TransNameArray(struct ndr_pull *ndr, int ndr_flags, struct lsa_TransNameArray *r)
+{
+ uint32_t _ptr_names;
+ uint32_t cntr_names_1;
+ TALLOC_CTX *_mem_save_names_0;
+ TALLOC_CTX *_mem_save_names_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 1000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_names));
+ if (_ptr_names) {
+ NDR_PULL_ALLOC(ndr, r->names);
+ } else {
+ r->names = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->names) {
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->names, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->names));
+ NDR_PULL_ALLOC_N(ndr, r->names, ndr_get_array_size(ndr, &r->names));
+ _mem_save_names_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->names, 0);
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_pull_lsa_TranslatedName(ndr, NDR_SCALARS, &r->names[cntr_names_1]));
+ }
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_pull_lsa_TranslatedName(ndr, NDR_BUFFERS, &r->names[cntr_names_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, 0);
+ }
+ if (r->names) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->names, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TransNameArray(struct ndr_print *ndr, const char *name, const struct lsa_TransNameArray *r)
+{
+ uint32_t cntr_names_1;
+ ndr_print_struct(ndr, name, "lsa_TransNameArray");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "names", r->names);
+ ndr->depth++;
+ if (r->names) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "names", (int)r->count);
+ ndr->depth++;
+ for (cntr_names_1=0;cntr_names_1<r->count;cntr_names_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_names_1) != -1) {
+ ndr_print_lsa_TranslatedName(ndr, "names", &r->names[cntr_names_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_LUIDAttribute(struct ndr_push *ndr, int ndr_flags, const struct lsa_LUIDAttribute *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_LUID(ndr, NDR_SCALARS, &r->luid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->attribute));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_LUIDAttribute(struct ndr_pull *ndr, int ndr_flags, struct lsa_LUIDAttribute *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_LUID(ndr, NDR_SCALARS, &r->luid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->attribute));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LUIDAttribute(struct ndr_print *ndr, const char *name, const struct lsa_LUIDAttribute *r)
+{
+ ndr_print_struct(ndr, name, "lsa_LUIDAttribute");
+ ndr->depth++;
+ ndr_print_lsa_LUID(ndr, "luid", &r->luid);
+ ndr_print_uint32(ndr, "attribute", r->attribute);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_PrivilegeSet(struct ndr_push *ndr, int ndr_flags, const struct lsa_PrivilegeSet *r)
+{
+ uint32_t cntr_set_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown));
+ for (cntr_set_0 = 0; cntr_set_0 < r->count; cntr_set_0++) {
+ NDR_CHECK(ndr_push_lsa_LUIDAttribute(ndr, NDR_SCALARS, &r->set[cntr_set_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_PrivilegeSet(struct ndr_pull *ndr, int ndr_flags, struct lsa_PrivilegeSet *r)
+{
+ uint32_t cntr_set_0;
+ TALLOC_CTX *_mem_save_set_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->set));
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 1000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown));
+ NDR_PULL_ALLOC_N(ndr, r->set, ndr_get_array_size(ndr, &r->set));
+ _mem_save_set_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->set, 0);
+ for (cntr_set_0 = 0; cntr_set_0 < r->count; cntr_set_0++) {
+ NDR_CHECK(ndr_pull_lsa_LUIDAttribute(ndr, NDR_SCALARS, &r->set[cntr_set_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_set_0, 0);
+ if (r->set) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->set, r->count));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_PrivilegeSet(struct ndr_print *ndr, const char *name, const struct lsa_PrivilegeSet *r)
+{
+ uint32_t cntr_set_0;
+ ndr_print_struct(ndr, name, "lsa_PrivilegeSet");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_uint32(ndr, "unknown", r->unknown);
+ ndr->print(ndr, "%s: ARRAY(%d)", "set", (int)r->count);
+ ndr->depth++;
+ for (cntr_set_0=0;cntr_set_0<r->count;cntr_set_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_set_0) != -1) {
+ ndr_print_lsa_LUIDAttribute(ndr, "set", &r->set[cntr_set_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_DATA_BUF(struct ndr_push *ndr, int ndr_flags, const struct lsa_DATA_BUF *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data, r->length));
+ }
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_DATA_BUF(struct ndr_pull *ndr, int ndr_flags, struct lsa_DATA_BUF *r)
+{
+ uint32_t _ptr_data;
+ TALLOC_CTX *_mem_save_data_0;
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data));
+ if (_ptr_data) {
+ NDR_PULL_ALLOC(ndr, r->data);
+ } else {
+ r->data = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->data, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->data));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->data));
+ if (ndr_get_array_length(ndr, &r->data) > ndr_get_array_size(ndr, &r->data)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->data), ndr_get_array_length(ndr, &r->data));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->data, ndr_get_array_size(ndr, &r->data));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data, ndr_get_array_length(ndr, &r->data)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, 0);
+ }
+ if (r->data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->data, r->size));
+ }
+ if (r->data) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->data, r->length));
+ }
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_DATA_BUF(struct ndr_print *ndr, const char *name, const struct lsa_DATA_BUF *r)
+{
+ ndr_print_struct(ndr, name, "lsa_DATA_BUF");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "length", r->length);
+ ndr_print_uint32(ndr, "size", r->size);
+ ndr_print_ptr(ndr, "data", r->data);
+ ndr->depth++;
+ if (r->data) {
+ ndr_print_array_uint8(ndr, "data", r->data, r->length);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_lsa_DATA_BUF2(struct ndr_push *ndr, int ndr_flags, const struct lsa_DATA_BUF2 *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data, r->size));
+ }
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_DATA_BUF2(struct ndr_pull *ndr, int ndr_flags, struct lsa_DATA_BUF2 *r)
+{
+ uint32_t _ptr_data;
+ TALLOC_CTX *_mem_save_data_0;
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->size));
+ if (r->size < 0 || r->size > 65536) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data));
+ if (_ptr_data) {
+ NDR_PULL_ALLOC(ndr, r->data);
+ } else {
+ r->data = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->data, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->data));
+ NDR_PULL_ALLOC_N(ndr, r->data, ndr_get_array_size(ndr, &r->data));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data, ndr_get_array_size(ndr, &r->data)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, 0);
+ }
+ if (r->data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->data, r->size));
+ }
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_DATA_BUF2(struct ndr_print *ndr, const char *name, const struct lsa_DATA_BUF2 *r)
+{
+ ndr_print_struct(ndr, name, "lsa_DATA_BUF2");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "size", r->size);
+ ndr_print_ptr(ndr, "data", r->data);
+ ndr->depth++;
+ if (r->data) {
+ ndr_print_array_uint8(ndr, "data", r->data, r->size);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_lsa_TrustDomInfoEnum(struct ndr_push *ndr, int ndr_flags, enum lsa_TrustDomInfoEnum r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TrustDomInfoEnum(struct ndr_pull *ndr, int ndr_flags, enum lsa_TrustDomInfoEnum *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TrustDomInfoEnum(struct ndr_print *ndr, const char *name, enum lsa_TrustDomInfoEnum r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case LSA_TRUSTED_DOMAIN_INFO_NAME: val = "LSA_TRUSTED_DOMAIN_INFO_NAME"; break;
+ case LSA_TRUSTED_DOMAIN_INFO_CONTROLLERS_INFO: val = "LSA_TRUSTED_DOMAIN_INFO_CONTROLLERS_INFO"; break;
+ case LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET: val = "LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET"; break;
+ case LSA_TRUSTED_DOMAIN_INFO_PASSWORD: val = "LSA_TRUSTED_DOMAIN_INFO_PASSWORD"; break;
+ case LSA_TRUSTED_DOMAIN_INFO_BASIC: val = "LSA_TRUSTED_DOMAIN_INFO_BASIC"; break;
+ case LSA_TRUSTED_DOMAIN_INFO_INFO_EX: val = "LSA_TRUSTED_DOMAIN_INFO_INFO_EX"; break;
+ case LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO: val = "LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO"; break;
+ case LSA_TRUSTED_DOMAIN_INFO_FULL_INFO: val = "LSA_TRUSTED_DOMAIN_INFO_FULL_INFO"; break;
+ case LSA_TRUSTED_DOMAIN_INFO_11: val = "LSA_TRUSTED_DOMAIN_INFO_11"; break;
+ case LSA_TRUSTED_DOMAIN_INFO_INFO_ALL: val = "LSA_TRUSTED_DOMAIN_INFO_INFO_ALL"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_lsa_TrustDomainInfoName(struct ndr_push *ndr, int ndr_flags, const struct lsa_TrustDomainInfoName *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->netbios_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->netbios_name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TrustDomainInfoName(struct ndr_pull *ndr, int ndr_flags, struct lsa_TrustDomainInfoName *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->netbios_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->netbios_name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoName(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoName *r)
+{
+ ndr_print_struct(ndr, name, "lsa_TrustDomainInfoName");
+ ndr->depth++;
+ ndr_print_lsa_StringLarge(ndr, "netbios_name", &r->netbios_name);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TrustDomainInfoPosixOffset(struct ndr_push *ndr, int ndr_flags, const struct lsa_TrustDomainInfoPosixOffset *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->posix_offset));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TrustDomainInfoPosixOffset(struct ndr_pull *ndr, int ndr_flags, struct lsa_TrustDomainInfoPosixOffset *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->posix_offset));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoPosixOffset(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoPosixOffset *r)
+{
+ ndr_print_struct(ndr, name, "lsa_TrustDomainInfoPosixOffset");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "posix_offset", r->posix_offset);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TrustDomainInfoPassword(struct ndr_push *ndr, int ndr_flags, const struct lsa_TrustDomainInfoPassword *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->password));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->old_password));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->password) {
+ NDR_CHECK(ndr_push_lsa_DATA_BUF(ndr, NDR_SCALARS|NDR_BUFFERS, r->password));
+ }
+ if (r->old_password) {
+ NDR_CHECK(ndr_push_lsa_DATA_BUF(ndr, NDR_SCALARS|NDR_BUFFERS, r->old_password));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TrustDomainInfoPassword(struct ndr_pull *ndr, int ndr_flags, struct lsa_TrustDomainInfoPassword *r)
+{
+ uint32_t _ptr_password;
+ TALLOC_CTX *_mem_save_password_0;
+ uint32_t _ptr_old_password;
+ TALLOC_CTX *_mem_save_old_password_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password));
+ if (_ptr_password) {
+ NDR_PULL_ALLOC(ndr, r->password);
+ } else {
+ r->password = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_old_password));
+ if (_ptr_old_password) {
+ NDR_PULL_ALLOC(ndr, r->old_password);
+ } else {
+ r->old_password = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->password) {
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->password, 0);
+ NDR_CHECK(ndr_pull_lsa_DATA_BUF(ndr, NDR_SCALARS|NDR_BUFFERS, r->password));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, 0);
+ }
+ if (r->old_password) {
+ _mem_save_old_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->old_password, 0);
+ NDR_CHECK(ndr_pull_lsa_DATA_BUF(ndr, NDR_SCALARS|NDR_BUFFERS, r->old_password));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_old_password_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoPassword(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoPassword *r)
+{
+ ndr_print_struct(ndr, name, "lsa_TrustDomainInfoPassword");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "password", r->password);
+ ndr->depth++;
+ if (r->password) {
+ ndr_print_lsa_DATA_BUF(ndr, "password", r->password);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "old_password", r->old_password);
+ ndr->depth++;
+ if (r->old_password) {
+ ndr_print_lsa_DATA_BUF(ndr, "old_password", r->old_password);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TrustDomainInfoBasic(struct ndr_push *ndr, int ndr_flags, const struct lsa_TrustDomainInfoBasic *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->netbios_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->netbios_name));
+ if (r->sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TrustDomainInfoBasic(struct ndr_pull *ndr, int ndr_flags, struct lsa_TrustDomainInfoBasic *r)
+{
+ uint32_t _ptr_sid;
+ TALLOC_CTX *_mem_save_sid_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->netbios_name));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sid));
+ if (_ptr_sid) {
+ NDR_PULL_ALLOC(ndr, r->sid);
+ } else {
+ r->sid = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->netbios_name));
+ if (r->sid) {
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoBasic(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoBasic *r)
+{
+ ndr_print_struct(ndr, name, "lsa_TrustDomainInfoBasic");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "netbios_name", &r->netbios_name);
+ ndr_print_ptr(ndr, "sid", r->sid);
+ ndr->depth++;
+ if (r->sid) {
+ ndr_print_dom_sid2(ndr, "sid", r->sid);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TrustDomainInfoInfoEx(struct ndr_push *ndr, int ndr_flags, const struct lsa_TrustDomainInfoInfoEx *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->domain_name));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->netbios_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->trust_direction));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->trust_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->trust_attributes));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->domain_name));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->netbios_name));
+ if (r->sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TrustDomainInfoInfoEx(struct ndr_pull *ndr, int ndr_flags, struct lsa_TrustDomainInfoInfoEx *r)
+{
+ uint32_t _ptr_sid;
+ TALLOC_CTX *_mem_save_sid_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->domain_name));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->netbios_name));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sid));
+ if (_ptr_sid) {
+ NDR_PULL_ALLOC(ndr, r->sid);
+ } else {
+ r->sid = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->trust_direction));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->trust_type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->trust_attributes));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->domain_name));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->netbios_name));
+ if (r->sid) {
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoInfoEx(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoInfoEx *r)
+{
+ ndr_print_struct(ndr, name, "lsa_TrustDomainInfoInfoEx");
+ ndr->depth++;
+ ndr_print_lsa_StringLarge(ndr, "domain_name", &r->domain_name);
+ ndr_print_lsa_StringLarge(ndr, "netbios_name", &r->netbios_name);
+ ndr_print_ptr(ndr, "sid", r->sid);
+ ndr->depth++;
+ if (r->sid) {
+ ndr_print_dom_sid2(ndr, "sid", r->sid);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "trust_direction", r->trust_direction);
+ ndr_print_uint32(ndr, "trust_type", r->trust_type);
+ ndr_print_uint32(ndr, "trust_attributes", r->trust_attributes);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TrustDomainInfoBuffer(struct ndr_push *ndr, int ndr_flags, const struct lsa_TrustDomainInfoBuffer *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_NTTIME_hyper(ndr, NDR_SCALARS, r->last_update_time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->secret_type));
+ NDR_CHECK(ndr_push_lsa_DATA_BUF2(ndr, NDR_SCALARS, &r->data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_DATA_BUF2(ndr, NDR_BUFFERS, &r->data));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TrustDomainInfoBuffer(struct ndr_pull *ndr, int ndr_flags, struct lsa_TrustDomainInfoBuffer *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_NTTIME_hyper(ndr, NDR_SCALARS, &r->last_update_time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->secret_type));
+ NDR_CHECK(ndr_pull_lsa_DATA_BUF2(ndr, NDR_SCALARS, &r->data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_DATA_BUF2(ndr, NDR_BUFFERS, &r->data));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoBuffer(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoBuffer *r)
+{
+ ndr_print_struct(ndr, name, "lsa_TrustDomainInfoBuffer");
+ ndr->depth++;
+ ndr_print_NTTIME_hyper(ndr, "last_update_time", r->last_update_time);
+ ndr_print_uint32(ndr, "secret_type", r->secret_type);
+ ndr_print_lsa_DATA_BUF2(ndr, "data", &r->data);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TrustDomainInfoAuthInfo(struct ndr_push *ndr, int ndr_flags, const struct lsa_TrustDomainInfoAuthInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->incoming_count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->incoming_current_auth_info));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->incoming_previous_auth_info));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->outgoing_count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->outgoing_current_auth_info));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->outgoing_previous_auth_info));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->incoming_current_auth_info) {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoBuffer(ndr, NDR_SCALARS|NDR_BUFFERS, r->incoming_current_auth_info));
+ }
+ if (r->incoming_previous_auth_info) {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoBuffer(ndr, NDR_SCALARS|NDR_BUFFERS, r->incoming_previous_auth_info));
+ }
+ if (r->outgoing_current_auth_info) {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoBuffer(ndr, NDR_SCALARS|NDR_BUFFERS, r->outgoing_current_auth_info));
+ }
+ if (r->outgoing_previous_auth_info) {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoBuffer(ndr, NDR_SCALARS|NDR_BUFFERS, r->outgoing_previous_auth_info));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TrustDomainInfoAuthInfo(struct ndr_pull *ndr, int ndr_flags, struct lsa_TrustDomainInfoAuthInfo *r)
+{
+ uint32_t _ptr_incoming_current_auth_info;
+ TALLOC_CTX *_mem_save_incoming_current_auth_info_0;
+ uint32_t _ptr_incoming_previous_auth_info;
+ TALLOC_CTX *_mem_save_incoming_previous_auth_info_0;
+ uint32_t _ptr_outgoing_current_auth_info;
+ TALLOC_CTX *_mem_save_outgoing_current_auth_info_0;
+ uint32_t _ptr_outgoing_previous_auth_info;
+ TALLOC_CTX *_mem_save_outgoing_previous_auth_info_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->incoming_count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_incoming_current_auth_info));
+ if (_ptr_incoming_current_auth_info) {
+ NDR_PULL_ALLOC(ndr, r->incoming_current_auth_info);
+ } else {
+ r->incoming_current_auth_info = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_incoming_previous_auth_info));
+ if (_ptr_incoming_previous_auth_info) {
+ NDR_PULL_ALLOC(ndr, r->incoming_previous_auth_info);
+ } else {
+ r->incoming_previous_auth_info = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->outgoing_count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_outgoing_current_auth_info));
+ if (_ptr_outgoing_current_auth_info) {
+ NDR_PULL_ALLOC(ndr, r->outgoing_current_auth_info);
+ } else {
+ r->outgoing_current_auth_info = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_outgoing_previous_auth_info));
+ if (_ptr_outgoing_previous_auth_info) {
+ NDR_PULL_ALLOC(ndr, r->outgoing_previous_auth_info);
+ } else {
+ r->outgoing_previous_auth_info = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->incoming_current_auth_info) {
+ _mem_save_incoming_current_auth_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->incoming_current_auth_info, 0);
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoBuffer(ndr, NDR_SCALARS|NDR_BUFFERS, r->incoming_current_auth_info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_incoming_current_auth_info_0, 0);
+ }
+ if (r->incoming_previous_auth_info) {
+ _mem_save_incoming_previous_auth_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->incoming_previous_auth_info, 0);
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoBuffer(ndr, NDR_SCALARS|NDR_BUFFERS, r->incoming_previous_auth_info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_incoming_previous_auth_info_0, 0);
+ }
+ if (r->outgoing_current_auth_info) {
+ _mem_save_outgoing_current_auth_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->outgoing_current_auth_info, 0);
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoBuffer(ndr, NDR_SCALARS|NDR_BUFFERS, r->outgoing_current_auth_info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_outgoing_current_auth_info_0, 0);
+ }
+ if (r->outgoing_previous_auth_info) {
+ _mem_save_outgoing_previous_auth_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->outgoing_previous_auth_info, 0);
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoBuffer(ndr, NDR_SCALARS|NDR_BUFFERS, r->outgoing_previous_auth_info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_outgoing_previous_auth_info_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoAuthInfo(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoAuthInfo *r)
+{
+ ndr_print_struct(ndr, name, "lsa_TrustDomainInfoAuthInfo");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "incoming_count", r->incoming_count);
+ ndr_print_ptr(ndr, "incoming_current_auth_info", r->incoming_current_auth_info);
+ ndr->depth++;
+ if (r->incoming_current_auth_info) {
+ ndr_print_lsa_TrustDomainInfoBuffer(ndr, "incoming_current_auth_info", r->incoming_current_auth_info);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "incoming_previous_auth_info", r->incoming_previous_auth_info);
+ ndr->depth++;
+ if (r->incoming_previous_auth_info) {
+ ndr_print_lsa_TrustDomainInfoBuffer(ndr, "incoming_previous_auth_info", r->incoming_previous_auth_info);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "outgoing_count", r->outgoing_count);
+ ndr_print_ptr(ndr, "outgoing_current_auth_info", r->outgoing_current_auth_info);
+ ndr->depth++;
+ if (r->outgoing_current_auth_info) {
+ ndr_print_lsa_TrustDomainInfoBuffer(ndr, "outgoing_current_auth_info", r->outgoing_current_auth_info);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "outgoing_previous_auth_info", r->outgoing_previous_auth_info);
+ ndr->depth++;
+ if (r->outgoing_previous_auth_info) {
+ ndr_print_lsa_TrustDomainInfoBuffer(ndr, "outgoing_previous_auth_info", r->outgoing_previous_auth_info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TrustDomainInfoFullInfo(struct ndr_push *ndr, int ndr_flags, const struct lsa_TrustDomainInfoFullInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoInfoEx(ndr, NDR_SCALARS, &r->info_ex));
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoPosixOffset(ndr, NDR_SCALARS, &r->posix_offset));
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoAuthInfo(ndr, NDR_SCALARS, &r->auth_info));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoInfoEx(ndr, NDR_BUFFERS, &r->info_ex));
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoAuthInfo(ndr, NDR_BUFFERS, &r->auth_info));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TrustDomainInfoFullInfo(struct ndr_pull *ndr, int ndr_flags, struct lsa_TrustDomainInfoFullInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoInfoEx(ndr, NDR_SCALARS, &r->info_ex));
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoPosixOffset(ndr, NDR_SCALARS, &r->posix_offset));
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoAuthInfo(ndr, NDR_SCALARS, &r->auth_info));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoInfoEx(ndr, NDR_BUFFERS, &r->info_ex));
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoAuthInfo(ndr, NDR_BUFFERS, &r->auth_info));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoFullInfo(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoFullInfo *r)
+{
+ ndr_print_struct(ndr, name, "lsa_TrustDomainInfoFullInfo");
+ ndr->depth++;
+ ndr_print_lsa_TrustDomainInfoInfoEx(ndr, "info_ex", &r->info_ex);
+ ndr_print_lsa_TrustDomainInfoPosixOffset(ndr, "posix_offset", &r->posix_offset);
+ ndr_print_lsa_TrustDomainInfoAuthInfo(ndr, "auth_info", &r->auth_info);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TrustDomainInfo11(struct ndr_push *ndr, int ndr_flags, const struct lsa_TrustDomainInfo11 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoInfoEx(ndr, NDR_SCALARS, &r->info_ex));
+ NDR_CHECK(ndr_push_lsa_DATA_BUF2(ndr, NDR_SCALARS, &r->data1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoInfoEx(ndr, NDR_BUFFERS, &r->info_ex));
+ NDR_CHECK(ndr_push_lsa_DATA_BUF2(ndr, NDR_BUFFERS, &r->data1));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TrustDomainInfo11(struct ndr_pull *ndr, int ndr_flags, struct lsa_TrustDomainInfo11 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoInfoEx(ndr, NDR_SCALARS, &r->info_ex));
+ NDR_CHECK(ndr_pull_lsa_DATA_BUF2(ndr, NDR_SCALARS, &r->data1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoInfoEx(ndr, NDR_BUFFERS, &r->info_ex));
+ NDR_CHECK(ndr_pull_lsa_DATA_BUF2(ndr, NDR_BUFFERS, &r->data1));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfo11(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfo11 *r)
+{
+ ndr_print_struct(ndr, name, "lsa_TrustDomainInfo11");
+ ndr->depth++;
+ ndr_print_lsa_TrustDomainInfoInfoEx(ndr, "info_ex", &r->info_ex);
+ ndr_print_lsa_DATA_BUF2(ndr, "data1", &r->data1);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TrustDomainInfoInfoAll(struct ndr_push *ndr, int ndr_flags, const struct lsa_TrustDomainInfoInfoAll *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoInfoEx(ndr, NDR_SCALARS, &r->info_ex));
+ NDR_CHECK(ndr_push_lsa_DATA_BUF2(ndr, NDR_SCALARS, &r->data1));
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoPosixOffset(ndr, NDR_SCALARS, &r->posix_offset));
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoAuthInfo(ndr, NDR_SCALARS, &r->auth_info));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoInfoEx(ndr, NDR_BUFFERS, &r->info_ex));
+ NDR_CHECK(ndr_push_lsa_DATA_BUF2(ndr, NDR_BUFFERS, &r->data1));
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoAuthInfo(ndr, NDR_BUFFERS, &r->auth_info));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TrustDomainInfoInfoAll(struct ndr_pull *ndr, int ndr_flags, struct lsa_TrustDomainInfoInfoAll *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoInfoEx(ndr, NDR_SCALARS, &r->info_ex));
+ NDR_CHECK(ndr_pull_lsa_DATA_BUF2(ndr, NDR_SCALARS, &r->data1));
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoPosixOffset(ndr, NDR_SCALARS, &r->posix_offset));
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoAuthInfo(ndr, NDR_SCALARS, &r->auth_info));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoInfoEx(ndr, NDR_BUFFERS, &r->info_ex));
+ NDR_CHECK(ndr_pull_lsa_DATA_BUF2(ndr, NDR_BUFFERS, &r->data1));
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoAuthInfo(ndr, NDR_BUFFERS, &r->auth_info));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TrustDomainInfoInfoAll(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoInfoAll *r)
+{
+ ndr_print_struct(ndr, name, "lsa_TrustDomainInfoInfoAll");
+ ndr->depth++;
+ ndr_print_lsa_TrustDomainInfoInfoEx(ndr, "info_ex", &r->info_ex);
+ ndr_print_lsa_DATA_BUF2(ndr, "data1", &r->data1);
+ ndr_print_lsa_TrustDomainInfoPosixOffset(ndr, "posix_offset", &r->posix_offset);
+ ndr_print_lsa_TrustDomainInfoAuthInfo(ndr, "auth_info", &r->auth_info);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TrustedDomainInfo(struct ndr_push *ndr, int ndr_flags, const union lsa_TrustedDomainInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_lsa_TrustDomInfoEnum(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case LSA_TRUSTED_DOMAIN_INFO_NAME: {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoName(ndr, NDR_SCALARS, &r->name));
+ break; }
+
+ case LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET: {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoPosixOffset(ndr, NDR_SCALARS, &r->posix_offset));
+ break; }
+
+ case LSA_TRUSTED_DOMAIN_INFO_PASSWORD: {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoPassword(ndr, NDR_SCALARS, &r->password));
+ break; }
+
+ case LSA_TRUSTED_DOMAIN_INFO_BASIC: {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoBasic(ndr, NDR_SCALARS, &r->info_basic));
+ break; }
+
+ case LSA_TRUSTED_DOMAIN_INFO_INFO_EX: {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoInfoEx(ndr, NDR_SCALARS, &r->info_ex));
+ break; }
+
+ case LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO: {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoAuthInfo(ndr, NDR_SCALARS, &r->auth_info));
+ break; }
+
+ case LSA_TRUSTED_DOMAIN_INFO_FULL_INFO: {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoFullInfo(ndr, NDR_SCALARS, &r->full_info));
+ break; }
+
+ case LSA_TRUSTED_DOMAIN_INFO_11: {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfo11(ndr, NDR_SCALARS, &r->info11));
+ break; }
+
+ case LSA_TRUSTED_DOMAIN_INFO_INFO_ALL: {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoInfoAll(ndr, NDR_SCALARS, &r->info_all));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case LSA_TRUSTED_DOMAIN_INFO_NAME:
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoName(ndr, NDR_BUFFERS, &r->name));
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET:
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_PASSWORD:
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoPassword(ndr, NDR_BUFFERS, &r->password));
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_BASIC:
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoBasic(ndr, NDR_BUFFERS, &r->info_basic));
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_INFO_EX:
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoInfoEx(ndr, NDR_BUFFERS, &r->info_ex));
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO:
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoAuthInfo(ndr, NDR_BUFFERS, &r->auth_info));
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_FULL_INFO:
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoFullInfo(ndr, NDR_BUFFERS, &r->full_info));
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_11:
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfo11(ndr, NDR_BUFFERS, &r->info11));
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_INFO_ALL:
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoInfoAll(ndr, NDR_BUFFERS, &r->info_all));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TrustedDomainInfo(struct ndr_pull *ndr, int ndr_flags, union lsa_TrustedDomainInfo *r)
+{
+ int level;
+ uint16_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case LSA_TRUSTED_DOMAIN_INFO_NAME: {
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoName(ndr, NDR_SCALARS, &r->name));
+ break; }
+
+ case LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET: {
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoPosixOffset(ndr, NDR_SCALARS, &r->posix_offset));
+ break; }
+
+ case LSA_TRUSTED_DOMAIN_INFO_PASSWORD: {
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoPassword(ndr, NDR_SCALARS, &r->password));
+ break; }
+
+ case LSA_TRUSTED_DOMAIN_INFO_BASIC: {
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoBasic(ndr, NDR_SCALARS, &r->info_basic));
+ break; }
+
+ case LSA_TRUSTED_DOMAIN_INFO_INFO_EX: {
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoInfoEx(ndr, NDR_SCALARS, &r->info_ex));
+ break; }
+
+ case LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO: {
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoAuthInfo(ndr, NDR_SCALARS, &r->auth_info));
+ break; }
+
+ case LSA_TRUSTED_DOMAIN_INFO_FULL_INFO: {
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoFullInfo(ndr, NDR_SCALARS, &r->full_info));
+ break; }
+
+ case LSA_TRUSTED_DOMAIN_INFO_11: {
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfo11(ndr, NDR_SCALARS, &r->info11));
+ break; }
+
+ case LSA_TRUSTED_DOMAIN_INFO_INFO_ALL: {
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoInfoAll(ndr, NDR_SCALARS, &r->info_all));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case LSA_TRUSTED_DOMAIN_INFO_NAME:
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoName(ndr, NDR_BUFFERS, &r->name));
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET:
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_PASSWORD:
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoPassword(ndr, NDR_BUFFERS, &r->password));
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_BASIC:
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoBasic(ndr, NDR_BUFFERS, &r->info_basic));
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_INFO_EX:
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoInfoEx(ndr, NDR_BUFFERS, &r->info_ex));
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO:
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoAuthInfo(ndr, NDR_BUFFERS, &r->auth_info));
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_FULL_INFO:
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoFullInfo(ndr, NDR_BUFFERS, &r->full_info));
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_11:
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfo11(ndr, NDR_BUFFERS, &r->info11));
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_INFO_ALL:
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoInfoAll(ndr, NDR_BUFFERS, &r->info_all));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TrustedDomainInfo(struct ndr_print *ndr, const char *name, const union lsa_TrustedDomainInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "lsa_TrustedDomainInfo");
+ switch (level) {
+ case LSA_TRUSTED_DOMAIN_INFO_NAME:
+ ndr_print_lsa_TrustDomainInfoName(ndr, "name", &r->name);
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET:
+ ndr_print_lsa_TrustDomainInfoPosixOffset(ndr, "posix_offset", &r->posix_offset);
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_PASSWORD:
+ ndr_print_lsa_TrustDomainInfoPassword(ndr, "password", &r->password);
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_BASIC:
+ ndr_print_lsa_TrustDomainInfoBasic(ndr, "info_basic", &r->info_basic);
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_INFO_EX:
+ ndr_print_lsa_TrustDomainInfoInfoEx(ndr, "info_ex", &r->info_ex);
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO:
+ ndr_print_lsa_TrustDomainInfoAuthInfo(ndr, "auth_info", &r->auth_info);
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_FULL_INFO:
+ ndr_print_lsa_TrustDomainInfoFullInfo(ndr, "full_info", &r->full_info);
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_11:
+ ndr_print_lsa_TrustDomainInfo11(ndr, "info11", &r->info11);
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_INFO_ALL:
+ ndr_print_lsa_TrustDomainInfoInfoAll(ndr, "info_all", &r->info_all);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_lsa_DATA_BUF_PTR(struct ndr_push *ndr, int ndr_flags, const struct lsa_DATA_BUF_PTR *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->buf));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->buf) {
+ NDR_CHECK(ndr_push_lsa_DATA_BUF(ndr, NDR_SCALARS|NDR_BUFFERS, r->buf));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_DATA_BUF_PTR(struct ndr_pull *ndr, int ndr_flags, struct lsa_DATA_BUF_PTR *r)
+{
+ uint32_t _ptr_buf;
+ TALLOC_CTX *_mem_save_buf_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_buf));
+ if (_ptr_buf) {
+ NDR_PULL_ALLOC(ndr, r->buf);
+ } else {
+ r->buf = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->buf) {
+ _mem_save_buf_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->buf, 0);
+ NDR_CHECK(ndr_pull_lsa_DATA_BUF(ndr, NDR_SCALARS|NDR_BUFFERS, r->buf));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_buf_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_DATA_BUF_PTR(struct ndr_print *ndr, const char *name, const struct lsa_DATA_BUF_PTR *r)
+{
+ ndr_print_struct(ndr, name, "lsa_DATA_BUF_PTR");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buf", r->buf);
+ ndr->depth++;
+ if (r->buf) {
+ ndr_print_lsa_DATA_BUF(ndr, "buf", r->buf);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_RightSet(struct ndr_push *ndr, int ndr_flags, const struct lsa_RightSet *r)
+{
+ uint32_t cntr_names_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->names));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->names) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->names[cntr_names_1]));
+ }
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->names[cntr_names_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_RightSet(struct ndr_pull *ndr, int ndr_flags, struct lsa_RightSet *r)
+{
+ uint32_t _ptr_names;
+ uint32_t cntr_names_1;
+ TALLOC_CTX *_mem_save_names_0;
+ TALLOC_CTX *_mem_save_names_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 256) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_names));
+ if (_ptr_names) {
+ NDR_PULL_ALLOC(ndr, r->names);
+ } else {
+ r->names = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->names) {
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->names, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->names));
+ NDR_PULL_ALLOC_N(ndr, r->names, ndr_get_array_size(ndr, &r->names));
+ _mem_save_names_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->names, 0);
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->names[cntr_names_1]));
+ }
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->names[cntr_names_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, 0);
+ }
+ if (r->names) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->names, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_RightSet(struct ndr_print *ndr, const char *name, const struct lsa_RightSet *r)
+{
+ uint32_t cntr_names_1;
+ ndr_print_struct(ndr, name, "lsa_RightSet");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "names", r->names);
+ ndr->depth++;
+ if (r->names) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "names", (int)r->count);
+ ndr->depth++;
+ for (cntr_names_1=0;cntr_names_1<r->count;cntr_names_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_names_1) != -1) {
+ ndr_print_lsa_StringLarge(ndr, "names", &r->names[cntr_names_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_DomainListEx(struct ndr_push *ndr, int ndr_flags, const struct lsa_DomainListEx *r)
+{
+ uint32_t cntr_domains_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domains));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->domains) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_domains_1 = 0; cntr_domains_1 < r->count; cntr_domains_1++) {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoInfoEx(ndr, NDR_SCALARS, &r->domains[cntr_domains_1]));
+ }
+ for (cntr_domains_1 = 0; cntr_domains_1 < r->count; cntr_domains_1++) {
+ NDR_CHECK(ndr_push_lsa_TrustDomainInfoInfoEx(ndr, NDR_BUFFERS, &r->domains[cntr_domains_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_DomainListEx(struct ndr_pull *ndr, int ndr_flags, struct lsa_DomainListEx *r)
+{
+ uint32_t _ptr_domains;
+ uint32_t cntr_domains_1;
+ TALLOC_CTX *_mem_save_domains_0;
+ TALLOC_CTX *_mem_save_domains_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domains));
+ if (_ptr_domains) {
+ NDR_PULL_ALLOC(ndr, r->domains);
+ } else {
+ r->domains = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->domains) {
+ _mem_save_domains_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domains, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domains));
+ NDR_PULL_ALLOC_N(ndr, r->domains, ndr_get_array_size(ndr, &r->domains));
+ _mem_save_domains_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domains, 0);
+ for (cntr_domains_1 = 0; cntr_domains_1 < r->count; cntr_domains_1++) {
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoInfoEx(ndr, NDR_SCALARS, &r->domains[cntr_domains_1]));
+ }
+ for (cntr_domains_1 = 0; cntr_domains_1 < r->count; cntr_domains_1++) {
+ NDR_CHECK(ndr_pull_lsa_TrustDomainInfoInfoEx(ndr, NDR_BUFFERS, &r->domains[cntr_domains_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_0, 0);
+ }
+ if (r->domains) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->domains, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_DomainListEx(struct ndr_print *ndr, const char *name, const struct lsa_DomainListEx *r)
+{
+ uint32_t cntr_domains_1;
+ ndr_print_struct(ndr, name, "lsa_DomainListEx");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "domains", r->domains);
+ ndr->depth++;
+ if (r->domains) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "domains", (int)r->count);
+ ndr->depth++;
+ for (cntr_domains_1=0;cntr_domains_1<r->count;cntr_domains_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_domains_1) != -1) {
+ ndr_print_lsa_TrustDomainInfoInfoEx(ndr, "domains", &r->domains[cntr_domains_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_DomainInfoKerberos(struct ndr_push *ndr, int ndr_flags, const struct lsa_DomainInfoKerberos *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enforce_restrictions));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->service_tkt_lifetime));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->user_tkt_lifetime));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->user_tkt_renewaltime));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->clock_skew));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown6));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_DomainInfoKerberos(struct ndr_pull *ndr, int ndr_flags, struct lsa_DomainInfoKerberos *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enforce_restrictions));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->service_tkt_lifetime));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->user_tkt_lifetime));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->user_tkt_renewaltime));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->clock_skew));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown6));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_DomainInfoKerberos(struct ndr_print *ndr, const char *name, const struct lsa_DomainInfoKerberos *r)
+{
+ ndr_print_struct(ndr, name, "lsa_DomainInfoKerberos");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "enforce_restrictions", r->enforce_restrictions);
+ ndr_print_hyper(ndr, "service_tkt_lifetime", r->service_tkt_lifetime);
+ ndr_print_hyper(ndr, "user_tkt_lifetime", r->user_tkt_lifetime);
+ ndr_print_hyper(ndr, "user_tkt_renewaltime", r->user_tkt_renewaltime);
+ ndr_print_hyper(ndr, "clock_skew", r->clock_skew);
+ ndr_print_hyper(ndr, "unknown6", r->unknown6);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_DomainInfoEfs(struct ndr_push *ndr, int ndr_flags, const struct lsa_DomainInfoEfs *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->blob_size));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->efs_blob));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->efs_blob) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->blob_size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->efs_blob, r->blob_size));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_DomainInfoEfs(struct ndr_pull *ndr, int ndr_flags, struct lsa_DomainInfoEfs *r)
+{
+ uint32_t _ptr_efs_blob;
+ TALLOC_CTX *_mem_save_efs_blob_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->blob_size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_efs_blob));
+ if (_ptr_efs_blob) {
+ NDR_PULL_ALLOC(ndr, r->efs_blob);
+ } else {
+ r->efs_blob = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->efs_blob) {
+ _mem_save_efs_blob_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->efs_blob, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->efs_blob));
+ NDR_PULL_ALLOC_N(ndr, r->efs_blob, ndr_get_array_size(ndr, &r->efs_blob));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->efs_blob, ndr_get_array_size(ndr, &r->efs_blob)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_efs_blob_0, 0);
+ }
+ if (r->efs_blob) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->efs_blob, r->blob_size));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_DomainInfoEfs(struct ndr_print *ndr, const char *name, const struct lsa_DomainInfoEfs *r)
+{
+ ndr_print_struct(ndr, name, "lsa_DomainInfoEfs");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "blob_size", r->blob_size);
+ ndr_print_ptr(ndr, "efs_blob", r->efs_blob);
+ ndr->depth++;
+ if (r->efs_blob) {
+ ndr_print_array_uint8(ndr, "efs_blob", r->efs_blob, r->blob_size);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_DomainInformationPolicy(struct ndr_push *ndr, int ndr_flags, const union lsa_DomainInformationPolicy *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case LSA_DOMAIN_INFO_POLICY_EFS: {
+ NDR_CHECK(ndr_push_lsa_DomainInfoEfs(ndr, NDR_SCALARS, &r->efs_info));
+ break; }
+
+ case LSA_DOMAIN_INFO_POLICY_KERBEROS: {
+ NDR_CHECK(ndr_push_lsa_DomainInfoKerberos(ndr, NDR_SCALARS, &r->kerberos_info));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case LSA_DOMAIN_INFO_POLICY_EFS:
+ NDR_CHECK(ndr_push_lsa_DomainInfoEfs(ndr, NDR_BUFFERS, &r->efs_info));
+ break;
+
+ case LSA_DOMAIN_INFO_POLICY_KERBEROS:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_DomainInformationPolicy(struct ndr_pull *ndr, int ndr_flags, union lsa_DomainInformationPolicy *r)
+{
+ int level;
+ uint16_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case LSA_DOMAIN_INFO_POLICY_EFS: {
+ NDR_CHECK(ndr_pull_lsa_DomainInfoEfs(ndr, NDR_SCALARS, &r->efs_info));
+ break; }
+
+ case LSA_DOMAIN_INFO_POLICY_KERBEROS: {
+ NDR_CHECK(ndr_pull_lsa_DomainInfoKerberos(ndr, NDR_SCALARS, &r->kerberos_info));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case LSA_DOMAIN_INFO_POLICY_EFS:
+ NDR_CHECK(ndr_pull_lsa_DomainInfoEfs(ndr, NDR_BUFFERS, &r->efs_info));
+ break;
+
+ case LSA_DOMAIN_INFO_POLICY_KERBEROS:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_DomainInformationPolicy(struct ndr_print *ndr, const char *name, const union lsa_DomainInformationPolicy *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "lsa_DomainInformationPolicy");
+ switch (level) {
+ case LSA_DOMAIN_INFO_POLICY_EFS:
+ ndr_print_lsa_DomainInfoEfs(ndr, "efs_info", &r->efs_info);
+ break;
+
+ case LSA_DOMAIN_INFO_POLICY_KERBEROS:
+ ndr_print_lsa_DomainInfoKerberos(ndr, "kerberos_info", &r->kerberos_info);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_lsa_TranslatedName2(struct ndr_push *ndr, int ndr_flags, const struct lsa_TranslatedName2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_SidType(ndr, NDR_SCALARS, r->sid_type));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sid_index));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TranslatedName2(struct ndr_pull *ndr, int ndr_flags, struct lsa_TranslatedName2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_SidType(ndr, NDR_SCALARS, &r->sid_type));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sid_index));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TranslatedName2(struct ndr_print *ndr, const char *name, const struct lsa_TranslatedName2 *r)
+{
+ ndr_print_struct(ndr, name, "lsa_TranslatedName2");
+ ndr->depth++;
+ ndr_print_lsa_SidType(ndr, "sid_type", r->sid_type);
+ ndr_print_lsa_String(ndr, "name", &r->name);
+ ndr_print_uint32(ndr, "sid_index", r->sid_index);
+ ndr_print_uint32(ndr, "unknown", r->unknown);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TransNameArray2(struct ndr_push *ndr, int ndr_flags, const struct lsa_TransNameArray2 *r)
+{
+ uint32_t cntr_names_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->names));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->names) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_push_lsa_TranslatedName2(ndr, NDR_SCALARS, &r->names[cntr_names_1]));
+ }
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_push_lsa_TranslatedName2(ndr, NDR_BUFFERS, &r->names[cntr_names_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TransNameArray2(struct ndr_pull *ndr, int ndr_flags, struct lsa_TransNameArray2 *r)
+{
+ uint32_t _ptr_names;
+ uint32_t cntr_names_1;
+ TALLOC_CTX *_mem_save_names_0;
+ TALLOC_CTX *_mem_save_names_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 1000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_names));
+ if (_ptr_names) {
+ NDR_PULL_ALLOC(ndr, r->names);
+ } else {
+ r->names = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->names) {
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->names, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->names));
+ NDR_PULL_ALLOC_N(ndr, r->names, ndr_get_array_size(ndr, &r->names));
+ _mem_save_names_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->names, 0);
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_pull_lsa_TranslatedName2(ndr, NDR_SCALARS, &r->names[cntr_names_1]));
+ }
+ for (cntr_names_1 = 0; cntr_names_1 < r->count; cntr_names_1++) {
+ NDR_CHECK(ndr_pull_lsa_TranslatedName2(ndr, NDR_BUFFERS, &r->names[cntr_names_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, 0);
+ }
+ if (r->names) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->names, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TransNameArray2(struct ndr_print *ndr, const char *name, const struct lsa_TransNameArray2 *r)
+{
+ uint32_t cntr_names_1;
+ ndr_print_struct(ndr, name, "lsa_TransNameArray2");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "names", r->names);
+ ndr->depth++;
+ if (r->names) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "names", (int)r->count);
+ ndr->depth++;
+ for (cntr_names_1=0;cntr_names_1<r->count;cntr_names_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_names_1) != -1) {
+ ndr_print_lsa_TranslatedName2(ndr, "names", &r->names[cntr_names_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TranslatedSid2(struct ndr_push *ndr, int ndr_flags, const struct lsa_TranslatedSid2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_SidType(ndr, NDR_SCALARS, r->sid_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sid_index));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TranslatedSid2(struct ndr_pull *ndr, int ndr_flags, struct lsa_TranslatedSid2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_SidType(ndr, NDR_SCALARS, &r->sid_type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sid_index));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TranslatedSid2(struct ndr_print *ndr, const char *name, const struct lsa_TranslatedSid2 *r)
+{
+ ndr_print_struct(ndr, name, "lsa_TranslatedSid2");
+ ndr->depth++;
+ ndr_print_lsa_SidType(ndr, "sid_type", r->sid_type);
+ ndr_print_uint32(ndr, "rid", r->rid);
+ ndr_print_uint32(ndr, "sid_index", r->sid_index);
+ ndr_print_uint32(ndr, "unknown", r->unknown);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TransSidArray2(struct ndr_push *ndr, int ndr_flags, const struct lsa_TransSidArray2 *r)
+{
+ uint32_t cntr_sids_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sids));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sids) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->count; cntr_sids_1++) {
+ NDR_CHECK(ndr_push_lsa_TranslatedSid2(ndr, NDR_SCALARS, &r->sids[cntr_sids_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TransSidArray2(struct ndr_pull *ndr, int ndr_flags, struct lsa_TransSidArray2 *r)
+{
+ uint32_t _ptr_sids;
+ uint32_t cntr_sids_1;
+ TALLOC_CTX *_mem_save_sids_0;
+ TALLOC_CTX *_mem_save_sids_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 1000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sids));
+ if (_ptr_sids) {
+ NDR_PULL_ALLOC(ndr, r->sids);
+ } else {
+ r->sids = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sids) {
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->sids));
+ NDR_PULL_ALLOC_N(ndr, r->sids, ndr_get_array_size(ndr, &r->sids));
+ _mem_save_sids_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids, 0);
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->count; cntr_sids_1++) {
+ NDR_CHECK(ndr_pull_lsa_TranslatedSid2(ndr, NDR_SCALARS, &r->sids[cntr_sids_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, 0);
+ }
+ if (r->sids) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->sids, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TransSidArray2(struct ndr_print *ndr, const char *name, const struct lsa_TransSidArray2 *r)
+{
+ uint32_t cntr_sids_1;
+ ndr_print_struct(ndr, name, "lsa_TransSidArray2");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "sids", r->sids);
+ ndr->depth++;
+ if (r->sids) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "sids", (int)r->count);
+ ndr->depth++;
+ for (cntr_sids_1=0;cntr_sids_1<r->count;cntr_sids_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_sids_1) != -1) {
+ ndr_print_lsa_TranslatedSid2(ndr, "sids", &r->sids[cntr_sids_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TranslatedSid3(struct ndr_push *ndr, int ndr_flags, const struct lsa_TranslatedSid3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_SidType(ndr, NDR_SCALARS, r->sid_type));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sid_index));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TranslatedSid3(struct ndr_pull *ndr, int ndr_flags, struct lsa_TranslatedSid3 *r)
+{
+ uint32_t _ptr_sid;
+ TALLOC_CTX *_mem_save_sid_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_SidType(ndr, NDR_SCALARS, &r->sid_type));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sid));
+ if (_ptr_sid) {
+ NDR_PULL_ALLOC(ndr, r->sid);
+ } else {
+ r->sid = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sid_index));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sid) {
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TranslatedSid3(struct ndr_print *ndr, const char *name, const struct lsa_TranslatedSid3 *r)
+{
+ ndr_print_struct(ndr, name, "lsa_TranslatedSid3");
+ ndr->depth++;
+ ndr_print_lsa_SidType(ndr, "sid_type", r->sid_type);
+ ndr_print_ptr(ndr, "sid", r->sid);
+ ndr->depth++;
+ if (r->sid) {
+ ndr_print_dom_sid2(ndr, "sid", r->sid);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "sid_index", r->sid_index);
+ ndr_print_uint32(ndr, "unknown", r->unknown);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TransSidArray3(struct ndr_push *ndr, int ndr_flags, const struct lsa_TransSidArray3 *r)
+{
+ uint32_t cntr_sids_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sids));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sids) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->count; cntr_sids_1++) {
+ NDR_CHECK(ndr_push_lsa_TranslatedSid3(ndr, NDR_SCALARS, &r->sids[cntr_sids_1]));
+ }
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->count; cntr_sids_1++) {
+ NDR_CHECK(ndr_push_lsa_TranslatedSid3(ndr, NDR_BUFFERS, &r->sids[cntr_sids_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TransSidArray3(struct ndr_pull *ndr, int ndr_flags, struct lsa_TransSidArray3 *r)
+{
+ uint32_t _ptr_sids;
+ uint32_t cntr_sids_1;
+ TALLOC_CTX *_mem_save_sids_0;
+ TALLOC_CTX *_mem_save_sids_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 1000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sids));
+ if (_ptr_sids) {
+ NDR_PULL_ALLOC(ndr, r->sids);
+ } else {
+ r->sids = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sids) {
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->sids));
+ NDR_PULL_ALLOC_N(ndr, r->sids, ndr_get_array_size(ndr, &r->sids));
+ _mem_save_sids_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids, 0);
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->count; cntr_sids_1++) {
+ NDR_CHECK(ndr_pull_lsa_TranslatedSid3(ndr, NDR_SCALARS, &r->sids[cntr_sids_1]));
+ }
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->count; cntr_sids_1++) {
+ NDR_CHECK(ndr_pull_lsa_TranslatedSid3(ndr, NDR_BUFFERS, &r->sids[cntr_sids_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, 0);
+ }
+ if (r->sids) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->sids, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TransSidArray3(struct ndr_print *ndr, const char *name, const struct lsa_TransSidArray3 *r)
+{
+ uint32_t cntr_sids_1;
+ ndr_print_struct(ndr, name, "lsa_TransSidArray3");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "sids", r->sids);
+ ndr->depth++;
+ if (r->sids) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "sids", (int)r->count);
+ ndr->depth++;
+ for (cntr_sids_1=0;cntr_sids_1<r->count;cntr_sids_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_sids_1) != -1) {
+ ndr_print_lsa_TranslatedSid3(ndr, "sids", &r->sids[cntr_sids_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_ForestTrustBinaryData(struct ndr_push *ndr, int ndr_flags, const struct lsa_ForestTrustBinaryData *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data, r->length));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_ForestTrustBinaryData(struct ndr_pull *ndr, int ndr_flags, struct lsa_ForestTrustBinaryData *r)
+{
+ uint32_t _ptr_data;
+ TALLOC_CTX *_mem_save_data_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->length));
+ if (r->length < 0 || r->length > 131072) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data));
+ if (_ptr_data) {
+ NDR_PULL_ALLOC(ndr, r->data);
+ } else {
+ r->data = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->data, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->data));
+ NDR_PULL_ALLOC_N(ndr, r->data, ndr_get_array_size(ndr, &r->data));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data, ndr_get_array_size(ndr, &r->data)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, 0);
+ }
+ if (r->data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->data, r->length));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_ForestTrustBinaryData(struct ndr_print *ndr, const char *name, const struct lsa_ForestTrustBinaryData *r)
+{
+ ndr_print_struct(ndr, name, "lsa_ForestTrustBinaryData");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "length", r->length);
+ ndr_print_ptr(ndr, "data", r->data);
+ ndr->depth++;
+ if (r->data) {
+ ndr_print_array_uint8(ndr, "data", r->data, r->length);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_ForestTrustDomainInfo(struct ndr_push *ndr, int ndr_flags, const struct lsa_ForestTrustDomainInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain_sid));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->dns_domain_name));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->netbios_domain_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->domain_sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->domain_sid));
+ }
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->dns_domain_name));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->netbios_domain_name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_ForestTrustDomainInfo(struct ndr_pull *ndr, int ndr_flags, struct lsa_ForestTrustDomainInfo *r)
+{
+ uint32_t _ptr_domain_sid;
+ TALLOC_CTX *_mem_save_domain_sid_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_sid));
+ if (_ptr_domain_sid) {
+ NDR_PULL_ALLOC(ndr, r->domain_sid);
+ } else {
+ r->domain_sid = NULL;
+ }
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->dns_domain_name));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->netbios_domain_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->domain_sid) {
+ _mem_save_domain_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain_sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->domain_sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_sid_0, 0);
+ }
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->dns_domain_name));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->netbios_domain_name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_ForestTrustDomainInfo(struct ndr_print *ndr, const char *name, const struct lsa_ForestTrustDomainInfo *r)
+{
+ ndr_print_struct(ndr, name, "lsa_ForestTrustDomainInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_sid", r->domain_sid);
+ ndr->depth++;
+ if (r->domain_sid) {
+ ndr_print_dom_sid2(ndr, "domain_sid", r->domain_sid);
+ }
+ ndr->depth--;
+ ndr_print_lsa_StringLarge(ndr, "dns_domain_name", &r->dns_domain_name);
+ ndr_print_lsa_StringLarge(ndr, "netbios_domain_name", &r->netbios_domain_name);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_ForestTrustData(struct ndr_push *ndr, int ndr_flags, const union lsa_ForestTrustData *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case LSA_FOREST_TRUST_TOP_LEVEL_NAME: {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->top_level_name));
+ break; }
+
+ case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX: {
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->top_level_name_ex));
+ break; }
+
+ case LSA_FOREST_TRUST_DOMAIN_INFO: {
+ NDR_CHECK(ndr_push_lsa_ForestTrustDomainInfo(ndr, NDR_SCALARS, &r->domain_info));
+ break; }
+
+ default: {
+ NDR_CHECK(ndr_push_lsa_ForestTrustBinaryData(ndr, NDR_SCALARS, &r->data));
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->top_level_name));
+ break;
+
+ case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->top_level_name_ex));
+ break;
+
+ case LSA_FOREST_TRUST_DOMAIN_INFO:
+ NDR_CHECK(ndr_push_lsa_ForestTrustDomainInfo(ndr, NDR_BUFFERS, &r->domain_info));
+ break;
+
+ default:
+ NDR_CHECK(ndr_push_lsa_ForestTrustBinaryData(ndr, NDR_BUFFERS, &r->data));
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_ForestTrustData(struct ndr_pull *ndr, int ndr_flags, union lsa_ForestTrustData *r)
+{
+ int level;
+ uint32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case LSA_FOREST_TRUST_TOP_LEVEL_NAME: {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->top_level_name));
+ break; }
+
+ case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX: {
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->top_level_name_ex));
+ break; }
+
+ case LSA_FOREST_TRUST_DOMAIN_INFO: {
+ NDR_CHECK(ndr_pull_lsa_ForestTrustDomainInfo(ndr, NDR_SCALARS, &r->domain_info));
+ break; }
+
+ default: {
+ NDR_CHECK(ndr_pull_lsa_ForestTrustBinaryData(ndr, NDR_SCALARS, &r->data));
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->top_level_name));
+ break;
+
+ case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->top_level_name_ex));
+ break;
+
+ case LSA_FOREST_TRUST_DOMAIN_INFO:
+ NDR_CHECK(ndr_pull_lsa_ForestTrustDomainInfo(ndr, NDR_BUFFERS, &r->domain_info));
+ break;
+
+ default:
+ NDR_CHECK(ndr_pull_lsa_ForestTrustBinaryData(ndr, NDR_BUFFERS, &r->data));
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_ForestTrustData(struct ndr_print *ndr, const char *name, const union lsa_ForestTrustData *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "lsa_ForestTrustData");
+ switch (level) {
+ case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
+ ndr_print_lsa_String(ndr, "top_level_name", &r->top_level_name);
+ break;
+
+ case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
+ ndr_print_lsa_StringLarge(ndr, "top_level_name_ex", &r->top_level_name_ex);
+ break;
+
+ case LSA_FOREST_TRUST_DOMAIN_INFO:
+ ndr_print_lsa_ForestTrustDomainInfo(ndr, "domain_info", &r->domain_info);
+ break;
+
+ default:
+ ndr_print_lsa_ForestTrustBinaryData(ndr, "data", &r->data);
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_lsa_ForestTrustRecordType(struct ndr_push *ndr, int ndr_flags, enum lsa_ForestTrustRecordType r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_ForestTrustRecordType(struct ndr_pull *ndr, int ndr_flags, enum lsa_ForestTrustRecordType *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_ForestTrustRecordType(struct ndr_print *ndr, const char *name, enum lsa_ForestTrustRecordType r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case LSA_FOREST_TRUST_TOP_LEVEL_NAME: val = "LSA_FOREST_TRUST_TOP_LEVEL_NAME"; break;
+ case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX: val = "LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX"; break;
+ case LSA_FOREST_TRUST_DOMAIN_INFO: val = "LSA_FOREST_TRUST_DOMAIN_INFO"; break;
+ case LSA_FOREST_TRUST_RECORD_TYPE_LAST: val = "LSA_FOREST_TRUST_RECORD_TYPE_LAST"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_lsa_ForestTrustRecord(struct ndr_push *ndr, int ndr_flags, const struct lsa_ForestTrustRecord *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_lsa_ForestTrustRecordType(ndr, NDR_SCALARS, r->level));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->forest_trust_data, r->level));
+ NDR_CHECK(ndr_push_lsa_ForestTrustData(ndr, NDR_SCALARS, &r->forest_trust_data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_ForestTrustData(ndr, NDR_BUFFERS, &r->forest_trust_data));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_ForestTrustRecord(struct ndr_pull *ndr, int ndr_flags, struct lsa_ForestTrustRecord *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_lsa_ForestTrustRecordType(ndr, NDR_SCALARS, &r->level));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->forest_trust_data, r->level));
+ NDR_CHECK(ndr_pull_lsa_ForestTrustData(ndr, NDR_SCALARS, &r->forest_trust_data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_ForestTrustData(ndr, NDR_BUFFERS, &r->forest_trust_data));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_ForestTrustRecord(struct ndr_print *ndr, const char *name, const struct lsa_ForestTrustRecord *r)
+{
+ ndr_print_struct(ndr, name, "lsa_ForestTrustRecord");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "flags", r->flags);
+ ndr_print_lsa_ForestTrustRecordType(ndr, "level", r->level);
+ ndr_print_hyper(ndr, "unknown", r->unknown);
+ ndr_print_set_switch_value(ndr, &r->forest_trust_data, r->level);
+ ndr_print_lsa_ForestTrustData(ndr, "forest_trust_data", &r->forest_trust_data);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_ForestTrustInformation(struct ndr_push *ndr, int ndr_flags, const struct lsa_ForestTrustInformation *r)
+{
+ uint32_t cntr_entries_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->entries));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->entries) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->entries[cntr_entries_1]));
+ }
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ if (r->entries[cntr_entries_1]) {
+ NDR_CHECK(ndr_push_lsa_ForestTrustRecord(ndr, NDR_SCALARS|NDR_BUFFERS, r->entries[cntr_entries_1]));
+ }
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_ForestTrustInformation(struct ndr_pull *ndr, int ndr_flags, struct lsa_ForestTrustInformation *r)
+{
+ uint32_t _ptr_entries;
+ uint32_t cntr_entries_1;
+ TALLOC_CTX *_mem_save_entries_0;
+ TALLOC_CTX *_mem_save_entries_1;
+ TALLOC_CTX *_mem_save_entries_2;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 4000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_entries));
+ if (_ptr_entries) {
+ NDR_PULL_ALLOC(ndr, r->entries);
+ } else {
+ r->entries = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->entries) {
+ _mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->entries));
+ NDR_PULL_ALLOC_N(ndr, r->entries, ndr_get_array_size(ndr, &r->entries));
+ _mem_save_entries_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_entries));
+ if (_ptr_entries) {
+ NDR_PULL_ALLOC(ndr, r->entries[cntr_entries_1]);
+ } else {
+ r->entries[cntr_entries_1] = NULL;
+ }
+ }
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ if (r->entries[cntr_entries_1]) {
+ _mem_save_entries_2 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->entries[cntr_entries_1], 0);
+ NDR_CHECK(ndr_pull_lsa_ForestTrustRecord(ndr, NDR_SCALARS|NDR_BUFFERS, r->entries[cntr_entries_1]));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_2, 0);
+ }
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0);
+ }
+ if (r->entries) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->entries, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_ForestTrustInformation(struct ndr_print *ndr, const char *name, const struct lsa_ForestTrustInformation *r)
+{
+ uint32_t cntr_entries_1;
+ ndr_print_struct(ndr, name, "lsa_ForestTrustInformation");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "entries", r->entries);
+ ndr->depth++;
+ if (r->entries) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "entries", (int)r->count);
+ ndr->depth++;
+ for (cntr_entries_1=0;cntr_entries_1<r->count;cntr_entries_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_entries_1) != -1) {
+ ndr_print_ptr(ndr, "entries", r->entries[cntr_entries_1]);
+ ndr->depth++;
+ if (r->entries[cntr_entries_1]) {
+ ndr_print_lsa_ForestTrustRecord(ndr, "entries", r->entries[cntr_entries_1]);
+ }
+ ndr->depth--;
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_Close(struct ndr_push *ndr, int flags, const struct lsa_Close *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_Close(struct ndr_pull *ndr, int flags, struct lsa_Close *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ *r->out.handle = *r->in.handle;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_Close(struct ndr_print *ndr, const char *name, int flags, const struct lsa_Close *r)
+{
+ ndr_print_struct(ndr, name, "lsa_Close");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_Close");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_Close");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_Delete(struct ndr_push *ndr, int flags, const struct lsa_Delete *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_Delete(struct ndr_pull *ndr, int flags, struct lsa_Delete *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_Delete(struct ndr_print *ndr, const char *name, int flags, const struct lsa_Delete *r)
+{
+ ndr_print_struct(ndr, name, "lsa_Delete");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_Delete");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_Delete");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_EnumPrivs(struct ndr_push *ndr, int flags, const struct lsa_EnumPrivs *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.resume_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_count));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.resume_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ if (r->out.privs == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_PrivArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.privs));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_EnumPrivs(struct ndr_pull *ndr, int flags, struct lsa_EnumPrivs *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ TALLOC_CTX *_mem_save_privs_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ }
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_count));
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ *r->out.resume_handle = *r->in.resume_handle;
+ NDR_PULL_ALLOC(ndr, r->out.privs);
+ ZERO_STRUCTP(r->out.privs);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ }
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.privs);
+ }
+ _mem_save_privs_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.privs, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_PrivArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.privs));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_privs_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_EnumPrivs(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumPrivs *r)
+{
+ ndr_print_struct(ndr, name, "lsa_EnumPrivs");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_EnumPrivs");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_count", r->in.max_count);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_EnumPrivs");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "privs", r->out.privs);
+ ndr->depth++;
+ ndr_print_lsa_PrivArray(ndr, "privs", r->out.privs);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_QuerySecurity(struct ndr_push *ndr, int flags, const struct lsa_QuerySecurity *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_security_secinfo(ndr, NDR_SCALARS, r->in.sec_info));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.sdbuf == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.sdbuf));
+ if (*r->out.sdbuf) {
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.sdbuf));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_QuerySecurity(struct ndr_pull *ndr, int flags, struct lsa_QuerySecurity *r)
+{
+ uint32_t _ptr_sdbuf;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sdbuf_0;
+ TALLOC_CTX *_mem_save_sdbuf_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_security_secinfo(ndr, NDR_SCALARS, &r->in.sec_info));
+ NDR_PULL_ALLOC(ndr, r->out.sdbuf);
+ ZERO_STRUCTP(r->out.sdbuf);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sdbuf);
+ }
+ _mem_save_sdbuf_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sdbuf, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sdbuf));
+ if (_ptr_sdbuf) {
+ NDR_PULL_ALLOC(ndr, *r->out.sdbuf);
+ } else {
+ *r->out.sdbuf = NULL;
+ }
+ if (*r->out.sdbuf) {
+ _mem_save_sdbuf_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.sdbuf, 0);
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.sdbuf));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sdbuf_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sdbuf_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_QuerySecurity(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QuerySecurity *r)
+{
+ ndr_print_struct(ndr, name, "lsa_QuerySecurity");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_QuerySecurity");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_security_secinfo(ndr, "sec_info", r->in.sec_info);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_QuerySecurity");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sdbuf", r->out.sdbuf);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sdbuf", *r->out.sdbuf);
+ ndr->depth++;
+ if (*r->out.sdbuf) {
+ ndr_print_sec_desc_buf(ndr, "sdbuf", *r->out.sdbuf);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_SetSecObj(struct ndr_push *ndr, int flags, const struct lsa_SetSecObj *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_security_secinfo(ndr, NDR_SCALARS, r->in.sec_info));
+ if (r->in.sdbuf == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sdbuf));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_SetSecObj(struct ndr_pull *ndr, int flags, struct lsa_SetSecObj *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sdbuf_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_security_secinfo(ndr, NDR_SCALARS, &r->in.sec_info));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sdbuf);
+ }
+ _mem_save_sdbuf_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sdbuf, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sdbuf));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sdbuf_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_SetSecObj(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetSecObj *r)
+{
+ ndr_print_struct(ndr, name, "lsa_SetSecObj");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_SetSecObj");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_security_secinfo(ndr, "sec_info", r->in.sec_info);
+ ndr_print_ptr(ndr, "sdbuf", r->in.sdbuf);
+ ndr->depth++;
+ ndr_print_sec_desc_buf(ndr, "sdbuf", r->in.sdbuf);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_SetSecObj");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_ChangePassword(struct ndr_push *ndr, int flags, const struct lsa_ChangePassword *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_ChangePassword(struct ndr_pull *ndr, int flags, struct lsa_ChangePassword *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_ChangePassword(struct ndr_print *ndr, const char *name, int flags, const struct lsa_ChangePassword *r)
+{
+ ndr_print_struct(ndr, name, "lsa_ChangePassword");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_ChangePassword");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_ChangePassword");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_OpenPolicy(struct ndr_push *ndr, int flags, const struct lsa_OpenPolicy *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.system_name));
+ }
+ if (r->in.attr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_ObjectAttribute(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.attr));
+ NDR_CHECK(ndr_push_lsa_PolicyAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_OpenPolicy(struct ndr_pull *ndr, int flags, struct lsa_OpenPolicy *r)
+{
+ uint32_t _ptr_system_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_attr_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.system_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.attr);
+ }
+ _mem_save_attr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.attr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_ObjectAttribute(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.attr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_attr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_PolicyAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_OpenPolicy(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenPolicy *r)
+{
+ ndr_print_struct(ndr, name, "lsa_OpenPolicy");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_OpenPolicy");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_uint16(ndr, "system_name", *r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "attr", r->in.attr);
+ ndr->depth++;
+ ndr_print_lsa_ObjectAttribute(ndr, "attr", r->in.attr);
+ ndr->depth--;
+ ndr_print_lsa_PolicyAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_OpenPolicy");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_QueryInfoPolicy(struct ndr_push *ndr, int flags, const struct lsa_QueryInfoPolicy *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_lsa_PolicyInfo(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.info));
+ if (*r->out.info) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_lsa_PolicyInformation(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_QueryInfoPolicy(struct ndr_pull *ndr, int flags, struct lsa_QueryInfoPolicy *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_PolicyInfo(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ } else {
+ *r->out.info = NULL;
+ }
+ if (*r->out.info) {
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.info, 0);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_lsa_PolicyInformation(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_QueryInfoPolicy(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryInfoPolicy *r)
+{
+ ndr_print_struct(ndr, name, "lsa_QueryInfoPolicy");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_QueryInfoPolicy");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_lsa_PolicyInfo(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_QueryInfoPolicy");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", *r->out.info);
+ ndr->depth++;
+ if (*r->out.info) {
+ ndr_print_set_switch_value(ndr, *r->out.info, r->in.level);
+ ndr_print_lsa_PolicyInformation(ndr, "info", *r->out.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_SetInfoPolicy(struct ndr_push *ndr, int flags, const struct lsa_SetInfoPolicy *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_lsa_PolicyInfo(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_lsa_PolicyInformation(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_SetInfoPolicy(struct ndr_pull *ndr, int flags, struct lsa_SetInfoPolicy *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_PolicyInfo(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_lsa_PolicyInformation(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_SetInfoPolicy(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetInfoPolicy *r)
+{
+ ndr_print_struct(ndr, name, "lsa_SetInfoPolicy");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_SetInfoPolicy");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_lsa_PolicyInfo(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.info, r->in.level);
+ ndr_print_lsa_PolicyInformation(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_SetInfoPolicy");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_ClearAuditLog(struct ndr_push *ndr, int flags, const struct lsa_ClearAuditLog *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_ClearAuditLog(struct ndr_pull *ndr, int flags, struct lsa_ClearAuditLog *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_ClearAuditLog(struct ndr_print *ndr, const char *name, int flags, const struct lsa_ClearAuditLog *r)
+{
+ ndr_print_struct(ndr, name, "lsa_ClearAuditLog");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_ClearAuditLog");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_ClearAuditLog");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_CreateAccount(struct ndr_push *ndr, int flags, const struct lsa_CreateAccount *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.sid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.acct_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.acct_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_CreateAccount(struct ndr_pull *ndr, int flags, struct lsa_CreateAccount *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sid_0;
+ TALLOC_CTX *_mem_save_acct_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sid);
+ }
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.acct_handle);
+ ZERO_STRUCTP(r->out.acct_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.acct_handle);
+ }
+ _mem_save_acct_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.acct_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.acct_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_acct_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_CreateAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CreateAccount *r)
+{
+ ndr_print_struct(ndr, name, "lsa_CreateAccount");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_CreateAccount");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sid", r->in.sid);
+ ndr->depth++;
+ ndr_print_dom_sid2(ndr, "sid", r->in.sid);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_CreateAccount");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "acct_handle", r->out.acct_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "acct_handle", r->out.acct_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_EnumAccounts(struct ndr_push *ndr, int flags, const struct lsa_EnumAccounts *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.resume_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_entries));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.resume_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ if (r->out.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sids));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_EnumAccounts(struct ndr_pull *ndr, int flags, struct lsa_EnumAccounts *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ TALLOC_CTX *_mem_save_sids_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ }
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.num_entries));
+ if (r->in.num_entries < 0 || r->in.num_entries > 8192) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ *r->out.resume_handle = *r->in.resume_handle;
+ NDR_PULL_ALLOC(ndr, r->out.sids);
+ ZERO_STRUCTP(r->out.sids);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ }
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_EnumAccounts(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumAccounts *r)
+{
+ ndr_print_struct(ndr, name, "lsa_EnumAccounts");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_EnumAccounts");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "num_entries", r->in.num_entries);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_EnumAccounts");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sids", r->out.sids);
+ ndr->depth++;
+ ndr_print_lsa_SidArray(ndr, "sids", r->out.sids);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_CreateTrustedDomain(struct ndr_push *ndr, int flags, const struct lsa_CreateTrustedDomain *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_DomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.trustdom_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.trustdom_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_CreateTrustedDomain(struct ndr_pull *ndr, int flags, struct lsa_CreateTrustedDomain *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_trustdom_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_DomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.trustdom_handle);
+ ZERO_STRUCTP(r->out.trustdom_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.trustdom_handle);
+ }
+ _mem_save_trustdom_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.trustdom_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.trustdom_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_trustdom_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_CreateTrustedDomain(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CreateTrustedDomain *r)
+{
+ ndr_print_struct(ndr, name, "lsa_CreateTrustedDomain");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_CreateTrustedDomain");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_lsa_DomainInfo(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_CreateTrustedDomain");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "trustdom_handle", r->out.trustdom_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "trustdom_handle", r->out.trustdom_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_EnumTrustDom(struct ndr_push *ndr, int flags, const struct lsa_EnumTrustDom *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.resume_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_size));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.resume_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ if (r->out.domains == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_DomainList(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.domains));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_EnumTrustDom(struct ndr_pull *ndr, int flags, struct lsa_EnumTrustDom *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ TALLOC_CTX *_mem_save_domains_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ }
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_size));
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ *r->out.resume_handle = *r->in.resume_handle;
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ ZERO_STRUCTP(r->out.domains);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ }
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ }
+ _mem_save_domains_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.domains, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_DomainList(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.domains));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_EnumTrustDom(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumTrustDom *r)
+{
+ ndr_print_struct(ndr, name, "lsa_EnumTrustDom");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_EnumTrustDom");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_size", r->in.max_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_EnumTrustDom");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domains", r->out.domains);
+ ndr->depth++;
+ ndr_print_lsa_DomainList(ndr, "domains", r->out.domains);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_LookupNames(struct ndr_push *ndr, int flags, const struct lsa_LookupNames *r)
+{
+ uint32_t cntr_names_0;
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_names));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_names));
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->in.names[cntr_names_0]));
+ }
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->in.names[cntr_names_0]));
+ }
+ if (r->in.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_TransSidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ NDR_CHECK(ndr_push_lsa_LookupNamesLevel(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.count == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.count));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.domains == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.domains));
+ if (*r->out.domains) {
+ NDR_CHECK(ndr_push_lsa_RefDomainList(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.domains));
+ }
+ if (r->out.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_TransSidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sids));
+ if (r->out.count == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.count));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_LookupNames(struct ndr_pull *ndr, int flags, struct lsa_LookupNames *r)
+{
+ uint32_t cntr_names_0;
+ uint32_t _ptr_domains;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_names_0;
+ TALLOC_CTX *_mem_save_domains_0;
+ TALLOC_CTX *_mem_save_domains_1;
+ TALLOC_CTX *_mem_save_sids_0;
+ TALLOC_CTX *_mem_save_count_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.num_names));
+ if (r->in.num_names < 0 || r->in.num_names > 1000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.names));
+ NDR_PULL_ALLOC_N(ndr, r->in.names, ndr_get_array_size(ndr, &r->in.names));
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.names, 0);
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->in.names[cntr_names_0]));
+ }
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->in.names[cntr_names_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, 0);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TransSidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_LookupNamesLevel(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.count);
+ }
+ _mem_save_count_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.count, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.count));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_count_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ ZERO_STRUCTP(r->out.domains);
+ NDR_PULL_ALLOC(ndr, r->out.sids);
+ *r->out.sids = *r->in.sids;
+ NDR_PULL_ALLOC(ndr, r->out.count);
+ *r->out.count = *r->in.count;
+ if (r->in.names) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.names, r->in.num_names));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ }
+ _mem_save_domains_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.domains, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domains));
+ if (_ptr_domains) {
+ NDR_PULL_ALLOC(ndr, *r->out.domains);
+ } else {
+ *r->out.domains = NULL;
+ }
+ if (*r->out.domains) {
+ _mem_save_domains_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.domains, 0);
+ NDR_CHECK(ndr_pull_lsa_RefDomainList(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.domains));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TransSidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.count);
+ }
+ _mem_save_count_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.count, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.count));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_count_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LookupNames(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupNames *r)
+{
+ uint32_t cntr_names_0;
+ ndr_print_struct(ndr, name, "lsa_LookupNames");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LookupNames");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "num_names", r->in.num_names);
+ ndr->print(ndr, "%s: ARRAY(%d)", "names", (int)r->in.num_names);
+ ndr->depth++;
+ for (cntr_names_0=0;cntr_names_0<r->in.num_names;cntr_names_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_names_0) != -1) {
+ ndr_print_lsa_String(ndr, "names", &r->in.names[cntr_names_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sids", r->in.sids);
+ ndr->depth++;
+ ndr_print_lsa_TransSidArray(ndr, "sids", r->in.sids);
+ ndr->depth--;
+ ndr_print_lsa_LookupNamesLevel(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "count", r->in.count);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", *r->in.count);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LookupNames");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domains", r->out.domains);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domains", *r->out.domains);
+ ndr->depth++;
+ if (*r->out.domains) {
+ ndr_print_lsa_RefDomainList(ndr, "domains", *r->out.domains);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sids", r->out.sids);
+ ndr->depth++;
+ ndr_print_lsa_TransSidArray(ndr, "sids", r->out.sids);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "count", r->out.count);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", *r->out.count);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_LookupSids(struct ndr_push *ndr, int flags, const struct lsa_LookupSids *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ if (r->in.names == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_TransNameArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.names));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.count == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.count));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.domains == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.domains));
+ if (*r->out.domains) {
+ NDR_CHECK(ndr_push_lsa_RefDomainList(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.domains));
+ }
+ if (r->out.names == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_TransNameArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.names));
+ if (r->out.count == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.count));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_LookupSids(struct ndr_pull *ndr, int flags, struct lsa_LookupSids *r)
+{
+ uint32_t _ptr_domains;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sids_0;
+ TALLOC_CTX *_mem_save_domains_0;
+ TALLOC_CTX *_mem_save_domains_1;
+ TALLOC_CTX *_mem_save_names_0;
+ TALLOC_CTX *_mem_save_count_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.names);
+ }
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.names, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TransNameArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.names));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.count);
+ }
+ _mem_save_count_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.count, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.count));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_count_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ ZERO_STRUCTP(r->out.domains);
+ NDR_PULL_ALLOC(ndr, r->out.names);
+ *r->out.names = *r->in.names;
+ NDR_PULL_ALLOC(ndr, r->out.count);
+ *r->out.count = *r->in.count;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ }
+ _mem_save_domains_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.domains, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domains));
+ if (_ptr_domains) {
+ NDR_PULL_ALLOC(ndr, *r->out.domains);
+ } else {
+ *r->out.domains = NULL;
+ }
+ if (*r->out.domains) {
+ _mem_save_domains_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.domains, 0);
+ NDR_CHECK(ndr_pull_lsa_RefDomainList(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.domains));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.names);
+ }
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.names, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TransNameArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.names));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.count);
+ }
+ _mem_save_count_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.count, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.count));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_count_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LookupSids(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupSids *r)
+{
+ ndr_print_struct(ndr, name, "lsa_LookupSids");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LookupSids");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sids", r->in.sids);
+ ndr->depth++;
+ ndr_print_lsa_SidArray(ndr, "sids", r->in.sids);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "names", r->in.names);
+ ndr->depth++;
+ ndr_print_lsa_TransNameArray(ndr, "names", r->in.names);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "count", r->in.count);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", *r->in.count);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LookupSids");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domains", r->out.domains);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domains", *r->out.domains);
+ ndr->depth++;
+ if (*r->out.domains) {
+ ndr_print_lsa_RefDomainList(ndr, "domains", *r->out.domains);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "names", r->out.names);
+ ndr->depth++;
+ ndr_print_lsa_TransNameArray(ndr, "names", r->out.names);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "count", r->out.count);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", *r->out.count);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_CreateSecret(struct ndr_push *ndr, int flags, const struct lsa_CreateSecret *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.sec_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sec_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_CreateSecret(struct ndr_pull *ndr, int flags, struct lsa_CreateSecret *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sec_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.sec_handle);
+ ZERO_STRUCTP(r->out.sec_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sec_handle);
+ }
+ _mem_save_sec_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sec_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sec_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sec_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_CreateSecret(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CreateSecret *r)
+{
+ ndr_print_struct(ndr, name, "lsa_CreateSecret");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_CreateSecret");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_lsa_String(ndr, "name", &r->in.name);
+ ndr_print_uint32(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_CreateSecret");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sec_handle", r->out.sec_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "sec_handle", r->out.sec_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_OpenAccount(struct ndr_push *ndr, int flags, const struct lsa_OpenAccount *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.sid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.acct_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.acct_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_OpenAccount(struct ndr_pull *ndr, int flags, struct lsa_OpenAccount *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sid_0;
+ TALLOC_CTX *_mem_save_acct_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sid);
+ }
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.acct_handle);
+ ZERO_STRUCTP(r->out.acct_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.acct_handle);
+ }
+ _mem_save_acct_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.acct_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.acct_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_acct_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_OpenAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenAccount *r)
+{
+ ndr_print_struct(ndr, name, "lsa_OpenAccount");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_OpenAccount");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sid", r->in.sid);
+ ndr->depth++;
+ ndr_print_dom_sid2(ndr, "sid", r->in.sid);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_OpenAccount");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "acct_handle", r->out.acct_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "acct_handle", r->out.acct_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_EnumPrivsAccount(struct ndr_push *ndr, int flags, const struct lsa_EnumPrivsAccount *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.privs == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.privs));
+ if (*r->out.privs) {
+ NDR_CHECK(ndr_push_lsa_PrivilegeSet(ndr, NDR_SCALARS, *r->out.privs));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_EnumPrivsAccount(struct ndr_pull *ndr, int flags, struct lsa_EnumPrivsAccount *r)
+{
+ uint32_t _ptr_privs;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_privs_0;
+ TALLOC_CTX *_mem_save_privs_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.privs);
+ ZERO_STRUCTP(r->out.privs);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.privs);
+ }
+ _mem_save_privs_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.privs, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_privs));
+ if (_ptr_privs) {
+ NDR_PULL_ALLOC(ndr, *r->out.privs);
+ } else {
+ *r->out.privs = NULL;
+ }
+ if (*r->out.privs) {
+ _mem_save_privs_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.privs, 0);
+ NDR_CHECK(ndr_pull_lsa_PrivilegeSet(ndr, NDR_SCALARS, *r->out.privs));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_privs_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_privs_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_EnumPrivsAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumPrivsAccount *r)
+{
+ ndr_print_struct(ndr, name, "lsa_EnumPrivsAccount");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_EnumPrivsAccount");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_EnumPrivsAccount");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "privs", r->out.privs);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "privs", *r->out.privs);
+ ndr->depth++;
+ if (*r->out.privs) {
+ ndr_print_lsa_PrivilegeSet(ndr, "privs", *r->out.privs);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_AddPrivilegesToAccount(struct ndr_push *ndr, int flags, const struct lsa_AddPrivilegesToAccount *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.privs == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_PrivilegeSet(ndr, NDR_SCALARS, r->in.privs));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_AddPrivilegesToAccount(struct ndr_pull *ndr, int flags, struct lsa_AddPrivilegesToAccount *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_privs_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.privs);
+ }
+ _mem_save_privs_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.privs, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_PrivilegeSet(ndr, NDR_SCALARS, r->in.privs));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_privs_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_AddPrivilegesToAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_AddPrivilegesToAccount *r)
+{
+ ndr_print_struct(ndr, name, "lsa_AddPrivilegesToAccount");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_AddPrivilegesToAccount");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "privs", r->in.privs);
+ ndr->depth++;
+ ndr_print_lsa_PrivilegeSet(ndr, "privs", r->in.privs);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_AddPrivilegesToAccount");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_RemovePrivilegesFromAccount(struct ndr_push *ndr, int flags, const struct lsa_RemovePrivilegesFromAccount *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.remove_all));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.privs));
+ if (r->in.privs) {
+ NDR_CHECK(ndr_push_lsa_PrivilegeSet(ndr, NDR_SCALARS, r->in.privs));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_RemovePrivilegesFromAccount(struct ndr_pull *ndr, int flags, struct lsa_RemovePrivilegesFromAccount *r)
+{
+ uint32_t _ptr_privs;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_privs_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.remove_all));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_privs));
+ if (_ptr_privs) {
+ NDR_PULL_ALLOC(ndr, r->in.privs);
+ } else {
+ r->in.privs = NULL;
+ }
+ if (r->in.privs) {
+ _mem_save_privs_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.privs, 0);
+ NDR_CHECK(ndr_pull_lsa_PrivilegeSet(ndr, NDR_SCALARS, r->in.privs));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_privs_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_RemovePrivilegesFromAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_RemovePrivilegesFromAccount *r)
+{
+ ndr_print_struct(ndr, name, "lsa_RemovePrivilegesFromAccount");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_RemovePrivilegesFromAccount");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint8(ndr, "remove_all", r->in.remove_all);
+ ndr_print_ptr(ndr, "privs", r->in.privs);
+ ndr->depth++;
+ if (r->in.privs) {
+ ndr_print_lsa_PrivilegeSet(ndr, "privs", r->in.privs);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_RemovePrivilegesFromAccount");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_GetQuotasForAccount(struct ndr_push *ndr, int flags, const struct lsa_GetQuotasForAccount *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_GetQuotasForAccount(struct ndr_pull *ndr, int flags, struct lsa_GetQuotasForAccount *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_GetQuotasForAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_GetQuotasForAccount *r)
+{
+ ndr_print_struct(ndr, name, "lsa_GetQuotasForAccount");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_GetQuotasForAccount");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_GetQuotasForAccount");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_SetQuotasForAccount(struct ndr_push *ndr, int flags, const struct lsa_SetQuotasForAccount *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_SetQuotasForAccount(struct ndr_pull *ndr, int flags, struct lsa_SetQuotasForAccount *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_SetQuotasForAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetQuotasForAccount *r)
+{
+ ndr_print_struct(ndr, name, "lsa_SetQuotasForAccount");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_SetQuotasForAccount");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_SetQuotasForAccount");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_GetSystemAccessAccount(struct ndr_push *ndr, int flags, const struct lsa_GetSystemAccessAccount *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.access_mask == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.access_mask));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_GetSystemAccessAccount(struct ndr_pull *ndr, int flags, struct lsa_GetSystemAccessAccount *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_access_mask_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.access_mask);
+ ZERO_STRUCTP(r->out.access_mask);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.access_mask);
+ }
+ _mem_save_access_mask_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.access_mask, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.access_mask));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_access_mask_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_GetSystemAccessAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_GetSystemAccessAccount *r)
+{
+ ndr_print_struct(ndr, name, "lsa_GetSystemAccessAccount");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_GetSystemAccessAccount");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_GetSystemAccessAccount");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "access_mask", r->out.access_mask);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "access_mask", *r->out.access_mask);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_SetSystemAccessAccount(struct ndr_push *ndr, int flags, const struct lsa_SetSystemAccessAccount *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_SetSystemAccessAccount(struct ndr_pull *ndr, int flags, struct lsa_SetSystemAccessAccount *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_SetSystemAccessAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetSystemAccessAccount *r)
+{
+ ndr_print_struct(ndr, name, "lsa_SetSystemAccessAccount");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_SetSystemAccessAccount");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_SetSystemAccessAccount");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_OpenTrustedDomain(struct ndr_push *ndr, int flags, const struct lsa_OpenTrustedDomain *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.sid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.trustdom_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.trustdom_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_OpenTrustedDomain(struct ndr_pull *ndr, int flags, struct lsa_OpenTrustedDomain *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sid_0;
+ TALLOC_CTX *_mem_save_trustdom_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sid);
+ }
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.trustdom_handle);
+ ZERO_STRUCTP(r->out.trustdom_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.trustdom_handle);
+ }
+ _mem_save_trustdom_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.trustdom_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.trustdom_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_trustdom_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_OpenTrustedDomain(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenTrustedDomain *r)
+{
+ ndr_print_struct(ndr, name, "lsa_OpenTrustedDomain");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_OpenTrustedDomain");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sid", r->in.sid);
+ ndr->depth++;
+ ndr_print_dom_sid2(ndr, "sid", r->in.sid);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_OpenTrustedDomain");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "trustdom_handle", r->out.trustdom_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "trustdom_handle", r->out.trustdom_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_QueryTrustedDomainInfo(struct ndr_push *ndr, int flags, const struct lsa_QueryTrustedDomainInfo *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.trustdom_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.trustdom_handle));
+ NDR_CHECK(ndr_push_lsa_TrustDomInfoEnum(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.info));
+ if (*r->out.info) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_lsa_TrustedDomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_QueryTrustedDomainInfo(struct ndr_pull *ndr, int flags, struct lsa_QueryTrustedDomainInfo *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_trustdom_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.trustdom_handle);
+ }
+ _mem_save_trustdom_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.trustdom_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.trustdom_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_trustdom_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TrustDomInfoEnum(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ } else {
+ *r->out.info = NULL;
+ }
+ if (*r->out.info) {
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.info, 0);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_lsa_TrustedDomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_QueryTrustedDomainInfo(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryTrustedDomainInfo *r)
+{
+ ndr_print_struct(ndr, name, "lsa_QueryTrustedDomainInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_QueryTrustedDomainInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "trustdom_handle", r->in.trustdom_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "trustdom_handle", r->in.trustdom_handle);
+ ndr->depth--;
+ ndr_print_lsa_TrustDomInfoEnum(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_QueryTrustedDomainInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", *r->out.info);
+ ndr->depth++;
+ if (*r->out.info) {
+ ndr_print_set_switch_value(ndr, *r->out.info, r->in.level);
+ ndr_print_lsa_TrustedDomainInfo(ndr, "info", *r->out.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_SetInformationTrustedDomain(struct ndr_push *ndr, int flags, const struct lsa_SetInformationTrustedDomain *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_SetInformationTrustedDomain(struct ndr_pull *ndr, int flags, struct lsa_SetInformationTrustedDomain *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_SetInformationTrustedDomain(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetInformationTrustedDomain *r)
+{
+ ndr_print_struct(ndr, name, "lsa_SetInformationTrustedDomain");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_SetInformationTrustedDomain");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_SetInformationTrustedDomain");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_OpenSecret(struct ndr_push *ndr, int flags, const struct lsa_OpenSecret *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.sec_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sec_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_OpenSecret(struct ndr_pull *ndr, int flags, struct lsa_OpenSecret *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sec_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.sec_handle);
+ ZERO_STRUCTP(r->out.sec_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sec_handle);
+ }
+ _mem_save_sec_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sec_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sec_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sec_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_OpenSecret(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenSecret *r)
+{
+ ndr_print_struct(ndr, name, "lsa_OpenSecret");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_OpenSecret");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_lsa_String(ndr, "name", &r->in.name);
+ ndr_print_uint32(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_OpenSecret");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sec_handle", r->out.sec_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "sec_handle", r->out.sec_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_SetSecret(struct ndr_push *ndr, int flags, const struct lsa_SetSecret *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.sec_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sec_handle));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.new_val));
+ if (r->in.new_val) {
+ NDR_CHECK(ndr_push_lsa_DATA_BUF(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.new_val));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.old_val));
+ if (r->in.old_val) {
+ NDR_CHECK(ndr_push_lsa_DATA_BUF(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.old_val));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_SetSecret(struct ndr_pull *ndr, int flags, struct lsa_SetSecret *r)
+{
+ uint32_t _ptr_new_val;
+ uint32_t _ptr_old_val;
+ TALLOC_CTX *_mem_save_sec_handle_0;
+ TALLOC_CTX *_mem_save_new_val_0;
+ TALLOC_CTX *_mem_save_old_val_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sec_handle);
+ }
+ _mem_save_sec_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sec_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sec_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sec_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_new_val));
+ if (_ptr_new_val) {
+ NDR_PULL_ALLOC(ndr, r->in.new_val);
+ } else {
+ r->in.new_val = NULL;
+ }
+ if (r->in.new_val) {
+ _mem_save_new_val_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.new_val, 0);
+ NDR_CHECK(ndr_pull_lsa_DATA_BUF(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.new_val));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_new_val_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_old_val));
+ if (_ptr_old_val) {
+ NDR_PULL_ALLOC(ndr, r->in.old_val);
+ } else {
+ r->in.old_val = NULL;
+ }
+ if (r->in.old_val) {
+ _mem_save_old_val_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.old_val, 0);
+ NDR_CHECK(ndr_pull_lsa_DATA_BUF(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.old_val));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_old_val_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_SetSecret(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetSecret *r)
+{
+ ndr_print_struct(ndr, name, "lsa_SetSecret");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_SetSecret");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sec_handle", r->in.sec_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "sec_handle", r->in.sec_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "new_val", r->in.new_val);
+ ndr->depth++;
+ if (r->in.new_val) {
+ ndr_print_lsa_DATA_BUF(ndr, "new_val", r->in.new_val);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "old_val", r->in.old_val);
+ ndr->depth++;
+ if (r->in.old_val) {
+ ndr_print_lsa_DATA_BUF(ndr, "old_val", r->in.old_val);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_SetSecret");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_QuerySecret(struct ndr_push *ndr, int flags, const struct lsa_QuerySecret *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.sec_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sec_handle));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.new_val));
+ if (r->in.new_val) {
+ NDR_CHECK(ndr_push_lsa_DATA_BUF_PTR(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.new_val));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.new_mtime));
+ if (r->in.new_mtime) {
+ NDR_CHECK(ndr_push_NTTIME_hyper(ndr, NDR_SCALARS, *r->in.new_mtime));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.old_val));
+ if (r->in.old_val) {
+ NDR_CHECK(ndr_push_lsa_DATA_BUF_PTR(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.old_val));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.old_mtime));
+ if (r->in.old_mtime) {
+ NDR_CHECK(ndr_push_NTTIME_hyper(ndr, NDR_SCALARS, *r->in.old_mtime));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.new_val));
+ if (r->out.new_val) {
+ NDR_CHECK(ndr_push_lsa_DATA_BUF_PTR(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.new_val));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.new_mtime));
+ if (r->out.new_mtime) {
+ NDR_CHECK(ndr_push_NTTIME_hyper(ndr, NDR_SCALARS, *r->out.new_mtime));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.old_val));
+ if (r->out.old_val) {
+ NDR_CHECK(ndr_push_lsa_DATA_BUF_PTR(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.old_val));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.old_mtime));
+ if (r->out.old_mtime) {
+ NDR_CHECK(ndr_push_NTTIME_hyper(ndr, NDR_SCALARS, *r->out.old_mtime));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_QuerySecret(struct ndr_pull *ndr, int flags, struct lsa_QuerySecret *r)
+{
+ uint32_t _ptr_new_val;
+ uint32_t _ptr_new_mtime;
+ uint32_t _ptr_old_val;
+ uint32_t _ptr_old_mtime;
+ TALLOC_CTX *_mem_save_sec_handle_0;
+ TALLOC_CTX *_mem_save_new_val_0;
+ TALLOC_CTX *_mem_save_new_mtime_0;
+ TALLOC_CTX *_mem_save_old_val_0;
+ TALLOC_CTX *_mem_save_old_mtime_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sec_handle);
+ }
+ _mem_save_sec_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sec_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sec_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sec_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_new_val));
+ if (_ptr_new_val) {
+ NDR_PULL_ALLOC(ndr, r->in.new_val);
+ } else {
+ r->in.new_val = NULL;
+ }
+ if (r->in.new_val) {
+ _mem_save_new_val_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.new_val, 0);
+ NDR_CHECK(ndr_pull_lsa_DATA_BUF_PTR(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.new_val));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_new_val_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_new_mtime));
+ if (_ptr_new_mtime) {
+ NDR_PULL_ALLOC(ndr, r->in.new_mtime);
+ } else {
+ r->in.new_mtime = NULL;
+ }
+ if (r->in.new_mtime) {
+ _mem_save_new_mtime_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.new_mtime, 0);
+ NDR_CHECK(ndr_pull_NTTIME_hyper(ndr, NDR_SCALARS, r->in.new_mtime));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_new_mtime_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_old_val));
+ if (_ptr_old_val) {
+ NDR_PULL_ALLOC(ndr, r->in.old_val);
+ } else {
+ r->in.old_val = NULL;
+ }
+ if (r->in.old_val) {
+ _mem_save_old_val_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.old_val, 0);
+ NDR_CHECK(ndr_pull_lsa_DATA_BUF_PTR(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.old_val));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_old_val_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_old_mtime));
+ if (_ptr_old_mtime) {
+ NDR_PULL_ALLOC(ndr, r->in.old_mtime);
+ } else {
+ r->in.old_mtime = NULL;
+ }
+ if (r->in.old_mtime) {
+ _mem_save_old_mtime_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.old_mtime, 0);
+ NDR_CHECK(ndr_pull_NTTIME_hyper(ndr, NDR_SCALARS, r->in.old_mtime));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_old_mtime_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_new_val));
+ if (_ptr_new_val) {
+ NDR_PULL_ALLOC(ndr, r->out.new_val);
+ } else {
+ r->out.new_val = NULL;
+ }
+ if (r->out.new_val) {
+ _mem_save_new_val_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.new_val, 0);
+ NDR_CHECK(ndr_pull_lsa_DATA_BUF_PTR(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.new_val));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_new_val_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_new_mtime));
+ if (_ptr_new_mtime) {
+ NDR_PULL_ALLOC(ndr, r->out.new_mtime);
+ } else {
+ r->out.new_mtime = NULL;
+ }
+ if (r->out.new_mtime) {
+ _mem_save_new_mtime_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.new_mtime, 0);
+ NDR_CHECK(ndr_pull_NTTIME_hyper(ndr, NDR_SCALARS, r->out.new_mtime));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_new_mtime_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_old_val));
+ if (_ptr_old_val) {
+ NDR_PULL_ALLOC(ndr, r->out.old_val);
+ } else {
+ r->out.old_val = NULL;
+ }
+ if (r->out.old_val) {
+ _mem_save_old_val_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.old_val, 0);
+ NDR_CHECK(ndr_pull_lsa_DATA_BUF_PTR(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.old_val));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_old_val_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_old_mtime));
+ if (_ptr_old_mtime) {
+ NDR_PULL_ALLOC(ndr, r->out.old_mtime);
+ } else {
+ r->out.old_mtime = NULL;
+ }
+ if (r->out.old_mtime) {
+ _mem_save_old_mtime_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.old_mtime, 0);
+ NDR_CHECK(ndr_pull_NTTIME_hyper(ndr, NDR_SCALARS, r->out.old_mtime));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_old_mtime_0, 0);
+ }
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_QuerySecret(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QuerySecret *r)
+{
+ ndr_print_struct(ndr, name, "lsa_QuerySecret");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_QuerySecret");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sec_handle", r->in.sec_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "sec_handle", r->in.sec_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "new_val", r->in.new_val);
+ ndr->depth++;
+ if (r->in.new_val) {
+ ndr_print_lsa_DATA_BUF_PTR(ndr, "new_val", r->in.new_val);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "new_mtime", r->in.new_mtime);
+ ndr->depth++;
+ if (r->in.new_mtime) {
+ ndr_print_NTTIME_hyper(ndr, "new_mtime", *r->in.new_mtime);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "old_val", r->in.old_val);
+ ndr->depth++;
+ if (r->in.old_val) {
+ ndr_print_lsa_DATA_BUF_PTR(ndr, "old_val", r->in.old_val);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "old_mtime", r->in.old_mtime);
+ ndr->depth++;
+ if (r->in.old_mtime) {
+ ndr_print_NTTIME_hyper(ndr, "old_mtime", *r->in.old_mtime);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_QuerySecret");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "new_val", r->out.new_val);
+ ndr->depth++;
+ if (r->out.new_val) {
+ ndr_print_lsa_DATA_BUF_PTR(ndr, "new_val", r->out.new_val);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "new_mtime", r->out.new_mtime);
+ ndr->depth++;
+ if (r->out.new_mtime) {
+ ndr_print_NTTIME_hyper(ndr, "new_mtime", *r->out.new_mtime);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "old_val", r->out.old_val);
+ ndr->depth++;
+ if (r->out.old_val) {
+ ndr_print_lsa_DATA_BUF_PTR(ndr, "old_val", r->out.old_val);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "old_mtime", r->out.old_mtime);
+ ndr->depth++;
+ if (r->out.old_mtime) {
+ ndr_print_NTTIME_hyper(ndr, "old_mtime", *r->out.old_mtime);
+ }
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_LookupPrivValue(struct ndr_push *ndr, int flags, const struct lsa_LookupPrivValue *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.luid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_LUID(ndr, NDR_SCALARS, r->out.luid));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_LookupPrivValue(struct ndr_pull *ndr, int flags, struct lsa_LookupPrivValue *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_name_0;
+ TALLOC_CTX *_mem_save_luid_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.name);
+ }
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.luid);
+ ZERO_STRUCTP(r->out.luid);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.luid);
+ }
+ _mem_save_luid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.luid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_LUID(ndr, NDR_SCALARS, r->out.luid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_luid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LookupPrivValue(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupPrivValue *r)
+{
+ ndr_print_struct(ndr, name, "lsa_LookupPrivValue");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LookupPrivValue");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "name", r->in.name);
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "name", r->in.name);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LookupPrivValue");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "luid", r->out.luid);
+ ndr->depth++;
+ ndr_print_lsa_LUID(ndr, "luid", r->out.luid);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_LookupPrivName(struct ndr_push *ndr, int flags, const struct lsa_LookupPrivName *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.luid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_LUID(ndr, NDR_SCALARS, r->in.luid));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.name));
+ if (*r->out.name) {
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.name));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_LookupPrivName(struct ndr_pull *ndr, int flags, struct lsa_LookupPrivName *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_luid_0;
+ TALLOC_CTX *_mem_save_name_0;
+ TALLOC_CTX *_mem_save_name_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.luid);
+ }
+ _mem_save_luid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.luid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_LUID(ndr, NDR_SCALARS, r->in.luid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_luid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.name);
+ ZERO_STRUCTP(r->out.name);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.name);
+ }
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, *r->out.name);
+ } else {
+ *r->out.name = NULL;
+ }
+ if (*r->out.name) {
+ _mem_save_name_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.name, 0);
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LookupPrivName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupPrivName *r)
+{
+ ndr_print_struct(ndr, name, "lsa_LookupPrivName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LookupPrivName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "luid", r->in.luid);
+ ndr->depth++;
+ ndr_print_lsa_LUID(ndr, "luid", r->in.luid);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LookupPrivName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "name", r->out.name);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "name", *r->out.name);
+ ndr->depth++;
+ if (*r->out.name) {
+ ndr_print_lsa_StringLarge(ndr, "name", *r->out.name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_LookupPrivDisplayName(struct ndr_push *ndr, int flags, const struct lsa_LookupPrivDisplayName *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.language_id));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.language_id_sys));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.disp_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.disp_name));
+ if (*r->out.disp_name) {
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.disp_name));
+ }
+ if (r->out.returned_language_id == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->out.returned_language_id));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_LookupPrivDisplayName(struct ndr_pull *ndr, int flags, struct lsa_LookupPrivDisplayName *r)
+{
+ uint32_t _ptr_disp_name;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_name_0;
+ TALLOC_CTX *_mem_save_disp_name_0;
+ TALLOC_CTX *_mem_save_disp_name_1;
+ TALLOC_CTX *_mem_save_returned_language_id_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.name);
+ }
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.language_id));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.language_id_sys));
+ NDR_PULL_ALLOC(ndr, r->out.disp_name);
+ ZERO_STRUCTP(r->out.disp_name);
+ NDR_PULL_ALLOC(ndr, r->out.returned_language_id);
+ ZERO_STRUCTP(r->out.returned_language_id);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.disp_name);
+ }
+ _mem_save_disp_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.disp_name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_disp_name));
+ if (_ptr_disp_name) {
+ NDR_PULL_ALLOC(ndr, *r->out.disp_name);
+ } else {
+ *r->out.disp_name = NULL;
+ }
+ if (*r->out.disp_name) {
+ _mem_save_disp_name_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.disp_name, 0);
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.disp_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_disp_name_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_disp_name_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.returned_language_id);
+ }
+ _mem_save_returned_language_id_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.returned_language_id, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->out.returned_language_id));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_returned_language_id_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LookupPrivDisplayName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupPrivDisplayName *r)
+{
+ ndr_print_struct(ndr, name, "lsa_LookupPrivDisplayName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LookupPrivDisplayName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "name", r->in.name);
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "name", r->in.name);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "language_id", r->in.language_id);
+ ndr_print_uint16(ndr, "language_id_sys", r->in.language_id_sys);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LookupPrivDisplayName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "disp_name", r->out.disp_name);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "disp_name", *r->out.disp_name);
+ ndr->depth++;
+ if (*r->out.disp_name) {
+ ndr_print_lsa_StringLarge(ndr, "disp_name", *r->out.disp_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "returned_language_id", r->out.returned_language_id);
+ ndr->depth++;
+ ndr_print_uint16(ndr, "returned_language_id", *r->out.returned_language_id);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_DeleteObject(struct ndr_push *ndr, int flags, const struct lsa_DeleteObject *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_DeleteObject(struct ndr_pull *ndr, int flags, struct lsa_DeleteObject *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ *r->out.handle = *r->in.handle;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_DeleteObject(struct ndr_print *ndr, const char *name, int flags, const struct lsa_DeleteObject *r)
+{
+ ndr_print_struct(ndr, name, "lsa_DeleteObject");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_DeleteObject");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_DeleteObject");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_EnumAccountsWithUserRight(struct ndr_push *ndr, int flags, const struct lsa_EnumAccountsWithUserRight *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.name));
+ if (r->in.name) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sids));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_EnumAccountsWithUserRight(struct ndr_pull *ndr, int flags, struct lsa_EnumAccountsWithUserRight *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_name_0;
+ TALLOC_CTX *_mem_save_sids_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->in.name);
+ } else {
+ r->in.name = NULL;
+ }
+ if (r->in.name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.name, 0);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.sids);
+ ZERO_STRUCTP(r->out.sids);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_EnumAccountsWithUserRight(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumAccountsWithUserRight *r)
+{
+ ndr_print_struct(ndr, name, "lsa_EnumAccountsWithUserRight");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_EnumAccountsWithUserRight");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "name", r->in.name);
+ ndr->depth++;
+ if (r->in.name) {
+ ndr_print_lsa_String(ndr, "name", r->in.name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_EnumAccountsWithUserRight");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sids", r->out.sids);
+ ndr->depth++;
+ ndr_print_lsa_SidArray(ndr, "sids", r->out.sids);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_EnumAccountRights(struct ndr_push *ndr, int flags, const struct lsa_EnumAccountRights *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.sid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.rights == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_RightSet(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.rights));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_EnumAccountRights(struct ndr_pull *ndr, int flags, struct lsa_EnumAccountRights *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sid_0;
+ TALLOC_CTX *_mem_save_rights_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sid);
+ }
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.rights);
+ ZERO_STRUCTP(r->out.rights);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.rights);
+ }
+ _mem_save_rights_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.rights, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_RightSet(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.rights));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rights_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_EnumAccountRights(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumAccountRights *r)
+{
+ ndr_print_struct(ndr, name, "lsa_EnumAccountRights");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_EnumAccountRights");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sid", r->in.sid);
+ ndr->depth++;
+ ndr_print_dom_sid2(ndr, "sid", r->in.sid);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_EnumAccountRights");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "rights", r->out.rights);
+ ndr->depth++;
+ ndr_print_lsa_RightSet(ndr, "rights", r->out.rights);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_AddAccountRights(struct ndr_push *ndr, int flags, const struct lsa_AddAccountRights *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.sid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ if (r->in.rights == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_RightSet(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.rights));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_AddAccountRights(struct ndr_pull *ndr, int flags, struct lsa_AddAccountRights *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sid_0;
+ TALLOC_CTX *_mem_save_rights_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sid);
+ }
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.rights);
+ }
+ _mem_save_rights_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.rights, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_RightSet(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.rights));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rights_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_AddAccountRights(struct ndr_print *ndr, const char *name, int flags, const struct lsa_AddAccountRights *r)
+{
+ ndr_print_struct(ndr, name, "lsa_AddAccountRights");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_AddAccountRights");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sid", r->in.sid);
+ ndr->depth++;
+ ndr_print_dom_sid2(ndr, "sid", r->in.sid);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "rights", r->in.rights);
+ ndr->depth++;
+ ndr_print_lsa_RightSet(ndr, "rights", r->in.rights);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_AddAccountRights");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_RemoveAccountRights(struct ndr_push *ndr, int flags, const struct lsa_RemoveAccountRights *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.sid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.remove_all));
+ if (r->in.rights == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_RightSet(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.rights));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_RemoveAccountRights(struct ndr_pull *ndr, int flags, struct lsa_RemoveAccountRights *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sid_0;
+ TALLOC_CTX *_mem_save_rights_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sid);
+ }
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.remove_all));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.rights);
+ }
+ _mem_save_rights_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.rights, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_RightSet(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.rights));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rights_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_RemoveAccountRights(struct ndr_print *ndr, const char *name, int flags, const struct lsa_RemoveAccountRights *r)
+{
+ ndr_print_struct(ndr, name, "lsa_RemoveAccountRights");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_RemoveAccountRights");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sid", r->in.sid);
+ ndr->depth++;
+ ndr_print_dom_sid2(ndr, "sid", r->in.sid);
+ ndr->depth--;
+ ndr_print_uint8(ndr, "remove_all", r->in.remove_all);
+ ndr_print_ptr(ndr, "rights", r->in.rights);
+ ndr->depth++;
+ ndr_print_lsa_RightSet(ndr, "rights", r->in.rights);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_RemoveAccountRights");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_QueryTrustedDomainInfoBySid(struct ndr_push *ndr, int flags, const struct lsa_QueryTrustedDomainInfoBySid *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.dom_sid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.dom_sid));
+ NDR_CHECK(ndr_push_lsa_TrustDomInfoEnum(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.info));
+ if (*r->out.info) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_lsa_TrustedDomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_QueryTrustedDomainInfoBySid(struct ndr_pull *ndr, int flags, struct lsa_QueryTrustedDomainInfoBySid *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_dom_sid_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.dom_sid);
+ }
+ _mem_save_dom_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.dom_sid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.dom_sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dom_sid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TrustDomInfoEnum(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ } else {
+ *r->out.info = NULL;
+ }
+ if (*r->out.info) {
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.info, 0);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_lsa_TrustedDomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_QueryTrustedDomainInfoBySid(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryTrustedDomainInfoBySid *r)
+{
+ ndr_print_struct(ndr, name, "lsa_QueryTrustedDomainInfoBySid");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_QueryTrustedDomainInfoBySid");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "dom_sid", r->in.dom_sid);
+ ndr->depth++;
+ ndr_print_dom_sid2(ndr, "dom_sid", r->in.dom_sid);
+ ndr->depth--;
+ ndr_print_lsa_TrustDomInfoEnum(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_QueryTrustedDomainInfoBySid");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", *r->out.info);
+ ndr->depth++;
+ if (*r->out.info) {
+ ndr_print_set_switch_value(ndr, *r->out.info, r->in.level);
+ ndr_print_lsa_TrustedDomainInfo(ndr, "info", *r->out.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_SetTrustedDomainInfo(struct ndr_push *ndr, int flags, const struct lsa_SetTrustedDomainInfo *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_SetTrustedDomainInfo(struct ndr_pull *ndr, int flags, struct lsa_SetTrustedDomainInfo *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_SetTrustedDomainInfo(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetTrustedDomainInfo *r)
+{
+ ndr_print_struct(ndr, name, "lsa_SetTrustedDomainInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_SetTrustedDomainInfo");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_SetTrustedDomainInfo");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_DeleteTrustedDomain(struct ndr_push *ndr, int flags, const struct lsa_DeleteTrustedDomain *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.dom_sid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.dom_sid));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_DeleteTrustedDomain(struct ndr_pull *ndr, int flags, struct lsa_DeleteTrustedDomain *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_dom_sid_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.dom_sid);
+ }
+ _mem_save_dom_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.dom_sid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.dom_sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dom_sid_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_DeleteTrustedDomain(struct ndr_print *ndr, const char *name, int flags, const struct lsa_DeleteTrustedDomain *r)
+{
+ ndr_print_struct(ndr, name, "lsa_DeleteTrustedDomain");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_DeleteTrustedDomain");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "dom_sid", r->in.dom_sid);
+ ndr->depth++;
+ ndr_print_dom_sid2(ndr, "dom_sid", r->in.dom_sid);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_DeleteTrustedDomain");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_StorePrivateData(struct ndr_push *ndr, int flags, const struct lsa_StorePrivateData *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_StorePrivateData(struct ndr_pull *ndr, int flags, struct lsa_StorePrivateData *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_StorePrivateData(struct ndr_print *ndr, const char *name, int flags, const struct lsa_StorePrivateData *r)
+{
+ ndr_print_struct(ndr, name, "lsa_StorePrivateData");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_StorePrivateData");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_StorePrivateData");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_RetrievePrivateData(struct ndr_push *ndr, int flags, const struct lsa_RetrievePrivateData *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_RetrievePrivateData(struct ndr_pull *ndr, int flags, struct lsa_RetrievePrivateData *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_RetrievePrivateData(struct ndr_print *ndr, const char *name, int flags, const struct lsa_RetrievePrivateData *r)
+{
+ ndr_print_struct(ndr, name, "lsa_RetrievePrivateData");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_RetrievePrivateData");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_RetrievePrivateData");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_OpenPolicy2(struct ndr_push *ndr, int flags, const struct lsa_OpenPolicy2 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.system_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.system_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.system_name, ndr_charset_length(r->in.system_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.attr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_ObjectAttribute(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.attr));
+ NDR_CHECK(ndr_push_lsa_PolicyAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_OpenPolicy2(struct ndr_pull *ndr, int flags, struct lsa_OpenPolicy2 *r)
+{
+ uint32_t _ptr_system_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_attr_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.system_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.system_name));
+ if (ndr_get_array_length(ndr, &r->in.system_name) > ndr_get_array_size(ndr, &r->in.system_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.system_name), ndr_get_array_length(ndr, &r->in.system_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.system_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.system_name, ndr_get_array_length(ndr, &r->in.system_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.attr);
+ }
+ _mem_save_attr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.attr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_ObjectAttribute(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.attr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_attr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_PolicyAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_OpenPolicy2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenPolicy2 *r)
+{
+ ndr_print_struct(ndr, name, "lsa_OpenPolicy2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_OpenPolicy2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_string(ndr, "system_name", r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "attr", r->in.attr);
+ ndr->depth++;
+ ndr_print_lsa_ObjectAttribute(ndr, "attr", r->in.attr);
+ ndr->depth--;
+ ndr_print_lsa_PolicyAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_OpenPolicy2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_GetUserName(struct ndr_push *ndr, int flags, const struct lsa_GetUserName *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.system_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.system_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.system_name, ndr_charset_length(r->in.system_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.account_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->in.account_name));
+ if (*r->in.account_name) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, *r->in.account_name));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.authority_name));
+ if (r->in.authority_name) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->in.authority_name));
+ if (*r->in.authority_name) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, *r->in.authority_name));
+ }
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.account_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.account_name));
+ if (*r->out.account_name) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.account_name));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.authority_name));
+ if (r->out.authority_name) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.authority_name));
+ if (*r->out.authority_name) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.authority_name));
+ }
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_GetUserName(struct ndr_pull *ndr, int flags, struct lsa_GetUserName *r)
+{
+ uint32_t _ptr_system_name;
+ uint32_t _ptr_account_name;
+ uint32_t _ptr_authority_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_account_name_0;
+ TALLOC_CTX *_mem_save_account_name_1;
+ TALLOC_CTX *_mem_save_authority_name_0;
+ TALLOC_CTX *_mem_save_authority_name_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.system_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.system_name));
+ if (ndr_get_array_length(ndr, &r->in.system_name) > ndr_get_array_size(ndr, &r->in.system_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.system_name), ndr_get_array_length(ndr, &r->in.system_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.system_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.system_name, ndr_get_array_length(ndr, &r->in.system_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.account_name);
+ }
+ _mem_save_account_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.account_name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_account_name));
+ if (_ptr_account_name) {
+ NDR_PULL_ALLOC(ndr, *r->in.account_name);
+ } else {
+ *r->in.account_name = NULL;
+ }
+ if (*r->in.account_name) {
+ _mem_save_account_name_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->in.account_name, 0);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, *r->in.account_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_account_name_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_account_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_authority_name));
+ if (_ptr_authority_name) {
+ NDR_PULL_ALLOC(ndr, r->in.authority_name);
+ } else {
+ r->in.authority_name = NULL;
+ }
+ if (r->in.authority_name) {
+ _mem_save_authority_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.authority_name, 0);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_authority_name));
+ if (_ptr_authority_name) {
+ NDR_PULL_ALLOC(ndr, *r->in.authority_name);
+ } else {
+ *r->in.authority_name = NULL;
+ }
+ if (*r->in.authority_name) {
+ _mem_save_authority_name_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->in.authority_name, 0);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, *r->in.authority_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_authority_name_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_authority_name_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.account_name);
+ *r->out.account_name = *r->in.account_name;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.account_name);
+ }
+ _mem_save_account_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.account_name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_account_name));
+ if (_ptr_account_name) {
+ NDR_PULL_ALLOC(ndr, *r->out.account_name);
+ } else {
+ *r->out.account_name = NULL;
+ }
+ if (*r->out.account_name) {
+ _mem_save_account_name_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.account_name, 0);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.account_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_account_name_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_account_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_authority_name));
+ if (_ptr_authority_name) {
+ NDR_PULL_ALLOC(ndr, r->out.authority_name);
+ } else {
+ r->out.authority_name = NULL;
+ }
+ if (r->out.authority_name) {
+ _mem_save_authority_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.authority_name, 0);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_authority_name));
+ if (_ptr_authority_name) {
+ NDR_PULL_ALLOC(ndr, *r->out.authority_name);
+ } else {
+ *r->out.authority_name = NULL;
+ }
+ if (*r->out.authority_name) {
+ _mem_save_authority_name_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.authority_name, 0);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.authority_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_authority_name_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_authority_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_GetUserName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_GetUserName *r)
+{
+ ndr_print_struct(ndr, name, "lsa_GetUserName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_GetUserName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_string(ndr, "system_name", r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "account_name", r->in.account_name);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "account_name", *r->in.account_name);
+ ndr->depth++;
+ if (*r->in.account_name) {
+ ndr_print_lsa_String(ndr, "account_name", *r->in.account_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "authority_name", r->in.authority_name);
+ ndr->depth++;
+ if (r->in.authority_name) {
+ ndr_print_ptr(ndr, "authority_name", *r->in.authority_name);
+ ndr->depth++;
+ if (*r->in.authority_name) {
+ ndr_print_lsa_String(ndr, "authority_name", *r->in.authority_name);
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_GetUserName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "account_name", r->out.account_name);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "account_name", *r->out.account_name);
+ ndr->depth++;
+ if (*r->out.account_name) {
+ ndr_print_lsa_String(ndr, "account_name", *r->out.account_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "authority_name", r->out.authority_name);
+ ndr->depth++;
+ if (r->out.authority_name) {
+ ndr_print_ptr(ndr, "authority_name", *r->out.authority_name);
+ ndr->depth++;
+ if (*r->out.authority_name) {
+ ndr_print_lsa_String(ndr, "authority_name", *r->out.authority_name);
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_QueryInfoPolicy2(struct ndr_push *ndr, int flags, const struct lsa_QueryInfoPolicy2 *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_lsa_PolicyInfo(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.info));
+ if (*r->out.info) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_lsa_PolicyInformation(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_QueryInfoPolicy2(struct ndr_pull *ndr, int flags, struct lsa_QueryInfoPolicy2 *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_PolicyInfo(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ } else {
+ *r->out.info = NULL;
+ }
+ if (*r->out.info) {
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.info, 0);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_lsa_PolicyInformation(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_QueryInfoPolicy2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryInfoPolicy2 *r)
+{
+ ndr_print_struct(ndr, name, "lsa_QueryInfoPolicy2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_QueryInfoPolicy2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_lsa_PolicyInfo(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_QueryInfoPolicy2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", *r->out.info);
+ ndr->depth++;
+ if (*r->out.info) {
+ ndr_print_set_switch_value(ndr, *r->out.info, r->in.level);
+ ndr_print_lsa_PolicyInformation(ndr, "info", *r->out.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_SetInfoPolicy2(struct ndr_push *ndr, int flags, const struct lsa_SetInfoPolicy2 *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_lsa_PolicyInfo(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_lsa_PolicyInformation(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_SetInfoPolicy2(struct ndr_pull *ndr, int flags, struct lsa_SetInfoPolicy2 *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_PolicyInfo(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_lsa_PolicyInformation(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_SetInfoPolicy2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetInfoPolicy2 *r)
+{
+ ndr_print_struct(ndr, name, "lsa_SetInfoPolicy2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_SetInfoPolicy2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_lsa_PolicyInfo(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.info, r->in.level);
+ ndr_print_lsa_PolicyInformation(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_SetInfoPolicy2");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_QueryTrustedDomainInfoByName(struct ndr_push *ndr, int flags, const struct lsa_QueryTrustedDomainInfoByName *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.trusted_domain == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.trusted_domain));
+ NDR_CHECK(ndr_push_lsa_TrustDomInfoEnum(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.info));
+ if (*r->out.info) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_lsa_TrustedDomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_QueryTrustedDomainInfoByName(struct ndr_pull *ndr, int flags, struct lsa_QueryTrustedDomainInfoByName *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_trusted_domain_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.trusted_domain);
+ }
+ _mem_save_trusted_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.trusted_domain, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.trusted_domain));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_trusted_domain_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TrustDomInfoEnum(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ } else {
+ *r->out.info = NULL;
+ }
+ if (*r->out.info) {
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.info, 0);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_lsa_TrustedDomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_QueryTrustedDomainInfoByName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryTrustedDomainInfoByName *r)
+{
+ ndr_print_struct(ndr, name, "lsa_QueryTrustedDomainInfoByName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_QueryTrustedDomainInfoByName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "trusted_domain", r->in.trusted_domain);
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "trusted_domain", r->in.trusted_domain);
+ ndr->depth--;
+ ndr_print_lsa_TrustDomInfoEnum(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_QueryTrustedDomainInfoByName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", *r->out.info);
+ ndr->depth++;
+ if (*r->out.info) {
+ ndr_print_set_switch_value(ndr, *r->out.info, r->in.level);
+ ndr_print_lsa_TrustedDomainInfo(ndr, "info", *r->out.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_SetTrustedDomainInfoByName(struct ndr_push *ndr, int flags, const struct lsa_SetTrustedDomainInfoByName *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.trusted_domain));
+ NDR_CHECK(ndr_push_lsa_TrustDomInfoEnum(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.info));
+ if (r->in.info) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_lsa_TrustedDomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_SetTrustedDomainInfoByName(struct ndr_pull *ndr, int flags, struct lsa_SetTrustedDomainInfoByName *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.trusted_domain));
+ NDR_CHECK(ndr_pull_lsa_TrustDomInfoEnum(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ } else {
+ r->in.info = NULL;
+ }
+ if (r->in.info) {
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, 0);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_lsa_TrustedDomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_SetTrustedDomainInfoByName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetTrustedDomainInfoByName *r)
+{
+ ndr_print_struct(ndr, name, "lsa_SetTrustedDomainInfoByName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_SetTrustedDomainInfoByName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_lsa_String(ndr, "trusted_domain", &r->in.trusted_domain);
+ ndr_print_lsa_TrustDomInfoEnum(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ if (r->in.info) {
+ ndr_print_set_switch_value(ndr, r->in.info, r->in.level);
+ ndr_print_lsa_TrustedDomainInfo(ndr, "info", r->in.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_SetTrustedDomainInfoByName");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_EnumTrustedDomainsEx(struct ndr_push *ndr, int flags, const struct lsa_EnumTrustedDomainsEx *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.resume_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_size));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.resume_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ if (r->out.domains == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_DomainListEx(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.domains));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_EnumTrustedDomainsEx(struct ndr_pull *ndr, int flags, struct lsa_EnumTrustedDomainsEx *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ TALLOC_CTX *_mem_save_domains_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ }
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_size));
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ *r->out.resume_handle = *r->in.resume_handle;
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ ZERO_STRUCTP(r->out.domains);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ }
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ }
+ _mem_save_domains_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.domains, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_DomainListEx(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.domains));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_EnumTrustedDomainsEx(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumTrustedDomainsEx *r)
+{
+ ndr_print_struct(ndr, name, "lsa_EnumTrustedDomainsEx");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_EnumTrustedDomainsEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_size", r->in.max_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_EnumTrustedDomainsEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domains", r->out.domains);
+ ndr->depth++;
+ ndr_print_lsa_DomainListEx(ndr, "domains", r->out.domains);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_CreateTrustedDomainEx(struct ndr_push *ndr, int flags, const struct lsa_CreateTrustedDomainEx *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_CreateTrustedDomainEx(struct ndr_pull *ndr, int flags, struct lsa_CreateTrustedDomainEx *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_CreateTrustedDomainEx(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CreateTrustedDomainEx *r)
+{
+ ndr_print_struct(ndr, name, "lsa_CreateTrustedDomainEx");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_CreateTrustedDomainEx");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_CreateTrustedDomainEx");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_CloseTrustedDomainEx(struct ndr_push *ndr, int flags, const struct lsa_CloseTrustedDomainEx *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_CloseTrustedDomainEx(struct ndr_pull *ndr, int flags, struct lsa_CloseTrustedDomainEx *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ *r->out.handle = *r->in.handle;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_CloseTrustedDomainEx(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CloseTrustedDomainEx *r)
+{
+ ndr_print_struct(ndr, name, "lsa_CloseTrustedDomainEx");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_CloseTrustedDomainEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_CloseTrustedDomainEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_QueryDomainInformationPolicy(struct ndr_push *ndr, int flags, const struct lsa_QueryDomainInformationPolicy *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.info));
+ if (*r->out.info) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_lsa_DomainInformationPolicy(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_QueryDomainInformationPolicy(struct ndr_pull *ndr, int flags, struct lsa_QueryDomainInformationPolicy *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ } else {
+ *r->out.info = NULL;
+ }
+ if (*r->out.info) {
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.info, 0);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_lsa_DomainInformationPolicy(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_QueryDomainInformationPolicy(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryDomainInformationPolicy *r)
+{
+ ndr_print_struct(ndr, name, "lsa_QueryDomainInformationPolicy");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_QueryDomainInformationPolicy");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_QueryDomainInformationPolicy");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", *r->out.info);
+ ndr->depth++;
+ if (*r->out.info) {
+ ndr_print_set_switch_value(ndr, *r->out.info, r->in.level);
+ ndr_print_lsa_DomainInformationPolicy(ndr, "info", *r->out.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_SetDomainInformationPolicy(struct ndr_push *ndr, int flags, const struct lsa_SetDomainInformationPolicy *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.info));
+ if (r->in.info) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_lsa_DomainInformationPolicy(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_SetDomainInformationPolicy(struct ndr_pull *ndr, int flags, struct lsa_SetDomainInformationPolicy *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ } else {
+ r->in.info = NULL;
+ }
+ if (r->in.info) {
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, 0);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_lsa_DomainInformationPolicy(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_SetDomainInformationPolicy(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetDomainInformationPolicy *r)
+{
+ ndr_print_struct(ndr, name, "lsa_SetDomainInformationPolicy");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_SetDomainInformationPolicy");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ if (r->in.info) {
+ ndr_print_set_switch_value(ndr, r->in.info, r->in.level);
+ ndr_print_lsa_DomainInformationPolicy(ndr, "info", r->in.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_SetDomainInformationPolicy");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_OpenTrustedDomainByName(struct ndr_push *ndr, int flags, const struct lsa_OpenTrustedDomainByName *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.trustdom_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.trustdom_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_OpenTrustedDomainByName(struct ndr_pull *ndr, int flags, struct lsa_OpenTrustedDomainByName *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_trustdom_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.trustdom_handle);
+ ZERO_STRUCTP(r->out.trustdom_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.trustdom_handle);
+ }
+ _mem_save_trustdom_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.trustdom_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.trustdom_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_trustdom_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_OpenTrustedDomainByName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenTrustedDomainByName *r)
+{
+ ndr_print_struct(ndr, name, "lsa_OpenTrustedDomainByName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_OpenTrustedDomainByName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_lsa_String(ndr, "name", &r->in.name);
+ ndr_print_uint32(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_OpenTrustedDomainByName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "trustdom_handle", r->out.trustdom_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "trustdom_handle", r->out.trustdom_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_TestCall(struct ndr_push *ndr, int flags, const struct lsa_TestCall *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_TestCall(struct ndr_pull *ndr, int flags, struct lsa_TestCall *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_TestCall(struct ndr_print *ndr, const char *name, int flags, const struct lsa_TestCall *r)
+{
+ ndr_print_struct(ndr, name, "lsa_TestCall");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_TestCall");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_TestCall");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_LookupSids2(struct ndr_push *ndr, int flags, const struct lsa_LookupSids2 *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ if (r->in.names == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_TransNameArray2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.names));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.count == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown2));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.domains == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.domains));
+ if (*r->out.domains) {
+ NDR_CHECK(ndr_push_lsa_RefDomainList(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.domains));
+ }
+ if (r->out.names == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_TransNameArray2(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.names));
+ if (r->out.count == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.count));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_LookupSids2(struct ndr_pull *ndr, int flags, struct lsa_LookupSids2 *r)
+{
+ uint32_t _ptr_domains;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sids_0;
+ TALLOC_CTX *_mem_save_domains_0;
+ TALLOC_CTX *_mem_save_domains_1;
+ TALLOC_CTX *_mem_save_names_0;
+ TALLOC_CTX *_mem_save_count_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.names);
+ }
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.names, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TransNameArray2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.names));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.count);
+ }
+ _mem_save_count_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.count, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.count));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_count_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown2));
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ ZERO_STRUCTP(r->out.domains);
+ NDR_PULL_ALLOC(ndr, r->out.names);
+ *r->out.names = *r->in.names;
+ NDR_PULL_ALLOC(ndr, r->out.count);
+ *r->out.count = *r->in.count;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ }
+ _mem_save_domains_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.domains, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domains));
+ if (_ptr_domains) {
+ NDR_PULL_ALLOC(ndr, *r->out.domains);
+ } else {
+ *r->out.domains = NULL;
+ }
+ if (*r->out.domains) {
+ _mem_save_domains_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.domains, 0);
+ NDR_CHECK(ndr_pull_lsa_RefDomainList(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.domains));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.names);
+ }
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.names, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TransNameArray2(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.names));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.count);
+ }
+ _mem_save_count_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.count, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.count));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_count_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LookupSids2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupSids2 *r)
+{
+ ndr_print_struct(ndr, name, "lsa_LookupSids2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LookupSids2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sids", r->in.sids);
+ ndr->depth++;
+ ndr_print_lsa_SidArray(ndr, "sids", r->in.sids);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "names", r->in.names);
+ ndr->depth++;
+ ndr_print_lsa_TransNameArray2(ndr, "names", r->in.names);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "count", r->in.count);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", *r->in.count);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown1", r->in.unknown1);
+ ndr_print_uint32(ndr, "unknown2", r->in.unknown2);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LookupSids2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domains", r->out.domains);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domains", *r->out.domains);
+ ndr->depth++;
+ if (*r->out.domains) {
+ ndr_print_lsa_RefDomainList(ndr, "domains", *r->out.domains);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "names", r->out.names);
+ ndr->depth++;
+ ndr_print_lsa_TransNameArray2(ndr, "names", r->out.names);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "count", r->out.count);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", *r->out.count);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_LookupNames2(struct ndr_push *ndr, int flags, const struct lsa_LookupNames2 *r)
+{
+ uint32_t cntr_names_0;
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_names));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_names));
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->in.names[cntr_names_0]));
+ }
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->in.names[cntr_names_0]));
+ }
+ if (r->in.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_TransSidArray2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ NDR_CHECK(ndr_push_lsa_LookupNamesLevel(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.count == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown2));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.domains == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.domains));
+ if (*r->out.domains) {
+ NDR_CHECK(ndr_push_lsa_RefDomainList(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.domains));
+ }
+ if (r->out.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_TransSidArray2(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sids));
+ if (r->out.count == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.count));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_LookupNames2(struct ndr_pull *ndr, int flags, struct lsa_LookupNames2 *r)
+{
+ uint32_t cntr_names_0;
+ uint32_t _ptr_domains;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_names_0;
+ TALLOC_CTX *_mem_save_domains_0;
+ TALLOC_CTX *_mem_save_domains_1;
+ TALLOC_CTX *_mem_save_sids_0;
+ TALLOC_CTX *_mem_save_count_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.num_names));
+ if (r->in.num_names < 0 || r->in.num_names > 1000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.names));
+ NDR_PULL_ALLOC_N(ndr, r->in.names, ndr_get_array_size(ndr, &r->in.names));
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.names, 0);
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->in.names[cntr_names_0]));
+ }
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->in.names[cntr_names_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, 0);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TransSidArray2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_LookupNamesLevel(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.count);
+ }
+ _mem_save_count_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.count, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.count));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_count_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown2));
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ ZERO_STRUCTP(r->out.domains);
+ NDR_PULL_ALLOC(ndr, r->out.sids);
+ *r->out.sids = *r->in.sids;
+ NDR_PULL_ALLOC(ndr, r->out.count);
+ *r->out.count = *r->in.count;
+ if (r->in.names) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.names, r->in.num_names));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ }
+ _mem_save_domains_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.domains, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domains));
+ if (_ptr_domains) {
+ NDR_PULL_ALLOC(ndr, *r->out.domains);
+ } else {
+ *r->out.domains = NULL;
+ }
+ if (*r->out.domains) {
+ _mem_save_domains_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.domains, 0);
+ NDR_CHECK(ndr_pull_lsa_RefDomainList(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.domains));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TransSidArray2(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.count);
+ }
+ _mem_save_count_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.count, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.count));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_count_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LookupNames2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupNames2 *r)
+{
+ uint32_t cntr_names_0;
+ ndr_print_struct(ndr, name, "lsa_LookupNames2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LookupNames2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "num_names", r->in.num_names);
+ ndr->print(ndr, "%s: ARRAY(%d)", "names", (int)r->in.num_names);
+ ndr->depth++;
+ for (cntr_names_0=0;cntr_names_0<r->in.num_names;cntr_names_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_names_0) != -1) {
+ ndr_print_lsa_String(ndr, "names", &r->in.names[cntr_names_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sids", r->in.sids);
+ ndr->depth++;
+ ndr_print_lsa_TransSidArray2(ndr, "sids", r->in.sids);
+ ndr->depth--;
+ ndr_print_lsa_LookupNamesLevel(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "count", r->in.count);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", *r->in.count);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown1", r->in.unknown1);
+ ndr_print_uint32(ndr, "unknown2", r->in.unknown2);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LookupNames2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domains", r->out.domains);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domains", *r->out.domains);
+ ndr->depth++;
+ if (*r->out.domains) {
+ ndr_print_lsa_RefDomainList(ndr, "domains", *r->out.domains);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sids", r->out.sids);
+ ndr->depth++;
+ ndr_print_lsa_TransSidArray2(ndr, "sids", r->out.sids);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "count", r->out.count);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", *r->out.count);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_CreateTrustedDomainEx2(struct ndr_push *ndr, int flags, const struct lsa_CreateTrustedDomainEx2 *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_CreateTrustedDomainEx2(struct ndr_pull *ndr, int flags, struct lsa_CreateTrustedDomainEx2 *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_CreateTrustedDomainEx2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CreateTrustedDomainEx2 *r)
+{
+ ndr_print_struct(ndr, name, "lsa_CreateTrustedDomainEx2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_CreateTrustedDomainEx2");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_CreateTrustedDomainEx2");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_CREDRWRITE(struct ndr_push *ndr, int flags, const struct lsa_CREDRWRITE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_CREDRWRITE(struct ndr_pull *ndr, int flags, struct lsa_CREDRWRITE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_CREDRWRITE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRWRITE *r)
+{
+ ndr_print_struct(ndr, name, "lsa_CREDRWRITE");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_CREDRWRITE");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_CREDRWRITE");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_CREDRREAD(struct ndr_push *ndr, int flags, const struct lsa_CREDRREAD *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_CREDRREAD(struct ndr_pull *ndr, int flags, struct lsa_CREDRREAD *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_CREDRREAD(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRREAD *r)
+{
+ ndr_print_struct(ndr, name, "lsa_CREDRREAD");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_CREDRREAD");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_CREDRREAD");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_CREDRENUMERATE(struct ndr_push *ndr, int flags, const struct lsa_CREDRENUMERATE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_CREDRENUMERATE(struct ndr_pull *ndr, int flags, struct lsa_CREDRENUMERATE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_CREDRENUMERATE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRENUMERATE *r)
+{
+ ndr_print_struct(ndr, name, "lsa_CREDRENUMERATE");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_CREDRENUMERATE");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_CREDRENUMERATE");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_CREDRWRITEDOMAINCREDENTIALS(struct ndr_push *ndr, int flags, const struct lsa_CREDRWRITEDOMAINCREDENTIALS *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_CREDRWRITEDOMAINCREDENTIALS(struct ndr_pull *ndr, int flags, struct lsa_CREDRWRITEDOMAINCREDENTIALS *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_CREDRWRITEDOMAINCREDENTIALS(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRWRITEDOMAINCREDENTIALS *r)
+{
+ ndr_print_struct(ndr, name, "lsa_CREDRWRITEDOMAINCREDENTIALS");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_CREDRWRITEDOMAINCREDENTIALS");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_CREDRWRITEDOMAINCREDENTIALS");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_CREDRREADDOMAINCREDENTIALS(struct ndr_push *ndr, int flags, const struct lsa_CREDRREADDOMAINCREDENTIALS *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_CREDRREADDOMAINCREDENTIALS(struct ndr_pull *ndr, int flags, struct lsa_CREDRREADDOMAINCREDENTIALS *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_CREDRREADDOMAINCREDENTIALS(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRREADDOMAINCREDENTIALS *r)
+{
+ ndr_print_struct(ndr, name, "lsa_CREDRREADDOMAINCREDENTIALS");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_CREDRREADDOMAINCREDENTIALS");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_CREDRREADDOMAINCREDENTIALS");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_CREDRDELETE(struct ndr_push *ndr, int flags, const struct lsa_CREDRDELETE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_CREDRDELETE(struct ndr_pull *ndr, int flags, struct lsa_CREDRDELETE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_CREDRDELETE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRDELETE *r)
+{
+ ndr_print_struct(ndr, name, "lsa_CREDRDELETE");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_CREDRDELETE");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_CREDRDELETE");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_CREDRGETTARGETINFO(struct ndr_push *ndr, int flags, const struct lsa_CREDRGETTARGETINFO *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_CREDRGETTARGETINFO(struct ndr_pull *ndr, int flags, struct lsa_CREDRGETTARGETINFO *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_CREDRGETTARGETINFO(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRGETTARGETINFO *r)
+{
+ ndr_print_struct(ndr, name, "lsa_CREDRGETTARGETINFO");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_CREDRGETTARGETINFO");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_CREDRGETTARGETINFO");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_CREDRPROFILELOADED(struct ndr_push *ndr, int flags, const struct lsa_CREDRPROFILELOADED *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_CREDRPROFILELOADED(struct ndr_pull *ndr, int flags, struct lsa_CREDRPROFILELOADED *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_CREDRPROFILELOADED(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRPROFILELOADED *r)
+{
+ ndr_print_struct(ndr, name, "lsa_CREDRPROFILELOADED");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_CREDRPROFILELOADED");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_CREDRPROFILELOADED");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_LookupNames3(struct ndr_push *ndr, int flags, const struct lsa_LookupNames3 *r)
+{
+ uint32_t cntr_names_0;
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_names));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_names));
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->in.names[cntr_names_0]));
+ }
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->in.names[cntr_names_0]));
+ }
+ if (r->in.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_TransSidArray3(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ NDR_CHECK(ndr_push_lsa_LookupNamesLevel(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.count == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown2));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.domains == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.domains));
+ if (*r->out.domains) {
+ NDR_CHECK(ndr_push_lsa_RefDomainList(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.domains));
+ }
+ if (r->out.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_TransSidArray3(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sids));
+ if (r->out.count == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.count));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_LookupNames3(struct ndr_pull *ndr, int flags, struct lsa_LookupNames3 *r)
+{
+ uint32_t cntr_names_0;
+ uint32_t _ptr_domains;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_names_0;
+ TALLOC_CTX *_mem_save_domains_0;
+ TALLOC_CTX *_mem_save_domains_1;
+ TALLOC_CTX *_mem_save_sids_0;
+ TALLOC_CTX *_mem_save_count_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.num_names));
+ if (r->in.num_names < 0 || r->in.num_names > 1000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.names));
+ NDR_PULL_ALLOC_N(ndr, r->in.names, ndr_get_array_size(ndr, &r->in.names));
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.names, 0);
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->in.names[cntr_names_0]));
+ }
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->in.names[cntr_names_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, 0);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TransSidArray3(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_LookupNamesLevel(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.count);
+ }
+ _mem_save_count_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.count, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.count));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_count_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown2));
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ ZERO_STRUCTP(r->out.domains);
+ NDR_PULL_ALLOC(ndr, r->out.sids);
+ *r->out.sids = *r->in.sids;
+ NDR_PULL_ALLOC(ndr, r->out.count);
+ *r->out.count = *r->in.count;
+ if (r->in.names) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.names, r->in.num_names));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ }
+ _mem_save_domains_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.domains, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domains));
+ if (_ptr_domains) {
+ NDR_PULL_ALLOC(ndr, *r->out.domains);
+ } else {
+ *r->out.domains = NULL;
+ }
+ if (*r->out.domains) {
+ _mem_save_domains_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.domains, 0);
+ NDR_CHECK(ndr_pull_lsa_RefDomainList(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.domains));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TransSidArray3(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.count);
+ }
+ _mem_save_count_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.count, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.count));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_count_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LookupNames3(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupNames3 *r)
+{
+ uint32_t cntr_names_0;
+ ndr_print_struct(ndr, name, "lsa_LookupNames3");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LookupNames3");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "num_names", r->in.num_names);
+ ndr->print(ndr, "%s: ARRAY(%d)", "names", (int)r->in.num_names);
+ ndr->depth++;
+ for (cntr_names_0=0;cntr_names_0<r->in.num_names;cntr_names_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_names_0) != -1) {
+ ndr_print_lsa_String(ndr, "names", &r->in.names[cntr_names_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sids", r->in.sids);
+ ndr->depth++;
+ ndr_print_lsa_TransSidArray3(ndr, "sids", r->in.sids);
+ ndr->depth--;
+ ndr_print_lsa_LookupNamesLevel(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "count", r->in.count);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", *r->in.count);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown1", r->in.unknown1);
+ ndr_print_uint32(ndr, "unknown2", r->in.unknown2);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LookupNames3");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domains", r->out.domains);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domains", *r->out.domains);
+ ndr->depth++;
+ if (*r->out.domains) {
+ ndr_print_lsa_RefDomainList(ndr, "domains", *r->out.domains);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sids", r->out.sids);
+ ndr->depth++;
+ ndr_print_lsa_TransSidArray3(ndr, "sids", r->out.sids);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "count", r->out.count);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", *r->out.count);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_CREDRGETSESSIONTYPES(struct ndr_push *ndr, int flags, const struct lsa_CREDRGETSESSIONTYPES *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_CREDRGETSESSIONTYPES(struct ndr_pull *ndr, int flags, struct lsa_CREDRGETSESSIONTYPES *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_CREDRGETSESSIONTYPES(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRGETSESSIONTYPES *r)
+{
+ ndr_print_struct(ndr, name, "lsa_CREDRGETSESSIONTYPES");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_CREDRGETSESSIONTYPES");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_CREDRGETSESSIONTYPES");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_LSARREGISTERAUDITEVENT(struct ndr_push *ndr, int flags, const struct lsa_LSARREGISTERAUDITEVENT *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_LSARREGISTERAUDITEVENT(struct ndr_pull *ndr, int flags, struct lsa_LSARREGISTERAUDITEVENT *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LSARREGISTERAUDITEVENT(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARREGISTERAUDITEVENT *r)
+{
+ ndr_print_struct(ndr, name, "lsa_LSARREGISTERAUDITEVENT");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LSARREGISTERAUDITEVENT");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LSARREGISTERAUDITEVENT");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_LSARGENAUDITEVENT(struct ndr_push *ndr, int flags, const struct lsa_LSARGENAUDITEVENT *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_LSARGENAUDITEVENT(struct ndr_pull *ndr, int flags, struct lsa_LSARGENAUDITEVENT *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LSARGENAUDITEVENT(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARGENAUDITEVENT *r)
+{
+ ndr_print_struct(ndr, name, "lsa_LSARGENAUDITEVENT");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LSARGENAUDITEVENT");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LSARGENAUDITEVENT");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_LSARUNREGISTERAUDITEVENT(struct ndr_push *ndr, int flags, const struct lsa_LSARUNREGISTERAUDITEVENT *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_LSARUNREGISTERAUDITEVENT(struct ndr_pull *ndr, int flags, struct lsa_LSARUNREGISTERAUDITEVENT *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LSARUNREGISTERAUDITEVENT(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARUNREGISTERAUDITEVENT *r)
+{
+ ndr_print_struct(ndr, name, "lsa_LSARUNREGISTERAUDITEVENT");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LSARUNREGISTERAUDITEVENT");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LSARUNREGISTERAUDITEVENT");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_lsaRQueryForestTrustInformation(struct ndr_push *ndr, int flags, const struct lsa_lsaRQueryForestTrustInformation *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.trusted_domain_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.trusted_domain_name));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.unknown));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.forest_trust_info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.forest_trust_info));
+ if (*r->out.forest_trust_info) {
+ NDR_CHECK(ndr_push_lsa_ForestTrustInformation(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.forest_trust_info));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_lsaRQueryForestTrustInformation(struct ndr_pull *ndr, int flags, struct lsa_lsaRQueryForestTrustInformation *r)
+{
+ uint32_t _ptr_forest_trust_info;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_trusted_domain_name_0;
+ TALLOC_CTX *_mem_save_forest_trust_info_0;
+ TALLOC_CTX *_mem_save_forest_trust_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.trusted_domain_name);
+ }
+ _mem_save_trusted_domain_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.trusted_domain_name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.trusted_domain_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_trusted_domain_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.unknown));
+ NDR_PULL_ALLOC(ndr, r->out.forest_trust_info);
+ ZERO_STRUCTP(r->out.forest_trust_info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.forest_trust_info);
+ }
+ _mem_save_forest_trust_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.forest_trust_info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_forest_trust_info));
+ if (_ptr_forest_trust_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.forest_trust_info);
+ } else {
+ *r->out.forest_trust_info = NULL;
+ }
+ if (*r->out.forest_trust_info) {
+ _mem_save_forest_trust_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.forest_trust_info, 0);
+ NDR_CHECK(ndr_pull_lsa_ForestTrustInformation(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.forest_trust_info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_forest_trust_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_forest_trust_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_lsaRQueryForestTrustInformation(struct ndr_print *ndr, const char *name, int flags, const struct lsa_lsaRQueryForestTrustInformation *r)
+{
+ ndr_print_struct(ndr, name, "lsa_lsaRQueryForestTrustInformation");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_lsaRQueryForestTrustInformation");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "trusted_domain_name", r->in.trusted_domain_name);
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "trusted_domain_name", r->in.trusted_domain_name);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "unknown", r->in.unknown);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_lsaRQueryForestTrustInformation");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "forest_trust_info", r->out.forest_trust_info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "forest_trust_info", *r->out.forest_trust_info);
+ ndr->depth++;
+ if (*r->out.forest_trust_info) {
+ ndr_print_lsa_ForestTrustInformation(ndr, "forest_trust_info", *r->out.forest_trust_info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_LSARSETFORESTTRUSTINFORMATION(struct ndr_push *ndr, int flags, const struct lsa_LSARSETFORESTTRUSTINFORMATION *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_LSARSETFORESTTRUSTINFORMATION(struct ndr_pull *ndr, int flags, struct lsa_LSARSETFORESTTRUSTINFORMATION *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LSARSETFORESTTRUSTINFORMATION(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARSETFORESTTRUSTINFORMATION *r)
+{
+ ndr_print_struct(ndr, name, "lsa_LSARSETFORESTTRUSTINFORMATION");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LSARSETFORESTTRUSTINFORMATION");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LSARSETFORESTTRUSTINFORMATION");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_CREDRRENAME(struct ndr_push *ndr, int flags, const struct lsa_CREDRRENAME *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_CREDRRENAME(struct ndr_pull *ndr, int flags, struct lsa_CREDRRENAME *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_CREDRRENAME(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRRENAME *r)
+{
+ ndr_print_struct(ndr, name, "lsa_CREDRRENAME");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_CREDRRENAME");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_CREDRRENAME");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_lsa_LookupSids3(struct ndr_push *ndr, int flags, const struct lsa_LookupSids3 *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ if (r->in.names == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_TransNameArray2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.names));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.count == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown2));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.domains == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.domains));
+ if (*r->out.domains) {
+ NDR_CHECK(ndr_push_lsa_RefDomainList(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.domains));
+ }
+ if (r->out.names == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_TransNameArray2(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.names));
+ if (r->out.count == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.count));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_lsa_LookupSids3(struct ndr_pull *ndr, int flags, struct lsa_LookupSids3 *r)
+{
+ uint32_t _ptr_domains;
+ TALLOC_CTX *_mem_save_sids_0;
+ TALLOC_CTX *_mem_save_domains_0;
+ TALLOC_CTX *_mem_save_domains_1;
+ TALLOC_CTX *_mem_save_names_0;
+ TALLOC_CTX *_mem_save_count_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.names);
+ }
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.names, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TransNameArray2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.names));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.count);
+ }
+ _mem_save_count_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.count, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.count));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_count_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown2));
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ ZERO_STRUCTP(r->out.domains);
+ NDR_PULL_ALLOC(ndr, r->out.names);
+ *r->out.names = *r->in.names;
+ NDR_PULL_ALLOC(ndr, r->out.count);
+ *r->out.count = *r->in.count;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ }
+ _mem_save_domains_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.domains, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domains));
+ if (_ptr_domains) {
+ NDR_PULL_ALLOC(ndr, *r->out.domains);
+ } else {
+ *r->out.domains = NULL;
+ }
+ if (*r->out.domains) {
+ _mem_save_domains_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.domains, 0);
+ NDR_CHECK(ndr_pull_lsa_RefDomainList(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.domains));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.names);
+ }
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.names, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TransNameArray2(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.names));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.count);
+ }
+ _mem_save_count_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.count, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.count));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_count_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LookupSids3(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupSids3 *r)
+{
+ ndr_print_struct(ndr, name, "lsa_LookupSids3");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LookupSids3");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sids", r->in.sids);
+ ndr->depth++;
+ ndr_print_lsa_SidArray(ndr, "sids", r->in.sids);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "names", r->in.names);
+ ndr->depth++;
+ ndr_print_lsa_TransNameArray2(ndr, "names", r->in.names);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "count", r->in.count);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", *r->in.count);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown1", r->in.unknown1);
+ ndr_print_uint32(ndr, "unknown2", r->in.unknown2);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LookupSids3");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domains", r->out.domains);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domains", *r->out.domains);
+ ndr->depth++;
+ if (*r->out.domains) {
+ ndr_print_lsa_RefDomainList(ndr, "domains", *r->out.domains);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "names", r->out.names);
+ ndr->depth++;
+ ndr_print_lsa_TransNameArray2(ndr, "names", r->out.names);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "count", r->out.count);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", *r->out.count);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_LookupNames4(struct ndr_push *ndr, int flags, const struct lsa_LookupNames4 *r)
+{
+ uint32_t cntr_names_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_names));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_names));
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->in.names[cntr_names_0]));
+ }
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->in.names[cntr_names_0]));
+ }
+ if (r->in.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_TransSidArray3(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ NDR_CHECK(ndr_push_lsa_LookupNamesLevel(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.count == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown2));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.domains == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.domains));
+ if (*r->out.domains) {
+ NDR_CHECK(ndr_push_lsa_RefDomainList(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.domains));
+ }
+ if (r->out.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_TransSidArray3(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sids));
+ if (r->out.count == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.count));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_LookupNames4(struct ndr_pull *ndr, int flags, struct lsa_LookupNames4 *r)
+{
+ uint32_t cntr_names_0;
+ uint32_t _ptr_domains;
+ TALLOC_CTX *_mem_save_names_0;
+ TALLOC_CTX *_mem_save_domains_0;
+ TALLOC_CTX *_mem_save_domains_1;
+ TALLOC_CTX *_mem_save_sids_0;
+ TALLOC_CTX *_mem_save_count_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.num_names));
+ if (r->in.num_names < 0 || r->in.num_names > 1000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.names));
+ NDR_PULL_ALLOC_N(ndr, r->in.names, ndr_get_array_size(ndr, &r->in.names));
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.names, 0);
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->in.names[cntr_names_0]));
+ }
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->in.names[cntr_names_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, 0);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TransSidArray3(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_LookupNamesLevel(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.count);
+ }
+ _mem_save_count_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.count, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.count));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_count_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown2));
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ ZERO_STRUCTP(r->out.domains);
+ NDR_PULL_ALLOC(ndr, r->out.sids);
+ *r->out.sids = *r->in.sids;
+ NDR_PULL_ALLOC(ndr, r->out.count);
+ *r->out.count = *r->in.count;
+ if (r->in.names) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.names, r->in.num_names));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.domains);
+ }
+ _mem_save_domains_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.domains, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domains));
+ if (_ptr_domains) {
+ NDR_PULL_ALLOC(ndr, *r->out.domains);
+ } else {
+ *r->out.domains = NULL;
+ }
+ if (*r->out.domains) {
+ _mem_save_domains_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.domains, 0);
+ NDR_CHECK(ndr_pull_lsa_RefDomainList(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.domains));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domains_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_TransSidArray3(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.count);
+ }
+ _mem_save_count_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.count, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.count));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_count_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LookupNames4(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupNames4 *r)
+{
+ uint32_t cntr_names_0;
+ ndr_print_struct(ndr, name, "lsa_LookupNames4");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LookupNames4");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_names", r->in.num_names);
+ ndr->print(ndr, "%s: ARRAY(%d)", "names", (int)r->in.num_names);
+ ndr->depth++;
+ for (cntr_names_0=0;cntr_names_0<r->in.num_names;cntr_names_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_names_0) != -1) {
+ ndr_print_lsa_String(ndr, "names", &r->in.names[cntr_names_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sids", r->in.sids);
+ ndr->depth++;
+ ndr_print_lsa_TransSidArray3(ndr, "sids", r->in.sids);
+ ndr->depth--;
+ ndr_print_lsa_LookupNamesLevel(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "count", r->in.count);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", *r->in.count);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown1", r->in.unknown1);
+ ndr_print_uint32(ndr, "unknown2", r->in.unknown2);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LookupNames4");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domains", r->out.domains);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domains", *r->out.domains);
+ ndr->depth++;
+ if (*r->out.domains) {
+ ndr_print_lsa_RefDomainList(ndr, "domains", *r->out.domains);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sids", r->out.sids);
+ ndr->depth++;
+ ndr_print_lsa_TransSidArray3(ndr, "sids", r->out.sids);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "count", r->out.count);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", *r->out.count);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_LSAROPENPOLICYSCE(struct ndr_push *ndr, int flags, const struct lsa_LSAROPENPOLICYSCE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_LSAROPENPOLICYSCE(struct ndr_pull *ndr, int flags, struct lsa_LSAROPENPOLICYSCE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LSAROPENPOLICYSCE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSAROPENPOLICYSCE *r)
+{
+ ndr_print_struct(ndr, name, "lsa_LSAROPENPOLICYSCE");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LSAROPENPOLICYSCE");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LSAROPENPOLICYSCE");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_LSARADTREGISTERSECURITYEVENTSOURCE(struct ndr_push *ndr, int flags, const struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_LSARADTREGISTERSECURITYEVENTSOURCE(struct ndr_pull *ndr, int flags, struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LSARADTREGISTERSECURITYEVENTSOURCE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE *r)
+{
+ ndr_print_struct(ndr, name, "lsa_LSARADTREGISTERSECURITYEVENTSOURCE");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LSARADTREGISTERSECURITYEVENTSOURCE");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LSARADTREGISTERSECURITYEVENTSOURCE");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(struct ndr_push *ndr, int flags, const struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(struct ndr_pull *ndr, int flags, struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE *r)
+{
+ ndr_print_struct(ndr, name, "lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_lsa_LSARADTREPORTSECURITYEVENT(struct ndr_push *ndr, int flags, const struct lsa_LSARADTREPORTSECURITYEVENT *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_lsa_LSARADTREPORTSECURITYEVENT(struct ndr_pull *ndr, int flags, struct lsa_LSARADTREPORTSECURITYEVENT *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_lsa_LSARADTREPORTSECURITYEVENT(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARADTREPORTSECURITYEVENT *r)
+{
+ ndr_print_struct(ndr, name, "lsa_LSARADTREPORTSECURITYEVENT");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "lsa_LSARADTREPORTSECURITYEVENT");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "lsa_LSARADTREPORTSECURITYEVENT");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call lsarpc_calls[] = {
+ {
+ "lsa_Close",
+ sizeof(struct lsa_Close),
+ (ndr_push_flags_fn_t) ndr_push_lsa_Close,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_Close,
+ (ndr_print_function_t) ndr_print_lsa_Close,
+ false,
+ },
+ {
+ "lsa_Delete",
+ sizeof(struct lsa_Delete),
+ (ndr_push_flags_fn_t) ndr_push_lsa_Delete,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_Delete,
+ (ndr_print_function_t) ndr_print_lsa_Delete,
+ false,
+ },
+ {
+ "lsa_EnumPrivs",
+ sizeof(struct lsa_EnumPrivs),
+ (ndr_push_flags_fn_t) ndr_push_lsa_EnumPrivs,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_EnumPrivs,
+ (ndr_print_function_t) ndr_print_lsa_EnumPrivs,
+ false,
+ },
+ {
+ "lsa_QuerySecurity",
+ sizeof(struct lsa_QuerySecurity),
+ (ndr_push_flags_fn_t) ndr_push_lsa_QuerySecurity,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_QuerySecurity,
+ (ndr_print_function_t) ndr_print_lsa_QuerySecurity,
+ false,
+ },
+ {
+ "lsa_SetSecObj",
+ sizeof(struct lsa_SetSecObj),
+ (ndr_push_flags_fn_t) ndr_push_lsa_SetSecObj,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_SetSecObj,
+ (ndr_print_function_t) ndr_print_lsa_SetSecObj,
+ false,
+ },
+ {
+ "lsa_ChangePassword",
+ sizeof(struct lsa_ChangePassword),
+ (ndr_push_flags_fn_t) ndr_push_lsa_ChangePassword,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_ChangePassword,
+ (ndr_print_function_t) ndr_print_lsa_ChangePassword,
+ false,
+ },
+ {
+ "lsa_OpenPolicy",
+ sizeof(struct lsa_OpenPolicy),
+ (ndr_push_flags_fn_t) ndr_push_lsa_OpenPolicy,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_OpenPolicy,
+ (ndr_print_function_t) ndr_print_lsa_OpenPolicy,
+ false,
+ },
+ {
+ "lsa_QueryInfoPolicy",
+ sizeof(struct lsa_QueryInfoPolicy),
+ (ndr_push_flags_fn_t) ndr_push_lsa_QueryInfoPolicy,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_QueryInfoPolicy,
+ (ndr_print_function_t) ndr_print_lsa_QueryInfoPolicy,
+ false,
+ },
+ {
+ "lsa_SetInfoPolicy",
+ sizeof(struct lsa_SetInfoPolicy),
+ (ndr_push_flags_fn_t) ndr_push_lsa_SetInfoPolicy,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_SetInfoPolicy,
+ (ndr_print_function_t) ndr_print_lsa_SetInfoPolicy,
+ false,
+ },
+ {
+ "lsa_ClearAuditLog",
+ sizeof(struct lsa_ClearAuditLog),
+ (ndr_push_flags_fn_t) ndr_push_lsa_ClearAuditLog,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_ClearAuditLog,
+ (ndr_print_function_t) ndr_print_lsa_ClearAuditLog,
+ false,
+ },
+ {
+ "lsa_CreateAccount",
+ sizeof(struct lsa_CreateAccount),
+ (ndr_push_flags_fn_t) ndr_push_lsa_CreateAccount,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_CreateAccount,
+ (ndr_print_function_t) ndr_print_lsa_CreateAccount,
+ false,
+ },
+ {
+ "lsa_EnumAccounts",
+ sizeof(struct lsa_EnumAccounts),
+ (ndr_push_flags_fn_t) ndr_push_lsa_EnumAccounts,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_EnumAccounts,
+ (ndr_print_function_t) ndr_print_lsa_EnumAccounts,
+ false,
+ },
+ {
+ "lsa_CreateTrustedDomain",
+ sizeof(struct lsa_CreateTrustedDomain),
+ (ndr_push_flags_fn_t) ndr_push_lsa_CreateTrustedDomain,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_CreateTrustedDomain,
+ (ndr_print_function_t) ndr_print_lsa_CreateTrustedDomain,
+ false,
+ },
+ {
+ "lsa_EnumTrustDom",
+ sizeof(struct lsa_EnumTrustDom),
+ (ndr_push_flags_fn_t) ndr_push_lsa_EnumTrustDom,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_EnumTrustDom,
+ (ndr_print_function_t) ndr_print_lsa_EnumTrustDom,
+ false,
+ },
+ {
+ "lsa_LookupNames",
+ sizeof(struct lsa_LookupNames),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LookupNames,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LookupNames,
+ (ndr_print_function_t) ndr_print_lsa_LookupNames,
+ false,
+ },
+ {
+ "lsa_LookupSids",
+ sizeof(struct lsa_LookupSids),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LookupSids,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LookupSids,
+ (ndr_print_function_t) ndr_print_lsa_LookupSids,
+ false,
+ },
+ {
+ "lsa_CreateSecret",
+ sizeof(struct lsa_CreateSecret),
+ (ndr_push_flags_fn_t) ndr_push_lsa_CreateSecret,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_CreateSecret,
+ (ndr_print_function_t) ndr_print_lsa_CreateSecret,
+ false,
+ },
+ {
+ "lsa_OpenAccount",
+ sizeof(struct lsa_OpenAccount),
+ (ndr_push_flags_fn_t) ndr_push_lsa_OpenAccount,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_OpenAccount,
+ (ndr_print_function_t) ndr_print_lsa_OpenAccount,
+ false,
+ },
+ {
+ "lsa_EnumPrivsAccount",
+ sizeof(struct lsa_EnumPrivsAccount),
+ (ndr_push_flags_fn_t) ndr_push_lsa_EnumPrivsAccount,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_EnumPrivsAccount,
+ (ndr_print_function_t) ndr_print_lsa_EnumPrivsAccount,
+ false,
+ },
+ {
+ "lsa_AddPrivilegesToAccount",
+ sizeof(struct lsa_AddPrivilegesToAccount),
+ (ndr_push_flags_fn_t) ndr_push_lsa_AddPrivilegesToAccount,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_AddPrivilegesToAccount,
+ (ndr_print_function_t) ndr_print_lsa_AddPrivilegesToAccount,
+ false,
+ },
+ {
+ "lsa_RemovePrivilegesFromAccount",
+ sizeof(struct lsa_RemovePrivilegesFromAccount),
+ (ndr_push_flags_fn_t) ndr_push_lsa_RemovePrivilegesFromAccount,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_RemovePrivilegesFromAccount,
+ (ndr_print_function_t) ndr_print_lsa_RemovePrivilegesFromAccount,
+ false,
+ },
+ {
+ "lsa_GetQuotasForAccount",
+ sizeof(struct lsa_GetQuotasForAccount),
+ (ndr_push_flags_fn_t) ndr_push_lsa_GetQuotasForAccount,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_GetQuotasForAccount,
+ (ndr_print_function_t) ndr_print_lsa_GetQuotasForAccount,
+ false,
+ },
+ {
+ "lsa_SetQuotasForAccount",
+ sizeof(struct lsa_SetQuotasForAccount),
+ (ndr_push_flags_fn_t) ndr_push_lsa_SetQuotasForAccount,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_SetQuotasForAccount,
+ (ndr_print_function_t) ndr_print_lsa_SetQuotasForAccount,
+ false,
+ },
+ {
+ "lsa_GetSystemAccessAccount",
+ sizeof(struct lsa_GetSystemAccessAccount),
+ (ndr_push_flags_fn_t) ndr_push_lsa_GetSystemAccessAccount,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_GetSystemAccessAccount,
+ (ndr_print_function_t) ndr_print_lsa_GetSystemAccessAccount,
+ false,
+ },
+ {
+ "lsa_SetSystemAccessAccount",
+ sizeof(struct lsa_SetSystemAccessAccount),
+ (ndr_push_flags_fn_t) ndr_push_lsa_SetSystemAccessAccount,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_SetSystemAccessAccount,
+ (ndr_print_function_t) ndr_print_lsa_SetSystemAccessAccount,
+ false,
+ },
+ {
+ "lsa_OpenTrustedDomain",
+ sizeof(struct lsa_OpenTrustedDomain),
+ (ndr_push_flags_fn_t) ndr_push_lsa_OpenTrustedDomain,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_OpenTrustedDomain,
+ (ndr_print_function_t) ndr_print_lsa_OpenTrustedDomain,
+ false,
+ },
+ {
+ "lsa_QueryTrustedDomainInfo",
+ sizeof(struct lsa_QueryTrustedDomainInfo),
+ (ndr_push_flags_fn_t) ndr_push_lsa_QueryTrustedDomainInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_QueryTrustedDomainInfo,
+ (ndr_print_function_t) ndr_print_lsa_QueryTrustedDomainInfo,
+ false,
+ },
+ {
+ "lsa_SetInformationTrustedDomain",
+ sizeof(struct lsa_SetInformationTrustedDomain),
+ (ndr_push_flags_fn_t) ndr_push_lsa_SetInformationTrustedDomain,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_SetInformationTrustedDomain,
+ (ndr_print_function_t) ndr_print_lsa_SetInformationTrustedDomain,
+ false,
+ },
+ {
+ "lsa_OpenSecret",
+ sizeof(struct lsa_OpenSecret),
+ (ndr_push_flags_fn_t) ndr_push_lsa_OpenSecret,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_OpenSecret,
+ (ndr_print_function_t) ndr_print_lsa_OpenSecret,
+ false,
+ },
+ {
+ "lsa_SetSecret",
+ sizeof(struct lsa_SetSecret),
+ (ndr_push_flags_fn_t) ndr_push_lsa_SetSecret,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_SetSecret,
+ (ndr_print_function_t) ndr_print_lsa_SetSecret,
+ false,
+ },
+ {
+ "lsa_QuerySecret",
+ sizeof(struct lsa_QuerySecret),
+ (ndr_push_flags_fn_t) ndr_push_lsa_QuerySecret,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_QuerySecret,
+ (ndr_print_function_t) ndr_print_lsa_QuerySecret,
+ false,
+ },
+ {
+ "lsa_LookupPrivValue",
+ sizeof(struct lsa_LookupPrivValue),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LookupPrivValue,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LookupPrivValue,
+ (ndr_print_function_t) ndr_print_lsa_LookupPrivValue,
+ false,
+ },
+ {
+ "lsa_LookupPrivName",
+ sizeof(struct lsa_LookupPrivName),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LookupPrivName,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LookupPrivName,
+ (ndr_print_function_t) ndr_print_lsa_LookupPrivName,
+ false,
+ },
+ {
+ "lsa_LookupPrivDisplayName",
+ sizeof(struct lsa_LookupPrivDisplayName),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LookupPrivDisplayName,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LookupPrivDisplayName,
+ (ndr_print_function_t) ndr_print_lsa_LookupPrivDisplayName,
+ false,
+ },
+ {
+ "lsa_DeleteObject",
+ sizeof(struct lsa_DeleteObject),
+ (ndr_push_flags_fn_t) ndr_push_lsa_DeleteObject,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_DeleteObject,
+ (ndr_print_function_t) ndr_print_lsa_DeleteObject,
+ false,
+ },
+ {
+ "lsa_EnumAccountsWithUserRight",
+ sizeof(struct lsa_EnumAccountsWithUserRight),
+ (ndr_push_flags_fn_t) ndr_push_lsa_EnumAccountsWithUserRight,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_EnumAccountsWithUserRight,
+ (ndr_print_function_t) ndr_print_lsa_EnumAccountsWithUserRight,
+ false,
+ },
+ {
+ "lsa_EnumAccountRights",
+ sizeof(struct lsa_EnumAccountRights),
+ (ndr_push_flags_fn_t) ndr_push_lsa_EnumAccountRights,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_EnumAccountRights,
+ (ndr_print_function_t) ndr_print_lsa_EnumAccountRights,
+ false,
+ },
+ {
+ "lsa_AddAccountRights",
+ sizeof(struct lsa_AddAccountRights),
+ (ndr_push_flags_fn_t) ndr_push_lsa_AddAccountRights,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_AddAccountRights,
+ (ndr_print_function_t) ndr_print_lsa_AddAccountRights,
+ false,
+ },
+ {
+ "lsa_RemoveAccountRights",
+ sizeof(struct lsa_RemoveAccountRights),
+ (ndr_push_flags_fn_t) ndr_push_lsa_RemoveAccountRights,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_RemoveAccountRights,
+ (ndr_print_function_t) ndr_print_lsa_RemoveAccountRights,
+ false,
+ },
+ {
+ "lsa_QueryTrustedDomainInfoBySid",
+ sizeof(struct lsa_QueryTrustedDomainInfoBySid),
+ (ndr_push_flags_fn_t) ndr_push_lsa_QueryTrustedDomainInfoBySid,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_QueryTrustedDomainInfoBySid,
+ (ndr_print_function_t) ndr_print_lsa_QueryTrustedDomainInfoBySid,
+ false,
+ },
+ {
+ "lsa_SetTrustedDomainInfo",
+ sizeof(struct lsa_SetTrustedDomainInfo),
+ (ndr_push_flags_fn_t) ndr_push_lsa_SetTrustedDomainInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_SetTrustedDomainInfo,
+ (ndr_print_function_t) ndr_print_lsa_SetTrustedDomainInfo,
+ false,
+ },
+ {
+ "lsa_DeleteTrustedDomain",
+ sizeof(struct lsa_DeleteTrustedDomain),
+ (ndr_push_flags_fn_t) ndr_push_lsa_DeleteTrustedDomain,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_DeleteTrustedDomain,
+ (ndr_print_function_t) ndr_print_lsa_DeleteTrustedDomain,
+ false,
+ },
+ {
+ "lsa_StorePrivateData",
+ sizeof(struct lsa_StorePrivateData),
+ (ndr_push_flags_fn_t) ndr_push_lsa_StorePrivateData,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_StorePrivateData,
+ (ndr_print_function_t) ndr_print_lsa_StorePrivateData,
+ false,
+ },
+ {
+ "lsa_RetrievePrivateData",
+ sizeof(struct lsa_RetrievePrivateData),
+ (ndr_push_flags_fn_t) ndr_push_lsa_RetrievePrivateData,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_RetrievePrivateData,
+ (ndr_print_function_t) ndr_print_lsa_RetrievePrivateData,
+ false,
+ },
+ {
+ "lsa_OpenPolicy2",
+ sizeof(struct lsa_OpenPolicy2),
+ (ndr_push_flags_fn_t) ndr_push_lsa_OpenPolicy2,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_OpenPolicy2,
+ (ndr_print_function_t) ndr_print_lsa_OpenPolicy2,
+ false,
+ },
+ {
+ "lsa_GetUserName",
+ sizeof(struct lsa_GetUserName),
+ (ndr_push_flags_fn_t) ndr_push_lsa_GetUserName,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_GetUserName,
+ (ndr_print_function_t) ndr_print_lsa_GetUserName,
+ false,
+ },
+ {
+ "lsa_QueryInfoPolicy2",
+ sizeof(struct lsa_QueryInfoPolicy2),
+ (ndr_push_flags_fn_t) ndr_push_lsa_QueryInfoPolicy2,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_QueryInfoPolicy2,
+ (ndr_print_function_t) ndr_print_lsa_QueryInfoPolicy2,
+ false,
+ },
+ {
+ "lsa_SetInfoPolicy2",
+ sizeof(struct lsa_SetInfoPolicy2),
+ (ndr_push_flags_fn_t) ndr_push_lsa_SetInfoPolicy2,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_SetInfoPolicy2,
+ (ndr_print_function_t) ndr_print_lsa_SetInfoPolicy2,
+ false,
+ },
+ {
+ "lsa_QueryTrustedDomainInfoByName",
+ sizeof(struct lsa_QueryTrustedDomainInfoByName),
+ (ndr_push_flags_fn_t) ndr_push_lsa_QueryTrustedDomainInfoByName,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_QueryTrustedDomainInfoByName,
+ (ndr_print_function_t) ndr_print_lsa_QueryTrustedDomainInfoByName,
+ false,
+ },
+ {
+ "lsa_SetTrustedDomainInfoByName",
+ sizeof(struct lsa_SetTrustedDomainInfoByName),
+ (ndr_push_flags_fn_t) ndr_push_lsa_SetTrustedDomainInfoByName,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_SetTrustedDomainInfoByName,
+ (ndr_print_function_t) ndr_print_lsa_SetTrustedDomainInfoByName,
+ false,
+ },
+ {
+ "lsa_EnumTrustedDomainsEx",
+ sizeof(struct lsa_EnumTrustedDomainsEx),
+ (ndr_push_flags_fn_t) ndr_push_lsa_EnumTrustedDomainsEx,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_EnumTrustedDomainsEx,
+ (ndr_print_function_t) ndr_print_lsa_EnumTrustedDomainsEx,
+ false,
+ },
+ {
+ "lsa_CreateTrustedDomainEx",
+ sizeof(struct lsa_CreateTrustedDomainEx),
+ (ndr_push_flags_fn_t) ndr_push_lsa_CreateTrustedDomainEx,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_CreateTrustedDomainEx,
+ (ndr_print_function_t) ndr_print_lsa_CreateTrustedDomainEx,
+ false,
+ },
+ {
+ "lsa_CloseTrustedDomainEx",
+ sizeof(struct lsa_CloseTrustedDomainEx),
+ (ndr_push_flags_fn_t) ndr_push_lsa_CloseTrustedDomainEx,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_CloseTrustedDomainEx,
+ (ndr_print_function_t) ndr_print_lsa_CloseTrustedDomainEx,
+ false,
+ },
+ {
+ "lsa_QueryDomainInformationPolicy",
+ sizeof(struct lsa_QueryDomainInformationPolicy),
+ (ndr_push_flags_fn_t) ndr_push_lsa_QueryDomainInformationPolicy,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_QueryDomainInformationPolicy,
+ (ndr_print_function_t) ndr_print_lsa_QueryDomainInformationPolicy,
+ false,
+ },
+ {
+ "lsa_SetDomainInformationPolicy",
+ sizeof(struct lsa_SetDomainInformationPolicy),
+ (ndr_push_flags_fn_t) ndr_push_lsa_SetDomainInformationPolicy,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_SetDomainInformationPolicy,
+ (ndr_print_function_t) ndr_print_lsa_SetDomainInformationPolicy,
+ false,
+ },
+ {
+ "lsa_OpenTrustedDomainByName",
+ sizeof(struct lsa_OpenTrustedDomainByName),
+ (ndr_push_flags_fn_t) ndr_push_lsa_OpenTrustedDomainByName,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_OpenTrustedDomainByName,
+ (ndr_print_function_t) ndr_print_lsa_OpenTrustedDomainByName,
+ false,
+ },
+ {
+ "lsa_TestCall",
+ sizeof(struct lsa_TestCall),
+ (ndr_push_flags_fn_t) ndr_push_lsa_TestCall,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_TestCall,
+ (ndr_print_function_t) ndr_print_lsa_TestCall,
+ false,
+ },
+ {
+ "lsa_LookupSids2",
+ sizeof(struct lsa_LookupSids2),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LookupSids2,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LookupSids2,
+ (ndr_print_function_t) ndr_print_lsa_LookupSids2,
+ false,
+ },
+ {
+ "lsa_LookupNames2",
+ sizeof(struct lsa_LookupNames2),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LookupNames2,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LookupNames2,
+ (ndr_print_function_t) ndr_print_lsa_LookupNames2,
+ false,
+ },
+ {
+ "lsa_CreateTrustedDomainEx2",
+ sizeof(struct lsa_CreateTrustedDomainEx2),
+ (ndr_push_flags_fn_t) ndr_push_lsa_CreateTrustedDomainEx2,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_CreateTrustedDomainEx2,
+ (ndr_print_function_t) ndr_print_lsa_CreateTrustedDomainEx2,
+ false,
+ },
+ {
+ "lsa_CREDRWRITE",
+ sizeof(struct lsa_CREDRWRITE),
+ (ndr_push_flags_fn_t) ndr_push_lsa_CREDRWRITE,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRWRITE,
+ (ndr_print_function_t) ndr_print_lsa_CREDRWRITE,
+ false,
+ },
+ {
+ "lsa_CREDRREAD",
+ sizeof(struct lsa_CREDRREAD),
+ (ndr_push_flags_fn_t) ndr_push_lsa_CREDRREAD,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRREAD,
+ (ndr_print_function_t) ndr_print_lsa_CREDRREAD,
+ false,
+ },
+ {
+ "lsa_CREDRENUMERATE",
+ sizeof(struct lsa_CREDRENUMERATE),
+ (ndr_push_flags_fn_t) ndr_push_lsa_CREDRENUMERATE,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRENUMERATE,
+ (ndr_print_function_t) ndr_print_lsa_CREDRENUMERATE,
+ false,
+ },
+ {
+ "lsa_CREDRWRITEDOMAINCREDENTIALS",
+ sizeof(struct lsa_CREDRWRITEDOMAINCREDENTIALS),
+ (ndr_push_flags_fn_t) ndr_push_lsa_CREDRWRITEDOMAINCREDENTIALS,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRWRITEDOMAINCREDENTIALS,
+ (ndr_print_function_t) ndr_print_lsa_CREDRWRITEDOMAINCREDENTIALS,
+ false,
+ },
+ {
+ "lsa_CREDRREADDOMAINCREDENTIALS",
+ sizeof(struct lsa_CREDRREADDOMAINCREDENTIALS),
+ (ndr_push_flags_fn_t) ndr_push_lsa_CREDRREADDOMAINCREDENTIALS,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRREADDOMAINCREDENTIALS,
+ (ndr_print_function_t) ndr_print_lsa_CREDRREADDOMAINCREDENTIALS,
+ false,
+ },
+ {
+ "lsa_CREDRDELETE",
+ sizeof(struct lsa_CREDRDELETE),
+ (ndr_push_flags_fn_t) ndr_push_lsa_CREDRDELETE,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRDELETE,
+ (ndr_print_function_t) ndr_print_lsa_CREDRDELETE,
+ false,
+ },
+ {
+ "lsa_CREDRGETTARGETINFO",
+ sizeof(struct lsa_CREDRGETTARGETINFO),
+ (ndr_push_flags_fn_t) ndr_push_lsa_CREDRGETTARGETINFO,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRGETTARGETINFO,
+ (ndr_print_function_t) ndr_print_lsa_CREDRGETTARGETINFO,
+ false,
+ },
+ {
+ "lsa_CREDRPROFILELOADED",
+ sizeof(struct lsa_CREDRPROFILELOADED),
+ (ndr_push_flags_fn_t) ndr_push_lsa_CREDRPROFILELOADED,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRPROFILELOADED,
+ (ndr_print_function_t) ndr_print_lsa_CREDRPROFILELOADED,
+ false,
+ },
+ {
+ "lsa_LookupNames3",
+ sizeof(struct lsa_LookupNames3),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LookupNames3,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LookupNames3,
+ (ndr_print_function_t) ndr_print_lsa_LookupNames3,
+ false,
+ },
+ {
+ "lsa_CREDRGETSESSIONTYPES",
+ sizeof(struct lsa_CREDRGETSESSIONTYPES),
+ (ndr_push_flags_fn_t) ndr_push_lsa_CREDRGETSESSIONTYPES,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRGETSESSIONTYPES,
+ (ndr_print_function_t) ndr_print_lsa_CREDRGETSESSIONTYPES,
+ false,
+ },
+ {
+ "lsa_LSARREGISTERAUDITEVENT",
+ sizeof(struct lsa_LSARREGISTERAUDITEVENT),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LSARREGISTERAUDITEVENT,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LSARREGISTERAUDITEVENT,
+ (ndr_print_function_t) ndr_print_lsa_LSARREGISTERAUDITEVENT,
+ false,
+ },
+ {
+ "lsa_LSARGENAUDITEVENT",
+ sizeof(struct lsa_LSARGENAUDITEVENT),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LSARGENAUDITEVENT,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LSARGENAUDITEVENT,
+ (ndr_print_function_t) ndr_print_lsa_LSARGENAUDITEVENT,
+ false,
+ },
+ {
+ "lsa_LSARUNREGISTERAUDITEVENT",
+ sizeof(struct lsa_LSARUNREGISTERAUDITEVENT),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LSARUNREGISTERAUDITEVENT,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LSARUNREGISTERAUDITEVENT,
+ (ndr_print_function_t) ndr_print_lsa_LSARUNREGISTERAUDITEVENT,
+ false,
+ },
+ {
+ "lsa_lsaRQueryForestTrustInformation",
+ sizeof(struct lsa_lsaRQueryForestTrustInformation),
+ (ndr_push_flags_fn_t) ndr_push_lsa_lsaRQueryForestTrustInformation,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_lsaRQueryForestTrustInformation,
+ (ndr_print_function_t) ndr_print_lsa_lsaRQueryForestTrustInformation,
+ false,
+ },
+ {
+ "lsa_LSARSETFORESTTRUSTINFORMATION",
+ sizeof(struct lsa_LSARSETFORESTTRUSTINFORMATION),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LSARSETFORESTTRUSTINFORMATION,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LSARSETFORESTTRUSTINFORMATION,
+ (ndr_print_function_t) ndr_print_lsa_LSARSETFORESTTRUSTINFORMATION,
+ false,
+ },
+ {
+ "lsa_CREDRRENAME",
+ sizeof(struct lsa_CREDRRENAME),
+ (ndr_push_flags_fn_t) ndr_push_lsa_CREDRRENAME,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRRENAME,
+ (ndr_print_function_t) ndr_print_lsa_CREDRRENAME,
+ false,
+ },
+ {
+ "lsa_LookupSids3",
+ sizeof(struct lsa_LookupSids3),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LookupSids3,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LookupSids3,
+ (ndr_print_function_t) ndr_print_lsa_LookupSids3,
+ false,
+ },
+ {
+ "lsa_LookupNames4",
+ sizeof(struct lsa_LookupNames4),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LookupNames4,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LookupNames4,
+ (ndr_print_function_t) ndr_print_lsa_LookupNames4,
+ false,
+ },
+ {
+ "lsa_LSAROPENPOLICYSCE",
+ sizeof(struct lsa_LSAROPENPOLICYSCE),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LSAROPENPOLICYSCE,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LSAROPENPOLICYSCE,
+ (ndr_print_function_t) ndr_print_lsa_LSAROPENPOLICYSCE,
+ false,
+ },
+ {
+ "lsa_LSARADTREGISTERSECURITYEVENTSOURCE",
+ sizeof(struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LSARADTREGISTERSECURITYEVENTSOURCE,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LSARADTREGISTERSECURITYEVENTSOURCE,
+ (ndr_print_function_t) ndr_print_lsa_LSARADTREGISTERSECURITYEVENTSOURCE,
+ false,
+ },
+ {
+ "lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE",
+ sizeof(struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE,
+ (ndr_print_function_t) ndr_print_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE,
+ false,
+ },
+ {
+ "lsa_LSARADTREPORTSECURITYEVENT",
+ sizeof(struct lsa_LSARADTREPORTSECURITYEVENT),
+ (ndr_push_flags_fn_t) ndr_push_lsa_LSARADTREPORTSECURITYEVENT,
+ (ndr_pull_flags_fn_t) ndr_pull_lsa_LSARADTREPORTSECURITYEVENT,
+ (ndr_print_function_t) ndr_print_lsa_LSARADTREPORTSECURITYEVENT,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const lsarpc_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\lsarpc]",
+ "ncacn_np:[\\pipe\\netlogon]",
+ "ncacn_np:[\\pipe\\lsass]",
+ "ncacn_ip_tcp:",
+ "ncalrpc:",
+};
+
+static const struct ndr_interface_string_array lsarpc_endpoints = {
+ .count = 5,
+ .names = lsarpc_endpoint_strings
+};
+
+static const char * const lsarpc_authservice_strings[] = {
+ "host",
+};
+
+static const struct ndr_interface_string_array lsarpc_authservices = {
+ .count = 1,
+ .names = lsarpc_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_lsarpc = {
+ .name = "lsarpc",
+ .syntax_id = {
+ {0x12345778,0x1234,0xabcd,{0xef,0x00},{0x01,0x23,0x45,0x67,0x89,0xab}},
+ NDR_LSARPC_VERSION
+ },
+ .helpstring = NDR_LSARPC_HELPSTRING,
+ .num_calls = 82,
+ .calls = lsarpc_calls,
+ .endpoints = &lsarpc_endpoints,
+ .authservices = &lsarpc_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_lsa.h b/source3/librpc/gen_ndr/ndr_lsa.h
new file mode 100644
index 0000000000..a489b5423e
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_lsa.h
@@ -0,0 +1,383 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/lsa.h"
+
+#ifndef _HEADER_NDR_lsarpc
+#define _HEADER_NDR_lsarpc
+
+#define NDR_LSARPC_UUID "12345778-1234-abcd-ef00-0123456789ab"
+#define NDR_LSARPC_VERSION 0.0
+#define NDR_LSARPC_NAME "lsarpc"
+#define NDR_LSARPC_HELPSTRING "Local Security Authority"
+extern const struct ndr_interface_table ndr_table_lsarpc;
+#define NDR_LSA_CLOSE (0x00)
+
+#define NDR_LSA_DELETE (0x01)
+
+#define NDR_LSA_ENUMPRIVS (0x02)
+
+#define NDR_LSA_QUERYSECURITY (0x03)
+
+#define NDR_LSA_SETSECOBJ (0x04)
+
+#define NDR_LSA_CHANGEPASSWORD (0x05)
+
+#define NDR_LSA_OPENPOLICY (0x06)
+
+#define NDR_LSA_QUERYINFOPOLICY (0x07)
+
+#define NDR_LSA_SETINFOPOLICY (0x08)
+
+#define NDR_LSA_CLEARAUDITLOG (0x09)
+
+#define NDR_LSA_CREATEACCOUNT (0x0a)
+
+#define NDR_LSA_ENUMACCOUNTS (0x0b)
+
+#define NDR_LSA_CREATETRUSTEDDOMAIN (0x0c)
+
+#define NDR_LSA_ENUMTRUSTDOM (0x0d)
+
+#define NDR_LSA_LOOKUPNAMES (0x0e)
+
+#define NDR_LSA_LOOKUPSIDS (0x0f)
+
+#define NDR_LSA_CREATESECRET (0x10)
+
+#define NDR_LSA_OPENACCOUNT (0x11)
+
+#define NDR_LSA_ENUMPRIVSACCOUNT (0x12)
+
+#define NDR_LSA_ADDPRIVILEGESTOACCOUNT (0x13)
+
+#define NDR_LSA_REMOVEPRIVILEGESFROMACCOUNT (0x14)
+
+#define NDR_LSA_GETQUOTASFORACCOUNT (0x15)
+
+#define NDR_LSA_SETQUOTASFORACCOUNT (0x16)
+
+#define NDR_LSA_GETSYSTEMACCESSACCOUNT (0x17)
+
+#define NDR_LSA_SETSYSTEMACCESSACCOUNT (0x18)
+
+#define NDR_LSA_OPENTRUSTEDDOMAIN (0x19)
+
+#define NDR_LSA_QUERYTRUSTEDDOMAININFO (0x1a)
+
+#define NDR_LSA_SETINFORMATIONTRUSTEDDOMAIN (0x1b)
+
+#define NDR_LSA_OPENSECRET (0x1c)
+
+#define NDR_LSA_SETSECRET (0x1d)
+
+#define NDR_LSA_QUERYSECRET (0x1e)
+
+#define NDR_LSA_LOOKUPPRIVVALUE (0x1f)
+
+#define NDR_LSA_LOOKUPPRIVNAME (0x20)
+
+#define NDR_LSA_LOOKUPPRIVDISPLAYNAME (0x21)
+
+#define NDR_LSA_DELETEOBJECT (0x22)
+
+#define NDR_LSA_ENUMACCOUNTSWITHUSERRIGHT (0x23)
+
+#define NDR_LSA_ENUMACCOUNTRIGHTS (0x24)
+
+#define NDR_LSA_ADDACCOUNTRIGHTS (0x25)
+
+#define NDR_LSA_REMOVEACCOUNTRIGHTS (0x26)
+
+#define NDR_LSA_QUERYTRUSTEDDOMAININFOBYSID (0x27)
+
+#define NDR_LSA_SETTRUSTEDDOMAININFO (0x28)
+
+#define NDR_LSA_DELETETRUSTEDDOMAIN (0x29)
+
+#define NDR_LSA_STOREPRIVATEDATA (0x2a)
+
+#define NDR_LSA_RETRIEVEPRIVATEDATA (0x2b)
+
+#define NDR_LSA_OPENPOLICY2 (0x2c)
+
+#define NDR_LSA_GETUSERNAME (0x2d)
+
+#define NDR_LSA_QUERYINFOPOLICY2 (0x2e)
+
+#define NDR_LSA_SETINFOPOLICY2 (0x2f)
+
+#define NDR_LSA_QUERYTRUSTEDDOMAININFOBYNAME (0x30)
+
+#define NDR_LSA_SETTRUSTEDDOMAININFOBYNAME (0x31)
+
+#define NDR_LSA_ENUMTRUSTEDDOMAINSEX (0x32)
+
+#define NDR_LSA_CREATETRUSTEDDOMAINEX (0x33)
+
+#define NDR_LSA_CLOSETRUSTEDDOMAINEX (0x34)
+
+#define NDR_LSA_QUERYDOMAININFORMATIONPOLICY (0x35)
+
+#define NDR_LSA_SETDOMAININFORMATIONPOLICY (0x36)
+
+#define NDR_LSA_OPENTRUSTEDDOMAINBYNAME (0x37)
+
+#define NDR_LSA_TESTCALL (0x38)
+
+#define NDR_LSA_LOOKUPSIDS2 (0x39)
+
+#define NDR_LSA_LOOKUPNAMES2 (0x3a)
+
+#define NDR_LSA_CREATETRUSTEDDOMAINEX2 (0x3b)
+
+#define NDR_LSA_CREDRWRITE (0x3c)
+
+#define NDR_LSA_CREDRREAD (0x3d)
+
+#define NDR_LSA_CREDRENUMERATE (0x3e)
+
+#define NDR_LSA_CREDRWRITEDOMAINCREDENTIALS (0x3f)
+
+#define NDR_LSA_CREDRREADDOMAINCREDENTIALS (0x40)
+
+#define NDR_LSA_CREDRDELETE (0x41)
+
+#define NDR_LSA_CREDRGETTARGETINFO (0x42)
+
+#define NDR_LSA_CREDRPROFILELOADED (0x43)
+
+#define NDR_LSA_LOOKUPNAMES3 (0x44)
+
+#define NDR_LSA_CREDRGETSESSIONTYPES (0x45)
+
+#define NDR_LSA_LSARREGISTERAUDITEVENT (0x46)
+
+#define NDR_LSA_LSARGENAUDITEVENT (0x47)
+
+#define NDR_LSA_LSARUNREGISTERAUDITEVENT (0x48)
+
+#define NDR_LSA_LSARQUERYFORESTTRUSTINFORMATION (0x49)
+
+#define NDR_LSA_LSARSETFORESTTRUSTINFORMATION (0x4a)
+
+#define NDR_LSA_CREDRRENAME (0x4b)
+
+#define NDR_LSA_LOOKUPSIDS3 (0x4c)
+
+#define NDR_LSA_LOOKUPNAMES4 (0x4d)
+
+#define NDR_LSA_LSAROPENPOLICYSCE (0x4e)
+
+#define NDR_LSA_LSARADTREGISTERSECURITYEVENTSOURCE (0x4f)
+
+#define NDR_LSA_LSARADTUNREGISTERSECURITYEVENTSOURCE (0x50)
+
+#define NDR_LSA_LSARADTREPORTSECURITYEVENT (0x51)
+
+#define NDR_LSARPC_CALL_COUNT (82)
+enum ndr_err_code ndr_push_lsa_String(struct ndr_push *ndr, int ndr_flags, const struct lsa_String *r);
+enum ndr_err_code ndr_pull_lsa_String(struct ndr_pull *ndr, int ndr_flags, struct lsa_String *r);
+void ndr_print_lsa_String(struct ndr_print *ndr, const char *name, const struct lsa_String *r);
+enum ndr_err_code ndr_push_lsa_StringLarge(struct ndr_push *ndr, int ndr_flags, const struct lsa_StringLarge *r);
+enum ndr_err_code ndr_pull_lsa_StringLarge(struct ndr_pull *ndr, int ndr_flags, struct lsa_StringLarge *r);
+void ndr_print_lsa_StringLarge(struct ndr_print *ndr, const char *name, const struct lsa_StringLarge *r);
+enum ndr_err_code ndr_push_lsa_Strings(struct ndr_push *ndr, int ndr_flags, const struct lsa_Strings *r);
+enum ndr_err_code ndr_pull_lsa_Strings(struct ndr_pull *ndr, int ndr_flags, struct lsa_Strings *r);
+void ndr_print_lsa_Strings(struct ndr_print *ndr, const char *name, const struct lsa_Strings *r);
+enum ndr_err_code ndr_push_lsa_AsciiString(struct ndr_push *ndr, int ndr_flags, const struct lsa_AsciiString *r);
+enum ndr_err_code ndr_pull_lsa_AsciiString(struct ndr_pull *ndr, int ndr_flags, struct lsa_AsciiString *r);
+void ndr_print_lsa_AsciiString(struct ndr_print *ndr, const char *name, const struct lsa_AsciiString *r);
+enum ndr_err_code ndr_push_lsa_AsciiStringLarge(struct ndr_push *ndr, int ndr_flags, const struct lsa_AsciiStringLarge *r);
+enum ndr_err_code ndr_pull_lsa_AsciiStringLarge(struct ndr_pull *ndr, int ndr_flags, struct lsa_AsciiStringLarge *r);
+void ndr_print_lsa_AsciiStringLarge(struct ndr_print *ndr, const char *name, const struct lsa_AsciiStringLarge *r);
+enum ndr_err_code ndr_push_lsa_BinaryString(struct ndr_push *ndr, int ndr_flags, const struct lsa_BinaryString *r);
+enum ndr_err_code ndr_pull_lsa_BinaryString(struct ndr_pull *ndr, int ndr_flags, struct lsa_BinaryString *r);
+void ndr_print_lsa_BinaryString(struct ndr_print *ndr, const char *name, const struct lsa_BinaryString *r);
+void ndr_print_lsa_LUID(struct ndr_print *ndr, const char *name, const struct lsa_LUID *r);
+void ndr_print_lsa_PrivEntry(struct ndr_print *ndr, const char *name, const struct lsa_PrivEntry *r);
+void ndr_print_lsa_PrivArray(struct ndr_print *ndr, const char *name, const struct lsa_PrivArray *r);
+void ndr_print_lsa_QosInfo(struct ndr_print *ndr, const char *name, const struct lsa_QosInfo *r);
+void ndr_print_lsa_ObjectAttribute(struct ndr_print *ndr, const char *name, const struct lsa_ObjectAttribute *r);
+enum ndr_err_code ndr_push_lsa_PolicyAccessMask(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_lsa_PolicyAccessMask(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_lsa_PolicyAccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_lsa_AuditLogInfo(struct ndr_print *ndr, const char *name, const struct lsa_AuditLogInfo *r);
+void ndr_print_lsa_PolicyAuditPolicy(struct ndr_print *ndr, const char *name, enum lsa_PolicyAuditPolicy r);
+void ndr_print_lsa_AuditEventsInfo(struct ndr_print *ndr, const char *name, const struct lsa_AuditEventsInfo *r);
+void ndr_print_lsa_DomainInfo(struct ndr_print *ndr, const char *name, const struct lsa_DomainInfo *r);
+void ndr_print_lsa_PDAccountInfo(struct ndr_print *ndr, const char *name, const struct lsa_PDAccountInfo *r);
+void ndr_print_lsa_ServerRole(struct ndr_print *ndr, const char *name, const struct lsa_ServerRole *r);
+void ndr_print_lsa_ReplicaSourceInfo(struct ndr_print *ndr, const char *name, const struct lsa_ReplicaSourceInfo *r);
+void ndr_print_lsa_DefaultQuotaInfo(struct ndr_print *ndr, const char *name, const struct lsa_DefaultQuotaInfo *r);
+void ndr_print_lsa_ModificationInfo(struct ndr_print *ndr, const char *name, const struct lsa_ModificationInfo *r);
+void ndr_print_lsa_AuditFullSetInfo(struct ndr_print *ndr, const char *name, const struct lsa_AuditFullSetInfo *r);
+void ndr_print_lsa_AuditFullQueryInfo(struct ndr_print *ndr, const char *name, const struct lsa_AuditFullQueryInfo *r);
+void ndr_print_lsa_DnsDomainInfo(struct ndr_print *ndr, const char *name, const struct lsa_DnsDomainInfo *r);
+void ndr_print_lsa_PolicyInfo(struct ndr_print *ndr, const char *name, enum lsa_PolicyInfo r);
+void ndr_print_lsa_PolicyInformation(struct ndr_print *ndr, const char *name, const union lsa_PolicyInformation *r);
+void ndr_print_lsa_SidPtr(struct ndr_print *ndr, const char *name, const struct lsa_SidPtr *r);
+enum ndr_err_code ndr_push_lsa_SidArray(struct ndr_push *ndr, int ndr_flags, const struct lsa_SidArray *r);
+enum ndr_err_code ndr_pull_lsa_SidArray(struct ndr_pull *ndr, int ndr_flags, struct lsa_SidArray *r);
+void ndr_print_lsa_SidArray(struct ndr_print *ndr, const char *name, const struct lsa_SidArray *r);
+void ndr_print_lsa_DomainList(struct ndr_print *ndr, const char *name, const struct lsa_DomainList *r);
+void ndr_print_lsa_SidType(struct ndr_print *ndr, const char *name, enum lsa_SidType r);
+void ndr_print_lsa_TranslatedSid(struct ndr_print *ndr, const char *name, const struct lsa_TranslatedSid *r);
+void ndr_print_lsa_TransSidArray(struct ndr_print *ndr, const char *name, const struct lsa_TransSidArray *r);
+void ndr_print_lsa_RefDomainList(struct ndr_print *ndr, const char *name, const struct lsa_RefDomainList *r);
+void ndr_print_lsa_LookupNamesLevel(struct ndr_print *ndr, const char *name, enum lsa_LookupNamesLevel r);
+void ndr_print_lsa_TranslatedName(struct ndr_print *ndr, const char *name, const struct lsa_TranslatedName *r);
+void ndr_print_lsa_TransNameArray(struct ndr_print *ndr, const char *name, const struct lsa_TransNameArray *r);
+void ndr_print_lsa_LUIDAttribute(struct ndr_print *ndr, const char *name, const struct lsa_LUIDAttribute *r);
+void ndr_print_lsa_PrivilegeSet(struct ndr_print *ndr, const char *name, const struct lsa_PrivilegeSet *r);
+void ndr_print_lsa_DATA_BUF(struct ndr_print *ndr, const char *name, const struct lsa_DATA_BUF *r);
+void ndr_print_lsa_DATA_BUF2(struct ndr_print *ndr, const char *name, const struct lsa_DATA_BUF2 *r);
+void ndr_print_lsa_TrustDomInfoEnum(struct ndr_print *ndr, const char *name, enum lsa_TrustDomInfoEnum r);
+void ndr_print_lsa_TrustDomainInfoName(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoName *r);
+void ndr_print_lsa_TrustDomainInfoPosixOffset(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoPosixOffset *r);
+void ndr_print_lsa_TrustDomainInfoPassword(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoPassword *r);
+void ndr_print_lsa_TrustDomainInfoBasic(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoBasic *r);
+void ndr_print_lsa_TrustDomainInfoInfoEx(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoInfoEx *r);
+void ndr_print_lsa_TrustDomainInfoBuffer(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoBuffer *r);
+void ndr_print_lsa_TrustDomainInfoAuthInfo(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoAuthInfo *r);
+void ndr_print_lsa_TrustDomainInfoFullInfo(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoFullInfo *r);
+void ndr_print_lsa_TrustDomainInfo11(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfo11 *r);
+void ndr_print_lsa_TrustDomainInfoInfoAll(struct ndr_print *ndr, const char *name, const struct lsa_TrustDomainInfoInfoAll *r);
+void ndr_print_lsa_TrustedDomainInfo(struct ndr_print *ndr, const char *name, const union lsa_TrustedDomainInfo *r);
+void ndr_print_lsa_DATA_BUF_PTR(struct ndr_print *ndr, const char *name, const struct lsa_DATA_BUF_PTR *r);
+void ndr_print_lsa_RightSet(struct ndr_print *ndr, const char *name, const struct lsa_RightSet *r);
+void ndr_print_lsa_DomainListEx(struct ndr_print *ndr, const char *name, const struct lsa_DomainListEx *r);
+void ndr_print_lsa_DomainInfoKerberos(struct ndr_print *ndr, const char *name, const struct lsa_DomainInfoKerberos *r);
+void ndr_print_lsa_DomainInfoEfs(struct ndr_print *ndr, const char *name, const struct lsa_DomainInfoEfs *r);
+void ndr_print_lsa_DomainInformationPolicy(struct ndr_print *ndr, const char *name, const union lsa_DomainInformationPolicy *r);
+void ndr_print_lsa_TranslatedName2(struct ndr_print *ndr, const char *name, const struct lsa_TranslatedName2 *r);
+void ndr_print_lsa_TransNameArray2(struct ndr_print *ndr, const char *name, const struct lsa_TransNameArray2 *r);
+void ndr_print_lsa_TranslatedSid2(struct ndr_print *ndr, const char *name, const struct lsa_TranslatedSid2 *r);
+void ndr_print_lsa_TransSidArray2(struct ndr_print *ndr, const char *name, const struct lsa_TransSidArray2 *r);
+void ndr_print_lsa_TranslatedSid3(struct ndr_print *ndr, const char *name, const struct lsa_TranslatedSid3 *r);
+void ndr_print_lsa_TransSidArray3(struct ndr_print *ndr, const char *name, const struct lsa_TransSidArray3 *r);
+void ndr_print_lsa_ForestTrustBinaryData(struct ndr_print *ndr, const char *name, const struct lsa_ForestTrustBinaryData *r);
+void ndr_print_lsa_ForestTrustDomainInfo(struct ndr_print *ndr, const char *name, const struct lsa_ForestTrustDomainInfo *r);
+void ndr_print_lsa_ForestTrustData(struct ndr_print *ndr, const char *name, const union lsa_ForestTrustData *r);
+void ndr_print_lsa_ForestTrustRecordType(struct ndr_print *ndr, const char *name, enum lsa_ForestTrustRecordType r);
+void ndr_print_lsa_ForestTrustRecord(struct ndr_print *ndr, const char *name, const struct lsa_ForestTrustRecord *r);
+enum ndr_err_code ndr_push_lsa_ForestTrustInformation(struct ndr_push *ndr, int ndr_flags, const struct lsa_ForestTrustInformation *r);
+enum ndr_err_code ndr_pull_lsa_ForestTrustInformation(struct ndr_pull *ndr, int ndr_flags, struct lsa_ForestTrustInformation *r);
+void ndr_print_lsa_ForestTrustInformation(struct ndr_print *ndr, const char *name, const struct lsa_ForestTrustInformation *r);
+void ndr_print_lsa_Close(struct ndr_print *ndr, const char *name, int flags, const struct lsa_Close *r);
+enum ndr_err_code ndr_push_lsa_Delete(struct ndr_push *ndr, int flags, const struct lsa_Delete *r);
+enum ndr_err_code ndr_pull_lsa_Delete(struct ndr_pull *ndr, int flags, struct lsa_Delete *r);
+void ndr_print_lsa_Delete(struct ndr_print *ndr, const char *name, int flags, const struct lsa_Delete *r);
+enum ndr_err_code ndr_push_lsa_EnumPrivs(struct ndr_push *ndr, int flags, const struct lsa_EnumPrivs *r);
+enum ndr_err_code ndr_pull_lsa_EnumPrivs(struct ndr_pull *ndr, int flags, struct lsa_EnumPrivs *r);
+void ndr_print_lsa_EnumPrivs(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumPrivs *r);
+void ndr_print_lsa_QuerySecurity(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QuerySecurity *r);
+void ndr_print_lsa_SetSecObj(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetSecObj *r);
+void ndr_print_lsa_ChangePassword(struct ndr_print *ndr, const char *name, int flags, const struct lsa_ChangePassword *r);
+enum ndr_err_code ndr_push_lsa_OpenPolicy(struct ndr_push *ndr, int flags, const struct lsa_OpenPolicy *r);
+enum ndr_err_code ndr_pull_lsa_OpenPolicy(struct ndr_pull *ndr, int flags, struct lsa_OpenPolicy *r);
+void ndr_print_lsa_OpenPolicy(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenPolicy *r);
+void ndr_print_lsa_QueryInfoPolicy(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryInfoPolicy *r);
+void ndr_print_lsa_SetInfoPolicy(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetInfoPolicy *r);
+void ndr_print_lsa_ClearAuditLog(struct ndr_print *ndr, const char *name, int flags, const struct lsa_ClearAuditLog *r);
+enum ndr_err_code ndr_push_lsa_CreateAccount(struct ndr_push *ndr, int flags, const struct lsa_CreateAccount *r);
+enum ndr_err_code ndr_pull_lsa_CreateAccount(struct ndr_pull *ndr, int flags, struct lsa_CreateAccount *r);
+void ndr_print_lsa_CreateAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CreateAccount *r);
+enum ndr_err_code ndr_push_lsa_EnumAccounts(struct ndr_push *ndr, int flags, const struct lsa_EnumAccounts *r);
+enum ndr_err_code ndr_pull_lsa_EnumAccounts(struct ndr_pull *ndr, int flags, struct lsa_EnumAccounts *r);
+void ndr_print_lsa_EnumAccounts(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumAccounts *r);
+enum ndr_err_code ndr_push_lsa_CreateTrustedDomain(struct ndr_push *ndr, int flags, const struct lsa_CreateTrustedDomain *r);
+enum ndr_err_code ndr_pull_lsa_CreateTrustedDomain(struct ndr_pull *ndr, int flags, struct lsa_CreateTrustedDomain *r);
+void ndr_print_lsa_CreateTrustedDomain(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CreateTrustedDomain *r);
+void ndr_print_lsa_EnumTrustDom(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumTrustDom *r);
+enum ndr_err_code ndr_push_lsa_LookupNames(struct ndr_push *ndr, int flags, const struct lsa_LookupNames *r);
+enum ndr_err_code ndr_pull_lsa_LookupNames(struct ndr_pull *ndr, int flags, struct lsa_LookupNames *r);
+void ndr_print_lsa_LookupNames(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupNames *r);
+enum ndr_err_code ndr_push_lsa_LookupSids(struct ndr_push *ndr, int flags, const struct lsa_LookupSids *r);
+enum ndr_err_code ndr_pull_lsa_LookupSids(struct ndr_pull *ndr, int flags, struct lsa_LookupSids *r);
+void ndr_print_lsa_LookupSids(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupSids *r);
+enum ndr_err_code ndr_push_lsa_CreateSecret(struct ndr_push *ndr, int flags, const struct lsa_CreateSecret *r);
+enum ndr_err_code ndr_pull_lsa_CreateSecret(struct ndr_pull *ndr, int flags, struct lsa_CreateSecret *r);
+void ndr_print_lsa_CreateSecret(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CreateSecret *r);
+void ndr_print_lsa_OpenAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenAccount *r);
+void ndr_print_lsa_EnumPrivsAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumPrivsAccount *r);
+void ndr_print_lsa_AddPrivilegesToAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_AddPrivilegesToAccount *r);
+void ndr_print_lsa_RemovePrivilegesFromAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_RemovePrivilegesFromAccount *r);
+void ndr_print_lsa_GetQuotasForAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_GetQuotasForAccount *r);
+void ndr_print_lsa_SetQuotasForAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetQuotasForAccount *r);
+void ndr_print_lsa_GetSystemAccessAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_GetSystemAccessAccount *r);
+void ndr_print_lsa_SetSystemAccessAccount(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetSystemAccessAccount *r);
+void ndr_print_lsa_OpenTrustedDomain(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenTrustedDomain *r);
+void ndr_print_lsa_QueryTrustedDomainInfo(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryTrustedDomainInfo *r);
+void ndr_print_lsa_SetInformationTrustedDomain(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetInformationTrustedDomain *r);
+enum ndr_err_code ndr_push_lsa_OpenSecret(struct ndr_push *ndr, int flags, const struct lsa_OpenSecret *r);
+enum ndr_err_code ndr_pull_lsa_OpenSecret(struct ndr_pull *ndr, int flags, struct lsa_OpenSecret *r);
+void ndr_print_lsa_OpenSecret(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenSecret *r);
+enum ndr_err_code ndr_push_lsa_SetSecret(struct ndr_push *ndr, int flags, const struct lsa_SetSecret *r);
+enum ndr_err_code ndr_pull_lsa_SetSecret(struct ndr_pull *ndr, int flags, struct lsa_SetSecret *r);
+void ndr_print_lsa_SetSecret(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetSecret *r);
+enum ndr_err_code ndr_push_lsa_QuerySecret(struct ndr_push *ndr, int flags, const struct lsa_QuerySecret *r);
+enum ndr_err_code ndr_pull_lsa_QuerySecret(struct ndr_pull *ndr, int flags, struct lsa_QuerySecret *r);
+void ndr_print_lsa_QuerySecret(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QuerySecret *r);
+void ndr_print_lsa_LookupPrivValue(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupPrivValue *r);
+void ndr_print_lsa_LookupPrivName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupPrivName *r);
+void ndr_print_lsa_LookupPrivDisplayName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupPrivDisplayName *r);
+void ndr_print_lsa_DeleteObject(struct ndr_print *ndr, const char *name, int flags, const struct lsa_DeleteObject *r);
+void ndr_print_lsa_EnumAccountsWithUserRight(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumAccountsWithUserRight *r);
+void ndr_print_lsa_EnumAccountRights(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumAccountRights *r);
+void ndr_print_lsa_AddAccountRights(struct ndr_print *ndr, const char *name, int flags, const struct lsa_AddAccountRights *r);
+void ndr_print_lsa_RemoveAccountRights(struct ndr_print *ndr, const char *name, int flags, const struct lsa_RemoveAccountRights *r);
+void ndr_print_lsa_QueryTrustedDomainInfoBySid(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryTrustedDomainInfoBySid *r);
+void ndr_print_lsa_SetTrustedDomainInfo(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetTrustedDomainInfo *r);
+void ndr_print_lsa_DeleteTrustedDomain(struct ndr_print *ndr, const char *name, int flags, const struct lsa_DeleteTrustedDomain *r);
+void ndr_print_lsa_StorePrivateData(struct ndr_print *ndr, const char *name, int flags, const struct lsa_StorePrivateData *r);
+void ndr_print_lsa_RetrievePrivateData(struct ndr_print *ndr, const char *name, int flags, const struct lsa_RetrievePrivateData *r);
+enum ndr_err_code ndr_push_lsa_OpenPolicy2(struct ndr_push *ndr, int flags, const struct lsa_OpenPolicy2 *r);
+enum ndr_err_code ndr_pull_lsa_OpenPolicy2(struct ndr_pull *ndr, int flags, struct lsa_OpenPolicy2 *r);
+void ndr_print_lsa_OpenPolicy2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenPolicy2 *r);
+void ndr_print_lsa_GetUserName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_GetUserName *r);
+void ndr_print_lsa_QueryInfoPolicy2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryInfoPolicy2 *r);
+void ndr_print_lsa_SetInfoPolicy2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetInfoPolicy2 *r);
+void ndr_print_lsa_QueryTrustedDomainInfoByName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryTrustedDomainInfoByName *r);
+void ndr_print_lsa_SetTrustedDomainInfoByName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetTrustedDomainInfoByName *r);
+void ndr_print_lsa_EnumTrustedDomainsEx(struct ndr_print *ndr, const char *name, int flags, const struct lsa_EnumTrustedDomainsEx *r);
+void ndr_print_lsa_CreateTrustedDomainEx(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CreateTrustedDomainEx *r);
+void ndr_print_lsa_CloseTrustedDomainEx(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CloseTrustedDomainEx *r);
+void ndr_print_lsa_QueryDomainInformationPolicy(struct ndr_print *ndr, const char *name, int flags, const struct lsa_QueryDomainInformationPolicy *r);
+void ndr_print_lsa_SetDomainInformationPolicy(struct ndr_print *ndr, const char *name, int flags, const struct lsa_SetDomainInformationPolicy *r);
+void ndr_print_lsa_OpenTrustedDomainByName(struct ndr_print *ndr, const char *name, int flags, const struct lsa_OpenTrustedDomainByName *r);
+void ndr_print_lsa_TestCall(struct ndr_print *ndr, const char *name, int flags, const struct lsa_TestCall *r);
+enum ndr_err_code ndr_push_lsa_LookupSids2(struct ndr_push *ndr, int flags, const struct lsa_LookupSids2 *r);
+enum ndr_err_code ndr_pull_lsa_LookupSids2(struct ndr_pull *ndr, int flags, struct lsa_LookupSids2 *r);
+void ndr_print_lsa_LookupSids2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupSids2 *r);
+enum ndr_err_code ndr_push_lsa_LookupNames2(struct ndr_push *ndr, int flags, const struct lsa_LookupNames2 *r);
+enum ndr_err_code ndr_pull_lsa_LookupNames2(struct ndr_pull *ndr, int flags, struct lsa_LookupNames2 *r);
+void ndr_print_lsa_LookupNames2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupNames2 *r);
+void ndr_print_lsa_CreateTrustedDomainEx2(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CreateTrustedDomainEx2 *r);
+void ndr_print_lsa_CREDRWRITE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRWRITE *r);
+void ndr_print_lsa_CREDRREAD(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRREAD *r);
+void ndr_print_lsa_CREDRENUMERATE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRENUMERATE *r);
+void ndr_print_lsa_CREDRWRITEDOMAINCREDENTIALS(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRWRITEDOMAINCREDENTIALS *r);
+void ndr_print_lsa_CREDRREADDOMAINCREDENTIALS(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRREADDOMAINCREDENTIALS *r);
+void ndr_print_lsa_CREDRDELETE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRDELETE *r);
+void ndr_print_lsa_CREDRGETTARGETINFO(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRGETTARGETINFO *r);
+void ndr_print_lsa_CREDRPROFILELOADED(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRPROFILELOADED *r);
+enum ndr_err_code ndr_push_lsa_LookupNames3(struct ndr_push *ndr, int flags, const struct lsa_LookupNames3 *r);
+enum ndr_err_code ndr_pull_lsa_LookupNames3(struct ndr_pull *ndr, int flags, struct lsa_LookupNames3 *r);
+void ndr_print_lsa_LookupNames3(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupNames3 *r);
+void ndr_print_lsa_CREDRGETSESSIONTYPES(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRGETSESSIONTYPES *r);
+void ndr_print_lsa_LSARREGISTERAUDITEVENT(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARREGISTERAUDITEVENT *r);
+void ndr_print_lsa_LSARGENAUDITEVENT(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARGENAUDITEVENT *r);
+void ndr_print_lsa_LSARUNREGISTERAUDITEVENT(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARUNREGISTERAUDITEVENT *r);
+void ndr_print_lsa_lsaRQueryForestTrustInformation(struct ndr_print *ndr, const char *name, int flags, const struct lsa_lsaRQueryForestTrustInformation *r);
+void ndr_print_lsa_LSARSETFORESTTRUSTINFORMATION(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARSETFORESTTRUSTINFORMATION *r);
+void ndr_print_lsa_CREDRRENAME(struct ndr_print *ndr, const char *name, int flags, const struct lsa_CREDRRENAME *r);
+enum ndr_err_code ndr_push_lsa_LookupSids3(struct ndr_push *ndr, int flags, const struct lsa_LookupSids3 *r);
+enum ndr_err_code ndr_pull_lsa_LookupSids3(struct ndr_pull *ndr, int flags, struct lsa_LookupSids3 *r);
+void ndr_print_lsa_LookupSids3(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupSids3 *r);
+void ndr_print_lsa_LookupNames4(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LookupNames4 *r);
+void ndr_print_lsa_LSAROPENPOLICYSCE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSAROPENPOLICYSCE *r);
+void ndr_print_lsa_LSARADTREGISTERSECURITYEVENTSOURCE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE *r);
+void ndr_print_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE *r);
+void ndr_print_lsa_LSARADTREPORTSECURITYEVENT(struct ndr_print *ndr, const char *name, int flags, const struct lsa_LSARADTREPORTSECURITYEVENT *r);
+#endif /* _HEADER_NDR_lsarpc */
diff --git a/source3/librpc/gen_ndr/ndr_messaging.c b/source3/librpc/gen_ndr/ndr_messaging.c
new file mode 100644
index 0000000000..e1e95eef4e
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_messaging.c
@@ -0,0 +1,270 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_messaging.h"
+
+_PUBLIC_ enum ndr_err_code ndr_push_messaging_type(struct ndr_push *ndr, int ndr_flags, enum messaging_type r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_messaging_type(struct ndr_pull *ndr, int ndr_flags, enum messaging_type *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_messaging_type(struct ndr_print *ndr, const char *name, enum messaging_type r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case MSG_DEBUG: val = "MSG_DEBUG"; break;
+ case MSG_PING: val = "MSG_PING"; break;
+ case MSG_PONG: val = "MSG_PONG"; break;
+ case MSG_PROFILE: val = "MSG_PROFILE"; break;
+ case MSG_REQ_DEBUGLEVEL: val = "MSG_REQ_DEBUGLEVEL"; break;
+ case MSG_DEBUGLEVEL: val = "MSG_DEBUGLEVEL"; break;
+ case MSG_REQ_PROFILELEVEL: val = "MSG_REQ_PROFILELEVEL"; break;
+ case MSG_PROFILELEVEL: val = "MSG_PROFILELEVEL"; break;
+ case MSG_REQ_POOL_USAGE: val = "MSG_REQ_POOL_USAGE"; break;
+ case MSG_POOL_USAGE: val = "MSG_POOL_USAGE"; break;
+ case MSG_REQ_DMALLOC_MARK: val = "MSG_REQ_DMALLOC_MARK"; break;
+ case MSG_REQ_DMALLOC_LOG_CHANGED: val = "MSG_REQ_DMALLOC_LOG_CHANGED"; break;
+ case MSG_SHUTDOWN: val = "MSG_SHUTDOWN"; break;
+ case MSG_FORCE_ELECTION: val = "MSG_FORCE_ELECTION"; break;
+ case MSG_WINS_NEW_ENTRY: val = "MSG_WINS_NEW_ENTRY"; break;
+ case MSG_SEND_PACKET: val = "MSG_SEND_PACKET"; break;
+ case MSG_PRINTER_NOTIFY: val = "MSG_PRINTER_NOTIFY"; break;
+ case MSG_PRINTER_NOTIFY2: val = "MSG_PRINTER_NOTIFY2"; break;
+ case MSG_PRINTER_DRVUPGRADE: val = "MSG_PRINTER_DRVUPGRADE"; break;
+ case MSG_PRINTERDATA_INIT_RESET: val = "MSG_PRINTERDATA_INIT_RESET"; break;
+ case MSG_PRINTER_UPDATE: val = "MSG_PRINTER_UPDATE"; break;
+ case MSG_PRINTER_MOD: val = "MSG_PRINTER_MOD"; break;
+ case MSG_SMB_CONF_UPDATED: val = "MSG_SMB_CONF_UPDATED"; break;
+ case MSG_SMB_FORCE_TDIS: val = "MSG_SMB_FORCE_TDIS"; break;
+ case MSG_SMB_SAM_SYNC: val = "MSG_SMB_SAM_SYNC"; break;
+ case MSG_SMB_SAM_REPL: val = "MSG_SMB_SAM_REPL"; break;
+ case MSG_SMB_UNLOCK: val = "MSG_SMB_UNLOCK"; break;
+ case MSG_SMB_BREAK_REQUEST: val = "MSG_SMB_BREAK_REQUEST"; break;
+ case MSG_SMB_BREAK_RESPONSE: val = "MSG_SMB_BREAK_RESPONSE"; break;
+ case MSG_SMB_ASYNC_LEVEL2_BREAK: val = "MSG_SMB_ASYNC_LEVEL2_BREAK"; break;
+ case MSG_SMB_OPEN_RETRY: val = "MSG_SMB_OPEN_RETRY"; break;
+ case MSG_SMB_KERNEL_BREAK: val = "MSG_SMB_KERNEL_BREAK"; break;
+ case MSG_SMB_FILE_RENAME: val = "MSG_SMB_FILE_RENAME"; break;
+ case MSG_SMB_INJECT_FAULT: val = "MSG_SMB_INJECT_FAULT"; break;
+ case MSG_SMB_BLOCKING_LOCK_CANCEL: val = "MSG_SMB_BLOCKING_LOCK_CANCEL"; break;
+ case MSG_SMB_NOTIFY: val = "MSG_SMB_NOTIFY"; break;
+ case MSG_SMB_STAT_CACHE_DELETE: val = "MSG_SMB_STAT_CACHE_DELETE"; break;
+ case MSG_PVFS_NOTIFY: val = "MSG_PVFS_NOTIFY"; break;
+ case MSG_SMB_BRL_VALIDATE: val = "MSG_SMB_BRL_VALIDATE"; break;
+ case MSG_SMB_RELEASE_IP: val = "MSG_SMB_RELEASE_IP"; break;
+ case MSG_SMB_CLOSE_FILE: val = "MSG_SMB_CLOSE_FILE"; break;
+ case MSG_WINBIND_FINISHED: val = "MSG_WINBIND_FINISHED"; break;
+ case MSG_WINBIND_FORGET_STATE: val = "MSG_WINBIND_FORGET_STATE"; break;
+ case MSG_WINBIND_ONLINE: val = "MSG_WINBIND_ONLINE"; break;
+ case MSG_WINBIND_OFFLINE: val = "MSG_WINBIND_OFFLINE"; break;
+ case MSG_WINBIND_ONLINESTATUS: val = "MSG_WINBIND_ONLINESTATUS"; break;
+ case MSG_WINBIND_TRY_TO_GO_ONLINE: val = "MSG_WINBIND_TRY_TO_GO_ONLINE"; break;
+ case MSG_WINBIND_FAILED_TO_GO_ONLINE: val = "MSG_WINBIND_FAILED_TO_GO_ONLINE"; break;
+ case MSG_WINBIND_VALIDATE_CACHE: val = "MSG_WINBIND_VALIDATE_CACHE"; break;
+ case MSG_WINBIND_DUMP_DOMAIN_LIST: val = "MSG_WINBIND_DUMP_DOMAIN_LIST"; break;
+ case MSG_DUMP_EVENT_LIST: val = "MSG_DUMP_EVENT_LIST"; break;
+ case MSG_DBWRAP_TDB2_CHANGES: val = "MSG_DBWRAP_TDB2_CHANGES"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_messaging_rec(struct ndr_push *ndr, int ndr_flags, const struct messaging_rec *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->msg_version));
+ NDR_CHECK(ndr_push_messaging_type(ndr, NDR_SCALARS, r->msg_type));
+ NDR_CHECK(ndr_push_server_id(ndr, NDR_SCALARS, &r->dest));
+ NDR_CHECK(ndr_push_server_id(ndr, NDR_SCALARS, &r->src));
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->buf));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_server_id(ndr, NDR_BUFFERS, &r->dest));
+ NDR_CHECK(ndr_push_server_id(ndr, NDR_BUFFERS, &r->src));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_messaging_rec(struct ndr_pull *ndr, int ndr_flags, struct messaging_rec *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->msg_version));
+ NDR_CHECK(ndr_pull_messaging_type(ndr, NDR_SCALARS, &r->msg_type));
+ NDR_CHECK(ndr_pull_server_id(ndr, NDR_SCALARS, &r->dest));
+ NDR_CHECK(ndr_pull_server_id(ndr, NDR_SCALARS, &r->src));
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->buf));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_server_id(ndr, NDR_BUFFERS, &r->dest));
+ NDR_CHECK(ndr_pull_server_id(ndr, NDR_BUFFERS, &r->src));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_messaging_rec(struct ndr_print *ndr, const char *name, const struct messaging_rec *r)
+{
+ ndr_print_struct(ndr, name, "messaging_rec");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "msg_version", r->msg_version);
+ ndr_print_messaging_type(ndr, "msg_type", r->msg_type);
+ ndr_print_server_id(ndr, "dest", &r->dest);
+ ndr_print_server_id(ndr, "src", &r->src);
+ ndr_print_DATA_BLOB(ndr, "buf", r->buf);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_messaging_array(struct ndr_push *ndr, int ndr_flags, const struct messaging_array *r)
+{
+ uint32_t cntr_messages_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_messages));
+ for (cntr_messages_0 = 0; cntr_messages_0 < r->num_messages; cntr_messages_0++) {
+ NDR_CHECK(ndr_push_messaging_rec(ndr, NDR_SCALARS, &r->messages[cntr_messages_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ for (cntr_messages_0 = 0; cntr_messages_0 < r->num_messages; cntr_messages_0++) {
+ NDR_CHECK(ndr_push_messaging_rec(ndr, NDR_BUFFERS, &r->messages[cntr_messages_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_messaging_array(struct ndr_pull *ndr, int ndr_flags, struct messaging_array *r)
+{
+ uint32_t cntr_messages_0;
+ TALLOC_CTX *_mem_save_messages_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_messages));
+ NDR_PULL_ALLOC_N(ndr, r->messages, r->num_messages);
+ _mem_save_messages_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->messages, 0);
+ for (cntr_messages_0 = 0; cntr_messages_0 < r->num_messages; cntr_messages_0++) {
+ NDR_CHECK(ndr_pull_messaging_rec(ndr, NDR_SCALARS, &r->messages[cntr_messages_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_messages_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_messages_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->messages, 0);
+ for (cntr_messages_0 = 0; cntr_messages_0 < r->num_messages; cntr_messages_0++) {
+ NDR_CHECK(ndr_pull_messaging_rec(ndr, NDR_BUFFERS, &r->messages[cntr_messages_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_messages_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_messaging_array(struct ndr_print *ndr, const char *name, const struct messaging_array *r)
+{
+ uint32_t cntr_messages_0;
+ ndr_print_struct(ndr, name, "messaging_array");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_messages", r->num_messages);
+ ndr->print(ndr, "%s: ARRAY(%d)", "messages", (int)r->num_messages);
+ ndr->depth++;
+ for (cntr_messages_0=0;cntr_messages_0<r->num_messages;cntr_messages_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_messages_0) != -1) {
+ ndr_print_messaging_rec(ndr, "messages", &r->messages[cntr_messages_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_dbwrap_tdb2_changes(struct ndr_push *ndr, int ndr_flags, const struct dbwrap_tdb2_changes *r)
+{
+ uint32_t cntr_keys_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, "TDB2", 4, sizeof(uint8_t), CH_DOS));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF8)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF8)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, ndr_charset_length(r->name, CH_UTF8), sizeof(uint8_t), CH_UTF8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->old_seqnum));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->new_seqnum));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_changes));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_keys));
+ for (cntr_keys_0 = 0; cntr_keys_0 < r->num_keys; cntr_keys_0++) {
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->keys[cntr_keys_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_dbwrap_tdb2_changes(struct ndr_pull *ndr, int ndr_flags, struct dbwrap_tdb2_changes *r)
+{
+ uint32_t cntr_keys_0;
+ TALLOC_CTX *_mem_save_keys_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->magic_string, 4, sizeof(uint8_t), CH_DOS));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->magic_version));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->name));
+ if (ndr_get_array_length(ndr, &r->name) > ndr_get_array_size(ndr, &r->name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->name), ndr_get_array_length(ndr, &r->name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->name), sizeof(uint8_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, ndr_get_array_length(ndr, &r->name), sizeof(uint8_t), CH_UTF8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->old_seqnum));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->new_seqnum));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_changes));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_keys));
+ NDR_PULL_ALLOC_N(ndr, r->keys, r->num_keys);
+ _mem_save_keys_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->keys, 0);
+ for (cntr_keys_0 = 0; cntr_keys_0 < r->num_keys; cntr_keys_0++) {
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->keys[cntr_keys_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_keys_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dbwrap_tdb2_changes(struct ndr_print *ndr, const char *name, const struct dbwrap_tdb2_changes *r)
+{
+ uint32_t cntr_keys_0;
+ ndr_print_struct(ndr, name, "dbwrap_tdb2_changes");
+ ndr->depth++;
+ ndr_print_string(ndr, "magic_string", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?"TDB2":r->magic_string);
+ ndr_print_uint32(ndr, "magic_version", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?1:r->magic_version);
+ ndr_print_string(ndr, "name", r->name);
+ ndr_print_uint32(ndr, "old_seqnum", r->old_seqnum);
+ ndr_print_uint32(ndr, "new_seqnum", r->new_seqnum);
+ ndr_print_uint32(ndr, "num_changes", r->num_changes);
+ ndr_print_uint32(ndr, "num_keys", r->num_keys);
+ ndr->print(ndr, "%s: ARRAY(%d)", "keys", (int)r->num_keys);
+ ndr->depth++;
+ for (cntr_keys_0=0;cntr_keys_0<r->num_keys;cntr_keys_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_keys_0) != -1) {
+ ndr_print_DATA_BLOB(ndr, "keys", r->keys[cntr_keys_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
diff --git a/source3/librpc/gen_ndr/ndr_messaging.h b/source3/librpc/gen_ndr/ndr_messaging.h
new file mode 100644
index 0000000000..9d0720232d
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_messaging.h
@@ -0,0 +1,22 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/messaging.h"
+
+#ifndef _HEADER_NDR_messaging
+#define _HEADER_NDR_messaging
+
+#define NDR_MESSAGING_CALL_COUNT (0)
+enum ndr_err_code ndr_push_messaging_type(struct ndr_push *ndr, int ndr_flags, enum messaging_type r);
+enum ndr_err_code ndr_pull_messaging_type(struct ndr_pull *ndr, int ndr_flags, enum messaging_type *r);
+void ndr_print_messaging_type(struct ndr_print *ndr, const char *name, enum messaging_type r);
+enum ndr_err_code ndr_push_messaging_rec(struct ndr_push *ndr, int ndr_flags, const struct messaging_rec *r);
+enum ndr_err_code ndr_pull_messaging_rec(struct ndr_pull *ndr, int ndr_flags, struct messaging_rec *r);
+void ndr_print_messaging_rec(struct ndr_print *ndr, const char *name, const struct messaging_rec *r);
+enum ndr_err_code ndr_push_messaging_array(struct ndr_push *ndr, int ndr_flags, const struct messaging_array *r);
+enum ndr_err_code ndr_pull_messaging_array(struct ndr_pull *ndr, int ndr_flags, struct messaging_array *r);
+void ndr_print_messaging_array(struct ndr_print *ndr, const char *name, const struct messaging_array *r);
+enum ndr_err_code ndr_push_dbwrap_tdb2_changes(struct ndr_push *ndr, int ndr_flags, const struct dbwrap_tdb2_changes *r);
+enum ndr_err_code ndr_pull_dbwrap_tdb2_changes(struct ndr_pull *ndr, int ndr_flags, struct dbwrap_tdb2_changes *r);
+void ndr_print_dbwrap_tdb2_changes(struct ndr_print *ndr, const char *name, const struct dbwrap_tdb2_changes *r);
+#endif /* _HEADER_NDR_messaging */
diff --git a/source3/librpc/gen_ndr/ndr_misc.c b/source3/librpc/gen_ndr/ndr_misc.c
new file mode 100644
index 0000000000..56105d499f
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_misc.c
@@ -0,0 +1,185 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+
+_PUBLIC_ enum ndr_err_code ndr_push_GUID(struct ndr_push *ndr, int ndr_flags, const struct GUID *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->time_low));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->time_mid));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->time_hi_and_version));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->clock_seq, 2));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->node, 6));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_GUID(struct ndr_pull *ndr, int ndr_flags, struct GUID *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->time_low));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->time_mid));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->time_hi_and_version));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->clock_seq, 2));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->node, 6));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ size_t ndr_size_GUID(const struct GUID *r, int flags)
+{
+ return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_GUID);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_ndr_syntax_id(struct ndr_push *ndr, int ndr_flags, const struct ndr_syntax_id *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->uuid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->if_version));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_ndr_syntax_id(struct ndr_pull *ndr, int ndr_flags, struct ndr_syntax_id *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->uuid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->if_version));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_ndr_syntax_id(struct ndr_print *ndr, const char *name, const struct ndr_syntax_id *r)
+{
+ ndr_print_struct(ndr, name, "ndr_syntax_id");
+ ndr->depth++;
+ ndr_print_GUID(ndr, "uuid", &r->uuid);
+ ndr_print_uint32(ndr, "if_version", r->if_version);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_policy_handle(struct ndr_push *ndr, int ndr_flags, const struct policy_handle *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->handle_type));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->uuid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_policy_handle(struct ndr_pull *ndr, int ndr_flags, struct policy_handle *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->handle_type));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->uuid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_policy_handle(struct ndr_print *ndr, const char *name, const struct policy_handle *r)
+{
+ ndr_print_struct(ndr, name, "policy_handle");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "handle_type", r->handle_type);
+ ndr_print_GUID(ndr, "uuid", &r->uuid);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_SchannelType(struct ndr_push *ndr, int ndr_flags, enum netr_SchannelType r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_SchannelType(struct ndr_pull *ndr, int ndr_flags, enum netr_SchannelType *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_SchannelType(struct ndr_print *ndr, const char *name, enum netr_SchannelType r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case SEC_CHAN_WKSTA: val = "SEC_CHAN_WKSTA"; break;
+ case SEC_CHAN_DOMAIN: val = "SEC_CHAN_DOMAIN"; break;
+ case SEC_CHAN_BDC: val = "SEC_CHAN_BDC"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_SamDatabaseID(struct ndr_push *ndr, int ndr_flags, enum netr_SamDatabaseID r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_SamDatabaseID(struct ndr_pull *ndr, int ndr_flags, enum netr_SamDatabaseID *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_SamDatabaseID(struct ndr_print *ndr, const char *name, enum netr_SamDatabaseID r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case SAM_DATABASE_DOMAIN: val = "SAM_DATABASE_DOMAIN"; break;
+ case SAM_DATABASE_BUILTIN: val = "SAM_DATABASE_BUILTIN"; break;
+ case SAM_DATABASE_PRIVS: val = "SAM_DATABASE_PRIVS"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_RejectReason(struct ndr_push *ndr, int ndr_flags, enum samr_RejectReason r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_RejectReason(struct ndr_pull *ndr, int ndr_flags, enum samr_RejectReason *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_RejectReason(struct ndr_print *ndr, const char *name, enum samr_RejectReason r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case SAMR_REJECT_OTHER: val = "SAMR_REJECT_OTHER"; break;
+ case SAMR_REJECT_TOO_SHORT: val = "SAMR_REJECT_TOO_SHORT"; break;
+ case SAMR_REJECT_IN_HISTORY: val = "SAMR_REJECT_IN_HISTORY"; break;
+ case SAMR_REJECT_COMPLEXITY: val = "SAMR_REJECT_COMPLEXITY"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
diff --git a/source3/librpc/gen_ndr/ndr_misc.h b/source3/librpc/gen_ndr/ndr_misc.h
new file mode 100644
index 0000000000..a15a781367
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_misc.h
@@ -0,0 +1,29 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/misc.h"
+
+#ifndef _HEADER_NDR_misc
+#define _HEADER_NDR_misc
+
+#define NDR_MISC_CALL_COUNT (0)
+enum ndr_err_code ndr_push_GUID(struct ndr_push *ndr, int ndr_flags, const struct GUID *r);
+enum ndr_err_code ndr_pull_GUID(struct ndr_pull *ndr, int ndr_flags, struct GUID *r);
+void ndr_print_GUID(struct ndr_print *ndr, const char *name, const struct GUID *r);
+size_t ndr_size_GUID(const struct GUID *r, int flags);
+enum ndr_err_code ndr_push_ndr_syntax_id(struct ndr_push *ndr, int ndr_flags, const struct ndr_syntax_id *r);
+enum ndr_err_code ndr_pull_ndr_syntax_id(struct ndr_pull *ndr, int ndr_flags, struct ndr_syntax_id *r);
+void ndr_print_ndr_syntax_id(struct ndr_print *ndr, const char *name, const struct ndr_syntax_id *r);
+enum ndr_err_code ndr_push_policy_handle(struct ndr_push *ndr, int ndr_flags, const struct policy_handle *r);
+enum ndr_err_code ndr_pull_policy_handle(struct ndr_pull *ndr, int ndr_flags, struct policy_handle *r);
+void ndr_print_policy_handle(struct ndr_print *ndr, const char *name, const struct policy_handle *r);
+enum ndr_err_code ndr_push_netr_SchannelType(struct ndr_push *ndr, int ndr_flags, enum netr_SchannelType r);
+enum ndr_err_code ndr_pull_netr_SchannelType(struct ndr_pull *ndr, int ndr_flags, enum netr_SchannelType *r);
+void ndr_print_netr_SchannelType(struct ndr_print *ndr, const char *name, enum netr_SchannelType r);
+enum ndr_err_code ndr_push_netr_SamDatabaseID(struct ndr_push *ndr, int ndr_flags, enum netr_SamDatabaseID r);
+enum ndr_err_code ndr_pull_netr_SamDatabaseID(struct ndr_pull *ndr, int ndr_flags, enum netr_SamDatabaseID *r);
+void ndr_print_netr_SamDatabaseID(struct ndr_print *ndr, const char *name, enum netr_SamDatabaseID r);
+enum ndr_err_code ndr_push_samr_RejectReason(struct ndr_push *ndr, int ndr_flags, enum samr_RejectReason r);
+enum ndr_err_code ndr_pull_samr_RejectReason(struct ndr_pull *ndr, int ndr_flags, enum samr_RejectReason *r);
+void ndr_print_samr_RejectReason(struct ndr_print *ndr, const char *name, enum samr_RejectReason r);
+#endif /* _HEADER_NDR_misc */
diff --git a/source3/librpc/gen_ndr/ndr_nbt.c b/source3/librpc/gen_ndr/ndr_nbt.c
new file mode 100644
index 0000000000..75667183a8
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_nbt.c
@@ -0,0 +1,4807 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_svcctl.h"
+#include "librpc/gen_ndr/ndr_samr.h"
+static enum ndr_err_code ndr_push_nbt_operation(struct ndr_push *ndr, int ndr_flags, uint16_t r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_operation(struct ndr_pull *ndr, int ndr_flags, uint16_t *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_operation(struct ndr_print *ndr, const char *name, uint16_t r)
+{
+ ndr_print_uint16(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "NBT_RCODE", NBT_RCODE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "NBT_FLAG_BROADCAST", NBT_FLAG_BROADCAST, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "NBT_FLAG_RECURSION_AVAIL", NBT_FLAG_RECURSION_AVAIL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "NBT_FLAG_RECURSION_DESIRED", NBT_FLAG_RECURSION_DESIRED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "NBT_FLAG_TRUNCATION", NBT_FLAG_TRUNCATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "NBT_FLAG_AUTHORITIVE", NBT_FLAG_AUTHORITIVE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "NBT_OPCODE", NBT_OPCODE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "NBT_FLAG_REPLY", NBT_FLAG_REPLY, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_name_type(struct ndr_push *ndr, int ndr_flags, enum nbt_name_type r)
+{
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_name_type(struct ndr_pull *ndr, int ndr_flags, enum nbt_name_type *r)
+{
+ uint8_t v;
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_name_type(struct ndr_print *ndr, const char *name, enum nbt_name_type r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case NBT_NAME_CLIENT: val = "NBT_NAME_CLIENT"; break;
+ case NBT_NAME_MS: val = "NBT_NAME_MS"; break;
+ case NBT_NAME_USER: val = "NBT_NAME_USER"; break;
+ case NBT_NAME_SERVER: val = "NBT_NAME_SERVER"; break;
+ case NBT_NAME_PDC: val = "NBT_NAME_PDC"; break;
+ case NBT_NAME_LOGON: val = "NBT_NAME_LOGON"; break;
+ case NBT_NAME_MASTER: val = "NBT_NAME_MASTER"; break;
+ case NBT_NAME_BROWSER: val = "NBT_NAME_BROWSER"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+_PUBLIC_ void ndr_print_nbt_name(struct ndr_print *ndr, const char *name, const struct nbt_name *r)
+{
+ ndr_print_struct(ndr, name, "nbt_name");
+ ndr->depth++;
+ ndr_print_string(ndr, "name", r->name);
+ ndr_print_string(ndr, "scope", r->scope);
+ ndr_print_nbt_name_type(ndr, "type", r->type);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_qclass(struct ndr_push *ndr, int ndr_flags, enum nbt_qclass r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_qclass(struct ndr_pull *ndr, int ndr_flags, enum nbt_qclass *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_qclass(struct ndr_print *ndr, const char *name, enum nbt_qclass r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case NBT_QCLASS_IP: val = "NBT_QCLASS_IP"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_nbt_qtype(struct ndr_push *ndr, int ndr_flags, enum nbt_qtype r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_qtype(struct ndr_pull *ndr, int ndr_flags, enum nbt_qtype *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_qtype(struct ndr_print *ndr, const char *name, enum nbt_qtype r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case NBT_QTYPE_ADDRESS: val = "NBT_QTYPE_ADDRESS"; break;
+ case NBT_QTYPE_NAMESERVICE: val = "NBT_QTYPE_NAMESERVICE"; break;
+ case NBT_QTYPE_NULL: val = "NBT_QTYPE_NULL"; break;
+ case NBT_QTYPE_NETBIOS: val = "NBT_QTYPE_NETBIOS"; break;
+ case NBT_QTYPE_STATUS: val = "NBT_QTYPE_STATUS"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_nbt_name_question(struct ndr_push *ndr, int ndr_flags, const struct nbt_name_question *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_nbt_name(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_push_nbt_qtype(ndr, NDR_SCALARS, r->question_type));
+ NDR_CHECK(ndr_push_nbt_qclass(ndr, NDR_SCALARS, r->question_class));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_name_question(struct ndr_pull *ndr, int ndr_flags, struct nbt_name_question *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_nbt_name(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_pull_nbt_qtype(ndr, NDR_SCALARS, &r->question_type));
+ NDR_CHECK(ndr_pull_nbt_qclass(ndr, NDR_SCALARS, &r->question_class));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_name_question(struct ndr_print *ndr, const char *name, const struct nbt_name_question *r)
+{
+ ndr_print_struct(ndr, name, "nbt_name_question");
+ ndr->depth++;
+ ndr_print_nbt_name(ndr, "name", &r->name);
+ ndr_print_nbt_qtype(ndr, "question_type", r->question_type);
+ ndr_print_nbt_qclass(ndr, "question_class", r->question_class);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nb_flags(struct ndr_push *ndr, int ndr_flags, uint16_t r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nb_flags(struct ndr_pull *ndr, int ndr_flags, uint16_t *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nb_flags(struct ndr_print *ndr, const char *name, uint16_t r)
+{
+ ndr_print_uint16(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "NBT_NM_PERMANENT", NBT_NM_PERMANENT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "NBT_NM_ACTIVE", NBT_NM_ACTIVE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "NBT_NM_CONFLICT", NBT_NM_CONFLICT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "NBT_NM_DEREGISTER", NBT_NM_DEREGISTER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "NBT_NM_OWNER_TYPE", NBT_NM_OWNER_TYPE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "NBT_NM_GROUP", NBT_NM_GROUP, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_rdata_address(struct ndr_push *ndr, int ndr_flags, const struct nbt_rdata_address *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_nb_flags(ndr, NDR_SCALARS, r->nb_flags));
+ NDR_CHECK(ndr_push_ipv4address(ndr, NDR_SCALARS, r->ipaddr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_rdata_address(struct ndr_pull *ndr, int ndr_flags, struct nbt_rdata_address *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_nb_flags(ndr, NDR_SCALARS, &r->nb_flags));
+ NDR_CHECK(ndr_pull_ipv4address(ndr, NDR_SCALARS, &r->ipaddr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_rdata_address(struct ndr_print *ndr, const char *name, const struct nbt_rdata_address *r)
+{
+ ndr_print_struct(ndr, name, "nbt_rdata_address");
+ ndr->depth++;
+ ndr_print_nb_flags(ndr, "nb_flags", r->nb_flags);
+ ndr_print_ipv4address(ndr, "ipaddr", r->ipaddr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_rdata_netbios(struct ndr_push *ndr, int ndr_flags, const struct nbt_rdata_netbios *r)
+{
+ uint32_t cntr_addresses_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->length));
+ for (cntr_addresses_0 = 0; cntr_addresses_0 < r->length / 6; cntr_addresses_0++) {
+ NDR_CHECK(ndr_push_nbt_rdata_address(ndr, NDR_SCALARS, &r->addresses[cntr_addresses_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_rdata_netbios(struct ndr_pull *ndr, int ndr_flags, struct nbt_rdata_netbios *r)
+{
+ uint32_t cntr_addresses_0;
+ TALLOC_CTX *_mem_save_addresses_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
+ NDR_PULL_ALLOC_N(ndr, r->addresses, r->length / 6);
+ _mem_save_addresses_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->addresses, 0);
+ for (cntr_addresses_0 = 0; cntr_addresses_0 < r->length / 6; cntr_addresses_0++) {
+ NDR_CHECK(ndr_pull_nbt_rdata_address(ndr, NDR_SCALARS, &r->addresses[cntr_addresses_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_addresses_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_rdata_netbios(struct ndr_print *ndr, const char *name, const struct nbt_rdata_netbios *r)
+{
+ uint32_t cntr_addresses_0;
+ ndr_print_struct(ndr, name, "nbt_rdata_netbios");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "length", r->length);
+ ndr->print(ndr, "%s: ARRAY(%d)", "addresses", (int)r->length / 6);
+ ndr->depth++;
+ for (cntr_addresses_0=0;cntr_addresses_0<r->length / 6;cntr_addresses_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_addresses_0) != -1) {
+ ndr_print_nbt_rdata_address(ndr, "addresses", &r->addresses[cntr_addresses_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_statistics(struct ndr_push *ndr, int ndr_flags, const struct nbt_statistics *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->unit_id, 6));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->jumpers));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->test_result));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->version_number));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->period_of_statistics));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->number_of_crcs));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->number_alignment_errors));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->number_of_collisions));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->number_send_aborts));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->number_good_sends));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->number_good_receives));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->number_retransmits));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->number_no_resource_conditions));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->number_free_command_blocks));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->total_number_command_blocks));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->max_total_number_command_blocks));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->number_pending_sessions));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->max_number_pending_sessions));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->max_total_sessions_possible));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->session_data_packet_size));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_statistics(struct ndr_pull *ndr, int ndr_flags, struct nbt_statistics *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->unit_id, 6));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->jumpers));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->test_result));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->version_number));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->period_of_statistics));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->number_of_crcs));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->number_alignment_errors));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->number_of_collisions));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->number_send_aborts));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->number_good_sends));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->number_good_receives));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->number_retransmits));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->number_no_resource_conditions));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->number_free_command_blocks));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->total_number_command_blocks));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->max_total_number_command_blocks));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->number_pending_sessions));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->max_number_pending_sessions));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->max_total_sessions_possible));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->session_data_packet_size));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_statistics(struct ndr_print *ndr, const char *name, const struct nbt_statistics *r)
+{
+ ndr_print_struct(ndr, name, "nbt_statistics");
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "unit_id", r->unit_id, 6);
+ ndr_print_uint8(ndr, "jumpers", r->jumpers);
+ ndr_print_uint8(ndr, "test_result", r->test_result);
+ ndr_print_uint16(ndr, "version_number", r->version_number);
+ ndr_print_uint16(ndr, "period_of_statistics", r->period_of_statistics);
+ ndr_print_uint16(ndr, "number_of_crcs", r->number_of_crcs);
+ ndr_print_uint16(ndr, "number_alignment_errors", r->number_alignment_errors);
+ ndr_print_uint16(ndr, "number_of_collisions", r->number_of_collisions);
+ ndr_print_uint16(ndr, "number_send_aborts", r->number_send_aborts);
+ ndr_print_uint32(ndr, "number_good_sends", r->number_good_sends);
+ ndr_print_uint32(ndr, "number_good_receives", r->number_good_receives);
+ ndr_print_uint16(ndr, "number_retransmits", r->number_retransmits);
+ ndr_print_uint16(ndr, "number_no_resource_conditions", r->number_no_resource_conditions);
+ ndr_print_uint16(ndr, "number_free_command_blocks", r->number_free_command_blocks);
+ ndr_print_uint16(ndr, "total_number_command_blocks", r->total_number_command_blocks);
+ ndr_print_uint16(ndr, "max_total_number_command_blocks", r->max_total_number_command_blocks);
+ ndr_print_uint16(ndr, "number_pending_sessions", r->number_pending_sessions);
+ ndr_print_uint16(ndr, "max_number_pending_sessions", r->max_number_pending_sessions);
+ ndr_print_uint16(ndr, "max_total_sessions_possible", r->max_total_sessions_possible);
+ ndr_print_uint16(ndr, "session_data_packet_size", r->session_data_packet_size);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_status_name(struct ndr_push *ndr, int ndr_flags, const struct nbt_status_name *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, 15, sizeof(uint8_t), CH_DOS));
+ NDR_CHECK(ndr_push_nbt_name_type(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_nb_flags(ndr, NDR_SCALARS, r->nb_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_status_name(struct ndr_pull *ndr, int ndr_flags, struct nbt_status_name *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, 15, sizeof(uint8_t), CH_DOS));
+ NDR_CHECK(ndr_pull_nbt_name_type(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_nb_flags(ndr, NDR_SCALARS, &r->nb_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_status_name(struct ndr_print *ndr, const char *name, const struct nbt_status_name *r)
+{
+ ndr_print_struct(ndr, name, "nbt_status_name");
+ ndr->depth++;
+ ndr_print_string(ndr, "name", r->name);
+ ndr_print_nbt_name_type(ndr, "type", r->type);
+ ndr_print_nb_flags(ndr, "nb_flags", r->nb_flags);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_rdata_status(struct ndr_push *ndr, int ndr_flags, const struct nbt_rdata_status *r)
+{
+ uint32_t cntr_names_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->num_names * 18 + 47));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->num_names));
+ for (cntr_names_0 = 0; cntr_names_0 < r->num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_push_nbt_status_name(ndr, NDR_SCALARS, &r->names[cntr_names_0]));
+ }
+ NDR_CHECK(ndr_push_nbt_statistics(ndr, NDR_SCALARS, &r->statistics));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_rdata_status(struct ndr_pull *ndr, int ndr_flags, struct nbt_rdata_status *r)
+{
+ uint32_t cntr_names_0;
+ TALLOC_CTX *_mem_save_names_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->num_names));
+ NDR_PULL_ALLOC_N(ndr, r->names, r->num_names);
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->names, 0);
+ for (cntr_names_0 = 0; cntr_names_0 < r->num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_pull_nbt_status_name(ndr, NDR_SCALARS, &r->names[cntr_names_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, 0);
+ NDR_CHECK(ndr_pull_nbt_statistics(ndr, NDR_SCALARS, &r->statistics));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_rdata_status(struct ndr_print *ndr, const char *name, const struct nbt_rdata_status *r)
+{
+ uint32_t cntr_names_0;
+ ndr_print_struct(ndr, name, "nbt_rdata_status");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "length", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?r->num_names * 18 + 47:r->length);
+ ndr_print_uint8(ndr, "num_names", r->num_names);
+ ndr->print(ndr, "%s: ARRAY(%d)", "names", (int)r->num_names);
+ ndr->depth++;
+ for (cntr_names_0=0;cntr_names_0<r->num_names;cntr_names_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_names_0) != -1) {
+ ndr_print_nbt_status_name(ndr, "names", &r->names[cntr_names_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr_print_nbt_statistics(ndr, "statistics", &r->statistics);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_rdata_data(struct ndr_push *ndr, int ndr_flags, const struct nbt_rdata_data *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data, r->length));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_rdata_data(struct ndr_pull *ndr, int ndr_flags, struct nbt_rdata_data *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
+ NDR_PULL_ALLOC_N(ndr, r->data, r->length);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data, r->length));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_rdata_data(struct ndr_print *ndr, const char *name, const struct nbt_rdata_data *r)
+{
+ ndr_print_struct(ndr, name, "nbt_rdata_data");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "length", r->length);
+ ndr_print_array_uint8(ndr, "data", r->data, r->length);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_rdata(struct ndr_push *ndr, int ndr_flags, const union nbt_rdata *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case NBT_QTYPE_NETBIOS: {
+ NDR_CHECK(ndr_push_nbt_rdata_netbios(ndr, NDR_SCALARS, &r->netbios));
+ break; }
+
+ case NBT_QTYPE_STATUS: {
+ NDR_CHECK(ndr_push_nbt_rdata_status(ndr, NDR_SCALARS, &r->status));
+ break; }
+
+ default: {
+ NDR_CHECK(ndr_push_nbt_rdata_data(ndr, NDR_SCALARS, &r->data));
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case NBT_QTYPE_NETBIOS:
+ break;
+
+ case NBT_QTYPE_STATUS:
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_rdata(struct ndr_pull *ndr, int ndr_flags, union nbt_rdata *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case NBT_QTYPE_NETBIOS: {
+ NDR_CHECK(ndr_pull_nbt_rdata_netbios(ndr, NDR_SCALARS, &r->netbios));
+ break; }
+
+ case NBT_QTYPE_STATUS: {
+ NDR_CHECK(ndr_pull_nbt_rdata_status(ndr, NDR_SCALARS, &r->status));
+ break; }
+
+ default: {
+ NDR_CHECK(ndr_pull_nbt_rdata_data(ndr, NDR_SCALARS, &r->data));
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case NBT_QTYPE_NETBIOS:
+ break;
+
+ case NBT_QTYPE_STATUS:
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_rdata(struct ndr_print *ndr, const char *name, const union nbt_rdata *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "nbt_rdata");
+ switch (level) {
+ case NBT_QTYPE_NETBIOS:
+ ndr_print_nbt_rdata_netbios(ndr, "netbios", &r->netbios);
+ break;
+
+ case NBT_QTYPE_STATUS:
+ ndr_print_nbt_rdata_status(ndr, "status", &r->status);
+ break;
+
+ default:
+ ndr_print_nbt_rdata_data(ndr, "data", &r->data);
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_nbt_res_rec(struct ndr_push *ndr, int ndr_flags, const struct nbt_res_rec *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_nbt_name(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_push_nbt_qtype(ndr, NDR_SCALARS, r->rr_type));
+ NDR_CHECK(ndr_push_nbt_qclass(ndr, NDR_SCALARS, r->rr_class));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ttl));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->rdata, ((((r->rr_type) == NBT_QTYPE_NETBIOS) && talloc_check_name(ndr, "struct ndr_push") && ((r->rdata).data.length == 2))?0:r->rr_type)));
+ NDR_CHECK(ndr_push_nbt_rdata(ndr, NDR_SCALARS, &r->rdata));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_res_rec(struct ndr_pull *ndr, int ndr_flags, struct nbt_res_rec *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_nbt_name(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_pull_nbt_qtype(ndr, NDR_SCALARS, &r->rr_type));
+ NDR_CHECK(ndr_pull_nbt_qclass(ndr, NDR_SCALARS, &r->rr_class));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->ttl));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->rdata, ((((r->rr_type) == NBT_QTYPE_NETBIOS) && talloc_check_name(ndr, "struct ndr_push") && ((r->rdata).data.length == 2))?0:r->rr_type)));
+ NDR_CHECK(ndr_pull_nbt_rdata(ndr, NDR_SCALARS, &r->rdata));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_res_rec(struct ndr_print *ndr, const char *name, const struct nbt_res_rec *r)
+{
+ ndr_print_struct(ndr, name, "nbt_res_rec");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_nbt_name(ndr, "name", &r->name);
+ ndr_print_nbt_qtype(ndr, "rr_type", r->rr_type);
+ ndr_print_nbt_qclass(ndr, "rr_class", r->rr_class);
+ ndr_print_uint32(ndr, "ttl", r->ttl);
+ ndr_print_set_switch_value(ndr, &r->rdata, ((((r->rr_type) == NBT_QTYPE_NETBIOS) && talloc_check_name(ndr, "struct ndr_push") && ((r->rdata).data.length == 2))?0:r->rr_type));
+ ndr_print_nbt_rdata(ndr, "rdata", &r->rdata);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_name_packet(struct ndr_push *ndr, int ndr_flags, const struct nbt_name_packet *r)
+{
+ uint32_t cntr_questions_0;
+ uint32_t cntr_answers_0;
+ uint32_t cntr_nsrecs_0;
+ uint32_t cntr_additional_0;
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_BIGENDIAN|LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->name_trn_id));
+ NDR_CHECK(ndr_push_nbt_operation(ndr, NDR_SCALARS, r->operation));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->qdcount));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->ancount));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->nscount));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->arcount));
+ for (cntr_questions_0 = 0; cntr_questions_0 < r->qdcount; cntr_questions_0++) {
+ NDR_CHECK(ndr_push_nbt_name_question(ndr, NDR_SCALARS, &r->questions[cntr_questions_0]));
+ }
+ for (cntr_answers_0 = 0; cntr_answers_0 < r->ancount; cntr_answers_0++) {
+ NDR_CHECK(ndr_push_nbt_res_rec(ndr, NDR_SCALARS, &r->answers[cntr_answers_0]));
+ }
+ for (cntr_nsrecs_0 = 0; cntr_nsrecs_0 < r->nscount; cntr_nsrecs_0++) {
+ NDR_CHECK(ndr_push_nbt_res_rec(ndr, NDR_SCALARS, &r->nsrecs[cntr_nsrecs_0]));
+ }
+ for (cntr_additional_0 = 0; cntr_additional_0 < r->arcount; cntr_additional_0++) {
+ NDR_CHECK(ndr_push_nbt_res_rec(ndr, NDR_SCALARS, &r->additional[cntr_additional_0]));
+ }
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->padding));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_name_packet(struct ndr_pull *ndr, int ndr_flags, struct nbt_name_packet *r)
+{
+ uint32_t cntr_questions_0;
+ TALLOC_CTX *_mem_save_questions_0;
+ uint32_t cntr_answers_0;
+ TALLOC_CTX *_mem_save_answers_0;
+ uint32_t cntr_nsrecs_0;
+ TALLOC_CTX *_mem_save_nsrecs_0;
+ uint32_t cntr_additional_0;
+ TALLOC_CTX *_mem_save_additional_0;
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_BIGENDIAN|LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->name_trn_id));
+ NDR_CHECK(ndr_pull_nbt_operation(ndr, NDR_SCALARS, &r->operation));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->qdcount));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->ancount));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->nscount));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->arcount));
+ NDR_PULL_ALLOC_N(ndr, r->questions, r->qdcount);
+ _mem_save_questions_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->questions, 0);
+ for (cntr_questions_0 = 0; cntr_questions_0 < r->qdcount; cntr_questions_0++) {
+ NDR_CHECK(ndr_pull_nbt_name_question(ndr, NDR_SCALARS, &r->questions[cntr_questions_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_questions_0, 0);
+ NDR_PULL_ALLOC_N(ndr, r->answers, r->ancount);
+ _mem_save_answers_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->answers, 0);
+ for (cntr_answers_0 = 0; cntr_answers_0 < r->ancount; cntr_answers_0++) {
+ NDR_CHECK(ndr_pull_nbt_res_rec(ndr, NDR_SCALARS, &r->answers[cntr_answers_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_answers_0, 0);
+ NDR_PULL_ALLOC_N(ndr, r->nsrecs, r->nscount);
+ _mem_save_nsrecs_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->nsrecs, 0);
+ for (cntr_nsrecs_0 = 0; cntr_nsrecs_0 < r->nscount; cntr_nsrecs_0++) {
+ NDR_CHECK(ndr_pull_nbt_res_rec(ndr, NDR_SCALARS, &r->nsrecs[cntr_nsrecs_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_nsrecs_0, 0);
+ NDR_PULL_ALLOC_N(ndr, r->additional, r->arcount);
+ _mem_save_additional_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->additional, 0);
+ for (cntr_additional_0 = 0; cntr_additional_0 < r->arcount; cntr_additional_0++) {
+ NDR_CHECK(ndr_pull_nbt_res_rec(ndr, NDR_SCALARS, &r->additional[cntr_additional_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_additional_0, 0);
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->padding));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_name_packet(struct ndr_print *ndr, const char *name, const struct nbt_name_packet *r)
+{
+ uint32_t cntr_questions_0;
+ uint32_t cntr_answers_0;
+ uint32_t cntr_nsrecs_0;
+ uint32_t cntr_additional_0;
+ ndr_print_struct(ndr, name, "nbt_name_packet");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_BIGENDIAN|LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_uint16(ndr, "name_trn_id", r->name_trn_id);
+ ndr_print_nbt_operation(ndr, "operation", r->operation);
+ ndr_print_uint16(ndr, "qdcount", r->qdcount);
+ ndr_print_uint16(ndr, "ancount", r->ancount);
+ ndr_print_uint16(ndr, "nscount", r->nscount);
+ ndr_print_uint16(ndr, "arcount", r->arcount);
+ ndr->print(ndr, "%s: ARRAY(%d)", "questions", (int)r->qdcount);
+ ndr->depth++;
+ for (cntr_questions_0=0;cntr_questions_0<r->qdcount;cntr_questions_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_questions_0) != -1) {
+ ndr_print_nbt_name_question(ndr, "questions", &r->questions[cntr_questions_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->print(ndr, "%s: ARRAY(%d)", "answers", (int)r->ancount);
+ ndr->depth++;
+ for (cntr_answers_0=0;cntr_answers_0<r->ancount;cntr_answers_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_answers_0) != -1) {
+ ndr_print_nbt_res_rec(ndr, "answers", &r->answers[cntr_answers_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->print(ndr, "%s: ARRAY(%d)", "nsrecs", (int)r->nscount);
+ ndr->depth++;
+ for (cntr_nsrecs_0=0;cntr_nsrecs_0<r->nscount;cntr_nsrecs_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_nsrecs_0) != -1) {
+ ndr_print_nbt_res_rec(ndr, "nsrecs", &r->nsrecs[cntr_nsrecs_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->print(ndr, "%s: ARRAY(%d)", "additional", (int)r->arcount);
+ ndr->depth++;
+ for (cntr_additional_0=0;cntr_additional_0<r->arcount;cntr_additional_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_additional_0) != -1) {
+ ndr_print_nbt_res_rec(ndr, "additional", &r->additional[cntr_additional_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr_print_DATA_BLOB(ndr, "padding", r->padding);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_dgram_msg_type(struct ndr_push *ndr, int ndr_flags, enum dgram_msg_type r)
+{
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dgram_msg_type(struct ndr_pull *ndr, int ndr_flags, enum dgram_msg_type *r)
+{
+ uint8_t v;
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dgram_msg_type(struct ndr_print *ndr, const char *name, enum dgram_msg_type r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DGRAM_DIRECT_UNIQUE: val = "DGRAM_DIRECT_UNIQUE"; break;
+ case DGRAM_DIRECT_GROUP: val = "DGRAM_DIRECT_GROUP"; break;
+ case DGRAM_BCAST: val = "DGRAM_BCAST"; break;
+ case DGRAM_ERROR: val = "DGRAM_ERROR"; break;
+ case DGRAM_QUERY: val = "DGRAM_QUERY"; break;
+ case DGRAM_QUERY_POSITIVE: val = "DGRAM_QUERY_POSITIVE"; break;
+ case DGRAM_QUERY_NEGATIVE: val = "DGRAM_QUERY_NEGATIVE"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_dgram_flags(struct ndr_push *ndr, int ndr_flags, uint8_t r)
+{
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dgram_flags(struct ndr_pull *ndr, int ndr_flags, uint8_t *r)
+{
+ uint8_t v;
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dgram_flags(struct ndr_print *ndr, const char *name, uint8_t r)
+{
+ ndr_print_uint8(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint8_t), "DGRAM_FLAG_MORE", DGRAM_FLAG_MORE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint8_t), "DGRAM_FLAG_FIRST", DGRAM_FLAG_FIRST, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint8_t), "DGRAM_FLAG_NODE_TYPE", DGRAM_FLAG_NODE_TYPE, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_smb_command(struct ndr_push *ndr, int ndr_flags, enum smb_command r)
+{
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_smb_command(struct ndr_pull *ndr, int ndr_flags, enum smb_command *r)
+{
+ uint8_t v;
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_smb_command(struct ndr_print *ndr, const char *name, enum smb_command r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case SMB_TRANSACTION: val = "SMB_TRANSACTION"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_smb_trans_body(struct ndr_push *ndr, int ndr_flags, const struct smb_trans_body *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 17));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->total_param_count));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->total_data_count));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->max_param_count));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->max_data_count));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->max_setup_count));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->pad));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->trans_flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->timeout));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->reserved));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->param_count));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->param_offset));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->data_count));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->data_offset));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 3));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->pad2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->opcode));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->priority));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->_class));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, strlen(r->mailslot_name) + 1 + r->data.length));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->mailslot_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->data));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_smb_trans_body(struct ndr_pull *ndr, int ndr_flags, struct smb_trans_body *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->wct));
+ if (r->wct < 17 || r->wct > 17) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->total_param_count));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->total_data_count));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->max_param_count));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->max_data_count));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->max_setup_count));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->pad));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->trans_flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->timeout));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->reserved));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->param_count));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->param_offset));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->data_count));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->data_offset));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->setup_count));
+ if (r->setup_count < 3 || r->setup_count > 3) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->pad2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->opcode));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->priority));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->_class));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->byte_count));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->mailslot_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->data));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_smb_trans_body(struct ndr_print *ndr, const char *name, const struct smb_trans_body *r)
+{
+ ndr_print_struct(ndr, name, "smb_trans_body");
+ ndr->depth++;
+ ndr_print_uint8(ndr, "wct", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?17:r->wct);
+ ndr_print_uint16(ndr, "total_param_count", r->total_param_count);
+ ndr_print_uint16(ndr, "total_data_count", r->total_data_count);
+ ndr_print_uint16(ndr, "max_param_count", r->max_param_count);
+ ndr_print_uint16(ndr, "max_data_count", r->max_data_count);
+ ndr_print_uint8(ndr, "max_setup_count", r->max_setup_count);
+ ndr_print_uint8(ndr, "pad", r->pad);
+ ndr_print_uint16(ndr, "trans_flags", r->trans_flags);
+ ndr_print_uint32(ndr, "timeout", r->timeout);
+ ndr_print_uint16(ndr, "reserved", r->reserved);
+ ndr_print_uint16(ndr, "param_count", r->param_count);
+ ndr_print_uint16(ndr, "param_offset", r->param_offset);
+ ndr_print_uint16(ndr, "data_count", r->data_count);
+ ndr_print_uint16(ndr, "data_offset", r->data_offset);
+ ndr_print_uint8(ndr, "setup_count", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?3:r->setup_count);
+ ndr_print_uint8(ndr, "pad2", r->pad2);
+ ndr_print_uint16(ndr, "opcode", r->opcode);
+ ndr_print_uint16(ndr, "priority", r->priority);
+ ndr_print_uint16(ndr, "_class", r->_class);
+ ndr_print_uint16(ndr, "byte_count", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen(r->mailslot_name) + 1 + r->data.length:r->byte_count);
+ ndr_print_string(ndr, "mailslot_name", r->mailslot_name);
+ ndr_print_DATA_BLOB(ndr, "data", r->data);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_smb_body(struct ndr_push *ndr, int ndr_flags, const union smb_body *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case SMB_TRANSACTION: {
+ NDR_CHECK(ndr_push_smb_trans_body(ndr, NDR_SCALARS, &r->trans));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case SMB_TRANSACTION:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_smb_body(struct ndr_pull *ndr, int ndr_flags, union smb_body *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case SMB_TRANSACTION: {
+ NDR_CHECK(ndr_pull_smb_trans_body(ndr, NDR_SCALARS, &r->trans));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case SMB_TRANSACTION:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_smb_body(struct ndr_print *ndr, const char *name, const union smb_body *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "smb_body");
+ switch (level) {
+ case SMB_TRANSACTION:
+ ndr_print_smb_trans_body(ndr, "trans", &r->trans);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_dgram_smb_packet(struct ndr_push *ndr, int ndr_flags, const struct dgram_smb_packet *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_smb_command(ndr, NDR_SCALARS, r->smb_command));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->err_class));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->pad));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->err_code));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->flags2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->pid_high));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->signature, 8));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->reserved));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->tid));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->pid));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->vuid));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->mid));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->body, r->smb_command));
+ NDR_CHECK(ndr_push_smb_body(ndr, NDR_SCALARS, &r->body));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_dgram_smb_packet(struct ndr_pull *ndr, int ndr_flags, struct dgram_smb_packet *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_smb_command(ndr, NDR_SCALARS, &r->smb_command));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->err_class));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->pad));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->err_code));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->flags2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->pid_high));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->signature, 8));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->reserved));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->tid));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->pid));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->vuid));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->mid));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->body, r->smb_command));
+ NDR_CHECK(ndr_pull_smb_body(ndr, NDR_SCALARS, &r->body));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dgram_smb_packet(struct ndr_print *ndr, const char *name, const struct dgram_smb_packet *r)
+{
+ ndr_print_struct(ndr, name, "dgram_smb_packet");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_smb_command(ndr, "smb_command", r->smb_command);
+ ndr_print_uint8(ndr, "err_class", r->err_class);
+ ndr_print_uint8(ndr, "pad", r->pad);
+ ndr_print_uint16(ndr, "err_code", r->err_code);
+ ndr_print_uint8(ndr, "flags", r->flags);
+ ndr_print_uint16(ndr, "flags2", r->flags2);
+ ndr_print_uint16(ndr, "pid_high", r->pid_high);
+ ndr_print_array_uint8(ndr, "signature", r->signature, 8);
+ ndr_print_uint16(ndr, "reserved", r->reserved);
+ ndr_print_uint16(ndr, "tid", r->tid);
+ ndr_print_uint16(ndr, "pid", r->pid);
+ ndr_print_uint16(ndr, "vuid", r->vuid);
+ ndr_print_uint16(ndr, "mid", r->mid);
+ ndr_print_set_switch_value(ndr, &r->body, r->smb_command);
+ ndr_print_smb_body(ndr, "body", &r->body);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_dgram_message_body(struct ndr_push *ndr, int ndr_flags, const union dgram_message_body *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case DGRAM_SMB: {
+ NDR_CHECK(ndr_push_dgram_smb_packet(ndr, NDR_SCALARS, &r->smb));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case DGRAM_SMB:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dgram_message_body(struct ndr_pull *ndr, int ndr_flags, union dgram_message_body *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case DGRAM_SMB: {
+ NDR_CHECK(ndr_pull_dgram_smb_packet(ndr, NDR_SCALARS, &r->smb));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case DGRAM_SMB:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dgram_message_body(struct ndr_print *ndr, const char *name, const union dgram_message_body *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "dgram_message_body");
+ switch (level) {
+ case DGRAM_SMB:
+ ndr_print_dgram_smb_packet(ndr, "smb", &r->smb);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_dgram_message(struct ndr_push *ndr, int ndr_flags, const struct dgram_message *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->offset));
+ NDR_CHECK(ndr_push_nbt_name(ndr, NDR_SCALARS, &r->source_name));
+ NDR_CHECK(ndr_push_nbt_name(ndr, NDR_SCALARS, &r->dest_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->dgram_body_type));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->body, r->dgram_body_type));
+ NDR_CHECK(ndr_push_dgram_message_body(ndr, NDR_SCALARS, &r->body));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dgram_message(struct ndr_pull *ndr, int ndr_flags, struct dgram_message *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->offset));
+ NDR_CHECK(ndr_pull_nbt_name(ndr, NDR_SCALARS, &r->source_name));
+ NDR_CHECK(ndr_pull_nbt_name(ndr, NDR_SCALARS, &r->dest_name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->dgram_body_type));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->body, r->dgram_body_type));
+ NDR_CHECK(ndr_pull_dgram_message_body(ndr, NDR_SCALARS, &r->body));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dgram_message(struct ndr_print *ndr, const char *name, const struct dgram_message *r)
+{
+ ndr_print_struct(ndr, name, "dgram_message");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "length", r->length);
+ ndr_print_uint16(ndr, "offset", r->offset);
+ ndr_print_nbt_name(ndr, "source_name", &r->source_name);
+ ndr_print_nbt_name(ndr, "dest_name", &r->dest_name);
+ ndr_print_uint32(ndr, "dgram_body_type", r->dgram_body_type);
+ ndr_print_set_switch_value(ndr, &r->body, r->dgram_body_type);
+ ndr_print_dgram_message_body(ndr, "body", &r->body);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_dgram_err_code(struct ndr_push *ndr, int ndr_flags, enum dgram_err_code r)
+{
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dgram_err_code(struct ndr_pull *ndr, int ndr_flags, enum dgram_err_code *r)
+{
+ uint8_t v;
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dgram_err_code(struct ndr_print *ndr, const char *name, enum dgram_err_code r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DGRAM_ERROR_NAME_NOT_PRESENT: val = "DGRAM_ERROR_NAME_NOT_PRESENT"; break;
+ case DGRAM_ERROR_INVALID_SOURCE: val = "DGRAM_ERROR_INVALID_SOURCE"; break;
+ case DGRAM_ERROR_INVALID_DEST: val = "DGRAM_ERROR_INVALID_DEST"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_dgram_data(struct ndr_push *ndr, int ndr_flags, const union dgram_data *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case DGRAM_DIRECT_UNIQUE: {
+ NDR_CHECK(ndr_push_dgram_message(ndr, NDR_SCALARS, &r->msg));
+ break; }
+
+ case DGRAM_DIRECT_GROUP: {
+ NDR_CHECK(ndr_push_dgram_message(ndr, NDR_SCALARS, &r->msg));
+ break; }
+
+ case DGRAM_BCAST: {
+ NDR_CHECK(ndr_push_dgram_message(ndr, NDR_SCALARS, &r->msg));
+ break; }
+
+ case DGRAM_ERROR: {
+ NDR_CHECK(ndr_push_dgram_err_code(ndr, NDR_SCALARS, r->error));
+ break; }
+
+ case DGRAM_QUERY: {
+ NDR_CHECK(ndr_push_nbt_name(ndr, NDR_SCALARS, &r->dest_name));
+ break; }
+
+ case DGRAM_QUERY_POSITIVE: {
+ NDR_CHECK(ndr_push_nbt_name(ndr, NDR_SCALARS, &r->dest_name));
+ break; }
+
+ case DGRAM_QUERY_NEGATIVE: {
+ NDR_CHECK(ndr_push_nbt_name(ndr, NDR_SCALARS, &r->dest_name));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case DGRAM_DIRECT_UNIQUE:
+ break;
+
+ case DGRAM_DIRECT_GROUP:
+ break;
+
+ case DGRAM_BCAST:
+ break;
+
+ case DGRAM_ERROR:
+ break;
+
+ case DGRAM_QUERY:
+ break;
+
+ case DGRAM_QUERY_POSITIVE:
+ break;
+
+ case DGRAM_QUERY_NEGATIVE:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_dgram_data(struct ndr_pull *ndr, int ndr_flags, union dgram_data *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case DGRAM_DIRECT_UNIQUE: {
+ NDR_CHECK(ndr_pull_dgram_message(ndr, NDR_SCALARS, &r->msg));
+ break; }
+
+ case DGRAM_DIRECT_GROUP: {
+ NDR_CHECK(ndr_pull_dgram_message(ndr, NDR_SCALARS, &r->msg));
+ break; }
+
+ case DGRAM_BCAST: {
+ NDR_CHECK(ndr_pull_dgram_message(ndr, NDR_SCALARS, &r->msg));
+ break; }
+
+ case DGRAM_ERROR: {
+ NDR_CHECK(ndr_pull_dgram_err_code(ndr, NDR_SCALARS, &r->error));
+ break; }
+
+ case DGRAM_QUERY: {
+ NDR_CHECK(ndr_pull_nbt_name(ndr, NDR_SCALARS, &r->dest_name));
+ break; }
+
+ case DGRAM_QUERY_POSITIVE: {
+ NDR_CHECK(ndr_pull_nbt_name(ndr, NDR_SCALARS, &r->dest_name));
+ break; }
+
+ case DGRAM_QUERY_NEGATIVE: {
+ NDR_CHECK(ndr_pull_nbt_name(ndr, NDR_SCALARS, &r->dest_name));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case DGRAM_DIRECT_UNIQUE:
+ break;
+
+ case DGRAM_DIRECT_GROUP:
+ break;
+
+ case DGRAM_BCAST:
+ break;
+
+ case DGRAM_ERROR:
+ break;
+
+ case DGRAM_QUERY:
+ break;
+
+ case DGRAM_QUERY_POSITIVE:
+ break;
+
+ case DGRAM_QUERY_NEGATIVE:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_dgram_data(struct ndr_print *ndr, const char *name, const union dgram_data *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "dgram_data");
+ switch (level) {
+ case DGRAM_DIRECT_UNIQUE:
+ ndr_print_dgram_message(ndr, "msg", &r->msg);
+ break;
+
+ case DGRAM_DIRECT_GROUP:
+ ndr_print_dgram_message(ndr, "msg", &r->msg);
+ break;
+
+ case DGRAM_BCAST:
+ ndr_print_dgram_message(ndr, "msg", &r->msg);
+ break;
+
+ case DGRAM_ERROR:
+ ndr_print_dgram_err_code(ndr, "error", r->error);
+ break;
+
+ case DGRAM_QUERY:
+ ndr_print_nbt_name(ndr, "dest_name", &r->dest_name);
+ break;
+
+ case DGRAM_QUERY_POSITIVE:
+ ndr_print_nbt_name(ndr, "dest_name", &r->dest_name);
+ break;
+
+ case DGRAM_QUERY_NEGATIVE:
+ ndr_print_nbt_name(ndr, "dest_name", &r->dest_name);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_dgram_packet(struct ndr_push *ndr, int ndr_flags, const struct nbt_dgram_packet *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_BIGENDIAN|LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_dgram_msg_type(ndr, NDR_SCALARS, r->msg_type));
+ NDR_CHECK(ndr_push_dgram_flags(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->dgram_id));
+ NDR_CHECK(ndr_push_ipv4address(ndr, NDR_SCALARS, r->src_addr));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->src_port));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->data, r->msg_type));
+ NDR_CHECK(ndr_push_dgram_data(ndr, NDR_SCALARS, &r->data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_dgram_packet(struct ndr_pull *ndr, int ndr_flags, struct nbt_dgram_packet *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_BIGENDIAN|LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_dgram_msg_type(ndr, NDR_SCALARS, &r->msg_type));
+ NDR_CHECK(ndr_pull_dgram_flags(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->dgram_id));
+ NDR_CHECK(ndr_pull_ipv4address(ndr, NDR_SCALARS, &r->src_addr));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->src_port));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->data, r->msg_type));
+ NDR_CHECK(ndr_pull_dgram_data(ndr, NDR_SCALARS, &r->data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_dgram_packet(struct ndr_print *ndr, const char *name, const struct nbt_dgram_packet *r)
+{
+ ndr_print_struct(ndr, name, "nbt_dgram_packet");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_BIGENDIAN|LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_dgram_msg_type(ndr, "msg_type", r->msg_type);
+ ndr_print_dgram_flags(ndr, "flags", r->flags);
+ ndr_print_uint16(ndr, "dgram_id", r->dgram_id);
+ ndr_print_ipv4address(ndr, "src_addr", r->src_addr);
+ ndr_print_uint16(ndr, "src_port", r->src_port);
+ ndr_print_set_switch_value(ndr, &r->data, r->msg_type);
+ ndr_print_dgram_data(ndr, "data", &r->data);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_nbt_netlogon_command(struct ndr_push *ndr, int ndr_flags, enum nbt_netlogon_command r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_netlogon_command(struct ndr_pull *ndr, int ndr_flags, enum nbt_netlogon_command *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_netlogon_command(struct ndr_print *ndr, const char *name, enum nbt_netlogon_command r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case NETLOGON_QUERY_FOR_PDC: val = "NETLOGON_QUERY_FOR_PDC"; break;
+ case NETLOGON_ANNOUNCE_UAS: val = "NETLOGON_ANNOUNCE_UAS"; break;
+ case NETLOGON_RESPONSE_FROM_PDC: val = "NETLOGON_RESPONSE_FROM_PDC"; break;
+ case NETLOGON_QUERY_FOR_PDC2: val = "NETLOGON_QUERY_FOR_PDC2"; break;
+ case NETLOGON_RESPONSE_FROM_PDC2: val = "NETLOGON_RESPONSE_FROM_PDC2"; break;
+ case NETLOGON_RESPONSE_FROM_PDC_USER: val = "NETLOGON_RESPONSE_FROM_PDC_USER"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_nbt_netlogon_version(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ {
+ uint32_t _flags_save_BITMAP = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ ndr->flags = _flags_save_BITMAP;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_netlogon_version(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ {
+ uint32_t _flags_save_BITMAP = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ ndr->flags = _flags_save_BITMAP;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_netlogon_version(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ {
+ uint32_t _flags_save_BITMAP = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_VERSION_1", NETLOGON_VERSION_1, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_VERSION_5", NETLOGON_VERSION_5, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_VERSION_5EX", NETLOGON_VERSION_5EX, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_VERSION_5EX_WITH_IP", NETLOGON_VERSION_5EX_WITH_IP, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_VERSION_WITH_CLOSEST_SITE", NETLOGON_VERSION_WITH_CLOSEST_SITE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_VERSION_AVOID_NT4_EMUL", NETLOGON_VERSION_AVOID_NT4_EMUL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_VERSION_PDC", NETLOGON_VERSION_PDC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_VERSION_IP", NETLOGON_VERSION_IP, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_VERSION_LOCAL", NETLOGON_VERSION_LOCAL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_VERSION_GC", NETLOGON_VERSION_GC, r);
+ ndr->depth--;
+ ndr->flags = _flags_save_BITMAP;
+ }
+}
+
+static enum ndr_err_code ndr_push_nbt_netlogon_query_for_pdc(struct ndr_push *ndr, int ndr_flags, const struct nbt_netlogon_query_for_pdc *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->computer_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->mailslot_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN2);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->unicode_name));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_push_nbt_netlogon_version(ndr, NDR_SCALARS, r->nt_version));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_netlogon_query_for_pdc(struct ndr_pull *ndr, int ndr_flags, struct nbt_netlogon_query_for_pdc *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->computer_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->mailslot_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN2);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->unicode_name));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_pull_nbt_netlogon_version(ndr, NDR_SCALARS, &r->nt_version));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_netlogon_query_for_pdc(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_query_for_pdc *r)
+{
+ ndr_print_struct(ndr, name, "nbt_netlogon_query_for_pdc");
+ ndr->depth++;
+ ndr_print_string(ndr, "computer_name", r->computer_name);
+ ndr_print_string(ndr, "mailslot_name", r->mailslot_name);
+ ndr_print_DATA_BLOB(ndr, "_pad", r->_pad);
+ ndr_print_string(ndr, "unicode_name", r->unicode_name);
+ ndr_print_nbt_netlogon_version(ndr, "nt_version", r->nt_version);
+ ndr_print_uint16(ndr, "lmnt_token", r->lmnt_token);
+ ndr_print_uint16(ndr, "lm20_token", r->lm20_token);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_netlogon_query_for_pdc2(struct ndr_push *ndr, int ndr_flags, const struct nbt_netlogon_query_for_pdc2 *r)
+{
+ uint32_t cntr_unknown_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->request_count));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->computer_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->user_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->mailslot_name));
+ ndr->flags = _flags_save_string;
+ }
+ for (cntr_unknown_0 = 0; cntr_unknown_0 < 2; cntr_unknown_0++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown[cntr_unknown_0]));
+ }
+ NDR_CHECK(ndr_push_nbt_netlogon_version(ndr, NDR_SCALARS, r->nt_version));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_netlogon_query_for_pdc2(struct ndr_pull *ndr, int ndr_flags, struct nbt_netlogon_query_for_pdc2 *r)
+{
+ uint32_t cntr_unknown_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->request_count));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->computer_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->user_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->mailslot_name));
+ ndr->flags = _flags_save_string;
+ }
+ for (cntr_unknown_0 = 0; cntr_unknown_0 < 2; cntr_unknown_0++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown[cntr_unknown_0]));
+ }
+ NDR_CHECK(ndr_pull_nbt_netlogon_version(ndr, NDR_SCALARS, &r->nt_version));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_netlogon_query_for_pdc2(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_query_for_pdc2 *r)
+{
+ uint32_t cntr_unknown_0;
+ ndr_print_struct(ndr, name, "nbt_netlogon_query_for_pdc2");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "request_count", r->request_count);
+ ndr_print_string(ndr, "computer_name", r->computer_name);
+ ndr_print_string(ndr, "user_name", r->user_name);
+ ndr_print_string(ndr, "mailslot_name", r->mailslot_name);
+ ndr->print(ndr, "%s: ARRAY(%d)", "unknown", (int)2);
+ ndr->depth++;
+ for (cntr_unknown_0=0;cntr_unknown_0<2;cntr_unknown_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_unknown_0) != -1) {
+ ndr_print_uint32(ndr, "unknown", r->unknown[cntr_unknown_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr_print_nbt_netlogon_version(ndr, "nt_version", r->nt_version);
+ ndr_print_uint16(ndr, "lmnt_token", r->lmnt_token);
+ ndr_print_uint16(ndr, "lm20_token", r->lm20_token);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_netlogon_response_from_pdc(struct ndr_push *ndr, int ndr_flags, const struct nbt_netlogon_response_from_pdc *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->pdc_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN2);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->unicode_pdc_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->domain_name));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_push_nbt_netlogon_version(ndr, NDR_SCALARS, r->nt_version));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_netlogon_response_from_pdc(struct ndr_pull *ndr, int ndr_flags, struct nbt_netlogon_response_from_pdc *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->pdc_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN2);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->unicode_pdc_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->domain_name));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_pull_nbt_netlogon_version(ndr, NDR_SCALARS, &r->nt_version));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_netlogon_response_from_pdc(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_response_from_pdc *r)
+{
+ ndr_print_struct(ndr, name, "nbt_netlogon_response_from_pdc");
+ ndr->depth++;
+ ndr_print_string(ndr, "pdc_name", r->pdc_name);
+ ndr_print_DATA_BLOB(ndr, "_pad", r->_pad);
+ ndr_print_string(ndr, "unicode_pdc_name", r->unicode_pdc_name);
+ ndr_print_string(ndr, "domain_name", r->domain_name);
+ ndr_print_nbt_netlogon_version(ndr, "nt_version", r->nt_version);
+ ndr_print_uint16(ndr, "lmnt_token", r->lmnt_token);
+ ndr_print_uint16(ndr, "lm20_token", r->lm20_token);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_server_type(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_server_type(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_server_type(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NBT_SERVER_PDC", NBT_SERVER_PDC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NBT_SERVER_GC", NBT_SERVER_GC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NBT_SERVER_LDAP", NBT_SERVER_LDAP, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NBT_SERVER_DS", NBT_SERVER_DS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NBT_SERVER_KDC", NBT_SERVER_KDC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NBT_SERVER_TIMESERV", NBT_SERVER_TIMESERV, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NBT_SERVER_CLOSEST", NBT_SERVER_CLOSEST, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NBT_SERVER_WRITABLE", NBT_SERVER_WRITABLE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NBT_SERVER_GOOD_TIMESERV", NBT_SERVER_GOOD_TIMESERV, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NBT_SERVER_NDNC", NBT_SERVER_NDNC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NBT_SERVER_SELECT_SECRET_DOMAIN_6", NBT_SERVER_SELECT_SECRET_DOMAIN_6, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NBT_SERVER_FULL_SECRET_DOMAIN_6", NBT_SERVER_FULL_SECRET_DOMAIN_6, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_dc_sock_addr(struct ndr_push *ndr, int ndr_flags, const struct nbt_dc_sock_addr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->family));
+ {
+ uint32_t _flags_save_ipv4address = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
+ NDR_CHECK(ndr_push_ipv4address(ndr, NDR_SCALARS, r->pdc_ip));
+ ndr->flags = _flags_save_ipv4address;
+ }
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->remaining));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_dc_sock_addr(struct ndr_pull *ndr, int ndr_flags, struct nbt_dc_sock_addr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->family));
+ {
+ uint32_t _flags_save_ipv4address = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
+ NDR_CHECK(ndr_pull_ipv4address(ndr, NDR_SCALARS, &r->pdc_ip));
+ ndr->flags = _flags_save_ipv4address;
+ }
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->remaining));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_dc_sock_addr(struct ndr_print *ndr, const char *name, const struct nbt_dc_sock_addr *r)
+{
+ ndr_print_struct(ndr, name, "nbt_dc_sock_addr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "family", r->family);
+ ndr_print_ipv4address(ndr, "pdc_ip", r->pdc_ip);
+ ndr_print_DATA_BLOB(ndr, "remaining", r->remaining);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_netlogon_response_from_pdc2(struct ndr_push *ndr, int ndr_flags, const struct nbt_netlogon_response_from_pdc2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ NDR_CHECK(ndr_push_nbt_server_type(ndr, NDR_SCALARS, r->server_type));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->domain_uuid));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->forest));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->dns_domain));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_dns_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->domain));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->user_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->server_site));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->client_site));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->dc_sock_addr_size));
+ {
+ struct ndr_push *_ndr_dc_sock_addr;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_dc_sock_addr, 0, r->dc_sock_addr_size));
+ NDR_CHECK(ndr_push_nbt_dc_sock_addr(_ndr_dc_sock_addr, NDR_SCALARS, &r->dc_sock_addr));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_dc_sock_addr, 0, r->dc_sock_addr_size));
+ }
+ NDR_CHECK(ndr_push_nbt_netlogon_version(ndr, NDR_SCALARS, r->nt_version));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_netlogon_response_from_pdc2(struct ndr_pull *ndr, int ndr_flags, struct nbt_netlogon_response_from_pdc2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ NDR_CHECK(ndr_pull_nbt_server_type(ndr, NDR_SCALARS, &r->server_type));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->domain_uuid));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->forest));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->dns_domain));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_dns_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->domain));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->user_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->server_site));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->client_site));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->dc_sock_addr_size));
+ {
+ struct ndr_pull *_ndr_dc_sock_addr;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_dc_sock_addr, 0, r->dc_sock_addr_size));
+ NDR_CHECK(ndr_pull_nbt_dc_sock_addr(_ndr_dc_sock_addr, NDR_SCALARS, &r->dc_sock_addr));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_dc_sock_addr, 0, r->dc_sock_addr_size));
+ }
+ NDR_CHECK(ndr_pull_nbt_netlogon_version(ndr, NDR_SCALARS, &r->nt_version));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_netlogon_response_from_pdc2(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_response_from_pdc2 *r)
+{
+ ndr_print_struct(ndr, name, "nbt_netlogon_response_from_pdc2");
+ ndr->depth++;
+ ndr_print_DATA_BLOB(ndr, "_pad", r->_pad);
+ ndr_print_nbt_server_type(ndr, "server_type", r->server_type);
+ ndr_print_GUID(ndr, "domain_uuid", &r->domain_uuid);
+ ndr_print_nbt_string(ndr, "forest", r->forest);
+ ndr_print_nbt_string(ndr, "dns_domain", r->dns_domain);
+ ndr_print_nbt_string(ndr, "pdc_dns_name", r->pdc_dns_name);
+ ndr_print_nbt_string(ndr, "domain", r->domain);
+ ndr_print_nbt_string(ndr, "pdc_name", r->pdc_name);
+ ndr_print_nbt_string(ndr, "user_name", r->user_name);
+ ndr_print_nbt_string(ndr, "server_site", r->server_site);
+ ndr_print_nbt_string(ndr, "client_site", r->client_site);
+ ndr_print_uint8(ndr, "dc_sock_addr_size", r->dc_sock_addr_size);
+ ndr_print_nbt_dc_sock_addr(ndr, "dc_sock_addr", &r->dc_sock_addr);
+ ndr_print_nbt_netlogon_version(ndr, "nt_version", r->nt_version);
+ ndr_print_uint16(ndr, "lmnt_token", r->lmnt_token);
+ ndr_print_uint16(ndr, "lm20_token", r->lm20_token);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_db_change(struct ndr_push *ndr, int ndr_flags, const struct nbt_db_change *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_netr_SamDatabaseID(ndr, NDR_SCALARS, r->db_index));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->serial));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->timestamp));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_db_change(struct ndr_pull *ndr, int ndr_flags, struct nbt_db_change *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_netr_SamDatabaseID(ndr, NDR_SCALARS, &r->db_index));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->serial));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->timestamp));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_db_change(struct ndr_print *ndr, const char *name, const struct nbt_db_change *r)
+{
+ ndr_print_struct(ndr, name, "nbt_db_change");
+ ndr->depth++;
+ ndr_print_netr_SamDatabaseID(ndr, "db_index", r->db_index);
+ ndr_print_hyper(ndr, "serial", r->serial);
+ ndr_print_NTTIME(ndr, "timestamp", r->timestamp);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_netlogon_announce_uas(struct ndr_push *ndr, int ndr_flags, const struct nbt_netlogon_announce_uas *r)
+{
+ uint32_t cntr_dbchange_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->serial_lo));
+ NDR_CHECK(ndr_push_time_t(ndr, NDR_SCALARS, r->timestamp));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pulse));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->random));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->pdc_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->domain));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN2);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->unicode_pdc_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->unicode_domain));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->db_count));
+ for (cntr_dbchange_0 = 0; cntr_dbchange_0 < r->db_count; cntr_dbchange_0++) {
+ NDR_CHECK(ndr_push_nbt_db_change(ndr, NDR_SCALARS, &r->dbchange[cntr_dbchange_0]));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_dom_sid0(&r->sid, ndr->flags)));
+ {
+ struct ndr_push *_ndr_sid;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_sid, 0, ndr_size_dom_sid0(&r->sid, ndr->flags)));
+ NDR_CHECK(ndr_push_dom_sid0(_ndr_sid, NDR_SCALARS|NDR_BUFFERS, &r->sid));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_sid, 0, ndr_size_dom_sid0(&r->sid, ndr->flags)));
+ }
+ NDR_CHECK(ndr_push_nbt_netlogon_version(ndr, NDR_SCALARS, r->nt_version));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_netlogon_announce_uas(struct ndr_pull *ndr, int ndr_flags, struct nbt_netlogon_announce_uas *r)
+{
+ uint32_t cntr_dbchange_0;
+ TALLOC_CTX *_mem_save_dbchange_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->serial_lo));
+ NDR_CHECK(ndr_pull_time_t(ndr, NDR_SCALARS, &r->timestamp));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pulse));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->random));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->pdc_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->domain));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN2);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->unicode_pdc_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->unicode_domain));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->db_count));
+ NDR_PULL_ALLOC_N(ndr, r->dbchange, r->db_count);
+ _mem_save_dbchange_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->dbchange, 0);
+ for (cntr_dbchange_0 = 0; cntr_dbchange_0 < r->db_count; cntr_dbchange_0++) {
+ NDR_CHECK(ndr_pull_nbt_db_change(ndr, NDR_SCALARS, &r->dbchange[cntr_dbchange_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dbchange_0, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sid_size));
+ {
+ struct ndr_pull *_ndr_sid;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_sid, 0, r->sid_size));
+ NDR_CHECK(ndr_pull_dom_sid0(_ndr_sid, NDR_SCALARS|NDR_BUFFERS, &r->sid));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_sid, 0, r->sid_size));
+ }
+ NDR_CHECK(ndr_pull_nbt_netlogon_version(ndr, NDR_SCALARS, &r->nt_version));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_netlogon_announce_uas(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_announce_uas *r)
+{
+ uint32_t cntr_dbchange_0;
+ ndr_print_struct(ndr, name, "nbt_netlogon_announce_uas");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "serial_lo", r->serial_lo);
+ ndr_print_time_t(ndr, "timestamp", r->timestamp);
+ ndr_print_uint32(ndr, "pulse", r->pulse);
+ ndr_print_uint32(ndr, "random", r->random);
+ ndr_print_string(ndr, "pdc_name", r->pdc_name);
+ ndr_print_string(ndr, "domain", r->domain);
+ ndr_print_DATA_BLOB(ndr, "_pad", r->_pad);
+ ndr_print_string(ndr, "unicode_pdc_name", r->unicode_pdc_name);
+ ndr_print_string(ndr, "unicode_domain", r->unicode_domain);
+ ndr_print_uint32(ndr, "db_count", r->db_count);
+ ndr->print(ndr, "%s: ARRAY(%d)", "dbchange", (int)r->db_count);
+ ndr->depth++;
+ for (cntr_dbchange_0=0;cntr_dbchange_0<r->db_count;cntr_dbchange_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_dbchange_0) != -1) {
+ ndr_print_nbt_db_change(ndr, "dbchange", &r->dbchange[cntr_dbchange_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "sid_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_dom_sid0(&r->sid, ndr->flags):r->sid_size);
+ ndr_print_dom_sid0(ndr, "sid", &r->sid);
+ ndr_print_nbt_netlogon_version(ndr, "nt_version", r->nt_version);
+ ndr_print_uint16(ndr, "lmnt_token", r->lmnt_token);
+ ndr_print_uint16(ndr, "lm20_token", r->lm20_token);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_netlogon_request(struct ndr_push *ndr, int ndr_flags, const union nbt_netlogon_request *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case NETLOGON_QUERY_FOR_PDC: {
+ NDR_CHECK(ndr_push_nbt_netlogon_query_for_pdc(ndr, NDR_SCALARS, &r->pdc));
+ break; }
+
+ case NETLOGON_QUERY_FOR_PDC2: {
+ NDR_CHECK(ndr_push_nbt_netlogon_query_for_pdc2(ndr, NDR_SCALARS, &r->pdc2));
+ break; }
+
+ case NETLOGON_ANNOUNCE_UAS: {
+ NDR_CHECK(ndr_push_nbt_netlogon_announce_uas(ndr, NDR_SCALARS, &r->uas));
+ break; }
+
+ case NETLOGON_RESPONSE_FROM_PDC: {
+ NDR_CHECK(ndr_push_nbt_netlogon_response_from_pdc(ndr, NDR_SCALARS, &r->response));
+ break; }
+
+ case NETLOGON_RESPONSE_FROM_PDC2: {
+ NDR_CHECK(ndr_push_nbt_netlogon_response_from_pdc2(ndr, NDR_SCALARS, &r->response2));
+ break; }
+
+ case NETLOGON_RESPONSE_FROM_PDC_USER: {
+ NDR_CHECK(ndr_push_nbt_netlogon_response_from_pdc2(ndr, NDR_SCALARS, &r->response2));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case NETLOGON_QUERY_FOR_PDC:
+ break;
+
+ case NETLOGON_QUERY_FOR_PDC2:
+ break;
+
+ case NETLOGON_ANNOUNCE_UAS:
+ NDR_CHECK(ndr_push_nbt_netlogon_announce_uas(ndr, NDR_BUFFERS, &r->uas));
+ break;
+
+ case NETLOGON_RESPONSE_FROM_PDC:
+ break;
+
+ case NETLOGON_RESPONSE_FROM_PDC2:
+ break;
+
+ case NETLOGON_RESPONSE_FROM_PDC_USER:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_netlogon_request(struct ndr_pull *ndr, int ndr_flags, union nbt_netlogon_request *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case NETLOGON_QUERY_FOR_PDC: {
+ NDR_CHECK(ndr_pull_nbt_netlogon_query_for_pdc(ndr, NDR_SCALARS, &r->pdc));
+ break; }
+
+ case NETLOGON_QUERY_FOR_PDC2: {
+ NDR_CHECK(ndr_pull_nbt_netlogon_query_for_pdc2(ndr, NDR_SCALARS, &r->pdc2));
+ break; }
+
+ case NETLOGON_ANNOUNCE_UAS: {
+ NDR_CHECK(ndr_pull_nbt_netlogon_announce_uas(ndr, NDR_SCALARS, &r->uas));
+ break; }
+
+ case NETLOGON_RESPONSE_FROM_PDC: {
+ NDR_CHECK(ndr_pull_nbt_netlogon_response_from_pdc(ndr, NDR_SCALARS, &r->response));
+ break; }
+
+ case NETLOGON_RESPONSE_FROM_PDC2: {
+ NDR_CHECK(ndr_pull_nbt_netlogon_response_from_pdc2(ndr, NDR_SCALARS, &r->response2));
+ break; }
+
+ case NETLOGON_RESPONSE_FROM_PDC_USER: {
+ NDR_CHECK(ndr_pull_nbt_netlogon_response_from_pdc2(ndr, NDR_SCALARS, &r->response2));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case NETLOGON_QUERY_FOR_PDC:
+ break;
+
+ case NETLOGON_QUERY_FOR_PDC2:
+ break;
+
+ case NETLOGON_ANNOUNCE_UAS:
+ NDR_CHECK(ndr_pull_nbt_netlogon_announce_uas(ndr, NDR_BUFFERS, &r->uas));
+ break;
+
+ case NETLOGON_RESPONSE_FROM_PDC:
+ break;
+
+ case NETLOGON_RESPONSE_FROM_PDC2:
+ break;
+
+ case NETLOGON_RESPONSE_FROM_PDC_USER:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_netlogon_request(struct ndr_print *ndr, const char *name, const union nbt_netlogon_request *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "nbt_netlogon_request");
+ switch (level) {
+ case NETLOGON_QUERY_FOR_PDC:
+ ndr_print_nbt_netlogon_query_for_pdc(ndr, "pdc", &r->pdc);
+ break;
+
+ case NETLOGON_QUERY_FOR_PDC2:
+ ndr_print_nbt_netlogon_query_for_pdc2(ndr, "pdc2", &r->pdc2);
+ break;
+
+ case NETLOGON_ANNOUNCE_UAS:
+ ndr_print_nbt_netlogon_announce_uas(ndr, "uas", &r->uas);
+ break;
+
+ case NETLOGON_RESPONSE_FROM_PDC:
+ ndr_print_nbt_netlogon_response_from_pdc(ndr, "response", &r->response);
+ break;
+
+ case NETLOGON_RESPONSE_FROM_PDC2:
+ ndr_print_nbt_netlogon_response_from_pdc2(ndr, "response2", &r->response2);
+ break;
+
+ case NETLOGON_RESPONSE_FROM_PDC_USER:
+ ndr_print_nbt_netlogon_response_from_pdc2(ndr, "response2", &r->response2);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_netlogon_packet(struct ndr_push *ndr, int ndr_flags, const struct nbt_netlogon_packet *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_nbt_netlogon_command(ndr, NDR_SCALARS, r->command));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->req, r->command));
+ NDR_CHECK(ndr_push_nbt_netlogon_request(ndr, NDR_SCALARS, &r->req));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_nbt_netlogon_request(ndr, NDR_BUFFERS, &r->req));
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_netlogon_packet(struct ndr_pull *ndr, int ndr_flags, struct nbt_netlogon_packet *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_nbt_netlogon_command(ndr, NDR_SCALARS, &r->command));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->req, r->command));
+ NDR_CHECK(ndr_pull_nbt_netlogon_request(ndr, NDR_SCALARS, &r->req));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_nbt_netlogon_request(ndr, NDR_BUFFERS, &r->req));
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_netlogon_packet(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_packet *r)
+{
+ ndr_print_struct(ndr, name, "nbt_netlogon_packet");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ ndr->depth++;
+ ndr_print_nbt_netlogon_command(ndr, "command", r->command);
+ ndr_print_set_switch_value(ndr, &r->req, r->command);
+ ndr_print_nbt_netlogon_request(ndr, "req", &r->req);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_nbt_cldap_netlogon_1(struct ndr_push *ndr, int ndr_flags, const struct nbt_cldap_netlogon_1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_nbt_netlogon_command(ndr, NDR_SCALARS, r->type));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->pdc_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->user_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->domain_name));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_push_nbt_netlogon_version(ndr, NDR_SCALARS, 1));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_cldap_netlogon_1(struct ndr_pull *ndr, int ndr_flags, struct nbt_cldap_netlogon_1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_nbt_netlogon_command(ndr, NDR_SCALARS, &r->type));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->pdc_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->user_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->domain_name));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_pull_nbt_netlogon_version(ndr, NDR_SCALARS, &r->nt_version));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_cldap_netlogon_1(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_1 *r)
+{
+ ndr_print_struct(ndr, name, "nbt_cldap_netlogon_1");
+ ndr->depth++;
+ ndr_print_nbt_netlogon_command(ndr, "type", r->type);
+ ndr_print_string(ndr, "pdc_name", r->pdc_name);
+ ndr_print_string(ndr, "user_name", r->user_name);
+ ndr_print_string(ndr, "domain_name", r->domain_name);
+ ndr_print_nbt_netlogon_version(ndr, "nt_version", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?1:r->nt_version);
+ ndr_print_uint16(ndr, "lmnt_token", r->lmnt_token);
+ ndr_print_uint16(ndr, "lm20_token", r->lm20_token);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_cldap_netlogon_3(struct ndr_push *ndr, int ndr_flags, const struct nbt_cldap_netlogon_3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_nbt_netlogon_command(ndr, NDR_SCALARS, r->type));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->pdc_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->user_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->domain_name));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->domain_uuid));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->unknown_uuid));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->forest));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->dns_domain));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_dns_name));
+ NDR_CHECK(ndr_push_ipv4address(ndr, NDR_SCALARS, r->pdc_ip));
+ NDR_CHECK(ndr_push_nbt_server_type(ndr, NDR_SCALARS, r->server_type));
+ NDR_CHECK(ndr_push_nbt_netlogon_version(ndr, NDR_SCALARS, 3));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_cldap_netlogon_3(struct ndr_pull *ndr, int ndr_flags, struct nbt_cldap_netlogon_3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_nbt_netlogon_command(ndr, NDR_SCALARS, &r->type));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->pdc_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->user_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->domain_name));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->domain_uuid));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->unknown_uuid));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->forest));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->dns_domain));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_dns_name));
+ NDR_CHECK(ndr_pull_ipv4address(ndr, NDR_SCALARS, &r->pdc_ip));
+ NDR_CHECK(ndr_pull_nbt_server_type(ndr, NDR_SCALARS, &r->server_type));
+ NDR_CHECK(ndr_pull_nbt_netlogon_version(ndr, NDR_SCALARS, &r->nt_version));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_cldap_netlogon_3(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_3 *r)
+{
+ ndr_print_struct(ndr, name, "nbt_cldap_netlogon_3");
+ ndr->depth++;
+ ndr_print_nbt_netlogon_command(ndr, "type", r->type);
+ ndr_print_string(ndr, "pdc_name", r->pdc_name);
+ ndr_print_string(ndr, "user_name", r->user_name);
+ ndr_print_string(ndr, "domain_name", r->domain_name);
+ ndr_print_GUID(ndr, "domain_uuid", &r->domain_uuid);
+ ndr_print_GUID(ndr, "unknown_uuid", &r->unknown_uuid);
+ ndr_print_nbt_string(ndr, "forest", r->forest);
+ ndr_print_nbt_string(ndr, "dns_domain", r->dns_domain);
+ ndr_print_nbt_string(ndr, "pdc_dns_name", r->pdc_dns_name);
+ ndr_print_ipv4address(ndr, "pdc_ip", r->pdc_ip);
+ ndr_print_nbt_server_type(ndr, "server_type", r->server_type);
+ ndr_print_nbt_netlogon_version(ndr, "nt_version", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?3:r->nt_version);
+ ndr_print_uint16(ndr, "lmnt_token", r->lmnt_token);
+ ndr_print_uint16(ndr, "lm20_token", r->lm20_token);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_cldap_netlogon_5(struct ndr_push *ndr, int ndr_flags, const struct nbt_cldap_netlogon_5 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_nbt_netlogon_command(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->sbz));
+ NDR_CHECK(ndr_push_nbt_server_type(ndr, NDR_SCALARS, r->server_type));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->domain_uuid));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->forest));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->dns_domain));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_dns_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->domain));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->user_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->server_site));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->client_site));
+ NDR_CHECK(ndr_push_nbt_netlogon_version(ndr, NDR_SCALARS, 5));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_cldap_netlogon_5(struct ndr_pull *ndr, int ndr_flags, struct nbt_cldap_netlogon_5 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_nbt_netlogon_command(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->sbz));
+ NDR_CHECK(ndr_pull_nbt_server_type(ndr, NDR_SCALARS, &r->server_type));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->domain_uuid));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->forest));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->dns_domain));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_dns_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->domain));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->user_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->server_site));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->client_site));
+ NDR_CHECK(ndr_pull_nbt_netlogon_version(ndr, NDR_SCALARS, &r->nt_version));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_cldap_netlogon_5(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_5 *r)
+{
+ ndr_print_struct(ndr, name, "nbt_cldap_netlogon_5");
+ ndr->depth++;
+ ndr_print_nbt_netlogon_command(ndr, "type", r->type);
+ ndr_print_uint16(ndr, "sbz", r->sbz);
+ ndr_print_nbt_server_type(ndr, "server_type", r->server_type);
+ ndr_print_GUID(ndr, "domain_uuid", &r->domain_uuid);
+ ndr_print_nbt_string(ndr, "forest", r->forest);
+ ndr_print_nbt_string(ndr, "dns_domain", r->dns_domain);
+ ndr_print_nbt_string(ndr, "pdc_dns_name", r->pdc_dns_name);
+ ndr_print_nbt_string(ndr, "domain", r->domain);
+ ndr_print_nbt_string(ndr, "pdc_name", r->pdc_name);
+ ndr_print_nbt_string(ndr, "user_name", r->user_name);
+ ndr_print_nbt_string(ndr, "server_site", r->server_site);
+ ndr_print_nbt_string(ndr, "client_site", r->client_site);
+ ndr_print_nbt_netlogon_version(ndr, "nt_version", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?5:r->nt_version);
+ ndr_print_uint16(ndr, "lmnt_token", r->lmnt_token);
+ ndr_print_uint16(ndr, "lm20_token", r->lm20_token);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_cldap_netlogon_13(struct ndr_push *ndr, int ndr_flags, const struct nbt_cldap_netlogon_13 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_nbt_netlogon_command(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->sbz));
+ NDR_CHECK(ndr_push_nbt_server_type(ndr, NDR_SCALARS, r->server_type));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->domain_uuid));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->forest));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->dns_domain));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_dns_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->domain));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->user_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->server_site));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->client_site));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->dc_sock_addr_size));
+ {
+ struct ndr_push *_ndr_dc_sock_addr;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_dc_sock_addr, 0, r->dc_sock_addr_size));
+ NDR_CHECK(ndr_push_nbt_dc_sock_addr(_ndr_dc_sock_addr, NDR_SCALARS, &r->dc_sock_addr));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_dc_sock_addr, 0, r->dc_sock_addr_size));
+ }
+ NDR_CHECK(ndr_push_nbt_netlogon_version(ndr, NDR_SCALARS, 13));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_cldap_netlogon_13(struct ndr_pull *ndr, int ndr_flags, struct nbt_cldap_netlogon_13 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_nbt_netlogon_command(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->sbz));
+ NDR_CHECK(ndr_pull_nbt_server_type(ndr, NDR_SCALARS, &r->server_type));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->domain_uuid));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->forest));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->dns_domain));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_dns_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->domain));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->user_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->server_site));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->client_site));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->dc_sock_addr_size));
+ {
+ struct ndr_pull *_ndr_dc_sock_addr;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_dc_sock_addr, 0, r->dc_sock_addr_size));
+ NDR_CHECK(ndr_pull_nbt_dc_sock_addr(_ndr_dc_sock_addr, NDR_SCALARS, &r->dc_sock_addr));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_dc_sock_addr, 0, r->dc_sock_addr_size));
+ }
+ NDR_CHECK(ndr_pull_nbt_netlogon_version(ndr, NDR_SCALARS, &r->nt_version));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_cldap_netlogon_13(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_13 *r)
+{
+ ndr_print_struct(ndr, name, "nbt_cldap_netlogon_13");
+ ndr->depth++;
+ ndr_print_nbt_netlogon_command(ndr, "type", r->type);
+ ndr_print_uint16(ndr, "sbz", r->sbz);
+ ndr_print_nbt_server_type(ndr, "server_type", r->server_type);
+ ndr_print_GUID(ndr, "domain_uuid", &r->domain_uuid);
+ ndr_print_nbt_string(ndr, "forest", r->forest);
+ ndr_print_nbt_string(ndr, "dns_domain", r->dns_domain);
+ ndr_print_nbt_string(ndr, "pdc_dns_name", r->pdc_dns_name);
+ ndr_print_nbt_string(ndr, "domain", r->domain);
+ ndr_print_nbt_string(ndr, "pdc_name", r->pdc_name);
+ ndr_print_nbt_string(ndr, "user_name", r->user_name);
+ ndr_print_nbt_string(ndr, "server_site", r->server_site);
+ ndr_print_nbt_string(ndr, "client_site", r->client_site);
+ ndr_print_uint8(ndr, "dc_sock_addr_size", r->dc_sock_addr_size);
+ ndr_print_nbt_dc_sock_addr(ndr, "dc_sock_addr", &r->dc_sock_addr);
+ ndr_print_nbt_netlogon_version(ndr, "nt_version", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?13:r->nt_version);
+ ndr_print_uint16(ndr, "lmnt_token", r->lmnt_token);
+ ndr_print_uint16(ndr, "lm20_token", r->lm20_token);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_cldap_netlogon_15(struct ndr_push *ndr, int ndr_flags, const struct nbt_cldap_netlogon_15 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_nbt_netlogon_command(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->sbz));
+ NDR_CHECK(ndr_push_nbt_server_type(ndr, NDR_SCALARS, r->server_type));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->domain_uuid));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->forest));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->dns_domain));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_dns_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->domain));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->user_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->server_site));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->client_site));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->next_closest_site));
+ NDR_CHECK(ndr_push_nbt_netlogon_version(ndr, NDR_SCALARS, 15));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_cldap_netlogon_15(struct ndr_pull *ndr, int ndr_flags, struct nbt_cldap_netlogon_15 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_nbt_netlogon_command(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->sbz));
+ NDR_CHECK(ndr_pull_nbt_server_type(ndr, NDR_SCALARS, &r->server_type));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->domain_uuid));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->forest));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->dns_domain));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_dns_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->domain));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->user_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->server_site));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->client_site));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->next_closest_site));
+ NDR_CHECK(ndr_pull_nbt_netlogon_version(ndr, NDR_SCALARS, &r->nt_version));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_cldap_netlogon_15(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_15 *r)
+{
+ ndr_print_struct(ndr, name, "nbt_cldap_netlogon_15");
+ ndr->depth++;
+ ndr_print_nbt_netlogon_command(ndr, "type", r->type);
+ ndr_print_uint16(ndr, "sbz", r->sbz);
+ ndr_print_nbt_server_type(ndr, "server_type", r->server_type);
+ ndr_print_GUID(ndr, "domain_uuid", &r->domain_uuid);
+ ndr_print_nbt_string(ndr, "forest", r->forest);
+ ndr_print_nbt_string(ndr, "dns_domain", r->dns_domain);
+ ndr_print_nbt_string(ndr, "pdc_dns_name", r->pdc_dns_name);
+ ndr_print_nbt_string(ndr, "domain", r->domain);
+ ndr_print_nbt_string(ndr, "pdc_name", r->pdc_name);
+ ndr_print_nbt_string(ndr, "user_name", r->user_name);
+ ndr_print_nbt_string(ndr, "server_site", r->server_site);
+ ndr_print_nbt_string(ndr, "client_site", r->client_site);
+ ndr_print_nbt_string(ndr, "next_closest_site", r->next_closest_site);
+ ndr_print_nbt_netlogon_version(ndr, "nt_version", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?15:r->nt_version);
+ ndr_print_uint16(ndr, "lmnt_token", r->lmnt_token);
+ ndr_print_uint16(ndr, "lm20_token", r->lm20_token);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_cldap_netlogon_29(struct ndr_push *ndr, int ndr_flags, const struct nbt_cldap_netlogon_29 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_nbt_netlogon_command(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->sbz));
+ NDR_CHECK(ndr_push_nbt_server_type(ndr, NDR_SCALARS, r->server_type));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->domain_uuid));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->forest));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->dns_domain));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_dns_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->domain));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->user_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->server_site));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->client_site));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->dc_sock_addr_size));
+ {
+ struct ndr_push *_ndr_dc_sock_addr;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_dc_sock_addr, 0, r->dc_sock_addr_size));
+ NDR_CHECK(ndr_push_nbt_dc_sock_addr(_ndr_dc_sock_addr, NDR_SCALARS, &r->dc_sock_addr));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_dc_sock_addr, 0, r->dc_sock_addr_size));
+ }
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->next_closest_site));
+ NDR_CHECK(ndr_push_nbt_netlogon_version(ndr, NDR_SCALARS, 29));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_cldap_netlogon_29(struct ndr_pull *ndr, int ndr_flags, struct nbt_cldap_netlogon_29 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_nbt_netlogon_command(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->sbz));
+ NDR_CHECK(ndr_pull_nbt_server_type(ndr, NDR_SCALARS, &r->server_type));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->domain_uuid));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->forest));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->dns_domain));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_dns_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->domain));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->user_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->server_site));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->client_site));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->dc_sock_addr_size));
+ {
+ struct ndr_pull *_ndr_dc_sock_addr;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_dc_sock_addr, 0, r->dc_sock_addr_size));
+ NDR_CHECK(ndr_pull_nbt_dc_sock_addr(_ndr_dc_sock_addr, NDR_SCALARS, &r->dc_sock_addr));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_dc_sock_addr, 0, r->dc_sock_addr_size));
+ }
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->next_closest_site));
+ NDR_CHECK(ndr_pull_nbt_netlogon_version(ndr, NDR_SCALARS, &r->nt_version));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_cldap_netlogon_29(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_29 *r)
+{
+ ndr_print_struct(ndr, name, "nbt_cldap_netlogon_29");
+ ndr->depth++;
+ ndr_print_nbt_netlogon_command(ndr, "type", r->type);
+ ndr_print_uint16(ndr, "sbz", r->sbz);
+ ndr_print_nbt_server_type(ndr, "server_type", r->server_type);
+ ndr_print_GUID(ndr, "domain_uuid", &r->domain_uuid);
+ ndr_print_nbt_string(ndr, "forest", r->forest);
+ ndr_print_nbt_string(ndr, "dns_domain", r->dns_domain);
+ ndr_print_nbt_string(ndr, "pdc_dns_name", r->pdc_dns_name);
+ ndr_print_nbt_string(ndr, "domain", r->domain);
+ ndr_print_nbt_string(ndr, "pdc_name", r->pdc_name);
+ ndr_print_nbt_string(ndr, "user_name", r->user_name);
+ ndr_print_nbt_string(ndr, "server_site", r->server_site);
+ ndr_print_nbt_string(ndr, "client_site", r->client_site);
+ ndr_print_uint8(ndr, "dc_sock_addr_size", r->dc_sock_addr_size);
+ ndr_print_nbt_dc_sock_addr(ndr, "dc_sock_addr", &r->dc_sock_addr);
+ ndr_print_nbt_string(ndr, "next_closest_site", r->next_closest_site);
+ ndr_print_nbt_netlogon_version(ndr, "nt_version", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?29:r->nt_version);
+ ndr_print_uint16(ndr, "lmnt_token", r->lmnt_token);
+ ndr_print_uint16(ndr, "lm20_token", r->lm20_token);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_cldap_netlogon(struct ndr_push *ndr, int ndr_flags, const union nbt_cldap_netlogon *r)
+{
+ {
+ uint32_t _flags_save_UNION = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_1(ndr, NDR_SCALARS, &r->logon1));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_1(ndr, NDR_SCALARS, &r->logon1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_3(ndr, NDR_SCALARS, &r->logon3));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_3(ndr, NDR_SCALARS, &r->logon3));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_5(ndr, NDR_SCALARS, &r->logon5));
+ break; }
+
+ case 5: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_5(ndr, NDR_SCALARS, &r->logon5));
+ break; }
+
+ case 6: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_5(ndr, NDR_SCALARS, &r->logon5));
+ break; }
+
+ case 7: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_5(ndr, NDR_SCALARS, &r->logon5));
+ break; }
+
+ case 8: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_13(ndr, NDR_SCALARS, &r->logon13));
+ break; }
+
+ case 9: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_13(ndr, NDR_SCALARS, &r->logon13));
+ break; }
+
+ case 10: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_13(ndr, NDR_SCALARS, &r->logon13));
+ break; }
+
+ case 11: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_13(ndr, NDR_SCALARS, &r->logon13));
+ break; }
+
+ case 12: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_13(ndr, NDR_SCALARS, &r->logon13));
+ break; }
+
+ case 13: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_13(ndr, NDR_SCALARS, &r->logon13));
+ break; }
+
+ case 14: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_13(ndr, NDR_SCALARS, &r->logon13));
+ break; }
+
+ case 15: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_13(ndr, NDR_SCALARS, &r->logon13));
+ break; }
+
+ case 16: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_1(ndr, NDR_SCALARS, &r->logon1));
+ break; }
+
+ case 17: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_1(ndr, NDR_SCALARS, &r->logon1));
+ break; }
+
+ case 18: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_3(ndr, NDR_SCALARS, &r->logon3));
+ break; }
+
+ case 19: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_3(ndr, NDR_SCALARS, &r->logon3));
+ break; }
+
+ case 20: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 21: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 22: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 23: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 24: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 25: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 26: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 27: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 28: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 29: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_29(ndr, NDR_SCALARS, &r->logon29));
+ break; }
+
+ case 30: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_29(ndr, NDR_SCALARS, &r->logon29));
+ break; }
+
+ case 31: {
+ NDR_CHECK(ndr_push_nbt_cldap_netlogon_29(ndr, NDR_SCALARS, &r->logon29));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ break;
+
+ case 1:
+ break;
+
+ case 2:
+ break;
+
+ case 3:
+ break;
+
+ case 4:
+ break;
+
+ case 5:
+ break;
+
+ case 6:
+ break;
+
+ case 7:
+ break;
+
+ case 8:
+ break;
+
+ case 9:
+ break;
+
+ case 10:
+ break;
+
+ case 11:
+ break;
+
+ case 12:
+ break;
+
+ case 13:
+ break;
+
+ case 14:
+ break;
+
+ case 15:
+ break;
+
+ case 16:
+ break;
+
+ case 17:
+ break;
+
+ case 18:
+ break;
+
+ case 19:
+ break;
+
+ case 20:
+ break;
+
+ case 21:
+ break;
+
+ case 22:
+ break;
+
+ case 23:
+ break;
+
+ case 24:
+ break;
+
+ case 25:
+ break;
+
+ case 26:
+ break;
+
+ case 27:
+ break;
+
+ case 28:
+ break;
+
+ case 29:
+ break;
+
+ case 30:
+ break;
+
+ case 31:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ ndr->flags = _flags_save_UNION;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_cldap_netlogon(struct ndr_pull *ndr, int ndr_flags, union nbt_cldap_netlogon *r)
+{
+ int level;
+ {
+ uint32_t _flags_save_UNION = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_1(ndr, NDR_SCALARS, &r->logon1));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_1(ndr, NDR_SCALARS, &r->logon1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_3(ndr, NDR_SCALARS, &r->logon3));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_3(ndr, NDR_SCALARS, &r->logon3));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_5(ndr, NDR_SCALARS, &r->logon5));
+ break; }
+
+ case 5: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_5(ndr, NDR_SCALARS, &r->logon5));
+ break; }
+
+ case 6: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_5(ndr, NDR_SCALARS, &r->logon5));
+ break; }
+
+ case 7: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_5(ndr, NDR_SCALARS, &r->logon5));
+ break; }
+
+ case 8: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_13(ndr, NDR_SCALARS, &r->logon13));
+ break; }
+
+ case 9: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_13(ndr, NDR_SCALARS, &r->logon13));
+ break; }
+
+ case 10: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_13(ndr, NDR_SCALARS, &r->logon13));
+ break; }
+
+ case 11: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_13(ndr, NDR_SCALARS, &r->logon13));
+ break; }
+
+ case 12: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_13(ndr, NDR_SCALARS, &r->logon13));
+ break; }
+
+ case 13: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_13(ndr, NDR_SCALARS, &r->logon13));
+ break; }
+
+ case 14: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_13(ndr, NDR_SCALARS, &r->logon13));
+ break; }
+
+ case 15: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_13(ndr, NDR_SCALARS, &r->logon13));
+ break; }
+
+ case 16: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_1(ndr, NDR_SCALARS, &r->logon1));
+ break; }
+
+ case 17: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_1(ndr, NDR_SCALARS, &r->logon1));
+ break; }
+
+ case 18: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_3(ndr, NDR_SCALARS, &r->logon3));
+ break; }
+
+ case 19: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_3(ndr, NDR_SCALARS, &r->logon3));
+ break; }
+
+ case 20: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 21: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 22: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 23: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 24: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 25: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 26: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 27: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 28: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_15(ndr, NDR_SCALARS, &r->logon15));
+ break; }
+
+ case 29: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_29(ndr, NDR_SCALARS, &r->logon29));
+ break; }
+
+ case 30: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_29(ndr, NDR_SCALARS, &r->logon29));
+ break; }
+
+ case 31: {
+ NDR_CHECK(ndr_pull_nbt_cldap_netlogon_29(ndr, NDR_SCALARS, &r->logon29));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ break;
+
+ case 1:
+ break;
+
+ case 2:
+ break;
+
+ case 3:
+ break;
+
+ case 4:
+ break;
+
+ case 5:
+ break;
+
+ case 6:
+ break;
+
+ case 7:
+ break;
+
+ case 8:
+ break;
+
+ case 9:
+ break;
+
+ case 10:
+ break;
+
+ case 11:
+ break;
+
+ case 12:
+ break;
+
+ case 13:
+ break;
+
+ case 14:
+ break;
+
+ case 15:
+ break;
+
+ case 16:
+ break;
+
+ case 17:
+ break;
+
+ case 18:
+ break;
+
+ case 19:
+ break;
+
+ case 20:
+ break;
+
+ case 21:
+ break;
+
+ case 22:
+ break;
+
+ case 23:
+ break;
+
+ case 24:
+ break;
+
+ case 25:
+ break;
+
+ case 26:
+ break;
+
+ case 27:
+ break;
+
+ case 28:
+ break;
+
+ case 29:
+ break;
+
+ case 30:
+ break;
+
+ case 31:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ ndr->flags = _flags_save_UNION;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_cldap_netlogon(struct ndr_print *ndr, const char *name, const union nbt_cldap_netlogon *r)
+{
+ int level;
+ {
+ uint32_t _flags_save_UNION = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "nbt_cldap_netlogon");
+ switch (level) {
+ case 0:
+ ndr_print_nbt_cldap_netlogon_1(ndr, "logon1", &r->logon1);
+ break;
+
+ case 1:
+ ndr_print_nbt_cldap_netlogon_1(ndr, "logon1", &r->logon1);
+ break;
+
+ case 2:
+ ndr_print_nbt_cldap_netlogon_3(ndr, "logon3", &r->logon3);
+ break;
+
+ case 3:
+ ndr_print_nbt_cldap_netlogon_3(ndr, "logon3", &r->logon3);
+ break;
+
+ case 4:
+ ndr_print_nbt_cldap_netlogon_5(ndr, "logon5", &r->logon5);
+ break;
+
+ case 5:
+ ndr_print_nbt_cldap_netlogon_5(ndr, "logon5", &r->logon5);
+ break;
+
+ case 6:
+ ndr_print_nbt_cldap_netlogon_5(ndr, "logon5", &r->logon5);
+ break;
+
+ case 7:
+ ndr_print_nbt_cldap_netlogon_5(ndr, "logon5", &r->logon5);
+ break;
+
+ case 8:
+ ndr_print_nbt_cldap_netlogon_13(ndr, "logon13", &r->logon13);
+ break;
+
+ case 9:
+ ndr_print_nbt_cldap_netlogon_13(ndr, "logon13", &r->logon13);
+ break;
+
+ case 10:
+ ndr_print_nbt_cldap_netlogon_13(ndr, "logon13", &r->logon13);
+ break;
+
+ case 11:
+ ndr_print_nbt_cldap_netlogon_13(ndr, "logon13", &r->logon13);
+ break;
+
+ case 12:
+ ndr_print_nbt_cldap_netlogon_13(ndr, "logon13", &r->logon13);
+ break;
+
+ case 13:
+ ndr_print_nbt_cldap_netlogon_13(ndr, "logon13", &r->logon13);
+ break;
+
+ case 14:
+ ndr_print_nbt_cldap_netlogon_13(ndr, "logon13", &r->logon13);
+ break;
+
+ case 15:
+ ndr_print_nbt_cldap_netlogon_13(ndr, "logon13", &r->logon13);
+ break;
+
+ case 16:
+ ndr_print_nbt_cldap_netlogon_1(ndr, "logon1", &r->logon1);
+ break;
+
+ case 17:
+ ndr_print_nbt_cldap_netlogon_1(ndr, "logon1", &r->logon1);
+ break;
+
+ case 18:
+ ndr_print_nbt_cldap_netlogon_3(ndr, "logon3", &r->logon3);
+ break;
+
+ case 19:
+ ndr_print_nbt_cldap_netlogon_3(ndr, "logon3", &r->logon3);
+ break;
+
+ case 20:
+ ndr_print_nbt_cldap_netlogon_15(ndr, "logon15", &r->logon15);
+ break;
+
+ case 21:
+ ndr_print_nbt_cldap_netlogon_15(ndr, "logon15", &r->logon15);
+ break;
+
+ case 22:
+ ndr_print_nbt_cldap_netlogon_15(ndr, "logon15", &r->logon15);
+ break;
+
+ case 23:
+ ndr_print_nbt_cldap_netlogon_15(ndr, "logon15", &r->logon15);
+ break;
+
+ case 24:
+ ndr_print_nbt_cldap_netlogon_15(ndr, "logon15", &r->logon15);
+ break;
+
+ case 25:
+ ndr_print_nbt_cldap_netlogon_15(ndr, "logon15", &r->logon15);
+ break;
+
+ case 26:
+ ndr_print_nbt_cldap_netlogon_15(ndr, "logon15", &r->logon15);
+ break;
+
+ case 27:
+ ndr_print_nbt_cldap_netlogon_15(ndr, "logon15", &r->logon15);
+ break;
+
+ case 28:
+ ndr_print_nbt_cldap_netlogon_15(ndr, "logon15", &r->logon15);
+ break;
+
+ case 29:
+ ndr_print_nbt_cldap_netlogon_29(ndr, "logon29", &r->logon29);
+ break;
+
+ case 30:
+ ndr_print_nbt_cldap_netlogon_29(ndr, "logon29", &r->logon29);
+ break;
+
+ case 31:
+ ndr_print_nbt_cldap_netlogon_29(ndr, "logon29", &r->logon29);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+ ndr->flags = _flags_save_UNION;
+ }
+}
+
+static enum ndr_err_code ndr_push_nbt_ntlogon_command(struct ndr_push *ndr, int ndr_flags, enum nbt_ntlogon_command r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_ntlogon_command(struct ndr_pull *ndr, int ndr_flags, enum nbt_ntlogon_command *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_ntlogon_command(struct ndr_print *ndr, const char *name, enum nbt_ntlogon_command r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case NTLOGON_SAM_LOGON: val = "NTLOGON_SAM_LOGON"; break;
+ case NTLOGON_SAM_LOGON_REPLY: val = "NTLOGON_SAM_LOGON_REPLY"; break;
+ case NTLOGON_SAM_LOGON_REPLY15: val = "NTLOGON_SAM_LOGON_REPLY15"; break;
+ case NTLOGON_RESPONSE_FROM_PDC2: val = "NTLOGON_RESPONSE_FROM_PDC2"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_nbt_ntlogon_sam_logon(struct ndr_push *ndr, int ndr_flags, const struct nbt_ntlogon_sam_logon *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->request_count));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->computer_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->user_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->mailslot_name));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_push_samr_AcctFlags(ndr, NDR_SCALARS, r->acct_control));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_dom_sid0(&r->sid, ndr->flags)));
+ {
+ struct ndr_push *_ndr_sid;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_sid, 0, ndr_size_dom_sid0(&r->sid, ndr->flags)));
+ NDR_CHECK(ndr_push_dom_sid0(_ndr_sid, NDR_SCALARS|NDR_BUFFERS, &r->sid));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_sid, 0, ndr_size_dom_sid0(&r->sid, ndr->flags)));
+ }
+ NDR_CHECK(ndr_push_nbt_netlogon_version(ndr, NDR_SCALARS, r->nt_version));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_ntlogon_sam_logon(struct ndr_pull *ndr, int ndr_flags, struct nbt_ntlogon_sam_logon *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->request_count));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->computer_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->user_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->mailslot_name));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_pull_samr_AcctFlags(ndr, NDR_SCALARS, &r->acct_control));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sid_size));
+ {
+ struct ndr_pull *_ndr_sid;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_sid, 0, r->sid_size));
+ NDR_CHECK(ndr_pull_dom_sid0(_ndr_sid, NDR_SCALARS|NDR_BUFFERS, &r->sid));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_sid, 0, r->sid_size));
+ }
+ NDR_CHECK(ndr_pull_nbt_netlogon_version(ndr, NDR_SCALARS, &r->nt_version));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_ntlogon_sam_logon(struct ndr_print *ndr, const char *name, const struct nbt_ntlogon_sam_logon *r)
+{
+ ndr_print_struct(ndr, name, "nbt_ntlogon_sam_logon");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "request_count", r->request_count);
+ ndr_print_string(ndr, "computer_name", r->computer_name);
+ ndr_print_string(ndr, "user_name", r->user_name);
+ ndr_print_string(ndr, "mailslot_name", r->mailslot_name);
+ ndr_print_samr_AcctFlags(ndr, "acct_control", r->acct_control);
+ ndr_print_uint32(ndr, "sid_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_dom_sid0(&r->sid, ndr->flags):r->sid_size);
+ ndr_print_dom_sid0(ndr, "sid", &r->sid);
+ ndr_print_nbt_netlogon_version(ndr, "nt_version", r->nt_version);
+ ndr_print_uint16(ndr, "lmnt_token", r->lmnt_token);
+ ndr_print_uint16(ndr, "lm20_token", r->lm20_token);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_ntlogon_sam_logon_reply(struct ndr_push *ndr, int ndr_flags, const struct nbt_ntlogon_sam_logon_reply *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->server));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->user_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->domain));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_push_nbt_netlogon_version(ndr, NDR_SCALARS, r->nt_version));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_ntlogon_sam_logon_reply(struct ndr_pull *ndr, int ndr_flags, struct nbt_ntlogon_sam_logon_reply *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->server));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->user_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->domain));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_pull_nbt_netlogon_version(ndr, NDR_SCALARS, &r->nt_version));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_ntlogon_sam_logon_reply(struct ndr_print *ndr, const char *name, const struct nbt_ntlogon_sam_logon_reply *r)
+{
+ ndr_print_struct(ndr, name, "nbt_ntlogon_sam_logon_reply");
+ ndr->depth++;
+ ndr_print_string(ndr, "server", r->server);
+ ndr_print_string(ndr, "user_name", r->user_name);
+ ndr_print_string(ndr, "domain", r->domain);
+ ndr_print_nbt_netlogon_version(ndr, "nt_version", r->nt_version);
+ ndr_print_uint16(ndr, "lmnt_token", r->lmnt_token);
+ ndr_print_uint16(ndr, "lm20_token", r->lm20_token);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_ntlogon_request(struct ndr_push *ndr, int ndr_flags, const union nbt_ntlogon_request *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case NTLOGON_SAM_LOGON: {
+ NDR_CHECK(ndr_push_nbt_ntlogon_sam_logon(ndr, NDR_SCALARS, &r->logon));
+ break; }
+
+ case NTLOGON_SAM_LOGON_REPLY: {
+ NDR_CHECK(ndr_push_nbt_ntlogon_sam_logon_reply(ndr, NDR_SCALARS, &r->reply));
+ break; }
+
+ case NTLOGON_SAM_LOGON_REPLY15: {
+ NDR_CHECK(ndr_push_nbt_ntlogon_sam_logon_reply(ndr, NDR_SCALARS, &r->reply));
+ break; }
+
+ case NTLOGON_RESPONSE_FROM_PDC2: {
+ NDR_CHECK(ndr_push_nbt_netlogon_response_from_pdc2(ndr, NDR_SCALARS, &r->reply2));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case NTLOGON_SAM_LOGON:
+ NDR_CHECK(ndr_push_nbt_ntlogon_sam_logon(ndr, NDR_BUFFERS, &r->logon));
+ break;
+
+ case NTLOGON_SAM_LOGON_REPLY:
+ break;
+
+ case NTLOGON_SAM_LOGON_REPLY15:
+ break;
+
+ case NTLOGON_RESPONSE_FROM_PDC2:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_ntlogon_request(struct ndr_pull *ndr, int ndr_flags, union nbt_ntlogon_request *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case NTLOGON_SAM_LOGON: {
+ NDR_CHECK(ndr_pull_nbt_ntlogon_sam_logon(ndr, NDR_SCALARS, &r->logon));
+ break; }
+
+ case NTLOGON_SAM_LOGON_REPLY: {
+ NDR_CHECK(ndr_pull_nbt_ntlogon_sam_logon_reply(ndr, NDR_SCALARS, &r->reply));
+ break; }
+
+ case NTLOGON_SAM_LOGON_REPLY15: {
+ NDR_CHECK(ndr_pull_nbt_ntlogon_sam_logon_reply(ndr, NDR_SCALARS, &r->reply));
+ break; }
+
+ case NTLOGON_RESPONSE_FROM_PDC2: {
+ NDR_CHECK(ndr_pull_nbt_netlogon_response_from_pdc2(ndr, NDR_SCALARS, &r->reply2));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case NTLOGON_SAM_LOGON:
+ NDR_CHECK(ndr_pull_nbt_ntlogon_sam_logon(ndr, NDR_BUFFERS, &r->logon));
+ break;
+
+ case NTLOGON_SAM_LOGON_REPLY:
+ break;
+
+ case NTLOGON_SAM_LOGON_REPLY15:
+ break;
+
+ case NTLOGON_RESPONSE_FROM_PDC2:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_ntlogon_request(struct ndr_print *ndr, const char *name, const union nbt_ntlogon_request *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "nbt_ntlogon_request");
+ switch (level) {
+ case NTLOGON_SAM_LOGON:
+ ndr_print_nbt_ntlogon_sam_logon(ndr, "logon", &r->logon);
+ break;
+
+ case NTLOGON_SAM_LOGON_REPLY:
+ ndr_print_nbt_ntlogon_sam_logon_reply(ndr, "reply", &r->reply);
+ break;
+
+ case NTLOGON_SAM_LOGON_REPLY15:
+ ndr_print_nbt_ntlogon_sam_logon_reply(ndr, "reply", &r->reply);
+ break;
+
+ case NTLOGON_RESPONSE_FROM_PDC2:
+ ndr_print_nbt_netlogon_response_from_pdc2(ndr, "reply2", &r->reply2);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_ntlogon_packet(struct ndr_push *ndr, int ndr_flags, const struct nbt_ntlogon_packet *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_nbt_ntlogon_command(ndr, NDR_SCALARS, r->command));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->req, r->command));
+ NDR_CHECK(ndr_push_nbt_ntlogon_request(ndr, NDR_SCALARS, &r->req));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_nbt_ntlogon_request(ndr, NDR_BUFFERS, &r->req));
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_ntlogon_packet(struct ndr_pull *ndr, int ndr_flags, struct nbt_ntlogon_packet *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_nbt_ntlogon_command(ndr, NDR_SCALARS, &r->command));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->req, r->command));
+ NDR_CHECK(ndr_pull_nbt_ntlogon_request(ndr, NDR_SCALARS, &r->req));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_nbt_ntlogon_request(ndr, NDR_BUFFERS, &r->req));
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_ntlogon_packet(struct ndr_print *ndr, const char *name, const struct nbt_ntlogon_packet *r)
+{
+ ndr_print_struct(ndr, name, "nbt_ntlogon_packet");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ ndr->depth++;
+ ndr_print_nbt_ntlogon_command(ndr, "command", r->command);
+ ndr_print_set_switch_value(ndr, &r->req, r->command);
+ ndr_print_nbt_ntlogon_request(ndr, "req", &r->req);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_nbt_browse_opcode(struct ndr_push *ndr, int ndr_flags, enum nbt_browse_opcode r)
+{
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_browse_opcode(struct ndr_pull *ndr, int ndr_flags, enum nbt_browse_opcode *r)
+{
+ uint8_t v;
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_browse_opcode(struct ndr_print *ndr, const char *name, enum nbt_browse_opcode r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case HostAnnouncement: val = "HostAnnouncement"; break;
+ case AnnouncementRequest: val = "AnnouncementRequest"; break;
+ case Election: val = "Election"; break;
+ case GetBackupListReq: val = "GetBackupListReq"; break;
+ case GetBackupListResp: val = "GetBackupListResp"; break;
+ case BecomeBackup: val = "BecomeBackup"; break;
+ case DomainAnnouncement: val = "DomainAnnouncement"; break;
+ case MasterAnnouncement: val = "MasterAnnouncement"; break;
+ case ResetBrowserState: val = "ResetBrowserState"; break;
+ case LocalMasterAnnouncement: val = "LocalMasterAnnouncement"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_nbt_browse_host_announcement(struct ndr_push *ndr, int ndr_flags, const struct nbt_browse_host_announcement *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->UpdateCount));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->Periodicity));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->ServerName, 16, sizeof(uint8_t), CH_DOS));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->OSMajor));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->OSMinor));
+ NDR_CHECK(ndr_push_svcctl_ServerType(ndr, NDR_SCALARS, r->ServerType));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->BroMajorVer));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->BroMinorVer));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->Signature));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->Comment));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_browse_host_announcement(struct ndr_pull *ndr, int ndr_flags, struct nbt_browse_host_announcement *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->UpdateCount));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->Periodicity));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->ServerName, 16, sizeof(uint8_t), CH_DOS));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->OSMajor));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->OSMinor));
+ NDR_CHECK(ndr_pull_svcctl_ServerType(ndr, NDR_SCALARS, &r->ServerType));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->BroMajorVer));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->BroMinorVer));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->Signature));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->Comment));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_browse_host_announcement(struct ndr_print *ndr, const char *name, const struct nbt_browse_host_announcement *r)
+{
+ ndr_print_struct(ndr, name, "nbt_browse_host_announcement");
+ ndr->depth++;
+ ndr_print_uint8(ndr, "UpdateCount", r->UpdateCount);
+ ndr_print_uint32(ndr, "Periodicity", r->Periodicity);
+ ndr_print_string(ndr, "ServerName", r->ServerName);
+ ndr_print_uint8(ndr, "OSMajor", r->OSMajor);
+ ndr_print_uint8(ndr, "OSMinor", r->OSMinor);
+ ndr_print_svcctl_ServerType(ndr, "ServerType", r->ServerType);
+ ndr_print_uint8(ndr, "BroMajorVer", r->BroMajorVer);
+ ndr_print_uint8(ndr, "BroMinorVer", r->BroMinorVer);
+ ndr_print_uint16(ndr, "Signature", r->Signature);
+ ndr_print_string(ndr, "Comment", r->Comment);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_browse_announcement_request(struct ndr_push *ndr, int ndr_flags, const struct nbt_browse_announcement_request *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->Unused));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->ResponseName));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_browse_announcement_request(struct ndr_pull *ndr, int ndr_flags, struct nbt_browse_announcement_request *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->Unused));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->ResponseName));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_browse_announcement_request(struct ndr_print *ndr, const char *name, const struct nbt_browse_announcement_request *r)
+{
+ ndr_print_struct(ndr, name, "nbt_browse_announcement_request");
+ ndr->depth++;
+ ndr_print_uint8(ndr, "Unused", r->Unused);
+ ndr_print_string(ndr, "ResponseName", r->ResponseName);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_browse_election_request(struct ndr_push *ndr, int ndr_flags, const struct nbt_browse_election_request *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->Version));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->Criteria));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->UpTime));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->Reserved));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->ServerName));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_browse_election_request(struct ndr_pull *ndr, int ndr_flags, struct nbt_browse_election_request *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->Version));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->Criteria));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->UpTime));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->Reserved));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->ServerName));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_browse_election_request(struct ndr_print *ndr, const char *name, const struct nbt_browse_election_request *r)
+{
+ ndr_print_struct(ndr, name, "nbt_browse_election_request");
+ ndr->depth++;
+ ndr_print_uint8(ndr, "Version", r->Version);
+ ndr_print_uint32(ndr, "Criteria", r->Criteria);
+ ndr_print_uint32(ndr, "UpTime", r->UpTime);
+ ndr_print_uint32(ndr, "Reserved", r->Reserved);
+ ndr_print_string(ndr, "ServerName", r->ServerName);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_browse_backup_list_request(struct ndr_push *ndr, int ndr_flags, const struct nbt_browse_backup_list_request *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->ReqCount));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->Token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_browse_backup_list_request(struct ndr_pull *ndr, int ndr_flags, struct nbt_browse_backup_list_request *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->ReqCount));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->Token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_browse_backup_list_request(struct ndr_print *ndr, const char *name, const struct nbt_browse_backup_list_request *r)
+{
+ ndr_print_struct(ndr, name, "nbt_browse_backup_list_request");
+ ndr->depth++;
+ ndr_print_uint8(ndr, "ReqCount", r->ReqCount);
+ ndr_print_uint32(ndr, "Token", r->Token);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_browse_backup_list_response(struct ndr_push *ndr, int ndr_flags, const struct nbt_browse_backup_list_response *r)
+{
+ uint32_t cntr_BackupServerList_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->BackupCount));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->Token));
+ for (cntr_BackupServerList_0 = 0; cntr_BackupServerList_0 < r->BackupCount; cntr_BackupServerList_0++) {
+ NDR_CHECK(ndr_push_nbt_name(ndr, NDR_SCALARS, &r->BackupServerList[cntr_BackupServerList_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_browse_backup_list_response(struct ndr_pull *ndr, int ndr_flags, struct nbt_browse_backup_list_response *r)
+{
+ uint32_t cntr_BackupServerList_0;
+ TALLOC_CTX *_mem_save_BackupServerList_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->BackupCount));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->Token));
+ NDR_PULL_ALLOC_N(ndr, r->BackupServerList, r->BackupCount);
+ _mem_save_BackupServerList_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->BackupServerList, 0);
+ for (cntr_BackupServerList_0 = 0; cntr_BackupServerList_0 < r->BackupCount; cntr_BackupServerList_0++) {
+ NDR_CHECK(ndr_pull_nbt_name(ndr, NDR_SCALARS, &r->BackupServerList[cntr_BackupServerList_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_BackupServerList_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_browse_backup_list_response(struct ndr_print *ndr, const char *name, const struct nbt_browse_backup_list_response *r)
+{
+ uint32_t cntr_BackupServerList_0;
+ ndr_print_struct(ndr, name, "nbt_browse_backup_list_response");
+ ndr->depth++;
+ ndr_print_uint8(ndr, "BackupCount", r->BackupCount);
+ ndr_print_uint32(ndr, "Token", r->Token);
+ ndr->print(ndr, "%s: ARRAY(%d)", "BackupServerList", (int)r->BackupCount);
+ ndr->depth++;
+ for (cntr_BackupServerList_0=0;cntr_BackupServerList_0<r->BackupCount;cntr_BackupServerList_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_BackupServerList_0) != -1) {
+ ndr_print_nbt_name(ndr, "BackupServerList", &r->BackupServerList[cntr_BackupServerList_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_browse_become_backup(struct ndr_push *ndr, int ndr_flags, const struct nbt_browse_become_backup *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->BrowserName));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_browse_become_backup(struct ndr_pull *ndr, int ndr_flags, struct nbt_browse_become_backup *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->BrowserName));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_browse_become_backup(struct ndr_print *ndr, const char *name, const struct nbt_browse_become_backup *r)
+{
+ ndr_print_struct(ndr, name, "nbt_browse_become_backup");
+ ndr->depth++;
+ ndr_print_string(ndr, "BrowserName", r->BrowserName);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_browse_domain_announcement(struct ndr_push *ndr, int ndr_flags, const struct nbt_browse_domain_announcement *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->UpdateCount));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->Periodicity));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->ServerName, 16, sizeof(uint8_t), CH_DOS));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->OSMajor));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->OSMinor));
+ NDR_CHECK(ndr_push_svcctl_ServerType(ndr, NDR_SCALARS, r->ServerType));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->MysteriousField));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->Comment));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_browse_domain_announcement(struct ndr_pull *ndr, int ndr_flags, struct nbt_browse_domain_announcement *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->UpdateCount));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->Periodicity));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->ServerName, 16, sizeof(uint8_t), CH_DOS));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->OSMajor));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->OSMinor));
+ NDR_CHECK(ndr_pull_svcctl_ServerType(ndr, NDR_SCALARS, &r->ServerType));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->MysteriousField));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->Comment));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_browse_domain_announcement(struct ndr_print *ndr, const char *name, const struct nbt_browse_domain_announcement *r)
+{
+ ndr_print_struct(ndr, name, "nbt_browse_domain_announcement");
+ ndr->depth++;
+ ndr_print_uint8(ndr, "UpdateCount", r->UpdateCount);
+ ndr_print_uint32(ndr, "Periodicity", r->Periodicity);
+ ndr_print_string(ndr, "ServerName", r->ServerName);
+ ndr_print_uint8(ndr, "OSMajor", r->OSMajor);
+ ndr_print_uint8(ndr, "OSMinor", r->OSMinor);
+ ndr_print_svcctl_ServerType(ndr, "ServerType", r->ServerType);
+ ndr_print_uint32(ndr, "MysteriousField", r->MysteriousField);
+ ndr_print_string(ndr, "Comment", r->Comment);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_browse_master_announcement(struct ndr_push *ndr, int ndr_flags, const struct nbt_browse_master_announcement *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->ServerName));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_browse_master_announcement(struct ndr_pull *ndr, int ndr_flags, struct nbt_browse_master_announcement *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->ServerName));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_browse_master_announcement(struct ndr_print *ndr, const char *name, const struct nbt_browse_master_announcement *r)
+{
+ ndr_print_struct(ndr, name, "nbt_browse_master_announcement");
+ ndr->depth++;
+ ndr_print_string(ndr, "ServerName", r->ServerName);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_browse_reset_state(struct ndr_push *ndr, int ndr_flags, const struct nbt_browse_reset_state *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->Command));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_browse_reset_state(struct ndr_pull *ndr, int ndr_flags, struct nbt_browse_reset_state *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->Command));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_browse_reset_state(struct ndr_print *ndr, const char *name, const struct nbt_browse_reset_state *r)
+{
+ ndr_print_struct(ndr, name, "nbt_browse_reset_state");
+ ndr->depth++;
+ ndr_print_uint8(ndr, "Command", r->Command);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_browse_local_master_announcement(struct ndr_push *ndr, int ndr_flags, const struct nbt_browse_local_master_announcement *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->UpdateCount));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->Periodicity));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->ServerName, 16, sizeof(uint8_t), CH_DOS));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->OSMajor));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->OSMinor));
+ NDR_CHECK(ndr_push_svcctl_ServerType(ndr, NDR_SCALARS, r->ServerType));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->BroMajorVer));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->BroMinorVer));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->Signature));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->Comment));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_browse_local_master_announcement(struct ndr_pull *ndr, int ndr_flags, struct nbt_browse_local_master_announcement *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->UpdateCount));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->Periodicity));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->ServerName, 16, sizeof(uint8_t), CH_DOS));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->OSMajor));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->OSMinor));
+ NDR_CHECK(ndr_pull_svcctl_ServerType(ndr, NDR_SCALARS, &r->ServerType));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->BroMajorVer));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->BroMinorVer));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->Signature));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->Comment));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_browse_local_master_announcement(struct ndr_print *ndr, const char *name, const struct nbt_browse_local_master_announcement *r)
+{
+ ndr_print_struct(ndr, name, "nbt_browse_local_master_announcement");
+ ndr->depth++;
+ ndr_print_uint8(ndr, "UpdateCount", r->UpdateCount);
+ ndr_print_uint32(ndr, "Periodicity", r->Periodicity);
+ ndr_print_string(ndr, "ServerName", r->ServerName);
+ ndr_print_uint8(ndr, "OSMajor", r->OSMajor);
+ ndr_print_uint8(ndr, "OSMinor", r->OSMinor);
+ ndr_print_svcctl_ServerType(ndr, "ServerType", r->ServerType);
+ ndr_print_uint8(ndr, "BroMajorVer", r->BroMajorVer);
+ ndr_print_uint8(ndr, "BroMinorVer", r->BroMinorVer);
+ ndr_print_uint16(ndr, "Signature", r->Signature);
+ ndr_print_string(ndr, "Comment", r->Comment);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_nbt_browse_payload(struct ndr_push *ndr, int ndr_flags, const union nbt_browse_payload *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case HostAnnouncement: {
+ NDR_CHECK(ndr_push_nbt_browse_host_announcement(ndr, NDR_SCALARS, &r->host_annoucement));
+ break; }
+
+ case AnnouncementRequest: {
+ NDR_CHECK(ndr_push_nbt_browse_announcement_request(ndr, NDR_SCALARS, &r->announcement_request));
+ break; }
+
+ case Election: {
+ NDR_CHECK(ndr_push_nbt_browse_election_request(ndr, NDR_SCALARS, &r->election_request));
+ break; }
+
+ case GetBackupListReq: {
+ NDR_CHECK(ndr_push_nbt_browse_backup_list_request(ndr, NDR_SCALARS, &r->backup_list_request));
+ break; }
+
+ case GetBackupListResp: {
+ NDR_CHECK(ndr_push_nbt_browse_backup_list_response(ndr, NDR_SCALARS, &r->backup_list_response));
+ break; }
+
+ case BecomeBackup: {
+ NDR_CHECK(ndr_push_nbt_browse_become_backup(ndr, NDR_SCALARS, &r->become_backup));
+ break; }
+
+ case DomainAnnouncement: {
+ NDR_CHECK(ndr_push_nbt_browse_domain_announcement(ndr, NDR_SCALARS, &r->domain_announcement));
+ break; }
+
+ case MasterAnnouncement: {
+ NDR_CHECK(ndr_push_nbt_browse_master_announcement(ndr, NDR_SCALARS, &r->master_announcement));
+ break; }
+
+ case ResetBrowserState: {
+ NDR_CHECK(ndr_push_nbt_browse_reset_state(ndr, NDR_SCALARS, &r->reset_browser_state));
+ break; }
+
+ case LocalMasterAnnouncement: {
+ NDR_CHECK(ndr_push_nbt_browse_local_master_announcement(ndr, NDR_SCALARS, &r->local_master_announcement));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case HostAnnouncement:
+ break;
+
+ case AnnouncementRequest:
+ break;
+
+ case Election:
+ break;
+
+ case GetBackupListReq:
+ break;
+
+ case GetBackupListResp:
+ break;
+
+ case BecomeBackup:
+ break;
+
+ case DomainAnnouncement:
+ break;
+
+ case MasterAnnouncement:
+ break;
+
+ case ResetBrowserState:
+ break;
+
+ case LocalMasterAnnouncement:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_nbt_browse_payload(struct ndr_pull *ndr, int ndr_flags, union nbt_browse_payload *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case HostAnnouncement: {
+ NDR_CHECK(ndr_pull_nbt_browse_host_announcement(ndr, NDR_SCALARS, &r->host_annoucement));
+ break; }
+
+ case AnnouncementRequest: {
+ NDR_CHECK(ndr_pull_nbt_browse_announcement_request(ndr, NDR_SCALARS, &r->announcement_request));
+ break; }
+
+ case Election: {
+ NDR_CHECK(ndr_pull_nbt_browse_election_request(ndr, NDR_SCALARS, &r->election_request));
+ break; }
+
+ case GetBackupListReq: {
+ NDR_CHECK(ndr_pull_nbt_browse_backup_list_request(ndr, NDR_SCALARS, &r->backup_list_request));
+ break; }
+
+ case GetBackupListResp: {
+ NDR_CHECK(ndr_pull_nbt_browse_backup_list_response(ndr, NDR_SCALARS, &r->backup_list_response));
+ break; }
+
+ case BecomeBackup: {
+ NDR_CHECK(ndr_pull_nbt_browse_become_backup(ndr, NDR_SCALARS, &r->become_backup));
+ break; }
+
+ case DomainAnnouncement: {
+ NDR_CHECK(ndr_pull_nbt_browse_domain_announcement(ndr, NDR_SCALARS, &r->domain_announcement));
+ break; }
+
+ case MasterAnnouncement: {
+ NDR_CHECK(ndr_pull_nbt_browse_master_announcement(ndr, NDR_SCALARS, &r->master_announcement));
+ break; }
+
+ case ResetBrowserState: {
+ NDR_CHECK(ndr_pull_nbt_browse_reset_state(ndr, NDR_SCALARS, &r->reset_browser_state));
+ break; }
+
+ case LocalMasterAnnouncement: {
+ NDR_CHECK(ndr_pull_nbt_browse_local_master_announcement(ndr, NDR_SCALARS, &r->local_master_announcement));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case HostAnnouncement:
+ break;
+
+ case AnnouncementRequest:
+ break;
+
+ case Election:
+ break;
+
+ case GetBackupListReq:
+ break;
+
+ case GetBackupListResp:
+ break;
+
+ case BecomeBackup:
+ break;
+
+ case DomainAnnouncement:
+ break;
+
+ case MasterAnnouncement:
+ break;
+
+ case ResetBrowserState:
+ break;
+
+ case LocalMasterAnnouncement:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_browse_payload(struct ndr_print *ndr, const char *name, const union nbt_browse_payload *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "nbt_browse_payload");
+ switch (level) {
+ case HostAnnouncement:
+ ndr_print_nbt_browse_host_announcement(ndr, "host_annoucement", &r->host_annoucement);
+ break;
+
+ case AnnouncementRequest:
+ ndr_print_nbt_browse_announcement_request(ndr, "announcement_request", &r->announcement_request);
+ break;
+
+ case Election:
+ ndr_print_nbt_browse_election_request(ndr, "election_request", &r->election_request);
+ break;
+
+ case GetBackupListReq:
+ ndr_print_nbt_browse_backup_list_request(ndr, "backup_list_request", &r->backup_list_request);
+ break;
+
+ case GetBackupListResp:
+ ndr_print_nbt_browse_backup_list_response(ndr, "backup_list_response", &r->backup_list_response);
+ break;
+
+ case BecomeBackup:
+ ndr_print_nbt_browse_become_backup(ndr, "become_backup", &r->become_backup);
+ break;
+
+ case DomainAnnouncement:
+ ndr_print_nbt_browse_domain_announcement(ndr, "domain_announcement", &r->domain_announcement);
+ break;
+
+ case MasterAnnouncement:
+ ndr_print_nbt_browse_master_announcement(ndr, "master_announcement", &r->master_announcement);
+ break;
+
+ case ResetBrowserState:
+ ndr_print_nbt_browse_reset_state(ndr, "reset_browser_state", &r->reset_browser_state);
+ break;
+
+ case LocalMasterAnnouncement:
+ ndr_print_nbt_browse_local_master_announcement(ndr, "local_master_announcement", &r->local_master_announcement);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_browse_packet(struct ndr_push *ndr, int ndr_flags, const struct nbt_browse_packet *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_nbt_browse_opcode(ndr, NDR_SCALARS, r->opcode));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->payload, r->opcode));
+ NDR_CHECK(ndr_push_nbt_browse_payload(ndr, NDR_SCALARS, &r->payload));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_browse_packet(struct ndr_pull *ndr, int ndr_flags, struct nbt_browse_packet *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_nbt_browse_opcode(ndr, NDR_SCALARS, &r->opcode));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->payload, r->opcode));
+ NDR_CHECK(ndr_pull_nbt_browse_payload(ndr, NDR_SCALARS, &r->payload));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_nbt_browse_packet(struct ndr_print *ndr, const char *name, const struct nbt_browse_packet *r)
+{
+ ndr_print_struct(ndr, name, "nbt_browse_packet");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ ndr->depth++;
+ ndr_print_nbt_browse_opcode(ndr, "opcode", r->opcode);
+ ndr_print_set_switch_value(ndr, &r->payload, r->opcode);
+ ndr_print_nbt_browse_payload(ndr, "payload", &r->payload);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
diff --git a/source3/librpc/gen_ndr/ndr_nbt.h b/source3/librpc/gen_ndr/ndr_nbt.h
new file mode 100644
index 0000000000..6e9702d5d5
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_nbt.h
@@ -0,0 +1,97 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/nbt.h"
+
+#ifndef _HEADER_NDR_nbt
+#define _HEADER_NDR_nbt
+
+#include "libcli/nbt/libnbt.h"
+#define NDR_NBT_CALL_COUNT (0)
+void ndr_print_nbt_operation(struct ndr_print *ndr, const char *name, uint16_t r);
+void ndr_print_nbt_name_type(struct ndr_print *ndr, const char *name, enum nbt_name_type r);
+enum ndr_err_code ndr_push_nbt_name(struct ndr_push *ndr, int ndr_flags, const struct nbt_name *r);
+enum ndr_err_code ndr_pull_nbt_name(struct ndr_pull *ndr, int ndr_flags, struct nbt_name *r);
+void ndr_print_nbt_name(struct ndr_print *ndr, const char *name, const struct nbt_name *r);
+void ndr_print_nbt_qclass(struct ndr_print *ndr, const char *name, enum nbt_qclass r);
+void ndr_print_nbt_qtype(struct ndr_print *ndr, const char *name, enum nbt_qtype r);
+void ndr_print_nbt_name_question(struct ndr_print *ndr, const char *name, const struct nbt_name_question *r);
+void ndr_print_nb_flags(struct ndr_print *ndr, const char *name, uint16_t r);
+void ndr_print_nbt_rdata_address(struct ndr_print *ndr, const char *name, const struct nbt_rdata_address *r);
+void ndr_print_nbt_rdata_netbios(struct ndr_print *ndr, const char *name, const struct nbt_rdata_netbios *r);
+void ndr_print_nbt_statistics(struct ndr_print *ndr, const char *name, const struct nbt_statistics *r);
+void ndr_print_nbt_status_name(struct ndr_print *ndr, const char *name, const struct nbt_status_name *r);
+void ndr_print_nbt_rdata_status(struct ndr_print *ndr, const char *name, const struct nbt_rdata_status *r);
+void ndr_print_nbt_rdata_data(struct ndr_print *ndr, const char *name, const struct nbt_rdata_data *r);
+void ndr_print_nbt_rdata(struct ndr_print *ndr, const char *name, const union nbt_rdata *r);
+void ndr_print_nbt_res_rec(struct ndr_print *ndr, const char *name, const struct nbt_res_rec *r);
+enum ndr_err_code ndr_push_nbt_name_packet(struct ndr_push *ndr, int ndr_flags, const struct nbt_name_packet *r);
+enum ndr_err_code ndr_pull_nbt_name_packet(struct ndr_pull *ndr, int ndr_flags, struct nbt_name_packet *r);
+void ndr_print_nbt_name_packet(struct ndr_print *ndr, const char *name, const struct nbt_name_packet *r);
+void ndr_print_dgram_msg_type(struct ndr_print *ndr, const char *name, enum dgram_msg_type r);
+void ndr_print_dgram_flags(struct ndr_print *ndr, const char *name, uint8_t r);
+void ndr_print_smb_command(struct ndr_print *ndr, const char *name, enum smb_command r);
+void ndr_print_smb_trans_body(struct ndr_print *ndr, const char *name, const struct smb_trans_body *r);
+void ndr_print_smb_body(struct ndr_print *ndr, const char *name, const union smb_body *r);
+enum ndr_err_code ndr_push_dgram_smb_packet(struct ndr_push *ndr, int ndr_flags, const struct dgram_smb_packet *r);
+enum ndr_err_code ndr_pull_dgram_smb_packet(struct ndr_pull *ndr, int ndr_flags, struct dgram_smb_packet *r);
+void ndr_print_dgram_smb_packet(struct ndr_print *ndr, const char *name, const struct dgram_smb_packet *r);
+void ndr_print_dgram_message_body(struct ndr_print *ndr, const char *name, const union dgram_message_body *r);
+void ndr_print_dgram_message(struct ndr_print *ndr, const char *name, const struct dgram_message *r);
+void ndr_print_dgram_err_code(struct ndr_print *ndr, const char *name, enum dgram_err_code r);
+void ndr_print_dgram_data(struct ndr_print *ndr, const char *name, const union dgram_data *r);
+enum ndr_err_code ndr_push_nbt_dgram_packet(struct ndr_push *ndr, int ndr_flags, const struct nbt_dgram_packet *r);
+enum ndr_err_code ndr_pull_nbt_dgram_packet(struct ndr_pull *ndr, int ndr_flags, struct nbt_dgram_packet *r);
+void ndr_print_nbt_dgram_packet(struct ndr_print *ndr, const char *name, const struct nbt_dgram_packet *r);
+void ndr_print_nbt_netlogon_command(struct ndr_print *ndr, const char *name, enum nbt_netlogon_command r);
+void ndr_print_nbt_netlogon_version(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_nbt_netlogon_query_for_pdc(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_query_for_pdc *r);
+void ndr_print_nbt_netlogon_query_for_pdc2(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_query_for_pdc2 *r);
+void ndr_print_nbt_netlogon_response_from_pdc(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_response_from_pdc *r);
+void ndr_print_nbt_server_type(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_nbt_dc_sock_addr(struct ndr_print *ndr, const char *name, const struct nbt_dc_sock_addr *r);
+void ndr_print_nbt_netlogon_response_from_pdc2(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_response_from_pdc2 *r);
+void ndr_print_nbt_db_change(struct ndr_print *ndr, const char *name, const struct nbt_db_change *r);
+void ndr_print_nbt_netlogon_announce_uas(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_announce_uas *r);
+void ndr_print_nbt_netlogon_request(struct ndr_print *ndr, const char *name, const union nbt_netlogon_request *r);
+enum ndr_err_code ndr_push_nbt_netlogon_packet(struct ndr_push *ndr, int ndr_flags, const struct nbt_netlogon_packet *r);
+enum ndr_err_code ndr_pull_nbt_netlogon_packet(struct ndr_pull *ndr, int ndr_flags, struct nbt_netlogon_packet *r);
+void ndr_print_nbt_netlogon_packet(struct ndr_print *ndr, const char *name, const struct nbt_netlogon_packet *r);
+void ndr_print_nbt_cldap_netlogon_1(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_1 *r);
+void ndr_print_nbt_cldap_netlogon_3(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_3 *r);
+enum ndr_err_code ndr_push_nbt_cldap_netlogon_5(struct ndr_push *ndr, int ndr_flags, const struct nbt_cldap_netlogon_5 *r);
+enum ndr_err_code ndr_pull_nbt_cldap_netlogon_5(struct ndr_pull *ndr, int ndr_flags, struct nbt_cldap_netlogon_5 *r);
+void ndr_print_nbt_cldap_netlogon_5(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_5 *r);
+void ndr_print_nbt_cldap_netlogon_13(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_13 *r);
+enum ndr_err_code ndr_push_nbt_cldap_netlogon_15(struct ndr_push *ndr, int ndr_flags, const struct nbt_cldap_netlogon_15 *r);
+enum ndr_err_code ndr_pull_nbt_cldap_netlogon_15(struct ndr_pull *ndr, int ndr_flags, struct nbt_cldap_netlogon_15 *r);
+void ndr_print_nbt_cldap_netlogon_15(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_15 *r);
+enum ndr_err_code ndr_push_nbt_cldap_netlogon_29(struct ndr_push *ndr, int ndr_flags, const struct nbt_cldap_netlogon_29 *r);
+enum ndr_err_code ndr_pull_nbt_cldap_netlogon_29(struct ndr_pull *ndr, int ndr_flags, struct nbt_cldap_netlogon_29 *r);
+void ndr_print_nbt_cldap_netlogon_29(struct ndr_print *ndr, const char *name, const struct nbt_cldap_netlogon_29 *r);
+enum ndr_err_code ndr_push_nbt_cldap_netlogon(struct ndr_push *ndr, int ndr_flags, const union nbt_cldap_netlogon *r);
+enum ndr_err_code ndr_pull_nbt_cldap_netlogon(struct ndr_pull *ndr, int ndr_flags, union nbt_cldap_netlogon *r);
+void ndr_print_nbt_cldap_netlogon(struct ndr_print *ndr, const char *name, const union nbt_cldap_netlogon *r);
+void ndr_print_nbt_ntlogon_command(struct ndr_print *ndr, const char *name, enum nbt_ntlogon_command r);
+void ndr_print_nbt_ntlogon_sam_logon(struct ndr_print *ndr, const char *name, const struct nbt_ntlogon_sam_logon *r);
+void ndr_print_nbt_ntlogon_sam_logon_reply(struct ndr_print *ndr, const char *name, const struct nbt_ntlogon_sam_logon_reply *r);
+void ndr_print_nbt_ntlogon_request(struct ndr_print *ndr, const char *name, const union nbt_ntlogon_request *r);
+enum ndr_err_code ndr_push_nbt_ntlogon_packet(struct ndr_push *ndr, int ndr_flags, const struct nbt_ntlogon_packet *r);
+enum ndr_err_code ndr_pull_nbt_ntlogon_packet(struct ndr_pull *ndr, int ndr_flags, struct nbt_ntlogon_packet *r);
+void ndr_print_nbt_ntlogon_packet(struct ndr_print *ndr, const char *name, const struct nbt_ntlogon_packet *r);
+void ndr_print_nbt_browse_opcode(struct ndr_print *ndr, const char *name, enum nbt_browse_opcode r);
+void ndr_print_nbt_browse_host_announcement(struct ndr_print *ndr, const char *name, const struct nbt_browse_host_announcement *r);
+void ndr_print_nbt_browse_announcement_request(struct ndr_print *ndr, const char *name, const struct nbt_browse_announcement_request *r);
+void ndr_print_nbt_browse_election_request(struct ndr_print *ndr, const char *name, const struct nbt_browse_election_request *r);
+void ndr_print_nbt_browse_backup_list_request(struct ndr_print *ndr, const char *name, const struct nbt_browse_backup_list_request *r);
+void ndr_print_nbt_browse_backup_list_response(struct ndr_print *ndr, const char *name, const struct nbt_browse_backup_list_response *r);
+void ndr_print_nbt_browse_become_backup(struct ndr_print *ndr, const char *name, const struct nbt_browse_become_backup *r);
+void ndr_print_nbt_browse_domain_announcement(struct ndr_print *ndr, const char *name, const struct nbt_browse_domain_announcement *r);
+void ndr_print_nbt_browse_master_announcement(struct ndr_print *ndr, const char *name, const struct nbt_browse_master_announcement *r);
+void ndr_print_nbt_browse_reset_state(struct ndr_print *ndr, const char *name, const struct nbt_browse_reset_state *r);
+void ndr_print_nbt_browse_local_master_announcement(struct ndr_print *ndr, const char *name, const struct nbt_browse_local_master_announcement *r);
+void ndr_print_nbt_browse_payload(struct ndr_print *ndr, const char *name, const union nbt_browse_payload *r);
+enum ndr_err_code ndr_push_nbt_browse_packet(struct ndr_push *ndr, int ndr_flags, const struct nbt_browse_packet *r);
+enum ndr_err_code ndr_pull_nbt_browse_packet(struct ndr_pull *ndr, int ndr_flags, struct nbt_browse_packet *r);
+void ndr_print_nbt_browse_packet(struct ndr_print *ndr, const char *name, const struct nbt_browse_packet *r);
+#endif /* _HEADER_NDR_nbt */
diff --git a/source3/librpc/gen_ndr/ndr_netlogon.c b/source3/librpc/gen_ndr/ndr_netlogon.c
new file mode 100644
index 0000000000..b43a157997
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_netlogon.c
@@ -0,0 +1,15131 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+
+#include "librpc/gen_ndr/ndr_lsa.h"
+#include "librpc/gen_ndr/ndr_samr.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+static enum ndr_err_code ndr_push_netr_UasInfo(struct ndr_push *ndr, int ndr_flags, const struct netr_UasInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->account_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->priv));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->auth_flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->logon_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->bad_pw_count));
+ NDR_CHECK(ndr_push_time_t(ndr, NDR_SCALARS, r->last_logon));
+ NDR_CHECK(ndr_push_time_t(ndr, NDR_SCALARS, r->last_logoff));
+ NDR_CHECK(ndr_push_time_t(ndr, NDR_SCALARS, r->logoff_time));
+ NDR_CHECK(ndr_push_time_t(ndr, NDR_SCALARS, r->kickoff_time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->password_age));
+ NDR_CHECK(ndr_push_time_t(ndr, NDR_SCALARS, r->pw_can_change));
+ NDR_CHECK(ndr_push_time_t(ndr, NDR_SCALARS, r->pw_must_change));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->computer));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->script_path));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->account_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->account_name, ndr_charset_length(r->account_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->computer) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->computer, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->computer, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->computer, ndr_charset_length(r->computer, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->domain) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain, ndr_charset_length(r->domain, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->script_path) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->script_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->script_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->script_path, ndr_charset_length(r->script_path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_UasInfo(struct ndr_pull *ndr, int ndr_flags, struct netr_UasInfo *r)
+{
+ uint32_t _ptr_account_name;
+ TALLOC_CTX *_mem_save_account_name_0;
+ uint32_t _ptr_computer;
+ TALLOC_CTX *_mem_save_computer_0;
+ uint32_t _ptr_domain;
+ TALLOC_CTX *_mem_save_domain_0;
+ uint32_t _ptr_script_path;
+ TALLOC_CTX *_mem_save_script_path_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_account_name));
+ if (_ptr_account_name) {
+ NDR_PULL_ALLOC(ndr, r->account_name);
+ } else {
+ r->account_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->priv));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->auth_flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->logon_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->bad_pw_count));
+ NDR_CHECK(ndr_pull_time_t(ndr, NDR_SCALARS, &r->last_logon));
+ NDR_CHECK(ndr_pull_time_t(ndr, NDR_SCALARS, &r->last_logoff));
+ NDR_CHECK(ndr_pull_time_t(ndr, NDR_SCALARS, &r->logoff_time));
+ NDR_CHECK(ndr_pull_time_t(ndr, NDR_SCALARS, &r->kickoff_time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->password_age));
+ NDR_CHECK(ndr_pull_time_t(ndr, NDR_SCALARS, &r->pw_can_change));
+ NDR_CHECK(ndr_pull_time_t(ndr, NDR_SCALARS, &r->pw_must_change));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_computer));
+ if (_ptr_computer) {
+ NDR_PULL_ALLOC(ndr, r->computer);
+ } else {
+ r->computer = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain));
+ if (_ptr_domain) {
+ NDR_PULL_ALLOC(ndr, r->domain);
+ } else {
+ r->domain = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_script_path));
+ if (_ptr_script_path) {
+ NDR_PULL_ALLOC(ndr, r->script_path);
+ } else {
+ r->script_path = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->account_name) {
+ _mem_save_account_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->account_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->account_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->account_name));
+ if (ndr_get_array_length(ndr, &r->account_name) > ndr_get_array_size(ndr, &r->account_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->account_name), ndr_get_array_length(ndr, &r->account_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->account_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->account_name, ndr_get_array_length(ndr, &r->account_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_account_name_0, 0);
+ }
+ if (r->computer) {
+ _mem_save_computer_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->computer, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->computer));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->computer));
+ if (ndr_get_array_length(ndr, &r->computer) > ndr_get_array_size(ndr, &r->computer)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->computer), ndr_get_array_length(ndr, &r->computer));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->computer), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->computer, ndr_get_array_length(ndr, &r->computer), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_computer_0, 0);
+ }
+ if (r->domain) {
+ _mem_save_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain));
+ if (ndr_get_array_length(ndr, &r->domain) > ndr_get_array_size(ndr, &r->domain)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain), ndr_get_array_length(ndr, &r->domain));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_0, 0);
+ }
+ if (r->script_path) {
+ _mem_save_script_path_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->script_path, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->script_path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->script_path));
+ if (ndr_get_array_length(ndr, &r->script_path) > ndr_get_array_size(ndr, &r->script_path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->script_path), ndr_get_array_length(ndr, &r->script_path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->script_path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->script_path, ndr_get_array_length(ndr, &r->script_path), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_script_path_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_UasInfo(struct ndr_print *ndr, const char *name, const struct netr_UasInfo *r)
+{
+ ndr_print_struct(ndr, name, "netr_UasInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "account_name", r->account_name);
+ ndr->depth++;
+ if (r->account_name) {
+ ndr_print_string(ndr, "account_name", r->account_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "priv", r->priv);
+ ndr_print_uint32(ndr, "auth_flags", r->auth_flags);
+ ndr_print_uint32(ndr, "logon_count", r->logon_count);
+ ndr_print_uint32(ndr, "bad_pw_count", r->bad_pw_count);
+ ndr_print_time_t(ndr, "last_logon", r->last_logon);
+ ndr_print_time_t(ndr, "last_logoff", r->last_logoff);
+ ndr_print_time_t(ndr, "logoff_time", r->logoff_time);
+ ndr_print_time_t(ndr, "kickoff_time", r->kickoff_time);
+ ndr_print_uint32(ndr, "password_age", r->password_age);
+ ndr_print_time_t(ndr, "pw_can_change", r->pw_can_change);
+ ndr_print_time_t(ndr, "pw_must_change", r->pw_must_change);
+ ndr_print_ptr(ndr, "computer", r->computer);
+ ndr->depth++;
+ if (r->computer) {
+ ndr_print_string(ndr, "computer", r->computer);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain", r->domain);
+ ndr->depth++;
+ if (r->domain) {
+ ndr_print_string(ndr, "domain", r->domain);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "script_path", r->script_path);
+ ndr->depth++;
+ if (r->script_path) {
+ ndr_print_string(ndr, "script_path", r->script_path);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown", r->unknown);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_UasLogoffInfo(struct ndr_push *ndr, int ndr_flags, const struct netr_UasLogoffInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->duration));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->logon_count));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_UasLogoffInfo(struct ndr_pull *ndr, int ndr_flags, struct netr_UasLogoffInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->duration));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->logon_count));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_UasLogoffInfo(struct ndr_print *ndr, const char *name, const struct netr_UasLogoffInfo *r)
+{
+ ndr_print_struct(ndr, name, "netr_UasLogoffInfo");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "duration", r->duration);
+ ndr_print_uint16(ndr, "logon_count", r->logon_count);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_AcctLockStr(struct ndr_push *ndr, int ndr_flags, const struct netr_AcctLockStr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_dlong(ndr, NDR_SCALARS, r->lockout_duration));
+ NDR_CHECK(ndr_push_udlong(ndr, NDR_SCALARS, r->reset_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->bad_attempt_lockout));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->dummy));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_AcctLockStr(struct ndr_pull *ndr, int ndr_flags, struct netr_AcctLockStr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_dlong(ndr, NDR_SCALARS, &r->lockout_duration));
+ NDR_CHECK(ndr_pull_udlong(ndr, NDR_SCALARS, &r->reset_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->bad_attempt_lockout));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->dummy));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_AcctLockStr(struct ndr_print *ndr, const char *name, const struct netr_AcctLockStr *r)
+{
+ ndr_print_struct(ndr, name, "netr_AcctLockStr");
+ ndr->depth++;
+ ndr_print_dlong(ndr, "lockout_duration", r->lockout_duration);
+ ndr_print_udlong(ndr, "reset_count", r->reset_count);
+ ndr_print_uint32(ndr, "bad_attempt_lockout", r->bad_attempt_lockout);
+ ndr_print_uint32(ndr, "dummy", r->dummy);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_LogonParameterControl(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_LogonParameterControl(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_LogonParameterControl(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "MSV1_0_CLEARTEXT_PASSWORD_ALLOWED", MSV1_0_CLEARTEXT_PASSWORD_ALLOWED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "MSV1_0_UPDATE_LOGON_STATISTICS", MSV1_0_UPDATE_LOGON_STATISTICS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "MSV1_0_RETURN_USER_PARAMETERS", MSV1_0_RETURN_USER_PARAMETERS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT", MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "MSV1_0_RETURN_PROFILE_PATH", MSV1_0_RETURN_PROFILE_PATH, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT", MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_IdentityInfo(struct ndr_push *ndr, int ndr_flags, const struct netr_IdentityInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->domain_name));
+ NDR_CHECK(ndr_push_netr_LogonParameterControl(ndr, NDR_SCALARS, r->parameter_control));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->logon_id_low));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->logon_id_high));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->workstation));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->domain_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->workstation));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_IdentityInfo(struct ndr_pull *ndr, int ndr_flags, struct netr_IdentityInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->domain_name));
+ NDR_CHECK(ndr_pull_netr_LogonParameterControl(ndr, NDR_SCALARS, &r->parameter_control));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->logon_id_low));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->logon_id_high));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->workstation));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->domain_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->workstation));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_IdentityInfo(struct ndr_print *ndr, const char *name, const struct netr_IdentityInfo *r)
+{
+ ndr_print_struct(ndr, name, "netr_IdentityInfo");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "domain_name", &r->domain_name);
+ ndr_print_netr_LogonParameterControl(ndr, "parameter_control", r->parameter_control);
+ ndr_print_uint32(ndr, "logon_id_low", r->logon_id_low);
+ ndr_print_uint32(ndr, "logon_id_high", r->logon_id_high);
+ ndr_print_lsa_String(ndr, "account_name", &r->account_name);
+ ndr_print_lsa_String(ndr, "workstation", &r->workstation);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_PasswordInfo(struct ndr_push *ndr, int ndr_flags, const struct netr_PasswordInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netr_IdentityInfo(ndr, NDR_SCALARS, &r->identity_info));
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, &r->lmpassword));
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, &r->ntpassword));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_netr_IdentityInfo(ndr, NDR_BUFFERS, &r->identity_info));
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_BUFFERS, &r->lmpassword));
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_BUFFERS, &r->ntpassword));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_PasswordInfo(struct ndr_pull *ndr, int ndr_flags, struct netr_PasswordInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netr_IdentityInfo(ndr, NDR_SCALARS, &r->identity_info));
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, &r->lmpassword));
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, &r->ntpassword));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_netr_IdentityInfo(ndr, NDR_BUFFERS, &r->identity_info));
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_BUFFERS, &r->lmpassword));
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_BUFFERS, &r->ntpassword));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_PasswordInfo(struct ndr_print *ndr, const char *name, const struct netr_PasswordInfo *r)
+{
+ ndr_print_struct(ndr, name, "netr_PasswordInfo");
+ ndr->depth++;
+ ndr_print_netr_IdentityInfo(ndr, "identity_info", &r->identity_info);
+ ndr_print_samr_Password(ndr, "lmpassword", &r->lmpassword);
+ ndr_print_samr_Password(ndr, "ntpassword", &r->ntpassword);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_ChallengeResponse(struct ndr_push *ndr, int ndr_flags, const struct netr_ChallengeResponse *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data, r->length));
+ }
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_ChallengeResponse(struct ndr_pull *ndr, int ndr_flags, struct netr_ChallengeResponse *r)
+{
+ uint32_t _ptr_data;
+ TALLOC_CTX *_mem_save_data_0;
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data));
+ if (_ptr_data) {
+ NDR_PULL_ALLOC(ndr, r->data);
+ } else {
+ r->data = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->data, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->data));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->data));
+ if (ndr_get_array_length(ndr, &r->data) > ndr_get_array_size(ndr, &r->data)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->data), ndr_get_array_length(ndr, &r->data));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->data, ndr_get_array_size(ndr, &r->data));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data, ndr_get_array_length(ndr, &r->data)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, 0);
+ }
+ if (r->data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->data, r->length));
+ }
+ if (r->data) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->data, r->length));
+ }
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_ChallengeResponse(struct ndr_print *ndr, const char *name, const struct netr_ChallengeResponse *r)
+{
+ ndr_print_struct(ndr, name, "netr_ChallengeResponse");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_uint16(ndr, "length", r->length);
+ ndr_print_uint16(ndr, "size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?r->length:r->size);
+ ndr_print_ptr(ndr, "data", r->data);
+ ndr->depth++;
+ if (r->data) {
+ ndr_print_array_uint8(ndr, "data", r->data, r->length);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_netr_NetworkInfo(struct ndr_push *ndr, int ndr_flags, const struct netr_NetworkInfo *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netr_IdentityInfo(ndr, NDR_SCALARS, &r->identity_info));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->challenge, 8));
+ NDR_CHECK(ndr_push_netr_ChallengeResponse(ndr, NDR_SCALARS, &r->nt));
+ NDR_CHECK(ndr_push_netr_ChallengeResponse(ndr, NDR_SCALARS, &r->lm));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_netr_IdentityInfo(ndr, NDR_BUFFERS, &r->identity_info));
+ NDR_CHECK(ndr_push_netr_ChallengeResponse(ndr, NDR_BUFFERS, &r->nt));
+ NDR_CHECK(ndr_push_netr_ChallengeResponse(ndr, NDR_BUFFERS, &r->lm));
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_NetworkInfo(struct ndr_pull *ndr, int ndr_flags, struct netr_NetworkInfo *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netr_IdentityInfo(ndr, NDR_SCALARS, &r->identity_info));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->challenge, 8));
+ NDR_CHECK(ndr_pull_netr_ChallengeResponse(ndr, NDR_SCALARS, &r->nt));
+ NDR_CHECK(ndr_pull_netr_ChallengeResponse(ndr, NDR_SCALARS, &r->lm));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_netr_IdentityInfo(ndr, NDR_BUFFERS, &r->identity_info));
+ NDR_CHECK(ndr_pull_netr_ChallengeResponse(ndr, NDR_BUFFERS, &r->nt));
+ NDR_CHECK(ndr_pull_netr_ChallengeResponse(ndr, NDR_BUFFERS, &r->lm));
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_NetworkInfo(struct ndr_print *ndr, const char *name, const struct netr_NetworkInfo *r)
+{
+ ndr_print_struct(ndr, name, "netr_NetworkInfo");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_netr_IdentityInfo(ndr, "identity_info", &r->identity_info);
+ ndr_print_array_uint8(ndr, "challenge", r->challenge, 8);
+ ndr_print_netr_ChallengeResponse(ndr, "nt", &r->nt);
+ ndr_print_netr_ChallengeResponse(ndr, "lm", &r->lm);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_LogonInfo(struct ndr_push *ndr, int ndr_flags, const union netr_LogonInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->password));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->network));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->password));
+ break; }
+
+ case 5: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->password));
+ break; }
+
+ case 6: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->network));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ if (r->password) {
+ NDR_CHECK(ndr_push_netr_PasswordInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->password));
+ }
+ break;
+
+ case 2:
+ if (r->network) {
+ NDR_CHECK(ndr_push_netr_NetworkInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->network));
+ }
+ break;
+
+ case 3:
+ if (r->password) {
+ NDR_CHECK(ndr_push_netr_PasswordInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->password));
+ }
+ break;
+
+ case 5:
+ if (r->password) {
+ NDR_CHECK(ndr_push_netr_PasswordInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->password));
+ }
+ break;
+
+ case 6:
+ if (r->network) {
+ NDR_CHECK(ndr_push_netr_NetworkInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->network));
+ }
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_LogonInfo(struct ndr_pull *ndr, int ndr_flags, union netr_LogonInfo *r)
+{
+ int level;
+ uint16_t _level;
+ TALLOC_CTX *_mem_save_password_0;
+ TALLOC_CTX *_mem_save_network_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ uint32_t _ptr_password;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password));
+ if (_ptr_password) {
+ NDR_PULL_ALLOC(ndr, r->password);
+ } else {
+ r->password = NULL;
+ }
+ break; }
+
+ case 2: {
+ uint32_t _ptr_network;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_network));
+ if (_ptr_network) {
+ NDR_PULL_ALLOC(ndr, r->network);
+ } else {
+ r->network = NULL;
+ }
+ break; }
+
+ case 3: {
+ uint32_t _ptr_password;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password));
+ if (_ptr_password) {
+ NDR_PULL_ALLOC(ndr, r->password);
+ } else {
+ r->password = NULL;
+ }
+ break; }
+
+ case 5: {
+ uint32_t _ptr_password;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password));
+ if (_ptr_password) {
+ NDR_PULL_ALLOC(ndr, r->password);
+ } else {
+ r->password = NULL;
+ }
+ break; }
+
+ case 6: {
+ uint32_t _ptr_network;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_network));
+ if (_ptr_network) {
+ NDR_PULL_ALLOC(ndr, r->network);
+ } else {
+ r->network = NULL;
+ }
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ if (r->password) {
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->password, 0);
+ NDR_CHECK(ndr_pull_netr_PasswordInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->password));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, 0);
+ }
+ break;
+
+ case 2:
+ if (r->network) {
+ _mem_save_network_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->network, 0);
+ NDR_CHECK(ndr_pull_netr_NetworkInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->network));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_network_0, 0);
+ }
+ break;
+
+ case 3:
+ if (r->password) {
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->password, 0);
+ NDR_CHECK(ndr_pull_netr_PasswordInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->password));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, 0);
+ }
+ break;
+
+ case 5:
+ if (r->password) {
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->password, 0);
+ NDR_CHECK(ndr_pull_netr_PasswordInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->password));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, 0);
+ }
+ break;
+
+ case 6:
+ if (r->network) {
+ _mem_save_network_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->network, 0);
+ NDR_CHECK(ndr_pull_netr_NetworkInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->network));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_network_0, 0);
+ }
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_LogonInfo(struct ndr_print *ndr, const char *name, const union netr_LogonInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "netr_LogonInfo");
+ switch (level) {
+ case 1:
+ ndr_print_ptr(ndr, "password", r->password);
+ ndr->depth++;
+ if (r->password) {
+ ndr_print_netr_PasswordInfo(ndr, "password", r->password);
+ }
+ ndr->depth--;
+ break;
+
+ case 2:
+ ndr_print_ptr(ndr, "network", r->network);
+ ndr->depth++;
+ if (r->network) {
+ ndr_print_netr_NetworkInfo(ndr, "network", r->network);
+ }
+ ndr->depth--;
+ break;
+
+ case 3:
+ ndr_print_ptr(ndr, "password", r->password);
+ ndr->depth++;
+ if (r->password) {
+ ndr_print_netr_PasswordInfo(ndr, "password", r->password);
+ }
+ ndr->depth--;
+ break;
+
+ case 5:
+ ndr_print_ptr(ndr, "password", r->password);
+ ndr->depth++;
+ if (r->password) {
+ ndr_print_netr_PasswordInfo(ndr, "password", r->password);
+ }
+ ndr->depth--;
+ break;
+
+ case 6:
+ ndr_print_ptr(ndr, "network", r->network);
+ ndr->depth++;
+ if (r->network) {
+ ndr_print_netr_NetworkInfo(ndr, "network", r->network);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_UserSessionKey(struct ndr_push *ndr, int ndr_flags, const struct netr_UserSessionKey *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->key, 16));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_UserSessionKey(struct ndr_pull *ndr, int ndr_flags, struct netr_UserSessionKey *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->key, 16));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_UserSessionKey(struct ndr_print *ndr, const char *name, const struct netr_UserSessionKey *r)
+{
+ ndr_print_struct(ndr, name, "netr_UserSessionKey");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "key", r->key, 16);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_LMSessionKey(struct ndr_push *ndr, int ndr_flags, const struct netr_LMSessionKey *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->key, 8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_LMSessionKey(struct ndr_pull *ndr, int ndr_flags, struct netr_LMSessionKey *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->key, 8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_LMSessionKey(struct ndr_print *ndr, const char *name, const struct netr_LMSessionKey *r)
+{
+ ndr_print_struct(ndr, name, "netr_LMSessionKey");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "key", r->key, 8);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_UserFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_UserFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_UserFlags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_GUEST", NETLOGON_GUEST, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NOENCRYPTION", NETLOGON_NOENCRYPTION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_CACHED_ACCOUNT", NETLOGON_CACHED_ACCOUNT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_USED_LM_PASSWORD", NETLOGON_USED_LM_PASSWORD, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_EXTRA_SIDS", NETLOGON_EXTRA_SIDS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_SUBAUTH_SESSION_KEY", NETLOGON_SUBAUTH_SESSION_KEY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_SERVER_TRUST_ACCOUNT", NETLOGON_SERVER_TRUST_ACCOUNT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NTLMV2_ENABLED", NETLOGON_NTLMV2_ENABLED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_RESOURCE_GROUPS", NETLOGON_RESOURCE_GROUPS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_PROFILE_PATH_RETURNED", NETLOGON_PROFILE_PATH_RETURNED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_GRACE_LOGON", NETLOGON_GRACE_LOGON, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_SamBaseInfo(struct ndr_push *ndr, int ndr_flags, const struct netr_SamBaseInfo *r)
+{
+ uint32_t cntr_unknown_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_logon));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_logoff));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->acct_expiry));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_password_change));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->allow_password_change));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->force_password_change));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->logon_script));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->profile_path));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->home_directory));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->home_drive));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->logon_count));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->bad_password_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->primary_gid));
+ NDR_CHECK(ndr_push_samr_RidWithAttributeArray(ndr, NDR_SCALARS, &r->groups));
+ NDR_CHECK(ndr_push_netr_UserFlags(ndr, NDR_SCALARS, r->user_flags));
+ NDR_CHECK(ndr_push_netr_UserSessionKey(ndr, NDR_SCALARS, &r->key));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->logon_server));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->domain));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain_sid));
+ NDR_CHECK(ndr_push_netr_LMSessionKey(ndr, NDR_SCALARS, &r->LMSessKey));
+ NDR_CHECK(ndr_push_samr_AcctFlags(ndr, NDR_SCALARS, r->acct_flags));
+ for (cntr_unknown_0 = 0; cntr_unknown_0 < 7; cntr_unknown_0++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown[cntr_unknown_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->logon_script));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->profile_path));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->home_directory));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->home_drive));
+ NDR_CHECK(ndr_push_samr_RidWithAttributeArray(ndr, NDR_BUFFERS, &r->groups));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->logon_server));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->domain));
+ if (r->domain_sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->domain_sid));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_SamBaseInfo(struct ndr_pull *ndr, int ndr_flags, struct netr_SamBaseInfo *r)
+{
+ uint32_t _ptr_domain_sid;
+ TALLOC_CTX *_mem_save_domain_sid_0;
+ uint32_t cntr_unknown_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_logon));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_logoff));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->acct_expiry));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_password_change));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->allow_password_change));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->force_password_change));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->logon_script));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->profile_path));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->home_directory));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->home_drive));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->logon_count));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->bad_password_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->primary_gid));
+ NDR_CHECK(ndr_pull_samr_RidWithAttributeArray(ndr, NDR_SCALARS, &r->groups));
+ NDR_CHECK(ndr_pull_netr_UserFlags(ndr, NDR_SCALARS, &r->user_flags));
+ NDR_CHECK(ndr_pull_netr_UserSessionKey(ndr, NDR_SCALARS, &r->key));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->logon_server));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->domain));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_sid));
+ if (_ptr_domain_sid) {
+ NDR_PULL_ALLOC(ndr, r->domain_sid);
+ } else {
+ r->domain_sid = NULL;
+ }
+ NDR_CHECK(ndr_pull_netr_LMSessionKey(ndr, NDR_SCALARS, &r->LMSessKey));
+ NDR_CHECK(ndr_pull_samr_AcctFlags(ndr, NDR_SCALARS, &r->acct_flags));
+ for (cntr_unknown_0 = 0; cntr_unknown_0 < 7; cntr_unknown_0++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown[cntr_unknown_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->logon_script));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->profile_path));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->home_directory));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->home_drive));
+ NDR_CHECK(ndr_pull_samr_RidWithAttributeArray(ndr, NDR_BUFFERS, &r->groups));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->logon_server));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->domain));
+ if (r->domain_sid) {
+ _mem_save_domain_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain_sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->domain_sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_sid_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_SamBaseInfo(struct ndr_print *ndr, const char *name, const struct netr_SamBaseInfo *r)
+{
+ uint32_t cntr_unknown_0;
+ ndr_print_struct(ndr, name, "netr_SamBaseInfo");
+ ndr->depth++;
+ ndr_print_NTTIME(ndr, "last_logon", r->last_logon);
+ ndr_print_NTTIME(ndr, "last_logoff", r->last_logoff);
+ ndr_print_NTTIME(ndr, "acct_expiry", r->acct_expiry);
+ ndr_print_NTTIME(ndr, "last_password_change", r->last_password_change);
+ ndr_print_NTTIME(ndr, "allow_password_change", r->allow_password_change);
+ ndr_print_NTTIME(ndr, "force_password_change", r->force_password_change);
+ ndr_print_lsa_String(ndr, "account_name", &r->account_name);
+ ndr_print_lsa_String(ndr, "full_name", &r->full_name);
+ ndr_print_lsa_String(ndr, "logon_script", &r->logon_script);
+ ndr_print_lsa_String(ndr, "profile_path", &r->profile_path);
+ ndr_print_lsa_String(ndr, "home_directory", &r->home_directory);
+ ndr_print_lsa_String(ndr, "home_drive", &r->home_drive);
+ ndr_print_uint16(ndr, "logon_count", r->logon_count);
+ ndr_print_uint16(ndr, "bad_password_count", r->bad_password_count);
+ ndr_print_uint32(ndr, "rid", r->rid);
+ ndr_print_uint32(ndr, "primary_gid", r->primary_gid);
+ ndr_print_samr_RidWithAttributeArray(ndr, "groups", &r->groups);
+ ndr_print_netr_UserFlags(ndr, "user_flags", r->user_flags);
+ ndr_print_netr_UserSessionKey(ndr, "key", &r->key);
+ ndr_print_lsa_StringLarge(ndr, "logon_server", &r->logon_server);
+ ndr_print_lsa_StringLarge(ndr, "domain", &r->domain);
+ ndr_print_ptr(ndr, "domain_sid", r->domain_sid);
+ ndr->depth++;
+ if (r->domain_sid) {
+ ndr_print_dom_sid2(ndr, "domain_sid", r->domain_sid);
+ }
+ ndr->depth--;
+ ndr_print_netr_LMSessionKey(ndr, "LMSessKey", &r->LMSessKey);
+ ndr_print_samr_AcctFlags(ndr, "acct_flags", r->acct_flags);
+ ndr->print(ndr, "%s: ARRAY(%d)", "unknown", (int)7);
+ ndr->depth++;
+ for (cntr_unknown_0=0;cntr_unknown_0<7;cntr_unknown_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_unknown_0) != -1) {
+ ndr_print_uint32(ndr, "unknown", r->unknown[cntr_unknown_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_SamInfo2(struct ndr_push *ndr, int ndr_flags, const struct netr_SamInfo2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netr_SamBaseInfo(ndr, NDR_SCALARS, &r->base));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_netr_SamBaseInfo(ndr, NDR_BUFFERS, &r->base));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_SamInfo2(struct ndr_pull *ndr, int ndr_flags, struct netr_SamInfo2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netr_SamBaseInfo(ndr, NDR_SCALARS, &r->base));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_netr_SamBaseInfo(ndr, NDR_BUFFERS, &r->base));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_SamInfo2(struct ndr_print *ndr, const char *name, const struct netr_SamInfo2 *r)
+{
+ ndr_print_struct(ndr, name, "netr_SamInfo2");
+ ndr->depth++;
+ ndr_print_netr_SamBaseInfo(ndr, "base", &r->base);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_SidAttr(struct ndr_push *ndr, int ndr_flags, const struct netr_SidAttr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sid));
+ NDR_CHECK(ndr_push_samr_GroupAttrs(ndr, NDR_SCALARS, r->attributes));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_SidAttr(struct ndr_pull *ndr, int ndr_flags, struct netr_SidAttr *r)
+{
+ uint32_t _ptr_sid;
+ TALLOC_CTX *_mem_save_sid_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sid));
+ if (_ptr_sid) {
+ NDR_PULL_ALLOC(ndr, r->sid);
+ } else {
+ r->sid = NULL;
+ }
+ NDR_CHECK(ndr_pull_samr_GroupAttrs(ndr, NDR_SCALARS, &r->attributes));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sid) {
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_SidAttr(struct ndr_print *ndr, const char *name, const struct netr_SidAttr *r)
+{
+ ndr_print_struct(ndr, name, "netr_SidAttr");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sid", r->sid);
+ ndr->depth++;
+ if (r->sid) {
+ ndr_print_dom_sid2(ndr, "sid", r->sid);
+ }
+ ndr->depth--;
+ ndr_print_samr_GroupAttrs(ndr, "attributes", r->attributes);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_SamInfo3(struct ndr_push *ndr, int ndr_flags, const struct netr_SamInfo3 *r)
+{
+ uint32_t cntr_sids_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netr_SamBaseInfo(ndr, NDR_SCALARS, &r->base));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sidcount));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sids));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_netr_SamBaseInfo(ndr, NDR_BUFFERS, &r->base));
+ if (r->sids) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sidcount));
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->sidcount; cntr_sids_1++) {
+ NDR_CHECK(ndr_push_netr_SidAttr(ndr, NDR_SCALARS, &r->sids[cntr_sids_1]));
+ }
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->sidcount; cntr_sids_1++) {
+ NDR_CHECK(ndr_push_netr_SidAttr(ndr, NDR_BUFFERS, &r->sids[cntr_sids_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_SamInfo3(struct ndr_pull *ndr, int ndr_flags, struct netr_SamInfo3 *r)
+{
+ uint32_t _ptr_sids;
+ uint32_t cntr_sids_1;
+ TALLOC_CTX *_mem_save_sids_0;
+ TALLOC_CTX *_mem_save_sids_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netr_SamBaseInfo(ndr, NDR_SCALARS, &r->base));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sidcount));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sids));
+ if (_ptr_sids) {
+ NDR_PULL_ALLOC(ndr, r->sids);
+ } else {
+ r->sids = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_netr_SamBaseInfo(ndr, NDR_BUFFERS, &r->base));
+ if (r->sids) {
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->sids));
+ NDR_PULL_ALLOC_N(ndr, r->sids, ndr_get_array_size(ndr, &r->sids));
+ _mem_save_sids_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids, 0);
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->sidcount; cntr_sids_1++) {
+ NDR_CHECK(ndr_pull_netr_SidAttr(ndr, NDR_SCALARS, &r->sids[cntr_sids_1]));
+ }
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->sidcount; cntr_sids_1++) {
+ NDR_CHECK(ndr_pull_netr_SidAttr(ndr, NDR_BUFFERS, &r->sids[cntr_sids_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, 0);
+ }
+ if (r->sids) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->sids, r->sidcount));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_SamInfo3(struct ndr_print *ndr, const char *name, const struct netr_SamInfo3 *r)
+{
+ uint32_t cntr_sids_1;
+ ndr_print_struct(ndr, name, "netr_SamInfo3");
+ ndr->depth++;
+ ndr_print_netr_SamBaseInfo(ndr, "base", &r->base);
+ ndr_print_uint32(ndr, "sidcount", r->sidcount);
+ ndr_print_ptr(ndr, "sids", r->sids);
+ ndr->depth++;
+ if (r->sids) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "sids", (int)r->sidcount);
+ ndr->depth++;
+ for (cntr_sids_1=0;cntr_sids_1<r->sidcount;cntr_sids_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_sids_1) != -1) {
+ ndr_print_netr_SidAttr(ndr, "sids", &r->sids[cntr_sids_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_SamInfo6(struct ndr_push *ndr, int ndr_flags, const struct netr_SamInfo6 *r)
+{
+ uint32_t cntr_sids_1;
+ uint32_t cntr_unknown4_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netr_SamBaseInfo(ndr, NDR_SCALARS, &r->base));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sidcount));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sids));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->forest));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->principle));
+ for (cntr_unknown4_0 = 0; cntr_unknown4_0 < 20; cntr_unknown4_0++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown4[cntr_unknown4_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_netr_SamBaseInfo(ndr, NDR_BUFFERS, &r->base));
+ if (r->sids) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sidcount));
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->sidcount; cntr_sids_1++) {
+ NDR_CHECK(ndr_push_netr_SidAttr(ndr, NDR_SCALARS, &r->sids[cntr_sids_1]));
+ }
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->sidcount; cntr_sids_1++) {
+ NDR_CHECK(ndr_push_netr_SidAttr(ndr, NDR_BUFFERS, &r->sids[cntr_sids_1]));
+ }
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->forest));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->principle));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_SamInfo6(struct ndr_pull *ndr, int ndr_flags, struct netr_SamInfo6 *r)
+{
+ uint32_t _ptr_sids;
+ uint32_t cntr_sids_1;
+ TALLOC_CTX *_mem_save_sids_0;
+ TALLOC_CTX *_mem_save_sids_1;
+ uint32_t cntr_unknown4_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netr_SamBaseInfo(ndr, NDR_SCALARS, &r->base));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sidcount));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sids));
+ if (_ptr_sids) {
+ NDR_PULL_ALLOC(ndr, r->sids);
+ } else {
+ r->sids = NULL;
+ }
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->forest));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->principle));
+ for (cntr_unknown4_0 = 0; cntr_unknown4_0 < 20; cntr_unknown4_0++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown4[cntr_unknown4_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_netr_SamBaseInfo(ndr, NDR_BUFFERS, &r->base));
+ if (r->sids) {
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->sids));
+ NDR_PULL_ALLOC_N(ndr, r->sids, ndr_get_array_size(ndr, &r->sids));
+ _mem_save_sids_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids, 0);
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->sidcount; cntr_sids_1++) {
+ NDR_CHECK(ndr_pull_netr_SidAttr(ndr, NDR_SCALARS, &r->sids[cntr_sids_1]));
+ }
+ for (cntr_sids_1 = 0; cntr_sids_1 < r->sidcount; cntr_sids_1++) {
+ NDR_CHECK(ndr_pull_netr_SidAttr(ndr, NDR_BUFFERS, &r->sids[cntr_sids_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, 0);
+ }
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->forest));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->principle));
+ if (r->sids) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->sids, r->sidcount));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_SamInfo6(struct ndr_print *ndr, const char *name, const struct netr_SamInfo6 *r)
+{
+ uint32_t cntr_sids_1;
+ uint32_t cntr_unknown4_0;
+ ndr_print_struct(ndr, name, "netr_SamInfo6");
+ ndr->depth++;
+ ndr_print_netr_SamBaseInfo(ndr, "base", &r->base);
+ ndr_print_uint32(ndr, "sidcount", r->sidcount);
+ ndr_print_ptr(ndr, "sids", r->sids);
+ ndr->depth++;
+ if (r->sids) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "sids", (int)r->sidcount);
+ ndr->depth++;
+ for (cntr_sids_1=0;cntr_sids_1<r->sidcount;cntr_sids_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_sids_1) != -1) {
+ ndr_print_netr_SidAttr(ndr, "sids", &r->sids[cntr_sids_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_lsa_String(ndr, "forest", &r->forest);
+ ndr_print_lsa_String(ndr, "principle", &r->principle);
+ ndr->print(ndr, "%s: ARRAY(%d)", "unknown4", (int)20);
+ ndr->depth++;
+ for (cntr_unknown4_0=0;cntr_unknown4_0<20;cntr_unknown4_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_unknown4_0) != -1) {
+ ndr_print_uint32(ndr, "unknown4", r->unknown4[cntr_unknown4_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_PacInfo(struct ndr_push *ndr, int ndr_flags, const struct netr_PacInfo *r)
+{
+ uint32_t cntr_expansionroom_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pac_size));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->pac));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->logon_domain));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->logon_server));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->principal_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->auth_size));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->auth));
+ NDR_CHECK(ndr_push_netr_UserSessionKey(ndr, NDR_SCALARS, &r->user_session_key));
+ for (cntr_expansionroom_0 = 0; cntr_expansionroom_0 < 10; cntr_expansionroom_0++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->expansionroom[cntr_expansionroom_0]));
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->pac) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pac_size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->pac, r->pac_size));
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->logon_domain));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->logon_server));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->principal_name));
+ if (r->auth) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->auth_size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->auth, r->auth_size));
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_PacInfo(struct ndr_pull *ndr, int ndr_flags, struct netr_PacInfo *r)
+{
+ uint32_t _ptr_pac;
+ TALLOC_CTX *_mem_save_pac_0;
+ uint32_t _ptr_auth;
+ TALLOC_CTX *_mem_save_auth_0;
+ uint32_t cntr_expansionroom_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pac_size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_pac));
+ if (_ptr_pac) {
+ NDR_PULL_ALLOC(ndr, r->pac);
+ } else {
+ r->pac = NULL;
+ }
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->logon_domain));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->logon_server));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->principal_name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->auth_size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_auth));
+ if (_ptr_auth) {
+ NDR_PULL_ALLOC(ndr, r->auth);
+ } else {
+ r->auth = NULL;
+ }
+ NDR_CHECK(ndr_pull_netr_UserSessionKey(ndr, NDR_SCALARS, &r->user_session_key));
+ for (cntr_expansionroom_0 = 0; cntr_expansionroom_0 < 10; cntr_expansionroom_0++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->expansionroom[cntr_expansionroom_0]));
+ }
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->pac) {
+ _mem_save_pac_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->pac, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->pac));
+ NDR_PULL_ALLOC_N(ndr, r->pac, ndr_get_array_size(ndr, &r->pac));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->pac, ndr_get_array_size(ndr, &r->pac)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_pac_0, 0);
+ }
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->logon_domain));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->logon_server));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->principal_name));
+ if (r->auth) {
+ _mem_save_auth_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->auth, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->auth));
+ NDR_PULL_ALLOC_N(ndr, r->auth, ndr_get_array_size(ndr, &r->auth));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->auth, ndr_get_array_size(ndr, &r->auth)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_auth_0, 0);
+ }
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ if (r->pac) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->pac, r->pac_size));
+ }
+ if (r->auth) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->auth, r->auth_size));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_PacInfo(struct ndr_print *ndr, const char *name, const struct netr_PacInfo *r)
+{
+ uint32_t cntr_expansionroom_0;
+ ndr_print_struct(ndr, name, "netr_PacInfo");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "pac_size", r->pac_size);
+ ndr_print_ptr(ndr, "pac", r->pac);
+ ndr->depth++;
+ if (r->pac) {
+ ndr_print_array_uint8(ndr, "pac", r->pac, r->pac_size);
+ }
+ ndr->depth--;
+ ndr_print_lsa_String(ndr, "logon_domain", &r->logon_domain);
+ ndr_print_lsa_String(ndr, "logon_server", &r->logon_server);
+ ndr_print_lsa_String(ndr, "principal_name", &r->principal_name);
+ ndr_print_uint32(ndr, "auth_size", r->auth_size);
+ ndr_print_ptr(ndr, "auth", r->auth);
+ ndr->depth++;
+ if (r->auth) {
+ ndr_print_array_uint8(ndr, "auth", r->auth, r->auth_size);
+ }
+ ndr->depth--;
+ ndr_print_netr_UserSessionKey(ndr, "user_session_key", &r->user_session_key);
+ ndr->print(ndr, "%s: ARRAY(%d)", "expansionroom", (int)10);
+ ndr->depth++;
+ for (cntr_expansionroom_0=0;cntr_expansionroom_0<10;cntr_expansionroom_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_expansionroom_0) != -1) {
+ ndr_print_uint32(ndr, "expansionroom", r->expansionroom[cntr_expansionroom_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr_print_lsa_String(ndr, "unknown1", &r->unknown1);
+ ndr_print_lsa_String(ndr, "unknown2", &r->unknown2);
+ ndr_print_lsa_String(ndr, "unknown3", &r->unknown3);
+ ndr_print_lsa_String(ndr, "unknown4", &r->unknown4);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_Validation(struct ndr_push *ndr, int ndr_flags, const union netr_Validation *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sam2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sam3));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->pac));
+ break; }
+
+ case 5: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->pac));
+ break; }
+
+ case 6: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sam6));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 2:
+ if (r->sam2) {
+ NDR_CHECK(ndr_push_netr_SamInfo2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sam2));
+ }
+ break;
+
+ case 3:
+ if (r->sam3) {
+ NDR_CHECK(ndr_push_netr_SamInfo3(ndr, NDR_SCALARS|NDR_BUFFERS, r->sam3));
+ }
+ break;
+
+ case 4:
+ if (r->pac) {
+ NDR_CHECK(ndr_push_netr_PacInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->pac));
+ }
+ break;
+
+ case 5:
+ if (r->pac) {
+ NDR_CHECK(ndr_push_netr_PacInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->pac));
+ }
+ break;
+
+ case 6:
+ if (r->sam6) {
+ NDR_CHECK(ndr_push_netr_SamInfo6(ndr, NDR_SCALARS|NDR_BUFFERS, r->sam6));
+ }
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_Validation(struct ndr_pull *ndr, int ndr_flags, union netr_Validation *r)
+{
+ int level;
+ uint16_t _level;
+ TALLOC_CTX *_mem_save_sam2_0;
+ TALLOC_CTX *_mem_save_sam3_0;
+ TALLOC_CTX *_mem_save_pac_0;
+ TALLOC_CTX *_mem_save_sam6_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 2: {
+ uint32_t _ptr_sam2;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sam2));
+ if (_ptr_sam2) {
+ NDR_PULL_ALLOC(ndr, r->sam2);
+ } else {
+ r->sam2 = NULL;
+ }
+ break; }
+
+ case 3: {
+ uint32_t _ptr_sam3;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sam3));
+ if (_ptr_sam3) {
+ NDR_PULL_ALLOC(ndr, r->sam3);
+ } else {
+ r->sam3 = NULL;
+ }
+ break; }
+
+ case 4: {
+ uint32_t _ptr_pac;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_pac));
+ if (_ptr_pac) {
+ NDR_PULL_ALLOC(ndr, r->pac);
+ } else {
+ r->pac = NULL;
+ }
+ break; }
+
+ case 5: {
+ uint32_t _ptr_pac;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_pac));
+ if (_ptr_pac) {
+ NDR_PULL_ALLOC(ndr, r->pac);
+ } else {
+ r->pac = NULL;
+ }
+ break; }
+
+ case 6: {
+ uint32_t _ptr_sam6;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sam6));
+ if (_ptr_sam6) {
+ NDR_PULL_ALLOC(ndr, r->sam6);
+ } else {
+ r->sam6 = NULL;
+ }
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 2:
+ if (r->sam2) {
+ _mem_save_sam2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sam2, 0);
+ NDR_CHECK(ndr_pull_netr_SamInfo2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sam2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sam2_0, 0);
+ }
+ break;
+
+ case 3:
+ if (r->sam3) {
+ _mem_save_sam3_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sam3, 0);
+ NDR_CHECK(ndr_pull_netr_SamInfo3(ndr, NDR_SCALARS|NDR_BUFFERS, r->sam3));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sam3_0, 0);
+ }
+ break;
+
+ case 4:
+ if (r->pac) {
+ _mem_save_pac_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->pac, 0);
+ NDR_CHECK(ndr_pull_netr_PacInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->pac));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_pac_0, 0);
+ }
+ break;
+
+ case 5:
+ if (r->pac) {
+ _mem_save_pac_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->pac, 0);
+ NDR_CHECK(ndr_pull_netr_PacInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->pac));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_pac_0, 0);
+ }
+ break;
+
+ case 6:
+ if (r->sam6) {
+ _mem_save_sam6_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sam6, 0);
+ NDR_CHECK(ndr_pull_netr_SamInfo6(ndr, NDR_SCALARS|NDR_BUFFERS, r->sam6));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sam6_0, 0);
+ }
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_Validation(struct ndr_print *ndr, const char *name, const union netr_Validation *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "netr_Validation");
+ switch (level) {
+ case 2:
+ ndr_print_ptr(ndr, "sam2", r->sam2);
+ ndr->depth++;
+ if (r->sam2) {
+ ndr_print_netr_SamInfo2(ndr, "sam2", r->sam2);
+ }
+ ndr->depth--;
+ break;
+
+ case 3:
+ ndr_print_ptr(ndr, "sam3", r->sam3);
+ ndr->depth++;
+ if (r->sam3) {
+ ndr_print_netr_SamInfo3(ndr, "sam3", r->sam3);
+ }
+ ndr->depth--;
+ break;
+
+ case 4:
+ ndr_print_ptr(ndr, "pac", r->pac);
+ ndr->depth++;
+ if (r->pac) {
+ ndr_print_netr_PacInfo(ndr, "pac", r->pac);
+ }
+ ndr->depth--;
+ break;
+
+ case 5:
+ ndr_print_ptr(ndr, "pac", r->pac);
+ ndr->depth++;
+ if (r->pac) {
+ ndr_print_netr_PacInfo(ndr, "pac", r->pac);
+ }
+ ndr->depth--;
+ break;
+
+ case 6:
+ ndr_print_ptr(ndr, "sam6", r->sam6);
+ ndr->depth++;
+ if (r->sam6) {
+ ndr_print_netr_SamInfo6(ndr, "sam6", r->sam6);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_Credential(struct ndr_push *ndr, int ndr_flags, const struct netr_Credential *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data, 8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_Credential(struct ndr_pull *ndr, int ndr_flags, struct netr_Credential *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data, 8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_Credential(struct ndr_print *ndr, const char *name, const struct netr_Credential *r)
+{
+ ndr_print_struct(ndr, name, "netr_Credential");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "data", r->data, 8);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_Authenticator(struct ndr_push *ndr, int ndr_flags, const struct netr_Authenticator *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netr_Credential(ndr, NDR_SCALARS, &r->cred));
+ NDR_CHECK(ndr_push_time_t(ndr, NDR_SCALARS, r->timestamp));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_Authenticator(struct ndr_pull *ndr, int ndr_flags, struct netr_Authenticator *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netr_Credential(ndr, NDR_SCALARS, &r->cred));
+ NDR_CHECK(ndr_pull_time_t(ndr, NDR_SCALARS, &r->timestamp));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_Authenticator(struct ndr_print *ndr, const char *name, const struct netr_Authenticator *r)
+{
+ ndr_print_struct(ndr, name, "netr_Authenticator");
+ ndr->depth++;
+ ndr_print_netr_Credential(ndr, "cred", &r->cred);
+ ndr_print_time_t(ndr, "timestamp", r->timestamp);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_LogonLevel(struct ndr_push *ndr, int ndr_flags, enum netr_LogonLevel r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_LogonLevel(struct ndr_pull *ndr, int ndr_flags, enum netr_LogonLevel *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_LogonLevel(struct ndr_print *ndr, const char *name, enum netr_LogonLevel r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case INTERACTIVE_LOGON_TYPE: val = "INTERACTIVE_LOGON_TYPE"; break;
+ case NET_LOGON_TYPE: val = "NET_LOGON_TYPE"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_DELETE_USER(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_DELETE_USER *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown5));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown6));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown7));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->account_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->account_name, ndr_charset_length(r->account_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_DELETE_USER(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_DELETE_USER *r)
+{
+ uint32_t _ptr_account_name;
+ TALLOC_CTX *_mem_save_account_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_account_name));
+ if (_ptr_account_name) {
+ NDR_PULL_ALLOC(ndr, r->account_name);
+ } else {
+ r->account_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown5));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown6));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown7));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->account_name) {
+ _mem_save_account_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->account_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->account_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->account_name));
+ if (ndr_get_array_length(ndr, &r->account_name) > ndr_get_array_size(ndr, &r->account_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->account_name), ndr_get_array_length(ndr, &r->account_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->account_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->account_name, ndr_get_array_length(ndr, &r->account_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_account_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_DELETE_USER(struct ndr_print *ndr, const char *name, const struct netr_DELTA_DELETE_USER *r)
+{
+ ndr_print_struct(ndr, name, "netr_DELTA_DELETE_USER");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "account_name", r->account_name);
+ ndr->depth++;
+ if (r->account_name) {
+ ndr_print_string(ndr, "account_name", r->account_name);
+ }
+ ndr->depth--;
+ ndr_print_lsa_String(ndr, "unknown1", &r->unknown1);
+ ndr_print_lsa_String(ndr, "unknown2", &r->unknown2);
+ ndr_print_lsa_String(ndr, "unknown3", &r->unknown3);
+ ndr_print_lsa_String(ndr, "unknown4", &r->unknown4);
+ ndr_print_uint32(ndr, "unknown5", r->unknown5);
+ ndr_print_uint32(ndr, "unknown6", r->unknown6);
+ ndr_print_uint32(ndr, "unknown7", r->unknown7);
+ ndr_print_uint32(ndr, "unknown8", r->unknown8);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_USER_KEY16(struct ndr_push *ndr, int ndr_flags, const struct netr_USER_KEY16 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, &r->pwd));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_BUFFERS, &r->pwd));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_USER_KEY16(struct ndr_pull *ndr, int ndr_flags, struct netr_USER_KEY16 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, &r->pwd));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_BUFFERS, &r->pwd));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_USER_KEY16(struct ndr_print *ndr, const char *name, const struct netr_USER_KEY16 *r)
+{
+ ndr_print_struct(ndr, name, "netr_USER_KEY16");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "length", r->length);
+ ndr_print_uint16(ndr, "size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?r->length:r->size);
+ ndr_print_uint32(ndr, "flags", r->flags);
+ ndr_print_samr_Password(ndr, "pwd", &r->pwd);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_PasswordHistory(struct ndr_push *ndr, int ndr_flags, const struct netr_PasswordHistory *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->nt_length));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->nt_length));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->nt_flags));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm_length));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm_length));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->lm_flags));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->nt_history, r->nt_length));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->lm_history, r->lm_length));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_PasswordHistory(struct ndr_pull *ndr, int ndr_flags, struct netr_PasswordHistory *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->nt_length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->nt_size));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->nt_flags));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm_length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm_size));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->lm_flags));
+ NDR_PULL_ALLOC_N(ndr, r->nt_history, r->nt_length);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->nt_history, r->nt_length));
+ NDR_PULL_ALLOC_N(ndr, r->lm_history, r->lm_length);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->lm_history, r->lm_length));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_PasswordHistory(struct ndr_print *ndr, const char *name, const struct netr_PasswordHistory *r)
+{
+ ndr_print_struct(ndr, name, "netr_PasswordHistory");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "nt_length", r->nt_length);
+ ndr_print_uint16(ndr, "nt_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?r->nt_length:r->nt_size);
+ ndr_print_uint32(ndr, "nt_flags", r->nt_flags);
+ ndr_print_uint16(ndr, "lm_length", r->lm_length);
+ ndr_print_uint16(ndr, "lm_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?r->lm_length:r->lm_size);
+ ndr_print_uint32(ndr, "lm_flags", r->lm_flags);
+ ndr_print_array_uint8(ndr, "nt_history", r->nt_history, r->nt_length);
+ ndr_print_array_uint8(ndr, "lm_history", r->lm_history, r->lm_length);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_USER_KEYS2(struct ndr_push *ndr, int ndr_flags, const struct netr_USER_KEYS2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netr_USER_KEY16(ndr, NDR_SCALARS, &r->lmpassword));
+ NDR_CHECK(ndr_push_netr_USER_KEY16(ndr, NDR_SCALARS, &r->ntpassword));
+ NDR_CHECK(ndr_push_netr_PasswordHistory(ndr, NDR_SCALARS, &r->history));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_netr_USER_KEY16(ndr, NDR_BUFFERS, &r->lmpassword));
+ NDR_CHECK(ndr_push_netr_USER_KEY16(ndr, NDR_BUFFERS, &r->ntpassword));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_USER_KEYS2(struct ndr_pull *ndr, int ndr_flags, struct netr_USER_KEYS2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netr_USER_KEY16(ndr, NDR_SCALARS, &r->lmpassword));
+ NDR_CHECK(ndr_pull_netr_USER_KEY16(ndr, NDR_SCALARS, &r->ntpassword));
+ NDR_CHECK(ndr_pull_netr_PasswordHistory(ndr, NDR_SCALARS, &r->history));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_netr_USER_KEY16(ndr, NDR_BUFFERS, &r->lmpassword));
+ NDR_CHECK(ndr_pull_netr_USER_KEY16(ndr, NDR_BUFFERS, &r->ntpassword));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_USER_KEYS2(struct ndr_print *ndr, const char *name, const struct netr_USER_KEYS2 *r)
+{
+ ndr_print_struct(ndr, name, "netr_USER_KEYS2");
+ ndr->depth++;
+ ndr_print_netr_USER_KEY16(ndr, "lmpassword", &r->lmpassword);
+ ndr_print_netr_USER_KEY16(ndr, "ntpassword", &r->ntpassword);
+ ndr_print_netr_PasswordHistory(ndr, "history", &r->history);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_USER_KEY_UNION(struct ndr_push *ndr, int ndr_flags, const struct netr_USER_KEY_UNION *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netr_USER_KEYS2(ndr, NDR_SCALARS, &r->keys2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_netr_USER_KEYS2(ndr, NDR_BUFFERS, &r->keys2));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_USER_KEY_UNION(struct ndr_pull *ndr, int ndr_flags, struct netr_USER_KEY_UNION *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netr_USER_KEYS2(ndr, NDR_SCALARS, &r->keys2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_netr_USER_KEYS2(ndr, NDR_BUFFERS, &r->keys2));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_USER_KEY_UNION(struct ndr_print *ndr, const char *name, const struct netr_USER_KEY_UNION *r)
+{
+ ndr_print_struct(ndr, name, "netr_USER_KEY_UNION");
+ ndr->depth++;
+ ndr_print_netr_USER_KEYS2(ndr, "keys2", &r->keys2);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_USER_KEYS(struct ndr_push *ndr, int ndr_flags, const struct netr_USER_KEYS *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version));
+ NDR_CHECK(ndr_push_netr_USER_KEY_UNION(ndr, NDR_SCALARS, &r->keys));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_netr_USER_KEY_UNION(ndr, NDR_BUFFERS, &r->keys));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_USER_KEYS(struct ndr_pull *ndr, int ndr_flags, struct netr_USER_KEYS *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_netr_USER_KEY_UNION(ndr, NDR_SCALARS, &r->keys));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_netr_USER_KEY_UNION(ndr, NDR_BUFFERS, &r->keys));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_USER_KEYS(struct ndr_print *ndr, const char *name, const struct netr_USER_KEYS *r)
+{
+ ndr_print_struct(ndr, name, "netr_USER_KEYS");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "version", r->version);
+ ndr_print_netr_USER_KEY_UNION(ndr, "keys", &r->keys);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_USER_PRIVATE_INFO(struct ndr_push *ndr, int ndr_flags, const struct netr_USER_PRIVATE_INFO *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->SensitiveDataFlag));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->DataLength));
+ {
+ uint32_t _flags_save_uint8 = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->SensitiveData));
+ ndr->flags = _flags_save_uint8;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ uint32_t _flags_save_uint8 = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (r->SensitiveData) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->DataLength));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->SensitiveData, r->DataLength));
+ }
+ ndr->flags = _flags_save_uint8;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_USER_PRIVATE_INFO(struct ndr_pull *ndr, int ndr_flags, struct netr_USER_PRIVATE_INFO *r)
+{
+ uint32_t _ptr_SensitiveData;
+ TALLOC_CTX *_mem_save_SensitiveData_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->SensitiveDataFlag));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->DataLength));
+ {
+ uint32_t _flags_save_uint8 = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_SensitiveData));
+ if (_ptr_SensitiveData) {
+ NDR_PULL_ALLOC(ndr, r->SensitiveData);
+ } else {
+ r->SensitiveData = NULL;
+ }
+ ndr->flags = _flags_save_uint8;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ uint32_t _flags_save_uint8 = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (r->SensitiveData) {
+ _mem_save_SensitiveData_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->SensitiveData, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->SensitiveData));
+ NDR_PULL_ALLOC_N(ndr, r->SensitiveData, ndr_get_array_size(ndr, &r->SensitiveData));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->SensitiveData, ndr_get_array_size(ndr, &r->SensitiveData)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_SensitiveData_0, 0);
+ }
+ ndr->flags = _flags_save_uint8;
+ }
+ if (r->SensitiveData) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->SensitiveData, r->DataLength));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_USER_PRIVATE_INFO(struct ndr_print *ndr, const char *name, const struct netr_USER_PRIVATE_INFO *r)
+{
+ ndr_print_struct(ndr, name, "netr_USER_PRIVATE_INFO");
+ ndr->depth++;
+ ndr_print_uint8(ndr, "SensitiveDataFlag", r->SensitiveDataFlag);
+ ndr_print_uint32(ndr, "DataLength", r->DataLength);
+ ndr_print_ptr(ndr, "SensitiveData", r->SensitiveData);
+ ndr->depth++;
+ if (r->SensitiveData) {
+ ndr_print_array_uint8(ndr, "SensitiveData", r->SensitiveData, r->DataLength);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_USER(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_USER *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->primary_gid));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->home_directory));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->home_drive));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->logon_script));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->description));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->workstations));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_logon));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_logoff));
+ NDR_CHECK(ndr_push_samr_LogonHours(ndr, NDR_SCALARS, &r->logon_hours));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->bad_password_count));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->logon_count));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_password_change));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->acct_expiry));
+ NDR_CHECK(ndr_push_samr_AcctFlags(ndr, NDR_SCALARS, r->acct_flags));
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, &r->lmpassword));
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, &r->ntpassword));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->nt_password_present));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->lm_password_present));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->password_expired));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->comment));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->parameters));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->country_code));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->code_page));
+ NDR_CHECK(ndr_push_netr_USER_PRIVATE_INFO(ndr, NDR_SCALARS, &r->user_private_info));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->SecurityInformation));
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS, &r->sdbuf));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->profile_path));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown5));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown6));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown7));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->home_directory));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->home_drive));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->logon_script));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->workstations));
+ NDR_CHECK(ndr_push_samr_LogonHours(ndr, NDR_BUFFERS, &r->logon_hours));
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_BUFFERS, &r->lmpassword));
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_BUFFERS, &r->ntpassword));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->comment));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->parameters));
+ NDR_CHECK(ndr_push_netr_USER_PRIVATE_INFO(ndr, NDR_BUFFERS, &r->user_private_info));
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_BUFFERS, &r->sdbuf));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->profile_path));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_USER(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_USER *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->primary_gid));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->home_directory));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->home_drive));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->logon_script));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->description));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->workstations));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_logon));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_logoff));
+ NDR_CHECK(ndr_pull_samr_LogonHours(ndr, NDR_SCALARS, &r->logon_hours));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->bad_password_count));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->logon_count));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_password_change));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->acct_expiry));
+ NDR_CHECK(ndr_pull_samr_AcctFlags(ndr, NDR_SCALARS, &r->acct_flags));
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, &r->lmpassword));
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, &r->ntpassword));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->nt_password_present));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->lm_password_present));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->password_expired));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->comment));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->parameters));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->country_code));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->code_page));
+ NDR_CHECK(ndr_pull_netr_USER_PRIVATE_INFO(ndr, NDR_SCALARS, &r->user_private_info));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->SecurityInformation));
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS, &r->sdbuf));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->profile_path));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown5));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown6));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown7));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->home_directory));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->home_drive));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->logon_script));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->workstations));
+ NDR_CHECK(ndr_pull_samr_LogonHours(ndr, NDR_BUFFERS, &r->logon_hours));
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_BUFFERS, &r->lmpassword));
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_BUFFERS, &r->ntpassword));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->comment));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->parameters));
+ NDR_CHECK(ndr_pull_netr_USER_PRIVATE_INFO(ndr, NDR_BUFFERS, &r->user_private_info));
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_BUFFERS, &r->sdbuf));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->profile_path));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_USER(struct ndr_print *ndr, const char *name, const struct netr_DELTA_USER *r)
+{
+ ndr_print_struct(ndr, name, "netr_DELTA_USER");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "account_name", &r->account_name);
+ ndr_print_lsa_String(ndr, "full_name", &r->full_name);
+ ndr_print_uint32(ndr, "rid", r->rid);
+ ndr_print_uint32(ndr, "primary_gid", r->primary_gid);
+ ndr_print_lsa_String(ndr, "home_directory", &r->home_directory);
+ ndr_print_lsa_String(ndr, "home_drive", &r->home_drive);
+ ndr_print_lsa_String(ndr, "logon_script", &r->logon_script);
+ ndr_print_lsa_String(ndr, "description", &r->description);
+ ndr_print_lsa_String(ndr, "workstations", &r->workstations);
+ ndr_print_NTTIME(ndr, "last_logon", r->last_logon);
+ ndr_print_NTTIME(ndr, "last_logoff", r->last_logoff);
+ ndr_print_samr_LogonHours(ndr, "logon_hours", &r->logon_hours);
+ ndr_print_uint16(ndr, "bad_password_count", r->bad_password_count);
+ ndr_print_uint16(ndr, "logon_count", r->logon_count);
+ ndr_print_NTTIME(ndr, "last_password_change", r->last_password_change);
+ ndr_print_NTTIME(ndr, "acct_expiry", r->acct_expiry);
+ ndr_print_samr_AcctFlags(ndr, "acct_flags", r->acct_flags);
+ ndr_print_samr_Password(ndr, "lmpassword", &r->lmpassword);
+ ndr_print_samr_Password(ndr, "ntpassword", &r->ntpassword);
+ ndr_print_uint8(ndr, "nt_password_present", r->nt_password_present);
+ ndr_print_uint8(ndr, "lm_password_present", r->lm_password_present);
+ ndr_print_uint8(ndr, "password_expired", r->password_expired);
+ ndr_print_lsa_String(ndr, "comment", &r->comment);
+ ndr_print_lsa_String(ndr, "parameters", &r->parameters);
+ ndr_print_uint16(ndr, "country_code", r->country_code);
+ ndr_print_uint16(ndr, "code_page", r->code_page);
+ ndr_print_netr_USER_PRIVATE_INFO(ndr, "user_private_info", &r->user_private_info);
+ ndr_print_uint32(ndr, "SecurityInformation", r->SecurityInformation);
+ ndr_print_sec_desc_buf(ndr, "sdbuf", &r->sdbuf);
+ ndr_print_lsa_String(ndr, "profile_path", &r->profile_path);
+ ndr_print_lsa_String(ndr, "unknown2", &r->unknown2);
+ ndr_print_lsa_String(ndr, "unknown3", &r->unknown3);
+ ndr_print_lsa_String(ndr, "unknown4", &r->unknown4);
+ ndr_print_uint32(ndr, "unknown5", r->unknown5);
+ ndr_print_uint32(ndr, "unknown6", r->unknown6);
+ ndr_print_uint32(ndr, "unknown7", r->unknown7);
+ ndr_print_uint32(ndr, "unknown8", r->unknown8);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_DOMAIN(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_DOMAIN *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->domain_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->comment));
+ NDR_CHECK(ndr_push_dlong(ndr, NDR_SCALARS, r->force_logoff_time));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->min_password_length));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->password_history_length));
+ NDR_CHECK(ndr_push_dlong(ndr, NDR_SCALARS, r->max_password_age));
+ NDR_CHECK(ndr_push_dlong(ndr, NDR_SCALARS, r->min_password_age));
+ NDR_CHECK(ndr_push_udlong(ndr, NDR_SCALARS, r->sequence_num));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->domain_create_time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->SecurityInformation));
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS, &r->sdbuf));
+ NDR_CHECK(ndr_push_lsa_BinaryString(ndr, NDR_SCALARS, &r->account_lockout));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->logon_to_chgpass));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown6));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown7));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->domain_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->comment));
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_BUFFERS, &r->sdbuf));
+ NDR_CHECK(ndr_push_lsa_BinaryString(ndr, NDR_BUFFERS, &r->account_lockout));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_DOMAIN(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_DOMAIN *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->domain_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->comment));
+ NDR_CHECK(ndr_pull_dlong(ndr, NDR_SCALARS, &r->force_logoff_time));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->min_password_length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->password_history_length));
+ NDR_CHECK(ndr_pull_dlong(ndr, NDR_SCALARS, &r->max_password_age));
+ NDR_CHECK(ndr_pull_dlong(ndr, NDR_SCALARS, &r->min_password_age));
+ NDR_CHECK(ndr_pull_udlong(ndr, NDR_SCALARS, &r->sequence_num));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->domain_create_time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->SecurityInformation));
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS, &r->sdbuf));
+ NDR_CHECK(ndr_pull_lsa_BinaryString(ndr, NDR_SCALARS, &r->account_lockout));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->logon_to_chgpass));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown6));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown7));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->domain_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->comment));
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_BUFFERS, &r->sdbuf));
+ NDR_CHECK(ndr_pull_lsa_BinaryString(ndr, NDR_BUFFERS, &r->account_lockout));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_DOMAIN(struct ndr_print *ndr, const char *name, const struct netr_DELTA_DOMAIN *r)
+{
+ ndr_print_struct(ndr, name, "netr_DELTA_DOMAIN");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "domain_name", &r->domain_name);
+ ndr_print_lsa_String(ndr, "comment", &r->comment);
+ ndr_print_dlong(ndr, "force_logoff_time", r->force_logoff_time);
+ ndr_print_uint16(ndr, "min_password_length", r->min_password_length);
+ ndr_print_uint16(ndr, "password_history_length", r->password_history_length);
+ ndr_print_dlong(ndr, "max_password_age", r->max_password_age);
+ ndr_print_dlong(ndr, "min_password_age", r->min_password_age);
+ ndr_print_udlong(ndr, "sequence_num", r->sequence_num);
+ ndr_print_NTTIME(ndr, "domain_create_time", r->domain_create_time);
+ ndr_print_uint32(ndr, "SecurityInformation", r->SecurityInformation);
+ ndr_print_sec_desc_buf(ndr, "sdbuf", &r->sdbuf);
+ ndr_print_lsa_BinaryString(ndr, "account_lockout", &r->account_lockout);
+ ndr_print_lsa_String(ndr, "unknown2", &r->unknown2);
+ ndr_print_lsa_String(ndr, "unknown3", &r->unknown3);
+ ndr_print_lsa_String(ndr, "unknown4", &r->unknown4);
+ ndr_print_uint32(ndr, "logon_to_chgpass", r->logon_to_chgpass);
+ ndr_print_uint32(ndr, "unknown6", r->unknown6);
+ ndr_print_uint32(ndr, "unknown7", r->unknown7);
+ ndr_print_uint32(ndr, "unknown8", r->unknown8);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_GROUP(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_GROUP *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->group_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->attributes));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->description));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->SecurityInformation));
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS, &r->sdbuf));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown5));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown6));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown7));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->group_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_BUFFERS, &r->sdbuf));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_GROUP(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_GROUP *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->group_name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->attributes));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->description));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->SecurityInformation));
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS, &r->sdbuf));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown5));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown6));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown7));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->group_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_BUFFERS, &r->sdbuf));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_GROUP(struct ndr_print *ndr, const char *name, const struct netr_DELTA_GROUP *r)
+{
+ ndr_print_struct(ndr, name, "netr_DELTA_GROUP");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "group_name", &r->group_name);
+ ndr_print_uint32(ndr, "rid", r->rid);
+ ndr_print_uint32(ndr, "attributes", r->attributes);
+ ndr_print_lsa_String(ndr, "description", &r->description);
+ ndr_print_uint32(ndr, "SecurityInformation", r->SecurityInformation);
+ ndr_print_sec_desc_buf(ndr, "sdbuf", &r->sdbuf);
+ ndr_print_lsa_String(ndr, "unknown1", &r->unknown1);
+ ndr_print_lsa_String(ndr, "unknown2", &r->unknown2);
+ ndr_print_lsa_String(ndr, "unknown3", &r->unknown3);
+ ndr_print_lsa_String(ndr, "unknown4", &r->unknown4);
+ ndr_print_uint32(ndr, "unknown5", r->unknown5);
+ ndr_print_uint32(ndr, "unknown6", r->unknown6);
+ ndr_print_uint32(ndr, "unknown7", r->unknown7);
+ ndr_print_uint32(ndr, "unknown8", r->unknown8);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_RENAME(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_RENAME *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->OldName));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->NewName));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown5));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown6));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown7));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->OldName));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->NewName));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_RENAME(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_RENAME *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->OldName));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->NewName));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown5));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown6));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown7));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->OldName));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->NewName));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_RENAME(struct ndr_print *ndr, const char *name, const struct netr_DELTA_RENAME *r)
+{
+ ndr_print_struct(ndr, name, "netr_DELTA_RENAME");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "OldName", &r->OldName);
+ ndr_print_lsa_String(ndr, "NewName", &r->NewName);
+ ndr_print_lsa_String(ndr, "unknown1", &r->unknown1);
+ ndr_print_lsa_String(ndr, "unknown2", &r->unknown2);
+ ndr_print_lsa_String(ndr, "unknown3", &r->unknown3);
+ ndr_print_lsa_String(ndr, "unknown4", &r->unknown4);
+ ndr_print_uint32(ndr, "unknown5", r->unknown5);
+ ndr_print_uint32(ndr, "unknown6", r->unknown6);
+ ndr_print_uint32(ndr, "unknown7", r->unknown7);
+ ndr_print_uint32(ndr, "unknown8", r->unknown8);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_GROUP_MEMBER(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_GROUP_MEMBER *r)
+{
+ uint32_t cntr_rids_1;
+ uint32_t cntr_attribs_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->rids));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->attribs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_rids));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown3));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->rids) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_rids));
+ for (cntr_rids_1 = 0; cntr_rids_1 < r->num_rids; cntr_rids_1++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rids[cntr_rids_1]));
+ }
+ }
+ if (r->attribs) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_rids));
+ for (cntr_attribs_1 = 0; cntr_attribs_1 < r->num_rids; cntr_attribs_1++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->attribs[cntr_attribs_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_GROUP_MEMBER(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_GROUP_MEMBER *r)
+{
+ uint32_t _ptr_rids;
+ uint32_t cntr_rids_1;
+ TALLOC_CTX *_mem_save_rids_0;
+ TALLOC_CTX *_mem_save_rids_1;
+ uint32_t _ptr_attribs;
+ uint32_t cntr_attribs_1;
+ TALLOC_CTX *_mem_save_attribs_0;
+ TALLOC_CTX *_mem_save_attribs_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_rids));
+ if (_ptr_rids) {
+ NDR_PULL_ALLOC(ndr, r->rids);
+ } else {
+ r->rids = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_attribs));
+ if (_ptr_attribs) {
+ NDR_PULL_ALLOC(ndr, r->attribs);
+ } else {
+ r->attribs = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_rids));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->rids) {
+ _mem_save_rids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->rids, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->rids));
+ NDR_PULL_ALLOC_N(ndr, r->rids, ndr_get_array_size(ndr, &r->rids));
+ _mem_save_rids_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->rids, 0);
+ for (cntr_rids_1 = 0; cntr_rids_1 < r->num_rids; cntr_rids_1++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rids[cntr_rids_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rids_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rids_0, 0);
+ }
+ if (r->attribs) {
+ _mem_save_attribs_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->attribs, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->attribs));
+ NDR_PULL_ALLOC_N(ndr, r->attribs, ndr_get_array_size(ndr, &r->attribs));
+ _mem_save_attribs_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->attribs, 0);
+ for (cntr_attribs_1 = 0; cntr_attribs_1 < r->num_rids; cntr_attribs_1++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->attribs[cntr_attribs_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_attribs_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_attribs_0, 0);
+ }
+ if (r->rids) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->rids, r->num_rids));
+ }
+ if (r->attribs) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->attribs, r->num_rids));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_GROUP_MEMBER(struct ndr_print *ndr, const char *name, const struct netr_DELTA_GROUP_MEMBER *r)
+{
+ uint32_t cntr_rids_1;
+ uint32_t cntr_attribs_1;
+ ndr_print_struct(ndr, name, "netr_DELTA_GROUP_MEMBER");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "rids", r->rids);
+ ndr->depth++;
+ if (r->rids) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "rids", (int)r->num_rids);
+ ndr->depth++;
+ for (cntr_rids_1=0;cntr_rids_1<r->num_rids;cntr_rids_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_rids_1) != -1) {
+ ndr_print_uint32(ndr, "rids", r->rids[cntr_rids_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "attribs", r->attribs);
+ ndr->depth++;
+ if (r->attribs) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "attribs", (int)r->num_rids);
+ ndr->depth++;
+ for (cntr_attribs_1=0;cntr_attribs_1<r->num_rids;cntr_attribs_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_attribs_1) != -1) {
+ ndr_print_uint32(ndr, "attribs", r->attribs[cntr_attribs_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "num_rids", r->num_rids);
+ ndr_print_uint32(ndr, "unknown1", r->unknown1);
+ ndr_print_uint32(ndr, "unknown2", r->unknown2);
+ ndr_print_uint32(ndr, "unknown3", r->unknown3);
+ ndr_print_uint32(ndr, "unknown4", r->unknown4);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_ALIAS(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_ALIAS *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->alias_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->SecurityInformation));
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS, &r->sdbuf));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->description));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown5));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown6));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown7));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->alias_name));
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_BUFFERS, &r->sdbuf));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_ALIAS(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_ALIAS *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->alias_name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->SecurityInformation));
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS, &r->sdbuf));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->description));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown5));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown6));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown7));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->alias_name));
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_BUFFERS, &r->sdbuf));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_ALIAS(struct ndr_print *ndr, const char *name, const struct netr_DELTA_ALIAS *r)
+{
+ ndr_print_struct(ndr, name, "netr_DELTA_ALIAS");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "alias_name", &r->alias_name);
+ ndr_print_uint32(ndr, "rid", r->rid);
+ ndr_print_uint32(ndr, "SecurityInformation", r->SecurityInformation);
+ ndr_print_sec_desc_buf(ndr, "sdbuf", &r->sdbuf);
+ ndr_print_lsa_String(ndr, "description", &r->description);
+ ndr_print_lsa_String(ndr, "unknown2", &r->unknown2);
+ ndr_print_lsa_String(ndr, "unknown3", &r->unknown3);
+ ndr_print_lsa_String(ndr, "unknown4", &r->unknown4);
+ ndr_print_uint32(ndr, "unknown5", r->unknown5);
+ ndr_print_uint32(ndr, "unknown6", r->unknown6);
+ ndr_print_uint32(ndr, "unknown7", r->unknown7);
+ ndr_print_uint32(ndr, "unknown8", r->unknown8);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_ALIAS_MEMBER(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_ALIAS_MEMBER *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_SidArray(ndr, NDR_SCALARS, &r->sids));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown3));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_SidArray(ndr, NDR_BUFFERS, &r->sids));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_ALIAS_MEMBER(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_ALIAS_MEMBER *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_SidArray(ndr, NDR_SCALARS, &r->sids));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_SidArray(ndr, NDR_BUFFERS, &r->sids));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_ALIAS_MEMBER(struct ndr_print *ndr, const char *name, const struct netr_DELTA_ALIAS_MEMBER *r)
+{
+ ndr_print_struct(ndr, name, "netr_DELTA_ALIAS_MEMBER");
+ ndr->depth++;
+ ndr_print_lsa_SidArray(ndr, "sids", &r->sids);
+ ndr_print_uint32(ndr, "unknown1", r->unknown1);
+ ndr_print_uint32(ndr, "unknown2", r->unknown2);
+ ndr_print_uint32(ndr, "unknown3", r->unknown3);
+ ndr_print_uint32(ndr, "unknown4", r->unknown4);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_QUOTA_LIMITS(struct ndr_push *ndr, int ndr_flags, const struct netr_QUOTA_LIMITS *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pagedpoollimit));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->nonpagedpoollimit));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minimumworkingsetsize));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maximumworkingsetsize));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pagefilelimit));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->timelimit));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_QUOTA_LIMITS(struct ndr_pull *ndr, int ndr_flags, struct netr_QUOTA_LIMITS *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pagedpoollimit));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->nonpagedpoollimit));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minimumworkingsetsize));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maximumworkingsetsize));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pagefilelimit));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->timelimit));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_QUOTA_LIMITS(struct ndr_print *ndr, const char *name, const struct netr_QUOTA_LIMITS *r)
+{
+ ndr_print_struct(ndr, name, "netr_QUOTA_LIMITS");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "pagedpoollimit", r->pagedpoollimit);
+ ndr_print_uint32(ndr, "nonpagedpoollimit", r->nonpagedpoollimit);
+ ndr_print_uint32(ndr, "minimumworkingsetsize", r->minimumworkingsetsize);
+ ndr_print_uint32(ndr, "maximumworkingsetsize", r->maximumworkingsetsize);
+ ndr_print_uint32(ndr, "pagefilelimit", r->pagefilelimit);
+ ndr_print_NTTIME(ndr, "timelimit", r->timelimit);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_POLICY(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_POLICY *r)
+{
+ uint32_t cntr_eventauditoptions_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxlogsize));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->auditretentionperiod));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->auditingmode));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxauditeventcount));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->eventauditoptions));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->primary_domain_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sid));
+ NDR_CHECK(ndr_push_netr_QUOTA_LIMITS(ndr, NDR_SCALARS, &r->quota_limits));
+ NDR_CHECK(ndr_push_udlong(ndr, NDR_SCALARS, r->sequence_num));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->db_create_time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->SecurityInformation));
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS, &r->sdbuf));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown5));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown6));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown7));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->eventauditoptions) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxauditeventcount + 1));
+ for (cntr_eventauditoptions_1 = 0; cntr_eventauditoptions_1 < r->maxauditeventcount + 1; cntr_eventauditoptions_1++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->eventauditoptions[cntr_eventauditoptions_1]));
+ }
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->primary_domain_name));
+ if (r->sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ }
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_BUFFERS, &r->sdbuf));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_POLICY(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_POLICY *r)
+{
+ uint32_t _ptr_eventauditoptions;
+ uint32_t cntr_eventauditoptions_1;
+ TALLOC_CTX *_mem_save_eventauditoptions_0;
+ TALLOC_CTX *_mem_save_eventauditoptions_1;
+ uint32_t _ptr_sid;
+ TALLOC_CTX *_mem_save_sid_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxlogsize));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->auditretentionperiod));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->auditingmode));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxauditeventcount));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_eventauditoptions));
+ if (_ptr_eventauditoptions) {
+ NDR_PULL_ALLOC(ndr, r->eventauditoptions);
+ } else {
+ r->eventauditoptions = NULL;
+ }
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->primary_domain_name));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sid));
+ if (_ptr_sid) {
+ NDR_PULL_ALLOC(ndr, r->sid);
+ } else {
+ r->sid = NULL;
+ }
+ NDR_CHECK(ndr_pull_netr_QUOTA_LIMITS(ndr, NDR_SCALARS, &r->quota_limits));
+ NDR_CHECK(ndr_pull_udlong(ndr, NDR_SCALARS, &r->sequence_num));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->db_create_time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->SecurityInformation));
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS, &r->sdbuf));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown5));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown6));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown7));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->eventauditoptions) {
+ _mem_save_eventauditoptions_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->eventauditoptions, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->eventauditoptions));
+ NDR_PULL_ALLOC_N(ndr, r->eventauditoptions, ndr_get_array_size(ndr, &r->eventauditoptions));
+ _mem_save_eventauditoptions_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->eventauditoptions, 0);
+ for (cntr_eventauditoptions_1 = 0; cntr_eventauditoptions_1 < r->maxauditeventcount + 1; cntr_eventauditoptions_1++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->eventauditoptions[cntr_eventauditoptions_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_eventauditoptions_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_eventauditoptions_0, 0);
+ }
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->primary_domain_name));
+ if (r->sid) {
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, 0);
+ }
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_BUFFERS, &r->sdbuf));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ if (r->eventauditoptions) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->eventauditoptions, r->maxauditeventcount + 1));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_POLICY(struct ndr_print *ndr, const char *name, const struct netr_DELTA_POLICY *r)
+{
+ uint32_t cntr_eventauditoptions_1;
+ ndr_print_struct(ndr, name, "netr_DELTA_POLICY");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "maxlogsize", r->maxlogsize);
+ ndr_print_NTTIME(ndr, "auditretentionperiod", r->auditretentionperiod);
+ ndr_print_uint8(ndr, "auditingmode", r->auditingmode);
+ ndr_print_uint32(ndr, "maxauditeventcount", r->maxauditeventcount);
+ ndr_print_ptr(ndr, "eventauditoptions", r->eventauditoptions);
+ ndr->depth++;
+ if (r->eventauditoptions) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "eventauditoptions", (int)r->maxauditeventcount + 1);
+ ndr->depth++;
+ for (cntr_eventauditoptions_1=0;cntr_eventauditoptions_1<r->maxauditeventcount + 1;cntr_eventauditoptions_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_eventauditoptions_1) != -1) {
+ ndr_print_uint32(ndr, "eventauditoptions", r->eventauditoptions[cntr_eventauditoptions_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_lsa_String(ndr, "primary_domain_name", &r->primary_domain_name);
+ ndr_print_ptr(ndr, "sid", r->sid);
+ ndr->depth++;
+ if (r->sid) {
+ ndr_print_dom_sid2(ndr, "sid", r->sid);
+ }
+ ndr->depth--;
+ ndr_print_netr_QUOTA_LIMITS(ndr, "quota_limits", &r->quota_limits);
+ ndr_print_udlong(ndr, "sequence_num", r->sequence_num);
+ ndr_print_NTTIME(ndr, "db_create_time", r->db_create_time);
+ ndr_print_uint32(ndr, "SecurityInformation", r->SecurityInformation);
+ ndr_print_sec_desc_buf(ndr, "sdbuf", &r->sdbuf);
+ ndr_print_lsa_String(ndr, "unknown1", &r->unknown1);
+ ndr_print_lsa_String(ndr, "unknown2", &r->unknown2);
+ ndr_print_lsa_String(ndr, "unknown3", &r->unknown3);
+ ndr_print_lsa_String(ndr, "unknown4", &r->unknown4);
+ ndr_print_uint32(ndr, "unknown5", r->unknown5);
+ ndr_print_uint32(ndr, "unknown6", r->unknown6);
+ ndr_print_uint32(ndr, "unknown7", r->unknown7);
+ ndr_print_uint32(ndr, "unknown8", r->unknown8);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_TRUSTED_DOMAIN(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_TRUSTED_DOMAIN *r)
+{
+ uint32_t cntr_controller_names_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->domain_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_controllers));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->controller_names));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->SecurityInformation));
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS, &r->sdbuf));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->posix_offset));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown6));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown7));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->domain_name));
+ if (r->controller_names) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_controllers));
+ for (cntr_controller_names_1 = 0; cntr_controller_names_1 < r->num_controllers; cntr_controller_names_1++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->controller_names[cntr_controller_names_1]));
+ }
+ for (cntr_controller_names_1 = 0; cntr_controller_names_1 < r->num_controllers; cntr_controller_names_1++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->controller_names[cntr_controller_names_1]));
+ }
+ }
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_BUFFERS, &r->sdbuf));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_TRUSTED_DOMAIN(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_TRUSTED_DOMAIN *r)
+{
+ uint32_t _ptr_controller_names;
+ uint32_t cntr_controller_names_1;
+ TALLOC_CTX *_mem_save_controller_names_0;
+ TALLOC_CTX *_mem_save_controller_names_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->domain_name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_controllers));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_controller_names));
+ if (_ptr_controller_names) {
+ NDR_PULL_ALLOC(ndr, r->controller_names);
+ } else {
+ r->controller_names = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->SecurityInformation));
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS, &r->sdbuf));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->posix_offset));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown6));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown7));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->domain_name));
+ if (r->controller_names) {
+ _mem_save_controller_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->controller_names, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->controller_names));
+ NDR_PULL_ALLOC_N(ndr, r->controller_names, ndr_get_array_size(ndr, &r->controller_names));
+ _mem_save_controller_names_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->controller_names, 0);
+ for (cntr_controller_names_1 = 0; cntr_controller_names_1 < r->num_controllers; cntr_controller_names_1++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->controller_names[cntr_controller_names_1]));
+ }
+ for (cntr_controller_names_1 = 0; cntr_controller_names_1 < r->num_controllers; cntr_controller_names_1++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->controller_names[cntr_controller_names_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_controller_names_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_controller_names_0, 0);
+ }
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_BUFFERS, &r->sdbuf));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ if (r->controller_names) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->controller_names, r->num_controllers));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_TRUSTED_DOMAIN(struct ndr_print *ndr, const char *name, const struct netr_DELTA_TRUSTED_DOMAIN *r)
+{
+ uint32_t cntr_controller_names_1;
+ ndr_print_struct(ndr, name, "netr_DELTA_TRUSTED_DOMAIN");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "domain_name", &r->domain_name);
+ ndr_print_uint32(ndr, "num_controllers", r->num_controllers);
+ ndr_print_ptr(ndr, "controller_names", r->controller_names);
+ ndr->depth++;
+ if (r->controller_names) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "controller_names", (int)r->num_controllers);
+ ndr->depth++;
+ for (cntr_controller_names_1=0;cntr_controller_names_1<r->num_controllers;cntr_controller_names_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_controller_names_1) != -1) {
+ ndr_print_lsa_String(ndr, "controller_names", &r->controller_names[cntr_controller_names_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "SecurityInformation", r->SecurityInformation);
+ ndr_print_sec_desc_buf(ndr, "sdbuf", &r->sdbuf);
+ ndr_print_lsa_String(ndr, "unknown1", &r->unknown1);
+ ndr_print_lsa_String(ndr, "unknown2", &r->unknown2);
+ ndr_print_lsa_String(ndr, "unknown3", &r->unknown3);
+ ndr_print_lsa_String(ndr, "unknown4", &r->unknown4);
+ ndr_print_uint32(ndr, "posix_offset", r->posix_offset);
+ ndr_print_uint32(ndr, "unknown6", r->unknown6);
+ ndr_print_uint32(ndr, "unknown7", r->unknown7);
+ ndr_print_uint32(ndr, "unknown8", r->unknown8);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_DELETE_TRUST(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_DELETE_TRUST *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_DELETE_TRUST(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_DELETE_TRUST *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_DELETE_TRUST(struct ndr_print *ndr, const char *name, const struct netr_DELTA_DELETE_TRUST *r)
+{
+ ndr_print_struct(ndr, name, "netr_DELTA_DELETE_TRUST");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "unknown", r->unknown);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_ACCOUNT(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_ACCOUNT *r)
+{
+ uint32_t cntr_privilege_attrib_1;
+ uint32_t cntr_privilege_name_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->privilege_entries));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->privilege_control));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->privilege_attrib));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->privilege_name));
+ NDR_CHECK(ndr_push_netr_QUOTA_LIMITS(ndr, NDR_SCALARS, &r->quotalimits));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->system_flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->SecurityInformation));
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS, &r->sdbuf));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown5));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown6));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown7));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->privilege_attrib) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->privilege_entries));
+ for (cntr_privilege_attrib_1 = 0; cntr_privilege_attrib_1 < r->privilege_entries; cntr_privilege_attrib_1++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->privilege_attrib[cntr_privilege_attrib_1]));
+ }
+ }
+ if (r->privilege_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->privilege_entries));
+ for (cntr_privilege_name_1 = 0; cntr_privilege_name_1 < r->privilege_entries; cntr_privilege_name_1++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->privilege_name[cntr_privilege_name_1]));
+ }
+ for (cntr_privilege_name_1 = 0; cntr_privilege_name_1 < r->privilege_entries; cntr_privilege_name_1++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->privilege_name[cntr_privilege_name_1]));
+ }
+ }
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_BUFFERS, &r->sdbuf));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_ACCOUNT(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_ACCOUNT *r)
+{
+ uint32_t _ptr_privilege_attrib;
+ uint32_t cntr_privilege_attrib_1;
+ TALLOC_CTX *_mem_save_privilege_attrib_0;
+ TALLOC_CTX *_mem_save_privilege_attrib_1;
+ uint32_t _ptr_privilege_name;
+ uint32_t cntr_privilege_name_1;
+ TALLOC_CTX *_mem_save_privilege_name_0;
+ TALLOC_CTX *_mem_save_privilege_name_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->privilege_entries));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->privilege_control));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_privilege_attrib));
+ if (_ptr_privilege_attrib) {
+ NDR_PULL_ALLOC(ndr, r->privilege_attrib);
+ } else {
+ r->privilege_attrib = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_privilege_name));
+ if (_ptr_privilege_name) {
+ NDR_PULL_ALLOC(ndr, r->privilege_name);
+ } else {
+ r->privilege_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_netr_QUOTA_LIMITS(ndr, NDR_SCALARS, &r->quotalimits));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->system_flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->SecurityInformation));
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS, &r->sdbuf));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown5));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown6));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown7));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->privilege_attrib) {
+ _mem_save_privilege_attrib_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->privilege_attrib, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->privilege_attrib));
+ NDR_PULL_ALLOC_N(ndr, r->privilege_attrib, ndr_get_array_size(ndr, &r->privilege_attrib));
+ _mem_save_privilege_attrib_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->privilege_attrib, 0);
+ for (cntr_privilege_attrib_1 = 0; cntr_privilege_attrib_1 < r->privilege_entries; cntr_privilege_attrib_1++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->privilege_attrib[cntr_privilege_attrib_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_privilege_attrib_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_privilege_attrib_0, 0);
+ }
+ if (r->privilege_name) {
+ _mem_save_privilege_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->privilege_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->privilege_name));
+ NDR_PULL_ALLOC_N(ndr, r->privilege_name, ndr_get_array_size(ndr, &r->privilege_name));
+ _mem_save_privilege_name_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->privilege_name, 0);
+ for (cntr_privilege_name_1 = 0; cntr_privilege_name_1 < r->privilege_entries; cntr_privilege_name_1++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->privilege_name[cntr_privilege_name_1]));
+ }
+ for (cntr_privilege_name_1 = 0; cntr_privilege_name_1 < r->privilege_entries; cntr_privilege_name_1++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->privilege_name[cntr_privilege_name_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_privilege_name_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_privilege_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_BUFFERS, &r->sdbuf));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ if (r->privilege_attrib) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->privilege_attrib, r->privilege_entries));
+ }
+ if (r->privilege_name) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->privilege_name, r->privilege_entries));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_ACCOUNT(struct ndr_print *ndr, const char *name, const struct netr_DELTA_ACCOUNT *r)
+{
+ uint32_t cntr_privilege_attrib_1;
+ uint32_t cntr_privilege_name_1;
+ ndr_print_struct(ndr, name, "netr_DELTA_ACCOUNT");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "privilege_entries", r->privilege_entries);
+ ndr_print_uint32(ndr, "privilege_control", r->privilege_control);
+ ndr_print_ptr(ndr, "privilege_attrib", r->privilege_attrib);
+ ndr->depth++;
+ if (r->privilege_attrib) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "privilege_attrib", (int)r->privilege_entries);
+ ndr->depth++;
+ for (cntr_privilege_attrib_1=0;cntr_privilege_attrib_1<r->privilege_entries;cntr_privilege_attrib_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_privilege_attrib_1) != -1) {
+ ndr_print_uint32(ndr, "privilege_attrib", r->privilege_attrib[cntr_privilege_attrib_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "privilege_name", r->privilege_name);
+ ndr->depth++;
+ if (r->privilege_name) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "privilege_name", (int)r->privilege_entries);
+ ndr->depth++;
+ for (cntr_privilege_name_1=0;cntr_privilege_name_1<r->privilege_entries;cntr_privilege_name_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_privilege_name_1) != -1) {
+ ndr_print_lsa_String(ndr, "privilege_name", &r->privilege_name[cntr_privilege_name_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_netr_QUOTA_LIMITS(ndr, "quotalimits", &r->quotalimits);
+ ndr_print_uint32(ndr, "system_flags", r->system_flags);
+ ndr_print_uint32(ndr, "SecurityInformation", r->SecurityInformation);
+ ndr_print_sec_desc_buf(ndr, "sdbuf", &r->sdbuf);
+ ndr_print_lsa_String(ndr, "unknown1", &r->unknown1);
+ ndr_print_lsa_String(ndr, "unknown2", &r->unknown2);
+ ndr_print_lsa_String(ndr, "unknown3", &r->unknown3);
+ ndr_print_lsa_String(ndr, "unknown4", &r->unknown4);
+ ndr_print_uint32(ndr, "unknown5", r->unknown5);
+ ndr_print_uint32(ndr, "unknown6", r->unknown6);
+ ndr_print_uint32(ndr, "unknown7", r->unknown7);
+ ndr_print_uint32(ndr, "unknown8", r->unknown8);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_DELETE_ACCOUNT(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_DELETE_ACCOUNT *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_DELETE_ACCOUNT(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_DELETE_ACCOUNT *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_DELETE_ACCOUNT(struct ndr_print *ndr, const char *name, const struct netr_DELTA_DELETE_ACCOUNT *r)
+{
+ ndr_print_struct(ndr, name, "netr_DELTA_DELETE_ACCOUNT");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "unknown", r->unknown);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_DELETE_SECRET(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_DELETE_SECRET *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_DELETE_SECRET(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_DELETE_SECRET *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 2));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_DELETE_SECRET(struct ndr_print *ndr, const char *name, const struct netr_DELTA_DELETE_SECRET *r)
+{
+ ndr_print_struct(ndr, name, "netr_DELTA_DELETE_SECRET");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "unknown", r->unknown);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_CIPHER_VALUE(struct ndr_push *ndr, int ndr_flags, const struct netr_CIPHER_VALUE *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->len));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxlen));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->cipher_data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->cipher_data) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxlen));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->len));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->cipher_data, r->len));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_CIPHER_VALUE(struct ndr_pull *ndr, int ndr_flags, struct netr_CIPHER_VALUE *r)
+{
+ uint32_t _ptr_cipher_data;
+ TALLOC_CTX *_mem_save_cipher_data_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->len));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxlen));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_cipher_data));
+ if (_ptr_cipher_data) {
+ NDR_PULL_ALLOC(ndr, r->cipher_data);
+ } else {
+ r->cipher_data = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->cipher_data) {
+ _mem_save_cipher_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->cipher_data, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->cipher_data));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->cipher_data));
+ if (ndr_get_array_length(ndr, &r->cipher_data) > ndr_get_array_size(ndr, &r->cipher_data)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->cipher_data), ndr_get_array_length(ndr, &r->cipher_data));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->cipher_data, ndr_get_array_size(ndr, &r->cipher_data));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->cipher_data, ndr_get_array_length(ndr, &r->cipher_data)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cipher_data_0, 0);
+ }
+ if (r->cipher_data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->cipher_data, r->maxlen));
+ }
+ if (r->cipher_data) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->cipher_data, r->len));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_CIPHER_VALUE(struct ndr_print *ndr, const char *name, const struct netr_CIPHER_VALUE *r)
+{
+ ndr_print_struct(ndr, name, "netr_CIPHER_VALUE");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "len", r->len);
+ ndr_print_uint32(ndr, "maxlen", r->maxlen);
+ ndr_print_ptr(ndr, "cipher_data", r->cipher_data);
+ ndr->depth++;
+ if (r->cipher_data) {
+ ndr_print_array_uint8(ndr, "cipher_data", r->cipher_data, r->len);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_SECRET(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_SECRET *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netr_CIPHER_VALUE(ndr, NDR_SCALARS, &r->current_cipher));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->current_cipher_set_time));
+ NDR_CHECK(ndr_push_netr_CIPHER_VALUE(ndr, NDR_SCALARS, &r->old_cipher));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->old_cipher_set_time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->SecurityInformation));
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS, &r->sdbuf));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown5));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown6));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown7));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_netr_CIPHER_VALUE(ndr, NDR_BUFFERS, &r->current_cipher));
+ NDR_CHECK(ndr_push_netr_CIPHER_VALUE(ndr, NDR_BUFFERS, &r->old_cipher));
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_BUFFERS, &r->sdbuf));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_SECRET(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_SECRET *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netr_CIPHER_VALUE(ndr, NDR_SCALARS, &r->current_cipher));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->current_cipher_set_time));
+ NDR_CHECK(ndr_pull_netr_CIPHER_VALUE(ndr, NDR_SCALARS, &r->old_cipher));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->old_cipher_set_time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->SecurityInformation));
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS, &r->sdbuf));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown5));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown6));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown7));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_netr_CIPHER_VALUE(ndr, NDR_BUFFERS, &r->current_cipher));
+ NDR_CHECK(ndr_pull_netr_CIPHER_VALUE(ndr, NDR_BUFFERS, &r->old_cipher));
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_BUFFERS, &r->sdbuf));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown4));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_SECRET(struct ndr_print *ndr, const char *name, const struct netr_DELTA_SECRET *r)
+{
+ ndr_print_struct(ndr, name, "netr_DELTA_SECRET");
+ ndr->depth++;
+ ndr_print_netr_CIPHER_VALUE(ndr, "current_cipher", &r->current_cipher);
+ ndr_print_NTTIME(ndr, "current_cipher_set_time", r->current_cipher_set_time);
+ ndr_print_netr_CIPHER_VALUE(ndr, "old_cipher", &r->old_cipher);
+ ndr_print_NTTIME(ndr, "old_cipher_set_time", r->old_cipher_set_time);
+ ndr_print_uint32(ndr, "SecurityInformation", r->SecurityInformation);
+ ndr_print_sec_desc_buf(ndr, "sdbuf", &r->sdbuf);
+ ndr_print_lsa_String(ndr, "unknown1", &r->unknown1);
+ ndr_print_lsa_String(ndr, "unknown2", &r->unknown2);
+ ndr_print_lsa_String(ndr, "unknown3", &r->unknown3);
+ ndr_print_lsa_String(ndr, "unknown4", &r->unknown4);
+ ndr_print_uint32(ndr, "unknown5", r->unknown5);
+ ndr_print_uint32(ndr, "unknown6", r->unknown6);
+ ndr_print_uint32(ndr, "unknown7", r->unknown7);
+ ndr_print_uint32(ndr, "unknown8", r->unknown8);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DeltaEnum(struct ndr_push *ndr, int ndr_flags, enum netr_DeltaEnum r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DeltaEnum(struct ndr_pull *ndr, int ndr_flags, enum netr_DeltaEnum *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DeltaEnum(struct ndr_print *ndr, const char *name, enum netr_DeltaEnum r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case NETR_DELTA_DOMAIN: val = "NETR_DELTA_DOMAIN"; break;
+ case NETR_DELTA_GROUP: val = "NETR_DELTA_GROUP"; break;
+ case NETR_DELTA_DELETE_GROUP: val = "NETR_DELTA_DELETE_GROUP"; break;
+ case NETR_DELTA_RENAME_GROUP: val = "NETR_DELTA_RENAME_GROUP"; break;
+ case NETR_DELTA_USER: val = "NETR_DELTA_USER"; break;
+ case NETR_DELTA_DELETE_USER: val = "NETR_DELTA_DELETE_USER"; break;
+ case NETR_DELTA_RENAME_USER: val = "NETR_DELTA_RENAME_USER"; break;
+ case NETR_DELTA_GROUP_MEMBER: val = "NETR_DELTA_GROUP_MEMBER"; break;
+ case NETR_DELTA_ALIAS: val = "NETR_DELTA_ALIAS"; break;
+ case NETR_DELTA_DELETE_ALIAS: val = "NETR_DELTA_DELETE_ALIAS"; break;
+ case NETR_DELTA_RENAME_ALIAS: val = "NETR_DELTA_RENAME_ALIAS"; break;
+ case NETR_DELTA_ALIAS_MEMBER: val = "NETR_DELTA_ALIAS_MEMBER"; break;
+ case NETR_DELTA_POLICY: val = "NETR_DELTA_POLICY"; break;
+ case NETR_DELTA_TRUSTED_DOMAIN: val = "NETR_DELTA_TRUSTED_DOMAIN"; break;
+ case NETR_DELTA_DELETE_TRUST: val = "NETR_DELTA_DELETE_TRUST"; break;
+ case NETR_DELTA_ACCOUNT: val = "NETR_DELTA_ACCOUNT"; break;
+ case NETR_DELTA_DELETE_ACCOUNT: val = "NETR_DELTA_DELETE_ACCOUNT"; break;
+ case NETR_DELTA_SECRET: val = "NETR_DELTA_SECRET"; break;
+ case NETR_DELTA_DELETE_SECRET: val = "NETR_DELTA_DELETE_SECRET"; break;
+ case NETR_DELTA_DELETE_GROUP2: val = "NETR_DELTA_DELETE_GROUP2"; break;
+ case NETR_DELTA_DELETE_USER2: val = "NETR_DELTA_DELETE_USER2"; break;
+ case NETR_DELTA_MODIFY_COUNT: val = "NETR_DELTA_MODIFY_COUNT"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_UNION(struct ndr_push *ndr, int ndr_flags, const union netr_DELTA_UNION *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_netr_DeltaEnum(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case NETR_DELTA_DOMAIN: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain));
+ break; }
+
+ case NETR_DELTA_GROUP: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->group));
+ break; }
+
+ case NETR_DELTA_DELETE_GROUP: {
+ break; }
+
+ case NETR_DELTA_RENAME_GROUP: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->rename_group));
+ break; }
+
+ case NETR_DELTA_USER: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->user));
+ break; }
+
+ case NETR_DELTA_DELETE_USER: {
+ break; }
+
+ case NETR_DELTA_RENAME_USER: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->rename_user));
+ break; }
+
+ case NETR_DELTA_GROUP_MEMBER: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->group_member));
+ break; }
+
+ case NETR_DELTA_ALIAS: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->alias));
+ break; }
+
+ case NETR_DELTA_DELETE_ALIAS: {
+ break; }
+
+ case NETR_DELTA_RENAME_ALIAS: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->rename_alias));
+ break; }
+
+ case NETR_DELTA_ALIAS_MEMBER: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->alias_member));
+ break; }
+
+ case NETR_DELTA_POLICY: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->policy));
+ break; }
+
+ case NETR_DELTA_TRUSTED_DOMAIN: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->trusted_domain));
+ break; }
+
+ case NETR_DELTA_DELETE_TRUST: {
+ NDR_CHECK(ndr_push_netr_DELTA_DELETE_TRUST(ndr, NDR_SCALARS, &r->delete_trust));
+ break; }
+
+ case NETR_DELTA_ACCOUNT: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->account));
+ break; }
+
+ case NETR_DELTA_DELETE_ACCOUNT: {
+ NDR_CHECK(ndr_push_netr_DELTA_DELETE_ACCOUNT(ndr, NDR_SCALARS, &r->delete_account));
+ break; }
+
+ case NETR_DELTA_SECRET: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->secret));
+ break; }
+
+ case NETR_DELTA_DELETE_SECRET: {
+ NDR_CHECK(ndr_push_netr_DELTA_DELETE_SECRET(ndr, NDR_SCALARS, &r->delete_secret));
+ break; }
+
+ case NETR_DELTA_DELETE_GROUP2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->delete_group));
+ break; }
+
+ case NETR_DELTA_DELETE_USER2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->delete_user));
+ break; }
+
+ case NETR_DELTA_MODIFY_COUNT: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->modified_count));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case NETR_DELTA_DOMAIN:
+ if (r->domain) {
+ NDR_CHECK(ndr_push_netr_DELTA_DOMAIN(ndr, NDR_SCALARS|NDR_BUFFERS, r->domain));
+ }
+ break;
+
+ case NETR_DELTA_GROUP:
+ if (r->group) {
+ NDR_CHECK(ndr_push_netr_DELTA_GROUP(ndr, NDR_SCALARS|NDR_BUFFERS, r->group));
+ }
+ break;
+
+ case NETR_DELTA_DELETE_GROUP:
+ break;
+
+ case NETR_DELTA_RENAME_GROUP:
+ if (r->rename_group) {
+ NDR_CHECK(ndr_push_netr_DELTA_RENAME(ndr, NDR_SCALARS|NDR_BUFFERS, r->rename_group));
+ }
+ break;
+
+ case NETR_DELTA_USER:
+ if (r->user) {
+ NDR_CHECK(ndr_push_netr_DELTA_USER(ndr, NDR_SCALARS|NDR_BUFFERS, r->user));
+ }
+ break;
+
+ case NETR_DELTA_DELETE_USER:
+ break;
+
+ case NETR_DELTA_RENAME_USER:
+ if (r->rename_user) {
+ NDR_CHECK(ndr_push_netr_DELTA_RENAME(ndr, NDR_SCALARS|NDR_BUFFERS, r->rename_user));
+ }
+ break;
+
+ case NETR_DELTA_GROUP_MEMBER:
+ if (r->group_member) {
+ NDR_CHECK(ndr_push_netr_DELTA_GROUP_MEMBER(ndr, NDR_SCALARS|NDR_BUFFERS, r->group_member));
+ }
+ break;
+
+ case NETR_DELTA_ALIAS:
+ if (r->alias) {
+ NDR_CHECK(ndr_push_netr_DELTA_ALIAS(ndr, NDR_SCALARS|NDR_BUFFERS, r->alias));
+ }
+ break;
+
+ case NETR_DELTA_DELETE_ALIAS:
+ break;
+
+ case NETR_DELTA_RENAME_ALIAS:
+ if (r->rename_alias) {
+ NDR_CHECK(ndr_push_netr_DELTA_RENAME(ndr, NDR_SCALARS|NDR_BUFFERS, r->rename_alias));
+ }
+ break;
+
+ case NETR_DELTA_ALIAS_MEMBER:
+ if (r->alias_member) {
+ NDR_CHECK(ndr_push_netr_DELTA_ALIAS_MEMBER(ndr, NDR_SCALARS|NDR_BUFFERS, r->alias_member));
+ }
+ break;
+
+ case NETR_DELTA_POLICY:
+ if (r->policy) {
+ NDR_CHECK(ndr_push_netr_DELTA_POLICY(ndr, NDR_SCALARS|NDR_BUFFERS, r->policy));
+ }
+ break;
+
+ case NETR_DELTA_TRUSTED_DOMAIN:
+ if (r->trusted_domain) {
+ NDR_CHECK(ndr_push_netr_DELTA_TRUSTED_DOMAIN(ndr, NDR_SCALARS|NDR_BUFFERS, r->trusted_domain));
+ }
+ break;
+
+ case NETR_DELTA_DELETE_TRUST:
+ break;
+
+ case NETR_DELTA_ACCOUNT:
+ if (r->account) {
+ NDR_CHECK(ndr_push_netr_DELTA_ACCOUNT(ndr, NDR_SCALARS|NDR_BUFFERS, r->account));
+ }
+ break;
+
+ case NETR_DELTA_DELETE_ACCOUNT:
+ break;
+
+ case NETR_DELTA_SECRET:
+ if (r->secret) {
+ NDR_CHECK(ndr_push_netr_DELTA_SECRET(ndr, NDR_SCALARS|NDR_BUFFERS, r->secret));
+ }
+ break;
+
+ case NETR_DELTA_DELETE_SECRET:
+ break;
+
+ case NETR_DELTA_DELETE_GROUP2:
+ if (r->delete_group) {
+ NDR_CHECK(ndr_push_netr_DELTA_DELETE_USER(ndr, NDR_SCALARS|NDR_BUFFERS, r->delete_group));
+ }
+ break;
+
+ case NETR_DELTA_DELETE_USER2:
+ if (r->delete_user) {
+ NDR_CHECK(ndr_push_netr_DELTA_DELETE_USER(ndr, NDR_SCALARS|NDR_BUFFERS, r->delete_user));
+ }
+ break;
+
+ case NETR_DELTA_MODIFY_COUNT:
+ if (r->modified_count) {
+ NDR_CHECK(ndr_push_udlong(ndr, NDR_SCALARS, *r->modified_count));
+ }
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_UNION(struct ndr_pull *ndr, int ndr_flags, union netr_DELTA_UNION *r)
+{
+ int level;
+ uint16_t _level;
+ TALLOC_CTX *_mem_save_domain_0;
+ TALLOC_CTX *_mem_save_group_0;
+ TALLOC_CTX *_mem_save_rename_group_0;
+ TALLOC_CTX *_mem_save_user_0;
+ TALLOC_CTX *_mem_save_rename_user_0;
+ TALLOC_CTX *_mem_save_group_member_0;
+ TALLOC_CTX *_mem_save_alias_0;
+ TALLOC_CTX *_mem_save_rename_alias_0;
+ TALLOC_CTX *_mem_save_alias_member_0;
+ TALLOC_CTX *_mem_save_policy_0;
+ TALLOC_CTX *_mem_save_trusted_domain_0;
+ TALLOC_CTX *_mem_save_account_0;
+ TALLOC_CTX *_mem_save_secret_0;
+ TALLOC_CTX *_mem_save_delete_group_0;
+ TALLOC_CTX *_mem_save_delete_user_0;
+ TALLOC_CTX *_mem_save_modified_count_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case NETR_DELTA_DOMAIN: {
+ uint32_t _ptr_domain;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain));
+ if (_ptr_domain) {
+ NDR_PULL_ALLOC(ndr, r->domain);
+ } else {
+ r->domain = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_GROUP: {
+ uint32_t _ptr_group;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_group));
+ if (_ptr_group) {
+ NDR_PULL_ALLOC(ndr, r->group);
+ } else {
+ r->group = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_DELETE_GROUP: {
+ break; }
+
+ case NETR_DELTA_RENAME_GROUP: {
+ uint32_t _ptr_rename_group;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_rename_group));
+ if (_ptr_rename_group) {
+ NDR_PULL_ALLOC(ndr, r->rename_group);
+ } else {
+ r->rename_group = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_USER: {
+ uint32_t _ptr_user;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user));
+ if (_ptr_user) {
+ NDR_PULL_ALLOC(ndr, r->user);
+ } else {
+ r->user = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_DELETE_USER: {
+ break; }
+
+ case NETR_DELTA_RENAME_USER: {
+ uint32_t _ptr_rename_user;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_rename_user));
+ if (_ptr_rename_user) {
+ NDR_PULL_ALLOC(ndr, r->rename_user);
+ } else {
+ r->rename_user = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_GROUP_MEMBER: {
+ uint32_t _ptr_group_member;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_group_member));
+ if (_ptr_group_member) {
+ NDR_PULL_ALLOC(ndr, r->group_member);
+ } else {
+ r->group_member = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_ALIAS: {
+ uint32_t _ptr_alias;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_alias));
+ if (_ptr_alias) {
+ NDR_PULL_ALLOC(ndr, r->alias);
+ } else {
+ r->alias = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_DELETE_ALIAS: {
+ break; }
+
+ case NETR_DELTA_RENAME_ALIAS: {
+ uint32_t _ptr_rename_alias;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_rename_alias));
+ if (_ptr_rename_alias) {
+ NDR_PULL_ALLOC(ndr, r->rename_alias);
+ } else {
+ r->rename_alias = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_ALIAS_MEMBER: {
+ uint32_t _ptr_alias_member;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_alias_member));
+ if (_ptr_alias_member) {
+ NDR_PULL_ALLOC(ndr, r->alias_member);
+ } else {
+ r->alias_member = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_POLICY: {
+ uint32_t _ptr_policy;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_policy));
+ if (_ptr_policy) {
+ NDR_PULL_ALLOC(ndr, r->policy);
+ } else {
+ r->policy = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_TRUSTED_DOMAIN: {
+ uint32_t _ptr_trusted_domain;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_trusted_domain));
+ if (_ptr_trusted_domain) {
+ NDR_PULL_ALLOC(ndr, r->trusted_domain);
+ } else {
+ r->trusted_domain = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_DELETE_TRUST: {
+ NDR_CHECK(ndr_pull_netr_DELTA_DELETE_TRUST(ndr, NDR_SCALARS, &r->delete_trust));
+ break; }
+
+ case NETR_DELTA_ACCOUNT: {
+ uint32_t _ptr_account;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_account));
+ if (_ptr_account) {
+ NDR_PULL_ALLOC(ndr, r->account);
+ } else {
+ r->account = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_DELETE_ACCOUNT: {
+ NDR_CHECK(ndr_pull_netr_DELTA_DELETE_ACCOUNT(ndr, NDR_SCALARS, &r->delete_account));
+ break; }
+
+ case NETR_DELTA_SECRET: {
+ uint32_t _ptr_secret;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_secret));
+ if (_ptr_secret) {
+ NDR_PULL_ALLOC(ndr, r->secret);
+ } else {
+ r->secret = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_DELETE_SECRET: {
+ NDR_CHECK(ndr_pull_netr_DELTA_DELETE_SECRET(ndr, NDR_SCALARS, &r->delete_secret));
+ break; }
+
+ case NETR_DELTA_DELETE_GROUP2: {
+ uint32_t _ptr_delete_group;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_delete_group));
+ if (_ptr_delete_group) {
+ NDR_PULL_ALLOC(ndr, r->delete_group);
+ } else {
+ r->delete_group = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_DELETE_USER2: {
+ uint32_t _ptr_delete_user;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_delete_user));
+ if (_ptr_delete_user) {
+ NDR_PULL_ALLOC(ndr, r->delete_user);
+ } else {
+ r->delete_user = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_MODIFY_COUNT: {
+ uint32_t _ptr_modified_count;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_modified_count));
+ if (_ptr_modified_count) {
+ NDR_PULL_ALLOC(ndr, r->modified_count);
+ } else {
+ r->modified_count = NULL;
+ }
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case NETR_DELTA_DOMAIN:
+ if (r->domain) {
+ _mem_save_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_DOMAIN(ndr, NDR_SCALARS|NDR_BUFFERS, r->domain));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_GROUP:
+ if (r->group) {
+ _mem_save_group_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->group, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_GROUP(ndr, NDR_SCALARS|NDR_BUFFERS, r->group));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_DELETE_GROUP:
+ break;
+
+ case NETR_DELTA_RENAME_GROUP:
+ if (r->rename_group) {
+ _mem_save_rename_group_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->rename_group, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_RENAME(ndr, NDR_SCALARS|NDR_BUFFERS, r->rename_group));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rename_group_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_USER:
+ if (r->user) {
+ _mem_save_user_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_USER(ndr, NDR_SCALARS|NDR_BUFFERS, r->user));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_DELETE_USER:
+ break;
+
+ case NETR_DELTA_RENAME_USER:
+ if (r->rename_user) {
+ _mem_save_rename_user_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->rename_user, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_RENAME(ndr, NDR_SCALARS|NDR_BUFFERS, r->rename_user));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rename_user_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_GROUP_MEMBER:
+ if (r->group_member) {
+ _mem_save_group_member_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->group_member, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_GROUP_MEMBER(ndr, NDR_SCALARS|NDR_BUFFERS, r->group_member));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_member_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_ALIAS:
+ if (r->alias) {
+ _mem_save_alias_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->alias, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_ALIAS(ndr, NDR_SCALARS|NDR_BUFFERS, r->alias));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alias_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_DELETE_ALIAS:
+ break;
+
+ case NETR_DELTA_RENAME_ALIAS:
+ if (r->rename_alias) {
+ _mem_save_rename_alias_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->rename_alias, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_RENAME(ndr, NDR_SCALARS|NDR_BUFFERS, r->rename_alias));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rename_alias_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_ALIAS_MEMBER:
+ if (r->alias_member) {
+ _mem_save_alias_member_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->alias_member, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_ALIAS_MEMBER(ndr, NDR_SCALARS|NDR_BUFFERS, r->alias_member));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alias_member_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_POLICY:
+ if (r->policy) {
+ _mem_save_policy_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->policy, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_POLICY(ndr, NDR_SCALARS|NDR_BUFFERS, r->policy));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_policy_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_TRUSTED_DOMAIN:
+ if (r->trusted_domain) {
+ _mem_save_trusted_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->trusted_domain, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_TRUSTED_DOMAIN(ndr, NDR_SCALARS|NDR_BUFFERS, r->trusted_domain));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_trusted_domain_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_DELETE_TRUST:
+ break;
+
+ case NETR_DELTA_ACCOUNT:
+ if (r->account) {
+ _mem_save_account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->account, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_ACCOUNT(ndr, NDR_SCALARS|NDR_BUFFERS, r->account));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_account_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_DELETE_ACCOUNT:
+ break;
+
+ case NETR_DELTA_SECRET:
+ if (r->secret) {
+ _mem_save_secret_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->secret, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_SECRET(ndr, NDR_SCALARS|NDR_BUFFERS, r->secret));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_secret_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_DELETE_SECRET:
+ break;
+
+ case NETR_DELTA_DELETE_GROUP2:
+ if (r->delete_group) {
+ _mem_save_delete_group_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->delete_group, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_DELETE_USER(ndr, NDR_SCALARS|NDR_BUFFERS, r->delete_group));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_delete_group_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_DELETE_USER2:
+ if (r->delete_user) {
+ _mem_save_delete_user_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->delete_user, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_DELETE_USER(ndr, NDR_SCALARS|NDR_BUFFERS, r->delete_user));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_delete_user_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_MODIFY_COUNT:
+ if (r->modified_count) {
+ _mem_save_modified_count_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->modified_count, 0);
+ NDR_CHECK(ndr_pull_udlong(ndr, NDR_SCALARS, r->modified_count));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_modified_count_0, 0);
+ }
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_UNION(struct ndr_print *ndr, const char *name, const union netr_DELTA_UNION *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "netr_DELTA_UNION");
+ switch (level) {
+ case NETR_DELTA_DOMAIN:
+ ndr_print_ptr(ndr, "domain", r->domain);
+ ndr->depth++;
+ if (r->domain) {
+ ndr_print_netr_DELTA_DOMAIN(ndr, "domain", r->domain);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_GROUP:
+ ndr_print_ptr(ndr, "group", r->group);
+ ndr->depth++;
+ if (r->group) {
+ ndr_print_netr_DELTA_GROUP(ndr, "group", r->group);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_DELETE_GROUP:
+ break;
+
+ case NETR_DELTA_RENAME_GROUP:
+ ndr_print_ptr(ndr, "rename_group", r->rename_group);
+ ndr->depth++;
+ if (r->rename_group) {
+ ndr_print_netr_DELTA_RENAME(ndr, "rename_group", r->rename_group);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_USER:
+ ndr_print_ptr(ndr, "user", r->user);
+ ndr->depth++;
+ if (r->user) {
+ ndr_print_netr_DELTA_USER(ndr, "user", r->user);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_DELETE_USER:
+ break;
+
+ case NETR_DELTA_RENAME_USER:
+ ndr_print_ptr(ndr, "rename_user", r->rename_user);
+ ndr->depth++;
+ if (r->rename_user) {
+ ndr_print_netr_DELTA_RENAME(ndr, "rename_user", r->rename_user);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_GROUP_MEMBER:
+ ndr_print_ptr(ndr, "group_member", r->group_member);
+ ndr->depth++;
+ if (r->group_member) {
+ ndr_print_netr_DELTA_GROUP_MEMBER(ndr, "group_member", r->group_member);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_ALIAS:
+ ndr_print_ptr(ndr, "alias", r->alias);
+ ndr->depth++;
+ if (r->alias) {
+ ndr_print_netr_DELTA_ALIAS(ndr, "alias", r->alias);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_DELETE_ALIAS:
+ break;
+
+ case NETR_DELTA_RENAME_ALIAS:
+ ndr_print_ptr(ndr, "rename_alias", r->rename_alias);
+ ndr->depth++;
+ if (r->rename_alias) {
+ ndr_print_netr_DELTA_RENAME(ndr, "rename_alias", r->rename_alias);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_ALIAS_MEMBER:
+ ndr_print_ptr(ndr, "alias_member", r->alias_member);
+ ndr->depth++;
+ if (r->alias_member) {
+ ndr_print_netr_DELTA_ALIAS_MEMBER(ndr, "alias_member", r->alias_member);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_POLICY:
+ ndr_print_ptr(ndr, "policy", r->policy);
+ ndr->depth++;
+ if (r->policy) {
+ ndr_print_netr_DELTA_POLICY(ndr, "policy", r->policy);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_TRUSTED_DOMAIN:
+ ndr_print_ptr(ndr, "trusted_domain", r->trusted_domain);
+ ndr->depth++;
+ if (r->trusted_domain) {
+ ndr_print_netr_DELTA_TRUSTED_DOMAIN(ndr, "trusted_domain", r->trusted_domain);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_DELETE_TRUST:
+ ndr_print_netr_DELTA_DELETE_TRUST(ndr, "delete_trust", &r->delete_trust);
+ break;
+
+ case NETR_DELTA_ACCOUNT:
+ ndr_print_ptr(ndr, "account", r->account);
+ ndr->depth++;
+ if (r->account) {
+ ndr_print_netr_DELTA_ACCOUNT(ndr, "account", r->account);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_DELETE_ACCOUNT:
+ ndr_print_netr_DELTA_DELETE_ACCOUNT(ndr, "delete_account", &r->delete_account);
+ break;
+
+ case NETR_DELTA_SECRET:
+ ndr_print_ptr(ndr, "secret", r->secret);
+ ndr->depth++;
+ if (r->secret) {
+ ndr_print_netr_DELTA_SECRET(ndr, "secret", r->secret);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_DELETE_SECRET:
+ ndr_print_netr_DELTA_DELETE_SECRET(ndr, "delete_secret", &r->delete_secret);
+ break;
+
+ case NETR_DELTA_DELETE_GROUP2:
+ ndr_print_ptr(ndr, "delete_group", r->delete_group);
+ ndr->depth++;
+ if (r->delete_group) {
+ ndr_print_netr_DELTA_DELETE_USER(ndr, "delete_group", r->delete_group);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_DELETE_USER2:
+ ndr_print_ptr(ndr, "delete_user", r->delete_user);
+ ndr->depth++;
+ if (r->delete_user) {
+ ndr_print_netr_DELTA_DELETE_USER(ndr, "delete_user", r->delete_user);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_MODIFY_COUNT:
+ ndr_print_ptr(ndr, "modified_count", r->modified_count);
+ ndr->depth++;
+ if (r->modified_count) {
+ ndr_print_udlong(ndr, "modified_count", *r->modified_count);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_ID_UNION(struct ndr_push *ndr, int ndr_flags, const union netr_DELTA_ID_UNION *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_netr_DeltaEnum(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case NETR_DELTA_DOMAIN: {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ break; }
+
+ case NETR_DELTA_GROUP: {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ break; }
+
+ case NETR_DELTA_DELETE_GROUP: {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ break; }
+
+ case NETR_DELTA_RENAME_GROUP: {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ break; }
+
+ case NETR_DELTA_USER: {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ break; }
+
+ case NETR_DELTA_DELETE_USER: {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ break; }
+
+ case NETR_DELTA_RENAME_USER: {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ break; }
+
+ case NETR_DELTA_GROUP_MEMBER: {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ break; }
+
+ case NETR_DELTA_ALIAS: {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ break; }
+
+ case NETR_DELTA_DELETE_ALIAS: {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ break; }
+
+ case NETR_DELTA_RENAME_ALIAS: {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ break; }
+
+ case NETR_DELTA_ALIAS_MEMBER: {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ break; }
+
+ case NETR_DELTA_POLICY: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sid));
+ break; }
+
+ case NETR_DELTA_TRUSTED_DOMAIN: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sid));
+ break; }
+
+ case NETR_DELTA_DELETE_TRUST: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sid));
+ break; }
+
+ case NETR_DELTA_ACCOUNT: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sid));
+ break; }
+
+ case NETR_DELTA_DELETE_ACCOUNT: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sid));
+ break; }
+
+ case NETR_DELTA_SECRET: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ break; }
+
+ case NETR_DELTA_DELETE_SECRET: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ break; }
+
+ case NETR_DELTA_DELETE_GROUP2: {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ break; }
+
+ case NETR_DELTA_DELETE_USER2: {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ break; }
+
+ case NETR_DELTA_MODIFY_COUNT: {
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case NETR_DELTA_DOMAIN:
+ break;
+
+ case NETR_DELTA_GROUP:
+ break;
+
+ case NETR_DELTA_DELETE_GROUP:
+ break;
+
+ case NETR_DELTA_RENAME_GROUP:
+ break;
+
+ case NETR_DELTA_USER:
+ break;
+
+ case NETR_DELTA_DELETE_USER:
+ break;
+
+ case NETR_DELTA_RENAME_USER:
+ break;
+
+ case NETR_DELTA_GROUP_MEMBER:
+ break;
+
+ case NETR_DELTA_ALIAS:
+ break;
+
+ case NETR_DELTA_DELETE_ALIAS:
+ break;
+
+ case NETR_DELTA_RENAME_ALIAS:
+ break;
+
+ case NETR_DELTA_ALIAS_MEMBER:
+ break;
+
+ case NETR_DELTA_POLICY:
+ if (r->sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ }
+ break;
+
+ case NETR_DELTA_TRUSTED_DOMAIN:
+ if (r->sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ }
+ break;
+
+ case NETR_DELTA_DELETE_TRUST:
+ if (r->sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ }
+ break;
+
+ case NETR_DELTA_ACCOUNT:
+ if (r->sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ }
+ break;
+
+ case NETR_DELTA_DELETE_ACCOUNT:
+ if (r->sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ }
+ break;
+
+ case NETR_DELTA_SECRET:
+ if (r->name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, ndr_charset_length(r->name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ break;
+
+ case NETR_DELTA_DELETE_SECRET:
+ if (r->name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, ndr_charset_length(r->name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ break;
+
+ case NETR_DELTA_DELETE_GROUP2:
+ break;
+
+ case NETR_DELTA_DELETE_USER2:
+ break;
+
+ case NETR_DELTA_MODIFY_COUNT:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_ID_UNION(struct ndr_pull *ndr, int ndr_flags, union netr_DELTA_ID_UNION *r)
+{
+ int level;
+ uint16_t _level;
+ TALLOC_CTX *_mem_save_sid_0;
+ TALLOC_CTX *_mem_save_name_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case NETR_DELTA_DOMAIN: {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ break; }
+
+ case NETR_DELTA_GROUP: {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ break; }
+
+ case NETR_DELTA_DELETE_GROUP: {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ break; }
+
+ case NETR_DELTA_RENAME_GROUP: {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ break; }
+
+ case NETR_DELTA_USER: {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ break; }
+
+ case NETR_DELTA_DELETE_USER: {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ break; }
+
+ case NETR_DELTA_RENAME_USER: {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ break; }
+
+ case NETR_DELTA_GROUP_MEMBER: {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ break; }
+
+ case NETR_DELTA_ALIAS: {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ break; }
+
+ case NETR_DELTA_DELETE_ALIAS: {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ break; }
+
+ case NETR_DELTA_RENAME_ALIAS: {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ break; }
+
+ case NETR_DELTA_ALIAS_MEMBER: {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ break; }
+
+ case NETR_DELTA_POLICY: {
+ uint32_t _ptr_sid;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sid));
+ if (_ptr_sid) {
+ NDR_PULL_ALLOC(ndr, r->sid);
+ } else {
+ r->sid = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_TRUSTED_DOMAIN: {
+ uint32_t _ptr_sid;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sid));
+ if (_ptr_sid) {
+ NDR_PULL_ALLOC(ndr, r->sid);
+ } else {
+ r->sid = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_DELETE_TRUST: {
+ uint32_t _ptr_sid;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sid));
+ if (_ptr_sid) {
+ NDR_PULL_ALLOC(ndr, r->sid);
+ } else {
+ r->sid = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_ACCOUNT: {
+ uint32_t _ptr_sid;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sid));
+ if (_ptr_sid) {
+ NDR_PULL_ALLOC(ndr, r->sid);
+ } else {
+ r->sid = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_DELETE_ACCOUNT: {
+ uint32_t _ptr_sid;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sid));
+ if (_ptr_sid) {
+ NDR_PULL_ALLOC(ndr, r->sid);
+ } else {
+ r->sid = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_SECRET: {
+ uint32_t _ptr_name;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_DELETE_SECRET: {
+ uint32_t _ptr_name;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ break; }
+
+ case NETR_DELTA_DELETE_GROUP2: {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ break; }
+
+ case NETR_DELTA_DELETE_USER2: {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ break; }
+
+ case NETR_DELTA_MODIFY_COUNT: {
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case NETR_DELTA_DOMAIN:
+ break;
+
+ case NETR_DELTA_GROUP:
+ break;
+
+ case NETR_DELTA_DELETE_GROUP:
+ break;
+
+ case NETR_DELTA_RENAME_GROUP:
+ break;
+
+ case NETR_DELTA_USER:
+ break;
+
+ case NETR_DELTA_DELETE_USER:
+ break;
+
+ case NETR_DELTA_RENAME_USER:
+ break;
+
+ case NETR_DELTA_GROUP_MEMBER:
+ break;
+
+ case NETR_DELTA_ALIAS:
+ break;
+
+ case NETR_DELTA_DELETE_ALIAS:
+ break;
+
+ case NETR_DELTA_RENAME_ALIAS:
+ break;
+
+ case NETR_DELTA_ALIAS_MEMBER:
+ break;
+
+ case NETR_DELTA_POLICY:
+ if (r->sid) {
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_TRUSTED_DOMAIN:
+ if (r->sid) {
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_DELETE_TRUST:
+ if (r->sid) {
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_ACCOUNT:
+ if (r->sid) {
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_DELETE_ACCOUNT:
+ if (r->sid) {
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_SECRET:
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->name));
+ if (ndr_get_array_length(ndr, &r->name) > ndr_get_array_size(ndr, &r->name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->name), ndr_get_array_length(ndr, &r->name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_DELETE_SECRET:
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->name));
+ if (ndr_get_array_length(ndr, &r->name) > ndr_get_array_size(ndr, &r->name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->name), ndr_get_array_length(ndr, &r->name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ break;
+
+ case NETR_DELTA_DELETE_GROUP2:
+ break;
+
+ case NETR_DELTA_DELETE_USER2:
+ break;
+
+ case NETR_DELTA_MODIFY_COUNT:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_ID_UNION(struct ndr_print *ndr, const char *name, const union netr_DELTA_ID_UNION *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "netr_DELTA_ID_UNION");
+ switch (level) {
+ case NETR_DELTA_DOMAIN:
+ ndr_print_uint32(ndr, "rid", r->rid);
+ break;
+
+ case NETR_DELTA_GROUP:
+ ndr_print_uint32(ndr, "rid", r->rid);
+ break;
+
+ case NETR_DELTA_DELETE_GROUP:
+ ndr_print_uint32(ndr, "rid", r->rid);
+ break;
+
+ case NETR_DELTA_RENAME_GROUP:
+ ndr_print_uint32(ndr, "rid", r->rid);
+ break;
+
+ case NETR_DELTA_USER:
+ ndr_print_uint32(ndr, "rid", r->rid);
+ break;
+
+ case NETR_DELTA_DELETE_USER:
+ ndr_print_uint32(ndr, "rid", r->rid);
+ break;
+
+ case NETR_DELTA_RENAME_USER:
+ ndr_print_uint32(ndr, "rid", r->rid);
+ break;
+
+ case NETR_DELTA_GROUP_MEMBER:
+ ndr_print_uint32(ndr, "rid", r->rid);
+ break;
+
+ case NETR_DELTA_ALIAS:
+ ndr_print_uint32(ndr, "rid", r->rid);
+ break;
+
+ case NETR_DELTA_DELETE_ALIAS:
+ ndr_print_uint32(ndr, "rid", r->rid);
+ break;
+
+ case NETR_DELTA_RENAME_ALIAS:
+ ndr_print_uint32(ndr, "rid", r->rid);
+ break;
+
+ case NETR_DELTA_ALIAS_MEMBER:
+ ndr_print_uint32(ndr, "rid", r->rid);
+ break;
+
+ case NETR_DELTA_POLICY:
+ ndr_print_ptr(ndr, "sid", r->sid);
+ ndr->depth++;
+ if (r->sid) {
+ ndr_print_dom_sid2(ndr, "sid", r->sid);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_TRUSTED_DOMAIN:
+ ndr_print_ptr(ndr, "sid", r->sid);
+ ndr->depth++;
+ if (r->sid) {
+ ndr_print_dom_sid2(ndr, "sid", r->sid);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_DELETE_TRUST:
+ ndr_print_ptr(ndr, "sid", r->sid);
+ ndr->depth++;
+ if (r->sid) {
+ ndr_print_dom_sid2(ndr, "sid", r->sid);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_ACCOUNT:
+ ndr_print_ptr(ndr, "sid", r->sid);
+ ndr->depth++;
+ if (r->sid) {
+ ndr_print_dom_sid2(ndr, "sid", r->sid);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_DELETE_ACCOUNT:
+ ndr_print_ptr(ndr, "sid", r->sid);
+ ndr->depth++;
+ if (r->sid) {
+ ndr_print_dom_sid2(ndr, "sid", r->sid);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_SECRET:
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_string(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_DELETE_SECRET:
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_string(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ break;
+
+ case NETR_DELTA_DELETE_GROUP2:
+ ndr_print_uint32(ndr, "rid", r->rid);
+ break;
+
+ case NETR_DELTA_DELETE_USER2:
+ ndr_print_uint32(ndr, "rid", r->rid);
+ break;
+
+ case NETR_DELTA_MODIFY_COUNT:
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_ENUM(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_ENUM *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netr_DeltaEnum(ndr, NDR_SCALARS, r->delta_type));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->delta_id_union, r->delta_type));
+ NDR_CHECK(ndr_push_netr_DELTA_ID_UNION(ndr, NDR_SCALARS, &r->delta_id_union));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->delta_union, r->delta_type));
+ NDR_CHECK(ndr_push_netr_DELTA_UNION(ndr, NDR_SCALARS, &r->delta_union));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_netr_DELTA_ID_UNION(ndr, NDR_BUFFERS, &r->delta_id_union));
+ NDR_CHECK(ndr_push_netr_DELTA_UNION(ndr, NDR_BUFFERS, &r->delta_union));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_ENUM(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_ENUM *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netr_DeltaEnum(ndr, NDR_SCALARS, &r->delta_type));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->delta_id_union, r->delta_type));
+ NDR_CHECK(ndr_pull_netr_DELTA_ID_UNION(ndr, NDR_SCALARS, &r->delta_id_union));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->delta_union, r->delta_type));
+ NDR_CHECK(ndr_pull_netr_DELTA_UNION(ndr, NDR_SCALARS, &r->delta_union));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_netr_DELTA_ID_UNION(ndr, NDR_BUFFERS, &r->delta_id_union));
+ NDR_CHECK(ndr_pull_netr_DELTA_UNION(ndr, NDR_BUFFERS, &r->delta_union));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_ENUM(struct ndr_print *ndr, const char *name, const struct netr_DELTA_ENUM *r)
+{
+ ndr_print_struct(ndr, name, "netr_DELTA_ENUM");
+ ndr->depth++;
+ ndr_print_netr_DeltaEnum(ndr, "delta_type", r->delta_type);
+ ndr_print_set_switch_value(ndr, &r->delta_id_union, r->delta_type);
+ ndr_print_netr_DELTA_ID_UNION(ndr, "delta_id_union", &r->delta_id_union);
+ ndr_print_set_switch_value(ndr, &r->delta_union, r->delta_type);
+ ndr_print_netr_DELTA_UNION(ndr, "delta_union", &r->delta_union);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DELTA_ENUM_ARRAY(struct ndr_push *ndr, int ndr_flags, const struct netr_DELTA_ENUM_ARRAY *r)
+{
+ uint32_t cntr_delta_enum_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_deltas));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->delta_enum));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->delta_enum) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_deltas));
+ for (cntr_delta_enum_1 = 0; cntr_delta_enum_1 < r->num_deltas; cntr_delta_enum_1++) {
+ NDR_CHECK(ndr_push_netr_DELTA_ENUM(ndr, NDR_SCALARS, &r->delta_enum[cntr_delta_enum_1]));
+ }
+ for (cntr_delta_enum_1 = 0; cntr_delta_enum_1 < r->num_deltas; cntr_delta_enum_1++) {
+ NDR_CHECK(ndr_push_netr_DELTA_ENUM(ndr, NDR_BUFFERS, &r->delta_enum[cntr_delta_enum_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DELTA_ENUM_ARRAY(struct ndr_pull *ndr, int ndr_flags, struct netr_DELTA_ENUM_ARRAY *r)
+{
+ uint32_t _ptr_delta_enum;
+ uint32_t cntr_delta_enum_1;
+ TALLOC_CTX *_mem_save_delta_enum_0;
+ TALLOC_CTX *_mem_save_delta_enum_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_deltas));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_delta_enum));
+ if (_ptr_delta_enum) {
+ NDR_PULL_ALLOC(ndr, r->delta_enum);
+ } else {
+ r->delta_enum = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->delta_enum) {
+ _mem_save_delta_enum_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->delta_enum, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->delta_enum));
+ NDR_PULL_ALLOC_N(ndr, r->delta_enum, ndr_get_array_size(ndr, &r->delta_enum));
+ _mem_save_delta_enum_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->delta_enum, 0);
+ for (cntr_delta_enum_1 = 0; cntr_delta_enum_1 < r->num_deltas; cntr_delta_enum_1++) {
+ NDR_CHECK(ndr_pull_netr_DELTA_ENUM(ndr, NDR_SCALARS, &r->delta_enum[cntr_delta_enum_1]));
+ }
+ for (cntr_delta_enum_1 = 0; cntr_delta_enum_1 < r->num_deltas; cntr_delta_enum_1++) {
+ NDR_CHECK(ndr_pull_netr_DELTA_ENUM(ndr, NDR_BUFFERS, &r->delta_enum[cntr_delta_enum_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_delta_enum_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_delta_enum_0, 0);
+ }
+ if (r->delta_enum) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->delta_enum, r->num_deltas));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DELTA_ENUM_ARRAY(struct ndr_print *ndr, const char *name, const struct netr_DELTA_ENUM_ARRAY *r)
+{
+ uint32_t cntr_delta_enum_1;
+ ndr_print_struct(ndr, name, "netr_DELTA_ENUM_ARRAY");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_deltas", r->num_deltas);
+ ndr_print_ptr(ndr, "delta_enum", r->delta_enum);
+ ndr->depth++;
+ if (r->delta_enum) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "delta_enum", (int)r->num_deltas);
+ ndr->depth++;
+ for (cntr_delta_enum_1=0;cntr_delta_enum_1<r->num_deltas;cntr_delta_enum_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_delta_enum_1) != -1) {
+ ndr_print_netr_DELTA_ENUM(ndr, "delta_enum", &r->delta_enum[cntr_delta_enum_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_UAS_INFO_0(struct ndr_push *ndr, int ndr_flags, const struct netr_UAS_INFO_0 *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->computer_name, 16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->timecreated));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->serial_number));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_UAS_INFO_0(struct ndr_pull *ndr, int ndr_flags, struct netr_UAS_INFO_0 *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->computer_name, 16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->timecreated));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->serial_number));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_UAS_INFO_0(struct ndr_print *ndr, const char *name, const struct netr_UAS_INFO_0 *r)
+{
+ ndr_print_struct(ndr, name, "netr_UAS_INFO_0");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "computer_name", r->computer_name, 16);
+ ndr_print_uint32(ndr, "timecreated", r->timecreated);
+ ndr_print_uint32(ndr, "serial_number", r->serial_number);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_netr_AccountBuffer(struct ndr_push *ndr, int ndr_flags, const struct netr_AccountBuffer *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->blob));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_AccountBuffer(struct ndr_pull *ndr, int ndr_flags, struct netr_AccountBuffer *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->blob));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_AccountBuffer(struct ndr_print *ndr, const char *name, const struct netr_AccountBuffer *r)
+{
+ ndr_print_struct(ndr, name, "netr_AccountBuffer");
+ ndr->depth++;
+ ndr_print_DATA_BLOB(ndr, "blob", r->blob);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_InfoFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_InfoFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_InfoFlags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_CTRL_REPL_NEEDED", NETLOGON_CTRL_REPL_NEEDED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_CTRL_REPL_IN_PROGRESS", NETLOGON_CTRL_REPL_IN_PROGRESS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_CTRL_REPL_FULL_SYNC", NETLOGON_CTRL_REPL_FULL_SYNC, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_NETLOGON_INFO_1(struct ndr_push *ndr, int ndr_flags, const struct netr_NETLOGON_INFO_1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netr_InfoFlags(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pdc_connection_status));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_NETLOGON_INFO_1(struct ndr_pull *ndr, int ndr_flags, struct netr_NETLOGON_INFO_1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netr_InfoFlags(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pdc_connection_status));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_NETLOGON_INFO_1(struct ndr_print *ndr, const char *name, const struct netr_NETLOGON_INFO_1 *r)
+{
+ ndr_print_struct(ndr, name, "netr_NETLOGON_INFO_1");
+ ndr->depth++;
+ ndr_print_netr_InfoFlags(ndr, "flags", r->flags);
+ ndr_print_uint32(ndr, "pdc_connection_status", r->pdc_connection_status);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_NETLOGON_INFO_2(struct ndr_push *ndr, int ndr_flags, const struct netr_NETLOGON_INFO_2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netr_InfoFlags(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pdc_connection_status));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->trusted_dc_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->tc_connection_status));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->trusted_dc_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->trusted_dc_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->trusted_dc_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->trusted_dc_name, ndr_charset_length(r->trusted_dc_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_NETLOGON_INFO_2(struct ndr_pull *ndr, int ndr_flags, struct netr_NETLOGON_INFO_2 *r)
+{
+ uint32_t _ptr_trusted_dc_name;
+ TALLOC_CTX *_mem_save_trusted_dc_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netr_InfoFlags(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pdc_connection_status));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_trusted_dc_name));
+ if (_ptr_trusted_dc_name) {
+ NDR_PULL_ALLOC(ndr, r->trusted_dc_name);
+ } else {
+ r->trusted_dc_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->tc_connection_status));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->trusted_dc_name) {
+ _mem_save_trusted_dc_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->trusted_dc_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->trusted_dc_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->trusted_dc_name));
+ if (ndr_get_array_length(ndr, &r->trusted_dc_name) > ndr_get_array_size(ndr, &r->trusted_dc_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->trusted_dc_name), ndr_get_array_length(ndr, &r->trusted_dc_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->trusted_dc_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->trusted_dc_name, ndr_get_array_length(ndr, &r->trusted_dc_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_trusted_dc_name_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_NETLOGON_INFO_2(struct ndr_print *ndr, const char *name, const struct netr_NETLOGON_INFO_2 *r)
+{
+ ndr_print_struct(ndr, name, "netr_NETLOGON_INFO_2");
+ ndr->depth++;
+ ndr_print_netr_InfoFlags(ndr, "flags", r->flags);
+ ndr_print_uint32(ndr, "pdc_connection_status", r->pdc_connection_status);
+ ndr_print_ptr(ndr, "trusted_dc_name", r->trusted_dc_name);
+ ndr->depth++;
+ if (r->trusted_dc_name) {
+ ndr_print_string(ndr, "trusted_dc_name", r->trusted_dc_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "tc_connection_status", r->tc_connection_status);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_NETLOGON_INFO_3(struct ndr_push *ndr, int ndr_flags, const struct netr_NETLOGON_INFO_3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netr_InfoFlags(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->logon_attempts));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown3));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_NETLOGON_INFO_3(struct ndr_pull *ndr, int ndr_flags, struct netr_NETLOGON_INFO_3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netr_InfoFlags(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->logon_attempts));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_NETLOGON_INFO_3(struct ndr_print *ndr, const char *name, const struct netr_NETLOGON_INFO_3 *r)
+{
+ ndr_print_struct(ndr, name, "netr_NETLOGON_INFO_3");
+ ndr->depth++;
+ ndr_print_netr_InfoFlags(ndr, "flags", r->flags);
+ ndr_print_uint32(ndr, "logon_attempts", r->logon_attempts);
+ ndr_print_uint32(ndr, "unknown1", r->unknown1);
+ ndr_print_uint32(ndr, "unknown2", r->unknown2);
+ ndr_print_uint32(ndr, "unknown3", r->unknown3);
+ ndr_print_uint32(ndr, "unknown4", r->unknown4);
+ ndr_print_uint32(ndr, "unknown5", r->unknown5);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_CONTROL_QUERY_INFORMATION(struct ndr_push *ndr, int ndr_flags, const union netr_CONTROL_QUERY_INFORMATION *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info3));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ if (r->info1) {
+ NDR_CHECK(ndr_push_netr_NETLOGON_INFO_1(ndr, NDR_SCALARS, r->info1));
+ }
+ break;
+
+ case 2:
+ if (r->info2) {
+ NDR_CHECK(ndr_push_netr_NETLOGON_INFO_2(ndr, NDR_SCALARS|NDR_BUFFERS, r->info2));
+ }
+ break;
+
+ case 3:
+ if (r->info3) {
+ NDR_CHECK(ndr_push_netr_NETLOGON_INFO_3(ndr, NDR_SCALARS, r->info3));
+ }
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_CONTROL_QUERY_INFORMATION(struct ndr_pull *ndr, int ndr_flags, union netr_CONTROL_QUERY_INFORMATION *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_info1_0;
+ TALLOC_CTX *_mem_save_info2_0;
+ TALLOC_CTX *_mem_save_info3_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ uint32_t _ptr_info1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1));
+ if (_ptr_info1) {
+ NDR_PULL_ALLOC(ndr, r->info1);
+ } else {
+ r->info1 = NULL;
+ }
+ break; }
+
+ case 2: {
+ uint32_t _ptr_info2;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info2));
+ if (_ptr_info2) {
+ NDR_PULL_ALLOC(ndr, r->info2);
+ } else {
+ r->info2 = NULL;
+ }
+ break; }
+
+ case 3: {
+ uint32_t _ptr_info3;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info3));
+ if (_ptr_info3) {
+ NDR_PULL_ALLOC(ndr, r->info3);
+ } else {
+ r->info3 = NULL;
+ }
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ if (r->info1) {
+ _mem_save_info1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1, 0);
+ NDR_CHECK(ndr_pull_netr_NETLOGON_INFO_1(ndr, NDR_SCALARS, r->info1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1_0, 0);
+ }
+ break;
+
+ case 2:
+ if (r->info2) {
+ _mem_save_info2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info2, 0);
+ NDR_CHECK(ndr_pull_netr_NETLOGON_INFO_2(ndr, NDR_SCALARS|NDR_BUFFERS, r->info2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info2_0, 0);
+ }
+ break;
+
+ case 3:
+ if (r->info3) {
+ _mem_save_info3_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info3, 0);
+ NDR_CHECK(ndr_pull_netr_NETLOGON_INFO_3(ndr, NDR_SCALARS, r->info3));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info3_0, 0);
+ }
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_CONTROL_QUERY_INFORMATION(struct ndr_print *ndr, const char *name, const union netr_CONTROL_QUERY_INFORMATION *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "netr_CONTROL_QUERY_INFORMATION");
+ switch (level) {
+ case 1:
+ ndr_print_ptr(ndr, "info1", r->info1);
+ ndr->depth++;
+ if (r->info1) {
+ ndr_print_netr_NETLOGON_INFO_1(ndr, "info1", r->info1);
+ }
+ ndr->depth--;
+ break;
+
+ case 2:
+ ndr_print_ptr(ndr, "info2", r->info2);
+ ndr->depth++;
+ if (r->info2) {
+ ndr_print_netr_NETLOGON_INFO_2(ndr, "info2", r->info2);
+ }
+ ndr->depth--;
+ break;
+
+ case 3:
+ ndr_print_ptr(ndr, "info3", r->info3);
+ ndr->depth++;
+ if (r->info3) {
+ ndr_print_netr_NETLOGON_INFO_3(ndr, "info3", r->info3);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_netr_LogonControlCode(struct ndr_push *ndr, int ndr_flags, enum netr_LogonControlCode r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_LogonControlCode(struct ndr_pull *ndr, int ndr_flags, enum netr_LogonControlCode *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_LogonControlCode(struct ndr_print *ndr, const char *name, enum netr_LogonControlCode r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case NETLOGON_CONTROL_SYNC: val = "NETLOGON_CONTROL_SYNC"; break;
+ case NETLOGON_CONTROL_REDISCOVER: val = "NETLOGON_CONTROL_REDISCOVER"; break;
+ case NETLOGON_CONTROL_TC_QUERY: val = "NETLOGON_CONTROL_TC_QUERY"; break;
+ case NETLOGON_CONTROL_TRANSPORT_NOTIFY: val = "NETLOGON_CONTROL_TRANSPORT_NOTIFY"; break;
+ case NETLOGON_CONTROL_SET_DBFLAG: val = "NETLOGON_CONTROL_SET_DBFLAG"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_netr_CONTROL_DATA_INFORMATION(struct ndr_push *ndr, int ndr_flags, const union netr_CONTROL_DATA_INFORMATION *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case NETLOGON_CONTROL_REDISCOVER: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain));
+ break; }
+
+ case NETLOGON_CONTROL_TC_QUERY: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain));
+ break; }
+
+ case NETLOGON_CONTROL_TRANSPORT_NOTIFY: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain));
+ break; }
+
+ case NETLOGON_CONTROL_SET_DBFLAG: {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->debug_level));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case NETLOGON_CONTROL_REDISCOVER:
+ if (r->domain) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain, ndr_charset_length(r->domain, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ break;
+
+ case NETLOGON_CONTROL_TC_QUERY:
+ if (r->domain) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain, ndr_charset_length(r->domain, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ break;
+
+ case NETLOGON_CONTROL_TRANSPORT_NOTIFY:
+ if (r->domain) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain, ndr_charset_length(r->domain, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ break;
+
+ case NETLOGON_CONTROL_SET_DBFLAG:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_CONTROL_DATA_INFORMATION(struct ndr_pull *ndr, int ndr_flags, union netr_CONTROL_DATA_INFORMATION *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_domain_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case NETLOGON_CONTROL_REDISCOVER: {
+ uint32_t _ptr_domain;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain));
+ if (_ptr_domain) {
+ NDR_PULL_ALLOC(ndr, r->domain);
+ } else {
+ r->domain = NULL;
+ }
+ break; }
+
+ case NETLOGON_CONTROL_TC_QUERY: {
+ uint32_t _ptr_domain;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain));
+ if (_ptr_domain) {
+ NDR_PULL_ALLOC(ndr, r->domain);
+ } else {
+ r->domain = NULL;
+ }
+ break; }
+
+ case NETLOGON_CONTROL_TRANSPORT_NOTIFY: {
+ uint32_t _ptr_domain;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain));
+ if (_ptr_domain) {
+ NDR_PULL_ALLOC(ndr, r->domain);
+ } else {
+ r->domain = NULL;
+ }
+ break; }
+
+ case NETLOGON_CONTROL_SET_DBFLAG: {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->debug_level));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case NETLOGON_CONTROL_REDISCOVER:
+ if (r->domain) {
+ _mem_save_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain));
+ if (ndr_get_array_length(ndr, &r->domain) > ndr_get_array_size(ndr, &r->domain)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain), ndr_get_array_length(ndr, &r->domain));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_0, 0);
+ }
+ break;
+
+ case NETLOGON_CONTROL_TC_QUERY:
+ if (r->domain) {
+ _mem_save_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain));
+ if (ndr_get_array_length(ndr, &r->domain) > ndr_get_array_size(ndr, &r->domain)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain), ndr_get_array_length(ndr, &r->domain));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_0, 0);
+ }
+ break;
+
+ case NETLOGON_CONTROL_TRANSPORT_NOTIFY:
+ if (r->domain) {
+ _mem_save_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain));
+ if (ndr_get_array_length(ndr, &r->domain) > ndr_get_array_size(ndr, &r->domain)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain), ndr_get_array_length(ndr, &r->domain));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_0, 0);
+ }
+ break;
+
+ case NETLOGON_CONTROL_SET_DBFLAG:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_CONTROL_DATA_INFORMATION(struct ndr_print *ndr, const char *name, const union netr_CONTROL_DATA_INFORMATION *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "netr_CONTROL_DATA_INFORMATION");
+ switch (level) {
+ case NETLOGON_CONTROL_REDISCOVER:
+ ndr_print_ptr(ndr, "domain", r->domain);
+ ndr->depth++;
+ if (r->domain) {
+ ndr_print_string(ndr, "domain", r->domain);
+ }
+ ndr->depth--;
+ break;
+
+ case NETLOGON_CONTROL_TC_QUERY:
+ ndr_print_ptr(ndr, "domain", r->domain);
+ ndr->depth++;
+ if (r->domain) {
+ ndr_print_string(ndr, "domain", r->domain);
+ }
+ ndr->depth--;
+ break;
+
+ case NETLOGON_CONTROL_TRANSPORT_NOTIFY:
+ ndr_print_ptr(ndr, "domain", r->domain);
+ ndr->depth++;
+ if (r->domain) {
+ ndr_print_string(ndr, "domain", r->domain);
+ }
+ ndr->depth--;
+ break;
+
+ case NETLOGON_CONTROL_SET_DBFLAG:
+ ndr_print_uint32(ndr, "debug_level", r->debug_level);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_netr_NegotiateFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_NegotiateFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_NegotiateFlags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_ACCOUNT_LOCKOUT", NETLOGON_NEG_ACCOUNT_LOCKOUT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_PERSISTENT_SAMREPL", NETLOGON_NEG_PERSISTENT_SAMREPL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_ARCFOUR", NETLOGON_NEG_ARCFOUR, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_PROMOTION_COUNT", NETLOGON_NEG_PROMOTION_COUNT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_CHANGELOG_BDC", NETLOGON_NEG_CHANGELOG_BDC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_FULL_SYNC_REPL", NETLOGON_NEG_FULL_SYNC_REPL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_MULTIPLE_SIDS", NETLOGON_NEG_MULTIPLE_SIDS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_REDO", NETLOGON_NEG_REDO, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_PASSWORD_CHANGE_REFUSAL", NETLOGON_NEG_PASSWORD_CHANGE_REFUSAL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_SEND_PASSWORD_INFO_PDC", NETLOGON_NEG_SEND_PASSWORD_INFO_PDC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_GENERIC_PASSTHROUGH", NETLOGON_NEG_GENERIC_PASSTHROUGH, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_CONCURRENT_RPC", NETLOGON_NEG_CONCURRENT_RPC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_AVOID_ACCOUNT_DB_REPL", NETLOGON_NEG_AVOID_ACCOUNT_DB_REPL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_AVOID_SECURITYAUTH_DB_REPL", NETLOGON_NEG_AVOID_SECURITYAUTH_DB_REPL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_128BIT", NETLOGON_NEG_128BIT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_TRANSITIVE_TRUSTS", NETLOGON_NEG_TRANSITIVE_TRUSTS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_DNS_DOMAIN_TRUSTS", NETLOGON_NEG_DNS_DOMAIN_TRUSTS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_PASSWORD_SET2", NETLOGON_NEG_PASSWORD_SET2, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_GETDOMAININFO", NETLOGON_NEG_GETDOMAININFO, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_CROSS_FOREST_TRUSTS", NETLOGON_NEG_CROSS_FOREST_TRUSTS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION", NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_RODC_PASSTHROUGH", NETLOGON_NEG_RODC_PASSTHROUGH, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_AUTHENTICATED_RPC_LSASS", NETLOGON_NEG_AUTHENTICATED_RPC_LSASS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETLOGON_NEG_SCHANNEL", NETLOGON_NEG_SCHANNEL, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_Blob(struct ndr_push *ndr, int ndr_flags, const struct netr_Blob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data, r->length));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_Blob(struct ndr_pull *ndr, int ndr_flags, struct netr_Blob *r)
+{
+ uint32_t _ptr_data;
+ TALLOC_CTX *_mem_save_data_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data));
+ if (_ptr_data) {
+ NDR_PULL_ALLOC(ndr, r->data);
+ } else {
+ r->data = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->data, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->data));
+ NDR_PULL_ALLOC_N(ndr, r->data, ndr_get_array_size(ndr, &r->data));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data, ndr_get_array_size(ndr, &r->data)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, 0);
+ }
+ if (r->data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->data, r->length));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_Blob(struct ndr_print *ndr, const char *name, const struct netr_Blob *r)
+{
+ ndr_print_struct(ndr, name, "netr_Blob");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "length", r->length);
+ ndr_print_ptr(ndr, "data", r->data);
+ ndr->depth++;
+ if (r->data) {
+ ndr_print_array_uint8(ndr, "data", r->data, r->length);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DsRGetDCName_flags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DsRGetDCName_flags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsRGetDCName_flags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_FORCE_REDISCOVERY", DS_FORCE_REDISCOVERY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_DIRECTORY_SERVICE_REQUIRED", DS_DIRECTORY_SERVICE_REQUIRED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_DIRECTORY_SERVICE_PREFERRED", DS_DIRECTORY_SERVICE_PREFERRED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_GC_SERVER_REQUIRED", DS_GC_SERVER_REQUIRED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_PDC_REQUIRED", DS_PDC_REQUIRED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_BACKGROUND_ONLY", DS_BACKGROUND_ONLY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_IP_REQUIRED", DS_IP_REQUIRED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_KDC_REQUIRED", DS_KDC_REQUIRED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_TIMESERV_REQUIRED", DS_TIMESERV_REQUIRED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_WRITABLE_REQUIRED", DS_WRITABLE_REQUIRED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_GOOD_TIMESERV_PREFERRED", DS_GOOD_TIMESERV_PREFERRED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_AVOID_SELF", DS_AVOID_SELF, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_ONLY_LDAP_NEEDED", DS_ONLY_LDAP_NEEDED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_IS_FLAT_NAME", DS_IS_FLAT_NAME, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_IS_DNS_NAME", DS_IS_DNS_NAME, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_TRY_NEXTCLOSEST_SITE", DS_TRY_NEXTCLOSEST_SITE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_DIRECTORY_SERVICE_6_REQUIRED", DS_DIRECTORY_SERVICE_6_REQUIRED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_RETURN_DNS_NAME", DS_RETURN_DNS_NAME, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_RETURN_FLAT_NAME", DS_RETURN_FLAT_NAME, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DsRGetDCNameInfo_AddressType(struct ndr_push *ndr, int ndr_flags, enum netr_DsRGetDCNameInfo_AddressType r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DsRGetDCNameInfo_AddressType(struct ndr_pull *ndr, int ndr_flags, enum netr_DsRGetDCNameInfo_AddressType *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsRGetDCNameInfo_AddressType(struct ndr_print *ndr, const char *name, enum netr_DsRGetDCNameInfo_AddressType r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case DS_ADDRESS_TYPE_INET: val = "DS_ADDRESS_TYPE_INET"; break;
+ case DS_ADDRESS_TYPE_NETBIOS: val = "DS_ADDRESS_TYPE_NETBIOS"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_netr_DsR_DcFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DsR_DcFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsR_DcFlags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_SERVER_PDC", DS_SERVER_PDC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_SERVER_GC", DS_SERVER_GC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_SERVER_LDAP", DS_SERVER_LDAP, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_SERVER_DS", DS_SERVER_DS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_SERVER_KDC", DS_SERVER_KDC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_SERVER_TIMESERV", DS_SERVER_TIMESERV, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_SERVER_CLOSEST", DS_SERVER_CLOSEST, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_SERVER_WRITABLE", DS_SERVER_WRITABLE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_SERVER_GOOD_TIMESERV", DS_SERVER_GOOD_TIMESERV, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_SERVER_NDNC", DS_SERVER_NDNC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_SERVER_SELECT_SECRET_DOMAIN_6", DS_SERVER_SELECT_SECRET_DOMAIN_6, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_SERVER_FULL_SECRET_DOMAIN_6", DS_SERVER_FULL_SECRET_DOMAIN_6, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_DNS_CONTROLLER", DS_DNS_CONTROLLER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_DNS_DOMAIN", DS_DNS_DOMAIN, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DS_DNS_FOREST", DS_DNS_FOREST, r);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_DsRGetDCNameInfo(struct ndr_push *ndr, int ndr_flags, const struct netr_DsRGetDCNameInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->dc_unc));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->dc_address));
+ NDR_CHECK(ndr_push_netr_DsRGetDCNameInfo_AddressType(ndr, NDR_SCALARS, r->dc_address_type));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->domain_guid));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->forest_name));
+ NDR_CHECK(ndr_push_netr_DsR_DcFlags(ndr, NDR_SCALARS, r->dc_flags));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->dc_site_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->client_site_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->dc_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dc_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dc_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dc_unc, ndr_charset_length(r->dc_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->dc_address) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dc_address, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dc_address, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dc_address, ndr_charset_length(r->dc_address, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_BUFFERS, &r->domain_guid));
+ if (r->domain_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain_name, ndr_charset_length(r->domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->forest_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->forest_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->forest_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->forest_name, ndr_charset_length(r->forest_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->dc_site_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dc_site_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dc_site_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dc_site_name, ndr_charset_length(r->dc_site_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->client_site_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client_site_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client_site_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->client_site_name, ndr_charset_length(r->client_site_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_DsRGetDCNameInfo(struct ndr_pull *ndr, int ndr_flags, struct netr_DsRGetDCNameInfo *r)
+{
+ uint32_t _ptr_dc_unc;
+ TALLOC_CTX *_mem_save_dc_unc_0;
+ uint32_t _ptr_dc_address;
+ TALLOC_CTX *_mem_save_dc_address_0;
+ uint32_t _ptr_domain_name;
+ TALLOC_CTX *_mem_save_domain_name_0;
+ uint32_t _ptr_forest_name;
+ TALLOC_CTX *_mem_save_forest_name_0;
+ uint32_t _ptr_dc_site_name;
+ TALLOC_CTX *_mem_save_dc_site_name_0;
+ uint32_t _ptr_client_site_name;
+ TALLOC_CTX *_mem_save_client_site_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dc_unc));
+ if (_ptr_dc_unc) {
+ NDR_PULL_ALLOC(ndr, r->dc_unc);
+ } else {
+ r->dc_unc = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dc_address));
+ if (_ptr_dc_address) {
+ NDR_PULL_ALLOC(ndr, r->dc_address);
+ } else {
+ r->dc_address = NULL;
+ }
+ NDR_CHECK(ndr_pull_netr_DsRGetDCNameInfo_AddressType(ndr, NDR_SCALARS, &r->dc_address_type));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->domain_guid));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_name));
+ if (_ptr_domain_name) {
+ NDR_PULL_ALLOC(ndr, r->domain_name);
+ } else {
+ r->domain_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_forest_name));
+ if (_ptr_forest_name) {
+ NDR_PULL_ALLOC(ndr, r->forest_name);
+ } else {
+ r->forest_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_netr_DsR_DcFlags(ndr, NDR_SCALARS, &r->dc_flags));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dc_site_name));
+ if (_ptr_dc_site_name) {
+ NDR_PULL_ALLOC(ndr, r->dc_site_name);
+ } else {
+ r->dc_site_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_client_site_name));
+ if (_ptr_client_site_name) {
+ NDR_PULL_ALLOC(ndr, r->client_site_name);
+ } else {
+ r->client_site_name = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->dc_unc) {
+ _mem_save_dc_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->dc_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->dc_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->dc_unc));
+ if (ndr_get_array_length(ndr, &r->dc_unc) > ndr_get_array_size(ndr, &r->dc_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->dc_unc), ndr_get_array_length(ndr, &r->dc_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->dc_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dc_unc, ndr_get_array_length(ndr, &r->dc_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dc_unc_0, 0);
+ }
+ if (r->dc_address) {
+ _mem_save_dc_address_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->dc_address, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->dc_address));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->dc_address));
+ if (ndr_get_array_length(ndr, &r->dc_address) > ndr_get_array_size(ndr, &r->dc_address)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->dc_address), ndr_get_array_length(ndr, &r->dc_address));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->dc_address), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dc_address, ndr_get_array_length(ndr, &r->dc_address), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dc_address_0, 0);
+ }
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_BUFFERS, &r->domain_guid));
+ if (r->domain_name) {
+ _mem_save_domain_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain_name));
+ if (ndr_get_array_length(ndr, &r->domain_name) > ndr_get_array_size(ndr, &r->domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain_name), ndr_get_array_length(ndr, &r->domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain_name, ndr_get_array_length(ndr, &r->domain_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_name_0, 0);
+ }
+ if (r->forest_name) {
+ _mem_save_forest_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->forest_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->forest_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->forest_name));
+ if (ndr_get_array_length(ndr, &r->forest_name) > ndr_get_array_size(ndr, &r->forest_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->forest_name), ndr_get_array_length(ndr, &r->forest_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->forest_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->forest_name, ndr_get_array_length(ndr, &r->forest_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_forest_name_0, 0);
+ }
+ if (r->dc_site_name) {
+ _mem_save_dc_site_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->dc_site_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->dc_site_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->dc_site_name));
+ if (ndr_get_array_length(ndr, &r->dc_site_name) > ndr_get_array_size(ndr, &r->dc_site_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->dc_site_name), ndr_get_array_length(ndr, &r->dc_site_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->dc_site_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dc_site_name, ndr_get_array_length(ndr, &r->dc_site_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dc_site_name_0, 0);
+ }
+ if (r->client_site_name) {
+ _mem_save_client_site_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->client_site_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->client_site_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->client_site_name));
+ if (ndr_get_array_length(ndr, &r->client_site_name) > ndr_get_array_size(ndr, &r->client_site_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->client_site_name), ndr_get_array_length(ndr, &r->client_site_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->client_site_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->client_site_name, ndr_get_array_length(ndr, &r->client_site_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_client_site_name_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsRGetDCNameInfo(struct ndr_print *ndr, const char *name, const struct netr_DsRGetDCNameInfo *r)
+{
+ ndr_print_struct(ndr, name, "netr_DsRGetDCNameInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "dc_unc", r->dc_unc);
+ ndr->depth++;
+ if (r->dc_unc) {
+ ndr_print_string(ndr, "dc_unc", r->dc_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "dc_address", r->dc_address);
+ ndr->depth++;
+ if (r->dc_address) {
+ ndr_print_string(ndr, "dc_address", r->dc_address);
+ }
+ ndr->depth--;
+ ndr_print_netr_DsRGetDCNameInfo_AddressType(ndr, "dc_address_type", r->dc_address_type);
+ ndr_print_GUID(ndr, "domain_guid", &r->domain_guid);
+ ndr_print_ptr(ndr, "domain_name", r->domain_name);
+ ndr->depth++;
+ if (r->domain_name) {
+ ndr_print_string(ndr, "domain_name", r->domain_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "forest_name", r->forest_name);
+ ndr->depth++;
+ if (r->forest_name) {
+ ndr_print_string(ndr, "forest_name", r->forest_name);
+ }
+ ndr->depth--;
+ ndr_print_netr_DsR_DcFlags(ndr, "dc_flags", r->dc_flags);
+ ndr_print_ptr(ndr, "dc_site_name", r->dc_site_name);
+ ndr->depth++;
+ if (r->dc_site_name) {
+ ndr_print_string(ndr, "dc_site_name", r->dc_site_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "client_site_name", r->client_site_name);
+ ndr->depth++;
+ if (r->client_site_name) {
+ ndr_print_string(ndr, "client_site_name", r->client_site_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_BinaryString(struct ndr_push *ndr, int ndr_flags, const struct netr_BinaryString *r)
+{
+ uint32_t cntr_data_1;
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->size));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size / 2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length / 2));
+ for (cntr_data_1 = 0; cntr_data_1 < r->length / 2; cntr_data_1++) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->data[cntr_data_1]));
+ }
+ }
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_BinaryString(struct ndr_pull *ndr, int ndr_flags, struct netr_BinaryString *r)
+{
+ uint32_t _ptr_data;
+ uint32_t cntr_data_1;
+ TALLOC_CTX *_mem_save_data_0;
+ TALLOC_CTX *_mem_save_data_1;
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data));
+ if (_ptr_data) {
+ NDR_PULL_ALLOC(ndr, r->data);
+ } else {
+ r->data = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->data, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->data));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->data));
+ if (ndr_get_array_length(ndr, &r->data) > ndr_get_array_size(ndr, &r->data)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->data), ndr_get_array_length(ndr, &r->data));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->data, ndr_get_array_size(ndr, &r->data));
+ _mem_save_data_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->data, 0);
+ for (cntr_data_1 = 0; cntr_data_1 < r->length / 2; cntr_data_1++) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->data[cntr_data_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, 0);
+ }
+ if (r->data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->data, r->size / 2));
+ }
+ if (r->data) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->data, r->length / 2));
+ }
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_BinaryString(struct ndr_print *ndr, const char *name, const struct netr_BinaryString *r)
+{
+ uint32_t cntr_data_1;
+ ndr_print_struct(ndr, name, "netr_BinaryString");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_uint16(ndr, "length", r->length);
+ ndr_print_uint16(ndr, "size", r->size);
+ ndr_print_ptr(ndr, "data", r->data);
+ ndr->depth++;
+ if (r->data) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "data", (int)r->length / 2);
+ ndr->depth++;
+ for (cntr_data_1=0;cntr_data_1<r->length / 2;cntr_data_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_data_1) != -1) {
+ ndr_print_uint16(ndr, "data", r->data[cntr_data_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_netr_DomainQuery1(struct ndr_push *ndr, int ndr_flags, const struct netr_DomainQuery1 *r)
+{
+ uint32_t cntr_unknown7_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netr_Blob(ndr, NDR_SCALARS, &r->blob));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->workstation_domain));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->workstation_site));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->unknown1));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->unknown2));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->unknown3));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->unknown4));
+ NDR_CHECK(ndr_push_netr_BinaryString(ndr, NDR_SCALARS, &r->blob2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->product));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown5));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown6));
+ for (cntr_unknown7_0 = 0; cntr_unknown7_0 < 4; cntr_unknown7_0++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown7[cntr_unknown7_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_netr_Blob(ndr, NDR_BUFFERS, &r->blob));
+ if (r->workstation_domain) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->workstation_domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->workstation_domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->workstation_domain, ndr_charset_length(r->workstation_domain, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->workstation_site) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->workstation_site, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->workstation_site, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->workstation_site, ndr_charset_length(r->workstation_site, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->unknown1) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->unknown1, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->unknown1, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->unknown1, ndr_charset_length(r->unknown1, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->unknown2) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->unknown2, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->unknown2, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->unknown2, ndr_charset_length(r->unknown2, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->unknown3) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->unknown3, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->unknown3, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->unknown3, ndr_charset_length(r->unknown3, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->unknown4) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->unknown4, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->unknown4, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->unknown4, ndr_charset_length(r->unknown4, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_netr_BinaryString(ndr, NDR_BUFFERS, &r->blob2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->product));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown5));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown6));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DomainQuery1(struct ndr_pull *ndr, int ndr_flags, struct netr_DomainQuery1 *r)
+{
+ uint32_t _ptr_workstation_domain;
+ TALLOC_CTX *_mem_save_workstation_domain_0;
+ uint32_t _ptr_workstation_site;
+ TALLOC_CTX *_mem_save_workstation_site_0;
+ uint32_t _ptr_unknown1;
+ TALLOC_CTX *_mem_save_unknown1_0;
+ uint32_t _ptr_unknown2;
+ TALLOC_CTX *_mem_save_unknown2_0;
+ uint32_t _ptr_unknown3;
+ TALLOC_CTX *_mem_save_unknown3_0;
+ uint32_t _ptr_unknown4;
+ TALLOC_CTX *_mem_save_unknown4_0;
+ uint32_t cntr_unknown7_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netr_Blob(ndr, NDR_SCALARS, &r->blob));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_workstation_domain));
+ if (_ptr_workstation_domain) {
+ NDR_PULL_ALLOC(ndr, r->workstation_domain);
+ } else {
+ r->workstation_domain = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_workstation_site));
+ if (_ptr_workstation_site) {
+ NDR_PULL_ALLOC(ndr, r->workstation_site);
+ } else {
+ r->workstation_site = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown1));
+ if (_ptr_unknown1) {
+ NDR_PULL_ALLOC(ndr, r->unknown1);
+ } else {
+ r->unknown1 = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown2));
+ if (_ptr_unknown2) {
+ NDR_PULL_ALLOC(ndr, r->unknown2);
+ } else {
+ r->unknown2 = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown3));
+ if (_ptr_unknown3) {
+ NDR_PULL_ALLOC(ndr, r->unknown3);
+ } else {
+ r->unknown3 = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown4));
+ if (_ptr_unknown4) {
+ NDR_PULL_ALLOC(ndr, r->unknown4);
+ } else {
+ r->unknown4 = NULL;
+ }
+ NDR_CHECK(ndr_pull_netr_BinaryString(ndr, NDR_SCALARS, &r->blob2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->product));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown5));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown6));
+ for (cntr_unknown7_0 = 0; cntr_unknown7_0 < 4; cntr_unknown7_0++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown7[cntr_unknown7_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_netr_Blob(ndr, NDR_BUFFERS, &r->blob));
+ if (r->workstation_domain) {
+ _mem_save_workstation_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->workstation_domain, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->workstation_domain));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->workstation_domain));
+ if (ndr_get_array_length(ndr, &r->workstation_domain) > ndr_get_array_size(ndr, &r->workstation_domain)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->workstation_domain), ndr_get_array_length(ndr, &r->workstation_domain));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->workstation_domain), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->workstation_domain, ndr_get_array_length(ndr, &r->workstation_domain), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_workstation_domain_0, 0);
+ }
+ if (r->workstation_site) {
+ _mem_save_workstation_site_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->workstation_site, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->workstation_site));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->workstation_site));
+ if (ndr_get_array_length(ndr, &r->workstation_site) > ndr_get_array_size(ndr, &r->workstation_site)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->workstation_site), ndr_get_array_length(ndr, &r->workstation_site));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->workstation_site), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->workstation_site, ndr_get_array_length(ndr, &r->workstation_site), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_workstation_site_0, 0);
+ }
+ if (r->unknown1) {
+ _mem_save_unknown1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->unknown1, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->unknown1));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->unknown1));
+ if (ndr_get_array_length(ndr, &r->unknown1) > ndr_get_array_size(ndr, &r->unknown1)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->unknown1), ndr_get_array_length(ndr, &r->unknown1));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->unknown1), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->unknown1, ndr_get_array_length(ndr, &r->unknown1), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown1_0, 0);
+ }
+ if (r->unknown2) {
+ _mem_save_unknown2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->unknown2, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->unknown2));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->unknown2));
+ if (ndr_get_array_length(ndr, &r->unknown2) > ndr_get_array_size(ndr, &r->unknown2)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->unknown2), ndr_get_array_length(ndr, &r->unknown2));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->unknown2), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->unknown2, ndr_get_array_length(ndr, &r->unknown2), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown2_0, 0);
+ }
+ if (r->unknown3) {
+ _mem_save_unknown3_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->unknown3, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->unknown3));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->unknown3));
+ if (ndr_get_array_length(ndr, &r->unknown3) > ndr_get_array_size(ndr, &r->unknown3)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->unknown3), ndr_get_array_length(ndr, &r->unknown3));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->unknown3), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->unknown3, ndr_get_array_length(ndr, &r->unknown3), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown3_0, 0);
+ }
+ if (r->unknown4) {
+ _mem_save_unknown4_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->unknown4, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->unknown4));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->unknown4));
+ if (ndr_get_array_length(ndr, &r->unknown4) > ndr_get_array_size(ndr, &r->unknown4)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->unknown4), ndr_get_array_length(ndr, &r->unknown4));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->unknown4), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->unknown4, ndr_get_array_length(ndr, &r->unknown4), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown4_0, 0);
+ }
+ NDR_CHECK(ndr_pull_netr_BinaryString(ndr, NDR_BUFFERS, &r->blob2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->product));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown5));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown6));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DomainQuery1(struct ndr_print *ndr, const char *name, const struct netr_DomainQuery1 *r)
+{
+ uint32_t cntr_unknown7_0;
+ ndr_print_struct(ndr, name, "netr_DomainQuery1");
+ ndr->depth++;
+ ndr_print_netr_Blob(ndr, "blob", &r->blob);
+ ndr_print_ptr(ndr, "workstation_domain", r->workstation_domain);
+ ndr->depth++;
+ if (r->workstation_domain) {
+ ndr_print_string(ndr, "workstation_domain", r->workstation_domain);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "workstation_site", r->workstation_site);
+ ndr->depth++;
+ if (r->workstation_site) {
+ ndr_print_string(ndr, "workstation_site", r->workstation_site);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "unknown1", r->unknown1);
+ ndr->depth++;
+ if (r->unknown1) {
+ ndr_print_string(ndr, "unknown1", r->unknown1);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "unknown2", r->unknown2);
+ ndr->depth++;
+ if (r->unknown2) {
+ ndr_print_string(ndr, "unknown2", r->unknown2);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "unknown3", r->unknown3);
+ ndr->depth++;
+ if (r->unknown3) {
+ ndr_print_string(ndr, "unknown3", r->unknown3);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "unknown4", r->unknown4);
+ ndr->depth++;
+ if (r->unknown4) {
+ ndr_print_string(ndr, "unknown4", r->unknown4);
+ }
+ ndr->depth--;
+ ndr_print_netr_BinaryString(ndr, "blob2", &r->blob2);
+ ndr_print_lsa_String(ndr, "product", &r->product);
+ ndr_print_lsa_String(ndr, "unknown5", &r->unknown5);
+ ndr_print_lsa_String(ndr, "unknown6", &r->unknown6);
+ ndr->print(ndr, "%s: ARRAY(%d)", "unknown7", (int)4);
+ ndr->depth++;
+ for (cntr_unknown7_0=0;cntr_unknown7_0<4;cntr_unknown7_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_unknown7_0) != -1) {
+ ndr_print_uint32(ndr, "unknown7", r->unknown7[cntr_unknown7_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DomainQuery(struct ndr_push *ndr, int ndr_flags, const union netr_DomainQuery *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->query1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->query1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ if (r->query1) {
+ NDR_CHECK(ndr_push_netr_DomainQuery1(ndr, NDR_SCALARS|NDR_BUFFERS, r->query1));
+ }
+ break;
+
+ case 2:
+ if (r->query1) {
+ NDR_CHECK(ndr_push_netr_DomainQuery1(ndr, NDR_SCALARS|NDR_BUFFERS, r->query1));
+ }
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DomainQuery(struct ndr_pull *ndr, int ndr_flags, union netr_DomainQuery *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_query1_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ uint32_t _ptr_query1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_query1));
+ if (_ptr_query1) {
+ NDR_PULL_ALLOC(ndr, r->query1);
+ } else {
+ r->query1 = NULL;
+ }
+ break; }
+
+ case 2: {
+ uint32_t _ptr_query1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_query1));
+ if (_ptr_query1) {
+ NDR_PULL_ALLOC(ndr, r->query1);
+ } else {
+ r->query1 = NULL;
+ }
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ if (r->query1) {
+ _mem_save_query1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->query1, 0);
+ NDR_CHECK(ndr_pull_netr_DomainQuery1(ndr, NDR_SCALARS|NDR_BUFFERS, r->query1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_query1_0, 0);
+ }
+ break;
+
+ case 2:
+ if (r->query1) {
+ _mem_save_query1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->query1, 0);
+ NDR_CHECK(ndr_pull_netr_DomainQuery1(ndr, NDR_SCALARS|NDR_BUFFERS, r->query1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_query1_0, 0);
+ }
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DomainQuery(struct ndr_print *ndr, const char *name, const union netr_DomainQuery *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "netr_DomainQuery");
+ switch (level) {
+ case 1:
+ ndr_print_ptr(ndr, "query1", r->query1);
+ ndr->depth++;
+ if (r->query1) {
+ ndr_print_netr_DomainQuery1(ndr, "query1", r->query1);
+ }
+ ndr->depth--;
+ break;
+
+ case 2:
+ ndr_print_ptr(ndr, "query1", r->query1);
+ ndr->depth++;
+ if (r->query1) {
+ ndr_print_netr_DomainQuery1(ndr, "query1", r->query1);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_netr_DomainTrustInfo(struct ndr_push *ndr, int ndr_flags, const struct netr_DomainTrustInfo *r)
+{
+ uint32_t cntr_unknown1_0;
+ uint32_t cntr_unknown_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->domainname));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->fulldomainname));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->forest));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->guid));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sid));
+ for (cntr_unknown1_0 = 0; cntr_unknown1_0 < 4; cntr_unknown1_0++) {
+ NDR_CHECK(ndr_push_netr_BinaryString(ndr, NDR_SCALARS, &r->unknown1[cntr_unknown1_0]));
+ }
+ for (cntr_unknown_0 = 0; cntr_unknown_0 < 4; cntr_unknown_0++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown[cntr_unknown_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->domainname));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->fulldomainname));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->forest));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_BUFFERS, &r->guid));
+ if (r->sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ }
+ for (cntr_unknown1_0 = 0; cntr_unknown1_0 < 4; cntr_unknown1_0++) {
+ NDR_CHECK(ndr_push_netr_BinaryString(ndr, NDR_BUFFERS, &r->unknown1[cntr_unknown1_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DomainTrustInfo(struct ndr_pull *ndr, int ndr_flags, struct netr_DomainTrustInfo *r)
+{
+ uint32_t _ptr_sid;
+ TALLOC_CTX *_mem_save_sid_0;
+ uint32_t cntr_unknown1_0;
+ uint32_t cntr_unknown_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->domainname));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->fulldomainname));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->forest));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->guid));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sid));
+ if (_ptr_sid) {
+ NDR_PULL_ALLOC(ndr, r->sid);
+ } else {
+ r->sid = NULL;
+ }
+ for (cntr_unknown1_0 = 0; cntr_unknown1_0 < 4; cntr_unknown1_0++) {
+ NDR_CHECK(ndr_pull_netr_BinaryString(ndr, NDR_SCALARS, &r->unknown1[cntr_unknown1_0]));
+ }
+ for (cntr_unknown_0 = 0; cntr_unknown_0 < 4; cntr_unknown_0++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown[cntr_unknown_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->domainname));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->fulldomainname));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->forest));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_BUFFERS, &r->guid));
+ if (r->sid) {
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, 0);
+ }
+ for (cntr_unknown1_0 = 0; cntr_unknown1_0 < 4; cntr_unknown1_0++) {
+ NDR_CHECK(ndr_pull_netr_BinaryString(ndr, NDR_BUFFERS, &r->unknown1[cntr_unknown1_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DomainTrustInfo(struct ndr_print *ndr, const char *name, const struct netr_DomainTrustInfo *r)
+{
+ uint32_t cntr_unknown1_0;
+ uint32_t cntr_unknown_0;
+ ndr_print_struct(ndr, name, "netr_DomainTrustInfo");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "domainname", &r->domainname);
+ ndr_print_lsa_String(ndr, "fulldomainname", &r->fulldomainname);
+ ndr_print_lsa_String(ndr, "forest", &r->forest);
+ ndr_print_GUID(ndr, "guid", &r->guid);
+ ndr_print_ptr(ndr, "sid", r->sid);
+ ndr->depth++;
+ if (r->sid) {
+ ndr_print_dom_sid2(ndr, "sid", r->sid);
+ }
+ ndr->depth--;
+ ndr->print(ndr, "%s: ARRAY(%d)", "unknown1", (int)4);
+ ndr->depth++;
+ for (cntr_unknown1_0=0;cntr_unknown1_0<4;cntr_unknown1_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_unknown1_0) != -1) {
+ ndr_print_netr_BinaryString(ndr, "unknown1", &r->unknown1[cntr_unknown1_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->print(ndr, "%s: ARRAY(%d)", "unknown", (int)4);
+ ndr->depth++;
+ for (cntr_unknown_0=0;cntr_unknown_0<4;cntr_unknown_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_unknown_0) != -1) {
+ ndr_print_uint32(ndr, "unknown", r->unknown[cntr_unknown_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DomainInfo1(struct ndr_push *ndr, int ndr_flags, const struct netr_DomainInfo1 *r)
+{
+ uint32_t cntr_trusts_1;
+ uint32_t cntr_unknown_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netr_DomainTrustInfo(ndr, NDR_SCALARS, &r->domaininfo));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_trusts));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->trusts));
+ for (cntr_unknown_0 = 0; cntr_unknown_0 < 14; cntr_unknown_0++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown[cntr_unknown_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_netr_DomainTrustInfo(ndr, NDR_BUFFERS, &r->domaininfo));
+ if (r->trusts) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_trusts));
+ for (cntr_trusts_1 = 0; cntr_trusts_1 < r->num_trusts; cntr_trusts_1++) {
+ NDR_CHECK(ndr_push_netr_DomainTrustInfo(ndr, NDR_SCALARS, &r->trusts[cntr_trusts_1]));
+ }
+ for (cntr_trusts_1 = 0; cntr_trusts_1 < r->num_trusts; cntr_trusts_1++) {
+ NDR_CHECK(ndr_push_netr_DomainTrustInfo(ndr, NDR_BUFFERS, &r->trusts[cntr_trusts_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DomainInfo1(struct ndr_pull *ndr, int ndr_flags, struct netr_DomainInfo1 *r)
+{
+ uint32_t _ptr_trusts;
+ uint32_t cntr_trusts_1;
+ TALLOC_CTX *_mem_save_trusts_0;
+ TALLOC_CTX *_mem_save_trusts_1;
+ uint32_t cntr_unknown_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netr_DomainTrustInfo(ndr, NDR_SCALARS, &r->domaininfo));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_trusts));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_trusts));
+ if (_ptr_trusts) {
+ NDR_PULL_ALLOC(ndr, r->trusts);
+ } else {
+ r->trusts = NULL;
+ }
+ for (cntr_unknown_0 = 0; cntr_unknown_0 < 14; cntr_unknown_0++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown[cntr_unknown_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_netr_DomainTrustInfo(ndr, NDR_BUFFERS, &r->domaininfo));
+ if (r->trusts) {
+ _mem_save_trusts_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->trusts, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->trusts));
+ NDR_PULL_ALLOC_N(ndr, r->trusts, ndr_get_array_size(ndr, &r->trusts));
+ _mem_save_trusts_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->trusts, 0);
+ for (cntr_trusts_1 = 0; cntr_trusts_1 < r->num_trusts; cntr_trusts_1++) {
+ NDR_CHECK(ndr_pull_netr_DomainTrustInfo(ndr, NDR_SCALARS, &r->trusts[cntr_trusts_1]));
+ }
+ for (cntr_trusts_1 = 0; cntr_trusts_1 < r->num_trusts; cntr_trusts_1++) {
+ NDR_CHECK(ndr_pull_netr_DomainTrustInfo(ndr, NDR_BUFFERS, &r->trusts[cntr_trusts_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_trusts_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_trusts_0, 0);
+ }
+ if (r->trusts) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->trusts, r->num_trusts));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DomainInfo1(struct ndr_print *ndr, const char *name, const struct netr_DomainInfo1 *r)
+{
+ uint32_t cntr_trusts_1;
+ uint32_t cntr_unknown_0;
+ ndr_print_struct(ndr, name, "netr_DomainInfo1");
+ ndr->depth++;
+ ndr_print_netr_DomainTrustInfo(ndr, "domaininfo", &r->domaininfo);
+ ndr_print_uint32(ndr, "num_trusts", r->num_trusts);
+ ndr_print_ptr(ndr, "trusts", r->trusts);
+ ndr->depth++;
+ if (r->trusts) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "trusts", (int)r->num_trusts);
+ ndr->depth++;
+ for (cntr_trusts_1=0;cntr_trusts_1<r->num_trusts;cntr_trusts_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_trusts_1) != -1) {
+ ndr_print_netr_DomainTrustInfo(ndr, "trusts", &r->trusts[cntr_trusts_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->print(ndr, "%s: ARRAY(%d)", "unknown", (int)14);
+ ndr->depth++;
+ for (cntr_unknown_0=0;cntr_unknown_0<14;cntr_unknown_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_unknown_0) != -1) {
+ ndr_print_uint32(ndr, "unknown", r->unknown[cntr_unknown_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DomainInfo(struct ndr_push *ndr, int ndr_flags, const union netr_DomainInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ if (r->info1) {
+ NDR_CHECK(ndr_push_netr_DomainInfo1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ }
+ break;
+
+ case 2:
+ if (r->info1) {
+ NDR_CHECK(ndr_push_netr_DomainInfo1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ }
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DomainInfo(struct ndr_pull *ndr, int ndr_flags, union netr_DomainInfo *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_info1_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ uint32_t _ptr_info1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1));
+ if (_ptr_info1) {
+ NDR_PULL_ALLOC(ndr, r->info1);
+ } else {
+ r->info1 = NULL;
+ }
+ break; }
+
+ case 2: {
+ uint32_t _ptr_info1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1));
+ if (_ptr_info1) {
+ NDR_PULL_ALLOC(ndr, r->info1);
+ } else {
+ r->info1 = NULL;
+ }
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ if (r->info1) {
+ _mem_save_info1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1, 0);
+ NDR_CHECK(ndr_pull_netr_DomainInfo1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1_0, 0);
+ }
+ break;
+
+ case 2:
+ if (r->info1) {
+ _mem_save_info1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1, 0);
+ NDR_CHECK(ndr_pull_netr_DomainInfo1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1_0, 0);
+ }
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DomainInfo(struct ndr_print *ndr, const char *name, const union netr_DomainInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "netr_DomainInfo");
+ switch (level) {
+ case 1:
+ ndr_print_ptr(ndr, "info1", r->info1);
+ ndr->depth++;
+ if (r->info1) {
+ ndr_print_netr_DomainInfo1(ndr, "info1", r->info1);
+ }
+ ndr->depth--;
+ break;
+
+ case 2:
+ ndr_print_ptr(ndr, "info1", r->info1);
+ ndr->depth++;
+ if (r->info1) {
+ ndr_print_netr_DomainInfo1(ndr, "info1", r->info1);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_netr_CryptPassword(struct ndr_push *ndr, int ndr_flags, const struct netr_CryptPassword *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data, 512));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_CryptPassword(struct ndr_pull *ndr, int ndr_flags, struct netr_CryptPassword *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data, 512));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->length));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_CryptPassword(struct ndr_print *ndr, const char *name, const struct netr_CryptPassword *r)
+{
+ ndr_print_struct(ndr, name, "netr_CryptPassword");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "data", r->data, 512);
+ ndr_print_uint32(ndr, "length", r->length);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_netr_DsRAddressToSitenamesWCtr(struct ndr_push *ndr, int ndr_flags, const struct netr_DsRAddressToSitenamesWCtr *r)
+{
+ uint32_t cntr_sitename_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sitename));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sitename) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_sitename_1 = 0; cntr_sitename_1 < r->count; cntr_sitename_1++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->sitename[cntr_sitename_1]));
+ }
+ for (cntr_sitename_1 = 0; cntr_sitename_1 < r->count; cntr_sitename_1++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->sitename[cntr_sitename_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DsRAddressToSitenamesWCtr(struct ndr_pull *ndr, int ndr_flags, struct netr_DsRAddressToSitenamesWCtr *r)
+{
+ uint32_t _ptr_sitename;
+ uint32_t cntr_sitename_1;
+ TALLOC_CTX *_mem_save_sitename_0;
+ TALLOC_CTX *_mem_save_sitename_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sitename));
+ if (_ptr_sitename) {
+ NDR_PULL_ALLOC(ndr, r->sitename);
+ } else {
+ r->sitename = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sitename) {
+ _mem_save_sitename_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sitename, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->sitename));
+ NDR_PULL_ALLOC_N(ndr, r->sitename, ndr_get_array_size(ndr, &r->sitename));
+ _mem_save_sitename_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sitename, 0);
+ for (cntr_sitename_1 = 0; cntr_sitename_1 < r->count; cntr_sitename_1++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->sitename[cntr_sitename_1]));
+ }
+ for (cntr_sitename_1 = 0; cntr_sitename_1 < r->count; cntr_sitename_1++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->sitename[cntr_sitename_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sitename_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sitename_0, 0);
+ }
+ if (r->sitename) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->sitename, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsRAddressToSitenamesWCtr(struct ndr_print *ndr, const char *name, const struct netr_DsRAddressToSitenamesWCtr *r)
+{
+ uint32_t cntr_sitename_1;
+ ndr_print_struct(ndr, name, "netr_DsRAddressToSitenamesWCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "sitename", r->sitename);
+ ndr->depth++;
+ if (r->sitename) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "sitename", (int)r->count);
+ ndr->depth++;
+ for (cntr_sitename_1=0;cntr_sitename_1<r->count;cntr_sitename_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_sitename_1) != -1) {
+ ndr_print_lsa_String(ndr, "sitename", &r->sitename[cntr_sitename_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DsRAddress(struct ndr_push *ndr, int ndr_flags, const struct netr_DsRAddress *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->buffer));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->buffer) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->buffer, r->size));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DsRAddress(struct ndr_pull *ndr, int ndr_flags, struct netr_DsRAddress *r)
+{
+ uint32_t _ptr_buffer;
+ TALLOC_CTX *_mem_save_buffer_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_buffer));
+ if (_ptr_buffer) {
+ NDR_PULL_ALLOC(ndr, r->buffer);
+ } else {
+ r->buffer = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->size));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->buffer) {
+ _mem_save_buffer_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->buffer, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->buffer));
+ NDR_PULL_ALLOC_N(ndr, r->buffer, ndr_get_array_size(ndr, &r->buffer));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->buffer, ndr_get_array_size(ndr, &r->buffer)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_buffer_0, 0);
+ }
+ if (r->buffer) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->buffer, r->size));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsRAddress(struct ndr_print *ndr, const char *name, const struct netr_DsRAddress *r)
+{
+ ndr_print_struct(ndr, name, "netr_DsRAddress");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->buffer);
+ ndr->depth++;
+ if (r->buffer) {
+ ndr_print_array_uint8(ndr, "buffer", r->buffer, r->size);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "size", r->size);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_TrustFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_TrustFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_TrustFlags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETR_TRUST_FLAG_IN_FOREST", NETR_TRUST_FLAG_IN_FOREST, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETR_TRUST_FLAG_OUTBOUND", NETR_TRUST_FLAG_OUTBOUND, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETR_TRUST_FLAG_TREEROOT", NETR_TRUST_FLAG_TREEROOT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETR_TRUST_FLAG_PRIMARY", NETR_TRUST_FLAG_PRIMARY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETR_TRUST_FLAG_NATIVE", NETR_TRUST_FLAG_NATIVE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETR_TRUST_FLAG_INBOUND", NETR_TRUST_FLAG_INBOUND, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_TrustType(struct ndr_push *ndr, int ndr_flags, enum netr_TrustType r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_TrustType(struct ndr_pull *ndr, int ndr_flags, enum netr_TrustType *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_TrustType(struct ndr_print *ndr, const char *name, enum netr_TrustType r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case NETR_TRUST_TYPE_DOWNLEVEL: val = "NETR_TRUST_TYPE_DOWNLEVEL"; break;
+ case NETR_TRUST_TYPE_UPLEVEL: val = "NETR_TRUST_TYPE_UPLEVEL"; break;
+ case NETR_TRUST_TYPE_MIT: val = "NETR_TRUST_TYPE_MIT"; break;
+ case NETR_TRUST_TYPE_DCE: val = "NETR_TRUST_TYPE_DCE"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_netr_TrustAttributes(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_TrustAttributes(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_TrustAttributes(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE", NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETR_TRUST_ATTRIBUTE_UPLEVEL_ONLY", NETR_TRUST_ATTRIBUTE_UPLEVEL_ONLY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN", NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE", NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETR_TRUST_ATTRIBUTE_CROSS_ORGANIZATION", NETR_TRUST_ATTRIBUTE_CROSS_ORGANIZATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETR_TRUST_ATTRIBUTE_WITHIN_FOREST", NETR_TRUST_ATTRIBUTE_WITHIN_FOREST, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL", NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DomainTrust(struct ndr_push *ndr, int ndr_flags, const struct netr_DomainTrust *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->netbios_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->dns_name));
+ NDR_CHECK(ndr_push_netr_TrustFlags(ndr, NDR_SCALARS, r->trust_flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->parent_index));
+ NDR_CHECK(ndr_push_netr_TrustType(ndr, NDR_SCALARS, r->trust_type));
+ NDR_CHECK(ndr_push_netr_TrustAttributes(ndr, NDR_SCALARS, r->trust_attributes));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sid));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->guid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->netbios_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->netbios_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->netbios_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->netbios_name, ndr_charset_length(r->netbios_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->dns_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dns_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->dns_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->dns_name, ndr_charset_length(r->dns_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ }
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_BUFFERS, &r->guid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DomainTrust(struct ndr_pull *ndr, int ndr_flags, struct netr_DomainTrust *r)
+{
+ uint32_t _ptr_netbios_name;
+ TALLOC_CTX *_mem_save_netbios_name_0;
+ uint32_t _ptr_dns_name;
+ TALLOC_CTX *_mem_save_dns_name_0;
+ uint32_t _ptr_sid;
+ TALLOC_CTX *_mem_save_sid_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_netbios_name));
+ if (_ptr_netbios_name) {
+ NDR_PULL_ALLOC(ndr, r->netbios_name);
+ } else {
+ r->netbios_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dns_name));
+ if (_ptr_dns_name) {
+ NDR_PULL_ALLOC(ndr, r->dns_name);
+ } else {
+ r->dns_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_netr_TrustFlags(ndr, NDR_SCALARS, &r->trust_flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->parent_index));
+ NDR_CHECK(ndr_pull_netr_TrustType(ndr, NDR_SCALARS, &r->trust_type));
+ NDR_CHECK(ndr_pull_netr_TrustAttributes(ndr, NDR_SCALARS, &r->trust_attributes));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sid));
+ if (_ptr_sid) {
+ NDR_PULL_ALLOC(ndr, r->sid);
+ } else {
+ r->sid = NULL;
+ }
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->guid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->netbios_name) {
+ _mem_save_netbios_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->netbios_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->netbios_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->netbios_name));
+ if (ndr_get_array_length(ndr, &r->netbios_name) > ndr_get_array_size(ndr, &r->netbios_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->netbios_name), ndr_get_array_length(ndr, &r->netbios_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->netbios_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->netbios_name, ndr_get_array_length(ndr, &r->netbios_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_netbios_name_0, 0);
+ }
+ if (r->dns_name) {
+ _mem_save_dns_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->dns_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->dns_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->dns_name));
+ if (ndr_get_array_length(ndr, &r->dns_name) > ndr_get_array_size(ndr, &r->dns_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->dns_name), ndr_get_array_length(ndr, &r->dns_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->dns_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->dns_name, ndr_get_array_length(ndr, &r->dns_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dns_name_0, 0);
+ }
+ if (r->sid) {
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, 0);
+ }
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_BUFFERS, &r->guid));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DomainTrust(struct ndr_print *ndr, const char *name, const struct netr_DomainTrust *r)
+{
+ ndr_print_struct(ndr, name, "netr_DomainTrust");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "netbios_name", r->netbios_name);
+ ndr->depth++;
+ if (r->netbios_name) {
+ ndr_print_string(ndr, "netbios_name", r->netbios_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "dns_name", r->dns_name);
+ ndr->depth++;
+ if (r->dns_name) {
+ ndr_print_string(ndr, "dns_name", r->dns_name);
+ }
+ ndr->depth--;
+ ndr_print_netr_TrustFlags(ndr, "trust_flags", r->trust_flags);
+ ndr_print_uint32(ndr, "parent_index", r->parent_index);
+ ndr_print_netr_TrustType(ndr, "trust_type", r->trust_type);
+ ndr_print_netr_TrustAttributes(ndr, "trust_attributes", r->trust_attributes);
+ ndr_print_ptr(ndr, "sid", r->sid);
+ ndr->depth++;
+ if (r->sid) {
+ ndr_print_dom_sid2(ndr, "sid", r->sid);
+ }
+ ndr->depth--;
+ ndr_print_GUID(ndr, "guid", &r->guid);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DomainTrustList(struct ndr_push *ndr, int ndr_flags, const struct netr_DomainTrustList *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_netr_DomainTrust(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_netr_DomainTrust(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DomainTrustList(struct ndr_pull *ndr, int ndr_flags, struct netr_DomainTrustList *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_netr_DomainTrust(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_netr_DomainTrust(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DomainTrustList(struct ndr_print *ndr, const char *name, const struct netr_DomainTrustList *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "netr_DomainTrustList");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_netr_DomainTrust(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DsRAddressToSitenamesExWCtr(struct ndr_push *ndr, int ndr_flags, const struct netr_DsRAddressToSitenamesExWCtr *r)
+{
+ uint32_t cntr_sitename_1;
+ uint32_t cntr_subnetname_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sitename));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->subnetname));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sitename) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_sitename_1 = 0; cntr_sitename_1 < r->count; cntr_sitename_1++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->sitename[cntr_sitename_1]));
+ }
+ for (cntr_sitename_1 = 0; cntr_sitename_1 < r->count; cntr_sitename_1++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->sitename[cntr_sitename_1]));
+ }
+ }
+ if (r->subnetname) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_subnetname_1 = 0; cntr_subnetname_1 < r->count; cntr_subnetname_1++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->subnetname[cntr_subnetname_1]));
+ }
+ for (cntr_subnetname_1 = 0; cntr_subnetname_1 < r->count; cntr_subnetname_1++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->subnetname[cntr_subnetname_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DsRAddressToSitenamesExWCtr(struct ndr_pull *ndr, int ndr_flags, struct netr_DsRAddressToSitenamesExWCtr *r)
+{
+ uint32_t _ptr_sitename;
+ uint32_t cntr_sitename_1;
+ TALLOC_CTX *_mem_save_sitename_0;
+ TALLOC_CTX *_mem_save_sitename_1;
+ uint32_t _ptr_subnetname;
+ uint32_t cntr_subnetname_1;
+ TALLOC_CTX *_mem_save_subnetname_0;
+ TALLOC_CTX *_mem_save_subnetname_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sitename));
+ if (_ptr_sitename) {
+ NDR_PULL_ALLOC(ndr, r->sitename);
+ } else {
+ r->sitename = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_subnetname));
+ if (_ptr_subnetname) {
+ NDR_PULL_ALLOC(ndr, r->subnetname);
+ } else {
+ r->subnetname = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sitename) {
+ _mem_save_sitename_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sitename, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->sitename));
+ NDR_PULL_ALLOC_N(ndr, r->sitename, ndr_get_array_size(ndr, &r->sitename));
+ _mem_save_sitename_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sitename, 0);
+ for (cntr_sitename_1 = 0; cntr_sitename_1 < r->count; cntr_sitename_1++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->sitename[cntr_sitename_1]));
+ }
+ for (cntr_sitename_1 = 0; cntr_sitename_1 < r->count; cntr_sitename_1++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->sitename[cntr_sitename_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sitename_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sitename_0, 0);
+ }
+ if (r->subnetname) {
+ _mem_save_subnetname_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->subnetname, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->subnetname));
+ NDR_PULL_ALLOC_N(ndr, r->subnetname, ndr_get_array_size(ndr, &r->subnetname));
+ _mem_save_subnetname_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->subnetname, 0);
+ for (cntr_subnetname_1 = 0; cntr_subnetname_1 < r->count; cntr_subnetname_1++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->subnetname[cntr_subnetname_1]));
+ }
+ for (cntr_subnetname_1 = 0; cntr_subnetname_1 < r->count; cntr_subnetname_1++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->subnetname[cntr_subnetname_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_subnetname_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_subnetname_0, 0);
+ }
+ if (r->sitename) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->sitename, r->count));
+ }
+ if (r->subnetname) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->subnetname, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsRAddressToSitenamesExWCtr(struct ndr_print *ndr, const char *name, const struct netr_DsRAddressToSitenamesExWCtr *r)
+{
+ uint32_t cntr_sitename_1;
+ uint32_t cntr_subnetname_1;
+ ndr_print_struct(ndr, name, "netr_DsRAddressToSitenamesExWCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "sitename", r->sitename);
+ ndr->depth++;
+ if (r->sitename) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "sitename", (int)r->count);
+ ndr->depth++;
+ for (cntr_sitename_1=0;cntr_sitename_1<r->count;cntr_sitename_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_sitename_1) != -1) {
+ ndr_print_lsa_String(ndr, "sitename", &r->sitename[cntr_sitename_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "subnetname", r->subnetname);
+ ndr->depth++;
+ if (r->subnetname) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "subnetname", (int)r->count);
+ ndr->depth++;
+ for (cntr_subnetname_1=0;cntr_subnetname_1<r->count;cntr_subnetname_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_subnetname_1) != -1) {
+ ndr_print_lsa_String(ndr, "subnetname", &r->subnetname[cntr_subnetname_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_DcSitesCtr(struct ndr_push *ndr, int ndr_flags, const struct DcSitesCtr *r)
+{
+ uint32_t cntr_sites_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_sites));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sites));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sites) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_sites));
+ for (cntr_sites_1 = 0; cntr_sites_1 < r->num_sites; cntr_sites_1++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->sites[cntr_sites_1]));
+ }
+ for (cntr_sites_1 = 0; cntr_sites_1 < r->num_sites; cntr_sites_1++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->sites[cntr_sites_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_DcSitesCtr(struct ndr_pull *ndr, int ndr_flags, struct DcSitesCtr *r)
+{
+ uint32_t _ptr_sites;
+ uint32_t cntr_sites_1;
+ TALLOC_CTX *_mem_save_sites_0;
+ TALLOC_CTX *_mem_save_sites_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_sites));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sites));
+ if (_ptr_sites) {
+ NDR_PULL_ALLOC(ndr, r->sites);
+ } else {
+ r->sites = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sites) {
+ _mem_save_sites_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sites, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->sites));
+ NDR_PULL_ALLOC_N(ndr, r->sites, ndr_get_array_size(ndr, &r->sites));
+ _mem_save_sites_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sites, 0);
+ for (cntr_sites_1 = 0; cntr_sites_1 < r->num_sites; cntr_sites_1++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->sites[cntr_sites_1]));
+ }
+ for (cntr_sites_1 = 0; cntr_sites_1 < r->num_sites; cntr_sites_1++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->sites[cntr_sites_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sites_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sites_0, 0);
+ }
+ if (r->sites) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->sites, r->num_sites));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_DcSitesCtr(struct ndr_print *ndr, const char *name, const struct DcSitesCtr *r)
+{
+ uint32_t cntr_sites_1;
+ ndr_print_struct(ndr, name, "DcSitesCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_sites", r->num_sites);
+ ndr_print_ptr(ndr, "sites", r->sites);
+ ndr->depth++;
+ if (r->sites) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "sites", (int)r->num_sites);
+ ndr->depth++;
+ for (cntr_sites_1=0;cntr_sites_1<r->num_sites;cntr_sites_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_sites_1) != -1) {
+ ndr_print_lsa_String(ndr, "sites", &r->sites[cntr_sites_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_LogonUasLogon(struct ndr_push *ndr, int flags, const struct netr_LogonUasLogon *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.account_name, ndr_charset_length(r->in.account_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.workstation, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.workstation, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.workstation, ndr_charset_length(r->in.workstation, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_UasInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_LogonUasLogon(struct ndr_pull *ndr, int flags, struct netr_LogonUasLogon *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.account_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.account_name));
+ if (ndr_get_array_length(ndr, &r->in.account_name) > ndr_get_array_size(ndr, &r->in.account_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.account_name), ndr_get_array_length(ndr, &r->in.account_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.account_name, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.workstation));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.workstation));
+ if (ndr_get_array_length(ndr, &r->in.workstation) > ndr_get_array_size(ndr, &r->in.workstation)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.workstation), ndr_get_array_length(ndr, &r->in.workstation));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.workstation), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.workstation, ndr_get_array_length(ndr, &r->in.workstation), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_UasInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_LogonUasLogon(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonUasLogon *r)
+{
+ ndr_print_struct(ndr, name, "netr_LogonUasLogon");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_LogonUasLogon");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "account_name", r->in.account_name);
+ ndr_print_string(ndr, "workstation", r->in.workstation);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_LogonUasLogon");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_netr_UasInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_LogonUasLogoff(struct ndr_push *ndr, int flags, const struct netr_LogonUasLogoff *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.account_name, ndr_charset_length(r->in.account_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.workstation, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.workstation, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.workstation, ndr_charset_length(r->in.workstation, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_UasLogoffInfo(ndr, NDR_SCALARS, r->out.info));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_LogonUasLogoff(struct ndr_pull *ndr, int flags, struct netr_LogonUasLogoff *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.account_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.account_name));
+ if (ndr_get_array_length(ndr, &r->in.account_name) > ndr_get_array_size(ndr, &r->in.account_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.account_name), ndr_get_array_length(ndr, &r->in.account_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.account_name, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.workstation));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.workstation));
+ if (ndr_get_array_length(ndr, &r->in.workstation) > ndr_get_array_size(ndr, &r->in.workstation)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.workstation), ndr_get_array_length(ndr, &r->in.workstation));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.workstation), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.workstation, ndr_get_array_length(ndr, &r->in.workstation), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_UasLogoffInfo(ndr, NDR_SCALARS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_LogonUasLogoff(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonUasLogoff *r)
+{
+ ndr_print_struct(ndr, name, "netr_LogonUasLogoff");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_LogonUasLogoff");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "account_name", r->in.account_name);
+ ndr_print_string(ndr, "workstation", r->in.workstation);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_LogonUasLogoff");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_netr_UasLogoffInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_LogonSamLogon(struct ndr_push *ndr, int flags, const struct netr_LogonSamLogon *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.computer_name));
+ if (r->in.computer_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computer_name, ndr_charset_length(r->in.computer_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.credential));
+ if (r->in.credential) {
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.return_authenticator));
+ if (r->in.return_authenticator) {
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ }
+ NDR_CHECK(ndr_push_netr_LogonLevel(ndr, NDR_SCALARS, r->in.logon_level));
+ if (r->in.logon == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.logon, r->in.logon_level));
+ NDR_CHECK(ndr_push_netr_LogonInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.logon));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.validation_level));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.return_authenticator));
+ if (r->out.return_authenticator) {
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ }
+ if (r->out.validation == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.validation, r->in.validation_level));
+ NDR_CHECK(ndr_push_netr_Validation(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.validation));
+ if (r->out.authoritative == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, *r->out.authoritative));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_LogonSamLogon(struct ndr_pull *ndr, int flags, struct netr_LogonSamLogon *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_computer_name;
+ uint32_t _ptr_credential;
+ uint32_t _ptr_return_authenticator;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_computer_name_0;
+ TALLOC_CTX *_mem_save_credential_0;
+ TALLOC_CTX *_mem_save_return_authenticator_0;
+ TALLOC_CTX *_mem_save_logon_0;
+ TALLOC_CTX *_mem_save_validation_0;
+ TALLOC_CTX *_mem_save_authoritative_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_computer_name));
+ if (_ptr_computer_name) {
+ NDR_PULL_ALLOC(ndr, r->in.computer_name);
+ } else {
+ r->in.computer_name = NULL;
+ }
+ if (r->in.computer_name) {
+ _mem_save_computer_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.computer_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computer_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computer_name));
+ if (ndr_get_array_length(ndr, &r->in.computer_name) > ndr_get_array_size(ndr, &r->in.computer_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computer_name), ndr_get_array_length(ndr, &r->in.computer_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computer_name, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_computer_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_credential));
+ if (_ptr_credential) {
+ NDR_PULL_ALLOC(ndr, r->in.credential);
+ } else {
+ r->in.credential = NULL;
+ }
+ if (r->in.credential) {
+ _mem_save_credential_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.credential, 0);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_credential_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_return_authenticator));
+ if (_ptr_return_authenticator) {
+ NDR_PULL_ALLOC(ndr, r->in.return_authenticator);
+ } else {
+ r->in.return_authenticator = NULL;
+ }
+ if (r->in.return_authenticator) {
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.return_authenticator, 0);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, 0);
+ }
+ NDR_CHECK(ndr_pull_netr_LogonLevel(ndr, NDR_SCALARS, &r->in.logon_level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.logon);
+ }
+ _mem_save_logon_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.logon, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.logon, r->in.logon_level));
+ NDR_CHECK(ndr_pull_netr_LogonInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.logon));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_logon_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.validation_level));
+ NDR_PULL_ALLOC(ndr, r->out.validation);
+ ZERO_STRUCTP(r->out.validation);
+ NDR_PULL_ALLOC(ndr, r->out.authoritative);
+ ZERO_STRUCTP(r->out.authoritative);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_return_authenticator));
+ if (_ptr_return_authenticator) {
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ } else {
+ r->out.return_authenticator = NULL;
+ }
+ if (r->out.return_authenticator) {
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_authenticator, 0);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.validation);
+ }
+ _mem_save_validation_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.validation, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.validation, r->in.validation_level));
+ NDR_CHECK(ndr_pull_netr_Validation(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.validation));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_validation_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.authoritative);
+ }
+ _mem_save_authoritative_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.authoritative, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, r->out.authoritative));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_authoritative_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_LogonSamLogon(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonSamLogon *r)
+{
+ ndr_print_struct(ndr, name, "netr_LogonSamLogon");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_LogonSamLogon");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "computer_name", r->in.computer_name);
+ ndr->depth++;
+ if (r->in.computer_name) {
+ ndr_print_string(ndr, "computer_name", r->in.computer_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "credential", r->in.credential);
+ ndr->depth++;
+ if (r->in.credential) {
+ ndr_print_netr_Authenticator(ndr, "credential", r->in.credential);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth++;
+ if (r->in.return_authenticator) {
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->in.return_authenticator);
+ }
+ ndr->depth--;
+ ndr_print_netr_LogonLevel(ndr, "logon_level", r->in.logon_level);
+ ndr_print_ptr(ndr, "logon", r->in.logon);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.logon, r->in.logon_level);
+ ndr_print_netr_LogonInfo(ndr, "logon", r->in.logon);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "validation_level", r->in.validation_level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_LogonSamLogon");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth++;
+ if (r->out.return_authenticator) {
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->out.return_authenticator);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "validation", r->out.validation);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.validation, r->in.validation_level);
+ ndr_print_netr_Validation(ndr, "validation", r->out.validation);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "authoritative", r->out.authoritative);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "authoritative", *r->out.authoritative);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_LogonSamLogoff(struct ndr_push *ndr, int flags, const struct netr_LogonSamLogoff *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.computer_name));
+ if (r->in.computer_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computer_name, ndr_charset_length(r->in.computer_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.credential));
+ if (r->in.credential) {
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.return_authenticator));
+ if (r->in.return_authenticator) {
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ }
+ NDR_CHECK(ndr_push_netr_LogonLevel(ndr, NDR_SCALARS, r->in.logon_level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->in.logon, r->in.logon_level));
+ NDR_CHECK(ndr_push_netr_LogonInfo(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.logon));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.return_authenticator));
+ if (r->out.return_authenticator) {
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_LogonSamLogoff(struct ndr_pull *ndr, int flags, struct netr_LogonSamLogoff *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_computer_name;
+ uint32_t _ptr_credential;
+ uint32_t _ptr_return_authenticator;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_computer_name_0;
+ TALLOC_CTX *_mem_save_credential_0;
+ TALLOC_CTX *_mem_save_return_authenticator_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_computer_name));
+ if (_ptr_computer_name) {
+ NDR_PULL_ALLOC(ndr, r->in.computer_name);
+ } else {
+ r->in.computer_name = NULL;
+ }
+ if (r->in.computer_name) {
+ _mem_save_computer_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.computer_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computer_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computer_name));
+ if (ndr_get_array_length(ndr, &r->in.computer_name) > ndr_get_array_size(ndr, &r->in.computer_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computer_name), ndr_get_array_length(ndr, &r->in.computer_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computer_name, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_computer_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_credential));
+ if (_ptr_credential) {
+ NDR_PULL_ALLOC(ndr, r->in.credential);
+ } else {
+ r->in.credential = NULL;
+ }
+ if (r->in.credential) {
+ _mem_save_credential_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.credential, 0);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_credential_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_return_authenticator));
+ if (_ptr_return_authenticator) {
+ NDR_PULL_ALLOC(ndr, r->in.return_authenticator);
+ } else {
+ r->in.return_authenticator = NULL;
+ }
+ if (r->in.return_authenticator) {
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.return_authenticator, 0);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, 0);
+ }
+ NDR_CHECK(ndr_pull_netr_LogonLevel(ndr, NDR_SCALARS, &r->in.logon_level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->in.logon, r->in.logon_level));
+ NDR_CHECK(ndr_pull_netr_LogonInfo(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.logon));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_return_authenticator));
+ if (_ptr_return_authenticator) {
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ } else {
+ r->out.return_authenticator = NULL;
+ }
+ if (r->out.return_authenticator) {
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_authenticator, 0);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, 0);
+ }
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_LogonSamLogoff(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonSamLogoff *r)
+{
+ ndr_print_struct(ndr, name, "netr_LogonSamLogoff");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_LogonSamLogoff");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "computer_name", r->in.computer_name);
+ ndr->depth++;
+ if (r->in.computer_name) {
+ ndr_print_string(ndr, "computer_name", r->in.computer_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "credential", r->in.credential);
+ ndr->depth++;
+ if (r->in.credential) {
+ ndr_print_netr_Authenticator(ndr, "credential", r->in.credential);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth++;
+ if (r->in.return_authenticator) {
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->in.return_authenticator);
+ }
+ ndr->depth--;
+ ndr_print_netr_LogonLevel(ndr, "logon_level", r->in.logon_level);
+ ndr_print_set_switch_value(ndr, &r->in.logon, r->in.logon_level);
+ ndr_print_netr_LogonInfo(ndr, "logon", &r->in.logon);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_LogonSamLogoff");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth++;
+ if (r->out.return_authenticator) {
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->out.return_authenticator);
+ }
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_ServerReqChallenge(struct ndr_push *ndr, int flags, const struct netr_ServerReqChallenge *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computer_name, ndr_charset_length(r->in.computer_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ if (r->in.credentials == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Credential(ndr, NDR_SCALARS, r->in.credentials));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.return_credentials == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Credential(ndr, NDR_SCALARS, r->out.return_credentials));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_ServerReqChallenge(struct ndr_pull *ndr, int flags, struct netr_ServerReqChallenge *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_credentials_0;
+ TALLOC_CTX *_mem_save_return_credentials_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computer_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computer_name));
+ if (ndr_get_array_length(ndr, &r->in.computer_name) > ndr_get_array_size(ndr, &r->in.computer_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computer_name), ndr_get_array_length(ndr, &r->in.computer_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computer_name, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t), CH_UTF16));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.credentials);
+ }
+ _mem_save_credentials_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.credentials, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Credential(ndr, NDR_SCALARS, r->in.credentials));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_credentials_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.return_credentials);
+ ZERO_STRUCTP(r->out.return_credentials);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.return_credentials);
+ }
+ _mem_save_return_credentials_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_credentials, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Credential(ndr, NDR_SCALARS, r->out.return_credentials));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_credentials_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_ServerReqChallenge(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerReqChallenge *r)
+{
+ ndr_print_struct(ndr, name, "netr_ServerReqChallenge");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_ServerReqChallenge");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "computer_name", r->in.computer_name);
+ ndr_print_ptr(ndr, "credentials", r->in.credentials);
+ ndr->depth++;
+ ndr_print_netr_Credential(ndr, "credentials", r->in.credentials);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_ServerReqChallenge");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_credentials", r->out.return_credentials);
+ ndr->depth++;
+ ndr_print_netr_Credential(ndr, "return_credentials", r->out.return_credentials);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_ServerAuthenticate(struct ndr_push *ndr, int flags, const struct netr_ServerAuthenticate *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.account_name, ndr_charset_length(r->in.account_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_netr_SchannelType(ndr, NDR_SCALARS, r->in.secure_channel_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computer_name, ndr_charset_length(r->in.computer_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ if (r->in.credentials == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Credential(ndr, NDR_SCALARS, r->in.credentials));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.return_credentials == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Credential(ndr, NDR_SCALARS, r->out.return_credentials));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_ServerAuthenticate(struct ndr_pull *ndr, int flags, struct netr_ServerAuthenticate *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_credentials_0;
+ TALLOC_CTX *_mem_save_return_credentials_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.account_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.account_name));
+ if (ndr_get_array_length(ndr, &r->in.account_name) > ndr_get_array_size(ndr, &r->in.account_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.account_name), ndr_get_array_length(ndr, &r->in.account_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.account_name, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_netr_SchannelType(ndr, NDR_SCALARS, &r->in.secure_channel_type));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computer_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computer_name));
+ if (ndr_get_array_length(ndr, &r->in.computer_name) > ndr_get_array_size(ndr, &r->in.computer_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computer_name), ndr_get_array_length(ndr, &r->in.computer_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computer_name, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t), CH_UTF16));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.credentials);
+ }
+ _mem_save_credentials_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.credentials, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Credential(ndr, NDR_SCALARS, r->in.credentials));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_credentials_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.return_credentials);
+ ZERO_STRUCTP(r->out.return_credentials);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.return_credentials);
+ }
+ _mem_save_return_credentials_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_credentials, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Credential(ndr, NDR_SCALARS, r->out.return_credentials));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_credentials_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_ServerAuthenticate(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerAuthenticate *r)
+{
+ ndr_print_struct(ndr, name, "netr_ServerAuthenticate");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_ServerAuthenticate");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "account_name", r->in.account_name);
+ ndr_print_netr_SchannelType(ndr, "secure_channel_type", r->in.secure_channel_type);
+ ndr_print_string(ndr, "computer_name", r->in.computer_name);
+ ndr_print_ptr(ndr, "credentials", r->in.credentials);
+ ndr->depth++;
+ ndr_print_netr_Credential(ndr, "credentials", r->in.credentials);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_ServerAuthenticate");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_credentials", r->out.return_credentials);
+ ndr->depth++;
+ ndr_print_netr_Credential(ndr, "return_credentials", r->out.return_credentials);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_ServerPasswordSet(struct ndr_push *ndr, int flags, const struct netr_ServerPasswordSet *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.account_name, ndr_charset_length(r->in.account_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_netr_SchannelType(ndr, NDR_SCALARS, r->in.secure_channel_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computer_name, ndr_charset_length(r->in.computer_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ if (r->in.credential == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ if (r->in.new_password == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.new_password));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_ServerPasswordSet(struct ndr_pull *ndr, int flags, struct netr_ServerPasswordSet *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_credential_0;
+ TALLOC_CTX *_mem_save_return_authenticator_0;
+ TALLOC_CTX *_mem_save_new_password_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.account_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.account_name));
+ if (ndr_get_array_length(ndr, &r->in.account_name) > ndr_get_array_size(ndr, &r->in.account_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.account_name), ndr_get_array_length(ndr, &r->in.account_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.account_name, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_netr_SchannelType(ndr, NDR_SCALARS, &r->in.secure_channel_type));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computer_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computer_name));
+ if (ndr_get_array_length(ndr, &r->in.computer_name) > ndr_get_array_size(ndr, &r->in.computer_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computer_name), ndr_get_array_length(ndr, &r->in.computer_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computer_name, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t), CH_UTF16));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.credential);
+ }
+ _mem_save_credential_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.credential, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_credential_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.new_password);
+ }
+ _mem_save_new_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.new_password, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.new_password));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_new_password_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ ZERO_STRUCTP(r->out.return_authenticator);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_ServerPasswordSet(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerPasswordSet *r)
+{
+ ndr_print_struct(ndr, name, "netr_ServerPasswordSet");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_ServerPasswordSet");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "account_name", r->in.account_name);
+ ndr_print_netr_SchannelType(ndr, "secure_channel_type", r->in.secure_channel_type);
+ ndr_print_string(ndr, "computer_name", r->in.computer_name);
+ ndr_print_ptr(ndr, "credential", r->in.credential);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "credential", r->in.credential);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "new_password", r->in.new_password);
+ ndr->depth++;
+ ndr_print_samr_Password(ndr, "new_password", r->in.new_password);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_ServerPasswordSet");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DatabaseDeltas(struct ndr_push *ndr, int flags, const struct netr_DatabaseDeltas *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.logon_server, ndr_charset_length(r->in.logon_server, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computername, ndr_charset_length(r->in.computername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ if (r->in.credential == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ if (r->in.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_CHECK(ndr_push_netr_SamDatabaseID(ndr, NDR_SCALARS, r->in.database_id));
+ if (r->in.sequence_num == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_udlong(ndr, NDR_SCALARS, *r->in.sequence_num));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.preferredmaximumlength));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ if (r->out.sequence_num == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_udlong(ndr, NDR_SCALARS, *r->out.sequence_num));
+ if (r->out.delta_enum_array == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.delta_enum_array));
+ if (*r->out.delta_enum_array) {
+ NDR_CHECK(ndr_push_netr_DELTA_ENUM_ARRAY(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.delta_enum_array));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DatabaseDeltas(struct ndr_pull *ndr, int flags, struct netr_DatabaseDeltas *r)
+{
+ uint32_t _ptr_delta_enum_array;
+ TALLOC_CTX *_mem_save_credential_0;
+ TALLOC_CTX *_mem_save_return_authenticator_0;
+ TALLOC_CTX *_mem_save_sequence_num_0;
+ TALLOC_CTX *_mem_save_delta_enum_array_0;
+ TALLOC_CTX *_mem_save_delta_enum_array_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.logon_server));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.logon_server));
+ if (ndr_get_array_length(ndr, &r->in.logon_server) > ndr_get_array_size(ndr, &r->in.logon_server)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.logon_server), ndr_get_array_length(ndr, &r->in.logon_server));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.logon_server, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computername));
+ if (ndr_get_array_length(ndr, &r->in.computername) > ndr_get_array_size(ndr, &r->in.computername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computername), ndr_get_array_length(ndr, &r->in.computername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computername, ndr_get_array_length(ndr, &r->in.computername), sizeof(uint16_t), CH_UTF16));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.credential);
+ }
+ _mem_save_credential_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.credential, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_credential_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_SamDatabaseID(ndr, NDR_SCALARS, &r->in.database_id));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sequence_num);
+ }
+ _mem_save_sequence_num_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sequence_num, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_udlong(ndr, NDR_SCALARS, r->in.sequence_num));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sequence_num_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.preferredmaximumlength));
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ *r->out.return_authenticator = *r->in.return_authenticator;
+ NDR_PULL_ALLOC(ndr, r->out.sequence_num);
+ *r->out.sequence_num = *r->in.sequence_num;
+ NDR_PULL_ALLOC(ndr, r->out.delta_enum_array);
+ ZERO_STRUCTP(r->out.delta_enum_array);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sequence_num);
+ }
+ _mem_save_sequence_num_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sequence_num, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_udlong(ndr, NDR_SCALARS, r->out.sequence_num));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sequence_num_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.delta_enum_array);
+ }
+ _mem_save_delta_enum_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.delta_enum_array, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_delta_enum_array));
+ if (_ptr_delta_enum_array) {
+ NDR_PULL_ALLOC(ndr, *r->out.delta_enum_array);
+ } else {
+ *r->out.delta_enum_array = NULL;
+ }
+ if (*r->out.delta_enum_array) {
+ _mem_save_delta_enum_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.delta_enum_array, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_ENUM_ARRAY(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.delta_enum_array));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_delta_enum_array_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_delta_enum_array_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DatabaseDeltas(struct ndr_print *ndr, const char *name, int flags, const struct netr_DatabaseDeltas *r)
+{
+ ndr_print_struct(ndr, name, "netr_DatabaseDeltas");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_DatabaseDeltas");
+ ndr->depth++;
+ ndr_print_string(ndr, "logon_server", r->in.logon_server);
+ ndr_print_string(ndr, "computername", r->in.computername);
+ ndr_print_ptr(ndr, "credential", r->in.credential);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "credential", r->in.credential);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth--;
+ ndr_print_netr_SamDatabaseID(ndr, "database_id", r->in.database_id);
+ ndr_print_ptr(ndr, "sequence_num", r->in.sequence_num);
+ ndr->depth++;
+ ndr_print_udlong(ndr, "sequence_num", *r->in.sequence_num);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "preferredmaximumlength", r->in.preferredmaximumlength);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_DatabaseDeltas");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sequence_num", r->out.sequence_num);
+ ndr->depth++;
+ ndr_print_udlong(ndr, "sequence_num", *r->out.sequence_num);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "delta_enum_array", r->out.delta_enum_array);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "delta_enum_array", *r->out.delta_enum_array);
+ ndr->depth++;
+ if (*r->out.delta_enum_array) {
+ ndr_print_netr_DELTA_ENUM_ARRAY(ndr, "delta_enum_array", *r->out.delta_enum_array);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DatabaseSync(struct ndr_push *ndr, int flags, const struct netr_DatabaseSync *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.logon_server, ndr_charset_length(r->in.logon_server, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computername, ndr_charset_length(r->in.computername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, &r->in.credential));
+ if (r->in.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_CHECK(ndr_push_netr_SamDatabaseID(ndr, NDR_SCALARS, r->in.database_id));
+ if (r->in.sync_context == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.sync_context));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.preferredmaximumlength));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ if (r->out.sync_context == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.sync_context));
+ if (r->out.delta_enum_array == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_DELTA_ENUM_ARRAY(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.delta_enum_array));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DatabaseSync(struct ndr_pull *ndr, int flags, struct netr_DatabaseSync *r)
+{
+ TALLOC_CTX *_mem_save_return_authenticator_0;
+ TALLOC_CTX *_mem_save_sync_context_0;
+ TALLOC_CTX *_mem_save_delta_enum_array_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.logon_server));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.logon_server));
+ if (ndr_get_array_length(ndr, &r->in.logon_server) > ndr_get_array_size(ndr, &r->in.logon_server)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.logon_server), ndr_get_array_length(ndr, &r->in.logon_server));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.logon_server, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computername));
+ if (ndr_get_array_length(ndr, &r->in.computername) > ndr_get_array_size(ndr, &r->in.computername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computername), ndr_get_array_length(ndr, &r->in.computername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computername, ndr_get_array_length(ndr, &r->in.computername), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, &r->in.credential));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_SamDatabaseID(ndr, NDR_SCALARS, &r->in.database_id));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sync_context);
+ }
+ _mem_save_sync_context_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sync_context, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.sync_context));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sync_context_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.preferredmaximumlength));
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ *r->out.return_authenticator = *r->in.return_authenticator;
+ NDR_PULL_ALLOC(ndr, r->out.sync_context);
+ *r->out.sync_context = *r->in.sync_context;
+ NDR_PULL_ALLOC(ndr, r->out.delta_enum_array);
+ ZERO_STRUCTP(r->out.delta_enum_array);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sync_context);
+ }
+ _mem_save_sync_context_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sync_context, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.sync_context));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sync_context_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.delta_enum_array);
+ }
+ _mem_save_delta_enum_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.delta_enum_array, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_DELTA_ENUM_ARRAY(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.delta_enum_array));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_delta_enum_array_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DatabaseSync(struct ndr_print *ndr, const char *name, int flags, const struct netr_DatabaseSync *r)
+{
+ ndr_print_struct(ndr, name, "netr_DatabaseSync");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_DatabaseSync");
+ ndr->depth++;
+ ndr_print_string(ndr, "logon_server", r->in.logon_server);
+ ndr_print_string(ndr, "computername", r->in.computername);
+ ndr_print_netr_Authenticator(ndr, "credential", &r->in.credential);
+ ndr_print_ptr(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth--;
+ ndr_print_netr_SamDatabaseID(ndr, "database_id", r->in.database_id);
+ ndr_print_ptr(ndr, "sync_context", r->in.sync_context);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "sync_context", *r->in.sync_context);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "preferredmaximumlength", r->in.preferredmaximumlength);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_DatabaseSync");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sync_context", r->out.sync_context);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "sync_context", *r->out.sync_context);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "delta_enum_array", r->out.delta_enum_array);
+ ndr->depth++;
+ ndr_print_netr_DELTA_ENUM_ARRAY(ndr, "delta_enum_array", r->out.delta_enum_array);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_AccountDeltas(struct ndr_push *ndr, int flags, const struct netr_AccountDeltas *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.logon_server));
+ if (r->in.logon_server) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.logon_server, ndr_charset_length(r->in.logon_server, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computername, ndr_charset_length(r->in.computername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, &r->in.credential));
+ if (r->in.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_CHECK(ndr_push_netr_UAS_INFO_0(ndr, NDR_SCALARS, &r->in.uas));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buffersize));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ if (r->out.buffer == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ {
+ struct ndr_push *_ndr_buffer;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_buffer, 4, -1));
+ NDR_CHECK(ndr_push_netr_AccountBuffer(_ndr_buffer, NDR_SCALARS, r->out.buffer));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_buffer, 4, -1));
+ }
+ if (r->out.count_returned == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.count_returned));
+ if (r->out.total_entries == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.total_entries));
+ if (r->out.recordid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_UAS_INFO_0(ndr, NDR_SCALARS, r->out.recordid));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_AccountDeltas(struct ndr_pull *ndr, int flags, struct netr_AccountDeltas *r)
+{
+ uint32_t _ptr_logon_server;
+ TALLOC_CTX *_mem_save_logon_server_0;
+ TALLOC_CTX *_mem_save_return_authenticator_0;
+ TALLOC_CTX *_mem_save_buffer_0;
+ TALLOC_CTX *_mem_save_count_returned_0;
+ TALLOC_CTX *_mem_save_total_entries_0;
+ TALLOC_CTX *_mem_save_recordid_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_logon_server));
+ if (_ptr_logon_server) {
+ NDR_PULL_ALLOC(ndr, r->in.logon_server);
+ } else {
+ r->in.logon_server = NULL;
+ }
+ if (r->in.logon_server) {
+ _mem_save_logon_server_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.logon_server, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.logon_server));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.logon_server));
+ if (ndr_get_array_length(ndr, &r->in.logon_server) > ndr_get_array_size(ndr, &r->in.logon_server)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.logon_server), ndr_get_array_length(ndr, &r->in.logon_server));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.logon_server, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_logon_server_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computername));
+ if (ndr_get_array_length(ndr, &r->in.computername) > ndr_get_array_size(ndr, &r->in.computername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computername), ndr_get_array_length(ndr, &r->in.computername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computername, ndr_get_array_length(ndr, &r->in.computername), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, &r->in.credential));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_UAS_INFO_0(ndr, NDR_SCALARS, &r->in.uas));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buffersize));
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ *r->out.return_authenticator = *r->in.return_authenticator;
+ NDR_PULL_ALLOC(ndr, r->out.buffer);
+ ZERO_STRUCTP(r->out.buffer);
+ NDR_PULL_ALLOC(ndr, r->out.count_returned);
+ ZERO_STRUCTP(r->out.count_returned);
+ NDR_PULL_ALLOC(ndr, r->out.total_entries);
+ ZERO_STRUCTP(r->out.total_entries);
+ NDR_PULL_ALLOC(ndr, r->out.recordid);
+ ZERO_STRUCTP(r->out.recordid);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.buffer);
+ }
+ _mem_save_buffer_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.buffer, LIBNDR_FLAG_REF_ALLOC);
+ {
+ struct ndr_pull *_ndr_buffer;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_buffer, 4, -1));
+ NDR_CHECK(ndr_pull_netr_AccountBuffer(_ndr_buffer, NDR_SCALARS, r->out.buffer));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_buffer, 4, -1));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_buffer_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.count_returned);
+ }
+ _mem_save_count_returned_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.count_returned, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.count_returned));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_count_returned_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.total_entries);
+ }
+ _mem_save_total_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.total_entries, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.total_entries));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_total_entries_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.recordid);
+ }
+ _mem_save_recordid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.recordid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_UAS_INFO_0(ndr, NDR_SCALARS, r->out.recordid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_recordid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_AccountDeltas(struct ndr_print *ndr, const char *name, int flags, const struct netr_AccountDeltas *r)
+{
+ ndr_print_struct(ndr, name, "netr_AccountDeltas");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_AccountDeltas");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "logon_server", r->in.logon_server);
+ ndr->depth++;
+ if (r->in.logon_server) {
+ ndr_print_string(ndr, "logon_server", r->in.logon_server);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "computername", r->in.computername);
+ ndr_print_netr_Authenticator(ndr, "credential", &r->in.credential);
+ ndr_print_ptr(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth--;
+ ndr_print_netr_UAS_INFO_0(ndr, "uas", &r->in.uas);
+ ndr_print_uint32(ndr, "count", r->in.count);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "buffersize", r->in.buffersize);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_AccountDeltas");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_netr_AccountBuffer(ndr, "buffer", r->out.buffer);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "count_returned", r->out.count_returned);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count_returned", *r->out.count_returned);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "total_entries", r->out.total_entries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "total_entries", *r->out.total_entries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "recordid", r->out.recordid);
+ ndr->depth++;
+ ndr_print_netr_UAS_INFO_0(ndr, "recordid", r->out.recordid);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_AccountSync(struct ndr_push *ndr, int flags, const struct netr_AccountSync *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.logon_server));
+ if (r->in.logon_server) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.logon_server, ndr_charset_length(r->in.logon_server, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computername, ndr_charset_length(r->in.computername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, &r->in.credential));
+ if (r->in.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.reference));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buffersize));
+ if (r->in.recordid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_UAS_INFO_0(ndr, NDR_SCALARS, r->in.recordid));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ if (r->out.buffer == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ {
+ struct ndr_push *_ndr_buffer;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_buffer, 4, -1));
+ NDR_CHECK(ndr_push_netr_AccountBuffer(_ndr_buffer, NDR_SCALARS, r->out.buffer));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_buffer, 4, -1));
+ }
+ if (r->out.count_returned == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.count_returned));
+ if (r->out.total_entries == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.total_entries));
+ if (r->out.next_reference == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.next_reference));
+ if (r->out.recordid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_UAS_INFO_0(ndr, NDR_SCALARS, r->out.recordid));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_AccountSync(struct ndr_pull *ndr, int flags, struct netr_AccountSync *r)
+{
+ uint32_t _ptr_logon_server;
+ TALLOC_CTX *_mem_save_logon_server_0;
+ TALLOC_CTX *_mem_save_return_authenticator_0;
+ TALLOC_CTX *_mem_save_buffer_0;
+ TALLOC_CTX *_mem_save_count_returned_0;
+ TALLOC_CTX *_mem_save_total_entries_0;
+ TALLOC_CTX *_mem_save_next_reference_0;
+ TALLOC_CTX *_mem_save_recordid_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_logon_server));
+ if (_ptr_logon_server) {
+ NDR_PULL_ALLOC(ndr, r->in.logon_server);
+ } else {
+ r->in.logon_server = NULL;
+ }
+ if (r->in.logon_server) {
+ _mem_save_logon_server_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.logon_server, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.logon_server));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.logon_server));
+ if (ndr_get_array_length(ndr, &r->in.logon_server) > ndr_get_array_size(ndr, &r->in.logon_server)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.logon_server), ndr_get_array_length(ndr, &r->in.logon_server));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.logon_server, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_logon_server_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computername));
+ if (ndr_get_array_length(ndr, &r->in.computername) > ndr_get_array_size(ndr, &r->in.computername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computername), ndr_get_array_length(ndr, &r->in.computername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computername, ndr_get_array_length(ndr, &r->in.computername), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, &r->in.credential));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.reference));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buffersize));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.recordid);
+ }
+ _mem_save_recordid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.recordid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_UAS_INFO_0(ndr, NDR_SCALARS, r->in.recordid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_recordid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ *r->out.return_authenticator = *r->in.return_authenticator;
+ NDR_PULL_ALLOC(ndr, r->out.buffer);
+ ZERO_STRUCTP(r->out.buffer);
+ NDR_PULL_ALLOC(ndr, r->out.count_returned);
+ ZERO_STRUCTP(r->out.count_returned);
+ NDR_PULL_ALLOC(ndr, r->out.total_entries);
+ ZERO_STRUCTP(r->out.total_entries);
+ NDR_PULL_ALLOC(ndr, r->out.next_reference);
+ ZERO_STRUCTP(r->out.next_reference);
+ NDR_PULL_ALLOC(ndr, r->out.recordid);
+ *r->out.recordid = *r->in.recordid;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.buffer);
+ }
+ _mem_save_buffer_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.buffer, LIBNDR_FLAG_REF_ALLOC);
+ {
+ struct ndr_pull *_ndr_buffer;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_buffer, 4, -1));
+ NDR_CHECK(ndr_pull_netr_AccountBuffer(_ndr_buffer, NDR_SCALARS, r->out.buffer));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_buffer, 4, -1));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_buffer_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.count_returned);
+ }
+ _mem_save_count_returned_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.count_returned, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.count_returned));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_count_returned_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.total_entries);
+ }
+ _mem_save_total_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.total_entries, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.total_entries));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_total_entries_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.next_reference);
+ }
+ _mem_save_next_reference_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.next_reference, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.next_reference));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_next_reference_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.recordid);
+ }
+ _mem_save_recordid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.recordid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_UAS_INFO_0(ndr, NDR_SCALARS, r->out.recordid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_recordid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_AccountSync(struct ndr_print *ndr, const char *name, int flags, const struct netr_AccountSync *r)
+{
+ ndr_print_struct(ndr, name, "netr_AccountSync");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_AccountSync");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "logon_server", r->in.logon_server);
+ ndr->depth++;
+ if (r->in.logon_server) {
+ ndr_print_string(ndr, "logon_server", r->in.logon_server);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "computername", r->in.computername);
+ ndr_print_netr_Authenticator(ndr, "credential", &r->in.credential);
+ ndr_print_ptr(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "reference", r->in.reference);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "buffersize", r->in.buffersize);
+ ndr_print_ptr(ndr, "recordid", r->in.recordid);
+ ndr->depth++;
+ ndr_print_netr_UAS_INFO_0(ndr, "recordid", r->in.recordid);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_AccountSync");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_netr_AccountBuffer(ndr, "buffer", r->out.buffer);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "count_returned", r->out.count_returned);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count_returned", *r->out.count_returned);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "total_entries", r->out.total_entries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "total_entries", *r->out.total_entries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "next_reference", r->out.next_reference);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "next_reference", *r->out.next_reference);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "recordid", r->out.recordid);
+ ndr->depth++;
+ ndr_print_netr_UAS_INFO_0(ndr, "recordid", r->out.recordid);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_GetDcName(struct ndr_push *ndr, int flags, const struct netr_GetDcName *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.logon_server, ndr_charset_length(r->in.logon_server, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.domainname));
+ if (r->in.domainname) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domainname, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domainname, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.domainname, ndr_charset_length(r->in.domainname, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.dcname == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.dcname));
+ if (*r->out.dcname) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.dcname, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.dcname, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, *r->out.dcname, ndr_charset_length(*r->out.dcname, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_GetDcName(struct ndr_pull *ndr, int flags, struct netr_GetDcName *r)
+{
+ uint32_t _ptr_domainname;
+ uint32_t _ptr_dcname;
+ TALLOC_CTX *_mem_save_domainname_0;
+ TALLOC_CTX *_mem_save_dcname_0;
+ TALLOC_CTX *_mem_save_dcname_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.logon_server));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.logon_server));
+ if (ndr_get_array_length(ndr, &r->in.logon_server) > ndr_get_array_size(ndr, &r->in.logon_server)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.logon_server), ndr_get_array_length(ndr, &r->in.logon_server));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.logon_server, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domainname));
+ if (_ptr_domainname) {
+ NDR_PULL_ALLOC(ndr, r->in.domainname);
+ } else {
+ r->in.domainname = NULL;
+ }
+ if (r->in.domainname) {
+ _mem_save_domainname_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domainname, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.domainname));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.domainname));
+ if (ndr_get_array_length(ndr, &r->in.domainname) > ndr_get_array_size(ndr, &r->in.domainname)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.domainname), ndr_get_array_length(ndr, &r->in.domainname));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.domainname), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.domainname, ndr_get_array_length(ndr, &r->in.domainname), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domainname_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.dcname);
+ ZERO_STRUCTP(r->out.dcname);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.dcname);
+ }
+ _mem_save_dcname_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.dcname, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dcname));
+ if (_ptr_dcname) {
+ NDR_PULL_ALLOC(ndr, *r->out.dcname);
+ } else {
+ *r->out.dcname = NULL;
+ }
+ if (*r->out.dcname) {
+ _mem_save_dcname_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.dcname, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->out.dcname));
+ NDR_CHECK(ndr_pull_array_length(ndr, r->out.dcname));
+ if (ndr_get_array_length(ndr, r->out.dcname) > ndr_get_array_size(ndr, r->out.dcname)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, r->out.dcname), ndr_get_array_length(ndr, r->out.dcname));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, r->out.dcname), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, r->out.dcname, ndr_get_array_length(ndr, r->out.dcname), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dcname_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dcname_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_GetDcName(struct ndr_print *ndr, const char *name, int flags, const struct netr_GetDcName *r)
+{
+ ndr_print_struct(ndr, name, "netr_GetDcName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_GetDcName");
+ ndr->depth++;
+ ndr_print_string(ndr, "logon_server", r->in.logon_server);
+ ndr_print_ptr(ndr, "domainname", r->in.domainname);
+ ndr->depth++;
+ if (r->in.domainname) {
+ ndr_print_string(ndr, "domainname", r->in.domainname);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_GetDcName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "dcname", r->out.dcname);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "dcname", *r->out.dcname);
+ ndr->depth++;
+ if (*r->out.dcname) {
+ ndr_print_string(ndr, "dcname", *r->out.dcname);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_LogonControl(struct ndr_push *ndr, int flags, const struct netr_LogonControl *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.logon_server));
+ if (r->in.logon_server) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.logon_server, ndr_charset_length(r->in.logon_server, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_netr_LogonControlCode(ndr, NDR_SCALARS, r->in.function_code));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_netr_CONTROL_QUERY_INFORMATION(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_LogonControl(struct ndr_pull *ndr, int flags, struct netr_LogonControl *r)
+{
+ uint32_t _ptr_logon_server;
+ TALLOC_CTX *_mem_save_logon_server_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_logon_server));
+ if (_ptr_logon_server) {
+ NDR_PULL_ALLOC(ndr, r->in.logon_server);
+ } else {
+ r->in.logon_server = NULL;
+ }
+ if (r->in.logon_server) {
+ _mem_save_logon_server_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.logon_server, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.logon_server));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.logon_server));
+ if (ndr_get_array_length(ndr, &r->in.logon_server) > ndr_get_array_size(ndr, &r->in.logon_server)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.logon_server), ndr_get_array_length(ndr, &r->in.logon_server));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.logon_server, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_logon_server_0, 0);
+ }
+ NDR_CHECK(ndr_pull_netr_LogonControlCode(ndr, NDR_SCALARS, &r->in.function_code));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_netr_CONTROL_QUERY_INFORMATION(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_LogonControl(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonControl *r)
+{
+ ndr_print_struct(ndr, name, "netr_LogonControl");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_LogonControl");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "logon_server", r->in.logon_server);
+ ndr->depth++;
+ if (r->in.logon_server) {
+ ndr_print_string(ndr, "logon_server", r->in.logon_server);
+ }
+ ndr->depth--;
+ ndr_print_netr_LogonControlCode(ndr, "function_code", r->in.function_code);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_LogonControl");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, r->in.level);
+ ndr_print_netr_CONTROL_QUERY_INFORMATION(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_GetAnyDCName(struct ndr_push *ndr, int flags, const struct netr_GetAnyDCName *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.logon_server));
+ if (r->in.logon_server) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.logon_server, ndr_charset_length(r->in.logon_server, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.domainname));
+ if (r->in.domainname) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domainname, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domainname, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.domainname, ndr_charset_length(r->in.domainname, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.dcname == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.dcname));
+ if (*r->out.dcname) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.dcname, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.dcname, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, *r->out.dcname, ndr_charset_length(*r->out.dcname, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_GetAnyDCName(struct ndr_pull *ndr, int flags, struct netr_GetAnyDCName *r)
+{
+ uint32_t _ptr_logon_server;
+ uint32_t _ptr_domainname;
+ uint32_t _ptr_dcname;
+ TALLOC_CTX *_mem_save_logon_server_0;
+ TALLOC_CTX *_mem_save_domainname_0;
+ TALLOC_CTX *_mem_save_dcname_0;
+ TALLOC_CTX *_mem_save_dcname_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_logon_server));
+ if (_ptr_logon_server) {
+ NDR_PULL_ALLOC(ndr, r->in.logon_server);
+ } else {
+ r->in.logon_server = NULL;
+ }
+ if (r->in.logon_server) {
+ _mem_save_logon_server_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.logon_server, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.logon_server));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.logon_server));
+ if (ndr_get_array_length(ndr, &r->in.logon_server) > ndr_get_array_size(ndr, &r->in.logon_server)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.logon_server), ndr_get_array_length(ndr, &r->in.logon_server));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.logon_server, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_logon_server_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domainname));
+ if (_ptr_domainname) {
+ NDR_PULL_ALLOC(ndr, r->in.domainname);
+ } else {
+ r->in.domainname = NULL;
+ }
+ if (r->in.domainname) {
+ _mem_save_domainname_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domainname, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.domainname));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.domainname));
+ if (ndr_get_array_length(ndr, &r->in.domainname) > ndr_get_array_size(ndr, &r->in.domainname)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.domainname), ndr_get_array_length(ndr, &r->in.domainname));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.domainname), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.domainname, ndr_get_array_length(ndr, &r->in.domainname), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domainname_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.dcname);
+ ZERO_STRUCTP(r->out.dcname);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.dcname);
+ }
+ _mem_save_dcname_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.dcname, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dcname));
+ if (_ptr_dcname) {
+ NDR_PULL_ALLOC(ndr, *r->out.dcname);
+ } else {
+ *r->out.dcname = NULL;
+ }
+ if (*r->out.dcname) {
+ _mem_save_dcname_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.dcname, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->out.dcname));
+ NDR_CHECK(ndr_pull_array_length(ndr, r->out.dcname));
+ if (ndr_get_array_length(ndr, r->out.dcname) > ndr_get_array_size(ndr, r->out.dcname)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, r->out.dcname), ndr_get_array_length(ndr, r->out.dcname));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, r->out.dcname), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, r->out.dcname, ndr_get_array_length(ndr, r->out.dcname), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dcname_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dcname_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_GetAnyDCName(struct ndr_print *ndr, const char *name, int flags, const struct netr_GetAnyDCName *r)
+{
+ ndr_print_struct(ndr, name, "netr_GetAnyDCName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_GetAnyDCName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "logon_server", r->in.logon_server);
+ ndr->depth++;
+ if (r->in.logon_server) {
+ ndr_print_string(ndr, "logon_server", r->in.logon_server);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domainname", r->in.domainname);
+ ndr->depth++;
+ if (r->in.domainname) {
+ ndr_print_string(ndr, "domainname", r->in.domainname);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_GetAnyDCName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "dcname", r->out.dcname);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "dcname", *r->out.dcname);
+ ndr->depth++;
+ if (*r->out.dcname) {
+ ndr_print_string(ndr, "dcname", *r->out.dcname);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_LogonControl2(struct ndr_push *ndr, int flags, const struct netr_LogonControl2 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.logon_server));
+ if (r->in.logon_server) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.logon_server, ndr_charset_length(r->in.logon_server, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_netr_LogonControlCode(ndr, NDR_SCALARS, r->in.function_code));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.data == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.data, r->in.function_code));
+ NDR_CHECK(ndr_push_netr_CONTROL_DATA_INFORMATION(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.data));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.query == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.query, r->in.level));
+ NDR_CHECK(ndr_push_netr_CONTROL_QUERY_INFORMATION(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.query));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_LogonControl2(struct ndr_pull *ndr, int flags, struct netr_LogonControl2 *r)
+{
+ uint32_t _ptr_logon_server;
+ TALLOC_CTX *_mem_save_logon_server_0;
+ TALLOC_CTX *_mem_save_data_0;
+ TALLOC_CTX *_mem_save_query_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_logon_server));
+ if (_ptr_logon_server) {
+ NDR_PULL_ALLOC(ndr, r->in.logon_server);
+ } else {
+ r->in.logon_server = NULL;
+ }
+ if (r->in.logon_server) {
+ _mem_save_logon_server_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.logon_server, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.logon_server));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.logon_server));
+ if (ndr_get_array_length(ndr, &r->in.logon_server) > ndr_get_array_size(ndr, &r->in.logon_server)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.logon_server), ndr_get_array_length(ndr, &r->in.logon_server));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.logon_server, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_logon_server_0, 0);
+ }
+ NDR_CHECK(ndr_pull_netr_LogonControlCode(ndr, NDR_SCALARS, &r->in.function_code));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.data);
+ }
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.data, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.data, r->in.function_code));
+ NDR_CHECK(ndr_pull_netr_CONTROL_DATA_INFORMATION(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.data));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.query);
+ ZERO_STRUCTP(r->out.query);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.query);
+ }
+ _mem_save_query_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.query, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.query, r->in.level));
+ NDR_CHECK(ndr_pull_netr_CONTROL_QUERY_INFORMATION(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.query));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_query_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_LogonControl2(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonControl2 *r)
+{
+ ndr_print_struct(ndr, name, "netr_LogonControl2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_LogonControl2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "logon_server", r->in.logon_server);
+ ndr->depth++;
+ if (r->in.logon_server) {
+ ndr_print_string(ndr, "logon_server", r->in.logon_server);
+ }
+ ndr->depth--;
+ ndr_print_netr_LogonControlCode(ndr, "function_code", r->in.function_code);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "data", r->in.data);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.data, r->in.function_code);
+ ndr_print_netr_CONTROL_DATA_INFORMATION(ndr, "data", r->in.data);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_LogonControl2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "query", r->out.query);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.query, r->in.level);
+ ndr_print_netr_CONTROL_QUERY_INFORMATION(ndr, "query", r->out.query);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_ServerAuthenticate2(struct ndr_push *ndr, int flags, const struct netr_ServerAuthenticate2 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.account_name, ndr_charset_length(r->in.account_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_netr_SchannelType(ndr, NDR_SCALARS, r->in.secure_channel_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computer_name, ndr_charset_length(r->in.computer_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ if (r->in.credentials == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Credential(ndr, NDR_SCALARS, r->in.credentials));
+ if (r->in.negotiate_flags == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_NegotiateFlags(ndr, NDR_SCALARS, *r->in.negotiate_flags));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.return_credentials == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Credential(ndr, NDR_SCALARS, r->out.return_credentials));
+ if (r->out.negotiate_flags == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_NegotiateFlags(ndr, NDR_SCALARS, *r->out.negotiate_flags));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_ServerAuthenticate2(struct ndr_pull *ndr, int flags, struct netr_ServerAuthenticate2 *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_credentials_0;
+ TALLOC_CTX *_mem_save_return_credentials_0;
+ TALLOC_CTX *_mem_save_negotiate_flags_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.account_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.account_name));
+ if (ndr_get_array_length(ndr, &r->in.account_name) > ndr_get_array_size(ndr, &r->in.account_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.account_name), ndr_get_array_length(ndr, &r->in.account_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.account_name, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_netr_SchannelType(ndr, NDR_SCALARS, &r->in.secure_channel_type));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computer_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computer_name));
+ if (ndr_get_array_length(ndr, &r->in.computer_name) > ndr_get_array_size(ndr, &r->in.computer_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computer_name), ndr_get_array_length(ndr, &r->in.computer_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computer_name, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t), CH_UTF16));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.credentials);
+ }
+ _mem_save_credentials_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.credentials, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Credential(ndr, NDR_SCALARS, r->in.credentials));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_credentials_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.negotiate_flags);
+ }
+ _mem_save_negotiate_flags_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.negotiate_flags, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_NegotiateFlags(ndr, NDR_SCALARS, r->in.negotiate_flags));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_negotiate_flags_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.return_credentials);
+ ZERO_STRUCTP(r->out.return_credentials);
+ NDR_PULL_ALLOC(ndr, r->out.negotiate_flags);
+ *r->out.negotiate_flags = *r->in.negotiate_flags;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.return_credentials);
+ }
+ _mem_save_return_credentials_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_credentials, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Credential(ndr, NDR_SCALARS, r->out.return_credentials));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_credentials_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.negotiate_flags);
+ }
+ _mem_save_negotiate_flags_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.negotiate_flags, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_NegotiateFlags(ndr, NDR_SCALARS, r->out.negotiate_flags));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_negotiate_flags_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_ServerAuthenticate2(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerAuthenticate2 *r)
+{
+ ndr_print_struct(ndr, name, "netr_ServerAuthenticate2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_ServerAuthenticate2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "account_name", r->in.account_name);
+ ndr_print_netr_SchannelType(ndr, "secure_channel_type", r->in.secure_channel_type);
+ ndr_print_string(ndr, "computer_name", r->in.computer_name);
+ ndr_print_ptr(ndr, "credentials", r->in.credentials);
+ ndr->depth++;
+ ndr_print_netr_Credential(ndr, "credentials", r->in.credentials);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "negotiate_flags", r->in.negotiate_flags);
+ ndr->depth++;
+ ndr_print_netr_NegotiateFlags(ndr, "negotiate_flags", *r->in.negotiate_flags);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_ServerAuthenticate2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_credentials", r->out.return_credentials);
+ ndr->depth++;
+ ndr_print_netr_Credential(ndr, "return_credentials", r->out.return_credentials);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "negotiate_flags", r->out.negotiate_flags);
+ ndr->depth++;
+ ndr_print_netr_NegotiateFlags(ndr, "negotiate_flags", *r->out.negotiate_flags);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DatabaseSync2(struct ndr_push *ndr, int flags, const struct netr_DatabaseSync2 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.logon_server, ndr_charset_length(r->in.logon_server, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computername, ndr_charset_length(r->in.computername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ if (r->in.credential == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ if (r->in.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_CHECK(ndr_push_netr_SamDatabaseID(ndr, NDR_SCALARS, r->in.database_id));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.restart_state));
+ if (r->in.sync_context == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.sync_context));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.preferredmaximumlength));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ if (r->out.sync_context == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.sync_context));
+ if (r->out.delta_enum_array == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.delta_enum_array));
+ if (*r->out.delta_enum_array) {
+ NDR_CHECK(ndr_push_netr_DELTA_ENUM_ARRAY(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.delta_enum_array));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DatabaseSync2(struct ndr_pull *ndr, int flags, struct netr_DatabaseSync2 *r)
+{
+ uint32_t _ptr_delta_enum_array;
+ TALLOC_CTX *_mem_save_credential_0;
+ TALLOC_CTX *_mem_save_return_authenticator_0;
+ TALLOC_CTX *_mem_save_sync_context_0;
+ TALLOC_CTX *_mem_save_delta_enum_array_0;
+ TALLOC_CTX *_mem_save_delta_enum_array_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.logon_server));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.logon_server));
+ if (ndr_get_array_length(ndr, &r->in.logon_server) > ndr_get_array_size(ndr, &r->in.logon_server)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.logon_server), ndr_get_array_length(ndr, &r->in.logon_server));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.logon_server, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computername));
+ if (ndr_get_array_length(ndr, &r->in.computername) > ndr_get_array_size(ndr, &r->in.computername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computername), ndr_get_array_length(ndr, &r->in.computername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computername, ndr_get_array_length(ndr, &r->in.computername), sizeof(uint16_t), CH_UTF16));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.credential);
+ }
+ _mem_save_credential_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.credential, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_credential_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_SamDatabaseID(ndr, NDR_SCALARS, &r->in.database_id));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.restart_state));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sync_context);
+ }
+ _mem_save_sync_context_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sync_context, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.sync_context));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sync_context_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.preferredmaximumlength));
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ *r->out.return_authenticator = *r->in.return_authenticator;
+ NDR_PULL_ALLOC(ndr, r->out.sync_context);
+ *r->out.sync_context = *r->in.sync_context;
+ NDR_PULL_ALLOC(ndr, r->out.delta_enum_array);
+ ZERO_STRUCTP(r->out.delta_enum_array);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sync_context);
+ }
+ _mem_save_sync_context_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sync_context, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.sync_context));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sync_context_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.delta_enum_array);
+ }
+ _mem_save_delta_enum_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.delta_enum_array, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_delta_enum_array));
+ if (_ptr_delta_enum_array) {
+ NDR_PULL_ALLOC(ndr, *r->out.delta_enum_array);
+ } else {
+ *r->out.delta_enum_array = NULL;
+ }
+ if (*r->out.delta_enum_array) {
+ _mem_save_delta_enum_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.delta_enum_array, 0);
+ NDR_CHECK(ndr_pull_netr_DELTA_ENUM_ARRAY(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.delta_enum_array));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_delta_enum_array_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_delta_enum_array_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DatabaseSync2(struct ndr_print *ndr, const char *name, int flags, const struct netr_DatabaseSync2 *r)
+{
+ ndr_print_struct(ndr, name, "netr_DatabaseSync2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_DatabaseSync2");
+ ndr->depth++;
+ ndr_print_string(ndr, "logon_server", r->in.logon_server);
+ ndr_print_string(ndr, "computername", r->in.computername);
+ ndr_print_ptr(ndr, "credential", r->in.credential);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "credential", r->in.credential);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth--;
+ ndr_print_netr_SamDatabaseID(ndr, "database_id", r->in.database_id);
+ ndr_print_uint16(ndr, "restart_state", r->in.restart_state);
+ ndr_print_ptr(ndr, "sync_context", r->in.sync_context);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "sync_context", *r->in.sync_context);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "preferredmaximumlength", r->in.preferredmaximumlength);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_DatabaseSync2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sync_context", r->out.sync_context);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "sync_context", *r->out.sync_context);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "delta_enum_array", r->out.delta_enum_array);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "delta_enum_array", *r->out.delta_enum_array);
+ ndr->depth++;
+ if (*r->out.delta_enum_array) {
+ ndr_print_netr_DELTA_ENUM_ARRAY(ndr, "delta_enum_array", *r->out.delta_enum_array);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DatabaseRedo(struct ndr_push *ndr, int flags, const struct netr_DatabaseRedo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.logon_server, ndr_charset_length(r->in.logon_server, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computername, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computername, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computername, ndr_charset_length(r->in.computername, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, &r->in.credential));
+ if (r->in.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.change_log_entry));
+ if (r->in.change_log_entry) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.change_log_entry_size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->in.change_log_entry, r->in.change_log_entry_size));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.change_log_entry_size));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ if (r->out.delta_enum_array == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_DELTA_ENUM_ARRAY(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.delta_enum_array));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DatabaseRedo(struct ndr_pull *ndr, int flags, struct netr_DatabaseRedo *r)
+{
+ uint32_t _ptr_change_log_entry;
+ TALLOC_CTX *_mem_save_return_authenticator_0;
+ TALLOC_CTX *_mem_save_change_log_entry_0;
+ TALLOC_CTX *_mem_save_delta_enum_array_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.logon_server));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.logon_server));
+ if (ndr_get_array_length(ndr, &r->in.logon_server) > ndr_get_array_size(ndr, &r->in.logon_server)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.logon_server), ndr_get_array_length(ndr, &r->in.logon_server));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.logon_server, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computername));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computername));
+ if (ndr_get_array_length(ndr, &r->in.computername) > ndr_get_array_size(ndr, &r->in.computername)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computername), ndr_get_array_length(ndr, &r->in.computername));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computername), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computername, ndr_get_array_length(ndr, &r->in.computername), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, &r->in.credential));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_change_log_entry));
+ if (_ptr_change_log_entry) {
+ NDR_PULL_ALLOC(ndr, r->in.change_log_entry);
+ } else {
+ r->in.change_log_entry = NULL;
+ }
+ if (r->in.change_log_entry) {
+ _mem_save_change_log_entry_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.change_log_entry, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.change_log_entry));
+ NDR_PULL_ALLOC_N(ndr, r->in.change_log_entry, ndr_get_array_size(ndr, &r->in.change_log_entry));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->in.change_log_entry, ndr_get_array_size(ndr, &r->in.change_log_entry)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_change_log_entry_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.change_log_entry_size));
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ *r->out.return_authenticator = *r->in.return_authenticator;
+ NDR_PULL_ALLOC(ndr, r->out.delta_enum_array);
+ ZERO_STRUCTP(r->out.delta_enum_array);
+ if (r->in.change_log_entry) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.change_log_entry, r->in.change_log_entry_size));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.delta_enum_array);
+ }
+ _mem_save_delta_enum_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.delta_enum_array, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_DELTA_ENUM_ARRAY(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.delta_enum_array));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_delta_enum_array_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DatabaseRedo(struct ndr_print *ndr, const char *name, int flags, const struct netr_DatabaseRedo *r)
+{
+ ndr_print_struct(ndr, name, "netr_DatabaseRedo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_DatabaseRedo");
+ ndr->depth++;
+ ndr_print_string(ndr, "logon_server", r->in.logon_server);
+ ndr_print_string(ndr, "computername", r->in.computername);
+ ndr_print_netr_Authenticator(ndr, "credential", &r->in.credential);
+ ndr_print_ptr(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "change_log_entry", r->in.change_log_entry);
+ ndr->depth++;
+ if (r->in.change_log_entry) {
+ ndr_print_array_uint8(ndr, "change_log_entry", r->in.change_log_entry, r->in.change_log_entry_size);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "change_log_entry_size", r->in.change_log_entry_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_DatabaseRedo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "delta_enum_array", r->out.delta_enum_array);
+ ndr->depth++;
+ ndr_print_netr_DELTA_ENUM_ARRAY(ndr, "delta_enum_array", r->out.delta_enum_array);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_LogonControl2Ex(struct ndr_push *ndr, int flags, const struct netr_LogonControl2Ex *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.logon_server));
+ if (r->in.logon_server) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.logon_server, ndr_charset_length(r->in.logon_server, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.function_code));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->in.data, r->in.function_code));
+ NDR_CHECK(ndr_push_netr_CONTROL_DATA_INFORMATION(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.data));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.query == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.query, r->in.level));
+ NDR_CHECK(ndr_push_netr_CONTROL_QUERY_INFORMATION(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.query));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_LogonControl2Ex(struct ndr_pull *ndr, int flags, struct netr_LogonControl2Ex *r)
+{
+ uint32_t _ptr_logon_server;
+ TALLOC_CTX *_mem_save_logon_server_0;
+ TALLOC_CTX *_mem_save_query_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_logon_server));
+ if (_ptr_logon_server) {
+ NDR_PULL_ALLOC(ndr, r->in.logon_server);
+ } else {
+ r->in.logon_server = NULL;
+ }
+ if (r->in.logon_server) {
+ _mem_save_logon_server_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.logon_server, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.logon_server));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.logon_server));
+ if (ndr_get_array_length(ndr, &r->in.logon_server) > ndr_get_array_size(ndr, &r->in.logon_server)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.logon_server), ndr_get_array_length(ndr, &r->in.logon_server));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.logon_server, ndr_get_array_length(ndr, &r->in.logon_server), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_logon_server_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.function_code));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->in.data, r->in.function_code));
+ NDR_CHECK(ndr_pull_netr_CONTROL_DATA_INFORMATION(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.data));
+ NDR_PULL_ALLOC(ndr, r->out.query);
+ ZERO_STRUCTP(r->out.query);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.query);
+ }
+ _mem_save_query_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.query, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.query, r->in.level));
+ NDR_CHECK(ndr_pull_netr_CONTROL_QUERY_INFORMATION(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.query));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_query_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_LogonControl2Ex(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonControl2Ex *r)
+{
+ ndr_print_struct(ndr, name, "netr_LogonControl2Ex");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_LogonControl2Ex");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "logon_server", r->in.logon_server);
+ ndr->depth++;
+ if (r->in.logon_server) {
+ ndr_print_string(ndr, "logon_server", r->in.logon_server);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "function_code", r->in.function_code);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_set_switch_value(ndr, &r->in.data, r->in.function_code);
+ ndr_print_netr_CONTROL_DATA_INFORMATION(ndr, "data", &r->in.data);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_LogonControl2Ex");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "query", r->out.query);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.query, r->in.level);
+ ndr_print_netr_CONTROL_QUERY_INFORMATION(ndr, "query", r->out.query);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_NetrEnumerateTrustedDomains(struct ndr_push *ndr, int flags, const struct netr_NetrEnumerateTrustedDomains *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.trusted_domains_blob == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Blob(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.trusted_domains_blob));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_NetrEnumerateTrustedDomains(struct ndr_pull *ndr, int flags, struct netr_NetrEnumerateTrustedDomains *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_trusted_domains_blob_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.trusted_domains_blob);
+ ZERO_STRUCTP(r->out.trusted_domains_blob);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.trusted_domains_blob);
+ }
+ _mem_save_trusted_domains_blob_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.trusted_domains_blob, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Blob(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.trusted_domains_blob));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_trusted_domains_blob_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_NetrEnumerateTrustedDomains(struct ndr_print *ndr, const char *name, int flags, const struct netr_NetrEnumerateTrustedDomains *r)
+{
+ ndr_print_struct(ndr, name, "netr_NetrEnumerateTrustedDomains");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_NetrEnumerateTrustedDomains");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_NetrEnumerateTrustedDomains");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "trusted_domains_blob", r->out.trusted_domains_blob);
+ ndr->depth++;
+ ndr_print_netr_Blob(ndr, "trusted_domains_blob", r->out.trusted_domains_blob);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DsRGetDCName(struct ndr_push *ndr, int flags, const struct netr_DsRGetDCName *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.domain_name));
+ if (r->in.domain_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.domain_name, ndr_charset_length(r->in.domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.domain_guid));
+ if (r->in.domain_guid) {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.domain_guid));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.site_guid));
+ if (r->in.site_guid) {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.site_guid));
+ }
+ NDR_CHECK(ndr_push_netr_DsRGetDCName_flags(ndr, NDR_SCALARS, r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.info));
+ if (*r->out.info) {
+ NDR_CHECK(ndr_push_netr_DsRGetDCNameInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DsRGetDCName(struct ndr_pull *ndr, int flags, struct netr_DsRGetDCName *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_domain_name;
+ uint32_t _ptr_domain_guid;
+ uint32_t _ptr_site_guid;
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_domain_name_0;
+ TALLOC_CTX *_mem_save_domain_guid_0;
+ TALLOC_CTX *_mem_save_site_guid_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_name));
+ if (_ptr_domain_name) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_name);
+ } else {
+ r->in.domain_name = NULL;
+ }
+ if (r->in.domain_name) {
+ _mem_save_domain_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.domain_name));
+ if (ndr_get_array_length(ndr, &r->in.domain_name) > ndr_get_array_size(ndr, &r->in.domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.domain_name), ndr_get_array_length(ndr, &r->in.domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.domain_name, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_guid));
+ if (_ptr_domain_guid) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_guid);
+ } else {
+ r->in.domain_guid = NULL;
+ }
+ if (r->in.domain_guid) {
+ _mem_save_domain_guid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_guid, 0);
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.domain_guid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_guid_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_site_guid));
+ if (_ptr_site_guid) {
+ NDR_PULL_ALLOC(ndr, r->in.site_guid);
+ } else {
+ r->in.site_guid = NULL;
+ }
+ if (r->in.site_guid) {
+ _mem_save_site_guid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.site_guid, 0);
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.site_guid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_site_guid_0, 0);
+ }
+ NDR_CHECK(ndr_pull_netr_DsRGetDCName_flags(ndr, NDR_SCALARS, &r->in.flags));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ } else {
+ *r->out.info = NULL;
+ }
+ if (*r->out.info) {
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.info, 0);
+ NDR_CHECK(ndr_pull_netr_DsRGetDCNameInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsRGetDCName(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRGetDCName *r)
+{
+ ndr_print_struct(ndr, name, "netr_DsRGetDCName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_DsRGetDCName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_name", r->in.domain_name);
+ ndr->depth++;
+ if (r->in.domain_name) {
+ ndr_print_string(ndr, "domain_name", r->in.domain_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_guid", r->in.domain_guid);
+ ndr->depth++;
+ if (r->in.domain_guid) {
+ ndr_print_GUID(ndr, "domain_guid", r->in.domain_guid);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "site_guid", r->in.site_guid);
+ ndr->depth++;
+ if (r->in.site_guid) {
+ ndr_print_GUID(ndr, "site_guid", r->in.site_guid);
+ }
+ ndr->depth--;
+ ndr_print_netr_DsRGetDCName_flags(ndr, "flags", r->in.flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_DsRGetDCName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", *r->out.info);
+ ndr->depth++;
+ if (*r->out.info) {
+ ndr_print_netr_DsRGetDCNameInfo(ndr, "info", *r->out.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_NETRLOGONDUMMYROUTINE1(struct ndr_push *ndr, int flags, const struct netr_NETRLOGONDUMMYROUTINE1 *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_NETRLOGONDUMMYROUTINE1(struct ndr_pull *ndr, int flags, struct netr_NETRLOGONDUMMYROUTINE1 *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_NETRLOGONDUMMYROUTINE1(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONDUMMYROUTINE1 *r)
+{
+ ndr_print_struct(ndr, name, "netr_NETRLOGONDUMMYROUTINE1");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_NETRLOGONDUMMYROUTINE1");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_NETRLOGONDUMMYROUTINE1");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_NETRLOGONSETSERVICEBITS(struct ndr_push *ndr, int flags, const struct netr_NETRLOGONSETSERVICEBITS *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_NETRLOGONSETSERVICEBITS(struct ndr_pull *ndr, int flags, struct netr_NETRLOGONSETSERVICEBITS *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_NETRLOGONSETSERVICEBITS(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONSETSERVICEBITS *r)
+{
+ ndr_print_struct(ndr, name, "netr_NETRLOGONSETSERVICEBITS");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_NETRLOGONSETSERVICEBITS");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_NETRLOGONSETSERVICEBITS");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_LogonGetTrustRid(struct ndr_push *ndr, int flags, const struct netr_LogonGetTrustRid *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.domain_name));
+ if (r->in.domain_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.domain_name, ndr_charset_length(r->in.domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.rid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.rid));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_LogonGetTrustRid(struct ndr_pull *ndr, int flags, struct netr_LogonGetTrustRid *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_domain_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_domain_name_0;
+ TALLOC_CTX *_mem_save_rid_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_name));
+ if (_ptr_domain_name) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_name);
+ } else {
+ r->in.domain_name = NULL;
+ }
+ if (r->in.domain_name) {
+ _mem_save_domain_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.domain_name));
+ if (ndr_get_array_length(ndr, &r->in.domain_name) > ndr_get_array_size(ndr, &r->in.domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.domain_name), ndr_get_array_length(ndr, &r->in.domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.domain_name, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_name_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.rid);
+ ZERO_STRUCTP(r->out.rid);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.rid);
+ }
+ _mem_save_rid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.rid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.rid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_LogonGetTrustRid(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonGetTrustRid *r)
+{
+ ndr_print_struct(ndr, name, "netr_LogonGetTrustRid");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_LogonGetTrustRid");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_name", r->in.domain_name);
+ ndr->depth++;
+ if (r->in.domain_name) {
+ ndr_print_string(ndr, "domain_name", r->in.domain_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_LogonGetTrustRid");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "rid", r->out.rid);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "rid", *r->out.rid);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_NETRLOGONCOMPUTESERVERDIGEST(struct ndr_push *ndr, int flags, const struct netr_NETRLOGONCOMPUTESERVERDIGEST *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_NETRLOGONCOMPUTESERVERDIGEST(struct ndr_pull *ndr, int flags, struct netr_NETRLOGONCOMPUTESERVERDIGEST *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_NETRLOGONCOMPUTESERVERDIGEST(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONCOMPUTESERVERDIGEST *r)
+{
+ ndr_print_struct(ndr, name, "netr_NETRLOGONCOMPUTESERVERDIGEST");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_NETRLOGONCOMPUTESERVERDIGEST");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_NETRLOGONCOMPUTESERVERDIGEST");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_NETRLOGONCOMPUTECLIENTDIGEST(struct ndr_push *ndr, int flags, const struct netr_NETRLOGONCOMPUTECLIENTDIGEST *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_NETRLOGONCOMPUTECLIENTDIGEST(struct ndr_pull *ndr, int flags, struct netr_NETRLOGONCOMPUTECLIENTDIGEST *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_NETRLOGONCOMPUTECLIENTDIGEST(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONCOMPUTECLIENTDIGEST *r)
+{
+ ndr_print_struct(ndr, name, "netr_NETRLOGONCOMPUTECLIENTDIGEST");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_NETRLOGONCOMPUTECLIENTDIGEST");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_NETRLOGONCOMPUTECLIENTDIGEST");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_ServerAuthenticate3(struct ndr_push *ndr, int flags, const struct netr_ServerAuthenticate3 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.account_name, ndr_charset_length(r->in.account_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_netr_SchannelType(ndr, NDR_SCALARS, r->in.secure_channel_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computer_name, ndr_charset_length(r->in.computer_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ if (r->in.credentials == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Credential(ndr, NDR_SCALARS, r->in.credentials));
+ if (r->in.negotiate_flags == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_NegotiateFlags(ndr, NDR_SCALARS, *r->in.negotiate_flags));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.credentials == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Credential(ndr, NDR_SCALARS, r->out.credentials));
+ if (r->out.negotiate_flags == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_NegotiateFlags(ndr, NDR_SCALARS, *r->out.negotiate_flags));
+ if (r->out.rid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.rid));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_ServerAuthenticate3(struct ndr_pull *ndr, int flags, struct netr_ServerAuthenticate3 *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_credentials_0;
+ TALLOC_CTX *_mem_save_negotiate_flags_0;
+ TALLOC_CTX *_mem_save_rid_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.account_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.account_name));
+ if (ndr_get_array_length(ndr, &r->in.account_name) > ndr_get_array_size(ndr, &r->in.account_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.account_name), ndr_get_array_length(ndr, &r->in.account_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.account_name, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_netr_SchannelType(ndr, NDR_SCALARS, &r->in.secure_channel_type));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computer_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computer_name));
+ if (ndr_get_array_length(ndr, &r->in.computer_name) > ndr_get_array_size(ndr, &r->in.computer_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computer_name), ndr_get_array_length(ndr, &r->in.computer_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computer_name, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t), CH_UTF16));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.credentials);
+ }
+ _mem_save_credentials_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.credentials, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Credential(ndr, NDR_SCALARS, r->in.credentials));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_credentials_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.negotiate_flags);
+ }
+ _mem_save_negotiate_flags_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.negotiate_flags, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_NegotiateFlags(ndr, NDR_SCALARS, r->in.negotiate_flags));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_negotiate_flags_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.credentials);
+ *r->out.credentials = *r->in.credentials;
+ NDR_PULL_ALLOC(ndr, r->out.negotiate_flags);
+ *r->out.negotiate_flags = *r->in.negotiate_flags;
+ NDR_PULL_ALLOC(ndr, r->out.rid);
+ ZERO_STRUCTP(r->out.rid);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.credentials);
+ }
+ _mem_save_credentials_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.credentials, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Credential(ndr, NDR_SCALARS, r->out.credentials));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_credentials_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.negotiate_flags);
+ }
+ _mem_save_negotiate_flags_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.negotiate_flags, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_NegotiateFlags(ndr, NDR_SCALARS, r->out.negotiate_flags));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_negotiate_flags_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.rid);
+ }
+ _mem_save_rid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.rid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.rid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_ServerAuthenticate3(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerAuthenticate3 *r)
+{
+ ndr_print_struct(ndr, name, "netr_ServerAuthenticate3");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_ServerAuthenticate3");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "account_name", r->in.account_name);
+ ndr_print_netr_SchannelType(ndr, "secure_channel_type", r->in.secure_channel_type);
+ ndr_print_string(ndr, "computer_name", r->in.computer_name);
+ ndr_print_ptr(ndr, "credentials", r->in.credentials);
+ ndr->depth++;
+ ndr_print_netr_Credential(ndr, "credentials", r->in.credentials);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "negotiate_flags", r->in.negotiate_flags);
+ ndr->depth++;
+ ndr_print_netr_NegotiateFlags(ndr, "negotiate_flags", *r->in.negotiate_flags);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_ServerAuthenticate3");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "credentials", r->out.credentials);
+ ndr->depth++;
+ ndr_print_netr_Credential(ndr, "credentials", r->out.credentials);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "negotiate_flags", r->out.negotiate_flags);
+ ndr->depth++;
+ ndr_print_netr_NegotiateFlags(ndr, "negotiate_flags", *r->out.negotiate_flags);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "rid", r->out.rid);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "rid", *r->out.rid);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DsRGetDCNameEx(struct ndr_push *ndr, int flags, const struct netr_DsRGetDCNameEx *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.domain_name));
+ if (r->in.domain_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.domain_name, ndr_charset_length(r->in.domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.domain_guid));
+ if (r->in.domain_guid) {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.domain_guid));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.site_name));
+ if (r->in.site_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.site_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.site_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.site_name, ndr_charset_length(r->in.site_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_netr_DsRGetDCName_flags(ndr, NDR_SCALARS, r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.info));
+ if (*r->out.info) {
+ NDR_CHECK(ndr_push_netr_DsRGetDCNameInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DsRGetDCNameEx(struct ndr_pull *ndr, int flags, struct netr_DsRGetDCNameEx *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_domain_name;
+ uint32_t _ptr_domain_guid;
+ uint32_t _ptr_site_name;
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_domain_name_0;
+ TALLOC_CTX *_mem_save_domain_guid_0;
+ TALLOC_CTX *_mem_save_site_name_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_name));
+ if (_ptr_domain_name) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_name);
+ } else {
+ r->in.domain_name = NULL;
+ }
+ if (r->in.domain_name) {
+ _mem_save_domain_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.domain_name));
+ if (ndr_get_array_length(ndr, &r->in.domain_name) > ndr_get_array_size(ndr, &r->in.domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.domain_name), ndr_get_array_length(ndr, &r->in.domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.domain_name, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_guid));
+ if (_ptr_domain_guid) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_guid);
+ } else {
+ r->in.domain_guid = NULL;
+ }
+ if (r->in.domain_guid) {
+ _mem_save_domain_guid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_guid, 0);
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.domain_guid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_guid_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_site_name));
+ if (_ptr_site_name) {
+ NDR_PULL_ALLOC(ndr, r->in.site_name);
+ } else {
+ r->in.site_name = NULL;
+ }
+ if (r->in.site_name) {
+ _mem_save_site_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.site_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.site_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.site_name));
+ if (ndr_get_array_length(ndr, &r->in.site_name) > ndr_get_array_size(ndr, &r->in.site_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.site_name), ndr_get_array_length(ndr, &r->in.site_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.site_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.site_name, ndr_get_array_length(ndr, &r->in.site_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_site_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_netr_DsRGetDCName_flags(ndr, NDR_SCALARS, &r->in.flags));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ } else {
+ *r->out.info = NULL;
+ }
+ if (*r->out.info) {
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.info, 0);
+ NDR_CHECK(ndr_pull_netr_DsRGetDCNameInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsRGetDCNameEx(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRGetDCNameEx *r)
+{
+ ndr_print_struct(ndr, name, "netr_DsRGetDCNameEx");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_DsRGetDCNameEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_name", r->in.domain_name);
+ ndr->depth++;
+ if (r->in.domain_name) {
+ ndr_print_string(ndr, "domain_name", r->in.domain_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_guid", r->in.domain_guid);
+ ndr->depth++;
+ if (r->in.domain_guid) {
+ ndr_print_GUID(ndr, "domain_guid", r->in.domain_guid);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "site_name", r->in.site_name);
+ ndr->depth++;
+ if (r->in.site_name) {
+ ndr_print_string(ndr, "site_name", r->in.site_name);
+ }
+ ndr->depth--;
+ ndr_print_netr_DsRGetDCName_flags(ndr, "flags", r->in.flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_DsRGetDCNameEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", *r->out.info);
+ ndr->depth++;
+ if (*r->out.info) {
+ ndr_print_netr_DsRGetDCNameInfo(ndr, "info", *r->out.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DsRGetSiteName(struct ndr_push *ndr, int flags, const struct netr_DsRGetSiteName *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.computer_name));
+ if (r->in.computer_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computer_name, ndr_charset_length(r->in.computer_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.site == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.site));
+ if (*r->out.site) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.site, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.site, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, *r->out.site, ndr_charset_length(*r->out.site, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DsRGetSiteName(struct ndr_pull *ndr, int flags, struct netr_DsRGetSiteName *r)
+{
+ uint32_t _ptr_computer_name;
+ uint32_t _ptr_site;
+ TALLOC_CTX *_mem_save_computer_name_0;
+ TALLOC_CTX *_mem_save_site_0;
+ TALLOC_CTX *_mem_save_site_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_computer_name));
+ if (_ptr_computer_name) {
+ NDR_PULL_ALLOC(ndr, r->in.computer_name);
+ } else {
+ r->in.computer_name = NULL;
+ }
+ if (r->in.computer_name) {
+ _mem_save_computer_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.computer_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computer_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computer_name));
+ if (ndr_get_array_length(ndr, &r->in.computer_name) > ndr_get_array_size(ndr, &r->in.computer_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computer_name), ndr_get_array_length(ndr, &r->in.computer_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computer_name, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_computer_name_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.site);
+ ZERO_STRUCTP(r->out.site);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.site);
+ }
+ _mem_save_site_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.site, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_site));
+ if (_ptr_site) {
+ NDR_PULL_ALLOC(ndr, *r->out.site);
+ } else {
+ *r->out.site = NULL;
+ }
+ if (*r->out.site) {
+ _mem_save_site_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.site, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->out.site));
+ NDR_CHECK(ndr_pull_array_length(ndr, r->out.site));
+ if (ndr_get_array_length(ndr, r->out.site) > ndr_get_array_size(ndr, r->out.site)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, r->out.site), ndr_get_array_length(ndr, r->out.site));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, r->out.site), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, r->out.site, ndr_get_array_length(ndr, r->out.site), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_site_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_site_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsRGetSiteName(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRGetSiteName *r)
+{
+ ndr_print_struct(ndr, name, "netr_DsRGetSiteName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_DsRGetSiteName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "computer_name", r->in.computer_name);
+ ndr->depth++;
+ if (r->in.computer_name) {
+ ndr_print_string(ndr, "computer_name", r->in.computer_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_DsRGetSiteName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "site", r->out.site);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "site", *r->out.site);
+ ndr->depth++;
+ if (*r->out.site) {
+ ndr_print_string(ndr, "site", *r->out.site);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_LogonGetDomainInfo(struct ndr_push *ndr, int flags, const struct netr_LogonGetDomainInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.computer_name));
+ if (r->in.computer_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computer_name, ndr_charset_length(r->in.computer_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.credential == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ if (r->in.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->in.query, r->in.level));
+ NDR_CHECK(ndr_push_netr_DomainQuery(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.query));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_netr_DomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_LogonGetDomainInfo(struct ndr_pull *ndr, int flags, struct netr_LogonGetDomainInfo *r)
+{
+ uint32_t _ptr_computer_name;
+ TALLOC_CTX *_mem_save_computer_name_0;
+ TALLOC_CTX *_mem_save_credential_0;
+ TALLOC_CTX *_mem_save_return_authenticator_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_computer_name));
+ if (_ptr_computer_name) {
+ NDR_PULL_ALLOC(ndr, r->in.computer_name);
+ } else {
+ r->in.computer_name = NULL;
+ }
+ if (r->in.computer_name) {
+ _mem_save_computer_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.computer_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computer_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computer_name));
+ if (ndr_get_array_length(ndr, &r->in.computer_name) > ndr_get_array_size(ndr, &r->in.computer_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computer_name), ndr_get_array_length(ndr, &r->in.computer_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computer_name, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_computer_name_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.credential);
+ }
+ _mem_save_credential_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.credential, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_credential_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->in.query, r->in.level));
+ NDR_CHECK(ndr_pull_netr_DomainQuery(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.query));
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ *r->out.return_authenticator = *r->in.return_authenticator;
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_netr_DomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_LogonGetDomainInfo(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonGetDomainInfo *r)
+{
+ ndr_print_struct(ndr, name, "netr_LogonGetDomainInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_LogonGetDomainInfo");
+ ndr->depth++;
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ ndr_print_ptr(ndr, "computer_name", r->in.computer_name);
+ ndr->depth++;
+ if (r->in.computer_name) {
+ ndr_print_string(ndr, "computer_name", r->in.computer_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "credential", r->in.credential);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "credential", r->in.credential);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_set_switch_value(ndr, &r->in.query, r->in.level);
+ ndr_print_netr_DomainQuery(ndr, "query", &r->in.query);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_LogonGetDomainInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, r->in.level);
+ ndr_print_netr_DomainInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_ServerPasswordSet2(struct ndr_push *ndr, int flags, const struct netr_ServerPasswordSet2 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.account_name, ndr_charset_length(r->in.account_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_netr_SchannelType(ndr, NDR_SCALARS, r->in.secure_channel_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computer_name, ndr_charset_length(r->in.computer_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ if (r->in.credential == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ if (r->in.new_password == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_CryptPassword(ndr, NDR_SCALARS, r->in.new_password));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_ServerPasswordSet2(struct ndr_pull *ndr, int flags, struct netr_ServerPasswordSet2 *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_credential_0;
+ TALLOC_CTX *_mem_save_return_authenticator_0;
+ TALLOC_CTX *_mem_save_new_password_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.account_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.account_name));
+ if (ndr_get_array_length(ndr, &r->in.account_name) > ndr_get_array_size(ndr, &r->in.account_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.account_name), ndr_get_array_length(ndr, &r->in.account_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.account_name, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_netr_SchannelType(ndr, NDR_SCALARS, &r->in.secure_channel_type));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computer_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computer_name));
+ if (ndr_get_array_length(ndr, &r->in.computer_name) > ndr_get_array_size(ndr, &r->in.computer_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computer_name), ndr_get_array_length(ndr, &r->in.computer_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computer_name, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t), CH_UTF16));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.credential);
+ }
+ _mem_save_credential_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.credential, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_credential_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.new_password);
+ }
+ _mem_save_new_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.new_password, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_CryptPassword(ndr, NDR_SCALARS, r->in.new_password));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_new_password_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ ZERO_STRUCTP(r->out.return_authenticator);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_ServerPasswordSet2(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerPasswordSet2 *r)
+{
+ ndr_print_struct(ndr, name, "netr_ServerPasswordSet2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_ServerPasswordSet2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "account_name", r->in.account_name);
+ ndr_print_netr_SchannelType(ndr, "secure_channel_type", r->in.secure_channel_type);
+ ndr_print_string(ndr, "computer_name", r->in.computer_name);
+ ndr_print_ptr(ndr, "credential", r->in.credential);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "credential", r->in.credential);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "new_password", r->in.new_password);
+ ndr->depth++;
+ ndr_print_netr_CryptPassword(ndr, "new_password", r->in.new_password);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_ServerPasswordSet2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_ServerPasswordGet(struct ndr_push *ndr, int flags, const struct netr_ServerPasswordGet *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.account_name, ndr_charset_length(r->in.account_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_netr_SchannelType(ndr, NDR_SCALARS, r->in.secure_channel_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computer_name, ndr_charset_length(r->in.computer_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ if (r->in.credential == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ if (r->out.password == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.password));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_ServerPasswordGet(struct ndr_pull *ndr, int flags, struct netr_ServerPasswordGet *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_credential_0;
+ TALLOC_CTX *_mem_save_return_authenticator_0;
+ TALLOC_CTX *_mem_save_password_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.account_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.account_name));
+ if (ndr_get_array_length(ndr, &r->in.account_name) > ndr_get_array_size(ndr, &r->in.account_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.account_name), ndr_get_array_length(ndr, &r->in.account_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.account_name, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_netr_SchannelType(ndr, NDR_SCALARS, &r->in.secure_channel_type));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computer_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computer_name));
+ if (ndr_get_array_length(ndr, &r->in.computer_name) > ndr_get_array_size(ndr, &r->in.computer_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computer_name), ndr_get_array_length(ndr, &r->in.computer_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computer_name, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t), CH_UTF16));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.credential);
+ }
+ _mem_save_credential_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.credential, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_credential_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ ZERO_STRUCTP(r->out.return_authenticator);
+ NDR_PULL_ALLOC(ndr, r->out.password);
+ ZERO_STRUCTP(r->out.password);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.password);
+ }
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.password, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.password));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_ServerPasswordGet(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerPasswordGet *r)
+{
+ ndr_print_struct(ndr, name, "netr_ServerPasswordGet");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_ServerPasswordGet");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "account_name", r->in.account_name);
+ ndr_print_netr_SchannelType(ndr, "secure_channel_type", r->in.secure_channel_type);
+ ndr_print_string(ndr, "computer_name", r->in.computer_name);
+ ndr_print_ptr(ndr, "credential", r->in.credential);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "credential", r->in.credential);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_ServerPasswordGet");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->out.password);
+ ndr->depth++;
+ ndr_print_samr_Password(ndr, "password", r->out.password);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_NETRLOGONSENDTOSAM(struct ndr_push *ndr, int flags, const struct netr_NETRLOGONSENDTOSAM *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_NETRLOGONSENDTOSAM(struct ndr_pull *ndr, int flags, struct netr_NETRLOGONSENDTOSAM *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_NETRLOGONSENDTOSAM(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONSENDTOSAM *r)
+{
+ ndr_print_struct(ndr, name, "netr_NETRLOGONSENDTOSAM");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_NETRLOGONSENDTOSAM");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_NETRLOGONSENDTOSAM");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DsRAddressToSitenamesW(struct ndr_push *ndr, int flags, const struct netr_DsRAddressToSitenamesW *r)
+{
+ uint32_t cntr_addresses_1;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.count));
+ if (r->in.addresses == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.count));
+ for (cntr_addresses_1 = 0; cntr_addresses_1 < r->in.count; cntr_addresses_1++) {
+ NDR_CHECK(ndr_push_netr_DsRAddress(ndr, NDR_SCALARS, &r->in.addresses[cntr_addresses_1]));
+ }
+ for (cntr_addresses_1 = 0; cntr_addresses_1 < r->in.count; cntr_addresses_1++) {
+ NDR_CHECK(ndr_push_netr_DsRAddress(ndr, NDR_BUFFERS, &r->in.addresses[cntr_addresses_1]));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.ctr));
+ if (*r->out.ctr) {
+ NDR_CHECK(ndr_push_netr_DsRAddressToSitenamesWCtr(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.ctr));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DsRAddressToSitenamesW(struct ndr_pull *ndr, int flags, struct netr_DsRAddressToSitenamesW *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t cntr_addresses_1;
+ uint32_t _ptr_ctr;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_addresses_1;
+ TALLOC_CTX *_mem_save_ctr_0;
+ TALLOC_CTX *_mem_save_ctr_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.count));
+ if (r->in.count < 0 || r->in.count > 32000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.addresses));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC_N(ndr, r->in.addresses, ndr_get_array_size(ndr, &r->in.addresses));
+ }
+ _mem_save_addresses_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.addresses, 0);
+ for (cntr_addresses_1 = 0; cntr_addresses_1 < r->in.count; cntr_addresses_1++) {
+ NDR_CHECK(ndr_pull_netr_DsRAddress(ndr, NDR_SCALARS, &r->in.addresses[cntr_addresses_1]));
+ }
+ for (cntr_addresses_1 = 0; cntr_addresses_1 < r->in.count; cntr_addresses_1++) {
+ NDR_CHECK(ndr_pull_netr_DsRAddress(ndr, NDR_BUFFERS, &r->in.addresses[cntr_addresses_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_addresses_1, 0);
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ ZERO_STRUCTP(r->out.ctr);
+ if (r->in.addresses) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.addresses, r->in.count));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr));
+ if (_ptr_ctr) {
+ NDR_PULL_ALLOC(ndr, *r->out.ctr);
+ } else {
+ *r->out.ctr = NULL;
+ }
+ if (*r->out.ctr) {
+ _mem_save_ctr_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.ctr, 0);
+ NDR_CHECK(ndr_pull_netr_DsRAddressToSitenamesWCtr(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsRAddressToSitenamesW(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRAddressToSitenamesW *r)
+{
+ uint32_t cntr_addresses_1;
+ ndr_print_struct(ndr, name, "netr_DsRAddressToSitenamesW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_DsRAddressToSitenamesW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "count", r->in.count);
+ ndr_print_ptr(ndr, "addresses", r->in.addresses);
+ ndr->depth++;
+ ndr->print(ndr, "%s: ARRAY(%d)", "addresses", (int)r->in.count);
+ ndr->depth++;
+ for (cntr_addresses_1=0;cntr_addresses_1<r->in.count;cntr_addresses_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_addresses_1) != -1) {
+ ndr_print_netr_DsRAddress(ndr, "addresses", &r->in.addresses[cntr_addresses_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_DsRAddressToSitenamesW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "ctr", r->out.ctr);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "ctr", *r->out.ctr);
+ ndr->depth++;
+ if (*r->out.ctr) {
+ ndr_print_netr_DsRAddressToSitenamesWCtr(ndr, "ctr", *r->out.ctr);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DsRGetDCNameEx2(struct ndr_push *ndr, int flags, const struct netr_DsRGetDCNameEx2 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.client_account));
+ if (r->in.client_account) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.client_account, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.client_account, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.client_account, ndr_charset_length(r->in.client_account, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_samr_AcctFlags(ndr, NDR_SCALARS, r->in.mask));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.domain_name));
+ if (r->in.domain_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.domain_name, ndr_charset_length(r->in.domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.domain_guid));
+ if (r->in.domain_guid) {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.domain_guid));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.site_name));
+ if (r->in.site_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.site_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.site_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.site_name, ndr_charset_length(r->in.site_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_netr_DsRGetDCName_flags(ndr, NDR_SCALARS, r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.info));
+ if (*r->out.info) {
+ NDR_CHECK(ndr_push_netr_DsRGetDCNameInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DsRGetDCNameEx2(struct ndr_pull *ndr, int flags, struct netr_DsRGetDCNameEx2 *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_client_account;
+ uint32_t _ptr_domain_name;
+ uint32_t _ptr_domain_guid;
+ uint32_t _ptr_site_name;
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_client_account_0;
+ TALLOC_CTX *_mem_save_domain_name_0;
+ TALLOC_CTX *_mem_save_domain_guid_0;
+ TALLOC_CTX *_mem_save_site_name_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_client_account));
+ if (_ptr_client_account) {
+ NDR_PULL_ALLOC(ndr, r->in.client_account);
+ } else {
+ r->in.client_account = NULL;
+ }
+ if (r->in.client_account) {
+ _mem_save_client_account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.client_account, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.client_account));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.client_account));
+ if (ndr_get_array_length(ndr, &r->in.client_account) > ndr_get_array_size(ndr, &r->in.client_account)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.client_account), ndr_get_array_length(ndr, &r->in.client_account));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.client_account), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.client_account, ndr_get_array_length(ndr, &r->in.client_account), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_client_account_0, 0);
+ }
+ NDR_CHECK(ndr_pull_samr_AcctFlags(ndr, NDR_SCALARS, &r->in.mask));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_name));
+ if (_ptr_domain_name) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_name);
+ } else {
+ r->in.domain_name = NULL;
+ }
+ if (r->in.domain_name) {
+ _mem_save_domain_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.domain_name));
+ if (ndr_get_array_length(ndr, &r->in.domain_name) > ndr_get_array_size(ndr, &r->in.domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.domain_name), ndr_get_array_length(ndr, &r->in.domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.domain_name, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_guid));
+ if (_ptr_domain_guid) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_guid);
+ } else {
+ r->in.domain_guid = NULL;
+ }
+ if (r->in.domain_guid) {
+ _mem_save_domain_guid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_guid, 0);
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.domain_guid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_guid_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_site_name));
+ if (_ptr_site_name) {
+ NDR_PULL_ALLOC(ndr, r->in.site_name);
+ } else {
+ r->in.site_name = NULL;
+ }
+ if (r->in.site_name) {
+ _mem_save_site_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.site_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.site_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.site_name));
+ if (ndr_get_array_length(ndr, &r->in.site_name) > ndr_get_array_size(ndr, &r->in.site_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.site_name), ndr_get_array_length(ndr, &r->in.site_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.site_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.site_name, ndr_get_array_length(ndr, &r->in.site_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_site_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_netr_DsRGetDCName_flags(ndr, NDR_SCALARS, &r->in.flags));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ } else {
+ *r->out.info = NULL;
+ }
+ if (*r->out.info) {
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.info, 0);
+ NDR_CHECK(ndr_pull_netr_DsRGetDCNameInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsRGetDCNameEx2(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRGetDCNameEx2 *r)
+{
+ ndr_print_struct(ndr, name, "netr_DsRGetDCNameEx2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_DsRGetDCNameEx2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "client_account", r->in.client_account);
+ ndr->depth++;
+ if (r->in.client_account) {
+ ndr_print_string(ndr, "client_account", r->in.client_account);
+ }
+ ndr->depth--;
+ ndr_print_samr_AcctFlags(ndr, "mask", r->in.mask);
+ ndr_print_ptr(ndr, "domain_name", r->in.domain_name);
+ ndr->depth++;
+ if (r->in.domain_name) {
+ ndr_print_string(ndr, "domain_name", r->in.domain_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_guid", r->in.domain_guid);
+ ndr->depth++;
+ if (r->in.domain_guid) {
+ ndr_print_GUID(ndr, "domain_guid", r->in.domain_guid);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "site_name", r->in.site_name);
+ ndr->depth++;
+ if (r->in.site_name) {
+ ndr_print_string(ndr, "site_name", r->in.site_name);
+ }
+ ndr->depth--;
+ ndr_print_netr_DsRGetDCName_flags(ndr, "flags", r->in.flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_DsRGetDCNameEx2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", *r->out.info);
+ ndr->depth++;
+ if (*r->out.info) {
+ ndr_print_netr_DsRGetDCNameInfo(ndr, "info", *r->out.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(struct ndr_push *ndr, int flags, const struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(struct ndr_pull *ndr, int flags, struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN *r)
+{
+ ndr_print_struct(ndr, name, "netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_NetrEnumerateTrustedDomainsEx(struct ndr_push *ndr, int flags, const struct netr_NetrEnumerateTrustedDomainsEx *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.dom_trust_list == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_DomainTrustList(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.dom_trust_list));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_NetrEnumerateTrustedDomainsEx(struct ndr_pull *ndr, int flags, struct netr_NetrEnumerateTrustedDomainsEx *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_dom_trust_list_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.dom_trust_list);
+ ZERO_STRUCTP(r->out.dom_trust_list);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.dom_trust_list);
+ }
+ _mem_save_dom_trust_list_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.dom_trust_list, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_DomainTrustList(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.dom_trust_list));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dom_trust_list_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_NetrEnumerateTrustedDomainsEx(struct ndr_print *ndr, const char *name, int flags, const struct netr_NetrEnumerateTrustedDomainsEx *r)
+{
+ ndr_print_struct(ndr, name, "netr_NetrEnumerateTrustedDomainsEx");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_NetrEnumerateTrustedDomainsEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_NetrEnumerateTrustedDomainsEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "dom_trust_list", r->out.dom_trust_list);
+ ndr->depth++;
+ ndr_print_netr_DomainTrustList(ndr, "dom_trust_list", r->out.dom_trust_list);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DsRAddressToSitenamesExW(struct ndr_push *ndr, int flags, const struct netr_DsRAddressToSitenamesExW *r)
+{
+ uint32_t cntr_addresses_1;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.count));
+ if (r->in.addresses == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.count));
+ for (cntr_addresses_1 = 0; cntr_addresses_1 < r->in.count; cntr_addresses_1++) {
+ NDR_CHECK(ndr_push_netr_DsRAddress(ndr, NDR_SCALARS, &r->in.addresses[cntr_addresses_1]));
+ }
+ for (cntr_addresses_1 = 0; cntr_addresses_1 < r->in.count; cntr_addresses_1++) {
+ NDR_CHECK(ndr_push_netr_DsRAddress(ndr, NDR_BUFFERS, &r->in.addresses[cntr_addresses_1]));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.ctr));
+ if (*r->out.ctr) {
+ NDR_CHECK(ndr_push_netr_DsRAddressToSitenamesExWCtr(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.ctr));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DsRAddressToSitenamesExW(struct ndr_pull *ndr, int flags, struct netr_DsRAddressToSitenamesExW *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t cntr_addresses_1;
+ uint32_t _ptr_ctr;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_addresses_1;
+ TALLOC_CTX *_mem_save_ctr_0;
+ TALLOC_CTX *_mem_save_ctr_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.count));
+ if (r->in.count < 0 || r->in.count > 32000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.addresses));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC_N(ndr, r->in.addresses, ndr_get_array_size(ndr, &r->in.addresses));
+ }
+ _mem_save_addresses_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.addresses, 0);
+ for (cntr_addresses_1 = 0; cntr_addresses_1 < r->in.count; cntr_addresses_1++) {
+ NDR_CHECK(ndr_pull_netr_DsRAddress(ndr, NDR_SCALARS, &r->in.addresses[cntr_addresses_1]));
+ }
+ for (cntr_addresses_1 = 0; cntr_addresses_1 < r->in.count; cntr_addresses_1++) {
+ NDR_CHECK(ndr_pull_netr_DsRAddress(ndr, NDR_BUFFERS, &r->in.addresses[cntr_addresses_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_addresses_1, 0);
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ ZERO_STRUCTP(r->out.ctr);
+ if (r->in.addresses) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.addresses, r->in.count));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr));
+ if (_ptr_ctr) {
+ NDR_PULL_ALLOC(ndr, *r->out.ctr);
+ } else {
+ *r->out.ctr = NULL;
+ }
+ if (*r->out.ctr) {
+ _mem_save_ctr_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.ctr, 0);
+ NDR_CHECK(ndr_pull_netr_DsRAddressToSitenamesExWCtr(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsRAddressToSitenamesExW(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRAddressToSitenamesExW *r)
+{
+ uint32_t cntr_addresses_1;
+ ndr_print_struct(ndr, name, "netr_DsRAddressToSitenamesExW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_DsRAddressToSitenamesExW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "count", r->in.count);
+ ndr_print_ptr(ndr, "addresses", r->in.addresses);
+ ndr->depth++;
+ ndr->print(ndr, "%s: ARRAY(%d)", "addresses", (int)r->in.count);
+ ndr->depth++;
+ for (cntr_addresses_1=0;cntr_addresses_1<r->in.count;cntr_addresses_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_addresses_1) != -1) {
+ ndr_print_netr_DsRAddress(ndr, "addresses", &r->in.addresses[cntr_addresses_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_DsRAddressToSitenamesExW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "ctr", r->out.ctr);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "ctr", *r->out.ctr);
+ ndr->depth++;
+ if (*r->out.ctr) {
+ ndr_print_netr_DsRAddressToSitenamesExWCtr(ndr, "ctr", *r->out.ctr);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DsrGetDcSiteCoverageW(struct ndr_push *ndr, int flags, const struct netr_DsrGetDcSiteCoverageW *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_DcSitesCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DsrGetDcSiteCoverageW(struct ndr_pull *ndr, int flags, struct netr_DsrGetDcSiteCoverageW *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_ctr_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ ZERO_STRUCTP(r->out.ctr);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_DcSitesCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsrGetDcSiteCoverageW(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsrGetDcSiteCoverageW *r)
+{
+ ndr_print_struct(ndr, name, "netr_DsrGetDcSiteCoverageW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_DsrGetDcSiteCoverageW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_DsrGetDcSiteCoverageW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "ctr", r->out.ctr);
+ ndr->depth++;
+ ndr_print_DcSitesCtr(ndr, "ctr", r->out.ctr);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_LogonSamLogonEx(struct ndr_push *ndr, int flags, const struct netr_LogonSamLogonEx *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.computer_name));
+ if (r->in.computer_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computer_name, ndr_charset_length(r->in.computer_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_netr_LogonLevel(ndr, NDR_SCALARS, r->in.logon_level));
+ if (r->in.logon == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.logon, r->in.logon_level));
+ NDR_CHECK(ndr_push_netr_LogonInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.logon));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.validation_level));
+ if (r->in.flags == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.validation == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.validation, r->in.validation_level));
+ NDR_CHECK(ndr_push_netr_Validation(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.validation));
+ if (r->out.authoritative == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, *r->out.authoritative));
+ if (r->out.flags == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.flags));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_LogonSamLogonEx(struct ndr_pull *ndr, int flags, struct netr_LogonSamLogonEx *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_computer_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_computer_name_0;
+ TALLOC_CTX *_mem_save_logon_0;
+ TALLOC_CTX *_mem_save_validation_0;
+ TALLOC_CTX *_mem_save_authoritative_0;
+ TALLOC_CTX *_mem_save_flags_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_computer_name));
+ if (_ptr_computer_name) {
+ NDR_PULL_ALLOC(ndr, r->in.computer_name);
+ } else {
+ r->in.computer_name = NULL;
+ }
+ if (r->in.computer_name) {
+ _mem_save_computer_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.computer_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computer_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computer_name));
+ if (ndr_get_array_length(ndr, &r->in.computer_name) > ndr_get_array_size(ndr, &r->in.computer_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computer_name), ndr_get_array_length(ndr, &r->in.computer_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computer_name, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_computer_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_netr_LogonLevel(ndr, NDR_SCALARS, &r->in.logon_level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.logon);
+ }
+ _mem_save_logon_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.logon, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.logon, r->in.logon_level));
+ NDR_CHECK(ndr_pull_netr_LogonInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.logon));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_logon_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.validation_level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.flags);
+ }
+ _mem_save_flags_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.flags, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.flags));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_flags_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.validation);
+ ZERO_STRUCTP(r->out.validation);
+ NDR_PULL_ALLOC(ndr, r->out.authoritative);
+ ZERO_STRUCTP(r->out.authoritative);
+ NDR_PULL_ALLOC(ndr, r->out.flags);
+ *r->out.flags = *r->in.flags;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.validation);
+ }
+ _mem_save_validation_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.validation, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.validation, r->in.validation_level));
+ NDR_CHECK(ndr_pull_netr_Validation(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.validation));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_validation_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.authoritative);
+ }
+ _mem_save_authoritative_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.authoritative, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, r->out.authoritative));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_authoritative_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.flags);
+ }
+ _mem_save_flags_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.flags, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.flags));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_flags_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_LogonSamLogonEx(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonSamLogonEx *r)
+{
+ ndr_print_struct(ndr, name, "netr_LogonSamLogonEx");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_LogonSamLogonEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "computer_name", r->in.computer_name);
+ ndr->depth++;
+ if (r->in.computer_name) {
+ ndr_print_string(ndr, "computer_name", r->in.computer_name);
+ }
+ ndr->depth--;
+ ndr_print_netr_LogonLevel(ndr, "logon_level", r->in.logon_level);
+ ndr_print_ptr(ndr, "logon", r->in.logon);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.logon, r->in.logon_level);
+ ndr_print_netr_LogonInfo(ndr, "logon", r->in.logon);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "validation_level", r->in.validation_level);
+ ndr_print_ptr(ndr, "flags", r->in.flags);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "flags", *r->in.flags);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_LogonSamLogonEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "validation", r->out.validation);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.validation, r->in.validation_level);
+ ndr_print_netr_Validation(ndr, "validation", r->out.validation);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "authoritative", r->out.authoritative);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "authoritative", *r->out.authoritative);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "flags", r->out.flags);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "flags", *r->out.flags);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DsrEnumerateDomainTrusts(struct ndr_push *ndr, int flags, const struct netr_DsrEnumerateDomainTrusts *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_netr_TrustFlags(ndr, NDR_SCALARS, r->in.trust_flags));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.trusts == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_DomainTrustList(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.trusts));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DsrEnumerateDomainTrusts(struct ndr_pull *ndr, int flags, struct netr_DsrEnumerateDomainTrusts *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_trusts_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_netr_TrustFlags(ndr, NDR_SCALARS, &r->in.trust_flags));
+ NDR_PULL_ALLOC(ndr, r->out.trusts);
+ ZERO_STRUCTP(r->out.trusts);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.trusts);
+ }
+ _mem_save_trusts_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.trusts, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_DomainTrustList(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.trusts));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_trusts_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsrEnumerateDomainTrusts(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsrEnumerateDomainTrusts *r)
+{
+ ndr_print_struct(ndr, name, "netr_DsrEnumerateDomainTrusts");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_DsrEnumerateDomainTrusts");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_netr_TrustFlags(ndr, "trust_flags", r->in.trust_flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_DsrEnumerateDomainTrusts");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "trusts", r->out.trusts);
+ ndr->depth++;
+ ndr_print_netr_DomainTrustList(ndr, "trusts", r->out.trusts);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DsrDeregisterDNSHostRecords(struct ndr_push *ndr, int flags, const struct netr_DsrDeregisterDNSHostRecords *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.domain));
+ if (r->in.domain) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.domain, ndr_charset_length(r->in.domain, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.domain_guid));
+ if (r->in.domain_guid) {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.domain_guid));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.dsa_guid));
+ if (r->in.dsa_guid) {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.dsa_guid));
+ }
+ if (r->in.dns_host == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dns_host, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dns_host, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.dns_host, ndr_charset_length(r->in.dns_host, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DsrDeregisterDNSHostRecords(struct ndr_pull *ndr, int flags, struct netr_DsrDeregisterDNSHostRecords *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_domain;
+ uint32_t _ptr_domain_guid;
+ uint32_t _ptr_dsa_guid;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_domain_0;
+ TALLOC_CTX *_mem_save_domain_guid_0;
+ TALLOC_CTX *_mem_save_dsa_guid_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain));
+ if (_ptr_domain) {
+ NDR_PULL_ALLOC(ndr, r->in.domain);
+ } else {
+ r->in.domain = NULL;
+ }
+ if (r->in.domain) {
+ _mem_save_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.domain));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.domain));
+ if (ndr_get_array_length(ndr, &r->in.domain) > ndr_get_array_size(ndr, &r->in.domain)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.domain), ndr_get_array_length(ndr, &r->in.domain));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.domain), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.domain, ndr_get_array_length(ndr, &r->in.domain), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_guid));
+ if (_ptr_domain_guid) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_guid);
+ } else {
+ r->in.domain_guid = NULL;
+ }
+ if (r->in.domain_guid) {
+ _mem_save_domain_guid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_guid, 0);
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.domain_guid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_guid_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dsa_guid));
+ if (_ptr_dsa_guid) {
+ NDR_PULL_ALLOC(ndr, r->in.dsa_guid);
+ } else {
+ r->in.dsa_guid = NULL;
+ }
+ if (r->in.dsa_guid) {
+ _mem_save_dsa_guid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.dsa_guid, 0);
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.dsa_guid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dsa_guid_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.dns_host));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.dns_host));
+ if (ndr_get_array_length(ndr, &r->in.dns_host) > ndr_get_array_size(ndr, &r->in.dns_host)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.dns_host), ndr_get_array_length(ndr, &r->in.dns_host));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.dns_host), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.dns_host, ndr_get_array_length(ndr, &r->in.dns_host), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsrDeregisterDNSHostRecords(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsrDeregisterDNSHostRecords *r)
+{
+ ndr_print_struct(ndr, name, "netr_DsrDeregisterDNSHostRecords");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_DsrDeregisterDNSHostRecords");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain", r->in.domain);
+ ndr->depth++;
+ if (r->in.domain) {
+ ndr_print_string(ndr, "domain", r->in.domain);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_guid", r->in.domain_guid);
+ ndr->depth++;
+ if (r->in.domain_guid) {
+ ndr_print_GUID(ndr, "domain_guid", r->in.domain_guid);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "dsa_guid", r->in.dsa_guid);
+ ndr->depth++;
+ if (r->in.dsa_guid) {
+ ndr_print_GUID(ndr, "dsa_guid", r->in.dsa_guid);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "dns_host", r->in.dns_host);
+ ndr->depth++;
+ ndr_print_string(ndr, "dns_host", r->in.dns_host);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_DsrDeregisterDNSHostRecords");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_ServerTrustPasswordsGet(struct ndr_push *ndr, int flags, const struct netr_ServerTrustPasswordsGet *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.account_name, ndr_charset_length(r->in.account_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_netr_SchannelType(ndr, NDR_SCALARS, r->in.secure_channel_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computer_name, ndr_charset_length(r->in.computer_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ if (r->in.credential == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ if (r->out.password == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.password));
+ if (r->out.password2 == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.password2));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_ServerTrustPasswordsGet(struct ndr_pull *ndr, int flags, struct netr_ServerTrustPasswordsGet *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_credential_0;
+ TALLOC_CTX *_mem_save_return_authenticator_0;
+ TALLOC_CTX *_mem_save_password_0;
+ TALLOC_CTX *_mem_save_password2_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.account_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.account_name));
+ if (ndr_get_array_length(ndr, &r->in.account_name) > ndr_get_array_size(ndr, &r->in.account_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.account_name), ndr_get_array_length(ndr, &r->in.account_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.account_name, ndr_get_array_length(ndr, &r->in.account_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_netr_SchannelType(ndr, NDR_SCALARS, &r->in.secure_channel_type));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computer_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computer_name));
+ if (ndr_get_array_length(ndr, &r->in.computer_name) > ndr_get_array_size(ndr, &r->in.computer_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computer_name), ndr_get_array_length(ndr, &r->in.computer_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computer_name, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t), CH_UTF16));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.credential);
+ }
+ _mem_save_credential_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.credential, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_credential_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ ZERO_STRUCTP(r->out.return_authenticator);
+ NDR_PULL_ALLOC(ndr, r->out.password);
+ ZERO_STRUCTP(r->out.password);
+ NDR_PULL_ALLOC(ndr, r->out.password2);
+ ZERO_STRUCTP(r->out.password2);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.password);
+ }
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.password, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.password));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.password2);
+ }
+ _mem_save_password2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.password2, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.password2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password2_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_ServerTrustPasswordsGet(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerTrustPasswordsGet *r)
+{
+ ndr_print_struct(ndr, name, "netr_ServerTrustPasswordsGet");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_ServerTrustPasswordsGet");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "account_name", r->in.account_name);
+ ndr_print_netr_SchannelType(ndr, "secure_channel_type", r->in.secure_channel_type);
+ ndr_print_string(ndr, "computer_name", r->in.computer_name);
+ ndr_print_ptr(ndr, "credential", r->in.credential);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "credential", r->in.credential);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_ServerTrustPasswordsGet");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->out.password);
+ ndr->depth++;
+ ndr_print_samr_Password(ndr, "password", r->out.password);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password2", r->out.password2);
+ ndr->depth++;
+ ndr_print_samr_Password(ndr, "password2", r->out.password2);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_DsRGetForestTrustInformation(struct ndr_push *ndr, int flags, const struct netr_DsRGetForestTrustInformation *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.trusted_domain_name));
+ if (r->in.trusted_domain_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.trusted_domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.trusted_domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.trusted_domain_name, ndr_charset_length(r->in.trusted_domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.forest_trust_info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.forest_trust_info));
+ if (*r->out.forest_trust_info) {
+ NDR_CHECK(ndr_push_lsa_ForestTrustInformation(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.forest_trust_info));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_DsRGetForestTrustInformation(struct ndr_pull *ndr, int flags, struct netr_DsRGetForestTrustInformation *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_trusted_domain_name;
+ uint32_t _ptr_forest_trust_info;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_trusted_domain_name_0;
+ TALLOC_CTX *_mem_save_forest_trust_info_0;
+ TALLOC_CTX *_mem_save_forest_trust_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_trusted_domain_name));
+ if (_ptr_trusted_domain_name) {
+ NDR_PULL_ALLOC(ndr, r->in.trusted_domain_name);
+ } else {
+ r->in.trusted_domain_name = NULL;
+ }
+ if (r->in.trusted_domain_name) {
+ _mem_save_trusted_domain_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.trusted_domain_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.trusted_domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.trusted_domain_name));
+ if (ndr_get_array_length(ndr, &r->in.trusted_domain_name) > ndr_get_array_size(ndr, &r->in.trusted_domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.trusted_domain_name), ndr_get_array_length(ndr, &r->in.trusted_domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.trusted_domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.trusted_domain_name, ndr_get_array_length(ndr, &r->in.trusted_domain_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_trusted_domain_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.flags));
+ NDR_PULL_ALLOC(ndr, r->out.forest_trust_info);
+ ZERO_STRUCTP(r->out.forest_trust_info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.forest_trust_info);
+ }
+ _mem_save_forest_trust_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.forest_trust_info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_forest_trust_info));
+ if (_ptr_forest_trust_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.forest_trust_info);
+ } else {
+ *r->out.forest_trust_info = NULL;
+ }
+ if (*r->out.forest_trust_info) {
+ _mem_save_forest_trust_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.forest_trust_info, 0);
+ NDR_CHECK(ndr_pull_lsa_ForestTrustInformation(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.forest_trust_info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_forest_trust_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_forest_trust_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DsRGetForestTrustInformation(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRGetForestTrustInformation *r)
+{
+ ndr_print_struct(ndr, name, "netr_DsRGetForestTrustInformation");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_DsRGetForestTrustInformation");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "trusted_domain_name", r->in.trusted_domain_name);
+ ndr->depth++;
+ if (r->in.trusted_domain_name) {
+ ndr_print_string(ndr, "trusted_domain_name", r->in.trusted_domain_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_DsRGetForestTrustInformation");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "forest_trust_info", r->out.forest_trust_info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "forest_trust_info", *r->out.forest_trust_info);
+ ndr->depth++;
+ if (*r->out.forest_trust_info) {
+ ndr_print_lsa_ForestTrustInformation(ndr, "forest_trust_info", *r->out.forest_trust_info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_GetForestTrustInformation(struct ndr_push *ndr, int flags, const struct netr_GetForestTrustInformation *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.trusted_domain_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.trusted_domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.trusted_domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.trusted_domain_name, ndr_charset_length(r->in.trusted_domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ if (r->in.credential == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.return_authenticator == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ if (r->out.forest_trust_info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.forest_trust_info));
+ if (*r->out.forest_trust_info) {
+ NDR_CHECK(ndr_push_lsa_ForestTrustInformation(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.forest_trust_info));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_GetForestTrustInformation(struct ndr_pull *ndr, int flags, struct netr_GetForestTrustInformation *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_forest_trust_info;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_credential_0;
+ TALLOC_CTX *_mem_save_return_authenticator_0;
+ TALLOC_CTX *_mem_save_forest_trust_info_0;
+ TALLOC_CTX *_mem_save_forest_trust_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.trusted_domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.trusted_domain_name));
+ if (ndr_get_array_length(ndr, &r->in.trusted_domain_name) > ndr_get_array_size(ndr, &r->in.trusted_domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.trusted_domain_name), ndr_get_array_length(ndr, &r->in.trusted_domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.trusted_domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.trusted_domain_name, ndr_get_array_length(ndr, &r->in.trusted_domain_name), sizeof(uint16_t), CH_UTF16));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.credential);
+ }
+ _mem_save_credential_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.credential, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_credential_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.flags));
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ ZERO_STRUCTP(r->out.return_authenticator);
+ NDR_PULL_ALLOC(ndr, r->out.forest_trust_info);
+ ZERO_STRUCTP(r->out.forest_trust_info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ }
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_authenticator, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.forest_trust_info);
+ }
+ _mem_save_forest_trust_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.forest_trust_info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_forest_trust_info));
+ if (_ptr_forest_trust_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.forest_trust_info);
+ } else {
+ *r->out.forest_trust_info = NULL;
+ }
+ if (*r->out.forest_trust_info) {
+ _mem_save_forest_trust_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.forest_trust_info, 0);
+ NDR_CHECK(ndr_pull_lsa_ForestTrustInformation(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.forest_trust_info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_forest_trust_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_forest_trust_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_GetForestTrustInformation(struct ndr_print *ndr, const char *name, int flags, const struct netr_GetForestTrustInformation *r)
+{
+ ndr_print_struct(ndr, name, "netr_GetForestTrustInformation");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_GetForestTrustInformation");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "trusted_domain_name", r->in.trusted_domain_name);
+ ndr->depth++;
+ ndr_print_string(ndr, "trusted_domain_name", r->in.trusted_domain_name);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "credential", r->in.credential);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "credential", r->in.credential);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_GetForestTrustInformation");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth++;
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "forest_trust_info", r->out.forest_trust_info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "forest_trust_info", *r->out.forest_trust_info);
+ ndr->depth++;
+ if (*r->out.forest_trust_info) {
+ ndr_print_lsa_ForestTrustInformation(ndr, "forest_trust_info", *r->out.forest_trust_info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_LogonSamLogonWithFlags(struct ndr_push *ndr, int flags, const struct netr_LogonSamLogonWithFlags *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.computer_name));
+ if (r->in.computer_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computer_name, ndr_charset_length(r->in.computer_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.credential));
+ if (r->in.credential) {
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.return_authenticator));
+ if (r->in.return_authenticator) {
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ }
+ NDR_CHECK(ndr_push_netr_LogonLevel(ndr, NDR_SCALARS, r->in.logon_level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->in.logon, r->in.logon_level));
+ NDR_CHECK(ndr_push_netr_LogonInfo(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.logon));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.validation_level));
+ if (r->in.flags == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.return_authenticator));
+ if (r->out.return_authenticator) {
+ NDR_CHECK(ndr_push_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ }
+ if (r->out.validation == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.validation, r->in.validation_level));
+ NDR_CHECK(ndr_push_netr_Validation(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.validation));
+ if (r->out.authoritative == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, *r->out.authoritative));
+ if (r->out.flags == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.flags));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_LogonSamLogonWithFlags(struct ndr_pull *ndr, int flags, struct netr_LogonSamLogonWithFlags *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_computer_name;
+ uint32_t _ptr_credential;
+ uint32_t _ptr_return_authenticator;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_computer_name_0;
+ TALLOC_CTX *_mem_save_credential_0;
+ TALLOC_CTX *_mem_save_return_authenticator_0;
+ TALLOC_CTX *_mem_save_validation_0;
+ TALLOC_CTX *_mem_save_authoritative_0;
+ TALLOC_CTX *_mem_save_flags_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_computer_name));
+ if (_ptr_computer_name) {
+ NDR_PULL_ALLOC(ndr, r->in.computer_name);
+ } else {
+ r->in.computer_name = NULL;
+ }
+ if (r->in.computer_name) {
+ _mem_save_computer_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.computer_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computer_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computer_name));
+ if (ndr_get_array_length(ndr, &r->in.computer_name) > ndr_get_array_size(ndr, &r->in.computer_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computer_name), ndr_get_array_length(ndr, &r->in.computer_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computer_name, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_computer_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_credential));
+ if (_ptr_credential) {
+ NDR_PULL_ALLOC(ndr, r->in.credential);
+ } else {
+ r->in.credential = NULL;
+ }
+ if (r->in.credential) {
+ _mem_save_credential_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.credential, 0);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.credential));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_credential_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_return_authenticator));
+ if (_ptr_return_authenticator) {
+ NDR_PULL_ALLOC(ndr, r->in.return_authenticator);
+ } else {
+ r->in.return_authenticator = NULL;
+ }
+ if (r->in.return_authenticator) {
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.return_authenticator, 0);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->in.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, 0);
+ }
+ NDR_CHECK(ndr_pull_netr_LogonLevel(ndr, NDR_SCALARS, &r->in.logon_level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->in.logon, r->in.logon_level));
+ NDR_CHECK(ndr_pull_netr_LogonInfo(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.logon));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.validation_level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.flags);
+ }
+ _mem_save_flags_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.flags, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.flags));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_flags_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.validation);
+ ZERO_STRUCTP(r->out.validation);
+ NDR_PULL_ALLOC(ndr, r->out.authoritative);
+ ZERO_STRUCTP(r->out.authoritative);
+ NDR_PULL_ALLOC(ndr, r->out.flags);
+ *r->out.flags = *r->in.flags;
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_return_authenticator));
+ if (_ptr_return_authenticator) {
+ NDR_PULL_ALLOC(ndr, r->out.return_authenticator);
+ } else {
+ r->out.return_authenticator = NULL;
+ }
+ if (r->out.return_authenticator) {
+ _mem_save_return_authenticator_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.return_authenticator, 0);
+ NDR_CHECK(ndr_pull_netr_Authenticator(ndr, NDR_SCALARS, r->out.return_authenticator));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_return_authenticator_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.validation);
+ }
+ _mem_save_validation_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.validation, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.validation, r->in.validation_level));
+ NDR_CHECK(ndr_pull_netr_Validation(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.validation));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_validation_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.authoritative);
+ }
+ _mem_save_authoritative_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.authoritative, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, r->out.authoritative));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_authoritative_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.flags);
+ }
+ _mem_save_flags_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.flags, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.flags));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_flags_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_LogonSamLogonWithFlags(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonSamLogonWithFlags *r)
+{
+ ndr_print_struct(ndr, name, "netr_LogonSamLogonWithFlags");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_LogonSamLogonWithFlags");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "computer_name", r->in.computer_name);
+ ndr->depth++;
+ if (r->in.computer_name) {
+ ndr_print_string(ndr, "computer_name", r->in.computer_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "credential", r->in.credential);
+ ndr->depth++;
+ if (r->in.credential) {
+ ndr_print_netr_Authenticator(ndr, "credential", r->in.credential);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "return_authenticator", r->in.return_authenticator);
+ ndr->depth++;
+ if (r->in.return_authenticator) {
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->in.return_authenticator);
+ }
+ ndr->depth--;
+ ndr_print_netr_LogonLevel(ndr, "logon_level", r->in.logon_level);
+ ndr_print_set_switch_value(ndr, &r->in.logon, r->in.logon_level);
+ ndr_print_netr_LogonInfo(ndr, "logon", &r->in.logon);
+ ndr_print_uint16(ndr, "validation_level", r->in.validation_level);
+ ndr_print_ptr(ndr, "flags", r->in.flags);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "flags", *r->in.flags);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_LogonSamLogonWithFlags");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "return_authenticator", r->out.return_authenticator);
+ ndr->depth++;
+ if (r->out.return_authenticator) {
+ ndr_print_netr_Authenticator(ndr, "return_authenticator", r->out.return_authenticator);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "validation", r->out.validation);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.validation, r->in.validation_level);
+ ndr_print_netr_Validation(ndr, "validation", r->out.validation);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "authoritative", r->out.authoritative);
+ ndr->depth++;
+ ndr_print_uint8(ndr, "authoritative", *r->out.authoritative);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "flags", r->out.flags);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "flags", *r->out.flags);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_netr_NETRSERVERGETTRUSTINFO(struct ndr_push *ndr, int flags, const struct netr_NETRSERVERGETTRUSTINFO *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_netr_NETRSERVERGETTRUSTINFO(struct ndr_pull *ndr, int flags, struct netr_NETRSERVERGETTRUSTINFO *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_NETRSERVERGETTRUSTINFO(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRSERVERGETTRUSTINFO *r)
+{
+ ndr_print_struct(ndr, name, "netr_NETRSERVERGETTRUSTINFO");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "netr_NETRSERVERGETTRUSTINFO");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "netr_NETRSERVERGETTRUSTINFO");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call netlogon_calls[] = {
+ {
+ "netr_LogonUasLogon",
+ sizeof(struct netr_LogonUasLogon),
+ (ndr_push_flags_fn_t) ndr_push_netr_LogonUasLogon,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_LogonUasLogon,
+ (ndr_print_function_t) ndr_print_netr_LogonUasLogon,
+ false,
+ },
+ {
+ "netr_LogonUasLogoff",
+ sizeof(struct netr_LogonUasLogoff),
+ (ndr_push_flags_fn_t) ndr_push_netr_LogonUasLogoff,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_LogonUasLogoff,
+ (ndr_print_function_t) ndr_print_netr_LogonUasLogoff,
+ false,
+ },
+ {
+ "netr_LogonSamLogon",
+ sizeof(struct netr_LogonSamLogon),
+ (ndr_push_flags_fn_t) ndr_push_netr_LogonSamLogon,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_LogonSamLogon,
+ (ndr_print_function_t) ndr_print_netr_LogonSamLogon,
+ false,
+ },
+ {
+ "netr_LogonSamLogoff",
+ sizeof(struct netr_LogonSamLogoff),
+ (ndr_push_flags_fn_t) ndr_push_netr_LogonSamLogoff,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_LogonSamLogoff,
+ (ndr_print_function_t) ndr_print_netr_LogonSamLogoff,
+ false,
+ },
+ {
+ "netr_ServerReqChallenge",
+ sizeof(struct netr_ServerReqChallenge),
+ (ndr_push_flags_fn_t) ndr_push_netr_ServerReqChallenge,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_ServerReqChallenge,
+ (ndr_print_function_t) ndr_print_netr_ServerReqChallenge,
+ false,
+ },
+ {
+ "netr_ServerAuthenticate",
+ sizeof(struct netr_ServerAuthenticate),
+ (ndr_push_flags_fn_t) ndr_push_netr_ServerAuthenticate,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_ServerAuthenticate,
+ (ndr_print_function_t) ndr_print_netr_ServerAuthenticate,
+ false,
+ },
+ {
+ "netr_ServerPasswordSet",
+ sizeof(struct netr_ServerPasswordSet),
+ (ndr_push_flags_fn_t) ndr_push_netr_ServerPasswordSet,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_ServerPasswordSet,
+ (ndr_print_function_t) ndr_print_netr_ServerPasswordSet,
+ false,
+ },
+ {
+ "netr_DatabaseDeltas",
+ sizeof(struct netr_DatabaseDeltas),
+ (ndr_push_flags_fn_t) ndr_push_netr_DatabaseDeltas,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_DatabaseDeltas,
+ (ndr_print_function_t) ndr_print_netr_DatabaseDeltas,
+ false,
+ },
+ {
+ "netr_DatabaseSync",
+ sizeof(struct netr_DatabaseSync),
+ (ndr_push_flags_fn_t) ndr_push_netr_DatabaseSync,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_DatabaseSync,
+ (ndr_print_function_t) ndr_print_netr_DatabaseSync,
+ false,
+ },
+ {
+ "netr_AccountDeltas",
+ sizeof(struct netr_AccountDeltas),
+ (ndr_push_flags_fn_t) ndr_push_netr_AccountDeltas,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_AccountDeltas,
+ (ndr_print_function_t) ndr_print_netr_AccountDeltas,
+ false,
+ },
+ {
+ "netr_AccountSync",
+ sizeof(struct netr_AccountSync),
+ (ndr_push_flags_fn_t) ndr_push_netr_AccountSync,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_AccountSync,
+ (ndr_print_function_t) ndr_print_netr_AccountSync,
+ false,
+ },
+ {
+ "netr_GetDcName",
+ sizeof(struct netr_GetDcName),
+ (ndr_push_flags_fn_t) ndr_push_netr_GetDcName,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_GetDcName,
+ (ndr_print_function_t) ndr_print_netr_GetDcName,
+ false,
+ },
+ {
+ "netr_LogonControl",
+ sizeof(struct netr_LogonControl),
+ (ndr_push_flags_fn_t) ndr_push_netr_LogonControl,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_LogonControl,
+ (ndr_print_function_t) ndr_print_netr_LogonControl,
+ false,
+ },
+ {
+ "netr_GetAnyDCName",
+ sizeof(struct netr_GetAnyDCName),
+ (ndr_push_flags_fn_t) ndr_push_netr_GetAnyDCName,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_GetAnyDCName,
+ (ndr_print_function_t) ndr_print_netr_GetAnyDCName,
+ false,
+ },
+ {
+ "netr_LogonControl2",
+ sizeof(struct netr_LogonControl2),
+ (ndr_push_flags_fn_t) ndr_push_netr_LogonControl2,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_LogonControl2,
+ (ndr_print_function_t) ndr_print_netr_LogonControl2,
+ false,
+ },
+ {
+ "netr_ServerAuthenticate2",
+ sizeof(struct netr_ServerAuthenticate2),
+ (ndr_push_flags_fn_t) ndr_push_netr_ServerAuthenticate2,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_ServerAuthenticate2,
+ (ndr_print_function_t) ndr_print_netr_ServerAuthenticate2,
+ false,
+ },
+ {
+ "netr_DatabaseSync2",
+ sizeof(struct netr_DatabaseSync2),
+ (ndr_push_flags_fn_t) ndr_push_netr_DatabaseSync2,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_DatabaseSync2,
+ (ndr_print_function_t) ndr_print_netr_DatabaseSync2,
+ false,
+ },
+ {
+ "netr_DatabaseRedo",
+ sizeof(struct netr_DatabaseRedo),
+ (ndr_push_flags_fn_t) ndr_push_netr_DatabaseRedo,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_DatabaseRedo,
+ (ndr_print_function_t) ndr_print_netr_DatabaseRedo,
+ false,
+ },
+ {
+ "netr_LogonControl2Ex",
+ sizeof(struct netr_LogonControl2Ex),
+ (ndr_push_flags_fn_t) ndr_push_netr_LogonControl2Ex,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_LogonControl2Ex,
+ (ndr_print_function_t) ndr_print_netr_LogonControl2Ex,
+ false,
+ },
+ {
+ "netr_NetrEnumerateTrustedDomains",
+ sizeof(struct netr_NetrEnumerateTrustedDomains),
+ (ndr_push_flags_fn_t) ndr_push_netr_NetrEnumerateTrustedDomains,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_NetrEnumerateTrustedDomains,
+ (ndr_print_function_t) ndr_print_netr_NetrEnumerateTrustedDomains,
+ false,
+ },
+ {
+ "netr_DsRGetDCName",
+ sizeof(struct netr_DsRGetDCName),
+ (ndr_push_flags_fn_t) ndr_push_netr_DsRGetDCName,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_DsRGetDCName,
+ (ndr_print_function_t) ndr_print_netr_DsRGetDCName,
+ false,
+ },
+ {
+ "netr_NETRLOGONDUMMYROUTINE1",
+ sizeof(struct netr_NETRLOGONDUMMYROUTINE1),
+ (ndr_push_flags_fn_t) ndr_push_netr_NETRLOGONDUMMYROUTINE1,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_NETRLOGONDUMMYROUTINE1,
+ (ndr_print_function_t) ndr_print_netr_NETRLOGONDUMMYROUTINE1,
+ false,
+ },
+ {
+ "netr_NETRLOGONSETSERVICEBITS",
+ sizeof(struct netr_NETRLOGONSETSERVICEBITS),
+ (ndr_push_flags_fn_t) ndr_push_netr_NETRLOGONSETSERVICEBITS,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_NETRLOGONSETSERVICEBITS,
+ (ndr_print_function_t) ndr_print_netr_NETRLOGONSETSERVICEBITS,
+ false,
+ },
+ {
+ "netr_LogonGetTrustRid",
+ sizeof(struct netr_LogonGetTrustRid),
+ (ndr_push_flags_fn_t) ndr_push_netr_LogonGetTrustRid,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_LogonGetTrustRid,
+ (ndr_print_function_t) ndr_print_netr_LogonGetTrustRid,
+ false,
+ },
+ {
+ "netr_NETRLOGONCOMPUTESERVERDIGEST",
+ sizeof(struct netr_NETRLOGONCOMPUTESERVERDIGEST),
+ (ndr_push_flags_fn_t) ndr_push_netr_NETRLOGONCOMPUTESERVERDIGEST,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_NETRLOGONCOMPUTESERVERDIGEST,
+ (ndr_print_function_t) ndr_print_netr_NETRLOGONCOMPUTESERVERDIGEST,
+ false,
+ },
+ {
+ "netr_NETRLOGONCOMPUTECLIENTDIGEST",
+ sizeof(struct netr_NETRLOGONCOMPUTECLIENTDIGEST),
+ (ndr_push_flags_fn_t) ndr_push_netr_NETRLOGONCOMPUTECLIENTDIGEST,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_NETRLOGONCOMPUTECLIENTDIGEST,
+ (ndr_print_function_t) ndr_print_netr_NETRLOGONCOMPUTECLIENTDIGEST,
+ false,
+ },
+ {
+ "netr_ServerAuthenticate3",
+ sizeof(struct netr_ServerAuthenticate3),
+ (ndr_push_flags_fn_t) ndr_push_netr_ServerAuthenticate3,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_ServerAuthenticate3,
+ (ndr_print_function_t) ndr_print_netr_ServerAuthenticate3,
+ false,
+ },
+ {
+ "netr_DsRGetDCNameEx",
+ sizeof(struct netr_DsRGetDCNameEx),
+ (ndr_push_flags_fn_t) ndr_push_netr_DsRGetDCNameEx,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_DsRGetDCNameEx,
+ (ndr_print_function_t) ndr_print_netr_DsRGetDCNameEx,
+ false,
+ },
+ {
+ "netr_DsRGetSiteName",
+ sizeof(struct netr_DsRGetSiteName),
+ (ndr_push_flags_fn_t) ndr_push_netr_DsRGetSiteName,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_DsRGetSiteName,
+ (ndr_print_function_t) ndr_print_netr_DsRGetSiteName,
+ false,
+ },
+ {
+ "netr_LogonGetDomainInfo",
+ sizeof(struct netr_LogonGetDomainInfo),
+ (ndr_push_flags_fn_t) ndr_push_netr_LogonGetDomainInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_LogonGetDomainInfo,
+ (ndr_print_function_t) ndr_print_netr_LogonGetDomainInfo,
+ false,
+ },
+ {
+ "netr_ServerPasswordSet2",
+ sizeof(struct netr_ServerPasswordSet2),
+ (ndr_push_flags_fn_t) ndr_push_netr_ServerPasswordSet2,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_ServerPasswordSet2,
+ (ndr_print_function_t) ndr_print_netr_ServerPasswordSet2,
+ false,
+ },
+ {
+ "netr_ServerPasswordGet",
+ sizeof(struct netr_ServerPasswordGet),
+ (ndr_push_flags_fn_t) ndr_push_netr_ServerPasswordGet,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_ServerPasswordGet,
+ (ndr_print_function_t) ndr_print_netr_ServerPasswordGet,
+ false,
+ },
+ {
+ "netr_NETRLOGONSENDTOSAM",
+ sizeof(struct netr_NETRLOGONSENDTOSAM),
+ (ndr_push_flags_fn_t) ndr_push_netr_NETRLOGONSENDTOSAM,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_NETRLOGONSENDTOSAM,
+ (ndr_print_function_t) ndr_print_netr_NETRLOGONSENDTOSAM,
+ false,
+ },
+ {
+ "netr_DsRAddressToSitenamesW",
+ sizeof(struct netr_DsRAddressToSitenamesW),
+ (ndr_push_flags_fn_t) ndr_push_netr_DsRAddressToSitenamesW,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_DsRAddressToSitenamesW,
+ (ndr_print_function_t) ndr_print_netr_DsRAddressToSitenamesW,
+ false,
+ },
+ {
+ "netr_DsRGetDCNameEx2",
+ sizeof(struct netr_DsRGetDCNameEx2),
+ (ndr_push_flags_fn_t) ndr_push_netr_DsRGetDCNameEx2,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_DsRGetDCNameEx2,
+ (ndr_print_function_t) ndr_print_netr_DsRGetDCNameEx2,
+ false,
+ },
+ {
+ "netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN",
+ sizeof(struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN),
+ (ndr_push_flags_fn_t) ndr_push_netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN,
+ (ndr_print_function_t) ndr_print_netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN,
+ false,
+ },
+ {
+ "netr_NetrEnumerateTrustedDomainsEx",
+ sizeof(struct netr_NetrEnumerateTrustedDomainsEx),
+ (ndr_push_flags_fn_t) ndr_push_netr_NetrEnumerateTrustedDomainsEx,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_NetrEnumerateTrustedDomainsEx,
+ (ndr_print_function_t) ndr_print_netr_NetrEnumerateTrustedDomainsEx,
+ false,
+ },
+ {
+ "netr_DsRAddressToSitenamesExW",
+ sizeof(struct netr_DsRAddressToSitenamesExW),
+ (ndr_push_flags_fn_t) ndr_push_netr_DsRAddressToSitenamesExW,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_DsRAddressToSitenamesExW,
+ (ndr_print_function_t) ndr_print_netr_DsRAddressToSitenamesExW,
+ false,
+ },
+ {
+ "netr_DsrGetDcSiteCoverageW",
+ sizeof(struct netr_DsrGetDcSiteCoverageW),
+ (ndr_push_flags_fn_t) ndr_push_netr_DsrGetDcSiteCoverageW,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_DsrGetDcSiteCoverageW,
+ (ndr_print_function_t) ndr_print_netr_DsrGetDcSiteCoverageW,
+ false,
+ },
+ {
+ "netr_LogonSamLogonEx",
+ sizeof(struct netr_LogonSamLogonEx),
+ (ndr_push_flags_fn_t) ndr_push_netr_LogonSamLogonEx,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_LogonSamLogonEx,
+ (ndr_print_function_t) ndr_print_netr_LogonSamLogonEx,
+ false,
+ },
+ {
+ "netr_DsrEnumerateDomainTrusts",
+ sizeof(struct netr_DsrEnumerateDomainTrusts),
+ (ndr_push_flags_fn_t) ndr_push_netr_DsrEnumerateDomainTrusts,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_DsrEnumerateDomainTrusts,
+ (ndr_print_function_t) ndr_print_netr_DsrEnumerateDomainTrusts,
+ false,
+ },
+ {
+ "netr_DsrDeregisterDNSHostRecords",
+ sizeof(struct netr_DsrDeregisterDNSHostRecords),
+ (ndr_push_flags_fn_t) ndr_push_netr_DsrDeregisterDNSHostRecords,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_DsrDeregisterDNSHostRecords,
+ (ndr_print_function_t) ndr_print_netr_DsrDeregisterDNSHostRecords,
+ false,
+ },
+ {
+ "netr_ServerTrustPasswordsGet",
+ sizeof(struct netr_ServerTrustPasswordsGet),
+ (ndr_push_flags_fn_t) ndr_push_netr_ServerTrustPasswordsGet,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_ServerTrustPasswordsGet,
+ (ndr_print_function_t) ndr_print_netr_ServerTrustPasswordsGet,
+ false,
+ },
+ {
+ "netr_DsRGetForestTrustInformation",
+ sizeof(struct netr_DsRGetForestTrustInformation),
+ (ndr_push_flags_fn_t) ndr_push_netr_DsRGetForestTrustInformation,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_DsRGetForestTrustInformation,
+ (ndr_print_function_t) ndr_print_netr_DsRGetForestTrustInformation,
+ false,
+ },
+ {
+ "netr_GetForestTrustInformation",
+ sizeof(struct netr_GetForestTrustInformation),
+ (ndr_push_flags_fn_t) ndr_push_netr_GetForestTrustInformation,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_GetForestTrustInformation,
+ (ndr_print_function_t) ndr_print_netr_GetForestTrustInformation,
+ false,
+ },
+ {
+ "netr_LogonSamLogonWithFlags",
+ sizeof(struct netr_LogonSamLogonWithFlags),
+ (ndr_push_flags_fn_t) ndr_push_netr_LogonSamLogonWithFlags,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_LogonSamLogonWithFlags,
+ (ndr_print_function_t) ndr_print_netr_LogonSamLogonWithFlags,
+ false,
+ },
+ {
+ "netr_NETRSERVERGETTRUSTINFO",
+ sizeof(struct netr_NETRSERVERGETTRUSTINFO),
+ (ndr_push_flags_fn_t) ndr_push_netr_NETRSERVERGETTRUSTINFO,
+ (ndr_pull_flags_fn_t) ndr_pull_netr_NETRSERVERGETTRUSTINFO,
+ (ndr_print_function_t) ndr_print_netr_NETRSERVERGETTRUSTINFO,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const netlogon_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\netlogon]",
+ "ncacn_ip_tcp:",
+ "ncalrpc:",
+};
+
+static const struct ndr_interface_string_array netlogon_endpoints = {
+ .count = 3,
+ .names = netlogon_endpoint_strings
+};
+
+static const char * const netlogon_authservice_strings[] = {
+ "host",
+};
+
+static const struct ndr_interface_string_array netlogon_authservices = {
+ .count = 1,
+ .names = netlogon_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_netlogon = {
+ .name = "netlogon",
+ .syntax_id = {
+ {0x12345678,0x1234,0xabcd,{0xef,0x00},{0x01,0x23,0x45,0x67,0xcf,0xfb}},
+ NDR_NETLOGON_VERSION
+ },
+ .helpstring = NDR_NETLOGON_HELPSTRING,
+ .num_calls = 47,
+ .calls = netlogon_calls,
+ .endpoints = &netlogon_endpoints,
+ .authservices = &netlogon_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_netlogon.h b/source3/librpc/gen_ndr/ndr_netlogon.h
new file mode 100644
index 0000000000..a9d36aeacb
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_netlogon.h
@@ -0,0 +1,261 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/netlogon.h"
+
+#ifndef _HEADER_NDR_netlogon
+#define _HEADER_NDR_netlogon
+
+#define NDR_NETLOGON_UUID "12345678-1234-abcd-ef00-01234567cffb"
+#define NDR_NETLOGON_VERSION 1.0
+#define NDR_NETLOGON_NAME "netlogon"
+#define NDR_NETLOGON_HELPSTRING NULL
+extern const struct ndr_interface_table ndr_table_netlogon;
+#define NDR_NETR_LOGONUASLOGON (0x00)
+
+#define NDR_NETR_LOGONUASLOGOFF (0x01)
+
+#define NDR_NETR_LOGONSAMLOGON (0x02)
+
+#define NDR_NETR_LOGONSAMLOGOFF (0x03)
+
+#define NDR_NETR_SERVERREQCHALLENGE (0x04)
+
+#define NDR_NETR_SERVERAUTHENTICATE (0x05)
+
+#define NDR_NETR_SERVERPASSWORDSET (0x06)
+
+#define NDR_NETR_DATABASEDELTAS (0x07)
+
+#define NDR_NETR_DATABASESYNC (0x08)
+
+#define NDR_NETR_ACCOUNTDELTAS (0x09)
+
+#define NDR_NETR_ACCOUNTSYNC (0x0a)
+
+#define NDR_NETR_GETDCNAME (0x0b)
+
+#define NDR_NETR_LOGONCONTROL (0x0c)
+
+#define NDR_NETR_GETANYDCNAME (0x0d)
+
+#define NDR_NETR_LOGONCONTROL2 (0x0e)
+
+#define NDR_NETR_SERVERAUTHENTICATE2 (0x0f)
+
+#define NDR_NETR_DATABASESYNC2 (0x10)
+
+#define NDR_NETR_DATABASEREDO (0x11)
+
+#define NDR_NETR_LOGONCONTROL2EX (0x12)
+
+#define NDR_NETR_NETRENUMERATETRUSTEDDOMAINS (0x13)
+
+#define NDR_NETR_DSRGETDCNAME (0x14)
+
+#define NDR_NETR_NETRLOGONDUMMYROUTINE1 (0x15)
+
+#define NDR_NETR_NETRLOGONSETSERVICEBITS (0x16)
+
+#define NDR_NETR_LOGONGETTRUSTRID (0x17)
+
+#define NDR_NETR_NETRLOGONCOMPUTESERVERDIGEST (0x18)
+
+#define NDR_NETR_NETRLOGONCOMPUTECLIENTDIGEST (0x19)
+
+#define NDR_NETR_SERVERAUTHENTICATE3 (0x1a)
+
+#define NDR_NETR_DSRGETDCNAMEEX (0x1b)
+
+#define NDR_NETR_DSRGETSITENAME (0x1c)
+
+#define NDR_NETR_LOGONGETDOMAININFO (0x1d)
+
+#define NDR_NETR_SERVERPASSWORDSET2 (0x1e)
+
+#define NDR_NETR_SERVERPASSWORDGET (0x1f)
+
+#define NDR_NETR_NETRLOGONSENDTOSAM (0x20)
+
+#define NDR_NETR_DSRADDRESSTOSITENAMESW (0x21)
+
+#define NDR_NETR_DSRGETDCNAMEEX2 (0x22)
+
+#define NDR_NETR_NETRLOGONGETTIMESERVICEPARENTDOMAIN (0x23)
+
+#define NDR_NETR_NETRENUMERATETRUSTEDDOMAINSEX (0x24)
+
+#define NDR_NETR_DSRADDRESSTOSITENAMESEXW (0x25)
+
+#define NDR_NETR_DSRGETDCSITECOVERAGEW (0x26)
+
+#define NDR_NETR_LOGONSAMLOGONEX (0x27)
+
+#define NDR_NETR_DSRENUMERATEDOMAINTRUSTS (0x28)
+
+#define NDR_NETR_DSRDEREGISTERDNSHOSTRECORDS (0x29)
+
+#define NDR_NETR_SERVERTRUSTPASSWORDSGET (0x2a)
+
+#define NDR_NETR_DSRGETFORESTTRUSTINFORMATION (0x2b)
+
+#define NDR_NETR_GETFORESTTRUSTINFORMATION (0x2c)
+
+#define NDR_NETR_LOGONSAMLOGONWITHFLAGS (0x2d)
+
+#define NDR_NETR_NETRSERVERGETTRUSTINFO (0x2e)
+
+#define NDR_NETLOGON_CALL_COUNT (47)
+void ndr_print_netr_UasInfo(struct ndr_print *ndr, const char *name, const struct netr_UasInfo *r);
+void ndr_print_netr_UasLogoffInfo(struct ndr_print *ndr, const char *name, const struct netr_UasLogoffInfo *r);
+enum ndr_err_code ndr_push_netr_AcctLockStr(struct ndr_push *ndr, int ndr_flags, const struct netr_AcctLockStr *r);
+enum ndr_err_code ndr_pull_netr_AcctLockStr(struct ndr_pull *ndr, int ndr_flags, struct netr_AcctLockStr *r);
+void ndr_print_netr_AcctLockStr(struct ndr_print *ndr, const char *name, const struct netr_AcctLockStr *r);
+enum ndr_err_code ndr_push_netr_LogonParameterControl(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_netr_LogonParameterControl(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_netr_LogonParameterControl(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_netr_IdentityInfo(struct ndr_print *ndr, const char *name, const struct netr_IdentityInfo *r);
+void ndr_print_netr_PasswordInfo(struct ndr_print *ndr, const char *name, const struct netr_PasswordInfo *r);
+void ndr_print_netr_ChallengeResponse(struct ndr_print *ndr, const char *name, const struct netr_ChallengeResponse *r);
+void ndr_print_netr_NetworkInfo(struct ndr_print *ndr, const char *name, const struct netr_NetworkInfo *r);
+enum ndr_err_code ndr_push_netr_LogonInfo(struct ndr_push *ndr, int ndr_flags, const union netr_LogonInfo *r);
+enum ndr_err_code ndr_pull_netr_LogonInfo(struct ndr_pull *ndr, int ndr_flags, union netr_LogonInfo *r);
+void ndr_print_netr_LogonInfo(struct ndr_print *ndr, const char *name, const union netr_LogonInfo *r);
+enum ndr_err_code ndr_push_netr_UserSessionKey(struct ndr_push *ndr, int ndr_flags, const struct netr_UserSessionKey *r);
+enum ndr_err_code ndr_pull_netr_UserSessionKey(struct ndr_pull *ndr, int ndr_flags, struct netr_UserSessionKey *r);
+void ndr_print_netr_UserSessionKey(struct ndr_print *ndr, const char *name, const struct netr_UserSessionKey *r);
+enum ndr_err_code ndr_push_netr_LMSessionKey(struct ndr_push *ndr, int ndr_flags, const struct netr_LMSessionKey *r);
+enum ndr_err_code ndr_pull_netr_LMSessionKey(struct ndr_pull *ndr, int ndr_flags, struct netr_LMSessionKey *r);
+void ndr_print_netr_LMSessionKey(struct ndr_print *ndr, const char *name, const struct netr_LMSessionKey *r);
+enum ndr_err_code ndr_push_netr_UserFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_netr_UserFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_netr_UserFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_netr_SamBaseInfo(struct ndr_print *ndr, const char *name, const struct netr_SamBaseInfo *r);
+void ndr_print_netr_SamInfo2(struct ndr_print *ndr, const char *name, const struct netr_SamInfo2 *r);
+void ndr_print_netr_SidAttr(struct ndr_print *ndr, const char *name, const struct netr_SidAttr *r);
+enum ndr_err_code ndr_push_netr_SamInfo3(struct ndr_push *ndr, int ndr_flags, const struct netr_SamInfo3 *r);
+enum ndr_err_code ndr_pull_netr_SamInfo3(struct ndr_pull *ndr, int ndr_flags, struct netr_SamInfo3 *r);
+void ndr_print_netr_SamInfo3(struct ndr_print *ndr, const char *name, const struct netr_SamInfo3 *r);
+void ndr_print_netr_SamInfo6(struct ndr_print *ndr, const char *name, const struct netr_SamInfo6 *r);
+void ndr_print_netr_PacInfo(struct ndr_print *ndr, const char *name, const struct netr_PacInfo *r);
+enum ndr_err_code ndr_push_netr_Validation(struct ndr_push *ndr, int ndr_flags, const union netr_Validation *r);
+enum ndr_err_code ndr_pull_netr_Validation(struct ndr_pull *ndr, int ndr_flags, union netr_Validation *r);
+void ndr_print_netr_Validation(struct ndr_print *ndr, const char *name, const union netr_Validation *r);
+enum ndr_err_code ndr_push_netr_Credential(struct ndr_push *ndr, int ndr_flags, const struct netr_Credential *r);
+enum ndr_err_code ndr_pull_netr_Credential(struct ndr_pull *ndr, int ndr_flags, struct netr_Credential *r);
+void ndr_print_netr_Credential(struct ndr_print *ndr, const char *name, const struct netr_Credential *r);
+enum ndr_err_code ndr_push_netr_Authenticator(struct ndr_push *ndr, int ndr_flags, const struct netr_Authenticator *r);
+enum ndr_err_code ndr_pull_netr_Authenticator(struct ndr_pull *ndr, int ndr_flags, struct netr_Authenticator *r);
+void ndr_print_netr_Authenticator(struct ndr_print *ndr, const char *name, const struct netr_Authenticator *r);
+void ndr_print_netr_LogonLevel(struct ndr_print *ndr, const char *name, enum netr_LogonLevel r);
+void ndr_print_netr_DELTA_DELETE_USER(struct ndr_print *ndr, const char *name, const struct netr_DELTA_DELETE_USER *r);
+void ndr_print_netr_USER_KEY16(struct ndr_print *ndr, const char *name, const struct netr_USER_KEY16 *r);
+void ndr_print_netr_PasswordHistory(struct ndr_print *ndr, const char *name, const struct netr_PasswordHistory *r);
+void ndr_print_netr_USER_KEYS2(struct ndr_print *ndr, const char *name, const struct netr_USER_KEYS2 *r);
+void ndr_print_netr_USER_KEY_UNION(struct ndr_print *ndr, const char *name, const struct netr_USER_KEY_UNION *r);
+enum ndr_err_code ndr_push_netr_USER_KEYS(struct ndr_push *ndr, int ndr_flags, const struct netr_USER_KEYS *r);
+enum ndr_err_code ndr_pull_netr_USER_KEYS(struct ndr_pull *ndr, int ndr_flags, struct netr_USER_KEYS *r);
+void ndr_print_netr_USER_KEYS(struct ndr_print *ndr, const char *name, const struct netr_USER_KEYS *r);
+void ndr_print_netr_USER_PRIVATE_INFO(struct ndr_print *ndr, const char *name, const struct netr_USER_PRIVATE_INFO *r);
+void ndr_print_netr_DELTA_USER(struct ndr_print *ndr, const char *name, const struct netr_DELTA_USER *r);
+void ndr_print_netr_DELTA_DOMAIN(struct ndr_print *ndr, const char *name, const struct netr_DELTA_DOMAIN *r);
+void ndr_print_netr_DELTA_GROUP(struct ndr_print *ndr, const char *name, const struct netr_DELTA_GROUP *r);
+void ndr_print_netr_DELTA_RENAME(struct ndr_print *ndr, const char *name, const struct netr_DELTA_RENAME *r);
+void ndr_print_netr_DELTA_GROUP_MEMBER(struct ndr_print *ndr, const char *name, const struct netr_DELTA_GROUP_MEMBER *r);
+void ndr_print_netr_DELTA_ALIAS(struct ndr_print *ndr, const char *name, const struct netr_DELTA_ALIAS *r);
+void ndr_print_netr_DELTA_ALIAS_MEMBER(struct ndr_print *ndr, const char *name, const struct netr_DELTA_ALIAS_MEMBER *r);
+void ndr_print_netr_QUOTA_LIMITS(struct ndr_print *ndr, const char *name, const struct netr_QUOTA_LIMITS *r);
+void ndr_print_netr_DELTA_POLICY(struct ndr_print *ndr, const char *name, const struct netr_DELTA_POLICY *r);
+void ndr_print_netr_DELTA_TRUSTED_DOMAIN(struct ndr_print *ndr, const char *name, const struct netr_DELTA_TRUSTED_DOMAIN *r);
+void ndr_print_netr_DELTA_DELETE_TRUST(struct ndr_print *ndr, const char *name, const struct netr_DELTA_DELETE_TRUST *r);
+void ndr_print_netr_DELTA_ACCOUNT(struct ndr_print *ndr, const char *name, const struct netr_DELTA_ACCOUNT *r);
+void ndr_print_netr_DELTA_DELETE_ACCOUNT(struct ndr_print *ndr, const char *name, const struct netr_DELTA_DELETE_ACCOUNT *r);
+void ndr_print_netr_DELTA_DELETE_SECRET(struct ndr_print *ndr, const char *name, const struct netr_DELTA_DELETE_SECRET *r);
+void ndr_print_netr_CIPHER_VALUE(struct ndr_print *ndr, const char *name, const struct netr_CIPHER_VALUE *r);
+void ndr_print_netr_DELTA_SECRET(struct ndr_print *ndr, const char *name, const struct netr_DELTA_SECRET *r);
+void ndr_print_netr_DeltaEnum(struct ndr_print *ndr, const char *name, enum netr_DeltaEnum r);
+void ndr_print_netr_DELTA_UNION(struct ndr_print *ndr, const char *name, const union netr_DELTA_UNION *r);
+void ndr_print_netr_DELTA_ID_UNION(struct ndr_print *ndr, const char *name, const union netr_DELTA_ID_UNION *r);
+void ndr_print_netr_DELTA_ENUM(struct ndr_print *ndr, const char *name, const struct netr_DELTA_ENUM *r);
+void ndr_print_netr_DELTA_ENUM_ARRAY(struct ndr_print *ndr, const char *name, const struct netr_DELTA_ENUM_ARRAY *r);
+void ndr_print_netr_UAS_INFO_0(struct ndr_print *ndr, const char *name, const struct netr_UAS_INFO_0 *r);
+void ndr_print_netr_AccountBuffer(struct ndr_print *ndr, const char *name, const struct netr_AccountBuffer *r);
+void ndr_print_netr_InfoFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_netr_NETLOGON_INFO_1(struct ndr_print *ndr, const char *name, const struct netr_NETLOGON_INFO_1 *r);
+void ndr_print_netr_NETLOGON_INFO_2(struct ndr_print *ndr, const char *name, const struct netr_NETLOGON_INFO_2 *r);
+void ndr_print_netr_NETLOGON_INFO_3(struct ndr_print *ndr, const char *name, const struct netr_NETLOGON_INFO_3 *r);
+void ndr_print_netr_CONTROL_QUERY_INFORMATION(struct ndr_print *ndr, const char *name, const union netr_CONTROL_QUERY_INFORMATION *r);
+void ndr_print_netr_LogonControlCode(struct ndr_print *ndr, const char *name, enum netr_LogonControlCode r);
+void ndr_print_netr_CONTROL_DATA_INFORMATION(struct ndr_print *ndr, const char *name, const union netr_CONTROL_DATA_INFORMATION *r);
+void ndr_print_netr_NegotiateFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_netr_Blob(struct ndr_print *ndr, const char *name, const struct netr_Blob *r);
+void ndr_print_netr_DsRGetDCName_flags(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_netr_DsRGetDCNameInfo_AddressType(struct ndr_print *ndr, const char *name, enum netr_DsRGetDCNameInfo_AddressType r);
+void ndr_print_netr_DsR_DcFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+enum ndr_err_code ndr_push_netr_DsRGetDCNameInfo(struct ndr_push *ndr, int ndr_flags, const struct netr_DsRGetDCNameInfo *r);
+enum ndr_err_code ndr_pull_netr_DsRGetDCNameInfo(struct ndr_pull *ndr, int ndr_flags, struct netr_DsRGetDCNameInfo *r);
+void ndr_print_netr_DsRGetDCNameInfo(struct ndr_print *ndr, const char *name, const struct netr_DsRGetDCNameInfo *r);
+void ndr_print_netr_BinaryString(struct ndr_print *ndr, const char *name, const struct netr_BinaryString *r);
+void ndr_print_netr_DomainQuery1(struct ndr_print *ndr, const char *name, const struct netr_DomainQuery1 *r);
+void ndr_print_netr_DomainQuery(struct ndr_print *ndr, const char *name, const union netr_DomainQuery *r);
+void ndr_print_netr_DomainTrustInfo(struct ndr_print *ndr, const char *name, const struct netr_DomainTrustInfo *r);
+void ndr_print_netr_DomainInfo1(struct ndr_print *ndr, const char *name, const struct netr_DomainInfo1 *r);
+void ndr_print_netr_DomainInfo(struct ndr_print *ndr, const char *name, const union netr_DomainInfo *r);
+void ndr_print_netr_CryptPassword(struct ndr_print *ndr, const char *name, const struct netr_CryptPassword *r);
+void ndr_print_netr_DsRAddressToSitenamesWCtr(struct ndr_print *ndr, const char *name, const struct netr_DsRAddressToSitenamesWCtr *r);
+void ndr_print_netr_DsRAddress(struct ndr_print *ndr, const char *name, const struct netr_DsRAddress *r);
+void ndr_print_netr_TrustFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_netr_TrustType(struct ndr_print *ndr, const char *name, enum netr_TrustType r);
+void ndr_print_netr_TrustAttributes(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_netr_DomainTrust(struct ndr_print *ndr, const char *name, const struct netr_DomainTrust *r);
+void ndr_print_netr_DomainTrustList(struct ndr_print *ndr, const char *name, const struct netr_DomainTrustList *r);
+void ndr_print_netr_DsRAddressToSitenamesExWCtr(struct ndr_print *ndr, const char *name, const struct netr_DsRAddressToSitenamesExWCtr *r);
+void ndr_print_DcSitesCtr(struct ndr_print *ndr, const char *name, const struct DcSitesCtr *r);
+void ndr_print_netr_LogonUasLogon(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonUasLogon *r);
+void ndr_print_netr_LogonUasLogoff(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonUasLogoff *r);
+void ndr_print_netr_LogonSamLogon(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonSamLogon *r);
+void ndr_print_netr_LogonSamLogoff(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonSamLogoff *r);
+void ndr_print_netr_ServerReqChallenge(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerReqChallenge *r);
+void ndr_print_netr_ServerAuthenticate(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerAuthenticate *r);
+void ndr_print_netr_ServerPasswordSet(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerPasswordSet *r);
+void ndr_print_netr_DatabaseDeltas(struct ndr_print *ndr, const char *name, int flags, const struct netr_DatabaseDeltas *r);
+void ndr_print_netr_DatabaseSync(struct ndr_print *ndr, const char *name, int flags, const struct netr_DatabaseSync *r);
+void ndr_print_netr_AccountDeltas(struct ndr_print *ndr, const char *name, int flags, const struct netr_AccountDeltas *r);
+void ndr_print_netr_AccountSync(struct ndr_print *ndr, const char *name, int flags, const struct netr_AccountSync *r);
+void ndr_print_netr_GetDcName(struct ndr_print *ndr, const char *name, int flags, const struct netr_GetDcName *r);
+void ndr_print_netr_LogonControl(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonControl *r);
+void ndr_print_netr_GetAnyDCName(struct ndr_print *ndr, const char *name, int flags, const struct netr_GetAnyDCName *r);
+void ndr_print_netr_LogonControl2(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonControl2 *r);
+void ndr_print_netr_ServerAuthenticate2(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerAuthenticate2 *r);
+void ndr_print_netr_DatabaseSync2(struct ndr_print *ndr, const char *name, int flags, const struct netr_DatabaseSync2 *r);
+void ndr_print_netr_DatabaseRedo(struct ndr_print *ndr, const char *name, int flags, const struct netr_DatabaseRedo *r);
+void ndr_print_netr_LogonControl2Ex(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonControl2Ex *r);
+void ndr_print_netr_NetrEnumerateTrustedDomains(struct ndr_print *ndr, const char *name, int flags, const struct netr_NetrEnumerateTrustedDomains *r);
+void ndr_print_netr_DsRGetDCName(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRGetDCName *r);
+void ndr_print_netr_NETRLOGONDUMMYROUTINE1(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONDUMMYROUTINE1 *r);
+void ndr_print_netr_NETRLOGONSETSERVICEBITS(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONSETSERVICEBITS *r);
+void ndr_print_netr_LogonGetTrustRid(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonGetTrustRid *r);
+void ndr_print_netr_NETRLOGONCOMPUTESERVERDIGEST(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONCOMPUTESERVERDIGEST *r);
+void ndr_print_netr_NETRLOGONCOMPUTECLIENTDIGEST(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONCOMPUTECLIENTDIGEST *r);
+void ndr_print_netr_ServerAuthenticate3(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerAuthenticate3 *r);
+void ndr_print_netr_DsRGetDCNameEx(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRGetDCNameEx *r);
+void ndr_print_netr_DsRGetSiteName(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRGetSiteName *r);
+void ndr_print_netr_LogonGetDomainInfo(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonGetDomainInfo *r);
+void ndr_print_netr_ServerPasswordSet2(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerPasswordSet2 *r);
+void ndr_print_netr_ServerPasswordGet(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerPasswordGet *r);
+void ndr_print_netr_NETRLOGONSENDTOSAM(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONSENDTOSAM *r);
+void ndr_print_netr_DsRAddressToSitenamesW(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRAddressToSitenamesW *r);
+void ndr_print_netr_DsRGetDCNameEx2(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRGetDCNameEx2 *r);
+void ndr_print_netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN *r);
+void ndr_print_netr_NetrEnumerateTrustedDomainsEx(struct ndr_print *ndr, const char *name, int flags, const struct netr_NetrEnumerateTrustedDomainsEx *r);
+void ndr_print_netr_DsRAddressToSitenamesExW(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRAddressToSitenamesExW *r);
+void ndr_print_netr_DsrGetDcSiteCoverageW(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsrGetDcSiteCoverageW *r);
+void ndr_print_netr_LogonSamLogonEx(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonSamLogonEx *r);
+void ndr_print_netr_DsrEnumerateDomainTrusts(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsrEnumerateDomainTrusts *r);
+void ndr_print_netr_DsrDeregisterDNSHostRecords(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsrDeregisterDNSHostRecords *r);
+void ndr_print_netr_ServerTrustPasswordsGet(struct ndr_print *ndr, const char *name, int flags, const struct netr_ServerTrustPasswordsGet *r);
+void ndr_print_netr_DsRGetForestTrustInformation(struct ndr_print *ndr, const char *name, int flags, const struct netr_DsRGetForestTrustInformation *r);
+void ndr_print_netr_GetForestTrustInformation(struct ndr_print *ndr, const char *name, int flags, const struct netr_GetForestTrustInformation *r);
+void ndr_print_netr_LogonSamLogonWithFlags(struct ndr_print *ndr, const char *name, int flags, const struct netr_LogonSamLogonWithFlags *r);
+void ndr_print_netr_NETRSERVERGETTRUSTINFO(struct ndr_print *ndr, const char *name, int flags, const struct netr_NETRSERVERGETTRUSTINFO *r);
+#endif /* _HEADER_NDR_netlogon */
diff --git a/source3/librpc/gen_ndr/ndr_notify.c b/source3/librpc/gen_ndr/ndr_notify.c
new file mode 100644
index 0000000000..00ba8bc293
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_notify.c
@@ -0,0 +1,240 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_notify.h"
+
+_PUBLIC_ enum ndr_err_code ndr_push_notify_entry(struct ndr_push *ndr, int ndr_flags, const struct notify_entry *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_server_id(ndr, NDR_SCALARS, &r->server));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->filter));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->subdir_filter));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->path));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->path_len));
+ NDR_CHECK(ndr_push_pointer(ndr, NDR_SCALARS, r->private_data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_server_id(ndr, NDR_BUFFERS, &r->server));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_notify_entry(struct ndr_pull *ndr, int ndr_flags, struct notify_entry *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_server_id(ndr, NDR_SCALARS, &r->server));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->filter));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->subdir_filter));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->path));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->path_len));
+ NDR_CHECK(ndr_pull_pointer(ndr, NDR_SCALARS, &r->private_data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_server_id(ndr, NDR_BUFFERS, &r->server));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_notify_entry(struct ndr_print *ndr, const char *name, const struct notify_entry *r)
+{
+ ndr_print_struct(ndr, name, "notify_entry");
+ ndr->depth++;
+ ndr_print_server_id(ndr, "server", &r->server);
+ ndr_print_uint32(ndr, "filter", r->filter);
+ ndr_print_uint32(ndr, "subdir_filter", r->subdir_filter);
+ ndr_print_string(ndr, "path", r->path);
+ ndr_print_uint32(ndr, "path_len", r->path_len);
+ ndr_print_pointer(ndr, "private_data", r->private_data);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_notify_depth(struct ndr_push *ndr, int ndr_flags, const struct notify_depth *r)
+{
+ uint32_t cntr_entries_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_mask));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_mask_subdir));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_entries));
+ for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; cntr_entries_0++) {
+ NDR_CHECK(ndr_push_notify_entry(ndr, NDR_SCALARS, &r->entries[cntr_entries_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; cntr_entries_0++) {
+ NDR_CHECK(ndr_push_notify_entry(ndr, NDR_BUFFERS, &r->entries[cntr_entries_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_notify_depth(struct ndr_pull *ndr, int ndr_flags, struct notify_depth *r)
+{
+ uint32_t cntr_entries_0;
+ TALLOC_CTX *_mem_save_entries_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_mask));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_mask_subdir));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_entries));
+ NDR_PULL_ALLOC_N(ndr, r->entries, r->num_entries);
+ _mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+ for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; cntr_entries_0++) {
+ NDR_CHECK(ndr_pull_notify_entry(ndr, NDR_SCALARS, &r->entries[cntr_entries_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+ for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; cntr_entries_0++) {
+ NDR_CHECK(ndr_pull_notify_entry(ndr, NDR_BUFFERS, &r->entries[cntr_entries_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_notify_depth(struct ndr_print *ndr, const char *name, const struct notify_depth *r)
+{
+ uint32_t cntr_entries_0;
+ ndr_print_struct(ndr, name, "notify_depth");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "max_mask", r->max_mask);
+ ndr_print_uint32(ndr, "max_mask_subdir", r->max_mask_subdir);
+ ndr_print_uint32(ndr, "num_entries", r->num_entries);
+ ndr->print(ndr, "%s: ARRAY(%d)", "entries", (int)r->num_entries);
+ ndr->depth++;
+ for (cntr_entries_0=0;cntr_entries_0<r->num_entries;cntr_entries_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_entries_0) != -1) {
+ ndr_print_notify_entry(ndr, "entries", &r->entries[cntr_entries_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_notify_array(struct ndr_push *ndr, int ndr_flags, const struct notify_array *r)
+{
+ uint32_t cntr_depth_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_depths));
+ for (cntr_depth_0 = 0; cntr_depth_0 < r->num_depths; cntr_depth_0++) {
+ NDR_CHECK(ndr_push_notify_depth(ndr, NDR_SCALARS, &r->depth[cntr_depth_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ for (cntr_depth_0 = 0; cntr_depth_0 < r->num_depths; cntr_depth_0++) {
+ NDR_CHECK(ndr_push_notify_depth(ndr, NDR_BUFFERS, &r->depth[cntr_depth_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_notify_array(struct ndr_pull *ndr, int ndr_flags, struct notify_array *r)
+{
+ uint32_t cntr_depth_0;
+ TALLOC_CTX *_mem_save_depth_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_depths));
+ NDR_PULL_ALLOC_N(ndr, r->depth, r->num_depths);
+ _mem_save_depth_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->depth, 0);
+ for (cntr_depth_0 = 0; cntr_depth_0 < r->num_depths; cntr_depth_0++) {
+ NDR_CHECK(ndr_pull_notify_depth(ndr, NDR_SCALARS, &r->depth[cntr_depth_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_depth_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_depth_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->depth, 0);
+ for (cntr_depth_0 = 0; cntr_depth_0 < r->num_depths; cntr_depth_0++) {
+ NDR_CHECK(ndr_pull_notify_depth(ndr, NDR_BUFFERS, &r->depth[cntr_depth_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_depth_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_notify_array(struct ndr_print *ndr, const char *name, const struct notify_array *r)
+{
+ uint32_t cntr_depth_0;
+ ndr_print_struct(ndr, name, "notify_array");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_depths", r->num_depths);
+ ndr->print(ndr, "%s: ARRAY(%d)", "depth", (int)r->num_depths);
+ ndr->depth++;
+ for (cntr_depth_0=0;cntr_depth_0<r->num_depths;cntr_depth_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_depth_0) != -1) {
+ ndr_print_notify_depth(ndr, "depth", &r->depth[cntr_depth_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_notify_event(struct ndr_push *ndr, int ndr_flags, const struct notify_event *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->action));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->path));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_push_pointer(ndr, NDR_SCALARS, r->private_data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_notify_event(struct ndr_pull *ndr, int ndr_flags, struct notify_event *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->action));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->path));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_pull_pointer(ndr, NDR_SCALARS, &r->private_data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_notify_event(struct ndr_print *ndr, const char *name, const struct notify_event *r)
+{
+ ndr_print_struct(ndr, name, "notify_event");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "action", r->action);
+ ndr_print_string(ndr, "path", r->path);
+ ndr_print_pointer(ndr, "private_data", r->private_data);
+ ndr->depth--;
+}
+
diff --git a/source3/librpc/gen_ndr/ndr_notify.h b/source3/librpc/gen_ndr/ndr_notify.h
new file mode 100644
index 0000000000..23d3d3fc0a
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_notify.h
@@ -0,0 +1,20 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/notify.h"
+
+#ifndef _HEADER_NDR_notify
+#define _HEADER_NDR_notify
+
+#define NDR_NOTIFY_CALL_COUNT (0)
+enum ndr_err_code ndr_push_notify_entry(struct ndr_push *ndr, int ndr_flags, const struct notify_entry *r);
+enum ndr_err_code ndr_pull_notify_entry(struct ndr_pull *ndr, int ndr_flags, struct notify_entry *r);
+void ndr_print_notify_entry(struct ndr_print *ndr, const char *name, const struct notify_entry *r);
+void ndr_print_notify_depth(struct ndr_print *ndr, const char *name, const struct notify_depth *r);
+enum ndr_err_code ndr_push_notify_array(struct ndr_push *ndr, int ndr_flags, const struct notify_array *r);
+enum ndr_err_code ndr_pull_notify_array(struct ndr_pull *ndr, int ndr_flags, struct notify_array *r);
+void ndr_print_notify_array(struct ndr_print *ndr, const char *name, const struct notify_array *r);
+enum ndr_err_code ndr_push_notify_event(struct ndr_push *ndr, int ndr_flags, const struct notify_event *r);
+enum ndr_err_code ndr_pull_notify_event(struct ndr_pull *ndr, int ndr_flags, struct notify_event *r);
+void ndr_print_notify_event(struct ndr_print *ndr, const char *name, const struct notify_event *r);
+#endif /* _HEADER_NDR_notify */
diff --git a/source3/librpc/gen_ndr/ndr_ntsvcs.c b/source3/librpc/gen_ndr/ndr_ntsvcs.c
new file mode 100644
index 0000000000..62acf474ae
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_ntsvcs.c
@@ -0,0 +1,3769 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_ntsvcs.h"
+
+static enum ndr_err_code ndr_push_PNP_HwProfInfo(struct ndr_push *ndr, int ndr_flags, const struct PNP_HwProfInfo *r)
+{
+ uint32_t cntr_unknown2_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown1));
+ for (cntr_unknown2_0 = 0; cntr_unknown2_0 < 160; cntr_unknown2_0++) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->unknown2[cntr_unknown2_0]));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown3));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_HwProfInfo(struct ndr_pull *ndr, int ndr_flags, struct PNP_HwProfInfo *r)
+{
+ uint32_t cntr_unknown2_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ for (cntr_unknown2_0 = 0; cntr_unknown2_0 < 160; cntr_unknown2_0++) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->unknown2[cntr_unknown2_0]));
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown3));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_HwProfInfo(struct ndr_print *ndr, const char *name, const struct PNP_HwProfInfo *r)
+{
+ uint32_t cntr_unknown2_0;
+ ndr_print_struct(ndr, name, "PNP_HwProfInfo");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "unknown1", r->unknown1);
+ ndr->print(ndr, "%s: ARRAY(%d)", "unknown2", (int)160);
+ ndr->depth++;
+ for (cntr_unknown2_0=0;cntr_unknown2_0<160;cntr_unknown2_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_unknown2_0) != -1) {
+ ndr_print_uint16(ndr, "unknown2", r->unknown2[cntr_unknown2_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown3", r->unknown3);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_Disconnect(struct ndr_push *ndr, int flags, const struct PNP_Disconnect *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_Disconnect(struct ndr_pull *ndr, int flags, struct PNP_Disconnect *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_Disconnect(struct ndr_print *ndr, const char *name, int flags, const struct PNP_Disconnect *r)
+{
+ ndr_print_struct(ndr, name, "PNP_Disconnect");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_Disconnect");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_Disconnect");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_Connect(struct ndr_push *ndr, int flags, const struct PNP_Connect *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_Connect(struct ndr_pull *ndr, int flags, struct PNP_Connect *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_Connect(struct ndr_print *ndr, const char *name, int flags, const struct PNP_Connect *r)
+{
+ ndr_print_struct(ndr, name, "PNP_Connect");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_Connect");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_Connect");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetVersion(struct ndr_push *ndr, int flags, const struct PNP_GetVersion *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.version == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->out.version));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetVersion(struct ndr_pull *ndr, int flags, struct PNP_GetVersion *r)
+{
+ TALLOC_CTX *_mem_save_version_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_PULL_ALLOC(ndr, r->out.version);
+ ZERO_STRUCTP(r->out.version);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.version);
+ }
+ _mem_save_version_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.version, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->out.version));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_version_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetVersion(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetVersion *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetVersion");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetVersion");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetVersion");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "version", r->out.version);
+ ndr->depth++;
+ ndr_print_uint16(ndr, "version", *r->out.version);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetGlobalState(struct ndr_push *ndr, int flags, const struct PNP_GetGlobalState *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetGlobalState(struct ndr_pull *ndr, int flags, struct PNP_GetGlobalState *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetGlobalState(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetGlobalState *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetGlobalState");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetGlobalState");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetGlobalState");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_InitDetection(struct ndr_push *ndr, int flags, const struct PNP_InitDetection *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_InitDetection(struct ndr_pull *ndr, int flags, struct PNP_InitDetection *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_InitDetection(struct ndr_print *ndr, const char *name, int flags, const struct PNP_InitDetection *r)
+{
+ ndr_print_struct(ndr, name, "PNP_InitDetection");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_InitDetection");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_InitDetection");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_ReportLogOn(struct ndr_push *ndr, int flags, const struct PNP_ReportLogOn *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_ReportLogOn(struct ndr_pull *ndr, int flags, struct PNP_ReportLogOn *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_ReportLogOn(struct ndr_print *ndr, const char *name, int flags, const struct PNP_ReportLogOn *r)
+{
+ ndr_print_struct(ndr, name, "PNP_ReportLogOn");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_ReportLogOn");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_ReportLogOn");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_ValidateDeviceInstance(struct ndr_push *ndr, int flags, const struct PNP_ValidateDeviceInstance *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.devicepath == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.devicepath, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.devicepath, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.devicepath, ndr_charset_length(r->in.devicepath, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_ValidateDeviceInstance(struct ndr_pull *ndr, int flags, struct PNP_ValidateDeviceInstance *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.devicepath));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.devicepath));
+ if (ndr_get_array_length(ndr, &r->in.devicepath) > ndr_get_array_size(ndr, &r->in.devicepath)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.devicepath), ndr_get_array_length(ndr, &r->in.devicepath));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.devicepath), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.devicepath, ndr_get_array_length(ndr, &r->in.devicepath), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_ValidateDeviceInstance(struct ndr_print *ndr, const char *name, int flags, const struct PNP_ValidateDeviceInstance *r)
+{
+ ndr_print_struct(ndr, name, "PNP_ValidateDeviceInstance");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_ValidateDeviceInstance");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "devicepath", r->in.devicepath);
+ ndr->depth++;
+ ndr_print_string(ndr, "devicepath", r->in.devicepath);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_ValidateDeviceInstance");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetRootDeviceInstance(struct ndr_push *ndr, int flags, const struct PNP_GetRootDeviceInstance *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetRootDeviceInstance(struct ndr_pull *ndr, int flags, struct PNP_GetRootDeviceInstance *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetRootDeviceInstance(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetRootDeviceInstance *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetRootDeviceInstance");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetRootDeviceInstance");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetRootDeviceInstance");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetRelatedDeviceInstance(struct ndr_push *ndr, int flags, const struct PNP_GetRelatedDeviceInstance *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetRelatedDeviceInstance(struct ndr_pull *ndr, int flags, struct PNP_GetRelatedDeviceInstance *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetRelatedDeviceInstance(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetRelatedDeviceInstance *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetRelatedDeviceInstance");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetRelatedDeviceInstance");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetRelatedDeviceInstance");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_EnumerateSubKeys(struct ndr_push *ndr, int flags, const struct PNP_EnumerateSubKeys *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_EnumerateSubKeys(struct ndr_pull *ndr, int flags, struct PNP_EnumerateSubKeys *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_EnumerateSubKeys(struct ndr_print *ndr, const char *name, int flags, const struct PNP_EnumerateSubKeys *r)
+{
+ ndr_print_struct(ndr, name, "PNP_EnumerateSubKeys");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_EnumerateSubKeys");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_EnumerateSubKeys");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetDeviceList(struct ndr_push *ndr, int flags, const struct PNP_GetDeviceList *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetDeviceList(struct ndr_pull *ndr, int flags, struct PNP_GetDeviceList *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetDeviceList(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetDeviceList *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetDeviceList");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetDeviceList");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetDeviceList");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetDeviceListSize(struct ndr_push *ndr, int flags, const struct PNP_GetDeviceListSize *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.devicename));
+ if (r->in.devicename) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.devicename, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.devicename, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.devicename, ndr_charset_length(r->in.devicename, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.size == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.size));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetDeviceListSize(struct ndr_pull *ndr, int flags, struct PNP_GetDeviceListSize *r)
+{
+ uint32_t _ptr_devicename;
+ TALLOC_CTX *_mem_save_devicename_0;
+ TALLOC_CTX *_mem_save_size_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_devicename));
+ if (_ptr_devicename) {
+ NDR_PULL_ALLOC(ndr, r->in.devicename);
+ } else {
+ r->in.devicename = NULL;
+ }
+ if (r->in.devicename) {
+ _mem_save_devicename_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.devicename, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.devicename));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.devicename));
+ if (ndr_get_array_length(ndr, &r->in.devicename) > ndr_get_array_size(ndr, &r->in.devicename)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.devicename), ndr_get_array_length(ndr, &r->in.devicename));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.devicename), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.devicename, ndr_get_array_length(ndr, &r->in.devicename), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_devicename_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.flags));
+ NDR_PULL_ALLOC(ndr, r->out.size);
+ ZERO_STRUCTP(r->out.size);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.size);
+ }
+ _mem_save_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.size, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_size_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetDeviceListSize(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetDeviceListSize *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetDeviceListSize");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetDeviceListSize");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "devicename", r->in.devicename);
+ ndr->depth++;
+ if (r->in.devicename) {
+ ndr_print_string(ndr, "devicename", r->in.devicename);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetDeviceListSize");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "size", r->out.size);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "size", *r->out.size);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetDepth(struct ndr_push *ndr, int flags, const struct PNP_GetDepth *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetDepth(struct ndr_pull *ndr, int flags, struct PNP_GetDepth *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetDepth(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetDepth *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetDepth");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetDepth");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetDepth");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetDeviceRegProp(struct ndr_push *ndr, int flags, const struct PNP_GetDeviceRegProp *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.devicepath == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.devicepath, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.devicepath, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.devicepath, ndr_charset_length(r->in.devicepath, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.property));
+ if (r->in.unknown1 == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.unknown1));
+ if (r->in.buffer_size == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.buffer_size));
+ if (r->in.needed == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.needed));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown3));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.unknown1 == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.unknown1));
+ if (r->out.buffer == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.buffer_size));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.buffer_size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.buffer, *r->out.buffer_size));
+ if (r->out.buffer_size == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.buffer_size));
+ if (r->out.needed == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.needed));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetDeviceRegProp(struct ndr_pull *ndr, int flags, struct PNP_GetDeviceRegProp *r)
+{
+ TALLOC_CTX *_mem_save_unknown1_0;
+ TALLOC_CTX *_mem_save_buffer_size_0;
+ TALLOC_CTX *_mem_save_needed_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.devicepath));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.devicepath));
+ if (ndr_get_array_length(ndr, &r->in.devicepath) > ndr_get_array_size(ndr, &r->in.devicepath)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.devicepath), ndr_get_array_length(ndr, &r->in.devicepath));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.devicepath), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.devicepath, ndr_get_array_length(ndr, &r->in.devicepath), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.property));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.unknown1);
+ }
+ _mem_save_unknown1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.unknown1, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.unknown1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown1_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.buffer_size);
+ }
+ _mem_save_buffer_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.buffer_size, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.buffer_size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_buffer_size_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.needed);
+ }
+ _mem_save_needed_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.needed, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.needed));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_needed_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown3));
+ NDR_PULL_ALLOC(ndr, r->out.unknown1);
+ *r->out.unknown1 = *r->in.unknown1;
+ NDR_PULL_ALLOC_N(ndr, r->out.buffer, *r->in.buffer_size);
+ memset(r->out.buffer, 0, (*r->in.buffer_size) * sizeof(*r->out.buffer));
+ NDR_PULL_ALLOC(ndr, r->out.buffer_size);
+ *r->out.buffer_size = *r->in.buffer_size;
+ NDR_PULL_ALLOC(ndr, r->out.needed);
+ *r->out.needed = *r->in.needed;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.unknown1);
+ }
+ _mem_save_unknown1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.unknown1, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.unknown1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown1_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->out.buffer));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->out.buffer));
+ if (ndr_get_array_length(ndr, &r->out.buffer) > ndr_get_array_size(ndr, &r->out.buffer)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->out.buffer), ndr_get_array_length(ndr, &r->out.buffer));
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC_N(ndr, r->out.buffer, ndr_get_array_size(ndr, &r->out.buffer));
+ }
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.buffer, ndr_get_array_length(ndr, &r->out.buffer)));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.buffer_size);
+ }
+ _mem_save_buffer_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.buffer_size, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.buffer_size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_buffer_size_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.needed);
+ }
+ _mem_save_needed_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.needed, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.needed));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_needed_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ if (r->out.buffer) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->out.buffer, *r->out.buffer_size));
+ }
+ if (r->out.buffer) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->out.buffer, *r->out.buffer_size));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetDeviceRegProp(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetDeviceRegProp *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetDeviceRegProp");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetDeviceRegProp");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "devicepath", r->in.devicepath);
+ ndr->depth++;
+ ndr_print_string(ndr, "devicepath", r->in.devicepath);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "property", r->in.property);
+ ndr_print_ptr(ndr, "unknown1", r->in.unknown1);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "unknown1", *r->in.unknown1);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "buffer_size", r->in.buffer_size);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "buffer_size", *r->in.buffer_size);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "needed", r->in.needed);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "needed", *r->in.needed);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown3", r->in.unknown3);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetDeviceRegProp");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "unknown1", r->out.unknown1);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "unknown1", *r->out.unknown1);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "buffer", r->out.buffer, *r->out.buffer_size);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "buffer_size", r->out.buffer_size);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "buffer_size", *r->out.buffer_size);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "needed", r->out.needed);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "needed", *r->out.needed);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_SetDeviceRegProp(struct ndr_push *ndr, int flags, const struct PNP_SetDeviceRegProp *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_SetDeviceRegProp(struct ndr_pull *ndr, int flags, struct PNP_SetDeviceRegProp *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_SetDeviceRegProp(struct ndr_print *ndr, const char *name, int flags, const struct PNP_SetDeviceRegProp *r)
+{
+ ndr_print_struct(ndr, name, "PNP_SetDeviceRegProp");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_SetDeviceRegProp");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_SetDeviceRegProp");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetClassInstance(struct ndr_push *ndr, int flags, const struct PNP_GetClassInstance *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetClassInstance(struct ndr_pull *ndr, int flags, struct PNP_GetClassInstance *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetClassInstance(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetClassInstance *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetClassInstance");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetClassInstance");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetClassInstance");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_CreateKey(struct ndr_push *ndr, int flags, const struct PNP_CreateKey *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_CreateKey(struct ndr_pull *ndr, int flags, struct PNP_CreateKey *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_CreateKey(struct ndr_print *ndr, const char *name, int flags, const struct PNP_CreateKey *r)
+{
+ ndr_print_struct(ndr, name, "PNP_CreateKey");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_CreateKey");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_CreateKey");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_DeleteRegistryKey(struct ndr_push *ndr, int flags, const struct PNP_DeleteRegistryKey *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_DeleteRegistryKey(struct ndr_pull *ndr, int flags, struct PNP_DeleteRegistryKey *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_DeleteRegistryKey(struct ndr_print *ndr, const char *name, int flags, const struct PNP_DeleteRegistryKey *r)
+{
+ ndr_print_struct(ndr, name, "PNP_DeleteRegistryKey");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_DeleteRegistryKey");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_DeleteRegistryKey");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetClassCount(struct ndr_push *ndr, int flags, const struct PNP_GetClassCount *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetClassCount(struct ndr_pull *ndr, int flags, struct PNP_GetClassCount *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetClassCount(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetClassCount *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetClassCount");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetClassCount");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetClassCount");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetClassName(struct ndr_push *ndr, int flags, const struct PNP_GetClassName *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetClassName(struct ndr_pull *ndr, int flags, struct PNP_GetClassName *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetClassName(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetClassName *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetClassName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetClassName");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetClassName");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_DeleteClassKey(struct ndr_push *ndr, int flags, const struct PNP_DeleteClassKey *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_DeleteClassKey(struct ndr_pull *ndr, int flags, struct PNP_DeleteClassKey *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_DeleteClassKey(struct ndr_print *ndr, const char *name, int flags, const struct PNP_DeleteClassKey *r)
+{
+ ndr_print_struct(ndr, name, "PNP_DeleteClassKey");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_DeleteClassKey");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_DeleteClassKey");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetInterfaceDeviceAlias(struct ndr_push *ndr, int flags, const struct PNP_GetInterfaceDeviceAlias *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetInterfaceDeviceAlias(struct ndr_pull *ndr, int flags, struct PNP_GetInterfaceDeviceAlias *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetInterfaceDeviceAlias(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetInterfaceDeviceAlias *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetInterfaceDeviceAlias");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetInterfaceDeviceAlias");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetInterfaceDeviceAlias");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetInterfaceDeviceList(struct ndr_push *ndr, int flags, const struct PNP_GetInterfaceDeviceList *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetInterfaceDeviceList(struct ndr_pull *ndr, int flags, struct PNP_GetInterfaceDeviceList *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetInterfaceDeviceList(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetInterfaceDeviceList *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetInterfaceDeviceList");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetInterfaceDeviceList");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetInterfaceDeviceList");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetInterfaceDeviceListSize(struct ndr_push *ndr, int flags, const struct PNP_GetInterfaceDeviceListSize *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetInterfaceDeviceListSize(struct ndr_pull *ndr, int flags, struct PNP_GetInterfaceDeviceListSize *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetInterfaceDeviceListSize(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetInterfaceDeviceListSize *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetInterfaceDeviceListSize");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetInterfaceDeviceListSize");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetInterfaceDeviceListSize");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_RegisterDeviceClassAssociation(struct ndr_push *ndr, int flags, const struct PNP_RegisterDeviceClassAssociation *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_RegisterDeviceClassAssociation(struct ndr_pull *ndr, int flags, struct PNP_RegisterDeviceClassAssociation *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_RegisterDeviceClassAssociation(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RegisterDeviceClassAssociation *r)
+{
+ ndr_print_struct(ndr, name, "PNP_RegisterDeviceClassAssociation");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_RegisterDeviceClassAssociation");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_RegisterDeviceClassAssociation");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_UnregisterDeviceClassAssociation(struct ndr_push *ndr, int flags, const struct PNP_UnregisterDeviceClassAssociation *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_UnregisterDeviceClassAssociation(struct ndr_pull *ndr, int flags, struct PNP_UnregisterDeviceClassAssociation *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_UnregisterDeviceClassAssociation(struct ndr_print *ndr, const char *name, int flags, const struct PNP_UnregisterDeviceClassAssociation *r)
+{
+ ndr_print_struct(ndr, name, "PNP_UnregisterDeviceClassAssociation");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_UnregisterDeviceClassAssociation");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_UnregisterDeviceClassAssociation");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetClassRegProp(struct ndr_push *ndr, int flags, const struct PNP_GetClassRegProp *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetClassRegProp(struct ndr_pull *ndr, int flags, struct PNP_GetClassRegProp *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetClassRegProp(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetClassRegProp *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetClassRegProp");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetClassRegProp");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetClassRegProp");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_SetClassRegProp(struct ndr_push *ndr, int flags, const struct PNP_SetClassRegProp *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_SetClassRegProp(struct ndr_pull *ndr, int flags, struct PNP_SetClassRegProp *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_SetClassRegProp(struct ndr_print *ndr, const char *name, int flags, const struct PNP_SetClassRegProp *r)
+{
+ ndr_print_struct(ndr, name, "PNP_SetClassRegProp");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_SetClassRegProp");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_SetClassRegProp");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_CreateDevInst(struct ndr_push *ndr, int flags, const struct PNP_CreateDevInst *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_CreateDevInst(struct ndr_pull *ndr, int flags, struct PNP_CreateDevInst *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_CreateDevInst(struct ndr_print *ndr, const char *name, int flags, const struct PNP_CreateDevInst *r)
+{
+ ndr_print_struct(ndr, name, "PNP_CreateDevInst");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_CreateDevInst");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_CreateDevInst");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_DeviceInstanceAction(struct ndr_push *ndr, int flags, const struct PNP_DeviceInstanceAction *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_DeviceInstanceAction(struct ndr_pull *ndr, int flags, struct PNP_DeviceInstanceAction *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_DeviceInstanceAction(struct ndr_print *ndr, const char *name, int flags, const struct PNP_DeviceInstanceAction *r)
+{
+ ndr_print_struct(ndr, name, "PNP_DeviceInstanceAction");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_DeviceInstanceAction");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_DeviceInstanceAction");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetDeviceStatus(struct ndr_push *ndr, int flags, const struct PNP_GetDeviceStatus *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetDeviceStatus(struct ndr_pull *ndr, int flags, struct PNP_GetDeviceStatus *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetDeviceStatus(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetDeviceStatus *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetDeviceStatus");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetDeviceStatus");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetDeviceStatus");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_SetDeviceProblem(struct ndr_push *ndr, int flags, const struct PNP_SetDeviceProblem *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_SetDeviceProblem(struct ndr_pull *ndr, int flags, struct PNP_SetDeviceProblem *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_SetDeviceProblem(struct ndr_print *ndr, const char *name, int flags, const struct PNP_SetDeviceProblem *r)
+{
+ ndr_print_struct(ndr, name, "PNP_SetDeviceProblem");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_SetDeviceProblem");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_SetDeviceProblem");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_DisableDevInst(struct ndr_push *ndr, int flags, const struct PNP_DisableDevInst *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_DisableDevInst(struct ndr_pull *ndr, int flags, struct PNP_DisableDevInst *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_DisableDevInst(struct ndr_print *ndr, const char *name, int flags, const struct PNP_DisableDevInst *r)
+{
+ ndr_print_struct(ndr, name, "PNP_DisableDevInst");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_DisableDevInst");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_DisableDevInst");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_UninstallDevInst(struct ndr_push *ndr, int flags, const struct PNP_UninstallDevInst *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_UninstallDevInst(struct ndr_pull *ndr, int flags, struct PNP_UninstallDevInst *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_UninstallDevInst(struct ndr_print *ndr, const char *name, int flags, const struct PNP_UninstallDevInst *r)
+{
+ ndr_print_struct(ndr, name, "PNP_UninstallDevInst");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_UninstallDevInst");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_UninstallDevInst");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_AddID(struct ndr_push *ndr, int flags, const struct PNP_AddID *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_AddID(struct ndr_pull *ndr, int flags, struct PNP_AddID *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_AddID(struct ndr_print *ndr, const char *name, int flags, const struct PNP_AddID *r)
+{
+ ndr_print_struct(ndr, name, "PNP_AddID");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_AddID");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_AddID");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_RegisterDriver(struct ndr_push *ndr, int flags, const struct PNP_RegisterDriver *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_RegisterDriver(struct ndr_pull *ndr, int flags, struct PNP_RegisterDriver *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_RegisterDriver(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RegisterDriver *r)
+{
+ ndr_print_struct(ndr, name, "PNP_RegisterDriver");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_RegisterDriver");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_RegisterDriver");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_QueryRemove(struct ndr_push *ndr, int flags, const struct PNP_QueryRemove *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_QueryRemove(struct ndr_pull *ndr, int flags, struct PNP_QueryRemove *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_QueryRemove(struct ndr_print *ndr, const char *name, int flags, const struct PNP_QueryRemove *r)
+{
+ ndr_print_struct(ndr, name, "PNP_QueryRemove");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_QueryRemove");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_QueryRemove");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_RequestDeviceEject(struct ndr_push *ndr, int flags, const struct PNP_RequestDeviceEject *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_RequestDeviceEject(struct ndr_pull *ndr, int flags, struct PNP_RequestDeviceEject *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_RequestDeviceEject(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RequestDeviceEject *r)
+{
+ ndr_print_struct(ndr, name, "PNP_RequestDeviceEject");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_RequestDeviceEject");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_RequestDeviceEject");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_IsDockStationPresent(struct ndr_push *ndr, int flags, const struct PNP_IsDockStationPresent *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_IsDockStationPresent(struct ndr_pull *ndr, int flags, struct PNP_IsDockStationPresent *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_IsDockStationPresent(struct ndr_print *ndr, const char *name, int flags, const struct PNP_IsDockStationPresent *r)
+{
+ ndr_print_struct(ndr, name, "PNP_IsDockStationPresent");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_IsDockStationPresent");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_IsDockStationPresent");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_RequestEjectPC(struct ndr_push *ndr, int flags, const struct PNP_RequestEjectPC *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_RequestEjectPC(struct ndr_pull *ndr, int flags, struct PNP_RequestEjectPC *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_RequestEjectPC(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RequestEjectPC *r)
+{
+ ndr_print_struct(ndr, name, "PNP_RequestEjectPC");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_RequestEjectPC");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_RequestEjectPC");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_HwProfFlags(struct ndr_push *ndr, int flags, const struct PNP_HwProfFlags *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown1));
+ if (r->in.devicepath == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.devicepath, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.devicepath, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.devicepath, ndr_charset_length(r->in.devicepath, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown2));
+ if (r->in.unknown3 == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.unknown3));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.unknown4));
+ if (r->in.unknown4) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.unknown4));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.unknown5));
+ if (r->in.unknown5) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.unknown5, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.unknown5, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.unknown5, ndr_charset_length(r->in.unknown5, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown6));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown7));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.unknown3 == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.unknown3));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.unknown4));
+ if (r->out.unknown4) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->out.unknown4));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.unknown5a));
+ if (r->out.unknown5a) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.unknown5a));
+ if (*r->out.unknown5a) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.unknown5a, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.unknown5a, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, *r->out.unknown5a, ndr_charset_length(*r->out.unknown5a, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_HwProfFlags(struct ndr_pull *ndr, int flags, struct PNP_HwProfFlags *r)
+{
+ uint32_t _ptr_unknown4;
+ uint32_t _ptr_unknown5;
+ uint32_t _ptr_unknown5a;
+ TALLOC_CTX *_mem_save_unknown3_0;
+ TALLOC_CTX *_mem_save_unknown4_0;
+ TALLOC_CTX *_mem_save_unknown5_0;
+ TALLOC_CTX *_mem_save_unknown5a_0;
+ TALLOC_CTX *_mem_save_unknown5a_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown1));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.devicepath));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.devicepath));
+ if (ndr_get_array_length(ndr, &r->in.devicepath) > ndr_get_array_size(ndr, &r->in.devicepath)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.devicepath), ndr_get_array_length(ndr, &r->in.devicepath));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.devicepath), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.devicepath, ndr_get_array_length(ndr, &r->in.devicepath), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown2));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.unknown3);
+ }
+ _mem_save_unknown3_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.unknown3, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.unknown3));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown3_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown4));
+ if (_ptr_unknown4) {
+ NDR_PULL_ALLOC(ndr, r->in.unknown4);
+ } else {
+ r->in.unknown4 = NULL;
+ }
+ if (r->in.unknown4) {
+ _mem_save_unknown4_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.unknown4, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.unknown4));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown4_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown5));
+ if (_ptr_unknown5) {
+ NDR_PULL_ALLOC(ndr, r->in.unknown5);
+ } else {
+ r->in.unknown5 = NULL;
+ }
+ if (r->in.unknown5) {
+ _mem_save_unknown5_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.unknown5, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.unknown5));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.unknown5));
+ if (ndr_get_array_length(ndr, &r->in.unknown5) > ndr_get_array_size(ndr, &r->in.unknown5)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.unknown5), ndr_get_array_length(ndr, &r->in.unknown5));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.unknown5), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.unknown5, ndr_get_array_length(ndr, &r->in.unknown5), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown5_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown6));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown7));
+ NDR_PULL_ALLOC(ndr, r->out.unknown3);
+ *r->out.unknown3 = *r->in.unknown3;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.unknown3);
+ }
+ _mem_save_unknown3_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.unknown3, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.unknown3));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown3_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown4));
+ if (_ptr_unknown4) {
+ NDR_PULL_ALLOC(ndr, r->out.unknown4);
+ } else {
+ r->out.unknown4 = NULL;
+ }
+ if (r->out.unknown4) {
+ _mem_save_unknown4_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.unknown4, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->out.unknown4));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown4_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown5a));
+ if (_ptr_unknown5a) {
+ NDR_PULL_ALLOC(ndr, r->out.unknown5a);
+ } else {
+ r->out.unknown5a = NULL;
+ }
+ if (r->out.unknown5a) {
+ _mem_save_unknown5a_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.unknown5a, 0);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown5a));
+ if (_ptr_unknown5a) {
+ NDR_PULL_ALLOC(ndr, *r->out.unknown5a);
+ } else {
+ *r->out.unknown5a = NULL;
+ }
+ if (*r->out.unknown5a) {
+ _mem_save_unknown5a_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.unknown5a, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->out.unknown5a));
+ NDR_CHECK(ndr_pull_array_length(ndr, r->out.unknown5a));
+ if (ndr_get_array_length(ndr, r->out.unknown5a) > ndr_get_array_size(ndr, r->out.unknown5a)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, r->out.unknown5a), ndr_get_array_length(ndr, r->out.unknown5a));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, r->out.unknown5a), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, r->out.unknown5a, ndr_get_array_length(ndr, r->out.unknown5a), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown5a_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown5a_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_HwProfFlags(struct ndr_print *ndr, const char *name, int flags, const struct PNP_HwProfFlags *r)
+{
+ ndr_print_struct(ndr, name, "PNP_HwProfFlags");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_HwProfFlags");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "unknown1", r->in.unknown1);
+ ndr_print_ptr(ndr, "devicepath", r->in.devicepath);
+ ndr->depth++;
+ ndr_print_string(ndr, "devicepath", r->in.devicepath);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown2", r->in.unknown2);
+ ndr_print_ptr(ndr, "unknown3", r->in.unknown3);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "unknown3", *r->in.unknown3);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "unknown4", r->in.unknown4);
+ ndr->depth++;
+ if (r->in.unknown4) {
+ ndr_print_uint16(ndr, "unknown4", *r->in.unknown4);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "unknown5", r->in.unknown5);
+ ndr->depth++;
+ if (r->in.unknown5) {
+ ndr_print_string(ndr, "unknown5", r->in.unknown5);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown6", r->in.unknown6);
+ ndr_print_uint32(ndr, "unknown7", r->in.unknown7);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_HwProfFlags");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "unknown3", r->out.unknown3);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "unknown3", *r->out.unknown3);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "unknown4", r->out.unknown4);
+ ndr->depth++;
+ if (r->out.unknown4) {
+ ndr_print_uint16(ndr, "unknown4", *r->out.unknown4);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "unknown5a", r->out.unknown5a);
+ ndr->depth++;
+ if (r->out.unknown5a) {
+ ndr_print_ptr(ndr, "unknown5a", *r->out.unknown5a);
+ ndr->depth++;
+ if (*r->out.unknown5a) {
+ ndr_print_string(ndr, "unknown5a", *r->out.unknown5a);
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetHwProfInfo(struct ndr_push *ndr, int flags, const struct PNP_GetHwProfInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.idx));
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_PNP_HwProfInfo(ndr, NDR_SCALARS, r->in.info));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown2));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_PNP_HwProfInfo(ndr, NDR_SCALARS, r->out.info));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetHwProfInfo(struct ndr_pull *ndr, int flags, struct PNP_GetHwProfInfo *r)
+{
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.idx));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_PNP_HwProfInfo(ndr, NDR_SCALARS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown2));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ *r->out.info = *r->in.info;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_PNP_HwProfInfo(ndr, NDR_SCALARS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetHwProfInfo(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetHwProfInfo *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetHwProfInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetHwProfInfo");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "idx", r->in.idx);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_PNP_HwProfInfo(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown1", r->in.unknown1);
+ ndr_print_uint32(ndr, "unknown2", r->in.unknown2);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetHwProfInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_PNP_HwProfInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_AddEmptyLogConf(struct ndr_push *ndr, int flags, const struct PNP_AddEmptyLogConf *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_AddEmptyLogConf(struct ndr_pull *ndr, int flags, struct PNP_AddEmptyLogConf *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_AddEmptyLogConf(struct ndr_print *ndr, const char *name, int flags, const struct PNP_AddEmptyLogConf *r)
+{
+ ndr_print_struct(ndr, name, "PNP_AddEmptyLogConf");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_AddEmptyLogConf");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_AddEmptyLogConf");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_FreeLogConf(struct ndr_push *ndr, int flags, const struct PNP_FreeLogConf *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_FreeLogConf(struct ndr_pull *ndr, int flags, struct PNP_FreeLogConf *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_FreeLogConf(struct ndr_print *ndr, const char *name, int flags, const struct PNP_FreeLogConf *r)
+{
+ ndr_print_struct(ndr, name, "PNP_FreeLogConf");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_FreeLogConf");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_FreeLogConf");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetFirstLogConf(struct ndr_push *ndr, int flags, const struct PNP_GetFirstLogConf *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetFirstLogConf(struct ndr_pull *ndr, int flags, struct PNP_GetFirstLogConf *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetFirstLogConf(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetFirstLogConf *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetFirstLogConf");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetFirstLogConf");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetFirstLogConf");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetNextLogConf(struct ndr_push *ndr, int flags, const struct PNP_GetNextLogConf *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetNextLogConf(struct ndr_pull *ndr, int flags, struct PNP_GetNextLogConf *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetNextLogConf(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetNextLogConf *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetNextLogConf");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetNextLogConf");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetNextLogConf");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetLogConfPriority(struct ndr_push *ndr, int flags, const struct PNP_GetLogConfPriority *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetLogConfPriority(struct ndr_pull *ndr, int flags, struct PNP_GetLogConfPriority *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetLogConfPriority(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetLogConfPriority *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetLogConfPriority");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetLogConfPriority");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetLogConfPriority");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_AddResDes(struct ndr_push *ndr, int flags, const struct PNP_AddResDes *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_AddResDes(struct ndr_pull *ndr, int flags, struct PNP_AddResDes *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_AddResDes(struct ndr_print *ndr, const char *name, int flags, const struct PNP_AddResDes *r)
+{
+ ndr_print_struct(ndr, name, "PNP_AddResDes");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_AddResDes");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_AddResDes");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_FreeResDes(struct ndr_push *ndr, int flags, const struct PNP_FreeResDes *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_FreeResDes(struct ndr_pull *ndr, int flags, struct PNP_FreeResDes *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_FreeResDes(struct ndr_print *ndr, const char *name, int flags, const struct PNP_FreeResDes *r)
+{
+ ndr_print_struct(ndr, name, "PNP_FreeResDes");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_FreeResDes");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_FreeResDes");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetNextResDes(struct ndr_push *ndr, int flags, const struct PNP_GetNextResDes *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetNextResDes(struct ndr_pull *ndr, int flags, struct PNP_GetNextResDes *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetNextResDes(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetNextResDes *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetNextResDes");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetNextResDes");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetNextResDes");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetResDesData(struct ndr_push *ndr, int flags, const struct PNP_GetResDesData *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetResDesData(struct ndr_pull *ndr, int flags, struct PNP_GetResDesData *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetResDesData(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetResDesData *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetResDesData");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetResDesData");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetResDesData");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetResDesDataSize(struct ndr_push *ndr, int flags, const struct PNP_GetResDesDataSize *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetResDesDataSize(struct ndr_pull *ndr, int flags, struct PNP_GetResDesDataSize *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetResDesDataSize(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetResDesDataSize *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetResDesDataSize");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetResDesDataSize");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetResDesDataSize");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_ModifyResDes(struct ndr_push *ndr, int flags, const struct PNP_ModifyResDes *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_ModifyResDes(struct ndr_pull *ndr, int flags, struct PNP_ModifyResDes *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_ModifyResDes(struct ndr_print *ndr, const char *name, int flags, const struct PNP_ModifyResDes *r)
+{
+ ndr_print_struct(ndr, name, "PNP_ModifyResDes");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_ModifyResDes");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_ModifyResDes");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_DetectResourceLimit(struct ndr_push *ndr, int flags, const struct PNP_DetectResourceLimit *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_DetectResourceLimit(struct ndr_pull *ndr, int flags, struct PNP_DetectResourceLimit *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_DetectResourceLimit(struct ndr_print *ndr, const char *name, int flags, const struct PNP_DetectResourceLimit *r)
+{
+ ndr_print_struct(ndr, name, "PNP_DetectResourceLimit");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_DetectResourceLimit");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_DetectResourceLimit");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_QueryResConfList(struct ndr_push *ndr, int flags, const struct PNP_QueryResConfList *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_QueryResConfList(struct ndr_pull *ndr, int flags, struct PNP_QueryResConfList *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_QueryResConfList(struct ndr_print *ndr, const char *name, int flags, const struct PNP_QueryResConfList *r)
+{
+ ndr_print_struct(ndr, name, "PNP_QueryResConfList");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_QueryResConfList");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_QueryResConfList");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_SetHwProf(struct ndr_push *ndr, int flags, const struct PNP_SetHwProf *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_SetHwProf(struct ndr_pull *ndr, int flags, struct PNP_SetHwProf *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_SetHwProf(struct ndr_print *ndr, const char *name, int flags, const struct PNP_SetHwProf *r)
+{
+ ndr_print_struct(ndr, name, "PNP_SetHwProf");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_SetHwProf");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_SetHwProf");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_QueryArbitratorFreeData(struct ndr_push *ndr, int flags, const struct PNP_QueryArbitratorFreeData *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_QueryArbitratorFreeData(struct ndr_pull *ndr, int flags, struct PNP_QueryArbitratorFreeData *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_QueryArbitratorFreeData(struct ndr_print *ndr, const char *name, int flags, const struct PNP_QueryArbitratorFreeData *r)
+{
+ ndr_print_struct(ndr, name, "PNP_QueryArbitratorFreeData");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_QueryArbitratorFreeData");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_QueryArbitratorFreeData");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_QueryArbitratorFreeSize(struct ndr_push *ndr, int flags, const struct PNP_QueryArbitratorFreeSize *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_QueryArbitratorFreeSize(struct ndr_pull *ndr, int flags, struct PNP_QueryArbitratorFreeSize *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_QueryArbitratorFreeSize(struct ndr_print *ndr, const char *name, int flags, const struct PNP_QueryArbitratorFreeSize *r)
+{
+ ndr_print_struct(ndr, name, "PNP_QueryArbitratorFreeSize");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_QueryArbitratorFreeSize");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_QueryArbitratorFreeSize");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_RunDetection(struct ndr_push *ndr, int flags, const struct PNP_RunDetection *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_RunDetection(struct ndr_pull *ndr, int flags, struct PNP_RunDetection *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_RunDetection(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RunDetection *r)
+{
+ ndr_print_struct(ndr, name, "PNP_RunDetection");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_RunDetection");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_RunDetection");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_RegisterNotification(struct ndr_push *ndr, int flags, const struct PNP_RegisterNotification *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_RegisterNotification(struct ndr_pull *ndr, int flags, struct PNP_RegisterNotification *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_RegisterNotification(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RegisterNotification *r)
+{
+ ndr_print_struct(ndr, name, "PNP_RegisterNotification");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_RegisterNotification");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_RegisterNotification");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_UnregisterNotification(struct ndr_push *ndr, int flags, const struct PNP_UnregisterNotification *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_UnregisterNotification(struct ndr_pull *ndr, int flags, struct PNP_UnregisterNotification *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_UnregisterNotification(struct ndr_print *ndr, const char *name, int flags, const struct PNP_UnregisterNotification *r)
+{
+ ndr_print_struct(ndr, name, "PNP_UnregisterNotification");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_UnregisterNotification");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_UnregisterNotification");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetCustomDevProp(struct ndr_push *ndr, int flags, const struct PNP_GetCustomDevProp *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetCustomDevProp(struct ndr_pull *ndr, int flags, struct PNP_GetCustomDevProp *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetCustomDevProp(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetCustomDevProp *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetCustomDevProp");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetCustomDevProp");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetCustomDevProp");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetVersionInternal(struct ndr_push *ndr, int flags, const struct PNP_GetVersionInternal *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetVersionInternal(struct ndr_pull *ndr, int flags, struct PNP_GetVersionInternal *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetVersionInternal(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetVersionInternal *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetVersionInternal");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetVersionInternal");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetVersionInternal");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetBlockedDriverInfo(struct ndr_push *ndr, int flags, const struct PNP_GetBlockedDriverInfo *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetBlockedDriverInfo(struct ndr_pull *ndr, int flags, struct PNP_GetBlockedDriverInfo *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetBlockedDriverInfo(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetBlockedDriverInfo *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetBlockedDriverInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetBlockedDriverInfo");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetBlockedDriverInfo");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_PNP_GetServerSideDeviceInstallFlags(struct ndr_push *ndr, int flags, const struct PNP_GetServerSideDeviceInstallFlags *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_PNP_GetServerSideDeviceInstallFlags(struct ndr_pull *ndr, int flags, struct PNP_GetServerSideDeviceInstallFlags *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_PNP_GetServerSideDeviceInstallFlags(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetServerSideDeviceInstallFlags *r)
+{
+ ndr_print_struct(ndr, name, "PNP_GetServerSideDeviceInstallFlags");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "PNP_GetServerSideDeviceInstallFlags");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "PNP_GetServerSideDeviceInstallFlags");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call ntsvcs_calls[] = {
+ {
+ "PNP_Disconnect",
+ sizeof(struct PNP_Disconnect),
+ (ndr_push_flags_fn_t) ndr_push_PNP_Disconnect,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_Disconnect,
+ (ndr_print_function_t) ndr_print_PNP_Disconnect,
+ false,
+ },
+ {
+ "PNP_Connect",
+ sizeof(struct PNP_Connect),
+ (ndr_push_flags_fn_t) ndr_push_PNP_Connect,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_Connect,
+ (ndr_print_function_t) ndr_print_PNP_Connect,
+ false,
+ },
+ {
+ "PNP_GetVersion",
+ sizeof(struct PNP_GetVersion),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetVersion,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetVersion,
+ (ndr_print_function_t) ndr_print_PNP_GetVersion,
+ false,
+ },
+ {
+ "PNP_GetGlobalState",
+ sizeof(struct PNP_GetGlobalState),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetGlobalState,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetGlobalState,
+ (ndr_print_function_t) ndr_print_PNP_GetGlobalState,
+ false,
+ },
+ {
+ "PNP_InitDetection",
+ sizeof(struct PNP_InitDetection),
+ (ndr_push_flags_fn_t) ndr_push_PNP_InitDetection,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_InitDetection,
+ (ndr_print_function_t) ndr_print_PNP_InitDetection,
+ false,
+ },
+ {
+ "PNP_ReportLogOn",
+ sizeof(struct PNP_ReportLogOn),
+ (ndr_push_flags_fn_t) ndr_push_PNP_ReportLogOn,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_ReportLogOn,
+ (ndr_print_function_t) ndr_print_PNP_ReportLogOn,
+ false,
+ },
+ {
+ "PNP_ValidateDeviceInstance",
+ sizeof(struct PNP_ValidateDeviceInstance),
+ (ndr_push_flags_fn_t) ndr_push_PNP_ValidateDeviceInstance,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_ValidateDeviceInstance,
+ (ndr_print_function_t) ndr_print_PNP_ValidateDeviceInstance,
+ false,
+ },
+ {
+ "PNP_GetRootDeviceInstance",
+ sizeof(struct PNP_GetRootDeviceInstance),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetRootDeviceInstance,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetRootDeviceInstance,
+ (ndr_print_function_t) ndr_print_PNP_GetRootDeviceInstance,
+ false,
+ },
+ {
+ "PNP_GetRelatedDeviceInstance",
+ sizeof(struct PNP_GetRelatedDeviceInstance),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetRelatedDeviceInstance,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetRelatedDeviceInstance,
+ (ndr_print_function_t) ndr_print_PNP_GetRelatedDeviceInstance,
+ false,
+ },
+ {
+ "PNP_EnumerateSubKeys",
+ sizeof(struct PNP_EnumerateSubKeys),
+ (ndr_push_flags_fn_t) ndr_push_PNP_EnumerateSubKeys,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_EnumerateSubKeys,
+ (ndr_print_function_t) ndr_print_PNP_EnumerateSubKeys,
+ false,
+ },
+ {
+ "PNP_GetDeviceList",
+ sizeof(struct PNP_GetDeviceList),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetDeviceList,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetDeviceList,
+ (ndr_print_function_t) ndr_print_PNP_GetDeviceList,
+ false,
+ },
+ {
+ "PNP_GetDeviceListSize",
+ sizeof(struct PNP_GetDeviceListSize),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetDeviceListSize,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetDeviceListSize,
+ (ndr_print_function_t) ndr_print_PNP_GetDeviceListSize,
+ false,
+ },
+ {
+ "PNP_GetDepth",
+ sizeof(struct PNP_GetDepth),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetDepth,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetDepth,
+ (ndr_print_function_t) ndr_print_PNP_GetDepth,
+ false,
+ },
+ {
+ "PNP_GetDeviceRegProp",
+ sizeof(struct PNP_GetDeviceRegProp),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetDeviceRegProp,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetDeviceRegProp,
+ (ndr_print_function_t) ndr_print_PNP_GetDeviceRegProp,
+ false,
+ },
+ {
+ "PNP_SetDeviceRegProp",
+ sizeof(struct PNP_SetDeviceRegProp),
+ (ndr_push_flags_fn_t) ndr_push_PNP_SetDeviceRegProp,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_SetDeviceRegProp,
+ (ndr_print_function_t) ndr_print_PNP_SetDeviceRegProp,
+ false,
+ },
+ {
+ "PNP_GetClassInstance",
+ sizeof(struct PNP_GetClassInstance),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetClassInstance,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetClassInstance,
+ (ndr_print_function_t) ndr_print_PNP_GetClassInstance,
+ false,
+ },
+ {
+ "PNP_CreateKey",
+ sizeof(struct PNP_CreateKey),
+ (ndr_push_flags_fn_t) ndr_push_PNP_CreateKey,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_CreateKey,
+ (ndr_print_function_t) ndr_print_PNP_CreateKey,
+ false,
+ },
+ {
+ "PNP_DeleteRegistryKey",
+ sizeof(struct PNP_DeleteRegistryKey),
+ (ndr_push_flags_fn_t) ndr_push_PNP_DeleteRegistryKey,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_DeleteRegistryKey,
+ (ndr_print_function_t) ndr_print_PNP_DeleteRegistryKey,
+ false,
+ },
+ {
+ "PNP_GetClassCount",
+ sizeof(struct PNP_GetClassCount),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetClassCount,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetClassCount,
+ (ndr_print_function_t) ndr_print_PNP_GetClassCount,
+ false,
+ },
+ {
+ "PNP_GetClassName",
+ sizeof(struct PNP_GetClassName),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetClassName,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetClassName,
+ (ndr_print_function_t) ndr_print_PNP_GetClassName,
+ false,
+ },
+ {
+ "PNP_DeleteClassKey",
+ sizeof(struct PNP_DeleteClassKey),
+ (ndr_push_flags_fn_t) ndr_push_PNP_DeleteClassKey,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_DeleteClassKey,
+ (ndr_print_function_t) ndr_print_PNP_DeleteClassKey,
+ false,
+ },
+ {
+ "PNP_GetInterfaceDeviceAlias",
+ sizeof(struct PNP_GetInterfaceDeviceAlias),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetInterfaceDeviceAlias,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetInterfaceDeviceAlias,
+ (ndr_print_function_t) ndr_print_PNP_GetInterfaceDeviceAlias,
+ false,
+ },
+ {
+ "PNP_GetInterfaceDeviceList",
+ sizeof(struct PNP_GetInterfaceDeviceList),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetInterfaceDeviceList,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetInterfaceDeviceList,
+ (ndr_print_function_t) ndr_print_PNP_GetInterfaceDeviceList,
+ false,
+ },
+ {
+ "PNP_GetInterfaceDeviceListSize",
+ sizeof(struct PNP_GetInterfaceDeviceListSize),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetInterfaceDeviceListSize,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetInterfaceDeviceListSize,
+ (ndr_print_function_t) ndr_print_PNP_GetInterfaceDeviceListSize,
+ false,
+ },
+ {
+ "PNP_RegisterDeviceClassAssociation",
+ sizeof(struct PNP_RegisterDeviceClassAssociation),
+ (ndr_push_flags_fn_t) ndr_push_PNP_RegisterDeviceClassAssociation,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_RegisterDeviceClassAssociation,
+ (ndr_print_function_t) ndr_print_PNP_RegisterDeviceClassAssociation,
+ false,
+ },
+ {
+ "PNP_UnregisterDeviceClassAssociation",
+ sizeof(struct PNP_UnregisterDeviceClassAssociation),
+ (ndr_push_flags_fn_t) ndr_push_PNP_UnregisterDeviceClassAssociation,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_UnregisterDeviceClassAssociation,
+ (ndr_print_function_t) ndr_print_PNP_UnregisterDeviceClassAssociation,
+ false,
+ },
+ {
+ "PNP_GetClassRegProp",
+ sizeof(struct PNP_GetClassRegProp),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetClassRegProp,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetClassRegProp,
+ (ndr_print_function_t) ndr_print_PNP_GetClassRegProp,
+ false,
+ },
+ {
+ "PNP_SetClassRegProp",
+ sizeof(struct PNP_SetClassRegProp),
+ (ndr_push_flags_fn_t) ndr_push_PNP_SetClassRegProp,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_SetClassRegProp,
+ (ndr_print_function_t) ndr_print_PNP_SetClassRegProp,
+ false,
+ },
+ {
+ "PNP_CreateDevInst",
+ sizeof(struct PNP_CreateDevInst),
+ (ndr_push_flags_fn_t) ndr_push_PNP_CreateDevInst,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_CreateDevInst,
+ (ndr_print_function_t) ndr_print_PNP_CreateDevInst,
+ false,
+ },
+ {
+ "PNP_DeviceInstanceAction",
+ sizeof(struct PNP_DeviceInstanceAction),
+ (ndr_push_flags_fn_t) ndr_push_PNP_DeviceInstanceAction,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_DeviceInstanceAction,
+ (ndr_print_function_t) ndr_print_PNP_DeviceInstanceAction,
+ false,
+ },
+ {
+ "PNP_GetDeviceStatus",
+ sizeof(struct PNP_GetDeviceStatus),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetDeviceStatus,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetDeviceStatus,
+ (ndr_print_function_t) ndr_print_PNP_GetDeviceStatus,
+ false,
+ },
+ {
+ "PNP_SetDeviceProblem",
+ sizeof(struct PNP_SetDeviceProblem),
+ (ndr_push_flags_fn_t) ndr_push_PNP_SetDeviceProblem,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_SetDeviceProblem,
+ (ndr_print_function_t) ndr_print_PNP_SetDeviceProblem,
+ false,
+ },
+ {
+ "PNP_DisableDevInst",
+ sizeof(struct PNP_DisableDevInst),
+ (ndr_push_flags_fn_t) ndr_push_PNP_DisableDevInst,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_DisableDevInst,
+ (ndr_print_function_t) ndr_print_PNP_DisableDevInst,
+ false,
+ },
+ {
+ "PNP_UninstallDevInst",
+ sizeof(struct PNP_UninstallDevInst),
+ (ndr_push_flags_fn_t) ndr_push_PNP_UninstallDevInst,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_UninstallDevInst,
+ (ndr_print_function_t) ndr_print_PNP_UninstallDevInst,
+ false,
+ },
+ {
+ "PNP_AddID",
+ sizeof(struct PNP_AddID),
+ (ndr_push_flags_fn_t) ndr_push_PNP_AddID,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_AddID,
+ (ndr_print_function_t) ndr_print_PNP_AddID,
+ false,
+ },
+ {
+ "PNP_RegisterDriver",
+ sizeof(struct PNP_RegisterDriver),
+ (ndr_push_flags_fn_t) ndr_push_PNP_RegisterDriver,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_RegisterDriver,
+ (ndr_print_function_t) ndr_print_PNP_RegisterDriver,
+ false,
+ },
+ {
+ "PNP_QueryRemove",
+ sizeof(struct PNP_QueryRemove),
+ (ndr_push_flags_fn_t) ndr_push_PNP_QueryRemove,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_QueryRemove,
+ (ndr_print_function_t) ndr_print_PNP_QueryRemove,
+ false,
+ },
+ {
+ "PNP_RequestDeviceEject",
+ sizeof(struct PNP_RequestDeviceEject),
+ (ndr_push_flags_fn_t) ndr_push_PNP_RequestDeviceEject,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_RequestDeviceEject,
+ (ndr_print_function_t) ndr_print_PNP_RequestDeviceEject,
+ false,
+ },
+ {
+ "PNP_IsDockStationPresent",
+ sizeof(struct PNP_IsDockStationPresent),
+ (ndr_push_flags_fn_t) ndr_push_PNP_IsDockStationPresent,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_IsDockStationPresent,
+ (ndr_print_function_t) ndr_print_PNP_IsDockStationPresent,
+ false,
+ },
+ {
+ "PNP_RequestEjectPC",
+ sizeof(struct PNP_RequestEjectPC),
+ (ndr_push_flags_fn_t) ndr_push_PNP_RequestEjectPC,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_RequestEjectPC,
+ (ndr_print_function_t) ndr_print_PNP_RequestEjectPC,
+ false,
+ },
+ {
+ "PNP_HwProfFlags",
+ sizeof(struct PNP_HwProfFlags),
+ (ndr_push_flags_fn_t) ndr_push_PNP_HwProfFlags,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_HwProfFlags,
+ (ndr_print_function_t) ndr_print_PNP_HwProfFlags,
+ false,
+ },
+ {
+ "PNP_GetHwProfInfo",
+ sizeof(struct PNP_GetHwProfInfo),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetHwProfInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetHwProfInfo,
+ (ndr_print_function_t) ndr_print_PNP_GetHwProfInfo,
+ false,
+ },
+ {
+ "PNP_AddEmptyLogConf",
+ sizeof(struct PNP_AddEmptyLogConf),
+ (ndr_push_flags_fn_t) ndr_push_PNP_AddEmptyLogConf,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_AddEmptyLogConf,
+ (ndr_print_function_t) ndr_print_PNP_AddEmptyLogConf,
+ false,
+ },
+ {
+ "PNP_FreeLogConf",
+ sizeof(struct PNP_FreeLogConf),
+ (ndr_push_flags_fn_t) ndr_push_PNP_FreeLogConf,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_FreeLogConf,
+ (ndr_print_function_t) ndr_print_PNP_FreeLogConf,
+ false,
+ },
+ {
+ "PNP_GetFirstLogConf",
+ sizeof(struct PNP_GetFirstLogConf),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetFirstLogConf,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetFirstLogConf,
+ (ndr_print_function_t) ndr_print_PNP_GetFirstLogConf,
+ false,
+ },
+ {
+ "PNP_GetNextLogConf",
+ sizeof(struct PNP_GetNextLogConf),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetNextLogConf,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetNextLogConf,
+ (ndr_print_function_t) ndr_print_PNP_GetNextLogConf,
+ false,
+ },
+ {
+ "PNP_GetLogConfPriority",
+ sizeof(struct PNP_GetLogConfPriority),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetLogConfPriority,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetLogConfPriority,
+ (ndr_print_function_t) ndr_print_PNP_GetLogConfPriority,
+ false,
+ },
+ {
+ "PNP_AddResDes",
+ sizeof(struct PNP_AddResDes),
+ (ndr_push_flags_fn_t) ndr_push_PNP_AddResDes,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_AddResDes,
+ (ndr_print_function_t) ndr_print_PNP_AddResDes,
+ false,
+ },
+ {
+ "PNP_FreeResDes",
+ sizeof(struct PNP_FreeResDes),
+ (ndr_push_flags_fn_t) ndr_push_PNP_FreeResDes,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_FreeResDes,
+ (ndr_print_function_t) ndr_print_PNP_FreeResDes,
+ false,
+ },
+ {
+ "PNP_GetNextResDes",
+ sizeof(struct PNP_GetNextResDes),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetNextResDes,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetNextResDes,
+ (ndr_print_function_t) ndr_print_PNP_GetNextResDes,
+ false,
+ },
+ {
+ "PNP_GetResDesData",
+ sizeof(struct PNP_GetResDesData),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetResDesData,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetResDesData,
+ (ndr_print_function_t) ndr_print_PNP_GetResDesData,
+ false,
+ },
+ {
+ "PNP_GetResDesDataSize",
+ sizeof(struct PNP_GetResDesDataSize),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetResDesDataSize,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetResDesDataSize,
+ (ndr_print_function_t) ndr_print_PNP_GetResDesDataSize,
+ false,
+ },
+ {
+ "PNP_ModifyResDes",
+ sizeof(struct PNP_ModifyResDes),
+ (ndr_push_flags_fn_t) ndr_push_PNP_ModifyResDes,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_ModifyResDes,
+ (ndr_print_function_t) ndr_print_PNP_ModifyResDes,
+ false,
+ },
+ {
+ "PNP_DetectResourceLimit",
+ sizeof(struct PNP_DetectResourceLimit),
+ (ndr_push_flags_fn_t) ndr_push_PNP_DetectResourceLimit,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_DetectResourceLimit,
+ (ndr_print_function_t) ndr_print_PNP_DetectResourceLimit,
+ false,
+ },
+ {
+ "PNP_QueryResConfList",
+ sizeof(struct PNP_QueryResConfList),
+ (ndr_push_flags_fn_t) ndr_push_PNP_QueryResConfList,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_QueryResConfList,
+ (ndr_print_function_t) ndr_print_PNP_QueryResConfList,
+ false,
+ },
+ {
+ "PNP_SetHwProf",
+ sizeof(struct PNP_SetHwProf),
+ (ndr_push_flags_fn_t) ndr_push_PNP_SetHwProf,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_SetHwProf,
+ (ndr_print_function_t) ndr_print_PNP_SetHwProf,
+ false,
+ },
+ {
+ "PNP_QueryArbitratorFreeData",
+ sizeof(struct PNP_QueryArbitratorFreeData),
+ (ndr_push_flags_fn_t) ndr_push_PNP_QueryArbitratorFreeData,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_QueryArbitratorFreeData,
+ (ndr_print_function_t) ndr_print_PNP_QueryArbitratorFreeData,
+ false,
+ },
+ {
+ "PNP_QueryArbitratorFreeSize",
+ sizeof(struct PNP_QueryArbitratorFreeSize),
+ (ndr_push_flags_fn_t) ndr_push_PNP_QueryArbitratorFreeSize,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_QueryArbitratorFreeSize,
+ (ndr_print_function_t) ndr_print_PNP_QueryArbitratorFreeSize,
+ false,
+ },
+ {
+ "PNP_RunDetection",
+ sizeof(struct PNP_RunDetection),
+ (ndr_push_flags_fn_t) ndr_push_PNP_RunDetection,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_RunDetection,
+ (ndr_print_function_t) ndr_print_PNP_RunDetection,
+ false,
+ },
+ {
+ "PNP_RegisterNotification",
+ sizeof(struct PNP_RegisterNotification),
+ (ndr_push_flags_fn_t) ndr_push_PNP_RegisterNotification,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_RegisterNotification,
+ (ndr_print_function_t) ndr_print_PNP_RegisterNotification,
+ false,
+ },
+ {
+ "PNP_UnregisterNotification",
+ sizeof(struct PNP_UnregisterNotification),
+ (ndr_push_flags_fn_t) ndr_push_PNP_UnregisterNotification,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_UnregisterNotification,
+ (ndr_print_function_t) ndr_print_PNP_UnregisterNotification,
+ false,
+ },
+ {
+ "PNP_GetCustomDevProp",
+ sizeof(struct PNP_GetCustomDevProp),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetCustomDevProp,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetCustomDevProp,
+ (ndr_print_function_t) ndr_print_PNP_GetCustomDevProp,
+ false,
+ },
+ {
+ "PNP_GetVersionInternal",
+ sizeof(struct PNP_GetVersionInternal),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetVersionInternal,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetVersionInternal,
+ (ndr_print_function_t) ndr_print_PNP_GetVersionInternal,
+ false,
+ },
+ {
+ "PNP_GetBlockedDriverInfo",
+ sizeof(struct PNP_GetBlockedDriverInfo),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetBlockedDriverInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetBlockedDriverInfo,
+ (ndr_print_function_t) ndr_print_PNP_GetBlockedDriverInfo,
+ false,
+ },
+ {
+ "PNP_GetServerSideDeviceInstallFlags",
+ sizeof(struct PNP_GetServerSideDeviceInstallFlags),
+ (ndr_push_flags_fn_t) ndr_push_PNP_GetServerSideDeviceInstallFlags,
+ (ndr_pull_flags_fn_t) ndr_pull_PNP_GetServerSideDeviceInstallFlags,
+ (ndr_print_function_t) ndr_print_PNP_GetServerSideDeviceInstallFlags,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const ntsvcs_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\ntsvcs]",
+};
+
+static const struct ndr_interface_string_array ntsvcs_endpoints = {
+ .count = 1,
+ .names = ntsvcs_endpoint_strings
+};
+
+static const char * const ntsvcs_authservice_strings[] = {
+ "host",
+};
+
+static const struct ndr_interface_string_array ntsvcs_authservices = {
+ .count = 1,
+ .names = ntsvcs_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_ntsvcs = {
+ .name = "ntsvcs",
+ .syntax_id = {
+ {0x8d9f4e40,0xa03d,0x11ce,{0x8f,0x69},{0x08,0x00,0x3e,0x30,0x05,0x1b}},
+ NDR_NTSVCS_VERSION
+ },
+ .helpstring = NDR_NTSVCS_HELPSTRING,
+ .num_calls = 65,
+ .calls = ntsvcs_calls,
+ .endpoints = &ntsvcs_endpoints,
+ .authservices = &ntsvcs_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_ntsvcs.h b/source3/librpc/gen_ndr/ndr_ntsvcs.h
new file mode 100644
index 0000000000..0e3b6b91c4
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_ntsvcs.h
@@ -0,0 +1,211 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ntsvcs.h"
+
+#ifndef _HEADER_NDR_ntsvcs
+#define _HEADER_NDR_ntsvcs
+
+#define NDR_NTSVCS_UUID "8d9f4e40-a03d-11ce-8f69-08003e30051b"
+#define NDR_NTSVCS_VERSION 1.0
+#define NDR_NTSVCS_NAME "ntsvcs"
+#define NDR_NTSVCS_HELPSTRING "Plug and Play services"
+extern const struct ndr_interface_table ndr_table_ntsvcs;
+#define NDR_PNP_DISCONNECT (0x00)
+
+#define NDR_PNP_CONNECT (0x01)
+
+#define NDR_PNP_GETVERSION (0x02)
+
+#define NDR_PNP_GETGLOBALSTATE (0x03)
+
+#define NDR_PNP_INITDETECTION (0x04)
+
+#define NDR_PNP_REPORTLOGON (0x05)
+
+#define NDR_PNP_VALIDATEDEVICEINSTANCE (0x06)
+
+#define NDR_PNP_GETROOTDEVICEINSTANCE (0x07)
+
+#define NDR_PNP_GETRELATEDDEVICEINSTANCE (0x08)
+
+#define NDR_PNP_ENUMERATESUBKEYS (0x09)
+
+#define NDR_PNP_GETDEVICELIST (0x0a)
+
+#define NDR_PNP_GETDEVICELISTSIZE (0x0b)
+
+#define NDR_PNP_GETDEPTH (0x0c)
+
+#define NDR_PNP_GETDEVICEREGPROP (0x0d)
+
+#define NDR_PNP_SETDEVICEREGPROP (0x0e)
+
+#define NDR_PNP_GETCLASSINSTANCE (0x0f)
+
+#define NDR_PNP_CREATEKEY (0x10)
+
+#define NDR_PNP_DELETEREGISTRYKEY (0x11)
+
+#define NDR_PNP_GETCLASSCOUNT (0x12)
+
+#define NDR_PNP_GETCLASSNAME (0x13)
+
+#define NDR_PNP_DELETECLASSKEY (0x14)
+
+#define NDR_PNP_GETINTERFACEDEVICEALIAS (0x15)
+
+#define NDR_PNP_GETINTERFACEDEVICELIST (0x16)
+
+#define NDR_PNP_GETINTERFACEDEVICELISTSIZE (0x17)
+
+#define NDR_PNP_REGISTERDEVICECLASSASSOCIATION (0x18)
+
+#define NDR_PNP_UNREGISTERDEVICECLASSASSOCIATION (0x19)
+
+#define NDR_PNP_GETCLASSREGPROP (0x1a)
+
+#define NDR_PNP_SETCLASSREGPROP (0x1b)
+
+#define NDR_PNP_CREATEDEVINST (0x1c)
+
+#define NDR_PNP_DEVICEINSTANCEACTION (0x1d)
+
+#define NDR_PNP_GETDEVICESTATUS (0x1e)
+
+#define NDR_PNP_SETDEVICEPROBLEM (0x1f)
+
+#define NDR_PNP_DISABLEDEVINST (0x20)
+
+#define NDR_PNP_UNINSTALLDEVINST (0x21)
+
+#define NDR_PNP_ADDID (0x22)
+
+#define NDR_PNP_REGISTERDRIVER (0x23)
+
+#define NDR_PNP_QUERYREMOVE (0x24)
+
+#define NDR_PNP_REQUESTDEVICEEJECT (0x25)
+
+#define NDR_PNP_ISDOCKSTATIONPRESENT (0x26)
+
+#define NDR_PNP_REQUESTEJECTPC (0x27)
+
+#define NDR_PNP_HWPROFFLAGS (0x28)
+
+#define NDR_PNP_GETHWPROFINFO (0x29)
+
+#define NDR_PNP_ADDEMPTYLOGCONF (0x2a)
+
+#define NDR_PNP_FREELOGCONF (0x2b)
+
+#define NDR_PNP_GETFIRSTLOGCONF (0x2c)
+
+#define NDR_PNP_GETNEXTLOGCONF (0x2d)
+
+#define NDR_PNP_GETLOGCONFPRIORITY (0x2e)
+
+#define NDR_PNP_ADDRESDES (0x2f)
+
+#define NDR_PNP_FREERESDES (0x30)
+
+#define NDR_PNP_GETNEXTRESDES (0x31)
+
+#define NDR_PNP_GETRESDESDATA (0x32)
+
+#define NDR_PNP_GETRESDESDATASIZE (0x33)
+
+#define NDR_PNP_MODIFYRESDES (0x34)
+
+#define NDR_PNP_DETECTRESOURCELIMIT (0x35)
+
+#define NDR_PNP_QUERYRESCONFLIST (0x36)
+
+#define NDR_PNP_SETHWPROF (0x37)
+
+#define NDR_PNP_QUERYARBITRATORFREEDATA (0x38)
+
+#define NDR_PNP_QUERYARBITRATORFREESIZE (0x39)
+
+#define NDR_PNP_RUNDETECTION (0x3a)
+
+#define NDR_PNP_REGISTERNOTIFICATION (0x3b)
+
+#define NDR_PNP_UNREGISTERNOTIFICATION (0x3c)
+
+#define NDR_PNP_GETCUSTOMDEVPROP (0x3d)
+
+#define NDR_PNP_GETVERSIONINTERNAL (0x3e)
+
+#define NDR_PNP_GETBLOCKEDDRIVERINFO (0x3f)
+
+#define NDR_PNP_GETSERVERSIDEDEVICEINSTALLFLAGS (0x40)
+
+#define NDR_NTSVCS_CALL_COUNT (65)
+void ndr_print_PNP_HwProfInfo(struct ndr_print *ndr, const char *name, const struct PNP_HwProfInfo *r);
+void ndr_print_PNP_Disconnect(struct ndr_print *ndr, const char *name, int flags, const struct PNP_Disconnect *r);
+void ndr_print_PNP_Connect(struct ndr_print *ndr, const char *name, int flags, const struct PNP_Connect *r);
+void ndr_print_PNP_GetVersion(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetVersion *r);
+void ndr_print_PNP_GetGlobalState(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetGlobalState *r);
+void ndr_print_PNP_InitDetection(struct ndr_print *ndr, const char *name, int flags, const struct PNP_InitDetection *r);
+void ndr_print_PNP_ReportLogOn(struct ndr_print *ndr, const char *name, int flags, const struct PNP_ReportLogOn *r);
+void ndr_print_PNP_ValidateDeviceInstance(struct ndr_print *ndr, const char *name, int flags, const struct PNP_ValidateDeviceInstance *r);
+void ndr_print_PNP_GetRootDeviceInstance(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetRootDeviceInstance *r);
+void ndr_print_PNP_GetRelatedDeviceInstance(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetRelatedDeviceInstance *r);
+void ndr_print_PNP_EnumerateSubKeys(struct ndr_print *ndr, const char *name, int flags, const struct PNP_EnumerateSubKeys *r);
+void ndr_print_PNP_GetDeviceList(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetDeviceList *r);
+void ndr_print_PNP_GetDeviceListSize(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetDeviceListSize *r);
+void ndr_print_PNP_GetDepth(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetDepth *r);
+void ndr_print_PNP_GetDeviceRegProp(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetDeviceRegProp *r);
+void ndr_print_PNP_SetDeviceRegProp(struct ndr_print *ndr, const char *name, int flags, const struct PNP_SetDeviceRegProp *r);
+void ndr_print_PNP_GetClassInstance(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetClassInstance *r);
+void ndr_print_PNP_CreateKey(struct ndr_print *ndr, const char *name, int flags, const struct PNP_CreateKey *r);
+void ndr_print_PNP_DeleteRegistryKey(struct ndr_print *ndr, const char *name, int flags, const struct PNP_DeleteRegistryKey *r);
+void ndr_print_PNP_GetClassCount(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetClassCount *r);
+void ndr_print_PNP_GetClassName(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetClassName *r);
+void ndr_print_PNP_DeleteClassKey(struct ndr_print *ndr, const char *name, int flags, const struct PNP_DeleteClassKey *r);
+void ndr_print_PNP_GetInterfaceDeviceAlias(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetInterfaceDeviceAlias *r);
+void ndr_print_PNP_GetInterfaceDeviceList(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetInterfaceDeviceList *r);
+void ndr_print_PNP_GetInterfaceDeviceListSize(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetInterfaceDeviceListSize *r);
+void ndr_print_PNP_RegisterDeviceClassAssociation(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RegisterDeviceClassAssociation *r);
+void ndr_print_PNP_UnregisterDeviceClassAssociation(struct ndr_print *ndr, const char *name, int flags, const struct PNP_UnregisterDeviceClassAssociation *r);
+void ndr_print_PNP_GetClassRegProp(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetClassRegProp *r);
+void ndr_print_PNP_SetClassRegProp(struct ndr_print *ndr, const char *name, int flags, const struct PNP_SetClassRegProp *r);
+void ndr_print_PNP_CreateDevInst(struct ndr_print *ndr, const char *name, int flags, const struct PNP_CreateDevInst *r);
+void ndr_print_PNP_DeviceInstanceAction(struct ndr_print *ndr, const char *name, int flags, const struct PNP_DeviceInstanceAction *r);
+void ndr_print_PNP_GetDeviceStatus(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetDeviceStatus *r);
+void ndr_print_PNP_SetDeviceProblem(struct ndr_print *ndr, const char *name, int flags, const struct PNP_SetDeviceProblem *r);
+void ndr_print_PNP_DisableDevInst(struct ndr_print *ndr, const char *name, int flags, const struct PNP_DisableDevInst *r);
+void ndr_print_PNP_UninstallDevInst(struct ndr_print *ndr, const char *name, int flags, const struct PNP_UninstallDevInst *r);
+void ndr_print_PNP_AddID(struct ndr_print *ndr, const char *name, int flags, const struct PNP_AddID *r);
+void ndr_print_PNP_RegisterDriver(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RegisterDriver *r);
+void ndr_print_PNP_QueryRemove(struct ndr_print *ndr, const char *name, int flags, const struct PNP_QueryRemove *r);
+void ndr_print_PNP_RequestDeviceEject(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RequestDeviceEject *r);
+void ndr_print_PNP_IsDockStationPresent(struct ndr_print *ndr, const char *name, int flags, const struct PNP_IsDockStationPresent *r);
+void ndr_print_PNP_RequestEjectPC(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RequestEjectPC *r);
+void ndr_print_PNP_HwProfFlags(struct ndr_print *ndr, const char *name, int flags, const struct PNP_HwProfFlags *r);
+void ndr_print_PNP_GetHwProfInfo(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetHwProfInfo *r);
+void ndr_print_PNP_AddEmptyLogConf(struct ndr_print *ndr, const char *name, int flags, const struct PNP_AddEmptyLogConf *r);
+void ndr_print_PNP_FreeLogConf(struct ndr_print *ndr, const char *name, int flags, const struct PNP_FreeLogConf *r);
+void ndr_print_PNP_GetFirstLogConf(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetFirstLogConf *r);
+void ndr_print_PNP_GetNextLogConf(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetNextLogConf *r);
+void ndr_print_PNP_GetLogConfPriority(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetLogConfPriority *r);
+void ndr_print_PNP_AddResDes(struct ndr_print *ndr, const char *name, int flags, const struct PNP_AddResDes *r);
+void ndr_print_PNP_FreeResDes(struct ndr_print *ndr, const char *name, int flags, const struct PNP_FreeResDes *r);
+void ndr_print_PNP_GetNextResDes(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetNextResDes *r);
+void ndr_print_PNP_GetResDesData(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetResDesData *r);
+void ndr_print_PNP_GetResDesDataSize(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetResDesDataSize *r);
+void ndr_print_PNP_ModifyResDes(struct ndr_print *ndr, const char *name, int flags, const struct PNP_ModifyResDes *r);
+void ndr_print_PNP_DetectResourceLimit(struct ndr_print *ndr, const char *name, int flags, const struct PNP_DetectResourceLimit *r);
+void ndr_print_PNP_QueryResConfList(struct ndr_print *ndr, const char *name, int flags, const struct PNP_QueryResConfList *r);
+void ndr_print_PNP_SetHwProf(struct ndr_print *ndr, const char *name, int flags, const struct PNP_SetHwProf *r);
+void ndr_print_PNP_QueryArbitratorFreeData(struct ndr_print *ndr, const char *name, int flags, const struct PNP_QueryArbitratorFreeData *r);
+void ndr_print_PNP_QueryArbitratorFreeSize(struct ndr_print *ndr, const char *name, int flags, const struct PNP_QueryArbitratorFreeSize *r);
+void ndr_print_PNP_RunDetection(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RunDetection *r);
+void ndr_print_PNP_RegisterNotification(struct ndr_print *ndr, const char *name, int flags, const struct PNP_RegisterNotification *r);
+void ndr_print_PNP_UnregisterNotification(struct ndr_print *ndr, const char *name, int flags, const struct PNP_UnregisterNotification *r);
+void ndr_print_PNP_GetCustomDevProp(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetCustomDevProp *r);
+void ndr_print_PNP_GetVersionInternal(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetVersionInternal *r);
+void ndr_print_PNP_GetBlockedDriverInfo(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetBlockedDriverInfo *r);
+void ndr_print_PNP_GetServerSideDeviceInstallFlags(struct ndr_print *ndr, const char *name, int flags, const struct PNP_GetServerSideDeviceInstallFlags *r);
+#endif /* _HEADER_NDR_ntsvcs */
diff --git a/source3/librpc/gen_ndr/ndr_samr.c b/source3/librpc/gen_ndr/ndr_samr.c
new file mode 100644
index 0000000000..9c5a886325
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_samr.c
@@ -0,0 +1,12702 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_samr.h"
+
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/ndr_lsa.h"
+#include "librpc/gen_ndr/ndr_security.h"
+_PUBLIC_ enum ndr_err_code ndr_push_samr_AcctFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_AcctFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_AcctFlags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_DISABLED", ACB_DISABLED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_HOMDIRREQ", ACB_HOMDIRREQ, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_PWNOTREQ", ACB_PWNOTREQ, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_TEMPDUP", ACB_TEMPDUP, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_NORMAL", ACB_NORMAL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_MNS", ACB_MNS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_DOMTRUST", ACB_DOMTRUST, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_WSTRUST", ACB_WSTRUST, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_SVRTRUST", ACB_SVRTRUST, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_PWNOEXP", ACB_PWNOEXP, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_AUTOLOCK", ACB_AUTOLOCK, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_ENC_TXT_PWD_ALLOWED", ACB_ENC_TXT_PWD_ALLOWED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_SMARTCARD_REQUIRED", ACB_SMARTCARD_REQUIRED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_TRUSTED_FOR_DELEGATION", ACB_TRUSTED_FOR_DELEGATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_NOT_DELEGATED", ACB_NOT_DELEGATED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_USE_DES_KEY_ONLY", ACB_USE_DES_KEY_ONLY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_DONT_REQUIRE_PREAUTH", ACB_DONT_REQUIRE_PREAUTH, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_PW_EXPIRED", ACB_PW_EXPIRED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "ACB_NO_AUTH_DATA_REQD", ACB_NO_AUTH_DATA_REQD, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_ConnectAccessMask(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ConnectAccessMask(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ConnectAccessMask(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_ACCESS_CONNECT_TO_SERVER", SAMR_ACCESS_CONNECT_TO_SERVER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_ACCESS_SHUTDOWN_SERVER", SAMR_ACCESS_SHUTDOWN_SERVER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_ACCESS_INITIALIZE_SERVER", SAMR_ACCESS_INITIALIZE_SERVER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_ACCESS_CREATE_DOMAIN", SAMR_ACCESS_CREATE_DOMAIN, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_ACCESS_ENUM_DOMAINS", SAMR_ACCESS_ENUM_DOMAINS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_ACCESS_OPEN_DOMAIN", SAMR_ACCESS_OPEN_DOMAIN, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserAccessMask(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserAccessMask(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserAccessMask(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_USER_ACCESS_GET_NAME_ETC", SAMR_USER_ACCESS_GET_NAME_ETC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_USER_ACCESS_GET_LOCALE", SAMR_USER_ACCESS_GET_LOCALE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_USER_ACCESS_SET_LOC_COM", SAMR_USER_ACCESS_SET_LOC_COM, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_USER_ACCESS_GET_LOGONINFO", SAMR_USER_ACCESS_GET_LOGONINFO, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_USER_ACCESS_GET_ATTRIBUTES", SAMR_USER_ACCESS_GET_ATTRIBUTES, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_USER_ACCESS_SET_ATTRIBUTES", SAMR_USER_ACCESS_SET_ATTRIBUTES, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_USER_ACCESS_CHANGE_PASSWORD", SAMR_USER_ACCESS_CHANGE_PASSWORD, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_USER_ACCESS_SET_PASSWORD", SAMR_USER_ACCESS_SET_PASSWORD, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_USER_ACCESS_GET_GROUPS", SAMR_USER_ACCESS_GET_GROUPS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP", SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_USER_ACCESS_CHANGE_GROUP_MEMBERSHIP", SAMR_USER_ACCESS_CHANGE_GROUP_MEMBERSHIP, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DomainAccessMask(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DomainAccessMask(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DomainAccessMask(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1", SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_DOMAIN_ACCESS_SET_INFO_1", SAMR_DOMAIN_ACCESS_SET_INFO_1, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2", SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_DOMAIN_ACCESS_SET_INFO_2", SAMR_DOMAIN_ACCESS_SET_INFO_2, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_DOMAIN_ACCESS_CREATE_USER", SAMR_DOMAIN_ACCESS_CREATE_USER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_DOMAIN_ACCESS_CREATE_GROUP", SAMR_DOMAIN_ACCESS_CREATE_GROUP, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_DOMAIN_ACCESS_CREATE_ALIAS", SAMR_DOMAIN_ACCESS_CREATE_ALIAS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS", SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS", SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT", SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_DOMAIN_ACCESS_SET_INFO_3", SAMR_DOMAIN_ACCESS_SET_INFO_3, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_GroupAccessMask(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_GroupAccessMask(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_GroupAccessMask(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_GROUP_ACCESS_LOOKUP_INFO", SAMR_GROUP_ACCESS_LOOKUP_INFO, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_GROUP_ACCESS_SET_INFO", SAMR_GROUP_ACCESS_SET_INFO, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_GROUP_ACCESS_ADD_MEMBER", SAMR_GROUP_ACCESS_ADD_MEMBER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_GROUP_ACCESS_REMOVE_MEMBER", SAMR_GROUP_ACCESS_REMOVE_MEMBER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_GROUP_ACCESS_GET_MEMBERS", SAMR_GROUP_ACCESS_GET_MEMBERS, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_AliasAccessMask(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_AliasAccessMask(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_AliasAccessMask(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_ALIAS_ACCESS_ADD_MEMBER", SAMR_ALIAS_ACCESS_ADD_MEMBER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_ALIAS_ACCESS_REMOVE_MEMBER", SAMR_ALIAS_ACCESS_REMOVE_MEMBER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_ALIAS_ACCESS_GET_MEMBERS", SAMR_ALIAS_ACCESS_GET_MEMBERS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_ALIAS_ACCESS_LOOKUP_INFO", SAMR_ALIAS_ACCESS_LOOKUP_INFO, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_ALIAS_ACCESS_SET_INFO", SAMR_ALIAS_ACCESS_SET_INFO, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_SamEntry(struct ndr_push *ndr, int ndr_flags, const struct samr_SamEntry *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->idx));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_SamEntry(struct ndr_pull *ndr, int ndr_flags, struct samr_SamEntry *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->idx));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_SamEntry(struct ndr_print *ndr, const char *name, const struct samr_SamEntry *r)
+{
+ ndr_print_struct(ndr, name, "samr_SamEntry");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "idx", r->idx);
+ ndr_print_lsa_String(ndr, "name", &r->name);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_SamArray(struct ndr_push *ndr, int ndr_flags, const struct samr_SamArray *r)
+{
+ uint32_t cntr_entries_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->entries));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->entries) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_push_samr_SamEntry(ndr, NDR_SCALARS, &r->entries[cntr_entries_1]));
+ }
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_push_samr_SamEntry(ndr, NDR_BUFFERS, &r->entries[cntr_entries_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_SamArray(struct ndr_pull *ndr, int ndr_flags, struct samr_SamArray *r)
+{
+ uint32_t _ptr_entries;
+ uint32_t cntr_entries_1;
+ TALLOC_CTX *_mem_save_entries_0;
+ TALLOC_CTX *_mem_save_entries_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_entries));
+ if (_ptr_entries) {
+ NDR_PULL_ALLOC(ndr, r->entries);
+ } else {
+ r->entries = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->entries) {
+ _mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->entries));
+ NDR_PULL_ALLOC_N(ndr, r->entries, ndr_get_array_size(ndr, &r->entries));
+ _mem_save_entries_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_pull_samr_SamEntry(ndr, NDR_SCALARS, &r->entries[cntr_entries_1]));
+ }
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_pull_samr_SamEntry(ndr, NDR_BUFFERS, &r->entries[cntr_entries_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0);
+ }
+ if (r->entries) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->entries, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_SamArray(struct ndr_print *ndr, const char *name, const struct samr_SamArray *r)
+{
+ uint32_t cntr_entries_1;
+ ndr_print_struct(ndr, name, "samr_SamArray");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "entries", r->entries);
+ ndr->depth++;
+ if (r->entries) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "entries", (int)r->count);
+ ndr->depth++;
+ for (cntr_entries_1=0;cntr_entries_1<r->count;cntr_entries_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_entries_1) != -1) {
+ ndr_print_samr_SamEntry(ndr, "entries", &r->entries[cntr_entries_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_Role(struct ndr_push *ndr, int ndr_flags, enum samr_Role r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_Role(struct ndr_pull *ndr, int ndr_flags, enum samr_Role *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_Role(struct ndr_print *ndr, const char *name, enum samr_Role r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case SAMR_ROLE_STANDALONE: val = "SAMR_ROLE_STANDALONE"; break;
+ case SAMR_ROLE_DOMAIN_MEMBER: val = "SAMR_ROLE_DOMAIN_MEMBER"; break;
+ case SAMR_ROLE_DOMAIN_BDC: val = "SAMR_ROLE_DOMAIN_BDC"; break;
+ case SAMR_ROLE_DOMAIN_PDC: val = "SAMR_ROLE_DOMAIN_PDC"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_PasswordProperties(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_PasswordProperties(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_PasswordProperties(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DOMAIN_PASSWORD_COMPLEX", DOMAIN_PASSWORD_COMPLEX, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DOMAIN_PASSWORD_NO_ANON_CHANGE", DOMAIN_PASSWORD_NO_ANON_CHANGE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DOMAIN_PASSWORD_NO_CLEAR_CHANGE", DOMAIN_PASSWORD_NO_CLEAR_CHANGE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DOMAIN_PASSWORD_LOCKOUT_ADMINS", DOMAIN_PASSWORD_LOCKOUT_ADMINS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DOMAIN_PASSWORD_STORE_CLEARTEXT", DOMAIN_PASSWORD_STORE_CLEARTEXT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "DOMAIN_REFUSE_PASSWORD_CHANGE", DOMAIN_REFUSE_PASSWORD_CHANGE, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DomInfo1(struct ndr_push *ndr, int ndr_flags, const struct samr_DomInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->min_password_length));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->password_history_length));
+ NDR_CHECK(ndr_push_samr_PasswordProperties(ndr, NDR_SCALARS, r->password_properties));
+ NDR_CHECK(ndr_push_dlong(ndr, NDR_SCALARS, r->max_password_age));
+ NDR_CHECK(ndr_push_dlong(ndr, NDR_SCALARS, r->min_password_age));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DomInfo1(struct ndr_pull *ndr, int ndr_flags, struct samr_DomInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->min_password_length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->password_history_length));
+ NDR_CHECK(ndr_pull_samr_PasswordProperties(ndr, NDR_SCALARS, &r->password_properties));
+ NDR_CHECK(ndr_pull_dlong(ndr, NDR_SCALARS, &r->max_password_age));
+ NDR_CHECK(ndr_pull_dlong(ndr, NDR_SCALARS, &r->min_password_age));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DomInfo1(struct ndr_print *ndr, const char *name, const struct samr_DomInfo1 *r)
+{
+ ndr_print_struct(ndr, name, "samr_DomInfo1");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "min_password_length", r->min_password_length);
+ ndr_print_uint16(ndr, "password_history_length", r->password_history_length);
+ ndr_print_samr_PasswordProperties(ndr, "password_properties", r->password_properties);
+ ndr_print_dlong(ndr, "max_password_age", r->max_password_age);
+ ndr_print_dlong(ndr, "min_password_age", r->min_password_age);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DomInfo2(struct ndr_push *ndr, int ndr_flags, const struct samr_DomInfo2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->force_logoff_time));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->comment));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->domain_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->primary));
+ NDR_CHECK(ndr_push_udlong(ndr, NDR_SCALARS, r->sequence_num));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown2));
+ NDR_CHECK(ndr_push_samr_Role(ndr, NDR_SCALARS, r->role));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown3));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_users));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_groups));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_aliases));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->comment));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->domain_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->primary));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DomInfo2(struct ndr_pull *ndr, int ndr_flags, struct samr_DomInfo2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->force_logoff_time));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->comment));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->domain_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->primary));
+ NDR_CHECK(ndr_pull_udlong(ndr, NDR_SCALARS, &r->sequence_num));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_samr_Role(ndr, NDR_SCALARS, &r->role));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_users));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_groups));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_aliases));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->comment));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->domain_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->primary));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DomInfo2(struct ndr_print *ndr, const char *name, const struct samr_DomInfo2 *r)
+{
+ ndr_print_struct(ndr, name, "samr_DomInfo2");
+ ndr->depth++;
+ ndr_print_NTTIME(ndr, "force_logoff_time", r->force_logoff_time);
+ ndr_print_lsa_String(ndr, "comment", &r->comment);
+ ndr_print_lsa_String(ndr, "domain_name", &r->domain_name);
+ ndr_print_lsa_String(ndr, "primary", &r->primary);
+ ndr_print_udlong(ndr, "sequence_num", r->sequence_num);
+ ndr_print_uint32(ndr, "unknown2", r->unknown2);
+ ndr_print_samr_Role(ndr, "role", r->role);
+ ndr_print_uint32(ndr, "unknown3", r->unknown3);
+ ndr_print_uint32(ndr, "num_users", r->num_users);
+ ndr_print_uint32(ndr, "num_groups", r->num_groups);
+ ndr_print_uint32(ndr, "num_aliases", r->num_aliases);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DomInfo3(struct ndr_push *ndr, int ndr_flags, const struct samr_DomInfo3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->force_logoff_time));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DomInfo3(struct ndr_pull *ndr, int ndr_flags, struct samr_DomInfo3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->force_logoff_time));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DomInfo3(struct ndr_print *ndr, const char *name, const struct samr_DomInfo3 *r)
+{
+ ndr_print_struct(ndr, name, "samr_DomInfo3");
+ ndr->depth++;
+ ndr_print_NTTIME(ndr, "force_logoff_time", r->force_logoff_time);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DomInfo4(struct ndr_push *ndr, int ndr_flags, const struct samr_DomInfo4 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->comment));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DomInfo4(struct ndr_pull *ndr, int ndr_flags, struct samr_DomInfo4 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->comment));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DomInfo4(struct ndr_print *ndr, const char *name, const struct samr_DomInfo4 *r)
+{
+ ndr_print_struct(ndr, name, "samr_DomInfo4");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "comment", &r->comment);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DomInfo5(struct ndr_push *ndr, int ndr_flags, const struct samr_DomInfo5 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->domain_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->domain_name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DomInfo5(struct ndr_pull *ndr, int ndr_flags, struct samr_DomInfo5 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->domain_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->domain_name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DomInfo5(struct ndr_print *ndr, const char *name, const struct samr_DomInfo5 *r)
+{
+ ndr_print_struct(ndr, name, "samr_DomInfo5");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "domain_name", &r->domain_name);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DomInfo6(struct ndr_push *ndr, int ndr_flags, const struct samr_DomInfo6 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->primary));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->primary));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DomInfo6(struct ndr_pull *ndr, int ndr_flags, struct samr_DomInfo6 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->primary));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->primary));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DomInfo6(struct ndr_print *ndr, const char *name, const struct samr_DomInfo6 *r)
+{
+ ndr_print_struct(ndr, name, "samr_DomInfo6");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "primary", &r->primary);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DomInfo7(struct ndr_push *ndr, int ndr_flags, const struct samr_DomInfo7 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_samr_Role(ndr, NDR_SCALARS, r->role));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DomInfo7(struct ndr_pull *ndr, int ndr_flags, struct samr_DomInfo7 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_samr_Role(ndr, NDR_SCALARS, &r->role));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DomInfo7(struct ndr_print *ndr, const char *name, const struct samr_DomInfo7 *r)
+{
+ ndr_print_struct(ndr, name, "samr_DomInfo7");
+ ndr->depth++;
+ ndr_print_samr_Role(ndr, "role", r->role);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DomInfo8(struct ndr_push *ndr, int ndr_flags, const struct samr_DomInfo8 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->sequence_num));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->domain_create_time));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DomInfo8(struct ndr_pull *ndr, int ndr_flags, struct samr_DomInfo8 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->sequence_num));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->domain_create_time));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DomInfo8(struct ndr_print *ndr, const char *name, const struct samr_DomInfo8 *r)
+{
+ ndr_print_struct(ndr, name, "samr_DomInfo8");
+ ndr->depth++;
+ ndr_print_hyper(ndr, "sequence_num", r->sequence_num);
+ ndr_print_NTTIME(ndr, "domain_create_time", r->domain_create_time);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DomInfo9(struct ndr_push *ndr, int ndr_flags, const struct samr_DomInfo9 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DomInfo9(struct ndr_pull *ndr, int ndr_flags, struct samr_DomInfo9 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DomInfo9(struct ndr_print *ndr, const char *name, const struct samr_DomInfo9 *r)
+{
+ ndr_print_struct(ndr, name, "samr_DomInfo9");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "unknown", r->unknown);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DomInfo11(struct ndr_push *ndr, int ndr_flags, const struct samr_DomInfo11 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_samr_DomInfo2(ndr, NDR_SCALARS, &r->info2));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->lockout_duration));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->lockout_window));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lockout_threshold));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_samr_DomInfo2(ndr, NDR_BUFFERS, &r->info2));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DomInfo11(struct ndr_pull *ndr, int ndr_flags, struct samr_DomInfo11 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_samr_DomInfo2(ndr, NDR_SCALARS, &r->info2));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->lockout_duration));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->lockout_window));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lockout_threshold));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_samr_DomInfo2(ndr, NDR_BUFFERS, &r->info2));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DomInfo11(struct ndr_print *ndr, const char *name, const struct samr_DomInfo11 *r)
+{
+ ndr_print_struct(ndr, name, "samr_DomInfo11");
+ ndr->depth++;
+ ndr_print_samr_DomInfo2(ndr, "info2", &r->info2);
+ ndr_print_hyper(ndr, "lockout_duration", r->lockout_duration);
+ ndr_print_hyper(ndr, "lockout_window", r->lockout_window);
+ ndr_print_uint16(ndr, "lockout_threshold", r->lockout_threshold);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DomInfo12(struct ndr_push *ndr, int ndr_flags, const struct samr_DomInfo12 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->lockout_duration));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->lockout_window));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lockout_threshold));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DomInfo12(struct ndr_pull *ndr, int ndr_flags, struct samr_DomInfo12 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->lockout_duration));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->lockout_window));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lockout_threshold));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DomInfo12(struct ndr_print *ndr, const char *name, const struct samr_DomInfo12 *r)
+{
+ ndr_print_struct(ndr, name, "samr_DomInfo12");
+ ndr->depth++;
+ ndr_print_hyper(ndr, "lockout_duration", r->lockout_duration);
+ ndr_print_hyper(ndr, "lockout_window", r->lockout_window);
+ ndr_print_uint16(ndr, "lockout_threshold", r->lockout_threshold);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DomInfo13(struct ndr_push *ndr, int ndr_flags, const struct samr_DomInfo13 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->sequence_num));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->domain_create_time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DomInfo13(struct ndr_pull *ndr, int ndr_flags, struct samr_DomInfo13 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->sequence_num));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->domain_create_time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DomInfo13(struct ndr_print *ndr, const char *name, const struct samr_DomInfo13 *r)
+{
+ ndr_print_struct(ndr, name, "samr_DomInfo13");
+ ndr->depth++;
+ ndr_print_hyper(ndr, "sequence_num", r->sequence_num);
+ ndr_print_NTTIME(ndr, "domain_create_time", r->domain_create_time);
+ ndr_print_uint32(ndr, "unknown1", r->unknown1);
+ ndr_print_uint32(ndr, "unknown2", r->unknown2);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DomainInfo(struct ndr_push *ndr, int ndr_flags, const union samr_DomainInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_samr_DomInfo1(ndr, NDR_SCALARS, &r->info1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_samr_DomInfo2(ndr, NDR_SCALARS, &r->info2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_samr_DomInfo3(ndr, NDR_SCALARS, &r->info3));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_push_samr_DomInfo4(ndr, NDR_SCALARS, &r->info4));
+ break; }
+
+ case 5: {
+ NDR_CHECK(ndr_push_samr_DomInfo5(ndr, NDR_SCALARS, &r->info5));
+ break; }
+
+ case 6: {
+ NDR_CHECK(ndr_push_samr_DomInfo6(ndr, NDR_SCALARS, &r->info6));
+ break; }
+
+ case 7: {
+ NDR_CHECK(ndr_push_samr_DomInfo7(ndr, NDR_SCALARS, &r->info7));
+ break; }
+
+ case 8: {
+ NDR_CHECK(ndr_push_samr_DomInfo8(ndr, NDR_SCALARS, &r->info8));
+ break; }
+
+ case 9: {
+ NDR_CHECK(ndr_push_samr_DomInfo9(ndr, NDR_SCALARS, &r->info9));
+ break; }
+
+ case 11: {
+ NDR_CHECK(ndr_push_samr_DomInfo11(ndr, NDR_SCALARS, &r->info11));
+ break; }
+
+ case 12: {
+ NDR_CHECK(ndr_push_samr_DomInfo12(ndr, NDR_SCALARS, &r->info12));
+ break; }
+
+ case 13: {
+ NDR_CHECK(ndr_push_samr_DomInfo13(ndr, NDR_SCALARS, &r->info13));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_push_samr_DomInfo2(ndr, NDR_BUFFERS, &r->info2));
+ break;
+
+ case 3:
+ break;
+
+ case 4:
+ NDR_CHECK(ndr_push_samr_DomInfo4(ndr, NDR_BUFFERS, &r->info4));
+ break;
+
+ case 5:
+ NDR_CHECK(ndr_push_samr_DomInfo5(ndr, NDR_BUFFERS, &r->info5));
+ break;
+
+ case 6:
+ NDR_CHECK(ndr_push_samr_DomInfo6(ndr, NDR_BUFFERS, &r->info6));
+ break;
+
+ case 7:
+ break;
+
+ case 8:
+ break;
+
+ case 9:
+ break;
+
+ case 11:
+ NDR_CHECK(ndr_push_samr_DomInfo11(ndr, NDR_BUFFERS, &r->info11));
+ break;
+
+ case 12:
+ break;
+
+ case 13:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DomainInfo(struct ndr_pull *ndr, int ndr_flags, union samr_DomainInfo *r)
+{
+ int level;
+ uint16_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_samr_DomInfo1(ndr, NDR_SCALARS, &r->info1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_pull_samr_DomInfo2(ndr, NDR_SCALARS, &r->info2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_pull_samr_DomInfo3(ndr, NDR_SCALARS, &r->info3));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_pull_samr_DomInfo4(ndr, NDR_SCALARS, &r->info4));
+ break; }
+
+ case 5: {
+ NDR_CHECK(ndr_pull_samr_DomInfo5(ndr, NDR_SCALARS, &r->info5));
+ break; }
+
+ case 6: {
+ NDR_CHECK(ndr_pull_samr_DomInfo6(ndr, NDR_SCALARS, &r->info6));
+ break; }
+
+ case 7: {
+ NDR_CHECK(ndr_pull_samr_DomInfo7(ndr, NDR_SCALARS, &r->info7));
+ break; }
+
+ case 8: {
+ NDR_CHECK(ndr_pull_samr_DomInfo8(ndr, NDR_SCALARS, &r->info8));
+ break; }
+
+ case 9: {
+ NDR_CHECK(ndr_pull_samr_DomInfo9(ndr, NDR_SCALARS, &r->info9));
+ break; }
+
+ case 11: {
+ NDR_CHECK(ndr_pull_samr_DomInfo11(ndr, NDR_SCALARS, &r->info11));
+ break; }
+
+ case 12: {
+ NDR_CHECK(ndr_pull_samr_DomInfo12(ndr, NDR_SCALARS, &r->info12));
+ break; }
+
+ case 13: {
+ NDR_CHECK(ndr_pull_samr_DomInfo13(ndr, NDR_SCALARS, &r->info13));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_pull_samr_DomInfo2(ndr, NDR_BUFFERS, &r->info2));
+ break;
+
+ case 3:
+ break;
+
+ case 4:
+ NDR_CHECK(ndr_pull_samr_DomInfo4(ndr, NDR_BUFFERS, &r->info4));
+ break;
+
+ case 5:
+ NDR_CHECK(ndr_pull_samr_DomInfo5(ndr, NDR_BUFFERS, &r->info5));
+ break;
+
+ case 6:
+ NDR_CHECK(ndr_pull_samr_DomInfo6(ndr, NDR_BUFFERS, &r->info6));
+ break;
+
+ case 7:
+ break;
+
+ case 8:
+ break;
+
+ case 9:
+ break;
+
+ case 11:
+ NDR_CHECK(ndr_pull_samr_DomInfo11(ndr, NDR_BUFFERS, &r->info11));
+ break;
+
+ case 12:
+ break;
+
+ case 13:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DomainInfo(struct ndr_print *ndr, const char *name, const union samr_DomainInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "samr_DomainInfo");
+ switch (level) {
+ case 1:
+ ndr_print_samr_DomInfo1(ndr, "info1", &r->info1);
+ break;
+
+ case 2:
+ ndr_print_samr_DomInfo2(ndr, "info2", &r->info2);
+ break;
+
+ case 3:
+ ndr_print_samr_DomInfo3(ndr, "info3", &r->info3);
+ break;
+
+ case 4:
+ ndr_print_samr_DomInfo4(ndr, "info4", &r->info4);
+ break;
+
+ case 5:
+ ndr_print_samr_DomInfo5(ndr, "info5", &r->info5);
+ break;
+
+ case 6:
+ ndr_print_samr_DomInfo6(ndr, "info6", &r->info6);
+ break;
+
+ case 7:
+ ndr_print_samr_DomInfo7(ndr, "info7", &r->info7);
+ break;
+
+ case 8:
+ ndr_print_samr_DomInfo8(ndr, "info8", &r->info8);
+ break;
+
+ case 9:
+ ndr_print_samr_DomInfo9(ndr, "info9", &r->info9);
+ break;
+
+ case 11:
+ ndr_print_samr_DomInfo11(ndr, "info11", &r->info11);
+ break;
+
+ case 12:
+ ndr_print_samr_DomInfo12(ndr, "info12", &r->info12);
+ break;
+
+ case 13:
+ ndr_print_samr_DomInfo13(ndr, "info13", &r->info13);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_samr_Ids(struct ndr_push *ndr, int ndr_flags, const struct samr_Ids *r)
+{
+ uint32_t cntr_ids_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ids));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->ids) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_ids_1 = 0; cntr_ids_1 < r->count; cntr_ids_1++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ids[cntr_ids_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_Ids(struct ndr_pull *ndr, int ndr_flags, struct samr_Ids *r)
+{
+ uint32_t _ptr_ids;
+ uint32_t cntr_ids_1;
+ TALLOC_CTX *_mem_save_ids_0;
+ TALLOC_CTX *_mem_save_ids_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ if (r->count < 0 || r->count > 1024) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ids));
+ if (_ptr_ids) {
+ NDR_PULL_ALLOC(ndr, r->ids);
+ } else {
+ r->ids = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->ids) {
+ _mem_save_ids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ids, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->ids));
+ NDR_PULL_ALLOC_N(ndr, r->ids, ndr_get_array_size(ndr, &r->ids));
+ _mem_save_ids_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ids, 0);
+ for (cntr_ids_1 = 0; cntr_ids_1 < r->count; cntr_ids_1++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->ids[cntr_ids_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ids_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ids_0, 0);
+ }
+ if (r->ids) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->ids, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_Ids(struct ndr_print *ndr, const char *name, const struct samr_Ids *r)
+{
+ uint32_t cntr_ids_1;
+ ndr_print_struct(ndr, name, "samr_Ids");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "ids", r->ids);
+ ndr->depth++;
+ if (r->ids) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "ids", (int)r->count);
+ ndr->depth++;
+ for (cntr_ids_1=0;cntr_ids_1<r->count;cntr_ids_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_ids_1) != -1) {
+ ndr_print_uint32(ndr, "ids", r->ids[cntr_ids_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_GroupAttrs(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_GroupAttrs(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_GroupAttrs(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SE_GROUP_MANDATORY", SE_GROUP_MANDATORY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SE_GROUP_ENABLED_BY_DEFAULT", SE_GROUP_ENABLED_BY_DEFAULT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SE_GROUP_ENABLED", SE_GROUP_ENABLED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SE_GROUP_OWNER", SE_GROUP_OWNER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SE_GROUP_USE_FOR_DENY_ONLY", SE_GROUP_USE_FOR_DENY_ONLY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SE_GROUP_RESOURCE", SE_GROUP_RESOURCE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SE_GROUP_LOGON_ID", SE_GROUP_LOGON_ID, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_GroupInfoAll(struct ndr_push *ndr, int ndr_flags, const struct samr_GroupInfoAll *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_push_samr_GroupAttrs(ndr, NDR_SCALARS, r->attributes));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_members));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->description));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_GroupInfoAll(struct ndr_pull *ndr, int ndr_flags, struct samr_GroupInfoAll *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_pull_samr_GroupAttrs(ndr, NDR_SCALARS, &r->attributes));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_members));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->description));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_GroupInfoAll(struct ndr_print *ndr, const char *name, const struct samr_GroupInfoAll *r)
+{
+ ndr_print_struct(ndr, name, "samr_GroupInfoAll");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "name", &r->name);
+ ndr_print_samr_GroupAttrs(ndr, "attributes", r->attributes);
+ ndr_print_uint32(ndr, "num_members", r->num_members);
+ ndr_print_lsa_String(ndr, "description", &r->description);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_GroupInfoAttributes(struct ndr_push *ndr, int ndr_flags, const struct samr_GroupInfoAttributes *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_samr_GroupAttrs(ndr, NDR_SCALARS, r->attributes));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_GroupInfoAttributes(struct ndr_pull *ndr, int ndr_flags, struct samr_GroupInfoAttributes *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_samr_GroupAttrs(ndr, NDR_SCALARS, &r->attributes));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_GroupInfoAttributes(struct ndr_print *ndr, const char *name, const struct samr_GroupInfoAttributes *r)
+{
+ ndr_print_struct(ndr, name, "samr_GroupInfoAttributes");
+ ndr->depth++;
+ ndr_print_samr_GroupAttrs(ndr, "attributes", r->attributes);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_GroupInfoEnum(struct ndr_push *ndr, int ndr_flags, enum samr_GroupInfoEnum r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_GroupInfoEnum(struct ndr_pull *ndr, int ndr_flags, enum samr_GroupInfoEnum *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_GroupInfoEnum(struct ndr_print *ndr, const char *name, enum samr_GroupInfoEnum r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case GROUPINFOALL: val = "GROUPINFOALL"; break;
+ case GROUPINFONAME: val = "GROUPINFONAME"; break;
+ case GROUPINFOATTRIBUTES: val = "GROUPINFOATTRIBUTES"; break;
+ case GROUPINFODESCRIPTION: val = "GROUPINFODESCRIPTION"; break;
+ case GROUPINFOALL2: val = "GROUPINFOALL2"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_samr_GroupInfo(struct ndr_push *ndr, int ndr_flags, const union samr_GroupInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_samr_GroupInfoEnum(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case GROUPINFOALL: {
+ NDR_CHECK(ndr_push_samr_GroupInfoAll(ndr, NDR_SCALARS, &r->all));
+ break; }
+
+ case GROUPINFONAME: {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->name));
+ break; }
+
+ case GROUPINFOATTRIBUTES: {
+ NDR_CHECK(ndr_push_samr_GroupInfoAttributes(ndr, NDR_SCALARS, &r->attributes));
+ break; }
+
+ case GROUPINFODESCRIPTION: {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->description));
+ break; }
+
+ case GROUPINFOALL2: {
+ NDR_CHECK(ndr_push_samr_GroupInfoAll(ndr, NDR_SCALARS, &r->all2));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case GROUPINFOALL:
+ NDR_CHECK(ndr_push_samr_GroupInfoAll(ndr, NDR_BUFFERS, &r->all));
+ break;
+
+ case GROUPINFONAME:
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->name));
+ break;
+
+ case GROUPINFOATTRIBUTES:
+ break;
+
+ case GROUPINFODESCRIPTION:
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ break;
+
+ case GROUPINFOALL2:
+ NDR_CHECK(ndr_push_samr_GroupInfoAll(ndr, NDR_BUFFERS, &r->all2));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_GroupInfo(struct ndr_pull *ndr, int ndr_flags, union samr_GroupInfo *r)
+{
+ int level;
+ uint16_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case GROUPINFOALL: {
+ NDR_CHECK(ndr_pull_samr_GroupInfoAll(ndr, NDR_SCALARS, &r->all));
+ break; }
+
+ case GROUPINFONAME: {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->name));
+ break; }
+
+ case GROUPINFOATTRIBUTES: {
+ NDR_CHECK(ndr_pull_samr_GroupInfoAttributes(ndr, NDR_SCALARS, &r->attributes));
+ break; }
+
+ case GROUPINFODESCRIPTION: {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->description));
+ break; }
+
+ case GROUPINFOALL2: {
+ NDR_CHECK(ndr_pull_samr_GroupInfoAll(ndr, NDR_SCALARS, &r->all2));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case GROUPINFOALL:
+ NDR_CHECK(ndr_pull_samr_GroupInfoAll(ndr, NDR_BUFFERS, &r->all));
+ break;
+
+ case GROUPINFONAME:
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->name));
+ break;
+
+ case GROUPINFOATTRIBUTES:
+ break;
+
+ case GROUPINFODESCRIPTION:
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ break;
+
+ case GROUPINFOALL2:
+ NDR_CHECK(ndr_pull_samr_GroupInfoAll(ndr, NDR_BUFFERS, &r->all2));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_GroupInfo(struct ndr_print *ndr, const char *name, const union samr_GroupInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "samr_GroupInfo");
+ switch (level) {
+ case GROUPINFOALL:
+ ndr_print_samr_GroupInfoAll(ndr, "all", &r->all);
+ break;
+
+ case GROUPINFONAME:
+ ndr_print_lsa_String(ndr, "name", &r->name);
+ break;
+
+ case GROUPINFOATTRIBUTES:
+ ndr_print_samr_GroupInfoAttributes(ndr, "attributes", &r->attributes);
+ break;
+
+ case GROUPINFODESCRIPTION:
+ ndr_print_lsa_String(ndr, "description", &r->description);
+ break;
+
+ case GROUPINFOALL2:
+ ndr_print_samr_GroupInfoAll(ndr, "all2", &r->all2);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_samr_RidTypeArray(struct ndr_push *ndr, int ndr_flags, const struct samr_RidTypeArray *r)
+{
+ uint32_t cntr_rids_1;
+ uint32_t cntr_types_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->rids));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->types));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->rids) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_rids_1 = 0; cntr_rids_1 < r->count; cntr_rids_1++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rids[cntr_rids_1]));
+ }
+ }
+ if (r->types) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_types_1 = 0; cntr_types_1 < r->count; cntr_types_1++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->types[cntr_types_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_RidTypeArray(struct ndr_pull *ndr, int ndr_flags, struct samr_RidTypeArray *r)
+{
+ uint32_t _ptr_rids;
+ uint32_t cntr_rids_1;
+ TALLOC_CTX *_mem_save_rids_0;
+ TALLOC_CTX *_mem_save_rids_1;
+ uint32_t _ptr_types;
+ uint32_t cntr_types_1;
+ TALLOC_CTX *_mem_save_types_0;
+ TALLOC_CTX *_mem_save_types_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_rids));
+ if (_ptr_rids) {
+ NDR_PULL_ALLOC(ndr, r->rids);
+ } else {
+ r->rids = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_types));
+ if (_ptr_types) {
+ NDR_PULL_ALLOC(ndr, r->types);
+ } else {
+ r->types = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->rids) {
+ _mem_save_rids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->rids, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->rids));
+ NDR_PULL_ALLOC_N(ndr, r->rids, ndr_get_array_size(ndr, &r->rids));
+ _mem_save_rids_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->rids, 0);
+ for (cntr_rids_1 = 0; cntr_rids_1 < r->count; cntr_rids_1++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rids[cntr_rids_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rids_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rids_0, 0);
+ }
+ if (r->types) {
+ _mem_save_types_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->types, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->types));
+ NDR_PULL_ALLOC_N(ndr, r->types, ndr_get_array_size(ndr, &r->types));
+ _mem_save_types_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->types, 0);
+ for (cntr_types_1 = 0; cntr_types_1 < r->count; cntr_types_1++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->types[cntr_types_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_types_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_types_0, 0);
+ }
+ if (r->rids) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->rids, r->count));
+ }
+ if (r->types) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->types, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_RidTypeArray(struct ndr_print *ndr, const char *name, const struct samr_RidTypeArray *r)
+{
+ uint32_t cntr_rids_1;
+ uint32_t cntr_types_1;
+ ndr_print_struct(ndr, name, "samr_RidTypeArray");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "rids", r->rids);
+ ndr->depth++;
+ if (r->rids) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "rids", (int)r->count);
+ ndr->depth++;
+ for (cntr_rids_1=0;cntr_rids_1<r->count;cntr_rids_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_rids_1) != -1) {
+ ndr_print_uint32(ndr, "rids", r->rids[cntr_rids_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "types", r->types);
+ ndr->depth++;
+ if (r->types) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "types", (int)r->count);
+ ndr->depth++;
+ for (cntr_types_1=0;cntr_types_1<r->count;cntr_types_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_types_1) != -1) {
+ ndr_print_uint32(ndr, "types", r->types[cntr_types_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_AliasInfoAll(struct ndr_push *ndr, int ndr_flags, const struct samr_AliasInfoAll *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_members));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->description));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_AliasInfoAll(struct ndr_pull *ndr, int ndr_flags, struct samr_AliasInfoAll *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_members));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->description));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_AliasInfoAll(struct ndr_print *ndr, const char *name, const struct samr_AliasInfoAll *r)
+{
+ ndr_print_struct(ndr, name, "samr_AliasInfoAll");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "name", &r->name);
+ ndr_print_uint32(ndr, "num_members", r->num_members);
+ ndr_print_lsa_String(ndr, "description", &r->description);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_AliasInfoEnum(struct ndr_push *ndr, int ndr_flags, enum samr_AliasInfoEnum r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_AliasInfoEnum(struct ndr_pull *ndr, int ndr_flags, enum samr_AliasInfoEnum *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_AliasInfoEnum(struct ndr_print *ndr, const char *name, enum samr_AliasInfoEnum r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case ALIASINFOALL: val = "ALIASINFOALL"; break;
+ case ALIASINFONAME: val = "ALIASINFONAME"; break;
+ case ALIASINFODESCRIPTION: val = "ALIASINFODESCRIPTION"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_samr_AliasInfo(struct ndr_push *ndr, int ndr_flags, const union samr_AliasInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_samr_AliasInfoEnum(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case ALIASINFOALL: {
+ NDR_CHECK(ndr_push_samr_AliasInfoAll(ndr, NDR_SCALARS, &r->all));
+ break; }
+
+ case ALIASINFONAME: {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->name));
+ break; }
+
+ case ALIASINFODESCRIPTION: {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->description));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case ALIASINFOALL:
+ NDR_CHECK(ndr_push_samr_AliasInfoAll(ndr, NDR_BUFFERS, &r->all));
+ break;
+
+ case ALIASINFONAME:
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->name));
+ break;
+
+ case ALIASINFODESCRIPTION:
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_AliasInfo(struct ndr_pull *ndr, int ndr_flags, union samr_AliasInfo *r)
+{
+ int level;
+ uint16_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case ALIASINFOALL: {
+ NDR_CHECK(ndr_pull_samr_AliasInfoAll(ndr, NDR_SCALARS, &r->all));
+ break; }
+
+ case ALIASINFONAME: {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->name));
+ break; }
+
+ case ALIASINFODESCRIPTION: {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->description));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case ALIASINFOALL:
+ NDR_CHECK(ndr_pull_samr_AliasInfoAll(ndr, NDR_BUFFERS, &r->all));
+ break;
+
+ case ALIASINFONAME:
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->name));
+ break;
+
+ case ALIASINFODESCRIPTION:
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_AliasInfo(struct ndr_print *ndr, const char *name, const union samr_AliasInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "samr_AliasInfo");
+ switch (level) {
+ case ALIASINFOALL:
+ ndr_print_samr_AliasInfoAll(ndr, "all", &r->all);
+ break;
+
+ case ALIASINFONAME:
+ ndr_print_lsa_String(ndr, "name", &r->name);
+ break;
+
+ case ALIASINFODESCRIPTION:
+ ndr_print_lsa_String(ndr, "description", &r->description);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo1(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->primary_gid));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->description));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->comment));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo1(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->primary_gid));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->description));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->comment));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo1(struct ndr_print *ndr, const char *name, const struct samr_UserInfo1 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo1");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "account_name", &r->account_name);
+ ndr_print_lsa_String(ndr, "full_name", &r->full_name);
+ ndr_print_uint32(ndr, "primary_gid", r->primary_gid);
+ ndr_print_lsa_String(ndr, "description", &r->description);
+ ndr_print_lsa_String(ndr, "comment", &r->comment);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo2(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->comment));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->country_code));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->code_page));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->comment));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo2(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->comment));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->country_code));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->code_page));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->comment));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo2(struct ndr_print *ndr, const char *name, const struct samr_UserInfo2 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo2");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "comment", &r->comment);
+ ndr_print_lsa_String(ndr, "unknown", &r->unknown);
+ ndr_print_uint16(ndr, "country_code", r->country_code);
+ ndr_print_uint16(ndr, "code_page", r->code_page);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_LogonHours(struct ndr_push *ndr, int ndr_flags, const struct samr_LogonHours *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->units_per_week));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->bits));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->bits) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 1260));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->units_per_week / 8));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->bits, r->units_per_week / 8));
+ }
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_LogonHours(struct ndr_pull *ndr, int ndr_flags, struct samr_LogonHours *r)
+{
+ uint32_t _ptr_bits;
+ TALLOC_CTX *_mem_save_bits_0;
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->units_per_week));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_bits));
+ if (_ptr_bits) {
+ NDR_PULL_ALLOC(ndr, r->bits);
+ } else {
+ r->bits = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->bits) {
+ _mem_save_bits_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->bits, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->bits));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->bits));
+ if (ndr_get_array_length(ndr, &r->bits) > ndr_get_array_size(ndr, &r->bits)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->bits), ndr_get_array_length(ndr, &r->bits));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->bits, ndr_get_array_size(ndr, &r->bits));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->bits, ndr_get_array_length(ndr, &r->bits)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bits_0, 0);
+ }
+ if (r->bits) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->bits, 1260));
+ }
+ if (r->bits) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->bits, r->units_per_week / 8));
+ }
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_LogonHours(struct ndr_print *ndr, const char *name, const struct samr_LogonHours *r)
+{
+ ndr_print_struct(ndr, name, "samr_LogonHours");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_uint16(ndr, "units_per_week", r->units_per_week);
+ ndr_print_ptr(ndr, "bits", r->bits);
+ ndr->depth++;
+ if (r->bits) {
+ ndr_print_array_uint8(ndr, "bits", r->bits, r->units_per_week / 8);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo3(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->primary_gid));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->home_directory));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->home_drive));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->logon_script));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->profile_path));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->workstations));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_logon));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_logoff));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_password_change));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->allow_password_change));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->force_password_change));
+ NDR_CHECK(ndr_push_samr_LogonHours(ndr, NDR_SCALARS, &r->logon_hours));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->bad_password_count));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->logon_count));
+ NDR_CHECK(ndr_push_samr_AcctFlags(ndr, NDR_SCALARS, r->acct_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->home_directory));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->home_drive));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->logon_script));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->profile_path));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->workstations));
+ NDR_CHECK(ndr_push_samr_LogonHours(ndr, NDR_BUFFERS, &r->logon_hours));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo3(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->primary_gid));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->home_directory));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->home_drive));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->logon_script));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->profile_path));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->workstations));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_logon));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_logoff));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_password_change));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->allow_password_change));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->force_password_change));
+ NDR_CHECK(ndr_pull_samr_LogonHours(ndr, NDR_SCALARS, &r->logon_hours));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->bad_password_count));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->logon_count));
+ NDR_CHECK(ndr_pull_samr_AcctFlags(ndr, NDR_SCALARS, &r->acct_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->home_directory));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->home_drive));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->logon_script));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->profile_path));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->workstations));
+ NDR_CHECK(ndr_pull_samr_LogonHours(ndr, NDR_BUFFERS, &r->logon_hours));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo3(struct ndr_print *ndr, const char *name, const struct samr_UserInfo3 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo3");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "account_name", &r->account_name);
+ ndr_print_lsa_String(ndr, "full_name", &r->full_name);
+ ndr_print_uint32(ndr, "rid", r->rid);
+ ndr_print_uint32(ndr, "primary_gid", r->primary_gid);
+ ndr_print_lsa_String(ndr, "home_directory", &r->home_directory);
+ ndr_print_lsa_String(ndr, "home_drive", &r->home_drive);
+ ndr_print_lsa_String(ndr, "logon_script", &r->logon_script);
+ ndr_print_lsa_String(ndr, "profile_path", &r->profile_path);
+ ndr_print_lsa_String(ndr, "workstations", &r->workstations);
+ ndr_print_NTTIME(ndr, "last_logon", r->last_logon);
+ ndr_print_NTTIME(ndr, "last_logoff", r->last_logoff);
+ ndr_print_NTTIME(ndr, "last_password_change", r->last_password_change);
+ ndr_print_NTTIME(ndr, "allow_password_change", r->allow_password_change);
+ ndr_print_NTTIME(ndr, "force_password_change", r->force_password_change);
+ ndr_print_samr_LogonHours(ndr, "logon_hours", &r->logon_hours);
+ ndr_print_uint16(ndr, "bad_password_count", r->bad_password_count);
+ ndr_print_uint16(ndr, "logon_count", r->logon_count);
+ ndr_print_samr_AcctFlags(ndr, "acct_flags", r->acct_flags);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo4(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo4 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_samr_LogonHours(ndr, NDR_SCALARS, &r->logon_hours));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_samr_LogonHours(ndr, NDR_BUFFERS, &r->logon_hours));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo4(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo4 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_samr_LogonHours(ndr, NDR_SCALARS, &r->logon_hours));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_samr_LogonHours(ndr, NDR_BUFFERS, &r->logon_hours));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo4(struct ndr_print *ndr, const char *name, const struct samr_UserInfo4 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo4");
+ ndr->depth++;
+ ndr_print_samr_LogonHours(ndr, "logon_hours", &r->logon_hours);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo5(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo5 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->primary_gid));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->home_directory));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->home_drive));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->logon_script));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->profile_path));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->description));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->workstations));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_logon));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_logoff));
+ NDR_CHECK(ndr_push_samr_LogonHours(ndr, NDR_SCALARS, &r->logon_hours));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->bad_password_count));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->logon_count));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_password_change));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->acct_expiry));
+ NDR_CHECK(ndr_push_samr_AcctFlags(ndr, NDR_SCALARS, r->acct_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->home_directory));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->home_drive));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->logon_script));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->profile_path));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->workstations));
+ NDR_CHECK(ndr_push_samr_LogonHours(ndr, NDR_BUFFERS, &r->logon_hours));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo5(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo5 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->primary_gid));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->home_directory));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->home_drive));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->logon_script));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->profile_path));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->description));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->workstations));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_logon));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_logoff));
+ NDR_CHECK(ndr_pull_samr_LogonHours(ndr, NDR_SCALARS, &r->logon_hours));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->bad_password_count));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->logon_count));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_password_change));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->acct_expiry));
+ NDR_CHECK(ndr_pull_samr_AcctFlags(ndr, NDR_SCALARS, &r->acct_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->home_directory));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->home_drive));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->logon_script));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->profile_path));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->workstations));
+ NDR_CHECK(ndr_pull_samr_LogonHours(ndr, NDR_BUFFERS, &r->logon_hours));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo5(struct ndr_print *ndr, const char *name, const struct samr_UserInfo5 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo5");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "account_name", &r->account_name);
+ ndr_print_lsa_String(ndr, "full_name", &r->full_name);
+ ndr_print_uint32(ndr, "rid", r->rid);
+ ndr_print_uint32(ndr, "primary_gid", r->primary_gid);
+ ndr_print_lsa_String(ndr, "home_directory", &r->home_directory);
+ ndr_print_lsa_String(ndr, "home_drive", &r->home_drive);
+ ndr_print_lsa_String(ndr, "logon_script", &r->logon_script);
+ ndr_print_lsa_String(ndr, "profile_path", &r->profile_path);
+ ndr_print_lsa_String(ndr, "description", &r->description);
+ ndr_print_lsa_String(ndr, "workstations", &r->workstations);
+ ndr_print_NTTIME(ndr, "last_logon", r->last_logon);
+ ndr_print_NTTIME(ndr, "last_logoff", r->last_logoff);
+ ndr_print_samr_LogonHours(ndr, "logon_hours", &r->logon_hours);
+ ndr_print_uint16(ndr, "bad_password_count", r->bad_password_count);
+ ndr_print_uint16(ndr, "logon_count", r->logon_count);
+ ndr_print_NTTIME(ndr, "last_password_change", r->last_password_change);
+ ndr_print_NTTIME(ndr, "acct_expiry", r->acct_expiry);
+ ndr_print_samr_AcctFlags(ndr, "acct_flags", r->acct_flags);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo6(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo6 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo6(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo6 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo6(struct ndr_print *ndr, const char *name, const struct samr_UserInfo6 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo6");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "account_name", &r->account_name);
+ ndr_print_lsa_String(ndr, "full_name", &r->full_name);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo7(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo7 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo7(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo7 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo7(struct ndr_print *ndr, const char *name, const struct samr_UserInfo7 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo7");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "account_name", &r->account_name);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo8(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo8 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo8(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo8 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo8(struct ndr_print *ndr, const char *name, const struct samr_UserInfo8 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo8");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "full_name", &r->full_name);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo9(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo9 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->primary_gid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo9(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo9 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->primary_gid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo9(struct ndr_print *ndr, const char *name, const struct samr_UserInfo9 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo9");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "primary_gid", r->primary_gid);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo10(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo10 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->home_directory));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->home_drive));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->home_directory));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->home_drive));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo10(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo10 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->home_directory));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->home_drive));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->home_directory));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->home_drive));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo10(struct ndr_print *ndr, const char *name, const struct samr_UserInfo10 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo10");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "home_directory", &r->home_directory);
+ ndr_print_lsa_String(ndr, "home_drive", &r->home_drive);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo11(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo11 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->logon_script));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->logon_script));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo11(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo11 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->logon_script));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->logon_script));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo11(struct ndr_print *ndr, const char *name, const struct samr_UserInfo11 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo11");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "logon_script", &r->logon_script);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo12(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo12 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->profile_path));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->profile_path));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo12(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo12 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->profile_path));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->profile_path));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo12(struct ndr_print *ndr, const char *name, const struct samr_UserInfo12 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo12");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "profile_path", &r->profile_path);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo13(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo13 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->description));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo13(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo13 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->description));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo13(struct ndr_print *ndr, const char *name, const struct samr_UserInfo13 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo13");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "description", &r->description);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo14(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo14 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->workstations));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->workstations));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo14(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo14 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->workstations));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->workstations));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo14(struct ndr_print *ndr, const char *name, const struct samr_UserInfo14 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo14");
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "workstations", &r->workstations);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo16(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo16 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_samr_AcctFlags(ndr, NDR_SCALARS, r->acct_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo16(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo16 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_samr_AcctFlags(ndr, NDR_SCALARS, &r->acct_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo16(struct ndr_print *ndr, const char *name, const struct samr_UserInfo16 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo16");
+ ndr->depth++;
+ ndr_print_samr_AcctFlags(ndr, "acct_flags", r->acct_flags);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo17(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo17 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->acct_expiry));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo17(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo17 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->acct_expiry));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo17(struct ndr_print *ndr, const char *name, const struct samr_UserInfo17 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo17");
+ ndr->depth++;
+ ndr_print_NTTIME(ndr, "acct_expiry", r->acct_expiry);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_Password(struct ndr_push *ndr, int ndr_flags, const struct samr_Password *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->hash, 16));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_Password(struct ndr_pull *ndr, int ndr_flags, struct samr_Password *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->hash, 16));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_Password(struct ndr_print *ndr, const char *name, const struct samr_Password *r)
+{
+ ndr_print_struct(ndr, name, "samr_Password");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "hash", r->hash, 16);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo18(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo18 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, &r->lm_pwd));
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, &r->nt_pwd));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->lm_pwd_active));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->nt_pwd_active));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo18(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo18 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, &r->lm_pwd));
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, &r->nt_pwd));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->lm_pwd_active));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->nt_pwd_active));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo18(struct ndr_print *ndr, const char *name, const struct samr_UserInfo18 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo18");
+ ndr->depth++;
+ ndr_print_samr_Password(ndr, "lm_pwd", &r->lm_pwd);
+ ndr_print_samr_Password(ndr, "nt_pwd", &r->nt_pwd);
+ ndr_print_uint8(ndr, "lm_pwd_active", r->lm_pwd_active);
+ ndr_print_uint8(ndr, "nt_pwd_active", r->nt_pwd_active);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo20(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo20 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_lsa_BinaryString(ndr, NDR_SCALARS, &r->parameters));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_BinaryString(ndr, NDR_BUFFERS, &r->parameters));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo20(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo20 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_lsa_BinaryString(ndr, NDR_SCALARS, &r->parameters));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_BinaryString(ndr, NDR_BUFFERS, &r->parameters));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo20(struct ndr_print *ndr, const char *name, const struct samr_UserInfo20 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo20");
+ ndr->depth++;
+ ndr_print_lsa_BinaryString(ndr, "parameters", &r->parameters);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_FieldsPresent(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_FieldsPresent(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_FieldsPresent(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_ACCOUNT_NAME", SAMR_FIELD_ACCOUNT_NAME, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_FULL_NAME", SAMR_FIELD_FULL_NAME, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_RID", SAMR_FIELD_RID, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_PRIMARY_GID", SAMR_FIELD_PRIMARY_GID, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_DESCRIPTION", SAMR_FIELD_DESCRIPTION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_COMMENT", SAMR_FIELD_COMMENT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_HOME_DIRECTORY", SAMR_FIELD_HOME_DIRECTORY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_HOME_DRIVE", SAMR_FIELD_HOME_DRIVE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_LOGON_SCRIPT", SAMR_FIELD_LOGON_SCRIPT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_PROFILE_PATH", SAMR_FIELD_PROFILE_PATH, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_WORKSTATIONS", SAMR_FIELD_WORKSTATIONS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_LAST_LOGON", SAMR_FIELD_LAST_LOGON, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_LAST_LOGOFF", SAMR_FIELD_LAST_LOGOFF, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_LOGON_HOURS", SAMR_FIELD_LOGON_HOURS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_BAD_PWD_COUNT", SAMR_FIELD_BAD_PWD_COUNT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_NUM_LOGONS", SAMR_FIELD_NUM_LOGONS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_ALLOW_PWD_CHANGE", SAMR_FIELD_ALLOW_PWD_CHANGE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_FORCE_PWD_CHANGE", SAMR_FIELD_FORCE_PWD_CHANGE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_LAST_PWD_CHANGE", SAMR_FIELD_LAST_PWD_CHANGE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_ACCT_EXPIRY", SAMR_FIELD_ACCT_EXPIRY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_ACCT_FLAGS", SAMR_FIELD_ACCT_FLAGS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_PARAMETERS", SAMR_FIELD_PARAMETERS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_COUNTRY_CODE", SAMR_FIELD_COUNTRY_CODE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_CODE_PAGE", SAMR_FIELD_CODE_PAGE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_PASSWORD", SAMR_FIELD_PASSWORD, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_PASSWORD2", SAMR_FIELD_PASSWORD2, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_PRIVATE_DATA", SAMR_FIELD_PRIVATE_DATA, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_EXPIRED_FLAG", SAMR_FIELD_EXPIRED_FLAG, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_SEC_DESC", SAMR_FIELD_SEC_DESC, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_FIELD_OWF_PWD", SAMR_FIELD_OWF_PWD, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo21(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo21 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_logon));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_logoff));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_password_change));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->acct_expiry));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->allow_password_change));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->force_password_change));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->home_directory));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->home_drive));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->logon_script));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->profile_path));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->description));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->workstations));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->comment));
+ NDR_CHECK(ndr_push_lsa_BinaryString(ndr, NDR_SCALARS, &r->parameters));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->buf_count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->buffer));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->primary_gid));
+ NDR_CHECK(ndr_push_samr_AcctFlags(ndr, NDR_SCALARS, r->acct_flags));
+ NDR_CHECK(ndr_push_samr_FieldsPresent(ndr, NDR_SCALARS, r->fields_present));
+ NDR_CHECK(ndr_push_samr_LogonHours(ndr, NDR_SCALARS, &r->logon_hours));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->bad_password_count));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->logon_count));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->country_code));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->code_page));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->nt_password_set));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->lm_password_set));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->password_expired));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->unknown4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->home_directory));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->home_drive));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->logon_script));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->profile_path));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->workstations));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->comment));
+ NDR_CHECK(ndr_push_lsa_BinaryString(ndr, NDR_BUFFERS, &r->parameters));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ if (r->buffer) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->buf_count));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->buffer, r->buf_count));
+ }
+ NDR_CHECK(ndr_push_samr_LogonHours(ndr, NDR_BUFFERS, &r->logon_hours));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo21(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo21 *r)
+{
+ uint32_t _ptr_buffer;
+ TALLOC_CTX *_mem_save_buffer_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_logon));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_logoff));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_password_change));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->acct_expiry));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->allow_password_change));
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->force_password_change));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->home_directory));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->home_drive));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->logon_script));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->profile_path));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->description));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->workstations));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->comment));
+ NDR_CHECK(ndr_pull_lsa_BinaryString(ndr, NDR_SCALARS, &r->parameters));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->buf_count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_buffer));
+ if (_ptr_buffer) {
+ NDR_PULL_ALLOC(ndr, r->buffer);
+ } else {
+ r->buffer = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->primary_gid));
+ NDR_CHECK(ndr_pull_samr_AcctFlags(ndr, NDR_SCALARS, &r->acct_flags));
+ NDR_CHECK(ndr_pull_samr_FieldsPresent(ndr, NDR_SCALARS, &r->fields_present));
+ NDR_CHECK(ndr_pull_samr_LogonHours(ndr, NDR_SCALARS, &r->logon_hours));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->bad_password_count));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->logon_count));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->country_code));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->code_page));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->nt_password_set));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->lm_password_set));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->password_expired));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->unknown4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->home_directory));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->home_drive));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->logon_script));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->profile_path));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->workstations));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->comment));
+ NDR_CHECK(ndr_pull_lsa_BinaryString(ndr, NDR_BUFFERS, &r->parameters));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown1));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown2));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->unknown3));
+ if (r->buffer) {
+ _mem_save_buffer_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->buffer, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->buffer));
+ NDR_PULL_ALLOC_N(ndr, r->buffer, ndr_get_array_size(ndr, &r->buffer));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->buffer, ndr_get_array_size(ndr, &r->buffer)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_buffer_0, 0);
+ }
+ NDR_CHECK(ndr_pull_samr_LogonHours(ndr, NDR_BUFFERS, &r->logon_hours));
+ if (r->buffer) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->buffer, r->buf_count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo21(struct ndr_print *ndr, const char *name, const struct samr_UserInfo21 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo21");
+ ndr->depth++;
+ ndr_print_NTTIME(ndr, "last_logon", r->last_logon);
+ ndr_print_NTTIME(ndr, "last_logoff", r->last_logoff);
+ ndr_print_NTTIME(ndr, "last_password_change", r->last_password_change);
+ ndr_print_NTTIME(ndr, "acct_expiry", r->acct_expiry);
+ ndr_print_NTTIME(ndr, "allow_password_change", r->allow_password_change);
+ ndr_print_NTTIME(ndr, "force_password_change", r->force_password_change);
+ ndr_print_lsa_String(ndr, "account_name", &r->account_name);
+ ndr_print_lsa_String(ndr, "full_name", &r->full_name);
+ ndr_print_lsa_String(ndr, "home_directory", &r->home_directory);
+ ndr_print_lsa_String(ndr, "home_drive", &r->home_drive);
+ ndr_print_lsa_String(ndr, "logon_script", &r->logon_script);
+ ndr_print_lsa_String(ndr, "profile_path", &r->profile_path);
+ ndr_print_lsa_String(ndr, "description", &r->description);
+ ndr_print_lsa_String(ndr, "workstations", &r->workstations);
+ ndr_print_lsa_String(ndr, "comment", &r->comment);
+ ndr_print_lsa_BinaryString(ndr, "parameters", &r->parameters);
+ ndr_print_lsa_String(ndr, "unknown1", &r->unknown1);
+ ndr_print_lsa_String(ndr, "unknown2", &r->unknown2);
+ ndr_print_lsa_String(ndr, "unknown3", &r->unknown3);
+ ndr_print_uint32(ndr, "buf_count", r->buf_count);
+ ndr_print_ptr(ndr, "buffer", r->buffer);
+ ndr->depth++;
+ if (r->buffer) {
+ ndr_print_array_uint8(ndr, "buffer", r->buffer, r->buf_count);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "rid", r->rid);
+ ndr_print_uint32(ndr, "primary_gid", r->primary_gid);
+ ndr_print_samr_AcctFlags(ndr, "acct_flags", r->acct_flags);
+ ndr_print_samr_FieldsPresent(ndr, "fields_present", r->fields_present);
+ ndr_print_samr_LogonHours(ndr, "logon_hours", &r->logon_hours);
+ ndr_print_uint16(ndr, "bad_password_count", r->bad_password_count);
+ ndr_print_uint16(ndr, "logon_count", r->logon_count);
+ ndr_print_uint16(ndr, "country_code", r->country_code);
+ ndr_print_uint16(ndr, "code_page", r->code_page);
+ ndr_print_uint8(ndr, "nt_password_set", r->nt_password_set);
+ ndr_print_uint8(ndr, "lm_password_set", r->lm_password_set);
+ ndr_print_uint8(ndr, "password_expired", r->password_expired);
+ ndr_print_uint8(ndr, "unknown4", r->unknown4);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_CryptPassword(struct ndr_push *ndr, int ndr_flags, const struct samr_CryptPassword *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data, 516));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_CryptPassword(struct ndr_pull *ndr, int ndr_flags, struct samr_CryptPassword *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data, 516));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_CryptPassword(struct ndr_print *ndr, const char *name, const struct samr_CryptPassword *r)
+{
+ ndr_print_struct(ndr, name, "samr_CryptPassword");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "data", r->data, 516);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo23(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo23 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_samr_UserInfo21(ndr, NDR_SCALARS, &r->info));
+ NDR_CHECK(ndr_push_samr_CryptPassword(ndr, NDR_SCALARS, &r->password));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_samr_UserInfo21(ndr, NDR_BUFFERS, &r->info));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo23(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo23 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_samr_UserInfo21(ndr, NDR_SCALARS, &r->info));
+ NDR_CHECK(ndr_pull_samr_CryptPassword(ndr, NDR_SCALARS, &r->password));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_samr_UserInfo21(ndr, NDR_BUFFERS, &r->info));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo23(struct ndr_print *ndr, const char *name, const struct samr_UserInfo23 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo23");
+ ndr->depth++;
+ ndr_print_samr_UserInfo21(ndr, "info", &r->info);
+ ndr_print_samr_CryptPassword(ndr, "password", &r->password);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo24(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo24 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ NDR_CHECK(ndr_push_samr_CryptPassword(ndr, NDR_SCALARS, &r->password));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->pw_len));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo24(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo24 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_CHECK(ndr_pull_samr_CryptPassword(ndr, NDR_SCALARS, &r->password));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->pw_len));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo24(struct ndr_print *ndr, const char *name, const struct samr_UserInfo24 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo24");
+ ndr->depth++;
+ ndr_print_samr_CryptPassword(ndr, "password", &r->password);
+ ndr_print_uint8(ndr, "pw_len", r->pw_len);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_CryptPasswordEx(struct ndr_push *ndr, int ndr_flags, const struct samr_CryptPasswordEx *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data, 532));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_CryptPasswordEx(struct ndr_pull *ndr, int ndr_flags, struct samr_CryptPasswordEx *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data, 532));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_CryptPasswordEx(struct ndr_print *ndr, const char *name, const struct samr_CryptPasswordEx *r)
+{
+ ndr_print_struct(ndr, name, "samr_CryptPasswordEx");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "data", r->data, 532);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo25(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo25 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_samr_UserInfo21(ndr, NDR_SCALARS, &r->info));
+ NDR_CHECK(ndr_push_samr_CryptPasswordEx(ndr, NDR_SCALARS, &r->password));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_samr_UserInfo21(ndr, NDR_BUFFERS, &r->info));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo25(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo25 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_samr_UserInfo21(ndr, NDR_SCALARS, &r->info));
+ NDR_CHECK(ndr_pull_samr_CryptPasswordEx(ndr, NDR_SCALARS, &r->password));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_samr_UserInfo21(ndr, NDR_BUFFERS, &r->info));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo25(struct ndr_print *ndr, const char *name, const struct samr_UserInfo25 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo25");
+ ndr->depth++;
+ ndr_print_samr_UserInfo21(ndr, "info", &r->info);
+ ndr_print_samr_CryptPasswordEx(ndr, "password", &r->password);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo26(struct ndr_push *ndr, int ndr_flags, const struct samr_UserInfo26 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ NDR_CHECK(ndr_push_samr_CryptPasswordEx(ndr, NDR_SCALARS, &r->password));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->pw_len));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo26(struct ndr_pull *ndr, int ndr_flags, struct samr_UserInfo26 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_CHECK(ndr_pull_samr_CryptPasswordEx(ndr, NDR_SCALARS, &r->password));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->pw_len));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo26(struct ndr_print *ndr, const char *name, const struct samr_UserInfo26 *r)
+{
+ ndr_print_struct(ndr, name, "samr_UserInfo26");
+ ndr->depth++;
+ ndr_print_samr_CryptPasswordEx(ndr, "password", &r->password);
+ ndr_print_uint8(ndr, "pw_len", r->pw_len);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_UserInfo(struct ndr_push *ndr, int ndr_flags, const union samr_UserInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_samr_UserInfo1(ndr, NDR_SCALARS, &r->info1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_samr_UserInfo2(ndr, NDR_SCALARS, &r->info2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_samr_UserInfo3(ndr, NDR_SCALARS, &r->info3));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_push_samr_UserInfo4(ndr, NDR_SCALARS, &r->info4));
+ break; }
+
+ case 5: {
+ NDR_CHECK(ndr_push_samr_UserInfo5(ndr, NDR_SCALARS, &r->info5));
+ break; }
+
+ case 6: {
+ NDR_CHECK(ndr_push_samr_UserInfo6(ndr, NDR_SCALARS, &r->info6));
+ break; }
+
+ case 7: {
+ NDR_CHECK(ndr_push_samr_UserInfo7(ndr, NDR_SCALARS, &r->info7));
+ break; }
+
+ case 8: {
+ NDR_CHECK(ndr_push_samr_UserInfo8(ndr, NDR_SCALARS, &r->info8));
+ break; }
+
+ case 9: {
+ NDR_CHECK(ndr_push_samr_UserInfo9(ndr, NDR_SCALARS, &r->info9));
+ break; }
+
+ case 10: {
+ NDR_CHECK(ndr_push_samr_UserInfo10(ndr, NDR_SCALARS, &r->info10));
+ break; }
+
+ case 11: {
+ NDR_CHECK(ndr_push_samr_UserInfo11(ndr, NDR_SCALARS, &r->info11));
+ break; }
+
+ case 12: {
+ NDR_CHECK(ndr_push_samr_UserInfo12(ndr, NDR_SCALARS, &r->info12));
+ break; }
+
+ case 13: {
+ NDR_CHECK(ndr_push_samr_UserInfo13(ndr, NDR_SCALARS, &r->info13));
+ break; }
+
+ case 14: {
+ NDR_CHECK(ndr_push_samr_UserInfo14(ndr, NDR_SCALARS, &r->info14));
+ break; }
+
+ case 16: {
+ NDR_CHECK(ndr_push_samr_UserInfo16(ndr, NDR_SCALARS, &r->info16));
+ break; }
+
+ case 17: {
+ NDR_CHECK(ndr_push_samr_UserInfo17(ndr, NDR_SCALARS, &r->info17));
+ break; }
+
+ case 18: {
+ NDR_CHECK(ndr_push_samr_UserInfo18(ndr, NDR_SCALARS, &r->info18));
+ break; }
+
+ case 20: {
+ NDR_CHECK(ndr_push_samr_UserInfo20(ndr, NDR_SCALARS, &r->info20));
+ break; }
+
+ case 21: {
+ NDR_CHECK(ndr_push_samr_UserInfo21(ndr, NDR_SCALARS, &r->info21));
+ break; }
+
+ case 23: {
+ NDR_CHECK(ndr_push_samr_UserInfo23(ndr, NDR_SCALARS, &r->info23));
+ break; }
+
+ case 24: {
+ NDR_CHECK(ndr_push_samr_UserInfo24(ndr, NDR_SCALARS, &r->info24));
+ break; }
+
+ case 25: {
+ NDR_CHECK(ndr_push_samr_UserInfo25(ndr, NDR_SCALARS, &r->info25));
+ break; }
+
+ case 26: {
+ NDR_CHECK(ndr_push_samr_UserInfo26(ndr, NDR_SCALARS, &r->info26));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_samr_UserInfo1(ndr, NDR_BUFFERS, &r->info1));
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_push_samr_UserInfo2(ndr, NDR_BUFFERS, &r->info2));
+ break;
+
+ case 3:
+ NDR_CHECK(ndr_push_samr_UserInfo3(ndr, NDR_BUFFERS, &r->info3));
+ break;
+
+ case 4:
+ NDR_CHECK(ndr_push_samr_UserInfo4(ndr, NDR_BUFFERS, &r->info4));
+ break;
+
+ case 5:
+ NDR_CHECK(ndr_push_samr_UserInfo5(ndr, NDR_BUFFERS, &r->info5));
+ break;
+
+ case 6:
+ NDR_CHECK(ndr_push_samr_UserInfo6(ndr, NDR_BUFFERS, &r->info6));
+ break;
+
+ case 7:
+ NDR_CHECK(ndr_push_samr_UserInfo7(ndr, NDR_BUFFERS, &r->info7));
+ break;
+
+ case 8:
+ NDR_CHECK(ndr_push_samr_UserInfo8(ndr, NDR_BUFFERS, &r->info8));
+ break;
+
+ case 9:
+ break;
+
+ case 10:
+ NDR_CHECK(ndr_push_samr_UserInfo10(ndr, NDR_BUFFERS, &r->info10));
+ break;
+
+ case 11:
+ NDR_CHECK(ndr_push_samr_UserInfo11(ndr, NDR_BUFFERS, &r->info11));
+ break;
+
+ case 12:
+ NDR_CHECK(ndr_push_samr_UserInfo12(ndr, NDR_BUFFERS, &r->info12));
+ break;
+
+ case 13:
+ NDR_CHECK(ndr_push_samr_UserInfo13(ndr, NDR_BUFFERS, &r->info13));
+ break;
+
+ case 14:
+ NDR_CHECK(ndr_push_samr_UserInfo14(ndr, NDR_BUFFERS, &r->info14));
+ break;
+
+ case 16:
+ break;
+
+ case 17:
+ break;
+
+ case 18:
+ break;
+
+ case 20:
+ NDR_CHECK(ndr_push_samr_UserInfo20(ndr, NDR_BUFFERS, &r->info20));
+ break;
+
+ case 21:
+ NDR_CHECK(ndr_push_samr_UserInfo21(ndr, NDR_BUFFERS, &r->info21));
+ break;
+
+ case 23:
+ NDR_CHECK(ndr_push_samr_UserInfo23(ndr, NDR_BUFFERS, &r->info23));
+ break;
+
+ case 24:
+ break;
+
+ case 25:
+ NDR_CHECK(ndr_push_samr_UserInfo25(ndr, NDR_BUFFERS, &r->info25));
+ break;
+
+ case 26:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_UserInfo(struct ndr_pull *ndr, int ndr_flags, union samr_UserInfo *r)
+{
+ int level;
+ uint16_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_samr_UserInfo1(ndr, NDR_SCALARS, &r->info1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_pull_samr_UserInfo2(ndr, NDR_SCALARS, &r->info2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_pull_samr_UserInfo3(ndr, NDR_SCALARS, &r->info3));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_pull_samr_UserInfo4(ndr, NDR_SCALARS, &r->info4));
+ break; }
+
+ case 5: {
+ NDR_CHECK(ndr_pull_samr_UserInfo5(ndr, NDR_SCALARS, &r->info5));
+ break; }
+
+ case 6: {
+ NDR_CHECK(ndr_pull_samr_UserInfo6(ndr, NDR_SCALARS, &r->info6));
+ break; }
+
+ case 7: {
+ NDR_CHECK(ndr_pull_samr_UserInfo7(ndr, NDR_SCALARS, &r->info7));
+ break; }
+
+ case 8: {
+ NDR_CHECK(ndr_pull_samr_UserInfo8(ndr, NDR_SCALARS, &r->info8));
+ break; }
+
+ case 9: {
+ NDR_CHECK(ndr_pull_samr_UserInfo9(ndr, NDR_SCALARS, &r->info9));
+ break; }
+
+ case 10: {
+ NDR_CHECK(ndr_pull_samr_UserInfo10(ndr, NDR_SCALARS, &r->info10));
+ break; }
+
+ case 11: {
+ NDR_CHECK(ndr_pull_samr_UserInfo11(ndr, NDR_SCALARS, &r->info11));
+ break; }
+
+ case 12: {
+ NDR_CHECK(ndr_pull_samr_UserInfo12(ndr, NDR_SCALARS, &r->info12));
+ break; }
+
+ case 13: {
+ NDR_CHECK(ndr_pull_samr_UserInfo13(ndr, NDR_SCALARS, &r->info13));
+ break; }
+
+ case 14: {
+ NDR_CHECK(ndr_pull_samr_UserInfo14(ndr, NDR_SCALARS, &r->info14));
+ break; }
+
+ case 16: {
+ NDR_CHECK(ndr_pull_samr_UserInfo16(ndr, NDR_SCALARS, &r->info16));
+ break; }
+
+ case 17: {
+ NDR_CHECK(ndr_pull_samr_UserInfo17(ndr, NDR_SCALARS, &r->info17));
+ break; }
+
+ case 18: {
+ NDR_CHECK(ndr_pull_samr_UserInfo18(ndr, NDR_SCALARS, &r->info18));
+ break; }
+
+ case 20: {
+ NDR_CHECK(ndr_pull_samr_UserInfo20(ndr, NDR_SCALARS, &r->info20));
+ break; }
+
+ case 21: {
+ NDR_CHECK(ndr_pull_samr_UserInfo21(ndr, NDR_SCALARS, &r->info21));
+ break; }
+
+ case 23: {
+ NDR_CHECK(ndr_pull_samr_UserInfo23(ndr, NDR_SCALARS, &r->info23));
+ break; }
+
+ case 24: {
+ NDR_CHECK(ndr_pull_samr_UserInfo24(ndr, NDR_SCALARS, &r->info24));
+ break; }
+
+ case 25: {
+ NDR_CHECK(ndr_pull_samr_UserInfo25(ndr, NDR_SCALARS, &r->info25));
+ break; }
+
+ case 26: {
+ NDR_CHECK(ndr_pull_samr_UserInfo26(ndr, NDR_SCALARS, &r->info26));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_samr_UserInfo1(ndr, NDR_BUFFERS, &r->info1));
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_pull_samr_UserInfo2(ndr, NDR_BUFFERS, &r->info2));
+ break;
+
+ case 3:
+ NDR_CHECK(ndr_pull_samr_UserInfo3(ndr, NDR_BUFFERS, &r->info3));
+ break;
+
+ case 4:
+ NDR_CHECK(ndr_pull_samr_UserInfo4(ndr, NDR_BUFFERS, &r->info4));
+ break;
+
+ case 5:
+ NDR_CHECK(ndr_pull_samr_UserInfo5(ndr, NDR_BUFFERS, &r->info5));
+ break;
+
+ case 6:
+ NDR_CHECK(ndr_pull_samr_UserInfo6(ndr, NDR_BUFFERS, &r->info6));
+ break;
+
+ case 7:
+ NDR_CHECK(ndr_pull_samr_UserInfo7(ndr, NDR_BUFFERS, &r->info7));
+ break;
+
+ case 8:
+ NDR_CHECK(ndr_pull_samr_UserInfo8(ndr, NDR_BUFFERS, &r->info8));
+ break;
+
+ case 9:
+ break;
+
+ case 10:
+ NDR_CHECK(ndr_pull_samr_UserInfo10(ndr, NDR_BUFFERS, &r->info10));
+ break;
+
+ case 11:
+ NDR_CHECK(ndr_pull_samr_UserInfo11(ndr, NDR_BUFFERS, &r->info11));
+ break;
+
+ case 12:
+ NDR_CHECK(ndr_pull_samr_UserInfo12(ndr, NDR_BUFFERS, &r->info12));
+ break;
+
+ case 13:
+ NDR_CHECK(ndr_pull_samr_UserInfo13(ndr, NDR_BUFFERS, &r->info13));
+ break;
+
+ case 14:
+ NDR_CHECK(ndr_pull_samr_UserInfo14(ndr, NDR_BUFFERS, &r->info14));
+ break;
+
+ case 16:
+ break;
+
+ case 17:
+ break;
+
+ case 18:
+ break;
+
+ case 20:
+ NDR_CHECK(ndr_pull_samr_UserInfo20(ndr, NDR_BUFFERS, &r->info20));
+ break;
+
+ case 21:
+ NDR_CHECK(ndr_pull_samr_UserInfo21(ndr, NDR_BUFFERS, &r->info21));
+ break;
+
+ case 23:
+ NDR_CHECK(ndr_pull_samr_UserInfo23(ndr, NDR_BUFFERS, &r->info23));
+ break;
+
+ case 24:
+ break;
+
+ case 25:
+ NDR_CHECK(ndr_pull_samr_UserInfo25(ndr, NDR_BUFFERS, &r->info25));
+ break;
+
+ case 26:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_UserInfo(struct ndr_print *ndr, const char *name, const union samr_UserInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "samr_UserInfo");
+ switch (level) {
+ case 1:
+ ndr_print_samr_UserInfo1(ndr, "info1", &r->info1);
+ break;
+
+ case 2:
+ ndr_print_samr_UserInfo2(ndr, "info2", &r->info2);
+ break;
+
+ case 3:
+ ndr_print_samr_UserInfo3(ndr, "info3", &r->info3);
+ break;
+
+ case 4:
+ ndr_print_samr_UserInfo4(ndr, "info4", &r->info4);
+ break;
+
+ case 5:
+ ndr_print_samr_UserInfo5(ndr, "info5", &r->info5);
+ break;
+
+ case 6:
+ ndr_print_samr_UserInfo6(ndr, "info6", &r->info6);
+ break;
+
+ case 7:
+ ndr_print_samr_UserInfo7(ndr, "info7", &r->info7);
+ break;
+
+ case 8:
+ ndr_print_samr_UserInfo8(ndr, "info8", &r->info8);
+ break;
+
+ case 9:
+ ndr_print_samr_UserInfo9(ndr, "info9", &r->info9);
+ break;
+
+ case 10:
+ ndr_print_samr_UserInfo10(ndr, "info10", &r->info10);
+ break;
+
+ case 11:
+ ndr_print_samr_UserInfo11(ndr, "info11", &r->info11);
+ break;
+
+ case 12:
+ ndr_print_samr_UserInfo12(ndr, "info12", &r->info12);
+ break;
+
+ case 13:
+ ndr_print_samr_UserInfo13(ndr, "info13", &r->info13);
+ break;
+
+ case 14:
+ ndr_print_samr_UserInfo14(ndr, "info14", &r->info14);
+ break;
+
+ case 16:
+ ndr_print_samr_UserInfo16(ndr, "info16", &r->info16);
+ break;
+
+ case 17:
+ ndr_print_samr_UserInfo17(ndr, "info17", &r->info17);
+ break;
+
+ case 18:
+ ndr_print_samr_UserInfo18(ndr, "info18", &r->info18);
+ break;
+
+ case 20:
+ ndr_print_samr_UserInfo20(ndr, "info20", &r->info20);
+ break;
+
+ case 21:
+ ndr_print_samr_UserInfo21(ndr, "info21", &r->info21);
+ break;
+
+ case 23:
+ ndr_print_samr_UserInfo23(ndr, "info23", &r->info23);
+ break;
+
+ case 24:
+ ndr_print_samr_UserInfo24(ndr, "info24", &r->info24);
+ break;
+
+ case 25:
+ ndr_print_samr_UserInfo25(ndr, "info25", &r->info25);
+ break;
+
+ case 26:
+ ndr_print_samr_UserInfo26(ndr, "info26", &r->info26);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_RidWithAttribute(struct ndr_push *ndr, int ndr_flags, const struct samr_RidWithAttribute *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ NDR_CHECK(ndr_push_samr_GroupAttrs(ndr, NDR_SCALARS, r->attributes));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_RidWithAttribute(struct ndr_pull *ndr, int ndr_flags, struct samr_RidWithAttribute *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ NDR_CHECK(ndr_pull_samr_GroupAttrs(ndr, NDR_SCALARS, &r->attributes));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_RidWithAttribute(struct ndr_print *ndr, const char *name, const struct samr_RidWithAttribute *r)
+{
+ ndr_print_struct(ndr, name, "samr_RidWithAttribute");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "rid", r->rid);
+ ndr_print_samr_GroupAttrs(ndr, "attributes", r->attributes);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_RidWithAttributeArray(struct ndr_push *ndr, int ndr_flags, const struct samr_RidWithAttributeArray *r)
+{
+ uint32_t cntr_rids_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->rids));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->rids) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_rids_1 = 0; cntr_rids_1 < r->count; cntr_rids_1++) {
+ NDR_CHECK(ndr_push_samr_RidWithAttribute(ndr, NDR_SCALARS, &r->rids[cntr_rids_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_RidWithAttributeArray(struct ndr_pull *ndr, int ndr_flags, struct samr_RidWithAttributeArray *r)
+{
+ uint32_t _ptr_rids;
+ uint32_t cntr_rids_1;
+ TALLOC_CTX *_mem_save_rids_0;
+ TALLOC_CTX *_mem_save_rids_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_rids));
+ if (_ptr_rids) {
+ NDR_PULL_ALLOC(ndr, r->rids);
+ } else {
+ r->rids = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->rids) {
+ _mem_save_rids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->rids, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->rids));
+ NDR_PULL_ALLOC_N(ndr, r->rids, ndr_get_array_size(ndr, &r->rids));
+ _mem_save_rids_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->rids, 0);
+ for (cntr_rids_1 = 0; cntr_rids_1 < r->count; cntr_rids_1++) {
+ NDR_CHECK(ndr_pull_samr_RidWithAttribute(ndr, NDR_SCALARS, &r->rids[cntr_rids_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rids_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rids_0, 0);
+ }
+ if (r->rids) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->rids, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_RidWithAttributeArray(struct ndr_print *ndr, const char *name, const struct samr_RidWithAttributeArray *r)
+{
+ uint32_t cntr_rids_1;
+ ndr_print_struct(ndr, name, "samr_RidWithAttributeArray");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "rids", r->rids);
+ ndr->depth++;
+ if (r->rids) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "rids", (int)r->count);
+ ndr->depth++;
+ for (cntr_rids_1=0;cntr_rids_1<r->count;cntr_rids_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_rids_1) != -1) {
+ ndr_print_samr_RidWithAttribute(ndr, "rids", &r->rids[cntr_rids_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DispEntryGeneral(struct ndr_push *ndr, int ndr_flags, const struct samr_DispEntryGeneral *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->idx));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ NDR_CHECK(ndr_push_samr_AcctFlags(ndr, NDR_SCALARS, r->acct_flags));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->description));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DispEntryGeneral(struct ndr_pull *ndr, int ndr_flags, struct samr_DispEntryGeneral *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->idx));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ NDR_CHECK(ndr_pull_samr_AcctFlags(ndr, NDR_SCALARS, &r->acct_flags));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->description));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->full_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->full_name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DispEntryGeneral(struct ndr_print *ndr, const char *name, const struct samr_DispEntryGeneral *r)
+{
+ ndr_print_struct(ndr, name, "samr_DispEntryGeneral");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "idx", r->idx);
+ ndr_print_uint32(ndr, "rid", r->rid);
+ ndr_print_samr_AcctFlags(ndr, "acct_flags", r->acct_flags);
+ ndr_print_lsa_String(ndr, "account_name", &r->account_name);
+ ndr_print_lsa_String(ndr, "description", &r->description);
+ ndr_print_lsa_String(ndr, "full_name", &r->full_name);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DispInfoGeneral(struct ndr_push *ndr, int ndr_flags, const struct samr_DispInfoGeneral *r)
+{
+ uint32_t cntr_entries_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->entries));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->entries) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_push_samr_DispEntryGeneral(ndr, NDR_SCALARS, &r->entries[cntr_entries_1]));
+ }
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_push_samr_DispEntryGeneral(ndr, NDR_BUFFERS, &r->entries[cntr_entries_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DispInfoGeneral(struct ndr_pull *ndr, int ndr_flags, struct samr_DispInfoGeneral *r)
+{
+ uint32_t _ptr_entries;
+ uint32_t cntr_entries_1;
+ TALLOC_CTX *_mem_save_entries_0;
+ TALLOC_CTX *_mem_save_entries_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_entries));
+ if (_ptr_entries) {
+ NDR_PULL_ALLOC(ndr, r->entries);
+ } else {
+ r->entries = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->entries) {
+ _mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->entries));
+ NDR_PULL_ALLOC_N(ndr, r->entries, ndr_get_array_size(ndr, &r->entries));
+ _mem_save_entries_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_pull_samr_DispEntryGeneral(ndr, NDR_SCALARS, &r->entries[cntr_entries_1]));
+ }
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_pull_samr_DispEntryGeneral(ndr, NDR_BUFFERS, &r->entries[cntr_entries_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0);
+ }
+ if (r->entries) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->entries, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DispInfoGeneral(struct ndr_print *ndr, const char *name, const struct samr_DispInfoGeneral *r)
+{
+ uint32_t cntr_entries_1;
+ ndr_print_struct(ndr, name, "samr_DispInfoGeneral");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "entries", r->entries);
+ ndr->depth++;
+ if (r->entries) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "entries", (int)r->count);
+ ndr->depth++;
+ for (cntr_entries_1=0;cntr_entries_1<r->count;cntr_entries_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_entries_1) != -1) {
+ ndr_print_samr_DispEntryGeneral(ndr, "entries", &r->entries[cntr_entries_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DispEntryFull(struct ndr_push *ndr, int ndr_flags, const struct samr_DispEntryFull *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->idx));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ NDR_CHECK(ndr_push_samr_AcctFlags(ndr, NDR_SCALARS, r->acct_flags));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->description));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DispEntryFull(struct ndr_pull *ndr, int ndr_flags, struct samr_DispEntryFull *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->idx));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ NDR_CHECK(ndr_pull_samr_AcctFlags(ndr, NDR_SCALARS, &r->acct_flags));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->description));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DispEntryFull(struct ndr_print *ndr, const char *name, const struct samr_DispEntryFull *r)
+{
+ ndr_print_struct(ndr, name, "samr_DispEntryFull");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "idx", r->idx);
+ ndr_print_uint32(ndr, "rid", r->rid);
+ ndr_print_samr_AcctFlags(ndr, "acct_flags", r->acct_flags);
+ ndr_print_lsa_String(ndr, "account_name", &r->account_name);
+ ndr_print_lsa_String(ndr, "description", &r->description);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DispInfoFull(struct ndr_push *ndr, int ndr_flags, const struct samr_DispInfoFull *r)
+{
+ uint32_t cntr_entries_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->entries));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->entries) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_push_samr_DispEntryFull(ndr, NDR_SCALARS, &r->entries[cntr_entries_1]));
+ }
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_push_samr_DispEntryFull(ndr, NDR_BUFFERS, &r->entries[cntr_entries_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DispInfoFull(struct ndr_pull *ndr, int ndr_flags, struct samr_DispInfoFull *r)
+{
+ uint32_t _ptr_entries;
+ uint32_t cntr_entries_1;
+ TALLOC_CTX *_mem_save_entries_0;
+ TALLOC_CTX *_mem_save_entries_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_entries));
+ if (_ptr_entries) {
+ NDR_PULL_ALLOC(ndr, r->entries);
+ } else {
+ r->entries = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->entries) {
+ _mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->entries));
+ NDR_PULL_ALLOC_N(ndr, r->entries, ndr_get_array_size(ndr, &r->entries));
+ _mem_save_entries_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_pull_samr_DispEntryFull(ndr, NDR_SCALARS, &r->entries[cntr_entries_1]));
+ }
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_pull_samr_DispEntryFull(ndr, NDR_BUFFERS, &r->entries[cntr_entries_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0);
+ }
+ if (r->entries) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->entries, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DispInfoFull(struct ndr_print *ndr, const char *name, const struct samr_DispInfoFull *r)
+{
+ uint32_t cntr_entries_1;
+ ndr_print_struct(ndr, name, "samr_DispInfoFull");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "entries", r->entries);
+ ndr->depth++;
+ if (r->entries) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "entries", (int)r->count);
+ ndr->depth++;
+ for (cntr_entries_1=0;cntr_entries_1<r->count;cntr_entries_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_entries_1) != -1) {
+ ndr_print_samr_DispEntryFull(ndr, "entries", &r->entries[cntr_entries_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DispEntryFullGroup(struct ndr_push *ndr, int ndr_flags, const struct samr_DispEntryFullGroup *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->idx));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rid));
+ NDR_CHECK(ndr_push_samr_GroupAttrs(ndr, NDR_SCALARS, r->acct_flags));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->description));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DispEntryFullGroup(struct ndr_pull *ndr, int ndr_flags, struct samr_DispEntryFullGroup *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->idx));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rid));
+ NDR_CHECK(ndr_pull_samr_GroupAttrs(ndr, NDR_SCALARS, &r->acct_flags));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->description));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->account_name));
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->description));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DispEntryFullGroup(struct ndr_print *ndr, const char *name, const struct samr_DispEntryFullGroup *r)
+{
+ ndr_print_struct(ndr, name, "samr_DispEntryFullGroup");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "idx", r->idx);
+ ndr_print_uint32(ndr, "rid", r->rid);
+ ndr_print_samr_GroupAttrs(ndr, "acct_flags", r->acct_flags);
+ ndr_print_lsa_String(ndr, "account_name", &r->account_name);
+ ndr_print_lsa_String(ndr, "description", &r->description);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DispInfoFullGroups(struct ndr_push *ndr, int ndr_flags, const struct samr_DispInfoFullGroups *r)
+{
+ uint32_t cntr_entries_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->entries));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->entries) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_push_samr_DispEntryFullGroup(ndr, NDR_SCALARS, &r->entries[cntr_entries_1]));
+ }
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_push_samr_DispEntryFullGroup(ndr, NDR_BUFFERS, &r->entries[cntr_entries_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DispInfoFullGroups(struct ndr_pull *ndr, int ndr_flags, struct samr_DispInfoFullGroups *r)
+{
+ uint32_t _ptr_entries;
+ uint32_t cntr_entries_1;
+ TALLOC_CTX *_mem_save_entries_0;
+ TALLOC_CTX *_mem_save_entries_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_entries));
+ if (_ptr_entries) {
+ NDR_PULL_ALLOC(ndr, r->entries);
+ } else {
+ r->entries = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->entries) {
+ _mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->entries));
+ NDR_PULL_ALLOC_N(ndr, r->entries, ndr_get_array_size(ndr, &r->entries));
+ _mem_save_entries_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_pull_samr_DispEntryFullGroup(ndr, NDR_SCALARS, &r->entries[cntr_entries_1]));
+ }
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_pull_samr_DispEntryFullGroup(ndr, NDR_BUFFERS, &r->entries[cntr_entries_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0);
+ }
+ if (r->entries) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->entries, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DispInfoFullGroups(struct ndr_print *ndr, const char *name, const struct samr_DispInfoFullGroups *r)
+{
+ uint32_t cntr_entries_1;
+ ndr_print_struct(ndr, name, "samr_DispInfoFullGroups");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "entries", r->entries);
+ ndr->depth++;
+ if (r->entries) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "entries", (int)r->count);
+ ndr->depth++;
+ for (cntr_entries_1=0;cntr_entries_1<r->count;cntr_entries_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_entries_1) != -1) {
+ ndr_print_samr_DispEntryFullGroup(ndr, "entries", &r->entries[cntr_entries_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DispEntryAscii(struct ndr_push *ndr, int ndr_flags, const struct samr_DispEntryAscii *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->idx));
+ NDR_CHECK(ndr_push_lsa_AsciiStringLarge(ndr, NDR_SCALARS, &r->account_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_lsa_AsciiStringLarge(ndr, NDR_BUFFERS, &r->account_name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DispEntryAscii(struct ndr_pull *ndr, int ndr_flags, struct samr_DispEntryAscii *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->idx));
+ NDR_CHECK(ndr_pull_lsa_AsciiStringLarge(ndr, NDR_SCALARS, &r->account_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_lsa_AsciiStringLarge(ndr, NDR_BUFFERS, &r->account_name));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DispEntryAscii(struct ndr_print *ndr, const char *name, const struct samr_DispEntryAscii *r)
+{
+ ndr_print_struct(ndr, name, "samr_DispEntryAscii");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "idx", r->idx);
+ ndr_print_lsa_AsciiStringLarge(ndr, "account_name", &r->account_name);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DispInfoAscii(struct ndr_push *ndr, int ndr_flags, const struct samr_DispInfoAscii *r)
+{
+ uint32_t cntr_entries_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->entries));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->entries) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_push_samr_DispEntryAscii(ndr, NDR_SCALARS, &r->entries[cntr_entries_1]));
+ }
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_push_samr_DispEntryAscii(ndr, NDR_BUFFERS, &r->entries[cntr_entries_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DispInfoAscii(struct ndr_pull *ndr, int ndr_flags, struct samr_DispInfoAscii *r)
+{
+ uint32_t _ptr_entries;
+ uint32_t cntr_entries_1;
+ TALLOC_CTX *_mem_save_entries_0;
+ TALLOC_CTX *_mem_save_entries_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_entries));
+ if (_ptr_entries) {
+ NDR_PULL_ALLOC(ndr, r->entries);
+ } else {
+ r->entries = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->entries) {
+ _mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->entries));
+ NDR_PULL_ALLOC_N(ndr, r->entries, ndr_get_array_size(ndr, &r->entries));
+ _mem_save_entries_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_pull_samr_DispEntryAscii(ndr, NDR_SCALARS, &r->entries[cntr_entries_1]));
+ }
+ for (cntr_entries_1 = 0; cntr_entries_1 < r->count; cntr_entries_1++) {
+ NDR_CHECK(ndr_pull_samr_DispEntryAscii(ndr, NDR_BUFFERS, &r->entries[cntr_entries_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0);
+ }
+ if (r->entries) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->entries, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DispInfoAscii(struct ndr_print *ndr, const char *name, const struct samr_DispInfoAscii *r)
+{
+ uint32_t cntr_entries_1;
+ ndr_print_struct(ndr, name, "samr_DispInfoAscii");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "entries", r->entries);
+ ndr->depth++;
+ if (r->entries) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "entries", (int)r->count);
+ ndr->depth++;
+ for (cntr_entries_1=0;cntr_entries_1<r->count;cntr_entries_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_entries_1) != -1) {
+ ndr_print_samr_DispEntryAscii(ndr, "entries", &r->entries[cntr_entries_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DispInfo(struct ndr_push *ndr, int ndr_flags, const union samr_DispInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_samr_DispInfoGeneral(ndr, NDR_SCALARS, &r->info1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_samr_DispInfoFull(ndr, NDR_SCALARS, &r->info2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_samr_DispInfoFullGroups(ndr, NDR_SCALARS, &r->info3));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_push_samr_DispInfoAscii(ndr, NDR_SCALARS, &r->info4));
+ break; }
+
+ case 5: {
+ NDR_CHECK(ndr_push_samr_DispInfoAscii(ndr, NDR_SCALARS, &r->info5));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_samr_DispInfoGeneral(ndr, NDR_BUFFERS, &r->info1));
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_push_samr_DispInfoFull(ndr, NDR_BUFFERS, &r->info2));
+ break;
+
+ case 3:
+ NDR_CHECK(ndr_push_samr_DispInfoFullGroups(ndr, NDR_BUFFERS, &r->info3));
+ break;
+
+ case 4:
+ NDR_CHECK(ndr_push_samr_DispInfoAscii(ndr, NDR_BUFFERS, &r->info4));
+ break;
+
+ case 5:
+ NDR_CHECK(ndr_push_samr_DispInfoAscii(ndr, NDR_BUFFERS, &r->info5));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DispInfo(struct ndr_pull *ndr, int ndr_flags, union samr_DispInfo *r)
+{
+ int level;
+ uint16_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_samr_DispInfoGeneral(ndr, NDR_SCALARS, &r->info1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_pull_samr_DispInfoFull(ndr, NDR_SCALARS, &r->info2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_pull_samr_DispInfoFullGroups(ndr, NDR_SCALARS, &r->info3));
+ break; }
+
+ case 4: {
+ NDR_CHECK(ndr_pull_samr_DispInfoAscii(ndr, NDR_SCALARS, &r->info4));
+ break; }
+
+ case 5: {
+ NDR_CHECK(ndr_pull_samr_DispInfoAscii(ndr, NDR_SCALARS, &r->info5));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_samr_DispInfoGeneral(ndr, NDR_BUFFERS, &r->info1));
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_pull_samr_DispInfoFull(ndr, NDR_BUFFERS, &r->info2));
+ break;
+
+ case 3:
+ NDR_CHECK(ndr_pull_samr_DispInfoFullGroups(ndr, NDR_BUFFERS, &r->info3));
+ break;
+
+ case 4:
+ NDR_CHECK(ndr_pull_samr_DispInfoAscii(ndr, NDR_BUFFERS, &r->info4));
+ break;
+
+ case 5:
+ NDR_CHECK(ndr_pull_samr_DispInfoAscii(ndr, NDR_BUFFERS, &r->info5));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DispInfo(struct ndr_print *ndr, const char *name, const union samr_DispInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "samr_DispInfo");
+ switch (level) {
+ case 1:
+ ndr_print_samr_DispInfoGeneral(ndr, "info1", &r->info1);
+ break;
+
+ case 2:
+ ndr_print_samr_DispInfoFull(ndr, "info2", &r->info2);
+ break;
+
+ case 3:
+ ndr_print_samr_DispInfoFullGroups(ndr, "info3", &r->info3);
+ break;
+
+ case 4:
+ ndr_print_samr_DispInfoAscii(ndr, "info4", &r->info4);
+ break;
+
+ case 5:
+ ndr_print_samr_DispInfoAscii(ndr, "info5", &r->info5);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_samr_PwInfo(struct ndr_push *ndr, int ndr_flags, const struct samr_PwInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->min_password_length));
+ NDR_CHECK(ndr_push_samr_PasswordProperties(ndr, NDR_SCALARS, r->password_properties));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_PwInfo(struct ndr_pull *ndr, int ndr_flags, struct samr_PwInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->min_password_length));
+ NDR_CHECK(ndr_pull_samr_PasswordProperties(ndr, NDR_SCALARS, &r->password_properties));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_PwInfo(struct ndr_print *ndr, const char *name, const struct samr_PwInfo *r)
+{
+ ndr_print_struct(ndr, name, "samr_PwInfo");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "min_password_length", r->min_password_length);
+ ndr_print_samr_PasswordProperties(ndr, "password_properties", r->password_properties);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_ConnectVersion(struct ndr_push *ndr, int ndr_flags, enum samr_ConnectVersion r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ConnectVersion(struct ndr_pull *ndr, int ndr_flags, enum samr_ConnectVersion *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ConnectVersion(struct ndr_print *ndr, const char *name, enum samr_ConnectVersion r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case SAMR_CONNECT_PRE_W2K: val = "SAMR_CONNECT_PRE_W2K"; break;
+ case SAMR_CONNECT_W2K: val = "SAMR_CONNECT_W2K"; break;
+ case SAMR_CONNECT_AFTER_W2K: val = "SAMR_CONNECT_AFTER_W2K"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_samr_ChangeReject(struct ndr_push *ndr, int ndr_flags, const struct samr_ChangeReject *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_samr_RejectReason(ndr, NDR_SCALARS, r->reason));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ChangeReject(struct ndr_pull *ndr, int ndr_flags, struct samr_ChangeReject *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_samr_RejectReason(ndr, NDR_SCALARS, &r->reason));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ChangeReject(struct ndr_print *ndr, const char *name, const struct samr_ChangeReject *r)
+{
+ ndr_print_struct(ndr, name, "samr_ChangeReject");
+ ndr->depth++;
+ ndr_print_samr_RejectReason(ndr, "reason", r->reason);
+ ndr_print_uint32(ndr, "unknown1", r->unknown1);
+ ndr_print_uint32(ndr, "unknown2", r->unknown2);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_ConnectInfo1(struct ndr_push *ndr, int ndr_flags, const struct samr_ConnectInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_samr_ConnectVersion(ndr, NDR_SCALARS, r->client_version));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ConnectInfo1(struct ndr_pull *ndr, int ndr_flags, struct samr_ConnectInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_samr_ConnectVersion(ndr, NDR_SCALARS, &r->client_version));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ConnectInfo1(struct ndr_print *ndr, const char *name, const struct samr_ConnectInfo1 *r)
+{
+ ndr_print_struct(ndr, name, "samr_ConnectInfo1");
+ ndr->depth++;
+ ndr_print_samr_ConnectVersion(ndr, "client_version", r->client_version);
+ ndr_print_uint32(ndr, "unknown2", r->unknown2);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_ConnectInfo(struct ndr_push *ndr, int ndr_flags, const union samr_ConnectInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_samr_ConnectInfo1(ndr, NDR_SCALARS, &r->info1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ConnectInfo(struct ndr_pull *ndr, int ndr_flags, union samr_ConnectInfo *r)
+{
+ int level;
+ uint32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_samr_ConnectInfo1(ndr, NDR_SCALARS, &r->info1));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ConnectInfo(struct ndr_print *ndr, const char *name, const union samr_ConnectInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "samr_ConnectInfo");
+ switch (level) {
+ case 1:
+ ndr_print_samr_ConnectInfo1(ndr, "info1", &r->info1);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_samr_ValidateFieldsPresent(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ValidateFieldsPresent(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ValidateFieldsPresent(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_VALIDATE_FIELD_PASSWORD_LAST_SET", SAMR_VALIDATE_FIELD_PASSWORD_LAST_SET, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_VALIDATE_FIELD_BAD_PASSWORD_TIME", SAMR_VALIDATE_FIELD_BAD_PASSWORD_TIME, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_VALIDATE_FIELD_LOCKOUT_TIME", SAMR_VALIDATE_FIELD_LOCKOUT_TIME, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_VALIDATE_FIELD_BAD_PASSWORD_COUNT", SAMR_VALIDATE_FIELD_BAD_PASSWORD_COUNT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_VALIDATE_FIELD_PASSWORD_HISTORY_LENGTH", SAMR_VALIDATE_FIELD_PASSWORD_HISTORY_LENGTH, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SAMR_VALIDATE_FIELD_PASSWORD_HISTORY", SAMR_VALIDATE_FIELD_PASSWORD_HISTORY, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_ValidatePasswordLevel(struct ndr_push *ndr, int ndr_flags, enum samr_ValidatePasswordLevel r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ValidatePasswordLevel(struct ndr_pull *ndr, int ndr_flags, enum samr_ValidatePasswordLevel *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ValidatePasswordLevel(struct ndr_print *ndr, const char *name, enum samr_ValidatePasswordLevel r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case NetValidateAuthentication: val = "NetValidateAuthentication"; break;
+ case NetValidatePasswordChange: val = "NetValidatePasswordChange"; break;
+ case NetValidatePasswordReset: val = "NetValidatePasswordReset"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_samr_ValidationStatus(struct ndr_push *ndr, int ndr_flags, enum samr_ValidationStatus r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ValidationStatus(struct ndr_pull *ndr, int ndr_flags, enum samr_ValidationStatus *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ValidationStatus(struct ndr_print *ndr, const char *name, enum samr_ValidationStatus r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case SAMR_VALIDATION_STATUS_SUCCESS: val = "SAMR_VALIDATION_STATUS_SUCCESS"; break;
+ case SAMR_VALIDATION_STATUS_PASSWORD_MUST_CHANGE: val = "SAMR_VALIDATION_STATUS_PASSWORD_MUST_CHANGE"; break;
+ case SAMR_VALIDATION_STATUS_ACCOUNT_LOCKED_OUT: val = "SAMR_VALIDATION_STATUS_ACCOUNT_LOCKED_OUT"; break;
+ case SAMR_VALIDATION_STATUS_BAD_PASSWORD: val = "SAMR_VALIDATION_STATUS_BAD_PASSWORD"; break;
+ case SAMR_VALIDATION_STATUS_PWD_HISTORY_CONFLICT: val = "SAMR_VALIDATION_STATUS_PWD_HISTORY_CONFLICT"; break;
+ case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT: val = "SAMR_VALIDATION_STATUS_PWD_TOO_SHORT"; break;
+ case SAMR_VALIDATION_STATUS_PWD_TOO_LONG: val = "SAMR_VALIDATION_STATUS_PWD_TOO_LONG"; break;
+ case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH: val = "SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH"; break;
+ case SAMR_VALIDATION_STATUS_PASSWORD_TOO_RECENT: val = "SAMR_VALIDATION_STATUS_PASSWORD_TOO_RECENT"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_samr_ValidationBlob(struct ndr_push *ndr, int ndr_flags, const struct samr_ValidationBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data, r->length));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ValidationBlob(struct ndr_pull *ndr, int ndr_flags, struct samr_ValidationBlob *r)
+{
+ uint32_t _ptr_data;
+ TALLOC_CTX *_mem_save_data_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data));
+ if (_ptr_data) {
+ NDR_PULL_ALLOC(ndr, r->data);
+ } else {
+ r->data = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->data, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->data));
+ NDR_PULL_ALLOC_N(ndr, r->data, ndr_get_array_size(ndr, &r->data));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data, ndr_get_array_size(ndr, &r->data)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, 0);
+ }
+ if (r->data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->data, r->length));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ValidationBlob(struct ndr_print *ndr, const char *name, const struct samr_ValidationBlob *r)
+{
+ ndr_print_struct(ndr, name, "samr_ValidationBlob");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "length", r->length);
+ ndr_print_ptr(ndr, "data", r->data);
+ ndr->depth++;
+ if (r->data) {
+ ndr_print_array_uint8(ndr, "data", r->data, r->length);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_ValidatePasswordInfo(struct ndr_push *ndr, int ndr_flags, const struct samr_ValidatePasswordInfo *r)
+{
+ uint32_t cntr_pwd_history_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_samr_ValidateFieldsPresent(ndr, NDR_SCALARS, r->fields_present));
+ NDR_CHECK(ndr_push_NTTIME_hyper(ndr, NDR_SCALARS, r->last_password_change));
+ NDR_CHECK(ndr_push_NTTIME_hyper(ndr, NDR_SCALARS, r->bad_password_time));
+ NDR_CHECK(ndr_push_NTTIME_hyper(ndr, NDR_SCALARS, r->lockout_time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->bad_pwd_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pwd_history_len));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->pwd_history));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->pwd_history) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pwd_history_len));
+ for (cntr_pwd_history_1 = 0; cntr_pwd_history_1 < r->pwd_history_len; cntr_pwd_history_1++) {
+ NDR_CHECK(ndr_push_samr_ValidationBlob(ndr, NDR_SCALARS, &r->pwd_history[cntr_pwd_history_1]));
+ }
+ for (cntr_pwd_history_1 = 0; cntr_pwd_history_1 < r->pwd_history_len; cntr_pwd_history_1++) {
+ NDR_CHECK(ndr_push_samr_ValidationBlob(ndr, NDR_BUFFERS, &r->pwd_history[cntr_pwd_history_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ValidatePasswordInfo(struct ndr_pull *ndr, int ndr_flags, struct samr_ValidatePasswordInfo *r)
+{
+ uint32_t _ptr_pwd_history;
+ uint32_t cntr_pwd_history_1;
+ TALLOC_CTX *_mem_save_pwd_history_0;
+ TALLOC_CTX *_mem_save_pwd_history_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_samr_ValidateFieldsPresent(ndr, NDR_SCALARS, &r->fields_present));
+ NDR_CHECK(ndr_pull_NTTIME_hyper(ndr, NDR_SCALARS, &r->last_password_change));
+ NDR_CHECK(ndr_pull_NTTIME_hyper(ndr, NDR_SCALARS, &r->bad_password_time));
+ NDR_CHECK(ndr_pull_NTTIME_hyper(ndr, NDR_SCALARS, &r->lockout_time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->bad_pwd_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pwd_history_len));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_pwd_history));
+ if (_ptr_pwd_history) {
+ NDR_PULL_ALLOC(ndr, r->pwd_history);
+ } else {
+ r->pwd_history = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->pwd_history) {
+ _mem_save_pwd_history_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->pwd_history, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->pwd_history));
+ NDR_PULL_ALLOC_N(ndr, r->pwd_history, ndr_get_array_size(ndr, &r->pwd_history));
+ _mem_save_pwd_history_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->pwd_history, 0);
+ for (cntr_pwd_history_1 = 0; cntr_pwd_history_1 < r->pwd_history_len; cntr_pwd_history_1++) {
+ NDR_CHECK(ndr_pull_samr_ValidationBlob(ndr, NDR_SCALARS, &r->pwd_history[cntr_pwd_history_1]));
+ }
+ for (cntr_pwd_history_1 = 0; cntr_pwd_history_1 < r->pwd_history_len; cntr_pwd_history_1++) {
+ NDR_CHECK(ndr_pull_samr_ValidationBlob(ndr, NDR_BUFFERS, &r->pwd_history[cntr_pwd_history_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_pwd_history_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_pwd_history_0, 0);
+ }
+ if (r->pwd_history) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->pwd_history, r->pwd_history_len));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ValidatePasswordInfo(struct ndr_print *ndr, const char *name, const struct samr_ValidatePasswordInfo *r)
+{
+ uint32_t cntr_pwd_history_1;
+ ndr_print_struct(ndr, name, "samr_ValidatePasswordInfo");
+ ndr->depth++;
+ ndr_print_samr_ValidateFieldsPresent(ndr, "fields_present", r->fields_present);
+ ndr_print_NTTIME_hyper(ndr, "last_password_change", r->last_password_change);
+ ndr_print_NTTIME_hyper(ndr, "bad_password_time", r->bad_password_time);
+ ndr_print_NTTIME_hyper(ndr, "lockout_time", r->lockout_time);
+ ndr_print_uint32(ndr, "bad_pwd_count", r->bad_pwd_count);
+ ndr_print_uint32(ndr, "pwd_history_len", r->pwd_history_len);
+ ndr_print_ptr(ndr, "pwd_history", r->pwd_history);
+ ndr->depth++;
+ if (r->pwd_history) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "pwd_history", (int)r->pwd_history_len);
+ ndr->depth++;
+ for (cntr_pwd_history_1=0;cntr_pwd_history_1<r->pwd_history_len;cntr_pwd_history_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_pwd_history_1) != -1) {
+ ndr_print_samr_ValidationBlob(ndr, "pwd_history", &r->pwd_history[cntr_pwd_history_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_ValidatePasswordRepCtr(struct ndr_push *ndr, int ndr_flags, const struct samr_ValidatePasswordRepCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_samr_ValidatePasswordInfo(ndr, NDR_SCALARS, &r->info));
+ NDR_CHECK(ndr_push_samr_ValidationStatus(ndr, NDR_SCALARS, r->status));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_samr_ValidatePasswordInfo(ndr, NDR_BUFFERS, &r->info));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ValidatePasswordRepCtr(struct ndr_pull *ndr, int ndr_flags, struct samr_ValidatePasswordRepCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordInfo(ndr, NDR_SCALARS, &r->info));
+ NDR_CHECK(ndr_pull_samr_ValidationStatus(ndr, NDR_SCALARS, &r->status));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordInfo(ndr, NDR_BUFFERS, &r->info));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ValidatePasswordRepCtr(struct ndr_print *ndr, const char *name, const struct samr_ValidatePasswordRepCtr *r)
+{
+ ndr_print_struct(ndr, name, "samr_ValidatePasswordRepCtr");
+ ndr->depth++;
+ ndr_print_samr_ValidatePasswordInfo(ndr, "info", &r->info);
+ ndr_print_samr_ValidationStatus(ndr, "status", r->status);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_ValidatePasswordRep(struct ndr_push *ndr, int ndr_flags, const union samr_ValidatePasswordRep *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_samr_ValidatePasswordRepCtr(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_samr_ValidatePasswordRepCtr(ndr, NDR_SCALARS, &r->ctr2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_samr_ValidatePasswordRepCtr(ndr, NDR_SCALARS, &r->ctr3));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_samr_ValidatePasswordRepCtr(ndr, NDR_BUFFERS, &r->ctr1));
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_push_samr_ValidatePasswordRepCtr(ndr, NDR_BUFFERS, &r->ctr2));
+ break;
+
+ case 3:
+ NDR_CHECK(ndr_push_samr_ValidatePasswordRepCtr(ndr, NDR_BUFFERS, &r->ctr3));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ValidatePasswordRep(struct ndr_pull *ndr, int ndr_flags, union samr_ValidatePasswordRep *r)
+{
+ int level;
+ uint16_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordRepCtr(ndr, NDR_SCALARS, &r->ctr1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordRepCtr(ndr, NDR_SCALARS, &r->ctr2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordRepCtr(ndr, NDR_SCALARS, &r->ctr3));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordRepCtr(ndr, NDR_BUFFERS, &r->ctr1));
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordRepCtr(ndr, NDR_BUFFERS, &r->ctr2));
+ break;
+
+ case 3:
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordRepCtr(ndr, NDR_BUFFERS, &r->ctr3));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ValidatePasswordRep(struct ndr_print *ndr, const char *name, const union samr_ValidatePasswordRep *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "samr_ValidatePasswordRep");
+ switch (level) {
+ case 1:
+ ndr_print_samr_ValidatePasswordRepCtr(ndr, "ctr1", &r->ctr1);
+ break;
+
+ case 2:
+ ndr_print_samr_ValidatePasswordRepCtr(ndr, "ctr2", &r->ctr2);
+ break;
+
+ case 3:
+ ndr_print_samr_ValidatePasswordRepCtr(ndr, "ctr3", &r->ctr3);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_samr_ValidatePasswordReq3(struct ndr_push *ndr, int ndr_flags, const struct samr_ValidatePasswordReq3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_samr_ValidatePasswordInfo(ndr, NDR_SCALARS, &r->info));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->password));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->account));
+ NDR_CHECK(ndr_push_samr_ValidationBlob(ndr, NDR_SCALARS, &r->hash));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->pwd_must_change_at_next_logon));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->clear_lockout));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_samr_ValidatePasswordInfo(ndr, NDR_BUFFERS, &r->info));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->password));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->account));
+ NDR_CHECK(ndr_push_samr_ValidationBlob(ndr, NDR_BUFFERS, &r->hash));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ValidatePasswordReq3(struct ndr_pull *ndr, int ndr_flags, struct samr_ValidatePasswordReq3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordInfo(ndr, NDR_SCALARS, &r->info));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->password));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->account));
+ NDR_CHECK(ndr_pull_samr_ValidationBlob(ndr, NDR_SCALARS, &r->hash));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->pwd_must_change_at_next_logon));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->clear_lockout));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordInfo(ndr, NDR_BUFFERS, &r->info));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->password));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->account));
+ NDR_CHECK(ndr_pull_samr_ValidationBlob(ndr, NDR_BUFFERS, &r->hash));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ValidatePasswordReq3(struct ndr_print *ndr, const char *name, const struct samr_ValidatePasswordReq3 *r)
+{
+ ndr_print_struct(ndr, name, "samr_ValidatePasswordReq3");
+ ndr->depth++;
+ ndr_print_samr_ValidatePasswordInfo(ndr, "info", &r->info);
+ ndr_print_lsa_StringLarge(ndr, "password", &r->password);
+ ndr_print_lsa_StringLarge(ndr, "account", &r->account);
+ ndr_print_samr_ValidationBlob(ndr, "hash", &r->hash);
+ ndr_print_uint8(ndr, "pwd_must_change_at_next_logon", r->pwd_must_change_at_next_logon);
+ ndr_print_uint8(ndr, "clear_lockout", r->clear_lockout);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_ValidatePasswordReq2(struct ndr_push *ndr, int ndr_flags, const struct samr_ValidatePasswordReq2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_samr_ValidatePasswordInfo(ndr, NDR_SCALARS, &r->info));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->password));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_SCALARS, &r->account));
+ NDR_CHECK(ndr_push_samr_ValidationBlob(ndr, NDR_SCALARS, &r->hash));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->password_matched));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_samr_ValidatePasswordInfo(ndr, NDR_BUFFERS, &r->info));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->password));
+ NDR_CHECK(ndr_push_lsa_StringLarge(ndr, NDR_BUFFERS, &r->account));
+ NDR_CHECK(ndr_push_samr_ValidationBlob(ndr, NDR_BUFFERS, &r->hash));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ValidatePasswordReq2(struct ndr_pull *ndr, int ndr_flags, struct samr_ValidatePasswordReq2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordInfo(ndr, NDR_SCALARS, &r->info));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->password));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_SCALARS, &r->account));
+ NDR_CHECK(ndr_pull_samr_ValidationBlob(ndr, NDR_SCALARS, &r->hash));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->password_matched));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordInfo(ndr, NDR_BUFFERS, &r->info));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->password));
+ NDR_CHECK(ndr_pull_lsa_StringLarge(ndr, NDR_BUFFERS, &r->account));
+ NDR_CHECK(ndr_pull_samr_ValidationBlob(ndr, NDR_BUFFERS, &r->hash));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ValidatePasswordReq2(struct ndr_print *ndr, const char *name, const struct samr_ValidatePasswordReq2 *r)
+{
+ ndr_print_struct(ndr, name, "samr_ValidatePasswordReq2");
+ ndr->depth++;
+ ndr_print_samr_ValidatePasswordInfo(ndr, "info", &r->info);
+ ndr_print_lsa_StringLarge(ndr, "password", &r->password);
+ ndr_print_lsa_StringLarge(ndr, "account", &r->account);
+ ndr_print_samr_ValidationBlob(ndr, "hash", &r->hash);
+ ndr_print_uint8(ndr, "password_matched", r->password_matched);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_ValidatePasswordReq1(struct ndr_push *ndr, int ndr_flags, const struct samr_ValidatePasswordReq1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_samr_ValidatePasswordInfo(ndr, NDR_SCALARS, &r->info));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->password_matched));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_samr_ValidatePasswordInfo(ndr, NDR_BUFFERS, &r->info));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ValidatePasswordReq1(struct ndr_pull *ndr, int ndr_flags, struct samr_ValidatePasswordReq1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordInfo(ndr, NDR_SCALARS, &r->info));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->password_matched));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordInfo(ndr, NDR_BUFFERS, &r->info));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ValidatePasswordReq1(struct ndr_print *ndr, const char *name, const struct samr_ValidatePasswordReq1 *r)
+{
+ ndr_print_struct(ndr, name, "samr_ValidatePasswordReq1");
+ ndr->depth++;
+ ndr_print_samr_ValidatePasswordInfo(ndr, "info", &r->info);
+ ndr_print_uint8(ndr, "password_matched", r->password_matched);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_ValidatePasswordReq(struct ndr_push *ndr, int ndr_flags, const union samr_ValidatePasswordReq *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_samr_ValidatePasswordReq1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_samr_ValidatePasswordReq2(ndr, NDR_SCALARS, &r->req2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_samr_ValidatePasswordReq3(ndr, NDR_SCALARS, &r->req3));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_push_samr_ValidatePasswordReq1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_push_samr_ValidatePasswordReq2(ndr, NDR_BUFFERS, &r->req2));
+ break;
+
+ case 3:
+ NDR_CHECK(ndr_push_samr_ValidatePasswordReq3(ndr, NDR_BUFFERS, &r->req3));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ValidatePasswordReq(struct ndr_pull *ndr, int ndr_flags, union samr_ValidatePasswordReq *r)
+{
+ int level;
+ uint16_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordReq1(ndr, NDR_SCALARS, &r->req1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordReq2(ndr, NDR_SCALARS, &r->req2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordReq3(ndr, NDR_SCALARS, &r->req3));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordReq1(ndr, NDR_BUFFERS, &r->req1));
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordReq2(ndr, NDR_BUFFERS, &r->req2));
+ break;
+
+ case 3:
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordReq3(ndr, NDR_BUFFERS, &r->req3));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ValidatePasswordReq(struct ndr_print *ndr, const char *name, const union samr_ValidatePasswordReq *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "samr_ValidatePasswordReq");
+ switch (level) {
+ case 1:
+ ndr_print_samr_ValidatePasswordReq1(ndr, "req1", &r->req1);
+ break;
+
+ case 2:
+ ndr_print_samr_ValidatePasswordReq2(ndr, "req2", &r->req2);
+ break;
+
+ case 3:
+ ndr_print_samr_ValidatePasswordReq3(ndr, "req3", &r->req3);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_samr_Connect(struct ndr_push *ndr, int flags, const struct samr_Connect *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.system_name));
+ }
+ NDR_CHECK(ndr_push_samr_ConnectAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.connect_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.connect_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_Connect(struct ndr_pull *ndr, int flags, struct samr_Connect *r)
+{
+ uint32_t _ptr_system_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_connect_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.system_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_samr_ConnectAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.connect_handle);
+ ZERO_STRUCTP(r->out.connect_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.connect_handle);
+ }
+ _mem_save_connect_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.connect_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.connect_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_connect_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_Connect(struct ndr_print *ndr, const char *name, int flags, const struct samr_Connect *r)
+{
+ ndr_print_struct(ndr, name, "samr_Connect");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_Connect");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_uint16(ndr, "system_name", *r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_samr_ConnectAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_Connect");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "connect_handle", r->out.connect_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "connect_handle", r->out.connect_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_Close(struct ndr_push *ndr, int flags, const struct samr_Close *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_Close(struct ndr_pull *ndr, int flags, struct samr_Close *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ *r->out.handle = *r->in.handle;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_Close(struct ndr_print *ndr, const char *name, int flags, const struct samr_Close *r)
+{
+ ndr_print_struct(ndr, name, "samr_Close");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_Close");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_Close");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_SetSecurity(struct ndr_push *ndr, int flags, const struct samr_SetSecurity *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.handle));
+ NDR_CHECK(ndr_push_security_secinfo(ndr, NDR_SCALARS, r->in.sec_info));
+ if (r->in.sdbuf == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sdbuf));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_SetSecurity(struct ndr_pull *ndr, int flags, struct samr_SetSecurity *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sdbuf_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_security_secinfo(ndr, NDR_SCALARS, &r->in.sec_info));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sdbuf);
+ }
+ _mem_save_sdbuf_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sdbuf, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sdbuf));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sdbuf_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_SetSecurity(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetSecurity *r)
+{
+ ndr_print_struct(ndr, name, "samr_SetSecurity");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_SetSecurity");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_security_secinfo(ndr, "sec_info", r->in.sec_info);
+ ndr_print_ptr(ndr, "sdbuf", r->in.sdbuf);
+ ndr->depth++;
+ ndr_print_sec_desc_buf(ndr, "sdbuf", r->in.sdbuf);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_SetSecurity");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_QuerySecurity(struct ndr_push *ndr, int flags, const struct samr_QuerySecurity *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.handle));
+ NDR_CHECK(ndr_push_security_secinfo(ndr, NDR_SCALARS, r->in.sec_info));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.sdbuf == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.sdbuf));
+ if (*r->out.sdbuf) {
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.sdbuf));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_QuerySecurity(struct ndr_pull *ndr, int flags, struct samr_QuerySecurity *r)
+{
+ uint32_t _ptr_sdbuf;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sdbuf_0;
+ TALLOC_CTX *_mem_save_sdbuf_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_security_secinfo(ndr, NDR_SCALARS, &r->in.sec_info));
+ NDR_PULL_ALLOC(ndr, r->out.sdbuf);
+ ZERO_STRUCTP(r->out.sdbuf);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sdbuf);
+ }
+ _mem_save_sdbuf_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sdbuf, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sdbuf));
+ if (_ptr_sdbuf) {
+ NDR_PULL_ALLOC(ndr, *r->out.sdbuf);
+ } else {
+ *r->out.sdbuf = NULL;
+ }
+ if (*r->out.sdbuf) {
+ _mem_save_sdbuf_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.sdbuf, 0);
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.sdbuf));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sdbuf_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sdbuf_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_QuerySecurity(struct ndr_print *ndr, const char *name, int flags, const struct samr_QuerySecurity *r)
+{
+ ndr_print_struct(ndr, name, "samr_QuerySecurity");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_QuerySecurity");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_security_secinfo(ndr, "sec_info", r->in.sec_info);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_QuerySecurity");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sdbuf", r->out.sdbuf);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sdbuf", *r->out.sdbuf);
+ ndr->depth++;
+ if (*r->out.sdbuf) {
+ ndr_print_sec_desc_buf(ndr, "sdbuf", *r->out.sdbuf);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_Shutdown(struct ndr_push *ndr, int flags, const struct samr_Shutdown *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.connect_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.connect_handle));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_Shutdown(struct ndr_pull *ndr, int flags, struct samr_Shutdown *r)
+{
+ TALLOC_CTX *_mem_save_connect_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.connect_handle);
+ }
+ _mem_save_connect_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.connect_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.connect_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_connect_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_Shutdown(struct ndr_print *ndr, const char *name, int flags, const struct samr_Shutdown *r)
+{
+ ndr_print_struct(ndr, name, "samr_Shutdown");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_Shutdown");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "connect_handle", r->in.connect_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "connect_handle", r->in.connect_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_Shutdown");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_LookupDomain(struct ndr_push *ndr, int flags, const struct samr_LookupDomain *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.connect_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.connect_handle));
+ if (r->in.domain_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.domain_name));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.sid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.sid));
+ if (*r->out.sid) {
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.sid));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_LookupDomain(struct ndr_pull *ndr, int flags, struct samr_LookupDomain *r)
+{
+ uint32_t _ptr_sid;
+ TALLOC_CTX *_mem_save_connect_handle_0;
+ TALLOC_CTX *_mem_save_domain_name_0;
+ TALLOC_CTX *_mem_save_sid_0;
+ TALLOC_CTX *_mem_save_sid_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.connect_handle);
+ }
+ _mem_save_connect_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.connect_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.connect_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_connect_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_name);
+ }
+ _mem_save_domain_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.domain_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.sid);
+ ZERO_STRUCTP(r->out.sid);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sid);
+ }
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sid));
+ if (_ptr_sid) {
+ NDR_PULL_ALLOC(ndr, *r->out.sid);
+ } else {
+ *r->out.sid = NULL;
+ }
+ if (*r->out.sid) {
+ _mem_save_sid_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_LookupDomain(struct ndr_print *ndr, const char *name, int flags, const struct samr_LookupDomain *r)
+{
+ ndr_print_struct(ndr, name, "samr_LookupDomain");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_LookupDomain");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "connect_handle", r->in.connect_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "connect_handle", r->in.connect_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_name", r->in.domain_name);
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "domain_name", r->in.domain_name);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_LookupDomain");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sid", r->out.sid);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sid", *r->out.sid);
+ ndr->depth++;
+ if (*r->out.sid) {
+ ndr_print_dom_sid2(ndr, "sid", *r->out.sid);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_EnumDomains(struct ndr_push *ndr, int flags, const struct samr_EnumDomains *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.connect_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.connect_handle));
+ if (r->in.resume_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.resume_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ if (r->out.sam == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.sam));
+ if (*r->out.sam) {
+ NDR_CHECK(ndr_push_samr_SamArray(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.sam));
+ }
+ if (r->out.num_entries == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.num_entries));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_EnumDomains(struct ndr_pull *ndr, int flags, struct samr_EnumDomains *r)
+{
+ uint32_t _ptr_sam;
+ TALLOC_CTX *_mem_save_connect_handle_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ TALLOC_CTX *_mem_save_sam_0;
+ TALLOC_CTX *_mem_save_sam_1;
+ TALLOC_CTX *_mem_save_num_entries_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.connect_handle);
+ }
+ _mem_save_connect_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.connect_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.connect_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_connect_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ }
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ *r->out.resume_handle = *r->in.resume_handle;
+ NDR_PULL_ALLOC(ndr, r->out.sam);
+ ZERO_STRUCTP(r->out.sam);
+ NDR_PULL_ALLOC(ndr, r->out.num_entries);
+ ZERO_STRUCTP(r->out.num_entries);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ }
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sam);
+ }
+ _mem_save_sam_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sam, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sam));
+ if (_ptr_sam) {
+ NDR_PULL_ALLOC(ndr, *r->out.sam);
+ } else {
+ *r->out.sam = NULL;
+ }
+ if (*r->out.sam) {
+ _mem_save_sam_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.sam, 0);
+ NDR_CHECK(ndr_pull_samr_SamArray(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.sam));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sam_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sam_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.num_entries);
+ }
+ _mem_save_num_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.num_entries, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.num_entries));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_num_entries_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_EnumDomains(struct ndr_print *ndr, const char *name, int flags, const struct samr_EnumDomains *r)
+{
+ ndr_print_struct(ndr, name, "samr_EnumDomains");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_EnumDomains");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "connect_handle", r->in.connect_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "connect_handle", r->in.connect_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_EnumDomains");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sam", r->out.sam);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sam", *r->out.sam);
+ ndr->depth++;
+ if (*r->out.sam) {
+ ndr_print_samr_SamArray(ndr, "sam", *r->out.sam);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "num_entries", r->out.num_entries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_entries", *r->out.num_entries);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_OpenDomain(struct ndr_push *ndr, int flags, const struct samr_OpenDomain *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.connect_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.connect_handle));
+ NDR_CHECK(ndr_push_samr_DomainAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ if (r->in.sid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.domain_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_OpenDomain(struct ndr_pull *ndr, int flags, struct samr_OpenDomain *r)
+{
+ TALLOC_CTX *_mem_save_connect_handle_0;
+ TALLOC_CTX *_mem_save_sid_0;
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.connect_handle);
+ }
+ _mem_save_connect_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.connect_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.connect_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_connect_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_DomainAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sid);
+ }
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.domain_handle);
+ ZERO_STRUCTP(r->out.domain_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_OpenDomain(struct ndr_print *ndr, const char *name, int flags, const struct samr_OpenDomain *r)
+{
+ ndr_print_struct(ndr, name, "samr_OpenDomain");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_OpenDomain");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "connect_handle", r->in.connect_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "connect_handle", r->in.connect_handle);
+ ndr->depth--;
+ ndr_print_samr_DomainAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr_print_ptr(ndr, "sid", r->in.sid);
+ ndr->depth++;
+ ndr_print_dom_sid2(ndr, "sid", r->in.sid);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_OpenDomain");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->out.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->out.domain_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_QueryDomainInfo(struct ndr_push *ndr, int flags, const struct samr_QueryDomainInfo *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.info));
+ if (*r->out.info) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_samr_DomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_QueryDomainInfo(struct ndr_pull *ndr, int flags, struct samr_QueryDomainInfo *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ } else {
+ *r->out.info = NULL;
+ }
+ if (*r->out.info) {
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.info, 0);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_samr_DomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_QueryDomainInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryDomainInfo *r)
+{
+ ndr_print_struct(ndr, name, "samr_QueryDomainInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_QueryDomainInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_QueryDomainInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", *r->out.info);
+ ndr->depth++;
+ if (*r->out.info) {
+ ndr_print_set_switch_value(ndr, *r->out.info, r->in.level);
+ ndr_print_samr_DomainInfo(ndr, "info", *r->out.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_SetDomainInfo(struct ndr_push *ndr, int flags, const struct samr_SetDomainInfo *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_samr_DomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_SetDomainInfo(struct ndr_pull *ndr, int flags, struct samr_SetDomainInfo *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_samr_DomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_SetDomainInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetDomainInfo *r)
+{
+ ndr_print_struct(ndr, name, "samr_SetDomainInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_SetDomainInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.info, r->in.level);
+ ndr_print_samr_DomainInfo(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_SetDomainInfo");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_CreateDomainGroup(struct ndr_push *ndr, int flags, const struct samr_CreateDomainGroup *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ if (r->in.name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ NDR_CHECK(ndr_push_samr_GroupAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.group_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.group_handle));
+ if (r->out.rid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.rid));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_CreateDomainGroup(struct ndr_pull *ndr, int flags, struct samr_CreateDomainGroup *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_name_0;
+ TALLOC_CTX *_mem_save_group_handle_0;
+ TALLOC_CTX *_mem_save_rid_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.name);
+ }
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_GroupAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.group_handle);
+ ZERO_STRUCTP(r->out.group_handle);
+ NDR_PULL_ALLOC(ndr, r->out.rid);
+ ZERO_STRUCTP(r->out.rid);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.group_handle);
+ }
+ _mem_save_group_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.group_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.group_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.rid);
+ }
+ _mem_save_rid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.rid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.rid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_CreateDomainGroup(struct ndr_print *ndr, const char *name, int flags, const struct samr_CreateDomainGroup *r)
+{
+ ndr_print_struct(ndr, name, "samr_CreateDomainGroup");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_CreateDomainGroup");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "name", r->in.name);
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "name", r->in.name);
+ ndr->depth--;
+ ndr_print_samr_GroupAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_CreateDomainGroup");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "group_handle", r->out.group_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "group_handle", r->out.group_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "rid", r->out.rid);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "rid", *r->out.rid);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_EnumDomainGroups(struct ndr_push *ndr, int flags, const struct samr_EnumDomainGroups *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ if (r->in.resume_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_size));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.resume_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ if (r->out.sam == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.sam));
+ if (*r->out.sam) {
+ NDR_CHECK(ndr_push_samr_SamArray(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.sam));
+ }
+ if (r->out.num_entries == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.num_entries));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_EnumDomainGroups(struct ndr_pull *ndr, int flags, struct samr_EnumDomainGroups *r)
+{
+ uint32_t _ptr_sam;
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ TALLOC_CTX *_mem_save_sam_0;
+ TALLOC_CTX *_mem_save_sam_1;
+ TALLOC_CTX *_mem_save_num_entries_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ }
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_size));
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ *r->out.resume_handle = *r->in.resume_handle;
+ NDR_PULL_ALLOC(ndr, r->out.sam);
+ ZERO_STRUCTP(r->out.sam);
+ NDR_PULL_ALLOC(ndr, r->out.num_entries);
+ ZERO_STRUCTP(r->out.num_entries);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ }
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sam);
+ }
+ _mem_save_sam_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sam, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sam));
+ if (_ptr_sam) {
+ NDR_PULL_ALLOC(ndr, *r->out.sam);
+ } else {
+ *r->out.sam = NULL;
+ }
+ if (*r->out.sam) {
+ _mem_save_sam_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.sam, 0);
+ NDR_CHECK(ndr_pull_samr_SamArray(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.sam));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sam_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sam_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.num_entries);
+ }
+ _mem_save_num_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.num_entries, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.num_entries));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_num_entries_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_EnumDomainGroups(struct ndr_print *ndr, const char *name, int flags, const struct samr_EnumDomainGroups *r)
+{
+ ndr_print_struct(ndr, name, "samr_EnumDomainGroups");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_EnumDomainGroups");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_size", r->in.max_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_EnumDomainGroups");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sam", r->out.sam);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sam", *r->out.sam);
+ ndr->depth++;
+ if (*r->out.sam) {
+ ndr_print_samr_SamArray(ndr, "sam", *r->out.sam);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "num_entries", r->out.num_entries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_entries", *r->out.num_entries);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_CreateUser(struct ndr_push *ndr, int flags, const struct samr_CreateUser *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ if (r->in.account_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.account_name));
+ NDR_CHECK(ndr_push_samr_UserAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.user_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.user_handle));
+ if (r->out.rid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.rid));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_CreateUser(struct ndr_pull *ndr, int flags, struct samr_CreateUser *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_account_name_0;
+ TALLOC_CTX *_mem_save_user_handle_0;
+ TALLOC_CTX *_mem_save_rid_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.account_name);
+ }
+ _mem_save_account_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.account_name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.account_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_account_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_UserAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.user_handle);
+ ZERO_STRUCTP(r->out.user_handle);
+ NDR_PULL_ALLOC(ndr, r->out.rid);
+ ZERO_STRUCTP(r->out.rid);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.user_handle);
+ }
+ _mem_save_user_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.user_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.user_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.rid);
+ }
+ _mem_save_rid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.rid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.rid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_CreateUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_CreateUser *r)
+{
+ ndr_print_struct(ndr, name, "samr_CreateUser");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_CreateUser");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "account_name", r->in.account_name);
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "account_name", r->in.account_name);
+ ndr->depth--;
+ ndr_print_samr_UserAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_CreateUser");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "user_handle", r->out.user_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "user_handle", r->out.user_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "rid", r->out.rid);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "rid", *r->out.rid);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_EnumDomainUsers(struct ndr_push *ndr, int flags, const struct samr_EnumDomainUsers *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ if (r->in.resume_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ NDR_CHECK(ndr_push_samr_AcctFlags(ndr, NDR_SCALARS, r->in.acct_flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_size));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.resume_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ if (r->out.sam == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.sam));
+ if (*r->out.sam) {
+ NDR_CHECK(ndr_push_samr_SamArray(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.sam));
+ }
+ if (r->out.num_entries == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.num_entries));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_EnumDomainUsers(struct ndr_pull *ndr, int flags, struct samr_EnumDomainUsers *r)
+{
+ uint32_t _ptr_sam;
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ TALLOC_CTX *_mem_save_sam_0;
+ TALLOC_CTX *_mem_save_sam_1;
+ TALLOC_CTX *_mem_save_num_entries_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ }
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_AcctFlags(ndr, NDR_SCALARS, &r->in.acct_flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_size));
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ *r->out.resume_handle = *r->in.resume_handle;
+ NDR_PULL_ALLOC(ndr, r->out.sam);
+ ZERO_STRUCTP(r->out.sam);
+ NDR_PULL_ALLOC(ndr, r->out.num_entries);
+ ZERO_STRUCTP(r->out.num_entries);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ }
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sam);
+ }
+ _mem_save_sam_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sam, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sam));
+ if (_ptr_sam) {
+ NDR_PULL_ALLOC(ndr, *r->out.sam);
+ } else {
+ *r->out.sam = NULL;
+ }
+ if (*r->out.sam) {
+ _mem_save_sam_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.sam, 0);
+ NDR_CHECK(ndr_pull_samr_SamArray(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.sam));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sam_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sam_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.num_entries);
+ }
+ _mem_save_num_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.num_entries, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.num_entries));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_num_entries_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_EnumDomainUsers(struct ndr_print *ndr, const char *name, int flags, const struct samr_EnumDomainUsers *r)
+{
+ ndr_print_struct(ndr, name, "samr_EnumDomainUsers");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_EnumDomainUsers");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ ndr->depth--;
+ ndr_print_samr_AcctFlags(ndr, "acct_flags", r->in.acct_flags);
+ ndr_print_uint32(ndr, "max_size", r->in.max_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_EnumDomainUsers");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sam", r->out.sam);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sam", *r->out.sam);
+ ndr->depth++;
+ if (*r->out.sam) {
+ ndr_print_samr_SamArray(ndr, "sam", *r->out.sam);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "num_entries", r->out.num_entries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_entries", *r->out.num_entries);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_CreateDomAlias(struct ndr_push *ndr, int flags, const struct samr_CreateDomAlias *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ if (r->in.alias_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.alias_name));
+ NDR_CHECK(ndr_push_samr_AliasAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.alias_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.alias_handle));
+ if (r->out.rid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.rid));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_CreateDomAlias(struct ndr_pull *ndr, int flags, struct samr_CreateDomAlias *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_alias_name_0;
+ TALLOC_CTX *_mem_save_alias_handle_0;
+ TALLOC_CTX *_mem_save_rid_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.alias_name);
+ }
+ _mem_save_alias_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.alias_name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.alias_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alias_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_AliasAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.alias_handle);
+ ZERO_STRUCTP(r->out.alias_handle);
+ NDR_PULL_ALLOC(ndr, r->out.rid);
+ ZERO_STRUCTP(r->out.rid);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.alias_handle);
+ }
+ _mem_save_alias_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.alias_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.alias_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alias_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.rid);
+ }
+ _mem_save_rid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.rid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.rid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_CreateDomAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_CreateDomAlias *r)
+{
+ ndr_print_struct(ndr, name, "samr_CreateDomAlias");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_CreateDomAlias");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "alias_name", r->in.alias_name);
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "alias_name", r->in.alias_name);
+ ndr->depth--;
+ ndr_print_samr_AliasAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_CreateDomAlias");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "alias_handle", r->out.alias_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "alias_handle", r->out.alias_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "rid", r->out.rid);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "rid", *r->out.rid);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_EnumDomainAliases(struct ndr_push *ndr, int flags, const struct samr_EnumDomainAliases *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ if (r->in.resume_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_size));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.resume_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ if (r->out.sam == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.sam));
+ if (*r->out.sam) {
+ NDR_CHECK(ndr_push_samr_SamArray(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.sam));
+ }
+ if (r->out.num_entries == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.num_entries));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_EnumDomainAliases(struct ndr_pull *ndr, int flags, struct samr_EnumDomainAliases *r)
+{
+ uint32_t _ptr_sam;
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ TALLOC_CTX *_mem_save_sam_0;
+ TALLOC_CTX *_mem_save_sam_1;
+ TALLOC_CTX *_mem_save_num_entries_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ }
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_size));
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ *r->out.resume_handle = *r->in.resume_handle;
+ NDR_PULL_ALLOC(ndr, r->out.sam);
+ ZERO_STRUCTP(r->out.sam);
+ NDR_PULL_ALLOC(ndr, r->out.num_entries);
+ ZERO_STRUCTP(r->out.num_entries);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ }
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sam);
+ }
+ _mem_save_sam_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sam, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sam));
+ if (_ptr_sam) {
+ NDR_PULL_ALLOC(ndr, *r->out.sam);
+ } else {
+ *r->out.sam = NULL;
+ }
+ if (*r->out.sam) {
+ _mem_save_sam_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.sam, 0);
+ NDR_CHECK(ndr_pull_samr_SamArray(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.sam));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sam_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sam_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.num_entries);
+ }
+ _mem_save_num_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.num_entries, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.num_entries));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_num_entries_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_EnumDomainAliases(struct ndr_print *ndr, const char *name, int flags, const struct samr_EnumDomainAliases *r)
+{
+ ndr_print_struct(ndr, name, "samr_EnumDomainAliases");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_EnumDomainAliases");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_size", r->in.max_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_EnumDomainAliases");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sam", r->out.sam);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sam", *r->out.sam);
+ ndr->depth++;
+ if (*r->out.sam) {
+ ndr_print_samr_SamArray(ndr, "sam", *r->out.sam);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "num_entries", r->out.num_entries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_entries", *r->out.num_entries);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_GetAliasMembership(struct ndr_push *ndr, int flags, const struct samr_GetAliasMembership *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ if (r->in.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.rids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_samr_Ids(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.rids));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_GetAliasMembership(struct ndr_pull *ndr, int flags, struct samr_GetAliasMembership *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_sids_0;
+ TALLOC_CTX *_mem_save_rids_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.rids);
+ ZERO_STRUCTP(r->out.rids);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.rids);
+ }
+ _mem_save_rids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.rids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_Ids(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.rids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rids_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_GetAliasMembership(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetAliasMembership *r)
+{
+ ndr_print_struct(ndr, name, "samr_GetAliasMembership");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_GetAliasMembership");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sids", r->in.sids);
+ ndr->depth++;
+ ndr_print_lsa_SidArray(ndr, "sids", r->in.sids);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_GetAliasMembership");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "rids", r->out.rids);
+ ndr->depth++;
+ ndr_print_samr_Ids(ndr, "rids", r->out.rids);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_LookupNames(struct ndr_push *ndr, int flags, const struct samr_LookupNames *r)
+{
+ uint32_t cntr_names_0;
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_names));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 1000));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_names));
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->in.names[cntr_names_0]));
+ }
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->in.names[cntr_names_0]));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.rids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_samr_Ids(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.rids));
+ if (r->out.types == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_samr_Ids(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.types));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_LookupNames(struct ndr_pull *ndr, int flags, struct samr_LookupNames *r)
+{
+ uint32_t cntr_names_0;
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_names_0;
+ TALLOC_CTX *_mem_save_rids_0;
+ TALLOC_CTX *_mem_save_types_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.num_names));
+ if (r->in.num_names < 0 || r->in.num_names > 1000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.names));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.names));
+ if (ndr_get_array_length(ndr, &r->in.names) > ndr_get_array_size(ndr, &r->in.names)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.names), ndr_get_array_length(ndr, &r->in.names));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->in.names, ndr_get_array_size(ndr, &r->in.names));
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.names, 0);
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->in.names[cntr_names_0]));
+ }
+ for (cntr_names_0 = 0; cntr_names_0 < r->in.num_names; cntr_names_0++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->in.names[cntr_names_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, 0);
+ NDR_PULL_ALLOC(ndr, r->out.rids);
+ ZERO_STRUCTP(r->out.rids);
+ NDR_PULL_ALLOC(ndr, r->out.types);
+ ZERO_STRUCTP(r->out.types);
+ if (r->in.names) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.names, 1000));
+ }
+ if (r->in.names) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->in.names, r->in.num_names));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.rids);
+ }
+ _mem_save_rids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.rids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_Ids(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.rids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rids_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.types);
+ }
+ _mem_save_types_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.types, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_Ids(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.types));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_types_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_LookupNames(struct ndr_print *ndr, const char *name, int flags, const struct samr_LookupNames *r)
+{
+ uint32_t cntr_names_0;
+ ndr_print_struct(ndr, name, "samr_LookupNames");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_LookupNames");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "num_names", r->in.num_names);
+ ndr->print(ndr, "%s: ARRAY(%d)", "names", (int)r->in.num_names);
+ ndr->depth++;
+ for (cntr_names_0=0;cntr_names_0<r->in.num_names;cntr_names_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_names_0) != -1) {
+ ndr_print_lsa_String(ndr, "names", &r->in.names[cntr_names_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_LookupNames");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "rids", r->out.rids);
+ ndr->depth++;
+ ndr_print_samr_Ids(ndr, "rids", r->out.rids);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "types", r->out.types);
+ ndr->depth++;
+ ndr_print_samr_Ids(ndr, "types", r->out.types);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_LookupRids(struct ndr_push *ndr, int flags, const struct samr_LookupRids *r)
+{
+ uint32_t cntr_rids_0;
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_rids));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 1000));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_rids));
+ for (cntr_rids_0 = 0; cntr_rids_0 < r->in.num_rids; cntr_rids_0++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.rids[cntr_rids_0]));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.names == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_Strings(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.names));
+ if (r->out.types == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_samr_Ids(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.types));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_LookupRids(struct ndr_pull *ndr, int flags, struct samr_LookupRids *r)
+{
+ uint32_t cntr_rids_0;
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_rids_0;
+ TALLOC_CTX *_mem_save_names_0;
+ TALLOC_CTX *_mem_save_types_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.num_rids));
+ if (r->in.num_rids < 0 || r->in.num_rids > 1000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.rids));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.rids));
+ if (ndr_get_array_length(ndr, &r->in.rids) > ndr_get_array_size(ndr, &r->in.rids)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.rids), ndr_get_array_length(ndr, &r->in.rids));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->in.rids, ndr_get_array_size(ndr, &r->in.rids));
+ _mem_save_rids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.rids, 0);
+ for (cntr_rids_0 = 0; cntr_rids_0 < r->in.num_rids; cntr_rids_0++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.rids[cntr_rids_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rids_0, 0);
+ NDR_PULL_ALLOC(ndr, r->out.names);
+ ZERO_STRUCTP(r->out.names);
+ NDR_PULL_ALLOC(ndr, r->out.types);
+ ZERO_STRUCTP(r->out.types);
+ if (r->in.rids) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.rids, 1000));
+ }
+ if (r->in.rids) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->in.rids, r->in.num_rids));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.names);
+ }
+ _mem_save_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.names, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_Strings(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.names));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_names_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.types);
+ }
+ _mem_save_types_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.types, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_Ids(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.types));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_types_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_LookupRids(struct ndr_print *ndr, const char *name, int flags, const struct samr_LookupRids *r)
+{
+ uint32_t cntr_rids_0;
+ ndr_print_struct(ndr, name, "samr_LookupRids");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_LookupRids");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "num_rids", r->in.num_rids);
+ ndr->print(ndr, "%s: ARRAY(%d)", "rids", (int)r->in.num_rids);
+ ndr->depth++;
+ for (cntr_rids_0=0;cntr_rids_0<r->in.num_rids;cntr_rids_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_rids_0) != -1) {
+ ndr_print_uint32(ndr, "rids", r->in.rids[cntr_rids_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_LookupRids");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "names", r->out.names);
+ ndr->depth++;
+ ndr_print_lsa_Strings(ndr, "names", r->out.names);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "types", r->out.types);
+ ndr->depth++;
+ ndr_print_samr_Ids(ndr, "types", r->out.types);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_OpenGroup(struct ndr_push *ndr, int flags, const struct samr_OpenGroup *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_CHECK(ndr_push_samr_GroupAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.rid));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.group_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.group_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_OpenGroup(struct ndr_pull *ndr, int flags, struct samr_OpenGroup *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_group_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_GroupAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.rid));
+ NDR_PULL_ALLOC(ndr, r->out.group_handle);
+ ZERO_STRUCTP(r->out.group_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.group_handle);
+ }
+ _mem_save_group_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.group_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.group_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_OpenGroup(struct ndr_print *ndr, const char *name, int flags, const struct samr_OpenGroup *r)
+{
+ ndr_print_struct(ndr, name, "samr_OpenGroup");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_OpenGroup");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_samr_GroupAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr_print_uint32(ndr, "rid", r->in.rid);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_OpenGroup");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "group_handle", r->out.group_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "group_handle", r->out.group_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_QueryGroupInfo(struct ndr_push *ndr, int flags, const struct samr_QueryGroupInfo *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.group_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.group_handle));
+ NDR_CHECK(ndr_push_samr_GroupInfoEnum(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.info));
+ if (*r->out.info) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_samr_GroupInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_QueryGroupInfo(struct ndr_pull *ndr, int flags, struct samr_QueryGroupInfo *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_group_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.group_handle);
+ }
+ _mem_save_group_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.group_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.group_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_GroupInfoEnum(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ } else {
+ *r->out.info = NULL;
+ }
+ if (*r->out.info) {
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.info, 0);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_samr_GroupInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_QueryGroupInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryGroupInfo *r)
+{
+ ndr_print_struct(ndr, name, "samr_QueryGroupInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_QueryGroupInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "group_handle", r->in.group_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "group_handle", r->in.group_handle);
+ ndr->depth--;
+ ndr_print_samr_GroupInfoEnum(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_QueryGroupInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", *r->out.info);
+ ndr->depth++;
+ if (*r->out.info) {
+ ndr_print_set_switch_value(ndr, *r->out.info, r->in.level);
+ ndr_print_samr_GroupInfo(ndr, "info", *r->out.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_SetGroupInfo(struct ndr_push *ndr, int flags, const struct samr_SetGroupInfo *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.group_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.group_handle));
+ NDR_CHECK(ndr_push_samr_GroupInfoEnum(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_samr_GroupInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_SetGroupInfo(struct ndr_pull *ndr, int flags, struct samr_SetGroupInfo *r)
+{
+ TALLOC_CTX *_mem_save_group_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.group_handle);
+ }
+ _mem_save_group_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.group_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.group_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_GroupInfoEnum(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_samr_GroupInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_SetGroupInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetGroupInfo *r)
+{
+ ndr_print_struct(ndr, name, "samr_SetGroupInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_SetGroupInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "group_handle", r->in.group_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "group_handle", r->in.group_handle);
+ ndr->depth--;
+ ndr_print_samr_GroupInfoEnum(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.info, r->in.level);
+ ndr_print_samr_GroupInfo(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_SetGroupInfo");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_AddGroupMember(struct ndr_push *ndr, int flags, const struct samr_AddGroupMember *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.group_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.group_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.rid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_AddGroupMember(struct ndr_pull *ndr, int flags, struct samr_AddGroupMember *r)
+{
+ TALLOC_CTX *_mem_save_group_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.group_handle);
+ }
+ _mem_save_group_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.group_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.group_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.rid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_AddGroupMember(struct ndr_print *ndr, const char *name, int flags, const struct samr_AddGroupMember *r)
+{
+ ndr_print_struct(ndr, name, "samr_AddGroupMember");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_AddGroupMember");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "group_handle", r->in.group_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "group_handle", r->in.group_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "rid", r->in.rid);
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_AddGroupMember");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DeleteDomainGroup(struct ndr_push *ndr, int flags, const struct samr_DeleteDomainGroup *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.group_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.group_handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.group_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.group_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DeleteDomainGroup(struct ndr_pull *ndr, int flags, struct samr_DeleteDomainGroup *r)
+{
+ TALLOC_CTX *_mem_save_group_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.group_handle);
+ }
+ _mem_save_group_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.group_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.group_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.group_handle);
+ *r->out.group_handle = *r->in.group_handle;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.group_handle);
+ }
+ _mem_save_group_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.group_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.group_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DeleteDomainGroup(struct ndr_print *ndr, const char *name, int flags, const struct samr_DeleteDomainGroup *r)
+{
+ ndr_print_struct(ndr, name, "samr_DeleteDomainGroup");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_DeleteDomainGroup");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "group_handle", r->in.group_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "group_handle", r->in.group_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_DeleteDomainGroup");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "group_handle", r->out.group_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "group_handle", r->out.group_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DeleteGroupMember(struct ndr_push *ndr, int flags, const struct samr_DeleteGroupMember *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.group_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.group_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.rid));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DeleteGroupMember(struct ndr_pull *ndr, int flags, struct samr_DeleteGroupMember *r)
+{
+ TALLOC_CTX *_mem_save_group_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.group_handle);
+ }
+ _mem_save_group_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.group_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.group_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.rid));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DeleteGroupMember(struct ndr_print *ndr, const char *name, int flags, const struct samr_DeleteGroupMember *r)
+{
+ ndr_print_struct(ndr, name, "samr_DeleteGroupMember");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_DeleteGroupMember");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "group_handle", r->in.group_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "group_handle", r->in.group_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "rid", r->in.rid);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_DeleteGroupMember");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_QueryGroupMember(struct ndr_push *ndr, int flags, const struct samr_QueryGroupMember *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.group_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.group_handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.rids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.rids));
+ if (*r->out.rids) {
+ NDR_CHECK(ndr_push_samr_RidTypeArray(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.rids));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_QueryGroupMember(struct ndr_pull *ndr, int flags, struct samr_QueryGroupMember *r)
+{
+ uint32_t _ptr_rids;
+ TALLOC_CTX *_mem_save_group_handle_0;
+ TALLOC_CTX *_mem_save_rids_0;
+ TALLOC_CTX *_mem_save_rids_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.group_handle);
+ }
+ _mem_save_group_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.group_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.group_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.rids);
+ ZERO_STRUCTP(r->out.rids);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.rids);
+ }
+ _mem_save_rids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.rids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_rids));
+ if (_ptr_rids) {
+ NDR_PULL_ALLOC(ndr, *r->out.rids);
+ } else {
+ *r->out.rids = NULL;
+ }
+ if (*r->out.rids) {
+ _mem_save_rids_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.rids, 0);
+ NDR_CHECK(ndr_pull_samr_RidTypeArray(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.rids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rids_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rids_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_QueryGroupMember(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryGroupMember *r)
+{
+ ndr_print_struct(ndr, name, "samr_QueryGroupMember");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_QueryGroupMember");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "group_handle", r->in.group_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "group_handle", r->in.group_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_QueryGroupMember");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "rids", r->out.rids);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "rids", *r->out.rids);
+ ndr->depth++;
+ if (*r->out.rids) {
+ ndr_print_samr_RidTypeArray(ndr, "rids", *r->out.rids);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_SetMemberAttributesOfGroup(struct ndr_push *ndr, int flags, const struct samr_SetMemberAttributesOfGroup *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.group_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.group_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown2));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_SetMemberAttributesOfGroup(struct ndr_pull *ndr, int flags, struct samr_SetMemberAttributesOfGroup *r)
+{
+ TALLOC_CTX *_mem_save_group_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.group_handle);
+ }
+ _mem_save_group_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.group_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.group_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown2));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_SetMemberAttributesOfGroup(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetMemberAttributesOfGroup *r)
+{
+ ndr_print_struct(ndr, name, "samr_SetMemberAttributesOfGroup");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_SetMemberAttributesOfGroup");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "group_handle", r->in.group_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "group_handle", r->in.group_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown1", r->in.unknown1);
+ ndr_print_uint32(ndr, "unknown2", r->in.unknown2);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_SetMemberAttributesOfGroup");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_OpenAlias(struct ndr_push *ndr, int flags, const struct samr_OpenAlias *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_CHECK(ndr_push_samr_AliasAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.rid));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.alias_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.alias_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_OpenAlias(struct ndr_pull *ndr, int flags, struct samr_OpenAlias *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_alias_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_AliasAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.rid));
+ NDR_PULL_ALLOC(ndr, r->out.alias_handle);
+ ZERO_STRUCTP(r->out.alias_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.alias_handle);
+ }
+ _mem_save_alias_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.alias_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.alias_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alias_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_OpenAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_OpenAlias *r)
+{
+ ndr_print_struct(ndr, name, "samr_OpenAlias");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_OpenAlias");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_samr_AliasAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr_print_uint32(ndr, "rid", r->in.rid);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_OpenAlias");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "alias_handle", r->out.alias_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "alias_handle", r->out.alias_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_QueryAliasInfo(struct ndr_push *ndr, int flags, const struct samr_QueryAliasInfo *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.alias_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.alias_handle));
+ NDR_CHECK(ndr_push_samr_AliasInfoEnum(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.info));
+ if (*r->out.info) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_samr_AliasInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_QueryAliasInfo(struct ndr_pull *ndr, int flags, struct samr_QueryAliasInfo *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_alias_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.alias_handle);
+ }
+ _mem_save_alias_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.alias_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.alias_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alias_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_AliasInfoEnum(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ } else {
+ *r->out.info = NULL;
+ }
+ if (*r->out.info) {
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.info, 0);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_samr_AliasInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_QueryAliasInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryAliasInfo *r)
+{
+ ndr_print_struct(ndr, name, "samr_QueryAliasInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_QueryAliasInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "alias_handle", r->in.alias_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "alias_handle", r->in.alias_handle);
+ ndr->depth--;
+ ndr_print_samr_AliasInfoEnum(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_QueryAliasInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", *r->out.info);
+ ndr->depth++;
+ if (*r->out.info) {
+ ndr_print_set_switch_value(ndr, *r->out.info, r->in.level);
+ ndr_print_samr_AliasInfo(ndr, "info", *r->out.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_SetAliasInfo(struct ndr_push *ndr, int flags, const struct samr_SetAliasInfo *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.alias_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.alias_handle));
+ NDR_CHECK(ndr_push_samr_AliasInfoEnum(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_samr_AliasInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_SetAliasInfo(struct ndr_pull *ndr, int flags, struct samr_SetAliasInfo *r)
+{
+ TALLOC_CTX *_mem_save_alias_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.alias_handle);
+ }
+ _mem_save_alias_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.alias_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.alias_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alias_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_AliasInfoEnum(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_samr_AliasInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_SetAliasInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetAliasInfo *r)
+{
+ ndr_print_struct(ndr, name, "samr_SetAliasInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_SetAliasInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "alias_handle", r->in.alias_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "alias_handle", r->in.alias_handle);
+ ndr->depth--;
+ ndr_print_samr_AliasInfoEnum(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.info, r->in.level);
+ ndr_print_samr_AliasInfo(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_SetAliasInfo");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DeleteDomAlias(struct ndr_push *ndr, int flags, const struct samr_DeleteDomAlias *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.alias_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.alias_handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.alias_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.alias_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DeleteDomAlias(struct ndr_pull *ndr, int flags, struct samr_DeleteDomAlias *r)
+{
+ TALLOC_CTX *_mem_save_alias_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.alias_handle);
+ }
+ _mem_save_alias_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.alias_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.alias_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alias_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.alias_handle);
+ *r->out.alias_handle = *r->in.alias_handle;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.alias_handle);
+ }
+ _mem_save_alias_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.alias_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.alias_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alias_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DeleteDomAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_DeleteDomAlias *r)
+{
+ ndr_print_struct(ndr, name, "samr_DeleteDomAlias");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_DeleteDomAlias");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "alias_handle", r->in.alias_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "alias_handle", r->in.alias_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_DeleteDomAlias");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "alias_handle", r->out.alias_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "alias_handle", r->out.alias_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_AddAliasMember(struct ndr_push *ndr, int flags, const struct samr_AddAliasMember *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.alias_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.alias_handle));
+ if (r->in.sid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_AddAliasMember(struct ndr_pull *ndr, int flags, struct samr_AddAliasMember *r)
+{
+ TALLOC_CTX *_mem_save_alias_handle_0;
+ TALLOC_CTX *_mem_save_sid_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.alias_handle);
+ }
+ _mem_save_alias_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.alias_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.alias_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alias_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sid);
+ }
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_AddAliasMember(struct ndr_print *ndr, const char *name, int flags, const struct samr_AddAliasMember *r)
+{
+ ndr_print_struct(ndr, name, "samr_AddAliasMember");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_AddAliasMember");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "alias_handle", r->in.alias_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "alias_handle", r->in.alias_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sid", r->in.sid);
+ ndr->depth++;
+ ndr_print_dom_sid2(ndr, "sid", r->in.sid);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_AddAliasMember");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DeleteAliasMember(struct ndr_push *ndr, int flags, const struct samr_DeleteAliasMember *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.alias_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.alias_handle));
+ if (r->in.sid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DeleteAliasMember(struct ndr_pull *ndr, int flags, struct samr_DeleteAliasMember *r)
+{
+ TALLOC_CTX *_mem_save_alias_handle_0;
+ TALLOC_CTX *_mem_save_sid_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.alias_handle);
+ }
+ _mem_save_alias_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.alias_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.alias_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alias_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sid);
+ }
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DeleteAliasMember(struct ndr_print *ndr, const char *name, int flags, const struct samr_DeleteAliasMember *r)
+{
+ ndr_print_struct(ndr, name, "samr_DeleteAliasMember");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_DeleteAliasMember");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "alias_handle", r->in.alias_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "alias_handle", r->in.alias_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sid", r->in.sid);
+ ndr->depth++;
+ ndr_print_dom_sid2(ndr, "sid", r->in.sid);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_DeleteAliasMember");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_GetMembersInAlias(struct ndr_push *ndr, int flags, const struct samr_GetMembersInAlias *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.alias_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.alias_handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sids));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_GetMembersInAlias(struct ndr_pull *ndr, int flags, struct samr_GetMembersInAlias *r)
+{
+ TALLOC_CTX *_mem_save_alias_handle_0;
+ TALLOC_CTX *_mem_save_sids_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.alias_handle);
+ }
+ _mem_save_alias_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.alias_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.alias_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alias_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.sids);
+ ZERO_STRUCTP(r->out.sids);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_GetMembersInAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetMembersInAlias *r)
+{
+ ndr_print_struct(ndr, name, "samr_GetMembersInAlias");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_GetMembersInAlias");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "alias_handle", r->in.alias_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "alias_handle", r->in.alias_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_GetMembersInAlias");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sids", r->out.sids);
+ ndr->depth++;
+ ndr_print_lsa_SidArray(ndr, "sids", r->out.sids);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_OpenUser(struct ndr_push *ndr, int flags, const struct samr_OpenUser *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_CHECK(ndr_push_samr_UserAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.rid));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.user_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.user_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_OpenUser(struct ndr_pull *ndr, int flags, struct samr_OpenUser *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_user_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_UserAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.rid));
+ NDR_PULL_ALLOC(ndr, r->out.user_handle);
+ ZERO_STRUCTP(r->out.user_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.user_handle);
+ }
+ _mem_save_user_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.user_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.user_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_OpenUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_OpenUser *r)
+{
+ ndr_print_struct(ndr, name, "samr_OpenUser");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_OpenUser");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_samr_UserAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr_print_uint32(ndr, "rid", r->in.rid);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_OpenUser");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "user_handle", r->out.user_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "user_handle", r->out.user_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_DeleteUser(struct ndr_push *ndr, int flags, const struct samr_DeleteUser *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.user_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.user_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.user_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_DeleteUser(struct ndr_pull *ndr, int flags, struct samr_DeleteUser *r)
+{
+ TALLOC_CTX *_mem_save_user_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.user_handle);
+ }
+ _mem_save_user_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.user_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.user_handle);
+ *r->out.user_handle = *r->in.user_handle;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.user_handle);
+ }
+ _mem_save_user_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.user_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.user_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_DeleteUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_DeleteUser *r)
+{
+ ndr_print_struct(ndr, name, "samr_DeleteUser");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_DeleteUser");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "user_handle", r->in.user_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "user_handle", r->in.user_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_DeleteUser");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "user_handle", r->out.user_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "user_handle", r->out.user_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_QueryUserInfo(struct ndr_push *ndr, int flags, const struct samr_QueryUserInfo *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.user_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.info));
+ if (*r->out.info) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_samr_UserInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_QueryUserInfo(struct ndr_pull *ndr, int flags, struct samr_QueryUserInfo *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_user_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.user_handle);
+ }
+ _mem_save_user_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.user_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ } else {
+ *r->out.info = NULL;
+ }
+ if (*r->out.info) {
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.info, 0);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_samr_UserInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_QueryUserInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryUserInfo *r)
+{
+ ndr_print_struct(ndr, name, "samr_QueryUserInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_QueryUserInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "user_handle", r->in.user_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "user_handle", r->in.user_handle);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_QueryUserInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", *r->out.info);
+ ndr->depth++;
+ if (*r->out.info) {
+ ndr_print_set_switch_value(ndr, *r->out.info, r->in.level);
+ ndr_print_samr_UserInfo(ndr, "info", *r->out.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_SetUserInfo(struct ndr_push *ndr, int flags, const struct samr_SetUserInfo *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.user_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_samr_UserInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_SetUserInfo(struct ndr_pull *ndr, int flags, struct samr_SetUserInfo *r)
+{
+ TALLOC_CTX *_mem_save_user_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.user_handle);
+ }
+ _mem_save_user_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.user_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_samr_UserInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_SetUserInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetUserInfo *r)
+{
+ ndr_print_struct(ndr, name, "samr_SetUserInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_SetUserInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "user_handle", r->in.user_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "user_handle", r->in.user_handle);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.info, r->in.level);
+ ndr_print_samr_UserInfo(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_SetUserInfo");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_ChangePasswordUser(struct ndr_push *ndr, int flags, const struct samr_ChangePasswordUser *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.user_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.lm_present));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.old_lm_crypted));
+ if (r->in.old_lm_crypted) {
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, r->in.old_lm_crypted));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.new_lm_crypted));
+ if (r->in.new_lm_crypted) {
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, r->in.new_lm_crypted));
+ }
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.nt_present));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.old_nt_crypted));
+ if (r->in.old_nt_crypted) {
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, r->in.old_nt_crypted));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.new_nt_crypted));
+ if (r->in.new_nt_crypted) {
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, r->in.new_nt_crypted));
+ }
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.cross1_present));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.nt_cross));
+ if (r->in.nt_cross) {
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, r->in.nt_cross));
+ }
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.cross2_present));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.lm_cross));
+ if (r->in.lm_cross) {
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, r->in.lm_cross));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ChangePasswordUser(struct ndr_pull *ndr, int flags, struct samr_ChangePasswordUser *r)
+{
+ uint32_t _ptr_old_lm_crypted;
+ uint32_t _ptr_new_lm_crypted;
+ uint32_t _ptr_old_nt_crypted;
+ uint32_t _ptr_new_nt_crypted;
+ uint32_t _ptr_nt_cross;
+ uint32_t _ptr_lm_cross;
+ TALLOC_CTX *_mem_save_user_handle_0;
+ TALLOC_CTX *_mem_save_old_lm_crypted_0;
+ TALLOC_CTX *_mem_save_new_lm_crypted_0;
+ TALLOC_CTX *_mem_save_old_nt_crypted_0;
+ TALLOC_CTX *_mem_save_new_nt_crypted_0;
+ TALLOC_CTX *_mem_save_nt_cross_0;
+ TALLOC_CTX *_mem_save_lm_cross_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.user_handle);
+ }
+ _mem_save_user_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.user_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.lm_present));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_old_lm_crypted));
+ if (_ptr_old_lm_crypted) {
+ NDR_PULL_ALLOC(ndr, r->in.old_lm_crypted);
+ } else {
+ r->in.old_lm_crypted = NULL;
+ }
+ if (r->in.old_lm_crypted) {
+ _mem_save_old_lm_crypted_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.old_lm_crypted, 0);
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, r->in.old_lm_crypted));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_old_lm_crypted_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_new_lm_crypted));
+ if (_ptr_new_lm_crypted) {
+ NDR_PULL_ALLOC(ndr, r->in.new_lm_crypted);
+ } else {
+ r->in.new_lm_crypted = NULL;
+ }
+ if (r->in.new_lm_crypted) {
+ _mem_save_new_lm_crypted_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.new_lm_crypted, 0);
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, r->in.new_lm_crypted));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_new_lm_crypted_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.nt_present));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_old_nt_crypted));
+ if (_ptr_old_nt_crypted) {
+ NDR_PULL_ALLOC(ndr, r->in.old_nt_crypted);
+ } else {
+ r->in.old_nt_crypted = NULL;
+ }
+ if (r->in.old_nt_crypted) {
+ _mem_save_old_nt_crypted_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.old_nt_crypted, 0);
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, r->in.old_nt_crypted));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_old_nt_crypted_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_new_nt_crypted));
+ if (_ptr_new_nt_crypted) {
+ NDR_PULL_ALLOC(ndr, r->in.new_nt_crypted);
+ } else {
+ r->in.new_nt_crypted = NULL;
+ }
+ if (r->in.new_nt_crypted) {
+ _mem_save_new_nt_crypted_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.new_nt_crypted, 0);
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, r->in.new_nt_crypted));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_new_nt_crypted_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.cross1_present));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_nt_cross));
+ if (_ptr_nt_cross) {
+ NDR_PULL_ALLOC(ndr, r->in.nt_cross);
+ } else {
+ r->in.nt_cross = NULL;
+ }
+ if (r->in.nt_cross) {
+ _mem_save_nt_cross_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.nt_cross, 0);
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, r->in.nt_cross));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_nt_cross_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.cross2_present));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_lm_cross));
+ if (_ptr_lm_cross) {
+ NDR_PULL_ALLOC(ndr, r->in.lm_cross);
+ } else {
+ r->in.lm_cross = NULL;
+ }
+ if (r->in.lm_cross) {
+ _mem_save_lm_cross_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.lm_cross, 0);
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, r->in.lm_cross));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_lm_cross_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ChangePasswordUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_ChangePasswordUser *r)
+{
+ ndr_print_struct(ndr, name, "samr_ChangePasswordUser");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_ChangePasswordUser");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "user_handle", r->in.user_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "user_handle", r->in.user_handle);
+ ndr->depth--;
+ ndr_print_uint8(ndr, "lm_present", r->in.lm_present);
+ ndr_print_ptr(ndr, "old_lm_crypted", r->in.old_lm_crypted);
+ ndr->depth++;
+ if (r->in.old_lm_crypted) {
+ ndr_print_samr_Password(ndr, "old_lm_crypted", r->in.old_lm_crypted);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "new_lm_crypted", r->in.new_lm_crypted);
+ ndr->depth++;
+ if (r->in.new_lm_crypted) {
+ ndr_print_samr_Password(ndr, "new_lm_crypted", r->in.new_lm_crypted);
+ }
+ ndr->depth--;
+ ndr_print_uint8(ndr, "nt_present", r->in.nt_present);
+ ndr_print_ptr(ndr, "old_nt_crypted", r->in.old_nt_crypted);
+ ndr->depth++;
+ if (r->in.old_nt_crypted) {
+ ndr_print_samr_Password(ndr, "old_nt_crypted", r->in.old_nt_crypted);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "new_nt_crypted", r->in.new_nt_crypted);
+ ndr->depth++;
+ if (r->in.new_nt_crypted) {
+ ndr_print_samr_Password(ndr, "new_nt_crypted", r->in.new_nt_crypted);
+ }
+ ndr->depth--;
+ ndr_print_uint8(ndr, "cross1_present", r->in.cross1_present);
+ ndr_print_ptr(ndr, "nt_cross", r->in.nt_cross);
+ ndr->depth++;
+ if (r->in.nt_cross) {
+ ndr_print_samr_Password(ndr, "nt_cross", r->in.nt_cross);
+ }
+ ndr->depth--;
+ ndr_print_uint8(ndr, "cross2_present", r->in.cross2_present);
+ ndr_print_ptr(ndr, "lm_cross", r->in.lm_cross);
+ ndr->depth++;
+ if (r->in.lm_cross) {
+ ndr_print_samr_Password(ndr, "lm_cross", r->in.lm_cross);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_ChangePasswordUser");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_GetGroupsForUser(struct ndr_push *ndr, int flags, const struct samr_GetGroupsForUser *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.user_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.rids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.rids));
+ if (*r->out.rids) {
+ NDR_CHECK(ndr_push_samr_RidWithAttributeArray(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.rids));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_GetGroupsForUser(struct ndr_pull *ndr, int flags, struct samr_GetGroupsForUser *r)
+{
+ uint32_t _ptr_rids;
+ TALLOC_CTX *_mem_save_user_handle_0;
+ TALLOC_CTX *_mem_save_rids_0;
+ TALLOC_CTX *_mem_save_rids_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.user_handle);
+ }
+ _mem_save_user_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.user_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.rids);
+ ZERO_STRUCTP(r->out.rids);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.rids);
+ }
+ _mem_save_rids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.rids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_rids));
+ if (_ptr_rids) {
+ NDR_PULL_ALLOC(ndr, *r->out.rids);
+ } else {
+ *r->out.rids = NULL;
+ }
+ if (*r->out.rids) {
+ _mem_save_rids_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.rids, 0);
+ NDR_CHECK(ndr_pull_samr_RidWithAttributeArray(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.rids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rids_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rids_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_GetGroupsForUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetGroupsForUser *r)
+{
+ ndr_print_struct(ndr, name, "samr_GetGroupsForUser");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_GetGroupsForUser");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "user_handle", r->in.user_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "user_handle", r->in.user_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_GetGroupsForUser");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "rids", r->out.rids);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "rids", *r->out.rids);
+ ndr->depth++;
+ if (*r->out.rids) {
+ ndr_print_samr_RidWithAttributeArray(ndr, "rids", *r->out.rids);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_QueryDisplayInfo(struct ndr_push *ndr, int flags, const struct samr_QueryDisplayInfo *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.start_idx));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_entries));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.total_size == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.total_size));
+ if (r->out.returned_size == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.returned_size));
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_samr_DispInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_QueryDisplayInfo(struct ndr_pull *ndr, int flags, struct samr_QueryDisplayInfo *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_total_size_0;
+ TALLOC_CTX *_mem_save_returned_size_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.start_idx));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_entries));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ NDR_PULL_ALLOC(ndr, r->out.total_size);
+ ZERO_STRUCTP(r->out.total_size);
+ NDR_PULL_ALLOC(ndr, r->out.returned_size);
+ ZERO_STRUCTP(r->out.returned_size);
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.total_size);
+ }
+ _mem_save_total_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.total_size, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.total_size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_total_size_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.returned_size);
+ }
+ _mem_save_returned_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.returned_size, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.returned_size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_returned_size_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_samr_DispInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_QueryDisplayInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryDisplayInfo *r)
+{
+ ndr_print_struct(ndr, name, "samr_QueryDisplayInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_QueryDisplayInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "start_idx", r->in.start_idx);
+ ndr_print_uint32(ndr, "max_entries", r->in.max_entries);
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_QueryDisplayInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "total_size", r->out.total_size);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "total_size", *r->out.total_size);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "returned_size", r->out.returned_size);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "returned_size", *r->out.returned_size);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, r->in.level);
+ ndr_print_samr_DispInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_GetDisplayEnumerationIndex(struct ndr_push *ndr, int flags, const struct samr_GetDisplayEnumerationIndex *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.idx == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.idx));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_GetDisplayEnumerationIndex(struct ndr_pull *ndr, int flags, struct samr_GetDisplayEnumerationIndex *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_name_0;
+ TALLOC_CTX *_mem_save_idx_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.name);
+ }
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.idx);
+ ZERO_STRUCTP(r->out.idx);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.idx);
+ }
+ _mem_save_idx_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.idx, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.idx));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_idx_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_GetDisplayEnumerationIndex(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetDisplayEnumerationIndex *r)
+{
+ ndr_print_struct(ndr, name, "samr_GetDisplayEnumerationIndex");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_GetDisplayEnumerationIndex");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "name", r->in.name);
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "name", r->in.name);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_GetDisplayEnumerationIndex");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "idx", r->out.idx);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "idx", *r->out.idx);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_TestPrivateFunctionsDomain(struct ndr_push *ndr, int flags, const struct samr_TestPrivateFunctionsDomain *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_TestPrivateFunctionsDomain(struct ndr_pull *ndr, int flags, struct samr_TestPrivateFunctionsDomain *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_TestPrivateFunctionsDomain(struct ndr_print *ndr, const char *name, int flags, const struct samr_TestPrivateFunctionsDomain *r)
+{
+ ndr_print_struct(ndr, name, "samr_TestPrivateFunctionsDomain");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_TestPrivateFunctionsDomain");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_TestPrivateFunctionsDomain");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_TestPrivateFunctionsUser(struct ndr_push *ndr, int flags, const struct samr_TestPrivateFunctionsUser *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.user_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_TestPrivateFunctionsUser(struct ndr_pull *ndr, int flags, struct samr_TestPrivateFunctionsUser *r)
+{
+ TALLOC_CTX *_mem_save_user_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.user_handle);
+ }
+ _mem_save_user_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.user_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_TestPrivateFunctionsUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_TestPrivateFunctionsUser *r)
+{
+ ndr_print_struct(ndr, name, "samr_TestPrivateFunctionsUser");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_TestPrivateFunctionsUser");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "user_handle", r->in.user_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "user_handle", r->in.user_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_TestPrivateFunctionsUser");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_GetUserPwInfo(struct ndr_push *ndr, int flags, const struct samr_GetUserPwInfo *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.user_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_samr_PwInfo(ndr, NDR_SCALARS, r->out.info));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_GetUserPwInfo(struct ndr_pull *ndr, int flags, struct samr_GetUserPwInfo *r)
+{
+ TALLOC_CTX *_mem_save_user_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.user_handle);
+ }
+ _mem_save_user_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.user_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_PwInfo(ndr, NDR_SCALARS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_GetUserPwInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetUserPwInfo *r)
+{
+ ndr_print_struct(ndr, name, "samr_GetUserPwInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_GetUserPwInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "user_handle", r->in.user_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "user_handle", r->in.user_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_GetUserPwInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_samr_PwInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_RemoveMemberFromForeignDomain(struct ndr_push *ndr, int flags, const struct samr_RemoveMemberFromForeignDomain *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ if (r->in.sid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_RemoveMemberFromForeignDomain(struct ndr_pull *ndr, int flags, struct samr_RemoveMemberFromForeignDomain *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_sid_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sid);
+ }
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_RemoveMemberFromForeignDomain(struct ndr_print *ndr, const char *name, int flags, const struct samr_RemoveMemberFromForeignDomain *r)
+{
+ ndr_print_struct(ndr, name, "samr_RemoveMemberFromForeignDomain");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_RemoveMemberFromForeignDomain");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sid", r->in.sid);
+ ndr->depth++;
+ ndr_print_dom_sid2(ndr, "sid", r->in.sid);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_RemoveMemberFromForeignDomain");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_QueryDomainInfo2(struct ndr_push *ndr, int flags, const struct samr_QueryDomainInfo2 *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.info));
+ if (*r->out.info) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_samr_DomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_QueryDomainInfo2(struct ndr_pull *ndr, int flags, struct samr_QueryDomainInfo2 *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ } else {
+ *r->out.info = NULL;
+ }
+ if (*r->out.info) {
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.info, 0);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, *r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_samr_DomainInfo(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_QueryDomainInfo2(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryDomainInfo2 *r)
+{
+ ndr_print_struct(ndr, name, "samr_QueryDomainInfo2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_QueryDomainInfo2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_QueryDomainInfo2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", *r->out.info);
+ ndr->depth++;
+ if (*r->out.info) {
+ ndr_print_set_switch_value(ndr, *r->out.info, r->in.level);
+ ndr_print_samr_DomainInfo(ndr, "info", *r->out.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_QueryUserInfo2(struct ndr_push *ndr, int flags, const struct samr_QueryUserInfo2 *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.user_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_samr_UserInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_QueryUserInfo2(struct ndr_pull *ndr, int flags, struct samr_QueryUserInfo2 *r)
+{
+ TALLOC_CTX *_mem_save_user_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.user_handle);
+ }
+ _mem_save_user_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.user_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_samr_UserInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_QueryUserInfo2(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryUserInfo2 *r)
+{
+ ndr_print_struct(ndr, name, "samr_QueryUserInfo2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_QueryUserInfo2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "user_handle", r->in.user_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "user_handle", r->in.user_handle);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_QueryUserInfo2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, r->in.level);
+ ndr_print_samr_UserInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_QueryDisplayInfo2(struct ndr_push *ndr, int flags, const struct samr_QueryDisplayInfo2 *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.start_idx));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_entries));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.total_size == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.total_size));
+ if (r->out.returned_size == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.returned_size));
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_samr_DispInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_QueryDisplayInfo2(struct ndr_pull *ndr, int flags, struct samr_QueryDisplayInfo2 *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_total_size_0;
+ TALLOC_CTX *_mem_save_returned_size_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.start_idx));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_entries));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ NDR_PULL_ALLOC(ndr, r->out.total_size);
+ ZERO_STRUCTP(r->out.total_size);
+ NDR_PULL_ALLOC(ndr, r->out.returned_size);
+ ZERO_STRUCTP(r->out.returned_size);
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.total_size);
+ }
+ _mem_save_total_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.total_size, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.total_size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_total_size_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.returned_size);
+ }
+ _mem_save_returned_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.returned_size, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.returned_size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_returned_size_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_samr_DispInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_QueryDisplayInfo2(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryDisplayInfo2 *r)
+{
+ ndr_print_struct(ndr, name, "samr_QueryDisplayInfo2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_QueryDisplayInfo2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "start_idx", r->in.start_idx);
+ ndr_print_uint32(ndr, "max_entries", r->in.max_entries);
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_QueryDisplayInfo2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "total_size", r->out.total_size);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "total_size", *r->out.total_size);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "returned_size", r->out.returned_size);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "returned_size", *r->out.returned_size);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, r->in.level);
+ ndr_print_samr_DispInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_GetDisplayEnumerationIndex2(struct ndr_push *ndr, int flags, const struct samr_GetDisplayEnumerationIndex2 *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.idx == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.idx));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_GetDisplayEnumerationIndex2(struct ndr_pull *ndr, int flags, struct samr_GetDisplayEnumerationIndex2 *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_name_0;
+ TALLOC_CTX *_mem_save_idx_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.name);
+ }
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.idx);
+ ZERO_STRUCTP(r->out.idx);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.idx);
+ }
+ _mem_save_idx_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.idx, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.idx));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_idx_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_GetDisplayEnumerationIndex2(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetDisplayEnumerationIndex2 *r)
+{
+ ndr_print_struct(ndr, name, "samr_GetDisplayEnumerationIndex2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_GetDisplayEnumerationIndex2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "name", r->in.name);
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "name", r->in.name);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_GetDisplayEnumerationIndex2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "idx", r->out.idx);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "idx", *r->out.idx);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_CreateUser2(struct ndr_push *ndr, int flags, const struct samr_CreateUser2 *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ if (r->in.account_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.account_name));
+ NDR_CHECK(ndr_push_samr_AcctFlags(ndr, NDR_SCALARS, r->in.acct_flags));
+ NDR_CHECK(ndr_push_samr_UserAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.user_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.user_handle));
+ if (r->out.access_granted == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.access_granted));
+ if (r->out.rid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.rid));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_CreateUser2(struct ndr_pull *ndr, int flags, struct samr_CreateUser2 *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_account_name_0;
+ TALLOC_CTX *_mem_save_user_handle_0;
+ TALLOC_CTX *_mem_save_access_granted_0;
+ TALLOC_CTX *_mem_save_rid_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.account_name);
+ }
+ _mem_save_account_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.account_name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.account_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_account_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_AcctFlags(ndr, NDR_SCALARS, &r->in.acct_flags));
+ NDR_CHECK(ndr_pull_samr_UserAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.user_handle);
+ ZERO_STRUCTP(r->out.user_handle);
+ NDR_PULL_ALLOC(ndr, r->out.access_granted);
+ ZERO_STRUCTP(r->out.access_granted);
+ NDR_PULL_ALLOC(ndr, r->out.rid);
+ ZERO_STRUCTP(r->out.rid);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.user_handle);
+ }
+ _mem_save_user_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.user_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.user_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.access_granted);
+ }
+ _mem_save_access_granted_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.access_granted, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.access_granted));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_access_granted_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.rid);
+ }
+ _mem_save_rid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.rid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.rid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_CreateUser2(struct ndr_print *ndr, const char *name, int flags, const struct samr_CreateUser2 *r)
+{
+ ndr_print_struct(ndr, name, "samr_CreateUser2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_CreateUser2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "account_name", r->in.account_name);
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "account_name", r->in.account_name);
+ ndr->depth--;
+ ndr_print_samr_AcctFlags(ndr, "acct_flags", r->in.acct_flags);
+ ndr_print_samr_UserAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_CreateUser2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "user_handle", r->out.user_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "user_handle", r->out.user_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "access_granted", r->out.access_granted);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "access_granted", *r->out.access_granted);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "rid", r->out.rid);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "rid", *r->out.rid);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_QueryDisplayInfo3(struct ndr_push *ndr, int flags, const struct samr_QueryDisplayInfo3 *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.start_idx));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_entries));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.total_size == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.total_size));
+ if (r->out.returned_size == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.returned_size));
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_samr_DispInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_QueryDisplayInfo3(struct ndr_pull *ndr, int flags, struct samr_QueryDisplayInfo3 *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_total_size_0;
+ TALLOC_CTX *_mem_save_returned_size_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.start_idx));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_entries));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ NDR_PULL_ALLOC(ndr, r->out.total_size);
+ ZERO_STRUCTP(r->out.total_size);
+ NDR_PULL_ALLOC(ndr, r->out.returned_size);
+ ZERO_STRUCTP(r->out.returned_size);
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.total_size);
+ }
+ _mem_save_total_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.total_size, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.total_size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_total_size_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.returned_size);
+ }
+ _mem_save_returned_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.returned_size, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.returned_size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_returned_size_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_samr_DispInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_QueryDisplayInfo3(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryDisplayInfo3 *r)
+{
+ ndr_print_struct(ndr, name, "samr_QueryDisplayInfo3");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_QueryDisplayInfo3");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "start_idx", r->in.start_idx);
+ ndr_print_uint32(ndr, "max_entries", r->in.max_entries);
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_QueryDisplayInfo3");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "total_size", r->out.total_size);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "total_size", *r->out.total_size);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "returned_size", r->out.returned_size);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "returned_size", *r->out.returned_size);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, r->in.level);
+ ndr_print_samr_DispInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_AddMultipleMembersToAlias(struct ndr_push *ndr, int flags, const struct samr_AddMultipleMembersToAlias *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.alias_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.alias_handle));
+ if (r->in.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_AddMultipleMembersToAlias(struct ndr_pull *ndr, int flags, struct samr_AddMultipleMembersToAlias *r)
+{
+ TALLOC_CTX *_mem_save_alias_handle_0;
+ TALLOC_CTX *_mem_save_sids_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.alias_handle);
+ }
+ _mem_save_alias_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.alias_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.alias_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alias_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_AddMultipleMembersToAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_AddMultipleMembersToAlias *r)
+{
+ ndr_print_struct(ndr, name, "samr_AddMultipleMembersToAlias");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_AddMultipleMembersToAlias");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "alias_handle", r->in.alias_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "alias_handle", r->in.alias_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sids", r->in.sids);
+ ndr->depth++;
+ ndr_print_lsa_SidArray(ndr, "sids", r->in.sids);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_AddMultipleMembersToAlias");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_RemoveMultipleMembersFromAlias(struct ndr_push *ndr, int flags, const struct samr_RemoveMultipleMembersFromAlias *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.alias_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.alias_handle));
+ if (r->in.sids == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_RemoveMultipleMembersFromAlias(struct ndr_pull *ndr, int flags, struct samr_RemoveMultipleMembersFromAlias *r)
+{
+ TALLOC_CTX *_mem_save_alias_handle_0;
+ TALLOC_CTX *_mem_save_sids_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.alias_handle);
+ }
+ _mem_save_alias_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.alias_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.alias_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alias_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sids);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sids, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_SidArray(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sids));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_RemoveMultipleMembersFromAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_RemoveMultipleMembersFromAlias *r)
+{
+ ndr_print_struct(ndr, name, "samr_RemoveMultipleMembersFromAlias");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_RemoveMultipleMembersFromAlias");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "alias_handle", r->in.alias_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "alias_handle", r->in.alias_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sids", r->in.sids);
+ ndr->depth++;
+ ndr_print_lsa_SidArray(ndr, "sids", r->in.sids);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_RemoveMultipleMembersFromAlias");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_OemChangePasswordUser2(struct ndr_push *ndr, int flags, const struct samr_OemChangePasswordUser2 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server));
+ if (r->in.server) {
+ NDR_CHECK(ndr_push_lsa_AsciiString(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.server));
+ }
+ if (r->in.account == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_AsciiString(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.account));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.password));
+ if (r->in.password) {
+ NDR_CHECK(ndr_push_samr_CryptPassword(ndr, NDR_SCALARS, r->in.password));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.hash));
+ if (r->in.hash) {
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, r->in.hash));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_OemChangePasswordUser2(struct ndr_pull *ndr, int flags, struct samr_OemChangePasswordUser2 *r)
+{
+ uint32_t _ptr_server;
+ uint32_t _ptr_password;
+ uint32_t _ptr_hash;
+ TALLOC_CTX *_mem_save_server_0;
+ TALLOC_CTX *_mem_save_account_0;
+ TALLOC_CTX *_mem_save_password_0;
+ TALLOC_CTX *_mem_save_hash_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server));
+ if (_ptr_server) {
+ NDR_PULL_ALLOC(ndr, r->in.server);
+ } else {
+ r->in.server = NULL;
+ }
+ if (r->in.server) {
+ _mem_save_server_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server, 0);
+ NDR_CHECK(ndr_pull_lsa_AsciiString(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.server));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.account);
+ }
+ _mem_save_account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.account, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_AsciiString(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.account));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_account_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password));
+ if (_ptr_password) {
+ NDR_PULL_ALLOC(ndr, r->in.password);
+ } else {
+ r->in.password = NULL;
+ }
+ if (r->in.password) {
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.password, 0);
+ NDR_CHECK(ndr_pull_samr_CryptPassword(ndr, NDR_SCALARS, r->in.password));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_hash));
+ if (_ptr_hash) {
+ NDR_PULL_ALLOC(ndr, r->in.hash);
+ } else {
+ r->in.hash = NULL;
+ }
+ if (r->in.hash) {
+ _mem_save_hash_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.hash, 0);
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, r->in.hash));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_hash_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_OemChangePasswordUser2(struct ndr_print *ndr, const char *name, int flags, const struct samr_OemChangePasswordUser2 *r)
+{
+ ndr_print_struct(ndr, name, "samr_OemChangePasswordUser2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_OemChangePasswordUser2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server", r->in.server);
+ ndr->depth++;
+ if (r->in.server) {
+ ndr_print_lsa_AsciiString(ndr, "server", r->in.server);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "account", r->in.account);
+ ndr->depth++;
+ ndr_print_lsa_AsciiString(ndr, "account", r->in.account);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->in.password);
+ ndr->depth++;
+ if (r->in.password) {
+ ndr_print_samr_CryptPassword(ndr, "password", r->in.password);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "hash", r->in.hash);
+ ndr->depth++;
+ if (r->in.hash) {
+ ndr_print_samr_Password(ndr, "hash", r->in.hash);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_OemChangePasswordUser2");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_ChangePasswordUser2(struct ndr_push *ndr, int flags, const struct samr_ChangePasswordUser2 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server));
+ if (r->in.server) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.server));
+ }
+ if (r->in.account == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.account));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.nt_password));
+ if (r->in.nt_password) {
+ NDR_CHECK(ndr_push_samr_CryptPassword(ndr, NDR_SCALARS, r->in.nt_password));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.nt_verifier));
+ if (r->in.nt_verifier) {
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, r->in.nt_verifier));
+ }
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.lm_change));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.lm_password));
+ if (r->in.lm_password) {
+ NDR_CHECK(ndr_push_samr_CryptPassword(ndr, NDR_SCALARS, r->in.lm_password));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.lm_verifier));
+ if (r->in.lm_verifier) {
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, r->in.lm_verifier));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ChangePasswordUser2(struct ndr_pull *ndr, int flags, struct samr_ChangePasswordUser2 *r)
+{
+ uint32_t _ptr_server;
+ uint32_t _ptr_nt_password;
+ uint32_t _ptr_nt_verifier;
+ uint32_t _ptr_lm_password;
+ uint32_t _ptr_lm_verifier;
+ TALLOC_CTX *_mem_save_server_0;
+ TALLOC_CTX *_mem_save_account_0;
+ TALLOC_CTX *_mem_save_nt_password_0;
+ TALLOC_CTX *_mem_save_nt_verifier_0;
+ TALLOC_CTX *_mem_save_lm_password_0;
+ TALLOC_CTX *_mem_save_lm_verifier_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server));
+ if (_ptr_server) {
+ NDR_PULL_ALLOC(ndr, r->in.server);
+ } else {
+ r->in.server = NULL;
+ }
+ if (r->in.server) {
+ _mem_save_server_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server, 0);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.server));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.account);
+ }
+ _mem_save_account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.account, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.account));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_account_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_nt_password));
+ if (_ptr_nt_password) {
+ NDR_PULL_ALLOC(ndr, r->in.nt_password);
+ } else {
+ r->in.nt_password = NULL;
+ }
+ if (r->in.nt_password) {
+ _mem_save_nt_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.nt_password, 0);
+ NDR_CHECK(ndr_pull_samr_CryptPassword(ndr, NDR_SCALARS, r->in.nt_password));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_nt_password_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_nt_verifier));
+ if (_ptr_nt_verifier) {
+ NDR_PULL_ALLOC(ndr, r->in.nt_verifier);
+ } else {
+ r->in.nt_verifier = NULL;
+ }
+ if (r->in.nt_verifier) {
+ _mem_save_nt_verifier_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.nt_verifier, 0);
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, r->in.nt_verifier));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_nt_verifier_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.lm_change));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_lm_password));
+ if (_ptr_lm_password) {
+ NDR_PULL_ALLOC(ndr, r->in.lm_password);
+ } else {
+ r->in.lm_password = NULL;
+ }
+ if (r->in.lm_password) {
+ _mem_save_lm_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.lm_password, 0);
+ NDR_CHECK(ndr_pull_samr_CryptPassword(ndr, NDR_SCALARS, r->in.lm_password));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_lm_password_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_lm_verifier));
+ if (_ptr_lm_verifier) {
+ NDR_PULL_ALLOC(ndr, r->in.lm_verifier);
+ } else {
+ r->in.lm_verifier = NULL;
+ }
+ if (r->in.lm_verifier) {
+ _mem_save_lm_verifier_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.lm_verifier, 0);
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, r->in.lm_verifier));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_lm_verifier_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ChangePasswordUser2(struct ndr_print *ndr, const char *name, int flags, const struct samr_ChangePasswordUser2 *r)
+{
+ ndr_print_struct(ndr, name, "samr_ChangePasswordUser2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_ChangePasswordUser2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server", r->in.server);
+ ndr->depth++;
+ if (r->in.server) {
+ ndr_print_lsa_String(ndr, "server", r->in.server);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "account", r->in.account);
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "account", r->in.account);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "nt_password", r->in.nt_password);
+ ndr->depth++;
+ if (r->in.nt_password) {
+ ndr_print_samr_CryptPassword(ndr, "nt_password", r->in.nt_password);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "nt_verifier", r->in.nt_verifier);
+ ndr->depth++;
+ if (r->in.nt_verifier) {
+ ndr_print_samr_Password(ndr, "nt_verifier", r->in.nt_verifier);
+ }
+ ndr->depth--;
+ ndr_print_uint8(ndr, "lm_change", r->in.lm_change);
+ ndr_print_ptr(ndr, "lm_password", r->in.lm_password);
+ ndr->depth++;
+ if (r->in.lm_password) {
+ ndr_print_samr_CryptPassword(ndr, "lm_password", r->in.lm_password);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "lm_verifier", r->in.lm_verifier);
+ ndr->depth++;
+ if (r->in.lm_verifier) {
+ ndr_print_samr_Password(ndr, "lm_verifier", r->in.lm_verifier);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_ChangePasswordUser2");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_GetDomPwInfo(struct ndr_push *ndr, int flags, const struct samr_GetDomPwInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.domain_name));
+ if (r->in.domain_name) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.domain_name));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_samr_PwInfo(ndr, NDR_SCALARS, r->out.info));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_GetDomPwInfo(struct ndr_pull *ndr, int flags, struct samr_GetDomPwInfo *r)
+{
+ uint32_t _ptr_domain_name;
+ TALLOC_CTX *_mem_save_domain_name_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_name));
+ if (_ptr_domain_name) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_name);
+ } else {
+ r->in.domain_name = NULL;
+ }
+ if (r->in.domain_name) {
+ _mem_save_domain_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_name, 0);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.domain_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_name_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_samr_PwInfo(ndr, NDR_SCALARS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_GetDomPwInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetDomPwInfo *r)
+{
+ ndr_print_struct(ndr, name, "samr_GetDomPwInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_GetDomPwInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_name", r->in.domain_name);
+ ndr->depth++;
+ if (r->in.domain_name) {
+ ndr_print_lsa_String(ndr, "domain_name", r->in.domain_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_GetDomPwInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_samr_PwInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_Connect2(struct ndr_push *ndr, int flags, const struct samr_Connect2 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.system_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.system_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.system_name, ndr_charset_length(r->in.system_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_samr_ConnectAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.connect_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.connect_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_Connect2(struct ndr_pull *ndr, int flags, struct samr_Connect2 *r)
+{
+ uint32_t _ptr_system_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_connect_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.system_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.system_name));
+ if (ndr_get_array_length(ndr, &r->in.system_name) > ndr_get_array_size(ndr, &r->in.system_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.system_name), ndr_get_array_length(ndr, &r->in.system_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.system_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.system_name, ndr_get_array_length(ndr, &r->in.system_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_samr_ConnectAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.connect_handle);
+ ZERO_STRUCTP(r->out.connect_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.connect_handle);
+ }
+ _mem_save_connect_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.connect_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.connect_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_connect_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_Connect2(struct ndr_print *ndr, const char *name, int flags, const struct samr_Connect2 *r)
+{
+ ndr_print_struct(ndr, name, "samr_Connect2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_Connect2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_string(ndr, "system_name", r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_samr_ConnectAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_Connect2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "connect_handle", r->out.connect_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "connect_handle", r->out.connect_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_SetUserInfo2(struct ndr_push *ndr, int flags, const struct samr_SetUserInfo2 *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.user_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_samr_UserInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_SetUserInfo2(struct ndr_pull *ndr, int flags, struct samr_SetUserInfo2 *r)
+{
+ TALLOC_CTX *_mem_save_user_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.user_handle);
+ }
+ _mem_save_user_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.user_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.user_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_samr_UserInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_SetUserInfo2(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetUserInfo2 *r)
+{
+ ndr_print_struct(ndr, name, "samr_SetUserInfo2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_SetUserInfo2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "user_handle", r->in.user_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "user_handle", r->in.user_handle);
+ ndr->depth--;
+ ndr_print_uint16(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.info, r->in.level);
+ ndr_print_samr_UserInfo(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_SetUserInfo2");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_SetBootKeyInformation(struct ndr_push *ndr, int flags, const struct samr_SetBootKeyInformation *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.connect_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.connect_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown3));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_SetBootKeyInformation(struct ndr_pull *ndr, int flags, struct samr_SetBootKeyInformation *r)
+{
+ TALLOC_CTX *_mem_save_connect_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.connect_handle);
+ }
+ _mem_save_connect_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.connect_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.connect_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_connect_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown3));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_SetBootKeyInformation(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetBootKeyInformation *r)
+{
+ ndr_print_struct(ndr, name, "samr_SetBootKeyInformation");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_SetBootKeyInformation");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "connect_handle", r->in.connect_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "connect_handle", r->in.connect_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown1", r->in.unknown1);
+ ndr_print_uint32(ndr, "unknown2", r->in.unknown2);
+ ndr_print_uint32(ndr, "unknown3", r->in.unknown3);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_SetBootKeyInformation");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_GetBootKeyInformation(struct ndr_push *ndr, int flags, const struct samr_GetBootKeyInformation *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.unknown == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.unknown));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_GetBootKeyInformation(struct ndr_pull *ndr, int flags, struct samr_GetBootKeyInformation *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_unknown_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.unknown);
+ ZERO_STRUCTP(r->out.unknown);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.unknown);
+ }
+ _mem_save_unknown_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.unknown, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.unknown));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_GetBootKeyInformation(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetBootKeyInformation *r)
+{
+ ndr_print_struct(ndr, name, "samr_GetBootKeyInformation");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_GetBootKeyInformation");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_GetBootKeyInformation");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "unknown", r->out.unknown);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "unknown", *r->out.unknown);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_Connect3(struct ndr_push *ndr, int flags, const struct samr_Connect3 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.system_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.system_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.system_name, ndr_charset_length(r->in.system_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown));
+ NDR_CHECK(ndr_push_samr_ConnectAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.connect_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.connect_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_Connect3(struct ndr_pull *ndr, int flags, struct samr_Connect3 *r)
+{
+ uint32_t _ptr_system_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_connect_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.system_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.system_name));
+ if (ndr_get_array_length(ndr, &r->in.system_name) > ndr_get_array_size(ndr, &r->in.system_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.system_name), ndr_get_array_length(ndr, &r->in.system_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.system_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.system_name, ndr_get_array_length(ndr, &r->in.system_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown));
+ NDR_CHECK(ndr_pull_samr_ConnectAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.connect_handle);
+ ZERO_STRUCTP(r->out.connect_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.connect_handle);
+ }
+ _mem_save_connect_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.connect_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.connect_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_connect_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_Connect3(struct ndr_print *ndr, const char *name, int flags, const struct samr_Connect3 *r)
+{
+ ndr_print_struct(ndr, name, "samr_Connect3");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_Connect3");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_string(ndr, "system_name", r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown", r->in.unknown);
+ ndr_print_samr_ConnectAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_Connect3");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "connect_handle", r->out.connect_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "connect_handle", r->out.connect_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_Connect4(struct ndr_push *ndr, int flags, const struct samr_Connect4 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.system_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.system_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.system_name, ndr_charset_length(r->in.system_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_samr_ConnectVersion(ndr, NDR_SCALARS, r->in.client_version));
+ NDR_CHECK(ndr_push_samr_ConnectAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.connect_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.connect_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_Connect4(struct ndr_pull *ndr, int flags, struct samr_Connect4 *r)
+{
+ uint32_t _ptr_system_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_connect_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.system_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.system_name));
+ if (ndr_get_array_length(ndr, &r->in.system_name) > ndr_get_array_size(ndr, &r->in.system_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.system_name), ndr_get_array_length(ndr, &r->in.system_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.system_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.system_name, ndr_get_array_length(ndr, &r->in.system_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_samr_ConnectVersion(ndr, NDR_SCALARS, &r->in.client_version));
+ NDR_CHECK(ndr_pull_samr_ConnectAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.connect_handle);
+ ZERO_STRUCTP(r->out.connect_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.connect_handle);
+ }
+ _mem_save_connect_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.connect_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.connect_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_connect_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_Connect4(struct ndr_print *ndr, const char *name, int flags, const struct samr_Connect4 *r)
+{
+ ndr_print_struct(ndr, name, "samr_Connect4");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_Connect4");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_string(ndr, "system_name", r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_samr_ConnectVersion(ndr, "client_version", r->in.client_version);
+ ndr_print_samr_ConnectAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_Connect4");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "connect_handle", r->out.connect_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "connect_handle", r->out.connect_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_ChangePasswordUser3(struct ndr_push *ndr, int flags, const struct samr_ChangePasswordUser3 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server));
+ if (r->in.server) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.server));
+ }
+ if (r->in.account == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.account));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.nt_password));
+ if (r->in.nt_password) {
+ NDR_CHECK(ndr_push_samr_CryptPassword(ndr, NDR_SCALARS, r->in.nt_password));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.nt_verifier));
+ if (r->in.nt_verifier) {
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, r->in.nt_verifier));
+ }
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.lm_change));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.lm_password));
+ if (r->in.lm_password) {
+ NDR_CHECK(ndr_push_samr_CryptPassword(ndr, NDR_SCALARS, r->in.lm_password));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.lm_verifier));
+ if (r->in.lm_verifier) {
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, r->in.lm_verifier));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.password3));
+ if (r->in.password3) {
+ NDR_CHECK(ndr_push_samr_CryptPassword(ndr, NDR_SCALARS, r->in.password3));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.dominfo == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.dominfo));
+ if (*r->out.dominfo) {
+ NDR_CHECK(ndr_push_samr_DomInfo1(ndr, NDR_SCALARS, *r->out.dominfo));
+ }
+ if (r->out.reject == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.reject));
+ if (*r->out.reject) {
+ NDR_CHECK(ndr_push_samr_ChangeReject(ndr, NDR_SCALARS, *r->out.reject));
+ }
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ChangePasswordUser3(struct ndr_pull *ndr, int flags, struct samr_ChangePasswordUser3 *r)
+{
+ uint32_t _ptr_server;
+ uint32_t _ptr_nt_password;
+ uint32_t _ptr_nt_verifier;
+ uint32_t _ptr_lm_password;
+ uint32_t _ptr_lm_verifier;
+ uint32_t _ptr_password3;
+ uint32_t _ptr_dominfo;
+ uint32_t _ptr_reject;
+ TALLOC_CTX *_mem_save_server_0;
+ TALLOC_CTX *_mem_save_account_0;
+ TALLOC_CTX *_mem_save_nt_password_0;
+ TALLOC_CTX *_mem_save_nt_verifier_0;
+ TALLOC_CTX *_mem_save_lm_password_0;
+ TALLOC_CTX *_mem_save_lm_verifier_0;
+ TALLOC_CTX *_mem_save_password3_0;
+ TALLOC_CTX *_mem_save_dominfo_0;
+ TALLOC_CTX *_mem_save_dominfo_1;
+ TALLOC_CTX *_mem_save_reject_0;
+ TALLOC_CTX *_mem_save_reject_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server));
+ if (_ptr_server) {
+ NDR_PULL_ALLOC(ndr, r->in.server);
+ } else {
+ r->in.server = NULL;
+ }
+ if (r->in.server) {
+ _mem_save_server_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server, 0);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.server));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.account);
+ }
+ _mem_save_account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.account, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.account));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_account_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_nt_password));
+ if (_ptr_nt_password) {
+ NDR_PULL_ALLOC(ndr, r->in.nt_password);
+ } else {
+ r->in.nt_password = NULL;
+ }
+ if (r->in.nt_password) {
+ _mem_save_nt_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.nt_password, 0);
+ NDR_CHECK(ndr_pull_samr_CryptPassword(ndr, NDR_SCALARS, r->in.nt_password));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_nt_password_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_nt_verifier));
+ if (_ptr_nt_verifier) {
+ NDR_PULL_ALLOC(ndr, r->in.nt_verifier);
+ } else {
+ r->in.nt_verifier = NULL;
+ }
+ if (r->in.nt_verifier) {
+ _mem_save_nt_verifier_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.nt_verifier, 0);
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, r->in.nt_verifier));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_nt_verifier_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.lm_change));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_lm_password));
+ if (_ptr_lm_password) {
+ NDR_PULL_ALLOC(ndr, r->in.lm_password);
+ } else {
+ r->in.lm_password = NULL;
+ }
+ if (r->in.lm_password) {
+ _mem_save_lm_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.lm_password, 0);
+ NDR_CHECK(ndr_pull_samr_CryptPassword(ndr, NDR_SCALARS, r->in.lm_password));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_lm_password_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_lm_verifier));
+ if (_ptr_lm_verifier) {
+ NDR_PULL_ALLOC(ndr, r->in.lm_verifier);
+ } else {
+ r->in.lm_verifier = NULL;
+ }
+ if (r->in.lm_verifier) {
+ _mem_save_lm_verifier_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.lm_verifier, 0);
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, r->in.lm_verifier));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_lm_verifier_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password3));
+ if (_ptr_password3) {
+ NDR_PULL_ALLOC(ndr, r->in.password3);
+ } else {
+ r->in.password3 = NULL;
+ }
+ if (r->in.password3) {
+ _mem_save_password3_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.password3, 0);
+ NDR_CHECK(ndr_pull_samr_CryptPassword(ndr, NDR_SCALARS, r->in.password3));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password3_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.dominfo);
+ ZERO_STRUCTP(r->out.dominfo);
+ NDR_PULL_ALLOC(ndr, r->out.reject);
+ ZERO_STRUCTP(r->out.reject);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.dominfo);
+ }
+ _mem_save_dominfo_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.dominfo, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dominfo));
+ if (_ptr_dominfo) {
+ NDR_PULL_ALLOC(ndr, *r->out.dominfo);
+ } else {
+ *r->out.dominfo = NULL;
+ }
+ if (*r->out.dominfo) {
+ _mem_save_dominfo_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.dominfo, 0);
+ NDR_CHECK(ndr_pull_samr_DomInfo1(ndr, NDR_SCALARS, *r->out.dominfo));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dominfo_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dominfo_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.reject);
+ }
+ _mem_save_reject_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.reject, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_reject));
+ if (_ptr_reject) {
+ NDR_PULL_ALLOC(ndr, *r->out.reject);
+ } else {
+ *r->out.reject = NULL;
+ }
+ if (*r->out.reject) {
+ _mem_save_reject_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.reject, 0);
+ NDR_CHECK(ndr_pull_samr_ChangeReject(ndr, NDR_SCALARS, *r->out.reject));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_reject_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_reject_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ChangePasswordUser3(struct ndr_print *ndr, const char *name, int flags, const struct samr_ChangePasswordUser3 *r)
+{
+ ndr_print_struct(ndr, name, "samr_ChangePasswordUser3");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_ChangePasswordUser3");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server", r->in.server);
+ ndr->depth++;
+ if (r->in.server) {
+ ndr_print_lsa_String(ndr, "server", r->in.server);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "account", r->in.account);
+ ndr->depth++;
+ ndr_print_lsa_String(ndr, "account", r->in.account);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "nt_password", r->in.nt_password);
+ ndr->depth++;
+ if (r->in.nt_password) {
+ ndr_print_samr_CryptPassword(ndr, "nt_password", r->in.nt_password);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "nt_verifier", r->in.nt_verifier);
+ ndr->depth++;
+ if (r->in.nt_verifier) {
+ ndr_print_samr_Password(ndr, "nt_verifier", r->in.nt_verifier);
+ }
+ ndr->depth--;
+ ndr_print_uint8(ndr, "lm_change", r->in.lm_change);
+ ndr_print_ptr(ndr, "lm_password", r->in.lm_password);
+ ndr->depth++;
+ if (r->in.lm_password) {
+ ndr_print_samr_CryptPassword(ndr, "lm_password", r->in.lm_password);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "lm_verifier", r->in.lm_verifier);
+ ndr->depth++;
+ if (r->in.lm_verifier) {
+ ndr_print_samr_Password(ndr, "lm_verifier", r->in.lm_verifier);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password3", r->in.password3);
+ ndr->depth++;
+ if (r->in.password3) {
+ ndr_print_samr_CryptPassword(ndr, "password3", r->in.password3);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_ChangePasswordUser3");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "dominfo", r->out.dominfo);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "dominfo", *r->out.dominfo);
+ ndr->depth++;
+ if (*r->out.dominfo) {
+ ndr_print_samr_DomInfo1(ndr, "dominfo", *r->out.dominfo);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "reject", r->out.reject);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "reject", *r->out.reject);
+ ndr->depth++;
+ if (*r->out.reject) {
+ ndr_print_samr_ChangeReject(ndr, "reject", *r->out.reject);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_samr_Connect5(struct ndr_push *ndr, int flags, const struct samr_Connect5 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.system_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.system_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.system_name, ndr_charset_length(r->in.system_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_samr_ConnectAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level_in));
+ if (r->in.info_in == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.info_in, r->in.level_in));
+ NDR_CHECK(ndr_push_samr_ConnectInfo(ndr, NDR_SCALARS, r->in.info_in));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.level_out == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.level_out));
+ if (r->out.info_out == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info_out, *r->out.level_out));
+ NDR_CHECK(ndr_push_samr_ConnectInfo(ndr, NDR_SCALARS, r->out.info_out));
+ if (r->out.connect_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->out.connect_handle));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_samr_Connect5(struct ndr_pull *ndr, int flags, struct samr_Connect5 *r)
+{
+ uint32_t _ptr_system_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_info_in_0;
+ TALLOC_CTX *_mem_save_level_out_0;
+ TALLOC_CTX *_mem_save_info_out_0;
+ TALLOC_CTX *_mem_save_connect_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.system_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.system_name));
+ if (ndr_get_array_length(ndr, &r->in.system_name) > ndr_get_array_size(ndr, &r->in.system_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.system_name), ndr_get_array_length(ndr, &r->in.system_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.system_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.system_name, ndr_get_array_length(ndr, &r->in.system_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_samr_ConnectAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level_in));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info_in);
+ }
+ _mem_save_info_in_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info_in, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.info_in, r->in.level_in));
+ NDR_CHECK(ndr_pull_samr_ConnectInfo(ndr, NDR_SCALARS, r->in.info_in));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_in_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ ZERO_STRUCTP(r->out.level_out);
+ NDR_PULL_ALLOC(ndr, r->out.info_out);
+ ZERO_STRUCTP(r->out.info_out);
+ NDR_PULL_ALLOC(ndr, r->out.connect_handle);
+ ZERO_STRUCTP(r->out.connect_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.level_out);
+ }
+ _mem_save_level_out_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.level_out, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.level_out));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_out_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info_out);
+ }
+ _mem_save_info_out_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info_out, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info_out, *r->out.level_out));
+ NDR_CHECK(ndr_pull_samr_ConnectInfo(ndr, NDR_SCALARS, r->out.info_out));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_out_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.connect_handle);
+ }
+ _mem_save_connect_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.connect_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->out.connect_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_connect_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_Connect5(struct ndr_print *ndr, const char *name, int flags, const struct samr_Connect5 *r)
+{
+ ndr_print_struct(ndr, name, "samr_Connect5");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_Connect5");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_string(ndr, "system_name", r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_samr_ConnectAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr_print_uint32(ndr, "level_in", r->in.level_in);
+ ndr_print_ptr(ndr, "info_in", r->in.info_in);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.info_in, r->in.level_in);
+ ndr_print_samr_ConnectInfo(ndr, "info_in", r->in.info_in);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_Connect5");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "level_out", r->out.level_out);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level_out", *r->out.level_out);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "info_out", r->out.info_out);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info_out, *r->out.level_out);
+ ndr_print_samr_ConnectInfo(ndr, "info_out", r->out.info_out);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "connect_handle", r->out.connect_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "connect_handle", r->out.connect_handle);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_RidToSid(struct ndr_push *ndr, int flags, const struct samr_RidToSid *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.rid));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.sid == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sid));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_RidToSid(struct ndr_pull *ndr, int flags, struct samr_RidToSid *r)
+{
+ TALLOC_CTX *_mem_save_domain_handle_0;
+ TALLOC_CTX *_mem_save_sid_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.domain_handle);
+ }
+ _mem_save_domain_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.domain_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS, r->in.domain_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.rid));
+ NDR_PULL_ALLOC(ndr, r->out.sid);
+ ZERO_STRUCTP(r->out.sid);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sid);
+ }
+ _mem_save_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sid, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_dom_sid2(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sid_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_RidToSid(struct ndr_print *ndr, const char *name, int flags, const struct samr_RidToSid *r)
+{
+ ndr_print_struct(ndr, name, "samr_RidToSid");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_RidToSid");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "domain_handle", r->in.domain_handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "rid", r->in.rid);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_RidToSid");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sid", r->out.sid);
+ ndr->depth++;
+ ndr_print_dom_sid2(ndr, "sid", r->out.sid);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_SetDsrmPassword(struct ndr_push *ndr, int flags, const struct samr_SetDsrmPassword *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.name));
+ if (r->in.name) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.hash));
+ if (r->in.hash) {
+ NDR_CHECK(ndr_push_samr_Password(ndr, NDR_SCALARS, r->in.hash));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_SetDsrmPassword(struct ndr_pull *ndr, int flags, struct samr_SetDsrmPassword *r)
+{
+ uint32_t _ptr_name;
+ uint32_t _ptr_hash;
+ TALLOC_CTX *_mem_save_name_0;
+ TALLOC_CTX *_mem_save_hash_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->in.name);
+ } else {
+ r->in.name = NULL;
+ }
+ if (r->in.name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.name, 0);
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_hash));
+ if (_ptr_hash) {
+ NDR_PULL_ALLOC(ndr, r->in.hash);
+ } else {
+ r->in.hash = NULL;
+ }
+ if (r->in.hash) {
+ _mem_save_hash_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.hash, 0);
+ NDR_CHECK(ndr_pull_samr_Password(ndr, NDR_SCALARS, r->in.hash));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_hash_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_SetDsrmPassword(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetDsrmPassword *r)
+{
+ ndr_print_struct(ndr, name, "samr_SetDsrmPassword");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_SetDsrmPassword");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "name", r->in.name);
+ ndr->depth++;
+ if (r->in.name) {
+ ndr_print_lsa_String(ndr, "name", r->in.name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown", r->in.unknown);
+ ndr_print_ptr(ndr, "hash", r->in.hash);
+ ndr->depth++;
+ if (r->in.hash) {
+ ndr_print_samr_Password(ndr, "hash", r->in.hash);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_SetDsrmPassword");
+ ndr->depth++;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_samr_ValidatePassword(struct ndr_push *ndr, int flags, const struct samr_ValidatePassword *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_samr_ValidatePasswordLevel(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->in.req, r->in.level));
+ NDR_CHECK(ndr_push_samr_ValidatePasswordReq(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.req));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.rep == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.rep, r->in.level));
+ NDR_CHECK(ndr_push_samr_ValidatePasswordRep(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.rep));
+ NDR_CHECK(ndr_push_NTSTATUS(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_samr_ValidatePassword(struct ndr_pull *ndr, int flags, struct samr_ValidatePassword *r)
+{
+ TALLOC_CTX *_mem_save_rep_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordLevel(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->in.req, r->in.level));
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordReq(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.req));
+ NDR_PULL_ALLOC(ndr, r->out.rep);
+ ZERO_STRUCTP(r->out.rep);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.rep);
+ }
+ _mem_save_rep_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.rep, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.rep, r->in.level));
+ NDR_CHECK(ndr_pull_samr_ValidatePasswordRep(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.rep));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_rep_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTSTATUS(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_samr_ValidatePassword(struct ndr_print *ndr, const char *name, int flags, const struct samr_ValidatePassword *r)
+{
+ ndr_print_struct(ndr, name, "samr_ValidatePassword");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "samr_ValidatePassword");
+ ndr->depth++;
+ ndr_print_samr_ValidatePasswordLevel(ndr, "level", r->in.level);
+ ndr_print_set_switch_value(ndr, &r->in.req, r->in.level);
+ ndr_print_samr_ValidatePasswordReq(ndr, "req", &r->in.req);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "samr_ValidatePassword");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "rep", r->out.rep);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.rep, r->in.level);
+ ndr_print_samr_ValidatePasswordRep(ndr, "rep", r->out.rep);
+ ndr->depth--;
+ ndr_print_NTSTATUS(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call samr_calls[] = {
+ {
+ "samr_Connect",
+ sizeof(struct samr_Connect),
+ (ndr_push_flags_fn_t) ndr_push_samr_Connect,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_Connect,
+ (ndr_print_function_t) ndr_print_samr_Connect,
+ false,
+ },
+ {
+ "samr_Close",
+ sizeof(struct samr_Close),
+ (ndr_push_flags_fn_t) ndr_push_samr_Close,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_Close,
+ (ndr_print_function_t) ndr_print_samr_Close,
+ false,
+ },
+ {
+ "samr_SetSecurity",
+ sizeof(struct samr_SetSecurity),
+ (ndr_push_flags_fn_t) ndr_push_samr_SetSecurity,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_SetSecurity,
+ (ndr_print_function_t) ndr_print_samr_SetSecurity,
+ false,
+ },
+ {
+ "samr_QuerySecurity",
+ sizeof(struct samr_QuerySecurity),
+ (ndr_push_flags_fn_t) ndr_push_samr_QuerySecurity,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_QuerySecurity,
+ (ndr_print_function_t) ndr_print_samr_QuerySecurity,
+ false,
+ },
+ {
+ "samr_Shutdown",
+ sizeof(struct samr_Shutdown),
+ (ndr_push_flags_fn_t) ndr_push_samr_Shutdown,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_Shutdown,
+ (ndr_print_function_t) ndr_print_samr_Shutdown,
+ false,
+ },
+ {
+ "samr_LookupDomain",
+ sizeof(struct samr_LookupDomain),
+ (ndr_push_flags_fn_t) ndr_push_samr_LookupDomain,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_LookupDomain,
+ (ndr_print_function_t) ndr_print_samr_LookupDomain,
+ false,
+ },
+ {
+ "samr_EnumDomains",
+ sizeof(struct samr_EnumDomains),
+ (ndr_push_flags_fn_t) ndr_push_samr_EnumDomains,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_EnumDomains,
+ (ndr_print_function_t) ndr_print_samr_EnumDomains,
+ false,
+ },
+ {
+ "samr_OpenDomain",
+ sizeof(struct samr_OpenDomain),
+ (ndr_push_flags_fn_t) ndr_push_samr_OpenDomain,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_OpenDomain,
+ (ndr_print_function_t) ndr_print_samr_OpenDomain,
+ false,
+ },
+ {
+ "samr_QueryDomainInfo",
+ sizeof(struct samr_QueryDomainInfo),
+ (ndr_push_flags_fn_t) ndr_push_samr_QueryDomainInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_QueryDomainInfo,
+ (ndr_print_function_t) ndr_print_samr_QueryDomainInfo,
+ false,
+ },
+ {
+ "samr_SetDomainInfo",
+ sizeof(struct samr_SetDomainInfo),
+ (ndr_push_flags_fn_t) ndr_push_samr_SetDomainInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_SetDomainInfo,
+ (ndr_print_function_t) ndr_print_samr_SetDomainInfo,
+ false,
+ },
+ {
+ "samr_CreateDomainGroup",
+ sizeof(struct samr_CreateDomainGroup),
+ (ndr_push_flags_fn_t) ndr_push_samr_CreateDomainGroup,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_CreateDomainGroup,
+ (ndr_print_function_t) ndr_print_samr_CreateDomainGroup,
+ false,
+ },
+ {
+ "samr_EnumDomainGroups",
+ sizeof(struct samr_EnumDomainGroups),
+ (ndr_push_flags_fn_t) ndr_push_samr_EnumDomainGroups,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_EnumDomainGroups,
+ (ndr_print_function_t) ndr_print_samr_EnumDomainGroups,
+ false,
+ },
+ {
+ "samr_CreateUser",
+ sizeof(struct samr_CreateUser),
+ (ndr_push_flags_fn_t) ndr_push_samr_CreateUser,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_CreateUser,
+ (ndr_print_function_t) ndr_print_samr_CreateUser,
+ false,
+ },
+ {
+ "samr_EnumDomainUsers",
+ sizeof(struct samr_EnumDomainUsers),
+ (ndr_push_flags_fn_t) ndr_push_samr_EnumDomainUsers,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_EnumDomainUsers,
+ (ndr_print_function_t) ndr_print_samr_EnumDomainUsers,
+ false,
+ },
+ {
+ "samr_CreateDomAlias",
+ sizeof(struct samr_CreateDomAlias),
+ (ndr_push_flags_fn_t) ndr_push_samr_CreateDomAlias,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_CreateDomAlias,
+ (ndr_print_function_t) ndr_print_samr_CreateDomAlias,
+ false,
+ },
+ {
+ "samr_EnumDomainAliases",
+ sizeof(struct samr_EnumDomainAliases),
+ (ndr_push_flags_fn_t) ndr_push_samr_EnumDomainAliases,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_EnumDomainAliases,
+ (ndr_print_function_t) ndr_print_samr_EnumDomainAliases,
+ false,
+ },
+ {
+ "samr_GetAliasMembership",
+ sizeof(struct samr_GetAliasMembership),
+ (ndr_push_flags_fn_t) ndr_push_samr_GetAliasMembership,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_GetAliasMembership,
+ (ndr_print_function_t) ndr_print_samr_GetAliasMembership,
+ false,
+ },
+ {
+ "samr_LookupNames",
+ sizeof(struct samr_LookupNames),
+ (ndr_push_flags_fn_t) ndr_push_samr_LookupNames,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_LookupNames,
+ (ndr_print_function_t) ndr_print_samr_LookupNames,
+ false,
+ },
+ {
+ "samr_LookupRids",
+ sizeof(struct samr_LookupRids),
+ (ndr_push_flags_fn_t) ndr_push_samr_LookupRids,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_LookupRids,
+ (ndr_print_function_t) ndr_print_samr_LookupRids,
+ false,
+ },
+ {
+ "samr_OpenGroup",
+ sizeof(struct samr_OpenGroup),
+ (ndr_push_flags_fn_t) ndr_push_samr_OpenGroup,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_OpenGroup,
+ (ndr_print_function_t) ndr_print_samr_OpenGroup,
+ false,
+ },
+ {
+ "samr_QueryGroupInfo",
+ sizeof(struct samr_QueryGroupInfo),
+ (ndr_push_flags_fn_t) ndr_push_samr_QueryGroupInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_QueryGroupInfo,
+ (ndr_print_function_t) ndr_print_samr_QueryGroupInfo,
+ false,
+ },
+ {
+ "samr_SetGroupInfo",
+ sizeof(struct samr_SetGroupInfo),
+ (ndr_push_flags_fn_t) ndr_push_samr_SetGroupInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_SetGroupInfo,
+ (ndr_print_function_t) ndr_print_samr_SetGroupInfo,
+ false,
+ },
+ {
+ "samr_AddGroupMember",
+ sizeof(struct samr_AddGroupMember),
+ (ndr_push_flags_fn_t) ndr_push_samr_AddGroupMember,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_AddGroupMember,
+ (ndr_print_function_t) ndr_print_samr_AddGroupMember,
+ false,
+ },
+ {
+ "samr_DeleteDomainGroup",
+ sizeof(struct samr_DeleteDomainGroup),
+ (ndr_push_flags_fn_t) ndr_push_samr_DeleteDomainGroup,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_DeleteDomainGroup,
+ (ndr_print_function_t) ndr_print_samr_DeleteDomainGroup,
+ false,
+ },
+ {
+ "samr_DeleteGroupMember",
+ sizeof(struct samr_DeleteGroupMember),
+ (ndr_push_flags_fn_t) ndr_push_samr_DeleteGroupMember,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_DeleteGroupMember,
+ (ndr_print_function_t) ndr_print_samr_DeleteGroupMember,
+ false,
+ },
+ {
+ "samr_QueryGroupMember",
+ sizeof(struct samr_QueryGroupMember),
+ (ndr_push_flags_fn_t) ndr_push_samr_QueryGroupMember,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_QueryGroupMember,
+ (ndr_print_function_t) ndr_print_samr_QueryGroupMember,
+ false,
+ },
+ {
+ "samr_SetMemberAttributesOfGroup",
+ sizeof(struct samr_SetMemberAttributesOfGroup),
+ (ndr_push_flags_fn_t) ndr_push_samr_SetMemberAttributesOfGroup,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_SetMemberAttributesOfGroup,
+ (ndr_print_function_t) ndr_print_samr_SetMemberAttributesOfGroup,
+ false,
+ },
+ {
+ "samr_OpenAlias",
+ sizeof(struct samr_OpenAlias),
+ (ndr_push_flags_fn_t) ndr_push_samr_OpenAlias,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_OpenAlias,
+ (ndr_print_function_t) ndr_print_samr_OpenAlias,
+ false,
+ },
+ {
+ "samr_QueryAliasInfo",
+ sizeof(struct samr_QueryAliasInfo),
+ (ndr_push_flags_fn_t) ndr_push_samr_QueryAliasInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_QueryAliasInfo,
+ (ndr_print_function_t) ndr_print_samr_QueryAliasInfo,
+ false,
+ },
+ {
+ "samr_SetAliasInfo",
+ sizeof(struct samr_SetAliasInfo),
+ (ndr_push_flags_fn_t) ndr_push_samr_SetAliasInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_SetAliasInfo,
+ (ndr_print_function_t) ndr_print_samr_SetAliasInfo,
+ false,
+ },
+ {
+ "samr_DeleteDomAlias",
+ sizeof(struct samr_DeleteDomAlias),
+ (ndr_push_flags_fn_t) ndr_push_samr_DeleteDomAlias,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_DeleteDomAlias,
+ (ndr_print_function_t) ndr_print_samr_DeleteDomAlias,
+ false,
+ },
+ {
+ "samr_AddAliasMember",
+ sizeof(struct samr_AddAliasMember),
+ (ndr_push_flags_fn_t) ndr_push_samr_AddAliasMember,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_AddAliasMember,
+ (ndr_print_function_t) ndr_print_samr_AddAliasMember,
+ false,
+ },
+ {
+ "samr_DeleteAliasMember",
+ sizeof(struct samr_DeleteAliasMember),
+ (ndr_push_flags_fn_t) ndr_push_samr_DeleteAliasMember,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_DeleteAliasMember,
+ (ndr_print_function_t) ndr_print_samr_DeleteAliasMember,
+ false,
+ },
+ {
+ "samr_GetMembersInAlias",
+ sizeof(struct samr_GetMembersInAlias),
+ (ndr_push_flags_fn_t) ndr_push_samr_GetMembersInAlias,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_GetMembersInAlias,
+ (ndr_print_function_t) ndr_print_samr_GetMembersInAlias,
+ false,
+ },
+ {
+ "samr_OpenUser",
+ sizeof(struct samr_OpenUser),
+ (ndr_push_flags_fn_t) ndr_push_samr_OpenUser,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_OpenUser,
+ (ndr_print_function_t) ndr_print_samr_OpenUser,
+ false,
+ },
+ {
+ "samr_DeleteUser",
+ sizeof(struct samr_DeleteUser),
+ (ndr_push_flags_fn_t) ndr_push_samr_DeleteUser,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_DeleteUser,
+ (ndr_print_function_t) ndr_print_samr_DeleteUser,
+ false,
+ },
+ {
+ "samr_QueryUserInfo",
+ sizeof(struct samr_QueryUserInfo),
+ (ndr_push_flags_fn_t) ndr_push_samr_QueryUserInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_QueryUserInfo,
+ (ndr_print_function_t) ndr_print_samr_QueryUserInfo,
+ false,
+ },
+ {
+ "samr_SetUserInfo",
+ sizeof(struct samr_SetUserInfo),
+ (ndr_push_flags_fn_t) ndr_push_samr_SetUserInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_SetUserInfo,
+ (ndr_print_function_t) ndr_print_samr_SetUserInfo,
+ false,
+ },
+ {
+ "samr_ChangePasswordUser",
+ sizeof(struct samr_ChangePasswordUser),
+ (ndr_push_flags_fn_t) ndr_push_samr_ChangePasswordUser,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_ChangePasswordUser,
+ (ndr_print_function_t) ndr_print_samr_ChangePasswordUser,
+ false,
+ },
+ {
+ "samr_GetGroupsForUser",
+ sizeof(struct samr_GetGroupsForUser),
+ (ndr_push_flags_fn_t) ndr_push_samr_GetGroupsForUser,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_GetGroupsForUser,
+ (ndr_print_function_t) ndr_print_samr_GetGroupsForUser,
+ false,
+ },
+ {
+ "samr_QueryDisplayInfo",
+ sizeof(struct samr_QueryDisplayInfo),
+ (ndr_push_flags_fn_t) ndr_push_samr_QueryDisplayInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_QueryDisplayInfo,
+ (ndr_print_function_t) ndr_print_samr_QueryDisplayInfo,
+ false,
+ },
+ {
+ "samr_GetDisplayEnumerationIndex",
+ sizeof(struct samr_GetDisplayEnumerationIndex),
+ (ndr_push_flags_fn_t) ndr_push_samr_GetDisplayEnumerationIndex,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_GetDisplayEnumerationIndex,
+ (ndr_print_function_t) ndr_print_samr_GetDisplayEnumerationIndex,
+ false,
+ },
+ {
+ "samr_TestPrivateFunctionsDomain",
+ sizeof(struct samr_TestPrivateFunctionsDomain),
+ (ndr_push_flags_fn_t) ndr_push_samr_TestPrivateFunctionsDomain,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_TestPrivateFunctionsDomain,
+ (ndr_print_function_t) ndr_print_samr_TestPrivateFunctionsDomain,
+ false,
+ },
+ {
+ "samr_TestPrivateFunctionsUser",
+ sizeof(struct samr_TestPrivateFunctionsUser),
+ (ndr_push_flags_fn_t) ndr_push_samr_TestPrivateFunctionsUser,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_TestPrivateFunctionsUser,
+ (ndr_print_function_t) ndr_print_samr_TestPrivateFunctionsUser,
+ false,
+ },
+ {
+ "samr_GetUserPwInfo",
+ sizeof(struct samr_GetUserPwInfo),
+ (ndr_push_flags_fn_t) ndr_push_samr_GetUserPwInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_GetUserPwInfo,
+ (ndr_print_function_t) ndr_print_samr_GetUserPwInfo,
+ false,
+ },
+ {
+ "samr_RemoveMemberFromForeignDomain",
+ sizeof(struct samr_RemoveMemberFromForeignDomain),
+ (ndr_push_flags_fn_t) ndr_push_samr_RemoveMemberFromForeignDomain,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_RemoveMemberFromForeignDomain,
+ (ndr_print_function_t) ndr_print_samr_RemoveMemberFromForeignDomain,
+ false,
+ },
+ {
+ "samr_QueryDomainInfo2",
+ sizeof(struct samr_QueryDomainInfo2),
+ (ndr_push_flags_fn_t) ndr_push_samr_QueryDomainInfo2,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_QueryDomainInfo2,
+ (ndr_print_function_t) ndr_print_samr_QueryDomainInfo2,
+ false,
+ },
+ {
+ "samr_QueryUserInfo2",
+ sizeof(struct samr_QueryUserInfo2),
+ (ndr_push_flags_fn_t) ndr_push_samr_QueryUserInfo2,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_QueryUserInfo2,
+ (ndr_print_function_t) ndr_print_samr_QueryUserInfo2,
+ false,
+ },
+ {
+ "samr_QueryDisplayInfo2",
+ sizeof(struct samr_QueryDisplayInfo2),
+ (ndr_push_flags_fn_t) ndr_push_samr_QueryDisplayInfo2,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_QueryDisplayInfo2,
+ (ndr_print_function_t) ndr_print_samr_QueryDisplayInfo2,
+ false,
+ },
+ {
+ "samr_GetDisplayEnumerationIndex2",
+ sizeof(struct samr_GetDisplayEnumerationIndex2),
+ (ndr_push_flags_fn_t) ndr_push_samr_GetDisplayEnumerationIndex2,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_GetDisplayEnumerationIndex2,
+ (ndr_print_function_t) ndr_print_samr_GetDisplayEnumerationIndex2,
+ false,
+ },
+ {
+ "samr_CreateUser2",
+ sizeof(struct samr_CreateUser2),
+ (ndr_push_flags_fn_t) ndr_push_samr_CreateUser2,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_CreateUser2,
+ (ndr_print_function_t) ndr_print_samr_CreateUser2,
+ false,
+ },
+ {
+ "samr_QueryDisplayInfo3",
+ sizeof(struct samr_QueryDisplayInfo3),
+ (ndr_push_flags_fn_t) ndr_push_samr_QueryDisplayInfo3,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_QueryDisplayInfo3,
+ (ndr_print_function_t) ndr_print_samr_QueryDisplayInfo3,
+ false,
+ },
+ {
+ "samr_AddMultipleMembersToAlias",
+ sizeof(struct samr_AddMultipleMembersToAlias),
+ (ndr_push_flags_fn_t) ndr_push_samr_AddMultipleMembersToAlias,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_AddMultipleMembersToAlias,
+ (ndr_print_function_t) ndr_print_samr_AddMultipleMembersToAlias,
+ false,
+ },
+ {
+ "samr_RemoveMultipleMembersFromAlias",
+ sizeof(struct samr_RemoveMultipleMembersFromAlias),
+ (ndr_push_flags_fn_t) ndr_push_samr_RemoveMultipleMembersFromAlias,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_RemoveMultipleMembersFromAlias,
+ (ndr_print_function_t) ndr_print_samr_RemoveMultipleMembersFromAlias,
+ false,
+ },
+ {
+ "samr_OemChangePasswordUser2",
+ sizeof(struct samr_OemChangePasswordUser2),
+ (ndr_push_flags_fn_t) ndr_push_samr_OemChangePasswordUser2,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_OemChangePasswordUser2,
+ (ndr_print_function_t) ndr_print_samr_OemChangePasswordUser2,
+ false,
+ },
+ {
+ "samr_ChangePasswordUser2",
+ sizeof(struct samr_ChangePasswordUser2),
+ (ndr_push_flags_fn_t) ndr_push_samr_ChangePasswordUser2,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_ChangePasswordUser2,
+ (ndr_print_function_t) ndr_print_samr_ChangePasswordUser2,
+ false,
+ },
+ {
+ "samr_GetDomPwInfo",
+ sizeof(struct samr_GetDomPwInfo),
+ (ndr_push_flags_fn_t) ndr_push_samr_GetDomPwInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_GetDomPwInfo,
+ (ndr_print_function_t) ndr_print_samr_GetDomPwInfo,
+ false,
+ },
+ {
+ "samr_Connect2",
+ sizeof(struct samr_Connect2),
+ (ndr_push_flags_fn_t) ndr_push_samr_Connect2,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_Connect2,
+ (ndr_print_function_t) ndr_print_samr_Connect2,
+ false,
+ },
+ {
+ "samr_SetUserInfo2",
+ sizeof(struct samr_SetUserInfo2),
+ (ndr_push_flags_fn_t) ndr_push_samr_SetUserInfo2,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_SetUserInfo2,
+ (ndr_print_function_t) ndr_print_samr_SetUserInfo2,
+ false,
+ },
+ {
+ "samr_SetBootKeyInformation",
+ sizeof(struct samr_SetBootKeyInformation),
+ (ndr_push_flags_fn_t) ndr_push_samr_SetBootKeyInformation,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_SetBootKeyInformation,
+ (ndr_print_function_t) ndr_print_samr_SetBootKeyInformation,
+ false,
+ },
+ {
+ "samr_GetBootKeyInformation",
+ sizeof(struct samr_GetBootKeyInformation),
+ (ndr_push_flags_fn_t) ndr_push_samr_GetBootKeyInformation,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_GetBootKeyInformation,
+ (ndr_print_function_t) ndr_print_samr_GetBootKeyInformation,
+ false,
+ },
+ {
+ "samr_Connect3",
+ sizeof(struct samr_Connect3),
+ (ndr_push_flags_fn_t) ndr_push_samr_Connect3,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_Connect3,
+ (ndr_print_function_t) ndr_print_samr_Connect3,
+ false,
+ },
+ {
+ "samr_Connect4",
+ sizeof(struct samr_Connect4),
+ (ndr_push_flags_fn_t) ndr_push_samr_Connect4,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_Connect4,
+ (ndr_print_function_t) ndr_print_samr_Connect4,
+ false,
+ },
+ {
+ "samr_ChangePasswordUser3",
+ sizeof(struct samr_ChangePasswordUser3),
+ (ndr_push_flags_fn_t) ndr_push_samr_ChangePasswordUser3,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_ChangePasswordUser3,
+ (ndr_print_function_t) ndr_print_samr_ChangePasswordUser3,
+ false,
+ },
+ {
+ "samr_Connect5",
+ sizeof(struct samr_Connect5),
+ (ndr_push_flags_fn_t) ndr_push_samr_Connect5,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_Connect5,
+ (ndr_print_function_t) ndr_print_samr_Connect5,
+ false,
+ },
+ {
+ "samr_RidToSid",
+ sizeof(struct samr_RidToSid),
+ (ndr_push_flags_fn_t) ndr_push_samr_RidToSid,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_RidToSid,
+ (ndr_print_function_t) ndr_print_samr_RidToSid,
+ false,
+ },
+ {
+ "samr_SetDsrmPassword",
+ sizeof(struct samr_SetDsrmPassword),
+ (ndr_push_flags_fn_t) ndr_push_samr_SetDsrmPassword,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_SetDsrmPassword,
+ (ndr_print_function_t) ndr_print_samr_SetDsrmPassword,
+ false,
+ },
+ {
+ "samr_ValidatePassword",
+ sizeof(struct samr_ValidatePassword),
+ (ndr_push_flags_fn_t) ndr_push_samr_ValidatePassword,
+ (ndr_pull_flags_fn_t) ndr_pull_samr_ValidatePassword,
+ (ndr_print_function_t) ndr_print_samr_ValidatePassword,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const samr_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\samr]",
+ "ncacn_ip_tcp:",
+ "ncalrpc:",
+};
+
+static const struct ndr_interface_string_array samr_endpoints = {
+ .count = 3,
+ .names = samr_endpoint_strings
+};
+
+static const char * const samr_authservice_strings[] = {
+ "host",
+};
+
+static const struct ndr_interface_string_array samr_authservices = {
+ .count = 1,
+ .names = samr_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_samr = {
+ .name = "samr",
+ .syntax_id = {
+ {0x12345778,0x1234,0xabcd,{0xef,0x00},{0x01,0x23,0x45,0x67,0x89,0xac}},
+ NDR_SAMR_VERSION
+ },
+ .helpstring = NDR_SAMR_HELPSTRING,
+ .num_calls = 68,
+ .calls = samr_calls,
+ .endpoints = &samr_endpoints,
+ .authservices = &samr_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_samr.h b/source3/librpc/gen_ndr/ndr_samr.h
new file mode 100644
index 0000000000..c21b5455fb
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_samr.h
@@ -0,0 +1,342 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/samr.h"
+
+#ifndef _HEADER_NDR_samr
+#define _HEADER_NDR_samr
+
+#define NDR_SAMR_UUID "12345778-1234-abcd-ef00-0123456789ac"
+#define NDR_SAMR_VERSION 1.0
+#define NDR_SAMR_NAME "samr"
+#define NDR_SAMR_HELPSTRING NULL
+extern const struct ndr_interface_table ndr_table_samr;
+#define NDR_SAMR_CONNECT (0x00)
+
+#define NDR_SAMR_CLOSE (0x01)
+
+#define NDR_SAMR_SETSECURITY (0x02)
+
+#define NDR_SAMR_QUERYSECURITY (0x03)
+
+#define NDR_SAMR_SHUTDOWN (0x04)
+
+#define NDR_SAMR_LOOKUPDOMAIN (0x05)
+
+#define NDR_SAMR_ENUMDOMAINS (0x06)
+
+#define NDR_SAMR_OPENDOMAIN (0x07)
+
+#define NDR_SAMR_QUERYDOMAININFO (0x08)
+
+#define NDR_SAMR_SETDOMAININFO (0x09)
+
+#define NDR_SAMR_CREATEDOMAINGROUP (0x0a)
+
+#define NDR_SAMR_ENUMDOMAINGROUPS (0x0b)
+
+#define NDR_SAMR_CREATEUSER (0x0c)
+
+#define NDR_SAMR_ENUMDOMAINUSERS (0x0d)
+
+#define NDR_SAMR_CREATEDOMALIAS (0x0e)
+
+#define NDR_SAMR_ENUMDOMAINALIASES (0x0f)
+
+#define NDR_SAMR_GETALIASMEMBERSHIP (0x10)
+
+#define NDR_SAMR_LOOKUPNAMES (0x11)
+
+#define NDR_SAMR_LOOKUPRIDS (0x12)
+
+#define NDR_SAMR_OPENGROUP (0x13)
+
+#define NDR_SAMR_QUERYGROUPINFO (0x14)
+
+#define NDR_SAMR_SETGROUPINFO (0x15)
+
+#define NDR_SAMR_ADDGROUPMEMBER (0x16)
+
+#define NDR_SAMR_DELETEDOMAINGROUP (0x17)
+
+#define NDR_SAMR_DELETEGROUPMEMBER (0x18)
+
+#define NDR_SAMR_QUERYGROUPMEMBER (0x19)
+
+#define NDR_SAMR_SETMEMBERATTRIBUTESOFGROUP (0x1a)
+
+#define NDR_SAMR_OPENALIAS (0x1b)
+
+#define NDR_SAMR_QUERYALIASINFO (0x1c)
+
+#define NDR_SAMR_SETALIASINFO (0x1d)
+
+#define NDR_SAMR_DELETEDOMALIAS (0x1e)
+
+#define NDR_SAMR_ADDALIASMEMBER (0x1f)
+
+#define NDR_SAMR_DELETEALIASMEMBER (0x20)
+
+#define NDR_SAMR_GETMEMBERSINALIAS (0x21)
+
+#define NDR_SAMR_OPENUSER (0x22)
+
+#define NDR_SAMR_DELETEUSER (0x23)
+
+#define NDR_SAMR_QUERYUSERINFO (0x24)
+
+#define NDR_SAMR_SETUSERINFO (0x25)
+
+#define NDR_SAMR_CHANGEPASSWORDUSER (0x26)
+
+#define NDR_SAMR_GETGROUPSFORUSER (0x27)
+
+#define NDR_SAMR_QUERYDISPLAYINFO (0x28)
+
+#define NDR_SAMR_GETDISPLAYENUMERATIONINDEX (0x29)
+
+#define NDR_SAMR_TESTPRIVATEFUNCTIONSDOMAIN (0x2a)
+
+#define NDR_SAMR_TESTPRIVATEFUNCTIONSUSER (0x2b)
+
+#define NDR_SAMR_GETUSERPWINFO (0x2c)
+
+#define NDR_SAMR_REMOVEMEMBERFROMFOREIGNDOMAIN (0x2d)
+
+#define NDR_SAMR_QUERYDOMAININFO2 (0x2e)
+
+#define NDR_SAMR_QUERYUSERINFO2 (0x2f)
+
+#define NDR_SAMR_QUERYDISPLAYINFO2 (0x30)
+
+#define NDR_SAMR_GETDISPLAYENUMERATIONINDEX2 (0x31)
+
+#define NDR_SAMR_CREATEUSER2 (0x32)
+
+#define NDR_SAMR_QUERYDISPLAYINFO3 (0x33)
+
+#define NDR_SAMR_ADDMULTIPLEMEMBERSTOALIAS (0x34)
+
+#define NDR_SAMR_REMOVEMULTIPLEMEMBERSFROMALIAS (0x35)
+
+#define NDR_SAMR_OEMCHANGEPASSWORDUSER2 (0x36)
+
+#define NDR_SAMR_CHANGEPASSWORDUSER2 (0x37)
+
+#define NDR_SAMR_GETDOMPWINFO (0x38)
+
+#define NDR_SAMR_CONNECT2 (0x39)
+
+#define NDR_SAMR_SETUSERINFO2 (0x3a)
+
+#define NDR_SAMR_SETBOOTKEYINFORMATION (0x3b)
+
+#define NDR_SAMR_GETBOOTKEYINFORMATION (0x3c)
+
+#define NDR_SAMR_CONNECT3 (0x3d)
+
+#define NDR_SAMR_CONNECT4 (0x3e)
+
+#define NDR_SAMR_CHANGEPASSWORDUSER3 (0x3f)
+
+#define NDR_SAMR_CONNECT5 (0x40)
+
+#define NDR_SAMR_RIDTOSID (0x41)
+
+#define NDR_SAMR_SETDSRMPASSWORD (0x42)
+
+#define NDR_SAMR_VALIDATEPASSWORD (0x43)
+
+#define NDR_SAMR_CALL_COUNT (68)
+enum ndr_err_code ndr_push_samr_AcctFlags(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_samr_AcctFlags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_samr_AcctFlags(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_samr_ConnectAccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_samr_UserAccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_samr_DomainAccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_samr_GroupAccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_samr_AliasAccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_samr_SamEntry(struct ndr_print *ndr, const char *name, const struct samr_SamEntry *r);
+void ndr_print_samr_SamArray(struct ndr_print *ndr, const char *name, const struct samr_SamArray *r);
+void ndr_print_samr_Role(struct ndr_print *ndr, const char *name, enum samr_Role r);
+enum ndr_err_code ndr_push_samr_PasswordProperties(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_samr_PasswordProperties(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_samr_PasswordProperties(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_samr_DomInfo1(struct ndr_print *ndr, const char *name, const struct samr_DomInfo1 *r);
+void ndr_print_samr_DomInfo2(struct ndr_print *ndr, const char *name, const struct samr_DomInfo2 *r);
+void ndr_print_samr_DomInfo3(struct ndr_print *ndr, const char *name, const struct samr_DomInfo3 *r);
+void ndr_print_samr_DomInfo4(struct ndr_print *ndr, const char *name, const struct samr_DomInfo4 *r);
+void ndr_print_samr_DomInfo5(struct ndr_print *ndr, const char *name, const struct samr_DomInfo5 *r);
+void ndr_print_samr_DomInfo6(struct ndr_print *ndr, const char *name, const struct samr_DomInfo6 *r);
+void ndr_print_samr_DomInfo7(struct ndr_print *ndr, const char *name, const struct samr_DomInfo7 *r);
+void ndr_print_samr_DomInfo8(struct ndr_print *ndr, const char *name, const struct samr_DomInfo8 *r);
+void ndr_print_samr_DomInfo9(struct ndr_print *ndr, const char *name, const struct samr_DomInfo9 *r);
+void ndr_print_samr_DomInfo11(struct ndr_print *ndr, const char *name, const struct samr_DomInfo11 *r);
+void ndr_print_samr_DomInfo12(struct ndr_print *ndr, const char *name, const struct samr_DomInfo12 *r);
+void ndr_print_samr_DomInfo13(struct ndr_print *ndr, const char *name, const struct samr_DomInfo13 *r);
+void ndr_print_samr_DomainInfo(struct ndr_print *ndr, const char *name, const union samr_DomainInfo *r);
+void ndr_print_samr_Ids(struct ndr_print *ndr, const char *name, const struct samr_Ids *r);
+enum ndr_err_code ndr_push_samr_GroupAttrs(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_samr_GroupAttrs(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_samr_GroupAttrs(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_samr_GroupInfoAll(struct ndr_print *ndr, const char *name, const struct samr_GroupInfoAll *r);
+void ndr_print_samr_GroupInfoAttributes(struct ndr_print *ndr, const char *name, const struct samr_GroupInfoAttributes *r);
+void ndr_print_samr_GroupInfoEnum(struct ndr_print *ndr, const char *name, enum samr_GroupInfoEnum r);
+void ndr_print_samr_GroupInfo(struct ndr_print *ndr, const char *name, const union samr_GroupInfo *r);
+void ndr_print_samr_RidTypeArray(struct ndr_print *ndr, const char *name, const struct samr_RidTypeArray *r);
+void ndr_print_samr_AliasInfoAll(struct ndr_print *ndr, const char *name, const struct samr_AliasInfoAll *r);
+void ndr_print_samr_AliasInfoEnum(struct ndr_print *ndr, const char *name, enum samr_AliasInfoEnum r);
+void ndr_print_samr_AliasInfo(struct ndr_print *ndr, const char *name, const union samr_AliasInfo *r);
+void ndr_print_samr_UserInfo1(struct ndr_print *ndr, const char *name, const struct samr_UserInfo1 *r);
+void ndr_print_samr_UserInfo2(struct ndr_print *ndr, const char *name, const struct samr_UserInfo2 *r);
+enum ndr_err_code ndr_push_samr_LogonHours(struct ndr_push *ndr, int ndr_flags, const struct samr_LogonHours *r);
+enum ndr_err_code ndr_pull_samr_LogonHours(struct ndr_pull *ndr, int ndr_flags, struct samr_LogonHours *r);
+void ndr_print_samr_LogonHours(struct ndr_print *ndr, const char *name, const struct samr_LogonHours *r);
+void ndr_print_samr_UserInfo3(struct ndr_print *ndr, const char *name, const struct samr_UserInfo3 *r);
+void ndr_print_samr_UserInfo4(struct ndr_print *ndr, const char *name, const struct samr_UserInfo4 *r);
+void ndr_print_samr_UserInfo5(struct ndr_print *ndr, const char *name, const struct samr_UserInfo5 *r);
+void ndr_print_samr_UserInfo6(struct ndr_print *ndr, const char *name, const struct samr_UserInfo6 *r);
+void ndr_print_samr_UserInfo7(struct ndr_print *ndr, const char *name, const struct samr_UserInfo7 *r);
+void ndr_print_samr_UserInfo8(struct ndr_print *ndr, const char *name, const struct samr_UserInfo8 *r);
+void ndr_print_samr_UserInfo9(struct ndr_print *ndr, const char *name, const struct samr_UserInfo9 *r);
+void ndr_print_samr_UserInfo10(struct ndr_print *ndr, const char *name, const struct samr_UserInfo10 *r);
+void ndr_print_samr_UserInfo11(struct ndr_print *ndr, const char *name, const struct samr_UserInfo11 *r);
+void ndr_print_samr_UserInfo12(struct ndr_print *ndr, const char *name, const struct samr_UserInfo12 *r);
+void ndr_print_samr_UserInfo13(struct ndr_print *ndr, const char *name, const struct samr_UserInfo13 *r);
+void ndr_print_samr_UserInfo14(struct ndr_print *ndr, const char *name, const struct samr_UserInfo14 *r);
+void ndr_print_samr_UserInfo16(struct ndr_print *ndr, const char *name, const struct samr_UserInfo16 *r);
+void ndr_print_samr_UserInfo17(struct ndr_print *ndr, const char *name, const struct samr_UserInfo17 *r);
+enum ndr_err_code ndr_push_samr_Password(struct ndr_push *ndr, int ndr_flags, const struct samr_Password *r);
+enum ndr_err_code ndr_pull_samr_Password(struct ndr_pull *ndr, int ndr_flags, struct samr_Password *r);
+void ndr_print_samr_Password(struct ndr_print *ndr, const char *name, const struct samr_Password *r);
+void ndr_print_samr_UserInfo18(struct ndr_print *ndr, const char *name, const struct samr_UserInfo18 *r);
+void ndr_print_samr_UserInfo20(struct ndr_print *ndr, const char *name, const struct samr_UserInfo20 *r);
+void ndr_print_samr_FieldsPresent(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_samr_UserInfo21(struct ndr_print *ndr, const char *name, const struct samr_UserInfo21 *r);
+enum ndr_err_code ndr_push_samr_CryptPassword(struct ndr_push *ndr, int ndr_flags, const struct samr_CryptPassword *r);
+enum ndr_err_code ndr_pull_samr_CryptPassword(struct ndr_pull *ndr, int ndr_flags, struct samr_CryptPassword *r);
+void ndr_print_samr_CryptPassword(struct ndr_print *ndr, const char *name, const struct samr_CryptPassword *r);
+void ndr_print_samr_UserInfo23(struct ndr_print *ndr, const char *name, const struct samr_UserInfo23 *r);
+void ndr_print_samr_UserInfo24(struct ndr_print *ndr, const char *name, const struct samr_UserInfo24 *r);
+void ndr_print_samr_CryptPasswordEx(struct ndr_print *ndr, const char *name, const struct samr_CryptPasswordEx *r);
+void ndr_print_samr_UserInfo25(struct ndr_print *ndr, const char *name, const struct samr_UserInfo25 *r);
+void ndr_print_samr_UserInfo26(struct ndr_print *ndr, const char *name, const struct samr_UserInfo26 *r);
+void ndr_print_samr_UserInfo(struct ndr_print *ndr, const char *name, const union samr_UserInfo *r);
+enum ndr_err_code ndr_push_samr_RidWithAttribute(struct ndr_push *ndr, int ndr_flags, const struct samr_RidWithAttribute *r);
+enum ndr_err_code ndr_pull_samr_RidWithAttribute(struct ndr_pull *ndr, int ndr_flags, struct samr_RidWithAttribute *r);
+void ndr_print_samr_RidWithAttribute(struct ndr_print *ndr, const char *name, const struct samr_RidWithAttribute *r);
+enum ndr_err_code ndr_push_samr_RidWithAttributeArray(struct ndr_push *ndr, int ndr_flags, const struct samr_RidWithAttributeArray *r);
+enum ndr_err_code ndr_pull_samr_RidWithAttributeArray(struct ndr_pull *ndr, int ndr_flags, struct samr_RidWithAttributeArray *r);
+void ndr_print_samr_RidWithAttributeArray(struct ndr_print *ndr, const char *name, const struct samr_RidWithAttributeArray *r);
+void ndr_print_samr_DispEntryGeneral(struct ndr_print *ndr, const char *name, const struct samr_DispEntryGeneral *r);
+void ndr_print_samr_DispInfoGeneral(struct ndr_print *ndr, const char *name, const struct samr_DispInfoGeneral *r);
+void ndr_print_samr_DispEntryFull(struct ndr_print *ndr, const char *name, const struct samr_DispEntryFull *r);
+void ndr_print_samr_DispInfoFull(struct ndr_print *ndr, const char *name, const struct samr_DispInfoFull *r);
+void ndr_print_samr_DispEntryFullGroup(struct ndr_print *ndr, const char *name, const struct samr_DispEntryFullGroup *r);
+void ndr_print_samr_DispInfoFullGroups(struct ndr_print *ndr, const char *name, const struct samr_DispInfoFullGroups *r);
+void ndr_print_samr_DispEntryAscii(struct ndr_print *ndr, const char *name, const struct samr_DispEntryAscii *r);
+void ndr_print_samr_DispInfoAscii(struct ndr_print *ndr, const char *name, const struct samr_DispInfoAscii *r);
+void ndr_print_samr_DispInfo(struct ndr_print *ndr, const char *name, const union samr_DispInfo *r);
+void ndr_print_samr_PwInfo(struct ndr_print *ndr, const char *name, const struct samr_PwInfo *r);
+void ndr_print_samr_ConnectVersion(struct ndr_print *ndr, const char *name, enum samr_ConnectVersion r);
+void ndr_print_samr_ChangeReject(struct ndr_print *ndr, const char *name, const struct samr_ChangeReject *r);
+void ndr_print_samr_ConnectInfo1(struct ndr_print *ndr, const char *name, const struct samr_ConnectInfo1 *r);
+void ndr_print_samr_ConnectInfo(struct ndr_print *ndr, const char *name, const union samr_ConnectInfo *r);
+void ndr_print_samr_ValidateFieldsPresent(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_samr_ValidatePasswordLevel(struct ndr_print *ndr, const char *name, enum samr_ValidatePasswordLevel r);
+void ndr_print_samr_ValidationStatus(struct ndr_print *ndr, const char *name, enum samr_ValidationStatus r);
+void ndr_print_samr_ValidationBlob(struct ndr_print *ndr, const char *name, const struct samr_ValidationBlob *r);
+void ndr_print_samr_ValidatePasswordInfo(struct ndr_print *ndr, const char *name, const struct samr_ValidatePasswordInfo *r);
+void ndr_print_samr_ValidatePasswordRepCtr(struct ndr_print *ndr, const char *name, const struct samr_ValidatePasswordRepCtr *r);
+void ndr_print_samr_ValidatePasswordRep(struct ndr_print *ndr, const char *name, const union samr_ValidatePasswordRep *r);
+void ndr_print_samr_ValidatePasswordReq3(struct ndr_print *ndr, const char *name, const struct samr_ValidatePasswordReq3 *r);
+void ndr_print_samr_ValidatePasswordReq2(struct ndr_print *ndr, const char *name, const struct samr_ValidatePasswordReq2 *r);
+void ndr_print_samr_ValidatePasswordReq1(struct ndr_print *ndr, const char *name, const struct samr_ValidatePasswordReq1 *r);
+void ndr_print_samr_ValidatePasswordReq(struct ndr_print *ndr, const char *name, const union samr_ValidatePasswordReq *r);
+void ndr_print_samr_Connect(struct ndr_print *ndr, const char *name, int flags, const struct samr_Connect *r);
+enum ndr_err_code ndr_push_samr_Close(struct ndr_push *ndr, int flags, const struct samr_Close *r);
+enum ndr_err_code ndr_pull_samr_Close(struct ndr_pull *ndr, int flags, struct samr_Close *r);
+void ndr_print_samr_Close(struct ndr_print *ndr, const char *name, int flags, const struct samr_Close *r);
+void ndr_print_samr_SetSecurity(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetSecurity *r);
+void ndr_print_samr_QuerySecurity(struct ndr_print *ndr, const char *name, int flags, const struct samr_QuerySecurity *r);
+void ndr_print_samr_Shutdown(struct ndr_print *ndr, const char *name, int flags, const struct samr_Shutdown *r);
+void ndr_print_samr_LookupDomain(struct ndr_print *ndr, const char *name, int flags, const struct samr_LookupDomain *r);
+void ndr_print_samr_EnumDomains(struct ndr_print *ndr, const char *name, int flags, const struct samr_EnumDomains *r);
+enum ndr_err_code ndr_push_samr_OpenDomain(struct ndr_push *ndr, int flags, const struct samr_OpenDomain *r);
+enum ndr_err_code ndr_pull_samr_OpenDomain(struct ndr_pull *ndr, int flags, struct samr_OpenDomain *r);
+void ndr_print_samr_OpenDomain(struct ndr_print *ndr, const char *name, int flags, const struct samr_OpenDomain *r);
+void ndr_print_samr_QueryDomainInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryDomainInfo *r);
+void ndr_print_samr_SetDomainInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetDomainInfo *r);
+void ndr_print_samr_CreateDomainGroup(struct ndr_print *ndr, const char *name, int flags, const struct samr_CreateDomainGroup *r);
+void ndr_print_samr_EnumDomainGroups(struct ndr_print *ndr, const char *name, int flags, const struct samr_EnumDomainGroups *r);
+void ndr_print_samr_CreateUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_CreateUser *r);
+void ndr_print_samr_EnumDomainUsers(struct ndr_print *ndr, const char *name, int flags, const struct samr_EnumDomainUsers *r);
+void ndr_print_samr_CreateDomAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_CreateDomAlias *r);
+void ndr_print_samr_EnumDomainAliases(struct ndr_print *ndr, const char *name, int flags, const struct samr_EnumDomainAliases *r);
+void ndr_print_samr_GetAliasMembership(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetAliasMembership *r);
+enum ndr_err_code ndr_push_samr_LookupNames(struct ndr_push *ndr, int flags, const struct samr_LookupNames *r);
+enum ndr_err_code ndr_pull_samr_LookupNames(struct ndr_pull *ndr, int flags, struct samr_LookupNames *r);
+void ndr_print_samr_LookupNames(struct ndr_print *ndr, const char *name, int flags, const struct samr_LookupNames *r);
+void ndr_print_samr_LookupRids(struct ndr_print *ndr, const char *name, int flags, const struct samr_LookupRids *r);
+void ndr_print_samr_OpenGroup(struct ndr_print *ndr, const char *name, int flags, const struct samr_OpenGroup *r);
+void ndr_print_samr_QueryGroupInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryGroupInfo *r);
+void ndr_print_samr_SetGroupInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetGroupInfo *r);
+void ndr_print_samr_AddGroupMember(struct ndr_print *ndr, const char *name, int flags, const struct samr_AddGroupMember *r);
+void ndr_print_samr_DeleteDomainGroup(struct ndr_print *ndr, const char *name, int flags, const struct samr_DeleteDomainGroup *r);
+void ndr_print_samr_DeleteGroupMember(struct ndr_print *ndr, const char *name, int flags, const struct samr_DeleteGroupMember *r);
+void ndr_print_samr_QueryGroupMember(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryGroupMember *r);
+void ndr_print_samr_SetMemberAttributesOfGroup(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetMemberAttributesOfGroup *r);
+void ndr_print_samr_OpenAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_OpenAlias *r);
+void ndr_print_samr_QueryAliasInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryAliasInfo *r);
+void ndr_print_samr_SetAliasInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetAliasInfo *r);
+void ndr_print_samr_DeleteDomAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_DeleteDomAlias *r);
+void ndr_print_samr_AddAliasMember(struct ndr_print *ndr, const char *name, int flags, const struct samr_AddAliasMember *r);
+void ndr_print_samr_DeleteAliasMember(struct ndr_print *ndr, const char *name, int flags, const struct samr_DeleteAliasMember *r);
+void ndr_print_samr_GetMembersInAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetMembersInAlias *r);
+enum ndr_err_code ndr_push_samr_OpenUser(struct ndr_push *ndr, int flags, const struct samr_OpenUser *r);
+enum ndr_err_code ndr_pull_samr_OpenUser(struct ndr_pull *ndr, int flags, struct samr_OpenUser *r);
+void ndr_print_samr_OpenUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_OpenUser *r);
+void ndr_print_samr_DeleteUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_DeleteUser *r);
+enum ndr_err_code ndr_push_samr_QueryUserInfo(struct ndr_push *ndr, int flags, const struct samr_QueryUserInfo *r);
+enum ndr_err_code ndr_pull_samr_QueryUserInfo(struct ndr_pull *ndr, int flags, struct samr_QueryUserInfo *r);
+void ndr_print_samr_QueryUserInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryUserInfo *r);
+enum ndr_err_code ndr_push_samr_SetUserInfo(struct ndr_push *ndr, int flags, const struct samr_SetUserInfo *r);
+enum ndr_err_code ndr_pull_samr_SetUserInfo(struct ndr_pull *ndr, int flags, struct samr_SetUserInfo *r);
+void ndr_print_samr_SetUserInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetUserInfo *r);
+void ndr_print_samr_ChangePasswordUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_ChangePasswordUser *r);
+void ndr_print_samr_GetGroupsForUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetGroupsForUser *r);
+void ndr_print_samr_QueryDisplayInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryDisplayInfo *r);
+void ndr_print_samr_GetDisplayEnumerationIndex(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetDisplayEnumerationIndex *r);
+void ndr_print_samr_TestPrivateFunctionsDomain(struct ndr_print *ndr, const char *name, int flags, const struct samr_TestPrivateFunctionsDomain *r);
+void ndr_print_samr_TestPrivateFunctionsUser(struct ndr_print *ndr, const char *name, int flags, const struct samr_TestPrivateFunctionsUser *r);
+enum ndr_err_code ndr_push_samr_GetUserPwInfo(struct ndr_push *ndr, int flags, const struct samr_GetUserPwInfo *r);
+enum ndr_err_code ndr_pull_samr_GetUserPwInfo(struct ndr_pull *ndr, int flags, struct samr_GetUserPwInfo *r);
+void ndr_print_samr_GetUserPwInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetUserPwInfo *r);
+void ndr_print_samr_RemoveMemberFromForeignDomain(struct ndr_print *ndr, const char *name, int flags, const struct samr_RemoveMemberFromForeignDomain *r);
+void ndr_print_samr_QueryDomainInfo2(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryDomainInfo2 *r);
+void ndr_print_samr_QueryUserInfo2(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryUserInfo2 *r);
+void ndr_print_samr_QueryDisplayInfo2(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryDisplayInfo2 *r);
+void ndr_print_samr_GetDisplayEnumerationIndex2(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetDisplayEnumerationIndex2 *r);
+void ndr_print_samr_CreateUser2(struct ndr_print *ndr, const char *name, int flags, const struct samr_CreateUser2 *r);
+void ndr_print_samr_QueryDisplayInfo3(struct ndr_print *ndr, const char *name, int flags, const struct samr_QueryDisplayInfo3 *r);
+void ndr_print_samr_AddMultipleMembersToAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_AddMultipleMembersToAlias *r);
+void ndr_print_samr_RemoveMultipleMembersFromAlias(struct ndr_print *ndr, const char *name, int flags, const struct samr_RemoveMultipleMembersFromAlias *r);
+void ndr_print_samr_OemChangePasswordUser2(struct ndr_print *ndr, const char *name, int flags, const struct samr_OemChangePasswordUser2 *r);
+void ndr_print_samr_ChangePasswordUser2(struct ndr_print *ndr, const char *name, int flags, const struct samr_ChangePasswordUser2 *r);
+void ndr_print_samr_GetDomPwInfo(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetDomPwInfo *r);
+void ndr_print_samr_Connect2(struct ndr_print *ndr, const char *name, int flags, const struct samr_Connect2 *r);
+enum ndr_err_code ndr_push_samr_SetUserInfo2(struct ndr_push *ndr, int flags, const struct samr_SetUserInfo2 *r);
+enum ndr_err_code ndr_pull_samr_SetUserInfo2(struct ndr_pull *ndr, int flags, struct samr_SetUserInfo2 *r);
+void ndr_print_samr_SetUserInfo2(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetUserInfo2 *r);
+void ndr_print_samr_SetBootKeyInformation(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetBootKeyInformation *r);
+void ndr_print_samr_GetBootKeyInformation(struct ndr_print *ndr, const char *name, int flags, const struct samr_GetBootKeyInformation *r);
+void ndr_print_samr_Connect3(struct ndr_print *ndr, const char *name, int flags, const struct samr_Connect3 *r);
+void ndr_print_samr_Connect4(struct ndr_print *ndr, const char *name, int flags, const struct samr_Connect4 *r);
+void ndr_print_samr_ChangePasswordUser3(struct ndr_print *ndr, const char *name, int flags, const struct samr_ChangePasswordUser3 *r);
+enum ndr_err_code ndr_push_samr_Connect5(struct ndr_push *ndr, int flags, const struct samr_Connect5 *r);
+enum ndr_err_code ndr_pull_samr_Connect5(struct ndr_pull *ndr, int flags, struct samr_Connect5 *r);
+void ndr_print_samr_Connect5(struct ndr_print *ndr, const char *name, int flags, const struct samr_Connect5 *r);
+void ndr_print_samr_RidToSid(struct ndr_print *ndr, const char *name, int flags, const struct samr_RidToSid *r);
+void ndr_print_samr_SetDsrmPassword(struct ndr_print *ndr, const char *name, int flags, const struct samr_SetDsrmPassword *r);
+void ndr_print_samr_ValidatePassword(struct ndr_print *ndr, const char *name, int flags, const struct samr_ValidatePassword *r);
+#endif /* _HEADER_NDR_samr */
diff --git a/source3/librpc/gen_ndr/ndr_security.c b/source3/librpc/gen_ndr/ndr_security.c
new file mode 100644
index 0000000000..d54fdb2395
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_security.c
@@ -0,0 +1,1026 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_security.h"
+
+#include "librpc/gen_ndr/ndr_misc.h"
+static enum ndr_err_code ndr_push_security_ace_flags(struct ndr_push *ndr, int ndr_flags, uint8_t r)
+{
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_security_ace_flags(struct ndr_pull *ndr, int ndr_flags, uint8_t *r)
+{
+ uint8_t v;
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_security_ace_flags(struct ndr_print *ndr, const char *name, uint8_t r)
+{
+ ndr_print_uint8(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint8_t), "SEC_ACE_FLAG_OBJECT_INHERIT", SEC_ACE_FLAG_OBJECT_INHERIT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint8_t), "SEC_ACE_FLAG_CONTAINER_INHERIT", SEC_ACE_FLAG_CONTAINER_INHERIT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint8_t), "SEC_ACE_FLAG_NO_PROPAGATE_INHERIT", SEC_ACE_FLAG_NO_PROPAGATE_INHERIT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint8_t), "SEC_ACE_FLAG_INHERIT_ONLY", SEC_ACE_FLAG_INHERIT_ONLY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint8_t), "SEC_ACE_FLAG_INHERITED_ACE", SEC_ACE_FLAG_INHERITED_ACE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint8_t), "SEC_ACE_FLAG_VALID_INHERIT", SEC_ACE_FLAG_VALID_INHERIT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint8_t), "SEC_ACE_FLAG_SUCCESSFUL_ACCESS", SEC_ACE_FLAG_SUCCESSFUL_ACCESS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint8_t), "SEC_ACE_FLAG_FAILED_ACCESS", SEC_ACE_FLAG_FAILED_ACCESS, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_security_ace_type(struct ndr_push *ndr, int ndr_flags, enum security_ace_type r)
+{
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_security_ace_type(struct ndr_pull *ndr, int ndr_flags, enum security_ace_type *r)
+{
+ uint8_t v;
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_security_ace_type(struct ndr_print *ndr, const char *name, enum security_ace_type r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED: val = "SEC_ACE_TYPE_ACCESS_ALLOWED"; break;
+ case SEC_ACE_TYPE_ACCESS_DENIED: val = "SEC_ACE_TYPE_ACCESS_DENIED"; break;
+ case SEC_ACE_TYPE_SYSTEM_AUDIT: val = "SEC_ACE_TYPE_SYSTEM_AUDIT"; break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM: val = "SEC_ACE_TYPE_SYSTEM_ALARM"; break;
+ case SEC_ACE_TYPE_ALLOWED_COMPOUND: val = "SEC_ACE_TYPE_ALLOWED_COMPOUND"; break;
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT: val = "SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT"; break;
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT: val = "SEC_ACE_TYPE_ACCESS_DENIED_OBJECT"; break;
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT: val = "SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT"; break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT: val = "SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_security_ace_object_flags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_security_ace_object_flags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_security_ace_object_flags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SEC_ACE_OBJECT_TYPE_PRESENT", SEC_ACE_OBJECT_TYPE_PRESENT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT", SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_security_ace_object_type(struct ndr_push *ndr, int ndr_flags, const union security_ace_object_type *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case SEC_ACE_OBJECT_TYPE_PRESENT: {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->type));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case SEC_ACE_OBJECT_TYPE_PRESENT:
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_security_ace_object_type(struct ndr_pull *ndr, int ndr_flags, union security_ace_object_type *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case SEC_ACE_OBJECT_TYPE_PRESENT: {
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->type));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case SEC_ACE_OBJECT_TYPE_PRESENT:
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_security_ace_object_type(struct ndr_print *ndr, const char *name, const union security_ace_object_type *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "security_ace_object_type");
+ switch (level) {
+ case SEC_ACE_OBJECT_TYPE_PRESENT:
+ ndr_print_GUID(ndr, "type", &r->type);
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_security_ace_object_inherited_type(struct ndr_push *ndr, int ndr_flags, const union security_ace_object_inherited_type *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT: {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->inherited_type));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT:
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_security_ace_object_inherited_type(struct ndr_pull *ndr, int ndr_flags, union security_ace_object_inherited_type *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT: {
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->inherited_type));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT:
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_security_ace_object_inherited_type(struct ndr_print *ndr, const char *name, const union security_ace_object_inherited_type *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "security_ace_object_inherited_type");
+ switch (level) {
+ case SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT:
+ ndr_print_GUID(ndr, "inherited_type", &r->inherited_type);
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_security_ace_object(struct ndr_push *ndr, int ndr_flags, const struct security_ace_object *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_security_ace_object_flags(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->type, r->flags & SEC_ACE_OBJECT_TYPE_PRESENT));
+ NDR_CHECK(ndr_push_security_ace_object_type(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->inherited_type, r->flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT));
+ NDR_CHECK(ndr_push_security_ace_object_inherited_type(ndr, NDR_SCALARS, &r->inherited_type));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_security_ace_object_type(ndr, NDR_BUFFERS, &r->type));
+ NDR_CHECK(ndr_push_security_ace_object_inherited_type(ndr, NDR_BUFFERS, &r->inherited_type));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_security_ace_object(struct ndr_pull *ndr, int ndr_flags, struct security_ace_object *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_security_ace_object_flags(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->type, r->flags & SEC_ACE_OBJECT_TYPE_PRESENT));
+ NDR_CHECK(ndr_pull_security_ace_object_type(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->inherited_type, r->flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT));
+ NDR_CHECK(ndr_pull_security_ace_object_inherited_type(ndr, NDR_SCALARS, &r->inherited_type));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_security_ace_object_type(ndr, NDR_BUFFERS, &r->type));
+ NDR_CHECK(ndr_pull_security_ace_object_inherited_type(ndr, NDR_BUFFERS, &r->inherited_type));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_security_ace_object(struct ndr_print *ndr, const char *name, const struct security_ace_object *r)
+{
+ ndr_print_struct(ndr, name, "security_ace_object");
+ ndr->depth++;
+ ndr_print_security_ace_object_flags(ndr, "flags", r->flags);
+ ndr_print_set_switch_value(ndr, &r->type, r->flags & SEC_ACE_OBJECT_TYPE_PRESENT);
+ ndr_print_security_ace_object_type(ndr, "type", &r->type);
+ ndr_print_set_switch_value(ndr, &r->inherited_type, r->flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT);
+ ndr_print_security_ace_object_inherited_type(ndr, "inherited_type", &r->inherited_type);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_security_ace_object_ctr(struct ndr_push *ndr, int ndr_flags, const union security_ace_object_ctr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT: {
+ NDR_CHECK(ndr_push_security_ace_object(ndr, NDR_SCALARS, &r->object));
+ break; }
+
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT: {
+ NDR_CHECK(ndr_push_security_ace_object(ndr, NDR_SCALARS, &r->object));
+ break; }
+
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT: {
+ NDR_CHECK(ndr_push_security_ace_object(ndr, NDR_SCALARS, &r->object));
+ break; }
+
+ case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT: {
+ NDR_CHECK(ndr_push_security_ace_object(ndr, NDR_SCALARS, &r->object));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
+ NDR_CHECK(ndr_push_security_ace_object(ndr, NDR_BUFFERS, &r->object));
+ break;
+
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+ NDR_CHECK(ndr_push_security_ace_object(ndr, NDR_BUFFERS, &r->object));
+ break;
+
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT:
+ NDR_CHECK(ndr_push_security_ace_object(ndr, NDR_BUFFERS, &r->object));
+ break;
+
+ case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT:
+ NDR_CHECK(ndr_push_security_ace_object(ndr, NDR_BUFFERS, &r->object));
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_security_ace_object_ctr(struct ndr_pull *ndr, int ndr_flags, union security_ace_object_ctr *r)
+{
+ int level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ switch (level) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT: {
+ NDR_CHECK(ndr_pull_security_ace_object(ndr, NDR_SCALARS, &r->object));
+ break; }
+
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT: {
+ NDR_CHECK(ndr_pull_security_ace_object(ndr, NDR_SCALARS, &r->object));
+ break; }
+
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT: {
+ NDR_CHECK(ndr_pull_security_ace_object(ndr, NDR_SCALARS, &r->object));
+ break; }
+
+ case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT: {
+ NDR_CHECK(ndr_pull_security_ace_object(ndr, NDR_SCALARS, &r->object));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
+ NDR_CHECK(ndr_pull_security_ace_object(ndr, NDR_BUFFERS, &r->object));
+ break;
+
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+ NDR_CHECK(ndr_pull_security_ace_object(ndr, NDR_BUFFERS, &r->object));
+ break;
+
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT:
+ NDR_CHECK(ndr_pull_security_ace_object(ndr, NDR_BUFFERS, &r->object));
+ break;
+
+ case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT:
+ NDR_CHECK(ndr_pull_security_ace_object(ndr, NDR_BUFFERS, &r->object));
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_security_ace_object_ctr(struct ndr_print *ndr, const char *name, const union security_ace_object_ctr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "security_ace_object_ctr");
+ switch (level) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
+ ndr_print_security_ace_object(ndr, "object", &r->object);
+ break;
+
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+ ndr_print_security_ace_object(ndr, "object", &r->object);
+ break;
+
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT:
+ ndr_print_security_ace_object(ndr, "object", &r->object);
+ break;
+
+ case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT:
+ ndr_print_security_ace_object(ndr, "object", &r->object);
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_security_ace(struct ndr_push *ndr, int ndr_flags, const struct security_ace *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_security_ace_type(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_security_ace_flags(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, ndr_size_security_ace(r, ndr->flags)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->access_mask));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->object, r->type));
+ NDR_CHECK(ndr_push_security_ace_object_ctr(ndr, NDR_SCALARS, &r->object));
+ NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS, &r->trustee));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_security_ace_object_ctr(ndr, NDR_BUFFERS, &r->object));
+ NDR_CHECK(ndr_push_dom_sid(ndr, NDR_BUFFERS, &r->trustee));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_security_ace(struct ndr_pull *ndr, int ndr_flags, struct security_ace *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_security_ace_type(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_security_ace_flags(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->access_mask));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->object, r->type));
+ NDR_CHECK(ndr_pull_security_ace_object_ctr(ndr, NDR_SCALARS, &r->object));
+ NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, &r->trustee));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_security_ace_object_ctr(ndr, NDR_BUFFERS, &r->object));
+ NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_BUFFERS, &r->trustee));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_security_ace(struct ndr_print *ndr, const char *name, const struct security_ace *r)
+{
+ ndr_print_struct(ndr, name, "security_ace");
+ ndr->depth++;
+ ndr_print_security_ace_type(ndr, "type", r->type);
+ ndr_print_security_ace_flags(ndr, "flags", r->flags);
+ ndr_print_uint16(ndr, "size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_security_ace(r, ndr->flags):r->size);
+ ndr_print_uint32(ndr, "access_mask", r->access_mask);
+ ndr_print_set_switch_value(ndr, &r->object, r->type);
+ ndr_print_security_ace_object_ctr(ndr, "object", &r->object);
+ ndr_print_dom_sid(ndr, "trustee", &r->trustee);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_security_acl_revision(struct ndr_push *ndr, int ndr_flags, enum security_acl_revision r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_security_acl_revision(struct ndr_pull *ndr, int ndr_flags, enum security_acl_revision *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_security_acl_revision(struct ndr_print *ndr, const char *name, enum security_acl_revision r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case SECURITY_ACL_REVISION_NT4: val = "SECURITY_ACL_REVISION_NT4"; break;
+ case SECURITY_ACL_REVISION_ADS: val = "SECURITY_ACL_REVISION_ADS"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_security_acl(struct ndr_push *ndr, int ndr_flags, const struct security_acl *r)
+{
+ uint32_t cntr_aces_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_security_acl_revision(ndr, NDR_SCALARS, r->revision));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, ndr_size_security_acl(r, ndr->flags)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_aces));
+ for (cntr_aces_0 = 0; cntr_aces_0 < r->num_aces; cntr_aces_0++) {
+ NDR_CHECK(ndr_push_security_ace(ndr, NDR_SCALARS, &r->aces[cntr_aces_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ for (cntr_aces_0 = 0; cntr_aces_0 < r->num_aces; cntr_aces_0++) {
+ NDR_CHECK(ndr_push_security_ace(ndr, NDR_BUFFERS, &r->aces[cntr_aces_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_security_acl(struct ndr_pull *ndr, int ndr_flags, struct security_acl *r)
+{
+ uint32_t cntr_aces_0;
+ TALLOC_CTX *_mem_save_aces_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_security_acl_revision(ndr, NDR_SCALARS, &r->revision));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_aces));
+ if (r->num_aces < 0 || r->num_aces > 1000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_PULL_ALLOC_N(ndr, r->aces, r->num_aces);
+ _mem_save_aces_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->aces, 0);
+ for (cntr_aces_0 = 0; cntr_aces_0 < r->num_aces; cntr_aces_0++) {
+ NDR_CHECK(ndr_pull_security_ace(ndr, NDR_SCALARS, &r->aces[cntr_aces_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_aces_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_aces_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->aces, 0);
+ for (cntr_aces_0 = 0; cntr_aces_0 < r->num_aces; cntr_aces_0++) {
+ NDR_CHECK(ndr_pull_security_ace(ndr, NDR_BUFFERS, &r->aces[cntr_aces_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_aces_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_security_acl(struct ndr_print *ndr, const char *name, const struct security_acl *r)
+{
+ uint32_t cntr_aces_0;
+ ndr_print_struct(ndr, name, "security_acl");
+ ndr->depth++;
+ ndr_print_security_acl_revision(ndr, "revision", r->revision);
+ ndr_print_uint16(ndr, "size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_security_acl(r, ndr->flags):r->size);
+ ndr_print_uint32(ndr, "num_aces", r->num_aces);
+ ndr->print(ndr, "%s: ARRAY(%d)", "aces", (int)r->num_aces);
+ ndr->depth++;
+ for (cntr_aces_0=0;cntr_aces_0<r->num_aces;cntr_aces_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_aces_0) != -1) {
+ ndr_print_security_ace(ndr, "aces", &r->aces[cntr_aces_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_security_descriptor_revision(struct ndr_push *ndr, int ndr_flags, enum security_descriptor_revision r)
+{
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_security_descriptor_revision(struct ndr_pull *ndr, int ndr_flags, enum security_descriptor_revision *r)
+{
+ uint8_t v;
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_security_descriptor_revision(struct ndr_print *ndr, const char *name, enum security_descriptor_revision r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case SECURITY_DESCRIPTOR_REVISION_1: val = "SECURITY_DESCRIPTOR_REVISION_1"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_security_descriptor_type(struct ndr_push *ndr, int ndr_flags, uint16_t r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_security_descriptor_type(struct ndr_pull *ndr, int ndr_flags, uint16_t *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_security_descriptor_type(struct ndr_print *ndr, const char *name, uint16_t r)
+{
+ ndr_print_uint16(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "SEC_DESC_OWNER_DEFAULTED", SEC_DESC_OWNER_DEFAULTED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "SEC_DESC_GROUP_DEFAULTED", SEC_DESC_GROUP_DEFAULTED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "SEC_DESC_DACL_PRESENT", SEC_DESC_DACL_PRESENT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "SEC_DESC_DACL_DEFAULTED", SEC_DESC_DACL_DEFAULTED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "SEC_DESC_SACL_PRESENT", SEC_DESC_SACL_PRESENT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "SEC_DESC_SACL_DEFAULTED", SEC_DESC_SACL_DEFAULTED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "SEC_DESC_DACL_TRUSTED", SEC_DESC_DACL_TRUSTED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "SEC_DESC_SERVER_SECURITY", SEC_DESC_SERVER_SECURITY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "SEC_DESC_DACL_AUTO_INHERIT_REQ", SEC_DESC_DACL_AUTO_INHERIT_REQ, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "SEC_DESC_SACL_AUTO_INHERIT_REQ", SEC_DESC_SACL_AUTO_INHERIT_REQ, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "SEC_DESC_DACL_AUTO_INHERITED", SEC_DESC_DACL_AUTO_INHERITED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "SEC_DESC_SACL_AUTO_INHERITED", SEC_DESC_SACL_AUTO_INHERITED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "SEC_DESC_DACL_PROTECTED", SEC_DESC_DACL_PROTECTED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "SEC_DESC_SACL_PROTECTED", SEC_DESC_SACL_PROTECTED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "SEC_DESC_RM_CONTROL_VALID", SEC_DESC_RM_CONTROL_VALID, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint16_t), "SEC_DESC_SELF_RELATIVE", SEC_DESC_SELF_RELATIVE, r);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_security_descriptor(struct ndr_push *ndr, int ndr_flags, const struct security_descriptor *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_security_descriptor_revision(ndr, NDR_SCALARS, r->revision));
+ NDR_CHECK(ndr_push_security_descriptor_type(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->owner_sid));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->group_sid));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->sacl));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->dacl));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->owner_sid) {
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, r->owner_sid));
+ NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS|NDR_BUFFERS, r->owner_sid));
+ }
+ if (r->group_sid) {
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, r->group_sid));
+ NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS|NDR_BUFFERS, r->group_sid));
+ }
+ if (r->sacl) {
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, r->sacl));
+ NDR_CHECK(ndr_push_security_acl(ndr, NDR_SCALARS|NDR_BUFFERS, r->sacl));
+ }
+ if (r->dacl) {
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, r->dacl));
+ NDR_CHECK(ndr_push_security_acl(ndr, NDR_SCALARS|NDR_BUFFERS, r->dacl));
+ }
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_security_descriptor(struct ndr_pull *ndr, int ndr_flags, struct security_descriptor *r)
+{
+ uint32_t _ptr_owner_sid;
+ TALLOC_CTX *_mem_save_owner_sid_0;
+ uint32_t _ptr_group_sid;
+ TALLOC_CTX *_mem_save_group_sid_0;
+ uint32_t _ptr_sacl;
+ TALLOC_CTX *_mem_save_sacl_0;
+ uint32_t _ptr_dacl;
+ TALLOC_CTX *_mem_save_dacl_0;
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_security_descriptor_revision(ndr, NDR_SCALARS, &r->revision));
+ NDR_CHECK(ndr_pull_security_descriptor_type(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_owner_sid));
+ if (_ptr_owner_sid) {
+ NDR_PULL_ALLOC(ndr, r->owner_sid);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->owner_sid, _ptr_owner_sid));
+ } else {
+ r->owner_sid = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_group_sid));
+ if (_ptr_group_sid) {
+ NDR_PULL_ALLOC(ndr, r->group_sid);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->group_sid, _ptr_group_sid));
+ } else {
+ r->group_sid = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sacl));
+ if (_ptr_sacl) {
+ NDR_PULL_ALLOC(ndr, r->sacl);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->sacl, _ptr_sacl));
+ } else {
+ r->sacl = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dacl));
+ if (_ptr_dacl) {
+ NDR_PULL_ALLOC(ndr, r->dacl);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->dacl, _ptr_dacl));
+ } else {
+ r->dacl = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->owner_sid) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->owner_sid));
+ _mem_save_owner_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->owner_sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS|NDR_BUFFERS, r->owner_sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_owner_sid_0, 0);
+ ndr->offset = _relative_save_offset;
+ }
+ if (r->group_sid) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->group_sid));
+ _mem_save_group_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->group_sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS|NDR_BUFFERS, r->group_sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_sid_0, 0);
+ ndr->offset = _relative_save_offset;
+ }
+ if (r->sacl) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->sacl));
+ _mem_save_sacl_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sacl, 0);
+ NDR_CHECK(ndr_pull_security_acl(ndr, NDR_SCALARS|NDR_BUFFERS, r->sacl));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sacl_0, 0);
+ ndr->offset = _relative_save_offset;
+ }
+ if (r->dacl) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->dacl));
+ _mem_save_dacl_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->dacl, 0);
+ NDR_CHECK(ndr_pull_security_acl(ndr, NDR_SCALARS|NDR_BUFFERS, r->dacl));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dacl_0, 0);
+ ndr->offset = _relative_save_offset;
+ }
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_security_descriptor(struct ndr_print *ndr, const char *name, const struct security_descriptor *r)
+{
+ ndr_print_struct(ndr, name, "security_descriptor");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
+ ndr->depth++;
+ ndr_print_security_descriptor_revision(ndr, "revision", r->revision);
+ ndr_print_security_descriptor_type(ndr, "type", r->type);
+ ndr_print_ptr(ndr, "owner_sid", r->owner_sid);
+ ndr->depth++;
+ if (r->owner_sid) {
+ ndr_print_dom_sid(ndr, "owner_sid", r->owner_sid);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "group_sid", r->group_sid);
+ ndr->depth++;
+ if (r->group_sid) {
+ ndr_print_dom_sid(ndr, "group_sid", r->group_sid);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sacl", r->sacl);
+ ndr->depth++;
+ if (r->sacl) {
+ ndr_print_security_acl(ndr, "sacl", r->sacl);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "dacl", r->dacl);
+ ndr->depth++;
+ if (r->dacl) {
+ ndr_print_security_acl(ndr, "dacl", r->dacl);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_sec_desc_buf(struct ndr_push *ndr, int ndr_flags, const struct sec_desc_buf *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_security_descriptor(r->sd, ndr->flags)));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sd));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sd) {
+ {
+ struct ndr_push *_ndr_sd;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_sd, 4, -1));
+ NDR_CHECK(ndr_push_security_descriptor(_ndr_sd, NDR_SCALARS|NDR_BUFFERS, r->sd));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_sd, 4, -1));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_sec_desc_buf(struct ndr_pull *ndr, int ndr_flags, struct sec_desc_buf *r)
+{
+ uint32_t _ptr_sd;
+ TALLOC_CTX *_mem_save_sd_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sd_size));
+ if (r->sd_size < 0 || r->sd_size > 0x40000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sd));
+ if (_ptr_sd) {
+ NDR_PULL_ALLOC(ndr, r->sd);
+ } else {
+ r->sd = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sd) {
+ _mem_save_sd_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sd, 0);
+ {
+ struct ndr_pull *_ndr_sd;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_sd, 4, -1));
+ NDR_CHECK(ndr_pull_security_descriptor(_ndr_sd, NDR_SCALARS|NDR_BUFFERS, r->sd));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_sd, 4, -1));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sd_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_sec_desc_buf(struct ndr_print *ndr, const char *name, const struct sec_desc_buf *r)
+{
+ ndr_print_struct(ndr, name, "sec_desc_buf");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "sd_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?ndr_size_security_descriptor(r->sd, ndr->flags):r->sd_size);
+ ndr_print_ptr(ndr, "sd", r->sd);
+ ndr->depth++;
+ if (r->sd) {
+ ndr_print_security_descriptor(ndr, "sd", r->sd);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_security_token(struct ndr_push *ndr, int ndr_flags, const struct security_token *r)
+{
+ uint32_t cntr_sids_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->user_sid));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->group_sid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_sids));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_sids));
+ for (cntr_sids_0 = 0; cntr_sids_0 < r->num_sids; cntr_sids_0++) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sids[cntr_sids_0]));
+ }
+ NDR_CHECK(ndr_push_udlong(ndr, NDR_SCALARS, r->privilege_mask));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->user_sid) {
+ NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS|NDR_BUFFERS, r->user_sid));
+ }
+ if (r->group_sid) {
+ NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS|NDR_BUFFERS, r->group_sid));
+ }
+ for (cntr_sids_0 = 0; cntr_sids_0 < r->num_sids; cntr_sids_0++) {
+ if (r->sids[cntr_sids_0]) {
+ NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS|NDR_BUFFERS, r->sids[cntr_sids_0]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_security_token(struct ndr_pull *ndr, int ndr_flags, struct security_token *r)
+{
+ uint32_t _ptr_user_sid;
+ TALLOC_CTX *_mem_save_user_sid_0;
+ uint32_t _ptr_group_sid;
+ TALLOC_CTX *_mem_save_group_sid_0;
+ uint32_t _ptr_sids;
+ uint32_t cntr_sids_0;
+ TALLOC_CTX *_mem_save_sids_0;
+ TALLOC_CTX *_mem_save_sids_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user_sid));
+ if (_ptr_user_sid) {
+ NDR_PULL_ALLOC(ndr, r->user_sid);
+ } else {
+ r->user_sid = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_group_sid));
+ if (_ptr_group_sid) {
+ NDR_PULL_ALLOC(ndr, r->group_sid);
+ } else {
+ r->group_sid = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_sids));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->sids));
+ NDR_PULL_ALLOC_N(ndr, r->sids, ndr_get_array_size(ndr, &r->sids));
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids, 0);
+ for (cntr_sids_0 = 0; cntr_sids_0 < r->num_sids; cntr_sids_0++) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sids));
+ if (_ptr_sids) {
+ NDR_PULL_ALLOC(ndr, r->sids[cntr_sids_0]);
+ } else {
+ r->sids[cntr_sids_0] = NULL;
+ }
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, 0);
+ NDR_CHECK(ndr_pull_udlong(ndr, NDR_SCALARS, &r->privilege_mask));
+ if (r->sids) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->sids, r->num_sids));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->user_sid) {
+ _mem_save_user_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user_sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS|NDR_BUFFERS, r->user_sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_sid_0, 0);
+ }
+ if (r->group_sid) {
+ _mem_save_group_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->group_sid, 0);
+ NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS|NDR_BUFFERS, r->group_sid));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_sid_0, 0);
+ }
+ _mem_save_sids_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids, 0);
+ for (cntr_sids_0 = 0; cntr_sids_0 < r->num_sids; cntr_sids_0++) {
+ if (r->sids[cntr_sids_0]) {
+ _mem_save_sids_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sids[cntr_sids_0], 0);
+ NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS|NDR_BUFFERS, r->sids[cntr_sids_0]));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_1, 0);
+ }
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sids_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_security_token(struct ndr_print *ndr, const char *name, const struct security_token *r)
+{
+ uint32_t cntr_sids_0;
+ ndr_print_struct(ndr, name, "security_token");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "user_sid", r->user_sid);
+ ndr->depth++;
+ if (r->user_sid) {
+ ndr_print_dom_sid(ndr, "user_sid", r->user_sid);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "group_sid", r->group_sid);
+ ndr->depth++;
+ if (r->group_sid) {
+ ndr_print_dom_sid(ndr, "group_sid", r->group_sid);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "num_sids", r->num_sids);
+ ndr->print(ndr, "%s: ARRAY(%d)", "sids", (int)r->num_sids);
+ ndr->depth++;
+ for (cntr_sids_0=0;cntr_sids_0<r->num_sids;cntr_sids_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_sids_0) != -1) {
+ ndr_print_ptr(ndr, "sids", r->sids[cntr_sids_0]);
+ ndr->depth++;
+ if (r->sids[cntr_sids_0]) {
+ ndr_print_dom_sid(ndr, "sids", r->sids[cntr_sids_0]);
+ }
+ ndr->depth--;
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr_print_udlong(ndr, "privilege_mask", r->privilege_mask);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_security_secinfo(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_security_secinfo(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_security_secinfo(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SECINFO_OWNER", SECINFO_OWNER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SECINFO_GROUP", SECINFO_GROUP, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SECINFO_DACL", SECINFO_DACL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SECINFO_SACL", SECINFO_SACL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SECINFO_UNPROTECTED_SACL", SECINFO_UNPROTECTED_SACL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SECINFO_UNPROTECTED_DACL", SECINFO_UNPROTECTED_DACL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SECINFO_PROTECTED_SACL", SECINFO_PROTECTED_SACL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SECINFO_PROTECTED_DACL", SECINFO_PROTECTED_DACL, r);
+ ndr->depth--;
+}
+
diff --git a/source3/librpc/gen_ndr/ndr_security.h b/source3/librpc/gen_ndr/ndr_security.h
new file mode 100644
index 0000000000..79bfd78f51
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_security.h
@@ -0,0 +1,41 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/security.h"
+
+#ifndef _HEADER_NDR_security
+#define _HEADER_NDR_security
+
+#define NDR_SECURITY_CALL_COUNT (0)
+void ndr_print_security_ace_flags(struct ndr_print *ndr, const char *name, uint8_t r);
+void ndr_print_security_ace_type(struct ndr_print *ndr, const char *name, enum security_ace_type r);
+void ndr_print_security_ace_object_flags(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_security_ace_object_type(struct ndr_print *ndr, const char *name, const union security_ace_object_type *r);
+void ndr_print_security_ace_object_inherited_type(struct ndr_print *ndr, const char *name, const union security_ace_object_inherited_type *r);
+void ndr_print_security_ace_object(struct ndr_print *ndr, const char *name, const struct security_ace_object *r);
+void ndr_print_security_ace_object_ctr(struct ndr_print *ndr, const char *name, const union security_ace_object_ctr *r);
+enum ndr_err_code ndr_push_security_ace(struct ndr_push *ndr, int ndr_flags, const struct security_ace *r);
+enum ndr_err_code ndr_pull_security_ace(struct ndr_pull *ndr, int ndr_flags, struct security_ace *r);
+void ndr_print_security_ace(struct ndr_print *ndr, const char *name, const struct security_ace *r);
+size_t ndr_size_security_ace(const struct security_ace *r, int flags);
+void ndr_print_security_acl_revision(struct ndr_print *ndr, const char *name, enum security_acl_revision r);
+enum ndr_err_code ndr_push_security_acl(struct ndr_push *ndr, int ndr_flags, const struct security_acl *r);
+enum ndr_err_code ndr_pull_security_acl(struct ndr_pull *ndr, int ndr_flags, struct security_acl *r);
+void ndr_print_security_acl(struct ndr_print *ndr, const char *name, const struct security_acl *r);
+size_t ndr_size_security_acl(const struct security_acl *r, int flags);
+void ndr_print_security_descriptor_revision(struct ndr_print *ndr, const char *name, enum security_descriptor_revision r);
+void ndr_print_security_descriptor_type(struct ndr_print *ndr, const char *name, uint16_t r);
+enum ndr_err_code ndr_push_security_descriptor(struct ndr_push *ndr, int ndr_flags, const struct security_descriptor *r);
+enum ndr_err_code ndr_pull_security_descriptor(struct ndr_pull *ndr, int ndr_flags, struct security_descriptor *r);
+void ndr_print_security_descriptor(struct ndr_print *ndr, const char *name, const struct security_descriptor *r);
+size_t ndr_size_security_descriptor(const struct security_descriptor *r, int flags);
+enum ndr_err_code ndr_push_sec_desc_buf(struct ndr_push *ndr, int ndr_flags, const struct sec_desc_buf *r);
+enum ndr_err_code ndr_pull_sec_desc_buf(struct ndr_pull *ndr, int ndr_flags, struct sec_desc_buf *r);
+void ndr_print_sec_desc_buf(struct ndr_print *ndr, const char *name, const struct sec_desc_buf *r);
+enum ndr_err_code ndr_push_security_token(struct ndr_push *ndr, int ndr_flags, const struct security_token *r);
+enum ndr_err_code ndr_pull_security_token(struct ndr_pull *ndr, int ndr_flags, struct security_token *r);
+void ndr_print_security_token(struct ndr_print *ndr, const char *name, const struct security_token *r);
+enum ndr_err_code ndr_push_security_secinfo(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_security_secinfo(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_security_secinfo(struct ndr_print *ndr, const char *name, uint32_t r);
+#endif /* _HEADER_NDR_security */
diff --git a/source3/librpc/gen_ndr/ndr_srvsvc.c b/source3/librpc/gen_ndr/ndr_srvsvc.c
new file mode 100644
index 0000000000..d97ee0171c
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_srvsvc.c
@@ -0,0 +1,19654 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_srvsvc.h"
+
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_svcctl.h"
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevInfo0(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetCharDevInfo0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->device));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->device) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->device, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->device, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->device, ndr_charset_length(r->device, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevInfo0(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetCharDevInfo0 *r)
+{
+ uint32_t _ptr_device;
+ TALLOC_CTX *_mem_save_device_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_device));
+ if (_ptr_device) {
+ NDR_PULL_ALLOC(ndr, r->device);
+ } else {
+ r->device = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->device) {
+ _mem_save_device_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->device, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->device));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->device));
+ if (ndr_get_array_length(ndr, &r->device) > ndr_get_array_size(ndr, &r->device)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->device), ndr_get_array_length(ndr, &r->device));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->device), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->device, ndr_get_array_length(ndr, &r->device), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_device_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevInfo0 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetCharDevInfo0");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "device", r->device);
+ ndr->depth++;
+ if (r->device) {
+ ndr_print_string(ndr, "device", r->device);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevCtr0(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetCharDevCtr0 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevInfo0(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevInfo0(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevCtr0(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetCharDevCtr0 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevInfo0(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevInfo0(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevCtr0 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetCharDevCtr0");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetCharDevInfo0(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevInfo1(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetCharDevInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->device));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->status));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->user));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->time));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->device) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->device, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->device, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->device, ndr_charset_length(r->device, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->user) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->user, ndr_charset_length(r->user, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevInfo1(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetCharDevInfo1 *r)
+{
+ uint32_t _ptr_device;
+ TALLOC_CTX *_mem_save_device_0;
+ uint32_t _ptr_user;
+ TALLOC_CTX *_mem_save_user_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_device));
+ if (_ptr_device) {
+ NDR_PULL_ALLOC(ndr, r->device);
+ } else {
+ r->device = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->status));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user));
+ if (_ptr_user) {
+ NDR_PULL_ALLOC(ndr, r->user);
+ } else {
+ r->user = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->time));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->device) {
+ _mem_save_device_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->device, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->device));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->device));
+ if (ndr_get_array_length(ndr, &r->device) > ndr_get_array_size(ndr, &r->device)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->device), ndr_get_array_length(ndr, &r->device));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->device), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->device, ndr_get_array_length(ndr, &r->device), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_device_0, 0);
+ }
+ if (r->user) {
+ _mem_save_user_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->user));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->user));
+ if (ndr_get_array_length(ndr, &r->user) > ndr_get_array_size(ndr, &r->user)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->user), ndr_get_array_length(ndr, &r->user));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->user), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->user, ndr_get_array_length(ndr, &r->user), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevInfo1 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetCharDevInfo1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "device", r->device);
+ ndr->depth++;
+ if (r->device) {
+ ndr_print_string(ndr, "device", r->device);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "status", r->status);
+ ndr_print_ptr(ndr, "user", r->user);
+ ndr->depth++;
+ if (r->user) {
+ ndr_print_string(ndr, "user", r->user);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "time", r->time);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevCtr1(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetCharDevCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevCtr1(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetCharDevCtr1 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetCharDevCtr1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetCharDevInfo1(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevInfo(struct ndr_push *ndr, int ndr_flags, const union srvsvc_NetCharDevInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info0));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ if (r->info0) {
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevInfo0(ndr, NDR_SCALARS|NDR_BUFFERS, r->info0));
+ }
+ break;
+
+ case 1:
+ if (r->info1) {
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevInfo1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevInfo(struct ndr_pull *ndr, int ndr_flags, union srvsvc_NetCharDevInfo *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_info0_0;
+ TALLOC_CTX *_mem_save_info1_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 0: {
+ uint32_t _ptr_info0;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info0));
+ if (_ptr_info0) {
+ NDR_PULL_ALLOC(ndr, r->info0);
+ } else {
+ r->info0 = NULL;
+ }
+ break; }
+
+ case 1: {
+ uint32_t _ptr_info1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1));
+ if (_ptr_info1) {
+ NDR_PULL_ALLOC(ndr, r->info1);
+ } else {
+ r->info1 = NULL;
+ }
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ if (r->info0) {
+ _mem_save_info0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info0, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevInfo0(ndr, NDR_SCALARS|NDR_BUFFERS, r->info0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info0_0, 0);
+ }
+ break;
+
+ case 1:
+ if (r->info1) {
+ _mem_save_info1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevInfo1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1_0, 0);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetCharDevInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "srvsvc_NetCharDevInfo");
+ switch (level) {
+ case 0:
+ ndr_print_ptr(ndr, "info0", r->info0);
+ ndr->depth++;
+ if (r->info0) {
+ ndr_print_srvsvc_NetCharDevInfo0(ndr, "info0", r->info0);
+ }
+ ndr->depth--;
+ break;
+
+ case 1:
+ ndr_print_ptr(ndr, "info1", r->info1);
+ ndr->depth++;
+ if (r->info1) {
+ ndr_print_srvsvc_NetCharDevInfo1(ndr, "info1", r->info1);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevCtr(struct ndr_push *ndr, int ndr_flags, const union srvsvc_NetCharDevCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr0));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr1));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ if (r->ctr0) {
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr0));
+ }
+ break;
+
+ case 1:
+ if (r->ctr1) {
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevCtr(struct ndr_pull *ndr, int ndr_flags, union srvsvc_NetCharDevCtr *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_ctr0_0;
+ TALLOC_CTX *_mem_save_ctr1_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 0: {
+ uint32_t _ptr_ctr0;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr0));
+ if (_ptr_ctr0) {
+ NDR_PULL_ALLOC(ndr, r->ctr0);
+ } else {
+ r->ctr0 = NULL;
+ }
+ break; }
+
+ case 1: {
+ uint32_t _ptr_ctr1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr1));
+ if (_ptr_ctr1) {
+ NDR_PULL_ALLOC(ndr, r->ctr1);
+ } else {
+ r->ctr1 = NULL;
+ }
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ if (r->ctr0) {
+ _mem_save_ctr0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr0, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr0_0, 0);
+ }
+ break;
+
+ case 1:
+ if (r->ctr1) {
+ _mem_save_ctr1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr1, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr1_0, 0);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetCharDevCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "srvsvc_NetCharDevCtr");
+ switch (level) {
+ case 0:
+ ndr_print_ptr(ndr, "ctr0", r->ctr0);
+ ndr->depth++;
+ if (r->ctr0) {
+ ndr_print_srvsvc_NetCharDevCtr0(ndr, "ctr0", r->ctr0);
+ }
+ ndr->depth--;
+ break;
+
+ case 1:
+ ndr_print_ptr(ndr, "ctr1", r->ctr1);
+ ndr->depth++;
+ if (r->ctr1) {
+ ndr_print_srvsvc_NetCharDevCtr1(ndr, "ctr1", r->ctr1);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevQInfo0(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetCharDevQInfo0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->device));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->device) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->device, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->device, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->device, ndr_charset_length(r->device, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevQInfo0(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetCharDevQInfo0 *r)
+{
+ uint32_t _ptr_device;
+ TALLOC_CTX *_mem_save_device_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_device));
+ if (_ptr_device) {
+ NDR_PULL_ALLOC(ndr, r->device);
+ } else {
+ r->device = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->device) {
+ _mem_save_device_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->device, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->device));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->device));
+ if (ndr_get_array_length(ndr, &r->device) > ndr_get_array_size(ndr, &r->device)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->device), ndr_get_array_length(ndr, &r->device));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->device), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->device, ndr_get_array_length(ndr, &r->device), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_device_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevQInfo0 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetCharDevQInfo0");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "device", r->device);
+ ndr->depth++;
+ if (r->device) {
+ ndr_print_string(ndr, "device", r->device);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevQCtr0(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetCharDevQCtr0 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevQInfo0(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevQInfo0(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevQCtr0(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetCharDevQCtr0 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevQInfo0(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevQInfo0(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevQCtr0 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetCharDevQCtr0");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetCharDevQInfo0(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevQInfo1(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetCharDevQInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->device));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->priority));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->devices));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->users));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_ahead));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->device) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->device, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->device, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->device, ndr_charset_length(r->device, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->devices) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->devices, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->devices, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->devices, ndr_charset_length(r->devices, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevQInfo1(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetCharDevQInfo1 *r)
+{
+ uint32_t _ptr_device;
+ TALLOC_CTX *_mem_save_device_0;
+ uint32_t _ptr_devices;
+ TALLOC_CTX *_mem_save_devices_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_device));
+ if (_ptr_device) {
+ NDR_PULL_ALLOC(ndr, r->device);
+ } else {
+ r->device = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->priority));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_devices));
+ if (_ptr_devices) {
+ NDR_PULL_ALLOC(ndr, r->devices);
+ } else {
+ r->devices = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->users));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_ahead));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->device) {
+ _mem_save_device_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->device, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->device));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->device));
+ if (ndr_get_array_length(ndr, &r->device) > ndr_get_array_size(ndr, &r->device)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->device), ndr_get_array_length(ndr, &r->device));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->device), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->device, ndr_get_array_length(ndr, &r->device), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_device_0, 0);
+ }
+ if (r->devices) {
+ _mem_save_devices_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->devices, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->devices));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->devices));
+ if (ndr_get_array_length(ndr, &r->devices) > ndr_get_array_size(ndr, &r->devices)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->devices), ndr_get_array_length(ndr, &r->devices));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->devices), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->devices, ndr_get_array_length(ndr, &r->devices), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_devices_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevQInfo1 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetCharDevQInfo1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "device", r->device);
+ ndr->depth++;
+ if (r->device) {
+ ndr_print_string(ndr, "device", r->device);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "priority", r->priority);
+ ndr_print_ptr(ndr, "devices", r->devices);
+ ndr->depth++;
+ if (r->devices) {
+ ndr_print_string(ndr, "devices", r->devices);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "users", r->users);
+ ndr_print_uint32(ndr, "num_ahead", r->num_ahead);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevQCtr1(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetCharDevQCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevQInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevQInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevQCtr1(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetCharDevQCtr1 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevQInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevQInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevQCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetCharDevQCtr1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetCharDevQInfo1(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevQInfo(struct ndr_push *ndr, int ndr_flags, const union srvsvc_NetCharDevQInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info0));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ if (r->info0) {
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevQInfo0(ndr, NDR_SCALARS|NDR_BUFFERS, r->info0));
+ }
+ break;
+
+ case 1:
+ if (r->info1) {
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevQInfo1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevQInfo(struct ndr_pull *ndr, int ndr_flags, union srvsvc_NetCharDevQInfo *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_info0_0;
+ TALLOC_CTX *_mem_save_info1_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 0: {
+ uint32_t _ptr_info0;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info0));
+ if (_ptr_info0) {
+ NDR_PULL_ALLOC(ndr, r->info0);
+ } else {
+ r->info0 = NULL;
+ }
+ break; }
+
+ case 1: {
+ uint32_t _ptr_info1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1));
+ if (_ptr_info1) {
+ NDR_PULL_ALLOC(ndr, r->info1);
+ } else {
+ r->info1 = NULL;
+ }
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ if (r->info0) {
+ _mem_save_info0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info0, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevQInfo0(ndr, NDR_SCALARS|NDR_BUFFERS, r->info0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info0_0, 0);
+ }
+ break;
+
+ case 1:
+ if (r->info1) {
+ _mem_save_info1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevQInfo1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1_0, 0);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetCharDevQInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "srvsvc_NetCharDevQInfo");
+ switch (level) {
+ case 0:
+ ndr_print_ptr(ndr, "info0", r->info0);
+ ndr->depth++;
+ if (r->info0) {
+ ndr_print_srvsvc_NetCharDevQInfo0(ndr, "info0", r->info0);
+ }
+ ndr->depth--;
+ break;
+
+ case 1:
+ ndr_print_ptr(ndr, "info1", r->info1);
+ ndr->depth++;
+ if (r->info1) {
+ ndr_print_srvsvc_NetCharDevQInfo1(ndr, "info1", r->info1);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevQCtr(struct ndr_push *ndr, int ndr_flags, const union srvsvc_NetCharDevQCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr0));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr1));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ if (r->ctr0) {
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevQCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr0));
+ }
+ break;
+
+ case 1:
+ if (r->ctr1) {
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevQCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevQCtr(struct ndr_pull *ndr, int ndr_flags, union srvsvc_NetCharDevQCtr *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_ctr0_0;
+ TALLOC_CTX *_mem_save_ctr1_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 0: {
+ uint32_t _ptr_ctr0;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr0));
+ if (_ptr_ctr0) {
+ NDR_PULL_ALLOC(ndr, r->ctr0);
+ } else {
+ r->ctr0 = NULL;
+ }
+ break; }
+
+ case 1: {
+ uint32_t _ptr_ctr1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr1));
+ if (_ptr_ctr1) {
+ NDR_PULL_ALLOC(ndr, r->ctr1);
+ } else {
+ r->ctr1 = NULL;
+ }
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ if (r->ctr0) {
+ _mem_save_ctr0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr0, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevQCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr0_0, 0);
+ }
+ break;
+
+ case 1:
+ if (r->ctr1) {
+ _mem_save_ctr1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr1, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevQCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr1_0, 0);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetCharDevQCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "srvsvc_NetCharDevQCtr");
+ switch (level) {
+ case 0:
+ ndr_print_ptr(ndr, "ctr0", r->ctr0);
+ ndr->depth++;
+ if (r->ctr0) {
+ ndr_print_srvsvc_NetCharDevQCtr0(ndr, "ctr0", r->ctr0);
+ }
+ ndr->depth--;
+ break;
+
+ case 1:
+ ndr_print_ptr(ndr, "ctr1", r->ctr1);
+ ndr->depth++;
+ if (r->ctr1) {
+ ndr_print_srvsvc_NetCharDevQCtr1(ndr, "ctr1", r->ctr1);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetConnInfo0(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetConnInfo0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->conn_id));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetConnInfo0(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetConnInfo0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->conn_id));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetConnInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetConnInfo0 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetConnInfo0");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "conn_id", r->conn_id);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetConnCtr0(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetConnCtr0 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetConnInfo0(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetConnCtr0(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetConnCtr0 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetConnInfo0(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetConnCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetConnCtr0 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetConnCtr0");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetConnInfo0(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetConnInfo1(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetConnInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->conn_id));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->conn_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_open));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_users));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->conn_time));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->user));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->share));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->user) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->user, ndr_charset_length(r->user, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->share) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->share, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->share, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->share, ndr_charset_length(r->share, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetConnInfo1(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetConnInfo1 *r)
+{
+ uint32_t _ptr_user;
+ TALLOC_CTX *_mem_save_user_0;
+ uint32_t _ptr_share;
+ TALLOC_CTX *_mem_save_share_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->conn_id));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->conn_type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_open));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_users));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->conn_time));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user));
+ if (_ptr_user) {
+ NDR_PULL_ALLOC(ndr, r->user);
+ } else {
+ r->user = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_share));
+ if (_ptr_share) {
+ NDR_PULL_ALLOC(ndr, r->share);
+ } else {
+ r->share = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->user) {
+ _mem_save_user_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->user));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->user));
+ if (ndr_get_array_length(ndr, &r->user) > ndr_get_array_size(ndr, &r->user)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->user), ndr_get_array_length(ndr, &r->user));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->user), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->user, ndr_get_array_length(ndr, &r->user), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_0, 0);
+ }
+ if (r->share) {
+ _mem_save_share_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->share, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->share));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->share));
+ if (ndr_get_array_length(ndr, &r->share) > ndr_get_array_size(ndr, &r->share)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->share), ndr_get_array_length(ndr, &r->share));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->share), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->share, ndr_get_array_length(ndr, &r->share), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_share_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetConnInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetConnInfo1 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetConnInfo1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "conn_id", r->conn_id);
+ ndr_print_uint32(ndr, "conn_type", r->conn_type);
+ ndr_print_uint32(ndr, "num_open", r->num_open);
+ ndr_print_uint32(ndr, "num_users", r->num_users);
+ ndr_print_uint32(ndr, "conn_time", r->conn_time);
+ ndr_print_ptr(ndr, "user", r->user);
+ ndr->depth++;
+ if (r->user) {
+ ndr_print_string(ndr, "user", r->user);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "share", r->share);
+ ndr->depth++;
+ if (r->share) {
+ ndr_print_string(ndr, "share", r->share);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetConnCtr1(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetConnCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetConnInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetConnInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetConnCtr1(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetConnCtr1 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetConnInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetConnInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetConnCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetConnCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetConnCtr1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetConnInfo1(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetConnCtr(struct ndr_push *ndr, int ndr_flags, const union srvsvc_NetConnCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr0));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr1));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ if (r->ctr0) {
+ NDR_CHECK(ndr_push_srvsvc_NetConnCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr0));
+ }
+ break;
+
+ case 1:
+ if (r->ctr1) {
+ NDR_CHECK(ndr_push_srvsvc_NetConnCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetConnCtr(struct ndr_pull *ndr, int ndr_flags, union srvsvc_NetConnCtr *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_ctr0_0;
+ TALLOC_CTX *_mem_save_ctr1_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 0: {
+ uint32_t _ptr_ctr0;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr0));
+ if (_ptr_ctr0) {
+ NDR_PULL_ALLOC(ndr, r->ctr0);
+ } else {
+ r->ctr0 = NULL;
+ }
+ break; }
+
+ case 1: {
+ uint32_t _ptr_ctr1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr1));
+ if (_ptr_ctr1) {
+ NDR_PULL_ALLOC(ndr, r->ctr1);
+ } else {
+ r->ctr1 = NULL;
+ }
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ if (r->ctr0) {
+ _mem_save_ctr0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr0, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetConnCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr0_0, 0);
+ }
+ break;
+
+ case 1:
+ if (r->ctr1) {
+ _mem_save_ctr1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr1, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetConnCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr1_0, 0);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetConnCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetConnCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "srvsvc_NetConnCtr");
+ switch (level) {
+ case 0:
+ ndr_print_ptr(ndr, "ctr0", r->ctr0);
+ ndr->depth++;
+ if (r->ctr0) {
+ ndr_print_srvsvc_NetConnCtr0(ndr, "ctr0", r->ctr0);
+ }
+ ndr->depth--;
+ break;
+
+ case 1:
+ ndr_print_ptr(ndr, "ctr1", r->ctr1);
+ ndr->depth++;
+ if (r->ctr1) {
+ ndr_print_srvsvc_NetConnCtr1(ndr, "ctr1", r->ctr1);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetConnInfoCtr(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetConnInfoCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->ctr, r->level));
+ NDR_CHECK(ndr_push_srvsvc_NetConnCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_srvsvc_NetConnCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetConnInfoCtr(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetConnInfoCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->ctr, r->level));
+ NDR_CHECK(ndr_pull_srvsvc_NetConnCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_srvsvc_NetConnCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetConnInfoCtr(struct ndr_print *ndr, const char *name, const struct srvsvc_NetConnInfoCtr *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetConnInfoCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level", r->level);
+ ndr_print_set_switch_value(ndr, &r->ctr, r->level);
+ ndr_print_srvsvc_NetConnCtr(ndr, "ctr", &r->ctr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetFileInfo2(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetFileInfo2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->fid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetFileInfo2(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetFileInfo2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->fid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetFileInfo2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetFileInfo2 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetFileInfo2");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "fid", r->fid);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetFileCtr2(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetFileCtr2 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetFileInfo2(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetFileCtr2(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetFileCtr2 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetFileInfo2(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetFileCtr2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetFileCtr2 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetFileCtr2");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetFileInfo2(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetFileInfo3(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetFileInfo3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->fid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->permissions));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_locks));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->path));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->user));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->path) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->path, ndr_charset_length(r->path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->user) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->user, ndr_charset_length(r->user, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetFileInfo3(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetFileInfo3 *r)
+{
+ uint32_t _ptr_path;
+ TALLOC_CTX *_mem_save_path_0;
+ uint32_t _ptr_user;
+ TALLOC_CTX *_mem_save_user_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->fid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->permissions));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_locks));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_path));
+ if (_ptr_path) {
+ NDR_PULL_ALLOC(ndr, r->path);
+ } else {
+ r->path = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user));
+ if (_ptr_user) {
+ NDR_PULL_ALLOC(ndr, r->user);
+ } else {
+ r->user = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->path) {
+ _mem_save_path_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->path, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->path));
+ if (ndr_get_array_length(ndr, &r->path) > ndr_get_array_size(ndr, &r->path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->path), ndr_get_array_length(ndr, &r->path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->path, ndr_get_array_length(ndr, &r->path), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_path_0, 0);
+ }
+ if (r->user) {
+ _mem_save_user_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->user));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->user));
+ if (ndr_get_array_length(ndr, &r->user) > ndr_get_array_size(ndr, &r->user)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->user), ndr_get_array_length(ndr, &r->user));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->user), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->user, ndr_get_array_length(ndr, &r->user), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetFileInfo3(struct ndr_print *ndr, const char *name, const struct srvsvc_NetFileInfo3 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetFileInfo3");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "fid", r->fid);
+ ndr_print_uint32(ndr, "permissions", r->permissions);
+ ndr_print_uint32(ndr, "num_locks", r->num_locks);
+ ndr_print_ptr(ndr, "path", r->path);
+ ndr->depth++;
+ if (r->path) {
+ ndr_print_string(ndr, "path", r->path);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "user", r->user);
+ ndr->depth++;
+ if (r->user) {
+ ndr_print_string(ndr, "user", r->user);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetFileCtr3(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetFileCtr3 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetFileInfo3(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetFileInfo3(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetFileCtr3(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetFileCtr3 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetFileInfo3(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetFileInfo3(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetFileCtr3(struct ndr_print *ndr, const char *name, const struct srvsvc_NetFileCtr3 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetFileCtr3");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetFileInfo3(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetFileInfo(struct ndr_push *ndr, int ndr_flags, const union srvsvc_NetFileInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info3));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 2:
+ if (r->info2) {
+ NDR_CHECK(ndr_push_srvsvc_NetFileInfo2(ndr, NDR_SCALARS, r->info2));
+ }
+ break;
+
+ case 3:
+ if (r->info3) {
+ NDR_CHECK(ndr_push_srvsvc_NetFileInfo3(ndr, NDR_SCALARS|NDR_BUFFERS, r->info3));
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetFileInfo(struct ndr_pull *ndr, int ndr_flags, union srvsvc_NetFileInfo *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_info2_0;
+ TALLOC_CTX *_mem_save_info3_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 2: {
+ uint32_t _ptr_info2;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info2));
+ if (_ptr_info2) {
+ NDR_PULL_ALLOC(ndr, r->info2);
+ } else {
+ r->info2 = NULL;
+ }
+ break; }
+
+ case 3: {
+ uint32_t _ptr_info3;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info3));
+ if (_ptr_info3) {
+ NDR_PULL_ALLOC(ndr, r->info3);
+ } else {
+ r->info3 = NULL;
+ }
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 2:
+ if (r->info2) {
+ _mem_save_info2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info2, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetFileInfo2(ndr, NDR_SCALARS, r->info2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info2_0, 0);
+ }
+ break;
+
+ case 3:
+ if (r->info3) {
+ _mem_save_info3_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info3, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetFileInfo3(ndr, NDR_SCALARS|NDR_BUFFERS, r->info3));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info3_0, 0);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetFileInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetFileInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "srvsvc_NetFileInfo");
+ switch (level) {
+ case 2:
+ ndr_print_ptr(ndr, "info2", r->info2);
+ ndr->depth++;
+ if (r->info2) {
+ ndr_print_srvsvc_NetFileInfo2(ndr, "info2", r->info2);
+ }
+ ndr->depth--;
+ break;
+
+ case 3:
+ ndr_print_ptr(ndr, "info3", r->info3);
+ ndr->depth++;
+ if (r->info3) {
+ ndr_print_srvsvc_NetFileInfo3(ndr, "info3", r->info3);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetFileCtr(struct ndr_push *ndr, int ndr_flags, const union srvsvc_NetFileCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr3));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 2:
+ if (r->ctr2) {
+ NDR_CHECK(ndr_push_srvsvc_NetFileCtr2(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr2));
+ }
+ break;
+
+ case 3:
+ if (r->ctr3) {
+ NDR_CHECK(ndr_push_srvsvc_NetFileCtr3(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr3));
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetFileCtr(struct ndr_pull *ndr, int ndr_flags, union srvsvc_NetFileCtr *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_ctr2_0;
+ TALLOC_CTX *_mem_save_ctr3_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 2: {
+ uint32_t _ptr_ctr2;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr2));
+ if (_ptr_ctr2) {
+ NDR_PULL_ALLOC(ndr, r->ctr2);
+ } else {
+ r->ctr2 = NULL;
+ }
+ break; }
+
+ case 3: {
+ uint32_t _ptr_ctr3;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr3));
+ if (_ptr_ctr3) {
+ NDR_PULL_ALLOC(ndr, r->ctr3);
+ } else {
+ r->ctr3 = NULL;
+ }
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 2:
+ if (r->ctr2) {
+ _mem_save_ctr2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr2, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetFileCtr2(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr2_0, 0);
+ }
+ break;
+
+ case 3:
+ if (r->ctr3) {
+ _mem_save_ctr3_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr3, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetFileCtr3(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr3));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr3_0, 0);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetFileCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetFileCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "srvsvc_NetFileCtr");
+ switch (level) {
+ case 2:
+ ndr_print_ptr(ndr, "ctr2", r->ctr2);
+ ndr->depth++;
+ if (r->ctr2) {
+ ndr_print_srvsvc_NetFileCtr2(ndr, "ctr2", r->ctr2);
+ }
+ ndr->depth--;
+ break;
+
+ case 3:
+ ndr_print_ptr(ndr, "ctr3", r->ctr3);
+ ndr->depth++;
+ if (r->ctr3) {
+ ndr_print_srvsvc_NetFileCtr3(ndr, "ctr3", r->ctr3);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetFileInfoCtr(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetFileInfoCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->ctr, r->level));
+ NDR_CHECK(ndr_push_srvsvc_NetFileCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_srvsvc_NetFileCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetFileInfoCtr(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetFileInfoCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->ctr, r->level));
+ NDR_CHECK(ndr_pull_srvsvc_NetFileCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_srvsvc_NetFileCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetFileInfoCtr(struct ndr_print *ndr, const char *name, const struct srvsvc_NetFileInfoCtr *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetFileInfoCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level", r->level);
+ ndr_print_set_switch_value(ndr, &r->ctr, r->level);
+ ndr_print_srvsvc_NetFileCtr(ndr, "ctr", &r->ctr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSessInfo0(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSessInfo0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->client));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->client) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->client, ndr_charset_length(r->client, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSessInfo0(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSessInfo0 *r)
+{
+ uint32_t _ptr_client;
+ TALLOC_CTX *_mem_save_client_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_client));
+ if (_ptr_client) {
+ NDR_PULL_ALLOC(ndr, r->client);
+ } else {
+ r->client = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->client) {
+ _mem_save_client_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->client, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->client));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->client));
+ if (ndr_get_array_length(ndr, &r->client) > ndr_get_array_size(ndr, &r->client)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->client), ndr_get_array_length(ndr, &r->client));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->client), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->client, ndr_get_array_length(ndr, &r->client), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_client_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSessInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfo0 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSessInfo0");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "client", r->client);
+ ndr->depth++;
+ if (r->client) {
+ ndr_print_string(ndr, "client", r->client);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSessCtr0(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSessCtr0 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetSessInfo0(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetSessInfo0(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSessCtr0(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSessCtr0 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetSessInfo0(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetSessInfo0(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSessCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessCtr0 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetSessCtr0");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetSessInfo0(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSessInfo1(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSessInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->client));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->user));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_open));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->idle_time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->user_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->client) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->client, ndr_charset_length(r->client, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->user) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->user, ndr_charset_length(r->user, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSessInfo1(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSessInfo1 *r)
+{
+ uint32_t _ptr_client;
+ TALLOC_CTX *_mem_save_client_0;
+ uint32_t _ptr_user;
+ TALLOC_CTX *_mem_save_user_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_client));
+ if (_ptr_client) {
+ NDR_PULL_ALLOC(ndr, r->client);
+ } else {
+ r->client = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user));
+ if (_ptr_user) {
+ NDR_PULL_ALLOC(ndr, r->user);
+ } else {
+ r->user = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_open));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->idle_time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->user_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->client) {
+ _mem_save_client_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->client, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->client));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->client));
+ if (ndr_get_array_length(ndr, &r->client) > ndr_get_array_size(ndr, &r->client)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->client), ndr_get_array_length(ndr, &r->client));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->client), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->client, ndr_get_array_length(ndr, &r->client), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_client_0, 0);
+ }
+ if (r->user) {
+ _mem_save_user_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->user));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->user));
+ if (ndr_get_array_length(ndr, &r->user) > ndr_get_array_size(ndr, &r->user)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->user), ndr_get_array_length(ndr, &r->user));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->user), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->user, ndr_get_array_length(ndr, &r->user), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSessInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfo1 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSessInfo1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "client", r->client);
+ ndr->depth++;
+ if (r->client) {
+ ndr_print_string(ndr, "client", r->client);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "user", r->user);
+ ndr->depth++;
+ if (r->user) {
+ ndr_print_string(ndr, "user", r->user);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "num_open", r->num_open);
+ ndr_print_uint32(ndr, "time", r->time);
+ ndr_print_uint32(ndr, "idle_time", r->idle_time);
+ ndr_print_uint32(ndr, "user_flags", r->user_flags);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSessCtr1(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSessCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetSessInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetSessInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSessCtr1(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSessCtr1 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetSessInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetSessInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSessCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetSessCtr1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetSessInfo1(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSessInfo2(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSessInfo2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->client));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->user));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_open));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->idle_time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->user_flags));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->client_type));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->client) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->client, ndr_charset_length(r->client, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->user) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->user, ndr_charset_length(r->user, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->client_type) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client_type, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client_type, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->client_type, ndr_charset_length(r->client_type, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSessInfo2(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSessInfo2 *r)
+{
+ uint32_t _ptr_client;
+ TALLOC_CTX *_mem_save_client_0;
+ uint32_t _ptr_user;
+ TALLOC_CTX *_mem_save_user_0;
+ uint32_t _ptr_client_type;
+ TALLOC_CTX *_mem_save_client_type_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_client));
+ if (_ptr_client) {
+ NDR_PULL_ALLOC(ndr, r->client);
+ } else {
+ r->client = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user));
+ if (_ptr_user) {
+ NDR_PULL_ALLOC(ndr, r->user);
+ } else {
+ r->user = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_open));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->idle_time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->user_flags));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_client_type));
+ if (_ptr_client_type) {
+ NDR_PULL_ALLOC(ndr, r->client_type);
+ } else {
+ r->client_type = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->client) {
+ _mem_save_client_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->client, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->client));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->client));
+ if (ndr_get_array_length(ndr, &r->client) > ndr_get_array_size(ndr, &r->client)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->client), ndr_get_array_length(ndr, &r->client));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->client), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->client, ndr_get_array_length(ndr, &r->client), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_client_0, 0);
+ }
+ if (r->user) {
+ _mem_save_user_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->user));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->user));
+ if (ndr_get_array_length(ndr, &r->user) > ndr_get_array_size(ndr, &r->user)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->user), ndr_get_array_length(ndr, &r->user));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->user), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->user, ndr_get_array_length(ndr, &r->user), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_0, 0);
+ }
+ if (r->client_type) {
+ _mem_save_client_type_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->client_type, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->client_type));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->client_type));
+ if (ndr_get_array_length(ndr, &r->client_type) > ndr_get_array_size(ndr, &r->client_type)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->client_type), ndr_get_array_length(ndr, &r->client_type));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->client_type), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->client_type, ndr_get_array_length(ndr, &r->client_type), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_client_type_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSessInfo2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfo2 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSessInfo2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "client", r->client);
+ ndr->depth++;
+ if (r->client) {
+ ndr_print_string(ndr, "client", r->client);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "user", r->user);
+ ndr->depth++;
+ if (r->user) {
+ ndr_print_string(ndr, "user", r->user);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "num_open", r->num_open);
+ ndr_print_uint32(ndr, "time", r->time);
+ ndr_print_uint32(ndr, "idle_time", r->idle_time);
+ ndr_print_uint32(ndr, "user_flags", r->user_flags);
+ ndr_print_ptr(ndr, "client_type", r->client_type);
+ ndr->depth++;
+ if (r->client_type) {
+ ndr_print_string(ndr, "client_type", r->client_type);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSessCtr2(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSessCtr2 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetSessInfo2(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetSessInfo2(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSessCtr2(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSessCtr2 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetSessInfo2(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetSessInfo2(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSessCtr2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessCtr2 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetSessCtr2");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetSessInfo2(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSessInfo10(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSessInfo10 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->client));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->user));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->idle_time));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->client) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->client, ndr_charset_length(r->client, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->user) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->user, ndr_charset_length(r->user, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSessInfo10(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSessInfo10 *r)
+{
+ uint32_t _ptr_client;
+ TALLOC_CTX *_mem_save_client_0;
+ uint32_t _ptr_user;
+ TALLOC_CTX *_mem_save_user_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_client));
+ if (_ptr_client) {
+ NDR_PULL_ALLOC(ndr, r->client);
+ } else {
+ r->client = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user));
+ if (_ptr_user) {
+ NDR_PULL_ALLOC(ndr, r->user);
+ } else {
+ r->user = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->idle_time));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->client) {
+ _mem_save_client_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->client, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->client));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->client));
+ if (ndr_get_array_length(ndr, &r->client) > ndr_get_array_size(ndr, &r->client)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->client), ndr_get_array_length(ndr, &r->client));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->client), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->client, ndr_get_array_length(ndr, &r->client), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_client_0, 0);
+ }
+ if (r->user) {
+ _mem_save_user_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->user));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->user));
+ if (ndr_get_array_length(ndr, &r->user) > ndr_get_array_size(ndr, &r->user)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->user), ndr_get_array_length(ndr, &r->user));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->user), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->user, ndr_get_array_length(ndr, &r->user), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSessInfo10(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfo10 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSessInfo10");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "client", r->client);
+ ndr->depth++;
+ if (r->client) {
+ ndr_print_string(ndr, "client", r->client);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "user", r->user);
+ ndr->depth++;
+ if (r->user) {
+ ndr_print_string(ndr, "user", r->user);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "time", r->time);
+ ndr_print_uint32(ndr, "idle_time", r->idle_time);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSessCtr10(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSessCtr10 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetSessInfo10(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetSessInfo10(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSessCtr10(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSessCtr10 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetSessInfo10(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetSessInfo10(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSessCtr10(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessCtr10 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetSessCtr10");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetSessInfo10(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSessInfo502(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSessInfo502 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->client));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->user));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_open));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->idle_time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->user_flags));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->client_type));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->transport));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->client) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->client, ndr_charset_length(r->client, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->user) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->user, ndr_charset_length(r->user, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->client_type) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client_type, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->client_type, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->client_type, ndr_charset_length(r->client_type, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->transport) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->transport, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->transport, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->transport, ndr_charset_length(r->transport, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSessInfo502(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSessInfo502 *r)
+{
+ uint32_t _ptr_client;
+ TALLOC_CTX *_mem_save_client_0;
+ uint32_t _ptr_user;
+ TALLOC_CTX *_mem_save_user_0;
+ uint32_t _ptr_client_type;
+ TALLOC_CTX *_mem_save_client_type_0;
+ uint32_t _ptr_transport;
+ TALLOC_CTX *_mem_save_transport_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_client));
+ if (_ptr_client) {
+ NDR_PULL_ALLOC(ndr, r->client);
+ } else {
+ r->client = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user));
+ if (_ptr_user) {
+ NDR_PULL_ALLOC(ndr, r->user);
+ } else {
+ r->user = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_open));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->idle_time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->user_flags));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_client_type));
+ if (_ptr_client_type) {
+ NDR_PULL_ALLOC(ndr, r->client_type);
+ } else {
+ r->client_type = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_transport));
+ if (_ptr_transport) {
+ NDR_PULL_ALLOC(ndr, r->transport);
+ } else {
+ r->transport = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->client) {
+ _mem_save_client_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->client, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->client));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->client));
+ if (ndr_get_array_length(ndr, &r->client) > ndr_get_array_size(ndr, &r->client)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->client), ndr_get_array_length(ndr, &r->client));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->client), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->client, ndr_get_array_length(ndr, &r->client), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_client_0, 0);
+ }
+ if (r->user) {
+ _mem_save_user_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->user));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->user));
+ if (ndr_get_array_length(ndr, &r->user) > ndr_get_array_size(ndr, &r->user)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->user), ndr_get_array_length(ndr, &r->user));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->user), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->user, ndr_get_array_length(ndr, &r->user), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_0, 0);
+ }
+ if (r->client_type) {
+ _mem_save_client_type_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->client_type, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->client_type));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->client_type));
+ if (ndr_get_array_length(ndr, &r->client_type) > ndr_get_array_size(ndr, &r->client_type)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->client_type), ndr_get_array_length(ndr, &r->client_type));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->client_type), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->client_type, ndr_get_array_length(ndr, &r->client_type), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_client_type_0, 0);
+ }
+ if (r->transport) {
+ _mem_save_transport_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->transport, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->transport));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->transport));
+ if (ndr_get_array_length(ndr, &r->transport) > ndr_get_array_size(ndr, &r->transport)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->transport), ndr_get_array_length(ndr, &r->transport));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->transport), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->transport, ndr_get_array_length(ndr, &r->transport), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_transport_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSessInfo502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfo502 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSessInfo502");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "client", r->client);
+ ndr->depth++;
+ if (r->client) {
+ ndr_print_string(ndr, "client", r->client);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "user", r->user);
+ ndr->depth++;
+ if (r->user) {
+ ndr_print_string(ndr, "user", r->user);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "num_open", r->num_open);
+ ndr_print_uint32(ndr, "time", r->time);
+ ndr_print_uint32(ndr, "idle_time", r->idle_time);
+ ndr_print_uint32(ndr, "user_flags", r->user_flags);
+ ndr_print_ptr(ndr, "client_type", r->client_type);
+ ndr->depth++;
+ if (r->client_type) {
+ ndr_print_string(ndr, "client_type", r->client_type);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "transport", r->transport);
+ ndr->depth++;
+ if (r->transport) {
+ ndr_print_string(ndr, "transport", r->transport);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSessCtr502(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSessCtr502 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetSessInfo502(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetSessInfo502(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSessCtr502(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSessCtr502 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetSessInfo502(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetSessInfo502(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSessCtr502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessCtr502 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetSessCtr502");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetSessInfo502(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSessCtr(struct ndr_push *ndr, int ndr_flags, const union srvsvc_NetSessCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr0));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr2));
+ break; }
+
+ case 10: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr10));
+ break; }
+
+ case 502: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr502));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ if (r->ctr0) {
+ NDR_CHECK(ndr_push_srvsvc_NetSessCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr0));
+ }
+ break;
+
+ case 1:
+ if (r->ctr1) {
+ NDR_CHECK(ndr_push_srvsvc_NetSessCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ }
+ break;
+
+ case 2:
+ if (r->ctr2) {
+ NDR_CHECK(ndr_push_srvsvc_NetSessCtr2(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr2));
+ }
+ break;
+
+ case 10:
+ if (r->ctr10) {
+ NDR_CHECK(ndr_push_srvsvc_NetSessCtr10(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr10));
+ }
+ break;
+
+ case 502:
+ if (r->ctr502) {
+ NDR_CHECK(ndr_push_srvsvc_NetSessCtr502(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr502));
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSessCtr(struct ndr_pull *ndr, int ndr_flags, union srvsvc_NetSessCtr *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_ctr0_0;
+ TALLOC_CTX *_mem_save_ctr1_0;
+ TALLOC_CTX *_mem_save_ctr2_0;
+ TALLOC_CTX *_mem_save_ctr10_0;
+ TALLOC_CTX *_mem_save_ctr502_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 0: {
+ uint32_t _ptr_ctr0;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr0));
+ if (_ptr_ctr0) {
+ NDR_PULL_ALLOC(ndr, r->ctr0);
+ } else {
+ r->ctr0 = NULL;
+ }
+ break; }
+
+ case 1: {
+ uint32_t _ptr_ctr1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr1));
+ if (_ptr_ctr1) {
+ NDR_PULL_ALLOC(ndr, r->ctr1);
+ } else {
+ r->ctr1 = NULL;
+ }
+ break; }
+
+ case 2: {
+ uint32_t _ptr_ctr2;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr2));
+ if (_ptr_ctr2) {
+ NDR_PULL_ALLOC(ndr, r->ctr2);
+ } else {
+ r->ctr2 = NULL;
+ }
+ break; }
+
+ case 10: {
+ uint32_t _ptr_ctr10;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr10));
+ if (_ptr_ctr10) {
+ NDR_PULL_ALLOC(ndr, r->ctr10);
+ } else {
+ r->ctr10 = NULL;
+ }
+ break; }
+
+ case 502: {
+ uint32_t _ptr_ctr502;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr502));
+ if (_ptr_ctr502) {
+ NDR_PULL_ALLOC(ndr, r->ctr502);
+ } else {
+ r->ctr502 = NULL;
+ }
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ if (r->ctr0) {
+ _mem_save_ctr0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr0, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSessCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr0_0, 0);
+ }
+ break;
+
+ case 1:
+ if (r->ctr1) {
+ _mem_save_ctr1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr1, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSessCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr1_0, 0);
+ }
+ break;
+
+ case 2:
+ if (r->ctr2) {
+ _mem_save_ctr2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr2, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSessCtr2(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr2_0, 0);
+ }
+ break;
+
+ case 10:
+ if (r->ctr10) {
+ _mem_save_ctr10_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr10, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSessCtr10(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr10));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr10_0, 0);
+ }
+ break;
+
+ case 502:
+ if (r->ctr502) {
+ _mem_save_ctr502_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr502, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSessCtr502(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr502));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr502_0, 0);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSessCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetSessCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "srvsvc_NetSessCtr");
+ switch (level) {
+ case 0:
+ ndr_print_ptr(ndr, "ctr0", r->ctr0);
+ ndr->depth++;
+ if (r->ctr0) {
+ ndr_print_srvsvc_NetSessCtr0(ndr, "ctr0", r->ctr0);
+ }
+ ndr->depth--;
+ break;
+
+ case 1:
+ ndr_print_ptr(ndr, "ctr1", r->ctr1);
+ ndr->depth++;
+ if (r->ctr1) {
+ ndr_print_srvsvc_NetSessCtr1(ndr, "ctr1", r->ctr1);
+ }
+ ndr->depth--;
+ break;
+
+ case 2:
+ ndr_print_ptr(ndr, "ctr2", r->ctr2);
+ ndr->depth++;
+ if (r->ctr2) {
+ ndr_print_srvsvc_NetSessCtr2(ndr, "ctr2", r->ctr2);
+ }
+ ndr->depth--;
+ break;
+
+ case 10:
+ ndr_print_ptr(ndr, "ctr10", r->ctr10);
+ ndr->depth++;
+ if (r->ctr10) {
+ ndr_print_srvsvc_NetSessCtr10(ndr, "ctr10", r->ctr10);
+ }
+ ndr->depth--;
+ break;
+
+ case 502:
+ ndr_print_ptr(ndr, "ctr502", r->ctr502);
+ ndr->depth++;
+ if (r->ctr502) {
+ ndr_print_srvsvc_NetSessCtr502(ndr, "ctr502", r->ctr502);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSessInfoCtr(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSessInfoCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->ctr, r->level));
+ NDR_CHECK(ndr_push_srvsvc_NetSessCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_srvsvc_NetSessCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSessInfoCtr(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSessInfoCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->ctr, r->level));
+ NDR_CHECK(ndr_pull_srvsvc_NetSessCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_srvsvc_NetSessCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSessInfoCtr(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfoCtr *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSessInfoCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level", r->level);
+ ndr_print_set_switch_value(ndr, &r->ctr, r->level);
+ ndr_print_srvsvc_NetSessCtr(ndr, "ctr", &r->ctr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_ShareType(struct ndr_push *ndr, int ndr_flags, enum srvsvc_ShareType r)
+{
+ {
+ uint32_t _flags_save_ENUM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ ndr->flags = _flags_save_ENUM;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_ShareType(struct ndr_pull *ndr, int ndr_flags, enum srvsvc_ShareType *r)
+{
+ uint32_t v;
+ {
+ uint32_t _flags_save_ENUM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ ndr->flags = _flags_save_ENUM;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_ShareType(struct ndr_print *ndr, const char *name, enum srvsvc_ShareType r)
+{
+ const char *val = NULL;
+
+ {
+ uint32_t _flags_save_ENUM = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ switch (r) {
+ case STYPE_DISKTREE: val = "STYPE_DISKTREE"; break;
+ case STYPE_DISKTREE_TEMPORARY: val = "STYPE_DISKTREE_TEMPORARY"; break;
+ case STYPE_DISKTREE_HIDDEN: val = "STYPE_DISKTREE_HIDDEN"; break;
+ case STYPE_PRINTQ: val = "STYPE_PRINTQ"; break;
+ case STYPE_PRINTQ_TEMPORARY: val = "STYPE_PRINTQ_TEMPORARY"; break;
+ case STYPE_PRINTQ_HIDDEN: val = "STYPE_PRINTQ_HIDDEN"; break;
+ case STYPE_DEVICE: val = "STYPE_DEVICE"; break;
+ case STYPE_DEVICE_TEMPORARY: val = "STYPE_DEVICE_TEMPORARY"; break;
+ case STYPE_DEVICE_HIDDEN: val = "STYPE_DEVICE_HIDDEN"; break;
+ case STYPE_IPC: val = "STYPE_IPC"; break;
+ case STYPE_IPC_TEMPORARY: val = "STYPE_IPC_TEMPORARY"; break;
+ case STYPE_IPC_HIDDEN: val = "STYPE_IPC_HIDDEN"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+ ndr->flags = _flags_save_ENUM;
+ }
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareInfo0(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareInfo0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, ndr_charset_length(r->name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareInfo0(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareInfo0 *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->name));
+ if (ndr_get_array_length(ndr, &r->name) > ndr_get_array_size(ndr, &r->name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->name), ndr_get_array_length(ndr, &r->name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo0 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareInfo0");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_string(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareCtr0(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareCtr0 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo0(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo0(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareCtr0(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareCtr0 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo0(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo0(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr0 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetShareCtr0");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetShareInfo0(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareInfo1(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ NDR_CHECK(ndr_push_srvsvc_ShareType(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, ndr_charset_length(r->name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->comment) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->comment, ndr_charset_length(r->comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareInfo1(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareInfo1 *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_name_0;
+ uint32_t _ptr_comment;
+ TALLOC_CTX *_mem_save_comment_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ NDR_CHECK(ndr_pull_srvsvc_ShareType(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_comment));
+ if (_ptr_comment) {
+ NDR_PULL_ALLOC(ndr, r->comment);
+ } else {
+ r->comment = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->name));
+ if (ndr_get_array_length(ndr, &r->name) > ndr_get_array_size(ndr, &r->name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->name), ndr_get_array_length(ndr, &r->name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ if (r->comment) {
+ _mem_save_comment_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->comment, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->comment));
+ if (ndr_get_array_length(ndr, &r->comment) > ndr_get_array_size(ndr, &r->comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->comment), ndr_get_array_length(ndr, &r->comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->comment, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_comment_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo1 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareInfo1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_string(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ ndr_print_srvsvc_ShareType(ndr, "type", r->type);
+ ndr_print_ptr(ndr, "comment", r->comment);
+ ndr->depth++;
+ if (r->comment) {
+ ndr_print_string(ndr, "comment", r->comment);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareCtr1(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareCtr1(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareCtr1 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetShareCtr1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetShareInfo1(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareInfo2(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareInfo2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ NDR_CHECK(ndr_push_srvsvc_ShareType(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->comment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->permissions));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_users));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->current_users));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->path));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->password));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, ndr_charset_length(r->name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->comment) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->comment, ndr_charset_length(r->comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->path) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->path, ndr_charset_length(r->path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->password) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->password, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->password, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->password, ndr_charset_length(r->password, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareInfo2(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareInfo2 *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_name_0;
+ uint32_t _ptr_comment;
+ TALLOC_CTX *_mem_save_comment_0;
+ uint32_t _ptr_path;
+ TALLOC_CTX *_mem_save_path_0;
+ uint32_t _ptr_password;
+ TALLOC_CTX *_mem_save_password_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ NDR_CHECK(ndr_pull_srvsvc_ShareType(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_comment));
+ if (_ptr_comment) {
+ NDR_PULL_ALLOC(ndr, r->comment);
+ } else {
+ r->comment = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->permissions));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_users));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->current_users));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_path));
+ if (_ptr_path) {
+ NDR_PULL_ALLOC(ndr, r->path);
+ } else {
+ r->path = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password));
+ if (_ptr_password) {
+ NDR_PULL_ALLOC(ndr, r->password);
+ } else {
+ r->password = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->name));
+ if (ndr_get_array_length(ndr, &r->name) > ndr_get_array_size(ndr, &r->name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->name), ndr_get_array_length(ndr, &r->name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ if (r->comment) {
+ _mem_save_comment_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->comment, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->comment));
+ if (ndr_get_array_length(ndr, &r->comment) > ndr_get_array_size(ndr, &r->comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->comment), ndr_get_array_length(ndr, &r->comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->comment, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_comment_0, 0);
+ }
+ if (r->path) {
+ _mem_save_path_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->path, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->path));
+ if (ndr_get_array_length(ndr, &r->path) > ndr_get_array_size(ndr, &r->path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->path), ndr_get_array_length(ndr, &r->path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->path, ndr_get_array_length(ndr, &r->path), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_path_0, 0);
+ }
+ if (r->password) {
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->password, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->password));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->password));
+ if (ndr_get_array_length(ndr, &r->password) > ndr_get_array_size(ndr, &r->password)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->password), ndr_get_array_length(ndr, &r->password));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->password), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->password, ndr_get_array_length(ndr, &r->password), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo2 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareInfo2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_string(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ ndr_print_srvsvc_ShareType(ndr, "type", r->type);
+ ndr_print_ptr(ndr, "comment", r->comment);
+ ndr->depth++;
+ if (r->comment) {
+ ndr_print_string(ndr, "comment", r->comment);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "permissions", r->permissions);
+ ndr_print_uint32(ndr, "max_users", r->max_users);
+ ndr_print_uint32(ndr, "current_users", r->current_users);
+ ndr_print_ptr(ndr, "path", r->path);
+ ndr->depth++;
+ if (r->path) {
+ ndr_print_string(ndr, "path", r->path);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->password);
+ ndr->depth++;
+ if (r->password) {
+ ndr_print_string(ndr, "password", r->password);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareCtr2(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareCtr2 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo2(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo2(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareCtr2(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareCtr2 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo2(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo2(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr2 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetShareCtr2");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetShareInfo2(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareInfo501(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareInfo501 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ NDR_CHECK(ndr_push_srvsvc_ShareType(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->comment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->csc_policy));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, ndr_charset_length(r->name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->comment) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->comment, ndr_charset_length(r->comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareInfo501(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareInfo501 *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_name_0;
+ uint32_t _ptr_comment;
+ TALLOC_CTX *_mem_save_comment_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ NDR_CHECK(ndr_pull_srvsvc_ShareType(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_comment));
+ if (_ptr_comment) {
+ NDR_PULL_ALLOC(ndr, r->comment);
+ } else {
+ r->comment = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->csc_policy));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->name));
+ if (ndr_get_array_length(ndr, &r->name) > ndr_get_array_size(ndr, &r->name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->name), ndr_get_array_length(ndr, &r->name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ if (r->comment) {
+ _mem_save_comment_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->comment, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->comment));
+ if (ndr_get_array_length(ndr, &r->comment) > ndr_get_array_size(ndr, &r->comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->comment), ndr_get_array_length(ndr, &r->comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->comment, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_comment_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo501(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo501 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareInfo501");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_string(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ ndr_print_srvsvc_ShareType(ndr, "type", r->type);
+ ndr_print_ptr(ndr, "comment", r->comment);
+ ndr->depth++;
+ if (r->comment) {
+ ndr_print_string(ndr, "comment", r->comment);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "csc_policy", r->csc_policy);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareCtr501(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareCtr501 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo501(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo501(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareCtr501(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareCtr501 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo501(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo501(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr501(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr501 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetShareCtr501");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetShareInfo501(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareInfo502(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareInfo502 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ NDR_CHECK(ndr_push_srvsvc_ShareType(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->comment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->permissions));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_users));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->current_users));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->path));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->password));
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS, &r->sd_buf));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, ndr_charset_length(r->name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->comment) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->comment, ndr_charset_length(r->comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->path) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->path, ndr_charset_length(r->path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->password) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->password, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->password, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->password, ndr_charset_length(r->password, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_BUFFERS, &r->sd_buf));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareInfo502(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareInfo502 *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_name_0;
+ uint32_t _ptr_comment;
+ TALLOC_CTX *_mem_save_comment_0;
+ uint32_t _ptr_path;
+ TALLOC_CTX *_mem_save_path_0;
+ uint32_t _ptr_password;
+ TALLOC_CTX *_mem_save_password_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ NDR_CHECK(ndr_pull_srvsvc_ShareType(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_comment));
+ if (_ptr_comment) {
+ NDR_PULL_ALLOC(ndr, r->comment);
+ } else {
+ r->comment = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->permissions));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_users));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->current_users));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_path));
+ if (_ptr_path) {
+ NDR_PULL_ALLOC(ndr, r->path);
+ } else {
+ r->path = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password));
+ if (_ptr_password) {
+ NDR_PULL_ALLOC(ndr, r->password);
+ } else {
+ r->password = NULL;
+ }
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS, &r->sd_buf));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->name));
+ if (ndr_get_array_length(ndr, &r->name) > ndr_get_array_size(ndr, &r->name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->name), ndr_get_array_length(ndr, &r->name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ if (r->comment) {
+ _mem_save_comment_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->comment, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->comment));
+ if (ndr_get_array_length(ndr, &r->comment) > ndr_get_array_size(ndr, &r->comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->comment), ndr_get_array_length(ndr, &r->comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->comment, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_comment_0, 0);
+ }
+ if (r->path) {
+ _mem_save_path_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->path, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->path));
+ if (ndr_get_array_length(ndr, &r->path) > ndr_get_array_size(ndr, &r->path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->path), ndr_get_array_length(ndr, &r->path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->path, ndr_get_array_length(ndr, &r->path), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_path_0, 0);
+ }
+ if (r->password) {
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->password, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->password));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->password));
+ if (ndr_get_array_length(ndr, &r->password) > ndr_get_array_size(ndr, &r->password)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->password), ndr_get_array_length(ndr, &r->password));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->password), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->password, ndr_get_array_length(ndr, &r->password), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, 0);
+ }
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_BUFFERS, &r->sd_buf));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo502 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareInfo502");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_string(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ ndr_print_srvsvc_ShareType(ndr, "type", r->type);
+ ndr_print_ptr(ndr, "comment", r->comment);
+ ndr->depth++;
+ if (r->comment) {
+ ndr_print_string(ndr, "comment", r->comment);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "permissions", r->permissions);
+ ndr_print_uint32(ndr, "max_users", r->max_users);
+ ndr_print_uint32(ndr, "current_users", r->current_users);
+ ndr_print_ptr(ndr, "path", r->path);
+ ndr->depth++;
+ if (r->path) {
+ ndr_print_string(ndr, "path", r->path);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->password);
+ ndr->depth++;
+ if (r->password) {
+ ndr_print_string(ndr, "password", r->password);
+ }
+ ndr->depth--;
+ ndr_print_sec_desc_buf(ndr, "sd_buf", &r->sd_buf);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareCtr502(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareCtr502 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo502(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo502(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareCtr502(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareCtr502 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo502(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo502(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr502 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetShareCtr502");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetShareInfo502(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareInfo1004(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareInfo1004 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->comment) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->comment, ndr_charset_length(r->comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareInfo1004(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareInfo1004 *r)
+{
+ uint32_t _ptr_comment;
+ TALLOC_CTX *_mem_save_comment_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_comment));
+ if (_ptr_comment) {
+ NDR_PULL_ALLOC(ndr, r->comment);
+ } else {
+ r->comment = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->comment) {
+ _mem_save_comment_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->comment, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->comment));
+ if (ndr_get_array_length(ndr, &r->comment) > ndr_get_array_size(ndr, &r->comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->comment), ndr_get_array_length(ndr, &r->comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->comment, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_comment_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo1004(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo1004 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareInfo1004");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "comment", r->comment);
+ ndr->depth++;
+ if (r->comment) {
+ ndr_print_string(ndr, "comment", r->comment);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareCtr1004(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareCtr1004 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo1004(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo1004(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareCtr1004(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareCtr1004 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo1004(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo1004(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr1004(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1004 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetShareCtr1004");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetShareInfo1004(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_NetShareInfo1005Flags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_NetShareInfo1005Flags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_NetShareInfo1005Flags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SHARE_1005_IN_DFS", SHARE_1005_IN_DFS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SHARE_1005_DFS_ROOT", SHARE_1005_DFS_ROOT, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareInfo1005(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareInfo1005 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_NetShareInfo1005Flags(ndr, NDR_SCALARS, r->dfs_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareInfo1005(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareInfo1005 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_NetShareInfo1005Flags(ndr, NDR_SCALARS, &r->dfs_flags));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo1005(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo1005 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareInfo1005");
+ ndr->depth++;
+ ndr_print_NetShareInfo1005Flags(ndr, "dfs_flags", r->dfs_flags);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareCtr1005(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareCtr1005 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo1005(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareCtr1005(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareCtr1005 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo1005(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr1005(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1005 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetShareCtr1005");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetShareInfo1005(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareInfo1006(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareInfo1006 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_users));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareInfo1006(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareInfo1006 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_users));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo1006(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo1006 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareInfo1006");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "max_users", r->max_users);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareCtr1006(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareCtr1006 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo1006(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareCtr1006(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareCtr1006 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo1006(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr1006(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1006 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetShareCtr1006");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetShareInfo1006(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareInfo1007(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareInfo1007 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->alternate_directory_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->alternate_directory_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->alternate_directory_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->alternate_directory_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->alternate_directory_name, ndr_charset_length(r->alternate_directory_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareInfo1007(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareInfo1007 *r)
+{
+ uint32_t _ptr_alternate_directory_name;
+ TALLOC_CTX *_mem_save_alternate_directory_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_alternate_directory_name));
+ if (_ptr_alternate_directory_name) {
+ NDR_PULL_ALLOC(ndr, r->alternate_directory_name);
+ } else {
+ r->alternate_directory_name = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->alternate_directory_name) {
+ _mem_save_alternate_directory_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->alternate_directory_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->alternate_directory_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->alternate_directory_name));
+ if (ndr_get_array_length(ndr, &r->alternate_directory_name) > ndr_get_array_size(ndr, &r->alternate_directory_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->alternate_directory_name), ndr_get_array_length(ndr, &r->alternate_directory_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->alternate_directory_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->alternate_directory_name, ndr_get_array_length(ndr, &r->alternate_directory_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alternate_directory_name_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo1007(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo1007 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareInfo1007");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "flags", r->flags);
+ ndr_print_ptr(ndr, "alternate_directory_name", r->alternate_directory_name);
+ ndr->depth++;
+ if (r->alternate_directory_name) {
+ ndr_print_string(ndr, "alternate_directory_name", r->alternate_directory_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareCtr1007(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareCtr1007 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo1007(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo1007(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareCtr1007(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareCtr1007 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo1007(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo1007(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr1007(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1007 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetShareCtr1007");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetShareInfo1007(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareCtr1501(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareCtr1501 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareCtr1501(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareCtr1501 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr1501(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1501 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetShareCtr1501");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_sec_desc_buf(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareInfo(struct ndr_push *ndr, int ndr_flags, const union srvsvc_NetShareInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info0));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info2));
+ break; }
+
+ case 501: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info501));
+ break; }
+
+ case 502: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info502));
+ break; }
+
+ case 1004: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1004));
+ break; }
+
+ case 1005: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1005));
+ break; }
+
+ case 1006: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1006));
+ break; }
+
+ case 1007: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1007));
+ break; }
+
+ case 1501: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1501));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ if (r->info0) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo0(ndr, NDR_SCALARS|NDR_BUFFERS, r->info0));
+ }
+ break;
+
+ case 1:
+ if (r->info1) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ }
+ break;
+
+ case 2:
+ if (r->info2) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo2(ndr, NDR_SCALARS|NDR_BUFFERS, r->info2));
+ }
+ break;
+
+ case 501:
+ if (r->info501) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo501(ndr, NDR_SCALARS|NDR_BUFFERS, r->info501));
+ }
+ break;
+
+ case 502:
+ if (r->info502) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo502(ndr, NDR_SCALARS|NDR_BUFFERS, r->info502));
+ }
+ break;
+
+ case 1004:
+ if (r->info1004) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo1004(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1004));
+ }
+ break;
+
+ case 1005:
+ if (r->info1005) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo1005(ndr, NDR_SCALARS, r->info1005));
+ }
+ break;
+
+ case 1006:
+ if (r->info1006) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo1006(ndr, NDR_SCALARS, r->info1006));
+ }
+ break;
+
+ case 1007:
+ if (r->info1007) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo1007(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1007));
+ }
+ break;
+
+ case 1501:
+ if (r->info1501) {
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1501));
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareInfo(struct ndr_pull *ndr, int ndr_flags, union srvsvc_NetShareInfo *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_info0_0;
+ TALLOC_CTX *_mem_save_info1_0;
+ TALLOC_CTX *_mem_save_info2_0;
+ TALLOC_CTX *_mem_save_info501_0;
+ TALLOC_CTX *_mem_save_info502_0;
+ TALLOC_CTX *_mem_save_info1004_0;
+ TALLOC_CTX *_mem_save_info1005_0;
+ TALLOC_CTX *_mem_save_info1006_0;
+ TALLOC_CTX *_mem_save_info1007_0;
+ TALLOC_CTX *_mem_save_info1501_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 0: {
+ uint32_t _ptr_info0;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info0));
+ if (_ptr_info0) {
+ NDR_PULL_ALLOC(ndr, r->info0);
+ } else {
+ r->info0 = NULL;
+ }
+ break; }
+
+ case 1: {
+ uint32_t _ptr_info1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1));
+ if (_ptr_info1) {
+ NDR_PULL_ALLOC(ndr, r->info1);
+ } else {
+ r->info1 = NULL;
+ }
+ break; }
+
+ case 2: {
+ uint32_t _ptr_info2;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info2));
+ if (_ptr_info2) {
+ NDR_PULL_ALLOC(ndr, r->info2);
+ } else {
+ r->info2 = NULL;
+ }
+ break; }
+
+ case 501: {
+ uint32_t _ptr_info501;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info501));
+ if (_ptr_info501) {
+ NDR_PULL_ALLOC(ndr, r->info501);
+ } else {
+ r->info501 = NULL;
+ }
+ break; }
+
+ case 502: {
+ uint32_t _ptr_info502;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info502));
+ if (_ptr_info502) {
+ NDR_PULL_ALLOC(ndr, r->info502);
+ } else {
+ r->info502 = NULL;
+ }
+ break; }
+
+ case 1004: {
+ uint32_t _ptr_info1004;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1004));
+ if (_ptr_info1004) {
+ NDR_PULL_ALLOC(ndr, r->info1004);
+ } else {
+ r->info1004 = NULL;
+ }
+ break; }
+
+ case 1005: {
+ uint32_t _ptr_info1005;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1005));
+ if (_ptr_info1005) {
+ NDR_PULL_ALLOC(ndr, r->info1005);
+ } else {
+ r->info1005 = NULL;
+ }
+ break; }
+
+ case 1006: {
+ uint32_t _ptr_info1006;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1006));
+ if (_ptr_info1006) {
+ NDR_PULL_ALLOC(ndr, r->info1006);
+ } else {
+ r->info1006 = NULL;
+ }
+ break; }
+
+ case 1007: {
+ uint32_t _ptr_info1007;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1007));
+ if (_ptr_info1007) {
+ NDR_PULL_ALLOC(ndr, r->info1007);
+ } else {
+ r->info1007 = NULL;
+ }
+ break; }
+
+ case 1501: {
+ uint32_t _ptr_info1501;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1501));
+ if (_ptr_info1501) {
+ NDR_PULL_ALLOC(ndr, r->info1501);
+ } else {
+ r->info1501 = NULL;
+ }
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ if (r->info0) {
+ _mem_save_info0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info0, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo0(ndr, NDR_SCALARS|NDR_BUFFERS, r->info0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info0_0, 0);
+ }
+ break;
+
+ case 1:
+ if (r->info1) {
+ _mem_save_info1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1_0, 0);
+ }
+ break;
+
+ case 2:
+ if (r->info2) {
+ _mem_save_info2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info2, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo2(ndr, NDR_SCALARS|NDR_BUFFERS, r->info2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info2_0, 0);
+ }
+ break;
+
+ case 501:
+ if (r->info501) {
+ _mem_save_info501_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info501, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo501(ndr, NDR_SCALARS|NDR_BUFFERS, r->info501));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info501_0, 0);
+ }
+ break;
+
+ case 502:
+ if (r->info502) {
+ _mem_save_info502_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info502, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo502(ndr, NDR_SCALARS|NDR_BUFFERS, r->info502));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info502_0, 0);
+ }
+ break;
+
+ case 1004:
+ if (r->info1004) {
+ _mem_save_info1004_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1004, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo1004(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1004));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1004_0, 0);
+ }
+ break;
+
+ case 1005:
+ if (r->info1005) {
+ _mem_save_info1005_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1005, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo1005(ndr, NDR_SCALARS, r->info1005));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1005_0, 0);
+ }
+ break;
+
+ case 1006:
+ if (r->info1006) {
+ _mem_save_info1006_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1006, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo1006(ndr, NDR_SCALARS, r->info1006));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1006_0, 0);
+ }
+ break;
+
+ case 1007:
+ if (r->info1007) {
+ _mem_save_info1007_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1007, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo1007(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1007));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1007_0, 0);
+ }
+ break;
+
+ case 1501:
+ if (r->info1501) {
+ _mem_save_info1501_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1501, 0);
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1501));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1501_0, 0);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetShareInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "srvsvc_NetShareInfo");
+ switch (level) {
+ case 0:
+ ndr_print_ptr(ndr, "info0", r->info0);
+ ndr->depth++;
+ if (r->info0) {
+ ndr_print_srvsvc_NetShareInfo0(ndr, "info0", r->info0);
+ }
+ ndr->depth--;
+ break;
+
+ case 1:
+ ndr_print_ptr(ndr, "info1", r->info1);
+ ndr->depth++;
+ if (r->info1) {
+ ndr_print_srvsvc_NetShareInfo1(ndr, "info1", r->info1);
+ }
+ ndr->depth--;
+ break;
+
+ case 2:
+ ndr_print_ptr(ndr, "info2", r->info2);
+ ndr->depth++;
+ if (r->info2) {
+ ndr_print_srvsvc_NetShareInfo2(ndr, "info2", r->info2);
+ }
+ ndr->depth--;
+ break;
+
+ case 501:
+ ndr_print_ptr(ndr, "info501", r->info501);
+ ndr->depth++;
+ if (r->info501) {
+ ndr_print_srvsvc_NetShareInfo501(ndr, "info501", r->info501);
+ }
+ ndr->depth--;
+ break;
+
+ case 502:
+ ndr_print_ptr(ndr, "info502", r->info502);
+ ndr->depth++;
+ if (r->info502) {
+ ndr_print_srvsvc_NetShareInfo502(ndr, "info502", r->info502);
+ }
+ ndr->depth--;
+ break;
+
+ case 1004:
+ ndr_print_ptr(ndr, "info1004", r->info1004);
+ ndr->depth++;
+ if (r->info1004) {
+ ndr_print_srvsvc_NetShareInfo1004(ndr, "info1004", r->info1004);
+ }
+ ndr->depth--;
+ break;
+
+ case 1005:
+ ndr_print_ptr(ndr, "info1005", r->info1005);
+ ndr->depth++;
+ if (r->info1005) {
+ ndr_print_srvsvc_NetShareInfo1005(ndr, "info1005", r->info1005);
+ }
+ ndr->depth--;
+ break;
+
+ case 1006:
+ ndr_print_ptr(ndr, "info1006", r->info1006);
+ ndr->depth++;
+ if (r->info1006) {
+ ndr_print_srvsvc_NetShareInfo1006(ndr, "info1006", r->info1006);
+ }
+ ndr->depth--;
+ break;
+
+ case 1007:
+ ndr_print_ptr(ndr, "info1007", r->info1007);
+ ndr->depth++;
+ if (r->info1007) {
+ ndr_print_srvsvc_NetShareInfo1007(ndr, "info1007", r->info1007);
+ }
+ ndr->depth--;
+ break;
+
+ case 1501:
+ ndr_print_ptr(ndr, "info1501", r->info1501);
+ ndr->depth++;
+ if (r->info1501) {
+ ndr_print_sec_desc_buf(ndr, "info1501", r->info1501);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareCtr(struct ndr_push *ndr, int ndr_flags, const union srvsvc_NetShareCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr0));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr2));
+ break; }
+
+ case 501: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr501));
+ break; }
+
+ case 502: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr502));
+ break; }
+
+ case 1004: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr1004));
+ break; }
+
+ case 1005: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr1005));
+ break; }
+
+ case 1006: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr1006));
+ break; }
+
+ case 1007: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr1007));
+ break; }
+
+ case 1501: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr1501));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ if (r->ctr0) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr0));
+ }
+ break;
+
+ case 1:
+ if (r->ctr1) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ }
+ break;
+
+ case 2:
+ if (r->ctr2) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareCtr2(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr2));
+ }
+ break;
+
+ case 501:
+ if (r->ctr501) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareCtr501(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr501));
+ }
+ break;
+
+ case 502:
+ if (r->ctr502) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareCtr502(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr502));
+ }
+ break;
+
+ case 1004:
+ if (r->ctr1004) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareCtr1004(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1004));
+ }
+ break;
+
+ case 1005:
+ if (r->ctr1005) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareCtr1005(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1005));
+ }
+ break;
+
+ case 1006:
+ if (r->ctr1006) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareCtr1006(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1006));
+ }
+ break;
+
+ case 1007:
+ if (r->ctr1007) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareCtr1007(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1007));
+ }
+ break;
+
+ case 1501:
+ if (r->ctr1501) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareCtr1501(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1501));
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareCtr(struct ndr_pull *ndr, int ndr_flags, union srvsvc_NetShareCtr *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_ctr0_0;
+ TALLOC_CTX *_mem_save_ctr1_0;
+ TALLOC_CTX *_mem_save_ctr2_0;
+ TALLOC_CTX *_mem_save_ctr501_0;
+ TALLOC_CTX *_mem_save_ctr502_0;
+ TALLOC_CTX *_mem_save_ctr1004_0;
+ TALLOC_CTX *_mem_save_ctr1005_0;
+ TALLOC_CTX *_mem_save_ctr1006_0;
+ TALLOC_CTX *_mem_save_ctr1007_0;
+ TALLOC_CTX *_mem_save_ctr1501_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 0: {
+ uint32_t _ptr_ctr0;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr0));
+ if (_ptr_ctr0) {
+ NDR_PULL_ALLOC(ndr, r->ctr0);
+ } else {
+ r->ctr0 = NULL;
+ }
+ break; }
+
+ case 1: {
+ uint32_t _ptr_ctr1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr1));
+ if (_ptr_ctr1) {
+ NDR_PULL_ALLOC(ndr, r->ctr1);
+ } else {
+ r->ctr1 = NULL;
+ }
+ break; }
+
+ case 2: {
+ uint32_t _ptr_ctr2;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr2));
+ if (_ptr_ctr2) {
+ NDR_PULL_ALLOC(ndr, r->ctr2);
+ } else {
+ r->ctr2 = NULL;
+ }
+ break; }
+
+ case 501: {
+ uint32_t _ptr_ctr501;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr501));
+ if (_ptr_ctr501) {
+ NDR_PULL_ALLOC(ndr, r->ctr501);
+ } else {
+ r->ctr501 = NULL;
+ }
+ break; }
+
+ case 502: {
+ uint32_t _ptr_ctr502;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr502));
+ if (_ptr_ctr502) {
+ NDR_PULL_ALLOC(ndr, r->ctr502);
+ } else {
+ r->ctr502 = NULL;
+ }
+ break; }
+
+ case 1004: {
+ uint32_t _ptr_ctr1004;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr1004));
+ if (_ptr_ctr1004) {
+ NDR_PULL_ALLOC(ndr, r->ctr1004);
+ } else {
+ r->ctr1004 = NULL;
+ }
+ break; }
+
+ case 1005: {
+ uint32_t _ptr_ctr1005;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr1005));
+ if (_ptr_ctr1005) {
+ NDR_PULL_ALLOC(ndr, r->ctr1005);
+ } else {
+ r->ctr1005 = NULL;
+ }
+ break; }
+
+ case 1006: {
+ uint32_t _ptr_ctr1006;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr1006));
+ if (_ptr_ctr1006) {
+ NDR_PULL_ALLOC(ndr, r->ctr1006);
+ } else {
+ r->ctr1006 = NULL;
+ }
+ break; }
+
+ case 1007: {
+ uint32_t _ptr_ctr1007;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr1007));
+ if (_ptr_ctr1007) {
+ NDR_PULL_ALLOC(ndr, r->ctr1007);
+ } else {
+ r->ctr1007 = NULL;
+ }
+ break; }
+
+ case 1501: {
+ uint32_t _ptr_ctr1501;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr1501));
+ if (_ptr_ctr1501) {
+ NDR_PULL_ALLOC(ndr, r->ctr1501);
+ } else {
+ r->ctr1501 = NULL;
+ }
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ if (r->ctr0) {
+ _mem_save_ctr0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr0, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr0_0, 0);
+ }
+ break;
+
+ case 1:
+ if (r->ctr1) {
+ _mem_save_ctr1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr1, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr1_0, 0);
+ }
+ break;
+
+ case 2:
+ if (r->ctr2) {
+ _mem_save_ctr2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr2, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareCtr2(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr2_0, 0);
+ }
+ break;
+
+ case 501:
+ if (r->ctr501) {
+ _mem_save_ctr501_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr501, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareCtr501(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr501));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr501_0, 0);
+ }
+ break;
+
+ case 502:
+ if (r->ctr502) {
+ _mem_save_ctr502_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr502, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareCtr502(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr502));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr502_0, 0);
+ }
+ break;
+
+ case 1004:
+ if (r->ctr1004) {
+ _mem_save_ctr1004_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr1004, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareCtr1004(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1004));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr1004_0, 0);
+ }
+ break;
+
+ case 1005:
+ if (r->ctr1005) {
+ _mem_save_ctr1005_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr1005, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareCtr1005(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1005));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr1005_0, 0);
+ }
+ break;
+
+ case 1006:
+ if (r->ctr1006) {
+ _mem_save_ctr1006_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr1006, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareCtr1006(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1006));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr1006_0, 0);
+ }
+ break;
+
+ case 1007:
+ if (r->ctr1007) {
+ _mem_save_ctr1007_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr1007, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareCtr1007(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1007));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr1007_0, 0);
+ }
+ break;
+
+ case 1501:
+ if (r->ctr1501) {
+ _mem_save_ctr1501_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr1501, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareCtr1501(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1501));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr1501_0, 0);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetShareCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "srvsvc_NetShareCtr");
+ switch (level) {
+ case 0:
+ ndr_print_ptr(ndr, "ctr0", r->ctr0);
+ ndr->depth++;
+ if (r->ctr0) {
+ ndr_print_srvsvc_NetShareCtr0(ndr, "ctr0", r->ctr0);
+ }
+ ndr->depth--;
+ break;
+
+ case 1:
+ ndr_print_ptr(ndr, "ctr1", r->ctr1);
+ ndr->depth++;
+ if (r->ctr1) {
+ ndr_print_srvsvc_NetShareCtr1(ndr, "ctr1", r->ctr1);
+ }
+ ndr->depth--;
+ break;
+
+ case 2:
+ ndr_print_ptr(ndr, "ctr2", r->ctr2);
+ ndr->depth++;
+ if (r->ctr2) {
+ ndr_print_srvsvc_NetShareCtr2(ndr, "ctr2", r->ctr2);
+ }
+ ndr->depth--;
+ break;
+
+ case 501:
+ ndr_print_ptr(ndr, "ctr501", r->ctr501);
+ ndr->depth++;
+ if (r->ctr501) {
+ ndr_print_srvsvc_NetShareCtr501(ndr, "ctr501", r->ctr501);
+ }
+ ndr->depth--;
+ break;
+
+ case 502:
+ ndr_print_ptr(ndr, "ctr502", r->ctr502);
+ ndr->depth++;
+ if (r->ctr502) {
+ ndr_print_srvsvc_NetShareCtr502(ndr, "ctr502", r->ctr502);
+ }
+ ndr->depth--;
+ break;
+
+ case 1004:
+ ndr_print_ptr(ndr, "ctr1004", r->ctr1004);
+ ndr->depth++;
+ if (r->ctr1004) {
+ ndr_print_srvsvc_NetShareCtr1004(ndr, "ctr1004", r->ctr1004);
+ }
+ ndr->depth--;
+ break;
+
+ case 1005:
+ ndr_print_ptr(ndr, "ctr1005", r->ctr1005);
+ ndr->depth++;
+ if (r->ctr1005) {
+ ndr_print_srvsvc_NetShareCtr1005(ndr, "ctr1005", r->ctr1005);
+ }
+ ndr->depth--;
+ break;
+
+ case 1006:
+ ndr_print_ptr(ndr, "ctr1006", r->ctr1006);
+ ndr->depth++;
+ if (r->ctr1006) {
+ ndr_print_srvsvc_NetShareCtr1006(ndr, "ctr1006", r->ctr1006);
+ }
+ ndr->depth--;
+ break;
+
+ case 1007:
+ ndr_print_ptr(ndr, "ctr1007", r->ctr1007);
+ ndr->depth++;
+ if (r->ctr1007) {
+ ndr_print_srvsvc_NetShareCtr1007(ndr, "ctr1007", r->ctr1007);
+ }
+ ndr->depth--;
+ break;
+
+ case 1501:
+ ndr_print_ptr(ndr, "ctr1501", r->ctr1501);
+ ndr->depth++;
+ if (r->ctr1501) {
+ ndr_print_srvsvc_NetShareCtr1501(ndr, "ctr1501", r->ctr1501);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareInfoCtr(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetShareInfoCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->ctr, r->level));
+ NDR_CHECK(ndr_push_srvsvc_NetShareCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_srvsvc_NetShareCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareInfoCtr(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetShareInfoCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->ctr, r->level));
+ NDR_CHECK(ndr_pull_srvsvc_NetShareCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_srvsvc_NetShareCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareInfoCtr(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfoCtr *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareInfoCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level", r->level);
+ ndr_print_set_switch_value(ndr, &r->ctr, r->level);
+ ndr_print_srvsvc_NetShareCtr(ndr, "ctr", &r->ctr);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_srvsvc_PlatformId(struct ndr_push *ndr, int ndr_flags, enum srvsvc_PlatformId r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_srvsvc_PlatformId(struct ndr_pull *ndr, int ndr_flags, enum srvsvc_PlatformId *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_PlatformId(struct ndr_print *ndr, const char *name, enum srvsvc_PlatformId r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case PLATFORM_ID_DOS: val = "PLATFORM_ID_DOS"; break;
+ case PLATFORM_ID_OS2: val = "PLATFORM_ID_OS2"; break;
+ case PLATFORM_ID_NT: val = "PLATFORM_ID_NT"; break;
+ case PLATFORM_ID_OSF: val = "PLATFORM_ID_OSF"; break;
+ case PLATFORM_ID_VMS: val = "PLATFORM_ID_VMS"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo100(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo100 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_srvsvc_PlatformId(ndr, NDR_SCALARS, r->platform_id));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->server_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->server_name, ndr_charset_length(r->server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo100(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo100 *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_srvsvc_PlatformId(ndr, NDR_SCALARS, &r->platform_id));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->server_name);
+ } else {
+ r->server_name = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->server_name));
+ if (ndr_get_array_length(ndr, &r->server_name) > ndr_get_array_size(ndr, &r->server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->server_name), ndr_get_array_length(ndr, &r->server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->server_name, ndr_get_array_length(ndr, &r->server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo100(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo100 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo100");
+ ndr->depth++;
+ ndr_print_srvsvc_PlatformId(ndr, "platform_id", r->platform_id);
+ ndr_print_ptr(ndr, "server_name", r->server_name);
+ ndr->depth++;
+ if (r->server_name) {
+ ndr_print_string(ndr, "server_name", r->server_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo101(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo101 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_srvsvc_PlatformId(ndr, NDR_SCALARS, r->platform_id));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->server_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version_major));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version_minor));
+ NDR_CHECK(ndr_push_svcctl_ServerType(ndr, NDR_SCALARS, r->server_type));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->server_name, ndr_charset_length(r->server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->comment) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->comment, ndr_charset_length(r->comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo101(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo101 *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ uint32_t _ptr_comment;
+ TALLOC_CTX *_mem_save_comment_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_srvsvc_PlatformId(ndr, NDR_SCALARS, &r->platform_id));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->server_name);
+ } else {
+ r->server_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version_major));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version_minor));
+ NDR_CHECK(ndr_pull_svcctl_ServerType(ndr, NDR_SCALARS, &r->server_type));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_comment));
+ if (_ptr_comment) {
+ NDR_PULL_ALLOC(ndr, r->comment);
+ } else {
+ r->comment = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->server_name));
+ if (ndr_get_array_length(ndr, &r->server_name) > ndr_get_array_size(ndr, &r->server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->server_name), ndr_get_array_length(ndr, &r->server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->server_name, ndr_get_array_length(ndr, &r->server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ if (r->comment) {
+ _mem_save_comment_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->comment, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->comment));
+ if (ndr_get_array_length(ndr, &r->comment) > ndr_get_array_size(ndr, &r->comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->comment), ndr_get_array_length(ndr, &r->comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->comment, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_comment_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo101(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo101 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo101");
+ ndr->depth++;
+ ndr_print_srvsvc_PlatformId(ndr, "platform_id", r->platform_id);
+ ndr_print_ptr(ndr, "server_name", r->server_name);
+ ndr->depth++;
+ if (r->server_name) {
+ ndr_print_string(ndr, "server_name", r->server_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "version_major", r->version_major);
+ ndr_print_uint32(ndr, "version_minor", r->version_minor);
+ ndr_print_svcctl_ServerType(ndr, "server_type", r->server_type);
+ ndr_print_ptr(ndr, "comment", r->comment);
+ ndr->depth++;
+ if (r->comment) {
+ ndr_print_string(ndr, "comment", r->comment);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo102(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo102 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_srvsvc_PlatformId(ndr, NDR_SCALARS, r->platform_id));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->server_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version_major));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version_minor));
+ NDR_CHECK(ndr_push_svcctl_ServerType(ndr, NDR_SCALARS, r->server_type));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->comment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->users));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->disc));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->hidden));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->announce));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->anndelta));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->licenses));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->userpath));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->server_name, ndr_charset_length(r->server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->comment) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->comment, ndr_charset_length(r->comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->userpath) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->userpath, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->userpath, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->userpath, ndr_charset_length(r->userpath, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo102(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo102 *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ uint32_t _ptr_comment;
+ TALLOC_CTX *_mem_save_comment_0;
+ uint32_t _ptr_userpath;
+ TALLOC_CTX *_mem_save_userpath_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_srvsvc_PlatformId(ndr, NDR_SCALARS, &r->platform_id));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->server_name);
+ } else {
+ r->server_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version_major));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version_minor));
+ NDR_CHECK(ndr_pull_svcctl_ServerType(ndr, NDR_SCALARS, &r->server_type));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_comment));
+ if (_ptr_comment) {
+ NDR_PULL_ALLOC(ndr, r->comment);
+ } else {
+ r->comment = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->users));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->disc));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->hidden));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->announce));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->anndelta));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->licenses));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_userpath));
+ if (_ptr_userpath) {
+ NDR_PULL_ALLOC(ndr, r->userpath);
+ } else {
+ r->userpath = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->server_name));
+ if (ndr_get_array_length(ndr, &r->server_name) > ndr_get_array_size(ndr, &r->server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->server_name), ndr_get_array_length(ndr, &r->server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->server_name, ndr_get_array_length(ndr, &r->server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ if (r->comment) {
+ _mem_save_comment_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->comment, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->comment));
+ if (ndr_get_array_length(ndr, &r->comment) > ndr_get_array_size(ndr, &r->comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->comment), ndr_get_array_length(ndr, &r->comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->comment, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_comment_0, 0);
+ }
+ if (r->userpath) {
+ _mem_save_userpath_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->userpath, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->userpath));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->userpath));
+ if (ndr_get_array_length(ndr, &r->userpath) > ndr_get_array_size(ndr, &r->userpath)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->userpath), ndr_get_array_length(ndr, &r->userpath));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->userpath), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->userpath, ndr_get_array_length(ndr, &r->userpath), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_userpath_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo102(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo102 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo102");
+ ndr->depth++;
+ ndr_print_srvsvc_PlatformId(ndr, "platform_id", r->platform_id);
+ ndr_print_ptr(ndr, "server_name", r->server_name);
+ ndr->depth++;
+ if (r->server_name) {
+ ndr_print_string(ndr, "server_name", r->server_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "version_major", r->version_major);
+ ndr_print_uint32(ndr, "version_minor", r->version_minor);
+ ndr_print_svcctl_ServerType(ndr, "server_type", r->server_type);
+ ndr_print_ptr(ndr, "comment", r->comment);
+ ndr->depth++;
+ if (r->comment) {
+ ndr_print_string(ndr, "comment", r->comment);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "users", r->users);
+ ndr_print_uint32(ndr, "disc", r->disc);
+ ndr_print_uint32(ndr, "hidden", r->hidden);
+ ndr_print_uint32(ndr, "announce", r->announce);
+ ndr_print_uint32(ndr, "anndelta", r->anndelta);
+ ndr_print_uint32(ndr, "licenses", r->licenses);
+ ndr_print_ptr(ndr, "userpath", r->userpath);
+ ndr->depth++;
+ if (r->userpath) {
+ ndr_print_string(ndr, "userpath", r->userpath);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo402(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo402 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ulist_mtime));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->glist_mtime));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->alist_mtime));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->alerts));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->security));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->numadmin));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->lanmask));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->guestaccount));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->chdevs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->chdevqs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->chdevjobs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->connections));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->shares));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->openfiles));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sessopen));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sesssvc));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sessreqs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->opensearch));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->activelocks));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sizereqbufs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->numbigbufs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->numfiletasks));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->alertsched));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->erroralert));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->logonalert));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->accessalert));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->diskalert));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->netioalert));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxaudits));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->srvheuristics));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->alerts) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->alerts, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->alerts, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->alerts, ndr_charset_length(r->alerts, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->guestaccount) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->guestaccount, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->guestaccount, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->guestaccount, ndr_charset_length(r->guestaccount, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->srvheuristics) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->srvheuristics, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->srvheuristics, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->srvheuristics, ndr_charset_length(r->srvheuristics, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo402(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo402 *r)
+{
+ uint32_t _ptr_alerts;
+ TALLOC_CTX *_mem_save_alerts_0;
+ uint32_t _ptr_guestaccount;
+ TALLOC_CTX *_mem_save_guestaccount_0;
+ uint32_t _ptr_srvheuristics;
+ TALLOC_CTX *_mem_save_srvheuristics_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->ulist_mtime));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->glist_mtime));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->alist_mtime));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_alerts));
+ if (_ptr_alerts) {
+ NDR_PULL_ALLOC(ndr, r->alerts);
+ } else {
+ r->alerts = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->security));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->numadmin));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->lanmask));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_guestaccount));
+ if (_ptr_guestaccount) {
+ NDR_PULL_ALLOC(ndr, r->guestaccount);
+ } else {
+ r->guestaccount = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->chdevs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->chdevqs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->chdevjobs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->connections));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->shares));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->openfiles));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sessopen));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sesssvc));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sessreqs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->opensearch));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->activelocks));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sizereqbufs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->numbigbufs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->numfiletasks));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->alertsched));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->erroralert));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->logonalert));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->accessalert));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->diskalert));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->netioalert));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxaudits));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_srvheuristics));
+ if (_ptr_srvheuristics) {
+ NDR_PULL_ALLOC(ndr, r->srvheuristics);
+ } else {
+ r->srvheuristics = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->alerts) {
+ _mem_save_alerts_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->alerts, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->alerts));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->alerts));
+ if (ndr_get_array_length(ndr, &r->alerts) > ndr_get_array_size(ndr, &r->alerts)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->alerts), ndr_get_array_length(ndr, &r->alerts));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->alerts), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->alerts, ndr_get_array_length(ndr, &r->alerts), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alerts_0, 0);
+ }
+ if (r->guestaccount) {
+ _mem_save_guestaccount_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->guestaccount, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->guestaccount));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->guestaccount));
+ if (ndr_get_array_length(ndr, &r->guestaccount) > ndr_get_array_size(ndr, &r->guestaccount)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->guestaccount), ndr_get_array_length(ndr, &r->guestaccount));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->guestaccount), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->guestaccount, ndr_get_array_length(ndr, &r->guestaccount), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_guestaccount_0, 0);
+ }
+ if (r->srvheuristics) {
+ _mem_save_srvheuristics_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->srvheuristics, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->srvheuristics));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->srvheuristics));
+ if (ndr_get_array_length(ndr, &r->srvheuristics) > ndr_get_array_size(ndr, &r->srvheuristics)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->srvheuristics), ndr_get_array_length(ndr, &r->srvheuristics));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->srvheuristics), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->srvheuristics, ndr_get_array_length(ndr, &r->srvheuristics), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_srvheuristics_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo402(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo402 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo402");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "ulist_mtime", r->ulist_mtime);
+ ndr_print_uint32(ndr, "glist_mtime", r->glist_mtime);
+ ndr_print_uint32(ndr, "alist_mtime", r->alist_mtime);
+ ndr_print_ptr(ndr, "alerts", r->alerts);
+ ndr->depth++;
+ if (r->alerts) {
+ ndr_print_string(ndr, "alerts", r->alerts);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "security", r->security);
+ ndr_print_uint32(ndr, "numadmin", r->numadmin);
+ ndr_print_uint32(ndr, "lanmask", r->lanmask);
+ ndr_print_ptr(ndr, "guestaccount", r->guestaccount);
+ ndr->depth++;
+ if (r->guestaccount) {
+ ndr_print_string(ndr, "guestaccount", r->guestaccount);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "chdevs", r->chdevs);
+ ndr_print_uint32(ndr, "chdevqs", r->chdevqs);
+ ndr_print_uint32(ndr, "chdevjobs", r->chdevjobs);
+ ndr_print_uint32(ndr, "connections", r->connections);
+ ndr_print_uint32(ndr, "shares", r->shares);
+ ndr_print_uint32(ndr, "openfiles", r->openfiles);
+ ndr_print_uint32(ndr, "sessopen", r->sessopen);
+ ndr_print_uint32(ndr, "sesssvc", r->sesssvc);
+ ndr_print_uint32(ndr, "sessreqs", r->sessreqs);
+ ndr_print_uint32(ndr, "opensearch", r->opensearch);
+ ndr_print_uint32(ndr, "activelocks", r->activelocks);
+ ndr_print_uint32(ndr, "sizereqbufs", r->sizereqbufs);
+ ndr_print_uint32(ndr, "numbigbufs", r->numbigbufs);
+ ndr_print_uint32(ndr, "numfiletasks", r->numfiletasks);
+ ndr_print_uint32(ndr, "alertsched", r->alertsched);
+ ndr_print_uint32(ndr, "erroralert", r->erroralert);
+ ndr_print_uint32(ndr, "logonalert", r->logonalert);
+ ndr_print_uint32(ndr, "accessalert", r->accessalert);
+ ndr_print_uint32(ndr, "diskalert", r->diskalert);
+ ndr_print_uint32(ndr, "netioalert", r->netioalert);
+ ndr_print_uint32(ndr, "maxaudits", r->maxaudits);
+ ndr_print_ptr(ndr, "srvheuristics", r->srvheuristics);
+ ndr->depth++;
+ if (r->srvheuristics) {
+ ndr_print_string(ndr, "srvheuristics", r->srvheuristics);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo403(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo403 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ulist_mtime));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->glist_mtime));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->alist_mtime));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->alerts));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->security));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->numadmin));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->lanmask));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->guestaccount));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->chdevs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->chdevqs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->chdevjobs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->connections));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->shares));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->openfiles));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sessopen));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sesssvc));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sessreqs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->opensearch));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->activelocks));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sizereqbufs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->numbigbufs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->numfiletasks));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->alertsched));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->eroralert));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->logonalert));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->accessalert));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->diskalert));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->netioalert));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxaudits));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->srvheuristics));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->auditedevents));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->auditprofile));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->autopath));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->alerts) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->alerts, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->alerts, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->alerts, ndr_charset_length(r->alerts, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->guestaccount) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->guestaccount, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->guestaccount, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->guestaccount, ndr_charset_length(r->guestaccount, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->srvheuristics) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->srvheuristics, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->srvheuristics, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->srvheuristics, ndr_charset_length(r->srvheuristics, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->autopath) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->autopath, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->autopath, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->autopath, ndr_charset_length(r->autopath, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo403(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo403 *r)
+{
+ uint32_t _ptr_alerts;
+ TALLOC_CTX *_mem_save_alerts_0;
+ uint32_t _ptr_guestaccount;
+ TALLOC_CTX *_mem_save_guestaccount_0;
+ uint32_t _ptr_srvheuristics;
+ TALLOC_CTX *_mem_save_srvheuristics_0;
+ uint32_t _ptr_autopath;
+ TALLOC_CTX *_mem_save_autopath_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->ulist_mtime));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->glist_mtime));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->alist_mtime));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_alerts));
+ if (_ptr_alerts) {
+ NDR_PULL_ALLOC(ndr, r->alerts);
+ } else {
+ r->alerts = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->security));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->numadmin));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->lanmask));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_guestaccount));
+ if (_ptr_guestaccount) {
+ NDR_PULL_ALLOC(ndr, r->guestaccount);
+ } else {
+ r->guestaccount = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->chdevs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->chdevqs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->chdevjobs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->connections));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->shares));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->openfiles));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sessopen));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sesssvc));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sessreqs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->opensearch));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->activelocks));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sizereqbufs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->numbigbufs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->numfiletasks));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->alertsched));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->eroralert));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->logonalert));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->accessalert));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->diskalert));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->netioalert));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxaudits));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_srvheuristics));
+ if (_ptr_srvheuristics) {
+ NDR_PULL_ALLOC(ndr, r->srvheuristics);
+ } else {
+ r->srvheuristics = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->auditedevents));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->auditprofile));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_autopath));
+ if (_ptr_autopath) {
+ NDR_PULL_ALLOC(ndr, r->autopath);
+ } else {
+ r->autopath = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->alerts) {
+ _mem_save_alerts_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->alerts, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->alerts));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->alerts));
+ if (ndr_get_array_length(ndr, &r->alerts) > ndr_get_array_size(ndr, &r->alerts)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->alerts), ndr_get_array_length(ndr, &r->alerts));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->alerts), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->alerts, ndr_get_array_length(ndr, &r->alerts), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_alerts_0, 0);
+ }
+ if (r->guestaccount) {
+ _mem_save_guestaccount_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->guestaccount, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->guestaccount));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->guestaccount));
+ if (ndr_get_array_length(ndr, &r->guestaccount) > ndr_get_array_size(ndr, &r->guestaccount)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->guestaccount), ndr_get_array_length(ndr, &r->guestaccount));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->guestaccount), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->guestaccount, ndr_get_array_length(ndr, &r->guestaccount), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_guestaccount_0, 0);
+ }
+ if (r->srvheuristics) {
+ _mem_save_srvheuristics_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->srvheuristics, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->srvheuristics));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->srvheuristics));
+ if (ndr_get_array_length(ndr, &r->srvheuristics) > ndr_get_array_size(ndr, &r->srvheuristics)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->srvheuristics), ndr_get_array_length(ndr, &r->srvheuristics));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->srvheuristics), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->srvheuristics, ndr_get_array_length(ndr, &r->srvheuristics), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_srvheuristics_0, 0);
+ }
+ if (r->autopath) {
+ _mem_save_autopath_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->autopath, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->autopath));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->autopath));
+ if (ndr_get_array_length(ndr, &r->autopath) > ndr_get_array_size(ndr, &r->autopath)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->autopath), ndr_get_array_length(ndr, &r->autopath));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->autopath), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->autopath, ndr_get_array_length(ndr, &r->autopath), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_autopath_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo403(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo403 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo403");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "ulist_mtime", r->ulist_mtime);
+ ndr_print_uint32(ndr, "glist_mtime", r->glist_mtime);
+ ndr_print_uint32(ndr, "alist_mtime", r->alist_mtime);
+ ndr_print_ptr(ndr, "alerts", r->alerts);
+ ndr->depth++;
+ if (r->alerts) {
+ ndr_print_string(ndr, "alerts", r->alerts);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "security", r->security);
+ ndr_print_uint32(ndr, "numadmin", r->numadmin);
+ ndr_print_uint32(ndr, "lanmask", r->lanmask);
+ ndr_print_ptr(ndr, "guestaccount", r->guestaccount);
+ ndr->depth++;
+ if (r->guestaccount) {
+ ndr_print_string(ndr, "guestaccount", r->guestaccount);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "chdevs", r->chdevs);
+ ndr_print_uint32(ndr, "chdevqs", r->chdevqs);
+ ndr_print_uint32(ndr, "chdevjobs", r->chdevjobs);
+ ndr_print_uint32(ndr, "connections", r->connections);
+ ndr_print_uint32(ndr, "shares", r->shares);
+ ndr_print_uint32(ndr, "openfiles", r->openfiles);
+ ndr_print_uint32(ndr, "sessopen", r->sessopen);
+ ndr_print_uint32(ndr, "sesssvc", r->sesssvc);
+ ndr_print_uint32(ndr, "sessreqs", r->sessreqs);
+ ndr_print_uint32(ndr, "opensearch", r->opensearch);
+ ndr_print_uint32(ndr, "activelocks", r->activelocks);
+ ndr_print_uint32(ndr, "sizereqbufs", r->sizereqbufs);
+ ndr_print_uint32(ndr, "numbigbufs", r->numbigbufs);
+ ndr_print_uint32(ndr, "numfiletasks", r->numfiletasks);
+ ndr_print_uint32(ndr, "alertsched", r->alertsched);
+ ndr_print_uint32(ndr, "eroralert", r->eroralert);
+ ndr_print_uint32(ndr, "logonalert", r->logonalert);
+ ndr_print_uint32(ndr, "accessalert", r->accessalert);
+ ndr_print_uint32(ndr, "diskalert", r->diskalert);
+ ndr_print_uint32(ndr, "netioalert", r->netioalert);
+ ndr_print_uint32(ndr, "maxaudits", r->maxaudits);
+ ndr_print_ptr(ndr, "srvheuristics", r->srvheuristics);
+ ndr->depth++;
+ if (r->srvheuristics) {
+ ndr_print_string(ndr, "srvheuristics", r->srvheuristics);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "auditedevents", r->auditedevents);
+ ndr_print_uint32(ndr, "auditprofile", r->auditprofile);
+ ndr_print_ptr(ndr, "autopath", r->autopath);
+ ndr->depth++;
+ if (r->autopath) {
+ ndr_print_string(ndr, "autopath", r->autopath);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo502(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo502 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sessopen));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sesssvc));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->opensearch));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sizereqbufs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->initworkitems));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxworkitems));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rawworkitems));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->irpstacksize));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxrawbuflen));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sessusers));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sessconns));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxpagedmemoryusage));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxnonpagedmemoryusage));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enablesoftcompat));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enableforcedlogoff));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->timesource));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->acceptdownlevelapis));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->lmannounce));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo502(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo502 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sessopen));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sesssvc));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->opensearch));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sizereqbufs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->initworkitems));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxworkitems));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rawworkitems));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->irpstacksize));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxrawbuflen));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sessusers));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sessconns));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxpagedmemoryusage));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxnonpagedmemoryusage));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enablesoftcompat));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enableforcedlogoff));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->timesource));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->acceptdownlevelapis));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->lmannounce));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo502 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo502");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "sessopen", r->sessopen);
+ ndr_print_uint32(ndr, "sesssvc", r->sesssvc);
+ ndr_print_uint32(ndr, "opensearch", r->opensearch);
+ ndr_print_uint32(ndr, "sizereqbufs", r->sizereqbufs);
+ ndr_print_uint32(ndr, "initworkitems", r->initworkitems);
+ ndr_print_uint32(ndr, "maxworkitems", r->maxworkitems);
+ ndr_print_uint32(ndr, "rawworkitems", r->rawworkitems);
+ ndr_print_uint32(ndr, "irpstacksize", r->irpstacksize);
+ ndr_print_uint32(ndr, "maxrawbuflen", r->maxrawbuflen);
+ ndr_print_uint32(ndr, "sessusers", r->sessusers);
+ ndr_print_uint32(ndr, "sessconns", r->sessconns);
+ ndr_print_uint32(ndr, "maxpagedmemoryusage", r->maxpagedmemoryusage);
+ ndr_print_uint32(ndr, "maxnonpagedmemoryusage", r->maxnonpagedmemoryusage);
+ ndr_print_uint32(ndr, "enablesoftcompat", r->enablesoftcompat);
+ ndr_print_uint32(ndr, "enableforcedlogoff", r->enableforcedlogoff);
+ ndr_print_uint32(ndr, "timesource", r->timesource);
+ ndr_print_uint32(ndr, "acceptdownlevelapis", r->acceptdownlevelapis);
+ ndr_print_uint32(ndr, "lmannounce", r->lmannounce);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo503(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo503 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sessopen));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sesssvc));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->opensearch));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sizereqbufs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->initworkitems));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxworkitems));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rawworkitems));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->irpstacksize));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxrawbuflen));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sessusers));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sessconns));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxpagedmemoryusage));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxnonpagedmemoryusage));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enablesoftcompat));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enableforcedlogoff));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->timesource));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->acceptdownlevelapis));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->lmannounce));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxcopyreadlen));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxcopywritelen));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minkeepsearch));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxkeepsearch));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minkeepcomplsearch));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxkeepcomplsearch));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->threadcountadd));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->numlockthreads));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->scavtimeout));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minrcvqueue));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minfreeworkitems));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->xactmemsize));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->threadpriority));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxmpxct));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->oplockbreakwait));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->oplockbreakresponsewait));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enableoplocks));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enableoplockforceclose));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enablefcbopens));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enableraw));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enablesharednetdrives));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minfreeconnections));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxfreeconnections));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->domain) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain, ndr_charset_length(r->domain, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo503(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo503 *r)
+{
+ uint32_t _ptr_domain;
+ TALLOC_CTX *_mem_save_domain_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sessopen));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sesssvc));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->opensearch));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sizereqbufs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->initworkitems));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxworkitems));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rawworkitems));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->irpstacksize));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxrawbuflen));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sessusers));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sessconns));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxpagedmemoryusage));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxnonpagedmemoryusage));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enablesoftcompat));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enableforcedlogoff));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->timesource));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->acceptdownlevelapis));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->lmannounce));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain));
+ if (_ptr_domain) {
+ NDR_PULL_ALLOC(ndr, r->domain);
+ } else {
+ r->domain = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxcopyreadlen));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxcopywritelen));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minkeepsearch));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxkeepsearch));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minkeepcomplsearch));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxkeepcomplsearch));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->threadcountadd));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->numlockthreads));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->scavtimeout));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minrcvqueue));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minfreeworkitems));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->xactmemsize));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->threadpriority));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxmpxct));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->oplockbreakwait));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->oplockbreakresponsewait));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enableoplocks));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enableoplockforceclose));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enablefcbopens));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enableraw));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enablesharednetdrives));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minfreeconnections));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxfreeconnections));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->domain) {
+ _mem_save_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain));
+ if (ndr_get_array_length(ndr, &r->domain) > ndr_get_array_size(ndr, &r->domain)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain), ndr_get_array_length(ndr, &r->domain));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo503(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo503 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo503");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "sessopen", r->sessopen);
+ ndr_print_uint32(ndr, "sesssvc", r->sesssvc);
+ ndr_print_uint32(ndr, "opensearch", r->opensearch);
+ ndr_print_uint32(ndr, "sizereqbufs", r->sizereqbufs);
+ ndr_print_uint32(ndr, "initworkitems", r->initworkitems);
+ ndr_print_uint32(ndr, "maxworkitems", r->maxworkitems);
+ ndr_print_uint32(ndr, "rawworkitems", r->rawworkitems);
+ ndr_print_uint32(ndr, "irpstacksize", r->irpstacksize);
+ ndr_print_uint32(ndr, "maxrawbuflen", r->maxrawbuflen);
+ ndr_print_uint32(ndr, "sessusers", r->sessusers);
+ ndr_print_uint32(ndr, "sessconns", r->sessconns);
+ ndr_print_uint32(ndr, "maxpagedmemoryusage", r->maxpagedmemoryusage);
+ ndr_print_uint32(ndr, "maxnonpagedmemoryusage", r->maxnonpagedmemoryusage);
+ ndr_print_uint32(ndr, "enablesoftcompat", r->enablesoftcompat);
+ ndr_print_uint32(ndr, "enableforcedlogoff", r->enableforcedlogoff);
+ ndr_print_uint32(ndr, "timesource", r->timesource);
+ ndr_print_uint32(ndr, "acceptdownlevelapis", r->acceptdownlevelapis);
+ ndr_print_uint32(ndr, "lmannounce", r->lmannounce);
+ ndr_print_ptr(ndr, "domain", r->domain);
+ ndr->depth++;
+ if (r->domain) {
+ ndr_print_string(ndr, "domain", r->domain);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "maxcopyreadlen", r->maxcopyreadlen);
+ ndr_print_uint32(ndr, "maxcopywritelen", r->maxcopywritelen);
+ ndr_print_uint32(ndr, "minkeepsearch", r->minkeepsearch);
+ ndr_print_uint32(ndr, "maxkeepsearch", r->maxkeepsearch);
+ ndr_print_uint32(ndr, "minkeepcomplsearch", r->minkeepcomplsearch);
+ ndr_print_uint32(ndr, "maxkeepcomplsearch", r->maxkeepcomplsearch);
+ ndr_print_uint32(ndr, "threadcountadd", r->threadcountadd);
+ ndr_print_uint32(ndr, "numlockthreads", r->numlockthreads);
+ ndr_print_uint32(ndr, "scavtimeout", r->scavtimeout);
+ ndr_print_uint32(ndr, "minrcvqueue", r->minrcvqueue);
+ ndr_print_uint32(ndr, "minfreeworkitems", r->minfreeworkitems);
+ ndr_print_uint32(ndr, "xactmemsize", r->xactmemsize);
+ ndr_print_uint32(ndr, "threadpriority", r->threadpriority);
+ ndr_print_uint32(ndr, "maxmpxct", r->maxmpxct);
+ ndr_print_uint32(ndr, "oplockbreakwait", r->oplockbreakwait);
+ ndr_print_uint32(ndr, "oplockbreakresponsewait", r->oplockbreakresponsewait);
+ ndr_print_uint32(ndr, "enableoplocks", r->enableoplocks);
+ ndr_print_uint32(ndr, "enableoplockforceclose", r->enableoplockforceclose);
+ ndr_print_uint32(ndr, "enablefcbopens", r->enablefcbopens);
+ ndr_print_uint32(ndr, "enableraw", r->enableraw);
+ ndr_print_uint32(ndr, "enablesharednetdrives", r->enablesharednetdrives);
+ ndr_print_uint32(ndr, "minfreeconnections", r->minfreeconnections);
+ ndr_print_uint32(ndr, "maxfreeconnections", r->maxfreeconnections);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo599(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo599 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sessopen));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sesssvc));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->opensearch));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sizereqbufs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->initworkitems));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxworkitems));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->rawworkitems));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->irpstacksize));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxrawbuflen));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sessusers));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sessconns));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxpagedmemoryusage));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxnonpagedmemoryusage));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enablesoftcompat));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enableforcedlogoff));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->timesource));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->acceptdownlevelapis));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->lmannounce));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxcopyreadlen));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxcopywritelen));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minkeepsearch));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minkeepcomplsearch));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxkeepcomplsearch));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->threadcountadd));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->numlockthreads));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->scavtimeout));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minrcvqueue));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minfreeworkitems));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->xactmemsize));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->threadpriority));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxmpxct));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->oplockbreakwait));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->oplockbreakresponsewait));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enableoplocks));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enableoplockforceclose));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enablefcbopens));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enableraw));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enablesharednetdrives));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minfreeconnections));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxfreeconnections));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->initsesstable));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->initconntable));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->initfiletable));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->initsearchtable));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->alertsched));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->errortreshold));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->networkerrortreshold));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->diskspacetreshold));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reserved));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxlinkdelay));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minlinkthroughput));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->linkinfovalidtime));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->scavqosinfoupdatetime));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxworkitemidletime));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->domain) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain, ndr_charset_length(r->domain, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo599(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo599 *r)
+{
+ uint32_t _ptr_domain;
+ TALLOC_CTX *_mem_save_domain_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sessopen));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sesssvc));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->opensearch));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sizereqbufs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->initworkitems));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxworkitems));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->rawworkitems));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->irpstacksize));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxrawbuflen));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sessusers));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sessconns));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxpagedmemoryusage));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxnonpagedmemoryusage));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enablesoftcompat));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enableforcedlogoff));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->timesource));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->acceptdownlevelapis));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->lmannounce));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain));
+ if (_ptr_domain) {
+ NDR_PULL_ALLOC(ndr, r->domain);
+ } else {
+ r->domain = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxcopyreadlen));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxcopywritelen));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minkeepsearch));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minkeepcomplsearch));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxkeepcomplsearch));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->threadcountadd));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->numlockthreads));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->scavtimeout));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minrcvqueue));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minfreeworkitems));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->xactmemsize));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->threadpriority));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxmpxct));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->oplockbreakwait));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->oplockbreakresponsewait));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enableoplocks));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enableoplockforceclose));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enablefcbopens));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enableraw));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enablesharednetdrives));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minfreeconnections));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxfreeconnections));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->initsesstable));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->initconntable));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->initfiletable));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->initsearchtable));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->alertsched));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->errortreshold));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->networkerrortreshold));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->diskspacetreshold));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reserved));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxlinkdelay));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minlinkthroughput));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->linkinfovalidtime));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->scavqosinfoupdatetime));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxworkitemidletime));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->domain) {
+ _mem_save_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain));
+ if (ndr_get_array_length(ndr, &r->domain) > ndr_get_array_size(ndr, &r->domain)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain), ndr_get_array_length(ndr, &r->domain));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo599(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo599 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo599");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "sessopen", r->sessopen);
+ ndr_print_uint32(ndr, "sesssvc", r->sesssvc);
+ ndr_print_uint32(ndr, "opensearch", r->opensearch);
+ ndr_print_uint32(ndr, "sizereqbufs", r->sizereqbufs);
+ ndr_print_uint32(ndr, "initworkitems", r->initworkitems);
+ ndr_print_uint32(ndr, "maxworkitems", r->maxworkitems);
+ ndr_print_uint32(ndr, "rawworkitems", r->rawworkitems);
+ ndr_print_uint32(ndr, "irpstacksize", r->irpstacksize);
+ ndr_print_uint32(ndr, "maxrawbuflen", r->maxrawbuflen);
+ ndr_print_uint32(ndr, "sessusers", r->sessusers);
+ ndr_print_uint32(ndr, "sessconns", r->sessconns);
+ ndr_print_uint32(ndr, "maxpagedmemoryusage", r->maxpagedmemoryusage);
+ ndr_print_uint32(ndr, "maxnonpagedmemoryusage", r->maxnonpagedmemoryusage);
+ ndr_print_uint32(ndr, "enablesoftcompat", r->enablesoftcompat);
+ ndr_print_uint32(ndr, "enableforcedlogoff", r->enableforcedlogoff);
+ ndr_print_uint32(ndr, "timesource", r->timesource);
+ ndr_print_uint32(ndr, "acceptdownlevelapis", r->acceptdownlevelapis);
+ ndr_print_uint32(ndr, "lmannounce", r->lmannounce);
+ ndr_print_ptr(ndr, "domain", r->domain);
+ ndr->depth++;
+ if (r->domain) {
+ ndr_print_string(ndr, "domain", r->domain);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "maxcopyreadlen", r->maxcopyreadlen);
+ ndr_print_uint32(ndr, "maxcopywritelen", r->maxcopywritelen);
+ ndr_print_uint32(ndr, "minkeepsearch", r->minkeepsearch);
+ ndr_print_uint32(ndr, "minkeepcomplsearch", r->minkeepcomplsearch);
+ ndr_print_uint32(ndr, "maxkeepcomplsearch", r->maxkeepcomplsearch);
+ ndr_print_uint32(ndr, "threadcountadd", r->threadcountadd);
+ ndr_print_uint32(ndr, "numlockthreads", r->numlockthreads);
+ ndr_print_uint32(ndr, "scavtimeout", r->scavtimeout);
+ ndr_print_uint32(ndr, "minrcvqueue", r->minrcvqueue);
+ ndr_print_uint32(ndr, "minfreeworkitems", r->minfreeworkitems);
+ ndr_print_uint32(ndr, "xactmemsize", r->xactmemsize);
+ ndr_print_uint32(ndr, "threadpriority", r->threadpriority);
+ ndr_print_uint32(ndr, "maxmpxct", r->maxmpxct);
+ ndr_print_uint32(ndr, "oplockbreakwait", r->oplockbreakwait);
+ ndr_print_uint32(ndr, "oplockbreakresponsewait", r->oplockbreakresponsewait);
+ ndr_print_uint32(ndr, "enableoplocks", r->enableoplocks);
+ ndr_print_uint32(ndr, "enableoplockforceclose", r->enableoplockforceclose);
+ ndr_print_uint32(ndr, "enablefcbopens", r->enablefcbopens);
+ ndr_print_uint32(ndr, "enableraw", r->enableraw);
+ ndr_print_uint32(ndr, "enablesharednetdrives", r->enablesharednetdrives);
+ ndr_print_uint32(ndr, "minfreeconnections", r->minfreeconnections);
+ ndr_print_uint32(ndr, "maxfreeconnections", r->maxfreeconnections);
+ ndr_print_uint32(ndr, "initsesstable", r->initsesstable);
+ ndr_print_uint32(ndr, "initconntable", r->initconntable);
+ ndr_print_uint32(ndr, "initfiletable", r->initfiletable);
+ ndr_print_uint32(ndr, "initsearchtable", r->initsearchtable);
+ ndr_print_uint32(ndr, "alertsched", r->alertsched);
+ ndr_print_uint32(ndr, "errortreshold", r->errortreshold);
+ ndr_print_uint32(ndr, "networkerrortreshold", r->networkerrortreshold);
+ ndr_print_uint32(ndr, "diskspacetreshold", r->diskspacetreshold);
+ ndr_print_uint32(ndr, "reserved", r->reserved);
+ ndr_print_uint32(ndr, "maxlinkdelay", r->maxlinkdelay);
+ ndr_print_uint32(ndr, "minlinkthroughput", r->minlinkthroughput);
+ ndr_print_uint32(ndr, "linkinfovalidtime", r->linkinfovalidtime);
+ ndr_print_uint32(ndr, "scavqosinfoupdatetime", r->scavqosinfoupdatetime);
+ ndr_print_uint32(ndr, "maxworkitemidletime", r->maxworkitemidletime);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1005(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1005 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->comment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->comment) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->comment, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->comment, ndr_charset_length(r->comment, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1005(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1005 *r)
+{
+ uint32_t _ptr_comment;
+ TALLOC_CTX *_mem_save_comment_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_comment));
+ if (_ptr_comment) {
+ NDR_PULL_ALLOC(ndr, r->comment);
+ } else {
+ r->comment = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->comment) {
+ _mem_save_comment_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->comment, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->comment));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->comment));
+ if (ndr_get_array_length(ndr, &r->comment) > ndr_get_array_size(ndr, &r->comment)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->comment), ndr_get_array_length(ndr, &r->comment));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->comment, ndr_get_array_length(ndr, &r->comment), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_comment_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1005(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1005 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1005");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "comment", r->comment);
+ ndr->depth++;
+ if (r->comment) {
+ ndr_print_string(ndr, "comment", r->comment);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1010(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1010 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->disc));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1010(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1010 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->disc));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1010(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1010 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1010");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "disc", r->disc);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1016(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1016 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->hidden));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1016(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1016 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->hidden));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1016(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1016 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1016");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "hidden", r->hidden);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1017(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1017 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->announce));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1017(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1017 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->announce));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1017(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1017 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1017");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "announce", r->announce);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1018(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1018 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->anndelta));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1018(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1018 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->anndelta));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1018(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1018 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1018");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "anndelta", r->anndelta);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1107(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1107 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->users));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1107(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1107 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->users));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1107(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1107 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1107");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "users", r->users);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1501(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1501 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sessopens));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1501(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1501 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sessopens));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1501(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1501 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1501");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "sessopens", r->sessopens);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1502(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1502 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sessvcs));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1502(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1502 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sessvcs));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1502 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1502");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "sessvcs", r->sessvcs);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1503(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1503 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->opensearch));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1503(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1503 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->opensearch));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1503(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1503 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1503");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "opensearch", r->opensearch);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1506(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1506 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxworkitems));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1506(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1506 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxworkitems));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1506(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1506 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1506");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "maxworkitems", r->maxworkitems);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1509(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1509 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxrawbuflen));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1509(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1509 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxrawbuflen));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1509(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1509 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1509");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "maxrawbuflen", r->maxrawbuflen);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1510(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1510 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sessusers));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1510(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1510 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sessusers));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1510(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1510 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1510");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "sessusers", r->sessusers);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1511(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1511 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sesscons));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1511(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1511 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sesscons));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1511(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1511 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1511");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "sesscons", r->sesscons);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1512(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1512 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxnonpagedmemoryusage));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1512(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1512 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxnonpagedmemoryusage));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1512(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1512 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1512");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "maxnonpagedmemoryusage", r->maxnonpagedmemoryusage);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1513(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1513 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxpagedmemoryusage));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1513(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1513 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxpagedmemoryusage));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1513(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1513 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1513");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "maxpagedmemoryusage", r->maxpagedmemoryusage);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1514(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1514 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enablesoftcompat));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1514(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1514 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enablesoftcompat));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1514(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1514 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1514");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "enablesoftcompat", r->enablesoftcompat);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1515(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1515 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enableforcedlogoff));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1515(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1515 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enableforcedlogoff));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1515(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1515 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1515");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "enableforcedlogoff", r->enableforcedlogoff);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1516(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1516 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->timesource));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1516(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1516 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->timesource));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1516(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1516 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1516");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "timesource", r->timesource);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1518(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1518 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->lmannounce));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1518(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1518 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->lmannounce));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1518(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1518 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1518");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "lmannounce", r->lmannounce);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1520(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1520 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxcopyreadlen));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1520(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1520 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxcopyreadlen));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1520(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1520 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1520");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "maxcopyreadlen", r->maxcopyreadlen);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1521(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1521 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxcopywritelen));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1521(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1521 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxcopywritelen));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1521(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1521 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1521");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "maxcopywritelen", r->maxcopywritelen);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1522(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1522 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minkeepsearch));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1522(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1522 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minkeepsearch));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1522(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1522 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1522");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "minkeepsearch", r->minkeepsearch);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1523(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1523 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxkeepsearch));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1523(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1523 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxkeepsearch));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1523(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1523 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1523");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "maxkeepsearch", r->maxkeepsearch);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1524(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1524 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minkeepcomplsearch));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1524(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1524 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minkeepcomplsearch));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1524(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1524 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1524");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "minkeepcomplsearch", r->minkeepcomplsearch);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1525(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1525 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxkeepcomplsearch));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1525(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1525 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxkeepcomplsearch));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1525(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1525 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1525");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "maxkeepcomplsearch", r->maxkeepcomplsearch);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1528(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1528 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->scavtimeout));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1528(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1528 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->scavtimeout));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1528(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1528 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1528");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "scavtimeout", r->scavtimeout);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1529(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1529 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minrcvqueue));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1529(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1529 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minrcvqueue));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1529(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1529 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1529");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "minrcvqueue", r->minrcvqueue);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1530(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1530 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minfreeworkitems));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1530(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1530 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minfreeworkitems));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1530(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1530 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1530");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "minfreeworkitems", r->minfreeworkitems);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1533(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1533 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxmpxct));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1533(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1533 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxmpxct));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1533(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1533 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1533");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "maxmpxct", r->maxmpxct);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1534(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1534 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->oplockbreakwait));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1534(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1534 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->oplockbreakwait));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1534(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1534 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1534");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "oplockbreakwait", r->oplockbreakwait);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1535(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1535 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->oplockbreakresponsewait));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1535(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1535 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->oplockbreakresponsewait));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1535(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1535 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1535");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "oplockbreakresponsewait", r->oplockbreakresponsewait);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1536(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1536 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enableoplocks));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1536(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1536 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enableoplocks));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1536(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1536 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1536");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "enableoplocks", r->enableoplocks);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1537(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1537 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enableoplockforceclose));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1537(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1537 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enableoplockforceclose));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1537(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1537 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1537");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "enableoplockforceclose", r->enableoplockforceclose);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1538(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1538 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enablefcbopens));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1538(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1538 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enablefcbopens));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1538(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1538 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1538");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "enablefcbopens", r->enablefcbopens);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1539(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1539 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enableraw));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1539(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1539 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enableraw));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1539(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1539 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1539");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "enableraw", r->enableraw);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1540(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1540 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->enablesharednetdrives));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1540(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1540 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->enablesharednetdrives));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1540(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1540 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1540");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "enablesharednetdrives", r->enablesharednetdrives);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1541(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1541 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minfreeconnections));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1541(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1541 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minfreeconnections));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1541(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1541 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1541");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "minfreeconnections", r->minfreeconnections);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1542(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1542 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxfreeconnections));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1542(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1542 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxfreeconnections));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1542(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1542 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1542");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "maxfreeconnections", r->maxfreeconnections);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1543(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1543 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->initsesstable));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1543(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1543 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->initsesstable));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1543(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1543 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1543");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "initsesstable", r->initsesstable);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1544(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1544 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->initconntable));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1544(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1544 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->initconntable));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1544(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1544 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1544");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "initconntable", r->initconntable);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1545(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1545 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->initfiletable));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1545(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1545 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->initfiletable));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1545(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1545 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1545");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "initfiletable", r->initfiletable);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1546(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1546 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->initsearchtable));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1546(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1546 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->initsearchtable));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1546(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1546 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1546");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "initsearchtable", r->initsearchtable);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1547(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1547 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->alertsched));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1547(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1547 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->alertsched));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1547(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1547 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1547");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "alertsched", r->alertsched);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1548(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1548 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->errortreshold));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1548(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1548 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->errortreshold));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1548(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1548 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1548");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "errortreshold", r->errortreshold);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1549(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1549 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->networkerrortreshold));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1549(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1549 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->networkerrortreshold));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1549(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1549 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1549");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "networkerrortreshold", r->networkerrortreshold);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1550(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1550 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->diskspacetreshold));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1550(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1550 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->diskspacetreshold));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1550(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1550 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1550");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "diskspacetreshold", r->diskspacetreshold);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1552(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1552 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxlinkdelay));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1552(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1552 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxlinkdelay));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1552(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1552 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1552");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "maxlinkdelay", r->maxlinkdelay);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1553(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1553 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->minlinkthroughput));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1553(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1553 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->minlinkthroughput));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1553(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1553 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1553");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "minlinkthroughput", r->minlinkthroughput);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1554(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1554 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->linkinfovalidtime));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1554(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1554 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->linkinfovalidtime));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1554(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1554 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1554");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "linkinfovalidtime", r->linkinfovalidtime);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1555(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1555 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->scavqosinfoupdatetime));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1555(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1555 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->scavqosinfoupdatetime));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1555(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1555 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1555");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "scavqosinfoupdatetime", r->scavqosinfoupdatetime);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo1556(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetSrvInfo1556 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maxworkitemidletime));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo1556(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetSrvInfo1556 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maxworkitemidletime));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo1556(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1556 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvInfo1556");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "maxworkitemidletime", r->maxworkitemidletime);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvInfo(struct ndr_push *ndr, int ndr_flags, const union srvsvc_NetSrvInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 100: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info100));
+ break; }
+
+ case 101: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info101));
+ break; }
+
+ case 102: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info102));
+ break; }
+
+ case 402: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info402));
+ break; }
+
+ case 403: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info403));
+ break; }
+
+ case 502: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info502));
+ break; }
+
+ case 503: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info503));
+ break; }
+
+ case 599: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info599));
+ break; }
+
+ case 1005: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1005));
+ break; }
+
+ case 1010: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1010));
+ break; }
+
+ case 1016: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1016));
+ break; }
+
+ case 1017: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1017));
+ break; }
+
+ case 1018: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1018));
+ break; }
+
+ case 1107: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1107));
+ break; }
+
+ case 1501: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1501));
+ break; }
+
+ case 1502: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1502));
+ break; }
+
+ case 1503: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1503));
+ break; }
+
+ case 1506: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1506));
+ break; }
+
+ case 1509: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1509));
+ break; }
+
+ case 1510: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1510));
+ break; }
+
+ case 1511: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1511));
+ break; }
+
+ case 1512: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1512));
+ break; }
+
+ case 1513: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1513));
+ break; }
+
+ case 1514: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1514));
+ break; }
+
+ case 1515: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1515));
+ break; }
+
+ case 1516: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1516));
+ break; }
+
+ case 1518: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1518));
+ break; }
+
+ case 1520: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1520));
+ break; }
+
+ case 1521: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1521));
+ break; }
+
+ case 1522: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1522));
+ break; }
+
+ case 1523: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1523));
+ break; }
+
+ case 1524: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1524));
+ break; }
+
+ case 1525: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1525));
+ break; }
+
+ case 1528: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1528));
+ break; }
+
+ case 1529: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1529));
+ break; }
+
+ case 1530: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1530));
+ break; }
+
+ case 1533: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1533));
+ break; }
+
+ case 1534: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1534));
+ break; }
+
+ case 1535: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1535));
+ break; }
+
+ case 1536: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1536));
+ break; }
+
+ case 1537: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1537));
+ break; }
+
+ case 1538: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1538));
+ break; }
+
+ case 1539: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1539));
+ break; }
+
+ case 1540: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1540));
+ break; }
+
+ case 1541: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1541));
+ break; }
+
+ case 1542: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1542));
+ break; }
+
+ case 1543: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1543));
+ break; }
+
+ case 1544: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1544));
+ break; }
+
+ case 1545: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1545));
+ break; }
+
+ case 1546: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1546));
+ break; }
+
+ case 1547: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1547));
+ break; }
+
+ case 1548: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1548));
+ break; }
+
+ case 1549: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1549));
+ break; }
+
+ case 1550: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1550));
+ break; }
+
+ case 1552: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1552));
+ break; }
+
+ case 1553: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1553));
+ break; }
+
+ case 1554: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1554));
+ break; }
+
+ case 1555: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1555));
+ break; }
+
+ case 1556: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1556));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 100:
+ if (r->info100) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo100(ndr, NDR_SCALARS|NDR_BUFFERS, r->info100));
+ }
+ break;
+
+ case 101:
+ if (r->info101) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo101(ndr, NDR_SCALARS|NDR_BUFFERS, r->info101));
+ }
+ break;
+
+ case 102:
+ if (r->info102) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo102(ndr, NDR_SCALARS|NDR_BUFFERS, r->info102));
+ }
+ break;
+
+ case 402:
+ if (r->info402) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo402(ndr, NDR_SCALARS|NDR_BUFFERS, r->info402));
+ }
+ break;
+
+ case 403:
+ if (r->info403) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo403(ndr, NDR_SCALARS|NDR_BUFFERS, r->info403));
+ }
+ break;
+
+ case 502:
+ if (r->info502) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo502(ndr, NDR_SCALARS, r->info502));
+ }
+ break;
+
+ case 503:
+ if (r->info503) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo503(ndr, NDR_SCALARS|NDR_BUFFERS, r->info503));
+ }
+ break;
+
+ case 599:
+ if (r->info599) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo599(ndr, NDR_SCALARS|NDR_BUFFERS, r->info599));
+ }
+ break;
+
+ case 1005:
+ if (r->info1005) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1005(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1005));
+ }
+ break;
+
+ case 1010:
+ if (r->info1010) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1010(ndr, NDR_SCALARS, r->info1010));
+ }
+ break;
+
+ case 1016:
+ if (r->info1016) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1016(ndr, NDR_SCALARS, r->info1016));
+ }
+ break;
+
+ case 1017:
+ if (r->info1017) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1017(ndr, NDR_SCALARS, r->info1017));
+ }
+ break;
+
+ case 1018:
+ if (r->info1018) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1018(ndr, NDR_SCALARS, r->info1018));
+ }
+ break;
+
+ case 1107:
+ if (r->info1107) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1107(ndr, NDR_SCALARS, r->info1107));
+ }
+ break;
+
+ case 1501:
+ if (r->info1501) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1501(ndr, NDR_SCALARS, r->info1501));
+ }
+ break;
+
+ case 1502:
+ if (r->info1502) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1502(ndr, NDR_SCALARS, r->info1502));
+ }
+ break;
+
+ case 1503:
+ if (r->info1503) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1503(ndr, NDR_SCALARS, r->info1503));
+ }
+ break;
+
+ case 1506:
+ if (r->info1506) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1506(ndr, NDR_SCALARS, r->info1506));
+ }
+ break;
+
+ case 1509:
+ if (r->info1509) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1509(ndr, NDR_SCALARS, r->info1509));
+ }
+ break;
+
+ case 1510:
+ if (r->info1510) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1510(ndr, NDR_SCALARS, r->info1510));
+ }
+ break;
+
+ case 1511:
+ if (r->info1511) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1511(ndr, NDR_SCALARS, r->info1511));
+ }
+ break;
+
+ case 1512:
+ if (r->info1512) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1512(ndr, NDR_SCALARS, r->info1512));
+ }
+ break;
+
+ case 1513:
+ if (r->info1513) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1513(ndr, NDR_SCALARS, r->info1513));
+ }
+ break;
+
+ case 1514:
+ if (r->info1514) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1514(ndr, NDR_SCALARS, r->info1514));
+ }
+ break;
+
+ case 1515:
+ if (r->info1515) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1515(ndr, NDR_SCALARS, r->info1515));
+ }
+ break;
+
+ case 1516:
+ if (r->info1516) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1516(ndr, NDR_SCALARS, r->info1516));
+ }
+ break;
+
+ case 1518:
+ if (r->info1518) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1518(ndr, NDR_SCALARS, r->info1518));
+ }
+ break;
+
+ case 1520:
+ if (r->info1520) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1520(ndr, NDR_SCALARS, r->info1520));
+ }
+ break;
+
+ case 1521:
+ if (r->info1521) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1521(ndr, NDR_SCALARS, r->info1521));
+ }
+ break;
+
+ case 1522:
+ if (r->info1522) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1522(ndr, NDR_SCALARS, r->info1522));
+ }
+ break;
+
+ case 1523:
+ if (r->info1523) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1523(ndr, NDR_SCALARS, r->info1523));
+ }
+ break;
+
+ case 1524:
+ if (r->info1524) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1524(ndr, NDR_SCALARS, r->info1524));
+ }
+ break;
+
+ case 1525:
+ if (r->info1525) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1525(ndr, NDR_SCALARS, r->info1525));
+ }
+ break;
+
+ case 1528:
+ if (r->info1528) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1528(ndr, NDR_SCALARS, r->info1528));
+ }
+ break;
+
+ case 1529:
+ if (r->info1529) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1529(ndr, NDR_SCALARS, r->info1529));
+ }
+ break;
+
+ case 1530:
+ if (r->info1530) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1530(ndr, NDR_SCALARS, r->info1530));
+ }
+ break;
+
+ case 1533:
+ if (r->info1533) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1533(ndr, NDR_SCALARS, r->info1533));
+ }
+ break;
+
+ case 1534:
+ if (r->info1534) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1534(ndr, NDR_SCALARS, r->info1534));
+ }
+ break;
+
+ case 1535:
+ if (r->info1535) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1535(ndr, NDR_SCALARS, r->info1535));
+ }
+ break;
+
+ case 1536:
+ if (r->info1536) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1536(ndr, NDR_SCALARS, r->info1536));
+ }
+ break;
+
+ case 1537:
+ if (r->info1537) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1537(ndr, NDR_SCALARS, r->info1537));
+ }
+ break;
+
+ case 1538:
+ if (r->info1538) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1538(ndr, NDR_SCALARS, r->info1538));
+ }
+ break;
+
+ case 1539:
+ if (r->info1539) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1539(ndr, NDR_SCALARS, r->info1539));
+ }
+ break;
+
+ case 1540:
+ if (r->info1540) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1540(ndr, NDR_SCALARS, r->info1540));
+ }
+ break;
+
+ case 1541:
+ if (r->info1541) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1541(ndr, NDR_SCALARS, r->info1541));
+ }
+ break;
+
+ case 1542:
+ if (r->info1542) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1542(ndr, NDR_SCALARS, r->info1542));
+ }
+ break;
+
+ case 1543:
+ if (r->info1543) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1543(ndr, NDR_SCALARS, r->info1543));
+ }
+ break;
+
+ case 1544:
+ if (r->info1544) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1544(ndr, NDR_SCALARS, r->info1544));
+ }
+ break;
+
+ case 1545:
+ if (r->info1545) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1545(ndr, NDR_SCALARS, r->info1545));
+ }
+ break;
+
+ case 1546:
+ if (r->info1546) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1546(ndr, NDR_SCALARS, r->info1546));
+ }
+ break;
+
+ case 1547:
+ if (r->info1547) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1547(ndr, NDR_SCALARS, r->info1547));
+ }
+ break;
+
+ case 1548:
+ if (r->info1548) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1548(ndr, NDR_SCALARS, r->info1548));
+ }
+ break;
+
+ case 1549:
+ if (r->info1549) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1549(ndr, NDR_SCALARS, r->info1549));
+ }
+ break;
+
+ case 1550:
+ if (r->info1550) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1550(ndr, NDR_SCALARS, r->info1550));
+ }
+ break;
+
+ case 1552:
+ if (r->info1552) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1552(ndr, NDR_SCALARS, r->info1552));
+ }
+ break;
+
+ case 1553:
+ if (r->info1553) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1553(ndr, NDR_SCALARS, r->info1553));
+ }
+ break;
+
+ case 1554:
+ if (r->info1554) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1554(ndr, NDR_SCALARS, r->info1554));
+ }
+ break;
+
+ case 1555:
+ if (r->info1555) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1555(ndr, NDR_SCALARS, r->info1555));
+ }
+ break;
+
+ case 1556:
+ if (r->info1556) {
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo1556(ndr, NDR_SCALARS, r->info1556));
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvInfo(struct ndr_pull *ndr, int ndr_flags, union srvsvc_NetSrvInfo *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_info100_0;
+ TALLOC_CTX *_mem_save_info101_0;
+ TALLOC_CTX *_mem_save_info102_0;
+ TALLOC_CTX *_mem_save_info402_0;
+ TALLOC_CTX *_mem_save_info403_0;
+ TALLOC_CTX *_mem_save_info502_0;
+ TALLOC_CTX *_mem_save_info503_0;
+ TALLOC_CTX *_mem_save_info599_0;
+ TALLOC_CTX *_mem_save_info1005_0;
+ TALLOC_CTX *_mem_save_info1010_0;
+ TALLOC_CTX *_mem_save_info1016_0;
+ TALLOC_CTX *_mem_save_info1017_0;
+ TALLOC_CTX *_mem_save_info1018_0;
+ TALLOC_CTX *_mem_save_info1107_0;
+ TALLOC_CTX *_mem_save_info1501_0;
+ TALLOC_CTX *_mem_save_info1502_0;
+ TALLOC_CTX *_mem_save_info1503_0;
+ TALLOC_CTX *_mem_save_info1506_0;
+ TALLOC_CTX *_mem_save_info1509_0;
+ TALLOC_CTX *_mem_save_info1510_0;
+ TALLOC_CTX *_mem_save_info1511_0;
+ TALLOC_CTX *_mem_save_info1512_0;
+ TALLOC_CTX *_mem_save_info1513_0;
+ TALLOC_CTX *_mem_save_info1514_0;
+ TALLOC_CTX *_mem_save_info1515_0;
+ TALLOC_CTX *_mem_save_info1516_0;
+ TALLOC_CTX *_mem_save_info1518_0;
+ TALLOC_CTX *_mem_save_info1520_0;
+ TALLOC_CTX *_mem_save_info1521_0;
+ TALLOC_CTX *_mem_save_info1522_0;
+ TALLOC_CTX *_mem_save_info1523_0;
+ TALLOC_CTX *_mem_save_info1524_0;
+ TALLOC_CTX *_mem_save_info1525_0;
+ TALLOC_CTX *_mem_save_info1528_0;
+ TALLOC_CTX *_mem_save_info1529_0;
+ TALLOC_CTX *_mem_save_info1530_0;
+ TALLOC_CTX *_mem_save_info1533_0;
+ TALLOC_CTX *_mem_save_info1534_0;
+ TALLOC_CTX *_mem_save_info1535_0;
+ TALLOC_CTX *_mem_save_info1536_0;
+ TALLOC_CTX *_mem_save_info1537_0;
+ TALLOC_CTX *_mem_save_info1538_0;
+ TALLOC_CTX *_mem_save_info1539_0;
+ TALLOC_CTX *_mem_save_info1540_0;
+ TALLOC_CTX *_mem_save_info1541_0;
+ TALLOC_CTX *_mem_save_info1542_0;
+ TALLOC_CTX *_mem_save_info1543_0;
+ TALLOC_CTX *_mem_save_info1544_0;
+ TALLOC_CTX *_mem_save_info1545_0;
+ TALLOC_CTX *_mem_save_info1546_0;
+ TALLOC_CTX *_mem_save_info1547_0;
+ TALLOC_CTX *_mem_save_info1548_0;
+ TALLOC_CTX *_mem_save_info1549_0;
+ TALLOC_CTX *_mem_save_info1550_0;
+ TALLOC_CTX *_mem_save_info1552_0;
+ TALLOC_CTX *_mem_save_info1553_0;
+ TALLOC_CTX *_mem_save_info1554_0;
+ TALLOC_CTX *_mem_save_info1555_0;
+ TALLOC_CTX *_mem_save_info1556_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 100: {
+ uint32_t _ptr_info100;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info100));
+ if (_ptr_info100) {
+ NDR_PULL_ALLOC(ndr, r->info100);
+ } else {
+ r->info100 = NULL;
+ }
+ break; }
+
+ case 101: {
+ uint32_t _ptr_info101;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info101));
+ if (_ptr_info101) {
+ NDR_PULL_ALLOC(ndr, r->info101);
+ } else {
+ r->info101 = NULL;
+ }
+ break; }
+
+ case 102: {
+ uint32_t _ptr_info102;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info102));
+ if (_ptr_info102) {
+ NDR_PULL_ALLOC(ndr, r->info102);
+ } else {
+ r->info102 = NULL;
+ }
+ break; }
+
+ case 402: {
+ uint32_t _ptr_info402;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info402));
+ if (_ptr_info402) {
+ NDR_PULL_ALLOC(ndr, r->info402);
+ } else {
+ r->info402 = NULL;
+ }
+ break; }
+
+ case 403: {
+ uint32_t _ptr_info403;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info403));
+ if (_ptr_info403) {
+ NDR_PULL_ALLOC(ndr, r->info403);
+ } else {
+ r->info403 = NULL;
+ }
+ break; }
+
+ case 502: {
+ uint32_t _ptr_info502;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info502));
+ if (_ptr_info502) {
+ NDR_PULL_ALLOC(ndr, r->info502);
+ } else {
+ r->info502 = NULL;
+ }
+ break; }
+
+ case 503: {
+ uint32_t _ptr_info503;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info503));
+ if (_ptr_info503) {
+ NDR_PULL_ALLOC(ndr, r->info503);
+ } else {
+ r->info503 = NULL;
+ }
+ break; }
+
+ case 599: {
+ uint32_t _ptr_info599;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info599));
+ if (_ptr_info599) {
+ NDR_PULL_ALLOC(ndr, r->info599);
+ } else {
+ r->info599 = NULL;
+ }
+ break; }
+
+ case 1005: {
+ uint32_t _ptr_info1005;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1005));
+ if (_ptr_info1005) {
+ NDR_PULL_ALLOC(ndr, r->info1005);
+ } else {
+ r->info1005 = NULL;
+ }
+ break; }
+
+ case 1010: {
+ uint32_t _ptr_info1010;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1010));
+ if (_ptr_info1010) {
+ NDR_PULL_ALLOC(ndr, r->info1010);
+ } else {
+ r->info1010 = NULL;
+ }
+ break; }
+
+ case 1016: {
+ uint32_t _ptr_info1016;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1016));
+ if (_ptr_info1016) {
+ NDR_PULL_ALLOC(ndr, r->info1016);
+ } else {
+ r->info1016 = NULL;
+ }
+ break; }
+
+ case 1017: {
+ uint32_t _ptr_info1017;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1017));
+ if (_ptr_info1017) {
+ NDR_PULL_ALLOC(ndr, r->info1017);
+ } else {
+ r->info1017 = NULL;
+ }
+ break; }
+
+ case 1018: {
+ uint32_t _ptr_info1018;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1018));
+ if (_ptr_info1018) {
+ NDR_PULL_ALLOC(ndr, r->info1018);
+ } else {
+ r->info1018 = NULL;
+ }
+ break; }
+
+ case 1107: {
+ uint32_t _ptr_info1107;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1107));
+ if (_ptr_info1107) {
+ NDR_PULL_ALLOC(ndr, r->info1107);
+ } else {
+ r->info1107 = NULL;
+ }
+ break; }
+
+ case 1501: {
+ uint32_t _ptr_info1501;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1501));
+ if (_ptr_info1501) {
+ NDR_PULL_ALLOC(ndr, r->info1501);
+ } else {
+ r->info1501 = NULL;
+ }
+ break; }
+
+ case 1502: {
+ uint32_t _ptr_info1502;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1502));
+ if (_ptr_info1502) {
+ NDR_PULL_ALLOC(ndr, r->info1502);
+ } else {
+ r->info1502 = NULL;
+ }
+ break; }
+
+ case 1503: {
+ uint32_t _ptr_info1503;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1503));
+ if (_ptr_info1503) {
+ NDR_PULL_ALLOC(ndr, r->info1503);
+ } else {
+ r->info1503 = NULL;
+ }
+ break; }
+
+ case 1506: {
+ uint32_t _ptr_info1506;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1506));
+ if (_ptr_info1506) {
+ NDR_PULL_ALLOC(ndr, r->info1506);
+ } else {
+ r->info1506 = NULL;
+ }
+ break; }
+
+ case 1509: {
+ uint32_t _ptr_info1509;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1509));
+ if (_ptr_info1509) {
+ NDR_PULL_ALLOC(ndr, r->info1509);
+ } else {
+ r->info1509 = NULL;
+ }
+ break; }
+
+ case 1510: {
+ uint32_t _ptr_info1510;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1510));
+ if (_ptr_info1510) {
+ NDR_PULL_ALLOC(ndr, r->info1510);
+ } else {
+ r->info1510 = NULL;
+ }
+ break; }
+
+ case 1511: {
+ uint32_t _ptr_info1511;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1511));
+ if (_ptr_info1511) {
+ NDR_PULL_ALLOC(ndr, r->info1511);
+ } else {
+ r->info1511 = NULL;
+ }
+ break; }
+
+ case 1512: {
+ uint32_t _ptr_info1512;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1512));
+ if (_ptr_info1512) {
+ NDR_PULL_ALLOC(ndr, r->info1512);
+ } else {
+ r->info1512 = NULL;
+ }
+ break; }
+
+ case 1513: {
+ uint32_t _ptr_info1513;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1513));
+ if (_ptr_info1513) {
+ NDR_PULL_ALLOC(ndr, r->info1513);
+ } else {
+ r->info1513 = NULL;
+ }
+ break; }
+
+ case 1514: {
+ uint32_t _ptr_info1514;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1514));
+ if (_ptr_info1514) {
+ NDR_PULL_ALLOC(ndr, r->info1514);
+ } else {
+ r->info1514 = NULL;
+ }
+ break; }
+
+ case 1515: {
+ uint32_t _ptr_info1515;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1515));
+ if (_ptr_info1515) {
+ NDR_PULL_ALLOC(ndr, r->info1515);
+ } else {
+ r->info1515 = NULL;
+ }
+ break; }
+
+ case 1516: {
+ uint32_t _ptr_info1516;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1516));
+ if (_ptr_info1516) {
+ NDR_PULL_ALLOC(ndr, r->info1516);
+ } else {
+ r->info1516 = NULL;
+ }
+ break; }
+
+ case 1518: {
+ uint32_t _ptr_info1518;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1518));
+ if (_ptr_info1518) {
+ NDR_PULL_ALLOC(ndr, r->info1518);
+ } else {
+ r->info1518 = NULL;
+ }
+ break; }
+
+ case 1520: {
+ uint32_t _ptr_info1520;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1520));
+ if (_ptr_info1520) {
+ NDR_PULL_ALLOC(ndr, r->info1520);
+ } else {
+ r->info1520 = NULL;
+ }
+ break; }
+
+ case 1521: {
+ uint32_t _ptr_info1521;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1521));
+ if (_ptr_info1521) {
+ NDR_PULL_ALLOC(ndr, r->info1521);
+ } else {
+ r->info1521 = NULL;
+ }
+ break; }
+
+ case 1522: {
+ uint32_t _ptr_info1522;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1522));
+ if (_ptr_info1522) {
+ NDR_PULL_ALLOC(ndr, r->info1522);
+ } else {
+ r->info1522 = NULL;
+ }
+ break; }
+
+ case 1523: {
+ uint32_t _ptr_info1523;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1523));
+ if (_ptr_info1523) {
+ NDR_PULL_ALLOC(ndr, r->info1523);
+ } else {
+ r->info1523 = NULL;
+ }
+ break; }
+
+ case 1524: {
+ uint32_t _ptr_info1524;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1524));
+ if (_ptr_info1524) {
+ NDR_PULL_ALLOC(ndr, r->info1524);
+ } else {
+ r->info1524 = NULL;
+ }
+ break; }
+
+ case 1525: {
+ uint32_t _ptr_info1525;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1525));
+ if (_ptr_info1525) {
+ NDR_PULL_ALLOC(ndr, r->info1525);
+ } else {
+ r->info1525 = NULL;
+ }
+ break; }
+
+ case 1528: {
+ uint32_t _ptr_info1528;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1528));
+ if (_ptr_info1528) {
+ NDR_PULL_ALLOC(ndr, r->info1528);
+ } else {
+ r->info1528 = NULL;
+ }
+ break; }
+
+ case 1529: {
+ uint32_t _ptr_info1529;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1529));
+ if (_ptr_info1529) {
+ NDR_PULL_ALLOC(ndr, r->info1529);
+ } else {
+ r->info1529 = NULL;
+ }
+ break; }
+
+ case 1530: {
+ uint32_t _ptr_info1530;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1530));
+ if (_ptr_info1530) {
+ NDR_PULL_ALLOC(ndr, r->info1530);
+ } else {
+ r->info1530 = NULL;
+ }
+ break; }
+
+ case 1533: {
+ uint32_t _ptr_info1533;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1533));
+ if (_ptr_info1533) {
+ NDR_PULL_ALLOC(ndr, r->info1533);
+ } else {
+ r->info1533 = NULL;
+ }
+ break; }
+
+ case 1534: {
+ uint32_t _ptr_info1534;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1534));
+ if (_ptr_info1534) {
+ NDR_PULL_ALLOC(ndr, r->info1534);
+ } else {
+ r->info1534 = NULL;
+ }
+ break; }
+
+ case 1535: {
+ uint32_t _ptr_info1535;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1535));
+ if (_ptr_info1535) {
+ NDR_PULL_ALLOC(ndr, r->info1535);
+ } else {
+ r->info1535 = NULL;
+ }
+ break; }
+
+ case 1536: {
+ uint32_t _ptr_info1536;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1536));
+ if (_ptr_info1536) {
+ NDR_PULL_ALLOC(ndr, r->info1536);
+ } else {
+ r->info1536 = NULL;
+ }
+ break; }
+
+ case 1537: {
+ uint32_t _ptr_info1537;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1537));
+ if (_ptr_info1537) {
+ NDR_PULL_ALLOC(ndr, r->info1537);
+ } else {
+ r->info1537 = NULL;
+ }
+ break; }
+
+ case 1538: {
+ uint32_t _ptr_info1538;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1538));
+ if (_ptr_info1538) {
+ NDR_PULL_ALLOC(ndr, r->info1538);
+ } else {
+ r->info1538 = NULL;
+ }
+ break; }
+
+ case 1539: {
+ uint32_t _ptr_info1539;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1539));
+ if (_ptr_info1539) {
+ NDR_PULL_ALLOC(ndr, r->info1539);
+ } else {
+ r->info1539 = NULL;
+ }
+ break; }
+
+ case 1540: {
+ uint32_t _ptr_info1540;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1540));
+ if (_ptr_info1540) {
+ NDR_PULL_ALLOC(ndr, r->info1540);
+ } else {
+ r->info1540 = NULL;
+ }
+ break; }
+
+ case 1541: {
+ uint32_t _ptr_info1541;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1541));
+ if (_ptr_info1541) {
+ NDR_PULL_ALLOC(ndr, r->info1541);
+ } else {
+ r->info1541 = NULL;
+ }
+ break; }
+
+ case 1542: {
+ uint32_t _ptr_info1542;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1542));
+ if (_ptr_info1542) {
+ NDR_PULL_ALLOC(ndr, r->info1542);
+ } else {
+ r->info1542 = NULL;
+ }
+ break; }
+
+ case 1543: {
+ uint32_t _ptr_info1543;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1543));
+ if (_ptr_info1543) {
+ NDR_PULL_ALLOC(ndr, r->info1543);
+ } else {
+ r->info1543 = NULL;
+ }
+ break; }
+
+ case 1544: {
+ uint32_t _ptr_info1544;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1544));
+ if (_ptr_info1544) {
+ NDR_PULL_ALLOC(ndr, r->info1544);
+ } else {
+ r->info1544 = NULL;
+ }
+ break; }
+
+ case 1545: {
+ uint32_t _ptr_info1545;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1545));
+ if (_ptr_info1545) {
+ NDR_PULL_ALLOC(ndr, r->info1545);
+ } else {
+ r->info1545 = NULL;
+ }
+ break; }
+
+ case 1546: {
+ uint32_t _ptr_info1546;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1546));
+ if (_ptr_info1546) {
+ NDR_PULL_ALLOC(ndr, r->info1546);
+ } else {
+ r->info1546 = NULL;
+ }
+ break; }
+
+ case 1547: {
+ uint32_t _ptr_info1547;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1547));
+ if (_ptr_info1547) {
+ NDR_PULL_ALLOC(ndr, r->info1547);
+ } else {
+ r->info1547 = NULL;
+ }
+ break; }
+
+ case 1548: {
+ uint32_t _ptr_info1548;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1548));
+ if (_ptr_info1548) {
+ NDR_PULL_ALLOC(ndr, r->info1548);
+ } else {
+ r->info1548 = NULL;
+ }
+ break; }
+
+ case 1549: {
+ uint32_t _ptr_info1549;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1549));
+ if (_ptr_info1549) {
+ NDR_PULL_ALLOC(ndr, r->info1549);
+ } else {
+ r->info1549 = NULL;
+ }
+ break; }
+
+ case 1550: {
+ uint32_t _ptr_info1550;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1550));
+ if (_ptr_info1550) {
+ NDR_PULL_ALLOC(ndr, r->info1550);
+ } else {
+ r->info1550 = NULL;
+ }
+ break; }
+
+ case 1552: {
+ uint32_t _ptr_info1552;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1552));
+ if (_ptr_info1552) {
+ NDR_PULL_ALLOC(ndr, r->info1552);
+ } else {
+ r->info1552 = NULL;
+ }
+ break; }
+
+ case 1553: {
+ uint32_t _ptr_info1553;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1553));
+ if (_ptr_info1553) {
+ NDR_PULL_ALLOC(ndr, r->info1553);
+ } else {
+ r->info1553 = NULL;
+ }
+ break; }
+
+ case 1554: {
+ uint32_t _ptr_info1554;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1554));
+ if (_ptr_info1554) {
+ NDR_PULL_ALLOC(ndr, r->info1554);
+ } else {
+ r->info1554 = NULL;
+ }
+ break; }
+
+ case 1555: {
+ uint32_t _ptr_info1555;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1555));
+ if (_ptr_info1555) {
+ NDR_PULL_ALLOC(ndr, r->info1555);
+ } else {
+ r->info1555 = NULL;
+ }
+ break; }
+
+ case 1556: {
+ uint32_t _ptr_info1556;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1556));
+ if (_ptr_info1556) {
+ NDR_PULL_ALLOC(ndr, r->info1556);
+ } else {
+ r->info1556 = NULL;
+ }
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 100:
+ if (r->info100) {
+ _mem_save_info100_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info100, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo100(ndr, NDR_SCALARS|NDR_BUFFERS, r->info100));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info100_0, 0);
+ }
+ break;
+
+ case 101:
+ if (r->info101) {
+ _mem_save_info101_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info101, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo101(ndr, NDR_SCALARS|NDR_BUFFERS, r->info101));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info101_0, 0);
+ }
+ break;
+
+ case 102:
+ if (r->info102) {
+ _mem_save_info102_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info102, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo102(ndr, NDR_SCALARS|NDR_BUFFERS, r->info102));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info102_0, 0);
+ }
+ break;
+
+ case 402:
+ if (r->info402) {
+ _mem_save_info402_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info402, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo402(ndr, NDR_SCALARS|NDR_BUFFERS, r->info402));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info402_0, 0);
+ }
+ break;
+
+ case 403:
+ if (r->info403) {
+ _mem_save_info403_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info403, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo403(ndr, NDR_SCALARS|NDR_BUFFERS, r->info403));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info403_0, 0);
+ }
+ break;
+
+ case 502:
+ if (r->info502) {
+ _mem_save_info502_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info502, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo502(ndr, NDR_SCALARS, r->info502));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info502_0, 0);
+ }
+ break;
+
+ case 503:
+ if (r->info503) {
+ _mem_save_info503_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info503, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo503(ndr, NDR_SCALARS|NDR_BUFFERS, r->info503));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info503_0, 0);
+ }
+ break;
+
+ case 599:
+ if (r->info599) {
+ _mem_save_info599_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info599, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo599(ndr, NDR_SCALARS|NDR_BUFFERS, r->info599));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info599_0, 0);
+ }
+ break;
+
+ case 1005:
+ if (r->info1005) {
+ _mem_save_info1005_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1005, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1005(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1005));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1005_0, 0);
+ }
+ break;
+
+ case 1010:
+ if (r->info1010) {
+ _mem_save_info1010_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1010, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1010(ndr, NDR_SCALARS, r->info1010));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1010_0, 0);
+ }
+ break;
+
+ case 1016:
+ if (r->info1016) {
+ _mem_save_info1016_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1016, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1016(ndr, NDR_SCALARS, r->info1016));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1016_0, 0);
+ }
+ break;
+
+ case 1017:
+ if (r->info1017) {
+ _mem_save_info1017_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1017, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1017(ndr, NDR_SCALARS, r->info1017));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1017_0, 0);
+ }
+ break;
+
+ case 1018:
+ if (r->info1018) {
+ _mem_save_info1018_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1018, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1018(ndr, NDR_SCALARS, r->info1018));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1018_0, 0);
+ }
+ break;
+
+ case 1107:
+ if (r->info1107) {
+ _mem_save_info1107_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1107, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1107(ndr, NDR_SCALARS, r->info1107));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1107_0, 0);
+ }
+ break;
+
+ case 1501:
+ if (r->info1501) {
+ _mem_save_info1501_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1501, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1501(ndr, NDR_SCALARS, r->info1501));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1501_0, 0);
+ }
+ break;
+
+ case 1502:
+ if (r->info1502) {
+ _mem_save_info1502_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1502, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1502(ndr, NDR_SCALARS, r->info1502));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1502_0, 0);
+ }
+ break;
+
+ case 1503:
+ if (r->info1503) {
+ _mem_save_info1503_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1503, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1503(ndr, NDR_SCALARS, r->info1503));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1503_0, 0);
+ }
+ break;
+
+ case 1506:
+ if (r->info1506) {
+ _mem_save_info1506_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1506, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1506(ndr, NDR_SCALARS, r->info1506));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1506_0, 0);
+ }
+ break;
+
+ case 1509:
+ if (r->info1509) {
+ _mem_save_info1509_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1509, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1509(ndr, NDR_SCALARS, r->info1509));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1509_0, 0);
+ }
+ break;
+
+ case 1510:
+ if (r->info1510) {
+ _mem_save_info1510_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1510, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1510(ndr, NDR_SCALARS, r->info1510));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1510_0, 0);
+ }
+ break;
+
+ case 1511:
+ if (r->info1511) {
+ _mem_save_info1511_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1511, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1511(ndr, NDR_SCALARS, r->info1511));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1511_0, 0);
+ }
+ break;
+
+ case 1512:
+ if (r->info1512) {
+ _mem_save_info1512_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1512, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1512(ndr, NDR_SCALARS, r->info1512));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1512_0, 0);
+ }
+ break;
+
+ case 1513:
+ if (r->info1513) {
+ _mem_save_info1513_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1513, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1513(ndr, NDR_SCALARS, r->info1513));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1513_0, 0);
+ }
+ break;
+
+ case 1514:
+ if (r->info1514) {
+ _mem_save_info1514_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1514, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1514(ndr, NDR_SCALARS, r->info1514));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1514_0, 0);
+ }
+ break;
+
+ case 1515:
+ if (r->info1515) {
+ _mem_save_info1515_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1515, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1515(ndr, NDR_SCALARS, r->info1515));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1515_0, 0);
+ }
+ break;
+
+ case 1516:
+ if (r->info1516) {
+ _mem_save_info1516_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1516, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1516(ndr, NDR_SCALARS, r->info1516));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1516_0, 0);
+ }
+ break;
+
+ case 1518:
+ if (r->info1518) {
+ _mem_save_info1518_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1518, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1518(ndr, NDR_SCALARS, r->info1518));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1518_0, 0);
+ }
+ break;
+
+ case 1520:
+ if (r->info1520) {
+ _mem_save_info1520_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1520, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1520(ndr, NDR_SCALARS, r->info1520));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1520_0, 0);
+ }
+ break;
+
+ case 1521:
+ if (r->info1521) {
+ _mem_save_info1521_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1521, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1521(ndr, NDR_SCALARS, r->info1521));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1521_0, 0);
+ }
+ break;
+
+ case 1522:
+ if (r->info1522) {
+ _mem_save_info1522_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1522, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1522(ndr, NDR_SCALARS, r->info1522));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1522_0, 0);
+ }
+ break;
+
+ case 1523:
+ if (r->info1523) {
+ _mem_save_info1523_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1523, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1523(ndr, NDR_SCALARS, r->info1523));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1523_0, 0);
+ }
+ break;
+
+ case 1524:
+ if (r->info1524) {
+ _mem_save_info1524_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1524, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1524(ndr, NDR_SCALARS, r->info1524));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1524_0, 0);
+ }
+ break;
+
+ case 1525:
+ if (r->info1525) {
+ _mem_save_info1525_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1525, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1525(ndr, NDR_SCALARS, r->info1525));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1525_0, 0);
+ }
+ break;
+
+ case 1528:
+ if (r->info1528) {
+ _mem_save_info1528_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1528, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1528(ndr, NDR_SCALARS, r->info1528));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1528_0, 0);
+ }
+ break;
+
+ case 1529:
+ if (r->info1529) {
+ _mem_save_info1529_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1529, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1529(ndr, NDR_SCALARS, r->info1529));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1529_0, 0);
+ }
+ break;
+
+ case 1530:
+ if (r->info1530) {
+ _mem_save_info1530_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1530, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1530(ndr, NDR_SCALARS, r->info1530));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1530_0, 0);
+ }
+ break;
+
+ case 1533:
+ if (r->info1533) {
+ _mem_save_info1533_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1533, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1533(ndr, NDR_SCALARS, r->info1533));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1533_0, 0);
+ }
+ break;
+
+ case 1534:
+ if (r->info1534) {
+ _mem_save_info1534_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1534, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1534(ndr, NDR_SCALARS, r->info1534));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1534_0, 0);
+ }
+ break;
+
+ case 1535:
+ if (r->info1535) {
+ _mem_save_info1535_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1535, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1535(ndr, NDR_SCALARS, r->info1535));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1535_0, 0);
+ }
+ break;
+
+ case 1536:
+ if (r->info1536) {
+ _mem_save_info1536_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1536, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1536(ndr, NDR_SCALARS, r->info1536));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1536_0, 0);
+ }
+ break;
+
+ case 1537:
+ if (r->info1537) {
+ _mem_save_info1537_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1537, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1537(ndr, NDR_SCALARS, r->info1537));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1537_0, 0);
+ }
+ break;
+
+ case 1538:
+ if (r->info1538) {
+ _mem_save_info1538_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1538, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1538(ndr, NDR_SCALARS, r->info1538));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1538_0, 0);
+ }
+ break;
+
+ case 1539:
+ if (r->info1539) {
+ _mem_save_info1539_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1539, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1539(ndr, NDR_SCALARS, r->info1539));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1539_0, 0);
+ }
+ break;
+
+ case 1540:
+ if (r->info1540) {
+ _mem_save_info1540_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1540, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1540(ndr, NDR_SCALARS, r->info1540));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1540_0, 0);
+ }
+ break;
+
+ case 1541:
+ if (r->info1541) {
+ _mem_save_info1541_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1541, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1541(ndr, NDR_SCALARS, r->info1541));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1541_0, 0);
+ }
+ break;
+
+ case 1542:
+ if (r->info1542) {
+ _mem_save_info1542_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1542, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1542(ndr, NDR_SCALARS, r->info1542));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1542_0, 0);
+ }
+ break;
+
+ case 1543:
+ if (r->info1543) {
+ _mem_save_info1543_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1543, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1543(ndr, NDR_SCALARS, r->info1543));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1543_0, 0);
+ }
+ break;
+
+ case 1544:
+ if (r->info1544) {
+ _mem_save_info1544_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1544, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1544(ndr, NDR_SCALARS, r->info1544));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1544_0, 0);
+ }
+ break;
+
+ case 1545:
+ if (r->info1545) {
+ _mem_save_info1545_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1545, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1545(ndr, NDR_SCALARS, r->info1545));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1545_0, 0);
+ }
+ break;
+
+ case 1546:
+ if (r->info1546) {
+ _mem_save_info1546_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1546, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1546(ndr, NDR_SCALARS, r->info1546));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1546_0, 0);
+ }
+ break;
+
+ case 1547:
+ if (r->info1547) {
+ _mem_save_info1547_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1547, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1547(ndr, NDR_SCALARS, r->info1547));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1547_0, 0);
+ }
+ break;
+
+ case 1548:
+ if (r->info1548) {
+ _mem_save_info1548_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1548, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1548(ndr, NDR_SCALARS, r->info1548));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1548_0, 0);
+ }
+ break;
+
+ case 1549:
+ if (r->info1549) {
+ _mem_save_info1549_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1549, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1549(ndr, NDR_SCALARS, r->info1549));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1549_0, 0);
+ }
+ break;
+
+ case 1550:
+ if (r->info1550) {
+ _mem_save_info1550_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1550, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1550(ndr, NDR_SCALARS, r->info1550));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1550_0, 0);
+ }
+ break;
+
+ case 1552:
+ if (r->info1552) {
+ _mem_save_info1552_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1552, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1552(ndr, NDR_SCALARS, r->info1552));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1552_0, 0);
+ }
+ break;
+
+ case 1553:
+ if (r->info1553) {
+ _mem_save_info1553_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1553, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1553(ndr, NDR_SCALARS, r->info1553));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1553_0, 0);
+ }
+ break;
+
+ case 1554:
+ if (r->info1554) {
+ _mem_save_info1554_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1554, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1554(ndr, NDR_SCALARS, r->info1554));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1554_0, 0);
+ }
+ break;
+
+ case 1555:
+ if (r->info1555) {
+ _mem_save_info1555_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1555, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1555(ndr, NDR_SCALARS, r->info1555));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1555_0, 0);
+ }
+ break;
+
+ case 1556:
+ if (r->info1556) {
+ _mem_save_info1556_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1556, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo1556(ndr, NDR_SCALARS, r->info1556));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1556_0, 0);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetSrvInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "srvsvc_NetSrvInfo");
+ switch (level) {
+ case 100:
+ ndr_print_ptr(ndr, "info100", r->info100);
+ ndr->depth++;
+ if (r->info100) {
+ ndr_print_srvsvc_NetSrvInfo100(ndr, "info100", r->info100);
+ }
+ ndr->depth--;
+ break;
+
+ case 101:
+ ndr_print_ptr(ndr, "info101", r->info101);
+ ndr->depth++;
+ if (r->info101) {
+ ndr_print_srvsvc_NetSrvInfo101(ndr, "info101", r->info101);
+ }
+ ndr->depth--;
+ break;
+
+ case 102:
+ ndr_print_ptr(ndr, "info102", r->info102);
+ ndr->depth++;
+ if (r->info102) {
+ ndr_print_srvsvc_NetSrvInfo102(ndr, "info102", r->info102);
+ }
+ ndr->depth--;
+ break;
+
+ case 402:
+ ndr_print_ptr(ndr, "info402", r->info402);
+ ndr->depth++;
+ if (r->info402) {
+ ndr_print_srvsvc_NetSrvInfo402(ndr, "info402", r->info402);
+ }
+ ndr->depth--;
+ break;
+
+ case 403:
+ ndr_print_ptr(ndr, "info403", r->info403);
+ ndr->depth++;
+ if (r->info403) {
+ ndr_print_srvsvc_NetSrvInfo403(ndr, "info403", r->info403);
+ }
+ ndr->depth--;
+ break;
+
+ case 502:
+ ndr_print_ptr(ndr, "info502", r->info502);
+ ndr->depth++;
+ if (r->info502) {
+ ndr_print_srvsvc_NetSrvInfo502(ndr, "info502", r->info502);
+ }
+ ndr->depth--;
+ break;
+
+ case 503:
+ ndr_print_ptr(ndr, "info503", r->info503);
+ ndr->depth++;
+ if (r->info503) {
+ ndr_print_srvsvc_NetSrvInfo503(ndr, "info503", r->info503);
+ }
+ ndr->depth--;
+ break;
+
+ case 599:
+ ndr_print_ptr(ndr, "info599", r->info599);
+ ndr->depth++;
+ if (r->info599) {
+ ndr_print_srvsvc_NetSrvInfo599(ndr, "info599", r->info599);
+ }
+ ndr->depth--;
+ break;
+
+ case 1005:
+ ndr_print_ptr(ndr, "info1005", r->info1005);
+ ndr->depth++;
+ if (r->info1005) {
+ ndr_print_srvsvc_NetSrvInfo1005(ndr, "info1005", r->info1005);
+ }
+ ndr->depth--;
+ break;
+
+ case 1010:
+ ndr_print_ptr(ndr, "info1010", r->info1010);
+ ndr->depth++;
+ if (r->info1010) {
+ ndr_print_srvsvc_NetSrvInfo1010(ndr, "info1010", r->info1010);
+ }
+ ndr->depth--;
+ break;
+
+ case 1016:
+ ndr_print_ptr(ndr, "info1016", r->info1016);
+ ndr->depth++;
+ if (r->info1016) {
+ ndr_print_srvsvc_NetSrvInfo1016(ndr, "info1016", r->info1016);
+ }
+ ndr->depth--;
+ break;
+
+ case 1017:
+ ndr_print_ptr(ndr, "info1017", r->info1017);
+ ndr->depth++;
+ if (r->info1017) {
+ ndr_print_srvsvc_NetSrvInfo1017(ndr, "info1017", r->info1017);
+ }
+ ndr->depth--;
+ break;
+
+ case 1018:
+ ndr_print_ptr(ndr, "info1018", r->info1018);
+ ndr->depth++;
+ if (r->info1018) {
+ ndr_print_srvsvc_NetSrvInfo1018(ndr, "info1018", r->info1018);
+ }
+ ndr->depth--;
+ break;
+
+ case 1107:
+ ndr_print_ptr(ndr, "info1107", r->info1107);
+ ndr->depth++;
+ if (r->info1107) {
+ ndr_print_srvsvc_NetSrvInfo1107(ndr, "info1107", r->info1107);
+ }
+ ndr->depth--;
+ break;
+
+ case 1501:
+ ndr_print_ptr(ndr, "info1501", r->info1501);
+ ndr->depth++;
+ if (r->info1501) {
+ ndr_print_srvsvc_NetSrvInfo1501(ndr, "info1501", r->info1501);
+ }
+ ndr->depth--;
+ break;
+
+ case 1502:
+ ndr_print_ptr(ndr, "info1502", r->info1502);
+ ndr->depth++;
+ if (r->info1502) {
+ ndr_print_srvsvc_NetSrvInfo1502(ndr, "info1502", r->info1502);
+ }
+ ndr->depth--;
+ break;
+
+ case 1503:
+ ndr_print_ptr(ndr, "info1503", r->info1503);
+ ndr->depth++;
+ if (r->info1503) {
+ ndr_print_srvsvc_NetSrvInfo1503(ndr, "info1503", r->info1503);
+ }
+ ndr->depth--;
+ break;
+
+ case 1506:
+ ndr_print_ptr(ndr, "info1506", r->info1506);
+ ndr->depth++;
+ if (r->info1506) {
+ ndr_print_srvsvc_NetSrvInfo1506(ndr, "info1506", r->info1506);
+ }
+ ndr->depth--;
+ break;
+
+ case 1509:
+ ndr_print_ptr(ndr, "info1509", r->info1509);
+ ndr->depth++;
+ if (r->info1509) {
+ ndr_print_srvsvc_NetSrvInfo1509(ndr, "info1509", r->info1509);
+ }
+ ndr->depth--;
+ break;
+
+ case 1510:
+ ndr_print_ptr(ndr, "info1510", r->info1510);
+ ndr->depth++;
+ if (r->info1510) {
+ ndr_print_srvsvc_NetSrvInfo1510(ndr, "info1510", r->info1510);
+ }
+ ndr->depth--;
+ break;
+
+ case 1511:
+ ndr_print_ptr(ndr, "info1511", r->info1511);
+ ndr->depth++;
+ if (r->info1511) {
+ ndr_print_srvsvc_NetSrvInfo1511(ndr, "info1511", r->info1511);
+ }
+ ndr->depth--;
+ break;
+
+ case 1512:
+ ndr_print_ptr(ndr, "info1512", r->info1512);
+ ndr->depth++;
+ if (r->info1512) {
+ ndr_print_srvsvc_NetSrvInfo1512(ndr, "info1512", r->info1512);
+ }
+ ndr->depth--;
+ break;
+
+ case 1513:
+ ndr_print_ptr(ndr, "info1513", r->info1513);
+ ndr->depth++;
+ if (r->info1513) {
+ ndr_print_srvsvc_NetSrvInfo1513(ndr, "info1513", r->info1513);
+ }
+ ndr->depth--;
+ break;
+
+ case 1514:
+ ndr_print_ptr(ndr, "info1514", r->info1514);
+ ndr->depth++;
+ if (r->info1514) {
+ ndr_print_srvsvc_NetSrvInfo1514(ndr, "info1514", r->info1514);
+ }
+ ndr->depth--;
+ break;
+
+ case 1515:
+ ndr_print_ptr(ndr, "info1515", r->info1515);
+ ndr->depth++;
+ if (r->info1515) {
+ ndr_print_srvsvc_NetSrvInfo1515(ndr, "info1515", r->info1515);
+ }
+ ndr->depth--;
+ break;
+
+ case 1516:
+ ndr_print_ptr(ndr, "info1516", r->info1516);
+ ndr->depth++;
+ if (r->info1516) {
+ ndr_print_srvsvc_NetSrvInfo1516(ndr, "info1516", r->info1516);
+ }
+ ndr->depth--;
+ break;
+
+ case 1518:
+ ndr_print_ptr(ndr, "info1518", r->info1518);
+ ndr->depth++;
+ if (r->info1518) {
+ ndr_print_srvsvc_NetSrvInfo1518(ndr, "info1518", r->info1518);
+ }
+ ndr->depth--;
+ break;
+
+ case 1520:
+ ndr_print_ptr(ndr, "info1520", r->info1520);
+ ndr->depth++;
+ if (r->info1520) {
+ ndr_print_srvsvc_NetSrvInfo1520(ndr, "info1520", r->info1520);
+ }
+ ndr->depth--;
+ break;
+
+ case 1521:
+ ndr_print_ptr(ndr, "info1521", r->info1521);
+ ndr->depth++;
+ if (r->info1521) {
+ ndr_print_srvsvc_NetSrvInfo1521(ndr, "info1521", r->info1521);
+ }
+ ndr->depth--;
+ break;
+
+ case 1522:
+ ndr_print_ptr(ndr, "info1522", r->info1522);
+ ndr->depth++;
+ if (r->info1522) {
+ ndr_print_srvsvc_NetSrvInfo1522(ndr, "info1522", r->info1522);
+ }
+ ndr->depth--;
+ break;
+
+ case 1523:
+ ndr_print_ptr(ndr, "info1523", r->info1523);
+ ndr->depth++;
+ if (r->info1523) {
+ ndr_print_srvsvc_NetSrvInfo1523(ndr, "info1523", r->info1523);
+ }
+ ndr->depth--;
+ break;
+
+ case 1524:
+ ndr_print_ptr(ndr, "info1524", r->info1524);
+ ndr->depth++;
+ if (r->info1524) {
+ ndr_print_srvsvc_NetSrvInfo1524(ndr, "info1524", r->info1524);
+ }
+ ndr->depth--;
+ break;
+
+ case 1525:
+ ndr_print_ptr(ndr, "info1525", r->info1525);
+ ndr->depth++;
+ if (r->info1525) {
+ ndr_print_srvsvc_NetSrvInfo1525(ndr, "info1525", r->info1525);
+ }
+ ndr->depth--;
+ break;
+
+ case 1528:
+ ndr_print_ptr(ndr, "info1528", r->info1528);
+ ndr->depth++;
+ if (r->info1528) {
+ ndr_print_srvsvc_NetSrvInfo1528(ndr, "info1528", r->info1528);
+ }
+ ndr->depth--;
+ break;
+
+ case 1529:
+ ndr_print_ptr(ndr, "info1529", r->info1529);
+ ndr->depth++;
+ if (r->info1529) {
+ ndr_print_srvsvc_NetSrvInfo1529(ndr, "info1529", r->info1529);
+ }
+ ndr->depth--;
+ break;
+
+ case 1530:
+ ndr_print_ptr(ndr, "info1530", r->info1530);
+ ndr->depth++;
+ if (r->info1530) {
+ ndr_print_srvsvc_NetSrvInfo1530(ndr, "info1530", r->info1530);
+ }
+ ndr->depth--;
+ break;
+
+ case 1533:
+ ndr_print_ptr(ndr, "info1533", r->info1533);
+ ndr->depth++;
+ if (r->info1533) {
+ ndr_print_srvsvc_NetSrvInfo1533(ndr, "info1533", r->info1533);
+ }
+ ndr->depth--;
+ break;
+
+ case 1534:
+ ndr_print_ptr(ndr, "info1534", r->info1534);
+ ndr->depth++;
+ if (r->info1534) {
+ ndr_print_srvsvc_NetSrvInfo1534(ndr, "info1534", r->info1534);
+ }
+ ndr->depth--;
+ break;
+
+ case 1535:
+ ndr_print_ptr(ndr, "info1535", r->info1535);
+ ndr->depth++;
+ if (r->info1535) {
+ ndr_print_srvsvc_NetSrvInfo1535(ndr, "info1535", r->info1535);
+ }
+ ndr->depth--;
+ break;
+
+ case 1536:
+ ndr_print_ptr(ndr, "info1536", r->info1536);
+ ndr->depth++;
+ if (r->info1536) {
+ ndr_print_srvsvc_NetSrvInfo1536(ndr, "info1536", r->info1536);
+ }
+ ndr->depth--;
+ break;
+
+ case 1537:
+ ndr_print_ptr(ndr, "info1537", r->info1537);
+ ndr->depth++;
+ if (r->info1537) {
+ ndr_print_srvsvc_NetSrvInfo1537(ndr, "info1537", r->info1537);
+ }
+ ndr->depth--;
+ break;
+
+ case 1538:
+ ndr_print_ptr(ndr, "info1538", r->info1538);
+ ndr->depth++;
+ if (r->info1538) {
+ ndr_print_srvsvc_NetSrvInfo1538(ndr, "info1538", r->info1538);
+ }
+ ndr->depth--;
+ break;
+
+ case 1539:
+ ndr_print_ptr(ndr, "info1539", r->info1539);
+ ndr->depth++;
+ if (r->info1539) {
+ ndr_print_srvsvc_NetSrvInfo1539(ndr, "info1539", r->info1539);
+ }
+ ndr->depth--;
+ break;
+
+ case 1540:
+ ndr_print_ptr(ndr, "info1540", r->info1540);
+ ndr->depth++;
+ if (r->info1540) {
+ ndr_print_srvsvc_NetSrvInfo1540(ndr, "info1540", r->info1540);
+ }
+ ndr->depth--;
+ break;
+
+ case 1541:
+ ndr_print_ptr(ndr, "info1541", r->info1541);
+ ndr->depth++;
+ if (r->info1541) {
+ ndr_print_srvsvc_NetSrvInfo1541(ndr, "info1541", r->info1541);
+ }
+ ndr->depth--;
+ break;
+
+ case 1542:
+ ndr_print_ptr(ndr, "info1542", r->info1542);
+ ndr->depth++;
+ if (r->info1542) {
+ ndr_print_srvsvc_NetSrvInfo1542(ndr, "info1542", r->info1542);
+ }
+ ndr->depth--;
+ break;
+
+ case 1543:
+ ndr_print_ptr(ndr, "info1543", r->info1543);
+ ndr->depth++;
+ if (r->info1543) {
+ ndr_print_srvsvc_NetSrvInfo1543(ndr, "info1543", r->info1543);
+ }
+ ndr->depth--;
+ break;
+
+ case 1544:
+ ndr_print_ptr(ndr, "info1544", r->info1544);
+ ndr->depth++;
+ if (r->info1544) {
+ ndr_print_srvsvc_NetSrvInfo1544(ndr, "info1544", r->info1544);
+ }
+ ndr->depth--;
+ break;
+
+ case 1545:
+ ndr_print_ptr(ndr, "info1545", r->info1545);
+ ndr->depth++;
+ if (r->info1545) {
+ ndr_print_srvsvc_NetSrvInfo1545(ndr, "info1545", r->info1545);
+ }
+ ndr->depth--;
+ break;
+
+ case 1546:
+ ndr_print_ptr(ndr, "info1546", r->info1546);
+ ndr->depth++;
+ if (r->info1546) {
+ ndr_print_srvsvc_NetSrvInfo1546(ndr, "info1546", r->info1546);
+ }
+ ndr->depth--;
+ break;
+
+ case 1547:
+ ndr_print_ptr(ndr, "info1547", r->info1547);
+ ndr->depth++;
+ if (r->info1547) {
+ ndr_print_srvsvc_NetSrvInfo1547(ndr, "info1547", r->info1547);
+ }
+ ndr->depth--;
+ break;
+
+ case 1548:
+ ndr_print_ptr(ndr, "info1548", r->info1548);
+ ndr->depth++;
+ if (r->info1548) {
+ ndr_print_srvsvc_NetSrvInfo1548(ndr, "info1548", r->info1548);
+ }
+ ndr->depth--;
+ break;
+
+ case 1549:
+ ndr_print_ptr(ndr, "info1549", r->info1549);
+ ndr->depth++;
+ if (r->info1549) {
+ ndr_print_srvsvc_NetSrvInfo1549(ndr, "info1549", r->info1549);
+ }
+ ndr->depth--;
+ break;
+
+ case 1550:
+ ndr_print_ptr(ndr, "info1550", r->info1550);
+ ndr->depth++;
+ if (r->info1550) {
+ ndr_print_srvsvc_NetSrvInfo1550(ndr, "info1550", r->info1550);
+ }
+ ndr->depth--;
+ break;
+
+ case 1552:
+ ndr_print_ptr(ndr, "info1552", r->info1552);
+ ndr->depth++;
+ if (r->info1552) {
+ ndr_print_srvsvc_NetSrvInfo1552(ndr, "info1552", r->info1552);
+ }
+ ndr->depth--;
+ break;
+
+ case 1553:
+ ndr_print_ptr(ndr, "info1553", r->info1553);
+ ndr->depth++;
+ if (r->info1553) {
+ ndr_print_srvsvc_NetSrvInfo1553(ndr, "info1553", r->info1553);
+ }
+ ndr->depth--;
+ break;
+
+ case 1554:
+ ndr_print_ptr(ndr, "info1554", r->info1554);
+ ndr->depth++;
+ if (r->info1554) {
+ ndr_print_srvsvc_NetSrvInfo1554(ndr, "info1554", r->info1554);
+ }
+ ndr->depth--;
+ break;
+
+ case 1555:
+ ndr_print_ptr(ndr, "info1555", r->info1555);
+ ndr->depth++;
+ if (r->info1555) {
+ ndr_print_srvsvc_NetSrvInfo1555(ndr, "info1555", r->info1555);
+ }
+ ndr->depth--;
+ break;
+
+ case 1556:
+ ndr_print_ptr(ndr, "info1556", r->info1556);
+ ndr->depth++;
+ if (r->info1556) {
+ ndr_print_srvsvc_NetSrvInfo1556(ndr, "info1556", r->info1556);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetDiskInfo0(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetDiskInfo0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_LEN4);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->disk));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetDiskInfo0(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetDiskInfo0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_LEN4);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->disk));
+ ndr->flags = _flags_save_string;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetDiskInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetDiskInfo0 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetDiskInfo0");
+ ndr->depth++;
+ ndr_print_string(ndr, "disk", r->disk);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetDiskInfo(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetDiskInfo *r)
+{
+ uint32_t cntr_disks_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->disks));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->disks) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_disks_1 = 0; cntr_disks_1 < r->count; cntr_disks_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetDiskInfo0(ndr, NDR_SCALARS, &r->disks[cntr_disks_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetDiskInfo(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetDiskInfo *r)
+{
+ uint32_t _ptr_disks;
+ uint32_t cntr_disks_1;
+ TALLOC_CTX *_mem_save_disks_0;
+ TALLOC_CTX *_mem_save_disks_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_disks));
+ if (_ptr_disks) {
+ NDR_PULL_ALLOC(ndr, r->disks);
+ } else {
+ r->disks = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->disks) {
+ _mem_save_disks_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->disks, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->disks));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->disks));
+ if (ndr_get_array_length(ndr, &r->disks) > ndr_get_array_size(ndr, &r->disks)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->disks), ndr_get_array_length(ndr, &r->disks));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->disks, ndr_get_array_size(ndr, &r->disks));
+ _mem_save_disks_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->disks, 0);
+ for (cntr_disks_1 = 0; cntr_disks_1 < r->count; cntr_disks_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetDiskInfo0(ndr, NDR_SCALARS, &r->disks[cntr_disks_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_disks_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_disks_0, 0);
+ }
+ if (r->disks) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->disks, r->count));
+ }
+ if (r->disks) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->disks, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetDiskInfo(struct ndr_print *ndr, const char *name, const struct srvsvc_NetDiskInfo *r)
+{
+ uint32_t cntr_disks_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetDiskInfo");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "disks", r->disks);
+ ndr->depth++;
+ if (r->disks) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "disks", (int)r->count);
+ ndr->depth++;
+ for (cntr_disks_1=0;cntr_disks_1<r->count;cntr_disks_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_disks_1) != -1) {
+ ndr_print_srvsvc_NetDiskInfo0(ndr, "disks", &r->disks[cntr_disks_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_Statistics(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_Statistics *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->start));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->fopens));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->devopens));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->jobsqueued));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sopens));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->stimeouts));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->serrorout));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pwerrors));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->permerrors));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->syserrors));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->bytessent_low));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->bytessent_high));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->bytesrcvd_low));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->bytesrcvd_high));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->avresponse));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->reqbufneed));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->bigbufneed));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_Statistics(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_Statistics *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->start));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->fopens));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->devopens));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->jobsqueued));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sopens));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->stimeouts));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->serrorout));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pwerrors));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->permerrors));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->syserrors));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->bytessent_low));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->bytessent_high));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->bytesrcvd_low));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->bytesrcvd_high));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->avresponse));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->reqbufneed));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->bigbufneed));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_Statistics(struct ndr_print *ndr, const char *name, const struct srvsvc_Statistics *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_Statistics");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "start", r->start);
+ ndr_print_uint32(ndr, "fopens", r->fopens);
+ ndr_print_uint32(ndr, "devopens", r->devopens);
+ ndr_print_uint32(ndr, "jobsqueued", r->jobsqueued);
+ ndr_print_uint32(ndr, "sopens", r->sopens);
+ ndr_print_uint32(ndr, "stimeouts", r->stimeouts);
+ ndr_print_uint32(ndr, "serrorout", r->serrorout);
+ ndr_print_uint32(ndr, "pwerrors", r->pwerrors);
+ ndr_print_uint32(ndr, "permerrors", r->permerrors);
+ ndr_print_uint32(ndr, "syserrors", r->syserrors);
+ ndr_print_uint32(ndr, "bytessent_low", r->bytessent_low);
+ ndr_print_uint32(ndr, "bytessent_high", r->bytessent_high);
+ ndr_print_uint32(ndr, "bytesrcvd_low", r->bytesrcvd_low);
+ ndr_print_uint32(ndr, "bytesrcvd_high", r->bytesrcvd_high);
+ ndr_print_uint32(ndr, "avresponse", r->avresponse);
+ ndr_print_uint32(ndr, "reqbufneed", r->reqbufneed);
+ ndr_print_uint32(ndr, "bigbufneed", r->bigbufneed);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetTransportInfo0(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetTransportInfo0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->vcs));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->addr));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->addr_len));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->net_addr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, ndr_charset_length(r->name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->addr) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->addr_len));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->addr, r->addr_len));
+ }
+ if (r->net_addr) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->net_addr, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->net_addr, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->net_addr, ndr_charset_length(r->net_addr, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetTransportInfo0(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetTransportInfo0 *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_name_0;
+ uint32_t _ptr_addr;
+ TALLOC_CTX *_mem_save_addr_0;
+ uint32_t _ptr_net_addr;
+ TALLOC_CTX *_mem_save_net_addr_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->vcs));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_addr));
+ if (_ptr_addr) {
+ NDR_PULL_ALLOC(ndr, r->addr);
+ } else {
+ r->addr = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->addr_len));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_net_addr));
+ if (_ptr_net_addr) {
+ NDR_PULL_ALLOC(ndr, r->net_addr);
+ } else {
+ r->net_addr = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->name));
+ if (ndr_get_array_length(ndr, &r->name) > ndr_get_array_size(ndr, &r->name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->name), ndr_get_array_length(ndr, &r->name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ if (r->addr) {
+ _mem_save_addr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->addr, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->addr));
+ NDR_PULL_ALLOC_N(ndr, r->addr, ndr_get_array_size(ndr, &r->addr));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->addr, ndr_get_array_size(ndr, &r->addr)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_addr_0, 0);
+ }
+ if (r->net_addr) {
+ _mem_save_net_addr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->net_addr, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->net_addr));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->net_addr));
+ if (ndr_get_array_length(ndr, &r->net_addr) > ndr_get_array_size(ndr, &r->net_addr)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->net_addr), ndr_get_array_length(ndr, &r->net_addr));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->net_addr), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->net_addr, ndr_get_array_length(ndr, &r->net_addr), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_net_addr_0, 0);
+ }
+ if (r->addr) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->addr, r->addr_len));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetTransportInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportInfo0 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetTransportInfo0");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "vcs", r->vcs);
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_string(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "addr", r->addr);
+ ndr->depth++;
+ if (r->addr) {
+ ndr_print_array_uint8(ndr, "addr", r->addr, r->addr_len);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "addr_len", r->addr_len);
+ ndr_print_ptr(ndr, "net_addr", r->net_addr);
+ ndr->depth++;
+ if (r->net_addr) {
+ ndr_print_string(ndr, "net_addr", r->net_addr);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetTransportCtr0(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetTransportCtr0 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo0(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo0(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetTransportCtr0(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetTransportCtr0 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo0(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo0(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetTransportCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportCtr0 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetTransportCtr0");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetTransportInfo0(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetTransportInfo1(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetTransportInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->vcs));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->addr));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->addr_len));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->net_addr));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, ndr_charset_length(r->name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->addr) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->addr_len));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->addr, r->addr_len));
+ }
+ if (r->net_addr) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->net_addr, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->net_addr, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->net_addr, ndr_charset_length(r->net_addr, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->domain) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain, ndr_charset_length(r->domain, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetTransportInfo1(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetTransportInfo1 *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_name_0;
+ uint32_t _ptr_addr;
+ TALLOC_CTX *_mem_save_addr_0;
+ uint32_t _ptr_net_addr;
+ TALLOC_CTX *_mem_save_net_addr_0;
+ uint32_t _ptr_domain;
+ TALLOC_CTX *_mem_save_domain_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->vcs));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_addr));
+ if (_ptr_addr) {
+ NDR_PULL_ALLOC(ndr, r->addr);
+ } else {
+ r->addr = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->addr_len));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_net_addr));
+ if (_ptr_net_addr) {
+ NDR_PULL_ALLOC(ndr, r->net_addr);
+ } else {
+ r->net_addr = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain));
+ if (_ptr_domain) {
+ NDR_PULL_ALLOC(ndr, r->domain);
+ } else {
+ r->domain = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->name));
+ if (ndr_get_array_length(ndr, &r->name) > ndr_get_array_size(ndr, &r->name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->name), ndr_get_array_length(ndr, &r->name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ if (r->addr) {
+ _mem_save_addr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->addr, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->addr));
+ NDR_PULL_ALLOC_N(ndr, r->addr, ndr_get_array_size(ndr, &r->addr));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->addr, ndr_get_array_size(ndr, &r->addr)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_addr_0, 0);
+ }
+ if (r->net_addr) {
+ _mem_save_net_addr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->net_addr, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->net_addr));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->net_addr));
+ if (ndr_get_array_length(ndr, &r->net_addr) > ndr_get_array_size(ndr, &r->net_addr)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->net_addr), ndr_get_array_length(ndr, &r->net_addr));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->net_addr), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->net_addr, ndr_get_array_length(ndr, &r->net_addr), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_net_addr_0, 0);
+ }
+ if (r->domain) {
+ _mem_save_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain));
+ if (ndr_get_array_length(ndr, &r->domain) > ndr_get_array_size(ndr, &r->domain)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain), ndr_get_array_length(ndr, &r->domain));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_0, 0);
+ }
+ if (r->addr) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->addr, r->addr_len));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetTransportInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportInfo1 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetTransportInfo1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "vcs", r->vcs);
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_string(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "addr", r->addr);
+ ndr->depth++;
+ if (r->addr) {
+ ndr_print_array_uint8(ndr, "addr", r->addr, r->addr_len);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "addr_len", r->addr_len);
+ ndr_print_ptr(ndr, "net_addr", r->net_addr);
+ ndr->depth++;
+ if (r->net_addr) {
+ ndr_print_string(ndr, "net_addr", r->net_addr);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain", r->domain);
+ ndr->depth++;
+ if (r->domain) {
+ ndr_print_string(ndr, "domain", r->domain);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetTransportCtr1(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetTransportCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetTransportCtr1(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetTransportCtr1 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetTransportCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetTransportCtr1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetTransportInfo1(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetTransportInfo2(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetTransportInfo2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->vcs));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->addr));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->addr_len));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->net_addr));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, ndr_charset_length(r->name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->addr) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->addr_len));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->addr, r->addr_len));
+ }
+ if (r->net_addr) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->net_addr, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->net_addr, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->net_addr, ndr_charset_length(r->net_addr, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->domain) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain, ndr_charset_length(r->domain, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetTransportInfo2(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetTransportInfo2 *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_name_0;
+ uint32_t _ptr_addr;
+ TALLOC_CTX *_mem_save_addr_0;
+ uint32_t _ptr_net_addr;
+ TALLOC_CTX *_mem_save_net_addr_0;
+ uint32_t _ptr_domain;
+ TALLOC_CTX *_mem_save_domain_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->vcs));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_addr));
+ if (_ptr_addr) {
+ NDR_PULL_ALLOC(ndr, r->addr);
+ } else {
+ r->addr = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->addr_len));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_net_addr));
+ if (_ptr_net_addr) {
+ NDR_PULL_ALLOC(ndr, r->net_addr);
+ } else {
+ r->net_addr = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain));
+ if (_ptr_domain) {
+ NDR_PULL_ALLOC(ndr, r->domain);
+ } else {
+ r->domain = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->name));
+ if (ndr_get_array_length(ndr, &r->name) > ndr_get_array_size(ndr, &r->name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->name), ndr_get_array_length(ndr, &r->name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ if (r->addr) {
+ _mem_save_addr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->addr, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->addr));
+ NDR_PULL_ALLOC_N(ndr, r->addr, ndr_get_array_size(ndr, &r->addr));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->addr, ndr_get_array_size(ndr, &r->addr)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_addr_0, 0);
+ }
+ if (r->net_addr) {
+ _mem_save_net_addr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->net_addr, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->net_addr));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->net_addr));
+ if (ndr_get_array_length(ndr, &r->net_addr) > ndr_get_array_size(ndr, &r->net_addr)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->net_addr), ndr_get_array_length(ndr, &r->net_addr));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->net_addr), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->net_addr, ndr_get_array_length(ndr, &r->net_addr), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_net_addr_0, 0);
+ }
+ if (r->domain) {
+ _mem_save_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain));
+ if (ndr_get_array_length(ndr, &r->domain) > ndr_get_array_size(ndr, &r->domain)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain), ndr_get_array_length(ndr, &r->domain));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_0, 0);
+ }
+ if (r->addr) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->addr, r->addr_len));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetTransportInfo2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportInfo2 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetTransportInfo2");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "vcs", r->vcs);
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_string(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "addr", r->addr);
+ ndr->depth++;
+ if (r->addr) {
+ ndr_print_array_uint8(ndr, "addr", r->addr, r->addr_len);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "addr_len", r->addr_len);
+ ndr_print_ptr(ndr, "net_addr", r->net_addr);
+ ndr->depth++;
+ if (r->net_addr) {
+ ndr_print_string(ndr, "net_addr", r->net_addr);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain", r->domain);
+ ndr->depth++;
+ if (r->domain) {
+ ndr_print_string(ndr, "domain", r->domain);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown", r->unknown);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetTransportCtr2(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetTransportCtr2 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo2(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo2(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetTransportCtr2(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetTransportCtr2 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo2(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo2(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetTransportCtr2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportCtr2 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetTransportCtr2");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetTransportInfo2(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetTransportInfo3(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetTransportInfo3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->vcs));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->addr));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->addr_len));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->net_addr));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown2));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->unknown3, 256));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, ndr_charset_length(r->name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->addr) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->addr_len));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->addr, r->addr_len));
+ }
+ if (r->net_addr) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->net_addr, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->net_addr, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->net_addr, ndr_charset_length(r->net_addr, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->domain) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain, ndr_charset_length(r->domain, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetTransportInfo3(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetTransportInfo3 *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_name_0;
+ uint32_t _ptr_addr;
+ TALLOC_CTX *_mem_save_addr_0;
+ uint32_t _ptr_net_addr;
+ TALLOC_CTX *_mem_save_net_addr_0;
+ uint32_t _ptr_domain;
+ TALLOC_CTX *_mem_save_domain_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->vcs));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_addr));
+ if (_ptr_addr) {
+ NDR_PULL_ALLOC(ndr, r->addr);
+ } else {
+ r->addr = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->addr_len));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_net_addr));
+ if (_ptr_net_addr) {
+ NDR_PULL_ALLOC(ndr, r->net_addr);
+ } else {
+ r->net_addr = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain));
+ if (_ptr_domain) {
+ NDR_PULL_ALLOC(ndr, r->domain);
+ } else {
+ r->domain = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->unknown3, 256));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->name));
+ if (ndr_get_array_length(ndr, &r->name) > ndr_get_array_size(ndr, &r->name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->name), ndr_get_array_length(ndr, &r->name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ if (r->addr) {
+ _mem_save_addr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->addr, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->addr));
+ NDR_PULL_ALLOC_N(ndr, r->addr, ndr_get_array_size(ndr, &r->addr));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->addr, ndr_get_array_size(ndr, &r->addr)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_addr_0, 0);
+ }
+ if (r->net_addr) {
+ _mem_save_net_addr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->net_addr, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->net_addr));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->net_addr));
+ if (ndr_get_array_length(ndr, &r->net_addr) > ndr_get_array_size(ndr, &r->net_addr)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->net_addr), ndr_get_array_length(ndr, &r->net_addr));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->net_addr), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->net_addr, ndr_get_array_length(ndr, &r->net_addr), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_net_addr_0, 0);
+ }
+ if (r->domain) {
+ _mem_save_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain));
+ if (ndr_get_array_length(ndr, &r->domain) > ndr_get_array_size(ndr, &r->domain)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain), ndr_get_array_length(ndr, &r->domain));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain, ndr_get_array_length(ndr, &r->domain), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_0, 0);
+ }
+ if (r->addr) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->addr, r->addr_len));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetTransportInfo3(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportInfo3 *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetTransportInfo3");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "vcs", r->vcs);
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_string(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "addr", r->addr);
+ ndr->depth++;
+ if (r->addr) {
+ ndr_print_array_uint8(ndr, "addr", r->addr, r->addr_len);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "addr_len", r->addr_len);
+ ndr_print_ptr(ndr, "net_addr", r->net_addr);
+ ndr->depth++;
+ if (r->net_addr) {
+ ndr_print_string(ndr, "net_addr", r->net_addr);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain", r->domain);
+ ndr->depth++;
+ if (r->domain) {
+ ndr_print_string(ndr, "domain", r->domain);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown1", r->unknown1);
+ ndr_print_uint32(ndr, "unknown2", r->unknown2);
+ ndr_print_array_uint8(ndr, "unknown3", r->unknown3, 256);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetTransportCtr3(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetTransportCtr3 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo3(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo3(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetTransportCtr3(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetTransportCtr3 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo3(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo3(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetTransportCtr3(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportCtr3 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "srvsvc_NetTransportCtr3");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_srvsvc_NetTransportInfo3(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetTransportCtr(struct ndr_push *ndr, int ndr_flags, const union srvsvc_NetTransportCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr0));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr3));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ if (r->ctr0) {
+ NDR_CHECK(ndr_push_srvsvc_NetTransportCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr0));
+ }
+ break;
+
+ case 1:
+ if (r->ctr1) {
+ NDR_CHECK(ndr_push_srvsvc_NetTransportCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ }
+ break;
+
+ case 2:
+ if (r->ctr2) {
+ NDR_CHECK(ndr_push_srvsvc_NetTransportCtr2(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr2));
+ }
+ break;
+
+ case 3:
+ if (r->ctr3) {
+ NDR_CHECK(ndr_push_srvsvc_NetTransportCtr3(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr3));
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetTransportCtr(struct ndr_pull *ndr, int ndr_flags, union srvsvc_NetTransportCtr *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_ctr0_0;
+ TALLOC_CTX *_mem_save_ctr1_0;
+ TALLOC_CTX *_mem_save_ctr2_0;
+ TALLOC_CTX *_mem_save_ctr3_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 0: {
+ uint32_t _ptr_ctr0;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr0));
+ if (_ptr_ctr0) {
+ NDR_PULL_ALLOC(ndr, r->ctr0);
+ } else {
+ r->ctr0 = NULL;
+ }
+ break; }
+
+ case 1: {
+ uint32_t _ptr_ctr1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr1));
+ if (_ptr_ctr1) {
+ NDR_PULL_ALLOC(ndr, r->ctr1);
+ } else {
+ r->ctr1 = NULL;
+ }
+ break; }
+
+ case 2: {
+ uint32_t _ptr_ctr2;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr2));
+ if (_ptr_ctr2) {
+ NDR_PULL_ALLOC(ndr, r->ctr2);
+ } else {
+ r->ctr2 = NULL;
+ }
+ break; }
+
+ case 3: {
+ uint32_t _ptr_ctr3;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr3));
+ if (_ptr_ctr3) {
+ NDR_PULL_ALLOC(ndr, r->ctr3);
+ } else {
+ r->ctr3 = NULL;
+ }
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ if (r->ctr0) {
+ _mem_save_ctr0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr0, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr0_0, 0);
+ }
+ break;
+
+ case 1:
+ if (r->ctr1) {
+ _mem_save_ctr1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr1, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr1_0, 0);
+ }
+ break;
+
+ case 2:
+ if (r->ctr2) {
+ _mem_save_ctr2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr2, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportCtr2(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr2_0, 0);
+ }
+ break;
+
+ case 3:
+ if (r->ctr3) {
+ _mem_save_ctr3_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr3, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportCtr3(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr3));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr3_0, 0);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetTransportCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetTransportCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "srvsvc_NetTransportCtr");
+ switch (level) {
+ case 0:
+ ndr_print_ptr(ndr, "ctr0", r->ctr0);
+ ndr->depth++;
+ if (r->ctr0) {
+ ndr_print_srvsvc_NetTransportCtr0(ndr, "ctr0", r->ctr0);
+ }
+ ndr->depth--;
+ break;
+
+ case 1:
+ ndr_print_ptr(ndr, "ctr1", r->ctr1);
+ ndr->depth++;
+ if (r->ctr1) {
+ ndr_print_srvsvc_NetTransportCtr1(ndr, "ctr1", r->ctr1);
+ }
+ ndr->depth--;
+ break;
+
+ case 2:
+ ndr_print_ptr(ndr, "ctr2", r->ctr2);
+ ndr->depth++;
+ if (r->ctr2) {
+ ndr_print_srvsvc_NetTransportCtr2(ndr, "ctr2", r->ctr2);
+ }
+ ndr->depth--;
+ break;
+
+ case 3:
+ ndr_print_ptr(ndr, "ctr3", r->ctr3);
+ ndr->depth++;
+ if (r->ctr3) {
+ ndr_print_srvsvc_NetTransportCtr3(ndr, "ctr3", r->ctr3);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetRemoteTODInfo(struct ndr_push *ndr, int ndr_flags, const struct srvsvc_NetRemoteTODInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->elapsed));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->msecs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->hours));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->mins));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->secs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->hunds));
+ NDR_CHECK(ndr_push_int32(ndr, NDR_SCALARS, r->timezone));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->tinterval));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->day));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->month));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->year));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->weekday));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetRemoteTODInfo(struct ndr_pull *ndr, int ndr_flags, struct srvsvc_NetRemoteTODInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->elapsed));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->msecs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->hours));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->mins));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->secs));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->hunds));
+ NDR_CHECK(ndr_pull_int32(ndr, NDR_SCALARS, &r->timezone));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->tinterval));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->day));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->month));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->year));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->weekday));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetRemoteTODInfo(struct ndr_print *ndr, const char *name, const struct srvsvc_NetRemoteTODInfo *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetRemoteTODInfo");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "elapsed", r->elapsed);
+ ndr_print_uint32(ndr, "msecs", r->msecs);
+ ndr_print_uint32(ndr, "hours", r->hours);
+ ndr_print_uint32(ndr, "mins", r->mins);
+ ndr_print_uint32(ndr, "secs", r->secs);
+ ndr_print_uint32(ndr, "hunds", r->hunds);
+ ndr_print_int32(ndr, "timezone", r->timezone);
+ ndr_print_uint32(ndr, "tinterval", r->tinterval);
+ ndr_print_uint32(ndr, "day", r->day);
+ ndr_print_uint32(ndr, "month", r->month);
+ ndr_print_uint32(ndr, "year", r->year);
+ ndr_print_uint32(ndr, "weekday", r->weekday);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetTransportInfo(struct ndr_push *ndr, int ndr_flags, const union srvsvc_NetTransportInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo0(ndr, NDR_SCALARS, &r->info0));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo1(ndr, NDR_SCALARS, &r->info1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo2(ndr, NDR_SCALARS, &r->info2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo3(ndr, NDR_SCALARS, &r->info3));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo0(ndr, NDR_BUFFERS, &r->info0));
+ break;
+
+ case 1:
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo1(ndr, NDR_BUFFERS, &r->info1));
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo2(ndr, NDR_BUFFERS, &r->info2));
+ break;
+
+ case 3:
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo3(ndr, NDR_BUFFERS, &r->info3));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetTransportInfo(struct ndr_pull *ndr, int ndr_flags, union srvsvc_NetTransportInfo *r)
+{
+ int level;
+ uint32_t _level;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo0(ndr, NDR_SCALARS, &r->info0));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo1(ndr, NDR_SCALARS, &r->info1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo2(ndr, NDR_SCALARS, &r->info2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo3(ndr, NDR_SCALARS, &r->info3));
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo0(ndr, NDR_BUFFERS, &r->info0));
+ break;
+
+ case 1:
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo1(ndr, NDR_BUFFERS, &r->info1));
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo2(ndr, NDR_BUFFERS, &r->info2));
+ break;
+
+ case 3:
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo3(ndr, NDR_BUFFERS, &r->info3));
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetTransportInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetTransportInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "srvsvc_NetTransportInfo");
+ switch (level) {
+ case 0:
+ ndr_print_srvsvc_NetTransportInfo0(ndr, "info0", &r->info0);
+ break;
+
+ case 1:
+ ndr_print_srvsvc_NetTransportInfo1(ndr, "info1", &r->info1);
+ break;
+
+ case 2:
+ ndr_print_srvsvc_NetTransportInfo2(ndr, "info2", &r->info2);
+ break;
+
+ case 3:
+ ndr_print_srvsvc_NetTransportInfo3(ndr, "info3", &r->info3);
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevEnum(struct ndr_push *ndr, int flags, const struct srvsvc_NetCharDevEnum *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.level == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.level));
+ if (r->in.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.ctr, *r->in.level));
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.ctr));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_buffer));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.resume_handle));
+ if (r->in.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.level == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.level));
+ if (r->out.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.ctr, *r->out.level));
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ if (r->out.totalentries == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.totalentries));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.resume_handle));
+ if (r->out.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevEnum(struct ndr_pull *ndr, int flags, struct srvsvc_NetCharDevEnum *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_resume_handle;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_level_0;
+ TALLOC_CTX *_mem_save_ctr_0;
+ TALLOC_CTX *_mem_save_totalentries_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.level);
+ }
+ _mem_save_level_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.level, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.level));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.ctr, *r->in.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_buffer));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ } else {
+ r->in.resume_handle = NULL;
+ }
+ if (r->in.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.level);
+ *r->out.level = *r->in.level;
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ *r->out.ctr = *r->in.ctr;
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ ZERO_STRUCTP(r->out.totalentries);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.level);
+ }
+ _mem_save_level_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.level, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.level));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.ctr, *r->out.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ }
+ _mem_save_totalentries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.totalentries, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.totalentries));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_totalentries_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ } else {
+ r->out.resume_handle = NULL;
+ }
+ if (r->out.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevEnum *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetCharDevEnum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetCharDevEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "level", r->in.level);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level", *r->in.level);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ctr", r->in.ctr);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.ctr, *r->in.level);
+ ndr_print_srvsvc_NetCharDevCtr(ndr, "ctr", r->in.ctr);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_buffer", r->in.max_buffer);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ if (r->in.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetCharDevEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "level", r->out.level);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level", *r->out.level);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ctr", r->out.ctr);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.ctr, *r->out.level);
+ ndr_print_srvsvc_NetCharDevCtr(ndr, "ctr", r->out.ctr);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "totalentries", r->out.totalentries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "totalentries", *r->out.totalentries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ if (r->out.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevGetInfo(struct ndr_push *ndr, int flags, const struct srvsvc_NetCharDevGetInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.device_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.device_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.device_name, ndr_charset_length(r->in.device_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevGetInfo(struct ndr_pull *ndr, int flags, struct srvsvc_NetCharDevGetInfo *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.device_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.device_name));
+ if (ndr_get_array_length(ndr, &r->in.device_name) > ndr_get_array_size(ndr, &r->in.device_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.device_name), ndr_get_array_length(ndr, &r->in.device_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.device_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.device_name, ndr_get_array_length(ndr, &r->in.device_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevGetInfo *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetCharDevGetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetCharDevGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "device_name", r->in.device_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetCharDevGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, r->in.level);
+ ndr_print_srvsvc_NetCharDevInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevControl(struct ndr_push *ndr, int flags, const struct srvsvc_NetCharDevControl *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.device_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.device_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.device_name, ndr_charset_length(r->in.device_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.opcode));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevControl(struct ndr_pull *ndr, int flags, struct srvsvc_NetCharDevControl *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.device_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.device_name));
+ if (ndr_get_array_length(ndr, &r->in.device_name) > ndr_get_array_size(ndr, &r->in.device_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.device_name), ndr_get_array_length(ndr, &r->in.device_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.device_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.device_name, ndr_get_array_length(ndr, &r->in.device_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.opcode));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevControl(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevControl *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetCharDevControl");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetCharDevControl");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "device_name", r->in.device_name);
+ ndr_print_uint32(ndr, "opcode", r->in.opcode);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetCharDevControl");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevQEnum(struct ndr_push *ndr, int flags, const struct srvsvc_NetCharDevQEnum *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.user));
+ if (r->in.user) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.user, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.user, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.user, ndr_charset_length(r->in.user, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.level == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.level));
+ if (r->in.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.ctr, *r->in.level));
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevQCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.ctr));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_buffer));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.resume_handle));
+ if (r->in.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.level == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.level));
+ if (r->out.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.ctr, *r->out.level));
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevQCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ if (r->out.totalentries == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.totalentries));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.resume_handle));
+ if (r->out.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevQEnum(struct ndr_pull *ndr, int flags, struct srvsvc_NetCharDevQEnum *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_user;
+ uint32_t _ptr_resume_handle;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_user_0;
+ TALLOC_CTX *_mem_save_level_0;
+ TALLOC_CTX *_mem_save_ctr_0;
+ TALLOC_CTX *_mem_save_totalentries_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user));
+ if (_ptr_user) {
+ NDR_PULL_ALLOC(ndr, r->in.user);
+ } else {
+ r->in.user = NULL;
+ }
+ if (r->in.user) {
+ _mem_save_user_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.user, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.user));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.user));
+ if (ndr_get_array_length(ndr, &r->in.user) > ndr_get_array_size(ndr, &r->in.user)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.user), ndr_get_array_length(ndr, &r->in.user));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.user), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.user, ndr_get_array_length(ndr, &r->in.user), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.level);
+ }
+ _mem_save_level_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.level, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.level));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.ctr, *r->in.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevQCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_buffer));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ } else {
+ r->in.resume_handle = NULL;
+ }
+ if (r->in.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.level);
+ *r->out.level = *r->in.level;
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ *r->out.ctr = *r->in.ctr;
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ ZERO_STRUCTP(r->out.totalentries);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.level);
+ }
+ _mem_save_level_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.level, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.level));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.ctr, *r->out.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevQCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ }
+ _mem_save_totalentries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.totalentries, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.totalentries));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_totalentries_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ } else {
+ r->out.resume_handle = NULL;
+ }
+ if (r->out.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevQEnum *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetCharDevQEnum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetCharDevQEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "user", r->in.user);
+ ndr->depth++;
+ if (r->in.user) {
+ ndr_print_string(ndr, "user", r->in.user);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "level", r->in.level);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level", *r->in.level);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ctr", r->in.ctr);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.ctr, *r->in.level);
+ ndr_print_srvsvc_NetCharDevQCtr(ndr, "ctr", r->in.ctr);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_buffer", r->in.max_buffer);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ if (r->in.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetCharDevQEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "level", r->out.level);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level", *r->out.level);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ctr", r->out.ctr);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.ctr, *r->out.level);
+ ndr_print_srvsvc_NetCharDevQCtr(ndr, "ctr", r->out.ctr);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "totalentries", r->out.totalentries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "totalentries", *r->out.totalentries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ if (r->out.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevQGetInfo(struct ndr_push *ndr, int flags, const struct srvsvc_NetCharDevQGetInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.queue_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.queue_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.queue_name, ndr_charset_length(r->in.queue_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.user, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.user, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.user, ndr_charset_length(r->in.user, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevQInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevQGetInfo(struct ndr_pull *ndr, int flags, struct srvsvc_NetCharDevQGetInfo *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.queue_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.queue_name));
+ if (ndr_get_array_length(ndr, &r->in.queue_name) > ndr_get_array_size(ndr, &r->in.queue_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.queue_name), ndr_get_array_length(ndr, &r->in.queue_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.queue_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.queue_name, ndr_get_array_length(ndr, &r->in.queue_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.user));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.user));
+ if (ndr_get_array_length(ndr, &r->in.user) > ndr_get_array_size(ndr, &r->in.user)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.user), ndr_get_array_length(ndr, &r->in.user));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.user), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.user, ndr_get_array_length(ndr, &r->in.user), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevQInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevQGetInfo *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetCharDevQGetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetCharDevQGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "queue_name", r->in.queue_name);
+ ndr_print_string(ndr, "user", r->in.user);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetCharDevQGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, r->in.level);
+ ndr_print_srvsvc_NetCharDevQInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevQSetInfo(struct ndr_push *ndr, int flags, const struct srvsvc_NetCharDevQSetInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.queue_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.queue_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.queue_name, ndr_charset_length(r->in.queue_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_srvsvc_NetCharDevQInfo(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.info));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.parm_error));
+ if (r->in.parm_error) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.parm_error));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.parm_error));
+ if (r->out.parm_error) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.parm_error));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevQSetInfo(struct ndr_pull *ndr, int flags, struct srvsvc_NetCharDevQSetInfo *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_parm_error;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_parm_error_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.queue_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.queue_name));
+ if (ndr_get_array_length(ndr, &r->in.queue_name) > ndr_get_array_size(ndr, &r->in.queue_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.queue_name), ndr_get_array_length(ndr, &r->in.queue_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.queue_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.queue_name, ndr_get_array_length(ndr, &r->in.queue_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetCharDevQInfo(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.info));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_parm_error));
+ if (_ptr_parm_error) {
+ NDR_PULL_ALLOC(ndr, r->in.parm_error);
+ } else {
+ r->in.parm_error = NULL;
+ }
+ if (r->in.parm_error) {
+ _mem_save_parm_error_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.parm_error, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.parm_error));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parm_error_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_parm_error));
+ if (_ptr_parm_error) {
+ NDR_PULL_ALLOC(ndr, r->out.parm_error);
+ } else {
+ r->out.parm_error = NULL;
+ }
+ if (r->out.parm_error) {
+ _mem_save_parm_error_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.parm_error, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.parm_error));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parm_error_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevQSetInfo *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetCharDevQSetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetCharDevQSetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "queue_name", r->in.queue_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_set_switch_value(ndr, &r->in.info, r->in.level);
+ ndr_print_srvsvc_NetCharDevQInfo(ndr, "info", &r->in.info);
+ ndr_print_ptr(ndr, "parm_error", r->in.parm_error);
+ ndr->depth++;
+ if (r->in.parm_error) {
+ ndr_print_uint32(ndr, "parm_error", *r->in.parm_error);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetCharDevQSetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_error", r->out.parm_error);
+ ndr->depth++;
+ if (r->out.parm_error) {
+ ndr_print_uint32(ndr, "parm_error", *r->out.parm_error);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevQPurge(struct ndr_push *ndr, int flags, const struct srvsvc_NetCharDevQPurge *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.queue_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.queue_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.queue_name, ndr_charset_length(r->in.queue_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevQPurge(struct ndr_pull *ndr, int flags, struct srvsvc_NetCharDevQPurge *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.queue_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.queue_name));
+ if (ndr_get_array_length(ndr, &r->in.queue_name) > ndr_get_array_size(ndr, &r->in.queue_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.queue_name), ndr_get_array_length(ndr, &r->in.queue_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.queue_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.queue_name, ndr_get_array_length(ndr, &r->in.queue_name), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQPurge(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevQPurge *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetCharDevQPurge");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetCharDevQPurge");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "queue_name", r->in.queue_name);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetCharDevQPurge");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetCharDevQPurgeSelf(struct ndr_push *ndr, int flags, const struct srvsvc_NetCharDevQPurgeSelf *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.queue_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.queue_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.queue_name, ndr_charset_length(r->in.queue_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.computer_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.computer_name, ndr_charset_length(r->in.computer_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetCharDevQPurgeSelf(struct ndr_pull *ndr, int flags, struct srvsvc_NetCharDevQPurgeSelf *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.queue_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.queue_name));
+ if (ndr_get_array_length(ndr, &r->in.queue_name) > ndr_get_array_size(ndr, &r->in.queue_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.queue_name), ndr_get_array_length(ndr, &r->in.queue_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.queue_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.queue_name, ndr_get_array_length(ndr, &r->in.queue_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.computer_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.computer_name));
+ if (ndr_get_array_length(ndr, &r->in.computer_name) > ndr_get_array_size(ndr, &r->in.computer_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.computer_name), ndr_get_array_length(ndr, &r->in.computer_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.computer_name, ndr_get_array_length(ndr, &r->in.computer_name), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetCharDevQPurgeSelf(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevQPurgeSelf *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetCharDevQPurgeSelf");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetCharDevQPurgeSelf");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "queue_name", r->in.queue_name);
+ ndr_print_string(ndr, "computer_name", r->in.computer_name);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetCharDevQPurgeSelf");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetConnEnum(struct ndr_push *ndr, int flags, const struct srvsvc_NetConnEnum *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.path));
+ if (r->in.path) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.path, ndr_charset_length(r->in.path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.info_ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_srvsvc_NetConnInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info_ctr));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_buffer));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.resume_handle));
+ if (r->in.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info_ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_srvsvc_NetConnInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info_ctr));
+ if (r->out.totalentries == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.totalentries));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.resume_handle));
+ if (r->out.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetConnEnum(struct ndr_pull *ndr, int flags, struct srvsvc_NetConnEnum *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_path;
+ uint32_t _ptr_resume_handle;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_path_0;
+ TALLOC_CTX *_mem_save_info_ctr_0;
+ TALLOC_CTX *_mem_save_totalentries_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_path));
+ if (_ptr_path) {
+ NDR_PULL_ALLOC(ndr, r->in.path);
+ } else {
+ r->in.path = NULL;
+ }
+ if (r->in.path) {
+ _mem_save_path_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.path, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.path));
+ if (ndr_get_array_length(ndr, &r->in.path) > ndr_get_array_size(ndr, &r->in.path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.path), ndr_get_array_length(ndr, &r->in.path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.path, ndr_get_array_length(ndr, &r->in.path), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_path_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info_ctr);
+ }
+ _mem_save_info_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info_ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_srvsvc_NetConnInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info_ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_buffer));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ } else {
+ r->in.resume_handle = NULL;
+ }
+ if (r->in.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.info_ctr);
+ *r->out.info_ctr = *r->in.info_ctr;
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ ZERO_STRUCTP(r->out.totalentries);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info_ctr);
+ }
+ _mem_save_info_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info_ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_srvsvc_NetConnInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info_ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ }
+ _mem_save_totalentries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.totalentries, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.totalentries));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_totalentries_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ } else {
+ r->out.resume_handle = NULL;
+ }
+ if (r->out.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetConnEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetConnEnum *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetConnEnum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetConnEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "path", r->in.path);
+ ndr->depth++;
+ if (r->in.path) {
+ ndr_print_string(ndr, "path", r->in.path);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "info_ctr", r->in.info_ctr);
+ ndr->depth++;
+ ndr_print_srvsvc_NetConnInfoCtr(ndr, "info_ctr", r->in.info_ctr);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_buffer", r->in.max_buffer);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ if (r->in.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetConnEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info_ctr", r->out.info_ctr);
+ ndr->depth++;
+ ndr_print_srvsvc_NetConnInfoCtr(ndr, "info_ctr", r->out.info_ctr);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "totalentries", r->out.totalentries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "totalentries", *r->out.totalentries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ if (r->out.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetFileEnum(struct ndr_push *ndr, int flags, const struct srvsvc_NetFileEnum *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.path));
+ if (r->in.path) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.path, ndr_charset_length(r->in.path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.user));
+ if (r->in.user) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.user, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.user, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.user, ndr_charset_length(r->in.user, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.info_ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_srvsvc_NetFileInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info_ctr));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_buffer));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.resume_handle));
+ if (r->in.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info_ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_srvsvc_NetFileInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info_ctr));
+ if (r->out.totalentries == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.totalentries));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.resume_handle));
+ if (r->out.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetFileEnum(struct ndr_pull *ndr, int flags, struct srvsvc_NetFileEnum *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_path;
+ uint32_t _ptr_user;
+ uint32_t _ptr_resume_handle;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_path_0;
+ TALLOC_CTX *_mem_save_user_0;
+ TALLOC_CTX *_mem_save_info_ctr_0;
+ TALLOC_CTX *_mem_save_totalentries_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_path));
+ if (_ptr_path) {
+ NDR_PULL_ALLOC(ndr, r->in.path);
+ } else {
+ r->in.path = NULL;
+ }
+ if (r->in.path) {
+ _mem_save_path_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.path, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.path));
+ if (ndr_get_array_length(ndr, &r->in.path) > ndr_get_array_size(ndr, &r->in.path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.path), ndr_get_array_length(ndr, &r->in.path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.path, ndr_get_array_length(ndr, &r->in.path), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_path_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user));
+ if (_ptr_user) {
+ NDR_PULL_ALLOC(ndr, r->in.user);
+ } else {
+ r->in.user = NULL;
+ }
+ if (r->in.user) {
+ _mem_save_user_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.user, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.user));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.user));
+ if (ndr_get_array_length(ndr, &r->in.user) > ndr_get_array_size(ndr, &r->in.user)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.user), ndr_get_array_length(ndr, &r->in.user));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.user), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.user, ndr_get_array_length(ndr, &r->in.user), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info_ctr);
+ }
+ _mem_save_info_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info_ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_srvsvc_NetFileInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info_ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_buffer));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ } else {
+ r->in.resume_handle = NULL;
+ }
+ if (r->in.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.info_ctr);
+ *r->out.info_ctr = *r->in.info_ctr;
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ ZERO_STRUCTP(r->out.totalentries);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info_ctr);
+ }
+ _mem_save_info_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info_ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_srvsvc_NetFileInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info_ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ }
+ _mem_save_totalentries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.totalentries, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.totalentries));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_totalentries_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ } else {
+ r->out.resume_handle = NULL;
+ }
+ if (r->out.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetFileEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetFileEnum *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetFileEnum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetFileEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "path", r->in.path);
+ ndr->depth++;
+ if (r->in.path) {
+ ndr_print_string(ndr, "path", r->in.path);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "user", r->in.user);
+ ndr->depth++;
+ if (r->in.user) {
+ ndr_print_string(ndr, "user", r->in.user);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "info_ctr", r->in.info_ctr);
+ ndr->depth++;
+ ndr_print_srvsvc_NetFileInfoCtr(ndr, "info_ctr", r->in.info_ctr);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_buffer", r->in.max_buffer);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ if (r->in.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetFileEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info_ctr", r->out.info_ctr);
+ ndr->depth++;
+ ndr_print_srvsvc_NetFileInfoCtr(ndr, "info_ctr", r->out.info_ctr);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "totalentries", r->out.totalentries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "totalentries", *r->out.totalentries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ if (r->out.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetFileGetInfo(struct ndr_push *ndr, int flags, const struct srvsvc_NetFileGetInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.fid));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_srvsvc_NetFileInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetFileGetInfo(struct ndr_pull *ndr, int flags, struct srvsvc_NetFileGetInfo *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.fid));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetFileInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetFileGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetFileGetInfo *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetFileGetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetFileGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "fid", r->in.fid);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetFileGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, r->in.level);
+ ndr_print_srvsvc_NetFileInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetFileClose(struct ndr_push *ndr, int flags, const struct srvsvc_NetFileClose *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.fid));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetFileClose(struct ndr_pull *ndr, int flags, struct srvsvc_NetFileClose *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.fid));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetFileClose(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetFileClose *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetFileClose");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetFileClose");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "fid", r->in.fid);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetFileClose");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSessEnum(struct ndr_push *ndr, int flags, const struct srvsvc_NetSessEnum *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.client));
+ if (r->in.client) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.client, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.client, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.client, ndr_charset_length(r->in.client, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.user));
+ if (r->in.user) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.user, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.user, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.user, ndr_charset_length(r->in.user, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.info_ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_srvsvc_NetSessInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info_ctr));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_buffer));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.resume_handle));
+ if (r->in.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info_ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_srvsvc_NetSessInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info_ctr));
+ if (r->out.totalentries == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.totalentries));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.resume_handle));
+ if (r->out.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSessEnum(struct ndr_pull *ndr, int flags, struct srvsvc_NetSessEnum *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_client;
+ uint32_t _ptr_user;
+ uint32_t _ptr_resume_handle;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_client_0;
+ TALLOC_CTX *_mem_save_user_0;
+ TALLOC_CTX *_mem_save_info_ctr_0;
+ TALLOC_CTX *_mem_save_totalentries_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_client));
+ if (_ptr_client) {
+ NDR_PULL_ALLOC(ndr, r->in.client);
+ } else {
+ r->in.client = NULL;
+ }
+ if (r->in.client) {
+ _mem_save_client_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.client, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.client));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.client));
+ if (ndr_get_array_length(ndr, &r->in.client) > ndr_get_array_size(ndr, &r->in.client)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.client), ndr_get_array_length(ndr, &r->in.client));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.client), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.client, ndr_get_array_length(ndr, &r->in.client), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_client_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user));
+ if (_ptr_user) {
+ NDR_PULL_ALLOC(ndr, r->in.user);
+ } else {
+ r->in.user = NULL;
+ }
+ if (r->in.user) {
+ _mem_save_user_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.user, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.user));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.user));
+ if (ndr_get_array_length(ndr, &r->in.user) > ndr_get_array_size(ndr, &r->in.user)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.user), ndr_get_array_length(ndr, &r->in.user));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.user), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.user, ndr_get_array_length(ndr, &r->in.user), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info_ctr);
+ }
+ _mem_save_info_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info_ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_srvsvc_NetSessInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info_ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_buffer));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ } else {
+ r->in.resume_handle = NULL;
+ }
+ if (r->in.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.info_ctr);
+ *r->out.info_ctr = *r->in.info_ctr;
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ ZERO_STRUCTP(r->out.totalentries);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info_ctr);
+ }
+ _mem_save_info_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info_ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_srvsvc_NetSessInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info_ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ }
+ _mem_save_totalentries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.totalentries, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.totalentries));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_totalentries_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ } else {
+ r->out.resume_handle = NULL;
+ }
+ if (r->out.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSessEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSessEnum *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSessEnum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetSessEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "client", r->in.client);
+ ndr->depth++;
+ if (r->in.client) {
+ ndr_print_string(ndr, "client", r->in.client);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "user", r->in.user);
+ ndr->depth++;
+ if (r->in.user) {
+ ndr_print_string(ndr, "user", r->in.user);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "info_ctr", r->in.info_ctr);
+ ndr->depth++;
+ ndr_print_srvsvc_NetSessInfoCtr(ndr, "info_ctr", r->in.info_ctr);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_buffer", r->in.max_buffer);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ if (r->in.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetSessEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info_ctr", r->out.info_ctr);
+ ndr->depth++;
+ ndr_print_srvsvc_NetSessInfoCtr(ndr, "info_ctr", r->out.info_ctr);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "totalentries", r->out.totalentries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "totalentries", *r->out.totalentries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ if (r->out.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSessDel(struct ndr_push *ndr, int flags, const struct srvsvc_NetSessDel *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.client));
+ if (r->in.client) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.client, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.client, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.client, ndr_charset_length(r->in.client, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.user));
+ if (r->in.user) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.user, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.user, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.user, ndr_charset_length(r->in.user, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSessDel(struct ndr_pull *ndr, int flags, struct srvsvc_NetSessDel *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_client;
+ uint32_t _ptr_user;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_client_0;
+ TALLOC_CTX *_mem_save_user_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_client));
+ if (_ptr_client) {
+ NDR_PULL_ALLOC(ndr, r->in.client);
+ } else {
+ r->in.client = NULL;
+ }
+ if (r->in.client) {
+ _mem_save_client_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.client, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.client));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.client));
+ if (ndr_get_array_length(ndr, &r->in.client) > ndr_get_array_size(ndr, &r->in.client)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.client), ndr_get_array_length(ndr, &r->in.client));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.client), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.client, ndr_get_array_length(ndr, &r->in.client), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_client_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user));
+ if (_ptr_user) {
+ NDR_PULL_ALLOC(ndr, r->in.user);
+ } else {
+ r->in.user = NULL;
+ }
+ if (r->in.user) {
+ _mem_save_user_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.user, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.user));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.user));
+ if (ndr_get_array_length(ndr, &r->in.user) > ndr_get_array_size(ndr, &r->in.user)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.user), ndr_get_array_length(ndr, &r->in.user));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.user), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.user, ndr_get_array_length(ndr, &r->in.user), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSessDel(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSessDel *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSessDel");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetSessDel");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "client", r->in.client);
+ ndr->depth++;
+ if (r->in.client) {
+ ndr_print_string(ndr, "client", r->in.client);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "user", r->in.user);
+ ndr->depth++;
+ if (r->in.user) {
+ ndr_print_string(ndr, "user", r->in.user);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetSessDel");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareAdd(struct ndr_push *ndr, int flags, const struct srvsvc_NetShareAdd *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.parm_error));
+ if (r->in.parm_error) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.parm_error));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.parm_error));
+ if (r->out.parm_error) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.parm_error));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareAdd(struct ndr_pull *ndr, int flags, struct srvsvc_NetShareAdd *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_parm_error;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_parm_error_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_parm_error));
+ if (_ptr_parm_error) {
+ NDR_PULL_ALLOC(ndr, r->in.parm_error);
+ } else {
+ r->in.parm_error = NULL;
+ }
+ if (r->in.parm_error) {
+ _mem_save_parm_error_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.parm_error, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.parm_error));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parm_error_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_parm_error));
+ if (_ptr_parm_error) {
+ NDR_PULL_ALLOC(ndr, r->out.parm_error);
+ } else {
+ r->out.parm_error = NULL;
+ }
+ if (r->out.parm_error) {
+ _mem_save_parm_error_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.parm_error, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.parm_error));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parm_error_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareAdd(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareAdd *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareAdd");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetShareAdd");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.info, r->in.level);
+ ndr_print_srvsvc_NetShareInfo(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "parm_error", r->in.parm_error);
+ ndr->depth++;
+ if (r->in.parm_error) {
+ ndr_print_uint32(ndr, "parm_error", *r->in.parm_error);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetShareAdd");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_error", r->out.parm_error);
+ ndr->depth++;
+ if (r->out.parm_error) {
+ ndr_print_uint32(ndr, "parm_error", *r->out.parm_error);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareEnumAll(struct ndr_push *ndr, int flags, const struct srvsvc_NetShareEnumAll *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.info_ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info_ctr));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_buffer));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.resume_handle));
+ if (r->in.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info_ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info_ctr));
+ if (r->out.totalentries == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.totalentries));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.resume_handle));
+ if (r->out.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareEnumAll(struct ndr_pull *ndr, int flags, struct srvsvc_NetShareEnumAll *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_resume_handle;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_info_ctr_0;
+ TALLOC_CTX *_mem_save_totalentries_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info_ctr);
+ }
+ _mem_save_info_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info_ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info_ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_buffer));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ } else {
+ r->in.resume_handle = NULL;
+ }
+ if (r->in.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.info_ctr);
+ *r->out.info_ctr = *r->in.info_ctr;
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ ZERO_STRUCTP(r->out.totalentries);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info_ctr);
+ }
+ _mem_save_info_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info_ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info_ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ }
+ _mem_save_totalentries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.totalentries, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.totalentries));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_totalentries_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ } else {
+ r->out.resume_handle = NULL;
+ }
+ if (r->out.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareEnumAll(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareEnumAll *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareEnumAll");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetShareEnumAll");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "info_ctr", r->in.info_ctr);
+ ndr->depth++;
+ ndr_print_srvsvc_NetShareInfoCtr(ndr, "info_ctr", r->in.info_ctr);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_buffer", r->in.max_buffer);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ if (r->in.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetShareEnumAll");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info_ctr", r->out.info_ctr);
+ ndr->depth++;
+ ndr_print_srvsvc_NetShareInfoCtr(ndr, "info_ctr", r->out.info_ctr);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "totalentries", r->out.totalentries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "totalentries", *r->out.totalentries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ if (r->out.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareGetInfo(struct ndr_push *ndr, int flags, const struct srvsvc_NetShareGetInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.share_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.share_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.share_name, ndr_charset_length(r->in.share_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareGetInfo(struct ndr_pull *ndr, int flags, struct srvsvc_NetShareGetInfo *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.share_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.share_name));
+ if (ndr_get_array_length(ndr, &r->in.share_name) > ndr_get_array_size(ndr, &r->in.share_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.share_name), ndr_get_array_length(ndr, &r->in.share_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.share_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.share_name, ndr_get_array_length(ndr, &r->in.share_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareGetInfo *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareGetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetShareGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "share_name", r->in.share_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetShareGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, r->in.level);
+ ndr_print_srvsvc_NetShareInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareSetInfo(struct ndr_push *ndr, int flags, const struct srvsvc_NetShareSetInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.share_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.share_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.share_name, ndr_charset_length(r->in.share_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.parm_error));
+ if (r->in.parm_error) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.parm_error));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.parm_error));
+ if (r->out.parm_error) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.parm_error));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareSetInfo(struct ndr_pull *ndr, int flags, struct srvsvc_NetShareSetInfo *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_parm_error;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_parm_error_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.share_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.share_name));
+ if (ndr_get_array_length(ndr, &r->in.share_name) > ndr_get_array_size(ndr, &r->in.share_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.share_name), ndr_get_array_length(ndr, &r->in.share_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.share_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.share_name, ndr_get_array_length(ndr, &r->in.share_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_parm_error));
+ if (_ptr_parm_error) {
+ NDR_PULL_ALLOC(ndr, r->in.parm_error);
+ } else {
+ r->in.parm_error = NULL;
+ }
+ if (r->in.parm_error) {
+ _mem_save_parm_error_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.parm_error, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.parm_error));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parm_error_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_parm_error));
+ if (_ptr_parm_error) {
+ NDR_PULL_ALLOC(ndr, r->out.parm_error);
+ } else {
+ r->out.parm_error = NULL;
+ }
+ if (r->out.parm_error) {
+ _mem_save_parm_error_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.parm_error, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.parm_error));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parm_error_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareSetInfo *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareSetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetShareSetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "share_name", r->in.share_name);
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.info, r->in.level);
+ ndr_print_srvsvc_NetShareInfo(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "parm_error", r->in.parm_error);
+ ndr->depth++;
+ if (r->in.parm_error) {
+ ndr_print_uint32(ndr, "parm_error", *r->in.parm_error);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetShareSetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_error", r->out.parm_error);
+ ndr->depth++;
+ if (r->out.parm_error) {
+ ndr_print_uint32(ndr, "parm_error", *r->out.parm_error);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareDel(struct ndr_push *ndr, int flags, const struct srvsvc_NetShareDel *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.share_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.share_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.share_name, ndr_charset_length(r->in.share_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.reserved));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareDel(struct ndr_pull *ndr, int flags, struct srvsvc_NetShareDel *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.share_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.share_name));
+ if (ndr_get_array_length(ndr, &r->in.share_name) > ndr_get_array_size(ndr, &r->in.share_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.share_name), ndr_get_array_length(ndr, &r->in.share_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.share_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.share_name, ndr_get_array_length(ndr, &r->in.share_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.reserved));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareDel(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareDel *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareDel");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetShareDel");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "share_name", r->in.share_name);
+ ndr_print_uint32(ndr, "reserved", r->in.reserved);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetShareDel");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareDelSticky(struct ndr_push *ndr, int flags, const struct srvsvc_NetShareDelSticky *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.share_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.share_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.share_name, ndr_charset_length(r->in.share_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.reserved));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareDelSticky(struct ndr_pull *ndr, int flags, struct srvsvc_NetShareDelSticky *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.share_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.share_name));
+ if (ndr_get_array_length(ndr, &r->in.share_name) > ndr_get_array_size(ndr, &r->in.share_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.share_name), ndr_get_array_length(ndr, &r->in.share_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.share_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.share_name, ndr_get_array_length(ndr, &r->in.share_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.reserved));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareDelSticky(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareDelSticky *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareDelSticky");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetShareDelSticky");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "share_name", r->in.share_name);
+ ndr_print_uint32(ndr, "reserved", r->in.reserved);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetShareDelSticky");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareCheck(struct ndr_push *ndr, int flags, const struct srvsvc_NetShareCheck *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.device_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.device_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.device_name, ndr_charset_length(r->in.device_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.type == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_srvsvc_ShareType(ndr, NDR_SCALARS, *r->out.type));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareCheck(struct ndr_pull *ndr, int flags, struct srvsvc_NetShareCheck *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_type_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.device_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.device_name));
+ if (ndr_get_array_length(ndr, &r->in.device_name) > ndr_get_array_size(ndr, &r->in.device_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.device_name), ndr_get_array_length(ndr, &r->in.device_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.device_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.device_name, ndr_get_array_length(ndr, &r->in.device_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_ALLOC(ndr, r->out.type);
+ ZERO_STRUCTP(r->out.type);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.type);
+ }
+ _mem_save_type_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.type, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_srvsvc_ShareType(ndr, NDR_SCALARS, r->out.type));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_type_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareCheck(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareCheck *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareCheck");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetShareCheck");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "device_name", r->in.device_name);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetShareCheck");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "type", r->out.type);
+ ndr->depth++;
+ ndr_print_srvsvc_ShareType(ndr, "type", *r->out.type);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvGetInfo(struct ndr_push *ndr, int flags, const struct srvsvc_NetSrvGetInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvGetInfo(struct ndr_pull *ndr, int flags, struct srvsvc_NetSrvGetInfo *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSrvGetInfo *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvGetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetSrvGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetSrvGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, r->in.level);
+ ndr_print_srvsvc_NetSrvInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSrvSetInfo(struct ndr_push *ndr, int flags, const struct srvsvc_NetSrvSetInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_srvsvc_NetSrvInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.parm_error));
+ if (r->in.parm_error) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.parm_error));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.parm_error));
+ if (r->out.parm_error) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.parm_error));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSrvSetInfo(struct ndr_pull *ndr, int flags, struct srvsvc_NetSrvSetInfo *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_parm_error;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_parm_error_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetSrvInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_parm_error));
+ if (_ptr_parm_error) {
+ NDR_PULL_ALLOC(ndr, r->in.parm_error);
+ } else {
+ r->in.parm_error = NULL;
+ }
+ if (r->in.parm_error) {
+ _mem_save_parm_error_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.parm_error, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.parm_error));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parm_error_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_parm_error));
+ if (_ptr_parm_error) {
+ NDR_PULL_ALLOC(ndr, r->out.parm_error);
+ } else {
+ r->out.parm_error = NULL;
+ }
+ if (r->out.parm_error) {
+ _mem_save_parm_error_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.parm_error, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.parm_error));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parm_error_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSrvSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSrvSetInfo *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSrvSetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetSrvSetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.info, r->in.level);
+ ndr_print_srvsvc_NetSrvInfo(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "parm_error", r->in.parm_error);
+ ndr->depth++;
+ if (r->in.parm_error) {
+ ndr_print_uint32(ndr, "parm_error", *r->in.parm_error);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetSrvSetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_error", r->out.parm_error);
+ ndr->depth++;
+ if (r->out.parm_error) {
+ ndr_print_uint32(ndr, "parm_error", *r->out.parm_error);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetDiskEnum(struct ndr_push *ndr, int flags, const struct srvsvc_NetDiskEnum *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_srvsvc_NetDiskInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.maxlen));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.resume_handle));
+ if (r->in.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_srvsvc_NetDiskInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ if (r->out.totalentries == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.totalentries));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.resume_handle));
+ if (r->out.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetDiskEnum(struct ndr_pull *ndr, int flags, struct srvsvc_NetDiskEnum *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_resume_handle;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_totalentries_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_srvsvc_NetDiskInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.maxlen));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ } else {
+ r->in.resume_handle = NULL;
+ }
+ if (r->in.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ *r->out.info = *r->in.info;
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ ZERO_STRUCTP(r->out.totalentries);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_srvsvc_NetDiskInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ }
+ _mem_save_totalentries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.totalentries, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.totalentries));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_totalentries_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ } else {
+ r->out.resume_handle = NULL;
+ }
+ if (r->out.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetDiskEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetDiskEnum *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetDiskEnum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetDiskEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_srvsvc_NetDiskInfo(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "maxlen", r->in.maxlen);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ if (r->in.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetDiskEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_srvsvc_NetDiskInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "totalentries", r->out.totalentries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "totalentries", *r->out.totalentries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ if (r->out.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetServerStatisticsGet(struct ndr_push *ndr, int flags, const struct srvsvc_NetServerStatisticsGet *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.service));
+ if (r->in.service) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.service, ndr_charset_length(r->in.service, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.options));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.stats == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_srvsvc_Statistics(ndr, NDR_SCALARS, r->out.stats));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetServerStatisticsGet(struct ndr_pull *ndr, int flags, struct srvsvc_NetServerStatisticsGet *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_service;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_service_0;
+ TALLOC_CTX *_mem_save_stats_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_service));
+ if (_ptr_service) {
+ NDR_PULL_ALLOC(ndr, r->in.service);
+ } else {
+ r->in.service = NULL;
+ }
+ if (r->in.service) {
+ _mem_save_service_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.service, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.service));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.service));
+ if (ndr_get_array_length(ndr, &r->in.service) > ndr_get_array_size(ndr, &r->in.service)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.service), ndr_get_array_length(ndr, &r->in.service));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.service), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.service, ndr_get_array_length(ndr, &r->in.service), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.options));
+ NDR_PULL_ALLOC(ndr, r->out.stats);
+ ZERO_STRUCTP(r->out.stats);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.stats);
+ }
+ _mem_save_stats_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.stats, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_srvsvc_Statistics(ndr, NDR_SCALARS, r->out.stats));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_stats_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetServerStatisticsGet(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetServerStatisticsGet *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetServerStatisticsGet");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetServerStatisticsGet");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "service", r->in.service);
+ ndr->depth++;
+ if (r->in.service) {
+ ndr_print_string(ndr, "service", r->in.service);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_uint32(ndr, "options", r->in.options);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetServerStatisticsGet");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "stats", r->out.stats);
+ ndr->depth++;
+ ndr_print_srvsvc_Statistics(ndr, "stats", r->out.stats);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetTransportAdd(struct ndr_push *ndr, int flags, const struct srvsvc_NetTransportAdd *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.info));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetTransportAdd(struct ndr_pull *ndr, int flags, struct srvsvc_NetTransportAdd *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.info));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetTransportAdd(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetTransportAdd *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetTransportAdd");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetTransportAdd");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_set_switch_value(ndr, &r->in.info, r->in.level);
+ ndr_print_srvsvc_NetTransportInfo(ndr, "info", &r->in.info);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetTransportAdd");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetTransportEnum(struct ndr_push *ndr, int flags, const struct srvsvc_NetTransportEnum *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.level == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.level));
+ if (r->in.transports == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.transports, *r->in.level));
+ NDR_CHECK(ndr_push_srvsvc_NetTransportCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.transports));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_buffer));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.resume_handle));
+ if (r->in.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.level == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.level));
+ if (r->out.transports == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.transports, *r->out.level));
+ NDR_CHECK(ndr_push_srvsvc_NetTransportCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.transports));
+ if (r->out.totalentries == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.totalentries));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.resume_handle));
+ if (r->out.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetTransportEnum(struct ndr_pull *ndr, int flags, struct srvsvc_NetTransportEnum *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_resume_handle;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_level_0;
+ TALLOC_CTX *_mem_save_transports_0;
+ TALLOC_CTX *_mem_save_totalentries_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.level);
+ }
+ _mem_save_level_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.level, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.level));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.transports);
+ }
+ _mem_save_transports_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.transports, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.transports, *r->in.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.transports));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_transports_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_buffer));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ } else {
+ r->in.resume_handle = NULL;
+ }
+ if (r->in.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.level);
+ *r->out.level = *r->in.level;
+ NDR_PULL_ALLOC(ndr, r->out.transports);
+ *r->out.transports = *r->in.transports;
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ ZERO_STRUCTP(r->out.totalentries);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.level);
+ }
+ _mem_save_level_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.level, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.level));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_level_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.transports);
+ }
+ _mem_save_transports_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.transports, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.transports, *r->out.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.transports));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_transports_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ }
+ _mem_save_totalentries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.totalentries, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.totalentries));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_totalentries_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ } else {
+ r->out.resume_handle = NULL;
+ }
+ if (r->out.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetTransportEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetTransportEnum *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetTransportEnum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetTransportEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "level", r->in.level);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level", *r->in.level);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "transports", r->in.transports);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.transports, *r->in.level);
+ ndr_print_srvsvc_NetTransportCtr(ndr, "transports", r->in.transports);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_buffer", r->in.max_buffer);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ if (r->in.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetTransportEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "level", r->out.level);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level", *r->out.level);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "transports", r->out.transports);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.transports, *r->out.level);
+ ndr_print_srvsvc_NetTransportCtr(ndr, "transports", r->out.transports);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "totalentries", r->out.totalentries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "totalentries", *r->out.totalentries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ if (r->out.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetTransportDel(struct ndr_push *ndr, int flags, const struct srvsvc_NetTransportDel *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown));
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo0(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.transport));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetTransportDel(struct ndr_pull *ndr, int flags, struct srvsvc_NetTransportDel *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown));
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo0(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.transport));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetTransportDel(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetTransportDel *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetTransportDel");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetTransportDel");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown", r->in.unknown);
+ ndr_print_srvsvc_NetTransportInfo0(ndr, "transport", &r->in.transport);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetTransportDel");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetRemoteTOD(struct ndr_push *ndr, int flags, const struct srvsvc_NetRemoteTOD *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.info));
+ if (*r->out.info) {
+ NDR_CHECK(ndr_push_srvsvc_NetRemoteTODInfo(ndr, NDR_SCALARS, *r->out.info));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetRemoteTOD(struct ndr_pull *ndr, int flags, struct srvsvc_NetRemoteTOD *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ } else {
+ *r->out.info = NULL;
+ }
+ if (*r->out.info) {
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.info, 0);
+ NDR_CHECK(ndr_pull_srvsvc_NetRemoteTODInfo(ndr, NDR_SCALARS, *r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetRemoteTOD(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetRemoteTOD *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetRemoteTOD");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetRemoteTOD");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetRemoteTOD");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", *r->out.info);
+ ndr->depth++;
+ if (*r->out.info) {
+ ndr_print_srvsvc_NetRemoteTODInfo(ndr, "info", *r->out.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSetServiceBits(struct ndr_push *ndr, int flags, const struct srvsvc_NetSetServiceBits *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.transport));
+ if (r->in.transport) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.transport, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.transport, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.transport, ndr_charset_length(r->in.transport, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.servicebits));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.updateimmediately));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSetServiceBits(struct ndr_pull *ndr, int flags, struct srvsvc_NetSetServiceBits *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_transport;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_transport_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_transport));
+ if (_ptr_transport) {
+ NDR_PULL_ALLOC(ndr, r->in.transport);
+ } else {
+ r->in.transport = NULL;
+ }
+ if (r->in.transport) {
+ _mem_save_transport_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.transport, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.transport));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.transport));
+ if (ndr_get_array_length(ndr, &r->in.transport) > ndr_get_array_size(ndr, &r->in.transport)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.transport), ndr_get_array_length(ndr, &r->in.transport));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.transport), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.transport, ndr_get_array_length(ndr, &r->in.transport), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_transport_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.servicebits));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.updateimmediately));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSetServiceBits(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSetServiceBits *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSetServiceBits");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetSetServiceBits");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "transport", r->in.transport);
+ ndr->depth++;
+ if (r->in.transport) {
+ ndr_print_string(ndr, "transport", r->in.transport);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "servicebits", r->in.servicebits);
+ ndr_print_uint32(ndr, "updateimmediately", r->in.updateimmediately);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetSetServiceBits");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetPathType(struct ndr_push *ndr, int flags, const struct srvsvc_NetPathType *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.path, ndr_charset_length(r->in.path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.pathflags));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.pathtype == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.pathtype));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetPathType(struct ndr_pull *ndr, int flags, struct srvsvc_NetPathType *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_pathtype_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.path));
+ if (ndr_get_array_length(ndr, &r->in.path) > ndr_get_array_size(ndr, &r->in.path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.path), ndr_get_array_length(ndr, &r->in.path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.path, ndr_get_array_length(ndr, &r->in.path), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.pathflags));
+ NDR_PULL_ALLOC(ndr, r->out.pathtype);
+ ZERO_STRUCTP(r->out.pathtype);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.pathtype);
+ }
+ _mem_save_pathtype_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.pathtype, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.pathtype));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_pathtype_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetPathType(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetPathType *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetPathType");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetPathType");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "path", r->in.path);
+ ndr_print_uint32(ndr, "pathflags", r->in.pathflags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetPathType");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "pathtype", r->out.pathtype);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "pathtype", *r->out.pathtype);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetPathCanonicalize(struct ndr_push *ndr, int flags, const struct srvsvc_NetPathCanonicalize *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.path, ndr_charset_length(r->in.path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.maxbuf));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.prefix, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.prefix, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.prefix, ndr_charset_length(r->in.prefix, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ if (r->in.pathtype == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.pathtype));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.pathflags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.maxbuf));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.can_path, r->in.maxbuf));
+ if (r->out.pathtype == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.pathtype));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetPathCanonicalize(struct ndr_pull *ndr, int flags, struct srvsvc_NetPathCanonicalize *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_pathtype_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.path));
+ if (ndr_get_array_length(ndr, &r->in.path) > ndr_get_array_size(ndr, &r->in.path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.path), ndr_get_array_length(ndr, &r->in.path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.path, ndr_get_array_length(ndr, &r->in.path), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.maxbuf));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.prefix));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.prefix));
+ if (ndr_get_array_length(ndr, &r->in.prefix) > ndr_get_array_size(ndr, &r->in.prefix)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.prefix), ndr_get_array_length(ndr, &r->in.prefix));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.prefix), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.prefix, ndr_get_array_length(ndr, &r->in.prefix), sizeof(uint16_t), CH_UTF16));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.pathtype);
+ }
+ _mem_save_pathtype_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.pathtype, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.pathtype));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_pathtype_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.pathflags));
+ NDR_PULL_ALLOC(ndr, r->out.pathtype);
+ *r->out.pathtype = *r->in.pathtype;
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->out.can_path));
+ NDR_PULL_ALLOC_N(ndr, r->out.can_path, ndr_get_array_size(ndr, &r->out.can_path));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.can_path, ndr_get_array_size(ndr, &r->out.can_path)));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.pathtype);
+ }
+ _mem_save_pathtype_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.pathtype, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.pathtype));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_pathtype_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ if (r->out.can_path) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->out.can_path, r->in.maxbuf));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetPathCanonicalize(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetPathCanonicalize *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetPathCanonicalize");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetPathCanonicalize");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "path", r->in.path);
+ ndr_print_uint32(ndr, "maxbuf", r->in.maxbuf);
+ ndr_print_string(ndr, "prefix", r->in.prefix);
+ ndr_print_ptr(ndr, "pathtype", r->in.pathtype);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "pathtype", *r->in.pathtype);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "pathflags", r->in.pathflags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetPathCanonicalize");
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "can_path", r->out.can_path, r->in.maxbuf);
+ ndr_print_ptr(ndr, "pathtype", r->out.pathtype);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "pathtype", *r->out.pathtype);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetPathCompare(struct ndr_push *ndr, int flags, const struct srvsvc_NetPathCompare *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.path1, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.path1, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.path1, ndr_charset_length(r->in.path1, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.path2, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.path2, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.path2, ndr_charset_length(r->in.path2, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.pathtype));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.pathflags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetPathCompare(struct ndr_pull *ndr, int flags, struct srvsvc_NetPathCompare *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.path1));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.path1));
+ if (ndr_get_array_length(ndr, &r->in.path1) > ndr_get_array_size(ndr, &r->in.path1)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.path1), ndr_get_array_length(ndr, &r->in.path1));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.path1), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.path1, ndr_get_array_length(ndr, &r->in.path1), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.path2));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.path2));
+ if (ndr_get_array_length(ndr, &r->in.path2) > ndr_get_array_size(ndr, &r->in.path2)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.path2), ndr_get_array_length(ndr, &r->in.path2));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.path2), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.path2, ndr_get_array_length(ndr, &r->in.path2), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.pathtype));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.pathflags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetPathCompare(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetPathCompare *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetPathCompare");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetPathCompare");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "path1", r->in.path1);
+ ndr_print_string(ndr, "path2", r->in.path2);
+ ndr_print_uint32(ndr, "pathtype", r->in.pathtype);
+ ndr_print_uint32(ndr, "pathflags", r->in.pathflags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetPathCompare");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetNameValidate(struct ndr_push *ndr, int flags, const struct srvsvc_NetNameValidate *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.name, ndr_charset_length(r->in.name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.name_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetNameValidate(struct ndr_pull *ndr, int flags, struct srvsvc_NetNameValidate *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.name));
+ if (ndr_get_array_length(ndr, &r->in.name) > ndr_get_array_size(ndr, &r->in.name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.name), ndr_get_array_length(ndr, &r->in.name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.name, ndr_get_array_length(ndr, &r->in.name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.name_type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetNameValidate(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetNameValidate *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetNameValidate");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetNameValidate");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "name", r->in.name);
+ ndr_print_uint32(ndr, "name_type", r->in.name_type);
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetNameValidate");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NETRPRNAMECANONICALIZE(struct ndr_push *ndr, int flags, const struct srvsvc_NETRPRNAMECANONICALIZE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NETRPRNAMECANONICALIZE(struct ndr_pull *ndr, int flags, struct srvsvc_NETRPRNAMECANONICALIZE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NETRPRNAMECANONICALIZE(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRPRNAMECANONICALIZE *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NETRPRNAMECANONICALIZE");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NETRPRNAMECANONICALIZE");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NETRPRNAMECANONICALIZE");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetPRNameCompare(struct ndr_push *ndr, int flags, const struct srvsvc_NetPRNameCompare *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.name1, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.name1, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.name1, ndr_charset_length(r->in.name1, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.name2, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.name2, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.name2, ndr_charset_length(r->in.name2, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.name_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetPRNameCompare(struct ndr_pull *ndr, int flags, struct srvsvc_NetPRNameCompare *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.name1));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.name1));
+ if (ndr_get_array_length(ndr, &r->in.name1) > ndr_get_array_size(ndr, &r->in.name1)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.name1), ndr_get_array_length(ndr, &r->in.name1));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.name1), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.name1, ndr_get_array_length(ndr, &r->in.name1), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.name2));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.name2));
+ if (ndr_get_array_length(ndr, &r->in.name2) > ndr_get_array_size(ndr, &r->in.name2)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.name2), ndr_get_array_length(ndr, &r->in.name2));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.name2), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.name2, ndr_get_array_length(ndr, &r->in.name2), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.name_type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetPRNameCompare(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetPRNameCompare *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetPRNameCompare");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetPRNameCompare");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "name1", r->in.name1);
+ ndr_print_string(ndr, "name2", r->in.name2);
+ ndr_print_uint32(ndr, "name_type", r->in.name_type);
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetPRNameCompare");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareEnum(struct ndr_push *ndr, int flags, const struct srvsvc_NetShareEnum *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.info_ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info_ctr));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_buffer));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.resume_handle));
+ if (r->in.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info_ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_srvsvc_NetShareInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info_ctr));
+ if (r->out.totalentries == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.totalentries));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.resume_handle));
+ if (r->out.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareEnum(struct ndr_pull *ndr, int flags, struct srvsvc_NetShareEnum *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_resume_handle;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_info_ctr_0;
+ TALLOC_CTX *_mem_save_totalentries_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info_ctr);
+ }
+ _mem_save_info_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info_ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info_ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_buffer));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ } else {
+ r->in.resume_handle = NULL;
+ }
+ if (r->in.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.info_ctr);
+ *r->out.info_ctr = *r->in.info_ctr;
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ ZERO_STRUCTP(r->out.totalentries);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info_ctr);
+ }
+ _mem_save_info_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info_ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_srvsvc_NetShareInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info_ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.totalentries);
+ }
+ _mem_save_totalentries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.totalentries, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.totalentries));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_totalentries_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ } else {
+ r->out.resume_handle = NULL;
+ }
+ if (r->out.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareEnum *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareEnum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetShareEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "info_ctr", r->in.info_ctr);
+ ndr->depth++;
+ ndr_print_srvsvc_NetShareInfoCtr(ndr, "info_ctr", r->in.info_ctr);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_buffer", r->in.max_buffer);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ if (r->in.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetShareEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info_ctr", r->out.info_ctr);
+ ndr->depth++;
+ ndr_print_srvsvc_NetShareInfoCtr(ndr, "info_ctr", r->out.info_ctr);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "totalentries", r->out.totalentries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "totalentries", *r->out.totalentries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ if (r->out.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareDelStart(struct ndr_push *ndr, int flags, const struct srvsvc_NetShareDelStart *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.share, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.share, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.share, ndr_charset_length(r->in.share, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.reserved));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.hnd));
+ if (r->out.hnd) {
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.hnd));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareDelStart(struct ndr_pull *ndr, int flags, struct srvsvc_NetShareDelStart *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_hnd;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_hnd_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.share));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.share));
+ if (ndr_get_array_length(ndr, &r->in.share) > ndr_get_array_size(ndr, &r->in.share)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.share), ndr_get_array_length(ndr, &r->in.share));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.share), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.share, ndr_get_array_length(ndr, &r->in.share), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.reserved));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_hnd));
+ if (_ptr_hnd) {
+ NDR_PULL_ALLOC(ndr, r->out.hnd);
+ } else {
+ r->out.hnd = NULL;
+ }
+ if (r->out.hnd) {
+ _mem_save_hnd_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.hnd, 0);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.hnd));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_hnd_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareDelStart(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareDelStart *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareDelStart");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetShareDelStart");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "share", r->in.share);
+ ndr_print_uint32(ndr, "reserved", r->in.reserved);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetShareDelStart");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "hnd", r->out.hnd);
+ ndr->depth++;
+ if (r->out.hnd) {
+ ndr_print_policy_handle(ndr, "hnd", r->out.hnd);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetShareDelCommit(struct ndr_push *ndr, int flags, const struct srvsvc_NetShareDelCommit *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.hnd));
+ if (r->in.hnd) {
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.hnd));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.hnd));
+ if (r->out.hnd) {
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.hnd));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetShareDelCommit(struct ndr_pull *ndr, int flags, struct srvsvc_NetShareDelCommit *r)
+{
+ uint32_t _ptr_hnd;
+ TALLOC_CTX *_mem_save_hnd_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_hnd));
+ if (_ptr_hnd) {
+ NDR_PULL_ALLOC(ndr, r->in.hnd);
+ } else {
+ r->in.hnd = NULL;
+ }
+ if (r->in.hnd) {
+ _mem_save_hnd_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.hnd, 0);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.hnd));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_hnd_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_hnd));
+ if (_ptr_hnd) {
+ NDR_PULL_ALLOC(ndr, r->out.hnd);
+ } else {
+ r->out.hnd = NULL;
+ }
+ if (r->out.hnd) {
+ _mem_save_hnd_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.hnd, 0);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.hnd));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_hnd_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetShareDelCommit(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareDelCommit *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetShareDelCommit");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetShareDelCommit");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "hnd", r->in.hnd);
+ ndr->depth++;
+ if (r->in.hnd) {
+ ndr_print_policy_handle(ndr, "hnd", r->in.hnd);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetShareDelCommit");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "hnd", r->out.hnd);
+ ndr->depth++;
+ if (r->out.hnd) {
+ ndr_print_policy_handle(ndr, "hnd", r->out.hnd);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetGetFileSecurity(struct ndr_push *ndr, int flags, const struct srvsvc_NetGetFileSecurity *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.share));
+ if (r->in.share) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.share, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.share, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.share, ndr_charset_length(r->in.share, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.file, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.file, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.file, ndr_charset_length(r->in.file, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_security_secinfo(ndr, NDR_SCALARS, r->in.securityinformation));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.sd_buf == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.sd_buf));
+ if (*r->out.sd_buf) {
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.sd_buf));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetGetFileSecurity(struct ndr_pull *ndr, int flags, struct srvsvc_NetGetFileSecurity *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_share;
+ uint32_t _ptr_sd_buf;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_share_0;
+ TALLOC_CTX *_mem_save_sd_buf_0;
+ TALLOC_CTX *_mem_save_sd_buf_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_share));
+ if (_ptr_share) {
+ NDR_PULL_ALLOC(ndr, r->in.share);
+ } else {
+ r->in.share = NULL;
+ }
+ if (r->in.share) {
+ _mem_save_share_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.share, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.share));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.share));
+ if (ndr_get_array_length(ndr, &r->in.share) > ndr_get_array_size(ndr, &r->in.share)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.share), ndr_get_array_length(ndr, &r->in.share));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.share), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.share, ndr_get_array_length(ndr, &r->in.share), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_share_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.file));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.file));
+ if (ndr_get_array_length(ndr, &r->in.file) > ndr_get_array_size(ndr, &r->in.file)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.file), ndr_get_array_length(ndr, &r->in.file));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.file), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.file, ndr_get_array_length(ndr, &r->in.file), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_security_secinfo(ndr, NDR_SCALARS, &r->in.securityinformation));
+ NDR_PULL_ALLOC(ndr, r->out.sd_buf);
+ ZERO_STRUCTP(r->out.sd_buf);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sd_buf);
+ }
+ _mem_save_sd_buf_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sd_buf, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sd_buf));
+ if (_ptr_sd_buf) {
+ NDR_PULL_ALLOC(ndr, *r->out.sd_buf);
+ } else {
+ *r->out.sd_buf = NULL;
+ }
+ if (*r->out.sd_buf) {
+ _mem_save_sd_buf_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.sd_buf, 0);
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.sd_buf));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sd_buf_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sd_buf_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetGetFileSecurity(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetGetFileSecurity *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetGetFileSecurity");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetGetFileSecurity");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "share", r->in.share);
+ ndr->depth++;
+ if (r->in.share) {
+ ndr_print_string(ndr, "share", r->in.share);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "file", r->in.file);
+ ndr_print_security_secinfo(ndr, "securityinformation", r->in.securityinformation);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetGetFileSecurity");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sd_buf", r->out.sd_buf);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sd_buf", *r->out.sd_buf);
+ ndr->depth++;
+ if (*r->out.sd_buf) {
+ ndr_print_sec_desc_buf(ndr, "sd_buf", *r->out.sd_buf);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetSetFileSecurity(struct ndr_push *ndr, int flags, const struct srvsvc_NetSetFileSecurity *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.share));
+ if (r->in.share) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.share, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.share, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.share, ndr_charset_length(r->in.share, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.file, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.file, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.file, ndr_charset_length(r->in.file, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_security_secinfo(ndr, NDR_SCALARS, r->in.securityinformation));
+ if (r->in.sd_buf == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_sec_desc_buf(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sd_buf));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetSetFileSecurity(struct ndr_pull *ndr, int flags, struct srvsvc_NetSetFileSecurity *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_share;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_share_0;
+ TALLOC_CTX *_mem_save_sd_buf_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_share));
+ if (_ptr_share) {
+ NDR_PULL_ALLOC(ndr, r->in.share);
+ } else {
+ r->in.share = NULL;
+ }
+ if (r->in.share) {
+ _mem_save_share_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.share, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.share));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.share));
+ if (ndr_get_array_length(ndr, &r->in.share) > ndr_get_array_size(ndr, &r->in.share)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.share), ndr_get_array_length(ndr, &r->in.share));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.share), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.share, ndr_get_array_length(ndr, &r->in.share), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_share_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.file));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.file));
+ if (ndr_get_array_length(ndr, &r->in.file) > ndr_get_array_size(ndr, &r->in.file)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.file), ndr_get_array_length(ndr, &r->in.file));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.file), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.file, ndr_get_array_length(ndr, &r->in.file), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_security_secinfo(ndr, NDR_SCALARS, &r->in.securityinformation));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sd_buf);
+ }
+ _mem_save_sd_buf_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sd_buf, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_sec_desc_buf(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sd_buf));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sd_buf_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetSetFileSecurity(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSetFileSecurity *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetSetFileSecurity");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetSetFileSecurity");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "share", r->in.share);
+ ndr->depth++;
+ if (r->in.share) {
+ ndr_print_string(ndr, "share", r->in.share);
+ }
+ ndr->depth--;
+ ndr_print_string(ndr, "file", r->in.file);
+ ndr_print_security_secinfo(ndr, "securityinformation", r->in.securityinformation);
+ ndr_print_ptr(ndr, "sd_buf", r->in.sd_buf);
+ ndr->depth++;
+ ndr_print_sec_desc_buf(ndr, "sd_buf", r->in.sd_buf);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetSetFileSecurity");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetServerTransportAddEx(struct ndr_push *ndr, int flags, const struct srvsvc_NetServerTransportAddEx *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_srvsvc_NetTransportInfo(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.info));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetServerTransportAddEx(struct ndr_pull *ndr, int flags, struct srvsvc_NetServerTransportAddEx *r)
+{
+ uint32_t _ptr_server_unc;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_srvsvc_NetTransportInfo(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.info));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetServerTransportAddEx(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetServerTransportAddEx *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetServerTransportAddEx");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetServerTransportAddEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_set_switch_value(ndr, &r->in.info, r->in.level);
+ ndr_print_srvsvc_NetTransportInfo(ndr, "info", &r->in.info);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetServerTransportAddEx");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NetServerSetServiceBitsEx(struct ndr_push *ndr, int flags, const struct srvsvc_NetServerSetServiceBitsEx *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_unc));
+ if (r->in.server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_unc, ndr_charset_length(r->in.server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.emulated_server_unc));
+ if (r->in.emulated_server_unc) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.emulated_server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.emulated_server_unc, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.emulated_server_unc, ndr_charset_length(r->in.emulated_server_unc, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.transport));
+ if (r->in.transport) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.transport, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.transport, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.transport, ndr_charset_length(r->in.transport, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.servicebitsofinterest));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.servicebits));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.updateimmediately));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NetServerSetServiceBitsEx(struct ndr_pull *ndr, int flags, struct srvsvc_NetServerSetServiceBitsEx *r)
+{
+ uint32_t _ptr_server_unc;
+ uint32_t _ptr_emulated_server_unc;
+ uint32_t _ptr_transport;
+ TALLOC_CTX *_mem_save_server_unc_0;
+ TALLOC_CTX *_mem_save_emulated_server_unc_0;
+ TALLOC_CTX *_mem_save_transport_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_unc));
+ if (_ptr_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.server_unc);
+ } else {
+ r->in.server_unc = NULL;
+ }
+ if (r->in.server_unc) {
+ _mem_save_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_unc));
+ if (ndr_get_array_length(ndr, &r->in.server_unc) > ndr_get_array_size(ndr, &r->in.server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_unc), ndr_get_array_length(ndr, &r->in.server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_unc, ndr_get_array_length(ndr, &r->in.server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_emulated_server_unc));
+ if (_ptr_emulated_server_unc) {
+ NDR_PULL_ALLOC(ndr, r->in.emulated_server_unc);
+ } else {
+ r->in.emulated_server_unc = NULL;
+ }
+ if (r->in.emulated_server_unc) {
+ _mem_save_emulated_server_unc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.emulated_server_unc, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.emulated_server_unc));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.emulated_server_unc));
+ if (ndr_get_array_length(ndr, &r->in.emulated_server_unc) > ndr_get_array_size(ndr, &r->in.emulated_server_unc)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.emulated_server_unc), ndr_get_array_length(ndr, &r->in.emulated_server_unc));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.emulated_server_unc), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.emulated_server_unc, ndr_get_array_length(ndr, &r->in.emulated_server_unc), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_emulated_server_unc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_transport));
+ if (_ptr_transport) {
+ NDR_PULL_ALLOC(ndr, r->in.transport);
+ } else {
+ r->in.transport = NULL;
+ }
+ if (r->in.transport) {
+ _mem_save_transport_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.transport, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.transport));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.transport));
+ if (ndr_get_array_length(ndr, &r->in.transport) > ndr_get_array_size(ndr, &r->in.transport)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.transport), ndr_get_array_length(ndr, &r->in.transport));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.transport), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.transport, ndr_get_array_length(ndr, &r->in.transport), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_transport_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.servicebitsofinterest));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.servicebits));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.updateimmediately));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NetServerSetServiceBitsEx(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetServerSetServiceBitsEx *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NetServerSetServiceBitsEx");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NetServerSetServiceBitsEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_unc", r->in.server_unc);
+ ndr->depth++;
+ if (r->in.server_unc) {
+ ndr_print_string(ndr, "server_unc", r->in.server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "emulated_server_unc", r->in.emulated_server_unc);
+ ndr->depth++;
+ if (r->in.emulated_server_unc) {
+ ndr_print_string(ndr, "emulated_server_unc", r->in.emulated_server_unc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "transport", r->in.transport);
+ ndr->depth++;
+ if (r->in.transport) {
+ ndr_print_string(ndr, "transport", r->in.transport);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "servicebitsofinterest", r->in.servicebitsofinterest);
+ ndr_print_uint32(ndr, "servicebits", r->in.servicebits);
+ ndr_print_uint32(ndr, "updateimmediately", r->in.updateimmediately);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NetServerSetServiceBitsEx");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NETRDFSGETVERSION(struct ndr_push *ndr, int flags, const struct srvsvc_NETRDFSGETVERSION *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NETRDFSGETVERSION(struct ndr_pull *ndr, int flags, struct srvsvc_NETRDFSGETVERSION *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSGETVERSION(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSGETVERSION *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NETRDFSGETVERSION");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NETRDFSGETVERSION");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NETRDFSGETVERSION");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NETRDFSCREATELOCALPARTITION(struct ndr_push *ndr, int flags, const struct srvsvc_NETRDFSCREATELOCALPARTITION *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NETRDFSCREATELOCALPARTITION(struct ndr_pull *ndr, int flags, struct srvsvc_NETRDFSCREATELOCALPARTITION *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSCREATELOCALPARTITION(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSCREATELOCALPARTITION *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NETRDFSCREATELOCALPARTITION");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NETRDFSCREATELOCALPARTITION");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NETRDFSCREATELOCALPARTITION");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NETRDFSDELETELOCALPARTITION(struct ndr_push *ndr, int flags, const struct srvsvc_NETRDFSDELETELOCALPARTITION *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NETRDFSDELETELOCALPARTITION(struct ndr_pull *ndr, int flags, struct srvsvc_NETRDFSDELETELOCALPARTITION *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSDELETELOCALPARTITION(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSDELETELOCALPARTITION *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NETRDFSDELETELOCALPARTITION");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NETRDFSDELETELOCALPARTITION");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NETRDFSDELETELOCALPARTITION");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NETRDFSSETLOCALVOLUMESTATE(struct ndr_push *ndr, int flags, const struct srvsvc_NETRDFSSETLOCALVOLUMESTATE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NETRDFSSETLOCALVOLUMESTATE(struct ndr_pull *ndr, int flags, struct srvsvc_NETRDFSSETLOCALVOLUMESTATE *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSSETLOCALVOLUMESTATE(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSSETLOCALVOLUMESTATE *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NETRDFSSETLOCALVOLUMESTATE");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NETRDFSSETLOCALVOLUMESTATE");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NETRDFSSETLOCALVOLUMESTATE");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NETRDFSSETSERVERINFO(struct ndr_push *ndr, int flags, const struct srvsvc_NETRDFSSETSERVERINFO *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NETRDFSSETSERVERINFO(struct ndr_pull *ndr, int flags, struct srvsvc_NETRDFSSETSERVERINFO *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSSETSERVERINFO(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSSETSERVERINFO *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NETRDFSSETSERVERINFO");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NETRDFSSETSERVERINFO");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NETRDFSSETSERVERINFO");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NETRDFSCREATEEXITPOINT(struct ndr_push *ndr, int flags, const struct srvsvc_NETRDFSCREATEEXITPOINT *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NETRDFSCREATEEXITPOINT(struct ndr_pull *ndr, int flags, struct srvsvc_NETRDFSCREATEEXITPOINT *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSCREATEEXITPOINT(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSCREATEEXITPOINT *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NETRDFSCREATEEXITPOINT");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NETRDFSCREATEEXITPOINT");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NETRDFSCREATEEXITPOINT");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NETRDFSDELETEEXITPOINT(struct ndr_push *ndr, int flags, const struct srvsvc_NETRDFSDELETEEXITPOINT *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NETRDFSDELETEEXITPOINT(struct ndr_pull *ndr, int flags, struct srvsvc_NETRDFSDELETEEXITPOINT *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSDELETEEXITPOINT(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSDELETEEXITPOINT *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NETRDFSDELETEEXITPOINT");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NETRDFSDELETEEXITPOINT");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NETRDFSDELETEEXITPOINT");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NETRDFSMODIFYPREFIX(struct ndr_push *ndr, int flags, const struct srvsvc_NETRDFSMODIFYPREFIX *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NETRDFSMODIFYPREFIX(struct ndr_pull *ndr, int flags, struct srvsvc_NETRDFSMODIFYPREFIX *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSMODIFYPREFIX(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSMODIFYPREFIX *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NETRDFSMODIFYPREFIX");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NETRDFSMODIFYPREFIX");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NETRDFSMODIFYPREFIX");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NETRDFSFIXLOCALVOLUME(struct ndr_push *ndr, int flags, const struct srvsvc_NETRDFSFIXLOCALVOLUME *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NETRDFSFIXLOCALVOLUME(struct ndr_pull *ndr, int flags, struct srvsvc_NETRDFSFIXLOCALVOLUME *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSFIXLOCALVOLUME(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSFIXLOCALVOLUME *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NETRDFSFIXLOCALVOLUME");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NETRDFSFIXLOCALVOLUME");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NETRDFSFIXLOCALVOLUME");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NETRDFSMANAGERREPORTSITEINFO(struct ndr_push *ndr, int flags, const struct srvsvc_NETRDFSMANAGERREPORTSITEINFO *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NETRDFSMANAGERREPORTSITEINFO(struct ndr_pull *ndr, int flags, struct srvsvc_NETRDFSMANAGERREPORTSITEINFO *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NETRDFSMANAGERREPORTSITEINFO(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSMANAGERREPORTSITEINFO *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NETRDFSMANAGERREPORTSITEINFO");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NETRDFSMANAGERREPORTSITEINFO");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NETRDFSMANAGERREPORTSITEINFO");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_srvsvc_NETRSERVERTRANSPORTDELEX(struct ndr_push *ndr, int flags, const struct srvsvc_NETRSERVERTRANSPORTDELEX *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_srvsvc_NETRSERVERTRANSPORTDELEX(struct ndr_pull *ndr, int flags, struct srvsvc_NETRSERVERTRANSPORTDELEX *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_srvsvc_NETRSERVERTRANSPORTDELEX(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRSERVERTRANSPORTDELEX *r)
+{
+ ndr_print_struct(ndr, name, "srvsvc_NETRSERVERTRANSPORTDELEX");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "srvsvc_NETRSERVERTRANSPORTDELEX");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "srvsvc_NETRSERVERTRANSPORTDELEX");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call srvsvc_calls[] = {
+ {
+ "srvsvc_NetCharDevEnum",
+ sizeof(struct srvsvc_NetCharDevEnum),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetCharDevEnum,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetCharDevEnum,
+ (ndr_print_function_t) ndr_print_srvsvc_NetCharDevEnum,
+ false,
+ },
+ {
+ "srvsvc_NetCharDevGetInfo",
+ sizeof(struct srvsvc_NetCharDevGetInfo),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetCharDevGetInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetCharDevGetInfo,
+ (ndr_print_function_t) ndr_print_srvsvc_NetCharDevGetInfo,
+ false,
+ },
+ {
+ "srvsvc_NetCharDevControl",
+ sizeof(struct srvsvc_NetCharDevControl),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetCharDevControl,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetCharDevControl,
+ (ndr_print_function_t) ndr_print_srvsvc_NetCharDevControl,
+ false,
+ },
+ {
+ "srvsvc_NetCharDevQEnum",
+ sizeof(struct srvsvc_NetCharDevQEnum),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetCharDevQEnum,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetCharDevQEnum,
+ (ndr_print_function_t) ndr_print_srvsvc_NetCharDevQEnum,
+ false,
+ },
+ {
+ "srvsvc_NetCharDevQGetInfo",
+ sizeof(struct srvsvc_NetCharDevQGetInfo),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetCharDevQGetInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetCharDevQGetInfo,
+ (ndr_print_function_t) ndr_print_srvsvc_NetCharDevQGetInfo,
+ false,
+ },
+ {
+ "srvsvc_NetCharDevQSetInfo",
+ sizeof(struct srvsvc_NetCharDevQSetInfo),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetCharDevQSetInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetCharDevQSetInfo,
+ (ndr_print_function_t) ndr_print_srvsvc_NetCharDevQSetInfo,
+ false,
+ },
+ {
+ "srvsvc_NetCharDevQPurge",
+ sizeof(struct srvsvc_NetCharDevQPurge),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetCharDevQPurge,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetCharDevQPurge,
+ (ndr_print_function_t) ndr_print_srvsvc_NetCharDevQPurge,
+ false,
+ },
+ {
+ "srvsvc_NetCharDevQPurgeSelf",
+ sizeof(struct srvsvc_NetCharDevQPurgeSelf),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetCharDevQPurgeSelf,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetCharDevQPurgeSelf,
+ (ndr_print_function_t) ndr_print_srvsvc_NetCharDevQPurgeSelf,
+ false,
+ },
+ {
+ "srvsvc_NetConnEnum",
+ sizeof(struct srvsvc_NetConnEnum),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetConnEnum,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetConnEnum,
+ (ndr_print_function_t) ndr_print_srvsvc_NetConnEnum,
+ false,
+ },
+ {
+ "srvsvc_NetFileEnum",
+ sizeof(struct srvsvc_NetFileEnum),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetFileEnum,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetFileEnum,
+ (ndr_print_function_t) ndr_print_srvsvc_NetFileEnum,
+ false,
+ },
+ {
+ "srvsvc_NetFileGetInfo",
+ sizeof(struct srvsvc_NetFileGetInfo),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetFileGetInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetFileGetInfo,
+ (ndr_print_function_t) ndr_print_srvsvc_NetFileGetInfo,
+ false,
+ },
+ {
+ "srvsvc_NetFileClose",
+ sizeof(struct srvsvc_NetFileClose),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetFileClose,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetFileClose,
+ (ndr_print_function_t) ndr_print_srvsvc_NetFileClose,
+ false,
+ },
+ {
+ "srvsvc_NetSessEnum",
+ sizeof(struct srvsvc_NetSessEnum),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetSessEnum,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetSessEnum,
+ (ndr_print_function_t) ndr_print_srvsvc_NetSessEnum,
+ false,
+ },
+ {
+ "srvsvc_NetSessDel",
+ sizeof(struct srvsvc_NetSessDel),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetSessDel,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetSessDel,
+ (ndr_print_function_t) ndr_print_srvsvc_NetSessDel,
+ false,
+ },
+ {
+ "srvsvc_NetShareAdd",
+ sizeof(struct srvsvc_NetShareAdd),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareAdd,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareAdd,
+ (ndr_print_function_t) ndr_print_srvsvc_NetShareAdd,
+ false,
+ },
+ {
+ "srvsvc_NetShareEnumAll",
+ sizeof(struct srvsvc_NetShareEnumAll),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareEnumAll,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareEnumAll,
+ (ndr_print_function_t) ndr_print_srvsvc_NetShareEnumAll,
+ false,
+ },
+ {
+ "srvsvc_NetShareGetInfo",
+ sizeof(struct srvsvc_NetShareGetInfo),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareGetInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareGetInfo,
+ (ndr_print_function_t) ndr_print_srvsvc_NetShareGetInfo,
+ false,
+ },
+ {
+ "srvsvc_NetShareSetInfo",
+ sizeof(struct srvsvc_NetShareSetInfo),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareSetInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareSetInfo,
+ (ndr_print_function_t) ndr_print_srvsvc_NetShareSetInfo,
+ false,
+ },
+ {
+ "srvsvc_NetShareDel",
+ sizeof(struct srvsvc_NetShareDel),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareDel,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareDel,
+ (ndr_print_function_t) ndr_print_srvsvc_NetShareDel,
+ false,
+ },
+ {
+ "srvsvc_NetShareDelSticky",
+ sizeof(struct srvsvc_NetShareDelSticky),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareDelSticky,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareDelSticky,
+ (ndr_print_function_t) ndr_print_srvsvc_NetShareDelSticky,
+ false,
+ },
+ {
+ "srvsvc_NetShareCheck",
+ sizeof(struct srvsvc_NetShareCheck),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareCheck,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareCheck,
+ (ndr_print_function_t) ndr_print_srvsvc_NetShareCheck,
+ false,
+ },
+ {
+ "srvsvc_NetSrvGetInfo",
+ sizeof(struct srvsvc_NetSrvGetInfo),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetSrvGetInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetSrvGetInfo,
+ (ndr_print_function_t) ndr_print_srvsvc_NetSrvGetInfo,
+ false,
+ },
+ {
+ "srvsvc_NetSrvSetInfo",
+ sizeof(struct srvsvc_NetSrvSetInfo),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetSrvSetInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetSrvSetInfo,
+ (ndr_print_function_t) ndr_print_srvsvc_NetSrvSetInfo,
+ false,
+ },
+ {
+ "srvsvc_NetDiskEnum",
+ sizeof(struct srvsvc_NetDiskEnum),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetDiskEnum,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetDiskEnum,
+ (ndr_print_function_t) ndr_print_srvsvc_NetDiskEnum,
+ false,
+ },
+ {
+ "srvsvc_NetServerStatisticsGet",
+ sizeof(struct srvsvc_NetServerStatisticsGet),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetServerStatisticsGet,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetServerStatisticsGet,
+ (ndr_print_function_t) ndr_print_srvsvc_NetServerStatisticsGet,
+ false,
+ },
+ {
+ "srvsvc_NetTransportAdd",
+ sizeof(struct srvsvc_NetTransportAdd),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetTransportAdd,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetTransportAdd,
+ (ndr_print_function_t) ndr_print_srvsvc_NetTransportAdd,
+ false,
+ },
+ {
+ "srvsvc_NetTransportEnum",
+ sizeof(struct srvsvc_NetTransportEnum),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetTransportEnum,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetTransportEnum,
+ (ndr_print_function_t) ndr_print_srvsvc_NetTransportEnum,
+ false,
+ },
+ {
+ "srvsvc_NetTransportDel",
+ sizeof(struct srvsvc_NetTransportDel),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetTransportDel,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetTransportDel,
+ (ndr_print_function_t) ndr_print_srvsvc_NetTransportDel,
+ false,
+ },
+ {
+ "srvsvc_NetRemoteTOD",
+ sizeof(struct srvsvc_NetRemoteTOD),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetRemoteTOD,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetRemoteTOD,
+ (ndr_print_function_t) ndr_print_srvsvc_NetRemoteTOD,
+ false,
+ },
+ {
+ "srvsvc_NetSetServiceBits",
+ sizeof(struct srvsvc_NetSetServiceBits),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetSetServiceBits,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetSetServiceBits,
+ (ndr_print_function_t) ndr_print_srvsvc_NetSetServiceBits,
+ false,
+ },
+ {
+ "srvsvc_NetPathType",
+ sizeof(struct srvsvc_NetPathType),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetPathType,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetPathType,
+ (ndr_print_function_t) ndr_print_srvsvc_NetPathType,
+ false,
+ },
+ {
+ "srvsvc_NetPathCanonicalize",
+ sizeof(struct srvsvc_NetPathCanonicalize),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetPathCanonicalize,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetPathCanonicalize,
+ (ndr_print_function_t) ndr_print_srvsvc_NetPathCanonicalize,
+ false,
+ },
+ {
+ "srvsvc_NetPathCompare",
+ sizeof(struct srvsvc_NetPathCompare),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetPathCompare,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetPathCompare,
+ (ndr_print_function_t) ndr_print_srvsvc_NetPathCompare,
+ false,
+ },
+ {
+ "srvsvc_NetNameValidate",
+ sizeof(struct srvsvc_NetNameValidate),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetNameValidate,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetNameValidate,
+ (ndr_print_function_t) ndr_print_srvsvc_NetNameValidate,
+ false,
+ },
+ {
+ "srvsvc_NETRPRNAMECANONICALIZE",
+ sizeof(struct srvsvc_NETRPRNAMECANONICALIZE),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NETRPRNAMECANONICALIZE,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRPRNAMECANONICALIZE,
+ (ndr_print_function_t) ndr_print_srvsvc_NETRPRNAMECANONICALIZE,
+ false,
+ },
+ {
+ "srvsvc_NetPRNameCompare",
+ sizeof(struct srvsvc_NetPRNameCompare),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetPRNameCompare,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetPRNameCompare,
+ (ndr_print_function_t) ndr_print_srvsvc_NetPRNameCompare,
+ false,
+ },
+ {
+ "srvsvc_NetShareEnum",
+ sizeof(struct srvsvc_NetShareEnum),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareEnum,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareEnum,
+ (ndr_print_function_t) ndr_print_srvsvc_NetShareEnum,
+ false,
+ },
+ {
+ "srvsvc_NetShareDelStart",
+ sizeof(struct srvsvc_NetShareDelStart),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareDelStart,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareDelStart,
+ (ndr_print_function_t) ndr_print_srvsvc_NetShareDelStart,
+ false,
+ },
+ {
+ "srvsvc_NetShareDelCommit",
+ sizeof(struct srvsvc_NetShareDelCommit),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareDelCommit,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareDelCommit,
+ (ndr_print_function_t) ndr_print_srvsvc_NetShareDelCommit,
+ false,
+ },
+ {
+ "srvsvc_NetGetFileSecurity",
+ sizeof(struct srvsvc_NetGetFileSecurity),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetGetFileSecurity,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetGetFileSecurity,
+ (ndr_print_function_t) ndr_print_srvsvc_NetGetFileSecurity,
+ false,
+ },
+ {
+ "srvsvc_NetSetFileSecurity",
+ sizeof(struct srvsvc_NetSetFileSecurity),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetSetFileSecurity,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetSetFileSecurity,
+ (ndr_print_function_t) ndr_print_srvsvc_NetSetFileSecurity,
+ false,
+ },
+ {
+ "srvsvc_NetServerTransportAddEx",
+ sizeof(struct srvsvc_NetServerTransportAddEx),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetServerTransportAddEx,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetServerTransportAddEx,
+ (ndr_print_function_t) ndr_print_srvsvc_NetServerTransportAddEx,
+ false,
+ },
+ {
+ "srvsvc_NetServerSetServiceBitsEx",
+ sizeof(struct srvsvc_NetServerSetServiceBitsEx),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NetServerSetServiceBitsEx,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetServerSetServiceBitsEx,
+ (ndr_print_function_t) ndr_print_srvsvc_NetServerSetServiceBitsEx,
+ false,
+ },
+ {
+ "srvsvc_NETRDFSGETVERSION",
+ sizeof(struct srvsvc_NETRDFSGETVERSION),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSGETVERSION,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSGETVERSION,
+ (ndr_print_function_t) ndr_print_srvsvc_NETRDFSGETVERSION,
+ false,
+ },
+ {
+ "srvsvc_NETRDFSCREATELOCALPARTITION",
+ sizeof(struct srvsvc_NETRDFSCREATELOCALPARTITION),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSCREATELOCALPARTITION,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSCREATELOCALPARTITION,
+ (ndr_print_function_t) ndr_print_srvsvc_NETRDFSCREATELOCALPARTITION,
+ false,
+ },
+ {
+ "srvsvc_NETRDFSDELETELOCALPARTITION",
+ sizeof(struct srvsvc_NETRDFSDELETELOCALPARTITION),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSDELETELOCALPARTITION,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSDELETELOCALPARTITION,
+ (ndr_print_function_t) ndr_print_srvsvc_NETRDFSDELETELOCALPARTITION,
+ false,
+ },
+ {
+ "srvsvc_NETRDFSSETLOCALVOLUMESTATE",
+ sizeof(struct srvsvc_NETRDFSSETLOCALVOLUMESTATE),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSSETLOCALVOLUMESTATE,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSSETLOCALVOLUMESTATE,
+ (ndr_print_function_t) ndr_print_srvsvc_NETRDFSSETLOCALVOLUMESTATE,
+ false,
+ },
+ {
+ "srvsvc_NETRDFSSETSERVERINFO",
+ sizeof(struct srvsvc_NETRDFSSETSERVERINFO),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSSETSERVERINFO,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSSETSERVERINFO,
+ (ndr_print_function_t) ndr_print_srvsvc_NETRDFSSETSERVERINFO,
+ false,
+ },
+ {
+ "srvsvc_NETRDFSCREATEEXITPOINT",
+ sizeof(struct srvsvc_NETRDFSCREATEEXITPOINT),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSCREATEEXITPOINT,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSCREATEEXITPOINT,
+ (ndr_print_function_t) ndr_print_srvsvc_NETRDFSCREATEEXITPOINT,
+ false,
+ },
+ {
+ "srvsvc_NETRDFSDELETEEXITPOINT",
+ sizeof(struct srvsvc_NETRDFSDELETEEXITPOINT),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSDELETEEXITPOINT,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSDELETEEXITPOINT,
+ (ndr_print_function_t) ndr_print_srvsvc_NETRDFSDELETEEXITPOINT,
+ false,
+ },
+ {
+ "srvsvc_NETRDFSMODIFYPREFIX",
+ sizeof(struct srvsvc_NETRDFSMODIFYPREFIX),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSMODIFYPREFIX,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSMODIFYPREFIX,
+ (ndr_print_function_t) ndr_print_srvsvc_NETRDFSMODIFYPREFIX,
+ false,
+ },
+ {
+ "srvsvc_NETRDFSFIXLOCALVOLUME",
+ sizeof(struct srvsvc_NETRDFSFIXLOCALVOLUME),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSFIXLOCALVOLUME,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSFIXLOCALVOLUME,
+ (ndr_print_function_t) ndr_print_srvsvc_NETRDFSFIXLOCALVOLUME,
+ false,
+ },
+ {
+ "srvsvc_NETRDFSMANAGERREPORTSITEINFO",
+ sizeof(struct srvsvc_NETRDFSMANAGERREPORTSITEINFO),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSMANAGERREPORTSITEINFO,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSMANAGERREPORTSITEINFO,
+ (ndr_print_function_t) ndr_print_srvsvc_NETRDFSMANAGERREPORTSITEINFO,
+ false,
+ },
+ {
+ "srvsvc_NETRSERVERTRANSPORTDELEX",
+ sizeof(struct srvsvc_NETRSERVERTRANSPORTDELEX),
+ (ndr_push_flags_fn_t) ndr_push_srvsvc_NETRSERVERTRANSPORTDELEX,
+ (ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRSERVERTRANSPORTDELEX,
+ (ndr_print_function_t) ndr_print_srvsvc_NETRSERVERTRANSPORTDELEX,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const srvsvc_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\srvsvc]",
+ "ncacn_ip_tcp:",
+ "ncalrpc:",
+};
+
+static const struct ndr_interface_string_array srvsvc_endpoints = {
+ .count = 3,
+ .names = srvsvc_endpoint_strings
+};
+
+static const char * const srvsvc_authservice_strings[] = {
+ "host",
+};
+
+static const struct ndr_interface_string_array srvsvc_authservices = {
+ .count = 1,
+ .names = srvsvc_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_srvsvc = {
+ .name = "srvsvc",
+ .syntax_id = {
+ {0x4b324fc8,0x1670,0x01d3,{0x12,0x78},{0x5a,0x47,0xbf,0x6e,0xe1,0x88}},
+ NDR_SRVSVC_VERSION
+ },
+ .helpstring = NDR_SRVSVC_HELPSTRING,
+ .num_calls = 54,
+ .calls = srvsvc_calls,
+ .endpoints = &srvsvc_endpoints,
+ .authservices = &srvsvc_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_srvsvc.h b/source3/librpc/gen_ndr/ndr_srvsvc.h
new file mode 100644
index 0000000000..8a29469ec5
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_srvsvc.h
@@ -0,0 +1,315 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/srvsvc.h"
+
+#ifndef _HEADER_NDR_srvsvc
+#define _HEADER_NDR_srvsvc
+
+#define NDR_SRVSVC_UUID "4b324fc8-1670-01d3-1278-5a47bf6ee188"
+#define NDR_SRVSVC_VERSION 3.0
+#define NDR_SRVSVC_NAME "srvsvc"
+#define NDR_SRVSVC_HELPSTRING "Server Service"
+extern const struct ndr_interface_table ndr_table_srvsvc;
+#define NDR_SRVSVC_NETCHARDEVENUM (0x00)
+
+#define NDR_SRVSVC_NETCHARDEVGETINFO (0x01)
+
+#define NDR_SRVSVC_NETCHARDEVCONTROL (0x02)
+
+#define NDR_SRVSVC_NETCHARDEVQENUM (0x03)
+
+#define NDR_SRVSVC_NETCHARDEVQGETINFO (0x04)
+
+#define NDR_SRVSVC_NETCHARDEVQSETINFO (0x05)
+
+#define NDR_SRVSVC_NETCHARDEVQPURGE (0x06)
+
+#define NDR_SRVSVC_NETCHARDEVQPURGESELF (0x07)
+
+#define NDR_SRVSVC_NETCONNENUM (0x08)
+
+#define NDR_SRVSVC_NETFILEENUM (0x09)
+
+#define NDR_SRVSVC_NETFILEGETINFO (0x0a)
+
+#define NDR_SRVSVC_NETFILECLOSE (0x0b)
+
+#define NDR_SRVSVC_NETSESSENUM (0x0c)
+
+#define NDR_SRVSVC_NETSESSDEL (0x0d)
+
+#define NDR_SRVSVC_NETSHAREADD (0x0e)
+
+#define NDR_SRVSVC_NETSHAREENUMALL (0x0f)
+
+#define NDR_SRVSVC_NETSHAREGETINFO (0x10)
+
+#define NDR_SRVSVC_NETSHARESETINFO (0x11)
+
+#define NDR_SRVSVC_NETSHAREDEL (0x12)
+
+#define NDR_SRVSVC_NETSHAREDELSTICKY (0x13)
+
+#define NDR_SRVSVC_NETSHARECHECK (0x14)
+
+#define NDR_SRVSVC_NETSRVGETINFO (0x15)
+
+#define NDR_SRVSVC_NETSRVSETINFO (0x16)
+
+#define NDR_SRVSVC_NETDISKENUM (0x17)
+
+#define NDR_SRVSVC_NETSERVERSTATISTICSGET (0x18)
+
+#define NDR_SRVSVC_NETTRANSPORTADD (0x19)
+
+#define NDR_SRVSVC_NETTRANSPORTENUM (0x1a)
+
+#define NDR_SRVSVC_NETTRANSPORTDEL (0x1b)
+
+#define NDR_SRVSVC_NETREMOTETOD (0x1c)
+
+#define NDR_SRVSVC_NETSETSERVICEBITS (0x1d)
+
+#define NDR_SRVSVC_NETPATHTYPE (0x1e)
+
+#define NDR_SRVSVC_NETPATHCANONICALIZE (0x1f)
+
+#define NDR_SRVSVC_NETPATHCOMPARE (0x20)
+
+#define NDR_SRVSVC_NETNAMEVALIDATE (0x21)
+
+#define NDR_SRVSVC_NETRPRNAMECANONICALIZE (0x22)
+
+#define NDR_SRVSVC_NETPRNAMECOMPARE (0x23)
+
+#define NDR_SRVSVC_NETSHAREENUM (0x24)
+
+#define NDR_SRVSVC_NETSHAREDELSTART (0x25)
+
+#define NDR_SRVSVC_NETSHAREDELCOMMIT (0x26)
+
+#define NDR_SRVSVC_NETGETFILESECURITY (0x27)
+
+#define NDR_SRVSVC_NETSETFILESECURITY (0x28)
+
+#define NDR_SRVSVC_NETSERVERTRANSPORTADDEX (0x29)
+
+#define NDR_SRVSVC_NETSERVERSETSERVICEBITSEX (0x2a)
+
+#define NDR_SRVSVC_NETRDFSGETVERSION (0x2b)
+
+#define NDR_SRVSVC_NETRDFSCREATELOCALPARTITION (0x2c)
+
+#define NDR_SRVSVC_NETRDFSDELETELOCALPARTITION (0x2d)
+
+#define NDR_SRVSVC_NETRDFSSETLOCALVOLUMESTATE (0x2e)
+
+#define NDR_SRVSVC_NETRDFSSETSERVERINFO (0x2f)
+
+#define NDR_SRVSVC_NETRDFSCREATEEXITPOINT (0x30)
+
+#define NDR_SRVSVC_NETRDFSDELETEEXITPOINT (0x31)
+
+#define NDR_SRVSVC_NETRDFSMODIFYPREFIX (0x32)
+
+#define NDR_SRVSVC_NETRDFSFIXLOCALVOLUME (0x33)
+
+#define NDR_SRVSVC_NETRDFSMANAGERREPORTSITEINFO (0x34)
+
+#define NDR_SRVSVC_NETRSERVERTRANSPORTDELEX (0x35)
+
+#define NDR_SRVSVC_CALL_COUNT (54)
+void ndr_print_srvsvc_NetCharDevInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevInfo0 *r);
+void ndr_print_srvsvc_NetCharDevCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevCtr0 *r);
+void ndr_print_srvsvc_NetCharDevInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevInfo1 *r);
+void ndr_print_srvsvc_NetCharDevCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevCtr1 *r);
+void ndr_print_srvsvc_NetCharDevInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetCharDevInfo *r);
+void ndr_print_srvsvc_NetCharDevCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetCharDevCtr *r);
+void ndr_print_srvsvc_NetCharDevQInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevQInfo0 *r);
+void ndr_print_srvsvc_NetCharDevQCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevQCtr0 *r);
+void ndr_print_srvsvc_NetCharDevQInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevQInfo1 *r);
+void ndr_print_srvsvc_NetCharDevQCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetCharDevQCtr1 *r);
+void ndr_print_srvsvc_NetCharDevQInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetCharDevQInfo *r);
+void ndr_print_srvsvc_NetCharDevQCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetCharDevQCtr *r);
+void ndr_print_srvsvc_NetConnInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetConnInfo0 *r);
+void ndr_print_srvsvc_NetConnCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetConnCtr0 *r);
+void ndr_print_srvsvc_NetConnInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetConnInfo1 *r);
+void ndr_print_srvsvc_NetConnCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetConnCtr1 *r);
+void ndr_print_srvsvc_NetConnCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetConnCtr *r);
+void ndr_print_srvsvc_NetConnInfoCtr(struct ndr_print *ndr, const char *name, const struct srvsvc_NetConnInfoCtr *r);
+void ndr_print_srvsvc_NetFileInfo2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetFileInfo2 *r);
+void ndr_print_srvsvc_NetFileCtr2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetFileCtr2 *r);
+void ndr_print_srvsvc_NetFileInfo3(struct ndr_print *ndr, const char *name, const struct srvsvc_NetFileInfo3 *r);
+void ndr_print_srvsvc_NetFileCtr3(struct ndr_print *ndr, const char *name, const struct srvsvc_NetFileCtr3 *r);
+void ndr_print_srvsvc_NetFileInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetFileInfo *r);
+void ndr_print_srvsvc_NetFileCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetFileCtr *r);
+void ndr_print_srvsvc_NetFileInfoCtr(struct ndr_print *ndr, const char *name, const struct srvsvc_NetFileInfoCtr *r);
+void ndr_print_srvsvc_NetSessInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfo0 *r);
+void ndr_print_srvsvc_NetSessCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessCtr0 *r);
+void ndr_print_srvsvc_NetSessInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfo1 *r);
+void ndr_print_srvsvc_NetSessCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessCtr1 *r);
+void ndr_print_srvsvc_NetSessInfo2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfo2 *r);
+void ndr_print_srvsvc_NetSessCtr2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessCtr2 *r);
+void ndr_print_srvsvc_NetSessInfo10(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfo10 *r);
+void ndr_print_srvsvc_NetSessCtr10(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessCtr10 *r);
+void ndr_print_srvsvc_NetSessInfo502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfo502 *r);
+void ndr_print_srvsvc_NetSessCtr502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessCtr502 *r);
+void ndr_print_srvsvc_NetSessCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetSessCtr *r);
+void ndr_print_srvsvc_NetSessInfoCtr(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSessInfoCtr *r);
+void ndr_print_srvsvc_ShareType(struct ndr_print *ndr, const char *name, enum srvsvc_ShareType r);
+void ndr_print_srvsvc_NetShareInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo0 *r);
+void ndr_print_srvsvc_NetShareCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr0 *r);
+void ndr_print_srvsvc_NetShareInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo1 *r);
+void ndr_print_srvsvc_NetShareCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1 *r);
+void ndr_print_srvsvc_NetShareInfo2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo2 *r);
+void ndr_print_srvsvc_NetShareCtr2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr2 *r);
+void ndr_print_srvsvc_NetShareInfo501(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo501 *r);
+void ndr_print_srvsvc_NetShareCtr501(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr501 *r);
+void ndr_print_srvsvc_NetShareInfo502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo502 *r);
+void ndr_print_srvsvc_NetShareCtr502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr502 *r);
+void ndr_print_srvsvc_NetShareInfo1004(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo1004 *r);
+void ndr_print_srvsvc_NetShareCtr1004(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1004 *r);
+void ndr_print_NetShareInfo1005Flags(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_srvsvc_NetShareInfo1005(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo1005 *r);
+void ndr_print_srvsvc_NetShareCtr1005(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1005 *r);
+void ndr_print_srvsvc_NetShareInfo1006(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo1006 *r);
+void ndr_print_srvsvc_NetShareCtr1006(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1006 *r);
+void ndr_print_srvsvc_NetShareInfo1007(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfo1007 *r);
+void ndr_print_srvsvc_NetShareCtr1007(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1007 *r);
+void ndr_print_srvsvc_NetShareCtr1501(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareCtr1501 *r);
+void ndr_print_srvsvc_NetShareInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetShareInfo *r);
+void ndr_print_srvsvc_NetShareCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetShareCtr *r);
+void ndr_print_srvsvc_NetShareInfoCtr(struct ndr_print *ndr, const char *name, const struct srvsvc_NetShareInfoCtr *r);
+enum ndr_err_code ndr_push_srvsvc_PlatformId(struct ndr_push *ndr, int ndr_flags, enum srvsvc_PlatformId r);
+enum ndr_err_code ndr_pull_srvsvc_PlatformId(struct ndr_pull *ndr, int ndr_flags, enum srvsvc_PlatformId *r);
+void ndr_print_srvsvc_PlatformId(struct ndr_print *ndr, const char *name, enum srvsvc_PlatformId r);
+void ndr_print_srvsvc_NetSrvInfo100(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo100 *r);
+void ndr_print_srvsvc_NetSrvInfo101(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo101 *r);
+void ndr_print_srvsvc_NetSrvInfo102(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo102 *r);
+void ndr_print_srvsvc_NetSrvInfo402(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo402 *r);
+void ndr_print_srvsvc_NetSrvInfo403(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo403 *r);
+void ndr_print_srvsvc_NetSrvInfo502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo502 *r);
+void ndr_print_srvsvc_NetSrvInfo503(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo503 *r);
+void ndr_print_srvsvc_NetSrvInfo599(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo599 *r);
+void ndr_print_srvsvc_NetSrvInfo1005(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1005 *r);
+void ndr_print_srvsvc_NetSrvInfo1010(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1010 *r);
+void ndr_print_srvsvc_NetSrvInfo1016(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1016 *r);
+void ndr_print_srvsvc_NetSrvInfo1017(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1017 *r);
+void ndr_print_srvsvc_NetSrvInfo1018(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1018 *r);
+void ndr_print_srvsvc_NetSrvInfo1107(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1107 *r);
+void ndr_print_srvsvc_NetSrvInfo1501(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1501 *r);
+void ndr_print_srvsvc_NetSrvInfo1502(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1502 *r);
+void ndr_print_srvsvc_NetSrvInfo1503(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1503 *r);
+void ndr_print_srvsvc_NetSrvInfo1506(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1506 *r);
+void ndr_print_srvsvc_NetSrvInfo1509(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1509 *r);
+void ndr_print_srvsvc_NetSrvInfo1510(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1510 *r);
+void ndr_print_srvsvc_NetSrvInfo1511(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1511 *r);
+void ndr_print_srvsvc_NetSrvInfo1512(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1512 *r);
+void ndr_print_srvsvc_NetSrvInfo1513(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1513 *r);
+void ndr_print_srvsvc_NetSrvInfo1514(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1514 *r);
+void ndr_print_srvsvc_NetSrvInfo1515(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1515 *r);
+void ndr_print_srvsvc_NetSrvInfo1516(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1516 *r);
+void ndr_print_srvsvc_NetSrvInfo1518(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1518 *r);
+void ndr_print_srvsvc_NetSrvInfo1520(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1520 *r);
+void ndr_print_srvsvc_NetSrvInfo1521(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1521 *r);
+void ndr_print_srvsvc_NetSrvInfo1522(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1522 *r);
+void ndr_print_srvsvc_NetSrvInfo1523(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1523 *r);
+void ndr_print_srvsvc_NetSrvInfo1524(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1524 *r);
+void ndr_print_srvsvc_NetSrvInfo1525(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1525 *r);
+void ndr_print_srvsvc_NetSrvInfo1528(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1528 *r);
+void ndr_print_srvsvc_NetSrvInfo1529(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1529 *r);
+void ndr_print_srvsvc_NetSrvInfo1530(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1530 *r);
+void ndr_print_srvsvc_NetSrvInfo1533(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1533 *r);
+void ndr_print_srvsvc_NetSrvInfo1534(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1534 *r);
+void ndr_print_srvsvc_NetSrvInfo1535(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1535 *r);
+void ndr_print_srvsvc_NetSrvInfo1536(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1536 *r);
+void ndr_print_srvsvc_NetSrvInfo1537(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1537 *r);
+void ndr_print_srvsvc_NetSrvInfo1538(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1538 *r);
+void ndr_print_srvsvc_NetSrvInfo1539(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1539 *r);
+void ndr_print_srvsvc_NetSrvInfo1540(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1540 *r);
+void ndr_print_srvsvc_NetSrvInfo1541(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1541 *r);
+void ndr_print_srvsvc_NetSrvInfo1542(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1542 *r);
+void ndr_print_srvsvc_NetSrvInfo1543(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1543 *r);
+void ndr_print_srvsvc_NetSrvInfo1544(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1544 *r);
+void ndr_print_srvsvc_NetSrvInfo1545(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1545 *r);
+void ndr_print_srvsvc_NetSrvInfo1546(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1546 *r);
+void ndr_print_srvsvc_NetSrvInfo1547(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1547 *r);
+void ndr_print_srvsvc_NetSrvInfo1548(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1548 *r);
+void ndr_print_srvsvc_NetSrvInfo1549(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1549 *r);
+void ndr_print_srvsvc_NetSrvInfo1550(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1550 *r);
+void ndr_print_srvsvc_NetSrvInfo1552(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1552 *r);
+void ndr_print_srvsvc_NetSrvInfo1553(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1553 *r);
+void ndr_print_srvsvc_NetSrvInfo1554(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1554 *r);
+void ndr_print_srvsvc_NetSrvInfo1555(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1555 *r);
+void ndr_print_srvsvc_NetSrvInfo1556(struct ndr_print *ndr, const char *name, const struct srvsvc_NetSrvInfo1556 *r);
+void ndr_print_srvsvc_NetSrvInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetSrvInfo *r);
+void ndr_print_srvsvc_NetDiskInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetDiskInfo0 *r);
+void ndr_print_srvsvc_NetDiskInfo(struct ndr_print *ndr, const char *name, const struct srvsvc_NetDiskInfo *r);
+void ndr_print_srvsvc_Statistics(struct ndr_print *ndr, const char *name, const struct srvsvc_Statistics *r);
+void ndr_print_srvsvc_NetTransportInfo0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportInfo0 *r);
+void ndr_print_srvsvc_NetTransportCtr0(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportCtr0 *r);
+void ndr_print_srvsvc_NetTransportInfo1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportInfo1 *r);
+void ndr_print_srvsvc_NetTransportCtr1(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportCtr1 *r);
+void ndr_print_srvsvc_NetTransportInfo2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportInfo2 *r);
+void ndr_print_srvsvc_NetTransportCtr2(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportCtr2 *r);
+void ndr_print_srvsvc_NetTransportInfo3(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportInfo3 *r);
+void ndr_print_srvsvc_NetTransportCtr3(struct ndr_print *ndr, const char *name, const struct srvsvc_NetTransportCtr3 *r);
+void ndr_print_srvsvc_NetTransportCtr(struct ndr_print *ndr, const char *name, const union srvsvc_NetTransportCtr *r);
+void ndr_print_srvsvc_NetRemoteTODInfo(struct ndr_print *ndr, const char *name, const struct srvsvc_NetRemoteTODInfo *r);
+void ndr_print_srvsvc_NetTransportInfo(struct ndr_print *ndr, const char *name, const union srvsvc_NetTransportInfo *r);
+void ndr_print_srvsvc_NetCharDevEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevEnum *r);
+void ndr_print_srvsvc_NetCharDevGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevGetInfo *r);
+void ndr_print_srvsvc_NetCharDevControl(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevControl *r);
+void ndr_print_srvsvc_NetCharDevQEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevQEnum *r);
+void ndr_print_srvsvc_NetCharDevQGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevQGetInfo *r);
+void ndr_print_srvsvc_NetCharDevQSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevQSetInfo *r);
+void ndr_print_srvsvc_NetCharDevQPurge(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevQPurge *r);
+void ndr_print_srvsvc_NetCharDevQPurgeSelf(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetCharDevQPurgeSelf *r);
+void ndr_print_srvsvc_NetConnEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetConnEnum *r);
+void ndr_print_srvsvc_NetFileEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetFileEnum *r);
+void ndr_print_srvsvc_NetFileGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetFileGetInfo *r);
+void ndr_print_srvsvc_NetFileClose(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetFileClose *r);
+void ndr_print_srvsvc_NetSessEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSessEnum *r);
+void ndr_print_srvsvc_NetSessDel(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSessDel *r);
+void ndr_print_srvsvc_NetShareAdd(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareAdd *r);
+void ndr_print_srvsvc_NetShareEnumAll(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareEnumAll *r);
+void ndr_print_srvsvc_NetShareGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareGetInfo *r);
+void ndr_print_srvsvc_NetShareSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareSetInfo *r);
+void ndr_print_srvsvc_NetShareDel(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareDel *r);
+void ndr_print_srvsvc_NetShareDelSticky(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareDelSticky *r);
+void ndr_print_srvsvc_NetShareCheck(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareCheck *r);
+void ndr_print_srvsvc_NetSrvGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSrvGetInfo *r);
+void ndr_print_srvsvc_NetSrvSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSrvSetInfo *r);
+void ndr_print_srvsvc_NetDiskEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetDiskEnum *r);
+void ndr_print_srvsvc_NetServerStatisticsGet(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetServerStatisticsGet *r);
+void ndr_print_srvsvc_NetTransportAdd(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetTransportAdd *r);
+void ndr_print_srvsvc_NetTransportEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetTransportEnum *r);
+void ndr_print_srvsvc_NetTransportDel(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetTransportDel *r);
+void ndr_print_srvsvc_NetRemoteTOD(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetRemoteTOD *r);
+void ndr_print_srvsvc_NetSetServiceBits(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSetServiceBits *r);
+void ndr_print_srvsvc_NetPathType(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetPathType *r);
+void ndr_print_srvsvc_NetPathCanonicalize(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetPathCanonicalize *r);
+void ndr_print_srvsvc_NetPathCompare(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetPathCompare *r);
+void ndr_print_srvsvc_NetNameValidate(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetNameValidate *r);
+void ndr_print_srvsvc_NETRPRNAMECANONICALIZE(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRPRNAMECANONICALIZE *r);
+void ndr_print_srvsvc_NetPRNameCompare(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetPRNameCompare *r);
+void ndr_print_srvsvc_NetShareEnum(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareEnum *r);
+void ndr_print_srvsvc_NetShareDelStart(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareDelStart *r);
+void ndr_print_srvsvc_NetShareDelCommit(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetShareDelCommit *r);
+void ndr_print_srvsvc_NetGetFileSecurity(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetGetFileSecurity *r);
+void ndr_print_srvsvc_NetSetFileSecurity(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetSetFileSecurity *r);
+void ndr_print_srvsvc_NetServerTransportAddEx(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetServerTransportAddEx *r);
+void ndr_print_srvsvc_NetServerSetServiceBitsEx(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NetServerSetServiceBitsEx *r);
+void ndr_print_srvsvc_NETRDFSGETVERSION(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSGETVERSION *r);
+void ndr_print_srvsvc_NETRDFSCREATELOCALPARTITION(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSCREATELOCALPARTITION *r);
+void ndr_print_srvsvc_NETRDFSDELETELOCALPARTITION(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSDELETELOCALPARTITION *r);
+void ndr_print_srvsvc_NETRDFSSETLOCALVOLUMESTATE(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSSETLOCALVOLUMESTATE *r);
+void ndr_print_srvsvc_NETRDFSSETSERVERINFO(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSSETSERVERINFO *r);
+void ndr_print_srvsvc_NETRDFSCREATEEXITPOINT(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSCREATEEXITPOINT *r);
+void ndr_print_srvsvc_NETRDFSDELETEEXITPOINT(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSDELETEEXITPOINT *r);
+void ndr_print_srvsvc_NETRDFSMODIFYPREFIX(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSMODIFYPREFIX *r);
+void ndr_print_srvsvc_NETRDFSFIXLOCALVOLUME(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSFIXLOCALVOLUME *r);
+void ndr_print_srvsvc_NETRDFSMANAGERREPORTSITEINFO(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRDFSMANAGERREPORTSITEINFO *r);
+void ndr_print_srvsvc_NETRSERVERTRANSPORTDELEX(struct ndr_print *ndr, const char *name, int flags, const struct srvsvc_NETRSERVERTRANSPORTDELEX *r);
+#endif /* _HEADER_NDR_srvsvc */
diff --git a/source3/librpc/gen_ndr/ndr_svcctl.c b/source3/librpc/gen_ndr/ndr_svcctl.c
new file mode 100644
index 0000000000..eb3929696e
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_svcctl.c
@@ -0,0 +1,6079 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_svcctl.h"
+
+static enum ndr_err_code ndr_push_SERVICE_LOCK_STATUS(struct ndr_push *ndr, int ndr_flags, const struct SERVICE_LOCK_STATUS *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->is_locked));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->lock_owner));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->lock_duration));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->lock_owner) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->lock_owner, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->lock_owner, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->lock_owner, ndr_charset_length(r->lock_owner, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_SERVICE_LOCK_STATUS(struct ndr_pull *ndr, int ndr_flags, struct SERVICE_LOCK_STATUS *r)
+{
+ uint32_t _ptr_lock_owner;
+ TALLOC_CTX *_mem_save_lock_owner_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->is_locked));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_lock_owner));
+ if (_ptr_lock_owner) {
+ NDR_PULL_ALLOC(ndr, r->lock_owner);
+ } else {
+ r->lock_owner = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->lock_duration));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->lock_owner) {
+ _mem_save_lock_owner_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->lock_owner, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->lock_owner));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->lock_owner));
+ if (ndr_get_array_length(ndr, &r->lock_owner) > ndr_get_array_size(ndr, &r->lock_owner)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->lock_owner), ndr_get_array_length(ndr, &r->lock_owner));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->lock_owner), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->lock_owner, ndr_get_array_length(ndr, &r->lock_owner), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_lock_owner_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_SERVICE_LOCK_STATUS(struct ndr_print *ndr, const char *name, const struct SERVICE_LOCK_STATUS *r)
+{
+ ndr_print_struct(ndr, name, "SERVICE_LOCK_STATUS");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "is_locked", r->is_locked);
+ ndr_print_ptr(ndr, "lock_owner", r->lock_owner);
+ ndr->depth++;
+ if (r->lock_owner) {
+ ndr_print_string(ndr, "lock_owner", r->lock_owner);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "lock_duration", r->lock_duration);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_SERVICE_STATUS(struct ndr_push *ndr, int ndr_flags, const struct SERVICE_STATUS *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->state));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->controls_accepted));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->win32_exit_code));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->service_exit_code));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->check_point));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->wait_hint));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_SERVICE_STATUS(struct ndr_pull *ndr, int ndr_flags, struct SERVICE_STATUS *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->state));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->controls_accepted));
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->win32_exit_code));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->service_exit_code));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->check_point));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->wait_hint));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_SERVICE_STATUS(struct ndr_print *ndr, const char *name, const struct SERVICE_STATUS *r)
+{
+ ndr_print_struct(ndr, name, "SERVICE_STATUS");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "type", r->type);
+ ndr_print_uint32(ndr, "state", r->state);
+ ndr_print_uint32(ndr, "controls_accepted", r->controls_accepted);
+ ndr_print_WERROR(ndr, "win32_exit_code", r->win32_exit_code);
+ ndr_print_uint32(ndr, "service_exit_code", r->service_exit_code);
+ ndr_print_uint32(ndr, "check_point", r->check_point);
+ ndr_print_uint32(ndr, "wait_hint", r->wait_hint);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_ENUM_SERVICE_STATUS(struct ndr_push *ndr, int ndr_flags, const struct ENUM_SERVICE_STATUS *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->service_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->display_name));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_push_SERVICE_STATUS(ndr, NDR_SCALARS, &r->status));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ if (r->service_name) {
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, r->service_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->service_name));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ if (r->display_name) {
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, r->display_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->display_name));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_ENUM_SERVICE_STATUS(struct ndr_pull *ndr, int ndr_flags, struct ENUM_SERVICE_STATUS *r)
+{
+ uint32_t _ptr_service_name;
+ TALLOC_CTX *_mem_save_service_name_0;
+ uint32_t _ptr_display_name;
+ TALLOC_CTX *_mem_save_display_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_service_name));
+ if (_ptr_service_name) {
+ NDR_PULL_ALLOC(ndr, r->service_name);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->service_name, _ptr_service_name));
+ } else {
+ r->service_name = NULL;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_display_name));
+ if (_ptr_display_name) {
+ NDR_PULL_ALLOC(ndr, r->display_name);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->display_name, _ptr_display_name));
+ } else {
+ r->display_name = NULL;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_pull_SERVICE_STATUS(ndr, NDR_SCALARS, &r->status));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ if (r->service_name) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->service_name));
+ _mem_save_service_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->service_name, 0);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->service_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_name_0, 0);
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ if (r->display_name) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->display_name));
+ _mem_save_display_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->display_name, 0);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->display_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_display_name_0, 0);
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_ENUM_SERVICE_STATUS(struct ndr_print *ndr, const char *name, const struct ENUM_SERVICE_STATUS *r)
+{
+ ndr_print_struct(ndr, name, "ENUM_SERVICE_STATUS");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "service_name", r->service_name);
+ ndr->depth++;
+ if (r->service_name) {
+ ndr_print_string(ndr, "service_name", r->service_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "display_name", r->display_name);
+ ndr->depth++;
+ if (r->display_name) {
+ ndr_print_string(ndr, "display_name", r->display_name);
+ }
+ ndr->depth--;
+ ndr_print_SERVICE_STATUS(ndr, "status", &r->status);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_svcctl_ServerType(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_svcctl_ServerType(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_ServerType(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_WORKSTATION", SV_TYPE_WORKSTATION, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_SERVER", SV_TYPE_SERVER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_SQLSERVER", SV_TYPE_SQLSERVER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_DOMAIN_CTRL", SV_TYPE_DOMAIN_CTRL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_DOMAIN_BAKCTRL", SV_TYPE_DOMAIN_BAKCTRL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_TIME_SOURCE", SV_TYPE_TIME_SOURCE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_AFP", SV_TYPE_AFP, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_NOVELL", SV_TYPE_NOVELL, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_DOMAIN_MEMBER", SV_TYPE_DOMAIN_MEMBER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_PRINTQ_SERVER", SV_TYPE_PRINTQ_SERVER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_DIALIN_SERVER", SV_TYPE_DIALIN_SERVER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_SERVER_UNIX", SV_TYPE_SERVER_UNIX, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_NT", SV_TYPE_NT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_WFW", SV_TYPE_WFW, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_SERVER_MFPN", SV_TYPE_SERVER_MFPN, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_SERVER_NT", SV_TYPE_SERVER_NT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_POTENTIAL_BROWSER", SV_TYPE_POTENTIAL_BROWSER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_BACKUP_BROWSER", SV_TYPE_BACKUP_BROWSER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_MASTER_BROWSER", SV_TYPE_MASTER_BROWSER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_DOMAIN_MASTER", SV_TYPE_DOMAIN_MASTER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_SERVER_OSF", SV_TYPE_SERVER_OSF, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_SERVER_VMS", SV_TYPE_SERVER_VMS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_WIN95_PLUS", SV_TYPE_WIN95_PLUS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_DFS_SERVER", SV_TYPE_DFS_SERVER, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_ALTERNATE_XPORT", SV_TYPE_ALTERNATE_XPORT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_LOCAL_LIST_ONLY", SV_TYPE_LOCAL_LIST_ONLY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SV_TYPE_DOMAIN_ENUM", SV_TYPE_DOMAIN_ENUM, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_MgrAccessMask(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_MgrAccessMask(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_MgrAccessMask(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SC_RIGHT_MGR_CONNECT", SC_RIGHT_MGR_CONNECT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SC_RIGHT_MGR_CREATE_SERVICE", SC_RIGHT_MGR_CREATE_SERVICE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SC_RIGHT_MGR_ENUMERATE_SERVICE", SC_RIGHT_MGR_ENUMERATE_SERVICE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SC_RIGHT_MGR_LOCK", SC_RIGHT_MGR_LOCK, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SC_RIGHT_MGR_QUERY_LOCK_STATUS", SC_RIGHT_MGR_QUERY_LOCK_STATUS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SC_RIGHT_MGR_MODIFY_BOOT_CONFIG", SC_RIGHT_MGR_MODIFY_BOOT_CONFIG, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_ServiceAccessMask(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_ServiceAccessMask(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_ServiceAccessMask(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SC_RIGHT_SVC_QUERY_CONFIG", SC_RIGHT_SVC_QUERY_CONFIG, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SC_RIGHT_SVC_CHANGE_CONFIG", SC_RIGHT_SVC_CHANGE_CONFIG, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SC_RIGHT_SVC_QUERY_STATUS", SC_RIGHT_SVC_QUERY_STATUS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SC_RIGHT_SVC_ENUMERATE_DEPENDENTS", SC_RIGHT_SVC_ENUMERATE_DEPENDENTS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SC_RIGHT_SVC_START", SC_RIGHT_SVC_START, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SC_RIGHT_SVC_STOP", SC_RIGHT_SVC_STOP, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SC_RIGHT_SVC_PAUSE_CONTINUE", SC_RIGHT_SVC_PAUSE_CONTINUE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SC_RIGHT_SVC_INTERROGATE", SC_RIGHT_SVC_INTERROGATE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "SC_RIGHT_SVC_USER_DEFINED_CONTROL", SC_RIGHT_SVC_USER_DEFINED_CONTROL, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_CloseServiceHandle(struct ndr_push *ndr, int flags, const struct svcctl_CloseServiceHandle *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_CloseServiceHandle(struct ndr_pull *ndr, int flags, struct svcctl_CloseServiceHandle *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ *r->out.handle = *r->in.handle;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_CloseServiceHandle(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_CloseServiceHandle *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_CloseServiceHandle");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_CloseServiceHandle");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_CloseServiceHandle");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_ControlService(struct ndr_push *ndr, int flags, const struct svcctl_ControlService *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.control));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.service_status == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_SERVICE_STATUS(ndr, NDR_SCALARS, r->out.service_status));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_ControlService(struct ndr_pull *ndr, int flags, struct svcctl_ControlService *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_service_status_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.control));
+ NDR_PULL_ALLOC(ndr, r->out.service_status);
+ ZERO_STRUCTP(r->out.service_status);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.service_status);
+ }
+ _mem_save_service_status_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.service_status, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_SERVICE_STATUS(ndr, NDR_SCALARS, r->out.service_status));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_status_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_ControlService(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_ControlService *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_ControlService");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_ControlService");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "control", r->in.control);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_ControlService");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "service_status", r->out.service_status);
+ ndr->depth++;
+ ndr_print_SERVICE_STATUS(ndr, "service_status", r->out.service_status);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_DeleteService(struct ndr_push *ndr, int flags, const struct svcctl_DeleteService *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_DeleteService(struct ndr_pull *ndr, int flags, struct svcctl_DeleteService *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_DeleteService(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_DeleteService *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_DeleteService");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_DeleteService");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_DeleteService");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_LockServiceDatabase(struct ndr_push *ndr, int flags, const struct svcctl_LockServiceDatabase *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.lock == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.lock));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_LockServiceDatabase(struct ndr_pull *ndr, int flags, struct svcctl_LockServiceDatabase *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_lock_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.lock);
+ ZERO_STRUCTP(r->out.lock);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.lock);
+ }
+ _mem_save_lock_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.lock, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.lock));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_lock_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_LockServiceDatabase(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_LockServiceDatabase *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_LockServiceDatabase");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_LockServiceDatabase");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_LockServiceDatabase");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "lock", r->out.lock);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "lock", r->out.lock);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_QueryServiceObjectSecurity(struct ndr_push *ndr, int flags, const struct svcctl_QueryServiceObjectSecurity *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.security_flags));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buffer_size));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.buffer == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buffer_size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.buffer, r->in.buffer_size));
+ if (r->out.needed == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.needed));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_QueryServiceObjectSecurity(struct ndr_pull *ndr, int flags, struct svcctl_QueryServiceObjectSecurity *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_needed_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.security_flags));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buffer_size));
+ if (r->in.buffer_size < 0 || r->in.buffer_size > 0x40000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_PULL_ALLOC_N(ndr, r->out.buffer, r->in.buffer_size);
+ memset(r->out.buffer, 0, (r->in.buffer_size) * sizeof(*r->out.buffer));
+ NDR_PULL_ALLOC(ndr, r->out.needed);
+ ZERO_STRUCTP(r->out.needed);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->out.buffer));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC_N(ndr, r->out.buffer, ndr_get_array_size(ndr, &r->out.buffer));
+ }
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.buffer, ndr_get_array_size(ndr, &r->out.buffer)));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.needed);
+ }
+ _mem_save_needed_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.needed, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.needed));
+ if (*r->out.needed < 0 || *r->out.needed > 0x40000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_needed_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ if (r->out.buffer) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->out.buffer, r->in.buffer_size));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_QueryServiceObjectSecurity(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceObjectSecurity *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_QueryServiceObjectSecurity");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_QueryServiceObjectSecurity");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "security_flags", r->in.security_flags);
+ ndr_print_uint32(ndr, "buffer_size", r->in.buffer_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_QueryServiceObjectSecurity");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "buffer", r->out.buffer, r->in.buffer_size);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "needed", r->out.needed);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "needed", *r->out.needed);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_SetServiceObjectSecurity(struct ndr_push *ndr, int flags, const struct svcctl_SetServiceObjectSecurity *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.security_flags));
+ if (r->in.buffer == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buffer_size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->in.buffer, r->in.buffer_size));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buffer_size));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_SetServiceObjectSecurity(struct ndr_pull *ndr, int flags, struct svcctl_SetServiceObjectSecurity *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.security_flags));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.buffer));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC_N(ndr, r->in.buffer, ndr_get_array_size(ndr, &r->in.buffer));
+ }
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->in.buffer, ndr_get_array_size(ndr, &r->in.buffer)));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buffer_size));
+ if (r->in.buffer) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.buffer, r->in.buffer_size));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_SetServiceObjectSecurity(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_SetServiceObjectSecurity *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_SetServiceObjectSecurity");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_SetServiceObjectSecurity");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "security_flags", r->in.security_flags);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "buffer", r->in.buffer, r->in.buffer_size);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "buffer_size", r->in.buffer_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_SetServiceObjectSecurity");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_QueryServiceStatus(struct ndr_push *ndr, int flags, const struct svcctl_QueryServiceStatus *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.service_status == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_SERVICE_STATUS(ndr, NDR_SCALARS, r->out.service_status));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_QueryServiceStatus(struct ndr_pull *ndr, int flags, struct svcctl_QueryServiceStatus *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_service_status_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.service_status);
+ ZERO_STRUCTP(r->out.service_status);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.service_status);
+ }
+ _mem_save_service_status_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.service_status, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_SERVICE_STATUS(ndr, NDR_SCALARS, r->out.service_status));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_status_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_QueryServiceStatus(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceStatus *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_QueryServiceStatus");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_QueryServiceStatus");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_QueryServiceStatus");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "service_status", r->out.service_status);
+ ndr->depth++;
+ ndr_print_SERVICE_STATUS(ndr, "service_status", r->out.service_status);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_SetServiceStatus(struct ndr_push *ndr, int flags, const struct svcctl_SetServiceStatus *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_SetServiceStatus(struct ndr_pull *ndr, int flags, struct svcctl_SetServiceStatus *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_SetServiceStatus(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_SetServiceStatus *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_SetServiceStatus");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_SetServiceStatus");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_SetServiceStatus");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_UnlockServiceDatabase(struct ndr_push *ndr, int flags, const struct svcctl_UnlockServiceDatabase *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.lock == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.lock));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.lock == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.lock));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_UnlockServiceDatabase(struct ndr_pull *ndr, int flags, struct svcctl_UnlockServiceDatabase *r)
+{
+ TALLOC_CTX *_mem_save_lock_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.lock);
+ }
+ _mem_save_lock_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.lock, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.lock));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_lock_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.lock);
+ *r->out.lock = *r->in.lock;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.lock);
+ }
+ _mem_save_lock_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.lock, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.lock));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_lock_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_UnlockServiceDatabase(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_UnlockServiceDatabase *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_UnlockServiceDatabase");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_UnlockServiceDatabase");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "lock", r->in.lock);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "lock", r->in.lock);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_UnlockServiceDatabase");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "lock", r->out.lock);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "lock", r->out.lock);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_NotifyBootConfigStatus(struct ndr_push *ndr, int flags, const struct svcctl_NotifyBootConfigStatus *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_NotifyBootConfigStatus(struct ndr_pull *ndr, int flags, struct svcctl_NotifyBootConfigStatus *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_NotifyBootConfigStatus(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_NotifyBootConfigStatus *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_NotifyBootConfigStatus");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_NotifyBootConfigStatus");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_NotifyBootConfigStatus");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_SCSetServiceBitsW(struct ndr_push *ndr, int flags, const struct svcctl_SCSetServiceBitsW *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.bits));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.bitson));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.immediate));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_SCSetServiceBitsW(struct ndr_pull *ndr, int flags, struct svcctl_SCSetServiceBitsW *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.bits));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.bitson));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.immediate));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_SCSetServiceBitsW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_SCSetServiceBitsW *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_SCSetServiceBitsW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_SCSetServiceBitsW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "bits", r->in.bits);
+ ndr_print_uint32(ndr, "bitson", r->in.bitson);
+ ndr_print_uint32(ndr, "immediate", r->in.immediate);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_SCSetServiceBitsW");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_ChangeServiceConfigW(struct ndr_push *ndr, int flags, const struct svcctl_ChangeServiceConfigW *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.start));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.error));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.binary_path));
+ if (r->in.binary_path) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.binary_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.binary_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.binary_path, ndr_charset_length(r->in.binary_path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.load_order_group));
+ if (r->in.load_order_group) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.load_order_group, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.load_order_group, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.load_order_group, ndr_charset_length(r->in.load_order_group, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.dependencies));
+ if (r->in.dependencies) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dependencies, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dependencies, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.dependencies, ndr_charset_length(r->in.dependencies, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.service_start_name));
+ if (r->in.service_start_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service_start_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service_start_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.service_start_name, ndr_charset_length(r->in.service_start_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.password));
+ if (r->in.password) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.password, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.password, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.password, ndr_charset_length(r->in.password, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.display_name));
+ if (r->in.display_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.display_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.display_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.display_name, ndr_charset_length(r->in.display_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.tag_id == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.tag_id));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_ChangeServiceConfigW(struct ndr_pull *ndr, int flags, struct svcctl_ChangeServiceConfigW *r)
+{
+ uint32_t _ptr_binary_path;
+ uint32_t _ptr_load_order_group;
+ uint32_t _ptr_dependencies;
+ uint32_t _ptr_service_start_name;
+ uint32_t _ptr_password;
+ uint32_t _ptr_display_name;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_binary_path_0;
+ TALLOC_CTX *_mem_save_load_order_group_0;
+ TALLOC_CTX *_mem_save_tag_id_0;
+ TALLOC_CTX *_mem_save_dependencies_0;
+ TALLOC_CTX *_mem_save_service_start_name_0;
+ TALLOC_CTX *_mem_save_password_0;
+ TALLOC_CTX *_mem_save_display_name_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.start));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.error));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_binary_path));
+ if (_ptr_binary_path) {
+ NDR_PULL_ALLOC(ndr, r->in.binary_path);
+ } else {
+ r->in.binary_path = NULL;
+ }
+ if (r->in.binary_path) {
+ _mem_save_binary_path_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.binary_path, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.binary_path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.binary_path));
+ if (ndr_get_array_length(ndr, &r->in.binary_path) > ndr_get_array_size(ndr, &r->in.binary_path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.binary_path), ndr_get_array_length(ndr, &r->in.binary_path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.binary_path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.binary_path, ndr_get_array_length(ndr, &r->in.binary_path), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_binary_path_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_load_order_group));
+ if (_ptr_load_order_group) {
+ NDR_PULL_ALLOC(ndr, r->in.load_order_group);
+ } else {
+ r->in.load_order_group = NULL;
+ }
+ if (r->in.load_order_group) {
+ _mem_save_load_order_group_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.load_order_group, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.load_order_group));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.load_order_group));
+ if (ndr_get_array_length(ndr, &r->in.load_order_group) > ndr_get_array_size(ndr, &r->in.load_order_group)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.load_order_group), ndr_get_array_length(ndr, &r->in.load_order_group));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.load_order_group), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.load_order_group, ndr_get_array_length(ndr, &r->in.load_order_group), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_load_order_group_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dependencies));
+ if (_ptr_dependencies) {
+ NDR_PULL_ALLOC(ndr, r->in.dependencies);
+ } else {
+ r->in.dependencies = NULL;
+ }
+ if (r->in.dependencies) {
+ _mem_save_dependencies_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.dependencies, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.dependencies));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.dependencies));
+ if (ndr_get_array_length(ndr, &r->in.dependencies) > ndr_get_array_size(ndr, &r->in.dependencies)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.dependencies), ndr_get_array_length(ndr, &r->in.dependencies));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.dependencies), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.dependencies, ndr_get_array_length(ndr, &r->in.dependencies), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dependencies_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_service_start_name));
+ if (_ptr_service_start_name) {
+ NDR_PULL_ALLOC(ndr, r->in.service_start_name);
+ } else {
+ r->in.service_start_name = NULL;
+ }
+ if (r->in.service_start_name) {
+ _mem_save_service_start_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.service_start_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.service_start_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.service_start_name));
+ if (ndr_get_array_length(ndr, &r->in.service_start_name) > ndr_get_array_size(ndr, &r->in.service_start_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.service_start_name), ndr_get_array_length(ndr, &r->in.service_start_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.service_start_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.service_start_name, ndr_get_array_length(ndr, &r->in.service_start_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_start_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password));
+ if (_ptr_password) {
+ NDR_PULL_ALLOC(ndr, r->in.password);
+ } else {
+ r->in.password = NULL;
+ }
+ if (r->in.password) {
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.password, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.password));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.password));
+ if (ndr_get_array_length(ndr, &r->in.password) > ndr_get_array_size(ndr, &r->in.password)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.password), ndr_get_array_length(ndr, &r->in.password));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.password), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.password, ndr_get_array_length(ndr, &r->in.password), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_display_name));
+ if (_ptr_display_name) {
+ NDR_PULL_ALLOC(ndr, r->in.display_name);
+ } else {
+ r->in.display_name = NULL;
+ }
+ if (r->in.display_name) {
+ _mem_save_display_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.display_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.display_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.display_name));
+ if (ndr_get_array_length(ndr, &r->in.display_name) > ndr_get_array_size(ndr, &r->in.display_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.display_name), ndr_get_array_length(ndr, &r->in.display_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.display_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.display_name, ndr_get_array_length(ndr, &r->in.display_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_display_name_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.tag_id);
+ ZERO_STRUCTP(r->out.tag_id);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.tag_id);
+ }
+ _mem_save_tag_id_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.tag_id, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.tag_id));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_tag_id_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_ChangeServiceConfigW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_ChangeServiceConfigW *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_ChangeServiceConfigW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_ChangeServiceConfigW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "type", r->in.type);
+ ndr_print_uint32(ndr, "start", r->in.start);
+ ndr_print_uint32(ndr, "error", r->in.error);
+ ndr_print_ptr(ndr, "binary_path", r->in.binary_path);
+ ndr->depth++;
+ if (r->in.binary_path) {
+ ndr_print_string(ndr, "binary_path", r->in.binary_path);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "load_order_group", r->in.load_order_group);
+ ndr->depth++;
+ if (r->in.load_order_group) {
+ ndr_print_string(ndr, "load_order_group", r->in.load_order_group);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "dependencies", r->in.dependencies);
+ ndr->depth++;
+ if (r->in.dependencies) {
+ ndr_print_string(ndr, "dependencies", r->in.dependencies);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "service_start_name", r->in.service_start_name);
+ ndr->depth++;
+ if (r->in.service_start_name) {
+ ndr_print_string(ndr, "service_start_name", r->in.service_start_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->in.password);
+ ndr->depth++;
+ if (r->in.password) {
+ ndr_print_string(ndr, "password", r->in.password);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "display_name", r->in.display_name);
+ ndr->depth++;
+ if (r->in.display_name) {
+ ndr_print_string(ndr, "display_name", r->in.display_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_ChangeServiceConfigW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "tag_id", r->out.tag_id);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "tag_id", *r->out.tag_id);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_CreateServiceW(struct ndr_push *ndr, int flags, const struct svcctl_CreateServiceW *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.scmanager_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.scmanager_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.ServiceName, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.ServiceName, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.ServiceName, ndr_charset_length(r->in.ServiceName, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.DisplayName));
+ if (r->in.DisplayName) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.DisplayName, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.DisplayName, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.DisplayName, ndr_charset_length(r->in.DisplayName, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.desired_access));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.start_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.error_control));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.binary_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.binary_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.binary_path, ndr_charset_length(r->in.binary_path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.LoadOrderGroupKey));
+ if (r->in.LoadOrderGroupKey) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.LoadOrderGroupKey, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.LoadOrderGroupKey, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.LoadOrderGroupKey, ndr_charset_length(r->in.LoadOrderGroupKey, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.TagId));
+ if (r->in.TagId) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.TagId));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.dependencies));
+ if (r->in.dependencies) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.dependencies_size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->in.dependencies, r->in.dependencies_size));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.dependencies_size));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.service_start_name));
+ if (r->in.service_start_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service_start_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service_start_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.service_start_name, ndr_charset_length(r->in.service_start_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.password));
+ if (r->in.password) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.password_size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->in.password, r->in.password_size));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.password_size));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.TagId));
+ if (r->out.TagId) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.TagId));
+ }
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_CreateServiceW(struct ndr_pull *ndr, int flags, struct svcctl_CreateServiceW *r)
+{
+ uint32_t _ptr_DisplayName;
+ uint32_t _ptr_LoadOrderGroupKey;
+ uint32_t _ptr_TagId;
+ uint32_t _ptr_dependencies;
+ uint32_t _ptr_service_start_name;
+ uint32_t _ptr_password;
+ TALLOC_CTX *_mem_save_scmanager_handle_0;
+ TALLOC_CTX *_mem_save_DisplayName_0;
+ TALLOC_CTX *_mem_save_LoadOrderGroupKey_0;
+ TALLOC_CTX *_mem_save_TagId_0;
+ TALLOC_CTX *_mem_save_dependencies_0;
+ TALLOC_CTX *_mem_save_service_start_name_0;
+ TALLOC_CTX *_mem_save_password_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.scmanager_handle);
+ }
+ _mem_save_scmanager_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.scmanager_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.scmanager_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_scmanager_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.ServiceName));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.ServiceName));
+ if (ndr_get_array_length(ndr, &r->in.ServiceName) > ndr_get_array_size(ndr, &r->in.ServiceName)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.ServiceName), ndr_get_array_length(ndr, &r->in.ServiceName));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.ServiceName), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.ServiceName, ndr_get_array_length(ndr, &r->in.ServiceName), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_DisplayName));
+ if (_ptr_DisplayName) {
+ NDR_PULL_ALLOC(ndr, r->in.DisplayName);
+ } else {
+ r->in.DisplayName = NULL;
+ }
+ if (r->in.DisplayName) {
+ _mem_save_DisplayName_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.DisplayName, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.DisplayName));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.DisplayName));
+ if (ndr_get_array_length(ndr, &r->in.DisplayName) > ndr_get_array_size(ndr, &r->in.DisplayName)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.DisplayName), ndr_get_array_length(ndr, &r->in.DisplayName));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.DisplayName), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.DisplayName, ndr_get_array_length(ndr, &r->in.DisplayName), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_DisplayName_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.desired_access));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.start_type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.error_control));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.binary_path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.binary_path));
+ if (ndr_get_array_length(ndr, &r->in.binary_path) > ndr_get_array_size(ndr, &r->in.binary_path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.binary_path), ndr_get_array_length(ndr, &r->in.binary_path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.binary_path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.binary_path, ndr_get_array_length(ndr, &r->in.binary_path), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_LoadOrderGroupKey));
+ if (_ptr_LoadOrderGroupKey) {
+ NDR_PULL_ALLOC(ndr, r->in.LoadOrderGroupKey);
+ } else {
+ r->in.LoadOrderGroupKey = NULL;
+ }
+ if (r->in.LoadOrderGroupKey) {
+ _mem_save_LoadOrderGroupKey_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.LoadOrderGroupKey, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.LoadOrderGroupKey));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.LoadOrderGroupKey));
+ if (ndr_get_array_length(ndr, &r->in.LoadOrderGroupKey) > ndr_get_array_size(ndr, &r->in.LoadOrderGroupKey)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.LoadOrderGroupKey), ndr_get_array_length(ndr, &r->in.LoadOrderGroupKey));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.LoadOrderGroupKey), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.LoadOrderGroupKey, ndr_get_array_length(ndr, &r->in.LoadOrderGroupKey), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_LoadOrderGroupKey_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_TagId));
+ if (_ptr_TagId) {
+ NDR_PULL_ALLOC(ndr, r->in.TagId);
+ } else {
+ r->in.TagId = NULL;
+ }
+ if (r->in.TagId) {
+ _mem_save_TagId_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.TagId, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.TagId));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_TagId_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dependencies));
+ if (_ptr_dependencies) {
+ NDR_PULL_ALLOC(ndr, r->in.dependencies);
+ } else {
+ r->in.dependencies = NULL;
+ }
+ if (r->in.dependencies) {
+ _mem_save_dependencies_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.dependencies, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.dependencies));
+ NDR_PULL_ALLOC_N(ndr, r->in.dependencies, ndr_get_array_size(ndr, &r->in.dependencies));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->in.dependencies, ndr_get_array_size(ndr, &r->in.dependencies)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dependencies_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.dependencies_size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_service_start_name));
+ if (_ptr_service_start_name) {
+ NDR_PULL_ALLOC(ndr, r->in.service_start_name);
+ } else {
+ r->in.service_start_name = NULL;
+ }
+ if (r->in.service_start_name) {
+ _mem_save_service_start_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.service_start_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.service_start_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.service_start_name));
+ if (ndr_get_array_length(ndr, &r->in.service_start_name) > ndr_get_array_size(ndr, &r->in.service_start_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.service_start_name), ndr_get_array_length(ndr, &r->in.service_start_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.service_start_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.service_start_name, ndr_get_array_length(ndr, &r->in.service_start_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_start_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password));
+ if (_ptr_password) {
+ NDR_PULL_ALLOC(ndr, r->in.password);
+ } else {
+ r->in.password = NULL;
+ }
+ if (r->in.password) {
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.password, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.password));
+ NDR_PULL_ALLOC_N(ndr, r->in.password, ndr_get_array_size(ndr, &r->in.password));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->in.password, ndr_get_array_size(ndr, &r->in.password)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.password_size));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ if (r->in.dependencies) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.dependencies, r->in.dependencies_size));
+ }
+ if (r->in.password) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.password, r->in.password_size));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_TagId));
+ if (_ptr_TagId) {
+ NDR_PULL_ALLOC(ndr, r->out.TagId);
+ } else {
+ r->out.TagId = NULL;
+ }
+ if (r->out.TagId) {
+ _mem_save_TagId_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.TagId, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.TagId));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_TagId_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_CreateServiceW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_CreateServiceW *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_CreateServiceW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_CreateServiceW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "scmanager_handle", r->in.scmanager_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "scmanager_handle", r->in.scmanager_handle);
+ ndr->depth--;
+ ndr_print_string(ndr, "ServiceName", r->in.ServiceName);
+ ndr_print_ptr(ndr, "DisplayName", r->in.DisplayName);
+ ndr->depth++;
+ if (r->in.DisplayName) {
+ ndr_print_string(ndr, "DisplayName", r->in.DisplayName);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "desired_access", r->in.desired_access);
+ ndr_print_uint32(ndr, "type", r->in.type);
+ ndr_print_uint32(ndr, "start_type", r->in.start_type);
+ ndr_print_uint32(ndr, "error_control", r->in.error_control);
+ ndr_print_string(ndr, "binary_path", r->in.binary_path);
+ ndr_print_ptr(ndr, "LoadOrderGroupKey", r->in.LoadOrderGroupKey);
+ ndr->depth++;
+ if (r->in.LoadOrderGroupKey) {
+ ndr_print_string(ndr, "LoadOrderGroupKey", r->in.LoadOrderGroupKey);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "TagId", r->in.TagId);
+ ndr->depth++;
+ if (r->in.TagId) {
+ ndr_print_uint32(ndr, "TagId", *r->in.TagId);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "dependencies", r->in.dependencies);
+ ndr->depth++;
+ if (r->in.dependencies) {
+ ndr_print_array_uint8(ndr, "dependencies", r->in.dependencies, r->in.dependencies_size);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "dependencies_size", r->in.dependencies_size);
+ ndr_print_ptr(ndr, "service_start_name", r->in.service_start_name);
+ ndr->depth++;
+ if (r->in.service_start_name) {
+ ndr_print_string(ndr, "service_start_name", r->in.service_start_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->in.password);
+ ndr->depth++;
+ if (r->in.password) {
+ ndr_print_array_uint8(ndr, "password", r->in.password, r->in.password_size);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "password_size", r->in.password_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_CreateServiceW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "TagId", r->out.TagId);
+ ndr->depth++;
+ if (r->out.TagId) {
+ ndr_print_uint32(ndr, "TagId", *r->out.TagId);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_EnumDependentServicesW(struct ndr_push *ndr, int flags, const struct svcctl_EnumDependentServicesW *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.service == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.service));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.state));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.service_status == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.service_status, r->in.buf_size));
+ if (r->out.bytes_needed == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.bytes_needed));
+ if (r->out.services_returned == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.services_returned));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_EnumDependentServicesW(struct ndr_pull *ndr, int flags, struct svcctl_EnumDependentServicesW *r)
+{
+ TALLOC_CTX *_mem_save_service_0;
+ TALLOC_CTX *_mem_save_bytes_needed_0;
+ TALLOC_CTX *_mem_save_services_returned_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.service);
+ }
+ _mem_save_service_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.service, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.service));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.state));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ if (r->in.buf_size < 0 || r->in.buf_size > 0x40000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_PULL_ALLOC_N(ndr, r->out.service_status, r->in.buf_size);
+ memset(r->out.service_status, 0, (r->in.buf_size) * sizeof(*r->out.service_status));
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ ZERO_STRUCTP(r->out.bytes_needed);
+ NDR_PULL_ALLOC(ndr, r->out.services_returned);
+ ZERO_STRUCTP(r->out.services_returned);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->out.service_status));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC_N(ndr, r->out.service_status, ndr_get_array_size(ndr, &r->out.service_status));
+ }
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.service_status, ndr_get_array_size(ndr, &r->out.service_status)));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ }
+ _mem_save_bytes_needed_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.bytes_needed, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.bytes_needed));
+ if (*r->out.bytes_needed < 0 || *r->out.bytes_needed > 0x40000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bytes_needed_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.services_returned);
+ }
+ _mem_save_services_returned_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.services_returned, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.services_returned));
+ if (*r->out.services_returned < 0 || *r->out.services_returned > 0x40000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_services_returned_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ if (r->out.service_status) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->out.service_status, r->in.buf_size));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_EnumDependentServicesW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_EnumDependentServicesW *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_EnumDependentServicesW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_EnumDependentServicesW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "service", r->in.service);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "service", r->in.service);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "state", r->in.state);
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_EnumDependentServicesW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "service_status", r->out.service_status);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "service_status", r->out.service_status, r->in.buf_size);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "bytes_needed", r->out.bytes_needed);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "bytes_needed", *r->out.bytes_needed);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "services_returned", r->out.services_returned);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "services_returned", *r->out.services_returned);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_EnumServicesStatusW(struct ndr_push *ndr, int flags, const struct svcctl_EnumServicesStatusW *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.state));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.resume_handle));
+ if (r->in.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.service, r->in.buf_size));
+ if (r->out.bytes_needed == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.bytes_needed));
+ if (r->out.services_returned == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.services_returned));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.resume_handle));
+ if (r->out.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_EnumServicesStatusW(struct ndr_pull *ndr, int flags, struct svcctl_EnumServicesStatusW *r)
+{
+ uint32_t _ptr_resume_handle;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_bytes_needed_0;
+ TALLOC_CTX *_mem_save_services_returned_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.state));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ } else {
+ r->in.resume_handle = NULL;
+ }
+ if (r->in.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ ZERO_STRUCTP(r->out.bytes_needed);
+ NDR_PULL_ALLOC(ndr, r->out.services_returned);
+ ZERO_STRUCTP(r->out.services_returned);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->out.service));
+ NDR_PULL_ALLOC_N(ndr, r->out.service, ndr_get_array_size(ndr, &r->out.service));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.service, ndr_get_array_size(ndr, &r->out.service)));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ }
+ _mem_save_bytes_needed_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.bytes_needed, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.bytes_needed));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bytes_needed_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.services_returned);
+ }
+ _mem_save_services_returned_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.services_returned, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.services_returned));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_services_returned_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ } else {
+ r->out.resume_handle = NULL;
+ }
+ if (r->out.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ if (r->out.service) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->out.service, r->in.buf_size));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_EnumServicesStatusW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_EnumServicesStatusW *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_EnumServicesStatusW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_EnumServicesStatusW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "type", r->in.type);
+ ndr_print_uint32(ndr, "state", r->in.state);
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ if (r->in.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_EnumServicesStatusW");
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "service", r->out.service, r->in.buf_size);
+ ndr_print_ptr(ndr, "bytes_needed", r->out.bytes_needed);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "bytes_needed", *r->out.bytes_needed);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "services_returned", r->out.services_returned);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "services_returned", *r->out.services_returned);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ if (r->out.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_OpenSCManagerW(struct ndr_push *ndr, int flags, const struct svcctl_OpenSCManagerW *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.MachineName));
+ if (r->in.MachineName) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.MachineName, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.MachineName, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.MachineName, ndr_charset_length(r->in.MachineName, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.DatabaseName));
+ if (r->in.DatabaseName) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.DatabaseName, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.DatabaseName, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.DatabaseName, ndr_charset_length(r->in.DatabaseName, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_svcctl_MgrAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_OpenSCManagerW(struct ndr_pull *ndr, int flags, struct svcctl_OpenSCManagerW *r)
+{
+ uint32_t _ptr_MachineName;
+ uint32_t _ptr_DatabaseName;
+ TALLOC_CTX *_mem_save_MachineName_0;
+ TALLOC_CTX *_mem_save_DatabaseName_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_MachineName));
+ if (_ptr_MachineName) {
+ NDR_PULL_ALLOC(ndr, r->in.MachineName);
+ } else {
+ r->in.MachineName = NULL;
+ }
+ if (r->in.MachineName) {
+ _mem_save_MachineName_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.MachineName, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.MachineName));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.MachineName));
+ if (ndr_get_array_length(ndr, &r->in.MachineName) > ndr_get_array_size(ndr, &r->in.MachineName)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.MachineName), ndr_get_array_length(ndr, &r->in.MachineName));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.MachineName), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.MachineName, ndr_get_array_length(ndr, &r->in.MachineName), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_MachineName_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_DatabaseName));
+ if (_ptr_DatabaseName) {
+ NDR_PULL_ALLOC(ndr, r->in.DatabaseName);
+ } else {
+ r->in.DatabaseName = NULL;
+ }
+ if (r->in.DatabaseName) {
+ _mem_save_DatabaseName_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.DatabaseName, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.DatabaseName));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.DatabaseName));
+ if (ndr_get_array_length(ndr, &r->in.DatabaseName) > ndr_get_array_size(ndr, &r->in.DatabaseName)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.DatabaseName), ndr_get_array_length(ndr, &r->in.DatabaseName));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.DatabaseName), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.DatabaseName, ndr_get_array_length(ndr, &r->in.DatabaseName), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_DatabaseName_0, 0);
+ }
+ NDR_CHECK(ndr_pull_svcctl_MgrAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_OpenSCManagerW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_OpenSCManagerW *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_OpenSCManagerW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_OpenSCManagerW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "MachineName", r->in.MachineName);
+ ndr->depth++;
+ if (r->in.MachineName) {
+ ndr_print_string(ndr, "MachineName", r->in.MachineName);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "DatabaseName", r->in.DatabaseName);
+ ndr->depth++;
+ if (r->in.DatabaseName) {
+ ndr_print_string(ndr, "DatabaseName", r->in.DatabaseName);
+ }
+ ndr->depth--;
+ ndr_print_svcctl_MgrAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_OpenSCManagerW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_OpenServiceW(struct ndr_push *ndr, int flags, const struct svcctl_OpenServiceW *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.scmanager_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.scmanager_handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.ServiceName, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.ServiceName, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.ServiceName, ndr_charset_length(r->in.ServiceName, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_svcctl_ServiceAccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_OpenServiceW(struct ndr_pull *ndr, int flags, struct svcctl_OpenServiceW *r)
+{
+ TALLOC_CTX *_mem_save_scmanager_handle_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.scmanager_handle);
+ }
+ _mem_save_scmanager_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.scmanager_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.scmanager_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_scmanager_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.ServiceName));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.ServiceName));
+ if (ndr_get_array_length(ndr, &r->in.ServiceName) > ndr_get_array_size(ndr, &r->in.ServiceName)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.ServiceName), ndr_get_array_length(ndr, &r->in.ServiceName));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.ServiceName), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.ServiceName, ndr_get_array_length(ndr, &r->in.ServiceName), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_svcctl_ServiceAccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_OpenServiceW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_OpenServiceW *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_OpenServiceW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_OpenServiceW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "scmanager_handle", r->in.scmanager_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "scmanager_handle", r->in.scmanager_handle);
+ ndr->depth--;
+ ndr_print_string(ndr, "ServiceName", r->in.ServiceName);
+ ndr_print_svcctl_ServiceAccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_OpenServiceW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_QueryServiceConfigW(struct ndr_push *ndr, int flags, const struct svcctl_QueryServiceConfigW *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.query, r->in.buf_size));
+ if (r->out.bytes_needed == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.bytes_needed));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_QueryServiceConfigW(struct ndr_pull *ndr, int flags, struct svcctl_QueryServiceConfigW *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_bytes_needed_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ ZERO_STRUCTP(r->out.bytes_needed);
+ }
+ if (flags & NDR_OUT) {
+ NDR_PULL_ALLOC_N(ndr, r->out.query, r->in.buf_size);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.query, r->in.buf_size));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ }
+ _mem_save_bytes_needed_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.bytes_needed, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.bytes_needed));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bytes_needed_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_QueryServiceConfigW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceConfigW *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_QueryServiceConfigW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_QueryServiceConfigW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_QueryServiceConfigW");
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "query", r->out.query, r->in.buf_size);
+ ndr_print_ptr(ndr, "bytes_needed", r->out.bytes_needed);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "bytes_needed", *r->out.bytes_needed);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_QueryServiceLockStatusW(struct ndr_push *ndr, int flags, const struct svcctl_QueryServiceLockStatusW *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.lock_status == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_SERVICE_LOCK_STATUS(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.lock_status));
+ if (r->out.required_buf_size == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.required_buf_size));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_QueryServiceLockStatusW(struct ndr_pull *ndr, int flags, struct svcctl_QueryServiceLockStatusW *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_lock_status_0;
+ TALLOC_CTX *_mem_save_required_buf_size_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ NDR_PULL_ALLOC(ndr, r->out.lock_status);
+ ZERO_STRUCTP(r->out.lock_status);
+ NDR_PULL_ALLOC(ndr, r->out.required_buf_size);
+ ZERO_STRUCTP(r->out.required_buf_size);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.lock_status);
+ }
+ _mem_save_lock_status_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.lock_status, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_SERVICE_LOCK_STATUS(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.lock_status));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_lock_status_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.required_buf_size);
+ }
+ _mem_save_required_buf_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.required_buf_size, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.required_buf_size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_required_buf_size_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_QueryServiceLockStatusW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceLockStatusW *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_QueryServiceLockStatusW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_QueryServiceLockStatusW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_QueryServiceLockStatusW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "lock_status", r->out.lock_status);
+ ndr->depth++;
+ ndr_print_SERVICE_LOCK_STATUS(ndr, "lock_status", r->out.lock_status);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "required_buf_size", r->out.required_buf_size);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "required_buf_size", *r->out.required_buf_size);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_StartServiceW(struct ndr_push *ndr, int flags, const struct svcctl_StartServiceW *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.NumArgs));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.Arguments));
+ if (r->in.Arguments) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Arguments, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Arguments, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.Arguments, ndr_charset_length(r->in.Arguments, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_StartServiceW(struct ndr_pull *ndr, int flags, struct svcctl_StartServiceW *r)
+{
+ uint32_t _ptr_Arguments;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_Arguments_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.NumArgs));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_Arguments));
+ if (_ptr_Arguments) {
+ NDR_PULL_ALLOC(ndr, r->in.Arguments);
+ } else {
+ r->in.Arguments = NULL;
+ }
+ if (r->in.Arguments) {
+ _mem_save_Arguments_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.Arguments, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.Arguments));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.Arguments));
+ if (ndr_get_array_length(ndr, &r->in.Arguments) > ndr_get_array_size(ndr, &r->in.Arguments)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.Arguments), ndr_get_array_length(ndr, &r->in.Arguments));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.Arguments), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.Arguments, ndr_get_array_length(ndr, &r->in.Arguments), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_Arguments_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_StartServiceW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_StartServiceW *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_StartServiceW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_StartServiceW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "NumArgs", r->in.NumArgs);
+ ndr_print_ptr(ndr, "Arguments", r->in.Arguments);
+ ndr->depth++;
+ if (r->in.Arguments) {
+ ndr_print_string(ndr, "Arguments", r->in.Arguments);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_StartServiceW");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_GetServiceDisplayNameW(struct ndr_push *ndr, int flags, const struct svcctl_GetServiceDisplayNameW *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.service_name));
+ if (r->in.service_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.service_name, ndr_charset_length(r->in.service_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.display_name_length));
+ if (r->in.display_name_length) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.display_name_length));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.display_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.display_name));
+ if (*r->out.display_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.display_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.display_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, *r->out.display_name, ndr_charset_length(*r->out.display_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.display_name_length));
+ if (r->out.display_name_length) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.display_name_length));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_GetServiceDisplayNameW(struct ndr_pull *ndr, int flags, struct svcctl_GetServiceDisplayNameW *r)
+{
+ uint32_t _ptr_service_name;
+ uint32_t _ptr_display_name;
+ uint32_t _ptr_display_name_length;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_service_name_0;
+ TALLOC_CTX *_mem_save_display_name_0;
+ TALLOC_CTX *_mem_save_display_name_1;
+ TALLOC_CTX *_mem_save_display_name_length_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_service_name));
+ if (_ptr_service_name) {
+ NDR_PULL_ALLOC(ndr, r->in.service_name);
+ } else {
+ r->in.service_name = NULL;
+ }
+ if (r->in.service_name) {
+ _mem_save_service_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.service_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.service_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.service_name));
+ if (ndr_get_array_length(ndr, &r->in.service_name) > ndr_get_array_size(ndr, &r->in.service_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.service_name), ndr_get_array_length(ndr, &r->in.service_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.service_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.service_name, ndr_get_array_length(ndr, &r->in.service_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_display_name_length));
+ if (_ptr_display_name_length) {
+ NDR_PULL_ALLOC(ndr, r->in.display_name_length);
+ } else {
+ r->in.display_name_length = NULL;
+ }
+ if (r->in.display_name_length) {
+ _mem_save_display_name_length_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.display_name_length, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.display_name_length));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_display_name_length_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.display_name);
+ ZERO_STRUCTP(r->out.display_name);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.display_name);
+ }
+ _mem_save_display_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.display_name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_display_name));
+ if (_ptr_display_name) {
+ NDR_PULL_ALLOC(ndr, *r->out.display_name);
+ } else {
+ *r->out.display_name = NULL;
+ }
+ if (*r->out.display_name) {
+ _mem_save_display_name_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.display_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->out.display_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, r->out.display_name));
+ if (ndr_get_array_length(ndr, r->out.display_name) > ndr_get_array_size(ndr, r->out.display_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, r->out.display_name), ndr_get_array_length(ndr, r->out.display_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, r->out.display_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, r->out.display_name, ndr_get_array_length(ndr, r->out.display_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_display_name_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_display_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_display_name_length));
+ if (_ptr_display_name_length) {
+ NDR_PULL_ALLOC(ndr, r->out.display_name_length);
+ } else {
+ r->out.display_name_length = NULL;
+ }
+ if (r->out.display_name_length) {
+ _mem_save_display_name_length_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.display_name_length, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.display_name_length));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_display_name_length_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_GetServiceDisplayNameW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_GetServiceDisplayNameW *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_GetServiceDisplayNameW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_GetServiceDisplayNameW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "service_name", r->in.service_name);
+ ndr->depth++;
+ if (r->in.service_name) {
+ ndr_print_string(ndr, "service_name", r->in.service_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "display_name_length", r->in.display_name_length);
+ ndr->depth++;
+ if (r->in.display_name_length) {
+ ndr_print_uint32(ndr, "display_name_length", *r->in.display_name_length);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_GetServiceDisplayNameW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "display_name", r->out.display_name);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "display_name", *r->out.display_name);
+ ndr->depth++;
+ if (*r->out.display_name) {
+ ndr_print_string(ndr, "display_name", *r->out.display_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "display_name_length", r->out.display_name_length);
+ ndr->depth++;
+ if (r->out.display_name_length) {
+ ndr_print_uint32(ndr, "display_name_length", *r->out.display_name_length);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_GetServiceKeyNameW(struct ndr_push *ndr, int flags, const struct svcctl_GetServiceKeyNameW *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.service_name));
+ if (r->in.service_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.service_name, ndr_charset_length(r->in.service_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.display_name_length));
+ if (r->in.display_name_length) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.display_name_length));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.key_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.key_name));
+ if (*r->out.key_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.key_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.key_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, *r->out.key_name, ndr_charset_length(*r->out.key_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.display_name_length));
+ if (r->out.display_name_length) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.display_name_length));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_GetServiceKeyNameW(struct ndr_pull *ndr, int flags, struct svcctl_GetServiceKeyNameW *r)
+{
+ uint32_t _ptr_service_name;
+ uint32_t _ptr_key_name;
+ uint32_t _ptr_display_name_length;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_service_name_0;
+ TALLOC_CTX *_mem_save_key_name_0;
+ TALLOC_CTX *_mem_save_key_name_1;
+ TALLOC_CTX *_mem_save_display_name_length_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_service_name));
+ if (_ptr_service_name) {
+ NDR_PULL_ALLOC(ndr, r->in.service_name);
+ } else {
+ r->in.service_name = NULL;
+ }
+ if (r->in.service_name) {
+ _mem_save_service_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.service_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.service_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.service_name));
+ if (ndr_get_array_length(ndr, &r->in.service_name) > ndr_get_array_size(ndr, &r->in.service_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.service_name), ndr_get_array_length(ndr, &r->in.service_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.service_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.service_name, ndr_get_array_length(ndr, &r->in.service_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_display_name_length));
+ if (_ptr_display_name_length) {
+ NDR_PULL_ALLOC(ndr, r->in.display_name_length);
+ } else {
+ r->in.display_name_length = NULL;
+ }
+ if (r->in.display_name_length) {
+ _mem_save_display_name_length_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.display_name_length, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.display_name_length));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_display_name_length_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.key_name);
+ ZERO_STRUCTP(r->out.key_name);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.key_name);
+ }
+ _mem_save_key_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.key_name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_key_name));
+ if (_ptr_key_name) {
+ NDR_PULL_ALLOC(ndr, *r->out.key_name);
+ } else {
+ *r->out.key_name = NULL;
+ }
+ if (*r->out.key_name) {
+ _mem_save_key_name_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.key_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->out.key_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, r->out.key_name));
+ if (ndr_get_array_length(ndr, r->out.key_name) > ndr_get_array_size(ndr, r->out.key_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, r->out.key_name), ndr_get_array_length(ndr, r->out.key_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, r->out.key_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, r->out.key_name, ndr_get_array_length(ndr, r->out.key_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_key_name_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_key_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_display_name_length));
+ if (_ptr_display_name_length) {
+ NDR_PULL_ALLOC(ndr, r->out.display_name_length);
+ } else {
+ r->out.display_name_length = NULL;
+ }
+ if (r->out.display_name_length) {
+ _mem_save_display_name_length_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.display_name_length, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.display_name_length));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_display_name_length_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_GetServiceKeyNameW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_GetServiceKeyNameW *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_GetServiceKeyNameW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_GetServiceKeyNameW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "service_name", r->in.service_name);
+ ndr->depth++;
+ if (r->in.service_name) {
+ ndr_print_string(ndr, "service_name", r->in.service_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "display_name_length", r->in.display_name_length);
+ ndr->depth++;
+ if (r->in.display_name_length) {
+ ndr_print_uint32(ndr, "display_name_length", *r->in.display_name_length);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_GetServiceKeyNameW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "key_name", r->out.key_name);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "key_name", *r->out.key_name);
+ ndr->depth++;
+ if (*r->out.key_name) {
+ ndr_print_string(ndr, "key_name", *r->out.key_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "display_name_length", r->out.display_name_length);
+ ndr->depth++;
+ if (r->out.display_name_length) {
+ ndr_print_uint32(ndr, "display_name_length", *r->out.display_name_length);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_SCSetServiceBitsA(struct ndr_push *ndr, int flags, const struct svcctl_SCSetServiceBitsA *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.bits));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.bitson));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.immediate));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_SCSetServiceBitsA(struct ndr_pull *ndr, int flags, struct svcctl_SCSetServiceBitsA *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.bits));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.bitson));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.immediate));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_SCSetServiceBitsA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_SCSetServiceBitsA *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_SCSetServiceBitsA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_SCSetServiceBitsA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "bits", r->in.bits);
+ ndr_print_uint32(ndr, "bitson", r->in.bitson);
+ ndr_print_uint32(ndr, "immediate", r->in.immediate);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_SCSetServiceBitsA");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_ChangeServiceConfigA(struct ndr_push *ndr, int flags, const struct svcctl_ChangeServiceConfigA *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.start));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.error));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.binary_path));
+ if (r->in.binary_path) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.binary_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.binary_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.binary_path, ndr_charset_length(r->in.binary_path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.load_order_group));
+ if (r->in.load_order_group) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.load_order_group, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.load_order_group, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.load_order_group, ndr_charset_length(r->in.load_order_group, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.dependencies));
+ if (r->in.dependencies) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dependencies, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dependencies, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.dependencies, ndr_charset_length(r->in.dependencies, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.service_start_name));
+ if (r->in.service_start_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service_start_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service_start_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.service_start_name, ndr_charset_length(r->in.service_start_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.password));
+ if (r->in.password) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.password, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.password, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.password, ndr_charset_length(r->in.password, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.display_name));
+ if (r->in.display_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.display_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.display_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.display_name, ndr_charset_length(r->in.display_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.tag_id == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.tag_id));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_ChangeServiceConfigA(struct ndr_pull *ndr, int flags, struct svcctl_ChangeServiceConfigA *r)
+{
+ uint32_t _ptr_binary_path;
+ uint32_t _ptr_load_order_group;
+ uint32_t _ptr_dependencies;
+ uint32_t _ptr_service_start_name;
+ uint32_t _ptr_password;
+ uint32_t _ptr_display_name;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_binary_path_0;
+ TALLOC_CTX *_mem_save_load_order_group_0;
+ TALLOC_CTX *_mem_save_tag_id_0;
+ TALLOC_CTX *_mem_save_dependencies_0;
+ TALLOC_CTX *_mem_save_service_start_name_0;
+ TALLOC_CTX *_mem_save_password_0;
+ TALLOC_CTX *_mem_save_display_name_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.start));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.error));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_binary_path));
+ if (_ptr_binary_path) {
+ NDR_PULL_ALLOC(ndr, r->in.binary_path);
+ } else {
+ r->in.binary_path = NULL;
+ }
+ if (r->in.binary_path) {
+ _mem_save_binary_path_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.binary_path, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.binary_path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.binary_path));
+ if (ndr_get_array_length(ndr, &r->in.binary_path) > ndr_get_array_size(ndr, &r->in.binary_path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.binary_path), ndr_get_array_length(ndr, &r->in.binary_path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.binary_path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.binary_path, ndr_get_array_length(ndr, &r->in.binary_path), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_binary_path_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_load_order_group));
+ if (_ptr_load_order_group) {
+ NDR_PULL_ALLOC(ndr, r->in.load_order_group);
+ } else {
+ r->in.load_order_group = NULL;
+ }
+ if (r->in.load_order_group) {
+ _mem_save_load_order_group_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.load_order_group, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.load_order_group));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.load_order_group));
+ if (ndr_get_array_length(ndr, &r->in.load_order_group) > ndr_get_array_size(ndr, &r->in.load_order_group)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.load_order_group), ndr_get_array_length(ndr, &r->in.load_order_group));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.load_order_group), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.load_order_group, ndr_get_array_length(ndr, &r->in.load_order_group), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_load_order_group_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dependencies));
+ if (_ptr_dependencies) {
+ NDR_PULL_ALLOC(ndr, r->in.dependencies);
+ } else {
+ r->in.dependencies = NULL;
+ }
+ if (r->in.dependencies) {
+ _mem_save_dependencies_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.dependencies, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.dependencies));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.dependencies));
+ if (ndr_get_array_length(ndr, &r->in.dependencies) > ndr_get_array_size(ndr, &r->in.dependencies)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.dependencies), ndr_get_array_length(ndr, &r->in.dependencies));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.dependencies), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.dependencies, ndr_get_array_length(ndr, &r->in.dependencies), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dependencies_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_service_start_name));
+ if (_ptr_service_start_name) {
+ NDR_PULL_ALLOC(ndr, r->in.service_start_name);
+ } else {
+ r->in.service_start_name = NULL;
+ }
+ if (r->in.service_start_name) {
+ _mem_save_service_start_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.service_start_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.service_start_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.service_start_name));
+ if (ndr_get_array_length(ndr, &r->in.service_start_name) > ndr_get_array_size(ndr, &r->in.service_start_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.service_start_name), ndr_get_array_length(ndr, &r->in.service_start_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.service_start_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.service_start_name, ndr_get_array_length(ndr, &r->in.service_start_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_start_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password));
+ if (_ptr_password) {
+ NDR_PULL_ALLOC(ndr, r->in.password);
+ } else {
+ r->in.password = NULL;
+ }
+ if (r->in.password) {
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.password, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.password));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.password));
+ if (ndr_get_array_length(ndr, &r->in.password) > ndr_get_array_size(ndr, &r->in.password)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.password), ndr_get_array_length(ndr, &r->in.password));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.password), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.password, ndr_get_array_length(ndr, &r->in.password), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_display_name));
+ if (_ptr_display_name) {
+ NDR_PULL_ALLOC(ndr, r->in.display_name);
+ } else {
+ r->in.display_name = NULL;
+ }
+ if (r->in.display_name) {
+ _mem_save_display_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.display_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.display_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.display_name));
+ if (ndr_get_array_length(ndr, &r->in.display_name) > ndr_get_array_size(ndr, &r->in.display_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.display_name), ndr_get_array_length(ndr, &r->in.display_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.display_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.display_name, ndr_get_array_length(ndr, &r->in.display_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_display_name_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.tag_id);
+ ZERO_STRUCTP(r->out.tag_id);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.tag_id);
+ }
+ _mem_save_tag_id_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.tag_id, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.tag_id));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_tag_id_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_ChangeServiceConfigA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_ChangeServiceConfigA *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_ChangeServiceConfigA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_ChangeServiceConfigA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "type", r->in.type);
+ ndr_print_uint32(ndr, "start", r->in.start);
+ ndr_print_uint32(ndr, "error", r->in.error);
+ ndr_print_ptr(ndr, "binary_path", r->in.binary_path);
+ ndr->depth++;
+ if (r->in.binary_path) {
+ ndr_print_string(ndr, "binary_path", r->in.binary_path);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "load_order_group", r->in.load_order_group);
+ ndr->depth++;
+ if (r->in.load_order_group) {
+ ndr_print_string(ndr, "load_order_group", r->in.load_order_group);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "dependencies", r->in.dependencies);
+ ndr->depth++;
+ if (r->in.dependencies) {
+ ndr_print_string(ndr, "dependencies", r->in.dependencies);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "service_start_name", r->in.service_start_name);
+ ndr->depth++;
+ if (r->in.service_start_name) {
+ ndr_print_string(ndr, "service_start_name", r->in.service_start_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->in.password);
+ ndr->depth++;
+ if (r->in.password) {
+ ndr_print_string(ndr, "password", r->in.password);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "display_name", r->in.display_name);
+ ndr->depth++;
+ if (r->in.display_name) {
+ ndr_print_string(ndr, "display_name", r->in.display_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_ChangeServiceConfigA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "tag_id", r->out.tag_id);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "tag_id", *r->out.tag_id);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_CreateServiceA(struct ndr_push *ndr, int flags, const struct svcctl_CreateServiceA *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.ServiceName));
+ if (r->in.ServiceName) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.ServiceName, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.ServiceName, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.ServiceName, ndr_charset_length(r->in.ServiceName, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.DisplayName));
+ if (r->in.DisplayName) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.DisplayName, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.DisplayName, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.DisplayName, ndr_charset_length(r->in.DisplayName, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.desired_access));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.start_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.error_control));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.binary_path));
+ if (r->in.binary_path) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.binary_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.binary_path, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.binary_path, ndr_charset_length(r->in.binary_path, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.LoadOrderGroupKey));
+ if (r->in.LoadOrderGroupKey) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.LoadOrderGroupKey, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.LoadOrderGroupKey, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.LoadOrderGroupKey, ndr_charset_length(r->in.LoadOrderGroupKey, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.dependencies));
+ if (r->in.dependencies) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dependencies, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.dependencies, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.dependencies, ndr_charset_length(r->in.dependencies, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.service_start_name));
+ if (r->in.service_start_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service_start_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service_start_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.service_start_name, ndr_charset_length(r->in.service_start_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.password));
+ if (r->in.password) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.password, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.password, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.password, ndr_charset_length(r->in.password, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.TagId));
+ if (r->out.TagId) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.TagId));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_CreateServiceA(struct ndr_pull *ndr, int flags, struct svcctl_CreateServiceA *r)
+{
+ uint32_t _ptr_ServiceName;
+ uint32_t _ptr_DisplayName;
+ uint32_t _ptr_binary_path;
+ uint32_t _ptr_LoadOrderGroupKey;
+ uint32_t _ptr_TagId;
+ uint32_t _ptr_dependencies;
+ uint32_t _ptr_service_start_name;
+ uint32_t _ptr_password;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_ServiceName_0;
+ TALLOC_CTX *_mem_save_DisplayName_0;
+ TALLOC_CTX *_mem_save_binary_path_0;
+ TALLOC_CTX *_mem_save_LoadOrderGroupKey_0;
+ TALLOC_CTX *_mem_save_TagId_0;
+ TALLOC_CTX *_mem_save_dependencies_0;
+ TALLOC_CTX *_mem_save_service_start_name_0;
+ TALLOC_CTX *_mem_save_password_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ServiceName));
+ if (_ptr_ServiceName) {
+ NDR_PULL_ALLOC(ndr, r->in.ServiceName);
+ } else {
+ r->in.ServiceName = NULL;
+ }
+ if (r->in.ServiceName) {
+ _mem_save_ServiceName_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.ServiceName, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.ServiceName));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.ServiceName));
+ if (ndr_get_array_length(ndr, &r->in.ServiceName) > ndr_get_array_size(ndr, &r->in.ServiceName)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.ServiceName), ndr_get_array_length(ndr, &r->in.ServiceName));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.ServiceName), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.ServiceName, ndr_get_array_length(ndr, &r->in.ServiceName), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ServiceName_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_DisplayName));
+ if (_ptr_DisplayName) {
+ NDR_PULL_ALLOC(ndr, r->in.DisplayName);
+ } else {
+ r->in.DisplayName = NULL;
+ }
+ if (r->in.DisplayName) {
+ _mem_save_DisplayName_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.DisplayName, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.DisplayName));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.DisplayName));
+ if (ndr_get_array_length(ndr, &r->in.DisplayName) > ndr_get_array_size(ndr, &r->in.DisplayName)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.DisplayName), ndr_get_array_length(ndr, &r->in.DisplayName));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.DisplayName), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.DisplayName, ndr_get_array_length(ndr, &r->in.DisplayName), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_DisplayName_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.desired_access));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.start_type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.error_control));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_binary_path));
+ if (_ptr_binary_path) {
+ NDR_PULL_ALLOC(ndr, r->in.binary_path);
+ } else {
+ r->in.binary_path = NULL;
+ }
+ if (r->in.binary_path) {
+ _mem_save_binary_path_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.binary_path, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.binary_path));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.binary_path));
+ if (ndr_get_array_length(ndr, &r->in.binary_path) > ndr_get_array_size(ndr, &r->in.binary_path)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.binary_path), ndr_get_array_length(ndr, &r->in.binary_path));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.binary_path), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.binary_path, ndr_get_array_length(ndr, &r->in.binary_path), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_binary_path_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_LoadOrderGroupKey));
+ if (_ptr_LoadOrderGroupKey) {
+ NDR_PULL_ALLOC(ndr, r->in.LoadOrderGroupKey);
+ } else {
+ r->in.LoadOrderGroupKey = NULL;
+ }
+ if (r->in.LoadOrderGroupKey) {
+ _mem_save_LoadOrderGroupKey_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.LoadOrderGroupKey, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.LoadOrderGroupKey));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.LoadOrderGroupKey));
+ if (ndr_get_array_length(ndr, &r->in.LoadOrderGroupKey) > ndr_get_array_size(ndr, &r->in.LoadOrderGroupKey)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.LoadOrderGroupKey), ndr_get_array_length(ndr, &r->in.LoadOrderGroupKey));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.LoadOrderGroupKey), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.LoadOrderGroupKey, ndr_get_array_length(ndr, &r->in.LoadOrderGroupKey), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_LoadOrderGroupKey_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dependencies));
+ if (_ptr_dependencies) {
+ NDR_PULL_ALLOC(ndr, r->in.dependencies);
+ } else {
+ r->in.dependencies = NULL;
+ }
+ if (r->in.dependencies) {
+ _mem_save_dependencies_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.dependencies, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.dependencies));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.dependencies));
+ if (ndr_get_array_length(ndr, &r->in.dependencies) > ndr_get_array_size(ndr, &r->in.dependencies)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.dependencies), ndr_get_array_length(ndr, &r->in.dependencies));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.dependencies), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.dependencies, ndr_get_array_length(ndr, &r->in.dependencies), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dependencies_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_service_start_name));
+ if (_ptr_service_start_name) {
+ NDR_PULL_ALLOC(ndr, r->in.service_start_name);
+ } else {
+ r->in.service_start_name = NULL;
+ }
+ if (r->in.service_start_name) {
+ _mem_save_service_start_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.service_start_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.service_start_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.service_start_name));
+ if (ndr_get_array_length(ndr, &r->in.service_start_name) > ndr_get_array_size(ndr, &r->in.service_start_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.service_start_name), ndr_get_array_length(ndr, &r->in.service_start_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.service_start_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.service_start_name, ndr_get_array_length(ndr, &r->in.service_start_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_start_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password));
+ if (_ptr_password) {
+ NDR_PULL_ALLOC(ndr, r->in.password);
+ } else {
+ r->in.password = NULL;
+ }
+ if (r->in.password) {
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.password, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.password));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.password));
+ if (ndr_get_array_length(ndr, &r->in.password) > ndr_get_array_size(ndr, &r->in.password)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.password), ndr_get_array_length(ndr, &r->in.password));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.password), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.password, ndr_get_array_length(ndr, &r->in.password), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_TagId));
+ if (_ptr_TagId) {
+ NDR_PULL_ALLOC(ndr, r->out.TagId);
+ } else {
+ r->out.TagId = NULL;
+ }
+ if (r->out.TagId) {
+ _mem_save_TagId_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.TagId, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.TagId));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_TagId_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_CreateServiceA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_CreateServiceA *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_CreateServiceA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_CreateServiceA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ServiceName", r->in.ServiceName);
+ ndr->depth++;
+ if (r->in.ServiceName) {
+ ndr_print_string(ndr, "ServiceName", r->in.ServiceName);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "DisplayName", r->in.DisplayName);
+ ndr->depth++;
+ if (r->in.DisplayName) {
+ ndr_print_string(ndr, "DisplayName", r->in.DisplayName);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "desired_access", r->in.desired_access);
+ ndr_print_uint32(ndr, "type", r->in.type);
+ ndr_print_uint32(ndr, "start_type", r->in.start_type);
+ ndr_print_uint32(ndr, "error_control", r->in.error_control);
+ ndr_print_ptr(ndr, "binary_path", r->in.binary_path);
+ ndr->depth++;
+ if (r->in.binary_path) {
+ ndr_print_string(ndr, "binary_path", r->in.binary_path);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "LoadOrderGroupKey", r->in.LoadOrderGroupKey);
+ ndr->depth++;
+ if (r->in.LoadOrderGroupKey) {
+ ndr_print_string(ndr, "LoadOrderGroupKey", r->in.LoadOrderGroupKey);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "dependencies", r->in.dependencies);
+ ndr->depth++;
+ if (r->in.dependencies) {
+ ndr_print_string(ndr, "dependencies", r->in.dependencies);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "service_start_name", r->in.service_start_name);
+ ndr->depth++;
+ if (r->in.service_start_name) {
+ ndr_print_string(ndr, "service_start_name", r->in.service_start_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->in.password);
+ ndr->depth++;
+ if (r->in.password) {
+ ndr_print_string(ndr, "password", r->in.password);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_CreateServiceA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "TagId", r->out.TagId);
+ ndr->depth++;
+ if (r->out.TagId) {
+ ndr_print_uint32(ndr, "TagId", *r->out.TagId);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_EnumDependentServicesA(struct ndr_push *ndr, int flags, const struct svcctl_EnumDependentServicesA *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.service == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.service));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.state));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.service_status));
+ if (r->out.service_status) {
+ NDR_CHECK(ndr_push_ENUM_SERVICE_STATUS(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.service_status));
+ }
+ if (r->out.bytes_needed == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.bytes_needed));
+ if (r->out.services_returned == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.services_returned));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_EnumDependentServicesA(struct ndr_pull *ndr, int flags, struct svcctl_EnumDependentServicesA *r)
+{
+ uint32_t _ptr_service_status;
+ TALLOC_CTX *_mem_save_service_0;
+ TALLOC_CTX *_mem_save_service_status_0;
+ TALLOC_CTX *_mem_save_bytes_needed_0;
+ TALLOC_CTX *_mem_save_services_returned_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.service);
+ }
+ _mem_save_service_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.service, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.service));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.state));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ ZERO_STRUCTP(r->out.bytes_needed);
+ NDR_PULL_ALLOC(ndr, r->out.services_returned);
+ ZERO_STRUCTP(r->out.services_returned);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_service_status));
+ if (_ptr_service_status) {
+ NDR_PULL_ALLOC(ndr, r->out.service_status);
+ } else {
+ r->out.service_status = NULL;
+ }
+ if (r->out.service_status) {
+ _mem_save_service_status_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.service_status, 0);
+ NDR_CHECK(ndr_pull_ENUM_SERVICE_STATUS(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.service_status));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_status_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ }
+ _mem_save_bytes_needed_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.bytes_needed, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.bytes_needed));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bytes_needed_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.services_returned);
+ }
+ _mem_save_services_returned_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.services_returned, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.services_returned));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_services_returned_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_EnumDependentServicesA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_EnumDependentServicesA *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_EnumDependentServicesA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_EnumDependentServicesA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "service", r->in.service);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "service", r->in.service);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "state", r->in.state);
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_EnumDependentServicesA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "service_status", r->out.service_status);
+ ndr->depth++;
+ if (r->out.service_status) {
+ ndr_print_ENUM_SERVICE_STATUS(ndr, "service_status", r->out.service_status);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "bytes_needed", r->out.bytes_needed);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "bytes_needed", *r->out.bytes_needed);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "services_returned", r->out.services_returned);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "services_returned", *r->out.services_returned);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_EnumServicesStatusA(struct ndr_push *ndr, int flags, const struct svcctl_EnumServicesStatusA *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.state));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.resume_handle));
+ if (r->in.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.service, r->in.buf_size));
+ if (r->out.bytes_needed == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.bytes_needed));
+ if (r->out.services_returned == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.services_returned));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.resume_handle));
+ if (r->out.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_EnumServicesStatusA(struct ndr_pull *ndr, int flags, struct svcctl_EnumServicesStatusA *r)
+{
+ uint32_t _ptr_resume_handle;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_bytes_needed_0;
+ TALLOC_CTX *_mem_save_services_returned_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.state));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ } else {
+ r->in.resume_handle = NULL;
+ }
+ if (r->in.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ ZERO_STRUCTP(r->out.bytes_needed);
+ NDR_PULL_ALLOC(ndr, r->out.services_returned);
+ ZERO_STRUCTP(r->out.services_returned);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->out.service));
+ NDR_PULL_ALLOC_N(ndr, r->out.service, ndr_get_array_size(ndr, &r->out.service));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.service, ndr_get_array_size(ndr, &r->out.service)));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ }
+ _mem_save_bytes_needed_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.bytes_needed, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.bytes_needed));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bytes_needed_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.services_returned);
+ }
+ _mem_save_services_returned_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.services_returned, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.services_returned));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_services_returned_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ } else {
+ r->out.resume_handle = NULL;
+ }
+ if (r->out.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ if (r->out.service) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->out.service, r->in.buf_size));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_EnumServicesStatusA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_EnumServicesStatusA *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_EnumServicesStatusA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_EnumServicesStatusA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "type", r->in.type);
+ ndr_print_uint32(ndr, "state", r->in.state);
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ if (r->in.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_EnumServicesStatusA");
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "service", r->out.service, r->in.buf_size);
+ ndr_print_ptr(ndr, "bytes_needed", r->out.bytes_needed);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "bytes_needed", *r->out.bytes_needed);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "services_returned", r->out.services_returned);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "services_returned", *r->out.services_returned);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ if (r->out.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_OpenSCManagerA(struct ndr_push *ndr, int flags, const struct svcctl_OpenSCManagerA *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.MachineName));
+ if (r->in.MachineName) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.MachineName, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.MachineName, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.MachineName, ndr_charset_length(r->in.MachineName, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.DatabaseName));
+ if (r->in.DatabaseName) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.DatabaseName, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.DatabaseName, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.DatabaseName, ndr_charset_length(r->in.DatabaseName, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_OpenSCManagerA(struct ndr_pull *ndr, int flags, struct svcctl_OpenSCManagerA *r)
+{
+ uint32_t _ptr_MachineName;
+ uint32_t _ptr_DatabaseName;
+ TALLOC_CTX *_mem_save_MachineName_0;
+ TALLOC_CTX *_mem_save_DatabaseName_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_MachineName));
+ if (_ptr_MachineName) {
+ NDR_PULL_ALLOC(ndr, r->in.MachineName);
+ } else {
+ r->in.MachineName = NULL;
+ }
+ if (r->in.MachineName) {
+ _mem_save_MachineName_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.MachineName, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.MachineName));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.MachineName));
+ if (ndr_get_array_length(ndr, &r->in.MachineName) > ndr_get_array_size(ndr, &r->in.MachineName)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.MachineName), ndr_get_array_length(ndr, &r->in.MachineName));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.MachineName), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.MachineName, ndr_get_array_length(ndr, &r->in.MachineName), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_MachineName_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_DatabaseName));
+ if (_ptr_DatabaseName) {
+ NDR_PULL_ALLOC(ndr, r->in.DatabaseName);
+ } else {
+ r->in.DatabaseName = NULL;
+ }
+ if (r->in.DatabaseName) {
+ _mem_save_DatabaseName_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.DatabaseName, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.DatabaseName));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.DatabaseName));
+ if (ndr_get_array_length(ndr, &r->in.DatabaseName) > ndr_get_array_size(ndr, &r->in.DatabaseName)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.DatabaseName), ndr_get_array_length(ndr, &r->in.DatabaseName));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.DatabaseName), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.DatabaseName, ndr_get_array_length(ndr, &r->in.DatabaseName), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_DatabaseName_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_OpenSCManagerA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_OpenSCManagerA *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_OpenSCManagerA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_OpenSCManagerA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "MachineName", r->in.MachineName);
+ ndr->depth++;
+ if (r->in.MachineName) {
+ ndr_print_string(ndr, "MachineName", r->in.MachineName);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "DatabaseName", r->in.DatabaseName);
+ ndr->depth++;
+ if (r->in.DatabaseName) {
+ ndr_print_string(ndr, "DatabaseName", r->in.DatabaseName);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_OpenSCManagerA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_OpenServiceA(struct ndr_push *ndr, int flags, const struct svcctl_OpenServiceA *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.scmanager_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.scmanager_handle));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.ServiceName));
+ if (r->in.ServiceName) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.ServiceName, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.ServiceName, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.ServiceName, ndr_charset_length(r->in.ServiceName, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_OpenServiceA(struct ndr_pull *ndr, int flags, struct svcctl_OpenServiceA *r)
+{
+ uint32_t _ptr_ServiceName;
+ TALLOC_CTX *_mem_save_scmanager_handle_0;
+ TALLOC_CTX *_mem_save_ServiceName_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.scmanager_handle);
+ }
+ _mem_save_scmanager_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.scmanager_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.scmanager_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_scmanager_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ServiceName));
+ if (_ptr_ServiceName) {
+ NDR_PULL_ALLOC(ndr, r->in.ServiceName);
+ } else {
+ r->in.ServiceName = NULL;
+ }
+ if (r->in.ServiceName) {
+ _mem_save_ServiceName_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.ServiceName, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.ServiceName));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.ServiceName));
+ if (ndr_get_array_length(ndr, &r->in.ServiceName) > ndr_get_array_size(ndr, &r->in.ServiceName)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.ServiceName), ndr_get_array_length(ndr, &r->in.ServiceName));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.ServiceName), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.ServiceName, ndr_get_array_length(ndr, &r->in.ServiceName), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ServiceName_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_OpenServiceA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_OpenServiceA *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_OpenServiceA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_OpenServiceA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "scmanager_handle", r->in.scmanager_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "scmanager_handle", r->in.scmanager_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ServiceName", r->in.ServiceName);
+ ndr->depth++;
+ if (r->in.ServiceName) {
+ ndr_print_string(ndr, "ServiceName", r->in.ServiceName);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_OpenServiceA");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_QueryServiceConfigA(struct ndr_push *ndr, int flags, const struct svcctl_QueryServiceConfigA *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.query, r->in.buf_size));
+ if (r->out.bytes_needed == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.bytes_needed));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_QueryServiceConfigA(struct ndr_pull *ndr, int flags, struct svcctl_QueryServiceConfigA *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_bytes_needed_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ ZERO_STRUCTP(r->out.bytes_needed);
+ }
+ if (flags & NDR_OUT) {
+ NDR_PULL_ALLOC_N(ndr, r->out.query, r->in.buf_size);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.query, r->in.buf_size));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ }
+ _mem_save_bytes_needed_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.bytes_needed, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.bytes_needed));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bytes_needed_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_QueryServiceConfigA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceConfigA *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_QueryServiceConfigA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_QueryServiceConfigA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_QueryServiceConfigA");
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "query", r->out.query, r->in.buf_size);
+ ndr_print_ptr(ndr, "bytes_needed", r->out.bytes_needed);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "bytes_needed", *r->out.bytes_needed);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_QueryServiceLockStatusA(struct ndr_push *ndr, int flags, const struct svcctl_QueryServiceLockStatusA *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.lock_status == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_SERVICE_LOCK_STATUS(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.lock_status));
+ if (r->out.required_buf_size == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.required_buf_size));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_QueryServiceLockStatusA(struct ndr_pull *ndr, int flags, struct svcctl_QueryServiceLockStatusA *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_lock_status_0;
+ TALLOC_CTX *_mem_save_required_buf_size_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ NDR_PULL_ALLOC(ndr, r->out.lock_status);
+ ZERO_STRUCTP(r->out.lock_status);
+ NDR_PULL_ALLOC(ndr, r->out.required_buf_size);
+ ZERO_STRUCTP(r->out.required_buf_size);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.lock_status);
+ }
+ _mem_save_lock_status_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.lock_status, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_SERVICE_LOCK_STATUS(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.lock_status));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_lock_status_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.required_buf_size);
+ }
+ _mem_save_required_buf_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.required_buf_size, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.required_buf_size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_required_buf_size_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_QueryServiceLockStatusA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceLockStatusA *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_QueryServiceLockStatusA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_QueryServiceLockStatusA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_QueryServiceLockStatusA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "lock_status", r->out.lock_status);
+ ndr->depth++;
+ ndr_print_SERVICE_LOCK_STATUS(ndr, "lock_status", r->out.lock_status);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "required_buf_size", r->out.required_buf_size);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "required_buf_size", *r->out.required_buf_size);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_StartServiceA(struct ndr_push *ndr, int flags, const struct svcctl_StartServiceA *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.NumArgs));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.Arguments));
+ if (r->in.Arguments) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Arguments, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Arguments, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.Arguments, ndr_charset_length(r->in.Arguments, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_StartServiceA(struct ndr_pull *ndr, int flags, struct svcctl_StartServiceA *r)
+{
+ uint32_t _ptr_Arguments;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_Arguments_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.NumArgs));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_Arguments));
+ if (_ptr_Arguments) {
+ NDR_PULL_ALLOC(ndr, r->in.Arguments);
+ } else {
+ r->in.Arguments = NULL;
+ }
+ if (r->in.Arguments) {
+ _mem_save_Arguments_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.Arguments, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.Arguments));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.Arguments));
+ if (ndr_get_array_length(ndr, &r->in.Arguments) > ndr_get_array_size(ndr, &r->in.Arguments)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.Arguments), ndr_get_array_length(ndr, &r->in.Arguments));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.Arguments), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.Arguments, ndr_get_array_length(ndr, &r->in.Arguments), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_Arguments_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_StartServiceA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_StartServiceA *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_StartServiceA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_StartServiceA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "NumArgs", r->in.NumArgs);
+ ndr_print_ptr(ndr, "Arguments", r->in.Arguments);
+ ndr->depth++;
+ if (r->in.Arguments) {
+ ndr_print_string(ndr, "Arguments", r->in.Arguments);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_StartServiceA");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_GetServiceDisplayNameA(struct ndr_push *ndr, int flags, const struct svcctl_GetServiceDisplayNameA *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.service_name));
+ if (r->in.service_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.service_name, ndr_charset_length(r->in.service_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.display_name_length));
+ if (r->in.display_name_length) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.display_name_length));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.display_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.display_name));
+ if (*r->out.display_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.display_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.display_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, *r->out.display_name, ndr_charset_length(*r->out.display_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.display_name_length));
+ if (r->out.display_name_length) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.display_name_length));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_GetServiceDisplayNameA(struct ndr_pull *ndr, int flags, struct svcctl_GetServiceDisplayNameA *r)
+{
+ uint32_t _ptr_service_name;
+ uint32_t _ptr_display_name;
+ uint32_t _ptr_display_name_length;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_service_name_0;
+ TALLOC_CTX *_mem_save_display_name_0;
+ TALLOC_CTX *_mem_save_display_name_1;
+ TALLOC_CTX *_mem_save_display_name_length_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_service_name));
+ if (_ptr_service_name) {
+ NDR_PULL_ALLOC(ndr, r->in.service_name);
+ } else {
+ r->in.service_name = NULL;
+ }
+ if (r->in.service_name) {
+ _mem_save_service_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.service_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.service_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.service_name));
+ if (ndr_get_array_length(ndr, &r->in.service_name) > ndr_get_array_size(ndr, &r->in.service_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.service_name), ndr_get_array_length(ndr, &r->in.service_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.service_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.service_name, ndr_get_array_length(ndr, &r->in.service_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_display_name_length));
+ if (_ptr_display_name_length) {
+ NDR_PULL_ALLOC(ndr, r->in.display_name_length);
+ } else {
+ r->in.display_name_length = NULL;
+ }
+ if (r->in.display_name_length) {
+ _mem_save_display_name_length_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.display_name_length, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.display_name_length));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_display_name_length_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.display_name);
+ ZERO_STRUCTP(r->out.display_name);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.display_name);
+ }
+ _mem_save_display_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.display_name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_display_name));
+ if (_ptr_display_name) {
+ NDR_PULL_ALLOC(ndr, *r->out.display_name);
+ } else {
+ *r->out.display_name = NULL;
+ }
+ if (*r->out.display_name) {
+ _mem_save_display_name_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.display_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->out.display_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, r->out.display_name));
+ if (ndr_get_array_length(ndr, r->out.display_name) > ndr_get_array_size(ndr, r->out.display_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, r->out.display_name), ndr_get_array_length(ndr, r->out.display_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, r->out.display_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, r->out.display_name, ndr_get_array_length(ndr, r->out.display_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_display_name_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_display_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_display_name_length));
+ if (_ptr_display_name_length) {
+ NDR_PULL_ALLOC(ndr, r->out.display_name_length);
+ } else {
+ r->out.display_name_length = NULL;
+ }
+ if (r->out.display_name_length) {
+ _mem_save_display_name_length_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.display_name_length, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.display_name_length));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_display_name_length_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_GetServiceDisplayNameA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_GetServiceDisplayNameA *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_GetServiceDisplayNameA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_GetServiceDisplayNameA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "service_name", r->in.service_name);
+ ndr->depth++;
+ if (r->in.service_name) {
+ ndr_print_string(ndr, "service_name", r->in.service_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "display_name_length", r->in.display_name_length);
+ ndr->depth++;
+ if (r->in.display_name_length) {
+ ndr_print_uint32(ndr, "display_name_length", *r->in.display_name_length);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_GetServiceDisplayNameA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "display_name", r->out.display_name);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "display_name", *r->out.display_name);
+ ndr->depth++;
+ if (*r->out.display_name) {
+ ndr_print_string(ndr, "display_name", *r->out.display_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "display_name_length", r->out.display_name_length);
+ ndr->depth++;
+ if (r->out.display_name_length) {
+ ndr_print_uint32(ndr, "display_name_length", *r->out.display_name_length);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_GetServiceKeyNameA(struct ndr_push *ndr, int flags, const struct svcctl_GetServiceKeyNameA *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.service_name));
+ if (r->in.service_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.service_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.service_name, ndr_charset_length(r->in.service_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.display_name_length));
+ if (r->in.display_name_length) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.display_name_length));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.key_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.key_name));
+ if (*r->out.key_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.key_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.key_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, *r->out.key_name, ndr_charset_length(*r->out.key_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.display_name_length));
+ if (r->out.display_name_length) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.display_name_length));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_GetServiceKeyNameA(struct ndr_pull *ndr, int flags, struct svcctl_GetServiceKeyNameA *r)
+{
+ uint32_t _ptr_service_name;
+ uint32_t _ptr_key_name;
+ uint32_t _ptr_display_name_length;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_service_name_0;
+ TALLOC_CTX *_mem_save_key_name_0;
+ TALLOC_CTX *_mem_save_key_name_1;
+ TALLOC_CTX *_mem_save_display_name_length_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_service_name));
+ if (_ptr_service_name) {
+ NDR_PULL_ALLOC(ndr, r->in.service_name);
+ } else {
+ r->in.service_name = NULL;
+ }
+ if (r->in.service_name) {
+ _mem_save_service_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.service_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.service_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.service_name));
+ if (ndr_get_array_length(ndr, &r->in.service_name) > ndr_get_array_size(ndr, &r->in.service_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.service_name), ndr_get_array_length(ndr, &r->in.service_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.service_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.service_name, ndr_get_array_length(ndr, &r->in.service_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_display_name_length));
+ if (_ptr_display_name_length) {
+ NDR_PULL_ALLOC(ndr, r->in.display_name_length);
+ } else {
+ r->in.display_name_length = NULL;
+ }
+ if (r->in.display_name_length) {
+ _mem_save_display_name_length_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.display_name_length, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.display_name_length));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_display_name_length_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.key_name);
+ ZERO_STRUCTP(r->out.key_name);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.key_name);
+ }
+ _mem_save_key_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.key_name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_key_name));
+ if (_ptr_key_name) {
+ NDR_PULL_ALLOC(ndr, *r->out.key_name);
+ } else {
+ *r->out.key_name = NULL;
+ }
+ if (*r->out.key_name) {
+ _mem_save_key_name_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.key_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->out.key_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, r->out.key_name));
+ if (ndr_get_array_length(ndr, r->out.key_name) > ndr_get_array_size(ndr, r->out.key_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, r->out.key_name), ndr_get_array_length(ndr, r->out.key_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, r->out.key_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, r->out.key_name, ndr_get_array_length(ndr, r->out.key_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_key_name_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_key_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_display_name_length));
+ if (_ptr_display_name_length) {
+ NDR_PULL_ALLOC(ndr, r->out.display_name_length);
+ } else {
+ r->out.display_name_length = NULL;
+ }
+ if (r->out.display_name_length) {
+ _mem_save_display_name_length_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.display_name_length, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.display_name_length));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_display_name_length_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_GetServiceKeyNameA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_GetServiceKeyNameA *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_GetServiceKeyNameA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_GetServiceKeyNameA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "service_name", r->in.service_name);
+ ndr->depth++;
+ if (r->in.service_name) {
+ ndr_print_string(ndr, "service_name", r->in.service_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "display_name_length", r->in.display_name_length);
+ ndr->depth++;
+ if (r->in.display_name_length) {
+ ndr_print_uint32(ndr, "display_name_length", *r->in.display_name_length);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_GetServiceKeyNameA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "key_name", r->out.key_name);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "key_name", *r->out.key_name);
+ ndr->depth++;
+ if (*r->out.key_name) {
+ ndr_print_string(ndr, "key_name", *r->out.key_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "display_name_length", r->out.display_name_length);
+ ndr->depth++;
+ if (r->out.display_name_length) {
+ ndr_print_uint32(ndr, "display_name_length", *r->out.display_name_length);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_GetCurrentGroupeStateW(struct ndr_push *ndr, int flags, const struct svcctl_GetCurrentGroupeStateW *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_GetCurrentGroupeStateW(struct ndr_pull *ndr, int flags, struct svcctl_GetCurrentGroupeStateW *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_GetCurrentGroupeStateW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_GetCurrentGroupeStateW *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_GetCurrentGroupeStateW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_GetCurrentGroupeStateW");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_GetCurrentGroupeStateW");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_EnumServiceGroupW(struct ndr_push *ndr, int flags, const struct svcctl_EnumServiceGroupW *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_EnumServiceGroupW(struct ndr_pull *ndr, int flags, struct svcctl_EnumServiceGroupW *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_EnumServiceGroupW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_EnumServiceGroupW *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_EnumServiceGroupW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_EnumServiceGroupW");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_EnumServiceGroupW");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_ChangeServiceConfig2A(struct ndr_push *ndr, int flags, const struct svcctl_ChangeServiceConfig2A *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.info_level));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.info));
+ if (r->in.info) {
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, *r->in.info));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_ChangeServiceConfig2A(struct ndr_pull *ndr, int flags, struct svcctl_ChangeServiceConfig2A *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.info_level));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ } else {
+ r->in.info = NULL;
+ }
+ if (r->in.info) {
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, 0);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_ChangeServiceConfig2A(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_ChangeServiceConfig2A *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_ChangeServiceConfig2A");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_ChangeServiceConfig2A");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "info_level", r->in.info_level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ if (r->in.info) {
+ ndr_print_uint8(ndr, "info", *r->in.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_ChangeServiceConfig2A");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_ChangeServiceConfig2W(struct ndr_push *ndr, int flags, const struct svcctl_ChangeServiceConfig2W *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.info_level));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.info));
+ if (r->in.info) {
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, *r->in.info));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_ChangeServiceConfig2W(struct ndr_pull *ndr, int flags, struct svcctl_ChangeServiceConfig2W *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.info_level));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ } else {
+ r->in.info = NULL;
+ }
+ if (r->in.info) {
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, 0);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_ChangeServiceConfig2W(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_ChangeServiceConfig2W *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_ChangeServiceConfig2W");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_ChangeServiceConfig2W");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "info_level", r->in.info_level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ if (r->in.info) {
+ ndr_print_uint8(ndr, "info", *r->in.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_ChangeServiceConfig2W");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_QueryServiceConfig2A(struct ndr_push *ndr, int flags, const struct svcctl_QueryServiceConfig2A *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.info_level));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.buffer, r->in.buf_size));
+ if (r->out.bytes_needed == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.bytes_needed));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_QueryServiceConfig2A(struct ndr_pull *ndr, int flags, struct svcctl_QueryServiceConfig2A *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_bytes_needed_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.info_level));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ ZERO_STRUCTP(r->out.bytes_needed);
+ }
+ if (flags & NDR_OUT) {
+ NDR_PULL_ALLOC_N(ndr, r->out.buffer, r->in.buf_size);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.buffer, r->in.buf_size));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ }
+ _mem_save_bytes_needed_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.bytes_needed, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.bytes_needed));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bytes_needed_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_QueryServiceConfig2A(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceConfig2A *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_QueryServiceConfig2A");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_QueryServiceConfig2A");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "info_level", r->in.info_level);
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_QueryServiceConfig2A");
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "buffer", r->out.buffer, r->in.buf_size);
+ ndr_print_ptr(ndr, "bytes_needed", r->out.bytes_needed);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "bytes_needed", *r->out.bytes_needed);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_QueryServiceConfig2W(struct ndr_push *ndr, int flags, const struct svcctl_QueryServiceConfig2W *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.info_level));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.buffer, r->in.buf_size));
+ if (r->out.bytes_needed == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.bytes_needed));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_QueryServiceConfig2W(struct ndr_pull *ndr, int flags, struct svcctl_QueryServiceConfig2W *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_bytes_needed_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.info_level));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ ZERO_STRUCTP(r->out.bytes_needed);
+ }
+ if (flags & NDR_OUT) {
+ NDR_PULL_ALLOC_N(ndr, r->out.buffer, r->in.buf_size);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.buffer, r->in.buf_size));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ }
+ _mem_save_bytes_needed_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.bytes_needed, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.bytes_needed));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bytes_needed_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_QueryServiceConfig2W(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceConfig2W *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_QueryServiceConfig2W");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_QueryServiceConfig2W");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "info_level", r->in.info_level);
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_QueryServiceConfig2W");
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "buffer", r->out.buffer, r->in.buf_size);
+ ndr_print_ptr(ndr, "bytes_needed", r->out.bytes_needed);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "bytes_needed", *r->out.bytes_needed);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_QueryServiceStatusEx(struct ndr_push *ndr, int flags, const struct svcctl_QueryServiceStatusEx *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.info_level));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.buffer, r->in.buf_size));
+ if (r->out.bytes_needed == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.bytes_needed));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_QueryServiceStatusEx(struct ndr_pull *ndr, int flags, struct svcctl_QueryServiceStatusEx *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_bytes_needed_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.info_level));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ ZERO_STRUCTP(r->out.bytes_needed);
+ }
+ if (flags & NDR_OUT) {
+ NDR_PULL_ALLOC_N(ndr, r->out.buffer, r->in.buf_size);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.buffer, r->in.buf_size));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ }
+ _mem_save_bytes_needed_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.bytes_needed, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.bytes_needed));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bytes_needed_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_QueryServiceStatusEx(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceStatusEx *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_QueryServiceStatusEx");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_QueryServiceStatusEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "info_level", r->in.info_level);
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_QueryServiceStatusEx");
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "buffer", r->out.buffer, r->in.buf_size);
+ ndr_print_ptr(ndr, "bytes_needed", r->out.bytes_needed);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "bytes_needed", *r->out.bytes_needed);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_EnumServicesStatusExA(struct ndr_push *ndr, int flags, const struct EnumServicesStatusExA *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.scmanager == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.scmanager));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.info_level));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.state));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.resume_handle));
+ if (r->in.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.services, r->in.buf_size));
+ if (r->out.bytes_needed == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.bytes_needed));
+ if (r->out.service_returned == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.service_returned));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.resume_handle));
+ if (r->out.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ }
+ if (r->out.group_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.group_name));
+ if (*r->out.group_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.group_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.group_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, *r->out.group_name, ndr_charset_length(*r->out.group_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_EnumServicesStatusExA(struct ndr_pull *ndr, int flags, struct EnumServicesStatusExA *r)
+{
+ uint32_t _ptr_resume_handle;
+ uint32_t _ptr_group_name;
+ TALLOC_CTX *_mem_save_scmanager_0;
+ TALLOC_CTX *_mem_save_bytes_needed_0;
+ TALLOC_CTX *_mem_save_service_returned_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ TALLOC_CTX *_mem_save_group_name_0;
+ TALLOC_CTX *_mem_save_group_name_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.scmanager);
+ }
+ _mem_save_scmanager_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.scmanager, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.scmanager));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_scmanager_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.info_level));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.state));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ } else {
+ r->in.resume_handle = NULL;
+ }
+ if (r->in.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ ZERO_STRUCTP(r->out.bytes_needed);
+ NDR_PULL_ALLOC(ndr, r->out.service_returned);
+ ZERO_STRUCTP(r->out.service_returned);
+ NDR_PULL_ALLOC(ndr, r->out.group_name);
+ ZERO_STRUCTP(r->out.group_name);
+ }
+ if (flags & NDR_OUT) {
+ NDR_PULL_ALLOC_N(ndr, r->out.services, r->in.buf_size);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.services, r->in.buf_size));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ }
+ _mem_save_bytes_needed_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.bytes_needed, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.bytes_needed));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bytes_needed_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.service_returned);
+ }
+ _mem_save_service_returned_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.service_returned, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.service_returned));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_returned_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ } else {
+ r->out.resume_handle = NULL;
+ }
+ if (r->out.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.group_name);
+ }
+ _mem_save_group_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.group_name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_group_name));
+ if (_ptr_group_name) {
+ NDR_PULL_ALLOC(ndr, *r->out.group_name);
+ } else {
+ *r->out.group_name = NULL;
+ }
+ if (*r->out.group_name) {
+ _mem_save_group_name_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.group_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->out.group_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, r->out.group_name));
+ if (ndr_get_array_length(ndr, r->out.group_name) > ndr_get_array_size(ndr, r->out.group_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, r->out.group_name), ndr_get_array_length(ndr, r->out.group_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, r->out.group_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, r->out.group_name, ndr_get_array_length(ndr, r->out.group_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_name_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_EnumServicesStatusExA(struct ndr_print *ndr, const char *name, int flags, const struct EnumServicesStatusExA *r)
+{
+ ndr_print_struct(ndr, name, "EnumServicesStatusExA");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "EnumServicesStatusExA");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "scmanager", r->in.scmanager);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "scmanager", r->in.scmanager);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "info_level", r->in.info_level);
+ ndr_print_uint32(ndr, "type", r->in.type);
+ ndr_print_uint32(ndr, "state", r->in.state);
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ if (r->in.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "EnumServicesStatusExA");
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "services", r->out.services, r->in.buf_size);
+ ndr_print_ptr(ndr, "bytes_needed", r->out.bytes_needed);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "bytes_needed", *r->out.bytes_needed);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "service_returned", r->out.service_returned);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "service_returned", *r->out.service_returned);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ if (r->out.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "group_name", r->out.group_name);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "group_name", *r->out.group_name);
+ ndr->depth++;
+ if (*r->out.group_name) {
+ ndr_print_string(ndr, "group_name", *r->out.group_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_EnumServicesStatusExW(struct ndr_push *ndr, int flags, const struct EnumServicesStatusExW *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.scmanager == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.scmanager));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.info_level));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.state));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.buf_size));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.resume_handle));
+ if (r->in.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.services, r->in.buf_size));
+ if (r->out.bytes_needed == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.bytes_needed));
+ if (r->out.service_returned == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.service_returned));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.resume_handle));
+ if (r->out.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ }
+ if (r->out.group_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.group_name));
+ if (*r->out.group_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.group_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.group_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, *r->out.group_name, ndr_charset_length(*r->out.group_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_EnumServicesStatusExW(struct ndr_pull *ndr, int flags, struct EnumServicesStatusExW *r)
+{
+ uint32_t _ptr_resume_handle;
+ uint32_t _ptr_group_name;
+ TALLOC_CTX *_mem_save_scmanager_0;
+ TALLOC_CTX *_mem_save_bytes_needed_0;
+ TALLOC_CTX *_mem_save_service_returned_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ TALLOC_CTX *_mem_save_group_name_0;
+ TALLOC_CTX *_mem_save_group_name_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.scmanager);
+ }
+ _mem_save_scmanager_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.scmanager, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.scmanager));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_scmanager_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.info_level));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.state));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.buf_size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ } else {
+ r->in.resume_handle = NULL;
+ }
+ if (r->in.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ ZERO_STRUCTP(r->out.bytes_needed);
+ NDR_PULL_ALLOC(ndr, r->out.service_returned);
+ ZERO_STRUCTP(r->out.service_returned);
+ NDR_PULL_ALLOC(ndr, r->out.group_name);
+ ZERO_STRUCTP(r->out.group_name);
+ }
+ if (flags & NDR_OUT) {
+ NDR_PULL_ALLOC_N(ndr, r->out.services, r->in.buf_size);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.services, r->in.buf_size));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.bytes_needed);
+ }
+ _mem_save_bytes_needed_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.bytes_needed, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.bytes_needed));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_bytes_needed_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.service_returned);
+ }
+ _mem_save_service_returned_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.service_returned, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.service_returned));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_service_returned_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ } else {
+ r->out.resume_handle = NULL;
+ }
+ if (r->out.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.group_name);
+ }
+ _mem_save_group_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.group_name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_group_name));
+ if (_ptr_group_name) {
+ NDR_PULL_ALLOC(ndr, *r->out.group_name);
+ } else {
+ *r->out.group_name = NULL;
+ }
+ if (*r->out.group_name) {
+ _mem_save_group_name_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.group_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->out.group_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, r->out.group_name));
+ if (ndr_get_array_length(ndr, r->out.group_name) > ndr_get_array_size(ndr, r->out.group_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, r->out.group_name), ndr_get_array_length(ndr, r->out.group_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, r->out.group_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, r->out.group_name, ndr_get_array_length(ndr, r->out.group_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_name_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_EnumServicesStatusExW(struct ndr_print *ndr, const char *name, int flags, const struct EnumServicesStatusExW *r)
+{
+ ndr_print_struct(ndr, name, "EnumServicesStatusExW");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "EnumServicesStatusExW");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "scmanager", r->in.scmanager);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "scmanager", r->in.scmanager);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "info_level", r->in.info_level);
+ ndr_print_uint32(ndr, "type", r->in.type);
+ ndr_print_uint32(ndr, "state", r->in.state);
+ ndr_print_uint32(ndr, "buf_size", r->in.buf_size);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ if (r->in.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "EnumServicesStatusExW");
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "services", r->out.services, r->in.buf_size);
+ ndr_print_ptr(ndr, "bytes_needed", r->out.bytes_needed);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "bytes_needed", *r->out.bytes_needed);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "service_returned", r->out.service_returned);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "service_returned", *r->out.service_returned);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ if (r->out.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "group_name", r->out.group_name);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "group_name", *r->out.group_name);
+ ndr->depth++;
+ if (*r->out.group_name) {
+ ndr_print_string(ndr, "group_name", *r->out.group_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_svcctl_SCSendTSMessage(struct ndr_push *ndr, int flags, const struct svcctl_SCSendTSMessage *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_svcctl_SCSendTSMessage(struct ndr_pull *ndr, int flags, struct svcctl_SCSendTSMessage *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_svcctl_SCSendTSMessage(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_SCSendTSMessage *r)
+{
+ ndr_print_struct(ndr, name, "svcctl_SCSendTSMessage");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "svcctl_SCSendTSMessage");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "svcctl_SCSendTSMessage");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call svcctl_calls[] = {
+ {
+ "svcctl_CloseServiceHandle",
+ sizeof(struct svcctl_CloseServiceHandle),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_CloseServiceHandle,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_CloseServiceHandle,
+ (ndr_print_function_t) ndr_print_svcctl_CloseServiceHandle,
+ false,
+ },
+ {
+ "svcctl_ControlService",
+ sizeof(struct svcctl_ControlService),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_ControlService,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_ControlService,
+ (ndr_print_function_t) ndr_print_svcctl_ControlService,
+ false,
+ },
+ {
+ "svcctl_DeleteService",
+ sizeof(struct svcctl_DeleteService),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_DeleteService,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_DeleteService,
+ (ndr_print_function_t) ndr_print_svcctl_DeleteService,
+ false,
+ },
+ {
+ "svcctl_LockServiceDatabase",
+ sizeof(struct svcctl_LockServiceDatabase),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_LockServiceDatabase,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_LockServiceDatabase,
+ (ndr_print_function_t) ndr_print_svcctl_LockServiceDatabase,
+ false,
+ },
+ {
+ "svcctl_QueryServiceObjectSecurity",
+ sizeof(struct svcctl_QueryServiceObjectSecurity),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceObjectSecurity,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceObjectSecurity,
+ (ndr_print_function_t) ndr_print_svcctl_QueryServiceObjectSecurity,
+ false,
+ },
+ {
+ "svcctl_SetServiceObjectSecurity",
+ sizeof(struct svcctl_SetServiceObjectSecurity),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_SetServiceObjectSecurity,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_SetServiceObjectSecurity,
+ (ndr_print_function_t) ndr_print_svcctl_SetServiceObjectSecurity,
+ false,
+ },
+ {
+ "svcctl_QueryServiceStatus",
+ sizeof(struct svcctl_QueryServiceStatus),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceStatus,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceStatus,
+ (ndr_print_function_t) ndr_print_svcctl_QueryServiceStatus,
+ false,
+ },
+ {
+ "svcctl_SetServiceStatus",
+ sizeof(struct svcctl_SetServiceStatus),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_SetServiceStatus,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_SetServiceStatus,
+ (ndr_print_function_t) ndr_print_svcctl_SetServiceStatus,
+ false,
+ },
+ {
+ "svcctl_UnlockServiceDatabase",
+ sizeof(struct svcctl_UnlockServiceDatabase),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_UnlockServiceDatabase,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_UnlockServiceDatabase,
+ (ndr_print_function_t) ndr_print_svcctl_UnlockServiceDatabase,
+ false,
+ },
+ {
+ "svcctl_NotifyBootConfigStatus",
+ sizeof(struct svcctl_NotifyBootConfigStatus),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_NotifyBootConfigStatus,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_NotifyBootConfigStatus,
+ (ndr_print_function_t) ndr_print_svcctl_NotifyBootConfigStatus,
+ false,
+ },
+ {
+ "svcctl_SCSetServiceBitsW",
+ sizeof(struct svcctl_SCSetServiceBitsW),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_SCSetServiceBitsW,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_SCSetServiceBitsW,
+ (ndr_print_function_t) ndr_print_svcctl_SCSetServiceBitsW,
+ false,
+ },
+ {
+ "svcctl_ChangeServiceConfigW",
+ sizeof(struct svcctl_ChangeServiceConfigW),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_ChangeServiceConfigW,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_ChangeServiceConfigW,
+ (ndr_print_function_t) ndr_print_svcctl_ChangeServiceConfigW,
+ false,
+ },
+ {
+ "svcctl_CreateServiceW",
+ sizeof(struct svcctl_CreateServiceW),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_CreateServiceW,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_CreateServiceW,
+ (ndr_print_function_t) ndr_print_svcctl_CreateServiceW,
+ false,
+ },
+ {
+ "svcctl_EnumDependentServicesW",
+ sizeof(struct svcctl_EnumDependentServicesW),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_EnumDependentServicesW,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_EnumDependentServicesW,
+ (ndr_print_function_t) ndr_print_svcctl_EnumDependentServicesW,
+ false,
+ },
+ {
+ "svcctl_EnumServicesStatusW",
+ sizeof(struct svcctl_EnumServicesStatusW),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_EnumServicesStatusW,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_EnumServicesStatusW,
+ (ndr_print_function_t) ndr_print_svcctl_EnumServicesStatusW,
+ false,
+ },
+ {
+ "svcctl_OpenSCManagerW",
+ sizeof(struct svcctl_OpenSCManagerW),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_OpenSCManagerW,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_OpenSCManagerW,
+ (ndr_print_function_t) ndr_print_svcctl_OpenSCManagerW,
+ false,
+ },
+ {
+ "svcctl_OpenServiceW",
+ sizeof(struct svcctl_OpenServiceW),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_OpenServiceW,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_OpenServiceW,
+ (ndr_print_function_t) ndr_print_svcctl_OpenServiceW,
+ false,
+ },
+ {
+ "svcctl_QueryServiceConfigW",
+ sizeof(struct svcctl_QueryServiceConfigW),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceConfigW,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceConfigW,
+ (ndr_print_function_t) ndr_print_svcctl_QueryServiceConfigW,
+ false,
+ },
+ {
+ "svcctl_QueryServiceLockStatusW",
+ sizeof(struct svcctl_QueryServiceLockStatusW),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceLockStatusW,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceLockStatusW,
+ (ndr_print_function_t) ndr_print_svcctl_QueryServiceLockStatusW,
+ false,
+ },
+ {
+ "svcctl_StartServiceW",
+ sizeof(struct svcctl_StartServiceW),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_StartServiceW,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_StartServiceW,
+ (ndr_print_function_t) ndr_print_svcctl_StartServiceW,
+ false,
+ },
+ {
+ "svcctl_GetServiceDisplayNameW",
+ sizeof(struct svcctl_GetServiceDisplayNameW),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_GetServiceDisplayNameW,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_GetServiceDisplayNameW,
+ (ndr_print_function_t) ndr_print_svcctl_GetServiceDisplayNameW,
+ false,
+ },
+ {
+ "svcctl_GetServiceKeyNameW",
+ sizeof(struct svcctl_GetServiceKeyNameW),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_GetServiceKeyNameW,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_GetServiceKeyNameW,
+ (ndr_print_function_t) ndr_print_svcctl_GetServiceKeyNameW,
+ false,
+ },
+ {
+ "svcctl_SCSetServiceBitsA",
+ sizeof(struct svcctl_SCSetServiceBitsA),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_SCSetServiceBitsA,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_SCSetServiceBitsA,
+ (ndr_print_function_t) ndr_print_svcctl_SCSetServiceBitsA,
+ false,
+ },
+ {
+ "svcctl_ChangeServiceConfigA",
+ sizeof(struct svcctl_ChangeServiceConfigA),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_ChangeServiceConfigA,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_ChangeServiceConfigA,
+ (ndr_print_function_t) ndr_print_svcctl_ChangeServiceConfigA,
+ false,
+ },
+ {
+ "svcctl_CreateServiceA",
+ sizeof(struct svcctl_CreateServiceA),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_CreateServiceA,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_CreateServiceA,
+ (ndr_print_function_t) ndr_print_svcctl_CreateServiceA,
+ false,
+ },
+ {
+ "svcctl_EnumDependentServicesA",
+ sizeof(struct svcctl_EnumDependentServicesA),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_EnumDependentServicesA,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_EnumDependentServicesA,
+ (ndr_print_function_t) ndr_print_svcctl_EnumDependentServicesA,
+ false,
+ },
+ {
+ "svcctl_EnumServicesStatusA",
+ sizeof(struct svcctl_EnumServicesStatusA),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_EnumServicesStatusA,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_EnumServicesStatusA,
+ (ndr_print_function_t) ndr_print_svcctl_EnumServicesStatusA,
+ false,
+ },
+ {
+ "svcctl_OpenSCManagerA",
+ sizeof(struct svcctl_OpenSCManagerA),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_OpenSCManagerA,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_OpenSCManagerA,
+ (ndr_print_function_t) ndr_print_svcctl_OpenSCManagerA,
+ false,
+ },
+ {
+ "svcctl_OpenServiceA",
+ sizeof(struct svcctl_OpenServiceA),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_OpenServiceA,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_OpenServiceA,
+ (ndr_print_function_t) ndr_print_svcctl_OpenServiceA,
+ false,
+ },
+ {
+ "svcctl_QueryServiceConfigA",
+ sizeof(struct svcctl_QueryServiceConfigA),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceConfigA,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceConfigA,
+ (ndr_print_function_t) ndr_print_svcctl_QueryServiceConfigA,
+ false,
+ },
+ {
+ "svcctl_QueryServiceLockStatusA",
+ sizeof(struct svcctl_QueryServiceLockStatusA),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceLockStatusA,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceLockStatusA,
+ (ndr_print_function_t) ndr_print_svcctl_QueryServiceLockStatusA,
+ false,
+ },
+ {
+ "svcctl_StartServiceA",
+ sizeof(struct svcctl_StartServiceA),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_StartServiceA,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_StartServiceA,
+ (ndr_print_function_t) ndr_print_svcctl_StartServiceA,
+ false,
+ },
+ {
+ "svcctl_GetServiceDisplayNameA",
+ sizeof(struct svcctl_GetServiceDisplayNameA),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_GetServiceDisplayNameA,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_GetServiceDisplayNameA,
+ (ndr_print_function_t) ndr_print_svcctl_GetServiceDisplayNameA,
+ false,
+ },
+ {
+ "svcctl_GetServiceKeyNameA",
+ sizeof(struct svcctl_GetServiceKeyNameA),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_GetServiceKeyNameA,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_GetServiceKeyNameA,
+ (ndr_print_function_t) ndr_print_svcctl_GetServiceKeyNameA,
+ false,
+ },
+ {
+ "svcctl_GetCurrentGroupeStateW",
+ sizeof(struct svcctl_GetCurrentGroupeStateW),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_GetCurrentGroupeStateW,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_GetCurrentGroupeStateW,
+ (ndr_print_function_t) ndr_print_svcctl_GetCurrentGroupeStateW,
+ false,
+ },
+ {
+ "svcctl_EnumServiceGroupW",
+ sizeof(struct svcctl_EnumServiceGroupW),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_EnumServiceGroupW,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_EnumServiceGroupW,
+ (ndr_print_function_t) ndr_print_svcctl_EnumServiceGroupW,
+ false,
+ },
+ {
+ "svcctl_ChangeServiceConfig2A",
+ sizeof(struct svcctl_ChangeServiceConfig2A),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_ChangeServiceConfig2A,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_ChangeServiceConfig2A,
+ (ndr_print_function_t) ndr_print_svcctl_ChangeServiceConfig2A,
+ false,
+ },
+ {
+ "svcctl_ChangeServiceConfig2W",
+ sizeof(struct svcctl_ChangeServiceConfig2W),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_ChangeServiceConfig2W,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_ChangeServiceConfig2W,
+ (ndr_print_function_t) ndr_print_svcctl_ChangeServiceConfig2W,
+ false,
+ },
+ {
+ "svcctl_QueryServiceConfig2A",
+ sizeof(struct svcctl_QueryServiceConfig2A),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceConfig2A,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceConfig2A,
+ (ndr_print_function_t) ndr_print_svcctl_QueryServiceConfig2A,
+ false,
+ },
+ {
+ "svcctl_QueryServiceConfig2W",
+ sizeof(struct svcctl_QueryServiceConfig2W),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceConfig2W,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceConfig2W,
+ (ndr_print_function_t) ndr_print_svcctl_QueryServiceConfig2W,
+ false,
+ },
+ {
+ "svcctl_QueryServiceStatusEx",
+ sizeof(struct svcctl_QueryServiceStatusEx),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceStatusEx,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceStatusEx,
+ (ndr_print_function_t) ndr_print_svcctl_QueryServiceStatusEx,
+ false,
+ },
+ {
+ "EnumServicesStatusExA",
+ sizeof(struct EnumServicesStatusExA),
+ (ndr_push_flags_fn_t) ndr_push_EnumServicesStatusExA,
+ (ndr_pull_flags_fn_t) ndr_pull_EnumServicesStatusExA,
+ (ndr_print_function_t) ndr_print_EnumServicesStatusExA,
+ false,
+ },
+ {
+ "EnumServicesStatusExW",
+ sizeof(struct EnumServicesStatusExW),
+ (ndr_push_flags_fn_t) ndr_push_EnumServicesStatusExW,
+ (ndr_pull_flags_fn_t) ndr_pull_EnumServicesStatusExW,
+ (ndr_print_function_t) ndr_print_EnumServicesStatusExW,
+ false,
+ },
+ {
+ "svcctl_SCSendTSMessage",
+ sizeof(struct svcctl_SCSendTSMessage),
+ (ndr_push_flags_fn_t) ndr_push_svcctl_SCSendTSMessage,
+ (ndr_pull_flags_fn_t) ndr_pull_svcctl_SCSendTSMessage,
+ (ndr_print_function_t) ndr_print_svcctl_SCSendTSMessage,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const svcctl_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\svcctl]",
+ "ncalrpc:",
+};
+
+static const struct ndr_interface_string_array svcctl_endpoints = {
+ .count = 2,
+ .names = svcctl_endpoint_strings
+};
+
+static const char * const svcctl_authservice_strings[] = {
+ "host",
+};
+
+static const struct ndr_interface_string_array svcctl_authservices = {
+ .count = 1,
+ .names = svcctl_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_svcctl = {
+ .name = "svcctl",
+ .syntax_id = {
+ {0x367abb81,0x9844,0x35f1,{0xad,0x32},{0x98,0xf0,0x38,0x00,0x10,0x03}},
+ NDR_SVCCTL_VERSION
+ },
+ .helpstring = NDR_SVCCTL_HELPSTRING,
+ .num_calls = 44,
+ .calls = svcctl_calls,
+ .endpoints = &svcctl_endpoints,
+ .authservices = &svcctl_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_svcctl.h b/source3/librpc/gen_ndr/ndr_svcctl.h
new file mode 100644
index 0000000000..4475b08792
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_svcctl.h
@@ -0,0 +1,155 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/svcctl.h"
+
+#ifndef _HEADER_NDR_svcctl
+#define _HEADER_NDR_svcctl
+
+#define NDR_SVCCTL_UUID "367abb81-9844-35f1-ad32-98f038001003"
+#define NDR_SVCCTL_VERSION 2.0
+#define NDR_SVCCTL_NAME "svcctl"
+#define NDR_SVCCTL_HELPSTRING "Service Control"
+extern const struct ndr_interface_table ndr_table_svcctl;
+#define NDR_SVCCTL_CLOSESERVICEHANDLE (0x00)
+
+#define NDR_SVCCTL_CONTROLSERVICE (0x01)
+
+#define NDR_SVCCTL_DELETESERVICE (0x02)
+
+#define NDR_SVCCTL_LOCKSERVICEDATABASE (0x03)
+
+#define NDR_SVCCTL_QUERYSERVICEOBJECTSECURITY (0x04)
+
+#define NDR_SVCCTL_SETSERVICEOBJECTSECURITY (0x05)
+
+#define NDR_SVCCTL_QUERYSERVICESTATUS (0x06)
+
+#define NDR_SVCCTL_SETSERVICESTATUS (0x07)
+
+#define NDR_SVCCTL_UNLOCKSERVICEDATABASE (0x08)
+
+#define NDR_SVCCTL_NOTIFYBOOTCONFIGSTATUS (0x09)
+
+#define NDR_SVCCTL_SCSETSERVICEBITSW (0x0a)
+
+#define NDR_SVCCTL_CHANGESERVICECONFIGW (0x0b)
+
+#define NDR_SVCCTL_CREATESERVICEW (0x0c)
+
+#define NDR_SVCCTL_ENUMDEPENDENTSERVICESW (0x0d)
+
+#define NDR_SVCCTL_ENUMSERVICESSTATUSW (0x0e)
+
+#define NDR_SVCCTL_OPENSCMANAGERW (0x0f)
+
+#define NDR_SVCCTL_OPENSERVICEW (0x10)
+
+#define NDR_SVCCTL_QUERYSERVICECONFIGW (0x11)
+
+#define NDR_SVCCTL_QUERYSERVICELOCKSTATUSW (0x12)
+
+#define NDR_SVCCTL_STARTSERVICEW (0x13)
+
+#define NDR_SVCCTL_GETSERVICEDISPLAYNAMEW (0x14)
+
+#define NDR_SVCCTL_GETSERVICEKEYNAMEW (0x15)
+
+#define NDR_SVCCTL_SCSETSERVICEBITSA (0x16)
+
+#define NDR_SVCCTL_CHANGESERVICECONFIGA (0x17)
+
+#define NDR_SVCCTL_CREATESERVICEA (0x18)
+
+#define NDR_SVCCTL_ENUMDEPENDENTSERVICESA (0x19)
+
+#define NDR_SVCCTL_ENUMSERVICESSTATUSA (0x1a)
+
+#define NDR_SVCCTL_OPENSCMANAGERA (0x1b)
+
+#define NDR_SVCCTL_OPENSERVICEA (0x1c)
+
+#define NDR_SVCCTL_QUERYSERVICECONFIGA (0x1d)
+
+#define NDR_SVCCTL_QUERYSERVICELOCKSTATUSA (0x1e)
+
+#define NDR_SVCCTL_STARTSERVICEA (0x1f)
+
+#define NDR_SVCCTL_GETSERVICEDISPLAYNAMEA (0x20)
+
+#define NDR_SVCCTL_GETSERVICEKEYNAMEA (0x21)
+
+#define NDR_SVCCTL_GETCURRENTGROUPESTATEW (0x22)
+
+#define NDR_SVCCTL_ENUMSERVICEGROUPW (0x23)
+
+#define NDR_SVCCTL_CHANGESERVICECONFIG2A (0x24)
+
+#define NDR_SVCCTL_CHANGESERVICECONFIG2W (0x25)
+
+#define NDR_SVCCTL_QUERYSERVICECONFIG2A (0x26)
+
+#define NDR_SVCCTL_QUERYSERVICECONFIG2W (0x27)
+
+#define NDR_SVCCTL_QUERYSERVICESTATUSEX (0x28)
+
+#define NDR_ENUMSERVICESSTATUSEXA (0x29)
+
+#define NDR_ENUMSERVICESSTATUSEXW (0x2a)
+
+#define NDR_SVCCTL_SCSENDTSMESSAGE (0x2b)
+
+#define NDR_SVCCTL_CALL_COUNT (44)
+void ndr_print_SERVICE_LOCK_STATUS(struct ndr_print *ndr, const char *name, const struct SERVICE_LOCK_STATUS *r);
+void ndr_print_SERVICE_STATUS(struct ndr_print *ndr, const char *name, const struct SERVICE_STATUS *r);
+void ndr_print_ENUM_SERVICE_STATUS(struct ndr_print *ndr, const char *name, const struct ENUM_SERVICE_STATUS *r);
+enum ndr_err_code ndr_push_svcctl_ServerType(struct ndr_push *ndr, int ndr_flags, uint32_t r);
+enum ndr_err_code ndr_pull_svcctl_ServerType(struct ndr_pull *ndr, int ndr_flags, uint32_t *r);
+void ndr_print_svcctl_ServerType(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_svcctl_MgrAccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_svcctl_ServiceAccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_svcctl_CloseServiceHandle(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_CloseServiceHandle *r);
+void ndr_print_svcctl_ControlService(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_ControlService *r);
+void ndr_print_svcctl_DeleteService(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_DeleteService *r);
+void ndr_print_svcctl_LockServiceDatabase(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_LockServiceDatabase *r);
+void ndr_print_svcctl_QueryServiceObjectSecurity(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceObjectSecurity *r);
+void ndr_print_svcctl_SetServiceObjectSecurity(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_SetServiceObjectSecurity *r);
+void ndr_print_svcctl_QueryServiceStatus(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceStatus *r);
+void ndr_print_svcctl_SetServiceStatus(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_SetServiceStatus *r);
+void ndr_print_svcctl_UnlockServiceDatabase(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_UnlockServiceDatabase *r);
+void ndr_print_svcctl_NotifyBootConfigStatus(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_NotifyBootConfigStatus *r);
+void ndr_print_svcctl_SCSetServiceBitsW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_SCSetServiceBitsW *r);
+void ndr_print_svcctl_ChangeServiceConfigW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_ChangeServiceConfigW *r);
+void ndr_print_svcctl_CreateServiceW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_CreateServiceW *r);
+void ndr_print_svcctl_EnumDependentServicesW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_EnumDependentServicesW *r);
+void ndr_print_svcctl_EnumServicesStatusW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_EnumServicesStatusW *r);
+void ndr_print_svcctl_OpenSCManagerW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_OpenSCManagerW *r);
+void ndr_print_svcctl_OpenServiceW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_OpenServiceW *r);
+void ndr_print_svcctl_QueryServiceConfigW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceConfigW *r);
+void ndr_print_svcctl_QueryServiceLockStatusW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceLockStatusW *r);
+void ndr_print_svcctl_StartServiceW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_StartServiceW *r);
+void ndr_print_svcctl_GetServiceDisplayNameW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_GetServiceDisplayNameW *r);
+void ndr_print_svcctl_GetServiceKeyNameW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_GetServiceKeyNameW *r);
+void ndr_print_svcctl_SCSetServiceBitsA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_SCSetServiceBitsA *r);
+void ndr_print_svcctl_ChangeServiceConfigA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_ChangeServiceConfigA *r);
+void ndr_print_svcctl_CreateServiceA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_CreateServiceA *r);
+void ndr_print_svcctl_EnumDependentServicesA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_EnumDependentServicesA *r);
+void ndr_print_svcctl_EnumServicesStatusA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_EnumServicesStatusA *r);
+void ndr_print_svcctl_OpenSCManagerA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_OpenSCManagerA *r);
+void ndr_print_svcctl_OpenServiceA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_OpenServiceA *r);
+void ndr_print_svcctl_QueryServiceConfigA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceConfigA *r);
+void ndr_print_svcctl_QueryServiceLockStatusA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceLockStatusA *r);
+void ndr_print_svcctl_StartServiceA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_StartServiceA *r);
+void ndr_print_svcctl_GetServiceDisplayNameA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_GetServiceDisplayNameA *r);
+void ndr_print_svcctl_GetServiceKeyNameA(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_GetServiceKeyNameA *r);
+void ndr_print_svcctl_GetCurrentGroupeStateW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_GetCurrentGroupeStateW *r);
+void ndr_print_svcctl_EnumServiceGroupW(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_EnumServiceGroupW *r);
+void ndr_print_svcctl_ChangeServiceConfig2A(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_ChangeServiceConfig2A *r);
+void ndr_print_svcctl_ChangeServiceConfig2W(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_ChangeServiceConfig2W *r);
+void ndr_print_svcctl_QueryServiceConfig2A(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceConfig2A *r);
+void ndr_print_svcctl_QueryServiceConfig2W(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceConfig2W *r);
+void ndr_print_svcctl_QueryServiceStatusEx(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_QueryServiceStatusEx *r);
+void ndr_print_EnumServicesStatusExA(struct ndr_print *ndr, const char *name, int flags, const struct EnumServicesStatusExA *r);
+void ndr_print_EnumServicesStatusExW(struct ndr_print *ndr, const char *name, int flags, const struct EnumServicesStatusExW *r);
+void ndr_print_svcctl_SCSendTSMessage(struct ndr_print *ndr, const char *name, int flags, const struct svcctl_SCSendTSMessage *r);
+#endif /* _HEADER_NDR_svcctl */
diff --git a/source3/librpc/gen_ndr/ndr_winreg.c b/source3/librpc/gen_ndr/ndr_winreg.c
new file mode 100644
index 0000000000..053e155616
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_winreg.c
@@ -0,0 +1,4542 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_winreg.h"
+
+#include "librpc/gen_ndr/ndr_lsa.h"
+#include "librpc/gen_ndr/ndr_initshutdown.h"
+#include "librpc/gen_ndr/ndr_security.h"
+static enum ndr_err_code ndr_push_winreg_AccessMask(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_AccessMask(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_AccessMask(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "KEY_QUERY_VALUE", KEY_QUERY_VALUE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "KEY_SET_VALUE", KEY_SET_VALUE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "KEY_CREATE_SUB_KEY", KEY_CREATE_SUB_KEY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "KEY_ENUMERATE_SUB_KEYS", KEY_ENUMERATE_SUB_KEYS, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "KEY_NOTIFY", KEY_NOTIFY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "KEY_CREATE_LINK", KEY_CREATE_LINK, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "KEY_WOW64_64KEY", KEY_WOW64_64KEY, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "KEY_WOW64_32KEY", KEY_WOW64_32KEY, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_Type(struct ndr_push *ndr, int ndr_flags, enum winreg_Type r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_Type(struct ndr_pull *ndr, int ndr_flags, enum winreg_Type *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_Type(struct ndr_print *ndr, const char *name, enum winreg_Type r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case REG_NONE: val = "REG_NONE"; break;
+ case REG_SZ: val = "REG_SZ"; break;
+ case REG_EXPAND_SZ: val = "REG_EXPAND_SZ"; break;
+ case REG_BINARY: val = "REG_BINARY"; break;
+ case REG_DWORD: val = "REG_DWORD"; break;
+ case REG_DWORD_BIG_ENDIAN: val = "REG_DWORD_BIG_ENDIAN"; break;
+ case REG_LINK: val = "REG_LINK"; break;
+ case REG_MULTI_SZ: val = "REG_MULTI_SZ"; break;
+ case REG_RESOURCE_LIST: val = "REG_RESOURCE_LIST"; break;
+ case REG_FULL_RESOURCE_DESCRIPTOR: val = "REG_FULL_RESOURCE_DESCRIPTOR"; break;
+ case REG_RESOURCE_REQUIREMENTS_LIST: val = "REG_RESOURCE_REQUIREMENTS_LIST"; break;
+ case REG_QWORD: val = "REG_QWORD"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_winreg_String(struct ndr_push *ndr, int ndr_flags, const struct winreg_String *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, strlen_m_term(r->name) * 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, strlen_m_term(r->name) * 2));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, ndr_charset_length(r->name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_winreg_String(struct ndr_pull *ndr, int ndr_flags, struct winreg_String *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->name_len));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->name_size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->name));
+ if (ndr_get_array_length(ndr, &r->name) > ndr_get_array_size(ndr, &r->name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->name), ndr_get_array_length(ndr, &r->name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_String(struct ndr_print *ndr, const char *name, const struct winreg_String *r)
+{
+ ndr_print_struct(ndr, name, "winreg_String");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "name_len", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen_m_term(r->name) * 2:r->name_len);
+ ndr_print_uint16(ndr, "name_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen_m_term(r->name) * 2:r->name_size);
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_string(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_KeySecurityData(struct ndr_push *ndr, int ndr_flags, const struct KeySecurityData *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->data));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->len));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->len));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data, r->len));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_KeySecurityData(struct ndr_pull *ndr, int ndr_flags, struct KeySecurityData *r)
+{
+ uint32_t _ptr_data;
+ TALLOC_CTX *_mem_save_data_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data));
+ if (_ptr_data) {
+ NDR_PULL_ALLOC(ndr, r->data);
+ } else {
+ r->data = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->len));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->data) {
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->data, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->data));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->data));
+ if (ndr_get_array_length(ndr, &r->data) > ndr_get_array_size(ndr, &r->data)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->data), ndr_get_array_length(ndr, &r->data));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->data, ndr_get_array_size(ndr, &r->data));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data, ndr_get_array_length(ndr, &r->data)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, 0);
+ }
+ if (r->data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->data, r->size));
+ }
+ if (r->data) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->data, r->len));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_KeySecurityData(struct ndr_print *ndr, const char *name, const struct KeySecurityData *r)
+{
+ ndr_print_struct(ndr, name, "KeySecurityData");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "data", r->data);
+ ndr->depth++;
+ if (r->data) {
+ ndr_print_array_uint8(ndr, "data", r->data, r->len);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "size", r->size);
+ ndr_print_uint32(ndr, "len", r->len);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_SecBuf(struct ndr_push *ndr, int ndr_flags, const struct winreg_SecBuf *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length));
+ NDR_CHECK(ndr_push_KeySecurityData(ndr, NDR_SCALARS, &r->sd));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->inherit));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_KeySecurityData(ndr, NDR_BUFFERS, &r->sd));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_SecBuf(struct ndr_pull *ndr, int ndr_flags, struct winreg_SecBuf *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_KeySecurityData(ndr, NDR_SCALARS, &r->sd));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->inherit));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_KeySecurityData(ndr, NDR_BUFFERS, &r->sd));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_SecBuf(struct ndr_print *ndr, const char *name, const struct winreg_SecBuf *r)
+{
+ ndr_print_struct(ndr, name, "winreg_SecBuf");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "length", r->length);
+ ndr_print_KeySecurityData(ndr, "sd", &r->sd);
+ ndr_print_uint8(ndr, "inherit", r->inherit);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_CreateAction(struct ndr_push *ndr, int ndr_flags, enum winreg_CreateAction r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_CreateAction(struct ndr_pull *ndr, int ndr_flags, enum winreg_CreateAction *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_CreateAction(struct ndr_print *ndr, const char *name, enum winreg_CreateAction r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case REG_ACTION_NONE: val = "REG_ACTION_NONE"; break;
+ case REG_CREATED_NEW_KEY: val = "REG_CREATED_NEW_KEY"; break;
+ case REG_OPENED_EXISTING_KEY: val = "REG_OPENED_EXISTING_KEY"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_winreg_StringBuf(struct ndr_push *ndr, int ndr_flags, const struct winreg_StringBuf *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, strlen_m_term_null(r->name) * 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->size));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size / 2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, strlen_m_term_null(r->name) * 2 / 2));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, strlen_m_term_null(r->name) * 2 / 2, sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_StringBuf(struct ndr_pull *ndr, int ndr_flags, struct winreg_StringBuf *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->name));
+ if (ndr_get_array_length(ndr, &r->name) > ndr_get_array_size(ndr, &r->name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->name), ndr_get_array_length(ndr, &r->name));
+ }
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ if (r->name) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->name, r->size / 2));
+ }
+ if (r->name) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->name, r->length / 2));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_StringBuf(struct ndr_print *ndr, const char *name, const struct winreg_StringBuf *r)
+{
+ ndr_print_struct(ndr, name, "winreg_StringBuf");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "length", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen_m_term_null(r->name) * 2:r->length);
+ ndr_print_uint16(ndr, "size", r->size);
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_string(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_ValNameBuf(struct ndr_push *ndr, int ndr_flags, const struct winreg_ValNameBuf *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, strlen_m_term(r->name) * 2));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->size));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size / 2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, strlen_m_term(r->name) * 2 / 2));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, strlen_m_term(r->name) * 2 / 2, sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_ValNameBuf(struct ndr_pull *ndr, int ndr_flags, struct winreg_ValNameBuf *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->name));
+ if (ndr_get_array_length(ndr, &r->name) > ndr_get_array_size(ndr, &r->name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->name), ndr_get_array_length(ndr, &r->name));
+ }
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ if (r->name) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->name, r->size / 2));
+ }
+ if (r->name) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->name, r->length / 2));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_ValNameBuf(struct ndr_print *ndr, const char *name, const struct winreg_ValNameBuf *r)
+{
+ ndr_print_struct(ndr, name, "winreg_ValNameBuf");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "length", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?strlen_m_term(r->name) * 2:r->length);
+ ndr_print_uint16(ndr, "size", r->size);
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_string(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_KeySecurityAttribute(struct ndr_push *ndr, int ndr_flags, const struct KeySecurityAttribute *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->data_size));
+ NDR_CHECK(ndr_push_KeySecurityData(ndr, NDR_SCALARS, &r->sec_data));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->inherit));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_KeySecurityData(ndr, NDR_BUFFERS, &r->sec_data));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_KeySecurityAttribute(struct ndr_pull *ndr, int ndr_flags, struct KeySecurityAttribute *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->data_size));
+ NDR_CHECK(ndr_pull_KeySecurityData(ndr, NDR_SCALARS, &r->sec_data));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->inherit));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_KeySecurityData(ndr, NDR_BUFFERS, &r->sec_data));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_KeySecurityAttribute(struct ndr_print *ndr, const char *name, const struct KeySecurityAttribute *r)
+{
+ ndr_print_struct(ndr, name, "KeySecurityAttribute");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "data_size", r->data_size);
+ ndr_print_KeySecurityData(ndr, "sec_data", &r->sec_data);
+ ndr_print_uint8(ndr, "inherit", r->inherit);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_QueryMultipleValue(struct ndr_push *ndr, int ndr_flags, const struct QueryMultipleValue *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ NDR_CHECK(ndr_push_winreg_Type(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->offset));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->length));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ NDR_CHECK(ndr_push_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->name));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_QueryMultipleValue(struct ndr_pull *ndr, int ndr_flags, struct QueryMultipleValue *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ NDR_CHECK(ndr_pull_winreg_Type(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->offset));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->length));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_QueryMultipleValue(struct ndr_print *ndr, const char *name, const struct QueryMultipleValue *r)
+{
+ ndr_print_struct(ndr, name, "QueryMultipleValue");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_winreg_String(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ ndr_print_winreg_Type(ndr, "type", r->type);
+ ndr_print_uint32(ndr, "offset", r->offset);
+ ndr_print_uint32(ndr, "length", r->length);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_OpenHKCR(struct ndr_push *ndr, int flags, const struct winreg_OpenHKCR *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.system_name));
+ }
+ NDR_CHECK(ndr_push_winreg_AccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_OpenHKCR(struct ndr_pull *ndr, int flags, struct winreg_OpenHKCR *r)
+{
+ uint32_t _ptr_system_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.system_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_winreg_AccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_OpenHKCR(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKCR *r)
+{
+ ndr_print_struct(ndr, name, "winreg_OpenHKCR");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_OpenHKCR");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_uint16(ndr, "system_name", *r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_winreg_AccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_OpenHKCR");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_OpenHKCU(struct ndr_push *ndr, int flags, const struct winreg_OpenHKCU *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.system_name));
+ }
+ NDR_CHECK(ndr_push_winreg_AccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_OpenHKCU(struct ndr_pull *ndr, int flags, struct winreg_OpenHKCU *r)
+{
+ uint32_t _ptr_system_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.system_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_winreg_AccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_OpenHKCU(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKCU *r)
+{
+ ndr_print_struct(ndr, name, "winreg_OpenHKCU");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_OpenHKCU");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_uint16(ndr, "system_name", *r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_winreg_AccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_OpenHKCU");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_OpenHKLM(struct ndr_push *ndr, int flags, const struct winreg_OpenHKLM *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.system_name));
+ }
+ NDR_CHECK(ndr_push_winreg_AccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_OpenHKLM(struct ndr_pull *ndr, int flags, struct winreg_OpenHKLM *r)
+{
+ uint32_t _ptr_system_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.system_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_winreg_AccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_OpenHKLM(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKLM *r)
+{
+ ndr_print_struct(ndr, name, "winreg_OpenHKLM");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_OpenHKLM");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_uint16(ndr, "system_name", *r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_winreg_AccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_OpenHKLM");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_OpenHKPD(struct ndr_push *ndr, int flags, const struct winreg_OpenHKPD *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.system_name));
+ }
+ NDR_CHECK(ndr_push_winreg_AccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_OpenHKPD(struct ndr_pull *ndr, int flags, struct winreg_OpenHKPD *r)
+{
+ uint32_t _ptr_system_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.system_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_winreg_AccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_OpenHKPD(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKPD *r)
+{
+ ndr_print_struct(ndr, name, "winreg_OpenHKPD");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_OpenHKPD");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_uint16(ndr, "system_name", *r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_winreg_AccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_OpenHKPD");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_OpenHKU(struct ndr_push *ndr, int flags, const struct winreg_OpenHKU *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.system_name));
+ }
+ NDR_CHECK(ndr_push_winreg_AccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_OpenHKU(struct ndr_pull *ndr, int flags, struct winreg_OpenHKU *r)
+{
+ uint32_t _ptr_system_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.system_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_winreg_AccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_OpenHKU(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKU *r)
+{
+ ndr_print_struct(ndr, name, "winreg_OpenHKU");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_OpenHKU");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_uint16(ndr, "system_name", *r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_winreg_AccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_OpenHKU");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_CloseKey(struct ndr_push *ndr, int flags, const struct winreg_CloseKey *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_CloseKey(struct ndr_pull *ndr, int flags, struct winreg_CloseKey *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ *r->out.handle = *r->in.handle;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_CloseKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_CloseKey *r)
+{
+ ndr_print_struct(ndr, name, "winreg_CloseKey");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_CloseKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_CloseKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_CreateKey(struct ndr_push *ndr, int flags, const struct winreg_CreateKey *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.name));
+ NDR_CHECK(ndr_push_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.keyclass));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.options));
+ NDR_CHECK(ndr_push_winreg_AccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.secdesc));
+ if (r->in.secdesc) {
+ NDR_CHECK(ndr_push_winreg_SecBuf(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.secdesc));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.action_taken));
+ if (r->in.action_taken) {
+ NDR_CHECK(ndr_push_winreg_CreateAction(ndr, NDR_SCALARS, *r->in.action_taken));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.new_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.new_handle));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.action_taken));
+ if (r->out.action_taken) {
+ NDR_CHECK(ndr_push_winreg_CreateAction(ndr, NDR_SCALARS, *r->out.action_taken));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_CreateKey(struct ndr_pull *ndr, int flags, struct winreg_CreateKey *r)
+{
+ uint32_t _ptr_secdesc;
+ uint32_t _ptr_action_taken;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_secdesc_0;
+ TALLOC_CTX *_mem_save_new_handle_0;
+ TALLOC_CTX *_mem_save_action_taken_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.name));
+ NDR_CHECK(ndr_pull_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.keyclass));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.options));
+ NDR_CHECK(ndr_pull_winreg_AccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_secdesc));
+ if (_ptr_secdesc) {
+ NDR_PULL_ALLOC(ndr, r->in.secdesc);
+ } else {
+ r->in.secdesc = NULL;
+ }
+ if (r->in.secdesc) {
+ _mem_save_secdesc_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.secdesc, 0);
+ NDR_CHECK(ndr_pull_winreg_SecBuf(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.secdesc));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_secdesc_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_action_taken));
+ if (_ptr_action_taken) {
+ NDR_PULL_ALLOC(ndr, r->in.action_taken);
+ } else {
+ r->in.action_taken = NULL;
+ }
+ if (r->in.action_taken) {
+ _mem_save_action_taken_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.action_taken, 0);
+ NDR_CHECK(ndr_pull_winreg_CreateAction(ndr, NDR_SCALARS, r->in.action_taken));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_action_taken_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.new_handle);
+ ZERO_STRUCTP(r->out.new_handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.new_handle);
+ }
+ _mem_save_new_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.new_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.new_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_new_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_action_taken));
+ if (_ptr_action_taken) {
+ NDR_PULL_ALLOC(ndr, r->out.action_taken);
+ } else {
+ r->out.action_taken = NULL;
+ }
+ if (r->out.action_taken) {
+ _mem_save_action_taken_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.action_taken, 0);
+ NDR_CHECK(ndr_pull_winreg_CreateAction(ndr, NDR_SCALARS, r->out.action_taken));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_action_taken_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_CreateKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_CreateKey *r)
+{
+ ndr_print_struct(ndr, name, "winreg_CreateKey");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_CreateKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_winreg_String(ndr, "name", &r->in.name);
+ ndr_print_winreg_String(ndr, "keyclass", &r->in.keyclass);
+ ndr_print_uint32(ndr, "options", r->in.options);
+ ndr_print_winreg_AccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr_print_ptr(ndr, "secdesc", r->in.secdesc);
+ ndr->depth++;
+ if (r->in.secdesc) {
+ ndr_print_winreg_SecBuf(ndr, "secdesc", r->in.secdesc);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "action_taken", r->in.action_taken);
+ ndr->depth++;
+ if (r->in.action_taken) {
+ ndr_print_winreg_CreateAction(ndr, "action_taken", *r->in.action_taken);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_CreateKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "new_handle", r->out.new_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "new_handle", r->out.new_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "action_taken", r->out.action_taken);
+ ndr->depth++;
+ if (r->out.action_taken) {
+ ndr_print_winreg_CreateAction(ndr, "action_taken", *r->out.action_taken);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_DeleteKey(struct ndr_push *ndr, int flags, const struct winreg_DeleteKey *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.key));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_DeleteKey(struct ndr_pull *ndr, int flags, struct winreg_DeleteKey *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.key));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_DeleteKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_DeleteKey *r)
+{
+ ndr_print_struct(ndr, name, "winreg_DeleteKey");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_DeleteKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_winreg_String(ndr, "key", &r->in.key);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_DeleteKey");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_DeleteValue(struct ndr_push *ndr, int flags, const struct winreg_DeleteValue *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.value));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_DeleteValue(struct ndr_pull *ndr, int flags, struct winreg_DeleteValue *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.value));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_DeleteValue(struct ndr_print *ndr, const char *name, int flags, const struct winreg_DeleteValue *r)
+{
+ ndr_print_struct(ndr, name, "winreg_DeleteValue");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_DeleteValue");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_winreg_String(ndr, "value", &r->in.value);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_DeleteValue");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_EnumKey(struct ndr_push *ndr, int flags, const struct winreg_EnumKey *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.enum_index));
+ if (r->in.name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_winreg_StringBuf(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.keyclass));
+ if (r->in.keyclass) {
+ NDR_CHECK(ndr_push_winreg_StringBuf(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.keyclass));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.last_changed_time));
+ if (r->in.last_changed_time) {
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, *r->in.last_changed_time));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_winreg_StringBuf(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.keyclass));
+ if (r->out.keyclass) {
+ NDR_CHECK(ndr_push_winreg_StringBuf(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.keyclass));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.last_changed_time));
+ if (r->out.last_changed_time) {
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, *r->out.last_changed_time));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_EnumKey(struct ndr_pull *ndr, int flags, struct winreg_EnumKey *r)
+{
+ uint32_t _ptr_keyclass;
+ uint32_t _ptr_last_changed_time;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_name_0;
+ TALLOC_CTX *_mem_save_keyclass_0;
+ TALLOC_CTX *_mem_save_last_changed_time_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.enum_index));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.name);
+ }
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_winreg_StringBuf(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_keyclass));
+ if (_ptr_keyclass) {
+ NDR_PULL_ALLOC(ndr, r->in.keyclass);
+ } else {
+ r->in.keyclass = NULL;
+ }
+ if (r->in.keyclass) {
+ _mem_save_keyclass_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.keyclass, 0);
+ NDR_CHECK(ndr_pull_winreg_StringBuf(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.keyclass));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_keyclass_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_last_changed_time));
+ if (_ptr_last_changed_time) {
+ NDR_PULL_ALLOC(ndr, r->in.last_changed_time);
+ } else {
+ r->in.last_changed_time = NULL;
+ }
+ if (r->in.last_changed_time) {
+ _mem_save_last_changed_time_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.last_changed_time, 0);
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, r->in.last_changed_time));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_last_changed_time_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.name);
+ *r->out.name = *r->in.name;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.name);
+ }
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_winreg_StringBuf(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_keyclass));
+ if (_ptr_keyclass) {
+ NDR_PULL_ALLOC(ndr, r->out.keyclass);
+ } else {
+ r->out.keyclass = NULL;
+ }
+ if (r->out.keyclass) {
+ _mem_save_keyclass_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.keyclass, 0);
+ NDR_CHECK(ndr_pull_winreg_StringBuf(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.keyclass));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_keyclass_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_last_changed_time));
+ if (_ptr_last_changed_time) {
+ NDR_PULL_ALLOC(ndr, r->out.last_changed_time);
+ } else {
+ r->out.last_changed_time = NULL;
+ }
+ if (r->out.last_changed_time) {
+ _mem_save_last_changed_time_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.last_changed_time, 0);
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, r->out.last_changed_time));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_last_changed_time_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_EnumKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_EnumKey *r)
+{
+ ndr_print_struct(ndr, name, "winreg_EnumKey");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_EnumKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "enum_index", r->in.enum_index);
+ ndr_print_ptr(ndr, "name", r->in.name);
+ ndr->depth++;
+ ndr_print_winreg_StringBuf(ndr, "name", r->in.name);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "keyclass", r->in.keyclass);
+ ndr->depth++;
+ if (r->in.keyclass) {
+ ndr_print_winreg_StringBuf(ndr, "keyclass", r->in.keyclass);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "last_changed_time", r->in.last_changed_time);
+ ndr->depth++;
+ if (r->in.last_changed_time) {
+ ndr_print_NTTIME(ndr, "last_changed_time", *r->in.last_changed_time);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_EnumKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "name", r->out.name);
+ ndr->depth++;
+ ndr_print_winreg_StringBuf(ndr, "name", r->out.name);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "keyclass", r->out.keyclass);
+ ndr->depth++;
+ if (r->out.keyclass) {
+ ndr_print_winreg_StringBuf(ndr, "keyclass", r->out.keyclass);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "last_changed_time", r->out.last_changed_time);
+ ndr->depth++;
+ if (r->out.last_changed_time) {
+ ndr_print_NTTIME(ndr, "last_changed_time", *r->out.last_changed_time);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_EnumValue(struct ndr_push *ndr, int flags, const struct winreg_EnumValue *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.enum_index));
+ if (r->in.name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_winreg_ValNameBuf(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.type));
+ if (r->in.type) {
+ NDR_CHECK(ndr_push_winreg_Type(ndr, NDR_SCALARS, *r->in.type));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.value));
+ if (r->in.value) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.size));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.length));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->in.value, *r->in.length));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.size));
+ if (r->in.size) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.size));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.length));
+ if (r->in.length) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.length));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_winreg_ValNameBuf(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.type));
+ if (r->out.type) {
+ NDR_CHECK(ndr_push_winreg_Type(ndr, NDR_SCALARS, *r->out.type));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.value));
+ if (r->out.value) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.size));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.length));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.value, *r->out.length));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.size));
+ if (r->out.size) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.size));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.length));
+ if (r->out.length) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.length));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_EnumValue(struct ndr_pull *ndr, int flags, struct winreg_EnumValue *r)
+{
+ uint32_t _ptr_type;
+ uint32_t _ptr_value;
+ uint32_t _ptr_size;
+ uint32_t _ptr_length;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_name_0;
+ TALLOC_CTX *_mem_save_type_0;
+ TALLOC_CTX *_mem_save_value_0;
+ TALLOC_CTX *_mem_save_size_0;
+ TALLOC_CTX *_mem_save_length_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.enum_index));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.name);
+ }
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_winreg_ValNameBuf(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_type));
+ if (_ptr_type) {
+ NDR_PULL_ALLOC(ndr, r->in.type);
+ } else {
+ r->in.type = NULL;
+ }
+ if (r->in.type) {
+ _mem_save_type_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.type, 0);
+ NDR_CHECK(ndr_pull_winreg_Type(ndr, NDR_SCALARS, r->in.type));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_type_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_value));
+ if (_ptr_value) {
+ NDR_PULL_ALLOC(ndr, r->in.value);
+ } else {
+ r->in.value = NULL;
+ }
+ if (r->in.value) {
+ _mem_save_value_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.value, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.value));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.value));
+ if (ndr_get_array_length(ndr, &r->in.value) > ndr_get_array_size(ndr, &r->in.value)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.value), ndr_get_array_length(ndr, &r->in.value));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->in.value, ndr_get_array_size(ndr, &r->in.value));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->in.value, ndr_get_array_length(ndr, &r->in.value)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_value_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_size));
+ if (_ptr_size) {
+ NDR_PULL_ALLOC(ndr, r->in.size);
+ } else {
+ r->in.size = NULL;
+ }
+ if (r->in.size) {
+ _mem_save_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.size, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_size_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_length));
+ if (_ptr_length) {
+ NDR_PULL_ALLOC(ndr, r->in.length);
+ } else {
+ r->in.length = NULL;
+ }
+ if (r->in.length) {
+ _mem_save_length_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.length, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.length));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_length_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.name);
+ *r->out.name = *r->in.name;
+ if (r->in.value) {
+ if (r->in.size == NULL) return ndr_pull_error(ndr, NDR_ERR_INVALID_POINTER, "NULL Pointer for size_is()");
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.value, *r->in.size));
+ }
+ if (r->in.value) {
+ if (r->in.length == NULL) return ndr_pull_error(ndr, NDR_ERR_INVALID_POINTER, "NULL Pointer for length_is()");
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->in.value, *r->in.length));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.name);
+ }
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_winreg_ValNameBuf(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_type));
+ if (_ptr_type) {
+ NDR_PULL_ALLOC(ndr, r->out.type);
+ } else {
+ r->out.type = NULL;
+ }
+ if (r->out.type) {
+ _mem_save_type_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.type, 0);
+ NDR_CHECK(ndr_pull_winreg_Type(ndr, NDR_SCALARS, r->out.type));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_type_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_value));
+ if (_ptr_value) {
+ NDR_PULL_ALLOC(ndr, r->out.value);
+ } else {
+ r->out.value = NULL;
+ }
+ if (r->out.value) {
+ _mem_save_value_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.value, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->out.value));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->out.value));
+ if (ndr_get_array_length(ndr, &r->out.value) > ndr_get_array_size(ndr, &r->out.value)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->out.value), ndr_get_array_length(ndr, &r->out.value));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->out.value, ndr_get_array_size(ndr, &r->out.value));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.value, ndr_get_array_length(ndr, &r->out.value)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_value_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_size));
+ if (_ptr_size) {
+ NDR_PULL_ALLOC(ndr, r->out.size);
+ } else {
+ r->out.size = NULL;
+ }
+ if (r->out.size) {
+ _mem_save_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.size, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_size_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_length));
+ if (_ptr_length) {
+ NDR_PULL_ALLOC(ndr, r->out.length);
+ } else {
+ r->out.length = NULL;
+ }
+ if (r->out.length) {
+ _mem_save_length_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.length, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.length));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_length_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ if (r->out.value) {
+ if (r->out.size == NULL) return ndr_pull_error(ndr, NDR_ERR_INVALID_POINTER, "NULL Pointer for size_is()");
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->out.value, *r->out.size));
+ }
+ if (r->out.value) {
+ if (r->out.length == NULL) return ndr_pull_error(ndr, NDR_ERR_INVALID_POINTER, "NULL Pointer for length_is()");
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->out.value, *r->out.length));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_EnumValue(struct ndr_print *ndr, const char *name, int flags, const struct winreg_EnumValue *r)
+{
+ ndr_print_struct(ndr, name, "winreg_EnumValue");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_EnumValue");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "enum_index", r->in.enum_index);
+ ndr_print_ptr(ndr, "name", r->in.name);
+ ndr->depth++;
+ ndr_print_winreg_ValNameBuf(ndr, "name", r->in.name);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "type", r->in.type);
+ ndr->depth++;
+ if (r->in.type) {
+ ndr_print_winreg_Type(ndr, "type", *r->in.type);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "value", r->in.value);
+ ndr->depth++;
+ if (r->in.value) {
+ if (r->in.length == NULL) return;
+ ndr_print_array_uint8(ndr, "value", r->in.value, *r->in.length);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "size", r->in.size);
+ ndr->depth++;
+ if (r->in.size) {
+ ndr_print_uint32(ndr, "size", *r->in.size);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "length", r->in.length);
+ ndr->depth++;
+ if (r->in.length) {
+ ndr_print_uint32(ndr, "length", *r->in.length);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_EnumValue");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "name", r->out.name);
+ ndr->depth++;
+ ndr_print_winreg_ValNameBuf(ndr, "name", r->out.name);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "type", r->out.type);
+ ndr->depth++;
+ if (r->out.type) {
+ ndr_print_winreg_Type(ndr, "type", *r->out.type);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "value", r->out.value);
+ ndr->depth++;
+ if (r->out.value) {
+ if (r->out.length == NULL) return;
+ ndr_print_array_uint8(ndr, "value", r->out.value, *r->out.length);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "size", r->out.size);
+ ndr->depth++;
+ if (r->out.size) {
+ ndr_print_uint32(ndr, "size", *r->out.size);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "length", r->out.length);
+ ndr->depth++;
+ if (r->out.length) {
+ ndr_print_uint32(ndr, "length", *r->out.length);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_FlushKey(struct ndr_push *ndr, int flags, const struct winreg_FlushKey *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_FlushKey(struct ndr_pull *ndr, int flags, struct winreg_FlushKey *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_FlushKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_FlushKey *r)
+{
+ ndr_print_struct(ndr, name, "winreg_FlushKey");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_FlushKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_FlushKey");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_GetKeySecurity(struct ndr_push *ndr, int flags, const struct winreg_GetKeySecurity *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_security_secinfo(ndr, NDR_SCALARS, r->in.sec_info));
+ if (r->in.sd == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_KeySecurityData(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sd));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.sd == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_KeySecurityData(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sd));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_GetKeySecurity(struct ndr_pull *ndr, int flags, struct winreg_GetKeySecurity *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sd_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_security_secinfo(ndr, NDR_SCALARS, &r->in.sec_info));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sd);
+ }
+ _mem_save_sd_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sd, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_KeySecurityData(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sd));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sd_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.sd);
+ *r->out.sd = *r->in.sd;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.sd);
+ }
+ _mem_save_sd_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.sd, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_KeySecurityData(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.sd));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sd_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_GetKeySecurity(struct ndr_print *ndr, const char *name, int flags, const struct winreg_GetKeySecurity *r)
+{
+ ndr_print_struct(ndr, name, "winreg_GetKeySecurity");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_GetKeySecurity");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_security_secinfo(ndr, "sec_info", r->in.sec_info);
+ ndr_print_ptr(ndr, "sd", r->in.sd);
+ ndr->depth++;
+ ndr_print_KeySecurityData(ndr, "sd", r->in.sd);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_GetKeySecurity");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sd", r->out.sd);
+ ndr->depth++;
+ ndr_print_KeySecurityData(ndr, "sd", r->out.sd);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_LoadKey(struct ndr_push *ndr, int flags, const struct winreg_LoadKey *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.keyname));
+ if (r->in.keyname) {
+ NDR_CHECK(ndr_push_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.keyname));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.filename));
+ if (r->in.filename) {
+ NDR_CHECK(ndr_push_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.filename));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_LoadKey(struct ndr_pull *ndr, int flags, struct winreg_LoadKey *r)
+{
+ uint32_t _ptr_keyname;
+ uint32_t _ptr_filename;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_keyname_0;
+ TALLOC_CTX *_mem_save_filename_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_keyname));
+ if (_ptr_keyname) {
+ NDR_PULL_ALLOC(ndr, r->in.keyname);
+ } else {
+ r->in.keyname = NULL;
+ }
+ if (r->in.keyname) {
+ _mem_save_keyname_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.keyname, 0);
+ NDR_CHECK(ndr_pull_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.keyname));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_keyname_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_filename));
+ if (_ptr_filename) {
+ NDR_PULL_ALLOC(ndr, r->in.filename);
+ } else {
+ r->in.filename = NULL;
+ }
+ if (r->in.filename) {
+ _mem_save_filename_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.filename, 0);
+ NDR_CHECK(ndr_pull_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.filename));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_filename_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_LoadKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_LoadKey *r)
+{
+ ndr_print_struct(ndr, name, "winreg_LoadKey");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_LoadKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "keyname", r->in.keyname);
+ ndr->depth++;
+ if (r->in.keyname) {
+ ndr_print_winreg_String(ndr, "keyname", r->in.keyname);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "filename", r->in.filename);
+ ndr->depth++;
+ if (r->in.filename) {
+ ndr_print_winreg_String(ndr, "filename", r->in.filename);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_LoadKey");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_NotifyChangeKeyValue(struct ndr_push *ndr, int flags, const struct winreg_NotifyChangeKeyValue *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.watch_subtree));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.notify_filter));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown));
+ NDR_CHECK(ndr_push_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.string1));
+ NDR_CHECK(ndr_push_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.string2));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown2));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_NotifyChangeKeyValue(struct ndr_pull *ndr, int flags, struct winreg_NotifyChangeKeyValue *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.watch_subtree));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.notify_filter));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown));
+ NDR_CHECK(ndr_pull_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.string1));
+ NDR_CHECK(ndr_pull_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.string2));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown2));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_NotifyChangeKeyValue(struct ndr_print *ndr, const char *name, int flags, const struct winreg_NotifyChangeKeyValue *r)
+{
+ ndr_print_struct(ndr, name, "winreg_NotifyChangeKeyValue");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_NotifyChangeKeyValue");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_uint8(ndr, "watch_subtree", r->in.watch_subtree);
+ ndr_print_uint32(ndr, "notify_filter", r->in.notify_filter);
+ ndr_print_uint32(ndr, "unknown", r->in.unknown);
+ ndr_print_winreg_String(ndr, "string1", &r->in.string1);
+ ndr_print_winreg_String(ndr, "string2", &r->in.string2);
+ ndr_print_uint32(ndr, "unknown2", r->in.unknown2);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_NotifyChangeKeyValue");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_OpenKey(struct ndr_push *ndr, int flags, const struct winreg_OpenKey *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.parent_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.parent_handle));
+ NDR_CHECK(ndr_push_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.keyname));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown));
+ NDR_CHECK(ndr_push_winreg_AccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_OpenKey(struct ndr_pull *ndr, int flags, struct winreg_OpenKey *r)
+{
+ TALLOC_CTX *_mem_save_parent_handle_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.parent_handle);
+ }
+ _mem_save_parent_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.parent_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.parent_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parent_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.keyname));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown));
+ NDR_CHECK(ndr_pull_winreg_AccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_OpenKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenKey *r)
+{
+ ndr_print_struct(ndr, name, "winreg_OpenKey");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_OpenKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parent_handle", r->in.parent_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "parent_handle", r->in.parent_handle);
+ ndr->depth--;
+ ndr_print_winreg_String(ndr, "keyname", &r->in.keyname);
+ ndr_print_uint32(ndr, "unknown", r->in.unknown);
+ ndr_print_winreg_AccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_OpenKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_QueryInfoKey(struct ndr_push *ndr, int flags, const struct winreg_QueryInfoKey *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.classname == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.classname));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.classname == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.classname));
+ if (r->out.num_subkeys == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.num_subkeys));
+ if (r->out.max_subkeylen == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.max_subkeylen));
+ if (r->out.max_classlen == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.max_classlen));
+ if (r->out.num_values == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.num_values));
+ if (r->out.max_valnamelen == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.max_valnamelen));
+ if (r->out.max_valbufsize == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.max_valbufsize));
+ if (r->out.secdescsize == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.secdescsize));
+ if (r->out.last_changed_time == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, *r->out.last_changed_time));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_QueryInfoKey(struct ndr_pull *ndr, int flags, struct winreg_QueryInfoKey *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_classname_0;
+ TALLOC_CTX *_mem_save_num_subkeys_0;
+ TALLOC_CTX *_mem_save_max_subkeylen_0;
+ TALLOC_CTX *_mem_save_max_classlen_0;
+ TALLOC_CTX *_mem_save_num_values_0;
+ TALLOC_CTX *_mem_save_max_valnamelen_0;
+ TALLOC_CTX *_mem_save_max_valbufsize_0;
+ TALLOC_CTX *_mem_save_secdescsize_0;
+ TALLOC_CTX *_mem_save_last_changed_time_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.classname);
+ }
+ _mem_save_classname_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.classname, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.classname));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_classname_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.classname);
+ *r->out.classname = *r->in.classname;
+ NDR_PULL_ALLOC(ndr, r->out.num_subkeys);
+ ZERO_STRUCTP(r->out.num_subkeys);
+ NDR_PULL_ALLOC(ndr, r->out.max_subkeylen);
+ ZERO_STRUCTP(r->out.max_subkeylen);
+ NDR_PULL_ALLOC(ndr, r->out.max_classlen);
+ ZERO_STRUCTP(r->out.max_classlen);
+ NDR_PULL_ALLOC(ndr, r->out.num_values);
+ ZERO_STRUCTP(r->out.num_values);
+ NDR_PULL_ALLOC(ndr, r->out.max_valnamelen);
+ ZERO_STRUCTP(r->out.max_valnamelen);
+ NDR_PULL_ALLOC(ndr, r->out.max_valbufsize);
+ ZERO_STRUCTP(r->out.max_valbufsize);
+ NDR_PULL_ALLOC(ndr, r->out.secdescsize);
+ ZERO_STRUCTP(r->out.secdescsize);
+ NDR_PULL_ALLOC(ndr, r->out.last_changed_time);
+ ZERO_STRUCTP(r->out.last_changed_time);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.classname);
+ }
+ _mem_save_classname_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.classname, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.classname));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_classname_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.num_subkeys);
+ }
+ _mem_save_num_subkeys_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.num_subkeys, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.num_subkeys));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_num_subkeys_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.max_subkeylen);
+ }
+ _mem_save_max_subkeylen_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.max_subkeylen, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.max_subkeylen));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_max_subkeylen_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.max_classlen);
+ }
+ _mem_save_max_classlen_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.max_classlen, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.max_classlen));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_max_classlen_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.num_values);
+ }
+ _mem_save_num_values_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.num_values, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.num_values));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_num_values_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.max_valnamelen);
+ }
+ _mem_save_max_valnamelen_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.max_valnamelen, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.max_valnamelen));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_max_valnamelen_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.max_valbufsize);
+ }
+ _mem_save_max_valbufsize_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.max_valbufsize, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.max_valbufsize));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_max_valbufsize_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.secdescsize);
+ }
+ _mem_save_secdescsize_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.secdescsize, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.secdescsize));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_secdescsize_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.last_changed_time);
+ }
+ _mem_save_last_changed_time_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.last_changed_time, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, r->out.last_changed_time));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_last_changed_time_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_QueryInfoKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_QueryInfoKey *r)
+{
+ ndr_print_struct(ndr, name, "winreg_QueryInfoKey");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_QueryInfoKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "classname", r->in.classname);
+ ndr->depth++;
+ ndr_print_winreg_String(ndr, "classname", r->in.classname);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_QueryInfoKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "classname", r->out.classname);
+ ndr->depth++;
+ ndr_print_winreg_String(ndr, "classname", r->out.classname);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "num_subkeys", r->out.num_subkeys);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_subkeys", *r->out.num_subkeys);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "max_subkeylen", r->out.max_subkeylen);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "max_subkeylen", *r->out.max_subkeylen);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "max_classlen", r->out.max_classlen);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "max_classlen", *r->out.max_classlen);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "num_values", r->out.num_values);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_values", *r->out.num_values);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "max_valnamelen", r->out.max_valnamelen);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "max_valnamelen", *r->out.max_valnamelen);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "max_valbufsize", r->out.max_valbufsize);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "max_valbufsize", *r->out.max_valbufsize);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "secdescsize", r->out.secdescsize);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "secdescsize", *r->out.secdescsize);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "last_changed_time", r->out.last_changed_time);
+ ndr->depth++;
+ ndr_print_NTTIME(ndr, "last_changed_time", *r->out.last_changed_time);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_QueryValue(struct ndr_push *ndr, int flags, const struct winreg_QueryValue *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.value_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.value_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.type));
+ if (r->in.type) {
+ NDR_CHECK(ndr_push_winreg_Type(ndr, NDR_SCALARS, *r->in.type));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.data));
+ if (r->in.data) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.data_size));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.value_length));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->in.data, *r->in.value_length));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.data_size));
+ if (r->in.data_size) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.data_size));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.value_length));
+ if (r->in.value_length) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.value_length));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.type));
+ if (r->out.type) {
+ NDR_CHECK(ndr_push_winreg_Type(ndr, NDR_SCALARS, *r->out.type));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.data));
+ if (r->out.data) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.data_size));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.value_length));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.data, *r->out.value_length));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.data_size));
+ if (r->out.data_size) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.data_size));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.value_length));
+ if (r->out.value_length) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.value_length));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_QueryValue(struct ndr_pull *ndr, int flags, struct winreg_QueryValue *r)
+{
+ uint32_t _ptr_type;
+ uint32_t _ptr_data;
+ uint32_t _ptr_data_size;
+ uint32_t _ptr_value_length;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_value_name_0;
+ TALLOC_CTX *_mem_save_type_0;
+ TALLOC_CTX *_mem_save_data_0;
+ TALLOC_CTX *_mem_save_data_size_0;
+ TALLOC_CTX *_mem_save_value_length_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.value_name);
+ }
+ _mem_save_value_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.value_name, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.value_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_value_name_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_type));
+ if (_ptr_type) {
+ NDR_PULL_ALLOC(ndr, r->in.type);
+ } else {
+ r->in.type = NULL;
+ }
+ if (r->in.type) {
+ _mem_save_type_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.type, 0);
+ NDR_CHECK(ndr_pull_winreg_Type(ndr, NDR_SCALARS, r->in.type));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_type_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data));
+ if (_ptr_data) {
+ NDR_PULL_ALLOC(ndr, r->in.data);
+ } else {
+ r->in.data = NULL;
+ }
+ if (r->in.data) {
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.data, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.data));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.data));
+ if (ndr_get_array_length(ndr, &r->in.data) > ndr_get_array_size(ndr, &r->in.data)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.data), ndr_get_array_length(ndr, &r->in.data));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->in.data, ndr_get_array_size(ndr, &r->in.data));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->in.data, ndr_get_array_length(ndr, &r->in.data)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data_size));
+ if (_ptr_data_size) {
+ NDR_PULL_ALLOC(ndr, r->in.data_size);
+ } else {
+ r->in.data_size = NULL;
+ }
+ if (r->in.data_size) {
+ _mem_save_data_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.data_size, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.data_size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_size_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_value_length));
+ if (_ptr_value_length) {
+ NDR_PULL_ALLOC(ndr, r->in.value_length);
+ } else {
+ r->in.value_length = NULL;
+ }
+ if (r->in.value_length) {
+ _mem_save_value_length_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.value_length, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.value_length));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_value_length_0, 0);
+ }
+ if (r->in.data) {
+ if (r->in.data_size == NULL) return ndr_pull_error(ndr, NDR_ERR_INVALID_POINTER, "NULL Pointer for size_is()");
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.data, *r->in.data_size));
+ }
+ if (r->in.data) {
+ if (r->in.value_length == NULL) return ndr_pull_error(ndr, NDR_ERR_INVALID_POINTER, "NULL Pointer for length_is()");
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->in.data, *r->in.value_length));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_type));
+ if (_ptr_type) {
+ NDR_PULL_ALLOC(ndr, r->out.type);
+ } else {
+ r->out.type = NULL;
+ }
+ if (r->out.type) {
+ _mem_save_type_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.type, 0);
+ NDR_CHECK(ndr_pull_winreg_Type(ndr, NDR_SCALARS, r->out.type));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_type_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data));
+ if (_ptr_data) {
+ NDR_PULL_ALLOC(ndr, r->out.data);
+ } else {
+ r->out.data = NULL;
+ }
+ if (r->out.data) {
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.data, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->out.data));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->out.data));
+ if (ndr_get_array_length(ndr, &r->out.data) > ndr_get_array_size(ndr, &r->out.data)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->out.data), ndr_get_array_length(ndr, &r->out.data));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->out.data, ndr_get_array_size(ndr, &r->out.data));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.data, ndr_get_array_length(ndr, &r->out.data)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data_size));
+ if (_ptr_data_size) {
+ NDR_PULL_ALLOC(ndr, r->out.data_size);
+ } else {
+ r->out.data_size = NULL;
+ }
+ if (r->out.data_size) {
+ _mem_save_data_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.data_size, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.data_size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_size_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_value_length));
+ if (_ptr_value_length) {
+ NDR_PULL_ALLOC(ndr, r->out.value_length);
+ } else {
+ r->out.value_length = NULL;
+ }
+ if (r->out.value_length) {
+ _mem_save_value_length_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.value_length, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.value_length));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_value_length_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ if (r->out.data) {
+ if (r->out.data_size == NULL) return ndr_pull_error(ndr, NDR_ERR_INVALID_POINTER, "NULL Pointer for size_is()");
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->out.data, *r->out.data_size));
+ }
+ if (r->out.data) {
+ if (r->out.value_length == NULL) return ndr_pull_error(ndr, NDR_ERR_INVALID_POINTER, "NULL Pointer for length_is()");
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->out.data, *r->out.value_length));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_QueryValue(struct ndr_print *ndr, const char *name, int flags, const struct winreg_QueryValue *r)
+{
+ ndr_print_struct(ndr, name, "winreg_QueryValue");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_QueryValue");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "value_name", r->in.value_name);
+ ndr->depth++;
+ ndr_print_winreg_String(ndr, "value_name", r->in.value_name);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "type", r->in.type);
+ ndr->depth++;
+ if (r->in.type) {
+ ndr_print_winreg_Type(ndr, "type", *r->in.type);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "data", r->in.data);
+ ndr->depth++;
+ if (r->in.data) {
+ if (r->in.value_length == NULL) return;
+ ndr_print_array_uint8(ndr, "data", r->in.data, *r->in.value_length);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "data_size", r->in.data_size);
+ ndr->depth++;
+ if (r->in.data_size) {
+ ndr_print_uint32(ndr, "data_size", *r->in.data_size);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "value_length", r->in.value_length);
+ ndr->depth++;
+ if (r->in.value_length) {
+ ndr_print_uint32(ndr, "value_length", *r->in.value_length);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_QueryValue");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "type", r->out.type);
+ ndr->depth++;
+ if (r->out.type) {
+ ndr_print_winreg_Type(ndr, "type", *r->out.type);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "data", r->out.data);
+ ndr->depth++;
+ if (r->out.data) {
+ if (r->out.value_length == NULL) return;
+ ndr_print_array_uint8(ndr, "data", r->out.data, *r->out.value_length);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "data_size", r->out.data_size);
+ ndr->depth++;
+ if (r->out.data_size) {
+ ndr_print_uint32(ndr, "data_size", *r->out.data_size);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "value_length", r->out.value_length);
+ ndr->depth++;
+ if (r->out.value_length) {
+ ndr_print_uint32(ndr, "value_length", *r->out.value_length);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_ReplaceKey(struct ndr_push *ndr, int flags, const struct winreg_ReplaceKey *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_ReplaceKey(struct ndr_pull *ndr, int flags, struct winreg_ReplaceKey *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_ReplaceKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_ReplaceKey *r)
+{
+ ndr_print_struct(ndr, name, "winreg_ReplaceKey");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_ReplaceKey");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_ReplaceKey");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_RestoreKey(struct ndr_push *ndr, int flags, const struct winreg_RestoreKey *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.filename == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.filename));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_RestoreKey(struct ndr_pull *ndr, int flags, struct winreg_RestoreKey *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_filename_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.filename);
+ }
+ _mem_save_filename_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.filename, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.filename));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_filename_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_RestoreKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_RestoreKey *r)
+{
+ ndr_print_struct(ndr, name, "winreg_RestoreKey");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_RestoreKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "filename", r->in.filename);
+ ndr->depth++;
+ ndr_print_winreg_String(ndr, "filename", r->in.filename);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "flags", r->in.flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_RestoreKey");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_SaveKey(struct ndr_push *ndr, int flags, const struct winreg_SaveKey *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ if (r->in.filename == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.filename));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.sec_attrib));
+ if (r->in.sec_attrib) {
+ NDR_CHECK(ndr_push_KeySecurityAttribute(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sec_attrib));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_SaveKey(struct ndr_pull *ndr, int flags, struct winreg_SaveKey *r)
+{
+ uint32_t _ptr_sec_attrib;
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_filename_0;
+ TALLOC_CTX *_mem_save_sec_attrib_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.filename);
+ }
+ _mem_save_filename_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.filename, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.filename));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_filename_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sec_attrib));
+ if (_ptr_sec_attrib) {
+ NDR_PULL_ALLOC(ndr, r->in.sec_attrib);
+ } else {
+ r->in.sec_attrib = NULL;
+ }
+ if (r->in.sec_attrib) {
+ _mem_save_sec_attrib_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sec_attrib, 0);
+ NDR_CHECK(ndr_pull_KeySecurityAttribute(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sec_attrib));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sec_attrib_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_SaveKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_SaveKey *r)
+{
+ ndr_print_struct(ndr, name, "winreg_SaveKey");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_SaveKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "filename", r->in.filename);
+ ndr->depth++;
+ ndr_print_winreg_String(ndr, "filename", r->in.filename);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "sec_attrib", r->in.sec_attrib);
+ ndr->depth++;
+ if (r->in.sec_attrib) {
+ ndr_print_KeySecurityAttribute(ndr, "sec_attrib", r->in.sec_attrib);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_SaveKey");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_SetKeySecurity(struct ndr_push *ndr, int flags, const struct winreg_SetKeySecurity *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_winreg_AccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ if (r->in.sd == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_KeySecurityData(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sd));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_SetKeySecurity(struct ndr_pull *ndr, int flags, struct winreg_SetKeySecurity *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_sd_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_winreg_AccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.sd);
+ }
+ _mem_save_sd_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.sd, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_KeySecurityData(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.sd));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sd_0, LIBNDR_FLAG_REF_ALLOC);
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_SetKeySecurity(struct ndr_print *ndr, const char *name, int flags, const struct winreg_SetKeySecurity *r)
+{
+ ndr_print_struct(ndr, name, "winreg_SetKeySecurity");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_SetKeySecurity");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_winreg_AccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr_print_ptr(ndr, "sd", r->in.sd);
+ ndr->depth++;
+ ndr_print_KeySecurityData(ndr, "sd", r->in.sd);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_SetKeySecurity");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_SetValue(struct ndr_push *ndr, int flags, const struct winreg_SetValue *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_CHECK(ndr_push_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.name));
+ NDR_CHECK(ndr_push_winreg_Type(ndr, NDR_SCALARS, r->in.type));
+ if (r->in.data == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->in.data, r->in.size));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.size));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_SetValue(struct ndr_pull *ndr, int flags, struct winreg_SetValue *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_winreg_String(ndr, NDR_SCALARS|NDR_BUFFERS, &r->in.name));
+ NDR_CHECK(ndr_pull_winreg_Type(ndr, NDR_SCALARS, &r->in.type));
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.data));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC_N(ndr, r->in.data, ndr_get_array_size(ndr, &r->in.data));
+ }
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->in.data, ndr_get_array_size(ndr, &r->in.data)));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.size));
+ if (r->in.data) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.data, r->in.size));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_SetValue(struct ndr_print *ndr, const char *name, int flags, const struct winreg_SetValue *r)
+{
+ ndr_print_struct(ndr, name, "winreg_SetValue");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_SetValue");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr_print_winreg_String(ndr, "name", &r->in.name);
+ ndr_print_winreg_Type(ndr, "type", r->in.type);
+ ndr_print_ptr(ndr, "data", r->in.data);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "data", r->in.data, r->in.size);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "size", r->in.size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_SetValue");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_UnLoadKey(struct ndr_push *ndr, int flags, const struct winreg_UnLoadKey *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_UnLoadKey(struct ndr_pull *ndr, int flags, struct winreg_UnLoadKey *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_UnLoadKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_UnLoadKey *r)
+{
+ ndr_print_struct(ndr, name, "winreg_UnLoadKey");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_UnLoadKey");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_UnLoadKey");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_InitiateSystemShutdown(struct ndr_push *ndr, int flags, const struct winreg_InitiateSystemShutdown *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.hostname));
+ if (r->in.hostname) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.hostname));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.message));
+ if (r->in.message) {
+ NDR_CHECK(ndr_push_initshutdown_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.message));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.timeout));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.force_apps));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.do_reboot));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_InitiateSystemShutdown(struct ndr_pull *ndr, int flags, struct winreg_InitiateSystemShutdown *r)
+{
+ uint32_t _ptr_hostname;
+ uint32_t _ptr_message;
+ TALLOC_CTX *_mem_save_hostname_0;
+ TALLOC_CTX *_mem_save_message_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_hostname));
+ if (_ptr_hostname) {
+ NDR_PULL_ALLOC(ndr, r->in.hostname);
+ } else {
+ r->in.hostname = NULL;
+ }
+ if (r->in.hostname) {
+ _mem_save_hostname_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.hostname, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.hostname));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_hostname_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_message));
+ if (_ptr_message) {
+ NDR_PULL_ALLOC(ndr, r->in.message);
+ } else {
+ r->in.message = NULL;
+ }
+ if (r->in.message) {
+ _mem_save_message_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.message, 0);
+ NDR_CHECK(ndr_pull_initshutdown_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.message));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_message_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.timeout));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.force_apps));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.do_reboot));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_InitiateSystemShutdown(struct ndr_print *ndr, const char *name, int flags, const struct winreg_InitiateSystemShutdown *r)
+{
+ ndr_print_struct(ndr, name, "winreg_InitiateSystemShutdown");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_InitiateSystemShutdown");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "hostname", r->in.hostname);
+ ndr->depth++;
+ if (r->in.hostname) {
+ ndr_print_uint16(ndr, "hostname", *r->in.hostname);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "message", r->in.message);
+ ndr->depth++;
+ if (r->in.message) {
+ ndr_print_initshutdown_String(ndr, "message", r->in.message);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "timeout", r->in.timeout);
+ ndr_print_uint8(ndr, "force_apps", r->in.force_apps);
+ ndr_print_uint8(ndr, "do_reboot", r->in.do_reboot);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_InitiateSystemShutdown");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_AbortSystemShutdown(struct ndr_push *ndr, int flags, const struct winreg_AbortSystemShutdown *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server));
+ if (r->in.server) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.server));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_AbortSystemShutdown(struct ndr_pull *ndr, int flags, struct winreg_AbortSystemShutdown *r)
+{
+ uint32_t _ptr_server;
+ TALLOC_CTX *_mem_save_server_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server));
+ if (_ptr_server) {
+ NDR_PULL_ALLOC(ndr, r->in.server);
+ } else {
+ r->in.server = NULL;
+ }
+ if (r->in.server) {
+ _mem_save_server_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.server));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_AbortSystemShutdown(struct ndr_print *ndr, const char *name, int flags, const struct winreg_AbortSystemShutdown *r)
+{
+ ndr_print_struct(ndr, name, "winreg_AbortSystemShutdown");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_AbortSystemShutdown");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server", r->in.server);
+ ndr->depth++;
+ if (r->in.server) {
+ ndr_print_uint16(ndr, "server", *r->in.server);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_AbortSystemShutdown");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_GetVersion(struct ndr_push *ndr, int flags, const struct winreg_GetVersion *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.version == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.version));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_GetVersion(struct ndr_pull *ndr, int flags, struct winreg_GetVersion *r)
+{
+ TALLOC_CTX *_mem_save_handle_0;
+ TALLOC_CTX *_mem_save_version_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.version);
+ ZERO_STRUCTP(r->out.version);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.version);
+ }
+ _mem_save_version_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.version, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.version));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_version_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_GetVersion(struct ndr_print *ndr, const char *name, int flags, const struct winreg_GetVersion *r)
+{
+ ndr_print_struct(ndr, name, "winreg_GetVersion");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_GetVersion");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->in.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->in.handle);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_GetVersion");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "version", r->out.version);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "version", *r->out.version);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_OpenHKCC(struct ndr_push *ndr, int flags, const struct winreg_OpenHKCC *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.system_name));
+ }
+ NDR_CHECK(ndr_push_winreg_AccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_OpenHKCC(struct ndr_pull *ndr, int flags, struct winreg_OpenHKCC *r)
+{
+ uint32_t _ptr_system_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.system_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_winreg_AccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_OpenHKCC(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKCC *r)
+{
+ ndr_print_struct(ndr, name, "winreg_OpenHKCC");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_OpenHKCC");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_uint16(ndr, "system_name", *r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_winreg_AccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_OpenHKCC");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_OpenHKDD(struct ndr_push *ndr, int flags, const struct winreg_OpenHKDD *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.system_name));
+ }
+ NDR_CHECK(ndr_push_winreg_AccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_OpenHKDD(struct ndr_pull *ndr, int flags, struct winreg_OpenHKDD *r)
+{
+ uint32_t _ptr_system_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.system_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_winreg_AccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_OpenHKDD(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKDD *r)
+{
+ ndr_print_struct(ndr, name, "winreg_OpenHKDD");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_OpenHKDD");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_uint16(ndr, "system_name", *r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_winreg_AccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_OpenHKDD");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_QueryMultipleValues(struct ndr_push *ndr, int flags, const struct winreg_QueryMultipleValues *r)
+{
+ uint32_t cntr_values_1;
+ if (flags & NDR_IN) {
+ if (r->in.key_handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.key_handle));
+ if (r->in.values == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_values));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_values));
+ for (cntr_values_1 = 0; cntr_values_1 < r->in.num_values; cntr_values_1++) {
+ NDR_CHECK(ndr_push_QueryMultipleValue(ndr, NDR_SCALARS, &r->in.values[cntr_values_1]));
+ }
+ for (cntr_values_1 = 0; cntr_values_1 < r->in.num_values; cntr_values_1++) {
+ NDR_CHECK(ndr_push_QueryMultipleValue(ndr, NDR_BUFFERS, &r->in.values[cntr_values_1]));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_values));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.buffer));
+ if (r->in.buffer) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.buffer_size));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.buffer_size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->in.buffer, *r->in.buffer_size));
+ }
+ if (r->in.buffer_size == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.buffer_size));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.values == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_values));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.num_values));
+ for (cntr_values_1 = 0; cntr_values_1 < r->in.num_values; cntr_values_1++) {
+ NDR_CHECK(ndr_push_QueryMultipleValue(ndr, NDR_SCALARS, &r->out.values[cntr_values_1]));
+ }
+ for (cntr_values_1 = 0; cntr_values_1 < r->in.num_values; cntr_values_1++) {
+ NDR_CHECK(ndr_push_QueryMultipleValue(ndr, NDR_BUFFERS, &r->out.values[cntr_values_1]));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.buffer));
+ if (r->out.buffer) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.buffer_size));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.buffer_size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->out.buffer, *r->out.buffer_size));
+ }
+ if (r->out.buffer_size == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.buffer_size));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_QueryMultipleValues(struct ndr_pull *ndr, int flags, struct winreg_QueryMultipleValues *r)
+{
+ uint32_t cntr_values_1;
+ uint32_t _ptr_buffer;
+ TALLOC_CTX *_mem_save_key_handle_0;
+ TALLOC_CTX *_mem_save_values_1;
+ TALLOC_CTX *_mem_save_buffer_0;
+ TALLOC_CTX *_mem_save_buffer_size_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.key_handle);
+ }
+ _mem_save_key_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.key_handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.key_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_key_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.values));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.values));
+ if (ndr_get_array_length(ndr, &r->in.values) > ndr_get_array_size(ndr, &r->in.values)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.values), ndr_get_array_length(ndr, &r->in.values));
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC_N(ndr, r->in.values, ndr_get_array_size(ndr, &r->in.values));
+ }
+ memcpy(r->out.values, r->in.values, ndr_get_array_size(ndr, &r->in.values) * sizeof(*r->in.values));
+ _mem_save_values_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.values, 0);
+ for (cntr_values_1 = 0; cntr_values_1 < r->in.num_values; cntr_values_1++) {
+ NDR_CHECK(ndr_pull_QueryMultipleValue(ndr, NDR_SCALARS, &r->in.values[cntr_values_1]));
+ }
+ for (cntr_values_1 = 0; cntr_values_1 < r->in.num_values; cntr_values_1++) {
+ NDR_CHECK(ndr_pull_QueryMultipleValue(ndr, NDR_BUFFERS, &r->in.values[cntr_values_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_values_1, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.num_values));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_buffer));
+ if (_ptr_buffer) {
+ NDR_PULL_ALLOC(ndr, r->in.buffer);
+ } else {
+ r->in.buffer = NULL;
+ }
+ if (r->in.buffer) {
+ _mem_save_buffer_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.buffer, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.buffer));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.buffer));
+ if (ndr_get_array_length(ndr, &r->in.buffer) > ndr_get_array_size(ndr, &r->in.buffer)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.buffer), ndr_get_array_length(ndr, &r->in.buffer));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->in.buffer, ndr_get_array_size(ndr, &r->in.buffer));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->in.buffer, ndr_get_array_length(ndr, &r->in.buffer)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_buffer_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.buffer_size);
+ }
+ _mem_save_buffer_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.buffer_size, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.buffer_size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_buffer_size_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC_N(ndr, r->out.values, r->in.num_values);
+ memcpy(r->out.values, r->in.values, (r->in.num_values) * sizeof(*r->in.values));
+ NDR_PULL_ALLOC(ndr, r->out.buffer_size);
+ *r->out.buffer_size = *r->in.buffer_size;
+ if (r->in.values) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.values, r->in.num_values));
+ }
+ if (r->in.values) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->in.values, r->in.num_values));
+ }
+ if (r->in.buffer) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.buffer, *r->in.buffer_size));
+ }
+ if (r->in.buffer) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->in.buffer, *r->in.buffer_size));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->out.values));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->out.values));
+ if (ndr_get_array_length(ndr, &r->out.values) > ndr_get_array_size(ndr, &r->out.values)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->out.values), ndr_get_array_length(ndr, &r->out.values));
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC_N(ndr, r->out.values, ndr_get_array_size(ndr, &r->out.values));
+ }
+ memcpy(r->out.values, r->in.values, ndr_get_array_size(ndr, &r->out.values) * sizeof(*r->in.values));
+ _mem_save_values_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.values, 0);
+ for (cntr_values_1 = 0; cntr_values_1 < r->in.num_values; cntr_values_1++) {
+ NDR_CHECK(ndr_pull_QueryMultipleValue(ndr, NDR_SCALARS, &r->out.values[cntr_values_1]));
+ }
+ for (cntr_values_1 = 0; cntr_values_1 < r->in.num_values; cntr_values_1++) {
+ NDR_CHECK(ndr_pull_QueryMultipleValue(ndr, NDR_BUFFERS, &r->out.values[cntr_values_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_values_1, 0);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_buffer));
+ if (_ptr_buffer) {
+ NDR_PULL_ALLOC(ndr, r->out.buffer);
+ } else {
+ r->out.buffer = NULL;
+ }
+ if (r->out.buffer) {
+ _mem_save_buffer_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.buffer, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->out.buffer));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->out.buffer));
+ if (ndr_get_array_length(ndr, &r->out.buffer) > ndr_get_array_size(ndr, &r->out.buffer)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->out.buffer), ndr_get_array_length(ndr, &r->out.buffer));
+ }
+ NDR_PULL_ALLOC_N(ndr, r->out.buffer, ndr_get_array_size(ndr, &r->out.buffer));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->out.buffer, ndr_get_array_length(ndr, &r->out.buffer)));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_buffer_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.buffer_size);
+ }
+ _mem_save_buffer_size_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.buffer_size, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.buffer_size));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_buffer_size_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ if (r->out.values) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->out.values, r->in.num_values));
+ }
+ if (r->out.values) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->out.values, r->in.num_values));
+ }
+ if (r->out.buffer) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->out.buffer, *r->out.buffer_size));
+ }
+ if (r->out.buffer) {
+ NDR_CHECK(ndr_check_array_length(ndr, (void*)&r->out.buffer, *r->out.buffer_size));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_QueryMultipleValues(struct ndr_print *ndr, const char *name, int flags, const struct winreg_QueryMultipleValues *r)
+{
+ uint32_t cntr_values_1;
+ ndr_print_struct(ndr, name, "winreg_QueryMultipleValues");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_QueryMultipleValues");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "key_handle", r->in.key_handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "key_handle", r->in.key_handle);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "values", r->in.values);
+ ndr->depth++;
+ ndr->print(ndr, "%s: ARRAY(%d)", "values", (int)r->in.num_values);
+ ndr->depth++;
+ for (cntr_values_1=0;cntr_values_1<r->in.num_values;cntr_values_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_values_1) != -1) {
+ ndr_print_QueryMultipleValue(ndr, "values", &r->in.values[cntr_values_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_uint32(ndr, "num_values", r->in.num_values);
+ ndr_print_ptr(ndr, "buffer", r->in.buffer);
+ ndr->depth++;
+ if (r->in.buffer) {
+ ndr_print_array_uint8(ndr, "buffer", r->in.buffer, *r->in.buffer_size);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "buffer_size", r->in.buffer_size);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "buffer_size", *r->in.buffer_size);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_QueryMultipleValues");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "values", r->out.values);
+ ndr->depth++;
+ ndr->print(ndr, "%s: ARRAY(%d)", "values", (int)r->in.num_values);
+ ndr->depth++;
+ for (cntr_values_1=0;cntr_values_1<r->in.num_values;cntr_values_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_values_1) != -1) {
+ ndr_print_QueryMultipleValue(ndr, "values", &r->out.values[cntr_values_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "buffer", r->out.buffer);
+ ndr->depth++;
+ if (r->out.buffer) {
+ ndr_print_array_uint8(ndr, "buffer", r->out.buffer, *r->out.buffer_size);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "buffer_size", r->out.buffer_size);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "buffer_size", *r->out.buffer_size);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_InitiateSystemShutdownEx(struct ndr_push *ndr, int flags, const struct winreg_InitiateSystemShutdownEx *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.hostname));
+ if (r->in.hostname) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.hostname));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.message));
+ if (r->in.message) {
+ NDR_CHECK(ndr_push_initshutdown_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.message));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.timeout));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.force_apps));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->in.do_reboot));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.reason));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_InitiateSystemShutdownEx(struct ndr_pull *ndr, int flags, struct winreg_InitiateSystemShutdownEx *r)
+{
+ uint32_t _ptr_hostname;
+ uint32_t _ptr_message;
+ TALLOC_CTX *_mem_save_hostname_0;
+ TALLOC_CTX *_mem_save_message_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_hostname));
+ if (_ptr_hostname) {
+ NDR_PULL_ALLOC(ndr, r->in.hostname);
+ } else {
+ r->in.hostname = NULL;
+ }
+ if (r->in.hostname) {
+ _mem_save_hostname_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.hostname, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.hostname));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_hostname_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_message));
+ if (_ptr_message) {
+ NDR_PULL_ALLOC(ndr, r->in.message);
+ } else {
+ r->in.message = NULL;
+ }
+ if (r->in.message) {
+ _mem_save_message_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.message, 0);
+ NDR_CHECK(ndr_pull_initshutdown_String(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.message));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_message_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.timeout));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.force_apps));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->in.do_reboot));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.reason));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_InitiateSystemShutdownEx(struct ndr_print *ndr, const char *name, int flags, const struct winreg_InitiateSystemShutdownEx *r)
+{
+ ndr_print_struct(ndr, name, "winreg_InitiateSystemShutdownEx");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_InitiateSystemShutdownEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "hostname", r->in.hostname);
+ ndr->depth++;
+ if (r->in.hostname) {
+ ndr_print_uint16(ndr, "hostname", *r->in.hostname);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "message", r->in.message);
+ ndr->depth++;
+ if (r->in.message) {
+ ndr_print_initshutdown_String(ndr, "message", r->in.message);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "timeout", r->in.timeout);
+ ndr_print_uint8(ndr, "force_apps", r->in.force_apps);
+ ndr_print_uint8(ndr, "do_reboot", r->in.do_reboot);
+ ndr_print_uint32(ndr, "reason", r->in.reason);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_InitiateSystemShutdownEx");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_SaveKeyEx(struct ndr_push *ndr, int flags, const struct winreg_SaveKeyEx *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_SaveKeyEx(struct ndr_pull *ndr, int flags, struct winreg_SaveKeyEx *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_SaveKeyEx(struct ndr_print *ndr, const char *name, int flags, const struct winreg_SaveKeyEx *r)
+{
+ ndr_print_struct(ndr, name, "winreg_SaveKeyEx");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_SaveKeyEx");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_SaveKeyEx");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_OpenHKPT(struct ndr_push *ndr, int flags, const struct winreg_OpenHKPT *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.system_name));
+ }
+ NDR_CHECK(ndr_push_winreg_AccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_OpenHKPT(struct ndr_pull *ndr, int flags, struct winreg_OpenHKPT *r)
+{
+ uint32_t _ptr_system_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.system_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_winreg_AccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_OpenHKPT(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKPT *r)
+{
+ ndr_print_struct(ndr, name, "winreg_OpenHKPT");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_OpenHKPT");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_uint16(ndr, "system_name", *r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_winreg_AccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_OpenHKPT");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_OpenHKPN(struct ndr_push *ndr, int flags, const struct winreg_OpenHKPN *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.system_name));
+ if (r->in.system_name) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, *r->in.system_name));
+ }
+ NDR_CHECK(ndr_push_winreg_AccessMask(ndr, NDR_SCALARS, r->in.access_mask));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.handle == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_OpenHKPN(struct ndr_pull *ndr, int flags, struct winreg_OpenHKPN *r)
+{
+ uint32_t _ptr_system_name;
+ TALLOC_CTX *_mem_save_system_name_0;
+ TALLOC_CTX *_mem_save_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_system_name));
+ if (_ptr_system_name) {
+ NDR_PULL_ALLOC(ndr, r->in.system_name);
+ } else {
+ r->in.system_name = NULL;
+ }
+ if (r->in.system_name) {
+ _mem_save_system_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.system_name, 0);
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, r->in.system_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_system_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_winreg_AccessMask(ndr, NDR_SCALARS, &r->in.access_mask));
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ ZERO_STRUCTP(r->out.handle);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.handle);
+ }
+ _mem_save_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.handle, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_policy_handle(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_handle_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_OpenHKPN(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKPN *r)
+{
+ ndr_print_struct(ndr, name, "winreg_OpenHKPN");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_OpenHKPN");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "system_name", r->in.system_name);
+ ndr->depth++;
+ if (r->in.system_name) {
+ ndr_print_uint16(ndr, "system_name", *r->in.system_name);
+ }
+ ndr->depth--;
+ ndr_print_winreg_AccessMask(ndr, "access_mask", r->in.access_mask);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_OpenHKPN");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "handle", r->out.handle);
+ ndr->depth++;
+ ndr_print_policy_handle(ndr, "handle", r->out.handle);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_winreg_QueryMultipleValues2(struct ndr_push *ndr, int flags, const struct winreg_QueryMultipleValues2 *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_winreg_QueryMultipleValues2(struct ndr_pull *ndr, int flags, struct winreg_QueryMultipleValues2 *r)
+{
+ if (flags & NDR_IN) {
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_winreg_QueryMultipleValues2(struct ndr_print *ndr, const char *name, int flags, const struct winreg_QueryMultipleValues2 *r)
+{
+ ndr_print_struct(ndr, name, "winreg_QueryMultipleValues2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "winreg_QueryMultipleValues2");
+ ndr->depth++;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "winreg_QueryMultipleValues2");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call winreg_calls[] = {
+ {
+ "winreg_OpenHKCR",
+ sizeof(struct winreg_OpenHKCR),
+ (ndr_push_flags_fn_t) ndr_push_winreg_OpenHKCR,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKCR,
+ (ndr_print_function_t) ndr_print_winreg_OpenHKCR,
+ false,
+ },
+ {
+ "winreg_OpenHKCU",
+ sizeof(struct winreg_OpenHKCU),
+ (ndr_push_flags_fn_t) ndr_push_winreg_OpenHKCU,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKCU,
+ (ndr_print_function_t) ndr_print_winreg_OpenHKCU,
+ false,
+ },
+ {
+ "winreg_OpenHKLM",
+ sizeof(struct winreg_OpenHKLM),
+ (ndr_push_flags_fn_t) ndr_push_winreg_OpenHKLM,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKLM,
+ (ndr_print_function_t) ndr_print_winreg_OpenHKLM,
+ false,
+ },
+ {
+ "winreg_OpenHKPD",
+ sizeof(struct winreg_OpenHKPD),
+ (ndr_push_flags_fn_t) ndr_push_winreg_OpenHKPD,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKPD,
+ (ndr_print_function_t) ndr_print_winreg_OpenHKPD,
+ false,
+ },
+ {
+ "winreg_OpenHKU",
+ sizeof(struct winreg_OpenHKU),
+ (ndr_push_flags_fn_t) ndr_push_winreg_OpenHKU,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKU,
+ (ndr_print_function_t) ndr_print_winreg_OpenHKU,
+ false,
+ },
+ {
+ "winreg_CloseKey",
+ sizeof(struct winreg_CloseKey),
+ (ndr_push_flags_fn_t) ndr_push_winreg_CloseKey,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_CloseKey,
+ (ndr_print_function_t) ndr_print_winreg_CloseKey,
+ false,
+ },
+ {
+ "winreg_CreateKey",
+ sizeof(struct winreg_CreateKey),
+ (ndr_push_flags_fn_t) ndr_push_winreg_CreateKey,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_CreateKey,
+ (ndr_print_function_t) ndr_print_winreg_CreateKey,
+ false,
+ },
+ {
+ "winreg_DeleteKey",
+ sizeof(struct winreg_DeleteKey),
+ (ndr_push_flags_fn_t) ndr_push_winreg_DeleteKey,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_DeleteKey,
+ (ndr_print_function_t) ndr_print_winreg_DeleteKey,
+ false,
+ },
+ {
+ "winreg_DeleteValue",
+ sizeof(struct winreg_DeleteValue),
+ (ndr_push_flags_fn_t) ndr_push_winreg_DeleteValue,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_DeleteValue,
+ (ndr_print_function_t) ndr_print_winreg_DeleteValue,
+ false,
+ },
+ {
+ "winreg_EnumKey",
+ sizeof(struct winreg_EnumKey),
+ (ndr_push_flags_fn_t) ndr_push_winreg_EnumKey,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_EnumKey,
+ (ndr_print_function_t) ndr_print_winreg_EnumKey,
+ false,
+ },
+ {
+ "winreg_EnumValue",
+ sizeof(struct winreg_EnumValue),
+ (ndr_push_flags_fn_t) ndr_push_winreg_EnumValue,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_EnumValue,
+ (ndr_print_function_t) ndr_print_winreg_EnumValue,
+ false,
+ },
+ {
+ "winreg_FlushKey",
+ sizeof(struct winreg_FlushKey),
+ (ndr_push_flags_fn_t) ndr_push_winreg_FlushKey,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_FlushKey,
+ (ndr_print_function_t) ndr_print_winreg_FlushKey,
+ false,
+ },
+ {
+ "winreg_GetKeySecurity",
+ sizeof(struct winreg_GetKeySecurity),
+ (ndr_push_flags_fn_t) ndr_push_winreg_GetKeySecurity,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_GetKeySecurity,
+ (ndr_print_function_t) ndr_print_winreg_GetKeySecurity,
+ false,
+ },
+ {
+ "winreg_LoadKey",
+ sizeof(struct winreg_LoadKey),
+ (ndr_push_flags_fn_t) ndr_push_winreg_LoadKey,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_LoadKey,
+ (ndr_print_function_t) ndr_print_winreg_LoadKey,
+ false,
+ },
+ {
+ "winreg_NotifyChangeKeyValue",
+ sizeof(struct winreg_NotifyChangeKeyValue),
+ (ndr_push_flags_fn_t) ndr_push_winreg_NotifyChangeKeyValue,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_NotifyChangeKeyValue,
+ (ndr_print_function_t) ndr_print_winreg_NotifyChangeKeyValue,
+ false,
+ },
+ {
+ "winreg_OpenKey",
+ sizeof(struct winreg_OpenKey),
+ (ndr_push_flags_fn_t) ndr_push_winreg_OpenKey,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_OpenKey,
+ (ndr_print_function_t) ndr_print_winreg_OpenKey,
+ false,
+ },
+ {
+ "winreg_QueryInfoKey",
+ sizeof(struct winreg_QueryInfoKey),
+ (ndr_push_flags_fn_t) ndr_push_winreg_QueryInfoKey,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_QueryInfoKey,
+ (ndr_print_function_t) ndr_print_winreg_QueryInfoKey,
+ false,
+ },
+ {
+ "winreg_QueryValue",
+ sizeof(struct winreg_QueryValue),
+ (ndr_push_flags_fn_t) ndr_push_winreg_QueryValue,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_QueryValue,
+ (ndr_print_function_t) ndr_print_winreg_QueryValue,
+ false,
+ },
+ {
+ "winreg_ReplaceKey",
+ sizeof(struct winreg_ReplaceKey),
+ (ndr_push_flags_fn_t) ndr_push_winreg_ReplaceKey,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_ReplaceKey,
+ (ndr_print_function_t) ndr_print_winreg_ReplaceKey,
+ false,
+ },
+ {
+ "winreg_RestoreKey",
+ sizeof(struct winreg_RestoreKey),
+ (ndr_push_flags_fn_t) ndr_push_winreg_RestoreKey,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_RestoreKey,
+ (ndr_print_function_t) ndr_print_winreg_RestoreKey,
+ false,
+ },
+ {
+ "winreg_SaveKey",
+ sizeof(struct winreg_SaveKey),
+ (ndr_push_flags_fn_t) ndr_push_winreg_SaveKey,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_SaveKey,
+ (ndr_print_function_t) ndr_print_winreg_SaveKey,
+ false,
+ },
+ {
+ "winreg_SetKeySecurity",
+ sizeof(struct winreg_SetKeySecurity),
+ (ndr_push_flags_fn_t) ndr_push_winreg_SetKeySecurity,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_SetKeySecurity,
+ (ndr_print_function_t) ndr_print_winreg_SetKeySecurity,
+ false,
+ },
+ {
+ "winreg_SetValue",
+ sizeof(struct winreg_SetValue),
+ (ndr_push_flags_fn_t) ndr_push_winreg_SetValue,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_SetValue,
+ (ndr_print_function_t) ndr_print_winreg_SetValue,
+ false,
+ },
+ {
+ "winreg_UnLoadKey",
+ sizeof(struct winreg_UnLoadKey),
+ (ndr_push_flags_fn_t) ndr_push_winreg_UnLoadKey,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_UnLoadKey,
+ (ndr_print_function_t) ndr_print_winreg_UnLoadKey,
+ false,
+ },
+ {
+ "winreg_InitiateSystemShutdown",
+ sizeof(struct winreg_InitiateSystemShutdown),
+ (ndr_push_flags_fn_t) ndr_push_winreg_InitiateSystemShutdown,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_InitiateSystemShutdown,
+ (ndr_print_function_t) ndr_print_winreg_InitiateSystemShutdown,
+ false,
+ },
+ {
+ "winreg_AbortSystemShutdown",
+ sizeof(struct winreg_AbortSystemShutdown),
+ (ndr_push_flags_fn_t) ndr_push_winreg_AbortSystemShutdown,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_AbortSystemShutdown,
+ (ndr_print_function_t) ndr_print_winreg_AbortSystemShutdown,
+ false,
+ },
+ {
+ "winreg_GetVersion",
+ sizeof(struct winreg_GetVersion),
+ (ndr_push_flags_fn_t) ndr_push_winreg_GetVersion,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_GetVersion,
+ (ndr_print_function_t) ndr_print_winreg_GetVersion,
+ false,
+ },
+ {
+ "winreg_OpenHKCC",
+ sizeof(struct winreg_OpenHKCC),
+ (ndr_push_flags_fn_t) ndr_push_winreg_OpenHKCC,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKCC,
+ (ndr_print_function_t) ndr_print_winreg_OpenHKCC,
+ false,
+ },
+ {
+ "winreg_OpenHKDD",
+ sizeof(struct winreg_OpenHKDD),
+ (ndr_push_flags_fn_t) ndr_push_winreg_OpenHKDD,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKDD,
+ (ndr_print_function_t) ndr_print_winreg_OpenHKDD,
+ false,
+ },
+ {
+ "winreg_QueryMultipleValues",
+ sizeof(struct winreg_QueryMultipleValues),
+ (ndr_push_flags_fn_t) ndr_push_winreg_QueryMultipleValues,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_QueryMultipleValues,
+ (ndr_print_function_t) ndr_print_winreg_QueryMultipleValues,
+ false,
+ },
+ {
+ "winreg_InitiateSystemShutdownEx",
+ sizeof(struct winreg_InitiateSystemShutdownEx),
+ (ndr_push_flags_fn_t) ndr_push_winreg_InitiateSystemShutdownEx,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_InitiateSystemShutdownEx,
+ (ndr_print_function_t) ndr_print_winreg_InitiateSystemShutdownEx,
+ false,
+ },
+ {
+ "winreg_SaveKeyEx",
+ sizeof(struct winreg_SaveKeyEx),
+ (ndr_push_flags_fn_t) ndr_push_winreg_SaveKeyEx,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_SaveKeyEx,
+ (ndr_print_function_t) ndr_print_winreg_SaveKeyEx,
+ false,
+ },
+ {
+ "winreg_OpenHKPT",
+ sizeof(struct winreg_OpenHKPT),
+ (ndr_push_flags_fn_t) ndr_push_winreg_OpenHKPT,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKPT,
+ (ndr_print_function_t) ndr_print_winreg_OpenHKPT,
+ false,
+ },
+ {
+ "winreg_OpenHKPN",
+ sizeof(struct winreg_OpenHKPN),
+ (ndr_push_flags_fn_t) ndr_push_winreg_OpenHKPN,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKPN,
+ (ndr_print_function_t) ndr_print_winreg_OpenHKPN,
+ false,
+ },
+ {
+ "winreg_QueryMultipleValues2",
+ sizeof(struct winreg_QueryMultipleValues2),
+ (ndr_push_flags_fn_t) ndr_push_winreg_QueryMultipleValues2,
+ (ndr_pull_flags_fn_t) ndr_pull_winreg_QueryMultipleValues2,
+ (ndr_print_function_t) ndr_print_winreg_QueryMultipleValues2,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const winreg_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\winreg]",
+ "ncacn_ip_tcp:",
+ "ncalrpc:",
+};
+
+static const struct ndr_interface_string_array winreg_endpoints = {
+ .count = 3,
+ .names = winreg_endpoint_strings
+};
+
+static const char * const winreg_authservice_strings[] = {
+ "host",
+};
+
+static const struct ndr_interface_string_array winreg_authservices = {
+ .count = 1,
+ .names = winreg_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_winreg = {
+ .name = "winreg",
+ .syntax_id = {
+ {0x338cd001,0x2244,0x31f1,{0xaa,0xaa},{0x90,0x00,0x38,0x00,0x10,0x03}},
+ NDR_WINREG_VERSION
+ },
+ .helpstring = NDR_WINREG_HELPSTRING,
+ .num_calls = 35,
+ .calls = winreg_calls,
+ .endpoints = &winreg_endpoints,
+ .authservices = &winreg_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_winreg.h b/source3/librpc/gen_ndr/ndr_winreg.h
new file mode 100644
index 0000000000..c093b0d1e0
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_winreg.h
@@ -0,0 +1,132 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/winreg.h"
+
+#ifndef _HEADER_NDR_winreg
+#define _HEADER_NDR_winreg
+
+#define NDR_WINREG_UUID "338cd001-2244-31f1-aaaa-900038001003"
+#define NDR_WINREG_VERSION 1.0
+#define NDR_WINREG_NAME "winreg"
+#define NDR_WINREG_HELPSTRING "Remote Registry Service"
+extern const struct ndr_interface_table ndr_table_winreg;
+#define NDR_WINREG_OPENHKCR (0x00)
+
+#define NDR_WINREG_OPENHKCU (0x01)
+
+#define NDR_WINREG_OPENHKLM (0x02)
+
+#define NDR_WINREG_OPENHKPD (0x03)
+
+#define NDR_WINREG_OPENHKU (0x04)
+
+#define NDR_WINREG_CLOSEKEY (0x05)
+
+#define NDR_WINREG_CREATEKEY (0x06)
+
+#define NDR_WINREG_DELETEKEY (0x07)
+
+#define NDR_WINREG_DELETEVALUE (0x08)
+
+#define NDR_WINREG_ENUMKEY (0x09)
+
+#define NDR_WINREG_ENUMVALUE (0x0a)
+
+#define NDR_WINREG_FLUSHKEY (0x0b)
+
+#define NDR_WINREG_GETKEYSECURITY (0x0c)
+
+#define NDR_WINREG_LOADKEY (0x0d)
+
+#define NDR_WINREG_NOTIFYCHANGEKEYVALUE (0x0e)
+
+#define NDR_WINREG_OPENKEY (0x0f)
+
+#define NDR_WINREG_QUERYINFOKEY (0x10)
+
+#define NDR_WINREG_QUERYVALUE (0x11)
+
+#define NDR_WINREG_REPLACEKEY (0x12)
+
+#define NDR_WINREG_RESTOREKEY (0x13)
+
+#define NDR_WINREG_SAVEKEY (0x14)
+
+#define NDR_WINREG_SETKEYSECURITY (0x15)
+
+#define NDR_WINREG_SETVALUE (0x16)
+
+#define NDR_WINREG_UNLOADKEY (0x17)
+
+#define NDR_WINREG_INITIATESYSTEMSHUTDOWN (0x18)
+
+#define NDR_WINREG_ABORTSYSTEMSHUTDOWN (0x19)
+
+#define NDR_WINREG_GETVERSION (0x1a)
+
+#define NDR_WINREG_OPENHKCC (0x1b)
+
+#define NDR_WINREG_OPENHKDD (0x1c)
+
+#define NDR_WINREG_QUERYMULTIPLEVALUES (0x1d)
+
+#define NDR_WINREG_INITIATESYSTEMSHUTDOWNEX (0x1e)
+
+#define NDR_WINREG_SAVEKEYEX (0x1f)
+
+#define NDR_WINREG_OPENHKPT (0x20)
+
+#define NDR_WINREG_OPENHKPN (0x21)
+
+#define NDR_WINREG_QUERYMULTIPLEVALUES2 (0x22)
+
+#define NDR_WINREG_CALL_COUNT (35)
+void ndr_print_winreg_AccessMask(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_winreg_Type(struct ndr_print *ndr, const char *name, enum winreg_Type r);
+enum ndr_err_code ndr_push_winreg_String(struct ndr_push *ndr, int ndr_flags, const struct winreg_String *r);
+enum ndr_err_code ndr_pull_winreg_String(struct ndr_pull *ndr, int ndr_flags, struct winreg_String *r);
+void ndr_print_winreg_String(struct ndr_print *ndr, const char *name, const struct winreg_String *r);
+void ndr_print_KeySecurityData(struct ndr_print *ndr, const char *name, const struct KeySecurityData *r);
+void ndr_print_winreg_SecBuf(struct ndr_print *ndr, const char *name, const struct winreg_SecBuf *r);
+void ndr_print_winreg_CreateAction(struct ndr_print *ndr, const char *name, enum winreg_CreateAction r);
+void ndr_print_winreg_StringBuf(struct ndr_print *ndr, const char *name, const struct winreg_StringBuf *r);
+void ndr_print_winreg_ValNameBuf(struct ndr_print *ndr, const char *name, const struct winreg_ValNameBuf *r);
+void ndr_print_KeySecurityAttribute(struct ndr_print *ndr, const char *name, const struct KeySecurityAttribute *r);
+void ndr_print_QueryMultipleValue(struct ndr_print *ndr, const char *name, const struct QueryMultipleValue *r);
+void ndr_print_winreg_OpenHKCR(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKCR *r);
+void ndr_print_winreg_OpenHKCU(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKCU *r);
+void ndr_print_winreg_OpenHKLM(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKLM *r);
+void ndr_print_winreg_OpenHKPD(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKPD *r);
+void ndr_print_winreg_OpenHKU(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKU *r);
+void ndr_print_winreg_CloseKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_CloseKey *r);
+void ndr_print_winreg_CreateKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_CreateKey *r);
+void ndr_print_winreg_DeleteKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_DeleteKey *r);
+void ndr_print_winreg_DeleteValue(struct ndr_print *ndr, const char *name, int flags, const struct winreg_DeleteValue *r);
+void ndr_print_winreg_EnumKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_EnumKey *r);
+void ndr_print_winreg_EnumValue(struct ndr_print *ndr, const char *name, int flags, const struct winreg_EnumValue *r);
+void ndr_print_winreg_FlushKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_FlushKey *r);
+void ndr_print_winreg_GetKeySecurity(struct ndr_print *ndr, const char *name, int flags, const struct winreg_GetKeySecurity *r);
+void ndr_print_winreg_LoadKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_LoadKey *r);
+void ndr_print_winreg_NotifyChangeKeyValue(struct ndr_print *ndr, const char *name, int flags, const struct winreg_NotifyChangeKeyValue *r);
+void ndr_print_winreg_OpenKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenKey *r);
+void ndr_print_winreg_QueryInfoKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_QueryInfoKey *r);
+void ndr_print_winreg_QueryValue(struct ndr_print *ndr, const char *name, int flags, const struct winreg_QueryValue *r);
+void ndr_print_winreg_ReplaceKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_ReplaceKey *r);
+void ndr_print_winreg_RestoreKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_RestoreKey *r);
+void ndr_print_winreg_SaveKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_SaveKey *r);
+void ndr_print_winreg_SetKeySecurity(struct ndr_print *ndr, const char *name, int flags, const struct winreg_SetKeySecurity *r);
+void ndr_print_winreg_SetValue(struct ndr_print *ndr, const char *name, int flags, const struct winreg_SetValue *r);
+void ndr_print_winreg_UnLoadKey(struct ndr_print *ndr, const char *name, int flags, const struct winreg_UnLoadKey *r);
+void ndr_print_winreg_InitiateSystemShutdown(struct ndr_print *ndr, const char *name, int flags, const struct winreg_InitiateSystemShutdown *r);
+void ndr_print_winreg_AbortSystemShutdown(struct ndr_print *ndr, const char *name, int flags, const struct winreg_AbortSystemShutdown *r);
+void ndr_print_winreg_GetVersion(struct ndr_print *ndr, const char *name, int flags, const struct winreg_GetVersion *r);
+void ndr_print_winreg_OpenHKCC(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKCC *r);
+void ndr_print_winreg_OpenHKDD(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKDD *r);
+void ndr_print_winreg_QueryMultipleValues(struct ndr_print *ndr, const char *name, int flags, const struct winreg_QueryMultipleValues *r);
+void ndr_print_winreg_InitiateSystemShutdownEx(struct ndr_print *ndr, const char *name, int flags, const struct winreg_InitiateSystemShutdownEx *r);
+void ndr_print_winreg_SaveKeyEx(struct ndr_print *ndr, const char *name, int flags, const struct winreg_SaveKeyEx *r);
+void ndr_print_winreg_OpenHKPT(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKPT *r);
+void ndr_print_winreg_OpenHKPN(struct ndr_print *ndr, const char *name, int flags, const struct winreg_OpenHKPN *r);
+void ndr_print_winreg_QueryMultipleValues2(struct ndr_print *ndr, const char *name, int flags, const struct winreg_QueryMultipleValues2 *r);
+#endif /* _HEADER_NDR_winreg */
diff --git a/source3/librpc/gen_ndr/ndr_wkssvc.c b/source3/librpc/gen_ndr/ndr_wkssvc.c
new file mode 100644
index 0000000000..e494f08be0
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_wkssvc.c
@@ -0,0 +1,10679 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_wkssvc.h"
+
+#include "librpc/gen_ndr/ndr_srvsvc.h"
+#include "librpc/gen_ndr/ndr_lsa.h"
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo100(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo100 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_srvsvc_PlatformId(ndr, NDR_SCALARS, r->platform_id));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->server_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version_major));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version_minor));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->server_name, ndr_charset_length(r->server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->domain_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain_name, ndr_charset_length(r->domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo100(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo100 *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ uint32_t _ptr_domain_name;
+ TALLOC_CTX *_mem_save_domain_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_srvsvc_PlatformId(ndr, NDR_SCALARS, &r->platform_id));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->server_name);
+ } else {
+ r->server_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_name));
+ if (_ptr_domain_name) {
+ NDR_PULL_ALLOC(ndr, r->domain_name);
+ } else {
+ r->domain_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version_major));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version_minor));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->server_name));
+ if (ndr_get_array_length(ndr, &r->server_name) > ndr_get_array_size(ndr, &r->server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->server_name), ndr_get_array_length(ndr, &r->server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->server_name, ndr_get_array_length(ndr, &r->server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ if (r->domain_name) {
+ _mem_save_domain_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain_name));
+ if (ndr_get_array_length(ndr, &r->domain_name) > ndr_get_array_size(ndr, &r->domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain_name), ndr_get_array_length(ndr, &r->domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain_name, ndr_get_array_length(ndr, &r->domain_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_name_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo100(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo100 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo100");
+ ndr->depth++;
+ ndr_print_srvsvc_PlatformId(ndr, "platform_id", r->platform_id);
+ ndr_print_ptr(ndr, "server_name", r->server_name);
+ ndr->depth++;
+ if (r->server_name) {
+ ndr_print_string(ndr, "server_name", r->server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_name", r->domain_name);
+ ndr->depth++;
+ if (r->domain_name) {
+ ndr_print_string(ndr, "domain_name", r->domain_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "version_major", r->version_major);
+ ndr_print_uint32(ndr, "version_minor", r->version_minor);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo101(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo101 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_srvsvc_PlatformId(ndr, NDR_SCALARS, r->platform_id));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->server_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version_major));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version_minor));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->lan_root));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->server_name, ndr_charset_length(r->server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->domain_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain_name, ndr_charset_length(r->domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->lan_root) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->lan_root, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->lan_root, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->lan_root, ndr_charset_length(r->lan_root, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo101(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo101 *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ uint32_t _ptr_domain_name;
+ TALLOC_CTX *_mem_save_domain_name_0;
+ uint32_t _ptr_lan_root;
+ TALLOC_CTX *_mem_save_lan_root_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_srvsvc_PlatformId(ndr, NDR_SCALARS, &r->platform_id));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->server_name);
+ } else {
+ r->server_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_name));
+ if (_ptr_domain_name) {
+ NDR_PULL_ALLOC(ndr, r->domain_name);
+ } else {
+ r->domain_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version_major));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version_minor));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_lan_root));
+ if (_ptr_lan_root) {
+ NDR_PULL_ALLOC(ndr, r->lan_root);
+ } else {
+ r->lan_root = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->server_name));
+ if (ndr_get_array_length(ndr, &r->server_name) > ndr_get_array_size(ndr, &r->server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->server_name), ndr_get_array_length(ndr, &r->server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->server_name, ndr_get_array_length(ndr, &r->server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ if (r->domain_name) {
+ _mem_save_domain_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain_name));
+ if (ndr_get_array_length(ndr, &r->domain_name) > ndr_get_array_size(ndr, &r->domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain_name), ndr_get_array_length(ndr, &r->domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain_name, ndr_get_array_length(ndr, &r->domain_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_name_0, 0);
+ }
+ if (r->lan_root) {
+ _mem_save_lan_root_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->lan_root, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->lan_root));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->lan_root));
+ if (ndr_get_array_length(ndr, &r->lan_root) > ndr_get_array_size(ndr, &r->lan_root)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->lan_root), ndr_get_array_length(ndr, &r->lan_root));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->lan_root), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->lan_root, ndr_get_array_length(ndr, &r->lan_root), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_lan_root_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo101(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo101 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo101");
+ ndr->depth++;
+ ndr_print_srvsvc_PlatformId(ndr, "platform_id", r->platform_id);
+ ndr_print_ptr(ndr, "server_name", r->server_name);
+ ndr->depth++;
+ if (r->server_name) {
+ ndr_print_string(ndr, "server_name", r->server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_name", r->domain_name);
+ ndr->depth++;
+ if (r->domain_name) {
+ ndr_print_string(ndr, "domain_name", r->domain_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "version_major", r->version_major);
+ ndr_print_uint32(ndr, "version_minor", r->version_minor);
+ ndr_print_ptr(ndr, "lan_root", r->lan_root);
+ ndr->depth++;
+ if (r->lan_root) {
+ ndr_print_string(ndr, "lan_root", r->lan_root);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo102(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo102 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_srvsvc_PlatformId(ndr, NDR_SCALARS, r->platform_id));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->server_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain_name));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version_major));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->version_minor));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->lan_root));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->logged_on_users));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->server_name, ndr_charset_length(r->server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->domain_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain_name, ndr_charset_length(r->domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->lan_root) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->lan_root, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->lan_root, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->lan_root, ndr_charset_length(r->lan_root, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo102(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo102 *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ uint32_t _ptr_domain_name;
+ TALLOC_CTX *_mem_save_domain_name_0;
+ uint32_t _ptr_lan_root;
+ TALLOC_CTX *_mem_save_lan_root_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_srvsvc_PlatformId(ndr, NDR_SCALARS, &r->platform_id));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->server_name);
+ } else {
+ r->server_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_name));
+ if (_ptr_domain_name) {
+ NDR_PULL_ALLOC(ndr, r->domain_name);
+ } else {
+ r->domain_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version_major));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->version_minor));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_lan_root));
+ if (_ptr_lan_root) {
+ NDR_PULL_ALLOC(ndr, r->lan_root);
+ } else {
+ r->lan_root = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->logged_on_users));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->server_name));
+ if (ndr_get_array_length(ndr, &r->server_name) > ndr_get_array_size(ndr, &r->server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->server_name), ndr_get_array_length(ndr, &r->server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->server_name, ndr_get_array_length(ndr, &r->server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ if (r->domain_name) {
+ _mem_save_domain_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain_name));
+ if (ndr_get_array_length(ndr, &r->domain_name) > ndr_get_array_size(ndr, &r->domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain_name), ndr_get_array_length(ndr, &r->domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain_name, ndr_get_array_length(ndr, &r->domain_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_name_0, 0);
+ }
+ if (r->lan_root) {
+ _mem_save_lan_root_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->lan_root, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->lan_root));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->lan_root));
+ if (ndr_get_array_length(ndr, &r->lan_root) > ndr_get_array_size(ndr, &r->lan_root)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->lan_root), ndr_get_array_length(ndr, &r->lan_root));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->lan_root), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->lan_root, ndr_get_array_length(ndr, &r->lan_root), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_lan_root_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo102(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo102 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo102");
+ ndr->depth++;
+ ndr_print_srvsvc_PlatformId(ndr, "platform_id", r->platform_id);
+ ndr_print_ptr(ndr, "server_name", r->server_name);
+ ndr->depth++;
+ if (r->server_name) {
+ ndr_print_string(ndr, "server_name", r->server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_name", r->domain_name);
+ ndr->depth++;
+ if (r->domain_name) {
+ ndr_print_string(ndr, "domain_name", r->domain_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "version_major", r->version_major);
+ ndr_print_uint32(ndr, "version_minor", r->version_minor);
+ ndr_print_ptr(ndr, "lan_root", r->lan_root);
+ ndr->depth++;
+ if (r->lan_root) {
+ ndr_print_string(ndr, "lan_root", r->lan_root);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "logged_on_users", r->logged_on_users);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo502(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo502 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->char_wait));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->collection_time));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maximum_collection_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->keep_connection));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_commands));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->session_timeout));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size_char_buf));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_threads));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->lock_quota));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->lock_increment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->lock_maximum));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pipe_increment));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pipe_maximum));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->cache_file_timeout));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->dormant_file_limit));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->read_ahead_throughput));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_mailslot_buffers));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_srv_announce_buffers));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_illegal_dgram_events));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->dgram_event_reset_freq));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->log_election_packets));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_opportunistic_locking));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_unlock_behind));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_close_behind));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->buf_named_pipes));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_lock_read_unlock));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->utilize_nt_caching));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_raw_read));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_raw_write));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_write_raw_data));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_encryption));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->buf_files_deny_write));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->buf_read_only_files));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->force_core_create_mode));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_512_byte_max_transfer));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo502(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo502 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->char_wait));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->collection_time));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maximum_collection_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->keep_connection));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_commands));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->session_timeout));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->size_char_buf));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_threads));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->lock_quota));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->lock_increment));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->lock_maximum));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pipe_increment));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pipe_maximum));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->cache_file_timeout));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->dormant_file_limit));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->read_ahead_throughput));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_mailslot_buffers));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_srv_announce_buffers));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_illegal_dgram_events));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->dgram_event_reset_freq));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->log_election_packets));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_opportunistic_locking));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_unlock_behind));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_close_behind));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->buf_named_pipes));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_lock_read_unlock));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->utilize_nt_caching));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_raw_read));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_raw_write));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_write_raw_data));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_encryption));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->buf_files_deny_write));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->buf_read_only_files));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->force_core_create_mode));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_512_byte_max_transfer));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo502(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo502 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo502");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "char_wait", r->char_wait);
+ ndr_print_uint32(ndr, "collection_time", r->collection_time);
+ ndr_print_uint32(ndr, "maximum_collection_count", r->maximum_collection_count);
+ ndr_print_uint32(ndr, "keep_connection", r->keep_connection);
+ ndr_print_uint32(ndr, "max_commands", r->max_commands);
+ ndr_print_uint32(ndr, "session_timeout", r->session_timeout);
+ ndr_print_uint32(ndr, "size_char_buf", r->size_char_buf);
+ ndr_print_uint32(ndr, "max_threads", r->max_threads);
+ ndr_print_uint32(ndr, "lock_quota", r->lock_quota);
+ ndr_print_uint32(ndr, "lock_increment", r->lock_increment);
+ ndr_print_uint32(ndr, "lock_maximum", r->lock_maximum);
+ ndr_print_uint32(ndr, "pipe_increment", r->pipe_increment);
+ ndr_print_uint32(ndr, "pipe_maximum", r->pipe_maximum);
+ ndr_print_uint32(ndr, "cache_file_timeout", r->cache_file_timeout);
+ ndr_print_uint32(ndr, "dormant_file_limit", r->dormant_file_limit);
+ ndr_print_uint32(ndr, "read_ahead_throughput", r->read_ahead_throughput);
+ ndr_print_uint32(ndr, "num_mailslot_buffers", r->num_mailslot_buffers);
+ ndr_print_uint32(ndr, "num_srv_announce_buffers", r->num_srv_announce_buffers);
+ ndr_print_uint32(ndr, "max_illegal_dgram_events", r->max_illegal_dgram_events);
+ ndr_print_uint32(ndr, "dgram_event_reset_freq", r->dgram_event_reset_freq);
+ ndr_print_uint32(ndr, "log_election_packets", r->log_election_packets);
+ ndr_print_uint32(ndr, "use_opportunistic_locking", r->use_opportunistic_locking);
+ ndr_print_uint32(ndr, "use_unlock_behind", r->use_unlock_behind);
+ ndr_print_uint32(ndr, "use_close_behind", r->use_close_behind);
+ ndr_print_uint32(ndr, "buf_named_pipes", r->buf_named_pipes);
+ ndr_print_uint32(ndr, "use_lock_read_unlock", r->use_lock_read_unlock);
+ ndr_print_uint32(ndr, "utilize_nt_caching", r->utilize_nt_caching);
+ ndr_print_uint32(ndr, "use_raw_read", r->use_raw_read);
+ ndr_print_uint32(ndr, "use_raw_write", r->use_raw_write);
+ ndr_print_uint32(ndr, "use_write_raw_data", r->use_write_raw_data);
+ ndr_print_uint32(ndr, "use_encryption", r->use_encryption);
+ ndr_print_uint32(ndr, "buf_files_deny_write", r->buf_files_deny_write);
+ ndr_print_uint32(ndr, "buf_read_only_files", r->buf_read_only_files);
+ ndr_print_uint32(ndr, "force_core_create_mode", r->force_core_create_mode);
+ ndr_print_uint32(ndr, "use_512_byte_max_transfer", r->use_512_byte_max_transfer);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1010(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1010 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->char_wait));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1010(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1010 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->char_wait));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1010(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1010 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1010");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "char_wait", r->char_wait);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1011(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1011 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->collection_time));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1011(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1011 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->collection_time));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1011(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1011 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1011");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "collection_time", r->collection_time);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1012(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1012 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->maximum_collection_count));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1012(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1012 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->maximum_collection_count));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1012(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1012 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1012");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "maximum_collection_count", r->maximum_collection_count);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1013(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1013 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->keep_connection));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1013(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1013 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->keep_connection));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1013(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1013 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1013");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "keep_connection", r->keep_connection);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1018(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1018 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->session_timeout));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1018(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1018 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->session_timeout));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1018(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1018 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1018");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "session_timeout", r->session_timeout);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1023(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1023 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->size_char_buf));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1023(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1023 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->size_char_buf));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1023(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1023 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1023");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "size_char_buf", r->size_char_buf);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1027(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1027 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->errorlog_sz));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1027(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1027 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->errorlog_sz));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1027(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1027 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1027");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "errorlog_sz", r->errorlog_sz);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1028(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1028 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->print_buf_time));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1028(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1028 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->print_buf_time));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1028(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1028 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1028");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "print_buf_time", r->print_buf_time);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1032(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1032 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->wrk_heuristics));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1032(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1032 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->wrk_heuristics));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1032(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1032 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1032");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "wrk_heuristics", r->wrk_heuristics);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1033(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1033 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_threads));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1033(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1033 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_threads));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1033(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1033 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1033");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "max_threads", r->max_threads);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1041(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1041 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->lock_quota));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1041(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1041 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->lock_quota));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1041(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1041 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1041");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "lock_quota", r->lock_quota);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1042(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1042 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->lock_increment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1042(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1042 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->lock_increment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1042(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1042 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1042");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "lock_increment", r->lock_increment);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1043(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1043 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->lock_maximum));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1043(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1043 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->lock_maximum));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1043(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1043 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1043");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "lock_maximum", r->lock_maximum);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1044(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1044 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pipe_increment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1044(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1044 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pipe_increment));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1044(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1044 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1044");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "pipe_increment", r->pipe_increment);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1045(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1045 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->pipe_maximum));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1045(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1045 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->pipe_maximum));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1045(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1045 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1045");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "pipe_maximum", r->pipe_maximum);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1046(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1046 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->dormant_file_limit));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1046(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1046 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->dormant_file_limit));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1046(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1046 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1046");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "dormant_file_limit", r->dormant_file_limit);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1047(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1047 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->cache_file_timeout));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1047(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1047 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->cache_file_timeout));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1047(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1047 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1047");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "cache_file_timeout", r->cache_file_timeout);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1048(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1048 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_opportunistic_locking));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1048(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1048 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_opportunistic_locking));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1048(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1048 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1048");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "use_opportunistic_locking", r->use_opportunistic_locking);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1049(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1049 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_unlock_behind));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1049(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1049 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_unlock_behind));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1049(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1049 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1049");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "use_unlock_behind", r->use_unlock_behind);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1050(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1050 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_close_behind));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1050(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1050 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_close_behind));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1050(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1050 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1050");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "use_close_behind", r->use_close_behind);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1051(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1051 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->buf_named_pipes));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1051(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1051 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->buf_named_pipes));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1051(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1051 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1051");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "buf_named_pipes", r->buf_named_pipes);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1052(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1052 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_lock_read_unlock));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1052(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1052 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_lock_read_unlock));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1052(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1052 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1052");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "use_lock_read_unlock", r->use_lock_read_unlock);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1053(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1053 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->utilize_nt_caching));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1053(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1053 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->utilize_nt_caching));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1053(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1053 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1053");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "utilize_nt_caching", r->utilize_nt_caching);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1054(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1054 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_raw_read));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1054(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1054 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_raw_read));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1054(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1054 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1054");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "use_raw_read", r->use_raw_read);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1055(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1055 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_raw_write));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1055(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1055 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_raw_write));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1055(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1055 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1055");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "use_raw_write", r->use_raw_write);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1056(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1056 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_write_raw_data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1056(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1056 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_write_raw_data));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1056(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1056 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1056");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "use_write_raw_data", r->use_write_raw_data);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1057(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1057 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_encryption));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1057(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1057 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_encryption));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1057(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1057 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1057");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "use_encryption", r->use_encryption);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1058(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1058 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->buf_files_deny_write));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1058(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1058 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->buf_files_deny_write));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1058(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1058 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1058");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "buf_files_deny_write", r->buf_files_deny_write);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1059(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1059 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->buf_read_only_files));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1059(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1059 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->buf_read_only_files));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1059(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1059 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1059");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "buf_read_only_files", r->buf_read_only_files);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1060(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1060 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->force_core_create_mode));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1060(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1060 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->force_core_create_mode));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1060(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1060 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1060");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "force_core_create_mode", r->force_core_create_mode);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1061(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1061 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_512_byte_max_transfer));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1061(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1061 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_512_byte_max_transfer));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1061(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1061 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1061");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "use_512_byte_max_transfer", r->use_512_byte_max_transfer);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo1062(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaInfo1062 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->read_ahead_throughput));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo1062(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaInfo1062 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->read_ahead_throughput));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo1062(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1062 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaInfo1062");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "read_ahead_throughput", r->read_ahead_throughput);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaInfo(struct ndr_push *ndr, int ndr_flags, const union wkssvc_NetWkstaInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 100: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info100));
+ break; }
+
+ case 101: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info101));
+ break; }
+
+ case 102: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info102));
+ break; }
+
+ case 502: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info502));
+ break; }
+
+ case 1010: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1010));
+ break; }
+
+ case 1011: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1011));
+ break; }
+
+ case 1012: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1012));
+ break; }
+
+ case 1013: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1013));
+ break; }
+
+ case 1018: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1018));
+ break; }
+
+ case 1023: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1023));
+ break; }
+
+ case 1027: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1027));
+ break; }
+
+ case 1028: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1028));
+ break; }
+
+ case 1032: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1032));
+ break; }
+
+ case 1033: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1033));
+ break; }
+
+ case 1041: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1041));
+ break; }
+
+ case 1042: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1042));
+ break; }
+
+ case 1043: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1043));
+ break; }
+
+ case 1044: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1044));
+ break; }
+
+ case 1045: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1045));
+ break; }
+
+ case 1046: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1046));
+ break; }
+
+ case 1047: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1047));
+ break; }
+
+ case 1048: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1048));
+ break; }
+
+ case 1049: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1049));
+ break; }
+
+ case 1050: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1050));
+ break; }
+
+ case 1051: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1051));
+ break; }
+
+ case 1052: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1052));
+ break; }
+
+ case 1053: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1053));
+ break; }
+
+ case 1054: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1054));
+ break; }
+
+ case 1055: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1055));
+ break; }
+
+ case 1056: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1056));
+ break; }
+
+ case 1057: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1057));
+ break; }
+
+ case 1058: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1058));
+ break; }
+
+ case 1059: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1059));
+ break; }
+
+ case 1060: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1060));
+ break; }
+
+ case 1061: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1061));
+ break; }
+
+ case 1062: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1062));
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 100:
+ if (r->info100) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo100(ndr, NDR_SCALARS|NDR_BUFFERS, r->info100));
+ }
+ break;
+
+ case 101:
+ if (r->info101) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo101(ndr, NDR_SCALARS|NDR_BUFFERS, r->info101));
+ }
+ break;
+
+ case 102:
+ if (r->info102) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo102(ndr, NDR_SCALARS|NDR_BUFFERS, r->info102));
+ }
+ break;
+
+ case 502:
+ if (r->info502) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo502(ndr, NDR_SCALARS, r->info502));
+ }
+ break;
+
+ case 1010:
+ if (r->info1010) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1010(ndr, NDR_SCALARS, r->info1010));
+ }
+ break;
+
+ case 1011:
+ if (r->info1011) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1011(ndr, NDR_SCALARS, r->info1011));
+ }
+ break;
+
+ case 1012:
+ if (r->info1012) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1012(ndr, NDR_SCALARS, r->info1012));
+ }
+ break;
+
+ case 1013:
+ if (r->info1013) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1013(ndr, NDR_SCALARS, r->info1013));
+ }
+ break;
+
+ case 1018:
+ if (r->info1018) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1018(ndr, NDR_SCALARS, r->info1018));
+ }
+ break;
+
+ case 1023:
+ if (r->info1023) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1023(ndr, NDR_SCALARS, r->info1023));
+ }
+ break;
+
+ case 1027:
+ if (r->info1027) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1027(ndr, NDR_SCALARS, r->info1027));
+ }
+ break;
+
+ case 1028:
+ if (r->info1028) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1028(ndr, NDR_SCALARS, r->info1028));
+ }
+ break;
+
+ case 1032:
+ if (r->info1032) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1032(ndr, NDR_SCALARS, r->info1032));
+ }
+ break;
+
+ case 1033:
+ if (r->info1033) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1033(ndr, NDR_SCALARS, r->info1033));
+ }
+ break;
+
+ case 1041:
+ if (r->info1041) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1041(ndr, NDR_SCALARS, r->info1041));
+ }
+ break;
+
+ case 1042:
+ if (r->info1042) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1042(ndr, NDR_SCALARS, r->info1042));
+ }
+ break;
+
+ case 1043:
+ if (r->info1043) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1043(ndr, NDR_SCALARS, r->info1043));
+ }
+ break;
+
+ case 1044:
+ if (r->info1044) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1044(ndr, NDR_SCALARS, r->info1044));
+ }
+ break;
+
+ case 1045:
+ if (r->info1045) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1045(ndr, NDR_SCALARS, r->info1045));
+ }
+ break;
+
+ case 1046:
+ if (r->info1046) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1046(ndr, NDR_SCALARS, r->info1046));
+ }
+ break;
+
+ case 1047:
+ if (r->info1047) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1047(ndr, NDR_SCALARS, r->info1047));
+ }
+ break;
+
+ case 1048:
+ if (r->info1048) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1048(ndr, NDR_SCALARS, r->info1048));
+ }
+ break;
+
+ case 1049:
+ if (r->info1049) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1049(ndr, NDR_SCALARS, r->info1049));
+ }
+ break;
+
+ case 1050:
+ if (r->info1050) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1050(ndr, NDR_SCALARS, r->info1050));
+ }
+ break;
+
+ case 1051:
+ if (r->info1051) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1051(ndr, NDR_SCALARS, r->info1051));
+ }
+ break;
+
+ case 1052:
+ if (r->info1052) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1052(ndr, NDR_SCALARS, r->info1052));
+ }
+ break;
+
+ case 1053:
+ if (r->info1053) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1053(ndr, NDR_SCALARS, r->info1053));
+ }
+ break;
+
+ case 1054:
+ if (r->info1054) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1054(ndr, NDR_SCALARS, r->info1054));
+ }
+ break;
+
+ case 1055:
+ if (r->info1055) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1055(ndr, NDR_SCALARS, r->info1055));
+ }
+ break;
+
+ case 1056:
+ if (r->info1056) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1056(ndr, NDR_SCALARS, r->info1056));
+ }
+ break;
+
+ case 1057:
+ if (r->info1057) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1057(ndr, NDR_SCALARS, r->info1057));
+ }
+ break;
+
+ case 1058:
+ if (r->info1058) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1058(ndr, NDR_SCALARS, r->info1058));
+ }
+ break;
+
+ case 1059:
+ if (r->info1059) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1059(ndr, NDR_SCALARS, r->info1059));
+ }
+ break;
+
+ case 1060:
+ if (r->info1060) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1060(ndr, NDR_SCALARS, r->info1060));
+ }
+ break;
+
+ case 1061:
+ if (r->info1061) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1061(ndr, NDR_SCALARS, r->info1061));
+ }
+ break;
+
+ case 1062:
+ if (r->info1062) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo1062(ndr, NDR_SCALARS, r->info1062));
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaInfo(struct ndr_pull *ndr, int ndr_flags, union wkssvc_NetWkstaInfo *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_info100_0;
+ TALLOC_CTX *_mem_save_info101_0;
+ TALLOC_CTX *_mem_save_info102_0;
+ TALLOC_CTX *_mem_save_info502_0;
+ TALLOC_CTX *_mem_save_info1010_0;
+ TALLOC_CTX *_mem_save_info1011_0;
+ TALLOC_CTX *_mem_save_info1012_0;
+ TALLOC_CTX *_mem_save_info1013_0;
+ TALLOC_CTX *_mem_save_info1018_0;
+ TALLOC_CTX *_mem_save_info1023_0;
+ TALLOC_CTX *_mem_save_info1027_0;
+ TALLOC_CTX *_mem_save_info1028_0;
+ TALLOC_CTX *_mem_save_info1032_0;
+ TALLOC_CTX *_mem_save_info1033_0;
+ TALLOC_CTX *_mem_save_info1041_0;
+ TALLOC_CTX *_mem_save_info1042_0;
+ TALLOC_CTX *_mem_save_info1043_0;
+ TALLOC_CTX *_mem_save_info1044_0;
+ TALLOC_CTX *_mem_save_info1045_0;
+ TALLOC_CTX *_mem_save_info1046_0;
+ TALLOC_CTX *_mem_save_info1047_0;
+ TALLOC_CTX *_mem_save_info1048_0;
+ TALLOC_CTX *_mem_save_info1049_0;
+ TALLOC_CTX *_mem_save_info1050_0;
+ TALLOC_CTX *_mem_save_info1051_0;
+ TALLOC_CTX *_mem_save_info1052_0;
+ TALLOC_CTX *_mem_save_info1053_0;
+ TALLOC_CTX *_mem_save_info1054_0;
+ TALLOC_CTX *_mem_save_info1055_0;
+ TALLOC_CTX *_mem_save_info1056_0;
+ TALLOC_CTX *_mem_save_info1057_0;
+ TALLOC_CTX *_mem_save_info1058_0;
+ TALLOC_CTX *_mem_save_info1059_0;
+ TALLOC_CTX *_mem_save_info1060_0;
+ TALLOC_CTX *_mem_save_info1061_0;
+ TALLOC_CTX *_mem_save_info1062_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 100: {
+ uint32_t _ptr_info100;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info100));
+ if (_ptr_info100) {
+ NDR_PULL_ALLOC(ndr, r->info100);
+ } else {
+ r->info100 = NULL;
+ }
+ break; }
+
+ case 101: {
+ uint32_t _ptr_info101;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info101));
+ if (_ptr_info101) {
+ NDR_PULL_ALLOC(ndr, r->info101);
+ } else {
+ r->info101 = NULL;
+ }
+ break; }
+
+ case 102: {
+ uint32_t _ptr_info102;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info102));
+ if (_ptr_info102) {
+ NDR_PULL_ALLOC(ndr, r->info102);
+ } else {
+ r->info102 = NULL;
+ }
+ break; }
+
+ case 502: {
+ uint32_t _ptr_info502;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info502));
+ if (_ptr_info502) {
+ NDR_PULL_ALLOC(ndr, r->info502);
+ } else {
+ r->info502 = NULL;
+ }
+ break; }
+
+ case 1010: {
+ uint32_t _ptr_info1010;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1010));
+ if (_ptr_info1010) {
+ NDR_PULL_ALLOC(ndr, r->info1010);
+ } else {
+ r->info1010 = NULL;
+ }
+ break; }
+
+ case 1011: {
+ uint32_t _ptr_info1011;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1011));
+ if (_ptr_info1011) {
+ NDR_PULL_ALLOC(ndr, r->info1011);
+ } else {
+ r->info1011 = NULL;
+ }
+ break; }
+
+ case 1012: {
+ uint32_t _ptr_info1012;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1012));
+ if (_ptr_info1012) {
+ NDR_PULL_ALLOC(ndr, r->info1012);
+ } else {
+ r->info1012 = NULL;
+ }
+ break; }
+
+ case 1013: {
+ uint32_t _ptr_info1013;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1013));
+ if (_ptr_info1013) {
+ NDR_PULL_ALLOC(ndr, r->info1013);
+ } else {
+ r->info1013 = NULL;
+ }
+ break; }
+
+ case 1018: {
+ uint32_t _ptr_info1018;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1018));
+ if (_ptr_info1018) {
+ NDR_PULL_ALLOC(ndr, r->info1018);
+ } else {
+ r->info1018 = NULL;
+ }
+ break; }
+
+ case 1023: {
+ uint32_t _ptr_info1023;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1023));
+ if (_ptr_info1023) {
+ NDR_PULL_ALLOC(ndr, r->info1023);
+ } else {
+ r->info1023 = NULL;
+ }
+ break; }
+
+ case 1027: {
+ uint32_t _ptr_info1027;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1027));
+ if (_ptr_info1027) {
+ NDR_PULL_ALLOC(ndr, r->info1027);
+ } else {
+ r->info1027 = NULL;
+ }
+ break; }
+
+ case 1028: {
+ uint32_t _ptr_info1028;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1028));
+ if (_ptr_info1028) {
+ NDR_PULL_ALLOC(ndr, r->info1028);
+ } else {
+ r->info1028 = NULL;
+ }
+ break; }
+
+ case 1032: {
+ uint32_t _ptr_info1032;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1032));
+ if (_ptr_info1032) {
+ NDR_PULL_ALLOC(ndr, r->info1032);
+ } else {
+ r->info1032 = NULL;
+ }
+ break; }
+
+ case 1033: {
+ uint32_t _ptr_info1033;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1033));
+ if (_ptr_info1033) {
+ NDR_PULL_ALLOC(ndr, r->info1033);
+ } else {
+ r->info1033 = NULL;
+ }
+ break; }
+
+ case 1041: {
+ uint32_t _ptr_info1041;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1041));
+ if (_ptr_info1041) {
+ NDR_PULL_ALLOC(ndr, r->info1041);
+ } else {
+ r->info1041 = NULL;
+ }
+ break; }
+
+ case 1042: {
+ uint32_t _ptr_info1042;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1042));
+ if (_ptr_info1042) {
+ NDR_PULL_ALLOC(ndr, r->info1042);
+ } else {
+ r->info1042 = NULL;
+ }
+ break; }
+
+ case 1043: {
+ uint32_t _ptr_info1043;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1043));
+ if (_ptr_info1043) {
+ NDR_PULL_ALLOC(ndr, r->info1043);
+ } else {
+ r->info1043 = NULL;
+ }
+ break; }
+
+ case 1044: {
+ uint32_t _ptr_info1044;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1044));
+ if (_ptr_info1044) {
+ NDR_PULL_ALLOC(ndr, r->info1044);
+ } else {
+ r->info1044 = NULL;
+ }
+ break; }
+
+ case 1045: {
+ uint32_t _ptr_info1045;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1045));
+ if (_ptr_info1045) {
+ NDR_PULL_ALLOC(ndr, r->info1045);
+ } else {
+ r->info1045 = NULL;
+ }
+ break; }
+
+ case 1046: {
+ uint32_t _ptr_info1046;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1046));
+ if (_ptr_info1046) {
+ NDR_PULL_ALLOC(ndr, r->info1046);
+ } else {
+ r->info1046 = NULL;
+ }
+ break; }
+
+ case 1047: {
+ uint32_t _ptr_info1047;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1047));
+ if (_ptr_info1047) {
+ NDR_PULL_ALLOC(ndr, r->info1047);
+ } else {
+ r->info1047 = NULL;
+ }
+ break; }
+
+ case 1048: {
+ uint32_t _ptr_info1048;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1048));
+ if (_ptr_info1048) {
+ NDR_PULL_ALLOC(ndr, r->info1048);
+ } else {
+ r->info1048 = NULL;
+ }
+ break; }
+
+ case 1049: {
+ uint32_t _ptr_info1049;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1049));
+ if (_ptr_info1049) {
+ NDR_PULL_ALLOC(ndr, r->info1049);
+ } else {
+ r->info1049 = NULL;
+ }
+ break; }
+
+ case 1050: {
+ uint32_t _ptr_info1050;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1050));
+ if (_ptr_info1050) {
+ NDR_PULL_ALLOC(ndr, r->info1050);
+ } else {
+ r->info1050 = NULL;
+ }
+ break; }
+
+ case 1051: {
+ uint32_t _ptr_info1051;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1051));
+ if (_ptr_info1051) {
+ NDR_PULL_ALLOC(ndr, r->info1051);
+ } else {
+ r->info1051 = NULL;
+ }
+ break; }
+
+ case 1052: {
+ uint32_t _ptr_info1052;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1052));
+ if (_ptr_info1052) {
+ NDR_PULL_ALLOC(ndr, r->info1052);
+ } else {
+ r->info1052 = NULL;
+ }
+ break; }
+
+ case 1053: {
+ uint32_t _ptr_info1053;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1053));
+ if (_ptr_info1053) {
+ NDR_PULL_ALLOC(ndr, r->info1053);
+ } else {
+ r->info1053 = NULL;
+ }
+ break; }
+
+ case 1054: {
+ uint32_t _ptr_info1054;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1054));
+ if (_ptr_info1054) {
+ NDR_PULL_ALLOC(ndr, r->info1054);
+ } else {
+ r->info1054 = NULL;
+ }
+ break; }
+
+ case 1055: {
+ uint32_t _ptr_info1055;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1055));
+ if (_ptr_info1055) {
+ NDR_PULL_ALLOC(ndr, r->info1055);
+ } else {
+ r->info1055 = NULL;
+ }
+ break; }
+
+ case 1056: {
+ uint32_t _ptr_info1056;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1056));
+ if (_ptr_info1056) {
+ NDR_PULL_ALLOC(ndr, r->info1056);
+ } else {
+ r->info1056 = NULL;
+ }
+ break; }
+
+ case 1057: {
+ uint32_t _ptr_info1057;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1057));
+ if (_ptr_info1057) {
+ NDR_PULL_ALLOC(ndr, r->info1057);
+ } else {
+ r->info1057 = NULL;
+ }
+ break; }
+
+ case 1058: {
+ uint32_t _ptr_info1058;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1058));
+ if (_ptr_info1058) {
+ NDR_PULL_ALLOC(ndr, r->info1058);
+ } else {
+ r->info1058 = NULL;
+ }
+ break; }
+
+ case 1059: {
+ uint32_t _ptr_info1059;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1059));
+ if (_ptr_info1059) {
+ NDR_PULL_ALLOC(ndr, r->info1059);
+ } else {
+ r->info1059 = NULL;
+ }
+ break; }
+
+ case 1060: {
+ uint32_t _ptr_info1060;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1060));
+ if (_ptr_info1060) {
+ NDR_PULL_ALLOC(ndr, r->info1060);
+ } else {
+ r->info1060 = NULL;
+ }
+ break; }
+
+ case 1061: {
+ uint32_t _ptr_info1061;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1061));
+ if (_ptr_info1061) {
+ NDR_PULL_ALLOC(ndr, r->info1061);
+ } else {
+ r->info1061 = NULL;
+ }
+ break; }
+
+ case 1062: {
+ uint32_t _ptr_info1062;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1062));
+ if (_ptr_info1062) {
+ NDR_PULL_ALLOC(ndr, r->info1062);
+ } else {
+ r->info1062 = NULL;
+ }
+ break; }
+
+ default: {
+ break; }
+
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 100:
+ if (r->info100) {
+ _mem_save_info100_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info100, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo100(ndr, NDR_SCALARS|NDR_BUFFERS, r->info100));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info100_0, 0);
+ }
+ break;
+
+ case 101:
+ if (r->info101) {
+ _mem_save_info101_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info101, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo101(ndr, NDR_SCALARS|NDR_BUFFERS, r->info101));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info101_0, 0);
+ }
+ break;
+
+ case 102:
+ if (r->info102) {
+ _mem_save_info102_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info102, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo102(ndr, NDR_SCALARS|NDR_BUFFERS, r->info102));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info102_0, 0);
+ }
+ break;
+
+ case 502:
+ if (r->info502) {
+ _mem_save_info502_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info502, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo502(ndr, NDR_SCALARS, r->info502));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info502_0, 0);
+ }
+ break;
+
+ case 1010:
+ if (r->info1010) {
+ _mem_save_info1010_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1010, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1010(ndr, NDR_SCALARS, r->info1010));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1010_0, 0);
+ }
+ break;
+
+ case 1011:
+ if (r->info1011) {
+ _mem_save_info1011_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1011, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1011(ndr, NDR_SCALARS, r->info1011));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1011_0, 0);
+ }
+ break;
+
+ case 1012:
+ if (r->info1012) {
+ _mem_save_info1012_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1012, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1012(ndr, NDR_SCALARS, r->info1012));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1012_0, 0);
+ }
+ break;
+
+ case 1013:
+ if (r->info1013) {
+ _mem_save_info1013_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1013, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1013(ndr, NDR_SCALARS, r->info1013));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1013_0, 0);
+ }
+ break;
+
+ case 1018:
+ if (r->info1018) {
+ _mem_save_info1018_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1018, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1018(ndr, NDR_SCALARS, r->info1018));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1018_0, 0);
+ }
+ break;
+
+ case 1023:
+ if (r->info1023) {
+ _mem_save_info1023_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1023, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1023(ndr, NDR_SCALARS, r->info1023));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1023_0, 0);
+ }
+ break;
+
+ case 1027:
+ if (r->info1027) {
+ _mem_save_info1027_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1027, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1027(ndr, NDR_SCALARS, r->info1027));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1027_0, 0);
+ }
+ break;
+
+ case 1028:
+ if (r->info1028) {
+ _mem_save_info1028_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1028, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1028(ndr, NDR_SCALARS, r->info1028));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1028_0, 0);
+ }
+ break;
+
+ case 1032:
+ if (r->info1032) {
+ _mem_save_info1032_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1032, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1032(ndr, NDR_SCALARS, r->info1032));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1032_0, 0);
+ }
+ break;
+
+ case 1033:
+ if (r->info1033) {
+ _mem_save_info1033_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1033, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1033(ndr, NDR_SCALARS, r->info1033));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1033_0, 0);
+ }
+ break;
+
+ case 1041:
+ if (r->info1041) {
+ _mem_save_info1041_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1041, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1041(ndr, NDR_SCALARS, r->info1041));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1041_0, 0);
+ }
+ break;
+
+ case 1042:
+ if (r->info1042) {
+ _mem_save_info1042_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1042, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1042(ndr, NDR_SCALARS, r->info1042));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1042_0, 0);
+ }
+ break;
+
+ case 1043:
+ if (r->info1043) {
+ _mem_save_info1043_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1043, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1043(ndr, NDR_SCALARS, r->info1043));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1043_0, 0);
+ }
+ break;
+
+ case 1044:
+ if (r->info1044) {
+ _mem_save_info1044_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1044, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1044(ndr, NDR_SCALARS, r->info1044));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1044_0, 0);
+ }
+ break;
+
+ case 1045:
+ if (r->info1045) {
+ _mem_save_info1045_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1045, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1045(ndr, NDR_SCALARS, r->info1045));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1045_0, 0);
+ }
+ break;
+
+ case 1046:
+ if (r->info1046) {
+ _mem_save_info1046_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1046, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1046(ndr, NDR_SCALARS, r->info1046));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1046_0, 0);
+ }
+ break;
+
+ case 1047:
+ if (r->info1047) {
+ _mem_save_info1047_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1047, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1047(ndr, NDR_SCALARS, r->info1047));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1047_0, 0);
+ }
+ break;
+
+ case 1048:
+ if (r->info1048) {
+ _mem_save_info1048_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1048, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1048(ndr, NDR_SCALARS, r->info1048));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1048_0, 0);
+ }
+ break;
+
+ case 1049:
+ if (r->info1049) {
+ _mem_save_info1049_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1049, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1049(ndr, NDR_SCALARS, r->info1049));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1049_0, 0);
+ }
+ break;
+
+ case 1050:
+ if (r->info1050) {
+ _mem_save_info1050_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1050, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1050(ndr, NDR_SCALARS, r->info1050));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1050_0, 0);
+ }
+ break;
+
+ case 1051:
+ if (r->info1051) {
+ _mem_save_info1051_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1051, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1051(ndr, NDR_SCALARS, r->info1051));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1051_0, 0);
+ }
+ break;
+
+ case 1052:
+ if (r->info1052) {
+ _mem_save_info1052_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1052, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1052(ndr, NDR_SCALARS, r->info1052));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1052_0, 0);
+ }
+ break;
+
+ case 1053:
+ if (r->info1053) {
+ _mem_save_info1053_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1053, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1053(ndr, NDR_SCALARS, r->info1053));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1053_0, 0);
+ }
+ break;
+
+ case 1054:
+ if (r->info1054) {
+ _mem_save_info1054_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1054, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1054(ndr, NDR_SCALARS, r->info1054));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1054_0, 0);
+ }
+ break;
+
+ case 1055:
+ if (r->info1055) {
+ _mem_save_info1055_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1055, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1055(ndr, NDR_SCALARS, r->info1055));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1055_0, 0);
+ }
+ break;
+
+ case 1056:
+ if (r->info1056) {
+ _mem_save_info1056_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1056, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1056(ndr, NDR_SCALARS, r->info1056));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1056_0, 0);
+ }
+ break;
+
+ case 1057:
+ if (r->info1057) {
+ _mem_save_info1057_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1057, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1057(ndr, NDR_SCALARS, r->info1057));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1057_0, 0);
+ }
+ break;
+
+ case 1058:
+ if (r->info1058) {
+ _mem_save_info1058_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1058, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1058(ndr, NDR_SCALARS, r->info1058));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1058_0, 0);
+ }
+ break;
+
+ case 1059:
+ if (r->info1059) {
+ _mem_save_info1059_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1059, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1059(ndr, NDR_SCALARS, r->info1059));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1059_0, 0);
+ }
+ break;
+
+ case 1060:
+ if (r->info1060) {
+ _mem_save_info1060_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1060, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1060(ndr, NDR_SCALARS, r->info1060));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1060_0, 0);
+ }
+ break;
+
+ case 1061:
+ if (r->info1061) {
+ _mem_save_info1061_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1061, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1061(ndr, NDR_SCALARS, r->info1061));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1061_0, 0);
+ }
+ break;
+
+ case 1062:
+ if (r->info1062) {
+ _mem_save_info1062_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1062, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo1062(ndr, NDR_SCALARS, r->info1062));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1062_0, 0);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaInfo(struct ndr_print *ndr, const char *name, const union wkssvc_NetWkstaInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "wkssvc_NetWkstaInfo");
+ switch (level) {
+ case 100:
+ ndr_print_ptr(ndr, "info100", r->info100);
+ ndr->depth++;
+ if (r->info100) {
+ ndr_print_wkssvc_NetWkstaInfo100(ndr, "info100", r->info100);
+ }
+ ndr->depth--;
+ break;
+
+ case 101:
+ ndr_print_ptr(ndr, "info101", r->info101);
+ ndr->depth++;
+ if (r->info101) {
+ ndr_print_wkssvc_NetWkstaInfo101(ndr, "info101", r->info101);
+ }
+ ndr->depth--;
+ break;
+
+ case 102:
+ ndr_print_ptr(ndr, "info102", r->info102);
+ ndr->depth++;
+ if (r->info102) {
+ ndr_print_wkssvc_NetWkstaInfo102(ndr, "info102", r->info102);
+ }
+ ndr->depth--;
+ break;
+
+ case 502:
+ ndr_print_ptr(ndr, "info502", r->info502);
+ ndr->depth++;
+ if (r->info502) {
+ ndr_print_wkssvc_NetWkstaInfo502(ndr, "info502", r->info502);
+ }
+ ndr->depth--;
+ break;
+
+ case 1010:
+ ndr_print_ptr(ndr, "info1010", r->info1010);
+ ndr->depth++;
+ if (r->info1010) {
+ ndr_print_wkssvc_NetWkstaInfo1010(ndr, "info1010", r->info1010);
+ }
+ ndr->depth--;
+ break;
+
+ case 1011:
+ ndr_print_ptr(ndr, "info1011", r->info1011);
+ ndr->depth++;
+ if (r->info1011) {
+ ndr_print_wkssvc_NetWkstaInfo1011(ndr, "info1011", r->info1011);
+ }
+ ndr->depth--;
+ break;
+
+ case 1012:
+ ndr_print_ptr(ndr, "info1012", r->info1012);
+ ndr->depth++;
+ if (r->info1012) {
+ ndr_print_wkssvc_NetWkstaInfo1012(ndr, "info1012", r->info1012);
+ }
+ ndr->depth--;
+ break;
+
+ case 1013:
+ ndr_print_ptr(ndr, "info1013", r->info1013);
+ ndr->depth++;
+ if (r->info1013) {
+ ndr_print_wkssvc_NetWkstaInfo1013(ndr, "info1013", r->info1013);
+ }
+ ndr->depth--;
+ break;
+
+ case 1018:
+ ndr_print_ptr(ndr, "info1018", r->info1018);
+ ndr->depth++;
+ if (r->info1018) {
+ ndr_print_wkssvc_NetWkstaInfo1018(ndr, "info1018", r->info1018);
+ }
+ ndr->depth--;
+ break;
+
+ case 1023:
+ ndr_print_ptr(ndr, "info1023", r->info1023);
+ ndr->depth++;
+ if (r->info1023) {
+ ndr_print_wkssvc_NetWkstaInfo1023(ndr, "info1023", r->info1023);
+ }
+ ndr->depth--;
+ break;
+
+ case 1027:
+ ndr_print_ptr(ndr, "info1027", r->info1027);
+ ndr->depth++;
+ if (r->info1027) {
+ ndr_print_wkssvc_NetWkstaInfo1027(ndr, "info1027", r->info1027);
+ }
+ ndr->depth--;
+ break;
+
+ case 1028:
+ ndr_print_ptr(ndr, "info1028", r->info1028);
+ ndr->depth++;
+ if (r->info1028) {
+ ndr_print_wkssvc_NetWkstaInfo1028(ndr, "info1028", r->info1028);
+ }
+ ndr->depth--;
+ break;
+
+ case 1032:
+ ndr_print_ptr(ndr, "info1032", r->info1032);
+ ndr->depth++;
+ if (r->info1032) {
+ ndr_print_wkssvc_NetWkstaInfo1032(ndr, "info1032", r->info1032);
+ }
+ ndr->depth--;
+ break;
+
+ case 1033:
+ ndr_print_ptr(ndr, "info1033", r->info1033);
+ ndr->depth++;
+ if (r->info1033) {
+ ndr_print_wkssvc_NetWkstaInfo1033(ndr, "info1033", r->info1033);
+ }
+ ndr->depth--;
+ break;
+
+ case 1041:
+ ndr_print_ptr(ndr, "info1041", r->info1041);
+ ndr->depth++;
+ if (r->info1041) {
+ ndr_print_wkssvc_NetWkstaInfo1041(ndr, "info1041", r->info1041);
+ }
+ ndr->depth--;
+ break;
+
+ case 1042:
+ ndr_print_ptr(ndr, "info1042", r->info1042);
+ ndr->depth++;
+ if (r->info1042) {
+ ndr_print_wkssvc_NetWkstaInfo1042(ndr, "info1042", r->info1042);
+ }
+ ndr->depth--;
+ break;
+
+ case 1043:
+ ndr_print_ptr(ndr, "info1043", r->info1043);
+ ndr->depth++;
+ if (r->info1043) {
+ ndr_print_wkssvc_NetWkstaInfo1043(ndr, "info1043", r->info1043);
+ }
+ ndr->depth--;
+ break;
+
+ case 1044:
+ ndr_print_ptr(ndr, "info1044", r->info1044);
+ ndr->depth++;
+ if (r->info1044) {
+ ndr_print_wkssvc_NetWkstaInfo1044(ndr, "info1044", r->info1044);
+ }
+ ndr->depth--;
+ break;
+
+ case 1045:
+ ndr_print_ptr(ndr, "info1045", r->info1045);
+ ndr->depth++;
+ if (r->info1045) {
+ ndr_print_wkssvc_NetWkstaInfo1045(ndr, "info1045", r->info1045);
+ }
+ ndr->depth--;
+ break;
+
+ case 1046:
+ ndr_print_ptr(ndr, "info1046", r->info1046);
+ ndr->depth++;
+ if (r->info1046) {
+ ndr_print_wkssvc_NetWkstaInfo1046(ndr, "info1046", r->info1046);
+ }
+ ndr->depth--;
+ break;
+
+ case 1047:
+ ndr_print_ptr(ndr, "info1047", r->info1047);
+ ndr->depth++;
+ if (r->info1047) {
+ ndr_print_wkssvc_NetWkstaInfo1047(ndr, "info1047", r->info1047);
+ }
+ ndr->depth--;
+ break;
+
+ case 1048:
+ ndr_print_ptr(ndr, "info1048", r->info1048);
+ ndr->depth++;
+ if (r->info1048) {
+ ndr_print_wkssvc_NetWkstaInfo1048(ndr, "info1048", r->info1048);
+ }
+ ndr->depth--;
+ break;
+
+ case 1049:
+ ndr_print_ptr(ndr, "info1049", r->info1049);
+ ndr->depth++;
+ if (r->info1049) {
+ ndr_print_wkssvc_NetWkstaInfo1049(ndr, "info1049", r->info1049);
+ }
+ ndr->depth--;
+ break;
+
+ case 1050:
+ ndr_print_ptr(ndr, "info1050", r->info1050);
+ ndr->depth++;
+ if (r->info1050) {
+ ndr_print_wkssvc_NetWkstaInfo1050(ndr, "info1050", r->info1050);
+ }
+ ndr->depth--;
+ break;
+
+ case 1051:
+ ndr_print_ptr(ndr, "info1051", r->info1051);
+ ndr->depth++;
+ if (r->info1051) {
+ ndr_print_wkssvc_NetWkstaInfo1051(ndr, "info1051", r->info1051);
+ }
+ ndr->depth--;
+ break;
+
+ case 1052:
+ ndr_print_ptr(ndr, "info1052", r->info1052);
+ ndr->depth++;
+ if (r->info1052) {
+ ndr_print_wkssvc_NetWkstaInfo1052(ndr, "info1052", r->info1052);
+ }
+ ndr->depth--;
+ break;
+
+ case 1053:
+ ndr_print_ptr(ndr, "info1053", r->info1053);
+ ndr->depth++;
+ if (r->info1053) {
+ ndr_print_wkssvc_NetWkstaInfo1053(ndr, "info1053", r->info1053);
+ }
+ ndr->depth--;
+ break;
+
+ case 1054:
+ ndr_print_ptr(ndr, "info1054", r->info1054);
+ ndr->depth++;
+ if (r->info1054) {
+ ndr_print_wkssvc_NetWkstaInfo1054(ndr, "info1054", r->info1054);
+ }
+ ndr->depth--;
+ break;
+
+ case 1055:
+ ndr_print_ptr(ndr, "info1055", r->info1055);
+ ndr->depth++;
+ if (r->info1055) {
+ ndr_print_wkssvc_NetWkstaInfo1055(ndr, "info1055", r->info1055);
+ }
+ ndr->depth--;
+ break;
+
+ case 1056:
+ ndr_print_ptr(ndr, "info1056", r->info1056);
+ ndr->depth++;
+ if (r->info1056) {
+ ndr_print_wkssvc_NetWkstaInfo1056(ndr, "info1056", r->info1056);
+ }
+ ndr->depth--;
+ break;
+
+ case 1057:
+ ndr_print_ptr(ndr, "info1057", r->info1057);
+ ndr->depth++;
+ if (r->info1057) {
+ ndr_print_wkssvc_NetWkstaInfo1057(ndr, "info1057", r->info1057);
+ }
+ ndr->depth--;
+ break;
+
+ case 1058:
+ ndr_print_ptr(ndr, "info1058", r->info1058);
+ ndr->depth++;
+ if (r->info1058) {
+ ndr_print_wkssvc_NetWkstaInfo1058(ndr, "info1058", r->info1058);
+ }
+ ndr->depth--;
+ break;
+
+ case 1059:
+ ndr_print_ptr(ndr, "info1059", r->info1059);
+ ndr->depth++;
+ if (r->info1059) {
+ ndr_print_wkssvc_NetWkstaInfo1059(ndr, "info1059", r->info1059);
+ }
+ ndr->depth--;
+ break;
+
+ case 1060:
+ ndr_print_ptr(ndr, "info1060", r->info1060);
+ ndr->depth++;
+ if (r->info1060) {
+ ndr_print_wkssvc_NetWkstaInfo1060(ndr, "info1060", r->info1060);
+ }
+ ndr->depth--;
+ break;
+
+ case 1061:
+ ndr_print_ptr(ndr, "info1061", r->info1061);
+ ndr->depth++;
+ if (r->info1061) {
+ ndr_print_wkssvc_NetWkstaInfo1061(ndr, "info1061", r->info1061);
+ }
+ ndr->depth--;
+ break;
+
+ case 1062:
+ ndr_print_ptr(ndr, "info1062", r->info1062);
+ ndr->depth++;
+ if (r->info1062) {
+ ndr_print_wkssvc_NetWkstaInfo1062(ndr, "info1062", r->info1062);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrWkstaUserInfo0(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetrWkstaUserInfo0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->user_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->user_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->user_name, ndr_charset_length(r->user_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrWkstaUserInfo0(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetrWkstaUserInfo0 *r)
+{
+ uint32_t _ptr_user_name;
+ TALLOC_CTX *_mem_save_user_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user_name));
+ if (_ptr_user_name) {
+ NDR_PULL_ALLOC(ndr, r->user_name);
+ } else {
+ r->user_name = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->user_name) {
+ _mem_save_user_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->user_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->user_name));
+ if (ndr_get_array_length(ndr, &r->user_name) > ndr_get_array_size(ndr, &r->user_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->user_name), ndr_get_array_length(ndr, &r->user_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->user_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->user_name, ndr_get_array_length(ndr, &r->user_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_name_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrWkstaUserInfo0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrWkstaUserInfo0 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrWkstaUserInfo0");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "user_name", r->user_name);
+ ndr->depth++;
+ if (r->user_name) {
+ ndr_print_string(ndr, "user_name", r->user_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaEnumUsersCtr0(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaEnumUsersCtr0 *r)
+{
+ uint32_t cntr_user0_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->entries_read));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->user0));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->user0) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->entries_read));
+ for (cntr_user0_1 = 0; cntr_user0_1 < r->entries_read; cntr_user0_1++) {
+ NDR_CHECK(ndr_push_wkssvc_NetrWkstaUserInfo0(ndr, NDR_SCALARS, &r->user0[cntr_user0_1]));
+ }
+ for (cntr_user0_1 = 0; cntr_user0_1 < r->entries_read; cntr_user0_1++) {
+ NDR_CHECK(ndr_push_wkssvc_NetrWkstaUserInfo0(ndr, NDR_BUFFERS, &r->user0[cntr_user0_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaEnumUsersCtr0(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaEnumUsersCtr0 *r)
+{
+ uint32_t _ptr_user0;
+ uint32_t cntr_user0_1;
+ TALLOC_CTX *_mem_save_user0_0;
+ TALLOC_CTX *_mem_save_user0_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->entries_read));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user0));
+ if (_ptr_user0) {
+ NDR_PULL_ALLOC(ndr, r->user0);
+ } else {
+ r->user0 = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->user0) {
+ _mem_save_user0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user0, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->user0));
+ NDR_PULL_ALLOC_N(ndr, r->user0, ndr_get_array_size(ndr, &r->user0));
+ _mem_save_user0_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user0, 0);
+ for (cntr_user0_1 = 0; cntr_user0_1 < r->entries_read; cntr_user0_1++) {
+ NDR_CHECK(ndr_pull_wkssvc_NetrWkstaUserInfo0(ndr, NDR_SCALARS, &r->user0[cntr_user0_1]));
+ }
+ for (cntr_user0_1 = 0; cntr_user0_1 < r->entries_read; cntr_user0_1++) {
+ NDR_CHECK(ndr_pull_wkssvc_NetrWkstaUserInfo0(ndr, NDR_BUFFERS, &r->user0[cntr_user0_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user0_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user0_0, 0);
+ }
+ if (r->user0) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->user0, r->entries_read));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaEnumUsersCtr0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaEnumUsersCtr0 *r)
+{
+ uint32_t cntr_user0_1;
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaEnumUsersCtr0");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "entries_read", r->entries_read);
+ ndr_print_ptr(ndr, "user0", r->user0);
+ ndr->depth++;
+ if (r->user0) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "user0", (int)r->entries_read);
+ ndr->depth++;
+ for (cntr_user0_1=0;cntr_user0_1<r->entries_read;cntr_user0_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_user0_1) != -1) {
+ ndr_print_wkssvc_NetrWkstaUserInfo0(ndr, "user0", &r->user0[cntr_user0_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrWkstaUserInfo1(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetrWkstaUserInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->user_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->logon_domain));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->other_domains));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->logon_server));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->user_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->user_name, ndr_charset_length(r->user_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->logon_domain) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->logon_domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->logon_domain, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->logon_domain, ndr_charset_length(r->logon_domain, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->other_domains) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->other_domains, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->other_domains, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->other_domains, ndr_charset_length(r->other_domains, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->logon_server) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->logon_server, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->logon_server, ndr_charset_length(r->logon_server, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrWkstaUserInfo1(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetrWkstaUserInfo1 *r)
+{
+ uint32_t _ptr_user_name;
+ TALLOC_CTX *_mem_save_user_name_0;
+ uint32_t _ptr_logon_domain;
+ TALLOC_CTX *_mem_save_logon_domain_0;
+ uint32_t _ptr_other_domains;
+ TALLOC_CTX *_mem_save_other_domains_0;
+ uint32_t _ptr_logon_server;
+ TALLOC_CTX *_mem_save_logon_server_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user_name));
+ if (_ptr_user_name) {
+ NDR_PULL_ALLOC(ndr, r->user_name);
+ } else {
+ r->user_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_logon_domain));
+ if (_ptr_logon_domain) {
+ NDR_PULL_ALLOC(ndr, r->logon_domain);
+ } else {
+ r->logon_domain = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_other_domains));
+ if (_ptr_other_domains) {
+ NDR_PULL_ALLOC(ndr, r->other_domains);
+ } else {
+ r->other_domains = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_logon_server));
+ if (_ptr_logon_server) {
+ NDR_PULL_ALLOC(ndr, r->logon_server);
+ } else {
+ r->logon_server = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->user_name) {
+ _mem_save_user_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->user_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->user_name));
+ if (ndr_get_array_length(ndr, &r->user_name) > ndr_get_array_size(ndr, &r->user_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->user_name), ndr_get_array_length(ndr, &r->user_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->user_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->user_name, ndr_get_array_length(ndr, &r->user_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_name_0, 0);
+ }
+ if (r->logon_domain) {
+ _mem_save_logon_domain_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->logon_domain, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->logon_domain));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->logon_domain));
+ if (ndr_get_array_length(ndr, &r->logon_domain) > ndr_get_array_size(ndr, &r->logon_domain)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->logon_domain), ndr_get_array_length(ndr, &r->logon_domain));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->logon_domain), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->logon_domain, ndr_get_array_length(ndr, &r->logon_domain), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_logon_domain_0, 0);
+ }
+ if (r->other_domains) {
+ _mem_save_other_domains_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->other_domains, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->other_domains));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->other_domains));
+ if (ndr_get_array_length(ndr, &r->other_domains) > ndr_get_array_size(ndr, &r->other_domains)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->other_domains), ndr_get_array_length(ndr, &r->other_domains));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->other_domains), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->other_domains, ndr_get_array_length(ndr, &r->other_domains), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_other_domains_0, 0);
+ }
+ if (r->logon_server) {
+ _mem_save_logon_server_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->logon_server, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->logon_server));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->logon_server));
+ if (ndr_get_array_length(ndr, &r->logon_server) > ndr_get_array_size(ndr, &r->logon_server)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->logon_server), ndr_get_array_length(ndr, &r->logon_server));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->logon_server), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->logon_server, ndr_get_array_length(ndr, &r->logon_server), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_logon_server_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrWkstaUserInfo1(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrWkstaUserInfo1 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrWkstaUserInfo1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "user_name", r->user_name);
+ ndr->depth++;
+ if (r->user_name) {
+ ndr_print_string(ndr, "user_name", r->user_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "logon_domain", r->logon_domain);
+ ndr->depth++;
+ if (r->logon_domain) {
+ ndr_print_string(ndr, "logon_domain", r->logon_domain);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "other_domains", r->other_domains);
+ ndr->depth++;
+ if (r->other_domains) {
+ ndr_print_string(ndr, "other_domains", r->other_domains);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "logon_server", r->logon_server);
+ ndr->depth++;
+ if (r->logon_server) {
+ ndr_print_string(ndr, "logon_server", r->logon_server);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaEnumUsersCtr1(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaEnumUsersCtr1 *r)
+{
+ uint32_t cntr_user1_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->entries_read));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->user1));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->user1) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->entries_read));
+ for (cntr_user1_1 = 0; cntr_user1_1 < r->entries_read; cntr_user1_1++) {
+ NDR_CHECK(ndr_push_wkssvc_NetrWkstaUserInfo1(ndr, NDR_SCALARS, &r->user1[cntr_user1_1]));
+ }
+ for (cntr_user1_1 = 0; cntr_user1_1 < r->entries_read; cntr_user1_1++) {
+ NDR_CHECK(ndr_push_wkssvc_NetrWkstaUserInfo1(ndr, NDR_BUFFERS, &r->user1[cntr_user1_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaEnumUsersCtr1(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaEnumUsersCtr1 *r)
+{
+ uint32_t _ptr_user1;
+ uint32_t cntr_user1_1;
+ TALLOC_CTX *_mem_save_user1_0;
+ TALLOC_CTX *_mem_save_user1_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->entries_read));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user1));
+ if (_ptr_user1) {
+ NDR_PULL_ALLOC(ndr, r->user1);
+ } else {
+ r->user1 = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->user1) {
+ _mem_save_user1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user1, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->user1));
+ NDR_PULL_ALLOC_N(ndr, r->user1, ndr_get_array_size(ndr, &r->user1));
+ _mem_save_user1_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user1, 0);
+ for (cntr_user1_1 = 0; cntr_user1_1 < r->entries_read; cntr_user1_1++) {
+ NDR_CHECK(ndr_pull_wkssvc_NetrWkstaUserInfo1(ndr, NDR_SCALARS, &r->user1[cntr_user1_1]));
+ }
+ for (cntr_user1_1 = 0; cntr_user1_1 < r->entries_read; cntr_user1_1++) {
+ NDR_CHECK(ndr_pull_wkssvc_NetrWkstaUserInfo1(ndr, NDR_BUFFERS, &r->user1[cntr_user1_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user1_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user1_0, 0);
+ }
+ if (r->user1) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->user1, r->entries_read));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaEnumUsersCtr1(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaEnumUsersCtr1 *r)
+{
+ uint32_t cntr_user1_1;
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaEnumUsersCtr1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "entries_read", r->entries_read);
+ ndr_print_ptr(ndr, "user1", r->user1);
+ ndr->depth++;
+ if (r->user1) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "user1", (int)r->entries_read);
+ ndr->depth++;
+ for (cntr_user1_1=0;cntr_user1_1<r->entries_read;cntr_user1_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_user1_1) != -1) {
+ ndr_print_wkssvc_NetrWkstaUserInfo1(ndr, "user1", &r->user1[cntr_user1_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaEnumUsersCtr(struct ndr_push *ndr, int ndr_flags, const union wkssvc_NetWkstaEnumUsersCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->user0));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->user1));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ if (r->user0) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaEnumUsersCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->user0));
+ }
+ break;
+
+ case 1:
+ if (r->user1) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaEnumUsersCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->user1));
+ }
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaEnumUsersCtr(struct ndr_pull *ndr, int ndr_flags, union wkssvc_NetWkstaEnumUsersCtr *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_user0_0;
+ TALLOC_CTX *_mem_save_user1_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 0: {
+ uint32_t _ptr_user0;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user0));
+ if (_ptr_user0) {
+ NDR_PULL_ALLOC(ndr, r->user0);
+ } else {
+ r->user0 = NULL;
+ }
+ break; }
+
+ case 1: {
+ uint32_t _ptr_user1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user1));
+ if (_ptr_user1) {
+ NDR_PULL_ALLOC(ndr, r->user1);
+ } else {
+ r->user1 = NULL;
+ }
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ if (r->user0) {
+ _mem_save_user0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user0, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaEnumUsersCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->user0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user0_0, 0);
+ }
+ break;
+
+ case 1:
+ if (r->user1) {
+ _mem_save_user1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user1, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaEnumUsersCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->user1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user1_0, 0);
+ }
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaEnumUsersCtr(struct ndr_print *ndr, const char *name, const union wkssvc_NetWkstaEnumUsersCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "wkssvc_NetWkstaEnumUsersCtr");
+ switch (level) {
+ case 0:
+ ndr_print_ptr(ndr, "user0", r->user0);
+ ndr->depth++;
+ if (r->user0) {
+ ndr_print_wkssvc_NetWkstaEnumUsersCtr0(ndr, "user0", r->user0);
+ }
+ ndr->depth--;
+ break;
+
+ case 1:
+ ndr_print_ptr(ndr, "user1", r->user1);
+ ndr->depth++;
+ if (r->user1) {
+ ndr_print_wkssvc_NetWkstaEnumUsersCtr1(ndr, "user1", r->user1);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaEnumUsersInfo(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaEnumUsersInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->ctr, r->level));
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaEnumUsersCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaEnumUsersCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaEnumUsersInfo(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaEnumUsersInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->ctr, r->level));
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaEnumUsersCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaEnumUsersCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaEnumUsersInfo(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaEnumUsersInfo *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaEnumUsersInfo");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level", r->level);
+ ndr_print_set_switch_value(ndr, &r->ctr, r->level);
+ ndr_print_wkssvc_NetWkstaEnumUsersCtr(ndr, "ctr", &r->ctr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrWkstaUserInfo1101(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetrWkstaUserInfo1101 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->other_domains));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->other_domains) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->other_domains, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->other_domains, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->other_domains, ndr_charset_length(r->other_domains, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrWkstaUserInfo1101(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetrWkstaUserInfo1101 *r)
+{
+ uint32_t _ptr_other_domains;
+ TALLOC_CTX *_mem_save_other_domains_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_other_domains));
+ if (_ptr_other_domains) {
+ NDR_PULL_ALLOC(ndr, r->other_domains);
+ } else {
+ r->other_domains = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->other_domains) {
+ _mem_save_other_domains_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->other_domains, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->other_domains));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->other_domains));
+ if (ndr_get_array_length(ndr, &r->other_domains) > ndr_get_array_size(ndr, &r->other_domains)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->other_domains), ndr_get_array_length(ndr, &r->other_domains));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->other_domains), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->other_domains, ndr_get_array_length(ndr, &r->other_domains), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_other_domains_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrWkstaUserInfo1101(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrWkstaUserInfo1101 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrWkstaUserInfo1101");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "other_domains", r->other_domains);
+ ndr->depth++;
+ if (r->other_domains) {
+ ndr_print_string(ndr, "other_domains", r->other_domains);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrWkstaUserInfo(struct ndr_push *ndr, int ndr_flags, const union wkssvc_NetrWkstaUserInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info0));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1));
+ break; }
+
+ case 1101: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1101));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ if (r->info0) {
+ NDR_CHECK(ndr_push_wkssvc_NetrWkstaUserInfo0(ndr, NDR_SCALARS|NDR_BUFFERS, r->info0));
+ }
+ break;
+
+ case 1:
+ if (r->info1) {
+ NDR_CHECK(ndr_push_wkssvc_NetrWkstaUserInfo1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ }
+ break;
+
+ case 1101:
+ if (r->info1101) {
+ NDR_CHECK(ndr_push_wkssvc_NetrWkstaUserInfo1101(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1101));
+ }
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrWkstaUserInfo(struct ndr_pull *ndr, int ndr_flags, union wkssvc_NetrWkstaUserInfo *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_info0_0;
+ TALLOC_CTX *_mem_save_info1_0;
+ TALLOC_CTX *_mem_save_info1101_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 0: {
+ uint32_t _ptr_info0;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info0));
+ if (_ptr_info0) {
+ NDR_PULL_ALLOC(ndr, r->info0);
+ } else {
+ r->info0 = NULL;
+ }
+ break; }
+
+ case 1: {
+ uint32_t _ptr_info1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1));
+ if (_ptr_info1) {
+ NDR_PULL_ALLOC(ndr, r->info1);
+ } else {
+ r->info1 = NULL;
+ }
+ break; }
+
+ case 1101: {
+ uint32_t _ptr_info1101;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1101));
+ if (_ptr_info1101) {
+ NDR_PULL_ALLOC(ndr, r->info1101);
+ } else {
+ r->info1101 = NULL;
+ }
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ if (r->info0) {
+ _mem_save_info0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info0, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetrWkstaUserInfo0(ndr, NDR_SCALARS|NDR_BUFFERS, r->info0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info0_0, 0);
+ }
+ break;
+
+ case 1:
+ if (r->info1) {
+ _mem_save_info1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetrWkstaUserInfo1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1_0, 0);
+ }
+ break;
+
+ case 1101:
+ if (r->info1101) {
+ _mem_save_info1101_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1101, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetrWkstaUserInfo1101(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1101));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1101_0, 0);
+ }
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrWkstaUserInfo(struct ndr_print *ndr, const char *name, const union wkssvc_NetrWkstaUserInfo *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "wkssvc_NetrWkstaUserInfo");
+ switch (level) {
+ case 0:
+ ndr_print_ptr(ndr, "info0", r->info0);
+ ndr->depth++;
+ if (r->info0) {
+ ndr_print_wkssvc_NetrWkstaUserInfo0(ndr, "info0", r->info0);
+ }
+ ndr->depth--;
+ break;
+
+ case 1:
+ ndr_print_ptr(ndr, "info1", r->info1);
+ ndr->depth++;
+ if (r->info1) {
+ ndr_print_wkssvc_NetrWkstaUserInfo1(ndr, "info1", r->info1);
+ }
+ ndr->depth--;
+ break;
+
+ case 1101:
+ ndr_print_ptr(ndr, "info1101", r->info1101);
+ ndr->depth++;
+ if (r->info1101) {
+ ndr_print_wkssvc_NetrWkstaUserInfo1101(ndr, "info1101", r->info1101);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaTransportInfo0(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaTransportInfo0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->quality_of_service));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->vc_count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->address));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->wan_link));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->name, ndr_charset_length(r->name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->address) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->address, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->address, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->address, ndr_charset_length(r->address, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaTransportInfo0(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaTransportInfo0 *r)
+{
+ uint32_t _ptr_name;
+ TALLOC_CTX *_mem_save_name_0;
+ uint32_t _ptr_address;
+ TALLOC_CTX *_mem_save_address_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->quality_of_service));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->vc_count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name));
+ if (_ptr_name) {
+ NDR_PULL_ALLOC(ndr, r->name);
+ } else {
+ r->name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_address));
+ if (_ptr_address) {
+ NDR_PULL_ALLOC(ndr, r->address);
+ } else {
+ r->address = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->wan_link));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->name) {
+ _mem_save_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->name));
+ if (ndr_get_array_length(ndr, &r->name) > ndr_get_array_size(ndr, &r->name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->name), ndr_get_array_length(ndr, &r->name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->name, ndr_get_array_length(ndr, &r->name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_0, 0);
+ }
+ if (r->address) {
+ _mem_save_address_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->address, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->address));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->address));
+ if (ndr_get_array_length(ndr, &r->address) > ndr_get_array_size(ndr, &r->address)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->address), ndr_get_array_length(ndr, &r->address));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->address), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->address, ndr_get_array_length(ndr, &r->address), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_address_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaTransportInfo0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaTransportInfo0 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaTransportInfo0");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "quality_of_service", r->quality_of_service);
+ ndr_print_uint32(ndr, "vc_count", r->vc_count);
+ ndr_print_ptr(ndr, "name", r->name);
+ ndr->depth++;
+ if (r->name) {
+ ndr_print_string(ndr, "name", r->name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "address", r->address);
+ ndr->depth++;
+ if (r->address) {
+ ndr_print_string(ndr, "address", r->address);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "wan_link", r->wan_link);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaTransportCtr0(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaTransportCtr0 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaTransportInfo0(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaTransportInfo0(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaTransportCtr0(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaTransportCtr0 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaTransportInfo0(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaTransportInfo0(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaTransportCtr0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaTransportCtr0 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaTransportCtr0");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_wkssvc_NetWkstaTransportInfo0(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaTransportCtr(struct ndr_push *ndr, int ndr_flags, const union wkssvc_NetWkstaTransportCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr0));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ if (r->ctr0) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaTransportCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr0));
+ }
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaTransportCtr(struct ndr_pull *ndr, int ndr_flags, union wkssvc_NetWkstaTransportCtr *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_ctr0_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 0: {
+ uint32_t _ptr_ctr0;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr0));
+ if (_ptr_ctr0) {
+ NDR_PULL_ALLOC(ndr, r->ctr0);
+ } else {
+ r->ctr0 = NULL;
+ }
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ if (r->ctr0) {
+ _mem_save_ctr0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr0, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaTransportCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr0_0, 0);
+ }
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaTransportCtr(struct ndr_print *ndr, const char *name, const union wkssvc_NetWkstaTransportCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "wkssvc_NetWkstaTransportCtr");
+ switch (level) {
+ case 0:
+ ndr_print_ptr(ndr, "ctr0", r->ctr0);
+ ndr->depth++;
+ if (r->ctr0) {
+ ndr_print_wkssvc_NetWkstaTransportCtr0(ndr, "ctr0", r->ctr0);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaTransportInfo(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetWkstaTransportInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->ctr, r->level));
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaTransportCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaTransportCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaTransportInfo(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetWkstaTransportInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->ctr, r->level));
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaTransportCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaTransportCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaTransportInfo(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaTransportInfo *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaTransportInfo");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level", r->level);
+ ndr_print_set_switch_value(ndr, &r->ctr, r->level);
+ ndr_print_wkssvc_NetWkstaTransportCtr(ndr, "ctr", &r->ctr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrUseInfo3(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetrUseInfo3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->unknown1));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->unknown2));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->unknown1) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->unknown1, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->unknown1, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->unknown1, ndr_charset_length(r->unknown1, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->unknown2) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->unknown2, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->unknown2, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->unknown2, ndr_charset_length(r->unknown2, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrUseInfo3(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetrUseInfo3 *r)
+{
+ uint32_t _ptr_unknown1;
+ TALLOC_CTX *_mem_save_unknown1_0;
+ uint32_t _ptr_unknown2;
+ TALLOC_CTX *_mem_save_unknown2_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown1));
+ if (_ptr_unknown1) {
+ NDR_PULL_ALLOC(ndr, r->unknown1);
+ } else {
+ r->unknown1 = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown2));
+ if (_ptr_unknown2) {
+ NDR_PULL_ALLOC(ndr, r->unknown2);
+ } else {
+ r->unknown2 = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->unknown1) {
+ _mem_save_unknown1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->unknown1, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->unknown1));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->unknown1));
+ if (ndr_get_array_length(ndr, &r->unknown1) > ndr_get_array_size(ndr, &r->unknown1)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->unknown1), ndr_get_array_length(ndr, &r->unknown1));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->unknown1), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->unknown1, ndr_get_array_length(ndr, &r->unknown1), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown1_0, 0);
+ }
+ if (r->unknown2) {
+ _mem_save_unknown2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->unknown2, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->unknown2));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->unknown2));
+ if (ndr_get_array_length(ndr, &r->unknown2) > ndr_get_array_size(ndr, &r->unknown2)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->unknown2), ndr_get_array_length(ndr, &r->unknown2));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->unknown2), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->unknown2, ndr_get_array_length(ndr, &r->unknown2), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown2_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrUseInfo3(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseInfo3 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrUseInfo3");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "unknown1", r->unknown1);
+ ndr->depth++;
+ if (r->unknown1) {
+ ndr_print_string(ndr, "unknown1", r->unknown1);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "unknown2", r->unknown2);
+ ndr->depth++;
+ if (r->unknown2) {
+ ndr_print_string(ndr, "unknown2", r->unknown2);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrUseInfo2(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetrUseInfo2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->local));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->remote));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->password));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->status));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->asg_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ref_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->user_name));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->domain_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->local) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->local, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->local, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->local, ndr_charset_length(r->local, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->remote) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->remote, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->remote, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->remote, ndr_charset_length(r->remote, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->password) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->password, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->password, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->password, ndr_charset_length(r->password, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->user_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->user_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->user_name, ndr_charset_length(r->user_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->domain_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->domain_name, ndr_charset_length(r->domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrUseInfo2(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetrUseInfo2 *r)
+{
+ uint32_t _ptr_local;
+ TALLOC_CTX *_mem_save_local_0;
+ uint32_t _ptr_remote;
+ TALLOC_CTX *_mem_save_remote_0;
+ uint32_t _ptr_password;
+ TALLOC_CTX *_mem_save_password_0;
+ uint32_t _ptr_user_name;
+ TALLOC_CTX *_mem_save_user_name_0;
+ uint32_t _ptr_domain_name;
+ TALLOC_CTX *_mem_save_domain_name_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_local));
+ if (_ptr_local) {
+ NDR_PULL_ALLOC(ndr, r->local);
+ } else {
+ r->local = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_remote));
+ if (_ptr_remote) {
+ NDR_PULL_ALLOC(ndr, r->remote);
+ } else {
+ r->remote = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password));
+ if (_ptr_password) {
+ NDR_PULL_ALLOC(ndr, r->password);
+ } else {
+ r->password = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->status));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->asg_type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->ref_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_user_name));
+ if (_ptr_user_name) {
+ NDR_PULL_ALLOC(ndr, r->user_name);
+ } else {
+ r->user_name = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_domain_name));
+ if (_ptr_domain_name) {
+ NDR_PULL_ALLOC(ndr, r->domain_name);
+ } else {
+ r->domain_name = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->local) {
+ _mem_save_local_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->local, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->local));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->local));
+ if (ndr_get_array_length(ndr, &r->local) > ndr_get_array_size(ndr, &r->local)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->local), ndr_get_array_length(ndr, &r->local));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->local), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->local, ndr_get_array_length(ndr, &r->local), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_local_0, 0);
+ }
+ if (r->remote) {
+ _mem_save_remote_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->remote, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->remote));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->remote));
+ if (ndr_get_array_length(ndr, &r->remote) > ndr_get_array_size(ndr, &r->remote)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->remote), ndr_get_array_length(ndr, &r->remote));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->remote), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->remote, ndr_get_array_length(ndr, &r->remote), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_remote_0, 0);
+ }
+ if (r->password) {
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->password, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->password));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->password));
+ if (ndr_get_array_length(ndr, &r->password) > ndr_get_array_size(ndr, &r->password)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->password), ndr_get_array_length(ndr, &r->password));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->password), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->password, ndr_get_array_length(ndr, &r->password), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, 0);
+ }
+ if (r->user_name) {
+ _mem_save_user_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->user_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->user_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->user_name));
+ if (ndr_get_array_length(ndr, &r->user_name) > ndr_get_array_size(ndr, &r->user_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->user_name), ndr_get_array_length(ndr, &r->user_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->user_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->user_name, ndr_get_array_length(ndr, &r->user_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_user_name_0, 0);
+ }
+ if (r->domain_name) {
+ _mem_save_domain_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->domain_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->domain_name));
+ if (ndr_get_array_length(ndr, &r->domain_name) > ndr_get_array_size(ndr, &r->domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->domain_name), ndr_get_array_length(ndr, &r->domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->domain_name, ndr_get_array_length(ndr, &r->domain_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_domain_name_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrUseInfo2(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseInfo2 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrUseInfo2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "local", r->local);
+ ndr->depth++;
+ if (r->local) {
+ ndr_print_string(ndr, "local", r->local);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "remote", r->remote);
+ ndr->depth++;
+ if (r->remote) {
+ ndr_print_string(ndr, "remote", r->remote);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->password);
+ ndr->depth++;
+ if (r->password) {
+ ndr_print_string(ndr, "password", r->password);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "status", r->status);
+ ndr_print_uint32(ndr, "asg_type", r->asg_type);
+ ndr_print_uint32(ndr, "ref_count", r->ref_count);
+ ndr_print_uint32(ndr, "use_count", r->use_count);
+ ndr_print_ptr(ndr, "user_name", r->user_name);
+ ndr->depth++;
+ if (r->user_name) {
+ ndr_print_string(ndr, "user_name", r->user_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_name", r->domain_name);
+ ndr->depth++;
+ if (r->domain_name) {
+ ndr_print_string(ndr, "domain_name", r->domain_name);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrUseInfo1(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetrUseInfo1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->local));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->remote));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->password));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->status));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->asg_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ref_count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->use_count));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->local) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->local, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->local, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->local, ndr_charset_length(r->local, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->remote) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->remote, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->remote, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->remote, ndr_charset_length(r->remote, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->password) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->password, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->password, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->password, ndr_charset_length(r->password, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrUseInfo1(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetrUseInfo1 *r)
+{
+ uint32_t _ptr_local;
+ TALLOC_CTX *_mem_save_local_0;
+ uint32_t _ptr_remote;
+ TALLOC_CTX *_mem_save_remote_0;
+ uint32_t _ptr_password;
+ TALLOC_CTX *_mem_save_password_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_local));
+ if (_ptr_local) {
+ NDR_PULL_ALLOC(ndr, r->local);
+ } else {
+ r->local = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_remote));
+ if (_ptr_remote) {
+ NDR_PULL_ALLOC(ndr, r->remote);
+ } else {
+ r->remote = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password));
+ if (_ptr_password) {
+ NDR_PULL_ALLOC(ndr, r->password);
+ } else {
+ r->password = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->status));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->asg_type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->ref_count));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->use_count));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->local) {
+ _mem_save_local_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->local, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->local));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->local));
+ if (ndr_get_array_length(ndr, &r->local) > ndr_get_array_size(ndr, &r->local)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->local), ndr_get_array_length(ndr, &r->local));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->local), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->local, ndr_get_array_length(ndr, &r->local), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_local_0, 0);
+ }
+ if (r->remote) {
+ _mem_save_remote_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->remote, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->remote));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->remote));
+ if (ndr_get_array_length(ndr, &r->remote) > ndr_get_array_size(ndr, &r->remote)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->remote), ndr_get_array_length(ndr, &r->remote));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->remote), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->remote, ndr_get_array_length(ndr, &r->remote), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_remote_0, 0);
+ }
+ if (r->password) {
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->password, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->password));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->password));
+ if (ndr_get_array_length(ndr, &r->password) > ndr_get_array_size(ndr, &r->password)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->password), ndr_get_array_length(ndr, &r->password));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->password), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->password, ndr_get_array_length(ndr, &r->password), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrUseInfo1(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseInfo1 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrUseInfo1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "local", r->local);
+ ndr->depth++;
+ if (r->local) {
+ ndr_print_string(ndr, "local", r->local);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "remote", r->remote);
+ ndr->depth++;
+ if (r->remote) {
+ ndr_print_string(ndr, "remote", r->remote);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->password);
+ ndr->depth++;
+ if (r->password) {
+ ndr_print_string(ndr, "password", r->password);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "status", r->status);
+ ndr_print_uint32(ndr, "asg_type", r->asg_type);
+ ndr_print_uint32(ndr, "ref_count", r->ref_count);
+ ndr_print_uint32(ndr, "use_count", r->use_count);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrUseInfo0(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetrUseInfo0 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->local));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->remote));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->local) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->local, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->local, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->local, ndr_charset_length(r->local, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->remote) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->remote, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->remote, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->remote, ndr_charset_length(r->remote, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrUseInfo0(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetrUseInfo0 *r)
+{
+ uint32_t _ptr_local;
+ TALLOC_CTX *_mem_save_local_0;
+ uint32_t _ptr_remote;
+ TALLOC_CTX *_mem_save_remote_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_local));
+ if (_ptr_local) {
+ NDR_PULL_ALLOC(ndr, r->local);
+ } else {
+ r->local = NULL;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_remote));
+ if (_ptr_remote) {
+ NDR_PULL_ALLOC(ndr, r->remote);
+ } else {
+ r->remote = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->local) {
+ _mem_save_local_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->local, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->local));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->local));
+ if (ndr_get_array_length(ndr, &r->local) > ndr_get_array_size(ndr, &r->local)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->local), ndr_get_array_length(ndr, &r->local));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->local), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->local, ndr_get_array_length(ndr, &r->local), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_local_0, 0);
+ }
+ if (r->remote) {
+ _mem_save_remote_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->remote, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->remote));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->remote));
+ if (ndr_get_array_length(ndr, &r->remote) > ndr_get_array_size(ndr, &r->remote)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->remote), ndr_get_array_length(ndr, &r->remote));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->remote), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->remote, ndr_get_array_length(ndr, &r->remote), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_remote_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrUseInfo0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseInfo0 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrUseInfo0");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "local", r->local);
+ ndr->depth++;
+ if (r->local) {
+ ndr_print_string(ndr, "local", r->local);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "remote", r->remote);
+ ndr->depth++;
+ if (r->remote) {
+ ndr_print_string(ndr, "remote", r->remote);
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrUseGetInfoCtr(struct ndr_push *ndr, int ndr_flags, const union wkssvc_NetrUseGetInfoCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info0));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info2));
+ break; }
+
+ case 3: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->info3));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ if (r->info0) {
+ NDR_CHECK(ndr_push_wkssvc_NetrUseInfo0(ndr, NDR_SCALARS|NDR_BUFFERS, r->info0));
+ }
+ break;
+
+ case 1:
+ if (r->info1) {
+ NDR_CHECK(ndr_push_wkssvc_NetrUseInfo1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ }
+ break;
+
+ case 2:
+ if (r->info2) {
+ NDR_CHECK(ndr_push_wkssvc_NetrUseInfo2(ndr, NDR_SCALARS|NDR_BUFFERS, r->info2));
+ }
+ break;
+
+ case 3:
+ if (r->info3) {
+ NDR_CHECK(ndr_push_wkssvc_NetrUseInfo3(ndr, NDR_SCALARS|NDR_BUFFERS, r->info3));
+ }
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrUseGetInfoCtr(struct ndr_pull *ndr, int ndr_flags, union wkssvc_NetrUseGetInfoCtr *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_info0_0;
+ TALLOC_CTX *_mem_save_info1_0;
+ TALLOC_CTX *_mem_save_info2_0;
+ TALLOC_CTX *_mem_save_info3_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 0: {
+ uint32_t _ptr_info0;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info0));
+ if (_ptr_info0) {
+ NDR_PULL_ALLOC(ndr, r->info0);
+ } else {
+ r->info0 = NULL;
+ }
+ break; }
+
+ case 1: {
+ uint32_t _ptr_info1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info1));
+ if (_ptr_info1) {
+ NDR_PULL_ALLOC(ndr, r->info1);
+ } else {
+ r->info1 = NULL;
+ }
+ break; }
+
+ case 2: {
+ uint32_t _ptr_info2;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info2));
+ if (_ptr_info2) {
+ NDR_PULL_ALLOC(ndr, r->info2);
+ } else {
+ r->info2 = NULL;
+ }
+ break; }
+
+ case 3: {
+ uint32_t _ptr_info3;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info3));
+ if (_ptr_info3) {
+ NDR_PULL_ALLOC(ndr, r->info3);
+ } else {
+ r->info3 = NULL;
+ }
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ if (r->info0) {
+ _mem_save_info0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info0, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseInfo0(ndr, NDR_SCALARS|NDR_BUFFERS, r->info0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info0_0, 0);
+ }
+ break;
+
+ case 1:
+ if (r->info1) {
+ _mem_save_info1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info1, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseInfo1(ndr, NDR_SCALARS|NDR_BUFFERS, r->info1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info1_0, 0);
+ }
+ break;
+
+ case 2:
+ if (r->info2) {
+ _mem_save_info2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info2, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseInfo2(ndr, NDR_SCALARS|NDR_BUFFERS, r->info2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info2_0, 0);
+ }
+ break;
+
+ case 3:
+ if (r->info3) {
+ _mem_save_info3_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info3, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseInfo3(ndr, NDR_SCALARS|NDR_BUFFERS, r->info3));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info3_0, 0);
+ }
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrUseGetInfoCtr(struct ndr_print *ndr, const char *name, const union wkssvc_NetrUseGetInfoCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "wkssvc_NetrUseGetInfoCtr");
+ switch (level) {
+ case 0:
+ ndr_print_ptr(ndr, "info0", r->info0);
+ ndr->depth++;
+ if (r->info0) {
+ ndr_print_wkssvc_NetrUseInfo0(ndr, "info0", r->info0);
+ }
+ ndr->depth--;
+ break;
+
+ case 1:
+ ndr_print_ptr(ndr, "info1", r->info1);
+ ndr->depth++;
+ if (r->info1) {
+ ndr_print_wkssvc_NetrUseInfo1(ndr, "info1", r->info1);
+ }
+ ndr->depth--;
+ break;
+
+ case 2:
+ ndr_print_ptr(ndr, "info2", r->info2);
+ ndr->depth++;
+ if (r->info2) {
+ ndr_print_wkssvc_NetrUseInfo2(ndr, "info2", r->info2);
+ }
+ ndr->depth--;
+ break;
+
+ case 3:
+ ndr_print_ptr(ndr, "info3", r->info3);
+ ndr->depth++;
+ if (r->info3) {
+ ndr_print_wkssvc_NetrUseInfo3(ndr, "info3", r->info3);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrUseEnumCtr2(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetrUseEnumCtr2 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_wkssvc_NetrUseInfo2(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_wkssvc_NetrUseInfo2(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrUseEnumCtr2(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetrUseEnumCtr2 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseInfo2(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseInfo2(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrUseEnumCtr2(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseEnumCtr2 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "wkssvc_NetrUseEnumCtr2");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_wkssvc_NetrUseInfo2(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrUseEnumCtr1(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetrUseEnumCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_wkssvc_NetrUseInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_wkssvc_NetrUseInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrUseEnumCtr1(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetrUseEnumCtr1 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseInfo1(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseInfo1(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrUseEnumCtr1(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseEnumCtr1 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "wkssvc_NetrUseEnumCtr1");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_wkssvc_NetrUseInfo1(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrUseEnumCtr0(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetrUseEnumCtr0 *r)
+{
+ uint32_t cntr_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->array));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_wkssvc_NetrUseInfo0(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_wkssvc_NetrUseInfo0(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrUseEnumCtr0(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetrUseEnumCtr0 *r)
+{
+ uint32_t _ptr_array;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0;
+ TALLOC_CTX *_mem_save_array_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ } else {
+ r->array = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ NDR_PULL_ALLOC_N(ndr, r->array, ndr_get_array_size(ndr, &r->array));
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseInfo0(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < r->count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseInfo0(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ }
+ if (r->array) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->array, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrUseEnumCtr0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseEnumCtr0 *r)
+{
+ uint32_t cntr_array_1;
+ ndr_print_struct(ndr, name, "wkssvc_NetrUseEnumCtr0");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "array", r->array);
+ ndr->depth++;
+ if (r->array) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "array", (int)r->count);
+ ndr->depth++;
+ for (cntr_array_1=0;cntr_array_1<r->count;cntr_array_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_array_1) != -1) {
+ ndr_print_wkssvc_NetrUseInfo0(ndr, "array", &r->array[cntr_array_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrUseEnumCtr(struct ndr_push *ndr, int ndr_flags, const union wkssvc_NetrUseEnumCtr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 0: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr0));
+ break; }
+
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr1));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ctr2));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 0:
+ if (r->ctr0) {
+ NDR_CHECK(ndr_push_wkssvc_NetrUseEnumCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr0));
+ }
+ break;
+
+ case 1:
+ if (r->ctr1) {
+ NDR_CHECK(ndr_push_wkssvc_NetrUseEnumCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ }
+ break;
+
+ case 2:
+ if (r->ctr2) {
+ NDR_CHECK(ndr_push_wkssvc_NetrUseEnumCtr2(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr2));
+ }
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrUseEnumCtr(struct ndr_pull *ndr, int ndr_flags, union wkssvc_NetrUseEnumCtr *r)
+{
+ int level;
+ uint32_t _level;
+ TALLOC_CTX *_mem_save_ctr0_0;
+ TALLOC_CTX *_mem_save_ctr1_0;
+ TALLOC_CTX *_mem_save_ctr2_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 0: {
+ uint32_t _ptr_ctr0;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr0));
+ if (_ptr_ctr0) {
+ NDR_PULL_ALLOC(ndr, r->ctr0);
+ } else {
+ r->ctr0 = NULL;
+ }
+ break; }
+
+ case 1: {
+ uint32_t _ptr_ctr1;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr1));
+ if (_ptr_ctr1) {
+ NDR_PULL_ALLOC(ndr, r->ctr1);
+ } else {
+ r->ctr1 = NULL;
+ }
+ break; }
+
+ case 2: {
+ uint32_t _ptr_ctr2;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr2));
+ if (_ptr_ctr2) {
+ NDR_PULL_ALLOC(ndr, r->ctr2);
+ } else {
+ r->ctr2 = NULL;
+ }
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 0:
+ if (r->ctr0) {
+ _mem_save_ctr0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr0, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseEnumCtr0(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr0_0, 0);
+ }
+ break;
+
+ case 1:
+ if (r->ctr1) {
+ _mem_save_ctr1_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr1, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseEnumCtr1(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr1));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr1_0, 0);
+ }
+ break;
+
+ case 2:
+ if (r->ctr2) {
+ _mem_save_ctr2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->ctr2, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseEnumCtr2(ndr, NDR_SCALARS|NDR_BUFFERS, r->ctr2));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr2_0, 0);
+ }
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrUseEnumCtr(struct ndr_print *ndr, const char *name, const union wkssvc_NetrUseEnumCtr *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "wkssvc_NetrUseEnumCtr");
+ switch (level) {
+ case 0:
+ ndr_print_ptr(ndr, "ctr0", r->ctr0);
+ ndr->depth++;
+ if (r->ctr0) {
+ ndr_print_wkssvc_NetrUseEnumCtr0(ndr, "ctr0", r->ctr0);
+ }
+ ndr->depth--;
+ break;
+
+ case 1:
+ ndr_print_ptr(ndr, "ctr1", r->ctr1);
+ ndr->depth++;
+ if (r->ctr1) {
+ ndr_print_wkssvc_NetrUseEnumCtr1(ndr, "ctr1", r->ctr1);
+ }
+ ndr->depth--;
+ break;
+
+ case 2:
+ ndr_print_ptr(ndr, "ctr2", r->ctr2);
+ ndr->depth++;
+ if (r->ctr2) {
+ ndr_print_wkssvc_NetrUseEnumCtr2(ndr, "ctr2", r->ctr2);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrUseEnumInfo(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetrUseEnumInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->level));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->ctr, r->level));
+ NDR_CHECK(ndr_push_wkssvc_NetrUseEnumCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_wkssvc_NetrUseEnumCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrUseEnumInfo(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetrUseEnumInfo *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->level));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->ctr, r->level));
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseEnumCtr(ndr, NDR_SCALARS, &r->ctr));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseEnumCtr(ndr, NDR_BUFFERS, &r->ctr));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrUseEnumInfo(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseEnumInfo *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrUseEnumInfo");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "level", r->level);
+ ndr_print_set_switch_value(ndr, &r->ctr, r->level);
+ ndr_print_wkssvc_NetrUseEnumCtr(ndr, "ctr", &r->ctr);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrWorkstationStatistics(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_NetrWorkstationStatistics *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown1));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown2));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown3));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown4));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown5));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown6));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown7));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown8));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown9));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown10));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown11));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown12));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->unknown13));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown14));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown15));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown17));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown18));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown19));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown20));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown21));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown22));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown23));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown24));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown25));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown26));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown27));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown28));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown29));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown30));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown31));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown32));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown33));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown34));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown35));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown36));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown37));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown38));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown39));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->unknown40));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrWorkstationStatistics(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_NetrWorkstationStatistics *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown1));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown2));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown3));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown4));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown5));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown6));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown7));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown8));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown9));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown10));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown11));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown12));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->unknown13));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown14));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown15));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown17));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown18));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown19));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown20));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown21));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown22));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown23));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown24));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown25));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown26));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown27));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown28));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown29));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown30));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown31));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown32));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown33));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown34));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown35));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown36));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown37));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown38));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown39));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->unknown40));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrWorkstationStatistics(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrWorkstationStatistics *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrWorkstationStatistics");
+ ndr->depth++;
+ ndr_print_hyper(ndr, "unknown1", r->unknown1);
+ ndr_print_hyper(ndr, "unknown2", r->unknown2);
+ ndr_print_hyper(ndr, "unknown3", r->unknown3);
+ ndr_print_hyper(ndr, "unknown4", r->unknown4);
+ ndr_print_hyper(ndr, "unknown5", r->unknown5);
+ ndr_print_hyper(ndr, "unknown6", r->unknown6);
+ ndr_print_hyper(ndr, "unknown7", r->unknown7);
+ ndr_print_hyper(ndr, "unknown8", r->unknown8);
+ ndr_print_hyper(ndr, "unknown9", r->unknown9);
+ ndr_print_hyper(ndr, "unknown10", r->unknown10);
+ ndr_print_hyper(ndr, "unknown11", r->unknown11);
+ ndr_print_hyper(ndr, "unknown12", r->unknown12);
+ ndr_print_hyper(ndr, "unknown13", r->unknown13);
+ ndr_print_uint32(ndr, "unknown14", r->unknown14);
+ ndr_print_uint32(ndr, "unknown15", r->unknown15);
+ ndr_print_uint32(ndr, "unknown16", r->unknown16);
+ ndr_print_uint32(ndr, "unknown17", r->unknown17);
+ ndr_print_uint32(ndr, "unknown18", r->unknown18);
+ ndr_print_uint32(ndr, "unknown19", r->unknown19);
+ ndr_print_uint32(ndr, "unknown20", r->unknown20);
+ ndr_print_uint32(ndr, "unknown21", r->unknown21);
+ ndr_print_uint32(ndr, "unknown22", r->unknown22);
+ ndr_print_uint32(ndr, "unknown23", r->unknown23);
+ ndr_print_uint32(ndr, "unknown24", r->unknown24);
+ ndr_print_uint32(ndr, "unknown25", r->unknown25);
+ ndr_print_uint32(ndr, "unknown26", r->unknown26);
+ ndr_print_uint32(ndr, "unknown27", r->unknown27);
+ ndr_print_uint32(ndr, "unknown28", r->unknown28);
+ ndr_print_uint32(ndr, "unknown29", r->unknown29);
+ ndr_print_uint32(ndr, "unknown30", r->unknown30);
+ ndr_print_uint32(ndr, "unknown31", r->unknown31);
+ ndr_print_uint32(ndr, "unknown32", r->unknown32);
+ ndr_print_uint32(ndr, "unknown33", r->unknown33);
+ ndr_print_uint32(ndr, "unknown34", r->unknown34);
+ ndr_print_uint32(ndr, "unknown35", r->unknown35);
+ ndr_print_uint32(ndr, "unknown36", r->unknown36);
+ ndr_print_uint32(ndr, "unknown37", r->unknown37);
+ ndr_print_uint32(ndr, "unknown38", r->unknown38);
+ ndr_print_uint32(ndr, "unknown39", r->unknown39);
+ ndr_print_uint32(ndr, "unknown40", r->unknown40);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_renameflags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_renameflags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_renameflags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE", WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetValidateNameType(struct ndr_push *ndr, int ndr_flags, enum wkssvc_NetValidateNameType r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetValidateNameType(struct ndr_pull *ndr, int ndr_flags, enum wkssvc_NetValidateNameType *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetValidateNameType(struct ndr_print *ndr, const char *name, enum wkssvc_NetValidateNameType r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case NetSetupUnknown: val = "NetSetupUnknown"; break;
+ case NetSetupMachine: val = "NetSetupMachine"; break;
+ case NetSetupWorkgroup: val = "NetSetupWorkgroup"; break;
+ case NetSetupDomain: val = "NetSetupDomain"; break;
+ case NetSetupNonExistentDomain: val = "NetSetupNonExistentDomain"; break;
+ case NetSetupDnsMachine: val = "NetSetupDnsMachine"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetJoinStatus(struct ndr_push *ndr, int ndr_flags, enum wkssvc_NetJoinStatus r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetJoinStatus(struct ndr_pull *ndr, int ndr_flags, enum wkssvc_NetJoinStatus *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetJoinStatus(struct ndr_print *ndr, const char *name, enum wkssvc_NetJoinStatus r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case NET_SETUP_UNKNOWN_STATUS: val = "NET_SETUP_UNKNOWN_STATUS"; break;
+ case NET_SETUP_UNJOINED: val = "NET_SETUP_UNJOINED"; break;
+ case NET_SETUP_WORKGROUP_NAME: val = "NET_SETUP_WORKGROUP_NAME"; break;
+ case NET_SETUP_DOMAIN_NAME: val = "NET_SETUP_DOMAIN_NAME"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_wkssvc_PasswordBuffer(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_PasswordBuffer *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 1));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->data, 524));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_PasswordBuffer(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_PasswordBuffer *r)
+{
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->data, 524));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_PasswordBuffer(struct ndr_print *ndr, const char *name, const struct wkssvc_PasswordBuffer *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_PasswordBuffer");
+ {
+ uint32_t _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "data", r->data, 524);
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+static enum ndr_err_code ndr_push_wkssvc_joinflags(struct ndr_push *ndr, int ndr_flags, uint32_t r)
+{
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_joinflags(struct ndr_pull *ndr, int ndr_flags, uint32_t *r)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_joinflags(struct ndr_print *ndr, const char *name, uint32_t r)
+{
+ ndr_print_uint32(ndr, name, r);
+ ndr->depth++;
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "WKSSVC_JOIN_FLAGS_JOIN_WITH_NEW_NAME", WKSSVC_JOIN_FLAGS_JOIN_WITH_NEW_NAME, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "WKSSVC_JOIN_FLAGS_JOIN_DC_ACCOUNT", WKSSVC_JOIN_FLAGS_JOIN_DC_ACCOUNT, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "WKSSVC_JOIN_FLAGS_DEFER_SPN", WKSSVC_JOIN_FLAGS_DEFER_SPN, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED", WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "WKSSVC_JOIN_FLAGS_JOIN_UNSECURE", WKSSVC_JOIN_FLAGS_JOIN_UNSECURE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED", WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "WKSSVC_JOIN_FLAGS_WIN9X_UPGRADE", WKSSVC_JOIN_FLAGS_WIN9X_UPGRADE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE", WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE", WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE, r);
+ ndr_print_bitmap_flag(ndr, sizeof(uint32_t), "WKSSVC_JOIN_FLAGS_JOIN_TYPE", WKSSVC_JOIN_FLAGS_JOIN_TYPE, r);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_ComputerNameType(struct ndr_push *ndr, int ndr_flags, enum wkssvc_ComputerNameType r)
+{
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_ComputerNameType(struct ndr_pull *ndr, int ndr_flags, enum wkssvc_ComputerNameType *r)
+{
+ uint16_t v;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_ComputerNameType(struct ndr_print *ndr, const char *name, enum wkssvc_ComputerNameType r)
+{
+ const char *val = NULL;
+
+ switch (r) {
+ case NetPrimaryComputerName: val = "NetPrimaryComputerName"; break;
+ case NetAlternateComputerNames: val = "NetAlternateComputerNames"; break;
+ case NetAllComputerNames: val = "NetAllComputerNames"; break;
+ case NetComputerNameTypeMax: val = "NetComputerNameTypeMax"; break;
+ }
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+}
+
+static enum ndr_err_code ndr_push_wkssvc_ComputerNamesCtr(struct ndr_push *ndr, int ndr_flags, const struct wkssvc_ComputerNamesCtr *r)
+{
+ uint32_t cntr_computer_name_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->computer_name));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->computer_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ for (cntr_computer_name_1 = 0; cntr_computer_name_1 < r->count; cntr_computer_name_1++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_SCALARS, &r->computer_name[cntr_computer_name_1]));
+ }
+ for (cntr_computer_name_1 = 0; cntr_computer_name_1 < r->count; cntr_computer_name_1++) {
+ NDR_CHECK(ndr_push_lsa_String(ndr, NDR_BUFFERS, &r->computer_name[cntr_computer_name_1]));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_ComputerNamesCtr(struct ndr_pull *ndr, int ndr_flags, struct wkssvc_ComputerNamesCtr *r)
+{
+ uint32_t _ptr_computer_name;
+ uint32_t cntr_computer_name_1;
+ TALLOC_CTX *_mem_save_computer_name_0;
+ TALLOC_CTX *_mem_save_computer_name_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_computer_name));
+ if (_ptr_computer_name) {
+ NDR_PULL_ALLOC(ndr, r->computer_name);
+ } else {
+ r->computer_name = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->computer_name) {
+ _mem_save_computer_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->computer_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->computer_name));
+ NDR_PULL_ALLOC_N(ndr, r->computer_name, ndr_get_array_size(ndr, &r->computer_name));
+ _mem_save_computer_name_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->computer_name, 0);
+ for (cntr_computer_name_1 = 0; cntr_computer_name_1 < r->count; cntr_computer_name_1++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_SCALARS, &r->computer_name[cntr_computer_name_1]));
+ }
+ for (cntr_computer_name_1 = 0; cntr_computer_name_1 < r->count; cntr_computer_name_1++) {
+ NDR_CHECK(ndr_pull_lsa_String(ndr, NDR_BUFFERS, &r->computer_name[cntr_computer_name_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_computer_name_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_computer_name_0, 0);
+ }
+ if (r->computer_name) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->computer_name, r->count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_ComputerNamesCtr(struct ndr_print *ndr, const char *name, const struct wkssvc_ComputerNamesCtr *r)
+{
+ uint32_t cntr_computer_name_1;
+ ndr_print_struct(ndr, name, "wkssvc_ComputerNamesCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "count", r->count);
+ ndr_print_ptr(ndr, "computer_name", r->computer_name);
+ ndr->depth++;
+ if (r->computer_name) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "computer_name", (int)r->count);
+ ndr->depth++;
+ for (cntr_computer_name_1=0;cntr_computer_name_1<r->count;cntr_computer_name_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%d]", cntr_computer_name_1) != -1) {
+ ndr_print_lsa_String(ndr, "computer_name", &r->computer_name[cntr_computer_name_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaGetInfo(struct ndr_push *ndr, int flags, const struct wkssvc_NetWkstaGetInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaGetInfo(struct ndr_pull *ndr, int flags, struct wkssvc_NetWkstaGetInfo *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetWkstaGetInfo *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaGetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetWkstaGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetWkstaGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, r->in.level);
+ ndr_print_wkssvc_NetWkstaInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaSetInfo(struct ndr_push *ndr, int flags, const struct wkssvc_NetWkstaSetInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ if (r->in.parm_error == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.parm_error));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.parm_error == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.parm_error));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaSetInfo(struct ndr_pull *ndr, int flags, struct wkssvc_NetWkstaSetInfo *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_parm_error_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.parm_error);
+ }
+ _mem_save_parm_error_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.parm_error, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.parm_error));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parm_error_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.parm_error);
+ *r->out.parm_error = *r->in.parm_error;
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.parm_error);
+ }
+ _mem_save_parm_error_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.parm_error, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.parm_error));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parm_error_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetWkstaSetInfo *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaSetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetWkstaSetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.info, r->in.level);
+ ndr_print_wkssvc_NetWkstaInfo(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "parm_error", r->in.parm_error);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "parm_error", *r->in.parm_error);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetWkstaSetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_error", r->out.parm_error);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "parm_error", *r->out.parm_error);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaEnumUsers(struct ndr_push *ndr, int flags, const struct wkssvc_NetWkstaEnumUsers *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaEnumUsersInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.prefmaxlen));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.resume_handle));
+ if (r->in.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaEnumUsersInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ if (r->out.entries_read == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.entries_read));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.resume_handle));
+ if (r->out.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaEnumUsers(struct ndr_pull *ndr, int flags, struct wkssvc_NetWkstaEnumUsers *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_resume_handle;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_entries_read_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaEnumUsersInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.prefmaxlen));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ } else {
+ r->in.resume_handle = NULL;
+ }
+ if (r->in.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ *r->out.info = *r->in.info;
+ NDR_PULL_ALLOC(ndr, r->out.entries_read);
+ ZERO_STRUCTP(r->out.entries_read);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaEnumUsersInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.entries_read);
+ }
+ _mem_save_entries_read_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.entries_read, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.entries_read));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_read_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ } else {
+ r->out.resume_handle = NULL;
+ }
+ if (r->out.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaEnumUsers(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetWkstaEnumUsers *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaEnumUsers");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetWkstaEnumUsers");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_wkssvc_NetWkstaEnumUsersInfo(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "prefmaxlen", r->in.prefmaxlen);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ if (r->in.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetWkstaEnumUsers");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_wkssvc_NetWkstaEnumUsersInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "entries_read", r->out.entries_read);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "entries_read", *r->out.entries_read);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ if (r->out.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrWkstaUserGetInfo(struct ndr_push *ndr, int flags, const struct wkssvc_NetrWkstaUserGetInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.unknown));
+ if (r->in.unknown) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.unknown, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.unknown, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.unknown, ndr_charset_length(r->in.unknown, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_push_wkssvc_NetrWkstaUserInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrWkstaUserGetInfo(struct ndr_pull *ndr, int flags, struct wkssvc_NetrWkstaUserGetInfo *r)
+{
+ uint32_t _ptr_unknown;
+ TALLOC_CTX *_mem_save_unknown_0;
+ TALLOC_CTX *_mem_save_info_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown));
+ if (_ptr_unknown) {
+ NDR_PULL_ALLOC(ndr, r->in.unknown);
+ } else {
+ r->in.unknown = NULL;
+ }
+ if (r->in.unknown) {
+ _mem_save_unknown_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.unknown, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.unknown));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.unknown));
+ if (ndr_get_array_length(ndr, &r->in.unknown) > ndr_get_array_size(ndr, &r->in.unknown)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.unknown), ndr_get_array_length(ndr, &r->in.unknown));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.unknown), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.unknown, ndr_get_array_length(ndr, &r->in.unknown), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.info, r->in.level));
+ NDR_CHECK(ndr_pull_wkssvc_NetrWkstaUserInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrWkstaUserGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrWkstaUserGetInfo *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrWkstaUserGetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrWkstaUserGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "unknown", r->in.unknown);
+ ndr->depth++;
+ if (r->in.unknown) {
+ ndr_print_string(ndr, "unknown", r->in.unknown);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrWkstaUserGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.info, r->in.level);
+ ndr_print_wkssvc_NetrWkstaUserInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrWkstaUserSetInfo(struct ndr_push *ndr, int flags, const struct wkssvc_NetrWkstaUserSetInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.unknown));
+ if (r->in.unknown) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.unknown, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.unknown, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.unknown, ndr_charset_length(r->in.unknown, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_push_wkssvc_NetrWkstaUserInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.parm_err));
+ if (r->in.parm_err) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.parm_err));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.parm_err));
+ if (r->out.parm_err) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.parm_err));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrWkstaUserSetInfo(struct ndr_pull *ndr, int flags, struct wkssvc_NetrWkstaUserSetInfo *r)
+{
+ uint32_t _ptr_unknown;
+ uint32_t _ptr_parm_err;
+ TALLOC_CTX *_mem_save_unknown_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_parm_err_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown));
+ if (_ptr_unknown) {
+ NDR_PULL_ALLOC(ndr, r->in.unknown);
+ } else {
+ r->in.unknown = NULL;
+ }
+ if (r->in.unknown) {
+ _mem_save_unknown_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.unknown, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.unknown));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.unknown));
+ if (ndr_get_array_length(ndr, &r->in.unknown) > ndr_get_array_size(ndr, &r->in.unknown)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.unknown), ndr_get_array_length(ndr, &r->in.unknown));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.unknown), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.unknown, ndr_get_array_length(ndr, &r->in.unknown), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.info, r->in.level));
+ NDR_CHECK(ndr_pull_wkssvc_NetrWkstaUserInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_parm_err));
+ if (_ptr_parm_err) {
+ NDR_PULL_ALLOC(ndr, r->in.parm_err);
+ } else {
+ r->in.parm_err = NULL;
+ }
+ if (r->in.parm_err) {
+ _mem_save_parm_err_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.parm_err, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.parm_err));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parm_err_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_parm_err));
+ if (_ptr_parm_err) {
+ NDR_PULL_ALLOC(ndr, r->out.parm_err);
+ } else {
+ r->out.parm_err = NULL;
+ }
+ if (r->out.parm_err) {
+ _mem_save_parm_err_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.parm_err, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.parm_err));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parm_err_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrWkstaUserSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrWkstaUserSetInfo *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrWkstaUserSetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrWkstaUserSetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "unknown", r->in.unknown);
+ ndr->depth++;
+ if (r->in.unknown) {
+ ndr_print_string(ndr, "unknown", r->in.unknown);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.info, r->in.level);
+ ndr_print_wkssvc_NetrWkstaUserInfo(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "parm_err", r->in.parm_err);
+ ndr->depth++;
+ if (r->in.parm_err) {
+ ndr_print_uint32(ndr, "parm_err", *r->in.parm_err);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrWkstaUserSetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_err", r->out.parm_err);
+ ndr->depth++;
+ if (r->out.parm_err) {
+ ndr_print_uint32(ndr, "parm_err", *r->out.parm_err);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetWkstaTransportEnum(struct ndr_push *ndr, int flags, const struct wkssvc_NetWkstaTransportEnum *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaTransportInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.max_buffer));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.resume_handle));
+ if (r->in.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaTransportInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ if (r->out.total_entries == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.total_entries));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.resume_handle));
+ if (r->out.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetWkstaTransportEnum(struct ndr_pull *ndr, int flags, struct wkssvc_NetWkstaTransportEnum *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_resume_handle;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_total_entries_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaTransportInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.max_buffer));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ } else {
+ r->in.resume_handle = NULL;
+ }
+ if (r->in.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ *r->out.info = *r->in.info;
+ NDR_PULL_ALLOC(ndr, r->out.total_entries);
+ ZERO_STRUCTP(r->out.total_entries);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaTransportInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.total_entries);
+ }
+ _mem_save_total_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.total_entries, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.total_entries));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_total_entries_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ } else {
+ r->out.resume_handle = NULL;
+ }
+ if (r->out.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetWkstaTransportEnum(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetWkstaTransportEnum *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetWkstaTransportEnum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetWkstaTransportEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_wkssvc_NetWkstaTransportInfo(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "max_buffer", r->in.max_buffer);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ if (r->in.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetWkstaTransportEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_wkssvc_NetWkstaTransportInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "total_entries", r->out.total_entries);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "total_entries", *r->out.total_entries);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ if (r->out.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrWkstaTransportAdd(struct ndr_push *ndr, int flags, const struct wkssvc_NetrWkstaTransportAdd *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.info0 == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_wkssvc_NetWkstaTransportInfo0(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info0));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.parm_err));
+ if (r->in.parm_err) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.parm_err));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.parm_err));
+ if (r->out.parm_err) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.parm_err));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrWkstaTransportAdd(struct ndr_pull *ndr, int flags, struct wkssvc_NetrWkstaTransportAdd *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_parm_err;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_info0_0;
+ TALLOC_CTX *_mem_save_parm_err_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info0);
+ }
+ _mem_save_info0_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_wkssvc_NetWkstaTransportInfo0(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info0));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info0_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_parm_err));
+ if (_ptr_parm_err) {
+ NDR_PULL_ALLOC(ndr, r->in.parm_err);
+ } else {
+ r->in.parm_err = NULL;
+ }
+ if (r->in.parm_err) {
+ _mem_save_parm_err_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.parm_err, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.parm_err));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parm_err_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_parm_err));
+ if (_ptr_parm_err) {
+ NDR_PULL_ALLOC(ndr, r->out.parm_err);
+ } else {
+ r->out.parm_err = NULL;
+ }
+ if (r->out.parm_err) {
+ _mem_save_parm_err_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.parm_err, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.parm_err));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parm_err_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrWkstaTransportAdd(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrWkstaTransportAdd *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrWkstaTransportAdd");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrWkstaTransportAdd");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "info0", r->in.info0);
+ ndr->depth++;
+ ndr_print_wkssvc_NetWkstaTransportInfo0(ndr, "info0", r->in.info0);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "parm_err", r->in.parm_err);
+ ndr->depth++;
+ if (r->in.parm_err) {
+ ndr_print_uint32(ndr, "parm_err", *r->in.parm_err);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrWkstaTransportAdd");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_err", r->out.parm_err);
+ ndr->depth++;
+ if (r->out.parm_err) {
+ ndr_print_uint32(ndr, "parm_err", *r->out.parm_err);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrWkstaTransportDel(struct ndr_push *ndr, int flags, const struct wkssvc_NetrWkstaTransportDel *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.transport_name));
+ if (r->in.transport_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.transport_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.transport_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.transport_name, ndr_charset_length(r->in.transport_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown3));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrWkstaTransportDel(struct ndr_pull *ndr, int flags, struct wkssvc_NetrWkstaTransportDel *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_transport_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_transport_name_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_transport_name));
+ if (_ptr_transport_name) {
+ NDR_PULL_ALLOC(ndr, r->in.transport_name);
+ } else {
+ r->in.transport_name = NULL;
+ }
+ if (r->in.transport_name) {
+ _mem_save_transport_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.transport_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.transport_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.transport_name));
+ if (ndr_get_array_length(ndr, &r->in.transport_name) > ndr_get_array_size(ndr, &r->in.transport_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.transport_name), ndr_get_array_length(ndr, &r->in.transport_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.transport_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.transport_name, ndr_get_array_length(ndr, &r->in.transport_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_transport_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown3));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrWkstaTransportDel(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrWkstaTransportDel *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrWkstaTransportDel");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrWkstaTransportDel");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "transport_name", r->in.transport_name);
+ ndr->depth++;
+ if (r->in.transport_name) {
+ ndr_print_string(ndr, "transport_name", r->in.transport_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown3", r->in.unknown3);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrWkstaTransportDel");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrUseAdd(struct ndr_push *ndr, int flags, const struct wkssvc_NetrUseAdd *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ if (r->in.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->in.ctr, r->in.level));
+ NDR_CHECK(ndr_push_wkssvc_NetrUseGetInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.ctr));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.parm_err));
+ if (r->in.parm_err) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.parm_err));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.parm_err));
+ if (r->out.parm_err) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.parm_err));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrUseAdd(struct ndr_pull *ndr, int flags, struct wkssvc_NetrUseAdd *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_parm_err;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_ctr_0;
+ TALLOC_CTX *_mem_save_parm_err_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->in.ctr, r->in.level));
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseGetInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_parm_err));
+ if (_ptr_parm_err) {
+ NDR_PULL_ALLOC(ndr, r->in.parm_err);
+ } else {
+ r->in.parm_err = NULL;
+ }
+ if (r->in.parm_err) {
+ _mem_save_parm_err_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.parm_err, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.parm_err));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parm_err_0, 0);
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_parm_err));
+ if (_ptr_parm_err) {
+ NDR_PULL_ALLOC(ndr, r->out.parm_err);
+ } else {
+ r->out.parm_err = NULL;
+ }
+ if (r->out.parm_err) {
+ _mem_save_parm_err_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.parm_err, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.parm_err));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_parm_err_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrUseAdd(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUseAdd *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrUseAdd");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrUseAdd");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr_print_ptr(ndr, "ctr", r->in.ctr);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->in.ctr, r->in.level);
+ ndr_print_wkssvc_NetrUseGetInfoCtr(ndr, "ctr", r->in.ctr);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "parm_err", r->in.parm_err);
+ ndr->depth++;
+ if (r->in.parm_err) {
+ ndr_print_uint32(ndr, "parm_err", *r->in.parm_err);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrUseAdd");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "parm_err", r->out.parm_err);
+ ndr->depth++;
+ if (r->out.parm_err) {
+ ndr_print_uint32(ndr, "parm_err", *r->out.parm_err);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrUseGetInfo(struct ndr_push *ndr, int flags, const struct wkssvc_NetrUseGetInfo *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.use_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.use_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.use_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.use_name, ndr_charset_length(r->in.use_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.level));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_set_switch_value(ndr, r->out.ctr, r->in.level));
+ NDR_CHECK(ndr_push_wkssvc_NetrUseGetInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrUseGetInfo(struct ndr_pull *ndr, int flags, struct wkssvc_NetrUseGetInfo *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_ctr_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.use_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.use_name));
+ if (ndr_get_array_length(ndr, &r->in.use_name) > ndr_get_array_size(ndr, &r->in.use_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.use_name), ndr_get_array_length(ndr, &r->in.use_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.use_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.use_name, ndr_get_array_length(ndr, &r->in.use_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.level));
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ ZERO_STRUCTP(r->out.ctr);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, r->out.ctr, r->in.level));
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseGetInfoCtr(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrUseGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUseGetInfo *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrUseGetInfo");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrUseGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "use_name", r->in.use_name);
+ ndr->depth++;
+ ndr_print_string(ndr, "use_name", r->in.use_name);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "level", r->in.level);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrUseGetInfo");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "ctr", r->out.ctr);
+ ndr->depth++;
+ ndr_print_set_switch_value(ndr, r->out.ctr, r->in.level);
+ ndr_print_wkssvc_NetrUseGetInfoCtr(ndr, "ctr", r->out.ctr);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrUseDel(struct ndr_push *ndr, int flags, const struct wkssvc_NetrUseDel *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.use_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.use_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.use_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.use_name, ndr_charset_length(r->in.use_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.force_cond));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrUseDel(struct ndr_pull *ndr, int flags, struct wkssvc_NetrUseDel *r)
+{
+ uint32_t _ptr_server_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.use_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.use_name));
+ if (ndr_get_array_length(ndr, &r->in.use_name) > ndr_get_array_size(ndr, &r->in.use_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.use_name), ndr_get_array_length(ndr, &r->in.use_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.use_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.use_name, ndr_get_array_length(ndr, &r->in.use_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.force_cond));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrUseDel(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUseDel *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrUseDel");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrUseDel");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "use_name", r->in.use_name);
+ ndr->depth++;
+ ndr_print_string(ndr, "use_name", r->in.use_name);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "force_cond", r->in.force_cond);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrUseDel");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrUseEnum(struct ndr_push *ndr, int flags, const struct wkssvc_NetrUseEnum *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_wkssvc_NetrUseEnumInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.prefmaxlen));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.resume_handle));
+ if (r->in.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.resume_handle));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_wkssvc_NetrUseEnumInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ if (r->out.entries_read == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.entries_read));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->out.resume_handle));
+ if (r->out.resume_handle) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.resume_handle));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrUseEnum(struct ndr_pull *ndr, int flags, struct wkssvc_NetrUseEnum *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_resume_handle;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_entries_read_0;
+ TALLOC_CTX *_mem_save_resume_handle_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseEnumInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.prefmaxlen));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->in.resume_handle);
+ } else {
+ r->in.resume_handle = NULL;
+ }
+ if (r->in.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ *r->out.info = *r->in.info;
+ NDR_PULL_ALLOC(ndr, r->out.entries_read);
+ ZERO_STRUCTP(r->out.entries_read);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_wkssvc_NetrUseEnumInfo(ndr, NDR_SCALARS|NDR_BUFFERS, r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.entries_read);
+ }
+ _mem_save_entries_read_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.entries_read, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.entries_read));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_read_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_resume_handle));
+ if (_ptr_resume_handle) {
+ NDR_PULL_ALLOC(ndr, r->out.resume_handle);
+ } else {
+ r->out.resume_handle = NULL;
+ }
+ if (r->out.resume_handle) {
+ _mem_save_resume_handle_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.resume_handle, 0);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.resume_handle));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_resume_handle_0, 0);
+ }
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrUseEnum(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUseEnum *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrUseEnum");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrUseEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "info", r->in.info);
+ ndr->depth++;
+ ndr_print_wkssvc_NetrUseEnumInfo(ndr, "info", r->in.info);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "prefmaxlen", r->in.prefmaxlen);
+ ndr_print_ptr(ndr, "resume_handle", r->in.resume_handle);
+ ndr->depth++;
+ if (r->in.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->in.resume_handle);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrUseEnum");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_wkssvc_NetrUseEnumInfo(ndr, "info", r->out.info);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "entries_read", r->out.entries_read);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "entries_read", *r->out.entries_read);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "resume_handle", r->out.resume_handle);
+ ndr->depth++;
+ if (r->out.resume_handle) {
+ ndr_print_uint32(ndr, "resume_handle", *r->out.resume_handle);
+ }
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrMessageBufferSend(struct ndr_push *ndr, int flags, const struct wkssvc_NetrMessageBufferSend *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.message_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.message_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.message_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.message_name, ndr_charset_length(r->in.message_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.message_sender_name));
+ if (r->in.message_sender_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.message_sender_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.message_sender_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.message_sender_name, ndr_charset_length(r->in.message_sender_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.message_buffer == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.message_size));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->in.message_buffer, r->in.message_size));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.message_size));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrMessageBufferSend(struct ndr_pull *ndr, int flags, struct wkssvc_NetrMessageBufferSend *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_message_sender_name;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_message_sender_name_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.message_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.message_name));
+ if (ndr_get_array_length(ndr, &r->in.message_name) > ndr_get_array_size(ndr, &r->in.message_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.message_name), ndr_get_array_length(ndr, &r->in.message_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.message_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.message_name, ndr_get_array_length(ndr, &r->in.message_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_message_sender_name));
+ if (_ptr_message_sender_name) {
+ NDR_PULL_ALLOC(ndr, r->in.message_sender_name);
+ } else {
+ r->in.message_sender_name = NULL;
+ }
+ if (r->in.message_sender_name) {
+ _mem_save_message_sender_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.message_sender_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.message_sender_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.message_sender_name));
+ if (ndr_get_array_length(ndr, &r->in.message_sender_name) > ndr_get_array_size(ndr, &r->in.message_sender_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.message_sender_name), ndr_get_array_length(ndr, &r->in.message_sender_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.message_sender_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.message_sender_name, ndr_get_array_length(ndr, &r->in.message_sender_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_message_sender_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.message_buffer));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC_N(ndr, r->in.message_buffer, ndr_get_array_size(ndr, &r->in.message_buffer));
+ }
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->in.message_buffer, ndr_get_array_size(ndr, &r->in.message_buffer)));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.message_size));
+ if (r->in.message_buffer) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->in.message_buffer, r->in.message_size));
+ }
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrMessageBufferSend(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrMessageBufferSend *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrMessageBufferSend");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrMessageBufferSend");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "message_name", r->in.message_name);
+ ndr->depth++;
+ ndr_print_string(ndr, "message_name", r->in.message_name);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "message_sender_name", r->in.message_sender_name);
+ ndr->depth++;
+ if (r->in.message_sender_name) {
+ ndr_print_string(ndr, "message_sender_name", r->in.message_sender_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "message_buffer", r->in.message_buffer);
+ ndr->depth++;
+ ndr_print_array_uint8(ndr, "message_buffer", r->in.message_buffer, r->in.message_size);
+ ndr->depth--;
+ ndr_print_uint32(ndr, "message_size", r->in.message_size);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrMessageBufferSend");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrWorkstationStatisticsGet(struct ndr_push *ndr, int flags, const struct wkssvc_NetrWorkstationStatisticsGet *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.unknown2));
+ if (r->in.unknown2) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.unknown2, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.unknown2, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.unknown2, ndr_charset_length(r->in.unknown2, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown3));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.unknown4));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.info == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.info));
+ if (*r->out.info) {
+ NDR_CHECK(ndr_push_wkssvc_NetrWorkstationStatistics(ndr, NDR_SCALARS, *r->out.info));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrWorkstationStatisticsGet(struct ndr_pull *ndr, int flags, struct wkssvc_NetrWorkstationStatisticsGet *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_unknown2;
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_unknown2_0;
+ TALLOC_CTX *_mem_save_info_0;
+ TALLOC_CTX *_mem_save_info_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown2));
+ if (_ptr_unknown2) {
+ NDR_PULL_ALLOC(ndr, r->in.unknown2);
+ } else {
+ r->in.unknown2 = NULL;
+ }
+ if (r->in.unknown2) {
+ _mem_save_unknown2_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.unknown2, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.unknown2));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.unknown2));
+ if (ndr_get_array_length(ndr, &r->in.unknown2) > ndr_get_array_size(ndr, &r->in.unknown2)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.unknown2), ndr_get_array_length(ndr, &r->in.unknown2));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.unknown2), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.unknown2, ndr_get_array_length(ndr, &r->in.unknown2), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown2_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown3));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.unknown4));
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.info, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ } else {
+ *r->out.info = NULL;
+ }
+ if (*r->out.info) {
+ _mem_save_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.info, 0);
+ NDR_CHECK(ndr_pull_wkssvc_NetrWorkstationStatistics(ndr, NDR_SCALARS, *r->out.info));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrWorkstationStatisticsGet(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrWorkstationStatisticsGet *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrWorkstationStatisticsGet");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrWorkstationStatisticsGet");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "unknown2", r->in.unknown2);
+ ndr->depth++;
+ if (r->in.unknown2) {
+ ndr_print_string(ndr, "unknown2", r->in.unknown2);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "unknown3", r->in.unknown3);
+ ndr_print_uint32(ndr, "unknown4", r->in.unknown4);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrWorkstationStatisticsGet");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", r->out.info);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "info", *r->out.info);
+ ndr->depth++;
+ if (*r->out.info) {
+ ndr_print_wkssvc_NetrWorkstationStatistics(ndr, "info", *r->out.info);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrLogonDomainNameAdd(struct ndr_push *ndr, int flags, const struct wkssvc_NetrLogonDomainNameAdd *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.domain_name, ndr_charset_length(r->in.domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrLogonDomainNameAdd(struct ndr_pull *ndr, int flags, struct wkssvc_NetrLogonDomainNameAdd *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.domain_name));
+ if (ndr_get_array_length(ndr, &r->in.domain_name) > ndr_get_array_size(ndr, &r->in.domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.domain_name), ndr_get_array_length(ndr, &r->in.domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.domain_name, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrLogonDomainNameAdd(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrLogonDomainNameAdd *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrLogonDomainNameAdd");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrLogonDomainNameAdd");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_name", r->in.domain_name);
+ ndr->depth++;
+ ndr_print_string(ndr, "domain_name", r->in.domain_name);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrLogonDomainNameAdd");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrLogonDomainNameDel(struct ndr_push *ndr, int flags, const struct wkssvc_NetrLogonDomainNameDel *r)
+{
+ if (flags & NDR_IN) {
+ if (r->in.domain_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.domain_name, ndr_charset_length(r->in.domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrLogonDomainNameDel(struct ndr_pull *ndr, int flags, struct wkssvc_NetrLogonDomainNameDel *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.domain_name));
+ if (ndr_get_array_length(ndr, &r->in.domain_name) > ndr_get_array_size(ndr, &r->in.domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.domain_name), ndr_get_array_length(ndr, &r->in.domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.domain_name, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t), CH_UTF16));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrLogonDomainNameDel(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrLogonDomainNameDel *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrLogonDomainNameDel");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrLogonDomainNameDel");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "domain_name", r->in.domain_name);
+ ndr->depth++;
+ ndr_print_string(ndr, "domain_name", r->in.domain_name);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrLogonDomainNameDel");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrJoinDomain(struct ndr_push *ndr, int flags, const struct wkssvc_NetrJoinDomain *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.domain_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.domain_name, ndr_charset_length(r->in.domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.account_ou));
+ if (r->in.account_ou) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_ou, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_ou, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.account_ou, ndr_charset_length(r->in.account_ou, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.Account));
+ if (r->in.Account) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.Account, ndr_charset_length(r->in.Account, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.password));
+ if (r->in.password) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.password, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.password, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.password, ndr_charset_length(r->in.password, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_wkssvc_joinflags(ndr, NDR_SCALARS, r->in.join_flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrJoinDomain(struct ndr_pull *ndr, int flags, struct wkssvc_NetrJoinDomain *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_account_ou;
+ uint32_t _ptr_Account;
+ uint32_t _ptr_password;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_account_ou_0;
+ TALLOC_CTX *_mem_save_Account_0;
+ TALLOC_CTX *_mem_save_password_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.domain_name));
+ if (ndr_get_array_length(ndr, &r->in.domain_name) > ndr_get_array_size(ndr, &r->in.domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.domain_name), ndr_get_array_length(ndr, &r->in.domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.domain_name, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_account_ou));
+ if (_ptr_account_ou) {
+ NDR_PULL_ALLOC(ndr, r->in.account_ou);
+ } else {
+ r->in.account_ou = NULL;
+ }
+ if (r->in.account_ou) {
+ _mem_save_account_ou_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.account_ou, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.account_ou));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.account_ou));
+ if (ndr_get_array_length(ndr, &r->in.account_ou) > ndr_get_array_size(ndr, &r->in.account_ou)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.account_ou), ndr_get_array_length(ndr, &r->in.account_ou));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.account_ou), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.account_ou, ndr_get_array_length(ndr, &r->in.account_ou), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_account_ou_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_Account));
+ if (_ptr_Account) {
+ NDR_PULL_ALLOC(ndr, r->in.Account);
+ } else {
+ r->in.Account = NULL;
+ }
+ if (r->in.Account) {
+ _mem_save_Account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.Account, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.Account));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.Account));
+ if (ndr_get_array_length(ndr, &r->in.Account) > ndr_get_array_size(ndr, &r->in.Account)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.Account), ndr_get_array_length(ndr, &r->in.Account));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.Account, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_Account_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password));
+ if (_ptr_password) {
+ NDR_PULL_ALLOC(ndr, r->in.password);
+ } else {
+ r->in.password = NULL;
+ }
+ if (r->in.password) {
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.password, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.password));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.password));
+ if (ndr_get_array_length(ndr, &r->in.password) > ndr_get_array_size(ndr, &r->in.password)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.password), ndr_get_array_length(ndr, &r->in.password));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.password), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.password, ndr_get_array_length(ndr, &r->in.password), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, 0);
+ }
+ NDR_CHECK(ndr_pull_wkssvc_joinflags(ndr, NDR_SCALARS, &r->in.join_flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrJoinDomain(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrJoinDomain *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrJoinDomain");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrJoinDomain");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_name", r->in.domain_name);
+ ndr->depth++;
+ ndr_print_string(ndr, "domain_name", r->in.domain_name);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "account_ou", r->in.account_ou);
+ ndr->depth++;
+ if (r->in.account_ou) {
+ ndr_print_string(ndr, "account_ou", r->in.account_ou);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "Account", r->in.Account);
+ ndr->depth++;
+ if (r->in.Account) {
+ ndr_print_string(ndr, "Account", r->in.Account);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->in.password);
+ ndr->depth++;
+ if (r->in.password) {
+ ndr_print_string(ndr, "password", r->in.password);
+ }
+ ndr->depth--;
+ ndr_print_wkssvc_joinflags(ndr, "join_flags", r->in.join_flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrJoinDomain");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrUnjoinDomain(struct ndr_push *ndr, int flags, const struct wkssvc_NetrUnjoinDomain *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.Account));
+ if (r->in.Account) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.Account, ndr_charset_length(r->in.Account, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.password));
+ if (r->in.password) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.password, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.password, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.password, ndr_charset_length(r->in.password, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_wkssvc_joinflags(ndr, NDR_SCALARS, r->in.unjoin_flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrUnjoinDomain(struct ndr_pull *ndr, int flags, struct wkssvc_NetrUnjoinDomain *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_Account;
+ uint32_t _ptr_password;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_Account_0;
+ TALLOC_CTX *_mem_save_password_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_Account));
+ if (_ptr_Account) {
+ NDR_PULL_ALLOC(ndr, r->in.Account);
+ } else {
+ r->in.Account = NULL;
+ }
+ if (r->in.Account) {
+ _mem_save_Account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.Account, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.Account));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.Account));
+ if (ndr_get_array_length(ndr, &r->in.Account) > ndr_get_array_size(ndr, &r->in.Account)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.Account), ndr_get_array_length(ndr, &r->in.Account));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.Account, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_Account_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password));
+ if (_ptr_password) {
+ NDR_PULL_ALLOC(ndr, r->in.password);
+ } else {
+ r->in.password = NULL;
+ }
+ if (r->in.password) {
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.password, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.password));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.password));
+ if (ndr_get_array_length(ndr, &r->in.password) > ndr_get_array_size(ndr, &r->in.password)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.password), ndr_get_array_length(ndr, &r->in.password));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.password), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.password, ndr_get_array_length(ndr, &r->in.password), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, 0);
+ }
+ NDR_CHECK(ndr_pull_wkssvc_joinflags(ndr, NDR_SCALARS, &r->in.unjoin_flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrUnjoinDomain(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUnjoinDomain *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrUnjoinDomain");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrUnjoinDomain");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "Account", r->in.Account);
+ ndr->depth++;
+ if (r->in.Account) {
+ ndr_print_string(ndr, "Account", r->in.Account);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->in.password);
+ ndr->depth++;
+ if (r->in.password) {
+ ndr_print_string(ndr, "password", r->in.password);
+ }
+ ndr->depth--;
+ ndr_print_wkssvc_joinflags(ndr, "unjoin_flags", r->in.unjoin_flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrUnjoinDomain");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrRenameMachineInDomain(struct ndr_push *ndr, int flags, const struct wkssvc_NetrRenameMachineInDomain *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.NewMachineName));
+ if (r->in.NewMachineName) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.NewMachineName, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.NewMachineName, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.NewMachineName, ndr_charset_length(r->in.NewMachineName, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.Account));
+ if (r->in.Account) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.Account, ndr_charset_length(r->in.Account, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.password));
+ if (r->in.password) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.password, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.password, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.password, ndr_charset_length(r->in.password, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_wkssvc_renameflags(ndr, NDR_SCALARS, r->in.RenameOptions));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrRenameMachineInDomain(struct ndr_pull *ndr, int flags, struct wkssvc_NetrRenameMachineInDomain *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_NewMachineName;
+ uint32_t _ptr_Account;
+ uint32_t _ptr_password;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_NewMachineName_0;
+ TALLOC_CTX *_mem_save_Account_0;
+ TALLOC_CTX *_mem_save_password_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_NewMachineName));
+ if (_ptr_NewMachineName) {
+ NDR_PULL_ALLOC(ndr, r->in.NewMachineName);
+ } else {
+ r->in.NewMachineName = NULL;
+ }
+ if (r->in.NewMachineName) {
+ _mem_save_NewMachineName_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.NewMachineName, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.NewMachineName));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.NewMachineName));
+ if (ndr_get_array_length(ndr, &r->in.NewMachineName) > ndr_get_array_size(ndr, &r->in.NewMachineName)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.NewMachineName), ndr_get_array_length(ndr, &r->in.NewMachineName));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.NewMachineName), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.NewMachineName, ndr_get_array_length(ndr, &r->in.NewMachineName), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_NewMachineName_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_Account));
+ if (_ptr_Account) {
+ NDR_PULL_ALLOC(ndr, r->in.Account);
+ } else {
+ r->in.Account = NULL;
+ }
+ if (r->in.Account) {
+ _mem_save_Account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.Account, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.Account));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.Account));
+ if (ndr_get_array_length(ndr, &r->in.Account) > ndr_get_array_size(ndr, &r->in.Account)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.Account), ndr_get_array_length(ndr, &r->in.Account));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.Account, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_Account_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_password));
+ if (_ptr_password) {
+ NDR_PULL_ALLOC(ndr, r->in.password);
+ } else {
+ r->in.password = NULL;
+ }
+ if (r->in.password) {
+ _mem_save_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.password, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.password));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.password));
+ if (ndr_get_array_length(ndr, &r->in.password) > ndr_get_array_size(ndr, &r->in.password)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.password), ndr_get_array_length(ndr, &r->in.password));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.password), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.password, ndr_get_array_length(ndr, &r->in.password), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_password_0, 0);
+ }
+ NDR_CHECK(ndr_pull_wkssvc_renameflags(ndr, NDR_SCALARS, &r->in.RenameOptions));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrRenameMachineInDomain(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrRenameMachineInDomain *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrRenameMachineInDomain");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrRenameMachineInDomain");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "NewMachineName", r->in.NewMachineName);
+ ndr->depth++;
+ if (r->in.NewMachineName) {
+ ndr_print_string(ndr, "NewMachineName", r->in.NewMachineName);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "Account", r->in.Account);
+ ndr->depth++;
+ if (r->in.Account) {
+ ndr_print_string(ndr, "Account", r->in.Account);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "password", r->in.password);
+ ndr->depth++;
+ if (r->in.password) {
+ ndr_print_string(ndr, "password", r->in.password);
+ }
+ ndr->depth--;
+ ndr_print_wkssvc_renameflags(ndr, "RenameOptions", r->in.RenameOptions);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrRenameMachineInDomain");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrValidateName(struct ndr_push *ndr, int flags, const struct wkssvc_NetrValidateName *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.name, ndr_charset_length(r->in.name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.Account));
+ if (r->in.Account) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.Account, ndr_charset_length(r->in.Account, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.Password));
+ if (r->in.Password) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Password, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Password, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.Password, ndr_charset_length(r->in.Password, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_wkssvc_NetValidateNameType(ndr, NDR_SCALARS, r->in.name_type));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrValidateName(struct ndr_pull *ndr, int flags, struct wkssvc_NetrValidateName *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_Account;
+ uint32_t _ptr_Password;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_Account_0;
+ TALLOC_CTX *_mem_save_Password_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.name));
+ if (ndr_get_array_length(ndr, &r->in.name) > ndr_get_array_size(ndr, &r->in.name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.name), ndr_get_array_length(ndr, &r->in.name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.name, ndr_get_array_length(ndr, &r->in.name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_Account));
+ if (_ptr_Account) {
+ NDR_PULL_ALLOC(ndr, r->in.Account);
+ } else {
+ r->in.Account = NULL;
+ }
+ if (r->in.Account) {
+ _mem_save_Account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.Account, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.Account));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.Account));
+ if (ndr_get_array_length(ndr, &r->in.Account) > ndr_get_array_size(ndr, &r->in.Account)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.Account), ndr_get_array_length(ndr, &r->in.Account));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.Account, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_Account_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_Password));
+ if (_ptr_Password) {
+ NDR_PULL_ALLOC(ndr, r->in.Password);
+ } else {
+ r->in.Password = NULL;
+ }
+ if (r->in.Password) {
+ _mem_save_Password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.Password, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.Password));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.Password));
+ if (ndr_get_array_length(ndr, &r->in.Password) > ndr_get_array_size(ndr, &r->in.Password)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.Password), ndr_get_array_length(ndr, &r->in.Password));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.Password), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.Password, ndr_get_array_length(ndr, &r->in.Password), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_Password_0, 0);
+ }
+ NDR_CHECK(ndr_pull_wkssvc_NetValidateNameType(ndr, NDR_SCALARS, &r->in.name_type));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrValidateName(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrValidateName *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrValidateName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrValidateName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "name", r->in.name);
+ ndr->depth++;
+ ndr_print_string(ndr, "name", r->in.name);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "Account", r->in.Account);
+ ndr->depth++;
+ if (r->in.Account) {
+ ndr_print_string(ndr, "Account", r->in.Account);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "Password", r->in.Password);
+ ndr->depth++;
+ if (r->in.Password) {
+ ndr_print_string(ndr, "Password", r->in.Password);
+ }
+ ndr->depth--;
+ ndr_print_wkssvc_NetValidateNameType(ndr, "name_type", r->in.name_type);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrValidateName");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrGetJoinInformation(struct ndr_push *ndr, int flags, const struct wkssvc_NetrGetJoinInformation *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.name_buffer == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->in.name_buffer));
+ if (*r->in.name_buffer) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->in.name_buffer, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->in.name_buffer, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, *r->in.name_buffer, ndr_charset_length(*r->in.name_buffer, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.name_buffer == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.name_buffer));
+ if (*r->out.name_buffer) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.name_buffer, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(*r->out.name_buffer, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, *r->out.name_buffer, ndr_charset_length(*r->out.name_buffer, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->out.name_type == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_wkssvc_NetJoinStatus(ndr, NDR_SCALARS, *r->out.name_type));
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrGetJoinInformation(struct ndr_pull *ndr, int flags, struct wkssvc_NetrGetJoinInformation *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_name_buffer;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_name_buffer_0;
+ TALLOC_CTX *_mem_save_name_buffer_1;
+ TALLOC_CTX *_mem_save_name_type_0;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.name_buffer);
+ }
+ _mem_save_name_buffer_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.name_buffer, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name_buffer));
+ if (_ptr_name_buffer) {
+ NDR_PULL_ALLOC(ndr, *r->in.name_buffer);
+ } else {
+ *r->in.name_buffer = NULL;
+ }
+ if (*r->in.name_buffer) {
+ _mem_save_name_buffer_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->in.name_buffer, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->in.name_buffer));
+ NDR_CHECK(ndr_pull_array_length(ndr, r->in.name_buffer));
+ if (ndr_get_array_length(ndr, r->in.name_buffer) > ndr_get_array_size(ndr, r->in.name_buffer)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, r->in.name_buffer), ndr_get_array_length(ndr, r->in.name_buffer));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, r->in.name_buffer), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, r->in.name_buffer, ndr_get_array_length(ndr, r->in.name_buffer), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_buffer_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_buffer_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.name_buffer);
+ *r->out.name_buffer = *r->in.name_buffer;
+ NDR_PULL_ALLOC(ndr, r->out.name_type);
+ ZERO_STRUCTP(r->out.name_type);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.name_buffer);
+ }
+ _mem_save_name_buffer_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.name_buffer, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_name_buffer));
+ if (_ptr_name_buffer) {
+ NDR_PULL_ALLOC(ndr, *r->out.name_buffer);
+ } else {
+ *r->out.name_buffer = NULL;
+ }
+ if (*r->out.name_buffer) {
+ _mem_save_name_buffer_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.name_buffer, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->out.name_buffer));
+ NDR_CHECK(ndr_pull_array_length(ndr, r->out.name_buffer));
+ if (ndr_get_array_length(ndr, r->out.name_buffer) > ndr_get_array_size(ndr, r->out.name_buffer)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, r->out.name_buffer), ndr_get_array_length(ndr, r->out.name_buffer));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, r->out.name_buffer), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, r->out.name_buffer, ndr_get_array_length(ndr, r->out.name_buffer), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_buffer_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_buffer_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.name_type);
+ }
+ _mem_save_name_type_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.name_type, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_wkssvc_NetJoinStatus(ndr, NDR_SCALARS, r->out.name_type));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_name_type_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrGetJoinInformation(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrGetJoinInformation *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrGetJoinInformation");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrGetJoinInformation");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "name_buffer", r->in.name_buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "name_buffer", *r->in.name_buffer);
+ ndr->depth++;
+ if (*r->in.name_buffer) {
+ ndr_print_string(ndr, "name_buffer", *r->in.name_buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrGetJoinInformation");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "name_buffer", r->out.name_buffer);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "name_buffer", *r->out.name_buffer);
+ ndr->depth++;
+ if (*r->out.name_buffer) {
+ ndr_print_string(ndr, "name_buffer", *r->out.name_buffer);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "name_type", r->out.name_type);
+ ndr->depth++;
+ ndr_print_wkssvc_NetJoinStatus(ndr, "name_type", *r->out.name_type);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrGetJoinableOus(struct ndr_push *ndr, int flags, const struct wkssvc_NetrGetJoinableOus *r)
+{
+ uint32_t cntr_ous_2;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.domain_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.domain_name, ndr_charset_length(r->in.domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.Account));
+ if (r->in.Account) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.Account, ndr_charset_length(r->in.Account, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.unknown));
+ if (r->in.unknown) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.unknown, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.unknown, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.unknown, ndr_charset_length(r->in.unknown, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.num_ous == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.num_ous));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.num_ous == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.num_ous));
+ if (r->out.ous == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.ous));
+ if (*r->out.ous) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.num_ous));
+ for (cntr_ous_2 = 0; cntr_ous_2 < *r->out.num_ous; cntr_ous_2++) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, (*r->out.ous)[cntr_ous_2]));
+ }
+ for (cntr_ous_2 = 0; cntr_ous_2 < *r->out.num_ous; cntr_ous_2++) {
+ if ((*r->out.ous)[cntr_ous_2]) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length((*r->out.ous)[cntr_ous_2], CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length((*r->out.ous)[cntr_ous_2], CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, (*r->out.ous)[cntr_ous_2], ndr_charset_length((*r->out.ous)[cntr_ous_2], CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrGetJoinableOus(struct ndr_pull *ndr, int flags, struct wkssvc_NetrGetJoinableOus *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_Account;
+ uint32_t _ptr_unknown;
+ uint32_t _ptr_ous;
+ uint32_t cntr_ous_2;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_Account_0;
+ TALLOC_CTX *_mem_save_unknown_0;
+ TALLOC_CTX *_mem_save_num_ous_0;
+ TALLOC_CTX *_mem_save_ous_0;
+ TALLOC_CTX *_mem_save_ous_1;
+ TALLOC_CTX *_mem_save_ous_2;
+ TALLOC_CTX *_mem_save_ous_3;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.domain_name));
+ if (ndr_get_array_length(ndr, &r->in.domain_name) > ndr_get_array_size(ndr, &r->in.domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.domain_name), ndr_get_array_length(ndr, &r->in.domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.domain_name, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_Account));
+ if (_ptr_Account) {
+ NDR_PULL_ALLOC(ndr, r->in.Account);
+ } else {
+ r->in.Account = NULL;
+ }
+ if (r->in.Account) {
+ _mem_save_Account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.Account, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.Account));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.Account));
+ if (ndr_get_array_length(ndr, &r->in.Account) > ndr_get_array_size(ndr, &r->in.Account)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.Account), ndr_get_array_length(ndr, &r->in.Account));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.Account, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_Account_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_unknown));
+ if (_ptr_unknown) {
+ NDR_PULL_ALLOC(ndr, r->in.unknown);
+ } else {
+ r->in.unknown = NULL;
+ }
+ if (r->in.unknown) {
+ _mem_save_unknown_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.unknown, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.unknown));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.unknown));
+ if (ndr_get_array_length(ndr, &r->in.unknown) > ndr_get_array_size(ndr, &r->in.unknown)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.unknown), ndr_get_array_length(ndr, &r->in.unknown));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.unknown), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.unknown, ndr_get_array_length(ndr, &r->in.unknown), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_unknown_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.num_ous);
+ }
+ _mem_save_num_ous_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.num_ous, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.num_ous));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_num_ous_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.num_ous);
+ *r->out.num_ous = *r->in.num_ous;
+ NDR_PULL_ALLOC(ndr, r->out.ous);
+ ZERO_STRUCTP(r->out.ous);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.num_ous);
+ }
+ _mem_save_num_ous_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.num_ous, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.num_ous));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_num_ous_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ous);
+ }
+ _mem_save_ous_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ous, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ous));
+ if (_ptr_ous) {
+ NDR_PULL_ALLOC(ndr, *r->out.ous);
+ } else {
+ *r->out.ous = NULL;
+ }
+ if (*r->out.ous) {
+ _mem_save_ous_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.ous, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->out.ous));
+ NDR_PULL_ALLOC_N(ndr, *r->out.ous, ndr_get_array_size(ndr, r->out.ous));
+ _mem_save_ous_2 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.ous, 0);
+ for (cntr_ous_2 = 0; cntr_ous_2 < *r->out.num_ous; cntr_ous_2++) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ous));
+ if (_ptr_ous) {
+ NDR_PULL_ALLOC(ndr, (*r->out.ous)[cntr_ous_2]);
+ } else {
+ (*r->out.ous)[cntr_ous_2] = NULL;
+ }
+ }
+ for (cntr_ous_2 = 0; cntr_ous_2 < *r->out.num_ous; cntr_ous_2++) {
+ if ((*r->out.ous)[cntr_ous_2]) {
+ _mem_save_ous_3 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, (*r->out.ous)[cntr_ous_2], 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &(*r->out.ous)[cntr_ous_2]));
+ NDR_CHECK(ndr_pull_array_length(ndr, &(*r->out.ous)[cntr_ous_2]));
+ if (ndr_get_array_length(ndr, &(*r->out.ous)[cntr_ous_2]) > ndr_get_array_size(ndr, &(*r->out.ous)[cntr_ous_2])) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &(*r->out.ous)[cntr_ous_2]), ndr_get_array_length(ndr, &(*r->out.ous)[cntr_ous_2]));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &(*r->out.ous)[cntr_ous_2]), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &(*r->out.ous)[cntr_ous_2], ndr_get_array_length(ndr, &(*r->out.ous)[cntr_ous_2]), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ous_3, 0);
+ }
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ous_2, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ous_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ous_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ if (*r->out.ous) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)r->out.ous, *r->out.num_ous));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrGetJoinableOus(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrGetJoinableOus *r)
+{
+ uint32_t cntr_ous_2;
+ ndr_print_struct(ndr, name, "wkssvc_NetrGetJoinableOus");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrGetJoinableOus");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_name", r->in.domain_name);
+ ndr->depth++;
+ ndr_print_string(ndr, "domain_name", r->in.domain_name);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "Account", r->in.Account);
+ ndr->depth++;
+ if (r->in.Account) {
+ ndr_print_string(ndr, "Account", r->in.Account);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "unknown", r->in.unknown);
+ ndr->depth++;
+ if (r->in.unknown) {
+ ndr_print_string(ndr, "unknown", r->in.unknown);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "num_ous", r->in.num_ous);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_ous", *r->in.num_ous);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrGetJoinableOus");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "num_ous", r->out.num_ous);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_ous", *r->out.num_ous);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ous", r->out.ous);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "ous", *r->out.ous);
+ ndr->depth++;
+ if (*r->out.ous) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "ous", (int)*r->out.num_ous);
+ ndr->depth++;
+ for (cntr_ous_2=0;cntr_ous_2<*r->out.num_ous;cntr_ous_2++) {
+ char *idx_2=NULL;
+ if (asprintf(&idx_2, "[%d]", cntr_ous_2) != -1) {
+ ndr_print_ptr(ndr, "ous", (*r->out.ous)[cntr_ous_2]);
+ ndr->depth++;
+ if ((*r->out.ous)[cntr_ous_2]) {
+ ndr_print_string(ndr, "ous", (*r->out.ous)[cntr_ous_2]);
+ }
+ ndr->depth--;
+ free(idx_2);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrJoinDomain2(struct ndr_push *ndr, int flags, const struct wkssvc_NetrJoinDomain2 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.domain_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.domain_name, ndr_charset_length(r->in.domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.account_ou));
+ if (r->in.account_ou) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_ou, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account_ou, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.account_ou, ndr_charset_length(r->in.account_ou, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.admin_account));
+ if (r->in.admin_account) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.admin_account, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.admin_account, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.admin_account, ndr_charset_length(r->in.admin_account, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.encrypted_password));
+ if (r->in.encrypted_password) {
+ NDR_CHECK(ndr_push_wkssvc_PasswordBuffer(ndr, NDR_SCALARS, r->in.encrypted_password));
+ }
+ NDR_CHECK(ndr_push_wkssvc_joinflags(ndr, NDR_SCALARS, r->in.join_flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrJoinDomain2(struct ndr_pull *ndr, int flags, struct wkssvc_NetrJoinDomain2 *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_account_ou;
+ uint32_t _ptr_admin_account;
+ uint32_t _ptr_encrypted_password;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_account_ou_0;
+ TALLOC_CTX *_mem_save_admin_account_0;
+ TALLOC_CTX *_mem_save_encrypted_password_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.domain_name));
+ if (ndr_get_array_length(ndr, &r->in.domain_name) > ndr_get_array_size(ndr, &r->in.domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.domain_name), ndr_get_array_length(ndr, &r->in.domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.domain_name, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_account_ou));
+ if (_ptr_account_ou) {
+ NDR_PULL_ALLOC(ndr, r->in.account_ou);
+ } else {
+ r->in.account_ou = NULL;
+ }
+ if (r->in.account_ou) {
+ _mem_save_account_ou_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.account_ou, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.account_ou));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.account_ou));
+ if (ndr_get_array_length(ndr, &r->in.account_ou) > ndr_get_array_size(ndr, &r->in.account_ou)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.account_ou), ndr_get_array_length(ndr, &r->in.account_ou));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.account_ou), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.account_ou, ndr_get_array_length(ndr, &r->in.account_ou), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_account_ou_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_admin_account));
+ if (_ptr_admin_account) {
+ NDR_PULL_ALLOC(ndr, r->in.admin_account);
+ } else {
+ r->in.admin_account = NULL;
+ }
+ if (r->in.admin_account) {
+ _mem_save_admin_account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.admin_account, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.admin_account));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.admin_account));
+ if (ndr_get_array_length(ndr, &r->in.admin_account) > ndr_get_array_size(ndr, &r->in.admin_account)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.admin_account), ndr_get_array_length(ndr, &r->in.admin_account));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.admin_account), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.admin_account, ndr_get_array_length(ndr, &r->in.admin_account), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_admin_account_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_encrypted_password));
+ if (_ptr_encrypted_password) {
+ NDR_PULL_ALLOC(ndr, r->in.encrypted_password);
+ } else {
+ r->in.encrypted_password = NULL;
+ }
+ if (r->in.encrypted_password) {
+ _mem_save_encrypted_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.encrypted_password, 0);
+ NDR_CHECK(ndr_pull_wkssvc_PasswordBuffer(ndr, NDR_SCALARS, r->in.encrypted_password));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_encrypted_password_0, 0);
+ }
+ NDR_CHECK(ndr_pull_wkssvc_joinflags(ndr, NDR_SCALARS, &r->in.join_flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrJoinDomain2(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrJoinDomain2 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrJoinDomain2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrJoinDomain2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_name", r->in.domain_name);
+ ndr->depth++;
+ ndr_print_string(ndr, "domain_name", r->in.domain_name);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "account_ou", r->in.account_ou);
+ ndr->depth++;
+ if (r->in.account_ou) {
+ ndr_print_string(ndr, "account_ou", r->in.account_ou);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "admin_account", r->in.admin_account);
+ ndr->depth++;
+ if (r->in.admin_account) {
+ ndr_print_string(ndr, "admin_account", r->in.admin_account);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "encrypted_password", r->in.encrypted_password);
+ ndr->depth++;
+ if (r->in.encrypted_password) {
+ ndr_print_wkssvc_PasswordBuffer(ndr, "encrypted_password", r->in.encrypted_password);
+ }
+ ndr->depth--;
+ ndr_print_wkssvc_joinflags(ndr, "join_flags", r->in.join_flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrJoinDomain2");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrUnjoinDomain2(struct ndr_push *ndr, int flags, const struct wkssvc_NetrUnjoinDomain2 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.account));
+ if (r->in.account) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.account, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.account, ndr_charset_length(r->in.account, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.encrypted_password));
+ if (r->in.encrypted_password) {
+ NDR_CHECK(ndr_push_wkssvc_PasswordBuffer(ndr, NDR_SCALARS, r->in.encrypted_password));
+ }
+ NDR_CHECK(ndr_push_wkssvc_joinflags(ndr, NDR_SCALARS, r->in.unjoin_flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrUnjoinDomain2(struct ndr_pull *ndr, int flags, struct wkssvc_NetrUnjoinDomain2 *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_account;
+ uint32_t _ptr_encrypted_password;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_account_0;
+ TALLOC_CTX *_mem_save_encrypted_password_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_account));
+ if (_ptr_account) {
+ NDR_PULL_ALLOC(ndr, r->in.account);
+ } else {
+ r->in.account = NULL;
+ }
+ if (r->in.account) {
+ _mem_save_account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.account, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.account));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.account));
+ if (ndr_get_array_length(ndr, &r->in.account) > ndr_get_array_size(ndr, &r->in.account)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.account), ndr_get_array_length(ndr, &r->in.account));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.account), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.account, ndr_get_array_length(ndr, &r->in.account), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_account_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_encrypted_password));
+ if (_ptr_encrypted_password) {
+ NDR_PULL_ALLOC(ndr, r->in.encrypted_password);
+ } else {
+ r->in.encrypted_password = NULL;
+ }
+ if (r->in.encrypted_password) {
+ _mem_save_encrypted_password_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.encrypted_password, 0);
+ NDR_CHECK(ndr_pull_wkssvc_PasswordBuffer(ndr, NDR_SCALARS, r->in.encrypted_password));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_encrypted_password_0, 0);
+ }
+ NDR_CHECK(ndr_pull_wkssvc_joinflags(ndr, NDR_SCALARS, &r->in.unjoin_flags));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrUnjoinDomain2(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUnjoinDomain2 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrUnjoinDomain2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrUnjoinDomain2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "account", r->in.account);
+ ndr->depth++;
+ if (r->in.account) {
+ ndr_print_string(ndr, "account", r->in.account);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "encrypted_password", r->in.encrypted_password);
+ ndr->depth++;
+ if (r->in.encrypted_password) {
+ ndr_print_wkssvc_PasswordBuffer(ndr, "encrypted_password", r->in.encrypted_password);
+ }
+ ndr->depth--;
+ ndr_print_wkssvc_joinflags(ndr, "unjoin_flags", r->in.unjoin_flags);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrUnjoinDomain2");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrRenameMachineInDomain2(struct ndr_push *ndr, int flags, const struct wkssvc_NetrRenameMachineInDomain2 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.NewMachineName));
+ if (r->in.NewMachineName) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.NewMachineName, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.NewMachineName, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.NewMachineName, ndr_charset_length(r->in.NewMachineName, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.Account));
+ if (r->in.Account) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.Account, ndr_charset_length(r->in.Account, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.EncryptedPassword));
+ if (r->in.EncryptedPassword) {
+ NDR_CHECK(ndr_push_wkssvc_PasswordBuffer(ndr, NDR_SCALARS, r->in.EncryptedPassword));
+ }
+ NDR_CHECK(ndr_push_wkssvc_renameflags(ndr, NDR_SCALARS, r->in.RenameOptions));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrRenameMachineInDomain2(struct ndr_pull *ndr, int flags, struct wkssvc_NetrRenameMachineInDomain2 *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_NewMachineName;
+ uint32_t _ptr_Account;
+ uint32_t _ptr_EncryptedPassword;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_NewMachineName_0;
+ TALLOC_CTX *_mem_save_Account_0;
+ TALLOC_CTX *_mem_save_EncryptedPassword_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_NewMachineName));
+ if (_ptr_NewMachineName) {
+ NDR_PULL_ALLOC(ndr, r->in.NewMachineName);
+ } else {
+ r->in.NewMachineName = NULL;
+ }
+ if (r->in.NewMachineName) {
+ _mem_save_NewMachineName_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.NewMachineName, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.NewMachineName));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.NewMachineName));
+ if (ndr_get_array_length(ndr, &r->in.NewMachineName) > ndr_get_array_size(ndr, &r->in.NewMachineName)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.NewMachineName), ndr_get_array_length(ndr, &r->in.NewMachineName));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.NewMachineName), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.NewMachineName, ndr_get_array_length(ndr, &r->in.NewMachineName), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_NewMachineName_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_Account));
+ if (_ptr_Account) {
+ NDR_PULL_ALLOC(ndr, r->in.Account);
+ } else {
+ r->in.Account = NULL;
+ }
+ if (r->in.Account) {
+ _mem_save_Account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.Account, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.Account));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.Account));
+ if (ndr_get_array_length(ndr, &r->in.Account) > ndr_get_array_size(ndr, &r->in.Account)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.Account), ndr_get_array_length(ndr, &r->in.Account));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.Account, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_Account_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_EncryptedPassword));
+ if (_ptr_EncryptedPassword) {
+ NDR_PULL_ALLOC(ndr, r->in.EncryptedPassword);
+ } else {
+ r->in.EncryptedPassword = NULL;
+ }
+ if (r->in.EncryptedPassword) {
+ _mem_save_EncryptedPassword_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.EncryptedPassword, 0);
+ NDR_CHECK(ndr_pull_wkssvc_PasswordBuffer(ndr, NDR_SCALARS, r->in.EncryptedPassword));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_EncryptedPassword_0, 0);
+ }
+ NDR_CHECK(ndr_pull_wkssvc_renameflags(ndr, NDR_SCALARS, &r->in.RenameOptions));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrRenameMachineInDomain2(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrRenameMachineInDomain2 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrRenameMachineInDomain2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrRenameMachineInDomain2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "NewMachineName", r->in.NewMachineName);
+ ndr->depth++;
+ if (r->in.NewMachineName) {
+ ndr_print_string(ndr, "NewMachineName", r->in.NewMachineName);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "Account", r->in.Account);
+ ndr->depth++;
+ if (r->in.Account) {
+ ndr_print_string(ndr, "Account", r->in.Account);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "EncryptedPassword", r->in.EncryptedPassword);
+ ndr->depth++;
+ if (r->in.EncryptedPassword) {
+ ndr_print_wkssvc_PasswordBuffer(ndr, "EncryptedPassword", r->in.EncryptedPassword);
+ }
+ ndr->depth--;
+ ndr_print_wkssvc_renameflags(ndr, "RenameOptions", r->in.RenameOptions);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrRenameMachineInDomain2");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrValidateName2(struct ndr_push *ndr, int flags, const struct wkssvc_NetrValidateName2 *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.name, ndr_charset_length(r->in.name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.Account));
+ if (r->in.Account) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.Account, ndr_charset_length(r->in.Account, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.EncryptedPassword));
+ if (r->in.EncryptedPassword) {
+ NDR_CHECK(ndr_push_wkssvc_PasswordBuffer(ndr, NDR_SCALARS, r->in.EncryptedPassword));
+ }
+ NDR_CHECK(ndr_push_wkssvc_NetValidateNameType(ndr, NDR_SCALARS, r->in.name_type));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrValidateName2(struct ndr_pull *ndr, int flags, struct wkssvc_NetrValidateName2 *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_Account;
+ uint32_t _ptr_EncryptedPassword;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_Account_0;
+ TALLOC_CTX *_mem_save_EncryptedPassword_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.name));
+ if (ndr_get_array_length(ndr, &r->in.name) > ndr_get_array_size(ndr, &r->in.name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.name), ndr_get_array_length(ndr, &r->in.name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.name, ndr_get_array_length(ndr, &r->in.name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_Account));
+ if (_ptr_Account) {
+ NDR_PULL_ALLOC(ndr, r->in.Account);
+ } else {
+ r->in.Account = NULL;
+ }
+ if (r->in.Account) {
+ _mem_save_Account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.Account, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.Account));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.Account));
+ if (ndr_get_array_length(ndr, &r->in.Account) > ndr_get_array_size(ndr, &r->in.Account)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.Account), ndr_get_array_length(ndr, &r->in.Account));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.Account, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_Account_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_EncryptedPassword));
+ if (_ptr_EncryptedPassword) {
+ NDR_PULL_ALLOC(ndr, r->in.EncryptedPassword);
+ } else {
+ r->in.EncryptedPassword = NULL;
+ }
+ if (r->in.EncryptedPassword) {
+ _mem_save_EncryptedPassword_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.EncryptedPassword, 0);
+ NDR_CHECK(ndr_pull_wkssvc_PasswordBuffer(ndr, NDR_SCALARS, r->in.EncryptedPassword));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_EncryptedPassword_0, 0);
+ }
+ NDR_CHECK(ndr_pull_wkssvc_NetValidateNameType(ndr, NDR_SCALARS, &r->in.name_type));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrValidateName2(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrValidateName2 *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrValidateName2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrValidateName2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "name", r->in.name);
+ ndr->depth++;
+ ndr_print_string(ndr, "name", r->in.name);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "Account", r->in.Account);
+ ndr->depth++;
+ if (r->in.Account) {
+ ndr_print_string(ndr, "Account", r->in.Account);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "EncryptedPassword", r->in.EncryptedPassword);
+ ndr->depth++;
+ if (r->in.EncryptedPassword) {
+ ndr_print_wkssvc_PasswordBuffer(ndr, "EncryptedPassword", r->in.EncryptedPassword);
+ }
+ ndr->depth--;
+ ndr_print_wkssvc_NetValidateNameType(ndr, "name_type", r->in.name_type);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrValidateName2");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrGetJoinableOus2(struct ndr_push *ndr, int flags, const struct wkssvc_NetrGetJoinableOus2 *r)
+{
+ uint32_t cntr_ous_2;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ if (r->in.domain_name == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.domain_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.domain_name, ndr_charset_length(r->in.domain_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.Account));
+ if (r->in.Account) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.Account, ndr_charset_length(r->in.Account, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.EncryptedPassword));
+ if (r->in.EncryptedPassword) {
+ NDR_CHECK(ndr_push_wkssvc_PasswordBuffer(ndr, NDR_SCALARS, r->in.EncryptedPassword));
+ }
+ if (r->in.num_ous == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->in.num_ous));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.num_ous == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.num_ous));
+ if (r->out.ous == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.ous));
+ if (*r->out.ous) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, *r->out.num_ous));
+ for (cntr_ous_2 = 0; cntr_ous_2 < *r->out.num_ous; cntr_ous_2++) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, (*r->out.ous)[cntr_ous_2]));
+ }
+ for (cntr_ous_2 = 0; cntr_ous_2 < *r->out.num_ous; cntr_ous_2++) {
+ if ((*r->out.ous)[cntr_ous_2]) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length((*r->out.ous)[cntr_ous_2], CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length((*r->out.ous)[cntr_ous_2], CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, (*r->out.ous)[cntr_ous_2], ndr_charset_length((*r->out.ous)[cntr_ous_2], CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ }
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrGetJoinableOus2(struct ndr_pull *ndr, int flags, struct wkssvc_NetrGetJoinableOus2 *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_Account;
+ uint32_t _ptr_EncryptedPassword;
+ uint32_t _ptr_ous;
+ uint32_t cntr_ous_2;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_Account_0;
+ TALLOC_CTX *_mem_save_EncryptedPassword_0;
+ TALLOC_CTX *_mem_save_num_ous_0;
+ TALLOC_CTX *_mem_save_ous_0;
+ TALLOC_CTX *_mem_save_ous_1;
+ TALLOC_CTX *_mem_save_ous_2;
+ TALLOC_CTX *_mem_save_ous_3;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.domain_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.domain_name));
+ if (ndr_get_array_length(ndr, &r->in.domain_name) > ndr_get_array_size(ndr, &r->in.domain_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.domain_name), ndr_get_array_length(ndr, &r->in.domain_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.domain_name, ndr_get_array_length(ndr, &r->in.domain_name), sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_Account));
+ if (_ptr_Account) {
+ NDR_PULL_ALLOC(ndr, r->in.Account);
+ } else {
+ r->in.Account = NULL;
+ }
+ if (r->in.Account) {
+ _mem_save_Account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.Account, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.Account));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.Account));
+ if (ndr_get_array_length(ndr, &r->in.Account) > ndr_get_array_size(ndr, &r->in.Account)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.Account), ndr_get_array_length(ndr, &r->in.Account));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.Account, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_Account_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_EncryptedPassword));
+ if (_ptr_EncryptedPassword) {
+ NDR_PULL_ALLOC(ndr, r->in.EncryptedPassword);
+ } else {
+ r->in.EncryptedPassword = NULL;
+ }
+ if (r->in.EncryptedPassword) {
+ _mem_save_EncryptedPassword_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.EncryptedPassword, 0);
+ NDR_CHECK(ndr_pull_wkssvc_PasswordBuffer(ndr, NDR_SCALARS, r->in.EncryptedPassword));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_EncryptedPassword_0, 0);
+ }
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->in.num_ous);
+ }
+ _mem_save_num_ous_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.num_ous, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->in.num_ous));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_num_ous_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_PULL_ALLOC(ndr, r->out.num_ous);
+ *r->out.num_ous = *r->in.num_ous;
+ NDR_PULL_ALLOC(ndr, r->out.ous);
+ ZERO_STRUCTP(r->out.ous);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.num_ous);
+ }
+ _mem_save_num_ous_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.num_ous, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.num_ous));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_num_ous_0, LIBNDR_FLAG_REF_ALLOC);
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ous);
+ }
+ _mem_save_ous_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ous, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ous));
+ if (_ptr_ous) {
+ NDR_PULL_ALLOC(ndr, *r->out.ous);
+ } else {
+ *r->out.ous = NULL;
+ }
+ if (*r->out.ous) {
+ _mem_save_ous_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.ous, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, r->out.ous));
+ NDR_PULL_ALLOC_N(ndr, *r->out.ous, ndr_get_array_size(ndr, r->out.ous));
+ _mem_save_ous_2 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.ous, 0);
+ for (cntr_ous_2 = 0; cntr_ous_2 < *r->out.num_ous; cntr_ous_2++) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ous));
+ if (_ptr_ous) {
+ NDR_PULL_ALLOC(ndr, (*r->out.ous)[cntr_ous_2]);
+ } else {
+ (*r->out.ous)[cntr_ous_2] = NULL;
+ }
+ }
+ for (cntr_ous_2 = 0; cntr_ous_2 < *r->out.num_ous; cntr_ous_2++) {
+ if ((*r->out.ous)[cntr_ous_2]) {
+ _mem_save_ous_3 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, (*r->out.ous)[cntr_ous_2], 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &(*r->out.ous)[cntr_ous_2]));
+ NDR_CHECK(ndr_pull_array_length(ndr, &(*r->out.ous)[cntr_ous_2]));
+ if (ndr_get_array_length(ndr, &(*r->out.ous)[cntr_ous_2]) > ndr_get_array_size(ndr, &(*r->out.ous)[cntr_ous_2])) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &(*r->out.ous)[cntr_ous_2]), ndr_get_array_length(ndr, &(*r->out.ous)[cntr_ous_2]));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &(*r->out.ous)[cntr_ous_2]), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &(*r->out.ous)[cntr_ous_2], ndr_get_array_length(ndr, &(*r->out.ous)[cntr_ous_2]), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ous_3, 0);
+ }
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ous_2, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ous_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ous_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ if (*r->out.ous) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)r->out.ous, *r->out.num_ous));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrGetJoinableOus2(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrGetJoinableOus2 *r)
+{
+ uint32_t cntr_ous_2;
+ ndr_print_struct(ndr, name, "wkssvc_NetrGetJoinableOus2");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrGetJoinableOus2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "domain_name", r->in.domain_name);
+ ndr->depth++;
+ ndr_print_string(ndr, "domain_name", r->in.domain_name);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "Account", r->in.Account);
+ ndr->depth++;
+ if (r->in.Account) {
+ ndr_print_string(ndr, "Account", r->in.Account);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "EncryptedPassword", r->in.EncryptedPassword);
+ ndr->depth++;
+ if (r->in.EncryptedPassword) {
+ ndr_print_wkssvc_PasswordBuffer(ndr, "EncryptedPassword", r->in.EncryptedPassword);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "num_ous", r->in.num_ous);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_ous", *r->in.num_ous);
+ ndr->depth--;
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrGetJoinableOus2");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "num_ous", r->out.num_ous);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_ous", *r->out.num_ous);
+ ndr->depth--;
+ ndr_print_ptr(ndr, "ous", r->out.ous);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "ous", *r->out.ous);
+ ndr->depth++;
+ if (*r->out.ous) {
+ ndr->print(ndr, "%s: ARRAY(%d)", "ous", (int)*r->out.num_ous);
+ ndr->depth++;
+ for (cntr_ous_2=0;cntr_ous_2<*r->out.num_ous;cntr_ous_2++) {
+ char *idx_2=NULL;
+ if (asprintf(&idx_2, "[%d]", cntr_ous_2) != -1) {
+ ndr_print_ptr(ndr, "ous", (*r->out.ous)[cntr_ous_2]);
+ ndr->depth++;
+ if ((*r->out.ous)[cntr_ous_2]) {
+ ndr_print_string(ndr, "ous", (*r->out.ous)[cntr_ous_2]);
+ }
+ ndr->depth--;
+ free(idx_2);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrAddAlternateComputerName(struct ndr_push *ndr, int flags, const struct wkssvc_NetrAddAlternateComputerName *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.NewAlternateMachineName));
+ if (r->in.NewAlternateMachineName) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.NewAlternateMachineName, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.NewAlternateMachineName, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.NewAlternateMachineName, ndr_charset_length(r->in.NewAlternateMachineName, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.Account));
+ if (r->in.Account) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.Account, ndr_charset_length(r->in.Account, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.EncryptedPassword));
+ if (r->in.EncryptedPassword) {
+ NDR_CHECK(ndr_push_wkssvc_PasswordBuffer(ndr, NDR_SCALARS, r->in.EncryptedPassword));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.Reserved));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrAddAlternateComputerName(struct ndr_pull *ndr, int flags, struct wkssvc_NetrAddAlternateComputerName *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_NewAlternateMachineName;
+ uint32_t _ptr_Account;
+ uint32_t _ptr_EncryptedPassword;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_NewAlternateMachineName_0;
+ TALLOC_CTX *_mem_save_Account_0;
+ TALLOC_CTX *_mem_save_EncryptedPassword_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_NewAlternateMachineName));
+ if (_ptr_NewAlternateMachineName) {
+ NDR_PULL_ALLOC(ndr, r->in.NewAlternateMachineName);
+ } else {
+ r->in.NewAlternateMachineName = NULL;
+ }
+ if (r->in.NewAlternateMachineName) {
+ _mem_save_NewAlternateMachineName_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.NewAlternateMachineName, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.NewAlternateMachineName));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.NewAlternateMachineName));
+ if (ndr_get_array_length(ndr, &r->in.NewAlternateMachineName) > ndr_get_array_size(ndr, &r->in.NewAlternateMachineName)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.NewAlternateMachineName), ndr_get_array_length(ndr, &r->in.NewAlternateMachineName));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.NewAlternateMachineName), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.NewAlternateMachineName, ndr_get_array_length(ndr, &r->in.NewAlternateMachineName), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_NewAlternateMachineName_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_Account));
+ if (_ptr_Account) {
+ NDR_PULL_ALLOC(ndr, r->in.Account);
+ } else {
+ r->in.Account = NULL;
+ }
+ if (r->in.Account) {
+ _mem_save_Account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.Account, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.Account));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.Account));
+ if (ndr_get_array_length(ndr, &r->in.Account) > ndr_get_array_size(ndr, &r->in.Account)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.Account), ndr_get_array_length(ndr, &r->in.Account));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.Account, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_Account_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_EncryptedPassword));
+ if (_ptr_EncryptedPassword) {
+ NDR_PULL_ALLOC(ndr, r->in.EncryptedPassword);
+ } else {
+ r->in.EncryptedPassword = NULL;
+ }
+ if (r->in.EncryptedPassword) {
+ _mem_save_EncryptedPassword_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.EncryptedPassword, 0);
+ NDR_CHECK(ndr_pull_wkssvc_PasswordBuffer(ndr, NDR_SCALARS, r->in.EncryptedPassword));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_EncryptedPassword_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.Reserved));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrAddAlternateComputerName(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrAddAlternateComputerName *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrAddAlternateComputerName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrAddAlternateComputerName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "NewAlternateMachineName", r->in.NewAlternateMachineName);
+ ndr->depth++;
+ if (r->in.NewAlternateMachineName) {
+ ndr_print_string(ndr, "NewAlternateMachineName", r->in.NewAlternateMachineName);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "Account", r->in.Account);
+ ndr->depth++;
+ if (r->in.Account) {
+ ndr_print_string(ndr, "Account", r->in.Account);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "EncryptedPassword", r->in.EncryptedPassword);
+ ndr->depth++;
+ if (r->in.EncryptedPassword) {
+ ndr_print_wkssvc_PasswordBuffer(ndr, "EncryptedPassword", r->in.EncryptedPassword);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "Reserved", r->in.Reserved);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrAddAlternateComputerName");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrRemoveAlternateComputerName(struct ndr_push *ndr, int flags, const struct wkssvc_NetrRemoveAlternateComputerName *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.AlternateMachineNameToRemove));
+ if (r->in.AlternateMachineNameToRemove) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.AlternateMachineNameToRemove, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.AlternateMachineNameToRemove, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.AlternateMachineNameToRemove, ndr_charset_length(r->in.AlternateMachineNameToRemove, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.Account));
+ if (r->in.Account) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.Account, ndr_charset_length(r->in.Account, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.EncryptedPassword));
+ if (r->in.EncryptedPassword) {
+ NDR_CHECK(ndr_push_wkssvc_PasswordBuffer(ndr, NDR_SCALARS, r->in.EncryptedPassword));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.Reserved));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrRemoveAlternateComputerName(struct ndr_pull *ndr, int flags, struct wkssvc_NetrRemoveAlternateComputerName *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_AlternateMachineNameToRemove;
+ uint32_t _ptr_Account;
+ uint32_t _ptr_EncryptedPassword;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_AlternateMachineNameToRemove_0;
+ TALLOC_CTX *_mem_save_Account_0;
+ TALLOC_CTX *_mem_save_EncryptedPassword_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_AlternateMachineNameToRemove));
+ if (_ptr_AlternateMachineNameToRemove) {
+ NDR_PULL_ALLOC(ndr, r->in.AlternateMachineNameToRemove);
+ } else {
+ r->in.AlternateMachineNameToRemove = NULL;
+ }
+ if (r->in.AlternateMachineNameToRemove) {
+ _mem_save_AlternateMachineNameToRemove_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.AlternateMachineNameToRemove, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.AlternateMachineNameToRemove));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.AlternateMachineNameToRemove));
+ if (ndr_get_array_length(ndr, &r->in.AlternateMachineNameToRemove) > ndr_get_array_size(ndr, &r->in.AlternateMachineNameToRemove)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.AlternateMachineNameToRemove), ndr_get_array_length(ndr, &r->in.AlternateMachineNameToRemove));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.AlternateMachineNameToRemove), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.AlternateMachineNameToRemove, ndr_get_array_length(ndr, &r->in.AlternateMachineNameToRemove), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_AlternateMachineNameToRemove_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_Account));
+ if (_ptr_Account) {
+ NDR_PULL_ALLOC(ndr, r->in.Account);
+ } else {
+ r->in.Account = NULL;
+ }
+ if (r->in.Account) {
+ _mem_save_Account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.Account, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.Account));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.Account));
+ if (ndr_get_array_length(ndr, &r->in.Account) > ndr_get_array_size(ndr, &r->in.Account)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.Account), ndr_get_array_length(ndr, &r->in.Account));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.Account, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_Account_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_EncryptedPassword));
+ if (_ptr_EncryptedPassword) {
+ NDR_PULL_ALLOC(ndr, r->in.EncryptedPassword);
+ } else {
+ r->in.EncryptedPassword = NULL;
+ }
+ if (r->in.EncryptedPassword) {
+ _mem_save_EncryptedPassword_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.EncryptedPassword, 0);
+ NDR_CHECK(ndr_pull_wkssvc_PasswordBuffer(ndr, NDR_SCALARS, r->in.EncryptedPassword));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_EncryptedPassword_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.Reserved));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrRemoveAlternateComputerName(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrRemoveAlternateComputerName *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrRemoveAlternateComputerName");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrRemoveAlternateComputerName");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "AlternateMachineNameToRemove", r->in.AlternateMachineNameToRemove);
+ ndr->depth++;
+ if (r->in.AlternateMachineNameToRemove) {
+ ndr_print_string(ndr, "AlternateMachineNameToRemove", r->in.AlternateMachineNameToRemove);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "Account", r->in.Account);
+ ndr->depth++;
+ if (r->in.Account) {
+ ndr_print_string(ndr, "Account", r->in.Account);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "EncryptedPassword", r->in.EncryptedPassword);
+ ndr->depth++;
+ if (r->in.EncryptedPassword) {
+ ndr_print_wkssvc_PasswordBuffer(ndr, "EncryptedPassword", r->in.EncryptedPassword);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "Reserved", r->in.Reserved);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrRemoveAlternateComputerName");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrSetPrimaryComputername(struct ndr_push *ndr, int flags, const struct wkssvc_NetrSetPrimaryComputername *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.primary_name));
+ if (r->in.primary_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.primary_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.primary_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.primary_name, ndr_charset_length(r->in.primary_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.Account));
+ if (r->in.Account) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.Account, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.Account, ndr_charset_length(r->in.Account, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.EncryptedPassword));
+ if (r->in.EncryptedPassword) {
+ NDR_CHECK(ndr_push_wkssvc_PasswordBuffer(ndr, NDR_SCALARS, r->in.EncryptedPassword));
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.Reserved));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrSetPrimaryComputername(struct ndr_pull *ndr, int flags, struct wkssvc_NetrSetPrimaryComputername *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_primary_name;
+ uint32_t _ptr_Account;
+ uint32_t _ptr_EncryptedPassword;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_primary_name_0;
+ TALLOC_CTX *_mem_save_Account_0;
+ TALLOC_CTX *_mem_save_EncryptedPassword_0;
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_primary_name));
+ if (_ptr_primary_name) {
+ NDR_PULL_ALLOC(ndr, r->in.primary_name);
+ } else {
+ r->in.primary_name = NULL;
+ }
+ if (r->in.primary_name) {
+ _mem_save_primary_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.primary_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.primary_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.primary_name));
+ if (ndr_get_array_length(ndr, &r->in.primary_name) > ndr_get_array_size(ndr, &r->in.primary_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.primary_name), ndr_get_array_length(ndr, &r->in.primary_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.primary_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.primary_name, ndr_get_array_length(ndr, &r->in.primary_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_primary_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_Account));
+ if (_ptr_Account) {
+ NDR_PULL_ALLOC(ndr, r->in.Account);
+ } else {
+ r->in.Account = NULL;
+ }
+ if (r->in.Account) {
+ _mem_save_Account_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.Account, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.Account));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.Account));
+ if (ndr_get_array_length(ndr, &r->in.Account) > ndr_get_array_size(ndr, &r->in.Account)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.Account), ndr_get_array_length(ndr, &r->in.Account));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.Account, ndr_get_array_length(ndr, &r->in.Account), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_Account_0, 0);
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_EncryptedPassword));
+ if (_ptr_EncryptedPassword) {
+ NDR_PULL_ALLOC(ndr, r->in.EncryptedPassword);
+ } else {
+ r->in.EncryptedPassword = NULL;
+ }
+ if (r->in.EncryptedPassword) {
+ _mem_save_EncryptedPassword_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.EncryptedPassword, 0);
+ NDR_CHECK(ndr_pull_wkssvc_PasswordBuffer(ndr, NDR_SCALARS, r->in.EncryptedPassword));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_EncryptedPassword_0, 0);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.Reserved));
+ }
+ if (flags & NDR_OUT) {
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrSetPrimaryComputername(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrSetPrimaryComputername *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrSetPrimaryComputername");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrSetPrimaryComputername");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "primary_name", r->in.primary_name);
+ ndr->depth++;
+ if (r->in.primary_name) {
+ ndr_print_string(ndr, "primary_name", r->in.primary_name);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "Account", r->in.Account);
+ ndr->depth++;
+ if (r->in.Account) {
+ ndr_print_string(ndr, "Account", r->in.Account);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "EncryptedPassword", r->in.EncryptedPassword);
+ ndr->depth++;
+ if (r->in.EncryptedPassword) {
+ ndr_print_wkssvc_PasswordBuffer(ndr, "EncryptedPassword", r->in.EncryptedPassword);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "Reserved", r->in.Reserved);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrSetPrimaryComputername");
+ ndr->depth++;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_wkssvc_NetrEnumerateComputerNames(struct ndr_push *ndr, int flags, const struct wkssvc_NetrEnumerateComputerNames *r)
+{
+ if (flags & NDR_IN) {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->in.server_name));
+ if (r->in.server_name) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_charset_length(r->in.server_name, CH_UTF16)));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, r->in.server_name, ndr_charset_length(r->in.server_name, CH_UTF16), sizeof(uint16_t), CH_UTF16));
+ }
+ NDR_CHECK(ndr_push_wkssvc_ComputerNameType(ndr, NDR_SCALARS, r->in.name_type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->in.Reserved));
+ }
+ if (flags & NDR_OUT) {
+ if (r->out.ctr == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+ NDR_CHECK(ndr_push_unique_ptr(ndr, *r->out.ctr));
+ if (*r->out.ctr) {
+ NDR_CHECK(ndr_push_wkssvc_ComputerNamesCtr(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.ctr));
+ }
+ NDR_CHECK(ndr_push_WERROR(ndr, NDR_SCALARS, r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_wkssvc_NetrEnumerateComputerNames(struct ndr_pull *ndr, int flags, struct wkssvc_NetrEnumerateComputerNames *r)
+{
+ uint32_t _ptr_server_name;
+ uint32_t _ptr_ctr;
+ TALLOC_CTX *_mem_save_server_name_0;
+ TALLOC_CTX *_mem_save_ctr_0;
+ TALLOC_CTX *_mem_save_ctr_1;
+ if (flags & NDR_IN) {
+ ZERO_STRUCT(r->out);
+
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_server_name));
+ if (_ptr_server_name) {
+ NDR_PULL_ALLOC(ndr, r->in.server_name);
+ } else {
+ r->in.server_name = NULL;
+ }
+ if (r->in.server_name) {
+ _mem_save_server_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->in.server_name, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->in.server_name));
+ NDR_CHECK(ndr_pull_array_length(ndr, &r->in.server_name));
+ if (ndr_get_array_length(ndr, &r->in.server_name) > ndr_get_array_size(ndr, &r->in.server_name)) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", ndr_get_array_size(ndr, &r->in.server_name), ndr_get_array_length(ndr, &r->in.server_name));
+ }
+ NDR_CHECK(ndr_check_string_terminator(ndr, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t)));
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.server_name, ndr_get_array_length(ndr, &r->in.server_name), sizeof(uint16_t), CH_UTF16));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_server_name_0, 0);
+ }
+ NDR_CHECK(ndr_pull_wkssvc_ComputerNameType(ndr, NDR_SCALARS, &r->in.name_type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->in.Reserved));
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ ZERO_STRUCTP(r->out.ctr);
+ }
+ if (flags & NDR_OUT) {
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.ctr);
+ }
+ _mem_save_ctr_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->out.ctr, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_ctr));
+ if (_ptr_ctr) {
+ NDR_PULL_ALLOC(ndr, *r->out.ctr);
+ } else {
+ *r->out.ctr = NULL;
+ }
+ if (*r->out.ctr) {
+ _mem_save_ctr_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, *r->out.ctr, 0);
+ NDR_CHECK(ndr_pull_wkssvc_ComputerNamesCtr(ndr, NDR_SCALARS|NDR_BUFFERS, *r->out.ctr));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_1, 0);
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_ctr_0, LIBNDR_FLAG_REF_ALLOC);
+ NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wkssvc_NetrEnumerateComputerNames(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrEnumerateComputerNames *r)
+{
+ ndr_print_struct(ndr, name, "wkssvc_NetrEnumerateComputerNames");
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ ndr_print_struct(ndr, "in", "wkssvc_NetrEnumerateComputerNames");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "server_name", r->in.server_name);
+ ndr->depth++;
+ if (r->in.server_name) {
+ ndr_print_string(ndr, "server_name", r->in.server_name);
+ }
+ ndr->depth--;
+ ndr_print_wkssvc_ComputerNameType(ndr, "name_type", r->in.name_type);
+ ndr_print_uint32(ndr, "Reserved", r->in.Reserved);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "wkssvc_NetrEnumerateComputerNames");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "ctr", r->out.ctr);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "ctr", *r->out.ctr);
+ ndr->depth++;
+ if (*r->out.ctr) {
+ ndr_print_wkssvc_ComputerNamesCtr(ndr, "ctr", *r->out.ctr);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+static const struct ndr_interface_call wkssvc_calls[] = {
+ {
+ "wkssvc_NetWkstaGetInfo",
+ sizeof(struct wkssvc_NetWkstaGetInfo),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetWkstaGetInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetWkstaGetInfo,
+ (ndr_print_function_t) ndr_print_wkssvc_NetWkstaGetInfo,
+ false,
+ },
+ {
+ "wkssvc_NetWkstaSetInfo",
+ sizeof(struct wkssvc_NetWkstaSetInfo),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetWkstaSetInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetWkstaSetInfo,
+ (ndr_print_function_t) ndr_print_wkssvc_NetWkstaSetInfo,
+ false,
+ },
+ {
+ "wkssvc_NetWkstaEnumUsers",
+ sizeof(struct wkssvc_NetWkstaEnumUsers),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetWkstaEnumUsers,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetWkstaEnumUsers,
+ (ndr_print_function_t) ndr_print_wkssvc_NetWkstaEnumUsers,
+ false,
+ },
+ {
+ "wkssvc_NetrWkstaUserGetInfo",
+ sizeof(struct wkssvc_NetrWkstaUserGetInfo),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrWkstaUserGetInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrWkstaUserGetInfo,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrWkstaUserGetInfo,
+ false,
+ },
+ {
+ "wkssvc_NetrWkstaUserSetInfo",
+ sizeof(struct wkssvc_NetrWkstaUserSetInfo),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrWkstaUserSetInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrWkstaUserSetInfo,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrWkstaUserSetInfo,
+ false,
+ },
+ {
+ "wkssvc_NetWkstaTransportEnum",
+ sizeof(struct wkssvc_NetWkstaTransportEnum),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetWkstaTransportEnum,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetWkstaTransportEnum,
+ (ndr_print_function_t) ndr_print_wkssvc_NetWkstaTransportEnum,
+ false,
+ },
+ {
+ "wkssvc_NetrWkstaTransportAdd",
+ sizeof(struct wkssvc_NetrWkstaTransportAdd),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrWkstaTransportAdd,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrWkstaTransportAdd,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrWkstaTransportAdd,
+ false,
+ },
+ {
+ "wkssvc_NetrWkstaTransportDel",
+ sizeof(struct wkssvc_NetrWkstaTransportDel),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrWkstaTransportDel,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrWkstaTransportDel,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrWkstaTransportDel,
+ false,
+ },
+ {
+ "wkssvc_NetrUseAdd",
+ sizeof(struct wkssvc_NetrUseAdd),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrUseAdd,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrUseAdd,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrUseAdd,
+ false,
+ },
+ {
+ "wkssvc_NetrUseGetInfo",
+ sizeof(struct wkssvc_NetrUseGetInfo),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrUseGetInfo,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrUseGetInfo,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrUseGetInfo,
+ false,
+ },
+ {
+ "wkssvc_NetrUseDel",
+ sizeof(struct wkssvc_NetrUseDel),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrUseDel,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrUseDel,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrUseDel,
+ false,
+ },
+ {
+ "wkssvc_NetrUseEnum",
+ sizeof(struct wkssvc_NetrUseEnum),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrUseEnum,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrUseEnum,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrUseEnum,
+ false,
+ },
+ {
+ "wkssvc_NetrMessageBufferSend",
+ sizeof(struct wkssvc_NetrMessageBufferSend),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrMessageBufferSend,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrMessageBufferSend,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrMessageBufferSend,
+ false,
+ },
+ {
+ "wkssvc_NetrWorkstationStatisticsGet",
+ sizeof(struct wkssvc_NetrWorkstationStatisticsGet),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrWorkstationStatisticsGet,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrWorkstationStatisticsGet,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrWorkstationStatisticsGet,
+ false,
+ },
+ {
+ "wkssvc_NetrLogonDomainNameAdd",
+ sizeof(struct wkssvc_NetrLogonDomainNameAdd),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrLogonDomainNameAdd,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrLogonDomainNameAdd,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrLogonDomainNameAdd,
+ false,
+ },
+ {
+ "wkssvc_NetrLogonDomainNameDel",
+ sizeof(struct wkssvc_NetrLogonDomainNameDel),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrLogonDomainNameDel,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrLogonDomainNameDel,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrLogonDomainNameDel,
+ false,
+ },
+ {
+ "wkssvc_NetrJoinDomain",
+ sizeof(struct wkssvc_NetrJoinDomain),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrJoinDomain,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrJoinDomain,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrJoinDomain,
+ false,
+ },
+ {
+ "wkssvc_NetrUnjoinDomain",
+ sizeof(struct wkssvc_NetrUnjoinDomain),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrUnjoinDomain,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrUnjoinDomain,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrUnjoinDomain,
+ false,
+ },
+ {
+ "wkssvc_NetrRenameMachineInDomain",
+ sizeof(struct wkssvc_NetrRenameMachineInDomain),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrRenameMachineInDomain,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrRenameMachineInDomain,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrRenameMachineInDomain,
+ false,
+ },
+ {
+ "wkssvc_NetrValidateName",
+ sizeof(struct wkssvc_NetrValidateName),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrValidateName,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrValidateName,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrValidateName,
+ false,
+ },
+ {
+ "wkssvc_NetrGetJoinInformation",
+ sizeof(struct wkssvc_NetrGetJoinInformation),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrGetJoinInformation,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrGetJoinInformation,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrGetJoinInformation,
+ false,
+ },
+ {
+ "wkssvc_NetrGetJoinableOus",
+ sizeof(struct wkssvc_NetrGetJoinableOus),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrGetJoinableOus,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrGetJoinableOus,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrGetJoinableOus,
+ false,
+ },
+ {
+ "wkssvc_NetrJoinDomain2",
+ sizeof(struct wkssvc_NetrJoinDomain2),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrJoinDomain2,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrJoinDomain2,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrJoinDomain2,
+ false,
+ },
+ {
+ "wkssvc_NetrUnjoinDomain2",
+ sizeof(struct wkssvc_NetrUnjoinDomain2),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrUnjoinDomain2,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrUnjoinDomain2,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrUnjoinDomain2,
+ false,
+ },
+ {
+ "wkssvc_NetrRenameMachineInDomain2",
+ sizeof(struct wkssvc_NetrRenameMachineInDomain2),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrRenameMachineInDomain2,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrRenameMachineInDomain2,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrRenameMachineInDomain2,
+ false,
+ },
+ {
+ "wkssvc_NetrValidateName2",
+ sizeof(struct wkssvc_NetrValidateName2),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrValidateName2,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrValidateName2,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrValidateName2,
+ false,
+ },
+ {
+ "wkssvc_NetrGetJoinableOus2",
+ sizeof(struct wkssvc_NetrGetJoinableOus2),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrGetJoinableOus2,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrGetJoinableOus2,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrGetJoinableOus2,
+ false,
+ },
+ {
+ "wkssvc_NetrAddAlternateComputerName",
+ sizeof(struct wkssvc_NetrAddAlternateComputerName),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrAddAlternateComputerName,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrAddAlternateComputerName,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrAddAlternateComputerName,
+ false,
+ },
+ {
+ "wkssvc_NetrRemoveAlternateComputerName",
+ sizeof(struct wkssvc_NetrRemoveAlternateComputerName),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrRemoveAlternateComputerName,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrRemoveAlternateComputerName,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrRemoveAlternateComputerName,
+ false,
+ },
+ {
+ "wkssvc_NetrSetPrimaryComputername",
+ sizeof(struct wkssvc_NetrSetPrimaryComputername),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrSetPrimaryComputername,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrSetPrimaryComputername,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrSetPrimaryComputername,
+ false,
+ },
+ {
+ "wkssvc_NetrEnumerateComputerNames",
+ sizeof(struct wkssvc_NetrEnumerateComputerNames),
+ (ndr_push_flags_fn_t) ndr_push_wkssvc_NetrEnumerateComputerNames,
+ (ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrEnumerateComputerNames,
+ (ndr_print_function_t) ndr_print_wkssvc_NetrEnumerateComputerNames,
+ false,
+ },
+ { NULL, 0, NULL, NULL, NULL, false }
+};
+
+static const char * const wkssvc_endpoint_strings[] = {
+ "ncacn_np:[\\pipe\\wkssvc]",
+ "ncacn_ip_tcp:",
+ "ncalrpc:",
+};
+
+static const struct ndr_interface_string_array wkssvc_endpoints = {
+ .count = 3,
+ .names = wkssvc_endpoint_strings
+};
+
+static const char * const wkssvc_authservice_strings[] = {
+ "host",
+};
+
+static const struct ndr_interface_string_array wkssvc_authservices = {
+ .count = 1,
+ .names = wkssvc_authservice_strings
+};
+
+
+const struct ndr_interface_table ndr_table_wkssvc = {
+ .name = "wkssvc",
+ .syntax_id = {
+ {0x6bffd098,0xa112,0x3610,{0x98,0x33},{0x46,0xc3,0xf8,0x7e,0x34,0x5a}},
+ NDR_WKSSVC_VERSION
+ },
+ .helpstring = NDR_WKSSVC_HELPSTRING,
+ .num_calls = 31,
+ .calls = wkssvc_calls,
+ .endpoints = &wkssvc_endpoints,
+ .authservices = &wkssvc_authservices
+};
+
diff --git a/source3/librpc/gen_ndr/ndr_wkssvc.h b/source3/librpc/gen_ndr/ndr_wkssvc.h
new file mode 100644
index 0000000000..0fa4d3f8d4
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_wkssvc.h
@@ -0,0 +1,175 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/wkssvc.h"
+
+#ifndef _HEADER_NDR_wkssvc
+#define _HEADER_NDR_wkssvc
+
+#define NDR_WKSSVC_UUID "6bffd098-a112-3610-9833-46c3f87e345a"
+#define NDR_WKSSVC_VERSION 1.0
+#define NDR_WKSSVC_NAME "wkssvc"
+#define NDR_WKSSVC_HELPSTRING "Workstation Service"
+extern const struct ndr_interface_table ndr_table_wkssvc;
+#define NDR_WKSSVC_NETWKSTAGETINFO (0x00)
+
+#define NDR_WKSSVC_NETWKSTASETINFO (0x01)
+
+#define NDR_WKSSVC_NETWKSTAENUMUSERS (0x02)
+
+#define NDR_WKSSVC_NETRWKSTAUSERGETINFO (0x03)
+
+#define NDR_WKSSVC_NETRWKSTAUSERSETINFO (0x04)
+
+#define NDR_WKSSVC_NETWKSTATRANSPORTENUM (0x05)
+
+#define NDR_WKSSVC_NETRWKSTATRANSPORTADD (0x06)
+
+#define NDR_WKSSVC_NETRWKSTATRANSPORTDEL (0x07)
+
+#define NDR_WKSSVC_NETRUSEADD (0x08)
+
+#define NDR_WKSSVC_NETRUSEGETINFO (0x09)
+
+#define NDR_WKSSVC_NETRUSEDEL (0x0a)
+
+#define NDR_WKSSVC_NETRUSEENUM (0x0b)
+
+#define NDR_WKSSVC_NETRMESSAGEBUFFERSEND (0x0c)
+
+#define NDR_WKSSVC_NETRWORKSTATIONSTATISTICSGET (0x0d)
+
+#define NDR_WKSSVC_NETRLOGONDOMAINNAMEADD (0x0e)
+
+#define NDR_WKSSVC_NETRLOGONDOMAINNAMEDEL (0x0f)
+
+#define NDR_WKSSVC_NETRJOINDOMAIN (0x10)
+
+#define NDR_WKSSVC_NETRUNJOINDOMAIN (0x11)
+
+#define NDR_WKSSVC_NETRRENAMEMACHINEINDOMAIN (0x12)
+
+#define NDR_WKSSVC_NETRVALIDATENAME (0x13)
+
+#define NDR_WKSSVC_NETRGETJOININFORMATION (0x14)
+
+#define NDR_WKSSVC_NETRGETJOINABLEOUS (0x15)
+
+#define NDR_WKSSVC_NETRJOINDOMAIN2 (0x16)
+
+#define NDR_WKSSVC_NETRUNJOINDOMAIN2 (0x17)
+
+#define NDR_WKSSVC_NETRRENAMEMACHINEINDOMAIN2 (0x18)
+
+#define NDR_WKSSVC_NETRVALIDATENAME2 (0x19)
+
+#define NDR_WKSSVC_NETRGETJOINABLEOUS2 (0x1a)
+
+#define NDR_WKSSVC_NETRADDALTERNATECOMPUTERNAME (0x1b)
+
+#define NDR_WKSSVC_NETRREMOVEALTERNATECOMPUTERNAME (0x1c)
+
+#define NDR_WKSSVC_NETRSETPRIMARYCOMPUTERNAME (0x1d)
+
+#define NDR_WKSSVC_NETRENUMERATECOMPUTERNAMES (0x1e)
+
+#define NDR_WKSSVC_CALL_COUNT (31)
+void ndr_print_wkssvc_NetWkstaInfo100(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo100 *r);
+void ndr_print_wkssvc_NetWkstaInfo101(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo101 *r);
+void ndr_print_wkssvc_NetWkstaInfo102(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo102 *r);
+void ndr_print_wkssvc_NetWkstaInfo502(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo502 *r);
+void ndr_print_wkssvc_NetWkstaInfo1010(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1010 *r);
+void ndr_print_wkssvc_NetWkstaInfo1011(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1011 *r);
+void ndr_print_wkssvc_NetWkstaInfo1012(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1012 *r);
+void ndr_print_wkssvc_NetWkstaInfo1013(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1013 *r);
+void ndr_print_wkssvc_NetWkstaInfo1018(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1018 *r);
+void ndr_print_wkssvc_NetWkstaInfo1023(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1023 *r);
+void ndr_print_wkssvc_NetWkstaInfo1027(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1027 *r);
+void ndr_print_wkssvc_NetWkstaInfo1028(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1028 *r);
+void ndr_print_wkssvc_NetWkstaInfo1032(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1032 *r);
+void ndr_print_wkssvc_NetWkstaInfo1033(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1033 *r);
+void ndr_print_wkssvc_NetWkstaInfo1041(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1041 *r);
+void ndr_print_wkssvc_NetWkstaInfo1042(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1042 *r);
+void ndr_print_wkssvc_NetWkstaInfo1043(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1043 *r);
+void ndr_print_wkssvc_NetWkstaInfo1044(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1044 *r);
+void ndr_print_wkssvc_NetWkstaInfo1045(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1045 *r);
+void ndr_print_wkssvc_NetWkstaInfo1046(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1046 *r);
+void ndr_print_wkssvc_NetWkstaInfo1047(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1047 *r);
+void ndr_print_wkssvc_NetWkstaInfo1048(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1048 *r);
+void ndr_print_wkssvc_NetWkstaInfo1049(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1049 *r);
+void ndr_print_wkssvc_NetWkstaInfo1050(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1050 *r);
+void ndr_print_wkssvc_NetWkstaInfo1051(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1051 *r);
+void ndr_print_wkssvc_NetWkstaInfo1052(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1052 *r);
+void ndr_print_wkssvc_NetWkstaInfo1053(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1053 *r);
+void ndr_print_wkssvc_NetWkstaInfo1054(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1054 *r);
+void ndr_print_wkssvc_NetWkstaInfo1055(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1055 *r);
+void ndr_print_wkssvc_NetWkstaInfo1056(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1056 *r);
+void ndr_print_wkssvc_NetWkstaInfo1057(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1057 *r);
+void ndr_print_wkssvc_NetWkstaInfo1058(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1058 *r);
+void ndr_print_wkssvc_NetWkstaInfo1059(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1059 *r);
+void ndr_print_wkssvc_NetWkstaInfo1060(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1060 *r);
+void ndr_print_wkssvc_NetWkstaInfo1061(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1061 *r);
+void ndr_print_wkssvc_NetWkstaInfo1062(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaInfo1062 *r);
+void ndr_print_wkssvc_NetWkstaInfo(struct ndr_print *ndr, const char *name, const union wkssvc_NetWkstaInfo *r);
+void ndr_print_wkssvc_NetrWkstaUserInfo0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrWkstaUserInfo0 *r);
+void ndr_print_wkssvc_NetWkstaEnumUsersCtr0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaEnumUsersCtr0 *r);
+void ndr_print_wkssvc_NetrWkstaUserInfo1(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrWkstaUserInfo1 *r);
+void ndr_print_wkssvc_NetWkstaEnumUsersCtr1(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaEnumUsersCtr1 *r);
+void ndr_print_wkssvc_NetWkstaEnumUsersCtr(struct ndr_print *ndr, const char *name, const union wkssvc_NetWkstaEnumUsersCtr *r);
+void ndr_print_wkssvc_NetWkstaEnumUsersInfo(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaEnumUsersInfo *r);
+void ndr_print_wkssvc_NetrWkstaUserInfo1101(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrWkstaUserInfo1101 *r);
+void ndr_print_wkssvc_NetrWkstaUserInfo(struct ndr_print *ndr, const char *name, const union wkssvc_NetrWkstaUserInfo *r);
+void ndr_print_wkssvc_NetWkstaTransportInfo0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaTransportInfo0 *r);
+void ndr_print_wkssvc_NetWkstaTransportCtr0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaTransportCtr0 *r);
+void ndr_print_wkssvc_NetWkstaTransportCtr(struct ndr_print *ndr, const char *name, const union wkssvc_NetWkstaTransportCtr *r);
+void ndr_print_wkssvc_NetWkstaTransportInfo(struct ndr_print *ndr, const char *name, const struct wkssvc_NetWkstaTransportInfo *r);
+void ndr_print_wkssvc_NetrUseInfo3(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseInfo3 *r);
+void ndr_print_wkssvc_NetrUseInfo2(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseInfo2 *r);
+void ndr_print_wkssvc_NetrUseInfo1(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseInfo1 *r);
+void ndr_print_wkssvc_NetrUseInfo0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseInfo0 *r);
+void ndr_print_wkssvc_NetrUseGetInfoCtr(struct ndr_print *ndr, const char *name, const union wkssvc_NetrUseGetInfoCtr *r);
+void ndr_print_wkssvc_NetrUseEnumCtr2(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseEnumCtr2 *r);
+void ndr_print_wkssvc_NetrUseEnumCtr1(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseEnumCtr1 *r);
+void ndr_print_wkssvc_NetrUseEnumCtr0(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseEnumCtr0 *r);
+void ndr_print_wkssvc_NetrUseEnumCtr(struct ndr_print *ndr, const char *name, const union wkssvc_NetrUseEnumCtr *r);
+void ndr_print_wkssvc_NetrUseEnumInfo(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrUseEnumInfo *r);
+void ndr_print_wkssvc_NetrWorkstationStatistics(struct ndr_print *ndr, const char *name, const struct wkssvc_NetrWorkstationStatistics *r);
+void ndr_print_wkssvc_renameflags(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_wkssvc_NetValidateNameType(struct ndr_print *ndr, const char *name, enum wkssvc_NetValidateNameType r);
+void ndr_print_wkssvc_NetJoinStatus(struct ndr_print *ndr, const char *name, enum wkssvc_NetJoinStatus r);
+void ndr_print_wkssvc_PasswordBuffer(struct ndr_print *ndr, const char *name, const struct wkssvc_PasswordBuffer *r);
+void ndr_print_wkssvc_joinflags(struct ndr_print *ndr, const char *name, uint32_t r);
+void ndr_print_wkssvc_ComputerNameType(struct ndr_print *ndr, const char *name, enum wkssvc_ComputerNameType r);
+void ndr_print_wkssvc_ComputerNamesCtr(struct ndr_print *ndr, const char *name, const struct wkssvc_ComputerNamesCtr *r);
+void ndr_print_wkssvc_NetWkstaGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetWkstaGetInfo *r);
+void ndr_print_wkssvc_NetWkstaSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetWkstaSetInfo *r);
+void ndr_print_wkssvc_NetWkstaEnumUsers(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetWkstaEnumUsers *r);
+void ndr_print_wkssvc_NetrWkstaUserGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrWkstaUserGetInfo *r);
+void ndr_print_wkssvc_NetrWkstaUserSetInfo(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrWkstaUserSetInfo *r);
+void ndr_print_wkssvc_NetWkstaTransportEnum(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetWkstaTransportEnum *r);
+void ndr_print_wkssvc_NetrWkstaTransportAdd(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrWkstaTransportAdd *r);
+void ndr_print_wkssvc_NetrWkstaTransportDel(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrWkstaTransportDel *r);
+void ndr_print_wkssvc_NetrUseAdd(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUseAdd *r);
+void ndr_print_wkssvc_NetrUseGetInfo(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUseGetInfo *r);
+void ndr_print_wkssvc_NetrUseDel(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUseDel *r);
+void ndr_print_wkssvc_NetrUseEnum(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUseEnum *r);
+void ndr_print_wkssvc_NetrMessageBufferSend(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrMessageBufferSend *r);
+void ndr_print_wkssvc_NetrWorkstationStatisticsGet(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrWorkstationStatisticsGet *r);
+void ndr_print_wkssvc_NetrLogonDomainNameAdd(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrLogonDomainNameAdd *r);
+void ndr_print_wkssvc_NetrLogonDomainNameDel(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrLogonDomainNameDel *r);
+void ndr_print_wkssvc_NetrJoinDomain(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrJoinDomain *r);
+void ndr_print_wkssvc_NetrUnjoinDomain(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUnjoinDomain *r);
+void ndr_print_wkssvc_NetrRenameMachineInDomain(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrRenameMachineInDomain *r);
+void ndr_print_wkssvc_NetrValidateName(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrValidateName *r);
+void ndr_print_wkssvc_NetrGetJoinInformation(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrGetJoinInformation *r);
+void ndr_print_wkssvc_NetrGetJoinableOus(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrGetJoinableOus *r);
+void ndr_print_wkssvc_NetrJoinDomain2(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrJoinDomain2 *r);
+void ndr_print_wkssvc_NetrUnjoinDomain2(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrUnjoinDomain2 *r);
+void ndr_print_wkssvc_NetrRenameMachineInDomain2(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrRenameMachineInDomain2 *r);
+void ndr_print_wkssvc_NetrValidateName2(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrValidateName2 *r);
+void ndr_print_wkssvc_NetrGetJoinableOus2(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrGetJoinableOus2 *r);
+void ndr_print_wkssvc_NetrAddAlternateComputerName(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrAddAlternateComputerName *r);
+void ndr_print_wkssvc_NetrRemoveAlternateComputerName(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrRemoveAlternateComputerName *r);
+void ndr_print_wkssvc_NetrSetPrimaryComputername(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrSetPrimaryComputername *r);
+void ndr_print_wkssvc_NetrEnumerateComputerNames(struct ndr_print *ndr, const char *name, int flags, const struct wkssvc_NetrEnumerateComputerNames *r);
+#endif /* _HEADER_NDR_wkssvc */
diff --git a/source3/librpc/gen_ndr/ndr_xattr.c b/source3/librpc/gen_ndr/ndr_xattr.c
new file mode 100644
index 0000000000..92369835cf
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_xattr.c
@@ -0,0 +1,327 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_xattr.h"
+
+_PUBLIC_ enum ndr_err_code ndr_push_tdb_xattr(struct ndr_push *ndr, int ndr_flags, const struct tdb_xattr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->name));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->value));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_tdb_xattr(struct ndr_pull *ndr, int ndr_flags, struct tdb_xattr *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ uint32_t _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->name));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->value));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_tdb_xattr(struct ndr_print *ndr, const char *name, const struct tdb_xattr *r)
+{
+ ndr_print_struct(ndr, name, "tdb_xattr");
+ ndr->depth++;
+ ndr_print_string(ndr, "name", r->name);
+ ndr_print_DATA_BLOB(ndr, "value", r->value);
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_tdb_xattrs(struct ndr_push *ndr, int ndr_flags, const struct tdb_xattrs *r)
+{
+ uint32_t cntr_xattrs_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_xattrs));
+ for (cntr_xattrs_0 = 0; cntr_xattrs_0 < r->num_xattrs; cntr_xattrs_0++) {
+ NDR_CHECK(ndr_push_tdb_xattr(ndr, NDR_SCALARS, &r->xattrs[cntr_xattrs_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_tdb_xattrs(struct ndr_pull *ndr, int ndr_flags, struct tdb_xattrs *r)
+{
+ uint32_t cntr_xattrs_0;
+ TALLOC_CTX *_mem_save_xattrs_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_xattrs));
+ NDR_PULL_ALLOC_N(ndr, r->xattrs, r->num_xattrs);
+ _mem_save_xattrs_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->xattrs, 0);
+ for (cntr_xattrs_0 = 0; cntr_xattrs_0 < r->num_xattrs; cntr_xattrs_0++) {
+ NDR_CHECK(ndr_pull_tdb_xattr(ndr, NDR_SCALARS, &r->xattrs[cntr_xattrs_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_xattrs_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_tdb_xattrs(struct ndr_print *ndr, const char *name, const struct tdb_xattrs *r)
+{
+ uint32_t cntr_xattrs_0;
+ ndr_print_struct(ndr, name, "tdb_xattrs");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_xattrs", r->num_xattrs);
+ ndr->print(ndr, "%s: ARRAY(%d)", "xattrs", (int)r->num_xattrs);
+ ndr->depth++;
+ for (cntr_xattrs_0=0;cntr_xattrs_0<r->num_xattrs;cntr_xattrs_0++) {
+ char *idx_0=NULL;
+ if (asprintf(&idx_0, "[%d]", cntr_xattrs_0) != -1) {
+ ndr_print_tdb_xattr(ndr, "xattrs", &r->xattrs[cntr_xattrs_0]);
+ free(idx_0);
+ }
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_security_descriptor_timestamp(struct ndr_push *ndr, int ndr_flags, const struct security_descriptor_timestamp *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sd));
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->last_changed));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sd) {
+ NDR_CHECK(ndr_push_security_descriptor(ndr, NDR_SCALARS|NDR_BUFFERS, r->sd));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_security_descriptor_timestamp(struct ndr_pull *ndr, int ndr_flags, struct security_descriptor_timestamp *r)
+{
+ uint32_t _ptr_sd;
+ TALLOC_CTX *_mem_save_sd_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sd));
+ if (_ptr_sd) {
+ NDR_PULL_ALLOC(ndr, r->sd);
+ } else {
+ r->sd = NULL;
+ }
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->last_changed));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sd) {
+ _mem_save_sd_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sd, 0);
+ NDR_CHECK(ndr_pull_security_descriptor(ndr, NDR_SCALARS|NDR_BUFFERS, r->sd));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sd_0, 0);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_security_descriptor_timestamp(struct ndr_print *ndr, const char *name, const struct security_descriptor_timestamp *r)
+{
+ ndr_print_struct(ndr, name, "security_descriptor_timestamp");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "sd", r->sd);
+ ndr->depth++;
+ if (r->sd) {
+ ndr_print_security_descriptor(ndr, "sd", r->sd);
+ }
+ ndr->depth--;
+ ndr_print_NTTIME(ndr, "last_changed", r->last_changed);
+ ndr->depth--;
+}
+
+static enum ndr_err_code ndr_push_xattr_NTACL_Info(struct ndr_push *ndr, int ndr_flags, const union xattr_NTACL_Info *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, level));
+ switch (level) {
+ case 1: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sd));
+ break; }
+
+ case 2: {
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->sd_ts));
+ break; }
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ int level = ndr_push_get_switch_value(ndr, r);
+ switch (level) {
+ case 1:
+ if (r->sd) {
+ NDR_CHECK(ndr_push_security_descriptor(ndr, NDR_SCALARS|NDR_BUFFERS, r->sd));
+ }
+ break;
+
+ case 2:
+ if (r->sd_ts) {
+ NDR_CHECK(ndr_push_security_descriptor_timestamp(ndr, NDR_SCALARS|NDR_BUFFERS, r->sd_ts));
+ }
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_xattr_NTACL_Info(struct ndr_pull *ndr, int ndr_flags, union xattr_NTACL_Info *r)
+{
+ int level;
+ uint16_t _level;
+ TALLOC_CTX *_mem_save_sd_0;
+ TALLOC_CTX *_mem_save_sd_ts_0;
+ level = ndr_pull_get_switch_value(ndr, r);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &_level));
+ if (_level != level) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u for r", _level);
+ }
+ switch (level) {
+ case 1: {
+ uint32_t _ptr_sd;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sd));
+ if (_ptr_sd) {
+ NDR_PULL_ALLOC(ndr, r->sd);
+ } else {
+ r->sd = NULL;
+ }
+ break; }
+
+ case 2: {
+ uint32_t _ptr_sd_ts;
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sd_ts));
+ if (_ptr_sd_ts) {
+ NDR_PULL_ALLOC(ndr, r->sd_ts);
+ } else {
+ r->sd_ts = NULL;
+ }
+ break; }
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ switch (level) {
+ case 1:
+ if (r->sd) {
+ _mem_save_sd_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sd, 0);
+ NDR_CHECK(ndr_pull_security_descriptor(ndr, NDR_SCALARS|NDR_BUFFERS, r->sd));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sd_0, 0);
+ }
+ break;
+
+ case 2:
+ if (r->sd_ts) {
+ _mem_save_sd_ts_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->sd_ts, 0);
+ NDR_CHECK(ndr_pull_security_descriptor_timestamp(ndr, NDR_SCALARS|NDR_BUFFERS, r->sd_ts));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sd_ts_0, 0);
+ }
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, "Bad switch value %u", level);
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_xattr_NTACL_Info(struct ndr_print *ndr, const char *name, const union xattr_NTACL_Info *r)
+{
+ int level;
+ level = ndr_print_get_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "xattr_NTACL_Info");
+ switch (level) {
+ case 1:
+ ndr_print_ptr(ndr, "sd", r->sd);
+ ndr->depth++;
+ if (r->sd) {
+ ndr_print_security_descriptor(ndr, "sd", r->sd);
+ }
+ ndr->depth--;
+ break;
+
+ case 2:
+ ndr_print_ptr(ndr, "sd_ts", r->sd_ts);
+ ndr->depth++;
+ if (r->sd_ts) {
+ ndr_print_security_descriptor_timestamp(ndr, "sd_ts", r->sd_ts);
+ }
+ ndr->depth--;
+ break;
+
+ default:
+ ndr_print_bad_level(ndr, name, level);
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_xattr_NTACL(struct ndr_push *ndr, int ndr_flags, const struct xattr_NTACL *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->version));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->info, r->version));
+ NDR_CHECK(ndr_push_xattr_NTACL_Info(ndr, NDR_SCALARS, &r->info));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_xattr_NTACL_Info(ndr, NDR_BUFFERS, &r->info));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_xattr_NTACL(struct ndr_pull *ndr, int ndr_flags, struct xattr_NTACL *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->version));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->info, r->version));
+ NDR_CHECK(ndr_pull_xattr_NTACL_Info(ndr, NDR_SCALARS, &r->info));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_xattr_NTACL_Info(ndr, NDR_BUFFERS, &r->info));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_xattr_NTACL(struct ndr_print *ndr, const char *name, const struct xattr_NTACL *r)
+{
+ ndr_print_struct(ndr, name, "xattr_NTACL");
+ ndr->depth++;
+ ndr_print_uint16(ndr, "version", r->version);
+ ndr_print_set_switch_value(ndr, &r->info, r->version);
+ ndr_print_xattr_NTACL_Info(ndr, "info", &r->info);
+ ndr->depth--;
+}
+
diff --git a/source3/librpc/gen_ndr/ndr_xattr.h b/source3/librpc/gen_ndr/ndr_xattr.h
new file mode 100644
index 0000000000..21c5ae03b5
--- /dev/null
+++ b/source3/librpc/gen_ndr/ndr_xattr.h
@@ -0,0 +1,23 @@
+/* header auto-generated by pidl */
+
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/xattr.h"
+
+#ifndef _HEADER_NDR_xattr
+#define _HEADER_NDR_xattr
+
+#define NDR_XATTR_CALL_COUNT (0)
+enum ndr_err_code ndr_push_tdb_xattr(struct ndr_push *ndr, int ndr_flags, const struct tdb_xattr *r);
+enum ndr_err_code ndr_pull_tdb_xattr(struct ndr_pull *ndr, int ndr_flags, struct tdb_xattr *r);
+void ndr_print_tdb_xattr(struct ndr_print *ndr, const char *name, const struct tdb_xattr *r);
+enum ndr_err_code ndr_push_tdb_xattrs(struct ndr_push *ndr, int ndr_flags, const struct tdb_xattrs *r);
+enum ndr_err_code ndr_pull_tdb_xattrs(struct ndr_pull *ndr, int ndr_flags, struct tdb_xattrs *r);
+void ndr_print_tdb_xattrs(struct ndr_print *ndr, const char *name, const struct tdb_xattrs *r);
+enum ndr_err_code ndr_push_security_descriptor_timestamp(struct ndr_push *ndr, int ndr_flags, const struct security_descriptor_timestamp *r);
+enum ndr_err_code ndr_pull_security_descriptor_timestamp(struct ndr_pull *ndr, int ndr_flags, struct security_descriptor_timestamp *r);
+void ndr_print_security_descriptor_timestamp(struct ndr_print *ndr, const char *name, const struct security_descriptor_timestamp *r);
+void ndr_print_xattr_NTACL_Info(struct ndr_print *ndr, const char *name, const union xattr_NTACL_Info *r);
+enum ndr_err_code ndr_push_xattr_NTACL(struct ndr_push *ndr, int ndr_flags, const struct xattr_NTACL *r);
+enum ndr_err_code ndr_pull_xattr_NTACL(struct ndr_pull *ndr, int ndr_flags, struct xattr_NTACL *r);
+void ndr_print_xattr_NTACL(struct ndr_print *ndr, const char *name, const struct xattr_NTACL *r);
+#endif /* _HEADER_NDR_xattr */
diff --git a/source3/librpc/gen_ndr/netlogon.h b/source3/librpc/gen_ndr/netlogon.h
new file mode 100644
index 0000000000..1cea1f0f42
--- /dev/null
+++ b/source3/librpc/gen_ndr/netlogon.h
@@ -0,0 +1,1610 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#include "librpc/gen_ndr/lsa.h"
+#include "librpc/gen_ndr/samr.h"
+#include "librpc/gen_ndr/security.h"
+#include "librpc/gen_ndr/nbt.h"
+#ifndef _HEADER_netlogon
+#define _HEADER_netlogon
+
+#define DSGETDC_VALID_FLAGS ( (DS_FORCE_REDISCOVERY|DS_DIRECTORY_SERVICE_REQUIRED|DS_DIRECTORY_SERVICE_PREFERRED|DS_GC_SERVER_REQUIRED|DS_PDC_REQUIRED|DS_BACKGROUND_ONLY|DS_IP_REQUIRED|DS_KDC_REQUIRED|DS_TIMESERV_REQUIRED|DS_WRITABLE_REQUIRED|DS_GOOD_TIMESERV_PREFERRED|DS_AVOID_SELF|DS_ONLY_LDAP_NEEDED|DS_IS_FLAT_NAME|DS_IS_DNS_NAME|DS_RETURN_FLAT_NAME|DS_RETURN_DNS_NAME) )
+#define DS_GFTI_UPDATE_TDO ( 0x1 )
+struct netr_UasInfo {
+ const char *account_name;/* [unique,charset(UTF16)] */
+ uint32_t priv;
+ uint32_t auth_flags;
+ uint32_t logon_count;
+ uint32_t bad_pw_count;
+ time_t last_logon;
+ time_t last_logoff;
+ time_t logoff_time;
+ time_t kickoff_time;
+ uint32_t password_age;
+ time_t pw_can_change;
+ time_t pw_must_change;
+ const char *computer;/* [unique,charset(UTF16)] */
+ const char *domain;/* [unique,charset(UTF16)] */
+ const char *script_path;/* [unique,charset(UTF16)] */
+ uint32_t unknown;
+};
+
+struct netr_UasLogoffInfo {
+ uint32_t duration;
+ uint16_t logon_count;
+};
+
+struct netr_AcctLockStr {
+ int64_t lockout_duration;
+ uint64_t reset_count;
+ uint32_t bad_attempt_lockout;
+ uint32_t dummy;
+}/* [public] */;
+
+/* bitmap netr_LogonParameterControl */
+#define MSV1_0_CLEARTEXT_PASSWORD_ALLOWED ( 0x00000002 )
+#define MSV1_0_UPDATE_LOGON_STATISTICS ( 0x00000004 )
+#define MSV1_0_RETURN_USER_PARAMETERS ( 0x00000008 )
+#define MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT ( 0x00000020 )
+#define MSV1_0_RETURN_PROFILE_PATH ( 0x00000200 )
+#define MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT ( 0x00000800 )
+
+struct netr_IdentityInfo {
+ struct lsa_String domain_name;
+ uint32_t parameter_control;
+ uint32_t logon_id_low;
+ uint32_t logon_id_high;
+ struct lsa_String account_name;
+ struct lsa_String workstation;
+};
+
+struct netr_PasswordInfo {
+ struct netr_IdentityInfo identity_info;
+ struct samr_Password lmpassword;
+ struct samr_Password ntpassword;
+};
+
+struct netr_ChallengeResponse {
+ uint16_t length;
+ uint16_t size;/* [value(length)] */
+ uint8_t *data;/* [unique,length_is(length),size_is(length)] */
+}/* [flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+struct netr_NetworkInfo {
+ struct netr_IdentityInfo identity_info;
+ uint8_t challenge[8];
+ struct netr_ChallengeResponse nt;
+ struct netr_ChallengeResponse lm;
+}/* [flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+union netr_LogonInfo {
+ struct netr_PasswordInfo *password;/* [unique,case] */
+ struct netr_NetworkInfo *network;/* [unique,case(2)] */
+}/* [public,switch_type(uint16)] */;
+
+struct netr_UserSessionKey {
+ uint8_t key[16];
+}/* [public,flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+struct netr_LMSessionKey {
+ uint8_t key[8];
+}/* [public,flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+/* bitmap netr_UserFlags */
+#define NETLOGON_GUEST ( 0x00000001 )
+#define NETLOGON_NOENCRYPTION ( 0x00000002 )
+#define NETLOGON_CACHED_ACCOUNT ( 0x00000004 )
+#define NETLOGON_USED_LM_PASSWORD ( 0x00000008 )
+#define NETLOGON_EXTRA_SIDS ( 0x00000020 )
+#define NETLOGON_SUBAUTH_SESSION_KEY ( 0x00000040 )
+#define NETLOGON_SERVER_TRUST_ACCOUNT ( 0x00000080 )
+#define NETLOGON_NTLMV2_ENABLED ( 0x00000100 )
+#define NETLOGON_RESOURCE_GROUPS ( 0x00000200 )
+#define NETLOGON_PROFILE_PATH_RETURNED ( 0x00000400 )
+#define NETLOGON_GRACE_LOGON ( 0x01000000 )
+
+struct netr_SamBaseInfo {
+ NTTIME last_logon;
+ NTTIME last_logoff;
+ NTTIME acct_expiry;
+ NTTIME last_password_change;
+ NTTIME allow_password_change;
+ NTTIME force_password_change;
+ struct lsa_String account_name;
+ struct lsa_String full_name;
+ struct lsa_String logon_script;
+ struct lsa_String profile_path;
+ struct lsa_String home_directory;
+ struct lsa_String home_drive;
+ uint16_t logon_count;
+ uint16_t bad_password_count;
+ uint32_t rid;
+ uint32_t primary_gid;
+ struct samr_RidWithAttributeArray groups;
+ uint32_t user_flags;
+ struct netr_UserSessionKey key;
+ struct lsa_StringLarge logon_server;
+ struct lsa_StringLarge domain;
+ struct dom_sid2 *domain_sid;/* [unique] */
+ struct netr_LMSessionKey LMSessKey;
+ uint32_t acct_flags;
+ uint32_t unknown[7];
+};
+
+struct netr_SamInfo2 {
+ struct netr_SamBaseInfo base;
+};
+
+struct netr_SidAttr {
+ struct dom_sid2 *sid;/* [unique] */
+ uint32_t attributes;
+};
+
+struct netr_SamInfo3 {
+ struct netr_SamBaseInfo base;
+ uint32_t sidcount;
+ struct netr_SidAttr *sids;/* [unique,size_is(sidcount)] */
+}/* [public] */;
+
+struct netr_SamInfo6 {
+ struct netr_SamBaseInfo base;
+ uint32_t sidcount;
+ struct netr_SidAttr *sids;/* [unique,size_is(sidcount)] */
+ struct lsa_String forest;
+ struct lsa_String principle;
+ uint32_t unknown4[20];
+};
+
+struct netr_PacInfo {
+ uint32_t pac_size;
+ uint8_t *pac;/* [unique,size_is(pac_size)] */
+ struct lsa_String logon_domain;
+ struct lsa_String logon_server;
+ struct lsa_String principal_name;
+ uint32_t auth_size;
+ uint8_t *auth;/* [unique,size_is(auth_size)] */
+ struct netr_UserSessionKey user_session_key;
+ uint32_t expansionroom[10];
+ struct lsa_String unknown1;
+ struct lsa_String unknown2;
+ struct lsa_String unknown3;
+ struct lsa_String unknown4;
+};
+
+union netr_Validation {
+ struct netr_SamInfo2 *sam2;/* [unique,case(2)] */
+ struct netr_SamInfo3 *sam3;/* [unique,case(3)] */
+ struct netr_PacInfo *pac;/* [unique,case(4)] */
+ struct netr_SamInfo6 *sam6;/* [unique,case(6)] */
+}/* [public,switch_type(uint16)] */;
+
+struct netr_Credential {
+ uint8_t data[8];
+}/* [public,flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+struct netr_Authenticator {
+ struct netr_Credential cred;
+ time_t timestamp;
+}/* [public] */;
+
+enum netr_LogonLevel
+#ifndef USE_UINT_ENUMS
+ {
+ INTERACTIVE_LOGON_TYPE=1,
+ NET_LOGON_TYPE=2
+}
+#else
+ { __donnot_use_enum_netr_LogonLevel=0x7FFFFFFF}
+#define INTERACTIVE_LOGON_TYPE ( 1 )
+#define NET_LOGON_TYPE ( 2 )
+#endif
+;
+
+enum netr_SchannelType;
+
+enum netr_SamDatabaseID;
+
+struct netr_DELTA_DELETE_USER {
+ const char *account_name;/* [unique,charset(UTF16)] */
+ struct lsa_String unknown1;
+ struct lsa_String unknown2;
+ struct lsa_String unknown3;
+ struct lsa_String unknown4;
+ uint32_t unknown5;
+ uint32_t unknown6;
+ uint32_t unknown7;
+ uint32_t unknown8;
+};
+
+struct netr_USER_KEY16 {
+ uint16_t length;
+ uint16_t size;/* [value(length)] */
+ uint32_t flags;
+ struct samr_Password pwd;
+};
+
+struct netr_PasswordHistory {
+ uint16_t nt_length;
+ uint16_t nt_size;/* [value(nt_length)] */
+ uint32_t nt_flags;
+ uint16_t lm_length;
+ uint16_t lm_size;/* [value(lm_length)] */
+ uint32_t lm_flags;
+ uint8_t *nt_history;
+ uint8_t *lm_history;
+};
+
+struct netr_USER_KEYS2 {
+ struct netr_USER_KEY16 lmpassword;
+ struct netr_USER_KEY16 ntpassword;
+ struct netr_PasswordHistory history;
+};
+
+struct netr_USER_KEY_UNION {
+ struct netr_USER_KEYS2 keys2;
+};
+
+struct netr_USER_KEYS {
+ uint32_t version;
+ struct netr_USER_KEY_UNION keys;
+}/* [public] */;
+
+struct netr_USER_PRIVATE_INFO {
+ uint8_t SensitiveDataFlag;
+ uint32_t DataLength;
+ uint8_t *SensitiveData;/* [unique,flag(LIBNDR_PRINT_ARRAY_HEX),size_is(DataLength)] */
+};
+
+struct netr_DELTA_USER {
+ struct lsa_String account_name;
+ struct lsa_String full_name;
+ uint32_t rid;
+ uint32_t primary_gid;
+ struct lsa_String home_directory;
+ struct lsa_String home_drive;
+ struct lsa_String logon_script;
+ struct lsa_String description;
+ struct lsa_String workstations;
+ NTTIME last_logon;
+ NTTIME last_logoff;
+ struct samr_LogonHours logon_hours;
+ uint16_t bad_password_count;
+ uint16_t logon_count;
+ NTTIME last_password_change;
+ NTTIME acct_expiry;
+ uint32_t acct_flags;
+ struct samr_Password lmpassword;
+ struct samr_Password ntpassword;
+ uint8_t nt_password_present;
+ uint8_t lm_password_present;
+ uint8_t password_expired;
+ struct lsa_String comment;
+ struct lsa_String parameters;
+ uint16_t country_code;
+ uint16_t code_page;
+ struct netr_USER_PRIVATE_INFO user_private_info;
+ uint32_t SecurityInformation;
+ struct sec_desc_buf sdbuf;
+ struct lsa_String profile_path;
+ struct lsa_String unknown2;
+ struct lsa_String unknown3;
+ struct lsa_String unknown4;
+ uint32_t unknown5;
+ uint32_t unknown6;
+ uint32_t unknown7;
+ uint32_t unknown8;
+};
+
+struct netr_DELTA_DOMAIN {
+ struct lsa_String domain_name;
+ struct lsa_String comment;
+ int64_t force_logoff_time;
+ uint16_t min_password_length;
+ uint16_t password_history_length;
+ int64_t max_password_age;
+ int64_t min_password_age;
+ uint64_t sequence_num;
+ NTTIME domain_create_time;
+ uint32_t SecurityInformation;
+ struct sec_desc_buf sdbuf;
+ struct lsa_BinaryString account_lockout;
+ struct lsa_String unknown2;
+ struct lsa_String unknown3;
+ struct lsa_String unknown4;
+ uint32_t logon_to_chgpass;
+ uint32_t unknown6;
+ uint32_t unknown7;
+ uint32_t unknown8;
+};
+
+struct netr_DELTA_GROUP {
+ struct lsa_String group_name;
+ uint32_t rid;
+ uint32_t attributes;
+ struct lsa_String description;
+ uint32_t SecurityInformation;
+ struct sec_desc_buf sdbuf;
+ struct lsa_String unknown1;
+ struct lsa_String unknown2;
+ struct lsa_String unknown3;
+ struct lsa_String unknown4;
+ uint32_t unknown5;
+ uint32_t unknown6;
+ uint32_t unknown7;
+ uint32_t unknown8;
+};
+
+struct netr_DELTA_RENAME {
+ struct lsa_String OldName;
+ struct lsa_String NewName;
+ struct lsa_String unknown1;
+ struct lsa_String unknown2;
+ struct lsa_String unknown3;
+ struct lsa_String unknown4;
+ uint32_t unknown5;
+ uint32_t unknown6;
+ uint32_t unknown7;
+ uint32_t unknown8;
+};
+
+struct netr_DELTA_GROUP_MEMBER {
+ uint32_t *rids;/* [unique,size_is(num_rids)] */
+ uint32_t *attribs;/* [unique,size_is(num_rids)] */
+ uint32_t num_rids;
+ uint32_t unknown1;
+ uint32_t unknown2;
+ uint32_t unknown3;
+ uint32_t unknown4;
+};
+
+struct netr_DELTA_ALIAS {
+ struct lsa_String alias_name;
+ uint32_t rid;
+ uint32_t SecurityInformation;
+ struct sec_desc_buf sdbuf;
+ struct lsa_String description;
+ struct lsa_String unknown2;
+ struct lsa_String unknown3;
+ struct lsa_String unknown4;
+ uint32_t unknown5;
+ uint32_t unknown6;
+ uint32_t unknown7;
+ uint32_t unknown8;
+};
+
+struct netr_DELTA_ALIAS_MEMBER {
+ struct lsa_SidArray sids;
+ uint32_t unknown1;
+ uint32_t unknown2;
+ uint32_t unknown3;
+ uint32_t unknown4;
+};
+
+struct netr_QUOTA_LIMITS {
+ uint32_t pagedpoollimit;
+ uint32_t nonpagedpoollimit;
+ uint32_t minimumworkingsetsize;
+ uint32_t maximumworkingsetsize;
+ uint32_t pagefilelimit;
+ NTTIME timelimit;
+};
+
+struct netr_DELTA_POLICY {
+ uint32_t maxlogsize;
+ NTTIME auditretentionperiod;
+ uint8_t auditingmode;
+ uint32_t maxauditeventcount;
+ uint32_t *eventauditoptions;/* [unique,size_is(maxauditeventcount+1)] */
+ struct lsa_String primary_domain_name;
+ struct dom_sid2 *sid;/* [unique] */
+ struct netr_QUOTA_LIMITS quota_limits;
+ uint64_t sequence_num;
+ NTTIME db_create_time;
+ uint32_t SecurityInformation;
+ struct sec_desc_buf sdbuf;
+ struct lsa_String unknown1;
+ struct lsa_String unknown2;
+ struct lsa_String unknown3;
+ struct lsa_String unknown4;
+ uint32_t unknown5;
+ uint32_t unknown6;
+ uint32_t unknown7;
+ uint32_t unknown8;
+};
+
+struct netr_DELTA_TRUSTED_DOMAIN {
+ struct lsa_String domain_name;
+ uint32_t num_controllers;
+ struct lsa_String *controller_names;/* [unique,size_is(num_controllers)] */
+ uint32_t SecurityInformation;
+ struct sec_desc_buf sdbuf;
+ struct lsa_String unknown1;
+ struct lsa_String unknown2;
+ struct lsa_String unknown3;
+ struct lsa_String unknown4;
+ uint32_t posix_offset;
+ uint32_t unknown6;
+ uint32_t unknown7;
+ uint32_t unknown8;
+};
+
+struct netr_DELTA_DELETE_TRUST {
+ uint16_t unknown;
+};
+
+struct netr_DELTA_ACCOUNT {
+ uint32_t privilege_entries;
+ uint32_t privilege_control;
+ uint32_t *privilege_attrib;/* [unique,size_is(privilege_entries)] */
+ struct lsa_String *privilege_name;/* [unique,size_is(privilege_entries)] */
+ struct netr_QUOTA_LIMITS quotalimits;
+ uint32_t system_flags;
+ uint32_t SecurityInformation;
+ struct sec_desc_buf sdbuf;
+ struct lsa_String unknown1;
+ struct lsa_String unknown2;
+ struct lsa_String unknown3;
+ struct lsa_String unknown4;
+ uint32_t unknown5;
+ uint32_t unknown6;
+ uint32_t unknown7;
+ uint32_t unknown8;
+};
+
+struct netr_DELTA_DELETE_ACCOUNT {
+ uint16_t unknown;
+};
+
+struct netr_DELTA_DELETE_SECRET {
+ uint16_t unknown;
+};
+
+struct netr_CIPHER_VALUE {
+ uint32_t len;
+ uint32_t maxlen;
+ uint8_t *cipher_data;/* [unique,length_is(len),size_is(maxlen)] */
+};
+
+struct netr_DELTA_SECRET {
+ struct netr_CIPHER_VALUE current_cipher;
+ NTTIME current_cipher_set_time;
+ struct netr_CIPHER_VALUE old_cipher;
+ NTTIME old_cipher_set_time;
+ uint32_t SecurityInformation;
+ struct sec_desc_buf sdbuf;
+ struct lsa_String unknown1;
+ struct lsa_String unknown2;
+ struct lsa_String unknown3;
+ struct lsa_String unknown4;
+ uint32_t unknown5;
+ uint32_t unknown6;
+ uint32_t unknown7;
+ uint32_t unknown8;
+};
+
+enum netr_DeltaEnum
+#ifndef USE_UINT_ENUMS
+ {
+ NETR_DELTA_DOMAIN=1,
+ NETR_DELTA_GROUP=2,
+ NETR_DELTA_DELETE_GROUP=3,
+ NETR_DELTA_RENAME_GROUP=4,
+ NETR_DELTA_USER=5,
+ NETR_DELTA_DELETE_USER=6,
+ NETR_DELTA_RENAME_USER=7,
+ NETR_DELTA_GROUP_MEMBER=8,
+ NETR_DELTA_ALIAS=9,
+ NETR_DELTA_DELETE_ALIAS=10,
+ NETR_DELTA_RENAME_ALIAS=11,
+ NETR_DELTA_ALIAS_MEMBER=12,
+ NETR_DELTA_POLICY=13,
+ NETR_DELTA_TRUSTED_DOMAIN=14,
+ NETR_DELTA_DELETE_TRUST=15,
+ NETR_DELTA_ACCOUNT=16,
+ NETR_DELTA_DELETE_ACCOUNT=17,
+ NETR_DELTA_SECRET=18,
+ NETR_DELTA_DELETE_SECRET=19,
+ NETR_DELTA_DELETE_GROUP2=20,
+ NETR_DELTA_DELETE_USER2=21,
+ NETR_DELTA_MODIFY_COUNT=22
+}
+#else
+ { __donnot_use_enum_netr_DeltaEnum=0x7FFFFFFF}
+#define NETR_DELTA_DOMAIN ( 1 )
+#define NETR_DELTA_GROUP ( 2 )
+#define NETR_DELTA_DELETE_GROUP ( 3 )
+#define NETR_DELTA_RENAME_GROUP ( 4 )
+#define NETR_DELTA_USER ( 5 )
+#define NETR_DELTA_DELETE_USER ( 6 )
+#define NETR_DELTA_RENAME_USER ( 7 )
+#define NETR_DELTA_GROUP_MEMBER ( 8 )
+#define NETR_DELTA_ALIAS ( 9 )
+#define NETR_DELTA_DELETE_ALIAS ( 10 )
+#define NETR_DELTA_RENAME_ALIAS ( 11 )
+#define NETR_DELTA_ALIAS_MEMBER ( 12 )
+#define NETR_DELTA_POLICY ( 13 )
+#define NETR_DELTA_TRUSTED_DOMAIN ( 14 )
+#define NETR_DELTA_DELETE_TRUST ( 15 )
+#define NETR_DELTA_ACCOUNT ( 16 )
+#define NETR_DELTA_DELETE_ACCOUNT ( 17 )
+#define NETR_DELTA_SECRET ( 18 )
+#define NETR_DELTA_DELETE_SECRET ( 19 )
+#define NETR_DELTA_DELETE_GROUP2 ( 20 )
+#define NETR_DELTA_DELETE_USER2 ( 21 )
+#define NETR_DELTA_MODIFY_COUNT ( 22 )
+#endif
+;
+
+union netr_DELTA_UNION {
+ struct netr_DELTA_DOMAIN *domain;/* [unique,case(NETR_DELTA_DOMAIN)] */
+ struct netr_DELTA_GROUP *group;/* [unique,case(NETR_DELTA_GROUP)] */
+ struct netr_DELTA_RENAME *rename_group;/* [unique,case(NETR_DELTA_RENAME_GROUP)] */
+ struct netr_DELTA_USER *user;/* [unique,case(NETR_DELTA_USER)] */
+ struct netr_DELTA_RENAME *rename_user;/* [unique,case(NETR_DELTA_RENAME_USER)] */
+ struct netr_DELTA_GROUP_MEMBER *group_member;/* [unique,case(NETR_DELTA_GROUP_MEMBER)] */
+ struct netr_DELTA_ALIAS *alias;/* [unique,case(NETR_DELTA_ALIAS)] */
+ struct netr_DELTA_RENAME *rename_alias;/* [unique,case(NETR_DELTA_RENAME_ALIAS)] */
+ struct netr_DELTA_ALIAS_MEMBER *alias_member;/* [unique,case(NETR_DELTA_ALIAS_MEMBER)] */
+ struct netr_DELTA_POLICY *policy;/* [unique,case(NETR_DELTA_POLICY)] */
+ struct netr_DELTA_TRUSTED_DOMAIN *trusted_domain;/* [unique,case(NETR_DELTA_TRUSTED_DOMAIN)] */
+ struct netr_DELTA_DELETE_TRUST delete_trust;/* [case(NETR_DELTA_DELETE_TRUST)] */
+ struct netr_DELTA_ACCOUNT *account;/* [unique,case(NETR_DELTA_ACCOUNT)] */
+ struct netr_DELTA_DELETE_ACCOUNT delete_account;/* [case(NETR_DELTA_DELETE_ACCOUNT)] */
+ struct netr_DELTA_SECRET *secret;/* [unique,case(NETR_DELTA_SECRET)] */
+ struct netr_DELTA_DELETE_SECRET delete_secret;/* [case(NETR_DELTA_DELETE_SECRET)] */
+ struct netr_DELTA_DELETE_USER *delete_group;/* [unique,case(NETR_DELTA_DELETE_GROUP2)] */
+ struct netr_DELTA_DELETE_USER *delete_user;/* [unique,case(NETR_DELTA_DELETE_USER2)] */
+ uint64_t *modified_count;/* [unique,case(NETR_DELTA_MODIFY_COUNT)] */
+}/* [switch_type(netr_DeltaEnum)] */;
+
+union netr_DELTA_ID_UNION {
+ uint32_t rid;/* [case(NETR_DELTA_DOMAIN)] */
+ struct dom_sid2 *sid;/* [unique,case(NETR_DELTA_POLICY)] */
+ const char *name;/* [unique,charset(UTF16),case(NETR_DELTA_SECRET)] */
+}/* [switch_type(netr_DeltaEnum)] */;
+
+struct netr_DELTA_ENUM {
+ enum netr_DeltaEnum delta_type;
+ union netr_DELTA_ID_UNION delta_id_union;/* [switch_is(delta_type)] */
+ union netr_DELTA_UNION delta_union;/* [switch_is(delta_type)] */
+};
+
+struct netr_DELTA_ENUM_ARRAY {
+ uint32_t num_deltas;
+ struct netr_DELTA_ENUM *delta_enum;/* [unique,size_is(num_deltas)] */
+};
+
+struct netr_UAS_INFO_0 {
+ uint8_t computer_name[16];
+ uint32_t timecreated;
+ uint32_t serial_number;
+}/* [flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+struct netr_AccountBuffer {
+ DATA_BLOB blob;/* [flag(LIBNDR_FLAG_REMAINING)] */
+};
+
+/* bitmap netr_InfoFlags */
+#define NETLOGON_CTRL_REPL_NEEDED ( 0x0001 )
+#define NETLOGON_CTRL_REPL_IN_PROGRESS ( 0x0002 )
+#define NETLOGON_CTRL_REPL_FULL_SYNC ( 0x0004 )
+
+struct netr_NETLOGON_INFO_1 {
+ uint32_t flags;
+ uint32_t pdc_connection_status;
+};
+
+struct netr_NETLOGON_INFO_2 {
+ uint32_t flags;
+ uint32_t pdc_connection_status;
+ const char *trusted_dc_name;/* [unique,charset(UTF16)] */
+ uint32_t tc_connection_status;
+};
+
+struct netr_NETLOGON_INFO_3 {
+ uint32_t flags;
+ uint32_t logon_attempts;
+ uint32_t unknown1;
+ uint32_t unknown2;
+ uint32_t unknown3;
+ uint32_t unknown4;
+ uint32_t unknown5;
+};
+
+union netr_CONTROL_QUERY_INFORMATION {
+ struct netr_NETLOGON_INFO_1 *info1;/* [unique,case] */
+ struct netr_NETLOGON_INFO_2 *info2;/* [unique,case(2)] */
+ struct netr_NETLOGON_INFO_3 *info3;/* [unique,case(3)] */
+};
+
+enum netr_LogonControlCode
+#ifndef USE_UINT_ENUMS
+ {
+ NETLOGON_CONTROL_SYNC=2,
+ NETLOGON_CONTROL_REDISCOVER=5,
+ NETLOGON_CONTROL_TC_QUERY=6,
+ NETLOGON_CONTROL_TRANSPORT_NOTIFY=7,
+ NETLOGON_CONTROL_SET_DBFLAG=65534
+}
+#else
+ { __donnot_use_enum_netr_LogonControlCode=0x7FFFFFFF}
+#define NETLOGON_CONTROL_SYNC ( 2 )
+#define NETLOGON_CONTROL_REDISCOVER ( 5 )
+#define NETLOGON_CONTROL_TC_QUERY ( 6 )
+#define NETLOGON_CONTROL_TRANSPORT_NOTIFY ( 7 )
+#define NETLOGON_CONTROL_SET_DBFLAG ( 65534 )
+#endif
+;
+
+union netr_CONTROL_DATA_INFORMATION {
+ const char *domain;/* [unique,charset(UTF16),case(NETLOGON_CONTROL_REDISCOVER)] */
+ uint32_t debug_level;/* [case(NETLOGON_CONTROL_SET_DBFLAG)] */
+};
+
+/* bitmap netr_NegotiateFlags */
+#define NETLOGON_NEG_ACCOUNT_LOCKOUT ( 0x00000001 )
+#define NETLOGON_NEG_PERSISTENT_SAMREPL ( 0x00000002 )
+#define NETLOGON_NEG_ARCFOUR ( 0x00000004 )
+#define NETLOGON_NEG_PROMOTION_COUNT ( 0x00000008 )
+#define NETLOGON_NEG_CHANGELOG_BDC ( 0x00000010 )
+#define NETLOGON_NEG_FULL_SYNC_REPL ( 0x00000020 )
+#define NETLOGON_NEG_MULTIPLE_SIDS ( 0x00000040 )
+#define NETLOGON_NEG_REDO ( 0x00000080 )
+#define NETLOGON_NEG_PASSWORD_CHANGE_REFUSAL ( 0x00000100 )
+#define NETLOGON_NEG_SEND_PASSWORD_INFO_PDC ( 0x00000200 )
+#define NETLOGON_NEG_GENERIC_PASSTHROUGH ( 0x00000400 )
+#define NETLOGON_NEG_CONCURRENT_RPC ( 0x00000800 )
+#define NETLOGON_NEG_AVOID_ACCOUNT_DB_REPL ( 0x00001000 )
+#define NETLOGON_NEG_AVOID_SECURITYAUTH_DB_REPL ( 0x00002000 )
+#define NETLOGON_NEG_128BIT ( 0x00004000 )
+#define NETLOGON_NEG_TRANSITIVE_TRUSTS ( 0x00008000 )
+#define NETLOGON_NEG_DNS_DOMAIN_TRUSTS ( 0x00010000 )
+#define NETLOGON_NEG_PASSWORD_SET2 ( 0x00020000 )
+#define NETLOGON_NEG_GETDOMAININFO ( 0x00040000 )
+#define NETLOGON_NEG_CROSS_FOREST_TRUSTS ( 0x00080000 )
+#define NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION ( 0x00100000 )
+#define NETLOGON_NEG_RODC_PASSTHROUGH ( 0x00200000 )
+#define NETLOGON_NEG_AUTHENTICATED_RPC_LSASS ( 0x20000000 )
+#define NETLOGON_NEG_SCHANNEL ( 0x40000000 )
+
+struct netr_Blob {
+ uint32_t length;
+ uint8_t *data;/* [unique,size_is(length)] */
+};
+
+/* bitmap netr_DsRGetDCName_flags */
+#define DS_FORCE_REDISCOVERY ( 0x00000001 )
+#define DS_DIRECTORY_SERVICE_REQUIRED ( 0x00000010 )
+#define DS_DIRECTORY_SERVICE_PREFERRED ( 0x00000020 )
+#define DS_GC_SERVER_REQUIRED ( 0x00000040 )
+#define DS_PDC_REQUIRED ( 0x00000080 )
+#define DS_BACKGROUND_ONLY ( 0x00000100 )
+#define DS_IP_REQUIRED ( 0x00000200 )
+#define DS_KDC_REQUIRED ( 0x00000400 )
+#define DS_TIMESERV_REQUIRED ( 0x00000800 )
+#define DS_WRITABLE_REQUIRED ( 0x00001000 )
+#define DS_GOOD_TIMESERV_PREFERRED ( 0x00002000 )
+#define DS_AVOID_SELF ( 0x00004000 )
+#define DS_ONLY_LDAP_NEEDED ( 0x00008000 )
+#define DS_IS_FLAT_NAME ( 0x00010000 )
+#define DS_IS_DNS_NAME ( 0x00020000 )
+#define DS_TRY_NEXTCLOSEST_SITE ( 0x00040000 )
+#define DS_DIRECTORY_SERVICE_6_REQUIRED ( 0x00080000 )
+#define DS_RETURN_DNS_NAME ( 0x40000000 )
+#define DS_RETURN_FLAT_NAME ( 0x80000000 )
+
+enum netr_DsRGetDCNameInfo_AddressType
+#ifndef USE_UINT_ENUMS
+ {
+ DS_ADDRESS_TYPE_INET=1,
+ DS_ADDRESS_TYPE_NETBIOS=2
+}
+#else
+ { __donnot_use_enum_netr_DsRGetDCNameInfo_AddressType=0x7FFFFFFF}
+#define DS_ADDRESS_TYPE_INET ( 1 )
+#define DS_ADDRESS_TYPE_NETBIOS ( 2 )
+#endif
+;
+
+/* bitmap netr_DsR_DcFlags */
+#define DS_SERVER_PDC ( NBT_SERVER_PDC )
+#define DS_SERVER_GC ( NBT_SERVER_GC )
+#define DS_SERVER_LDAP ( NBT_SERVER_LDAP )
+#define DS_SERVER_DS ( NBT_SERVER_DS )
+#define DS_SERVER_KDC ( NBT_SERVER_KDC )
+#define DS_SERVER_TIMESERV ( NBT_SERVER_TIMESERV )
+#define DS_SERVER_CLOSEST ( NBT_SERVER_CLOSEST )
+#define DS_SERVER_WRITABLE ( NBT_SERVER_WRITABLE )
+#define DS_SERVER_GOOD_TIMESERV ( NBT_SERVER_GOOD_TIMESERV )
+#define DS_SERVER_NDNC ( NBT_SERVER_NDNC )
+#define DS_SERVER_SELECT_SECRET_DOMAIN_6 ( NBT_SERVER_SELECT_SECRET_DOMAIN_6 )
+#define DS_SERVER_FULL_SECRET_DOMAIN_6 ( NBT_SERVER_FULL_SECRET_DOMAIN_6 )
+#define DS_DNS_CONTROLLER ( 0x20000000 )
+#define DS_DNS_DOMAIN ( 0x40000000 )
+#define DS_DNS_FOREST ( 0x80000000 )
+
+struct netr_DsRGetDCNameInfo {
+ const char *dc_unc;/* [unique,charset(UTF16)] */
+ const char *dc_address;/* [unique,charset(UTF16)] */
+ enum netr_DsRGetDCNameInfo_AddressType dc_address_type;
+ struct GUID domain_guid;
+ const char *domain_name;/* [unique,charset(UTF16)] */
+ const char *forest_name;/* [unique,charset(UTF16)] */
+ uint32_t dc_flags;
+ const char *dc_site_name;/* [unique,charset(UTF16)] */
+ const char *client_site_name;/* [unique,charset(UTF16)] */
+}/* [public] */;
+
+struct netr_BinaryString {
+ uint16_t length;
+ uint16_t size;
+ uint16_t *data;/* [unique,length_is(length/2),size_is(size/2)] */
+}/* [flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+struct netr_DomainQuery1 {
+ struct netr_Blob blob;
+ const char *workstation_domain;/* [unique,charset(UTF16)] */
+ const char *workstation_site;/* [unique,charset(UTF16)] */
+ const char *unknown1;/* [unique,charset(UTF16)] */
+ const char *unknown2;/* [unique,charset(UTF16)] */
+ const char *unknown3;/* [unique,charset(UTF16)] */
+ const char *unknown4;/* [unique,charset(UTF16)] */
+ struct netr_BinaryString blob2;
+ struct lsa_String product;
+ struct lsa_String unknown5;
+ struct lsa_String unknown6;
+ uint32_t unknown7[4];
+};
+
+union netr_DomainQuery {
+ struct netr_DomainQuery1 *query1;/* [unique,case] */
+};
+
+struct netr_DomainTrustInfo {
+ struct lsa_String domainname;
+ struct lsa_String fulldomainname;
+ struct lsa_String forest;
+ struct GUID guid;
+ struct dom_sid2 *sid;/* [unique] */
+ struct netr_BinaryString unknown1[4];
+ uint32_t unknown[4];
+};
+
+struct netr_DomainInfo1 {
+ struct netr_DomainTrustInfo domaininfo;
+ uint32_t num_trusts;
+ struct netr_DomainTrustInfo *trusts;/* [unique,size_is(num_trusts)] */
+ uint32_t unknown[14];
+};
+
+union netr_DomainInfo {
+ struct netr_DomainInfo1 *info1;/* [unique,case] */
+};
+
+struct netr_CryptPassword {
+ uint8_t data[512];
+ uint32_t length;
+}/* [flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+struct netr_DsRAddressToSitenamesWCtr {
+ uint32_t count;
+ struct lsa_String *sitename;/* [unique,size_is(count)] */
+};
+
+struct netr_DsRAddress {
+ uint8_t *buffer;/* [unique,size_is(size)] */
+ uint32_t size;
+};
+
+/* bitmap netr_TrustFlags */
+#define NETR_TRUST_FLAG_IN_FOREST ( 0x00000001 )
+#define NETR_TRUST_FLAG_OUTBOUND ( 0x00000002 )
+#define NETR_TRUST_FLAG_TREEROOT ( 0x00000004 )
+#define NETR_TRUST_FLAG_PRIMARY ( 0x00000008 )
+#define NETR_TRUST_FLAG_NATIVE ( 0x00000010 )
+#define NETR_TRUST_FLAG_INBOUND ( 0x00000020 )
+
+enum netr_TrustType
+#ifndef USE_UINT_ENUMS
+ {
+ NETR_TRUST_TYPE_DOWNLEVEL=1,
+ NETR_TRUST_TYPE_UPLEVEL=2,
+ NETR_TRUST_TYPE_MIT=3,
+ NETR_TRUST_TYPE_DCE=4
+}
+#else
+ { __donnot_use_enum_netr_TrustType=0x7FFFFFFF}
+#define NETR_TRUST_TYPE_DOWNLEVEL ( 1 )
+#define NETR_TRUST_TYPE_UPLEVEL ( 2 )
+#define NETR_TRUST_TYPE_MIT ( 3 )
+#define NETR_TRUST_TYPE_DCE ( 4 )
+#endif
+;
+
+/* bitmap netr_TrustAttributes */
+#define NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE ( 0x00000001 )
+#define NETR_TRUST_ATTRIBUTE_UPLEVEL_ONLY ( 0x00000002 )
+#define NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN ( 0x00000004 )
+#define NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE ( 0x00000008 )
+#define NETR_TRUST_ATTRIBUTE_CROSS_ORGANIZATION ( 0x00000010 )
+#define NETR_TRUST_ATTRIBUTE_WITHIN_FOREST ( 0x00000020 )
+#define NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL ( 0x00000040 )
+
+struct netr_DomainTrust {
+ const char *netbios_name;/* [unique,charset(UTF16)] */
+ const char *dns_name;/* [unique,charset(UTF16)] */
+ uint32_t trust_flags;
+ uint32_t parent_index;
+ enum netr_TrustType trust_type;
+ uint32_t trust_attributes;
+ struct dom_sid2 *sid;/* [unique] */
+ struct GUID guid;
+};
+
+struct netr_DomainTrustList {
+ uint32_t count;
+ struct netr_DomainTrust *array;/* [unique,size_is(count)] */
+};
+
+struct netr_DsRAddressToSitenamesExWCtr {
+ uint32_t count;
+ struct lsa_String *sitename;/* [unique,size_is(count)] */
+ struct lsa_String *subnetname;/* [unique,size_is(count)] */
+};
+
+struct DcSitesCtr {
+ uint32_t num_sites;
+ struct lsa_String *sites;/* [unique,size_is(num_sites)] */
+};
+
+
+struct netr_LogonUasLogon {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *account_name;/* [charset(UTF16)] */
+ const char *workstation;/* [charset(UTF16)] */
+ } in;
+
+ struct {
+ struct netr_UasInfo *info;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_LogonUasLogoff {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *account_name;/* [charset(UTF16)] */
+ const char *workstation;/* [charset(UTF16)] */
+ } in;
+
+ struct {
+ struct netr_UasLogoffInfo *info;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_LogonSamLogon {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *computer_name;/* [unique,charset(UTF16)] */
+ struct netr_Authenticator *credential;/* [unique] */
+ enum netr_LogonLevel logon_level;
+ union netr_LogonInfo *logon;/* [ref,switch_is(logon_level)] */
+ uint16_t validation_level;
+ struct netr_Authenticator *return_authenticator;/* [unique] */
+ } in;
+
+ struct {
+ union netr_Validation *validation;/* [ref,switch_is(validation_level)] */
+ uint8_t *authoritative;/* [ref] */
+ struct netr_Authenticator *return_authenticator;/* [unique] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_LogonSamLogoff {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *computer_name;/* [unique,charset(UTF16)] */
+ struct netr_Authenticator *credential;/* [unique] */
+ enum netr_LogonLevel logon_level;
+ union netr_LogonInfo logon;/* [switch_is(logon_level)] */
+ struct netr_Authenticator *return_authenticator;/* [unique] */
+ } in;
+
+ struct {
+ struct netr_Authenticator *return_authenticator;/* [unique] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_ServerReqChallenge {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *computer_name;/* [charset(UTF16)] */
+ struct netr_Credential *credentials;/* [ref] */
+ } in;
+
+ struct {
+ struct netr_Credential *return_credentials;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_ServerAuthenticate {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *account_name;/* [charset(UTF16)] */
+ enum netr_SchannelType secure_channel_type;
+ const char *computer_name;/* [charset(UTF16)] */
+ struct netr_Credential *credentials;/* [ref] */
+ } in;
+
+ struct {
+ struct netr_Credential *return_credentials;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_ServerPasswordSet {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *account_name;/* [charset(UTF16)] */
+ enum netr_SchannelType secure_channel_type;
+ const char *computer_name;/* [charset(UTF16)] */
+ struct netr_Authenticator *credential;/* [ref] */
+ struct samr_Password *new_password;/* [ref] */
+ } in;
+
+ struct {
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_DatabaseDeltas {
+ struct {
+ const char *logon_server;/* [charset(UTF16)] */
+ const char *computername;/* [charset(UTF16)] */
+ struct netr_Authenticator *credential;/* [ref] */
+ enum netr_SamDatabaseID database_id;
+ uint32_t preferredmaximumlength;
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ uint64_t *sequence_num;/* [ref] */
+ } in;
+
+ struct {
+ struct netr_DELTA_ENUM_ARRAY **delta_enum_array;/* [ref] */
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ uint64_t *sequence_num;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_DatabaseSync {
+ struct {
+ const char *logon_server;/* [charset(UTF16)] */
+ const char *computername;/* [charset(UTF16)] */
+ struct netr_Authenticator credential;
+ enum netr_SamDatabaseID database_id;
+ uint32_t preferredmaximumlength;
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ uint32_t *sync_context;/* [ref] */
+ } in;
+
+ struct {
+ struct netr_DELTA_ENUM_ARRAY *delta_enum_array;/* [ref] */
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ uint32_t *sync_context;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_AccountDeltas {
+ struct {
+ const char *logon_server;/* [unique,charset(UTF16)] */
+ const char *computername;/* [charset(UTF16)] */
+ struct netr_Authenticator credential;
+ struct netr_UAS_INFO_0 uas;
+ uint32_t count;
+ uint32_t level;
+ uint32_t buffersize;
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ } in;
+
+ struct {
+ struct netr_AccountBuffer *buffer;/* [ref,subcontext(4)] */
+ uint32_t *count_returned;/* [ref] */
+ uint32_t *total_entries;/* [ref] */
+ struct netr_UAS_INFO_0 *recordid;/* [ref] */
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_AccountSync {
+ struct {
+ const char *logon_server;/* [unique,charset(UTF16)] */
+ const char *computername;/* [charset(UTF16)] */
+ struct netr_Authenticator credential;
+ uint32_t reference;
+ uint32_t level;
+ uint32_t buffersize;
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ struct netr_UAS_INFO_0 *recordid;/* [ref] */
+ } in;
+
+ struct {
+ struct netr_AccountBuffer *buffer;/* [ref,subcontext(4)] */
+ uint32_t *count_returned;/* [ref] */
+ uint32_t *total_entries;/* [ref] */
+ uint32_t *next_reference;/* [ref] */
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ struct netr_UAS_INFO_0 *recordid;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_GetDcName {
+ struct {
+ const char *logon_server;/* [charset(UTF16)] */
+ const char *domainname;/* [unique,charset(UTF16)] */
+ } in;
+
+ struct {
+ const char **dcname;/* [ref,charset(UTF16)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_LogonControl {
+ struct {
+ const char *logon_server;/* [unique,charset(UTF16)] */
+ enum netr_LogonControlCode function_code;
+ uint32_t level;
+ } in;
+
+ struct {
+ union netr_CONTROL_QUERY_INFORMATION *info;/* [ref,switch_is(level)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_GetAnyDCName {
+ struct {
+ const char *logon_server;/* [unique,charset(UTF16)] */
+ const char *domainname;/* [unique,charset(UTF16)] */
+ } in;
+
+ struct {
+ const char **dcname;/* [ref,charset(UTF16)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_LogonControl2 {
+ struct {
+ const char *logon_server;/* [unique,charset(UTF16)] */
+ enum netr_LogonControlCode function_code;
+ uint32_t level;
+ union netr_CONTROL_DATA_INFORMATION *data;/* [ref,switch_is(function_code)] */
+ } in;
+
+ struct {
+ union netr_CONTROL_QUERY_INFORMATION *query;/* [ref,switch_is(level)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_ServerAuthenticate2 {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *account_name;/* [charset(UTF16)] */
+ enum netr_SchannelType secure_channel_type;
+ const char *computer_name;/* [charset(UTF16)] */
+ struct netr_Credential *credentials;/* [ref] */
+ uint32_t *negotiate_flags;/* [ref] */
+ } in;
+
+ struct {
+ struct netr_Credential *return_credentials;/* [ref] */
+ uint32_t *negotiate_flags;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_DatabaseSync2 {
+ struct {
+ const char *logon_server;/* [charset(UTF16)] */
+ const char *computername;/* [charset(UTF16)] */
+ struct netr_Authenticator *credential;/* [ref] */
+ enum netr_SamDatabaseID database_id;
+ uint16_t restart_state;
+ uint32_t preferredmaximumlength;
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ uint32_t *sync_context;/* [ref] */
+ } in;
+
+ struct {
+ struct netr_DELTA_ENUM_ARRAY **delta_enum_array;/* [ref] */
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ uint32_t *sync_context;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_DatabaseRedo {
+ struct {
+ const char *logon_server;/* [charset(UTF16)] */
+ const char *computername;/* [charset(UTF16)] */
+ struct netr_Authenticator credential;
+ uint8_t *change_log_entry;/* [unique,size_is(change_log_entry_size)] */
+ uint32_t change_log_entry_size;
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ } in;
+
+ struct {
+ struct netr_DELTA_ENUM_ARRAY *delta_enum_array;/* [ref] */
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_LogonControl2Ex {
+ struct {
+ const char *logon_server;/* [unique,charset(UTF16)] */
+ uint32_t function_code;
+ uint32_t level;
+ union netr_CONTROL_DATA_INFORMATION data;/* [switch_is(function_code)] */
+ } in;
+
+ struct {
+ union netr_CONTROL_QUERY_INFORMATION *query;/* [ref,switch_is(level)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_NetrEnumerateTrustedDomains {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ } in;
+
+ struct {
+ struct netr_Blob *trusted_domains_blob;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_DsRGetDCName {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *domain_name;/* [unique,charset(UTF16)] */
+ struct GUID *domain_guid;/* [unique] */
+ struct GUID *site_guid;/* [unique] */
+ uint32_t flags;
+ } in;
+
+ struct {
+ struct netr_DsRGetDCNameInfo **info;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_NETRLOGONDUMMYROUTINE1 {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_NETRLOGONSETSERVICEBITS {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_LogonGetTrustRid {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *domain_name;/* [unique,charset(UTF16)] */
+ } in;
+
+ struct {
+ uint32_t *rid;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_NETRLOGONCOMPUTESERVERDIGEST {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_NETRLOGONCOMPUTECLIENTDIGEST {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_ServerAuthenticate3 {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *account_name;/* [charset(UTF16)] */
+ enum netr_SchannelType secure_channel_type;
+ const char *computer_name;/* [charset(UTF16)] */
+ struct netr_Credential *credentials;/* [ref] */
+ uint32_t *negotiate_flags;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *rid;/* [ref] */
+ struct netr_Credential *credentials;/* [ref] */
+ uint32_t *negotiate_flags;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_DsRGetDCNameEx {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *domain_name;/* [unique,charset(UTF16)] */
+ struct GUID *domain_guid;/* [unique] */
+ const char *site_name;/* [unique,charset(UTF16)] */
+ uint32_t flags;
+ } in;
+
+ struct {
+ struct netr_DsRGetDCNameInfo **info;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_DsRGetSiteName {
+ struct {
+ const char *computer_name;/* [unique,charset(UTF16)] */
+ } in;
+
+ struct {
+ const char **site;/* [ref,charset(UTF16)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_LogonGetDomainInfo {
+ struct {
+ const char *server_name;/* [charset(UTF16)] */
+ const char *computer_name;/* [unique,charset(UTF16)] */
+ struct netr_Authenticator *credential;/* [ref] */
+ uint32_t level;
+ union netr_DomainQuery query;/* [switch_is(level)] */
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ } in;
+
+ struct {
+ union netr_DomainInfo *info;/* [ref,switch_is(level)] */
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_ServerPasswordSet2 {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *account_name;/* [charset(UTF16)] */
+ enum netr_SchannelType secure_channel_type;
+ const char *computer_name;/* [charset(UTF16)] */
+ struct netr_Authenticator *credential;/* [ref] */
+ struct netr_CryptPassword *new_password;/* [ref] */
+ } in;
+
+ struct {
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_ServerPasswordGet {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *account_name;/* [charset(UTF16)] */
+ enum netr_SchannelType secure_channel_type;
+ const char *computer_name;/* [charset(UTF16)] */
+ struct netr_Authenticator *credential;/* [ref] */
+ } in;
+
+ struct {
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ struct samr_Password *password;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_NETRLOGONSENDTOSAM {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_DsRAddressToSitenamesW {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ uint32_t count;/* [range(0,32000)] */
+ struct netr_DsRAddress *addresses;/* [ref,size_is(count)] */
+ } in;
+
+ struct {
+ struct netr_DsRAddressToSitenamesWCtr **ctr;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_DsRGetDCNameEx2 {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *client_account;/* [unique,charset(UTF16)] */
+ uint32_t mask;
+ const char *domain_name;/* [unique,charset(UTF16)] */
+ struct GUID *domain_guid;/* [unique] */
+ const char *site_name;/* [unique,charset(UTF16)] */
+ uint32_t flags;
+ } in;
+
+ struct {
+ struct netr_DsRGetDCNameInfo **info;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_NetrEnumerateTrustedDomainsEx {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ } in;
+
+ struct {
+ struct netr_DomainTrustList *dom_trust_list;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_DsRAddressToSitenamesExW {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ uint32_t count;/* [range(0,32000)] */
+ struct netr_DsRAddress *addresses;/* [ref,size_is(count)] */
+ } in;
+
+ struct {
+ struct netr_DsRAddressToSitenamesExWCtr **ctr;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_DsrGetDcSiteCoverageW {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ } in;
+
+ struct {
+ struct DcSitesCtr *ctr;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_LogonSamLogonEx {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *computer_name;/* [unique,charset(UTF16)] */
+ enum netr_LogonLevel logon_level;
+ union netr_LogonInfo *logon;/* [ref,switch_is(logon_level)] */
+ uint16_t validation_level;
+ uint32_t *flags;/* [ref] */
+ } in;
+
+ struct {
+ union netr_Validation *validation;/* [ref,switch_is(validation_level)] */
+ uint8_t *authoritative;/* [ref] */
+ uint32_t *flags;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_DsrEnumerateDomainTrusts {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ uint32_t trust_flags;
+ } in;
+
+ struct {
+ struct netr_DomainTrustList *trusts;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_DsrDeregisterDNSHostRecords {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *domain;/* [unique,charset(UTF16)] */
+ struct GUID *domain_guid;/* [unique] */
+ struct GUID *dsa_guid;/* [unique] */
+ const char *dns_host;/* [ref,charset(UTF16)] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_ServerTrustPasswordsGet {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *account_name;/* [charset(UTF16)] */
+ enum netr_SchannelType secure_channel_type;
+ const char *computer_name;/* [charset(UTF16)] */
+ struct netr_Authenticator *credential;/* [ref] */
+ } in;
+
+ struct {
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ struct samr_Password *password;/* [ref] */
+ struct samr_Password *password2;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_DsRGetForestTrustInformation {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *trusted_domain_name;/* [unique,charset(UTF16)] */
+ uint32_t flags;
+ } in;
+
+ struct {
+ struct lsa_ForestTrustInformation **forest_trust_info;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_GetForestTrustInformation {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *trusted_domain_name;/* [ref,charset(UTF16)] */
+ struct netr_Authenticator *credential;/* [ref] */
+ uint32_t flags;
+ } in;
+
+ struct {
+ struct netr_Authenticator *return_authenticator;/* [ref] */
+ struct lsa_ForestTrustInformation **forest_trust_info;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct netr_LogonSamLogonWithFlags {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *computer_name;/* [unique,charset(UTF16)] */
+ struct netr_Authenticator *credential;/* [unique] */
+ enum netr_LogonLevel logon_level;
+ union netr_LogonInfo logon;/* [switch_is(logon_level)] */
+ uint16_t validation_level;
+ struct netr_Authenticator *return_authenticator;/* [unique] */
+ uint32_t *flags;/* [ref] */
+ } in;
+
+ struct {
+ union netr_Validation *validation;/* [ref,switch_is(validation_level)] */
+ uint8_t *authoritative;/* [ref] */
+ struct netr_Authenticator *return_authenticator;/* [unique] */
+ uint32_t *flags;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct netr_NETRSERVERGETTRUSTINFO {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+#endif /* _HEADER_netlogon */
diff --git a/source3/librpc/gen_ndr/notify.h b/source3/librpc/gen_ndr/notify.h
new file mode 100644
index 0000000000..c809702e5d
--- /dev/null
+++ b/source3/librpc/gen_ndr/notify.h
@@ -0,0 +1,35 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#ifndef _HEADER_notify
+#define _HEADER_notify
+
+struct notify_entry {
+ struct server_id server;
+ uint32_t filter;
+ uint32_t subdir_filter;
+ const char * path;/* [flag(LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM)] */
+ uint32_t path_len;
+ void* private_data;
+}/* [public] */;
+
+struct notify_depth {
+ uint32_t max_mask;
+ uint32_t max_mask_subdir;
+ uint32_t num_entries;
+ struct notify_entry *entries;
+};
+
+struct notify_array {
+ uint32_t num_depths;
+ struct notify_depth *depth;
+}/* [public] */;
+
+struct notify_event {
+ uint32_t action;
+ const char * path;/* [flag(LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM)] */
+ void* private_data;
+}/* [public] */;
+
+#endif /* _HEADER_notify */
diff --git a/source3/librpc/gen_ndr/ntsvcs.h b/source3/librpc/gen_ndr/ntsvcs.h
new file mode 100644
index 0000000000..95484e49f5
--- /dev/null
+++ b/source3/librpc/gen_ndr/ntsvcs.h
@@ -0,0 +1,582 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#ifndef _HEADER_ntsvcs
+#define _HEADER_ntsvcs
+
+#define DEV_REGPROP_DESC ( 1 )
+struct PNP_HwProfInfo {
+ uint32_t unknown1;
+ uint16_t unknown2[160];
+ uint32_t unknown3;
+};
+
+
+struct PNP_Disconnect {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_Connect {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetVersion {
+ struct {
+ uint16_t *version;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetGlobalState {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_InitDetection {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_ReportLogOn {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_ValidateDeviceInstance {
+ struct {
+ const char *devicepath;/* [ref,charset(UTF16)] */
+ uint32_t flags;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetRootDeviceInstance {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetRelatedDeviceInstance {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_EnumerateSubKeys {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetDeviceList {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetDeviceListSize {
+ struct {
+ const char *devicename;/* [unique,charset(UTF16)] */
+ uint32_t flags;
+ } in;
+
+ struct {
+ uint32_t *size;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetDepth {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetDeviceRegProp {
+ struct {
+ const char *devicepath;/* [ref,charset(UTF16)] */
+ uint32_t property;
+ uint32_t unknown3;
+ uint32_t *unknown1;/* [ref] */
+ uint32_t *buffer_size;/* [ref] */
+ uint32_t *needed;/* [ref] */
+ } in;
+
+ struct {
+ uint8_t *buffer;/* [ref,length_is(*buffer_size),size_is(*buffer_size)] */
+ uint32_t *unknown1;/* [ref] */
+ uint32_t *buffer_size;/* [ref] */
+ uint32_t *needed;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_SetDeviceRegProp {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetClassInstance {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_CreateKey {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_DeleteRegistryKey {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetClassCount {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetClassName {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_DeleteClassKey {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetInterfaceDeviceAlias {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetInterfaceDeviceList {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetInterfaceDeviceListSize {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_RegisterDeviceClassAssociation {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_UnregisterDeviceClassAssociation {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetClassRegProp {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_SetClassRegProp {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_CreateDevInst {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_DeviceInstanceAction {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetDeviceStatus {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_SetDeviceProblem {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_DisableDevInst {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_UninstallDevInst {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_AddID {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_RegisterDriver {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_QueryRemove {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_RequestDeviceEject {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_IsDockStationPresent {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_RequestEjectPC {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_HwProfFlags {
+ struct {
+ uint32_t unknown1;
+ const char *devicepath;/* [ref,charset(UTF16)] */
+ uint32_t unknown2;
+ const char *unknown5;/* [unique,charset(UTF16)] */
+ uint32_t unknown6;
+ uint32_t unknown7;
+ uint32_t *unknown3;/* [ref] */
+ uint16_t *unknown4;/* [unique] */
+ } in;
+
+ struct {
+ const char **unknown5a;/* [unique,charset(UTF16)] */
+ uint32_t *unknown3;/* [ref] */
+ uint16_t *unknown4;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetHwProfInfo {
+ struct {
+ uint32_t idx;
+ uint32_t unknown1;
+ uint32_t unknown2;
+ struct PNP_HwProfInfo *info;/* [ref] */
+ } in;
+
+ struct {
+ struct PNP_HwProfInfo *info;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_AddEmptyLogConf {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_FreeLogConf {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetFirstLogConf {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetNextLogConf {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetLogConfPriority {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_AddResDes {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_FreeResDes {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetNextResDes {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetResDesData {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetResDesDataSize {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_ModifyResDes {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_DetectResourceLimit {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_QueryResConfList {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_SetHwProf {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_QueryArbitratorFreeData {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_QueryArbitratorFreeSize {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_RunDetection {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_RegisterNotification {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_UnregisterNotification {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetCustomDevProp {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetVersionInternal {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetBlockedDriverInfo {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct PNP_GetServerSideDeviceInstallFlags {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+#endif /* _HEADER_ntsvcs */
diff --git a/source3/librpc/gen_ndr/samr.h b/source3/librpc/gen_ndr/samr.h
new file mode 100644
index 0000000000..522c6a9cec
--- /dev/null
+++ b/source3/librpc/gen_ndr/samr.h
@@ -0,0 +1,1759 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#include "librpc/gen_ndr/misc.h"
+#include "librpc/gen_ndr/lsa.h"
+#include "librpc/gen_ndr/security.h"
+#ifndef _HEADER_samr
+#define _HEADER_samr
+
+#define MAX_SAM_ENTRIES_W2K ( 0x400 )
+#define MAX_SAM_ENTRIES_W95 ( 50 )
+#define SAMR_ENUM_USERS_MULTIPLIER ( 54 )
+#define PASS_MUST_CHANGE_AT_NEXT_LOGON ( 0x01 )
+#define PASS_DONT_CHANGE_AT_NEXT_LOGON ( 0x00 )
+/* bitmap samr_AcctFlags */
+#define ACB_DISABLED ( 0x00000001 )
+#define ACB_HOMDIRREQ ( 0x00000002 )
+#define ACB_PWNOTREQ ( 0x00000004 )
+#define ACB_TEMPDUP ( 0x00000008 )
+#define ACB_NORMAL ( 0x00000010 )
+#define ACB_MNS ( 0x00000020 )
+#define ACB_DOMTRUST ( 0x00000040 )
+#define ACB_WSTRUST ( 0x00000080 )
+#define ACB_SVRTRUST ( 0x00000100 )
+#define ACB_PWNOEXP ( 0x00000200 )
+#define ACB_AUTOLOCK ( 0x00000400 )
+#define ACB_ENC_TXT_PWD_ALLOWED ( 0x00000800 )
+#define ACB_SMARTCARD_REQUIRED ( 0x00001000 )
+#define ACB_TRUSTED_FOR_DELEGATION ( 0x00002000 )
+#define ACB_NOT_DELEGATED ( 0x00004000 )
+#define ACB_USE_DES_KEY_ONLY ( 0x00008000 )
+#define ACB_DONT_REQUIRE_PREAUTH ( 0x00010000 )
+#define ACB_PW_EXPIRED ( 0x00020000 )
+#define ACB_NO_AUTH_DATA_REQD ( 0x00080000 )
+
+/* bitmap samr_ConnectAccessMask */
+#define SAMR_ACCESS_CONNECT_TO_SERVER ( 0x00000001 )
+#define SAMR_ACCESS_SHUTDOWN_SERVER ( 0x00000002 )
+#define SAMR_ACCESS_INITIALIZE_SERVER ( 0x00000004 )
+#define SAMR_ACCESS_CREATE_DOMAIN ( 0x00000008 )
+#define SAMR_ACCESS_ENUM_DOMAINS ( 0x00000010 )
+#define SAMR_ACCESS_OPEN_DOMAIN ( 0x00000020 )
+
+/* bitmap samr_UserAccessMask */
+#define SAMR_USER_ACCESS_GET_NAME_ETC ( 0x00000001 )
+#define SAMR_USER_ACCESS_GET_LOCALE ( 0x00000002 )
+#define SAMR_USER_ACCESS_SET_LOC_COM ( 0x00000004 )
+#define SAMR_USER_ACCESS_GET_LOGONINFO ( 0x00000008 )
+#define SAMR_USER_ACCESS_GET_ATTRIBUTES ( 0x00000010 )
+#define SAMR_USER_ACCESS_SET_ATTRIBUTES ( 0x00000020 )
+#define SAMR_USER_ACCESS_CHANGE_PASSWORD ( 0x00000040 )
+#define SAMR_USER_ACCESS_SET_PASSWORD ( 0x00000080 )
+#define SAMR_USER_ACCESS_GET_GROUPS ( 0x00000100 )
+#define SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP ( 0x00000200 )
+#define SAMR_USER_ACCESS_CHANGE_GROUP_MEMBERSHIP ( 0x00000400 )
+
+/* bitmap samr_DomainAccessMask */
+#define SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 ( 0x00000001 )
+#define SAMR_DOMAIN_ACCESS_SET_INFO_1 ( 0x00000002 )
+#define SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 ( 0x00000004 )
+#define SAMR_DOMAIN_ACCESS_SET_INFO_2 ( 0x00000008 )
+#define SAMR_DOMAIN_ACCESS_CREATE_USER ( 0x00000010 )
+#define SAMR_DOMAIN_ACCESS_CREATE_GROUP ( 0x00000020 )
+#define SAMR_DOMAIN_ACCESS_CREATE_ALIAS ( 0x00000040 )
+#define SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS ( 0x00000080 )
+#define SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS ( 0x00000100 )
+#define SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT ( 0x00000200 )
+#define SAMR_DOMAIN_ACCESS_SET_INFO_3 ( 0x00000400 )
+
+/* bitmap samr_GroupAccessMask */
+#define SAMR_GROUP_ACCESS_LOOKUP_INFO ( 0x00000001 )
+#define SAMR_GROUP_ACCESS_SET_INFO ( 0x00000002 )
+#define SAMR_GROUP_ACCESS_ADD_MEMBER ( 0x00000004 )
+#define SAMR_GROUP_ACCESS_REMOVE_MEMBER ( 0x00000008 )
+#define SAMR_GROUP_ACCESS_GET_MEMBERS ( 0x00000010 )
+
+/* bitmap samr_AliasAccessMask */
+#define SAMR_ALIAS_ACCESS_ADD_MEMBER ( 0x00000001 )
+#define SAMR_ALIAS_ACCESS_REMOVE_MEMBER ( 0x00000002 )
+#define SAMR_ALIAS_ACCESS_GET_MEMBERS ( 0x00000004 )
+#define SAMR_ALIAS_ACCESS_LOOKUP_INFO ( 0x00000008 )
+#define SAMR_ALIAS_ACCESS_SET_INFO ( 0x00000010 )
+
+struct samr_SamEntry {
+ uint32_t idx;
+ struct lsa_String name;
+};
+
+struct samr_SamArray {
+ uint32_t count;
+ struct samr_SamEntry *entries;/* [unique,size_is(count)] */
+};
+
+enum samr_Role
+#ifndef USE_UINT_ENUMS
+ {
+ SAMR_ROLE_STANDALONE=0,
+ SAMR_ROLE_DOMAIN_MEMBER=1,
+ SAMR_ROLE_DOMAIN_BDC=2,
+ SAMR_ROLE_DOMAIN_PDC=3
+}
+#else
+ { __donnot_use_enum_samr_Role=0x7FFFFFFF}
+#define SAMR_ROLE_STANDALONE ( 0 )
+#define SAMR_ROLE_DOMAIN_MEMBER ( 1 )
+#define SAMR_ROLE_DOMAIN_BDC ( 2 )
+#define SAMR_ROLE_DOMAIN_PDC ( 3 )
+#endif
+;
+
+/* bitmap samr_PasswordProperties */
+#define DOMAIN_PASSWORD_COMPLEX ( 0x00000001 )
+#define DOMAIN_PASSWORD_NO_ANON_CHANGE ( 0x00000002 )
+#define DOMAIN_PASSWORD_NO_CLEAR_CHANGE ( 0x00000004 )
+#define DOMAIN_PASSWORD_LOCKOUT_ADMINS ( 0x00000008 )
+#define DOMAIN_PASSWORD_STORE_CLEARTEXT ( 0x00000010 )
+#define DOMAIN_REFUSE_PASSWORD_CHANGE ( 0x00000020 )
+
+struct samr_DomInfo1 {
+ uint16_t min_password_length;
+ uint16_t password_history_length;
+ uint32_t password_properties;
+ int64_t max_password_age;
+ int64_t min_password_age;
+};
+
+struct samr_DomInfo2 {
+ NTTIME force_logoff_time;
+ struct lsa_String comment;
+ struct lsa_String domain_name;
+ struct lsa_String primary;
+ uint64_t sequence_num;
+ uint32_t unknown2;
+ enum samr_Role role;
+ uint32_t unknown3;
+ uint32_t num_users;
+ uint32_t num_groups;
+ uint32_t num_aliases;
+};
+
+struct samr_DomInfo3 {
+ NTTIME force_logoff_time;
+};
+
+struct samr_DomInfo4 {
+ struct lsa_String comment;
+};
+
+struct samr_DomInfo5 {
+ struct lsa_String domain_name;
+};
+
+struct samr_DomInfo6 {
+ struct lsa_String primary;
+};
+
+struct samr_DomInfo7 {
+ enum samr_Role role;
+};
+
+struct samr_DomInfo8 {
+ uint64_t sequence_num;
+ NTTIME domain_create_time;
+};
+
+struct samr_DomInfo9 {
+ uint32_t unknown;
+};
+
+struct samr_DomInfo11 {
+ struct samr_DomInfo2 info2;
+ uint64_t lockout_duration;
+ uint64_t lockout_window;
+ uint16_t lockout_threshold;
+};
+
+struct samr_DomInfo12 {
+ uint64_t lockout_duration;
+ uint64_t lockout_window;
+ uint16_t lockout_threshold;
+};
+
+struct samr_DomInfo13 {
+ uint64_t sequence_num;
+ NTTIME domain_create_time;
+ uint32_t unknown1;
+ uint32_t unknown2;
+};
+
+union samr_DomainInfo {
+ struct samr_DomInfo1 info1;/* [case] */
+ struct samr_DomInfo2 info2;/* [case(2)] */
+ struct samr_DomInfo3 info3;/* [case(3)] */
+ struct samr_DomInfo4 info4;/* [case(4)] */
+ struct samr_DomInfo5 info5;/* [case(5)] */
+ struct samr_DomInfo6 info6;/* [case(6)] */
+ struct samr_DomInfo7 info7;/* [case(7)] */
+ struct samr_DomInfo8 info8;/* [case(8)] */
+ struct samr_DomInfo9 info9;/* [case(9)] */
+ struct samr_DomInfo11 info11;/* [case(11)] */
+ struct samr_DomInfo12 info12;/* [case(12)] */
+ struct samr_DomInfo13 info13;/* [case(13)] */
+}/* [switch_type(uint16)] */;
+
+struct samr_Ids {
+ uint32_t count;/* [range(0,1024)] */
+ uint32_t *ids;/* [unique,size_is(count)] */
+};
+
+/* bitmap samr_GroupAttrs */
+#define SE_GROUP_MANDATORY ( 0x00000001 )
+#define SE_GROUP_ENABLED_BY_DEFAULT ( 0x00000002 )
+#define SE_GROUP_ENABLED ( 0x00000004 )
+#define SE_GROUP_OWNER ( 0x00000008 )
+#define SE_GROUP_USE_FOR_DENY_ONLY ( 0x00000010 )
+#define SE_GROUP_RESOURCE ( 0x20000000 )
+#define SE_GROUP_LOGON_ID ( 0xC0000000 )
+
+struct samr_GroupInfoAll {
+ struct lsa_String name;
+ uint32_t attributes;
+ uint32_t num_members;
+ struct lsa_String description;
+};
+
+struct samr_GroupInfoAttributes {
+ uint32_t attributes;
+};
+
+struct samr_GroupInfoDescription {
+ struct lsa_String description;
+};
+
+enum samr_GroupInfoEnum
+#ifndef USE_UINT_ENUMS
+ {
+ GROUPINFOALL=1,
+ GROUPINFONAME=2,
+ GROUPINFOATTRIBUTES=3,
+ GROUPINFODESCRIPTION=4,
+ GROUPINFOALL2=5
+}
+#else
+ { __donnot_use_enum_samr_GroupInfoEnum=0x7FFFFFFF}
+#define GROUPINFOALL ( 1 )
+#define GROUPINFONAME ( 2 )
+#define GROUPINFOATTRIBUTES ( 3 )
+#define GROUPINFODESCRIPTION ( 4 )
+#define GROUPINFOALL2 ( 5 )
+#endif
+;
+
+union samr_GroupInfo {
+ struct samr_GroupInfoAll all;/* [case(GROUPINFOALL)] */
+ struct lsa_String name;/* [case(GROUPINFONAME)] */
+ struct samr_GroupInfoAttributes attributes;/* [case(GROUPINFOATTRIBUTES)] */
+ struct lsa_String description;/* [case(GROUPINFODESCRIPTION)] */
+ struct samr_GroupInfoAll all2;/* [case(GROUPINFOALL2)] */
+}/* [switch_type(samr_GroupInfoEnum)] */;
+
+struct samr_RidTypeArray {
+ uint32_t count;
+ uint32_t *rids;/* [unique,size_is(count)] */
+ uint32_t *types;/* [unique,size_is(count)] */
+};
+
+struct samr_AliasInfoAll {
+ struct lsa_String name;
+ uint32_t num_members;
+ struct lsa_String description;
+};
+
+enum samr_AliasInfoEnum
+#ifndef USE_UINT_ENUMS
+ {
+ ALIASINFOALL=1,
+ ALIASINFONAME=2,
+ ALIASINFODESCRIPTION=3
+}
+#else
+ { __donnot_use_enum_samr_AliasInfoEnum=0x7FFFFFFF}
+#define ALIASINFOALL ( 1 )
+#define ALIASINFONAME ( 2 )
+#define ALIASINFODESCRIPTION ( 3 )
+#endif
+;
+
+union samr_AliasInfo {
+ struct samr_AliasInfoAll all;/* [case(ALIASINFOALL)] */
+ struct lsa_String name;/* [case(ALIASINFONAME)] */
+ struct lsa_String description;/* [case(ALIASINFODESCRIPTION)] */
+}/* [switch_type(samr_AliasInfoEnum)] */;
+
+struct samr_UserInfo1 {
+ struct lsa_String account_name;
+ struct lsa_String full_name;
+ uint32_t primary_gid;
+ struct lsa_String description;
+ struct lsa_String comment;
+};
+
+struct samr_UserInfo2 {
+ struct lsa_String comment;
+ struct lsa_String unknown;
+ uint16_t country_code;
+ uint16_t code_page;
+};
+
+struct samr_LogonHours {
+ uint16_t units_per_week;
+ uint8_t *bits;/* [unique,length_is(units_per_week/8),size_is(1260)] */
+}/* [public,flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+struct samr_UserInfo3 {
+ struct lsa_String account_name;
+ struct lsa_String full_name;
+ uint32_t rid;
+ uint32_t primary_gid;
+ struct lsa_String home_directory;
+ struct lsa_String home_drive;
+ struct lsa_String logon_script;
+ struct lsa_String profile_path;
+ struct lsa_String workstations;
+ NTTIME last_logon;
+ NTTIME last_logoff;
+ NTTIME last_password_change;
+ NTTIME allow_password_change;
+ NTTIME force_password_change;
+ struct samr_LogonHours logon_hours;
+ uint16_t bad_password_count;
+ uint16_t logon_count;
+ uint32_t acct_flags;
+};
+
+struct samr_UserInfo4 {
+ struct samr_LogonHours logon_hours;
+};
+
+struct samr_UserInfo5 {
+ struct lsa_String account_name;
+ struct lsa_String full_name;
+ uint32_t rid;
+ uint32_t primary_gid;
+ struct lsa_String home_directory;
+ struct lsa_String home_drive;
+ struct lsa_String logon_script;
+ struct lsa_String profile_path;
+ struct lsa_String description;
+ struct lsa_String workstations;
+ NTTIME last_logon;
+ NTTIME last_logoff;
+ struct samr_LogonHours logon_hours;
+ uint16_t bad_password_count;
+ uint16_t logon_count;
+ NTTIME last_password_change;
+ NTTIME acct_expiry;
+ uint32_t acct_flags;
+};
+
+struct samr_UserInfo6 {
+ struct lsa_String account_name;
+ struct lsa_String full_name;
+};
+
+struct samr_UserInfo7 {
+ struct lsa_String account_name;
+};
+
+struct samr_UserInfo8 {
+ struct lsa_String full_name;
+};
+
+struct samr_UserInfo9 {
+ uint32_t primary_gid;
+};
+
+struct samr_UserInfo10 {
+ struct lsa_String home_directory;
+ struct lsa_String home_drive;
+};
+
+struct samr_UserInfo11 {
+ struct lsa_String logon_script;
+};
+
+struct samr_UserInfo12 {
+ struct lsa_String profile_path;
+};
+
+struct samr_UserInfo13 {
+ struct lsa_String description;
+};
+
+struct samr_UserInfo14 {
+ struct lsa_String workstations;
+};
+
+struct samr_UserInfo16 {
+ uint32_t acct_flags;
+};
+
+struct samr_UserInfo17 {
+ NTTIME acct_expiry;
+};
+
+struct samr_Password {
+ uint8_t hash[16];
+}/* [public,flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+struct samr_UserInfo18 {
+ struct samr_Password lm_pwd;
+ struct samr_Password nt_pwd;
+ uint8_t lm_pwd_active;
+ uint8_t nt_pwd_active;
+};
+
+struct samr_UserInfo20 {
+ struct lsa_BinaryString parameters;
+};
+
+/* bitmap samr_FieldsPresent */
+#define SAMR_FIELD_ACCOUNT_NAME ( 0x00000001 )
+#define SAMR_FIELD_FULL_NAME ( 0x00000002 )
+#define SAMR_FIELD_RID ( 0x00000004 )
+#define SAMR_FIELD_PRIMARY_GID ( 0x00000008 )
+#define SAMR_FIELD_DESCRIPTION ( 0x00000010 )
+#define SAMR_FIELD_COMMENT ( 0x00000020 )
+#define SAMR_FIELD_HOME_DIRECTORY ( 0x00000040 )
+#define SAMR_FIELD_HOME_DRIVE ( 0x00000080 )
+#define SAMR_FIELD_LOGON_SCRIPT ( 0x00000100 )
+#define SAMR_FIELD_PROFILE_PATH ( 0x00000200 )
+#define SAMR_FIELD_WORKSTATIONS ( 0x00000400 )
+#define SAMR_FIELD_LAST_LOGON ( 0x00000800 )
+#define SAMR_FIELD_LAST_LOGOFF ( 0x00001000 )
+#define SAMR_FIELD_LOGON_HOURS ( 0x00002000 )
+#define SAMR_FIELD_BAD_PWD_COUNT ( 0x00004000 )
+#define SAMR_FIELD_NUM_LOGONS ( 0x00008000 )
+#define SAMR_FIELD_ALLOW_PWD_CHANGE ( 0x00010000 )
+#define SAMR_FIELD_FORCE_PWD_CHANGE ( 0x00020000 )
+#define SAMR_FIELD_LAST_PWD_CHANGE ( 0x00040000 )
+#define SAMR_FIELD_ACCT_EXPIRY ( 0x00080000 )
+#define SAMR_FIELD_ACCT_FLAGS ( 0x00100000 )
+#define SAMR_FIELD_PARAMETERS ( 0x00200000 )
+#define SAMR_FIELD_COUNTRY_CODE ( 0x00400000 )
+#define SAMR_FIELD_CODE_PAGE ( 0x00800000 )
+#define SAMR_FIELD_PASSWORD ( 0x01000000 )
+#define SAMR_FIELD_PASSWORD2 ( 0x02000000 )
+#define SAMR_FIELD_PRIVATE_DATA ( 0x04000000 )
+#define SAMR_FIELD_EXPIRED_FLAG ( 0x08000000 )
+#define SAMR_FIELD_SEC_DESC ( 0x10000000 )
+#define SAMR_FIELD_OWF_PWD ( 0x20000000 )
+
+struct samr_UserInfo21 {
+ NTTIME last_logon;
+ NTTIME last_logoff;
+ NTTIME last_password_change;
+ NTTIME acct_expiry;
+ NTTIME allow_password_change;
+ NTTIME force_password_change;
+ struct lsa_String account_name;
+ struct lsa_String full_name;
+ struct lsa_String home_directory;
+ struct lsa_String home_drive;
+ struct lsa_String logon_script;
+ struct lsa_String profile_path;
+ struct lsa_String description;
+ struct lsa_String workstations;
+ struct lsa_String comment;
+ struct lsa_BinaryString parameters;
+ struct lsa_String unknown1;
+ struct lsa_String unknown2;
+ struct lsa_String unknown3;
+ uint32_t buf_count;
+ uint8_t *buffer;/* [unique,size_is(buf_count)] */
+ uint32_t rid;
+ uint32_t primary_gid;
+ uint32_t acct_flags;
+ uint32_t fields_present;
+ struct samr_LogonHours logon_hours;
+ uint16_t bad_password_count;
+ uint16_t logon_count;
+ uint16_t country_code;
+ uint16_t code_page;
+ uint8_t nt_password_set;
+ uint8_t lm_password_set;
+ uint8_t password_expired;
+ uint8_t unknown4;
+};
+
+struct samr_CryptPassword {
+ uint8_t data[516];
+}/* [public,flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+struct samr_UserInfo23 {
+ struct samr_UserInfo21 info;
+ struct samr_CryptPassword password;
+};
+
+struct samr_UserInfo24 {
+ struct samr_CryptPassword password;
+ uint8_t pw_len;
+};
+
+struct samr_CryptPasswordEx {
+ uint8_t data[532];
+}/* [flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+struct samr_UserInfo25 {
+ struct samr_UserInfo21 info;
+ struct samr_CryptPasswordEx password;
+};
+
+struct samr_UserInfo26 {
+ struct samr_CryptPasswordEx password;
+ uint8_t pw_len;
+};
+
+union samr_UserInfo {
+ struct samr_UserInfo1 info1;/* [case] */
+ struct samr_UserInfo2 info2;/* [case(2)] */
+ struct samr_UserInfo3 info3;/* [case(3)] */
+ struct samr_UserInfo4 info4;/* [case(4)] */
+ struct samr_UserInfo5 info5;/* [case(5)] */
+ struct samr_UserInfo6 info6;/* [case(6)] */
+ struct samr_UserInfo7 info7;/* [case(7)] */
+ struct samr_UserInfo8 info8;/* [case(8)] */
+ struct samr_UserInfo9 info9;/* [case(9)] */
+ struct samr_UserInfo10 info10;/* [case(10)] */
+ struct samr_UserInfo11 info11;/* [case(11)] */
+ struct samr_UserInfo12 info12;/* [case(12)] */
+ struct samr_UserInfo13 info13;/* [case(13)] */
+ struct samr_UserInfo14 info14;/* [case(14)] */
+ struct samr_UserInfo16 info16;/* [case(16)] */
+ struct samr_UserInfo17 info17;/* [case(17)] */
+ struct samr_UserInfo18 info18;/* [case(18)] */
+ struct samr_UserInfo20 info20;/* [case(20)] */
+ struct samr_UserInfo21 info21;/* [case(21)] */
+ struct samr_UserInfo23 info23;/* [case(23)] */
+ struct samr_UserInfo24 info24;/* [case(24)] */
+ struct samr_UserInfo25 info25;/* [case(25)] */
+ struct samr_UserInfo26 info26;/* [case(26)] */
+}/* [switch_type(uint16)] */;
+
+struct samr_RidWithAttribute {
+ uint32_t rid;
+ uint32_t attributes;
+}/* [public] */;
+
+struct samr_RidWithAttributeArray {
+ uint32_t count;
+ struct samr_RidWithAttribute *rids;/* [unique,size_is(count)] */
+}/* [public] */;
+
+struct samr_DispEntryGeneral {
+ uint32_t idx;
+ uint32_t rid;
+ uint32_t acct_flags;
+ struct lsa_String account_name;
+ struct lsa_String description;
+ struct lsa_String full_name;
+};
+
+struct samr_DispInfoGeneral {
+ uint32_t count;
+ struct samr_DispEntryGeneral *entries;/* [unique,size_is(count)] */
+};
+
+struct samr_DispEntryFull {
+ uint32_t idx;
+ uint32_t rid;
+ uint32_t acct_flags;
+ struct lsa_String account_name;
+ struct lsa_String description;
+};
+
+struct samr_DispInfoFull {
+ uint32_t count;
+ struct samr_DispEntryFull *entries;/* [unique,size_is(count)] */
+};
+
+struct samr_DispEntryFullGroup {
+ uint32_t idx;
+ uint32_t rid;
+ uint32_t acct_flags;
+ struct lsa_String account_name;
+ struct lsa_String description;
+};
+
+struct samr_DispInfoFullGroups {
+ uint32_t count;
+ struct samr_DispEntryFullGroup *entries;/* [unique,size_is(count)] */
+};
+
+struct samr_DispEntryAscii {
+ uint32_t idx;
+ struct lsa_AsciiStringLarge account_name;
+};
+
+struct samr_DispInfoAscii {
+ uint32_t count;
+ struct samr_DispEntryAscii *entries;/* [unique,size_is(count)] */
+};
+
+union samr_DispInfo {
+ struct samr_DispInfoGeneral info1;/* [case] */
+ struct samr_DispInfoFull info2;/* [case(2)] */
+ struct samr_DispInfoFullGroups info3;/* [case(3)] */
+ struct samr_DispInfoAscii info4;/* [case(4)] */
+ struct samr_DispInfoAscii info5;/* [case(5)] */
+}/* [switch_type(uint16)] */;
+
+struct samr_PwInfo {
+ uint16_t min_password_length;
+ uint32_t password_properties;
+};
+
+enum samr_ConnectVersion
+#ifndef USE_UINT_ENUMS
+ {
+ SAMR_CONNECT_PRE_W2K=1,
+ SAMR_CONNECT_W2K=2,
+ SAMR_CONNECT_AFTER_W2K=3
+}
+#else
+ { __donnot_use_enum_samr_ConnectVersion=0x7FFFFFFF}
+#define SAMR_CONNECT_PRE_W2K ( 1 )
+#define SAMR_CONNECT_W2K ( 2 )
+#define SAMR_CONNECT_AFTER_W2K ( 3 )
+#endif
+;
+
+enum samr_RejectReason;
+
+struct samr_ChangeReject {
+ enum samr_RejectReason reason;
+ uint32_t unknown1;
+ uint32_t unknown2;
+};
+
+struct samr_ConnectInfo1 {
+ enum samr_ConnectVersion client_version;
+ uint32_t unknown2;
+};
+
+union samr_ConnectInfo {
+ struct samr_ConnectInfo1 info1;/* [case] */
+};
+
+/* bitmap samr_ValidateFieldsPresent */
+#define SAMR_VALIDATE_FIELD_PASSWORD_LAST_SET ( 0x00000001 )
+#define SAMR_VALIDATE_FIELD_BAD_PASSWORD_TIME ( 0x00000002 )
+#define SAMR_VALIDATE_FIELD_LOCKOUT_TIME ( 0x00000004 )
+#define SAMR_VALIDATE_FIELD_BAD_PASSWORD_COUNT ( 0x00000008 )
+#define SAMR_VALIDATE_FIELD_PASSWORD_HISTORY_LENGTH ( 0x00000010 )
+#define SAMR_VALIDATE_FIELD_PASSWORD_HISTORY ( 0x00000020 )
+
+enum samr_ValidatePasswordLevel
+#ifndef USE_UINT_ENUMS
+ {
+ NetValidateAuthentication=1,
+ NetValidatePasswordChange=2,
+ NetValidatePasswordReset=3
+}
+#else
+ { __donnot_use_enum_samr_ValidatePasswordLevel=0x7FFFFFFF}
+#define NetValidateAuthentication ( 1 )
+#define NetValidatePasswordChange ( 2 )
+#define NetValidatePasswordReset ( 3 )
+#endif
+;
+
+enum samr_ValidationStatus
+#ifndef USE_UINT_ENUMS
+ {
+ SAMR_VALIDATION_STATUS_SUCCESS=0,
+ SAMR_VALIDATION_STATUS_PASSWORD_MUST_CHANGE=1,
+ SAMR_VALIDATION_STATUS_ACCOUNT_LOCKED_OUT=2,
+ SAMR_VALIDATION_STATUS_BAD_PASSWORD=4,
+ SAMR_VALIDATION_STATUS_PWD_HISTORY_CONFLICT=5,
+ SAMR_VALIDATION_STATUS_PWD_TOO_SHORT=6,
+ SAMR_VALIDATION_STATUS_PWD_TOO_LONG=7,
+ SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH=8,
+ SAMR_VALIDATION_STATUS_PASSWORD_TOO_RECENT=9
+}
+#else
+ { __donnot_use_enum_samr_ValidationStatus=0x7FFFFFFF}
+#define SAMR_VALIDATION_STATUS_SUCCESS ( 0 )
+#define SAMR_VALIDATION_STATUS_PASSWORD_MUST_CHANGE ( 1 )
+#define SAMR_VALIDATION_STATUS_ACCOUNT_LOCKED_OUT ( 2 )
+#define SAMR_VALIDATION_STATUS_BAD_PASSWORD ( 4 )
+#define SAMR_VALIDATION_STATUS_PWD_HISTORY_CONFLICT ( 5 )
+#define SAMR_VALIDATION_STATUS_PWD_TOO_SHORT ( 6 )
+#define SAMR_VALIDATION_STATUS_PWD_TOO_LONG ( 7 )
+#define SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH ( 8 )
+#define SAMR_VALIDATION_STATUS_PASSWORD_TOO_RECENT ( 9 )
+#endif
+;
+
+struct samr_ValidationBlob {
+ uint32_t length;
+ uint8_t *data;/* [unique,size_is(length)] */
+};
+
+struct samr_ValidatePasswordInfo {
+ uint32_t fields_present;
+ NTTIME last_password_change;
+ NTTIME bad_password_time;
+ NTTIME lockout_time;
+ uint32_t bad_pwd_count;
+ uint32_t pwd_history_len;
+ struct samr_ValidationBlob *pwd_history;/* [unique,size_is(pwd_history_len)] */
+};
+
+struct samr_ValidatePasswordRepCtr {
+ struct samr_ValidatePasswordInfo info;
+ enum samr_ValidationStatus status;
+};
+
+union samr_ValidatePasswordRep {
+ struct samr_ValidatePasswordRepCtr ctr1;/* [case] */
+ struct samr_ValidatePasswordRepCtr ctr2;/* [case(2)] */
+ struct samr_ValidatePasswordRepCtr ctr3;/* [case(3)] */
+}/* [switch_type(uint16)] */;
+
+struct samr_ValidatePasswordReq3 {
+ struct samr_ValidatePasswordInfo info;
+ struct lsa_StringLarge password;
+ struct lsa_StringLarge account;
+ struct samr_ValidationBlob hash;
+ uint8_t pwd_must_change_at_next_logon;
+ uint8_t clear_lockout;
+};
+
+struct samr_ValidatePasswordReq2 {
+ struct samr_ValidatePasswordInfo info;
+ struct lsa_StringLarge password;
+ struct lsa_StringLarge account;
+ struct samr_ValidationBlob hash;
+ uint8_t password_matched;
+};
+
+struct samr_ValidatePasswordReq1 {
+ struct samr_ValidatePasswordInfo info;
+ uint8_t password_matched;
+};
+
+union samr_ValidatePasswordReq {
+ struct samr_ValidatePasswordReq1 req1;/* [case] */
+ struct samr_ValidatePasswordReq2 req2;/* [case(2)] */
+ struct samr_ValidatePasswordReq3 req3;/* [case(3)] */
+}/* [switch_type(uint16)] */;
+
+
+struct samr_Connect {
+ struct {
+ uint16_t *system_name;/* [unique] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *connect_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_Close {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_SetSecurity {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t sec_info;
+ struct sec_desc_buf *sdbuf;/* [ref] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_QuerySecurity {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t sec_info;
+ } in;
+
+ struct {
+ struct sec_desc_buf **sdbuf;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_Shutdown {
+ struct {
+ struct policy_handle *connect_handle;/* [ref] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_LookupDomain {
+ struct {
+ struct policy_handle *connect_handle;/* [ref] */
+ struct lsa_String *domain_name;/* [ref] */
+ } in;
+
+ struct {
+ struct dom_sid2 **sid;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_EnumDomains {
+ struct {
+ struct policy_handle *connect_handle;/* [ref] */
+ uint32_t buf_size;
+ uint32_t *resume_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct samr_SamArray **sam;/* [ref] */
+ uint32_t *num_entries;/* [ref] */
+ uint32_t *resume_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_OpenDomain {
+ struct {
+ struct policy_handle *connect_handle;/* [ref] */
+ uint32_t access_mask;
+ struct dom_sid2 *sid;/* [ref] */
+ } in;
+
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_QueryDomainInfo {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint16_t level;
+ } in;
+
+ struct {
+ union samr_DomainInfo **info;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_SetDomainInfo {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint16_t level;
+ union samr_DomainInfo *info;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_CreateDomainGroup {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ struct lsa_String *name;/* [ref] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *group_handle;/* [ref] */
+ uint32_t *rid;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_EnumDomainGroups {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint32_t max_size;
+ uint32_t *resume_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct samr_SamArray **sam;/* [ref] */
+ uint32_t *num_entries;/* [ref] */
+ uint32_t *resume_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_CreateUser {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ struct lsa_String *account_name;/* [ref] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *user_handle;/* [ref] */
+ uint32_t *rid;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_EnumDomainUsers {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint32_t acct_flags;
+ uint32_t max_size;
+ uint32_t *resume_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct samr_SamArray **sam;/* [ref] */
+ uint32_t *num_entries;/* [ref] */
+ uint32_t *resume_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_CreateDomAlias {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ struct lsa_String *alias_name;/* [ref] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *alias_handle;/* [ref] */
+ uint32_t *rid;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_EnumDomainAliases {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint32_t max_size;
+ uint32_t *resume_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct samr_SamArray **sam;/* [ref] */
+ uint32_t *num_entries;/* [ref] */
+ uint32_t *resume_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_GetAliasMembership {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ struct lsa_SidArray *sids;/* [ref] */
+ } in;
+
+ struct {
+ struct samr_Ids *rids;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_LookupNames {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint32_t num_names;/* [range(0,1000)] */
+ struct lsa_String *names;/* [length_is(num_names),size_is(1000)] */
+ } in;
+
+ struct {
+ struct samr_Ids *rids;/* [ref] */
+ struct samr_Ids *types;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_LookupRids {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint32_t num_rids;/* [range(0,1000)] */
+ uint32_t *rids;/* [length_is(num_rids),size_is(1000)] */
+ } in;
+
+ struct {
+ struct lsa_Strings *names;/* [ref] */
+ struct samr_Ids *types;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_OpenGroup {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint32_t access_mask;
+ uint32_t rid;
+ } in;
+
+ struct {
+ struct policy_handle *group_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_QueryGroupInfo {
+ struct {
+ struct policy_handle *group_handle;/* [ref] */
+ enum samr_GroupInfoEnum level;
+ } in;
+
+ struct {
+ union samr_GroupInfo **info;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_SetGroupInfo {
+ struct {
+ struct policy_handle *group_handle;/* [ref] */
+ enum samr_GroupInfoEnum level;
+ union samr_GroupInfo *info;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_AddGroupMember {
+ struct {
+ struct policy_handle *group_handle;/* [ref] */
+ uint32_t rid;
+ uint32_t flags;
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_DeleteDomainGroup {
+ struct {
+ struct policy_handle *group_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct policy_handle *group_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_DeleteGroupMember {
+ struct {
+ struct policy_handle *group_handle;/* [ref] */
+ uint32_t rid;
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_QueryGroupMember {
+ struct {
+ struct policy_handle *group_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct samr_RidTypeArray **rids;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_SetMemberAttributesOfGroup {
+ struct {
+ struct policy_handle *group_handle;/* [ref] */
+ uint32_t unknown1;
+ uint32_t unknown2;
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_OpenAlias {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint32_t access_mask;
+ uint32_t rid;
+ } in;
+
+ struct {
+ struct policy_handle *alias_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_QueryAliasInfo {
+ struct {
+ struct policy_handle *alias_handle;/* [ref] */
+ enum samr_AliasInfoEnum level;
+ } in;
+
+ struct {
+ union samr_AliasInfo **info;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_SetAliasInfo {
+ struct {
+ struct policy_handle *alias_handle;/* [ref] */
+ enum samr_AliasInfoEnum level;
+ union samr_AliasInfo *info;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_DeleteDomAlias {
+ struct {
+ struct policy_handle *alias_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct policy_handle *alias_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_AddAliasMember {
+ struct {
+ struct policy_handle *alias_handle;/* [ref] */
+ struct dom_sid2 *sid;/* [ref] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_DeleteAliasMember {
+ struct {
+ struct policy_handle *alias_handle;/* [ref] */
+ struct dom_sid2 *sid;/* [ref] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_GetMembersInAlias {
+ struct {
+ struct policy_handle *alias_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct lsa_SidArray *sids;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_OpenUser {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint32_t access_mask;
+ uint32_t rid;
+ } in;
+
+ struct {
+ struct policy_handle *user_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_DeleteUser {
+ struct {
+ struct policy_handle *user_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct policy_handle *user_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_QueryUserInfo {
+ struct {
+ struct policy_handle *user_handle;/* [ref] */
+ uint16_t level;
+ } in;
+
+ struct {
+ union samr_UserInfo **info;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_SetUserInfo {
+ struct {
+ struct policy_handle *user_handle;/* [ref] */
+ uint16_t level;
+ union samr_UserInfo *info;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_ChangePasswordUser {
+ struct {
+ struct policy_handle *user_handle;/* [ref] */
+ uint8_t lm_present;
+ struct samr_Password *old_lm_crypted;/* [unique] */
+ struct samr_Password *new_lm_crypted;/* [unique] */
+ uint8_t nt_present;
+ struct samr_Password *old_nt_crypted;/* [unique] */
+ struct samr_Password *new_nt_crypted;/* [unique] */
+ uint8_t cross1_present;
+ struct samr_Password *nt_cross;/* [unique] */
+ uint8_t cross2_present;
+ struct samr_Password *lm_cross;/* [unique] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_GetGroupsForUser {
+ struct {
+ struct policy_handle *user_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct samr_RidWithAttributeArray **rids;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_QueryDisplayInfo {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint16_t level;
+ uint32_t start_idx;
+ uint32_t max_entries;
+ uint32_t buf_size;
+ } in;
+
+ struct {
+ uint32_t *total_size;/* [ref] */
+ uint32_t *returned_size;/* [ref] */
+ union samr_DispInfo *info;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_GetDisplayEnumerationIndex {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint16_t level;
+ struct lsa_String *name;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *idx;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_TestPrivateFunctionsDomain {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_TestPrivateFunctionsUser {
+ struct {
+ struct policy_handle *user_handle;/* [ref] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_GetUserPwInfo {
+ struct {
+ struct policy_handle *user_handle;/* [ref] */
+ } in;
+
+ struct {
+ struct samr_PwInfo *info;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_RemoveMemberFromForeignDomain {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ struct dom_sid2 *sid;/* [ref] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_QueryDomainInfo2 {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint16_t level;
+ } in;
+
+ struct {
+ union samr_DomainInfo **info;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_QueryUserInfo2 {
+ struct {
+ struct policy_handle *user_handle;/* [ref] */
+ uint16_t level;
+ } in;
+
+ struct {
+ union samr_UserInfo *info;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_QueryDisplayInfo2 {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint16_t level;
+ uint32_t start_idx;
+ uint32_t max_entries;
+ uint32_t buf_size;
+ } in;
+
+ struct {
+ uint32_t *total_size;/* [ref] */
+ uint32_t *returned_size;/* [ref] */
+ union samr_DispInfo *info;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_GetDisplayEnumerationIndex2 {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint16_t level;
+ struct lsa_String *name;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *idx;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_CreateUser2 {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ struct lsa_String *account_name;/* [ref] */
+ uint32_t acct_flags;
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *user_handle;/* [ref] */
+ uint32_t *access_granted;/* [ref] */
+ uint32_t *rid;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_QueryDisplayInfo3 {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint16_t level;
+ uint32_t start_idx;
+ uint32_t max_entries;
+ uint32_t buf_size;
+ } in;
+
+ struct {
+ uint32_t *total_size;/* [ref] */
+ uint32_t *returned_size;/* [ref] */
+ union samr_DispInfo *info;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_AddMultipleMembersToAlias {
+ struct {
+ struct policy_handle *alias_handle;/* [ref] */
+ struct lsa_SidArray *sids;/* [ref] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_RemoveMultipleMembersFromAlias {
+ struct {
+ struct policy_handle *alias_handle;/* [ref] */
+ struct lsa_SidArray *sids;/* [ref] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_OemChangePasswordUser2 {
+ struct {
+ struct lsa_AsciiString *server;/* [unique] */
+ struct lsa_AsciiString *account;/* [ref] */
+ struct samr_CryptPassword *password;/* [unique] */
+ struct samr_Password *hash;/* [unique] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_ChangePasswordUser2 {
+ struct {
+ struct lsa_String *server;/* [unique] */
+ struct lsa_String *account;/* [ref] */
+ struct samr_CryptPassword *nt_password;/* [unique] */
+ struct samr_Password *nt_verifier;/* [unique] */
+ uint8_t lm_change;
+ struct samr_CryptPassword *lm_password;/* [unique] */
+ struct samr_Password *lm_verifier;/* [unique] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_GetDomPwInfo {
+ struct {
+ struct lsa_String *domain_name;/* [unique] */
+ } in;
+
+ struct {
+ struct samr_PwInfo *info;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_Connect2 {
+ struct {
+ const char *system_name;/* [unique,charset(UTF16)] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *connect_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_SetUserInfo2 {
+ struct {
+ struct policy_handle *user_handle;/* [ref] */
+ uint16_t level;
+ union samr_UserInfo *info;/* [ref,switch_is(level)] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_SetBootKeyInformation {
+ struct {
+ struct policy_handle *connect_handle;/* [ref] */
+ uint32_t unknown1;
+ uint32_t unknown2;
+ uint32_t unknown3;
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_GetBootKeyInformation {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *unknown;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_Connect3 {
+ struct {
+ const char *system_name;/* [unique,charset(UTF16)] */
+ uint32_t unknown;
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *connect_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_Connect4 {
+ struct {
+ const char *system_name;/* [unique,charset(UTF16)] */
+ enum samr_ConnectVersion client_version;
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *connect_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_ChangePasswordUser3 {
+ struct {
+ struct lsa_String *server;/* [unique] */
+ struct lsa_String *account;/* [ref] */
+ struct samr_CryptPassword *nt_password;/* [unique] */
+ struct samr_Password *nt_verifier;/* [unique] */
+ uint8_t lm_change;
+ struct samr_CryptPassword *lm_password;/* [unique] */
+ struct samr_Password *lm_verifier;/* [unique] */
+ struct samr_CryptPassword *password3;/* [unique] */
+ } in;
+
+ struct {
+ struct samr_DomInfo1 **dominfo;/* [ref] */
+ struct samr_ChangeReject **reject;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_Connect5 {
+ struct {
+ const char *system_name;/* [unique,charset(UTF16)] */
+ uint32_t access_mask;
+ uint32_t level_in;
+ union samr_ConnectInfo *info_in;/* [ref,switch_is(level_in)] */
+ } in;
+
+ struct {
+ uint32_t *level_out;/* [ref] */
+ union samr_ConnectInfo *info_out;/* [ref,switch_is(*level_out)] */
+ struct policy_handle *connect_handle;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_RidToSid {
+ struct {
+ struct policy_handle *domain_handle;/* [ref] */
+ uint32_t rid;
+ } in;
+
+ struct {
+ struct dom_sid2 *sid;/* [ref] */
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_SetDsrmPassword {
+ struct {
+ struct lsa_String *name;/* [unique] */
+ uint32_t unknown;
+ struct samr_Password *hash;/* [unique] */
+ } in;
+
+ struct {
+ NTSTATUS result;
+ } out;
+
+};
+
+
+struct samr_ValidatePassword {
+ struct {
+ enum samr_ValidatePasswordLevel level;
+ union samr_ValidatePasswordReq req;/* [switch_is(level)] */
+ } in;
+
+ struct {
+ union samr_ValidatePasswordRep *rep;/* [ref,switch_is(level)] */
+ NTSTATUS result;
+ } out;
+
+};
+
+#endif /* _HEADER_samr */
diff --git a/source3/librpc/gen_ndr/security.h b/source3/librpc/gen_ndr/security.h
new file mode 100644
index 0000000000..04655b178e
--- /dev/null
+++ b/source3/librpc/gen_ndr/security.h
@@ -0,0 +1,327 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#include "librpc/gen_ndr/misc.h"
+#define dom_sid2 dom_sid
+#define dom_sid28 dom_sid
+#define dom_sid0 dom_sid
+#ifndef _HEADER_security
+#define _HEADER_security
+
+#define SEC_MASK_GENERIC ( 0xF0000000 )
+#define SEC_MASK_FLAGS ( 0x0F000000 )
+#define SEC_MASK_STANDARD ( 0x00FF0000 )
+#define SEC_MASK_SPECIFIC ( 0x0000FFFF )
+#define SEC_GENERIC_ALL ( 0x10000000 )
+#define SEC_GENERIC_EXECUTE ( 0x20000000 )
+#define SEC_GENERIC_WRITE ( 0x40000000 )
+#define SEC_GENERIC_READ ( 0x80000000 )
+#define SEC_FLAG_SYSTEM_SECURITY ( 0x01000000 )
+#define SEC_FLAG_MAXIMUM_ALLOWED ( 0x02000000 )
+#define SEC_STD_DELETE ( 0x00010000 )
+#define SEC_STD_READ_CONTROL ( 0x00020000 )
+#define SEC_STD_WRITE_DAC ( 0x00040000 )
+#define SEC_STD_WRITE_OWNER ( 0x00080000 )
+#define SEC_STD_SYNCHRONIZE ( 0x00100000 )
+#define SEC_STD_REQUIRED ( 0x000F0000 )
+#define SEC_STD_ALL ( 0x001F0000 )
+#define SEC_FILE_READ_DATA ( 0x00000001 )
+#define SEC_FILE_WRITE_DATA ( 0x00000002 )
+#define SEC_FILE_APPEND_DATA ( 0x00000004 )
+#define SEC_FILE_READ_EA ( 0x00000008 )
+#define SEC_FILE_WRITE_EA ( 0x00000010 )
+#define SEC_FILE_EXECUTE ( 0x00000020 )
+#define SEC_FILE_READ_ATTRIBUTE ( 0x00000080 )
+#define SEC_FILE_WRITE_ATTRIBUTE ( 0x00000100 )
+#define SEC_FILE_ALL ( 0x000001ff )
+#define SEC_DIR_LIST ( 0x00000001 )
+#define SEC_DIR_ADD_FILE ( 0x00000002 )
+#define SEC_DIR_ADD_SUBDIR ( 0x00000004 )
+#define SEC_DIR_READ_EA ( 0x00000008 )
+#define SEC_DIR_WRITE_EA ( 0x00000010 )
+#define SEC_DIR_TRAVERSE ( 0x00000020 )
+#define SEC_DIR_DELETE_CHILD ( 0x00000040 )
+#define SEC_DIR_READ_ATTRIBUTE ( 0x00000080 )
+#define SEC_DIR_WRITE_ATTRIBUTE ( 0x00000100 )
+#define SEC_REG_QUERY_VALUE ( 0x00000001 )
+#define SEC_REG_SET_VALUE ( 0x00000002 )
+#define SEC_REG_CREATE_SUBKEY ( 0x00000004 )
+#define SEC_REG_ENUM_SUBKEYS ( 0x00000008 )
+#define SEC_REG_NOTIFY ( 0x00000010 )
+#define SEC_REG_CREATE_LINK ( 0x00000020 )
+#define SEC_ADS_CREATE_CHILD ( 0x00000001 )
+#define SEC_ADS_DELETE_CHILD ( 0x00000002 )
+#define SEC_ADS_LIST ( 0x00000004 )
+#define SEC_ADS_SELF_WRITE ( 0x00000008 )
+#define SEC_ADS_READ_PROP ( 0x00000010 )
+#define SEC_ADS_WRITE_PROP ( 0x00000020 )
+#define SEC_ADS_DELETE_TREE ( 0x00000040 )
+#define SEC_ADS_LIST_OBJECT ( 0x00000080 )
+#define SEC_ADS_CONTROL_ACCESS ( 0x00000100 )
+#define SEC_RIGHTS_FILE_READ ( SEC_STD_READ_CONTROL|SEC_STD_SYNCHRONIZE|SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE|SEC_FILE_READ_EA )
+#define SEC_RIGHTS_FILE_WRITE ( SEC_STD_READ_CONTROL|SEC_STD_SYNCHRONIZE|SEC_FILE_WRITE_DATA|SEC_FILE_WRITE_ATTRIBUTE|SEC_FILE_WRITE_EA|SEC_FILE_APPEND_DATA )
+#define SEC_RIGHTS_FILE_EXECUTE ( SEC_STD_SYNCHRONIZE|SEC_STD_READ_CONTROL|SEC_FILE_READ_ATTRIBUTE|SEC_FILE_EXECUTE )
+#define SEC_RIGHTS_FILE_ALL ( SEC_STD_ALL|SEC_FILE_ALL )
+#define SEC_RIGHTS_DIR_READ ( SEC_RIGHTS_FILE_READ )
+#define SEC_RIGHTS_DIR_WRITE ( SEC_RIGHTS_FILE_WRITE )
+#define SEC_RIGHTS_DIR_EXECUTE ( SEC_RIGHTS_FILE_EXECUTE )
+#define SEC_RIGHTS_DIR_ALL ( SEC_RIGHTS_FILE_ALL )
+#define SID_NULL ( "S-1-0-0" )
+#define NAME_WORLD ( "WORLD" )
+#define SID_WORLD_DOMAIN ( "S-1-1" )
+#define SID_WORLD ( "S-1-1-0" )
+#define SID_CREATOR_OWNER_DOMAIN ( "S-1-3" )
+#define SID_CREATOR_OWNER ( "S-1-3-0" )
+#define SID_CREATOR_GROUP ( "S-1-3-1" )
+#define NAME_NT_AUTHORITY ( "NT AUTHORITY" )
+#define SID_NT_AUTHORITY ( "S-1-5" )
+#define SID_NT_DIALUP ( "S-1-5-1" )
+#define SID_NT_NETWORK ( "S-1-5-2" )
+#define SID_NT_BATCH ( "S-1-5-3" )
+#define SID_NT_INTERACTIVE ( "S-1-5-4" )
+#define SID_NT_SERVICE ( "S-1-5-6" )
+#define SID_NT_ANONYMOUS ( "S-1-5-7" )
+#define SID_NT_PROXY ( "S-1-5-8" )
+#define SID_NT_ENTERPRISE_DCS ( "S-1-5-9" )
+#define SID_NT_SELF ( "S-1-5-10" )
+#define SID_NT_AUTHENTICATED_USERS ( "S-1-5-11" )
+#define SID_NT_RESTRICTED ( "S-1-5-12" )
+#define SID_NT_TERMINAL_SERVER_USERS ( "S-1-5-13" )
+#define SID_NT_REMOTE_INTERACTIVE ( "S-1-5-14" )
+#define SID_NT_THIS_ORGANISATION ( "S-1-5-15" )
+#define SID_NT_SYSTEM ( "S-1-5-18" )
+#define SID_NT_LOCAL_SERVICE ( "S-1-5-19" )
+#define SID_NT_NETWORK_SERVICE ( "S-1-5-20" )
+#define NAME_BUILTIN ( "BUILTIN" )
+#define SID_BUILTIN ( "S-1-5-32" )
+#define SID_BUILTIN_ADMINISTRATORS ( "S-1-5-32-544" )
+#define SID_BUILTIN_USERS ( "S-1-5-32-545" )
+#define SID_BUILTIN_GUESTS ( "S-1-5-32-546" )
+#define SID_BUILTIN_POWER_USERS ( "S-1-5-32-547" )
+#define SID_BUILTIN_ACCOUNT_OPERATORS ( "S-1-5-32-548" )
+#define SID_BUILTIN_SERVER_OPERATORS ( "S-1-5-32-549" )
+#define SID_BUILTIN_PRINT_OPERATORS ( "S-1-5-32-550" )
+#define SID_BUILTIN_BACKUP_OPERATORS ( "S-1-5-32-551" )
+#define SID_BUILTIN_REPLICATOR ( "S-1-5-32-552" )
+#define SID_BUILTIN_RAS_SERVERS ( "S-1-5-32-553" )
+#define SID_BUILTIN_PREW2K ( "S-1-5-32-554" )
+#define DOMAIN_RID_LOGON ( 9 )
+#define DOMAIN_RID_ADMINISTRATOR ( 500 )
+#define DOMAIN_RID_GUEST ( 501 )
+#define DOMAIN_RID_ADMINS ( 512 )
+#define DOMAIN_RID_USERS ( 513 )
+#define DOMAIN_RID_DOMAIN_MEMBERS ( 515 )
+#define DOMAIN_RID_DCS ( 516 )
+#define DOMAIN_RID_CERT_ADMINS ( 517 )
+#define DOMAIN_RID_SCHEMA_ADMINS ( 518 )
+#define DOMAIN_RID_ENTERPRISE_ADMINS ( 519 )
+#define NT4_ACL_REVISION ( SECURITY_ACL_REVISION_NT4 )
+#define SD_REVISION ( SECURITY_DESCRIPTOR_REVISION_1 )
+enum sec_privilege
+#ifndef USE_UINT_ENUMS
+ {
+ SEC_PRIV_SECURITY=1,
+ SEC_PRIV_BACKUP=2,
+ SEC_PRIV_RESTORE=3,
+ SEC_PRIV_SYSTEMTIME=4,
+ SEC_PRIV_SHUTDOWN=5,
+ SEC_PRIV_REMOTE_SHUTDOWN=6,
+ SEC_PRIV_TAKE_OWNERSHIP=7,
+ SEC_PRIV_DEBUG=8,
+ SEC_PRIV_SYSTEM_ENVIRONMENT=9,
+ SEC_PRIV_SYSTEM_PROFILE=10,
+ SEC_PRIV_PROFILE_SINGLE_PROCESS=11,
+ SEC_PRIV_INCREASE_BASE_PRIORITY=12,
+ SEC_PRIV_LOAD_DRIVER=13,
+ SEC_PRIV_CREATE_PAGEFILE=14,
+ SEC_PRIV_INCREASE_QUOTA=15,
+ SEC_PRIV_CHANGE_NOTIFY=16,
+ SEC_PRIV_UNDOCK=17,
+ SEC_PRIV_MANAGE_VOLUME=18,
+ SEC_PRIV_IMPERSONATE=19,
+ SEC_PRIV_CREATE_GLOBAL=20,
+ SEC_PRIV_ENABLE_DELEGATION=21,
+ SEC_PRIV_INTERACTIVE_LOGON=22,
+ SEC_PRIV_NETWORK_LOGON=23,
+ SEC_PRIV_REMOTE_INTERACTIVE_LOGON=24
+}
+#else
+ { __donnot_use_enum_sec_privilege=0x7FFFFFFF}
+#define SEC_PRIV_SECURITY ( 1 )
+#define SEC_PRIV_BACKUP ( 2 )
+#define SEC_PRIV_RESTORE ( 3 )
+#define SEC_PRIV_SYSTEMTIME ( 4 )
+#define SEC_PRIV_SHUTDOWN ( 5 )
+#define SEC_PRIV_REMOTE_SHUTDOWN ( 6 )
+#define SEC_PRIV_TAKE_OWNERSHIP ( 7 )
+#define SEC_PRIV_DEBUG ( 8 )
+#define SEC_PRIV_SYSTEM_ENVIRONMENT ( 9 )
+#define SEC_PRIV_SYSTEM_PROFILE ( 10 )
+#define SEC_PRIV_PROFILE_SINGLE_PROCESS ( 11 )
+#define SEC_PRIV_INCREASE_BASE_PRIORITY ( 12 )
+#define SEC_PRIV_LOAD_DRIVER ( 13 )
+#define SEC_PRIV_CREATE_PAGEFILE ( 14 )
+#define SEC_PRIV_INCREASE_QUOTA ( 15 )
+#define SEC_PRIV_CHANGE_NOTIFY ( 16 )
+#define SEC_PRIV_UNDOCK ( 17 )
+#define SEC_PRIV_MANAGE_VOLUME ( 18 )
+#define SEC_PRIV_IMPERSONATE ( 19 )
+#define SEC_PRIV_CREATE_GLOBAL ( 20 )
+#define SEC_PRIV_ENABLE_DELEGATION ( 21 )
+#define SEC_PRIV_INTERACTIVE_LOGON ( 22 )
+#define SEC_PRIV_NETWORK_LOGON ( 23 )
+#define SEC_PRIV_REMOTE_INTERACTIVE_LOGON ( 24 )
+#endif
+;
+
+/* bitmap security_ace_flags */
+#define SEC_ACE_FLAG_OBJECT_INHERIT ( 0x01 )
+#define SEC_ACE_FLAG_CONTAINER_INHERIT ( 0x02 )
+#define SEC_ACE_FLAG_NO_PROPAGATE_INHERIT ( 0x04 )
+#define SEC_ACE_FLAG_INHERIT_ONLY ( 0x08 )
+#define SEC_ACE_FLAG_INHERITED_ACE ( 0x10 )
+#define SEC_ACE_FLAG_VALID_INHERIT ( 0x0f )
+#define SEC_ACE_FLAG_SUCCESSFUL_ACCESS ( 0x40 )
+#define SEC_ACE_FLAG_FAILED_ACCESS ( 0x80 )
+
+enum security_ace_type
+#ifndef USE_UINT_ENUMS
+ {
+ SEC_ACE_TYPE_ACCESS_ALLOWED=0,
+ SEC_ACE_TYPE_ACCESS_DENIED=1,
+ SEC_ACE_TYPE_SYSTEM_AUDIT=2,
+ SEC_ACE_TYPE_SYSTEM_ALARM=3,
+ SEC_ACE_TYPE_ALLOWED_COMPOUND=4,
+ SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT=5,
+ SEC_ACE_TYPE_ACCESS_DENIED_OBJECT=6,
+ SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT=7,
+ SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT=8
+}
+#else
+ { __donnot_use_enum_security_ace_type=0x7FFFFFFF}
+#define SEC_ACE_TYPE_ACCESS_ALLOWED ( 0 )
+#define SEC_ACE_TYPE_ACCESS_DENIED ( 1 )
+#define SEC_ACE_TYPE_SYSTEM_AUDIT ( 2 )
+#define SEC_ACE_TYPE_SYSTEM_ALARM ( 3 )
+#define SEC_ACE_TYPE_ALLOWED_COMPOUND ( 4 )
+#define SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ( 5 )
+#define SEC_ACE_TYPE_ACCESS_DENIED_OBJECT ( 6 )
+#define SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT ( 7 )
+#define SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT ( 8 )
+#endif
+;
+
+/* bitmap security_ace_object_flags */
+#define SEC_ACE_OBJECT_TYPE_PRESENT ( 0x00000001 )
+#define SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT ( 0x00000002 )
+
+union security_ace_object_type {
+ struct GUID type;/* [case(SEC_ACE_OBJECT_TYPE_PRESENT)] */
+}/* [nodiscriminant] */;
+
+union security_ace_object_inherited_type {
+ struct GUID inherited_type;/* [case(SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT)] */
+}/* [nodiscriminant] */;
+
+struct security_ace_object {
+ uint32_t flags;
+ union security_ace_object_type type;/* [switch_is(flags&SEC_ACE_OBJECT_TYPE_PRESENT)] */
+ union security_ace_object_inherited_type inherited_type;/* [switch_is(flags&SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT)] */
+};
+
+union security_ace_object_ctr {
+ struct security_ace_object object;/* [case(SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT)] */
+}/* [nodiscriminant] */;
+
+struct security_ace {
+ enum security_ace_type type;
+ uint8_t flags;
+ uint16_t size;/* [value(ndr_size_security_ace(r,ndr->flags))] */
+ uint32_t access_mask;
+ union security_ace_object_ctr object;/* [switch_is(type)] */
+ struct dom_sid trustee;
+}/* [gensize,public,nosize] */;
+
+enum security_acl_revision
+#ifndef USE_UINT_ENUMS
+ {
+ SECURITY_ACL_REVISION_NT4=2,
+ SECURITY_ACL_REVISION_ADS=4
+}
+#else
+ { __donnot_use_enum_security_acl_revision=0x7FFFFFFF}
+#define SECURITY_ACL_REVISION_NT4 ( 2 )
+#define SECURITY_ACL_REVISION_ADS ( 4 )
+#endif
+;
+
+struct security_acl {
+ enum security_acl_revision revision;
+ uint16_t size;/* [value(ndr_size_security_acl(r,ndr->flags))] */
+ uint32_t num_aces;/* [range(0,1000)] */
+ struct security_ace *aces;
+}/* [gensize,public,nosize] */;
+
+enum security_descriptor_revision
+#ifndef USE_UINT_ENUMS
+ {
+ SECURITY_DESCRIPTOR_REVISION_1=1
+}
+#else
+ { __donnot_use_enum_security_descriptor_revision=0x7FFFFFFF}
+#define SECURITY_DESCRIPTOR_REVISION_1 ( 1 )
+#endif
+;
+
+/* bitmap security_descriptor_type */
+#define SEC_DESC_OWNER_DEFAULTED ( 0x0001 )
+#define SEC_DESC_GROUP_DEFAULTED ( 0x0002 )
+#define SEC_DESC_DACL_PRESENT ( 0x0004 )
+#define SEC_DESC_DACL_DEFAULTED ( 0x0008 )
+#define SEC_DESC_SACL_PRESENT ( 0x0010 )
+#define SEC_DESC_SACL_DEFAULTED ( 0x0020 )
+#define SEC_DESC_DACL_TRUSTED ( 0x0040 )
+#define SEC_DESC_SERVER_SECURITY ( 0x0080 )
+#define SEC_DESC_DACL_AUTO_INHERIT_REQ ( 0x0100 )
+#define SEC_DESC_SACL_AUTO_INHERIT_REQ ( 0x0200 )
+#define SEC_DESC_DACL_AUTO_INHERITED ( 0x0400 )
+#define SEC_DESC_SACL_AUTO_INHERITED ( 0x0800 )
+#define SEC_DESC_DACL_PROTECTED ( 0x1000 )
+#define SEC_DESC_SACL_PROTECTED ( 0x2000 )
+#define SEC_DESC_RM_CONTROL_VALID ( 0x4000 )
+#define SEC_DESC_SELF_RELATIVE ( 0x8000 )
+
+struct security_descriptor {
+ enum security_descriptor_revision revision;
+ uint16_t type;
+ struct dom_sid *owner_sid;/* [relative] */
+ struct dom_sid *group_sid;/* [relative] */
+ struct security_acl *sacl;/* [relative] */
+ struct security_acl *dacl;/* [relative] */
+}/* [gensize,public,flag(LIBNDR_FLAG_LITTLE_ENDIAN),nosize] */;
+
+struct sec_desc_buf {
+ uint32_t sd_size;/* [value(ndr_size_security_descriptor(sd,ndr->flags)),range(0,0x40000)] */
+ struct security_descriptor *sd;/* [unique,subcontext(4)] */
+}/* [public] */;
+
+struct security_token {
+ struct dom_sid *user_sid;/* [unique] */
+ struct dom_sid *group_sid;/* [unique] */
+ uint32_t num_sids;
+ struct dom_sid **sids;/* [unique,size_is(num_sids)] */
+ uint64_t privilege_mask;
+}/* [public] */;
+
+/* bitmap security_secinfo */
+#define SECINFO_OWNER ( 0x00000001 )
+#define SECINFO_GROUP ( 0x00000002 )
+#define SECINFO_DACL ( 0x00000004 )
+#define SECINFO_SACL ( 0x00000008 )
+#define SECINFO_UNPROTECTED_SACL ( 0x10000000 )
+#define SECINFO_UNPROTECTED_DACL ( 0x20000000 )
+#define SECINFO_PROTECTED_SACL ( 0x40000000 )
+#define SECINFO_PROTECTED_DACL ( 0x80000000 )
+
+#endif /* _HEADER_security */
diff --git a/source3/librpc/gen_ndr/srv_dfs.c b/source3/librpc/gen_ndr/srv_dfs.c
new file mode 100644
index 0000000000..54b2184829
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_dfs.c
@@ -0,0 +1,1754 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * server auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/srv_dfs.h"
+
+static bool api_dfs_GetManagerVersion(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_GetManagerVersion *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_GETMANAGERVERSION];
+
+ r = talloc(talloc_tos(), struct dfs_GetManagerVersion);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_GetManagerVersion, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.version = talloc_zero(r, enum dfs_ManagerVersion);
+ if (r->out.version == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ _dfs_GetManagerVersion(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_GetManagerVersion, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_Add(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_Add *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_ADD];
+
+ r = talloc(talloc_tos(), struct dfs_Add);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_Add, r);
+ }
+
+ r->out.result = _dfs_Add(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_Add, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_Remove(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_Remove *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_REMOVE];
+
+ r = talloc(talloc_tos(), struct dfs_Remove);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_Remove, r);
+ }
+
+ r->out.result = _dfs_Remove(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_Remove, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_SetInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_SetInfo *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_SETINFO];
+
+ r = talloc(talloc_tos(), struct dfs_SetInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_SetInfo, r);
+ }
+
+ r->out.result = _dfs_SetInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_SetInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_GetInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_GetInfo *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_GETINFO];
+
+ r = talloc(talloc_tos(), struct dfs_GetInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_GetInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union dfs_Info);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _dfs_GetInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_GetInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_Enum(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_Enum *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_ENUM];
+
+ r = talloc(talloc_tos(), struct dfs_Enum);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_Enum, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = r->in.info;
+ r->out.total = r->in.total;
+ r->out.result = _dfs_Enum(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_Enum, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_Rename(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_Rename *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_RENAME];
+
+ r = talloc(talloc_tos(), struct dfs_Rename);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_Rename, r);
+ }
+
+ r->out.result = _dfs_Rename(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_Rename, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_Move(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_Move *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_MOVE];
+
+ r = talloc(talloc_tos(), struct dfs_Move);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_Move, r);
+ }
+
+ r->out.result = _dfs_Move(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_Move, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_ManagerGetConfigInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_ManagerGetConfigInfo *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_MANAGERGETCONFIGINFO];
+
+ r = talloc(talloc_tos(), struct dfs_ManagerGetConfigInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_ManagerGetConfigInfo, r);
+ }
+
+ r->out.result = _dfs_ManagerGetConfigInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_ManagerGetConfigInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_ManagerSendSiteInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_ManagerSendSiteInfo *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_MANAGERSENDSITEINFO];
+
+ r = talloc(talloc_tos(), struct dfs_ManagerSendSiteInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_ManagerSendSiteInfo, r);
+ }
+
+ r->out.result = _dfs_ManagerSendSiteInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_ManagerSendSiteInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_AddFtRoot(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_AddFtRoot *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_ADDFTROOT];
+
+ r = talloc(talloc_tos(), struct dfs_AddFtRoot);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_AddFtRoot, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.unknown2 = r->in.unknown2;
+ r->out.result = _dfs_AddFtRoot(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_AddFtRoot, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_RemoveFtRoot(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_RemoveFtRoot *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_REMOVEFTROOT];
+
+ r = talloc(talloc_tos(), struct dfs_RemoveFtRoot);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_RemoveFtRoot, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.unknown = r->in.unknown;
+ r->out.result = _dfs_RemoveFtRoot(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_RemoveFtRoot, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_AddStdRoot(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_AddStdRoot *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_ADDSTDROOT];
+
+ r = talloc(talloc_tos(), struct dfs_AddStdRoot);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_AddStdRoot, r);
+ }
+
+ r->out.result = _dfs_AddStdRoot(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_AddStdRoot, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_RemoveStdRoot(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_RemoveStdRoot *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_REMOVESTDROOT];
+
+ r = talloc(talloc_tos(), struct dfs_RemoveStdRoot);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_RemoveStdRoot, r);
+ }
+
+ r->out.result = _dfs_RemoveStdRoot(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_RemoveStdRoot, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_ManagerInitialize(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_ManagerInitialize *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_MANAGERINITIALIZE];
+
+ r = talloc(talloc_tos(), struct dfs_ManagerInitialize);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_ManagerInitialize, r);
+ }
+
+ r->out.result = _dfs_ManagerInitialize(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_ManagerInitialize, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_AddStdRootForced(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_AddStdRootForced *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_ADDSTDROOTFORCED];
+
+ r = talloc(talloc_tos(), struct dfs_AddStdRootForced);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_AddStdRootForced, r);
+ }
+
+ r->out.result = _dfs_AddStdRootForced(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_AddStdRootForced, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_GetDcAddress(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_GetDcAddress *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_GETDCADDRESS];
+
+ r = talloc(talloc_tos(), struct dfs_GetDcAddress);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_GetDcAddress, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.server_fullname = r->in.server_fullname;
+ r->out.is_root = r->in.is_root;
+ r->out.ttl = r->in.ttl;
+ r->out.result = _dfs_GetDcAddress(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_GetDcAddress, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_SetDcAddress(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_SetDcAddress *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_SETDCADDRESS];
+
+ r = talloc(talloc_tos(), struct dfs_SetDcAddress);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_SetDcAddress, r);
+ }
+
+ r->out.result = _dfs_SetDcAddress(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_SetDcAddress, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_FlushFtTable(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_FlushFtTable *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_FLUSHFTTABLE];
+
+ r = talloc(talloc_tos(), struct dfs_FlushFtTable);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_FlushFtTable, r);
+ }
+
+ r->out.result = _dfs_FlushFtTable(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_FlushFtTable, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_Add2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_Add2 *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_ADD2];
+
+ r = talloc(talloc_tos(), struct dfs_Add2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_Add2, r);
+ }
+
+ r->out.result = _dfs_Add2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_Add2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_Remove2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_Remove2 *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_REMOVE2];
+
+ r = talloc(talloc_tos(), struct dfs_Remove2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_Remove2, r);
+ }
+
+ r->out.result = _dfs_Remove2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_Remove2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_EnumEx(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_EnumEx *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_ENUMEX];
+
+ r = talloc(talloc_tos(), struct dfs_EnumEx);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_EnumEx, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = r->in.info;
+ r->out.total = r->in.total;
+ r->out.result = _dfs_EnumEx(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_EnumEx, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dfs_SetInfo2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dfs_SetInfo2 *r;
+
+ call = &ndr_table_netdfs.calls[NDR_DFS_SETINFO2];
+
+ r = talloc(talloc_tos(), struct dfs_SetInfo2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dfs_SetInfo2, r);
+ }
+
+ r->out.result = _dfs_SetInfo2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dfs_SetInfo2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+
+/* Tables */
+static struct api_struct api_netdfs_cmds[] =
+{
+ {"DFS_GETMANAGERVERSION", NDR_DFS_GETMANAGERVERSION, api_dfs_GetManagerVersion},
+ {"DFS_ADD", NDR_DFS_ADD, api_dfs_Add},
+ {"DFS_REMOVE", NDR_DFS_REMOVE, api_dfs_Remove},
+ {"DFS_SETINFO", NDR_DFS_SETINFO, api_dfs_SetInfo},
+ {"DFS_GETINFO", NDR_DFS_GETINFO, api_dfs_GetInfo},
+ {"DFS_ENUM", NDR_DFS_ENUM, api_dfs_Enum},
+ {"DFS_RENAME", NDR_DFS_RENAME, api_dfs_Rename},
+ {"DFS_MOVE", NDR_DFS_MOVE, api_dfs_Move},
+ {"DFS_MANAGERGETCONFIGINFO", NDR_DFS_MANAGERGETCONFIGINFO, api_dfs_ManagerGetConfigInfo},
+ {"DFS_MANAGERSENDSITEINFO", NDR_DFS_MANAGERSENDSITEINFO, api_dfs_ManagerSendSiteInfo},
+ {"DFS_ADDFTROOT", NDR_DFS_ADDFTROOT, api_dfs_AddFtRoot},
+ {"DFS_REMOVEFTROOT", NDR_DFS_REMOVEFTROOT, api_dfs_RemoveFtRoot},
+ {"DFS_ADDSTDROOT", NDR_DFS_ADDSTDROOT, api_dfs_AddStdRoot},
+ {"DFS_REMOVESTDROOT", NDR_DFS_REMOVESTDROOT, api_dfs_RemoveStdRoot},
+ {"DFS_MANAGERINITIALIZE", NDR_DFS_MANAGERINITIALIZE, api_dfs_ManagerInitialize},
+ {"DFS_ADDSTDROOTFORCED", NDR_DFS_ADDSTDROOTFORCED, api_dfs_AddStdRootForced},
+ {"DFS_GETDCADDRESS", NDR_DFS_GETDCADDRESS, api_dfs_GetDcAddress},
+ {"DFS_SETDCADDRESS", NDR_DFS_SETDCADDRESS, api_dfs_SetDcAddress},
+ {"DFS_FLUSHFTTABLE", NDR_DFS_FLUSHFTTABLE, api_dfs_FlushFtTable},
+ {"DFS_ADD2", NDR_DFS_ADD2, api_dfs_Add2},
+ {"DFS_REMOVE2", NDR_DFS_REMOVE2, api_dfs_Remove2},
+ {"DFS_ENUMEX", NDR_DFS_ENUMEX, api_dfs_EnumEx},
+ {"DFS_SETINFO2", NDR_DFS_SETINFO2, api_dfs_SetInfo2},
+};
+
+void netdfs_get_pipe_fns(struct api_struct **fns, int *n_fns)
+{
+ *fns = api_netdfs_cmds;
+ *n_fns = sizeof(api_netdfs_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_netdfs_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "netdfs", "netdfs", &ndr_table_netdfs.syntax_id, api_netdfs_cmds, sizeof(api_netdfs_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/librpc/gen_ndr/srv_dfs.h b/source3/librpc/gen_ndr/srv_dfs.h
new file mode 100644
index 0000000000..e4d7a99c73
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_dfs.h
@@ -0,0 +1,29 @@
+#include "librpc/gen_ndr/ndr_dfs.h"
+#ifndef __SRV_NETDFS__
+#define __SRV_NETDFS__
+void _dfs_GetManagerVersion(pipes_struct *p, struct dfs_GetManagerVersion *r);
+WERROR _dfs_Add(pipes_struct *p, struct dfs_Add *r);
+WERROR _dfs_Remove(pipes_struct *p, struct dfs_Remove *r);
+WERROR _dfs_SetInfo(pipes_struct *p, struct dfs_SetInfo *r);
+WERROR _dfs_GetInfo(pipes_struct *p, struct dfs_GetInfo *r);
+WERROR _dfs_Enum(pipes_struct *p, struct dfs_Enum *r);
+WERROR _dfs_Rename(pipes_struct *p, struct dfs_Rename *r);
+WERROR _dfs_Move(pipes_struct *p, struct dfs_Move *r);
+WERROR _dfs_ManagerGetConfigInfo(pipes_struct *p, struct dfs_ManagerGetConfigInfo *r);
+WERROR _dfs_ManagerSendSiteInfo(pipes_struct *p, struct dfs_ManagerSendSiteInfo *r);
+WERROR _dfs_AddFtRoot(pipes_struct *p, struct dfs_AddFtRoot *r);
+WERROR _dfs_RemoveFtRoot(pipes_struct *p, struct dfs_RemoveFtRoot *r);
+WERROR _dfs_AddStdRoot(pipes_struct *p, struct dfs_AddStdRoot *r);
+WERROR _dfs_RemoveStdRoot(pipes_struct *p, struct dfs_RemoveStdRoot *r);
+WERROR _dfs_ManagerInitialize(pipes_struct *p, struct dfs_ManagerInitialize *r);
+WERROR _dfs_AddStdRootForced(pipes_struct *p, struct dfs_AddStdRootForced *r);
+WERROR _dfs_GetDcAddress(pipes_struct *p, struct dfs_GetDcAddress *r);
+WERROR _dfs_SetDcAddress(pipes_struct *p, struct dfs_SetDcAddress *r);
+WERROR _dfs_FlushFtTable(pipes_struct *p, struct dfs_FlushFtTable *r);
+WERROR _dfs_Add2(pipes_struct *p, struct dfs_Add2 *r);
+WERROR _dfs_Remove2(pipes_struct *p, struct dfs_Remove2 *r);
+WERROR _dfs_EnumEx(pipes_struct *p, struct dfs_EnumEx *r);
+WERROR _dfs_SetInfo2(pipes_struct *p, struct dfs_SetInfo2 *r);
+void netdfs_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_netdfs_init(void);
+#endif /* __SRV_NETDFS__ */
diff --git a/source3/librpc/gen_ndr/srv_dssetup.c b/source3/librpc/gen_ndr/srv_dssetup.c
new file mode 100644
index 0000000000..79bde30d06
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_dssetup.c
@@ -0,0 +1,845 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * server auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/srv_dssetup.h"
+
+static bool api_dssetup_DsRoleGetPrimaryDomainInformation(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dssetup_DsRoleGetPrimaryDomainInformation *r;
+
+ call = &ndr_table_dssetup.calls[NDR_DSSETUP_DSROLEGETPRIMARYDOMAININFORMATION];
+
+ r = talloc(talloc_tos(), struct dssetup_DsRoleGetPrimaryDomainInformation);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleGetPrimaryDomainInformation, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union dssetup_DsRoleInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _dssetup_DsRoleGetPrimaryDomainInformation(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleGetPrimaryDomainInformation, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dssetup_DsRoleDnsNameToFlatName(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dssetup_DsRoleDnsNameToFlatName *r;
+
+ call = &ndr_table_dssetup.calls[NDR_DSSETUP_DSROLEDNSNAMETOFLATNAME];
+
+ r = talloc(talloc_tos(), struct dssetup_DsRoleDnsNameToFlatName);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleDnsNameToFlatName, r);
+ }
+
+ r->out.result = _dssetup_DsRoleDnsNameToFlatName(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleDnsNameToFlatName, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dssetup_DsRoleDcAsDc(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dssetup_DsRoleDcAsDc *r;
+
+ call = &ndr_table_dssetup.calls[NDR_DSSETUP_DSROLEDCASDC];
+
+ r = talloc(talloc_tos(), struct dssetup_DsRoleDcAsDc);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleDcAsDc, r);
+ }
+
+ r->out.result = _dssetup_DsRoleDcAsDc(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleDcAsDc, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dssetup_DsRoleDcAsReplica(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dssetup_DsRoleDcAsReplica *r;
+
+ call = &ndr_table_dssetup.calls[NDR_DSSETUP_DSROLEDCASREPLICA];
+
+ r = talloc(talloc_tos(), struct dssetup_DsRoleDcAsReplica);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleDcAsReplica, r);
+ }
+
+ r->out.result = _dssetup_DsRoleDcAsReplica(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleDcAsReplica, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dssetup_DsRoleDemoteDc(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dssetup_DsRoleDemoteDc *r;
+
+ call = &ndr_table_dssetup.calls[NDR_DSSETUP_DSROLEDEMOTEDC];
+
+ r = talloc(talloc_tos(), struct dssetup_DsRoleDemoteDc);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleDemoteDc, r);
+ }
+
+ r->out.result = _dssetup_DsRoleDemoteDc(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleDemoteDc, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dssetup_DsRoleGetDcOperationProgress(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dssetup_DsRoleGetDcOperationProgress *r;
+
+ call = &ndr_table_dssetup.calls[NDR_DSSETUP_DSROLEGETDCOPERATIONPROGRESS];
+
+ r = talloc(talloc_tos(), struct dssetup_DsRoleGetDcOperationProgress);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleGetDcOperationProgress, r);
+ }
+
+ r->out.result = _dssetup_DsRoleGetDcOperationProgress(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleGetDcOperationProgress, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dssetup_DsRoleGetDcOperationResults(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dssetup_DsRoleGetDcOperationResults *r;
+
+ call = &ndr_table_dssetup.calls[NDR_DSSETUP_DSROLEGETDCOPERATIONRESULTS];
+
+ r = talloc(talloc_tos(), struct dssetup_DsRoleGetDcOperationResults);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleGetDcOperationResults, r);
+ }
+
+ r->out.result = _dssetup_DsRoleGetDcOperationResults(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleGetDcOperationResults, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dssetup_DsRoleCancel(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dssetup_DsRoleCancel *r;
+
+ call = &ndr_table_dssetup.calls[NDR_DSSETUP_DSROLECANCEL];
+
+ r = talloc(talloc_tos(), struct dssetup_DsRoleCancel);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleCancel, r);
+ }
+
+ r->out.result = _dssetup_DsRoleCancel(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleCancel, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dssetup_DsRoleServerSaveStateForUpgrade(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dssetup_DsRoleServerSaveStateForUpgrade *r;
+
+ call = &ndr_table_dssetup.calls[NDR_DSSETUP_DSROLESERVERSAVESTATEFORUPGRADE];
+
+ r = talloc(talloc_tos(), struct dssetup_DsRoleServerSaveStateForUpgrade);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleServerSaveStateForUpgrade, r);
+ }
+
+ r->out.result = _dssetup_DsRoleServerSaveStateForUpgrade(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleServerSaveStateForUpgrade, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dssetup_DsRoleUpgradeDownlevelServer(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dssetup_DsRoleUpgradeDownlevelServer *r;
+
+ call = &ndr_table_dssetup.calls[NDR_DSSETUP_DSROLEUPGRADEDOWNLEVELSERVER];
+
+ r = talloc(talloc_tos(), struct dssetup_DsRoleUpgradeDownlevelServer);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleUpgradeDownlevelServer, r);
+ }
+
+ r->out.result = _dssetup_DsRoleUpgradeDownlevelServer(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleUpgradeDownlevelServer, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_dssetup_DsRoleAbortDownlevelServerUpgrade(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dssetup_DsRoleAbortDownlevelServerUpgrade *r;
+
+ call = &ndr_table_dssetup.calls[NDR_DSSETUP_DSROLEABORTDOWNLEVELSERVERUPGRADE];
+
+ r = talloc(talloc_tos(), struct dssetup_DsRoleAbortDownlevelServerUpgrade);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(dssetup_DsRoleAbortDownlevelServerUpgrade, r);
+ }
+
+ r->out.result = _dssetup_DsRoleAbortDownlevelServerUpgrade(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(dssetup_DsRoleAbortDownlevelServerUpgrade, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+
+/* Tables */
+static struct api_struct api_dssetup_cmds[] =
+{
+ {"DSSETUP_DSROLEGETPRIMARYDOMAININFORMATION", NDR_DSSETUP_DSROLEGETPRIMARYDOMAININFORMATION, api_dssetup_DsRoleGetPrimaryDomainInformation},
+ {"DSSETUP_DSROLEDNSNAMETOFLATNAME", NDR_DSSETUP_DSROLEDNSNAMETOFLATNAME, api_dssetup_DsRoleDnsNameToFlatName},
+ {"DSSETUP_DSROLEDCASDC", NDR_DSSETUP_DSROLEDCASDC, api_dssetup_DsRoleDcAsDc},
+ {"DSSETUP_DSROLEDCASREPLICA", NDR_DSSETUP_DSROLEDCASREPLICA, api_dssetup_DsRoleDcAsReplica},
+ {"DSSETUP_DSROLEDEMOTEDC", NDR_DSSETUP_DSROLEDEMOTEDC, api_dssetup_DsRoleDemoteDc},
+ {"DSSETUP_DSROLEGETDCOPERATIONPROGRESS", NDR_DSSETUP_DSROLEGETDCOPERATIONPROGRESS, api_dssetup_DsRoleGetDcOperationProgress},
+ {"DSSETUP_DSROLEGETDCOPERATIONRESULTS", NDR_DSSETUP_DSROLEGETDCOPERATIONRESULTS, api_dssetup_DsRoleGetDcOperationResults},
+ {"DSSETUP_DSROLECANCEL", NDR_DSSETUP_DSROLECANCEL, api_dssetup_DsRoleCancel},
+ {"DSSETUP_DSROLESERVERSAVESTATEFORUPGRADE", NDR_DSSETUP_DSROLESERVERSAVESTATEFORUPGRADE, api_dssetup_DsRoleServerSaveStateForUpgrade},
+ {"DSSETUP_DSROLEUPGRADEDOWNLEVELSERVER", NDR_DSSETUP_DSROLEUPGRADEDOWNLEVELSERVER, api_dssetup_DsRoleUpgradeDownlevelServer},
+ {"DSSETUP_DSROLEABORTDOWNLEVELSERVERUPGRADE", NDR_DSSETUP_DSROLEABORTDOWNLEVELSERVERUPGRADE, api_dssetup_DsRoleAbortDownlevelServerUpgrade},
+};
+
+void dssetup_get_pipe_fns(struct api_struct **fns, int *n_fns)
+{
+ *fns = api_dssetup_cmds;
+ *n_fns = sizeof(api_dssetup_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_dssetup_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "dssetup", "dssetup", &ndr_table_dssetup.syntax_id, api_dssetup_cmds, sizeof(api_dssetup_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/librpc/gen_ndr/srv_dssetup.h b/source3/librpc/gen_ndr/srv_dssetup.h
new file mode 100644
index 0000000000..3233899eac
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_dssetup.h
@@ -0,0 +1,17 @@
+#include "librpc/gen_ndr/ndr_dssetup.h"
+#ifndef __SRV_DSSETUP__
+#define __SRV_DSSETUP__
+WERROR _dssetup_DsRoleGetPrimaryDomainInformation(pipes_struct *p, struct dssetup_DsRoleGetPrimaryDomainInformation *r);
+WERROR _dssetup_DsRoleDnsNameToFlatName(pipes_struct *p, struct dssetup_DsRoleDnsNameToFlatName *r);
+WERROR _dssetup_DsRoleDcAsDc(pipes_struct *p, struct dssetup_DsRoleDcAsDc *r);
+WERROR _dssetup_DsRoleDcAsReplica(pipes_struct *p, struct dssetup_DsRoleDcAsReplica *r);
+WERROR _dssetup_DsRoleDemoteDc(pipes_struct *p, struct dssetup_DsRoleDemoteDc *r);
+WERROR _dssetup_DsRoleGetDcOperationProgress(pipes_struct *p, struct dssetup_DsRoleGetDcOperationProgress *r);
+WERROR _dssetup_DsRoleGetDcOperationResults(pipes_struct *p, struct dssetup_DsRoleGetDcOperationResults *r);
+WERROR _dssetup_DsRoleCancel(pipes_struct *p, struct dssetup_DsRoleCancel *r);
+WERROR _dssetup_DsRoleServerSaveStateForUpgrade(pipes_struct *p, struct dssetup_DsRoleServerSaveStateForUpgrade *r);
+WERROR _dssetup_DsRoleUpgradeDownlevelServer(pipes_struct *p, struct dssetup_DsRoleUpgradeDownlevelServer *r);
+WERROR _dssetup_DsRoleAbortDownlevelServerUpgrade(pipes_struct *p, struct dssetup_DsRoleAbortDownlevelServerUpgrade *r);
+void dssetup_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_dssetup_init(void);
+#endif /* __SRV_DSSETUP__ */
diff --git a/source3/librpc/gen_ndr/srv_echo.c b/source3/librpc/gen_ndr/srv_echo.c
new file mode 100644
index 0000000000..b8b38dad13
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_echo.c
@@ -0,0 +1,805 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * server auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/srv_echo.h"
+
+static bool api_echo_AddOne(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct echo_AddOne *r;
+
+ call = &ndr_table_rpcecho.calls[NDR_ECHO_ADDONE];
+
+ r = talloc(talloc_tos(), struct echo_AddOne);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_AddOne, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.out_data = talloc_zero(r, uint32_t);
+ if (r->out.out_data == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ _echo_AddOne(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_AddOne, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_echo_EchoData(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct echo_EchoData *r;
+
+ call = &ndr_table_rpcecho.calls[NDR_ECHO_ECHODATA];
+
+ r = talloc(talloc_tos(), struct echo_EchoData);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_EchoData, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.out_data = talloc_zero_array(r, uint8_t, r->in.len);
+ if (r->out.out_data == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ _echo_EchoData(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_EchoData, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_echo_SinkData(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct echo_SinkData *r;
+
+ call = &ndr_table_rpcecho.calls[NDR_ECHO_SINKDATA];
+
+ r = talloc(talloc_tos(), struct echo_SinkData);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_SinkData, r);
+ }
+
+ _echo_SinkData(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_SinkData, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_echo_SourceData(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct echo_SourceData *r;
+
+ call = &ndr_table_rpcecho.calls[NDR_ECHO_SOURCEDATA];
+
+ r = talloc(talloc_tos(), struct echo_SourceData);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_SourceData, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.data = talloc_zero_array(r, uint8_t, r->in.len);
+ if (r->out.data == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ _echo_SourceData(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_SourceData, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_echo_TestCall(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct echo_TestCall *r;
+
+ call = &ndr_table_rpcecho.calls[NDR_ECHO_TESTCALL];
+
+ r = talloc(talloc_tos(), struct echo_TestCall);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_TestCall, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.s2 = talloc_zero(r, const char *);
+ if (r->out.s2 == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ _echo_TestCall(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_TestCall, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_echo_TestCall2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct echo_TestCall2 *r;
+
+ call = &ndr_table_rpcecho.calls[NDR_ECHO_TESTCALL2];
+
+ r = talloc(talloc_tos(), struct echo_TestCall2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_TestCall2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union echo_Info);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _echo_TestCall2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_TestCall2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_echo_TestSleep(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct echo_TestSleep *r;
+
+ call = &ndr_table_rpcecho.calls[NDR_ECHO_TESTSLEEP];
+
+ r = talloc(talloc_tos(), struct echo_TestSleep);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_TestSleep, r);
+ }
+
+ r->out.result = _echo_TestSleep(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_TestSleep, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_echo_TestEnum(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct echo_TestEnum *r;
+
+ call = &ndr_table_rpcecho.calls[NDR_ECHO_TESTENUM];
+
+ r = talloc(talloc_tos(), struct echo_TestEnum);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_TestEnum, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.foo1 = r->in.foo1;
+ r->out.foo2 = r->in.foo2;
+ r->out.foo3 = r->in.foo3;
+ _echo_TestEnum(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_TestEnum, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_echo_TestSurrounding(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct echo_TestSurrounding *r;
+
+ call = &ndr_table_rpcecho.calls[NDR_ECHO_TESTSURROUNDING];
+
+ r = talloc(talloc_tos(), struct echo_TestSurrounding);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_TestSurrounding, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.data = r->in.data;
+ _echo_TestSurrounding(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_TestSurrounding, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_echo_TestDoublePointer(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct echo_TestDoublePointer *r;
+
+ call = &ndr_table_rpcecho.calls[NDR_ECHO_TESTDOUBLEPOINTER];
+
+ r = talloc(talloc_tos(), struct echo_TestDoublePointer);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(echo_TestDoublePointer, r);
+ }
+
+ r->out.result = _echo_TestDoublePointer(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(echo_TestDoublePointer, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+
+/* Tables */
+static struct api_struct api_rpcecho_cmds[] =
+{
+ {"ECHO_ADDONE", NDR_ECHO_ADDONE, api_echo_AddOne},
+ {"ECHO_ECHODATA", NDR_ECHO_ECHODATA, api_echo_EchoData},
+ {"ECHO_SINKDATA", NDR_ECHO_SINKDATA, api_echo_SinkData},
+ {"ECHO_SOURCEDATA", NDR_ECHO_SOURCEDATA, api_echo_SourceData},
+ {"ECHO_TESTCALL", NDR_ECHO_TESTCALL, api_echo_TestCall},
+ {"ECHO_TESTCALL2", NDR_ECHO_TESTCALL2, api_echo_TestCall2},
+ {"ECHO_TESTSLEEP", NDR_ECHO_TESTSLEEP, api_echo_TestSleep},
+ {"ECHO_TESTENUM", NDR_ECHO_TESTENUM, api_echo_TestEnum},
+ {"ECHO_TESTSURROUNDING", NDR_ECHO_TESTSURROUNDING, api_echo_TestSurrounding},
+ {"ECHO_TESTDOUBLEPOINTER", NDR_ECHO_TESTDOUBLEPOINTER, api_echo_TestDoublePointer},
+};
+
+void rpcecho_get_pipe_fns(struct api_struct **fns, int *n_fns)
+{
+ *fns = api_rpcecho_cmds;
+ *n_fns = sizeof(api_rpcecho_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_rpcecho_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "rpcecho", "rpcecho", &ndr_table_rpcecho.syntax_id, api_rpcecho_cmds, sizeof(api_rpcecho_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/librpc/gen_ndr/srv_echo.h b/source3/librpc/gen_ndr/srv_echo.h
new file mode 100644
index 0000000000..c3b0336652
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_echo.h
@@ -0,0 +1,16 @@
+#include "librpc/gen_ndr/ndr_echo.h"
+#ifndef __SRV_RPCECHO__
+#define __SRV_RPCECHO__
+void _echo_AddOne(pipes_struct *p, struct echo_AddOne *r);
+void _echo_EchoData(pipes_struct *p, struct echo_EchoData *r);
+void _echo_SinkData(pipes_struct *p, struct echo_SinkData *r);
+void _echo_SourceData(pipes_struct *p, struct echo_SourceData *r);
+void _echo_TestCall(pipes_struct *p, struct echo_TestCall *r);
+NTSTATUS _echo_TestCall2(pipes_struct *p, struct echo_TestCall2 *r);
+uint32 _echo_TestSleep(pipes_struct *p, struct echo_TestSleep *r);
+void _echo_TestEnum(pipes_struct *p, struct echo_TestEnum *r);
+void _echo_TestSurrounding(pipes_struct *p, struct echo_TestSurrounding *r);
+uint16 _echo_TestDoublePointer(pipes_struct *p, struct echo_TestDoublePointer *r);
+void rpcecho_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_rpcecho_init(void);
+#endif /* __SRV_RPCECHO__ */
diff --git a/source3/librpc/gen_ndr/srv_epmapper.c b/source3/librpc/gen_ndr/srv_epmapper.c
new file mode 100644
index 0000000000..f42598abd4
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_epmapper.c
@@ -0,0 +1,646 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * server auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/srv_epmapper.h"
+
+static bool api_epm_Insert(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct epm_Insert *r;
+
+ call = &ndr_table_epmapper.calls[NDR_EPM_INSERT];
+
+ r = talloc(talloc_tos(), struct epm_Insert);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(epm_Insert, r);
+ }
+
+ r->out.result = _epm_Insert(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(epm_Insert, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_epm_Delete(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct epm_Delete *r;
+
+ call = &ndr_table_epmapper.calls[NDR_EPM_DELETE];
+
+ r = talloc(talloc_tos(), struct epm_Delete);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(epm_Delete, r);
+ }
+
+ r->out.result = _epm_Delete(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(epm_Delete, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_epm_Lookup(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct epm_Lookup *r;
+
+ call = &ndr_table_epmapper.calls[NDR_EPM_LOOKUP];
+
+ r = talloc(talloc_tos(), struct epm_Lookup);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(epm_Lookup, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.entry_handle = r->in.entry_handle;
+ r->out.num_ents = talloc_zero(r, uint32_t);
+ if (r->out.num_ents == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.entries = talloc_zero_array(r, struct epm_entry_t, r->in.max_ents);
+ if (r->out.entries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _epm_Lookup(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(epm_Lookup, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_epm_Map(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct epm_Map *r;
+
+ call = &ndr_table_epmapper.calls[NDR_EPM_MAP];
+
+ r = talloc(talloc_tos(), struct epm_Map);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(epm_Map, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.entry_handle = r->in.entry_handle;
+ r->out.num_towers = talloc_zero(r, uint32_t);
+ if (r->out.num_towers == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.towers = talloc_zero_array(r, struct epm_twr_p_t, r->in.max_towers);
+ if (r->out.towers == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _epm_Map(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(epm_Map, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_epm_LookupHandleFree(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct epm_LookupHandleFree *r;
+
+ call = &ndr_table_epmapper.calls[NDR_EPM_LOOKUPHANDLEFREE];
+
+ r = talloc(talloc_tos(), struct epm_LookupHandleFree);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(epm_LookupHandleFree, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.entry_handle = r->in.entry_handle;
+ r->out.result = _epm_LookupHandleFree(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(epm_LookupHandleFree, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_epm_InqObject(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct epm_InqObject *r;
+
+ call = &ndr_table_epmapper.calls[NDR_EPM_INQOBJECT];
+
+ r = talloc(talloc_tos(), struct epm_InqObject);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(epm_InqObject, r);
+ }
+
+ r->out.result = _epm_InqObject(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(epm_InqObject, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_epm_MgmtDelete(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct epm_MgmtDelete *r;
+
+ call = &ndr_table_epmapper.calls[NDR_EPM_MGMTDELETE];
+
+ r = talloc(talloc_tos(), struct epm_MgmtDelete);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(epm_MgmtDelete, r);
+ }
+
+ r->out.result = _epm_MgmtDelete(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(epm_MgmtDelete, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_epm_MapAuth(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct epm_MapAuth *r;
+
+ call = &ndr_table_epmapper.calls[NDR_EPM_MAPAUTH];
+
+ r = talloc(talloc_tos(), struct epm_MapAuth);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(epm_MapAuth, r);
+ }
+
+ r->out.result = _epm_MapAuth(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(epm_MapAuth, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+
+/* Tables */
+static struct api_struct api_epmapper_cmds[] =
+{
+ {"EPM_INSERT", NDR_EPM_INSERT, api_epm_Insert},
+ {"EPM_DELETE", NDR_EPM_DELETE, api_epm_Delete},
+ {"EPM_LOOKUP", NDR_EPM_LOOKUP, api_epm_Lookup},
+ {"EPM_MAP", NDR_EPM_MAP, api_epm_Map},
+ {"EPM_LOOKUPHANDLEFREE", NDR_EPM_LOOKUPHANDLEFREE, api_epm_LookupHandleFree},
+ {"EPM_INQOBJECT", NDR_EPM_INQOBJECT, api_epm_InqObject},
+ {"EPM_MGMTDELETE", NDR_EPM_MGMTDELETE, api_epm_MgmtDelete},
+ {"EPM_MAPAUTH", NDR_EPM_MAPAUTH, api_epm_MapAuth},
+};
+
+void epmapper_get_pipe_fns(struct api_struct **fns, int *n_fns)
+{
+ *fns = api_epmapper_cmds;
+ *n_fns = sizeof(api_epmapper_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_epmapper_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "epmapper", "epmapper", &ndr_table_epmapper.syntax_id, api_epmapper_cmds, sizeof(api_epmapper_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/librpc/gen_ndr/srv_epmapper.h b/source3/librpc/gen_ndr/srv_epmapper.h
new file mode 100644
index 0000000000..e0d0105b78
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_epmapper.h
@@ -0,0 +1,14 @@
+#include "librpc/gen_ndr/ndr_epmapper.h"
+#ifndef __SRV_EPMAPPER__
+#define __SRV_EPMAPPER__
+uint32 _epm_Insert(pipes_struct *p, struct epm_Insert *r);
+uint32 _epm_Delete(pipes_struct *p, struct epm_Delete *r);
+uint32 _epm_Lookup(pipes_struct *p, struct epm_Lookup *r);
+uint32 _epm_Map(pipes_struct *p, struct epm_Map *r);
+uint32 _epm_LookupHandleFree(pipes_struct *p, struct epm_LookupHandleFree *r);
+uint32 _epm_InqObject(pipes_struct *p, struct epm_InqObject *r);
+uint32 _epm_MgmtDelete(pipes_struct *p, struct epm_MgmtDelete *r);
+uint32 _epm_MapAuth(pipes_struct *p, struct epm_MapAuth *r);
+void epmapper_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_epmapper_init(void);
+#endif /* __SRV_EPMAPPER__ */
diff --git a/source3/librpc/gen_ndr/srv_eventlog.c b/source3/librpc/gen_ndr/srv_eventlog.c
new file mode 100644
index 0000000000..eb3fb1fe6d
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_eventlog.c
@@ -0,0 +1,1842 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * server auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/srv_eventlog.h"
+
+static bool api_eventlog_ClearEventLogW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_ClearEventLogW *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_CLEAREVENTLOGW];
+
+ r = talloc(talloc_tos(), struct eventlog_ClearEventLogW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_ClearEventLogW, r);
+ }
+
+ r->out.result = _eventlog_ClearEventLogW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_ClearEventLogW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_BackupEventLogW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_BackupEventLogW *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_BACKUPEVENTLOGW];
+
+ r = talloc(talloc_tos(), struct eventlog_BackupEventLogW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_BackupEventLogW, r);
+ }
+
+ r->out.result = _eventlog_BackupEventLogW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_BackupEventLogW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_CloseEventLog(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_CloseEventLog *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_CLOSEEVENTLOG];
+
+ r = talloc(talloc_tos(), struct eventlog_CloseEventLog);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_CloseEventLog, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = r->in.handle;
+ r->out.result = _eventlog_CloseEventLog(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_CloseEventLog, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_DeregisterEventSource(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_DeregisterEventSource *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_DEREGISTEREVENTSOURCE];
+
+ r = talloc(talloc_tos(), struct eventlog_DeregisterEventSource);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_DeregisterEventSource, r);
+ }
+
+ r->out.result = _eventlog_DeregisterEventSource(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_DeregisterEventSource, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_GetNumRecords(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_GetNumRecords *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_GETNUMRECORDS];
+
+ r = talloc(talloc_tos(), struct eventlog_GetNumRecords);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_GetNumRecords, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.number = talloc_zero(r, uint32_t);
+ if (r->out.number == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _eventlog_GetNumRecords(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_GetNumRecords, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_GetOldestRecord(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_GetOldestRecord *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_GETOLDESTRECORD];
+
+ r = talloc(talloc_tos(), struct eventlog_GetOldestRecord);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_GetOldestRecord, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.oldest_entry = talloc_zero(r, uint32_t);
+ if (r->out.oldest_entry == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _eventlog_GetOldestRecord(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_GetOldestRecord, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_ChangeNotify(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_ChangeNotify *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_CHANGENOTIFY];
+
+ r = talloc(talloc_tos(), struct eventlog_ChangeNotify);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_ChangeNotify, r);
+ }
+
+ r->out.result = _eventlog_ChangeNotify(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_ChangeNotify, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_OpenEventLogW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_OpenEventLogW *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_OPENEVENTLOGW];
+
+ r = talloc(talloc_tos(), struct eventlog_OpenEventLogW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_OpenEventLogW, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _eventlog_OpenEventLogW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_OpenEventLogW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_RegisterEventSourceW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_RegisterEventSourceW *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_REGISTEREVENTSOURCEW];
+
+ r = talloc(talloc_tos(), struct eventlog_RegisterEventSourceW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_RegisterEventSourceW, r);
+ }
+
+ r->out.result = _eventlog_RegisterEventSourceW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_RegisterEventSourceW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_OpenBackupEventLogW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_OpenBackupEventLogW *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_OPENBACKUPEVENTLOGW];
+
+ r = talloc(talloc_tos(), struct eventlog_OpenBackupEventLogW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_OpenBackupEventLogW, r);
+ }
+
+ r->out.result = _eventlog_OpenBackupEventLogW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_OpenBackupEventLogW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_ReadEventLogW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_ReadEventLogW *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_READEVENTLOGW];
+
+ r = talloc(talloc_tos(), struct eventlog_ReadEventLogW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_ReadEventLogW, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.data = talloc_zero_array(r, uint8_t, r->in.number_of_bytes);
+ if (r->out.data == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.sent_size = talloc_zero(r, uint32_t);
+ if (r->out.sent_size == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.real_size = talloc_zero(r, uint32_t);
+ if (r->out.real_size == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _eventlog_ReadEventLogW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_ReadEventLogW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_ReportEventW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_ReportEventW *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_REPORTEVENTW];
+
+ r = talloc(talloc_tos(), struct eventlog_ReportEventW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_ReportEventW, r);
+ }
+
+ r->out.result = _eventlog_ReportEventW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_ReportEventW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_ClearEventLogA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_ClearEventLogA *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_CLEAREVENTLOGA];
+
+ r = talloc(talloc_tos(), struct eventlog_ClearEventLogA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_ClearEventLogA, r);
+ }
+
+ r->out.result = _eventlog_ClearEventLogA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_ClearEventLogA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_BackupEventLogA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_BackupEventLogA *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_BACKUPEVENTLOGA];
+
+ r = talloc(talloc_tos(), struct eventlog_BackupEventLogA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_BackupEventLogA, r);
+ }
+
+ r->out.result = _eventlog_BackupEventLogA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_BackupEventLogA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_OpenEventLogA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_OpenEventLogA *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_OPENEVENTLOGA];
+
+ r = talloc(talloc_tos(), struct eventlog_OpenEventLogA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_OpenEventLogA, r);
+ }
+
+ r->out.result = _eventlog_OpenEventLogA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_OpenEventLogA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_RegisterEventSourceA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_RegisterEventSourceA *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_REGISTEREVENTSOURCEA];
+
+ r = talloc(talloc_tos(), struct eventlog_RegisterEventSourceA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_RegisterEventSourceA, r);
+ }
+
+ r->out.result = _eventlog_RegisterEventSourceA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_RegisterEventSourceA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_OpenBackupEventLogA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_OpenBackupEventLogA *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_OPENBACKUPEVENTLOGA];
+
+ r = talloc(talloc_tos(), struct eventlog_OpenBackupEventLogA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_OpenBackupEventLogA, r);
+ }
+
+ r->out.result = _eventlog_OpenBackupEventLogA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_OpenBackupEventLogA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_ReadEventLogA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_ReadEventLogA *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_READEVENTLOGA];
+
+ r = talloc(talloc_tos(), struct eventlog_ReadEventLogA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_ReadEventLogA, r);
+ }
+
+ r->out.result = _eventlog_ReadEventLogA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_ReadEventLogA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_ReportEventA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_ReportEventA *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_REPORTEVENTA];
+
+ r = talloc(talloc_tos(), struct eventlog_ReportEventA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_ReportEventA, r);
+ }
+
+ r->out.result = _eventlog_ReportEventA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_ReportEventA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_RegisterClusterSvc(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_RegisterClusterSvc *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_REGISTERCLUSTERSVC];
+
+ r = talloc(talloc_tos(), struct eventlog_RegisterClusterSvc);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_RegisterClusterSvc, r);
+ }
+
+ r->out.result = _eventlog_RegisterClusterSvc(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_RegisterClusterSvc, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_DeregisterClusterSvc(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_DeregisterClusterSvc *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_DEREGISTERCLUSTERSVC];
+
+ r = talloc(talloc_tos(), struct eventlog_DeregisterClusterSvc);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_DeregisterClusterSvc, r);
+ }
+
+ r->out.result = _eventlog_DeregisterClusterSvc(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_DeregisterClusterSvc, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_WriteClusterEvents(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_WriteClusterEvents *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_WRITECLUSTEREVENTS];
+
+ r = talloc(talloc_tos(), struct eventlog_WriteClusterEvents);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_WriteClusterEvents, r);
+ }
+
+ r->out.result = _eventlog_WriteClusterEvents(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_WriteClusterEvents, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_GetLogIntormation(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_GetLogIntormation *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_GETLOGINTORMATION];
+
+ r = talloc(talloc_tos(), struct eventlog_GetLogIntormation);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_GetLogIntormation, r);
+ }
+
+ r->out.result = _eventlog_GetLogIntormation(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_GetLogIntormation, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_eventlog_FlushEventLog(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct eventlog_FlushEventLog *r;
+
+ call = &ndr_table_eventlog.calls[NDR_EVENTLOG_FLUSHEVENTLOG];
+
+ r = talloc(talloc_tos(), struct eventlog_FlushEventLog);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(eventlog_FlushEventLog, r);
+ }
+
+ r->out.result = _eventlog_FlushEventLog(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(eventlog_FlushEventLog, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+
+/* Tables */
+static struct api_struct api_eventlog_cmds[] =
+{
+ {"EVENTLOG_CLEAREVENTLOGW", NDR_EVENTLOG_CLEAREVENTLOGW, api_eventlog_ClearEventLogW},
+ {"EVENTLOG_BACKUPEVENTLOGW", NDR_EVENTLOG_BACKUPEVENTLOGW, api_eventlog_BackupEventLogW},
+ {"EVENTLOG_CLOSEEVENTLOG", NDR_EVENTLOG_CLOSEEVENTLOG, api_eventlog_CloseEventLog},
+ {"EVENTLOG_DEREGISTEREVENTSOURCE", NDR_EVENTLOG_DEREGISTEREVENTSOURCE, api_eventlog_DeregisterEventSource},
+ {"EVENTLOG_GETNUMRECORDS", NDR_EVENTLOG_GETNUMRECORDS, api_eventlog_GetNumRecords},
+ {"EVENTLOG_GETOLDESTRECORD", NDR_EVENTLOG_GETOLDESTRECORD, api_eventlog_GetOldestRecord},
+ {"EVENTLOG_CHANGENOTIFY", NDR_EVENTLOG_CHANGENOTIFY, api_eventlog_ChangeNotify},
+ {"EVENTLOG_OPENEVENTLOGW", NDR_EVENTLOG_OPENEVENTLOGW, api_eventlog_OpenEventLogW},
+ {"EVENTLOG_REGISTEREVENTSOURCEW", NDR_EVENTLOG_REGISTEREVENTSOURCEW, api_eventlog_RegisterEventSourceW},
+ {"EVENTLOG_OPENBACKUPEVENTLOGW", NDR_EVENTLOG_OPENBACKUPEVENTLOGW, api_eventlog_OpenBackupEventLogW},
+ {"EVENTLOG_READEVENTLOGW", NDR_EVENTLOG_READEVENTLOGW, api_eventlog_ReadEventLogW},
+ {"EVENTLOG_REPORTEVENTW", NDR_EVENTLOG_REPORTEVENTW, api_eventlog_ReportEventW},
+ {"EVENTLOG_CLEAREVENTLOGA", NDR_EVENTLOG_CLEAREVENTLOGA, api_eventlog_ClearEventLogA},
+ {"EVENTLOG_BACKUPEVENTLOGA", NDR_EVENTLOG_BACKUPEVENTLOGA, api_eventlog_BackupEventLogA},
+ {"EVENTLOG_OPENEVENTLOGA", NDR_EVENTLOG_OPENEVENTLOGA, api_eventlog_OpenEventLogA},
+ {"EVENTLOG_REGISTEREVENTSOURCEA", NDR_EVENTLOG_REGISTEREVENTSOURCEA, api_eventlog_RegisterEventSourceA},
+ {"EVENTLOG_OPENBACKUPEVENTLOGA", NDR_EVENTLOG_OPENBACKUPEVENTLOGA, api_eventlog_OpenBackupEventLogA},
+ {"EVENTLOG_READEVENTLOGA", NDR_EVENTLOG_READEVENTLOGA, api_eventlog_ReadEventLogA},
+ {"EVENTLOG_REPORTEVENTA", NDR_EVENTLOG_REPORTEVENTA, api_eventlog_ReportEventA},
+ {"EVENTLOG_REGISTERCLUSTERSVC", NDR_EVENTLOG_REGISTERCLUSTERSVC, api_eventlog_RegisterClusterSvc},
+ {"EVENTLOG_DEREGISTERCLUSTERSVC", NDR_EVENTLOG_DEREGISTERCLUSTERSVC, api_eventlog_DeregisterClusterSvc},
+ {"EVENTLOG_WRITECLUSTEREVENTS", NDR_EVENTLOG_WRITECLUSTEREVENTS, api_eventlog_WriteClusterEvents},
+ {"EVENTLOG_GETLOGINTORMATION", NDR_EVENTLOG_GETLOGINTORMATION, api_eventlog_GetLogIntormation},
+ {"EVENTLOG_FLUSHEVENTLOG", NDR_EVENTLOG_FLUSHEVENTLOG, api_eventlog_FlushEventLog},
+};
+
+void eventlog_get_pipe_fns(struct api_struct **fns, int *n_fns)
+{
+ *fns = api_eventlog_cmds;
+ *n_fns = sizeof(api_eventlog_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_eventlog_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "eventlog", "eventlog", &ndr_table_eventlog.syntax_id, api_eventlog_cmds, sizeof(api_eventlog_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/librpc/gen_ndr/srv_eventlog.h b/source3/librpc/gen_ndr/srv_eventlog.h
new file mode 100644
index 0000000000..6957c66beb
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_eventlog.h
@@ -0,0 +1,30 @@
+#include "librpc/gen_ndr/ndr_eventlog.h"
+#ifndef __SRV_EVENTLOG__
+#define __SRV_EVENTLOG__
+NTSTATUS _eventlog_ClearEventLogW(pipes_struct *p, struct eventlog_ClearEventLogW *r);
+NTSTATUS _eventlog_BackupEventLogW(pipes_struct *p, struct eventlog_BackupEventLogW *r);
+NTSTATUS _eventlog_CloseEventLog(pipes_struct *p, struct eventlog_CloseEventLog *r);
+NTSTATUS _eventlog_DeregisterEventSource(pipes_struct *p, struct eventlog_DeregisterEventSource *r);
+NTSTATUS _eventlog_GetNumRecords(pipes_struct *p, struct eventlog_GetNumRecords *r);
+NTSTATUS _eventlog_GetOldestRecord(pipes_struct *p, struct eventlog_GetOldestRecord *r);
+NTSTATUS _eventlog_ChangeNotify(pipes_struct *p, struct eventlog_ChangeNotify *r);
+NTSTATUS _eventlog_OpenEventLogW(pipes_struct *p, struct eventlog_OpenEventLogW *r);
+NTSTATUS _eventlog_RegisterEventSourceW(pipes_struct *p, struct eventlog_RegisterEventSourceW *r);
+NTSTATUS _eventlog_OpenBackupEventLogW(pipes_struct *p, struct eventlog_OpenBackupEventLogW *r);
+NTSTATUS _eventlog_ReadEventLogW(pipes_struct *p, struct eventlog_ReadEventLogW *r);
+NTSTATUS _eventlog_ReportEventW(pipes_struct *p, struct eventlog_ReportEventW *r);
+NTSTATUS _eventlog_ClearEventLogA(pipes_struct *p, struct eventlog_ClearEventLogA *r);
+NTSTATUS _eventlog_BackupEventLogA(pipes_struct *p, struct eventlog_BackupEventLogA *r);
+NTSTATUS _eventlog_OpenEventLogA(pipes_struct *p, struct eventlog_OpenEventLogA *r);
+NTSTATUS _eventlog_RegisterEventSourceA(pipes_struct *p, struct eventlog_RegisterEventSourceA *r);
+NTSTATUS _eventlog_OpenBackupEventLogA(pipes_struct *p, struct eventlog_OpenBackupEventLogA *r);
+NTSTATUS _eventlog_ReadEventLogA(pipes_struct *p, struct eventlog_ReadEventLogA *r);
+NTSTATUS _eventlog_ReportEventA(pipes_struct *p, struct eventlog_ReportEventA *r);
+NTSTATUS _eventlog_RegisterClusterSvc(pipes_struct *p, struct eventlog_RegisterClusterSvc *r);
+NTSTATUS _eventlog_DeregisterClusterSvc(pipes_struct *p, struct eventlog_DeregisterClusterSvc *r);
+NTSTATUS _eventlog_WriteClusterEvents(pipes_struct *p, struct eventlog_WriteClusterEvents *r);
+NTSTATUS _eventlog_GetLogIntormation(pipes_struct *p, struct eventlog_GetLogIntormation *r);
+NTSTATUS _eventlog_FlushEventLog(pipes_struct *p, struct eventlog_FlushEventLog *r);
+void eventlog_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_eventlog_init(void);
+#endif /* __SRV_EVENTLOG__ */
diff --git a/source3/librpc/gen_ndr/srv_initshutdown.c b/source3/librpc/gen_ndr/srv_initshutdown.c
new file mode 100644
index 0000000000..00a89661b5
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_initshutdown.c
@@ -0,0 +1,246 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * server auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/srv_initshutdown.h"
+
+static bool api_initshutdown_Init(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct initshutdown_Init *r;
+
+ call = &ndr_table_initshutdown.calls[NDR_INITSHUTDOWN_INIT];
+
+ r = talloc(talloc_tos(), struct initshutdown_Init);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(initshutdown_Init, r);
+ }
+
+ r->out.result = _initshutdown_Init(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(initshutdown_Init, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_initshutdown_Abort(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct initshutdown_Abort *r;
+
+ call = &ndr_table_initshutdown.calls[NDR_INITSHUTDOWN_ABORT];
+
+ r = talloc(talloc_tos(), struct initshutdown_Abort);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(initshutdown_Abort, r);
+ }
+
+ r->out.result = _initshutdown_Abort(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(initshutdown_Abort, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_initshutdown_InitEx(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct initshutdown_InitEx *r;
+
+ call = &ndr_table_initshutdown.calls[NDR_INITSHUTDOWN_INITEX];
+
+ r = talloc(talloc_tos(), struct initshutdown_InitEx);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(initshutdown_InitEx, r);
+ }
+
+ r->out.result = _initshutdown_InitEx(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(initshutdown_InitEx, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+
+/* Tables */
+static struct api_struct api_initshutdown_cmds[] =
+{
+ {"INITSHUTDOWN_INIT", NDR_INITSHUTDOWN_INIT, api_initshutdown_Init},
+ {"INITSHUTDOWN_ABORT", NDR_INITSHUTDOWN_ABORT, api_initshutdown_Abort},
+ {"INITSHUTDOWN_INITEX", NDR_INITSHUTDOWN_INITEX, api_initshutdown_InitEx},
+};
+
+void initshutdown_get_pipe_fns(struct api_struct **fns, int *n_fns)
+{
+ *fns = api_initshutdown_cmds;
+ *n_fns = sizeof(api_initshutdown_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_initshutdown_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "initshutdown", "initshutdown", &ndr_table_initshutdown.syntax_id, api_initshutdown_cmds, sizeof(api_initshutdown_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/librpc/gen_ndr/srv_initshutdown.h b/source3/librpc/gen_ndr/srv_initshutdown.h
new file mode 100644
index 0000000000..be3ea25271
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_initshutdown.h
@@ -0,0 +1,9 @@
+#include "librpc/gen_ndr/ndr_initshutdown.h"
+#ifndef __SRV_INITSHUTDOWN__
+#define __SRV_INITSHUTDOWN__
+WERROR _initshutdown_Init(pipes_struct *p, struct initshutdown_Init *r);
+WERROR _initshutdown_Abort(pipes_struct *p, struct initshutdown_Abort *r);
+WERROR _initshutdown_InitEx(pipes_struct *p, struct initshutdown_InitEx *r);
+void initshutdown_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_initshutdown_init(void);
+#endif /* __SRV_INITSHUTDOWN__ */
diff --git a/source3/librpc/gen_ndr/srv_lsa.c b/source3/librpc/gen_ndr/srv_lsa.c
new file mode 100644
index 0000000000..41d1c9716c
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_lsa.c
@@ -0,0 +1,6375 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * server auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/srv_lsa.h"
+
+static bool api_lsa_Close(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_Close *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CLOSE];
+
+ r = talloc(talloc_tos(), struct lsa_Close);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_Close, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = r->in.handle;
+ r->out.result = _lsa_Close(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_Close, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_Delete(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_Delete *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_DELETE];
+
+ r = talloc(talloc_tos(), struct lsa_Delete);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_Delete, r);
+ }
+
+ r->out.result = _lsa_Delete(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_Delete, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_EnumPrivs(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_EnumPrivs *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_ENUMPRIVS];
+
+ r = talloc(talloc_tos(), struct lsa_EnumPrivs);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_EnumPrivs, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.privs = talloc_zero(r, struct lsa_PrivArray);
+ if (r->out.privs == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_EnumPrivs(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_EnumPrivs, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_QuerySecurity(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_QuerySecurity *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_QUERYSECURITY];
+
+ r = talloc(talloc_tos(), struct lsa_QuerySecurity);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_QuerySecurity, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.sdbuf = talloc_zero(r, struct sec_desc_buf *);
+ if (r->out.sdbuf == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_QuerySecurity(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_QuerySecurity, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_SetSecObj(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_SetSecObj *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_SETSECOBJ];
+
+ r = talloc(talloc_tos(), struct lsa_SetSecObj);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetSecObj, r);
+ }
+
+ r->out.result = _lsa_SetSecObj(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetSecObj, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_ChangePassword(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_ChangePassword *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CHANGEPASSWORD];
+
+ r = talloc(talloc_tos(), struct lsa_ChangePassword);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_ChangePassword, r);
+ }
+
+ r->out.result = _lsa_ChangePassword(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_ChangePassword, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_OpenPolicy(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_OpenPolicy *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_OPENPOLICY];
+
+ r = talloc(talloc_tos(), struct lsa_OpenPolicy);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_OpenPolicy, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_OpenPolicy(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_OpenPolicy, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_QueryInfoPolicy(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_QueryInfoPolicy *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_QUERYINFOPOLICY];
+
+ r = talloc(talloc_tos(), struct lsa_QueryInfoPolicy);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_QueryInfoPolicy, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union lsa_PolicyInformation *);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_QueryInfoPolicy(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_QueryInfoPolicy, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_SetInfoPolicy(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_SetInfoPolicy *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_SETINFOPOLICY];
+
+ r = talloc(talloc_tos(), struct lsa_SetInfoPolicy);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetInfoPolicy, r);
+ }
+
+ r->out.result = _lsa_SetInfoPolicy(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetInfoPolicy, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_ClearAuditLog(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_ClearAuditLog *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CLEARAUDITLOG];
+
+ r = talloc(talloc_tos(), struct lsa_ClearAuditLog);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_ClearAuditLog, r);
+ }
+
+ r->out.result = _lsa_ClearAuditLog(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_ClearAuditLog, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_CreateAccount(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_CreateAccount *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CREATEACCOUNT];
+
+ r = talloc(talloc_tos(), struct lsa_CreateAccount);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CreateAccount, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.acct_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.acct_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_CreateAccount(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CreateAccount, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_EnumAccounts(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_EnumAccounts *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_ENUMACCOUNTS];
+
+ r = talloc(talloc_tos(), struct lsa_EnumAccounts);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_EnumAccounts, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.sids = talloc_zero(r, struct lsa_SidArray);
+ if (r->out.sids == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_EnumAccounts(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_EnumAccounts, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_CreateTrustedDomain(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_CreateTrustedDomain *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CREATETRUSTEDDOMAIN];
+
+ r = talloc(talloc_tos(), struct lsa_CreateTrustedDomain);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CreateTrustedDomain, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.trustdom_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.trustdom_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_CreateTrustedDomain(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CreateTrustedDomain, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_EnumTrustDom(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_EnumTrustDom *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_ENUMTRUSTDOM];
+
+ r = talloc(talloc_tos(), struct lsa_EnumTrustDom);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_EnumTrustDom, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.domains = talloc_zero(r, struct lsa_DomainList);
+ if (r->out.domains == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_EnumTrustDom(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_EnumTrustDom, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LookupNames(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LookupNames *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LOOKUPNAMES];
+
+ r = talloc(talloc_tos(), struct lsa_LookupNames);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupNames, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.domains = talloc_zero(r, struct lsa_RefDomainList *);
+ if (r->out.domains == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.sids = r->in.sids;
+ r->out.count = r->in.count;
+ r->out.result = _lsa_LookupNames(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupNames, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LookupSids(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LookupSids *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LOOKUPSIDS];
+
+ r = talloc(talloc_tos(), struct lsa_LookupSids);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupSids, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.domains = talloc_zero(r, struct lsa_RefDomainList *);
+ if (r->out.domains == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.names = r->in.names;
+ r->out.count = r->in.count;
+ r->out.result = _lsa_LookupSids(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupSids, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_CreateSecret(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_CreateSecret *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CREATESECRET];
+
+ r = talloc(talloc_tos(), struct lsa_CreateSecret);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CreateSecret, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.sec_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.sec_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_CreateSecret(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CreateSecret, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_OpenAccount(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_OpenAccount *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_OPENACCOUNT];
+
+ r = talloc(talloc_tos(), struct lsa_OpenAccount);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_OpenAccount, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.acct_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.acct_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_OpenAccount(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_OpenAccount, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_EnumPrivsAccount(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_EnumPrivsAccount *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_ENUMPRIVSACCOUNT];
+
+ r = talloc(talloc_tos(), struct lsa_EnumPrivsAccount);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_EnumPrivsAccount, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.privs = talloc_zero(r, struct lsa_PrivilegeSet *);
+ if (r->out.privs == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_EnumPrivsAccount(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_EnumPrivsAccount, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_AddPrivilegesToAccount(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_AddPrivilegesToAccount *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_ADDPRIVILEGESTOACCOUNT];
+
+ r = talloc(talloc_tos(), struct lsa_AddPrivilegesToAccount);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_AddPrivilegesToAccount, r);
+ }
+
+ r->out.result = _lsa_AddPrivilegesToAccount(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_AddPrivilegesToAccount, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_RemovePrivilegesFromAccount(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_RemovePrivilegesFromAccount *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_REMOVEPRIVILEGESFROMACCOUNT];
+
+ r = talloc(talloc_tos(), struct lsa_RemovePrivilegesFromAccount);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_RemovePrivilegesFromAccount, r);
+ }
+
+ r->out.result = _lsa_RemovePrivilegesFromAccount(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_RemovePrivilegesFromAccount, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_GetQuotasForAccount(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_GetQuotasForAccount *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_GETQUOTASFORACCOUNT];
+
+ r = talloc(talloc_tos(), struct lsa_GetQuotasForAccount);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_GetQuotasForAccount, r);
+ }
+
+ r->out.result = _lsa_GetQuotasForAccount(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_GetQuotasForAccount, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_SetQuotasForAccount(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_SetQuotasForAccount *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_SETQUOTASFORACCOUNT];
+
+ r = talloc(talloc_tos(), struct lsa_SetQuotasForAccount);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetQuotasForAccount, r);
+ }
+
+ r->out.result = _lsa_SetQuotasForAccount(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetQuotasForAccount, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_GetSystemAccessAccount(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_GetSystemAccessAccount *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_GETSYSTEMACCESSACCOUNT];
+
+ r = talloc(talloc_tos(), struct lsa_GetSystemAccessAccount);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_GetSystemAccessAccount, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.access_mask = talloc_zero(r, uint32_t);
+ if (r->out.access_mask == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_GetSystemAccessAccount(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_GetSystemAccessAccount, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_SetSystemAccessAccount(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_SetSystemAccessAccount *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_SETSYSTEMACCESSACCOUNT];
+
+ r = talloc(talloc_tos(), struct lsa_SetSystemAccessAccount);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetSystemAccessAccount, r);
+ }
+
+ r->out.result = _lsa_SetSystemAccessAccount(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetSystemAccessAccount, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_OpenTrustedDomain(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_OpenTrustedDomain *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_OPENTRUSTEDDOMAIN];
+
+ r = talloc(talloc_tos(), struct lsa_OpenTrustedDomain);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_OpenTrustedDomain, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.trustdom_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.trustdom_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_OpenTrustedDomain(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_OpenTrustedDomain, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_QueryTrustedDomainInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_QueryTrustedDomainInfo *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_QUERYTRUSTEDDOMAININFO];
+
+ r = talloc(talloc_tos(), struct lsa_QueryTrustedDomainInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_QueryTrustedDomainInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union lsa_TrustedDomainInfo *);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_QueryTrustedDomainInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_QueryTrustedDomainInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_SetInformationTrustedDomain(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_SetInformationTrustedDomain *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_SETINFORMATIONTRUSTEDDOMAIN];
+
+ r = talloc(talloc_tos(), struct lsa_SetInformationTrustedDomain);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetInformationTrustedDomain, r);
+ }
+
+ r->out.result = _lsa_SetInformationTrustedDomain(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetInformationTrustedDomain, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_OpenSecret(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_OpenSecret *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_OPENSECRET];
+
+ r = talloc(talloc_tos(), struct lsa_OpenSecret);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_OpenSecret, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.sec_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.sec_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_OpenSecret(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_OpenSecret, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_SetSecret(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_SetSecret *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_SETSECRET];
+
+ r = talloc(talloc_tos(), struct lsa_SetSecret);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetSecret, r);
+ }
+
+ r->out.result = _lsa_SetSecret(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetSecret, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_QuerySecret(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_QuerySecret *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_QUERYSECRET];
+
+ r = talloc(talloc_tos(), struct lsa_QuerySecret);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_QuerySecret, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.new_val = r->in.new_val;
+ r->out.new_mtime = r->in.new_mtime;
+ r->out.old_val = r->in.old_val;
+ r->out.old_mtime = r->in.old_mtime;
+ r->out.result = _lsa_QuerySecret(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_QuerySecret, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LookupPrivValue(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LookupPrivValue *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LOOKUPPRIVVALUE];
+
+ r = talloc(talloc_tos(), struct lsa_LookupPrivValue);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupPrivValue, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.luid = talloc_zero(r, struct lsa_LUID);
+ if (r->out.luid == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_LookupPrivValue(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupPrivValue, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LookupPrivName(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LookupPrivName *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LOOKUPPRIVNAME];
+
+ r = talloc(talloc_tos(), struct lsa_LookupPrivName);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupPrivName, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.name = talloc_zero(r, struct lsa_StringLarge *);
+ if (r->out.name == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_LookupPrivName(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupPrivName, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LookupPrivDisplayName(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LookupPrivDisplayName *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LOOKUPPRIVDISPLAYNAME];
+
+ r = talloc(talloc_tos(), struct lsa_LookupPrivDisplayName);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupPrivDisplayName, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.disp_name = talloc_zero(r, struct lsa_StringLarge *);
+ if (r->out.disp_name == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.returned_language_id = talloc_zero(r, uint16_t);
+ if (r->out.returned_language_id == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_LookupPrivDisplayName(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupPrivDisplayName, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_DeleteObject(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_DeleteObject *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_DELETEOBJECT];
+
+ r = talloc(talloc_tos(), struct lsa_DeleteObject);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_DeleteObject, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = r->in.handle;
+ r->out.result = _lsa_DeleteObject(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_DeleteObject, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_EnumAccountsWithUserRight(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_EnumAccountsWithUserRight *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_ENUMACCOUNTSWITHUSERRIGHT];
+
+ r = talloc(talloc_tos(), struct lsa_EnumAccountsWithUserRight);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_EnumAccountsWithUserRight, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.sids = talloc_zero(r, struct lsa_SidArray);
+ if (r->out.sids == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_EnumAccountsWithUserRight(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_EnumAccountsWithUserRight, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_EnumAccountRights(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_EnumAccountRights *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_ENUMACCOUNTRIGHTS];
+
+ r = talloc(talloc_tos(), struct lsa_EnumAccountRights);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_EnumAccountRights, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.rights = talloc_zero(r, struct lsa_RightSet);
+ if (r->out.rights == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_EnumAccountRights(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_EnumAccountRights, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_AddAccountRights(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_AddAccountRights *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_ADDACCOUNTRIGHTS];
+
+ r = talloc(talloc_tos(), struct lsa_AddAccountRights);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_AddAccountRights, r);
+ }
+
+ r->out.result = _lsa_AddAccountRights(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_AddAccountRights, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_RemoveAccountRights(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_RemoveAccountRights *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_REMOVEACCOUNTRIGHTS];
+
+ r = talloc(talloc_tos(), struct lsa_RemoveAccountRights);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_RemoveAccountRights, r);
+ }
+
+ r->out.result = _lsa_RemoveAccountRights(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_RemoveAccountRights, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_QueryTrustedDomainInfoBySid(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_QueryTrustedDomainInfoBySid *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_QUERYTRUSTEDDOMAININFOBYSID];
+
+ r = talloc(talloc_tos(), struct lsa_QueryTrustedDomainInfoBySid);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_QueryTrustedDomainInfoBySid, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union lsa_TrustedDomainInfo *);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_QueryTrustedDomainInfoBySid(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_QueryTrustedDomainInfoBySid, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_SetTrustedDomainInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_SetTrustedDomainInfo *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_SETTRUSTEDDOMAININFO];
+
+ r = talloc(talloc_tos(), struct lsa_SetTrustedDomainInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetTrustedDomainInfo, r);
+ }
+
+ r->out.result = _lsa_SetTrustedDomainInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetTrustedDomainInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_DeleteTrustedDomain(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_DeleteTrustedDomain *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_DELETETRUSTEDDOMAIN];
+
+ r = talloc(talloc_tos(), struct lsa_DeleteTrustedDomain);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_DeleteTrustedDomain, r);
+ }
+
+ r->out.result = _lsa_DeleteTrustedDomain(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_DeleteTrustedDomain, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_StorePrivateData(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_StorePrivateData *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_STOREPRIVATEDATA];
+
+ r = talloc(talloc_tos(), struct lsa_StorePrivateData);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_StorePrivateData, r);
+ }
+
+ r->out.result = _lsa_StorePrivateData(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_StorePrivateData, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_RetrievePrivateData(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_RetrievePrivateData *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_RETRIEVEPRIVATEDATA];
+
+ r = talloc(talloc_tos(), struct lsa_RetrievePrivateData);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_RetrievePrivateData, r);
+ }
+
+ r->out.result = _lsa_RetrievePrivateData(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_RetrievePrivateData, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_OpenPolicy2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_OpenPolicy2 *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_OPENPOLICY2];
+
+ r = talloc(talloc_tos(), struct lsa_OpenPolicy2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_OpenPolicy2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_OpenPolicy2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_OpenPolicy2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_GetUserName(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_GetUserName *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_GETUSERNAME];
+
+ r = talloc(talloc_tos(), struct lsa_GetUserName);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_GetUserName, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.account_name = r->in.account_name;
+ r->out.authority_name = r->in.authority_name;
+ r->out.result = _lsa_GetUserName(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_GetUserName, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_QueryInfoPolicy2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_QueryInfoPolicy2 *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_QUERYINFOPOLICY2];
+
+ r = talloc(talloc_tos(), struct lsa_QueryInfoPolicy2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_QueryInfoPolicy2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union lsa_PolicyInformation *);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_QueryInfoPolicy2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_QueryInfoPolicy2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_SetInfoPolicy2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_SetInfoPolicy2 *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_SETINFOPOLICY2];
+
+ r = talloc(talloc_tos(), struct lsa_SetInfoPolicy2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetInfoPolicy2, r);
+ }
+
+ r->out.result = _lsa_SetInfoPolicy2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetInfoPolicy2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_QueryTrustedDomainInfoByName(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_QueryTrustedDomainInfoByName *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_QUERYTRUSTEDDOMAININFOBYNAME];
+
+ r = talloc(talloc_tos(), struct lsa_QueryTrustedDomainInfoByName);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_QueryTrustedDomainInfoByName, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union lsa_TrustedDomainInfo *);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_QueryTrustedDomainInfoByName(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_QueryTrustedDomainInfoByName, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_SetTrustedDomainInfoByName(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_SetTrustedDomainInfoByName *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_SETTRUSTEDDOMAININFOBYNAME];
+
+ r = talloc(talloc_tos(), struct lsa_SetTrustedDomainInfoByName);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetTrustedDomainInfoByName, r);
+ }
+
+ r->out.result = _lsa_SetTrustedDomainInfoByName(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetTrustedDomainInfoByName, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_EnumTrustedDomainsEx(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_EnumTrustedDomainsEx *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_ENUMTRUSTEDDOMAINSEX];
+
+ r = talloc(talloc_tos(), struct lsa_EnumTrustedDomainsEx);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_EnumTrustedDomainsEx, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.domains = talloc_zero(r, struct lsa_DomainListEx);
+ if (r->out.domains == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_EnumTrustedDomainsEx(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_EnumTrustedDomainsEx, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_CreateTrustedDomainEx(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_CreateTrustedDomainEx *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CREATETRUSTEDDOMAINEX];
+
+ r = talloc(talloc_tos(), struct lsa_CreateTrustedDomainEx);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CreateTrustedDomainEx, r);
+ }
+
+ r->out.result = _lsa_CreateTrustedDomainEx(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CreateTrustedDomainEx, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_CloseTrustedDomainEx(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_CloseTrustedDomainEx *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CLOSETRUSTEDDOMAINEX];
+
+ r = talloc(talloc_tos(), struct lsa_CloseTrustedDomainEx);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CloseTrustedDomainEx, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = r->in.handle;
+ r->out.result = _lsa_CloseTrustedDomainEx(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CloseTrustedDomainEx, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_QueryDomainInformationPolicy(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_QueryDomainInformationPolicy *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_QUERYDOMAININFORMATIONPOLICY];
+
+ r = talloc(talloc_tos(), struct lsa_QueryDomainInformationPolicy);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_QueryDomainInformationPolicy, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union lsa_DomainInformationPolicy *);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_QueryDomainInformationPolicy(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_QueryDomainInformationPolicy, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_SetDomainInformationPolicy(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_SetDomainInformationPolicy *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_SETDOMAININFORMATIONPOLICY];
+
+ r = talloc(talloc_tos(), struct lsa_SetDomainInformationPolicy);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_SetDomainInformationPolicy, r);
+ }
+
+ r->out.result = _lsa_SetDomainInformationPolicy(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_SetDomainInformationPolicy, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_OpenTrustedDomainByName(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_OpenTrustedDomainByName *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_OPENTRUSTEDDOMAINBYNAME];
+
+ r = talloc(talloc_tos(), struct lsa_OpenTrustedDomainByName);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_OpenTrustedDomainByName, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.trustdom_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.trustdom_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_OpenTrustedDomainByName(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_OpenTrustedDomainByName, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_TestCall(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_TestCall *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_TESTCALL];
+
+ r = talloc(talloc_tos(), struct lsa_TestCall);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_TestCall, r);
+ }
+
+ r->out.result = _lsa_TestCall(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_TestCall, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LookupSids2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LookupSids2 *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LOOKUPSIDS2];
+
+ r = talloc(talloc_tos(), struct lsa_LookupSids2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupSids2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.domains = talloc_zero(r, struct lsa_RefDomainList *);
+ if (r->out.domains == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.names = r->in.names;
+ r->out.count = r->in.count;
+ r->out.result = _lsa_LookupSids2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupSids2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LookupNames2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LookupNames2 *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LOOKUPNAMES2];
+
+ r = talloc(talloc_tos(), struct lsa_LookupNames2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupNames2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.domains = talloc_zero(r, struct lsa_RefDomainList *);
+ if (r->out.domains == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.sids = r->in.sids;
+ r->out.count = r->in.count;
+ r->out.result = _lsa_LookupNames2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupNames2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_CreateTrustedDomainEx2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_CreateTrustedDomainEx2 *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CREATETRUSTEDDOMAINEX2];
+
+ r = talloc(talloc_tos(), struct lsa_CreateTrustedDomainEx2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CreateTrustedDomainEx2, r);
+ }
+
+ r->out.result = _lsa_CreateTrustedDomainEx2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CreateTrustedDomainEx2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_CREDRWRITE(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_CREDRWRITE *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CREDRWRITE];
+
+ r = talloc(talloc_tos(), struct lsa_CREDRWRITE);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRWRITE, r);
+ }
+
+ r->out.result = _lsa_CREDRWRITE(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRWRITE, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_CREDRREAD(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_CREDRREAD *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CREDRREAD];
+
+ r = talloc(talloc_tos(), struct lsa_CREDRREAD);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRREAD, r);
+ }
+
+ r->out.result = _lsa_CREDRREAD(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRREAD, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_CREDRENUMERATE(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_CREDRENUMERATE *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CREDRENUMERATE];
+
+ r = talloc(talloc_tos(), struct lsa_CREDRENUMERATE);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRENUMERATE, r);
+ }
+
+ r->out.result = _lsa_CREDRENUMERATE(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRENUMERATE, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_CREDRWRITEDOMAINCREDENTIALS(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_CREDRWRITEDOMAINCREDENTIALS *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CREDRWRITEDOMAINCREDENTIALS];
+
+ r = talloc(talloc_tos(), struct lsa_CREDRWRITEDOMAINCREDENTIALS);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRWRITEDOMAINCREDENTIALS, r);
+ }
+
+ r->out.result = _lsa_CREDRWRITEDOMAINCREDENTIALS(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRWRITEDOMAINCREDENTIALS, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_CREDRREADDOMAINCREDENTIALS(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_CREDRREADDOMAINCREDENTIALS *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CREDRREADDOMAINCREDENTIALS];
+
+ r = talloc(talloc_tos(), struct lsa_CREDRREADDOMAINCREDENTIALS);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRREADDOMAINCREDENTIALS, r);
+ }
+
+ r->out.result = _lsa_CREDRREADDOMAINCREDENTIALS(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRREADDOMAINCREDENTIALS, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_CREDRDELETE(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_CREDRDELETE *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CREDRDELETE];
+
+ r = talloc(talloc_tos(), struct lsa_CREDRDELETE);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRDELETE, r);
+ }
+
+ r->out.result = _lsa_CREDRDELETE(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRDELETE, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_CREDRGETTARGETINFO(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_CREDRGETTARGETINFO *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CREDRGETTARGETINFO];
+
+ r = talloc(talloc_tos(), struct lsa_CREDRGETTARGETINFO);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRGETTARGETINFO, r);
+ }
+
+ r->out.result = _lsa_CREDRGETTARGETINFO(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRGETTARGETINFO, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_CREDRPROFILELOADED(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_CREDRPROFILELOADED *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CREDRPROFILELOADED];
+
+ r = talloc(talloc_tos(), struct lsa_CREDRPROFILELOADED);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRPROFILELOADED, r);
+ }
+
+ r->out.result = _lsa_CREDRPROFILELOADED(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRPROFILELOADED, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LookupNames3(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LookupNames3 *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LOOKUPNAMES3];
+
+ r = talloc(talloc_tos(), struct lsa_LookupNames3);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupNames3, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.domains = talloc_zero(r, struct lsa_RefDomainList *);
+ if (r->out.domains == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.sids = r->in.sids;
+ r->out.count = r->in.count;
+ r->out.result = _lsa_LookupNames3(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupNames3, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_CREDRGETSESSIONTYPES(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_CREDRGETSESSIONTYPES *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CREDRGETSESSIONTYPES];
+
+ r = talloc(talloc_tos(), struct lsa_CREDRGETSESSIONTYPES);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRGETSESSIONTYPES, r);
+ }
+
+ r->out.result = _lsa_CREDRGETSESSIONTYPES(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRGETSESSIONTYPES, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LSARREGISTERAUDITEVENT(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LSARREGISTERAUDITEVENT *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LSARREGISTERAUDITEVENT];
+
+ r = talloc(talloc_tos(), struct lsa_LSARREGISTERAUDITEVENT);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LSARREGISTERAUDITEVENT, r);
+ }
+
+ r->out.result = _lsa_LSARREGISTERAUDITEVENT(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LSARREGISTERAUDITEVENT, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LSARGENAUDITEVENT(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LSARGENAUDITEVENT *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LSARGENAUDITEVENT];
+
+ r = talloc(talloc_tos(), struct lsa_LSARGENAUDITEVENT);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LSARGENAUDITEVENT, r);
+ }
+
+ r->out.result = _lsa_LSARGENAUDITEVENT(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LSARGENAUDITEVENT, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LSARUNREGISTERAUDITEVENT(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LSARUNREGISTERAUDITEVENT *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LSARUNREGISTERAUDITEVENT];
+
+ r = talloc(talloc_tos(), struct lsa_LSARUNREGISTERAUDITEVENT);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LSARUNREGISTERAUDITEVENT, r);
+ }
+
+ r->out.result = _lsa_LSARUNREGISTERAUDITEVENT(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LSARUNREGISTERAUDITEVENT, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_lsaRQueryForestTrustInformation(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_lsaRQueryForestTrustInformation *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LSARQUERYFORESTTRUSTINFORMATION];
+
+ r = talloc(talloc_tos(), struct lsa_lsaRQueryForestTrustInformation);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_lsaRQueryForestTrustInformation, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.forest_trust_info = talloc_zero(r, struct lsa_ForestTrustInformation *);
+ if (r->out.forest_trust_info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _lsa_lsaRQueryForestTrustInformation(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_lsaRQueryForestTrustInformation, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LSARSETFORESTTRUSTINFORMATION(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LSARSETFORESTTRUSTINFORMATION *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LSARSETFORESTTRUSTINFORMATION];
+
+ r = talloc(talloc_tos(), struct lsa_LSARSETFORESTTRUSTINFORMATION);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LSARSETFORESTTRUSTINFORMATION, r);
+ }
+
+ r->out.result = _lsa_LSARSETFORESTTRUSTINFORMATION(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LSARSETFORESTTRUSTINFORMATION, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_CREDRRENAME(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_CREDRRENAME *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_CREDRRENAME];
+
+ r = talloc(talloc_tos(), struct lsa_CREDRRENAME);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_CREDRRENAME, r);
+ }
+
+ r->out.result = _lsa_CREDRRENAME(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_CREDRRENAME, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LookupSids3(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LookupSids3 *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LOOKUPSIDS3];
+
+ r = talloc(talloc_tos(), struct lsa_LookupSids3);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupSids3, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.domains = talloc_zero(r, struct lsa_RefDomainList *);
+ if (r->out.domains == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.names = r->in.names;
+ r->out.count = r->in.count;
+ r->out.result = _lsa_LookupSids3(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupSids3, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LookupNames4(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LookupNames4 *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LOOKUPNAMES4];
+
+ r = talloc(talloc_tos(), struct lsa_LookupNames4);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LookupNames4, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.domains = talloc_zero(r, struct lsa_RefDomainList *);
+ if (r->out.domains == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.sids = r->in.sids;
+ r->out.count = r->in.count;
+ r->out.result = _lsa_LookupNames4(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LookupNames4, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LSAROPENPOLICYSCE(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LSAROPENPOLICYSCE *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LSAROPENPOLICYSCE];
+
+ r = talloc(talloc_tos(), struct lsa_LSAROPENPOLICYSCE);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LSAROPENPOLICYSCE, r);
+ }
+
+ r->out.result = _lsa_LSAROPENPOLICYSCE(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LSAROPENPOLICYSCE, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LSARADTREGISTERSECURITYEVENTSOURCE(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LSARADTREGISTERSECURITYEVENTSOURCE];
+
+ r = talloc(talloc_tos(), struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LSARADTREGISTERSECURITYEVENTSOURCE, r);
+ }
+
+ r->out.result = _lsa_LSARADTREGISTERSECURITYEVENTSOURCE(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LSARADTREGISTERSECURITYEVENTSOURCE, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LSARADTUNREGISTERSECURITYEVENTSOURCE];
+
+ r = talloc(talloc_tos(), struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE, r);
+ }
+
+ r->out.result = _lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_lsa_LSARADTREPORTSECURITYEVENT(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct lsa_LSARADTREPORTSECURITYEVENT *r;
+
+ call = &ndr_table_lsarpc.calls[NDR_LSA_LSARADTREPORTSECURITYEVENT];
+
+ r = talloc(talloc_tos(), struct lsa_LSARADTREPORTSECURITYEVENT);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(lsa_LSARADTREPORTSECURITYEVENT, r);
+ }
+
+ r->out.result = _lsa_LSARADTREPORTSECURITYEVENT(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(lsa_LSARADTREPORTSECURITYEVENT, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+
+/* Tables */
+static struct api_struct api_lsarpc_cmds[] =
+{
+ {"LSA_CLOSE", NDR_LSA_CLOSE, api_lsa_Close},
+ {"LSA_DELETE", NDR_LSA_DELETE, api_lsa_Delete},
+ {"LSA_ENUMPRIVS", NDR_LSA_ENUMPRIVS, api_lsa_EnumPrivs},
+ {"LSA_QUERYSECURITY", NDR_LSA_QUERYSECURITY, api_lsa_QuerySecurity},
+ {"LSA_SETSECOBJ", NDR_LSA_SETSECOBJ, api_lsa_SetSecObj},
+ {"LSA_CHANGEPASSWORD", NDR_LSA_CHANGEPASSWORD, api_lsa_ChangePassword},
+ {"LSA_OPENPOLICY", NDR_LSA_OPENPOLICY, api_lsa_OpenPolicy},
+ {"LSA_QUERYINFOPOLICY", NDR_LSA_QUERYINFOPOLICY, api_lsa_QueryInfoPolicy},
+ {"LSA_SETINFOPOLICY", NDR_LSA_SETINFOPOLICY, api_lsa_SetInfoPolicy},
+ {"LSA_CLEARAUDITLOG", NDR_LSA_CLEARAUDITLOG, api_lsa_ClearAuditLog},
+ {"LSA_CREATEACCOUNT", NDR_LSA_CREATEACCOUNT, api_lsa_CreateAccount},
+ {"LSA_ENUMACCOUNTS", NDR_LSA_ENUMACCOUNTS, api_lsa_EnumAccounts},
+ {"LSA_CREATETRUSTEDDOMAIN", NDR_LSA_CREATETRUSTEDDOMAIN, api_lsa_CreateTrustedDomain},
+ {"LSA_ENUMTRUSTDOM", NDR_LSA_ENUMTRUSTDOM, api_lsa_EnumTrustDom},
+ {"LSA_LOOKUPNAMES", NDR_LSA_LOOKUPNAMES, api_lsa_LookupNames},
+ {"LSA_LOOKUPSIDS", NDR_LSA_LOOKUPSIDS, api_lsa_LookupSids},
+ {"LSA_CREATESECRET", NDR_LSA_CREATESECRET, api_lsa_CreateSecret},
+ {"LSA_OPENACCOUNT", NDR_LSA_OPENACCOUNT, api_lsa_OpenAccount},
+ {"LSA_ENUMPRIVSACCOUNT", NDR_LSA_ENUMPRIVSACCOUNT, api_lsa_EnumPrivsAccount},
+ {"LSA_ADDPRIVILEGESTOACCOUNT", NDR_LSA_ADDPRIVILEGESTOACCOUNT, api_lsa_AddPrivilegesToAccount},
+ {"LSA_REMOVEPRIVILEGESFROMACCOUNT", NDR_LSA_REMOVEPRIVILEGESFROMACCOUNT, api_lsa_RemovePrivilegesFromAccount},
+ {"LSA_GETQUOTASFORACCOUNT", NDR_LSA_GETQUOTASFORACCOUNT, api_lsa_GetQuotasForAccount},
+ {"LSA_SETQUOTASFORACCOUNT", NDR_LSA_SETQUOTASFORACCOUNT, api_lsa_SetQuotasForAccount},
+ {"LSA_GETSYSTEMACCESSACCOUNT", NDR_LSA_GETSYSTEMACCESSACCOUNT, api_lsa_GetSystemAccessAccount},
+ {"LSA_SETSYSTEMACCESSACCOUNT", NDR_LSA_SETSYSTEMACCESSACCOUNT, api_lsa_SetSystemAccessAccount},
+ {"LSA_OPENTRUSTEDDOMAIN", NDR_LSA_OPENTRUSTEDDOMAIN, api_lsa_OpenTrustedDomain},
+ {"LSA_QUERYTRUSTEDDOMAININFO", NDR_LSA_QUERYTRUSTEDDOMAININFO, api_lsa_QueryTrustedDomainInfo},
+ {"LSA_SETINFORMATIONTRUSTEDDOMAIN", NDR_LSA_SETINFORMATIONTRUSTEDDOMAIN, api_lsa_SetInformationTrustedDomain},
+ {"LSA_OPENSECRET", NDR_LSA_OPENSECRET, api_lsa_OpenSecret},
+ {"LSA_SETSECRET", NDR_LSA_SETSECRET, api_lsa_SetSecret},
+ {"LSA_QUERYSECRET", NDR_LSA_QUERYSECRET, api_lsa_QuerySecret},
+ {"LSA_LOOKUPPRIVVALUE", NDR_LSA_LOOKUPPRIVVALUE, api_lsa_LookupPrivValue},
+ {"LSA_LOOKUPPRIVNAME", NDR_LSA_LOOKUPPRIVNAME, api_lsa_LookupPrivName},
+ {"LSA_LOOKUPPRIVDISPLAYNAME", NDR_LSA_LOOKUPPRIVDISPLAYNAME, api_lsa_LookupPrivDisplayName},
+ {"LSA_DELETEOBJECT", NDR_LSA_DELETEOBJECT, api_lsa_DeleteObject},
+ {"LSA_ENUMACCOUNTSWITHUSERRIGHT", NDR_LSA_ENUMACCOUNTSWITHUSERRIGHT, api_lsa_EnumAccountsWithUserRight},
+ {"LSA_ENUMACCOUNTRIGHTS", NDR_LSA_ENUMACCOUNTRIGHTS, api_lsa_EnumAccountRights},
+ {"LSA_ADDACCOUNTRIGHTS", NDR_LSA_ADDACCOUNTRIGHTS, api_lsa_AddAccountRights},
+ {"LSA_REMOVEACCOUNTRIGHTS", NDR_LSA_REMOVEACCOUNTRIGHTS, api_lsa_RemoveAccountRights},
+ {"LSA_QUERYTRUSTEDDOMAININFOBYSID", NDR_LSA_QUERYTRUSTEDDOMAININFOBYSID, api_lsa_QueryTrustedDomainInfoBySid},
+ {"LSA_SETTRUSTEDDOMAININFO", NDR_LSA_SETTRUSTEDDOMAININFO, api_lsa_SetTrustedDomainInfo},
+ {"LSA_DELETETRUSTEDDOMAIN", NDR_LSA_DELETETRUSTEDDOMAIN, api_lsa_DeleteTrustedDomain},
+ {"LSA_STOREPRIVATEDATA", NDR_LSA_STOREPRIVATEDATA, api_lsa_StorePrivateData},
+ {"LSA_RETRIEVEPRIVATEDATA", NDR_LSA_RETRIEVEPRIVATEDATA, api_lsa_RetrievePrivateData},
+ {"LSA_OPENPOLICY2", NDR_LSA_OPENPOLICY2, api_lsa_OpenPolicy2},
+ {"LSA_GETUSERNAME", NDR_LSA_GETUSERNAME, api_lsa_GetUserName},
+ {"LSA_QUERYINFOPOLICY2", NDR_LSA_QUERYINFOPOLICY2, api_lsa_QueryInfoPolicy2},
+ {"LSA_SETINFOPOLICY2", NDR_LSA_SETINFOPOLICY2, api_lsa_SetInfoPolicy2},
+ {"LSA_QUERYTRUSTEDDOMAININFOBYNAME", NDR_LSA_QUERYTRUSTEDDOMAININFOBYNAME, api_lsa_QueryTrustedDomainInfoByName},
+ {"LSA_SETTRUSTEDDOMAININFOBYNAME", NDR_LSA_SETTRUSTEDDOMAININFOBYNAME, api_lsa_SetTrustedDomainInfoByName},
+ {"LSA_ENUMTRUSTEDDOMAINSEX", NDR_LSA_ENUMTRUSTEDDOMAINSEX, api_lsa_EnumTrustedDomainsEx},
+ {"LSA_CREATETRUSTEDDOMAINEX", NDR_LSA_CREATETRUSTEDDOMAINEX, api_lsa_CreateTrustedDomainEx},
+ {"LSA_CLOSETRUSTEDDOMAINEX", NDR_LSA_CLOSETRUSTEDDOMAINEX, api_lsa_CloseTrustedDomainEx},
+ {"LSA_QUERYDOMAININFORMATIONPOLICY", NDR_LSA_QUERYDOMAININFORMATIONPOLICY, api_lsa_QueryDomainInformationPolicy},
+ {"LSA_SETDOMAININFORMATIONPOLICY", NDR_LSA_SETDOMAININFORMATIONPOLICY, api_lsa_SetDomainInformationPolicy},
+ {"LSA_OPENTRUSTEDDOMAINBYNAME", NDR_LSA_OPENTRUSTEDDOMAINBYNAME, api_lsa_OpenTrustedDomainByName},
+ {"LSA_TESTCALL", NDR_LSA_TESTCALL, api_lsa_TestCall},
+ {"LSA_LOOKUPSIDS2", NDR_LSA_LOOKUPSIDS2, api_lsa_LookupSids2},
+ {"LSA_LOOKUPNAMES2", NDR_LSA_LOOKUPNAMES2, api_lsa_LookupNames2},
+ {"LSA_CREATETRUSTEDDOMAINEX2", NDR_LSA_CREATETRUSTEDDOMAINEX2, api_lsa_CreateTrustedDomainEx2},
+ {"LSA_CREDRWRITE", NDR_LSA_CREDRWRITE, api_lsa_CREDRWRITE},
+ {"LSA_CREDRREAD", NDR_LSA_CREDRREAD, api_lsa_CREDRREAD},
+ {"LSA_CREDRENUMERATE", NDR_LSA_CREDRENUMERATE, api_lsa_CREDRENUMERATE},
+ {"LSA_CREDRWRITEDOMAINCREDENTIALS", NDR_LSA_CREDRWRITEDOMAINCREDENTIALS, api_lsa_CREDRWRITEDOMAINCREDENTIALS},
+ {"LSA_CREDRREADDOMAINCREDENTIALS", NDR_LSA_CREDRREADDOMAINCREDENTIALS, api_lsa_CREDRREADDOMAINCREDENTIALS},
+ {"LSA_CREDRDELETE", NDR_LSA_CREDRDELETE, api_lsa_CREDRDELETE},
+ {"LSA_CREDRGETTARGETINFO", NDR_LSA_CREDRGETTARGETINFO, api_lsa_CREDRGETTARGETINFO},
+ {"LSA_CREDRPROFILELOADED", NDR_LSA_CREDRPROFILELOADED, api_lsa_CREDRPROFILELOADED},
+ {"LSA_LOOKUPNAMES3", NDR_LSA_LOOKUPNAMES3, api_lsa_LookupNames3},
+ {"LSA_CREDRGETSESSIONTYPES", NDR_LSA_CREDRGETSESSIONTYPES, api_lsa_CREDRGETSESSIONTYPES},
+ {"LSA_LSARREGISTERAUDITEVENT", NDR_LSA_LSARREGISTERAUDITEVENT, api_lsa_LSARREGISTERAUDITEVENT},
+ {"LSA_LSARGENAUDITEVENT", NDR_LSA_LSARGENAUDITEVENT, api_lsa_LSARGENAUDITEVENT},
+ {"LSA_LSARUNREGISTERAUDITEVENT", NDR_LSA_LSARUNREGISTERAUDITEVENT, api_lsa_LSARUNREGISTERAUDITEVENT},
+ {"LSA_LSARQUERYFORESTTRUSTINFORMATION", NDR_LSA_LSARQUERYFORESTTRUSTINFORMATION, api_lsa_lsaRQueryForestTrustInformation},
+ {"LSA_LSARSETFORESTTRUSTINFORMATION", NDR_LSA_LSARSETFORESTTRUSTINFORMATION, api_lsa_LSARSETFORESTTRUSTINFORMATION},
+ {"LSA_CREDRRENAME", NDR_LSA_CREDRRENAME, api_lsa_CREDRRENAME},
+ {"LSA_LOOKUPSIDS3", NDR_LSA_LOOKUPSIDS3, api_lsa_LookupSids3},
+ {"LSA_LOOKUPNAMES4", NDR_LSA_LOOKUPNAMES4, api_lsa_LookupNames4},
+ {"LSA_LSAROPENPOLICYSCE", NDR_LSA_LSAROPENPOLICYSCE, api_lsa_LSAROPENPOLICYSCE},
+ {"LSA_LSARADTREGISTERSECURITYEVENTSOURCE", NDR_LSA_LSARADTREGISTERSECURITYEVENTSOURCE, api_lsa_LSARADTREGISTERSECURITYEVENTSOURCE},
+ {"LSA_LSARADTUNREGISTERSECURITYEVENTSOURCE", NDR_LSA_LSARADTUNREGISTERSECURITYEVENTSOURCE, api_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE},
+ {"LSA_LSARADTREPORTSECURITYEVENT", NDR_LSA_LSARADTREPORTSECURITYEVENT, api_lsa_LSARADTREPORTSECURITYEVENT},
+};
+
+void lsarpc_get_pipe_fns(struct api_struct **fns, int *n_fns)
+{
+ *fns = api_lsarpc_cmds;
+ *n_fns = sizeof(api_lsarpc_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_lsarpc_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "lsarpc", "lsarpc", &ndr_table_lsarpc.syntax_id, api_lsarpc_cmds, sizeof(api_lsarpc_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/librpc/gen_ndr/srv_lsa.h b/source3/librpc/gen_ndr/srv_lsa.h
new file mode 100644
index 0000000000..223ee5e970
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_lsa.h
@@ -0,0 +1,88 @@
+#include "librpc/gen_ndr/ndr_lsa.h"
+#ifndef __SRV_LSARPC__
+#define __SRV_LSARPC__
+NTSTATUS _lsa_Close(pipes_struct *p, struct lsa_Close *r);
+NTSTATUS _lsa_Delete(pipes_struct *p, struct lsa_Delete *r);
+NTSTATUS _lsa_EnumPrivs(pipes_struct *p, struct lsa_EnumPrivs *r);
+NTSTATUS _lsa_QuerySecurity(pipes_struct *p, struct lsa_QuerySecurity *r);
+NTSTATUS _lsa_SetSecObj(pipes_struct *p, struct lsa_SetSecObj *r);
+NTSTATUS _lsa_ChangePassword(pipes_struct *p, struct lsa_ChangePassword *r);
+NTSTATUS _lsa_OpenPolicy(pipes_struct *p, struct lsa_OpenPolicy *r);
+NTSTATUS _lsa_QueryInfoPolicy(pipes_struct *p, struct lsa_QueryInfoPolicy *r);
+NTSTATUS _lsa_SetInfoPolicy(pipes_struct *p, struct lsa_SetInfoPolicy *r);
+NTSTATUS _lsa_ClearAuditLog(pipes_struct *p, struct lsa_ClearAuditLog *r);
+NTSTATUS _lsa_CreateAccount(pipes_struct *p, struct lsa_CreateAccount *r);
+NTSTATUS _lsa_EnumAccounts(pipes_struct *p, struct lsa_EnumAccounts *r);
+NTSTATUS _lsa_CreateTrustedDomain(pipes_struct *p, struct lsa_CreateTrustedDomain *r);
+NTSTATUS _lsa_EnumTrustDom(pipes_struct *p, struct lsa_EnumTrustDom *r);
+NTSTATUS _lsa_LookupNames(pipes_struct *p, struct lsa_LookupNames *r);
+NTSTATUS _lsa_LookupSids(pipes_struct *p, struct lsa_LookupSids *r);
+NTSTATUS _lsa_CreateSecret(pipes_struct *p, struct lsa_CreateSecret *r);
+NTSTATUS _lsa_OpenAccount(pipes_struct *p, struct lsa_OpenAccount *r);
+NTSTATUS _lsa_EnumPrivsAccount(pipes_struct *p, struct lsa_EnumPrivsAccount *r);
+NTSTATUS _lsa_AddPrivilegesToAccount(pipes_struct *p, struct lsa_AddPrivilegesToAccount *r);
+NTSTATUS _lsa_RemovePrivilegesFromAccount(pipes_struct *p, struct lsa_RemovePrivilegesFromAccount *r);
+NTSTATUS _lsa_GetQuotasForAccount(pipes_struct *p, struct lsa_GetQuotasForAccount *r);
+NTSTATUS _lsa_SetQuotasForAccount(pipes_struct *p, struct lsa_SetQuotasForAccount *r);
+NTSTATUS _lsa_GetSystemAccessAccount(pipes_struct *p, struct lsa_GetSystemAccessAccount *r);
+NTSTATUS _lsa_SetSystemAccessAccount(pipes_struct *p, struct lsa_SetSystemAccessAccount *r);
+NTSTATUS _lsa_OpenTrustedDomain(pipes_struct *p, struct lsa_OpenTrustedDomain *r);
+NTSTATUS _lsa_QueryTrustedDomainInfo(pipes_struct *p, struct lsa_QueryTrustedDomainInfo *r);
+NTSTATUS _lsa_SetInformationTrustedDomain(pipes_struct *p, struct lsa_SetInformationTrustedDomain *r);
+NTSTATUS _lsa_OpenSecret(pipes_struct *p, struct lsa_OpenSecret *r);
+NTSTATUS _lsa_SetSecret(pipes_struct *p, struct lsa_SetSecret *r);
+NTSTATUS _lsa_QuerySecret(pipes_struct *p, struct lsa_QuerySecret *r);
+NTSTATUS _lsa_LookupPrivValue(pipes_struct *p, struct lsa_LookupPrivValue *r);
+NTSTATUS _lsa_LookupPrivName(pipes_struct *p, struct lsa_LookupPrivName *r);
+NTSTATUS _lsa_LookupPrivDisplayName(pipes_struct *p, struct lsa_LookupPrivDisplayName *r);
+NTSTATUS _lsa_DeleteObject(pipes_struct *p, struct lsa_DeleteObject *r);
+NTSTATUS _lsa_EnumAccountsWithUserRight(pipes_struct *p, struct lsa_EnumAccountsWithUserRight *r);
+NTSTATUS _lsa_EnumAccountRights(pipes_struct *p, struct lsa_EnumAccountRights *r);
+NTSTATUS _lsa_AddAccountRights(pipes_struct *p, struct lsa_AddAccountRights *r);
+NTSTATUS _lsa_RemoveAccountRights(pipes_struct *p, struct lsa_RemoveAccountRights *r);
+NTSTATUS _lsa_QueryTrustedDomainInfoBySid(pipes_struct *p, struct lsa_QueryTrustedDomainInfoBySid *r);
+NTSTATUS _lsa_SetTrustedDomainInfo(pipes_struct *p, struct lsa_SetTrustedDomainInfo *r);
+NTSTATUS _lsa_DeleteTrustedDomain(pipes_struct *p, struct lsa_DeleteTrustedDomain *r);
+NTSTATUS _lsa_StorePrivateData(pipes_struct *p, struct lsa_StorePrivateData *r);
+NTSTATUS _lsa_RetrievePrivateData(pipes_struct *p, struct lsa_RetrievePrivateData *r);
+NTSTATUS _lsa_OpenPolicy2(pipes_struct *p, struct lsa_OpenPolicy2 *r);
+NTSTATUS _lsa_GetUserName(pipes_struct *p, struct lsa_GetUserName *r);
+NTSTATUS _lsa_QueryInfoPolicy2(pipes_struct *p, struct lsa_QueryInfoPolicy2 *r);
+NTSTATUS _lsa_SetInfoPolicy2(pipes_struct *p, struct lsa_SetInfoPolicy2 *r);
+NTSTATUS _lsa_QueryTrustedDomainInfoByName(pipes_struct *p, struct lsa_QueryTrustedDomainInfoByName *r);
+NTSTATUS _lsa_SetTrustedDomainInfoByName(pipes_struct *p, struct lsa_SetTrustedDomainInfoByName *r);
+NTSTATUS _lsa_EnumTrustedDomainsEx(pipes_struct *p, struct lsa_EnumTrustedDomainsEx *r);
+NTSTATUS _lsa_CreateTrustedDomainEx(pipes_struct *p, struct lsa_CreateTrustedDomainEx *r);
+NTSTATUS _lsa_CloseTrustedDomainEx(pipes_struct *p, struct lsa_CloseTrustedDomainEx *r);
+NTSTATUS _lsa_QueryDomainInformationPolicy(pipes_struct *p, struct lsa_QueryDomainInformationPolicy *r);
+NTSTATUS _lsa_SetDomainInformationPolicy(pipes_struct *p, struct lsa_SetDomainInformationPolicy *r);
+NTSTATUS _lsa_OpenTrustedDomainByName(pipes_struct *p, struct lsa_OpenTrustedDomainByName *r);
+NTSTATUS _lsa_TestCall(pipes_struct *p, struct lsa_TestCall *r);
+NTSTATUS _lsa_LookupSids2(pipes_struct *p, struct lsa_LookupSids2 *r);
+NTSTATUS _lsa_LookupNames2(pipes_struct *p, struct lsa_LookupNames2 *r);
+NTSTATUS _lsa_CreateTrustedDomainEx2(pipes_struct *p, struct lsa_CreateTrustedDomainEx2 *r);
+NTSTATUS _lsa_CREDRWRITE(pipes_struct *p, struct lsa_CREDRWRITE *r);
+NTSTATUS _lsa_CREDRREAD(pipes_struct *p, struct lsa_CREDRREAD *r);
+NTSTATUS _lsa_CREDRENUMERATE(pipes_struct *p, struct lsa_CREDRENUMERATE *r);
+NTSTATUS _lsa_CREDRWRITEDOMAINCREDENTIALS(pipes_struct *p, struct lsa_CREDRWRITEDOMAINCREDENTIALS *r);
+NTSTATUS _lsa_CREDRREADDOMAINCREDENTIALS(pipes_struct *p, struct lsa_CREDRREADDOMAINCREDENTIALS *r);
+NTSTATUS _lsa_CREDRDELETE(pipes_struct *p, struct lsa_CREDRDELETE *r);
+NTSTATUS _lsa_CREDRGETTARGETINFO(pipes_struct *p, struct lsa_CREDRGETTARGETINFO *r);
+NTSTATUS _lsa_CREDRPROFILELOADED(pipes_struct *p, struct lsa_CREDRPROFILELOADED *r);
+NTSTATUS _lsa_LookupNames3(pipes_struct *p, struct lsa_LookupNames3 *r);
+NTSTATUS _lsa_CREDRGETSESSIONTYPES(pipes_struct *p, struct lsa_CREDRGETSESSIONTYPES *r);
+NTSTATUS _lsa_LSARREGISTERAUDITEVENT(pipes_struct *p, struct lsa_LSARREGISTERAUDITEVENT *r);
+NTSTATUS _lsa_LSARGENAUDITEVENT(pipes_struct *p, struct lsa_LSARGENAUDITEVENT *r);
+NTSTATUS _lsa_LSARUNREGISTERAUDITEVENT(pipes_struct *p, struct lsa_LSARUNREGISTERAUDITEVENT *r);
+NTSTATUS _lsa_lsaRQueryForestTrustInformation(pipes_struct *p, struct lsa_lsaRQueryForestTrustInformation *r);
+NTSTATUS _lsa_LSARSETFORESTTRUSTINFORMATION(pipes_struct *p, struct lsa_LSARSETFORESTTRUSTINFORMATION *r);
+NTSTATUS _lsa_CREDRRENAME(pipes_struct *p, struct lsa_CREDRRENAME *r);
+NTSTATUS _lsa_LookupSids3(pipes_struct *p, struct lsa_LookupSids3 *r);
+NTSTATUS _lsa_LookupNames4(pipes_struct *p, struct lsa_LookupNames4 *r);
+NTSTATUS _lsa_LSAROPENPOLICYSCE(pipes_struct *p, struct lsa_LSAROPENPOLICYSCE *r);
+NTSTATUS _lsa_LSARADTREGISTERSECURITYEVENTSOURCE(pipes_struct *p, struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE *r);
+NTSTATUS _lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(pipes_struct *p, struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE *r);
+NTSTATUS _lsa_LSARADTREPORTSECURITYEVENT(pipes_struct *p, struct lsa_LSARADTREPORTSECURITYEVENT *r);
+void lsarpc_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_lsarpc_init(void);
+#endif /* __SRV_LSARPC__ */
diff --git a/source3/librpc/gen_ndr/srv_netlogon.c b/source3/librpc/gen_ndr/srv_netlogon.c
new file mode 100644
index 0000000000..154ef71d40
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_netlogon.c
@@ -0,0 +1,3866 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * server auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/srv_netlogon.h"
+
+static bool api_netr_LogonUasLogon(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_LogonUasLogon *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_LOGONUASLOGON];
+
+ r = talloc(talloc_tos(), struct netr_LogonUasLogon);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonUasLogon, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, struct netr_UasInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_LogonUasLogon(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonUasLogon, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_LogonUasLogoff(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_LogonUasLogoff *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_LOGONUASLOGOFF];
+
+ r = talloc(talloc_tos(), struct netr_LogonUasLogoff);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonUasLogoff, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, struct netr_UasLogoffInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_LogonUasLogoff(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonUasLogoff, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_LogonSamLogon(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_LogonSamLogon *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_LOGONSAMLOGON];
+
+ r = talloc(talloc_tos(), struct netr_LogonSamLogon);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonSamLogon, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_authenticator = r->in.return_authenticator;
+ r->out.validation = talloc_zero(r, union netr_Validation);
+ if (r->out.validation == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.authoritative = talloc_zero(r, uint8_t);
+ if (r->out.authoritative == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_LogonSamLogon(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonSamLogon, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_LogonSamLogoff(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_LogonSamLogoff *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_LOGONSAMLOGOFF];
+
+ r = talloc(talloc_tos(), struct netr_LogonSamLogoff);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonSamLogoff, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_authenticator = r->in.return_authenticator;
+ r->out.result = _netr_LogonSamLogoff(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonSamLogoff, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_ServerReqChallenge(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_ServerReqChallenge *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_SERVERREQCHALLENGE];
+
+ r = talloc(talloc_tos(), struct netr_ServerReqChallenge);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_ServerReqChallenge, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_credentials = talloc_zero(r, struct netr_Credential);
+ if (r->out.return_credentials == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_ServerReqChallenge(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_ServerReqChallenge, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_ServerAuthenticate(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_ServerAuthenticate *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_SERVERAUTHENTICATE];
+
+ r = talloc(talloc_tos(), struct netr_ServerAuthenticate);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_ServerAuthenticate, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_credentials = talloc_zero(r, struct netr_Credential);
+ if (r->out.return_credentials == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_ServerAuthenticate(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_ServerAuthenticate, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_ServerPasswordSet(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_ServerPasswordSet *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_SERVERPASSWORDSET];
+
+ r = talloc(talloc_tos(), struct netr_ServerPasswordSet);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_ServerPasswordSet, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_authenticator = talloc_zero(r, struct netr_Authenticator);
+ if (r->out.return_authenticator == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_ServerPasswordSet(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_ServerPasswordSet, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_DatabaseDeltas(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_DatabaseDeltas *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_DATABASEDELTAS];
+
+ r = talloc(talloc_tos(), struct netr_DatabaseDeltas);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DatabaseDeltas, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_authenticator = r->in.return_authenticator;
+ r->out.sequence_num = r->in.sequence_num;
+ r->out.delta_enum_array = talloc_zero(r, struct netr_DELTA_ENUM_ARRAY *);
+ if (r->out.delta_enum_array == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_DatabaseDeltas(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DatabaseDeltas, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_DatabaseSync(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_DatabaseSync *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_DATABASESYNC];
+
+ r = talloc(talloc_tos(), struct netr_DatabaseSync);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DatabaseSync, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_authenticator = r->in.return_authenticator;
+ r->out.sync_context = r->in.sync_context;
+ r->out.delta_enum_array = talloc_zero(r, struct netr_DELTA_ENUM_ARRAY);
+ if (r->out.delta_enum_array == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_DatabaseSync(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DatabaseSync, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_AccountDeltas(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_AccountDeltas *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_ACCOUNTDELTAS];
+
+ r = talloc(talloc_tos(), struct netr_AccountDeltas);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_AccountDeltas, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_authenticator = r->in.return_authenticator;
+ r->out.buffer = talloc_zero(r, struct netr_AccountBuffer);
+ if (r->out.buffer == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.count_returned = talloc_zero(r, uint32_t);
+ if (r->out.count_returned == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.total_entries = talloc_zero(r, uint32_t);
+ if (r->out.total_entries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.recordid = talloc_zero(r, struct netr_UAS_INFO_0);
+ if (r->out.recordid == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_AccountDeltas(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_AccountDeltas, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_AccountSync(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_AccountSync *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_ACCOUNTSYNC];
+
+ r = talloc(talloc_tos(), struct netr_AccountSync);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_AccountSync, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_authenticator = r->in.return_authenticator;
+ r->out.buffer = talloc_zero(r, struct netr_AccountBuffer);
+ if (r->out.buffer == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.count_returned = talloc_zero(r, uint32_t);
+ if (r->out.count_returned == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.total_entries = talloc_zero(r, uint32_t);
+ if (r->out.total_entries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.next_reference = talloc_zero(r, uint32_t);
+ if (r->out.next_reference == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.recordid = r->in.recordid;
+ r->out.result = _netr_AccountSync(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_AccountSync, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_GetDcName(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_GetDcName *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_GETDCNAME];
+
+ r = talloc(talloc_tos(), struct netr_GetDcName);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_GetDcName, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.dcname = talloc_zero(r, const char *);
+ if (r->out.dcname == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_GetDcName(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_GetDcName, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_LogonControl(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_LogonControl *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_LOGONCONTROL];
+
+ r = talloc(talloc_tos(), struct netr_LogonControl);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonControl, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union netr_CONTROL_QUERY_INFORMATION);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_LogonControl(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonControl, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_GetAnyDCName(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_GetAnyDCName *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_GETANYDCNAME];
+
+ r = talloc(talloc_tos(), struct netr_GetAnyDCName);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_GetAnyDCName, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.dcname = talloc_zero(r, const char *);
+ if (r->out.dcname == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_GetAnyDCName(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_GetAnyDCName, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_LogonControl2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_LogonControl2 *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_LOGONCONTROL2];
+
+ r = talloc(talloc_tos(), struct netr_LogonControl2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonControl2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.query = talloc_zero(r, union netr_CONTROL_QUERY_INFORMATION);
+ if (r->out.query == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_LogonControl2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonControl2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_ServerAuthenticate2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_ServerAuthenticate2 *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_SERVERAUTHENTICATE2];
+
+ r = talloc(talloc_tos(), struct netr_ServerAuthenticate2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_ServerAuthenticate2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_credentials = talloc_zero(r, struct netr_Credential);
+ if (r->out.return_credentials == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.negotiate_flags = r->in.negotiate_flags;
+ r->out.result = _netr_ServerAuthenticate2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_ServerAuthenticate2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_DatabaseSync2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_DatabaseSync2 *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_DATABASESYNC2];
+
+ r = talloc(talloc_tos(), struct netr_DatabaseSync2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DatabaseSync2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_authenticator = r->in.return_authenticator;
+ r->out.sync_context = r->in.sync_context;
+ r->out.delta_enum_array = talloc_zero(r, struct netr_DELTA_ENUM_ARRAY *);
+ if (r->out.delta_enum_array == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_DatabaseSync2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DatabaseSync2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_DatabaseRedo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_DatabaseRedo *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_DATABASEREDO];
+
+ r = talloc(talloc_tos(), struct netr_DatabaseRedo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DatabaseRedo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_authenticator = r->in.return_authenticator;
+ r->out.delta_enum_array = talloc_zero(r, struct netr_DELTA_ENUM_ARRAY);
+ if (r->out.delta_enum_array == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_DatabaseRedo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DatabaseRedo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_LogonControl2Ex(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_LogonControl2Ex *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_LOGONCONTROL2EX];
+
+ r = talloc(talloc_tos(), struct netr_LogonControl2Ex);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonControl2Ex, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.query = talloc_zero(r, union netr_CONTROL_QUERY_INFORMATION);
+ if (r->out.query == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_LogonControl2Ex(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonControl2Ex, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_NetrEnumerateTrustedDomains(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_NetrEnumerateTrustedDomains *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_NETRENUMERATETRUSTEDDOMAINS];
+
+ r = talloc(talloc_tos(), struct netr_NetrEnumerateTrustedDomains);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NetrEnumerateTrustedDomains, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.trusted_domains_blob = talloc_zero(r, struct netr_Blob);
+ if (r->out.trusted_domains_blob == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_NetrEnumerateTrustedDomains(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NetrEnumerateTrustedDomains, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_DsRGetDCName(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_DsRGetDCName *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_DSRGETDCNAME];
+
+ r = talloc(talloc_tos(), struct netr_DsRGetDCName);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsRGetDCName, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, struct netr_DsRGetDCNameInfo *);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_DsRGetDCName(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsRGetDCName, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_NETRLOGONDUMMYROUTINE1(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_NETRLOGONDUMMYROUTINE1 *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_NETRLOGONDUMMYROUTINE1];
+
+ r = talloc(talloc_tos(), struct netr_NETRLOGONDUMMYROUTINE1);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NETRLOGONDUMMYROUTINE1, r);
+ }
+
+ r->out.result = _netr_NETRLOGONDUMMYROUTINE1(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NETRLOGONDUMMYROUTINE1, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_NETRLOGONSETSERVICEBITS(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_NETRLOGONSETSERVICEBITS *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_NETRLOGONSETSERVICEBITS];
+
+ r = talloc(talloc_tos(), struct netr_NETRLOGONSETSERVICEBITS);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NETRLOGONSETSERVICEBITS, r);
+ }
+
+ r->out.result = _netr_NETRLOGONSETSERVICEBITS(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NETRLOGONSETSERVICEBITS, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_LogonGetTrustRid(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_LogonGetTrustRid *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_LOGONGETTRUSTRID];
+
+ r = talloc(talloc_tos(), struct netr_LogonGetTrustRid);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonGetTrustRid, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.rid = talloc_zero(r, uint32_t);
+ if (r->out.rid == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_LogonGetTrustRid(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonGetTrustRid, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_NETRLOGONCOMPUTESERVERDIGEST(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_NETRLOGONCOMPUTESERVERDIGEST *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_NETRLOGONCOMPUTESERVERDIGEST];
+
+ r = talloc(talloc_tos(), struct netr_NETRLOGONCOMPUTESERVERDIGEST);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NETRLOGONCOMPUTESERVERDIGEST, r);
+ }
+
+ r->out.result = _netr_NETRLOGONCOMPUTESERVERDIGEST(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NETRLOGONCOMPUTESERVERDIGEST, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_NETRLOGONCOMPUTECLIENTDIGEST(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_NETRLOGONCOMPUTECLIENTDIGEST *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_NETRLOGONCOMPUTECLIENTDIGEST];
+
+ r = talloc(talloc_tos(), struct netr_NETRLOGONCOMPUTECLIENTDIGEST);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NETRLOGONCOMPUTECLIENTDIGEST, r);
+ }
+
+ r->out.result = _netr_NETRLOGONCOMPUTECLIENTDIGEST(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NETRLOGONCOMPUTECLIENTDIGEST, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_ServerAuthenticate3(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_ServerAuthenticate3 *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_SERVERAUTHENTICATE3];
+
+ r = talloc(talloc_tos(), struct netr_ServerAuthenticate3);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_ServerAuthenticate3, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.credentials = r->in.credentials;
+ r->out.negotiate_flags = r->in.negotiate_flags;
+ r->out.rid = talloc_zero(r, uint32_t);
+ if (r->out.rid == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_ServerAuthenticate3(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_ServerAuthenticate3, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_DsRGetDCNameEx(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_DsRGetDCNameEx *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_DSRGETDCNAMEEX];
+
+ r = talloc(talloc_tos(), struct netr_DsRGetDCNameEx);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsRGetDCNameEx, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, struct netr_DsRGetDCNameInfo *);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_DsRGetDCNameEx(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsRGetDCNameEx, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_DsRGetSiteName(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_DsRGetSiteName *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_DSRGETSITENAME];
+
+ r = talloc(talloc_tos(), struct netr_DsRGetSiteName);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsRGetSiteName, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.site = talloc_zero(r, const char *);
+ if (r->out.site == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_DsRGetSiteName(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsRGetSiteName, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_LogonGetDomainInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_LogonGetDomainInfo *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_LOGONGETDOMAININFO];
+
+ r = talloc(talloc_tos(), struct netr_LogonGetDomainInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonGetDomainInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_authenticator = r->in.return_authenticator;
+ r->out.info = talloc_zero(r, union netr_DomainInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_LogonGetDomainInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonGetDomainInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_ServerPasswordSet2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_ServerPasswordSet2 *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_SERVERPASSWORDSET2];
+
+ r = talloc(talloc_tos(), struct netr_ServerPasswordSet2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_ServerPasswordSet2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_authenticator = talloc_zero(r, struct netr_Authenticator);
+ if (r->out.return_authenticator == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_ServerPasswordSet2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_ServerPasswordSet2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_ServerPasswordGet(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_ServerPasswordGet *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_SERVERPASSWORDGET];
+
+ r = talloc(talloc_tos(), struct netr_ServerPasswordGet);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_ServerPasswordGet, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_authenticator = talloc_zero(r, struct netr_Authenticator);
+ if (r->out.return_authenticator == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.password = talloc_zero(r, struct samr_Password);
+ if (r->out.password == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_ServerPasswordGet(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_ServerPasswordGet, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_NETRLOGONSENDTOSAM(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_NETRLOGONSENDTOSAM *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_NETRLOGONSENDTOSAM];
+
+ r = talloc(talloc_tos(), struct netr_NETRLOGONSENDTOSAM);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NETRLOGONSENDTOSAM, r);
+ }
+
+ r->out.result = _netr_NETRLOGONSENDTOSAM(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NETRLOGONSENDTOSAM, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_DsRAddressToSitenamesW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_DsRAddressToSitenamesW *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_DSRADDRESSTOSITENAMESW];
+
+ r = talloc(talloc_tos(), struct netr_DsRAddressToSitenamesW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsRAddressToSitenamesW, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.ctr = talloc_zero(r, struct netr_DsRAddressToSitenamesWCtr *);
+ if (r->out.ctr == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_DsRAddressToSitenamesW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsRAddressToSitenamesW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_DsRGetDCNameEx2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_DsRGetDCNameEx2 *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_DSRGETDCNAMEEX2];
+
+ r = talloc(talloc_tos(), struct netr_DsRGetDCNameEx2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsRGetDCNameEx2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, struct netr_DsRGetDCNameInfo *);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_DsRGetDCNameEx2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsRGetDCNameEx2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_NETRLOGONGETTIMESERVICEPARENTDOMAIN];
+
+ r = talloc(talloc_tos(), struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN, r);
+ }
+
+ r->out.result = _netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_NetrEnumerateTrustedDomainsEx(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_NetrEnumerateTrustedDomainsEx *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_NETRENUMERATETRUSTEDDOMAINSEX];
+
+ r = talloc(talloc_tos(), struct netr_NetrEnumerateTrustedDomainsEx);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NetrEnumerateTrustedDomainsEx, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.dom_trust_list = talloc_zero(r, struct netr_DomainTrustList);
+ if (r->out.dom_trust_list == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_NetrEnumerateTrustedDomainsEx(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NetrEnumerateTrustedDomainsEx, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_DsRAddressToSitenamesExW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_DsRAddressToSitenamesExW *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_DSRADDRESSTOSITENAMESEXW];
+
+ r = talloc(talloc_tos(), struct netr_DsRAddressToSitenamesExW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsRAddressToSitenamesExW, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.ctr = talloc_zero(r, struct netr_DsRAddressToSitenamesExWCtr *);
+ if (r->out.ctr == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_DsRAddressToSitenamesExW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsRAddressToSitenamesExW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_DsrGetDcSiteCoverageW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_DsrGetDcSiteCoverageW *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_DSRGETDCSITECOVERAGEW];
+
+ r = talloc(talloc_tos(), struct netr_DsrGetDcSiteCoverageW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsrGetDcSiteCoverageW, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.ctr = talloc_zero(r, struct DcSitesCtr);
+ if (r->out.ctr == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_DsrGetDcSiteCoverageW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsrGetDcSiteCoverageW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_LogonSamLogonEx(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_LogonSamLogonEx *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_LOGONSAMLOGONEX];
+
+ r = talloc(talloc_tos(), struct netr_LogonSamLogonEx);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonSamLogonEx, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.validation = talloc_zero(r, union netr_Validation);
+ if (r->out.validation == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.authoritative = talloc_zero(r, uint8_t);
+ if (r->out.authoritative == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.flags = r->in.flags;
+ r->out.result = _netr_LogonSamLogonEx(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonSamLogonEx, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_DsrEnumerateDomainTrusts(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_DsrEnumerateDomainTrusts *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_DSRENUMERATEDOMAINTRUSTS];
+
+ r = talloc(talloc_tos(), struct netr_DsrEnumerateDomainTrusts);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsrEnumerateDomainTrusts, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.trusts = talloc_zero(r, struct netr_DomainTrustList);
+ if (r->out.trusts == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_DsrEnumerateDomainTrusts(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsrEnumerateDomainTrusts, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_DsrDeregisterDNSHostRecords(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_DsrDeregisterDNSHostRecords *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_DSRDEREGISTERDNSHOSTRECORDS];
+
+ r = talloc(talloc_tos(), struct netr_DsrDeregisterDNSHostRecords);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsrDeregisterDNSHostRecords, r);
+ }
+
+ r->out.result = _netr_DsrDeregisterDNSHostRecords(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsrDeregisterDNSHostRecords, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_ServerTrustPasswordsGet(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_ServerTrustPasswordsGet *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_SERVERTRUSTPASSWORDSGET];
+
+ r = talloc(talloc_tos(), struct netr_ServerTrustPasswordsGet);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_ServerTrustPasswordsGet, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_authenticator = talloc_zero(r, struct netr_Authenticator);
+ if (r->out.return_authenticator == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.password = talloc_zero(r, struct samr_Password);
+ if (r->out.password == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.password2 = talloc_zero(r, struct samr_Password);
+ if (r->out.password2 == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_ServerTrustPasswordsGet(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_ServerTrustPasswordsGet, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_DsRGetForestTrustInformation(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_DsRGetForestTrustInformation *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_DSRGETFORESTTRUSTINFORMATION];
+
+ r = talloc(talloc_tos(), struct netr_DsRGetForestTrustInformation);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_DsRGetForestTrustInformation, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.forest_trust_info = talloc_zero(r, struct lsa_ForestTrustInformation *);
+ if (r->out.forest_trust_info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_DsRGetForestTrustInformation(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_DsRGetForestTrustInformation, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_GetForestTrustInformation(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_GetForestTrustInformation *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_GETFORESTTRUSTINFORMATION];
+
+ r = talloc(talloc_tos(), struct netr_GetForestTrustInformation);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_GetForestTrustInformation, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_authenticator = talloc_zero(r, struct netr_Authenticator);
+ if (r->out.return_authenticator == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.forest_trust_info = talloc_zero(r, struct lsa_ForestTrustInformation *);
+ if (r->out.forest_trust_info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _netr_GetForestTrustInformation(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_GetForestTrustInformation, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_LogonSamLogonWithFlags(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_LogonSamLogonWithFlags *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_LOGONSAMLOGONWITHFLAGS];
+
+ r = talloc(talloc_tos(), struct netr_LogonSamLogonWithFlags);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_LogonSamLogonWithFlags, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.return_authenticator = r->in.return_authenticator;
+ r->out.validation = talloc_zero(r, union netr_Validation);
+ if (r->out.validation == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.authoritative = talloc_zero(r, uint8_t);
+ if (r->out.authoritative == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.flags = r->in.flags;
+ r->out.result = _netr_LogonSamLogonWithFlags(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_LogonSamLogonWithFlags, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_netr_NETRSERVERGETTRUSTINFO(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netr_NETRSERVERGETTRUSTINFO *r;
+
+ call = &ndr_table_netlogon.calls[NDR_NETR_NETRSERVERGETTRUSTINFO];
+
+ r = talloc(talloc_tos(), struct netr_NETRSERVERGETTRUSTINFO);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(netr_NETRSERVERGETTRUSTINFO, r);
+ }
+
+ r->out.result = _netr_NETRSERVERGETTRUSTINFO(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(netr_NETRSERVERGETTRUSTINFO, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+
+/* Tables */
+static struct api_struct api_netlogon_cmds[] =
+{
+ {"NETR_LOGONUASLOGON", NDR_NETR_LOGONUASLOGON, api_netr_LogonUasLogon},
+ {"NETR_LOGONUASLOGOFF", NDR_NETR_LOGONUASLOGOFF, api_netr_LogonUasLogoff},
+ {"NETR_LOGONSAMLOGON", NDR_NETR_LOGONSAMLOGON, api_netr_LogonSamLogon},
+ {"NETR_LOGONSAMLOGOFF", NDR_NETR_LOGONSAMLOGOFF, api_netr_LogonSamLogoff},
+ {"NETR_SERVERREQCHALLENGE", NDR_NETR_SERVERREQCHALLENGE, api_netr_ServerReqChallenge},
+ {"NETR_SERVERAUTHENTICATE", NDR_NETR_SERVERAUTHENTICATE, api_netr_ServerAuthenticate},
+ {"NETR_SERVERPASSWORDSET", NDR_NETR_SERVERPASSWORDSET, api_netr_ServerPasswordSet},
+ {"NETR_DATABASEDELTAS", NDR_NETR_DATABASEDELTAS, api_netr_DatabaseDeltas},
+ {"NETR_DATABASESYNC", NDR_NETR_DATABASESYNC, api_netr_DatabaseSync},
+ {"NETR_ACCOUNTDELTAS", NDR_NETR_ACCOUNTDELTAS, api_netr_AccountDeltas},
+ {"NETR_ACCOUNTSYNC", NDR_NETR_ACCOUNTSYNC, api_netr_AccountSync},
+ {"NETR_GETDCNAME", NDR_NETR_GETDCNAME, api_netr_GetDcName},
+ {"NETR_LOGONCONTROL", NDR_NETR_LOGONCONTROL, api_netr_LogonControl},
+ {"NETR_GETANYDCNAME", NDR_NETR_GETANYDCNAME, api_netr_GetAnyDCName},
+ {"NETR_LOGONCONTROL2", NDR_NETR_LOGONCONTROL2, api_netr_LogonControl2},
+ {"NETR_SERVERAUTHENTICATE2", NDR_NETR_SERVERAUTHENTICATE2, api_netr_ServerAuthenticate2},
+ {"NETR_DATABASESYNC2", NDR_NETR_DATABASESYNC2, api_netr_DatabaseSync2},
+ {"NETR_DATABASEREDO", NDR_NETR_DATABASEREDO, api_netr_DatabaseRedo},
+ {"NETR_LOGONCONTROL2EX", NDR_NETR_LOGONCONTROL2EX, api_netr_LogonControl2Ex},
+ {"NETR_NETRENUMERATETRUSTEDDOMAINS", NDR_NETR_NETRENUMERATETRUSTEDDOMAINS, api_netr_NetrEnumerateTrustedDomains},
+ {"NETR_DSRGETDCNAME", NDR_NETR_DSRGETDCNAME, api_netr_DsRGetDCName},
+ {"NETR_NETRLOGONDUMMYROUTINE1", NDR_NETR_NETRLOGONDUMMYROUTINE1, api_netr_NETRLOGONDUMMYROUTINE1},
+ {"NETR_NETRLOGONSETSERVICEBITS", NDR_NETR_NETRLOGONSETSERVICEBITS, api_netr_NETRLOGONSETSERVICEBITS},
+ {"NETR_LOGONGETTRUSTRID", NDR_NETR_LOGONGETTRUSTRID, api_netr_LogonGetTrustRid},
+ {"NETR_NETRLOGONCOMPUTESERVERDIGEST", NDR_NETR_NETRLOGONCOMPUTESERVERDIGEST, api_netr_NETRLOGONCOMPUTESERVERDIGEST},
+ {"NETR_NETRLOGONCOMPUTECLIENTDIGEST", NDR_NETR_NETRLOGONCOMPUTECLIENTDIGEST, api_netr_NETRLOGONCOMPUTECLIENTDIGEST},
+ {"NETR_SERVERAUTHENTICATE3", NDR_NETR_SERVERAUTHENTICATE3, api_netr_ServerAuthenticate3},
+ {"NETR_DSRGETDCNAMEEX", NDR_NETR_DSRGETDCNAMEEX, api_netr_DsRGetDCNameEx},
+ {"NETR_DSRGETSITENAME", NDR_NETR_DSRGETSITENAME, api_netr_DsRGetSiteName},
+ {"NETR_LOGONGETDOMAININFO", NDR_NETR_LOGONGETDOMAININFO, api_netr_LogonGetDomainInfo},
+ {"NETR_SERVERPASSWORDSET2", NDR_NETR_SERVERPASSWORDSET2, api_netr_ServerPasswordSet2},
+ {"NETR_SERVERPASSWORDGET", NDR_NETR_SERVERPASSWORDGET, api_netr_ServerPasswordGet},
+ {"NETR_NETRLOGONSENDTOSAM", NDR_NETR_NETRLOGONSENDTOSAM, api_netr_NETRLOGONSENDTOSAM},
+ {"NETR_DSRADDRESSTOSITENAMESW", NDR_NETR_DSRADDRESSTOSITENAMESW, api_netr_DsRAddressToSitenamesW},
+ {"NETR_DSRGETDCNAMEEX2", NDR_NETR_DSRGETDCNAMEEX2, api_netr_DsRGetDCNameEx2},
+ {"NETR_NETRLOGONGETTIMESERVICEPARENTDOMAIN", NDR_NETR_NETRLOGONGETTIMESERVICEPARENTDOMAIN, api_netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN},
+ {"NETR_NETRENUMERATETRUSTEDDOMAINSEX", NDR_NETR_NETRENUMERATETRUSTEDDOMAINSEX, api_netr_NetrEnumerateTrustedDomainsEx},
+ {"NETR_DSRADDRESSTOSITENAMESEXW", NDR_NETR_DSRADDRESSTOSITENAMESEXW, api_netr_DsRAddressToSitenamesExW},
+ {"NETR_DSRGETDCSITECOVERAGEW", NDR_NETR_DSRGETDCSITECOVERAGEW, api_netr_DsrGetDcSiteCoverageW},
+ {"NETR_LOGONSAMLOGONEX", NDR_NETR_LOGONSAMLOGONEX, api_netr_LogonSamLogonEx},
+ {"NETR_DSRENUMERATEDOMAINTRUSTS", NDR_NETR_DSRENUMERATEDOMAINTRUSTS, api_netr_DsrEnumerateDomainTrusts},
+ {"NETR_DSRDEREGISTERDNSHOSTRECORDS", NDR_NETR_DSRDEREGISTERDNSHOSTRECORDS, api_netr_DsrDeregisterDNSHostRecords},
+ {"NETR_SERVERTRUSTPASSWORDSGET", NDR_NETR_SERVERTRUSTPASSWORDSGET, api_netr_ServerTrustPasswordsGet},
+ {"NETR_DSRGETFORESTTRUSTINFORMATION", NDR_NETR_DSRGETFORESTTRUSTINFORMATION, api_netr_DsRGetForestTrustInformation},
+ {"NETR_GETFORESTTRUSTINFORMATION", NDR_NETR_GETFORESTTRUSTINFORMATION, api_netr_GetForestTrustInformation},
+ {"NETR_LOGONSAMLOGONWITHFLAGS", NDR_NETR_LOGONSAMLOGONWITHFLAGS, api_netr_LogonSamLogonWithFlags},
+ {"NETR_NETRSERVERGETTRUSTINFO", NDR_NETR_NETRSERVERGETTRUSTINFO, api_netr_NETRSERVERGETTRUSTINFO},
+};
+
+void netlogon_get_pipe_fns(struct api_struct **fns, int *n_fns)
+{
+ *fns = api_netlogon_cmds;
+ *n_fns = sizeof(api_netlogon_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_netlogon_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "netlogon", "netlogon", &ndr_table_netlogon.syntax_id, api_netlogon_cmds, sizeof(api_netlogon_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/librpc/gen_ndr/srv_netlogon.h b/source3/librpc/gen_ndr/srv_netlogon.h
new file mode 100644
index 0000000000..1fe16c603b
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_netlogon.h
@@ -0,0 +1,53 @@
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#ifndef __SRV_NETLOGON__
+#define __SRV_NETLOGON__
+WERROR _netr_LogonUasLogon(pipes_struct *p, struct netr_LogonUasLogon *r);
+WERROR _netr_LogonUasLogoff(pipes_struct *p, struct netr_LogonUasLogoff *r);
+NTSTATUS _netr_LogonSamLogon(pipes_struct *p, struct netr_LogonSamLogon *r);
+NTSTATUS _netr_LogonSamLogoff(pipes_struct *p, struct netr_LogonSamLogoff *r);
+NTSTATUS _netr_ServerReqChallenge(pipes_struct *p, struct netr_ServerReqChallenge *r);
+NTSTATUS _netr_ServerAuthenticate(pipes_struct *p, struct netr_ServerAuthenticate *r);
+NTSTATUS _netr_ServerPasswordSet(pipes_struct *p, struct netr_ServerPasswordSet *r);
+NTSTATUS _netr_DatabaseDeltas(pipes_struct *p, struct netr_DatabaseDeltas *r);
+NTSTATUS _netr_DatabaseSync(pipes_struct *p, struct netr_DatabaseSync *r);
+NTSTATUS _netr_AccountDeltas(pipes_struct *p, struct netr_AccountDeltas *r);
+NTSTATUS _netr_AccountSync(pipes_struct *p, struct netr_AccountSync *r);
+WERROR _netr_GetDcName(pipes_struct *p, struct netr_GetDcName *r);
+WERROR _netr_LogonControl(pipes_struct *p, struct netr_LogonControl *r);
+WERROR _netr_GetAnyDCName(pipes_struct *p, struct netr_GetAnyDCName *r);
+WERROR _netr_LogonControl2(pipes_struct *p, struct netr_LogonControl2 *r);
+NTSTATUS _netr_ServerAuthenticate2(pipes_struct *p, struct netr_ServerAuthenticate2 *r);
+NTSTATUS _netr_DatabaseSync2(pipes_struct *p, struct netr_DatabaseSync2 *r);
+NTSTATUS _netr_DatabaseRedo(pipes_struct *p, struct netr_DatabaseRedo *r);
+WERROR _netr_LogonControl2Ex(pipes_struct *p, struct netr_LogonControl2Ex *r);
+WERROR _netr_NetrEnumerateTrustedDomains(pipes_struct *p, struct netr_NetrEnumerateTrustedDomains *r);
+WERROR _netr_DsRGetDCName(pipes_struct *p, struct netr_DsRGetDCName *r);
+WERROR _netr_NETRLOGONDUMMYROUTINE1(pipes_struct *p, struct netr_NETRLOGONDUMMYROUTINE1 *r);
+WERROR _netr_NETRLOGONSETSERVICEBITS(pipes_struct *p, struct netr_NETRLOGONSETSERVICEBITS *r);
+WERROR _netr_LogonGetTrustRid(pipes_struct *p, struct netr_LogonGetTrustRid *r);
+WERROR _netr_NETRLOGONCOMPUTESERVERDIGEST(pipes_struct *p, struct netr_NETRLOGONCOMPUTESERVERDIGEST *r);
+WERROR _netr_NETRLOGONCOMPUTECLIENTDIGEST(pipes_struct *p, struct netr_NETRLOGONCOMPUTECLIENTDIGEST *r);
+NTSTATUS _netr_ServerAuthenticate3(pipes_struct *p, struct netr_ServerAuthenticate3 *r);
+WERROR _netr_DsRGetDCNameEx(pipes_struct *p, struct netr_DsRGetDCNameEx *r);
+WERROR _netr_DsRGetSiteName(pipes_struct *p, struct netr_DsRGetSiteName *r);
+NTSTATUS _netr_LogonGetDomainInfo(pipes_struct *p, struct netr_LogonGetDomainInfo *r);
+NTSTATUS _netr_ServerPasswordSet2(pipes_struct *p, struct netr_ServerPasswordSet2 *r);
+WERROR _netr_ServerPasswordGet(pipes_struct *p, struct netr_ServerPasswordGet *r);
+WERROR _netr_NETRLOGONSENDTOSAM(pipes_struct *p, struct netr_NETRLOGONSENDTOSAM *r);
+WERROR _netr_DsRAddressToSitenamesW(pipes_struct *p, struct netr_DsRAddressToSitenamesW *r);
+WERROR _netr_DsRGetDCNameEx2(pipes_struct *p, struct netr_DsRGetDCNameEx2 *r);
+WERROR _netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(pipes_struct *p, struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN *r);
+WERROR _netr_NetrEnumerateTrustedDomainsEx(pipes_struct *p, struct netr_NetrEnumerateTrustedDomainsEx *r);
+WERROR _netr_DsRAddressToSitenamesExW(pipes_struct *p, struct netr_DsRAddressToSitenamesExW *r);
+WERROR _netr_DsrGetDcSiteCoverageW(pipes_struct *p, struct netr_DsrGetDcSiteCoverageW *r);
+NTSTATUS _netr_LogonSamLogonEx(pipes_struct *p, struct netr_LogonSamLogonEx *r);
+WERROR _netr_DsrEnumerateDomainTrusts(pipes_struct *p, struct netr_DsrEnumerateDomainTrusts *r);
+WERROR _netr_DsrDeregisterDNSHostRecords(pipes_struct *p, struct netr_DsrDeregisterDNSHostRecords *r);
+NTSTATUS _netr_ServerTrustPasswordsGet(pipes_struct *p, struct netr_ServerTrustPasswordsGet *r);
+WERROR _netr_DsRGetForestTrustInformation(pipes_struct *p, struct netr_DsRGetForestTrustInformation *r);
+WERROR _netr_GetForestTrustInformation(pipes_struct *p, struct netr_GetForestTrustInformation *r);
+NTSTATUS _netr_LogonSamLogonWithFlags(pipes_struct *p, struct netr_LogonSamLogonWithFlags *r);
+WERROR _netr_NETRSERVERGETTRUSTINFO(pipes_struct *p, struct netr_NETRSERVERGETTRUSTINFO *r);
+void netlogon_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_netlogon_init(void);
+#endif /* __SRV_NETLOGON__ */
diff --git a/source3/librpc/gen_ndr/srv_ntsvcs.c b/source3/librpc/gen_ndr/srv_ntsvcs.c
new file mode 100644
index 0000000000..d21e86db6e
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_ntsvcs.c
@@ -0,0 +1,4869 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * server auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/srv_ntsvcs.h"
+
+static bool api_PNP_Disconnect(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_Disconnect *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_DISCONNECT];
+
+ r = talloc(talloc_tos(), struct PNP_Disconnect);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_Disconnect, r);
+ }
+
+ r->out.result = _PNP_Disconnect(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_Disconnect, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_Connect(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_Connect *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_CONNECT];
+
+ r = talloc(talloc_tos(), struct PNP_Connect);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_Connect, r);
+ }
+
+ r->out.result = _PNP_Connect(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_Connect, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetVersion(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetVersion *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETVERSION];
+
+ r = talloc(talloc_tos(), struct PNP_GetVersion);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetVersion, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.version = talloc_zero(r, uint16_t);
+ if (r->out.version == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _PNP_GetVersion(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetVersion, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetGlobalState(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetGlobalState *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETGLOBALSTATE];
+
+ r = talloc(talloc_tos(), struct PNP_GetGlobalState);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetGlobalState, r);
+ }
+
+ r->out.result = _PNP_GetGlobalState(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetGlobalState, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_InitDetection(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_InitDetection *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_INITDETECTION];
+
+ r = talloc(talloc_tos(), struct PNP_InitDetection);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_InitDetection, r);
+ }
+
+ r->out.result = _PNP_InitDetection(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_InitDetection, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_ReportLogOn(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_ReportLogOn *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_REPORTLOGON];
+
+ r = talloc(talloc_tos(), struct PNP_ReportLogOn);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_ReportLogOn, r);
+ }
+
+ r->out.result = _PNP_ReportLogOn(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_ReportLogOn, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_ValidateDeviceInstance(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_ValidateDeviceInstance *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_VALIDATEDEVICEINSTANCE];
+
+ r = talloc(talloc_tos(), struct PNP_ValidateDeviceInstance);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_ValidateDeviceInstance, r);
+ }
+
+ r->out.result = _PNP_ValidateDeviceInstance(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_ValidateDeviceInstance, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetRootDeviceInstance(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetRootDeviceInstance *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETROOTDEVICEINSTANCE];
+
+ r = talloc(talloc_tos(), struct PNP_GetRootDeviceInstance);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetRootDeviceInstance, r);
+ }
+
+ r->out.result = _PNP_GetRootDeviceInstance(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetRootDeviceInstance, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetRelatedDeviceInstance(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetRelatedDeviceInstance *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETRELATEDDEVICEINSTANCE];
+
+ r = talloc(talloc_tos(), struct PNP_GetRelatedDeviceInstance);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetRelatedDeviceInstance, r);
+ }
+
+ r->out.result = _PNP_GetRelatedDeviceInstance(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetRelatedDeviceInstance, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_EnumerateSubKeys(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_EnumerateSubKeys *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_ENUMERATESUBKEYS];
+
+ r = talloc(talloc_tos(), struct PNP_EnumerateSubKeys);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_EnumerateSubKeys, r);
+ }
+
+ r->out.result = _PNP_EnumerateSubKeys(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_EnumerateSubKeys, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetDeviceList(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetDeviceList *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETDEVICELIST];
+
+ r = talloc(talloc_tos(), struct PNP_GetDeviceList);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetDeviceList, r);
+ }
+
+ r->out.result = _PNP_GetDeviceList(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetDeviceList, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetDeviceListSize(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetDeviceListSize *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETDEVICELISTSIZE];
+
+ r = talloc(talloc_tos(), struct PNP_GetDeviceListSize);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetDeviceListSize, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.size = talloc_zero(r, uint32_t);
+ if (r->out.size == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _PNP_GetDeviceListSize(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetDeviceListSize, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetDepth(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetDepth *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETDEPTH];
+
+ r = talloc(talloc_tos(), struct PNP_GetDepth);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetDepth, r);
+ }
+
+ r->out.result = _PNP_GetDepth(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetDepth, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetDeviceRegProp(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetDeviceRegProp *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETDEVICEREGPROP];
+
+ r = talloc(talloc_tos(), struct PNP_GetDeviceRegProp);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetDeviceRegProp, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.unknown1 = r->in.unknown1;
+ r->out.buffer = talloc_zero_array(r, uint8_t, *r->out.buffer_size);
+ if (r->out.buffer == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.buffer_size = r->in.buffer_size;
+ r->out.needed = r->in.needed;
+ r->out.result = _PNP_GetDeviceRegProp(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetDeviceRegProp, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_SetDeviceRegProp(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_SetDeviceRegProp *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_SETDEVICEREGPROP];
+
+ r = talloc(talloc_tos(), struct PNP_SetDeviceRegProp);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_SetDeviceRegProp, r);
+ }
+
+ r->out.result = _PNP_SetDeviceRegProp(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_SetDeviceRegProp, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetClassInstance(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetClassInstance *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETCLASSINSTANCE];
+
+ r = talloc(talloc_tos(), struct PNP_GetClassInstance);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetClassInstance, r);
+ }
+
+ r->out.result = _PNP_GetClassInstance(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetClassInstance, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_CreateKey(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_CreateKey *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_CREATEKEY];
+
+ r = talloc(talloc_tos(), struct PNP_CreateKey);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_CreateKey, r);
+ }
+
+ r->out.result = _PNP_CreateKey(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_CreateKey, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_DeleteRegistryKey(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_DeleteRegistryKey *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_DELETEREGISTRYKEY];
+
+ r = talloc(talloc_tos(), struct PNP_DeleteRegistryKey);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_DeleteRegistryKey, r);
+ }
+
+ r->out.result = _PNP_DeleteRegistryKey(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_DeleteRegistryKey, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetClassCount(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetClassCount *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETCLASSCOUNT];
+
+ r = talloc(talloc_tos(), struct PNP_GetClassCount);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetClassCount, r);
+ }
+
+ r->out.result = _PNP_GetClassCount(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetClassCount, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetClassName(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetClassName *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETCLASSNAME];
+
+ r = talloc(talloc_tos(), struct PNP_GetClassName);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetClassName, r);
+ }
+
+ r->out.result = _PNP_GetClassName(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetClassName, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_DeleteClassKey(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_DeleteClassKey *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_DELETECLASSKEY];
+
+ r = talloc(talloc_tos(), struct PNP_DeleteClassKey);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_DeleteClassKey, r);
+ }
+
+ r->out.result = _PNP_DeleteClassKey(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_DeleteClassKey, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetInterfaceDeviceAlias(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetInterfaceDeviceAlias *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETINTERFACEDEVICEALIAS];
+
+ r = talloc(talloc_tos(), struct PNP_GetInterfaceDeviceAlias);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetInterfaceDeviceAlias, r);
+ }
+
+ r->out.result = _PNP_GetInterfaceDeviceAlias(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetInterfaceDeviceAlias, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetInterfaceDeviceList(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetInterfaceDeviceList *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETINTERFACEDEVICELIST];
+
+ r = talloc(talloc_tos(), struct PNP_GetInterfaceDeviceList);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetInterfaceDeviceList, r);
+ }
+
+ r->out.result = _PNP_GetInterfaceDeviceList(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetInterfaceDeviceList, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetInterfaceDeviceListSize(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetInterfaceDeviceListSize *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETINTERFACEDEVICELISTSIZE];
+
+ r = talloc(talloc_tos(), struct PNP_GetInterfaceDeviceListSize);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetInterfaceDeviceListSize, r);
+ }
+
+ r->out.result = _PNP_GetInterfaceDeviceListSize(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetInterfaceDeviceListSize, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_RegisterDeviceClassAssociation(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_RegisterDeviceClassAssociation *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_REGISTERDEVICECLASSASSOCIATION];
+
+ r = talloc(talloc_tos(), struct PNP_RegisterDeviceClassAssociation);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_RegisterDeviceClassAssociation, r);
+ }
+
+ r->out.result = _PNP_RegisterDeviceClassAssociation(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_RegisterDeviceClassAssociation, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_UnregisterDeviceClassAssociation(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_UnregisterDeviceClassAssociation *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_UNREGISTERDEVICECLASSASSOCIATION];
+
+ r = talloc(talloc_tos(), struct PNP_UnregisterDeviceClassAssociation);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_UnregisterDeviceClassAssociation, r);
+ }
+
+ r->out.result = _PNP_UnregisterDeviceClassAssociation(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_UnregisterDeviceClassAssociation, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetClassRegProp(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetClassRegProp *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETCLASSREGPROP];
+
+ r = talloc(talloc_tos(), struct PNP_GetClassRegProp);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetClassRegProp, r);
+ }
+
+ r->out.result = _PNP_GetClassRegProp(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetClassRegProp, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_SetClassRegProp(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_SetClassRegProp *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_SETCLASSREGPROP];
+
+ r = talloc(talloc_tos(), struct PNP_SetClassRegProp);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_SetClassRegProp, r);
+ }
+
+ r->out.result = _PNP_SetClassRegProp(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_SetClassRegProp, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_CreateDevInst(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_CreateDevInst *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_CREATEDEVINST];
+
+ r = talloc(talloc_tos(), struct PNP_CreateDevInst);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_CreateDevInst, r);
+ }
+
+ r->out.result = _PNP_CreateDevInst(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_CreateDevInst, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_DeviceInstanceAction(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_DeviceInstanceAction *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_DEVICEINSTANCEACTION];
+
+ r = talloc(talloc_tos(), struct PNP_DeviceInstanceAction);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_DeviceInstanceAction, r);
+ }
+
+ r->out.result = _PNP_DeviceInstanceAction(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_DeviceInstanceAction, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetDeviceStatus(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetDeviceStatus *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETDEVICESTATUS];
+
+ r = talloc(talloc_tos(), struct PNP_GetDeviceStatus);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetDeviceStatus, r);
+ }
+
+ r->out.result = _PNP_GetDeviceStatus(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetDeviceStatus, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_SetDeviceProblem(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_SetDeviceProblem *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_SETDEVICEPROBLEM];
+
+ r = talloc(talloc_tos(), struct PNP_SetDeviceProblem);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_SetDeviceProblem, r);
+ }
+
+ r->out.result = _PNP_SetDeviceProblem(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_SetDeviceProblem, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_DisableDevInst(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_DisableDevInst *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_DISABLEDEVINST];
+
+ r = talloc(talloc_tos(), struct PNP_DisableDevInst);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_DisableDevInst, r);
+ }
+
+ r->out.result = _PNP_DisableDevInst(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_DisableDevInst, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_UninstallDevInst(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_UninstallDevInst *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_UNINSTALLDEVINST];
+
+ r = talloc(talloc_tos(), struct PNP_UninstallDevInst);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_UninstallDevInst, r);
+ }
+
+ r->out.result = _PNP_UninstallDevInst(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_UninstallDevInst, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_AddID(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_AddID *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_ADDID];
+
+ r = talloc(talloc_tos(), struct PNP_AddID);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_AddID, r);
+ }
+
+ r->out.result = _PNP_AddID(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_AddID, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_RegisterDriver(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_RegisterDriver *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_REGISTERDRIVER];
+
+ r = talloc(talloc_tos(), struct PNP_RegisterDriver);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_RegisterDriver, r);
+ }
+
+ r->out.result = _PNP_RegisterDriver(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_RegisterDriver, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_QueryRemove(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_QueryRemove *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_QUERYREMOVE];
+
+ r = talloc(talloc_tos(), struct PNP_QueryRemove);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_QueryRemove, r);
+ }
+
+ r->out.result = _PNP_QueryRemove(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_QueryRemove, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_RequestDeviceEject(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_RequestDeviceEject *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_REQUESTDEVICEEJECT];
+
+ r = talloc(talloc_tos(), struct PNP_RequestDeviceEject);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_RequestDeviceEject, r);
+ }
+
+ r->out.result = _PNP_RequestDeviceEject(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_RequestDeviceEject, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_IsDockStationPresent(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_IsDockStationPresent *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_ISDOCKSTATIONPRESENT];
+
+ r = talloc(talloc_tos(), struct PNP_IsDockStationPresent);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_IsDockStationPresent, r);
+ }
+
+ r->out.result = _PNP_IsDockStationPresent(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_IsDockStationPresent, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_RequestEjectPC(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_RequestEjectPC *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_REQUESTEJECTPC];
+
+ r = talloc(talloc_tos(), struct PNP_RequestEjectPC);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_RequestEjectPC, r);
+ }
+
+ r->out.result = _PNP_RequestEjectPC(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_RequestEjectPC, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_HwProfFlags(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_HwProfFlags *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_HWPROFFLAGS];
+
+ r = talloc(talloc_tos(), struct PNP_HwProfFlags);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_HwProfFlags, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.unknown3 = r->in.unknown3;
+ r->out.unknown4 = r->in.unknown4;
+ r->out.unknown5a = talloc_zero(r, const char *);
+ if (r->out.unknown5a == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _PNP_HwProfFlags(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_HwProfFlags, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetHwProfInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetHwProfInfo *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETHWPROFINFO];
+
+ r = talloc(talloc_tos(), struct PNP_GetHwProfInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetHwProfInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = r->in.info;
+ r->out.result = _PNP_GetHwProfInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetHwProfInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_AddEmptyLogConf(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_AddEmptyLogConf *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_ADDEMPTYLOGCONF];
+
+ r = talloc(talloc_tos(), struct PNP_AddEmptyLogConf);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_AddEmptyLogConf, r);
+ }
+
+ r->out.result = _PNP_AddEmptyLogConf(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_AddEmptyLogConf, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_FreeLogConf(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_FreeLogConf *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_FREELOGCONF];
+
+ r = talloc(talloc_tos(), struct PNP_FreeLogConf);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_FreeLogConf, r);
+ }
+
+ r->out.result = _PNP_FreeLogConf(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_FreeLogConf, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetFirstLogConf(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetFirstLogConf *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETFIRSTLOGCONF];
+
+ r = talloc(talloc_tos(), struct PNP_GetFirstLogConf);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetFirstLogConf, r);
+ }
+
+ r->out.result = _PNP_GetFirstLogConf(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetFirstLogConf, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetNextLogConf(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetNextLogConf *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETNEXTLOGCONF];
+
+ r = talloc(talloc_tos(), struct PNP_GetNextLogConf);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetNextLogConf, r);
+ }
+
+ r->out.result = _PNP_GetNextLogConf(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetNextLogConf, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetLogConfPriority(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetLogConfPriority *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETLOGCONFPRIORITY];
+
+ r = talloc(talloc_tos(), struct PNP_GetLogConfPriority);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetLogConfPriority, r);
+ }
+
+ r->out.result = _PNP_GetLogConfPriority(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetLogConfPriority, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_AddResDes(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_AddResDes *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_ADDRESDES];
+
+ r = talloc(talloc_tos(), struct PNP_AddResDes);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_AddResDes, r);
+ }
+
+ r->out.result = _PNP_AddResDes(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_AddResDes, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_FreeResDes(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_FreeResDes *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_FREERESDES];
+
+ r = talloc(talloc_tos(), struct PNP_FreeResDes);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_FreeResDes, r);
+ }
+
+ r->out.result = _PNP_FreeResDes(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_FreeResDes, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetNextResDes(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetNextResDes *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETNEXTRESDES];
+
+ r = talloc(talloc_tos(), struct PNP_GetNextResDes);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetNextResDes, r);
+ }
+
+ r->out.result = _PNP_GetNextResDes(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetNextResDes, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetResDesData(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetResDesData *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETRESDESDATA];
+
+ r = talloc(talloc_tos(), struct PNP_GetResDesData);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetResDesData, r);
+ }
+
+ r->out.result = _PNP_GetResDesData(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetResDesData, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetResDesDataSize(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetResDesDataSize *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETRESDESDATASIZE];
+
+ r = talloc(talloc_tos(), struct PNP_GetResDesDataSize);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetResDesDataSize, r);
+ }
+
+ r->out.result = _PNP_GetResDesDataSize(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetResDesDataSize, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_ModifyResDes(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_ModifyResDes *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_MODIFYRESDES];
+
+ r = talloc(talloc_tos(), struct PNP_ModifyResDes);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_ModifyResDes, r);
+ }
+
+ r->out.result = _PNP_ModifyResDes(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_ModifyResDes, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_DetectResourceLimit(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_DetectResourceLimit *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_DETECTRESOURCELIMIT];
+
+ r = talloc(talloc_tos(), struct PNP_DetectResourceLimit);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_DetectResourceLimit, r);
+ }
+
+ r->out.result = _PNP_DetectResourceLimit(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_DetectResourceLimit, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_QueryResConfList(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_QueryResConfList *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_QUERYRESCONFLIST];
+
+ r = talloc(talloc_tos(), struct PNP_QueryResConfList);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_QueryResConfList, r);
+ }
+
+ r->out.result = _PNP_QueryResConfList(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_QueryResConfList, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_SetHwProf(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_SetHwProf *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_SETHWPROF];
+
+ r = talloc(talloc_tos(), struct PNP_SetHwProf);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_SetHwProf, r);
+ }
+
+ r->out.result = _PNP_SetHwProf(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_SetHwProf, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_QueryArbitratorFreeData(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_QueryArbitratorFreeData *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_QUERYARBITRATORFREEDATA];
+
+ r = talloc(talloc_tos(), struct PNP_QueryArbitratorFreeData);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_QueryArbitratorFreeData, r);
+ }
+
+ r->out.result = _PNP_QueryArbitratorFreeData(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_QueryArbitratorFreeData, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_QueryArbitratorFreeSize(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_QueryArbitratorFreeSize *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_QUERYARBITRATORFREESIZE];
+
+ r = talloc(talloc_tos(), struct PNP_QueryArbitratorFreeSize);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_QueryArbitratorFreeSize, r);
+ }
+
+ r->out.result = _PNP_QueryArbitratorFreeSize(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_QueryArbitratorFreeSize, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_RunDetection(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_RunDetection *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_RUNDETECTION];
+
+ r = talloc(talloc_tos(), struct PNP_RunDetection);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_RunDetection, r);
+ }
+
+ r->out.result = _PNP_RunDetection(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_RunDetection, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_RegisterNotification(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_RegisterNotification *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_REGISTERNOTIFICATION];
+
+ r = talloc(talloc_tos(), struct PNP_RegisterNotification);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_RegisterNotification, r);
+ }
+
+ r->out.result = _PNP_RegisterNotification(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_RegisterNotification, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_UnregisterNotification(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_UnregisterNotification *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_UNREGISTERNOTIFICATION];
+
+ r = talloc(talloc_tos(), struct PNP_UnregisterNotification);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_UnregisterNotification, r);
+ }
+
+ r->out.result = _PNP_UnregisterNotification(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_UnregisterNotification, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetCustomDevProp(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetCustomDevProp *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETCUSTOMDEVPROP];
+
+ r = talloc(talloc_tos(), struct PNP_GetCustomDevProp);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetCustomDevProp, r);
+ }
+
+ r->out.result = _PNP_GetCustomDevProp(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetCustomDevProp, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetVersionInternal(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetVersionInternal *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETVERSIONINTERNAL];
+
+ r = talloc(talloc_tos(), struct PNP_GetVersionInternal);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetVersionInternal, r);
+ }
+
+ r->out.result = _PNP_GetVersionInternal(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetVersionInternal, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetBlockedDriverInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetBlockedDriverInfo *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETBLOCKEDDRIVERINFO];
+
+ r = talloc(talloc_tos(), struct PNP_GetBlockedDriverInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetBlockedDriverInfo, r);
+ }
+
+ r->out.result = _PNP_GetBlockedDriverInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetBlockedDriverInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_PNP_GetServerSideDeviceInstallFlags(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct PNP_GetServerSideDeviceInstallFlags *r;
+
+ call = &ndr_table_ntsvcs.calls[NDR_PNP_GETSERVERSIDEDEVICEINSTALLFLAGS];
+
+ r = talloc(talloc_tos(), struct PNP_GetServerSideDeviceInstallFlags);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(PNP_GetServerSideDeviceInstallFlags, r);
+ }
+
+ r->out.result = _PNP_GetServerSideDeviceInstallFlags(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(PNP_GetServerSideDeviceInstallFlags, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+
+/* Tables */
+static struct api_struct api_ntsvcs_cmds[] =
+{
+ {"PNP_DISCONNECT", NDR_PNP_DISCONNECT, api_PNP_Disconnect},
+ {"PNP_CONNECT", NDR_PNP_CONNECT, api_PNP_Connect},
+ {"PNP_GETVERSION", NDR_PNP_GETVERSION, api_PNP_GetVersion},
+ {"PNP_GETGLOBALSTATE", NDR_PNP_GETGLOBALSTATE, api_PNP_GetGlobalState},
+ {"PNP_INITDETECTION", NDR_PNP_INITDETECTION, api_PNP_InitDetection},
+ {"PNP_REPORTLOGON", NDR_PNP_REPORTLOGON, api_PNP_ReportLogOn},
+ {"PNP_VALIDATEDEVICEINSTANCE", NDR_PNP_VALIDATEDEVICEINSTANCE, api_PNP_ValidateDeviceInstance},
+ {"PNP_GETROOTDEVICEINSTANCE", NDR_PNP_GETROOTDEVICEINSTANCE, api_PNP_GetRootDeviceInstance},
+ {"PNP_GETRELATEDDEVICEINSTANCE", NDR_PNP_GETRELATEDDEVICEINSTANCE, api_PNP_GetRelatedDeviceInstance},
+ {"PNP_ENUMERATESUBKEYS", NDR_PNP_ENUMERATESUBKEYS, api_PNP_EnumerateSubKeys},
+ {"PNP_GETDEVICELIST", NDR_PNP_GETDEVICELIST, api_PNP_GetDeviceList},
+ {"PNP_GETDEVICELISTSIZE", NDR_PNP_GETDEVICELISTSIZE, api_PNP_GetDeviceListSize},
+ {"PNP_GETDEPTH", NDR_PNP_GETDEPTH, api_PNP_GetDepth},
+ {"PNP_GETDEVICEREGPROP", NDR_PNP_GETDEVICEREGPROP, api_PNP_GetDeviceRegProp},
+ {"PNP_SETDEVICEREGPROP", NDR_PNP_SETDEVICEREGPROP, api_PNP_SetDeviceRegProp},
+ {"PNP_GETCLASSINSTANCE", NDR_PNP_GETCLASSINSTANCE, api_PNP_GetClassInstance},
+ {"PNP_CREATEKEY", NDR_PNP_CREATEKEY, api_PNP_CreateKey},
+ {"PNP_DELETEREGISTRYKEY", NDR_PNP_DELETEREGISTRYKEY, api_PNP_DeleteRegistryKey},
+ {"PNP_GETCLASSCOUNT", NDR_PNP_GETCLASSCOUNT, api_PNP_GetClassCount},
+ {"PNP_GETCLASSNAME", NDR_PNP_GETCLASSNAME, api_PNP_GetClassName},
+ {"PNP_DELETECLASSKEY", NDR_PNP_DELETECLASSKEY, api_PNP_DeleteClassKey},
+ {"PNP_GETINTERFACEDEVICEALIAS", NDR_PNP_GETINTERFACEDEVICEALIAS, api_PNP_GetInterfaceDeviceAlias},
+ {"PNP_GETINTERFACEDEVICELIST", NDR_PNP_GETINTERFACEDEVICELIST, api_PNP_GetInterfaceDeviceList},
+ {"PNP_GETINTERFACEDEVICELISTSIZE", NDR_PNP_GETINTERFACEDEVICELISTSIZE, api_PNP_GetInterfaceDeviceListSize},
+ {"PNP_REGISTERDEVICECLASSASSOCIATION", NDR_PNP_REGISTERDEVICECLASSASSOCIATION, api_PNP_RegisterDeviceClassAssociation},
+ {"PNP_UNREGISTERDEVICECLASSASSOCIATION", NDR_PNP_UNREGISTERDEVICECLASSASSOCIATION, api_PNP_UnregisterDeviceClassAssociation},
+ {"PNP_GETCLASSREGPROP", NDR_PNP_GETCLASSREGPROP, api_PNP_GetClassRegProp},
+ {"PNP_SETCLASSREGPROP", NDR_PNP_SETCLASSREGPROP, api_PNP_SetClassRegProp},
+ {"PNP_CREATEDEVINST", NDR_PNP_CREATEDEVINST, api_PNP_CreateDevInst},
+ {"PNP_DEVICEINSTANCEACTION", NDR_PNP_DEVICEINSTANCEACTION, api_PNP_DeviceInstanceAction},
+ {"PNP_GETDEVICESTATUS", NDR_PNP_GETDEVICESTATUS, api_PNP_GetDeviceStatus},
+ {"PNP_SETDEVICEPROBLEM", NDR_PNP_SETDEVICEPROBLEM, api_PNP_SetDeviceProblem},
+ {"PNP_DISABLEDEVINST", NDR_PNP_DISABLEDEVINST, api_PNP_DisableDevInst},
+ {"PNP_UNINSTALLDEVINST", NDR_PNP_UNINSTALLDEVINST, api_PNP_UninstallDevInst},
+ {"PNP_ADDID", NDR_PNP_ADDID, api_PNP_AddID},
+ {"PNP_REGISTERDRIVER", NDR_PNP_REGISTERDRIVER, api_PNP_RegisterDriver},
+ {"PNP_QUERYREMOVE", NDR_PNP_QUERYREMOVE, api_PNP_QueryRemove},
+ {"PNP_REQUESTDEVICEEJECT", NDR_PNP_REQUESTDEVICEEJECT, api_PNP_RequestDeviceEject},
+ {"PNP_ISDOCKSTATIONPRESENT", NDR_PNP_ISDOCKSTATIONPRESENT, api_PNP_IsDockStationPresent},
+ {"PNP_REQUESTEJECTPC", NDR_PNP_REQUESTEJECTPC, api_PNP_RequestEjectPC},
+ {"PNP_HWPROFFLAGS", NDR_PNP_HWPROFFLAGS, api_PNP_HwProfFlags},
+ {"PNP_GETHWPROFINFO", NDR_PNP_GETHWPROFINFO, api_PNP_GetHwProfInfo},
+ {"PNP_ADDEMPTYLOGCONF", NDR_PNP_ADDEMPTYLOGCONF, api_PNP_AddEmptyLogConf},
+ {"PNP_FREELOGCONF", NDR_PNP_FREELOGCONF, api_PNP_FreeLogConf},
+ {"PNP_GETFIRSTLOGCONF", NDR_PNP_GETFIRSTLOGCONF, api_PNP_GetFirstLogConf},
+ {"PNP_GETNEXTLOGCONF", NDR_PNP_GETNEXTLOGCONF, api_PNP_GetNextLogConf},
+ {"PNP_GETLOGCONFPRIORITY", NDR_PNP_GETLOGCONFPRIORITY, api_PNP_GetLogConfPriority},
+ {"PNP_ADDRESDES", NDR_PNP_ADDRESDES, api_PNP_AddResDes},
+ {"PNP_FREERESDES", NDR_PNP_FREERESDES, api_PNP_FreeResDes},
+ {"PNP_GETNEXTRESDES", NDR_PNP_GETNEXTRESDES, api_PNP_GetNextResDes},
+ {"PNP_GETRESDESDATA", NDR_PNP_GETRESDESDATA, api_PNP_GetResDesData},
+ {"PNP_GETRESDESDATASIZE", NDR_PNP_GETRESDESDATASIZE, api_PNP_GetResDesDataSize},
+ {"PNP_MODIFYRESDES", NDR_PNP_MODIFYRESDES, api_PNP_ModifyResDes},
+ {"PNP_DETECTRESOURCELIMIT", NDR_PNP_DETECTRESOURCELIMIT, api_PNP_DetectResourceLimit},
+ {"PNP_QUERYRESCONFLIST", NDR_PNP_QUERYRESCONFLIST, api_PNP_QueryResConfList},
+ {"PNP_SETHWPROF", NDR_PNP_SETHWPROF, api_PNP_SetHwProf},
+ {"PNP_QUERYARBITRATORFREEDATA", NDR_PNP_QUERYARBITRATORFREEDATA, api_PNP_QueryArbitratorFreeData},
+ {"PNP_QUERYARBITRATORFREESIZE", NDR_PNP_QUERYARBITRATORFREESIZE, api_PNP_QueryArbitratorFreeSize},
+ {"PNP_RUNDETECTION", NDR_PNP_RUNDETECTION, api_PNP_RunDetection},
+ {"PNP_REGISTERNOTIFICATION", NDR_PNP_REGISTERNOTIFICATION, api_PNP_RegisterNotification},
+ {"PNP_UNREGISTERNOTIFICATION", NDR_PNP_UNREGISTERNOTIFICATION, api_PNP_UnregisterNotification},
+ {"PNP_GETCUSTOMDEVPROP", NDR_PNP_GETCUSTOMDEVPROP, api_PNP_GetCustomDevProp},
+ {"PNP_GETVERSIONINTERNAL", NDR_PNP_GETVERSIONINTERNAL, api_PNP_GetVersionInternal},
+ {"PNP_GETBLOCKEDDRIVERINFO", NDR_PNP_GETBLOCKEDDRIVERINFO, api_PNP_GetBlockedDriverInfo},
+ {"PNP_GETSERVERSIDEDEVICEINSTALLFLAGS", NDR_PNP_GETSERVERSIDEDEVICEINSTALLFLAGS, api_PNP_GetServerSideDeviceInstallFlags},
+};
+
+void ntsvcs_get_pipe_fns(struct api_struct **fns, int *n_fns)
+{
+ *fns = api_ntsvcs_cmds;
+ *n_fns = sizeof(api_ntsvcs_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_ntsvcs_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "ntsvcs", "ntsvcs", &ndr_table_ntsvcs.syntax_id, api_ntsvcs_cmds, sizeof(api_ntsvcs_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/librpc/gen_ndr/srv_ntsvcs.h b/source3/librpc/gen_ndr/srv_ntsvcs.h
new file mode 100644
index 0000000000..c3969b11da
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_ntsvcs.h
@@ -0,0 +1,71 @@
+#include "librpc/gen_ndr/ndr_ntsvcs.h"
+#ifndef __SRV_NTSVCS__
+#define __SRV_NTSVCS__
+WERROR _PNP_Disconnect(pipes_struct *p, struct PNP_Disconnect *r);
+WERROR _PNP_Connect(pipes_struct *p, struct PNP_Connect *r);
+WERROR _PNP_GetVersion(pipes_struct *p, struct PNP_GetVersion *r);
+WERROR _PNP_GetGlobalState(pipes_struct *p, struct PNP_GetGlobalState *r);
+WERROR _PNP_InitDetection(pipes_struct *p, struct PNP_InitDetection *r);
+WERROR _PNP_ReportLogOn(pipes_struct *p, struct PNP_ReportLogOn *r);
+WERROR _PNP_ValidateDeviceInstance(pipes_struct *p, struct PNP_ValidateDeviceInstance *r);
+WERROR _PNP_GetRootDeviceInstance(pipes_struct *p, struct PNP_GetRootDeviceInstance *r);
+WERROR _PNP_GetRelatedDeviceInstance(pipes_struct *p, struct PNP_GetRelatedDeviceInstance *r);
+WERROR _PNP_EnumerateSubKeys(pipes_struct *p, struct PNP_EnumerateSubKeys *r);
+WERROR _PNP_GetDeviceList(pipes_struct *p, struct PNP_GetDeviceList *r);
+WERROR _PNP_GetDeviceListSize(pipes_struct *p, struct PNP_GetDeviceListSize *r);
+WERROR _PNP_GetDepth(pipes_struct *p, struct PNP_GetDepth *r);
+WERROR _PNP_GetDeviceRegProp(pipes_struct *p, struct PNP_GetDeviceRegProp *r);
+WERROR _PNP_SetDeviceRegProp(pipes_struct *p, struct PNP_SetDeviceRegProp *r);
+WERROR _PNP_GetClassInstance(pipes_struct *p, struct PNP_GetClassInstance *r);
+WERROR _PNP_CreateKey(pipes_struct *p, struct PNP_CreateKey *r);
+WERROR _PNP_DeleteRegistryKey(pipes_struct *p, struct PNP_DeleteRegistryKey *r);
+WERROR _PNP_GetClassCount(pipes_struct *p, struct PNP_GetClassCount *r);
+WERROR _PNP_GetClassName(pipes_struct *p, struct PNP_GetClassName *r);
+WERROR _PNP_DeleteClassKey(pipes_struct *p, struct PNP_DeleteClassKey *r);
+WERROR _PNP_GetInterfaceDeviceAlias(pipes_struct *p, struct PNP_GetInterfaceDeviceAlias *r);
+WERROR _PNP_GetInterfaceDeviceList(pipes_struct *p, struct PNP_GetInterfaceDeviceList *r);
+WERROR _PNP_GetInterfaceDeviceListSize(pipes_struct *p, struct PNP_GetInterfaceDeviceListSize *r);
+WERROR _PNP_RegisterDeviceClassAssociation(pipes_struct *p, struct PNP_RegisterDeviceClassAssociation *r);
+WERROR _PNP_UnregisterDeviceClassAssociation(pipes_struct *p, struct PNP_UnregisterDeviceClassAssociation *r);
+WERROR _PNP_GetClassRegProp(pipes_struct *p, struct PNP_GetClassRegProp *r);
+WERROR _PNP_SetClassRegProp(pipes_struct *p, struct PNP_SetClassRegProp *r);
+WERROR _PNP_CreateDevInst(pipes_struct *p, struct PNP_CreateDevInst *r);
+WERROR _PNP_DeviceInstanceAction(pipes_struct *p, struct PNP_DeviceInstanceAction *r);
+WERROR _PNP_GetDeviceStatus(pipes_struct *p, struct PNP_GetDeviceStatus *r);
+WERROR _PNP_SetDeviceProblem(pipes_struct *p, struct PNP_SetDeviceProblem *r);
+WERROR _PNP_DisableDevInst(pipes_struct *p, struct PNP_DisableDevInst *r);
+WERROR _PNP_UninstallDevInst(pipes_struct *p, struct PNP_UninstallDevInst *r);
+WERROR _PNP_AddID(pipes_struct *p, struct PNP_AddID *r);
+WERROR _PNP_RegisterDriver(pipes_struct *p, struct PNP_RegisterDriver *r);
+WERROR _PNP_QueryRemove(pipes_struct *p, struct PNP_QueryRemove *r);
+WERROR _PNP_RequestDeviceEject(pipes_struct *p, struct PNP_RequestDeviceEject *r);
+WERROR _PNP_IsDockStationPresent(pipes_struct *p, struct PNP_IsDockStationPresent *r);
+WERROR _PNP_RequestEjectPC(pipes_struct *p, struct PNP_RequestEjectPC *r);
+WERROR _PNP_HwProfFlags(pipes_struct *p, struct PNP_HwProfFlags *r);
+WERROR _PNP_GetHwProfInfo(pipes_struct *p, struct PNP_GetHwProfInfo *r);
+WERROR _PNP_AddEmptyLogConf(pipes_struct *p, struct PNP_AddEmptyLogConf *r);
+WERROR _PNP_FreeLogConf(pipes_struct *p, struct PNP_FreeLogConf *r);
+WERROR _PNP_GetFirstLogConf(pipes_struct *p, struct PNP_GetFirstLogConf *r);
+WERROR _PNP_GetNextLogConf(pipes_struct *p, struct PNP_GetNextLogConf *r);
+WERROR _PNP_GetLogConfPriority(pipes_struct *p, struct PNP_GetLogConfPriority *r);
+WERROR _PNP_AddResDes(pipes_struct *p, struct PNP_AddResDes *r);
+WERROR _PNP_FreeResDes(pipes_struct *p, struct PNP_FreeResDes *r);
+WERROR _PNP_GetNextResDes(pipes_struct *p, struct PNP_GetNextResDes *r);
+WERROR _PNP_GetResDesData(pipes_struct *p, struct PNP_GetResDesData *r);
+WERROR _PNP_GetResDesDataSize(pipes_struct *p, struct PNP_GetResDesDataSize *r);
+WERROR _PNP_ModifyResDes(pipes_struct *p, struct PNP_ModifyResDes *r);
+WERROR _PNP_DetectResourceLimit(pipes_struct *p, struct PNP_DetectResourceLimit *r);
+WERROR _PNP_QueryResConfList(pipes_struct *p, struct PNP_QueryResConfList *r);
+WERROR _PNP_SetHwProf(pipes_struct *p, struct PNP_SetHwProf *r);
+WERROR _PNP_QueryArbitratorFreeData(pipes_struct *p, struct PNP_QueryArbitratorFreeData *r);
+WERROR _PNP_QueryArbitratorFreeSize(pipes_struct *p, struct PNP_QueryArbitratorFreeSize *r);
+WERROR _PNP_RunDetection(pipes_struct *p, struct PNP_RunDetection *r);
+WERROR _PNP_RegisterNotification(pipes_struct *p, struct PNP_RegisterNotification *r);
+WERROR _PNP_UnregisterNotification(pipes_struct *p, struct PNP_UnregisterNotification *r);
+WERROR _PNP_GetCustomDevProp(pipes_struct *p, struct PNP_GetCustomDevProp *r);
+WERROR _PNP_GetVersionInternal(pipes_struct *p, struct PNP_GetVersionInternal *r);
+WERROR _PNP_GetBlockedDriverInfo(pipes_struct *p, struct PNP_GetBlockedDriverInfo *r);
+WERROR _PNP_GetServerSideDeviceInstallFlags(pipes_struct *p, struct PNP_GetServerSideDeviceInstallFlags *r);
+void ntsvcs_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_ntsvcs_init(void);
+#endif /* __SRV_NTSVCS__ */
diff --git a/source3/librpc/gen_ndr/srv_samr.c b/source3/librpc/gen_ndr/srv_samr.c
new file mode 100644
index 0000000000..1eaa19eaf7
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_samr.c
@@ -0,0 +1,5482 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * server auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/srv_samr.h"
+
+static bool api_samr_Connect(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_Connect *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_CONNECT];
+
+ r = talloc(talloc_tos(), struct samr_Connect);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_Connect, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.connect_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.connect_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_Connect(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_Connect, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_Close(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_Close *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_CLOSE];
+
+ r = talloc(talloc_tos(), struct samr_Close);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_Close, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = r->in.handle;
+ r->out.result = _samr_Close(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_Close, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_SetSecurity(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_SetSecurity *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_SETSECURITY];
+
+ r = talloc(talloc_tos(), struct samr_SetSecurity);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetSecurity, r);
+ }
+
+ r->out.result = _samr_SetSecurity(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetSecurity, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_QuerySecurity(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_QuerySecurity *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_QUERYSECURITY];
+
+ r = talloc(talloc_tos(), struct samr_QuerySecurity);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QuerySecurity, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.sdbuf = talloc_zero(r, struct sec_desc_buf *);
+ if (r->out.sdbuf == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_QuerySecurity(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QuerySecurity, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_Shutdown(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_Shutdown *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_SHUTDOWN];
+
+ r = talloc(talloc_tos(), struct samr_Shutdown);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_Shutdown, r);
+ }
+
+ r->out.result = _samr_Shutdown(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_Shutdown, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_LookupDomain(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_LookupDomain *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_LOOKUPDOMAIN];
+
+ r = talloc(talloc_tos(), struct samr_LookupDomain);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_LookupDomain, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.sid = talloc_zero(r, struct dom_sid2 *);
+ if (r->out.sid == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_LookupDomain(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_LookupDomain, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_EnumDomains(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_EnumDomains *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_ENUMDOMAINS];
+
+ r = talloc(talloc_tos(), struct samr_EnumDomains);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_EnumDomains, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.sam = talloc_zero(r, struct samr_SamArray *);
+ if (r->out.sam == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.num_entries = talloc_zero(r, uint32_t);
+ if (r->out.num_entries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_EnumDomains(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_EnumDomains, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_OpenDomain(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_OpenDomain *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_OPENDOMAIN];
+
+ r = talloc(talloc_tos(), struct samr_OpenDomain);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_OpenDomain, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.domain_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.domain_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_OpenDomain(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_OpenDomain, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_QueryDomainInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_QueryDomainInfo *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_QUERYDOMAININFO];
+
+ r = talloc(talloc_tos(), struct samr_QueryDomainInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryDomainInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union samr_DomainInfo *);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_QueryDomainInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryDomainInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_SetDomainInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_SetDomainInfo *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_SETDOMAININFO];
+
+ r = talloc(talloc_tos(), struct samr_SetDomainInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetDomainInfo, r);
+ }
+
+ r->out.result = _samr_SetDomainInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetDomainInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_CreateDomainGroup(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_CreateDomainGroup *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_CREATEDOMAINGROUP];
+
+ r = talloc(talloc_tos(), struct samr_CreateDomainGroup);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_CreateDomainGroup, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.group_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.group_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.rid = talloc_zero(r, uint32_t);
+ if (r->out.rid == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_CreateDomainGroup(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_CreateDomainGroup, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_EnumDomainGroups(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_EnumDomainGroups *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_ENUMDOMAINGROUPS];
+
+ r = talloc(talloc_tos(), struct samr_EnumDomainGroups);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_EnumDomainGroups, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.sam = talloc_zero(r, struct samr_SamArray *);
+ if (r->out.sam == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.num_entries = talloc_zero(r, uint32_t);
+ if (r->out.num_entries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_EnumDomainGroups(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_EnumDomainGroups, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_CreateUser(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_CreateUser *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_CREATEUSER];
+
+ r = talloc(talloc_tos(), struct samr_CreateUser);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_CreateUser, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.user_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.user_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.rid = talloc_zero(r, uint32_t);
+ if (r->out.rid == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_CreateUser(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_CreateUser, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_EnumDomainUsers(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_EnumDomainUsers *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_ENUMDOMAINUSERS];
+
+ r = talloc(talloc_tos(), struct samr_EnumDomainUsers);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_EnumDomainUsers, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.sam = talloc_zero(r, struct samr_SamArray *);
+ if (r->out.sam == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.num_entries = talloc_zero(r, uint32_t);
+ if (r->out.num_entries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_EnumDomainUsers(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_EnumDomainUsers, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_CreateDomAlias(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_CreateDomAlias *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_CREATEDOMALIAS];
+
+ r = talloc(talloc_tos(), struct samr_CreateDomAlias);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_CreateDomAlias, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.alias_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.alias_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.rid = talloc_zero(r, uint32_t);
+ if (r->out.rid == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_CreateDomAlias(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_CreateDomAlias, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_EnumDomainAliases(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_EnumDomainAliases *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_ENUMDOMAINALIASES];
+
+ r = talloc(talloc_tos(), struct samr_EnumDomainAliases);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_EnumDomainAliases, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.sam = talloc_zero(r, struct samr_SamArray *);
+ if (r->out.sam == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.num_entries = talloc_zero(r, uint32_t);
+ if (r->out.num_entries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_EnumDomainAliases(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_EnumDomainAliases, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_GetAliasMembership(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_GetAliasMembership *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_GETALIASMEMBERSHIP];
+
+ r = talloc(talloc_tos(), struct samr_GetAliasMembership);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_GetAliasMembership, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.rids = talloc_zero(r, struct samr_Ids);
+ if (r->out.rids == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_GetAliasMembership(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_GetAliasMembership, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_LookupNames(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_LookupNames *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_LOOKUPNAMES];
+
+ r = talloc(talloc_tos(), struct samr_LookupNames);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_LookupNames, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.rids = talloc_zero(r, struct samr_Ids);
+ if (r->out.rids == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.types = talloc_zero(r, struct samr_Ids);
+ if (r->out.types == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_LookupNames(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_LookupNames, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_LookupRids(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_LookupRids *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_LOOKUPRIDS];
+
+ r = talloc(talloc_tos(), struct samr_LookupRids);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_LookupRids, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.names = talloc_zero(r, struct lsa_Strings);
+ if (r->out.names == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.types = talloc_zero(r, struct samr_Ids);
+ if (r->out.types == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_LookupRids(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_LookupRids, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_OpenGroup(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_OpenGroup *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_OPENGROUP];
+
+ r = talloc(talloc_tos(), struct samr_OpenGroup);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_OpenGroup, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.group_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.group_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_OpenGroup(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_OpenGroup, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_QueryGroupInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_QueryGroupInfo *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_QUERYGROUPINFO];
+
+ r = talloc(talloc_tos(), struct samr_QueryGroupInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryGroupInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union samr_GroupInfo *);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_QueryGroupInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryGroupInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_SetGroupInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_SetGroupInfo *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_SETGROUPINFO];
+
+ r = talloc(talloc_tos(), struct samr_SetGroupInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetGroupInfo, r);
+ }
+
+ r->out.result = _samr_SetGroupInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetGroupInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_AddGroupMember(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_AddGroupMember *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_ADDGROUPMEMBER];
+
+ r = talloc(talloc_tos(), struct samr_AddGroupMember);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_AddGroupMember, r);
+ }
+
+ r->out.result = _samr_AddGroupMember(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_AddGroupMember, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_DeleteDomainGroup(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_DeleteDomainGroup *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_DELETEDOMAINGROUP];
+
+ r = talloc(talloc_tos(), struct samr_DeleteDomainGroup);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_DeleteDomainGroup, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.group_handle = r->in.group_handle;
+ r->out.result = _samr_DeleteDomainGroup(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_DeleteDomainGroup, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_DeleteGroupMember(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_DeleteGroupMember *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_DELETEGROUPMEMBER];
+
+ r = talloc(talloc_tos(), struct samr_DeleteGroupMember);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_DeleteGroupMember, r);
+ }
+
+ r->out.result = _samr_DeleteGroupMember(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_DeleteGroupMember, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_QueryGroupMember(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_QueryGroupMember *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_QUERYGROUPMEMBER];
+
+ r = talloc(talloc_tos(), struct samr_QueryGroupMember);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryGroupMember, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.rids = talloc_zero(r, struct samr_RidTypeArray *);
+ if (r->out.rids == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_QueryGroupMember(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryGroupMember, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_SetMemberAttributesOfGroup(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_SetMemberAttributesOfGroup *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_SETMEMBERATTRIBUTESOFGROUP];
+
+ r = talloc(talloc_tos(), struct samr_SetMemberAttributesOfGroup);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetMemberAttributesOfGroup, r);
+ }
+
+ r->out.result = _samr_SetMemberAttributesOfGroup(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetMemberAttributesOfGroup, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_OpenAlias(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_OpenAlias *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_OPENALIAS];
+
+ r = talloc(talloc_tos(), struct samr_OpenAlias);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_OpenAlias, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.alias_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.alias_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_OpenAlias(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_OpenAlias, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_QueryAliasInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_QueryAliasInfo *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_QUERYALIASINFO];
+
+ r = talloc(talloc_tos(), struct samr_QueryAliasInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryAliasInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union samr_AliasInfo *);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_QueryAliasInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryAliasInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_SetAliasInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_SetAliasInfo *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_SETALIASINFO];
+
+ r = talloc(talloc_tos(), struct samr_SetAliasInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetAliasInfo, r);
+ }
+
+ r->out.result = _samr_SetAliasInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetAliasInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_DeleteDomAlias(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_DeleteDomAlias *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_DELETEDOMALIAS];
+
+ r = talloc(talloc_tos(), struct samr_DeleteDomAlias);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_DeleteDomAlias, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.alias_handle = r->in.alias_handle;
+ r->out.result = _samr_DeleteDomAlias(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_DeleteDomAlias, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_AddAliasMember(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_AddAliasMember *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_ADDALIASMEMBER];
+
+ r = talloc(talloc_tos(), struct samr_AddAliasMember);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_AddAliasMember, r);
+ }
+
+ r->out.result = _samr_AddAliasMember(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_AddAliasMember, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_DeleteAliasMember(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_DeleteAliasMember *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_DELETEALIASMEMBER];
+
+ r = talloc(talloc_tos(), struct samr_DeleteAliasMember);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_DeleteAliasMember, r);
+ }
+
+ r->out.result = _samr_DeleteAliasMember(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_DeleteAliasMember, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_GetMembersInAlias(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_GetMembersInAlias *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_GETMEMBERSINALIAS];
+
+ r = talloc(talloc_tos(), struct samr_GetMembersInAlias);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_GetMembersInAlias, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.sids = talloc_zero(r, struct lsa_SidArray);
+ if (r->out.sids == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_GetMembersInAlias(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_GetMembersInAlias, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_OpenUser(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_OpenUser *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_OPENUSER];
+
+ r = talloc(talloc_tos(), struct samr_OpenUser);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_OpenUser, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.user_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.user_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_OpenUser(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_OpenUser, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_DeleteUser(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_DeleteUser *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_DELETEUSER];
+
+ r = talloc(talloc_tos(), struct samr_DeleteUser);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_DeleteUser, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.user_handle = r->in.user_handle;
+ r->out.result = _samr_DeleteUser(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_DeleteUser, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_QueryUserInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_QueryUserInfo *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_QUERYUSERINFO];
+
+ r = talloc(talloc_tos(), struct samr_QueryUserInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryUserInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union samr_UserInfo *);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_QueryUserInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryUserInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_SetUserInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_SetUserInfo *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_SETUSERINFO];
+
+ r = talloc(talloc_tos(), struct samr_SetUserInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetUserInfo, r);
+ }
+
+ r->out.result = _samr_SetUserInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetUserInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_ChangePasswordUser(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_ChangePasswordUser *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_CHANGEPASSWORDUSER];
+
+ r = talloc(talloc_tos(), struct samr_ChangePasswordUser);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_ChangePasswordUser, r);
+ }
+
+ r->out.result = _samr_ChangePasswordUser(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_ChangePasswordUser, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_GetGroupsForUser(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_GetGroupsForUser *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_GETGROUPSFORUSER];
+
+ r = talloc(talloc_tos(), struct samr_GetGroupsForUser);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_GetGroupsForUser, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.rids = talloc_zero(r, struct samr_RidWithAttributeArray *);
+ if (r->out.rids == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_GetGroupsForUser(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_GetGroupsForUser, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_QueryDisplayInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_QueryDisplayInfo *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_QUERYDISPLAYINFO];
+
+ r = talloc(talloc_tos(), struct samr_QueryDisplayInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryDisplayInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.total_size = talloc_zero(r, uint32_t);
+ if (r->out.total_size == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.returned_size = talloc_zero(r, uint32_t);
+ if (r->out.returned_size == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.info = talloc_zero(r, union samr_DispInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_QueryDisplayInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryDisplayInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_GetDisplayEnumerationIndex(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_GetDisplayEnumerationIndex *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_GETDISPLAYENUMERATIONINDEX];
+
+ r = talloc(talloc_tos(), struct samr_GetDisplayEnumerationIndex);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_GetDisplayEnumerationIndex, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.idx = talloc_zero(r, uint32_t);
+ if (r->out.idx == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_GetDisplayEnumerationIndex(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_GetDisplayEnumerationIndex, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_TestPrivateFunctionsDomain(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_TestPrivateFunctionsDomain *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_TESTPRIVATEFUNCTIONSDOMAIN];
+
+ r = talloc(talloc_tos(), struct samr_TestPrivateFunctionsDomain);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_TestPrivateFunctionsDomain, r);
+ }
+
+ r->out.result = _samr_TestPrivateFunctionsDomain(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_TestPrivateFunctionsDomain, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_TestPrivateFunctionsUser(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_TestPrivateFunctionsUser *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_TESTPRIVATEFUNCTIONSUSER];
+
+ r = talloc(talloc_tos(), struct samr_TestPrivateFunctionsUser);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_TestPrivateFunctionsUser, r);
+ }
+
+ r->out.result = _samr_TestPrivateFunctionsUser(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_TestPrivateFunctionsUser, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_GetUserPwInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_GetUserPwInfo *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_GETUSERPWINFO];
+
+ r = talloc(talloc_tos(), struct samr_GetUserPwInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_GetUserPwInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, struct samr_PwInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_GetUserPwInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_GetUserPwInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_RemoveMemberFromForeignDomain(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_RemoveMemberFromForeignDomain *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_REMOVEMEMBERFROMFOREIGNDOMAIN];
+
+ r = talloc(talloc_tos(), struct samr_RemoveMemberFromForeignDomain);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_RemoveMemberFromForeignDomain, r);
+ }
+
+ r->out.result = _samr_RemoveMemberFromForeignDomain(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_RemoveMemberFromForeignDomain, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_QueryDomainInfo2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_QueryDomainInfo2 *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_QUERYDOMAININFO2];
+
+ r = talloc(talloc_tos(), struct samr_QueryDomainInfo2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryDomainInfo2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union samr_DomainInfo *);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_QueryDomainInfo2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryDomainInfo2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_QueryUserInfo2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_QueryUserInfo2 *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_QUERYUSERINFO2];
+
+ r = talloc(talloc_tos(), struct samr_QueryUserInfo2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryUserInfo2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union samr_UserInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_QueryUserInfo2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryUserInfo2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_QueryDisplayInfo2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_QueryDisplayInfo2 *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_QUERYDISPLAYINFO2];
+
+ r = talloc(talloc_tos(), struct samr_QueryDisplayInfo2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryDisplayInfo2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.total_size = talloc_zero(r, uint32_t);
+ if (r->out.total_size == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.returned_size = talloc_zero(r, uint32_t);
+ if (r->out.returned_size == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.info = talloc_zero(r, union samr_DispInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_QueryDisplayInfo2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryDisplayInfo2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_GetDisplayEnumerationIndex2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_GetDisplayEnumerationIndex2 *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_GETDISPLAYENUMERATIONINDEX2];
+
+ r = talloc(talloc_tos(), struct samr_GetDisplayEnumerationIndex2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_GetDisplayEnumerationIndex2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.idx = talloc_zero(r, uint32_t);
+ if (r->out.idx == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_GetDisplayEnumerationIndex2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_GetDisplayEnumerationIndex2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_CreateUser2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_CreateUser2 *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_CREATEUSER2];
+
+ r = talloc(talloc_tos(), struct samr_CreateUser2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_CreateUser2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.user_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.user_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.access_granted = talloc_zero(r, uint32_t);
+ if (r->out.access_granted == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.rid = talloc_zero(r, uint32_t);
+ if (r->out.rid == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_CreateUser2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_CreateUser2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_QueryDisplayInfo3(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_QueryDisplayInfo3 *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_QUERYDISPLAYINFO3];
+
+ r = talloc(talloc_tos(), struct samr_QueryDisplayInfo3);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_QueryDisplayInfo3, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.total_size = talloc_zero(r, uint32_t);
+ if (r->out.total_size == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.returned_size = talloc_zero(r, uint32_t);
+ if (r->out.returned_size == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.info = talloc_zero(r, union samr_DispInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_QueryDisplayInfo3(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_QueryDisplayInfo3, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_AddMultipleMembersToAlias(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_AddMultipleMembersToAlias *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_ADDMULTIPLEMEMBERSTOALIAS];
+
+ r = talloc(talloc_tos(), struct samr_AddMultipleMembersToAlias);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_AddMultipleMembersToAlias, r);
+ }
+
+ r->out.result = _samr_AddMultipleMembersToAlias(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_AddMultipleMembersToAlias, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_RemoveMultipleMembersFromAlias(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_RemoveMultipleMembersFromAlias *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_REMOVEMULTIPLEMEMBERSFROMALIAS];
+
+ r = talloc(talloc_tos(), struct samr_RemoveMultipleMembersFromAlias);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_RemoveMultipleMembersFromAlias, r);
+ }
+
+ r->out.result = _samr_RemoveMultipleMembersFromAlias(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_RemoveMultipleMembersFromAlias, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_OemChangePasswordUser2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_OemChangePasswordUser2 *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_OEMCHANGEPASSWORDUSER2];
+
+ r = talloc(talloc_tos(), struct samr_OemChangePasswordUser2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_OemChangePasswordUser2, r);
+ }
+
+ r->out.result = _samr_OemChangePasswordUser2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_OemChangePasswordUser2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_ChangePasswordUser2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_ChangePasswordUser2 *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_CHANGEPASSWORDUSER2];
+
+ r = talloc(talloc_tos(), struct samr_ChangePasswordUser2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_ChangePasswordUser2, r);
+ }
+
+ r->out.result = _samr_ChangePasswordUser2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_ChangePasswordUser2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_GetDomPwInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_GetDomPwInfo *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_GETDOMPWINFO];
+
+ r = talloc(talloc_tos(), struct samr_GetDomPwInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_GetDomPwInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, struct samr_PwInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_GetDomPwInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_GetDomPwInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_Connect2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_Connect2 *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_CONNECT2];
+
+ r = talloc(talloc_tos(), struct samr_Connect2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_Connect2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.connect_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.connect_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_Connect2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_Connect2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_SetUserInfo2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_SetUserInfo2 *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_SETUSERINFO2];
+
+ r = talloc(talloc_tos(), struct samr_SetUserInfo2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetUserInfo2, r);
+ }
+
+ r->out.result = _samr_SetUserInfo2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetUserInfo2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_SetBootKeyInformation(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_SetBootKeyInformation *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_SETBOOTKEYINFORMATION];
+
+ r = talloc(talloc_tos(), struct samr_SetBootKeyInformation);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetBootKeyInformation, r);
+ }
+
+ r->out.result = _samr_SetBootKeyInformation(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetBootKeyInformation, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_GetBootKeyInformation(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_GetBootKeyInformation *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_GETBOOTKEYINFORMATION];
+
+ r = talloc(talloc_tos(), struct samr_GetBootKeyInformation);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_GetBootKeyInformation, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.unknown = talloc_zero(r, uint32_t);
+ if (r->out.unknown == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_GetBootKeyInformation(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_GetBootKeyInformation, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_Connect3(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_Connect3 *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_CONNECT3];
+
+ r = talloc(talloc_tos(), struct samr_Connect3);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_Connect3, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.connect_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.connect_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_Connect3(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_Connect3, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_Connect4(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_Connect4 *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_CONNECT4];
+
+ r = talloc(talloc_tos(), struct samr_Connect4);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_Connect4, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.connect_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.connect_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_Connect4(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_Connect4, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_ChangePasswordUser3(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_ChangePasswordUser3 *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_CHANGEPASSWORDUSER3];
+
+ r = talloc(talloc_tos(), struct samr_ChangePasswordUser3);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_ChangePasswordUser3, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.dominfo = talloc_zero(r, struct samr_DomInfo1 *);
+ if (r->out.dominfo == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.reject = talloc_zero(r, struct samr_ChangeReject *);
+ if (r->out.reject == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_ChangePasswordUser3(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_ChangePasswordUser3, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_Connect5(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_Connect5 *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_CONNECT5];
+
+ r = talloc(talloc_tos(), struct samr_Connect5);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_Connect5, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.level_out = talloc_zero(r, uint32_t);
+ if (r->out.level_out == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.info_out = talloc_zero(r, union samr_ConnectInfo);
+ if (r->out.info_out == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.connect_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.connect_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_Connect5(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_Connect5, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_RidToSid(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_RidToSid *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_RIDTOSID];
+
+ r = talloc(talloc_tos(), struct samr_RidToSid);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_RidToSid, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.sid = talloc_zero(r, struct dom_sid2);
+ if (r->out.sid == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_RidToSid(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_RidToSid, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_SetDsrmPassword(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_SetDsrmPassword *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_SETDSRMPASSWORD];
+
+ r = talloc(talloc_tos(), struct samr_SetDsrmPassword);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_SetDsrmPassword, r);
+ }
+
+ r->out.result = _samr_SetDsrmPassword(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_SetDsrmPassword, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_samr_ValidatePassword(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct samr_ValidatePassword *r;
+
+ call = &ndr_table_samr.calls[NDR_SAMR_VALIDATEPASSWORD];
+
+ r = talloc(talloc_tos(), struct samr_ValidatePassword);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(samr_ValidatePassword, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.rep = talloc_zero(r, union samr_ValidatePasswordRep);
+ if (r->out.rep == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _samr_ValidatePassword(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(samr_ValidatePassword, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+
+/* Tables */
+static struct api_struct api_samr_cmds[] =
+{
+ {"SAMR_CONNECT", NDR_SAMR_CONNECT, api_samr_Connect},
+ {"SAMR_CLOSE", NDR_SAMR_CLOSE, api_samr_Close},
+ {"SAMR_SETSECURITY", NDR_SAMR_SETSECURITY, api_samr_SetSecurity},
+ {"SAMR_QUERYSECURITY", NDR_SAMR_QUERYSECURITY, api_samr_QuerySecurity},
+ {"SAMR_SHUTDOWN", NDR_SAMR_SHUTDOWN, api_samr_Shutdown},
+ {"SAMR_LOOKUPDOMAIN", NDR_SAMR_LOOKUPDOMAIN, api_samr_LookupDomain},
+ {"SAMR_ENUMDOMAINS", NDR_SAMR_ENUMDOMAINS, api_samr_EnumDomains},
+ {"SAMR_OPENDOMAIN", NDR_SAMR_OPENDOMAIN, api_samr_OpenDomain},
+ {"SAMR_QUERYDOMAININFO", NDR_SAMR_QUERYDOMAININFO, api_samr_QueryDomainInfo},
+ {"SAMR_SETDOMAININFO", NDR_SAMR_SETDOMAININFO, api_samr_SetDomainInfo},
+ {"SAMR_CREATEDOMAINGROUP", NDR_SAMR_CREATEDOMAINGROUP, api_samr_CreateDomainGroup},
+ {"SAMR_ENUMDOMAINGROUPS", NDR_SAMR_ENUMDOMAINGROUPS, api_samr_EnumDomainGroups},
+ {"SAMR_CREATEUSER", NDR_SAMR_CREATEUSER, api_samr_CreateUser},
+ {"SAMR_ENUMDOMAINUSERS", NDR_SAMR_ENUMDOMAINUSERS, api_samr_EnumDomainUsers},
+ {"SAMR_CREATEDOMALIAS", NDR_SAMR_CREATEDOMALIAS, api_samr_CreateDomAlias},
+ {"SAMR_ENUMDOMAINALIASES", NDR_SAMR_ENUMDOMAINALIASES, api_samr_EnumDomainAliases},
+ {"SAMR_GETALIASMEMBERSHIP", NDR_SAMR_GETALIASMEMBERSHIP, api_samr_GetAliasMembership},
+ {"SAMR_LOOKUPNAMES", NDR_SAMR_LOOKUPNAMES, api_samr_LookupNames},
+ {"SAMR_LOOKUPRIDS", NDR_SAMR_LOOKUPRIDS, api_samr_LookupRids},
+ {"SAMR_OPENGROUP", NDR_SAMR_OPENGROUP, api_samr_OpenGroup},
+ {"SAMR_QUERYGROUPINFO", NDR_SAMR_QUERYGROUPINFO, api_samr_QueryGroupInfo},
+ {"SAMR_SETGROUPINFO", NDR_SAMR_SETGROUPINFO, api_samr_SetGroupInfo},
+ {"SAMR_ADDGROUPMEMBER", NDR_SAMR_ADDGROUPMEMBER, api_samr_AddGroupMember},
+ {"SAMR_DELETEDOMAINGROUP", NDR_SAMR_DELETEDOMAINGROUP, api_samr_DeleteDomainGroup},
+ {"SAMR_DELETEGROUPMEMBER", NDR_SAMR_DELETEGROUPMEMBER, api_samr_DeleteGroupMember},
+ {"SAMR_QUERYGROUPMEMBER", NDR_SAMR_QUERYGROUPMEMBER, api_samr_QueryGroupMember},
+ {"SAMR_SETMEMBERATTRIBUTESOFGROUP", NDR_SAMR_SETMEMBERATTRIBUTESOFGROUP, api_samr_SetMemberAttributesOfGroup},
+ {"SAMR_OPENALIAS", NDR_SAMR_OPENALIAS, api_samr_OpenAlias},
+ {"SAMR_QUERYALIASINFO", NDR_SAMR_QUERYALIASINFO, api_samr_QueryAliasInfo},
+ {"SAMR_SETALIASINFO", NDR_SAMR_SETALIASINFO, api_samr_SetAliasInfo},
+ {"SAMR_DELETEDOMALIAS", NDR_SAMR_DELETEDOMALIAS, api_samr_DeleteDomAlias},
+ {"SAMR_ADDALIASMEMBER", NDR_SAMR_ADDALIASMEMBER, api_samr_AddAliasMember},
+ {"SAMR_DELETEALIASMEMBER", NDR_SAMR_DELETEALIASMEMBER, api_samr_DeleteAliasMember},
+ {"SAMR_GETMEMBERSINALIAS", NDR_SAMR_GETMEMBERSINALIAS, api_samr_GetMembersInAlias},
+ {"SAMR_OPENUSER", NDR_SAMR_OPENUSER, api_samr_OpenUser},
+ {"SAMR_DELETEUSER", NDR_SAMR_DELETEUSER, api_samr_DeleteUser},
+ {"SAMR_QUERYUSERINFO", NDR_SAMR_QUERYUSERINFO, api_samr_QueryUserInfo},
+ {"SAMR_SETUSERINFO", NDR_SAMR_SETUSERINFO, api_samr_SetUserInfo},
+ {"SAMR_CHANGEPASSWORDUSER", NDR_SAMR_CHANGEPASSWORDUSER, api_samr_ChangePasswordUser},
+ {"SAMR_GETGROUPSFORUSER", NDR_SAMR_GETGROUPSFORUSER, api_samr_GetGroupsForUser},
+ {"SAMR_QUERYDISPLAYINFO", NDR_SAMR_QUERYDISPLAYINFO, api_samr_QueryDisplayInfo},
+ {"SAMR_GETDISPLAYENUMERATIONINDEX", NDR_SAMR_GETDISPLAYENUMERATIONINDEX, api_samr_GetDisplayEnumerationIndex},
+ {"SAMR_TESTPRIVATEFUNCTIONSDOMAIN", NDR_SAMR_TESTPRIVATEFUNCTIONSDOMAIN, api_samr_TestPrivateFunctionsDomain},
+ {"SAMR_TESTPRIVATEFUNCTIONSUSER", NDR_SAMR_TESTPRIVATEFUNCTIONSUSER, api_samr_TestPrivateFunctionsUser},
+ {"SAMR_GETUSERPWINFO", NDR_SAMR_GETUSERPWINFO, api_samr_GetUserPwInfo},
+ {"SAMR_REMOVEMEMBERFROMFOREIGNDOMAIN", NDR_SAMR_REMOVEMEMBERFROMFOREIGNDOMAIN, api_samr_RemoveMemberFromForeignDomain},
+ {"SAMR_QUERYDOMAININFO2", NDR_SAMR_QUERYDOMAININFO2, api_samr_QueryDomainInfo2},
+ {"SAMR_QUERYUSERINFO2", NDR_SAMR_QUERYUSERINFO2, api_samr_QueryUserInfo2},
+ {"SAMR_QUERYDISPLAYINFO2", NDR_SAMR_QUERYDISPLAYINFO2, api_samr_QueryDisplayInfo2},
+ {"SAMR_GETDISPLAYENUMERATIONINDEX2", NDR_SAMR_GETDISPLAYENUMERATIONINDEX2, api_samr_GetDisplayEnumerationIndex2},
+ {"SAMR_CREATEUSER2", NDR_SAMR_CREATEUSER2, api_samr_CreateUser2},
+ {"SAMR_QUERYDISPLAYINFO3", NDR_SAMR_QUERYDISPLAYINFO3, api_samr_QueryDisplayInfo3},
+ {"SAMR_ADDMULTIPLEMEMBERSTOALIAS", NDR_SAMR_ADDMULTIPLEMEMBERSTOALIAS, api_samr_AddMultipleMembersToAlias},
+ {"SAMR_REMOVEMULTIPLEMEMBERSFROMALIAS", NDR_SAMR_REMOVEMULTIPLEMEMBERSFROMALIAS, api_samr_RemoveMultipleMembersFromAlias},
+ {"SAMR_OEMCHANGEPASSWORDUSER2", NDR_SAMR_OEMCHANGEPASSWORDUSER2, api_samr_OemChangePasswordUser2},
+ {"SAMR_CHANGEPASSWORDUSER2", NDR_SAMR_CHANGEPASSWORDUSER2, api_samr_ChangePasswordUser2},
+ {"SAMR_GETDOMPWINFO", NDR_SAMR_GETDOMPWINFO, api_samr_GetDomPwInfo},
+ {"SAMR_CONNECT2", NDR_SAMR_CONNECT2, api_samr_Connect2},
+ {"SAMR_SETUSERINFO2", NDR_SAMR_SETUSERINFO2, api_samr_SetUserInfo2},
+ {"SAMR_SETBOOTKEYINFORMATION", NDR_SAMR_SETBOOTKEYINFORMATION, api_samr_SetBootKeyInformation},
+ {"SAMR_GETBOOTKEYINFORMATION", NDR_SAMR_GETBOOTKEYINFORMATION, api_samr_GetBootKeyInformation},
+ {"SAMR_CONNECT3", NDR_SAMR_CONNECT3, api_samr_Connect3},
+ {"SAMR_CONNECT4", NDR_SAMR_CONNECT4, api_samr_Connect4},
+ {"SAMR_CHANGEPASSWORDUSER3", NDR_SAMR_CHANGEPASSWORDUSER3, api_samr_ChangePasswordUser3},
+ {"SAMR_CONNECT5", NDR_SAMR_CONNECT5, api_samr_Connect5},
+ {"SAMR_RIDTOSID", NDR_SAMR_RIDTOSID, api_samr_RidToSid},
+ {"SAMR_SETDSRMPASSWORD", NDR_SAMR_SETDSRMPASSWORD, api_samr_SetDsrmPassword},
+ {"SAMR_VALIDATEPASSWORD", NDR_SAMR_VALIDATEPASSWORD, api_samr_ValidatePassword},
+};
+
+void samr_get_pipe_fns(struct api_struct **fns, int *n_fns)
+{
+ *fns = api_samr_cmds;
+ *n_fns = sizeof(api_samr_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_samr_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "samr", "samr", &ndr_table_samr.syntax_id, api_samr_cmds, sizeof(api_samr_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/librpc/gen_ndr/srv_samr.h b/source3/librpc/gen_ndr/srv_samr.h
new file mode 100644
index 0000000000..7d5cdd745d
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_samr.h
@@ -0,0 +1,74 @@
+#include "librpc/gen_ndr/ndr_samr.h"
+#ifndef __SRV_SAMR__
+#define __SRV_SAMR__
+NTSTATUS _samr_Connect(pipes_struct *p, struct samr_Connect *r);
+NTSTATUS _samr_Close(pipes_struct *p, struct samr_Close *r);
+NTSTATUS _samr_SetSecurity(pipes_struct *p, struct samr_SetSecurity *r);
+NTSTATUS _samr_QuerySecurity(pipes_struct *p, struct samr_QuerySecurity *r);
+NTSTATUS _samr_Shutdown(pipes_struct *p, struct samr_Shutdown *r);
+NTSTATUS _samr_LookupDomain(pipes_struct *p, struct samr_LookupDomain *r);
+NTSTATUS _samr_EnumDomains(pipes_struct *p, struct samr_EnumDomains *r);
+NTSTATUS _samr_OpenDomain(pipes_struct *p, struct samr_OpenDomain *r);
+NTSTATUS _samr_QueryDomainInfo(pipes_struct *p, struct samr_QueryDomainInfo *r);
+NTSTATUS _samr_SetDomainInfo(pipes_struct *p, struct samr_SetDomainInfo *r);
+NTSTATUS _samr_CreateDomainGroup(pipes_struct *p, struct samr_CreateDomainGroup *r);
+NTSTATUS _samr_EnumDomainGroups(pipes_struct *p, struct samr_EnumDomainGroups *r);
+NTSTATUS _samr_CreateUser(pipes_struct *p, struct samr_CreateUser *r);
+NTSTATUS _samr_EnumDomainUsers(pipes_struct *p, struct samr_EnumDomainUsers *r);
+NTSTATUS _samr_CreateDomAlias(pipes_struct *p, struct samr_CreateDomAlias *r);
+NTSTATUS _samr_EnumDomainAliases(pipes_struct *p, struct samr_EnumDomainAliases *r);
+NTSTATUS _samr_GetAliasMembership(pipes_struct *p, struct samr_GetAliasMembership *r);
+NTSTATUS _samr_LookupNames(pipes_struct *p, struct samr_LookupNames *r);
+NTSTATUS _samr_LookupRids(pipes_struct *p, struct samr_LookupRids *r);
+NTSTATUS _samr_OpenGroup(pipes_struct *p, struct samr_OpenGroup *r);
+NTSTATUS _samr_QueryGroupInfo(pipes_struct *p, struct samr_QueryGroupInfo *r);
+NTSTATUS _samr_SetGroupInfo(pipes_struct *p, struct samr_SetGroupInfo *r);
+NTSTATUS _samr_AddGroupMember(pipes_struct *p, struct samr_AddGroupMember *r);
+NTSTATUS _samr_DeleteDomainGroup(pipes_struct *p, struct samr_DeleteDomainGroup *r);
+NTSTATUS _samr_DeleteGroupMember(pipes_struct *p, struct samr_DeleteGroupMember *r);
+NTSTATUS _samr_QueryGroupMember(pipes_struct *p, struct samr_QueryGroupMember *r);
+NTSTATUS _samr_SetMemberAttributesOfGroup(pipes_struct *p, struct samr_SetMemberAttributesOfGroup *r);
+NTSTATUS _samr_OpenAlias(pipes_struct *p, struct samr_OpenAlias *r);
+NTSTATUS _samr_QueryAliasInfo(pipes_struct *p, struct samr_QueryAliasInfo *r);
+NTSTATUS _samr_SetAliasInfo(pipes_struct *p, struct samr_SetAliasInfo *r);
+NTSTATUS _samr_DeleteDomAlias(pipes_struct *p, struct samr_DeleteDomAlias *r);
+NTSTATUS _samr_AddAliasMember(pipes_struct *p, struct samr_AddAliasMember *r);
+NTSTATUS _samr_DeleteAliasMember(pipes_struct *p, struct samr_DeleteAliasMember *r);
+NTSTATUS _samr_GetMembersInAlias(pipes_struct *p, struct samr_GetMembersInAlias *r);
+NTSTATUS _samr_OpenUser(pipes_struct *p, struct samr_OpenUser *r);
+NTSTATUS _samr_DeleteUser(pipes_struct *p, struct samr_DeleteUser *r);
+NTSTATUS _samr_QueryUserInfo(pipes_struct *p, struct samr_QueryUserInfo *r);
+NTSTATUS _samr_SetUserInfo(pipes_struct *p, struct samr_SetUserInfo *r);
+NTSTATUS _samr_ChangePasswordUser(pipes_struct *p, struct samr_ChangePasswordUser *r);
+NTSTATUS _samr_GetGroupsForUser(pipes_struct *p, struct samr_GetGroupsForUser *r);
+NTSTATUS _samr_QueryDisplayInfo(pipes_struct *p, struct samr_QueryDisplayInfo *r);
+NTSTATUS _samr_GetDisplayEnumerationIndex(pipes_struct *p, struct samr_GetDisplayEnumerationIndex *r);
+NTSTATUS _samr_TestPrivateFunctionsDomain(pipes_struct *p, struct samr_TestPrivateFunctionsDomain *r);
+NTSTATUS _samr_TestPrivateFunctionsUser(pipes_struct *p, struct samr_TestPrivateFunctionsUser *r);
+NTSTATUS _samr_GetUserPwInfo(pipes_struct *p, struct samr_GetUserPwInfo *r);
+NTSTATUS _samr_RemoveMemberFromForeignDomain(pipes_struct *p, struct samr_RemoveMemberFromForeignDomain *r);
+NTSTATUS _samr_QueryDomainInfo2(pipes_struct *p, struct samr_QueryDomainInfo2 *r);
+NTSTATUS _samr_QueryUserInfo2(pipes_struct *p, struct samr_QueryUserInfo2 *r);
+NTSTATUS _samr_QueryDisplayInfo2(pipes_struct *p, struct samr_QueryDisplayInfo2 *r);
+NTSTATUS _samr_GetDisplayEnumerationIndex2(pipes_struct *p, struct samr_GetDisplayEnumerationIndex2 *r);
+NTSTATUS _samr_CreateUser2(pipes_struct *p, struct samr_CreateUser2 *r);
+NTSTATUS _samr_QueryDisplayInfo3(pipes_struct *p, struct samr_QueryDisplayInfo3 *r);
+NTSTATUS _samr_AddMultipleMembersToAlias(pipes_struct *p, struct samr_AddMultipleMembersToAlias *r);
+NTSTATUS _samr_RemoveMultipleMembersFromAlias(pipes_struct *p, struct samr_RemoveMultipleMembersFromAlias *r);
+NTSTATUS _samr_OemChangePasswordUser2(pipes_struct *p, struct samr_OemChangePasswordUser2 *r);
+NTSTATUS _samr_ChangePasswordUser2(pipes_struct *p, struct samr_ChangePasswordUser2 *r);
+NTSTATUS _samr_GetDomPwInfo(pipes_struct *p, struct samr_GetDomPwInfo *r);
+NTSTATUS _samr_Connect2(pipes_struct *p, struct samr_Connect2 *r);
+NTSTATUS _samr_SetUserInfo2(pipes_struct *p, struct samr_SetUserInfo2 *r);
+NTSTATUS _samr_SetBootKeyInformation(pipes_struct *p, struct samr_SetBootKeyInformation *r);
+NTSTATUS _samr_GetBootKeyInformation(pipes_struct *p, struct samr_GetBootKeyInformation *r);
+NTSTATUS _samr_Connect3(pipes_struct *p, struct samr_Connect3 *r);
+NTSTATUS _samr_Connect4(pipes_struct *p, struct samr_Connect4 *r);
+NTSTATUS _samr_ChangePasswordUser3(pipes_struct *p, struct samr_ChangePasswordUser3 *r);
+NTSTATUS _samr_Connect5(pipes_struct *p, struct samr_Connect5 *r);
+NTSTATUS _samr_RidToSid(pipes_struct *p, struct samr_RidToSid *r);
+NTSTATUS _samr_SetDsrmPassword(pipes_struct *p, struct samr_SetDsrmPassword *r);
+NTSTATUS _samr_ValidatePassword(pipes_struct *p, struct samr_ValidatePassword *r);
+void samr_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_samr_init(void);
+#endif /* __SRV_SAMR__ */
diff --git a/source3/librpc/gen_ndr/srv_srvsvc.c b/source3/librpc/gen_ndr/srv_srvsvc.c
new file mode 100644
index 0000000000..66faaaaf7e
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_srvsvc.c
@@ -0,0 +1,4199 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * server auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/srv_srvsvc.h"
+
+static bool api_srvsvc_NetCharDevEnum(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetCharDevEnum *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETCHARDEVENUM];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetCharDevEnum);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetCharDevEnum, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.level = r->in.level;
+ r->out.ctr = r->in.ctr;
+ r->out.totalentries = talloc_zero(r, uint32_t);
+ if (r->out.totalentries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.result = _srvsvc_NetCharDevEnum(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetCharDevEnum, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetCharDevGetInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetCharDevGetInfo *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETCHARDEVGETINFO];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetCharDevGetInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetCharDevGetInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union srvsvc_NetCharDevInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _srvsvc_NetCharDevGetInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetCharDevGetInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetCharDevControl(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetCharDevControl *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETCHARDEVCONTROL];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetCharDevControl);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetCharDevControl, r);
+ }
+
+ r->out.result = _srvsvc_NetCharDevControl(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetCharDevControl, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetCharDevQEnum(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetCharDevQEnum *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETCHARDEVQENUM];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetCharDevQEnum);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetCharDevQEnum, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.level = r->in.level;
+ r->out.ctr = r->in.ctr;
+ r->out.totalentries = talloc_zero(r, uint32_t);
+ if (r->out.totalentries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.result = _srvsvc_NetCharDevQEnum(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetCharDevQEnum, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetCharDevQGetInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetCharDevQGetInfo *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETCHARDEVQGETINFO];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetCharDevQGetInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetCharDevQGetInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union srvsvc_NetCharDevQInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _srvsvc_NetCharDevQGetInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetCharDevQGetInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetCharDevQSetInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetCharDevQSetInfo *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETCHARDEVQSETINFO];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetCharDevQSetInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetCharDevQSetInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.parm_error = r->in.parm_error;
+ r->out.result = _srvsvc_NetCharDevQSetInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetCharDevQSetInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetCharDevQPurge(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetCharDevQPurge *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETCHARDEVQPURGE];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetCharDevQPurge);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetCharDevQPurge, r);
+ }
+
+ r->out.result = _srvsvc_NetCharDevQPurge(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetCharDevQPurge, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetCharDevQPurgeSelf(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetCharDevQPurgeSelf *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETCHARDEVQPURGESELF];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetCharDevQPurgeSelf);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetCharDevQPurgeSelf, r);
+ }
+
+ r->out.result = _srvsvc_NetCharDevQPurgeSelf(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetCharDevQPurgeSelf, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetConnEnum(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetConnEnum *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETCONNENUM];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetConnEnum);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetConnEnum, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info_ctr = r->in.info_ctr;
+ r->out.totalentries = talloc_zero(r, uint32_t);
+ if (r->out.totalentries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.result = _srvsvc_NetConnEnum(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetConnEnum, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetFileEnum(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetFileEnum *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETFILEENUM];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetFileEnum);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetFileEnum, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info_ctr = r->in.info_ctr;
+ r->out.totalentries = talloc_zero(r, uint32_t);
+ if (r->out.totalentries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.result = _srvsvc_NetFileEnum(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetFileEnum, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetFileGetInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetFileGetInfo *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETFILEGETINFO];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetFileGetInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetFileGetInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union srvsvc_NetFileInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _srvsvc_NetFileGetInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetFileGetInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetFileClose(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetFileClose *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETFILECLOSE];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetFileClose);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetFileClose, r);
+ }
+
+ r->out.result = _srvsvc_NetFileClose(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetFileClose, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetSessEnum(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetSessEnum *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSESSENUM];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetSessEnum);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetSessEnum, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info_ctr = r->in.info_ctr;
+ r->out.totalentries = talloc_zero(r, uint32_t);
+ if (r->out.totalentries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.result = _srvsvc_NetSessEnum(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetSessEnum, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetSessDel(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetSessDel *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSESSDEL];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetSessDel);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetSessDel, r);
+ }
+
+ r->out.result = _srvsvc_NetSessDel(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetSessDel, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetShareAdd(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetShareAdd *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSHAREADD];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetShareAdd);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareAdd, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.parm_error = r->in.parm_error;
+ r->out.result = _srvsvc_NetShareAdd(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareAdd, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetShareEnumAll(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetShareEnumAll *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSHAREENUMALL];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetShareEnumAll);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareEnumAll, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info_ctr = r->in.info_ctr;
+ r->out.totalentries = talloc_zero(r, uint32_t);
+ if (r->out.totalentries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.result = _srvsvc_NetShareEnumAll(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareEnumAll, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetShareGetInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetShareGetInfo *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSHAREGETINFO];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetShareGetInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareGetInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union srvsvc_NetShareInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _srvsvc_NetShareGetInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareGetInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetShareSetInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetShareSetInfo *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSHARESETINFO];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetShareSetInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareSetInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.parm_error = r->in.parm_error;
+ r->out.result = _srvsvc_NetShareSetInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareSetInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetShareDel(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetShareDel *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSHAREDEL];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetShareDel);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareDel, r);
+ }
+
+ r->out.result = _srvsvc_NetShareDel(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareDel, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetShareDelSticky(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetShareDelSticky *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSHAREDELSTICKY];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetShareDelSticky);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareDelSticky, r);
+ }
+
+ r->out.result = _srvsvc_NetShareDelSticky(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareDelSticky, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetShareCheck(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetShareCheck *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSHARECHECK];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetShareCheck);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareCheck, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.type = talloc_zero(r, enum srvsvc_ShareType);
+ if (r->out.type == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _srvsvc_NetShareCheck(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareCheck, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetSrvGetInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetSrvGetInfo *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSRVGETINFO];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetSrvGetInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetSrvGetInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union srvsvc_NetSrvInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _srvsvc_NetSrvGetInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetSrvGetInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetSrvSetInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetSrvSetInfo *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSRVSETINFO];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetSrvSetInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetSrvSetInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.parm_error = r->in.parm_error;
+ r->out.result = _srvsvc_NetSrvSetInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetSrvSetInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetDiskEnum(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetDiskEnum *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETDISKENUM];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetDiskEnum);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetDiskEnum, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = r->in.info;
+ r->out.totalentries = talloc_zero(r, uint32_t);
+ if (r->out.totalentries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.result = _srvsvc_NetDiskEnum(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetDiskEnum, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetServerStatisticsGet(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetServerStatisticsGet *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSERVERSTATISTICSGET];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetServerStatisticsGet);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetServerStatisticsGet, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.stats = talloc_zero(r, struct srvsvc_Statistics);
+ if (r->out.stats == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _srvsvc_NetServerStatisticsGet(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetServerStatisticsGet, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetTransportAdd(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetTransportAdd *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETTRANSPORTADD];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetTransportAdd);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetTransportAdd, r);
+ }
+
+ r->out.result = _srvsvc_NetTransportAdd(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetTransportAdd, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetTransportEnum(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetTransportEnum *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETTRANSPORTENUM];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetTransportEnum);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetTransportEnum, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.level = r->in.level;
+ r->out.transports = r->in.transports;
+ r->out.totalentries = talloc_zero(r, uint32_t);
+ if (r->out.totalentries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.result = _srvsvc_NetTransportEnum(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetTransportEnum, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetTransportDel(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetTransportDel *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETTRANSPORTDEL];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetTransportDel);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetTransportDel, r);
+ }
+
+ r->out.result = _srvsvc_NetTransportDel(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetTransportDel, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetRemoteTOD(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetRemoteTOD *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETREMOTETOD];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetRemoteTOD);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetRemoteTOD, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, struct srvsvc_NetRemoteTODInfo *);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _srvsvc_NetRemoteTOD(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetRemoteTOD, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetSetServiceBits(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetSetServiceBits *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSETSERVICEBITS];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetSetServiceBits);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetSetServiceBits, r);
+ }
+
+ r->out.result = _srvsvc_NetSetServiceBits(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetSetServiceBits, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetPathType(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetPathType *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETPATHTYPE];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetPathType);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetPathType, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.pathtype = talloc_zero(r, uint32_t);
+ if (r->out.pathtype == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _srvsvc_NetPathType(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetPathType, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetPathCanonicalize(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetPathCanonicalize *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETPATHCANONICALIZE];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetPathCanonicalize);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetPathCanonicalize, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.can_path = talloc_zero_array(r, uint8_t, r->in.maxbuf);
+ if (r->out.can_path == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.pathtype = r->in.pathtype;
+ r->out.result = _srvsvc_NetPathCanonicalize(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetPathCanonicalize, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetPathCompare(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetPathCompare *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETPATHCOMPARE];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetPathCompare);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetPathCompare, r);
+ }
+
+ r->out.result = _srvsvc_NetPathCompare(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetPathCompare, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetNameValidate(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetNameValidate *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETNAMEVALIDATE];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetNameValidate);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetNameValidate, r);
+ }
+
+ r->out.result = _srvsvc_NetNameValidate(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetNameValidate, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NETRPRNAMECANONICALIZE(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NETRPRNAMECANONICALIZE *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETRPRNAMECANONICALIZE];
+
+ r = talloc(talloc_tos(), struct srvsvc_NETRPRNAMECANONICALIZE);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRPRNAMECANONICALIZE, r);
+ }
+
+ r->out.result = _srvsvc_NETRPRNAMECANONICALIZE(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRPRNAMECANONICALIZE, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetPRNameCompare(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetPRNameCompare *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETPRNAMECOMPARE];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetPRNameCompare);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetPRNameCompare, r);
+ }
+
+ r->out.result = _srvsvc_NetPRNameCompare(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetPRNameCompare, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetShareEnum(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetShareEnum *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSHAREENUM];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetShareEnum);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareEnum, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info_ctr = r->in.info_ctr;
+ r->out.totalentries = talloc_zero(r, uint32_t);
+ if (r->out.totalentries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.result = _srvsvc_NetShareEnum(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareEnum, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetShareDelStart(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetShareDelStart *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSHAREDELSTART];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetShareDelStart);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareDelStart, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.hnd = talloc_zero(r, struct policy_handle);
+ if (r->out.hnd == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _srvsvc_NetShareDelStart(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareDelStart, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetShareDelCommit(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetShareDelCommit *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSHAREDELCOMMIT];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetShareDelCommit);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetShareDelCommit, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.hnd = r->in.hnd;
+ r->out.result = _srvsvc_NetShareDelCommit(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetShareDelCommit, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetGetFileSecurity(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetGetFileSecurity *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETGETFILESECURITY];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetGetFileSecurity);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetGetFileSecurity, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.sd_buf = talloc_zero(r, struct sec_desc_buf *);
+ if (r->out.sd_buf == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _srvsvc_NetGetFileSecurity(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetGetFileSecurity, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetSetFileSecurity(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetSetFileSecurity *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSETFILESECURITY];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetSetFileSecurity);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetSetFileSecurity, r);
+ }
+
+ r->out.result = _srvsvc_NetSetFileSecurity(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetSetFileSecurity, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetServerTransportAddEx(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetServerTransportAddEx *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSERVERTRANSPORTADDEX];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetServerTransportAddEx);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetServerTransportAddEx, r);
+ }
+
+ r->out.result = _srvsvc_NetServerTransportAddEx(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetServerTransportAddEx, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NetServerSetServiceBitsEx(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NetServerSetServiceBitsEx *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETSERVERSETSERVICEBITSEX];
+
+ r = talloc(talloc_tos(), struct srvsvc_NetServerSetServiceBitsEx);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NetServerSetServiceBitsEx, r);
+ }
+
+ r->out.result = _srvsvc_NetServerSetServiceBitsEx(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NetServerSetServiceBitsEx, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NETRDFSGETVERSION(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NETRDFSGETVERSION *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETRDFSGETVERSION];
+
+ r = talloc(talloc_tos(), struct srvsvc_NETRDFSGETVERSION);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSGETVERSION, r);
+ }
+
+ r->out.result = _srvsvc_NETRDFSGETVERSION(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSGETVERSION, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NETRDFSCREATELOCALPARTITION(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NETRDFSCREATELOCALPARTITION *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETRDFSCREATELOCALPARTITION];
+
+ r = talloc(talloc_tos(), struct srvsvc_NETRDFSCREATELOCALPARTITION);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSCREATELOCALPARTITION, r);
+ }
+
+ r->out.result = _srvsvc_NETRDFSCREATELOCALPARTITION(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSCREATELOCALPARTITION, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NETRDFSDELETELOCALPARTITION(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NETRDFSDELETELOCALPARTITION *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETRDFSDELETELOCALPARTITION];
+
+ r = talloc(talloc_tos(), struct srvsvc_NETRDFSDELETELOCALPARTITION);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSDELETELOCALPARTITION, r);
+ }
+
+ r->out.result = _srvsvc_NETRDFSDELETELOCALPARTITION(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSDELETELOCALPARTITION, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NETRDFSSETLOCALVOLUMESTATE(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NETRDFSSETLOCALVOLUMESTATE *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETRDFSSETLOCALVOLUMESTATE];
+
+ r = talloc(talloc_tos(), struct srvsvc_NETRDFSSETLOCALVOLUMESTATE);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSSETLOCALVOLUMESTATE, r);
+ }
+
+ r->out.result = _srvsvc_NETRDFSSETLOCALVOLUMESTATE(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSSETLOCALVOLUMESTATE, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NETRDFSSETSERVERINFO(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NETRDFSSETSERVERINFO *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETRDFSSETSERVERINFO];
+
+ r = talloc(talloc_tos(), struct srvsvc_NETRDFSSETSERVERINFO);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSSETSERVERINFO, r);
+ }
+
+ r->out.result = _srvsvc_NETRDFSSETSERVERINFO(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSSETSERVERINFO, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NETRDFSCREATEEXITPOINT(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NETRDFSCREATEEXITPOINT *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETRDFSCREATEEXITPOINT];
+
+ r = talloc(talloc_tos(), struct srvsvc_NETRDFSCREATEEXITPOINT);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSCREATEEXITPOINT, r);
+ }
+
+ r->out.result = _srvsvc_NETRDFSCREATEEXITPOINT(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSCREATEEXITPOINT, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NETRDFSDELETEEXITPOINT(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NETRDFSDELETEEXITPOINT *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETRDFSDELETEEXITPOINT];
+
+ r = talloc(talloc_tos(), struct srvsvc_NETRDFSDELETEEXITPOINT);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSDELETEEXITPOINT, r);
+ }
+
+ r->out.result = _srvsvc_NETRDFSDELETEEXITPOINT(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSDELETEEXITPOINT, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NETRDFSMODIFYPREFIX(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NETRDFSMODIFYPREFIX *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETRDFSMODIFYPREFIX];
+
+ r = talloc(talloc_tos(), struct srvsvc_NETRDFSMODIFYPREFIX);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSMODIFYPREFIX, r);
+ }
+
+ r->out.result = _srvsvc_NETRDFSMODIFYPREFIX(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSMODIFYPREFIX, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NETRDFSFIXLOCALVOLUME(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NETRDFSFIXLOCALVOLUME *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETRDFSFIXLOCALVOLUME];
+
+ r = talloc(talloc_tos(), struct srvsvc_NETRDFSFIXLOCALVOLUME);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSFIXLOCALVOLUME, r);
+ }
+
+ r->out.result = _srvsvc_NETRDFSFIXLOCALVOLUME(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSFIXLOCALVOLUME, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NETRDFSMANAGERREPORTSITEINFO(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NETRDFSMANAGERREPORTSITEINFO *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETRDFSMANAGERREPORTSITEINFO];
+
+ r = talloc(talloc_tos(), struct srvsvc_NETRDFSMANAGERREPORTSITEINFO);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRDFSMANAGERREPORTSITEINFO, r);
+ }
+
+ r->out.result = _srvsvc_NETRDFSMANAGERREPORTSITEINFO(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRDFSMANAGERREPORTSITEINFO, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_srvsvc_NETRSERVERTRANSPORTDELEX(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct srvsvc_NETRSERVERTRANSPORTDELEX *r;
+
+ call = &ndr_table_srvsvc.calls[NDR_SRVSVC_NETRSERVERTRANSPORTDELEX];
+
+ r = talloc(talloc_tos(), struct srvsvc_NETRSERVERTRANSPORTDELEX);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(srvsvc_NETRSERVERTRANSPORTDELEX, r);
+ }
+
+ r->out.result = _srvsvc_NETRSERVERTRANSPORTDELEX(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(srvsvc_NETRSERVERTRANSPORTDELEX, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+
+/* Tables */
+static struct api_struct api_srvsvc_cmds[] =
+{
+ {"SRVSVC_NETCHARDEVENUM", NDR_SRVSVC_NETCHARDEVENUM, api_srvsvc_NetCharDevEnum},
+ {"SRVSVC_NETCHARDEVGETINFO", NDR_SRVSVC_NETCHARDEVGETINFO, api_srvsvc_NetCharDevGetInfo},
+ {"SRVSVC_NETCHARDEVCONTROL", NDR_SRVSVC_NETCHARDEVCONTROL, api_srvsvc_NetCharDevControl},
+ {"SRVSVC_NETCHARDEVQENUM", NDR_SRVSVC_NETCHARDEVQENUM, api_srvsvc_NetCharDevQEnum},
+ {"SRVSVC_NETCHARDEVQGETINFO", NDR_SRVSVC_NETCHARDEVQGETINFO, api_srvsvc_NetCharDevQGetInfo},
+ {"SRVSVC_NETCHARDEVQSETINFO", NDR_SRVSVC_NETCHARDEVQSETINFO, api_srvsvc_NetCharDevQSetInfo},
+ {"SRVSVC_NETCHARDEVQPURGE", NDR_SRVSVC_NETCHARDEVQPURGE, api_srvsvc_NetCharDevQPurge},
+ {"SRVSVC_NETCHARDEVQPURGESELF", NDR_SRVSVC_NETCHARDEVQPURGESELF, api_srvsvc_NetCharDevQPurgeSelf},
+ {"SRVSVC_NETCONNENUM", NDR_SRVSVC_NETCONNENUM, api_srvsvc_NetConnEnum},
+ {"SRVSVC_NETFILEENUM", NDR_SRVSVC_NETFILEENUM, api_srvsvc_NetFileEnum},
+ {"SRVSVC_NETFILEGETINFO", NDR_SRVSVC_NETFILEGETINFO, api_srvsvc_NetFileGetInfo},
+ {"SRVSVC_NETFILECLOSE", NDR_SRVSVC_NETFILECLOSE, api_srvsvc_NetFileClose},
+ {"SRVSVC_NETSESSENUM", NDR_SRVSVC_NETSESSENUM, api_srvsvc_NetSessEnum},
+ {"SRVSVC_NETSESSDEL", NDR_SRVSVC_NETSESSDEL, api_srvsvc_NetSessDel},
+ {"SRVSVC_NETSHAREADD", NDR_SRVSVC_NETSHAREADD, api_srvsvc_NetShareAdd},
+ {"SRVSVC_NETSHAREENUMALL", NDR_SRVSVC_NETSHAREENUMALL, api_srvsvc_NetShareEnumAll},
+ {"SRVSVC_NETSHAREGETINFO", NDR_SRVSVC_NETSHAREGETINFO, api_srvsvc_NetShareGetInfo},
+ {"SRVSVC_NETSHARESETINFO", NDR_SRVSVC_NETSHARESETINFO, api_srvsvc_NetShareSetInfo},
+ {"SRVSVC_NETSHAREDEL", NDR_SRVSVC_NETSHAREDEL, api_srvsvc_NetShareDel},
+ {"SRVSVC_NETSHAREDELSTICKY", NDR_SRVSVC_NETSHAREDELSTICKY, api_srvsvc_NetShareDelSticky},
+ {"SRVSVC_NETSHARECHECK", NDR_SRVSVC_NETSHARECHECK, api_srvsvc_NetShareCheck},
+ {"SRVSVC_NETSRVGETINFO", NDR_SRVSVC_NETSRVGETINFO, api_srvsvc_NetSrvGetInfo},
+ {"SRVSVC_NETSRVSETINFO", NDR_SRVSVC_NETSRVSETINFO, api_srvsvc_NetSrvSetInfo},
+ {"SRVSVC_NETDISKENUM", NDR_SRVSVC_NETDISKENUM, api_srvsvc_NetDiskEnum},
+ {"SRVSVC_NETSERVERSTATISTICSGET", NDR_SRVSVC_NETSERVERSTATISTICSGET, api_srvsvc_NetServerStatisticsGet},
+ {"SRVSVC_NETTRANSPORTADD", NDR_SRVSVC_NETTRANSPORTADD, api_srvsvc_NetTransportAdd},
+ {"SRVSVC_NETTRANSPORTENUM", NDR_SRVSVC_NETTRANSPORTENUM, api_srvsvc_NetTransportEnum},
+ {"SRVSVC_NETTRANSPORTDEL", NDR_SRVSVC_NETTRANSPORTDEL, api_srvsvc_NetTransportDel},
+ {"SRVSVC_NETREMOTETOD", NDR_SRVSVC_NETREMOTETOD, api_srvsvc_NetRemoteTOD},
+ {"SRVSVC_NETSETSERVICEBITS", NDR_SRVSVC_NETSETSERVICEBITS, api_srvsvc_NetSetServiceBits},
+ {"SRVSVC_NETPATHTYPE", NDR_SRVSVC_NETPATHTYPE, api_srvsvc_NetPathType},
+ {"SRVSVC_NETPATHCANONICALIZE", NDR_SRVSVC_NETPATHCANONICALIZE, api_srvsvc_NetPathCanonicalize},
+ {"SRVSVC_NETPATHCOMPARE", NDR_SRVSVC_NETPATHCOMPARE, api_srvsvc_NetPathCompare},
+ {"SRVSVC_NETNAMEVALIDATE", NDR_SRVSVC_NETNAMEVALIDATE, api_srvsvc_NetNameValidate},
+ {"SRVSVC_NETRPRNAMECANONICALIZE", NDR_SRVSVC_NETRPRNAMECANONICALIZE, api_srvsvc_NETRPRNAMECANONICALIZE},
+ {"SRVSVC_NETPRNAMECOMPARE", NDR_SRVSVC_NETPRNAMECOMPARE, api_srvsvc_NetPRNameCompare},
+ {"SRVSVC_NETSHAREENUM", NDR_SRVSVC_NETSHAREENUM, api_srvsvc_NetShareEnum},
+ {"SRVSVC_NETSHAREDELSTART", NDR_SRVSVC_NETSHAREDELSTART, api_srvsvc_NetShareDelStart},
+ {"SRVSVC_NETSHAREDELCOMMIT", NDR_SRVSVC_NETSHAREDELCOMMIT, api_srvsvc_NetShareDelCommit},
+ {"SRVSVC_NETGETFILESECURITY", NDR_SRVSVC_NETGETFILESECURITY, api_srvsvc_NetGetFileSecurity},
+ {"SRVSVC_NETSETFILESECURITY", NDR_SRVSVC_NETSETFILESECURITY, api_srvsvc_NetSetFileSecurity},
+ {"SRVSVC_NETSERVERTRANSPORTADDEX", NDR_SRVSVC_NETSERVERTRANSPORTADDEX, api_srvsvc_NetServerTransportAddEx},
+ {"SRVSVC_NETSERVERSETSERVICEBITSEX", NDR_SRVSVC_NETSERVERSETSERVICEBITSEX, api_srvsvc_NetServerSetServiceBitsEx},
+ {"SRVSVC_NETRDFSGETVERSION", NDR_SRVSVC_NETRDFSGETVERSION, api_srvsvc_NETRDFSGETVERSION},
+ {"SRVSVC_NETRDFSCREATELOCALPARTITION", NDR_SRVSVC_NETRDFSCREATELOCALPARTITION, api_srvsvc_NETRDFSCREATELOCALPARTITION},
+ {"SRVSVC_NETRDFSDELETELOCALPARTITION", NDR_SRVSVC_NETRDFSDELETELOCALPARTITION, api_srvsvc_NETRDFSDELETELOCALPARTITION},
+ {"SRVSVC_NETRDFSSETLOCALVOLUMESTATE", NDR_SRVSVC_NETRDFSSETLOCALVOLUMESTATE, api_srvsvc_NETRDFSSETLOCALVOLUMESTATE},
+ {"SRVSVC_NETRDFSSETSERVERINFO", NDR_SRVSVC_NETRDFSSETSERVERINFO, api_srvsvc_NETRDFSSETSERVERINFO},
+ {"SRVSVC_NETRDFSCREATEEXITPOINT", NDR_SRVSVC_NETRDFSCREATEEXITPOINT, api_srvsvc_NETRDFSCREATEEXITPOINT},
+ {"SRVSVC_NETRDFSDELETEEXITPOINT", NDR_SRVSVC_NETRDFSDELETEEXITPOINT, api_srvsvc_NETRDFSDELETEEXITPOINT},
+ {"SRVSVC_NETRDFSMODIFYPREFIX", NDR_SRVSVC_NETRDFSMODIFYPREFIX, api_srvsvc_NETRDFSMODIFYPREFIX},
+ {"SRVSVC_NETRDFSFIXLOCALVOLUME", NDR_SRVSVC_NETRDFSFIXLOCALVOLUME, api_srvsvc_NETRDFSFIXLOCALVOLUME},
+ {"SRVSVC_NETRDFSMANAGERREPORTSITEINFO", NDR_SRVSVC_NETRDFSMANAGERREPORTSITEINFO, api_srvsvc_NETRDFSMANAGERREPORTSITEINFO},
+ {"SRVSVC_NETRSERVERTRANSPORTDELEX", NDR_SRVSVC_NETRSERVERTRANSPORTDELEX, api_srvsvc_NETRSERVERTRANSPORTDELEX},
+};
+
+void srvsvc_get_pipe_fns(struct api_struct **fns, int *n_fns)
+{
+ *fns = api_srvsvc_cmds;
+ *n_fns = sizeof(api_srvsvc_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_srvsvc_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "srvsvc", "srvsvc", &ndr_table_srvsvc.syntax_id, api_srvsvc_cmds, sizeof(api_srvsvc_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/librpc/gen_ndr/srv_srvsvc.h b/source3/librpc/gen_ndr/srv_srvsvc.h
new file mode 100644
index 0000000000..1e1ebb1904
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_srvsvc.h
@@ -0,0 +1,60 @@
+#include "librpc/gen_ndr/ndr_srvsvc.h"
+#ifndef __SRV_SRVSVC__
+#define __SRV_SRVSVC__
+WERROR _srvsvc_NetCharDevEnum(pipes_struct *p, struct srvsvc_NetCharDevEnum *r);
+WERROR _srvsvc_NetCharDevGetInfo(pipes_struct *p, struct srvsvc_NetCharDevGetInfo *r);
+WERROR _srvsvc_NetCharDevControl(pipes_struct *p, struct srvsvc_NetCharDevControl *r);
+WERROR _srvsvc_NetCharDevQEnum(pipes_struct *p, struct srvsvc_NetCharDevQEnum *r);
+WERROR _srvsvc_NetCharDevQGetInfo(pipes_struct *p, struct srvsvc_NetCharDevQGetInfo *r);
+WERROR _srvsvc_NetCharDevQSetInfo(pipes_struct *p, struct srvsvc_NetCharDevQSetInfo *r);
+WERROR _srvsvc_NetCharDevQPurge(pipes_struct *p, struct srvsvc_NetCharDevQPurge *r);
+WERROR _srvsvc_NetCharDevQPurgeSelf(pipes_struct *p, struct srvsvc_NetCharDevQPurgeSelf *r);
+WERROR _srvsvc_NetConnEnum(pipes_struct *p, struct srvsvc_NetConnEnum *r);
+WERROR _srvsvc_NetFileEnum(pipes_struct *p, struct srvsvc_NetFileEnum *r);
+WERROR _srvsvc_NetFileGetInfo(pipes_struct *p, struct srvsvc_NetFileGetInfo *r);
+WERROR _srvsvc_NetFileClose(pipes_struct *p, struct srvsvc_NetFileClose *r);
+WERROR _srvsvc_NetSessEnum(pipes_struct *p, struct srvsvc_NetSessEnum *r);
+WERROR _srvsvc_NetSessDel(pipes_struct *p, struct srvsvc_NetSessDel *r);
+WERROR _srvsvc_NetShareAdd(pipes_struct *p, struct srvsvc_NetShareAdd *r);
+WERROR _srvsvc_NetShareEnumAll(pipes_struct *p, struct srvsvc_NetShareEnumAll *r);
+WERROR _srvsvc_NetShareGetInfo(pipes_struct *p, struct srvsvc_NetShareGetInfo *r);
+WERROR _srvsvc_NetShareSetInfo(pipes_struct *p, struct srvsvc_NetShareSetInfo *r);
+WERROR _srvsvc_NetShareDel(pipes_struct *p, struct srvsvc_NetShareDel *r);
+WERROR _srvsvc_NetShareDelSticky(pipes_struct *p, struct srvsvc_NetShareDelSticky *r);
+WERROR _srvsvc_NetShareCheck(pipes_struct *p, struct srvsvc_NetShareCheck *r);
+WERROR _srvsvc_NetSrvGetInfo(pipes_struct *p, struct srvsvc_NetSrvGetInfo *r);
+WERROR _srvsvc_NetSrvSetInfo(pipes_struct *p, struct srvsvc_NetSrvSetInfo *r);
+WERROR _srvsvc_NetDiskEnum(pipes_struct *p, struct srvsvc_NetDiskEnum *r);
+WERROR _srvsvc_NetServerStatisticsGet(pipes_struct *p, struct srvsvc_NetServerStatisticsGet *r);
+WERROR _srvsvc_NetTransportAdd(pipes_struct *p, struct srvsvc_NetTransportAdd *r);
+WERROR _srvsvc_NetTransportEnum(pipes_struct *p, struct srvsvc_NetTransportEnum *r);
+WERROR _srvsvc_NetTransportDel(pipes_struct *p, struct srvsvc_NetTransportDel *r);
+WERROR _srvsvc_NetRemoteTOD(pipes_struct *p, struct srvsvc_NetRemoteTOD *r);
+WERROR _srvsvc_NetSetServiceBits(pipes_struct *p, struct srvsvc_NetSetServiceBits *r);
+WERROR _srvsvc_NetPathType(pipes_struct *p, struct srvsvc_NetPathType *r);
+WERROR _srvsvc_NetPathCanonicalize(pipes_struct *p, struct srvsvc_NetPathCanonicalize *r);
+WERROR _srvsvc_NetPathCompare(pipes_struct *p, struct srvsvc_NetPathCompare *r);
+WERROR _srvsvc_NetNameValidate(pipes_struct *p, struct srvsvc_NetNameValidate *r);
+WERROR _srvsvc_NETRPRNAMECANONICALIZE(pipes_struct *p, struct srvsvc_NETRPRNAMECANONICALIZE *r);
+WERROR _srvsvc_NetPRNameCompare(pipes_struct *p, struct srvsvc_NetPRNameCompare *r);
+WERROR _srvsvc_NetShareEnum(pipes_struct *p, struct srvsvc_NetShareEnum *r);
+WERROR _srvsvc_NetShareDelStart(pipes_struct *p, struct srvsvc_NetShareDelStart *r);
+WERROR _srvsvc_NetShareDelCommit(pipes_struct *p, struct srvsvc_NetShareDelCommit *r);
+WERROR _srvsvc_NetGetFileSecurity(pipes_struct *p, struct srvsvc_NetGetFileSecurity *r);
+WERROR _srvsvc_NetSetFileSecurity(pipes_struct *p, struct srvsvc_NetSetFileSecurity *r);
+WERROR _srvsvc_NetServerTransportAddEx(pipes_struct *p, struct srvsvc_NetServerTransportAddEx *r);
+WERROR _srvsvc_NetServerSetServiceBitsEx(pipes_struct *p, struct srvsvc_NetServerSetServiceBitsEx *r);
+WERROR _srvsvc_NETRDFSGETVERSION(pipes_struct *p, struct srvsvc_NETRDFSGETVERSION *r);
+WERROR _srvsvc_NETRDFSCREATELOCALPARTITION(pipes_struct *p, struct srvsvc_NETRDFSCREATELOCALPARTITION *r);
+WERROR _srvsvc_NETRDFSDELETELOCALPARTITION(pipes_struct *p, struct srvsvc_NETRDFSDELETELOCALPARTITION *r);
+WERROR _srvsvc_NETRDFSSETLOCALVOLUMESTATE(pipes_struct *p, struct srvsvc_NETRDFSSETLOCALVOLUMESTATE *r);
+WERROR _srvsvc_NETRDFSSETSERVERINFO(pipes_struct *p, struct srvsvc_NETRDFSSETSERVERINFO *r);
+WERROR _srvsvc_NETRDFSCREATEEXITPOINT(pipes_struct *p, struct srvsvc_NETRDFSCREATEEXITPOINT *r);
+WERROR _srvsvc_NETRDFSDELETEEXITPOINT(pipes_struct *p, struct srvsvc_NETRDFSDELETEEXITPOINT *r);
+WERROR _srvsvc_NETRDFSMODIFYPREFIX(pipes_struct *p, struct srvsvc_NETRDFSMODIFYPREFIX *r);
+WERROR _srvsvc_NETRDFSFIXLOCALVOLUME(pipes_struct *p, struct srvsvc_NETRDFSFIXLOCALVOLUME *r);
+WERROR _srvsvc_NETRDFSMANAGERREPORTSITEINFO(pipes_struct *p, struct srvsvc_NETRDFSMANAGERREPORTSITEINFO *r);
+WERROR _srvsvc_NETRSERVERTRANSPORTDELEX(pipes_struct *p, struct srvsvc_NETRSERVERTRANSPORTDELEX *r);
+void srvsvc_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_srvsvc_init(void);
+#endif /* __SRV_SRVSVC__ */
diff --git a/source3/librpc/gen_ndr/srv_svcctl.c b/source3/librpc/gen_ndr/srv_svcctl.c
new file mode 100644
index 0000000000..32317ad8fe
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_svcctl.c
@@ -0,0 +1,3621 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * server auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/srv_svcctl.h"
+
+static bool api_svcctl_CloseServiceHandle(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_CloseServiceHandle *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_CLOSESERVICEHANDLE];
+
+ r = talloc(talloc_tos(), struct svcctl_CloseServiceHandle);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_CloseServiceHandle, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = r->in.handle;
+ r->out.result = _svcctl_CloseServiceHandle(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_CloseServiceHandle, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_ControlService(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_ControlService *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_CONTROLSERVICE];
+
+ r = talloc(talloc_tos(), struct svcctl_ControlService);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_ControlService, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.service_status = talloc_zero(r, struct SERVICE_STATUS);
+ if (r->out.service_status == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_ControlService(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_ControlService, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_DeleteService(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_DeleteService *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_DELETESERVICE];
+
+ r = talloc(talloc_tos(), struct svcctl_DeleteService);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_DeleteService, r);
+ }
+
+ r->out.result = _svcctl_DeleteService(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_DeleteService, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_LockServiceDatabase(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_LockServiceDatabase *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_LOCKSERVICEDATABASE];
+
+ r = talloc(talloc_tos(), struct svcctl_LockServiceDatabase);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_LockServiceDatabase, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.lock = talloc_zero(r, struct policy_handle);
+ if (r->out.lock == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_LockServiceDatabase(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_LockServiceDatabase, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_QueryServiceObjectSecurity(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_QueryServiceObjectSecurity *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_QUERYSERVICEOBJECTSECURITY];
+
+ r = talloc(talloc_tos(), struct svcctl_QueryServiceObjectSecurity);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceObjectSecurity, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.buffer = talloc_zero_array(r, uint8_t, r->in.buffer_size);
+ if (r->out.buffer == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.needed = talloc_zero(r, uint32_t);
+ if (r->out.needed == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_QueryServiceObjectSecurity(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceObjectSecurity, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_SetServiceObjectSecurity(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_SetServiceObjectSecurity *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_SETSERVICEOBJECTSECURITY];
+
+ r = talloc(talloc_tos(), struct svcctl_SetServiceObjectSecurity);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_SetServiceObjectSecurity, r);
+ }
+
+ r->out.result = _svcctl_SetServiceObjectSecurity(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_SetServiceObjectSecurity, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_QueryServiceStatus(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_QueryServiceStatus *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_QUERYSERVICESTATUS];
+
+ r = talloc(talloc_tos(), struct svcctl_QueryServiceStatus);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceStatus, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.service_status = talloc_zero(r, struct SERVICE_STATUS);
+ if (r->out.service_status == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_QueryServiceStatus(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceStatus, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_SetServiceStatus(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_SetServiceStatus *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_SETSERVICESTATUS];
+
+ r = talloc(talloc_tos(), struct svcctl_SetServiceStatus);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_SetServiceStatus, r);
+ }
+
+ r->out.result = _svcctl_SetServiceStatus(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_SetServiceStatus, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_UnlockServiceDatabase(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_UnlockServiceDatabase *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_UNLOCKSERVICEDATABASE];
+
+ r = talloc(talloc_tos(), struct svcctl_UnlockServiceDatabase);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_UnlockServiceDatabase, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.lock = r->in.lock;
+ r->out.result = _svcctl_UnlockServiceDatabase(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_UnlockServiceDatabase, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_NotifyBootConfigStatus(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_NotifyBootConfigStatus *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_NOTIFYBOOTCONFIGSTATUS];
+
+ r = talloc(talloc_tos(), struct svcctl_NotifyBootConfigStatus);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_NotifyBootConfigStatus, r);
+ }
+
+ r->out.result = _svcctl_NotifyBootConfigStatus(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_NotifyBootConfigStatus, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_SCSetServiceBitsW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_SCSetServiceBitsW *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_SCSETSERVICEBITSW];
+
+ r = talloc(talloc_tos(), struct svcctl_SCSetServiceBitsW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_SCSetServiceBitsW, r);
+ }
+
+ r->out.result = _svcctl_SCSetServiceBitsW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_SCSetServiceBitsW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_ChangeServiceConfigW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_ChangeServiceConfigW *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_CHANGESERVICECONFIGW];
+
+ r = talloc(talloc_tos(), struct svcctl_ChangeServiceConfigW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_ChangeServiceConfigW, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.tag_id = talloc_zero(r, uint32_t);
+ if (r->out.tag_id == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_ChangeServiceConfigW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_ChangeServiceConfigW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_CreateServiceW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_CreateServiceW *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_CREATESERVICEW];
+
+ r = talloc(talloc_tos(), struct svcctl_CreateServiceW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_CreateServiceW, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.TagId = r->in.TagId;
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_CreateServiceW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_CreateServiceW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_EnumDependentServicesW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_EnumDependentServicesW *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_ENUMDEPENDENTSERVICESW];
+
+ r = talloc(talloc_tos(), struct svcctl_EnumDependentServicesW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_EnumDependentServicesW, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.service_status = talloc_zero_array(r, uint8_t, r->in.buf_size);
+ if (r->out.service_status == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.bytes_needed = talloc_zero(r, uint32_t);
+ if (r->out.bytes_needed == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.services_returned = talloc_zero(r, uint32_t);
+ if (r->out.services_returned == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_EnumDependentServicesW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_EnumDependentServicesW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_EnumServicesStatusW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_EnumServicesStatusW *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_ENUMSERVICESSTATUSW];
+
+ r = talloc(talloc_tos(), struct svcctl_EnumServicesStatusW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_EnumServicesStatusW, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.service = talloc_zero_array(r, uint8_t, r->in.buf_size);
+ if (r->out.service == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.bytes_needed = talloc_zero(r, uint32_t);
+ if (r->out.bytes_needed == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.services_returned = talloc_zero(r, uint32_t);
+ if (r->out.services_returned == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.result = _svcctl_EnumServicesStatusW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_EnumServicesStatusW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_OpenSCManagerW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_OpenSCManagerW *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_OPENSCMANAGERW];
+
+ r = talloc(talloc_tos(), struct svcctl_OpenSCManagerW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_OpenSCManagerW, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_OpenSCManagerW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_OpenSCManagerW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_OpenServiceW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_OpenServiceW *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_OPENSERVICEW];
+
+ r = talloc(talloc_tos(), struct svcctl_OpenServiceW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_OpenServiceW, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_OpenServiceW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_OpenServiceW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_QueryServiceConfigW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_QueryServiceConfigW *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_QUERYSERVICECONFIGW];
+
+ r = talloc(talloc_tos(), struct svcctl_QueryServiceConfigW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceConfigW, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.query = talloc_zero_array(r, uint8_t, r->in.buf_size);
+ if (r->out.query == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.bytes_needed = talloc_zero(r, uint32_t);
+ if (r->out.bytes_needed == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_QueryServiceConfigW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceConfigW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_QueryServiceLockStatusW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_QueryServiceLockStatusW *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_QUERYSERVICELOCKSTATUSW];
+
+ r = talloc(talloc_tos(), struct svcctl_QueryServiceLockStatusW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceLockStatusW, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.lock_status = talloc_zero(r, struct SERVICE_LOCK_STATUS);
+ if (r->out.lock_status == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.required_buf_size = talloc_zero(r, uint32_t);
+ if (r->out.required_buf_size == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_QueryServiceLockStatusW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceLockStatusW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_StartServiceW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_StartServiceW *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_STARTSERVICEW];
+
+ r = talloc(talloc_tos(), struct svcctl_StartServiceW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_StartServiceW, r);
+ }
+
+ r->out.result = _svcctl_StartServiceW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_StartServiceW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_GetServiceDisplayNameW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_GetServiceDisplayNameW *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_GETSERVICEDISPLAYNAMEW];
+
+ r = talloc(talloc_tos(), struct svcctl_GetServiceDisplayNameW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_GetServiceDisplayNameW, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.display_name = talloc_zero(r, const char *);
+ if (r->out.display_name == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.display_name_length = r->in.display_name_length;
+ r->out.result = _svcctl_GetServiceDisplayNameW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_GetServiceDisplayNameW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_GetServiceKeyNameW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_GetServiceKeyNameW *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_GETSERVICEKEYNAMEW];
+
+ r = talloc(talloc_tos(), struct svcctl_GetServiceKeyNameW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_GetServiceKeyNameW, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.key_name = talloc_zero(r, const char *);
+ if (r->out.key_name == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.display_name_length = r->in.display_name_length;
+ r->out.result = _svcctl_GetServiceKeyNameW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_GetServiceKeyNameW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_SCSetServiceBitsA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_SCSetServiceBitsA *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_SCSETSERVICEBITSA];
+
+ r = talloc(talloc_tos(), struct svcctl_SCSetServiceBitsA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_SCSetServiceBitsA, r);
+ }
+
+ r->out.result = _svcctl_SCSetServiceBitsA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_SCSetServiceBitsA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_ChangeServiceConfigA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_ChangeServiceConfigA *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_CHANGESERVICECONFIGA];
+
+ r = talloc(talloc_tos(), struct svcctl_ChangeServiceConfigA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_ChangeServiceConfigA, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.tag_id = talloc_zero(r, uint32_t);
+ if (r->out.tag_id == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_ChangeServiceConfigA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_ChangeServiceConfigA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_CreateServiceA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_CreateServiceA *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_CREATESERVICEA];
+
+ r = talloc(talloc_tos(), struct svcctl_CreateServiceA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_CreateServiceA, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.TagId = talloc_zero(r, uint32_t);
+ if (r->out.TagId == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_CreateServiceA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_CreateServiceA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_EnumDependentServicesA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_EnumDependentServicesA *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_ENUMDEPENDENTSERVICESA];
+
+ r = talloc(talloc_tos(), struct svcctl_EnumDependentServicesA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_EnumDependentServicesA, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.service_status = talloc_zero(r, struct ENUM_SERVICE_STATUS);
+ if (r->out.service_status == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.bytes_needed = talloc_zero(r, uint32_t);
+ if (r->out.bytes_needed == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.services_returned = talloc_zero(r, uint32_t);
+ if (r->out.services_returned == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_EnumDependentServicesA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_EnumDependentServicesA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_EnumServicesStatusA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_EnumServicesStatusA *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_ENUMSERVICESSTATUSA];
+
+ r = talloc(talloc_tos(), struct svcctl_EnumServicesStatusA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_EnumServicesStatusA, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.service = talloc_zero_array(r, uint8_t, r->in.buf_size);
+ if (r->out.service == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.bytes_needed = talloc_zero(r, uint32_t);
+ if (r->out.bytes_needed == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.services_returned = talloc_zero(r, uint32_t);
+ if (r->out.services_returned == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.result = _svcctl_EnumServicesStatusA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_EnumServicesStatusA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_OpenSCManagerA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_OpenSCManagerA *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_OPENSCMANAGERA];
+
+ r = talloc(talloc_tos(), struct svcctl_OpenSCManagerA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_OpenSCManagerA, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_OpenSCManagerA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_OpenSCManagerA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_OpenServiceA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_OpenServiceA *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_OPENSERVICEA];
+
+ r = talloc(talloc_tos(), struct svcctl_OpenServiceA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_OpenServiceA, r);
+ }
+
+ r->out.result = _svcctl_OpenServiceA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_OpenServiceA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_QueryServiceConfigA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_QueryServiceConfigA *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_QUERYSERVICECONFIGA];
+
+ r = talloc(talloc_tos(), struct svcctl_QueryServiceConfigA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceConfigA, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.query = talloc_zero_array(r, uint8_t, r->in.buf_size);
+ if (r->out.query == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.bytes_needed = talloc_zero(r, uint32_t);
+ if (r->out.bytes_needed == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_QueryServiceConfigA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceConfigA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_QueryServiceLockStatusA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_QueryServiceLockStatusA *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_QUERYSERVICELOCKSTATUSA];
+
+ r = talloc(talloc_tos(), struct svcctl_QueryServiceLockStatusA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceLockStatusA, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.lock_status = talloc_zero(r, struct SERVICE_LOCK_STATUS);
+ if (r->out.lock_status == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.required_buf_size = talloc_zero(r, uint32_t);
+ if (r->out.required_buf_size == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_QueryServiceLockStatusA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceLockStatusA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_StartServiceA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_StartServiceA *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_STARTSERVICEA];
+
+ r = talloc(talloc_tos(), struct svcctl_StartServiceA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_StartServiceA, r);
+ }
+
+ r->out.result = _svcctl_StartServiceA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_StartServiceA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_GetServiceDisplayNameA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_GetServiceDisplayNameA *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_GETSERVICEDISPLAYNAMEA];
+
+ r = talloc(talloc_tos(), struct svcctl_GetServiceDisplayNameA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_GetServiceDisplayNameA, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.display_name = talloc_zero(r, const char *);
+ if (r->out.display_name == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.display_name_length = r->in.display_name_length;
+ r->out.result = _svcctl_GetServiceDisplayNameA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_GetServiceDisplayNameA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_GetServiceKeyNameA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_GetServiceKeyNameA *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_GETSERVICEKEYNAMEA];
+
+ r = talloc(talloc_tos(), struct svcctl_GetServiceKeyNameA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_GetServiceKeyNameA, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.key_name = talloc_zero(r, const char *);
+ if (r->out.key_name == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.display_name_length = r->in.display_name_length;
+ r->out.result = _svcctl_GetServiceKeyNameA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_GetServiceKeyNameA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_GetCurrentGroupeStateW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_GetCurrentGroupeStateW *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_GETCURRENTGROUPESTATEW];
+
+ r = talloc(talloc_tos(), struct svcctl_GetCurrentGroupeStateW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_GetCurrentGroupeStateW, r);
+ }
+
+ r->out.result = _svcctl_GetCurrentGroupeStateW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_GetCurrentGroupeStateW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_EnumServiceGroupW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_EnumServiceGroupW *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_ENUMSERVICEGROUPW];
+
+ r = talloc(talloc_tos(), struct svcctl_EnumServiceGroupW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_EnumServiceGroupW, r);
+ }
+
+ r->out.result = _svcctl_EnumServiceGroupW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_EnumServiceGroupW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_ChangeServiceConfig2A(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_ChangeServiceConfig2A *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_CHANGESERVICECONFIG2A];
+
+ r = talloc(talloc_tos(), struct svcctl_ChangeServiceConfig2A);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_ChangeServiceConfig2A, r);
+ }
+
+ r->out.result = _svcctl_ChangeServiceConfig2A(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_ChangeServiceConfig2A, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_ChangeServiceConfig2W(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_ChangeServiceConfig2W *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_CHANGESERVICECONFIG2W];
+
+ r = talloc(talloc_tos(), struct svcctl_ChangeServiceConfig2W);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_ChangeServiceConfig2W, r);
+ }
+
+ r->out.result = _svcctl_ChangeServiceConfig2W(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_ChangeServiceConfig2W, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_QueryServiceConfig2A(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_QueryServiceConfig2A *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_QUERYSERVICECONFIG2A];
+
+ r = talloc(talloc_tos(), struct svcctl_QueryServiceConfig2A);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceConfig2A, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.buffer = talloc_zero_array(r, uint8_t, r->in.buf_size);
+ if (r->out.buffer == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.bytes_needed = talloc_zero(r, uint32_t);
+ if (r->out.bytes_needed == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_QueryServiceConfig2A(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceConfig2A, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_QueryServiceConfig2W(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_QueryServiceConfig2W *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_QUERYSERVICECONFIG2W];
+
+ r = talloc(talloc_tos(), struct svcctl_QueryServiceConfig2W);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceConfig2W, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.buffer = talloc_zero_array(r, uint8_t, r->in.buf_size);
+ if (r->out.buffer == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.bytes_needed = talloc_zero(r, uint32_t);
+ if (r->out.bytes_needed == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_QueryServiceConfig2W(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceConfig2W, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_QueryServiceStatusEx(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_QueryServiceStatusEx *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_QUERYSERVICESTATUSEX];
+
+ r = talloc(talloc_tos(), struct svcctl_QueryServiceStatusEx);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_QueryServiceStatusEx, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.buffer = talloc_zero_array(r, uint8_t, r->in.buf_size);
+ if (r->out.buffer == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.bytes_needed = talloc_zero(r, uint32_t);
+ if (r->out.bytes_needed == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _svcctl_QueryServiceStatusEx(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_QueryServiceStatusEx, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_EnumServicesStatusExA(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct EnumServicesStatusExA *r;
+
+ call = &ndr_table_svcctl.calls[NDR_ENUMSERVICESSTATUSEXA];
+
+ r = talloc(talloc_tos(), struct EnumServicesStatusExA);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(EnumServicesStatusExA, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.services = talloc_zero_array(r, uint8_t, r->in.buf_size);
+ if (r->out.services == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.bytes_needed = talloc_zero(r, uint32_t);
+ if (r->out.bytes_needed == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.service_returned = talloc_zero(r, uint32_t);
+ if (r->out.service_returned == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.group_name = talloc_zero(r, const char *);
+ if (r->out.group_name == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _EnumServicesStatusExA(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(EnumServicesStatusExA, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_EnumServicesStatusExW(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct EnumServicesStatusExW *r;
+
+ call = &ndr_table_svcctl.calls[NDR_ENUMSERVICESSTATUSEXW];
+
+ r = talloc(talloc_tos(), struct EnumServicesStatusExW);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(EnumServicesStatusExW, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.services = talloc_zero_array(r, uint8_t, r->in.buf_size);
+ if (r->out.services == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.bytes_needed = talloc_zero(r, uint32_t);
+ if (r->out.bytes_needed == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.service_returned = talloc_zero(r, uint32_t);
+ if (r->out.service_returned == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.group_name = talloc_zero(r, const char *);
+ if (r->out.group_name == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _EnumServicesStatusExW(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(EnumServicesStatusExW, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_svcctl_SCSendTSMessage(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct svcctl_SCSendTSMessage *r;
+
+ call = &ndr_table_svcctl.calls[NDR_SVCCTL_SCSENDTSMESSAGE];
+
+ r = talloc(talloc_tos(), struct svcctl_SCSendTSMessage);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(svcctl_SCSendTSMessage, r);
+ }
+
+ r->out.result = _svcctl_SCSendTSMessage(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(svcctl_SCSendTSMessage, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+
+/* Tables */
+static struct api_struct api_svcctl_cmds[] =
+{
+ {"SVCCTL_CLOSESERVICEHANDLE", NDR_SVCCTL_CLOSESERVICEHANDLE, api_svcctl_CloseServiceHandle},
+ {"SVCCTL_CONTROLSERVICE", NDR_SVCCTL_CONTROLSERVICE, api_svcctl_ControlService},
+ {"SVCCTL_DELETESERVICE", NDR_SVCCTL_DELETESERVICE, api_svcctl_DeleteService},
+ {"SVCCTL_LOCKSERVICEDATABASE", NDR_SVCCTL_LOCKSERVICEDATABASE, api_svcctl_LockServiceDatabase},
+ {"SVCCTL_QUERYSERVICEOBJECTSECURITY", NDR_SVCCTL_QUERYSERVICEOBJECTSECURITY, api_svcctl_QueryServiceObjectSecurity},
+ {"SVCCTL_SETSERVICEOBJECTSECURITY", NDR_SVCCTL_SETSERVICEOBJECTSECURITY, api_svcctl_SetServiceObjectSecurity},
+ {"SVCCTL_QUERYSERVICESTATUS", NDR_SVCCTL_QUERYSERVICESTATUS, api_svcctl_QueryServiceStatus},
+ {"SVCCTL_SETSERVICESTATUS", NDR_SVCCTL_SETSERVICESTATUS, api_svcctl_SetServiceStatus},
+ {"SVCCTL_UNLOCKSERVICEDATABASE", NDR_SVCCTL_UNLOCKSERVICEDATABASE, api_svcctl_UnlockServiceDatabase},
+ {"SVCCTL_NOTIFYBOOTCONFIGSTATUS", NDR_SVCCTL_NOTIFYBOOTCONFIGSTATUS, api_svcctl_NotifyBootConfigStatus},
+ {"SVCCTL_SCSETSERVICEBITSW", NDR_SVCCTL_SCSETSERVICEBITSW, api_svcctl_SCSetServiceBitsW},
+ {"SVCCTL_CHANGESERVICECONFIGW", NDR_SVCCTL_CHANGESERVICECONFIGW, api_svcctl_ChangeServiceConfigW},
+ {"SVCCTL_CREATESERVICEW", NDR_SVCCTL_CREATESERVICEW, api_svcctl_CreateServiceW},
+ {"SVCCTL_ENUMDEPENDENTSERVICESW", NDR_SVCCTL_ENUMDEPENDENTSERVICESW, api_svcctl_EnumDependentServicesW},
+ {"SVCCTL_ENUMSERVICESSTATUSW", NDR_SVCCTL_ENUMSERVICESSTATUSW, api_svcctl_EnumServicesStatusW},
+ {"SVCCTL_OPENSCMANAGERW", NDR_SVCCTL_OPENSCMANAGERW, api_svcctl_OpenSCManagerW},
+ {"SVCCTL_OPENSERVICEW", NDR_SVCCTL_OPENSERVICEW, api_svcctl_OpenServiceW},
+ {"SVCCTL_QUERYSERVICECONFIGW", NDR_SVCCTL_QUERYSERVICECONFIGW, api_svcctl_QueryServiceConfigW},
+ {"SVCCTL_QUERYSERVICELOCKSTATUSW", NDR_SVCCTL_QUERYSERVICELOCKSTATUSW, api_svcctl_QueryServiceLockStatusW},
+ {"SVCCTL_STARTSERVICEW", NDR_SVCCTL_STARTSERVICEW, api_svcctl_StartServiceW},
+ {"SVCCTL_GETSERVICEDISPLAYNAMEW", NDR_SVCCTL_GETSERVICEDISPLAYNAMEW, api_svcctl_GetServiceDisplayNameW},
+ {"SVCCTL_GETSERVICEKEYNAMEW", NDR_SVCCTL_GETSERVICEKEYNAMEW, api_svcctl_GetServiceKeyNameW},
+ {"SVCCTL_SCSETSERVICEBITSA", NDR_SVCCTL_SCSETSERVICEBITSA, api_svcctl_SCSetServiceBitsA},
+ {"SVCCTL_CHANGESERVICECONFIGA", NDR_SVCCTL_CHANGESERVICECONFIGA, api_svcctl_ChangeServiceConfigA},
+ {"SVCCTL_CREATESERVICEA", NDR_SVCCTL_CREATESERVICEA, api_svcctl_CreateServiceA},
+ {"SVCCTL_ENUMDEPENDENTSERVICESA", NDR_SVCCTL_ENUMDEPENDENTSERVICESA, api_svcctl_EnumDependentServicesA},
+ {"SVCCTL_ENUMSERVICESSTATUSA", NDR_SVCCTL_ENUMSERVICESSTATUSA, api_svcctl_EnumServicesStatusA},
+ {"SVCCTL_OPENSCMANAGERA", NDR_SVCCTL_OPENSCMANAGERA, api_svcctl_OpenSCManagerA},
+ {"SVCCTL_OPENSERVICEA", NDR_SVCCTL_OPENSERVICEA, api_svcctl_OpenServiceA},
+ {"SVCCTL_QUERYSERVICECONFIGA", NDR_SVCCTL_QUERYSERVICECONFIGA, api_svcctl_QueryServiceConfigA},
+ {"SVCCTL_QUERYSERVICELOCKSTATUSA", NDR_SVCCTL_QUERYSERVICELOCKSTATUSA, api_svcctl_QueryServiceLockStatusA},
+ {"SVCCTL_STARTSERVICEA", NDR_SVCCTL_STARTSERVICEA, api_svcctl_StartServiceA},
+ {"SVCCTL_GETSERVICEDISPLAYNAMEA", NDR_SVCCTL_GETSERVICEDISPLAYNAMEA, api_svcctl_GetServiceDisplayNameA},
+ {"SVCCTL_GETSERVICEKEYNAMEA", NDR_SVCCTL_GETSERVICEKEYNAMEA, api_svcctl_GetServiceKeyNameA},
+ {"SVCCTL_GETCURRENTGROUPESTATEW", NDR_SVCCTL_GETCURRENTGROUPESTATEW, api_svcctl_GetCurrentGroupeStateW},
+ {"SVCCTL_ENUMSERVICEGROUPW", NDR_SVCCTL_ENUMSERVICEGROUPW, api_svcctl_EnumServiceGroupW},
+ {"SVCCTL_CHANGESERVICECONFIG2A", NDR_SVCCTL_CHANGESERVICECONFIG2A, api_svcctl_ChangeServiceConfig2A},
+ {"SVCCTL_CHANGESERVICECONFIG2W", NDR_SVCCTL_CHANGESERVICECONFIG2W, api_svcctl_ChangeServiceConfig2W},
+ {"SVCCTL_QUERYSERVICECONFIG2A", NDR_SVCCTL_QUERYSERVICECONFIG2A, api_svcctl_QueryServiceConfig2A},
+ {"SVCCTL_QUERYSERVICECONFIG2W", NDR_SVCCTL_QUERYSERVICECONFIG2W, api_svcctl_QueryServiceConfig2W},
+ {"SVCCTL_QUERYSERVICESTATUSEX", NDR_SVCCTL_QUERYSERVICESTATUSEX, api_svcctl_QueryServiceStatusEx},
+ {"ENUMSERVICESSTATUSEXA", NDR_ENUMSERVICESSTATUSEXA, api_EnumServicesStatusExA},
+ {"ENUMSERVICESSTATUSEXW", NDR_ENUMSERVICESSTATUSEXW, api_EnumServicesStatusExW},
+ {"SVCCTL_SCSENDTSMESSAGE", NDR_SVCCTL_SCSENDTSMESSAGE, api_svcctl_SCSendTSMessage},
+};
+
+void svcctl_get_pipe_fns(struct api_struct **fns, int *n_fns)
+{
+ *fns = api_svcctl_cmds;
+ *n_fns = sizeof(api_svcctl_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_svcctl_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "svcctl", "svcctl", &ndr_table_svcctl.syntax_id, api_svcctl_cmds, sizeof(api_svcctl_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/librpc/gen_ndr/srv_svcctl.h b/source3/librpc/gen_ndr/srv_svcctl.h
new file mode 100644
index 0000000000..ca63ebe970
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_svcctl.h
@@ -0,0 +1,50 @@
+#include "librpc/gen_ndr/ndr_svcctl.h"
+#ifndef __SRV_SVCCTL__
+#define __SRV_SVCCTL__
+WERROR _svcctl_CloseServiceHandle(pipes_struct *p, struct svcctl_CloseServiceHandle *r);
+WERROR _svcctl_ControlService(pipes_struct *p, struct svcctl_ControlService *r);
+WERROR _svcctl_DeleteService(pipes_struct *p, struct svcctl_DeleteService *r);
+WERROR _svcctl_LockServiceDatabase(pipes_struct *p, struct svcctl_LockServiceDatabase *r);
+WERROR _svcctl_QueryServiceObjectSecurity(pipes_struct *p, struct svcctl_QueryServiceObjectSecurity *r);
+WERROR _svcctl_SetServiceObjectSecurity(pipes_struct *p, struct svcctl_SetServiceObjectSecurity *r);
+WERROR _svcctl_QueryServiceStatus(pipes_struct *p, struct svcctl_QueryServiceStatus *r);
+WERROR _svcctl_SetServiceStatus(pipes_struct *p, struct svcctl_SetServiceStatus *r);
+WERROR _svcctl_UnlockServiceDatabase(pipes_struct *p, struct svcctl_UnlockServiceDatabase *r);
+WERROR _svcctl_NotifyBootConfigStatus(pipes_struct *p, struct svcctl_NotifyBootConfigStatus *r);
+WERROR _svcctl_SCSetServiceBitsW(pipes_struct *p, struct svcctl_SCSetServiceBitsW *r);
+WERROR _svcctl_ChangeServiceConfigW(pipes_struct *p, struct svcctl_ChangeServiceConfigW *r);
+WERROR _svcctl_CreateServiceW(pipes_struct *p, struct svcctl_CreateServiceW *r);
+WERROR _svcctl_EnumDependentServicesW(pipes_struct *p, struct svcctl_EnumDependentServicesW *r);
+WERROR _svcctl_EnumServicesStatusW(pipes_struct *p, struct svcctl_EnumServicesStatusW *r);
+WERROR _svcctl_OpenSCManagerW(pipes_struct *p, struct svcctl_OpenSCManagerW *r);
+WERROR _svcctl_OpenServiceW(pipes_struct *p, struct svcctl_OpenServiceW *r);
+WERROR _svcctl_QueryServiceConfigW(pipes_struct *p, struct svcctl_QueryServiceConfigW *r);
+WERROR _svcctl_QueryServiceLockStatusW(pipes_struct *p, struct svcctl_QueryServiceLockStatusW *r);
+WERROR _svcctl_StartServiceW(pipes_struct *p, struct svcctl_StartServiceW *r);
+WERROR _svcctl_GetServiceDisplayNameW(pipes_struct *p, struct svcctl_GetServiceDisplayNameW *r);
+WERROR _svcctl_GetServiceKeyNameW(pipes_struct *p, struct svcctl_GetServiceKeyNameW *r);
+WERROR _svcctl_SCSetServiceBitsA(pipes_struct *p, struct svcctl_SCSetServiceBitsA *r);
+WERROR _svcctl_ChangeServiceConfigA(pipes_struct *p, struct svcctl_ChangeServiceConfigA *r);
+WERROR _svcctl_CreateServiceA(pipes_struct *p, struct svcctl_CreateServiceA *r);
+WERROR _svcctl_EnumDependentServicesA(pipes_struct *p, struct svcctl_EnumDependentServicesA *r);
+WERROR _svcctl_EnumServicesStatusA(pipes_struct *p, struct svcctl_EnumServicesStatusA *r);
+WERROR _svcctl_OpenSCManagerA(pipes_struct *p, struct svcctl_OpenSCManagerA *r);
+WERROR _svcctl_OpenServiceA(pipes_struct *p, struct svcctl_OpenServiceA *r);
+WERROR _svcctl_QueryServiceConfigA(pipes_struct *p, struct svcctl_QueryServiceConfigA *r);
+WERROR _svcctl_QueryServiceLockStatusA(pipes_struct *p, struct svcctl_QueryServiceLockStatusA *r);
+WERROR _svcctl_StartServiceA(pipes_struct *p, struct svcctl_StartServiceA *r);
+WERROR _svcctl_GetServiceDisplayNameA(pipes_struct *p, struct svcctl_GetServiceDisplayNameA *r);
+WERROR _svcctl_GetServiceKeyNameA(pipes_struct *p, struct svcctl_GetServiceKeyNameA *r);
+WERROR _svcctl_GetCurrentGroupeStateW(pipes_struct *p, struct svcctl_GetCurrentGroupeStateW *r);
+WERROR _svcctl_EnumServiceGroupW(pipes_struct *p, struct svcctl_EnumServiceGroupW *r);
+WERROR _svcctl_ChangeServiceConfig2A(pipes_struct *p, struct svcctl_ChangeServiceConfig2A *r);
+WERROR _svcctl_ChangeServiceConfig2W(pipes_struct *p, struct svcctl_ChangeServiceConfig2W *r);
+WERROR _svcctl_QueryServiceConfig2A(pipes_struct *p, struct svcctl_QueryServiceConfig2A *r);
+WERROR _svcctl_QueryServiceConfig2W(pipes_struct *p, struct svcctl_QueryServiceConfig2W *r);
+WERROR _svcctl_QueryServiceStatusEx(pipes_struct *p, struct svcctl_QueryServiceStatusEx *r);
+WERROR _EnumServicesStatusExA(pipes_struct *p, struct EnumServicesStatusExA *r);
+WERROR _EnumServicesStatusExW(pipes_struct *p, struct EnumServicesStatusExW *r);
+WERROR _svcctl_SCSendTSMessage(pipes_struct *p, struct svcctl_SCSendTSMessage *r);
+void svcctl_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_svcctl_init(void);
+#endif /* __SRV_SVCCTL__ */
diff --git a/source3/librpc/gen_ndr/srv_winreg.c b/source3/librpc/gen_ndr/srv_winreg.c
new file mode 100644
index 0000000000..c697f44d2a
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_winreg.c
@@ -0,0 +1,2772 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * server auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/srv_winreg.h"
+
+static bool api_winreg_OpenHKCR(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_OpenHKCR *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_OPENHKCR];
+
+ r = talloc(talloc_tos(), struct winreg_OpenHKCR);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKCR, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _winreg_OpenHKCR(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKCR, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_OpenHKCU(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_OpenHKCU *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_OPENHKCU];
+
+ r = talloc(talloc_tos(), struct winreg_OpenHKCU);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKCU, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _winreg_OpenHKCU(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKCU, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_OpenHKLM(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_OpenHKLM *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_OPENHKLM];
+
+ r = talloc(talloc_tos(), struct winreg_OpenHKLM);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKLM, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _winreg_OpenHKLM(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKLM, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_OpenHKPD(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_OpenHKPD *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_OPENHKPD];
+
+ r = talloc(talloc_tos(), struct winreg_OpenHKPD);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKPD, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _winreg_OpenHKPD(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKPD, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_OpenHKU(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_OpenHKU *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_OPENHKU];
+
+ r = talloc(talloc_tos(), struct winreg_OpenHKU);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKU, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _winreg_OpenHKU(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKU, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_CloseKey(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_CloseKey *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_CLOSEKEY];
+
+ r = talloc(talloc_tos(), struct winreg_CloseKey);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_CloseKey, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = r->in.handle;
+ r->out.result = _winreg_CloseKey(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_CloseKey, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_CreateKey(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_CreateKey *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_CREATEKEY];
+
+ r = talloc(talloc_tos(), struct winreg_CreateKey);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_CreateKey, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.new_handle = talloc_zero(r, struct policy_handle);
+ if (r->out.new_handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.action_taken = r->in.action_taken;
+ r->out.result = _winreg_CreateKey(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_CreateKey, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_DeleteKey(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_DeleteKey *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_DELETEKEY];
+
+ r = talloc(talloc_tos(), struct winreg_DeleteKey);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_DeleteKey, r);
+ }
+
+ r->out.result = _winreg_DeleteKey(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_DeleteKey, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_DeleteValue(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_DeleteValue *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_DELETEVALUE];
+
+ r = talloc(talloc_tos(), struct winreg_DeleteValue);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_DeleteValue, r);
+ }
+
+ r->out.result = _winreg_DeleteValue(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_DeleteValue, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_EnumKey(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_EnumKey *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_ENUMKEY];
+
+ r = talloc(talloc_tos(), struct winreg_EnumKey);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_EnumKey, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.name = r->in.name;
+ r->out.keyclass = r->in.keyclass;
+ r->out.last_changed_time = r->in.last_changed_time;
+ r->out.result = _winreg_EnumKey(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_EnumKey, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_EnumValue(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_EnumValue *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_ENUMVALUE];
+
+ r = talloc(talloc_tos(), struct winreg_EnumValue);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_EnumValue, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.name = r->in.name;
+ r->out.type = r->in.type;
+ r->out.value = r->in.value;
+ r->out.size = r->in.size;
+ r->out.length = r->in.length;
+ r->out.result = _winreg_EnumValue(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_EnumValue, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_FlushKey(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_FlushKey *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_FLUSHKEY];
+
+ r = talloc(talloc_tos(), struct winreg_FlushKey);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_FlushKey, r);
+ }
+
+ r->out.result = _winreg_FlushKey(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_FlushKey, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_GetKeySecurity(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_GetKeySecurity *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_GETKEYSECURITY];
+
+ r = talloc(talloc_tos(), struct winreg_GetKeySecurity);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_GetKeySecurity, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.sd = r->in.sd;
+ r->out.result = _winreg_GetKeySecurity(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_GetKeySecurity, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_LoadKey(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_LoadKey *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_LOADKEY];
+
+ r = talloc(talloc_tos(), struct winreg_LoadKey);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_LoadKey, r);
+ }
+
+ r->out.result = _winreg_LoadKey(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_LoadKey, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_NotifyChangeKeyValue(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_NotifyChangeKeyValue *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_NOTIFYCHANGEKEYVALUE];
+
+ r = talloc(talloc_tos(), struct winreg_NotifyChangeKeyValue);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_NotifyChangeKeyValue, r);
+ }
+
+ r->out.result = _winreg_NotifyChangeKeyValue(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_NotifyChangeKeyValue, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_OpenKey(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_OpenKey *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_OPENKEY];
+
+ r = talloc(talloc_tos(), struct winreg_OpenKey);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenKey, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _winreg_OpenKey(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenKey, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_QueryInfoKey(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_QueryInfoKey *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_QUERYINFOKEY];
+
+ r = talloc(talloc_tos(), struct winreg_QueryInfoKey);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_QueryInfoKey, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.classname = r->in.classname;
+ r->out.num_subkeys = talloc_zero(r, uint32_t);
+ if (r->out.num_subkeys == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.max_subkeylen = talloc_zero(r, uint32_t);
+ if (r->out.max_subkeylen == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.max_classlen = talloc_zero(r, uint32_t);
+ if (r->out.max_classlen == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.num_values = talloc_zero(r, uint32_t);
+ if (r->out.num_values == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.max_valnamelen = talloc_zero(r, uint32_t);
+ if (r->out.max_valnamelen == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.max_valbufsize = talloc_zero(r, uint32_t);
+ if (r->out.max_valbufsize == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.secdescsize = talloc_zero(r, uint32_t);
+ if (r->out.secdescsize == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.last_changed_time = talloc_zero(r, NTTIME);
+ if (r->out.last_changed_time == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _winreg_QueryInfoKey(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_QueryInfoKey, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_QueryValue(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_QueryValue *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_QUERYVALUE];
+
+ r = talloc(talloc_tos(), struct winreg_QueryValue);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_QueryValue, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.type = r->in.type;
+ r->out.data = r->in.data;
+ r->out.data_size = r->in.data_size;
+ r->out.value_length = r->in.value_length;
+ r->out.result = _winreg_QueryValue(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_QueryValue, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_ReplaceKey(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_ReplaceKey *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_REPLACEKEY];
+
+ r = talloc(talloc_tos(), struct winreg_ReplaceKey);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_ReplaceKey, r);
+ }
+
+ r->out.result = _winreg_ReplaceKey(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_ReplaceKey, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_RestoreKey(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_RestoreKey *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_RESTOREKEY];
+
+ r = talloc(talloc_tos(), struct winreg_RestoreKey);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_RestoreKey, r);
+ }
+
+ r->out.result = _winreg_RestoreKey(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_RestoreKey, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_SaveKey(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_SaveKey *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_SAVEKEY];
+
+ r = talloc(talloc_tos(), struct winreg_SaveKey);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_SaveKey, r);
+ }
+
+ r->out.result = _winreg_SaveKey(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_SaveKey, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_SetKeySecurity(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_SetKeySecurity *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_SETKEYSECURITY];
+
+ r = talloc(talloc_tos(), struct winreg_SetKeySecurity);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_SetKeySecurity, r);
+ }
+
+ r->out.result = _winreg_SetKeySecurity(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_SetKeySecurity, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_SetValue(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_SetValue *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_SETVALUE];
+
+ r = talloc(talloc_tos(), struct winreg_SetValue);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_SetValue, r);
+ }
+
+ r->out.result = _winreg_SetValue(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_SetValue, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_UnLoadKey(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_UnLoadKey *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_UNLOADKEY];
+
+ r = talloc(talloc_tos(), struct winreg_UnLoadKey);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_UnLoadKey, r);
+ }
+
+ r->out.result = _winreg_UnLoadKey(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_UnLoadKey, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_InitiateSystemShutdown(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_InitiateSystemShutdown *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_INITIATESYSTEMSHUTDOWN];
+
+ r = talloc(talloc_tos(), struct winreg_InitiateSystemShutdown);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_InitiateSystemShutdown, r);
+ }
+
+ r->out.result = _winreg_InitiateSystemShutdown(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_InitiateSystemShutdown, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_AbortSystemShutdown(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_AbortSystemShutdown *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_ABORTSYSTEMSHUTDOWN];
+
+ r = talloc(talloc_tos(), struct winreg_AbortSystemShutdown);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_AbortSystemShutdown, r);
+ }
+
+ r->out.result = _winreg_AbortSystemShutdown(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_AbortSystemShutdown, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_GetVersion(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_GetVersion *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_GETVERSION];
+
+ r = talloc(talloc_tos(), struct winreg_GetVersion);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_GetVersion, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.version = talloc_zero(r, uint32_t);
+ if (r->out.version == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _winreg_GetVersion(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_GetVersion, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_OpenHKCC(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_OpenHKCC *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_OPENHKCC];
+
+ r = talloc(talloc_tos(), struct winreg_OpenHKCC);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKCC, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _winreg_OpenHKCC(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKCC, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_OpenHKDD(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_OpenHKDD *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_OPENHKDD];
+
+ r = talloc(talloc_tos(), struct winreg_OpenHKDD);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKDD, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _winreg_OpenHKDD(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKDD, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_QueryMultipleValues(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_QueryMultipleValues *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_QUERYMULTIPLEVALUES];
+
+ r = talloc(talloc_tos(), struct winreg_QueryMultipleValues);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_QueryMultipleValues, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.values = r->in.values;
+ r->out.buffer = r->in.buffer;
+ r->out.buffer_size = r->in.buffer_size;
+ r->out.result = _winreg_QueryMultipleValues(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_QueryMultipleValues, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_InitiateSystemShutdownEx(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_InitiateSystemShutdownEx *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_INITIATESYSTEMSHUTDOWNEX];
+
+ r = talloc(talloc_tos(), struct winreg_InitiateSystemShutdownEx);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_InitiateSystemShutdownEx, r);
+ }
+
+ r->out.result = _winreg_InitiateSystemShutdownEx(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_InitiateSystemShutdownEx, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_SaveKeyEx(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_SaveKeyEx *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_SAVEKEYEX];
+
+ r = talloc(talloc_tos(), struct winreg_SaveKeyEx);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_SaveKeyEx, r);
+ }
+
+ r->out.result = _winreg_SaveKeyEx(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_SaveKeyEx, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_OpenHKPT(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_OpenHKPT *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_OPENHKPT];
+
+ r = talloc(talloc_tos(), struct winreg_OpenHKPT);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKPT, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _winreg_OpenHKPT(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKPT, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_OpenHKPN(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_OpenHKPN *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_OPENHKPN];
+
+ r = talloc(talloc_tos(), struct winreg_OpenHKPN);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_OpenHKPN, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.handle = talloc_zero(r, struct policy_handle);
+ if (r->out.handle == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _winreg_OpenHKPN(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_OpenHKPN, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_winreg_QueryMultipleValues2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct winreg_QueryMultipleValues2 *r;
+
+ call = &ndr_table_winreg.calls[NDR_WINREG_QUERYMULTIPLEVALUES2];
+
+ r = talloc(talloc_tos(), struct winreg_QueryMultipleValues2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(winreg_QueryMultipleValues2, r);
+ }
+
+ r->out.result = _winreg_QueryMultipleValues2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(winreg_QueryMultipleValues2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+
+/* Tables */
+static struct api_struct api_winreg_cmds[] =
+{
+ {"WINREG_OPENHKCR", NDR_WINREG_OPENHKCR, api_winreg_OpenHKCR},
+ {"WINREG_OPENHKCU", NDR_WINREG_OPENHKCU, api_winreg_OpenHKCU},
+ {"WINREG_OPENHKLM", NDR_WINREG_OPENHKLM, api_winreg_OpenHKLM},
+ {"WINREG_OPENHKPD", NDR_WINREG_OPENHKPD, api_winreg_OpenHKPD},
+ {"WINREG_OPENHKU", NDR_WINREG_OPENHKU, api_winreg_OpenHKU},
+ {"WINREG_CLOSEKEY", NDR_WINREG_CLOSEKEY, api_winreg_CloseKey},
+ {"WINREG_CREATEKEY", NDR_WINREG_CREATEKEY, api_winreg_CreateKey},
+ {"WINREG_DELETEKEY", NDR_WINREG_DELETEKEY, api_winreg_DeleteKey},
+ {"WINREG_DELETEVALUE", NDR_WINREG_DELETEVALUE, api_winreg_DeleteValue},
+ {"WINREG_ENUMKEY", NDR_WINREG_ENUMKEY, api_winreg_EnumKey},
+ {"WINREG_ENUMVALUE", NDR_WINREG_ENUMVALUE, api_winreg_EnumValue},
+ {"WINREG_FLUSHKEY", NDR_WINREG_FLUSHKEY, api_winreg_FlushKey},
+ {"WINREG_GETKEYSECURITY", NDR_WINREG_GETKEYSECURITY, api_winreg_GetKeySecurity},
+ {"WINREG_LOADKEY", NDR_WINREG_LOADKEY, api_winreg_LoadKey},
+ {"WINREG_NOTIFYCHANGEKEYVALUE", NDR_WINREG_NOTIFYCHANGEKEYVALUE, api_winreg_NotifyChangeKeyValue},
+ {"WINREG_OPENKEY", NDR_WINREG_OPENKEY, api_winreg_OpenKey},
+ {"WINREG_QUERYINFOKEY", NDR_WINREG_QUERYINFOKEY, api_winreg_QueryInfoKey},
+ {"WINREG_QUERYVALUE", NDR_WINREG_QUERYVALUE, api_winreg_QueryValue},
+ {"WINREG_REPLACEKEY", NDR_WINREG_REPLACEKEY, api_winreg_ReplaceKey},
+ {"WINREG_RESTOREKEY", NDR_WINREG_RESTOREKEY, api_winreg_RestoreKey},
+ {"WINREG_SAVEKEY", NDR_WINREG_SAVEKEY, api_winreg_SaveKey},
+ {"WINREG_SETKEYSECURITY", NDR_WINREG_SETKEYSECURITY, api_winreg_SetKeySecurity},
+ {"WINREG_SETVALUE", NDR_WINREG_SETVALUE, api_winreg_SetValue},
+ {"WINREG_UNLOADKEY", NDR_WINREG_UNLOADKEY, api_winreg_UnLoadKey},
+ {"WINREG_INITIATESYSTEMSHUTDOWN", NDR_WINREG_INITIATESYSTEMSHUTDOWN, api_winreg_InitiateSystemShutdown},
+ {"WINREG_ABORTSYSTEMSHUTDOWN", NDR_WINREG_ABORTSYSTEMSHUTDOWN, api_winreg_AbortSystemShutdown},
+ {"WINREG_GETVERSION", NDR_WINREG_GETVERSION, api_winreg_GetVersion},
+ {"WINREG_OPENHKCC", NDR_WINREG_OPENHKCC, api_winreg_OpenHKCC},
+ {"WINREG_OPENHKDD", NDR_WINREG_OPENHKDD, api_winreg_OpenHKDD},
+ {"WINREG_QUERYMULTIPLEVALUES", NDR_WINREG_QUERYMULTIPLEVALUES, api_winreg_QueryMultipleValues},
+ {"WINREG_INITIATESYSTEMSHUTDOWNEX", NDR_WINREG_INITIATESYSTEMSHUTDOWNEX, api_winreg_InitiateSystemShutdownEx},
+ {"WINREG_SAVEKEYEX", NDR_WINREG_SAVEKEYEX, api_winreg_SaveKeyEx},
+ {"WINREG_OPENHKPT", NDR_WINREG_OPENHKPT, api_winreg_OpenHKPT},
+ {"WINREG_OPENHKPN", NDR_WINREG_OPENHKPN, api_winreg_OpenHKPN},
+ {"WINREG_QUERYMULTIPLEVALUES2", NDR_WINREG_QUERYMULTIPLEVALUES2, api_winreg_QueryMultipleValues2},
+};
+
+void winreg_get_pipe_fns(struct api_struct **fns, int *n_fns)
+{
+ *fns = api_winreg_cmds;
+ *n_fns = sizeof(api_winreg_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_winreg_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "winreg", "winreg", &ndr_table_winreg.syntax_id, api_winreg_cmds, sizeof(api_winreg_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/librpc/gen_ndr/srv_winreg.h b/source3/librpc/gen_ndr/srv_winreg.h
new file mode 100644
index 0000000000..decfb2589d
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_winreg.h
@@ -0,0 +1,41 @@
+#include "librpc/gen_ndr/ndr_winreg.h"
+#ifndef __SRV_WINREG__
+#define __SRV_WINREG__
+WERROR _winreg_OpenHKCR(pipes_struct *p, struct winreg_OpenHKCR *r);
+WERROR _winreg_OpenHKCU(pipes_struct *p, struct winreg_OpenHKCU *r);
+WERROR _winreg_OpenHKLM(pipes_struct *p, struct winreg_OpenHKLM *r);
+WERROR _winreg_OpenHKPD(pipes_struct *p, struct winreg_OpenHKPD *r);
+WERROR _winreg_OpenHKU(pipes_struct *p, struct winreg_OpenHKU *r);
+WERROR _winreg_CloseKey(pipes_struct *p, struct winreg_CloseKey *r);
+WERROR _winreg_CreateKey(pipes_struct *p, struct winreg_CreateKey *r);
+WERROR _winreg_DeleteKey(pipes_struct *p, struct winreg_DeleteKey *r);
+WERROR _winreg_DeleteValue(pipes_struct *p, struct winreg_DeleteValue *r);
+WERROR _winreg_EnumKey(pipes_struct *p, struct winreg_EnumKey *r);
+WERROR _winreg_EnumValue(pipes_struct *p, struct winreg_EnumValue *r);
+WERROR _winreg_FlushKey(pipes_struct *p, struct winreg_FlushKey *r);
+WERROR _winreg_GetKeySecurity(pipes_struct *p, struct winreg_GetKeySecurity *r);
+WERROR _winreg_LoadKey(pipes_struct *p, struct winreg_LoadKey *r);
+WERROR _winreg_NotifyChangeKeyValue(pipes_struct *p, struct winreg_NotifyChangeKeyValue *r);
+WERROR _winreg_OpenKey(pipes_struct *p, struct winreg_OpenKey *r);
+WERROR _winreg_QueryInfoKey(pipes_struct *p, struct winreg_QueryInfoKey *r);
+WERROR _winreg_QueryValue(pipes_struct *p, struct winreg_QueryValue *r);
+WERROR _winreg_ReplaceKey(pipes_struct *p, struct winreg_ReplaceKey *r);
+WERROR _winreg_RestoreKey(pipes_struct *p, struct winreg_RestoreKey *r);
+WERROR _winreg_SaveKey(pipes_struct *p, struct winreg_SaveKey *r);
+WERROR _winreg_SetKeySecurity(pipes_struct *p, struct winreg_SetKeySecurity *r);
+WERROR _winreg_SetValue(pipes_struct *p, struct winreg_SetValue *r);
+WERROR _winreg_UnLoadKey(pipes_struct *p, struct winreg_UnLoadKey *r);
+WERROR _winreg_InitiateSystemShutdown(pipes_struct *p, struct winreg_InitiateSystemShutdown *r);
+WERROR _winreg_AbortSystemShutdown(pipes_struct *p, struct winreg_AbortSystemShutdown *r);
+WERROR _winreg_GetVersion(pipes_struct *p, struct winreg_GetVersion *r);
+WERROR _winreg_OpenHKCC(pipes_struct *p, struct winreg_OpenHKCC *r);
+WERROR _winreg_OpenHKDD(pipes_struct *p, struct winreg_OpenHKDD *r);
+WERROR _winreg_QueryMultipleValues(pipes_struct *p, struct winreg_QueryMultipleValues *r);
+WERROR _winreg_InitiateSystemShutdownEx(pipes_struct *p, struct winreg_InitiateSystemShutdownEx *r);
+WERROR _winreg_SaveKeyEx(pipes_struct *p, struct winreg_SaveKeyEx *r);
+WERROR _winreg_OpenHKPT(pipes_struct *p, struct winreg_OpenHKPT *r);
+WERROR _winreg_OpenHKPN(pipes_struct *p, struct winreg_OpenHKPN *r);
+WERROR _winreg_QueryMultipleValues2(pipes_struct *p, struct winreg_QueryMultipleValues2 *r);
+void winreg_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_winreg_init(void);
+#endif /* __SRV_WINREG__ */
diff --git a/source3/librpc/gen_ndr/srv_wkssvc.c b/source3/librpc/gen_ndr/srv_wkssvc.c
new file mode 100644
index 0000000000..227e4c1a48
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_wkssvc.c
@@ -0,0 +1,2412 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * server auto-generated by pidl. DO NOT MODIFY!
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/srv_wkssvc.h"
+
+static bool api_wkssvc_NetWkstaGetInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetWkstaGetInfo *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETWKSTAGETINFO];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetWkstaGetInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetWkstaGetInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union wkssvc_NetWkstaInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _wkssvc_NetWkstaGetInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetWkstaGetInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetWkstaSetInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetWkstaSetInfo *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETWKSTASETINFO];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetWkstaSetInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetWkstaSetInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.parm_error = r->in.parm_error;
+ r->out.result = _wkssvc_NetWkstaSetInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetWkstaSetInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetWkstaEnumUsers(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetWkstaEnumUsers *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETWKSTAENUMUSERS];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetWkstaEnumUsers);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetWkstaEnumUsers, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = r->in.info;
+ r->out.entries_read = talloc_zero(r, uint32_t);
+ if (r->out.entries_read == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.result = _wkssvc_NetWkstaEnumUsers(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetWkstaEnumUsers, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrWkstaUserGetInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrWkstaUserGetInfo *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRWKSTAUSERGETINFO];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrWkstaUserGetInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrWkstaUserGetInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, union wkssvc_NetrWkstaUserInfo);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _wkssvc_NetrWkstaUserGetInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrWkstaUserGetInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrWkstaUserSetInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrWkstaUserSetInfo *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRWKSTAUSERSETINFO];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrWkstaUserSetInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrWkstaUserSetInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.parm_err = r->in.parm_err;
+ r->out.result = _wkssvc_NetrWkstaUserSetInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrWkstaUserSetInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetWkstaTransportEnum(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetWkstaTransportEnum *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETWKSTATRANSPORTENUM];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetWkstaTransportEnum);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetWkstaTransportEnum, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = r->in.info;
+ r->out.total_entries = talloc_zero(r, uint32_t);
+ if (r->out.total_entries == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.result = _wkssvc_NetWkstaTransportEnum(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetWkstaTransportEnum, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrWkstaTransportAdd(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrWkstaTransportAdd *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRWKSTATRANSPORTADD];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrWkstaTransportAdd);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrWkstaTransportAdd, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.parm_err = r->in.parm_err;
+ r->out.result = _wkssvc_NetrWkstaTransportAdd(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrWkstaTransportAdd, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrWkstaTransportDel(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrWkstaTransportDel *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRWKSTATRANSPORTDEL];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrWkstaTransportDel);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrWkstaTransportDel, r);
+ }
+
+ r->out.result = _wkssvc_NetrWkstaTransportDel(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrWkstaTransportDel, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrUseAdd(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrUseAdd *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRUSEADD];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrUseAdd);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrUseAdd, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.parm_err = r->in.parm_err;
+ r->out.result = _wkssvc_NetrUseAdd(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrUseAdd, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrUseGetInfo(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrUseGetInfo *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRUSEGETINFO];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrUseGetInfo);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrUseGetInfo, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.ctr = talloc_zero(r, union wkssvc_NetrUseGetInfoCtr);
+ if (r->out.ctr == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _wkssvc_NetrUseGetInfo(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrUseGetInfo, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrUseDel(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrUseDel *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRUSEDEL];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrUseDel);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrUseDel, r);
+ }
+
+ r->out.result = _wkssvc_NetrUseDel(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrUseDel, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrUseEnum(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrUseEnum *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRUSEENUM];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrUseEnum);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrUseEnum, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = r->in.info;
+ r->out.entries_read = talloc_zero(r, uint32_t);
+ if (r->out.entries_read == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.resume_handle = r->in.resume_handle;
+ r->out.result = _wkssvc_NetrUseEnum(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrUseEnum, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrMessageBufferSend(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrMessageBufferSend *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRMESSAGEBUFFERSEND];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrMessageBufferSend);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrMessageBufferSend, r);
+ }
+
+ r->out.result = _wkssvc_NetrMessageBufferSend(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrMessageBufferSend, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrWorkstationStatisticsGet(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrWorkstationStatisticsGet *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRWORKSTATIONSTATISTICSGET];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrWorkstationStatisticsGet);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrWorkstationStatisticsGet, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.info = talloc_zero(r, struct wkssvc_NetrWorkstationStatistics *);
+ if (r->out.info == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _wkssvc_NetrWorkstationStatisticsGet(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrWorkstationStatisticsGet, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrLogonDomainNameAdd(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrLogonDomainNameAdd *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRLOGONDOMAINNAMEADD];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrLogonDomainNameAdd);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrLogonDomainNameAdd, r);
+ }
+
+ r->out.result = _wkssvc_NetrLogonDomainNameAdd(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrLogonDomainNameAdd, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrLogonDomainNameDel(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrLogonDomainNameDel *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRLOGONDOMAINNAMEDEL];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrLogonDomainNameDel);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrLogonDomainNameDel, r);
+ }
+
+ r->out.result = _wkssvc_NetrLogonDomainNameDel(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrLogonDomainNameDel, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrJoinDomain(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrJoinDomain *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRJOINDOMAIN];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrJoinDomain);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrJoinDomain, r);
+ }
+
+ r->out.result = _wkssvc_NetrJoinDomain(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrJoinDomain, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrUnjoinDomain(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrUnjoinDomain *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRUNJOINDOMAIN];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrUnjoinDomain);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrUnjoinDomain, r);
+ }
+
+ r->out.result = _wkssvc_NetrUnjoinDomain(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrUnjoinDomain, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrRenameMachineInDomain(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrRenameMachineInDomain *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRRENAMEMACHINEINDOMAIN];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrRenameMachineInDomain);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrRenameMachineInDomain, r);
+ }
+
+ r->out.result = _wkssvc_NetrRenameMachineInDomain(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrRenameMachineInDomain, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrValidateName(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrValidateName *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRVALIDATENAME];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrValidateName);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrValidateName, r);
+ }
+
+ r->out.result = _wkssvc_NetrValidateName(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrValidateName, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrGetJoinInformation(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrGetJoinInformation *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRGETJOININFORMATION];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrGetJoinInformation);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrGetJoinInformation, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.name_buffer = r->in.name_buffer;
+ r->out.name_type = talloc_zero(r, enum wkssvc_NetJoinStatus);
+ if (r->out.name_type == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _wkssvc_NetrGetJoinInformation(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrGetJoinInformation, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrGetJoinableOus(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrGetJoinableOus *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRGETJOINABLEOUS];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrGetJoinableOus);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrGetJoinableOus, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.num_ous = r->in.num_ous;
+ r->out.ous = talloc_zero(r, const char **);
+ if (r->out.ous == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _wkssvc_NetrGetJoinableOus(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrGetJoinableOus, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrJoinDomain2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrJoinDomain2 *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRJOINDOMAIN2];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrJoinDomain2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrJoinDomain2, r);
+ }
+
+ r->out.result = _wkssvc_NetrJoinDomain2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrJoinDomain2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrUnjoinDomain2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrUnjoinDomain2 *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRUNJOINDOMAIN2];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrUnjoinDomain2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrUnjoinDomain2, r);
+ }
+
+ r->out.result = _wkssvc_NetrUnjoinDomain2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrUnjoinDomain2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrRenameMachineInDomain2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrRenameMachineInDomain2 *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRRENAMEMACHINEINDOMAIN2];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrRenameMachineInDomain2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrRenameMachineInDomain2, r);
+ }
+
+ r->out.result = _wkssvc_NetrRenameMachineInDomain2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrRenameMachineInDomain2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrValidateName2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrValidateName2 *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRVALIDATENAME2];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrValidateName2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrValidateName2, r);
+ }
+
+ r->out.result = _wkssvc_NetrValidateName2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrValidateName2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrGetJoinableOus2(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrGetJoinableOus2 *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRGETJOINABLEOUS2];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrGetJoinableOus2);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrGetJoinableOus2, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.num_ous = r->in.num_ous;
+ r->out.ous = talloc_zero(r, const char **);
+ if (r->out.ous == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _wkssvc_NetrGetJoinableOus2(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrGetJoinableOus2, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrAddAlternateComputerName(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrAddAlternateComputerName *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRADDALTERNATECOMPUTERNAME];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrAddAlternateComputerName);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrAddAlternateComputerName, r);
+ }
+
+ r->out.result = _wkssvc_NetrAddAlternateComputerName(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrAddAlternateComputerName, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrRemoveAlternateComputerName(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrRemoveAlternateComputerName *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRREMOVEALTERNATECOMPUTERNAME];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrRemoveAlternateComputerName);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrRemoveAlternateComputerName, r);
+ }
+
+ r->out.result = _wkssvc_NetrRemoveAlternateComputerName(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrRemoveAlternateComputerName, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrSetPrimaryComputername(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrSetPrimaryComputername *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRSETPRIMARYCOMPUTERNAME];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrSetPrimaryComputername);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrSetPrimaryComputername, r);
+ }
+
+ r->out.result = _wkssvc_NetrSetPrimaryComputername(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrSetPrimaryComputername, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+static bool api_wkssvc_NetrEnumerateComputerNames(pipes_struct *p)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct wkssvc_NetrEnumerateComputerNames *r;
+
+ call = &ndr_table_wkssvc.calls[NDR_WKSSVC_NETRENUMERATECOMPUTERNAMES];
+
+ r = talloc(talloc_tos(), struct wkssvc_NetrEnumerateComputerNames);
+ if (r == NULL) {
+ return false;
+ }
+
+ if (!prs_data_blob(&p->in_data.data, &blob, r)) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull = ndr_pull_init_blob(&blob, r);
+ if (pull == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_IN_DEBUG(wkssvc_NetrEnumerateComputerNames, r);
+ }
+
+ ZERO_STRUCT(r->out);
+ r->out.ctr = talloc_zero(r, struct wkssvc_ComputerNamesCtr *);
+ if (r->out.ctr == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ r->out.result = _wkssvc_NetrEnumerateComputerNames(p, r);
+
+ if (p->rng_fault_state) {
+ talloc_free(r);
+ /* Return true here, srv_pipe_hnd.c will take care */
+ return true;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_OUT_DEBUG(wkssvc_NetrEnumerateComputerNames, r);
+ }
+
+ push = ndr_push_init_ctx(r);
+ if (push == NULL) {
+ talloc_free(r);
+ return false;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(r);
+ return false;
+ }
+
+ blob = ndr_push_blob(push);
+ if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {
+ talloc_free(r);
+ return false;
+ }
+
+ talloc_free(r);
+
+ return true;
+}
+
+
+/* Tables */
+static struct api_struct api_wkssvc_cmds[] =
+{
+ {"WKSSVC_NETWKSTAGETINFO", NDR_WKSSVC_NETWKSTAGETINFO, api_wkssvc_NetWkstaGetInfo},
+ {"WKSSVC_NETWKSTASETINFO", NDR_WKSSVC_NETWKSTASETINFO, api_wkssvc_NetWkstaSetInfo},
+ {"WKSSVC_NETWKSTAENUMUSERS", NDR_WKSSVC_NETWKSTAENUMUSERS, api_wkssvc_NetWkstaEnumUsers},
+ {"WKSSVC_NETRWKSTAUSERGETINFO", NDR_WKSSVC_NETRWKSTAUSERGETINFO, api_wkssvc_NetrWkstaUserGetInfo},
+ {"WKSSVC_NETRWKSTAUSERSETINFO", NDR_WKSSVC_NETRWKSTAUSERSETINFO, api_wkssvc_NetrWkstaUserSetInfo},
+ {"WKSSVC_NETWKSTATRANSPORTENUM", NDR_WKSSVC_NETWKSTATRANSPORTENUM, api_wkssvc_NetWkstaTransportEnum},
+ {"WKSSVC_NETRWKSTATRANSPORTADD", NDR_WKSSVC_NETRWKSTATRANSPORTADD, api_wkssvc_NetrWkstaTransportAdd},
+ {"WKSSVC_NETRWKSTATRANSPORTDEL", NDR_WKSSVC_NETRWKSTATRANSPORTDEL, api_wkssvc_NetrWkstaTransportDel},
+ {"WKSSVC_NETRUSEADD", NDR_WKSSVC_NETRUSEADD, api_wkssvc_NetrUseAdd},
+ {"WKSSVC_NETRUSEGETINFO", NDR_WKSSVC_NETRUSEGETINFO, api_wkssvc_NetrUseGetInfo},
+ {"WKSSVC_NETRUSEDEL", NDR_WKSSVC_NETRUSEDEL, api_wkssvc_NetrUseDel},
+ {"WKSSVC_NETRUSEENUM", NDR_WKSSVC_NETRUSEENUM, api_wkssvc_NetrUseEnum},
+ {"WKSSVC_NETRMESSAGEBUFFERSEND", NDR_WKSSVC_NETRMESSAGEBUFFERSEND, api_wkssvc_NetrMessageBufferSend},
+ {"WKSSVC_NETRWORKSTATIONSTATISTICSGET", NDR_WKSSVC_NETRWORKSTATIONSTATISTICSGET, api_wkssvc_NetrWorkstationStatisticsGet},
+ {"WKSSVC_NETRLOGONDOMAINNAMEADD", NDR_WKSSVC_NETRLOGONDOMAINNAMEADD, api_wkssvc_NetrLogonDomainNameAdd},
+ {"WKSSVC_NETRLOGONDOMAINNAMEDEL", NDR_WKSSVC_NETRLOGONDOMAINNAMEDEL, api_wkssvc_NetrLogonDomainNameDel},
+ {"WKSSVC_NETRJOINDOMAIN", NDR_WKSSVC_NETRJOINDOMAIN, api_wkssvc_NetrJoinDomain},
+ {"WKSSVC_NETRUNJOINDOMAIN", NDR_WKSSVC_NETRUNJOINDOMAIN, api_wkssvc_NetrUnjoinDomain},
+ {"WKSSVC_NETRRENAMEMACHINEINDOMAIN", NDR_WKSSVC_NETRRENAMEMACHINEINDOMAIN, api_wkssvc_NetrRenameMachineInDomain},
+ {"WKSSVC_NETRVALIDATENAME", NDR_WKSSVC_NETRVALIDATENAME, api_wkssvc_NetrValidateName},
+ {"WKSSVC_NETRGETJOININFORMATION", NDR_WKSSVC_NETRGETJOININFORMATION, api_wkssvc_NetrGetJoinInformation},
+ {"WKSSVC_NETRGETJOINABLEOUS", NDR_WKSSVC_NETRGETJOINABLEOUS, api_wkssvc_NetrGetJoinableOus},
+ {"WKSSVC_NETRJOINDOMAIN2", NDR_WKSSVC_NETRJOINDOMAIN2, api_wkssvc_NetrJoinDomain2},
+ {"WKSSVC_NETRUNJOINDOMAIN2", NDR_WKSSVC_NETRUNJOINDOMAIN2, api_wkssvc_NetrUnjoinDomain2},
+ {"WKSSVC_NETRRENAMEMACHINEINDOMAIN2", NDR_WKSSVC_NETRRENAMEMACHINEINDOMAIN2, api_wkssvc_NetrRenameMachineInDomain2},
+ {"WKSSVC_NETRVALIDATENAME2", NDR_WKSSVC_NETRVALIDATENAME2, api_wkssvc_NetrValidateName2},
+ {"WKSSVC_NETRGETJOINABLEOUS2", NDR_WKSSVC_NETRGETJOINABLEOUS2, api_wkssvc_NetrGetJoinableOus2},
+ {"WKSSVC_NETRADDALTERNATECOMPUTERNAME", NDR_WKSSVC_NETRADDALTERNATECOMPUTERNAME, api_wkssvc_NetrAddAlternateComputerName},
+ {"WKSSVC_NETRREMOVEALTERNATECOMPUTERNAME", NDR_WKSSVC_NETRREMOVEALTERNATECOMPUTERNAME, api_wkssvc_NetrRemoveAlternateComputerName},
+ {"WKSSVC_NETRSETPRIMARYCOMPUTERNAME", NDR_WKSSVC_NETRSETPRIMARYCOMPUTERNAME, api_wkssvc_NetrSetPrimaryComputername},
+ {"WKSSVC_NETRENUMERATECOMPUTERNAMES", NDR_WKSSVC_NETRENUMERATECOMPUTERNAMES, api_wkssvc_NetrEnumerateComputerNames},
+};
+
+void wkssvc_get_pipe_fns(struct api_struct **fns, int *n_fns)
+{
+ *fns = api_wkssvc_cmds;
+ *n_fns = sizeof(api_wkssvc_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_wkssvc_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "wkssvc", "wkssvc", &ndr_table_wkssvc.syntax_id, api_wkssvc_cmds, sizeof(api_wkssvc_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/librpc/gen_ndr/srv_wkssvc.h b/source3/librpc/gen_ndr/srv_wkssvc.h
new file mode 100644
index 0000000000..f1d0b94c26
--- /dev/null
+++ b/source3/librpc/gen_ndr/srv_wkssvc.h
@@ -0,0 +1,37 @@
+#include "librpc/gen_ndr/ndr_wkssvc.h"
+#ifndef __SRV_WKSSVC__
+#define __SRV_WKSSVC__
+WERROR _wkssvc_NetWkstaGetInfo(pipes_struct *p, struct wkssvc_NetWkstaGetInfo *r);
+WERROR _wkssvc_NetWkstaSetInfo(pipes_struct *p, struct wkssvc_NetWkstaSetInfo *r);
+WERROR _wkssvc_NetWkstaEnumUsers(pipes_struct *p, struct wkssvc_NetWkstaEnumUsers *r);
+WERROR _wkssvc_NetrWkstaUserGetInfo(pipes_struct *p, struct wkssvc_NetrWkstaUserGetInfo *r);
+WERROR _wkssvc_NetrWkstaUserSetInfo(pipes_struct *p, struct wkssvc_NetrWkstaUserSetInfo *r);
+WERROR _wkssvc_NetWkstaTransportEnum(pipes_struct *p, struct wkssvc_NetWkstaTransportEnum *r);
+WERROR _wkssvc_NetrWkstaTransportAdd(pipes_struct *p, struct wkssvc_NetrWkstaTransportAdd *r);
+WERROR _wkssvc_NetrWkstaTransportDel(pipes_struct *p, struct wkssvc_NetrWkstaTransportDel *r);
+WERROR _wkssvc_NetrUseAdd(pipes_struct *p, struct wkssvc_NetrUseAdd *r);
+WERROR _wkssvc_NetrUseGetInfo(pipes_struct *p, struct wkssvc_NetrUseGetInfo *r);
+WERROR _wkssvc_NetrUseDel(pipes_struct *p, struct wkssvc_NetrUseDel *r);
+WERROR _wkssvc_NetrUseEnum(pipes_struct *p, struct wkssvc_NetrUseEnum *r);
+WERROR _wkssvc_NetrMessageBufferSend(pipes_struct *p, struct wkssvc_NetrMessageBufferSend *r);
+WERROR _wkssvc_NetrWorkstationStatisticsGet(pipes_struct *p, struct wkssvc_NetrWorkstationStatisticsGet *r);
+WERROR _wkssvc_NetrLogonDomainNameAdd(pipes_struct *p, struct wkssvc_NetrLogonDomainNameAdd *r);
+WERROR _wkssvc_NetrLogonDomainNameDel(pipes_struct *p, struct wkssvc_NetrLogonDomainNameDel *r);
+WERROR _wkssvc_NetrJoinDomain(pipes_struct *p, struct wkssvc_NetrJoinDomain *r);
+WERROR _wkssvc_NetrUnjoinDomain(pipes_struct *p, struct wkssvc_NetrUnjoinDomain *r);
+WERROR _wkssvc_NetrRenameMachineInDomain(pipes_struct *p, struct wkssvc_NetrRenameMachineInDomain *r);
+WERROR _wkssvc_NetrValidateName(pipes_struct *p, struct wkssvc_NetrValidateName *r);
+WERROR _wkssvc_NetrGetJoinInformation(pipes_struct *p, struct wkssvc_NetrGetJoinInformation *r);
+WERROR _wkssvc_NetrGetJoinableOus(pipes_struct *p, struct wkssvc_NetrGetJoinableOus *r);
+WERROR _wkssvc_NetrJoinDomain2(pipes_struct *p, struct wkssvc_NetrJoinDomain2 *r);
+WERROR _wkssvc_NetrUnjoinDomain2(pipes_struct *p, struct wkssvc_NetrUnjoinDomain2 *r);
+WERROR _wkssvc_NetrRenameMachineInDomain2(pipes_struct *p, struct wkssvc_NetrRenameMachineInDomain2 *r);
+WERROR _wkssvc_NetrValidateName2(pipes_struct *p, struct wkssvc_NetrValidateName2 *r);
+WERROR _wkssvc_NetrGetJoinableOus2(pipes_struct *p, struct wkssvc_NetrGetJoinableOus2 *r);
+WERROR _wkssvc_NetrAddAlternateComputerName(pipes_struct *p, struct wkssvc_NetrAddAlternateComputerName *r);
+WERROR _wkssvc_NetrRemoveAlternateComputerName(pipes_struct *p, struct wkssvc_NetrRemoveAlternateComputerName *r);
+WERROR _wkssvc_NetrSetPrimaryComputername(pipes_struct *p, struct wkssvc_NetrSetPrimaryComputername *r);
+WERROR _wkssvc_NetrEnumerateComputerNames(pipes_struct *p, struct wkssvc_NetrEnumerateComputerNames *r);
+void wkssvc_get_pipe_fns(struct api_struct **fns, int *n_fns);
+NTSTATUS rpc_wkssvc_init(void);
+#endif /* __SRV_WKSSVC__ */
diff --git a/source3/librpc/gen_ndr/srvsvc.h b/source3/librpc/gen_ndr/srvsvc.h
new file mode 100644
index 0000000000..8a2bbfb0a7
--- /dev/null
+++ b/source3/librpc/gen_ndr/srvsvc.h
@@ -0,0 +1,1793 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#include "librpc/gen_ndr/security.h"
+#include "librpc/gen_ndr/svcctl.h"
+#ifndef _HEADER_srvsvc
+#define _HEADER_srvsvc
+
+#define STYPE_TEMPORARY ( 0x40000000 )
+#define STYPE_HIDDEN ( 0x80000000 )
+#define SHARE_1005_CSC_POLICY_MASK ( 0x00000030 )
+#define SHARE_1005_CSC_POLICY_SHIFT ( 4 )
+struct srvsvc_NetCharDevInfo0 {
+ const char *device;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetCharDevCtr0 {
+ uint32_t count;
+ struct srvsvc_NetCharDevInfo0 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetCharDevInfo1 {
+ const char *device;/* [unique,charset(UTF16)] */
+ uint32_t status;
+ const char *user;/* [unique,charset(UTF16)] */
+ uint32_t time;
+};
+
+struct srvsvc_NetCharDevCtr1 {
+ uint32_t count;
+ struct srvsvc_NetCharDevInfo1 *array;/* [unique,size_is(count)] */
+};
+
+union srvsvc_NetCharDevInfo {
+ struct srvsvc_NetCharDevInfo0 *info0;/* [unique,case(0)] */
+ struct srvsvc_NetCharDevInfo1 *info1;/* [unique,case] */
+};
+
+union srvsvc_NetCharDevCtr {
+ struct srvsvc_NetCharDevCtr0 *ctr0;/* [unique,case(0)] */
+ struct srvsvc_NetCharDevCtr1 *ctr1;/* [unique,case] */
+};
+
+struct srvsvc_NetCharDevQInfo0 {
+ const char *device;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetCharDevQCtr0 {
+ uint32_t count;
+ struct srvsvc_NetCharDevQInfo0 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetCharDevQInfo1 {
+ const char *device;/* [unique,charset(UTF16)] */
+ uint32_t priority;
+ const char *devices;/* [unique,charset(UTF16)] */
+ uint32_t users;
+ uint32_t num_ahead;
+};
+
+struct srvsvc_NetCharDevQCtr1 {
+ uint32_t count;
+ struct srvsvc_NetCharDevQInfo1 *array;/* [unique,size_is(count)] */
+};
+
+union srvsvc_NetCharDevQInfo {
+ struct srvsvc_NetCharDevQInfo0 *info0;/* [unique,case(0)] */
+ struct srvsvc_NetCharDevQInfo1 *info1;/* [unique,case] */
+};
+
+union srvsvc_NetCharDevQCtr {
+ struct srvsvc_NetCharDevQCtr0 *ctr0;/* [unique,case(0)] */
+ struct srvsvc_NetCharDevQCtr1 *ctr1;/* [unique,case] */
+};
+
+struct srvsvc_NetConnInfo0 {
+ uint32_t conn_id;
+};
+
+struct srvsvc_NetConnCtr0 {
+ uint32_t count;
+ struct srvsvc_NetConnInfo0 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetConnInfo1 {
+ uint32_t conn_id;
+ uint32_t conn_type;
+ uint32_t num_open;
+ uint32_t num_users;
+ uint32_t conn_time;
+ const char *user;/* [unique,charset(UTF16)] */
+ const char *share;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetConnCtr1 {
+ uint32_t count;
+ struct srvsvc_NetConnInfo1 *array;/* [unique,size_is(count)] */
+};
+
+union srvsvc_NetConnCtr {
+ struct srvsvc_NetConnCtr0 *ctr0;/* [unique,case(0)] */
+ struct srvsvc_NetConnCtr1 *ctr1;/* [unique,case] */
+};
+
+struct srvsvc_NetConnInfoCtr {
+ uint32_t level;
+ union srvsvc_NetConnCtr ctr;/* [switch_is(level)] */
+};
+
+struct srvsvc_NetFileInfo2 {
+ uint32_t fid;
+};
+
+struct srvsvc_NetFileCtr2 {
+ uint32_t count;
+ struct srvsvc_NetFileInfo2 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetFileInfo3 {
+ uint32_t fid;
+ uint32_t permissions;
+ uint32_t num_locks;
+ const char *path;/* [unique,charset(UTF16)] */
+ const char *user;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetFileCtr3 {
+ uint32_t count;
+ struct srvsvc_NetFileInfo3 *array;/* [unique,size_is(count)] */
+};
+
+union srvsvc_NetFileInfo {
+ struct srvsvc_NetFileInfo2 *info2;/* [unique,case(2)] */
+ struct srvsvc_NetFileInfo3 *info3;/* [unique,case(3)] */
+};
+
+union srvsvc_NetFileCtr {
+ struct srvsvc_NetFileCtr2 *ctr2;/* [unique,case(2)] */
+ struct srvsvc_NetFileCtr3 *ctr3;/* [unique,case(3)] */
+};
+
+struct srvsvc_NetFileInfoCtr {
+ uint32_t level;
+ union srvsvc_NetFileCtr ctr;/* [switch_is(level)] */
+};
+
+struct srvsvc_NetSessInfo0 {
+ const char *client;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetSessCtr0 {
+ uint32_t count;
+ struct srvsvc_NetSessInfo0 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetSessInfo1 {
+ const char *client;/* [unique,charset(UTF16)] */
+ const char *user;/* [unique,charset(UTF16)] */
+ uint32_t num_open;
+ uint32_t time;
+ uint32_t idle_time;
+ uint32_t user_flags;
+};
+
+struct srvsvc_NetSessCtr1 {
+ uint32_t count;
+ struct srvsvc_NetSessInfo1 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetSessInfo2 {
+ const char *client;/* [unique,charset(UTF16)] */
+ const char *user;/* [unique,charset(UTF16)] */
+ uint32_t num_open;
+ uint32_t time;
+ uint32_t idle_time;
+ uint32_t user_flags;
+ const char *client_type;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetSessCtr2 {
+ uint32_t count;
+ struct srvsvc_NetSessInfo2 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetSessInfo10 {
+ const char *client;/* [unique,charset(UTF16)] */
+ const char *user;/* [unique,charset(UTF16)] */
+ uint32_t time;
+ uint32_t idle_time;
+};
+
+struct srvsvc_NetSessCtr10 {
+ uint32_t count;
+ struct srvsvc_NetSessInfo10 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetSessInfo502 {
+ const char *client;/* [unique,charset(UTF16)] */
+ const char *user;/* [unique,charset(UTF16)] */
+ uint32_t num_open;
+ uint32_t time;
+ uint32_t idle_time;
+ uint32_t user_flags;
+ const char *client_type;/* [unique,charset(UTF16)] */
+ const char *transport;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetSessCtr502 {
+ uint32_t count;
+ struct srvsvc_NetSessInfo502 *array;/* [unique,size_is(count)] */
+};
+
+union srvsvc_NetSessCtr {
+ struct srvsvc_NetSessCtr0 *ctr0;/* [unique,case(0)] */
+ struct srvsvc_NetSessCtr1 *ctr1;/* [unique,case] */
+ struct srvsvc_NetSessCtr2 *ctr2;/* [unique,case(2)] */
+ struct srvsvc_NetSessCtr10 *ctr10;/* [unique,case(10)] */
+ struct srvsvc_NetSessCtr502 *ctr502;/* [unique,case(502)] */
+};
+
+struct srvsvc_NetSessInfoCtr {
+ uint32_t level;
+ union srvsvc_NetSessCtr ctr;/* [switch_is(level)] */
+};
+
+enum srvsvc_ShareType
+#ifndef USE_UINT_ENUMS
+ {
+ STYPE_DISKTREE=0,
+ STYPE_DISKTREE_TEMPORARY=STYPE_DISKTREE|STYPE_TEMPORARY,
+ STYPE_DISKTREE_HIDDEN=STYPE_DISKTREE|STYPE_HIDDEN,
+ STYPE_PRINTQ=1,
+ STYPE_PRINTQ_TEMPORARY=STYPE_PRINTQ|STYPE_TEMPORARY,
+ STYPE_PRINTQ_HIDDEN=STYPE_PRINTQ|STYPE_HIDDEN,
+ STYPE_DEVICE=2,
+ STYPE_DEVICE_TEMPORARY=STYPE_DEVICE|STYPE_TEMPORARY,
+ STYPE_DEVICE_HIDDEN=STYPE_DEVICE|STYPE_HIDDEN,
+ STYPE_IPC=3,
+ STYPE_IPC_TEMPORARY=STYPE_IPC|STYPE_TEMPORARY,
+ STYPE_IPC_HIDDEN=STYPE_IPC|STYPE_HIDDEN
+}
+#else
+ { __donnot_use_enum_srvsvc_ShareType=0x7FFFFFFF}
+#define STYPE_DISKTREE ( 0 )
+#define STYPE_DISKTREE_TEMPORARY ( STYPE_DISKTREE|STYPE_TEMPORARY )
+#define STYPE_DISKTREE_HIDDEN ( STYPE_DISKTREE|STYPE_HIDDEN )
+#define STYPE_PRINTQ ( 1 )
+#define STYPE_PRINTQ_TEMPORARY ( STYPE_PRINTQ|STYPE_TEMPORARY )
+#define STYPE_PRINTQ_HIDDEN ( STYPE_PRINTQ|STYPE_HIDDEN )
+#define STYPE_DEVICE ( 2 )
+#define STYPE_DEVICE_TEMPORARY ( STYPE_DEVICE|STYPE_TEMPORARY )
+#define STYPE_DEVICE_HIDDEN ( STYPE_DEVICE|STYPE_HIDDEN )
+#define STYPE_IPC ( 3 )
+#define STYPE_IPC_TEMPORARY ( STYPE_IPC|STYPE_TEMPORARY )
+#define STYPE_IPC_HIDDEN ( STYPE_IPC|STYPE_HIDDEN )
+#endif
+;
+
+struct srvsvc_NetShareInfo0 {
+ const char *name;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetShareCtr0 {
+ uint32_t count;
+ struct srvsvc_NetShareInfo0 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetShareInfo1 {
+ const char *name;/* [unique,charset(UTF16)] */
+ enum srvsvc_ShareType type;
+ const char *comment;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetShareCtr1 {
+ uint32_t count;
+ struct srvsvc_NetShareInfo1 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetShareInfo2 {
+ const char *name;/* [unique,charset(UTF16)] */
+ enum srvsvc_ShareType type;
+ const char *comment;/* [unique,charset(UTF16)] */
+ uint32_t permissions;
+ uint32_t max_users;
+ uint32_t current_users;
+ const char *path;/* [unique,charset(UTF16)] */
+ const char *password;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetShareCtr2 {
+ uint32_t count;
+ struct srvsvc_NetShareInfo2 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetShareInfo501 {
+ const char *name;/* [unique,charset(UTF16)] */
+ enum srvsvc_ShareType type;
+ const char *comment;/* [unique,charset(UTF16)] */
+ uint32_t csc_policy;
+};
+
+struct srvsvc_NetShareCtr501 {
+ uint32_t count;
+ struct srvsvc_NetShareInfo501 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetShareInfo502 {
+ const char *name;/* [unique,charset(UTF16)] */
+ enum srvsvc_ShareType type;
+ const char *comment;/* [unique,charset(UTF16)] */
+ uint32_t permissions;
+ uint32_t max_users;
+ uint32_t current_users;
+ const char *path;/* [unique,charset(UTF16)] */
+ const char *password;/* [unique,charset(UTF16)] */
+ struct sec_desc_buf sd_buf;
+};
+
+struct srvsvc_NetShareCtr502 {
+ uint32_t count;
+ struct srvsvc_NetShareInfo502 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetShareInfo1004 {
+ const char *comment;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetShareCtr1004 {
+ uint32_t count;
+ struct srvsvc_NetShareInfo1004 *array;/* [unique,size_is(count)] */
+};
+
+/* bitmap NetShareInfo1005Flags */
+#define SHARE_1005_IN_DFS ( 0x00000001 )
+#define SHARE_1005_DFS_ROOT ( 0x00000002 )
+
+struct srvsvc_NetShareInfo1005 {
+ uint32_t dfs_flags;
+};
+
+struct srvsvc_NetShareCtr1005 {
+ uint32_t count;
+ struct srvsvc_NetShareInfo1005 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetShareInfo1006 {
+ uint32_t max_users;
+};
+
+struct srvsvc_NetShareCtr1006 {
+ uint32_t count;
+ struct srvsvc_NetShareInfo1006 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetShareInfo1007 {
+ uint32_t flags;
+ const char *alternate_directory_name;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetShareCtr1007 {
+ uint32_t count;
+ struct srvsvc_NetShareInfo1007 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetShareCtr1501 {
+ uint32_t count;
+ struct sec_desc_buf *array;/* [unique,size_is(count)] */
+};
+
+union srvsvc_NetShareInfo {
+ struct srvsvc_NetShareInfo0 *info0;/* [unique,case(0)] */
+ struct srvsvc_NetShareInfo1 *info1;/* [unique,case] */
+ struct srvsvc_NetShareInfo2 *info2;/* [unique,case(2)] */
+ struct srvsvc_NetShareInfo501 *info501;/* [unique,case(501)] */
+ struct srvsvc_NetShareInfo502 *info502;/* [unique,case(502)] */
+ struct srvsvc_NetShareInfo1004 *info1004;/* [unique,case(1004)] */
+ struct srvsvc_NetShareInfo1005 *info1005;/* [unique,case(1005)] */
+ struct srvsvc_NetShareInfo1006 *info1006;/* [unique,case(1006)] */
+ struct srvsvc_NetShareInfo1007 *info1007;/* [unique,case(1007)] */
+ struct sec_desc_buf *info1501;/* [unique,case(1501)] */
+};
+
+union srvsvc_NetShareCtr {
+ struct srvsvc_NetShareCtr0 *ctr0;/* [unique,case(0)] */
+ struct srvsvc_NetShareCtr1 *ctr1;/* [unique,case] */
+ struct srvsvc_NetShareCtr2 *ctr2;/* [unique,case(2)] */
+ struct srvsvc_NetShareCtr501 *ctr501;/* [unique,case(501)] */
+ struct srvsvc_NetShareCtr502 *ctr502;/* [unique,case(502)] */
+ struct srvsvc_NetShareCtr1004 *ctr1004;/* [unique,case(1004)] */
+ struct srvsvc_NetShareCtr1005 *ctr1005;/* [unique,case(1005)] */
+ struct srvsvc_NetShareCtr1006 *ctr1006;/* [unique,case(1006)] */
+ struct srvsvc_NetShareCtr1007 *ctr1007;/* [unique,case(1007)] */
+ struct srvsvc_NetShareCtr1501 *ctr1501;/* [unique,case(1501)] */
+};
+
+struct srvsvc_NetShareInfoCtr {
+ uint32_t level;
+ union srvsvc_NetShareCtr ctr;/* [switch_is(level)] */
+};
+
+enum srvsvc_PlatformId
+#ifndef USE_UINT_ENUMS
+ {
+ PLATFORM_ID_DOS=300,
+ PLATFORM_ID_OS2=400,
+ PLATFORM_ID_NT=500,
+ PLATFORM_ID_OSF=600,
+ PLATFORM_ID_VMS=700
+}
+#else
+ { __donnot_use_enum_srvsvc_PlatformId=0x7FFFFFFF}
+#define PLATFORM_ID_DOS ( 300 )
+#define PLATFORM_ID_OS2 ( 400 )
+#define PLATFORM_ID_NT ( 500 )
+#define PLATFORM_ID_OSF ( 600 )
+#define PLATFORM_ID_VMS ( 700 )
+#endif
+;
+
+struct srvsvc_NetSrvInfo100 {
+ enum srvsvc_PlatformId platform_id;
+ const char *server_name;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetSrvInfo101 {
+ enum srvsvc_PlatformId platform_id;
+ const char *server_name;/* [unique,charset(UTF16)] */
+ uint32_t version_major;
+ uint32_t version_minor;
+ uint32_t server_type;
+ const char *comment;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetSrvInfo102 {
+ enum srvsvc_PlatformId platform_id;
+ const char *server_name;/* [unique,charset(UTF16)] */
+ uint32_t version_major;
+ uint32_t version_minor;
+ uint32_t server_type;
+ const char *comment;/* [unique,charset(UTF16)] */
+ uint32_t users;
+ uint32_t disc;
+ uint32_t hidden;
+ uint32_t announce;
+ uint32_t anndelta;
+ uint32_t licenses;
+ const char *userpath;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetSrvInfo402 {
+ uint32_t ulist_mtime;
+ uint32_t glist_mtime;
+ uint32_t alist_mtime;
+ const char *alerts;/* [unique,charset(UTF16)] */
+ uint32_t security;
+ uint32_t numadmin;
+ uint32_t lanmask;
+ const char *guestaccount;/* [unique,charset(UTF16)] */
+ uint32_t chdevs;
+ uint32_t chdevqs;
+ uint32_t chdevjobs;
+ uint32_t connections;
+ uint32_t shares;
+ uint32_t openfiles;
+ uint32_t sessopen;
+ uint32_t sesssvc;
+ uint32_t sessreqs;
+ uint32_t opensearch;
+ uint32_t activelocks;
+ uint32_t sizereqbufs;
+ uint32_t numbigbufs;
+ uint32_t numfiletasks;
+ uint32_t alertsched;
+ uint32_t erroralert;
+ uint32_t logonalert;
+ uint32_t accessalert;
+ uint32_t diskalert;
+ uint32_t netioalert;
+ uint32_t maxaudits;
+ const char *srvheuristics;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetSrvInfo403 {
+ uint32_t ulist_mtime;
+ uint32_t glist_mtime;
+ uint32_t alist_mtime;
+ const char *alerts;/* [unique,charset(UTF16)] */
+ uint32_t security;
+ uint32_t numadmin;
+ uint32_t lanmask;
+ const char *guestaccount;/* [unique,charset(UTF16)] */
+ uint32_t chdevs;
+ uint32_t chdevqs;
+ uint32_t chdevjobs;
+ uint32_t connections;
+ uint32_t shares;
+ uint32_t openfiles;
+ uint32_t sessopen;
+ uint32_t sesssvc;
+ uint32_t sessreqs;
+ uint32_t opensearch;
+ uint32_t activelocks;
+ uint32_t sizereqbufs;
+ uint32_t numbigbufs;
+ uint32_t numfiletasks;
+ uint32_t alertsched;
+ uint32_t eroralert;
+ uint32_t logonalert;
+ uint32_t accessalert;
+ uint32_t diskalert;
+ uint32_t netioalert;
+ uint32_t maxaudits;
+ const char *srvheuristics;/* [unique,charset(UTF16)] */
+ uint32_t auditedevents;
+ uint32_t auditprofile;
+ const char *autopath;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetSrvInfo502 {
+ uint32_t sessopen;
+ uint32_t sesssvc;
+ uint32_t opensearch;
+ uint32_t sizereqbufs;
+ uint32_t initworkitems;
+ uint32_t maxworkitems;
+ uint32_t rawworkitems;
+ uint32_t irpstacksize;
+ uint32_t maxrawbuflen;
+ uint32_t sessusers;
+ uint32_t sessconns;
+ uint32_t maxpagedmemoryusage;
+ uint32_t maxnonpagedmemoryusage;
+ uint32_t enablesoftcompat;
+ uint32_t enableforcedlogoff;
+ uint32_t timesource;
+ uint32_t acceptdownlevelapis;
+ uint32_t lmannounce;
+};
+
+struct srvsvc_NetSrvInfo503 {
+ uint32_t sessopen;
+ uint32_t sesssvc;
+ uint32_t opensearch;
+ uint32_t sizereqbufs;
+ uint32_t initworkitems;
+ uint32_t maxworkitems;
+ uint32_t rawworkitems;
+ uint32_t irpstacksize;
+ uint32_t maxrawbuflen;
+ uint32_t sessusers;
+ uint32_t sessconns;
+ uint32_t maxpagedmemoryusage;
+ uint32_t maxnonpagedmemoryusage;
+ uint32_t enablesoftcompat;
+ uint32_t enableforcedlogoff;
+ uint32_t timesource;
+ uint32_t acceptdownlevelapis;
+ uint32_t lmannounce;
+ const char *domain;/* [unique,charset(UTF16)] */
+ uint32_t maxcopyreadlen;
+ uint32_t maxcopywritelen;
+ uint32_t minkeepsearch;
+ uint32_t maxkeepsearch;
+ uint32_t minkeepcomplsearch;
+ uint32_t maxkeepcomplsearch;
+ uint32_t threadcountadd;
+ uint32_t numlockthreads;
+ uint32_t scavtimeout;
+ uint32_t minrcvqueue;
+ uint32_t minfreeworkitems;
+ uint32_t xactmemsize;
+ uint32_t threadpriority;
+ uint32_t maxmpxct;
+ uint32_t oplockbreakwait;
+ uint32_t oplockbreakresponsewait;
+ uint32_t enableoplocks;
+ uint32_t enableoplockforceclose;
+ uint32_t enablefcbopens;
+ uint32_t enableraw;
+ uint32_t enablesharednetdrives;
+ uint32_t minfreeconnections;
+ uint32_t maxfreeconnections;
+};
+
+struct srvsvc_NetSrvInfo599 {
+ uint32_t sessopen;
+ uint32_t sesssvc;
+ uint32_t opensearch;
+ uint32_t sizereqbufs;
+ uint32_t initworkitems;
+ uint32_t maxworkitems;
+ uint32_t rawworkitems;
+ uint32_t irpstacksize;
+ uint32_t maxrawbuflen;
+ uint32_t sessusers;
+ uint32_t sessconns;
+ uint32_t maxpagedmemoryusage;
+ uint32_t maxnonpagedmemoryusage;
+ uint32_t enablesoftcompat;
+ uint32_t enableforcedlogoff;
+ uint32_t timesource;
+ uint32_t acceptdownlevelapis;
+ uint32_t lmannounce;
+ const char *domain;/* [unique,charset(UTF16)] */
+ uint32_t maxcopyreadlen;
+ uint32_t maxcopywritelen;
+ uint32_t minkeepsearch;
+ uint32_t minkeepcomplsearch;
+ uint32_t maxkeepcomplsearch;
+ uint32_t threadcountadd;
+ uint32_t numlockthreads;
+ uint32_t scavtimeout;
+ uint32_t minrcvqueue;
+ uint32_t minfreeworkitems;
+ uint32_t xactmemsize;
+ uint32_t threadpriority;
+ uint32_t maxmpxct;
+ uint32_t oplockbreakwait;
+ uint32_t oplockbreakresponsewait;
+ uint32_t enableoplocks;
+ uint32_t enableoplockforceclose;
+ uint32_t enablefcbopens;
+ uint32_t enableraw;
+ uint32_t enablesharednetdrives;
+ uint32_t minfreeconnections;
+ uint32_t maxfreeconnections;
+ uint32_t initsesstable;
+ uint32_t initconntable;
+ uint32_t initfiletable;
+ uint32_t initsearchtable;
+ uint32_t alertsched;
+ uint32_t errortreshold;
+ uint32_t networkerrortreshold;
+ uint32_t diskspacetreshold;
+ uint32_t reserved;
+ uint32_t maxlinkdelay;
+ uint32_t minlinkthroughput;
+ uint32_t linkinfovalidtime;
+ uint32_t scavqosinfoupdatetime;
+ uint32_t maxworkitemidletime;
+};
+
+struct srvsvc_NetSrvInfo1005 {
+ const char *comment;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetSrvInfo1010 {
+ uint32_t disc;
+};
+
+struct srvsvc_NetSrvInfo1016 {
+ uint32_t hidden;
+};
+
+struct srvsvc_NetSrvInfo1017 {
+ uint32_t announce;
+};
+
+struct srvsvc_NetSrvInfo1018 {
+ uint32_t anndelta;
+};
+
+struct srvsvc_NetSrvInfo1107 {
+ uint32_t users;
+};
+
+struct srvsvc_NetSrvInfo1501 {
+ uint32_t sessopens;
+};
+
+struct srvsvc_NetSrvInfo1502 {
+ uint32_t sessvcs;
+};
+
+struct srvsvc_NetSrvInfo1503 {
+ uint32_t opensearch;
+};
+
+struct srvsvc_NetSrvInfo1506 {
+ uint32_t maxworkitems;
+};
+
+struct srvsvc_NetSrvInfo1509 {
+ uint32_t maxrawbuflen;
+};
+
+struct srvsvc_NetSrvInfo1510 {
+ uint32_t sessusers;
+};
+
+struct srvsvc_NetSrvInfo1511 {
+ uint32_t sesscons;
+};
+
+struct srvsvc_NetSrvInfo1512 {
+ uint32_t maxnonpagedmemoryusage;
+};
+
+struct srvsvc_NetSrvInfo1513 {
+ uint32_t maxpagedmemoryusage;
+};
+
+struct srvsvc_NetSrvInfo1514 {
+ uint32_t enablesoftcompat;
+};
+
+struct srvsvc_NetSrvInfo1515 {
+ uint32_t enableforcedlogoff;
+};
+
+struct srvsvc_NetSrvInfo1516 {
+ uint32_t timesource;
+};
+
+struct srvsvc_NetSrvInfo1518 {
+ uint32_t lmannounce;
+};
+
+struct srvsvc_NetSrvInfo1520 {
+ uint32_t maxcopyreadlen;
+};
+
+struct srvsvc_NetSrvInfo1521 {
+ uint32_t maxcopywritelen;
+};
+
+struct srvsvc_NetSrvInfo1522 {
+ uint32_t minkeepsearch;
+};
+
+struct srvsvc_NetSrvInfo1523 {
+ uint32_t maxkeepsearch;
+};
+
+struct srvsvc_NetSrvInfo1524 {
+ uint32_t minkeepcomplsearch;
+};
+
+struct srvsvc_NetSrvInfo1525 {
+ uint32_t maxkeepcomplsearch;
+};
+
+struct srvsvc_NetSrvInfo1528 {
+ uint32_t scavtimeout;
+};
+
+struct srvsvc_NetSrvInfo1529 {
+ uint32_t minrcvqueue;
+};
+
+struct srvsvc_NetSrvInfo1530 {
+ uint32_t minfreeworkitems;
+};
+
+struct srvsvc_NetSrvInfo1533 {
+ uint32_t maxmpxct;
+};
+
+struct srvsvc_NetSrvInfo1534 {
+ uint32_t oplockbreakwait;
+};
+
+struct srvsvc_NetSrvInfo1535 {
+ uint32_t oplockbreakresponsewait;
+};
+
+struct srvsvc_NetSrvInfo1536 {
+ uint32_t enableoplocks;
+};
+
+struct srvsvc_NetSrvInfo1537 {
+ uint32_t enableoplockforceclose;
+};
+
+struct srvsvc_NetSrvInfo1538 {
+ uint32_t enablefcbopens;
+};
+
+struct srvsvc_NetSrvInfo1539 {
+ uint32_t enableraw;
+};
+
+struct srvsvc_NetSrvInfo1540 {
+ uint32_t enablesharednetdrives;
+};
+
+struct srvsvc_NetSrvInfo1541 {
+ uint32_t minfreeconnections;
+};
+
+struct srvsvc_NetSrvInfo1542 {
+ uint32_t maxfreeconnections;
+};
+
+struct srvsvc_NetSrvInfo1543 {
+ uint32_t initsesstable;
+};
+
+struct srvsvc_NetSrvInfo1544 {
+ uint32_t initconntable;
+};
+
+struct srvsvc_NetSrvInfo1545 {
+ uint32_t initfiletable;
+};
+
+struct srvsvc_NetSrvInfo1546 {
+ uint32_t initsearchtable;
+};
+
+struct srvsvc_NetSrvInfo1547 {
+ uint32_t alertsched;
+};
+
+struct srvsvc_NetSrvInfo1548 {
+ uint32_t errortreshold;
+};
+
+struct srvsvc_NetSrvInfo1549 {
+ uint32_t networkerrortreshold;
+};
+
+struct srvsvc_NetSrvInfo1550 {
+ uint32_t diskspacetreshold;
+};
+
+struct srvsvc_NetSrvInfo1552 {
+ uint32_t maxlinkdelay;
+};
+
+struct srvsvc_NetSrvInfo1553 {
+ uint32_t minlinkthroughput;
+};
+
+struct srvsvc_NetSrvInfo1554 {
+ uint32_t linkinfovalidtime;
+};
+
+struct srvsvc_NetSrvInfo1555 {
+ uint32_t scavqosinfoupdatetime;
+};
+
+struct srvsvc_NetSrvInfo1556 {
+ uint32_t maxworkitemidletime;
+};
+
+union srvsvc_NetSrvInfo {
+ struct srvsvc_NetSrvInfo100 *info100;/* [unique,case(100)] */
+ struct srvsvc_NetSrvInfo101 *info101;/* [unique,case(101)] */
+ struct srvsvc_NetSrvInfo102 *info102;/* [unique,case(102)] */
+ struct srvsvc_NetSrvInfo402 *info402;/* [unique,case(402)] */
+ struct srvsvc_NetSrvInfo403 *info403;/* [unique,case(403)] */
+ struct srvsvc_NetSrvInfo502 *info502;/* [unique,case(502)] */
+ struct srvsvc_NetSrvInfo503 *info503;/* [unique,case(503)] */
+ struct srvsvc_NetSrvInfo599 *info599;/* [unique,case(599)] */
+ struct srvsvc_NetSrvInfo1005 *info1005;/* [unique,case(1005)] */
+ struct srvsvc_NetSrvInfo1010 *info1010;/* [unique,case(1010)] */
+ struct srvsvc_NetSrvInfo1016 *info1016;/* [unique,case(1016)] */
+ struct srvsvc_NetSrvInfo1017 *info1017;/* [unique,case(1017)] */
+ struct srvsvc_NetSrvInfo1018 *info1018;/* [unique,case(1018)] */
+ struct srvsvc_NetSrvInfo1107 *info1107;/* [unique,case(1107)] */
+ struct srvsvc_NetSrvInfo1501 *info1501;/* [unique,case(1501)] */
+ struct srvsvc_NetSrvInfo1502 *info1502;/* [unique,case(1502)] */
+ struct srvsvc_NetSrvInfo1503 *info1503;/* [unique,case(1503)] */
+ struct srvsvc_NetSrvInfo1506 *info1506;/* [unique,case(1506)] */
+ struct srvsvc_NetSrvInfo1509 *info1509;/* [unique,case(1509)] */
+ struct srvsvc_NetSrvInfo1510 *info1510;/* [unique,case(1510)] */
+ struct srvsvc_NetSrvInfo1511 *info1511;/* [unique,case(1511)] */
+ struct srvsvc_NetSrvInfo1512 *info1512;/* [unique,case(1512)] */
+ struct srvsvc_NetSrvInfo1513 *info1513;/* [unique,case(1513)] */
+ struct srvsvc_NetSrvInfo1514 *info1514;/* [unique,case(1514)] */
+ struct srvsvc_NetSrvInfo1515 *info1515;/* [unique,case(1515)] */
+ struct srvsvc_NetSrvInfo1516 *info1516;/* [unique,case(1516)] */
+ struct srvsvc_NetSrvInfo1518 *info1518;/* [unique,case(1518)] */
+ struct srvsvc_NetSrvInfo1520 *info1520;/* [unique,case(1520)] */
+ struct srvsvc_NetSrvInfo1521 *info1521;/* [unique,case(1521)] */
+ struct srvsvc_NetSrvInfo1522 *info1522;/* [unique,case(1522)] */
+ struct srvsvc_NetSrvInfo1523 *info1523;/* [unique,case(1523)] */
+ struct srvsvc_NetSrvInfo1524 *info1524;/* [unique,case(1524)] */
+ struct srvsvc_NetSrvInfo1525 *info1525;/* [unique,case(1525)] */
+ struct srvsvc_NetSrvInfo1528 *info1528;/* [unique,case(1528)] */
+ struct srvsvc_NetSrvInfo1529 *info1529;/* [unique,case(1529)] */
+ struct srvsvc_NetSrvInfo1530 *info1530;/* [unique,case(1530)] */
+ struct srvsvc_NetSrvInfo1533 *info1533;/* [unique,case(1533)] */
+ struct srvsvc_NetSrvInfo1534 *info1534;/* [unique,case(1534)] */
+ struct srvsvc_NetSrvInfo1535 *info1535;/* [unique,case(1535)] */
+ struct srvsvc_NetSrvInfo1536 *info1536;/* [unique,case(1536)] */
+ struct srvsvc_NetSrvInfo1537 *info1537;/* [unique,case(1537)] */
+ struct srvsvc_NetSrvInfo1538 *info1538;/* [unique,case(1538)] */
+ struct srvsvc_NetSrvInfo1539 *info1539;/* [unique,case(1539)] */
+ struct srvsvc_NetSrvInfo1540 *info1540;/* [unique,case(1540)] */
+ struct srvsvc_NetSrvInfo1541 *info1541;/* [unique,case(1541)] */
+ struct srvsvc_NetSrvInfo1542 *info1542;/* [unique,case(1542)] */
+ struct srvsvc_NetSrvInfo1543 *info1543;/* [unique,case(1543)] */
+ struct srvsvc_NetSrvInfo1544 *info1544;/* [unique,case(1544)] */
+ struct srvsvc_NetSrvInfo1545 *info1545;/* [unique,case(1545)] */
+ struct srvsvc_NetSrvInfo1546 *info1546;/* [unique,case(1546)] */
+ struct srvsvc_NetSrvInfo1547 *info1547;/* [unique,case(1547)] */
+ struct srvsvc_NetSrvInfo1548 *info1548;/* [unique,case(1548)] */
+ struct srvsvc_NetSrvInfo1549 *info1549;/* [unique,case(1549)] */
+ struct srvsvc_NetSrvInfo1550 *info1550;/* [unique,case(1550)] */
+ struct srvsvc_NetSrvInfo1552 *info1552;/* [unique,case(1552)] */
+ struct srvsvc_NetSrvInfo1553 *info1553;/* [unique,case(1553)] */
+ struct srvsvc_NetSrvInfo1554 *info1554;/* [unique,case(1554)] */
+ struct srvsvc_NetSrvInfo1555 *info1555;/* [unique,case(1555)] */
+ struct srvsvc_NetSrvInfo1556 *info1556;/* [unique,case(1556)] */
+};
+
+struct srvsvc_NetDiskInfo0 {
+ const char * disk;/* [flag(LIBNDR_FLAG_STR_LEN4)] */
+};
+
+struct srvsvc_NetDiskInfo {
+ uint32_t count;
+ struct srvsvc_NetDiskInfo0 *disks;/* [unique,length_is(count),size_is(count)] */
+};
+
+struct srvsvc_Statistics {
+ uint32_t start;
+ uint32_t fopens;
+ uint32_t devopens;
+ uint32_t jobsqueued;
+ uint32_t sopens;
+ uint32_t stimeouts;
+ uint32_t serrorout;
+ uint32_t pwerrors;
+ uint32_t permerrors;
+ uint32_t syserrors;
+ uint32_t bytessent_low;
+ uint32_t bytessent_high;
+ uint32_t bytesrcvd_low;
+ uint32_t bytesrcvd_high;
+ uint32_t avresponse;
+ uint32_t reqbufneed;
+ uint32_t bigbufneed;
+};
+
+struct srvsvc_NetTransportInfo0 {
+ uint32_t vcs;
+ const char *name;/* [unique,charset(UTF16)] */
+ uint8_t *addr;/* [unique,size_is(addr_len)] */
+ uint32_t addr_len;
+ const char *net_addr;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetTransportCtr0 {
+ uint32_t count;
+ struct srvsvc_NetTransportInfo0 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetTransportInfo1 {
+ uint32_t vcs;
+ const char *name;/* [unique,charset(UTF16)] */
+ uint8_t *addr;/* [unique,size_is(addr_len)] */
+ uint32_t addr_len;
+ const char *net_addr;/* [unique,charset(UTF16)] */
+ const char *domain;/* [unique,charset(UTF16)] */
+};
+
+struct srvsvc_NetTransportCtr1 {
+ uint32_t count;
+ struct srvsvc_NetTransportInfo1 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetTransportInfo2 {
+ uint32_t vcs;
+ const char *name;/* [unique,charset(UTF16)] */
+ uint8_t *addr;/* [unique,size_is(addr_len)] */
+ uint32_t addr_len;
+ const char *net_addr;/* [unique,charset(UTF16)] */
+ const char *domain;/* [unique,charset(UTF16)] */
+ uint32_t unknown;
+};
+
+struct srvsvc_NetTransportCtr2 {
+ uint32_t count;
+ struct srvsvc_NetTransportInfo2 *array;/* [unique,size_is(count)] */
+};
+
+struct srvsvc_NetTransportInfo3 {
+ uint32_t vcs;
+ const char *name;/* [unique,charset(UTF16)] */
+ uint8_t *addr;/* [unique,size_is(addr_len)] */
+ uint32_t addr_len;
+ const char *net_addr;/* [unique,charset(UTF16)] */
+ const char *domain;/* [unique,charset(UTF16)] */
+ uint32_t unknown1;
+ uint32_t unknown2;
+ uint8_t unknown3[256];
+};
+
+struct srvsvc_NetTransportCtr3 {
+ uint32_t count;
+ struct srvsvc_NetTransportInfo3 *array;/* [unique,size_is(count)] */
+};
+
+union srvsvc_NetTransportCtr {
+ struct srvsvc_NetTransportCtr0 *ctr0;/* [unique,case(0)] */
+ struct srvsvc_NetTransportCtr1 *ctr1;/* [unique,case] */
+ struct srvsvc_NetTransportCtr2 *ctr2;/* [unique,case(2)] */
+ struct srvsvc_NetTransportCtr3 *ctr3;/* [unique,case(3)] */
+};
+
+struct srvsvc_NetRemoteTODInfo {
+ uint32_t elapsed;
+ uint32_t msecs;
+ uint32_t hours;
+ uint32_t mins;
+ uint32_t secs;
+ uint32_t hunds;
+ int32_t timezone;
+ uint32_t tinterval;
+ uint32_t day;
+ uint32_t month;
+ uint32_t year;
+ uint32_t weekday;
+};
+
+union srvsvc_NetTransportInfo {
+ struct srvsvc_NetTransportInfo0 info0;/* [case(0)] */
+ struct srvsvc_NetTransportInfo1 info1;/* [case] */
+ struct srvsvc_NetTransportInfo2 info2;/* [case(2)] */
+ struct srvsvc_NetTransportInfo3 info3;/* [case(3)] */
+}/* [switch_type(uint32)] */;
+
+
+struct srvsvc_NetCharDevEnum {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ uint32_t max_buffer;
+ uint32_t *level;/* [ref] */
+ union srvsvc_NetCharDevCtr *ctr;/* [ref,switch_is(*level)] */
+ uint32_t *resume_handle;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *totalentries;/* [ref] */
+ uint32_t *level;/* [ref] */
+ union srvsvc_NetCharDevCtr *ctr;/* [ref,switch_is(*level)] */
+ uint32_t *resume_handle;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetCharDevGetInfo {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *device_name;/* [charset(UTF16)] */
+ uint32_t level;
+ } in;
+
+ struct {
+ union srvsvc_NetCharDevInfo *info;/* [ref,switch_is(level)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetCharDevControl {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *device_name;/* [charset(UTF16)] */
+ uint32_t opcode;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetCharDevQEnum {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *user;/* [unique,charset(UTF16)] */
+ uint32_t max_buffer;
+ uint32_t *level;/* [ref] */
+ union srvsvc_NetCharDevQCtr *ctr;/* [ref,switch_is(*level)] */
+ uint32_t *resume_handle;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *totalentries;/* [ref] */
+ uint32_t *level;/* [ref] */
+ union srvsvc_NetCharDevQCtr *ctr;/* [ref,switch_is(*level)] */
+ uint32_t *resume_handle;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetCharDevQGetInfo {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *queue_name;/* [charset(UTF16)] */
+ const char *user;/* [charset(UTF16)] */
+ uint32_t level;
+ } in;
+
+ struct {
+ union srvsvc_NetCharDevQInfo *info;/* [ref,switch_is(level)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetCharDevQSetInfo {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *queue_name;/* [charset(UTF16)] */
+ uint32_t level;
+ union srvsvc_NetCharDevQInfo info;/* [switch_is(level)] */
+ uint32_t *parm_error;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *parm_error;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetCharDevQPurge {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *queue_name;/* [charset(UTF16)] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetCharDevQPurgeSelf {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *queue_name;/* [charset(UTF16)] */
+ const char *computer_name;/* [charset(UTF16)] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetConnEnum {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *path;/* [unique,charset(UTF16)] */
+ uint32_t max_buffer;
+ struct srvsvc_NetConnInfoCtr *info_ctr;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *totalentries;/* [ref] */
+ struct srvsvc_NetConnInfoCtr *info_ctr;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetFileEnum {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *path;/* [unique,charset(UTF16)] */
+ const char *user;/* [unique,charset(UTF16)] */
+ uint32_t max_buffer;
+ struct srvsvc_NetFileInfoCtr *info_ctr;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *totalentries;/* [ref] */
+ struct srvsvc_NetFileInfoCtr *info_ctr;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetFileGetInfo {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ uint32_t fid;
+ uint32_t level;
+ } in;
+
+ struct {
+ union srvsvc_NetFileInfo *info;/* [ref,switch_is(level)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetFileClose {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ uint32_t fid;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetSessEnum {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *client;/* [unique,charset(UTF16)] */
+ const char *user;/* [unique,charset(UTF16)] */
+ uint32_t max_buffer;
+ struct srvsvc_NetSessInfoCtr *info_ctr;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *totalentries;/* [ref] */
+ struct srvsvc_NetSessInfoCtr *info_ctr;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetSessDel {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *client;/* [unique,charset(UTF16)] */
+ const char *user;/* [unique,charset(UTF16)] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetShareAdd {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ uint32_t level;
+ union srvsvc_NetShareInfo *info;/* [ref,switch_is(level)] */
+ uint32_t *parm_error;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *parm_error;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetShareEnumAll {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ uint32_t max_buffer;
+ struct srvsvc_NetShareInfoCtr *info_ctr;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *totalentries;/* [ref] */
+ struct srvsvc_NetShareInfoCtr *info_ctr;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetShareGetInfo {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *share_name;/* [charset(UTF16)] */
+ uint32_t level;
+ } in;
+
+ struct {
+ union srvsvc_NetShareInfo *info;/* [ref,switch_is(level)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetShareSetInfo {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *share_name;/* [charset(UTF16)] */
+ uint32_t level;
+ union srvsvc_NetShareInfo *info;/* [ref,switch_is(level)] */
+ uint32_t *parm_error;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *parm_error;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetShareDel {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *share_name;/* [charset(UTF16)] */
+ uint32_t reserved;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetShareDelSticky {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *share_name;/* [charset(UTF16)] */
+ uint32_t reserved;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetShareCheck {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *device_name;/* [charset(UTF16)] */
+ } in;
+
+ struct {
+ enum srvsvc_ShareType *type;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetSrvGetInfo {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ uint32_t level;
+ } in;
+
+ struct {
+ union srvsvc_NetSrvInfo *info;/* [ref,switch_is(level)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetSrvSetInfo {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ uint32_t level;
+ union srvsvc_NetSrvInfo *info;/* [ref,switch_is(level)] */
+ uint32_t *parm_error;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *parm_error;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetDiskEnum {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ uint32_t level;
+ uint32_t maxlen;
+ struct srvsvc_NetDiskInfo *info;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *totalentries;/* [ref] */
+ struct srvsvc_NetDiskInfo *info;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetServerStatisticsGet {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *service;/* [unique,charset(UTF16)] */
+ uint32_t level;
+ uint32_t options;
+ } in;
+
+ struct {
+ struct srvsvc_Statistics *stats;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetTransportAdd {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ uint32_t level;
+ union srvsvc_NetTransportInfo info;/* [switch_is(level)] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetTransportEnum {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ uint32_t max_buffer;
+ uint32_t *level;/* [ref] */
+ union srvsvc_NetTransportCtr *transports;/* [ref,switch_is(*level)] */
+ uint32_t *resume_handle;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *totalentries;/* [ref] */
+ uint32_t *level;/* [ref] */
+ union srvsvc_NetTransportCtr *transports;/* [ref,switch_is(*level)] */
+ uint32_t *resume_handle;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetTransportDel {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ uint32_t unknown;
+ struct srvsvc_NetTransportInfo0 transport;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetRemoteTOD {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ } in;
+
+ struct {
+ struct srvsvc_NetRemoteTODInfo **info;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetSetServiceBits {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *transport;/* [unique,charset(UTF16)] */
+ uint32_t servicebits;
+ uint32_t updateimmediately;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetPathType {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *path;/* [charset(UTF16)] */
+ uint32_t pathflags;
+ } in;
+
+ struct {
+ uint32_t *pathtype;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetPathCanonicalize {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *path;/* [charset(UTF16)] */
+ uint32_t maxbuf;
+ const char *prefix;/* [charset(UTF16)] */
+ uint32_t pathflags;
+ uint32_t *pathtype;/* [ref] */
+ } in;
+
+ struct {
+ uint8_t *can_path;/* [size_is(maxbuf)] */
+ uint32_t *pathtype;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetPathCompare {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *path1;/* [charset(UTF16)] */
+ const char *path2;/* [charset(UTF16)] */
+ uint32_t pathtype;
+ uint32_t pathflags;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetNameValidate {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *name;/* [charset(UTF16)] */
+ uint32_t name_type;
+ uint32_t flags;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NETRPRNAMECANONICALIZE {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetPRNameCompare {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *name1;/* [charset(UTF16)] */
+ const char *name2;/* [charset(UTF16)] */
+ uint32_t name_type;
+ uint32_t flags;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetShareEnum {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ uint32_t max_buffer;
+ struct srvsvc_NetShareInfoCtr *info_ctr;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *totalentries;/* [ref] */
+ struct srvsvc_NetShareInfoCtr *info_ctr;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetShareDelStart {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *share;/* [charset(UTF16)] */
+ uint32_t reserved;
+ } in;
+
+ struct {
+ struct policy_handle *hnd;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetShareDelCommit {
+ struct {
+ struct policy_handle *hnd;/* [unique] */
+ } in;
+
+ struct {
+ struct policy_handle *hnd;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetGetFileSecurity {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *share;/* [unique,charset(UTF16)] */
+ const char *file;/* [charset(UTF16)] */
+ uint32_t securityinformation;
+ } in;
+
+ struct {
+ struct sec_desc_buf **sd_buf;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetSetFileSecurity {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *share;/* [unique,charset(UTF16)] */
+ const char *file;/* [charset(UTF16)] */
+ uint32_t securityinformation;
+ struct sec_desc_buf *sd_buf;/* [ref] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetServerTransportAddEx {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ uint32_t level;
+ union srvsvc_NetTransportInfo info;/* [switch_is(level)] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NetServerSetServiceBitsEx {
+ struct {
+ const char *server_unc;/* [unique,charset(UTF16)] */
+ const char *emulated_server_unc;/* [unique,charset(UTF16)] */
+ const char *transport;/* [unique,charset(UTF16)] */
+ uint32_t servicebitsofinterest;
+ uint32_t servicebits;
+ uint32_t updateimmediately;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NETRDFSGETVERSION {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NETRDFSCREATELOCALPARTITION {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NETRDFSDELETELOCALPARTITION {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NETRDFSSETLOCALVOLUMESTATE {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NETRDFSSETSERVERINFO {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NETRDFSCREATEEXITPOINT {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NETRDFSDELETEEXITPOINT {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NETRDFSMODIFYPREFIX {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NETRDFSFIXLOCALVOLUME {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NETRDFSMANAGERREPORTSITEINFO {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct srvsvc_NETRSERVERTRANSPORTDELEX {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+#endif /* _HEADER_srvsvc */
diff --git a/source3/librpc/gen_ndr/svcctl.h b/source3/librpc/gen_ndr/svcctl.h
new file mode 100644
index 0000000000..d4135d2ddb
--- /dev/null
+++ b/source3/librpc/gen_ndr/svcctl.h
@@ -0,0 +1,781 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#ifndef _HEADER_svcctl
+#define _HEADER_svcctl
+
+#define SERVICE_TYPE_KERNEL_DRIVER ( 0x01 )
+#define SERVICE_TYPE_FS_DRIVER ( 0x02 )
+#define SERVICE_TYPE_ADAPTER ( 0x04 )
+#define SERVICE_TYPE_RECOGNIZER_DRIVER ( 0x08 )
+#define SERVICE_TYPE_DRIVER ( SERVICE_TYPE_KERNEL_DRIVER|SERVICE_TYPE_FS_DRIVER|SERVICE_TYPE_RECOGNIZER_DRIVER )
+#define SERVICE_TYPE_WIN32_OWN_PROCESS ( 0x10 )
+#define SERVICE_TYPE_WIN32_SHARE_PROCESS ( 0x20 )
+#define SERVICE_TYPE_WIN32 ( SERVICE_TYPE_WIN32_OWN_PROCESS|SERVICE_TYPE_WIN32_SHARE_PROCESS )
+#define SERVICE_STATE_ACTIVE ( 0x01 )
+#define SERVICE_STATE_INACTIVE ( 0x02 )
+#define SERVICE_STATE_ALL ( 0x03 )
+#define SV_TYPE_ALL ( 0xFFFFFFFF )
+struct SERVICE_LOCK_STATUS {
+ uint32_t is_locked;
+ const char *lock_owner;/* [unique,charset(UTF16)] */
+ uint32_t lock_duration;
+};
+
+struct SERVICE_STATUS {
+ uint32_t type;
+ uint32_t state;
+ uint32_t controls_accepted;
+ WERROR win32_exit_code;
+ uint32_t service_exit_code;
+ uint32_t check_point;
+ uint32_t wait_hint;
+};
+
+struct ENUM_SERVICE_STATUS {
+ const char * service_name;/* [relative,flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+ const char * display_name;/* [relative,flag(LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM)] */
+ struct SERVICE_STATUS status;
+};
+
+/* bitmap svcctl_ServerType */
+#define SV_TYPE_WORKSTATION ( 0x00000001 )
+#define SV_TYPE_SERVER ( 0x00000002 )
+#define SV_TYPE_SQLSERVER ( 0x00000004 )
+#define SV_TYPE_DOMAIN_CTRL ( 0x00000008 )
+#define SV_TYPE_DOMAIN_BAKCTRL ( 0x00000010 )
+#define SV_TYPE_TIME_SOURCE ( 0x00000020 )
+#define SV_TYPE_AFP ( 0x00000040 )
+#define SV_TYPE_NOVELL ( 0x00000080 )
+#define SV_TYPE_DOMAIN_MEMBER ( 0x00000100 )
+#define SV_TYPE_PRINTQ_SERVER ( 0x00000200 )
+#define SV_TYPE_DIALIN_SERVER ( 0x00000400 )
+#define SV_TYPE_SERVER_UNIX ( 0x00000800 )
+#define SV_TYPE_NT ( 0x00001000 )
+#define SV_TYPE_WFW ( 0x00002000 )
+#define SV_TYPE_SERVER_MFPN ( 0x00004000 )
+#define SV_TYPE_SERVER_NT ( 0x00008000 )
+#define SV_TYPE_POTENTIAL_BROWSER ( 0x00010000 )
+#define SV_TYPE_BACKUP_BROWSER ( 0x00020000 )
+#define SV_TYPE_MASTER_BROWSER ( 0x00040000 )
+#define SV_TYPE_DOMAIN_MASTER ( 0x00080000 )
+#define SV_TYPE_SERVER_OSF ( 0x00100000 )
+#define SV_TYPE_SERVER_VMS ( 0x00200000 )
+#define SV_TYPE_WIN95_PLUS ( 0x00400000 )
+#define SV_TYPE_DFS_SERVER ( 0x00800000 )
+#define SV_TYPE_ALTERNATE_XPORT ( 0x20000000 )
+#define SV_TYPE_LOCAL_LIST_ONLY ( 0x40000000 )
+#define SV_TYPE_DOMAIN_ENUM ( 0x80000000 )
+
+enum SERVICE_CONTROL
+#ifndef USE_UINT_ENUMS
+ {
+ FIXME=1
+}
+#else
+ { __donnot_use_enum_SERVICE_CONTROL=0x7FFFFFFF}
+#define FIXME ( 1 )
+#endif
+;
+
+/* bitmap svcctl_MgrAccessMask */
+#define SC_RIGHT_MGR_CONNECT ( 0x0001 )
+#define SC_RIGHT_MGR_CREATE_SERVICE ( 0x0002 )
+#define SC_RIGHT_MGR_ENUMERATE_SERVICE ( 0x0004 )
+#define SC_RIGHT_MGR_LOCK ( 0x0008 )
+#define SC_RIGHT_MGR_QUERY_LOCK_STATUS ( 0x0010 )
+#define SC_RIGHT_MGR_MODIFY_BOOT_CONFIG ( 0x0020 )
+
+/* bitmap svcctl_ServiceAccessMask */
+#define SC_RIGHT_SVC_QUERY_CONFIG ( 0x0001 )
+#define SC_RIGHT_SVC_CHANGE_CONFIG ( 0x0002 )
+#define SC_RIGHT_SVC_QUERY_STATUS ( 0x0004 )
+#define SC_RIGHT_SVC_ENUMERATE_DEPENDENTS ( 0x0008 )
+#define SC_RIGHT_SVC_START ( 0x0010 )
+#define SC_RIGHT_SVC_STOP ( 0x0020 )
+#define SC_RIGHT_SVC_PAUSE_CONTINUE ( 0x0040 )
+#define SC_RIGHT_SVC_INTERROGATE ( 0x0080 )
+#define SC_RIGHT_SVC_USER_DEFINED_CONTROL ( 0x0100 )
+
+
+struct svcctl_CloseServiceHandle {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_ControlService {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t control;
+ } in;
+
+ struct {
+ struct SERVICE_STATUS *service_status;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_DeleteService {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_LockServiceDatabase {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ struct policy_handle *lock;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_QueryServiceObjectSecurity {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t security_flags;
+ uint32_t buffer_size;/* [range(0,0x40000)] */
+ } in;
+
+ struct {
+ uint8_t *buffer;/* [ref,size_is(buffer_size)] */
+ uint32_t *needed;/* [ref,range(0,0x40000)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_SetServiceObjectSecurity {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t security_flags;
+ uint8_t *buffer;/* [ref,size_is(buffer_size)] */
+ uint32_t buffer_size;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_QueryServiceStatus {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ struct SERVICE_STATUS *service_status;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_SetServiceStatus {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_UnlockServiceDatabase {
+ struct {
+ struct policy_handle *lock;/* [ref] */
+ } in;
+
+ struct {
+ struct policy_handle *lock;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_NotifyBootConfigStatus {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_SCSetServiceBitsW {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t bits;
+ uint32_t bitson;
+ uint32_t immediate;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_ChangeServiceConfigW {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t type;
+ uint32_t start;
+ uint32_t error;
+ const char *binary_path;/* [unique,charset(UTF16)] */
+ const char *load_order_group;/* [unique,charset(UTF16)] */
+ const char *dependencies;/* [unique,charset(UTF16)] */
+ const char *service_start_name;/* [unique,charset(UTF16)] */
+ const char *password;/* [unique,charset(UTF16)] */
+ const char *display_name;/* [unique,charset(UTF16)] */
+ } in;
+
+ struct {
+ uint32_t *tag_id;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_CreateServiceW {
+ struct {
+ struct policy_handle *scmanager_handle;/* [ref] */
+ const char *ServiceName;/* [charset(UTF16)] */
+ const char *DisplayName;/* [unique,charset(UTF16)] */
+ uint32_t desired_access;
+ uint32_t type;
+ uint32_t start_type;
+ uint32_t error_control;
+ const char *binary_path;/* [charset(UTF16)] */
+ const char *LoadOrderGroupKey;/* [unique,charset(UTF16)] */
+ uint8_t *dependencies;/* [unique,size_is(dependencies_size)] */
+ uint32_t dependencies_size;
+ const char *service_start_name;/* [unique,charset(UTF16)] */
+ uint8_t *password;/* [unique,size_is(password_size)] */
+ uint32_t password_size;
+ uint32_t *TagId;/* [unique] */
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t *TagId;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_EnumDependentServicesW {
+ struct {
+ struct policy_handle *service;/* [ref] */
+ uint32_t state;
+ uint32_t buf_size;/* [range(0,0x40000)] */
+ } in;
+
+ struct {
+ uint8_t *service_status;/* [ref,size_is(buf_size)] */
+ uint32_t *bytes_needed;/* [ref,range(0,0x40000)] */
+ uint32_t *services_returned;/* [ref,range(0,0x40000)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_EnumServicesStatusW {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t type;
+ uint32_t state;
+ uint32_t buf_size;
+ uint32_t *resume_handle;/* [unique] */
+ } in;
+
+ struct {
+ uint8_t *service;/* [size_is(buf_size)] */
+ uint32_t *bytes_needed;/* [ref] */
+ uint32_t *services_returned;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_OpenSCManagerW {
+ struct {
+ const char *MachineName;/* [unique,charset(UTF16)] */
+ const char *DatabaseName;/* [unique,charset(UTF16)] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_OpenServiceW {
+ struct {
+ struct policy_handle *scmanager_handle;/* [ref] */
+ const char *ServiceName;/* [charset(UTF16)] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_QueryServiceConfigW {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t buf_size;
+ } in;
+
+ struct {
+ uint8_t *query;
+ uint32_t *bytes_needed;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_QueryServiceLockStatusW {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t buf_size;
+ } in;
+
+ struct {
+ struct SERVICE_LOCK_STATUS *lock_status;/* [ref] */
+ uint32_t *required_buf_size;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_StartServiceW {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t NumArgs;
+ const char *Arguments;/* [unique,charset(UTF16)] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_GetServiceDisplayNameW {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ const char *service_name;/* [unique,charset(UTF16)] */
+ uint32_t *display_name_length;/* [unique] */
+ } in;
+
+ struct {
+ const char **display_name;/* [ref,charset(UTF16)] */
+ uint32_t *display_name_length;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_GetServiceKeyNameW {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ const char *service_name;/* [unique,charset(UTF16)] */
+ uint32_t *display_name_length;/* [unique] */
+ } in;
+
+ struct {
+ const char **key_name;/* [ref,charset(UTF16)] */
+ uint32_t *display_name_length;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_SCSetServiceBitsA {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t bits;
+ uint32_t bitson;
+ uint32_t immediate;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_ChangeServiceConfigA {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t type;
+ uint32_t start;
+ uint32_t error;
+ const char *binary_path;/* [unique,charset(UTF16)] */
+ const char *load_order_group;/* [unique,charset(UTF16)] */
+ const char *dependencies;/* [unique,charset(UTF16)] */
+ const char *service_start_name;/* [unique,charset(UTF16)] */
+ const char *password;/* [unique,charset(UTF16)] */
+ const char *display_name;/* [unique,charset(UTF16)] */
+ } in;
+
+ struct {
+ uint32_t *tag_id;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_CreateServiceA {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ const char *ServiceName;/* [unique,charset(UTF16)] */
+ const char *DisplayName;/* [unique,charset(UTF16)] */
+ uint32_t desired_access;
+ uint32_t type;
+ uint32_t start_type;
+ uint32_t error_control;
+ const char *binary_path;/* [unique,charset(UTF16)] */
+ const char *LoadOrderGroupKey;/* [unique,charset(UTF16)] */
+ const char *dependencies;/* [unique,charset(UTF16)] */
+ const char *service_start_name;/* [unique,charset(UTF16)] */
+ const char *password;/* [unique,charset(UTF16)] */
+ } in;
+
+ struct {
+ uint32_t *TagId;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_EnumDependentServicesA {
+ struct {
+ struct policy_handle *service;/* [ref] */
+ uint32_t state;
+ uint32_t buf_size;
+ } in;
+
+ struct {
+ struct ENUM_SERVICE_STATUS *service_status;/* [unique] */
+ uint32_t *bytes_needed;/* [ref] */
+ uint32_t *services_returned;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_EnumServicesStatusA {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t type;
+ uint32_t state;
+ uint32_t buf_size;
+ uint32_t *resume_handle;/* [unique] */
+ } in;
+
+ struct {
+ uint8_t *service;/* [size_is(buf_size)] */
+ uint32_t *bytes_needed;/* [ref] */
+ uint32_t *services_returned;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_OpenSCManagerA {
+ struct {
+ const char *MachineName;/* [unique,charset(UTF16)] */
+ const char *DatabaseName;/* [unique,charset(UTF16)] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_OpenServiceA {
+ struct {
+ struct policy_handle *scmanager_handle;/* [ref] */
+ const char *ServiceName;/* [unique,charset(UTF16)] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_QueryServiceConfigA {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t buf_size;
+ } in;
+
+ struct {
+ uint8_t *query;
+ uint32_t *bytes_needed;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_QueryServiceLockStatusA {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t buf_size;
+ } in;
+
+ struct {
+ struct SERVICE_LOCK_STATUS *lock_status;/* [ref] */
+ uint32_t *required_buf_size;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_StartServiceA {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t NumArgs;
+ const char *Arguments;/* [unique,charset(UTF16)] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_GetServiceDisplayNameA {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ const char *service_name;/* [unique,charset(UTF16)] */
+ uint32_t *display_name_length;/* [unique] */
+ } in;
+
+ struct {
+ const char **display_name;/* [ref,charset(UTF16)] */
+ uint32_t *display_name_length;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_GetServiceKeyNameA {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ const char *service_name;/* [unique,charset(UTF16)] */
+ uint32_t *display_name_length;/* [unique] */
+ } in;
+
+ struct {
+ const char **key_name;/* [ref,charset(UTF16)] */
+ uint32_t *display_name_length;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_GetCurrentGroupeStateW {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_EnumServiceGroupW {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_ChangeServiceConfig2A {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t info_level;
+ uint8_t *info;/* [unique] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_ChangeServiceConfig2W {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t info_level;
+ uint8_t *info;/* [unique] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_QueryServiceConfig2A {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t info_level;
+ uint32_t buf_size;
+ } in;
+
+ struct {
+ uint8_t *buffer;
+ uint32_t *bytes_needed;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_QueryServiceConfig2W {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t info_level;
+ uint32_t buf_size;
+ } in;
+
+ struct {
+ uint8_t *buffer;
+ uint32_t *bytes_needed;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_QueryServiceStatusEx {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t info_level;
+ uint32_t buf_size;
+ } in;
+
+ struct {
+ uint8_t *buffer;
+ uint32_t *bytes_needed;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct EnumServicesStatusExA {
+ struct {
+ struct policy_handle *scmanager;/* [ref] */
+ uint32_t info_level;
+ uint32_t type;
+ uint32_t state;
+ uint32_t buf_size;
+ uint32_t *resume_handle;/* [unique] */
+ } in;
+
+ struct {
+ uint8_t *services;
+ uint32_t *bytes_needed;/* [ref] */
+ uint32_t *service_returned;/* [ref] */
+ const char **group_name;/* [ref,charset(UTF16)] */
+ uint32_t *resume_handle;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct EnumServicesStatusExW {
+ struct {
+ struct policy_handle *scmanager;/* [ref] */
+ uint32_t info_level;
+ uint32_t type;
+ uint32_t state;
+ uint32_t buf_size;
+ uint32_t *resume_handle;/* [unique] */
+ } in;
+
+ struct {
+ uint8_t *services;
+ uint32_t *bytes_needed;/* [ref] */
+ uint32_t *service_returned;/* [ref] */
+ const char **group_name;/* [ref,charset(UTF16)] */
+ uint32_t *resume_handle;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct svcctl_SCSendTSMessage {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+#endif /* _HEADER_svcctl */
diff --git a/source3/librpc/gen_ndr/winreg.h b/source3/librpc/gen_ndr/winreg.h
new file mode 100644
index 0000000000..4a06e3bc83
--- /dev/null
+++ b/source3/librpc/gen_ndr/winreg.h
@@ -0,0 +1,624 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#include "librpc/gen_ndr/lsa.h"
+#include "librpc/gen_ndr/initshutdown.h"
+#include "librpc/gen_ndr/security.h"
+#ifndef _HEADER_winreg
+#define _HEADER_winreg
+
+/* bitmap winreg_AccessMask */
+#define KEY_QUERY_VALUE ( 0x00001 )
+#define KEY_SET_VALUE ( 0x00002 )
+#define KEY_CREATE_SUB_KEY ( 0x00004 )
+#define KEY_ENUMERATE_SUB_KEYS ( 0x00008 )
+#define KEY_NOTIFY ( 0x00010 )
+#define KEY_CREATE_LINK ( 0x00020 )
+#define KEY_WOW64_64KEY ( 0x00100 )
+#define KEY_WOW64_32KEY ( 0x00200 )
+
+enum winreg_Type
+#ifndef USE_UINT_ENUMS
+ {
+ REG_NONE=0,
+ REG_SZ=1,
+ REG_EXPAND_SZ=2,
+ REG_BINARY=3,
+ REG_DWORD=4,
+ REG_DWORD_BIG_ENDIAN=5,
+ REG_LINK=6,
+ REG_MULTI_SZ=7,
+ REG_RESOURCE_LIST=8,
+ REG_FULL_RESOURCE_DESCRIPTOR=9,
+ REG_RESOURCE_REQUIREMENTS_LIST=10,
+ REG_QWORD=11
+}
+#else
+ { __donnot_use_enum_winreg_Type=0x7FFFFFFF}
+#define REG_NONE ( 0 )
+#define REG_SZ ( 1 )
+#define REG_EXPAND_SZ ( 2 )
+#define REG_BINARY ( 3 )
+#define REG_DWORD ( 4 )
+#define REG_DWORD_BIG_ENDIAN ( 5 )
+#define REG_LINK ( 6 )
+#define REG_MULTI_SZ ( 7 )
+#define REG_RESOURCE_LIST ( 8 )
+#define REG_FULL_RESOURCE_DESCRIPTOR ( 9 )
+#define REG_RESOURCE_REQUIREMENTS_LIST ( 10 )
+#define REG_QWORD ( 11 )
+#endif
+;
+
+struct winreg_String {
+ uint16_t name_len;/* [value(strlen_m_term(name)*2)] */
+ uint16_t name_size;/* [value(strlen_m_term(name)*2)] */
+ const char *name;/* [unique,charset(UTF16)] */
+}/* [public,noejs] */;
+
+struct KeySecurityData {
+ uint8_t *data;/* [unique,length_is(len),size_is(size)] */
+ uint32_t size;
+ uint32_t len;
+};
+
+struct winreg_SecBuf {
+ uint32_t length;
+ struct KeySecurityData sd;
+ uint8_t inherit;
+};
+
+enum winreg_CreateAction
+#ifndef USE_UINT_ENUMS
+ {
+ REG_ACTION_NONE=0,
+ REG_CREATED_NEW_KEY=1,
+ REG_OPENED_EXISTING_KEY=2
+}
+#else
+ { __donnot_use_enum_winreg_CreateAction=0x7FFFFFFF}
+#define REG_ACTION_NONE ( 0 )
+#define REG_CREATED_NEW_KEY ( 1 )
+#define REG_OPENED_EXISTING_KEY ( 2 )
+#endif
+;
+
+struct winreg_StringBuf {
+ uint16_t length;/* [value(strlen_m_term_null(name)*2)] */
+ uint16_t size;
+ const char *name;/* [unique,length_is(length/2),charset(UTF16),size_is(size/2)] */
+};
+
+struct winreg_ValNameBuf {
+ uint16_t length;/* [value(strlen_m_term(name)*2)] */
+ uint16_t size;
+ const char *name;/* [unique,length_is(length/2),charset(UTF16),size_is(size/2)] */
+};
+
+struct KeySecurityAttribute {
+ uint32_t data_size;
+ struct KeySecurityData sec_data;
+ uint8_t inherit;
+};
+
+struct QueryMultipleValue {
+ struct winreg_String *name;/* [unique] */
+ enum winreg_Type type;
+ uint32_t offset;
+ uint32_t length;
+};
+
+
+struct winreg_OpenHKCR {
+ struct {
+ uint16_t *system_name;/* [unique] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_OpenHKCU {
+ struct {
+ uint16_t *system_name;/* [unique] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_OpenHKLM {
+ struct {
+ uint16_t *system_name;/* [unique] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_OpenHKPD {
+ struct {
+ uint16_t *system_name;/* [unique] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_OpenHKU {
+ struct {
+ uint16_t *system_name;/* [unique] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_CloseKey {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_CreateKey {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct winreg_String name;
+ struct winreg_String keyclass;
+ uint32_t options;
+ uint32_t access_mask;
+ struct winreg_SecBuf *secdesc;/* [unique] */
+ enum winreg_CreateAction *action_taken;/* [unique] */
+ } in;
+
+ struct {
+ struct policy_handle *new_handle;/* [ref] */
+ enum winreg_CreateAction *action_taken;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_DeleteKey {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct winreg_String key;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_DeleteValue {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct winreg_String value;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_EnumKey {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t enum_index;
+ struct winreg_StringBuf *name;/* [ref] */
+ struct winreg_StringBuf *keyclass;/* [unique] */
+ NTTIME *last_changed_time;/* [unique] */
+ } in;
+
+ struct {
+ struct winreg_StringBuf *name;/* [ref] */
+ struct winreg_StringBuf *keyclass;/* [unique] */
+ NTTIME *last_changed_time;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_EnumValue {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t enum_index;
+ struct winreg_ValNameBuf *name;/* [ref] */
+ enum winreg_Type *type;/* [unique] */
+ uint8_t *value;/* [unique,length_is(*length),size_is(*size)] */
+ uint32_t *size;/* [unique] */
+ uint32_t *length;/* [unique] */
+ } in;
+
+ struct {
+ struct winreg_ValNameBuf *name;/* [ref] */
+ enum winreg_Type *type;/* [unique] */
+ uint8_t *value;/* [unique,length_is(*length),size_is(*size)] */
+ uint32_t *size;/* [unique] */
+ uint32_t *length;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_FlushKey {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_GetKeySecurity {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t sec_info;
+ struct KeySecurityData *sd;/* [ref] */
+ } in;
+
+ struct {
+ struct KeySecurityData *sd;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_LoadKey {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct winreg_String *keyname;/* [unique] */
+ struct winreg_String *filename;/* [unique] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_NotifyChangeKeyValue {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint8_t watch_subtree;
+ uint32_t notify_filter;
+ uint32_t unknown;
+ struct winreg_String string1;
+ struct winreg_String string2;
+ uint32_t unknown2;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_OpenKey {
+ struct {
+ struct policy_handle *parent_handle;/* [ref] */
+ struct winreg_String keyname;
+ uint32_t unknown;
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_QueryInfoKey {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct winreg_String *classname;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *num_subkeys;/* [ref] */
+ uint32_t *max_subkeylen;/* [ref] */
+ uint32_t *max_classlen;/* [ref] */
+ uint32_t *num_values;/* [ref] */
+ uint32_t *max_valnamelen;/* [ref] */
+ uint32_t *max_valbufsize;/* [ref] */
+ uint32_t *secdescsize;/* [ref] */
+ NTTIME *last_changed_time;/* [ref] */
+ struct winreg_String *classname;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_QueryValue {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct winreg_String *value_name;/* [ref] */
+ enum winreg_Type *type;/* [unique] */
+ uint8_t *data;/* [unique,length_is(*value_length),size_is(*data_size)] */
+ uint32_t *data_size;/* [unique] */
+ uint32_t *value_length;/* [unique] */
+ } in;
+
+ struct {
+ enum winreg_Type *type;/* [unique] */
+ uint8_t *data;/* [unique,length_is(*value_length),size_is(*data_size)] */
+ uint32_t *data_size;/* [unique] */
+ uint32_t *value_length;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_ReplaceKey {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_RestoreKey {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct winreg_String *filename;/* [ref] */
+ uint32_t flags;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_SaveKey {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct winreg_String *filename;/* [ref] */
+ struct KeySecurityAttribute *sec_attrib;/* [unique] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_SetKeySecurity {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ uint32_t access_mask;
+ struct KeySecurityData *sd;/* [ref] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_SetValue {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ struct winreg_String name;
+ enum winreg_Type type;
+ uint8_t *data;/* [ref,size_is(size)] */
+ uint32_t size;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_UnLoadKey {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_InitiateSystemShutdown {
+ struct {
+ uint16_t *hostname;/* [unique] */
+ struct initshutdown_String *message;/* [unique] */
+ uint32_t timeout;
+ uint8_t force_apps;
+ uint8_t do_reboot;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_AbortSystemShutdown {
+ struct {
+ uint16_t *server;/* [unique] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_GetVersion {
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *version;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_OpenHKCC {
+ struct {
+ uint16_t *system_name;/* [unique] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_OpenHKDD {
+ struct {
+ uint16_t *system_name;/* [unique] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_QueryMultipleValues {
+ struct {
+ struct policy_handle *key_handle;/* [ref] */
+ uint32_t num_values;
+ struct QueryMultipleValue *values;/* [ref,length_is(num_values),size_is(num_values)] */
+ uint8_t *buffer;/* [unique,length_is(*buffer_size),size_is(*buffer_size)] */
+ uint32_t *buffer_size;/* [ref] */
+ } in;
+
+ struct {
+ struct QueryMultipleValue *values;/* [ref,length_is(num_values),size_is(num_values)] */
+ uint8_t *buffer;/* [unique,length_is(*buffer_size),size_is(*buffer_size)] */
+ uint32_t *buffer_size;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_InitiateSystemShutdownEx {
+ struct {
+ uint16_t *hostname;/* [unique] */
+ struct initshutdown_String *message;/* [unique] */
+ uint32_t timeout;
+ uint8_t force_apps;
+ uint8_t do_reboot;
+ uint32_t reason;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_SaveKeyEx {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_OpenHKPT {
+ struct {
+ uint16_t *system_name;/* [unique] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_OpenHKPN {
+ struct {
+ uint16_t *system_name;/* [unique] */
+ uint32_t access_mask;
+ } in;
+
+ struct {
+ struct policy_handle *handle;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct winreg_QueryMultipleValues2 {
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+#endif /* _HEADER_winreg */
diff --git a/source3/librpc/gen_ndr/wkssvc.h b/source3/librpc/gen_ndr/wkssvc.h
new file mode 100644
index 0000000000..07b4c40e83
--- /dev/null
+++ b/source3/librpc/gen_ndr/wkssvc.h
@@ -0,0 +1,981 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#include "librpc/gen_ndr/srvsvc.h"
+#include "librpc/gen_ndr/lsa.h"
+#ifndef _HEADER_wkssvc
+#define _HEADER_wkssvc
+
+enum srvsvc_PlatformId;
+
+struct wkssvc_NetWkstaInfo100 {
+ enum srvsvc_PlatformId platform_id;
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *domain_name;/* [unique,charset(UTF16)] */
+ uint32_t version_major;
+ uint32_t version_minor;
+};
+
+struct wkssvc_NetWkstaInfo101 {
+ enum srvsvc_PlatformId platform_id;
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *domain_name;/* [unique,charset(UTF16)] */
+ uint32_t version_major;
+ uint32_t version_minor;
+ const char *lan_root;/* [unique,charset(UTF16)] */
+};
+
+struct wkssvc_NetWkstaInfo102 {
+ enum srvsvc_PlatformId platform_id;
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *domain_name;/* [unique,charset(UTF16)] */
+ uint32_t version_major;
+ uint32_t version_minor;
+ const char *lan_root;/* [unique,charset(UTF16)] */
+ uint32_t logged_on_users;
+};
+
+struct wkssvc_NetWkstaInfo502 {
+ uint32_t char_wait;
+ uint32_t collection_time;
+ uint32_t maximum_collection_count;
+ uint32_t keep_connection;
+ uint32_t max_commands;
+ uint32_t session_timeout;
+ uint32_t size_char_buf;
+ uint32_t max_threads;
+ uint32_t lock_quota;
+ uint32_t lock_increment;
+ uint32_t lock_maximum;
+ uint32_t pipe_increment;
+ uint32_t pipe_maximum;
+ uint32_t cache_file_timeout;
+ uint32_t dormant_file_limit;
+ uint32_t read_ahead_throughput;
+ uint32_t num_mailslot_buffers;
+ uint32_t num_srv_announce_buffers;
+ uint32_t max_illegal_dgram_events;
+ uint32_t dgram_event_reset_freq;
+ uint32_t log_election_packets;
+ uint32_t use_opportunistic_locking;
+ uint32_t use_unlock_behind;
+ uint32_t use_close_behind;
+ uint32_t buf_named_pipes;
+ uint32_t use_lock_read_unlock;
+ uint32_t utilize_nt_caching;
+ uint32_t use_raw_read;
+ uint32_t use_raw_write;
+ uint32_t use_write_raw_data;
+ uint32_t use_encryption;
+ uint32_t buf_files_deny_write;
+ uint32_t buf_read_only_files;
+ uint32_t force_core_create_mode;
+ uint32_t use_512_byte_max_transfer;
+};
+
+struct wkssvc_NetWkstaInfo1010 {
+ uint32_t char_wait;
+};
+
+struct wkssvc_NetWkstaInfo1011 {
+ uint32_t collection_time;
+};
+
+struct wkssvc_NetWkstaInfo1012 {
+ uint32_t maximum_collection_count;
+};
+
+struct wkssvc_NetWkstaInfo1013 {
+ uint32_t keep_connection;
+};
+
+struct wkssvc_NetWkstaInfo1018 {
+ uint32_t session_timeout;
+};
+
+struct wkssvc_NetWkstaInfo1023 {
+ uint32_t size_char_buf;
+};
+
+struct wkssvc_NetWkstaInfo1027 {
+ uint32_t errorlog_sz;
+};
+
+struct wkssvc_NetWkstaInfo1028 {
+ uint32_t print_buf_time;
+};
+
+struct wkssvc_NetWkstaInfo1032 {
+ uint32_t wrk_heuristics;
+};
+
+struct wkssvc_NetWkstaInfo1033 {
+ uint32_t max_threads;
+};
+
+struct wkssvc_NetWkstaInfo1041 {
+ uint32_t lock_quota;
+};
+
+struct wkssvc_NetWkstaInfo1042 {
+ uint32_t lock_increment;
+};
+
+struct wkssvc_NetWkstaInfo1043 {
+ uint32_t lock_maximum;
+};
+
+struct wkssvc_NetWkstaInfo1044 {
+ uint32_t pipe_increment;
+};
+
+struct wkssvc_NetWkstaInfo1045 {
+ uint32_t pipe_maximum;
+};
+
+struct wkssvc_NetWkstaInfo1046 {
+ uint32_t dormant_file_limit;
+};
+
+struct wkssvc_NetWkstaInfo1047 {
+ uint32_t cache_file_timeout;
+};
+
+struct wkssvc_NetWkstaInfo1048 {
+ uint32_t use_opportunistic_locking;
+};
+
+struct wkssvc_NetWkstaInfo1049 {
+ uint32_t use_unlock_behind;
+};
+
+struct wkssvc_NetWkstaInfo1050 {
+ uint32_t use_close_behind;
+};
+
+struct wkssvc_NetWkstaInfo1051 {
+ uint32_t buf_named_pipes;
+};
+
+struct wkssvc_NetWkstaInfo1052 {
+ uint32_t use_lock_read_unlock;
+};
+
+struct wkssvc_NetWkstaInfo1053 {
+ uint32_t utilize_nt_caching;
+};
+
+struct wkssvc_NetWkstaInfo1054 {
+ uint32_t use_raw_read;
+};
+
+struct wkssvc_NetWkstaInfo1055 {
+ uint32_t use_raw_write;
+};
+
+struct wkssvc_NetWkstaInfo1056 {
+ uint32_t use_write_raw_data;
+};
+
+struct wkssvc_NetWkstaInfo1057 {
+ uint32_t use_encryption;
+};
+
+struct wkssvc_NetWkstaInfo1058 {
+ uint32_t buf_files_deny_write;
+};
+
+struct wkssvc_NetWkstaInfo1059 {
+ uint32_t buf_read_only_files;
+};
+
+struct wkssvc_NetWkstaInfo1060 {
+ uint32_t force_core_create_mode;
+};
+
+struct wkssvc_NetWkstaInfo1061 {
+ uint32_t use_512_byte_max_transfer;
+};
+
+struct wkssvc_NetWkstaInfo1062 {
+ uint32_t read_ahead_throughput;
+};
+
+union wkssvc_NetWkstaInfo {
+ struct wkssvc_NetWkstaInfo100 *info100;/* [unique,case(100)] */
+ struct wkssvc_NetWkstaInfo101 *info101;/* [unique,case(101)] */
+ struct wkssvc_NetWkstaInfo102 *info102;/* [unique,case(102)] */
+ struct wkssvc_NetWkstaInfo502 *info502;/* [unique,case(502)] */
+ struct wkssvc_NetWkstaInfo1010 *info1010;/* [unique,case(1010)] */
+ struct wkssvc_NetWkstaInfo1011 *info1011;/* [unique,case(1011)] */
+ struct wkssvc_NetWkstaInfo1012 *info1012;/* [unique,case(1012)] */
+ struct wkssvc_NetWkstaInfo1013 *info1013;/* [unique,case(1013)] */
+ struct wkssvc_NetWkstaInfo1018 *info1018;/* [unique,case(1018)] */
+ struct wkssvc_NetWkstaInfo1023 *info1023;/* [unique,case(1023)] */
+ struct wkssvc_NetWkstaInfo1027 *info1027;/* [unique,case(1027)] */
+ struct wkssvc_NetWkstaInfo1028 *info1028;/* [unique,case(1028)] */
+ struct wkssvc_NetWkstaInfo1032 *info1032;/* [unique,case(1032)] */
+ struct wkssvc_NetWkstaInfo1033 *info1033;/* [unique,case(1033)] */
+ struct wkssvc_NetWkstaInfo1041 *info1041;/* [unique,case(1041)] */
+ struct wkssvc_NetWkstaInfo1042 *info1042;/* [unique,case(1042)] */
+ struct wkssvc_NetWkstaInfo1043 *info1043;/* [unique,case(1043)] */
+ struct wkssvc_NetWkstaInfo1044 *info1044;/* [unique,case(1044)] */
+ struct wkssvc_NetWkstaInfo1045 *info1045;/* [unique,case(1045)] */
+ struct wkssvc_NetWkstaInfo1046 *info1046;/* [unique,case(1046)] */
+ struct wkssvc_NetWkstaInfo1047 *info1047;/* [unique,case(1047)] */
+ struct wkssvc_NetWkstaInfo1048 *info1048;/* [unique,case(1048)] */
+ struct wkssvc_NetWkstaInfo1049 *info1049;/* [unique,case(1049)] */
+ struct wkssvc_NetWkstaInfo1050 *info1050;/* [unique,case(1050)] */
+ struct wkssvc_NetWkstaInfo1051 *info1051;/* [unique,case(1051)] */
+ struct wkssvc_NetWkstaInfo1052 *info1052;/* [unique,case(1052)] */
+ struct wkssvc_NetWkstaInfo1053 *info1053;/* [unique,case(1053)] */
+ struct wkssvc_NetWkstaInfo1054 *info1054;/* [unique,case(1054)] */
+ struct wkssvc_NetWkstaInfo1055 *info1055;/* [unique,case(1055)] */
+ struct wkssvc_NetWkstaInfo1056 *info1056;/* [unique,case(1056)] */
+ struct wkssvc_NetWkstaInfo1057 *info1057;/* [unique,case(1057)] */
+ struct wkssvc_NetWkstaInfo1058 *info1058;/* [unique,case(1058)] */
+ struct wkssvc_NetWkstaInfo1059 *info1059;/* [unique,case(1059)] */
+ struct wkssvc_NetWkstaInfo1060 *info1060;/* [unique,case(1060)] */
+ struct wkssvc_NetWkstaInfo1061 *info1061;/* [unique,case(1061)] */
+ struct wkssvc_NetWkstaInfo1062 *info1062;/* [unique,case(1062)] */
+};
+
+struct wkssvc_NetrWkstaUserInfo0 {
+ const char *user_name;/* [unique,charset(UTF16)] */
+};
+
+struct wkssvc_NetWkstaEnumUsersCtr0 {
+ uint32_t entries_read;
+ struct wkssvc_NetrWkstaUserInfo0 *user0;/* [unique,size_is(entries_read)] */
+};
+
+struct wkssvc_NetrWkstaUserInfo1 {
+ const char *user_name;/* [unique,charset(UTF16)] */
+ const char *logon_domain;/* [unique,charset(UTF16)] */
+ const char *other_domains;/* [unique,charset(UTF16)] */
+ const char *logon_server;/* [unique,charset(UTF16)] */
+};
+
+struct wkssvc_NetWkstaEnumUsersCtr1 {
+ uint32_t entries_read;
+ struct wkssvc_NetrWkstaUserInfo1 *user1;/* [unique,size_is(entries_read)] */
+};
+
+union wkssvc_NetWkstaEnumUsersCtr {
+ struct wkssvc_NetWkstaEnumUsersCtr0 *user0;/* [unique,case(0)] */
+ struct wkssvc_NetWkstaEnumUsersCtr1 *user1;/* [unique,case] */
+}/* [switch_type(uint32)] */;
+
+struct wkssvc_NetWkstaEnumUsersInfo {
+ uint32_t level;
+ union wkssvc_NetWkstaEnumUsersCtr ctr;/* [switch_is(level)] */
+};
+
+struct wkssvc_NetrWkstaUserInfo1101 {
+ const char *other_domains;/* [unique,charset(UTF16)] */
+};
+
+union wkssvc_NetrWkstaUserInfo {
+ struct wkssvc_NetrWkstaUserInfo0 *info0;/* [unique,case(0)] */
+ struct wkssvc_NetrWkstaUserInfo1 *info1;/* [unique,case] */
+ struct wkssvc_NetrWkstaUserInfo1101 *info1101;/* [unique,case(1101)] */
+}/* [switch_type(uint32)] */;
+
+struct wkssvc_NetWkstaTransportInfo0 {
+ uint32_t quality_of_service;
+ uint32_t vc_count;
+ const char *name;/* [unique,charset(UTF16)] */
+ const char *address;/* [unique,charset(UTF16)] */
+ uint32_t wan_link;
+};
+
+struct wkssvc_NetWkstaTransportCtr0 {
+ uint32_t count;
+ struct wkssvc_NetWkstaTransportInfo0 *array;/* [unique,size_is(count)] */
+};
+
+union wkssvc_NetWkstaTransportCtr {
+ struct wkssvc_NetWkstaTransportCtr0 *ctr0;/* [unique,case(0)] */
+};
+
+struct wkssvc_NetWkstaTransportInfo {
+ uint32_t level;
+ union wkssvc_NetWkstaTransportCtr ctr;/* [switch_is(level)] */
+};
+
+struct wkssvc_NetrUseInfo3 {
+ const char *unknown1;/* [unique,charset(UTF16)] */
+ const char *unknown2;/* [unique,charset(UTF16)] */
+};
+
+struct wkssvc_NetrUseInfo2 {
+ const char *local;/* [unique,charset(UTF16)] */
+ const char *remote;/* [unique,charset(UTF16)] */
+ const char *password;/* [unique,charset(UTF16)] */
+ uint32_t status;
+ uint32_t asg_type;
+ uint32_t ref_count;
+ uint32_t use_count;
+ const char *user_name;/* [unique,charset(UTF16)] */
+ const char *domain_name;/* [unique,charset(UTF16)] */
+};
+
+struct wkssvc_NetrUseInfo1 {
+ const char *local;/* [unique,charset(UTF16)] */
+ const char *remote;/* [unique,charset(UTF16)] */
+ const char *password;/* [unique,charset(UTF16)] */
+ uint32_t status;
+ uint32_t asg_type;
+ uint32_t ref_count;
+ uint32_t use_count;
+};
+
+struct wkssvc_NetrUseInfo0 {
+ const char *local;/* [unique,charset(UTF16)] */
+ const char *remote;/* [unique,charset(UTF16)] */
+};
+
+union wkssvc_NetrUseGetInfoCtr {
+ struct wkssvc_NetrUseInfo0 *info0;/* [unique,case(0)] */
+ struct wkssvc_NetrUseInfo1 *info1;/* [unique,case] */
+ struct wkssvc_NetrUseInfo2 *info2;/* [unique,case(2)] */
+ struct wkssvc_NetrUseInfo3 *info3;/* [unique,case(3)] */
+}/* [switch_type(uint32)] */;
+
+struct wkssvc_NetrUseEnumCtr2 {
+ uint32_t count;
+ struct wkssvc_NetrUseInfo2 *array;/* [unique,size_is(count)] */
+};
+
+struct wkssvc_NetrUseEnumCtr1 {
+ uint32_t count;
+ struct wkssvc_NetrUseInfo1 *array;/* [unique,size_is(count)] */
+};
+
+struct wkssvc_NetrUseEnumCtr0 {
+ uint32_t count;
+ struct wkssvc_NetrUseInfo0 *array;/* [unique,size_is(count)] */
+};
+
+union wkssvc_NetrUseEnumCtr {
+ struct wkssvc_NetrUseEnumCtr0 *ctr0;/* [unique,case(0)] */
+ struct wkssvc_NetrUseEnumCtr1 *ctr1;/* [unique,case] */
+ struct wkssvc_NetrUseEnumCtr2 *ctr2;/* [unique,case(2)] */
+}/* [switch_type(uint32)] */;
+
+struct wkssvc_NetrUseEnumInfo {
+ uint32_t level;
+ union wkssvc_NetrUseEnumCtr ctr;/* [switch_is(level)] */
+};
+
+struct wkssvc_NetrWorkstationStatistics {
+ uint64_t unknown1;
+ uint64_t unknown2;
+ uint64_t unknown3;
+ uint64_t unknown4;
+ uint64_t unknown5;
+ uint64_t unknown6;
+ uint64_t unknown7;
+ uint64_t unknown8;
+ uint64_t unknown9;
+ uint64_t unknown10;
+ uint64_t unknown11;
+ uint64_t unknown12;
+ uint64_t unknown13;
+ uint32_t unknown14;
+ uint32_t unknown15;
+ uint32_t unknown16;
+ uint32_t unknown17;
+ uint32_t unknown18;
+ uint32_t unknown19;
+ uint32_t unknown20;
+ uint32_t unknown21;
+ uint32_t unknown22;
+ uint32_t unknown23;
+ uint32_t unknown24;
+ uint32_t unknown25;
+ uint32_t unknown26;
+ uint32_t unknown27;
+ uint32_t unknown28;
+ uint32_t unknown29;
+ uint32_t unknown30;
+ uint32_t unknown31;
+ uint32_t unknown32;
+ uint32_t unknown33;
+ uint32_t unknown34;
+ uint32_t unknown35;
+ uint32_t unknown36;
+ uint32_t unknown37;
+ uint32_t unknown38;
+ uint32_t unknown39;
+ uint32_t unknown40;
+};
+
+/* bitmap wkssvc_renameflags */
+#define WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE ( 0x00000002 )
+
+enum wkssvc_NetValidateNameType
+#ifndef USE_UINT_ENUMS
+ {
+ NetSetupUnknown=0,
+ NetSetupMachine=1,
+ NetSetupWorkgroup=2,
+ NetSetupDomain=3,
+ NetSetupNonExistentDomain=4,
+ NetSetupDnsMachine=5
+}
+#else
+ { __donnot_use_enum_wkssvc_NetValidateNameType=0x7FFFFFFF}
+#define NetSetupUnknown ( 0 )
+#define NetSetupMachine ( 1 )
+#define NetSetupWorkgroup ( 2 )
+#define NetSetupDomain ( 3 )
+#define NetSetupNonExistentDomain ( 4 )
+#define NetSetupDnsMachine ( 5 )
+#endif
+;
+
+enum wkssvc_NetJoinStatus
+#ifndef USE_UINT_ENUMS
+ {
+ NET_SETUP_UNKNOWN_STATUS=0,
+ NET_SETUP_UNJOINED=1,
+ NET_SETUP_WORKGROUP_NAME=2,
+ NET_SETUP_DOMAIN_NAME=3
+}
+#else
+ { __donnot_use_enum_wkssvc_NetJoinStatus=0x7FFFFFFF}
+#define NET_SETUP_UNKNOWN_STATUS ( 0 )
+#define NET_SETUP_UNJOINED ( 1 )
+#define NET_SETUP_WORKGROUP_NAME ( 2 )
+#define NET_SETUP_DOMAIN_NAME ( 3 )
+#endif
+;
+
+struct wkssvc_PasswordBuffer {
+ uint8_t data[524];
+}/* [flag(LIBNDR_PRINT_ARRAY_HEX)] */;
+
+/* bitmap wkssvc_joinflags */
+#define WKSSVC_JOIN_FLAGS_JOIN_WITH_NEW_NAME ( 0x00000400 )
+#define WKSSVC_JOIN_FLAGS_JOIN_DC_ACCOUNT ( 0x00000200 )
+#define WKSSVC_JOIN_FLAGS_DEFER_SPN ( 0x00000100 )
+#define WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED ( 0x00000080 )
+#define WKSSVC_JOIN_FLAGS_JOIN_UNSECURE ( 0x00000040 )
+#define WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED ( 0x00000020 )
+#define WKSSVC_JOIN_FLAGS_WIN9X_UPGRADE ( 0x00000010 )
+#define WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE ( 0x00000004 )
+#define WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE ( 0x00000002 )
+#define WKSSVC_JOIN_FLAGS_JOIN_TYPE ( 0x00000001 )
+
+enum wkssvc_ComputerNameType
+#ifndef USE_UINT_ENUMS
+ {
+ NetPrimaryComputerName=0,
+ NetAlternateComputerNames=1,
+ NetAllComputerNames=2,
+ NetComputerNameTypeMax=3
+}
+#else
+ { __donnot_use_enum_wkssvc_ComputerNameType=0x7FFFFFFF}
+#define NetPrimaryComputerName ( 0 )
+#define NetAlternateComputerNames ( 1 )
+#define NetAllComputerNames ( 2 )
+#define NetComputerNameTypeMax ( 3 )
+#endif
+;
+
+struct wkssvc_ComputerNamesCtr {
+ uint32_t count;
+ struct lsa_String *computer_name;/* [unique,size_is(count)] */
+};
+
+
+struct wkssvc_NetWkstaGetInfo {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ uint32_t level;
+ } in;
+
+ struct {
+ union wkssvc_NetWkstaInfo *info;/* [ref,switch_is(level)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetWkstaSetInfo {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ uint32_t level;
+ union wkssvc_NetWkstaInfo *info;/* [ref,switch_is(level)] */
+ uint32_t *parm_error;/* [ref] */
+ } in;
+
+ struct {
+ uint32_t *parm_error;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetWkstaEnumUsers {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ uint32_t prefmaxlen;
+ struct wkssvc_NetWkstaEnumUsersInfo *info;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *entries_read;/* [ref] */
+ struct wkssvc_NetWkstaEnumUsersInfo *info;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrWkstaUserGetInfo {
+ struct {
+ const char *unknown;/* [unique,charset(UTF16)] */
+ uint32_t level;
+ } in;
+
+ struct {
+ union wkssvc_NetrWkstaUserInfo *info;/* [ref,switch_is(level)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrWkstaUserSetInfo {
+ struct {
+ const char *unknown;/* [unique,charset(UTF16)] */
+ uint32_t level;
+ union wkssvc_NetrWkstaUserInfo *info;/* [ref,switch_is(level)] */
+ uint32_t *parm_err;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *parm_err;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetWkstaTransportEnum {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ uint32_t max_buffer;
+ struct wkssvc_NetWkstaTransportInfo *info;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *total_entries;/* [ref] */
+ struct wkssvc_NetWkstaTransportInfo *info;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrWkstaTransportAdd {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ uint32_t level;
+ struct wkssvc_NetWkstaTransportInfo0 *info0;/* [ref] */
+ uint32_t *parm_err;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *parm_err;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrWkstaTransportDel {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *transport_name;/* [unique,charset(UTF16)] */
+ uint32_t unknown3;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrUseAdd {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ uint32_t level;
+ union wkssvc_NetrUseGetInfoCtr *ctr;/* [ref,switch_is(level)] */
+ uint32_t *parm_err;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *parm_err;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrUseGetInfo {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *use_name;/* [ref,charset(UTF16)] */
+ uint32_t level;
+ } in;
+
+ struct {
+ union wkssvc_NetrUseGetInfoCtr *ctr;/* [ref,switch_is(level)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrUseDel {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *use_name;/* [ref,charset(UTF16)] */
+ uint32_t force_cond;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrUseEnum {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ uint32_t prefmaxlen;
+ struct wkssvc_NetrUseEnumInfo *info;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ } in;
+
+ struct {
+ uint32_t *entries_read;/* [ref] */
+ struct wkssvc_NetrUseEnumInfo *info;/* [ref] */
+ uint32_t *resume_handle;/* [unique] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrMessageBufferSend {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *message_name;/* [ref,charset(UTF16)] */
+ const char *message_sender_name;/* [unique,charset(UTF16)] */
+ uint8_t *message_buffer;/* [ref,size_is(message_size)] */
+ uint32_t message_size;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrWorkstationStatisticsGet {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *unknown2;/* [unique,charset(UTF16)] */
+ uint32_t unknown3;
+ uint32_t unknown4;
+ } in;
+
+ struct {
+ struct wkssvc_NetrWorkstationStatistics **info;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrLogonDomainNameAdd {
+ struct {
+ const char *domain_name;/* [ref,charset(UTF16)] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrLogonDomainNameDel {
+ struct {
+ const char *domain_name;/* [ref,charset(UTF16)] */
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrJoinDomain {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *domain_name;/* [ref,charset(UTF16)] */
+ const char *account_ou;/* [unique,charset(UTF16)] */
+ const char *Account;/* [unique,charset(UTF16)] */
+ const char *password;/* [unique,charset(UTF16)] */
+ uint32_t join_flags;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrUnjoinDomain {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *Account;/* [unique,charset(UTF16)] */
+ const char *password;/* [unique,charset(UTF16)] */
+ uint32_t unjoin_flags;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrRenameMachineInDomain {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *NewMachineName;/* [unique,charset(UTF16)] */
+ const char *Account;/* [unique,charset(UTF16)] */
+ const char *password;/* [unique,charset(UTF16)] */
+ uint32_t RenameOptions;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrValidateName {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *name;/* [ref,charset(UTF16)] */
+ const char *Account;/* [unique,charset(UTF16)] */
+ const char *Password;/* [unique,charset(UTF16)] */
+ enum wkssvc_NetValidateNameType name_type;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrGetJoinInformation {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char **name_buffer;/* [ref,charset(UTF16)] */
+ } in;
+
+ struct {
+ enum wkssvc_NetJoinStatus *name_type;/* [ref] */
+ const char **name_buffer;/* [ref,charset(UTF16)] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrGetJoinableOus {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *domain_name;/* [ref,charset(UTF16)] */
+ const char *Account;/* [unique,charset(UTF16)] */
+ const char *unknown;/* [unique,charset(UTF16)] */
+ uint32_t *num_ous;/* [ref] */
+ } in;
+
+ struct {
+ const char ***ous;/* [ref,charset(UTF16),size_is(,*num_ous)] */
+ uint32_t *num_ous;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrJoinDomain2 {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *domain_name;/* [ref,charset(UTF16)] */
+ const char *account_ou;/* [unique,charset(UTF16)] */
+ const char *admin_account;/* [unique,charset(UTF16)] */
+ struct wkssvc_PasswordBuffer *encrypted_password;/* [unique] */
+ uint32_t join_flags;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrUnjoinDomain2 {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *account;/* [unique,charset(UTF16)] */
+ struct wkssvc_PasswordBuffer *encrypted_password;/* [unique] */
+ uint32_t unjoin_flags;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrRenameMachineInDomain2 {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *NewMachineName;/* [unique,charset(UTF16)] */
+ const char *Account;/* [unique,charset(UTF16)] */
+ struct wkssvc_PasswordBuffer *EncryptedPassword;/* [unique] */
+ uint32_t RenameOptions;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrValidateName2 {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *name;/* [ref,charset(UTF16)] */
+ const char *Account;/* [unique,charset(UTF16)] */
+ struct wkssvc_PasswordBuffer *EncryptedPassword;/* [unique] */
+ enum wkssvc_NetValidateNameType name_type;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrGetJoinableOus2 {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *domain_name;/* [ref,charset(UTF16)] */
+ const char *Account;/* [unique,charset(UTF16)] */
+ struct wkssvc_PasswordBuffer *EncryptedPassword;/* [unique] */
+ uint32_t *num_ous;/* [ref] */
+ } in;
+
+ struct {
+ const char ***ous;/* [ref,charset(UTF16),size_is(,*num_ous)] */
+ uint32_t *num_ous;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrAddAlternateComputerName {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *NewAlternateMachineName;/* [unique,charset(UTF16)] */
+ const char *Account;/* [unique,charset(UTF16)] */
+ struct wkssvc_PasswordBuffer *EncryptedPassword;/* [unique] */
+ uint32_t Reserved;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrRemoveAlternateComputerName {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *AlternateMachineNameToRemove;/* [unique,charset(UTF16)] */
+ const char *Account;/* [unique,charset(UTF16)] */
+ struct wkssvc_PasswordBuffer *EncryptedPassword;/* [unique] */
+ uint32_t Reserved;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrSetPrimaryComputername {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ const char *primary_name;/* [unique,charset(UTF16)] */
+ const char *Account;/* [unique,charset(UTF16)] */
+ struct wkssvc_PasswordBuffer *EncryptedPassword;/* [unique] */
+ uint32_t Reserved;
+ } in;
+
+ struct {
+ WERROR result;
+ } out;
+
+};
+
+
+struct wkssvc_NetrEnumerateComputerNames {
+ struct {
+ const char *server_name;/* [unique,charset(UTF16)] */
+ enum wkssvc_ComputerNameType name_type;
+ uint32_t Reserved;
+ } in;
+
+ struct {
+ struct wkssvc_ComputerNamesCtr **ctr;/* [ref] */
+ WERROR result;
+ } out;
+
+};
+
+#endif /* _HEADER_wkssvc */
diff --git a/source3/librpc/gen_ndr/xattr.h b/source3/librpc/gen_ndr/xattr.h
new file mode 100644
index 0000000000..b0b9db99c1
--- /dev/null
+++ b/source3/librpc/gen_ndr/xattr.h
@@ -0,0 +1,34 @@
+/* header auto-generated by pidl */
+
+#include <stdint.h>
+
+#ifndef _HEADER_xattr
+#define _HEADER_xattr
+
+#define XATTR_NTACL_NAME ( "security.NTACL" )
+struct tdb_xattr {
+ const char * name;/* [flag(LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM)] */
+ DATA_BLOB value;
+}/* [public] */;
+
+struct tdb_xattrs {
+ uint32_t num_xattrs;
+ struct tdb_xattr *xattrs;
+}/* [public] */;
+
+struct security_descriptor_timestamp {
+ struct security_descriptor *sd;/* [unique] */
+ NTTIME last_changed;
+}/* [public] */;
+
+union xattr_NTACL_Info {
+ struct security_descriptor *sd;/* [unique,case] */
+ struct security_descriptor_timestamp *sd_ts;/* [unique,case(2)] */
+}/* [switch_type(uint16)] */;
+
+struct xattr_NTACL {
+ uint16_t version;
+ union xattr_NTACL_Info info;/* [switch_is(version)] */
+}/* [public] */;
+
+#endif /* _HEADER_xattr */
diff --git a/source3/librpc/idl/dfs.idl b/source3/librpc/idl/dfs.idl
new file mode 100644
index 0000000000..a729b0e560
--- /dev/null
+++ b/source3/librpc/idl/dfs.idl
@@ -0,0 +1,417 @@
+/*
+ dfs interface definition
+*/
+
+[ uuid("4fc742e0-4a10-11cf-8273-00aa004ae673"),
+ version(3.0),
+ pointer_default(unique),
+ helpstring("Settings for Microsoft Distributed File System"),
+ endpoint("ncacn_np:[\\pipe\\netdfs]", "ncacn_ip_tcp:", "ncalrpc:")
+] interface netdfs
+{
+ /******************/
+ /* Function: 0x00 */
+ typedef [v1_enum] enum {
+ DFS_MANAGER_VERSION_NT4 = 1,
+ DFS_MANAGER_VERSION_W2K = 2,
+ DFS_MANAGER_VERSION_W2K3 = 4,
+ DFS_MANAGER_VERSION_W2K8 = 6
+ } dfs_ManagerVersion;
+
+ [public] void dfs_GetManagerVersion(
+ [out] dfs_ManagerVersion *version
+ );
+
+
+ /******************/
+ /* Function: 0x01 */
+ WERROR dfs_Add (
+ [in] [string,charset(UTF16)] uint16 *path,
+ [in] [string,charset(UTF16)] uint16 *server,
+ [in,unique] [string,charset(UTF16)] uint16 *share,
+ [in,unique] [string,charset(UTF16)] uint16 *comment,
+ [in] uint32 flags
+ );
+
+ /******************/
+ /* Function: 0x02 */
+ WERROR dfs_Remove (
+ [in] [string,charset(UTF16)] uint16 *dfs_entry_path,
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,unique] [string,charset(UTF16)] uint16 *sharename
+ );
+
+ /******************/
+ /* Function: 0x03 */
+
+ typedef struct {
+ } dfs_Info0;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *path;
+ } dfs_Info1;
+
+ typedef [public,bitmap32bit] bitmap {
+ DFS_VOLUME_STATE_OK = 0x1,
+ DFS_VOLUME_STATE_INCONSISTENT = 0x2,
+ DFS_VOLUME_STATE_OFFLINE = 0x3,
+ DFS_VOLUME_STATE_ONLINE = 0x4,
+ DFS_VOLUME_STATE_STANDALONE = DFS_VOLUME_FLAVOR_STANDALONE,
+ DFS_VOLUME_STATE_AD_BLOB = DFS_VOLUME_FLAVOR_AD_BLOB
+ } dfs_VolumeState;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *path;
+ [string,charset(UTF16)] uint16 *comment;
+ dfs_VolumeState state;
+ uint32 num_stores;
+ } dfs_Info2;
+
+ const int DFS_STORAGE_STATES = 0xf;
+
+ /* yes, this is a bitmap */
+ typedef [public,bitmap32bit] bitmap {
+ DFS_STORAGE_STATE_OFFLINE = 1,
+ DFS_STORAGE_STATE_ONLINE = 2,
+ DFS_STORAGE_STATE_ACTIVE = 4
+ } dfs_StorageState;
+
+ typedef struct {
+ dfs_StorageState state;
+ [string,charset(UTF16)] uint16 *server;
+ [string,charset(UTF16)] uint16 *share;
+ } dfs_StorageInfo;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *path;
+ [string,charset(UTF16)] uint16 *comment;
+ dfs_VolumeState state;
+ uint32 num_stores;
+ [size_is(num_stores)] dfs_StorageInfo *stores;
+ } dfs_Info3;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *path;
+ [string,charset(UTF16)] uint16 *comment;
+ dfs_VolumeState state;
+ uint32 timeout;
+ GUID guid;
+ uint32 num_stores;
+ [size_is(num_stores)] dfs_StorageInfo *stores;
+ } dfs_Info4;
+
+ /* verified with dfsutil */
+ typedef [public,bitmap32bit] bitmap {
+ DFS_PROPERTY_FLAG_INSITE_REFERRALS = 0x01,
+ DFS_PROPERTY_FLAG_ROOT_SCALABILITY = 0x02,
+ DFS_PROPERTY_FLAG_SITE_COSTING = 0x04,
+ DFS_PROPERTY_FLAG_TARGET_FAILBACK = 0x08,
+ DFS_PROPERTY_FLAG_CLUSTER_ENABLED = 0x10 /* untested */
+ } dfs_PropertyFlags;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *path;
+ [string,charset(UTF16)] uint16 *comment;
+ dfs_VolumeState state;
+ uint32 timeout;
+ GUID guid;
+ dfs_PropertyFlags flags;
+ uint32 pktsize;
+ uint32 num_stores;
+ } dfs_Info5;
+
+ typedef [v1_enum] enum {
+ DFS_INVALID_PRIORITY_CLASS = -1,
+ DFS_SITE_COST_NORMAL_PRIORITY_CLASS = 0,
+ DFS_GLOBAL_HIGH_PRIORITY_CLASS = 1,
+ DFS_SITE_COST_HIGH_PRIORITY_CLASS = 2,
+ DFS_SITE_COST_LOW_PRIORITY_CLASS = 3,
+ DFS_GLOBAL_LOW_PRIORITY_CLASS = 4
+ } dfs_Target_PriorityClass;
+
+ typedef struct {
+ dfs_Target_PriorityClass target_priority_class;
+ uint16 target_priority_rank;
+ uint16 reserved;
+ } dfs_Target_Priority;
+
+ typedef struct {
+ dfs_StorageInfo info;
+ dfs_Target_Priority target_priority;
+ } dfs_StorageInfo2;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *entry_path;
+ [string,charset(UTF16)] uint16 *comment;
+ dfs_VolumeState state;
+ uint32 timeout;
+ GUID guid;
+ dfs_PropertyFlags flags;
+ uint32 pktsize;
+ uint16 num_stores;
+ [size_is(num_stores)] dfs_StorageInfo2 *stores;
+ } dfs_Info6;
+
+ typedef struct {
+ GUID generation_guid;
+ } dfs_Info7;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *comment;
+ } dfs_Info100;
+
+ typedef struct {
+ dfs_StorageState state;
+ } dfs_Info101;
+
+ typedef struct {
+ uint32 timeout;
+ } dfs_Info102;
+
+ typedef struct {
+ dfs_PropertyFlags flags;
+ } dfs_Info103;
+
+ typedef struct {
+ dfs_Target_Priority priority;
+ } dfs_Info104;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *comment;
+ dfs_VolumeState state;
+ uint32 timeout;
+ uint32 property_flag_mask;
+ uint32 property_flags;
+ } dfs_Info105;
+
+ typedef struct {
+ dfs_StorageState state;
+ dfs_Target_Priority priority;
+ } dfs_Info106;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *dom_root;
+ } dfs_Info200;
+
+ typedef enum {
+ DFS_VOLUME_FLAVOR_STANDALONE = 0x100,
+ DFS_VOLUME_FLAVOR_AD_BLOB = 0x200
+ } dfs_VolumeFlavor;
+
+ typedef struct {
+ dfs_VolumeFlavor flavor;
+ [string,charset(UTF16)] uint16 *dom_root;
+ } dfs_Info300;
+
+ typedef union {
+ [case(0)] dfs_Info0 *info0;
+ [case(1)] dfs_Info1 *info1;
+ [case(2)] dfs_Info2 *info2;
+ [case(3)] dfs_Info3 *info3;
+ [case(4)] dfs_Info4 *info4;
+ [case(5)] dfs_Info5 *info5;
+ [case(6)] dfs_Info6 *info6;
+ [case(7)] dfs_Info7 *info7;
+ [case(100)] dfs_Info100 *info100;
+ [case(101)] dfs_Info101 *info101;
+ [case(102)] dfs_Info102 *info102;
+ [case(103)] dfs_Info103 *info103;
+ [case(104)] dfs_Info104 *info104;
+ [case(105)] dfs_Info105 *info105;
+ [case(106)] dfs_Info106 *info106;
+ } dfs_Info;
+
+ WERROR dfs_SetInfo (
+ [in] [string,charset(UTF16)] uint16 dfs_entry_path[],
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,unique] [string,charset(UTF16)] uint16 *sharename,
+ [in] uint32 level,
+ [in,ref,switch_is(level)] dfs_Info *info
+ );
+
+ /******************/
+ /* Function: 0x04 */
+ WERROR dfs_GetInfo (
+ [in] [string,charset(UTF16)] uint16 dfs_entry_path[],
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,unique] [string,charset(UTF16)] uint16 *sharename,
+ [in] uint32 level,
+ [out,switch_is(level)] dfs_Info *info
+ );
+
+ /******************/
+ /* Function: 0x05 */
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] dfs_Info1 *s;
+ } dfs_EnumArray1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] dfs_Info2 *s;
+ } dfs_EnumArray2;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] dfs_Info3 *s;
+ } dfs_EnumArray3;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] dfs_Info4 *s;
+ } dfs_EnumArray4;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] dfs_Info5 *s;
+ } dfs_EnumArray5;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] dfs_Info6 *s;
+ } dfs_EnumArray6;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] dfs_Info200 *s;
+ } dfs_EnumArray200;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] dfs_Info300 *s;
+ } dfs_EnumArray300;
+
+
+ typedef union {
+ [case(1)] dfs_EnumArray1 *info1;
+ [case(2)] dfs_EnumArray2 *info2;
+ [case(3)] dfs_EnumArray3 *info3;
+ [case(4)] dfs_EnumArray4 *info4;
+ [case(5)] dfs_EnumArray5 *info5;
+ [case(6)] dfs_EnumArray6 *info6;
+ [case(200)] dfs_EnumArray200 *info200;
+ [case(300)] dfs_EnumArray300 *info300;
+ } dfs_EnumInfo;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] dfs_EnumInfo e;
+ } dfs_EnumStruct;
+
+ WERROR dfs_Enum (
+ [in] uint32 level,
+ [in] uint32 bufsize,
+ [in,out,unique] dfs_EnumStruct *info,
+ [in,out,unique] uint32 *total
+ );
+
+ /* Function 0x06 */
+ WERROR dfs_Rename();
+
+ /* Function 0x07 */
+ WERROR dfs_Move();
+
+ /* Function 0x08 */
+ WERROR dfs_ManagerGetConfigInfo();
+
+ /* Function 0x09 */
+ WERROR dfs_ManagerSendSiteInfo();
+
+ /* Function 0x0a */
+ typedef struct {
+ uint32 unknown1;
+ [string,charset(UTF16)] uint16 *unknown2;
+ } dfs_UnknownStruct;
+
+ WERROR dfs_AddFtRoot(
+ [in] [string,charset(UTF16)] uint16 servername[],
+ [in] [string,charset(UTF16)] uint16 dns_servername[],
+ [in] [string,charset(UTF16)] uint16 dfsname[],
+ [in] [string,charset(UTF16)] uint16 rootshare[],
+ [in] [string,charset(UTF16)] uint16 comment[],
+ [in] [string,charset(UTF16)] uint16 dfs_config_dn[],
+ [in] uint8 unknown1,
+ [in] uint32 flags,
+ [in,out,unique] dfs_UnknownStruct **unknown2
+ );
+
+ /* Function 0x0b */
+ WERROR dfs_RemoveFtRoot(
+ [in] [string,charset(UTF16)] uint16 servername[],
+ [in] [string,charset(UTF16)] uint16 dns_servername[],
+ [in] [string,charset(UTF16)] uint16 dfsname[],
+ [in] [string,charset(UTF16)] uint16 rootshare[],
+ [in] uint32 flags,
+ [in,out,unique] dfs_UnknownStruct **unknown
+ );
+
+ /* Function 0x0c */
+ WERROR dfs_AddStdRoot(
+ [in] [string,charset(UTF16)] uint16 servername[],
+ [in] [string,charset(UTF16)] uint16 rootshare[],
+ [in] [string,charset(UTF16)] uint16 comment[],
+ [in] uint32 flags
+ );
+
+ /* Function 0x0d */
+ WERROR dfs_RemoveStdRoot(
+ [in] [string,charset(UTF16)] uint16 servername[],
+ [in] [string,charset(UTF16)] uint16 rootshare[],
+ [in] uint32 flags
+ );
+
+ /* Function 0x0e */
+ WERROR dfs_ManagerInitialize(
+ [in] [string,charset(UTF16)] uint16 *servername,
+ [in] uint32 flags
+ );
+
+ /* Function 0x0f */
+ WERROR dfs_AddStdRootForced(
+ [in] [string,charset(UTF16)] uint16 servername[],
+ [in] [string,charset(UTF16)] uint16 rootshare[],
+ [in] [string,charset(UTF16)] uint16 comment[],
+ [in] [string,charset(UTF16)] uint16 store[] /* C:\\whatever */
+ );
+
+ /* Function 0x10 */
+ WERROR dfs_GetDcAddress(
+ [in] [string,charset(UTF16)] uint16 servername[],
+ [in,out,ref] [string,charset(UTF16)] uint16 **server_fullname,
+ [in,out,ref] boolean8 *is_root,
+ [in,out,ref] uint32 *ttl
+ );
+
+ /* Function 0x11 */
+ WERROR dfs_SetDcAddress(
+ [in] [string,charset(UTF16)] uint16 servername[],
+ [in] [string,charset(UTF16)] uint16 server_fullname[],
+ [in] uint32 flags,
+ [in] uint32 ttl
+ );
+
+ /* Function 0x12 */
+ WERROR dfs_FlushFtTable(
+ [in] [string,charset(UTF16)] uint16 servername[],
+ [in] [string,charset(UTF16)] uint16 rootshare[]
+ );
+
+ /* Function 0x13 */
+ WERROR dfs_Add2();
+
+ /* Function 0x14 */
+ WERROR dfs_Remove2();
+
+ /* Function 0x15 */
+ [public] WERROR dfs_EnumEx(
+ [in] [string,charset(UTF16)] uint16 dfs_name[],
+ [in] uint32 level,
+ [in] uint32 bufsize,
+ [in,out,unique] dfs_EnumStruct *info,
+ [in,out,unique] uint32 *total
+ );
+
+ /* Function 0x16 */
+ WERROR dfs_SetInfo2();
+}
diff --git a/source3/librpc/idl/drsblobs.idl b/source3/librpc/idl/drsblobs.idl
new file mode 100644
index 0000000000..6fdca0ec43
--- /dev/null
+++ b/source3/librpc/idl/drsblobs.idl
@@ -0,0 +1,436 @@
+#include "idl_types.h"
+
+import "drsuapi.idl", "misc.idl";
+
+[
+ uuid("12345778-1234-abcd-0001-00000001"),
+ version(0.0),
+ pointer_default(unique),
+ helpstring("Active Directory Replication LDAP Blobs")
+]
+interface drsblobs {
+ typedef bitmap drsuapi_DsReplicaSyncOptions drsuapi_DsReplicaSyncOptions;
+ typedef bitmap drsuapi_DsReplicaNeighbourFlags drsuapi_DsReplicaNeighbourFlags;
+ typedef [v1_enum] enum drsuapi_DsAttributeId drsuapi_DsAttributeId;
+
+ /*
+ * replPropertyMetaData
+ * w2k uses version 1
+ * w2k3 uses version 1
+ */
+ typedef struct {
+ drsuapi_DsAttributeId attid;
+ uint32 version;
+ NTTIME_1sec originating_change_time;
+ GUID originating_invocation_id;
+ hyper originating_usn;
+ hyper local_usn;
+ } replPropertyMetaData1;
+
+ typedef struct {
+ uint32 count;
+ uint32 reserved;
+ replPropertyMetaData1 array[count];
+ } replPropertyMetaDataCtr1;
+
+ typedef [nodiscriminant] union {
+ [case(1)] replPropertyMetaDataCtr1 ctr1;
+ } replPropertyMetaDataCtr;
+
+ typedef [public] struct {
+ uint32 version;
+ uint32 reserved;
+ [switch_is(version)] replPropertyMetaDataCtr ctr;
+ } replPropertyMetaDataBlob;
+
+ void decode_replPropertyMetaData(
+ [in] replPropertyMetaDataBlob blob
+ );
+
+ /*
+ * replUpToDateVector
+ * w2k uses version 1
+ * w2k3 uses version 2
+ */
+ typedef struct {
+ uint32 count;
+ uint32 reserved;
+ drsuapi_DsReplicaCursor cursors[count];
+ } replUpToDateVectorCtr1;
+
+ typedef struct {
+ uint32 count;
+ uint32 reserved;
+ drsuapi_DsReplicaCursor2 cursors[count];
+ } replUpToDateVectorCtr2;
+
+ typedef [nodiscriminant] union {
+ [case(1)] replUpToDateVectorCtr1 ctr1;
+ [case(2)] replUpToDateVectorCtr2 ctr2;
+ } replUpToDateVectorCtr;
+
+ typedef [public] struct {
+ uint32 version;
+ uint32 reserved;
+ [switch_is(version)] replUpToDateVectorCtr ctr;
+ } replUpToDateVectorBlob;
+
+ void decode_replUpToDateVector(
+ [in] replUpToDateVectorBlob blob
+ );
+
+ /*
+ * repsFrom/repsTo
+ * w2k uses version 1
+ * w2k3 uses version 1
+ */
+ typedef [public,gensize] struct {
+ [value(strlen(dns_name)+1)] uint32 __dns_name_size;
+ [charset(DOS)] uint8 dns_name[__dns_name_size];
+ } repsFromTo1OtherInfo;
+
+ typedef [public,gensize,flag(NDR_PAHEX)] struct {
+ /* this includes the 8 bytes of the repsFromToBlob header */
+ [value(ndr_size_repsFromTo1(this, ndr->flags)+8)] uint32 blobsize;
+ uint32 consecutive_sync_failures;
+ NTTIME_1sec last_success;
+ NTTIME_1sec last_attempt;
+ WERROR result_last_attempt;
+ [relative] repsFromTo1OtherInfo *other_info;
+ [value(ndr_size_repsFromTo1OtherInfo(other_info, ndr->flags))] uint32 other_info_length;
+ drsuapi_DsReplicaNeighbourFlags replica_flags;
+ uint8 schedule[84];
+ uint32 reserved;
+ drsuapi_DsReplicaHighWaterMark highwatermark;
+ GUID source_dsa_obj_guid; /* the 'objectGuid' field of the CN=NTDS Settings object */
+ GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */
+ GUID transport_guid;
+ } repsFromTo1;
+
+ typedef [nodiscriminant] union {
+ [case(1)] repsFromTo1 ctr1;
+ } repsFromTo;
+
+ typedef [public] struct {
+ uint32 version;
+ uint32 reserved;
+ [switch_is(version)] repsFromTo ctr;
+ } repsFromToBlob;
+
+ void decode_repsFromTo(
+ [in] repsFromToBlob blob
+ );
+
+ /*
+ * partialAttributeSet
+ * w2k uses version 1
+ * w2k3 uses version 1
+ */
+ typedef struct {
+ uint32 count;
+ drsuapi_DsAttributeId array[count];
+ } partialAttributeSetCtr1;
+
+ typedef [nodiscriminant] union {
+ [case(1)] partialAttributeSetCtr1 ctr1;
+ } partialAttributeSetCtr;
+
+ typedef [public] struct {
+ uint32 version;
+ uint32 reserved;
+ [switch_is(version)] partialAttributeSetCtr ctr;
+ } partialAttributeSetBlob;
+
+ void decode_partialAttributeSet(
+ [in] partialAttributeSetBlob blob
+ );
+
+ /*
+ * prefixMap
+ * w2k unknown
+ * w2k3 unknown
+ * samba4 uses 0x44534442 'DSDB'
+ *
+ * as we windows don't return the prefixMap attribute when you ask for
+ * we don't know the format, but the attribute is not replicated
+ * so that we can choose our own format...
+ */
+ typedef [v1_enum] enum {
+ PREFIX_MAP_VERSION_DSDB = 0x44534442
+ } prefixMapVersion;
+
+ typedef [nodiscriminant] union {
+ [case(PREFIX_MAP_VERSION_DSDB)] drsuapi_DsReplicaOIDMapping_Ctr dsdb;
+ } prefixMapCtr;
+
+ typedef [public] struct {
+ prefixMapVersion version;
+ uint32 reserved;
+ [switch_is(version)] prefixMapCtr ctr;
+ } prefixMapBlob;
+
+ void decode_prefixMap(
+ [in] prefixMapBlob blob
+ );
+
+ /*
+ * the cookie for the LDAP dirsync control
+ */
+ typedef [nodiscriminant,gensize] union {
+ [case(0)];
+ [default] replUpToDateVectorBlob uptodateness_vector;
+ } ldapControlDirSyncExtra;
+
+ typedef struct {
+ [value(3)] uint32 u1;
+ NTTIME time;
+ uint32 u2;
+ uint32 u3;
+ [value(ndr_size_ldapControlDirSyncExtra(&extra, extra.uptodateness_vector.version, 0))]
+ uint32 extra_length;
+ drsuapi_DsReplicaHighWaterMark highwatermark;
+ GUID guid1;
+ [switch_is(extra_length)] ldapControlDirSyncExtra extra;
+ } ldapControlDirSyncBlob;
+
+ typedef [public,relative_base] struct {
+ [charset(DOS),value("MSDS")] uint8 msds[4];
+ [subcontext(0)] ldapControlDirSyncBlob blob;
+ } ldapControlDirSyncCookie;
+
+ void decode_ldapControlDirSync(
+ [in] ldapControlDirSyncCookie cookie
+ );
+
+ typedef struct {
+ [value(2*strlen_m(name))] uint16 name_len;
+ [value(strlen(data))] uint16 data_len;
+ uint16 reserved; /* 2 for 'Packages', 1 for 'Primary:*', but should be ignored */
+ [charset(UTF16)] uint8 name[name_len];
+ /*
+ * the data field contains data as HEX strings
+ *
+ * 'Packages':
+ * data contains the list of packages
+ * as non termiated UTF16 strings with
+ * a UTF16 NULL byte as separator
+ *
+ * 'Primary:Kerberos-Newer-Keys':
+ * ...
+ *
+ * 'Primary:Kerberos':
+ * ...
+ *
+ * 'Primary:WDigest':
+ * ...
+ *
+ * 'Primary:CLEARTEXT':
+ * data contains the cleartext password
+ * as UTF16 string encoded as HEX string
+ */
+ [charset(DOS)] uint8 data[data_len];
+ } supplementalCredentialsPackage;
+
+ /* this are 0x30 (48) whitespaces (0x20) */
+ const string SUPPLEMENTAL_CREDENTIALS_PREFIX = " ";
+
+ typedef [flag(NDR_PAHEX)] enum {
+ SUPPLEMENTAL_CREDENTIALS_SIGNATURE = 0x0050
+ } supplementalCredentialsSignature;
+
+ typedef [gensize] struct {
+ [value(SUPPLEMENTAL_CREDENTIALS_PREFIX),charset(UTF16)] uint16 prefix[0x30];
+ [value(SUPPLEMENTAL_CREDENTIALS_SIGNATURE)] supplementalCredentialsSignature signature;
+ uint16 num_packages;
+ supplementalCredentialsPackage packages[num_packages];
+ } supplementalCredentialsSubBlob;
+
+ typedef [public] struct {
+ [value(0)] uint32 unknown1;
+ [value(ndr_size_supplementalCredentialsSubBlob(&sub, ndr->flags))] uint32 __ndr_size;
+ [value(0)] uint32 unknown2;
+ [subcontext(0),subcontext_size(__ndr_size)] supplementalCredentialsSubBlob sub;
+ [value(0)] uint8 unknown3;
+ } supplementalCredentialsBlob;
+
+ void decode_supplementalCredentials(
+ [in] supplementalCredentialsBlob blob
+ );
+
+ typedef [public] struct {
+ [flag(STR_NOTERM|NDR_REMAINING)] string_array names;
+ } package_PackagesBlob;
+
+ void decode_Packages(
+ [in] package_PackagesBlob blob
+ );
+
+ typedef struct {
+ [value(2*strlen_m(string))] uint16 length;
+ [value(2*strlen_m(string))] uint16 size;
+ [relative,subcontext(0),subcontext_size(size),flag(STR_NOTERM|NDR_REMAINING)] string *string;
+ } package_PrimaryKerberosString;
+
+ typedef struct {
+ [value(0)] uint16 reserved1;
+ [value(0)] uint16 reserved2;
+ [value(0)] uint32 reserved3;
+ uint32 keytype;
+ [value((value?value->length:0))] uint32 value_len;
+ [relative,subcontext(0),subcontext_size(value_len),flag(NDR_REMAINING)] DATA_BLOB *value;
+ } package_PrimaryKerberosKey3;
+
+ typedef struct {
+ uint16 num_keys;
+ uint16 num_old_keys;
+ package_PrimaryKerberosString salt;
+ package_PrimaryKerberosKey3 keys[num_keys];
+ package_PrimaryKerberosKey3 old_keys[num_old_keys];
+ [value(0)] uint32 padding1;
+ [value(0)] uint32 padding2;
+ [value(0)] uint32 padding3;
+ [value(0)] uint32 padding4;
+ [value(0)] uint32 padding5;
+ } package_PrimaryKerberosCtr3;
+
+ typedef struct {
+ [value(0)] uint16 reserved1;
+ [value(0)] uint16 reserved2;
+ [value(0)] uint32 reserved3;
+ uint32 iteration_count;
+ uint32 keytype;
+ [value((value?value->length:0))] uint32 value_len;
+ [relative,subcontext(0),subcontext_size(value_len),flag(NDR_REMAINING)] DATA_BLOB *value;
+ } package_PrimaryKerberosKey4;
+
+ typedef struct {
+ uint16 num_keys;
+ [value(0)] uint16 num_service_keys;
+ uint16 num_old_keys;
+ uint16 num_older_keys;
+ package_PrimaryKerberosString salt;
+ uint32 default_iteration_count;
+ package_PrimaryKerberosKey4 keys[num_keys];
+ package_PrimaryKerberosKey4 service_keys[num_service_keys];
+ package_PrimaryKerberosKey4 old_keys[num_old_keys];
+ package_PrimaryKerberosKey4 older_keys[num_older_keys];
+ } package_PrimaryKerberosCtr4;
+
+ typedef [nodiscriminant] union {
+ [case(3)] package_PrimaryKerberosCtr3 ctr3;
+ [case(4)] package_PrimaryKerberosCtr4 ctr4;
+ } package_PrimaryKerberosCtr;
+
+ typedef [public] struct {
+ uint16 version;
+ [value(0)] uint16 flags;
+ [switch_is(version)] package_PrimaryKerberosCtr ctr;
+ } package_PrimaryKerberosBlob;
+
+ void decode_PrimaryKerberos(
+ [in] package_PrimaryKerberosBlob blob
+ );
+
+ typedef [public] struct {
+ [flag(STR_NOTERM|NDR_REMAINING)] string cleartext;
+ } package_PrimaryCLEARTEXTBlob;
+
+ void decode_PrimaryCLEARTEXT(
+ [in] package_PrimaryCLEARTEXTBlob blob
+ );
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint8 hash[16];
+ } package_PrimaryWDigestHash;
+
+ typedef [public] struct {
+ [value(0x31)] uint16 unknown1;
+ [value(0x01)] uint8 unknown2;
+ uint8 num_hashes;
+ [value(0)] uint32 unknown3;
+ [value(0)] udlong uuknown4;
+ package_PrimaryWDigestHash hashes[num_hashes];
+ } package_PrimaryWDigestBlob;
+
+ void decode_PrimaryWDigest(
+ [in] package_PrimaryWDigestBlob blob
+ );
+
+ typedef struct {
+ NTTIME time1;
+ uint32 unknown1;
+ /*
+ * the secret value is encoded as UTF16 if it's a string
+ * but krb5 trusts have random bytes here, so converting to UTF16
+ * mayfail...
+ *
+ * TODO: We should try handle the case of a random buffer in all places
+ * we deal with cleartext passwords from windows
+ *
+ * so we don't use this:
+ *
+ * uint32 value_len;
+ * [charset(UTF16)] uint8 value[value_len];
+ */
+ DATA_BLOB value;
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad;
+ } trustAuthInOutSecret1;
+
+ typedef struct {
+ [relative] trustAuthInOutSecret1 *value1;
+ [relative] trustAuthInOutSecret1 *value2;
+ } trustAuthInOutCtr1;
+
+ typedef struct {
+ NTTIME time1;
+ uint32 unknown1;
+ DATA_BLOB value;
+ NTTIME time2;
+ uint32 unknown2;
+ uint32 unknown3;
+ uint32 unknown4;
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad;
+ } trustAuthInOutSecret2V1;
+
+ typedef struct {
+ NTTIME time1;
+ uint32 unknown1;
+ DATA_BLOB value;
+ NTTIME time2;
+ uint32 unknown2;
+ uint32 unknown3;
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad;
+ } trustAuthInOutSecret2V2;
+
+ typedef struct {
+ [relative] trustAuthInOutSecret2V1 *value1;
+ [relative] trustAuthInOutSecret2V2 *value2;
+ } trustAuthInOutCtr2;
+
+ typedef [nodiscriminant] union {
+ [case(1)] trustAuthInOutCtr1 ctr1;
+ [case(2)] trustAuthInOutCtr2 ctr2;
+ } trustAuthInOutCtr;
+
+ typedef [public] struct {
+ uint32 version;
+ [switch_is(version)] trustAuthInOutCtr ctr;
+ } trustAuthInOutBlob;
+
+ void decode_trustAuthInOut(
+ [in] trustAuthInOutBlob blob
+ );
+
+ typedef [public] struct {
+ uint32 marker;
+ DATA_BLOB data;
+ } DsCompressedChunk;
+
+ typedef [public] struct {
+ DsCompressedChunk chunks[5];
+ } DsCompressedBlob;
+
+ void decode_DsCompressed(
+ [in] DsCompressedBlob blob
+ );
+}
diff --git a/source3/librpc/idl/drsuapi.idl b/source3/librpc/idl/drsuapi.idl
new file mode 100644
index 0000000000..56dd483054
--- /dev/null
+++ b/source3/librpc/idl/drsuapi.idl
@@ -0,0 +1,1601 @@
+#include "idl_types.h"
+
+import "security.idl", "misc.idl", "samr.idl";
+
+[
+ uuid("e3514235-4b06-11d1-ab04-00c04fc2dcd2"),
+ version(4.0),
+ endpoint("ncacn_np:[\\pipe\\lsass]","ncacn_np:[\\pipe\\protected_storage]", "ncacn_ip_tcp:", "ncalrpc:"),
+ authservice("ldap"),
+ helpstring("Active Directory Replication"),
+ helper("librpc/ndr/ndr_drsuapi.h"),
+ pointer_default(unique)
+]
+interface drsuapi
+{
+ typedef bitmap samr_GroupAttrs samr_GroupAttrs;
+
+ /*****************/
+ /* Function 0x00 */
+ typedef [bitmap32bit] bitmap {
+ DRSUAPI_SUPPORTED_EXTENSION_BASE = 0x00000001,
+ DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION = 0x00000002,
+ DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI = 0x00000004,
+ DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2 = 0x00000008,
+ DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS = 0x00000010,
+ DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1 = 0x00000020,
+ DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION = 0x00000040,
+ DRSUAPI_SUPPORTED_EXTENSION_00000080 = 0x00000080,
+ DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE = 0x00000100,
+ DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2 = 0x00000200,
+ DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION = 0x00000400,
+ DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2 = 0x00000800,
+ DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD= 0x00001000,
+ DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND = 0x00002000,
+ DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO = 0x00004000,
+ DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION = 0x00008000,
+ DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01 = 0x00010000,
+ DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP = 0x00020000,
+ DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY = 0x00040000,
+ DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3 = 0x00080000,
+ DRSUAPI_SUPPORTED_EXTENSION_00100000 = 0x00100000,
+ DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2 = 0x00200000,
+ DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6 = 0x00400000,
+ DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS = 0x00800000,
+ DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8 = 0x01000000,
+ DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5 = 0x02000000,
+ DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6 = 0x04000000,
+ /*
+ * the following 3 have the same value
+ * repadmin.exe /bind says that
+ */
+ DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3 = 0x08000000,
+ DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7 = 0x08000000,
+ DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT = 0x08000000,
+ DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS = 0x10000000,
+ DRSUAPI_SUPPORTED_EXTENSION_20000000 = 0x20000000,
+ DRSUAPI_SUPPORTED_EXTENSION_40000000 = 0x40000000,
+ DRSUAPI_SUPPORTED_EXTENSION_80000000 = 0x80000000
+ } drsuapi_SupportedExtensions;
+
+ typedef [bitmap32bit] bitmap {
+ DRSUAPI_SUPPORTED_EXTENSION_ADAM = 0x00000001,
+ DRSUAPI_SUPPORTED_EXTENSION_LH_BETA2 = 0x00000002
+ } drsuapi_SupportedExtensionsExt;
+
+ /* this is used by w2k */
+ typedef struct {
+ drsuapi_SupportedExtensions supported_extensions;
+ GUID site_guid;
+ uint32 pid;
+ } drsuapi_DsBindInfo24;
+
+ /* this is used by w2k3 */
+ typedef struct {
+ drsuapi_SupportedExtensions supported_extensions;
+ GUID site_guid;
+ uint32 pid;
+ uint32 repl_epoch;
+ } drsuapi_DsBindInfo28;
+
+ /* this is used by w2k8 */
+ typedef struct {
+ drsuapi_SupportedExtensions supported_extensions;
+ GUID site_guid;
+ uint32 pid;
+ uint32 repl_epoch;
+ drsuapi_SupportedExtensionsExt supported_extensions_ext;
+ GUID config_dn_guid;
+ } drsuapi_DsBindInfo48;
+
+ typedef struct {
+ [flag(NDR_REMAINING)] DATA_BLOB info;
+ } drsuapi_DsBindInfoFallBack;
+
+ typedef [nodiscriminant] union {
+ [case(24)][subcontext(4)] drsuapi_DsBindInfo24 info24;
+ [case(28)][subcontext(4)] drsuapi_DsBindInfo28 info28;
+ [case(48)][subcontext(4)] drsuapi_DsBindInfo48 info48;
+ [default][subcontext(4)] drsuapi_DsBindInfoFallBack FallBack;
+ } drsuapi_DsBindInfo;
+
+ /* the drsuapi_DsBindInfoCtr was this before
+ * typedef [flag(NDR_PAHEX)] struct {
+ * [range(1,10000)] uint32 length;
+ * [size_is(length)] uint8 data[];
+ * } drsuapi_DsBindInfo;
+ *
+ * but we don't want the caller to manually decode this blob,
+ * so we're doing it here
+ */
+
+ typedef struct {
+ [range(1,10000)] uint32 length;
+ [switch_is(length)] drsuapi_DsBindInfo info;
+ } drsuapi_DsBindInfoCtr;
+
+ /* this is a magic guid you need to pass to DsBind to make drsuapi_DsWriteAccountSpn() work
+ *
+ * maybe the bind_guid could also be the invocation_id see drsuapi_DsReplicaConnection04
+ */
+ const char *DRSUAPI_DS_BIND_GUID = "e24d201a-4fd6-11d1-a3da-0000f875ae0d";
+ /*
+ * this magic guid are needed to fetch the whole tree with drsuapi_DsGetNCChanges()
+ * as administrator and this values are also used in the destination_dsa_guid field
+ * of drsuapi_DsGetNCChangesReq5/8 and the source_dsa_guid is zero.
+ */
+ const char *DRSUAPI_DS_BIND_GUID_W2K = "6abec3d1-3054-41c8-a362-5a0c5b7d5d71";
+ const char *DRSUAPI_DS_BIND_GUID_W2K3 = "6afab99c-6e26-464a-975f-f58f105218bc";
+
+ [public] WERROR drsuapi_DsBind(
+ [in,unique] GUID *bind_guid,
+ [in,out,unique] drsuapi_DsBindInfoCtr *bind_info,
+ [out] policy_handle *bind_handle
+ );
+
+ /*****************/
+ /* Function 0x01 */
+ WERROR drsuapi_DsUnbind(
+ [in,out] policy_handle *bind_handle
+ );
+
+ /*****************/
+ /* Function 0x02 */
+ typedef [public,gensize] struct {
+ [value(ndr_size_drsuapi_DsReplicaObjectIdentifier(r, ndr->flags)-4)] uint32 __ndr_size;
+ [value(ndr_size_dom_sid28(&sid, ndr->flags))] uint32 __ndr_size_sid;
+ GUID guid;
+ dom_sid28 sid;
+ [value(strlen_m(dn))] uint32 __ndr_size_dn;
+ [charset(UTF16),size_is(__ndr_size_dn+1)] uint16 dn[];
+ } drsuapi_DsReplicaObjectIdentifier;
+
+ typedef [public] bitmap {
+ DRSUAPI_DS_REPLICA_SYNC_ASYNCHRONOUS_OPERATION = 0x00000001,
+ DRSUAPI_DS_REPLICA_SYNC_WRITEABLE = 0x00000002,
+ DRSUAPI_DS_REPLICA_SYNC_PERIODIC = 0x00000004,
+ DRSUAPI_DS_REPLICA_SYNC_INTERSITE_MESSAGING = 0x00000008,
+ DRSUAPI_DS_REPLICA_SYNC_ALL_SOURCES = 0x00000010,
+ DRSUAPI_DS_REPLICA_SYNC_FULL = 0x00000020,
+ DRSUAPI_DS_REPLICA_SYNC_URGENT = 0x00000040,
+ DRSUAPI_DS_REPLICA_SYNC_NO_DISCARD = 0x00000080,
+ DRSUAPI_DS_REPLICA_SYNC_FORCE = 0x00000100,
+ DRSUAPI_DS_REPLICA_SYNC_ADD_REFERENCE = 0x00000200,
+ DRSUAPI_DS_REPLICA_SYNC_NEVER_COMPLETED = 0x00000400,
+ DRSUAPI_DS_REPLICA_SYNC_TWO_WAY = 0x00000800,
+ DRSUAPI_DS_REPLICA_SYNC_NEVER_NOTIFY = 0x00001000,
+ DRSUAPI_DS_REPLICA_SYNC_INITIAL = 0x00002000,
+ DRSUAPI_DS_REPLICA_SYNC_USE_COMPRESSION = 0x00004000,
+ DRSUAPI_DS_REPLICA_SYNC_ABANDONED = 0x00008000,
+ DRSUAPI_DS_REPLICA_SYNC_INITIAL_IN_PROGRESS = 0x00010000,
+ DRSUAPI_DS_REPLICA_SYNC_PARTIAL_ATTRIBUTE_SET = 0x00020000,
+ DRSUAPI_DS_REPLICA_SYNC_REQUEUE = 0x00040000,
+ DRSUAPI_DS_REPLICA_SYNC_NOTIFICATION = 0x00080000,
+ DRSUAPI_DS_REPLICA_SYNC_ASYNCHRONOUS_REPLICA = 0x00100000,
+ DRSUAPI_DS_REPLICA_SYNC_CRITICAL = 0x00200000,
+ DRSUAPI_DS_REPLICA_SYNC_FULL_IN_PROGRESS = 0x00400000,
+ DRSUAPI_DS_REPLICA_SYNC_PREEMPTED = 0x00800000
+ } drsuapi_DsReplicaSyncOptions;
+
+ typedef struct {
+ drsuapi_DsReplicaObjectIdentifier *naming_context;
+ GUID source_dsa_guid;
+ astring *other_info; /* I assume this is related to the repsFromTo1OtherInfo dns_name */
+ drsuapi_DsReplicaSyncOptions options;
+ } drsuapi_DsReplicaSyncRequest1;
+
+ typedef [switch_type(int32)] union {
+ [case(1)] drsuapi_DsReplicaSyncRequest1 req1;
+ } drsuapi_DsReplicaSyncRequest;
+
+ WERROR drsuapi_DsReplicaSync(
+ [in] policy_handle *bind_handle,
+ [in] int32 level,
+ [in,switch_is(level)] drsuapi_DsReplicaSyncRequest req
+ );
+
+ /*****************/
+ /* Function 0x03 */
+ typedef [public] struct {
+ hyper tmp_highest_usn; /* updated after each object update */
+ hyper reserved_usn;
+ hyper highest_usn; /* updated after a full replication cycle */
+ } drsuapi_DsReplicaHighWaterMark;
+
+ typedef [public] struct {
+ GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */
+ hyper highest_usn; /* updated after a full replication cycle */
+ } drsuapi_DsReplicaCursor;
+
+ typedef struct {
+ [value(1)] uint32 version;
+ [value(0)] uint32 reserved1;
+ [range(0,0x100000)] uint32 count;
+ [value(0)] uint32 reserved2;
+ [size_is(count)] drsuapi_DsReplicaCursor cursors[];
+ } drsuapi_DsReplicaCursorCtrEx;
+
+ typedef [public] bitmap {
+ /* the _WRITEABLE flag indicates a replication with all attributes
+ *
+ * --metze
+ */
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE = 0x00000010,
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP = 0x00000020,
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS = 0x00000040,
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_USE_ASYNC_INTERSIDE_TRANSPORT = 0x00000080,
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_TWO_WAY_SYNC = 0x00000200,
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS = 0x00000800,
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS = 0x00001000, /* was 0x00010000, */
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_NEXT_PACKET = 0x00002000, /* was 0x00020000, */
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED = 0x00200000,
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_PREEMPTED = 0x01000000,
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_IGNORE_CHANGE_NOTIFICATIONS = 0x04000000,
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_DISABLE_SCHEDULED_SYNC = 0x08000000,
+ /*
+ * the following NOTE applies to DsGetNCChangesRequest5:
+ * - the data is only compressed when 10 or more objects are replicated
+ * - but there could also be a size limit of 35 KBytes or something like that
+ * - the reply is DsGetNCChangesCtr2
+ * - maybe the same applies to DsGetNCChangesRequest8...
+ *
+ * --metze
+ */
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES = 0x10000000,
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_NO_CHANGE_NOTIFICATIONS = 0x20000000,
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_PARTIAL_ATTRIBUTE_SET = 0x40000000
+ } drsuapi_DsReplicaNeighbourFlags;
+
+ typedef [flag(NDR_PAHEX),v1_enum] enum {
+ DRSUAPI_EXOP_NONE = 0x00000000,
+ DRSUAPI_EXOP_FSMO_REQ_ROLE = 0x00000001,
+ DRSUAPI_EXOP_FSMO_RID_ALLOC = 0x00000002,
+ DRSUAPI_EXOP_FSMO_RID_REQ_ROLE = 0x00000003,
+ DRSUAPI_EXOP_FSMO_REQ_PDC = 0x00000004,
+ DRSUAPI_EXOP_FSMO_ABANDON_ROLE = 0x00000005,
+ DRSUAPI_EXOP_REPL_OBJ = 0x00000006,
+ DRSUAPI_EXOP_REPL_SECRET = 0x00000007
+ } drsuapi_DsExtendedOperation;
+
+ typedef [flag(NDR_PAHEX),v1_enum] enum {
+ DRSUAPI_EXOP_ERR_NONE = 0x00000000,
+ DRSUAPI_EXOP_ERR_SUCCESS = 0x00000001,
+ DRSUAPI_EXOP_ERR_UNKNOWN_OP = 0x00000002,
+ DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER = 0x00000003,
+ DRSUAPI_EXOP_ERR_UPDATE_ERR = 0x00000004,
+ DRSUAPI_EXOP_ERR_EXCEPTION = 0x00000005,
+ DRSUAPI_EXOP_ERR_UNKNOWN_CALLER = 0x00000006,
+ DRSUAPI_EXOP_ERR_RID_ALLOC = 0x00000007,
+ DRSUAPI_EXOP_ERR_FSMO_OWNER_DELETED = 0x00000008,
+ DRSUAPI_EXOP_ERR_FMSO_PENDING_OP = 0x00000009,
+ DRSUAPI_EXOP_ERR_MISMATCH = 0x0000000A,
+ DRSUAPI_EXOP_ERR_COULDNT_CONTACT = 0x0000000B,
+ DRSUAPI_EXOP_ERR_FSMO_REFUSING_ROLES = 0x0000000C,
+ DRSUAPI_EXOP_ERR_DIR_ERROR = 0x0000000D,
+ DRSUAPI_EXOP_ERR_FSMO_MISSING_SETTINGS = 0x0000000E,
+ DRSUAPI_EXOP_ERR_ACCESS_DENIED = 0x0000000F,
+ DRSUAPI_EXOP_ERR_PARAM_ERROR = 0x00000010
+ } drsuapi_DsExtendedError;
+
+ typedef struct {
+ GUID destination_dsa_guid;
+ GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */
+ [ref] drsuapi_DsReplicaObjectIdentifier *naming_context;
+ drsuapi_DsReplicaHighWaterMark highwatermark;
+ drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
+ drsuapi_DsReplicaNeighbourFlags replica_flags;
+ uint32 max_object_count; /* w2k3 uses min(133,max(100,max_object_count)) */
+ uint32 max_ndr_size; /* w2k3 seems to ignore this */
+ drsuapi_DsExtendedOperation extended_op;
+ hyper fsmo_info;
+ } drsuapi_DsGetNCChangesRequest5;
+
+ /*
+ * In DRSUAPI all attributes with syntax 2.5.5.2
+ * are identified by uint32 values
+ *
+ * the following table shows the mapping used between the two representations
+ * e.g. - objectClass 'nTDSDSA' has governsID: 1.2.840.113556.1.5.7000.47
+ * and a UINT32-ID of '0x0017002F'.
+ * - so the OID 1.2.840.113556.1.5.7000.47 is splitted into a
+ * OID-prefix: 1.2.840.113556.1.5.7000
+ * and a value: 47 => 0x2F
+ * - the mapping table gives a UINT32-prefix: 0x00170000
+ * - and the UINT32-ID is 0x0017002F = 0x00170000 | 0x2F
+ *
+ * This prefix mapping table is replied in the drsuapi_DsReplicaOIDMapping_Ctr
+ * array. The following are the default mappings of w2k3
+ *
+ * OID-prefix => UINT32-Id prefix
+ *
+ * 2.5.4.* => 0x00000000 (standard attributes RFC2256 core.schema)
+ * 2.5.6.* => 0x00010000 (standard object classes RFC2256 core.schema)
+ * 1.2.840.113556.1.2.* => 0x00020000
+ * 1.2.840.113556.1.3.* => 0x00030000
+ * 2.5.5.* => 0x00080000 (attributeSyntax OID's)
+ * 1.2.840.113556.1.4.* => 0x00090000
+ * 1.2.840.113556.1.5.* => 0x000A0000
+ * 2.16.840.1.113730.3.* => 0x00140000
+ * 0.9.2342.19200300.100.1.* => 0x00150000
+ * 2.16.840.1.113730.3.1.* => 0x00160000
+ * 1.2.840.113556.1.5.7000.* => 0x00170000
+ * 2.5.21.* => 0x00180000 (attrs for SubSchema)
+ * 2.5.18.* => 0x00190000 (createTimeStamp,modifyTimeStamp, SubSchema)
+ * 2.5.20.* => 0x001A0000
+ * 1.3.6.1.4.1.1466.101.119.* => 0x001B0000 (dynamicObject, entryTTL)
+ * 2.16.840.1.113730.3.2.* => 0x001C0000
+ * 1.3.6.1.4.1.250.1.* => 0x001D0000
+ * 1.2.840.113549.1.9.* => 0x001E0000 (unstructuredAddress,unstructuredName)
+ * 0.9.2342.19200300.100.4.* => 0x001F0000
+ *
+ * Here's a list of used 'attributeSyntax' OID's
+ *
+ * 2.5.5.1 => Object(DS-DN) string
+ * struct drsuapi_DsObjectIdentifier3
+ *
+ * 2.5.5.2 => OID-string
+ * => all values are represented as uint32 values in drsuapi
+ * => governsID, attributeID and attributeSyntax returned as OID-Strings in LDAP
+ * => mayContain, mustContain and all other attributes with 2.5.5.2 syntax
+ * are returned as attribute names
+ *
+ * 2.5.5.4 => String(Teletex) case-insensitive string with teletex charset
+ *
+ * 2.5.5.5 => String(IA5) case-sensitive string
+ *
+ * 2.5.5.6 => String(Numeric)
+ * => eg. internationalISDNNumber
+ *
+ * 2.5.5.7 => Object(DN-Binary) B:<byte count>:<bytes>:<object DN>
+ * => e.g. wellKnownObjects
+ *
+ * 2.5.5.8 => BOOL
+ *
+ * 2.5.5.9 => int32
+ *
+ * 2.5.5.10 => DATA_BLOB
+ * => struct GUID
+ *
+ * 2.5.5.11 => LDAP timestring
+ * => NTTIME_1sec
+ *
+ * 2.5.5.12 => String(Unicode) case-insensitive string
+ * => 'standard strings'
+ *
+ * 2.5.5.13 => Object(Presentation-Address) string
+ * => used in objectClass applicationEntity
+ *
+ * 2.5.5.14 => Object(DN-String) S:<char count>:<string>:<object DN>
+ * => not used
+ *
+ * 2.5.5.15 => ntSecurityDescriptor
+ *
+ * 2.5.5.16 => int64
+ *
+ * 2.5.5.17 => dom_sid
+ */
+ typedef [nopush,nopull] struct {
+ [range(0,10000),value(ndr_size_drsuapi_DsReplicaOID_oid(oid, 0))] uint32 __ndr_size;
+ [size_is(__ndr_size),charset(DOS)] uint8 *oid; /* it's encoded with asn1_write_OID_String() */
+ } drsuapi_DsReplicaOID;
+
+ typedef struct {
+ uint32 id_prefix;
+ drsuapi_DsReplicaOID oid;
+ } drsuapi_DsReplicaOIDMapping;
+
+ typedef [public] struct {
+ [range(0,0x100000)] uint32 num_mappings;
+ [size_is(num_mappings)] drsuapi_DsReplicaOIDMapping *mappings;
+ } drsuapi_DsReplicaOIDMapping_Ctr;
+
+ typedef [flag(NDR_PAHEX),v1_enum] enum {
+ DRSUAPI_OBJECTCLASS_top = 0x00010000,
+ DRSUAPI_OBJECTCLASS_classSchema = 0x0003000d,
+ DRSUAPI_OBJECTCLASS_attributeSchema = 0x0003000e
+ } drsuapi_DsObjectClassId;
+
+ typedef [flag(NDR_PAHEX),v1_enum,public] enum {
+ DRSUAPI_ATTRIBUTE_objectClass = 0x00000000,
+ DRSUAPI_ATTRIBUTE_description = 0x0000000d,
+ DRSUAPI_ATTRIBUTE_member = 0x0000001f,
+ DRSUAPI_ATTRIBUTE_instanceType = 0x00020001,
+ DRSUAPI_ATTRIBUTE_whenCreated = 0x00020002,
+ DRSUAPI_ATTRIBUTE_hasMasterNCs = 0x0002000e,
+ DRSUAPI_ATTRIBUTE_governsID = 0x00020016,
+ DRSUAPI_ATTRIBUTE_attributeID = 0x0002001e,
+ DRSUAPI_ATTRIBUTE_attributeSyntax = 0x00020020,
+ DRSUAPI_ATTRIBUTE_isSingleValued = 0x00020021,
+ DRSUAPI_ATTRIBUTE_rangeLower = 0x00020022,
+ DRSUAPI_ATTRIBUTE_rangeUpper = 0x00020023,
+ DRSUAPI_ATTRIBUTE_dMDLocation = 0x00020024,
+ DRSUAPI_ATTRIBUTE_objectVersion = 0x0002004c,
+ DRSUAPI_ATTRIBUTE_invocationId = 0x00020073,
+ DRSUAPI_ATTRIBUTE_showInAdvancedViewOnly = 0x000200a9,
+ DRSUAPI_ATTRIBUTE_adminDisplayName = 0x000200c2,
+ DRSUAPI_ATTRIBUTE_adminDescription = 0x000200e2,
+ DRSUAPI_ATTRIBUTE_oMSyntax = 0x000200e7,
+ DRSUAPI_ATTRIBUTE_ntSecurityDescriptor = 0x00020119,
+ DRSUAPI_ATTRIBUTE_searchFlags = 0x0002014e,
+ DRSUAPI_ATTRIBUTE_lDAPDisplayName = 0x000201cc,
+ DRSUAPI_ATTRIBUTE_name = 0x00090001,
+ DRSUAPI_ATTRIBUTE_userAccountControl = 0x00090008,
+ DRSUAPI_ATTRIBUTE_currentValue = 0x0009001b,
+ DRSUAPI_ATTRIBUTE_homeDirectory = 0x0009002c,
+ DRSUAPI_ATTRIBUTE_homeDrive = 0x0009002d,
+ DRSUAPI_ATTRIBUTE_scriptPath = 0x0009003e,
+ DRSUAPI_ATTRIBUTE_profilePath = 0x0009008b,
+ DRSUAPI_ATTRIBUTE_objectSid = 0x00090092,
+ DRSUAPI_ATTRIBUTE_schemaIDGUID = 0x00090094,
+ DRSUAPI_ATTRIBUTE_dBCSPwd = 0x00090037,/* lmPwdHash */
+ DRSUAPI_ATTRIBUTE_logonHours = 0x00090040,
+ DRSUAPI_ATTRIBUTE_userWorkstations = 0x00090056,
+ DRSUAPI_ATTRIBUTE_unicodePwd = 0x0009005a,/* ntPwdHash */
+ DRSUAPI_ATTRIBUTE_ntPwdHistory = 0x0009005e,
+ DRSUAPI_ATTRIBUTE_priorValue = 0x00090064,
+ DRSUAPI_ATTRIBUTE_supplementalCredentials = 0x0009007d,
+ DRSUAPI_ATTRIBUTE_trustAuthIncoming = 0x00090081,
+ DRSUAPI_ATTRIBUTE_trustAuthOutgoing = 0x00090087,
+ DRSUAPI_ATTRIBUTE_lmPwdHistory = 0x000900a0,
+ DRSUAPI_ATTRIBUTE_sAMAccountName = 0x000900dd,
+ DRSUAPI_ATTRIBUTE_sAMAccountType = 0x0009012e,
+ DRSUAPI_ATTRIBUTE_fSMORoleOwner = 0x00090171,
+ DRSUAPI_ATTRIBUTE_systemFlags = 0x00090177,
+ DRSUAPI_ATTRIBUTE_serverReference = 0x00090203,
+ DRSUAPI_ATTRIBUTE_serverReferenceBL = 0x00090204,
+ DRSUAPI_ATTRIBUTE_initialAuthIncoming = 0x0009021b,
+ DRSUAPI_ATTRIBUTE_initialAuthOutgoing = 0x0009021c,
+ DRSUAPI_ATTRIBUTE_wellKnownObjects = 0x0009026a,
+ DRSUAPI_ATTRIBUTE_dNSHostName = 0x0009026b,
+ DRSUAPI_ATTRIBUTE_isMemberOfPartialAttributeSet = 0x0009027f,
+ DRSUAPI_ATTRIBUTE_userPrincipalName = 0x00090290,
+ DRSUAPI_ATTRIBUTE_groupType = 0x000902ee,
+ DRSUAPI_ATTRIBUTE_servicePrincipalName = 0x00090303,
+ DRSUAPI_ATTRIBUTE_objectCategory = 0x0009030e,
+ DRSUAPI_ATTRIBUTE_gPLink = 0x0009037b,
+ DRSUAPI_ATTRIBUTE_msDS_Behavior_Version = 0x000905b3,
+ DRSUAPI_ATTRIBUTE_msDS_KeyVersionNumber = 0x000906f6,
+ DRSUAPI_ATTRIBUTE_msDS_HasDomainNCs = 0x0009071c,
+ DRSUAPI_ATTRIBUTE_msDS_hasMasterNCs = 0x0009072c
+ } drsuapi_DsAttributeId;
+
+ typedef struct {
+ [value(1)] uint32 version;
+ [value(0)] uint32 reserved1;
+ [range(1,0x100000)] uint32 num_attids;
+ [size_is(num_attids)] drsuapi_DsAttributeId attids[];
+ } drsuapi_DsPartialAttributeSet;
+
+ typedef struct {
+ GUID destination_dsa_guid;
+ GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */
+ [ref] drsuapi_DsReplicaObjectIdentifier *naming_context;
+ drsuapi_DsReplicaHighWaterMark highwatermark;
+ drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
+ drsuapi_DsReplicaNeighbourFlags replica_flags;
+ uint32 max_object_count; /* w2k3 uses min(133,max(100,max_object_count)) */
+ uint32 max_ndr_size; /* w2k3 seems to ignore this */
+ drsuapi_DsExtendedOperation extended_op;
+ hyper fsmo_info;
+ drsuapi_DsPartialAttributeSet *partial_attribute_set;
+ drsuapi_DsPartialAttributeSet *partial_attribute_set_ex;
+ drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr;
+ } drsuapi_DsGetNCChangesRequest8;
+
+ typedef [switch_type(int32)] union {
+ [case(5)] drsuapi_DsGetNCChangesRequest5 req5;
+ [case(8)] drsuapi_DsGetNCChangesRequest8 req8;
+ } drsuapi_DsGetNCChangesRequest;
+
+ typedef [public] struct {
+ GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */
+ hyper highest_usn; /* updated after a full replication cycle */
+ NTTIME last_sync_success;
+ } drsuapi_DsReplicaCursor2;
+
+ typedef struct {
+ [value(2)] uint32 version;
+ [value(0)] uint32 reserved1;
+ [range(0,0x100000)] uint32 count;
+ [value(0)] uint32 reserved2;
+ [size_is(count)] drsuapi_DsReplicaCursor2 cursors[];
+ } drsuapi_DsReplicaCursor2CtrEx;
+
+ /* Generic DATA_BLOB values */
+ typedef struct {
+ [range(0,10485760),value(ndr_size_DATA_BLOB(0,blob,0))] uint32 __ndr_size;
+ DATA_BLOB *blob;
+ } drsuapi_DsAttributeValue;
+
+ typedef struct {
+ [range(0,10485760)] uint32 num_values;
+ [size_is(num_values)] drsuapi_DsAttributeValue *values;
+ } drsuapi_DsAttributeValueCtr;
+
+ /* DN String values */
+ typedef [public,gensize] struct {
+ [value(ndr_size_drsuapi_DsReplicaObjectIdentifier3(r, ndr->flags))] uint32 __ndr_size;
+ [value(ndr_size_dom_sid28(&sid,ndr->flags))] uint32 __ndr_size_sid;
+ GUID guid;
+ dom_sid28 sid;
+ [value(strlen_m(dn))] uint32 __ndr_size_dn;
+ [charset(UTF16)] uint16 dn[__ndr_size_dn+1];
+ } drsuapi_DsReplicaObjectIdentifier3;
+
+ typedef [public,gensize] struct {
+ [value(ndr_size_drsuapi_DsReplicaObjectIdentifier3Binary(r, ndr->flags))] uint32 __ndr_size;
+ [value(ndr_size_dom_sid28(&sid,ndr->flags))] uint32 __ndr_size_sid;
+ GUID guid;
+ dom_sid28 sid;
+ [value(strlen_m(dn))] uint32 __ndr_size_dn;
+ [charset(UTF16)] uint16 dn[__ndr_size_dn+1];
+ [value(binary.length + 4)] uint32 __ndr_size_binary;
+ [flag(NDR_REMAINING)] DATA_BLOB binary;
+ } drsuapi_DsReplicaObjectIdentifier3Binary;
+
+ typedef [public] struct {
+ drsuapi_DsAttributeId attid;
+ drsuapi_DsAttributeValueCtr value_ctr;
+ } drsuapi_DsReplicaAttribute;
+
+ typedef struct {
+ [range(0,1048576)] uint32 num_attributes;
+ [size_is(num_attributes)] drsuapi_DsReplicaAttribute *attributes;
+ } drsuapi_DsReplicaAttributeCtr;
+
+ typedef [public] bitmap {
+ DRSUAPI_DS_REPLICA_OBJECT_FROM_MASTER = 0x00000001,
+ DRSUAPI_DS_REPLICA_OBJECT_DYNAMIC = 0x00000002,
+ DRSUAPI_DS_REPLICA_OBJECT_REMOTE_MODIFY = 0x00010000
+ } drsuapi_DsReplicaObjectFlags;
+
+ typedef [public] struct {
+ drsuapi_DsReplicaObjectIdentifier *identifier;
+ drsuapi_DsReplicaObjectFlags flags;
+ drsuapi_DsReplicaAttributeCtr attribute_ctr;
+ } drsuapi_DsReplicaObject;
+
+ typedef struct {
+ uint32 version;
+ NTTIME_1sec originating_change_time;
+ GUID originating_invocation_id;
+ hyper originating_usn;
+ } drsuapi_DsReplicaMetaData;
+
+ typedef [public] struct {
+ [range(0,1048576)] uint32 count;
+ [size_is(count)] drsuapi_DsReplicaMetaData meta_data[];
+ } drsuapi_DsReplicaMetaDataCtr;
+
+ typedef [public,noprint] struct {
+ drsuapi_DsReplicaObjectListItemEx *next_object;
+ drsuapi_DsReplicaObject object;
+ boolean32 is_nc_prefix;
+ GUID *parent_object_guid;
+ drsuapi_DsReplicaMetaDataCtr *meta_data_ctr;
+ } drsuapi_DsReplicaObjectListItemEx;
+
+ typedef [public,gensize] struct {
+ GUID source_dsa_guid; /* the 'objectGUID' field of the CN=NTDS Settings object */
+ GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */
+ drsuapi_DsReplicaObjectIdentifier *naming_context;
+ drsuapi_DsReplicaHighWaterMark old_highwatermark;
+ drsuapi_DsReplicaHighWaterMark new_highwatermark;
+ drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
+ drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr;
+ drsuapi_DsExtendedError extended_ret; /* w2k sends the nc_object_count value here */
+ uint32 object_count;
+ /* this +55 is sometimes +56, so I don't know where this comes from... --metze */
+ [value(ndr_size_drsuapi_DsGetNCChangesCtr1(r,ndr->flags)+55)] uint32 __ndr_size;
+ drsuapi_DsReplicaObjectListItemEx *first_object;
+ boolean32 more_data;
+ } drsuapi_DsGetNCChangesCtr1;
+
+ /*
+ * if the DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE flag
+ * isn't there it means the value is deleted
+ */
+ typedef [public] bitmap {
+ DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE = 0x00000001
+ } drsuapi_DsLinkedAttributeFlags;
+
+ typedef [public] struct {
+ drsuapi_DsReplicaObjectIdentifier *identifier;
+ drsuapi_DsAttributeId attid;
+ drsuapi_DsAttributeValue value;
+ drsuapi_DsLinkedAttributeFlags flags;
+ NTTIME_1sec originating_add_time;
+ drsuapi_DsReplicaMetaData meta_data;
+ } drsuapi_DsReplicaLinkedAttribute;
+
+ typedef [public,gensize] struct {
+ GUID source_dsa_guid; /* the 'objectGUID' field of the CN=NTDS Settings object */
+ GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */
+ drsuapi_DsReplicaObjectIdentifier *naming_context;
+ drsuapi_DsReplicaHighWaterMark old_highwatermark;
+ drsuapi_DsReplicaHighWaterMark new_highwatermark;
+ drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
+ drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr;
+ drsuapi_DsExtendedError extended_ret;
+ uint32 object_count;
+ /* this +55 is sometimes +56, so I don't know where this comes from... --metze */
+ [value(ndr_size_drsuapi_DsGetNCChangesCtr6(r,ndr->flags)+55)] uint32 __ndr_size;
+ drsuapi_DsReplicaObjectListItemEx *first_object;
+ boolean32 more_data;
+ uint32 nc_object_count; /* estimated amount of objects in the whole NC */
+ uint32 nc_linked_attributes_count; /* estimated amount of linked values in the whole NC */
+ [range(0,1048576)] uint32 linked_attributes_count;
+ [size_is(linked_attributes_count)] drsuapi_DsReplicaLinkedAttribute *linked_attributes;
+ WERROR drs_error;
+ } drsuapi_DsGetNCChangesCtr6;
+
+ typedef struct {
+ uint32 decompressed_length;
+ uint32 compressed_length;
+ [subcontext(4),subcontext_size(compressed_length),
+ compression(NDR_COMPRESSION_MSZIP,compressed_length,decompressed_length)]
+ drsuapi_DsGetNCChangesCtr1 *ctr1;
+ } drsuapi_DsGetNCChangesMSZIPCtr1;
+
+ typedef struct {
+ uint32 decompressed_length;
+ uint32 compressed_length;
+ [subcontext(4),subcontext_size(compressed_length),
+ compression(NDR_COMPRESSION_MSZIP,compressed_length,decompressed_length)]
+ drsuapi_DsGetNCChangesCtr6 *ctr6;
+ } drsuapi_DsGetNCChangesMSZIPCtr6;
+
+ typedef struct {
+ uint32 decompressed_length;
+ uint32 compressed_length;
+ [subcontext(4),subcontext_size(compressed_length),
+ compression(NDR_COMPRESSION_XPRESS,compressed_length,decompressed_length)]
+ drsuapi_DsGetNCChangesCtr1 *ctr1;
+ } drsuapi_DsGetNCChangesXPRESSCtr1;
+
+ typedef struct {
+ uint32 decompressed_length;
+ uint32 compressed_length;
+ [subcontext(4),subcontext_size(compressed_length),
+ compression(NDR_COMPRESSION_XPRESS,compressed_length,decompressed_length)]
+ drsuapi_DsGetNCChangesCtr6 *ctr6;
+ } drsuapi_DsGetNCChangesXPRESSCtr6;
+
+ typedef [enum16bit] enum {
+ DRSUAPI_COMPRESSION_TYPE_MSZIP = 2,
+ DRSUAPI_COMPRESSION_TYPE_XPRESS = 3
+ } drsuapi_DsGetNCChangesCompressionType;
+
+ typedef [nodiscriminant,flag(NDR_PAHEX)] union {
+ [case(1|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16))] drsuapi_DsGetNCChangesMSZIPCtr1 mszip1;
+ [case(6|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16))] drsuapi_DsGetNCChangesMSZIPCtr6 mszip6;
+ [case(1|(DRSUAPI_COMPRESSION_TYPE_XPRESS<<16))] drsuapi_DsGetNCChangesXPRESSCtr1 xpress1;
+ [case(6|(DRSUAPI_COMPRESSION_TYPE_XPRESS<<16))] drsuapi_DsGetNCChangesXPRESSCtr6 xpress6;
+ } drsuapi_DsGetNCChangesCompressedCtr;
+
+ typedef struct {
+ /*
+ * this is a bit ugly, as the compression depends on the flags
+ * in the DsBind(), but only w2k uses DsGetNCChangesReq5
+ * and will get DsGetNCChangesCtr2 replies, and w2k only knowns
+ * about MSZIP and level 1 replies
+ */
+ [switch_is(1|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16))] drsuapi_DsGetNCChangesCompressedCtr ctr;
+ } drsuapi_DsGetNCChangesCtr2;
+
+ typedef struct {
+ [range(0,6)] int32 level;
+ [range(2,3)] drsuapi_DsGetNCChangesCompressionType type;
+ [switch_is(level | (type<<16))] drsuapi_DsGetNCChangesCompressedCtr ctr;
+ } drsuapi_DsGetNCChangesCtr7;
+
+ typedef [switch_type(int32)] union {
+ [case(1)] drsuapi_DsGetNCChangesCtr1 ctr1;
+ [case(2)] drsuapi_DsGetNCChangesCtr2 ctr2;
+ [case(6)] drsuapi_DsGetNCChangesCtr6 ctr6;
+ [case(7)] drsuapi_DsGetNCChangesCtr7 ctr7;
+ } drsuapi_DsGetNCChangesCtr;
+
+ WERROR drsuapi_DsGetNCChanges(
+ [in] policy_handle *bind_handle,
+ [in] int32 level,
+ [in,ref,switch_is(level)] drsuapi_DsGetNCChangesRequest *req,
+ [out,ref] int32 *level_out,
+ [out,ref,switch_is(*level_out)] drsuapi_DsGetNCChangesCtr *ctr
+ );
+
+ /*****************/
+ /* Function 0x04 */
+ typedef bitmap {
+ DRSUAPI_DS_REPLICA_UPDATE_ASYNCHRONOUS_OPERATION = 0x00000001,
+ DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE = 0x00000002,
+ DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE = 0x00000004,
+ DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE = 0x00000008,
+ DRSUAPI_DS_REPLICA_UPDATE_0x00000010 = 0x00000010
+ } drsuapi_DsReplicaUpdateRefsOptions;
+
+ typedef struct {
+ [ref] drsuapi_DsReplicaObjectIdentifier *naming_context;
+ [ref,charset(DOS),string] uint8 *dest_dsa_dns_name;
+ GUID dest_dsa_guid;
+ drsuapi_DsReplicaUpdateRefsOptions options;
+ } drsuapi_DsReplicaUpdateRefsRequest1;
+
+ typedef [switch_type(int32)] union {
+ [case(1)] drsuapi_DsReplicaUpdateRefsRequest1 req1;
+ } drsuapi_DsReplicaUpdateRefsRequest;
+
+ WERROR drsuapi_DsReplicaUpdateRefs(
+ [in] policy_handle *bind_handle,
+ [in] int32 level,
+ [in,switch_is(level)] drsuapi_DsReplicaUpdateRefsRequest req
+ );
+
+ /*****************/
+ /* Function 0x05 */
+ typedef bitmap {
+ DRSUAPI_DS_REPLICA_ADD_ASYNCHRONOUS_OPERATION = 0x00000001,
+ DRSUAPI_DS_REPLICA_ADD_WRITEABLE = 0x00000002
+ /* TODO ... */
+ } drsuapi_DsReplicaAddOptions;
+
+ WERROR DRSUAPI_REPLICA_ADD();
+
+ /*****************/
+ /* Function 0x06 */
+ typedef bitmap {
+ DRSUAPI_DS_REPLICA_DELETE_ASYNCHRONOUS_OPERATION = 0x00000001,
+ DRSUAPI_DS_REPLICA_DELETE_WRITEABLE = 0x00000002
+ /* TODO ... */
+ } drsuapi_DsReplicaDeleteOptions;
+
+ WERROR DRSUAPI_REPLICA_DEL();
+
+ /*****************/
+ /* Function 0x07 */
+ typedef bitmap {
+ DRSUAPI_DS_REPLICA_MODIFY_ASYNCHRONOUS_OPERATION = 0x00000001,
+ DRSUAPI_DS_REPLICA_MODIFY_WRITEABLE = 0x00000002
+ } drsuapi_DsReplicaModifyOptions;
+
+ WERROR DRSUAPI_REPLICA_MODIFY();
+
+ /*****************/
+ /* Function 0x08 */
+ WERROR DRSUAPI_VERIFY_NAMES();
+
+ /*****************/
+ /* Function 0x09 */
+
+ /* how are type 4 and 7 different from 2 and 3 ? */
+ typedef [v1_enum] enum {
+ DRSUAPI_DS_MEMBERSHIP_TYPE_UNIVERSAL_AND_DOMAIN_GROUPS = 1,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_LOCAL_GROUPS = 2,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_GROUPS = 3,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_LOCAL_GROUPS2 = 4,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_UNIVERSAL_GROUPS = 5,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_GROUPMEMBERS = 6,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_GROUPS2 = 7
+ } drsuapi_DsMembershipType;
+
+ typedef struct {
+ NTSTATUS status;
+ [range(0,10000)] uint32 num_memberships;
+ [range(0,10000)] uint32 num_sids;
+ [size_is(num_memberships)] drsuapi_DsReplicaObjectIdentifier **info_array;
+ [size_is(num_memberships)] samr_GroupAttrs *group_attrs;
+ [size_is(num_sids)] dom_sid28 **sids;
+ } drsuapi_DsGetMembershipsCtr1;
+
+ typedef [switch_type(int32)] union {
+ [case(1)] drsuapi_DsGetMembershipsCtr1 ctr1;
+ } drsuapi_DsGetMembershipsCtr;
+
+ const int DRSUAPI_DS_MEMBERSHIP_FLAG_GROUP_ATTR = 0x1;
+
+ typedef struct {
+ [range(1,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsReplicaObjectIdentifier **info_array;
+ uint32 flags;
+ drsuapi_DsMembershipType type;
+ drsuapi_DsReplicaObjectIdentifier *domain;
+ } drsuapi_DsGetMembershipsRequest1;
+
+ typedef [switch_type(int32)] union {
+ [case(1)] drsuapi_DsGetMembershipsRequest1 req1;
+ } drsuapi_DsGetMembershipsRequest;
+
+ WERROR drsuapi_DsGetMemberships(
+ [in] policy_handle *bind_handle,
+ [in] int32 level,
+ [in,ref] [switch_is(level)] drsuapi_DsGetMembershipsRequest *req,
+ [out,ref] int32 *level_out,
+ [out,ref] [switch_is(*level_out)] drsuapi_DsGetMembershipsCtr *ctr
+ );
+
+ /*****************/
+ /* Function 0x0a */
+ WERROR DRSUAPI_INTER_DOMAIN_MOVE();
+
+ /*****************/
+ /* Function 0x0b */
+ typedef struct {
+ uint32 unknown1;
+ uint32 unknown2;
+ [range(0,0x00A00000)] uint32 length;
+ [size_is(length)] uint8 *data;
+ } drsuapi_DsGetNT4ChangeLogRequest1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsGetNT4ChangeLogRequest1 req1;
+ } drsuapi_DsGetNT4ChangeLogRequest;
+
+ typedef struct {
+ [range(0,0x00A00000)] uint32 length1;
+ [range(0,0x00A00000)] uint32 length2;
+ hyper unknown1;
+ NTTIME time2;
+ hyper unknown3;
+ NTTIME time4;
+ hyper unknown5;
+ NTTIME time6;
+ NTSTATUS status;
+ [size_is(length1)] uint8 *data1;
+ [size_is(length2)] uint8 *data2;
+ } drsuapi_DsGetNT4ChangeLogInfo1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsGetNT4ChangeLogInfo1 info1;
+ } drsuapi_DsGetNT4ChangeLogInfo;
+
+ WERROR drsuapi_DsGetNT4ChangeLog(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in,ref] [switch_is(level)] drsuapi_DsGetNT4ChangeLogRequest *req,
+ [out,ref] uint32 *level_out,
+ [out,ref] [switch_is(*level_out)] drsuapi_DsGetNT4ChangeLogInfo *info
+ );
+
+ /*****************/
+ /* Function 0x0c */
+ typedef [v1_enum] enum {
+ DRSUAPI_DS_NAME_STATUS_OK = 0,
+ DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR = 1,
+ DRSUAPI_DS_NAME_STATUS_NOT_FOUND = 2,
+ DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE = 3,
+ DRSUAPI_DS_NAME_STATUS_NO_MAPPING = 4,
+ DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY = 5,
+ DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING = 6,
+ DRSUAPI_DS_NAME_STATUS_TRUST_REFERRAL = 7
+ } drsuapi_DsNameStatus;
+
+ typedef [v1_enum] enum {
+ DRSUAPI_DS_NAME_FLAG_NO_FLAGS = 0x0,
+ DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY = 0x1,
+ DRSUAPI_DS_NAME_FLAG_EVAL_AT_DC = 0x2,
+ DRSUAPI_DS_NAME_FLAG_GCVERIFY = 0x4,
+ DRSUAPI_DS_NAME_FLAG_TRUST_REFERRAL = 0x8
+ } drsuapi_DsNameFlags;
+
+ typedef [v1_enum] enum {
+ DRSUAPI_DS_NAME_FORMAT_UKNOWN = 0,
+ DRSUAPI_DS_NAME_FORMAT_FQDN_1779 = 1,
+ DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT = 2,
+ DRSUAPI_DS_NAME_FORMAT_DISPLAY = 3,
+ DRSUAPI_DS_NAME_FORMAT_GUID = 6,
+ DRSUAPI_DS_NAME_FORMAT_CANONICAL = 7,
+ DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL = 8,
+ DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX = 9,
+ DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL = 10,
+ DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY = 11,
+ DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN = 12
+ } drsuapi_DsNameFormat;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *str;
+ } drsuapi_DsNameString;
+
+ typedef struct {
+ uint32 codepage; /* 0x000004e4 - 1252 is german codepage*/
+ uint32 language; /* 0x00000407 - german language ID*/
+ drsuapi_DsNameFlags format_flags;
+ drsuapi_DsNameFormat format_offered;
+ drsuapi_DsNameFormat format_desired;
+ [range(1,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsNameString *names;
+ } drsuapi_DsNameRequest1;
+
+ typedef [switch_type(int32)] union {
+ [case(1)] drsuapi_DsNameRequest1 req1;
+ } drsuapi_DsNameRequest;
+
+ typedef struct {
+ drsuapi_DsNameStatus status;
+ [charset(UTF16),string] uint16 *dns_domain_name;
+ [charset(UTF16),string] uint16 *result_name;
+ } drsuapi_DsNameInfo1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] drsuapi_DsNameInfo1 *array;
+ } drsuapi_DsNameCtr1;
+
+ typedef [switch_type(int32)] union {
+ [case(1)] drsuapi_DsNameCtr1 *ctr1;
+ } drsuapi_DsNameCtr;
+
+ WERROR drsuapi_DsCrackNames(
+ [in] policy_handle *bind_handle,
+ [in] int32 level,
+ [in,ref,switch_is(level)] drsuapi_DsNameRequest *req,
+ [out,ref] int32 *level_out,
+ [out,ref,switch_is(*level_out)] drsuapi_DsNameCtr *ctr
+ );
+
+ /*****************/
+ /* Function 0x0d */
+ typedef [v1_enum] enum {
+ DRSUAPI_DS_SPN_OPERATION_ADD = 0,
+ DRSUAPI_DS_SPN_OPERATION_REPLACE= 1,
+ DRSUAPI_DS_SPN_OPERATION_DELETE = 2
+ } drsuapi_DsSpnOperation;
+
+ typedef struct {
+ drsuapi_DsSpnOperation operation;
+ uint32 unknown1;
+ [charset(UTF16),string] uint16 *object_dn;
+ [range(0,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsNameString *spn_names;
+ } drsuapi_DsWriteAccountSpnRequest1;
+
+ typedef [switch_type(int32)] union {
+ [case(1)] drsuapi_DsWriteAccountSpnRequest1 req1;
+ } drsuapi_DsWriteAccountSpnRequest;
+
+ typedef struct {
+ WERROR status;
+ } drsuapi_DsWriteAccountSpnResult1;
+
+ typedef [switch_type(int32)] union {
+ [case(1)] drsuapi_DsWriteAccountSpnResult1 res1;
+ } drsuapi_DsWriteAccountSpnResult;
+
+ WERROR drsuapi_DsWriteAccountSpn(
+ [in] policy_handle *bind_handle,
+ [in] int32 level,
+ [in,ref,switch_is(level)] drsuapi_DsWriteAccountSpnRequest *req,
+ [out,ref] int32 *level_out,
+ [out,ref,switch_is(*level_out)] drsuapi_DsWriteAccountSpnResult *res
+ );
+
+ /*****************/
+ /* Function 0x0e */
+ typedef struct {
+ [charset(UTF16),string] uint16 *server_dn;
+ [charset(UTF16),string] uint16 *domain_dn;
+ uint32 unknown; /* 0x000000001 */
+ } drsuapi_DsRemoveDSServerRequest1;
+
+ typedef [switch_type(int32)] union {
+ [case(1)] drsuapi_DsRemoveDSServerRequest1 req1;
+ } drsuapi_DsRemoveDSServerRequest;
+
+ typedef struct {
+ WERROR status;
+ } drsuapi_DsRemoveDSServerResult1;
+
+ typedef [switch_type(int32)] union {
+ [case(1)] drsuapi_DsRemoveDSServerResult1 res1;
+ } drsuapi_DsRemoveDSServerResult;
+
+ WERROR drsuapi_DsRemoveDSServer(
+ [in] policy_handle *bind_handle,
+ [in] int32 level,
+ [in,ref,switch_is(level)] drsuapi_DsRemoveDSServerRequest *req,
+ [out,ref] int32 *level_out,
+ [out,ref,switch_is(*level_out)] drsuapi_DsRemoveDSServerResult *res
+ );
+
+ /*****************/
+ /* Function 0x0f */
+ WERROR DRSUAPI_REMOVE_DS_DOMAIN();
+
+ /*****************/
+ /* Function 0x10 */
+ typedef struct {
+ [charset(UTF16),string] uint16 *domain_name; /* netbios or dns */
+ int32 level; /* specifies the switch level for the request */
+ } drsuapi_DsGetDCInfoRequest1;
+
+ typedef [switch_type(int32)] union {
+ [case(1)] drsuapi_DsGetDCInfoRequest1 req1;
+ } drsuapi_DsGetDCInfoRequest;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *netbios_name;
+ [charset(UTF16),string] uint16 *dns_name;
+ [charset(UTF16),string] uint16 *site_name;
+ [charset(UTF16),string] uint16 *computer_dn;
+ [charset(UTF16),string] uint16 *server_dn;
+ uint32 is_pdc;
+ uint32 is_enabled;
+ } drsuapi_DsGetDCInfo1;
+
+ typedef struct {
+ [range(0,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsGetDCInfo1 *array;
+ } drsuapi_DsGetDCInfoCtr1;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *netbios_name;
+ [charset(UTF16),string] uint16 *dns_name;
+ [charset(UTF16),string] uint16 *site_name;
+ [charset(UTF16),string] uint16 *site_dn;
+ [charset(UTF16),string] uint16 *computer_dn;
+ [charset(UTF16),string] uint16 *server_dn;
+ [charset(UTF16),string] uint16 *ntds_dn;
+ uint32 is_pdc;
+ uint32 is_enabled;
+ uint32 is_gc;
+ GUID site_guid;
+ GUID computer_guid;
+ GUID server_guid;
+ GUID ntds_guid;
+ } drsuapi_DsGetDCInfo2;
+
+ typedef struct {
+ [range(0,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsGetDCInfo2 *array;
+ } drsuapi_DsGetDCInfoCtr2;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *netbios_name;
+ [charset(UTF16),string] uint16 *dns_name;
+ [charset(UTF16),string] uint16 *site_name;
+ [charset(UTF16),string] uint16 *site_dn;
+ [charset(UTF16),string] uint16 *computer_dn;
+ [charset(UTF16),string] uint16 *server_dn;
+ [charset(UTF16),string] uint16 *ntds_dn;
+ uint32 is_pdc;
+ uint32 is_enabled;
+ uint32 is_gc;
+ uint32 is_rodc;
+ GUID site_guid;
+ GUID computer_guid;
+ GUID server_guid;
+ GUID ntds_guid;
+ } drsuapi_DsGetDCInfo3;
+
+ typedef struct {
+ [range(0,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsGetDCInfo3 *array;
+ } drsuapi_DsGetDCInfoCtr3;
+
+ /*
+ * this represents an active connection to the
+ * Directory System Agent (DSA)
+ * this can be via LDAP or DRSUAPI
+ */
+ typedef struct {
+ [flag(NDR_BIG_ENDIAN)] ipv4address client_ip_address;
+ uint32 unknown2;
+ uint32 connection_time; /* in seconds */
+ uint32 unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ /*
+ * client_account can be the following:
+ * "W2K3\Administrator"
+ * "Administrator@W2K3"
+ * "cn=Administrator,cn=Users,DC=w2k3,DC=vmnet1,DC=vm,DC=base"
+ * ""
+ * or NULL
+ */
+ [charset(UTF16),string] uint16 *client_account;
+ } drsuapi_DsGetDCConnection01;
+
+ typedef struct {
+ [range(0,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsGetDCConnection01 *array;
+ } drsuapi_DsGetDCConnectionCtr01;
+
+ typedef [v1_enum] enum {
+ DRSUAPI_DC_INFO_CTR_1 = 1,
+ DRSUAPI_DC_INFO_CTR_2 = 2,
+ DRSUAPI_DC_INFO_CTR_3 = 3,
+ DRSUAPI_DC_CONNECTION_CTR_01 = -1
+ } drsuapi_DsGetDCInfoCtrLevels;
+
+ typedef [switch_type(int32)] union {
+ [case(DRSUAPI_DC_INFO_CTR_1)] drsuapi_DsGetDCInfoCtr1 ctr1;
+ [case(DRSUAPI_DC_INFO_CTR_2)] drsuapi_DsGetDCInfoCtr2 ctr2;
+ [case(DRSUAPI_DC_INFO_CTR_3)] drsuapi_DsGetDCInfoCtr3 ctr3;
+ [case(DRSUAPI_DC_CONNECTION_CTR_01)] drsuapi_DsGetDCConnectionCtr01 ctr01;
+ } drsuapi_DsGetDCInfoCtr;
+
+ WERROR drsuapi_DsGetDomainControllerInfo(
+ [in] policy_handle *bind_handle,
+ [in] int32 level,
+ [in,ref,switch_is(level)] drsuapi_DsGetDCInfoRequest *req,
+ [out,ref] int32 *level_out,
+ [out,ref,switch_is(*level_out)] drsuapi_DsGetDCInfoCtr *ctr
+ );
+
+ /*****************/
+ /* Function 0x11 */
+ typedef [public,noprint] struct {
+ drsuapi_DsReplicaObjectListItem *next_object;
+ drsuapi_DsReplicaObject object;
+ } drsuapi_DsReplicaObjectListItem;
+
+ /*
+ * The DsAddEntry() call which creates a nTDSDSA object,
+ * also adds a servicePrincipalName in the following form
+ * to the computer account of the new domain controller
+ * referenced by the "serverReferenece" attribute.
+ *
+ * E3514235-4B06-11D1-AB04-00C04FC2DCD2/<new-ntdsdsa-object-guid-as-string>/<domain-dns-name>
+ *
+ * also note that the "serverReference" isn't added to the new object!
+ */
+ const char *DRSUAPI_NTDSDSA_KRB5_SERVICE_GUID = "E3514235-4B06-11D1-AB04-00C04FC2DCD2";
+
+ /*
+ * please note the the current idl
+ * for DsAddEntry does only parse
+ * what I saw between 2 w2k3 boxes
+ * in my dssync experiments I got some other replies
+ * so all I want to say is that this is very incomplete yet...
+ * --metze
+ */
+ typedef struct {
+ drsuapi_DsReplicaObjectListItem first_object;
+ } drsuapi_DsAddEntryRequest2;
+
+ typedef [switch_type(int32)] union {
+ [case(2)] drsuapi_DsAddEntryRequest2 req2;
+ } drsuapi_DsAddEntryRequest;
+
+ typedef struct {
+ uint32 unknown1;
+ WERROR status;
+ uint32 unknown2;
+ uint16 unknown3;
+ } drsuapi_DsAddEntryErrorInfoX;
+
+ typedef struct {
+ [range(0,10485760)] uint32 size;
+ [size_is(size)] uint8 *data;
+ } drsuapi_DsAddEntryExtraErrorBuffer;
+
+ typedef struct {
+ drsuapi_DsAddEntryErrorInfoX error;
+ drsuapi_DsAttributeId attid;
+ uint32 unknown2;
+ drsuapi_DsAddEntryExtraErrorBuffer buffer;
+ } drsuapi_DsAddEntryExtraError1;
+
+ typedef /*[noprint]*/ struct {
+ drsuapi_DsAddEntryErrorListItem1 *next;
+ drsuapi_DsAddEntryExtraError1 error;
+ } drsuapi_DsAddEntryErrorListItem1;
+
+ typedef struct {
+ drsuapi_DsReplicaObjectIdentifier *id;
+ WERROR status;
+ drsuapi_DsAddEntryErrorListItem1 first;
+ } drsuapi_DsAddEntryErrorInfo1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsAddEntryErrorInfo1 error1;
+/* [case(2)] drsuapi_DsAddEntryErrorInfo2 error2;
+ [case(3)] drsuapi_DsAddEntryErrorInfo3 error3;
+*/ [case(4)] drsuapi_DsAddEntryErrorInfoX errorX;
+ [case(5)] drsuapi_DsAddEntryErrorInfoX errorX;
+ [case(6)] drsuapi_DsAddEntryErrorInfoX errorX;
+ [case(7)] drsuapi_DsAddEntryErrorInfoX errorX;
+ } drsuapi_DsAddEntryErrorInfo;
+
+ typedef struct {
+ WERROR status;
+ uint32 level;
+ [switch_is(level)] drsuapi_DsAddEntryErrorInfo *info;
+ } drsuapi_DsAddEntryError1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsAddEntryError1 info1;
+ } drsuapi_DsAddEntryError;
+
+ typedef struct {
+ GUID guid;
+ dom_sid28 sid;
+ } drsuapi_DsReplicaObjectIdentifier2;
+
+ typedef struct {
+ drsuapi_DsReplicaObjectIdentifier *id;
+ uint32 unknown1;
+ drsuapi_DsAddEntryErrorInfoX error;
+ [range(0,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsReplicaObjectIdentifier2 *objects;
+ } drsuapi_DsAddEntryCtr2;
+
+ typedef struct {
+ drsuapi_DsReplicaObjectIdentifier *id;
+ uint32 level;
+ [switch_is(level)] drsuapi_DsAddEntryError *error;
+ [range(0,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsReplicaObjectIdentifier2 *objects;
+ } drsuapi_DsAddEntryCtr3;
+
+ typedef [switch_type(int32)] union {
+ [case(2)] drsuapi_DsAddEntryCtr2 ctr2;
+ [case(3)] drsuapi_DsAddEntryCtr3 ctr3;
+ } drsuapi_DsAddEntryCtr;
+
+ [public] WERROR drsuapi_DsAddEntry(
+ [in] policy_handle *bind_handle,
+ [in] int32 level,
+ [in,ref,switch_is(level)] drsuapi_DsAddEntryRequest *req,
+ [out,ref] int32 *level_out,
+ [out,ref,switch_is(*level_out)] drsuapi_DsAddEntryCtr *ctr
+ );
+
+ /*****************/
+ /* Function 0x12 */
+ WERROR DRSUAPI_EXECUTE_KCC();
+
+ /*****************/
+ /* Function 0x13 */
+ typedef [v1_enum] enum {
+ DRSUAPI_DS_REPLICA_GET_INFO = 1,
+ DRSUAPI_DS_REPLICA_GET_INFO2 = 2
+ } drsuapi_DsReplicaGetInfoLevel;
+
+ typedef [v1_enum] enum {
+ DRSUAPI_DS_REPLICA_INFO_NEIGHBORS = 0,
+ DRSUAPI_DS_REPLICA_INFO_CURSORS = 1,
+ DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA = 2,
+ DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES = 3,
+ DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES = 4,
+ DRSUAPI_DS_REPLICA_INFO_PENDING_OPS = 5,
+ DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA = 6,
+ DRSUAPI_DS_REPLICA_INFO_CURSORS2 = 7,
+ DRSUAPI_DS_REPLICA_INFO_CURSORS3 = 8,
+ DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2 = 9,
+ DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2 = 10,
+ DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02 = -2,
+ DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04 = -4,
+ DRSUAPI_DS_REPLICA_INFO_CURSORS05 = -5,
+ DRSUAPI_DS_REPLICA_INFO_06 = -6
+ } drsuapi_DsReplicaInfoType;
+
+ typedef struct {
+ drsuapi_DsReplicaInfoType info_type;
+ [charset(UTF16),string] uint16 *object_dn;
+ GUID guid1;
+ } drsuapi_DsReplicaGetInfoRequest1;
+
+ typedef struct {
+ drsuapi_DsReplicaInfoType info_type;
+ [charset(UTF16),string] uint16 *object_dn;
+ GUID guid1;
+ uint32 unknown1;
+ [charset(UTF16),string] uint16 *string1;
+ [charset(UTF16),string] uint16 *string2;
+ uint32 unknown2;
+ } drsuapi_DsReplicaGetInfoRequest2;
+
+ typedef [switch_type(drsuapi_DsReplicaGetInfoLevel)] union {
+ [case(DRSUAPI_DS_REPLICA_GET_INFO)] drsuapi_DsReplicaGetInfoRequest1 req1;
+ [case(DRSUAPI_DS_REPLICA_GET_INFO2)] drsuapi_DsReplicaGetInfoRequest2 req2;
+ } drsuapi_DsReplicaGetInfoRequest;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *naming_context_dn;
+ [charset(UTF16),string] uint16 *source_dsa_obj_dn;
+ [charset(UTF16),string] uint16 *source_dsa_address;
+ [charset(UTF16),string] uint16 *transport_obj_dn;
+ drsuapi_DsReplicaNeighbourFlags replica_flags;
+ uint32 reserved;
+ GUID naming_context_obj_guid;
+ GUID source_dsa_obj_guid;
+ GUID source_dsa_invocation_id;
+ GUID transport_obj_guid;
+ hyper tmp_highest_usn;
+ hyper highest_usn;
+ NTTIME last_success;
+ NTTIME last_attempt;
+ WERROR result_last_attempt;
+ uint32 consecutive_sync_failures;
+ } drsuapi_DsReplicaNeighbour;
+
+ typedef struct {
+ uint32 count;
+ uint32 reserved;
+ [size_is(count)] drsuapi_DsReplicaNeighbour array[];
+ } drsuapi_DsReplicaNeighbourCtr;
+
+ typedef struct {
+ uint32 count;
+ uint32 reserved;
+ [size_is(count)] drsuapi_DsReplicaCursor array[];
+ } drsuapi_DsReplicaCursorCtr;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *attribute_name;
+ uint32 version;
+ NTTIME originating_change_time;
+ GUID originating_invocation_id;
+ hyper originating_usn;
+ hyper local_usn;
+ } drsuapi_DsReplicaObjMetaData;
+
+ typedef struct {
+ uint32 count;
+ uint32 reserved;
+ [size_is(count)] drsuapi_DsReplicaObjMetaData array[];
+ } drsuapi_DsReplicaObjMetaDataCtr;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *dsa_obj_dn;
+ GUID dsa_obj_guid;
+ NTTIME first_failure;
+ uint32 num_failures;
+ WERROR last_result;
+ } drsuapi_DsReplicaKccDsaFailure;
+
+ typedef struct {
+ uint32 count;
+ uint32 reserved;
+ [size_is(count)] drsuapi_DsReplicaKccDsaFailure array[];
+ } drsuapi_DsReplicaKccDsaFailuresCtr;
+
+ typedef enum {
+ DRSUAPI_DS_REPLICA_OP_TYPE_SYNC = 0,
+ DRSUAPI_DS_REPLICA_OP_TYPE_ADD = 1,
+ DRSUAPI_DS_REPLICA_OP_TYPE_DELETE = 2,
+ DRSUAPI_DS_REPLICA_OP_TYPE_MODIFY = 3,
+ DRSUAPI_DS_REPLICA_OP_TYPE_UPDATE_REFS = 4
+ } drsuapi_DsReplicaOpType;
+
+ typedef [switch_type(drsuapi_DsReplicaOpType)] union {
+ [case(DRSUAPI_DS_REPLICA_OP_TYPE_SYNC)] drsuapi_DsReplicaSyncOptions sync;
+ [case(DRSUAPI_DS_REPLICA_OP_TYPE_ADD)] drsuapi_DsReplicaAddOptions add;
+ [case(DRSUAPI_DS_REPLICA_OP_TYPE_DELETE)] drsuapi_DsReplicaDeleteOptions op_delete;
+ [case(DRSUAPI_DS_REPLICA_OP_TYPE_MODIFY)] drsuapi_DsReplicaModifyOptions modify;
+ [case(DRSUAPI_DS_REPLICA_OP_TYPE_UPDATE_REFS)] drsuapi_DsReplicaUpdateRefsOptions update_refs;
+ [default] uint32 unknown;
+ } drsuapi_DsRplicaOpOptions;
+
+ typedef struct {
+ NTTIME operation_start;
+ uint32 serial_num; /* unique till reboot */
+ uint32 priority;
+ drsuapi_DsReplicaOpType operation_type;
+ [switch_is(operation_type)] drsuapi_DsRplicaOpOptions options;
+ [charset(UTF16),string] uint16 *nc_dn;
+ [charset(UTF16),string] uint16 *remote_dsa_obj_dn;
+ [charset(UTF16),string] uint16 *remote_dsa_address;
+ GUID nc_obj_guid;
+ GUID remote_dsa_obj_guid;
+ } drsuapi_DsReplicaOp;
+
+ typedef struct {
+ NTTIME time;
+ uint32 count;
+ [size_is(count)] drsuapi_DsReplicaOp array[];
+ } drsuapi_DsReplicaOpCtr;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *attribute_name;
+ [charset(UTF16),string] uint16 *object_dn;
+ [value(ndr_size_DATA_BLOB(0,binary,0))] uint32 __ndr_size_binary;
+ DATA_BLOB *binary;
+ NTTIME deleted;
+ NTTIME created;
+ uint32 version;
+ NTTIME originating_change_time;
+ GUID originating_invocation_id;
+ hyper originating_usn;
+ hyper local_usn;
+ } drsuapi_DsReplicaAttrValMetaData;
+
+ typedef struct {
+ uint32 count;
+ int32 enumeration_context;
+ [size_is(count)] drsuapi_DsReplicaAttrValMetaData array[];
+ } drsuapi_DsReplicaAttrValMetaDataCtr;
+
+ typedef struct {
+ uint32 count;
+ int32 enumeration_context;
+ [size_is(count)] drsuapi_DsReplicaCursor2 array[];
+ } drsuapi_DsReplicaCursor2Ctr;
+
+ typedef struct {
+ GUID source_dsa_invocation_id;
+ hyper highest_usn;
+ NTTIME last_sync_success;
+ [charset(UTF16),string] uint16 *source_dsa_obj_dn;
+ } drsuapi_DsReplicaCursor3;
+
+ typedef struct {
+ uint32 count;
+ int32 enumeration_context;
+ [size_is(count)] drsuapi_DsReplicaCursor3 array[];
+ } drsuapi_DsReplicaCursor3Ctr;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *attribute_name;
+ uint32 version;
+ NTTIME originating_change_time;
+ GUID originating_invocation_id;
+ hyper originating_usn;
+ hyper local_usn;
+ [charset(UTF16),string] uint16 *originating_dsa_dn;
+ } drsuapi_DsReplicaObjMetaData2;
+
+ typedef struct {
+ uint32 count;
+ int32 enumeration_context;
+ [size_is(count)] drsuapi_DsReplicaObjMetaData2 array[];
+ } drsuapi_DsReplicaObjMetaData2Ctr;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *attribute_name;
+ [charset(UTF16),string] uint16 *object_dn;
+ [value(ndr_size_DATA_BLOB(0,binary,0))] uint32 __ndr_size_binary;
+ DATA_BLOB *binary;
+ NTTIME deleted;
+ NTTIME created;
+ uint32 version;
+ NTTIME originating_change_time;
+ GUID originating_invocation_id;
+ hyper originating_usn;
+ hyper local_usn;
+ [charset(UTF16),string] uint16 *originating_dsa_dn;
+ } drsuapi_DsReplicaAttrValMetaData2;
+
+ typedef struct {
+ uint32 count;
+ int32 enumeration_context;
+ [size_is(count)] drsuapi_DsReplicaAttrValMetaData2 array[];
+ } drsuapi_DsReplicaAttrValMetaData2Ctr;
+
+ typedef struct {
+ hyper u1; /* session number? */
+ uint32 u2;
+ uint32 u3;
+ GUID bind_guid;
+ NTTIME_1sec bind_time;
+ [flag(NDR_BIG_ENDIAN)] ipv4address client_ip_address;
+ uint32 u5; /* this is the same value the client used as pid in the DsBindInfoX struct */
+ } drsuapi_DsReplicaConnection04;
+
+ typedef struct {
+ [range(0,10000)] uint32 count;
+ uint32 reserved;
+ [size_is(count)] drsuapi_DsReplicaConnection04 array[];
+ } drsuapi_DsReplicaConnection04Ctr;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *str1;
+ uint32 u1;
+ uint32 u2;
+ uint32 u3;
+ uint32 u4;
+ uint32 u5;
+ hyper u6;
+ uint32 u7;
+ } drsuapi_DsReplica06;
+
+ typedef struct {
+ [range(0,256)] uint32 count;
+ uint32 reserved;
+ [size_is(count)] drsuapi_DsReplica06 array[];
+ } drsuapi_DsReplica06Ctr;
+
+ typedef [switch_type(drsuapi_DsReplicaInfoType)] union {
+ [case(DRSUAPI_DS_REPLICA_INFO_NEIGHBORS)] drsuapi_DsReplicaNeighbourCtr *neighbours;
+ [case(DRSUAPI_DS_REPLICA_INFO_CURSORS)] drsuapi_DsReplicaCursorCtr *cursors;
+ [case(DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA)] drsuapi_DsReplicaObjMetaDataCtr *objmetadata;
+ [case(DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES)] drsuapi_DsReplicaKccDsaFailuresCtr *connectfailures;
+ [case(DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES)] drsuapi_DsReplicaKccDsaFailuresCtr *linkfailures;
+ [case(DRSUAPI_DS_REPLICA_INFO_PENDING_OPS)] drsuapi_DsReplicaOpCtr *pendingops;
+ [case(DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA)] drsuapi_DsReplicaAttrValMetaDataCtr *attrvalmetadata;
+ [case(DRSUAPI_DS_REPLICA_INFO_CURSORS2)] drsuapi_DsReplicaCursor2Ctr *cursors2;
+ [case(DRSUAPI_DS_REPLICA_INFO_CURSORS3)] drsuapi_DsReplicaCursor3Ctr *cursors3;
+ [case(DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2)] drsuapi_DsReplicaObjMetaData2Ctr *objmetadata2;
+ [case(DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2)] drsuapi_DsReplicaAttrValMetaData2Ctr *attrvalmetadata2;
+ [case(DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02)] drsuapi_DsReplicaNeighbourCtr *neighbours02;
+ [case(DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04)] drsuapi_DsReplicaConnection04Ctr *connections04;
+ [case(DRSUAPI_DS_REPLICA_INFO_CURSORS05)] drsuapi_DsReplicaCursorCtrEx *cursors05;
+ [case(DRSUAPI_DS_REPLICA_INFO_06)] drsuapi_DsReplica06Ctr *i06;
+ } drsuapi_DsReplicaInfo;
+
+ WERROR drsuapi_DsReplicaGetInfo(
+ [in] policy_handle *bind_handle,
+ [in] drsuapi_DsReplicaGetInfoLevel level,
+ [in,ref,switch_is(level)] drsuapi_DsReplicaGetInfoRequest *req,
+ [out,ref] drsuapi_DsReplicaInfoType *info_type,
+ [out,ref,switch_is(*info_type)] drsuapi_DsReplicaInfo *info
+ );
+
+ /*****************/
+ /* Function 0x14 */
+ WERROR DRSUAPI_ADD_SID_HISTORY();
+
+ /*****************/
+ /* Function 0x15 */
+
+ typedef struct {
+ [range(0,10000)] uint32 num_entries;
+ [size_is(num_entries)] drsuapi_DsGetMembershipsCtr1 **ctrl_array;
+ } drsuapi_DsGetMemberships2Ctr1;
+
+ typedef [switch_type(int32)] union {
+ [case(1)] drsuapi_DsGetMembershipsCtr1 ctr1;
+ } drsuapi_DsGetMemberships2Ctr;
+
+ typedef struct {
+ [range(1,10000)] uint32 num_req;
+ [size_is(num_req)] drsuapi_DsGetMembershipsRequest1 **req_array;
+ } drsuapi_DsGetMemberships2Request1;
+
+ typedef [switch_type(int32)] union {
+ [case(1)] drsuapi_DsGetMemberships2Request1 req1;
+ } drsuapi_DsGetMemberships2Request;
+
+ WERROR drsuapi_DsGetMemberships2(
+ [in] policy_handle *bind_handle,
+ [in] int32 level,
+ [in,ref] [switch_is(level)] drsuapi_DsGetMemberships2Request *req,
+ [out,ref] int32 *level_out,
+ [out,ref] [switch_is(*level_out)] drsuapi_DsGetMemberships2Ctr *ctr
+ );
+
+
+ /*****************/
+ /* Function 0x16 */
+ WERROR DRSUAPI_REPLICA_VERIFY_OBJECTS();
+
+ /*****************/
+ /* Function 0x17 */
+ WERROR DRSUAPI_GET_OBJECT_EXISTENCE();
+
+ /*****************/
+ /* Function 0x18 */
+ typedef struct {
+ WERROR error_code;
+ uint32 site_cost;
+ } drsuapi_DsSiteCostInfo;
+
+ typedef struct {
+ [range(0,10000)] uint32 num_info;
+ [size_is(num_info)] drsuapi_DsSiteCostInfo *info;
+ uint32 unknown;
+ } drsuapi_QuerySitesByCostCtr1;
+
+ typedef [switch_type(int32)] union {
+ [case(1)] drsuapi_QuerySitesByCostCtr1 ctr1;
+ } drsuapi_QuerySitesByCostCtr;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *site_from;
+ [range(1,10000)] uint32 num_req;
+ [size_is(num_req)] [charset(UTF16),string] uint16 **site_to;
+ uint32 flags;
+ } drsuapi_QuerySitesByCostRequest1;
+
+ typedef [switch_type(int32)] union {
+ [case(1)] drsuapi_QuerySitesByCostRequest1 req1;
+ } drsuapi_QuerySitesByCostRequest;
+
+ WERROR drsuapi_QuerySitesByCost(
+ [in] policy_handle *bind_handle,
+ [in] int32 level,
+ [in,ref] [switch_is(level)] drsuapi_QuerySitesByCostRequest *req,
+ [out,ref] int32 *level_out,
+ [out,ref] [switch_is(*level_out)] drsuapi_QuerySitesByCostCtr *ctr
+ );
+}
diff --git a/source3/librpc/idl/dssetup.idl b/source3/librpc/idl/dssetup.idl
new file mode 100644
index 0000000000..af6350cc43
--- /dev/null
+++ b/source3/librpc/idl/dssetup.idl
@@ -0,0 +1,101 @@
+/*
+ dssetup interface definition
+*/
+
+import "misc.idl";
+
+[
+ uuid("3919286a-b10c-11d0-9ba8-00c04fd92ef5"),
+ version(0.0),
+ endpoint("ncacn_np:[\\pipe\\lsarpc]", "ncacn_np:[\\pipe\\lsass]", "ncacn_ip_tcp:", "ncalrpc:"),
+ pointer_default(unique),
+ helpstring("Active Directory Setup")
+] interface dssetup
+{
+ /**********************************************/
+ /* Function 0x00 */
+
+ typedef enum {
+ DS_ROLE_STANDALONE_WORKSTATION = 0,
+ DS_ROLE_MEMBER_WORKSTATION = 1,
+ DS_ROLE_STANDALONE_SERVER = 2,
+ DS_ROLE_MEMBER_SERVER = 3,
+ DS_ROLE_BACKUP_DC = 4,
+ DS_ROLE_PRIMARY_DC = 5
+ } dssetup_DsRole;
+
+ typedef [bitmap32bit] bitmap {
+ DS_ROLE_PRIMARY_DS_RUNNING = 0x00000001,
+ DS_ROLE_PRIMARY_DS_MIXED_MODE = 0x00000002,
+ DS_ROLE_UPGRADE_IN_PROGRESS = 0x00000004,
+ DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT = 0x01000000
+ } dssetup_DsRoleFlags;
+
+ typedef struct {
+ dssetup_DsRole role;
+ dssetup_DsRoleFlags flags;
+ [charset(UTF16),string] uint16 *domain;
+ [charset(UTF16),string] uint16 *dns_domain;
+ [charset(UTF16),string] uint16 *forest;
+ GUID domain_guid;
+ } dssetup_DsRolePrimaryDomInfoBasic;
+
+ typedef [v1_enum] enum {
+ DS_ROLE_NOT_UPGRADING = 0,
+ DS_ROLE_UPGRADING = 1
+ } dssetup_DsUpgrade;
+
+ typedef enum {
+ DS_ROLE_PREVIOUS_UNKNOWN = 0,
+ DS_ROLE_PREVIOUS_PRIMARY = 1,
+ DS_ROLE_PREVIOUS_BACKUP = 2
+ } dssetup_DsPrevious;
+
+ typedef struct {
+ dssetup_DsUpgrade upgrading;
+ dssetup_DsPrevious previous_role;
+ } dssetup_DsRoleUpgradeStatus;
+
+ typedef enum {
+ DS_ROLE_OP_IDLE = 0,
+ DS_ROLE_OP_ACTIVE = 1,
+ DS_ROLE_OP_NEEDS_REBOOT = 2
+ } dssetup_DsRoleOp;
+
+ typedef struct {
+ dssetup_DsRoleOp status;
+ } dssetup_DsRoleOpStatus;
+
+ typedef enum {
+ DS_ROLE_BASIC_INFORMATION = 1,
+ DS_ROLE_UPGRADE_STATUS = 2,
+ DS_ROLE_OP_STATUS = 3
+ } dssetup_DsRoleInfoLevel;
+
+ typedef [switch_type(dssetup_DsRoleInfoLevel)] union {
+ [case(DS_ROLE_BASIC_INFORMATION)] dssetup_DsRolePrimaryDomInfoBasic basic;
+ [case(DS_ROLE_UPGRADE_STATUS)] dssetup_DsRoleUpgradeStatus upgrade;
+ [case(DS_ROLE_OP_STATUS)] dssetup_DsRoleOpStatus opstatus;
+ } dssetup_DsRoleInfo;
+
+ WERROR dssetup_DsRoleGetPrimaryDomainInformation(
+ [in] dssetup_DsRoleInfoLevel level,
+ [out,switch_is(level),unique] dssetup_DsRoleInfo *info
+ );
+
+ /*
+ w2k3 has removed all the calls below from their implementation.
+ These stubs are left here only as a way of documenting the names
+ of the calls in case they ever turn up on the wire.
+ */
+ WERROR dssetup_DsRoleDnsNameToFlatName();
+ WERROR dssetup_DsRoleDcAsDc();
+ WERROR dssetup_DsRoleDcAsReplica();
+ WERROR dssetup_DsRoleDemoteDc();
+ WERROR dssetup_DsRoleGetDcOperationProgress();
+ WERROR dssetup_DsRoleGetDcOperationResults();
+ WERROR dssetup_DsRoleCancel();
+ WERROR dssetup_DsRoleServerSaveStateForUpgrade();
+ WERROR dssetup_DsRoleUpgradeDownlevelServer();
+ WERROR dssetup_DsRoleAbortDownlevelServerUpgrade();
+}
diff --git a/source3/librpc/idl/echo.idl b/source3/librpc/idl/echo.idl
new file mode 100644
index 0000000000..5ea37f1ac1
--- /dev/null
+++ b/source3/librpc/idl/echo.idl
@@ -0,0 +1,127 @@
+
+[
+ uuid("60a15ec5-4de8-11d7-a637-005056a20182"),
+ endpoint("ncacn_np:[\\pipe\\rpcecho]", "ncacn_ip_tcp:", "ncalrpc:"),
+ pointer_default(unique),
+ version(1.0),
+ helpstring("Simple echo pipe")
+]
+interface rpcecho
+{
+ /* Add one to an integer */
+ void echo_AddOne(
+ [in] uint32 in_data,
+ [out] uint32 *out_data
+ );
+ /* Echo an array of bytes back at the caller */
+ void echo_EchoData(
+ [in] uint32 len,
+ [in] [size_is(len)] uint8 in_data[],
+ [out] [size_is(len)] uint8 out_data[]
+ );
+ /* Sink data to the server */
+ void echo_SinkData(
+ [in] uint32 len,
+ [in,size_is(len)] uint8 data[]
+ );
+ /* Source data from server */
+ void echo_SourceData(
+ [in] uint32 len,
+ [out,size_is(len)] uint8 data[]
+ );
+
+ /* test strings */
+ void echo_TestCall (
+ [in,string,charset(UTF16)] uint16 *s1,
+ [out,string,charset(UTF16)] uint16 **s2
+ );
+
+
+ /* test some alignment issues */
+ typedef struct {
+ uint8 v;
+ } echo_info1;
+
+ typedef struct {
+ uint16 v;
+ } echo_info2;
+
+ typedef struct {
+ uint32 v;
+ } echo_info3;
+
+ struct echo_info4 {
+ hyper v;
+ };
+
+ typedef struct {
+ uint8 v1;
+ hyper v2;
+ } echo_info5;
+
+ typedef struct {
+ uint8 v1;
+ echo_info1 info1;
+ } echo_info6;
+
+ typedef struct {
+ uint8 v1;
+ struct echo_info4 info4;
+ } echo_info7;
+
+ typedef [switch_type(uint16)] union {
+ [case(1)] echo_info1 info1;
+ [case(2)] echo_info2 info2;
+ [case(3)] echo_info3 info3;
+ [case(4)] struct echo_info4 info4;
+ [case(5)] echo_info5 info5;
+ [case(6)] echo_info6 info6;
+ [case(7)] echo_info7 info7;
+ } echo_Info;
+
+ NTSTATUS echo_TestCall2 (
+ [in] uint16 level,
+ [out,switch_is(level)] echo_Info *info
+ );
+
+ uint32 echo_TestSleep(
+ [in] uint32 seconds
+ );
+
+ typedef enum {
+ ECHO_ENUM1 = 1,
+ ECHO_ENUM2 = 2
+ } echo_Enum1;
+
+ typedef [v1_enum] enum {
+ ECHO_ENUM1_32 = 1,
+ ECHO_ENUM2_32 = 2
+ } echo_Enum1_32;
+
+ typedef struct {
+ echo_Enum1 e1;
+ echo_Enum1_32 e2;
+ } echo_Enum2;
+
+ typedef [switch_type(uint16)] union {
+ [case(ECHO_ENUM1)] echo_Enum1 e1;
+ [case(ECHO_ENUM2)] echo_Enum2 e2;
+ } echo_Enum3;
+
+ void echo_TestEnum(
+ [in,out,ref] echo_Enum1 *foo1,
+ [in,out,ref] echo_Enum2 *foo2,
+ [in,out,ref,switch_is(*foo1)] echo_Enum3 *foo3
+ );
+
+ typedef struct {
+ uint32 x;
+ [size_is(x)] uint16 surrounding[*];
+ } echo_Surrounding;
+
+ void echo_TestSurrounding(
+ [in,out,ref] echo_Surrounding *data
+ );
+
+ uint16 echo_TestDoublePointer([in] uint16 ***data);
+}
diff --git a/source3/librpc/idl/epmapper.idl b/source3/librpc/idl/epmapper.idl
new file mode 100644
index 0000000000..5611c3de18
--- /dev/null
+++ b/source3/librpc/idl/epmapper.idl
@@ -0,0 +1,302 @@
+#include "idl_types.h"
+
+/*
+ endpoint mapper interface
+ Related links:
+ http://www.opengroup.org/onlinepubs/9629399/apdxl.htm : Details on towers
+http://www.opengroup.org/onlinepubs/9629399/chap6.htm#tagcjh_11_02_03_01: binding strings
+
+*/
+
+[
+ uuid("e1af8308-5d1f-11c9-91a4-08002b14a0fa"),
+ version(3.0),
+ endpoint("ncacn_np:[\\pipe\\epmapper]", "ncacn_ip_tcp:[135]",
+ "ncalrpc:[EPMAPPER]"),
+ helpstring("EndPoint Mapper"),
+ pointer_default(ptr)
+]
+interface epmapper
+{
+
+ /*
+ note that the following IDL won't work in MIDL, and in fact
+ that the full towers/floors representation of epm cannot be
+ represented in MIDL at all. I decided to represent it using
+ the extended IDL syntax in pidl to make it easier to work
+ with.
+ */
+
+ const int EPMAPPER_STATUS_NO_MORE_ENTRIES = 0x16c9a0d6;
+ const int EPMAPPER_STATUS_NO_MEMORY = 0x16C9A012;
+ const int EPMAPPER_STATUS_OK = 0;
+
+
+
+ typedef [enum8bit] enum {
+
+ /* Level 4 and higher */
+ EPM_PROTOCOL_DNET_NSP = 0x04,
+ EPM_PROTOCOL_OSI_TP4 = 0x05,
+ EPM_PROTOCOL_OSI_CLNS = 0x06,
+ EPM_PROTOCOL_TCP = 0x07,
+ EPM_PROTOCOL_UDP = 0x08,
+ EPM_PROTOCOL_IP = 0x09,
+ /* These 4 are protocol identifiers, always at level 3 or lower */
+ EPM_PROTOCOL_NCADG = 0x0a, /* Connectionless RPC */
+ EPM_PROTOCOL_NCACN = 0x0b,
+ EPM_PROTOCOL_NCALRPC = 0x0c, /* Local RPC */
+ EPM_PROTOCOL_UUID = 0x0d,
+ EPM_PROTOCOL_IPX = 0x0e,
+ EPM_PROTOCOL_SMB = 0x0f,
+ EPM_PROTOCOL_PIPE = 0x10,
+ EPM_PROTOCOL_NETBIOS = 0x11,
+ EPM_PROTOCOL_NETBEUI = 0x12,
+ EPM_PROTOCOL_SPX = 0x13,
+ EPM_PROTOCOL_NB_IPX = 0x14, /* NetBIOS over IPX */
+ EPM_PROTOCOL_DSP = 0x16, /* AppleTalk Data Stream Protocol */
+ EPM_PROTOCOL_DDP = 0x17, /* AppleTalk Data Datagram Protocol */
+ EPM_PROTOCOL_APPLETALK = 0x18, /* AppleTalk */
+ EPM_PROTOCOL_VINES_SPP = 0x1a,
+ EPM_PROTOCOL_VINES_IPC = 0x1b, /* Inter Process Communication */
+ EPM_PROTOCOL_STREETTALK = 0x1c, /* Vines Streettalk */
+ EPM_PROTOCOL_HTTP = 0x1f,
+ EPM_PROTOCOL_UNIX_DS = 0x20, /* Unix domain socket */
+ EPM_PROTOCOL_NULL = 0x21
+ } epm_protocol;
+
+ typedef struct {
+ /*FIXME */
+ } epm_rhs_dnet_nsp;
+
+ typedef struct {
+ /*FIXME*/
+ } epm_rhs_osi_tp4;
+
+ typedef struct {
+ /*FIXME*/
+ } epm_rhs_osi_clns;
+
+ typedef struct {
+ uint16 port;
+ } epm_rhs_udp;
+
+ typedef struct {
+ uint16 port;
+ } epm_rhs_tcp;
+
+ typedef struct {
+ ipv4address ipaddr;
+ } epm_rhs_ip;
+
+ typedef struct {
+ uint16 minor_version;
+ } epm_rhs_ncadg;
+
+ typedef struct {
+ uint16 minor_version;
+ } epm_rhs_ncacn;
+
+ typedef struct {
+ [flag(NDR_REMAINING)] DATA_BLOB unknown;
+ } epm_rhs_uuid;
+
+ typedef struct {
+ /*FIXME */
+ } epm_rhs_ipx;
+
+ typedef struct {
+ astring unc;
+ } epm_rhs_smb;
+
+ typedef struct {
+ astring path;
+ } epm_rhs_pipe;
+
+ typedef struct {
+ astring name;
+ } epm_rhs_netbios;
+
+ typedef struct {
+ } epm_rhs_netbeui;
+
+ typedef struct {
+ } epm_rhs_spx;
+
+ typedef struct {
+ } epm_rhs_nb_ipx;
+
+ typedef struct {
+ uint16 port;
+ } epm_rhs_http;
+
+ typedef struct {
+ astring path;
+ } epm_rhs_unix_ds;
+
+ typedef struct {
+ } epm_rhs_null;
+
+ typedef struct {
+ uint16 minor_version;
+ } epm_rhs_ncalrpc;
+
+ typedef struct {
+ } epm_rhs_appletalk;
+
+ typedef struct {
+ } epm_rhs_atalk_stream;
+
+ typedef struct {
+ } epm_rhs_atalk_datagram;
+
+ typedef struct {
+ uint16 port;
+ } epm_rhs_vines_spp;
+
+ typedef struct {
+ uint16 port;
+ } epm_rhs_vines_ipc;
+
+ typedef struct {
+ astring streettalk;
+ } epm_rhs_streettalk;
+
+ typedef [flag(NDR_BIG_ENDIAN),nodiscriminant] union {
+ [case(EPM_PROTOCOL_DNET_NSP)] epm_rhs_dnet_nsp dnet_nsp;
+ [case(EPM_PROTOCOL_OSI_TP4)] epm_rhs_osi_tp4 osi_tp4;
+ [case(EPM_PROTOCOL_OSI_CLNS)] epm_rhs_osi_clns osi_clns;
+ [case(EPM_PROTOCOL_TCP)] epm_rhs_tcp tcp;
+ [case(EPM_PROTOCOL_UDP)] epm_rhs_udp udp;
+ [case(EPM_PROTOCOL_IP)] epm_rhs_ip ip;
+ [case(EPM_PROTOCOL_NCADG)] epm_rhs_ncadg ncadg;
+ [case(EPM_PROTOCOL_NCACN)] epm_rhs_ncacn ncacn;
+ [case(EPM_PROTOCOL_NCALRPC)] epm_rhs_ncalrpc ncalrpc;
+ [case(EPM_PROTOCOL_UUID)] epm_rhs_uuid uuid;
+ [case(EPM_PROTOCOL_IPX)] epm_rhs_ipx ipx;
+ [case(EPM_PROTOCOL_SMB)] epm_rhs_smb smb;
+ [case(EPM_PROTOCOL_PIPE)] epm_rhs_pipe pipe;
+ [case(EPM_PROTOCOL_NETBIOS)] epm_rhs_netbios netbios;
+ [case(EPM_PROTOCOL_NETBEUI)] epm_rhs_netbeui netbeui;
+ [case(EPM_PROTOCOL_SPX)] epm_rhs_spx spx;
+ [case(EPM_PROTOCOL_NB_IPX)] epm_rhs_nb_ipx nb_ipx;
+ [case(EPM_PROTOCOL_DSP)] epm_rhs_atalk_stream atalk_stream;
+ [case(EPM_PROTOCOL_DDP)] epm_rhs_atalk_datagram atalk_datagram;
+ [case(EPM_PROTOCOL_APPLETALK)] epm_rhs_appletalk appletalk;
+ [case(EPM_PROTOCOL_VINES_SPP)] epm_rhs_vines_spp vines_spp;
+ [case(EPM_PROTOCOL_VINES_IPC)] epm_rhs_vines_ipc vines_ipc;
+ [case(EPM_PROTOCOL_STREETTALK)] epm_rhs_streettalk streettalk;
+ [case(EPM_PROTOCOL_HTTP)] epm_rhs_http http;
+ [case(EPM_PROTOCOL_UNIX_DS)] epm_rhs_unix_ds unix_ds;
+ [case(EPM_PROTOCOL_NULL)] epm_rhs_null null;
+ [default] [flag(NDR_REMAINING)] DATA_BLOB unknown;
+ } epm_rhs;
+
+ typedef struct {
+ epm_protocol protocol;
+ [flag(NDR_REMAINING)] DATA_BLOB lhs_data;
+ } epm_lhs;
+
+ typedef struct {
+ [subcontext(2)] epm_lhs lhs;
+ [subcontext(2),switch_is(lhs.protocol)] epm_rhs rhs;
+ } epm_floor;
+
+ /* note that the NDR_NOALIGN flag is inherited by all nested
+ structures. All of the towers/floors stuff is
+ non-aligned. I wonder what sort of wicked substance these
+ guys were smoking?
+ */
+ typedef [gensize,flag(NDR_NOALIGN|NDR_LITTLE_ENDIAN)] struct {
+ uint16 num_floors;
+ epm_floor floors[num_floors];
+ } epm_tower;
+
+ typedef struct {
+ [value(ndr_size_epm_tower(&tower, ndr->flags))] uint32 tower_length;
+ [subcontext(4)] epm_tower tower;
+ } epm_twr_t;
+
+ typedef struct {
+ GUID object;
+ epm_twr_t *tower;
+ ascstr2 annotation;
+ } epm_entry_t;
+
+ typedef struct {
+ GUID uuid;
+ uint16 vers_major;
+ uint16 vers_minor;
+ } rpc_if_id_t;
+
+ /**********************/
+ /* Function 0x0 */
+ error_status_t epm_Insert(
+ [in] uint32 num_ents,
+ [in,size_is(num_ents)] epm_entry_t entries[],
+ [in] uint32 replace
+ );
+
+ /**********************/
+ /* Function 0x1 */
+ error_status_t epm_Delete(
+ [in] uint32 num_ents,
+ [in, size_is(num_ents)] epm_entry_t entries[]
+ );
+
+ /**********************/
+ /* Function 0x02 */
+ error_status_t epm_Lookup(
+ [in] uint32 inquiry_type,
+ [in,ptr] GUID *object,
+ [in,ptr] rpc_if_id_t *interface_id,
+ [in] uint32 vers_option,
+ [in,out] policy_handle *entry_handle,
+ [in] uint32 max_ents,
+ [out] uint32 *num_ents,
+ [out, length_is(*num_ents), size_is(max_ents)] epm_entry_t entries[]
+ );
+
+
+ /**********************/
+ /* Function 0x03 */
+
+ typedef struct {
+ epm_twr_t *twr;
+ } epm_twr_p_t;
+
+ [public] error_status_t epm_Map(
+ [in,ptr] GUID *object,
+ [in,ptr] epm_twr_t *map_tower,
+ [in,out] policy_handle *entry_handle,
+ [in] uint32 max_towers,
+ [out] uint32 *num_towers,
+ [out, length_is(*num_towers), size_is(max_towers)] epm_twr_p_t towers[]
+ );
+
+
+ /**********************/
+ /* Function 0x04 */
+ error_status_t epm_LookupHandleFree(
+ [in,out] policy_handle *entry_handle
+ );
+
+ /**********************/
+ /* Function 0x05 */
+ error_status_t epm_InqObject(
+ [in] GUID *epm_object
+ );
+
+
+ /**********************/
+ /* Function 0x06 */
+ error_status_t epm_MgmtDelete(
+ [in] uint32 object_speced,
+ [in,ptr] GUID *object,
+ [in,ptr] epm_twr_t *tower
+ );
+
+ /**********************/
+ /* Function 0x07 */
+ error_status_t epm_MapAuth();
+}
diff --git a/source3/librpc/idl/eventlog.idl b/source3/librpc/idl/eventlog.idl
new file mode 100644
index 0000000000..18b1a0e454
--- /dev/null
+++ b/source3/librpc/idl/eventlog.idl
@@ -0,0 +1,181 @@
+#include "idl_types.h"
+
+/*
+ eventlog interface definition
+*/
+
+import "lsa.idl", "security.idl";
+
+[ uuid("82273fdc-e32a-18c3-3f78-827929dc23ea"),
+ version(0.0),
+ helpstring("Event Logger")
+] interface eventlog
+{
+ typedef bitmap {
+ EVENTLOG_SEQUENTIAL_READ = 0x0001,
+ EVENTLOG_SEEK_READ = 0x0002,
+ EVENTLOG_FORWARDS_READ = 0x0004,
+ EVENTLOG_BACKWARDS_READ = 0x0008
+ } eventlogReadFlags;
+
+ typedef bitmap {
+ EVENTLOG_SUCCESS = 0x0000,
+ EVENTLOG_ERROR_TYPE = 0x0001,
+ EVENTLOG_WARNING_TYPE = 0x0002,
+ EVENTLOG_INFORMATION_TYPE = 0x0004,
+ EVENTLOG_AUDIT_SUCCESS = 0x0008,
+ EVENTLOG_AUDIT_FAILURE = 0x0010
+ } eventlogEventTypes;
+
+ typedef struct {
+ uint16 unknown0;
+ uint16 unknown1;
+ } eventlog_OpenUnknown0;
+
+ typedef [public] struct {
+ uint32 size;
+ uint32 reserved;
+ uint32 record_number;
+ uint32 time_generated;
+ uint32 time_written;
+ uint32 event_id;
+ uint16 event_type;
+ uint16 num_of_strings;
+ uint16 event_category;
+ uint16 reserved_flags;
+ uint32 closing_record_number;
+ uint32 stringoffset;
+ uint32 sid_length;
+ uint32 sid_offset;
+ uint32 data_length;
+ uint32 data_offset;
+ nstring source_name;
+ nstring computer_name;
+ nstring strings[num_of_strings];
+ astring raw_data;
+ } eventlog_Record;
+
+ /******************/
+ /* Function: 0x00 */
+ NTSTATUS eventlog_ClearEventLogW(
+ [in] policy_handle *handle,
+ [in,unique] lsa_String *backupfile
+ );
+
+ /******************/
+ /* Function: 0x01 */
+ NTSTATUS eventlog_BackupEventLogW();
+
+ /******************/
+ /* Function: 0x02 */
+ NTSTATUS eventlog_CloseEventLog(
+ [in,out] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x03 */
+ NTSTATUS eventlog_DeregisterEventSource();
+
+ /******************/
+ /* Function: 0x04 */
+ NTSTATUS eventlog_GetNumRecords(
+ [in] policy_handle *handle,
+ [out] uint32 *number
+ );
+
+ /******************/
+ /* Function: 0x05 */
+ NTSTATUS eventlog_GetOldestRecord(
+ [in] policy_handle *handle,
+ [out,ref] uint32 *oldest_entry
+ );
+
+ /******************/
+ /* Function: 0x06 */
+ NTSTATUS eventlog_ChangeNotify();
+
+ /******************/
+ /* Function: 0x07 */
+ NTSTATUS eventlog_OpenEventLogW(
+ [in,unique] eventlog_OpenUnknown0 *unknown0,
+ [in,ref] lsa_String *logname,
+ [in,ref] lsa_String *servername,
+ [in] uint32 unknown2,
+ [in] uint32 unknown3,
+ [out] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x08 */
+ NTSTATUS eventlog_RegisterEventSourceW();
+
+ /******************/
+ /* Function: 0x09 */
+ NTSTATUS eventlog_OpenBackupEventLogW();
+
+ /******************/
+ /* Function: 0x0a */
+ NTSTATUS eventlog_ReadEventLogW(
+ [in] policy_handle *handle,
+ [in] uint32 flags,
+ [in] uint32 offset,
+ [in] [range(0,0x7FFFF)] uint32 number_of_bytes,
+ [out,ref,size_is(number_of_bytes)] uint8 *data,
+ [out,ref] uint32 *sent_size,
+ [out,ref] uint32 *real_size
+ );
+
+ /*****************/
+ /* Function 0x0b */
+ NTSTATUS eventlog_ReportEventW();
+
+ /*****************/
+ /* Function 0x0c */
+ NTSTATUS eventlog_ClearEventLogA();
+
+ /******************/
+ /* Function: 0x0d */
+ NTSTATUS eventlog_BackupEventLogA();
+
+ /*****************/
+ /* Function 0x0e */
+ NTSTATUS eventlog_OpenEventLogA();
+
+ /*****************/
+ /* Function 0x0f */
+ NTSTATUS eventlog_RegisterEventSourceA();
+
+ /*****************/
+ /* Function 0x10 */
+ NTSTATUS eventlog_OpenBackupEventLogA();
+
+ /*****************/
+ /* Function 0x11 */
+ NTSTATUS eventlog_ReadEventLogA();
+
+ /*****************/
+ /* Function 0x12 */
+ NTSTATUS eventlog_ReportEventA();
+
+ /*****************/
+ /* Function 0x13 */
+ NTSTATUS eventlog_RegisterClusterSvc();
+
+ /*****************/
+ /* Function 0x14 */
+ NTSTATUS eventlog_DeregisterClusterSvc();
+
+ /*****************/
+ /* Function 0x15 */
+ NTSTATUS eventlog_WriteClusterEvents();
+
+ /*****************/
+ /* Function 0x16 */
+ NTSTATUS eventlog_GetLogIntormation();
+
+ /*****************/
+ /* Function 0x17 */
+ NTSTATUS eventlog_FlushEventLog(
+ [in] policy_handle *handle
+ );
+}
diff --git a/source3/librpc/idl/idl_types.h b/source3/librpc/idl/idl_types.h
new file mode 100644
index 0000000000..f21f3e660d
--- /dev/null
+++ b/source3/librpc/idl/idl_types.h
@@ -0,0 +1,86 @@
+#define STR_ASCII LIBNDR_FLAG_STR_ASCII
+#define STR_LEN4 LIBNDR_FLAG_STR_LEN4
+#define STR_SIZE4 LIBNDR_FLAG_STR_SIZE4
+#define STR_SIZE2 LIBNDR_FLAG_STR_SIZE2
+#define STR_NOTERM LIBNDR_FLAG_STR_NOTERM
+#define STR_NULLTERM LIBNDR_FLAG_STR_NULLTERM
+#define STR_BYTESIZE LIBNDR_FLAG_STR_BYTESIZE
+#define STR_FIXLEN32 LIBNDR_FLAG_STR_FIXLEN32
+#define STR_FIXLEN15 LIBNDR_FLAG_STR_FIXLEN15
+#define STR_CONFORMANT LIBNDR_FLAG_STR_CONFORMANT
+#define STR_CHARLEN LIBNDR_FLAG_STR_CHARLEN
+#define STR_UTF8 LIBNDR_FLAG_STR_UTF8
+
+/*
+ a UCS2 string prefixed with [size], 32 bits
+*/
+#define lstring [flag(STR_SIZE4)] string
+
+/*
+ a null terminated UCS2 string
+*/
+#define nstring [flag(STR_NULLTERM)] string
+
+/*
+ fixed length 32 character UCS-2 string
+*/
+#define string32 [flag(STR_FIXLEN32)] string
+
+/*
+ fixed length 16 character ascii string
+*/
+#define astring15 [flag(STR_ASCII|STR_FIXLEN15)] string
+
+/*
+ an ascii string prefixed with [offset] [length], both 32 bits
+ null terminated
+*/
+#define ascstr2 [flag(STR_ASCII|STR_LEN4)] string
+
+/*
+ an ascii string prefixed with [size], 32 bits
+*/
+#define asclstr [flag(STR_ASCII|STR_SIZE4)] string
+
+/*
+ an ascii string prefixed with [size], 16 bits
+ null terminated
+*/
+#define ascstr3 [flag(STR_ASCII|STR_SIZE2)] string
+
+/*
+ an ascii string prefixed with [size] [offset] [length], all 32 bits
+ not null terminated
+*/
+#define ascstr_noterm [flag(STR_NOTERM|STR_ASCII|STR_SIZE4|STR_LEN4)] string
+
+/*
+ a null terminated ascii string
+*/
+#define astring [flag(STR_ASCII|STR_NULLTERM)] string
+
+/*
+ a null terminated UTF8 string
+*/
+#define utf8string [flag(STR_UTF8|STR_NULLTERM)] string
+
+/*
+ a null terminated UCS2 string
+*/
+#define nstring_array [flag(STR_NULLTERM)] string_array
+
+#define NDR_NOALIGN LIBNDR_FLAG_NOALIGN
+#define NDR_REMAINING LIBNDR_FLAG_REMAINING
+#define NDR_ALIGN2 LIBNDR_FLAG_ALIGN2
+#define NDR_ALIGN4 LIBNDR_FLAG_ALIGN4
+#define NDR_ALIGN8 LIBNDR_FLAG_ALIGN8
+
+/* this flag is used to force a section of IDL as little endian. It is
+ needed for the epmapper IDL, which is defined as always being LE */
+#define NDR_LITTLE_ENDIAN LIBNDR_FLAG_LITTLE_ENDIAN
+#define NDR_BIG_ENDIAN LIBNDR_FLAG_BIGENDIAN
+
+/*
+ this is used to control formatting of uint8 arrays
+*/
+#define NDR_PAHEX LIBNDR_PRINT_ARRAY_HEX
diff --git a/source3/librpc/idl/initshutdown.idl b/source3/librpc/idl/initshutdown.idl
new file mode 100644
index 0000000000..8815a9a29e
--- /dev/null
+++ b/source3/librpc/idl/initshutdown.idl
@@ -0,0 +1,46 @@
+#include "idl_types.h"
+
+/*
+ initshutdown interface definition
+*/
+
+[
+ uuid("894de0c0-0d55-11d3-a322-00c04fa321a1"),
+ version(1.0),
+ endpoint("ncacn_np:[\\pipe\\InitShutdown]"),
+ pointer_default(unique),
+ helpstring("Init shutdown service")
+] interface initshutdown
+{
+ typedef struct {
+ [value(strlen_m_term(name))] uint32 name_size;
+ [flag(STR_LEN4|STR_NOTERM)] string name;
+ } initshutdown_String_sub;
+
+ typedef [public] struct {
+ [value(strlen_m(name->name)*2)] uint16 name_len;
+ [value(strlen_m_term(name->name)*2)] uint16 name_size;
+ initshutdown_String_sub *name;
+ } initshutdown_String;
+
+ WERROR initshutdown_Init(
+ [in,unique] uint16 *hostname,
+ [in,unique] initshutdown_String *message,
+ [in] uint32 timeout,
+ [in] uint8 force_apps,
+ [in] uint8 do_reboot
+ );
+
+ WERROR initshutdown_Abort(
+ [in,unique] uint16 *server
+ );
+
+ WERROR initshutdown_InitEx(
+ [in,unique] uint16 *hostname,
+ [in,unique] initshutdown_String *message,
+ [in] uint32 timeout,
+ [in] uint8 force_apps,
+ [in] uint8 do_reboot,
+ [in] uint32 reason
+ );
+}
diff --git a/source3/librpc/idl/krb5pac.idl b/source3/librpc/idl/krb5pac.idl
new file mode 100644
index 0000000000..c039502d23
--- /dev/null
+++ b/source3/librpc/idl/krb5pac.idl
@@ -0,0 +1,120 @@
+/*
+ krb5 PAC
+*/
+
+#include "idl_types.h"
+
+import "security.idl", "netlogon.idl", "samr.idl";
+
+[
+ uuid("12345778-1234-abcd-0000-00000000"),
+ version(0.0),
+ pointer_default(unique),
+ helpstring("Active Directory KRB5 PAC")
+]
+interface krb5pac
+{
+ typedef struct {
+ NTTIME logon_time;
+ [value(2*strlen_m(account_name))] uint16 size;
+ [charset(UTF16)] uint8 account_name[size];
+ } PAC_LOGON_NAME;
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ uint32 type;
+ [flag(NDR_REMAINING)] DATA_BLOB signature;
+ } PAC_SIGNATURE_DATA;
+
+ typedef [gensize] struct {
+ netr_SamInfo3 info3;
+ dom_sid2 *res_group_dom_sid;
+ samr_RidWithAttributeArray res_groups;
+ } PAC_LOGON_INFO;
+
+ typedef struct {
+ [value(2*strlen_m(upn_name))] uint16 upn_size;
+ uint16 upn_offset;
+ [value(2*strlen_m(domain_name))] uint16 domain_size;
+ uint16 domain_offset;
+ uint16 unknown3; /* 0x01 */
+ uint16 unknown4;
+ uint32 unknown5;
+ [charset(UTF16)] uint8 upn_name[upn_size+2];
+ [charset(UTF16)] uint8 domain_name[domain_size+2];
+ uint32 unknown6; /* padding */
+ } PAC_UNKNOWN_12;
+
+ typedef [public] struct {
+ [value(0x00081001)] uint32 unknown1;
+ [value(0xCCCCCCCC)] uint32 unknown2;
+ [value(NDR_ROUND(ndr_size_PAC_LOGON_INFO(info, ndr->flags)+4,8))] uint32 _ndr_size;
+ [value(0x00000000)] uint32 unknown3;
+ PAC_LOGON_INFO *info;
+ } PAC_LOGON_INFO_CTR;
+
+ typedef [public,v1_enum] enum {
+ PAC_TYPE_LOGON_INFO = 1,
+ PAC_TYPE_SRV_CHECKSUM = 6,
+ PAC_TYPE_KDC_CHECKSUM = 7,
+ PAC_TYPE_LOGON_NAME = 10,
+ PAC_TYPE_CONSTRAINED_DELEGATION = 11,
+ PAC_TYPE_UNKNOWN_12 = 12
+ } PAC_TYPE;
+
+ typedef struct {
+ [flag(NDR_REMAINING)] DATA_BLOB remaining;
+ } DATA_BLOB_REM;
+
+ typedef [public,nodiscriminant,gensize] union {
+ [case(PAC_TYPE_LOGON_INFO)] PAC_LOGON_INFO_CTR logon_info;
+ [case(PAC_TYPE_SRV_CHECKSUM)] PAC_SIGNATURE_DATA srv_cksum;
+ [case(PAC_TYPE_KDC_CHECKSUM)] PAC_SIGNATURE_DATA kdc_cksum;
+ [case(PAC_TYPE_LOGON_NAME)] PAC_LOGON_NAME logon_name;
+ [default] [subcontext(0)] DATA_BLOB_REM unknown;
+ /* [case(PAC_TYPE_UNKNOWN_12)] PAC_UNKNOWN_12 unknown; */
+ } PAC_INFO;
+
+ typedef [public,nopush,nopull,noprint] struct {
+ PAC_TYPE type;
+ [value(_ndr_size_PAC_INFO(info, type, 0))] uint32 _ndr_size;
+ [relative,switch_is(type),subcontext(0),subcontext_size(_subcontext_size_PAC_INFO(r, ndr->flags)),flag(NDR_ALIGN8)] PAC_INFO *info;
+ [value(0)] uint32 _pad; /* Top half of a 64 bit pointer? */
+ } PAC_BUFFER;
+
+ typedef [public] struct {
+ uint32 num_buffers;
+ uint32 version;
+ PAC_BUFFER buffers[num_buffers];
+ } PAC_DATA;
+
+ typedef [public] struct {
+ PAC_TYPE type;
+ uint32 ndr_size;
+ [relative,subcontext(0),subcontext_size(NDR_ROUND(ndr_size,8)),flag(NDR_ALIGN8)] DATA_BLOB_REM *info;
+ [value(0)] uint32 _pad; /* Top half of a 64 bit pointer? */
+ } PAC_BUFFER_RAW;
+
+ typedef [public] struct {
+ uint32 num_buffers;
+ uint32 version;
+ PAC_BUFFER_RAW buffers[num_buffers];
+ } PAC_DATA_RAW;
+
+ void decode_pac(
+ [in] PAC_DATA pac
+ );
+
+ void decode_pac_raw(
+ [in] PAC_DATA_RAW pac
+ );
+
+ void decode_login_info(
+ [in] PAC_LOGON_INFO logon_info
+ );
+
+ /* used for samba3 netsamlogon cache */
+ typedef [public] struct {
+ time_t timestamp;
+ netr_SamInfo3 info3;
+ } netsamlogoncache_entry;
+}
diff --git a/source3/librpc/idl/libnet_join.idl b/source3/librpc/idl/libnet_join.idl
new file mode 100644
index 0000000000..c600ea094a
--- /dev/null
+++ b/source3/librpc/idl/libnet_join.idl
@@ -0,0 +1,70 @@
+#include "idl_types.h"
+
+import "wkssvc.idl", "security.idl";
+
+/*
+ libnetjoin interface definition
+*/
+
+[
+ pointer_default(unique)
+]
+interface libnetjoin
+{
+ typedef bitmap wkssvc_joinflags wkssvc_joinflags;
+ typedef enum netr_SchannelType netr_SchannelType;
+
+ [nopush,nopull,noopnum] WERROR libnet_JoinCtx(
+ [in] string dc_name,
+ [in] string machine_name,
+ [in,ref] string *domain_name,
+ [in] string account_ou,
+ [in] string admin_account,
+ [in] string admin_password,
+ [in] string machine_password,
+ [in] wkssvc_joinflags join_flags,
+ [in] string os_version,
+ [in] string os_name,
+ [in] boolean8 create_upn,
+ [in] string upn,
+ [in] boolean8 modify_config,
+ [in] ads_struct *ads,
+ [in] boolean8 debug,
+ [in] boolean8 use_kerberos,
+ [in] netr_SchannelType secure_channel_type,
+ [in,noprint] messaging_context *msg_ctx,
+ [out] string account_name,
+ [out] string netbios_domain_name,
+ [out] string dns_domain_name,
+ [out] string forest_name,
+ [out] string dn,
+ [out] dom_sid *domain_sid,
+ [out] boolean8 modified_config,
+ [out] string error_string,
+ [out] boolean8 domain_is_ad
+ );
+
+ [nopush,nopull,noopnum] WERROR libnet_UnjoinCtx(
+ [in] string dc_name,
+ [in] string machine_name,
+ [in] string domain_name,
+ [in] string account_ou,
+ [in] string admin_account,
+ [in] string admin_password,
+ [in] string machine_password,
+ [in] wkssvc_joinflags unjoin_flags,
+ [in] boolean8 modify_config,
+ [in] dom_sid *domain_sid,
+ [in] ads_struct *ads,
+ [in] boolean8 debug,
+ [in] boolean8 use_kerberos,
+ [in,noprint] messaging_context *msg_ctx,
+ [out] string netbios_domain_name,
+ [out] string dns_domain_name,
+ [out] string forest_name,
+ [out] boolean8 modified_config,
+ [out] string error_string,
+ [out] boolean8 disabled_machine_account,
+ [out] boolean8 deleted_machine_account
+ );
+}
diff --git a/source3/librpc/idl/libnetapi.idl b/source3/librpc/idl/libnetapi.idl
new file mode 100644
index 0000000000..039dcf4152
--- /dev/null
+++ b/source3/librpc/idl/libnetapi.idl
@@ -0,0 +1,1237 @@
+/*
+ libnetapi interface definition
+*/
+
+cpp_quote("#define LIBNETAPI_LOCAL_SERVER(x) (!x || is_myname_or_ipaddr(x))")
+cpp_quote("#ifndef MAXSUBAUTHS")
+cpp_quote("#define MAXSUBAUTHS 15 /* max sub authorities in a SID */")
+cpp_quote("#endif")
+
+[
+ pointer_default(unique)
+]
+interface libnetapi
+{
+ const int ERROR_MORE_DATA = 234L;
+
+ [public] typedef [v1_enum] enum {
+ NERR_Success=0
+ } NET_API_STATUS;
+
+ [public] typedef struct {
+ uint8 sid_rev_num;
+ uint8 num_auths;
+ uint8 id_auth[6];
+ uint32 sub_auths[MAXSUBAUTHS];
+ } domsid;
+
+ /*******************************************/
+ /* NetJoinDomain */
+ /*******************************************/
+
+ typedef [public,bitmap32bit] bitmap {
+ NETSETUP_JOIN_DOMAIN = 0x00000001,
+ NETSETUP_ACCT_CREATE = 0x00000002,
+ NETSETUP_ACCT_DELETE = 0x00000004,
+ NETSETUP_WIN9X_UPGRADE = 0x00000010,
+ NETSETUP_DOMAIN_JOIN_IF_JOINED = 0x00000020,
+ NETSETUP_JOIN_UNSECURE = 0x00000040,
+ NETSETUP_MACHINE_PWD_PASSED = 0x00000080,
+ NETSETUP_DEFER_SPN_SET = 0x00000100,
+ NETSETUP_JOIN_DC_ACCOUNT = 0x00000200,
+ NETSETUP_JOIN_WITH_NEW_NAME = 0x00000400,
+ NETSETUP_INSTALL_INVOCATION = 0x00040000,
+ NETSETUP_IGNORE_UNSUPPORTED_FLAGS = 0x10000000
+ } NetJoinFlags;
+
+ [nopush,nopull] NET_API_STATUS NetJoinDomain(
+ [in,unique] string *server,
+ [in,ref] string *domain,
+ [in,unique] string *account_ou,
+ [in,unique] string *account,
+ [in,unique] string *password,
+ [in] NetJoinFlags join_flags
+ );
+
+ /*******************************************/
+ /* NetUnjoinDomain */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetUnjoinDomain(
+ [in,unique] string *server_name,
+ [in,unique] string *account,
+ [in,unique] string *password,
+ [in] NetJoinFlags unjoin_flags
+ );
+
+ /*******************************************/
+ /* NetGetJoinInformation */
+ /*******************************************/
+
+ typedef enum {
+ NetSetupUnknownStatus = 0,
+ NetSetupUnjoined = 1,
+ NetSetupWorkgroupName = 2,
+ NetSetupDomainName = 3
+ } NETSETUP_JOIN_STATUS;
+
+ [nopush,nopull] NET_API_STATUS NetGetJoinInformation(
+ [in,unique] string *server_name,
+ [out] string **name_buffer,
+ [out] uint16 *name_type
+ );
+
+ /*******************************************/
+ /* NetGetJoinableOUs */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetGetJoinableOUs(
+ [in,unique] string *server_name,
+ [in,ref] string *domain,
+ [in,unique] string *account,
+ [in,unique] string *password,
+ [out] uint32 *ou_count,
+ [out] string ***ous
+ );
+
+ /*******************************************/
+ /* NetRenameMachineInDomain */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetRenameMachineInDomain(
+ [in] string server_name,
+ [in] string new_machine_name,
+ [in] string account,
+ [in] string password,
+ [in] uint32 rename_options
+ );
+
+ /*******************************************/
+ /* NetServerGetInfo */
+ /*******************************************/
+
+ [public] typedef struct {
+ uint32 sv100_platform_id;
+ string sv100_name;
+ } SERVER_INFO_100;
+
+ [public] typedef struct {
+ uint32 sv101_platform_id;
+ string sv101_name;
+ uint32 sv101_version_major;
+ uint32 sv101_version_minor;
+ uint32 sv101_type;
+ string sv101_comment;
+ } SERVER_INFO_101;
+
+ [public] typedef struct {
+ uint32 sv102_platform_id;
+ string sv102_name;
+ uint32 sv102_version_major;
+ uint32 sv102_version_minor;
+ uint32 sv102_type;
+ string sv102_comment;
+ uint32 sv102_users;
+ uint32 sv102_disc;
+ boolean8 sv102_hidden;
+ uint32 sv102_announce;
+ uint32 sv102_anndelta;
+ uint32 sv102_licenses;
+ string sv102_userpath;
+ } SERVER_INFO_102;
+
+ [public] typedef struct {
+ string sv1005_comment;
+ } SERVER_INFO_1005;
+
+ [nopush,nopull] NET_API_STATUS NetServerGetInfo(
+ [in,unique] string *server_name,
+ [in] uint32 level,
+ [out] uint8 **buffer
+ );
+
+ /*******************************************/
+ /* NetServerSetInfo */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetServerSetInfo(
+ [in,unique] string *server_name,
+ [in] uint32 level,
+ [in] uint8 *buffer,
+ [out] uint32 *parm_error
+ );
+
+ /*******************************************/
+ /* NetGetDCName */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetGetDCName(
+ [in,unique] string *server_name,
+ [in,unique] string *domain_name,
+ [out] uint8 **buffer
+ );
+
+ /*******************************************/
+ /* NetGetAnyDCName */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetGetAnyDCName(
+ [in,unique] string *server_name,
+ [in,unique] string *domain_name,
+ [out] uint8 **buffer
+ );
+
+ /*******************************************/
+ /* DsGetDcName */
+ /*******************************************/
+
+ [public] typedef struct {
+ string domain_controller_name;
+ string domain_controller_address;
+ uint32 domain_controller_address_type;
+ GUID domain_guid;
+ string domain_name;
+ string dns_forest_name;
+ uint32 flags;
+ string dc_site_name;
+ string client_site_name;
+ } DOMAIN_CONTROLLER_INFO;
+
+ [nopush,nopull] NET_API_STATUS DsGetDcName(
+ [in,unique] string *server_name,
+ [in,ref] string *domain_name,
+ [in,unique] GUID *domain_guid,
+ [in,unique] string *site_name,
+ [in] uint32 flags,
+ [out,ref] DOMAIN_CONTROLLER_INFO **dc_info
+ );
+
+ /*******************************************/
+ /* NetUserAdd */
+ /*******************************************/
+
+ [public] typedef struct {
+ string usri0_name;
+ } USER_INFO_0;
+
+ /* priv */
+ const int USER_PRIV_GUEST = 0;
+ const int USER_PRIV_USER = 1;
+ const int USER_PRIV_ADMIN = 2;
+
+ [public] typedef struct {
+ string usri1_name;
+ string usri1_password;
+ uint32 usri1_password_age;
+ uint32 usri1_priv;
+ string usri1_home_dir;
+ string usri1_comment;
+ uint32 usri1_flags;
+ string usri1_script_path;
+ } USER_INFO_1;
+
+ /* auth_flags in USER_INFO_2 */
+
+ const int AF_OP_PRINT = 0x1;
+ const int AF_OP_COMM = 0x2;
+ const int AF_OP_SERVER = 0x4;
+ const int AF_OP_ACCOUNTS = 0x8;
+ const int AF_SETTABLE_BITS = (AF_OP_PRINT | AF_OP_COMM | AF_OP_SERVER | AF_OP_ACCOUNTS);
+
+ const int USER_MAXSTORAGE_UNLIMITED = (uint32_t)-1L;
+
+ [public] typedef struct {
+ string usri2_name;
+ string usri2_password;
+ uint32 usri2_password_age;
+ uint32 usri2_priv;
+ string usri2_home_dir;
+ string usri2_comment;
+ uint32 usri2_flags;
+ string usri2_script_path;
+ uint32 usri2_auth_flags;
+ string usri2_full_name;
+ string usri2_usr_comment;
+ string usri2_parms;
+ string usri2_workstations;
+ uint32 usri2_last_logon;
+ uint32 usri2_last_logoff;
+ uint32 usri2_acct_expires;
+ uint32 usri2_max_storage;
+ uint32 usri2_units_per_week;
+ uint8 *usri2_logon_hours;
+ uint32 usri2_bad_pw_count;
+ uint32 usri2_num_logons;
+ string usri2_logon_server;
+ uint32 usri2_country_code;
+ uint32 usri2_code_page;
+ } USER_INFO_2;
+
+ [public] typedef struct {
+ string usri3_name;
+ uint32 usri3_password_age;
+ uint32 usri3_priv;
+ string usri3_home_dir;
+ string usri3_comment;
+ uint32 usri3_flags;
+ string usri3_script_path;
+ uint32 usri3_auth_flags;
+ string usri3_full_name;
+ string usri3_usr_comment;
+ string usri3_parms;
+ string usri3_workstations;
+ uint32 usri3_last_logon;
+ uint32 usri3_last_logoff;
+ uint32 usri3_acct_expires;
+ uint32 usri3_max_storage;
+ uint32 usri3_units_per_week;
+ uint8 *usri3_logon_hours;
+ uint32 usri3_bad_pw_count;
+ uint32 usri3_num_logons;
+ string usri3_logon_server;
+ uint32 usri3_country_code;
+ uint32 usri3_code_page;
+ uint32 usri3_user_id;
+ uint32 usri3_primary_group_id;
+ string usri3_profile;
+ string usri3_home_dir_drive;
+ uint32 usri3_password_expired;
+ } USER_INFO_3;
+
+ [public] typedef struct {
+ string usri4_name;
+ string usri4_password;
+ uint32 usri4_password_age;
+ uint32 usri4_priv;
+ string usri4_home_dir;
+ string usri4_comment;
+ uint32 usri4_flags;
+ string usri4_script_path;
+ uint32 usri4_auth_flags;
+ string usri4_full_name;
+ string usri4_usr_comment;
+ string usri4_parms;
+ string usri4_workstations;
+ uint32 usri4_last_logon;
+ uint32 usri4_last_logoff;
+ uint32 usri4_acct_expires;
+ uint32 usri4_max_storage;
+ uint32 usri4_units_per_week;
+ uint8 *usri4_logon_hours;
+ uint32 usri4_bad_pw_count;
+ uint32 usri4_num_logons;
+ string usri4_logon_server;
+ uint32 usri4_country_code;
+ uint32 usri4_code_page;
+ domsid *usri4_user_sid;
+ uint32 usri4_primary_group_id;
+ string usri4_profile;
+ string usri4_home_dir_drive;
+ uint32 usri4_password_expired;
+ } USER_INFO_4;
+
+ [public] typedef struct {
+ string usri10_name;
+ string usri10_comment;
+ string usri10_usr_comment;
+ string usri10_full_name;
+ } USER_INFO_10;
+
+ [public] typedef struct {
+ string usri11_name;
+ string usri11_comment;
+ string usri11_usr_comment;
+ string usri11_full_name;
+ uint32 usri11_priv;
+ uint32 usri11_auth_flags;
+ uint32 usri11_password_age;
+ string usri11_home_dir;
+ string usri11_parms;
+ uint32 usri11_last_logon;
+ uint32 usri11_last_logoff;
+ uint32 usri11_bad_pw_count;
+ uint32 usri11_num_logons;
+ string usri11_logon_server;
+ uint32 usri11_country_code;
+ string usri11_workstations;
+ uint32 usri11_max_storage;
+ uint32 usri11_units_per_week;
+ uint8 *usri11_logon_hours;
+ uint32 usri11_code_page;
+ } USER_INFO_11;
+
+ [public] typedef struct {
+ string usri20_name;
+ string usri20_full_name;
+ string usri20_comment;
+ uint32 usri20_flags;
+ uint32 usri20_user_id;
+ } USER_INFO_20;
+
+ const int ENCRYPTED_PWLEN = 16;
+
+ [public] typedef struct {
+ uint8 usri21_password[ENCRYPTED_PWLEN];
+ } USER_INFO_21;
+
+ [public] typedef struct {
+ string usri22_name;
+ uint8 usri22_password[ENCRYPTED_PWLEN];
+ uint32 usri22_password_age;
+ uint32 usri22_priv;
+ string usri22_home_dir;
+ string usri22_comment;
+ uint32 usri22_flags;
+ uint32 usri22_script_path;
+ uint32 usri22_auth_flags;
+ string usri22_full_name;
+ string usri22_usr_comment;
+ string usri22_parms;
+ string usri22_workstations;
+ uint32 usri22_last_logon;
+ uint32 usri22_last_logoff;
+ uint32 usri22_acct_expires;
+ uint32 usri22_max_storage;
+ uint32 usri22_units_per_week;
+ uint8 *usri22_logon_hours;
+ uint32 usri22_bad_pw_count;
+ uint32 usri22_num_logons;
+ string usri22_logon_server;
+ uint32 usri22_country_code;
+ uint32 usri22_code_page;
+ } USER_INFO_22;
+
+ [public] typedef struct {
+ string usri23_name;
+ string usri23_full_name;
+ string usri23_comment;
+ uint32 usri23_flags;
+ domsid *usri23_user_sid;
+ } USER_INFO_23;
+
+ [public] typedef struct {
+ string usri1003_password;
+ } USER_INFO_1003;
+
+ [public] typedef struct {
+ uint32 usri1005_priv;
+ } USER_INFO_1005;
+
+ [public] typedef struct {
+ string usri1006_home_dir;
+ } USER_INFO_1006;
+
+ [public] typedef struct {
+ string usri1007_comment;
+ } USER_INFO_1007;
+
+ [public] typedef struct {
+ uint32 usri1008_flags;
+ } USER_INFO_1008;
+
+ [public] typedef struct {
+ string usri1009_script_path;
+ } USER_INFO_1009;
+
+ [public] typedef struct {
+ uint32 usri1010_auth_flags;
+ } USER_INFO_1010;
+
+ [public] typedef struct {
+ string usri1011_full_name;
+ } USER_INFO_1011;
+
+ [public] typedef struct {
+ string usri1012_usr_comment;
+ } USER_INFO_1012;
+
+ [public] typedef struct {
+ string usri1013_parms;
+ } USER_INFO_1013;
+
+ [public] typedef struct {
+ string usri1014_workstations;
+ } USER_INFO_1014;
+
+ [public] typedef struct {
+ uint32 usri1017_acct_expires;
+ } USER_INFO_1017;
+
+ [public] typedef struct {
+ uint32 usri1018_max_storage;
+ } USER_INFO_1018;
+
+ [public] typedef struct {
+ uint32 usri1020_units_per_week;
+ uint8 *usri1020_logon_hours;
+ } USER_INFO_1020;
+
+ [public] typedef struct {
+ string usri1023_logon_server;
+ } USER_INFO_1023;
+
+ [public] typedef struct {
+ uint32 usri1024_country_code;
+ } USER_INFO_1024;
+
+ [public] typedef struct {
+ uint32 usri1025_code_page;
+ } USER_INFO_1025;
+
+ [public] typedef struct {
+ uint32 usri1051_primary_group_id;
+ } USER_INFO_1051;
+
+ [public] typedef struct {
+ string usri1052_profile;
+ } USER_INFO_1052;
+
+ [public] typedef struct {
+ string usri1053_home_dir_drive;
+ } USER_INFO_1053;
+
+ [public] typedef struct {
+ string usriX_name;
+ string usriX_password;
+ uint32 usriX_password_age;
+ uint32 usriX_priv;
+ string usriX_home_dir;
+ string usriX_comment;
+ uint32 usriX_flags;
+ string usriX_script_path;
+ uint32 usriX_auth_flags;
+ string usriX_full_name;
+ string usriX_usr_comment;
+ string usriX_parms;
+ string usriX_workstations;
+ uint32 usriX_last_logon;
+ uint32 usriX_last_logoff;
+ uint32 usriX_acct_expires;
+ uint32 usriX_max_storage;
+ uint32 usriX_units_per_week;
+ uint8 *usriX_logon_hours;
+ uint32 usriX_bad_pw_count;
+ uint32 usriX_num_logons;
+ string usriX_logon_server;
+ uint32 usriX_country_code;
+ uint32 usriX_code_page;
+ string usriX_profile;
+ string usriX_home_dir_drive;
+ uint32 usriX_primary_group_id;
+ } USER_INFO_X;
+
+ [nopush,nopull] NET_API_STATUS NetUserAdd(
+ [in,unique] string *server_name,
+ [in] uint32 level,
+ [in,ref] uint8 *buffer,
+ [out,ref] uint32 *parm_error
+ );
+
+ /*******************************************/
+ /* NetUserDel */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetUserDel(
+ [in,unique] string *server_name,
+ [in,ref] string *user_name
+ );
+
+ /*******************************************/
+ /* NetUserEnum */
+ /*******************************************/
+
+ const int FILTER_TEMP_DUPLICATE_ACCOUNT = 0x0001;
+ const int FILTER_NORMAL_ACCOUNT = 0x0002;
+ const int FILTER_INTERDOMAIN_TRUST_ACCOUNT = 0x0008;
+ const int FILTER_WORKSTATION_TRUST_ACCOUNT = 0x0010;
+ const int FILTER_SERVER_TRUST_ACCOUNT = 0x0020;
+
+ [nopush,nopull] NET_API_STATUS NetUserEnum(
+ [in,unique] string *server_name,
+ [in] uint32 level,
+ [in] uint32 filter,
+ [out,ref] uint8 **buffer,
+ [in] uint32 prefmaxlen,
+ [out,ref] uint32 *entries_read,
+ [out,ref] uint32 *total_entries,
+ [in,out,ref] uint32 *resume_handle
+ );
+
+ /*******************************************/
+ /* NetUserChangePassword */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetUserChangePassword(
+ [in] string domain_name,
+ [in] string user_name,
+ [in] string old_password,
+ [in] string new_password
+ );
+
+ /*******************************************/
+ /* NetUserGetInfo */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetUserGetInfo(
+ [in] string server_name,
+ [in] string user_name,
+ [in] uint32 level,
+ [out] uint8 **buffer
+ );
+
+ /*******************************************/
+ /* NetUserSetInfo */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetUserSetInfo(
+ [in] string server_name,
+ [in] string user_name,
+ [in] uint32 level,
+ [in] uint8 *buffer,
+ [out] uint32 *parm_err
+ );
+
+ /*******************************************/
+ /* NetUserGetGroups */
+ /*******************************************/
+
+ [public] typedef struct {
+ string grui0_name;
+ } GROUP_USERS_INFO_0;
+
+ [public] typedef struct {
+ string grui1_name;
+ uint32 grui1_attributes;
+ } GROUP_USERS_INFO_1;
+
+ [nopush,nopull] NET_API_STATUS NetUserGetGroups(
+ [in] string server_name,
+ [in] string user_name,
+ [in] uint32 level,
+ [out] uint8 **buffer,
+ [in] uint32 prefmaxlen,
+ [out,ref] uint32 *entries_read,
+ [out,ref] uint32 *total_entries
+ );
+
+ /*******************************************/
+ /* NetUserSetGroups */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetUserSetGroups(
+ [in] string server_name,
+ [in] string user_name,
+ [in] uint32 level,
+ [in] uint8 *buffer,
+ [in] uint32 num_entries
+ );
+
+ /*******************************************/
+ /* NetUserGetLocalGroups */
+ /*******************************************/
+
+ const int LG_INCLUDE_INDIRECT = 0x0001;
+
+ typedef struct {
+ string lgrui0_name;
+ } LOCALGROUP_USERS_INFO_0;
+
+ [nopush,nopull] NET_API_STATUS NetUserGetLocalGroups(
+ [in] string server_name,
+ [in] string user_name,
+ [in] uint32 level,
+ [in] uint32 flags,
+ [out] uint8 **buffer,
+ [in] uint32 prefmaxlen,
+ [out,ref] uint32 *entries_read,
+ [out,ref] uint32 *total_entries
+ );
+
+ /*******************************************/
+ /* NetUserModalsGet */
+ /*******************************************/
+
+ const int TIMEQ_FOREVER = (uint32_t)-1L;
+
+ typedef struct {
+ uint32 usrmod0_min_passwd_len;
+ uint32 usrmod0_max_passwd_age;
+ uint32 usrmod0_min_passwd_age;
+ uint32 usrmod0_force_logoff;
+ uint32 usrmod0_password_hist_len;
+ } USER_MODALS_INFO_0;
+
+ typedef struct {
+ uint32 usrmod1_role;
+ string usrmod1_primary;
+ } USER_MODALS_INFO_1;
+
+ typedef struct {
+ string usrmod2_domain_name;
+ domsid *usrmod2_domain_id;
+ } USER_MODALS_INFO_2;
+
+ typedef struct {
+ uint32 usrmod3_lockout_duration;
+ uint32 usrmod3_lockout_observation_window;
+ uint32 usrmod3_lockout_threshold;
+ } USER_MODALS_INFO_3;
+
+ typedef struct {
+ uint32 usrmod1001_min_passwd_len;
+ } USER_MODALS_INFO_1001;
+
+ typedef struct {
+ uint32 usrmod1002_max_passwd_age;
+ } USER_MODALS_INFO_1002;
+
+ typedef struct {
+ uint32 usrmod1003_min_passwd_age;
+ } USER_MODALS_INFO_1003;
+
+ typedef struct {
+ uint32 usrmod1004_force_logoff;
+ } USER_MODALS_INFO_1004;
+
+ typedef struct {
+ uint32 usrmod1005_password_hist_len;
+ } USER_MODALS_INFO_1005;
+
+ typedef struct {
+ uint32 usrmod1006_role;
+ } USER_MODALS_INFO_1006;
+
+ typedef struct {
+ string usrmod1007_primary;
+ } USER_MODALS_INFO_1007;
+
+ [nopush,nopull] NET_API_STATUS NetUserModalsGet(
+ [in] string server_name,
+ [in] uint32 level,
+ [out,ref] uint8 **buffer
+ );
+
+ /*******************************************/
+ /* NetUserModalsSet */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetUserModalsSet(
+ [in] string server_name,
+ [in] uint32 level,
+ [in] uint8 *buffer,
+ [out,ref] uint32 *parm_err
+ );
+
+ /*******************************************/
+ /* NetQueryDisplayInformation */
+ /*******************************************/
+
+ [public] typedef struct {
+ string usri1_name;
+ string usri1_comment;
+ uint32 usri1_flags;
+ string usri1_full_name;
+ uint32 usri1_user_id;
+ uint32 usri1_next_index;
+ } NET_DISPLAY_USER;
+
+ [public] typedef struct {
+ string usri2_name;
+ string usri2_comment;
+ uint32 usri2_flags;
+ uint32 usri2_user_id;
+ uint32 usri2_next_index;
+ } NET_DISPLAY_MACHINE;
+
+ [public] typedef struct {
+ string grpi3_name;
+ string grpi3_comment;
+ uint32 grpi3_group_id;
+ uint32 grpi3_attributes;
+ uint32 grpi3_next_index;
+ } NET_DISPLAY_GROUP;
+
+ [nopush,nopull] NET_API_STATUS NetQueryDisplayInformation(
+ [in,unique] string *server_name,
+ [in] uint32 level,
+ [in] uint32 idx,
+ [in] uint32 entries_requested,
+ [in] uint32 prefmaxlen,
+ [out,ref] uint32 *entries_read,
+ [out,ref,noprint] void **buffer
+ );
+
+ /*******************************************/
+ /* NetGroupAdd */
+ /*******************************************/
+
+ typedef struct {
+ string grpi0_name;
+ } GROUP_INFO_0;
+
+ typedef struct {
+ string grpi1_name;
+ string grpi1_comment;
+ } GROUP_INFO_1;
+
+ typedef struct {
+ string grpi2_name;
+ string grpi2_comment;
+ uint32 grpi2_group_id;
+ uint32 grpi2_attributes;
+ } GROUP_INFO_2;
+
+ typedef struct {
+ string grpi3_name;
+ string grpi3_comment;
+ domsid *grpi3_group_sid;
+ uint32 grpi3_attributes;
+ } GROUP_INFO_3;
+
+ typedef struct {
+ string grpi1002_comment;
+ } GROUP_INFO_1002;
+
+ typedef struct {
+ uint32 grpi1005_attributes;
+ } GROUP_INFO_1005;
+
+ [nopush,nopull] NET_API_STATUS NetGroupAdd(
+ [in] string server_name,
+ [in] uint32 level,
+ [in] uint8 *buffer,
+ [out] uint32 *parm_err
+ );
+
+ /*******************************************/
+ /* NetGroupDel */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetGroupDel(
+ [in] string server_name,
+ [in] string group_name
+ );
+
+ /*******************************************/
+ /* NetGroupEnum */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetGroupEnum(
+ [in] string server_name,
+ [in] uint32 level,
+ [out,ref] uint8 **buffer,
+ [in] uint32 prefmaxlen,
+ [out,ref] uint32 *entries_read,
+ [out,ref] uint32 *total_entries,
+ [in,out,ref] uint32 *resume_handle
+ );
+
+ /*******************************************/
+ /* NetGroupSetInfo */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetGroupSetInfo(
+ [in] string server_name,
+ [in] string group_name,
+ [in] uint32 level,
+ [in] uint8 *buffer,
+ [out] uint32 *parm_err
+ );
+
+ /*******************************************/
+ /* NetGroupGetInfo */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetGroupGetInfo(
+ [in] string server_name,
+ [in] string group_name,
+ [in] uint32 level,
+ [out] uint8 **buffer
+ );
+
+ /*******************************************/
+ /* NetGroupAddUser */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetGroupAddUser(
+ [in] string server_name,
+ [in] string group_name,
+ [in] string user_name
+ );
+
+ /*******************************************/
+ /* NetGroupDelUser */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetGroupDelUser(
+ [in] string server_name,
+ [in] string group_name,
+ [in] string user_name
+ );
+
+ /*******************************************/
+ /* NetGroupGetUsers */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetGroupGetUsers(
+ [in] string server_name,
+ [in] string group_name,
+ [in] uint32 level,
+ [out] uint8 **buffer,
+ [in] uint32 prefmaxlen,
+ [out,ref] uint32 *entries_read,
+ [out,ref] uint32 *total_entries,
+ [in,out,ref] uint32 *resume_handle
+ );
+
+ /*******************************************/
+ /* NetGroupSetUsers */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetGroupSetUsers(
+ [in] string server_name,
+ [in] string group_name,
+ [in] uint32 level,
+ [in] uint8 *buffer,
+ [in] uint32 num_entries
+ );
+
+ /*******************************************/
+ /* NetLocalGroupAdd */
+ /*******************************************/
+
+ typedef struct {
+ string lgrpi0_name;
+ } LOCALGROUP_INFO_0;
+
+ typedef struct {
+ string lgrpi1_name;
+ string lgrpi1_comment;
+ } LOCALGROUP_INFO_1;
+
+ typedef struct {
+ string lgrpi1002_comment;
+ } LOCALGROUP_INFO_1002;
+
+ [nopush,nopull] NET_API_STATUS NetLocalGroupAdd(
+ [in] string server_name,
+ [in] uint32 level,
+ [in] uint8 *buffer,
+ [out,ref] uint32 *parm_err
+ );
+
+ /*******************************************/
+ /* NetLocalGroupDel */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetLocalGroupDel(
+ [in] string server_name,
+ [in] string group_name
+ );
+
+ /*******************************************/
+ /* NetLocalGroupGetInfo */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetLocalGroupGetInfo(
+ [in] string server_name,
+ [in] string group_name,
+ [in] uint32 level,
+ [out,ref] uint8 **buffer
+ );
+
+ /*******************************************/
+ /* NetLocalGroupSetInfo */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetLocalGroupSetInfo(
+ [in] string server_name,
+ [in] string group_name,
+ [in] uint32 level,
+ [in,ref] uint8 *buffer,
+ [out,ref] uint32 *parm_err
+ );
+
+ /*******************************************/
+ /* NetLocalGroupEnum */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetLocalGroupEnum(
+ [in] string server_name,
+ [in] uint32 level,
+ [out,ref] uint8 **buffer,
+ [in] uint32 prefmaxlen,
+ [out,ref] uint32 *entries_read,
+ [out,ref] uint32 *total_entries,
+ [in,out,ref] uint32 *resume_handle
+ );
+
+ /*******************************************/
+ /* NetLocalGroupAddMembers */
+ /*******************************************/
+
+ typedef enum {
+ SidTypeUser = 1,
+ SidTypeGroup = 2,
+ SidTypeDomain = 3,
+ SidTypeAlias = 4,
+ SidTypeWellKnownGroup = 5,
+ SidTypeDeletedAccount = 6,
+ SidTypeInvalid = 7,
+ SidTypeUnknown = 8,
+ SidTypeComputer = 9,
+ SidTypeLabel = 10
+ } SID_NAME_USE;
+
+ typedef struct {
+ domsid *lgrmi0_sid;
+ } LOCALGROUP_MEMBERS_INFO_0;
+
+ typedef struct {
+ domsid *lgrmi1_sid;
+ SID_NAME_USE lgrmi1_sidusage;
+ string lgrmi1_name;
+ } LOCALGROUP_MEMBERS_INFO_1;
+
+ typedef struct {
+ domsid *lgrmi2_sid;
+ SID_NAME_USE lgrmi2_sidusage;
+ string lgrmi2_domainandname;
+ } LOCALGROUP_MEMBERS_INFO_2;
+
+ typedef struct {
+ string lgrmi3_domainandname;
+ } LOCALGROUP_MEMBERS_INFO_3;
+
+ [nopush,nopull] NET_API_STATUS NetLocalGroupAddMembers(
+ [in] string server_name,
+ [in] string group_name,
+ [in] uint32 level,
+ [in] uint8 *buffer,
+ [in] uint32 total_entries
+ );
+
+ /*******************************************/
+ /* NetLocalGroupDelMembers */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetLocalGroupDelMembers(
+ [in] string server_name,
+ [in] string group_name,
+ [in] uint32 level,
+ [in] uint8 *buffer,
+ [in] uint32 total_entries
+ );
+
+ /*******************************************/
+ /* NetLocalGroupGetMembers */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetLocalGroupGetMembers(
+ [in] string server_name,
+ [in] string local_group_name,
+ [in] uint32 level,
+ [out] uint8 **buffer,
+ [in] uint32 prefmaxlen,
+ [out] uint32 *entries_read,
+ [out] uint32 *total_entries,
+ [in,out] uint32 *resume_handle
+ );
+
+ /*******************************************/
+ /* NetLocalGroupSetMembers */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetLocalGroupSetMembers(
+ [in] string server_name,
+ [in] string group_name,
+ [in] uint32 level,
+ [in] uint8 *buffer,
+ [in] uint32 total_entries
+ );
+
+ /*******************************************/
+ /* NetRemoteTOD */
+ /*******************************************/
+
+ typedef struct {
+ uint32 tod_elapsedt;
+ uint32 tod_msecs;
+ uint32 tod_hours;
+ uint32 tod_mins;
+ uint32 tod_secs;
+ uint32 tod_hunds;
+ int32 tod_timezone;
+ uint32 tod_tinterval;
+ uint32 tod_day;
+ uint32 tod_month;
+ uint32 tod_year;
+ uint32 tod_weekday;
+ } TIME_OF_DAY_INFO;
+
+ [nopush,nopull] NET_API_STATUS NetRemoteTOD(
+ [in] string server_name,
+ [out,ref] uint8 **buffer
+ );
+
+ /*******************************************/
+ /* NetShareAdd */
+ /*******************************************/
+
+ typedef struct {
+ string shi0_netname;
+ } SHARE_INFO_0;
+
+ typedef struct {
+ string shi1_netname;
+ uint32 shi1_type;
+ string shi1_remark;
+ } SHARE_INFO_1;
+
+ typedef struct {
+ string shi2_netname;
+ uint32 shi2_type;
+ string shi2_remark;
+ uint32 shi2_permissions;
+ uint32 shi2_max_uses;
+ uint32 shi2_current_uses;
+ string shi2_path;
+ string shi2_passwd;
+ } SHARE_INFO_2;
+
+ typedef struct {
+ string shi501_netname;
+ uint32 shi501_type;
+ string shi501_remark;
+ uint32 shi501_flags;
+ } SHARE_INFO_501;
+
+ typedef struct {
+ string shi1004_remark;
+ } SHARE_INFO_1004;
+
+ const int CSC_MASK = 0x30;
+
+ typedef [public,bitmap32bit] bitmap {
+ SHI1005_FLAGS_DFS = 0x01,
+ SHI1005_FLAGS_DFS_ROOT = 0x02,
+ CSC_CACHE_MANUAL_REINT = 0x00,
+ CSC_CACHE_AUTO_REINT = 0x10,
+ CSC_CACHE_VDO = 0x20,
+ CSC_CACHE_NONE = 0x30,
+ SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS = 0x0100,
+ SHI1005_FLAGS_FORCE_SHARED_DELETE = 0x0200,
+ SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING = 0x0400,
+ SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM = 0x0800
+ } SHARE_INFO_1005_FLAGS;
+
+ typedef struct {
+ SHARE_INFO_1005_FLAGS shi1005_flags;
+ } SHARE_INFO_1005;
+
+ typedef struct {
+ uint32 shi1006_max_uses;
+ } SHARE_INFO_1006;
+
+ [nopush,nopull] NET_API_STATUS NetShareAdd(
+ [in] string server_name,
+ [in] uint32 level,
+ [in] uint8 *buffer,
+ [out] uint32 *parm_err
+ );
+
+ /*******************************************/
+ /* NetShareDel */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetShareDel(
+ [in] string server_name,
+ [in] string net_name,
+ [in] uint32 reserved
+ );
+
+ /*******************************************/
+ /* NetShareEnum */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetShareEnum(
+ [in] string server_name,
+ [in] uint32 level,
+ [out] uint8 **buffer,
+ [in] uint32 prefmaxlen,
+ [out] uint32 *entries_read,
+ [out] uint32 *total_entries,
+ [in,out] uint32 *resume_handle
+ );
+
+ /*******************************************/
+ /* NetShareGetInfo */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetShareGetInfo(
+ [in] string server_name,
+ [in] string net_name,
+ [in] uint32 level,
+ [out] uint8 **buffer
+ );
+
+ /*******************************************/
+ /* NetShareSetInfo */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetShareSetInfo(
+ [in] string server_name,
+ [in] string net_name,
+ [in] uint32 level,
+ [in] uint8 *buffer,
+ [out] uint32 *parm_err
+ );
+
+ /*******************************************/
+ /* NetFileClose */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetFileClose(
+ [in] string server_name,
+ [in] uint32 fileid
+ );
+
+ /*******************************************/
+ /* NetFileGetInfo */
+ /*******************************************/
+
+ typedef struct {
+ uint32 fi2_id;
+ } FILE_INFO_2;
+
+ typedef struct {
+ uint32 fi3_id;
+ uint32 fi3_permissions;
+ uint32 fi3_num_locks;
+ string fi3_pathname;
+ string fi3_username;
+ } FILE_INFO_3;
+
+ [nopush,nopull] NET_API_STATUS NetFileGetInfo(
+ [in] string server_name,
+ [in] uint32 fileid,
+ [in] uint32 level,
+ [out] uint8 **buffer
+ );
+
+ /*******************************************/
+ /* NetFileEnum */
+ /*******************************************/
+
+ [nopush,nopull] NET_API_STATUS NetFileEnum(
+ [in] string server_name,
+ [in] string base_path,
+ [in] string user_name,
+ [in] uint32 level,
+ [out] uint8 **buffer,
+ [in] uint32 prefmaxlen,
+ [out] uint32 *entries_read,
+ [out] uint32 *total_entries,
+ [in,out] uint32 *resume_handle
+ );
+}
diff --git a/source3/librpc/idl/lsa.idl b/source3/librpc/idl/lsa.idl
new file mode 100644
index 0000000000..cb16f64dab
--- /dev/null
+++ b/source3/librpc/idl/lsa.idl
@@ -0,0 +1,1103 @@
+#include "idl_types.h"
+
+/*
+ lsa interface definition
+*/
+
+import "security.idl";
+
+[ uuid("12345778-1234-abcd-ef00-0123456789ab"),
+ version(0.0),
+ endpoint("ncacn_np:[\\pipe\\lsarpc]","ncacn_np:[\\pipe\\netlogon]","ncacn_np:[\\pipe\\lsass]", "ncacn_ip_tcp:", "ncalrpc:"),
+ pointer_default(unique),
+ helpstring("Local Security Authority")
+] interface lsarpc
+{
+ typedef bitmap security_secinfo security_secinfo;
+
+ typedef [public,noejs] struct {
+ [value(2*strlen_m(string))] uint16 length;
+ [value(2*strlen_m(string))] uint16 size;
+ [charset(UTF16),size_is(size/2),length_is(length/2)] uint16 *string;
+ } lsa_String;
+
+ typedef [public] struct {
+ [value(2*strlen_m(string))] uint16 length;
+ [value(2*strlen_m_term(string))] uint16 size;
+ [charset(UTF16),size_is(size/2),length_is(length/2)] uint16 *string;
+ } lsa_StringLarge;
+
+ typedef [public] struct {
+ uint32 count;
+ [size_is(count)] lsa_String *names;
+ } lsa_Strings;
+
+ typedef [public] struct {
+ [value(strlen_m(string))] uint16 length;
+ [value(strlen_m(string))] uint16 size;
+ [charset(DOS),size_is(size),length_is(length)] uint8 *string;
+ } lsa_AsciiString;
+
+ typedef [public] struct {
+ [value(strlen_m(string))] uint16 length;
+ [value(strlen_m_term(string))] uint16 size;
+ [charset(DOS),size_is(size),length_is(length)] uint8 *string;
+ } lsa_AsciiStringLarge;
+
+ typedef [public] struct {
+ uint16 length;
+ uint16 size;
+ [size_is(size/2),length_is(length/2)] uint16 *array;
+ } lsa_BinaryString;
+
+ /******************/
+ /* Function: 0x00 */
+ NTSTATUS lsa_Close (
+ [in,out] policy_handle *handle
+ );
+
+
+ /******************/
+ /* Function: 0x01 */
+ [public] NTSTATUS lsa_Delete (
+ [in] policy_handle *handle
+ );
+
+
+ /******************/
+ /* Function: 0x02 */
+ typedef struct {
+ uint32 low;
+ uint32 high;
+ } lsa_LUID;
+
+ typedef struct {
+ lsa_StringLarge name;
+ lsa_LUID luid;
+ } lsa_PrivEntry;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] lsa_PrivEntry *privs;
+ } lsa_PrivArray;
+
+ [public] NTSTATUS lsa_EnumPrivs (
+ [in] policy_handle *handle,
+ [in,out,ref] uint32 *resume_handle,
+ [out,ref] lsa_PrivArray *privs,
+ [in] uint32 max_count
+ );
+
+ /******************/
+ /* Function: 0x03 */
+
+ NTSTATUS lsa_QuerySecurity (
+ [in] policy_handle *handle,
+ [in] security_secinfo sec_info,
+ [out,ref] sec_desc_buf **sdbuf
+ );
+
+
+ /******************/
+ /* Function: 0x04 */
+ NTSTATUS lsa_SetSecObj(
+ [in] policy_handle *handle,
+ [in] security_secinfo sec_info,
+ [in,ref] sec_desc_buf *sdbuf
+ );
+
+ /******************/
+ /* Function: 0x05 */
+ NTSTATUS lsa_ChangePassword ();
+
+
+ /******************/
+ /* Function: 0x06 */
+ typedef struct {
+ uint32 len; /* ignored */
+ uint16 impersonation_level;
+ uint8 context_mode;
+ uint8 effective_only;
+ } lsa_QosInfo;
+
+ typedef struct {
+ uint32 len; /* ignored */
+ uint8 *root_dir;
+ [string,charset(UTF16)] uint16 *object_name;
+ uint32 attributes;
+ security_descriptor *sec_desc;
+ lsa_QosInfo *sec_qos;
+ } lsa_ObjectAttribute;
+
+ typedef [public,bitmap32bit] bitmap {
+ LSA_POLICY_VIEW_LOCAL_INFORMATION = 0x00000001,
+ LSA_POLICY_VIEW_AUDIT_INFORMATION = 0x00000002,
+ LSA_POLICY_GET_PRIVATE_INFORMATION = 0x00000004,
+ LSA_POLICY_TRUST_ADMIN = 0x00000008,
+ LSA_POLICY_CREATE_ACCOUNT = 0x00000010,
+ LSA_POLICY_CREATE_SECRET = 0x00000020,
+ LSA_POLICY_CREATE_PRIVILEGE = 0x00000040,
+ LSA_POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080,
+ LSA_POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100,
+ LSA_POLICY_AUDIT_LOG_ADMIN = 0x00000200,
+ LSA_POLICY_SERVER_ADMIN = 0x00000400,
+ LSA_POLICY_LOOKUP_NAMES = 0x00000800
+ } lsa_PolicyAccessMask;
+
+ /* notice the screwup with the system_name - thats why MS created
+ OpenPolicy2 */
+ [public] NTSTATUS lsa_OpenPolicy (
+ [in,unique] uint16 *system_name,
+ [in] lsa_ObjectAttribute *attr,
+ [in] lsa_PolicyAccessMask access_mask,
+ [out] policy_handle *handle
+ );
+
+
+
+ /******************/
+ /* Function: 0x07 */
+
+ typedef struct {
+ uint32 percent_full;
+ uint32 log_size;
+ NTTIME retention_time;
+ uint8 shutdown_in_progress;
+ NTTIME time_to_shutdown;
+ uint32 next_audit_record;
+ uint32 unknown;
+ } lsa_AuditLogInfo;
+
+ typedef [v1_enum] enum {
+ LSA_AUDIT_POLICY_NONE=0,
+ LSA_AUDIT_POLICY_SUCCESS=1,
+ LSA_AUDIT_POLICY_FAILURE=2,
+ LSA_AUDIT_POLICY_ALL=(LSA_AUDIT_POLICY_SUCCESS|LSA_AUDIT_POLICY_FAILURE),
+ LSA_AUDIT_POLICY_CLEAR=4
+ } lsa_PolicyAuditPolicy;
+
+ typedef enum {
+ LSA_AUDIT_CATEGORY_SYSTEM = 0,
+ LSA_AUDIT_CATEGORY_LOGON = 1,
+ LSA_AUDIT_CATEGORY_FILE_AND_OBJECT_ACCESS = 2,
+ LSA_AUDIT_CATEGORY_USE_OF_USER_RIGHTS = 3,
+ LSA_AUDIT_CATEGORY_PROCCESS_TRACKING = 4,
+ LSA_AUDIT_CATEGORY_SECURITY_POLICY_CHANGES = 5,
+ LSA_AUDIT_CATEGORY_ACCOUNT_MANAGEMENT = 6,
+ LSA_AUDIT_CATEGORY_DIRECTORY_SERVICE_ACCESS = 7, /* only in win2k/2k3 */
+ LSA_AUDIT_CATEGORY_ACCOUNT_LOGON = 8 /* only in win2k/2k3 */
+ } lsa_PolicyAuditEventType;
+
+ typedef struct {
+ uint32 auditing_mode;
+ [size_is(count)] lsa_PolicyAuditPolicy *settings;
+ uint32 count;
+ } lsa_AuditEventsInfo;
+
+ typedef struct {
+ lsa_StringLarge name;
+ dom_sid2 *sid;
+ } lsa_DomainInfo;
+
+ typedef struct {
+ lsa_String name;
+ } lsa_PDAccountInfo;
+
+ typedef struct {
+ uint16 unknown; /* an midl padding bug? */
+ uint16 role;
+ } lsa_ServerRole;
+
+ typedef struct {
+ lsa_String source;
+ lsa_String account;
+ } lsa_ReplicaSourceInfo;
+
+ typedef struct {
+ uint32 paged_pool;
+ uint32 non_paged_pool;
+ uint32 min_wss;
+ uint32 max_wss;
+ uint32 pagefile;
+ hyper unknown;
+ } lsa_DefaultQuotaInfo;
+
+ typedef struct {
+ hyper modified_id;
+ NTTIME db_create_time;
+ } lsa_ModificationInfo;
+
+ typedef struct {
+ uint8 shutdown_on_full;
+ } lsa_AuditFullSetInfo;
+
+ typedef struct {
+ uint16 unknown; /* an midl padding bug? */
+ uint8 shutdown_on_full;
+ uint8 log_is_full;
+ } lsa_AuditFullQueryInfo;
+
+ typedef struct {
+ /* it's important that we use the lsa_StringLarge here,
+ * because otherwise windows clients result with such dns hostnames
+ * e.g. w2k3-client.samba4.samba.orgsamba4.samba.org
+ * where it should be
+ * w2k3-client.samba4.samba.org
+ */
+ lsa_StringLarge name;
+ lsa_StringLarge dns_domain;
+ lsa_StringLarge dns_forest;
+ GUID domain_guid;
+ dom_sid2 *sid;
+ } lsa_DnsDomainInfo;
+
+ typedef enum {
+ LSA_POLICY_INFO_AUDIT_LOG=1,
+ LSA_POLICY_INFO_AUDIT_EVENTS=2,
+ LSA_POLICY_INFO_DOMAIN=3,
+ LSA_POLICY_INFO_PD=4,
+ LSA_POLICY_INFO_ACCOUNT_DOMAIN=5,
+ LSA_POLICY_INFO_ROLE=6,
+ LSA_POLICY_INFO_REPLICA=7,
+ LSA_POLICY_INFO_QUOTA=8,
+ LSA_POLICY_INFO_DB=9,
+ LSA_POLICY_INFO_AUDIT_FULL_SET=10,
+ LSA_POLICY_INFO_AUDIT_FULL_QUERY=11,
+ LSA_POLICY_INFO_DNS=12
+ } lsa_PolicyInfo;
+
+ typedef [switch_type(uint16)] union {
+ [case(LSA_POLICY_INFO_AUDIT_LOG)] lsa_AuditLogInfo audit_log;
+ [case(LSA_POLICY_INFO_AUDIT_EVENTS)] lsa_AuditEventsInfo audit_events;
+ [case(LSA_POLICY_INFO_DOMAIN)] lsa_DomainInfo domain;
+ [case(LSA_POLICY_INFO_PD)] lsa_PDAccountInfo pd;
+ [case(LSA_POLICY_INFO_ACCOUNT_DOMAIN)] lsa_DomainInfo account_domain;
+ [case(LSA_POLICY_INFO_ROLE)] lsa_ServerRole role;
+ [case(LSA_POLICY_INFO_REPLICA)] lsa_ReplicaSourceInfo replica;
+ [case(LSA_POLICY_INFO_QUOTA)] lsa_DefaultQuotaInfo quota;
+ [case(LSA_POLICY_INFO_DB)] lsa_ModificationInfo db;
+ [case(LSA_POLICY_INFO_AUDIT_FULL_SET)] lsa_AuditFullSetInfo auditfullset;
+ [case(LSA_POLICY_INFO_AUDIT_FULL_QUERY)] lsa_AuditFullQueryInfo auditfullquery;
+ [case(LSA_POLICY_INFO_DNS)] lsa_DnsDomainInfo dns;
+ } lsa_PolicyInformation;
+
+ NTSTATUS lsa_QueryInfoPolicy(
+ [in] policy_handle *handle,
+ [in] lsa_PolicyInfo level,
+ [out,ref,switch_is(level)] lsa_PolicyInformation **info
+ );
+
+ /******************/
+ /* Function: 0x08 */
+ NTSTATUS lsa_SetInfoPolicy (
+ [in] policy_handle *handle,
+ [in] lsa_PolicyInfo level,
+ [in,switch_is(level)] lsa_PolicyInformation *info
+ );
+
+ /******************/
+ /* Function: 0x09 */
+ NTSTATUS lsa_ClearAuditLog ();
+
+ /******************/
+ /* Function: 0x0a */
+ [public] NTSTATUS lsa_CreateAccount (
+ [in] policy_handle *handle,
+ [in,ref] dom_sid2 *sid,
+ [in] uint32 access_mask,
+ [out] policy_handle *acct_handle
+ );
+
+ /******************/
+ /* NOTE: This only returns accounts that have at least
+ one privilege set
+ */
+ /* Function: 0x0b */
+ typedef struct {
+ dom_sid2 *sid;
+ } lsa_SidPtr;
+
+ typedef [public] struct {
+ [range(0,1000)] uint32 num_sids;
+ [size_is(num_sids)] lsa_SidPtr *sids;
+ } lsa_SidArray;
+
+ [public] NTSTATUS lsa_EnumAccounts (
+ [in] policy_handle *handle,
+ [in,out,ref] uint32 *resume_handle,
+ [out,ref] lsa_SidArray *sids,
+ [in,range(0,8192)] uint32 num_entries
+ );
+
+
+ /*************************************************/
+ /* Function: 0x0c */
+
+ [public] NTSTATUS lsa_CreateTrustedDomain(
+ [in] policy_handle *handle,
+ [in] lsa_DomainInfo *info,
+ [in] uint32 access_mask,
+ [out] policy_handle *trustdom_handle
+ );
+
+
+ /******************/
+ /* Function: 0x0d */
+
+ /* w2k3 treats max_size as max_domains*60 */
+ const int LSA_ENUM_TRUST_DOMAIN_MULTIPLIER = 60;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] lsa_DomainInfo *domains;
+ } lsa_DomainList;
+
+ NTSTATUS lsa_EnumTrustDom (
+ [in] policy_handle *handle,
+ [in,out,ref] uint32 *resume_handle,
+ [out,ref] lsa_DomainList *domains,
+ [in] uint32 max_size
+ );
+
+
+ /******************/
+ /* Function: 0x0e */
+ typedef enum {
+ SID_NAME_USE_NONE = 0,/* NOTUSED */
+ SID_NAME_USER = 1, /* user */
+ SID_NAME_DOM_GRP = 2, /* domain group */
+ SID_NAME_DOMAIN = 3, /* domain: don't know what this is */
+ SID_NAME_ALIAS = 4, /* local group */
+ SID_NAME_WKN_GRP = 5, /* well-known group */
+ SID_NAME_DELETED = 6, /* deleted account: needed for c2 rating */
+ SID_NAME_INVALID = 7, /* invalid account */
+ SID_NAME_UNKNOWN = 8, /* oops. */
+ SID_NAME_COMPUTER = 9 /* machine */
+ } lsa_SidType;
+
+ typedef struct {
+ lsa_SidType sid_type;
+ uint32 rid;
+ uint32 sid_index;
+ } lsa_TranslatedSid;
+
+ typedef struct {
+ [range(0,1000)] uint32 count;
+ [size_is(count)] lsa_TranslatedSid *sids;
+ } lsa_TransSidArray;
+
+ const int LSA_REF_DOMAIN_LIST_MULTIPLIER = 32;
+ const int MAX_REF_DOMAINS = LSA_REF_DOMAIN_LIST_MULTIPLIER;
+
+ typedef struct {
+ [range(0,1000)] uint32 count;
+ [size_is(count)] lsa_DomainInfo *domains;
+ uint32 max_size;
+ } lsa_RefDomainList;
+
+ /* Level 1: Ask everywhere
+ * Level 2: Ask domain and trusted domains, no builtin and wkn
+ * Level 3: Only ask domain
+ * Level 4: W2k3ad: Only ask AD trusts
+ * Level 5: Only ask transitive forest trusts
+ * Level 6: Like 4
+ */
+
+ typedef enum {
+ LSA_LOOKUP_NAMES_ALL = 1,
+ LSA_LOOKUP_NAMES_DOMAINS_ONLY = 2,
+ LSA_LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY = 3,
+ LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY = 4,
+ LSA_LOOKUP_NAMES_FOREST_TRUSTS_ONLY = 5,
+ LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2 = 6
+ } lsa_LookupNamesLevel;
+
+ [public] NTSTATUS lsa_LookupNames (
+ [in] policy_handle *handle,
+ [in,range(0,1000)] uint32 num_names,
+ [in,size_is(num_names)] lsa_String names[],
+ [out,ref] lsa_RefDomainList **domains,
+ [in,out,ref] lsa_TransSidArray *sids,
+ [in] lsa_LookupNamesLevel level,
+ [in,out,ref] uint32 *count
+ );
+
+
+ /******************/
+ /* Function: 0x0f */
+
+ typedef struct {
+ lsa_SidType sid_type;
+ lsa_String name;
+ uint32 sid_index;
+ } lsa_TranslatedName;
+
+ typedef struct {
+ [range(0,1000)] uint32 count;
+ [size_is(count)] lsa_TranslatedName *names;
+ } lsa_TransNameArray;
+
+ /* This number is based on Win2k and later maximum response allowed */
+ const int MAX_LOOKUP_SIDS = 0x5000; /* 20480 */
+
+ [public] NTSTATUS lsa_LookupSids (
+ [in] policy_handle *handle,
+ [in,ref] lsa_SidArray *sids,
+ [out,ref] lsa_RefDomainList **domains,
+ [in,out,ref] lsa_TransNameArray *names,
+ [in] uint16 level,
+ [in,out,ref] uint32 *count
+ );
+
+
+ /* Function: 0x10 */
+ [public] NTSTATUS lsa_CreateSecret(
+ [in] policy_handle *handle,
+ [in] lsa_String name,
+ [in] uint32 access_mask,
+ [out] policy_handle *sec_handle
+ );
+
+
+ /*****************************************/
+ /* Function: 0x11 */
+ NTSTATUS lsa_OpenAccount(
+ [in] policy_handle *handle,
+ [in,ref] dom_sid2 *sid,
+ [in] uint32 access_mask,
+ [out] policy_handle *acct_handle
+ );
+
+
+ /****************************************/
+ /* Function: 0x12 */
+
+ typedef struct {
+ lsa_LUID luid;
+ uint32 attribute;
+ } lsa_LUIDAttribute;
+
+ typedef struct {
+ [range(0,1000)] uint32 count;
+ uint32 unknown;
+ [size_is(count)] lsa_LUIDAttribute set[*];
+ } lsa_PrivilegeSet;
+
+ NTSTATUS lsa_EnumPrivsAccount (
+ [in] policy_handle *handle,
+ [out,ref] lsa_PrivilegeSet **privs
+ );
+
+
+ /****************************************/
+ /* Function: 0x13 */
+ NTSTATUS lsa_AddPrivilegesToAccount(
+ [in] policy_handle *handle,
+ [in,ref] lsa_PrivilegeSet *privs
+ );
+
+
+ /****************************************/
+ /* Function: 0x14 */
+ NTSTATUS lsa_RemovePrivilegesFromAccount(
+ [in] policy_handle *handle,
+ [in] uint8 remove_all,
+ [in,unique] lsa_PrivilegeSet *privs
+ );
+
+ /* Function: 0x15 */
+ NTSTATUS lsa_GetQuotasForAccount();
+
+ /* Function: 0x16 */
+ NTSTATUS lsa_SetQuotasForAccount();
+
+ /* Function: 0x17 */
+ NTSTATUS lsa_GetSystemAccessAccount(
+ [in] policy_handle *handle,
+ [out,ref] uint32 *access_mask
+ );
+
+ /* Function: 0x18 */
+ NTSTATUS lsa_SetSystemAccessAccount(
+ [in] policy_handle *handle,
+ [in] uint32 access_mask
+ );
+
+ /* Function: 0x19 */
+ NTSTATUS lsa_OpenTrustedDomain(
+ [in] policy_handle *handle,
+ [in] dom_sid2 *sid,
+ [in] uint32 access_mask,
+ [out] policy_handle *trustdom_handle
+ );
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint32 length;
+ uint32 size;
+ [size_is(size),length_is(length)] uint8 *data;
+ } lsa_DATA_BUF;
+
+ typedef [flag(NDR_PAHEX)] struct {
+ [range(0,65536)] uint32 size;
+ [size_is(size)] uint8 *data;
+ } lsa_DATA_BUF2;
+
+ typedef enum {
+ LSA_TRUSTED_DOMAIN_INFO_NAME = 1,
+ LSA_TRUSTED_DOMAIN_INFO_CONTROLLERS_INFO = 2,
+ LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET = 3,
+ LSA_TRUSTED_DOMAIN_INFO_PASSWORD = 4,
+ LSA_TRUSTED_DOMAIN_INFO_BASIC = 5,
+ LSA_TRUSTED_DOMAIN_INFO_INFO_EX = 6,
+ LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO = 7,
+ LSA_TRUSTED_DOMAIN_INFO_FULL_INFO = 8,
+ LSA_TRUSTED_DOMAIN_INFO_11 = 11,
+ LSA_TRUSTED_DOMAIN_INFO_INFO_ALL = 12
+ } lsa_TrustDomInfoEnum;
+
+ typedef struct {
+ lsa_StringLarge netbios_name;
+ } lsa_TrustDomainInfoName;
+
+ typedef struct {
+ uint32 posix_offset;
+ } lsa_TrustDomainInfoPosixOffset;
+
+ typedef struct {
+ lsa_DATA_BUF *password;
+ lsa_DATA_BUF *old_password;
+ } lsa_TrustDomainInfoPassword;
+
+ typedef struct {
+ lsa_String netbios_name;
+ dom_sid2 *sid;
+ } lsa_TrustDomainInfoBasic;
+
+ typedef struct {
+ lsa_StringLarge domain_name;
+ lsa_StringLarge netbios_name;
+ dom_sid2 *sid;
+ uint32 trust_direction;
+ uint32 trust_type;
+ uint32 trust_attributes;
+ } lsa_TrustDomainInfoInfoEx;
+
+ typedef struct {
+ NTTIME_hyper last_update_time;
+ uint32 secret_type;
+ lsa_DATA_BUF2 data;
+ } lsa_TrustDomainInfoBuffer;
+
+ typedef struct {
+ uint32 incoming_count;
+ lsa_TrustDomainInfoBuffer *incoming_current_auth_info;
+ lsa_TrustDomainInfoBuffer *incoming_previous_auth_info;
+ uint32 outgoing_count;
+ lsa_TrustDomainInfoBuffer *outgoing_current_auth_info;
+ lsa_TrustDomainInfoBuffer *outgoing_previous_auth_info;
+ } lsa_TrustDomainInfoAuthInfo;
+
+ typedef struct {
+ lsa_TrustDomainInfoInfoEx info_ex;
+ lsa_TrustDomainInfoPosixOffset posix_offset;
+ lsa_TrustDomainInfoAuthInfo auth_info;
+ } lsa_TrustDomainInfoFullInfo;
+
+ typedef struct {
+ lsa_TrustDomainInfoInfoEx info_ex;
+ lsa_DATA_BUF2 data1;
+ } lsa_TrustDomainInfo11;
+
+ typedef struct {
+ lsa_TrustDomainInfoInfoEx info_ex;
+ lsa_DATA_BUF2 data1;
+ lsa_TrustDomainInfoPosixOffset posix_offset;
+ lsa_TrustDomainInfoAuthInfo auth_info;
+ } lsa_TrustDomainInfoInfoAll;
+
+ typedef [switch_type(lsa_TrustDomInfoEnum)] union {
+ [case(LSA_TRUSTED_DOMAIN_INFO_NAME)] lsa_TrustDomainInfoName name;
+ [case(LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET)] lsa_TrustDomainInfoPosixOffset posix_offset;
+ [case(LSA_TRUSTED_DOMAIN_INFO_PASSWORD)] lsa_TrustDomainInfoPassword password;
+ [case(LSA_TRUSTED_DOMAIN_INFO_BASIC)] lsa_TrustDomainInfoBasic info_basic;
+ [case(LSA_TRUSTED_DOMAIN_INFO_INFO_EX)] lsa_TrustDomainInfoInfoEx info_ex;
+ [case(LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO)] lsa_TrustDomainInfoAuthInfo auth_info;
+ [case(LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)] lsa_TrustDomainInfoFullInfo full_info;
+ [case(LSA_TRUSTED_DOMAIN_INFO_11)] lsa_TrustDomainInfo11 info11;
+ [case(LSA_TRUSTED_DOMAIN_INFO_INFO_ALL)] lsa_TrustDomainInfoInfoAll info_all;
+ } lsa_TrustedDomainInfo;
+
+ /* Function: 0x1a */
+ NTSTATUS lsa_QueryTrustedDomainInfo(
+ [in] policy_handle *trustdom_handle,
+ [in] lsa_TrustDomInfoEnum level,
+ [out,switch_is(level),ref] lsa_TrustedDomainInfo **info
+ );
+
+ /* Function: 0x1b */
+ NTSTATUS lsa_SetInformationTrustedDomain();
+
+ /* Function: 0x1c */
+ [public] NTSTATUS lsa_OpenSecret(
+ [in] policy_handle *handle,
+ [in] lsa_String name,
+ [in] uint32 access_mask,
+ [out] policy_handle *sec_handle
+ );
+
+ /* Function: 0x1d */
+
+ [public] NTSTATUS lsa_SetSecret(
+ [in] policy_handle *sec_handle,
+ [in,unique] lsa_DATA_BUF *new_val,
+ [in,unique] lsa_DATA_BUF *old_val
+ );
+
+ typedef struct {
+ lsa_DATA_BUF *buf;
+ } lsa_DATA_BUF_PTR;
+
+ /* Function: 0x1e */
+ [public] NTSTATUS lsa_QuerySecret (
+ [in] policy_handle *sec_handle,
+ [in,out,unique] lsa_DATA_BUF_PTR *new_val,
+ [in,out,unique] NTTIME_hyper *new_mtime,
+ [in,out,unique] lsa_DATA_BUF_PTR *old_val,
+ [in,out,unique] NTTIME_hyper *old_mtime
+ );
+
+ /* Function: 0x1f */
+ NTSTATUS lsa_LookupPrivValue(
+ [in] policy_handle *handle,
+ [in,ref] lsa_String *name,
+ [out,ref] lsa_LUID *luid
+ );
+
+
+ /* Function: 0x20 */
+ NTSTATUS lsa_LookupPrivName (
+ [in] policy_handle *handle,
+ [in,ref] lsa_LUID *luid,
+ [out,ref] lsa_StringLarge **name
+ );
+
+
+ /*******************/
+ /* Function: 0x21 */
+ NTSTATUS lsa_LookupPrivDisplayName (
+ [in] policy_handle *handle,
+ [in,ref] lsa_String *name,
+ [in] uint16 language_id,
+ [in] uint16 language_id_sys,
+ [out,ref] lsa_StringLarge **disp_name,
+ /* see http://www.microsoft.com/globaldev/nlsweb/ for
+ language definitions */
+ [out,ref] uint16 *returned_language_id
+ );
+
+ /* Function: 0x22 */
+ NTSTATUS lsa_DeleteObject(
+ [in,out] policy_handle *handle
+ );
+
+ /*******************/
+ /* Function: 0x23 */
+ NTSTATUS lsa_EnumAccountsWithUserRight (
+ [in] policy_handle *handle,
+ [in,unique] lsa_String *name,
+ [out] lsa_SidArray *sids
+ );
+
+ /* Function: 0x24 */
+ typedef struct {
+ [string,charset(UTF16)] uint16 *name;
+ } lsa_RightAttribute;
+
+ typedef struct {
+ [range(0,256)] uint32 count;
+ [size_is(count)] lsa_StringLarge *names;
+ } lsa_RightSet;
+
+ NTSTATUS lsa_EnumAccountRights (
+ [in] policy_handle *handle,
+ [in,ref] dom_sid2 *sid,
+ [out,ref] lsa_RightSet *rights
+ );
+
+
+ /**********************/
+ /* Function: 0x25 */
+ NTSTATUS lsa_AddAccountRights (
+ [in] policy_handle *handle,
+ [in,ref] dom_sid2 *sid,
+ [in,ref] lsa_RightSet *rights
+ );
+
+ /**********************/
+ /* Function: 0x26 */
+ NTSTATUS lsa_RemoveAccountRights (
+ [in] policy_handle *handle,
+ [in,ref] dom_sid2 *sid,
+ [in] uint8 remove_all,
+ [in,ref] lsa_RightSet *rights
+ );
+
+ /* Function: 0x27 */
+ NTSTATUS lsa_QueryTrustedDomainInfoBySid(
+ [in] policy_handle *handle,
+ [in,ref] dom_sid2 *dom_sid,
+ [in] lsa_TrustDomInfoEnum level,
+ [out,switch_is(level),ref] lsa_TrustedDomainInfo **info
+ );
+
+ /* Function: 0x28 */
+ NTSTATUS lsa_SetTrustedDomainInfo();
+ /* Function: 0x29 */
+ NTSTATUS lsa_DeleteTrustedDomain(
+ [in] policy_handle *handle,
+ [in] dom_sid2 *dom_sid
+ );
+
+ /* Function: 0x2a */
+ NTSTATUS lsa_StorePrivateData();
+ /* Function: 0x2b */
+ NTSTATUS lsa_RetrievePrivateData();
+
+
+ /**********************/
+ /* Function: 0x2c */
+ [public] NTSTATUS lsa_OpenPolicy2 (
+ [in,unique] [string,charset(UTF16)] uint16 *system_name,
+ [in] lsa_ObjectAttribute *attr,
+ [in] lsa_PolicyAccessMask access_mask,
+ [out] policy_handle *handle
+ );
+
+ /**********************/
+ /* Function: 0x2d */
+ NTSTATUS lsa_GetUserName(
+ [in,unique] [string,charset(UTF16)] uint16 *system_name,
+ [in,out,ref] lsa_String **account_name,
+ [in,out,unique] lsa_String **authority_name
+ );
+
+ /**********************/
+ /* Function: 0x2e */
+
+ NTSTATUS lsa_QueryInfoPolicy2(
+ [in] policy_handle *handle,
+ [in] lsa_PolicyInfo level,
+ [out,ref,switch_is(level)] lsa_PolicyInformation **info
+ );
+
+ /* Function 0x2f */
+ NTSTATUS lsa_SetInfoPolicy2(
+ [in] policy_handle *handle,
+ [in] lsa_PolicyInfo level,
+ [in,switch_is(level)] lsa_PolicyInformation *info
+ );
+
+ /**********************/
+ /* Function 0x30 */
+ NTSTATUS lsa_QueryTrustedDomainInfoByName(
+ [in] policy_handle *handle,
+ [in,ref] lsa_String *trusted_domain,
+ [in] lsa_TrustDomInfoEnum level,
+ [out,ref,switch_is(level)] lsa_TrustedDomainInfo **info
+ );
+
+ /**********************/
+ /* Function 0x31 */
+ NTSTATUS lsa_SetTrustedDomainInfoByName(
+ [in] policy_handle *handle,
+ [in] lsa_String trusted_domain,
+ [in] lsa_TrustDomInfoEnum level,
+ [in,unique,switch_is(level)] lsa_TrustedDomainInfo *info
+ );
+
+ /* Function 0x32 */
+
+ /* w2k3 treats max_size as max_domains*82 */
+ const int LSA_ENUM_TRUST_DOMAIN_EX_MULTIPLIER = 82;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] lsa_TrustDomainInfoInfoEx *domains;
+ } lsa_DomainListEx;
+
+ NTSTATUS lsa_EnumTrustedDomainsEx (
+ [in] policy_handle *handle,
+ [in,out] uint32 *resume_handle,
+ [out] lsa_DomainListEx *domains,
+ [in] uint32 max_size
+ );
+
+
+ /* Function 0x33 */
+ NTSTATUS lsa_CreateTrustedDomainEx();
+
+ /* Function 0x34 */
+ NTSTATUS lsa_CloseTrustedDomainEx(
+ [in,out] policy_handle *handle
+ );
+
+ /* Function 0x35 */
+
+ /* w2k3 returns either 0x000bbbd000000000 or 0x000a48e800000000
+ for unknown6 - gd */
+ typedef struct {
+ uint32 enforce_restrictions;
+ hyper service_tkt_lifetime;
+ hyper user_tkt_lifetime;
+ hyper user_tkt_renewaltime;
+ hyper clock_skew;
+ hyper unknown6;
+ } lsa_DomainInfoKerberos;
+
+ typedef struct {
+ uint32 blob_size;
+ [size_is(blob_size)] uint8 *efs_blob;
+ } lsa_DomainInfoEfs;
+
+ typedef enum {
+ LSA_DOMAIN_INFO_POLICY_EFS=2,
+ LSA_DOMAIN_INFO_POLICY_KERBEROS=3
+ } lsa_DomainInfoEnum;
+
+ typedef [switch_type(uint16)] union {
+ [case(LSA_DOMAIN_INFO_POLICY_EFS)] lsa_DomainInfoEfs efs_info;
+ [case(LSA_DOMAIN_INFO_POLICY_KERBEROS)] lsa_DomainInfoKerberos kerberos_info;
+ } lsa_DomainInformationPolicy;
+
+ NTSTATUS lsa_QueryDomainInformationPolicy(
+ [in] policy_handle *handle,
+ [in] uint16 level,
+ [out,ref,switch_is(level)] lsa_DomainInformationPolicy **info
+ );
+
+ /* Function 0x36 */
+ NTSTATUS lsa_SetDomainInformationPolicy(
+ [in] policy_handle *handle,
+ [in] uint16 level,
+ [in,unique,switch_is(level)] lsa_DomainInformationPolicy *info
+ );
+
+ /**********************/
+ /* Function 0x37 */
+ NTSTATUS lsa_OpenTrustedDomainByName(
+ [in] policy_handle *handle,
+ [in] lsa_String name,
+ [in] uint32 access_mask,
+ [out] policy_handle *trustdom_handle
+ );
+
+ /* Function 0x38 */
+ NTSTATUS lsa_TestCall();
+
+ /**********************/
+ /* Function 0x39 */
+
+ typedef struct {
+ lsa_SidType sid_type;
+ lsa_String name;
+ uint32 sid_index;
+ uint32 unknown;
+ } lsa_TranslatedName2;
+
+ typedef struct {
+ [range(0,1000)] uint32 count;
+ [size_is(count)] lsa_TranslatedName2 *names;
+ } lsa_TransNameArray2;
+
+ [public] NTSTATUS lsa_LookupSids2(
+ [in] policy_handle *handle,
+ [in,ref] lsa_SidArray *sids,
+ [out,ref] lsa_RefDomainList **domains,
+ [in,out,ref] lsa_TransNameArray2 *names,
+ [in] uint16 level,
+ [in,out,ref] uint32 *count,
+ [in] uint32 unknown1,
+ [in] uint32 unknown2
+ );
+
+ /**********************/
+ /* Function 0x3a */
+
+ typedef struct {
+ lsa_SidType sid_type;
+ uint32 rid;
+ uint32 sid_index;
+ uint32 unknown;
+ } lsa_TranslatedSid2;
+
+ typedef struct {
+ [range(0,1000)] uint32 count;
+ [size_is(count)] lsa_TranslatedSid2 *sids;
+ } lsa_TransSidArray2;
+
+ [public] NTSTATUS lsa_LookupNames2 (
+ [in] policy_handle *handle,
+ [in,range(0,1000)] uint32 num_names,
+ [in,size_is(num_names)] lsa_String names[],
+ [out,ref] lsa_RefDomainList **domains,
+ [in,out,ref] lsa_TransSidArray2 *sids,
+ [in] lsa_LookupNamesLevel level,
+ [in,out,ref] uint32 *count,
+ [in] uint32 unknown1,
+ [in] uint32 unknown2
+ );
+
+ /* Function 0x3b */
+ NTSTATUS lsa_CreateTrustedDomainEx2();
+
+ /* Function 0x3c */
+ NTSTATUS lsa_CREDRWRITE();
+
+ /* Function 0x3d */
+ NTSTATUS lsa_CREDRREAD();
+
+ /* Function 0x3e */
+ NTSTATUS lsa_CREDRENUMERATE();
+
+ /* Function 0x3f */
+ NTSTATUS lsa_CREDRWRITEDOMAINCREDENTIALS();
+
+ /* Function 0x40 */
+ NTSTATUS lsa_CREDRREADDOMAINCREDENTIALS();
+
+ /* Function 0x41 */
+ NTSTATUS lsa_CREDRDELETE();
+
+ /* Function 0x42 */
+ NTSTATUS lsa_CREDRGETTARGETINFO();
+
+ /* Function 0x43 */
+ NTSTATUS lsa_CREDRPROFILELOADED();
+
+ /**********************/
+ /* Function 0x44 */
+ typedef struct {
+ lsa_SidType sid_type;
+ dom_sid2 *sid;
+ uint32 sid_index;
+ uint32 unknown;
+ } lsa_TranslatedSid3;
+
+ typedef struct {
+ [range(0,1000)] uint32 count;
+ [size_is(count)] lsa_TranslatedSid3 *sids;
+ } lsa_TransSidArray3;
+
+ [public] NTSTATUS lsa_LookupNames3 (
+ [in] policy_handle *handle,
+ [in,range(0,1000)] uint32 num_names,
+ [in,size_is(num_names)] lsa_String names[],
+ [out,ref] lsa_RefDomainList **domains,
+ [in,out,ref] lsa_TransSidArray3 *sids,
+ [in] lsa_LookupNamesLevel level,
+ [in,out,ref] uint32 *count,
+ [in] uint32 unknown1,
+ [in] uint32 unknown2
+ );
+
+ /* Function 0x45 */
+ NTSTATUS lsa_CREDRGETSESSIONTYPES();
+
+ /* Function 0x46 */
+ NTSTATUS lsa_LSARREGISTERAUDITEVENT();
+
+ /* Function 0x47 */
+ NTSTATUS lsa_LSARGENAUDITEVENT();
+
+ /* Function 0x48 */
+ NTSTATUS lsa_LSARUNREGISTERAUDITEVENT();
+
+ /* Function 0x49 */
+ typedef struct {
+ [range(0,131072)] uint32 length;
+ [size_is(length)] uint8 *data;
+ } lsa_ForestTrustBinaryData;
+
+ typedef struct {
+ dom_sid2 *domain_sid;
+ lsa_StringLarge dns_domain_name;
+ lsa_StringLarge netbios_domain_name;
+ } lsa_ForestTrustDomainInfo;
+
+ typedef [switch_type(uint32)] union {
+ [case(LSA_FOREST_TRUST_TOP_LEVEL_NAME)] lsa_String top_level_name;
+ [case(LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX)] lsa_StringLarge top_level_name_ex;
+ [case(LSA_FOREST_TRUST_DOMAIN_INFO)] lsa_ForestTrustDomainInfo domain_info;
+ [default] lsa_ForestTrustBinaryData data;
+ } lsa_ForestTrustData;
+
+ typedef [v1_enum] enum {
+ LSA_FOREST_TRUST_TOP_LEVEL_NAME = 0,
+ LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX = 1,
+ LSA_FOREST_TRUST_DOMAIN_INFO = 2,
+ LSA_FOREST_TRUST_RECORD_TYPE_LAST = 3
+ } lsa_ForestTrustRecordType;
+
+ typedef struct {
+ uint32 flags;
+ lsa_ForestTrustRecordType level;
+ hyper unknown;
+ [switch_is(level)] lsa_ForestTrustData forest_trust_data;
+ } lsa_ForestTrustRecord;
+
+ typedef [public] struct {
+ [range(0,4000)] uint32 count;
+ [size_is(count)] lsa_ForestTrustRecord **entries;
+ } lsa_ForestTrustInformation;
+
+ NTSTATUS lsa_lsaRQueryForestTrustInformation(
+ [in] policy_handle *handle,
+ [in,ref] lsa_String *trusted_domain_name,
+ [in] uint16 unknown, /* level ? */
+ [out,ref] lsa_ForestTrustInformation **forest_trust_info
+ );
+
+ /* Function 0x4a */
+ NTSTATUS lsa_LSARSETFORESTTRUSTINFORMATION();
+
+ /* Function 0x4b */
+ NTSTATUS lsa_CREDRRENAME();
+
+ /*****************/
+ /* Function 0x4c */
+
+ [public] NTSTATUS lsa_LookupSids3(
+ [in,ref] lsa_SidArray *sids,
+ [out,ref] lsa_RefDomainList **domains,
+ [in,out,ref] lsa_TransNameArray2 *names,
+ [in] uint16 level,
+ [in,out,ref] uint32 *count,
+ [in] uint32 unknown1,
+ [in] uint32 unknown2
+ );
+
+ /* Function 0x4d */
+ NTSTATUS lsa_LookupNames4(
+ [in,range(0,1000)] uint32 num_names,
+ [in,size_is(num_names)] lsa_String names[],
+ [out,ref] lsa_RefDomainList **domains,
+ [in,out,ref] lsa_TransSidArray3 *sids,
+ [in] lsa_LookupNamesLevel level,
+ [in,out,ref] uint32 *count,
+ [in] uint32 unknown1,
+ [in] uint32 unknown2
+ );
+
+ /* Function 0x4e */
+ NTSTATUS lsa_LSAROPENPOLICYSCE();
+
+ /* Function 0x4f */
+ NTSTATUS lsa_LSARADTREGISTERSECURITYEVENTSOURCE();
+
+ /* Function 0x50 */
+ NTSTATUS lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE();
+
+ /* Function 0x51 */
+ NTSTATUS lsa_LSARADTREPORTSECURITYEVENT();
+
+}
diff --git a/source3/librpc/idl/messaging.idl b/source3/librpc/idl/messaging.idl
new file mode 100644
index 0000000000..068658587f
--- /dev/null
+++ b/source3/librpc/idl/messaging.idl
@@ -0,0 +1,123 @@
+#include "idl_types.h"
+
+/*
+ IDL structures for messaging code
+*/
+
+[
+ pointer_default(unique)
+]
+interface messaging
+{
+ const int MSG_TYPE_MASK = 0xFFFF;
+
+ typedef [v1_enum,public] enum {
+
+ /* general messages */
+ MSG_DEBUG = 0x0001,
+ MSG_PING = 0x0002,
+ MSG_PONG = 0x0003,
+ MSG_PROFILE = 0x0004,
+ MSG_REQ_DEBUGLEVEL = 0x0005,
+ MSG_DEBUGLEVEL = 0x0006,
+ MSG_REQ_PROFILELEVEL = 0x0007,
+ MSG_PROFILELEVEL = 0x0008,
+ MSG_REQ_POOL_USAGE = 0x0009,
+ MSG_POOL_USAGE = 0x000A,
+
+ /* If dmalloc is included, set a steady-state mark */
+ MSG_REQ_DMALLOC_MARK = 0x000B,
+
+ /* If dmalloc is included, dump to the dmalloc log a description of
+ * what has changed since the last MARK */
+ MSG_REQ_DMALLOC_LOG_CHANGED = 0x000C,
+ MSG_SHUTDOWN = 0x000D,
+
+ /* nmbd messages */
+ MSG_FORCE_ELECTION = 0x0101,
+ MSG_WINS_NEW_ENTRY = 0x0102,
+ MSG_SEND_PACKET = 0x0103,
+
+ /* printing messages */
+ MSG_PRINTER_NOTIFY = 0x2001, /* Obsolete */
+ MSG_PRINTER_NOTIFY2 = 0x0202,
+ MSG_PRINTER_DRVUPGRADE = 0x0203,
+ MSG_PRINTERDATA_INIT_RESET = 0x0204,
+ MSG_PRINTER_UPDATE = 0x0205,
+ MSG_PRINTER_MOD = 0x0206,
+
+ /* smbd messages */
+ MSG_SMB_CONF_UPDATED = 0x0301,
+ MSG_SMB_FORCE_TDIS = 0x0302,
+ MSG_SMB_SAM_SYNC = 0x0303,
+ MSG_SMB_SAM_REPL = 0x0304,
+ MSG_SMB_UNLOCK = 0x0305,
+ MSG_SMB_BREAK_REQUEST = 0x0306,
+ MSG_SMB_BREAK_RESPONSE = 0x0307,
+ MSG_SMB_ASYNC_LEVEL2_BREAK = 0x0308,
+ MSG_SMB_OPEN_RETRY = 0x0309,
+ MSG_SMB_KERNEL_BREAK = 0x030A,
+ MSG_SMB_FILE_RENAME = 0x030B,
+ MSG_SMB_INJECT_FAULT = 0x030C,
+ MSG_SMB_BLOCKING_LOCK_CANCEL = 0x030D,
+ MSG_SMB_NOTIFY = 0x030E,
+ MSG_SMB_STAT_CACHE_DELETE = 0x030F,
+
+ /* Samba4 compatibility */
+ MSG_PVFS_NOTIFY = 0x0310,
+
+ /* cluster reconfigure events */
+ MSG_SMB_BRL_VALIDATE = 0x0311,
+ MSG_SMB_RELEASE_IP = 0x0312,
+
+ /*Close a specific file given a share entry. */
+ MSG_SMB_CLOSE_FILE = 0x0313,
+
+ /* winbind messages */
+ MSG_WINBIND_FINISHED = 0x0401,
+ MSG_WINBIND_FORGET_STATE = 0x0402,
+ MSG_WINBIND_ONLINE = 0x0403,
+ MSG_WINBIND_OFFLINE = 0x0404,
+ MSG_WINBIND_ONLINESTATUS = 0x0405,
+ MSG_WINBIND_TRY_TO_GO_ONLINE = 0x0406,
+ MSG_WINBIND_FAILED_TO_GO_ONLINE = 0x0407,
+ MSG_WINBIND_VALIDATE_CACHE = 0x0408,
+ MSG_WINBIND_DUMP_DOMAIN_LIST = 0x0409,
+
+ /* event messages */
+ MSG_DUMP_EVENT_LIST = 0x0500,
+
+ /* dbwrap messages 4001-4999 */
+ MSG_DBWRAP_TDB2_CHANGES = 4001
+ } messaging_type;
+
+ /* messaging struct sent across the sockets and stored in the tdb */
+
+ typedef [public] struct {
+ uint32 msg_version;
+ messaging_type msg_type;
+ server_id dest;
+ server_id src;
+ DATA_BLOB buf;
+ } messaging_rec;
+
+ typedef [public] struct {
+ uint32 num_messages;
+ messaging_rec messages[num_messages];
+ } messaging_array;
+
+ /*
+ * struct used for change notify messages
+ * in the dbwrap_tdb2 code
+ */
+ typedef [public] struct {
+ [charset(DOS),value("TDB2")] uint8 magic_string[4];
+ [value(1)] uint32 magic_version;
+ [charset(UTF8),string] uint8 name[];
+ uint32 old_seqnum;
+ uint32 new_seqnum;
+ uint32 num_changes;
+ uint32 num_keys;
+ DATA_BLOB keys[num_keys];
+ } dbwrap_tdb2_changes;
+}
diff --git a/source3/librpc/idl/misc.idl b/source3/librpc/idl/misc.idl
new file mode 100644
index 0000000000..132a81f138
--- /dev/null
+++ b/source3/librpc/idl/misc.idl
@@ -0,0 +1,51 @@
+/*
+ miscellaneous IDL structures
+*/
+
+
+[
+ pointer_default(unique)
+]
+interface misc
+{
+ typedef [public,noprint,gensize,noejs] struct {
+ uint32 time_low;
+ uint16 time_mid;
+ uint16 time_hi_and_version;
+ uint8 clock_seq[2];
+ uint8 node[6];
+ } GUID;
+
+ typedef [public] struct {
+ GUID uuid;
+ uint32 if_version;
+ } ndr_syntax_id;
+
+ typedef [public] struct {
+ uint32 handle_type;
+ GUID uuid;
+ } policy_handle;
+
+ /* secure channel types */
+ /* Only SEC_CHAN_WKSTA can forward requests to other domains. */
+
+ typedef [public] enum {
+ SEC_CHAN_WKSTA = 2,
+ SEC_CHAN_DOMAIN = 4,
+ SEC_CHAN_BDC = 6
+ } netr_SchannelType;
+
+ /* SAM database types */
+ typedef [public,v1_enum] enum {
+ SAM_DATABASE_DOMAIN = 0, /* Domain users and groups */
+ SAM_DATABASE_BUILTIN = 1, /* BUILTIN users and groups */
+ SAM_DATABASE_PRIVS = 2 /* Privileges */
+ } netr_SamDatabaseID;
+
+ typedef [public,v1_enum] enum {
+ SAMR_REJECT_OTHER = 0,
+ SAMR_REJECT_TOO_SHORT = 1,
+ SAMR_REJECT_IN_HISTORY = 2,
+ SAMR_REJECT_COMPLEXITY = 5
+ } samr_RejectReason;
+}
diff --git a/source3/librpc/idl/nbt.idl b/source3/librpc/idl/nbt.idl
new file mode 100644
index 0000000000..9f5c4a9a5f
--- /dev/null
+++ b/source3/librpc/idl/nbt.idl
@@ -0,0 +1,781 @@
+#include "idl_types.h"
+
+/*
+ IDL structures for NBT operations
+
+ NBT is not traditionally encoded using IDL/NDR. This is a bit of an
+ experiment, and I may well switch us back to a more traditional
+ encoding if it doesn't work out
+*/
+
+import "misc.idl", "security.idl", "svcctl.idl", "samr.idl";
+[
+helper("libcli/nbt/libnbt.h")
+]
+interface nbt
+{
+ const int NBT_NAME_SERVICE_PORT = 137;
+ const int NBT_DGRAM_SERVICE_PORT = 138;
+
+ typedef [bitmap16bit] bitmap {
+ NBT_RCODE = 0x000F,
+ NBT_FLAG_BROADCAST = 0x0010,
+ NBT_FLAG_RECURSION_AVAIL = 0x0080,
+ NBT_FLAG_RECURSION_DESIRED = 0x0100,
+ NBT_FLAG_TRUNCATION = 0x0200,
+ NBT_FLAG_AUTHORITIVE = 0x0400,
+ NBT_OPCODE = 0x7800,
+ NBT_FLAG_REPLY = 0x8000
+ } nbt_operation;
+
+ /* the opcodes are in the operation field, masked with
+ NBT_OPCODE */
+ typedef enum {
+ NBT_OPCODE_QUERY = (0x0<<11),
+ NBT_OPCODE_REGISTER = (0x5<<11),
+ NBT_OPCODE_RELEASE = (0x6<<11),
+ NBT_OPCODE_WACK = (0x7<<11),
+ NBT_OPCODE_REFRESH = (0x8<<11),
+ NBT_OPCODE_REFRESH2 = (0x9<<11),
+ NBT_OPCODE_MULTI_HOME_REG = (0xf<<11)
+ } nbt_opcode;
+
+ /* rcode values */
+ typedef enum {
+ NBT_RCODE_OK = 0x0,
+ NBT_RCODE_FMT = 0x1,
+ NBT_RCODE_SVR = 0x2,
+ NBT_RCODE_NAM = 0x3,
+ NBT_RCODE_IMP = 0x4,
+ NBT_RCODE_RFS = 0x5,
+ NBT_RCODE_ACT = 0x6,
+ NBT_RCODE_CFT = 0x7
+ } nbt_rcode;
+
+ /* we support any 8bit name type, but by defining the common
+ ones here we get better debug displays */
+ typedef [enum8bit] enum {
+ NBT_NAME_CLIENT = 0x00,
+ NBT_NAME_MS = 0x01,
+ NBT_NAME_USER = 0x03,
+ NBT_NAME_SERVER = 0x20,
+ NBT_NAME_PDC = 0x1B,
+ NBT_NAME_LOGON = 0x1C,
+ NBT_NAME_MASTER = 0x1D,
+ NBT_NAME_BROWSER = 0x1E
+ } nbt_name_type;
+
+ /* the ndr parser for nbt_name is separately defined in
+ nbtname.c (along with the parsers for nbt_string) */
+ typedef [public,nopull,nopush] struct {
+ string name;
+ string scope;
+ nbt_name_type type;
+ } nbt_name;
+
+ typedef [enum16bit] enum {
+ NBT_QCLASS_IP = 0x01
+ } nbt_qclass;
+
+ typedef [enum16bit] enum {
+ NBT_QTYPE_ADDRESS = 0x0001,
+ NBT_QTYPE_NAMESERVICE = 0x0002,
+ NBT_QTYPE_NULL = 0x000A,
+ NBT_QTYPE_NETBIOS = 0x0020,
+ NBT_QTYPE_STATUS = 0x0021
+ } nbt_qtype;
+
+ typedef struct {
+ nbt_name name;
+ nbt_qtype question_type;
+ nbt_qclass question_class;
+ } nbt_name_question;
+
+ /* these are the possible values of the NBT_NM_OWNER_TYPE
+ field */
+ typedef enum {
+ NBT_NODE_B = 0x0000,
+ NBT_NODE_P = 0x2000,
+ NBT_NODE_M = 0x4000,
+ NBT_NODE_H = 0x6000
+ } nbt_node_type;
+
+ typedef [bitmap16bit] bitmap {
+ NBT_NM_PERMANENT = 0x0200,
+ NBT_NM_ACTIVE = 0x0400,
+ NBT_NM_CONFLICT = 0x0800,
+ NBT_NM_DEREGISTER = 0x1000,
+ NBT_NM_OWNER_TYPE = 0x6000,
+ NBT_NM_GROUP = 0x8000
+ } nb_flags;
+
+ typedef struct {
+ nb_flags nb_flags;
+ ipv4address ipaddr;
+ } nbt_rdata_address;
+
+ typedef struct {
+ uint16 length;
+ nbt_rdata_address addresses[length/6];
+ } nbt_rdata_netbios;
+
+ typedef struct {
+ uint8 unit_id[6];
+ uint8 jumpers;
+ uint8 test_result;
+ uint16 version_number;
+ uint16 period_of_statistics;
+ uint16 number_of_crcs;
+ uint16 number_alignment_errors;
+ uint16 number_of_collisions;
+ uint16 number_send_aborts;
+ uint32 number_good_sends;
+ uint32 number_good_receives;
+ uint16 number_retransmits;
+ uint16 number_no_resource_conditions;
+ uint16 number_free_command_blocks;
+ uint16 total_number_command_blocks;
+ uint16 max_total_number_command_blocks;
+ uint16 number_pending_sessions;
+ uint16 max_number_pending_sessions;
+ uint16 max_total_sessions_possible;
+ uint16 session_data_packet_size;
+ } nbt_statistics;
+
+ typedef struct {
+ [charset(DOS)] uint8 name[15];
+ nbt_name_type type;
+ nb_flags nb_flags;
+ } nbt_status_name;
+
+ typedef struct {
+ [value(num_names * 18 + 47)] uint16 length;
+ uint8 num_names;
+ nbt_status_name names[num_names];
+ nbt_statistics statistics;
+ } nbt_rdata_status;
+
+ typedef struct {
+ uint16 length;
+ uint8 data[length];
+ } nbt_rdata_data;
+
+ typedef [nodiscriminant] union {
+ [case(NBT_QTYPE_NETBIOS)] nbt_rdata_netbios netbios;
+ [case(NBT_QTYPE_STATUS)] nbt_rdata_status status;
+ [default] nbt_rdata_data data;
+ } nbt_rdata;
+
+/*
+ * this macro works arround the problem
+ * that we need to use nbt_rdata_data
+ * together with NBT_QTYPE_NETBIOS
+ * for WACK replies
+ */
+#define NBT_RES_REC_LEVEL(rr_type, rdata) (\
+ (((rr_type) == NBT_QTYPE_NETBIOS) && \
+ talloc_check_name(ndr, "struct ndr_push") && \
+ ((rdata).data.length == 2)) \
+ ? 0 : rr_type)
+
+ typedef [flag(LIBNDR_PRINT_ARRAY_HEX)] struct {
+ nbt_name name;
+ nbt_qtype rr_type;
+ nbt_qclass rr_class;
+ uint32 ttl;
+ [switch_is(NBT_RES_REC_LEVEL(rr_type, rdata))] nbt_rdata rdata;
+ } nbt_res_rec;
+
+ typedef [flag(NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
+ uint16 name_trn_id;
+ nbt_operation operation;
+ uint16 qdcount;
+ uint16 ancount;
+ uint16 nscount;
+ uint16 arcount;
+ nbt_name_question questions[qdcount];
+ nbt_res_rec answers[ancount];
+ nbt_res_rec nsrecs[nscount];
+ nbt_res_rec additional[arcount];
+ [flag(NDR_REMAINING)] DATA_BLOB padding;
+ } nbt_name_packet;
+
+
+ /*
+ NBT DGRAM packets (UDP/138)
+ */
+
+ typedef [enum8bit] enum {
+ DGRAM_DIRECT_UNIQUE = 0x10,
+ DGRAM_DIRECT_GROUP = 0x11,
+ DGRAM_BCAST = 0x12,
+ DGRAM_ERROR = 0x13,
+ DGRAM_QUERY = 0x14,
+ DGRAM_QUERY_POSITIVE = 0x15,
+ DGRAM_QUERY_NEGATIVE = 0x16
+ } dgram_msg_type;
+
+ typedef [bitmap8bit] bitmap {
+ DGRAM_FLAG_MORE = 0x01,
+ DGRAM_FLAG_FIRST = 0x02,
+ DGRAM_FLAG_NODE_TYPE = 0x0C
+ } dgram_flags;
+
+ typedef [enum8bit] enum {
+ DGRAM_NODE_B = 0x00,
+ DGRAM_NODE_P = 0x04,
+ DGRAM_NODE_M = 0x08,
+ DGRAM_NODE_NBDD = 0x0C
+ } dgram_node_type;
+
+ /* a dgram_message is the main dgram body in general use */
+
+ /* the most common datagram type is a SMB_TRANSACTION
+ operation, where a SMB packet is used in the data section
+ of a dgram_message to hold a trans request, which in turn
+ holds a small command structure. It's a very strange beast
+ indeed. To make the code cleaner we define a basic SMB
+ packet in IDL here. This is not a general purpose SMB
+ packet, and won't be used in the core SMB client/server
+ code, but it does make working with these types of dgrams
+ easier */
+
+ const string NBT_MAILSLOT_NETLOGON = "\\MAILSLOT\\NET\\NETLOGON";
+ const string NBT_MAILSLOT_NTLOGON = "\\MAILSLOT\\NET\\NTLOGON";
+ const string NBT_MAILSLOT_GETDC = "\\MAILSLOT\\NET\\GETDC";
+ const string NBT_MAILSLOT_BROWSE = "\\MAILSLOT\\BROWSE";
+
+ typedef [enum8bit] enum {
+ SMB_TRANSACTION = 0x25
+ } smb_command;
+
+ typedef struct {
+ [range(17,17),value(17)] uint8 wct;
+ uint16 total_param_count;
+ uint16 total_data_count;
+ uint16 max_param_count;
+ uint16 max_data_count;
+ uint8 max_setup_count;
+ uint8 pad;
+ uint16 trans_flags;
+ uint32 timeout;
+ uint16 reserved;
+ uint16 param_count;
+ uint16 param_offset;
+ uint16 data_count;
+ uint16 data_offset;
+ [range(3,3),value(3)] uint8 setup_count;
+ uint8 pad2;
+ uint16 opcode;
+ uint16 priority;
+ uint16 _class;
+ [value(strlen(mailslot_name)+1+data.length)]
+ uint16 byte_count;
+ astring mailslot_name;
+ [flag(NDR_REMAINING)] DATA_BLOB data;
+ } smb_trans_body;
+
+ typedef [nodiscriminant] union {
+ [case(SMB_TRANSACTION)] smb_trans_body trans;
+ } smb_body;
+
+
+ typedef [flag(NDR_NOALIGN|NDR_LITTLE_ENDIAN|NDR_PAHEX),public] struct {
+ smb_command smb_command;
+ uint8 err_class;
+ uint8 pad;
+ uint16 err_code;
+ uint8 flags;
+ uint16 flags2;
+ uint16 pid_high;
+ uint8 signature[8];
+ uint16 reserved;
+ uint16 tid;
+ uint16 pid;
+ uint16 vuid;
+ uint16 mid;
+ [switch_is(smb_command)] smb_body body;
+ } dgram_smb_packet;
+
+ const uint32 DGRAM_SMB = 0xff534d42; /* 0xffSMB */
+
+ typedef [nodiscriminant] union {
+ [case(DGRAM_SMB)] dgram_smb_packet smb;
+ } dgram_message_body;
+
+ typedef struct {
+ uint16 length;
+ uint16 offset;
+ nbt_name source_name;
+ nbt_name dest_name;
+ uint32 dgram_body_type;
+ [switch_is(dgram_body_type)] dgram_message_body body;
+ } dgram_message;
+
+ typedef [enum8bit] enum {
+ DGRAM_ERROR_NAME_NOT_PRESENT = 0x82,
+ DGRAM_ERROR_INVALID_SOURCE = 0x83,
+ DGRAM_ERROR_INVALID_DEST = 0x84
+ } dgram_err_code;
+
+ typedef [nodiscriminant] union {
+ [case(DGRAM_DIRECT_UNIQUE)] dgram_message msg;
+ [case(DGRAM_DIRECT_GROUP)] dgram_message msg;
+ [case(DGRAM_BCAST)] dgram_message msg;
+ [case(DGRAM_ERROR)] dgram_err_code error;
+ [case(DGRAM_QUERY)] nbt_name dest_name;
+ [case(DGRAM_QUERY_POSITIVE)] nbt_name dest_name;
+ [case(DGRAM_QUERY_NEGATIVE)] nbt_name dest_name;
+ } dgram_data;
+
+ typedef [flag(NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
+ dgram_msg_type msg_type;
+ dgram_flags flags;
+ uint16 dgram_id;
+ ipv4address src_addr;
+ uint16 src_port;
+ [switch_is(msg_type)] dgram_data data;
+ } nbt_dgram_packet;
+
+
+ /*******************************************/
+ /* \MAILSLOT\NET\NETLOGON mailslot requests */
+ typedef enum {
+ NETLOGON_QUERY_FOR_PDC = 0x7,
+ NETLOGON_ANNOUNCE_UAS = 0xa,
+ NETLOGON_RESPONSE_FROM_PDC = 0xc,
+ NETLOGON_QUERY_FOR_PDC2 = 0x12,
+ NETLOGON_RESPONSE_FROM_PDC2 = 0x17,
+ NETLOGON_RESPONSE_FROM_PDC_USER = 0x19
+ } nbt_netlogon_command;
+
+ typedef [flag(NDR_LITTLE_ENDIAN),bitmap32bit] bitmap {
+ NETLOGON_VERSION_1 = 0x00000001,
+ NETLOGON_VERSION_5 = 0x00000002,
+ NETLOGON_VERSION_5EX = 0x00000004,
+ NETLOGON_VERSION_5EX_WITH_IP = 0x00000008,
+ NETLOGON_VERSION_WITH_CLOSEST_SITE = 0x00000010,
+ NETLOGON_VERSION_AVOID_NT4_EMUL = 0x01000000,
+ NETLOGON_VERSION_PDC = 0x10000000,
+ NETLOGON_VERSION_IP = 0x20000000,
+ NETLOGON_VERSION_LOCAL = 0x40000000,
+ NETLOGON_VERSION_GC = 0x80000000
+ } nbt_netlogon_version;
+
+ /* query for pdc request */
+ typedef struct {
+ astring computer_name;
+ astring mailslot_name;
+ [flag(NDR_ALIGN2)] DATA_BLOB _pad;
+ nstring unicode_name;
+ nbt_netlogon_version nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } nbt_netlogon_query_for_pdc;
+
+ /* query for pdc request - new style */
+ typedef struct {
+ uint16 request_count;
+ nstring computer_name;
+ nstring user_name;
+ astring mailslot_name;
+ uint32 unknown[2];
+ nbt_netlogon_version nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } nbt_netlogon_query_for_pdc2;
+
+ /* response from pdc */
+ typedef struct {
+ astring pdc_name;
+ [flag(NDR_ALIGN2)] DATA_BLOB _pad;
+ nstring unicode_pdc_name;
+ nstring domain_name;
+ nbt_netlogon_version nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } nbt_netlogon_response_from_pdc;
+
+ typedef [bitmap32bit] bitmap {
+ NBT_SERVER_PDC = 0x00000001,
+ NBT_SERVER_GC = 0x00000004,
+ NBT_SERVER_LDAP = 0x00000008,
+ NBT_SERVER_DS = 0x00000010,
+ NBT_SERVER_KDC = 0x00000020,
+ NBT_SERVER_TIMESERV = 0x00000040,
+ NBT_SERVER_CLOSEST = 0x00000080,
+ NBT_SERVER_WRITABLE = 0x00000100,
+ NBT_SERVER_GOOD_TIMESERV = 0x00000200,
+ NBT_SERVER_NDNC = 0x00000400,
+ NBT_SERVER_SELECT_SECRET_DOMAIN_6 = 0x00000800,
+ NBT_SERVER_FULL_SECRET_DOMAIN_6 = 0x00001000
+ } nbt_server_type;
+
+ typedef struct {
+ uint32 family;
+ [flag(NDR_BIG_ENDIAN)] ipv4address pdc_ip;
+ [flag(NDR_REMAINING)] DATA_BLOB remaining;
+ } nbt_dc_sock_addr;
+
+ /* response from pdc - type2 */
+ typedef struct {
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad;
+ nbt_server_type server_type;
+ GUID domain_uuid;
+ nbt_string forest;
+ nbt_string dns_domain;
+ nbt_string pdc_dns_name;
+ nbt_string domain;
+ nbt_string pdc_name;
+ nbt_string user_name;
+ nbt_string server_site;
+ nbt_string client_site;
+ uint8 dc_sock_addr_size;
+ [subcontext(0),subcontext_size(dc_sock_addr_size)] nbt_dc_sock_addr dc_sock_addr;
+ nbt_netlogon_version nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } nbt_netlogon_response_from_pdc2;
+
+ typedef enum netr_SamDatabaseID netr_SamDatabaseID;
+
+ /* announce change to UAS or SAM */
+ typedef struct {
+ netr_SamDatabaseID db_index;
+ hyper serial;
+ NTTIME timestamp;
+ } nbt_db_change;
+
+ /* used to announce SAM changes */
+ typedef struct {
+ uint32 serial_lo;
+ time_t timestamp;
+ uint32 pulse;
+ uint32 random;
+ astring pdc_name;
+ astring domain;
+ [flag(NDR_ALIGN2)] DATA_BLOB _pad;
+ nstring unicode_pdc_name;
+ nstring unicode_domain;
+ uint32 db_count;
+ nbt_db_change dbchange[db_count];
+ [value(ndr_size_dom_sid0(&sid, ndr->flags))] uint32 sid_size;
+ [subcontext(0),subcontext_size(sid_size)] dom_sid0 sid;
+ nbt_netlogon_version nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } nbt_netlogon_announce_uas;
+
+ typedef [nodiscriminant] union {
+ [case(NETLOGON_QUERY_FOR_PDC)] nbt_netlogon_query_for_pdc pdc;
+ [case(NETLOGON_QUERY_FOR_PDC2)] nbt_netlogon_query_for_pdc2 pdc2;
+ [case(NETLOGON_ANNOUNCE_UAS)] nbt_netlogon_announce_uas uas;
+ [case(NETLOGON_RESPONSE_FROM_PDC)] nbt_netlogon_response_from_pdc response;
+ [case(NETLOGON_RESPONSE_FROM_PDC2)] nbt_netlogon_response_from_pdc2 response2;
+ [case(NETLOGON_RESPONSE_FROM_PDC_USER)] nbt_netlogon_response_from_pdc2 response2;
+ } nbt_netlogon_request;
+
+ typedef [flag(NDR_NOALIGN),public] struct {
+ nbt_netlogon_command command;
+ [switch_is(command)] nbt_netlogon_request req;
+ } nbt_netlogon_packet;
+
+ /*******************************************/
+ /* CLDAP netlogon response */
+
+ /* note that these structures are very similar to, but not
+ quite identical to, the netlogon structures above */
+
+ typedef struct {
+ nbt_netlogon_command type;
+ nstring pdc_name;
+ nstring user_name;
+ nstring domain_name;
+ [value(1)] nbt_netlogon_version nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } nbt_cldap_netlogon_1;
+
+ typedef struct {
+ nbt_netlogon_command type;
+ nstring pdc_name;
+ nstring user_name;
+ nstring domain_name;
+ GUID domain_uuid;
+ GUID unknown_uuid;
+ nbt_string forest;
+ nbt_string dns_domain;
+ nbt_string pdc_dns_name;
+ ipv4address pdc_ip;
+ nbt_server_type server_type;
+ [value(3)] nbt_netlogon_version nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } nbt_cldap_netlogon_3;
+
+ typedef [public] struct {
+ nbt_netlogon_command type;
+ uint16 sbz;
+ nbt_server_type server_type;
+ GUID domain_uuid;
+ nbt_string forest;
+ nbt_string dns_domain;
+ nbt_string pdc_dns_name;
+ nbt_string domain;
+ nbt_string pdc_name;
+ nbt_string user_name;
+ nbt_string server_site;
+ nbt_string client_site;
+ [value(5)] nbt_netlogon_version nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } nbt_cldap_netlogon_5;
+
+ typedef struct {
+ nbt_netlogon_command type;
+ uint16 sbz;
+ nbt_server_type server_type;
+ GUID domain_uuid;
+ nbt_string forest;
+ nbt_string dns_domain;
+ nbt_string pdc_dns_name;
+ nbt_string domain;
+ nbt_string pdc_name;
+ nbt_string user_name;
+ nbt_string server_site;
+ nbt_string client_site;
+ uint8 dc_sock_addr_size;
+ [subcontext(0),subcontext_size(dc_sock_addr_size)] nbt_dc_sock_addr dc_sock_addr;
+ [value(13)] nbt_netlogon_version nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } nbt_cldap_netlogon_13;
+
+ typedef [public] struct {
+ nbt_netlogon_command type;
+ uint16 sbz;
+ nbt_server_type server_type;
+ GUID domain_uuid;
+ nbt_string forest;
+ nbt_string dns_domain;
+ nbt_string pdc_dns_name;
+ nbt_string domain;
+ nbt_string pdc_name;
+ nbt_string user_name;
+ nbt_string server_site;
+ nbt_string client_site;
+ nbt_string next_closest_site;
+ [value(15)] nbt_netlogon_version nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } nbt_cldap_netlogon_15;
+
+ typedef [public] struct {
+ nbt_netlogon_command type;
+ uint16 sbz;
+ nbt_server_type server_type;
+ GUID domain_uuid;
+ nbt_string forest;
+ nbt_string dns_domain;
+ nbt_string pdc_dns_name;
+ nbt_string domain;
+ nbt_string pdc_name;
+ nbt_string user_name;
+ nbt_string server_site;
+ nbt_string client_site;
+ uint8 dc_sock_addr_size;
+ [subcontext(0),subcontext_size(dc_sock_addr_size)] nbt_dc_sock_addr dc_sock_addr;
+ nbt_string next_closest_site;
+ [value(29)] nbt_netlogon_version nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } nbt_cldap_netlogon_29;
+
+ typedef [flag(NDR_NOALIGN),public,nodiscriminant] union {
+ [case(0)] nbt_cldap_netlogon_1 logon1;
+ [case(1)] nbt_cldap_netlogon_1 logon1;
+ [case(2)] nbt_cldap_netlogon_3 logon3;
+ [case(3)] nbt_cldap_netlogon_3 logon3;
+ [case(4)] nbt_cldap_netlogon_5 logon5;
+ [case(5)] nbt_cldap_netlogon_5 logon5;
+ [case(6)] nbt_cldap_netlogon_5 logon5;
+ [case(7)] nbt_cldap_netlogon_5 logon5;
+ [case(8)] nbt_cldap_netlogon_13 logon13;
+ [case(9)] nbt_cldap_netlogon_13 logon13;
+ [case(10)] nbt_cldap_netlogon_13 logon13;
+ [case(11)] nbt_cldap_netlogon_13 logon13;
+ [case(12)] nbt_cldap_netlogon_13 logon13;
+ [case(13)] nbt_cldap_netlogon_13 logon13;
+ [case(14)] nbt_cldap_netlogon_13 logon13;
+ [case(15)] nbt_cldap_netlogon_13 logon13;
+ [case(16)] nbt_cldap_netlogon_1 logon1;
+ [case(17)] nbt_cldap_netlogon_1 logon1;
+ [case(18)] nbt_cldap_netlogon_3 logon3;
+ [case(19)] nbt_cldap_netlogon_3 logon3;
+ [case(20)] nbt_cldap_netlogon_15 logon15;
+ [case(21)] nbt_cldap_netlogon_15 logon15;
+ [case(22)] nbt_cldap_netlogon_15 logon15;
+ [case(23)] nbt_cldap_netlogon_15 logon15;
+ [case(24)] nbt_cldap_netlogon_15 logon15;
+ [case(25)] nbt_cldap_netlogon_15 logon15;
+ [case(26)] nbt_cldap_netlogon_15 logon15;
+ [case(27)] nbt_cldap_netlogon_15 logon15;
+ [case(28)] nbt_cldap_netlogon_15 logon15;
+ [case(29)] nbt_cldap_netlogon_29 logon29;
+ [case(30)] nbt_cldap_netlogon_29 logon29;
+ [case(31)] nbt_cldap_netlogon_29 logon29;
+ } nbt_cldap_netlogon;
+
+ /*******************************************/
+ /* \MAILSLOT\NET\NTLOGON mailslot requests */
+ typedef enum {
+ NTLOGON_SAM_LOGON = 0x12,
+ NTLOGON_SAM_LOGON_REPLY = 0x13,
+ NTLOGON_SAM_LOGON_REPLY15 = 0x15,
+ NTLOGON_RESPONSE_FROM_PDC2 = 0x17
+ } nbt_ntlogon_command;
+
+ typedef struct {
+ uint16 request_count;
+ nstring computer_name;
+ nstring user_name;
+ astring mailslot_name;
+ samr_AcctFlags acct_control;
+ [value(ndr_size_dom_sid0(&sid, ndr->flags))] uint32 sid_size;
+ [subcontext(0),subcontext_size(sid_size)] dom_sid0 sid;
+ nbt_netlogon_version nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } nbt_ntlogon_sam_logon;
+
+ typedef struct {
+ nstring server;
+ nstring user_name;
+ nstring domain;
+ nbt_netlogon_version nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } nbt_ntlogon_sam_logon_reply;
+
+ typedef [nodiscriminant] union {
+ [case(NTLOGON_SAM_LOGON)] nbt_ntlogon_sam_logon logon;
+ [case(NTLOGON_SAM_LOGON_REPLY)] nbt_ntlogon_sam_logon_reply reply;
+ [case(NTLOGON_SAM_LOGON_REPLY15)] nbt_ntlogon_sam_logon_reply reply;
+ [case(NTLOGON_RESPONSE_FROM_PDC2)] nbt_netlogon_response_from_pdc2 reply2;
+ } nbt_ntlogon_request;
+
+ typedef [flag(NDR_NOALIGN),public] struct {
+ nbt_ntlogon_command command;
+ [switch_is(command)] nbt_ntlogon_request req;
+ } nbt_ntlogon_packet;
+
+ /********************************************************/
+ /* \MAILSLOT\BROWSE mailslot requests */
+ /* for details see http://ubiqx.org/cifs/Browsing.html */
+ /********************************************************/
+ typedef bitmap svcctl_ServerType svcctl_ServerType;
+
+ typedef [enum8bit] enum {
+ HostAnnouncement = 1,
+ AnnouncementRequest = 2,
+ Election = 8,
+ GetBackupListReq = 9,
+ GetBackupListResp = 10,
+ BecomeBackup = 11,
+ DomainAnnouncement = 12,
+ MasterAnnouncement = 13,
+ ResetBrowserState = 14,
+ LocalMasterAnnouncement = 15
+ } nbt_browse_opcode;
+
+ typedef struct {
+ uint8 UpdateCount;
+ uint32 Periodicity;
+ [charset(DOS)] uint8 ServerName[16];
+ uint8 OSMajor;
+ uint8 OSMinor;
+ svcctl_ServerType ServerType;
+ uint8 BroMajorVer;
+ uint8 BroMinorVer;
+ uint16 Signature;
+ astring Comment;
+ } nbt_browse_host_announcement;
+
+ typedef struct {
+ uint8 Unused;
+ astring ResponseName;
+ } nbt_browse_announcement_request;
+
+ typedef struct {
+ uint8 Version;
+ uint32 Criteria;
+ uint32 UpTime; /* In milliseconds */
+ uint32 Reserved; /* Must be zero */
+ astring ServerName;
+ } nbt_browse_election_request;
+
+ typedef struct {
+ uint8 ReqCount;
+ uint32 Token;
+ } nbt_browse_backup_list_request;
+
+ typedef struct {
+ uint8 BackupCount;
+ uint32 Token;
+ nbt_name BackupServerList[BackupCount];/* TODO: this is wrong */
+ } nbt_browse_backup_list_response;
+
+ typedef struct {
+ astring BrowserName;
+ } nbt_browse_become_backup;
+
+ typedef struct {
+ uint8 UpdateCount;
+ uint32 Periodicity;
+ [charset(DOS)] uint8 ServerName[16];
+ uint8 OSMajor;
+ uint8 OSMinor;
+ svcctl_ServerType ServerType;
+ uint32 MysteriousField;
+ astring Comment;
+ } nbt_browse_domain_announcement;
+
+ typedef struct {
+ astring ServerName;
+ } nbt_browse_master_announcement;
+
+ typedef struct {
+ uint8 Command;
+ } nbt_browse_reset_state;
+
+ typedef struct {
+ uint8 UpdateCount;
+ uint32 Periodicity;
+ [charset(DOS)] uint8 ServerName[16];
+ uint8 OSMajor;
+ uint8 OSMinor;
+ svcctl_ServerType ServerType;
+ uint8 BroMajorVer;
+ uint8 BroMinorVer;
+ uint16 Signature;
+ astring Comment;
+ } nbt_browse_local_master_announcement;
+
+ typedef [nodiscriminant] union {
+ [case(HostAnnouncement)] nbt_browse_host_announcement host_annoucement;
+ [case(AnnouncementRequest)] nbt_browse_announcement_request announcement_request;
+ [case(Election)] nbt_browse_election_request election_request;
+ [case(GetBackupListReq)] nbt_browse_backup_list_request backup_list_request;
+ [case(GetBackupListResp)] nbt_browse_backup_list_response backup_list_response;
+ [case(BecomeBackup)] nbt_browse_become_backup become_backup;
+ [case(DomainAnnouncement)] nbt_browse_domain_announcement domain_announcement;
+ [case(MasterAnnouncement)] nbt_browse_master_announcement master_announcement;
+ [case(ResetBrowserState)] nbt_browse_reset_state reset_browser_state;
+ [case(LocalMasterAnnouncement)] nbt_browse_local_master_announcement local_master_announcement;
+ } nbt_browse_payload;
+
+ typedef [public,flag(NDR_NOALIGN)] struct {
+ nbt_browse_opcode opcode;
+ [switch_is(opcode)] nbt_browse_payload payload;
+ } nbt_browse_packet;
+}
diff --git a/source3/librpc/idl/netlogon.idl b/source3/librpc/idl/netlogon.idl
new file mode 100644
index 0000000000..74535fc073
--- /dev/null
+++ b/source3/librpc/idl/netlogon.idl
@@ -0,0 +1,1408 @@
+/*
+ netlogon interface
+ much of this was derived from the ethereal sources - thanks to everyone
+ who contributed!
+*/
+
+import "lsa.idl", "samr.idl", "security.idl", "nbt.idl";
+
+#include "idl_types.h"
+
+[
+ uuid("12345678-1234-abcd-ef00-01234567cffb"),
+ version(1.0),
+ endpoint("ncacn_np:[\\pipe\\netlogon]","ncacn_ip_tcp:","ncalrpc:"),
+ pointer_default(unique)
+]
+
+interface netlogon
+{
+ typedef bitmap samr_AcctFlags samr_AcctFlags;
+ typedef bitmap samr_GroupAttrs samr_GroupAttrs;
+
+ /*****************/
+ /* Function 0x00 */
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *account_name;
+ uint32 priv;
+ uint32 auth_flags;
+ uint32 logon_count;
+ uint32 bad_pw_count;
+ time_t last_logon;
+ time_t last_logoff;
+ time_t logoff_time;
+ time_t kickoff_time;
+ uint32 password_age;
+ time_t pw_can_change;
+ time_t pw_must_change;
+ [string,charset(UTF16)] uint16 *computer;
+ [string,charset(UTF16)] uint16 *domain;
+ [string,charset(UTF16)] uint16 *script_path;
+ uint32 unknown;
+ } netr_UasInfo;
+
+ WERROR netr_LogonUasLogon(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 account_name[],
+ [in] [string,charset(UTF16)] uint16 workstation[],
+ [out,ref] netr_UasInfo *info
+ );
+
+
+ /*****************/
+ /* Function 0x01 */
+
+ typedef struct {
+ uint32 duration;
+ uint16 logon_count;
+ } netr_UasLogoffInfo;
+
+ WERROR netr_LogonUasLogoff(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 account_name[],
+ [in] [string,charset(UTF16)] uint16 workstation[],
+ [out,ref] netr_UasLogoffInfo *info
+ );
+
+
+ /*****************/
+ /* Function 0x02 */
+
+ /* in netr_AcctLockStr size seems to be be 24, and rrenard thinks
+ that the structure of the bindata looks like this:
+
+ dlong lockout_duration;
+ udlong reset_count;
+ uint32 bad_attempt_lockout;
+ uint32 dummy;
+
+ but it doesn't look as though this structure is reflected at the
+ NDR level. Maybe it is left to the application to decode the bindata array.
+ */
+ typedef [public] struct {
+ dlong lockout_duration;
+ udlong reset_count;
+ uint32 bad_attempt_lockout;
+ uint32 dummy;
+ } netr_AcctLockStr;
+
+ /* - MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
+ * sets the NETLOGON_SERVER_TRUST_ACCOUNT user_flag
+ * - MSV1_0_UPDATE_LOGON_STATISTICS
+ * sets the logon time on network logon
+ * - MSV1_0_RETURN_USER_PARAMETERS
+ * sets the user parameters in the driveletter
+ * - MSV1_0_RETURN_PROFILE_PATH
+ * returns the profilepath in the driveletter and
+ * sets LOGON_PROFILE_PATH_RETURNED user_flag
+ */
+
+ typedef [public,bitmap32bit] bitmap {
+ MSV1_0_CLEARTEXT_PASSWORD_ALLOWED = 0x00000002,
+ MSV1_0_UPDATE_LOGON_STATISTICS = 0x00000004,
+ MSV1_0_RETURN_USER_PARAMETERS = 0x00000008,
+ MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT = 0x00000020,
+ MSV1_0_RETURN_PROFILE_PATH = 0x00000200,
+ MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT = 0x00000800
+ } netr_LogonParameterControl;
+
+ typedef struct {
+ lsa_String domain_name;
+ netr_LogonParameterControl parameter_control; /* see MSV1_0_* */
+ uint32 logon_id_low;
+ uint32 logon_id_high;
+ lsa_String account_name;
+ lsa_String workstation;
+ } netr_IdentityInfo;
+
+ typedef struct {
+ netr_IdentityInfo identity_info;
+ samr_Password lmpassword;
+ samr_Password ntpassword;
+ } netr_PasswordInfo;
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint16 length;
+ [value(length)] uint16 size;
+ [size_is(length),length_is(length)] uint8 *data;
+ } netr_ChallengeResponse;
+
+ typedef [flag(NDR_PAHEX)] struct {
+ netr_IdentityInfo identity_info;
+ uint8 challenge[8];
+ netr_ChallengeResponse nt;
+ netr_ChallengeResponse lm;
+ } netr_NetworkInfo;
+
+ typedef [public,switch_type(uint16)] union {
+ [case(1)] netr_PasswordInfo *password;
+ [case(2)] netr_NetworkInfo *network;
+ [case(3)] netr_PasswordInfo *password;
+ [case(5)] netr_PasswordInfo *password;
+ [case(6)] netr_NetworkInfo *network;
+ } netr_LogonInfo;
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ uint8 key[16];
+ } netr_UserSessionKey;
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ uint8 key[8];
+ } netr_LMSessionKey;
+
+ /* Flags for user_flags below */
+ typedef [public,bitmap32bit] bitmap {
+ NETLOGON_GUEST = 0x00000001,
+ NETLOGON_NOENCRYPTION = 0x00000002,
+ NETLOGON_CACHED_ACCOUNT = 0x00000004,
+ NETLOGON_USED_LM_PASSWORD = 0x00000008,
+ NETLOGON_EXTRA_SIDS = 0x00000020,
+ NETLOGON_SUBAUTH_SESSION_KEY = 0x00000040,
+ NETLOGON_SERVER_TRUST_ACCOUNT = 0x00000080,
+ NETLOGON_NTLMV2_ENABLED = 0x00000100,
+ NETLOGON_RESOURCE_GROUPS = 0x00000200,
+ NETLOGON_PROFILE_PATH_RETURNED = 0x00000400,
+ NETLOGON_GRACE_LOGON = 0x01000000
+ } netr_UserFlags;
+
+ typedef struct {
+ NTTIME last_logon;
+ NTTIME last_logoff;
+ NTTIME acct_expiry;
+ NTTIME last_password_change;
+ NTTIME allow_password_change;
+ NTTIME force_password_change;
+ lsa_String account_name;
+ lsa_String full_name;
+ lsa_String logon_script;
+ lsa_String profile_path;
+ lsa_String home_directory;
+ lsa_String home_drive;
+ uint16 logon_count;
+ uint16 bad_password_count;
+ uint32 rid;
+ uint32 primary_gid;
+ samr_RidWithAttributeArray groups;
+ netr_UserFlags user_flags;
+ netr_UserSessionKey key;
+ lsa_StringLarge logon_server;
+ lsa_StringLarge domain;
+ dom_sid2 *domain_sid;
+ netr_LMSessionKey LMSessKey;
+ samr_AcctFlags acct_flags;
+ uint32 unknown[7];
+ } netr_SamBaseInfo;
+
+ typedef struct {
+ netr_SamBaseInfo base;
+ } netr_SamInfo2;
+
+ typedef struct {
+ dom_sid2 *sid;
+ samr_GroupAttrs attributes;
+ } netr_SidAttr;
+
+ typedef [public] struct {
+ netr_SamBaseInfo base;
+ uint32 sidcount;
+ [size_is(sidcount)] netr_SidAttr *sids;
+ } netr_SamInfo3;
+
+ typedef struct {
+ netr_SamBaseInfo base;
+ uint32 sidcount;
+ [size_is(sidcount)] netr_SidAttr *sids;
+ lsa_String forest;
+ lsa_String principle;
+ uint32 unknown4[20];
+ } netr_SamInfo6;
+
+ typedef struct {
+ uint32 pac_size;
+ [size_is(pac_size)] uint8 *pac;
+ lsa_String logon_domain;
+ lsa_String logon_server;
+ lsa_String principal_name;
+ uint32 auth_size;
+ [size_is(auth_size)] uint8 *auth;
+ netr_UserSessionKey user_session_key;
+ uint32 expansionroom[10];
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ } netr_PacInfo;
+
+ typedef [public,switch_type(uint16)] union {
+ [case(2)] netr_SamInfo2 *sam2;
+ [case(3)] netr_SamInfo3 *sam3;
+ [case(4)] netr_PacInfo *pac;
+ [case(5)] netr_PacInfo *pac;
+ [case(6)] netr_SamInfo6 *sam6;
+ } netr_Validation;
+
+ typedef [public, flag(NDR_PAHEX)] struct {
+ uint8 data[8];
+ } netr_Credential;
+
+ typedef [public] struct {
+ netr_Credential cred;
+ time_t timestamp;
+ } netr_Authenticator;
+
+ typedef enum {
+ INTERACTIVE_LOGON_TYPE = 1,
+ NET_LOGON_TYPE = 2
+ } netr_LogonLevel;
+
+ NTSTATUS netr_LogonSamLogon(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *computer_name,
+ [in,unique] netr_Authenticator *credential,
+ [in,out,unique] netr_Authenticator *return_authenticator,
+ [in] netr_LogonLevel logon_level,
+ [in,ref] [switch_is(logon_level)] netr_LogonInfo *logon,
+ [in] uint16 validation_level,
+ [out,ref] [switch_is(validation_level)] netr_Validation *validation,
+ [out,ref] uint8 *authoritative
+ );
+
+
+ /*****************/
+ /* Function 0x03 */
+
+ NTSTATUS netr_LogonSamLogoff(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *computer_name,
+ [in,unique] netr_Authenticator *credential,
+ [in,out,unique] netr_Authenticator *return_authenticator,
+ [in] netr_LogonLevel logon_level,
+ [in] [switch_is(logon_level)] netr_LogonInfo logon
+ );
+
+
+
+ /*****************/
+ /* Function 0x04 */
+
+ NTSTATUS netr_ServerReqChallenge(
+ [in,unique,string,charset(UTF16)] uint16 *server_name,
+ [in,string,charset(UTF16)] uint16 computer_name[],
+ [in,ref] netr_Credential *credentials,
+ [out,ref] netr_Credential *return_credentials
+ );
+
+
+ /*****************/
+ /* Function 0x05 */
+
+ typedef enum netr_SchannelType netr_SchannelType;
+
+ NTSTATUS netr_ServerAuthenticate(
+ [in,unique,string,charset(UTF16)] uint16 *server_name,
+ [in,string,charset(UTF16)] uint16 account_name[],
+ [in] netr_SchannelType secure_channel_type,
+ [in,string,charset(UTF16)] uint16 computer_name[],
+ [in,ref] netr_Credential *credentials,
+ [out,ref] netr_Credential *return_credentials
+ );
+
+
+ /*****************/
+ /* Function 0x06 */
+
+ NTSTATUS netr_ServerPasswordSet(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 account_name[],
+ [in] netr_SchannelType secure_channel_type,
+ [in] [string,charset(UTF16)] uint16 computer_name[],
+ [in,ref] netr_Authenticator *credential,
+ [out,ref] netr_Authenticator *return_authenticator,
+ [in,ref] samr_Password *new_password
+ );
+
+
+ /*****************/
+ /* Function 0x07 */
+
+ typedef enum netr_SamDatabaseID netr_SamDatabaseID;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *account_name;
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_DELETE_USER;
+
+ typedef struct {
+ uint16 length;
+ [value(length)] uint16 size;
+ uint32 flags;
+ samr_Password pwd;
+ } netr_USER_KEY16;
+
+ typedef struct {
+ uint16 nt_length;
+ [value(nt_length)] uint16 nt_size;
+ uint32 nt_flags;
+ uint16 lm_length;
+ [value(lm_length)] uint16 lm_size;
+ uint32 lm_flags;
+ uint8 nt_history[nt_length];
+ uint8 lm_history[lm_length];
+ } netr_PasswordHistory;
+
+ typedef struct {
+ netr_USER_KEY16 lmpassword;
+ netr_USER_KEY16 ntpassword;
+ netr_PasswordHistory history;
+ } netr_USER_KEYS2;
+
+ typedef struct { /* TODO: make this a union! */
+ netr_USER_KEYS2 keys2;
+ } netr_USER_KEY_UNION;
+
+ typedef [public] struct {
+ uint32 version;
+ netr_USER_KEY_UNION keys;
+ } netr_USER_KEYS;
+
+ typedef struct {
+ boolean8 SensitiveDataFlag;
+ uint32 DataLength;
+
+ /* netr_USER_KEYS encrypted with the session key */
+ [size_is(DataLength)][flag(NDR_PAHEX)] uint8 *SensitiveData;
+ } netr_USER_PRIVATE_INFO;
+
+ typedef struct {
+ lsa_String account_name;
+ lsa_String full_name;
+ uint32 rid;
+ uint32 primary_gid;
+ lsa_String home_directory;
+ lsa_String home_drive;
+ lsa_String logon_script;
+ lsa_String description;
+ lsa_String workstations;
+ NTTIME last_logon;
+ NTTIME last_logoff;
+ samr_LogonHours logon_hours;
+ uint16 bad_password_count;
+ uint16 logon_count;
+ NTTIME last_password_change;
+ NTTIME acct_expiry;
+ samr_AcctFlags acct_flags;
+ samr_Password lmpassword;
+ samr_Password ntpassword;
+ boolean8 nt_password_present;
+ boolean8 lm_password_present;
+ boolean8 password_expired;
+ lsa_String comment;
+ lsa_String parameters;
+ uint16 country_code;
+ uint16 code_page;
+ netr_USER_PRIVATE_INFO user_private_info;
+ uint32 SecurityInformation;
+ sec_desc_buf sdbuf;
+ lsa_String profile_path;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_USER;
+
+ typedef struct {
+ lsa_String domain_name;
+ lsa_String comment;
+ dlong force_logoff_time;
+ uint16 min_password_length;
+ uint16 password_history_length;
+ /* yes, these are signed. They are in negative 100ns */
+ dlong max_password_age;
+ dlong min_password_age;
+ udlong sequence_num;
+ NTTIME domain_create_time;
+ uint32 SecurityInformation;
+ sec_desc_buf sdbuf;
+ lsa_BinaryString account_lockout;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 logon_to_chgpass;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_DOMAIN;
+
+ typedef struct {
+ lsa_String group_name;
+ uint32 rid;
+ uint32 attributes;
+ lsa_String description;
+ uint32 SecurityInformation;
+ sec_desc_buf sdbuf;
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_GROUP;
+
+ typedef struct {
+ lsa_String OldName;
+ lsa_String NewName;
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_RENAME;
+
+ typedef struct {
+ [size_is(num_rids)] uint32 *rids;
+ [size_is(num_rids)] uint32 *attribs;
+ uint32 num_rids;
+ uint32 unknown1;
+ uint32 unknown2;
+ uint32 unknown3;
+ uint32 unknown4;
+ } netr_DELTA_GROUP_MEMBER;
+
+ typedef struct {
+ lsa_String alias_name;
+ uint32 rid;
+ uint32 SecurityInformation;
+ sec_desc_buf sdbuf;
+ lsa_String description;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_ALIAS;
+
+ typedef struct {
+ lsa_SidArray sids;
+ uint32 unknown1;
+ uint32 unknown2;
+ uint32 unknown3;
+ uint32 unknown4;
+ } netr_DELTA_ALIAS_MEMBER;
+
+ typedef struct {
+ uint32 pagedpoollimit;
+ uint32 nonpagedpoollimit;
+ uint32 minimumworkingsetsize;
+ uint32 maximumworkingsetsize;
+ uint32 pagefilelimit;
+ NTTIME timelimit;
+ } netr_QUOTA_LIMITS;
+
+ typedef struct {
+ uint32 maxlogsize;
+ NTTIME auditretentionperiod;
+ boolean8 auditingmode;
+ uint32 maxauditeventcount;
+ [size_is(maxauditeventcount+1)] uint32 *eventauditoptions;
+ lsa_String primary_domain_name;
+ dom_sid2 *sid;
+ netr_QUOTA_LIMITS quota_limits;
+ udlong sequence_num;
+ NTTIME db_create_time;
+ uint32 SecurityInformation;
+ sec_desc_buf sdbuf;
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_POLICY;
+
+ typedef struct {
+ lsa_String domain_name;
+ uint32 num_controllers;
+ [size_is(num_controllers)] lsa_String *controller_names;
+ uint32 SecurityInformation;
+ sec_desc_buf sdbuf;
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 posix_offset;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_TRUSTED_DOMAIN;
+
+ typedef struct {
+ uint16 unknown;
+ } netr_DELTA_DELETE_TRUST;
+
+ typedef struct {
+ uint32 privilege_entries;
+ uint32 privilege_control;
+ [size_is(privilege_entries)] uint32 *privilege_attrib;
+ [size_is(privilege_entries)] lsa_String *privilege_name;
+ netr_QUOTA_LIMITS quotalimits;
+ uint32 system_flags;
+ uint32 SecurityInformation;
+ sec_desc_buf sdbuf;
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_ACCOUNT;
+
+ typedef struct {
+ uint16 unknown;
+ } netr_DELTA_DELETE_ACCOUNT;
+
+ typedef struct {
+ uint16 unknown;
+ } netr_DELTA_DELETE_SECRET;
+
+ typedef struct {
+ uint32 len;
+ uint32 maxlen;
+ [size_is(maxlen)][length_is(len)] uint8 *cipher_data;
+ } netr_CIPHER_VALUE;
+
+ typedef struct {
+ netr_CIPHER_VALUE current_cipher;
+ NTTIME current_cipher_set_time;
+ netr_CIPHER_VALUE old_cipher;
+ NTTIME old_cipher_set_time;
+ uint32 SecurityInformation;
+ sec_desc_buf sdbuf;
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_SECRET;
+
+ typedef enum {
+ NETR_DELTA_DOMAIN = 1,
+ NETR_DELTA_GROUP = 2,
+ NETR_DELTA_DELETE_GROUP = 3,
+ NETR_DELTA_RENAME_GROUP = 4,
+ NETR_DELTA_USER = 5,
+ NETR_DELTA_DELETE_USER = 6,
+ NETR_DELTA_RENAME_USER = 7,
+ NETR_DELTA_GROUP_MEMBER = 8,
+ NETR_DELTA_ALIAS = 9,
+ NETR_DELTA_DELETE_ALIAS = 10,
+ NETR_DELTA_RENAME_ALIAS = 11,
+ NETR_DELTA_ALIAS_MEMBER = 12,
+ NETR_DELTA_POLICY = 13,
+ NETR_DELTA_TRUSTED_DOMAIN = 14,
+ NETR_DELTA_DELETE_TRUST = 15,
+ NETR_DELTA_ACCOUNT = 16,
+ NETR_DELTA_DELETE_ACCOUNT = 17,
+ NETR_DELTA_SECRET = 18,
+ NETR_DELTA_DELETE_SECRET = 19,
+ NETR_DELTA_DELETE_GROUP2 = 20,
+ NETR_DELTA_DELETE_USER2 = 21,
+ NETR_DELTA_MODIFY_COUNT = 22
+ } netr_DeltaEnum;
+
+ typedef [switch_type(netr_DeltaEnum)] union {
+ [case(NETR_DELTA_DOMAIN)] netr_DELTA_DOMAIN *domain;
+ [case(NETR_DELTA_GROUP)] netr_DELTA_GROUP *group;
+ [case(NETR_DELTA_DELETE_GROUP)] ; /* rid only */
+ [case(NETR_DELTA_RENAME_GROUP)] netr_DELTA_RENAME *rename_group;
+ [case(NETR_DELTA_USER)] netr_DELTA_USER *user;
+ [case(NETR_DELTA_DELETE_USER)] ; /* rid only */
+ [case(NETR_DELTA_RENAME_USER)] netr_DELTA_RENAME *rename_user;
+ [case(NETR_DELTA_GROUP_MEMBER)] netr_DELTA_GROUP_MEMBER *group_member;
+ [case(NETR_DELTA_ALIAS)] netr_DELTA_ALIAS *alias;
+ [case(NETR_DELTA_DELETE_ALIAS)] ; /* rid only */
+ [case(NETR_DELTA_RENAME_ALIAS)] netr_DELTA_RENAME *rename_alias;
+ [case(NETR_DELTA_ALIAS_MEMBER)] netr_DELTA_ALIAS_MEMBER *alias_member;
+ [case(NETR_DELTA_POLICY)] netr_DELTA_POLICY *policy;
+ [case(NETR_DELTA_TRUSTED_DOMAIN)] netr_DELTA_TRUSTED_DOMAIN *trusted_domain;
+ [case(NETR_DELTA_DELETE_TRUST)] netr_DELTA_DELETE_TRUST delete_trust;
+ [case(NETR_DELTA_ACCOUNT)] netr_DELTA_ACCOUNT *account;
+ [case(NETR_DELTA_DELETE_ACCOUNT)] netr_DELTA_DELETE_ACCOUNT delete_account;
+ [case(NETR_DELTA_SECRET)] netr_DELTA_SECRET *secret;
+ [case(NETR_DELTA_DELETE_SECRET)] netr_DELTA_DELETE_SECRET delete_secret;
+ [case(NETR_DELTA_DELETE_GROUP2)] netr_DELTA_DELETE_USER *delete_group;
+ [case(NETR_DELTA_DELETE_USER2)] netr_DELTA_DELETE_USER *delete_user;
+ [case(NETR_DELTA_MODIFY_COUNT)] udlong *modified_count;
+ } netr_DELTA_UNION;
+
+ typedef [switch_type(netr_DeltaEnum)] union {
+ [case(NETR_DELTA_DOMAIN)] uint32 rid;
+ [case(NETR_DELTA_GROUP)] uint32 rid;
+ [case(NETR_DELTA_DELETE_GROUP)] uint32 rid;
+ [case(NETR_DELTA_RENAME_GROUP)] uint32 rid;
+ [case(NETR_DELTA_USER)] uint32 rid;
+ [case(NETR_DELTA_DELETE_USER)] uint32 rid;
+ [case(NETR_DELTA_RENAME_USER)] uint32 rid;
+ [case(NETR_DELTA_GROUP_MEMBER)] uint32 rid;
+ [case(NETR_DELTA_ALIAS)] uint32 rid;
+ [case(NETR_DELTA_DELETE_ALIAS)] uint32 rid;
+ [case(NETR_DELTA_RENAME_ALIAS)] uint32 rid;
+ [case(NETR_DELTA_ALIAS_MEMBER)] uint32 rid;
+ [case(NETR_DELTA_POLICY)] dom_sid2 *sid;
+ [case(NETR_DELTA_TRUSTED_DOMAIN)] dom_sid2 *sid;
+ [case(NETR_DELTA_DELETE_TRUST)] dom_sid2 *sid;
+ [case(NETR_DELTA_ACCOUNT)] dom_sid2 *sid;
+ [case(NETR_DELTA_DELETE_ACCOUNT)] dom_sid2 *sid;
+ [case(NETR_DELTA_SECRET)] [string,charset(UTF16)] uint16 *name;
+ [case(NETR_DELTA_DELETE_SECRET)] [string,charset(UTF16)] uint16 *name;
+ [case(NETR_DELTA_DELETE_GROUP2)] uint32 rid;
+ [case(NETR_DELTA_DELETE_USER2)] uint32 rid;
+ [case(NETR_DELTA_MODIFY_COUNT)] ;
+ } netr_DELTA_ID_UNION;
+
+ typedef struct {
+ netr_DeltaEnum delta_type;
+ [switch_is(delta_type)] netr_DELTA_ID_UNION delta_id_union;
+ [switch_is(delta_type)] netr_DELTA_UNION delta_union;
+ } netr_DELTA_ENUM;
+
+ typedef struct {
+ uint32 num_deltas;
+ [size_is(num_deltas)] netr_DELTA_ENUM *delta_enum;
+ } netr_DELTA_ENUM_ARRAY;
+
+
+ NTSTATUS netr_DatabaseDeltas(
+ [in] [string,charset(UTF16)] uint16 logon_server[],
+ [in] [string,charset(UTF16)] uint16 computername[],
+ [in,ref] netr_Authenticator *credential,
+ [in,out,ref] netr_Authenticator *return_authenticator,
+ [in] netr_SamDatabaseID database_id,
+ [in,out,ref] udlong *sequence_num,
+ [out,ref] netr_DELTA_ENUM_ARRAY **delta_enum_array,
+ [in] uint32 preferredmaximumlength
+ );
+
+
+ /*****************/
+ /* Function 0x08 */
+
+ NTSTATUS netr_DatabaseSync(
+ [in] [string,charset(UTF16)] uint16 logon_server[],
+ [in] [string,charset(UTF16)] uint16 computername[],
+ [in] netr_Authenticator credential,
+ [in,out,ref] netr_Authenticator *return_authenticator,
+ [in] netr_SamDatabaseID database_id,
+ [in,out,ref] uint32 *sync_context,
+ [in] uint32 preferredmaximumlength,
+ [out,ref] netr_DELTA_ENUM_ARRAY *delta_enum_array
+ );
+
+
+ /*****************/
+ /* Function 0x09 */
+
+ /* w2k3 returns NT_STATUS_NOT_IMPLEMENTED for this call */
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint8 computer_name[16];
+ uint32 timecreated;
+ uint32 serial_number;
+ } netr_UAS_INFO_0;
+
+ typedef struct {
+ [flag(NDR_REMAINING)] DATA_BLOB blob;
+ } netr_AccountBuffer;
+
+ NTSTATUS netr_AccountDeltas(
+ [in,unique] [string,charset(UTF16)] uint16 *logon_server,
+ [in] [string,charset(UTF16)] uint16 computername[],
+ [in] netr_Authenticator credential,
+ [in,out,ref] netr_Authenticator *return_authenticator,
+ [in] netr_UAS_INFO_0 uas,
+ [in] uint32 count,
+ [in] uint32 level,
+ [in] uint32 buffersize,
+ [out,ref,subcontext(4)] netr_AccountBuffer *buffer,
+ [out,ref] uint32 *count_returned,
+ [out,ref] uint32 *total_entries,
+ [out,ref] netr_UAS_INFO_0 *recordid
+ );
+
+
+ /*****************/
+ /* Function 0x0A */
+
+ NTSTATUS netr_AccountSync(
+ [in,unique] [string,charset(UTF16)] uint16 *logon_server,
+ [in] [string,charset(UTF16)] uint16 computername[],
+ [in] netr_Authenticator credential,
+ [in,out,ref] netr_Authenticator *return_authenticator,
+ [in] uint32 reference,
+ [in] uint32 level,
+ [in] uint32 buffersize,
+ [out,ref,subcontext(4)] netr_AccountBuffer *buffer,
+ [out,ref] uint32 *count_returned,
+ [out,ref] uint32 *total_entries,
+ [out,ref] uint32 *next_reference,
+ [in,out,ref] netr_UAS_INFO_0 *recordid
+ );
+
+
+ /*****************/
+ /* Function 0x0B */
+
+ WERROR netr_GetDcName(
+ [in] [string,charset(UTF16)] uint16 logon_server[],
+ [in,unique] [string,charset(UTF16)] uint16 *domainname,
+ [out,ref] [string,charset(UTF16)] uint16 **dcname
+ );
+
+ /*****************/
+ /* Function 0x0C */
+
+ typedef [bitmap32bit] bitmap {
+ NETLOGON_CTRL_REPL_NEEDED = 0x0001,
+ NETLOGON_CTRL_REPL_IN_PROGRESS = 0x0002,
+ NETLOGON_CTRL_REPL_FULL_SYNC = 0x0004
+ } netr_InfoFlags;
+
+ typedef struct {
+ netr_InfoFlags flags;
+ uint32 pdc_connection_status;
+ } netr_NETLOGON_INFO_1;
+
+ typedef struct {
+ netr_InfoFlags flags;
+ uint32 pdc_connection_status;
+ [string,charset(UTF16)] uint16 *trusted_dc_name;
+ uint32 tc_connection_status;
+ } netr_NETLOGON_INFO_2;
+
+ typedef struct {
+ netr_InfoFlags flags;
+ uint32 logon_attempts;
+ uint32 unknown1;
+ uint32 unknown2;
+ uint32 unknown3;
+ uint32 unknown4;
+ uint32 unknown5;
+ } netr_NETLOGON_INFO_3;
+
+ typedef union {
+ [case(1)] netr_NETLOGON_INFO_1 *info1;
+ [case(2)] netr_NETLOGON_INFO_2 *info2;
+ [case(3)] netr_NETLOGON_INFO_3 *info3;
+ } netr_CONTROL_QUERY_INFORMATION;
+
+ /* function_code values */
+ typedef [v1_enum] enum {
+ NETLOGON_CONTROL_SYNC = 2,
+ NETLOGON_CONTROL_REDISCOVER = 5,
+ NETLOGON_CONTROL_TC_QUERY = 6,
+ NETLOGON_CONTROL_TRANSPORT_NOTIFY = 7,
+ NETLOGON_CONTROL_SET_DBFLAG = 65534
+ } netr_LogonControlCode;
+
+ WERROR netr_LogonControl(
+ [in,unique] [string,charset(UTF16)] uint16 *logon_server,
+ [in] netr_LogonControlCode function_code,
+ [in] uint32 level,
+ [out,ref,switch_is(level)] netr_CONTROL_QUERY_INFORMATION *info
+ );
+
+
+ /*****************/
+ /* Function 0x0D */
+
+ WERROR netr_GetAnyDCName(
+ [in,unique] [string,charset(UTF16)] uint16 *logon_server,
+ [in,unique] [string,charset(UTF16)] uint16 *domainname,
+ [out,ref] [string,charset(UTF16)] uint16 **dcname
+ );
+
+
+ /*****************/
+ /* Function 0x0E */
+
+ typedef union {
+ [case(NETLOGON_CONTROL_REDISCOVER)] [string,charset(UTF16)] uint16 *domain;
+ [case(NETLOGON_CONTROL_TC_QUERY)] [string,charset(UTF16)] uint16 *domain;
+ [case(NETLOGON_CONTROL_TRANSPORT_NOTIFY)] [string,charset(UTF16)] uint16 *domain;
+ [case(NETLOGON_CONTROL_SET_DBFLAG)] uint32 debug_level;
+ } netr_CONTROL_DATA_INFORMATION;
+
+ WERROR netr_LogonControl2(
+ [in,unique] [string,charset(UTF16)] uint16 *logon_server,
+ [in] netr_LogonControlCode function_code,
+ [in] uint32 level,
+ [in,ref][switch_is(function_code)] netr_CONTROL_DATA_INFORMATION *data,
+ [out,ref][switch_is(level)] netr_CONTROL_QUERY_INFORMATION *query
+ );
+
+
+ /* If NETLOGON_NEG_ARCFOUR flag is not set, then the passwords and LM
+ * session keys are encrypted with DES calls. (And the user session key
+ * is unencrypted) */
+
+ /*****************/
+ /* Function 0x0F */
+
+ typedef [bitmap32bit] bitmap {
+ NETLOGON_NEG_ACCOUNT_LOCKOUT = 0x00000001,
+ NETLOGON_NEG_PERSISTENT_SAMREPL = 0x00000002,
+ NETLOGON_NEG_ARCFOUR = 0x00000004,
+ NETLOGON_NEG_PROMOTION_COUNT = 0x00000008,
+ NETLOGON_NEG_CHANGELOG_BDC = 0x00000010,
+ NETLOGON_NEG_FULL_SYNC_REPL = 0x00000020,
+ NETLOGON_NEG_MULTIPLE_SIDS = 0x00000040,
+ NETLOGON_NEG_REDO = 0x00000080,
+ NETLOGON_NEG_PASSWORD_CHANGE_REFUSAL = 0x00000100,
+ NETLOGON_NEG_SEND_PASSWORD_INFO_PDC = 0x00000200,
+ NETLOGON_NEG_GENERIC_PASSTHROUGH = 0x00000400,
+ NETLOGON_NEG_CONCURRENT_RPC = 0x00000800,
+ NETLOGON_NEG_AVOID_ACCOUNT_DB_REPL = 0x00001000,
+ NETLOGON_NEG_AVOID_SECURITYAUTH_DB_REPL = 0x00002000,
+ NETLOGON_NEG_128BIT = 0x00004000, /* STRONG_KEYS */
+ NETLOGON_NEG_TRANSITIVE_TRUSTS = 0x00008000,
+ NETLOGON_NEG_DNS_DOMAIN_TRUSTS = 0x00010000,
+ NETLOGON_NEG_PASSWORD_SET2 = 0x00020000,
+ NETLOGON_NEG_GETDOMAININFO = 0x00040000,
+ NETLOGON_NEG_CROSS_FOREST_TRUSTS = 0x00080000,
+ NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION = 0x00100000,
+ NETLOGON_NEG_RODC_PASSTHROUGH = 0x00200000,
+ NETLOGON_NEG_AUTHENTICATED_RPC_LSASS = 0x20000000,
+ NETLOGON_NEG_SCHANNEL = 0x40000000 /* AUTHENTICATED_RPC */
+ } netr_NegotiateFlags;
+
+ NTSTATUS netr_ServerAuthenticate2(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 account_name[],
+ [in] netr_SchannelType secure_channel_type,
+ [in] [string,charset(UTF16)] uint16 computer_name[],
+ [in,ref] netr_Credential *credentials,
+ [out,ref] netr_Credential *return_credentials,
+ [in,out,ref] netr_NegotiateFlags *negotiate_flags
+ );
+
+
+ /*****************/
+ /* Function 0x10 */
+
+ NTSTATUS netr_DatabaseSync2(
+ [in] [string,charset(UTF16)] uint16 logon_server[],
+ [in] [string,charset(UTF16)] uint16 computername[],
+ [in] netr_Authenticator *credential,
+ [in,out,ref] netr_Authenticator *return_authenticator,
+ [in] netr_SamDatabaseID database_id,
+ [in] uint16 restart_state,
+ [in,out,ref] uint32 *sync_context,
+ [out,ref] netr_DELTA_ENUM_ARRAY **delta_enum_array,
+ [in] uint32 preferredmaximumlength
+ );
+
+
+ /*****************/
+ /* Function 0x11 */
+
+ /* i'm not at all sure how this call works */
+
+ NTSTATUS netr_DatabaseRedo(
+ [in] [string,charset(UTF16)] uint16 logon_server[],
+ [in] [string,charset(UTF16)] uint16 computername[],
+ [in] netr_Authenticator credential,
+ [in,out,ref] netr_Authenticator *return_authenticator,
+ [in,unique][size_is(change_log_entry_size)] uint8 *change_log_entry,
+ [in] uint32 change_log_entry_size,
+ [out,ref] netr_DELTA_ENUM_ARRAY *delta_enum_array
+ );
+
+
+ /*****************/
+ /* Function 0x12 */
+
+ WERROR netr_LogonControl2Ex(
+ [in,unique] [string,charset(UTF16)] uint16 *logon_server,
+ [in] uint32 function_code,
+ [in] uint32 level,
+ [in][switch_is(function_code)] netr_CONTROL_DATA_INFORMATION data,
+ [out,ref][switch_is(level)] netr_CONTROL_QUERY_INFORMATION *query
+ );
+
+ /*****************/
+ /* Function 0x13 */
+ typedef struct {
+ uint32 length;
+ [size_is(length)] uint8 *data;
+ } netr_Blob;
+
+ WERROR netr_NetrEnumerateTrustedDomains(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [out,ref] netr_Blob *trusted_domains_blob
+ );
+
+ /*****************/
+ /* Function 0x14 */
+
+ /* one unkown bit still: DS_IP_VERSION_AGNOSTIC - gd*/
+
+ const int DSGETDC_VALID_FLAGS = (DS_FORCE_REDISCOVERY |
+ DS_DIRECTORY_SERVICE_REQUIRED |
+ DS_DIRECTORY_SERVICE_PREFERRED |
+ DS_GC_SERVER_REQUIRED |
+ DS_PDC_REQUIRED |
+ DS_BACKGROUND_ONLY |
+ DS_IP_REQUIRED |
+ DS_KDC_REQUIRED |
+ DS_TIMESERV_REQUIRED |
+ DS_WRITABLE_REQUIRED |
+ DS_GOOD_TIMESERV_PREFERRED |
+ DS_AVOID_SELF |
+ DS_ONLY_LDAP_NEEDED |
+ DS_IS_FLAT_NAME |
+ DS_IS_DNS_NAME |
+ DS_RETURN_FLAT_NAME |
+ DS_RETURN_DNS_NAME);
+
+ typedef [bitmap32bit] bitmap {
+ DS_FORCE_REDISCOVERY = 0x00000001,
+ DS_DIRECTORY_SERVICE_REQUIRED = 0x00000010,
+ DS_DIRECTORY_SERVICE_PREFERRED = 0x00000020,
+ DS_GC_SERVER_REQUIRED = 0x00000040,
+ DS_PDC_REQUIRED = 0x00000080,
+ DS_BACKGROUND_ONLY = 0x00000100,
+ DS_IP_REQUIRED = 0x00000200,
+ DS_KDC_REQUIRED = 0x00000400,
+ DS_TIMESERV_REQUIRED = 0x00000800,
+ DS_WRITABLE_REQUIRED = 0x00001000,
+ DS_GOOD_TIMESERV_PREFERRED = 0x00002000,
+ DS_AVOID_SELF = 0x00004000,
+ DS_ONLY_LDAP_NEEDED = 0x00008000,
+ DS_IS_FLAT_NAME = 0x00010000,
+ DS_IS_DNS_NAME = 0x00020000,
+ DS_TRY_NEXTCLOSEST_SITE = 0x00040000,
+ DS_DIRECTORY_SERVICE_6_REQUIRED = 0x00080000,
+ DS_RETURN_DNS_NAME = 0x40000000,
+ DS_RETURN_FLAT_NAME = 0x80000000
+ } netr_DsRGetDCName_flags;
+
+ typedef [v1_enum] enum {
+ DS_ADDRESS_TYPE_INET = 1,
+ DS_ADDRESS_TYPE_NETBIOS = 2
+ } netr_DsRGetDCNameInfo_AddressType;
+
+ typedef [bitmap32bit] bitmap {
+ DS_SERVER_PDC = NBT_SERVER_PDC,
+ DS_SERVER_GC = NBT_SERVER_GC,
+ DS_SERVER_LDAP = NBT_SERVER_LDAP,
+ DS_SERVER_DS = NBT_SERVER_DS,
+ DS_SERVER_KDC = NBT_SERVER_KDC,
+ DS_SERVER_TIMESERV = NBT_SERVER_TIMESERV,
+ DS_SERVER_CLOSEST = NBT_SERVER_CLOSEST,
+ DS_SERVER_WRITABLE = NBT_SERVER_WRITABLE,
+ DS_SERVER_GOOD_TIMESERV = NBT_SERVER_GOOD_TIMESERV,
+ DS_SERVER_NDNC = NBT_SERVER_NDNC,
+ DS_SERVER_SELECT_SECRET_DOMAIN_6 = NBT_SERVER_SELECT_SECRET_DOMAIN_6,
+ DS_SERVER_FULL_SECRET_DOMAIN_6 = NBT_SERVER_FULL_SECRET_DOMAIN_6,
+ DS_DNS_CONTROLLER = 0x20000000,
+ DS_DNS_DOMAIN = 0x40000000,
+ DS_DNS_FOREST = 0x80000000
+ } netr_DsR_DcFlags;
+
+ typedef [public] struct {
+ [string,charset(UTF16)] uint16 *dc_unc;
+ [string,charset(UTF16)] uint16 *dc_address;
+ netr_DsRGetDCNameInfo_AddressType dc_address_type;
+ GUID domain_guid;
+ [string,charset(UTF16)] uint16 *domain_name;
+ [string,charset(UTF16)] uint16 *forest_name;
+ netr_DsR_DcFlags dc_flags;
+ [string,charset(UTF16)] uint16 *dc_site_name;
+ [string,charset(UTF16)] uint16 *client_site_name;
+ } netr_DsRGetDCNameInfo;
+
+ WERROR netr_DsRGetDCName(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *domain_name,
+ [in,unique] GUID *domain_guid,
+ [in,unique] GUID *site_guid,
+ [in] netr_DsRGetDCName_flags flags,
+ [out,ref] netr_DsRGetDCNameInfo **info
+ );
+
+ /*****************/
+ /* Function 0x15 */
+ WERROR netr_NETRLOGONDUMMYROUTINE1();
+
+ /****************/
+ /* Function 0x16 */
+ WERROR netr_NETRLOGONSETSERVICEBITS();
+
+ /****************/
+ /* Function 0x17 */
+ WERROR netr_LogonGetTrustRid(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *domain_name,
+ [out,ref] uint32 *rid
+ );
+
+ /****************/
+ /* Function 0x18 */
+ WERROR netr_NETRLOGONCOMPUTESERVERDIGEST();
+
+ /****************/
+ /* Function 0x19 */
+ WERROR netr_NETRLOGONCOMPUTECLIENTDIGEST();
+
+ /****************/
+ /* Function 0x1a */
+ NTSTATUS netr_ServerAuthenticate3(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 account_name[],
+ [in] netr_SchannelType secure_channel_type,
+ [in] [string,charset(UTF16)] uint16 computer_name[],
+ [in,out,ref] netr_Credential *credentials,
+ [in,out,ref] netr_NegotiateFlags *negotiate_flags,
+ [out,ref] uint32 *rid
+ );
+
+ /****************/
+ /* Function 0x1b */
+
+ WERROR netr_DsRGetDCNameEx(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *domain_name,
+ [in,unique] GUID *domain_guid,
+ [in,unique] [string,charset(UTF16)] uint16 *site_name,
+ [in] netr_DsRGetDCName_flags flags,
+ [out,ref] netr_DsRGetDCNameInfo **info
+ );
+
+ /****************/
+ /* Function 0x1c */
+ WERROR netr_DsRGetSiteName(
+ [in,unique] [string,charset(UTF16)] uint16 *computer_name,
+ [out,ref] [string,charset(UTF16)] uint16 **site
+ );
+
+ /****************/
+ /* Function 0x1d */
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint16 length;
+ uint16 size;
+ [size_is(size/2),length_is(length/2)] uint16 *data;
+ } netr_BinaryString;
+
+ typedef struct {
+ netr_Blob blob;
+ [string,charset(UTF16)] uint16 *workstation_domain;
+ [string,charset(UTF16)] uint16 *workstation_site;
+ [string,charset(UTF16)] uint16 *unknown1;
+ [string,charset(UTF16)] uint16 *unknown2;
+ [string,charset(UTF16)] uint16 *unknown3;
+ [string,charset(UTF16)] uint16 *unknown4;
+ netr_BinaryString blob2;
+ lsa_String product;
+ lsa_String unknown5;
+ lsa_String unknown6;
+ uint32 unknown7[4];
+ } netr_DomainQuery1;
+
+ typedef union {
+ [case(1)] netr_DomainQuery1 *query1;
+ [case(2)] netr_DomainQuery1 *query1;
+ } netr_DomainQuery;
+
+ typedef struct {
+ lsa_String domainname;
+ lsa_String fulldomainname;
+ lsa_String forest;
+ GUID guid;
+ dom_sid2 *sid;
+ netr_BinaryString unknown1[4];
+ uint32 unknown[4];
+ } netr_DomainTrustInfo;
+
+ typedef struct {
+ netr_DomainTrustInfo domaininfo;
+ uint32 num_trusts;
+ [size_is(num_trusts)] netr_DomainTrustInfo *trusts;
+ uint32 unknown[14]; /* room for expansion? */
+ } netr_DomainInfo1;
+
+ typedef union {
+ [case(1)] netr_DomainInfo1 *info1;
+ [case(2)] netr_DomainInfo1 *info1;
+ } netr_DomainInfo;
+
+ NTSTATUS netr_LogonGetDomainInfo(
+ [in] [string,charset(UTF16)] uint16 server_name[],
+ [in,unique] [string,charset(UTF16)] uint16 *computer_name,
+ [in,ref] netr_Authenticator *credential,
+ [in,out,ref] netr_Authenticator *return_authenticator,
+ [in] uint32 level,
+ [in,switch_is(level)] netr_DomainQuery query,
+ [out,ref,switch_is(level)] netr_DomainInfo *info
+ );
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint8 data[512];
+ uint32 length;
+ } netr_CryptPassword;
+
+ /*****************/
+ /* Function 0x1e */
+ NTSTATUS netr_ServerPasswordSet2(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 account_name[],
+ [in] netr_SchannelType secure_channel_type,
+ [in] [string,charset(UTF16)] uint16 computer_name[],
+ [in,ref] netr_Authenticator *credential,
+ [out,ref] netr_Authenticator *return_authenticator,
+ [in,ref] netr_CryptPassword *new_password
+ );
+
+ /****************/
+ /* Function 0x1f */
+ WERROR netr_ServerPasswordGet(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 account_name[],
+ [in] netr_SchannelType secure_channel_type,
+ [in] [string,charset(UTF16)] uint16 computer_name[],
+ [in,ref] netr_Authenticator *credential,
+ [out,ref] netr_Authenticator *return_authenticator,
+ [out,ref] samr_Password *password
+ );
+
+ /****************/
+ /* Function 0x20 */
+ WERROR netr_NETRLOGONSENDTOSAM();
+
+ /****************/
+ /* Function 0x21 */
+ typedef struct {
+ uint32 count;
+ [size_is(count)] lsa_String *sitename;
+ } netr_DsRAddressToSitenamesWCtr;
+
+ typedef struct {
+ [size_is(size)] uint8 *buffer;
+ uint32 size;
+ } netr_DsRAddress;
+
+ WERROR netr_DsRAddressToSitenamesW(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [range(0,32000)] uint32 count,
+ [in] [size_is(count)] [ref] netr_DsRAddress *addresses,
+ [out] [ref] netr_DsRAddressToSitenamesWCtr **ctr
+ );
+
+ /****************/
+ /* Function 0x22 */
+ WERROR netr_DsRGetDCNameEx2(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *client_account,
+ [in] samr_AcctFlags mask,
+ [in,unique] [string,charset(UTF16)] uint16 *domain_name,
+ [in,unique] GUID *domain_guid,
+ [in,unique] [string,charset(UTF16)] uint16 *site_name,
+ [in] netr_DsRGetDCName_flags flags,
+ [out,ref] netr_DsRGetDCNameInfo **info
+ );
+
+ /****************/
+ /* Function 0x23 */
+ WERROR netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN();
+
+ /****************/
+ /* Function 0x24 */
+ typedef [bitmap32bit] bitmap {
+ NETR_TRUST_FLAG_IN_FOREST = 0x00000001,
+ NETR_TRUST_FLAG_OUTBOUND = 0x00000002,
+ NETR_TRUST_FLAG_TREEROOT = 0x00000004,
+ NETR_TRUST_FLAG_PRIMARY = 0x00000008,
+ NETR_TRUST_FLAG_NATIVE = 0x00000010,
+ NETR_TRUST_FLAG_INBOUND = 0x00000020
+ } netr_TrustFlags;
+
+ typedef [v1_enum] enum {
+ NETR_TRUST_TYPE_DOWNLEVEL = 1,
+ NETR_TRUST_TYPE_UPLEVEL = 2,
+ NETR_TRUST_TYPE_MIT = 3,
+ NETR_TRUST_TYPE_DCE = 4
+ } netr_TrustType;
+
+ typedef [bitmap32bit] bitmap {
+ NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE = 0x00000001,
+ NETR_TRUST_ATTRIBUTE_UPLEVEL_ONLY = 0x00000002,
+ NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN = 0x00000004,
+ NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE = 0x00000008,
+ NETR_TRUST_ATTRIBUTE_CROSS_ORGANIZATION = 0x00000010,
+ NETR_TRUST_ATTRIBUTE_WITHIN_FOREST = 0x00000020,
+ NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL = 0x00000040
+ } netr_TrustAttributes;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *netbios_name;
+ [string,charset(UTF16)] uint16 *dns_name;
+ netr_TrustFlags trust_flags;
+ uint32 parent_index;
+ netr_TrustType trust_type;
+ netr_TrustAttributes trust_attributes;
+ dom_sid2 *sid;
+ GUID guid;
+ } netr_DomainTrust;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] netr_DomainTrust *array;
+ } netr_DomainTrustList;
+
+ WERROR netr_NetrEnumerateTrustedDomainsEx(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [out,ref] netr_DomainTrustList *dom_trust_list
+ );
+
+ /****************/
+ /* Function 0x25 */
+ typedef struct {
+ uint32 count;
+ [size_is(count)] lsa_String *sitename;
+ [size_is(count)] lsa_String *subnetname;
+ } netr_DsRAddressToSitenamesExWCtr;
+
+ WERROR netr_DsRAddressToSitenamesExW(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [range(0,32000)] uint32 count,
+ [in] [size_is(count)] [ref] netr_DsRAddress *addresses,
+ [out] [ref] netr_DsRAddressToSitenamesExWCtr **ctr
+ );
+
+ /****************/
+ /* Function 0x26 */
+
+ typedef struct {
+ uint32 num_sites;
+ [size_is(num_sites)] [unique] lsa_String *sites;
+ } DcSitesCtr;
+
+ WERROR netr_DsrGetDcSiteCoverageW(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [out,ref] DcSitesCtr *ctr
+ );
+
+ /****************/
+ /* Function 0x27 */
+ NTSTATUS netr_LogonSamLogonEx(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *computer_name,
+ [in] netr_LogonLevel logon_level,
+ [in,ref] [switch_is(logon_level)] netr_LogonInfo *logon,
+ [in] uint16 validation_level,
+ [out,ref] [switch_is(validation_level)] netr_Validation *validation,
+ [out,ref] uint8 *authoritative,
+ [in,out,ref] uint32 *flags
+ );
+
+ /****************/
+ /* Function 0x28 */
+
+ WERROR netr_DsrEnumerateDomainTrusts(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] netr_TrustFlags trust_flags,
+ [out,ref] netr_DomainTrustList *trusts
+ );
+
+
+ /****************/
+ /* Function 0x29 */
+ WERROR netr_DsrDeregisterDNSHostRecords(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *domain,
+ [in,unique] GUID *domain_guid,
+ [in,unique] GUID *dsa_guid,
+ [in,ref] [string,charset(UTF16)] uint16 *dns_host
+ );
+
+ /****************/
+ /* Function 0x2a */
+ NTSTATUS netr_ServerTrustPasswordsGet(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 account_name[],
+ [in] netr_SchannelType secure_channel_type,
+ [in] [string,charset(UTF16)] uint16 computer_name[],
+ [in,ref] netr_Authenticator *credential,
+ [out,ref] netr_Authenticator *return_authenticator,
+ [out,ref] samr_Password *password,
+ [out,ref] samr_Password *password2
+ );
+
+ /****************/
+ /* Function 0x2b */
+
+ const int DS_GFTI_UPDATE_TDO = 0x1;
+
+ WERROR netr_DsRGetForestTrustInformation(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *trusted_domain_name,
+ [in] uint32 flags,
+ [out,ref] lsa_ForestTrustInformation **forest_trust_info
+ );
+
+ /****************/
+ /* Function 0x2c */
+ WERROR netr_GetForestTrustInformation(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *trusted_domain_name,
+ [in,ref] netr_Authenticator *credential,
+ [out,ref] netr_Authenticator *return_authenticator,
+ [in] uint32 flags,
+ [out,ref] lsa_ForestTrustInformation **forest_trust_info
+ );
+
+ /****************/
+ /* Function 0x2d */
+
+ /* this is the ADS varient. I don't yet know what the "flags" are for */
+ NTSTATUS netr_LogonSamLogonWithFlags(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *computer_name,
+ [in,unique] netr_Authenticator *credential,
+ [in,out,unique] netr_Authenticator *return_authenticator,
+ [in] netr_LogonLevel logon_level,
+ [in] [switch_is(logon_level)] netr_LogonInfo logon,
+ [in] uint16 validation_level,
+ [out,ref] [switch_is(validation_level)] netr_Validation *validation,
+ [out,ref] uint8 *authoritative,
+ [in,out,ref] uint32 *flags
+ );
+
+ /****************/
+ /* Function 0x2e */
+ WERROR netr_NETRSERVERGETTRUSTINFO();
+}
diff --git a/source3/librpc/idl/notify.idl b/source3/librpc/idl/notify.idl
new file mode 100644
index 0000000000..c4e633c254
--- /dev/null
+++ b/source3/librpc/idl/notify.idl
@@ -0,0 +1,56 @@
+#include "idl_types.h"
+
+/*
+ IDL structures for notify change code
+
+ this defines the structures used in the notify database code, and
+ the change notify buffers
+*/
+
+[
+ pointer_default(unique)
+]
+interface notify
+{
+
+ /* structure used in the notify database */
+ typedef [public] struct {
+ server_id server;
+ uint32 filter; /* filter to apply in this directory */
+ uint32 subdir_filter; /* filter to apply in child directories */
+ utf8string path;
+ uint32 path_len; /* saves some computation on search */
+ pointer private_data;
+ } notify_entry;
+
+ /*
+ to allow for efficient search for matching entries, we
+ divide them by the directory depth, with a separate array
+ per depth. The entries within each depth are sorted by path,
+ allowing for a bisection search.
+
+ The max_mask and max_mask_subdir at each depth is the
+ bitwise or of the filters and subdir filters for all entries
+ at that depth. This allows a depth to be quickly skipped if
+ no entries will match the target filter
+ */
+ typedef struct {
+ uint32 max_mask;
+ uint32 max_mask_subdir;
+ uint32 num_entries;
+ notify_entry entries[num_entries];
+ } notify_depth;
+
+ typedef [public] struct {
+ uint32 num_depths;
+ notify_depth depth[num_depths];
+ } notify_array;
+
+ /* structure sent between servers in notify messages */
+ typedef [public] struct {
+ uint32 action;
+ utf8string path;
+ pointer private_data;
+ } notify_event;
+
+}
diff --git a/source3/librpc/idl/ntsvcs.idl b/source3/librpc/idl/ntsvcs.idl
new file mode 100644
index 0000000000..bac2549c73
--- /dev/null
+++ b/source3/librpc/idl/ntsvcs.idl
@@ -0,0 +1,375 @@
+/*
+ plug and play services
+*/
+[
+ uuid("8d9f4e40-a03d-11ce-8f69-08003e30051b"),
+ version(1.0),
+ helpstring("Plug and Play services")
+]
+interface ntsvcs
+{
+ /******************/
+ /* Function: 0x00 */
+
+ WERROR PNP_Disconnect();
+
+ /******************/
+ /* Function: 0x01 */
+
+ WERROR PNP_Connect();
+
+ /******************/
+ /* Function: 0x02 */
+
+ WERROR PNP_GetVersion(
+ [out,ref] uint16 *version
+ );
+
+ /******************/
+ /* Function: 0x03 */
+
+ WERROR PNP_GetGlobalState();
+
+ /******************/
+ /* Function: 0x04 */
+
+ WERROR PNP_InitDetection();
+
+ /******************/
+ /* Function: 0x05 */
+
+ WERROR PNP_ReportLogOn();
+
+ /******************/
+ /* Function: 0x06 */
+
+ WERROR PNP_ValidateDeviceInstance(
+ [in,ref] [string,charset(UTF16)] uint16 *devicepath,
+ [in] uint32 flags
+ );
+
+ /******************/
+ /* Function: 0x07 */
+
+ WERROR PNP_GetRootDeviceInstance();
+
+ /******************/
+ /* Function: 0x08 */
+
+ WERROR PNP_GetRelatedDeviceInstance();
+
+ /******************/
+ /* Function: 0x09 */
+
+ WERROR PNP_EnumerateSubKeys();
+
+ /******************/
+ /* Function: 0x0a */
+
+ WERROR PNP_GetDeviceList();
+
+ /******************/
+ /* Function: 0x0b */
+
+ WERROR PNP_GetDeviceListSize(
+ [in,unique] [string,charset(UTF16)] uint16 *devicename,
+ [out,ref] uint32 *size,
+ [in] uint32 flags
+ );
+
+ /******************/
+ /* Function: 0x0c */
+
+ WERROR PNP_GetDepth();
+
+ /******************/
+ /* Function: 0x0d */
+
+ const int DEV_REGPROP_DESC = 1;
+
+ WERROR PNP_GetDeviceRegProp(
+ [in,ref] [string,charset(UTF16)] uint16 *devicepath,
+ [in] uint32 property,
+ [in,out,ref] uint32 *unknown1,
+ [out,ref] [size_is(*buffer_size)] [length_is(*buffer_size)] uint8 *buffer,
+ [in,out,ref] uint32 *buffer_size,
+ [in,out,ref] uint32 *needed,
+ [in] uint32 unknown3
+ );
+
+ /******************/
+ /* Function: 0x0e */
+
+ WERROR PNP_SetDeviceRegProp();
+
+ /******************/
+ /* Function: 0x0f */
+
+ WERROR PNP_GetClassInstance();
+
+ /******************/
+ /* Function: 0x10 */
+
+ WERROR PNP_CreateKey();
+
+ /******************/
+ /* Function: 0x11 */
+
+ WERROR PNP_DeleteRegistryKey();
+
+ /******************/
+ /* Function: 0x12 */
+
+ WERROR PNP_GetClassCount();
+
+ /******************/
+ /* Function: 0x13 */
+
+ WERROR PNP_GetClassName();
+
+ /******************/
+ /* Function: 0x14 */
+
+ WERROR PNP_DeleteClassKey();
+
+ /******************/
+ /* Function: 0x15 */
+
+ WERROR PNP_GetInterfaceDeviceAlias();
+
+ /******************/
+ /* Function: 0x16 */
+
+ WERROR PNP_GetInterfaceDeviceList();
+
+ /******************/
+ /* Function: 0x17 */
+
+ WERROR PNP_GetInterfaceDeviceListSize();
+
+ /******************/
+ /* Function: 0x18 */
+
+ WERROR PNP_RegisterDeviceClassAssociation();
+
+ /******************/
+ /* Function: 0x19 */
+
+ WERROR PNP_UnregisterDeviceClassAssociation();
+
+ /******************/
+ /* Function: 0x1a */
+
+ WERROR PNP_GetClassRegProp();
+
+ /******************/
+ /* Function: 0x1b */
+
+ WERROR PNP_SetClassRegProp();
+
+ /******************/
+ /* Function: 0x1c */
+
+ WERROR PNP_CreateDevInst();
+
+ /******************/
+ /* Function: 0x1d */
+
+ WERROR PNP_DeviceInstanceAction();
+
+ /******************/
+ /* Function: 0x1e */
+
+ WERROR PNP_GetDeviceStatus();
+
+ /******************/
+ /* Function: 0x1f */
+
+ WERROR PNP_SetDeviceProblem();
+
+ /******************/
+ /* Function: 0x20 */
+
+ WERROR PNP_DisableDevInst();
+
+ /******************/
+ /* Function: 0x21 */
+
+ WERROR PNP_UninstallDevInst();
+
+ /******************/
+ /* Function: 0x22 */
+
+ WERROR PNP_AddID();
+
+ /******************/
+ /* Function: 0x23 */
+
+ WERROR PNP_RegisterDriver();
+
+ /******************/
+ /* Function: 0x24 */
+
+ WERROR PNP_QueryRemove();
+
+ /******************/
+ /* Function: 0x25 */
+
+ WERROR PNP_RequestDeviceEject();
+
+ /******************/
+ /* Function: 0x26 */
+
+ WERROR PNP_IsDockStationPresent();
+
+ /******************/
+ /* Function: 0x27 */
+
+ WERROR PNP_RequestEjectPC();
+
+ /******************/
+ /* Function: 0x28 */
+
+ WERROR PNP_HwProfFlags(
+ [in] uint32 unknown1,
+ [in,ref] [string,charset(UTF16)] uint16 *devicepath,
+ [in] uint32 unknown2,
+ [in,out,ref] uint32 *unknown3,
+ [in,out,unique] uint16 *unknown4,
+ [in,unique] [string,charset(UTF16)] uint16 *unknown5,
+ [out,unique] [string,charset(UTF16)] uint16 **unknown5a,
+ [in] uint32 unknown6,
+ [in] uint32 unknown7
+ );
+
+ /******************/
+ /* Function: 0x29 */
+
+ typedef struct {
+ uint32 unknown1;
+ uint16 unknown2[160];
+ uint32 unknown3;
+ } PNP_HwProfInfo;
+
+ WERROR PNP_GetHwProfInfo(
+ [in] uint32 idx,
+ [in,out,ref] PNP_HwProfInfo *info,
+ [in] uint32 unknown1,
+ [in] uint32 unknown2
+ );
+
+ /******************/
+ /* Function: 0x2a */
+
+ WERROR PNP_AddEmptyLogConf();
+
+ /******************/
+ /* Function: 0x2b */
+
+ WERROR PNP_FreeLogConf();
+
+ /******************/
+ /* Function: 0x2c */
+
+ WERROR PNP_GetFirstLogConf();
+
+ /******************/
+ /* Function: 0x2d */
+
+ WERROR PNP_GetNextLogConf();
+
+ /******************/
+ /* Function: 0x2e */
+
+ WERROR PNP_GetLogConfPriority();
+
+ /******************/
+ /* Function: 0x2f */
+
+ WERROR PNP_AddResDes();
+
+ /******************/
+ /* Function: 0x30 */
+
+ WERROR PNP_FreeResDes();
+
+ /******************/
+ /* Function: 0x31 */
+
+ WERROR PNP_GetNextResDes();
+
+ /******************/
+ /* Function: 0x32 */
+
+ WERROR PNP_GetResDesData();
+
+ /******************/
+ /* Function: 0x33 */
+
+ WERROR PNP_GetResDesDataSize();
+
+ /******************/
+ /* Function: 0x34 */
+
+ WERROR PNP_ModifyResDes();
+
+ /******************/
+ /* Function: 0x35 */
+
+ WERROR PNP_DetectResourceLimit();
+
+ /******************/
+ /* Function: 0x36 */
+
+ WERROR PNP_QueryResConfList();
+
+ /******************/
+ /* Function: 0x37 */
+
+ WERROR PNP_SetHwProf();
+
+ /******************/
+ /* Function: 0x38 */
+
+ WERROR PNP_QueryArbitratorFreeData();
+
+ /******************/
+ /* Function: 0x39 */
+
+ WERROR PNP_QueryArbitratorFreeSize();
+
+ /******************/
+ /* Function: 0x3a */
+
+ WERROR PNP_RunDetection();
+
+ /******************/
+ /* Function: 0x3b */
+
+ WERROR PNP_RegisterNotification();
+
+ /******************/
+ /* Function: 0x3c */
+
+ WERROR PNP_UnregisterNotification();
+
+ /******************/
+ /* Function: 0x3d */
+
+ WERROR PNP_GetCustomDevProp();
+
+ /******************/
+ /* Function: 0x3e */
+
+ WERROR PNP_GetVersionInternal();
+
+ /******************/
+ /* Function: 0x3f */
+
+ WERROR PNP_GetBlockedDriverInfo();
+
+ /******************/
+ /* Function: 0x40 */
+
+ WERROR PNP_GetServerSideDeviceInstallFlags();
+}
diff --git a/source3/librpc/idl/samr.idl b/source3/librpc/idl/samr.idl
new file mode 100644
index 0000000000..e823d1d77b
--- /dev/null
+++ b/source3/librpc/idl/samr.idl
@@ -0,0 +1,1430 @@
+#include "idl_types.h"
+
+/*
+ samr interface definition
+*/
+import "misc.idl", "lsa.idl", "security.idl";
+
+/*
+ Thanks to Todd Sabin for some information from his samr.idl in acltools
+*/
+
+[ uuid("12345778-1234-abcd-ef00-0123456789ac"),
+ version(1.0),
+ endpoint("ncacn_np:[\\pipe\\samr]","ncacn_ip_tcp:", "ncalrpc:"),
+ pointer_default(unique)
+] interface samr
+{
+ typedef bitmap security_secinfo security_secinfo;
+
+ /* account control (acct_flags) bits */
+ typedef [public,bitmap32bit] bitmap {
+ ACB_DISABLED = 0x00000001, /* 1 = User account disabled */
+ ACB_HOMDIRREQ = 0x00000002, /* 1 = Home directory required */
+ ACB_PWNOTREQ = 0x00000004, /* 1 = User password not required */
+ ACB_TEMPDUP = 0x00000008, /* 1 = Temporary duplicate account */
+ ACB_NORMAL = 0x00000010, /* 1 = Normal user account */
+ ACB_MNS = 0x00000020, /* 1 = MNS logon user account */
+ ACB_DOMTRUST = 0x00000040, /* 1 = Interdomain trust account */
+ ACB_WSTRUST = 0x00000080, /* 1 = Workstation trust account */
+ ACB_SVRTRUST = 0x00000100, /* 1 = Server trust account */
+ ACB_PWNOEXP = 0x00000200, /* 1 = User password does not expire */
+ ACB_AUTOLOCK = 0x00000400, /* 1 = Account auto locked */
+ ACB_ENC_TXT_PWD_ALLOWED = 0x00000800, /* 1 = Encryped text password is allowed */
+ ACB_SMARTCARD_REQUIRED = 0x00001000, /* 1 = Smart Card required */
+ ACB_TRUSTED_FOR_DELEGATION = 0x00002000, /* 1 = Trusted for Delegation */
+ ACB_NOT_DELEGATED = 0x00004000, /* 1 = Not delegated */
+ ACB_USE_DES_KEY_ONLY = 0x00008000, /* 1 = Use DES key only */
+ ACB_DONT_REQUIRE_PREAUTH = 0x00010000, /* 1 = Preauth not required */
+ ACB_PW_EXPIRED = 0x00020000, /* 1 = Password Expired */
+ ACB_NO_AUTH_DATA_REQD = 0x00080000 /* 1 = No authorization data required */
+ } samr_AcctFlags;
+
+ typedef [bitmap32bit] bitmap {
+ SAMR_ACCESS_CONNECT_TO_SERVER = 0x00000001,
+ SAMR_ACCESS_SHUTDOWN_SERVER = 0x00000002,
+ SAMR_ACCESS_INITIALIZE_SERVER = 0x00000004,
+ SAMR_ACCESS_CREATE_DOMAIN = 0x00000008,
+ SAMR_ACCESS_ENUM_DOMAINS = 0x00000010,
+ SAMR_ACCESS_OPEN_DOMAIN = 0x00000020
+ } samr_ConnectAccessMask;
+
+ typedef [bitmap32bit] bitmap {
+ SAMR_USER_ACCESS_GET_NAME_ETC = 0x00000001,
+ SAMR_USER_ACCESS_GET_LOCALE = 0x00000002,
+ SAMR_USER_ACCESS_SET_LOC_COM = 0x00000004,
+ SAMR_USER_ACCESS_GET_LOGONINFO = 0x00000008,
+ SAMR_USER_ACCESS_GET_ATTRIBUTES = 0x00000010,
+ SAMR_USER_ACCESS_SET_ATTRIBUTES = 0x00000020,
+ SAMR_USER_ACCESS_CHANGE_PASSWORD = 0x00000040,
+ SAMR_USER_ACCESS_SET_PASSWORD = 0x00000080,
+ SAMR_USER_ACCESS_GET_GROUPS = 0x00000100,
+ SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP = 0x00000200,
+ SAMR_USER_ACCESS_CHANGE_GROUP_MEMBERSHIP = 0x00000400
+ } samr_UserAccessMask;
+
+ typedef [bitmap32bit] bitmap {
+ SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 = 0x00000001,
+ SAMR_DOMAIN_ACCESS_SET_INFO_1 = 0x00000002,
+ SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 = 0x00000004,
+ SAMR_DOMAIN_ACCESS_SET_INFO_2 = 0x00000008,
+ SAMR_DOMAIN_ACCESS_CREATE_USER = 0x00000010,
+ SAMR_DOMAIN_ACCESS_CREATE_GROUP = 0x00000020,
+ SAMR_DOMAIN_ACCESS_CREATE_ALIAS = 0x00000040,
+ SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS = 0x00000080,
+ SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS = 0x00000100,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT = 0x00000200,
+ SAMR_DOMAIN_ACCESS_SET_INFO_3 = 0x00000400
+ } samr_DomainAccessMask;
+
+ typedef [bitmap32bit] bitmap {
+ SAMR_GROUP_ACCESS_LOOKUP_INFO = 0x00000001,
+ SAMR_GROUP_ACCESS_SET_INFO = 0x00000002,
+ SAMR_GROUP_ACCESS_ADD_MEMBER = 0x00000004,
+ SAMR_GROUP_ACCESS_REMOVE_MEMBER = 0x00000008,
+ SAMR_GROUP_ACCESS_GET_MEMBERS = 0x00000010
+ } samr_GroupAccessMask;
+
+ typedef [bitmap32bit] bitmap {
+ SAMR_ALIAS_ACCESS_ADD_MEMBER = 0x00000001,
+ SAMR_ALIAS_ACCESS_REMOVE_MEMBER = 0x00000002,
+ SAMR_ALIAS_ACCESS_GET_MEMBERS = 0x00000004,
+ SAMR_ALIAS_ACCESS_LOOKUP_INFO = 0x00000008,
+ SAMR_ALIAS_ACCESS_SET_INFO = 0x00000010
+ } samr_AliasAccessMask;
+
+ /******************/
+ /* Function: 0x00 */
+ NTSTATUS samr_Connect (
+ /* notice the lack of [string] */
+ [in,unique] uint16 *system_name,
+ [in] samr_ConnectAccessMask access_mask,
+ [out,ref] policy_handle *connect_handle
+ );
+
+
+ /******************/
+ /* Function: 0x01 */
+ [public] NTSTATUS samr_Close (
+ [in,out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x02 */
+
+ NTSTATUS samr_SetSecurity (
+ [in,ref] policy_handle *handle,
+ [in] security_secinfo sec_info,
+ [in,ref] sec_desc_buf *sdbuf
+ );
+
+ /******************/
+ /* Function: 0x03 */
+
+ NTSTATUS samr_QuerySecurity (
+ [in,ref] policy_handle *handle,
+ [in] security_secinfo sec_info,
+ [out,ref] sec_desc_buf **sdbuf
+ );
+
+ /******************/
+ /* Function: 0x04 */
+
+ /*
+ shutdown the SAM - once you call this the SAM will be dead
+ */
+ NTSTATUS samr_Shutdown (
+ [in,ref] policy_handle *connect_handle
+ );
+
+ /******************/
+ /* Function: 0x05 */
+ NTSTATUS samr_LookupDomain (
+ [in,ref] policy_handle *connect_handle,
+ [in,ref] lsa_String *domain_name,
+ [out,ref] dom_sid2 **sid
+ );
+
+
+ /******************/
+ /* Function: 0x06 */
+
+ typedef struct {
+ uint32 idx;
+ lsa_String name;
+ } samr_SamEntry;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] samr_SamEntry *entries;
+ } samr_SamArray;
+
+ NTSTATUS samr_EnumDomains (
+ [in] policy_handle *connect_handle,
+ [in,out,ref] uint32 *resume_handle,
+ [out,ref] samr_SamArray **sam,
+ [in] uint32 buf_size,
+ [out,ref] uint32 *num_entries
+ );
+
+
+ /************************/
+ /* Function 0x07 */
+ [public] NTSTATUS samr_OpenDomain(
+ [in,ref] policy_handle *connect_handle,
+ [in] samr_DomainAccessMask access_mask,
+ [in,ref] dom_sid2 *sid,
+ [out,ref] policy_handle *domain_handle
+ );
+
+ /************************/
+ /* Function 0x08 */
+ /* server roles */
+ typedef [v1_enum] enum {
+ SAMR_ROLE_STANDALONE = 0,
+ SAMR_ROLE_DOMAIN_MEMBER = 1,
+ SAMR_ROLE_DOMAIN_BDC = 2,
+ SAMR_ROLE_DOMAIN_PDC = 3
+ } samr_Role;
+
+ /* password properties flags */
+ typedef [public,bitmap32bit] bitmap {
+ DOMAIN_PASSWORD_COMPLEX = 0x00000001,
+ DOMAIN_PASSWORD_NO_ANON_CHANGE = 0x00000002,
+ DOMAIN_PASSWORD_NO_CLEAR_CHANGE = 0x00000004,
+ DOMAIN_PASSWORD_LOCKOUT_ADMINS = 0x00000008,
+ DOMAIN_PASSWORD_STORE_CLEARTEXT = 0x00000010,
+ DOMAIN_REFUSE_PASSWORD_CHANGE = 0x00000020
+ } samr_PasswordProperties;
+
+ typedef struct {
+ uint16 min_password_length;
+ uint16 password_history_length;
+ samr_PasswordProperties password_properties;
+ /* yes, these are signed. They are in negative 100ns */
+ dlong max_password_age;
+ dlong min_password_age;
+ } samr_DomInfo1;
+
+ typedef struct {
+ NTTIME force_logoff_time;
+ lsa_String comment;
+ lsa_String domain_name;
+ lsa_String primary; /* PDC name if this is a BDC */
+ udlong sequence_num;
+ uint32 unknown2;
+ samr_Role role;
+ uint32 unknown3;
+ uint32 num_users;
+ uint32 num_groups;
+ uint32 num_aliases;
+ } samr_DomInfo2;
+
+ typedef struct {
+ NTTIME force_logoff_time;
+ } samr_DomInfo3;
+
+ typedef struct {
+ lsa_String comment;
+ } samr_DomInfo4;
+
+ typedef struct {
+ lsa_String domain_name;
+ } samr_DomInfo5;
+
+ typedef struct {
+ lsa_String primary;
+ } samr_DomInfo6;
+
+ typedef struct {
+ samr_Role role;
+ } samr_DomInfo7;
+
+ typedef struct {
+ hyper sequence_num;
+ NTTIME domain_create_time;
+ } samr_DomInfo8;
+
+ typedef struct {
+ uint32 unknown; /* w2k3 returns 1 */
+ } samr_DomInfo9;
+
+ typedef struct {
+ samr_DomInfo2 info2;
+ hyper lockout_duration;
+ hyper lockout_window;
+ uint16 lockout_threshold;
+ } samr_DomInfo11;
+
+ typedef struct {
+ hyper lockout_duration;
+ hyper lockout_window;
+ uint16 lockout_threshold;
+ } samr_DomInfo12;
+
+ typedef struct {
+ hyper sequence_num;
+ NTTIME domain_create_time;
+ uint32 unknown1;
+ uint32 unknown2;
+ } samr_DomInfo13;
+
+ typedef [switch_type(uint16)] union {
+ [case(1)] samr_DomInfo1 info1;
+ [case(2)] samr_DomInfo2 info2;
+ [case(3)] samr_DomInfo3 info3;
+ [case(4)] samr_DomInfo4 info4;
+ [case(5)] samr_DomInfo5 info5;
+ [case(6)] samr_DomInfo6 info6;
+ [case(7)] samr_DomInfo7 info7;
+ [case(8)] samr_DomInfo8 info8;
+ [case(9)] samr_DomInfo9 info9;
+ [case(11)] samr_DomInfo11 info11;
+ [case(12)] samr_DomInfo12 info12;
+ [case(13)] samr_DomInfo13 info13;
+ } samr_DomainInfo;
+
+ NTSTATUS samr_QueryDomainInfo(
+ [in,ref] policy_handle *domain_handle,
+ [in] uint16 level,
+ [out,ref,switch_is(level)] samr_DomainInfo **info
+ );
+
+ /************************/
+ /* Function 0x09 */
+ /*
+ only levels 1, 3, 4, 6, 7, 9, 12 are valid for this
+ call in w2k3
+ */
+ NTSTATUS samr_SetDomainInfo(
+ [in,ref] policy_handle *domain_handle,
+ [in] uint16 level,
+ [in,switch_is(level),ref] samr_DomainInfo *info
+ );
+
+
+ /************************/
+ /* Function 0x0a */
+ NTSTATUS samr_CreateDomainGroup(
+ [in,ref] policy_handle *domain_handle,
+ [in,ref] lsa_String *name,
+ [in] samr_GroupAccessMask access_mask,
+ [out,ref] policy_handle *group_handle,
+ [out,ref] uint32 *rid
+ );
+
+
+ /************************/
+ /* Function 0x0b */
+
+ const int MAX_SAM_ENTRIES_W2K = 0x400; /* 1024 */
+ const int MAX_SAM_ENTRIES_W95 = 50;
+
+ NTSTATUS samr_EnumDomainGroups(
+ [in] policy_handle *domain_handle,
+ [in,out,ref] uint32 *resume_handle,
+ [out,ref] samr_SamArray **sam,
+ [in] uint32 max_size,
+ [out,ref] uint32 *num_entries
+ );
+
+ /************************/
+ /* Function 0x0c */
+ NTSTATUS samr_CreateUser(
+ [in,ref] policy_handle *domain_handle,
+ [in,ref] lsa_String *account_name,
+ [in] samr_UserAccessMask access_mask,
+ [out,ref] policy_handle *user_handle,
+ [out,ref] uint32 *rid
+ );
+
+ /************************/
+ /* Function 0x0d */
+
+
+ /* w2k3 treats max_size as max_users*54 and sets the
+ resume_handle as the rid of the last user sent
+ */
+ const int SAMR_ENUM_USERS_MULTIPLIER = 54;
+
+ NTSTATUS samr_EnumDomainUsers(
+ [in] policy_handle *domain_handle,
+ [in,out,ref] uint32 *resume_handle,
+ [in] samr_AcctFlags acct_flags,
+ [out,ref] samr_SamArray **sam,
+ [in] uint32 max_size,
+ [out,ref] uint32 *num_entries
+ );
+
+ /************************/
+ /* Function 0x0e */
+ NTSTATUS samr_CreateDomAlias(
+ [in,ref] policy_handle *domain_handle,
+ [in,ref] lsa_String *alias_name,
+ [in] samr_AliasAccessMask access_mask,
+ [out,ref] policy_handle *alias_handle,
+ [out,ref] uint32 *rid
+ );
+
+ /************************/
+ /* Function 0x0f */
+ NTSTATUS samr_EnumDomainAliases(
+ [in] policy_handle *domain_handle,
+ [in,out,ref] uint32 *resume_handle,
+ [out,ref] samr_SamArray **sam,
+ [in] uint32 max_size,
+ [out,ref] uint32 *num_entries
+ );
+
+ /************************/
+ /* Function 0x10 */
+
+ typedef struct {
+ [range(0,1024)] uint32 count;
+ [size_is(count)] uint32 *ids;
+ } samr_Ids;
+
+ NTSTATUS samr_GetAliasMembership(
+ [in,ref] policy_handle *domain_handle,
+ [in,ref] lsa_SidArray *sids,
+ [out,ref] samr_Ids *rids
+ );
+
+ /************************/
+ /* Function 0x11 */
+
+ [public] NTSTATUS samr_LookupNames(
+ [in,ref] policy_handle *domain_handle,
+ [in,range(0,1000)] uint32 num_names,
+ [in,size_is(1000),length_is(num_names)] lsa_String names[],
+ [out,ref] samr_Ids *rids,
+ [out,ref] samr_Ids *types
+ );
+
+
+ /************************/
+ /* Function 0x12 */
+ NTSTATUS samr_LookupRids(
+ [in,ref] policy_handle *domain_handle,
+ [in,range(0,1000)] uint32 num_rids,
+ [in,size_is(1000),length_is(num_rids)] uint32 rids[],
+ [out,ref] lsa_Strings *names,
+ [out,ref] samr_Ids *types
+ );
+
+ /************************/
+ /* Function 0x13 */
+ NTSTATUS samr_OpenGroup(
+ [in,ref] policy_handle *domain_handle,
+ [in] samr_GroupAccessMask access_mask,
+ [in] uint32 rid,
+ [out,ref] policy_handle *group_handle
+ );
+
+ /* Group attributes */
+ typedef [public,bitmap32bit] bitmap {
+ SE_GROUP_MANDATORY = 0x00000001,
+ SE_GROUP_ENABLED_BY_DEFAULT = 0x00000002,
+ SE_GROUP_ENABLED = 0x00000004,
+ SE_GROUP_OWNER = 0x00000008,
+ SE_GROUP_USE_FOR_DENY_ONLY = 0x00000010,
+ SE_GROUP_RESOURCE = 0x20000000,
+ SE_GROUP_LOGON_ID = 0xC0000000
+ } samr_GroupAttrs;
+
+ /************************/
+ /* Function 0x14 */
+
+ typedef struct {
+ lsa_String name;
+ samr_GroupAttrs attributes;
+ uint32 num_members;
+ lsa_String description;
+ } samr_GroupInfoAll;
+
+ typedef struct {
+ samr_GroupAttrs attributes;
+ } samr_GroupInfoAttributes;
+
+ typedef struct {
+ lsa_String description;
+ } samr_GroupInfoDescription;
+
+ typedef enum {
+ GROUPINFOALL = 1,
+ GROUPINFONAME = 2,
+ GROUPINFOATTRIBUTES = 3,
+ GROUPINFODESCRIPTION = 4,
+ GROUPINFOALL2 = 5
+ } samr_GroupInfoEnum;
+
+ typedef [switch_type(samr_GroupInfoEnum)] union {
+ [case(GROUPINFOALL)] samr_GroupInfoAll all;
+ [case(GROUPINFONAME)] lsa_String name;
+ [case(GROUPINFOATTRIBUTES)] samr_GroupInfoAttributes attributes;
+ [case(GROUPINFODESCRIPTION)] lsa_String description;
+ [case(GROUPINFOALL2)] samr_GroupInfoAll all2;
+ } samr_GroupInfo;
+
+ NTSTATUS samr_QueryGroupInfo(
+ [in,ref] policy_handle *group_handle,
+ [in] samr_GroupInfoEnum level,
+ [out,ref,switch_is(level)] samr_GroupInfo **info
+ );
+
+ /************************/
+ /* Function 0x15 */
+ NTSTATUS samr_SetGroupInfo(
+ [in,ref] policy_handle *group_handle,
+ [in] samr_GroupInfoEnum level,
+ [in,switch_is(level),ref] samr_GroupInfo *info
+ );
+
+ /************************/
+ /* Function 0x16 */
+ NTSTATUS samr_AddGroupMember(
+ [in,ref] policy_handle *group_handle,
+ [in] uint32 rid,
+ [in] uint32 flags
+ );
+
+ /************************/
+ /* Function 0x17 */
+ NTSTATUS samr_DeleteDomainGroup(
+ [in,out,ref] policy_handle *group_handle
+ );
+
+ /************************/
+ /* Function 0x18 */
+ NTSTATUS samr_DeleteGroupMember(
+ [in,ref] policy_handle *group_handle,
+ [in] uint32 rid
+ );
+
+
+ /************************/
+ /* Function 0x19 */
+ typedef struct {
+ uint32 count;
+ [size_is(count)] uint32 *rids;
+ [size_is(count)] uint32 *types;
+ } samr_RidTypeArray;
+
+ NTSTATUS samr_QueryGroupMember(
+ [in,ref] policy_handle *group_handle,
+ [out,ref] samr_RidTypeArray **rids
+ );
+
+
+ /************************/
+ /* Function 0x1a */
+
+ /*
+ win2003 seems to accept any data at all for the two integers
+ below, and doesn't seem to do anything with them that I can
+ see. Weird. I really expected the first integer to be a rid
+ and the second to be the attributes for that rid member.
+ */
+ NTSTATUS samr_SetMemberAttributesOfGroup(
+ [in,ref] policy_handle *group_handle,
+ [in] uint32 unknown1,
+ [in] uint32 unknown2
+ );
+
+
+ /************************/
+ /* Function 0x1b */
+ NTSTATUS samr_OpenAlias (
+ [in,ref] policy_handle *domain_handle,
+ [in] samr_AliasAccessMask access_mask,
+ [in] uint32 rid,
+ [out,ref] policy_handle *alias_handle
+ );
+
+
+ /************************/
+ /* Function 0x1c */
+
+ typedef struct {
+ lsa_String name;
+ uint32 num_members;
+ lsa_String description;
+ } samr_AliasInfoAll;
+
+ typedef enum {
+ ALIASINFOALL = 1,
+ ALIASINFONAME = 2,
+ ALIASINFODESCRIPTION = 3
+ } samr_AliasInfoEnum;
+
+ typedef [switch_type(samr_AliasInfoEnum)] union {
+ [case(ALIASINFOALL)] samr_AliasInfoAll all;
+ [case(ALIASINFONAME)] lsa_String name;
+ [case(ALIASINFODESCRIPTION)] lsa_String description;
+ } samr_AliasInfo;
+
+ NTSTATUS samr_QueryAliasInfo(
+ [in,ref] policy_handle *alias_handle,
+ [in] samr_AliasInfoEnum level,
+ [out,ref,switch_is(level)] samr_AliasInfo **info
+ );
+
+ /************************/
+ /* Function 0x1d */
+ NTSTATUS samr_SetAliasInfo(
+ [in,ref] policy_handle *alias_handle,
+ [in] samr_AliasInfoEnum level,
+ [in,switch_is(level),ref] samr_AliasInfo *info
+ );
+
+ /************************/
+ /* Function 0x1e */
+ NTSTATUS samr_DeleteDomAlias(
+ [in,out,ref] policy_handle *alias_handle
+ );
+
+ /************************/
+ /* Function 0x1f */
+ NTSTATUS samr_AddAliasMember(
+ [in,ref] policy_handle *alias_handle,
+ [in,ref] dom_sid2 *sid
+ );
+
+ /************************/
+ /* Function 0x20 */
+ NTSTATUS samr_DeleteAliasMember(
+ [in,ref] policy_handle *alias_handle,
+ [in,ref] dom_sid2 *sid
+ );
+
+ /************************/
+ /* Function 0x21 */
+ NTSTATUS samr_GetMembersInAlias(
+ [in,ref] policy_handle *alias_handle,
+ [out,ref] lsa_SidArray *sids
+ );
+
+ /************************/
+ /* Function 0x22 */
+ [public] NTSTATUS samr_OpenUser(
+ [in,ref] policy_handle *domain_handle,
+ [in] samr_UserAccessMask access_mask,
+ [in] uint32 rid,
+ [out,ref] policy_handle *user_handle
+ );
+
+ /************************/
+ /* Function 0x23 */
+ NTSTATUS samr_DeleteUser(
+ [in,out,ref] policy_handle *user_handle
+ );
+
+ /************************/
+ /* Function 0x24 */
+ typedef struct {
+ lsa_String account_name;
+ lsa_String full_name;
+ uint32 primary_gid;
+ lsa_String description;
+ lsa_String comment;
+ } samr_UserInfo1;
+
+ typedef struct {
+ lsa_String comment;
+ lsa_String unknown; /* settable, but doesn't stick. probably obsolete */
+ uint16 country_code;
+ uint16 code_page;
+ } samr_UserInfo2;
+
+ /* this is also used in samr and netlogon */
+ typedef [public, flag(NDR_PAHEX)] struct {
+ uint16 units_per_week;
+ [size_is(1260), length_is(units_per_week/8)] uint8 *bits;
+ } samr_LogonHours;
+
+ typedef struct {
+ lsa_String account_name;
+ lsa_String full_name;
+ uint32 rid;
+ uint32 primary_gid;
+ lsa_String home_directory;
+ lsa_String home_drive;
+ lsa_String logon_script;
+ lsa_String profile_path;
+ lsa_String workstations;
+ NTTIME last_logon;
+ NTTIME last_logoff;
+ NTTIME last_password_change;
+ NTTIME allow_password_change;
+ NTTIME force_password_change;
+ samr_LogonHours logon_hours;
+ uint16 bad_password_count;
+ uint16 logon_count;
+ samr_AcctFlags acct_flags;
+ } samr_UserInfo3;
+
+ typedef struct {
+ samr_LogonHours logon_hours;
+ } samr_UserInfo4;
+
+ typedef struct {
+ lsa_String account_name;
+ lsa_String full_name;
+ uint32 rid;
+ uint32 primary_gid;
+ lsa_String home_directory;
+ lsa_String home_drive;
+ lsa_String logon_script;
+ lsa_String profile_path;
+ lsa_String description;
+ lsa_String workstations;
+ NTTIME last_logon;
+ NTTIME last_logoff;
+ samr_LogonHours logon_hours;
+ uint16 bad_password_count;
+ uint16 logon_count;
+ NTTIME last_password_change;
+ NTTIME acct_expiry;
+ samr_AcctFlags acct_flags;
+ } samr_UserInfo5;
+
+ typedef struct {
+ lsa_String account_name;
+ lsa_String full_name;
+ } samr_UserInfo6;
+
+ typedef struct {
+ lsa_String account_name;
+ } samr_UserInfo7;
+
+ typedef struct {
+ lsa_String full_name;
+ } samr_UserInfo8;
+
+ typedef struct {
+ uint32 primary_gid;
+ } samr_UserInfo9;
+
+ typedef struct {
+ lsa_String home_directory;
+ lsa_String home_drive;
+ } samr_UserInfo10;
+
+ typedef struct {
+ lsa_String logon_script;
+ } samr_UserInfo11;
+
+ typedef struct {
+ lsa_String profile_path;
+ } samr_UserInfo12;
+
+ typedef struct {
+ lsa_String description;
+ } samr_UserInfo13;
+
+ typedef struct {
+ lsa_String workstations;
+ } samr_UserInfo14;
+
+ typedef struct {
+ samr_AcctFlags acct_flags;
+ } samr_UserInfo16;
+
+ typedef struct {
+ NTTIME acct_expiry;
+ } samr_UserInfo17;
+
+ typedef [public, flag(NDR_PAHEX)] struct {
+ uint8 hash[16];
+ } samr_Password;
+
+ typedef struct {
+ samr_Password lm_pwd;
+ samr_Password nt_pwd;
+ boolean8 lm_pwd_active;
+ boolean8 nt_pwd_active;
+ } samr_UserInfo18;
+
+ typedef struct {
+ lsa_BinaryString parameters;
+ } samr_UserInfo20;
+
+ /* this defines the bits used for fields_present in info21 */
+ typedef [bitmap32bit] bitmap {
+ SAMR_FIELD_ACCOUNT_NAME = 0x00000001,
+ SAMR_FIELD_FULL_NAME = 0x00000002,
+ SAMR_FIELD_RID = 0x00000004,
+ SAMR_FIELD_PRIMARY_GID = 0x00000008,
+ SAMR_FIELD_DESCRIPTION = 0x00000010,
+ SAMR_FIELD_COMMENT = 0x00000020,
+ SAMR_FIELD_HOME_DIRECTORY = 0x00000040,
+ SAMR_FIELD_HOME_DRIVE = 0x00000080,
+ SAMR_FIELD_LOGON_SCRIPT = 0x00000100,
+ SAMR_FIELD_PROFILE_PATH = 0x00000200,
+ SAMR_FIELD_WORKSTATIONS = 0x00000400,
+ SAMR_FIELD_LAST_LOGON = 0x00000800,
+ SAMR_FIELD_LAST_LOGOFF = 0x00001000,
+ SAMR_FIELD_LOGON_HOURS = 0x00002000,
+ SAMR_FIELD_BAD_PWD_COUNT = 0x00004000,
+ SAMR_FIELD_NUM_LOGONS = 0x00008000,
+ SAMR_FIELD_ALLOW_PWD_CHANGE = 0x00010000,
+ SAMR_FIELD_FORCE_PWD_CHANGE = 0x00020000,
+ SAMR_FIELD_LAST_PWD_CHANGE = 0x00040000,
+ SAMR_FIELD_ACCT_EXPIRY = 0x00080000,
+ SAMR_FIELD_ACCT_FLAGS = 0x00100000,
+ SAMR_FIELD_PARAMETERS = 0x00200000,
+ SAMR_FIELD_COUNTRY_CODE = 0x00400000,
+ SAMR_FIELD_CODE_PAGE = 0x00800000,
+ SAMR_FIELD_PASSWORD = 0x01000000, /* either of these */
+ SAMR_FIELD_PASSWORD2 = 0x02000000, /* two bits seems to work */
+ SAMR_FIELD_PRIVATE_DATA = 0x04000000,
+ SAMR_FIELD_EXPIRED_FLAG = 0x08000000,
+ SAMR_FIELD_SEC_DESC = 0x10000000,
+ SAMR_FIELD_OWF_PWD = 0x20000000
+ } samr_FieldsPresent;
+
+ /* used for 'password_expired' in samr_UserInfo21 */
+ const int PASS_MUST_CHANGE_AT_NEXT_LOGON = 0x01;
+ const int PASS_DONT_CHANGE_AT_NEXT_LOGON = 0x00;
+
+ typedef struct {
+ NTTIME last_logon;
+ NTTIME last_logoff;
+ NTTIME last_password_change;
+ NTTIME acct_expiry;
+ NTTIME allow_password_change;
+ NTTIME force_password_change;
+ lsa_String account_name;
+ lsa_String full_name;
+ lsa_String home_directory;
+ lsa_String home_drive;
+ lsa_String logon_script;
+ lsa_String profile_path;
+ lsa_String description;
+ lsa_String workstations;
+ lsa_String comment;
+ lsa_BinaryString parameters;
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ uint32 buf_count;
+ [size_is(buf_count)] uint8 *buffer;
+ uint32 rid;
+ uint32 primary_gid;
+ samr_AcctFlags acct_flags;
+ samr_FieldsPresent fields_present;
+ samr_LogonHours logon_hours;
+ uint16 bad_password_count;
+ uint16 logon_count;
+ uint16 country_code;
+ uint16 code_page;
+ uint8 nt_password_set;
+ uint8 lm_password_set;
+ uint8 password_expired;
+ uint8 unknown4;
+ } samr_UserInfo21;
+
+ typedef [public, flag(NDR_PAHEX)] struct {
+ uint8 data[516];
+ } samr_CryptPassword;
+
+ typedef struct {
+ samr_UserInfo21 info;
+ samr_CryptPassword password;
+ } samr_UserInfo23;
+
+ typedef struct {
+ samr_CryptPassword password;
+ uint8 pw_len;
+ } samr_UserInfo24;
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint8 data[532];
+ } samr_CryptPasswordEx;
+
+ typedef struct {
+ samr_UserInfo21 info;
+ samr_CryptPasswordEx password;
+ } samr_UserInfo25;
+
+ typedef struct {
+ samr_CryptPasswordEx password;
+ uint8 pw_len;
+ } samr_UserInfo26;
+
+ typedef [switch_type(uint16)] union {
+ [case(1)] samr_UserInfo1 info1;
+ [case(2)] samr_UserInfo2 info2;
+ [case(3)] samr_UserInfo3 info3;
+ [case(4)] samr_UserInfo4 info4;
+ [case(5)] samr_UserInfo5 info5;
+ [case(6)] samr_UserInfo6 info6;
+ [case(7)] samr_UserInfo7 info7;
+ [case(8)] samr_UserInfo8 info8;
+ [case(9)] samr_UserInfo9 info9;
+ [case(10)] samr_UserInfo10 info10;
+ [case(11)] samr_UserInfo11 info11;
+ [case(12)] samr_UserInfo12 info12;
+ [case(13)] samr_UserInfo13 info13;
+ [case(14)] samr_UserInfo14 info14;
+ [case(16)] samr_UserInfo16 info16;
+ [case(17)] samr_UserInfo17 info17;
+ [case(18)] samr_UserInfo18 info18;
+ [case(20)] samr_UserInfo20 info20;
+ [case(21)] samr_UserInfo21 info21;
+ [case(23)] samr_UserInfo23 info23;
+ [case(24)] samr_UserInfo24 info24;
+ [case(25)] samr_UserInfo25 info25;
+ [case(26)] samr_UserInfo26 info26;
+ } samr_UserInfo;
+
+ [public] NTSTATUS samr_QueryUserInfo(
+ [in,ref] policy_handle *user_handle,
+ [in] uint16 level,
+ [out,ref,switch_is(level)] samr_UserInfo **info
+ );
+
+
+ /************************/
+ /* Function 0x25 */
+ [public] NTSTATUS samr_SetUserInfo(
+ [in,ref] policy_handle *user_handle,
+ [in] uint16 level,
+ [in,ref,switch_is(level)] samr_UserInfo *info
+ );
+
+ /************************/
+ /* Function 0x26 */
+ /*
+ this is a password change interface that doesn't give
+ the server the plaintext password. Depricated.
+ */
+ NTSTATUS samr_ChangePasswordUser(
+ [in,ref] policy_handle *user_handle,
+ [in] boolean8 lm_present,
+ [in,unique] samr_Password *old_lm_crypted,
+ [in,unique] samr_Password *new_lm_crypted,
+ [in] boolean8 nt_present,
+ [in,unique] samr_Password *old_nt_crypted,
+ [in,unique] samr_Password *new_nt_crypted,
+ [in] boolean8 cross1_present,
+ [in,unique] samr_Password *nt_cross,
+ [in] boolean8 cross2_present,
+ [in,unique] samr_Password *lm_cross
+ );
+
+ /************************/
+ /* Function 0x27 */
+
+ typedef [public] struct {
+ uint32 rid;
+ samr_GroupAttrs attributes;
+ } samr_RidWithAttribute;
+
+ typedef [public] struct {
+ uint32 count;
+ [size_is(count)] samr_RidWithAttribute *rids;
+ } samr_RidWithAttributeArray;
+
+ NTSTATUS samr_GetGroupsForUser(
+ [in,ref] policy_handle *user_handle,
+ [out,ref] samr_RidWithAttributeArray **rids
+ );
+
+ /************************/
+ /* Function 0x28 */
+
+ typedef struct {
+ uint32 idx;
+ uint32 rid;
+ samr_AcctFlags acct_flags;
+ lsa_String account_name;
+ lsa_String description;
+ lsa_String full_name;
+ } samr_DispEntryGeneral;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] samr_DispEntryGeneral *entries;
+ } samr_DispInfoGeneral;
+
+ typedef struct {
+ uint32 idx;
+ uint32 rid;
+ samr_AcctFlags acct_flags;
+ lsa_String account_name;
+ lsa_String description;
+ } samr_DispEntryFull;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] samr_DispEntryFull *entries;
+ } samr_DispInfoFull;
+
+ typedef struct {
+ uint32 idx;
+ uint32 rid;
+ samr_GroupAttrs acct_flags;
+ lsa_String account_name;
+ lsa_String description;
+ } samr_DispEntryFullGroup;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] samr_DispEntryFullGroup *entries;
+ } samr_DispInfoFullGroups;
+
+ typedef struct {
+ uint32 idx;
+ lsa_AsciiStringLarge account_name;
+ } samr_DispEntryAscii;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] samr_DispEntryAscii *entries;
+ } samr_DispInfoAscii;
+
+ typedef [switch_type(uint16)] union {
+ [case(1)] samr_DispInfoGeneral info1;/* users */
+ [case(2)] samr_DispInfoFull info2; /* trust accounts? */
+ [case(3)] samr_DispInfoFullGroups info3; /* groups */
+ [case(4)] samr_DispInfoAscii info4; /* users */
+ [case(5)] samr_DispInfoAscii info5; /* groups */
+ } samr_DispInfo;
+
+ NTSTATUS samr_QueryDisplayInfo(
+ [in,ref] policy_handle *domain_handle,
+ [in] uint16 level,
+ [in] uint32 start_idx,
+ [in] uint32 max_entries,
+ [in] uint32 buf_size,
+ [out,ref] uint32 *total_size,
+ [out,ref] uint32 *returned_size,
+ [out,ref,switch_is(level)] samr_DispInfo *info
+ );
+
+
+ /************************/
+ /* Function 0x29 */
+
+ /*
+ this seems to be an alphabetic search function. The returned index
+ is the index for samr_QueryDisplayInfo needed to get names occurring
+ after the specified name. The supplied name does not need to exist
+ in the database (for example you can supply just a first letter for
+ searching starting at that letter)
+
+ The level corresponds to the samr_QueryDisplayInfo level
+ */
+ NTSTATUS samr_GetDisplayEnumerationIndex(
+ [in,ref] policy_handle *domain_handle,
+ [in] uint16 level,
+ [in,ref] lsa_String *name,
+ [out,ref] uint32 *idx
+ );
+
+
+
+ /************************/
+ /* Function 0x2a */
+
+ /*
+ w2k3 returns NT_STATUS_NOT_IMPLEMENTED for this
+ */
+ NTSTATUS samr_TestPrivateFunctionsDomain(
+ [in,ref] policy_handle *domain_handle
+ );
+
+
+ /************************/
+ /* Function 0x2b */
+
+ /*
+ w2k3 returns NT_STATUS_NOT_IMPLEMENTED for this
+ */
+ NTSTATUS samr_TestPrivateFunctionsUser(
+ [in,ref] policy_handle *user_handle
+ );
+
+
+ /************************/
+ /* Function 0x2c */
+
+ typedef struct {
+ uint16 min_password_length;
+ samr_PasswordProperties password_properties;
+ } samr_PwInfo;
+
+ [public] NTSTATUS samr_GetUserPwInfo(
+ [in,ref] policy_handle *user_handle,
+ [out,ref] samr_PwInfo *info
+ );
+
+ /************************/
+ /* Function 0x2d */
+ NTSTATUS samr_RemoveMemberFromForeignDomain(
+ [in,ref] policy_handle *domain_handle,
+ [in,ref] dom_sid2 *sid
+ );
+
+ /************************/
+ /* Function 0x2e */
+
+ /*
+ how is this different from QueryDomainInfo ??
+ */
+ NTSTATUS samr_QueryDomainInfo2(
+ [in,ref] policy_handle *domain_handle,
+ [in] uint16 level,
+ [out,ref,switch_is(level)] samr_DomainInfo **info
+ );
+
+ /************************/
+ /* Function 0x2f */
+
+ /*
+ how is this different from QueryUserInfo ??
+ */
+ NTSTATUS samr_QueryUserInfo2(
+ [in,ref] policy_handle *user_handle,
+ [in] uint16 level,
+ [out,ref,switch_is(level)] samr_UserInfo *info
+ );
+
+ /************************/
+ /* Function 0x30 */
+
+ /*
+ how is this different from QueryDisplayInfo??
+ */
+ NTSTATUS samr_QueryDisplayInfo2(
+ [in,ref] policy_handle *domain_handle,
+ [in] uint16 level,
+ [in] uint32 start_idx,
+ [in] uint32 max_entries,
+ [in] uint32 buf_size,
+ [out,ref] uint32 *total_size,
+ [out,ref] uint32 *returned_size,
+ [out,ref,switch_is(level)] samr_DispInfo *info
+ );
+
+ /************************/
+ /* Function 0x31 */
+
+ /*
+ how is this different from GetDisplayEnumerationIndex ??
+ */
+ NTSTATUS samr_GetDisplayEnumerationIndex2(
+ [in,ref] policy_handle *domain_handle,
+ [in] uint16 level,
+ [in,ref] lsa_String *name,
+ [out,ref] uint32 *idx
+ );
+
+
+ /************************/
+ /* Function 0x32 */
+ NTSTATUS samr_CreateUser2(
+ [in,ref] policy_handle *domain_handle,
+ [in,ref] lsa_String *account_name,
+ [in] samr_AcctFlags acct_flags,
+ [in] samr_UserAccessMask access_mask,
+ [out,ref] policy_handle *user_handle,
+ [out,ref] uint32 *access_granted,
+ [out,ref] uint32 *rid
+ );
+
+
+ /************************/
+ /* Function 0x33 */
+
+ /*
+ another duplicate. There must be a reason ....
+ */
+ NTSTATUS samr_QueryDisplayInfo3(
+ [in,ref] policy_handle *domain_handle,
+ [in] uint16 level,
+ [in] uint32 start_idx,
+ [in] uint32 max_entries,
+ [in] uint32 buf_size,
+ [out,ref] uint32 *total_size,
+ [out,ref] uint32 *returned_size,
+ [out,ref,switch_is(level)] samr_DispInfo *info
+ );
+
+ /************************/
+ /* Function 0x34 */
+ NTSTATUS samr_AddMultipleMembersToAlias(
+ [in,ref] policy_handle *alias_handle,
+ [in,ref] lsa_SidArray *sids
+ );
+
+ /************************/
+ /* Function 0x35 */
+ NTSTATUS samr_RemoveMultipleMembersFromAlias(
+ [in,ref] policy_handle *alias_handle,
+ [in,ref] lsa_SidArray *sids
+ );
+
+ /************************/
+ /* Function 0x36 */
+
+ NTSTATUS samr_OemChangePasswordUser2(
+ [in,unique] lsa_AsciiString *server,
+ [in,ref] lsa_AsciiString *account,
+ [in,unique] samr_CryptPassword *password,
+ [in,unique] samr_Password *hash
+ );
+
+ /************************/
+ /* Function 0x37 */
+ NTSTATUS samr_ChangePasswordUser2(
+ [in,unique] lsa_String *server,
+ [in,ref] lsa_String *account,
+ [in,unique] samr_CryptPassword *nt_password,
+ [in,unique] samr_Password *nt_verifier,
+ [in] boolean8 lm_change,
+ [in,unique] samr_CryptPassword *lm_password,
+ [in,unique] samr_Password *lm_verifier
+ );
+
+ /************************/
+ /* Function 0x38 */
+ NTSTATUS samr_GetDomPwInfo(
+ [in,unique] lsa_String *domain_name,
+ [out,ref] samr_PwInfo *info
+ );
+
+ /************************/
+ /* Function 0x39 */
+ NTSTATUS samr_Connect2(
+ [in,unique,string,charset(UTF16)] uint16 *system_name,
+ [in] samr_ConnectAccessMask access_mask,
+ [out,ref] policy_handle *connect_handle
+ );
+
+ /************************/
+ /* Function 0x3a */
+ /*
+ seems to be an exact alias for samr_SetUserInfo()
+ */
+ [public] NTSTATUS samr_SetUserInfo2(
+ [in,ref] policy_handle *user_handle,
+ [in] uint16 level,
+ [in,ref,switch_is(level)] samr_UserInfo *info
+ );
+
+ /************************/
+ /* Function 0x3b */
+ /*
+ this one is mysterious. I have a few guesses, but nothing working yet
+ */
+ NTSTATUS samr_SetBootKeyInformation(
+ [in,ref] policy_handle *connect_handle,
+ [in] uint32 unknown1,
+ [in] uint32 unknown2,
+ [in] uint32 unknown3
+ );
+
+ /************************/
+ /* Function 0x3c */
+ NTSTATUS samr_GetBootKeyInformation(
+ [in,ref] policy_handle *domain_handle,
+ [out,ref] uint32 *unknown
+ );
+
+ /************************/
+ /* Function 0x3d */
+ NTSTATUS samr_Connect3(
+ [in,unique,string,charset(UTF16)] uint16 *system_name,
+ /* this unknown value seems to be completely ignored by w2k3 */
+ [in] uint32 unknown,
+ [in] samr_ConnectAccessMask access_mask,
+ [out,ref] policy_handle *connect_handle
+ );
+
+ /************************/
+ /* Function 0x3e */
+
+ typedef enum {
+ SAMR_CONNECT_PRE_W2K = 1,
+ SAMR_CONNECT_W2K = 2,
+ SAMR_CONNECT_AFTER_W2K = 3
+ } samr_ConnectVersion;
+
+ NTSTATUS samr_Connect4(
+ [in,unique,string,charset(UTF16)] uint16 *system_name,
+ [in] samr_ConnectVersion client_version,
+ [in] samr_ConnectAccessMask access_mask,
+ [out,ref] policy_handle *connect_handle
+ );
+
+ /************************/
+ /* Function 0x3f */
+
+ typedef enum samr_RejectReason samr_RejectReason;
+
+ typedef struct {
+ samr_RejectReason reason;
+ uint32 unknown1;
+ uint32 unknown2;
+ } samr_ChangeReject;
+
+ NTSTATUS samr_ChangePasswordUser3(
+ [in,unique] lsa_String *server,
+ [in,ref] lsa_String *account,
+ [in,unique] samr_CryptPassword *nt_password,
+ [in,unique] samr_Password *nt_verifier,
+ [in] boolean8 lm_change,
+ [in,unique] samr_CryptPassword *lm_password,
+ [in,unique] samr_Password *lm_verifier,
+ [in,unique] samr_CryptPassword *password3,
+ [out,ref] samr_DomInfo1 **dominfo,
+ [out,ref] samr_ChangeReject **reject
+ );
+
+ /************************/
+ /* Function 0x40 */
+
+ typedef struct {
+ samr_ConnectVersion client_version; /* w2k3 gives 3 */
+ uint32 unknown2; /* w2k3 gives 0 */
+ } samr_ConnectInfo1;
+
+ typedef union {
+ [case(1)] samr_ConnectInfo1 info1;
+ } samr_ConnectInfo;
+
+ [public] NTSTATUS samr_Connect5(
+ [in,unique,string,charset(UTF16)] uint16 *system_name,
+ [in] samr_ConnectAccessMask access_mask,
+ [in] uint32 level_in,
+ [in,ref,switch_is(level_in)] samr_ConnectInfo *info_in,
+ [out,ref] uint32 *level_out,
+ [out,ref,switch_is(*level_out)] samr_ConnectInfo *info_out,
+ [out,ref] policy_handle *connect_handle
+ );
+
+ /************************/
+ /* Function 0x41 */
+ NTSTATUS samr_RidToSid(
+ [in,ref] policy_handle *domain_handle,
+ [in] uint32 rid,
+ [out,ref] dom_sid2 *sid
+ );
+
+
+ /************************/
+ /* Function 0x42 */
+
+ /*
+ this should set the DSRM password for the server, which is used
+ when booting into Directory Services Recovery Mode on a DC. Win2003
+ gives me NT_STATUS_NOT_SUPPORTED
+ */
+
+ NTSTATUS samr_SetDsrmPassword(
+ [in,unique] lsa_String *name,
+ [in] uint32 unknown,
+ [in,unique] samr_Password *hash
+ );
+
+
+ /************************/
+ /* Function 0x43 */
+ /************************/
+ typedef [bitmap32bit] bitmap {
+ SAMR_VALIDATE_FIELD_PASSWORD_LAST_SET = 0x00000001,
+ SAMR_VALIDATE_FIELD_BAD_PASSWORD_TIME = 0x00000002,
+ SAMR_VALIDATE_FIELD_LOCKOUT_TIME = 0x00000004,
+ SAMR_VALIDATE_FIELD_BAD_PASSWORD_COUNT = 0x00000008,
+ SAMR_VALIDATE_FIELD_PASSWORD_HISTORY_LENGTH = 0x00000010,
+ SAMR_VALIDATE_FIELD_PASSWORD_HISTORY = 0x00000020
+ } samr_ValidateFieldsPresent;
+
+ typedef enum {
+ NetValidateAuthentication = 1,
+ NetValidatePasswordChange= 2,
+ NetValidatePasswordReset = 3
+ } samr_ValidatePasswordLevel;
+
+ /* NetApi maps samr_ValidationStatus errors to WERRORs. Haven't
+ * identified the mapping of
+ * - NERR_PasswordFilterError
+ * - NERR_PasswordExpired and
+ * - NERR_PasswordCantChange
+ * yet - Guenther
+ */
+
+ typedef enum {
+ SAMR_VALIDATION_STATUS_SUCCESS = 0,
+ SAMR_VALIDATION_STATUS_PASSWORD_MUST_CHANGE = 1,
+ SAMR_VALIDATION_STATUS_ACCOUNT_LOCKED_OUT = 2,
+ SAMR_VALIDATION_STATUS_BAD_PASSWORD = 4,
+ SAMR_VALIDATION_STATUS_PWD_HISTORY_CONFLICT = 5,
+ SAMR_VALIDATION_STATUS_PWD_TOO_SHORT = 6,
+ SAMR_VALIDATION_STATUS_PWD_TOO_LONG = 7,
+ SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH = 8,
+ SAMR_VALIDATION_STATUS_PASSWORD_TOO_RECENT = 9
+ } samr_ValidationStatus;
+
+ typedef struct {
+ uint32 length;
+ [size_is(length)] uint8 *data;
+ } samr_ValidationBlob;
+
+ typedef struct {
+ samr_ValidateFieldsPresent fields_present;
+ NTTIME_hyper last_password_change;
+ NTTIME_hyper bad_password_time;
+ NTTIME_hyper lockout_time;
+ uint32 bad_pwd_count;
+ uint32 pwd_history_len;
+ [size_is(pwd_history_len)] samr_ValidationBlob *pwd_history;
+ } samr_ValidatePasswordInfo;
+
+ typedef struct {
+ samr_ValidatePasswordInfo info;
+ samr_ValidationStatus status;
+ } samr_ValidatePasswordRepCtr;
+
+ typedef [switch_type(uint16)] union {
+ [case(1)] samr_ValidatePasswordRepCtr ctr1;
+ [case(2)] samr_ValidatePasswordRepCtr ctr2;
+ [case(3)] samr_ValidatePasswordRepCtr ctr3;
+ } samr_ValidatePasswordRep;
+
+ typedef struct {
+ samr_ValidatePasswordInfo info;
+ lsa_StringLarge password;
+ lsa_StringLarge account;
+ samr_ValidationBlob hash;
+ boolean8 pwd_must_change_at_next_logon;
+ boolean8 clear_lockout;
+ } samr_ValidatePasswordReq3;
+
+ typedef struct {
+ samr_ValidatePasswordInfo info;
+ lsa_StringLarge password;
+ lsa_StringLarge account;
+ samr_ValidationBlob hash;
+ boolean8 password_matched;
+ } samr_ValidatePasswordReq2;
+
+ typedef struct {
+ samr_ValidatePasswordInfo info;
+ boolean8 password_matched;
+ } samr_ValidatePasswordReq1;
+
+ typedef [switch_type(uint16)] union {
+ [case(1)] samr_ValidatePasswordReq1 req1;
+ [case(2)] samr_ValidatePasswordReq2 req2;
+ [case(3)] samr_ValidatePasswordReq3 req3;
+ } samr_ValidatePasswordReq;
+
+ NTSTATUS samr_ValidatePassword(
+ [in] samr_ValidatePasswordLevel level,
+ [in,switch_is(level)] samr_ValidatePasswordReq req,
+ [out,ref,switch_is(level)] samr_ValidatePasswordRep *rep
+ );
+}
diff --git a/source3/librpc/idl/security.idl b/source3/librpc/idl/security.idl
new file mode 100644
index 0000000000..c1dfe272e9
--- /dev/null
+++ b/source3/librpc/idl/security.idl
@@ -0,0 +1,376 @@
+#include "idl_types.h"
+
+/*
+ security IDL structures
+*/
+
+import "misc.idl";
+
+/*
+ use the same structure for dom_sid2 as dom_sid. A dom_sid2 is really
+ just a dom sid, but with the sub_auths represented as a conformant
+ array. As with all in-structure conformant arrays, the array length
+ is placed before the start of the structure. That's what gives rise
+ to the extra num_auths elemenent. We don't want the Samba code to
+ have to bother with such esoteric NDR details, so its easier to just
+ define it as a dom_sid and use pidl magic to make it all work. It
+ just means you need to mark a sid as a "dom_sid2" in the IDL when you
+ know it is of the conformant array variety
+*/
+cpp_quote("#define dom_sid2 dom_sid")
+
+/* same struct as dom_sid but inside a 28 bytes fixed buffer in NDR */
+cpp_quote("#define dom_sid28 dom_sid")
+
+/* same struct as dom_sid but in a variable byte buffer, which is maybe empty in NDR */
+cpp_quote("#define dom_sid0 dom_sid")
+
+[
+ pointer_default(unique)
+]
+interface security
+{
+ /*
+ access masks are divided up like this:
+ 0xabccdddd
+ where
+ a = generic rights bits SEC_GENERIC_
+ b = flags SEC_FLAG_
+ c = standard rights bits SEC_STD_
+ d = object type specific bits SEC_{FILE,DIR,REG,xxx}_
+
+ common combinations of bits are prefixed with SEC_RIGHTS_
+ */
+ const int SEC_MASK_GENERIC = 0xF0000000;
+ const int SEC_MASK_FLAGS = 0x0F000000;
+ const int SEC_MASK_STANDARD = 0x00FF0000;
+ const int SEC_MASK_SPECIFIC = 0x0000FFFF;
+
+ /* generic bits */
+ const int SEC_GENERIC_ALL = 0x10000000;
+ const int SEC_GENERIC_EXECUTE = 0x20000000;
+ const int SEC_GENERIC_WRITE = 0x40000000;
+ const int SEC_GENERIC_READ = 0x80000000;
+
+ /* flag bits */
+ const int SEC_FLAG_SYSTEM_SECURITY = 0x01000000;
+ const int SEC_FLAG_MAXIMUM_ALLOWED = 0x02000000;
+
+ /* standard bits */
+ const int SEC_STD_DELETE = 0x00010000;
+ const int SEC_STD_READ_CONTROL = 0x00020000;
+ const int SEC_STD_WRITE_DAC = 0x00040000;
+ const int SEC_STD_WRITE_OWNER = 0x00080000;
+ const int SEC_STD_SYNCHRONIZE = 0x00100000;
+ const int SEC_STD_REQUIRED = 0x000F0000;
+ const int SEC_STD_ALL = 0x001F0000;
+
+ /* file specific bits */
+ const int SEC_FILE_READ_DATA = 0x00000001;
+ const int SEC_FILE_WRITE_DATA = 0x00000002;
+ const int SEC_FILE_APPEND_DATA = 0x00000004;
+ const int SEC_FILE_READ_EA = 0x00000008;
+ const int SEC_FILE_WRITE_EA = 0x00000010;
+ const int SEC_FILE_EXECUTE = 0x00000020;
+ const int SEC_FILE_READ_ATTRIBUTE = 0x00000080;
+ const int SEC_FILE_WRITE_ATTRIBUTE = 0x00000100;
+ const int SEC_FILE_ALL = 0x000001ff;
+
+ /* directory specific bits */
+ const int SEC_DIR_LIST = 0x00000001;
+ const int SEC_DIR_ADD_FILE = 0x00000002;
+ const int SEC_DIR_ADD_SUBDIR = 0x00000004;
+ const int SEC_DIR_READ_EA = 0x00000008;
+ const int SEC_DIR_WRITE_EA = 0x00000010;
+ const int SEC_DIR_TRAVERSE = 0x00000020;
+ const int SEC_DIR_DELETE_CHILD = 0x00000040;
+ const int SEC_DIR_READ_ATTRIBUTE = 0x00000080;
+ const int SEC_DIR_WRITE_ATTRIBUTE = 0x00000100;
+
+ /* registry entry specific bits */
+ const int SEC_REG_QUERY_VALUE = 0x00000001;
+ const int SEC_REG_SET_VALUE = 0x00000002;
+ const int SEC_REG_CREATE_SUBKEY = 0x00000004;
+ const int SEC_REG_ENUM_SUBKEYS = 0x00000008;
+ const int SEC_REG_NOTIFY = 0x00000010;
+ const int SEC_REG_CREATE_LINK = 0x00000020;
+
+ /* ldap specific access bits */
+ const int SEC_ADS_CREATE_CHILD = 0x00000001;
+ const int SEC_ADS_DELETE_CHILD = 0x00000002;
+ const int SEC_ADS_LIST = 0x00000004;
+ const int SEC_ADS_SELF_WRITE = 0x00000008;
+ const int SEC_ADS_READ_PROP = 0x00000010;
+ const int SEC_ADS_WRITE_PROP = 0x00000020;
+ const int SEC_ADS_DELETE_TREE = 0x00000040;
+ const int SEC_ADS_LIST_OBJECT = 0x00000080;
+ const int SEC_ADS_CONTROL_ACCESS = 0x00000100;
+
+ /* generic->specific mappings for files */
+ const int SEC_RIGHTS_FILE_READ = SEC_STD_READ_CONTROL |
+ SEC_STD_SYNCHRONIZE |
+ SEC_FILE_READ_DATA |
+ SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_READ_EA;
+
+ const int SEC_RIGHTS_FILE_WRITE = SEC_STD_READ_CONTROL |
+ SEC_STD_SYNCHRONIZE |
+ SEC_FILE_WRITE_DATA |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_FILE_WRITE_EA |
+ SEC_FILE_APPEND_DATA;
+
+ const int SEC_RIGHTS_FILE_EXECUTE = SEC_STD_SYNCHRONIZE |
+ SEC_STD_READ_CONTROL |
+ SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_EXECUTE;
+
+ const int SEC_RIGHTS_FILE_ALL = SEC_STD_ALL | SEC_FILE_ALL;
+
+ /* generic->specific mappings for directories (same as files) */
+ const int SEC_RIGHTS_DIR_READ = SEC_RIGHTS_FILE_READ;
+ const int SEC_RIGHTS_DIR_WRITE = SEC_RIGHTS_FILE_WRITE;
+ const int SEC_RIGHTS_DIR_EXECUTE = SEC_RIGHTS_FILE_EXECUTE;
+ const int SEC_RIGHTS_DIR_ALL = SEC_RIGHTS_FILE_ALL;
+
+
+ /***************************************************************/
+ /* WELL KNOWN SIDS */
+
+ /* a NULL sid */
+ const string SID_NULL = "S-1-0-0";
+
+ /* the world domain */
+ const string NAME_WORLD = "WORLD";
+
+ const string SID_WORLD_DOMAIN = "S-1-1";
+ const string SID_WORLD = "S-1-1-0";
+
+ /* SECURITY_CREATOR_SID_AUTHORITY */
+ const string SID_CREATOR_OWNER_DOMAIN = "S-1-3";
+ const string SID_CREATOR_OWNER = "S-1-3-0";
+ const string SID_CREATOR_GROUP = "S-1-3-1";
+
+ /* SECURITY_NT_AUTHORITY */
+ const string NAME_NT_AUTHORITY = "NT AUTHORITY";
+
+ const string SID_NT_AUTHORITY = "S-1-5";
+ const string SID_NT_DIALUP = "S-1-5-1";
+ const string SID_NT_NETWORK = "S-1-5-2";
+ const string SID_NT_BATCH = "S-1-5-3";
+ const string SID_NT_INTERACTIVE = "S-1-5-4";
+ const string SID_NT_SERVICE = "S-1-5-6";
+ const string SID_NT_ANONYMOUS = "S-1-5-7";
+ const string SID_NT_PROXY = "S-1-5-8";
+ const string SID_NT_ENTERPRISE_DCS = "S-1-5-9";
+ const string SID_NT_SELF = "S-1-5-10";
+ const string SID_NT_AUTHENTICATED_USERS = "S-1-5-11";
+ const string SID_NT_RESTRICTED = "S-1-5-12";
+ const string SID_NT_TERMINAL_SERVER_USERS = "S-1-5-13";
+ const string SID_NT_REMOTE_INTERACTIVE = "S-1-5-14";
+ const string SID_NT_THIS_ORGANISATION = "S-1-5-15";
+ const string SID_NT_SYSTEM = "S-1-5-18";
+ const string SID_NT_LOCAL_SERVICE = "S-1-5-19";
+ const string SID_NT_NETWORK_SERVICE = "S-1-5-20";
+
+ /* SECURITY_BUILTIN_DOMAIN_RID */
+ const string NAME_BUILTIN = "BUILTIN";
+
+ const string SID_BUILTIN = "S-1-5-32";
+ const string SID_BUILTIN_ADMINISTRATORS = "S-1-5-32-544";
+ const string SID_BUILTIN_USERS = "S-1-5-32-545";
+ const string SID_BUILTIN_GUESTS = "S-1-5-32-546";
+ const string SID_BUILTIN_POWER_USERS = "S-1-5-32-547";
+ const string SID_BUILTIN_ACCOUNT_OPERATORS = "S-1-5-32-548";
+ const string SID_BUILTIN_SERVER_OPERATORS = "S-1-5-32-549";
+ const string SID_BUILTIN_PRINT_OPERATORS = "S-1-5-32-550";
+ const string SID_BUILTIN_BACKUP_OPERATORS = "S-1-5-32-551";
+ const string SID_BUILTIN_REPLICATOR = "S-1-5-32-552";
+ const string SID_BUILTIN_RAS_SERVERS = "S-1-5-32-553";
+ const string SID_BUILTIN_PREW2K = "S-1-5-32-554";
+
+ /* well-known domain RIDs */
+ const int DOMAIN_RID_LOGON = 9;
+ const int DOMAIN_RID_ADMINISTRATOR = 500;
+ const int DOMAIN_RID_GUEST = 501;
+ const int DOMAIN_RID_ADMINS = 512;
+ const int DOMAIN_RID_USERS = 513;
+ const int DOMAIN_RID_DOMAIN_MEMBERS = 515;
+ const int DOMAIN_RID_DCS = 516;
+ const int DOMAIN_RID_CERT_ADMINS = 517;
+ const int DOMAIN_RID_SCHEMA_ADMINS = 518;
+ const int DOMAIN_RID_ENTERPRISE_ADMINS = 519;
+
+
+ /*
+ privilege IDs. Please keep the IDs below 64. If we get more
+ than 64 then we need to change security_token
+ */
+ typedef enum {
+ SEC_PRIV_SECURITY = 1,
+ SEC_PRIV_BACKUP = 2,
+ SEC_PRIV_RESTORE = 3,
+ SEC_PRIV_SYSTEMTIME = 4,
+ SEC_PRIV_SHUTDOWN = 5,
+ SEC_PRIV_REMOTE_SHUTDOWN = 6,
+ SEC_PRIV_TAKE_OWNERSHIP = 7,
+ SEC_PRIV_DEBUG = 8,
+ SEC_PRIV_SYSTEM_ENVIRONMENT = 9,
+ SEC_PRIV_SYSTEM_PROFILE = 10,
+ SEC_PRIV_PROFILE_SINGLE_PROCESS = 11,
+ SEC_PRIV_INCREASE_BASE_PRIORITY = 12,
+ SEC_PRIV_LOAD_DRIVER = 13,
+ SEC_PRIV_CREATE_PAGEFILE = 14,
+ SEC_PRIV_INCREASE_QUOTA = 15,
+ SEC_PRIV_CHANGE_NOTIFY = 16,
+ SEC_PRIV_UNDOCK = 17,
+ SEC_PRIV_MANAGE_VOLUME = 18,
+ SEC_PRIV_IMPERSONATE = 19,
+ SEC_PRIV_CREATE_GLOBAL = 20,
+ SEC_PRIV_ENABLE_DELEGATION = 21,
+ SEC_PRIV_INTERACTIVE_LOGON = 22,
+ SEC_PRIV_NETWORK_LOGON = 23,
+ SEC_PRIV_REMOTE_INTERACTIVE_LOGON = 24
+ } sec_privilege;
+
+ typedef [bitmap8bit] bitmap {
+ SEC_ACE_FLAG_OBJECT_INHERIT = 0x01,
+ SEC_ACE_FLAG_CONTAINER_INHERIT = 0x02,
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT = 0x04,
+ SEC_ACE_FLAG_INHERIT_ONLY = 0x08,
+ SEC_ACE_FLAG_INHERITED_ACE = 0x10,
+ SEC_ACE_FLAG_VALID_INHERIT = 0x0f,
+ SEC_ACE_FLAG_SUCCESSFUL_ACCESS = 0x40,
+ SEC_ACE_FLAG_FAILED_ACCESS = 0x80
+ } security_ace_flags;
+
+ typedef [enum8bit] enum {
+ SEC_ACE_TYPE_ACCESS_ALLOWED = 0,
+ SEC_ACE_TYPE_ACCESS_DENIED = 1,
+ SEC_ACE_TYPE_SYSTEM_AUDIT = 2,
+ SEC_ACE_TYPE_SYSTEM_ALARM = 3,
+ SEC_ACE_TYPE_ALLOWED_COMPOUND = 4,
+ SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT = 5,
+ SEC_ACE_TYPE_ACCESS_DENIED_OBJECT = 6,
+ SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT = 7,
+ SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT = 8
+ } security_ace_type;
+
+ typedef [bitmap32bit] bitmap {
+ SEC_ACE_OBJECT_TYPE_PRESENT = 0x00000001,
+ SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT = 0x00000002
+ } security_ace_object_flags;
+
+ typedef [nodiscriminant] union {
+ /* this is the 'schemaIDGUID' attribute of the attribute object in the schema naming context */
+ [case(SEC_ACE_OBJECT_TYPE_PRESENT)] GUID type;
+ [default];
+ } security_ace_object_type;
+
+ typedef [nodiscriminant] union {
+ /* this is the 'schemaIDGUID' attribute of the objectclass object in the schema naming context
+ * (of the parent container)
+ */
+ [case(SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT)] GUID inherited_type;
+ [default];
+ } security_ace_object_inherited_type;
+
+ typedef struct {
+ security_ace_object_flags flags;
+ [switch_is(flags & SEC_ACE_OBJECT_TYPE_PRESENT)] security_ace_object_type type;
+ [switch_is(flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT)] security_ace_object_inherited_type inherited_type;
+ } security_ace_object;
+
+ typedef [nodiscriminant] union {
+ [case(SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT)] security_ace_object object;
+ [case(SEC_ACE_TYPE_ACCESS_DENIED_OBJECT)] security_ace_object object;
+ [case(SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT)] security_ace_object object;
+ [case(SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT)] security_ace_object object;
+ [default];
+ } security_ace_object_ctr;
+
+ typedef [public,gensize,nosize] struct {
+ security_ace_type type; /* SEC_ACE_TYPE_* */
+ security_ace_flags flags; /* SEC_ACE_FLAG_* */
+ [value(ndr_size_security_ace(r,ndr->flags))] uint16 size;
+ uint32 access_mask;
+ [switch_is(type)] security_ace_object_ctr object;
+ dom_sid trustee;
+ } security_ace;
+
+ typedef enum {
+ SECURITY_ACL_REVISION_NT4 = 2,
+ SECURITY_ACL_REVISION_ADS = 4
+ } security_acl_revision;
+
+ const uint NT4_ACL_REVISION = SECURITY_ACL_REVISION_NT4;
+
+ typedef [public,gensize,nosize] struct {
+ security_acl_revision revision;
+ [value(ndr_size_security_acl(r,ndr->flags))] uint16 size;
+ [range(0,1000)] uint32 num_aces;
+ security_ace aces[num_aces];
+ } security_acl;
+
+ /* default revision for new ACLs */
+ typedef [enum8bit] enum {
+ SECURITY_DESCRIPTOR_REVISION_1 = 1
+ } security_descriptor_revision;
+
+ const int SD_REVISION = SECURITY_DESCRIPTOR_REVISION_1;
+
+ /* security_descriptor->type bits */
+ typedef [bitmap16bit] bitmap {
+ SEC_DESC_OWNER_DEFAULTED = 0x0001,
+ SEC_DESC_GROUP_DEFAULTED = 0x0002,
+ SEC_DESC_DACL_PRESENT = 0x0004,
+ SEC_DESC_DACL_DEFAULTED = 0x0008,
+ SEC_DESC_SACL_PRESENT = 0x0010,
+ SEC_DESC_SACL_DEFAULTED = 0x0020,
+ SEC_DESC_DACL_TRUSTED = 0x0040,
+ SEC_DESC_SERVER_SECURITY = 0x0080,
+ SEC_DESC_DACL_AUTO_INHERIT_REQ = 0x0100,
+ SEC_DESC_SACL_AUTO_INHERIT_REQ = 0x0200,
+ SEC_DESC_DACL_AUTO_INHERITED = 0x0400,
+ SEC_DESC_SACL_AUTO_INHERITED = 0x0800,
+ SEC_DESC_DACL_PROTECTED = 0x1000,
+ SEC_DESC_SACL_PROTECTED = 0x2000,
+ SEC_DESC_RM_CONTROL_VALID = 0x4000,
+ SEC_DESC_SELF_RELATIVE = 0x8000
+ } security_descriptor_type;
+
+ typedef [gensize,nosize,public,flag(NDR_LITTLE_ENDIAN)] struct {
+ security_descriptor_revision revision;
+ security_descriptor_type type; /* SEC_DESC_xxxx flags */
+ [relative] dom_sid *owner_sid;
+ [relative] dom_sid *group_sid;
+ [relative] security_acl *sacl; /* system ACL */
+ [relative] security_acl *dacl; /* user (discretionary) ACL */
+ } security_descriptor;
+
+ typedef [public] struct {
+ [range(0,0x40000),value(ndr_size_security_descriptor(sd,ndr->flags))] uint32 sd_size;
+ [subcontext(4)] security_descriptor *sd;
+ } sec_desc_buf;
+
+ typedef [public] struct {
+ dom_sid *user_sid;
+ dom_sid *group_sid;
+ uint32 num_sids;
+ [size_is(num_sids)] dom_sid *sids[*];
+ udlong privilege_mask;
+ } security_token;
+
+ /* bits that determine which parts of a security descriptor
+ are being queried/set */
+ typedef [public,bitmap32bit] bitmap {
+ SECINFO_OWNER = 0x00000001,
+ SECINFO_GROUP = 0x00000002,
+ SECINFO_DACL = 0x00000004,
+ SECINFO_SACL = 0x00000008,
+ SECINFO_UNPROTECTED_SACL = 0x10000000,
+ SECINFO_UNPROTECTED_DACL = 0x20000000,
+ SECINFO_PROTECTED_SACL = 0x40000000,
+ SECINFO_PROTECTED_DACL = 0x80000000
+ } security_secinfo;
+}
diff --git a/source3/librpc/idl/spoolss.idl b/source3/librpc/idl/spoolss.idl
new file mode 100644
index 0000000000..2144393ebd
--- /dev/null
+++ b/source3/librpc/idl/spoolss.idl
@@ -0,0 +1,1571 @@
+#include "idl_types.h"
+
+/*
+ spoolss interface definitions
+*/
+import "security.idl", "winreg.idl";
+
+[ uuid("12345678-1234-abcd-ef00-0123456789ab"),
+ version(1.0),
+ endpoint("ncacn_np:[\\pipe\\spoolss]"),
+ pointer_default(unique),
+ helpstring("Spooler SubSystem"),
+ helper("librpc/ndr/ndr_spoolss_buf.h")
+] interface spoolss
+{
+ typedef [v1_enum] enum winreg_Type winreg_Type;
+ typedef struct {
+ uint16 year;
+ uint16 month;
+ uint16 day_of_week;
+ uint16 day;
+ uint16 hour;
+ uint16 minute;
+ uint16 second;
+ uint16 millisecond;
+ } spoolss_Time;
+
+ typedef struct {
+ [relative] nstring *printername;
+ [relative] nstring *servername;
+ uint32 cjobs;
+ uint32 total_jobs;
+ uint32 total_bytes;
+ spoolss_Time time;
+ uint32 global_counter;
+ uint32 total_pages;
+ uint32 version;
+ uint32 unknown10;
+ uint32 unknown11;
+ uint32 unknown12;
+ uint32 session_counter;
+ uint32 unknown14;
+ uint32 printer_errors;
+ uint32 unknown16;
+ uint32 unknown17;
+ uint32 unknown18;
+ uint32 unknown19;
+ uint32 change_id;
+ uint32 unknown21;
+ uint32 status;
+ uint32 unknown23;
+ uint32 c_setprinter;
+ uint16 unknown25;
+ uint16 unknown26;
+ uint32 unknown27;
+ uint32 unknown28;
+ uint32 unknown29;
+ } spoolss_PrinterInfo0;
+
+ typedef [public,gensize] struct {
+ [charset(UTF16)] uint16 devicename[32];
+ uint16 specversion;
+ uint16 driverversion;
+ uint16 size;
+ [value(r->driverextra_data.length)] uint16 __driverextra_length;
+ uint32 fields;
+ uint16 orientation;
+ uint16 papersize;
+ uint16 paperlength;
+ uint16 paperwidth;
+ uint16 scale;
+ uint16 copies;
+ uint16 defaultsource;
+ uint16 printquality;
+ uint16 color;
+ uint16 duplex;
+ uint16 yresolution;
+ uint16 ttoption;
+ uint16 collate;
+ [charset(UTF16)] uint16 formname[32];
+ uint16 logpixels;
+ uint32 bitsperpel;
+ uint32 pelswidth;
+ uint32 pelsheight;
+ uint32 displayflags;
+ uint32 displayfrequency;
+ uint32 icmmethod;
+ uint32 icmintent;
+ uint32 mediatype;
+ uint32 dithertype;
+ uint32 reserved1;
+ uint32 reserved2;
+ uint32 panningwidth;
+ uint32 panningheight;
+ [subcontext_size(__driverextra_length),subcontext(0),flag(NDR_REMAINING)] DATA_BLOB driverextra_data;
+ } spoolss_DeviceMode;
+
+ typedef [public] bitmap {
+ PRINTER_ENUM_DEFAULT = 0x00000001,
+ PRINTER_ENUM_LOCAL = 0x00000002,
+ PRINTER_ENUM_CONNECTIONS = 0x00000004,
+ PRINTER_ENUM_FAVORITE = 0x00000004,
+ PRINTER_ENUM_NAME = 0x00000008,
+ PRINTER_ENUM_REMOTE = 0x00000010,
+ PRINTER_ENUM_SHARED = 0x00000020,
+ PRINTER_ENUM_NETWORK = 0x00000040,
+ PRINTER_ENUM_EXPAND = 0x00004000,
+ PRINTER_ENUM_CONTAINER = 0x00008000,
+ PRINTER_ENUM_ICON1 = 0x00010000,
+ PRINTER_ENUM_ICON2 = 0x00020000,
+ PRINTER_ENUM_ICON3 = 0x00040000,
+ PRINTER_ENUM_ICON4 = 0x00080000,
+ PRINTER_ENUM_ICON5 = 0x00100000,
+ PRINTER_ENUM_ICON6 = 0x00200000,
+ PRINTER_ENUM_ICON7 = 0x00400000,
+ PRINTER_ENUM_ICON8 = 0x00800000,
+ PRINTER_ENUM_HIDE = 0x01000000
+ } spoolss_EnumPrinterFlags;
+
+ typedef struct {
+ spoolss_EnumPrinterFlags flags;
+ [relative] nstring *name;
+ [relative] nstring *description;
+ [relative] nstring *comment;
+ } spoolss_PrinterInfo1;
+
+ typedef bitmap {
+ PRINTER_ATTRIBUTE_QUEUED = 0x00000001,
+ PRINTER_ATTRIBUTE_DIRECT = 0x00000002,
+ PRINTER_ATTRIBUTE_DEFAULT = 0x00000004,
+ PRINTER_ATTRIBUTE_SHARED = 0x00000008,
+ PRINTER_ATTRIBUTE_NETWORK = 0x00000010,
+ PRINTER_ATTRIBUTE_HIDDEN = 0x00000020,
+ PRINTER_ATTRIBUTE_LOCAL = 0x00000040,
+ PRINTER_ATTRIBUTE_ENABLE_DEVQ = 0x00000080,
+ PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS = 0x00000100,
+ PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST = 0x00000200,
+ PRINTER_ATTRIBUTE_WORK_OFFLINE = 0x00000400,
+ PRINTER_ATTRIBUTE_ENABLE_BIDI = 0x00000800,
+ PRINTER_ATTRIBUTE_RAW_ONLY = 0x00001000,
+ PRINTER_ATTRIBUTE_PUBLISHED = 0x00002000,
+ PRINTER_ATTRIBUTE_FAX = 0x00004000,
+ PRINTER_ATTRIBUTE_TS = 0x00008000
+ } spoolss_PrinterAttributes;
+
+ typedef bitmap {
+ PRINTER_STATUS_PAUSED = 0x00000001,
+ PRINTER_STATUS_ERROR = 0x00000002,
+ PRINTER_STATUS_PENDING_DELETION = 0x00000004,
+ PRINTER_STATUS_PAPER_JAM = 0x00000008,
+ PRINTER_STATUS_PAPER_OUT = 0x00000010,
+ PRINTER_STATUS_MANUAL_FEED = 0x00000020,
+ PRINTER_STATUS_PAPER_PROBLEM = 0x00000040,
+ PRINTER_STATUS_OFFLINE = 0x00000080,
+ PRINTER_STATUS_IO_ACTIVE = 0x00000100,
+ PRINTER_STATUS_BUSY = 0x00000200,
+ PRINTER_STATUS_PRINTING = 0x00000400,
+ PRINTER_STATUS_OUTPUT_BIN_FULL = 0x00000800,
+ PRINTER_STATUS_NOT_AVAILABLE = 0x00001000,
+ PRINTER_STATUS_WAITING = 0x00002000,
+ PRINTER_STATUS_PROCESSING = 0x00004000,
+ PRINTER_STATUS_INITIALIZING = 0x00008000,
+ PRINTER_STATUS_WARMING_UP = 0x00010000,
+ PRINTER_STATUS_TONER_LOW = 0x00020000,
+ PRINTER_STATUS_NO_TONER = 0x00040000,
+ PRINTER_STATUS_PAGE_PUNT = 0x00080000,
+ PRINTER_STATUS_USER_INTERVENTION= 0x00100000,
+ PRINTER_STATUS_OUT_OF_MEMORY = 0x00200000,
+ PRINTER_STATUS_DOOR_OPEN = 0x00400000,
+ PRINTER_STATUS_SERVER_UNKNOWN = 0x00800000,
+ PRINTER_STATUS_POWER_SAVE = 0x01000000
+ } spoolss_PrinterStatus;
+
+ typedef struct {
+ [relative] nstring *servername;
+ [relative] nstring *printername;
+ [relative] nstring *sharename;
+ [relative] nstring *portname;
+ [relative] nstring *drivername;
+ [relative] nstring *comment;
+ [relative] nstring *location;
+ [relative,subcontext(0)] spoolss_DeviceMode *devmode;
+ [relative] nstring *sepfile;
+ [relative] nstring *printprocessor;
+ [relative] nstring *datatype;
+ [relative] nstring *parameters;
+ [relative,subcontext(0)] security_descriptor *secdesc;
+ spoolss_PrinterAttributes attributes;
+ uint32 priority;
+ uint32 defaultpriority;
+ uint32 starttime;
+ uint32 untiltime;
+ spoolss_PrinterStatus status;
+ uint32 cjobs;
+ uint32 averageppm;
+ } spoolss_PrinterInfo2;
+
+ typedef struct {
+ [relative,subcontext(0)] security_descriptor *secdesc;
+ } spoolss_PrinterInfo3;
+
+ typedef struct {
+ [relative] nstring *printername;
+ [relative] nstring *servername;
+ spoolss_PrinterAttributes attributes;
+ } spoolss_PrinterInfo4;
+
+ typedef struct {
+ [relative] nstring *printername;
+ [relative] nstring *portname;
+ spoolss_PrinterAttributes attributes;
+ uint32 device_not_selected_timeout;
+ uint32 transmission_retry_timeout;
+ } spoolss_PrinterInfo5;
+
+ typedef struct {
+ spoolss_PrinterStatus status;
+ } spoolss_PrinterInfo6;
+
+ typedef bitmap {
+ DSPRINT_PUBLISH = 0x00000001,
+ DSPRINT_UPDATE = 0x00000002,
+ DSPRINT_UNPUBLISH = 0x00000004,
+ DSPRINT_REPUBLISH = 0x00000008,
+ DSPRINT_PENDING = 0x80000000
+ } spoolss_DsPrintAction;
+
+ typedef struct {
+ [relative] nstring *guid; /* text form of printer guid */
+ spoolss_DsPrintAction action;
+ } spoolss_PrinterInfo7;
+
+ typedef struct {
+ [relative,subcontext(0)] spoolss_DeviceMode *devmode;
+ } spoolss_DeviceModeInfo;
+
+ typedef [nodiscriminant,relative_base,public] union {
+ [case(0)] spoolss_PrinterInfo0 info0;
+ [case(1)] spoolss_PrinterInfo1 info1;
+ [case(2)] spoolss_PrinterInfo2 info2;
+ [case(3)] spoolss_PrinterInfo3 info3;
+ [case(4)] spoolss_PrinterInfo4 info4;
+ [case(5)] spoolss_PrinterInfo5 info5;
+ [case(6)] spoolss_PrinterInfo6 info6;
+ [case(7)] spoolss_PrinterInfo7 info7;
+ [case(8)] spoolss_DeviceModeInfo info8;
+ [case(9)] spoolss_DeviceModeInfo info9;
+ [default];
+ } spoolss_PrinterInfo;
+
+ /******************/
+ /* Function: 0x00 */
+ /* we are using this as internal parsing code */
+ [public,noopnum,noprint] WERROR _spoolss_EnumPrinters(
+ [in] spoolss_EnumPrinterFlags flags,
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique] DATA_BLOB *info,
+ [out] uint32 needed,
+ [out] uint32 count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumPrinters(
+ [in] uint32 level,
+ [in] uint32 count,
+ [out,switch_is(level)] spoolss_PrinterInfo info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumPrinters(
+ [in] spoolss_EnumPrinterFlags flags,
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ /* what we have here is a subcontext containing an array of no discriminant unions
+ * and the array has no size in front
+ */
+ [out,unique,switch_is(level),size_is(count)] spoolss_PrinterInfo *info,
+ [out] uint32 needed,
+ [out] uint32 count
+ );
+
+ /******************/
+ /* Function: 0x01 */
+ typedef struct {
+ [value(_ndr_size_spoolss_DeviceMode(devmode, ndr->flags))] uint32 _ndr_size;
+ [subcontext(4),subcontext_size(_ndr_size)] spoolss_DeviceMode *devmode;
+ } spoolss_DevmodeContainer;
+
+ [public] WERROR spoolss_OpenPrinter(
+ [in,unique] [string,charset(UTF16)] uint16 *printername,
+ [in,unique] [string,charset(UTF16)] uint16 *datatype,
+ [in] spoolss_DevmodeContainer devmode_ctr,
+ [in] uint32 access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x02 */
+ typedef struct {
+ uint32 job_id;
+ [relative] nstring *printer_name;
+ [relative] nstring *server_name;
+ [relative] nstring *user_name;
+ [relative] nstring *document_name;
+ [relative] nstring *data_type;
+ [relative] nstring *text_status;
+ uint32 status;
+ uint32 priority;
+ uint32 position;
+ uint32 total_pages;
+ uint32 pages_printed;
+ spoolss_Time time;
+ } spoolss_JobInfo1;
+
+ typedef [nodiscriminant,relative_base,public] union {
+ [case(1)] spoolss_JobInfo1 info1;
+ [case(2)]; /* TODO */
+ [case(3)]; /* TODO */
+ [default];
+ } spoolss_JobInfo;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] spoolss_JobInfo info;
+ } spoolss_JobInfoContainer;
+
+ typedef [v1_enum] enum {
+ SPOOLSS_JOB_CONTROL_PAUSE = 1,
+ SPOOLSS_JOB_CONTROL_RESUME = 2,
+ SPOOLSS_JOB_CONTROL_CANCEL = 3,
+ SPOOLSS_JOB_CONTROL_RESTART = 4,
+ SPOOLSS_JOB_CONTROL_DELETE = 5,
+ SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER = 6,
+ SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED = 7
+ } spoolss_JobControl;
+
+ WERROR spoolss_SetJob(
+ [in,ref] policy_handle *handle,
+ [in] uint32 job_id,
+ [in,unique] spoolss_JobInfoContainer *ctr,
+ [in] spoolss_JobControl command
+ );
+
+ /******************/
+ /* Function: 0x03 */
+ WERROR spoolss_GetJob(
+ [in,ref] policy_handle *handle,
+ [in] uint32 job_id,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique,subcontext(4),subcontext_size(offered),switch_is(level)] spoolss_JobInfo *info,
+ [out] uint32 needed
+ );
+
+ /******************/
+ /* Function: 0x04 */
+ [public,noopnum,noprint] WERROR _spoolss_EnumJobs(
+ [in,ref] policy_handle *handle,
+ [in] uint32 firstjob,
+ [in] uint32 numjobs,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique] DATA_BLOB *info,
+ [out] uint32 needed,
+ [out] uint32 count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumJobs(
+ [in] uint32 level,
+ [in] uint32 count,
+ [out,switch_is(level)] spoolss_JobInfo info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumJobs(
+ [in,ref] policy_handle *handle,
+ [in] uint32 firstjob,
+ [in] uint32 numjobs,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique,switch_is(level),size_is(count)] spoolss_JobInfo *info,
+ [out] uint32 needed,
+ [out] uint32 count
+ );
+
+ /******************/
+ /* Function: 0x05 */
+ WERROR spoolss_AddPrinter(
+ /* This function is not implemented in Samba 3 as no
+ clients have been observed using it. */
+ );
+
+ /******************/
+ /* Function: 0x06 */
+ WERROR spoolss_DeletePrinter(
+ );
+
+ /******************/
+ /* Function: 0x07 */
+ typedef [v1_enum] enum {
+ SPOOLSS_PRINTER_CONTROL_UNPAUSE = 0,
+ SPOOLSS_PRINTER_CONTROL_PAUSE = 1,
+ SPOOLSS_PRINTER_CONTROL_RESUME = 2,
+ SPOOLSS_PRINTER_CONTROL_PURGE = 3,
+ SPOOLSS_PRINTER_CONTROL_SET_STATUS = 4
+ } spoolss_PrinterControl;
+
+ typedef [switch_type(uint32)] union {
+ [case(0)] spoolss_PrinterInfo0 *info0;
+ [case(1)] spoolss_PrinterInfo1 *info1;
+ [case(2)] spoolss_PrinterInfo2 *info2;
+ [case(3)] spoolss_PrinterInfo3 *info3;
+ [case(4)] spoolss_PrinterInfo4 *info4;
+ [case(5)] spoolss_PrinterInfo5 *info5;
+ [case(6)] spoolss_PrinterInfo6 *info6;
+ [case(7)] spoolss_PrinterInfo7 *info7;
+ [case(8)] spoolss_DeviceModeInfo *info8;
+ [case(9)] spoolss_DeviceModeInfo *info9;
+ [default];
+ } spoolss_SetPrinterInfo;
+
+ WERROR spoolss_SetPrinter(
+ [in,ref] policy_handle *handle,
+ [in] uint32 level,
+ [in,switch_is(level)] spoolss_SetPrinterInfo info,
+ [in] spoolss_DevmodeContainer devmode_ctr,
+ [in] sec_desc_buf secdesc_ctr,
+ [in] spoolss_PrinterControl command
+ );
+
+ /******************/
+ /* Function: 0x08 */
+ [public] WERROR spoolss_GetPrinter(
+ [in,ref] policy_handle *handle,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique,subcontext(4),subcontext_size(offered),switch_is(level)] spoolss_PrinterInfo *info,
+ [out] uint32 needed
+ );
+
+ /******************/
+ /* Function: 0x09 */
+ WERROR spoolss_AddPrinterDriver(
+ );
+
+ typedef struct {
+ [relative] nstring *driver_name;
+ } spoolss_DriverInfo1;
+
+ typedef [v1_enum] enum {
+ SPOOLSS_DRIVER_VERSION_9X = 0,
+ SPOOLSS_DRIVER_VERSION_NT35 = 1,
+ SPOOLSS_DRIVER_VERSION_NT4 = 2,
+ SPOOLSS_DRIVER_VERSION_200X = 3
+ } spoolss_DriverOSVersion;
+
+ typedef struct {
+ spoolss_DriverOSVersion version;
+ [relative] nstring *driver_name;
+ [relative] nstring *architecture;
+ [relative] nstring *driver_path;
+ [relative] nstring *data_file;
+ [relative] nstring *config_file;
+ } spoolss_DriverInfo2;
+
+ typedef struct {
+ spoolss_DriverOSVersion version;
+ [relative] nstring *driver_name;
+ [relative] nstring *architecture;
+ [relative] nstring *driver_path;
+ [relative] nstring *data_file;
+ [relative] nstring *config_file;
+ [relative] nstring *help_file;
+ [relative] nstring_array *dependent_files;
+ [relative] nstring *monitor_name;
+ [relative] nstring *default_datatype;
+ } spoolss_DriverInfo3;
+
+ typedef struct {
+ spoolss_DriverOSVersion version;
+ [relative] nstring *driver_name;
+ [relative] nstring *architecture;
+ [relative] nstring *driver_path;
+ [relative] nstring *data_file;
+ [relative] nstring *config_file;
+ [relative] nstring *help_file;
+ [relative] nstring_array *dependent_files;
+ [relative] nstring *monitor_name;
+ [relative] nstring *default_datatype;
+ [relative] nstring_array *previous_names;
+ } spoolss_DriverInfo4;
+
+ typedef struct {
+ spoolss_DriverOSVersion version;
+ [relative] nstring *driver_name;
+ [relative] nstring *architecture;
+ [relative] nstring *driver_path;
+ [relative] nstring *data_file;
+ [relative] nstring *config_file;
+ uint32 driver_attributes;
+ uint32 config_version;
+ uint32 driver_version;
+ } spoolss_DriverInfo5;
+
+ typedef struct {
+ spoolss_DriverOSVersion version;
+ [relative] nstring *driver_name;
+ [relative] nstring *architecture;
+ [relative] nstring *driver_path;
+ [relative] nstring *data_file;
+ [relative] nstring *config_file;
+ [relative] nstring *help_file;
+ [relative] nstring_array *dependent_files;
+ [relative] nstring *monitor_name;
+ [relative] nstring *default_datatype;
+ [relative] nstring_array *previous_names;
+ NTTIME driver_data;
+ hyper driver_version;
+ [relative] nstring *manufacturer_name;
+ [relative] nstring *manufacturer_url;
+ [relative] nstring *hardware_id;
+ [relative] nstring *provider;
+ } spoolss_DriverInfo6;
+
+ typedef [nodiscriminant,relative_base,public] union {
+ [case(1)] spoolss_DriverInfo1 info1;
+ [case(2)] spoolss_DriverInfo2 info2;
+ [case(3)] spoolss_DriverInfo3 info3;
+ [case(4)] spoolss_DriverInfo4 info4;
+ [case(5)] spoolss_DriverInfo5 info5;
+ [case(6)] spoolss_DriverInfo6 info6;
+ [default];
+ } spoolss_DriverInfo;
+
+ /******************/
+ /* Function: 0x0a */
+ [public,noopnum,noprint] WERROR _spoolss_EnumPrinterDrivers(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in,unique] [string,charset(UTF16)] uint16 *environment,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique] DATA_BLOB *info,
+ [out] uint32 needed,
+ [out] uint32 count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumPrinterDrivers(
+ [in] uint32 level,
+ [in] uint32 count,
+ [out,switch_is(level)] spoolss_DriverInfo info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumPrinterDrivers(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in,unique] [string,charset(UTF16)] uint16 *environment,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique,switch_is(level),size_is(count)] spoolss_DriverInfo *info,
+ [out] uint32 needed,
+ [out] uint32 count
+ );
+
+ /******************/
+ /* Function: 0x0b */
+ WERROR spoolss_GetPrinterDriver(
+ );
+
+ /******************/
+ /* Function: 0x0c */
+ typedef struct {
+ nstring directory_name;
+ } spoolss_DriverDirectoryInfo1;
+
+ /* NOTE: it's seems that w2k3 completly ignores the level
+ in its server code
+ */
+ typedef [nodiscriminant,relative_base,gensize,public] union {
+ [case(1)] spoolss_DriverDirectoryInfo1 info1;
+ [default] spoolss_DriverDirectoryInfo1 info1;
+ } spoolss_DriverDirectoryInfo;
+
+ [public] WERROR spoolss_GetPrinterDriverDirectory(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in,unique] [string,charset(UTF16)] uint16 *environment,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique,subcontext(4),subcontext_size(offered),switch_is(level)] spoolss_DriverDirectoryInfo *info,
+ [out] uint32 needed
+ );
+
+ /******************/
+ /* Function: 0x0d */
+ WERROR spoolss_DeletePrinterDriver(
+ [in,ref] policy_handle *handle,
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in] [string,charset(UTF16)] uint16 architecture[],
+ [in] [string,charset(UTF16)] uint16 driver[]
+ );
+
+ /******************/
+ /* Function: 0x0e */
+ WERROR spoolss_AddPrintProcessor(
+ );
+
+ /******************/
+ /* Function: 0x0f */
+ typedef struct {
+ [relative] nstring *print_processor_name;
+ } spoolss_PrintProcessorInfo1;
+
+ typedef [nodiscriminant,relative_base,public] union {
+ [case(1)] spoolss_PrintProcessorInfo1 info1;
+ [default];
+ } spoolss_PrintProcessorInfo;
+
+ [public,noopnum,noprint] WERROR _spoolss_EnumPrintProcessors(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,unique] [string,charset(UTF16)] uint16 *environment,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique] DATA_BLOB *info,
+ [out] uint32 needed,
+ [out] uint32 count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumPrintProcessors(
+ [in] uint32 level,
+ [in] uint32 count,
+ [out,switch_is(level)] spoolss_PrintProcessorInfo info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumPrintProcessors(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,unique] [string,charset(UTF16)] uint16 *environment,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique,switch_is(level),size_is(count)] spoolss_PrintProcessorInfo *info,
+ [out] uint32 needed,
+ [out] uint32 count
+ );
+
+ /******************/
+ /* Function: 0x10 */
+ WERROR spoolss_GetPrintProcessorDirectory(
+ );
+
+ /******************/
+ /* Function: 0x11 */
+ typedef struct {
+ [string,charset(UTF16)] uint16 *document_name;
+ [string,charset(UTF16)] uint16 *output_file;
+ [string,charset(UTF16)] uint16 *datatype;
+ } spoolss_DocumentInfo1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] spoolss_DocumentInfo1 *info1;
+ [case(2)]; /* TODO */
+ [case(3)]; /* TODO */
+ [default];
+ } spoolss_DocumentInfo;
+
+ WERROR spoolss_StartDocPrinter(
+ [in,ref] policy_handle *handle,
+ [in] uint32 level,
+ [in,switch_is(level)] spoolss_DocumentInfo info,
+ [out] uint32 job_id
+ );
+
+ /******************/
+ /* Function: 0x12 */
+ WERROR spoolss_StartPagePrinter(
+ [in,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x13 */
+ WERROR spoolss_WritePrinter(
+ [in,ref] policy_handle *handle,
+ [in] DATA_BLOB data,
+ [in,value(r->in.data.length)] uint32 _data_size,
+ [out] uint32 num_written
+ );
+
+ /******************/
+ /* Function: 0x14 */
+ WERROR spoolss_EndPagePrinter(
+ [in,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x15 */
+ WERROR spoolss_AbortPrinter(
+ [in,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x16 */
+ WERROR spoolss_ReadPrinter(
+ [in,ref] policy_handle *handle,
+ [in] uint32 data_size,
+ [out] DATA_BLOB data,
+ [out,value(r->out.data.length)] uint32 _data_size
+ );
+
+ /******************/
+ /* Function: 0x17 */
+ WERROR spoolss_EndDocPrinter(
+ [in,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x18 */
+ WERROR spoolss_AddJob(
+ );
+
+ /******************/
+ /* Function: 0x19 */
+ WERROR spoolss_ScheduleJob(
+ );
+
+ /******************/
+ /* Function: 0x1a */
+ const string SPOOLSS_ARCHITECTURE_NT_X86 = "Windows NT x86";
+
+ typedef [public,gensize] struct {
+ [value(ndr_size_spoolss_OSVersion(r,ndr->flags))] uint32 _ndr_size;
+ uint32 major;
+ uint32 minor;
+ uint32 build;
+ [value(2)] uint32 unknown;
+ [subcontext(0),subcontext_size(256)] nstring extra_string;
+ } spoolss_OSVersion;
+
+ typedef [public,gensize] struct {
+ [value(ndr_size_spoolss_OSVersionEx(r,ndr->flags))] uint32 _ndr_size;
+ uint32 major;
+ uint32 minor;
+ uint32 build;
+ [value(2)] uint32 unknown1;
+ [subcontext(0),subcontext_size(256)] nstring extra_string;
+ uint32 unknown2;/* service pack number? I saw 0 from w2k3 and 1 from winxp sp1*/
+ uint32 unknown3;/* hmm? w2k3: 131346(0x20112) winxp sp1: 503382272 0x1E010100 */
+ } spoolss_OSVersionEx;
+
+ typedef [v1_enum] enum {
+ SPOOLSS_PRINTER_DATA_TYPE_NULL = 0,
+ SPOOLSS_PRINTER_DATA_TYPE_STRING = 1,
+ SPOOLSS_PRINTER_DATA_TYPE_BINARY = 3,
+ SPOOLSS_PRINTER_DATA_TYPE_UINT32 = 4,
+ SPOOLSS_PRINTER_DATA_TYPE_STRING_ARRAY = 7
+ } spoolss_PrinterDataType;
+
+ typedef [nodiscriminant,public,gensize] union {
+ [case(SPOOLSS_PRINTER_DATA_TYPE_NULL)];
+ [case(SPOOLSS_PRINTER_DATA_TYPE_STRING)] nstring string;
+ [case(SPOOLSS_PRINTER_DATA_TYPE_BINARY),flag(NDR_REMAINING)] DATA_BLOB binary;
+ [case(SPOOLSS_PRINTER_DATA_TYPE_UINT32)] uint32 value;
+ [case(SPOOLSS_PRINTER_DATA_TYPE_STRING_ARRAY)] nstring_array string_array;
+ [default,flag(NDR_REMAINING)] DATA_BLOB data;
+ } spoolss_PrinterData;
+
+ [noopnum,noprint,public] WERROR _spoolss_GetPrinterData(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 value_name[],
+ [in] uint32 offered,
+ [out] spoolss_PrinterDataType type,
+ [out] DATA_BLOB data,
+ [out] uint32 needed
+ );
+ [noopnum,noprint,public] void __spoolss_GetPrinterData(
+ [in] spoolss_PrinterDataType type,
+ [out,switch_is(type)] spoolss_PrinterData data
+ );
+ [nopull,nopush,public] WERROR spoolss_GetPrinterData(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 value_name[],
+ [in] uint32 offered,
+ [out] spoolss_PrinterDataType type,
+ [out,subcontext(4),subcontext_size(offered),switch_is(type)] spoolss_PrinterData data,
+ [out] uint32 needed
+ );
+
+ /******************/
+ /* Function: 0x1b */
+ [noopnum,nopull,noprint,public] WERROR _spoolss_SetPrinterData(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 value_name[],
+ [in] spoolss_PrinterDataType type,
+ [in] DATA_BLOB data,
+ [in] uint32 _offered
+ );
+ [noopnum,nopull,noprint,public] void __spoolss_SetPrinterData(
+ [in] spoolss_PrinterDataType type,
+ [out,switch_is(type)] spoolss_PrinterData data
+ );
+ [nopush] WERROR spoolss_SetPrinterData(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 value_name[],
+ [in] spoolss_PrinterDataType type,
+ [in,subcontext(4),switch_is(type)] spoolss_PrinterData data,
+ [in,value(ndr_size_spoolss_PrinterData(&data,type,flags))] uint32 _offered
+ );
+
+ /******************/
+ /* Function: 0x1c */
+ WERROR spoolss_WaitForPrinterChange(
+ );
+
+ /******************/
+ /* Function: 0x1d */
+ [public] WERROR spoolss_ClosePrinter(
+ [in,out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x1e */
+ typedef [v1_enum] enum {
+ SPOOLSS_FORM_USER = 0,
+ SPOOLSS_FORM_BUILTIN = 1,
+ SPOOLSS_FORM_PRINTER = 2
+ } spoolss_FormFlags;
+
+ typedef struct {
+ uint32 width;
+ uint32 height;
+ } spoolss_FormSize;
+
+ typedef struct {
+ uint32 left;
+ uint32 top;
+ uint32 right;
+ uint32 bottom;
+ } spoolss_FormArea;
+
+ typedef struct {
+ spoolss_FormFlags flags;
+ [relative] nstring *form_name;
+ spoolss_FormSize size;
+ spoolss_FormArea area;
+ } spoolss_FormInfo1;
+
+ typedef [nodiscriminant,relative_base,public,gensize] union {
+ [case(1)] spoolss_FormInfo1 info1;
+ [default];
+ } spoolss_FormInfo;
+
+ typedef struct {
+ spoolss_FormFlags flags;
+ [string,charset(UTF16)] uint16 *form_name;
+ spoolss_FormSize size;
+ spoolss_FormArea area;
+ } spoolss_AddFormInfo1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] spoolss_AddFormInfo1 *info1;
+ } spoolss_AddFormInfo;
+
+ WERROR spoolss_AddForm(
+ [in,ref] policy_handle *handle,
+ [in] uint32 level,
+ [in,switch_is(level)] spoolss_AddFormInfo info
+ );
+
+ /******************/
+ /* Function: 0x1f */
+ WERROR spoolss_DeleteForm(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 form_name[]
+ );
+
+ /******************/
+ /* Function: 0x20 */
+ WERROR spoolss_GetForm(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 form_name[],
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique,subcontext(4),subcontext_size(offered),switch_is(level)] spoolss_FormInfo *info,
+ [out] uint32 needed
+ );
+
+ /******************/
+ /* Function: 0x21 */
+ WERROR spoolss_SetForm(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 form_name[],
+ [in] uint32 level,
+ [in,switch_is(level)] spoolss_AddFormInfo info
+ );
+
+ /******************/
+ /* Function: 0x22 */
+ [public,noopnum,noprint] WERROR _spoolss_EnumForms(
+ [in,ref] policy_handle *handle,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique] DATA_BLOB *info,
+ [out] uint32 needed,
+ [out] uint32 count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumForms(
+ [in] uint32 level,
+ [in] uint32 count,
+ [out,switch_is(level)] spoolss_FormInfo info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumForms(
+ [in,ref] policy_handle *handle,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique,switch_is(level),size_is(count)] spoolss_FormInfo *info,
+ [out] uint32 needed,
+ [out] uint32 count
+ );
+
+ typedef struct {
+ [relative] nstring *port_name;
+ } spoolss_PortInfo1;
+
+ typedef bitmap {
+ SPOOLSS_PORT_TYPE_WRITE = 0x00000001,
+ SPOOLSS_PORT_TYPE_READ = 0x00000002,
+ SPOOLSS_PORT_TYPE_REDIRECTED = 0x00000004,
+ SPOOLSS_PORT_TYPE_NET_ATTACHED = 0x00000008
+ } spoolss_PortType;
+
+ typedef struct {
+ [relative] nstring *port_name;
+ [relative] nstring *monitor_name;
+ [relative] nstring *description;
+ spoolss_PortType port_type;
+ uint32 reserved;
+ } spoolss_PortInfo2;
+
+ typedef [nodiscriminant,relative_base,public] union {
+ [case(1)] spoolss_PortInfo1 info1;
+ [case(2)] spoolss_PortInfo2 info2;
+ [case(3)]; /* TODO */
+ [default];
+ } spoolss_PortInfo;
+
+ /******************/
+ /* Function: 0x23 */
+ [public,noopnum,noprint] WERROR _spoolss_EnumPorts(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique] DATA_BLOB *info,
+ [out] uint32 needed,
+ [out] uint32 count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumPorts(
+ [in] uint32 level,
+ [in] uint32 count,
+ [out,switch_is(level)] spoolss_PortInfo info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumPorts(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique,switch_is(level),size_is(count)] spoolss_PortInfo *info,
+ [out] uint32 needed,
+ [out] uint32 count
+ );
+
+ /******************/
+ /* Function: 0x24 */
+ typedef struct {
+ [relative] nstring *monitor_name;
+ } spoolss_MonitorInfo1;
+
+ typedef struct {
+ [relative] nstring *monitor_name;
+ [relative] nstring *environment;
+ [relative] nstring *dll_name;
+ } spoolss_MonitorInfo2;
+
+ typedef [nodiscriminant,relative_base,public] union {
+ [case(1)] spoolss_MonitorInfo1 info1;
+ [case(2)] spoolss_MonitorInfo2 info2;
+ [default];
+ } spoolss_MonitorInfo;
+
+ [public,noopnum,noprint] WERROR _spoolss_EnumMonitors(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique] DATA_BLOB *info,
+ [out] uint32 needed,
+ [out] uint32 count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumMonitors(
+ [in] uint32 level,
+ [in] uint32 count,
+ [out,switch_is(level)] spoolss_MonitorInfo info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumMonitors(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique,switch_is(level),size_is(count)] spoolss_MonitorInfo *info,
+ [out] uint32 needed,
+ [out] uint32 count
+ );
+
+ /******************/
+ /* Function: 0x25 */
+ WERROR spoolss_AddPort(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] uint32 unknown,
+ [in] [string,charset(UTF16)] uint16 monitor_name[]
+ );
+
+ /******************/
+ /* Function: 0x26 */
+ WERROR spoolss_ConfigurePort(
+ );
+
+ /******************/
+ /* Function: 0x27 */
+ WERROR spoolss_DeletePort(
+ );
+
+ /******************/
+ /* Function: 0x28 */
+ WERROR spoolss_CreatePrinterIC(
+ );
+
+ /******************/
+ /* Function: 0x29 */
+ WERROR spoolss_PlayGDIScriptOnPrinterIC(
+ );
+
+ /******************/
+ /* Function: 0x2a */
+ WERROR spoolss_DeletePrinterIC(
+ );
+
+ /******************/
+ /* Function: 0x2b */
+ WERROR spoolss_AddPrinterConnection(
+ );
+
+ /******************/
+ /* Function: 0x2c */
+ WERROR spoolss_DeletePrinterConnection(
+ );
+
+ /******************/
+ /* Function: 0x2d */
+ WERROR spoolss_PrinterMessageBox(
+ /* Marked as obsolete in MSDN. "Not necessary and has
+ no effect". */
+ );
+
+ /******************/
+ /* Function: 0x2e */
+ WERROR spoolss_AddMonitor(
+ );
+
+ /******************/
+ /* Function: 0x2f */
+ WERROR spoolss_DeleteMonitor(
+ );
+
+ /******************/
+ /* Function: 0x30 */
+ WERROR spoolss_DeletePrintProcessor(
+ );
+
+ /******************/
+ /* Function: 0x31 */
+ WERROR spoolss_AddPrintProvidor(
+ );
+
+ /******************/
+ /* Function: 0x32 */
+ WERROR spoolss_DeletePrintProvidor(
+ );
+
+ /******************/
+ /* Function: 0x33 */
+ WERROR spoolss_EnumPrintProcDataTypes(
+ );
+
+ /******************/
+ /* Function: 0x34 */
+ WERROR spoolss_ResetPrinter(
+ );
+
+ /******************/
+ /* Function: 0x35 */
+ WERROR spoolss_GetPrinterDriver2(
+ [in,ref] policy_handle *handle,
+ [in,unique] [string,charset(UTF16)] uint16 *architecture,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [in] uint32 client_major_version,
+ [in] uint32 client_minor_version,
+ [out,unique] DATA_BLOB *info,
+ [out] uint32 needed,
+ [out] uint32 server_major_version,
+ [out] uint32 server_minor_version
+ );
+
+ /******************/
+ /* Function: 0x36 */
+ WERROR spoolss_FindFirstPrinterChangeNotification(
+ );
+
+ /******************/
+ /* Function: 0x37 */
+ WERROR spoolss_FindNextPrinterChangeNotification(
+ );
+
+ /******************/
+ /* Function: 0x38 */
+ [public] WERROR spoolss_FindClosePrinterNotify(
+ [in,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x39 */
+ WERROR spoolss_RouterFindFirstPrinterChangeNotificationOld(
+ );
+
+ /******************/
+ /* Function: 0x3a */
+ [public] WERROR spoolss_ReplyOpenPrinter(
+ [in,string,charset(UTF16)] uint16 server_name[],
+ [in] uint32 printer_local,
+ [in] winreg_Type type,
+ [in] uint32 unknown1,
+ [in] uint32 unknown2,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x3b */
+ WERROR spoolss_RouterReplyPrinter(
+ );
+
+ /******************/
+ /* Function: 0x3c */
+ [public] WERROR spoolss_ReplyClosePrinter(
+ [in,out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x3d */
+ WERROR spoolss_AddPortEx(
+ );
+
+ /******************/
+ /* Function: 0x3e */
+ WERROR spoolss_RouterFindFirstPrinterChangeNotification(
+ );
+
+ /******************/
+ /* Function: 0x3f */
+ WERROR spoolss_SpoolerInit(
+ );
+
+ /******************/
+ /* Function: 0x40 */
+ WERROR spoolss_ResetPrinterEx(
+ );
+
+ typedef [enum16bit] enum {
+ SPOOLSS_FIELD_SERVER_NAME = 0,
+ SPOOLSS_FIELD_PRINTER_NAME = 1,
+ SPOOLSS_FIELD_SHARE_NAME = 2,
+ SPOOLSS_FIELD_PORT_NAME = 3,
+ SPOOLSS_FIELD_DRIVER_NAME = 4,
+ SPOOLSS_FIELD_COMMENT = 5,
+ SPOOLSS_FIELD_LOCATION = 6,
+ SPOOLSS_FIELD_DEVMODE = 7,
+ SPOOLSS_FIELD_SEPFILE = 8,
+ SPOOLSS_FIELD_PRINT_PROCESSOR = 9,
+ SPOOLSS_FIELD_PARAMETERS = 10,
+ SPOOLSS_FIELD_DATATYPE = 11,
+ SPOOLSS_FIELD_SECURITY_DESCRIPTOR=12,
+ SPOOLSS_FIELD_ATTRIBUTES = 13,
+ SPOOLSS_FIELD_PRIORITY = 14,
+ SPOOLSS_FIELD_DEFAULT_PRIORITY = 15,
+ SPOOLSS_FIELD_START_TIME = 16,
+ SPOOLSS_FIELD_UNTIL_TIME = 17,
+ SPOOLSS_FIELD_STATUS = 18,
+ SPOOLSS_FIELD_STATUS_STRING = 19,
+ SPOOLSS_FIELD_CJOBS = 20,
+ SPOOLSS_FIELD_AVERAGE_PPM = 21,
+ SPOOLSS_FIELD_TOTAL_PAGES = 22,
+ SPOOLSS_FIELD_PAGES_PRINTED = 23,
+ SPOOLSS_FIELD_TOTAL_BYTES = 24,
+ SPOOLSS_FIELD_BYTES_PRINTED = 25
+ } spoolss_Field;
+
+ typedef [enum16bit] enum {
+ SPOOLSS_NOTIFY_PRINTER = 0,
+ SPOOLSS_NOTIFY_JOB = 1
+ } spoolss_NotifyType;
+
+ /******************/
+ /* Function: 0x41 */
+ typedef struct {
+ spoolss_NotifyType type;
+ uint16 u1;
+ uint32 u2;
+ uint32 u3;
+ uint32 count;
+ [size_is(count)] spoolss_Field *fields;
+ } spoolss_NotifyOptionsArray;
+
+ typedef struct {
+ uint32 version;
+ uint32 flags;
+ uint32 count;
+ [size_is(count)] spoolss_NotifyOptionsArray *options;
+ } spoolss_NotifyOptionsContainer;
+
+ [public] WERROR spoolss_RemoteFindFirstPrinterChangeNotifyEx(
+ [in,ref] policy_handle *handle,
+ [in] uint32 flags,
+ [in] uint32 options,
+ [in,unique] [string,charset(UTF16)] uint16 *str,
+ [in] uint32 printer_local,
+ [in,unique] spoolss_NotifyOptionsContainer *t1
+ );
+
+ /******************/
+ /* Function: 0x42 */
+ WERROR spoolss_RouterRefreshPrinterChangeNotification(
+ );
+
+ typedef struct {
+ uint32 size;
+ [size_is(size/2),unique,charset(UTF16)] uint16 *string;
+ } spoolss_NotifyUTF16String;
+
+ typedef struct {
+ uint32 size;
+ [size_is(size),charset(DOS)] uint8 *string;
+ } spoolss_NotifyDOSString;
+
+ typedef struct {
+ uint16 data[8];
+ } spoolss_NotifyBlobData;
+
+ typedef struct {
+ uint32 len;
+ [unique] spoolss_NotifyBlobData *data;
+ } spoolss_NotifyBlob;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] dlong integer;
+ [case(2)] spoolss_NotifyUTF16String utf16_string;
+ [case(3)] spoolss_NotifyDOSString ascii_string;
+ [case(4)] spoolss_NotifyBlob blob;
+ [case(5)] spoolss_NotifyDOSString ascii_string;
+ } spoolss_NotifyData;
+
+ typedef struct {
+ spoolss_NotifyType type;
+ spoolss_Field field;
+ uint32 variable_type;
+ uint32 job_id;
+ [switch_is(variable_type)] spoolss_NotifyData data;
+ } spoolss_Notify;
+
+ typedef struct {
+ uint32 version;
+ uint32 flags;
+ uint32 count;
+ [size_is(count)] spoolss_Notify notifies[];
+ } spoolss_NotifyInfo;
+
+ /******************/
+ /* Function: 0x43 */
+ [public] WERROR spoolss_RemoteFindNextPrinterChangeNotifyEx(
+ [in,ref] policy_handle *handle,
+ [in] uint32 change_low,
+ [in,unique] spoolss_NotifyOptionsContainer *container,
+ [out, unique] spoolss_NotifyInfo *info
+ );
+
+ /******************/
+ /* Function: 0x44 */
+ WERROR spoolss_44(
+ );
+
+ typedef struct {
+ uint32 size;
+ [string,charset(UTF16)] uint16 *client;
+ [string,charset(UTF16)] uint16 *user;
+ uint32 build;
+ uint32 major;
+ uint32 minor;
+ uint32 processor;
+ } spoolss_UserLevel1;
+
+ typedef union {
+ [case(1)] spoolss_UserLevel1 *level1;
+ } spoolss_UserLevel;
+
+ typedef bitmap {
+ SERVER_ACCESS_ADMINISTER = 0x00000001,
+ SERVER_ACCESS_ENUMERATE = 0x00000002,
+ PRINTER_ACCESS_ADMINISTER = 0x00000004,
+ PRINTER_ACCESS_USE = 0x00000008,
+ JOB_ACCESS_ADMINISTER = 0x00000010
+ } spoolss_AccessRights;
+
+ /* Access rights for print servers */
+ const int SERVER_ALL_ACCESS = SEC_STD_REQUIRED |
+ SERVER_ACCESS_ADMINISTER |
+ SERVER_ACCESS_ENUMERATE;
+
+ const int SERVER_READ = SEC_STD_READ_CONTROL |
+ SERVER_ACCESS_ENUMERATE;
+
+ const int SERVER_WRITE = STANDARD_RIGHTS_WRITE_ACCESS |
+ SERVER_ACCESS_ADMINISTER |
+ SERVER_ACCESS_ENUMERATE;
+
+ const int SERVER_EXECUTE = SEC_STD_READ_CONTROL |
+ SERVER_ACCESS_ENUMERATE;
+
+ /* Access rights for printers */
+ const int PRINTER_ALL_ACCESS = SEC_STD_REQUIRED |
+ PRINTER_ACCESS_ADMINISTER |
+ PRINTER_ACCESS_USE;
+
+ const int PRINTER_READ = SEC_STD_READ_CONTROL |
+ PRINTER_ACCESS_USE;
+
+ const int PRINTER_WRITE = STANDARD_RIGHTS_WRITE_ACCESS |
+ PRINTER_ACCESS_USE;
+
+ const int PRINTER_EXECUTE = SEC_STD_READ_CONTROL |
+ PRINTER_ACCESS_USE;
+
+ /* Access rights for jobs */
+ const int JOB_ALL_ACCESS = SEC_STD_REQUIRED |
+ JOB_ACCESS_ADMINISTER;
+
+ const int JOB_READ = SEC_STD_READ_CONTROL |
+ JOB_ACCESS_ADMINISTER;
+
+ const int JOB_WRITE = STANDARD_RIGHTS_WRITE_ACCESS |
+ JOB_ACCESS_ADMINISTER;
+
+ const int JOB_EXECUTE = SEC_STD_READ_CONTROL |
+ JOB_ACCESS_ADMINISTER;
+
+ /* ACE masks for various print permissions */
+ const int PRINTER_ACE_FULL_CONTROL = SEC_GENERIC_ALL |
+ PRINTER_ALL_ACCESS;
+
+ const int PRINTER_ACE_MANAGE_DOCUMENTS = SEC_GENERIC_ALL |
+ READ_CONTROL_ACCESS;
+
+ const int PRINTER_ACE_PRINT = GENERIC_EXECUTE_ACCESS |
+ READ_CONTROL_ACCESS |
+ PRINTER_ACCESS_USE;
+
+ /******************/
+ /* Function: 0x45 */
+ [public] WERROR spoolss_OpenPrinterEx(
+ [in,unique] [string,charset(UTF16)] uint16 *printername,
+ [in,unique] [string,charset(UTF16)] uint16 *datatype,
+ [in] spoolss_DevmodeContainer devmode_ctr,
+ [in] uint32 access_mask,
+ [in] uint32 level,
+ [in,switch_is(level)] spoolss_UserLevel userlevel,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x46 */
+ WERROR spoolss_AddPrinterEx(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in] uint32 level,
+ [in,unique,switch_is(level)] spoolss_PrinterInfo *info,
+ [in] spoolss_DevmodeContainer devmode_ctr,
+ [in,unique] security_descriptor *secdesc,
+ [in] uint32 ulevel,
+ [in,switch_is(ulevel)] spoolss_UserLevel userlevel
+ );
+
+ /******************/
+ /* Function: 0x47 */
+ WERROR spoolss_47(
+ );
+
+ /******************/
+ /* Function: 0x48 */
+ WERROR spoolss_EnumPrinterData(
+ [in,ref] policy_handle *handle,
+ [in] uint32 enum_index,
+ [out,ref,size_is(value_offered/2),charset(UTF16)] uint16 *value_name,
+ [in] uint32 value_offered,
+ [out,ref] uint32 *value_needed,
+ [out,ref] uint32 *printerdata_type,
+ [out,ref] DATA_BLOB *buffer,
+ [in] uint32 data_offered,
+ [out,ref] uint32 *data_needed
+ );
+
+ /******************/
+ /* Function: 0x49 */
+ WERROR spoolss_DeletePrinterData(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 value_name[]
+ );
+
+ /******************/
+ /* Function: 0x4a */
+ WERROR spoolss_4a(
+ );
+
+ /******************/
+ /* Function: 0x4b */
+ WERROR spoolss_4b(
+ );
+
+ /******************/
+ /* Function: 0x4c */
+ WERROR spoolss_4c(
+ );
+
+ /******************/
+ /* Function: 0x4d */
+ WERROR spoolss_SetPrinterDataEx(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 key_name[],
+ [in] [string,charset(UTF16)] uint16 value_name[],
+ [in] uint32 type,
+ [in] DATA_BLOB buffer,
+ [in] uint32 offered
+ );
+
+ /******************/
+ /* Function: 0x4e */
+ WERROR spoolss_GetPrinterDataEx(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 key_name[],
+ [in] [string,charset(UTF16)] uint16 value_name[],
+ [in] uint32 offered,
+ [out] uint32 type,
+ [out] DATA_BLOB buffer,
+ [out] uint32 needed
+ );
+
+ /******************/
+ /* Function: 0x4f */
+ [public] WERROR spoolss_EnumPrinterDataEx(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 key_name[],
+ [in] uint32 offered,
+ [out] DATA_BLOB buffer,
+ [out] uint32 needed,
+ [out] uint32 count
+ );
+
+ /******************/
+ /* Function: 0x50 */
+ [public] WERROR spoolss_EnumPrinterKey(
+ [in, ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 key_name[],
+ [out] uint32 key_buffer_size,
+ [out] uint16 key_buffer[key_buffer_size],
+ [in,out] uint32 needed
+ );
+
+ /******************/
+ /* Function: 0x51 */
+ WERROR spoolss_DeletePrinterDataEx(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 key_name[],
+ [in] [string,charset(UTF16)] uint16 value_name[]
+ );
+
+ /******************/
+ /* Function: 0x52 */
+ WERROR spoolss_DeletePrinterKey(
+ );
+
+ /******************/
+ /* Function: 0x53 */
+ WERROR spoolss_53(
+ );
+
+ /******************/
+ /* Function: 0x54 */
+ WERROR spoolss_DeletePrinterDriverEx(
+ );
+
+ /******************/
+ /* Function: 0x55 */
+ WERROR spoolss_55(
+ );
+
+ /******************/
+ /* Function: 0x56 */
+ WERROR spoolss_56(
+ );
+
+ /******************/
+ /* Function: 0x57 */
+ WERROR spoolss_57(
+ );
+
+ /******************/
+ /* Function: 0x58 */
+ WERROR spoolss_XcvData(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 function_name[],
+ [in] DATA_BLOB in_data,
+ [in,value(r->in.in_data.length)] uint32 _in_data_length,
+ [in] uint32 offered,
+ [in] uint32 unknown1,
+ [out] DATA_BLOB out_data,
+ [out] uint32 needed,
+ [out] uint32 unknown2
+ );
+
+ /******************/
+ /* Function: 0x59 */
+ [public] WERROR spoolss_AddPrinterDriverEx(
+ );
+
+ /******************/
+ /* Function: 0x5a */
+ WERROR spoolss_5a(
+ );
+
+ /******************/
+ /* Function: 0x5b */
+ WERROR spoolss_5b(
+ );
+
+ /******************/
+ /* Function: 0x5c */
+ WERROR spoolss_5c(
+ );
+
+ /******************/
+ /* Function: 0x5d */
+ WERROR spoolss_5d(
+ );
+
+ /******************/
+ /* Function: 0x5e */
+ WERROR spoolss_5e(
+ );
+
+ /******************/
+ /* Function: 0x5f */
+ WERROR spoolss_5f(
+ );
+}
diff --git a/source3/librpc/idl/srvsvc.idl b/source3/librpc/idl/srvsvc.idl
new file mode 100644
index 0000000000..0bbd24a5dd
--- /dev/null
+++ b/source3/librpc/idl/srvsvc.idl
@@ -0,0 +1,1525 @@
+#include "idl_types.h"
+
+/*
+ srvsvc interface definitions
+*/
+
+import "security.idl", "svcctl.idl";
+
+[ uuid("4b324fc8-1670-01d3-1278-5a47bf6ee188"),
+ version(3.0),
+ endpoint("ncacn_np:[\\pipe\\srvsvc]", "ncacn_ip_tcp:", "ncalrpc:"),
+ pointer_default(unique),
+ helpstring("Server Service")
+] interface srvsvc
+{
+ typedef bitmap svcctl_ServerType svcctl_ServerType;
+ typedef bitmap security_secinfo security_secinfo;
+
+/**************************/
+/* srvsvc_NetCharDev */
+/**************************/
+ typedef struct {
+ [string,charset(UTF16)] uint16 *device;
+ } srvsvc_NetCharDevInfo0;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetCharDevInfo0 *array;
+ } srvsvc_NetCharDevCtr0;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *device;
+ uint32 status;
+ [string,charset(UTF16)] uint16 *user;
+ uint32 time;
+ } srvsvc_NetCharDevInfo1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetCharDevInfo1 *array;
+ } srvsvc_NetCharDevCtr1;
+
+ typedef union {
+ [case(0)] srvsvc_NetCharDevInfo0 *info0;
+ [case(1)] srvsvc_NetCharDevInfo1 *info1;
+ [default] ;
+ } srvsvc_NetCharDevInfo;
+
+ typedef union {
+ [case(0)] srvsvc_NetCharDevCtr0 *ctr0;
+ [case(1)] srvsvc_NetCharDevCtr1 *ctr1;
+ [default] ;
+ } srvsvc_NetCharDevCtr;
+
+ /******************/
+ /* Function: 0x00 */
+ WERROR srvsvc_NetCharDevEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,out,ref] uint32 *level,
+ [in,out,ref,switch_is(*level)] srvsvc_NetCharDevCtr *ctr,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /******************/
+ /* Function: 0x01 */
+ WERROR srvsvc_NetCharDevGetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 device_name[],
+ [in] uint32 level,
+ [out,ref,switch_is(level)] srvsvc_NetCharDevInfo *info
+ );
+
+ /******************/
+ /* Function: 0x02 */
+ WERROR srvsvc_NetCharDevControl(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 device_name[],
+ [in] uint32 opcode
+ );
+
+/**************************/
+/* srvsvc_NetCharDevQ */
+/**************************/
+ typedef struct {
+ [string,charset(UTF16)] uint16 *device;
+ } srvsvc_NetCharDevQInfo0;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetCharDevQInfo0 *array;
+ } srvsvc_NetCharDevQCtr0;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *device;
+ uint32 priority;
+ [string,charset(UTF16)] uint16 *devices;
+ uint32 users;
+ uint32 num_ahead;
+ } srvsvc_NetCharDevQInfo1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetCharDevQInfo1 *array;
+ } srvsvc_NetCharDevQCtr1;
+
+ typedef union {
+ [case(0)] srvsvc_NetCharDevQInfo0 *info0;
+ [case(1)] srvsvc_NetCharDevQInfo1 *info1;
+ [default] ;
+ } srvsvc_NetCharDevQInfo;
+
+ typedef union {
+ [case(0)] srvsvc_NetCharDevQCtr0 *ctr0;
+ [case(1)] srvsvc_NetCharDevQCtr1 *ctr1;
+ [default] ;
+ } srvsvc_NetCharDevQCtr;
+
+ /******************/
+ /* Function: 0x03 */
+ WERROR srvsvc_NetCharDevQEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *user,
+ [in,out,ref] uint32 *level,
+ [in,out,switch_is(*level),ref] srvsvc_NetCharDevQCtr *ctr,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /******************/
+ /* Function: 0x04 */
+ WERROR srvsvc_NetCharDevQGetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 queue_name[],
+ [in] [string,charset(UTF16)] uint16 user[],
+ [in] uint32 level,
+ [out,switch_is(level),ref] srvsvc_NetCharDevQInfo *info
+ );
+
+ /******************/
+ /* Function: 0x05 */
+ WERROR srvsvc_NetCharDevQSetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 queue_name[],
+ [in] uint32 level,
+ [in,switch_is(level)] srvsvc_NetCharDevQInfo info,
+ [in,out,unique] uint32 *parm_error
+ );
+
+ /******************/
+ /* Function: 0x06 */
+ WERROR srvsvc_NetCharDevQPurge(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 queue_name[]
+ );
+
+ /******************/
+ /* Function: 0x07 */
+ WERROR srvsvc_NetCharDevQPurgeSelf(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 queue_name[],
+ [in] [string,charset(UTF16)] uint16 computer_name[]
+ );
+
+/**************************/
+/* srvsvc_NetConn */
+/**************************/
+ typedef struct {
+ uint32 conn_id;
+ } srvsvc_NetConnInfo0;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetConnInfo0 *array;
+ } srvsvc_NetConnCtr0;
+
+ typedef struct {
+ uint32 conn_id;
+ uint32 conn_type;
+ uint32 num_open;
+ uint32 num_users;
+ uint32 conn_time;
+ [string,charset(UTF16)] uint16 *user;
+ [string,charset(UTF16)] uint16 *share;
+ } srvsvc_NetConnInfo1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetConnInfo1 *array;
+ } srvsvc_NetConnCtr1;
+
+ typedef union {
+ [case(0)] srvsvc_NetConnCtr0 *ctr0;
+ [case(1)] srvsvc_NetConnCtr1 *ctr1;
+ [default] ;
+ } srvsvc_NetConnCtr;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] srvsvc_NetConnCtr ctr;
+ } srvsvc_NetConnInfoCtr;
+
+ /******************/
+ /* Function: 0x08 */
+ WERROR srvsvc_NetConnEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *path,
+ [in,out,ref] srvsvc_NetConnInfoCtr *info_ctr,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+/**************************/
+/* srvsvc_NetFile */
+/**************************/
+ typedef struct {
+ uint32 fid;
+ } srvsvc_NetFileInfo2;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetFileInfo2 *array;
+ } srvsvc_NetFileCtr2;
+
+ typedef struct {
+ uint32 fid;
+ uint32 permissions;
+ uint32 num_locks;
+ [string,charset(UTF16)] uint16 *path;
+ [string,charset(UTF16)] uint16 *user;
+ } srvsvc_NetFileInfo3;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetFileInfo3 *array;
+ } srvsvc_NetFileCtr3;
+
+ typedef union {
+ [case(2)] srvsvc_NetFileInfo2 *info2;
+ [case(3)] srvsvc_NetFileInfo3 *info3;
+ [default] ;
+ } srvsvc_NetFileInfo;
+
+ typedef union {
+ [case(2)] srvsvc_NetFileCtr2 *ctr2;
+ [case(3)] srvsvc_NetFileCtr3 *ctr3;
+ [default] ;
+ } srvsvc_NetFileCtr;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] srvsvc_NetFileCtr ctr;
+ } srvsvc_NetFileInfoCtr;
+
+ /******************/
+ /* Function: 0x09 */
+ WERROR srvsvc_NetFileEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *path,
+ [in,unique] [string,charset(UTF16)] uint16 *user,
+ [in,out,ref] srvsvc_NetFileInfoCtr *info_ctr,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /******************/
+ /* Function: 0x0a */
+ WERROR srvsvc_NetFileGetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 fid,
+ [in] uint32 level,
+ [out,switch_is(level),ref] srvsvc_NetFileInfo *info
+ );
+
+ /******************/
+ /* Function: 0x0b */
+ WERROR srvsvc_NetFileClose(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 fid
+ );
+
+/**************************/
+/* srvsvc_NetSess */
+/**************************/
+ typedef struct {
+ [string,charset(UTF16)] uint16 *client;
+ } srvsvc_NetSessInfo0;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetSessInfo0 *array;
+ } srvsvc_NetSessCtr0;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *client;
+ [string,charset(UTF16)] uint16 *user;
+ uint32 num_open;
+ uint32 time;
+ uint32 idle_time;
+ uint32 user_flags;
+ } srvsvc_NetSessInfo1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetSessInfo1 *array;
+ } srvsvc_NetSessCtr1;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *client;
+ [string,charset(UTF16)] uint16 *user;
+ uint32 num_open;
+ uint32 time;
+ uint32 idle_time;
+ uint32 user_flags;
+ [string,charset(UTF16)] uint16 *client_type;
+ } srvsvc_NetSessInfo2;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetSessInfo2 *array;
+ } srvsvc_NetSessCtr2;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *client;
+ [string,charset(UTF16)] uint16 *user;
+ uint32 time;
+ uint32 idle_time;
+ } srvsvc_NetSessInfo10;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetSessInfo10 *array;
+ } srvsvc_NetSessCtr10;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *client;
+ [string,charset(UTF16)] uint16 *user;
+ uint32 num_open;
+ uint32 time;
+ uint32 idle_time;
+ uint32 user_flags;
+ [string,charset(UTF16)] uint16 *client_type;
+ [string,charset(UTF16)] uint16 *transport;
+ } srvsvc_NetSessInfo502;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetSessInfo502 *array;
+ } srvsvc_NetSessCtr502;
+
+ typedef union {
+ [case(0)] srvsvc_NetSessCtr0 *ctr0;
+ [case(1)] srvsvc_NetSessCtr1 *ctr1;
+ [case(2)] srvsvc_NetSessCtr2 *ctr2;
+ [case(10)] srvsvc_NetSessCtr10 *ctr10;
+ [case(502)] srvsvc_NetSessCtr502 *ctr502;
+ [default] ;
+ } srvsvc_NetSessCtr;
+
+ /******************/
+ /* Function: 0x0c */
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] srvsvc_NetSessCtr ctr;
+ } srvsvc_NetSessInfoCtr;
+
+ WERROR srvsvc_NetSessEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *client,
+ [in,unique] [string,charset(UTF16)] uint16 *user,
+ [in,out,ref] srvsvc_NetSessInfoCtr *info_ctr,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /******************/
+ /* Function: 0x0d */
+ WERROR srvsvc_NetSessDel(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *client,
+ [in,unique] [string,charset(UTF16)] uint16 *user
+ );
+
+/**************************/
+/* srvsvc_NetShare */
+/**************************/
+
+ /* share types */
+ const uint32 STYPE_TEMPORARY = 0x40000000; /* share is a temporary one */
+ const uint32 STYPE_HIDDEN = 0x80000000; /* share is a hidden one */
+
+ typedef [v1_enum, flag(NDR_PAHEX)] enum {
+ STYPE_DISKTREE = 0,
+ STYPE_DISKTREE_TEMPORARY = STYPE_DISKTREE|STYPE_TEMPORARY,
+ STYPE_DISKTREE_HIDDEN = STYPE_DISKTREE|STYPE_HIDDEN,
+ STYPE_PRINTQ = 1,
+ STYPE_PRINTQ_TEMPORARY = STYPE_PRINTQ|STYPE_TEMPORARY,
+ STYPE_PRINTQ_HIDDEN = STYPE_PRINTQ|STYPE_HIDDEN,
+ STYPE_DEVICE = 2, /* Serial device */
+ STYPE_DEVICE_TEMPORARY = STYPE_DEVICE|STYPE_TEMPORARY,
+ STYPE_DEVICE_HIDDEN = STYPE_DEVICE|STYPE_HIDDEN,
+ STYPE_IPC = 3, /* Interprocess communication (IPC) */
+ STYPE_IPC_TEMPORARY = STYPE_IPC|STYPE_TEMPORARY,
+ STYPE_IPC_HIDDEN = STYPE_IPC|STYPE_HIDDEN
+ } srvsvc_ShareType;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *name;
+ } srvsvc_NetShareInfo0;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo0 *array;
+ } srvsvc_NetShareCtr0;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *name;
+ srvsvc_ShareType type;
+ [string,charset(UTF16)] uint16 *comment;
+ } srvsvc_NetShareInfo1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo1 *array;
+ } srvsvc_NetShareCtr1;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *name;
+ srvsvc_ShareType type;
+ [string,charset(UTF16)] uint16 *comment;
+ uint32 permissions;
+ uint32 max_users;
+ uint32 current_users;
+ [string,charset(UTF16)] uint16 *path;
+ [string,charset(UTF16)] uint16 *password;
+ } srvsvc_NetShareInfo2;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo2 *array;
+ } srvsvc_NetShareCtr2;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *name;
+ srvsvc_ShareType type;
+ [string,charset(UTF16)] uint16 *comment;
+ uint32 csc_policy;
+ } srvsvc_NetShareInfo501;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo501 *array;
+ } srvsvc_NetShareCtr501;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *name;
+ srvsvc_ShareType type;
+ [string,charset(UTF16)] uint16 *comment;
+ uint32 permissions;
+ uint32 max_users;
+ uint32 current_users;
+ [string,charset(UTF16)] uint16 *path;
+ [string,charset(UTF16)] uint16 *password;
+ sec_desc_buf sd_buf;
+ } srvsvc_NetShareInfo502;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo502 *array;
+ } srvsvc_NetShareCtr502;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *comment;
+ } srvsvc_NetShareInfo1004;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo1004 *array;
+ } srvsvc_NetShareCtr1004;
+
+ typedef bitmap {
+ SHARE_1005_IN_DFS = 0x00000001,
+ SHARE_1005_DFS_ROOT = 0x00000002
+ } NetShareInfo1005Flags;
+
+ const uint32 SHARE_1005_CSC_POLICY_MASK = 0x00000030;
+ const uint32 SHARE_1005_CSC_POLICY_SHIFT = 4;
+
+ typedef struct {
+ NetShareInfo1005Flags dfs_flags;
+ } srvsvc_NetShareInfo1005;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo1005 *array;
+ } srvsvc_NetShareCtr1005;
+
+ typedef struct {
+ uint32 max_users;
+ } srvsvc_NetShareInfo1006;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo1006 *array;
+ } srvsvc_NetShareCtr1006;
+
+ typedef struct {
+ uint32 flags;
+ [string,charset(UTF16)] uint16 *alternate_directory_name;
+ } srvsvc_NetShareInfo1007;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo1007 *array;
+ } srvsvc_NetShareCtr1007;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] sec_desc_buf *array;
+ } srvsvc_NetShareCtr1501;
+
+ typedef union {
+ [case(0)] srvsvc_NetShareInfo0 *info0;
+ [case(1)] srvsvc_NetShareInfo1 *info1;
+ [case(2)] srvsvc_NetShareInfo2 *info2;
+ [case(501)] srvsvc_NetShareInfo501 *info501;
+ [case(502)] srvsvc_NetShareInfo502 *info502;
+ [case(1004)] srvsvc_NetShareInfo1004 *info1004;
+ [case(1005)] srvsvc_NetShareInfo1005 *info1005;
+ [case(1006)] srvsvc_NetShareInfo1006 *info1006;
+ [case(1007)] srvsvc_NetShareInfo1007 *info1007;
+ [case(1501)] sec_desc_buf *info1501;
+ [default] ;
+ } srvsvc_NetShareInfo;
+
+ typedef union {
+ [case(0)] srvsvc_NetShareCtr0 *ctr0;
+ [case(1)] srvsvc_NetShareCtr1 *ctr1;
+ [case(2)] srvsvc_NetShareCtr2 *ctr2;
+ [case(501)] srvsvc_NetShareCtr501 *ctr501;
+ [case(502)] srvsvc_NetShareCtr502 *ctr502;
+ [case(1004)] srvsvc_NetShareCtr1004 *ctr1004;
+ [case(1005)] srvsvc_NetShareCtr1005 *ctr1005;
+ [case(1006)] srvsvc_NetShareCtr1006 *ctr1006;
+ [case(1007)] srvsvc_NetShareCtr1007 *ctr1007;
+ [case(1501)] srvsvc_NetShareCtr1501 *ctr1501;
+ [default] ;
+ } srvsvc_NetShareCtr;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] srvsvc_NetShareCtr ctr;
+ } srvsvc_NetShareInfoCtr;
+
+ /******************/
+ /* Function: 0x0e */
+ WERROR srvsvc_NetShareAdd(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 level,
+ [in,ref,switch_is(level)] srvsvc_NetShareInfo *info,
+ [in,out,unique] uint32 *parm_error
+ );
+
+ /******************/
+ /* Function: 0x0f */
+ WERROR srvsvc_NetShareEnumAll (
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,out,ref] srvsvc_NetShareInfoCtr *info_ctr,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /******************/
+ /* Function: 0x10 */
+ WERROR srvsvc_NetShareGetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 share_name[],
+ [in] uint32 level,
+ [out,ref,switch_is(level)] srvsvc_NetShareInfo *info
+ );
+
+ /******************/
+ /* Function: 0x11 */
+ WERROR srvsvc_NetShareSetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 share_name[],
+ [in] uint32 level,
+ [in,ref,switch_is(level)] srvsvc_NetShareInfo *info,
+ [in,out,unique] uint32 *parm_error
+ );
+
+ /******************/
+ /* Function: 0x12 */
+ WERROR srvsvc_NetShareDel(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 share_name[],
+ [in] uint32 reserved
+ );
+
+ /******************/
+ /* Function: 0x13 */
+ WERROR srvsvc_NetShareDelSticky(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 share_name[],
+ [in] uint32 reserved
+ );
+
+ /******************/
+ /* Function: 0x14 */
+ WERROR srvsvc_NetShareCheck(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 device_name[],
+ [out,ref] srvsvc_ShareType *type
+ );
+
+/**************************/
+/* srvsvc_NetSrv */
+/**************************/
+ typedef [public,v1_enum] enum {
+ PLATFORM_ID_DOS = 300,
+ PLATFORM_ID_OS2 = 400,
+ PLATFORM_ID_NT = 500,
+ PLATFORM_ID_OSF = 600,
+ PLATFORM_ID_VMS = 700
+ } srvsvc_PlatformId;
+
+ typedef struct {
+ srvsvc_PlatformId platform_id;
+ [string,charset(UTF16)] uint16 *server_name;
+ } srvsvc_NetSrvInfo100;
+
+ typedef struct {
+ srvsvc_PlatformId platform_id;
+ [string,charset(UTF16)] uint16 *server_name;
+ uint32 version_major;
+ uint32 version_minor;
+ svcctl_ServerType server_type;
+ [string,charset(UTF16)] uint16 *comment;
+ } srvsvc_NetSrvInfo101;
+
+ typedef struct {
+ srvsvc_PlatformId platform_id;
+ [string,charset(UTF16)] uint16 *server_name;
+ uint32 version_major;
+ uint32 version_minor;
+ svcctl_ServerType server_type;
+ [string,charset(UTF16)] uint16 *comment;
+ uint32 users;
+ uint32 disc;
+ uint32 hidden;
+ uint32 announce;
+ uint32 anndelta;
+ uint32 licenses;
+ [string,charset(UTF16)] uint16 *userpath;
+ } srvsvc_NetSrvInfo102;
+
+ typedef struct {
+ uint32 ulist_mtime;
+ uint32 glist_mtime;
+ uint32 alist_mtime;
+ [string,charset(UTF16)] uint16 *alerts;
+ uint32 security;
+ uint32 numadmin;
+ uint32 lanmask;
+ [string,charset(UTF16)] uint16 *guestaccount;
+ uint32 chdevs;
+ uint32 chdevqs;
+ uint32 chdevjobs;
+ uint32 connections;
+ uint32 shares;
+ uint32 openfiles;
+ uint32 sessopen;
+ uint32 sesssvc;
+ uint32 sessreqs;
+ uint32 opensearch;
+ uint32 activelocks;
+ uint32 sizereqbufs;
+ uint32 numbigbufs;
+ uint32 numfiletasks;
+ uint32 alertsched;
+ uint32 erroralert;
+ uint32 logonalert;
+ uint32 accessalert;
+ uint32 diskalert;
+ uint32 netioalert;
+ uint32 maxaudits;
+ [string,charset(UTF16)] uint16 *srvheuristics;
+ } srvsvc_NetSrvInfo402;
+
+ typedef struct {
+ uint32 ulist_mtime;
+ uint32 glist_mtime;
+ uint32 alist_mtime;
+ [string,charset(UTF16)] uint16 *alerts;
+ uint32 security;
+ uint32 numadmin;
+ uint32 lanmask;
+ [string,charset(UTF16)] uint16 *guestaccount;
+ uint32 chdevs;
+ uint32 chdevqs;
+ uint32 chdevjobs;
+ uint32 connections;
+ uint32 shares;
+ uint32 openfiles;
+ uint32 sessopen;
+ uint32 sesssvc;
+ uint32 sessreqs;
+ uint32 opensearch;
+ uint32 activelocks;
+ uint32 sizereqbufs;
+ uint32 numbigbufs;
+ uint32 numfiletasks;
+ uint32 alertsched;
+ uint32 eroralert;
+ uint32 logonalert;
+ uint32 accessalert;
+ uint32 diskalert;
+ uint32 netioalert;
+ uint32 maxaudits;
+ [string,charset(UTF16)] uint16 *srvheuristics;
+ uint32 auditedevents;
+ uint32 auditprofile;
+ [string,charset(UTF16)] uint16 *autopath;
+ } srvsvc_NetSrvInfo403;
+
+ typedef struct {
+ uint32 sessopen;
+ uint32 sesssvc;
+ uint32 opensearch;
+ uint32 sizereqbufs;
+ uint32 initworkitems;
+ uint32 maxworkitems;
+ uint32 rawworkitems;
+ uint32 irpstacksize;
+ uint32 maxrawbuflen;
+ uint32 sessusers;
+ uint32 sessconns;
+ uint32 maxpagedmemoryusage;
+ uint32 maxnonpagedmemoryusage;
+ uint32 enablesoftcompat;
+ uint32 enableforcedlogoff;
+ uint32 timesource;
+ uint32 acceptdownlevelapis;
+ uint32 lmannounce;
+ } srvsvc_NetSrvInfo502;
+
+ typedef struct{
+ uint32 sessopen;
+ uint32 sesssvc;
+ uint32 opensearch;
+ uint32 sizereqbufs;
+ uint32 initworkitems;
+ uint32 maxworkitems;
+ uint32 rawworkitems;
+ uint32 irpstacksize;
+ uint32 maxrawbuflen;
+ uint32 sessusers;
+ uint32 sessconns;
+ uint32 maxpagedmemoryusage;
+ uint32 maxnonpagedmemoryusage;
+ uint32 enablesoftcompat;
+ uint32 enableforcedlogoff;
+ uint32 timesource;
+ uint32 acceptdownlevelapis;
+ uint32 lmannounce;
+ [string,charset(UTF16)] uint16 *domain;
+ uint32 maxcopyreadlen;
+ uint32 maxcopywritelen;
+ uint32 minkeepsearch;
+ uint32 maxkeepsearch;
+ uint32 minkeepcomplsearch;
+ uint32 maxkeepcomplsearch;
+ uint32 threadcountadd;
+ uint32 numlockthreads;
+ uint32 scavtimeout;
+ uint32 minrcvqueue;
+ uint32 minfreeworkitems;
+ uint32 xactmemsize;
+ uint32 threadpriority;
+ uint32 maxmpxct;
+ uint32 oplockbreakwait;
+ uint32 oplockbreakresponsewait;
+ uint32 enableoplocks;
+ uint32 enableoplockforceclose;
+ uint32 enablefcbopens;
+ uint32 enableraw;
+ uint32 enablesharednetdrives;
+ uint32 minfreeconnections;
+ uint32 maxfreeconnections;
+ } srvsvc_NetSrvInfo503;
+
+ typedef struct{
+ uint32 sessopen;
+ uint32 sesssvc;
+ uint32 opensearch;
+ uint32 sizereqbufs;
+ uint32 initworkitems;
+ uint32 maxworkitems;
+ uint32 rawworkitems;
+ uint32 irpstacksize;
+ uint32 maxrawbuflen;
+ uint32 sessusers;
+ uint32 sessconns;
+ uint32 maxpagedmemoryusage;
+ uint32 maxnonpagedmemoryusage;
+ uint32 enablesoftcompat;
+ uint32 enableforcedlogoff;
+ uint32 timesource;
+ uint32 acceptdownlevelapis;
+ uint32 lmannounce;
+ [string,charset(UTF16)] uint16 *domain;
+ uint32 maxcopyreadlen;
+ uint32 maxcopywritelen;
+ uint32 minkeepsearch;
+ uint32 minkeepcomplsearch;
+ uint32 maxkeepcomplsearch;
+ uint32 threadcountadd;
+ uint32 numlockthreads;
+ uint32 scavtimeout;
+ uint32 minrcvqueue;
+ uint32 minfreeworkitems;
+ uint32 xactmemsize;
+ uint32 threadpriority;
+ uint32 maxmpxct;
+ uint32 oplockbreakwait;
+ uint32 oplockbreakresponsewait;
+ uint32 enableoplocks;
+ uint32 enableoplockforceclose;
+ uint32 enablefcbopens;
+ uint32 enableraw;
+ uint32 enablesharednetdrives;
+ uint32 minfreeconnections;
+ uint32 maxfreeconnections;
+ uint32 initsesstable;
+ uint32 initconntable;
+ uint32 initfiletable;
+ uint32 initsearchtable;
+ uint32 alertsched;
+ uint32 errortreshold;
+ uint32 networkerrortreshold;
+ uint32 diskspacetreshold;
+ uint32 reserved;
+ uint32 maxlinkdelay;
+ uint32 minlinkthroughput;
+ uint32 linkinfovalidtime;
+ uint32 scavqosinfoupdatetime;
+ uint32 maxworkitemidletime;
+ } srvsvc_NetSrvInfo599;
+
+ typedef struct{
+ [string,charset(UTF16)] uint16 *comment;
+ } srvsvc_NetSrvInfo1005;
+
+ typedef struct{
+ uint32 disc;
+ } srvsvc_NetSrvInfo1010;
+
+ typedef struct{
+ uint32 hidden;
+ } srvsvc_NetSrvInfo1016;
+
+ typedef struct{
+ uint32 announce;
+ } srvsvc_NetSrvInfo1017;
+
+ typedef struct{
+ uint32 anndelta;
+ } srvsvc_NetSrvInfo1018;
+
+ typedef struct{
+ uint32 users;
+ } srvsvc_NetSrvInfo1107;
+
+ typedef struct{
+ uint32 sessopens;
+ } srvsvc_NetSrvInfo1501;
+
+ typedef struct{
+ uint32 sessvcs;
+ } srvsvc_NetSrvInfo1502;
+
+ typedef struct{
+ uint32 opensearch;
+ } srvsvc_NetSrvInfo1503;
+
+ typedef struct{
+ uint32 maxworkitems;
+ } srvsvc_NetSrvInfo1506;
+
+ typedef struct{
+ uint32 maxrawbuflen;
+ } srvsvc_NetSrvInfo1509;
+
+ typedef struct{
+ uint32 sessusers;
+ } srvsvc_NetSrvInfo1510;
+
+ typedef struct{
+ uint32 sesscons;
+ } srvsvc_NetSrvInfo1511;
+
+ typedef struct{
+ uint32 maxnonpagedmemoryusage;
+ } srvsvc_NetSrvInfo1512;
+
+ typedef struct{
+ uint32 maxpagedmemoryusage;
+ } srvsvc_NetSrvInfo1513;
+
+ typedef struct{
+ uint32 enablesoftcompat;
+ } srvsvc_NetSrvInfo1514;
+
+ typedef struct{
+ uint32 enableforcedlogoff;
+ } srvsvc_NetSrvInfo1515;
+
+ typedef struct{
+ uint32 timesource;
+ } srvsvc_NetSrvInfo1516;
+
+ typedef struct{
+ uint32 lmannounce;
+ } srvsvc_NetSrvInfo1518;
+
+ typedef struct{
+ uint32 maxcopyreadlen;
+ } srvsvc_NetSrvInfo1520;
+
+ typedef struct{
+ uint32 maxcopywritelen;
+ } srvsvc_NetSrvInfo1521;
+
+ typedef struct{
+ uint32 minkeepsearch;
+ } srvsvc_NetSrvInfo1522;
+
+ typedef struct{
+ uint32 maxkeepsearch;
+ } srvsvc_NetSrvInfo1523;
+
+ typedef struct{
+ uint32 minkeepcomplsearch;
+ } srvsvc_NetSrvInfo1524;
+
+ typedef struct{
+ uint32 maxkeepcomplsearch;
+ } srvsvc_NetSrvInfo1525;
+
+ typedef struct{
+ uint32 scavtimeout;
+ } srvsvc_NetSrvInfo1528;
+
+ typedef struct{
+ uint32 minrcvqueue;
+ } srvsvc_NetSrvInfo1529;
+
+ typedef struct{
+ uint32 minfreeworkitems;
+ } srvsvc_NetSrvInfo1530;
+
+ typedef struct{
+ uint32 maxmpxct;
+ } srvsvc_NetSrvInfo1533;
+
+ typedef struct{
+ uint32 oplockbreakwait;
+ } srvsvc_NetSrvInfo1534;
+
+ typedef struct{
+ uint32 oplockbreakresponsewait;
+ } srvsvc_NetSrvInfo1535;
+
+ typedef struct{
+ uint32 enableoplocks;
+ } srvsvc_NetSrvInfo1536;
+
+ typedef struct{
+ uint32 enableoplockforceclose;
+ } srvsvc_NetSrvInfo1537;
+
+ typedef struct{
+ uint32 enablefcbopens;
+ } srvsvc_NetSrvInfo1538;
+
+ typedef struct{
+ uint32 enableraw;
+ } srvsvc_NetSrvInfo1539;
+
+ typedef struct{
+ uint32 enablesharednetdrives;
+ } srvsvc_NetSrvInfo1540;
+
+ typedef struct{
+ uint32 minfreeconnections;
+ } srvsvc_NetSrvInfo1541;
+
+ typedef struct{
+ uint32 maxfreeconnections;
+ } srvsvc_NetSrvInfo1542;
+
+ typedef struct{
+ uint32 initsesstable;
+ } srvsvc_NetSrvInfo1543;
+
+ typedef struct{
+ uint32 initconntable;
+ } srvsvc_NetSrvInfo1544;
+
+ typedef struct{
+ uint32 initfiletable;
+ } srvsvc_NetSrvInfo1545;
+
+ typedef struct{
+ uint32 initsearchtable;
+ } srvsvc_NetSrvInfo1546;
+
+ typedef struct{
+ uint32 alertsched;
+ } srvsvc_NetSrvInfo1547;
+
+ typedef struct{
+ uint32 errortreshold;
+ } srvsvc_NetSrvInfo1548;
+
+ typedef struct{
+ uint32 networkerrortreshold;
+ } srvsvc_NetSrvInfo1549;
+
+ typedef struct{
+ uint32 diskspacetreshold;
+ } srvsvc_NetSrvInfo1550;
+
+ typedef struct{
+ uint32 maxlinkdelay;
+ } srvsvc_NetSrvInfo1552;
+
+ typedef struct{
+ uint32 minlinkthroughput;
+ } srvsvc_NetSrvInfo1553;
+
+ typedef struct{
+ uint32 linkinfovalidtime;
+ } srvsvc_NetSrvInfo1554;
+
+ typedef struct{
+ uint32 scavqosinfoupdatetime;
+ } srvsvc_NetSrvInfo1555;
+
+ typedef struct{
+ uint32 maxworkitemidletime;
+ } srvsvc_NetSrvInfo1556;
+
+
+ typedef union{
+ [case(100)] srvsvc_NetSrvInfo100 *info100;
+ [case(101)] srvsvc_NetSrvInfo101 *info101;
+ [case(102)] srvsvc_NetSrvInfo102 *info102;
+ [case(402)] srvsvc_NetSrvInfo402 *info402;
+ [case(403)] srvsvc_NetSrvInfo403 *info403;
+ [case(502)] srvsvc_NetSrvInfo502 *info502;
+ [case(503)] srvsvc_NetSrvInfo503 *info503;
+ [case(599)] srvsvc_NetSrvInfo599 *info599;
+ [case(1005)] srvsvc_NetSrvInfo1005 *info1005;
+ [case(1010)] srvsvc_NetSrvInfo1010 *info1010;
+ [case(1016)] srvsvc_NetSrvInfo1016 *info1016;
+ [case(1017)] srvsvc_NetSrvInfo1017 *info1017;
+ [case(1018)] srvsvc_NetSrvInfo1018 *info1018;
+ [case(1107)] srvsvc_NetSrvInfo1107 *info1107;
+ [case(1501)] srvsvc_NetSrvInfo1501 *info1501;
+ [case(1502)] srvsvc_NetSrvInfo1502 *info1502;
+ [case(1503)] srvsvc_NetSrvInfo1503 *info1503;
+ [case(1506)] srvsvc_NetSrvInfo1506 *info1506;
+ [case(1509)] srvsvc_NetSrvInfo1509 *info1509;
+ [case(1510)] srvsvc_NetSrvInfo1510 *info1510;
+ [case(1511)] srvsvc_NetSrvInfo1511 *info1511;
+ [case(1512)] srvsvc_NetSrvInfo1512 *info1512;
+ [case(1513)] srvsvc_NetSrvInfo1513 *info1513;
+ [case(1514)] srvsvc_NetSrvInfo1514 *info1514;
+ [case(1515)] srvsvc_NetSrvInfo1515 *info1515;
+ [case(1516)] srvsvc_NetSrvInfo1516 *info1516;
+ [case(1518)] srvsvc_NetSrvInfo1518 *info1518;
+ [case(1520)] srvsvc_NetSrvInfo1520 *info1520;
+ [case(1521)] srvsvc_NetSrvInfo1521 *info1521;
+ [case(1522)] srvsvc_NetSrvInfo1522 *info1522;
+ [case(1523)] srvsvc_NetSrvInfo1523 *info1523;
+ [case(1524)] srvsvc_NetSrvInfo1524 *info1524;
+ [case(1525)] srvsvc_NetSrvInfo1525 *info1525;
+ [case(1528)] srvsvc_NetSrvInfo1528 *info1528;
+ [case(1529)] srvsvc_NetSrvInfo1529 *info1529;
+ [case(1530)] srvsvc_NetSrvInfo1530 *info1530;
+ [case(1533)] srvsvc_NetSrvInfo1533 *info1533;
+ [case(1534)] srvsvc_NetSrvInfo1534 *info1534;
+ [case(1535)] srvsvc_NetSrvInfo1535 *info1535;
+ [case(1536)] srvsvc_NetSrvInfo1536 *info1536;
+ [case(1537)] srvsvc_NetSrvInfo1537 *info1537;
+ [case(1538)] srvsvc_NetSrvInfo1538 *info1538;
+ [case(1539)] srvsvc_NetSrvInfo1539 *info1539;
+ [case(1540)] srvsvc_NetSrvInfo1540 *info1540;
+ [case(1541)] srvsvc_NetSrvInfo1541 *info1541;
+ [case(1542)] srvsvc_NetSrvInfo1542 *info1542;
+ [case(1543)] srvsvc_NetSrvInfo1543 *info1543;
+ [case(1544)] srvsvc_NetSrvInfo1544 *info1544;
+ [case(1545)] srvsvc_NetSrvInfo1545 *info1545;
+ [case(1546)] srvsvc_NetSrvInfo1546 *info1546;
+ [case(1547)] srvsvc_NetSrvInfo1547 *info1547;
+ [case(1548)] srvsvc_NetSrvInfo1548 *info1548;
+ [case(1549)] srvsvc_NetSrvInfo1549 *info1549;
+ [case(1550)] srvsvc_NetSrvInfo1550 *info1550;
+ [case(1552)] srvsvc_NetSrvInfo1552 *info1552;
+ [case(1553)] srvsvc_NetSrvInfo1553 *info1553;
+ [case(1554)] srvsvc_NetSrvInfo1554 *info1554;
+ [case(1555)] srvsvc_NetSrvInfo1555 *info1555;
+ [case(1556)] srvsvc_NetSrvInfo1556 *info1556;
+ [default];
+ } srvsvc_NetSrvInfo;
+
+ /******************/
+ /* Function: 0x15 */
+ WERROR srvsvc_NetSrvGetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 level,
+ [out,ref,switch_is(level)] srvsvc_NetSrvInfo *info
+ );
+
+ /******************/
+ /* Function: 0x16 */
+ WERROR srvsvc_NetSrvSetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 level,
+ [in,ref,switch_is(level)] srvsvc_NetSrvInfo *info,
+ [in,out,unique] uint32 *parm_error
+ );
+
+/**************************/
+/* srvsvc_NetDisk */
+/**************************/
+ typedef struct {
+ [flag(STR_LEN4)] string disk;
+ } srvsvc_NetDiskInfo0;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count), length_is(count)] srvsvc_NetDiskInfo0 *disks;
+ } srvsvc_NetDiskInfo;
+
+ /******************/
+ /* Function: 0x17 */
+ WERROR srvsvc_NetDiskEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 level,
+ [in,out,ref] srvsvc_NetDiskInfo *info,
+ [in] uint32 maxlen,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+/**************************/
+/* srvsvc_NetStatistics */
+/**************************/
+ typedef struct {
+ uint32 start;
+ uint32 fopens;
+ uint32 devopens;
+ uint32 jobsqueued;
+ uint32 sopens;
+ uint32 stimeouts;
+ uint32 serrorout;
+ uint32 pwerrors;
+ uint32 permerrors;
+ uint32 syserrors;
+ uint32 bytessent_low;
+ uint32 bytessent_high;
+ uint32 bytesrcvd_low;
+ uint32 bytesrcvd_high;
+ uint32 avresponse;
+ uint32 reqbufneed;
+ uint32 bigbufneed;
+ } srvsvc_Statistics;
+
+ /******************/
+ /* Function: 0x18 */
+ WERROR srvsvc_NetServerStatisticsGet(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *service,
+ [in] uint32 level,
+ [in] uint32 options,
+ [out,ref] srvsvc_Statistics *stats
+ );
+
+/**************************/
+/* srvsvc_NetTransport */
+/**************************/
+ typedef struct {
+ uint32 vcs;
+ [string,charset(UTF16)] uint16 *name;
+ [size_is(addr_len)] uint8 *addr;
+ uint32 addr_len;
+ [string,charset(UTF16)] uint16 *net_addr;
+ } srvsvc_NetTransportInfo0;
+
+ /******************/
+ /* Function: 0x19 */
+ WERROR srvsvc_NetTransportAdd(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 level,
+ [in,switch_is(level)] srvsvc_NetTransportInfo info
+ );
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetTransportInfo0 *array;
+ } srvsvc_NetTransportCtr0;
+
+ typedef struct {
+ uint32 vcs;
+ [string,charset(UTF16)] uint16 *name;
+ [size_is(addr_len)] uint8 *addr;
+ uint32 addr_len;
+ [string,charset(UTF16)] uint16 *net_addr;
+ [string,charset(UTF16)] uint16 *domain;
+ } srvsvc_NetTransportInfo1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetTransportInfo1 *array;
+ } srvsvc_NetTransportCtr1;
+
+ typedef struct {
+ uint32 vcs;
+ [string,charset(UTF16)] uint16 *name;
+ [size_is(addr_len)] uint8 *addr;
+ uint32 addr_len;
+ [string,charset(UTF16)] uint16 *net_addr;
+ [string,charset(UTF16)] uint16 *domain;
+ uint32 unknown;
+ } srvsvc_NetTransportInfo2;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetTransportInfo2 *array;
+ } srvsvc_NetTransportCtr2;
+
+ typedef struct {
+ uint32 vcs;
+ [string,charset(UTF16)] uint16 *name;
+ [size_is(addr_len)] uint8 *addr;
+ uint32 addr_len;
+ [string,charset(UTF16)] uint16 *net_addr;
+ [string,charset(UTF16)] uint16 *domain;
+ uint32 unknown1;
+ uint32 unknown2;
+ uint8 unknown3[256];
+ } srvsvc_NetTransportInfo3;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetTransportInfo3 *array;
+ } srvsvc_NetTransportCtr3;
+
+ typedef union {
+ [case(0)] srvsvc_NetTransportCtr0 *ctr0;
+ [case(1)] srvsvc_NetTransportCtr1 *ctr1;
+ [case(2)] srvsvc_NetTransportCtr2 *ctr2;
+ [case(3)] srvsvc_NetTransportCtr3 *ctr3;
+ [default];
+ } srvsvc_NetTransportCtr;
+
+ /******************/
+ /* Function: 0x1a */
+ WERROR srvsvc_NetTransportEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,out,ref] uint32 *level,
+ [in,out,ref,switch_is(*level)] srvsvc_NetTransportCtr *transports,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /******************/
+ /* Function: 0x1b */
+ WERROR srvsvc_NetTransportDel(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 unknown,
+ [in] srvsvc_NetTransportInfo0 transport
+ );
+
+/**************************/
+/* srvsvc_NetRemoteTOD */
+/**************************/
+ typedef struct {
+ uint32 elapsed; /* time(NULL) */
+ uint32 msecs; /* milliseconds till system reboot (uptime) */
+ uint32 hours;
+ uint32 mins;
+ uint32 secs;
+ uint32 hunds;
+ int32 timezone; /* in minutes */
+ uint32 tinterval; /* clock tick interval in 0.0001 second units; 310 on windows */
+ uint32 day;
+ uint32 month;
+ uint32 year;
+ uint32 weekday;
+ } srvsvc_NetRemoteTODInfo;
+
+ /******************/
+ /* Function: 0x1c */
+ WERROR srvsvc_NetRemoteTOD(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [out,ref] srvsvc_NetRemoteTODInfo **info
+ );
+
+/**************************/
+/* srvsvc_NetServiceBits */
+/**************************/
+ /******************/
+ /* Function: 0x1d */
+ WERROR srvsvc_NetSetServiceBits(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *transport,
+ [in] uint32 servicebits,
+ [in] uint32 updateimmediately
+ );
+
+/**************************/
+/* srvsvc_NetPath */
+/**************************/
+ /******************/
+ /* Function: 0x1e */
+ WERROR srvsvc_NetPathType(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 path[],
+ [in] uint32 pathflags,
+ [out,ref] uint32 *pathtype
+ );
+
+ /******************/
+ /* Function: 0x1f */
+ WERROR srvsvc_NetPathCanonicalize(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 path[],
+ [out] [size_is(maxbuf)] uint8 can_path[],
+ [in] uint32 maxbuf,
+ [in] [string,charset(UTF16)] uint16 prefix[],
+ [in,out,ref] uint32 *pathtype,
+ [in] uint32 pathflags
+ );
+
+ /******************/
+ /* Function: 0x20 */
+ WERROR srvsvc_NetPathCompare(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 path1[],
+ [in] [string,charset(UTF16)] uint16 path2[],
+ [in] uint32 pathtype,
+ [in] uint32 pathflags
+ );
+
+/**************************/
+/* srvsvc_NetName */
+/**************************/
+ /******************/
+ /* Function: 0x21 */
+ WERROR srvsvc_NetNameValidate(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 name[],
+ [in] uint32 name_type,
+ [in] uint32 flags
+ );
+
+ /******************/
+ /* Function: 0x22 */
+ WERROR srvsvc_NETRPRNAMECANONICALIZE(
+ );
+
+ /******************/
+ /* Function: 0x23 */
+ WERROR srvsvc_NetPRNameCompare(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 name1[],
+ [in] [string,charset(UTF16)] uint16 name2[],
+ [in] uint32 name_type,
+ [in] uint32 flags
+ );
+
+/**************************/
+/* srvsvc_NetShare ... */
+/**************************/
+ /******************/
+ /* Function: 0x24 */
+ /* Note, there must be some way to return entries read vs
+ total entries ... */
+ WERROR srvsvc_NetShareEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,out,ref] srvsvc_NetShareInfoCtr *info_ctr,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /******************/
+ /* Function: 0x25 */
+ WERROR srvsvc_NetShareDelStart(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 share[],
+ [in] uint32 reserved,
+ [out,unique] policy_handle *hnd
+ );
+
+ /******************/
+ /* Function: 0x26 */
+ WERROR srvsvc_NetShareDelCommit(
+ [in, out,unique] policy_handle *hnd
+ );
+
+ /******************/
+ /* Function: 0x27 */
+ WERROR srvsvc_NetGetFileSecurity(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *share,
+ [in] [string,charset(UTF16)] uint16 file[],
+ [in] security_secinfo securityinformation,
+ [out,ref] sec_desc_buf **sd_buf
+ );
+
+ /******************/
+ /* Function: 0x28 */
+ WERROR srvsvc_NetSetFileSecurity(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *share,
+ [in] [string,charset(UTF16)] uint16 file[],
+ [in] security_secinfo securityinformation,
+ [in,ref] sec_desc_buf *sd_buf
+ );
+
+
+
+ typedef [switch_type(uint32)] union {
+ [case(0)] srvsvc_NetTransportInfo0 info0;
+ [case(1)] srvsvc_NetTransportInfo1 info1;
+ [case(2)] srvsvc_NetTransportInfo2 info2;
+ [case(3)] srvsvc_NetTransportInfo3 info3;
+ } srvsvc_NetTransportInfo;
+
+ /******************/
+ /* Function: 0x29 */
+ WERROR srvsvc_NetServerTransportAddEx(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 level,
+ [in,switch_is(level)] srvsvc_NetTransportInfo info
+ );
+
+ /******************/
+ /* Function: 0x2a */
+ WERROR srvsvc_NetServerSetServiceBitsEx(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *emulated_server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *transport,
+ [in] uint32 servicebitsofinterest,
+ [in] uint32 servicebits,
+ [in] uint32 updateimmediately
+ );
+
+ /******************/
+ /* Function: 0x2b */
+ WERROR srvsvc_NETRDFSGETVERSION(
+ );
+
+ /******************/
+ /* Function: 0x2c */
+ WERROR srvsvc_NETRDFSCREATELOCALPARTITION(
+ );
+
+ /******************/
+ /* Function: 0x2d */
+ WERROR srvsvc_NETRDFSDELETELOCALPARTITION(
+ );
+
+ /******************/
+ /* Function: 0x2e */
+ WERROR srvsvc_NETRDFSSETLOCALVOLUMESTATE(
+ );
+
+ /******************/
+ /* Function: 0x2f */
+ WERROR srvsvc_NETRDFSSETSERVERINFO(
+ );
+
+ /******************/
+ /* Function: 0x30 */
+ WERROR srvsvc_NETRDFSCREATEEXITPOINT(
+ );
+
+ /******************/
+ /* Function: 0x31 */
+ WERROR srvsvc_NETRDFSDELETEEXITPOINT(
+ );
+
+ /******************/
+ /* Function: 0x32 */
+ WERROR srvsvc_NETRDFSMODIFYPREFIX(
+ );
+
+ /******************/
+ /* Function: 0x33 */
+ WERROR srvsvc_NETRDFSFIXLOCALVOLUME(
+ );
+
+ /******************/
+ /* Function: 0x34 */
+ WERROR srvsvc_NETRDFSMANAGERREPORTSITEINFO(
+ );
+
+ /******************/
+ /* Function: 0x35 */
+ WERROR srvsvc_NETRSERVERTRANSPORTDELEX(
+ );
+}
diff --git a/source3/librpc/idl/svcctl.idl b/source3/librpc/idl/svcctl.idl
new file mode 100644
index 0000000000..5a843d04ef
--- /dev/null
+++ b/source3/librpc/idl/svcctl.idl
@@ -0,0 +1,528 @@
+#include "idl_types.h"
+
+/*
+ svcctl interface definitions
+*/
+
+[ uuid("367abb81-9844-35f1-ad32-98f038001003"),
+ version(2.0),
+ pointer_default(unique),
+ endpoint("ncacn_np:[\\pipe\\svcctl]", "ncalrpc:"),
+ helpstring("Service Control")
+] interface svcctl
+{
+ typedef struct {
+ uint32 is_locked;
+ [string,charset(UTF16)] uint16 *lock_owner;
+ uint32 lock_duration;
+ } SERVICE_LOCK_STATUS;
+
+ typedef struct {
+ uint32 type;
+ uint32 state;
+ uint32 controls_accepted;
+ WERROR win32_exit_code;
+ uint32 service_exit_code;
+ uint32 check_point;
+ uint32 wait_hint;
+ } SERVICE_STATUS;
+
+ typedef struct {
+ [relative] astring *service_name;
+ [relative] astring *display_name;
+ SERVICE_STATUS status;
+ } ENUM_SERVICE_STATUS;
+
+ const int SERVICE_TYPE_KERNEL_DRIVER = 0x01;
+ const int SERVICE_TYPE_FS_DRIVER = 0x02;
+ const int SERVICE_TYPE_ADAPTER = 0x04;
+ const int SERVICE_TYPE_RECOGNIZER_DRIVER = 0x08;
+ const int SERVICE_TYPE_DRIVER=SERVICE_TYPE_KERNEL_DRIVER|SERVICE_TYPE_FS_DRIVER|SERVICE_TYPE_RECOGNIZER_DRIVER;
+ const int SERVICE_TYPE_WIN32_OWN_PROCESS = 0x10;
+ const int SERVICE_TYPE_WIN32_SHARE_PROCESS = 0x20;
+ const int SERVICE_TYPE_WIN32=SERVICE_TYPE_WIN32_OWN_PROCESS|SERVICE_TYPE_WIN32_SHARE_PROCESS;
+
+ const int SERVICE_STATE_ACTIVE = 0x01;
+ const int SERVICE_STATE_INACTIVE = 0x02;
+ const int SERVICE_STATE_ALL = 0x03;
+
+ typedef [public,bitmap32bit] bitmap {
+ SV_TYPE_WORKSTATION = 0x00000001,
+ SV_TYPE_SERVER = 0x00000002,
+ SV_TYPE_SQLSERVER = 0x00000004,
+ SV_TYPE_DOMAIN_CTRL = 0x00000008,
+ SV_TYPE_DOMAIN_BAKCTRL = 0x00000010,
+ SV_TYPE_TIME_SOURCE = 0x00000020,
+ SV_TYPE_AFP = 0x00000040,
+ SV_TYPE_NOVELL = 0x00000080,
+
+ SV_TYPE_DOMAIN_MEMBER = 0x00000100,
+ SV_TYPE_PRINTQ_SERVER = 0x00000200,
+ SV_TYPE_DIALIN_SERVER = 0x00000400,
+ SV_TYPE_SERVER_UNIX = 0x00000800,
+ SV_TYPE_NT = 0x00001000,
+ SV_TYPE_WFW = 0x00002000,
+ SV_TYPE_SERVER_MFPN = 0x00004000,
+ SV_TYPE_SERVER_NT = 0x00008000,
+ SV_TYPE_POTENTIAL_BROWSER = 0x00010000,
+ SV_TYPE_BACKUP_BROWSER = 0x00020000,
+ SV_TYPE_MASTER_BROWSER = 0x00040000,
+ SV_TYPE_DOMAIN_MASTER = 0x00080000,
+ SV_TYPE_SERVER_OSF = 0x00100000,
+ SV_TYPE_SERVER_VMS = 0x00200000,
+ SV_TYPE_WIN95_PLUS = 0x00400000,
+ SV_TYPE_DFS_SERVER = 0x00800000,
+ SV_TYPE_ALTERNATE_XPORT = 0x20000000,
+ SV_TYPE_LOCAL_LIST_ONLY = 0x40000000,
+ SV_TYPE_DOMAIN_ENUM = 0x80000000
+ } svcctl_ServerType;
+
+ const uint32 SV_TYPE_ALL = 0xFFFFFFFF;
+
+ /*****************/
+ /* Function 0x00 */
+ WERROR svcctl_CloseServiceHandle(
+ [in,out,ref] policy_handle *handle
+ );
+
+ /*****************/
+ /* Function 0x01 */
+
+ typedef enum {
+ FIXME=1
+ } SERVICE_CONTROL;
+
+ WERROR svcctl_ControlService(
+ [in,ref] policy_handle *handle,
+ [in] uint32 control,
+ [out,ref] SERVICE_STATUS *service_status
+ );
+
+ /*****************/
+ /* Function 0x02 */
+ WERROR svcctl_DeleteService(
+ [in,ref] policy_handle *handle
+ );
+
+ /*****************/
+ /* Function 0x03 */
+
+ WERROR svcctl_LockServiceDatabase(
+ [in,ref] policy_handle *handle,
+ [out,ref] policy_handle *lock
+ );
+
+ /*****************/
+ /* Function 0x04 */
+ WERROR svcctl_QueryServiceObjectSecurity(
+ [in] policy_handle *handle,
+ [in] uint32 security_flags,
+ [out,ref,size_is(buffer_size)] uint8 *buffer,
+ [in,range(0,0x40000)] uint32 buffer_size,
+ [out,ref,range(0,0x40000)] uint32 *needed
+ );
+
+ /*****************/
+ /* Function 0x05 */
+ WERROR svcctl_SetServiceObjectSecurity(
+ [in] policy_handle *handle,
+ [in] uint32 security_flags,
+ [in,ref,size_is(buffer_size)] uint8 *buffer,
+ [in] uint32 buffer_size
+ );
+
+ /*****************/
+ /* Function 0x06 */
+ WERROR svcctl_QueryServiceStatus(
+ [in,ref] policy_handle *handle,
+ [out,ref] SERVICE_STATUS *service_status
+ );
+
+ /*****************/
+ /* Function 0x07 */
+ WERROR svcctl_SetServiceStatus(
+ );
+
+ /*****************/
+ /* Function 0x08 */
+ WERROR svcctl_UnlockServiceDatabase(
+ [in,out,ref] policy_handle *lock
+ );
+
+ /*****************/
+ /* Function 0x09 */
+ WERROR svcctl_NotifyBootConfigStatus(
+ );
+
+ /*****************/
+ /* Function 0x0a */
+ WERROR svcctl_SCSetServiceBitsW(
+ [in,ref] policy_handle *handle,
+ [in] uint32 bits,
+ [in] boolean32 bitson,
+ [in] boolean32 immediate
+ );
+
+ /*****************/
+ /* Function 0x0b */
+ WERROR svcctl_ChangeServiceConfigW(
+ [in,ref] policy_handle *handle,
+ [in] uint32 type,
+ [in] uint32 start,
+ [in] uint32 error,
+ [in,unique] [string,charset(UTF16)] uint16 *binary_path,
+ [in,unique] [string,charset(UTF16)] uint16 *load_order_group,
+ [out,ref] uint32 *tag_id,
+ [in,unique] [string,charset(UTF16)] uint16 *dependencies,
+ [in,unique] [string,charset(UTF16)] uint16 *service_start_name,
+ [in,unique] [string,charset(UTF16)] uint16 *password,
+ [in,unique] [string,charset(UTF16)] uint16 *display_name
+ );
+
+ /*****************/
+ /* Function 0x0c */
+ WERROR svcctl_CreateServiceW(
+ [in,ref] policy_handle *scmanager_handle,
+ [in] [string,charset(UTF16)] uint16 ServiceName[],
+ [in,unique] [string,charset(UTF16)] uint16 *DisplayName,
+ [in] uint32 desired_access,
+ [in] uint32 type,
+ [in] uint32 start_type,
+ [in] uint32 error_control,
+ [in] [string,charset(UTF16)] uint16 binary_path[],
+ [in,unique] [string,charset(UTF16)] uint16 *LoadOrderGroupKey,
+ [in,out,unique] uint32 *TagId,
+ [in,unique,size_is(dependencies_size)] uint8 *dependencies,
+ [in] uint32 dependencies_size,
+ [in,unique] [string,charset(UTF16)] uint16 *service_start_name,
+ [in,unique,size_is(password_size)] uint8 *password,
+ [in] uint32 password_size,
+ [out,ref] policy_handle *handle
+ );
+
+ /*****************/
+ /* Function 0x0d */
+ WERROR svcctl_EnumDependentServicesW(
+ [in,ref] policy_handle *service,
+ [in] uint32 state,
+ [out,ref,size_is(buf_size)] uint8 *service_status,
+ [in,range(0,0x40000)] uint32 buf_size,
+ [out,ref,range(0,0x40000)] uint32 *bytes_needed,
+ [out,ref,range(0,0x40000)] uint32 *services_returned
+ );
+
+ /*****************/
+ /* Function 0x0e */
+ WERROR svcctl_EnumServicesStatusW(
+ [in,ref] policy_handle *handle,
+ [in] uint32 type,
+ [in] uint32 state,
+ [in] uint32 buf_size,
+ [out,size_is(buf_size)] uint8 service[*],
+ [out,ref] uint32 *bytes_needed,
+ [out,ref] uint32 *services_returned,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /*****************/
+ /* Function 0x0f */
+ typedef [bitmap32bit] bitmap {
+ SC_RIGHT_MGR_CONNECT = 0x0001,
+ SC_RIGHT_MGR_CREATE_SERVICE = 0x0002,
+ SC_RIGHT_MGR_ENUMERATE_SERVICE = 0x0004,
+ SC_RIGHT_MGR_LOCK = 0x0008,
+ SC_RIGHT_MGR_QUERY_LOCK_STATUS = 0x0010,
+ SC_RIGHT_MGR_MODIFY_BOOT_CONFIG = 0x0020
+ } svcctl_MgrAccessMask;
+
+ WERROR svcctl_OpenSCManagerW(
+ [in,unique] [string,charset(UTF16)] uint16 *MachineName,
+ [in,unique] [string,charset(UTF16)] uint16 *DatabaseName,
+ [in] svcctl_MgrAccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /*****************/
+ /* Function 0x10 */
+ typedef [bitmap32bit] bitmap {
+ SC_RIGHT_SVC_QUERY_CONFIG = 0x0001,
+ SC_RIGHT_SVC_CHANGE_CONFIG = 0x0002,
+ SC_RIGHT_SVC_QUERY_STATUS = 0x0004,
+ SC_RIGHT_SVC_ENUMERATE_DEPENDENTS = 0x0008,
+ SC_RIGHT_SVC_START = 0x0010,
+ SC_RIGHT_SVC_STOP = 0x0020,
+ SC_RIGHT_SVC_PAUSE_CONTINUE = 0x0040,
+ SC_RIGHT_SVC_INTERROGATE = 0x0080,
+ SC_RIGHT_SVC_USER_DEFINED_CONTROL = 0x0100
+ } svcctl_ServiceAccessMask;
+
+ WERROR svcctl_OpenServiceW(
+ [in,ref] policy_handle *scmanager_handle,
+ [in] [string,charset(UTF16)] uint16 ServiceName[],
+ [in] svcctl_ServiceAccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /*****************/
+ /* Function 0x11 */
+ WERROR svcctl_QueryServiceConfigW(
+ [in,ref] policy_handle *handle,
+ [out] uint8 query[buf_size], /*QUERY_SERVICE_CONFIG */
+ [in] uint32 buf_size,
+ [out,ref] uint32 *bytes_needed
+ );
+
+ /*****************/
+ /* Function 0x12 */
+ WERROR svcctl_QueryServiceLockStatusW(
+ [in,ref] policy_handle *handle,
+ [in] uint32 buf_size,
+ [out,ref] SERVICE_LOCK_STATUS *lock_status,
+ [out,ref] uint32 *required_buf_size
+ );
+
+ /*****************/
+ /* Function 0x13 */
+ WERROR svcctl_StartServiceW(
+ [in,ref] policy_handle *handle,
+ [in] uint32 NumArgs,
+ [in,unique/*FIXME:,length_is(NumArgs)*/] [string,charset(UTF16)] uint16 *Arguments
+ );
+
+ /*****************/
+ /* Function 0x14 */
+ WERROR svcctl_GetServiceDisplayNameW(
+ [in,ref] policy_handle *handle,
+ [in,unique] [string,charset(UTF16)] uint16 *service_name,
+ [out,ref] [string,charset(UTF16)] uint16 **display_name,
+ [in,out,unique] uint32 *display_name_length
+ );
+
+ /*****************/
+ /* Function 0x15 */
+ WERROR svcctl_GetServiceKeyNameW(
+ [in,ref] policy_handle *handle,
+ [in,unique] [string,charset(UTF16)] uint16 *service_name,
+ [out,ref] [string,charset(UTF16)] uint16 **key_name,
+ [in,out,unique] uint32 *display_name_length
+ );
+
+ /*****************/
+ /* Function 0x16 */
+ WERROR svcctl_SCSetServiceBitsA(
+ [in,ref] policy_handle *handle,
+ [in] uint32 bits,
+ [in] boolean32 bitson,
+ [in] boolean32 immediate
+ );
+
+ /*****************/
+ /* Function 0x17 */
+ WERROR svcctl_ChangeServiceConfigA(
+ [in,ref] policy_handle *handle,
+ [in] uint32 type,
+ [in] uint32 start,
+ [in] uint32 error,
+ [in,unique] [string,charset(UTF16)] uint16 *binary_path,
+ [in,unique] [string,charset(UTF16)] uint16 *load_order_group,
+ [out,ref] uint32 *tag_id,
+ [in,unique] [string,charset(UTF16)] uint16 *dependencies,
+ [in,unique] [string,charset(UTF16)] uint16 *service_start_name,
+ [in,unique] [string,charset(UTF16)] uint16 *password,
+ [in,unique] [string,charset(UTF16)] uint16 *display_name
+ );
+
+ /*****************/
+ /* Function 0x18 */
+ WERROR svcctl_CreateServiceA(
+ [in,ref] policy_handle *handle,
+ [in,unique] [string,charset(UTF16)] uint16 *ServiceName,
+ [in,unique] [string,charset(UTF16)] uint16 *DisplayName,
+ [in] uint32 desired_access,
+ [in] uint32 type,
+ [in] uint32 start_type,
+ [in] uint32 error_control,
+ [in,unique] [string,charset(UTF16)] uint16 *binary_path,
+ [in,unique] [string,charset(UTF16)] uint16 *LoadOrderGroupKey,
+ [out,unique] uint32 *TagId,
+ [in,unique] [string,charset(UTF16)] uint16 *dependencies,
+ [in,unique] [string,charset(UTF16)] uint16 *service_start_name,
+ [in,unique] [string,charset(UTF16)] uint16 *password
+ );
+
+ /*****************/
+ /* Function 0x19 */
+ WERROR svcctl_EnumDependentServicesA(
+ [in,ref] policy_handle *service,
+ [in] uint32 state,
+ [out,unique] ENUM_SERVICE_STATUS *service_status,
+ [in] uint32 buf_size,
+ [out,ref] uint32 *bytes_needed,
+ [out,ref] uint32 *services_returned
+ );
+
+ /*****************/
+ /* Function 0x1a */
+ WERROR svcctl_EnumServicesStatusA(
+ [in,ref] policy_handle *handle,
+ [in] uint32 type,
+ [in] uint32 state,
+ [in] uint32 buf_size,
+ [out,size_is(buf_size)] uint8 service[*],
+ [out,ref] uint32 *bytes_needed,
+ [out,ref] uint32 *services_returned,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /*****************/
+ /* Function 0x1b */
+ WERROR svcctl_OpenSCManagerA(
+ [in,unique] [string,charset(UTF16)] uint16 *MachineName,
+ [in,unique] [string,charset(UTF16)] uint16 *DatabaseName,
+ [in] uint32 access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /*****************/
+ /* Function 0x1c */
+ WERROR svcctl_OpenServiceA(
+ [in,ref] policy_handle *scmanager_handle,
+ [in,unique] [string,charset(UTF16)] uint16 *ServiceName,
+ [in] uint32 access_mask
+ );
+
+ /*****************/
+ /* Function 0x1d */
+ WERROR svcctl_QueryServiceConfigA(
+ [in,ref] policy_handle *handle,
+ [out] uint8 query[buf_size], /*QUERYU_SERVICE_CONFIG */
+ [in] uint32 buf_size,
+ [out,ref] uint32 *bytes_needed
+ );
+
+ /*****************/
+ /* Function 0x1e */
+ WERROR svcctl_QueryServiceLockStatusA(
+ [in,ref] policy_handle *handle,
+ [in] uint32 buf_size,
+ [out,ref] SERVICE_LOCK_STATUS *lock_status,
+ [out,ref] uint32 *required_buf_size
+ );
+
+ /*****************/
+ /* Function 0x1f */
+ WERROR svcctl_StartServiceA(
+ [in,ref] policy_handle *handle,
+ [in] uint32 NumArgs,
+ [in,unique/*FIXME:,length_is(NumArgs)*/] [string,charset(UTF16)] uint16 *Arguments
+ );
+
+ /*****************/
+ /* Function 0x20 */
+ WERROR svcctl_GetServiceDisplayNameA(
+ [in,ref] policy_handle *handle,
+ [in,unique] [string,charset(UTF16)] uint16 *service_name,
+ [out,ref] [string,charset(UTF16)] uint16 **display_name,
+ [in,out,unique] uint32 *display_name_length
+ );
+
+ /*****************/
+ /* Function 0x21 */
+ WERROR svcctl_GetServiceKeyNameA(
+ [in,ref] policy_handle *handle,
+ [in,unique] [string,charset(UTF16)] uint16 *service_name,
+ [out,ref] [string,charset(UTF16)] uint16 **key_name,
+ [in,out,unique] uint32 *display_name_length
+ );
+
+ /*****************/
+ /* Function 0x22 */
+ WERROR svcctl_GetCurrentGroupeStateW(
+ );
+
+ /*****************/
+ /* Function 0x23 */
+ WERROR svcctl_EnumServiceGroupW(
+ );
+
+ /*****************/
+ /* Function 0x24 */
+ WERROR svcctl_ChangeServiceConfig2A(
+ [in,ref] policy_handle *handle,
+ [in] uint32 info_level,
+ [in,unique] uint8 *info
+ );
+
+ /*****************/
+ /* Function 0x25 */
+ WERROR svcctl_ChangeServiceConfig2W(
+ [in,ref] policy_handle *handle,
+ [in] uint32 info_level,
+ [in,unique] uint8 *info
+ );
+
+ /*****************/
+ /* Function 0x26 */
+ WERROR svcctl_QueryServiceConfig2A(
+ [in,ref] policy_handle *handle,
+ [in] uint32 info_level,
+ [out] uint8 buffer[buf_size],
+ [in] uint32 buf_size,
+ [out,ref] uint32 *bytes_needed
+ );
+
+ /*****************/
+ /* Function 0x27 */
+ WERROR svcctl_QueryServiceConfig2W(
+ [in,ref] policy_handle *handle,
+ [in] uint32 info_level,
+ [out] uint8 buffer[buf_size],
+ [in] uint32 buf_size,
+ [out,ref] uint32 *bytes_needed
+ );
+
+ /*****************/
+ /* Function 0x28 */
+ WERROR svcctl_QueryServiceStatusEx(
+ [in,ref] policy_handle *handle,
+ [in] uint32 info_level,
+ [out] uint8 buffer[buf_size],
+ [in] uint32 buf_size,
+ [out,ref] uint32 *bytes_needed
+ );
+
+ /*****************/
+ /* Function 0x29 */
+ WERROR EnumServicesStatusExA(
+ [in,ref] policy_handle *scmanager,
+ [in] uint32 info_level,
+ [in] uint32 type,
+ [in] uint32 state,
+ [out] uint8 services[buf_size],
+ [in] uint32 buf_size,
+ [out,ref] uint32 *bytes_needed,
+ [out,ref] uint32 *service_returned,
+ [in,out,unique] uint32 *resume_handle,
+ [out,ref] [string,charset(UTF16)] uint16 **group_name
+ );
+
+ /*****************/
+ /* Function 0x2a */
+ WERROR EnumServicesStatusExW(
+ [in,ref] policy_handle *scmanager,
+ [in] uint32 info_level,
+ [in] uint32 type,
+ [in] uint32 state,
+ [out] uint8 services[buf_size],
+ [in] uint32 buf_size,
+ [out,ref] uint32 *bytes_needed,
+ [out,ref] uint32 *service_returned,
+ [in,out,unique] uint32 *resume_handle,
+ [out,ref] [string,charset(UTF16)] uint16 **group_name
+ );
+
+ /*****************/
+ /* Function 0x2b */
+ WERROR svcctl_SCSendTSMessage(
+ );
+}
diff --git a/source3/librpc/idl/winreg.idl b/source3/librpc/idl/winreg.idl
new file mode 100644
index 0000000000..2f02419af5
--- /dev/null
+++ b/source3/librpc/idl/winreg.idl
@@ -0,0 +1,395 @@
+/*
+ winreg interface definition
+*/
+
+import "lsa.idl", "initshutdown.idl", "security.idl";
+
+[
+ uuid("338cd001-2244-31f1-aaaa-900038001003"),
+ version(1.0),
+ endpoint("ncacn_np:[\\pipe\\winreg]","ncacn_ip_tcp:","ncalrpc:"),
+ pointer_default(unique),
+ helpstring("Remote Registry Service")
+] interface winreg
+{
+ typedef bitmap security_secinfo security_secinfo;
+
+ typedef [bitmap32bit] bitmap {
+ KEY_QUERY_VALUE = 0x00001,
+ KEY_SET_VALUE = 0x00002,
+ KEY_CREATE_SUB_KEY = 0x00004,
+ KEY_ENUMERATE_SUB_KEYS = 0x00008,
+ KEY_NOTIFY = 0x00010,
+ KEY_CREATE_LINK = 0x00020,
+ KEY_WOW64_64KEY = 0x00100,
+ KEY_WOW64_32KEY = 0x00200
+ } winreg_AccessMask;
+
+ typedef [v1_enum] enum {
+ REG_NONE = 0,
+ REG_SZ = 1,
+ REG_EXPAND_SZ = 2,
+ REG_BINARY = 3,
+ REG_DWORD = 4,
+ REG_DWORD_BIG_ENDIAN = 5,
+ REG_LINK = 6,
+ REG_MULTI_SZ = 7,
+ REG_RESOURCE_LIST = 8,
+ REG_FULL_RESOURCE_DESCRIPTOR = 9,
+ REG_RESOURCE_REQUIREMENTS_LIST = 10,
+ REG_QWORD = 11
+ } winreg_Type;
+
+ typedef [public,noejs] struct {
+ [value(strlen_m_term(name)*2)] uint16 name_len;
+ [value(strlen_m_term(name)*2)] uint16 name_size;
+ [string,charset(UTF16)] uint16 *name;
+ } winreg_String;
+
+ /******************/
+ /* Function: 0x00 */
+ WERROR winreg_OpenHKCR(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x01 */
+ WERROR winreg_OpenHKCU(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x02 */
+ WERROR winreg_OpenHKLM(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x03 */
+ WERROR winreg_OpenHKPD(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x04 */
+ WERROR winreg_OpenHKU(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x05 */
+ WERROR winreg_CloseKey(
+ [in,out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x06 */
+
+ typedef struct {
+ [size_is(size),length_is(len)] uint8 *data;
+ uint32 size;
+ uint32 len;
+ } KeySecurityData;
+
+ typedef struct {
+ uint32 length;
+ KeySecurityData sd;
+ boolean8 inherit;
+ } winreg_SecBuf;
+
+ typedef [v1_enum] enum {
+ REG_ACTION_NONE = 0, /* used by caller */
+ REG_CREATED_NEW_KEY = 1,
+ REG_OPENED_EXISTING_KEY = 2
+ } winreg_CreateAction;
+
+ WERROR winreg_CreateKey(
+ [in,ref] policy_handle *handle,
+ [in] winreg_String name,
+ [in] winreg_String keyclass,
+ [in] uint32 options,
+ [in] winreg_AccessMask access_mask,
+ [in,unique] winreg_SecBuf *secdesc,
+ [out,ref] policy_handle *new_handle,
+ [in,out,unique] winreg_CreateAction *action_taken
+ );
+
+ /******************/
+ /* Function: 0x07 */
+ WERROR winreg_DeleteKey(
+ [in,ref] policy_handle *handle,
+ [in] winreg_String key
+ );
+
+ /******************/
+ /* Function: 0x08 */
+ WERROR winreg_DeleteValue(
+ [in,ref] policy_handle *handle,
+ [in] winreg_String value
+ );
+
+ typedef struct {
+ [value(strlen_m_term_null(name)*2)] uint16 length;
+ /* size cannot be auto-set by value() as it is the
+ amount of space the server is allowed to use for this
+ string in the reply, not its current size */
+ uint16 size;
+ [size_is(size/2),length_is(length/2),charset(UTF16)] uint16 *name;
+ } winreg_StringBuf;
+
+ /******************/
+ /* Function: 0x09 */
+ WERROR winreg_EnumKey(
+ [in,ref] policy_handle *handle,
+ [in] uint32 enum_index,
+ [in,out,ref] winreg_StringBuf *name,
+ [in,out,unique] winreg_StringBuf *keyclass,
+ [in,out,unique] NTTIME *last_changed_time
+ );
+
+ typedef struct {
+ [value(strlen_m_term(name)*2)] uint16 length;
+ /* size cannot be auto-set by value() as it is the
+ amount of space the server is allowed to use for this
+ string in the reply, not its current size */
+ uint16 size;
+ [size_is(size/2),length_is(length/2),charset(UTF16)] uint16 *name;
+ } winreg_ValNameBuf;
+
+ /******************/
+ /* Function: 0x0a */
+
+ WERROR winreg_EnumValue(
+ [in,ref] policy_handle *handle,
+ [in] uint32 enum_index,
+ [in,out,ref] winreg_ValNameBuf *name,
+ [in,out,unique] winreg_Type *type,
+ [in,out,unique,size_is(*size),length_is(*length)] uint8 *value,
+ [in,out,unique] uint32 *size,
+ [in,out,unique] uint32 *length
+ );
+
+ /******************/
+ /* Function: 0x0b */
+ WERROR winreg_FlushKey(
+ [in,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x0c */
+ WERROR winreg_GetKeySecurity(
+ [in,ref] policy_handle *handle,
+ [in] security_secinfo sec_info,
+ [in,out,ref] KeySecurityData *sd
+ );
+
+ /******************/
+ /* Function: 0x0d */
+ WERROR winreg_LoadKey(
+ [in,ref] policy_handle *handle,
+ [in,unique] winreg_String *keyname,
+ [in,unique] winreg_String *filename
+ );
+
+ /******************/
+ /* Function: 0x0e */
+ WERROR winreg_NotifyChangeKeyValue(
+ [in,ref] policy_handle *handle,
+ [in] uint8 watch_subtree,
+ [in] uint32 notify_filter,
+ [in] uint32 unknown,
+ [in] winreg_String string1,
+ [in] winreg_String string2,
+ [in] uint32 unknown2
+ );
+
+ /******************/
+ /* Function: 0x0f */
+ WERROR winreg_OpenKey(
+ [in,ref] policy_handle *parent_handle,
+ [in] winreg_String keyname,
+ [in] uint32 unknown,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x10 */
+ WERROR winreg_QueryInfoKey(
+ [in,ref] policy_handle *handle,
+ [in,out,ref] winreg_String *classname,
+ [out,ref] uint32 *num_subkeys,
+ [out,ref] uint32 *max_subkeylen,
+ [out,ref] uint32 *max_classlen,
+ [out,ref] uint32 *num_values,
+ [out,ref] uint32 *max_valnamelen,
+ [out,ref] uint32 *max_valbufsize,
+ [out,ref] uint32 *secdescsize,
+ [out,ref] NTTIME *last_changed_time
+ );
+
+ /******************/
+ /* Function: 0x11 */
+ WERROR winreg_QueryValue(
+ [in,ref] policy_handle *handle,
+ [in,ref] winreg_String *value_name,
+ [in,out,unique] winreg_Type *type,
+ [in,out,unique,size_is(*data_size),length_is(*value_length)] uint8 *data,
+ [in,out,unique] uint32 *data_size,
+ [in,out,unique] uint32 *value_length
+ );
+
+ /******************/
+ /* Function: 0x12 */
+ WERROR winreg_ReplaceKey(
+ );
+
+ /******************/
+ /* Function: 0x13 */
+ WERROR winreg_RestoreKey(
+ [in,ref] policy_handle *handle,
+ [in,ref] winreg_String *filename,
+ [in] uint32 flags
+ );
+
+ /******************/
+ /* Function: 0x14 */
+
+ typedef struct {
+ uint32 data_size;
+ KeySecurityData sec_data;
+ uint8 inherit;
+ } KeySecurityAttribute;
+
+ WERROR winreg_SaveKey(
+ [in,ref] policy_handle *handle,
+ [in,ref] winreg_String *filename,
+ [in,unique] KeySecurityAttribute *sec_attrib
+ );
+
+ /******************/
+ /* Function: 0x15 */
+ WERROR winreg_SetKeySecurity(
+ [in,ref] policy_handle *handle,
+ [in] winreg_AccessMask access_mask,
+ [in,ref] KeySecurityData *sd
+ );
+
+ /******************/
+ /* Function: 0x16 */
+ WERROR winreg_SetValue(
+ [in,ref] policy_handle *handle,
+ [in] winreg_String name,
+ [in] winreg_Type type,
+ [in,size_is(size),ref] uint8 *data,
+ [in] uint32 size
+ );
+
+ /******************/
+ /* Function: 0x17 */
+ WERROR winreg_UnLoadKey(
+ );
+
+ /******************/
+ /* Function: 0x18 */
+ WERROR winreg_InitiateSystemShutdown(
+ [in,unique] uint16 *hostname,
+ [in,unique] initshutdown_String *message,
+ [in] uint32 timeout,
+ [in] uint8 force_apps,
+ [in] uint8 do_reboot
+ );
+
+ /******************/
+ /* Function: 0x19 */
+ WERROR winreg_AbortSystemShutdown(
+ [in,unique] uint16 *server
+ );
+
+ /******************/
+ /* Function: 0x1a */
+ WERROR winreg_GetVersion(
+ [in,ref] policy_handle *handle,
+ [out,ref] uint32 *version
+ );
+
+ /******************/
+ /* Function: 0x1b */
+ WERROR winreg_OpenHKCC(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x1c */
+ WERROR winreg_OpenHKDD(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ typedef struct {
+ winreg_String *name;
+ winreg_Type type;
+ uint32 offset;
+ uint32 length;
+ } QueryMultipleValue;
+
+ /******************/
+ /* Function: 0x1d */
+ WERROR winreg_QueryMultipleValues(
+ [in,ref] policy_handle *key_handle,
+ [in,out,ref,size_is(num_values),length_is(num_values)] QueryMultipleValue *values,
+ [in] uint32 num_values,
+ [in,out,unique,size_is(*buffer_size),length_is(*buffer_size)] uint8 *buffer,
+ [in,out,ref] uint32 *buffer_size
+ );
+
+ /******************/
+ /* Function: 0x1e */
+ WERROR winreg_InitiateSystemShutdownEx(
+ [in,unique] uint16 *hostname,
+ [in,unique] initshutdown_String *message,
+ [in] uint32 timeout,
+ [in] uint8 force_apps,
+ [in] uint8 do_reboot,
+ [in] uint32 reason
+ );
+
+ /******************/
+ /* Function: 0x1f */
+ WERROR winreg_SaveKeyEx(
+ );
+
+ /******************/
+ /* Function: 0x20 */
+ WERROR winreg_OpenHKPT(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x21 */
+ WERROR winreg_OpenHKPN(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x22 */
+ WERROR winreg_QueryMultipleValues2(
+ );
+}
diff --git a/source3/librpc/idl/wkssvc.idl b/source3/librpc/idl/wkssvc.idl
new file mode 100644
index 0000000000..9340990e99
--- /dev/null
+++ b/source3/librpc/idl/wkssvc.idl
@@ -0,0 +1,795 @@
+#include "idl_types.h"
+
+/*
+ wkssvc interface definitions
+*/
+
+import "srvsvc.idl", "lsa.idl";
+
+[ uuid("6bffd098-a112-3610-9833-46c3f87e345a"),
+ version(1.0),
+ pointer_default(unique),
+ helpstring("Workstation Service"),
+ endpoint("ncacn_np:[\\pipe\\wkssvc]","ncacn_ip_tcp:","ncalrpc:")
+] interface wkssvc
+{
+ typedef [v1_enum] enum srvsvc_PlatformId srvsvc_PlatformId;
+
+#define BOOL uint32
+
+ /******************/
+ /* Function: 0x00 */
+
+ typedef struct {
+ srvsvc_PlatformId platform_id;
+ [string,charset(UTF16)] uint16 *server_name;
+ [string,charset(UTF16)] uint16 *domain_name;
+ uint32 version_major;
+ uint32 version_minor;
+ } wkssvc_NetWkstaInfo100;
+
+ typedef struct {
+ srvsvc_PlatformId platform_id;
+ [string,charset(UTF16)] uint16 *server_name;
+ [string,charset(UTF16)] uint16 *domain_name;
+ uint32 version_major;
+ uint32 version_minor;
+ [string,charset(UTF16)] uint16 *lan_root;
+ } wkssvc_NetWkstaInfo101;
+
+ typedef struct {
+ srvsvc_PlatformId platform_id;
+ [string,charset(UTF16)] uint16 *server_name;
+ [string,charset(UTF16)] uint16 *domain_name;
+ uint32 version_major;
+ uint32 version_minor;
+ [string,charset(UTF16)] uint16 *lan_root;
+ uint32 logged_on_users;
+ } wkssvc_NetWkstaInfo102;
+
+ /* FIXME: 302, 402 */
+
+ typedef struct {
+ uint32 char_wait;
+ uint32 collection_time;
+ uint32 maximum_collection_count;
+ uint32 keep_connection;
+ uint32 max_commands;
+ uint32 session_timeout;
+ uint32 size_char_buf;
+ uint32 max_threads;
+ uint32 lock_quota;
+ uint32 lock_increment;
+ uint32 lock_maximum;
+ uint32 pipe_increment;
+ uint32 pipe_maximum;
+ uint32 cache_file_timeout;
+ uint32 dormant_file_limit;
+ uint32 read_ahead_throughput;
+ uint32 num_mailslot_buffers;
+ uint32 num_srv_announce_buffers;
+ uint32 max_illegal_dgram_events;
+ uint32 dgram_event_reset_freq;
+ BOOL log_election_packets;
+ BOOL use_opportunistic_locking;
+ BOOL use_unlock_behind;
+ BOOL use_close_behind;
+ BOOL buf_named_pipes;
+ BOOL use_lock_read_unlock;
+ BOOL utilize_nt_caching;
+ BOOL use_raw_read;
+ BOOL use_raw_write;
+ BOOL use_write_raw_data;
+ BOOL use_encryption;
+ BOOL buf_files_deny_write;
+ BOOL buf_read_only_files;
+ BOOL force_core_create_mode;
+ BOOL use_512_byte_max_transfer;
+ } wkssvc_NetWkstaInfo502;
+
+ typedef struct {
+ uint32 char_wait;
+ } wkssvc_NetWkstaInfo1010;
+
+ typedef struct {
+ uint32 collection_time;
+ } wkssvc_NetWkstaInfo1011;
+
+ typedef struct {
+ uint32 maximum_collection_count;
+ } wkssvc_NetWkstaInfo1012;
+
+ typedef struct {
+ uint32 keep_connection;
+ } wkssvc_NetWkstaInfo1013;
+
+ typedef struct {
+ uint32 session_timeout;
+ } wkssvc_NetWkstaInfo1018;
+
+ typedef struct {
+ uint32 size_char_buf;
+ } wkssvc_NetWkstaInfo1023;
+
+ typedef struct {
+ uint32 errorlog_sz;
+ } wkssvc_NetWkstaInfo1027;
+
+ /* downlevel */
+ typedef struct {
+ uint32 print_buf_time;
+ } wkssvc_NetWkstaInfo1028;
+
+ /* downlevel */
+ typedef struct {
+ uint32 wrk_heuristics;
+ } wkssvc_NetWkstaInfo1032;
+
+ typedef struct {
+ uint32 max_threads;
+ } wkssvc_NetWkstaInfo1033;
+
+ typedef struct {
+ uint32 lock_quota;
+ } wkssvc_NetWkstaInfo1041;
+
+ typedef struct {
+ uint32 lock_increment;
+ } wkssvc_NetWkstaInfo1042;
+
+ typedef struct {
+ uint32 lock_maximum;
+ } wkssvc_NetWkstaInfo1043;
+
+ typedef struct {
+ uint32 pipe_increment;
+ } wkssvc_NetWkstaInfo1044;
+
+ typedef struct {
+ uint32 pipe_maximum;
+ } wkssvc_NetWkstaInfo1045;
+
+ typedef struct {
+ uint32 dormant_file_limit;
+ } wkssvc_NetWkstaInfo1046;
+
+ typedef struct {
+ uint32 cache_file_timeout;
+ } wkssvc_NetWkstaInfo1047;
+
+ typedef struct {
+ uint32 use_opportunistic_locking;
+ } wkssvc_NetWkstaInfo1048;
+
+ typedef struct {
+ uint32 use_unlock_behind;
+ } wkssvc_NetWkstaInfo1049;
+
+ typedef struct {
+ uint32 use_close_behind;
+ } wkssvc_NetWkstaInfo1050;
+
+ typedef struct {
+ uint32 buf_named_pipes;
+ } wkssvc_NetWkstaInfo1051;
+
+ typedef struct {
+ uint32 use_lock_read_unlock;
+ } wkssvc_NetWkstaInfo1052;
+
+ typedef struct {
+ uint32 utilize_nt_caching;
+ } wkssvc_NetWkstaInfo1053;
+
+ typedef struct {
+ uint32 use_raw_read;
+ } wkssvc_NetWkstaInfo1054;
+
+ typedef struct {
+ uint32 use_raw_write;
+ } wkssvc_NetWkstaInfo1055;
+
+ typedef struct {
+ uint32 use_write_raw_data;
+ } wkssvc_NetWkstaInfo1056;
+
+ typedef struct {
+ uint32 use_encryption;
+ } wkssvc_NetWkstaInfo1057;
+
+ typedef struct {
+ uint32 buf_files_deny_write;
+ } wkssvc_NetWkstaInfo1058;
+
+ typedef struct {
+ uint32 buf_read_only_files;
+ } wkssvc_NetWkstaInfo1059;
+
+ typedef struct {
+ uint32 force_core_create_mode;
+ } wkssvc_NetWkstaInfo1060;
+
+ typedef struct {
+ uint32 use_512_byte_max_transfer;
+ } wkssvc_NetWkstaInfo1061;
+
+ typedef struct {
+ uint32 read_ahead_throughput;
+ } wkssvc_NetWkstaInfo1062;
+
+ typedef union {
+ [case(100)] wkssvc_NetWkstaInfo100 *info100;
+ [case(101)] wkssvc_NetWkstaInfo101 *info101;
+ [case(102)] wkssvc_NetWkstaInfo102 *info102;
+ [case(502)] wkssvc_NetWkstaInfo502 *info502;
+ [case(1010)] wkssvc_NetWkstaInfo1010 *info1010;
+ [case(1011)] wkssvc_NetWkstaInfo1011 *info1011;
+ [case(1012)] wkssvc_NetWkstaInfo1012 *info1012;
+ [case(1013)] wkssvc_NetWkstaInfo1013 *info1013;
+ [case(1018)] wkssvc_NetWkstaInfo1018 *info1018;
+ [case(1023)] wkssvc_NetWkstaInfo1023 *info1023;
+ [case(1027)] wkssvc_NetWkstaInfo1027 *info1027;
+ [case(1028)] wkssvc_NetWkstaInfo1028 *info1028;
+ [case(1032)] wkssvc_NetWkstaInfo1032 *info1032;
+ [case(1033)] wkssvc_NetWkstaInfo1033 *info1033;
+ [case(1041)] wkssvc_NetWkstaInfo1041 *info1041;
+ [case(1042)] wkssvc_NetWkstaInfo1042 *info1042;
+ [case(1043)] wkssvc_NetWkstaInfo1043 *info1043;
+ [case(1044)] wkssvc_NetWkstaInfo1044 *info1044;
+ [case(1045)] wkssvc_NetWkstaInfo1045 *info1045;
+ [case(1046)] wkssvc_NetWkstaInfo1046 *info1046;
+ [case(1047)] wkssvc_NetWkstaInfo1047 *info1047;
+ [case(1048)] wkssvc_NetWkstaInfo1048 *info1048;
+ [case(1049)] wkssvc_NetWkstaInfo1049 *info1049;
+ [case(1050)] wkssvc_NetWkstaInfo1050 *info1050;
+ [case(1051)] wkssvc_NetWkstaInfo1051 *info1051;
+ [case(1052)] wkssvc_NetWkstaInfo1052 *info1052;
+ [case(1053)] wkssvc_NetWkstaInfo1053 *info1053;
+ [case(1054)] wkssvc_NetWkstaInfo1054 *info1054;
+ [case(1055)] wkssvc_NetWkstaInfo1055 *info1055;
+ [case(1056)] wkssvc_NetWkstaInfo1056 *info1056;
+ [case(1057)] wkssvc_NetWkstaInfo1057 *info1057;
+ [case(1058)] wkssvc_NetWkstaInfo1058 *info1058;
+ [case(1059)] wkssvc_NetWkstaInfo1059 *info1059;
+ [case(1060)] wkssvc_NetWkstaInfo1060 *info1060;
+ [case(1061)] wkssvc_NetWkstaInfo1061 *info1061;
+ [case(1062)] wkssvc_NetWkstaInfo1062 *info1062;
+ [default] ;
+ } wkssvc_NetWkstaInfo;
+
+ WERROR wkssvc_NetWkstaGetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] uint32 level,
+ [out,switch_is(level),ref] wkssvc_NetWkstaInfo *info
+ );
+
+
+ /******************/
+ /* Function: 0x01 */
+ WERROR wkssvc_NetWkstaSetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] uint32 level,
+ [in,switch_is(level),ref] wkssvc_NetWkstaInfo *info,
+ [in,out,ref] uint32 *parm_error
+ );
+
+
+ /*****************************/
+ /* Function 0x02 */
+ typedef struct {
+ [string,charset(UTF16)] uint16 *user_name;
+ } wkssvc_NetrWkstaUserInfo0;
+
+ typedef struct {
+ uint32 entries_read;
+ [size_is(entries_read)] wkssvc_NetrWkstaUserInfo0 *user0;
+ } wkssvc_NetWkstaEnumUsersCtr0;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *user_name;
+ [string,charset(UTF16)] uint16 *logon_domain;
+ [string,charset(UTF16)] uint16 *other_domains;
+ [string,charset(UTF16)] uint16 *logon_server;
+ } wkssvc_NetrWkstaUserInfo1;
+
+ typedef struct {
+ uint32 entries_read;
+ [size_is(entries_read)] wkssvc_NetrWkstaUserInfo1 *user1;
+ } wkssvc_NetWkstaEnumUsersCtr1;
+
+ typedef [switch_type(uint32)] union {
+ [case(0)] wkssvc_NetWkstaEnumUsersCtr0 *user0;
+ [case(1)] wkssvc_NetWkstaEnumUsersCtr1 *user1;
+ } wkssvc_NetWkstaEnumUsersCtr;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] wkssvc_NetWkstaEnumUsersCtr ctr;
+ } wkssvc_NetWkstaEnumUsersInfo;
+
+ WERROR wkssvc_NetWkstaEnumUsers(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,out,ref] wkssvc_NetWkstaEnumUsersInfo *info,
+ [in] uint32 prefmaxlen,
+ [out,ref] uint32 *entries_read,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /*****************************/
+ /* Function 0x03 */
+ typedef struct {
+ [string,charset(UTF16)] uint16 *other_domains;
+ } wkssvc_NetrWkstaUserInfo1101;
+
+ typedef [switch_type(uint32)] union {
+ [case(0)] wkssvc_NetrWkstaUserInfo0 *info0;
+ [case(1)] wkssvc_NetrWkstaUserInfo1 *info1;
+ [case(1101)] wkssvc_NetrWkstaUserInfo1101 *info1101;
+ } wkssvc_NetrWkstaUserInfo;
+
+ WERROR wkssvc_NetrWkstaUserGetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *unknown,
+ [in] uint32 level,
+ [out,ref] [switch_is(level)] wkssvc_NetrWkstaUserInfo *info
+ );
+
+ /*****************************/
+ /* Function 0x04 */
+ WERROR wkssvc_NetrWkstaUserSetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *unknown,
+ [in] uint32 level,
+ [in,ref] [switch_is(level)] wkssvc_NetrWkstaUserInfo *info,
+ [in,out,unique] uint32 *parm_err
+ );
+
+ /*****************************/
+ /* Function 0x05 */
+
+ typedef struct {
+ uint32 quality_of_service;
+ uint32 vc_count;
+ [string,charset(UTF16)] uint16 *name;
+ [string,charset(UTF16)] uint16 *address;
+ uint32 wan_link;
+ } wkssvc_NetWkstaTransportInfo0;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] wkssvc_NetWkstaTransportInfo0 *array;
+ } wkssvc_NetWkstaTransportCtr0;
+
+ typedef union {
+ [case(0)] wkssvc_NetWkstaTransportCtr0 *ctr0;
+ } wkssvc_NetWkstaTransportCtr;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] wkssvc_NetWkstaTransportCtr ctr;
+ } wkssvc_NetWkstaTransportInfo;
+
+ WERROR wkssvc_NetWkstaTransportEnum (
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,out,ref] wkssvc_NetWkstaTransportInfo *info,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *total_entries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /*****************************/
+ /* Function 0x06 */
+ /* only supported on NT */
+ WERROR wkssvc_NetrWkstaTransportAdd(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] uint32 level, /* must be 0 */
+ [in,ref] wkssvc_NetWkstaTransportInfo0 *info0,
+ [in,out,unique] uint32 *parm_err
+ );
+
+ /*****************************/
+ /* Function 0x07 */
+ /* only supported on NT */
+ WERROR wkssvc_NetrWkstaTransportDel(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *transport_name,
+ [in] uint32 unknown3
+ );
+
+ /*****************************/
+ /* Function 0x08 */
+ typedef struct {
+ [string,charset(UTF16)] uint16 *unknown1;
+ [string,charset(UTF16)] uint16 *unknown2;
+ } wkssvc_NetrUseInfo3;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *local;
+ [string,charset(UTF16)] uint16 *remote;
+ [string,charset(UTF16)] uint16 *password;
+ uint32 status;
+ uint32 asg_type;
+ uint32 ref_count;
+ uint32 use_count;
+ [string,charset(UTF16)] uint16 *user_name;
+ [string,charset(UTF16)] uint16 *domain_name;
+ } wkssvc_NetrUseInfo2;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *local;
+ [string,charset(UTF16)] uint16 *remote;
+ [string,charset(UTF16)] uint16 *password;
+ uint32 status;
+ uint32 asg_type;
+ uint32 ref_count;
+ uint32 use_count;
+ } wkssvc_NetrUseInfo1;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *local;
+ [string,charset(UTF16)] uint16 *remote;
+ } wkssvc_NetrUseInfo0;
+
+ typedef [switch_type(uint32)] union {
+ [case(0)] wkssvc_NetrUseInfo0 *info0;
+ [case(1)] wkssvc_NetrUseInfo1 *info1;
+ [case(2)] wkssvc_NetrUseInfo2 *info2;
+ [case(3)] wkssvc_NetrUseInfo3 *info3;
+ } wkssvc_NetrUseGetInfoCtr;
+
+ WERROR wkssvc_NetrUseAdd(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] uint32 level,
+ [in,ref] [switch_is(level)] wkssvc_NetrUseGetInfoCtr *ctr,
+ [in,out,unique] uint32 *parm_err
+ );
+
+ /*****************************/
+ /* Function 0x09 */
+ WERROR wkssvc_NetrUseGetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *use_name,
+ [in] uint32 level,
+ [out,ref] [switch_is(level)] wkssvc_NetrUseGetInfoCtr *ctr
+ );
+
+ /*****************************/
+ /* Function 0x0a */
+ WERROR wkssvc_NetrUseDel(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *use_name,
+ [in] uint32 force_cond
+ );
+
+ /*****************************/
+ /* Function 0x0b */
+ typedef struct {
+ uint32 count;
+ [size_is(count)] wkssvc_NetrUseInfo2 *array;
+ } wkssvc_NetrUseEnumCtr2;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] wkssvc_NetrUseInfo1 *array;
+ } wkssvc_NetrUseEnumCtr1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] wkssvc_NetrUseInfo0 *array;
+ } wkssvc_NetrUseEnumCtr0;
+
+ typedef [switch_type(uint32)] union {
+ [case(0)] wkssvc_NetrUseEnumCtr0 *ctr0;
+ [case(1)] wkssvc_NetrUseEnumCtr1 *ctr1;
+ [case(2)] wkssvc_NetrUseEnumCtr2 *ctr2;
+ } wkssvc_NetrUseEnumCtr;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] wkssvc_NetrUseEnumCtr ctr;
+ } wkssvc_NetrUseEnumInfo;
+
+ WERROR wkssvc_NetrUseEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,out,ref] wkssvc_NetrUseEnumInfo *info,
+ [in] uint32 prefmaxlen,
+ [out,ref] uint32 *entries_read,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /*****************************/
+ /* Function 0x0c */
+ WERROR wkssvc_NetrMessageBufferSend(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *message_name,
+ [in,unique] [string,charset(UTF16)] uint16 *message_sender_name,
+ [in,ref] [size_is(message_size)] uint8 *message_buffer,
+ [in] uint32 message_size
+ );
+
+ /*****************************/
+ /* Function 0x0d */
+ typedef struct {
+ hyper unknown1;
+ hyper unknown2;
+ hyper unknown3;
+ hyper unknown4;
+ hyper unknown5;
+ hyper unknown6;
+ hyper unknown7;
+ hyper unknown8;
+ hyper unknown9;
+ hyper unknown10;
+ hyper unknown11;
+ hyper unknown12;
+ hyper unknown13;
+ uint32 unknown14;
+ uint32 unknown15;
+ uint32 unknown16;
+ uint32 unknown17;
+ uint32 unknown18;
+ uint32 unknown19;
+ uint32 unknown20;
+ uint32 unknown21;
+ uint32 unknown22;
+ uint32 unknown23;
+ uint32 unknown24;
+ uint32 unknown25;
+ uint32 unknown26;
+ uint32 unknown27;
+ uint32 unknown28;
+ uint32 unknown29;
+ uint32 unknown30;
+ uint32 unknown31;
+ uint32 unknown32;
+ uint32 unknown33;
+ uint32 unknown34;
+ uint32 unknown35;
+ uint32 unknown36;
+ uint32 unknown37;
+ uint32 unknown38;
+ uint32 unknown39;
+ uint32 unknown40;
+ } wkssvc_NetrWorkstationStatistics;
+
+ WERROR wkssvc_NetrWorkstationStatisticsGet(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *unknown2,
+ [in] uint32 unknown3,
+ [in] uint32 unknown4,
+ [out,ref] wkssvc_NetrWorkstationStatistics **info
+ );
+
+ /*****************************/
+ /* Function 0x0e */
+ WERROR wkssvc_NetrLogonDomainNameAdd(
+ [in,ref] [string,charset(UTF16)] uint16 *domain_name
+ );
+
+ /*****************************/
+ /* Function 0x0f */
+ WERROR wkssvc_NetrLogonDomainNameDel(
+ [in,ref] [string,charset(UTF16)] uint16 *domain_name
+ );
+
+ /*****************************/
+ /* Function 0x10 */
+ WERROR wkssvc_NetrJoinDomain(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *domain_name,
+ [in,unique] [string,charset(UTF16)] uint16 *account_ou,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] [string,charset(UTF16)] uint16 *password,
+ [in] wkssvc_joinflags join_flags
+ );
+
+ /*****************************/
+ /* Function 0x11 */
+ WERROR wkssvc_NetrUnjoinDomain(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] [string,charset(UTF16)] uint16 *password,
+ [in] wkssvc_joinflags unjoin_flags
+ );
+
+ /*****************************/
+ /* Function 0x12 */
+ typedef [bitmap32bit] bitmap {
+ /* TRUE: create the account in the domain */
+ WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE = 0x00000002
+ } wkssvc_renameflags;
+
+ WERROR wkssvc_NetrRenameMachineInDomain(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *NewMachineName,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] [string,charset(UTF16)] uint16 *password,
+ [in] wkssvc_renameflags RenameOptions
+ );
+
+ /*****************************/
+ /* Function 0x13 */
+ typedef enum {
+ NetSetupUnknown = 0,
+ NetSetupMachine = 1,
+ NetSetupWorkgroup = 2,
+ NetSetupDomain = 3,
+ NetSetupNonExistentDomain = 4,
+ NetSetupDnsMachine = 5
+ } wkssvc_NetValidateNameType;
+
+ WERROR wkssvc_NetrValidateName(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *name,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] [string,charset(UTF16)] uint16 *Password,
+ [in] wkssvc_NetValidateNameType name_type
+ );
+
+ /*****************************/
+ /* Function 0x14 */
+ typedef enum {
+ NET_SETUP_UNKNOWN_STATUS = 0,
+ NET_SETUP_UNJOINED = 1,
+ NET_SETUP_WORKGROUP_NAME = 2,
+ NET_SETUP_DOMAIN_NAME = 3
+ } wkssvc_NetJoinStatus;
+
+ WERROR wkssvc_NetrGetJoinInformation(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,out,ref] [string,charset(UTF16)] uint16 **name_buffer,
+ [out,ref] wkssvc_NetJoinStatus *name_type
+ );
+
+ /*****************************/
+ /* Function 0x15 */
+ WERROR wkssvc_NetrGetJoinableOus(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *domain_name,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] [string,charset(UTF16)] uint16 *unknown,
+ [in,out,ref] uint32 *num_ous,
+ /*
+ * this is a [ref] pointer to a [unique] pointer to an
+ * array of [unique] pointers to a string array
+ */
+ [out,ref] [size_is(,*num_ous)] [string,charset(UTF16)] uint16 ***ous
+ );
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint8 data[524];
+ } wkssvc_PasswordBuffer;
+
+ typedef [bitmap32bit] bitmap {
+ WKSSVC_JOIN_FLAGS_JOIN_WITH_NEW_NAME = 0x00000400,
+ WKSSVC_JOIN_FLAGS_JOIN_DC_ACCOUNT = 0x00000200,
+ /* TRUE: defer setting the SPN and dNSHostName until a rename operation */
+ WKSSVC_JOIN_FLAGS_DEFER_SPN = 0x00000100,
+
+ /* TRUE: set the machine password to the provided one after the join completes */
+ WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED = 0x00000080,
+
+ /* TRUE: perform an unsecured join */
+ WKSSVC_JOIN_FLAGS_JOIN_UNSECURE = 0x00000040,
+
+ /* TRUE: allow the join to complete even if the account already exists */
+ WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED = 0x00000020,
+
+ /* TRUE: this join is part of a w9x upgrade */
+ WKSSVC_JOIN_FLAGS_WIN9X_UPGRADE = 0x00000010,
+
+ /* TRUE: delete the account when the domain is left */
+ WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE = 0x00000004,
+
+ /* TRUE: create the account in the domain */
+ WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE = 0x00000002,
+
+ /* TRUE: join domain FALSE: join workgroup */
+ WKSSVC_JOIN_FLAGS_JOIN_TYPE = 0x00000001
+
+ } wkssvc_joinflags;
+
+ /*****************************/
+ /* Function 0x16 */
+ WERROR wkssvc_NetrJoinDomain2 (
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *domain_name,
+ [in,unique] [string,charset(UTF16)] uint16 *account_ou,
+ [in,unique] [string,charset(UTF16)] uint16 *admin_account,
+ [in,unique] wkssvc_PasswordBuffer *encrypted_password,
+ [in] wkssvc_joinflags join_flags
+ );
+
+ /*****************************/
+ /* Function 0x17 */
+ WERROR wkssvc_NetrUnjoinDomain2 (
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *account,
+ [in,unique] wkssvc_PasswordBuffer *encrypted_password,
+ [in] wkssvc_joinflags unjoin_flags
+ );
+
+ /*****************************/
+ /* Function 0x18 */
+ WERROR wkssvc_NetrRenameMachineInDomain2(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *NewMachineName,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] wkssvc_PasswordBuffer *EncryptedPassword,
+ [in] wkssvc_renameflags RenameOptions
+ );
+
+ /*****************************/
+ /* Function 0x19 */
+ WERROR wkssvc_NetrValidateName2(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *name,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] wkssvc_PasswordBuffer *EncryptedPassword,
+ [in] wkssvc_NetValidateNameType name_type
+ );
+
+ /*****************************/
+ /* Function 0x1a */
+ WERROR wkssvc_NetrGetJoinableOus2(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *domain_name,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] wkssvc_PasswordBuffer *EncryptedPassword,
+ [in,out,ref] uint32 *num_ous,
+ /*
+ * this is a [ref] pointer to a [unique] pointer to an
+ * array of [unique] pointers to a string array
+ */
+ [out,ref] [size_is(,*num_ous)] [string,charset(UTF16)] uint16 ***ous
+ );
+
+ /*****************************/
+ /* Function 0x1b */
+ WERROR wkssvc_NetrAddAlternateComputerName(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *NewAlternateMachineName,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] wkssvc_PasswordBuffer *EncryptedPassword,
+ [in] uint32 Reserved
+ );
+
+ /*****************************/
+ /* Function 0x1c */
+ WERROR wkssvc_NetrRemoveAlternateComputerName(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *AlternateMachineNameToRemove,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] wkssvc_PasswordBuffer *EncryptedPassword,
+ [in] uint32 Reserved
+ );
+
+ /*****************************/
+ /* Function 0x1d */
+ WERROR wkssvc_NetrSetPrimaryComputername(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *primary_name,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] wkssvc_PasswordBuffer *EncryptedPassword,
+ [in] uint32 Reserved
+ );
+
+ /*****************************/
+ /* Function 0x1e */
+ typedef enum {
+ NetPrimaryComputerName = 0,
+ NetAlternateComputerNames = 1,
+ NetAllComputerNames = 2,
+ NetComputerNameTypeMax = 3
+ } wkssvc_ComputerNameType;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] lsa_String *computer_name;
+ } wkssvc_ComputerNamesCtr;
+
+ WERROR wkssvc_NetrEnumerateComputerNames(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] wkssvc_ComputerNameType name_type,
+ [in] uint32 Reserved,
+ [out,ref] wkssvc_ComputerNamesCtr **ctr
+ );
+}
diff --git a/source3/librpc/idl/xattr.idl b/source3/librpc/idl/xattr.idl
new file mode 100644
index 0000000000..23af2df404
--- /dev/null
+++ b/source3/librpc/idl/xattr.idl
@@ -0,0 +1,54 @@
+#include "idl_types.h"
+
+/*
+ IDL structures for xattrs
+*/
+
+[
+ pointer_default(unique)
+]
+interface xattr
+{
+ /* xattrs for file systems that don't have any */
+
+ typedef [public] struct {
+ utf8string name;
+ DATA_BLOB value;
+ } tdb_xattr;
+
+ typedef [public] struct {
+ uint32 num_xattrs;
+ tdb_xattr xattrs[num_xattrs];
+ } tdb_xattrs;
+
+ /* we store the NT ACL a NTACL xattr. It is versioned so we
+ can later add other acl attribs (such as posix acl mapping)
+
+ we put this xattr in the security namespace to ensure that
+ only trusted users can write to the ACL
+
+ stored in "security.NTACL"
+
+ Version 1. raw SD stored as Samba4 does it.
+ Version 2. raw SD + last changed timestamp so we
+ can discard if this doesn't match the POSIX st_ctime.
+ */
+
+ const char *XATTR_NTACL_NAME = "security.NTACL";
+
+ typedef [public] struct {
+ security_descriptor *sd;
+ NTTIME last_changed;
+ } security_descriptor_timestamp;
+
+ typedef [switch_type(uint16)] union {
+ [case(1)] security_descriptor *sd;
+ [case(2)] security_descriptor_timestamp *sd_ts;
+ } xattr_NTACL_Info;
+
+ typedef [public] struct {
+ uint16 version;
+ [switch_is(version)] xattr_NTACL_Info info;
+ } xattr_NTACL;
+
+}
diff --git a/source3/librpc/ndr/libndr.h b/source3/librpc/ndr/libndr.h
new file mode 100644
index 0000000000..155f5f1f7d
--- /dev/null
+++ b/source3/librpc/ndr/libndr.h
@@ -0,0 +1,354 @@
+/*
+ Unix SMB/CIFS implementation.
+ rpc interface definitions
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __LIBNDR_H__
+#define __LIBNDR_H__
+
+#define _PRINTF_ATTRIBUTE(a,b)
+
+#include "librpc/gen_ndr/misc.h"
+#include "librpc/gen_ndr/security.h"
+
+/*
+ this provides definitions for the libcli/rpc/ MSRPC library
+*/
+
+
+/*
+ this is used by the token store/retrieve code
+*/
+struct ndr_token_list {
+ struct ndr_token_list *next, *prev;
+ const void *key;
+ uint32_t value;
+};
+
+/* this is the base structure passed to routines that
+ parse MSRPC formatted data
+
+ note that in Samba4 we use separate routines and structures for
+ MSRPC marshalling and unmarshalling. Also note that these routines
+ are being kept deliberately very simple, and are not tied to a
+ particular transport
+*/
+struct ndr_pull {
+ uint32_t flags; /* LIBNDR_FLAG_* */
+ uint8_t *data;
+ uint32_t data_size;
+ uint32_t offset;
+
+ uint32_t relative_base_offset;
+ struct ndr_token_list *relative_base_list;
+
+ struct ndr_token_list *relative_list;
+ struct ndr_token_list *array_size_list;
+ struct ndr_token_list *array_length_list;
+ struct ndr_token_list *switch_list;
+
+ TALLOC_CTX *current_mem_ctx;
+
+ /* this is used to ensure we generate unique reference IDs
+ between request and reply */
+ uint32_t ptr_count;
+};
+
+struct ndr_pull_save {
+ uint32_t data_size;
+ uint32_t offset;
+ struct ndr_pull_save *next;
+};
+
+/* structure passed to functions that generate NDR formatted data */
+struct ndr_push {
+ uint32_t flags; /* LIBNDR_FLAG_* */
+ uint8_t *data;
+ uint32_t alloc_size;
+ uint32_t offset;
+
+ uint32_t relative_base_offset;
+ struct ndr_token_list *relative_base_list;
+
+ struct ndr_token_list *switch_list;
+ struct ndr_token_list *relative_list;
+ struct ndr_token_list *nbt_string_list;
+ struct ndr_token_list *full_ptr_list;
+
+ /* this is used to ensure we generate unique reference IDs */
+ uint32_t ptr_count;
+};
+
+struct ndr_push_save {
+ uint32_t offset;
+ struct ndr_push_save *next;
+};
+
+
+/* structure passed to functions that print IDL structures */
+struct ndr_print {
+ uint32_t flags; /* LIBNDR_FLAG_* */
+ uint32_t depth;
+ struct ndr_token_list *switch_list;
+ void (*print)(struct ndr_print *, const char *, ...) PRINTF_ATTRIBUTE(2,3);
+ void *private_data;
+};
+
+#define LIBNDR_FLAG_BIGENDIAN (1<<0)
+#define LIBNDR_FLAG_NOALIGN (1<<1)
+
+#define LIBNDR_FLAG_STR_ASCII (1<<2)
+#define LIBNDR_FLAG_STR_LEN4 (1<<3)
+#define LIBNDR_FLAG_STR_SIZE4 (1<<4)
+#define LIBNDR_FLAG_STR_NOTERM (1<<5)
+#define LIBNDR_FLAG_STR_NULLTERM (1<<6)
+#define LIBNDR_FLAG_STR_SIZE2 (1<<7)
+#define LIBNDR_FLAG_STR_BYTESIZE (1<<8)
+#define LIBNDR_FLAG_STR_FIXLEN32 (1<<9)
+#define LIBNDR_FLAG_STR_CONFORMANT (1<<10)
+#define LIBNDR_FLAG_STR_CHARLEN (1<<11)
+#define LIBNDR_FLAG_STR_UTF8 (1<<12)
+#define LIBNDR_FLAG_STR_FIXLEN15 (1<<13)
+#define LIBNDR_STRING_FLAGS (0x7FFC)
+
+
+#define LIBNDR_FLAG_REF_ALLOC (1<<20)
+#define LIBNDR_FLAG_REMAINING (1<<21)
+#define LIBNDR_FLAG_ALIGN2 (1<<22)
+#define LIBNDR_FLAG_ALIGN4 (1<<23)
+#define LIBNDR_FLAG_ALIGN8 (1<<24)
+
+#define LIBNDR_ALIGN_FLAGS (LIBNDR_FLAG_ALIGN2|LIBNDR_FLAG_ALIGN4|LIBNDR_FLAG_ALIGN8)
+
+#define LIBNDR_PRINT_ARRAY_HEX (1<<25)
+#define LIBNDR_PRINT_SET_VALUES (1<<26)
+
+/* used to force a section of IDL to be little-endian */
+#define LIBNDR_FLAG_LITTLE_ENDIAN (1<<27)
+
+/* used to check if alignment padding is zero */
+#define LIBNDR_FLAG_PAD_CHECK (1<<28)
+
+/* set if an object uuid will be present */
+#define LIBNDR_FLAG_OBJECT_PRESENT (1<<30)
+
+/* set to avoid recursion in ndr_size_*() calculation */
+#define LIBNDR_FLAG_NO_NDR_SIZE (1<<31)
+
+/* useful macro for debugging with DEBUG */
+#define NDR_PRINT_DEBUG(type, p) ndr_print_debug((ndr_print_fn_t)ndr_print_ ##type, #p, p)
+#define NDR_PRINT_UNION_DEBUG(type, level, p) ndr_print_union_debug((ndr_print_fn_t)ndr_print_ ##type, #p, level, p)
+#define NDR_PRINT_FUNCTION_DEBUG(type, flags, p) ndr_print_function_debug((ndr_print_function_t)ndr_print_ ##type, #type, flags, p)
+#define NDR_PRINT_BOTH_DEBUG(type, p) NDR_PRINT_FUNCTION_DEBUG(type, NDR_BOTH, p)
+#define NDR_PRINT_OUT_DEBUG(type, p) NDR_PRINT_FUNCTION_DEBUG(type, NDR_OUT, p)
+#define NDR_PRINT_IN_DEBUG(type, p) NDR_PRINT_FUNCTION_DEBUG(type, NDR_IN | NDR_SET_VALUES, p)
+
+/* useful macro for debugging in strings */
+#define NDR_PRINT_STRUCT_STRING(ctx, type, p) ndr_print_struct_string(ctx, (ndr_print_fn_t)ndr_print_ ##type, #p, p)
+#define NDR_PRINT_UNION_STRING(ctx, type, level, p) ndr_print_union_string(ctx, (ndr_print_fn_t)ndr_print_ ##type, #p, level, p)
+#define NDR_PRINT_FUNCTION_STRING(ctx, type, flags, p) ndr_print_function_string(ctx, (ndr_print_function_t)ndr_print_ ##type, #type, flags, p)
+#define NDR_PRINT_BOTH_STRING(ctx, type, p) NDR_PRINT_FUNCTION_STRING(ctx, type, NDR_BOTH, p)
+#define NDR_PRINT_OUT_STRING(ctx, type, p) NDR_PRINT_FUNCTION_STRING(ctx, type, NDR_OUT, p)
+#define NDR_PRINT_IN_STRING(ctx, type, p) NDR_PRINT_FUNCTION_STRING(ctx, type, NDR_IN | NDR_SET_VALUES, p)
+
+#define NDR_BE(ndr) (((ndr)->flags & (LIBNDR_FLAG_BIGENDIAN|LIBNDR_FLAG_LITTLE_ENDIAN)) == LIBNDR_FLAG_BIGENDIAN)
+
+enum ndr_err_code {
+ NDR_ERR_SUCCESS = 0,
+ NDR_ERR_ARRAY_SIZE,
+ NDR_ERR_BAD_SWITCH,
+ NDR_ERR_OFFSET,
+ NDR_ERR_RELATIVE,
+ NDR_ERR_CHARCNV,
+ NDR_ERR_LENGTH,
+ NDR_ERR_SUBCONTEXT,
+ NDR_ERR_COMPRESSION,
+ NDR_ERR_STRING,
+ NDR_ERR_VALIDATE,
+ NDR_ERR_BUFSIZE,
+ NDR_ERR_ALLOC,
+ NDR_ERR_RANGE,
+ NDR_ERR_TOKEN,
+ NDR_ERR_IPV4ADDRESS,
+ NDR_ERR_INVALID_POINTER,
+ NDR_ERR_UNREAD_BYTES
+};
+
+#define NDR_ERR_CODE_IS_SUCCESS(x) (x == NDR_ERR_SUCCESS)
+
+#define NDR_ERR_HAVE_NO_MEMORY(x) do { \
+ if (NULL == (x)) { \
+ return NDR_ERR_ALLOC; \
+ } \
+} while (0)
+
+enum ndr_compression_alg {
+ NDR_COMPRESSION_MSZIP = 2,
+ NDR_COMPRESSION_XPRESS = 3
+};
+
+/*
+ flags passed to control parse flow
+*/
+#define NDR_SCALARS 1
+#define NDR_BUFFERS 2
+
+/*
+ flags passed to ndr_print_*()
+*/
+#define NDR_IN 1
+#define NDR_OUT 2
+#define NDR_BOTH 3
+#define NDR_SET_VALUES 4
+
+#define NDR_PULL_NEED_BYTES(ndr, n) do { \
+ if ((n) > ndr->data_size || ndr->offset + (n) > ndr->data_size) { \
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "Pull bytes %u", (unsigned)n); \
+ } \
+} while(0)
+
+#define NDR_ALIGN(ndr, n) ndr_align_size(ndr->offset, n)
+
+#define NDR_ROUND(size, n) (((size)+((n)-1)) & ~((n)-1))
+
+#define NDR_PULL_ALIGN(ndr, n) do { \
+ if (!(ndr->flags & LIBNDR_FLAG_NOALIGN)) { \
+ if (ndr->flags & LIBNDR_FLAG_PAD_CHECK) { \
+ ndr_check_padding(ndr, n); \
+ } \
+ ndr->offset = (ndr->offset + (n-1)) & ~(n-1); \
+ } \
+ if (ndr->offset > ndr->data_size) { \
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "Pull align %u", (unsigned)n); \
+ } \
+} while(0)
+
+#define NDR_PUSH_NEED_BYTES(ndr, n) NDR_CHECK(ndr_push_expand(ndr, n))
+
+#define NDR_PUSH_ALIGN(ndr, n) do { \
+ if (!(ndr->flags & LIBNDR_FLAG_NOALIGN)) { \
+ uint32_t _pad = ((ndr->offset + (n-1)) & ~(n-1)) - ndr->offset; \
+ while (_pad--) NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 0)); \
+ } \
+} while(0)
+
+/* these are used to make the error checking on each element in libndr
+ less tedious, hopefully making the code more readable */
+#define NDR_CHECK(call) do { \
+ enum ndr_err_code _status; \
+ _status = call; \
+ if (!NDR_ERR_CODE_IS_SUCCESS(_status)) { \
+ return _status; \
+ } \
+} while (0)
+
+#define NDR_PULL_GET_MEM_CTX(ndr) (ndr->current_mem_ctx)
+
+#define NDR_PULL_SET_MEM_CTX(ndr, mem_ctx, flgs) do {\
+ if ( !(flgs) || (ndr->flags & flgs) ) {\
+ if (!(mem_ctx)) {\
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "NDR_PULL_SET_MEM_CTX(NULL): %s\n", __location__); \
+ }\
+ ndr->current_mem_ctx = discard_const(mem_ctx);\
+ }\
+} while(0)
+
+#define _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr) do {\
+ if (!ndr->current_mem_ctx) {\
+ ndr->current_mem_ctx = talloc_new(ndr);\
+ if (!ndr->current_mem_ctx) {\
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "_NDR_PULL_FIX_CURRENT_MEM_CTX() failed: %s\n", __location__); \
+ }\
+ }\
+} while(0)
+
+#define NDR_PULL_ALLOC(ndr, s) do { \
+ _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr);\
+ (s) = talloc_ptrtype(ndr->current_mem_ctx, (s)); \
+ if (!(s)) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Alloc %s failed: %s\n", # s, __location__); \
+} while (0)
+
+#define NDR_PULL_ALLOC_N(ndr, s, n) do { \
+ _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr);\
+ (s) = talloc_array_ptrtype(ndr->current_mem_ctx, (s), n); \
+ if (!(s)) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Alloc %u * %s failed: %s\n", (unsigned)n, # s, __location__); \
+} while (0)
+
+
+#define NDR_PUSH_ALLOC_SIZE(ndr, s, size) do { \
+ (s) = talloc_array(ndr, uint8_t, size); \
+ if (!(s)) return ndr_push_error(ndr, NDR_ERR_ALLOC, "push alloc %u failed: %s\n", (unsigned)size, __location__); \
+} while (0)
+
+#define NDR_PUSH_ALLOC(ndr, s) do { \
+ (s) = talloc_ptrtype(ndr, (s)); \
+ if (!(s)) return ndr_push_error(ndr, NDR_ERR_ALLOC, "push alloc %s failed: %s\n", # s, __location__); \
+} while (0)
+
+/* these are used when generic fn pointers are needed for ndr push/pull fns */
+typedef enum ndr_err_code (*ndr_push_flags_fn_t)(struct ndr_push *, int ndr_flags, const void *);
+typedef enum ndr_err_code (*ndr_pull_flags_fn_t)(struct ndr_pull *, int ndr_flags, void *);
+typedef void (*ndr_print_fn_t)(struct ndr_print *, const char *, const void *);
+typedef void (*ndr_print_function_t)(struct ndr_print *, const char *, int, const void *);
+
+extern const struct ndr_syntax_id ndr_transfer_syntax;
+extern const struct ndr_syntax_id ndr64_transfer_syntax;
+
+struct ndr_interface_call {
+ const char *name;
+ size_t struct_size;
+ ndr_push_flags_fn_t ndr_push;
+ ndr_pull_flags_fn_t ndr_pull;
+ ndr_print_function_t ndr_print;
+ bool async;
+};
+
+struct ndr_interface_string_array {
+ uint32_t count;
+ const char * const *names;
+};
+
+struct ndr_interface_table {
+ const char *name;
+ struct ndr_syntax_id syntax_id;
+ const char *helpstring;
+ uint32_t num_calls;
+ const struct ndr_interface_call *calls;
+ const struct ndr_interface_string_array *endpoints;
+ const struct ndr_interface_string_array *authservices;
+};
+
+struct ndr_interface_list {
+ struct ndr_interface_list *prev, *next;
+ const struct ndr_interface_table *table;
+};
+
+#define NDR_SCALAR_PROTO(name, type) \
+enum ndr_err_code ndr_push_ ## name(struct ndr_push *ndr, int ndr_flags, type v); \
+enum ndr_err_code ndr_pull_ ## name(struct ndr_pull *ndr, int ndr_flags, type *v); \
+void ndr_print_ ## name(struct ndr_print *ndr, const char *var_name, type v);
+
+#define NDR_BUFFER_PROTO(name, type) \
+enum ndr_err_code ndr_push_ ## name(struct ndr_push *ndr, int ndr_flags, const type *v); \
+enum ndr_err_code ndr_pull_ ## name(struct ndr_pull *ndr, int ndr_flags, type *v); \
+void ndr_print_ ## name(struct ndr_print *ndr, const char *var_name, const type *v);
+
+
+void ndr_print_dom_sid28(struct ndr_print *ndr, const char *name, const struct dom_sid *sid);
+size_t ndr_size_dom_sid28(const struct dom_sid *sid, int flags);
+
+#endif /* __LIBNDR_H__ */
diff --git a/source3/librpc/ndr/ndr.c b/source3/librpc/ndr/ndr.c
new file mode 100644
index 0000000000..d94d12e146
--- /dev/null
+++ b/source3/librpc/ndr/ndr.c
@@ -0,0 +1,1101 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ libndr interface
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ this provides the core routines for NDR parsing functions
+
+ see http://www.opengroup.org/onlinepubs/9629399/chap14.htm for details
+ of NDR encoding rules
+*/
+
+#include "includes.h"
+
+#define NDR_BASE_MARSHALL_SIZE 1024
+
+/* this guid indicates NDR encoding in a protocol tower */
+const struct ndr_syntax_id ndr_transfer_syntax = {
+ { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} },
+ 2
+};
+
+const struct ndr_syntax_id ndr64_transfer_syntax = {
+ { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} },
+ 1
+};
+
+/*
+ work out the number of bytes needed to align on a n byte boundary
+*/
+_PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n)
+{
+ if ((offset & (n-1)) == 0) return 0;
+ return n - (offset & (n-1));
+}
+
+/*
+ initialise a ndr parse structure from a data blob
+*/
+_PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
+{
+ struct ndr_pull *ndr;
+
+ ndr = talloc_zero(mem_ctx, struct ndr_pull);
+ if (!ndr) return NULL;
+ ndr->current_mem_ctx = mem_ctx;
+
+ ndr->data = blob->data;
+ ndr->data_size = blob->length;
+
+ return ndr;
+}
+
+/*
+ advance by 'size' bytes
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
+{
+ ndr->offset += size;
+ if (ndr->offset > ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_pull_advance by %u failed",
+ size);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ set the parse offset to 'ofs'
+*/
+static enum ndr_err_code ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
+{
+ ndr->offset = ofs;
+ if (ndr->offset > ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_pull_set_offset %u failed",
+ ofs);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/* save the offset/size of the current ndr state */
+_PUBLIC_ void ndr_pull_save(struct ndr_pull *ndr, struct ndr_pull_save *save)
+{
+ save->offset = ndr->offset;
+ save->data_size = ndr->data_size;
+}
+
+/* restore the size/offset of a ndr structure */
+_PUBLIC_ void ndr_pull_restore(struct ndr_pull *ndr, struct ndr_pull_save *save)
+{
+ ndr->offset = save->offset;
+ ndr->data_size = save->data_size;
+}
+
+
+/* create a ndr_push structure, ready for some marshalling */
+_PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
+{
+ struct ndr_push *ndr;
+
+ ndr = talloc_zero(mem_ctx, struct ndr_push);
+ if (!ndr) {
+ return NULL;
+ }
+
+ ndr->flags = 0;
+ ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
+ ndr->data = talloc_array(ndr, uint8_t, ndr->alloc_size);
+ if (!ndr->data) {
+ return NULL;
+ }
+
+ return ndr;
+}
+
+/* return a DATA_BLOB structure for the current ndr_push marshalled data */
+_PUBLIC_ DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
+{
+ DATA_BLOB blob;
+ blob = data_blob_const(ndr->data, ndr->offset);
+ if (ndr->alloc_size > ndr->offset) {
+ ndr->data[ndr->offset] = 0;
+ }
+ return blob;
+}
+
+
+/*
+ expand the available space in the buffer to ndr->offset + extra_size
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size)
+{
+ uint32_t size = extra_size + ndr->offset;
+
+ if (size < ndr->offset) {
+ /* extra_size overflowed the offset */
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand to %u",
+ size);
+ }
+
+ if (ndr->alloc_size > size) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
+ if (size+1 > ndr->alloc_size) {
+ ndr->alloc_size = size+1;
+ }
+ ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size);
+ if (!ndr->data) {
+ return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
+ ndr->alloc_size);
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...) _PRINTF_ATTRIBUTE(2,3)
+{
+ va_list ap;
+ char *s = NULL;
+ int i, ret;
+
+ va_start(ap, format);
+ ret = vasprintf(&s, format, ap);
+ va_end(ap);
+
+ if (ret == -1) {
+ return;
+ }
+
+ for (i=0;i<ndr->depth;i++) {
+ DEBUGADD(0,(" "));
+ }
+
+ DEBUGADD(0,("%s\n", s));
+ free(s);
+}
+
+_PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...) _PRINTF_ATTRIBUTE(2,3)
+{
+ va_list ap;
+ int i;
+
+ for (i=0;i<ndr->depth;i++) {
+ ndr->private_data = talloc_asprintf_append_buffer(
+ (char *)ndr->private_data, " ");
+ }
+
+ va_start(ap, format);
+ ndr->private_data = talloc_vasprintf_append_buffer((char *)ndr->private_data,
+ format, ap);
+ va_end(ap);
+ ndr->private_data = talloc_asprintf_append_buffer((char *)ndr->private_data,
+ "\n");
+}
+
+/*
+ a useful helper function for printing idl structures via DEBUG()
+*/
+_PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
+{
+ struct ndr_print *ndr;
+
+ ndr = talloc_zero(NULL, struct ndr_print);
+ if (!ndr) return;
+ ndr->print = ndr_print_debug_helper;
+ ndr->depth = 1;
+ ndr->flags = 0;
+ fn(ndr, name, ptr);
+ talloc_free(ndr);
+}
+
+/*
+ a useful helper function for printing idl unions via DEBUG()
+*/
+_PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
+{
+ struct ndr_print *ndr;
+
+ ndr = talloc_zero(NULL, struct ndr_print);
+ if (!ndr) return;
+ ndr->print = ndr_print_debug_helper;
+ ndr->depth = 1;
+ ndr->flags = 0;
+ ndr_print_set_switch_value(ndr, ptr, level);
+ fn(ndr, name, ptr);
+ talloc_free(ndr);
+}
+
+/*
+ a useful helper function for printing idl function calls via DEBUG()
+*/
+_PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr)
+{
+ struct ndr_print *ndr;
+
+ ndr = talloc_zero(NULL, struct ndr_print);
+ if (!ndr) return;
+ ndr->print = ndr_print_debug_helper;
+ ndr->depth = 1;
+ ndr->flags = 0;
+ fn(ndr, name, flags, ptr);
+ talloc_free(ndr);
+}
+
+/*
+ a useful helper function for printing idl structures to a string
+*/
+_PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr)
+{
+ struct ndr_print *ndr;
+ char *ret = NULL;
+
+ ndr = talloc_zero(mem_ctx, struct ndr_print);
+ if (!ndr) return NULL;
+ ndr->private_data = talloc_strdup(ndr, "");
+ if (!ndr->private_data) {
+ goto failed;
+ }
+ ndr->print = ndr_print_string_helper;
+ ndr->depth = 1;
+ ndr->flags = 0;
+ fn(ndr, name, ptr);
+ ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
+failed:
+ talloc_free(ndr);
+ return ret;
+}
+
+/*
+ a useful helper function for printing idl unions to a string
+*/
+_PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
+{
+ struct ndr_print *ndr;
+ char *ret = NULL;
+
+ ndr = talloc_zero(mem_ctx, struct ndr_print);
+ if (!ndr) return NULL;
+ ndr->private_data = talloc_strdup(ndr, "");
+ if (!ndr->private_data) {
+ goto failed;
+ }
+ ndr->print = ndr_print_string_helper;
+ ndr->depth = 1;
+ ndr->flags = 0;
+ ndr_print_set_switch_value(ndr, ptr, level);
+ fn(ndr, name, ptr);
+ ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
+failed:
+ talloc_free(ndr);
+ return ret;
+}
+
+/*
+ a useful helper function for printing idl function calls to a string
+*/
+_PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
+ ndr_print_function_t fn, const char *name,
+ int flags, void *ptr)
+{
+ struct ndr_print *ndr;
+ char *ret = NULL;
+
+ ndr = talloc_zero(mem_ctx, struct ndr_print);
+ if (!ndr) return NULL;
+ ndr->private_data = talloc_strdup(ndr, "");
+ if (!ndr->private_data) {
+ goto failed;
+ }
+ ndr->print = ndr_print_string_helper;
+ ndr->depth = 1;
+ ndr->flags = 0;
+ fn(ndr, name, flags, ptr);
+ ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
+failed:
+ talloc_free(ndr);
+ return ret;
+}
+
+_PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
+{
+ /* the big/little endian flags are inter-dependent */
+ if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
+ (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
+ }
+ if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
+ (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
+ }
+ if (new_flags & LIBNDR_FLAG_REMAINING) {
+ (*pflags) &= ~LIBNDR_ALIGN_FLAGS;
+ }
+ if (new_flags & LIBNDR_ALIGN_FLAGS) {
+ (*pflags) &= ~LIBNDR_FLAG_REMAINING;
+ }
+ (*pflags) |= new_flags;
+}
+
+NTSTATUS ndr_map_error2ntstatus(enum ndr_err_code ndr_err)
+{
+ switch (ndr_err) {
+ case NDR_ERR_SUCCESS:
+ return NT_STATUS_OK;
+ case NDR_ERR_BUFSIZE:
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ case NDR_ERR_TOKEN:
+ return NT_STATUS_INTERNAL_ERROR;
+ case NDR_ERR_ALLOC:
+ return NT_STATUS_NO_MEMORY;
+ case NDR_ERR_ARRAY_SIZE:
+ return NT_STATUS_ARRAY_BOUNDS_EXCEEDED;
+ case NDR_ERR_INVALID_POINTER:
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ case NDR_ERR_UNREAD_BYTES:
+ return NT_STATUS_PORT_MESSAGE_TOO_LONG;
+ default:
+ break;
+ }
+
+ /* we should map all error codes to different status codes */
+ return NT_STATUS_INVALID_PARAMETER;
+}
+
+/*
+ * Convert an ndr error to string
+ */
+
+const char *ndr_errstr(enum ndr_err_code err)
+{
+ switch (err) {
+ case NDR_ERR_SUCCESS:
+ return "NDR_ERR_SUCCESS";
+ break;
+ case NDR_ERR_ARRAY_SIZE:
+ return "NDR_ERR_ARRAY_SIZE";
+ break;
+ case NDR_ERR_BAD_SWITCH:
+ return "NDR_ERR_BAD_SWITCH";
+ break;
+ case NDR_ERR_OFFSET:
+ return "NDR_ERR_OFFSET";
+ break;
+ case NDR_ERR_RELATIVE:
+ return "NDR_ERR_RELATIVE";
+ break;
+ case NDR_ERR_CHARCNV:
+ return "NDR_ERR_CHARCNV";
+ break;
+ case NDR_ERR_LENGTH:
+ return "NDR_ERR_LENGTH";
+ break;
+ case NDR_ERR_SUBCONTEXT:
+ return "NDR_ERR_SUBCONTEXT";
+ break;
+ case NDR_ERR_COMPRESSION:
+ return "NDR_ERR_COMPRESSION";
+ break;
+ case NDR_ERR_STRING:
+ return "NDR_ERR_STRING";
+ break;
+ case NDR_ERR_VALIDATE:
+ return "NDR_ERR_VALIDATE";
+ break;
+ case NDR_ERR_BUFSIZE:
+ return "NDR_ERR_BUFSIZE";
+ break;
+ case NDR_ERR_ALLOC:
+ return "NDR_ERR_ALLOC";
+ break;
+ case NDR_ERR_RANGE:
+ return "NDR_ERR_RANGE";
+ break;
+ case NDR_ERR_TOKEN:
+ return "NDR_ERR_TOKEN";
+ break;
+ case NDR_ERR_IPV4ADDRESS:
+ return "NDR_ERR_IPV4ADDRESS";
+ break;
+ case NDR_ERR_INVALID_POINTER:
+ return "NDR_ERR_INVALID_POINTER";
+ break;
+ case NDR_ERR_UNREAD_BYTES:
+ return "NDR_ERR_UNREAD_BYTES";
+ break;
+ }
+
+ return talloc_asprintf(talloc_tos(), "Unknown NDR error: %d", err);
+}
+
+/*
+ return and possibly log an NDR error
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_error(struct ndr_pull *ndr,
+ enum ndr_err_code ndr_err,
+ const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
+{
+ char *s=NULL;
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = vasprintf(&s, format, ap);
+ va_end(ap);
+
+ if (ret == -1) {
+ return NDR_ERR_ALLOC;
+ }
+
+ DEBUG(1,("ndr_pull_error(%u): %s\n", ndr_err, s));
+
+ free(s);
+
+ return ndr_err;
+}
+
+/*
+ return and possibly log an NDR error
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_error(struct ndr_push *ndr,
+ enum ndr_err_code ndr_err,
+ const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
+{
+ char *s=NULL;
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = vasprintf(&s, format, ap);
+ va_end(ap);
+
+ if (ret == -1) {
+ return NDR_ERR_ALLOC;
+ }
+
+ DEBUG(1,("ndr_push_error(%u): %s\n", ndr_err, s));
+
+ free(s);
+
+ return ndr_err;
+}
+
+/*
+ handle subcontext buffers, which in midl land are user-marshalled, but
+ we use magic in pidl to make them easier to cope with
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
+ struct ndr_pull **_subndr,
+ size_t header_size,
+ ssize_t size_is)
+{
+ struct ndr_pull *subndr;
+ uint32_t r_content_size;
+
+ switch (header_size) {
+ case 0: {
+ uint32_t content_size = ndr->data_size - ndr->offset;
+ if (size_is >= 0) {
+ content_size = size_is;
+ }
+ r_content_size = content_size;
+ break;
+ }
+
+ case 2: {
+ uint16_t content_size;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size));
+ if (size_is >= 0 && size_is != content_size) {
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
+ (int)size_is, (int)content_size);
+ }
+ r_content_size = content_size;
+ break;
+ }
+
+ case 4: {
+ uint32_t content_size;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
+ if (size_is >= 0 && size_is != content_size) {
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
+ (int)size_is, (int)content_size);
+ }
+ r_content_size = content_size;
+ break;
+ }
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d",
+ (int)header_size);
+ }
+
+ NDR_PULL_NEED_BYTES(ndr, r_content_size);
+
+ subndr = talloc_zero(ndr, struct ndr_pull);
+ NDR_ERR_HAVE_NO_MEMORY(subndr);
+ subndr->flags = ndr->flags;
+ subndr->current_mem_ctx = ndr->current_mem_ctx;
+
+ subndr->data = ndr->data + ndr->offset;
+ subndr->offset = 0;
+ subndr->data_size = r_content_size;
+
+ *_subndr = subndr;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr,
+ struct ndr_pull *subndr,
+ size_t header_size,
+ ssize_t size_is)
+{
+ uint32_t advance;
+ if (size_is >= 0) {
+ advance = size_is;
+ } else if (header_size > 0) {
+ advance = subndr->data_size;
+ } else {
+ advance = subndr->offset;
+ }
+ NDR_CHECK(ndr_pull_advance(ndr, advance));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
+ struct ndr_push **_subndr,
+ size_t header_size,
+ ssize_t size_is)
+{
+ struct ndr_push *subndr;
+
+ subndr = ndr_push_init_ctx(ndr);
+ NDR_ERR_HAVE_NO_MEMORY(subndr);
+ subndr->flags = ndr->flags;
+
+ *_subndr = subndr;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a subcontext header
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
+ struct ndr_push *subndr,
+ size_t header_size,
+ ssize_t size_is)
+{
+ if (size_is >= 0) {
+ ssize_t padding_len = size_is - subndr->offset;
+ if (padding_len > 0) {
+ NDR_CHECK(ndr_push_zero(subndr, padding_len));
+ } else if (padding_len < 0) {
+ return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)",
+ (int)subndr->offset, (int)size_is);
+ }
+ }
+
+ switch (header_size) {
+ case 0:
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset));
+ break;
+
+ case 4:
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d",
+ (int)header_size);
+ }
+
+ NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ store a token in the ndr context, for later retrieval
+*/
+_PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx,
+ struct ndr_token_list **list,
+ const void *key,
+ uint32_t value)
+{
+ struct ndr_token_list *tok;
+ tok = talloc(mem_ctx, struct ndr_token_list);
+ NDR_ERR_HAVE_NO_MEMORY(tok);
+ tok->key = key;
+ tok->value = value;
+ DLIST_ADD((*list), tok);
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ retrieve a token from a ndr context, using cmp_fn to match the tokens
+*/
+_PUBLIC_ enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list **list, const void *key, uint32_t *v,
+ comparison_fn_t _cmp_fn, bool _remove_tok)
+{
+ struct ndr_token_list *tok;
+ for (tok=*list;tok;tok=tok->next) {
+ if (_cmp_fn && _cmp_fn(tok->key,key)==0) goto found;
+ else if (!_cmp_fn && tok->key == key) goto found;
+ }
+ return NDR_ERR_TOKEN;
+found:
+ *v = tok->value;
+ if (_remove_tok) {
+ DLIST_REMOVE((*list), tok);
+ talloc_free(tok);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ retrieve a token from a ndr context
+*/
+_PUBLIC_ enum ndr_err_code ndr_token_retrieve(struct ndr_token_list **list, const void *key, uint32_t *v)
+{
+ return ndr_token_retrieve_cmp_fn(list, key, v, NULL, true);
+}
+
+/*
+ peek at but don't removed a token from a ndr context
+*/
+_PUBLIC_ uint32_t ndr_token_peek(struct ndr_token_list **list, const void *key)
+{
+ enum ndr_err_code status;
+ uint32_t v;
+
+ status = ndr_token_retrieve_cmp_fn(list, key, &v, NULL, false);
+ if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
+ return 0;
+ }
+
+ return v;
+}
+
+/*
+ pull an array size field and add it to the array_size_list token list
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
+{
+ uint32_t size;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &size));
+ return ndr_token_store(ndr, &ndr->array_size_list, p, size);
+}
+
+/*
+ get the stored array size field
+*/
+_PUBLIC_ uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p)
+{
+ return ndr_token_peek(&ndr->array_size_list, p);
+}
+
+/*
+ check the stored array size field
+*/
+_PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size)
+{
+ uint32_t stored;
+ stored = ndr_token_peek(&ndr->array_size_list, p);
+ if (stored != size) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
+ "Bad array size - got %u expected %u\n",
+ stored, size);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull an array length field and add it to the array_length_list token list
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
+{
+ uint32_t length, offset;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &offset));
+ if (offset != 0) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
+ "non-zero array offset %u\n", offset);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &length));
+ return ndr_token_store(ndr, &ndr->array_length_list, p, length);
+}
+
+/*
+ get the stored array length field
+*/
+_PUBLIC_ uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p)
+{
+ return ndr_token_peek(&ndr->array_length_list, p);
+}
+
+/*
+ check the stored array length field
+*/
+_PUBLIC_ enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length)
+{
+ uint32_t stored;
+ stored = ndr_token_peek(&ndr->array_length_list, p);
+ if (stored != length) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
+ "Bad array length - got %u expected %u\n",
+ stored, length);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ store a switch value
+ */
+_PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
+{
+ return ndr_token_store(ndr, &ndr->switch_list, p, val);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
+{
+ return ndr_token_store(ndr, &ndr->switch_list, p, val);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
+{
+ return ndr_token_store(ndr, &ndr->switch_list, p, val);
+}
+
+/*
+ retrieve a switch value
+ */
+_PUBLIC_ uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, const void *p)
+{
+ return ndr_token_peek(&ndr->switch_list, p);
+}
+
+_PUBLIC_ uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, const void *p)
+{
+ return ndr_token_peek(&ndr->switch_list, p);
+}
+
+_PUBLIC_ uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void *p)
+{
+ return ndr_token_peek(&ndr->switch_list, p);
+}
+
+/*
+ pull a struct from a blob using NDR
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
+ ndr_pull_flags_fn_t fn)
+{
+ struct ndr_pull *ndr;
+ ndr = ndr_pull_init_blob(blob, mem_ctx);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+ NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a struct from a blob using NDR - failing if all bytes are not consumed
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
+ ndr_pull_flags_fn_t fn)
+{
+ struct ndr_pull *ndr;
+ ndr = ndr_pull_init_blob(blob, mem_ctx);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+ NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+ if (ndr->offset < ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
+ "not all bytes consumed ofs[%u] size[%u]",
+ ndr->offset, ndr->data_size);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a union from a blob using NDR, given the union discriminator
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
+ uint32_t level, ndr_pull_flags_fn_t fn)
+{
+ struct ndr_pull *ndr;
+ ndr = ndr_pull_init_blob(blob, mem_ctx);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, p, level));
+ NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a union from a blob using NDR, given the union discriminator,
+ failing if all bytes are not consumed
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
+ uint32_t level, ndr_pull_flags_fn_t fn)
+{
+ struct ndr_pull *ndr;
+ ndr = ndr_pull_init_blob(blob, mem_ctx);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, p, level));
+ NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+ if (ndr->offset < ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
+ "not all bytes consumed ofs[%u] size[%u]",
+ ndr->offset, ndr->data_size);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a struct to a blob using NDR
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, const void *p,
+ ndr_push_flags_fn_t fn)
+{
+ struct ndr_push *ndr;
+ ndr = ndr_push_init_ctx(mem_ctx);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+
+ NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+
+ *blob = ndr_push_blob(ndr);
+ talloc_steal(mem_ctx, blob->data);
+ talloc_free(ndr);
+
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a union to a blob using NDR
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
+ uint32_t level, ndr_push_flags_fn_t fn)
+{
+ struct ndr_push *ndr;
+ ndr = ndr_push_init_ctx(mem_ctx);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+
+ NDR_CHECK(ndr_push_set_switch_value(ndr, p, level));
+ NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+
+ *blob = ndr_push_blob(ndr);
+ talloc_steal(mem_ctx, blob->data);
+ talloc_free(ndr);
+
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ generic ndr_size_*() handler for structures
+*/
+_PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
+{
+ struct ndr_push *ndr;
+ enum ndr_err_code status;
+ size_t ret;
+
+ /* avoid recursion */
+ if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
+
+ ndr = ndr_push_init_ctx(NULL);
+ if (!ndr) return 0;
+ ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
+ status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
+ if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
+ talloc_free(ndr);
+ return 0;
+ }
+ ret = ndr->offset;
+ talloc_free(ndr);
+ return ret;
+}
+
+/*
+ generic ndr_size_*() handler for unions
+*/
+_PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
+{
+ struct ndr_push *ndr;
+ enum ndr_err_code status;
+ size_t ret;
+
+ /* avoid recursion */
+ if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
+
+ ndr = ndr_push_init_ctx(NULL);
+ if (!ndr) return 0;
+ ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
+
+ status = ndr_push_set_switch_value(ndr, p, level);
+ if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
+ talloc_free(ndr);
+ return 0;
+ }
+ status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
+ if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
+ talloc_free(ndr);
+ return 0;
+ }
+ ret = ndr->offset;
+ talloc_free(ndr);
+ return ret;
+}
+
+/*
+ get the current base for relative pointers for the push
+*/
+_PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
+{
+ return ndr->relative_base_offset;
+}
+
+/*
+ restore the old base for relative pointers for the push
+*/
+_PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
+{
+ ndr->relative_base_offset = offset;
+}
+
+/*
+ setup the current base for relative pointers for the push
+ called in the NDR_SCALAR stage
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
+{
+ ndr->relative_base_offset = offset;
+ return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
+}
+
+/*
+ setup the current base for relative pointers for the push
+ called in the NDR_BUFFERS stage
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
+{
+ return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
+}
+
+/*
+ push a relative object - stage1
+ this is called during SCALARS processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
+{
+ if (p == NULL) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ return NDR_ERR_SUCCESS;
+ }
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
+ return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
+}
+
+/*
+ push a relative object - stage2
+ this is called during buffers processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
+{
+ struct ndr_push_save save;
+ uint32_t ptr_offset = 0xFFFFFFFF;
+ if (p == NULL) {
+ return NDR_ERR_SUCCESS;
+ }
+ ndr_push_save(ndr, &save);
+ NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
+ if (ptr_offset > ndr->offset) {
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_push_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
+ ptr_offset, ndr->offset);
+ }
+ ndr->offset = ptr_offset;
+ if (save.offset < ndr->relative_base_offset) {
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_push_relative_ptr2 save.offset(%u) < ndr->relative_base_offset(%u)",
+ save.offset, ndr->relative_base_offset);
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save.offset - ndr->relative_base_offset));
+ ndr_push_restore(ndr, &save);
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ get the current base for relative pointers for the pull
+*/
+_PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
+{
+ return ndr->relative_base_offset;
+}
+
+/*
+ restore the old base for relative pointers for the pull
+*/
+_PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
+{
+ ndr->relative_base_offset = offset;
+}
+
+/*
+ setup the current base for relative pointers for the pull
+ called in the NDR_SCALAR stage
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
+{
+ ndr->relative_base_offset = offset;
+ return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
+}
+
+/*
+ setup the current base for relative pointers for the pull
+ called in the NDR_BUFFERS stage
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
+{
+ return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
+}
+
+/*
+ pull a relative object - stage1
+ called during SCALARS processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
+{
+ rel_offset += ndr->relative_base_offset;
+ if (rel_offset > ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)",
+ rel_offset, ndr->data_size);
+ }
+ return ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
+}
+
+/*
+ pull a relative object - stage2
+ called during BUFFERS processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
+{
+ uint32_t rel_offset;
+ NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
+ return ndr_pull_set_offset(ndr, rel_offset);
+}
diff --git a/source3/librpc/ndr/ndr_basic.c b/source3/librpc/ndr/ndr_basic.c
new file mode 100644
index 0000000000..c8fa70b185
--- /dev/null
+++ b/source3/librpc/ndr/ndr_basic.c
@@ -0,0 +1,859 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling basic types
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/network.h"
+#include "librpc/ndr/libndr.h"
+
+#define NDR_SVAL(ndr, ofs) (NDR_BE(ndr)?RSVAL(ndr->data,ofs):SVAL(ndr->data,ofs))
+#define NDR_IVAL(ndr, ofs) (NDR_BE(ndr)?RIVAL(ndr->data,ofs):IVAL(ndr->data,ofs))
+#define NDR_IVALS(ndr, ofs) (NDR_BE(ndr)?RIVALS(ndr->data,ofs):IVALS(ndr->data,ofs))
+#define NDR_SSVAL(ndr, ofs, v) do { if (NDR_BE(ndr)) { RSSVAL(ndr->data,ofs,v); } else SSVAL(ndr->data,ofs,v); } while (0)
+#define NDR_SIVAL(ndr, ofs, v) do { if (NDR_BE(ndr)) { RSIVAL(ndr->data,ofs,v); } else SIVAL(ndr->data,ofs,v); } while (0)
+#define NDR_SIVALS(ndr, ofs, v) do { if (NDR_BE(ndr)) { RSIVALS(ndr->data,ofs,v); } else SIVALS(ndr->data,ofs,v); } while (0)
+
+
+/*
+ check for data leaks from the server by looking for non-zero pad bytes
+ these could also indicate that real structure elements have been
+ mistaken for padding in the IDL
+*/
+_PUBLIC_ void ndr_check_padding(struct ndr_pull *ndr, size_t n)
+{
+ size_t ofs2 = (ndr->offset + (n-1)) & ~(n-1);
+ int i;
+ for (i=ndr->offset;i<ofs2;i++) {
+ if (ndr->data[i] != 0) {
+ break;
+ }
+ }
+ if (i<ofs2) {
+ DEBUG(0,("WARNING: Non-zero padding to %d: ", (int)n));
+ for (i=ndr->offset;i<ofs2;i++) {
+ DEBUG(0,("%02x ", ndr->data[i]));
+ }
+ DEBUG(0,("\n"));
+ }
+
+}
+
+/*
+ parse a int8_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_int8(struct ndr_pull *ndr, int ndr_flags, int8_t *v)
+{
+ NDR_PULL_NEED_BYTES(ndr, 1);
+ *v = (int8_t)CVAL(ndr->data, ndr->offset);
+ ndr->offset += 1;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a uint8_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_uint8(struct ndr_pull *ndr, int ndr_flags, uint8_t *v)
+{
+ NDR_PULL_NEED_BYTES(ndr, 1);
+ *v = CVAL(ndr->data, ndr->offset);
+ ndr->offset += 1;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a int16_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_int16(struct ndr_pull *ndr, int ndr_flags, int16_t *v)
+{
+ NDR_PULL_ALIGN(ndr, 2);
+ NDR_PULL_NEED_BYTES(ndr, 2);
+ *v = (uint16_t)NDR_SVAL(ndr, ndr->offset);
+ ndr->offset += 2;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a uint16_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_uint16(struct ndr_pull *ndr, int ndr_flags, uint16_t *v)
+{
+ NDR_PULL_ALIGN(ndr, 2);
+ NDR_PULL_NEED_BYTES(ndr, 2);
+ *v = NDR_SVAL(ndr, ndr->offset);
+ ndr->offset += 2;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a int32_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_int32(struct ndr_pull *ndr, int ndr_flags, int32_t *v)
+{
+ NDR_PULL_ALIGN(ndr, 4);
+ NDR_PULL_NEED_BYTES(ndr, 4);
+ *v = NDR_IVALS(ndr, ndr->offset);
+ ndr->offset += 4;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a uint32_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_uint32(struct ndr_pull *ndr, int ndr_flags, uint32_t *v)
+{
+ NDR_PULL_ALIGN(ndr, 4);
+ NDR_PULL_NEED_BYTES(ndr, 4);
+ *v = NDR_IVAL(ndr, ndr->offset);
+ ndr->offset += 4;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a pointer referent identifier
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_generic_ptr(struct ndr_pull *ndr, uint32_t *v)
+{
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, v));
+ if (*v != 0) {
+ ndr->ptr_count++;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a ref pointer referent identifier
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_ref_ptr(struct ndr_pull *ndr, uint32_t *v)
+{
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, v));
+ /* ref pointers always point to data */
+ *v = 1;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a udlong
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_udlong(struct ndr_pull *ndr, int ndr_flags, uint64_t *v)
+{
+ NDR_PULL_ALIGN(ndr, 4);
+ NDR_PULL_NEED_BYTES(ndr, 8);
+ *v = NDR_IVAL(ndr, ndr->offset);
+ *v |= (uint64_t)(NDR_IVAL(ndr, ndr->offset+4)) << 32;
+ ndr->offset += 8;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a udlongr
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_udlongr(struct ndr_pull *ndr, int ndr_flags, uint64_t *v)
+{
+ NDR_PULL_ALIGN(ndr, 4);
+ NDR_PULL_NEED_BYTES(ndr, 8);
+ *v = ((uint64_t)NDR_IVAL(ndr, ndr->offset)) << 32;
+ *v |= NDR_IVAL(ndr, ndr->offset+4);
+ ndr->offset += 8;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a dlong
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_dlong(struct ndr_pull *ndr, int ndr_flags, int64_t *v)
+{
+ return ndr_pull_udlong(ndr, ndr_flags, (uint64_t *)v);
+}
+
+/*
+ parse a hyper
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_hyper(struct ndr_pull *ndr, int ndr_flags, uint64_t *v)
+{
+ NDR_PULL_ALIGN(ndr, 8);
+ return ndr_pull_udlong(ndr, ndr_flags, v);
+}
+
+/*
+ parse a pointer
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_pointer(struct ndr_pull *ndr, int ndr_flags, void* *v)
+{
+ uintptr_t h;
+ NDR_PULL_ALIGN(ndr, sizeof(h));
+ NDR_PULL_NEED_BYTES(ndr, sizeof(h));
+ memcpy(&h, ndr->data+ndr->offset, sizeof(h));
+ ndr->offset += sizeof(h);
+ *v = (void *)h;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a NTSTATUS
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_NTSTATUS(struct ndr_pull *ndr, int ndr_flags, NTSTATUS *status)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *status = NT_STATUS(v);
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a NTSTATUS
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_NTSTATUS(struct ndr_push *ndr, int ndr_flags, NTSTATUS status)
+{
+ return ndr_push_uint32(ndr, ndr_flags, NT_STATUS_V(status));
+}
+
+_PUBLIC_ void ndr_print_NTSTATUS(struct ndr_print *ndr, const char *name, NTSTATUS r)
+{
+ ndr->print(ndr, "%-25s: %s", name, nt_errstr(r));
+}
+
+/*
+ pull a WERROR
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_WERROR(struct ndr_pull *ndr, int ndr_flags, WERROR *status)
+{
+ uint32_t v;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *status = W_ERROR(v);
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a WERROR
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_WERROR(struct ndr_push *ndr, int ndr_flags, WERROR status)
+{
+ return ndr_push_uint32(ndr, NDR_SCALARS, W_ERROR_V(status));
+}
+
+_PUBLIC_ void ndr_print_WERROR(struct ndr_print *ndr, const char *name, WERROR r)
+{
+ ndr->print(ndr, "%-25s: %s", name, win_errstr(r));
+}
+
+/*
+ parse a set of bytes
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_bytes(struct ndr_pull *ndr, uint8_t *data, uint32_t n)
+{
+ NDR_PULL_NEED_BYTES(ndr, n);
+ memcpy(data, ndr->data + ndr->offset, n);
+ ndr->offset += n;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull an array of uint8
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_array_uint8(struct ndr_pull *ndr, int ndr_flags, uint8_t *data, uint32_t n)
+{
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+ return ndr_pull_bytes(ndr, data, n);
+}
+
+/*
+ push a int8_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_int8(struct ndr_push *ndr, int ndr_flags, int8_t v)
+{
+ NDR_PUSH_NEED_BYTES(ndr, 1);
+ SCVAL(ndr->data, ndr->offset, (uint8_t)v);
+ ndr->offset += 1;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a uint8_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_uint8(struct ndr_push *ndr, int ndr_flags, uint8_t v)
+{
+ NDR_PUSH_NEED_BYTES(ndr, 1);
+ SCVAL(ndr->data, ndr->offset, v);
+ ndr->offset += 1;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a int16_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_int16(struct ndr_push *ndr, int ndr_flags, int16_t v)
+{
+ NDR_PUSH_ALIGN(ndr, 2);
+ NDR_PUSH_NEED_BYTES(ndr, 2);
+ NDR_SSVAL(ndr, ndr->offset, (uint16_t)v);
+ ndr->offset += 2;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a uint16_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_uint16(struct ndr_push *ndr, int ndr_flags, uint16_t v)
+{
+ NDR_PUSH_ALIGN(ndr, 2);
+ NDR_PUSH_NEED_BYTES(ndr, 2);
+ NDR_SSVAL(ndr, ndr->offset, v);
+ ndr->offset += 2;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a int32_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_int32(struct ndr_push *ndr, int ndr_flags, int32_t v)
+{
+ NDR_PUSH_ALIGN(ndr, 4);
+ NDR_PUSH_NEED_BYTES(ndr, 4);
+ NDR_SIVALS(ndr, ndr->offset, v);
+ ndr->offset += 4;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a uint32_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_uint32(struct ndr_push *ndr, int ndr_flags, uint32_t v)
+{
+ NDR_PUSH_ALIGN(ndr, 4);
+ NDR_PUSH_NEED_BYTES(ndr, 4);
+ NDR_SIVAL(ndr, ndr->offset, v);
+ ndr->offset += 4;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a udlong
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_udlong(struct ndr_push *ndr, int ndr_flags, uint64_t v)
+{
+ NDR_PUSH_ALIGN(ndr, 4);
+ NDR_PUSH_NEED_BYTES(ndr, 8);
+ NDR_SIVAL(ndr, ndr->offset, (v & 0xFFFFFFFF));
+ NDR_SIVAL(ndr, ndr->offset+4, (v>>32));
+ ndr->offset += 8;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a udlongr
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_udlongr(struct ndr_push *ndr, int ndr_flags, uint64_t v)
+{
+ NDR_PUSH_ALIGN(ndr, 4);
+ NDR_PUSH_NEED_BYTES(ndr, 8);
+ NDR_SIVAL(ndr, ndr->offset, (v>>32));
+ NDR_SIVAL(ndr, ndr->offset+4, (v & 0xFFFFFFFF));
+ ndr->offset += 8;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a dlong
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_dlong(struct ndr_push *ndr, int ndr_flags, int64_t v)
+{
+ return ndr_push_udlong(ndr, NDR_SCALARS, (uint64_t)v);
+}
+
+/*
+ push a hyper
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_hyper(struct ndr_push *ndr, int ndr_flags, uint64_t v)
+{
+ NDR_PUSH_ALIGN(ndr, 8);
+ return ndr_push_udlong(ndr, NDR_SCALARS, v);
+}
+
+/*
+ push a pointer
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_pointer(struct ndr_push *ndr, int ndr_flags, void* v)
+{
+ uintptr_t h = (intptr_t)v;
+ NDR_PUSH_ALIGN(ndr, sizeof(h));
+ NDR_PUSH_NEED_BYTES(ndr, sizeof(h));
+ memcpy(ndr->data+ndr->offset, &h, sizeof(h));
+ ndr->offset += sizeof(h);
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_align(struct ndr_push *ndr, size_t size)
+{
+ NDR_PUSH_ALIGN(ndr, size);
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_align(struct ndr_pull *ndr, size_t size)
+{
+ NDR_PULL_ALIGN(ndr, size);
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push some bytes
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_bytes(struct ndr_push *ndr, const uint8_t *data, uint32_t n)
+{
+ NDR_PUSH_NEED_BYTES(ndr, n);
+ memcpy(ndr->data + ndr->offset, data, n);
+ ndr->offset += n;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push some zero bytes
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_zero(struct ndr_push *ndr, uint32_t n)
+{
+ NDR_PUSH_NEED_BYTES(ndr, n);
+ memset(ndr->data + ndr->offset, 0, n);
+ ndr->offset += n;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push an array of uint8
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_array_uint8(struct ndr_push *ndr, int ndr_flags, const uint8_t *data, uint32_t n)
+{
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+ return ndr_push_bytes(ndr, data, n);
+}
+
+/*
+ save the current position
+ */
+_PUBLIC_ void ndr_push_save(struct ndr_push *ndr, struct ndr_push_save *save)
+{
+ save->offset = ndr->offset;
+}
+
+/*
+ restore the position
+ */
+_PUBLIC_ void ndr_push_restore(struct ndr_push *ndr, struct ndr_push_save *save)
+{
+ ndr->offset = save->offset;
+}
+
+/*
+ push a unique non-zero value if a pointer is non-NULL, otherwise 0
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_unique_ptr(struct ndr_push *ndr, const void *p)
+{
+ uint32_t ptr = 0;
+ if (p) {
+ ptr = ndr->ptr_count * 4;
+ ptr |= 0x00020000;
+ ndr->ptr_count++;
+ }
+ return ndr_push_uint32(ndr, NDR_SCALARS, ptr);
+}
+
+/*
+ push a 'simple' full non-zero value if a pointer is non-NULL, otherwise 0
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_full_ptr(struct ndr_push *ndr, const void *p)
+{
+ uint32_t ptr = 0;
+ if (p) {
+ /* Check if the pointer already exists and has an id */
+ ptr = ndr_token_peek(&ndr->full_ptr_list, p);
+ if (ptr == 0) {
+ ndr->ptr_count++;
+ ptr = ndr->ptr_count;
+ ndr_token_store(ndr, &ndr->full_ptr_list, p, ptr);
+ }
+ }
+ return ndr_push_uint32(ndr, NDR_SCALARS, ptr);
+}
+
+/*
+ push always a 0, if a pointer is NULL it's a fatal error
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_ref_ptr(struct ndr_push *ndr)
+{
+ return ndr_push_uint32(ndr, NDR_SCALARS, 0xAEF1AEF1);
+}
+
+
+/*
+ push a NTTIME
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_NTTIME(struct ndr_push *ndr, int ndr_flags, NTTIME t)
+{
+ NDR_CHECK(ndr_push_udlong(ndr, ndr_flags, t));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a NTTIME
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_NTTIME(struct ndr_pull *ndr, int ndr_flags, NTTIME *t)
+{
+ NDR_CHECK(ndr_pull_udlong(ndr, ndr_flags, t));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a NTTIME
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_NTTIME_1sec(struct ndr_push *ndr, int ndr_flags, NTTIME t)
+{
+ t /= 10000000;
+ NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, t));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a NTTIME_1sec
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_NTTIME_1sec(struct ndr_pull *ndr, int ndr_flags, NTTIME *t)
+{
+ NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, t));
+ (*t) *= 10000000;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a NTTIME_hyper
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_NTTIME_hyper(struct ndr_pull *ndr, int ndr_flags, NTTIME *t)
+{
+ NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, t));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a NTTIME_hyper
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_NTTIME_hyper(struct ndr_push *ndr, int ndr_flags, NTTIME t)
+{
+ NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, t));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a time_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_time_t(struct ndr_push *ndr, int ndr_flags, time_t t)
+{
+ return ndr_push_uint32(ndr, ndr_flags, t);
+}
+
+/*
+ pull a time_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_time_t(struct ndr_pull *ndr, int ndr_flags, time_t *t)
+{
+ uint32_t tt;
+ NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &tt));
+ *t = tt;
+ return NDR_ERR_SUCCESS;
+}
+
+
+/*
+ pull a ipv4address
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_ipv4address(struct ndr_pull *ndr, int ndr_flags, const char **address)
+{
+ struct in_addr in;
+ NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &in.s_addr));
+ in.s_addr = htonl(in.s_addr);
+ *address = talloc_strdup(ndr->current_mem_ctx, inet_ntoa(in));
+ NDR_ERR_HAVE_NO_MEMORY(*address);
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a ipv4address
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_ipv4address(struct ndr_push *ndr, int ndr_flags, const char *address)
+{
+ uint32_t addr;
+ if (!is_ipaddress(address)) {
+ return ndr_push_error(ndr, NDR_ERR_IPV4ADDRESS,
+ "Invalid IPv4 address: '%s'",
+ address);
+ }
+ addr = inet_addr(address);
+ NDR_CHECK(ndr_push_uint32(ndr, ndr_flags, htonl(addr)));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ print a ipv4address
+*/
+_PUBLIC_ void ndr_print_ipv4address(struct ndr_print *ndr, const char *name,
+ const char *address)
+{
+ ndr->print(ndr, "%-25s: %s", name, address);
+}
+
+
+_PUBLIC_ void ndr_print_struct(struct ndr_print *ndr, const char *name, const char *type)
+{
+ ndr->print(ndr, "%s: struct %s", name, type);
+}
+
+_PUBLIC_ void ndr_print_enum(struct ndr_print *ndr, const char *name, const char *type,
+ const char *val, uint32_t value)
+{
+ if (ndr->flags & LIBNDR_PRINT_ARRAY_HEX) {
+ ndr->print(ndr, "%-25s: %s (0x%X)", name, val?val:"UNKNOWN_ENUM_VALUE", value);
+ } else {
+ ndr->print(ndr, "%-25s: %s (%d)", name, val?val:"UNKNOWN_ENUM_VALUE", value);
+ }
+}
+
+_PUBLIC_ void ndr_print_bitmap_flag(struct ndr_print *ndr, size_t size, const char *flag_name, uint32_t flag, uint32_t value)
+{
+ /* this is an attempt to support multi-bit bitmap masks */
+ value &= flag;
+
+ while (!(flag & 1)) {
+ flag >>= 1;
+ value >>= 1;
+ }
+ if (flag == 1) {
+ ndr->print(ndr, " %d: %-25s", value, flag_name);
+ } else {
+ ndr->print(ndr, "0x%02x: %-25s (%d)", value, flag_name, value);
+ }
+}
+
+_PUBLIC_ void ndr_print_int8(struct ndr_print *ndr, const char *name, int8_t v)
+{
+ ndr->print(ndr, "%-25s: %d", name, v);
+}
+
+_PUBLIC_ void ndr_print_uint8(struct ndr_print *ndr, const char *name, uint8_t v)
+{
+ ndr->print(ndr, "%-25s: 0x%02x (%u)", name, v, v);
+}
+
+_PUBLIC_ void ndr_print_int16(struct ndr_print *ndr, const char *name, int16_t v)
+{
+ ndr->print(ndr, "%-25s: %d", name, v);
+}
+
+_PUBLIC_ void ndr_print_uint16(struct ndr_print *ndr, const char *name, uint16_t v)
+{
+ ndr->print(ndr, "%-25s: 0x%04x (%u)", name, v, v);
+}
+
+_PUBLIC_ void ndr_print_int32(struct ndr_print *ndr, const char *name, int32_t v)
+{
+ ndr->print(ndr, "%-25s: %d", name, v);
+}
+
+_PUBLIC_ void ndr_print_uint32(struct ndr_print *ndr, const char *name, uint32_t v)
+{
+ ndr->print(ndr, "%-25s: 0x%08x (%u)", name, v, v);
+}
+
+_PUBLIC_ void ndr_print_udlong(struct ndr_print *ndr, const char *name, uint64_t v)
+{
+ ndr->print(ndr, "%-25s: 0x%016llx (%llu)", name, (unsigned long long)v, (unsigned long long)v);
+}
+
+_PUBLIC_ void ndr_print_udlongr(struct ndr_print *ndr, const char *name, uint64_t v)
+{
+ ndr_print_udlong(ndr, name, v);
+}
+
+_PUBLIC_ void ndr_print_dlong(struct ndr_print *ndr, const char *name, int64_t v)
+{
+ ndr->print(ndr, "%-25s: 0x%016llx (%lld)", name, (unsigned long long)v, (long long)v);
+}
+
+_PUBLIC_ void ndr_print_hyper(struct ndr_print *ndr, const char *name, uint64_t v)
+{
+ ndr_print_dlong(ndr, name, v);
+}
+
+_PUBLIC_ void ndr_print_pointer(struct ndr_print *ndr, const char *name, void *v)
+{
+ ndr->print(ndr, "%-25s: %p", name, v);
+}
+
+_PUBLIC_ void ndr_print_ptr(struct ndr_print *ndr, const char *name, const void *p)
+{
+ if (p) {
+ ndr->print(ndr, "%-25s: *", name);
+ } else {
+ ndr->print(ndr, "%-25s: NULL", name);
+ }
+}
+
+_PUBLIC_ void ndr_print_NTTIME(struct ndr_print *ndr, const char *name, NTTIME t)
+{
+ ndr->print(ndr, "%-25s: %s", name, nt_time_string(ndr, t));
+}
+
+_PUBLIC_ void ndr_print_NTTIME_1sec(struct ndr_print *ndr, const char *name, NTTIME t)
+{
+ /* this is a standard NTTIME here
+ * as it's already converted in the pull/push code
+ */
+ ndr_print_NTTIME(ndr, name, t);
+}
+
+_PUBLIC_ void ndr_print_NTTIME_hyper(struct ndr_print *ndr, const char *name, NTTIME t)
+{
+ ndr_print_NTTIME(ndr, name, t);
+}
+
+_PUBLIC_ void ndr_print_time_t(struct ndr_print *ndr, const char *name, time_t t)
+{
+ if (t == (time_t)-1 || t == 0) {
+ ndr->print(ndr, "%-25s: (time_t)%d", name, (int)t);
+ } else {
+ ndr->print(ndr, "%-25s: %s", name, timestring(ndr, t));
+ }
+}
+
+_PUBLIC_ void ndr_print_union(struct ndr_print *ndr, const char *name, int level, const char *type)
+{
+ if (ndr->flags & LIBNDR_PRINT_ARRAY_HEX) {
+ ndr->print(ndr, "%-25s: union %s(case 0x%X)", name, type, level);
+ } else {
+ ndr->print(ndr, "%-25s: union %s(case %d)", name, type, level);
+ }
+}
+
+_PUBLIC_ void ndr_print_bad_level(struct ndr_print *ndr, const char *name, uint16_t level)
+{
+ ndr->print(ndr, "UNKNOWN LEVEL %u", level);
+}
+
+_PUBLIC_ void ndr_print_array_uint8(struct ndr_print *ndr, const char *name,
+ const uint8_t *data, uint32_t count)
+{
+ int i;
+
+ if (count <= 600 && (ndr->flags & LIBNDR_PRINT_ARRAY_HEX)) {
+ char s[1202];
+ for (i=0;i<count;i++) {
+ snprintf(&s[i*2], 3, "%02x", data[i]);
+ }
+ s[i*2] = 0;
+ ndr->print(ndr, "%-25s: %s", name, s);
+ return;
+ }
+
+ ndr->print(ndr, "%s: ARRAY(%d)", name, count);
+ ndr->depth++;
+ for (i=0;i<count;i++) {
+ char *idx=NULL;
+ if (asprintf(&idx, "[%d]", i) != -1) {
+ ndr_print_uint8(ndr, idx, data[i]);
+ free(idx);
+ }
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_DATA_BLOB(struct ndr_print *ndr, const char *name, DATA_BLOB r)
+{
+ ndr->print(ndr, "%-25s: DATA_BLOB length=%u", name, (unsigned)r.length);
+ if (r.length) {
+ dump_data(10, r.data, r.length);
+ }
+}
+
+
+/*
+ push a DATA_BLOB onto the wire.
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_DATA_BLOB(struct ndr_push *ndr, int ndr_flags, DATA_BLOB blob)
+{
+ if (ndr->flags & LIBNDR_ALIGN_FLAGS) {
+ if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
+ blob.length = NDR_ALIGN(ndr, 2);
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
+ blob.length = NDR_ALIGN(ndr, 4);
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
+ blob.length = NDR_ALIGN(ndr, 8);
+ }
+ NDR_PUSH_ALLOC_SIZE(ndr, blob.data, blob.length);
+ data_blob_clear(&blob);
+ } else if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, blob.length));
+ }
+ NDR_CHECK(ndr_push_bytes(ndr, blob.data, blob.length));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a DATA_BLOB from the wire.
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_DATA_BLOB(struct ndr_pull *ndr, int ndr_flags, DATA_BLOB *blob)
+{
+ uint32_t length = 0;
+
+ if (ndr->flags & LIBNDR_ALIGN_FLAGS) {
+ if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
+ length = NDR_ALIGN(ndr, 2);
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
+ length = NDR_ALIGN(ndr, 4);
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
+ length = NDR_ALIGN(ndr, 8);
+ }
+ if (ndr->data_size - ndr->offset < length) {
+ length = ndr->data_size - ndr->offset;
+ }
+ } else if (ndr->flags & LIBNDR_FLAG_REMAINING) {
+ length = ndr->data_size - ndr->offset;
+ } else {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &length));
+ }
+ NDR_PULL_NEED_BYTES(ndr, length);
+ *blob = data_blob_talloc(ndr->current_mem_ctx, ndr->data+ndr->offset, length);
+ ndr->offset += length;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ uint32_t ndr_size_DATA_BLOB(int ret, const DATA_BLOB *data, int flags)
+{
+ if (!data) return ret;
+ return ret + data->length;
+}
+
+_PUBLIC_ void ndr_print_bool(struct ndr_print *ndr, const char *name, const bool b)
+{
+ ndr->print(ndr, "%-25s: %s", name, b?"true":"false");
+}
+
+_PUBLIC_ void ndr_print_sockaddr_storage(struct ndr_print *ndr, const char *name, const struct sockaddr_storage *ss)
+{
+ char addr[INET6_ADDRSTRLEN];
+ ndr->print(ndr, "%-25s: %s", name, print_sockaddr(addr, sizeof(addr), ss));
+}
diff --git a/source3/librpc/ndr/ndr_compression.c b/source3/librpc/ndr/ndr_compression.c
new file mode 100644
index 0000000000..9da0773f28
--- /dev/null
+++ b/source3/librpc/ndr/ndr_compression.c
@@ -0,0 +1,293 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ libndr compression support
+
+ Copyright (C) Stefan Metzmacher 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/compression/mszip.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/ndr/ndr_compression.h"
+
+static enum ndr_err_code ndr_pull_compression_mszip_chunk(struct ndr_pull *ndrpull,
+ struct ndr_push *ndrpush,
+ struct decomp_state *decomp_state,
+ bool *last)
+{
+ DATA_BLOB comp_chunk;
+ uint32_t comp_chunk_offset;
+ uint32_t comp_chunk_size;
+ DATA_BLOB plain_chunk;
+ uint32_t plain_chunk_offset;
+ uint32_t plain_chunk_size;
+ int ret;
+
+ NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size));
+ if (plain_chunk_size > 0x00008000) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad MSZIP plain chunk size %08X > 0x00008000 (PULL)",
+ plain_chunk_size);
+ }
+
+ NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size));
+
+ DEBUG(10,("MSZIP plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
+ plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
+
+ comp_chunk_offset = ndrpull->offset;
+ NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
+ comp_chunk.length = comp_chunk_size;
+ comp_chunk.data = ndrpull->data + comp_chunk_offset;
+
+ plain_chunk_offset = ndrpush->offset;
+ NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size));
+ plain_chunk.length = plain_chunk_size;
+ plain_chunk.data = ndrpush->data + plain_chunk_offset;
+
+ ret = ZIPdecompress(decomp_state, &comp_chunk, &plain_chunk);
+ if (ret != DECR_OK) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad ZIPdecompress() error %d (PULL)",
+ ret);
+ }
+
+ if ((plain_chunk_size < 0x00008000) || (ndrpull->offset+4 >= ndrpull->data_size)) {
+ /* this is the last chunk */
+ *last = true;
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_compression_mszip(struct ndr_pull *subndr,
+ struct ndr_pull **_comndr,
+ ssize_t decompressed_len)
+{
+ struct ndr_push *ndrpush;
+ struct ndr_pull *comndr;
+ DATA_BLOB uncompressed;
+ uint32_t payload_header[4];
+ uint32_t payload_size;
+ uint32_t payload_offset;
+ uint8_t *payload;
+ struct decomp_state *decomp_state;
+ bool last = false;
+
+ ndrpush = ndr_push_init_ctx(subndr);
+ NDR_ERR_HAVE_NO_MEMORY(ndrpush);
+
+ decomp_state = ZIPdecomp_state(subndr);
+ NDR_ERR_HAVE_NO_MEMORY(decomp_state);
+
+ while (!last) {
+ NDR_CHECK(ndr_pull_compression_mszip_chunk(subndr, ndrpush, decomp_state, &last));
+ }
+
+ uncompressed = ndr_push_blob(ndrpush);
+
+ if (uncompressed.length != decompressed_len) {
+ return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP uncompressed_len [%u] != [%d] (PULL)",
+ (int)uncompressed.length, (int)decompressed_len);
+ }
+
+ comndr = talloc_zero(subndr, struct ndr_pull);
+ NDR_ERR_HAVE_NO_MEMORY(comndr);
+ comndr->flags = subndr->flags;
+ comndr->current_mem_ctx = subndr->current_mem_ctx;
+
+ comndr->data = uncompressed.data;
+ comndr->data_size = uncompressed.length;
+ comndr->offset = 0;
+
+ NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[0]));
+ NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[1]));
+ NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[2]));
+ NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[3]));
+
+ if (payload_header[0] != 0x00081001) {
+ return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[0] [0x%08X] != [0x00081001] (PULL)",
+ payload_header[0]);
+ }
+ if (payload_header[1] != 0xCCCCCCCC) {
+ return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[1] [0x%08X] != [0xCCCCCCCC] (PULL)",
+ payload_header[1]);
+ }
+
+ payload_size = payload_header[2];
+
+ if (payload_header[3] != 0x00000000) {
+ return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[3] [0x%08X] != [0x00000000] (PULL)",
+ payload_header[3]);
+ }
+
+ payload_offset = comndr->offset;
+ NDR_CHECK(ndr_pull_advance(comndr, payload_size));
+ payload = comndr->data + payload_offset;
+
+ comndr->data = payload;
+ comndr->data_size = payload_size;
+ comndr->offset = 0;
+
+ *_comndr = comndr;
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_push_compression_mszip(struct ndr_push *subndr,
+ struct ndr_push *comndr)
+{
+ return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Sorry MSZIP compression is not supported yet (PUSH)");
+}
+
+static enum ndr_err_code ndr_pull_compression_xpress_chunk(struct ndr_pull *ndrpull,
+ struct ndr_push *ndrpush,
+ bool *last)
+{
+ DATA_BLOB comp_chunk;
+ uint32_t comp_chunk_offset;
+ uint32_t comp_chunk_size;
+ uint32_t plain_chunk_size;
+
+ comp_chunk_offset = ndrpull->offset;
+
+ NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size));
+ if (plain_chunk_size > 0x00010000) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad XPRESS plain chunk size %08X > 0x00010000 (PULL)",
+ plain_chunk_size);
+ }
+
+ NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size));
+
+ NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
+ comp_chunk.length = comp_chunk_size + 8;
+ comp_chunk.data = ndrpull->data + comp_chunk_offset;
+
+ DEBUG(10,("XPRESS plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
+ plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
+
+ /* For now, we just copy over the compressed blob */
+ NDR_CHECK(ndr_push_bytes(ndrpush, comp_chunk.data, comp_chunk.length));
+
+ if ((plain_chunk_size < 0x00010000) || (ndrpull->offset+4 >= ndrpull->data_size)) {
+ /* this is the last chunk */
+ *last = true;
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_compression_xpress(struct ndr_pull *subndr,
+ struct ndr_pull **_comndr,
+ ssize_t decompressed_len)
+{
+ struct ndr_push *ndrpush;
+ struct ndr_pull *comndr;
+ DATA_BLOB uncompressed;
+ bool last = false;
+
+ ndrpush = ndr_push_init_ctx(subndr);
+ NDR_ERR_HAVE_NO_MEMORY(ndrpush);
+
+ while (!last) {
+ NDR_CHECK(ndr_pull_compression_xpress_chunk(subndr, ndrpush, &last));
+ }
+
+ uncompressed = ndr_push_blob(ndrpush);
+
+ comndr = talloc_zero(subndr, struct ndr_pull);
+ NDR_ERR_HAVE_NO_MEMORY(comndr);
+ comndr->flags = subndr->flags;
+ comndr->current_mem_ctx = subndr->current_mem_ctx;
+
+ comndr->data = uncompressed.data;
+ comndr->data_size = uncompressed.length;
+ comndr->offset = 0;
+
+ *_comndr = comndr;
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_push_compression_xpress(struct ndr_push *subndr,
+ struct ndr_push *comndr)
+{
+ return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "XPRESS compression is not supported yet (PUSH)");
+}
+
+/*
+ handle compressed subcontext buffers, which in midl land are user-marshalled, but
+ we use magic in pidl to make them easier to cope with
+*/
+enum ndr_err_code ndr_pull_compression_start(struct ndr_pull *subndr,
+ struct ndr_pull **_comndr,
+ enum ndr_compression_alg compression_alg,
+ ssize_t decompressed_len)
+{
+ switch (compression_alg) {
+ case NDR_COMPRESSION_MSZIP:
+ return ndr_pull_compression_mszip(subndr, _comndr, decompressed_len);
+ case NDR_COMPRESSION_XPRESS:
+ return ndr_pull_compression_xpress(subndr, _comndr, decompressed_len);
+ default:
+ return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PULL)",
+ compression_alg);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_compression_end(struct ndr_pull *subndr,
+ struct ndr_pull *comndr,
+ enum ndr_compression_alg compression_alg,
+ ssize_t decompressed_len)
+{
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a compressed subcontext
+*/
+enum ndr_err_code ndr_push_compression_start(struct ndr_push *subndr,
+ struct ndr_push **_comndr,
+ enum ndr_compression_alg compression_alg,
+ ssize_t decompressed_len)
+{
+ struct ndr_push *comndr;
+
+ comndr = ndr_push_init_ctx(subndr);
+ NDR_ERR_HAVE_NO_MEMORY(comndr);
+ comndr->flags = subndr->flags;
+
+ *_comndr = comndr;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a compressed subcontext
+*/
+enum ndr_err_code ndr_push_compression_end(struct ndr_push *subndr,
+ struct ndr_push *comndr,
+ enum ndr_compression_alg compression_alg,
+ ssize_t decompressed_len)
+{
+ switch (compression_alg) {
+ case NDR_COMPRESSION_MSZIP:
+ return ndr_push_compression_mszip(subndr, comndr);
+ case NDR_COMPRESSION_XPRESS:
+ return ndr_push_compression_xpress(subndr, comndr);
+ default:
+ return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PUSH)",
+ compression_alg);
+ }
+ return NDR_ERR_SUCCESS;
+}
diff --git a/source3/librpc/ndr/ndr_compression.h b/source3/librpc/ndr/ndr_compression.h
new file mode 100644
index 0000000000..4cebbe190c
--- /dev/null
+++ b/source3/librpc/ndr/ndr_compression.h
@@ -0,0 +1,51 @@
+#ifndef __LIBRPC_NDR_NDR_COMPRESSION_H__
+#define __LIBRPC_NDR_NDR_COMPRESSION_H__
+
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2)
+/* This file was automatically generated by mkproto.pl. DO NOT EDIT */
+
+#ifndef _PUBLIC_
+#define _PUBLIC_
+#endif
+
+#ifndef _PURE_
+#define _PURE_
+#endif
+
+#ifndef _NORETURN_
+#define _NORETURN_
+#endif
+
+#ifndef _DEPRECATED_
+#define _DEPRECATED_
+#endif
+
+#ifndef _WARN_UNUSED_RESULT_
+#define _WARN_UNUSED_RESULT_
+#endif
+
+
+/* The following definitions come from librpc/ndr/ndr_compression.c */
+
+enum ndr_err_code ndr_pull_compression_start(struct ndr_pull *subndr,
+ struct ndr_pull **_comndr,
+ enum ndr_compression_alg compression_alg,
+ ssize_t decompressed_len);
+enum ndr_err_code ndr_pull_compression_end(struct ndr_pull *subndr,
+ struct ndr_pull *comndr,
+ enum ndr_compression_alg compression_alg,
+ ssize_t decompressed_len);
+enum ndr_err_code ndr_push_compression_start(struct ndr_push *subndr,
+ struct ndr_push **_comndr,
+ enum ndr_compression_alg compression_alg,
+ ssize_t decompressed_len);
+enum ndr_err_code ndr_push_compression_end(struct ndr_push *subndr,
+ struct ndr_push *comndr,
+ enum ndr_compression_alg compression_alg,
+ ssize_t decompressed_len);
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2)
+
+#endif /* __LIBRPC_NDR_NDR_COMPRESSION_H__ */
+
diff --git a/source3/librpc/ndr/ndr_drsuapi.c b/source3/librpc/ndr/ndr_drsuapi.c
new file mode 100644
index 0000000000..aeb81c87bd
--- /dev/null
+++ b/source3/librpc/ndr/ndr_drsuapi.c
@@ -0,0 +1,177 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for printing some linked list structs in DRSUAPI
+
+ Copyright (C) Stefan (metze) Metzmacher 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_drsuapi.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+
+void ndr_print_drsuapi_DsReplicaObjectListItem(struct ndr_print *ndr, const char *name,
+ const struct drsuapi_DsReplicaObjectListItem *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaObjectListItem");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "next_object", r->next_object);
+ ndr_print_drsuapi_DsReplicaObject(ndr, "object", &r->object);
+ ndr->depth--;
+ if (r->next_object) {
+ ndr_print_drsuapi_DsReplicaObjectListItem(ndr, "next_object", r->next_object);
+ }
+}
+
+void ndr_print_drsuapi_DsReplicaObjectListItemEx(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjectListItemEx *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaObjectListItemEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "next_object", r->next_object);
+ ndr_print_drsuapi_DsReplicaObject(ndr, "object", &r->object);
+ ndr_print_uint32(ndr, "is_nc_prefix", r->is_nc_prefix);
+ ndr_print_ptr(ndr, "parent_object_guid", r->parent_object_guid);
+ ndr->depth++;
+ if (r->parent_object_guid) {
+ ndr_print_GUID(ndr, "parent_object_guid", r->parent_object_guid);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "meta_data_ctr", r->meta_data_ctr);
+ ndr->depth++;
+ if (r->meta_data_ctr) {
+ ndr_print_drsuapi_DsReplicaMetaDataCtr(ndr, "meta_data_ctr", r->meta_data_ctr);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ if (r->next_object) {
+ ndr_print_drsuapi_DsReplicaObjectListItemEx(ndr, "next_object", r->next_object);
+ }
+}
+
+#define _OID_PUSH_CHECK(call) do { \
+ bool _status; \
+ _status = call; \
+ if (_status != true) { \
+ return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "OID Conversion Error: %s\n", __location__); \
+ } \
+} while (0)
+
+#define _OID_PULL_CHECK(call) do { \
+ bool _status; \
+ _status = call; \
+ if (_status != true) { \
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "OID Conversion Error: %s\n", __location__); \
+ } \
+} while (0)
+
+enum ndr_err_code ndr_push_drsuapi_DsReplicaOID(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaOID *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_drsuapi_DsReplicaOID_oid(r->oid, 0)));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->oid));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->oid) {
+ DATA_BLOB blob;
+
+ if (StrnCaseCmp("ff", r->oid, 2) == 0) {
+ blob = strhex_to_data_blob(NULL, r->oid);
+ if (!blob.data) {
+ return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT,
+ "HEX String Conversion Error: %s\n",
+ __location__);
+ }
+ } else {
+ _OID_PUSH_CHECK(ber_write_OID_String(&blob, r->oid));
+ }
+ talloc_steal(ndr, blob.data);
+
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, blob.length));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, blob.data, blob.length));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaOID(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaOID *r)
+{
+ uint32_t _ptr_oid;
+ TALLOC_CTX *_mem_save_oid_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size));
+ if (r->__ndr_size < 0 || r->__ndr_size > 10000) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_oid));
+ if (_ptr_oid) {
+ NDR_PULL_ALLOC(ndr, r->oid);
+ } else {
+ r->oid = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->oid) {
+ DATA_BLOB _oid_array;
+ const char *_oid;
+
+ _mem_save_oid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, ndr, 0);
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->oid));
+ _oid_array.length = ndr_get_array_size(ndr, &r->oid);
+ NDR_PULL_ALLOC_N(ndr, _oid_array.data, _oid_array.length);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, _oid_array.data, _oid_array.length));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_oid_0, 0);
+
+ if (_oid_array.length && _oid_array.data[0] == 0xFF) {
+ _oid = data_blob_hex_string(ndr, &_oid_array);
+ NDR_ERR_HAVE_NO_MEMORY(_oid);
+ } else {
+ _OID_PULL_CHECK(ber_read_OID_String(ndr, _oid_array, &_oid));
+ }
+ TALLOC_FREE(_oid_array.data);
+ talloc_steal(r->oid, _oid);
+ r->oid = _oid;
+ }
+ if (r->oid) {
+ NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->oid, r->__ndr_size));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+size_t ndr_size_drsuapi_DsReplicaOID_oid(const char *oid, int flags)
+{
+ DATA_BLOB _blob;
+ size_t ret = 0;
+
+ if (!oid) return 0;
+
+ if (StrnCaseCmp("ff", oid, 2) == 0) {
+ _blob = strhex_to_data_blob(NULL, oid);
+ if (_blob.data) {
+ ret = _blob.length;
+ }
+ } else {
+ if (ber_write_OID_String(&_blob, oid)) {
+ ret = _blob.length;
+ }
+ }
+ data_blob_free(&_blob);
+ return ret;
+}
diff --git a/source3/librpc/ndr/ndr_drsuapi.h b/source3/librpc/ndr/ndr_drsuapi.h
new file mode 100644
index 0000000000..c663eadd7a
--- /dev/null
+++ b/source3/librpc/ndr/ndr_drsuapi.h
@@ -0,0 +1,35 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for printing some linked list structs in DRSUAPI
+
+ Copyright (C) Stefan (metze) Metzmacher 2005-2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _LIBRPC_NDR_NDR_DRSUAPI_H
+#define _LIBRPC_NDR_NDR_DRSUAPI_H
+
+void ndr_print_drsuapi_DsReplicaObjectListItem(struct ndr_print *ndr, const char *name,
+ const struct drsuapi_DsReplicaObjectListItem *r);
+
+void ndr_print_drsuapi_DsReplicaObjectListItemEx(struct ndr_print *ndr, const char *name,
+ const struct drsuapi_DsReplicaObjectListItemEx *r);
+
+enum ndr_err_code ndr_push_drsuapi_DsReplicaOID(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaOID *r);
+enum ndr_err_code ndr_pull_drsuapi_DsReplicaOID(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaOID *r);
+size_t ndr_size_drsuapi_DsReplicaOID_oid(const char *oid, int flags);
+
+#endif /* _LIBRPC_NDR_NDR_DRSUAPI_H */
diff --git a/source3/librpc/ndr/ndr_krb5pac.c b/source3/librpc/ndr/ndr_krb5pac.c
new file mode 100644
index 0000000000..b0eab44012
--- /dev/null
+++ b/source3/librpc/ndr/ndr_krb5pac.c
@@ -0,0 +1,141 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling spoolss subcontext buffer structures
+
+ Copyright (C) Stefan Metzmacher 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+
+#include "librpc/gen_ndr/ndr_krb5pac.h"
+
+static size_t _ndr_size_PAC_INFO(const union PAC_INFO *r, uint32_t level, int flags)
+{
+ size_t s = ndr_size_PAC_INFO(r, level, flags);
+ switch (level) {
+ case PAC_TYPE_LOGON_INFO:
+ return NDR_ROUND(s,8);
+ default:
+ return s;
+ }
+}
+
+static size_t _subcontext_size_PAC_INFO(const union PAC_INFO *r, uint32_t level, int flags)
+{
+ size_t s = ndr_size_PAC_INFO(r, level, flags);
+ return NDR_ROUND(s,8);
+}
+
+enum ndr_err_code ndr_push_PAC_BUFFER(struct ndr_push *ndr, int ndr_flags, const struct PAC_BUFFER *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_PAC_TYPE(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, _ndr_size_PAC_INFO(r->info,r->type,0)));
+ {
+ uint32_t _flags_save_PAC_INFO = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->info));
+ ndr->flags = _flags_save_PAC_INFO;
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ uint32_t _flags_save_PAC_INFO = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8);
+ if (r->info) {
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, r->info));
+ {
+ struct ndr_push *_ndr_info;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info, 0, _subcontext_size_PAC_INFO(r->info,r->type,0)));
+ NDR_CHECK(ndr_push_set_switch_value(_ndr_info, r->info, r->type));
+ NDR_CHECK(ndr_push_PAC_INFO(_ndr_info, NDR_SCALARS|NDR_BUFFERS, r->info));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_info, 0, _subcontext_size_PAC_INFO(r->info,r->type,0)));
+ }
+ }
+ ndr->flags = _flags_save_PAC_INFO;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_PAC_BUFFER(struct ndr_pull *ndr, int ndr_flags, struct PAC_BUFFER *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_info_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_PAC_TYPE(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->_ndr_size));
+ {
+ uint32_t _flags_save_PAC_INFO = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, r->info);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->info, _ptr_info));
+ } else {
+ r->info = NULL;
+ }
+ ndr->flags = _flags_save_PAC_INFO;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->_pad));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ uint32_t _flags_save_PAC_INFO = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8);
+ if (r->info) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->info));
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info, 0);
+ {
+ struct ndr_pull *_ndr_info;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info, 0, r->_ndr_size));
+ NDR_CHECK(ndr_pull_set_switch_value(_ndr_info, r->info, r->type));
+ NDR_CHECK(ndr_pull_PAC_INFO(_ndr_info, NDR_SCALARS|NDR_BUFFERS, r->info));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info, 0, r->_ndr_size));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0);
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_PAC_INFO;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+void ndr_print_PAC_BUFFER(struct ndr_print *ndr, const char *name, const struct PAC_BUFFER *r)
+{
+ ndr_print_struct(ndr, name, "PAC_BUFFER");
+ ndr->depth++;
+ ndr_print_PAC_TYPE(ndr, "type", r->type);
+ ndr_print_uint32(ndr, "_ndr_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?_ndr_size_PAC_INFO(r->info,r->type,0):r->_ndr_size);
+ ndr_print_ptr(ndr, "info", r->info);
+ ndr->depth++;
+ if (r->info) {
+ ndr_print_set_switch_value(ndr, r->info, r->type);
+ ndr_print_PAC_INFO(ndr, "info", r->info);
+ }
+ ndr->depth--;
+ ndr_print_uint32(ndr, "_pad", r->_pad);
+ ndr->depth--;
+}
diff --git a/source3/librpc/ndr/ndr_misc.c b/source3/librpc/ndr/ndr_misc.c
new file mode 100644
index 0000000000..e86842527c
--- /dev/null
+++ b/source3/librpc/ndr/ndr_misc.c
@@ -0,0 +1,94 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ UUID/GUID/policy_handle functions
+
+ Copyright (C) Theodore Ts'o 1996, 1997,
+ Copyright (C) Jim McDonough 2002.
+ Copyright (C) Andrew Tridgell 2003.
+ Copyright (C) Stefan (metze) Metzmacher 2004.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/**
+ * see if a range of memory is all zero. A NULL pointer is considered
+ * to be all zero
+ */
+bool all_zero(const uint8_t *ptr, size_t size)
+{
+ int i;
+ if (!ptr) return True;
+ for (i=0;i<size;i++) {
+ if (ptr[i]) return False;
+ }
+ return True;
+}
+
+void ndr_print_GUID(struct ndr_print *ndr, const char *name, const struct GUID *guid)
+{
+ ndr->print(ndr, "%-25s: %s", name, GUID_string(ndr, guid));
+}
+
+bool ndr_syntax_id_equal(const struct ndr_syntax_id *i1,
+ const struct ndr_syntax_id *i2)
+{
+ return GUID_equal(&i1->uuid, &i2->uuid)
+ && (i1->if_version == i2->if_version);
+}
+
+enum ndr_err_code ndr_push_server_id(struct ndr_push *ndr, int ndr_flags, const struct server_id *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS,
+ (uint32_t)r->pid));
+#ifdef CLUSTER_SUPPORT
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS,
+ (uint32_t)r->vnn));
+#endif
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_server_id(struct ndr_pull *ndr, int ndr_flags, struct server_id *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ uint32_t pid;
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &pid));
+#ifdef CLUSTER_SUPPORT
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->vnn));
+#endif
+ r->pid = (pid_t)pid;
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+void ndr_print_server_id(struct ndr_print *ndr, const char *name, const struct server_id *r)
+{
+ ndr_print_struct(ndr, name, "server_id");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "id", (uint32_t)r->pid);
+#ifdef CLUSTER_SUPPORT
+ ndr_print_uint32(ndr, "vnn", (uint32_t)r->vnn);
+#endif
+ ndr->depth--;
+}
diff --git a/source3/librpc/ndr/ndr_sec.h b/source3/librpc/ndr/ndr_sec.h
new file mode 100644
index 0000000000..8034367223
--- /dev/null
+++ b/source3/librpc/ndr/ndr_sec.h
@@ -0,0 +1,35 @@
+#ifndef __LIBRPC_NDR_NDR_SEC_H__
+#define __LIBRPC_NDR_NDR_SEC_H__
+
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2)
+/* This file was automatically generated by mkproto.pl. DO NOT EDIT */
+
+#ifndef _PUBLIC_
+#define _PUBLIC_
+#endif
+
+
+/* The following definitions come from librpc/ndr/ndr_sec_helper.c */
+
+size_t ndr_size_dom_sid(const struct dom_sid *sid);
+size_t ndr_length_dom_sid(const struct dom_sid *sid);
+size_t ndr_size_security_ace(const struct security_ace *ace);
+size_t ndr_size_security_acl(const struct security_acl *acl);
+size_t ndr_size_security_descriptor(const struct security_descriptor *sd);
+void ndr_print_dom_sid(struct ndr_print *ndr, const char *name, const struct dom_sid *sid);
+void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, const struct dom_sid *sid);
+void ndr_print_dom_sid28(struct ndr_print *ndr, const char *name, const struct dom_sid *sid);
+char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid);
+
+/* The following definitions come from librpc/ndr/ndr_sec.c */
+
+enum ndr_err_code ndr_pull_dom_sid2(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid);
+enum ndr_err_code ndr_push_dom_sid2(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid);
+enum ndr_err_code ndr_pull_dom_sid28(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid);
+enum ndr_err_code ndr_push_dom_sid28(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid);
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2)
+
+#endif /* __LIBRPC_NDR_NDR_SEC_H__ */
+
diff --git a/source3/librpc/ndr/ndr_sec_helper.c b/source3/librpc/ndr/ndr_sec_helper.c
new file mode 100644
index 0000000000..18d343799e
--- /dev/null
+++ b/source3/librpc/ndr/ndr_sec_helper.c
@@ -0,0 +1,117 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ fast routines for getting the wire size of security objects
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+
+/*
+ return the wire size of a dom_sid
+*/
+size_t ndr_size_dom_sid(const struct dom_sid *sid, int flags)
+{
+ if (!sid) return 0;
+ return 8 + 4*sid->num_auths;
+}
+
+size_t ndr_size_dom_sid28(const struct dom_sid *sid, int flags)
+{
+ struct dom_sid zero_sid;
+
+ if (!sid) return 0;
+
+ ZERO_STRUCT(zero_sid);
+
+ if (memcmp(&zero_sid, sid, sizeof(zero_sid)) == 0) {
+ return 0;
+ }
+
+ return 8 + 4*sid->num_auths;
+}
+
+size_t ndr_size_dom_sid0(const struct dom_sid *sid, int flags)
+{
+ return ndr_size_dom_sid28(sid, flags);
+}
+
+/*
+ return the wire size of a security_ace
+*/
+size_t ndr_size_security_ace(const struct security_ace *ace, int flags)
+{
+ if (!ace) return 0;
+ return 8 + ndr_size_dom_sid(&ace->trustee, flags);
+}
+
+
+/*
+ return the wire size of a security_acl
+*/
+size_t ndr_size_security_acl(const struct security_acl *acl, int flags)
+{
+ size_t ret;
+ int i;
+ if (!acl) return 0;
+ ret = 8;
+ for (i=0;i<acl->num_aces;i++) {
+ ret += ndr_size_security_ace(&acl->aces[i], flags);
+ }
+ return ret;
+}
+
+/*
+ return the wire size of a security descriptor
+*/
+size_t ndr_size_security_descriptor(const struct security_descriptor *sd, int flags)
+{
+ size_t ret;
+ if (!sd) return 0;
+
+ ret = 20;
+ ret += ndr_size_dom_sid(sd->owner_sid, flags);
+ ret += ndr_size_dom_sid(sd->group_sid, flags);
+ ret += ndr_size_security_acl(sd->dacl, flags);
+ ret += ndr_size_security_acl(sd->sacl, flags);
+ return ret;
+}
+
+/*
+ print a dom_sid
+*/
+void ndr_print_dom_sid(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
+{
+ ndr->print(ndr, "%-25s: %s", name, dom_sid_string(ndr, sid));
+}
+
+void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
+{
+ ndr_print_dom_sid(ndr, name, sid);
+}
+
+void ndr_print_dom_sid28(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
+{
+ ndr_print_dom_sid(ndr, name, sid);
+}
+
+void ndr_print_dom_sid0(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
+{
+ ndr_print_dom_sid(ndr, name, sid);
+}
+
diff --git a/source3/librpc/ndr/ndr_string.c b/source3/librpc/ndr/ndr_string.c
new file mode 100644
index 0000000000..e2c9ed5946
--- /dev/null
+++ b/source3/librpc/ndr/ndr_string.c
@@ -0,0 +1,738 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling string types
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/ndr/libndr.h"
+
+/**
+ pull a general string from the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s)
+{
+ char *as=NULL;
+ uint32_t len1, ofs, len2;
+ uint16_t len3;
+ size_t converted_size;
+ int chset = CH_UTF16;
+ unsigned byte_mul = 2;
+ unsigned flags = ndr->flags;
+ unsigned c_len_term = 0;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (NDR_BE(ndr)) {
+ chset = CH_UTF16BE;
+ }
+
+ if (flags & LIBNDR_FLAG_STR_ASCII) {
+ chset = CH_DOS;
+ byte_mul = 1;
+ flags &= ~LIBNDR_FLAG_STR_ASCII;
+ }
+
+ if (flags & LIBNDR_FLAG_STR_UTF8) {
+ chset = CH_UTF8;
+ byte_mul = 1;
+ flags &= ~LIBNDR_FLAG_STR_UTF8;
+ }
+
+ flags &= ~LIBNDR_FLAG_STR_CONFORMANT;
+ if (flags & LIBNDR_FLAG_STR_CHARLEN) {
+ c_len_term = 1;
+ flags &= ~LIBNDR_FLAG_STR_CHARLEN;
+ }
+
+ switch (flags & LIBNDR_STRING_FLAGS) {
+ case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
+ case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
+ if (ofs != 0) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len2));
+ if (len2 > len1) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "Bad string lengths len1=%u ofs=%u len2=%u\n",
+ len1, ofs, len2);
+ }
+ NDR_PULL_NEED_BYTES(ndr, (len2 + c_len_term)*byte_mul);
+ if (len2 == 0) {
+ as = talloc_strdup(ndr->current_mem_ctx, "");
+ } else {
+ if (!convert_string_talloc(ndr->current_mem_ctx, chset,
+ CH_UNIX,
+ ndr->data+ndr->offset,
+ (len2 + c_len_term)*byte_mul,
+ (void **)(void *)&as,
+ &converted_size, false))
+ {
+ return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
+ "Bad char conversion");
+ }
+ }
+ NDR_CHECK(ndr_pull_advance(ndr, (len2 + c_len_term)*byte_mul));
+
+ if (len1 != len2) {
+ DEBUG(6,("len1[%u] != len2[%u] '%s'\n", len1, len2, as));
+ }
+
+ /* this is a way of detecting if a string is sent with the wrong
+ termination */
+ if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
+ if (strlen(as) < (len2 + c_len_term)) {
+ DEBUG(6,("short string '%s'\n", as));
+ }
+ } else {
+ if (strlen(as) == (len2 + c_len_term)) {
+ DEBUG(6,("long string '%s'\n", as));
+ }
+ }
+ *s = as;
+ break;
+
+ case LIBNDR_FLAG_STR_SIZE4:
+ case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
+ NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul);
+ if (len1 == 0) {
+ as = talloc_strdup(ndr->current_mem_ctx, "");
+ } else {
+ if (!convert_string_talloc(ndr->current_mem_ctx, chset,
+ CH_UNIX,
+ ndr->data+ndr->offset,
+ (len1 + c_len_term)*byte_mul,
+ (void **)(void *)&as,
+ &converted_size, false))
+ {
+ return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
+ "Bad char conversion");
+ }
+ }
+ NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul));
+
+ /* this is a way of detecting if a string is sent with the wrong
+ termination */
+ if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
+ if (strlen(as) < (len1 + c_len_term)) {
+ DEBUG(6,("short string '%s'\n", as));
+ }
+ } else {
+ if (strlen(as) == (len1 + c_len_term)) {
+ DEBUG(6,("long string '%s'\n", as));
+ }
+ }
+ *s = as;
+ break;
+
+ case LIBNDR_FLAG_STR_LEN4:
+ case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM:
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
+ if (ofs != 0) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
+ NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul);
+ if (len1 == 0) {
+ as = talloc_strdup(ndr->current_mem_ctx, "");
+ } else {
+ if (!convert_string_talloc(ndr->current_mem_ctx, chset,
+ CH_UNIX,
+ ndr->data+ndr->offset,
+ (len1 + c_len_term)*byte_mul,
+ (void **)(void *)&as,
+ &converted_size, false))
+ {
+ return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
+ "Bad char conversion");
+ }
+ }
+ NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul));
+
+ /* this is a way of detecting if a string is sent with the wrong
+ termination */
+ if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
+ if (strlen(as) < (len1 + c_len_term)) {
+ DEBUG(6,("short string '%s'\n", as));
+ }
+ } else {
+ if (strlen(as) == (len1 + c_len_term)) {
+ DEBUG(6,("long string '%s'\n", as));
+ }
+ }
+ *s = as;
+ break;
+
+
+ case LIBNDR_FLAG_STR_SIZE2:
+ case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM:
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
+ NDR_PULL_NEED_BYTES(ndr, (len3 + c_len_term)*byte_mul);
+ if (len3 == 0) {
+ as = talloc_strdup(ndr->current_mem_ctx, "");
+ } else {
+ if (!convert_string_talloc(ndr->current_mem_ctx, chset,
+ CH_UNIX,
+ ndr->data+ndr->offset,
+ (len3 + c_len_term)*byte_mul,
+ (void **)(void *)&as,
+ &converted_size, false))
+ {
+ return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
+ "Bad char conversion");
+ }
+ }
+ NDR_CHECK(ndr_pull_advance(ndr, (len3 + c_len_term)*byte_mul));
+
+ /* this is a way of detecting if a string is sent with the wrong
+ termination */
+ if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
+ if (strlen(as) < (len3 + c_len_term)) {
+ DEBUG(6,("short string '%s'\n", as));
+ }
+ } else {
+ if (strlen(as) == (len3 + c_len_term)) {
+ DEBUG(6,("long string '%s'\n", as));
+ }
+ }
+ *s = as;
+ break;
+
+ case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE:
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
+ NDR_PULL_NEED_BYTES(ndr, len3);
+ if (len3 == 0) {
+ as = talloc_strdup(ndr->current_mem_ctx, "");
+ } else {
+ if (!convert_string_talloc(ndr->current_mem_ctx, chset,
+ CH_UNIX,
+ ndr->data+ndr->offset, len3,
+ (void **)(void *)&as,
+ &converted_size, false))
+ {
+ return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
+ "Bad char conversion");
+ }
+ }
+ NDR_CHECK(ndr_pull_advance(ndr, len3));
+ *s = as;
+ break;
+
+ case LIBNDR_FLAG_STR_NULLTERM:
+ if (byte_mul == 1) {
+ len1 = ascii_len_n((const char *)(ndr->data+ndr->offset), ndr->data_size - ndr->offset);
+ } else {
+ len1 = utf16_len_n(ndr->data+ndr->offset, ndr->data_size - ndr->offset);
+ }
+ if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX,
+ ndr->data+ndr->offset, len1,
+ (void **)(void *)&as,
+ &converted_size, false))
+ {
+ return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
+ "Bad char conversion");
+ }
+ NDR_CHECK(ndr_pull_advance(ndr, len1));
+ *s = as;
+ break;
+
+ case LIBNDR_FLAG_STR_FIXLEN15:
+ case LIBNDR_FLAG_STR_FIXLEN32:
+ len1 = (flags & LIBNDR_FLAG_STR_FIXLEN32)?32:15;
+ NDR_PULL_NEED_BYTES(ndr, len1*byte_mul);
+ if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX,
+ ndr->data+ndr->offset, len1*byte_mul,
+ (void **)(void *)&as,
+ &converted_size, false))
+ {
+ return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
+ "Bad char conversion");
+ }
+ NDR_CHECK(ndr_pull_advance(ndr, len1*byte_mul));
+ *s = as;
+ break;
+
+ case LIBNDR_FLAG_STR_NOTERM:
+ if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+
+ len1 = ndr->data_size - ndr->offset;
+
+ NDR_PULL_NEED_BYTES(ndr, len1);
+ if (len1 == 0) {
+ as = talloc_strdup(ndr->current_mem_ctx, "");
+ } else {
+ if (!convert_string_talloc(ndr->current_mem_ctx, chset,
+ CH_UNIX,
+ ndr->data+ndr->offset, len1,
+ (void **)(void *)&as,
+ &converted_size, false))
+ {
+ return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
+ "Bad char conversion");
+ }
+ }
+ NDR_CHECK(ndr_pull_advance(ndr, len1));
+
+ *s = as;
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+
+/**
+ push a general string onto the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s)
+{
+ ssize_t s_len, c_len;
+ size_t d_len;
+ int chset = CH_UTF16;
+ unsigned flags = ndr->flags;
+ unsigned byte_mul = 2;
+ uint8_t *dest = NULL;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (NDR_BE(ndr)) {
+ chset = CH_UTF16BE;
+ }
+
+ s_len = s?strlen(s):0;
+
+ if (flags & LIBNDR_FLAG_STR_ASCII) {
+ chset = CH_DOS;
+ byte_mul = 1;
+ flags &= ~LIBNDR_FLAG_STR_ASCII;
+ }
+
+ if (flags & LIBNDR_FLAG_STR_UTF8) {
+ chset = CH_UTF8;
+ byte_mul = 1;
+ flags &= ~LIBNDR_FLAG_STR_UTF8;
+ }
+
+ flags &= ~LIBNDR_FLAG_STR_CONFORMANT;
+
+ if (!(flags &
+ (LIBNDR_FLAG_STR_NOTERM |
+ LIBNDR_FLAG_STR_FIXLEN15 |
+ LIBNDR_FLAG_STR_FIXLEN32))) {
+ s_len++;
+ }
+ if (!convert_string_talloc(ndr, CH_UNIX, chset, s, s_len,
+ (void **)(void *)&dest, &d_len, false))
+ {
+ return ndr_push_error(ndr, NDR_ERR_CHARCNV,
+ "Bad char conversion");
+ }
+
+ if (flags & LIBNDR_FLAG_STR_BYTESIZE) {
+ c_len = d_len;
+ flags &= ~LIBNDR_FLAG_STR_BYTESIZE;
+ } else if (flags & LIBNDR_FLAG_STR_CHARLEN) {
+ c_len = (d_len / byte_mul)-1;
+ flags &= ~LIBNDR_FLAG_STR_CHARLEN;
+ } else {
+ c_len = d_len / byte_mul;
+ }
+
+ switch ((flags & LIBNDR_STRING_FLAGS) & ~LIBNDR_FLAG_STR_NOTERM) {
+ case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
+ NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
+ break;
+
+ case LIBNDR_FLAG_STR_LEN4:
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
+ NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
+ break;
+
+ case LIBNDR_FLAG_STR_SIZE4:
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
+ NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
+ break;
+
+ case LIBNDR_FLAG_STR_SIZE2:
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, c_len));
+ NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
+ break;
+
+ case LIBNDR_FLAG_STR_NULLTERM:
+ NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
+ break;
+
+ case LIBNDR_FLAG_STR_FIXLEN15:
+ case LIBNDR_FLAG_STR_FIXLEN32: {
+ ssize_t fix_len = (flags & LIBNDR_FLAG_STR_FIXLEN32)?32:15;
+ uint32_t pad_len = fix_len - d_len;
+ if (d_len > fix_len) {
+ return ndr_push_error(ndr, NDR_ERR_CHARCNV,
+ "Bad char conversion");
+ }
+ NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
+ if (pad_len != 0) {
+ NDR_CHECK(ndr_push_zero(ndr, pad_len));
+ }
+ break;
+ }
+
+ default:
+ if (ndr->flags & LIBNDR_FLAG_REMAINING) {
+ NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
+ break;
+ }
+
+ return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+
+ talloc_free(dest);
+
+ return NDR_ERR_SUCCESS;
+}
+
+/**
+ push a general string onto the wire
+*/
+_PUBLIC_ size_t ndr_string_array_size(struct ndr_push *ndr, const char *s)
+{
+ size_t c_len;
+ unsigned flags = ndr->flags;
+ unsigned byte_mul = 2;
+ unsigned c_len_term = 1;
+
+ if (flags & LIBNDR_FLAG_STR_FIXLEN32) {
+ return 32;
+ }
+ if (flags & LIBNDR_FLAG_STR_FIXLEN15) {
+ return 15;
+ }
+
+ c_len = s?strlen_m(s):0;
+
+ if (flags & (LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_UTF8)) {
+ byte_mul = 1;
+ }
+
+ if (flags & LIBNDR_FLAG_STR_NOTERM) {
+ c_len_term = 0;
+ }
+
+ c_len = c_len + c_len_term;
+
+ if (flags & LIBNDR_FLAG_STR_BYTESIZE) {
+ c_len = c_len * byte_mul;
+ }
+
+ return c_len;
+}
+
+_PUBLIC_ void ndr_print_string(struct ndr_print *ndr, const char *name, const char *s)
+{
+ if (s) {
+ ndr->print(ndr, "%-25s: '%s'", name, s);
+ } else {
+ ndr->print(ndr, "%-25s: NULL", name);
+ }
+}
+
+_PUBLIC_ uint32_t ndr_size_string(int ret, const char * const* string, int flags)
+{
+ /* FIXME: Is this correct for all strings ? */
+ if(!(*string)) return ret;
+ return ret+strlen(*string)+1;
+}
+
+/**
+ pull a general string array from the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, int ndr_flags, const char ***_a)
+{
+ const char **a = *_a;
+ uint32_t count;
+ unsigned flags = ndr->flags;
+ unsigned saved_flags = ndr->flags;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ switch (flags & LIBNDR_STRING_FLAGS) {
+ case LIBNDR_FLAG_STR_NULLTERM:
+ /*
+ * here the strings are null terminated
+ * but also the array is null terminated
+ */
+ for (count = 0;; count++) {
+ TALLOC_CTX *tmp_ctx;
+ const char *s = NULL;
+ a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 2);
+ NDR_ERR_HAVE_NO_MEMORY(a);
+ a[count] = NULL;
+ a[count+1] = NULL;
+
+ tmp_ctx = ndr->current_mem_ctx;
+ ndr->current_mem_ctx = a;
+ NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s));
+ ndr->current_mem_ctx = tmp_ctx;
+ if (strcmp("", s)==0) {
+ a[count] = NULL;
+ break;
+ } else {
+ a[count] = s;
+ }
+ }
+
+ *_a =a;
+ break;
+
+ case LIBNDR_FLAG_STR_NOTERM:
+ if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+ /*
+ * here the strings are not null terminated
+ * but serarated by a null terminator
+ *
+ * which means the same as:
+ * very string is null terminated exept the last
+ * string is terminated by the end of the buffer
+ *
+ * as LIBNDR_FLAG_STR_NULLTERM also end at the end
+ * of the buffer, we can pull each string with this flag
+ */
+ ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
+ ndr->flags |= LIBNDR_FLAG_STR_NULLTERM;
+
+ for (count = 0; ((ndr->data_size - ndr->offset) > 0); count++) {
+ TALLOC_CTX *tmp_ctx;
+ const char *s = NULL;
+ a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 2);
+ NDR_ERR_HAVE_NO_MEMORY(a);
+ a[count] = NULL;
+ a[count+1] = NULL;
+
+ tmp_ctx = ndr->current_mem_ctx;
+ ndr->current_mem_ctx = a;
+ NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s));
+ ndr->current_mem_ctx = tmp_ctx;
+ a[count] = s;
+ }
+
+ *_a =a;
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+
+ ndr->flags = saved_flags;
+ return NDR_ERR_SUCCESS;
+}
+
+/**
+ push a general string array onto the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_string_array(struct ndr_push *ndr, int ndr_flags, const char **a)
+{
+ uint32_t count;
+ unsigned flags = ndr->flags;
+ unsigned saved_flags = ndr->flags;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ switch (flags & LIBNDR_STRING_FLAGS) {
+ case LIBNDR_FLAG_STR_NULLTERM:
+ for (count = 0; a && a[count]; count++) {
+ NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count]));
+ }
+
+ NDR_CHECK(ndr_push_string(ndr, ndr_flags, ""));
+ break;
+
+ case LIBNDR_FLAG_STR_NOTERM:
+ if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
+ return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+
+ for (count = 0; a && a[count]; count++) {
+ if (count > 0) {
+ ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
+ ndr->flags |= LIBNDR_FLAG_STR_NULLTERM;
+ NDR_CHECK(ndr_push_string(ndr, ndr_flags, ""));
+ ndr->flags = saved_flags;
+ }
+ NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count]));
+ }
+
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+
+ ndr->flags = saved_flags;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a)
+{
+ uint32_t count;
+ uint32_t i;
+
+ for (count = 0; a && a[count]; count++) {}
+
+ ndr->print(ndr, "%s: ARRAY(%d)", name, count);
+ ndr->depth++;
+ for (i=0;i<count;i++) {
+ char *idx=NULL;
+ if (asprintf(&idx, "[%d]", i) != -1) {
+ ndr_print_string(ndr, idx, a[i]);
+ free(idx);
+ }
+ }
+ ndr->depth--;
+}
+
+/**
+ * Return number of elements in a string including the last (zeroed) element
+ */
+_PUBLIC_ uint32_t ndr_string_length(const void *_var, uint32_t element_size)
+{
+ uint32_t i;
+ uint8_t zero[4] = {0,0,0,0};
+ const char *var = (const char *)_var;
+
+ for (i = 0; memcmp(var+i*element_size,zero,element_size) != 0; i++);
+
+ return i+1;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_check_string_terminator(struct ndr_pull *ndr, uint32_t count, uint32_t element_size)
+{
+ uint32_t i;
+ struct ndr_pull_save save_offset;
+
+ ndr_pull_save(ndr, &save_offset);
+ ndr_pull_advance(ndr, (count - 1) * element_size);
+ NDR_PULL_NEED_BYTES(ndr, element_size);
+
+ for (i = 0; i < element_size; i++) {
+ if (ndr->data[ndr->offset+i] != 0) {
+ ndr_pull_restore(ndr, &save_offset);
+
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "String terminator not present or outside string boundaries");
+ }
+ }
+
+ ndr_pull_restore(ndr, &save_offset);
+
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_charset(struct ndr_pull *ndr, int ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset)
+{
+ size_t converted_size;
+
+ if (length == 0) {
+ *var = talloc_strdup(ndr->current_mem_ctx, "");
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (NDR_BE(ndr) && chset == CH_UTF16) {
+ chset = CH_UTF16BE;
+ }
+
+ NDR_PULL_NEED_BYTES(ndr, length*byte_mul);
+
+ if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX,
+ ndr->data+ndr->offset, length*byte_mul,
+ discard_const_p(void *, var),
+ &converted_size, false))
+ {
+ return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
+ "Bad char conversion");
+ }
+ NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul));
+
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_charset(struct ndr_push *ndr, int ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset)
+{
+ ssize_t ret, required;
+
+ if (NDR_BE(ndr) && chset == CH_UTF16) {
+ chset = CH_UTF16BE;
+ }
+
+ required = byte_mul * length;
+
+ NDR_PUSH_NEED_BYTES(ndr, required);
+ ret = convert_string(CH_UNIX, chset,
+ var, strlen(var),
+ ndr->data+ndr->offset, required, false);
+ if (ret == -1) {
+ return ndr_push_error(ndr, NDR_ERR_CHARCNV,
+ "Bad char conversion");
+ }
+
+ /* Make sure the remaining part of the string is filled with zeroes */
+ if (ret < required) {
+ memset(ndr->data+ndr->offset+ret, 0, required-ret);
+ }
+
+ ndr->offset += required;
+
+ return NDR_ERR_SUCCESS;
+}
+
+/* Return number of elements in a string in the specified charset */
+_PUBLIC_ uint32_t ndr_charset_length(const void *var, charset_t chset)
+{
+ /* FIXME: Treat special chars special here, taking chset into account */
+ /* Also include 0 byte */
+ return strlen((const char *)var)+1;
+}
diff --git a/source3/librpc/ndr/sid.c b/source3/librpc/ndr/sid.c
new file mode 100644
index 0000000000..ed27375de1
--- /dev/null
+++ b/source3/librpc/ndr/sid.c
@@ -0,0 +1,230 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ libndr interface
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+enum ndr_err_code ndr_push_dom_sid(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *r)
+{
+ uint32_t cntr_sub_auths_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->sid_rev_num));
+ NDR_CHECK(ndr_push_int8(ndr, NDR_SCALARS, r->num_auths));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6));
+ for (cntr_sub_auths_0 = 0; cntr_sub_auths_0 < r->num_auths; cntr_sub_auths_0++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sub_auths[cntr_sub_auths_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_dom_sid(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *r)
+{
+ uint32_t cntr_sub_auths_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->sid_rev_num));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->num_auths));
+ if (r->num_auths > 15) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+ }
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6));
+ for (cntr_sub_auths_0 = 0; cntr_sub_auths_0 < r->num_auths; cntr_sub_auths_0++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sub_auths[cntr_sub_auths_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ convert a dom_sid to a string
+*/
+char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
+{
+ int i, ofs, maxlen;
+ uint32_t ia;
+ char *ret;
+
+ if (!sid) {
+ return talloc_strdup(mem_ctx, "(NULL SID)");
+ }
+
+ maxlen = sid->num_auths * 11 + 25;
+ ret = (char *)talloc_size(mem_ctx, maxlen);
+ if (!ret) return talloc_strdup(mem_ctx, "(SID ERR)");
+
+ /*
+ * BIG NOTE: this function only does SIDS where the identauth is not
+ * >= ^32 in a range of 2^48.
+ */
+
+ ia = (sid->id_auth[5]) +
+ (sid->id_auth[4] << 8 ) +
+ (sid->id_auth[3] << 16) +
+ (sid->id_auth[2] << 24);
+
+ ofs = snprintf(ret, maxlen, "S-%u-%lu",
+ (unsigned int)sid->sid_rev_num, (unsigned long)ia);
+
+ for (i = 0; i < sid->num_auths; i++) {
+ ofs += snprintf(ret + ofs, maxlen - ofs, "-%lu", (unsigned long)sid->sub_auths[i]);
+ }
+
+ return ret;
+}
+
+/*
+ parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field
+*/
+enum ndr_err_code ndr_pull_dom_sid2(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid)
+{
+ uint32_t num_auths;
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &num_auths));
+ NDR_CHECK(ndr_pull_dom_sid(ndr, ndr_flags, sid));
+ if (sid->num_auths != num_auths) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
+ "Bad array size %u should exceed %u",
+ num_auths, sid->num_auths);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field
+*/
+enum ndr_err_code ndr_push_dom_sid2(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid)
+{
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, sid->num_auths));
+ return ndr_push_dom_sid(ndr, ndr_flags, sid);
+}
+
+/*
+ parse a dom_sid28 - this is a dom_sid in a fixed 28 byte buffer, so we need to ensure there are only upto 5 sub_auth
+*/
+enum ndr_err_code ndr_pull_dom_sid28(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid)
+{
+ enum ndr_err_code status;
+ struct ndr_pull *subndr;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ subndr = talloc_zero(ndr, struct ndr_pull);
+ NDR_ERR_HAVE_NO_MEMORY(subndr);
+ subndr->flags = ndr->flags;
+ subndr->current_mem_ctx = ndr->current_mem_ctx;
+
+ subndr->data = ndr->data + ndr->offset;
+ subndr->data_size = 28;
+ subndr->offset = 0;
+
+ NDR_CHECK(ndr_pull_advance(ndr, 28));
+
+ status = ndr_pull_dom_sid(subndr, ndr_flags, sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
+ /* handle a w2k bug which send random data in the buffer */
+ ZERO_STRUCTP(sid);
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a dom_sid28 - this is a dom_sid in a 28 byte fixed buffer
+*/
+enum ndr_err_code ndr_push_dom_sid28(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid)
+{
+ uint32_t old_offset;
+ uint32_t padding;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (sid->num_auths > 5) {
+ return ndr_push_error(ndr, NDR_ERR_RANGE,
+ "dom_sid28 allows only upto 5 sub auth [%u]",
+ sid->num_auths);
+ }
+
+ old_offset = ndr->offset;
+ NDR_CHECK(ndr_push_dom_sid(ndr, ndr_flags, sid));
+
+ padding = 28 - (ndr->offset - old_offset);
+
+ if (padding > 0) {
+ NDR_CHECK(ndr_push_zero(ndr, padding));
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a dom_sid0 - this is a dom_sid in a variable byte buffer, which is maybe empty
+*/
+enum ndr_err_code ndr_pull_dom_sid0(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid)
+{
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (ndr->data_size == ndr->offset) {
+ ZERO_STRUCTP(sid);
+ return NDR_ERR_SUCCESS;
+ }
+
+ return ndr_pull_dom_sid(ndr, ndr_flags, sid);
+}
+
+/*
+ push a dom_sid0 - this is a dom_sid in a variable byte buffer, which is maybe empty
+*/
+enum ndr_err_code ndr_push_dom_sid0(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid)
+{
+ struct dom_sid zero_sid;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (!sid) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ ZERO_STRUCT(zero_sid);
+
+ if (memcmp(&zero_sid, sid, sizeof(zero_sid)) == 0) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ return ndr_push_dom_sid(ndr, ndr_flags, sid);
+}
diff --git a/source3/librpc/ndr/uuid.c b/source3/librpc/ndr/uuid.c
new file mode 100644
index 0000000000..e92df22494
--- /dev/null
+++ b/source3/librpc/ndr/uuid.c
@@ -0,0 +1,227 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ UUID/GUID functions
+
+ Copyright (C) Theodore Ts'o 1996, 1997,
+ Copyright (C) Jim McDonough 2002.
+ Copyright (C) Andrew Tridgell 2003.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/ndr/libndr.h"
+
+/**
+ build a GUID from a string
+*/
+_PUBLIC_ NTSTATUS GUID_from_string(const char *s, struct GUID *guid)
+{
+ NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
+ uint32_t time_low;
+ uint32_t time_mid, time_hi_and_version;
+ uint32_t clock_seq[2];
+ uint32_t node[6];
+ int i;
+
+ if (s == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (11 == sscanf(s, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ &time_low, &time_mid, &time_hi_and_version,
+ &clock_seq[0], &clock_seq[1],
+ &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) {
+ status = NT_STATUS_OK;
+ } else if (11 == sscanf(s, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
+ &time_low, &time_mid, &time_hi_and_version,
+ &clock_seq[0], &clock_seq[1],
+ &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) {
+ status = NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ guid->time_low = time_low;
+ guid->time_mid = time_mid;
+ guid->time_hi_and_version = time_hi_and_version;
+ guid->clock_seq[0] = clock_seq[0];
+ guid->clock_seq[1] = clock_seq[1];
+ for (i=0;i<6;i++) {
+ guid->node[i] = node[i];
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ build a GUID from a string
+*/
+_PUBLIC_ NTSTATUS NS_GUID_from_string(const char *s, struct GUID *guid)
+{
+ NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
+ uint32_t time_low;
+ uint32_t time_mid, time_hi_and_version;
+ uint32_t clock_seq[2];
+ uint32_t node[6];
+ int i;
+
+ if (s == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (11 == sscanf(s, "%08x-%04x%04x-%02x%02x%02x%02x-%02x%02x%02x%02x",
+ &time_low, &time_mid, &time_hi_and_version,
+ &clock_seq[0], &clock_seq[1],
+ &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) {
+ status = NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ guid->time_low = time_low;
+ guid->time_mid = time_mid;
+ guid->time_hi_and_version = time_hi_and_version;
+ guid->clock_seq[0] = clock_seq[0];
+ guid->clock_seq[1] = clock_seq[1];
+ for (i=0;i<6;i++) {
+ guid->node[i] = node[i];
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * generate a random GUID
+ */
+struct GUID GUID_random(void)
+{
+ struct GUID guid;
+
+ generate_random_buffer((uint8_t *)&guid, sizeof(guid));
+ guid.clock_seq[0] = (guid.clock_seq[0] & 0x3F) | 0x80;
+ guid.time_hi_and_version = (guid.time_hi_and_version & 0x0FFF) | 0x4000;
+
+ return guid;
+}
+
+/**
+ * generate an empty GUID
+ */
+_PUBLIC_ struct GUID GUID_zero(void)
+{
+ struct GUID guid;
+
+ ZERO_STRUCT(guid);
+
+ return guid;
+}
+
+_PUBLIC_ bool GUID_all_zero(const struct GUID *u)
+{
+ if (u->time_low != 0 ||
+ u->time_mid != 0 ||
+ u->time_hi_and_version != 0 ||
+ u->clock_seq[0] != 0 ||
+ u->clock_seq[1] != 0 ||
+ !all_zero(u->node, 6)) {
+ return false;
+ }
+ return true;
+}
+
+_PUBLIC_ bool GUID_equal(const struct GUID *u1, const struct GUID *u2)
+{
+ if (u1->time_low != u2->time_low ||
+ u1->time_mid != u2->time_mid ||
+ u1->time_hi_and_version != u2->time_hi_and_version ||
+ u1->clock_seq[0] != u2->clock_seq[0] ||
+ u1->clock_seq[1] != u2->clock_seq[1] ||
+ memcmp(u1->node, u2->node, 6) != 0) {
+ return false;
+ }
+ return true;
+}
+
+_PUBLIC_ int GUID_compare(const struct GUID *u1, const struct GUID *u2)
+{
+ if (u1->time_low != u2->time_low) {
+ return u1->time_low - u2->time_low;
+ }
+
+ if (u1->time_mid != u2->time_mid) {
+ return u1->time_mid - u2->time_mid;
+ }
+
+ if (u1->time_hi_and_version != u2->time_hi_and_version) {
+ return u1->time_hi_and_version - u2->time_hi_and_version;
+ }
+
+ if (u1->clock_seq[0] != u2->clock_seq[0]) {
+ return u1->clock_seq[0] - u2->clock_seq[0];
+ }
+
+ if (u1->clock_seq[1] != u2->clock_seq[1]) {
+ return u1->clock_seq[1] - u2->clock_seq[1];
+ }
+
+ return memcmp(u1->node, u2->node, 6);
+}
+
+/**
+ its useful to be able to display these in debugging messages
+*/
+_PUBLIC_ char *GUID_string(TALLOC_CTX *mem_ctx, const struct GUID *guid)
+{
+ return talloc_asprintf(mem_ctx,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ guid->time_low, guid->time_mid,
+ guid->time_hi_and_version,
+ guid->clock_seq[0],
+ guid->clock_seq[1],
+ guid->node[0], guid->node[1],
+ guid->node[2], guid->node[3],
+ guid->node[4], guid->node[5]);
+}
+
+_PUBLIC_ char *GUID_string2(TALLOC_CTX *mem_ctx, const struct GUID *guid)
+{
+ char *ret, *s = GUID_string(mem_ctx, guid);
+ ret = talloc_asprintf(mem_ctx, "{%s}", s);
+ talloc_free(s);
+ return ret;
+}
+
+_PUBLIC_ char *NS_GUID_string(TALLOC_CTX *mem_ctx, const struct GUID *guid)
+{
+ return talloc_asprintf(mem_ctx,
+ "%08x-%04x%04x-%02x%02x%02x%02x-%02x%02x%02x%02x",
+ guid->time_low, guid->time_mid,
+ guid->time_hi_and_version,
+ guid->clock_seq[0],
+ guid->clock_seq[1],
+ guid->node[0], guid->node[1],
+ guid->node[2], guid->node[3],
+ guid->node[4], guid->node[5]);
+}
+
+_PUBLIC_ bool policy_handle_empty(struct policy_handle *h)
+{
+ return (h->handle_type == 0 && GUID_all_zero(&h->uuid));
+}
diff --git a/source3/librpc/rpc/binding.c b/source3/librpc/rpc/binding.c
new file mode 100644
index 0000000000..01e3479c23
--- /dev/null
+++ b/source3/librpc/rpc/binding.c
@@ -0,0 +1,709 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc utility functions
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Jelmer Vernooij 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+ Copyright (C) Rafal Szczesniak 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#define MAX_PROTSEQ 10
+
+static const struct {
+ const char *name;
+ enum dcerpc_transport_t transport;
+ int num_protocols;
+ enum epm_protocol protseq[MAX_PROTSEQ];
+} transports[] = {
+ { "ncacn_np", NCACN_NP, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB, EPM_PROTOCOL_NETBIOS }},
+ { "ncacn_ip_tcp", NCACN_IP_TCP, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP, EPM_PROTOCOL_IP } },
+ { "ncacn_http", NCACN_HTTP, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP, EPM_PROTOCOL_IP } },
+ { "ncadg_ip_udp", NCACN_IP_UDP, 3,
+ { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UDP, EPM_PROTOCOL_IP } },
+ { "ncalrpc", NCALRPC, 2,
+ { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE } },
+ { "ncacn_unix_stream", NCACN_UNIX_STREAM, 2,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_UNIX_DS } },
+ { "ncadg_unix_dgram", NCADG_UNIX_DGRAM, 2,
+ { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UNIX_DS } },
+ { "ncacn_at_dsp", NCACN_AT_DSP, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DSP } },
+ { "ncadg_at_ddp", NCADG_AT_DDP, 3,
+ { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DDP } },
+ { "ncacn_vns_ssp", NCACN_VNS_SPP, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_SPP } },
+ { "ncacn_vns_ipc", NCACN_VNS_IPC, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_IPC }, },
+ { "ncadg_ipx", NCADG_IPX, 2,
+ { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_IPX },
+ },
+ { "ncacn_spx", NCACN_SPX, 3,
+ /* I guess some MS programmer confused the identifier for
+ * EPM_PROTOCOL_UUID (0x0D or 13) with the one for
+ * EPM_PROTOCOL_SPX (0x13) here. -- jelmer*/
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_UUID },
+ },
+};
+
+static const struct {
+ const char *name;
+ uint32_t flag;
+} ncacn_options[] = {
+ { "", 0 }
+};
+
+const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
+{
+ struct ndr_syntax_id syntax;
+ NTSTATUS status;
+
+ switch(epm_floor->lhs.protocol) {
+ case EPM_PROTOCOL_UUID:
+ status = dcerpc_floor_get_lhs_data(epm_floor, &syntax);
+ if (NT_STATUS_IS_OK(status)) {
+ /* lhs is used: UUID */
+ char *uuidstr;
+
+ if (GUID_equal(&syntax.uuid, &ndr_transfer_syntax.uuid)) {
+ return "NDR";
+ }
+
+ if (GUID_equal(&syntax.uuid, &ndr64_transfer_syntax.uuid)) {
+ return "NDR64";
+ }
+
+ uuidstr = GUID_string(mem_ctx, &syntax.uuid);
+
+ return talloc_asprintf(mem_ctx, " uuid %s/0x%02x", uuidstr, syntax.if_version);
+ } else { /* IPX */
+ return NULL;
+ }
+
+ case EPM_PROTOCOL_NCACN:
+ return "RPC-C";
+
+ case EPM_PROTOCOL_NCADG:
+ return "RPC";
+
+ case EPM_PROTOCOL_NCALRPC:
+ return "NCALRPC";
+
+ case EPM_PROTOCOL_DNET_NSP:
+ return "DNET/NSP";
+
+ case EPM_PROTOCOL_IP:
+ return talloc_asprintf(mem_ctx, "IP:%s", epm_floor->rhs.ip.ipaddr);
+
+ case EPM_PROTOCOL_PIPE:
+ return talloc_asprintf(mem_ctx, "PIPE:%s", epm_floor->rhs.pipe.path);
+
+ case EPM_PROTOCOL_SMB:
+ return talloc_asprintf(mem_ctx, "SMB:%s", epm_floor->rhs.smb.unc);
+
+ case EPM_PROTOCOL_UNIX_DS:
+ return talloc_asprintf(mem_ctx, "Unix:%s", epm_floor->rhs.unix_ds.path);
+
+ case EPM_PROTOCOL_NETBIOS:
+ return talloc_asprintf(mem_ctx, "NetBIOS:%s", epm_floor->rhs.netbios.name);
+
+ case EPM_PROTOCOL_NETBEUI:
+ return "NETBeui";
+
+ case EPM_PROTOCOL_SPX:
+ return "SPX";
+
+ case EPM_PROTOCOL_NB_IPX:
+ return "NB_IPX";
+
+ case EPM_PROTOCOL_HTTP:
+ return talloc_asprintf(mem_ctx, "HTTP:%d", epm_floor->rhs.http.port);
+
+ case EPM_PROTOCOL_TCP:
+ return talloc_asprintf(mem_ctx, "TCP:%d", epm_floor->rhs.tcp.port);
+
+ case EPM_PROTOCOL_UDP:
+ return talloc_asprintf(mem_ctx, "UDP:%d", epm_floor->rhs.udp.port);
+
+ default:
+ return talloc_asprintf(mem_ctx, "UNK(%02x):", epm_floor->lhs.protocol);
+ }
+}
+
+
+/*
+ form a binding string from a binding structure
+*/
+_PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b)
+{
+ char *s = talloc_strdup(mem_ctx, "");
+ int i;
+ const char *t_name = NULL;
+
+ if (b->transport != NCA_UNKNOWN) {
+ for (i=0;i<ARRAY_SIZE(transports);i++) {
+ if (transports[i].transport == b->transport) {
+ t_name = transports[i].name;
+ }
+ }
+ if (!t_name) {
+ return NULL;
+ }
+ }
+
+ if (!GUID_all_zero(&b->object.uuid)) {
+ s = talloc_asprintf(s, "%s@",
+ GUID_string(mem_ctx, &b->object.uuid));
+ }
+
+ if (t_name != NULL) {
+ s = talloc_asprintf_append_buffer(s, "%s:", t_name);
+ if (s == NULL) {
+ return NULL;
+ }
+ }
+
+ if (b->host) {
+ s = talloc_asprintf_append_buffer(s, "%s", b->host);
+ }
+
+ if (!b->endpoint && !b->options && !b->flags) {
+ return s;
+ }
+
+ s = talloc_asprintf_append_buffer(s, "[");
+
+ if (b->endpoint) {
+ s = talloc_asprintf_append_buffer(s, "%s", b->endpoint);
+ }
+
+ /* this is a *really* inefficent way of dealing with strings,
+ but this is rarely called and the strings are always short,
+ so I don't care */
+ for (i=0;b->options && b->options[i];i++) {
+ s = talloc_asprintf_append_buffer(s, ",%s", b->options[i]);
+ if (!s) return NULL;
+ }
+
+ for (i=0;i<ARRAY_SIZE(ncacn_options);i++) {
+ if (b->flags & ncacn_options[i].flag) {
+ s = talloc_asprintf_append_buffer(s, ",%s", ncacn_options[i].name);
+ if (!s) return NULL;
+ }
+ }
+
+ s = talloc_asprintf_append_buffer(s, "]");
+
+ return s;
+}
+
+/*
+ parse a binding string into a dcerpc_binding structure
+*/
+_PUBLIC_ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_binding **b_out)
+{
+ struct dcerpc_binding *b;
+ char *options;
+ char *p;
+ int i, j, comma_count;
+
+ b = talloc(mem_ctx, struct dcerpc_binding);
+ if (!b) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ p = strchr(s, '@');
+
+ if (p && PTR_DIFF(p, s) == 36) { /* 36 is the length of a UUID */
+ NTSTATUS status;
+
+ status = GUID_from_string(s, &b->object.uuid);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ DEBUG(0, ("Failed parsing UUID\n"));
+ return status;
+ }
+
+ s = p + 1;
+ } else {
+ ZERO_STRUCT(b->object);
+ }
+
+ b->object.if_version = 0;
+
+ p = strchr(s, ':');
+
+ if (p == NULL) {
+ b->transport = NCA_UNKNOWN;
+ } else {
+ char *type = talloc_strndup(mem_ctx, s, PTR_DIFF(p, s));
+ if (!type) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0;i<ARRAY_SIZE(transports);i++) {
+ if (strcmp(type, transports[i].name) == 0) {
+ b->transport = transports[i].transport;
+ break;
+ }
+ }
+
+ if (i==ARRAY_SIZE(transports)) {
+ DEBUG(0,("Unknown dcerpc transport '%s'\n", type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ talloc_free(type);
+
+ s = p+1;
+ }
+
+ p = strchr(s, '[');
+ if (p) {
+ b->host = talloc_strndup(b, s, PTR_DIFF(p, s));
+ options = talloc_strdup(mem_ctx, p+1);
+ if (options[strlen(options)-1] != ']') {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ options[strlen(options)-1] = 0;
+ } else {
+ b->host = talloc_strdup(b, s);
+ options = NULL;
+ }
+ if (!b->host) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ b->target_hostname = b->host;
+
+ b->options = NULL;
+ b->flags = 0;
+ b->assoc_group_id = 0;
+ b->endpoint = NULL;
+
+ if (!options) {
+ *b_out = b;
+ return NT_STATUS_OK;
+ }
+
+ comma_count = count_chars(options, ',');
+
+ b->options = talloc_array(b, const char *, comma_count+2);
+ if (!b->options) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; (p = strchr(options, ',')); i++) {
+ b->options[i] = talloc_strndup(b, options, PTR_DIFF(p, options));
+ if (!b->options[i]) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ options = p+1;
+ }
+ b->options[i] = options;
+ b->options[i+1] = NULL;
+
+ /* some options are pre-parsed for convenience */
+ for (i=0;b->options[i];i++) {
+ for (j=0;j<ARRAY_SIZE(ncacn_options);j++) {
+ if (strcmp(ncacn_options[j].name, b->options[i]) == 0) {
+ int k;
+ b->flags |= ncacn_options[j].flag;
+ for (k=i;b->options[k];k++) {
+ b->options[k] = b->options[k+1];
+ }
+ i--;
+ break;
+ }
+ }
+ }
+
+ if (b->options[0]) {
+ /* Endpoint is first option */
+ b->endpoint = b->options[0];
+ if (strlen(b->endpoint) == 0) b->endpoint = NULL;
+
+ for (i=0;b->options[i];i++) {
+ b->options[i] = b->options[i+1];
+ }
+ }
+
+ if (b->options[0] == NULL)
+ b->options = NULL;
+
+ *b_out = b;
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS dcerpc_floor_get_lhs_data(struct epm_floor *epm_floor, struct ndr_syntax_id *syntax)
+{
+ TALLOC_CTX *mem_ctx = talloc_init("floor_get_lhs_data");
+ struct ndr_pull *ndr = ndr_pull_init_blob(&epm_floor->lhs.lhs_data, mem_ctx);
+ enum ndr_err_code ndr_err;
+ uint16_t if_version=0;
+
+ ndr->flags |= LIBNDR_FLAG_NOALIGN;
+
+ ndr_err = ndr_pull_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(mem_ctx);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ ndr_err = ndr_pull_uint16(ndr, NDR_SCALARS, &if_version);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(mem_ctx);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ syntax->if_version = if_version;
+
+ talloc_free(mem_ctx);
+
+ return NT_STATUS_OK;
+}
+
+static DATA_BLOB dcerpc_floor_pack_lhs_data(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax)
+{
+ struct ndr_push *ndr = ndr_push_init_ctx(mem_ctx);
+
+ ndr->flags |= LIBNDR_FLAG_NOALIGN;
+
+ ndr_push_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
+ ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version);
+
+ return ndr_push_blob(ndr);
+}
+
+const char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
+{
+ switch (epm_floor->lhs.protocol) {
+ case EPM_PROTOCOL_TCP:
+ if (epm_floor->rhs.tcp.port == 0) return NULL;
+ return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.tcp.port);
+
+ case EPM_PROTOCOL_UDP:
+ if (epm_floor->rhs.udp.port == 0) return NULL;
+ return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.udp.port);
+
+ case EPM_PROTOCOL_HTTP:
+ if (epm_floor->rhs.http.port == 0) return NULL;
+ return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.http.port);
+
+ case EPM_PROTOCOL_IP:
+ return talloc_strdup(mem_ctx, epm_floor->rhs.ip.ipaddr);
+
+ case EPM_PROTOCOL_NCACN:
+ return NULL;
+
+ case EPM_PROTOCOL_NCADG:
+ return NULL;
+
+ case EPM_PROTOCOL_SMB:
+ if (strlen(epm_floor->rhs.smb.unc) == 0) return NULL;
+ return talloc_strdup(mem_ctx, epm_floor->rhs.smb.unc);
+
+ case EPM_PROTOCOL_PIPE:
+ if (strlen(epm_floor->rhs.pipe.path) == 0) return NULL;
+ return talloc_strdup(mem_ctx, epm_floor->rhs.pipe.path);
+
+ case EPM_PROTOCOL_NETBIOS:
+ if (strlen(epm_floor->rhs.netbios.name) == 0) return NULL;
+ return talloc_strdup(mem_ctx, epm_floor->rhs.netbios.name);
+
+ case EPM_PROTOCOL_NCALRPC:
+ return NULL;
+
+ case EPM_PROTOCOL_VINES_SPP:
+ return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_spp.port);
+
+ case EPM_PROTOCOL_VINES_IPC:
+ return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_ipc.port);
+
+ case EPM_PROTOCOL_STREETTALK:
+ return talloc_strdup(mem_ctx, epm_floor->rhs.streettalk.streettalk);
+
+ case EPM_PROTOCOL_UNIX_DS:
+ if (strlen(epm_floor->rhs.unix_ds.path) == 0) return NULL;
+ return talloc_strdup(mem_ctx, epm_floor->rhs.unix_ds.path);
+
+ case EPM_PROTOCOL_NULL:
+ return NULL;
+
+ default:
+ DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
+ break;
+ }
+
+ return NULL;
+}
+
+static NTSTATUS dcerpc_floor_set_rhs_data(TALLOC_CTX *mem_ctx,
+ struct epm_floor *epm_floor,
+ const char *data)
+{
+ switch (epm_floor->lhs.protocol) {
+ case EPM_PROTOCOL_TCP:
+ epm_floor->rhs.tcp.port = atoi(data);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_UDP:
+ epm_floor->rhs.udp.port = atoi(data);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_HTTP:
+ epm_floor->rhs.http.port = atoi(data);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_IP:
+ epm_floor->rhs.ip.ipaddr = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.ip.ipaddr);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_NCACN:
+ epm_floor->rhs.ncacn.minor_version = 0;
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_NCADG:
+ epm_floor->rhs.ncadg.minor_version = 0;
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_SMB:
+ epm_floor->rhs.smb.unc = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.smb.unc);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_PIPE:
+ epm_floor->rhs.pipe.path = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.pipe.path);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_NETBIOS:
+ epm_floor->rhs.netbios.name = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.netbios.name);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_NCALRPC:
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_VINES_SPP:
+ epm_floor->rhs.vines_spp.port = atoi(data);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_VINES_IPC:
+ epm_floor->rhs.vines_ipc.port = atoi(data);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_STREETTALK:
+ epm_floor->rhs.streettalk.streettalk = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.streettalk.streettalk);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_UNIX_DS:
+ epm_floor->rhs.unix_ds.path = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.unix_ds.path);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_NULL:
+ return NT_STATUS_OK;
+
+ default:
+ DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
+ break;
+ }
+
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot)
+{
+ int i;
+
+ /* Find a transport that has 'prot' as 4th protocol */
+ for (i=0;i<ARRAY_SIZE(transports);i++) {
+ if (transports[i].num_protocols >= 2 &&
+ transports[i].protseq[1] == prot) {
+ return transports[i].transport;
+ }
+ }
+
+ /* Unknown transport */
+ return (unsigned int)-1;
+}
+
+_PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_tower(struct epm_tower *tower)
+{
+ int i;
+
+ /* Find a transport that matches this tower */
+ for (i=0;i<ARRAY_SIZE(transports);i++) {
+ int j;
+ if (transports[i].num_protocols != tower->num_floors - 2) {
+ continue;
+ }
+
+ for (j = 0; j < transports[i].num_protocols; j++) {
+ if (transports[i].protseq[j] != tower->floors[j+2].lhs.protocol) {
+ break;
+ }
+ }
+
+ if (j == transports[i].num_protocols) {
+ return transports[i].transport;
+ }
+ }
+
+ /* Unknown transport */
+ return (unsigned int)-1;
+}
+
+_PUBLIC_ NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
+ struct epm_tower *tower,
+ struct dcerpc_binding **b_out)
+{
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+
+ binding = talloc(mem_ctx, struct dcerpc_binding);
+ NT_STATUS_HAVE_NO_MEMORY(binding);
+
+ ZERO_STRUCT(binding->object);
+ binding->options = NULL;
+ binding->host = NULL;
+ binding->target_hostname = NULL;
+ binding->flags = 0;
+ binding->assoc_group_id = 0;
+
+ binding->transport = dcerpc_transport_by_tower(tower);
+
+ if (binding->transport == (unsigned int)-1) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ if (tower->num_floors < 1) {
+ return NT_STATUS_OK;
+ }
+
+ /* Set object uuid */
+ status = dcerpc_floor_get_lhs_data(&tower->floors[0], &binding->object);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Error pulling object uuid and version: %s", nt_errstr(status)));
+ return status;
+ }
+
+ /* Ignore floor 1, it contains the NDR version info */
+
+ binding->options = NULL;
+
+ /* Set endpoint */
+ if (tower->num_floors >= 4) {
+ binding->endpoint = dcerpc_floor_get_rhs_data(mem_ctx, &tower->floors[3]);
+ } else {
+ binding->endpoint = NULL;
+ }
+
+ /* Set network address */
+ if (tower->num_floors >= 5) {
+ binding->host = dcerpc_floor_get_rhs_data(mem_ctx, &tower->floors[4]);
+ NT_STATUS_HAVE_NO_MEMORY(binding->host);
+ binding->target_hostname = binding->host;
+ }
+ *b_out = binding;
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding, struct epm_tower *tower)
+{
+ const enum epm_protocol *protseq = NULL;
+ int num_protocols = -1, i;
+ NTSTATUS status;
+
+ /* Find transport */
+ for (i=0;i<ARRAY_SIZE(transports);i++) {
+ if (transports[i].transport == binding->transport) {
+ protseq = transports[i].protseq;
+ num_protocols = transports[i].num_protocols;
+ break;
+ }
+ }
+
+ if (num_protocols == -1) {
+ DEBUG(0, ("Unable to find transport with id '%d'\n", binding->transport));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ tower->num_floors = 2 + num_protocols;
+ tower->floors = talloc_array(mem_ctx, struct epm_floor, tower->num_floors);
+
+ /* Floor 0 */
+ tower->floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
+
+ tower->floors[0].lhs.lhs_data = dcerpc_floor_pack_lhs_data(mem_ctx, &binding->object);
+
+ tower->floors[0].rhs.uuid.unknown = data_blob_talloc_zero(mem_ctx, 2);
+
+ /* Floor 1 */
+ tower->floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
+
+ tower->floors[1].lhs.lhs_data = dcerpc_floor_pack_lhs_data(mem_ctx,
+ &ndr_transfer_syntax);
+
+ tower->floors[1].rhs.uuid.unknown = data_blob_talloc_zero(mem_ctx, 2);
+
+ /* Floor 2 to num_protocols */
+ for (i = 0; i < num_protocols; i++) {
+ tower->floors[2 + i].lhs.protocol = protseq[i];
+ tower->floors[2 + i].lhs.lhs_data = data_blob_talloc(mem_ctx, NULL, 0);
+ ZERO_STRUCT(tower->floors[2 + i].rhs);
+ dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[2 + i], "");
+ }
+
+ /* The 4th floor contains the endpoint */
+ if (num_protocols >= 2 && binding->endpoint) {
+ status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[3], binding->endpoint);
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+ }
+
+ /* The 5th contains the network address */
+ if (num_protocols >= 3 && binding->host) {
+ if (is_ipaddress(binding->host)) {
+ status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[4],
+ binding->host);
+ } else {
+ /* note that we don't attempt to resolve the
+ name here - when we get a hostname here we
+ are in the client code, and want to put in
+ a wildcard all-zeros IP for the server to
+ fill in */
+ status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[4],
+ "0.0.0.0");
+ }
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/librpc/rpc/dcerpc.c b/source3/librpc/rpc/dcerpc.c
new file mode 100644
index 0000000000..58d676a9d9
--- /dev/null
+++ b/source3/librpc/rpc/dcerpc.c
@@ -0,0 +1,180 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba 4-compatible DCE/RPC API on top of the Samba 3 DCE/RPC client library.
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/rpc/dcerpc.h"
+
+/**
+ * Send a struct-based RPC request using the Samba 3 RPC client library.
+ */
+struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p, const struct GUID *object,
+ const struct ndr_interface_table *table, uint32_t opnum,
+ TALLOC_CTX *mem_ctx, void *r)
+{
+ const struct ndr_interface_call *call;
+ struct ndr_push *push;
+ struct rpc_request *ret = talloc(mem_ctx, struct rpc_request);
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+
+ if (ret == NULL)
+ return NULL;
+
+ SMB_ASSERT(p->table->num_calls > opnum);
+
+ call = &p->table->calls[opnum];
+
+ ret->call = call;
+ ret->r = r;
+
+ push = ndr_push_init_ctx(mem_ctx);
+ if (!push) {
+ return NULL;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ /* FIXME: ndr_map_error2ntstatus(ndr_err); */
+ return NULL;
+ }
+
+ blob = ndr_push_blob(push);
+
+ if (!prs_init_data_blob(&ret->q_ps, &blob, mem_ctx)) {
+ return NULL;
+ }
+
+ talloc_free(push);
+
+ ret->opnum = opnum;
+
+ ret->pipe = p;
+
+ return ret;
+}
+
+/**
+ * Wait for a DCE/RPC request.
+ *
+ * @note at the moment this is still sync, even though the API is async.
+ */
+NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
+{
+ prs_struct r_ps;
+ struct ndr_pull *pull;
+ NTSTATUS status;
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ prs_init_empty( &r_ps, req, UNMARSHALL );
+
+ status = rpc_api_pipe_req(req->pipe->rpc_cli, req->opnum, &req->q_ps, &r_ps);
+
+ prs_mem_free( &req->q_ps );
+
+ if (!NT_STATUS_IS_OK(status)) {
+ prs_mem_free( &r_ps );
+ return status;
+ }
+
+ if (!prs_data_blob(&r_ps, &blob, req)) {
+ prs_mem_free( &r_ps );
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ prs_mem_free( &r_ps );
+
+ pull = ndr_pull_init_blob(&blob, req);
+ if (pull == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* have the ndr parser alloc memory for us */
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = req->call->ndr_pull(pull, NDR_OUT, req->r);
+ talloc_free(pull);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Connect to a DCE/RPC interface.
+ *
+ * @note lp_ctx and ev are ignored at the moment but present
+ * for API compatibility.
+ */
+_PUBLIC_ NTSTATUS dcerpc_pipe_connect(TALLOC_CTX *parent_ctx, struct dcerpc_pipe **pp,
+ const char *binding_string, const struct ndr_interface_table *table,
+ struct cli_credentials *credentials, struct event_context *ev,
+ struct loadparm_context *lp_ctx)
+{
+ struct dcerpc_pipe *p = talloc(parent_ctx, struct dcerpc_pipe);
+ struct dcerpc_binding *binding;
+ NTSTATUS nt_status;
+
+ nt_status = dcerpc_parse_binding(p, binding_string, &binding);
+
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ DEBUG(1, ("Unable to parse binding string '%s'", binding_string));
+ talloc_free(p);
+ return nt_status;
+ }
+
+ if (binding->transport != NCACN_NP) {
+ DEBUG(0, ("Only ncacn_np supported"));
+ talloc_free(p);
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ /* FIXME: Actually use loadparm_context.. */
+
+ /* FIXME: actually use credentials */
+
+ nt_status = cli_full_connection(&p->cli, global_myname(), binding->host,
+ NULL, 0,
+ "IPC$", "IPC",
+ get_cmdline_auth_info_username(),
+ lp_workgroup(),
+ get_cmdline_auth_info_password(),
+ get_cmdline_auth_info_use_kerberos() ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
+ get_cmdline_auth_info_signing_state(), NULL);
+
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ talloc_free(p);
+ return nt_status;
+ }
+
+ nt_status = cli_rpc_pipe_open_noauth(p->cli, &table->syntax_id,
+ &p->rpc_cli);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ talloc_free(p);
+ return nt_status;
+ }
+
+ p->table = table;
+
+ *pp = p;
+
+ return nt_status;
+}
diff --git a/source3/librpc/rpc/dcerpc.h b/source3/librpc/rpc/dcerpc.h
new file mode 100644
index 0000000000..739e60a341
--- /dev/null
+++ b/source3/librpc/rpc/dcerpc.h
@@ -0,0 +1,75 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ DCERPC client side interface structures
+
+ Copyright (C) 2008 Jelmer Vernooij
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This is a public header file that is installed as part of Samba.
+ * If you remove any functions or change their signature, update
+ * the so version number. */
+
+#ifndef __DCERPC_H__
+#define __DCERPC_H__
+
+#include "includes.h"
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/gen_ndr/epmapper.h"
+
+struct loadparm_context;
+struct cli_credentials;
+
+/**
+ * Connection to a particular DCE/RPC interface.
+ */
+struct dcerpc_pipe {
+ const struct ndr_interface_table *table;
+
+ /** SMB context used when transport is ncacn_np. */
+ struct cli_state *cli;
+
+ /** Samba 3 DCE/RPC client context. */
+ struct rpc_pipe_client *rpc_cli;
+};
+
+struct rpc_request {
+ const struct ndr_interface_call *call;
+ prs_struct q_ps;
+ uint32_t opnum;
+ struct dcerpc_pipe *pipe;
+ void *r;
+};
+
+enum dcerpc_transport_t {
+ NCA_UNKNOWN, NCACN_NP, NCACN_IP_TCP, NCACN_IP_UDP, NCACN_VNS_IPC,
+ NCACN_VNS_SPP, NCACN_AT_DSP, NCADG_AT_DDP, NCALRPC, NCACN_UNIX_STREAM,
+ NCADG_UNIX_DGRAM, NCACN_HTTP, NCADG_IPX, NCACN_SPX };
+
+
+/** this describes a binding to a particular transport/pipe */
+struct dcerpc_binding {
+ enum dcerpc_transport_t transport;
+ struct ndr_syntax_id object;
+ const char *host;
+ const char *target_hostname;
+ const char *endpoint;
+ const char **options;
+ uint32_t flags;
+ uint32_t assoc_group_id;
+};
+
+#endif /* __DCERPC_H__ */
diff --git a/source3/librpc/rpc/dcerpc_util.c b/source3/librpc/rpc/dcerpc_util.c
new file mode 100644
index 0000000000..3b8768ccc2
--- /dev/null
+++ b/source3/librpc/rpc/dcerpc_util.c
@@ -0,0 +1,1438 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc utility functions
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Jelmer Vernooij 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+ Copyright (C) Rafal Szczesniak 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/events/events.h"
+#include "libcli/composite/composite.h"
+#include "librpc/gen_ndr/ndr_epmapper_c.h"
+#include "librpc/gen_ndr/ndr_dcerpc.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/rpc/dcerpc_proto.h"
+#include "auth/credentials/credentials.h"
+#include "param/param.h"
+
+/*
+ find a dcerpc call on an interface by name
+*/
+const struct ndr_interface_call *dcerpc_iface_find_call(const struct ndr_interface_table *iface,
+ const char *name)
+{
+ int i;
+ for (i=0;i<iface->num_calls;i++) {
+ if (strcmp(iface->calls[i].name, name) == 0) {
+ return &iface->calls[i];
+ }
+ }
+ return NULL;
+}
+
+/*
+ push a ncacn_packet into a blob, potentially with auth info
+*/
+NTSTATUS ncacn_push_auth(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
+ struct smb_iconv_convenience *iconv_convenience,
+ struct ncacn_packet *pkt,
+ struct dcerpc_auth *auth_info)
+{
+ struct ndr_push *ndr;
+ enum ndr_err_code ndr_err;
+
+ ndr = ndr_push_init_ctx(mem_ctx, iconv_convenience);
+ if (!ndr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
+ ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
+ }
+
+ if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
+ ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
+ }
+
+ if (auth_info) {
+ pkt->auth_length = auth_info->credentials.length;
+ } else {
+ pkt->auth_length = 0;
+ }
+
+ ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ if (auth_info) {
+ ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth_info);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ }
+
+ *blob = ndr_push_blob(ndr);
+
+ /* fill in the frag length */
+ dcerpc_set_frag_length(blob, blob->length);
+
+ return NT_STATUS_OK;
+}
+
+#define MAX_PROTSEQ 10
+
+static const struct {
+ const char *name;
+ enum dcerpc_transport_t transport;
+ int num_protocols;
+ enum epm_protocol protseq[MAX_PROTSEQ];
+} transports[] = {
+ { "ncacn_np", NCACN_NP, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB, EPM_PROTOCOL_NETBIOS }},
+ { "ncacn_ip_tcp", NCACN_IP_TCP, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP, EPM_PROTOCOL_IP } },
+ { "ncacn_http", NCACN_HTTP, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP, EPM_PROTOCOL_IP } },
+ { "ncadg_ip_udp", NCACN_IP_UDP, 3,
+ { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UDP, EPM_PROTOCOL_IP } },
+ { "ncalrpc", NCALRPC, 2,
+ { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE } },
+ { "ncacn_unix_stream", NCACN_UNIX_STREAM, 2,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_UNIX_DS } },
+ { "ncadg_unix_dgram", NCADG_UNIX_DGRAM, 2,
+ { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UNIX_DS } },
+ { "ncacn_at_dsp", NCACN_AT_DSP, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DSP } },
+ { "ncadg_at_ddp", NCADG_AT_DDP, 3,
+ { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DDP } },
+ { "ncacn_vns_ssp", NCACN_VNS_SPP, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_SPP } },
+ { "ncacn_vns_ipc", NCACN_VNS_IPC, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_IPC }, },
+ { "ncadg_ipx", NCADG_IPX, 2,
+ { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_IPX },
+ },
+ { "ncacn_spx", NCACN_SPX, 3,
+ /* I guess some MS programmer confused the identifier for
+ * EPM_PROTOCOL_UUID (0x0D or 13) with the one for
+ * EPM_PROTOCOL_SPX (0x13) here. -- jelmer*/
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_UUID },
+ },
+};
+
+static const struct {
+ const char *name;
+ uint32_t flag;
+} ncacn_options[] = {
+ {"sign", DCERPC_SIGN},
+ {"seal", DCERPC_SEAL},
+ {"connect", DCERPC_CONNECT},
+ {"spnego", DCERPC_AUTH_SPNEGO},
+ {"ntlm", DCERPC_AUTH_NTLM},
+ {"krb5", DCERPC_AUTH_KRB5},
+ {"validate", DCERPC_DEBUG_VALIDATE_BOTH},
+ {"print", DCERPC_DEBUG_PRINT_BOTH},
+ {"padcheck", DCERPC_DEBUG_PAD_CHECK},
+ {"bigendian", DCERPC_PUSH_BIGENDIAN},
+ {"smb2", DCERPC_SMB2}
+};
+
+const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
+{
+ struct ndr_syntax_id syntax;
+ NTSTATUS status;
+
+ switch(epm_floor->lhs.protocol) {
+ case EPM_PROTOCOL_UUID:
+ status = dcerpc_floor_get_lhs_data(epm_floor, &syntax);
+ if (NT_STATUS_IS_OK(status)) {
+ /* lhs is used: UUID */
+ char *uuidstr;
+
+ if (GUID_equal(&syntax.uuid, &ndr_transfer_syntax.uuid)) {
+ return "NDR";
+ }
+
+ if (GUID_equal(&syntax.uuid, &ndr64_transfer_syntax.uuid)) {
+ return "NDR64";
+ }
+
+ uuidstr = GUID_string(mem_ctx, &syntax.uuid);
+
+ return talloc_asprintf(mem_ctx, " uuid %s/0x%02x", uuidstr, syntax.if_version);
+ } else { /* IPX */
+ return talloc_asprintf(mem_ctx, "IPX:%s",
+ data_blob_hex_string(mem_ctx, &epm_floor->rhs.uuid.unknown));
+ }
+
+ case EPM_PROTOCOL_NCACN:
+ return "RPC-C";
+
+ case EPM_PROTOCOL_NCADG:
+ return "RPC";
+
+ case EPM_PROTOCOL_NCALRPC:
+ return "NCALRPC";
+
+ case EPM_PROTOCOL_DNET_NSP:
+ return "DNET/NSP";
+
+ case EPM_PROTOCOL_IP:
+ return talloc_asprintf(mem_ctx, "IP:%s", epm_floor->rhs.ip.ipaddr);
+
+ case EPM_PROTOCOL_PIPE:
+ return talloc_asprintf(mem_ctx, "PIPE:%s", epm_floor->rhs.pipe.path);
+
+ case EPM_PROTOCOL_SMB:
+ return talloc_asprintf(mem_ctx, "SMB:%s", epm_floor->rhs.smb.unc);
+
+ case EPM_PROTOCOL_UNIX_DS:
+ return talloc_asprintf(mem_ctx, "Unix:%s", epm_floor->rhs.unix_ds.path);
+
+ case EPM_PROTOCOL_NETBIOS:
+ return talloc_asprintf(mem_ctx, "NetBIOS:%s", epm_floor->rhs.netbios.name);
+
+ case EPM_PROTOCOL_NETBEUI:
+ return "NETBeui";
+
+ case EPM_PROTOCOL_SPX:
+ return "SPX";
+
+ case EPM_PROTOCOL_NB_IPX:
+ return "NB_IPX";
+
+ case EPM_PROTOCOL_HTTP:
+ return talloc_asprintf(mem_ctx, "HTTP:%d", epm_floor->rhs.http.port);
+
+ case EPM_PROTOCOL_TCP:
+ return talloc_asprintf(mem_ctx, "TCP:%d", epm_floor->rhs.tcp.port);
+
+ case EPM_PROTOCOL_UDP:
+ return talloc_asprintf(mem_ctx, "UDP:%d", epm_floor->rhs.udp.port);
+
+ default:
+ return talloc_asprintf(mem_ctx, "UNK(%02x):", epm_floor->lhs.protocol);
+ }
+}
+
+
+/*
+ form a binding string from a binding structure
+*/
+_PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b)
+{
+ char *s = talloc_strdup(mem_ctx, "");
+ int i;
+ const char *t_name = NULL;
+
+ if (b->transport != NCA_UNKNOWN) {
+ for (i=0;i<ARRAY_SIZE(transports);i++) {
+ if (transports[i].transport == b->transport) {
+ t_name = transports[i].name;
+ }
+ }
+ if (!t_name) {
+ return NULL;
+ }
+ }
+
+ if (!GUID_all_zero(&b->object.uuid)) {
+ s = talloc_asprintf(s, "%s@",
+ GUID_string(mem_ctx, &b->object.uuid));
+ }
+
+ if (t_name != NULL) {
+ s = talloc_asprintf_append_buffer(s, "%s:", t_name);
+ if (s == NULL) {
+ return NULL;
+ }
+ }
+
+ if (b->host) {
+ s = talloc_asprintf_append_buffer(s, "%s", b->host);
+ }
+
+ if (!b->endpoint && !b->options && !b->flags) {
+ return s;
+ }
+
+ s = talloc_asprintf_append_buffer(s, "[");
+
+ if (b->endpoint) {
+ s = talloc_asprintf_append_buffer(s, "%s", b->endpoint);
+ }
+
+ /* this is a *really* inefficent way of dealing with strings,
+ but this is rarely called and the strings are always short,
+ so I don't care */
+ for (i=0;b->options && b->options[i];i++) {
+ s = talloc_asprintf_append_buffer(s, ",%s", b->options[i]);
+ if (!s) return NULL;
+ }
+
+ for (i=0;i<ARRAY_SIZE(ncacn_options);i++) {
+ if (b->flags & ncacn_options[i].flag) {
+ s = talloc_asprintf_append_buffer(s, ",%s", ncacn_options[i].name);
+ if (!s) return NULL;
+ }
+ }
+
+ s = talloc_asprintf_append_buffer(s, "]");
+
+ return s;
+}
+
+/*
+ parse a binding string into a dcerpc_binding structure
+*/
+_PUBLIC_ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_binding **b_out)
+{
+ struct dcerpc_binding *b;
+ char *options;
+ char *p;
+ int i, j, comma_count;
+
+ b = talloc(mem_ctx, struct dcerpc_binding);
+ if (!b) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ p = strchr(s, '@');
+
+ if (p && PTR_DIFF(p, s) == 36) { /* 36 is the length of a UUID */
+ NTSTATUS status;
+
+ status = GUID_from_string(s, &b->object.uuid);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ DEBUG(0, ("Failed parsing UUID\n"));
+ return status;
+ }
+
+ s = p + 1;
+ } else {
+ ZERO_STRUCT(b->object);
+ }
+
+ b->object.if_version = 0;
+
+ p = strchr(s, ':');
+
+ if (p == NULL) {
+ b->transport = NCA_UNKNOWN;
+ } else {
+ char *type = talloc_strndup(mem_ctx, s, PTR_DIFF(p, s));
+ if (!type) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0;i<ARRAY_SIZE(transports);i++) {
+ if (strcasecmp(type, transports[i].name) == 0) {
+ b->transport = transports[i].transport;
+ break;
+ }
+ }
+
+ if (i==ARRAY_SIZE(transports)) {
+ DEBUG(0,("Unknown dcerpc transport '%s'\n", type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ talloc_free(type);
+
+ s = p+1;
+ }
+
+ p = strchr(s, '[');
+ if (p) {
+ b->host = talloc_strndup(b, s, PTR_DIFF(p, s));
+ options = talloc_strdup(mem_ctx, p+1);
+ if (options[strlen(options)-1] != ']') {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ options[strlen(options)-1] = 0;
+ } else {
+ b->host = talloc_strdup(b, s);
+ options = NULL;
+ }
+ if (!b->host) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ b->target_hostname = b->host;
+
+ b->options = NULL;
+ b->flags = 0;
+ b->assoc_group_id = 0;
+ b->endpoint = NULL;
+
+ if (!options) {
+ *b_out = b;
+ return NT_STATUS_OK;
+ }
+
+ comma_count = count_chars(options, ',');
+
+ b->options = talloc_array(b, const char *, comma_count+2);
+ if (!b->options) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; (p = strchr(options, ',')); i++) {
+ b->options[i] = talloc_strndup(b, options, PTR_DIFF(p, options));
+ if (!b->options[i]) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ options = p+1;
+ }
+ b->options[i] = options;
+ b->options[i+1] = NULL;
+
+ /* some options are pre-parsed for convenience */
+ for (i=0;b->options[i];i++) {
+ for (j=0;j<ARRAY_SIZE(ncacn_options);j++) {
+ if (strcasecmp(ncacn_options[j].name, b->options[i]) == 0) {
+ int k;
+ b->flags |= ncacn_options[j].flag;
+ for (k=i;b->options[k];k++) {
+ b->options[k] = b->options[k+1];
+ }
+ i--;
+ break;
+ }
+ }
+ }
+
+ if (b->options[0]) {
+ /* Endpoint is first option */
+ b->endpoint = b->options[0];
+ if (strlen(b->endpoint) == 0) b->endpoint = NULL;
+
+ for (i=0;b->options[i];i++) {
+ b->options[i] = b->options[i+1];
+ }
+ }
+
+ if (b->options[0] == NULL)
+ b->options = NULL;
+
+ *b_out = b;
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS dcerpc_floor_get_lhs_data(struct epm_floor *epm_floor, struct ndr_syntax_id *syntax)
+{
+ TALLOC_CTX *mem_ctx = talloc_init("floor_get_lhs_data");
+ struct ndr_pull *ndr = ndr_pull_init_blob(&epm_floor->lhs.lhs_data, mem_ctx, NULL);
+ enum ndr_err_code ndr_err;
+ uint16_t if_version=0;
+
+ ndr->flags |= LIBNDR_FLAG_NOALIGN;
+
+ ndr_err = ndr_pull_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(mem_ctx);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ ndr_err = ndr_pull_uint16(ndr, NDR_SCALARS, &if_version);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(mem_ctx);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ syntax->if_version = if_version;
+
+ talloc_free(mem_ctx);
+
+ return NT_STATUS_OK;
+}
+
+static DATA_BLOB dcerpc_floor_pack_lhs_data(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax)
+{
+ struct ndr_push *ndr = ndr_push_init_ctx(mem_ctx, NULL);
+
+ ndr->flags |= LIBNDR_FLAG_NOALIGN;
+
+ ndr_push_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
+ ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version);
+
+ return ndr_push_blob(ndr);
+}
+
+const char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
+{
+ switch (epm_floor->lhs.protocol) {
+ case EPM_PROTOCOL_TCP:
+ if (epm_floor->rhs.tcp.port == 0) return NULL;
+ return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.tcp.port);
+
+ case EPM_PROTOCOL_UDP:
+ if (epm_floor->rhs.udp.port == 0) return NULL;
+ return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.udp.port);
+
+ case EPM_PROTOCOL_HTTP:
+ if (epm_floor->rhs.http.port == 0) return NULL;
+ return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.http.port);
+
+ case EPM_PROTOCOL_IP:
+ return talloc_strdup(mem_ctx, epm_floor->rhs.ip.ipaddr);
+
+ case EPM_PROTOCOL_NCACN:
+ return NULL;
+
+ case EPM_PROTOCOL_NCADG:
+ return NULL;
+
+ case EPM_PROTOCOL_SMB:
+ if (strlen(epm_floor->rhs.smb.unc) == 0) return NULL;
+ return talloc_strdup(mem_ctx, epm_floor->rhs.smb.unc);
+
+ case EPM_PROTOCOL_PIPE:
+ if (strlen(epm_floor->rhs.pipe.path) == 0) return NULL;
+ return talloc_strdup(mem_ctx, epm_floor->rhs.pipe.path);
+
+ case EPM_PROTOCOL_NETBIOS:
+ if (strlen(epm_floor->rhs.netbios.name) == 0) return NULL;
+ return talloc_strdup(mem_ctx, epm_floor->rhs.netbios.name);
+
+ case EPM_PROTOCOL_NCALRPC:
+ return NULL;
+
+ case EPM_PROTOCOL_VINES_SPP:
+ return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_spp.port);
+
+ case EPM_PROTOCOL_VINES_IPC:
+ return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_ipc.port);
+
+ case EPM_PROTOCOL_STREETTALK:
+ return talloc_strdup(mem_ctx, epm_floor->rhs.streettalk.streettalk);
+
+ case EPM_PROTOCOL_UNIX_DS:
+ if (strlen(epm_floor->rhs.unix_ds.path) == 0) return NULL;
+ return talloc_strdup(mem_ctx, epm_floor->rhs.unix_ds.path);
+
+ case EPM_PROTOCOL_NULL:
+ return NULL;
+
+ default:
+ DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
+ break;
+ }
+
+ return NULL;
+}
+
+static NTSTATUS dcerpc_floor_set_rhs_data(TALLOC_CTX *mem_ctx,
+ struct epm_floor *epm_floor,
+ const char *data)
+{
+ switch (epm_floor->lhs.protocol) {
+ case EPM_PROTOCOL_TCP:
+ epm_floor->rhs.tcp.port = atoi(data);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_UDP:
+ epm_floor->rhs.udp.port = atoi(data);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_HTTP:
+ epm_floor->rhs.http.port = atoi(data);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_IP:
+ epm_floor->rhs.ip.ipaddr = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.ip.ipaddr);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_NCACN:
+ epm_floor->rhs.ncacn.minor_version = 0;
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_NCADG:
+ epm_floor->rhs.ncadg.minor_version = 0;
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_SMB:
+ epm_floor->rhs.smb.unc = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.smb.unc);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_PIPE:
+ epm_floor->rhs.pipe.path = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.pipe.path);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_NETBIOS:
+ epm_floor->rhs.netbios.name = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.netbios.name);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_NCALRPC:
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_VINES_SPP:
+ epm_floor->rhs.vines_spp.port = atoi(data);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_VINES_IPC:
+ epm_floor->rhs.vines_ipc.port = atoi(data);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_STREETTALK:
+ epm_floor->rhs.streettalk.streettalk = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.streettalk.streettalk);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_UNIX_DS:
+ epm_floor->rhs.unix_ds.path = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.unix_ds.path);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_NULL:
+ return NT_STATUS_OK;
+
+ default:
+ DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
+ break;
+ }
+
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot)
+{
+ int i;
+
+ /* Find a transport that has 'prot' as 4th protocol */
+ for (i=0;i<ARRAY_SIZE(transports);i++) {
+ if (transports[i].num_protocols >= 2 &&
+ transports[i].protseq[1] == prot) {
+ return transports[i].transport;
+ }
+ }
+
+ /* Unknown transport */
+ return (unsigned int)-1;
+}
+
+_PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_tower(struct epm_tower *tower)
+{
+ int i;
+
+ /* Find a transport that matches this tower */
+ for (i=0;i<ARRAY_SIZE(transports);i++) {
+ int j;
+ if (transports[i].num_protocols != tower->num_floors - 2) {
+ continue;
+ }
+
+ for (j = 0; j < transports[i].num_protocols; j++) {
+ if (transports[i].protseq[j] != tower->floors[j+2].lhs.protocol) {
+ break;
+ }
+ }
+
+ if (j == transports[i].num_protocols) {
+ return transports[i].transport;
+ }
+ }
+
+ /* Unknown transport */
+ return (unsigned int)-1;
+}
+
+_PUBLIC_ NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
+ struct epm_tower *tower,
+ struct dcerpc_binding **b_out)
+{
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+
+ binding = talloc(mem_ctx, struct dcerpc_binding);
+ NT_STATUS_HAVE_NO_MEMORY(binding);
+
+ ZERO_STRUCT(binding->object);
+ binding->options = NULL;
+ binding->host = NULL;
+ binding->target_hostname = NULL;
+ binding->flags = 0;
+ binding->assoc_group_id = 0;
+
+ binding->transport = dcerpc_transport_by_tower(tower);
+
+ if (binding->transport == (unsigned int)-1) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ if (tower->num_floors < 1) {
+ return NT_STATUS_OK;
+ }
+
+ /* Set object uuid */
+ status = dcerpc_floor_get_lhs_data(&tower->floors[0], &binding->object);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Error pulling object uuid and version: %s", nt_errstr(status)));
+ return status;
+ }
+
+ /* Ignore floor 1, it contains the NDR version info */
+
+ binding->options = NULL;
+
+ /* Set endpoint */
+ if (tower->num_floors >= 4) {
+ binding->endpoint = dcerpc_floor_get_rhs_data(mem_ctx, &tower->floors[3]);
+ } else {
+ binding->endpoint = NULL;
+ }
+
+ /* Set network address */
+ if (tower->num_floors >= 5) {
+ binding->host = dcerpc_floor_get_rhs_data(mem_ctx, &tower->floors[4]);
+ NT_STATUS_HAVE_NO_MEMORY(binding->host);
+ binding->target_hostname = binding->host;
+ }
+ *b_out = binding;
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding, struct epm_tower *tower)
+{
+ const enum epm_protocol *protseq = NULL;
+ int num_protocols = -1, i;
+ NTSTATUS status;
+
+ /* Find transport */
+ for (i=0;i<ARRAY_SIZE(transports);i++) {
+ if (transports[i].transport == binding->transport) {
+ protseq = transports[i].protseq;
+ num_protocols = transports[i].num_protocols;
+ break;
+ }
+ }
+
+ if (num_protocols == -1) {
+ DEBUG(0, ("Unable to find transport with id '%d'\n", binding->transport));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ tower->num_floors = 2 + num_protocols;
+ tower->floors = talloc_array(mem_ctx, struct epm_floor, tower->num_floors);
+
+ /* Floor 0 */
+ tower->floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
+
+ tower->floors[0].lhs.lhs_data = dcerpc_floor_pack_lhs_data(mem_ctx, &binding->object);
+
+ tower->floors[0].rhs.uuid.unknown = data_blob_talloc_zero(mem_ctx, 2);
+
+ /* Floor 1 */
+ tower->floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
+
+ tower->floors[1].lhs.lhs_data = dcerpc_floor_pack_lhs_data(mem_ctx,
+ &ndr_transfer_syntax);
+
+ tower->floors[1].rhs.uuid.unknown = data_blob_talloc_zero(mem_ctx, 2);
+
+ /* Floor 2 to num_protocols */
+ for (i = 0; i < num_protocols; i++) {
+ tower->floors[2 + i].lhs.protocol = protseq[i];
+ tower->floors[2 + i].lhs.lhs_data = data_blob_talloc(mem_ctx, NULL, 0);
+ ZERO_STRUCT(tower->floors[2 + i].rhs);
+ dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[2 + i], "");
+ }
+
+ /* The 4th floor contains the endpoint */
+ if (num_protocols >= 2 && binding->endpoint) {
+ status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[3], binding->endpoint);
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+ }
+
+ /* The 5th contains the network address */
+ if (num_protocols >= 3 && binding->host) {
+ if (is_ipaddress(binding->host)) {
+ status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[4],
+ binding->host);
+ } else {
+ /* note that we don't attempt to resolve the
+ name here - when we get a hostname here we
+ are in the client code, and want to put in
+ a wildcard all-zeros IP for the server to
+ fill in */
+ status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[4],
+ "0.0.0.0");
+ }
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+struct epm_map_binding_state {
+ struct dcerpc_binding *binding;
+ const struct ndr_interface_table *table;
+ struct dcerpc_pipe *pipe;
+ struct policy_handle handle;
+ struct GUID guid;
+ struct epm_twr_t twr;
+ struct epm_twr_t *twr_r;
+ struct epm_Map r;
+};
+
+
+static void continue_epm_recv_binding(struct composite_context *ctx);
+static void continue_epm_map(struct rpc_request *req);
+
+
+/*
+ Stage 2 of epm_map_binding: Receive connected rpc pipe and send endpoint
+ mapping rpc request
+*/
+static void continue_epm_recv_binding(struct composite_context *ctx)
+{
+ struct rpc_request *map_req;
+
+ struct composite_context *c = talloc_get_type(ctx->async.private_data,
+ struct composite_context);
+ struct epm_map_binding_state *s = talloc_get_type(c->private_data,
+ struct epm_map_binding_state);
+
+ /* receive result of rpc pipe connect request */
+ c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->pipe);
+ if (!composite_is_ok(c)) return;
+
+ s->pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
+
+ /* prepare requested binding parameters */
+ s->binding->object = s->table->syntax_id;
+
+ c->status = dcerpc_binding_build_tower(s->pipe, s->binding, &s->twr.tower);
+ if (!composite_is_ok(c)) return;
+
+ /* with some nice pretty paper around it of course */
+ s->r.in.object = &s->guid;
+ s->r.in.map_tower = &s->twr;
+ s->r.in.entry_handle = &s->handle;
+ s->r.in.max_towers = 1;
+ s->r.out.entry_handle = &s->handle;
+
+ /* send request for an endpoint mapping - a rpc request on connected pipe */
+ map_req = dcerpc_epm_Map_send(s->pipe, c, &s->r);
+ if (composite_nomem(map_req, c)) return;
+
+ composite_continue_rpc(c, map_req, continue_epm_map, c);
+}
+
+
+/*
+ Stage 3 of epm_map_binding: Receive endpoint mapping and provide binding details
+*/
+static void continue_epm_map(struct rpc_request *req)
+{
+ struct composite_context *c = talloc_get_type(req->async.private_data,
+ struct composite_context);
+ struct epm_map_binding_state *s = talloc_get_type(c->private_data,
+ struct epm_map_binding_state);
+
+ /* receive result of a rpc request */
+ c->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(c)) return;
+
+ /* check the details */
+ if (s->r.out.result != 0 || *s->r.out.num_towers != 1) {
+ composite_error(c, NT_STATUS_PORT_UNREACHABLE);
+ return;
+ }
+
+ s->twr_r = s->r.out.towers[0].twr;
+ if (s->twr_r == NULL) {
+ composite_error(c, NT_STATUS_PORT_UNREACHABLE);
+ return;
+ }
+
+ if (s->twr_r->tower.num_floors != s->twr.tower.num_floors ||
+ s->twr_r->tower.floors[3].lhs.protocol != s->twr.tower.floors[3].lhs.protocol) {
+ composite_error(c, NT_STATUS_PORT_UNREACHABLE);
+ return;
+ }
+
+ /* get received endpoint */
+ s->binding->endpoint = talloc_reference(s->binding,
+ dcerpc_floor_get_rhs_data(c, &s->twr_r->tower.floors[3]));
+ if (composite_nomem(s->binding->endpoint, c)) return;
+
+ composite_done(c);
+}
+
+
+/*
+ Request for endpoint mapping of dcerpc binding - try to request for endpoint
+ unless there is default one.
+*/
+struct composite_context *dcerpc_epm_map_binding_send(TALLOC_CTX *mem_ctx,
+ struct dcerpc_binding *binding,
+ const struct ndr_interface_table *table,
+ struct event_context *ev,
+ struct loadparm_context *lp_ctx)
+{
+ struct composite_context *c;
+ struct epm_map_binding_state *s;
+ struct composite_context *pipe_connect_req;
+ struct cli_credentials *anon_creds;
+ struct event_context *new_ev = NULL;
+
+ NTSTATUS status;
+ struct dcerpc_binding *epmapper_binding;
+ int i;
+
+ /* Try to find event context in memory context in case passed
+ * event_context (argument) was NULL. If there's none, just
+ * create a new one.
+ */
+ if (ev == NULL) {
+ ev = event_context_find(mem_ctx);
+ if (ev == NULL) {
+ new_ev = event_context_init(mem_ctx);
+ if (new_ev == NULL) return NULL;
+ ev = new_ev;
+ }
+ }
+
+ /* composite context allocation and setup */
+ c = composite_create(mem_ctx, ev);
+ if (c == NULL) {
+ talloc_free(new_ev);
+ return NULL;
+ }
+ talloc_steal(c, new_ev);
+
+ s = talloc_zero(c, struct epm_map_binding_state);
+ if (composite_nomem(s, c)) return c;
+ c->private_data = s;
+
+ s->binding = binding;
+ s->table = table;
+
+ /* anonymous credentials for rpc connection used to get endpoint mapping */
+ anon_creds = cli_credentials_init(mem_ctx);
+ cli_credentials_set_event_context(anon_creds, ev);
+ cli_credentials_set_anonymous(anon_creds);
+
+ /*
+ First, check if there is a default endpoint specified in the IDL
+ */
+ if (table != NULL) {
+ struct dcerpc_binding *default_binding;
+
+ /* Find one of the default pipes for this interface */
+ for (i = 0; i < table->endpoints->count; i++) {
+ status = dcerpc_parse_binding(mem_ctx, table->endpoints->names[i], &default_binding);
+
+ if (NT_STATUS_IS_OK(status)) {
+ if (binding->transport == NCA_UNKNOWN)
+ binding->transport = default_binding->transport;
+ if (default_binding->transport == binding->transport &&
+ default_binding->endpoint) {
+ binding->endpoint = talloc_reference(binding, default_binding->endpoint);
+ talloc_free(default_binding);
+
+ composite_done(c);
+ return c;
+
+ } else {
+ talloc_free(default_binding);
+ }
+ }
+ }
+ }
+
+ epmapper_binding = talloc_zero(c, struct dcerpc_binding);
+ if (composite_nomem(epmapper_binding, c)) return c;
+
+ /* basic endpoint mapping data */
+ epmapper_binding->transport = binding->transport;
+ epmapper_binding->host = talloc_reference(epmapper_binding, binding->host);
+ epmapper_binding->target_hostname = epmapper_binding->host;
+ epmapper_binding->options = NULL;
+ epmapper_binding->flags = 0;
+ epmapper_binding->assoc_group_id = 0;
+ epmapper_binding->endpoint = NULL;
+
+ /* initiate rpc pipe connection */
+ pipe_connect_req = dcerpc_pipe_connect_b_send(c, epmapper_binding,
+ &ndr_table_epmapper,
+ anon_creds, c->event_ctx,
+ lp_ctx);
+ if (composite_nomem(pipe_connect_req, c)) return c;
+
+ composite_continue(c, pipe_connect_req, continue_epm_recv_binding, c);
+ return c;
+}
+
+
+/*
+ Receive result of endpoint mapping request
+ */
+NTSTATUS dcerpc_epm_map_binding_recv(struct composite_context *c)
+{
+ NTSTATUS status = composite_wait(c);
+
+ talloc_free(c);
+ return status;
+}
+
+
+/*
+ Get endpoint mapping for rpc connection
+*/
+_PUBLIC_ NTSTATUS dcerpc_epm_map_binding(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding,
+ const struct ndr_interface_table *table, struct event_context *ev,
+ struct loadparm_context *lp_ctx)
+{
+ struct composite_context *c;
+
+ c = dcerpc_epm_map_binding_send(mem_ctx, binding, table, ev, lp_ctx);
+ return dcerpc_epm_map_binding_recv(c);
+}
+
+
+struct pipe_auth_state {
+ struct dcerpc_pipe *pipe;
+ struct dcerpc_binding *binding;
+ const struct ndr_interface_table *table;
+ struct loadparm_context *lp_ctx;
+ struct cli_credentials *credentials;
+};
+
+
+static void continue_auth_schannel(struct composite_context *ctx);
+static void continue_auth(struct composite_context *ctx);
+static void continue_auth_none(struct composite_context *ctx);
+static void continue_ntlmssp_connection(struct composite_context *ctx);
+static void continue_spnego_after_wrong_pass(struct composite_context *ctx);
+
+
+/*
+ Stage 2 of pipe_auth: Receive result of schannel bind request
+*/
+static void continue_auth_schannel(struct composite_context *ctx)
+{
+ struct composite_context *c = talloc_get_type(ctx->async.private_data,
+ struct composite_context);
+
+ c->status = dcerpc_bind_auth_schannel_recv(ctx);
+ if (!composite_is_ok(c)) return;
+
+ composite_done(c);
+}
+
+
+/*
+ Stage 2 of pipe_auth: Receive result of authenticated bind request
+*/
+static void continue_auth(struct composite_context *ctx)
+{
+ struct composite_context *c = talloc_get_type(ctx->async.private_data,
+ struct composite_context);
+
+ c->status = dcerpc_bind_auth_recv(ctx);
+ if (!composite_is_ok(c)) return;
+
+ composite_done(c);
+}
+/*
+ Stage 2 of pipe_auth: Receive result of authenticated bind request, but handle fallbacks:
+ SPNEGO -> NTLMSSP
+*/
+static void continue_auth_auto(struct composite_context *ctx)
+{
+ struct composite_context *c = talloc_get_type(ctx->async.private_data,
+ struct composite_context);
+ struct pipe_auth_state *s = talloc_get_type(c->private_data, struct pipe_auth_state);
+ struct composite_context *sec_conn_req;
+
+ c->status = dcerpc_bind_auth_recv(ctx);
+ if (NT_STATUS_EQUAL(c->status, NT_STATUS_INVALID_PARAMETER)) {
+ /*
+ * Retry with NTLMSSP auth as fallback
+ * send a request for secondary rpc connection
+ */
+ sec_conn_req = dcerpc_secondary_connection_send(s->pipe,
+ s->binding);
+ composite_continue(c, sec_conn_req, continue_ntlmssp_connection, c);
+ return;
+ } else if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
+ if (cli_credentials_wrong_password(s->credentials)) {
+ /*
+ * Retry SPNEGO with a better password
+ * send a request for secondary rpc connection
+ */
+ sec_conn_req = dcerpc_secondary_connection_send(s->pipe,
+ s->binding);
+ composite_continue(c, sec_conn_req, continue_spnego_after_wrong_pass, c);
+ return;
+ }
+ }
+
+ if (!composite_is_ok(c)) return;
+
+ composite_done(c);
+}
+
+/*
+ Stage 3 of pipe_auth (fallback to NTLMSSP case): Receive secondary
+ rpc connection (the first one can't be used any more, due to the
+ bind nak) and perform authenticated bind request
+*/
+static void continue_ntlmssp_connection(struct composite_context *ctx)
+{
+ struct composite_context *c;
+ struct pipe_auth_state *s;
+ struct composite_context *auth_req;
+ struct dcerpc_pipe *p2;
+
+ c = talloc_get_type(ctx->async.private_data, struct composite_context);
+ s = talloc_get_type(c->private_data, struct pipe_auth_state);
+
+ /* receive secondary rpc connection */
+ c->status = dcerpc_secondary_connection_recv(ctx, &p2);
+ if (!composite_is_ok(c)) return;
+
+ talloc_steal(s, p2);
+ talloc_steal(p2, s->pipe);
+ s->pipe = p2;
+
+ /* initiate a authenticated bind */
+ auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
+ s->credentials, s->lp_ctx,
+ DCERPC_AUTH_TYPE_NTLMSSP,
+ dcerpc_auth_level(s->pipe->conn),
+ s->table->authservices->names[0]);
+ composite_continue(c, auth_req, continue_auth, c);
+}
+
+/*
+ Stage 3 of pipe_auth (retry on wrong password): Receive secondary
+ rpc connection (the first one can't be used any more, due to the
+ bind nak) and perform authenticated bind request
+*/
+static void continue_spnego_after_wrong_pass(struct composite_context *ctx)
+{
+ struct composite_context *c;
+ struct pipe_auth_state *s;
+ struct composite_context *auth_req;
+ struct dcerpc_pipe *p2;
+
+ c = talloc_get_type(ctx->async.private_data, struct composite_context);
+ s = talloc_get_type(c->private_data, struct pipe_auth_state);
+
+ /* receive secondary rpc connection */
+ c->status = dcerpc_secondary_connection_recv(ctx, &p2);
+ if (!composite_is_ok(c)) return;
+
+ talloc_steal(s, p2);
+ talloc_steal(p2, s->pipe);
+ s->pipe = p2;
+
+ /* initiate a authenticated bind */
+ auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
+ s->credentials, s->lp_ctx, DCERPC_AUTH_TYPE_SPNEGO,
+ dcerpc_auth_level(s->pipe->conn),
+ s->table->authservices->names[0]);
+ composite_continue(c, auth_req, continue_auth, c);
+}
+
+
+/*
+ Stage 2 of pipe_auth: Receive result of non-authenticated bind request
+*/
+static void continue_auth_none(struct composite_context *ctx)
+{
+ struct composite_context *c = talloc_get_type(ctx->async.private_data,
+ struct composite_context);
+
+ c->status = dcerpc_bind_auth_none_recv(ctx);
+ if (!composite_is_ok(c)) return;
+
+ composite_done(c);
+}
+
+
+/*
+ Request to perform an authenticated bind if required. Authentication
+ is determined using credentials passed and binding flags.
+*/
+struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p,
+ struct dcerpc_binding *binding,
+ const struct ndr_interface_table *table,
+ struct cli_credentials *credentials,
+ struct loadparm_context *lp_ctx)
+{
+ struct composite_context *c;
+ struct pipe_auth_state *s;
+ struct composite_context *auth_schannel_req;
+ struct composite_context *auth_req;
+ struct composite_context *auth_none_req;
+ struct dcerpc_connection *conn;
+ uint8_t auth_type;
+
+ /* composite context allocation and setup */
+ c = composite_create(p, p->conn->event_ctx);
+ if (c == NULL) return NULL;
+
+ s = talloc_zero(c, struct pipe_auth_state);
+ if (composite_nomem(s, c)) return c;
+ c->private_data = s;
+
+ /* store parameters in state structure */
+ s->binding = binding;
+ s->table = table;
+ s->credentials = credentials;
+ s->pipe = p;
+ s->lp_ctx = lp_ctx;
+
+ conn = s->pipe->conn;
+ conn->flags = binding->flags;
+
+ /* remember the binding string for possible secondary connections */
+ conn->binding_string = dcerpc_binding_string(p, binding);
+
+ if (cli_credentials_is_anonymous(s->credentials)) {
+ auth_none_req = dcerpc_bind_auth_none_send(c, s->pipe, s->table);
+ composite_continue(c, auth_none_req, continue_auth_none, c);
+ return c;
+ }
+
+ if ((binding->flags & DCERPC_SCHANNEL) &&
+ !cli_credentials_get_netlogon_creds(s->credentials)) {
+ /* If we don't already have netlogon credentials for
+ * the schannel bind, then we have to get these
+ * first */
+ auth_schannel_req = dcerpc_bind_auth_schannel_send(c, s->pipe, s->table,
+ s->credentials, s->lp_ctx,
+ dcerpc_auth_level(conn));
+ composite_continue(c, auth_schannel_req, continue_auth_schannel, c);
+ return c;
+ }
+
+ /*
+ * we rely on the already authenticated CIFS connection
+ * if not doing sign or seal
+ */
+ if (conn->transport.transport == NCACN_NP &&
+ !(s->binding->flags & (DCERPC_SIGN|DCERPC_SEAL))) {
+ auth_none_req = dcerpc_bind_auth_none_send(c, s->pipe, s->table);
+ composite_continue(c, auth_none_req, continue_auth_none, c);
+ return c;
+ }
+
+
+ /* Perform an authenticated DCE-RPC bind
+ */
+ if (!(conn->flags & (DCERPC_SIGN|DCERPC_SEAL))) {
+ /*
+ we are doing an authenticated connection,
+ but not using sign or seal. We must force
+ the CONNECT dcerpc auth type as a NONE auth
+ type doesn't allow authentication
+ information to be passed.
+ */
+ conn->flags |= DCERPC_CONNECT;
+ }
+
+ if (s->binding->flags & DCERPC_AUTH_SPNEGO) {
+ auth_type = DCERPC_AUTH_TYPE_SPNEGO;
+
+ } else if (s->binding->flags & DCERPC_AUTH_KRB5) {
+ auth_type = DCERPC_AUTH_TYPE_KRB5;
+
+ } else if (s->binding->flags & DCERPC_SCHANNEL) {
+ auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
+
+ } else if (s->binding->flags & DCERPC_AUTH_NTLM) {
+ auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
+
+ } else {
+ /* try SPNEGO with fallback to NTLMSSP */
+ auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
+ s->credentials, s->lp_ctx, DCERPC_AUTH_TYPE_SPNEGO,
+ dcerpc_auth_level(conn),
+ s->table->authservices->names[0]);
+ composite_continue(c, auth_req, continue_auth_auto, c);
+ return c;
+ }
+
+ auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
+ s->credentials, s->lp_ctx, auth_type,
+ dcerpc_auth_level(conn),
+ s->table->authservices->names[0]);
+ composite_continue(c, auth_req, continue_auth, c);
+ return c;
+}
+
+
+/*
+ Receive result of authenticated bind request on dcerpc pipe
+
+ This returns *p, which may be different to the one originally
+ supllied, as it rebinds to a new pipe due to authentication fallback
+
+*/
+NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
+ struct dcerpc_pipe **p)
+{
+ NTSTATUS status;
+
+ struct pipe_auth_state *s = talloc_get_type(c->private_data,
+ struct pipe_auth_state);
+ status = composite_wait(c);
+ if (!NT_STATUS_IS_OK(status)) {
+ char *uuid_str = GUID_string(s->pipe, &s->table->syntax_id.uuid);
+ DEBUG(0, ("Failed to bind to uuid %s - %s\n", uuid_str, nt_errstr(status)));
+ talloc_free(uuid_str);
+ } else {
+ talloc_steal(mem_ctx, s->pipe);
+ *p = s->pipe;
+ }
+
+ talloc_free(c);
+ return status;
+}
+
+
+/*
+ Perform an authenticated bind if needed - sync version
+
+ This may change *p, as it rebinds to a new pipe due to authentication fallback
+*/
+_PUBLIC_ NTSTATUS dcerpc_pipe_auth(TALLOC_CTX *mem_ctx,
+ struct dcerpc_pipe **p,
+ struct dcerpc_binding *binding,
+ const struct ndr_interface_table *table,
+ struct cli_credentials *credentials,
+ struct loadparm_context *lp_ctx)
+{
+ struct composite_context *c;
+
+ c = dcerpc_pipe_auth_send(*p, binding, table, credentials, lp_ctx);
+ return dcerpc_pipe_auth_recv(c, mem_ctx, p);
+}
+
+
+NTSTATUS dcerpc_generic_session_key(struct dcerpc_connection *c,
+ DATA_BLOB *session_key)
+{
+ /* this took quite a few CPU cycles to find ... */
+ session_key->data = discard_const_p(unsigned char, "SystemLibraryDTC");
+ session_key->length = 16;
+ return NT_STATUS_OK;
+}
+
+/*
+ fetch the user session key - may be default (above) or the SMB session key
+*/
+_PUBLIC_ NTSTATUS dcerpc_fetch_session_key(struct dcerpc_pipe *p,
+ DATA_BLOB *session_key)
+{
+ return p->conn->security_state.session_key(p->conn, session_key);
+}
+
+
+/*
+ log a rpc packet in a format suitable for ndrdump. This is especially useful
+ for sealed packets, where ethereal cannot easily see the contents
+
+ this triggers on a debug level of >= 10
+*/
+_PUBLIC_ void dcerpc_log_packet(const struct ndr_interface_table *ndr,
+ uint32_t opnum, uint32_t flags,
+ DATA_BLOB *pkt)
+{
+ const int num_examples = 20;
+ int i;
+
+ if (DEBUGLEVEL < 10) return;
+
+ for (i=0;i<num_examples;i++) {
+ char *name=NULL;
+ asprintf(&name, "%s/rpclog/%s-%u.%d.%s",
+ lp_lockdir(global_loadparm), ndr->name, opnum, i,
+ (flags&NDR_IN)?"in":"out");
+ if (name == NULL) {
+ return;
+ }
+ if (!file_exist(name)) {
+ if (file_save(name, pkt->data, pkt->length)) {
+ DEBUG(10,("Logged rpc packet to %s\n", name));
+ }
+ free(name);
+ break;
+ }
+ free(name);
+ }
+}
+
+
+
+/*
+ create a secondary context from a primary connection
+
+ this uses dcerpc_alter_context() to create a new dcerpc context_id
+*/
+_PUBLIC_ NTSTATUS dcerpc_secondary_context(struct dcerpc_pipe *p,
+ struct dcerpc_pipe **pp2,
+ const struct ndr_interface_table *table)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p2;
+
+ p2 = talloc_zero(p, struct dcerpc_pipe);
+ if (p2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ p2->conn = talloc_reference(p2, p->conn);
+ p2->request_timeout = p->request_timeout;
+
+ p2->context_id = ++p->conn->next_context_id;
+
+ p2->syntax = table->syntax_id;
+
+ p2->transfer_syntax = ndr_transfer_syntax;
+
+ p2->binding = talloc_reference(p2, p->binding);
+
+ status = dcerpc_alter_context(p2, p2, &p2->syntax, &p2->transfer_syntax);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(p2);
+ return status;
+ }
+
+ *pp2 = p2;
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/librpc/tables.pl b/source3/librpc/tables.pl
new file mode 100755
index 0000000000..946159c6f0
--- /dev/null
+++ b/source3/librpc/tables.pl
@@ -0,0 +1,89 @@
+#!/usr/bin/perl -w
+
+###################################################
+# package to produce a table of all idl parsers
+# Copyright tridge@samba.org 2003
+# Copyright jelmer@samba.org 2005
+# released under the GNU GPL
+
+use strict;
+
+use Getopt::Long;
+use File::Basename;
+
+my $opt_output = 'librpc/gen_ndr/tables.c';
+my $opt_help = 0;
+
+
+#########################################
+# display help text
+sub ShowHelp()
+{
+ print "
+ perl DCE/RPC interface table generator
+ Copyright (C) tridge\@samba.org
+
+ Usage: tables.pl [options] <idlfile>
+
+ \n";
+ exit(0);
+}
+
+# main program
+GetOptions (
+ 'help|h|?' => \$opt_help,
+ 'output=s' => \$opt_output,
+ );
+
+if ($opt_help) {
+ ShowHelp();
+ exit(0);
+}
+
+my $init_fns = "";
+
+###################################
+# extract table entries from 1 file
+sub process_file($)
+{
+ my $filename = shift;
+ open(FILE, $filename) || die "unable to open $filename\n";
+ my $found = 0;
+
+ while (my $line = <FILE>) {
+ if ($line =~ /extern const struct ndr_interface_table (\w+);/) {
+ $found = 1;
+ $init_fns.="\tstatus = librpc_register_interface(&$1);\n";
+ $init_fns.="\tif (NT_STATUS_IS_ERR(status)) return status;\n\n";
+ }
+ }
+
+ if ($found) {
+ print "#include \"$filename\"\n";
+ }
+
+ close(FILE);
+}
+
+print <<EOF;
+
+/* Automatically generated by tables.pl. DO NOT EDIT */
+
+#include "includes.h"
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/dcerpc_table.h"
+EOF
+
+process_file($_) foreach (@ARGV);
+
+print <<EOF;
+
+NTSTATUS dcerpc_register_builtin_interfaces(void)
+{
+ NTSTATUS status;
+
+$init_fns
+
+ return NT_STATUS_OK;
+}
+EOF
diff --git a/source3/librpc/tools/ndrdump.c b/source3/librpc/tools/ndrdump.c
new file mode 100644
index 0000000000..dc7f2be32f
--- /dev/null
+++ b/source3/librpc/tools/ndrdump.c
@@ -0,0 +1,453 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#if (_SAMBA_BUILD_ >= 4)
+#include "lib/cmdline/popt_common.h"
+#include "system/filesys.h"
+#include "system/locale.h"
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/dcerpc_table.h"
+#endif
+
+static const struct ndr_interface_call *find_function(
+ const struct ndr_interface_table *p,
+ const char *function)
+{
+ int i;
+ if (isdigit(function[0])) {
+ i = strtol(function, NULL, 0);
+ return &p->calls[i];
+ }
+ for (i=0;i<p->num_calls;i++) {
+ if (strcmp(p->calls[i].name, function) == 0) {
+ break;
+ }
+ }
+ if (i == p->num_calls) {
+ printf("Function '%s' not found\n", function);
+ exit(1);
+ }
+ return &p->calls[i];
+}
+
+#if (_SAMBA_BUILD_ >= 4)
+
+static void show_pipes(void)
+{
+ const struct ndr_interface_list *l;
+ printf("\nYou must specify a pipe\n");
+ printf("known pipes are:\n");
+ for (l=librpc_dcerpc_pipes();l;l=l->next) {
+ if(l->table->helpstring) {
+ printf("\t%s - %s\n", l->table->name, l->table->helpstring);
+ } else {
+ printf("\t%s\n", l->table->name);
+ }
+ }
+ exit(1);
+}
+
+#endif
+
+static void show_functions(const struct ndr_interface_table *p)
+{
+ int i;
+ printf("\nYou must specify a function\n");
+ printf("known functions on '%s' are:\n", p->name);
+ for (i=0;i<p->num_calls;i++) {
+ printf("\t0x%02x (%2d) %s\n", i, i, p->calls[i].name);
+ }
+ exit(1);
+}
+
+static char *stdin_load(TALLOC_CTX *mem_ctx, size_t *size)
+{
+ int num_read, total_len = 0;
+ char buf[255];
+ char *result = NULL;
+
+ while((num_read = read(STDIN_FILENO, buf, 255)) > 0) {
+
+ if (result) {
+ result = (char *) talloc_realloc(
+ mem_ctx, result, char *, total_len + num_read);
+ } else {
+ result = (char *) talloc_size(mem_ctx, num_read);
+ }
+
+ memcpy(result + total_len, buf, num_read);
+
+ total_len += num_read;
+ }
+
+ if (size)
+ *size = total_len;
+
+ return result;
+}
+
+static const struct ndr_interface_table *load_iface_from_plugin(const char *plugin, const char *pipe_name)
+{
+ const struct ndr_interface_table *p;
+ void *handle;
+ char *symbol;
+
+ handle = dlopen(plugin, RTLD_NOW);
+ if (handle == NULL) {
+ printf("%s: Unable to open: %s\n", plugin, dlerror());
+ return NULL;
+ }
+
+ symbol = talloc_asprintf(NULL, "ndr_table_%s", pipe_name);
+ p = (const struct ndr_interface_table *)dlsym(handle, symbol);
+
+ if (!p) {
+ printf("%s: Unable to find DCE/RPC interface table for '%s': %s\n", plugin, pipe_name, dlerror());
+ talloc_free(symbol);
+ return NULL;
+ }
+
+ talloc_free(symbol);
+
+ return p;
+}
+
+ int main(int argc, const char *argv[])
+{
+ const struct ndr_interface_table *p = NULL;
+ const struct ndr_interface_call *f;
+ const char *pipe_name, *function, *inout, *filename;
+ uint8_t *data;
+ size_t size;
+ DATA_BLOB blob;
+ struct ndr_pull *ndr_pull;
+ struct ndr_print *ndr_print;
+ TALLOC_CTX *mem_ctx;
+ int flags;
+ poptContext pc;
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ void *st;
+ void *v_st;
+ const char *ctx_filename = NULL;
+ const char *plugin = NULL;
+ bool validate = false;
+ bool dumpdata = false;
+ int opt;
+ enum {OPT_CONTEXT_FILE=1000, OPT_VALIDATE, OPT_DUMP_DATA, OPT_LOAD_DSO};
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"context-file", 'c', POPT_ARG_STRING, NULL, OPT_CONTEXT_FILE, "In-filename to parse first", "CTX-FILE" },
+ {"validate", 0, POPT_ARG_NONE, NULL, OPT_VALIDATE, "try to validate the data", NULL },
+ {"dump-data", 0, POPT_ARG_NONE, NULL, OPT_DUMP_DATA, "dump the hex data", NULL },
+ {"load-dso", 'l', POPT_ARG_STRING, NULL, OPT_LOAD_DSO, "load from shared object file", NULL },
+ POPT_COMMON_SAMBA
+ POPT_COMMON_VERSION
+ { NULL }
+ };
+
+#if (_SAMBA_BUILD_ >= 4)
+ ndr_table_init();
+#else
+ /* Initialise samba stuff */
+ load_case_tables();
+
+ setlinebuf(stdout);
+
+ dbf = x_stderr;
+
+ setup_logging(argv[0],True);
+#endif
+
+ pc = poptGetContext("ndrdump", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(
+ pc, "<pipe|uuid> <function> <inout> [<filename>]");
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case OPT_CONTEXT_FILE:
+ ctx_filename = poptGetOptArg(pc);
+ break;
+ case OPT_VALIDATE:
+ validate = true;
+ break;
+ case OPT_DUMP_DATA:
+ dumpdata = true;
+ break;
+ case OPT_LOAD_DSO:
+ plugin = poptGetOptArg(pc);
+ break;
+ }
+ }
+
+ pipe_name = poptGetArg(pc);
+
+ if (!pipe_name) {
+ poptPrintUsage(pc, stderr, 0);
+#if (_SAMBA_BUILD_ >= 4)
+ show_pipes();
+#endif
+ exit(1);
+ }
+
+ if (plugin != NULL) {
+ p = load_iface_from_plugin(plugin, pipe_name);
+ }
+#if (_SAMBA_BUILD_ <= 3)
+ else {
+ fprintf(stderr, "Only loading from DSO's supported in Samba 3\n");
+ exit(1);
+ }
+#else
+ if (!p) {
+ p = idl_iface_by_name(pipe_name);
+ }
+
+ if (!p) {
+ struct GUID uuid;
+
+ status = GUID_from_string(pipe_name, &uuid);
+
+ if (NT_STATUS_IS_OK(status)) {
+ p = idl_iface_by_uuid(&uuid);
+ }
+ }
+#endif
+
+ if (!p) {
+ printf("Unknown pipe or UUID '%s'\n", pipe_name);
+ exit(1);
+ }
+
+ function = poptGetArg(pc);
+ inout = poptGetArg(pc);
+ filename = poptGetArg(pc);
+
+ if (!function || !inout) {
+ poptPrintUsage(pc, stderr, 0);
+ show_functions(p);
+ exit(1);
+ }
+
+ if (strcmp(inout, "in") == 0 ||
+ strcmp(inout, "request") == 0) {
+ flags = NDR_IN;
+ } else if (strcmp(inout, "out") == 0 ||
+ strcmp(inout, "response") == 0) {
+ flags = NDR_OUT;
+ } else {
+ printf("Bad inout value '%s'\n", inout);
+ exit(1);
+ }
+
+ f = find_function(p, function);
+
+ mem_ctx = talloc_init("ndrdump");
+
+ st = talloc_zero_size(mem_ctx, f->struct_size);
+ if (!st) {
+ printf("Unable to allocate %d bytes\n", (int)f->struct_size);
+ exit(1);
+ }
+
+ v_st = talloc_zero_size(mem_ctx, f->struct_size);
+ if (!v_st) {
+ printf("Unable to allocate %d bytes\n", (int)f->struct_size);
+ exit(1);
+ }
+
+ if (ctx_filename) {
+ if (flags == NDR_IN) {
+ printf("Context file can only be used for \"out\" packages\n");
+ exit(1);
+ }
+
+#if (_SAMBA_BUILD_ >= 4)
+ data = (uint8_t *)file_load(ctx_filename, &size, mem_ctx);
+#else
+ data = (uint8_t *)file_load(ctx_filename, &size, 0);
+#endif
+ if (!data) {
+ perror(ctx_filename);
+ exit(1);
+ }
+
+ blob.data = data;
+ blob.length = size;
+
+ ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
+ ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+
+ ndr_err = f->ndr_pull(ndr_pull, NDR_IN, st);
+
+ if (ndr_pull->offset != ndr_pull->data_size) {
+ printf("WARNING! %d unread bytes while parsing context file\n", ndr_pull->data_size - ndr_pull->offset);
+ }
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ printf("pull for context file returned %s\n", nt_errstr(status));
+ exit(1);
+ }
+ memcpy(v_st, st, f->struct_size);
+ }
+
+ if (filename)
+#if (_SAMBA_BUILD_ >= 4)
+ data = (uint8_t *)file_load(filename, &size, mem_ctx);
+#else
+ data = (uint8_t *)file_load(filename, &size, 0);
+#endif
+ else
+ data = (uint8_t *)stdin_load(mem_ctx, &size);
+
+ if (!data) {
+ if (filename)
+ perror(filename);
+ else
+ perror("stdin");
+ exit(1);
+ }
+
+ blob.data = data;
+ blob.length = size;
+
+ ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
+ ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+
+ ndr_err = f->ndr_pull(ndr_pull, flags, st);
+ status = ndr_map_error2ntstatus(ndr_err);
+
+ printf("pull returned %s\n", nt_errstr(status));
+
+ if (ndr_pull->offset != ndr_pull->data_size) {
+ printf("WARNING! %d unread bytes\n", ndr_pull->data_size - ndr_pull->offset);
+ dump_data(0, ndr_pull->data+ndr_pull->offset, ndr_pull->data_size - ndr_pull->offset);
+ }
+
+ if (dumpdata) {
+ printf("%d bytes consumed\n", ndr_pull->offset);
+ dump_data(0, blob.data, blob.length);
+ }
+
+ ndr_print = talloc_zero(mem_ctx, struct ndr_print);
+ ndr_print->print = ndr_print_debug_helper;
+ ndr_print->depth = 1;
+ f->ndr_print(ndr_print, function, flags, st);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("dump FAILED\n");
+ exit(1);
+ }
+
+ if (validate) {
+ DATA_BLOB v_blob;
+ struct ndr_push *ndr_v_push;
+ struct ndr_pull *ndr_v_pull;
+ struct ndr_print *ndr_v_print;
+ uint32_t i;
+ uint8_t byte_a, byte_b;
+ bool differ;
+
+ ndr_v_push = ndr_push_init_ctx(mem_ctx);
+
+ ndr_err = f->ndr_push(ndr_v_push, flags, st);
+ status = ndr_map_error2ntstatus(ndr_err);
+ printf("push returned %s\n", nt_errstr(status));
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ printf("validate push FAILED\n");
+ exit(1);
+ }
+
+ v_blob = ndr_push_blob(ndr_v_push);
+
+ if (dumpdata) {
+ printf("%ld bytes generated (validate)\n", (long)v_blob.length);
+ dump_data(0, v_blob.data, v_blob.length);
+ }
+
+ ndr_v_pull = ndr_pull_init_blob(&v_blob, mem_ctx);
+ ndr_v_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+
+ ndr_err = f->ndr_pull(ndr_v_pull, flags, v_st);
+ status = ndr_map_error2ntstatus(ndr_err);
+ printf("pull returned %s\n", nt_errstr(status));
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ printf("validate pull FAILED\n");
+ exit(1);
+ }
+
+
+ if (ndr_v_pull->offset != ndr_v_pull->data_size) {
+ printf("WARNING! %d unread bytes in validation\n", ndr_v_pull->data_size - ndr_v_pull->offset);
+ dump_data(0, ndr_v_pull->data+ndr_v_pull->offset, ndr_v_pull->data_size - ndr_v_pull->offset);
+ }
+
+ ndr_v_print = talloc_zero(mem_ctx, struct ndr_print);
+ ndr_v_print->print = ndr_print_debug_helper;
+ ndr_v_print->depth = 1;
+ f->ndr_print(ndr_v_print, function, flags, v_st);
+
+ if (blob.length != v_blob.length) {
+ printf("WARNING! orig bytes:%u validated pushed "
+ "bytes:%u\n", (unsigned int)blob.length,
+ (unsigned int)v_blob.length);
+ }
+
+ if (ndr_pull->offset != ndr_v_pull->offset) {
+ printf("WARNING! orig pulled bytes:%u validated pulled bytes:%u\n", ndr_pull->offset, ndr_v_pull->offset);
+ }
+
+ differ = false;
+ byte_a = 0x00;
+ byte_b = 0x00;
+ for (i=0; i < blob.length; i++) {
+ byte_a = blob.data[i];
+
+ if (i == v_blob.length) {
+ byte_b = 0x00;
+ differ = true;
+ break;
+ }
+
+ byte_b = v_blob.data[i];
+
+ if (byte_a != byte_b) {
+ differ = true;
+ break;
+ }
+ }
+ if (differ) {
+ printf("WARNING! orig and validated differ at byte 0x%02X (%u)\n", i, i);
+ printf("WARNING! orig byte[0x%02X] = 0x%02X validated byte[0x%02X] = 0x%02X\n",
+ i, byte_a, i, byte_b);
+ }
+ }
+
+ printf("dump OK\n");
+
+ talloc_free(mem_ctx);
+
+ poptFreeContext(pc);
+
+ return 0;
+}
diff --git a/source3/libsmb/asn1.c b/source3/libsmb/asn1.c
new file mode 100644
index 0000000000..aca1c48841
--- /dev/null
+++ b/source3/libsmb/asn1.c
@@ -0,0 +1,603 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple SPNEGO routines
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* free an asn1 structure */
+void asn1_free(ASN1_DATA *data)
+{
+ struct nesting *nesting = data->nesting;
+
+ while (nesting) {
+ struct nesting *nnext = nesting->next;
+ free(nesting);
+ nesting = nnext;
+ };
+ data->nesting = NULL;
+ SAFE_FREE(data->data);
+}
+
+/* write to the ASN1 buffer, advancing the buffer pointer */
+bool asn1_write(ASN1_DATA *data, const void *p, int len)
+{
+ if (data->has_error) return false;
+ if (data->length < data->ofs+len) {
+ data->data = SMB_REALLOC_ARRAY(data->data, unsigned char,
+ data->ofs+len);
+ if (!data->data) {
+ data->has_error = true;
+ return false;
+ }
+ data->length = data->ofs+len;
+ }
+ memcpy(data->data + data->ofs, p, len);
+ data->ofs += len;
+ return true;
+}
+
+/* useful fn for writing a uint8 */
+bool asn1_write_uint8(ASN1_DATA *data, uint8 v)
+{
+ return asn1_write(data, &v, 1);
+}
+
+/* push a tag onto the asn1 data buffer. Used for nested structures */
+bool asn1_push_tag(ASN1_DATA *data, uint8 tag)
+{
+ struct nesting *nesting;
+
+ asn1_write_uint8(data, tag);
+ nesting = SMB_MALLOC_P(struct nesting);
+ if (!nesting) {
+ data->has_error = true;
+ return false;
+ }
+
+ nesting->start = data->ofs;
+ nesting->next = data->nesting;
+ data->nesting = nesting;
+ return asn1_write_uint8(data, 0xff);
+}
+
+/* pop a tag */
+bool asn1_pop_tag(ASN1_DATA *data)
+{
+ struct nesting *nesting;
+ size_t len;
+
+ if (data->has_error) {
+ return false;
+ }
+
+ nesting = data->nesting;
+
+ if (!nesting) {
+ data->has_error = true;
+ return false;
+ }
+ len = data->ofs - (nesting->start+1);
+ /* yes, this is ugly. We don't know in advance how many bytes the length
+ of a tag will take, so we assumed 1 byte. If we were wrong then we
+ need to correct our mistake */
+ if (len > 0xFFFF) {
+ data->data[nesting->start] = 0x83;
+ if (!asn1_write_uint8(data, 0)) return false;
+ if (!asn1_write_uint8(data, 0)) return false;
+ if (!asn1_write_uint8(data, 0)) return false;
+ memmove(data->data+nesting->start+4, data->data+nesting->start+1, len);
+ data->data[nesting->start+1] = (len>>16) & 0xFF;
+ data->data[nesting->start+2] = (len>>8) & 0xFF;
+ data->data[nesting->start+3] = len&0xff;
+ } else if (len > 255) {
+ data->data[nesting->start] = 0x82;
+ if (!asn1_write_uint8(data, 0)) return false;
+ if (!asn1_write_uint8(data, 0)) return false;
+ memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
+ data->data[nesting->start+1] = len>>8;
+ data->data[nesting->start+2] = len&0xff;
+ } else if (len > 127) {
+ data->data[nesting->start] = 0x81;
+ if (!asn1_write_uint8(data, 0)) return false;
+ memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
+ data->data[nesting->start+1] = len;
+ } else {
+ data->data[nesting->start] = len;
+ }
+
+ data->nesting = nesting->next;
+ free(nesting);
+ return true;
+}
+
+
+/* write an integer */
+bool asn1_write_Integer(ASN1_DATA *data, int i)
+{
+ if (!asn1_push_tag(data, ASN1_INTEGER)) return false;
+ do {
+ asn1_write_uint8(data, i);
+ i = i >> 8;
+ } while (i);
+ return asn1_pop_tag(data);
+}
+
+/* write an object ID to a ASN1 buffer */
+bool asn1_write_OID(ASN1_DATA *data, const char *OID)
+{
+ unsigned v, v2;
+ const char *p = (const char *)OID;
+ char *newp;
+
+ if (!asn1_push_tag(data, ASN1_OID))
+ return false;
+ v = strtol(p, &newp, 10);
+ p = newp;
+ v2 = strtol(p, &newp, 10);
+ p = newp;
+ if (!asn1_write_uint8(data, 40*v + v2))
+ return false;
+
+ while (*p) {
+ v = strtol(p, &newp, 10);
+ p = newp;
+ if (v >= (1<<28)) asn1_write_uint8(data, 0x80 | ((v>>28)&0xff));
+ if (v >= (1<<21)) asn1_write_uint8(data, 0x80 | ((v>>21)&0xff));
+ if (v >= (1<<14)) asn1_write_uint8(data, 0x80 | ((v>>14)&0xff));
+ if (v >= (1<<7)) asn1_write_uint8(data, 0x80 | ((v>>7)&0xff));
+ if (!asn1_write_uint8(data, v&0x7f))
+ return false;
+ }
+ return asn1_pop_tag(data);
+}
+
+/* write an octet string */
+bool asn1_write_OctetString(ASN1_DATA *data, const void *p, size_t length)
+{
+ asn1_push_tag(data, ASN1_OCTET_STRING);
+ asn1_write(data, p, length);
+ asn1_pop_tag(data);
+ return !data->has_error;
+}
+
+/* write a general string */
+bool asn1_write_GeneralString(ASN1_DATA *data, const char *s)
+{
+ asn1_push_tag(data, ASN1_GENERAL_STRING);
+ asn1_write(data, s, strlen(s));
+ asn1_pop_tag(data);
+ return !data->has_error;
+}
+
+/* write a BOOLEAN */
+bool asn1_write_BOOLEAN(ASN1_DATA *data, bool v)
+{
+ asn1_write_uint8(data, ASN1_BOOLEAN);
+ asn1_write_uint8(data, v);
+ return !data->has_error;
+}
+
+/* write a BOOLEAN - hmm, I suspect this one is the correct one, and the
+ above boolean is bogus. Need to check */
+bool asn1_write_BOOLEAN2(ASN1_DATA *data, bool v)
+{
+ asn1_push_tag(data, ASN1_BOOLEAN);
+ asn1_write_uint8(data, v);
+ asn1_pop_tag(data);
+ return !data->has_error;
+}
+
+/* check a BOOLEAN */
+bool asn1_check_BOOLEAN(ASN1_DATA *data, bool v)
+{
+ uint8 b = 0;
+
+ asn1_read_uint8(data, &b);
+ if (b != ASN1_BOOLEAN) {
+ data->has_error = true;
+ return false;
+ }
+ asn1_read_uint8(data, &b);
+ if (b != v) {
+ data->has_error = true;
+ return false;
+ }
+ return !data->has_error;
+}
+
+
+/* load a ASN1_DATA structure with a lump of data, ready to be parsed */
+bool asn1_load(ASN1_DATA *data, DATA_BLOB blob)
+{
+ ZERO_STRUCTP(data);
+ data->data = (unsigned char *)memdup(blob.data, blob.length);
+ if (!data->data) {
+ data->has_error = true;
+ return false;
+ }
+ data->length = blob.length;
+ return true;
+}
+
+/* read from a ASN1 buffer, advancing the buffer pointer */
+bool asn1_read(ASN1_DATA *data, void *p, int len)
+{
+ if (data->has_error)
+ return false;
+
+ if (len < 0 || data->ofs + len < data->ofs || data->ofs + len < len) {
+ data->has_error = true;
+ return false;
+ }
+
+ if (data->ofs + len > data->length) {
+ data->has_error = true;
+ return false;
+ }
+ memcpy(p, data->data + data->ofs, len);
+ data->ofs += len;
+ return true;
+}
+
+/* read a uint8 from a ASN1 buffer */
+bool asn1_read_uint8(ASN1_DATA *data, uint8 *v)
+{
+ return asn1_read(data, v, 1);
+}
+
+/*
+ * Check thta the value of the ASN1 buffer at the current offset equals tag.
+ */
+bool asn1_check_tag(ASN1_DATA *data, uint8 tag)
+{
+ if (data->has_error || data->ofs >= data->length || data->ofs < 0) {
+ data->has_error = true;
+ return false;
+ }
+
+ return (tag == data->data[data->ofs]);
+}
+
+/* start reading a nested asn1 structure */
+bool asn1_start_tag(ASN1_DATA *data, uint8 tag)
+{
+ uint8 b;
+ struct nesting *nesting;
+
+ if (!asn1_read_uint8(data, &b))
+ return false;
+
+ if (b != tag) {
+ data->has_error = true;
+ return false;
+ }
+ nesting = SMB_MALLOC_P(struct nesting);
+ if (!nesting) {
+ data->has_error = true;
+ return false;
+ }
+
+ if (!asn1_read_uint8(data, &b)) {
+ SAFE_FREE(nesting);
+ return false;
+ }
+
+ if (b & 0x80) {
+ int n = b & 0x7f;
+ if (!asn1_read_uint8(data, &b)) {
+ SAFE_FREE(nesting);
+ return false;
+ }
+ nesting->taglen = b;
+ while (n > 1) {
+ if (!asn1_read_uint8(data, &b)) {
+ SAFE_FREE(nesting);
+ return false;
+ }
+ nesting->taglen = (nesting->taglen << 8) | b;
+ n--;
+ }
+ } else {
+ nesting->taglen = b;
+ }
+ nesting->start = data->ofs;
+ nesting->next = data->nesting;
+ data->nesting = nesting;
+ return !data->has_error;
+}
+
+
+/* stop reading a tag */
+bool asn1_end_tag(ASN1_DATA *data)
+{
+ struct nesting *nesting;
+
+ /* make sure we read it all */
+ if (asn1_tag_remaining(data) != 0) {
+ data->has_error = true;
+ return false;
+ }
+
+ nesting = data->nesting;
+
+ if (!nesting) {
+ data->has_error = true;
+ return false;
+ }
+
+ data->nesting = nesting->next;
+ free(nesting);
+ return true;
+}
+
+/* work out how many bytes are left in this nested tag */
+int asn1_tag_remaining(ASN1_DATA *data)
+{
+ if (data->has_error)
+ return 0;
+
+ if (!data->nesting) {
+ data->has_error = true;
+ return -1;
+ }
+ return data->nesting->taglen - (data->ofs - data->nesting->start);
+}
+
+/* read an object ID from a ASN1 buffer */
+bool asn1_read_OID(ASN1_DATA *data, char **OID)
+{
+ uint8 b = 0;
+ char *oid_str = NULL;
+
+ *OID = NULL;
+
+ if (!asn1_start_tag(data, ASN1_OID)) {
+ return false;
+ }
+ asn1_read_uint8(data, &b);
+
+ oid_str = talloc_asprintf(NULL,
+ "%u",
+ b/40);
+ if (!oid_str) {
+ data->has_error = true;
+ goto out;
+ }
+ oid_str = talloc_asprintf_append(oid_str,
+ " %u",
+ b%40);
+ if (!oid_str) {
+ data->has_error = true;
+ goto out;
+ }
+
+ while (asn1_tag_remaining(data) > 0) {
+ unsigned v = 0;
+ do {
+ asn1_read_uint8(data, &b);
+ v = (v<<7) | (b&0x7f);
+ } while (!data->has_error && b & 0x80);
+ oid_str = talloc_asprintf_append(oid_str,
+ " %u",
+ v);
+ if (!oid_str) {
+ data->has_error = true;
+ goto out;
+ }
+ }
+
+ out:
+
+ asn1_end_tag(data);
+
+ if (!data->has_error) {
+ *OID = SMB_STRDUP(oid_str);
+ }
+
+ TALLOC_FREE(oid_str);
+
+ return !data->has_error;
+}
+
+/* check that the next object ID is correct */
+bool asn1_check_OID(ASN1_DATA *data, const char *OID)
+{
+ char *id;
+
+ if (!asn1_read_OID(data, &id)) {
+ return false;
+ }
+
+ if (strcmp(id, OID) != 0) {
+ data->has_error = true;
+ free(id);
+ return false;
+ }
+ free(id);
+ return true;
+}
+
+/* read a GeneralString from a ASN1 buffer */
+bool asn1_read_GeneralString(ASN1_DATA *data, char **s)
+{
+ int len;
+ char *str;
+
+ *s = NULL;
+
+ if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) {
+ return false;
+ }
+ len = asn1_tag_remaining(data);
+ if (len < 0) {
+ data->has_error = true;
+ return false;
+ }
+ str = SMB_MALLOC_ARRAY(char, len+1);
+ if (!str) {
+ data->has_error = true;
+ return false;
+ }
+ asn1_read(data, str, len);
+ str[len] = 0;
+ asn1_end_tag(data);
+
+ if (!data->has_error) {
+ *s = str;
+ }
+ return !data->has_error;
+}
+
+/* read a octet string blob */
+bool asn1_read_OctetString(ASN1_DATA *data, DATA_BLOB *blob)
+{
+ int len;
+ ZERO_STRUCTP(blob);
+ if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return false;
+ len = asn1_tag_remaining(data);
+ if (len < 0) {
+ data->has_error = true;
+ return false;
+ }
+ *blob = data_blob(NULL, len);
+ asn1_read(data, blob->data, len);
+ asn1_end_tag(data);
+ return !data->has_error;
+}
+
+/* read an interger */
+bool asn1_read_Integer(ASN1_DATA *data, int *i)
+{
+ uint8 b;
+ *i = 0;
+
+ if (!asn1_start_tag(data, ASN1_INTEGER)) return false;
+ while (asn1_tag_remaining(data)>0) {
+ asn1_read_uint8(data, &b);
+ *i = (*i << 8) + b;
+ }
+ return asn1_end_tag(data);
+
+}
+
+/* check a enumarted value is correct */
+bool asn1_check_enumerated(ASN1_DATA *data, int v)
+{
+ uint8 b;
+ if (!asn1_start_tag(data, ASN1_ENUMERATED)) return false;
+ asn1_read_uint8(data, &b);
+ asn1_end_tag(data);
+
+ if (v != b)
+ data->has_error = false;
+
+ return !data->has_error;
+}
+
+/* write an enumarted value to the stream */
+bool asn1_write_enumerated(ASN1_DATA *data, uint8 v)
+{
+ if (!asn1_push_tag(data, ASN1_ENUMERATED)) return false;
+ asn1_write_uint8(data, v);
+ asn1_pop_tag(data);
+ return !data->has_error;
+}
+
+bool ber_write_OID_String(DATA_BLOB *blob, const char *OID)
+{
+ uint_t v, v2;
+ const char *p = (const char *)OID;
+ char *newp;
+ int i;
+
+ v = strtoul(p, &newp, 10);
+ if (newp[0] != '.') return false;
+ p = newp + 1;
+
+ v2 = strtoul(p, &newp, 10);
+ if (newp[0] != '.') return false;
+ p = newp + 1;
+
+ /*the ber representation can't use more space then the string one */
+ *blob = data_blob(NULL, strlen(OID));
+ if (!blob->data) return false;
+
+ blob->data[0] = 40*v + v2;
+
+ i = 1;
+ while (*p) {
+ v = strtoul(p, &newp, 10);
+ if (newp[0] == '.') {
+ p = newp + 1;
+ } else if (newp[0] == '\0') {
+ p = newp;
+ } else {
+ data_blob_free(blob);
+ return false;
+ }
+ if (v >= (1<<28)) blob->data[i++] = (0x80 | ((v>>28)&0x7f));
+ if (v >= (1<<21)) blob->data[i++] = (0x80 | ((v>>21)&0x7f));
+ if (v >= (1<<14)) blob->data[i++] = (0x80 | ((v>>14)&0x7f));
+ if (v >= (1<<7)) blob->data[i++] = (0x80 | ((v>>7)&0x7f));
+ blob->data[i++] = (v&0x7f);
+ }
+
+ blob->length = i;
+
+ return true;
+}
+
+/* read an object ID from a data blob */
+bool ber_read_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB blob, const char **OID)
+{
+ int i;
+ uint8_t *b;
+ uint_t v;
+ char *tmp_oid = NULL;
+
+ if (blob.length < 2) return false;
+
+ b = blob.data;
+
+ tmp_oid = talloc_asprintf(mem_ctx, "%u", b[0]/40);
+ if (!tmp_oid) goto nomem;
+ tmp_oid = talloc_asprintf_append_buffer(tmp_oid, ".%u", b[0]%40);
+ if (!tmp_oid) goto nomem;
+
+ for(i = 1, v = 0; i < blob.length; i++) {
+ v = (v<<7) | (b[i]&0x7f);
+ if ( ! (b[i] & 0x80)) {
+ tmp_oid = talloc_asprintf_append_buffer(tmp_oid, ".%u", v);
+ v = 0;
+ }
+ if (!tmp_oid) goto nomem;
+ }
+
+ if (v != 0) {
+ talloc_free(tmp_oid);
+ return false;
+ }
+
+ *OID = tmp_oid;
+ return true;
+
+nomem:
+ return false;
+}
+
+
diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c
new file mode 100644
index 0000000000..d5eac07b48
--- /dev/null
+++ b/source3/libsmb/async_smb.c
@@ -0,0 +1,999 @@
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async SMB client requests
+ Copyright (C) Volker Lendecke 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static void cli_state_handler(struct event_context *event_ctx,
+ struct fd_event *event, uint16 flags, void *p);
+
+/**
+ * Fetch an error out of a NBT packet
+ * @param[in] buf The SMB packet
+ * @retval The error, converted to NTSTATUS
+ */
+
+NTSTATUS cli_pull_error(char *buf)
+{
+ uint32_t flags2 = SVAL(buf, smb_flg2);
+
+ if (flags2 & FLAGS2_32_BIT_ERROR_CODES) {
+ return NT_STATUS(IVAL(buf, smb_rcls));
+ }
+
+ /* if the client uses dos errors, but there is no error,
+ we should return no error here, otherwise it looks
+ like an unknown bad NT_STATUS. jmcd */
+ if (CVAL(buf, smb_rcls) == 0)
+ return NT_STATUS_OK;
+
+ return NT_STATUS_DOS(CVAL(buf, smb_rcls), SVAL(buf,smb_err));
+}
+
+/**
+ * Compatibility helper for the sync APIs: Fake NTSTATUS in cli->inbuf
+ * @param[in] cli The client connection that just received an error
+ * @param[in] status The error to set on "cli"
+ */
+
+void cli_set_error(struct cli_state *cli, NTSTATUS status)
+{
+ uint32_t flags2 = SVAL(cli->inbuf, smb_flg2);
+
+ if (NT_STATUS_IS_DOS(status)) {
+ SSVAL(cli->inbuf, smb_flg2,
+ flags2 & ~FLAGS2_32_BIT_ERROR_CODES);
+ SCVAL(cli->inbuf, smb_rcls, NT_STATUS_DOS_CLASS(status));
+ SSVAL(cli->inbuf, smb_err, NT_STATUS_DOS_CODE(status));
+ return;
+ }
+
+ SSVAL(cli->inbuf, smb_flg2, flags2 | FLAGS2_32_BIT_ERROR_CODES);
+ SIVAL(cli->inbuf, smb_rcls, NT_STATUS_V(status));
+ return;
+}
+
+/**
+ * Allocate a new mid
+ * @param[in] cli The client connection
+ * @retval The new, unused mid
+ */
+
+static uint16_t cli_new_mid(struct cli_state *cli)
+{
+ uint16_t result;
+ struct cli_request *req;
+
+ while (true) {
+ result = cli->mid++;
+ if (result == 0) {
+ continue;
+ }
+
+ for (req = cli->outstanding_requests; req; req = req->next) {
+ if (result == req->mid) {
+ break;
+ }
+ }
+
+ if (req == NULL) {
+ return result;
+ }
+ }
+}
+
+/**
+ * Print an async req that happens to be a cli_request
+ * @param[in] mem_ctx The TALLOC_CTX to put the result on
+ * @param[in] req The request to print
+ * @retval The string representation of "req"
+ */
+
+static char *cli_request_print(TALLOC_CTX *mem_ctx, struct async_req *req)
+{
+ char *result = async_req_print(mem_ctx, req);
+ struct cli_request *cli_req = talloc_get_type_abort(
+ req->private_data, struct cli_request);
+
+ if (result == NULL) {
+ return NULL;
+ }
+
+ return talloc_asprintf_append_buffer(
+ result, "mid=%d\n", cli_req->mid);
+}
+
+/**
+ * Destroy a cli_request
+ * @param[in] req The cli_request to kill
+ * @retval Can't fail
+ */
+
+static int cli_request_destructor(struct cli_request *req)
+{
+ if (req->enc_state != NULL) {
+ common_free_enc_buffer(req->enc_state, req->outbuf);
+ }
+ DLIST_REMOVE(req->cli->outstanding_requests, req);
+ if (req->cli->outstanding_requests == NULL) {
+ TALLOC_FREE(req->cli->fd_event);
+ }
+ return 0;
+}
+
+/**
+ * Are there already requests waiting in the chain_accumulator?
+ * @param[in] cli The cli_state we want to check
+ * @retval reply :-)
+ */
+
+bool cli_in_chain(struct cli_state *cli)
+{
+ if (cli->chain_accumulator == NULL) {
+ return false;
+ }
+
+ return (cli->chain_accumulator->num_async != 0);
+}
+
+/**
+ * Is the SMB command able to hold an AND_X successor
+ * @param[in] cmd The SMB command in question
+ * @retval Can we add a chained request after "cmd"?
+ */
+
+static bool is_andx_req(uint8_t cmd)
+{
+ switch (cmd) {
+ case SMBtconX:
+ case SMBlockingX:
+ case SMBopenX:
+ case SMBreadX:
+ case SMBwriteX:
+ case SMBsesssetupX:
+ case SMBulogoffX:
+ case SMBntcreateX:
+ return true;
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+/**
+ * @brief Find the smb_cmd offset of the last command pushed
+ * @param[in] buf The buffer we're building up
+ * @retval Where can we put our next andx cmd?
+ *
+ * While chaining requests, the "next" request we're looking at needs to put
+ * its SMB_Command before the data the previous request already built up added
+ * to the chain. Find the offset to the place where we have to put our cmd.
+ */
+
+static bool find_andx_cmd_ofs(char *buf, size_t *pofs)
+{
+ uint8_t cmd;
+ size_t ofs;
+
+ cmd = CVAL(buf, smb_com);
+
+ SMB_ASSERT(is_andx_req(cmd));
+
+ ofs = smb_vwv0;
+
+ while (CVAL(buf, ofs) != 0xff) {
+
+ if (!is_andx_req(CVAL(buf, ofs))) {
+ return false;
+ }
+
+ /*
+ * ofs is from start of smb header, so add the 4 length
+ * bytes. The next cmd is right after the wct field.
+ */
+ ofs = SVAL(buf, ofs+2) + 4 + 1;
+
+ SMB_ASSERT(ofs+4 < talloc_get_size(buf));
+ }
+
+ *pofs = ofs;
+ return true;
+}
+
+/**
+ * @brief Destroy an async_req that is the visible part of a cli_request
+ * @param[in] req The request to kill
+ * @retval Return 0 to make talloc happy
+ *
+ * This destructor is a bit tricky: Because a cli_request can host more than
+ * one async_req for chained requests, we need to make sure that the
+ * "cli_request" that we were part of is correctly destroyed at the right
+ * time. This is done by NULLing out ourself from the "async" member of our
+ * "cli_request". If there is none left, then also TALLOC_FREE() the
+ * cli_request, which was a talloc child of the client connection cli_state.
+ */
+
+static int cli_async_req_destructor(struct async_req *req)
+{
+ struct cli_request *cli_req = talloc_get_type_abort(
+ req->private_data, struct cli_request);
+ int i, pending;
+ bool found = false;
+
+ pending = 0;
+
+ for (i=0; i<cli_req->num_async; i++) {
+ if (cli_req->async[i] == req) {
+ cli_req->async[i] = NULL;
+ found = true;
+ }
+ if (cli_req->async[i] != NULL) {
+ pending += 1;
+ }
+ }
+
+ SMB_ASSERT(found);
+
+ if (pending == 0) {
+ TALLOC_FREE(cli_req);
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Chain up a request
+ * @param[in] mem_ctx The TALLOC_CTX for the result
+ * @param[in] ev The event context that will call us back
+ * @param[in] cli The cli_state we queue the request up for
+ * @param[in] smb_command The command that we want to issue
+ * @param[in] additional_flags open_and_x wants to add oplock header flags
+ * @param[in] wct How many words?
+ * @param[in] vwv The words, already in network order
+ * @param[in] num_bytes How many bytes?
+ * @param[in] bytes The data the request ships
+ *
+ * cli_request_chain() is the core of the SMB request marshalling routine. It
+ * will create a new async_req structure in the cli->chain_accumulator->async
+ * array and marshall the smb_cmd, the vwv array and the bytes into
+ * cli->chain_accumulator->outbuf.
+ */
+
+static struct async_req *cli_request_chain(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ uint8_t smb_command,
+ uint8_t additional_flags,
+ uint8_t wct, const uint16_t *vwv,
+ uint16_t num_bytes,
+ const uint8_t *bytes)
+{
+ struct async_req **tmp_reqs;
+ char *tmp_buf;
+ struct cli_request *req;
+ size_t old_size, new_size;
+ size_t ofs;
+
+ req = cli->chain_accumulator;
+
+ tmp_reqs = TALLOC_REALLOC_ARRAY(req, req->async, struct async_req *,
+ req->num_async + 1);
+ if (tmp_reqs == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+ req->async = tmp_reqs;
+ req->num_async += 1;
+
+ req->async[req->num_async-1] = async_req_new(mem_ctx, ev);
+ if (req->async[req->num_async-1] == NULL) {
+ DEBUG(0, ("async_req_new failed\n"));
+ req->num_async -= 1;
+ return NULL;
+ }
+ req->async[req->num_async-1]->private_data = req;
+ req->async[req->num_async-1]->print = cli_request_print;
+ talloc_set_destructor(req->async[req->num_async-1],
+ cli_async_req_destructor);
+
+ old_size = talloc_get_size(req->outbuf);
+
+ /*
+ * We need space for the wct field, the words, the byte count field
+ * and the bytes themselves.
+ */
+ new_size = old_size + 1 + wct * sizeof(uint16_t) + 2 + num_bytes;
+
+ if (new_size > 0xffff) {
+ DEBUG(1, ("cli_request_chain: %u bytes won't fit\n",
+ (unsigned)new_size));
+ goto fail;
+ }
+
+ tmp_buf = TALLOC_REALLOC_ARRAY(NULL, req->outbuf, char, new_size);
+ if (tmp_buf == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ goto fail;
+ }
+ req->outbuf = tmp_buf;
+
+ if (old_size == smb_wct) {
+ SCVAL(req->outbuf, smb_com, smb_command);
+ } else {
+ size_t andx_cmd_ofs;
+ if (!find_andx_cmd_ofs(req->outbuf, &andx_cmd_ofs)) {
+ DEBUG(1, ("invalid command chain\n"));
+ goto fail;
+ }
+ SCVAL(req->outbuf, andx_cmd_ofs, smb_command);
+ SSVAL(req->outbuf, andx_cmd_ofs + 2, old_size - 4);
+ }
+
+ ofs = old_size;
+
+ SCVAL(req->outbuf, ofs, wct);
+ ofs += 1;
+
+ memcpy(req->outbuf + ofs, vwv, sizeof(uint16_t) * wct);
+ ofs += sizeof(uint16_t) * wct;
+
+ SSVAL(req->outbuf, ofs, num_bytes);
+ ofs += sizeof(uint16_t);
+
+ memcpy(req->outbuf + ofs, bytes, num_bytes);
+
+ return req->async[req->num_async-1];
+
+ fail:
+ TALLOC_FREE(req->async[req->num_async-1]);
+ req->num_async -= 1;
+ return NULL;
+}
+
+/**
+ * @brief prepare a cli_state to accept a chain of requests
+ * @param[in] cli The cli_state we want to queue up in
+ * @param[in] ev The event_context that will call us back for the socket
+ * @param[in] size_hint How many bytes are expected, just an optimization
+ * @retval Did we have enough memory?
+ *
+ * cli_chain_cork() sets up a new cli_request in cli->chain_accumulator. If
+ * cli is used in an async fashion, i.e. if we have outstanding requests, then
+ * we do not have to create a fd event. If cli is used only with the sync
+ * helpers, we need to create the fd_event here.
+ *
+ * If you want to issue a chained request to the server, do a
+ * cli_chain_cork(), then do you cli_open_send(), cli_read_and_x_send(),
+ * cli_close_send() and so on. The async requests that come out of
+ * cli_xxx_send() are normal async requests with the difference that they
+ * won't be shipped individually. But the event_context will still trigger the
+ * req->async.fn to be called on every single request.
+ *
+ * You have to take care yourself that you only issue chainable requests in
+ * the middle of the chain.
+ */
+
+bool cli_chain_cork(struct cli_state *cli, struct event_context *ev,
+ size_t size_hint)
+{
+ struct cli_request *req = NULL;
+
+ SMB_ASSERT(cli->chain_accumulator == NULL);
+
+ if (cli->fd == -1) {
+ DEBUG(10, ("cli->fd closed\n"));
+ return false;
+ }
+
+ if (cli->fd_event == NULL) {
+ SMB_ASSERT(cli->outstanding_requests == NULL);
+ cli->fd_event = event_add_fd(ev, cli, cli->fd,
+ EVENT_FD_READ,
+ cli_state_handler, cli);
+ if (cli->fd_event == NULL) {
+ return false;
+ }
+ }
+
+ req = talloc(cli, struct cli_request);
+ if (req == NULL) {
+ goto fail;
+ }
+ req->cli = cli;
+
+ if (size_hint == 0) {
+ size_hint = 100;
+ }
+ req->outbuf = talloc_array(req, char, smb_wct + size_hint);
+ if (req->outbuf == NULL) {
+ goto fail;
+ }
+ req->outbuf = TALLOC_REALLOC_ARRAY(NULL, req->outbuf, char, smb_wct);
+
+ req->num_async = 0;
+ req->async = NULL;
+
+ req->enc_state = NULL;
+ req->recv_helper.fn = NULL;
+
+ SSVAL(req->outbuf, smb_tid, cli->cnum);
+ cli_setup_packet_buf(cli, req->outbuf);
+
+ req->mid = cli_new_mid(cli);
+
+ cli->chain_accumulator = req;
+
+ DEBUG(10, ("cli_chain_cork: mid=%d\n", req->mid));
+
+ return true;
+ fail:
+ TALLOC_FREE(req);
+ if (cli->outstanding_requests == NULL) {
+ TALLOC_FREE(cli->fd_event);
+ }
+ return false;
+}
+
+/**
+ * Ship a request queued up via cli_request_chain()
+ * @param[in] cl The connection
+ */
+
+void cli_chain_uncork(struct cli_state *cli)
+{
+ struct cli_request *req = cli->chain_accumulator;
+
+ SMB_ASSERT(req != NULL);
+
+ DLIST_ADD_END(cli->outstanding_requests, req, struct cli_request *);
+ talloc_set_destructor(req, cli_request_destructor);
+
+ cli->chain_accumulator = NULL;
+
+ SSVAL(req->outbuf, smb_mid, req->mid);
+ smb_setlen(req->outbuf, talloc_get_size(req->outbuf) - 4);
+
+ cli_calculate_sign_mac(cli, req->outbuf);
+
+ if (cli_encryption_on(cli)) {
+ NTSTATUS status;
+ char *enc_buf;
+
+ status = cli_encrypt_message(cli, req->outbuf, &enc_buf);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Error in encrypting client message. "
+ "Error %s\n", nt_errstr(status)));
+ TALLOC_FREE(req);
+ return;
+ }
+ req->outbuf = enc_buf;
+ req->enc_state = cli->trans_enc_state;
+ }
+
+ req->sent = 0;
+
+ event_fd_set_writeable(cli->fd_event);
+}
+
+/**
+ * @brief Send a request to the server
+ * @param[in] mem_ctx The TALLOC_CTX for the result
+ * @param[in] ev The event context that will call us back
+ * @param[in] cli The cli_state we queue the request up for
+ * @param[in] smb_command The command that we want to issue
+ * @param[in] additional_flags open_and_x wants to add oplock header flags
+ * @param[in] wct How many words?
+ * @param[in] vwv The words, already in network order
+ * @param[in] num_bytes How many bytes?
+ * @param[in] bytes The data the request ships
+ *
+ * This is the generic routine to be used by the cli_xxx_send routines.
+ */
+
+struct async_req *cli_request_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ uint8_t smb_command,
+ uint8_t additional_flags,
+ uint8_t wct, const uint16_t *vwv,
+ uint16_t num_bytes, const uint8_t *bytes)
+{
+ struct async_req *result;
+ bool uncork = false;
+
+ if (cli->chain_accumulator == NULL) {
+ if (!cli_chain_cork(cli, ev,
+ wct * sizeof(uint16_t) + num_bytes + 3)) {
+ DEBUG(1, ("cli_chain_cork failed\n"));
+ return NULL;
+ }
+ uncork = true;
+ }
+
+ result = cli_request_chain(mem_ctx, ev, cli, smb_command,
+ additional_flags, wct, vwv,
+ num_bytes, bytes);
+
+ if (result == NULL) {
+ DEBUG(1, ("cli_request_chain failed\n"));
+ }
+
+ if (uncork) {
+ cli_chain_uncork(cli);
+ }
+
+ return result;
+}
+
+/**
+ * Figure out if there is an andx command behind the current one
+ * @param[in] buf The smb buffer to look at
+ * @param[in] ofs The offset to the wct field that is followed by the cmd
+ * @retval Is there a command following?
+ */
+
+static bool have_andx_command(const char *buf, uint16_t ofs)
+{
+ uint8_t wct;
+ size_t buflen = talloc_get_size(buf);
+
+ if ((ofs == buflen-1) || (ofs == buflen)) {
+ return false;
+ }
+
+ wct = CVAL(buf, ofs);
+ if (wct < 2) {
+ /*
+ * Not enough space for the command and a following pointer
+ */
+ return false;
+ }
+ return (CVAL(buf, ofs+1) != 0xff);
+}
+
+/**
+ * @brief Pull reply data out of a request
+ * @param[in] req The request that we just received a reply for
+ * @param[out] pwct How many words did the server send?
+ * @param[out] pvwv The words themselves
+ * @param[out] pnum_bytes How many bytes did the server send?
+ * @param[out] pbytes The bytes themselves
+ * @retval Was the reply formally correct?
+ */
+
+NTSTATUS cli_pull_reply(struct async_req *req,
+ uint8_t *pwct, uint16_t **pvwv,
+ uint16_t *pnum_bytes, uint8_t **pbytes)
+{
+ struct cli_request *cli_req = talloc_get_type_abort(
+ req->private_data, struct cli_request);
+ uint8_t wct, cmd;
+ uint16_t num_bytes;
+ size_t wct_ofs, bytes_offset;
+ int i, j;
+ NTSTATUS status;
+
+ for (i = 0; i < cli_req->num_async; i++) {
+ if (req == cli_req->async[i]) {
+ break;
+ }
+ }
+
+ if (i == cli_req->num_async) {
+ cli_set_error(cli_req->cli, NT_STATUS_INVALID_PARAMETER);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /**
+ * The status we pull here is only relevant for the last reply in the
+ * chain.
+ */
+
+ status = cli_pull_error(cli_req->inbuf);
+
+ if (i == 0) {
+ if (NT_STATUS_IS_ERR(status)
+ && !have_andx_command(cli_req->inbuf, smb_wct)) {
+ cli_set_error(cli_req->cli, status);
+ return status;
+ }
+ wct_ofs = smb_wct;
+ goto done;
+ }
+
+ cmd = CVAL(cli_req->inbuf, smb_com);
+ wct_ofs = smb_wct;
+
+ for (j = 0; j < i; j++) {
+ if (j < i-1) {
+ if (cmd == 0xff) {
+ return NT_STATUS_REQUEST_ABORTED;
+ }
+ if (!is_andx_req(cmd)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ }
+
+ if (!have_andx_command(cli_req->inbuf, wct_ofs)) {
+ /*
+ * This request was not completed because a previous
+ * request in the chain had received an error.
+ */
+ return NT_STATUS_REQUEST_ABORTED;
+ }
+
+ wct_ofs = SVAL(cli_req->inbuf, wct_ofs + 3);
+
+ /*
+ * Skip the all-present length field. No overflow, we've just
+ * put a 16-bit value into a size_t.
+ */
+ wct_ofs += 4;
+
+ if (wct_ofs+2 > talloc_get_size(cli_req->inbuf)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ cmd = CVAL(cli_req->inbuf, wct_ofs + 1);
+ }
+
+ if (!have_andx_command(cli_req->inbuf, wct_ofs)
+ && NT_STATUS_IS_ERR(status)) {
+ /*
+ * The last command takes the error code. All further commands
+ * down the requested chain will get a
+ * NT_STATUS_REQUEST_ABORTED.
+ */
+ return status;
+ }
+
+ done:
+ wct = CVAL(cli_req->inbuf, wct_ofs);
+
+ bytes_offset = wct_ofs + 1 + wct * sizeof(uint16_t);
+ num_bytes = SVAL(cli_req->inbuf, bytes_offset);
+
+ /*
+ * wct_ofs is a 16-bit value plus 4, wct is a 8-bit value, num_bytes
+ * is a 16-bit value. So bytes_offset being size_t should be far from
+ * wrapping.
+ */
+
+ if ((bytes_offset + 2 > talloc_get_size(cli_req->inbuf))
+ || (bytes_offset > 0xffff)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ *pwct = wct;
+ *pvwv = (uint16_t *)(cli_req->inbuf + wct_ofs + 1);
+ *pnum_bytes = num_bytes;
+ *pbytes = (uint8_t *)cli_req->inbuf + bytes_offset + 2;
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Decrypt a PDU, check the signature
+ * @param[in] cli The cli_state that received something
+ * @param[in] pdu The incoming bytes
+ * @retval error code
+ */
+
+
+static NTSTATUS validate_smb_crypto(struct cli_state *cli, char *pdu)
+{
+ NTSTATUS status;
+
+ if ((IVAL(pdu, 4) != 0x424d53ff) /* 0xFF"SMB" */
+ && (SVAL(pdu, 4) != 0x45ff)) /* 0xFF"E" */ {
+ DEBUG(10, ("Got non-SMB PDU\n"));
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (cli_encryption_on(cli) && CVAL(pdu, 0) == 0) {
+ uint16_t enc_ctx_num;
+
+ status = get_enc_ctx_num((uint8_t *)pdu, &enc_ctx_num);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("get_enc_ctx_num returned %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ if (enc_ctx_num != cli->trans_enc_state->enc_ctx_num) {
+ DEBUG(10, ("wrong enc_ctx %d, expected %d\n",
+ enc_ctx_num,
+ cli->trans_enc_state->enc_ctx_num));
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ status = common_decrypt_buffer(cli->trans_enc_state, pdu);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("common_decrypt_buffer returned %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+ }
+
+ if (!cli_check_sign_mac(cli, pdu)) {
+ DEBUG(10, ("cli_check_sign_mac failed\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * A PDU has arrived on cli->evt_inbuf
+ * @param[in] cli The cli_state that received something
+ */
+
+static void handle_incoming_pdu(struct cli_state *cli)
+{
+ struct cli_request *req;
+ uint16_t mid;
+ size_t raw_pdu_len, buf_len, pdu_len, rest_len;
+ char *pdu;
+ int i;
+ NTSTATUS status;
+
+ int num_async;
+
+ /*
+ * The encrypted PDU len might differ from the unencrypted one
+ */
+ raw_pdu_len = smb_len(cli->evt_inbuf) + 4;
+ buf_len = talloc_get_size(cli->evt_inbuf);
+ rest_len = buf_len - raw_pdu_len;
+
+ if (buf_len == raw_pdu_len) {
+ /*
+ * Optimal case: Exactly one PDU was in the socket buffer
+ */
+ pdu = cli->evt_inbuf;
+ cli->evt_inbuf = NULL;
+ }
+ else {
+ DEBUG(11, ("buf_len = %d, raw_pdu_len = %d, splitting "
+ "buffer\n", (int)buf_len, (int)raw_pdu_len));
+
+ if (raw_pdu_len < rest_len) {
+ /*
+ * The PDU is shorter, talloc_memdup that one.
+ */
+ pdu = (char *)talloc_memdup(
+ cli, cli->evt_inbuf, raw_pdu_len);
+
+ memmove(cli->evt_inbuf, cli->evt_inbuf + raw_pdu_len,
+ buf_len - raw_pdu_len);
+
+ cli->evt_inbuf = TALLOC_REALLOC_ARRAY(
+ NULL, cli->evt_inbuf, char, rest_len);
+
+ if (pdu == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto invalidate_requests;
+ }
+ }
+ else {
+ /*
+ * The PDU is larger than the rest, talloc_memdup the
+ * rest
+ */
+ pdu = cli->evt_inbuf;
+
+ cli->evt_inbuf = (char *)talloc_memdup(
+ cli, pdu + raw_pdu_len, rest_len);
+
+ if (cli->evt_inbuf == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto invalidate_requests;
+ }
+ }
+ }
+
+ status = validate_smb_crypto(cli, pdu);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto invalidate_requests;
+ }
+
+ mid = SVAL(pdu, smb_mid);
+
+ DEBUG(10, ("handle_incoming_pdu: got mid %d\n", mid));
+
+ for (req = cli->outstanding_requests; req; req = req->next) {
+ if (req->mid == mid) {
+ break;
+ }
+ }
+
+ pdu_len = smb_len(pdu) + 4;
+
+ if (req == NULL) {
+ DEBUG(3, ("Request for mid %d not found, dumping PDU\n", mid));
+
+ TALLOC_FREE(pdu);
+ return;
+ }
+
+ req->inbuf = talloc_move(req, &pdu);
+
+ /*
+ * Freeing the last async_req will free the req (see
+ * cli_async_req_destructor). So make a copy of req->num_async, we
+ * can't reference it in the last round.
+ */
+
+ num_async = req->num_async;
+
+ for (i=0; i<num_async; i++) {
+ /**
+ * A request might have been talloc_free()'ed before we arrive
+ * here. It will have removed itself from req->async via its
+ * destructor cli_async_req_destructor().
+ */
+ if (req->async[i] != NULL) {
+ if (req->recv_helper.fn != NULL) {
+ req->recv_helper.fn(req->async[i]);
+ } else {
+ async_req_done(req->async[i]);
+ }
+ }
+ }
+ return;
+
+ invalidate_requests:
+
+ DEBUG(10, ("handle_incoming_pdu: Aborting with %s\n",
+ nt_errstr(status)));
+
+ for (req = cli->outstanding_requests; req; req = req->next) {
+ async_req_error(req->async[0], status);
+ }
+ return;
+}
+
+/**
+ * fd event callback. This is the basic connection to the socket
+ * @param[in] event_ctx The event context that called us
+ * @param[in] event The event that fired
+ * @param[in] flags EVENT_FD_READ | EVENT_FD_WRITE
+ * @param[in] p private_data, in this case the cli_state
+ */
+
+static void cli_state_handler(struct event_context *event_ctx,
+ struct fd_event *event, uint16 flags, void *p)
+{
+ struct cli_state *cli = (struct cli_state *)p;
+ struct cli_request *req;
+ NTSTATUS status;
+
+ DEBUG(11, ("cli_state_handler called with flags %d\n", flags));
+
+ if (flags & EVENT_FD_READ) {
+ int res, available;
+ size_t old_size, new_size;
+ char *tmp;
+
+ res = ioctl(cli->fd, FIONREAD, &available);
+ if (res == -1) {
+ DEBUG(10, ("ioctl(FIONREAD) failed: %s\n",
+ strerror(errno)));
+ status = map_nt_error_from_unix(errno);
+ goto sock_error;
+ }
+
+ if (available == 0) {
+ /* EOF */
+ status = NT_STATUS_END_OF_FILE;
+ goto sock_error;
+ }
+
+ old_size = talloc_get_size(cli->evt_inbuf);
+ new_size = old_size + available;
+
+ if (new_size < old_size) {
+ /* wrap */
+ status = NT_STATUS_UNEXPECTED_IO_ERROR;
+ goto sock_error;
+ }
+
+ tmp = TALLOC_REALLOC_ARRAY(cli, cli->evt_inbuf, char,
+ new_size);
+ if (tmp == NULL) {
+ /* nomem */
+ status = NT_STATUS_NO_MEMORY;
+ goto sock_error;
+ }
+ cli->evt_inbuf = tmp;
+
+ res = recv(cli->fd, cli->evt_inbuf + old_size, available, 0);
+ if (res == -1) {
+ DEBUG(10, ("recv failed: %s\n", strerror(errno)));
+ status = map_nt_error_from_unix(errno);
+ goto sock_error;
+ }
+
+ DEBUG(11, ("cli_state_handler: received %d bytes, "
+ "smb_len(evt_inbuf) = %d\n", (int)res,
+ smb_len(cli->evt_inbuf)));
+
+ /* recv *might* have returned less than announced */
+ new_size = old_size + res;
+
+ /* shrink, so I don't expect errors here */
+ cli->evt_inbuf = TALLOC_REALLOC_ARRAY(cli, cli->evt_inbuf,
+ char, new_size);
+
+ while ((cli->evt_inbuf != NULL)
+ && ((smb_len(cli->evt_inbuf) + 4) <= new_size)) {
+ /*
+ * we've got a complete NBT level PDU in evt_inbuf
+ */
+ handle_incoming_pdu(cli);
+ new_size = talloc_get_size(cli->evt_inbuf);
+ }
+ }
+
+ if (flags & EVENT_FD_WRITE) {
+ size_t to_send;
+ ssize_t sent;
+
+ for (req = cli->outstanding_requests; req; req = req->next) {
+ to_send = smb_len(req->outbuf)+4;
+ if (to_send > req->sent) {
+ break;
+ }
+ }
+
+ if (req == NULL) {
+ if (cli->fd_event != NULL) {
+ event_fd_set_not_writeable(cli->fd_event);
+ }
+ return;
+ }
+
+ sent = send(cli->fd, req->outbuf + req->sent,
+ to_send - req->sent, 0);
+
+ if (sent < 0) {
+ status = map_nt_error_from_unix(errno);
+ goto sock_error;
+ }
+
+ req->sent += sent;
+
+ if (req->sent == to_send) {
+ return;
+ }
+ }
+ return;
+
+ sock_error:
+ for (req = cli->outstanding_requests; req; req = req->next) {
+ int i;
+ for (i=0; i<req->num_async; i++) {
+ async_req_error(req->async[i], status);
+ }
+ }
+ TALLOC_FREE(cli->fd_event);
+ close(cli->fd);
+ cli->fd = -1;
+}
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
new file mode 100644
index 0000000000..8ef14d7973
--- /dev/null
+++ b/source3/libsmb/cliconnect.c
@@ -0,0 +1,2011 @@
+/*
+ Unix SMB/CIFS implementation.
+ client connect/disconnect routines
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Andrew Bartlett 2001-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static const struct {
+ int prot;
+ const char *name;
+} prots[] = {
+ {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
+ {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
+ {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
+ {PROTOCOL_LANMAN1,"LANMAN1.0"},
+ {PROTOCOL_LANMAN2,"LM1.2X002"},
+ {PROTOCOL_LANMAN2,"DOS LANMAN2.1"},
+ {PROTOCOL_LANMAN2,"LANMAN2.1"},
+ {PROTOCOL_LANMAN2,"Samba"},
+ {PROTOCOL_NT1,"NT LANMAN 1.0"},
+ {PROTOCOL_NT1,"NT LM 0.12"},
+ {-1,NULL}
+};
+
+static const char *star_smbserver_name = "*SMBSERVER";
+
+/**
+ * Set the user session key for a connection
+ * @param cli The cli structure to add it too
+ * @param session_key The session key used. (A copy of this is taken for the cli struct)
+ *
+ */
+
+static void cli_set_session_key (struct cli_state *cli, const DATA_BLOB session_key)
+{
+ cli->user_session_key = data_blob(session_key.data, session_key.length);
+}
+
+/****************************************************************************
+ Do an old lanman2 style session setup.
+****************************************************************************/
+
+static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli,
+ const char *user,
+ const char *pass, size_t passlen,
+ const char *workgroup)
+{
+ DATA_BLOB session_key = data_blob_null;
+ DATA_BLOB lm_response = data_blob_null;
+ fstring pword;
+ char *p;
+
+ if (passlen > sizeof(pword)-1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* LANMAN servers predate NT status codes and Unicode and ignore those
+ smb flags so we must disable the corresponding default capabilities
+ that would otherwise cause the Unicode and NT Status flags to be
+ set (and even returned by the server) */
+
+ cli->capabilities &= ~(CAP_UNICODE | CAP_STATUS32);
+
+ /* if in share level security then don't send a password now */
+ if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL))
+ passlen = 0;
+
+ if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
+ /* Encrypted mode needed, and non encrypted password supplied. */
+ lm_response = data_blob(NULL, 24);
+ if (!SMBencrypt(pass, cli->secblob.data,(uchar *)lm_response.data)) {
+ DEBUG(1, ("Password is > 14 chars in length, and is therefore incompatible with Lanman authentication\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
+ /* Encrypted mode needed, and encrypted password supplied. */
+ lm_response = data_blob(pass, passlen);
+ } else if (passlen > 0) {
+ /* Plaintext mode needed, assume plaintext supplied. */
+ passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
+ lm_response = data_blob(pass, passlen);
+ }
+
+ /* send a session setup command */
+ memset(cli->outbuf,'\0',smb_size);
+ cli_set_message(cli->outbuf,10, 0, True);
+ SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
+ cli_setup_packet(cli);
+
+ SCVAL(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,lm_response.length);
+
+ p = smb_buf(cli->outbuf);
+ memcpy(p,lm_response.data,lm_response.length);
+ p += lm_response.length;
+ p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
+ p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
+ p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
+ p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
+ cli_setup_bcc(cli, p);
+
+ if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
+ return cli_nt_error(cli);
+ }
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli)) {
+ return cli_nt_error(cli);
+ }
+
+ /* use the returned vuid from now on */
+ cli->vuid = SVAL(cli->inbuf,smb_uid);
+ fstrcpy(cli->user_name, user);
+
+ if (session_key.data) {
+ /* Have plaintext orginal */
+ cli_set_session_key(cli, session_key);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Work out suitable capabilities to offer the server.
+****************************************************************************/
+
+static uint32 cli_session_setup_capabilities(struct cli_state *cli)
+{
+ uint32 capabilities = CAP_NT_SMBS;
+
+ if (!cli->force_dos_errors)
+ capabilities |= CAP_STATUS32;
+
+ if (cli->use_level_II_oplocks)
+ capabilities |= CAP_LEVEL_II_OPLOCKS;
+
+ capabilities |= (cli->capabilities & (CAP_UNICODE|CAP_LARGE_FILES|CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_DFS));
+ return capabilities;
+}
+
+/****************************************************************************
+ Do a NT1 guest session setup.
+****************************************************************************/
+
+static NTSTATUS cli_session_setup_guest(struct cli_state *cli)
+{
+ char *p;
+ uint32 capabilities = cli_session_setup_capabilities(cli);
+
+ memset(cli->outbuf, '\0', smb_size);
+ cli_set_message(cli->outbuf,13,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
+ SSVAL(cli->outbuf,smb_vwv3,2);
+ SSVAL(cli->outbuf,smb_vwv4,cli->pid);
+ SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
+ SSVAL(cli->outbuf,smb_vwv7,0);
+ SSVAL(cli->outbuf,smb_vwv8,0);
+ SIVAL(cli->outbuf,smb_vwv11,capabilities);
+ p = smb_buf(cli->outbuf);
+ p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
+ p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
+ p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
+ p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
+ cli_setup_bcc(cli, p);
+
+ if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
+ return cli_nt_error(cli);
+ }
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli)) {
+ return cli_nt_error(cli);
+ }
+
+ cli->vuid = SVAL(cli->inbuf,smb_uid);
+
+ p = smb_buf(cli->inbuf);
+ p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
+
+ if (strstr(cli->server_type, "Samba")) {
+ cli->is_samba = True;
+ }
+
+ fstrcpy(cli->user_name, "");
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Do a NT1 plaintext session setup.
+****************************************************************************/
+
+static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli,
+ const char *user, const char *pass,
+ const char *workgroup)
+{
+ uint32 capabilities = cli_session_setup_capabilities(cli);
+ char *p;
+ fstring lanman;
+
+ fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
+
+ memset(cli->outbuf, '\0', smb_size);
+ cli_set_message(cli->outbuf,13,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
+ SSVAL(cli->outbuf,smb_vwv3,2);
+ SSVAL(cli->outbuf,smb_vwv4,cli->pid);
+ SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
+ SSVAL(cli->outbuf,smb_vwv8,0);
+ SIVAL(cli->outbuf,smb_vwv11,capabilities);
+ p = smb_buf(cli->outbuf);
+
+ /* check wether to send the ASCII or UNICODE version of the password */
+
+ if ( (capabilities & CAP_UNICODE) == 0 ) {
+ p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
+ SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
+ }
+ else {
+ /* For ucs2 passwords clistr_push calls ucs2_align, which causes
+ * the space taken by the unicode password to be one byte too
+ * long (as we're on an odd byte boundary here). Reduce the
+ * count by 1 to cope with this. Fixes smbclient against NetApp
+ * servers which can't cope. Fix from
+ * bryan.kolodziej@allenlund.com in bug #3840.
+ */
+ p += clistr_push(cli, p, pass, -1, STR_UNICODE|STR_TERMINATE); /* unicode password */
+ SSVAL(cli->outbuf,smb_vwv8,PTR_DIFF(p, smb_buf(cli->outbuf))-1);
+ }
+
+ p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
+ p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
+ p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
+ p += clistr_push(cli, p, lanman, -1, STR_TERMINATE);
+ cli_setup_bcc(cli, p);
+
+ if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
+ return cli_nt_error(cli);
+ }
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli)) {
+ return cli_nt_error(cli);
+ }
+
+ cli->vuid = SVAL(cli->inbuf,smb_uid);
+ p = smb_buf(cli->inbuf);
+ p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
+ fstrcpy(cli->user_name, user);
+
+ if (strstr(cli->server_type, "Samba")) {
+ cli->is_samba = True;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ do a NT1 NTLM/LM encrypted session setup - for when extended security
+ is not negotiated.
+ @param cli client state to create do session setup on
+ @param user username
+ @param pass *either* cleartext password (passlen !=24) or LM response.
+ @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
+ @param workgroup The user's domain.
+****************************************************************************/
+
+static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
+ const char *pass, size_t passlen,
+ const char *ntpass, size_t ntpasslen,
+ const char *workgroup)
+{
+ uint32 capabilities = cli_session_setup_capabilities(cli);
+ DATA_BLOB lm_response = data_blob_null;
+ DATA_BLOB nt_response = data_blob_null;
+ DATA_BLOB session_key = data_blob_null;
+ NTSTATUS result;
+ char *p;
+
+ if (passlen == 0) {
+ /* do nothing - guest login */
+ } else if (passlen != 24) {
+ if (lp_client_ntlmv2_auth()) {
+ DATA_BLOB server_chal;
+ DATA_BLOB names_blob;
+ server_chal = data_blob(cli->secblob.data, MIN(cli->secblob.length, 8));
+
+ /* note that the 'workgroup' here is a best guess - we don't know
+ the server's domain at this point. The 'server name' is also
+ dodgy...
+ */
+ names_blob = NTLMv2_generate_names_blob(cli->called.name, workgroup);
+
+ if (!SMBNTLMv2encrypt(user, workgroup, pass, &server_chal,
+ &names_blob,
+ &lm_response, &nt_response, &session_key)) {
+ data_blob_free(&names_blob);
+ data_blob_free(&server_chal);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ data_blob_free(&names_blob);
+ data_blob_free(&server_chal);
+
+ } else {
+ uchar nt_hash[16];
+ E_md4hash(pass, nt_hash);
+
+#ifdef LANMAN_ONLY
+ nt_response = data_blob_null;
+#else
+ nt_response = data_blob(NULL, 24);
+ SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
+#endif
+ /* non encrypted password supplied. Ignore ntpass. */
+ if (lp_client_lanman_auth()) {
+ lm_response = data_blob(NULL, 24);
+ if (!SMBencrypt(pass,cli->secblob.data, lm_response.data)) {
+ /* Oops, the LM response is invalid, just put
+ the NT response there instead */
+ data_blob_free(&lm_response);
+ lm_response = data_blob(nt_response.data, nt_response.length);
+ }
+ } else {
+ /* LM disabled, place NT# in LM field instead */
+ lm_response = data_blob(nt_response.data, nt_response.length);
+ }
+
+ session_key = data_blob(NULL, 16);
+#ifdef LANMAN_ONLY
+ E_deshash(pass, session_key.data);
+ memset(&session_key.data[8], '\0', 8);
+#else
+ SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+#endif
+ }
+#ifdef LANMAN_ONLY
+ cli_simple_set_signing(cli, session_key, lm_response);
+#else
+ cli_simple_set_signing(cli, session_key, nt_response);
+#endif
+ } else {
+ /* pre-encrypted password supplied. Only used for
+ security=server, can't do
+ signing because we don't have original key */
+
+ lm_response = data_blob(pass, passlen);
+ nt_response = data_blob(ntpass, ntpasslen);
+ }
+
+ /* send a session setup command */
+ memset(cli->outbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,13,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
+ SSVAL(cli->outbuf,smb_vwv3,2);
+ SSVAL(cli->outbuf,smb_vwv4,cli->pid);
+ SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
+ SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
+ SSVAL(cli->outbuf,smb_vwv8,nt_response.length);
+ SIVAL(cli->outbuf,smb_vwv11,capabilities);
+ p = smb_buf(cli->outbuf);
+ if (lm_response.length) {
+ memcpy(p,lm_response.data, lm_response.length); p += lm_response.length;
+ }
+ if (nt_response.length) {
+ memcpy(p,nt_response.data, nt_response.length); p += nt_response.length;
+ }
+ p += clistr_push(cli, p, user, -1, STR_TERMINATE);
+
+ /* Upper case here might help some NTLMv2 implementations */
+ p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
+ p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
+ p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
+ cli_setup_bcc(cli, p);
+
+ if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
+ result = cli_nt_error(cli);
+ goto end;
+ }
+
+ /* show_msg(cli->inbuf); */
+
+ if (cli_is_error(cli)) {
+ result = cli_nt_error(cli);
+ goto end;
+ }
+
+ /* use the returned vuid from now on */
+ cli->vuid = SVAL(cli->inbuf,smb_uid);
+
+ p = smb_buf(cli->inbuf);
+ p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
+
+ if (strstr(cli->server_type, "Samba")) {
+ cli->is_samba = True;
+ }
+
+ fstrcpy(cli->user_name, user);
+
+ if (session_key.data) {
+ /* Have plaintext orginal */
+ cli_set_session_key(cli, session_key);
+ }
+
+ result = NT_STATUS_OK;
+end:
+ data_blob_free(&lm_response);
+ data_blob_free(&nt_response);
+ data_blob_free(&session_key);
+ return result;
+}
+
+/****************************************************************************
+ Send a extended security session setup blob
+****************************************************************************/
+
+static bool cli_session_setup_blob_send(struct cli_state *cli, DATA_BLOB blob)
+{
+ uint32 capabilities = cli_session_setup_capabilities(cli);
+ char *p;
+
+ capabilities |= CAP_EXTENDED_SECURITY;
+
+ /* send a session setup command */
+ memset(cli->outbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,12,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
+
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
+ SSVAL(cli->outbuf,smb_vwv3,2);
+ SSVAL(cli->outbuf,smb_vwv4,1);
+ SIVAL(cli->outbuf,smb_vwv5,0);
+ SSVAL(cli->outbuf,smb_vwv7,blob.length);
+ SIVAL(cli->outbuf,smb_vwv10,capabilities);
+ p = smb_buf(cli->outbuf);
+ memcpy(p, blob.data, blob.length);
+ p += blob.length;
+ p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
+ p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
+ cli_setup_bcc(cli, p);
+ return cli_send_smb(cli);
+}
+
+/****************************************************************************
+ Send a extended security session setup blob, returning a reply blob.
+****************************************************************************/
+
+static DATA_BLOB cli_session_setup_blob_receive(struct cli_state *cli)
+{
+ DATA_BLOB blob2 = data_blob_null;
+ char *p;
+ size_t len;
+
+ if (!cli_receive_smb(cli))
+ return blob2;
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
+ NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ return blob2;
+ }
+
+ /* use the returned vuid from now on */
+ cli->vuid = SVAL(cli->inbuf,smb_uid);
+
+ p = smb_buf(cli->inbuf);
+
+ blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
+
+ p += blob2.length;
+ p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
+
+ /* w2k with kerberos doesn't properly null terminate this field */
+ len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf));
+ p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
+
+ return blob2;
+}
+
+#ifdef HAVE_KRB5
+/****************************************************************************
+ Send a extended security session setup blob, returning a reply blob.
+****************************************************************************/
+
+/* The following is calculated from :
+ * (smb_size-4) = 35
+ * (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
+ * (strlen("Unix") + 1 + strlen("Samba") + 1) * 2 = 22 (unicode strings at
+ * end of packet.
+ */
+
+#define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22)
+
+static bool cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob, DATA_BLOB session_key_krb5)
+{
+ int32 remaining = blob.length;
+ int32 cur = 0;
+ DATA_BLOB send_blob = data_blob_null;
+ int32 max_blob_size = 0;
+ DATA_BLOB receive_blob = data_blob_null;
+
+ if (cli->max_xmit < BASE_SESSSETUP_BLOB_PACKET_SIZE + 1) {
+ DEBUG(0,("cli_session_setup_blob: cli->max_xmit too small "
+ "(was %u, need minimum %u)\n",
+ (unsigned int)cli->max_xmit,
+ BASE_SESSSETUP_BLOB_PACKET_SIZE));
+ cli_set_nt_error(cli, NT_STATUS_INVALID_PARAMETER);
+ return False;
+ }
+
+ max_blob_size = cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE;
+
+ while ( remaining > 0) {
+ if (remaining >= max_blob_size) {
+ send_blob.length = max_blob_size;
+ remaining -= max_blob_size;
+ } else {
+ DATA_BLOB null_blob = data_blob_null;
+
+ send_blob.length = remaining;
+ remaining = 0;
+
+ /* This is the last packet in the sequence - turn signing on. */
+ cli_simple_set_signing(cli, session_key_krb5, null_blob);
+ }
+
+ send_blob.data = &blob.data[cur];
+ cur += send_blob.length;
+
+ DEBUG(10, ("cli_session_setup_blob: Remaining (%u) sending (%u) current (%u)\n",
+ (unsigned int)remaining,
+ (unsigned int)send_blob.length,
+ (unsigned int)cur ));
+
+ if (!cli_session_setup_blob_send(cli, send_blob)) {
+ DEBUG(0, ("cli_session_setup_blob: send failed\n"));
+ return False;
+ }
+
+ receive_blob = cli_session_setup_blob_receive(cli);
+ data_blob_free(&receive_blob);
+
+ if (cli_is_error(cli) &&
+ !NT_STATUS_EQUAL( cli_get_nt_error(cli),
+ NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DEBUG(0, ("cli_session_setup_blob: receive failed "
+ "(%s)\n", nt_errstr(cli_get_nt_error(cli))));
+ cli->vuid = 0;
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Use in-memory credentials cache
+****************************************************************************/
+
+static void use_in_memory_ccache(void) {
+ setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
+}
+
+/****************************************************************************
+ Do a spnego/kerberos encrypted session setup.
+****************************************************************************/
+
+static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup)
+{
+ DATA_BLOB negTokenTarg;
+ DATA_BLOB session_key_krb5;
+ int rc;
+
+ DEBUG(2,("Doing kerberos session setup\n"));
+
+ /* generate the encapsulated kerberos5 ticket */
+ rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5, 0, NULL);
+
+ if (rc) {
+ DEBUG(1, ("cli_session_setup_kerberos: spnego_gen_negTokenTarg failed: %s\n",
+ error_message(rc)));
+ return ADS_ERROR_KRB5(rc);
+ }
+
+#if 0
+ file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
+#endif
+
+ if (!cli_session_setup_blob(cli, negTokenTarg, session_key_krb5)) {
+ data_blob_free(&negTokenTarg);
+ data_blob_free(&session_key_krb5);
+ return ADS_ERROR_NT(cli_nt_error(cli));
+ }
+
+ cli_set_session_key(cli, session_key_krb5);
+
+ data_blob_free(&negTokenTarg);
+ data_blob_free(&session_key_krb5);
+
+ if (cli_is_error(cli)) {
+ if (NT_STATUS_IS_OK(cli_nt_error(cli))) {
+ return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+ }
+ }
+ return ADS_ERROR_NT(cli_nt_error(cli));
+}
+#endif /* HAVE_KRB5 */
+
+
+/****************************************************************************
+ Do a spnego/NTLMSSP encrypted session setup.
+****************************************************************************/
+
+static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
+ const char *pass, const char *domain)
+{
+ struct ntlmssp_state *ntlmssp_state;
+ NTSTATUS nt_status;
+ int turn = 1;
+ DATA_BLOB msg1;
+ DATA_BLOB blob = data_blob_null;
+ DATA_BLOB blob_in = data_blob_null;
+ DATA_BLOB blob_out = data_blob_null;
+
+ cli_temp_set_signing(cli);
+
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
+ return nt_status;
+ }
+ ntlmssp_want_feature(ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);
+
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
+ return nt_status;
+ }
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) {
+ return nt_status;
+ }
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) {
+ return nt_status;
+ }
+
+ do {
+ nt_status = ntlmssp_update(ntlmssp_state,
+ blob_in, &blob_out);
+ data_blob_free(&blob_in);
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(nt_status)) {
+ if (turn == 1) {
+ /* and wrap it in a SPNEGO wrapper */
+ msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
+ } else {
+ /* wrap it in SPNEGO */
+ msg1 = spnego_gen_auth(blob_out);
+ }
+
+ /* now send that blob on its way */
+ if (!cli_session_setup_blob_send(cli, msg1)) {
+ DEBUG(3, ("Failed to send NTLMSSP/SPNEGO blob to server!\n"));
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ } else {
+ blob = cli_session_setup_blob_receive(cli);
+
+ nt_status = cli_nt_error(cli);
+ if (cli_is_error(cli) && NT_STATUS_IS_OK(nt_status)) {
+ if (cli->smb_rw_error == SMB_READ_BAD_SIG) {
+ nt_status = NT_STATUS_ACCESS_DENIED;
+ } else {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+ }
+ data_blob_free(&msg1);
+ }
+
+ if (!blob.length) {
+ if (NT_STATUS_IS_OK(nt_status)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ }
+ } else if ((turn == 1) &&
+ NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DATA_BLOB tmp_blob = data_blob_null;
+ /* the server might give us back two challenges */
+ if (!spnego_parse_challenge(blob, &blob_in,
+ &tmp_blob)) {
+ DEBUG(3,("Failed to parse challenges\n"));
+ nt_status = NT_STATUS_INVALID_PARAMETER;
+ }
+ data_blob_free(&tmp_blob);
+ } else {
+ if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP,
+ &blob_in)) {
+ DEBUG(3,("Failed to parse auth response\n"));
+ if (NT_STATUS_IS_OK(nt_status)
+ || NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED))
+ nt_status = NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+ data_blob_free(&blob);
+ data_blob_free(&blob_out);
+ turn++;
+ } while (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED));
+
+ data_blob_free(&blob_in);
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+
+ DATA_BLOB key = data_blob(ntlmssp_state->session_key.data,
+ ntlmssp_state->session_key.length);
+ DATA_BLOB null_blob = data_blob_null;
+ bool res;
+
+ fstrcpy(cli->server_domain, ntlmssp_state->server_domain);
+ cli_set_session_key(cli, ntlmssp_state->session_key);
+
+ res = cli_simple_set_signing(cli, key, null_blob);
+
+ data_blob_free(&key);
+
+ if (res) {
+
+ /* 'resign' the last message, so we get the right sequence numbers
+ for checking the first reply from the server */
+ cli_calculate_sign_mac(cli, cli->outbuf);
+
+ if (!cli_check_sign_mac(cli, cli->inbuf)) {
+ nt_status = NT_STATUS_ACCESS_DENIED;
+ }
+ }
+ }
+
+ /* we have a reference conter on ntlmssp_state, if we are signing
+ then the state will be kept by the signing engine */
+
+ ntlmssp_end(&ntlmssp_state);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ cli->vuid = 0;
+ }
+ return nt_status;
+}
+
+/****************************************************************************
+ Do a spnego encrypted session setup.
+
+ user_domain: The shortname of the domain the user/machine is a member of.
+ dest_realm: The realm we're connecting to, if NULL we use our default realm.
+****************************************************************************/
+
+ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user,
+ const char *pass, const char *user_domain,
+ const char * dest_realm)
+{
+ char *principal = NULL;
+ char *OIDs[ASN1_MAX_OIDS];
+ int i;
+ DATA_BLOB blob;
+ const char *p = NULL;
+ char *account = NULL;
+
+ DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length));
+
+ /* the server might not even do spnego */
+ if (cli->secblob.length <= 16) {
+ DEBUG(3,("server didn't supply a full spnego negprot\n"));
+ goto ntlmssp;
+ }
+
+#if 0
+ file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
+#endif
+
+ /* there is 16 bytes of GUID before the real spnego packet starts */
+ blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
+
+ /* The server sent us the first part of the SPNEGO exchange in the
+ * negprot reply. It is WRONG to depend on the principal sent in the
+ * negprot reply, but right now we do it. If we don't receive one,
+ * we try to best guess, then fall back to NTLM. */
+ if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
+ data_blob_free(&blob);
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+ data_blob_free(&blob);
+
+ /* make sure the server understands kerberos */
+ for (i=0;OIDs[i];i++) {
+ DEBUG(3,("got OID=%s\n", OIDs[i]));
+ if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
+ strcmp(OIDs[i], OID_KERBEROS5) == 0) {
+ cli->got_kerberos_mechanism = True;
+ }
+ free(OIDs[i]);
+ }
+
+ DEBUG(3,("got principal=%s\n", principal ? principal : "<null>"));
+
+ fstrcpy(cli->user_name, user);
+
+#ifdef HAVE_KRB5
+ /* If password is set we reauthenticate to kerberos server
+ * and do not store results */
+
+ if (cli->got_kerberos_mechanism && cli->use_kerberos) {
+ ADS_STATUS rc;
+
+ if (pass && *pass) {
+ int ret;
+
+ use_in_memory_ccache();
+ ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
+
+ if (ret){
+ SAFE_FREE(principal);
+ DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
+ if (cli->fallback_after_kerberos)
+ goto ntlmssp;
+ return ADS_ERROR_KRB5(ret);
+ }
+ }
+
+ /* If we get a bad principal, try to guess it if
+ we have a valid host NetBIOS name.
+ */
+ if (strequal(principal, ADS_IGNORE_PRINCIPAL)) {
+ SAFE_FREE(principal);
+ }
+
+ if (principal == NULL &&
+ !is_ipaddress(cli->desthost) &&
+ !strequal(star_smbserver_name,
+ cli->desthost)) {
+ char *realm = NULL;
+ char *machine = NULL;
+ char *host = NULL;
+ DEBUG(3,("cli_session_setup_spnego: got a "
+ "bad server principal, trying to guess ...\n"));
+
+ host = strchr_m(cli->desthost, '.');
+ if (host) {
+ machine = SMB_STRNDUP(cli->desthost,
+ host - cli->desthost);
+ } else {
+ machine = SMB_STRDUP(cli->desthost);
+ }
+ if (machine == NULL) {
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ if (dest_realm) {
+ realm = SMB_STRDUP(dest_realm);
+ strupper_m(realm);
+ } else {
+ realm = kerberos_get_default_realm_from_ccache();
+ }
+ if (realm && *realm) {
+ if (asprintf(&principal, "%s$@%s",
+ machine, realm) < 0) {
+ SAFE_FREE(machine);
+ SAFE_FREE(realm);
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+ DEBUG(3,("cli_session_setup_spnego: guessed "
+ "server principal=%s\n",
+ principal ? principal : "<null>"));
+ }
+ SAFE_FREE(machine);
+ SAFE_FREE(realm);
+ }
+
+ if (principal) {
+ rc = cli_session_setup_kerberos(cli, principal,
+ dest_realm);
+ if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) {
+ SAFE_FREE(principal);
+ return rc;
+ }
+ }
+ }
+#endif
+
+ SAFE_FREE(principal);
+
+ntlmssp:
+
+ account = talloc_strdup(talloc_tos(), user);
+ if (!account) {
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ /* when falling back to ntlmssp while authenticating with a machine
+ * account strip off the realm - gd */
+
+ if ((p = strchr_m(user, '@')) != NULL) {
+ account[PTR_DIFF(p,user)] = '\0';
+ }
+
+ return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, account, pass, user_domain));
+}
+
+/****************************************************************************
+ Send a session setup. The username and workgroup is in UNIX character
+ format and must be converted to DOS codepage format before sending. If the
+ password is in plaintext, the same should be done.
+****************************************************************************/
+
+NTSTATUS cli_session_setup(struct cli_state *cli,
+ const char *user,
+ const char *pass, int passlen,
+ const char *ntpass, int ntpasslen,
+ const char *workgroup)
+{
+ char *p;
+ fstring user2;
+
+ if (user) {
+ fstrcpy(user2, user);
+ } else {
+ user2[0] ='\0';
+ }
+
+ if (!workgroup) {
+ workgroup = "";
+ }
+
+ /* allow for workgroups as part of the username */
+ if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
+ (p=strchr_m(user2,*lp_winbind_separator()))) {
+ *p = 0;
+ user = p+1;
+ workgroup = user2;
+ }
+
+ if (cli->protocol < PROTOCOL_LANMAN1) {
+ return NT_STATUS_OK;
+ }
+
+ /* now work out what sort of session setup we are going to
+ do. I have split this into separate functions to make the
+ flow a bit easier to understand (tridge) */
+
+ /* if its an older server then we have to use the older request format */
+
+ if (cli->protocol < PROTOCOL_NT1) {
+ if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
+ DEBUG(1, ("Server requested LM password but 'client lanman auth'"
+ " is disabled\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
+ !lp_client_plaintext_auth() && (*pass)) {
+ DEBUG(1, ("Server requested plaintext password but "
+ "'client plaintext auth' is disabled\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return cli_session_setup_lanman2(cli, user, pass, passlen,
+ workgroup);
+ }
+
+ /* if no user is supplied then we have to do an anonymous connection.
+ passwords are ignored */
+
+ if (!user || !*user)
+ return cli_session_setup_guest(cli);
+
+ /* if the server is share level then send a plaintext null
+ password at this point. The password is sent in the tree
+ connect */
+
+ if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0)
+ return cli_session_setup_plaintext(cli, user, "", workgroup);
+
+ /* if the server doesn't support encryption then we have to use
+ plaintext. The second password is ignored */
+
+ if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
+ if (!lp_client_plaintext_auth() && (*pass)) {
+ DEBUG(1, ("Server requested plaintext password but "
+ "'client plaintext auth' is disabled\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ return cli_session_setup_plaintext(cli, user, pass, workgroup);
+ }
+
+ /* if the server supports extended security then use SPNEGO */
+
+ if (cli->capabilities & CAP_EXTENDED_SECURITY) {
+ ADS_STATUS status = cli_session_setup_spnego(cli, user, pass,
+ workgroup, NULL);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
+ return ads_ntstatus(status);
+ }
+ } else {
+ NTSTATUS status;
+
+ /* otherwise do a NT1 style session setup */
+ status = cli_session_setup_nt1(cli, user, pass, passlen,
+ ntpass, ntpasslen, workgroup);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3,("cli_session_setup: NT1 session setup "
+ "failed: %s\n", nt_errstr(status)));
+ return status;
+ }
+ }
+
+ if (strstr(cli->server_type, "Samba")) {
+ cli->is_samba = True;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Send a uloggoff.
+*****************************************************************************/
+
+bool cli_ulogoff(struct cli_state *cli)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ cli_set_message(cli->outbuf,2,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBulogoffX);
+ cli_setup_packet(cli);
+ SSVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ cli->cnum = -1;
+ return True;
+}
+
+/****************************************************************************
+ Send a tconX.
+****************************************************************************/
+
+bool cli_send_tconX(struct cli_state *cli,
+ const char *share, const char *dev, const char *pass, int passlen)
+{
+ fstring fullshare, pword;
+ char *p;
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ fstrcpy(cli->share, share);
+
+ /* in user level security don't send a password now */
+ if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
+ passlen = 1;
+ pass = "";
+ } else if (!pass) {
+ DEBUG(1, ("Server not using user level security and no password supplied.\n"));
+ return False;
+ }
+
+ if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) &&
+ *pass && passlen != 24) {
+ if (!lp_client_lanman_auth()) {
+ DEBUG(1, ("Server requested LANMAN password "
+ "(share-level security) but "
+ "'client lanman auth' is disabled\n"));
+ return False;
+ }
+
+ /*
+ * Non-encrypted passwords - convert to DOS codepage before encryption.
+ */
+ passlen = 24;
+ SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
+ } else {
+ if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
+ if (!lp_client_plaintext_auth() && (*pass)) {
+ DEBUG(1, ("Server requested plaintext "
+ "password but 'client plaintext "
+ "auth' is disabled\n"));
+ return False;
+ }
+
+ /*
+ * Non-encrypted passwords - convert to DOS codepage before using.
+ */
+ passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
+
+ } else {
+ if (passlen) {
+ memcpy(pword, pass, passlen);
+ }
+ }
+ }
+
+ slprintf(fullshare, sizeof(fullshare)-1,
+ "\\\\%s\\%s", cli->desthost, share);
+
+ cli_set_message(cli->outbuf,4, 0, True);
+ SCVAL(cli->outbuf,smb_com,SMBtconX);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,TCONX_FLAG_EXTENDED_RESPONSE);
+ SSVAL(cli->outbuf,smb_vwv3,passlen);
+
+ p = smb_buf(cli->outbuf);
+ if (passlen) {
+ memcpy(p,pword,passlen);
+ }
+ p += passlen;
+ p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
+ p += clistr_push(cli, p, dev, -1, STR_TERMINATE |STR_UPPER | STR_ASCII);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ if (cli_is_error(cli))
+ return False;
+
+ clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
+
+ if (cli->protocol >= PROTOCOL_NT1 &&
+ smb_buflen(cli->inbuf) == 3) {
+ /* almost certainly win95 - enable bug fixes */
+ cli->win95 = True;
+ }
+
+ /* Make sure that we have the optional support 16-bit field. WCT > 2 */
+ /* Avoids issues when connecting to Win9x boxes sharing files */
+
+ cli->dfsroot = False;
+ if ( (CVAL(cli->inbuf, smb_wct))>2 && cli->protocol >= PROTOCOL_LANMAN2 )
+ cli->dfsroot = (SVAL( cli->inbuf, smb_vwv2 ) & SMB_SHARE_IN_DFS) ? True : False;
+
+ cli->cnum = SVAL(cli->inbuf,smb_tid);
+ return True;
+}
+
+/****************************************************************************
+ Send a tree disconnect.
+****************************************************************************/
+
+bool cli_tdis(struct cli_state *cli)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ cli_set_message(cli->outbuf,0,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBtdis);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ cli->cnum = -1;
+ return True;
+}
+
+/****************************************************************************
+ Send a negprot command.
+****************************************************************************/
+
+void cli_negprot_send(struct cli_state *cli)
+{
+ char *p;
+ int numprots;
+
+ if (cli->protocol < PROTOCOL_NT1)
+ cli->use_spnego = False;
+
+ memset(cli->outbuf,'\0',smb_size);
+
+ /* setup the protocol strings */
+ cli_set_message(cli->outbuf,0,0,True);
+
+ p = smb_buf(cli->outbuf);
+ for (numprots=0;
+ prots[numprots].name && prots[numprots].prot<=cli->protocol;
+ numprots++) {
+ *p++ = 2;
+ p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
+ }
+
+ SCVAL(cli->outbuf,smb_com,SMBnegprot);
+ cli_setup_bcc(cli, p);
+ cli_setup_packet(cli);
+
+ SCVAL(smb_buf(cli->outbuf),0,2);
+
+ cli_send_smb(cli);
+}
+
+/****************************************************************************
+ Send a negprot command.
+****************************************************************************/
+
+bool cli_negprot(struct cli_state *cli)
+{
+ char *p;
+ int numprots;
+ int plength;
+
+ if (cli->protocol < PROTOCOL_NT1)
+ cli->use_spnego = False;
+
+ memset(cli->outbuf,'\0',smb_size);
+
+ /* setup the protocol strings */
+ for (plength=0,numprots=0;
+ prots[numprots].name && prots[numprots].prot<=cli->protocol;
+ numprots++)
+ plength += strlen(prots[numprots].name)+2;
+
+ cli_set_message(cli->outbuf,0,plength,True);
+
+ p = smb_buf(cli->outbuf);
+ for (numprots=0;
+ prots[numprots].name && prots[numprots].prot<=cli->protocol;
+ numprots++) {
+ *p++ = 2;
+ p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
+ }
+
+ SCVAL(cli->outbuf,smb_com,SMBnegprot);
+ cli_setup_packet(cli);
+
+ SCVAL(smb_buf(cli->outbuf),0,2);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli) ||
+ ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
+ return(False);
+ }
+
+ cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
+
+ if ((cli->protocol < PROTOCOL_NT1) && cli->sign_info.mandatory_signing) {
+ DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
+ return False;
+ }
+
+ if (cli->protocol >= PROTOCOL_NT1) {
+ struct timespec ts;
+ /* NT protocol */
+ cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
+ cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
+ cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
+ cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
+ cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
+ cli->serverzone *= 60;
+ /* this time arrives in real GMT */
+ ts = interpret_long_date(cli->inbuf+smb_vwv11+1);
+ cli->servertime = ts.tv_sec;
+ cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
+ cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
+ if (cli->capabilities & CAP_RAW_MODE) {
+ cli->readbraw_supported = True;
+ cli->writebraw_supported = True;
+ }
+ /* work out if they sent us a workgroup */
+ if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
+ smb_buflen(cli->inbuf) > 8) {
+ clistr_pull(cli, cli->server_domain,
+ smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
+ smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
+ }
+
+ /*
+ * As signing is slow we only turn it on if either the client or
+ * the server require it. JRA.
+ */
+
+ if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
+ /* Fail if server says signing is mandatory and we don't want to support it. */
+ if (!cli->sign_info.allow_smb_signing) {
+ DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
+ return False;
+ }
+ cli->sign_info.negotiated_smb_signing = True;
+ cli->sign_info.mandatory_signing = True;
+ } else if (cli->sign_info.mandatory_signing && cli->sign_info.allow_smb_signing) {
+ /* Fail if client says signing is mandatory and the server doesn't support it. */
+ if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) {
+ DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
+ return False;
+ }
+ cli->sign_info.negotiated_smb_signing = True;
+ cli->sign_info.mandatory_signing = True;
+ } else if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
+ cli->sign_info.negotiated_smb_signing = True;
+ }
+
+ if (cli->capabilities & (CAP_LARGE_READX|CAP_LARGE_WRITEX)) {
+ SAFE_FREE(cli->outbuf);
+ SAFE_FREE(cli->inbuf);
+ cli->outbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
+ cli->inbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
+ cli->bufsize = CLI_SAMBA_MAX_LARGE_READX_SIZE + LARGE_WRITEX_HDR_SIZE;
+ }
+
+ } else if (cli->protocol >= PROTOCOL_LANMAN1) {
+ cli->use_spnego = False;
+ cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
+ cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
+ cli->max_mux = SVAL(cli->inbuf, smb_vwv3);
+ cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
+ cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
+ cli->serverzone *= 60;
+ /* this time is converted to GMT by make_unix_date */
+ cli->servertime = cli_make_unix_date(cli,cli->inbuf+smb_vwv8);
+ cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
+ cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
+ cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
+ } else {
+ /* the old core protocol */
+ cli->use_spnego = False;
+ cli->sec_mode = 0;
+ cli->serverzone = get_time_zone(time(NULL));
+ }
+
+ cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
+
+ /* a way to force ascii SMB */
+ if (getenv("CLI_FORCE_ASCII"))
+ cli->capabilities &= ~CAP_UNICODE;
+
+ return True;
+}
+
+/****************************************************************************
+ Send a session request. See rfc1002.txt 4.3 and 4.3.2.
+****************************************************************************/
+
+bool cli_session_request(struct cli_state *cli,
+ struct nmb_name *calling, struct nmb_name *called)
+{
+ char *p;
+ int len = 4;
+
+ 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);
+
+ /* 445 doesn't have session request */
+ if (cli->port == 445)
+ return True;
+
+ /* send a session request (RFC 1002) */
+ /* setup the packet length
+ * Remove four bytes from the length count, since the length
+ * field in the NBT Session Service header counts the number
+ * of bytes which follow. The cli_send_smb() function knows
+ * about this and accounts for those four bytes.
+ * CRH.
+ */
+ len -= 4;
+ _smb_setlen(cli->outbuf,len);
+ SCVAL(cli->outbuf,0,0x81);
+
+ cli_send_smb(cli);
+ DEBUG(5,("Sent session request\n"));
+
+ if (!cli_receive_smb(cli))
+ return False;
+
+ if (CVAL(cli->inbuf,0) == 0x84) {
+ /* C. Hoch 9/14/95 Start */
+ /* For information, here is the response structure.
+ * We do the byte-twiddling to for portability.
+ struct RetargetResponse{
+ unsigned char type;
+ unsigned char flags;
+ int16 length;
+ int32 ip_addr;
+ int16 port;
+ };
+ */
+ uint16_t port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
+ struct in_addr dest_ip;
+
+ /* SESSION RETARGET */
+ putip((char *)&dest_ip,cli->inbuf+4);
+ in_addr_to_sockaddr_storage(&cli->dest_ss, dest_ip);
+
+ cli->fd = open_socket_out(SOCK_STREAM,
+ &cli->dest_ss,
+ port,
+ LONG_CONNECT_TIMEOUT);
+ if (cli->fd == -1)
+ return False;
+
+ DEBUG(3,("Retargeted\n"));
+
+ set_socket_options(cli->fd, lp_socket_options());
+
+ /* Try again */
+ {
+ static int depth;
+ bool ret;
+ if (depth > 4) {
+ DEBUG(0,("Retarget recursion - failing\n"));
+ return False;
+ }
+ depth++;
+ ret = cli_session_request(cli, calling, called);
+ depth--;
+ return ret;
+ }
+ } /* C. Hoch 9/14/95 End */
+
+ if (CVAL(cli->inbuf,0) != 0x82) {
+ /* This is the wrong place to put the error... JRA. */
+ cli->rap_error = CVAL(cli->inbuf,4);
+ return False;
+ }
+ return(True);
+}
+
+/****************************************************************************
+ Open the client sockets.
+****************************************************************************/
+
+NTSTATUS cli_connect(struct cli_state *cli,
+ const char *host,
+ struct sockaddr_storage *dest_ss)
+
+{
+ int name_type = 0x20;
+ TALLOC_CTX *frame = talloc_stackframe();
+ unsigned int num_addrs = 0;
+ unsigned int i = 0;
+ struct sockaddr_storage *ss_arr = NULL;
+ char *p = NULL;
+
+ /* reasonable default hostname */
+ if (!host) {
+ host = star_smbserver_name;
+ }
+
+ fstrcpy(cli->desthost, host);
+
+ /* allow hostnames of the form NAME#xx and do a netbios lookup */
+ if ((p = strchr(cli->desthost, '#'))) {
+ name_type = strtol(p+1, NULL, 16);
+ *p = 0;
+ }
+
+ if (!dest_ss || is_zero_addr(dest_ss)) {
+ NTSTATUS status =resolve_name_list(frame,
+ cli->desthost,
+ name_type,
+ &ss_arr,
+ &num_addrs);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_BAD_NETWORK_NAME;
+ }
+ } else {
+ num_addrs = 1;
+ ss_arr = TALLOC_P(frame, struct sockaddr_storage);
+ if (!ss_arr) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+ *ss_arr = *dest_ss;
+ }
+
+ for (i = 0; i < num_addrs; i++) {
+ cli->dest_ss = ss_arr[i];
+ if (getenv("LIBSMB_PROG")) {
+ cli->fd = sock_exec(getenv("LIBSMB_PROG"));
+ } else {
+ /* try 445 first, then 139 */
+ uint16_t port = cli->port?cli->port:445;
+ cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ss,
+ port, cli->timeout);
+ if (cli->fd == -1 && cli->port == 0) {
+ port = 139;
+ cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ss,
+ port, cli->timeout);
+ }
+ if (cli->fd != -1) {
+ cli->port = port;
+ }
+ }
+ if (cli->fd == -1) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr), &ss_arr[i]);
+ DEBUG(2,("Error connecting to %s (%s)\n",
+ dest_ss?addr:host,strerror(errno)));
+ } else {
+ /* Exit from loop on first connection. */
+ break;
+ }
+ }
+
+ if (cli->fd == -1) {
+ TALLOC_FREE(frame);
+ return map_nt_error_from_unix(errno);
+ }
+
+ if (dest_ss) {
+ *dest_ss = cli->dest_ss;
+ }
+
+ set_socket_options(cli->fd, lp_socket_options());
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+/**
+ establishes a connection to after the negprot.
+ @param output_cli A fully initialised cli structure, non-null only on success
+ @param dest_host The netbios name of the remote host
+ @param dest_ss (optional) The the destination IP, NULL for name based lookup
+ @param port (optional) The destination port (0 for default)
+ @param retry bool. Did this connection fail with a retryable error ?
+
+*/
+NTSTATUS cli_start_connection(struct cli_state **output_cli,
+ const char *my_name,
+ const char *dest_host,
+ struct sockaddr_storage *dest_ss, int port,
+ int signing_state, int flags,
+ bool *retry)
+{
+ NTSTATUS nt_status;
+ struct nmb_name calling;
+ struct nmb_name called;
+ struct cli_state *cli;
+ struct sockaddr_storage ss;
+
+ if (retry)
+ *retry = False;
+
+ if (!my_name)
+ my_name = global_myname();
+
+ if (!(cli = cli_initialise())) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ make_nmb_name(&calling, my_name, 0x0);
+ make_nmb_name(&called , dest_host, 0x20);
+
+ if (cli_set_port(cli, port) != port) {
+ cli_shutdown(cli);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ cli_set_timeout(cli, 10000); /* 10 seconds. */
+
+ if (dest_ss) {
+ ss = *dest_ss;
+ } else {
+ zero_addr(&ss);
+ }
+
+again:
+
+ DEBUG(3,("Connecting to host=%s\n", dest_host));
+
+ nt_status = cli_connect(cli, dest_host, &ss);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr), &ss);
+ DEBUG(1,("cli_start_connection: failed to connect to %s (%s). Error %s\n",
+ nmb_namestr(&called), addr, nt_errstr(nt_status) ));
+ cli_shutdown(cli);
+ return nt_status;
+ }
+
+ if (retry)
+ *retry = True;
+
+ if (!cli_session_request(cli, &calling, &called)) {
+ char *p;
+ DEBUG(1,("session request to %s failed (%s)\n",
+ called.name, cli_errstr(cli)));
+ if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
+ *p = 0;
+ goto again;
+ }
+ if (strcmp(called.name, star_smbserver_name)) {
+ make_nmb_name(&called , star_smbserver_name, 0x20);
+ goto again;
+ }
+ return NT_STATUS_BAD_NETWORK_NAME;
+ }
+
+ cli_setup_signing_state(cli, signing_state);
+
+ if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
+ cli->use_spnego = False;
+ else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
+ cli->use_kerberos = True;
+
+ if ((flags & CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS) &&
+ cli->use_kerberos) {
+ cli->fallback_after_kerberos = true;
+ }
+
+ if (!cli_negprot(cli)) {
+ DEBUG(1,("failed negprot\n"));
+ nt_status = cli_nt_error(cli);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ }
+ cli_shutdown(cli);
+ return nt_status;
+ }
+
+ *output_cli = cli;
+ return NT_STATUS_OK;
+}
+
+
+/**
+ establishes a connection right up to doing tconX, password specified.
+ @param output_cli A fully initialised cli structure, non-null only on success
+ @param dest_host The netbios name of the remote host
+ @param dest_ip (optional) The the destination IP, NULL for name based lookup
+ @param port (optional) The destination port (0 for default)
+ @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
+ @param service_type The 'type' of serivice.
+ @param user Username, unix string
+ @param domain User's domain
+ @param password User's password, unencrypted unix string.
+ @param retry bool. Did this connection fail with a retryable error ?
+*/
+
+NTSTATUS cli_full_connection(struct cli_state **output_cli,
+ const char *my_name,
+ const char *dest_host,
+ struct sockaddr_storage *dest_ss, int port,
+ const char *service, const char *service_type,
+ const char *user, const char *domain,
+ const char *password, int flags,
+ int signing_state,
+ bool *retry)
+{
+ NTSTATUS nt_status;
+ struct cli_state *cli = NULL;
+ int pw_len = password ? strlen(password)+1 : 0;
+
+ *output_cli = NULL;
+
+ if (password == NULL) {
+ password = "";
+ }
+
+ nt_status = cli_start_connection(&cli, my_name, dest_host,
+ dest_ss, port, signing_state,
+ flags, retry);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ nt_status = cli_session_setup(cli, user, password, pw_len, password,
+ pw_len, domain);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+
+ if (!(flags & CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK)) {
+ DEBUG(1,("failed session setup with %s\n",
+ nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ return nt_status;
+ }
+
+ nt_status = cli_session_setup(cli, "", "", 0, "", 0, domain);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1,("anonymous failed session setup with %s\n",
+ nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ return nt_status;
+ }
+ }
+
+ if (service) {
+ if (!cli_send_tconX(cli, service, service_type, password, pw_len)) {
+ nt_status = cli_nt_error(cli);
+ DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ }
+ return nt_status;
+ }
+ }
+
+ cli_init_creds(cli, user, domain, password);
+
+ *output_cli = cli;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
+****************************************************************************/
+
+bool attempt_netbios_session_request(struct cli_state **ppcli, const char *srchost, const char *desthost,
+ struct sockaddr_storage *pdest_ss)
+{
+ struct nmb_name calling, called;
+
+ make_nmb_name(&calling, srchost, 0x0);
+
+ /*
+ * If the called name is an IP address
+ * then use *SMBSERVER immediately.
+ */
+
+ if(is_ipaddress(desthost)) {
+ make_nmb_name(&called, star_smbserver_name, 0x20);
+ } else {
+ make_nmb_name(&called, desthost, 0x20);
+ }
+
+ if (!cli_session_request(*ppcli, &calling, &called)) {
+ NTSTATUS status;
+ struct nmb_name smbservername;
+
+ make_nmb_name(&smbservername, star_smbserver_name, 0x20);
+
+ /*
+ * If the name wasn't *SMBSERVER then
+ * try with *SMBSERVER if the first name fails.
+ */
+
+ if (nmb_name_equal(&called, &smbservername)) {
+
+ /*
+ * The name used was *SMBSERVER, don't bother with another name.
+ */
+
+ DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
+with error %s.\n", desthost, cli_errstr(*ppcli) ));
+ return False;
+ }
+
+ /* Try again... */
+ cli_shutdown(*ppcli);
+
+ *ppcli = cli_initialise();
+ if (!*ppcli) {
+ /* Out of memory... */
+ return False;
+ }
+
+ status = cli_connect(*ppcli, desthost, pdest_ss);
+ if (!NT_STATUS_IS_OK(status) ||
+ !cli_session_request(*ppcli, &calling, &smbservername)) {
+ DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
+name *SMBSERVER with error %s\n", desthost, cli_errstr(*ppcli) ));
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Send an old style tcon.
+****************************************************************************/
+NTSTATUS cli_raw_tcon(struct cli_state *cli,
+ const char *service, const char *pass, const char *dev,
+ uint16 *max_xmit, uint16 *tid)
+{
+ char *p;
+
+ if (!lp_client_plaintext_auth() && (*pass)) {
+ DEBUG(1, ("Server requested plaintext password but 'client "
+ "plaintext auth' is disabled\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf, 0, 0, True);
+ SCVAL(cli->outbuf,smb_com,SMBtcon);
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
+ *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
+ *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ }
+
+ if (cli_is_error(cli)) {
+ return cli_nt_error(cli);
+ }
+
+ *max_xmit = SVAL(cli->inbuf, smb_vwv0);
+ *tid = SVAL(cli->inbuf, smb_vwv1);
+
+ return NT_STATUS_OK;
+}
+
+/* Return a cli_state pointing at the IPC$ share for the given server */
+
+struct cli_state *get_ipc_connect(char *server,
+ struct sockaddr_storage *server_ss,
+ const struct user_auth_info *user_info)
+{
+ struct cli_state *cli;
+ NTSTATUS nt_status;
+ uint32_t flags = CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
+
+ if (user_info->use_kerberos) {
+ flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
+ }
+
+ nt_status = cli_full_connection(&cli, NULL, server, server_ss, 0, "IPC$", "IPC",
+ user_info->username ? user_info->username : "",
+ lp_workgroup(),
+ user_info->password ? user_info->password : "",
+ flags,
+ Undefined, NULL);
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ return cli;
+ } else if (is_ipaddress(server)) {
+ /* windows 9* needs a correct NMB name for connections */
+ fstring remote_name;
+
+ if (name_status_find("*", 0, 0, server_ss, remote_name)) {
+ cli = get_ipc_connect(remote_name, server_ss, user_info);
+ if (cli)
+ return cli;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Given the IP address of a master browser on the network, return its
+ * workgroup and connect to it.
+ *
+ * This function is provided to allow additional processing beyond what
+ * get_ipc_connect_master_ip_bcast() does, e.g. to retrieve the list of master
+ * browsers and obtain each master browsers' list of domains (in case the
+ * first master browser is recently on the network and has not yet
+ * synchronized with other master browsers and therefore does not yet have the
+ * entire network browse list)
+ */
+
+struct cli_state *get_ipc_connect_master_ip(TALLOC_CTX *ctx,
+ struct ip_service *mb_ip,
+ const struct user_auth_info *user_info,
+ char **pp_workgroup_out)
+{
+ char addr[INET6_ADDRSTRLEN];
+ fstring name;
+ struct cli_state *cli;
+ struct sockaddr_storage server_ss;
+
+ *pp_workgroup_out = NULL;
+
+ print_sockaddr(addr, sizeof(addr), &mb_ip->ss);
+ DEBUG(99, ("Looking up name of master browser %s\n",
+ addr));
+
+ /*
+ * Do a name status query to find out the name of the master browser.
+ * We use <01><02>__MSBROWSE__<02>#01 if *#00 fails because a domain
+ * master browser will not respond to a wildcard query (or, at least,
+ * an NT4 server acting as the domain master browser will not).
+ *
+ * We might be able to use ONLY the query on MSBROWSE, but that's not
+ * yet been tested with all Windows versions, so until it is, leave
+ * the original wildcard query as the first choice and fall back to
+ * MSBROWSE if the wildcard query fails.
+ */
+ if (!name_status_find("*", 0, 0x1d, &mb_ip->ss, name) &&
+ !name_status_find(MSBROWSE, 1, 0x1d, &mb_ip->ss, name)) {
+
+ DEBUG(99, ("Could not retrieve name status for %s\n",
+ addr));
+ return NULL;
+ }
+
+ if (!find_master_ip(name, &server_ss)) {
+ DEBUG(99, ("Could not find master ip for %s\n", name));
+ return NULL;
+ }
+
+ *pp_workgroup_out = talloc_strdup(ctx, name);
+
+ DEBUG(4, ("found master browser %s, %s\n", name, addr));
+
+ print_sockaddr(addr, sizeof(addr), &server_ss);
+ cli = get_ipc_connect(addr, &server_ss, user_info);
+
+ return cli;
+}
+
+/*
+ * Return the IP address and workgroup of a master browser on the network, and
+ * connect to it.
+ */
+
+struct cli_state *get_ipc_connect_master_ip_bcast(TALLOC_CTX *ctx,
+ const struct user_auth_info *user_info,
+ char **pp_workgroup_out)
+{
+ struct ip_service *ip_list;
+ struct cli_state *cli;
+ int i, count;
+
+ *pp_workgroup_out = NULL;
+
+ DEBUG(99, ("Do broadcast lookup for workgroups on local network\n"));
+
+ /* Go looking for workgroups by broadcasting on the local network */
+
+ if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list,
+ &count))) {
+ DEBUG(99, ("No master browsers responded\n"));
+ return False;
+ }
+
+ for (i = 0; i < count; i++) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
+ DEBUG(99, ("Found master browser %s\n", addr));
+
+ cli = get_ipc_connect_master_ip(ctx, &ip_list[i],
+ user_info, pp_workgroup_out);
+ if (cli)
+ return(cli);
+ }
+
+ return NULL;
+}
diff --git a/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c
new file mode 100644
index 0000000000..7b63f9535e
--- /dev/null
+++ b/source3/libsmb/clidfs.c
@@ -0,0 +1,1125 @@
+/*
+ Unix SMB/CIFS implementation.
+ client connect/disconnect routines
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Gerald (Jerry) Carter 2004
+ Copyright (C) Jeremy Allison 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/********************************************************************
+ Important point.
+
+ DFS paths are *always* of the form \server\share\<pathname> (the \ characters
+ are not C escaped here).
+
+ - but if we're using POSIX paths then <pathname> may contain
+ '/' separators, not '\\' separators. So cope with '\\' or '/'
+ as a separator when looking at the pathname part.... JRA.
+********************************************************************/
+
+struct client_connection {
+ struct client_connection *prev, *next;
+ struct cli_state *cli;
+ char *mount;
+};
+
+/* global state....globals reek! */
+int max_protocol = PROTOCOL_NT1;
+
+static struct cm_cred_struct {
+ char *username;
+ char *password;
+ bool got_pass;
+ bool use_kerberos;
+ bool fallback_after_kerberos;
+ int signing_state;
+} cm_creds;
+
+static void cm_set_password(const char *newpass);
+
+static int port;
+static int name_type = 0x20;
+static bool have_ip;
+static struct sockaddr_storage dest_ss;
+
+static struct client_connection *connections;
+
+static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
+ struct cli_state *cli,
+ const char *sharename,
+ char **pp_newserver,
+ char **pp_newshare,
+ bool force_encrypt,
+ const char *username,
+ const char *password,
+ const char *domain);
+
+/********************************************************************
+ Ensure a connection is encrypted.
+********************************************************************/
+
+NTSTATUS cli_cm_force_encryption(struct cli_state *c,
+ const char *username,
+ const char *password,
+ const char *domain,
+ const char *sharename)
+{
+ NTSTATUS status = cli_force_encryption(c,
+ username,
+ password,
+ domain);
+
+ if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED)) {
+ d_printf("Encryption required and "
+ "server that doesn't support "
+ "UNIX extensions - failing connect\n");
+ } else if (NT_STATUS_EQUAL(status,NT_STATUS_UNKNOWN_REVISION)) {
+ d_printf("Encryption required and "
+ "can't get UNIX CIFS extensions "
+ "version from server.\n");
+ } else if (NT_STATUS_EQUAL(status,NT_STATUS_UNSUPPORTED_COMPRESSION)) {
+ d_printf("Encryption required and "
+ "share %s doesn't support "
+ "encryption.\n", sharename);
+ } else if (!NT_STATUS_IS_OK(status)) {
+ d_printf("Encryption required and "
+ "setup failed with error %s.\n",
+ nt_errstr(status));
+ }
+
+ return status;
+}
+
+/********************************************************************
+ Return a connection to a server.
+********************************************************************/
+
+static struct cli_state *do_connect(TALLOC_CTX *ctx,
+ const char *server,
+ const char *share,
+ bool show_sessetup,
+ bool force_encrypt)
+{
+ struct cli_state *c = NULL;
+ struct nmb_name called, calling;
+ const char *server_n;
+ struct sockaddr_storage ss;
+ char *servicename;
+ char *sharename;
+ char *newserver, *newshare;
+ const char *username;
+ const char *password;
+ NTSTATUS status;
+
+ /* make a copy so we don't modify the global string 'service' */
+ servicename = talloc_strdup(ctx,share);
+ if (!servicename) {
+ return NULL;
+ }
+ sharename = servicename;
+ if (*sharename == '\\') {
+ server = sharename+2;
+ sharename = strchr_m(server,'\\');
+ if (!sharename) {
+ return NULL;
+ }
+ *sharename = 0;
+ sharename++;
+ }
+
+ server_n = server;
+
+ zero_addr(&ss);
+
+ make_nmb_name(&calling, global_myname(), 0x0);
+ make_nmb_name(&called , server, name_type);
+
+ again:
+ zero_addr(&ss);
+ if (have_ip)
+ ss = dest_ss;
+
+ /* have to open a new connection */
+ if (!(c=cli_initialise()) || (cli_set_port(c, port) != port)) {
+ d_printf("Connection to %s failed\n", server_n);
+ if (c) {
+ cli_shutdown(c);
+ }
+ return NULL;
+ }
+ status = cli_connect(c, server_n, &ss);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("Connection to %s failed (Error %s)\n",
+ server_n,
+ nt_errstr(status));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ c->protocol = max_protocol;
+ c->use_kerberos = cm_creds.use_kerberos;
+ c->fallback_after_kerberos = cm_creds.fallback_after_kerberos;
+ cli_setup_signing_state(c, cm_creds.signing_state);
+
+ if (!cli_session_request(c, &calling, &called)) {
+ char *p;
+ d_printf("session request to %s failed (%s)\n",
+ called.name, cli_errstr(c));
+ cli_shutdown(c);
+ c = NULL;
+ if ((p=strchr_m(called.name, '.'))) {
+ *p = 0;
+ goto again;
+ }
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ }
+ return NULL;
+ }
+
+ DEBUG(4,(" session request ok\n"));
+
+ if (!cli_negprot(c)) {
+ d_printf("protocol negotiation failed\n");
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ if (!cm_creds.got_pass && !cm_creds.use_kerberos) {
+ char *label = NULL;
+ char *pass;
+ label = talloc_asprintf(ctx, "Enter %s's password: ",
+ cm_creds.username);
+ pass = getpass(label);
+ if (pass) {
+ cm_set_password(pass);
+ }
+ TALLOC_FREE(label);
+ }
+
+ username = cm_creds.username ? cm_creds.username : "";
+ password = cm_creds.password ? cm_creds.password : "";
+
+ if (!NT_STATUS_IS_OK(cli_session_setup(c, username,
+ password, strlen(password),
+ password, strlen(password),
+ lp_workgroup()))) {
+ /* If a password was not supplied then
+ * try again with a null username. */
+ if (password[0] || !username[0] || cm_creds.use_kerberos ||
+ !NT_STATUS_IS_OK(cli_session_setup(c, "",
+ "", 0,
+ "", 0,
+ lp_workgroup()))) {
+ d_printf("session setup failed: %s\n", cli_errstr(c));
+ if (NT_STATUS_V(cli_nt_error(c)) ==
+ NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED))
+ d_printf("did you forget to run kinit?\n");
+ cli_shutdown(c);
+ return NULL;
+ }
+ d_printf("Anonymous login successful\n");
+ }
+
+ if ( show_sessetup ) {
+ if (*c->server_domain) {
+ DEBUG(0,("Domain=[%s] OS=[%s] Server=[%s]\n",
+ c->server_domain,c->server_os,c->server_type));
+ } else if (*c->server_os || *c->server_type) {
+ DEBUG(0,("OS=[%s] Server=[%s]\n",
+ c->server_os,c->server_type));
+ }
+ }
+ DEBUG(4,(" session setup ok\n"));
+
+ /* here's the fun part....to support 'msdfs proxy' shares
+ (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL
+ here before trying to connect to the original share.
+ check_dfs_proxy() will fail if it is a normal share. */
+
+ if ((c->capabilities & CAP_DFS) &&
+ cli_check_msdfs_proxy(ctx, c, sharename,
+ &newserver, &newshare,
+ force_encrypt,
+ username,
+ password,
+ lp_workgroup())) {
+ cli_shutdown(c);
+ return do_connect(ctx, newserver,
+ newshare, false, force_encrypt);
+ }
+
+ /* must be a normal share */
+
+ if (!cli_send_tconX(c, sharename, "?????",
+ password, strlen(password)+1)) {
+ d_printf("tree connect failed: %s\n", cli_errstr(c));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ if (force_encrypt) {
+ status = cli_cm_force_encryption(c,
+ username,
+ password,
+ lp_workgroup(),
+ sharename);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_shutdown(c);
+ return NULL;
+ }
+ }
+
+ DEBUG(4,(" tconx ok\n"));
+ return c;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void cli_cm_set_mntpoint(struct cli_state *c, const char *mnt)
+{
+ struct client_connection *p;
+ int i;
+
+ for (p=connections,i=0; p; p=p->next,i++) {
+ if (strequal(p->cli->desthost, c->desthost) &&
+ strequal(p->cli->share, c->share)) {
+ break;
+ }
+ }
+
+ if (p) {
+ char *name = clean_name(NULL, p->mount);
+ if (!name) {
+ return;
+ }
+ p->mount = talloc_strdup(p, name);
+ TALLOC_FREE(name);
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+const char *cli_cm_get_mntpoint(struct cli_state *c)
+{
+ struct client_connection *p;
+ int i;
+
+ for (p=connections,i=0; p; p=p->next,i++) {
+ if (strequal(p->cli->desthost, c->desthost) &&
+ strequal(p->cli->share, c->share)) {
+ break;
+ }
+ }
+
+ if (p) {
+ return p->mount;
+ }
+ return NULL;
+}
+
+/********************************************************************
+ Add a new connection to the list
+********************************************************************/
+
+static struct cli_state *cli_cm_connect(TALLOC_CTX *ctx,
+ struct cli_state *referring_cli,
+ const char *server,
+ const char *share,
+ bool show_hdr,
+ bool force_encrypt)
+{
+ struct client_connection *node;
+
+ /* NB This must be the null context here... JRA. */
+ node = TALLOC_ZERO_ARRAY(NULL, struct client_connection, 1);
+ if (!node) {
+ return NULL;
+ }
+
+ node->cli = do_connect(ctx, server, share, show_hdr, force_encrypt);
+
+ if ( !node->cli ) {
+ TALLOC_FREE( node );
+ return NULL;
+ }
+
+ DLIST_ADD( connections, node );
+
+ cli_cm_set_mntpoint(node->cli, "");
+
+ if (referring_cli && referring_cli->posix_capabilities) {
+ uint16 major, minor;
+ uint32 caplow, caphigh;
+ if (cli_unix_extensions_version(node->cli, &major,
+ &minor, &caplow, &caphigh)) {
+ cli_set_unix_extensions_capabilities(node->cli,
+ major, minor,
+ caplow, caphigh);
+ }
+ }
+
+ return node->cli;
+}
+
+/********************************************************************
+ Return a connection to a server.
+********************************************************************/
+
+static struct cli_state *cli_cm_find(const char *server, const char *share)
+{
+ struct client_connection *p;
+
+ for (p=connections; p; p=p->next) {
+ if ( strequal(server, p->cli->desthost) &&
+ strequal(share,p->cli->share)) {
+ return p->cli;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Open a client connection to a \\server\share. Set's the current *cli
+ global variable as a side-effect (but only if the connection is successful).
+****************************************************************************/
+
+struct cli_state *cli_cm_open(TALLOC_CTX *ctx,
+ struct cli_state *referring_cli,
+ const char *server,
+ const char *share,
+ bool show_hdr,
+ bool force_encrypt)
+{
+ struct cli_state *c;
+
+ /* try to reuse an existing connection */
+
+ c = cli_cm_find(server, share);
+ if (!c) {
+ c = cli_cm_connect(ctx, referring_cli,
+ server, share, show_hdr, force_encrypt);
+ }
+
+ return c;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_shutdown(void)
+{
+ struct client_connection *p, *x;
+
+ for (p=connections; p;) {
+ cli_shutdown(p->cli);
+ x = p;
+ p = p->next;
+
+ TALLOC_FREE(x);
+ }
+
+ connections = NULL;
+ return;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_display(void)
+{
+ struct client_connection *p;
+ int i;
+
+ for ( p=connections,i=0; p; p=p->next,i++ ) {
+ d_printf("%d:\tserver=%s, share=%s\n",
+ i, p->cli->desthost, p->cli->share );
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void cm_set_password(const char *newpass)
+{
+ SAFE_FREE(cm_creds.password);
+ cm_creds.password = SMB_STRDUP(newpass);
+ if (cm_creds.password) {
+ cm_creds.got_pass = true;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_set_credentials(void)
+{
+ SAFE_FREE(cm_creds.username);
+ cm_creds.username = SMB_STRDUP(get_cmdline_auth_info_username());
+
+ if (get_cmdline_auth_info_got_pass()) {
+ cm_set_password(get_cmdline_auth_info_password());
+ }
+
+ cm_creds.use_kerberos = get_cmdline_auth_info_use_kerberos();
+ cm_creds.fallback_after_kerberos = false;
+ cm_creds.signing_state = get_cmdline_auth_info_signing_state();
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_set_port(int port_number)
+{
+ port = port_number;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_set_dest_name_type(int type)
+{
+ name_type = type;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_set_signing_state(int state)
+{
+ cm_creds.signing_state = state;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_set_username(const char *username)
+{
+ SAFE_FREE(cm_creds.username);
+ cm_creds.username = SMB_STRDUP(username);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_set_password(const char *newpass)
+{
+ SAFE_FREE(cm_creds.password);
+ cm_creds.password = SMB_STRDUP(newpass);
+ if (cm_creds.password) {
+ cm_creds.got_pass = true;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_set_use_kerberos(void)
+{
+ cm_creds.use_kerberos = true;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_set_fallback_after_kerberos(void)
+{
+ cm_creds.fallback_after_kerberos = true;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_set_dest_ss(struct sockaddr_storage *pss)
+{
+ dest_ss = *pss;
+ have_ip = true;
+}
+
+/**********************************************************************
+ split a dfs path into the server, share name, and extrapath components
+**********************************************************************/
+
+static void split_dfs_path(TALLOC_CTX *ctx,
+ const char *nodepath,
+ char **pp_server,
+ char **pp_share,
+ char **pp_extrapath)
+{
+ char *p, *q;
+ char *path;
+
+ *pp_server = NULL;
+ *pp_share = NULL;
+ *pp_extrapath = NULL;
+
+ path = talloc_strdup(ctx, nodepath);
+ if (!path) {
+ return;
+ }
+
+ if ( path[0] != '\\' ) {
+ return;
+ }
+
+ p = strchr_m( path + 1, '\\' );
+ if ( !p ) {
+ return;
+ }
+
+ *p = '\0';
+ p++;
+
+ /* Look for any extra/deep path */
+ q = strchr_m(p, '\\');
+ if (q != NULL) {
+ *q = '\0';
+ q++;
+ *pp_extrapath = talloc_strdup(ctx, q);
+ } else {
+ *pp_extrapath = talloc_strdup(ctx, "");
+ }
+
+ *pp_share = talloc_strdup(ctx, p);
+ *pp_server = talloc_strdup(ctx, &path[1]);
+}
+
+/****************************************************************************
+ Return the original path truncated at the directory component before
+ the first wildcard character. Trust the caller to provide a NULL
+ terminated string
+****************************************************************************/
+
+static char *clean_path(TALLOC_CTX *ctx, const char *path)
+{
+ size_t len;
+ char *p1, *p2, *p;
+ char *path_out;
+
+ /* No absolute paths. */
+ while (IS_DIRECTORY_SEP(*path)) {
+ path++;
+ }
+
+ path_out = talloc_strdup(ctx, path);
+ if (!path_out) {
+ return NULL;
+ }
+
+ p1 = strchr_m(path_out, '*');
+ p2 = strchr_m(path_out, '?');
+
+ if (p1 || p2) {
+ if (p1 && p2) {
+ p = MIN(p1,p2);
+ } else if (!p1) {
+ p = p2;
+ } else {
+ p = p1;
+ }
+ *p = '\0';
+
+ /* Now go back to the start of this component. */
+ p1 = strrchr_m(path_out, '/');
+ p2 = strrchr_m(path_out, '\\');
+ p = MAX(p1,p2);
+ if (p) {
+ *p = '\0';
+ }
+ }
+
+ /* Strip any trailing separator */
+
+ len = strlen(path_out);
+ if ( (len > 0) && IS_DIRECTORY_SEP(path_out[len-1])) {
+ path_out[len-1] = '\0';
+ }
+
+ return path_out;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static char *cli_dfs_make_full_path(TALLOC_CTX *ctx,
+ struct cli_state *cli,
+ const char *dir)
+{
+ /* Ensure the extrapath doesn't start with a separator. */
+ while (IS_DIRECTORY_SEP(*dir)) {
+ dir++;
+ }
+
+ return talloc_asprintf(ctx, "\\%s\\%s\\%s",
+ cli->desthost, cli->share, dir);
+}
+
+/********************************************************************
+ check for dfs referral
+********************************************************************/
+
+static bool cli_dfs_check_error( struct cli_state *cli, NTSTATUS status )
+{
+ uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
+
+ /* only deal with DS when we negotiated NT_STATUS codes and UNICODE */
+
+ if (!((flgs2&FLAGS2_32_BIT_ERROR_CODES) &&
+ (flgs2&FLAGS2_UNICODE_STRINGS)))
+ return false;
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS(IVAL(cli->inbuf,smb_rcls))))
+ return true;
+
+ return false;
+}
+
+/********************************************************************
+ Get the dfs referral link.
+********************************************************************/
+
+bool cli_dfs_get_referral(TALLOC_CTX *ctx,
+ struct cli_state *cli,
+ const char *path,
+ CLIENT_DFS_REFERRAL**refs,
+ size_t *num_refs,
+ uint16 *consumed)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ uint16 setup = TRANSACT2_GET_DFS_REFERRAL;
+ char *param;
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+ char *endp;
+ size_t pathlen = 2*(strlen(path)+1);
+ uint16 num_referrals;
+ CLIENT_DFS_REFERRAL *referrals = NULL;
+ bool ret = false;
+
+ *num_refs = 0;
+ *refs = NULL;
+
+ param = SMB_MALLOC_ARRAY(char, 2+pathlen+2);
+ if (!param) {
+ return false;
+ }
+ SSVAL(param, 0, 0x03); /* max referral level */
+ p = &param[2];
+
+ p += clistr_push(cli, p, path, pathlen, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ NULL, 0, cli->max_xmit /* data, length, max */
+ )) {
+ SAFE_FREE(param);
+ return false;
+ }
+
+ SAFE_FREE(param);
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return false;
+ }
+
+ if (data_len < 4) {
+ goto out;
+ }
+
+ endp = rdata + data_len;
+
+ *consumed = SVAL(rdata, 0);
+ num_referrals = SVAL(rdata, 2);
+
+ if (num_referrals != 0) {
+ uint16 ref_version;
+ uint16 ref_size;
+ int i;
+ uint16 node_offset;
+
+ referrals = TALLOC_ARRAY(ctx, CLIENT_DFS_REFERRAL,
+ num_referrals);
+
+ if (!referrals) {
+ goto out;
+ }
+ /* start at the referrals array */
+
+ p = rdata+8;
+ for (i=0; i<num_referrals && p < endp; i++) {
+ if (p + 18 > endp) {
+ goto out;
+ }
+ ref_version = SVAL(p, 0);
+ ref_size = SVAL(p, 2);
+ node_offset = SVAL(p, 16);
+
+ if (ref_version != 3) {
+ p += ref_size;
+ continue;
+ }
+
+ referrals[i].proximity = SVAL(p, 8);
+ referrals[i].ttl = SVAL(p, 10);
+
+ if (p + node_offset > endp) {
+ goto out;
+ }
+ clistr_pull_talloc(ctx, cli, &referrals[i].dfspath,
+ p+node_offset, -1,
+ STR_TERMINATE|STR_UNICODE );
+
+ if (!referrals[i].dfspath) {
+ goto out;
+ }
+ p += ref_size;
+ }
+ if (i < num_referrals) {
+ goto out;
+ }
+ }
+
+ ret = true;
+
+ *num_refs = num_referrals;
+ *refs = referrals;
+
+ out:
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return ret;
+}
+
+/********************************************************************
+********************************************************************/
+
+bool cli_resolve_path(TALLOC_CTX *ctx,
+ const char *mountpt,
+ struct cli_state *rootcli,
+ const char *path,
+ struct cli_state **targetcli,
+ char **pp_targetpath)
+{
+ CLIENT_DFS_REFERRAL *refs = NULL;
+ size_t num_refs = 0;
+ uint16 consumed;
+ struct cli_state *cli_ipc = NULL;
+ char *dfs_path = NULL;
+ char *cleanpath = NULL;
+ char *extrapath = NULL;
+ int pathlen;
+ char *server = NULL;
+ char *share = NULL;
+ struct cli_state *newcli = NULL;
+ char *newpath = NULL;
+ char *newmount = NULL;
+ char *ppath = NULL;
+ SMB_STRUCT_STAT sbuf;
+ uint32 attributes;
+
+ if ( !rootcli || !path || !targetcli ) {
+ return false;
+ }
+
+ /* Don't do anything if this is not a DFS root. */
+
+ if ( !rootcli->dfsroot) {
+ *targetcli = rootcli;
+ *pp_targetpath = talloc_strdup(ctx, path);
+ if (!*pp_targetpath) {
+ return false;
+ }
+ return true;
+ }
+
+ *targetcli = NULL;
+
+ /* Send a trans2_query_path_info to check for a referral. */
+
+ cleanpath = clean_path(ctx, path);
+ if (!cleanpath) {
+ return false;
+ }
+
+ dfs_path = cli_dfs_make_full_path(ctx, rootcli, cleanpath);
+ if (!dfs_path) {
+ return false;
+ }
+
+ if (cli_qpathinfo_basic( rootcli, dfs_path, &sbuf, &attributes)) {
+ /* This is an ordinary path, just return it. */
+ *targetcli = rootcli;
+ *pp_targetpath = talloc_strdup(ctx, path);
+ if (!*pp_targetpath) {
+ return false;
+ }
+ goto done;
+ }
+
+ /* Special case where client asked for a path that does not exist */
+
+ if (cli_dfs_check_error(rootcli, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ *targetcli = rootcli;
+ *pp_targetpath = talloc_strdup(ctx, path);
+ if (!*pp_targetpath) {
+ return false;
+ }
+ goto done;
+ }
+
+ /* We got an error, check for DFS referral. */
+
+ if (!cli_dfs_check_error(rootcli, NT_STATUS_PATH_NOT_COVERED)) {
+ return false;
+ }
+
+ /* Check for the referral. */
+
+ if (!(cli_ipc = cli_cm_open(ctx, rootcli,
+ rootcli->desthost,
+ "IPC$", false,
+ (rootcli->trans_enc_state != NULL)))) {
+ return false;
+ }
+
+ if (!cli_dfs_get_referral(ctx, cli_ipc, dfs_path, &refs,
+ &num_refs, &consumed) || !num_refs) {
+ return false;
+ }
+
+ /* Just store the first referral for now. */
+
+ if (!refs[0].dfspath) {
+ return false;
+ }
+ split_dfs_path(ctx, refs[0].dfspath, &server, &share, &extrapath );
+
+ if (!server || !share) {
+ return false;
+ }
+
+ /* Make sure to recreate the original string including any wildcards. */
+
+ dfs_path = cli_dfs_make_full_path(ctx, rootcli, path);
+ if (!dfs_path) {
+ return false;
+ }
+ pathlen = strlen(dfs_path)*2;
+ consumed = MIN(pathlen, consumed);
+ *pp_targetpath = talloc_strdup(ctx, &dfs_path[consumed/2]);
+ if (!*pp_targetpath) {
+ return false;
+ }
+ dfs_path[consumed/2] = '\0';
+
+ /*
+ * *pp_targetpath is now the unconsumed part of the path.
+ * dfs_path is now the consumed part of the path
+ * (in \server\share\path format).
+ */
+
+ /* Open the connection to the target server & share */
+ if ((*targetcli = cli_cm_open(ctx, rootcli,
+ server,
+ share,
+ false,
+ (rootcli->trans_enc_state != NULL))) == NULL) {
+ d_printf("Unable to follow dfs referral [\\%s\\%s]\n",
+ server, share );
+ return false;
+ }
+
+ if (extrapath && strlen(extrapath) > 0) {
+ *pp_targetpath = talloc_asprintf(ctx,
+ "%s%s",
+ extrapath,
+ *pp_targetpath);
+ if (!*pp_targetpath) {
+ return false;
+ }
+ }
+
+ /* parse out the consumed mount path */
+ /* trim off the \server\share\ */
+
+ ppath = dfs_path;
+
+ if (*ppath != '\\') {
+ d_printf("cli_resolve_path: "
+ "dfs_path (%s) not in correct format.\n",
+ dfs_path );
+ return false;
+ }
+
+ ppath++; /* Now pointing at start of server name. */
+
+ if ((ppath = strchr_m( dfs_path, '\\' )) == NULL) {
+ return false;
+ }
+
+ ppath++; /* Now pointing at start of share name. */
+
+ if ((ppath = strchr_m( ppath+1, '\\' )) == NULL) {
+ return false;
+ }
+
+ ppath++; /* Now pointing at path component. */
+
+ newmount = talloc_asprintf(ctx, "%s\\%s", mountpt, ppath );
+ if (!newmount) {
+ return false;
+ }
+
+ cli_cm_set_mntpoint(*targetcli, newmount);
+
+ /* Check for another dfs referral, note that we are not
+ checking for loops here. */
+
+ if (!strequal(*pp_targetpath, "\\") && !strequal(*pp_targetpath, "/")) {
+ if (cli_resolve_path(ctx,
+ newmount,
+ *targetcli,
+ *pp_targetpath,
+ &newcli,
+ &newpath)) {
+ /*
+ * When cli_resolve_path returns true here it's always
+ * returning the complete path in newpath, so we're done
+ * here.
+ */
+ *targetcli = newcli;
+ *pp_targetpath = newpath;
+ return true;
+ }
+ }
+
+ done:
+
+ /* If returning true ensure we return a dfs root full path. */
+ if ((*targetcli)->dfsroot) {
+ dfs_path = talloc_strdup(ctx, *pp_targetpath);
+ if (!dfs_path) {
+ return false;
+ }
+ *pp_targetpath = cli_dfs_make_full_path(ctx, *targetcli, dfs_path);
+ }
+
+ return true;
+}
+
+/********************************************************************
+********************************************************************/
+
+static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
+ struct cli_state *cli,
+ const char *sharename,
+ char **pp_newserver,
+ char **pp_newshare,
+ bool force_encrypt,
+ const char *username,
+ const char *password,
+ const char *domain)
+{
+ CLIENT_DFS_REFERRAL *refs = NULL;
+ size_t num_refs = 0;
+ uint16 consumed;
+ char *fullpath = NULL;
+ bool res;
+ uint16 cnum;
+ char *newextrapath = NULL;
+
+ if (!cli || !sharename) {
+ return false;
+ }
+
+ cnum = cli->cnum;
+
+ /* special case. never check for a referral on the IPC$ share */
+
+ if (strequal(sharename, "IPC$")) {
+ return false;
+ }
+
+ /* send a trans2_query_path_info to check for a referral */
+
+ fullpath = talloc_asprintf(ctx, "\\%s\\%s", cli->desthost, sharename );
+ if (!fullpath) {
+ return false;
+ }
+
+ /* check for the referral */
+
+ if (!cli_send_tconX(cli, "IPC$", "IPC", NULL, 0)) {
+ return false;
+ }
+
+ if (force_encrypt) {
+ NTSTATUS status = cli_cm_force_encryption(cli,
+ username,
+ password,
+ lp_workgroup(),
+ "IPC$");
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ }
+
+ res = cli_dfs_get_referral(ctx, cli, fullpath, &refs, &num_refs, &consumed);
+
+ if (!cli_tdis(cli)) {
+ return false;
+ }
+
+ cli->cnum = cnum;
+
+ if (!res || !num_refs) {
+ return false;
+ }
+
+ if (!refs[0].dfspath) {
+ return false;
+ }
+
+ split_dfs_path(ctx, refs[0].dfspath, pp_newserver,
+ pp_newshare, &newextrapath );
+
+ if ((*pp_newserver == NULL) || (*pp_newshare == NULL)) {
+ return false;
+ }
+
+ /* check that this is not a self-referral */
+
+ if (strequal(cli->desthost, *pp_newserver) &&
+ strequal(sharename, *pp_newshare)) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/source3/libsmb/clidgram.c b/source3/libsmb/clidgram.c
new file mode 100644
index 0000000000..8b35a69def
--- /dev/null
+++ b/source3/libsmb/clidgram.c
@@ -0,0 +1,357 @@
+/*
+ Unix SMB/CIFS implementation.
+ client dgram calls
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Richard Sharpe 2001
+ Copyright (C) John Terpstra 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*
+ * cli_send_mailslot, send a mailslot for client code ...
+ */
+
+bool cli_send_mailslot(struct messaging_context *msg_ctx,
+ bool unique, const char *mailslot,
+ uint16 priority,
+ char *buf, int len,
+ const char *srcname, int src_type,
+ const char *dstname, int dest_type,
+ const struct sockaddr_storage *dest_ss)
+{
+ struct packet_struct p;
+ struct dgram_packet *dgram = &p.packet.dgram;
+ char *ptr, *p2;
+ char tmp[4];
+ pid_t nmbd_pid;
+ char addr[INET6_ADDRSTRLEN];
+
+ if ((nmbd_pid = pidfile_pid("nmbd")) == 0) {
+ DEBUG(3, ("No nmbd found\n"));
+ return False;
+ }
+
+ if (dest_ss->ss_family != AF_INET) {
+ DEBUG(3, ("cli_send_mailslot: can't send to IPv6 address.\n"));
+ return false;
+ }
+
+ memset((char *)&p, '\0', sizeof(p));
+
+ /*
+ * Next, build the DGRAM ...
+ */
+
+ /* DIRECT GROUP or UNIQUE datagram. */
+ dgram->header.msg_type = unique ? 0x10 : 0x11;
+ dgram->header.flags.node_type = M_NODE;
+ dgram->header.flags.first = True;
+ dgram->header.flags.more = False;
+ dgram->header.dgm_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) +
+ ((unsigned)sys_getpid()%(unsigned)100);
+ /* source ip is filled by nmbd */
+ dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
+ dgram->header.packet_offset = 0;
+
+ make_nmb_name(&dgram->source_name,srcname,src_type);
+ make_nmb_name(&dgram->dest_name,dstname,dest_type);
+
+ ptr = &dgram->data[0];
+
+ /* Setup the smb part. */
+ ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
+ memcpy(tmp,ptr,4);
+
+ if (smb_size + 17*2 + strlen(mailslot) + 1 + len > MAX_DGRAM_SIZE) {
+ DEBUG(0, ("cli_send_mailslot: Cannot write beyond end of packet\n"));
+ return False;
+ }
+
+ cli_set_message(ptr,17,strlen(mailslot) + 1 + len,True);
+ memcpy(ptr,tmp,4);
+
+ SCVAL(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,priority);
+ SSVAL(ptr,smb_vwv16,2);
+ p2 = smb_buf(ptr);
+ fstrcpy(p2,mailslot);
+ p2 = skip_string(ptr,MAX_DGRAM_SIZE,p2);
+ if (!p2) {
+ return False;
+ }
+
+ memcpy(p2,buf,len);
+ p2 += len;
+
+ dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
+
+ p.packet_type = DGRAM_PACKET;
+ p.ip = ((const struct sockaddr_in *)dest_ss)->sin_addr;
+ p.timestamp = time(NULL);
+
+ DEBUG(4,("send_mailslot: Sending to mailslot %s from %s ",
+ mailslot, nmb_namestr(&dgram->source_name)));
+ print_sockaddr(addr, sizeof(addr), dest_ss);
+
+ DEBUGADD(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name), addr));
+
+ return NT_STATUS_IS_OK(messaging_send_buf(msg_ctx,
+ pid_to_procid(nmbd_pid),
+ MSG_SEND_PACKET,
+ (uint8 *)&p, sizeof(p)));
+}
+
+static const char *mailslot_name(TALLOC_CTX *mem_ctx, struct in_addr dc_ip)
+{
+ return talloc_asprintf(mem_ctx, "%s%X",
+ NBT_MAILSLOT_GETDC, dc_ip.s_addr);
+}
+
+bool send_getdc_request(TALLOC_CTX *mem_ctx,
+ struct messaging_context *msg_ctx,
+ struct sockaddr_storage *dc_ss,
+ const char *domain_name,
+ const DOM_SID *sid,
+ uint32_t nt_version)
+{
+ struct in_addr dc_ip;
+ const char *my_acct_name = NULL;
+ const char *my_mailslot = NULL;
+ struct nbt_ntlogon_packet packet;
+ struct nbt_ntlogon_sam_logon *s;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct dom_sid my_sid;
+
+ ZERO_STRUCT(packet);
+ ZERO_STRUCT(my_sid);
+
+ if (dc_ss->ss_family != AF_INET) {
+ return false;
+ }
+
+ if (sid) {
+ my_sid = *sid;
+ }
+
+ dc_ip = ((struct sockaddr_in *)dc_ss)->sin_addr;
+ my_mailslot = mailslot_name(mem_ctx, dc_ip);
+ if (!my_mailslot) {
+ return false;
+ }
+
+ my_acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
+ if (!my_acct_name) {
+ return false;
+ }
+
+ packet.command = NTLOGON_SAM_LOGON;
+ s = &packet.req.logon;
+
+ s->request_count = 0;
+ s->computer_name = global_myname();
+ s->user_name = my_acct_name;
+ s->mailslot_name = my_mailslot;
+ s->acct_control = ACB_WSTRUST;
+ s->sid = my_sid;
+ s->nt_version = nt_version;
+ s->lmnt_token = 0xffff;
+ s->lm20_token = 0xffff;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(nbt_ntlogon_packet, &packet);
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &packet,
+ (ndr_push_flags_fn_t)ndr_push_nbt_ntlogon_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+
+ return cli_send_mailslot(msg_ctx,
+ false, NBT_MAILSLOT_NTLOGON, 0,
+ (char *)blob.data, blob.length,
+ global_myname(), 0, domain_name, 0x1c,
+ dc_ss);
+}
+
+bool receive_getdc_response(TALLOC_CTX *mem_ctx,
+ struct sockaddr_storage *dc_ss,
+ const char *domain_name,
+ uint32_t *nt_version,
+ const char **dc_name,
+ union nbt_cldap_netlogon **reply)
+{
+ struct packet_struct *packet;
+ const char *my_mailslot = NULL;
+ struct in_addr dc_ip;
+ DATA_BLOB blob;
+ union nbt_cldap_netlogon r;
+ union dgram_message_body p;
+ enum ndr_err_code ndr_err;
+
+ const char *returned_dc = NULL;
+ const char *returned_domain = NULL;
+
+ if (dc_ss->ss_family != AF_INET) {
+ return false;
+ }
+
+ dc_ip = ((struct sockaddr_in *)dc_ss)->sin_addr;
+
+ my_mailslot = mailslot_name(mem_ctx, dc_ip);
+ if (!my_mailslot) {
+ return false;
+ }
+
+ packet = receive_unexpected(DGRAM_PACKET, 0, my_mailslot);
+
+ if (packet == NULL) {
+ DEBUG(5, ("Did not receive packet for %s\n", my_mailslot));
+ return False;
+ }
+
+ DEBUG(5, ("Received packet for %s\n", my_mailslot));
+
+ blob = data_blob_const(packet->packet.dgram.data,
+ packet->packet.dgram.datasize);
+
+ if (blob.length < 4) {
+ DEBUG(0,("invalid length: %d\n", (int)blob.length));
+ return false;
+ }
+
+ if (RIVAL(blob.data,0) != DGRAM_SMB) {
+ DEBUG(0,("invalid packet\n"));
+ return false;
+ }
+
+ blob.data += 4;
+ blob.length -= 4;
+
+ ndr_err = ndr_pull_union_blob_all(&blob, mem_ctx, &p, DGRAM_SMB,
+ (ndr_pull_flags_fn_t)ndr_pull_dgram_smb_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0,("failed to parse packet\n"));
+ return false;
+ }
+
+ if (p.smb.smb_command != SMB_TRANSACTION) {
+ DEBUG(0,("invalid smb_command: %d\n", p.smb.smb_command));
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(dgram_smb_packet, &p);
+ }
+
+ blob = p.smb.body.trans.data;
+
+ if (!pull_mailslot_cldap_reply(mem_ctx, &blob,
+ &r, nt_version))
+ {
+ return false;
+ }
+
+ switch (*nt_version) {
+ case 1:
+ case 16:
+ case 17:
+
+ returned_domain = r.logon1.domain_name;
+ returned_dc = r.logon1.pdc_name;
+ break;
+ case 2:
+ case 3:
+ case 18:
+ case 19:
+ returned_domain = r.logon3.domain_name;
+ returned_dc = r.logon3.pdc_name;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ returned_domain = r.logon5.domain;
+ returned_dc = r.logon5.pdc_name;
+ break;
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ returned_domain = r.logon13.domain;
+ returned_dc = r.logon13.pdc_name;
+ break;
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ returned_domain = r.logon15.domain;
+ returned_dc = r.logon15.pdc_name;
+ break;
+ case 29:
+ case 30:
+ case 31:
+ returned_domain = r.logon29.domain;
+ returned_dc = r.logon29.pdc_name;
+ break;
+ default:
+ return false;
+ }
+
+ if (!strequal(returned_domain, domain_name)) {
+ DEBUG(3, ("GetDC: Expected domain %s, got %s\n",
+ domain_name, returned_domain));
+ return false;
+ }
+
+ *dc_name = talloc_strdup(mem_ctx, returned_dc);
+ if (!*dc_name) {
+ return false;
+ }
+
+ if (**dc_name == '\\') *dc_name += 1;
+ if (**dc_name == '\\') *dc_name += 1;
+
+ if (reply) {
+ *reply = (union nbt_cldap_netlogon *)talloc_memdup(
+ mem_ctx, &r, sizeof(union nbt_cldap_netlogon));
+ if (!*reply) {
+ return false;
+ }
+ }
+
+ DEBUG(10, ("GetDC gave name %s for domain %s\n",
+ *dc_name, returned_domain));
+
+ return True;
+}
+
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c
new file mode 100644
index 0000000000..9d65fb4e94
--- /dev/null
+++ b/source3/libsmb/clientgen.c
@@ -0,0 +1,789 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client generic functions
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Jeremy Allison 2007.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*******************************************************************
+ Setup the word count and byte count for a client smb message.
+********************************************************************/
+
+int cli_set_message(char *buf,int num_words,int num_bytes,bool zero)
+{
+ if (zero && (num_words || num_bytes)) {
+ memset(buf + smb_size,'\0',num_words*2 + num_bytes);
+ }
+ SCVAL(buf,smb_wct,num_words);
+ SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
+ smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
+ return (smb_size + num_words*2 + num_bytes);
+}
+
+/****************************************************************************
+ Change the timeout (in milliseconds).
+****************************************************************************/
+
+unsigned int cli_set_timeout(struct cli_state *cli, unsigned int timeout)
+{
+ unsigned int old_timeout = cli->timeout;
+ cli->timeout = timeout;
+ return old_timeout;
+}
+
+/****************************************************************************
+ Change the port number used to call on.
+****************************************************************************/
+
+int cli_set_port(struct cli_state *cli, int port)
+{
+ cli->port = port;
+ return port;
+}
+
+/****************************************************************************
+ Read an smb from a fd ignoring all keepalive packets.
+ 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.
+****************************************************************************/
+
+static ssize_t client_receive_smb(struct cli_state *cli, size_t maxlen)
+{
+ size_t len;
+
+ for(;;) {
+ NTSTATUS status;
+
+ set_smb_read_error(&cli->smb_rw_error, SMB_READ_OK);
+
+ status = receive_smb_raw(cli->fd, cli->inbuf, cli->bufsize,
+ cli->timeout, maxlen, &len);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("client_receive_smb failed\n"));
+ show_msg(cli->inbuf);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
+ set_smb_read_error(&cli->smb_rw_error,
+ SMB_READ_EOF);
+ return -1;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ set_smb_read_error(&cli->smb_rw_error,
+ SMB_READ_TIMEOUT);
+ return -1;
+ }
+
+ set_smb_read_error(&cli->smb_rw_error, SMB_READ_ERROR);
+ return -1;
+ }
+
+ /*
+ * I don't believe len can be < 0 with NT_STATUS_OK
+ * returned above, but this check doesn't hurt. JRA.
+ */
+
+ if ((ssize_t)len < 0) {
+ return len;
+ }
+
+ /* Ignore session keepalive packets. */
+ if(CVAL(cli->inbuf,0) != SMBkeepalive) {
+ break;
+ }
+ }
+
+ if (cli_encryption_on(cli)) {
+ NTSTATUS status = cli_decrypt_message(cli);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("SMB decryption failed on incoming packet! Error %s\n",
+ nt_errstr(status)));
+ cli->smb_rw_error = SMB_READ_BAD_DECRYPT;
+ return -1;
+ }
+ }
+
+ show_msg(cli->inbuf);
+ return len;
+}
+
+/****************************************************************************
+ Recv an smb.
+****************************************************************************/
+
+bool cli_receive_smb(struct cli_state *cli)
+{
+ ssize_t len;
+
+ /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
+ if (cli->fd == -1)
+ return false;
+
+ again:
+ len = client_receive_smb(cli, 0);
+
+ if (len > 0) {
+ /* it might be an oplock break request */
+ if (!(CVAL(cli->inbuf, smb_flg) & FLAG_REPLY) &&
+ CVAL(cli->inbuf,smb_com) == SMBlockingX &&
+ SVAL(cli->inbuf,smb_vwv6) == 0 &&
+ SVAL(cli->inbuf,smb_vwv7) == 0) {
+ if (cli->oplock_handler) {
+ int fnum = SVAL(cli->inbuf,smb_vwv2);
+ unsigned char level = CVAL(cli->inbuf,smb_vwv3+1);
+ if (!cli->oplock_handler(cli, fnum, level)) {
+ return false;
+ }
+ }
+ /* try to prevent loops */
+ SCVAL(cli->inbuf,smb_com,0xFF);
+ goto again;
+ }
+ }
+
+ /* If the server is not responding, note that now */
+ if (len < 0) {
+ DEBUG(0, ("Receiving SMB: Server stopped responding\n"));
+ close(cli->fd);
+ cli->fd = -1;
+ return false;
+ }
+
+ if (!cli_check_sign_mac(cli, cli->inbuf)) {
+ /*
+ * If we get a signature failure in sessionsetup, then
+ * the server sometimes just reflects the sent signature
+ * back to us. Detect this and allow the upper layer to
+ * retrieve the correct Windows error message.
+ */
+ if (CVAL(cli->outbuf,smb_com) == SMBsesssetupX &&
+ (smb_len(cli->inbuf) > (smb_ss_field + 8 - 4)) &&
+ (SVAL(cli->inbuf,smb_flg2) & FLAGS2_SMB_SECURITY_SIGNATURES) &&
+ memcmp(&cli->outbuf[smb_ss_field],&cli->inbuf[smb_ss_field],8) == 0 &&
+ cli_is_error(cli)) {
+
+ /*
+ * Reflected signature on login error.
+ * Set bad sig but don't close fd.
+ */
+ cli->smb_rw_error = SMB_READ_BAD_SIG;
+ return true;
+ }
+
+ DEBUG(0, ("SMB Signature verification failed on incoming packet!\n"));
+ cli->smb_rw_error = SMB_READ_BAD_SIG;
+ close(cli->fd);
+ cli->fd = -1;
+ return false;
+ };
+ return true;
+}
+
+/****************************************************************************
+ Read the data portion of a readX smb.
+ The timeout is in milliseconds
+****************************************************************************/
+
+ssize_t cli_receive_smb_data(struct cli_state *cli, char *buffer, size_t len)
+{
+ NTSTATUS status;
+
+ set_smb_read_error(&cli->smb_rw_error, SMB_READ_OK);
+
+ status = read_socket_with_timeout(
+ cli->fd, buffer, len, len, cli->timeout, NULL);
+ if (NT_STATUS_IS_OK(status)) {
+ return len;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
+ set_smb_read_error(&cli->smb_rw_error, SMB_READ_EOF);
+ return -1;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ set_smb_read_error(&cli->smb_rw_error, SMB_READ_TIMEOUT);
+ return -1;
+ }
+
+ set_smb_read_error(&cli->smb_rw_error, SMB_READ_ERROR);
+ return -1;
+}
+
+static ssize_t write_socket(int fd, const char *buf, size_t len)
+{
+ ssize_t ret=0;
+
+ DEBUG(6,("write_socket(%d,%d)\n",fd,(int)len));
+ ret = write_data(fd,buf,len);
+
+ DEBUG(6,("write_socket(%d,%d) wrote %d\n",fd,(int)len,(int)ret));
+ if(ret <= 0)
+ DEBUG(0,("write_socket: Error writing %d bytes to socket %d: ERRNO = %s\n",
+ (int)len, fd, strerror(errno) ));
+
+ return(ret);
+}
+
+/****************************************************************************
+ Send an smb to a fd.
+****************************************************************************/
+
+bool cli_send_smb(struct cli_state *cli)
+{
+ size_t len;
+ size_t nwritten=0;
+ ssize_t ret;
+ char *buf_out = cli->outbuf;
+ bool enc_on = cli_encryption_on(cli);
+
+ /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
+ if (cli->fd == -1)
+ return false;
+
+ cli_calculate_sign_mac(cli, cli->outbuf);
+
+ if (enc_on) {
+ NTSTATUS status = cli_encrypt_message(cli, cli->outbuf,
+ &buf_out);
+ if (!NT_STATUS_IS_OK(status)) {
+ close(cli->fd);
+ cli->fd = -1;
+ cli->smb_rw_error = SMB_WRITE_ERROR;
+ DEBUG(0,("Error in encrypting client message. Error %s\n",
+ nt_errstr(status) ));
+ return false;
+ }
+ }
+
+ len = smb_len(buf_out) + 4;
+
+ while (nwritten < len) {
+ ret = write_socket(cli->fd,buf_out+nwritten,len - nwritten);
+ if (ret <= 0) {
+ if (enc_on) {
+ cli_free_enc_buffer(cli, buf_out);
+ }
+ close(cli->fd);
+ cli->fd = -1;
+ cli->smb_rw_error = SMB_WRITE_ERROR;
+ DEBUG(0,("Error writing %d bytes to client. %d (%s)\n",
+ (int)len,(int)ret, strerror(errno) ));
+ return false;
+ }
+ nwritten += ret;
+ }
+
+ if (enc_on) {
+ cli_free_enc_buffer(cli, buf_out);
+ }
+
+ /* Increment the mid so we can tell between responses. */
+ cli->mid++;
+ if (!cli->mid)
+ cli->mid++;
+ return true;
+}
+
+/****************************************************************************
+ Send a "direct" writeX smb to a fd.
+****************************************************************************/
+
+bool cli_send_smb_direct_writeX(struct cli_state *cli,
+ const char *p,
+ size_t extradata)
+{
+ /* First length to send is the offset to the data. */
+ size_t len = SVAL(cli->outbuf,smb_vwv11) + 4;
+ size_t nwritten=0;
+ ssize_t ret;
+
+ /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
+ if (cli->fd == -1) {
+ return false;
+ }
+
+ if (client_is_signing_on(cli)) {
+ DEBUG(0,("cli_send_smb_large: cannot send signed packet.\n"));
+ return false;
+ }
+
+ while (nwritten < len) {
+ ret = write_socket(cli->fd,cli->outbuf+nwritten,len - nwritten);
+ if (ret <= 0) {
+ close(cli->fd);
+ cli->fd = -1;
+ cli->smb_rw_error = SMB_WRITE_ERROR;
+ DEBUG(0,("Error writing %d bytes to client. %d (%s)\n",
+ (int)len,(int)ret, strerror(errno) ));
+ return false;
+ }
+ nwritten += ret;
+ }
+
+ /* Now write the extra data. */
+ nwritten=0;
+ while (nwritten < extradata) {
+ ret = write_socket(cli->fd,p+nwritten,extradata - nwritten);
+ if (ret <= 0) {
+ close(cli->fd);
+ cli->fd = -1;
+ cli->smb_rw_error = SMB_WRITE_ERROR;
+ DEBUG(0,("Error writing %d extradata "
+ "bytes to client. %d (%s)\n",
+ (int)extradata,(int)ret, strerror(errno) ));
+ return false;
+ }
+ nwritten += ret;
+ }
+
+ /* Increment the mid so we can tell between responses. */
+ cli->mid++;
+ if (!cli->mid)
+ cli->mid++;
+ return true;
+}
+
+/****************************************************************************
+ Setup basics in a outgoing packet.
+****************************************************************************/
+
+void cli_setup_packet_buf(struct cli_state *cli, char *buf)
+{
+ uint16 flags2;
+ cli->rap_error = 0;
+ SIVAL(buf,smb_rcls,0);
+ SSVAL(buf,smb_pid,cli->pid);
+ memset(buf+smb_pidhigh, 0, 12);
+ SSVAL(buf,smb_uid,cli->vuid);
+ SSVAL(buf,smb_mid,cli->mid);
+
+ if (cli->protocol <= PROTOCOL_CORE) {
+ return;
+ }
+
+ if (cli->case_sensitive) {
+ SCVAL(buf,smb_flg,0x0);
+ } else {
+ /* Default setting, case insensitive. */
+ SCVAL(buf,smb_flg,0x8);
+ }
+ flags2 = FLAGS2_LONG_PATH_COMPONENTS;
+ if (cli->capabilities & CAP_UNICODE)
+ flags2 |= FLAGS2_UNICODE_STRINGS;
+ if ((cli->capabilities & CAP_DFS) && cli->dfsroot)
+ flags2 |= FLAGS2_DFS_PATHNAMES;
+ if (cli->capabilities & CAP_STATUS32)
+ flags2 |= FLAGS2_32_BIT_ERROR_CODES;
+ if (cli->use_spnego)
+ flags2 |= FLAGS2_EXTENDED_SECURITY;
+ SSVAL(buf,smb_flg2, flags2);
+}
+
+void cli_setup_packet(struct cli_state *cli)
+{
+ cli_setup_packet_buf(cli, cli->outbuf);
+}
+
+/****************************************************************************
+ Setup the bcc length of the packet from a pointer to the end of the data.
+****************************************************************************/
+
+void cli_setup_bcc(struct cli_state *cli, void *p)
+{
+ set_message_bcc(cli->outbuf, PTR_DIFF(p, smb_buf(cli->outbuf)));
+}
+
+/****************************************************************************
+ Initialise credentials of a client structure.
+****************************************************************************/
+
+void cli_init_creds(struct cli_state *cli, const char *username, const char *domain, const char *password)
+{
+ fstrcpy(cli->domain, domain);
+ fstrcpy(cli->user_name, username);
+ pwd_set_cleartext(&cli->pwd, password);
+ if (!*username) {
+ cli->pwd.null_pwd = true;
+ }
+
+ DEBUG(10,("cli_init_creds: user %s domain %s\n", cli->user_name, cli->domain));
+}
+
+/****************************************************************************
+ Set the signing state (used from the command line).
+****************************************************************************/
+
+void cli_setup_signing_state(struct cli_state *cli, int signing_state)
+{
+ if (signing_state == Undefined)
+ return;
+
+ if (signing_state == false) {
+ cli->sign_info.allow_smb_signing = false;
+ cli->sign_info.mandatory_signing = false;
+ return;
+ }
+
+ cli->sign_info.allow_smb_signing = true;
+
+ if (signing_state == Required)
+ cli->sign_info.mandatory_signing = true;
+}
+
+/****************************************************************************
+ Initialise a client structure. Always returns a malloc'ed struct.
+****************************************************************************/
+
+struct cli_state *cli_initialise(void)
+{
+ struct cli_state *cli = NULL;
+
+ /* Check the effective uid - make sure we are not setuid */
+ if (is_setuid_root()) {
+ DEBUG(0,("libsmb based programs must *NOT* be setuid root.\n"));
+ return NULL;
+ }
+
+ cli = talloc(NULL, struct cli_state);
+ if (!cli) {
+ return NULL;
+ }
+
+ ZERO_STRUCTP(cli);
+
+ cli->port = 0;
+ cli->fd = -1;
+ cli->cnum = -1;
+ cli->pid = (uint16)sys_getpid();
+ cli->mid = 1;
+ cli->vuid = UID_FIELD_INVALID;
+ cli->protocol = PROTOCOL_NT1;
+ cli->timeout = 20000; /* Timeout is in milliseconds. */
+ cli->bufsize = CLI_BUFFER_SIZE+4;
+ cli->max_xmit = cli->bufsize;
+ cli->outbuf = (char *)SMB_MALLOC(cli->bufsize+SAFETY_MARGIN);
+ cli->inbuf = (char *)SMB_MALLOC(cli->bufsize+SAFETY_MARGIN);
+ cli->oplock_handler = cli_oplock_ack;
+ cli->case_sensitive = false;
+ cli->smb_rw_error = SMB_READ_OK;
+
+ cli->use_spnego = lp_client_use_spnego();
+
+ cli->capabilities = CAP_UNICODE | CAP_STATUS32 | CAP_DFS;
+
+ /* Set the CLI_FORCE_DOSERR environment variable to test
+ client routines using DOS errors instead of STATUS32
+ ones. This intended only as a temporary hack. */
+ if (getenv("CLI_FORCE_DOSERR"))
+ cli->force_dos_errors = true;
+
+ if (lp_client_signing())
+ cli->sign_info.allow_smb_signing = true;
+
+ if (lp_client_signing() == Required)
+ cli->sign_info.mandatory_signing = true;
+
+ if (!cli->outbuf || !cli->inbuf)
+ goto error;
+
+ memset(cli->outbuf, 0, cli->bufsize);
+ memset(cli->inbuf, 0, cli->bufsize);
+
+
+#if defined(DEVELOPER)
+ /* just because we over-allocate, doesn't mean it's right to use it */
+ clobber_region(FUNCTION_MACRO, __LINE__, cli->outbuf+cli->bufsize, SAFETY_MARGIN);
+ clobber_region(FUNCTION_MACRO, __LINE__, cli->inbuf+cli->bufsize, SAFETY_MARGIN);
+#endif
+
+ /* initialise signing */
+ cli_null_set_signing(cli);
+
+ cli->initialised = 1;
+
+ return cli;
+
+ /* Clean up after malloc() error */
+
+ error:
+
+ SAFE_FREE(cli->inbuf);
+ SAFE_FREE(cli->outbuf);
+ SAFE_FREE(cli);
+ return NULL;
+}
+
+/****************************************************************************
+ Close all pipes open on this session.
+****************************************************************************/
+
+void cli_nt_pipes_close(struct cli_state *cli)
+{
+ while (cli->pipe_list != NULL) {
+ /*
+ * No TALLOC_FREE here!
+ */
+ talloc_free(cli->pipe_list);
+ }
+}
+
+/****************************************************************************
+ Shutdown a client structure.
+****************************************************************************/
+
+void cli_shutdown(struct cli_state *cli)
+{
+ cli_nt_pipes_close(cli);
+
+ /*
+ * tell our peer to free his resources. Wihtout this, when an
+ * application attempts to do a graceful shutdown and calls
+ * smbc_free_context() to clean up all connections, some connections
+ * can remain active on the peer end, until some (long) timeout period
+ * later. This tree disconnect forces the peer to clean up, since the
+ * connection will be going away.
+ *
+ * Also, do not do tree disconnect when cli->smb_rw_error is SMB_DO_NOT_DO_TDIS
+ * the only user for this so far is smbmount which passes opened connection
+ * down to kernel's smbfs module.
+ */
+ if ( (cli->cnum != (uint16)-1) && (cli->smb_rw_error != SMB_DO_NOT_DO_TDIS ) ) {
+ cli_tdis(cli);
+ }
+
+ SAFE_FREE(cli->outbuf);
+ SAFE_FREE(cli->inbuf);
+
+ cli_free_signing_context(cli);
+ data_blob_free(&cli->secblob);
+ data_blob_free(&cli->user_session_key);
+
+ if (cli->fd != -1) {
+ close(cli->fd);
+ }
+ cli->fd = -1;
+ cli->smb_rw_error = SMB_READ_OK;
+
+ TALLOC_FREE(cli);
+}
+
+/****************************************************************************
+ Set socket options on a open connection.
+****************************************************************************/
+
+void cli_sockopt(struct cli_state *cli, const char *options)
+{
+ set_socket_options(cli->fd, options);
+}
+
+/****************************************************************************
+ Set the PID to use for smb messages. Return the old pid.
+****************************************************************************/
+
+uint16 cli_setpid(struct cli_state *cli, uint16 pid)
+{
+ uint16 ret = cli->pid;
+ cli->pid = pid;
+ return ret;
+}
+
+/****************************************************************************
+ Set the case sensitivity flag on the packets. Returns old state.
+****************************************************************************/
+
+bool cli_set_case_sensitive(struct cli_state *cli, bool case_sensitive)
+{
+ bool ret = cli->case_sensitive;
+ cli->case_sensitive = case_sensitive;
+ return ret;
+}
+
+/****************************************************************************
+Send a keepalive packet to the server
+****************************************************************************/
+
+bool cli_send_keepalive(struct cli_state *cli)
+{
+ if (cli->fd == -1) {
+ DEBUG(3, ("cli_send_keepalive: fd == -1\n"));
+ return false;
+ }
+ if (!send_keepalive(cli->fd)) {
+ close(cli->fd);
+ cli->fd = -1;
+ DEBUG(0,("Error sending keepalive packet to client.\n"));
+ return false;
+ }
+ return true;
+}
+
+/**
+ * @brief: Collect a echo reply
+ * @param[in] req The corresponding async request
+ *
+ * There might be more than one echo reply. This helper pulls the reply out of
+ * the data stream. If all expected replies have arrived, declare the
+ * async_req done.
+ */
+
+static void cli_echo_recv_helper(struct async_req *req)
+{
+ struct cli_request *cli_req;
+ uint8_t wct;
+ uint16_t *vwv;
+ uint16_t num_bytes;
+ uint8_t *bytes;
+ NTSTATUS status;
+
+ status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
+ if (!NT_STATUS_IS_OK(status)) {
+ async_req_error(req, status);
+ return;
+ }
+
+ cli_req = talloc_get_type_abort(req->private_data, struct cli_request);
+
+ if ((num_bytes != cli_req->data.echo.data.length)
+ || (memcmp(cli_req->data.echo.data.data, bytes,
+ num_bytes) != 0)) {
+ async_req_error(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ cli_req->data.echo.num_echos -= 1;
+
+ if (cli_req->data.echo.num_echos == 0) {
+ client_set_trans_sign_state_off(cli_req->cli, cli_req->mid);
+ async_req_done(req);
+ return;
+ }
+
+ return;
+}
+
+/**
+ * @brief Send SMBEcho requests
+ * @param[in] mem_ctx The memory context to put the async_req on
+ * @param[in] ev The event context that will call us back
+ * @param[in] cli The connection to send the echo to
+ * @param[in] num_echos How many times do we want to get the reply?
+ * @param[in] data The data we want to get back
+ * @retval The async request
+ */
+
+struct async_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ struct cli_state *cli, uint16_t num_echos,
+ DATA_BLOB data)
+{
+ uint16_t vwv[1];
+ uint8_t *data_copy;
+ struct async_req *result;
+ struct cli_request *req;
+
+ SSVAL(vwv, 0, num_echos);
+
+ data_copy = (uint8_t *)talloc_memdup(mem_ctx, data.data, data.length);
+ if (data_copy == NULL) {
+ return NULL;
+ }
+
+ result = cli_request_send(mem_ctx, ev, cli, SMBecho, 0, 1, vwv,
+ data.length, data.data);
+ if (result == NULL) {
+ TALLOC_FREE(data_copy);
+ return NULL;
+ }
+ req = talloc_get_type_abort(result->private_data, struct cli_request);
+
+ client_set_trans_sign_state_on(cli, req->mid);
+
+ req->data.echo.num_echos = num_echos;
+ req->data.echo.data.data = talloc_move(req, &data_copy);
+ req->data.echo.data.length = data.length;
+
+ req->recv_helper.fn = cli_echo_recv_helper;
+
+ return result;
+}
+
+/**
+ * Get the result out from an echo request
+ * @param[in] req The async_req from cli_echo_send
+ * @retval Did the server reply correctly?
+ */
+
+NTSTATUS cli_echo_recv(struct async_req *req)
+{
+ SMB_ASSERT(req->state >= ASYNC_REQ_DONE);
+ if (req->state == ASYNC_REQ_ERROR) {
+ return req->status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * @brief Send/Receive SMBEcho requests
+ * @param[in] mem_ctx The memory context to put the async_req on
+ * @param[in] ev The event context that will call us back
+ * @param[in] cli The connection to send the echo to
+ * @param[in] num_echos How many times do we want to get the reply?
+ * @param[in] data The data we want to get back
+ * @retval Did the server reply correctly?
+ */
+
+NTSTATUS cli_echo(struct cli_state *cli, uint16_t num_echos, DATA_BLOB data)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct async_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (cli->fd_event != NULL) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ cli_set_error(cli, NT_STATUS_INVALID_PARAMETER);
+ goto fail;
+ }
+
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+
+ req = cli_echo_send(frame, ev, cli, num_echos, data);
+ if (req == NULL) {
+ goto fail;
+ }
+
+ while (req->state < ASYNC_REQ_DONE) {
+ event_loop_once(ev);
+ }
+
+ status = cli_echo_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/source3/libsmb/clierror.c b/source3/libsmb/clierror.c
new file mode 100644
index 0000000000..36746419f7
--- /dev/null
+++ b/source3/libsmb/clierror.c
@@ -0,0 +1,497 @@
+/*
+ Unix SMB/CIFS implementation.
+ client error handling routines
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Jelmer Vernooij 2003
+ Copyright (C) Jeremy Allison 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*****************************************************
+ RAP error codes - a small start but will be extended.
+
+ XXX: Perhaps these should move into a common function because they're
+ duplicated in clirap2.c
+
+*******************************************************/
+
+static const struct {
+ int err;
+ const char *message;
+} rap_errmap[] = {
+ {5, "RAP5: User has insufficient privilege" },
+ {50, "RAP50: Not supported by server" },
+ {65, "RAP65: Access denied" },
+ {86, "RAP86: The specified password is invalid" },
+ {2220, "RAP2220: Group does not exist" },
+ {2221, "RAP2221: User does not exist" },
+ {2226, "RAP2226: Operation only permitted on a Primary Domain Controller" },
+ {2237, "RAP2237: User is not in group" },
+ {2242, "RAP2242: The password of this user has expired." },
+ {2243, "RAP2243: The password of this user cannot change." },
+ {2244, "RAP2244: This password cannot be used now (password history conflict)." },
+ {2245, "RAP2245: The password is shorter than required." },
+ {2246, "RAP2246: The password of this user is too recent to change."},
+
+ /* these really shouldn't be here ... */
+ {0x80, "Not listening on called name"},
+ {0x81, "Not listening for calling name"},
+ {0x82, "Called name not present"},
+ {0x83, "Called name present, but insufficient resources"},
+
+ {0, NULL}
+};
+
+/****************************************************************************
+ Return a description of an SMB error.
+****************************************************************************/
+
+static const char *cli_smb_errstr(struct cli_state *cli)
+{
+ return smb_dos_errstr(cli->inbuf);
+}
+
+/****************************************************************************
+ Convert a socket error into an NTSTATUS.
+****************************************************************************/
+
+static NTSTATUS cli_smb_rw_error_to_ntstatus(struct cli_state *cli)
+{
+ switch(cli->smb_rw_error) {
+ case SMB_READ_TIMEOUT:
+ return NT_STATUS_IO_TIMEOUT;
+ case SMB_READ_EOF:
+ return NT_STATUS_END_OF_FILE;
+ /* What we shoud really do for read/write errors is convert from errno. */
+ /* FIXME. JRA. */
+ case SMB_READ_ERROR:
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ case SMB_WRITE_ERROR:
+ return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ case SMB_READ_BAD_SIG:
+ return NT_STATUS_INVALID_PARAMETER;
+ case SMB_NO_MEMORY:
+ return NT_STATUS_NO_MEMORY;
+ default:
+ break;
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/***************************************************************************
+ Return an error message - either an NT error, SMB error or a RAP error.
+ Note some of the NT errors are actually warnings or "informational" errors
+ in which case they can be safely ignored.
+****************************************************************************/
+
+const char *cli_errstr(struct cli_state *cli)
+{
+ fstring cli_error_message;
+ uint32 flgs2 = SVAL(cli->inbuf,smb_flg2), errnum;
+ uint8 errclass;
+ int i;
+ char *result;
+
+ if (!cli->initialised) {
+ fstrcpy(cli_error_message, "[Programmer's error] cli_errstr called on unitialized cli_stat struct!\n");
+ goto done;
+ }
+
+ /* Was it server socket error ? */
+ if (cli->fd == -1 && cli->smb_rw_error) {
+ switch(cli->smb_rw_error) {
+ case SMB_READ_TIMEOUT:
+ slprintf(cli_error_message, sizeof(cli_error_message) - 1,
+ "Call timed out: server did not respond after %d milliseconds",
+ cli->timeout);
+ break;
+ case SMB_READ_EOF:
+ slprintf(cli_error_message, sizeof(cli_error_message) - 1,
+ "Call returned zero bytes (EOF)" );
+ break;
+ case SMB_READ_ERROR:
+ slprintf(cli_error_message, sizeof(cli_error_message) - 1,
+ "Read error: %s", strerror(errno) );
+ break;
+ case SMB_WRITE_ERROR:
+ slprintf(cli_error_message, sizeof(cli_error_message) - 1,
+ "Write error: %s", strerror(errno) );
+ break;
+ case SMB_READ_BAD_SIG:
+ slprintf(cli_error_message, sizeof(cli_error_message) - 1,
+ "Server packet had invalid SMB signature!");
+ break;
+ case SMB_NO_MEMORY:
+ slprintf(cli_error_message, sizeof(cli_error_message) - 1,
+ "Out of memory");
+ break;
+ default:
+ slprintf(cli_error_message, sizeof(cli_error_message) - 1,
+ "Unknown error code %d\n", cli->smb_rw_error );
+ break;
+ }
+ goto done;
+ }
+
+ /* Case #1: RAP error */
+ if (cli->rap_error) {
+ for (i = 0; rap_errmap[i].message != NULL; i++) {
+ if (rap_errmap[i].err == cli->rap_error) {
+ return rap_errmap[i].message;
+ }
+ }
+
+ slprintf(cli_error_message, sizeof(cli_error_message) - 1, "RAP code %d",
+ cli->rap_error);
+
+ goto done;
+ }
+
+ /* Case #2: 32-bit NT errors */
+ if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
+ NTSTATUS status = NT_STATUS(IVAL(cli->inbuf,smb_rcls));
+
+ return nt_errstr(status);
+ }
+
+ cli_dos_error(cli, &errclass, &errnum);
+
+ /* Case #3: SMB error */
+
+ return cli_smb_errstr(cli);
+
+ done:
+ result = talloc_strdup(talloc_tos(), cli_error_message);
+ SMB_ASSERT(result);
+ return result;
+}
+
+
+/****************************************************************************
+ Return the 32-bit NT status code from the last packet.
+****************************************************************************/
+
+NTSTATUS cli_nt_error(struct cli_state *cli)
+{
+ int flgs2 = SVAL(cli->inbuf,smb_flg2);
+
+ /* Deal with socket errors first. */
+ if (cli->fd == -1 && cli->smb_rw_error) {
+ return cli_smb_rw_error_to_ntstatus(cli);
+ }
+
+ if (!(flgs2 & FLAGS2_32_BIT_ERROR_CODES)) {
+ int e_class = CVAL(cli->inbuf,smb_rcls);
+ int code = SVAL(cli->inbuf,smb_err);
+ return dos_to_ntstatus(e_class, code);
+ }
+
+ return NT_STATUS(IVAL(cli->inbuf,smb_rcls));
+}
+
+
+/****************************************************************************
+ Return the DOS error from the last packet - an error class and an error
+ code.
+****************************************************************************/
+
+void cli_dos_error(struct cli_state *cli, uint8 *eclass, uint32 *ecode)
+{
+ int flgs2;
+
+ if(!cli->initialised) {
+ return;
+ }
+
+ /* Deal with socket errors first. */
+ if (cli->fd == -1 && cli->smb_rw_error) {
+ NTSTATUS status = cli_smb_rw_error_to_ntstatus(cli);
+ ntstatus_to_dos( status, eclass, ecode);
+ return;
+ }
+
+ flgs2 = SVAL(cli->inbuf,smb_flg2);
+
+ if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
+ NTSTATUS ntstatus = NT_STATUS(IVAL(cli->inbuf, smb_rcls));
+ ntstatus_to_dos(ntstatus, eclass, ecode);
+ return;
+ }
+
+ *eclass = CVAL(cli->inbuf,smb_rcls);
+ *ecode = SVAL(cli->inbuf,smb_err);
+}
+
+/* Return a UNIX errno from a NT status code */
+static const struct {
+ NTSTATUS status;
+ int error;
+} nt_errno_map[] = {
+ {NT_STATUS_ACCESS_VIOLATION, EACCES},
+ {NT_STATUS_INVALID_HANDLE, EBADF},
+ {NT_STATUS_ACCESS_DENIED, EACCES},
+ {NT_STATUS_OBJECT_NAME_NOT_FOUND, ENOENT},
+ {NT_STATUS_OBJECT_PATH_NOT_FOUND, ENOENT},
+ {NT_STATUS_SHARING_VIOLATION, EBUSY},
+ {NT_STATUS_OBJECT_PATH_INVALID, ENOTDIR},
+ {NT_STATUS_OBJECT_NAME_COLLISION, EEXIST},
+ {NT_STATUS_PATH_NOT_COVERED, ENOENT},
+ {NT_STATUS_UNSUCCESSFUL, EINVAL},
+ {NT_STATUS_NOT_IMPLEMENTED, ENOSYS},
+ {NT_STATUS_IN_PAGE_ERROR, EFAULT},
+ {NT_STATUS_BAD_NETWORK_NAME, ENOENT},
+#ifdef EDQUOT
+ {NT_STATUS_PAGEFILE_QUOTA, EDQUOT},
+ {NT_STATUS_QUOTA_EXCEEDED, EDQUOT},
+ {NT_STATUS_REGISTRY_QUOTA_LIMIT, EDQUOT},
+ {NT_STATUS_LICENSE_QUOTA_EXCEEDED, EDQUOT},
+#endif
+#ifdef ETIME
+ {NT_STATUS_TIMER_NOT_CANCELED, ETIME},
+#endif
+ {NT_STATUS_INVALID_PARAMETER, EINVAL},
+ {NT_STATUS_NO_SUCH_DEVICE, ENODEV},
+ {NT_STATUS_NO_SUCH_FILE, ENOENT},
+#ifdef ENODATA
+ {NT_STATUS_END_OF_FILE, ENODATA},
+#endif
+#ifdef ENOMEDIUM
+ {NT_STATUS_NO_MEDIA_IN_DEVICE, ENOMEDIUM},
+ {NT_STATUS_NO_MEDIA, ENOMEDIUM},
+#endif
+ {NT_STATUS_NONEXISTENT_SECTOR, ESPIPE},
+ {NT_STATUS_NO_MEMORY, ENOMEM},
+ {NT_STATUS_CONFLICTING_ADDRESSES, EADDRINUSE},
+ {NT_STATUS_NOT_MAPPED_VIEW, EINVAL},
+ {NT_STATUS_UNABLE_TO_FREE_VM, EADDRINUSE},
+ {NT_STATUS_ACCESS_DENIED, EACCES},
+ {NT_STATUS_BUFFER_TOO_SMALL, ENOBUFS},
+ {NT_STATUS_WRONG_PASSWORD, EACCES},
+ {NT_STATUS_LOGON_FAILURE, EACCES},
+ {NT_STATUS_INVALID_WORKSTATION, EACCES},
+ {NT_STATUS_INVALID_LOGON_HOURS, EACCES},
+ {NT_STATUS_PASSWORD_EXPIRED, EACCES},
+ {NT_STATUS_ACCOUNT_DISABLED, EACCES},
+ {NT_STATUS_DISK_FULL, ENOSPC},
+ {NT_STATUS_INVALID_PIPE_STATE, EPIPE},
+ {NT_STATUS_PIPE_BUSY, EPIPE},
+ {NT_STATUS_PIPE_DISCONNECTED, EPIPE},
+ {NT_STATUS_PIPE_NOT_AVAILABLE, ENOSYS},
+ {NT_STATUS_FILE_IS_A_DIRECTORY, EISDIR},
+ {NT_STATUS_NOT_SUPPORTED, ENOSYS},
+ {NT_STATUS_NOT_A_DIRECTORY, ENOTDIR},
+ {NT_STATUS_DIRECTORY_NOT_EMPTY, ENOTEMPTY},
+ {NT_STATUS_NETWORK_UNREACHABLE, ENETUNREACH},
+ {NT_STATUS_HOST_UNREACHABLE, EHOSTUNREACH},
+ {NT_STATUS_CONNECTION_ABORTED, ECONNABORTED},
+ {NT_STATUS_CONNECTION_REFUSED, ECONNREFUSED},
+ {NT_STATUS_TOO_MANY_LINKS, EMLINK},
+ {NT_STATUS_NETWORK_BUSY, EBUSY},
+ {NT_STATUS_DEVICE_DOES_NOT_EXIST, ENODEV},
+#ifdef ELIBACC
+ {NT_STATUS_DLL_NOT_FOUND, ELIBACC},
+#endif
+ {NT_STATUS_PIPE_BROKEN, EPIPE},
+ {NT_STATUS_REMOTE_NOT_LISTENING, ECONNREFUSED},
+ {NT_STATUS_NETWORK_ACCESS_DENIED, EACCES},
+ {NT_STATUS_TOO_MANY_OPENED_FILES, EMFILE},
+#ifdef EPROTO
+ {NT_STATUS_DEVICE_PROTOCOL_ERROR, EPROTO},
+#endif
+ {NT_STATUS_FLOAT_OVERFLOW, ERANGE},
+ {NT_STATUS_FLOAT_UNDERFLOW, ERANGE},
+ {NT_STATUS_INTEGER_OVERFLOW, ERANGE},
+ {NT_STATUS_MEDIA_WRITE_PROTECTED, EROFS},
+ {NT_STATUS_PIPE_CONNECTED, EISCONN},
+ {NT_STATUS_MEMORY_NOT_ALLOCATED, EFAULT},
+ {NT_STATUS_FLOAT_INEXACT_RESULT, ERANGE},
+ {NT_STATUS_ILL_FORMED_PASSWORD, EACCES},
+ {NT_STATUS_PASSWORD_RESTRICTION, EACCES},
+ {NT_STATUS_ACCOUNT_RESTRICTION, EACCES},
+ {NT_STATUS_PORT_CONNECTION_REFUSED, ECONNREFUSED},
+ {NT_STATUS_NAME_TOO_LONG, ENAMETOOLONG},
+ {NT_STATUS_REMOTE_DISCONNECT, ESHUTDOWN},
+ {NT_STATUS_CONNECTION_DISCONNECTED, ECONNABORTED},
+ {NT_STATUS_CONNECTION_RESET, ENETRESET},
+#ifdef ENOTUNIQ
+ {NT_STATUS_IP_ADDRESS_CONFLICT1, ENOTUNIQ},
+ {NT_STATUS_IP_ADDRESS_CONFLICT2, ENOTUNIQ},
+#endif
+ {NT_STATUS_PORT_MESSAGE_TOO_LONG, EMSGSIZE},
+ {NT_STATUS_PROTOCOL_UNREACHABLE, ENOPROTOOPT},
+ {NT_STATUS_ADDRESS_ALREADY_EXISTS, EADDRINUSE},
+ {NT_STATUS_PORT_UNREACHABLE, EHOSTUNREACH},
+ {NT_STATUS_IO_TIMEOUT, ETIMEDOUT},
+ {NT_STATUS_RETRY, EAGAIN},
+#ifdef ENOTUNIQ
+ {NT_STATUS_DUPLICATE_NAME, ENOTUNIQ},
+#endif
+#ifdef ECOMM
+ {NT_STATUS_NET_WRITE_FAULT, ECOMM},
+#endif
+#ifdef EXDEV
+ {NT_STATUS_NOT_SAME_DEVICE, EXDEV},
+#endif
+ {NT_STATUS(0), 0}
+};
+
+/****************************************************************************
+ The following mappings need tidying up and moving into libsmb/errormap.c...
+****************************************************************************/
+
+static int cli_errno_from_nt(NTSTATUS status)
+{
+ int i;
+ DEBUG(10,("cli_errno_from_nt: 32 bit codes: code=%08x\n", NT_STATUS_V(status)));
+
+ /* Status codes without this bit set are not errors */
+
+ if (!(NT_STATUS_V(status) & 0xc0000000)) {
+ return 0;
+ }
+
+ for (i=0;nt_errno_map[i].error;i++) {
+ if (NT_STATUS_V(nt_errno_map[i].status) ==
+ NT_STATUS_V(status)) return nt_errno_map[i].error;
+ }
+
+ /* for all other cases - a default code */
+ return EINVAL;
+}
+
+/* Return a UNIX errno appropriate for the error received in the last
+ packet. */
+
+int cli_errno(struct cli_state *cli)
+{
+ NTSTATUS status;
+
+ if (cli_is_nt_error(cli)) {
+ status = cli_nt_error(cli);
+ return cli_errno_from_nt(status);
+ }
+
+ if (cli_is_dos_error(cli)) {
+ uint8 eclass;
+ uint32 ecode;
+
+ cli_dos_error(cli, &eclass, &ecode);
+ status = dos_to_ntstatus(eclass, ecode);
+ return cli_errno_from_nt(status);
+ }
+
+ /*
+ * Yuck! A special case for this Vista error. Since its high-order
+ * byte isn't 0xc0, it doesn't match cli_is_nt_error() above.
+ */
+ status = cli_nt_error(cli);
+ if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT)) {
+ return EACCES;
+ }
+
+ /* for other cases */
+ return EINVAL;
+}
+
+/* Return true if the last packet was in error */
+
+bool cli_is_error(struct cli_state *cli)
+{
+ uint32 flgs2 = SVAL(cli->inbuf,smb_flg2), rcls = 0;
+
+ /* A socket error is always an error. */
+ if (cli->fd == -1 && cli->smb_rw_error != 0) {
+ return True;
+ }
+
+ if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
+ /* Return error is error bits are set */
+ rcls = IVAL(cli->inbuf, smb_rcls);
+ return (rcls & 0xF0000000) == 0xC0000000;
+ }
+
+ /* Return error if error class in non-zero */
+
+ rcls = CVAL(cli->inbuf, smb_rcls);
+ return rcls != 0;
+}
+
+/* Return true if the last error was an NT error */
+
+bool cli_is_nt_error(struct cli_state *cli)
+{
+ uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
+
+ /* A socket error is always an NT error. */
+ if (cli->fd == -1 && cli->smb_rw_error != 0) {
+ return True;
+ }
+
+ return cli_is_error(cli) && (flgs2 & FLAGS2_32_BIT_ERROR_CODES);
+}
+
+/* Return true if the last error was a DOS error */
+
+bool cli_is_dos_error(struct cli_state *cli)
+{
+ uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
+
+ /* A socket error is always a DOS error. */
+ if (cli->fd == -1 && cli->smb_rw_error != 0) {
+ return True;
+ }
+
+ return cli_is_error(cli) && !(flgs2 & FLAGS2_32_BIT_ERROR_CODES);
+}
+
+/* Return the last error always as an NTSTATUS. */
+
+NTSTATUS cli_get_nt_error(struct cli_state *cli)
+{
+ if (cli_is_nt_error(cli)) {
+ return cli_nt_error(cli);
+ } else if (cli_is_dos_error(cli)) {
+ uint32 ecode;
+ uint8 eclass;
+ cli_dos_error(cli, &eclass, &ecode);
+ return dos_to_ntstatus(eclass, ecode);
+ } else {
+ /* Something went wrong, we don't know what. */
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+}
+
+/* Push an error code into the inbuf to be returned on the next
+ * query. */
+
+void cli_set_nt_error(struct cli_state *cli, NTSTATUS status)
+{
+ SSVAL(cli->inbuf,smb_flg2, SVAL(cli->inbuf,smb_flg2)|FLAGS2_32_BIT_ERROR_CODES);
+ SIVAL(cli->inbuf, smb_rcls, NT_STATUS_V(status));
+}
+
+/* Reset an error. */
+
+void cli_reset_error(struct cli_state *cli)
+{
+ if (SVAL(cli->inbuf,smb_flg2) & FLAGS2_32_BIT_ERROR_CODES) {
+ SIVAL(cli->inbuf, smb_rcls, NT_STATUS_V(NT_STATUS_OK));
+ } else {
+ SCVAL(cli->inbuf,smb_rcls,0);
+ SSVAL(cli->inbuf,smb_err,0);
+ }
+}
diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
new file mode 100644
index 0000000000..d3819af444
--- /dev/null
+++ b/source3/libsmb/clifile.c
@@ -0,0 +1,2281 @@
+/*
+ Unix SMB/CIFS implementation.
+ client file operations
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Jeremy Allison 2001-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Hard/Symlink a file (UNIX extensions).
+ Creates new name (sym)linked to oldname.
+****************************************************************************/
+
+static bool cli_link_internal(struct cli_state *cli, const char *oldname, const char *newname, bool hard_link)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ uint16 setup = TRANSACT2_SETPATHINFO;
+ char *param;
+ char *data;
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+ size_t oldlen = 2*(strlen(oldname)+1);
+ size_t newlen = 2*(strlen(newname)+1);
+
+ param = SMB_MALLOC_ARRAY(char, 6+newlen+2);
+
+ if (!param) {
+ return false;
+ }
+
+ data = SMB_MALLOC_ARRAY(char, oldlen+2);
+
+ if (!data) {
+ SAFE_FREE(param);
+ return false;
+ }
+
+ SSVAL(param,0,hard_link ? SMB_SET_FILE_UNIX_HLINK : SMB_SET_FILE_UNIX_LINK);
+ SIVAL(param,2,0);
+ p = &param[6];
+
+ p += clistr_push(cli, p, newname, newlen, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+ p = data;
+ p += clistr_push(cli, p, oldname, oldlen, STR_TERMINATE);
+ data_len = PTR_DIFF(p, data);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ (char *)&data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ SAFE_FREE(data);
+ SAFE_FREE(param);
+ return false;
+ }
+
+ SAFE_FREE(data);
+ SAFE_FREE(param);
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return false;
+ }
+
+ SAFE_FREE(data);
+ SAFE_FREE(param);
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return true;
+}
+
+/****************************************************************************
+ Map standard UNIX permissions onto wire representations.
+****************************************************************************/
+
+uint32 unix_perms_to_wire(mode_t perms)
+{
+ unsigned int ret = 0;
+
+ ret |= ((perms & S_IXOTH) ? UNIX_X_OTH : 0);
+ ret |= ((perms & S_IWOTH) ? UNIX_W_OTH : 0);
+ ret |= ((perms & S_IROTH) ? UNIX_R_OTH : 0);
+ ret |= ((perms & S_IXGRP) ? UNIX_X_GRP : 0);
+ ret |= ((perms & S_IWGRP) ? UNIX_W_GRP : 0);
+ ret |= ((perms & S_IRGRP) ? UNIX_R_GRP : 0);
+ ret |= ((perms & S_IXUSR) ? UNIX_X_USR : 0);
+ ret |= ((perms & S_IWUSR) ? UNIX_W_USR : 0);
+ ret |= ((perms & S_IRUSR) ? UNIX_R_USR : 0);
+#ifdef S_ISVTX
+ ret |= ((perms & S_ISVTX) ? UNIX_STICKY : 0);
+#endif
+#ifdef S_ISGID
+ ret |= ((perms & S_ISGID) ? UNIX_SET_GID : 0);
+#endif
+#ifdef S_ISUID
+ ret |= ((perms & S_ISUID) ? UNIX_SET_UID : 0);
+#endif
+ return ret;
+}
+
+/****************************************************************************
+ Map wire permissions to standard UNIX.
+****************************************************************************/
+
+mode_t wire_perms_to_unix(uint32 perms)
+{
+ mode_t ret = (mode_t)0;
+
+ ret |= ((perms & UNIX_X_OTH) ? S_IXOTH : 0);
+ ret |= ((perms & UNIX_W_OTH) ? S_IWOTH : 0);
+ ret |= ((perms & UNIX_R_OTH) ? S_IROTH : 0);
+ ret |= ((perms & UNIX_X_GRP) ? S_IXGRP : 0);
+ ret |= ((perms & UNIX_W_GRP) ? S_IWGRP : 0);
+ ret |= ((perms & UNIX_R_GRP) ? S_IRGRP : 0);
+ ret |= ((perms & UNIX_X_USR) ? S_IXUSR : 0);
+ ret |= ((perms & UNIX_W_USR) ? S_IWUSR : 0);
+ ret |= ((perms & UNIX_R_USR) ? S_IRUSR : 0);
+#ifdef S_ISVTX
+ ret |= ((perms & UNIX_STICKY) ? S_ISVTX : 0);
+#endif
+#ifdef S_ISGID
+ ret |= ((perms & UNIX_SET_GID) ? S_ISGID : 0);
+#endif
+#ifdef S_ISUID
+ ret |= ((perms & UNIX_SET_UID) ? S_ISUID : 0);
+#endif
+ return ret;
+}
+
+/****************************************************************************
+ Return the file type from the wire filetype for UNIX extensions.
+****************************************************************************/
+
+static mode_t unix_filetype_from_wire(uint32 wire_type)
+{
+ switch (wire_type) {
+ case UNIX_TYPE_FILE:
+ return S_IFREG;
+ case UNIX_TYPE_DIR:
+ return S_IFDIR;
+#ifdef S_IFLNK
+ case UNIX_TYPE_SYMLINK:
+ return S_IFLNK;
+#endif
+#ifdef S_IFCHR
+ case UNIX_TYPE_CHARDEV:
+ return S_IFCHR;
+#endif
+#ifdef S_IFBLK
+ case UNIX_TYPE_BLKDEV:
+ return S_IFBLK;
+#endif
+#ifdef S_IFIFO
+ case UNIX_TYPE_FIFO:
+ return S_IFIFO;
+#endif
+#ifdef S_IFSOCK
+ case UNIX_TYPE_SOCKET:
+ return S_IFSOCK;
+#endif
+ default:
+ return (mode_t)0;
+ }
+}
+
+/****************************************************************************
+ Do a POSIX getfacl (UNIX extensions).
+****************************************************************************/
+
+bool cli_unix_getfacl(struct cli_state *cli, const char *name, size_t *prb_size, char **retbuf)
+{
+ unsigned int param_len = 0;
+ unsigned int data_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ char *param;
+ size_t nlen = 2*(strlen(name)+1);
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+
+ param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
+ if (!param) {
+ return false;
+ }
+
+ p = param;
+ memset(p, '\0', 6);
+ SSVAL(p, 0, SMB_QUERY_POSIX_ACL);
+ p += 6;
+ p += clistr_push(cli, p, name, nlen, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ NULL, 0, cli->max_xmit /* data, length, max */
+ )) {
+ SAFE_FREE(param);
+ return false;
+ }
+
+ SAFE_FREE(param);
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return false;
+ }
+
+ if (data_len < 6) {
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return false;
+ }
+
+ SAFE_FREE(rparam);
+ *retbuf = rdata;
+ *prb_size = (size_t)data_len;
+
+ return true;
+}
+
+/****************************************************************************
+ Stat a file (UNIX extensions).
+****************************************************************************/
+
+bool cli_unix_stat(struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbuf)
+{
+ unsigned int param_len = 0;
+ unsigned int data_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ char *param;
+ size_t nlen = 2*(strlen(name)+1);
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+
+ ZERO_STRUCTP(sbuf);
+
+ param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
+ if (!param) {
+ return false;
+ }
+ p = param;
+ memset(p, '\0', 6);
+ SSVAL(p, 0, SMB_QUERY_FILE_UNIX_BASIC);
+ p += 6;
+ p += clistr_push(cli, p, name, nlen, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ NULL, 0, cli->max_xmit /* data, length, max */
+ )) {
+ SAFE_FREE(param);
+ return false;
+ }
+
+ SAFE_FREE(param);
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return false;
+ }
+
+ if (data_len < 96) {
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return false;
+ }
+
+ sbuf->st_size = IVAL2_TO_SMB_BIG_UINT(rdata,0); /* total size, in bytes */
+ sbuf->st_blocks = IVAL2_TO_SMB_BIG_UINT(rdata,8); /* number of blocks allocated */
+#if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
+ sbuf->st_blocks /= STAT_ST_BLOCKSIZE;
+#else
+ /* assume 512 byte blocks */
+ sbuf->st_blocks /= 512;
+#endif
+ set_ctimespec(sbuf, interpret_long_date(rdata + 16)); /* time of last change */
+ set_atimespec(sbuf, interpret_long_date(rdata + 24)); /* time of last access */
+ set_mtimespec(sbuf, interpret_long_date(rdata + 32)); /* time of last modification */
+
+ sbuf->st_uid = (uid_t) IVAL(rdata,40); /* user ID of owner */
+ sbuf->st_gid = (gid_t) IVAL(rdata,48); /* group ID of owner */
+ sbuf->st_mode |= unix_filetype_from_wire(IVAL(rdata, 56));
+#if defined(HAVE_MAKEDEV)
+ {
+ uint32 dev_major = IVAL(rdata,60);
+ uint32 dev_minor = IVAL(rdata,68);
+ sbuf->st_rdev = makedev(dev_major, dev_minor);
+ }
+#endif
+ sbuf->st_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(rdata,76); /* inode */
+ sbuf->st_mode |= wire_perms_to_unix(IVAL(rdata,84)); /* protection */
+ sbuf->st_nlink = IVAL(rdata,92); /* number of hard links */
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return true;
+}
+
+/****************************************************************************
+ Symlink a file (UNIX extensions).
+****************************************************************************/
+
+bool cli_unix_symlink(struct cli_state *cli, const char *oldname, const char *newname)
+{
+ return cli_link_internal(cli, oldname, newname, False);
+}
+
+/****************************************************************************
+ Hard a file (UNIX extensions).
+****************************************************************************/
+
+bool cli_unix_hardlink(struct cli_state *cli, const char *oldname, const char *newname)
+{
+ return cli_link_internal(cli, oldname, newname, True);
+}
+
+/****************************************************************************
+ Chmod or chown a file internal (UNIX extensions).
+****************************************************************************/
+
+static bool cli_unix_chmod_chown_internal(struct cli_state *cli, const char *fname, uint32 mode, uint32 uid, uint32 gid)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ uint16 setup = TRANSACT2_SETPATHINFO;
+ size_t nlen = 2*(strlen(fname)+1);
+ char *param;
+ char data[100];
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+
+ param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
+ if (!param) {
+ return false;
+ }
+ memset(param, '\0', 6);
+ memset(data, 0, sizeof(data));
+
+ SSVAL(param,0,SMB_SET_FILE_UNIX_BASIC);
+ p = &param[6];
+
+ p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+ memset(data, 0xff, 40); /* Set all sizes/times to no change. */
+
+ SIVAL(data,40,uid);
+ SIVAL(data,48,gid);
+ SIVAL(data,84,mode);
+
+ data_len = 100;
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ (char *)&data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ SAFE_FREE(param);
+ return False;
+ }
+
+ SAFE_FREE(param);
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return false;
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return true;
+}
+
+/****************************************************************************
+ chmod a file (UNIX extensions).
+****************************************************************************/
+
+bool cli_unix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
+{
+ return cli_unix_chmod_chown_internal(cli, fname,
+ unix_perms_to_wire(mode), SMB_UID_NO_CHANGE, SMB_GID_NO_CHANGE);
+}
+
+/****************************************************************************
+ chown a file (UNIX extensions).
+****************************************************************************/
+
+bool cli_unix_chown(struct cli_state *cli, const char *fname, uid_t uid, gid_t gid)
+{
+ return cli_unix_chmod_chown_internal(cli, fname,
+ SMB_MODE_NO_CHANGE, (uint32)uid, (uint32)gid);
+}
+
+/****************************************************************************
+ Rename a file.
+****************************************************************************/
+
+bool cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,1, 0, true);
+
+ SCVAL(cli->outbuf,smb_com,SMBmv);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN | aDIR);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname_src,
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname_dst,
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return false;
+ }
+
+ if (cli_is_error(cli)) {
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************************
+ NT Rename a file.
+****************************************************************************/
+
+bool cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf, 4, 0, true);
+
+ SCVAL(cli->outbuf,smb_com,SMBntrename);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN | aDIR);
+ SSVAL(cli->outbuf,smb_vwv1, RENAME_FLAG_RENAME);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname_src,
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname_dst,
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return false;
+ }
+
+ if (cli_is_error(cli)) {
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************************
+ NT hardlink a file.
+****************************************************************************/
+
+bool cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf, 4, 0, true);
+
+ SCVAL(cli->outbuf,smb_com,SMBntrename);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN | aDIR);
+ SSVAL(cli->outbuf,smb_vwv1, RENAME_FLAG_HARD_LINK);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname_src,
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname_dst,
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return false;
+ }
+
+ if (cli_is_error(cli)) {
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************************
+ Delete a file.
+****************************************************************************/
+
+bool cli_unlink_full(struct cli_state *cli, const char *fname, uint16 attrs)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,1, 0, true);
+
+ SCVAL(cli->outbuf,smb_com,SMBunlink);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0, attrs);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname,
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return false;
+ }
+
+ if (cli_is_error(cli)) {
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************************
+ Delete a file.
+****************************************************************************/
+
+bool cli_unlink(struct cli_state *cli, const char *fname)
+{
+ return cli_unlink_full(cli, fname, aSYSTEM | aHIDDEN);
+}
+
+/****************************************************************************
+ Create a directory.
+****************************************************************************/
+
+bool cli_mkdir(struct cli_state *cli, const char *dname)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,0, 0, true);
+
+ SCVAL(cli->outbuf,smb_com,SMBmkdir);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, dname,
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Remove a directory.
+****************************************************************************/
+
+bool cli_rmdir(struct cli_state *cli, const char *dname)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,0, 0, true);
+
+ SCVAL(cli->outbuf,smb_com,SMBrmdir);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, dname,
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return false;
+ }
+
+ if (cli_is_error(cli)) {
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************************
+ Set or clear the delete on close flag.
+****************************************************************************/
+
+int cli_nt_delete_on_close(struct cli_state *cli, int fnum, bool flag)
+{
+ unsigned int data_len = 1;
+ unsigned int param_len = 6;
+ uint16 setup = TRANSACT2_SETFILEINFO;
+ char param[6];
+ unsigned char data;
+ char *rparam=NULL, *rdata=NULL;
+
+ memset(param, 0, param_len);
+ SSVAL(param,0,fnum);
+ SSVAL(param,2,SMB_SET_FILE_DISPOSITION_INFO);
+
+ data = flag ? 1 : 0;
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ (char *)&data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return false;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return false;
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return true;
+}
+
+/****************************************************************************
+ Open a file - exposing the full horror of the NT API :-).
+ Used in smbtorture.
+****************************************************************************/
+
+int cli_nt_create_full(struct cli_state *cli, const char *fname,
+ uint32 CreatFlags, uint32 DesiredAccess,
+ uint32 FileAttributes, uint32 ShareAccess,
+ uint32 CreateDisposition, uint32 CreateOptions,
+ uint8 SecurityFlags)
+{
+ char *p;
+ int len;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,24,0, true);
+
+ SCVAL(cli->outbuf,smb_com,SMBntcreateX);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,0xFF);
+ if (cli->use_oplocks)
+ CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
+
+ SIVAL(cli->outbuf,smb_ntcreate_Flags, CreatFlags);
+ SIVAL(cli->outbuf,smb_ntcreate_RootDirectoryFid, 0x0);
+ SIVAL(cli->outbuf,smb_ntcreate_DesiredAccess, DesiredAccess);
+ SIVAL(cli->outbuf,smb_ntcreate_FileAttributes, FileAttributes);
+ SIVAL(cli->outbuf,smb_ntcreate_ShareAccess, ShareAccess);
+ SIVAL(cli->outbuf,smb_ntcreate_CreateDisposition, CreateDisposition);
+ SIVAL(cli->outbuf,smb_ntcreate_CreateOptions, CreateOptions);
+ SIVAL(cli->outbuf,smb_ntcreate_ImpersonationLevel, 0x02);
+ SCVAL(cli->outbuf,smb_ntcreate_SecurityFlags, SecurityFlags);
+
+ p = smb_buf(cli->outbuf);
+ /* this alignment and termination is critical for netapp filers. Don't change */
+ p += clistr_align_out(cli, p, 0);
+ len = clistr_push(cli, p, fname,
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), 0);
+ p += len;
+ SSVAL(cli->outbuf,smb_ntcreate_NameLength, len);
+ /* sigh. this copes with broken netapp filer behaviour */
+ p += clistr_push(cli, p, "",
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return -1;
+ }
+
+ if (cli_is_error(cli)) {
+ return -1;
+ }
+
+ return SVAL(cli->inbuf,smb_vwv2 + 1);
+}
+
+/****************************************************************************
+ Open a file.
+****************************************************************************/
+
+int cli_nt_create(struct cli_state *cli, const char *fname, uint32 DesiredAccess)
+{
+ return cli_nt_create_full(cli, fname, 0, DesiredAccess, 0,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0);
+}
+
+uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2, const char *str)
+{
+ size_t buflen = talloc_get_size(buf);
+ char *converted;
+ size_t converted_size;
+
+ /*
+ * We're pushing into an SMB buffer, align odd
+ */
+ if (ucs2 && (buflen % 2 == 0)) {
+ buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t, buflen + 1);
+ if (buf == NULL) {
+ return NULL;
+ }
+ buf[buflen] = '\0';
+ buflen += 1;
+ }
+
+ if (!convert_string_allocate(talloc_tos(), CH_UNIX,
+ ucs2 ? CH_UTF16LE : CH_DOS,
+ str, strlen(str)+1, &converted,
+ &converted_size, true)) {
+ return NULL;
+ }
+
+ buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t,
+ buflen + converted_size);
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ memcpy(buf + buflen, converted, converted_size);
+
+ TALLOC_FREE(converted);
+ return buf;
+}
+
+/****************************************************************************
+ Open a file
+ WARNING: if you open with O_WRONLY then getattrE won't work!
+****************************************************************************/
+
+struct async_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ struct cli_state *cli,
+ const char *fname, int flags, int share_mode)
+{
+ unsigned openfn = 0;
+ unsigned accessmode = 0;
+ uint8_t additional_flags = 0;
+ uint8_t *bytes;
+ uint16_t vwv[15];
+ struct async_req *result;
+
+ if (flags & O_CREAT) {
+ openfn |= (1<<4);
+ }
+ if (!(flags & O_EXCL)) {
+ if (flags & O_TRUNC)
+ openfn |= (1<<1);
+ else
+ openfn |= (1<<0);
+ }
+
+ accessmode = (share_mode<<4);
+
+ if ((flags & O_ACCMODE) == O_RDWR) {
+ accessmode |= 2;
+ } else if ((flags & O_ACCMODE) == O_WRONLY) {
+ accessmode |= 1;
+ }
+
+#if defined(O_SYNC)
+ if ((flags & O_SYNC) == O_SYNC) {
+ accessmode |= (1<<14);
+ }
+#endif /* O_SYNC */
+
+ if (share_mode == DENY_FCB) {
+ accessmode = 0xFF;
+ }
+
+ SCVAL(vwv + 0, 0, 0xFF);
+ SCVAL(vwv + 0, 1, 0);
+ SSVAL(vwv + 1, 0, 0);
+ SSVAL(vwv + 2, 0, 0); /* no additional info */
+ SSVAL(vwv + 3, 0, accessmode);
+ SSVAL(vwv + 4, 0, aSYSTEM | aHIDDEN);
+ SSVAL(vwv + 5, 0, 0);
+ SIVAL(vwv + 6, 0, 0);
+ SSVAL(vwv + 8, 0, openfn);
+ SIVAL(vwv + 9, 0, 0);
+ SIVAL(vwv + 11, 0, 0);
+ SIVAL(vwv + 13, 0, 0);
+
+ if (cli->use_oplocks) {
+ /* if using oplocks then ask for a batch oplock via
+ core and extended methods */
+ additional_flags =
+ FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
+ SSVAL(vwv+2, 0, SVAL(vwv+2, 0) | 6);
+ }
+
+ bytes = talloc_array(talloc_tos(), uint8_t, 0);
+ if (bytes == NULL) {
+ return NULL;
+ }
+
+ bytes = smb_bytes_push_str(
+ bytes, (cli->capabilities & CAP_UNICODE) != 0, fname);
+ if (bytes == NULL) {
+ return NULL;
+ }
+
+ result = cli_request_send(mem_ctx, ev, cli, SMBopenX, additional_flags,
+ 15, vwv, talloc_get_size(bytes), bytes);
+ TALLOC_FREE(bytes);
+ return result;
+}
+
+NTSTATUS cli_open_recv(struct async_req *req, int *fnum)
+{
+ uint8_t wct;
+ uint16_t *vwv;
+ uint16_t num_bytes;
+ uint8_t *bytes;
+ NTSTATUS status;
+
+ SMB_ASSERT(req->state >= ASYNC_REQ_DONE);
+ if (req->state == ASYNC_REQ_ERROR) {
+ return req->status;
+ }
+
+ status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (wct < 3) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ *fnum = SVAL(vwv+2, 0);
+
+ return NT_STATUS_OK;
+}
+
+int cli_open(struct cli_state *cli, const char *fname, int flags,
+ int share_mode)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct async_req *req;
+ int result = -1;
+
+ if (cli->fd_event != NULL) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ cli_set_error(cli, NT_STATUS_INVALID_PARAMETER);
+ goto fail;
+ }
+
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+
+ req = cli_open_send(frame, ev, cli, fname, flags, share_mode);
+ if (req == NULL) {
+ goto fail;
+ }
+
+ while (req->state < ASYNC_REQ_DONE) {
+ event_loop_once(ev);
+ }
+
+ cli_open_recv(req, &result);
+ fail:
+ TALLOC_FREE(frame);
+ return result;
+}
+
+/****************************************************************************
+ Close a file.
+****************************************************************************/
+
+struct async_req *cli_close_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ struct cli_state *cli, int fnum)
+{
+ uint16_t vwv[3];
+
+ SSVAL(vwv+0, 0, fnum);
+ SIVALS(vwv+1, 0, -1);
+
+ return cli_request_send(mem_ctx, ev, cli, SMBclose, 0, 3, vwv,
+ 0, NULL);
+}
+
+NTSTATUS cli_close_recv(struct async_req *req)
+{
+ uint8_t wct;
+ uint16_t *vwv;
+ uint16_t num_bytes;
+ uint8_t *bytes;
+
+ SMB_ASSERT(req->state >= ASYNC_REQ_DONE);
+ if (req->state == ASYNC_REQ_ERROR) {
+ return req->status;
+ }
+
+ return cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
+}
+
+bool cli_close(struct cli_state *cli, int fnum)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct async_req *req;
+ bool result = false;
+
+ if (cli->fd_event != NULL) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ cli_set_error(cli, NT_STATUS_INVALID_PARAMETER);
+ goto fail;
+ }
+
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+
+ req = cli_close_send(frame, ev, cli, fnum);
+ if (req == NULL) {
+ goto fail;
+ }
+
+ while (req->state < ASYNC_REQ_DONE) {
+ event_loop_once(ev);
+ }
+
+ result = NT_STATUS_IS_OK(cli_close_recv(req));
+ fail:
+ TALLOC_FREE(frame);
+ return result;
+}
+
+/****************************************************************************
+ Truncate a file to a specified size
+****************************************************************************/
+
+bool cli_ftruncate(struct cli_state *cli, int fnum, uint64_t size)
+{
+ unsigned int param_len = 6;
+ unsigned int data_len = 8;
+ uint16 setup = TRANSACT2_SETFILEINFO;
+ char param[6];
+ unsigned char data[8];
+ char *rparam=NULL, *rdata=NULL;
+ int saved_timeout = cli->timeout;
+
+ SSVAL(param,0,fnum);
+ SSVAL(param,2,SMB_SET_FILE_END_OF_FILE_INFO);
+ SSVAL(param,4,0);
+
+ SBVAL(data, 0, size);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ (char *)&data, data_len,/* data, length, ... */
+ cli->max_xmit)) { /* ... max */
+ cli->timeout = saved_timeout;
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ cli->timeout = saved_timeout;
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return False;
+ }
+
+ cli->timeout = saved_timeout;
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return True;
+}
+
+
+/****************************************************************************
+ send a lock with a specified locktype
+ this is used for testing LOCKING_ANDX_CANCEL_LOCK
+****************************************************************************/
+
+NTSTATUS cli_locktype(struct cli_state *cli, int fnum,
+ uint32 offset, uint32 len,
+ int timeout, unsigned char locktype)
+{
+ char *p;
+ int saved_timeout = cli->timeout;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0', smb_size);
+
+ cli_set_message(cli->outbuf,8,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBlockingX);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ SCVAL(cli->outbuf,smb_vwv3,locktype);
+ SIVALS(cli->outbuf, smb_vwv4, timeout);
+ SSVAL(cli->outbuf,smb_vwv6,0);
+ SSVAL(cli->outbuf,smb_vwv7,1);
+
+ p = smb_buf(cli->outbuf);
+ SSVAL(p, 0, cli->pid);
+ SIVAL(p, 2, offset);
+ SIVAL(p, 6, len);
+
+ p += 10;
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+
+ if (timeout != 0) {
+ cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 2*1000);
+ }
+
+ if (!cli_receive_smb(cli)) {
+ cli->timeout = saved_timeout;
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ cli->timeout = saved_timeout;
+
+ return cli_nt_error(cli);
+}
+
+/****************************************************************************
+ Lock a file.
+ note that timeout is in units of 2 milliseconds
+****************************************************************************/
+
+bool cli_lock(struct cli_state *cli, int fnum,
+ uint32 offset, uint32 len, int timeout, enum brl_type lock_type)
+{
+ char *p;
+ int saved_timeout = cli->timeout;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0', smb_size);
+
+ cli_set_message(cli->outbuf,8,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBlockingX);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ SCVAL(cli->outbuf,smb_vwv3,(lock_type == READ_LOCK? 1 : 0));
+ SIVALS(cli->outbuf, smb_vwv4, timeout);
+ SSVAL(cli->outbuf,smb_vwv6,0);
+ SSVAL(cli->outbuf,smb_vwv7,1);
+
+ p = smb_buf(cli->outbuf);
+ SSVAL(p, 0, cli->pid);
+ SIVAL(p, 2, offset);
+ SIVAL(p, 6, len);
+
+ p += 10;
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+
+ if (timeout != 0) {
+ cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout*2 + 5*1000);
+ }
+
+ if (!cli_receive_smb(cli)) {
+ cli->timeout = saved_timeout;
+ return False;
+ }
+
+ cli->timeout = saved_timeout;
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Unlock a file.
+****************************************************************************/
+
+bool cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,8,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBlockingX);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ SCVAL(cli->outbuf,smb_vwv3,0);
+ SIVALS(cli->outbuf, smb_vwv4, 0);
+ SSVAL(cli->outbuf,smb_vwv6,1);
+ SSVAL(cli->outbuf,smb_vwv7,0);
+
+ p = smb_buf(cli->outbuf);
+ SSVAL(p, 0, cli->pid);
+ SIVAL(p, 2, offset);
+ SIVAL(p, 6, len);
+ p += 10;
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Lock a file with 64 bit offsets.
+****************************************************************************/
+
+bool cli_lock64(struct cli_state *cli, int fnum,
+ SMB_BIG_UINT offset, SMB_BIG_UINT len, int timeout, enum brl_type lock_type)
+{
+ char *p;
+ int saved_timeout = cli->timeout;
+ int ltype;
+
+ if (! (cli->capabilities & CAP_LARGE_FILES)) {
+ return cli_lock(cli, fnum, offset, len, timeout, lock_type);
+ }
+
+ ltype = (lock_type == READ_LOCK? 1 : 0);
+ ltype |= LOCKING_ANDX_LARGE_FILES;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0', smb_size);
+
+ cli_set_message(cli->outbuf,8,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBlockingX);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ SCVAL(cli->outbuf,smb_vwv3,ltype);
+ SIVALS(cli->outbuf, smb_vwv4, timeout);
+ SSVAL(cli->outbuf,smb_vwv6,0);
+ SSVAL(cli->outbuf,smb_vwv7,1);
+
+ p = smb_buf(cli->outbuf);
+ SIVAL(p, 0, cli->pid);
+ SOFF_T_R(p, 4, offset);
+ SOFF_T_R(p, 12, len);
+ p += 20;
+
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+
+ if (timeout != 0) {
+ cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 5*1000);
+ }
+
+ if (!cli_receive_smb(cli)) {
+ cli->timeout = saved_timeout;
+ return False;
+ }
+
+ cli->timeout = saved_timeout;
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Unlock a file with 64 bit offsets.
+****************************************************************************/
+
+bool cli_unlock64(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_UINT len)
+{
+ char *p;
+
+ if (! (cli->capabilities & CAP_LARGE_FILES)) {
+ return cli_unlock(cli, fnum, offset, len);
+ }
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,8,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBlockingX);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ SCVAL(cli->outbuf,smb_vwv3,LOCKING_ANDX_LARGE_FILES);
+ SIVALS(cli->outbuf, smb_vwv4, 0);
+ SSVAL(cli->outbuf,smb_vwv6,1);
+ SSVAL(cli->outbuf,smb_vwv7,0);
+
+ p = smb_buf(cli->outbuf);
+ SIVAL(p, 0, cli->pid);
+ SOFF_T_R(p, 4, offset);
+ SOFF_T_R(p, 12, len);
+ p += 20;
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Get/unlock a POSIX lock on a file - internal function.
+****************************************************************************/
+
+static bool cli_posix_lock_internal(struct cli_state *cli, int fnum,
+ SMB_BIG_UINT offset, SMB_BIG_UINT len, bool wait_lock, enum brl_type lock_type)
+{
+ unsigned int param_len = 4;
+ unsigned int data_len = POSIX_LOCK_DATA_SIZE;
+ uint16 setup = TRANSACT2_SETFILEINFO;
+ char param[4];
+ unsigned char data[POSIX_LOCK_DATA_SIZE];
+ char *rparam=NULL, *rdata=NULL;
+ int saved_timeout = cli->timeout;
+
+ SSVAL(param,0,fnum);
+ SSVAL(param,2,SMB_SET_POSIX_LOCK);
+
+ switch (lock_type) {
+ case READ_LOCK:
+ SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_READ);
+ break;
+ case WRITE_LOCK:
+ SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_WRITE);
+ break;
+ case UNLOCK_LOCK:
+ SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
+ break;
+ default:
+ return False;
+ }
+
+ if (wait_lock) {
+ SSVAL(data, POSIX_LOCK_FLAGS_OFFSET, POSIX_LOCK_FLAG_WAIT);
+ cli->timeout = 0x7FFFFFFF;
+ } else {
+ SSVAL(data, POSIX_LOCK_FLAGS_OFFSET, POSIX_LOCK_FLAG_NOWAIT);
+ }
+
+ SIVAL(data, POSIX_LOCK_PID_OFFSET, cli->pid);
+ SOFF_T(data, POSIX_LOCK_START_OFFSET, offset);
+ SOFF_T(data, POSIX_LOCK_LEN_OFFSET, len);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ (char *)&data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ cli->timeout = saved_timeout;
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ cli->timeout = saved_timeout;
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return False;
+ }
+
+ cli->timeout = saved_timeout;
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return True;
+}
+
+/****************************************************************************
+ POSIX Lock a file.
+****************************************************************************/
+
+bool cli_posix_lock(struct cli_state *cli, int fnum,
+ SMB_BIG_UINT offset, SMB_BIG_UINT len,
+ bool wait_lock, enum brl_type lock_type)
+{
+ if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
+ return False;
+ }
+ return cli_posix_lock_internal(cli, fnum, offset, len, wait_lock, lock_type);
+}
+
+/****************************************************************************
+ POSIX Unlock a file.
+****************************************************************************/
+
+bool cli_posix_unlock(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_UINT len)
+{
+ return cli_posix_lock_internal(cli, fnum, offset, len, False, UNLOCK_LOCK);
+}
+
+/****************************************************************************
+ POSIX Get any lock covering a file.
+****************************************************************************/
+
+bool cli_posix_getlock(struct cli_state *cli, int fnum, SMB_BIG_UINT *poffset, SMB_BIG_UINT *plen)
+{
+ return True;
+}
+
+/****************************************************************************
+ Do a SMBgetattrE call.
+****************************************************************************/
+
+bool cli_getattrE(struct cli_state *cli, int fd,
+ uint16 *attr, SMB_OFF_T *size,
+ time_t *change_time,
+ time_t *access_time,
+ time_t *write_time)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,1,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBgetattrE);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,fd);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ if (size) {
+ *size = IVAL(cli->inbuf, smb_vwv6);
+ }
+
+ if (attr) {
+ *attr = SVAL(cli->inbuf,smb_vwv10);
+ }
+
+ if (change_time) {
+ *change_time = cli_make_unix_date2(cli, cli->inbuf+smb_vwv0);
+ }
+
+ if (access_time) {
+ *access_time = cli_make_unix_date2(cli, cli->inbuf+smb_vwv2);
+ }
+
+ if (write_time) {
+ *write_time = cli_make_unix_date2(cli, cli->inbuf+smb_vwv4);
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Do a SMBgetatr call
+****************************************************************************/
+
+bool cli_getatr(struct cli_state *cli, const char *fname,
+ uint16 *attr, SMB_OFF_T *size, time_t *write_time)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,0,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBgetatr);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname,
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ if (size) {
+ *size = IVAL(cli->inbuf, smb_vwv3);
+ }
+
+ if (write_time) {
+ *write_time = cli_make_unix_date3(cli, cli->inbuf+smb_vwv1);
+ }
+
+ if (attr) {
+ *attr = SVAL(cli->inbuf,smb_vwv0);
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Do a SMBsetattrE call.
+****************************************************************************/
+
+bool cli_setattrE(struct cli_state *cli, int fd,
+ time_t change_time,
+ time_t access_time,
+ time_t write_time)
+
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,7,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBsetattrE);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0, fd);
+ cli_put_dos_date2(cli, cli->outbuf,smb_vwv1, change_time);
+ cli_put_dos_date2(cli, cli->outbuf,smb_vwv3, access_time);
+ cli_put_dos_date2(cli, cli->outbuf,smb_vwv5, write_time);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Do a SMBsetatr call.
+****************************************************************************/
+
+bool cli_setatr(struct cli_state *cli, const char *fname, uint16 attr, time_t t)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,8,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBsetatr);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0, attr);
+ cli_put_dos_date3(cli, cli->outbuf,smb_vwv1, t);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname,
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
+ *p++ = 4;
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Check for existance of a dir.
+****************************************************************************/
+
+bool cli_chkpath(struct cli_state *cli, const char *path)
+{
+ char *path2 = NULL;
+ char *p;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ path2 = talloc_strdup(frame, path);
+ if (!path2) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+ trim_char(path2,'\0','\\');
+ if (!*path2) {
+ path2 = talloc_strdup(frame, "\\");
+ if (!path2) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+ }
+
+ memset(cli->outbuf,'\0',smb_size);
+ cli_set_message(cli->outbuf,0,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBcheckpath);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, path2,
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ TALLOC_FREE(frame);
+
+ if (cli_is_error(cli)) return False;
+
+ return True;
+}
+
+/****************************************************************************
+ Query disk space.
+****************************************************************************/
+
+bool cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ cli_set_message(cli->outbuf,0,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBdskattr);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ *bsize = SVAL(cli->inbuf,smb_vwv1)*SVAL(cli->inbuf,smb_vwv2);
+ *total = SVAL(cli->inbuf,smb_vwv0);
+ *avail = SVAL(cli->inbuf,smb_vwv3);
+
+ return True;
+}
+
+/****************************************************************************
+ Create and open a temporary file.
+****************************************************************************/
+
+int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path)
+{
+ int len;
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,3,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBctemp);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,0);
+ SIVALS(cli->outbuf,smb_vwv1,-1);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, path,
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return -1;
+ }
+
+ if (cli_is_error(cli)) {
+ return -1;
+ }
+
+ /* despite the spec, the result has a -1, followed by
+ length, followed by name */
+ p = smb_buf(cli->inbuf);
+ p += 4;
+ len = smb_buflen(cli->inbuf) - 4;
+ if (len <= 0 || len > PATH_MAX) return -1;
+
+ if (tmp_path) {
+ char *path2 = SMB_MALLOC_ARRAY(char, len+1);
+ if (!path2) {
+ return -1;
+ }
+ clistr_pull(cli, path2, p,
+ len+1, len, STR_ASCII);
+ *tmp_path = path2;
+ }
+
+ return SVAL(cli->inbuf,smb_vwv0);
+}
+
+/*
+ send a raw ioctl - used by the torture code
+*/
+NTSTATUS cli_raw_ioctl(struct cli_state *cli, int fnum, uint32 code, DATA_BLOB *blob)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf, 3, 0, True);
+ SCVAL(cli->outbuf,smb_com,SMBioctl);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf, smb_vwv0, fnum);
+ SSVAL(cli->outbuf, smb_vwv1, code>>16);
+ SSVAL(cli->outbuf, smb_vwv2, (code&0xFFFF));
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ }
+
+ if (cli_is_error(cli)) {
+ return cli_nt_error(cli);
+ }
+
+ *blob = data_blob_null;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************
+ Set an extended attribute utility fn.
+*********************************************************/
+
+static bool cli_set_ea(struct cli_state *cli, uint16 setup, char *param, unsigned int param_len,
+ const char *ea_name, const char *ea_val, size_t ea_len)
+{
+ unsigned int data_len = 0;
+ char *data = NULL;
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+ size_t ea_namelen = strlen(ea_name);
+
+ if (ea_namelen == 0 && ea_len == 0) {
+ data_len = 4;
+ data = (char *)SMB_MALLOC(data_len);
+ if (!data) {
+ return False;
+ }
+ p = data;
+ SIVAL(p,0,data_len);
+ } else {
+ data_len = 4 + 4 + ea_namelen + 1 + ea_len;
+ data = (char *)SMB_MALLOC(data_len);
+ if (!data) {
+ return False;
+ }
+ p = data;
+ SIVAL(p,0,data_len);
+ p += 4;
+ SCVAL(p, 0, 0); /* EA flags. */
+ SCVAL(p, 1, ea_namelen);
+ SSVAL(p, 2, ea_len);
+ memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
+ memcpy(p+4+ea_namelen+1, ea_val, ea_len);
+ }
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ SAFE_FREE(data);
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ SAFE_FREE(data);
+ return false;
+ }
+
+ SAFE_FREE(data);
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return True;
+}
+
+/*********************************************************
+ Set an extended attribute on a pathname.
+*********************************************************/
+
+bool cli_set_ea_path(struct cli_state *cli, const char *path, const char *ea_name, const char *ea_val, size_t ea_len)
+{
+ uint16 setup = TRANSACT2_SETPATHINFO;
+ unsigned int param_len = 0;
+ char *param;
+ size_t srclen = 2*(strlen(path)+1);
+ char *p;
+ bool ret;
+
+ param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
+ if (!param) {
+ return false;
+ }
+ memset(param, '\0', 6);
+ SSVAL(param,0,SMB_INFO_SET_EA);
+ p = &param[6];
+
+ p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+ ret = cli_set_ea(cli, setup, param, param_len, ea_name, ea_val, ea_len);
+ SAFE_FREE(param);
+ return ret;
+}
+
+/*********************************************************
+ Set an extended attribute on an fnum.
+*********************************************************/
+
+bool cli_set_ea_fnum(struct cli_state *cli, int fnum, const char *ea_name, const char *ea_val, size_t ea_len)
+{
+ char param[6];
+ uint16 setup = TRANSACT2_SETFILEINFO;
+
+ memset(param, 0, 6);
+ SSVAL(param,0,fnum);
+ SSVAL(param,2,SMB_INFO_SET_EA);
+
+ return cli_set_ea(cli, setup, param, 6, ea_name, ea_val, ea_len);
+}
+
+/*********************************************************
+ Get an extended attribute list utility fn.
+*********************************************************/
+
+static bool cli_get_ea_list(struct cli_state *cli,
+ uint16 setup, char *param, unsigned int param_len,
+ TALLOC_CTX *ctx,
+ size_t *pnum_eas,
+ struct ea_struct **pea_list)
+{
+ unsigned int data_len = 0;
+ unsigned int rparam_len, rdata_len;
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+ size_t ea_size;
+ size_t num_eas;
+ bool ret = False;
+ struct ea_struct *ea_list;
+
+ *pnum_eas = 0;
+ if (pea_list) {
+ *pea_list = NULL;
+ }
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* Name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 10, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &rparam_len,
+ &rdata, &rdata_len)) {
+ return False;
+ }
+
+ if (!rdata || rdata_len < 4) {
+ goto out;
+ }
+
+ ea_size = (size_t)IVAL(rdata,0);
+ if (ea_size > rdata_len) {
+ goto out;
+ }
+
+ if (ea_size == 0) {
+ /* No EA's present. */
+ ret = True;
+ goto out;
+ }
+
+ p = rdata + 4;
+ ea_size -= 4;
+
+ /* Validate the EA list and count it. */
+ for (num_eas = 0; ea_size >= 4; num_eas++) {
+ unsigned int ea_namelen = CVAL(p,1);
+ unsigned int ea_valuelen = SVAL(p,2);
+ if (ea_namelen == 0) {
+ goto out;
+ }
+ if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
+ goto out;
+ }
+ ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
+ p += 4 + ea_namelen + 1 + ea_valuelen;
+ }
+
+ if (num_eas == 0) {
+ ret = True;
+ goto out;
+ }
+
+ *pnum_eas = num_eas;
+ if (!pea_list) {
+ /* Caller only wants number of EA's. */
+ ret = True;
+ goto out;
+ }
+
+ ea_list = TALLOC_ARRAY(ctx, struct ea_struct, num_eas);
+ if (!ea_list) {
+ goto out;
+ }
+
+ ea_size = (size_t)IVAL(rdata,0);
+ p = rdata + 4;
+
+ for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
+ struct ea_struct *ea = &ea_list[num_eas];
+ fstring unix_ea_name;
+ unsigned int ea_namelen = CVAL(p,1);
+ unsigned int ea_valuelen = SVAL(p,2);
+
+ ea->flags = CVAL(p,0);
+ unix_ea_name[0] = '\0';
+ pull_ascii_fstring(unix_ea_name, p + 4);
+ ea->name = talloc_strdup(ctx, unix_ea_name);
+ /* Ensure the value is null terminated (in case it's a string). */
+ ea->value = data_blob_talloc(ctx, NULL, ea_valuelen + 1);
+ if (!ea->value.data) {
+ goto out;
+ }
+ if (ea_valuelen) {
+ memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
+ }
+ ea->value.data[ea_valuelen] = 0;
+ ea->value.length--;
+ p += 4 + ea_namelen + 1 + ea_valuelen;
+ }
+
+ *pea_list = ea_list;
+ ret = True;
+
+ out :
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return ret;
+}
+
+/*********************************************************
+ Get an extended attribute list from a pathname.
+*********************************************************/
+
+bool cli_get_ea_list_path(struct cli_state *cli, const char *path,
+ TALLOC_CTX *ctx,
+ size_t *pnum_eas,
+ struct ea_struct **pea_list)
+{
+ uint16 setup = TRANSACT2_QPATHINFO;
+ unsigned int param_len = 0;
+ char *param;
+ char *p;
+ size_t srclen = 2*(strlen(path)+1);
+ bool ret;
+
+ param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
+ if (!param) {
+ return false;
+ }
+ p = param;
+ memset(p, 0, 6);
+ SSVAL(p, 0, SMB_INFO_QUERY_ALL_EAS);
+ p += 6;
+ p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+ ret = cli_get_ea_list(cli, setup, param, param_len, ctx, pnum_eas, pea_list);
+ SAFE_FREE(param);
+ return ret;
+}
+
+/*********************************************************
+ Get an extended attribute list from an fnum.
+*********************************************************/
+
+bool cli_get_ea_list_fnum(struct cli_state *cli, int fnum,
+ TALLOC_CTX *ctx,
+ size_t *pnum_eas,
+ struct ea_struct **pea_list)
+{
+ uint16 setup = TRANSACT2_QFILEINFO;
+ char param[6];
+
+ memset(param, 0, 6);
+ SSVAL(param,0,fnum);
+ SSVAL(param,2,SMB_INFO_SET_EA);
+
+ return cli_get_ea_list(cli, setup, param, 6, ctx, pnum_eas, pea_list);
+}
+
+/****************************************************************************
+ Convert open "flags" arg to uint32 on wire.
+****************************************************************************/
+
+static uint32 open_flags_to_wire(int flags)
+{
+ int open_mode = flags & O_ACCMODE;
+ uint32 ret = 0;
+
+ switch (open_mode) {
+ case O_WRONLY:
+ ret |= SMB_O_WRONLY;
+ break;
+ case O_RDWR:
+ ret |= SMB_O_RDWR;
+ break;
+ default:
+ case O_RDONLY:
+ ret |= SMB_O_RDONLY;
+ break;
+ }
+
+ if (flags & O_CREAT) {
+ ret |= SMB_O_CREAT;
+ }
+ if (flags & O_EXCL) {
+ ret |= SMB_O_EXCL;
+ }
+ if (flags & O_TRUNC) {
+ ret |= SMB_O_TRUNC;
+ }
+#if defined(O_SYNC)
+ if (flags & O_SYNC) {
+ ret |= SMB_O_SYNC;
+ }
+#endif /* O_SYNC */
+ if (flags & O_APPEND) {
+ ret |= SMB_O_APPEND;
+ }
+#if defined(O_DIRECT)
+ if (flags & O_DIRECT) {
+ ret |= SMB_O_DIRECT;
+ }
+#endif
+#if defined(O_DIRECTORY)
+ if (flags & O_DIRECTORY) {
+ ret &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
+ ret |= SMB_O_DIRECTORY;
+ }
+#endif
+ return ret;
+}
+
+/****************************************************************************
+ Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
+****************************************************************************/
+
+static int cli_posix_open_internal(struct cli_state *cli, const char *fname, int flags, mode_t mode, bool is_dir)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ uint16 setup = TRANSACT2_SETPATHINFO;
+ char *param;
+ char data[18];
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+ int fnum = -1;
+ uint32 wire_flags = open_flags_to_wire(flags);
+ size_t srclen = 2*(strlen(fname)+1);
+
+ param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
+ if (!param) {
+ return false;
+ }
+ memset(param, '\0', 6);
+ SSVAL(param,0, SMB_POSIX_PATH_OPEN);
+ p = &param[6];
+
+ p += clistr_push(cli, p, fname, srclen, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+ if (is_dir) {
+ wire_flags &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
+ wire_flags |= SMB_O_DIRECTORY;
+ }
+
+ p = data;
+ SIVAL(p,0,0); /* No oplock. */
+ SIVAL(p,4,wire_flags);
+ SIVAL(p,8,unix_perms_to_wire(mode));
+ SIVAL(p,12,0); /* Top bits of perms currently undefined. */
+ SSVAL(p,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
+
+ data_len = 18;
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ (char *)&data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ SAFE_FREE(param);
+ return -1;
+ }
+
+ SAFE_FREE(param);
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return -1;
+ }
+
+ fnum = SVAL(rdata,2);
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return fnum;
+}
+
+/****************************************************************************
+ open - POSIX semantics.
+****************************************************************************/
+
+int cli_posix_open(struct cli_state *cli, const char *fname, int flags, mode_t mode)
+{
+ return cli_posix_open_internal(cli, fname, flags, mode, False);
+}
+
+/****************************************************************************
+ mkdir - POSIX semantics.
+****************************************************************************/
+
+int cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
+{
+ return (cli_posix_open_internal(cli, fname, O_CREAT, mode, True) == -1) ? -1 : 0;
+}
+
+/****************************************************************************
+ unlink or rmdir - POSIX semantics.
+****************************************************************************/
+
+static bool cli_posix_unlink_internal(struct cli_state *cli, const char *fname, bool is_dir)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ uint16 setup = TRANSACT2_SETPATHINFO;
+ char *param;
+ char data[2];
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+ size_t srclen = 2*(strlen(fname)+1);
+
+ param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
+ if (!param) {
+ return false;
+ }
+ memset(param, '\0', 6);
+ SSVAL(param,0, SMB_POSIX_PATH_UNLINK);
+ p = &param[6];
+
+ p += clistr_push(cli, p, fname, srclen, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+ SSVAL(data, 0, is_dir ? SMB_POSIX_UNLINK_DIRECTORY_TARGET :
+ SMB_POSIX_UNLINK_FILE_TARGET);
+ data_len = 2;
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ (char *)&data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ SAFE_FREE(param);
+ return False;
+ }
+
+ SAFE_FREE(param);
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return True;
+}
+
+/****************************************************************************
+ unlink - POSIX semantics.
+****************************************************************************/
+
+bool cli_posix_unlink(struct cli_state *cli, const char *fname)
+{
+ return cli_posix_unlink_internal(cli, fname, False);
+}
+
+/****************************************************************************
+ rmdir - POSIX semantics.
+****************************************************************************/
+
+int cli_posix_rmdir(struct cli_state *cli, const char *fname)
+{
+ return cli_posix_unlink_internal(cli, fname, True);
+}
diff --git a/source3/libsmb/clifsinfo.c b/source3/libsmb/clifsinfo.c
new file mode 100644
index 0000000000..5e73b61cd2
--- /dev/null
+++ b/source3/libsmb/clifsinfo.c
@@ -0,0 +1,664 @@
+/*
+ Unix SMB/CIFS implementation.
+ FS info functions
+ Copyright (C) Stefan (metze) Metzmacher 2003
+ Copyright (C) Jeremy Allison 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Get UNIX extensions version info.
+****************************************************************************/
+
+bool cli_unix_extensions_version(struct cli_state *cli, uint16 *pmajor, uint16 *pminor,
+ uint32 *pcaplow, uint32 *pcaphigh)
+{
+ bool ret = False;
+ uint16 setup;
+ char param[2];
+ char *rparam=NULL, *rdata=NULL;
+ unsigned int rparam_count=0, rdata_count=0;
+
+ setup = TRANSACT2_QFSINFO;
+
+ SSVAL(param,0,SMB_QUERY_CIFS_UNIX_INFO);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL,
+ 0, 0,
+ &setup, 1, 0,
+ param, 2, 0,
+ NULL, 0, 560)) {
+ goto cleanup;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ goto cleanup;
+ }
+
+ if (cli_is_error(cli)) {
+ ret = False;
+ goto cleanup;
+ } else {
+ ret = True;
+ }
+
+ if (rdata_count < 12) {
+ goto cleanup;
+ }
+
+ *pmajor = SVAL(rdata,0);
+ *pminor = SVAL(rdata,2);
+ cli->posix_capabilities = *pcaplow = IVAL(rdata,4);
+ *pcaphigh = IVAL(rdata,8);
+
+ /* todo: but not yet needed
+ * return the other stuff
+ */
+
+cleanup:
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return ret;
+}
+
+/****************************************************************************
+ Set UNIX extensions capabilities.
+****************************************************************************/
+
+bool cli_set_unix_extensions_capabilities(struct cli_state *cli, uint16 major, uint16 minor,
+ uint32 caplow, uint32 caphigh)
+{
+ bool ret = False;
+ uint16 setup;
+ char param[4];
+ char data[12];
+ char *rparam=NULL, *rdata=NULL;
+ unsigned int rparam_count=0, rdata_count=0;
+
+ setup = TRANSACT2_SETFSINFO;
+
+ SSVAL(param,0,0);
+ SSVAL(param,2,SMB_SET_CIFS_UNIX_INFO);
+
+ SSVAL(data,0,major);
+ SSVAL(data,2,minor);
+ SIVAL(data,4,caplow);
+ SIVAL(data,8,caphigh);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL,
+ 0, 0,
+ &setup, 1, 0,
+ param, 4, 0,
+ data, 12, 560)) {
+ goto cleanup;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ goto cleanup;
+ }
+
+ if (cli_is_error(cli)) {
+ ret = False;
+ goto cleanup;
+ } else {
+ ret = True;
+ }
+
+cleanup:
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return ret;
+}
+
+bool cli_get_fs_attr_info(struct cli_state *cli, uint32 *fs_attr)
+{
+ bool ret = False;
+ uint16 setup;
+ char param[2];
+ char *rparam=NULL, *rdata=NULL;
+ unsigned int rparam_count=0, rdata_count=0;
+
+ if (!cli||!fs_attr)
+ smb_panic("cli_get_fs_attr_info() called with NULL Pionter!");
+
+ setup = TRANSACT2_QFSINFO;
+
+ SSVAL(param,0,SMB_QUERY_FS_ATTRIBUTE_INFO);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL,
+ 0, 0,
+ &setup, 1, 0,
+ param, 2, 0,
+ NULL, 0, 560)) {
+ goto cleanup;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ goto cleanup;
+ }
+
+ if (cli_is_error(cli)) {
+ ret = False;
+ goto cleanup;
+ } else {
+ ret = True;
+ }
+
+ if (rdata_count < 12) {
+ goto cleanup;
+ }
+
+ *fs_attr = IVAL(rdata,0);
+
+ /* todo: but not yet needed
+ * return the other stuff
+ */
+
+cleanup:
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return ret;
+}
+
+bool cli_get_fs_volume_info_old(struct cli_state *cli, fstring volume_name, uint32 *pserial_number)
+{
+ bool ret = False;
+ uint16 setup;
+ char param[2];
+ char *rparam=NULL, *rdata=NULL;
+ unsigned int rparam_count=0, rdata_count=0;
+ unsigned char nlen;
+
+ setup = TRANSACT2_QFSINFO;
+
+ SSVAL(param,0,SMB_INFO_VOLUME);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL,
+ 0, 0,
+ &setup, 1, 0,
+ param, 2, 0,
+ NULL, 0, 560)) {
+ goto cleanup;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ goto cleanup;
+ }
+
+ if (cli_is_error(cli)) {
+ ret = False;
+ goto cleanup;
+ } else {
+ ret = True;
+ }
+
+ if (rdata_count < 5) {
+ goto cleanup;
+ }
+
+ if (pserial_number) {
+ *pserial_number = IVAL(rdata,0);
+ }
+ nlen = CVAL(rdata,l2_vol_cch);
+ clistr_pull(cli, volume_name, rdata + l2_vol_szVolLabel, sizeof(fstring), nlen, STR_NOALIGN);
+
+ /* todo: but not yet needed
+ * return the other stuff
+ */
+
+cleanup:
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return ret;
+}
+
+bool cli_get_fs_volume_info(struct cli_state *cli, fstring volume_name, uint32 *pserial_number, time_t *pdate)
+{
+ bool ret = False;
+ uint16 setup;
+ char param[2];
+ char *rparam=NULL, *rdata=NULL;
+ unsigned int rparam_count=0, rdata_count=0;
+ unsigned int nlen;
+
+ setup = TRANSACT2_QFSINFO;
+
+ SSVAL(param,0,SMB_QUERY_FS_VOLUME_INFO);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL,
+ 0, 0,
+ &setup, 1, 0,
+ param, 2, 0,
+ NULL, 0, 560)) {
+ goto cleanup;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ goto cleanup;
+ }
+
+ if (cli_is_error(cli)) {
+ ret = False;
+ goto cleanup;
+ } else {
+ ret = True;
+ }
+
+ if (rdata_count < 19) {
+ goto cleanup;
+ }
+
+ if (pdate) {
+ struct timespec ts;
+ ts = interpret_long_date(rdata);
+ *pdate = ts.tv_sec;
+ }
+ if (pserial_number) {
+ *pserial_number = IVAL(rdata,8);
+ }
+ nlen = IVAL(rdata,12);
+ clistr_pull(cli, volume_name, rdata + 18, sizeof(fstring), nlen, STR_UNICODE);
+
+ /* todo: but not yet needed
+ * return the other stuff
+ */
+
+cleanup:
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return ret;
+}
+
+/******************************************************************************
+ Send/receive the request encryption blob.
+******************************************************************************/
+
+static NTSTATUS enc_blob_send_receive(struct cli_state *cli, DATA_BLOB *in, DATA_BLOB *out, DATA_BLOB *param_out)
+{
+ uint16 setup;
+ char param[4];
+ char *rparam=NULL, *rdata=NULL;
+ unsigned int rparam_count=0, rdata_count=0;
+ NTSTATUS status = NT_STATUS_OK;
+
+ setup = TRANSACT2_SETFSINFO;
+
+ SSVAL(param,0,0);
+ SSVAL(param,2,SMB_REQUEST_TRANSPORT_ENCRYPTION);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL,
+ 0, 0,
+ &setup, 1, 0,
+ param, 4, 0,
+ (char *)in->data, in->length, CLI_BUFFER_SIZE)) {
+ status = cli_nt_error(cli);
+ goto out;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ status = cli_nt_error(cli);
+ goto out;
+ }
+
+ if (cli_is_error(cli)) {
+ status = cli_nt_error(cli);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ goto out;
+ }
+ }
+
+ *out = data_blob(rdata, rdata_count);
+ *param_out = data_blob(rparam, rparam_count);
+
+ out:
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+ return status;
+}
+
+/******************************************************************************
+ Make a client state struct.
+******************************************************************************/
+
+static struct smb_trans_enc_state *make_cli_enc_state(enum smb_trans_enc_type smb_enc_type)
+{
+ struct smb_trans_enc_state *es = NULL;
+ es = SMB_MALLOC_P(struct smb_trans_enc_state);
+ if (!es) {
+ return NULL;
+ }
+ ZERO_STRUCTP(es);
+ es->smb_enc_type = smb_enc_type;
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+ if (smb_enc_type == SMB_TRANS_ENC_GSS) {
+ es->s.gss_state = SMB_MALLOC_P(struct smb_tran_enc_state_gss);
+ if (!es->s.gss_state) {
+ SAFE_FREE(es);
+ return NULL;
+ }
+ ZERO_STRUCTP(es->s.gss_state);
+ }
+#endif
+ return es;
+}
+
+/******************************************************************************
+ Start a raw ntlmssp encryption.
+******************************************************************************/
+
+NTSTATUS cli_raw_ntlm_smb_encryption_start(struct cli_state *cli,
+ const char *user,
+ const char *pass,
+ const char *domain)
+{
+ DATA_BLOB blob_in = data_blob_null;
+ DATA_BLOB blob_out = data_blob_null;
+ DATA_BLOB param_out = data_blob_null;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_NTLM);
+
+ if (!es) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ status = ntlmssp_client_start(&es->s.ntlmssp_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ ntlmssp_want_feature(es->s.ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);
+ es->s.ntlmssp_state->neg_flags |= (NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_SEAL);
+
+ if (!NT_STATUS_IS_OK(status = ntlmssp_set_username(es->s.ntlmssp_state, user))) {
+ goto fail;
+ }
+ if (!NT_STATUS_IS_OK(status = ntlmssp_set_domain(es->s.ntlmssp_state, domain))) {
+ goto fail;
+ }
+ if (!NT_STATUS_IS_OK(status = ntlmssp_set_password(es->s.ntlmssp_state, pass))) {
+ goto fail;
+ }
+
+ do {
+ status = ntlmssp_update(es->s.ntlmssp_state, blob_in, &blob_out);
+ data_blob_free(&blob_in);
+ data_blob_free(&param_out);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(status)) {
+ NTSTATUS trans_status = enc_blob_send_receive(cli,
+ &blob_out,
+ &blob_in,
+ &param_out);
+ if (!NT_STATUS_EQUAL(trans_status,
+ NT_STATUS_MORE_PROCESSING_REQUIRED) &&
+ !NT_STATUS_IS_OK(trans_status)) {
+ status = trans_status;
+ } else {
+ if (param_out.length == 2) {
+ es->enc_ctx_num = SVAL(param_out.data, 0);
+ }
+ }
+ }
+ data_blob_free(&blob_out);
+ } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
+
+ data_blob_free(&blob_in);
+
+ if (NT_STATUS_IS_OK(status)) {
+ /* Replace the old state, if any. */
+ if (cli->trans_enc_state) {
+ common_free_encryption_state(&cli->trans_enc_state);
+ }
+ cli->trans_enc_state = es;
+ cli->trans_enc_state->enc_on = True;
+ es = NULL;
+ }
+
+ fail:
+
+ common_free_encryption_state(&es);
+ return status;
+}
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+
+#ifndef SMB_GSS_REQUIRED_FLAGS
+#define SMB_GSS_REQUIRED_FLAGS (GSS_C_CONF_FLAG|GSS_C_INTEG_FLAG|GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)
+#endif
+
+/******************************************************************************
+ Get client gss blob to send to a server.
+******************************************************************************/
+
+static NTSTATUS make_cli_gss_blob(struct smb_trans_enc_state *es,
+ const char *service,
+ const char *host,
+ NTSTATUS status_in,
+ DATA_BLOB spnego_blob_in,
+ DATA_BLOB *p_blob_out)
+{
+ const char *krb_mechs[] = {OID_KERBEROS5, NULL};
+ OM_uint32 ret;
+ OM_uint32 min;
+ gss_name_t srv_name;
+ gss_buffer_desc input_name;
+ gss_buffer_desc *p_tok_in;
+ gss_buffer_desc tok_out, tok_in;
+ DATA_BLOB blob_out = data_blob_null;
+ DATA_BLOB blob_in = data_blob_null;
+ char *host_princ_s = NULL;
+ OM_uint32 ret_flags = 0;
+ NTSTATUS status = NT_STATUS_OK;
+
+ gss_OID_desc nt_hostbased_service =
+ {10, CONST_DISCARD(char *,"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04")};
+
+ memset(&tok_out, '\0', sizeof(tok_out));
+
+ /* Get a ticket for the service@host */
+ if (asprintf(&host_princ_s, "%s@%s", service, host) == -1) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ input_name.value = host_princ_s;
+ input_name.length = strlen(host_princ_s) + 1;
+
+ ret = gss_import_name(&min,
+ &input_name,
+ &nt_hostbased_service,
+ &srv_name);
+
+ if (ret != GSS_S_COMPLETE) {
+ SAFE_FREE(host_princ_s);
+ return map_nt_error_from_gss(ret, min);
+ }
+
+ if (spnego_blob_in.length == 0) {
+ p_tok_in = GSS_C_NO_BUFFER;
+ } else {
+ /* Remove the SPNEGO wrapper */
+ if (!spnego_parse_auth_response(spnego_blob_in, status_in, OID_KERBEROS5, &blob_in)) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ goto fail;
+ }
+ tok_in.value = blob_in.data;
+ tok_in.length = blob_in.length;
+ p_tok_in = &tok_in;
+ }
+
+ ret = gss_init_sec_context(&min,
+ GSS_C_NO_CREDENTIAL, /* Use our default cred. */
+ &es->s.gss_state->gss_ctx,
+ srv_name,
+ GSS_C_NO_OID, /* default OID. */
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG,
+ GSS_C_INDEFINITE, /* requested ticket lifetime. */
+ NULL, /* no channel bindings */
+ p_tok_in,
+ NULL, /* ignore mech type */
+ &tok_out,
+ &ret_flags,
+ NULL); /* ignore time_rec */
+
+ status = map_nt_error_from_gss(ret, min);
+ if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ ADS_STATUS adss = ADS_ERROR_GSS(ret, min);
+ DEBUG(10,("make_cli_gss_blob: gss_init_sec_context failed with %s\n",
+ ads_errstr(adss)));
+ goto fail;
+ }
+
+ if ((ret_flags & SMB_GSS_REQUIRED_FLAGS) != SMB_GSS_REQUIRED_FLAGS) {
+ status = NT_STATUS_ACCESS_DENIED;
+ }
+
+ blob_out = data_blob(tok_out.value, tok_out.length);
+
+ /* Wrap in an SPNEGO wrapper */
+ *p_blob_out = gen_negTokenTarg(krb_mechs, blob_out);
+
+ fail:
+
+ data_blob_free(&blob_out);
+ data_blob_free(&blob_in);
+ SAFE_FREE(host_princ_s);
+ gss_release_name(&min, &srv_name);
+ if (tok_out.value) {
+ gss_release_buffer(&min, &tok_out);
+ }
+ return status;
+}
+
+/******************************************************************************
+ Start a SPNEGO gssapi encryption context.
+******************************************************************************/
+
+NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
+{
+ DATA_BLOB blob_recv = data_blob_null;
+ DATA_BLOB blob_send = data_blob_null;
+ DATA_BLOB param_out = data_blob_null;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ fstring fqdn;
+ const char *servicename;
+ struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_GSS);
+
+ if (!es) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ name_to_fqdn(fqdn, cli->desthost);
+ strlower_m(fqdn);
+
+ servicename = "cifs";
+ status = make_cli_gss_blob(es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send);
+ if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ servicename = "host";
+ status = make_cli_gss_blob(es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send);
+ if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ goto fail;
+ }
+ }
+
+ do {
+ data_blob_free(&blob_recv);
+ status = enc_blob_send_receive(cli, &blob_send, &blob_recv, &param_out);
+ if (param_out.length == 2) {
+ es->enc_ctx_num = SVAL(param_out.data, 0);
+ }
+ data_blob_free(&blob_send);
+ status = make_cli_gss_blob(es, servicename, fqdn, status, blob_recv, &blob_send);
+ } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
+ data_blob_free(&blob_recv);
+
+ if (NT_STATUS_IS_OK(status)) {
+ /* Replace the old state, if any. */
+ if (cli->trans_enc_state) {
+ common_free_encryption_state(&cli->trans_enc_state);
+ }
+ cli->trans_enc_state = es;
+ cli->trans_enc_state->enc_on = True;
+ es = NULL;
+ }
+
+ fail:
+
+ common_free_encryption_state(&es);
+ return status;
+}
+#else
+NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
+{
+ return NT_STATUS_NOT_SUPPORTED;
+}
+#endif
+
+/********************************************************************
+ Ensure a connection is encrypted.
+********************************************************************/
+
+NTSTATUS cli_force_encryption(struct cli_state *c,
+ const char *username,
+ const char *password,
+ const char *domain)
+{
+ uint16 major, minor;
+ uint32 caplow, caphigh;
+
+ if (!SERVER_HAS_UNIX_CIFS(c)) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ if (!cli_unix_extensions_version(c, &major, &minor, &caplow, &caphigh)) {
+ return NT_STATUS_UNKNOWN_REVISION;
+ }
+
+ if (!(caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)) {
+ return NT_STATUS_UNSUPPORTED_COMPRESSION;
+ }
+
+ if (c->use_kerberos) {
+ return cli_gss_smb_encryption_start(c);
+ }
+ return cli_raw_ntlm_smb_encryption_start(c,
+ username,
+ password,
+ domain);
+}
diff --git a/source3/libsmb/clikrb5.c b/source3/libsmb/clikrb5.c
new file mode 100644
index 0000000000..b8afb57977
--- /dev/null
+++ b/source3/libsmb/clikrb5.c
@@ -0,0 +1,1923 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple kerberos5 routines for active directory
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Luke Howard 2002-2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+ Copyright (C) Guenther Deschner 2005-2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define KRB5_PRIVATE 1 /* this file uses PRIVATE interfaces! */
+#define KRB5_DEPRECATED 1 /* this file uses DEPRECATED interfaces! */
+
+#include "includes.h"
+
+#ifdef HAVE_KRB5
+
+#define GSSAPI_CHECKSUM 0x8003 /* Checksum type value for Kerberos */
+#define GSSAPI_BNDLENGTH 16 /* Bind Length (rfc-1964 pg.3) */
+#define GSSAPI_CHECKSUM_SIZE (12+GSSAPI_BNDLENGTH)
+
+#if defined(TKT_FLG_OK_AS_DELEGATE ) && defined(HAVE_KRB5_FWD_TGT_CREDS) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE) && defined(KRB5_AUTH_CONTEXT_USE_SUBKEY)
+static krb5_error_code ads_krb5_get_fwd_ticket( krb5_context context,
+ krb5_auth_context *auth_context,
+ krb5_creds *credsp,
+ krb5_ccache ccache,
+ krb5_data *authenticator);
+#endif
+
+/**************************************************************
+ Wrappers around kerberos string functions that convert from
+ utf8 -> unix charset and vica versa.
+**************************************************************/
+
+/**************************************************************
+ krb5_parse_name that takes a UNIX charset.
+**************************************************************/
+
+ krb5_error_code smb_krb5_parse_name(krb5_context context,
+ const char *name, /* in unix charset */
+ krb5_principal *principal)
+{
+ krb5_error_code ret;
+ char *utf8_name;
+ size_t converted_size;
+
+ if (!push_utf8_allocate(&utf8_name, name, &converted_size)) {
+ return ENOMEM;
+ }
+
+ ret = krb5_parse_name(context, utf8_name, principal);
+ SAFE_FREE(utf8_name);
+ return ret;
+}
+
+#ifdef HAVE_KRB5_PARSE_NAME_NOREALM
+/**************************************************************
+ krb5_parse_name_norealm that takes a UNIX charset.
+**************************************************************/
+
+static krb5_error_code smb_krb5_parse_name_norealm_conv(krb5_context context,
+ const char *name, /* in unix charset */
+ krb5_principal *principal)
+{
+ krb5_error_code ret;
+ char *utf8_name;
+ size_t converted_size;
+
+ *principal = NULL;
+ if (!push_utf8_allocate(&utf8_name, name, &converted_size)) {
+ return ENOMEM;
+ }
+
+ ret = krb5_parse_name_norealm(context, utf8_name, principal);
+ SAFE_FREE(utf8_name);
+ return ret;
+}
+#endif
+
+/**************************************************************
+ krb5_parse_name that returns a UNIX charset name. Must
+ be freed with normal free() call.
+**************************************************************/
+
+ krb5_error_code smb_krb5_unparse_name(krb5_context context,
+ krb5_const_principal principal,
+ char **unix_name)
+{
+ krb5_error_code ret;
+ char *utf8_name;
+ size_t converted_size;
+
+ *unix_name = NULL;
+ ret = krb5_unparse_name(context, principal, &utf8_name);
+ if (ret) {
+ return ret;
+ }
+
+ if (!pull_utf8_allocate(unix_name, utf8_name, &converted_size)) {
+ krb5_free_unparsed_name(context, utf8_name);
+ return ENOMEM;
+ }
+ krb5_free_unparsed_name(context, utf8_name);
+ return 0;
+}
+
+#ifndef HAVE_KRB5_SET_REAL_TIME
+/*
+ * This function is not in the Heimdal mainline.
+ */
+ krb5_error_code krb5_set_real_time(krb5_context context, int32_t seconds, int32_t microseconds)
+{
+ krb5_error_code ret;
+ int32_t sec, usec;
+
+ ret = krb5_us_timeofday(context, &sec, &usec);
+ if (ret)
+ return ret;
+
+ context->kdc_sec_offset = seconds - sec;
+ context->kdc_usec_offset = microseconds - usec;
+
+ return 0;
+}
+#endif
+
+#if !defined(HAVE_KRB5_SET_DEFAULT_TGS_KTYPES)
+
+#if defined(HAVE_KRB5_SET_DEFAULT_TGS_ENCTYPES)
+
+/* With MIT kerberos, we should use krb5_set_default_tgs_enctypes in preference
+ * to krb5_set_default_tgs_ktypes. See
+ * http://lists.samba.org/archive/samba-technical/2006-July/048271.html
+ *
+ * If the MIT libraries are not exporting internal symbols, we will end up in
+ * this branch, which is correct. Otherwise we will continue to use the
+ * internal symbol
+ */
+ krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc)
+{
+ return krb5_set_default_tgs_enctypes(ctx, enc);
+}
+
+#elif defined(HAVE_KRB5_SET_DEFAULT_IN_TKT_ETYPES)
+
+/* Heimdal */
+ krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc)
+{
+ return krb5_set_default_in_tkt_etypes(ctx, enc);
+}
+
+#endif /* HAVE_KRB5_SET_DEFAULT_TGS_ENCTYPES */
+
+#endif /* HAVE_KRB5_SET_DEFAULT_TGS_KTYPES */
+
+#if defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS)
+/* HEIMDAL */
+ bool setup_kaddr( krb5_address *pkaddr, struct sockaddr_storage *paddr)
+{
+ memset(pkaddr, '\0', sizeof(krb5_address));
+#if defined(HAVE_IPV6) && defined(KRB5_ADDRESS_INET6)
+ if (paddr->ss_family == AF_INET6) {
+ pkaddr->addr_type = KRB5_ADDRESS_INET6;
+ pkaddr->address.length = sizeof(((struct sockaddr_in6 *)paddr)->sin6_addr);
+ pkaddr->address.data = (char *)&(((struct sockaddr_in6 *)paddr)->sin6_addr);
+ return true;
+ }
+#endif
+ if (paddr->ss_family == AF_INET) {
+ pkaddr->addr_type = KRB5_ADDRESS_INET;
+ pkaddr->address.length = sizeof(((struct sockaddr_in *)paddr)->sin_addr);
+ pkaddr->address.data = (char *)&(((struct sockaddr_in *)paddr)->sin_addr);
+ return true;
+ }
+ return false;
+}
+#elif defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS)
+/* MIT */
+ bool setup_kaddr( krb5_address *pkaddr, struct sockaddr_storage *paddr)
+{
+ memset(pkaddr, '\0', sizeof(krb5_address));
+#if defined(HAVE_IPV6) && defined(ADDRTYPE_INET6)
+ if (paddr->ss_family == AF_INET6) {
+ pkaddr->addrtype = ADDRTYPE_INET6;
+ pkaddr->length = sizeof(((struct sockaddr_in6 *)paddr)->sin6_addr);
+ pkaddr->contents = (krb5_octet *)&(((struct sockaddr_in6 *)paddr)->sin6_addr);
+ return true;
+ }
+#endif
+ if (paddr->ss_family == AF_INET) {
+ pkaddr->addrtype = ADDRTYPE_INET;
+ pkaddr->length = sizeof(((struct sockaddr_in *)paddr)->sin_addr);
+ pkaddr->contents = (krb5_octet *)&(((struct sockaddr_in *)paddr)->sin_addr);
+ return true;
+ }
+ return false;
+}
+#else
+#error UNKNOWN_ADDRTYPE
+#endif
+
+#if defined(HAVE_KRB5_PRINCIPAL2SALT) && defined(HAVE_KRB5_USE_ENCTYPE) && defined(HAVE_KRB5_STRING_TO_KEY) && defined(HAVE_KRB5_ENCRYPT_BLOCK)
+static int create_kerberos_key_from_string_direct(krb5_context context,
+ krb5_principal host_princ,
+ krb5_data *password,
+ krb5_keyblock *key,
+ krb5_enctype enctype)
+{
+ int ret = 0;
+ krb5_data salt;
+ krb5_encrypt_block eblock;
+
+ ret = krb5_principal2salt(context, host_princ, &salt);
+ if (ret) {
+ DEBUG(1,("krb5_principal2salt failed (%s)\n", error_message(ret)));
+ return ret;
+ }
+ krb5_use_enctype(context, &eblock, enctype);
+ ret = krb5_string_to_key(context, &eblock, key, password, &salt);
+ SAFE_FREE(salt.data);
+
+ return ret;
+}
+#elif defined(HAVE_KRB5_GET_PW_SALT) && defined(HAVE_KRB5_STRING_TO_KEY_SALT)
+static int create_kerberos_key_from_string_direct(krb5_context context,
+ krb5_principal host_princ,
+ krb5_data *password,
+ krb5_keyblock *key,
+ krb5_enctype enctype)
+{
+ int ret;
+ krb5_salt salt;
+
+ ret = krb5_get_pw_salt(context, host_princ, &salt);
+ if (ret) {
+ DEBUG(1,("krb5_get_pw_salt failed (%s)\n", error_message(ret)));
+ return ret;
+ }
+
+ ret = krb5_string_to_key_salt(context, enctype, (const char *)password->data, salt, key);
+ krb5_free_salt(context, salt);
+
+ return ret;
+}
+#else
+#error UNKNOWN_CREATE_KEY_FUNCTIONS
+#endif
+
+ int create_kerberos_key_from_string(krb5_context context,
+ krb5_principal host_princ,
+ krb5_data *password,
+ krb5_keyblock *key,
+ krb5_enctype enctype,
+ bool no_salt)
+{
+ krb5_principal salt_princ = NULL;
+ int ret;
+ /*
+ * Check if we've determined that the KDC is salting keys for this
+ * principal/enctype in a non-obvious way. If it is, try to match
+ * its behavior.
+ */
+ if (no_salt) {
+ KRB5_KEY_DATA(key) = (KRB5_KEY_DATA_CAST *)SMB_MALLOC(password->length);
+ if (!KRB5_KEY_DATA(key)) {
+ return ENOMEM;
+ }
+ memcpy(KRB5_KEY_DATA(key), password->data, password->length);
+ KRB5_KEY_LENGTH(key) = password->length;
+ KRB5_KEY_TYPE(key) = enctype;
+ return 0;
+ }
+ salt_princ = kerberos_fetch_salt_princ_for_host_princ(context, host_princ, enctype);
+ ret = create_kerberos_key_from_string_direct(context, salt_princ ? salt_princ : host_princ, password, key, enctype);
+ if (salt_princ) {
+ krb5_free_principal(context, salt_princ);
+ }
+ return ret;
+}
+
+#if defined(HAVE_KRB5_GET_PERMITTED_ENCTYPES)
+ krb5_error_code get_kerberos_allowed_etypes(krb5_context context,
+ krb5_enctype **enctypes)
+{
+ return krb5_get_permitted_enctypes(context, enctypes);
+}
+#elif defined(HAVE_KRB5_GET_DEFAULT_IN_TKT_ETYPES)
+ krb5_error_code get_kerberos_allowed_etypes(krb5_context context,
+ krb5_enctype **enctypes)
+{
+ return krb5_get_default_in_tkt_etypes(context, enctypes);
+}
+#else
+#error UNKNOWN_GET_ENCTYPES_FUNCTIONS
+#endif
+
+#if defined(HAVE_KRB5_AUTH_CON_SETKEY) && !defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY)
+ krb5_error_code krb5_auth_con_setuseruserkey(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_keyblock *keyblock)
+{
+ return krb5_auth_con_setkey(context, auth_context, keyblock);
+}
+#endif
+
+bool unwrap_edata_ntstatus(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *edata,
+ DATA_BLOB *edata_out)
+{
+ DATA_BLOB edata_contents;
+ ASN1_DATA data;
+ int edata_type;
+
+ if (!edata->length) {
+ return False;
+ }
+
+ asn1_load(&data, *edata);
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_CONTEXT(1));
+ asn1_read_Integer(&data, &edata_type);
+
+ if (edata_type != KRB5_PADATA_PW_SALT) {
+ DEBUG(0,("edata is not of required type %d but of type %d\n",
+ KRB5_PADATA_PW_SALT, edata_type));
+ asn1_free(&data);
+ return False;
+ }
+
+ asn1_start_tag(&data, ASN1_CONTEXT(2));
+ asn1_read_OctetString(&data, &edata_contents);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_free(&data);
+
+ *edata_out = data_blob_talloc(mem_ctx, edata_contents.data, edata_contents.length);
+
+ data_blob_free(&edata_contents);
+
+ return True;
+}
+
+
+bool unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, DATA_BLOB *unwrapped_pac_data)
+{
+ DATA_BLOB pac_contents;
+ ASN1_DATA data;
+ int data_type;
+
+ if (!auth_data->length) {
+ return False;
+ }
+
+ asn1_load(&data, *auth_data);
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_CONTEXT(0));
+ asn1_read_Integer(&data, &data_type);
+
+ if (data_type != KRB5_AUTHDATA_WIN2K_PAC ) {
+ DEBUG(10,("authorization data is not a Windows PAC (type: %d)\n", data_type));
+ asn1_free(&data);
+ return False;
+ }
+
+ asn1_end_tag(&data);
+ asn1_start_tag(&data, ASN1_CONTEXT(1));
+ asn1_read_OctetString(&data, &pac_contents);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_free(&data);
+
+ *unwrapped_pac_data = data_blob_talloc(mem_ctx, pac_contents.data, pac_contents.length);
+
+ data_blob_free(&pac_contents);
+
+ return True;
+}
+
+ bool get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, krb5_ticket *tkt)
+{
+ DATA_BLOB auth_data_wrapped;
+ bool got_auth_data_pac = False;
+ int i;
+
+#if defined(HAVE_KRB5_TKT_ENC_PART2)
+ if (tkt->enc_part2 && tkt->enc_part2->authorization_data &&
+ tkt->enc_part2->authorization_data[0] &&
+ tkt->enc_part2->authorization_data[0]->length)
+ {
+ for (i = 0; tkt->enc_part2->authorization_data[i] != NULL; i++) {
+
+ if (tkt->enc_part2->authorization_data[i]->ad_type !=
+ KRB5_AUTHDATA_IF_RELEVANT) {
+ DEBUG(10,("get_auth_data_from_tkt: ad_type is %d\n",
+ tkt->enc_part2->authorization_data[i]->ad_type));
+ continue;
+ }
+
+ auth_data_wrapped = data_blob(tkt->enc_part2->authorization_data[i]->contents,
+ tkt->enc_part2->authorization_data[i]->length);
+
+ /* check if it is a PAC */
+ got_auth_data_pac = unwrap_pac(mem_ctx, &auth_data_wrapped, auth_data);
+ data_blob_free(&auth_data_wrapped);
+
+ if (got_auth_data_pac) {
+ return true;
+ }
+ }
+
+ return got_auth_data_pac;
+ }
+
+#else
+ if (tkt->ticket.authorization_data &&
+ tkt->ticket.authorization_data->len)
+ {
+ for (i = 0; i < tkt->ticket.authorization_data->len; i++) {
+
+ if (tkt->ticket.authorization_data->val[i].ad_type !=
+ KRB5_AUTHDATA_IF_RELEVANT) {
+ DEBUG(10,("get_auth_data_from_tkt: ad_type is %d\n",
+ tkt->ticket.authorization_data->val[i].ad_type));
+ continue;
+ }
+
+ auth_data_wrapped = data_blob(tkt->ticket.authorization_data->val[i].ad_data.data,
+ tkt->ticket.authorization_data->val[i].ad_data.length);
+
+ /* check if it is a PAC */
+ got_auth_data_pac = unwrap_pac(mem_ctx, &auth_data_wrapped, auth_data);
+ data_blob_free(&auth_data_wrapped);
+
+ if (got_auth_data_pac) {
+ return true;
+ }
+ }
+
+ return got_auth_data_pac;
+ }
+#endif
+ return False;
+}
+
+ krb5_const_principal get_principal_from_tkt(krb5_ticket *tkt)
+{
+#if defined(HAVE_KRB5_TKT_ENC_PART2)
+ return tkt->enc_part2->client;
+#else
+ return tkt->client;
+#endif
+}
+
+#if !defined(HAVE_KRB5_LOCATE_KDC)
+
+/* krb5_locate_kdc is an internal MIT symbol. MIT are not yet willing to commit
+ * to a public interface for this functionality, so we have to be able to live
+ * without it if the MIT libraries are hiding their internal symbols.
+ */
+
+#if defined(KRB5_KRBHST_INIT)
+/* Heimdal */
+ krb5_error_code smb_krb5_locate_kdc(krb5_context ctx, const krb5_data *realm, struct sockaddr **addr_pp, int *naddrs, int get_masters)
+{
+ krb5_krbhst_handle hnd;
+ krb5_krbhst_info *hinfo;
+ krb5_error_code rc;
+ int num_kdcs, i;
+ struct sockaddr *sa;
+ struct addrinfo *ai;
+
+ *addr_pp = NULL;
+ *naddrs = 0;
+
+ rc = krb5_krbhst_init(ctx, realm->data, KRB5_KRBHST_KDC, &hnd);
+ if (rc) {
+ DEBUG(0, ("smb_krb5_locate_kdc: krb5_krbhst_init failed (%s)\n", error_message(rc)));
+ return rc;
+ }
+
+ for ( num_kdcs = 0; (rc = krb5_krbhst_next(ctx, hnd, &hinfo) == 0); num_kdcs++)
+ ;
+
+ krb5_krbhst_reset(ctx, hnd);
+
+ if (!num_kdcs) {
+ DEBUG(0, ("smb_krb5_locate_kdc: zero kdcs found !\n"));
+ krb5_krbhst_free(ctx, hnd);
+ return -1;
+ }
+
+ sa = SMB_MALLOC_ARRAY( struct sockaddr, num_kdcs );
+ if (!sa) {
+ DEBUG(0, ("smb_krb5_locate_kdc: malloc failed\n"));
+ krb5_krbhst_free(ctx, hnd);
+ naddrs = 0;
+ return -1;
+ }
+
+ memset(sa, '\0', sizeof(struct sockaddr) * num_kdcs );
+
+ for (i = 0; i < num_kdcs && (rc = krb5_krbhst_next(ctx, hnd, &hinfo) == 0); i++) {
+
+#if defined(HAVE_KRB5_KRBHST_GET_ADDRINFO)
+ rc = krb5_krbhst_get_addrinfo(ctx, hinfo, &ai);
+ if (rc) {
+ DEBUG(0,("krb5_krbhst_get_addrinfo failed: %s\n", error_message(rc)));
+ continue;
+ }
+#endif
+ if (hinfo->ai && hinfo->ai->ai_family == AF_INET)
+ memcpy(&sa[i], hinfo->ai->ai_addr, sizeof(struct sockaddr));
+ }
+
+ krb5_krbhst_free(ctx, hnd);
+
+ *naddrs = num_kdcs;
+ *addr_pp = sa;
+ return 0;
+}
+
+#else /* ! defined(KRB5_KRBHST_INIT) */
+
+ krb5_error_code smb_krb5_locate_kdc(krb5_context ctx, const krb5_data *realm,
+ struct sockaddr **addr_pp, int *naddrs, int get_masters)
+{
+ DEBUG(0, ("unable to explicitly locate the KDC on this platform\n"));
+ return KRB5_KDC_UNREACH;
+}
+
+#endif /* KRB5_KRBHST_INIT */
+
+#else /* ! HAVE_KRB5_LOCATE_KDC */
+
+ krb5_error_code smb_krb5_locate_kdc(krb5_context ctx, const krb5_data *realm,
+ struct sockaddr **addr_pp, int *naddrs, int get_masters)
+{
+ return krb5_locate_kdc(ctx, realm, addr_pp, naddrs, get_masters);
+}
+
+#endif /* HAVE_KRB5_LOCATE_KDC */
+
+#if !defined(HAVE_KRB5_FREE_UNPARSED_NAME)
+ void krb5_free_unparsed_name(krb5_context context, char *val)
+{
+ SAFE_FREE(val);
+}
+#endif
+
+ void kerberos_free_data_contents(krb5_context context, krb5_data *pdata)
+{
+#if defined(HAVE_KRB5_FREE_DATA_CONTENTS)
+ if (pdata->data) {
+ krb5_free_data_contents(context, pdata);
+ }
+#else
+ SAFE_FREE(pdata->data);
+#endif
+}
+
+ void kerberos_set_creds_enctype(krb5_creds *pcreds, int enctype)
+{
+#if defined(HAVE_KRB5_KEYBLOCK_IN_CREDS)
+ KRB5_KEY_TYPE((&pcreds->keyblock)) = enctype;
+#elif defined(HAVE_KRB5_SESSION_IN_CREDS)
+ KRB5_KEY_TYPE((&pcreds->session)) = enctype;
+#else
+#error UNKNOWN_KEYBLOCK_MEMBER_IN_KRB5_CREDS_STRUCT
+#endif
+}
+
+ bool kerberos_compatible_enctypes(krb5_context context,
+ krb5_enctype enctype1,
+ krb5_enctype enctype2)
+{
+#if defined(HAVE_KRB5_C_ENCTYPE_COMPARE)
+ krb5_boolean similar = 0;
+
+ krb5_c_enctype_compare(context, enctype1, enctype2, &similar);
+ return similar ? True : False;
+#elif defined(HAVE_KRB5_ENCTYPES_COMPATIBLE_KEYS)
+ return krb5_enctypes_compatible_keys(context, enctype1, enctype2) ? True : False;
+#endif
+}
+
+static bool ads_cleanup_expired_creds(krb5_context context,
+ krb5_ccache ccache,
+ krb5_creds *credsp)
+{
+ krb5_error_code retval;
+ const char *cc_type = krb5_cc_get_type(context, ccache);
+
+ DEBUG(3, ("ads_cleanup_expired_creds: Ticket in ccache[%s:%s] expiration %s\n",
+ cc_type, krb5_cc_get_name(context, ccache),
+ http_timestring(credsp->times.endtime)));
+
+ /* we will probably need new tickets if the current ones
+ will expire within 10 seconds.
+ */
+ if (credsp->times.endtime >= (time(NULL) + 10))
+ return False;
+
+ /* heimdal won't remove creds from a file ccache, and
+ perhaps we shouldn't anyway, since internally we
+ use memory ccaches, and a FILE one probably means that
+ we're using creds obtained outside of our exectuable
+ */
+ if (strequal(cc_type, "FILE")) {
+ DEBUG(5, ("ads_cleanup_expired_creds: We do not remove creds from a %s ccache\n", cc_type));
+ return False;
+ }
+
+ retval = krb5_cc_remove_cred(context, ccache, 0, credsp);
+ if (retval) {
+ DEBUG(1, ("ads_cleanup_expired_creds: krb5_cc_remove_cred failed, err %s\n",
+ error_message(retval)));
+ /* If we have an error in this, we want to display it,
+ but continue as though we deleted it */
+ }
+ return True;
+}
+
+/*
+ we can't use krb5_mk_req because w2k wants the service to be in a particular format
+*/
+static krb5_error_code ads_krb5_mk_req(krb5_context context,
+ krb5_auth_context *auth_context,
+ const krb5_flags ap_req_options,
+ const char *principal,
+ krb5_ccache ccache,
+ krb5_data *outbuf,
+ time_t *expire_time)
+{
+ krb5_error_code retval;
+ krb5_principal server;
+ krb5_creds * credsp;
+ krb5_creds creds;
+ krb5_data in_data;
+ bool creds_ready = False;
+ int i = 0, maxtries = 3;
+
+ ZERO_STRUCT(in_data);
+
+ retval = smb_krb5_parse_name(context, principal, &server);
+ if (retval) {
+ DEBUG(1,("ads_krb5_mk_req: Failed to parse principal %s\n", principal));
+ return retval;
+ }
+
+ /* obtain ticket & session key */
+ ZERO_STRUCT(creds);
+ if ((retval = krb5_copy_principal(context, server, &creds.server))) {
+ DEBUG(1,("ads_krb5_mk_req: krb5_copy_principal failed (%s)\n",
+ error_message(retval)));
+ goto cleanup_princ;
+ }
+
+ if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) {
+ /* This can commonly fail on smbd startup with no ticket in the cache.
+ * Report at higher level than 1. */
+ DEBUG(3,("ads_krb5_mk_req: krb5_cc_get_principal failed (%s)\n",
+ error_message(retval)));
+ goto cleanup_creds;
+ }
+
+ while (!creds_ready && (i < maxtries)) {
+
+ if ((retval = krb5_get_credentials(context, 0, ccache,
+ &creds, &credsp))) {
+ DEBUG(1,("ads_krb5_mk_req: krb5_get_credentials failed for %s (%s)\n",
+ principal, error_message(retval)));
+ goto cleanup_creds;
+ }
+
+ /* cope with ticket being in the future due to clock skew */
+ if ((unsigned)credsp->times.starttime > time(NULL)) {
+ time_t t = time(NULL);
+ int time_offset =(int)((unsigned)credsp->times.starttime-t);
+ DEBUG(4,("ads_krb5_mk_req: Advancing clock by %d seconds to cope with clock skew\n", time_offset));
+ krb5_set_real_time(context, t + time_offset + 1, 0);
+ }
+
+ if (!ads_cleanup_expired_creds(context, ccache, credsp)) {
+ creds_ready = True;
+ }
+
+ i++;
+ }
+
+ DEBUG(10,("ads_krb5_mk_req: Ticket (%s) in ccache (%s:%s) is valid until: (%s - %u)\n",
+ principal, krb5_cc_get_type(context, ccache), krb5_cc_get_name(context, ccache),
+ http_timestring((unsigned)credsp->times.endtime),
+ (unsigned)credsp->times.endtime));
+
+ if (expire_time) {
+ *expire_time = (time_t)credsp->times.endtime;
+ }
+
+#if defined(TKT_FLG_OK_AS_DELEGATE ) && defined(HAVE_KRB5_FWD_TGT_CREDS) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE) && defined(KRB5_AUTH_CONTEXT_USE_SUBKEY)
+ if( credsp->ticket_flags & TKT_FLG_OK_AS_DELEGATE ) {
+ /* Fetch a forwarded TGT from the KDC so that we can hand off a 2nd ticket
+ as part of the kerberos exchange. */
+
+ DEBUG( 3, ("ads_krb5_mk_req: server marked as OK to delegate to, building forwardable TGT\n") );
+
+ if( *auth_context == NULL ) {
+ /* Allocate if it has not yet been allocated. */
+ retval = krb5_auth_con_init( context, auth_context );
+ if (retval) {
+ DEBUG(1,("ads_krb5_mk_req: krb5_auth_con_init failed (%s)\n",
+ error_message(retval)));
+ goto cleanup_creds;
+ }
+ }
+
+ retval = krb5_auth_con_setuseruserkey( context, *auth_context, &credsp->keyblock );
+ if (retval) {
+ DEBUG(1,("ads_krb5_mk_req: krb5_auth_con_setuseruserkey failed (%s)\n",
+ error_message(retval)));
+ goto cleanup_creds;
+ }
+
+ /* Must use a subkey for forwarded tickets. */
+ retval = krb5_auth_con_setflags( context, *auth_context, KRB5_AUTH_CONTEXT_USE_SUBKEY);
+ if (retval) {
+ DEBUG(1,("ads_krb5_mk_req: krb5_auth_con_setflags failed (%s)\n",
+ error_message(retval)));
+ goto cleanup_creds;
+ }
+
+ retval = ads_krb5_get_fwd_ticket( context,
+ auth_context,
+ credsp,
+ ccache,
+ &in_data );
+ if (retval) {
+ DEBUG( 3, ("ads_krb5_get_fwd_ticket failed (%s)\n",
+ error_message( retval ) ) );
+
+ /*
+ * This is not fatal. Delete the *auth_context and continue
+ * with krb5_mk_req_extended to get a non-forwardable ticket.
+ */
+
+ if (in_data.data) {
+ free( in_data.data );
+ in_data.data = NULL;
+ in_data.length = 0;
+ }
+ krb5_auth_con_free(context, *auth_context);
+ *auth_context = NULL;
+ }
+ }
+#endif
+
+ retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
+ &in_data, credsp, outbuf);
+ if (retval) {
+ DEBUG(1,("ads_krb5_mk_req: krb5_mk_req_extended failed (%s)\n",
+ error_message(retval)));
+ }
+
+ if (in_data.data) {
+ free( in_data.data );
+ in_data.length = 0;
+ }
+
+ krb5_free_creds(context, credsp);
+
+cleanup_creds:
+ krb5_free_cred_contents(context, &creds);
+
+cleanup_princ:
+ krb5_free_principal(context, server);
+
+ return retval;
+}
+
+/*
+ get a kerberos5 ticket for the given service
+*/
+int cli_krb5_get_ticket(const char *principal, time_t time_offset,
+ DATA_BLOB *ticket, DATA_BLOB *session_key_krb5,
+ uint32 extra_ap_opts, const char *ccname,
+ time_t *tgs_expire)
+
+{
+ krb5_error_code retval;
+ krb5_data packet;
+ krb5_context context = NULL;
+ krb5_ccache ccdef = NULL;
+ krb5_auth_context auth_context = NULL;
+ krb5_enctype enc_types[] = {
+#ifdef ENCTYPE_ARCFOUR_HMAC
+ ENCTYPE_ARCFOUR_HMAC,
+#endif
+ ENCTYPE_DES_CBC_MD5,
+ ENCTYPE_DES_CBC_CRC,
+ ENCTYPE_NULL};
+
+ initialize_krb5_error_table();
+ retval = krb5_init_context(&context);
+ if (retval) {
+ DEBUG(1,("cli_krb5_get_ticket: krb5_init_context failed (%s)\n",
+ error_message(retval)));
+ goto failed;
+ }
+
+ if (time_offset != 0) {
+ krb5_set_real_time(context, time(NULL) + time_offset, 0);
+ }
+
+ if ((retval = krb5_cc_resolve(context, ccname ?
+ ccname : krb5_cc_default_name(context), &ccdef))) {
+ DEBUG(1,("cli_krb5_get_ticket: krb5_cc_default failed (%s)\n",
+ error_message(retval)));
+ goto failed;
+ }
+
+ if ((retval = krb5_set_default_tgs_ktypes(context, enc_types))) {
+ DEBUG(1,("cli_krb5_get_ticket: krb5_set_default_tgs_ktypes failed (%s)\n",
+ error_message(retval)));
+ goto failed;
+ }
+
+ if ((retval = ads_krb5_mk_req(context,
+ &auth_context,
+ AP_OPTS_USE_SUBKEY | (krb5_flags)extra_ap_opts,
+ principal,
+ ccdef, &packet,
+ tgs_expire))) {
+ goto failed;
+ }
+
+ get_krb5_smb_session_key(context, auth_context, session_key_krb5, False);
+
+ *ticket = data_blob(packet.data, packet.length);
+
+ kerberos_free_data_contents(context, &packet);
+
+failed:
+
+ if ( context ) {
+ if (ccdef)
+ krb5_cc_close(context, ccdef);
+ if (auth_context)
+ krb5_auth_con_free(context, auth_context);
+ krb5_free_context(context);
+ }
+
+ return retval;
+}
+
+ bool get_krb5_smb_session_key(krb5_context context, krb5_auth_context auth_context, DATA_BLOB *session_key, bool remote)
+ {
+ krb5_keyblock *skey;
+ krb5_error_code err;
+ bool ret = False;
+
+ if (remote)
+ err = krb5_auth_con_getremotesubkey(context, auth_context, &skey);
+ else
+ err = krb5_auth_con_getlocalsubkey(context, auth_context, &skey);
+ if (err == 0 && skey != NULL) {
+ DEBUG(10, ("Got KRB5 session key of length %d\n", (int)KRB5_KEY_LENGTH(skey)));
+ *session_key = data_blob(KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey));
+ dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
+
+ ret = True;
+
+ krb5_free_keyblock(context, skey);
+ } else {
+ DEBUG(10, ("KRB5 error getting session key %d\n", err));
+ }
+
+ return ret;
+ }
+
+
+#if defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING) && !defined(HAVE_KRB5_PRINC_COMPONENT)
+ const krb5_data *krb5_princ_component(krb5_context context, krb5_principal principal, int i );
+
+ const krb5_data *krb5_princ_component(krb5_context context, krb5_principal principal, int i )
+{
+ static krb5_data kdata;
+
+ kdata.data = (char *)krb5_principal_get_comp_string(context, principal, i);
+ kdata.length = strlen((const char *)kdata.data);
+ return &kdata;
+}
+#endif
+
+ krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry)
+{
+#if defined(HAVE_KRB5_KT_FREE_ENTRY)
+ return krb5_kt_free_entry(context, kt_entry);
+#elif defined(HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS)
+ return krb5_free_keytab_entry_contents(context, kt_entry);
+#else
+#error UNKNOWN_KT_FREE_FUNCTION
+#endif
+}
+
+ void smb_krb5_checksum_from_pac_sig(krb5_checksum *cksum,
+ struct PAC_SIGNATURE_DATA *sig)
+{
+#ifdef HAVE_CHECKSUM_IN_KRB5_CHECKSUM
+ cksum->cksumtype = (krb5_cksumtype)sig->type;
+ cksum->checksum.length = sig->signature.length;
+ cksum->checksum.data = sig->signature.data;
+#else
+ cksum->checksum_type = (krb5_cksumtype)sig->type;
+ cksum->length = sig->signature.length;
+ cksum->contents = sig->signature.data;
+#endif
+}
+
+ krb5_error_code smb_krb5_verify_checksum(krb5_context context,
+ const krb5_keyblock *keyblock,
+ krb5_keyusage usage,
+ krb5_checksum *cksum,
+ uint8 *data,
+ size_t length)
+{
+ krb5_error_code ret;
+
+ /* verify the checksum */
+
+ /* welcome to the wonderful world of samba's kerberos abstraction layer:
+ *
+ * function heimdal 0.6.1rc3 heimdal 0.7 MIT krb 1.4.2
+ * -----------------------------------------------------------------------------
+ * krb5_c_verify_checksum - works works
+ * krb5_verify_checksum works (6 args) works (6 args) broken (7 args)
+ */
+
+#if defined(HAVE_KRB5_C_VERIFY_CHECKSUM)
+ {
+ krb5_boolean checksum_valid = False;
+ krb5_data input;
+
+ input.data = (char *)data;
+ input.length = length;
+
+ ret = krb5_c_verify_checksum(context,
+ keyblock,
+ usage,
+ &input,
+ cksum,
+ &checksum_valid);
+ if (ret) {
+ DEBUG(3,("smb_krb5_verify_checksum: krb5_c_verify_checksum() failed: %s\n",
+ error_message(ret)));
+ return ret;
+ }
+
+ if (!checksum_valid)
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ }
+
+#elif KRB5_VERIFY_CHECKSUM_ARGS == 6 && defined(HAVE_KRB5_CRYPTO_INIT) && defined(HAVE_KRB5_CRYPTO) && defined(HAVE_KRB5_CRYPTO_DESTROY)
+
+ /* Warning: MIT's krb5_verify_checksum cannot be used as it will use a key
+ * without enctype and it ignores any key_usage types - Guenther */
+
+ {
+
+ krb5_crypto crypto;
+ ret = krb5_crypto_init(context,
+ keyblock,
+ 0,
+ &crypto);
+ if (ret) {
+ DEBUG(0,("smb_krb5_verify_checksum: krb5_crypto_init() failed: %s\n",
+ error_message(ret)));
+ return ret;
+ }
+
+ ret = krb5_verify_checksum(context,
+ crypto,
+ usage,
+ data,
+ length,
+ cksum);
+
+ krb5_crypto_destroy(context, crypto);
+ }
+
+#else
+#error UNKNOWN_KRB5_VERIFY_CHECKSUM_FUNCTION
+#endif
+
+ return ret;
+}
+
+ time_t get_authtime_from_tkt(krb5_ticket *tkt)
+{
+#if defined(HAVE_KRB5_TKT_ENC_PART2)
+ return tkt->enc_part2->times.authtime;
+#else
+ return tkt->ticket.authtime;
+#endif
+}
+
+#ifdef HAVE_KRB5_DECODE_AP_REQ /* Heimdal */
+static int get_kvno_from_ap_req(krb5_ap_req *ap_req)
+{
+#ifdef HAVE_TICKET_POINTER_IN_KRB5_AP_REQ /* MIT */
+ if (ap_req->ticket->enc_part.kvno)
+ return ap_req->ticket->enc_part.kvno;
+#else /* Heimdal */
+ if (ap_req->ticket.enc_part.kvno)
+ return *ap_req->ticket.enc_part.kvno;
+#endif
+ return 0;
+}
+
+static krb5_enctype get_enctype_from_ap_req(krb5_ap_req *ap_req)
+{
+#ifdef HAVE_ETYPE_IN_ENCRYPTEDDATA /* Heimdal */
+ return ap_req->ticket.enc_part.etype;
+#else /* MIT */
+ return ap_req->ticket->enc_part.enctype;
+#endif
+}
+#endif /* HAVE_KRB5_DECODE_AP_REQ */
+
+static krb5_error_code
+get_key_from_keytab(krb5_context context,
+ krb5_const_principal server,
+ krb5_enctype enctype,
+ krb5_kvno kvno,
+ krb5_keyblock **out_key)
+{
+ krb5_keytab_entry entry;
+ krb5_error_code ret;
+ krb5_keytab keytab;
+ char *name = NULL;
+ krb5_keyblock *keyp;
+
+ /* We have to open a new keytab handle here, as MIT does
+ an implicit open/getnext/close on krb5_kt_get_entry. We
+ may be in the middle of a keytab enumeration when this is
+ called. JRA. */
+
+ ret = smb_krb5_open_keytab(context, NULL, False, &keytab);
+ if (ret) {
+ DEBUG(1,("get_key_from_keytab: smb_krb5_open_keytab failed (%s)\n", error_message(ret)));
+ return ret;
+ }
+
+ if ( DEBUGLEVEL >= 10 ) {
+ if (smb_krb5_unparse_name(context, server, &name) == 0) {
+ DEBUG(10,("get_key_from_keytab: will look for kvno %d, enctype %d and name: %s\n",
+ kvno, enctype, name));
+ SAFE_FREE(name);
+ }
+ }
+
+ ret = krb5_kt_get_entry(context,
+ keytab,
+ server,
+ kvno,
+ enctype,
+ &entry);
+
+ if (ret) {
+ DEBUG(0,("get_key_from_keytab: failed to retrieve key: %s\n", error_message(ret)));
+ goto out;
+ }
+
+ keyp = KRB5_KT_KEY(&entry);
+
+ ret = krb5_copy_keyblock(context, keyp, out_key);
+ if (ret) {
+ DEBUG(0,("get_key_from_keytab: failed to copy key: %s\n", error_message(ret)));
+ goto out;
+ }
+
+ smb_krb5_kt_free_entry(context, &entry);
+
+out:
+ krb5_kt_close(context, keytab);
+ return ret;
+}
+
+/* Prototypes */
+
+ krb5_error_code smb_krb5_get_keyinfo_from_ap_req(krb5_context context,
+ const krb5_data *inbuf,
+ krb5_kvno *kvno,
+ krb5_enctype *enctype)
+{
+#ifdef HAVE_KRB5_DECODE_AP_REQ /* Heimdal */
+ {
+ krb5_error_code ret;
+ krb5_ap_req ap_req;
+
+ ret = krb5_decode_ap_req(context, inbuf, &ap_req);
+ if (ret)
+ return ret;
+
+ *kvno = get_kvno_from_ap_req(&ap_req);
+ *enctype = get_enctype_from_ap_req(&ap_req);
+
+ free_AP_REQ(&ap_req);
+ return 0;
+ }
+#endif
+
+ /* Possibly not an appropriate error code. */
+ return KRB5KDC_ERR_BADOPTION;
+}
+
+ krb5_error_code krb5_rd_req_return_keyblock_from_keytab(krb5_context context,
+ krb5_auth_context *auth_context,
+ const krb5_data *inbuf,
+ krb5_const_principal server,
+ krb5_keytab keytab,
+ krb5_flags *ap_req_options,
+ krb5_ticket **ticket,
+ krb5_keyblock **keyblock)
+{
+ krb5_error_code ret;
+ krb5_kvno kvno;
+ krb5_enctype enctype;
+ krb5_keyblock *local_keyblock;
+
+ ret = krb5_rd_req(context,
+ auth_context,
+ inbuf,
+ server,
+ keytab,
+ ap_req_options,
+ ticket);
+ if (ret) {
+ return ret;
+ }
+
+#ifdef KRB5_TICKET_HAS_KEYINFO
+ enctype = (*ticket)->enc_part.enctype;
+ kvno = (*ticket)->enc_part.kvno;
+#else
+ ret = smb_krb5_get_keyinfo_from_ap_req(context, inbuf, &kvno, &enctype);
+ if (ret) {
+ return ret;
+ }
+#endif
+
+ ret = get_key_from_keytab(context,
+ server,
+ enctype,
+ kvno,
+ &local_keyblock);
+ if (ret) {
+ DEBUG(0,("krb5_rd_req_return_keyblock_from_keytab: failed to call get_key_from_keytab\n"));
+ goto out;
+ }
+
+out:
+ if (ret && local_keyblock != NULL) {
+ krb5_free_keyblock(context, local_keyblock);
+ } else {
+ *keyblock = local_keyblock;
+ }
+
+ return ret;
+}
+
+ krb5_error_code smb_krb5_parse_name_norealm(krb5_context context,
+ const char *name,
+ krb5_principal *principal)
+{
+#ifdef HAVE_KRB5_PARSE_NAME_NOREALM
+ return smb_krb5_parse_name_norealm_conv(context, name, principal);
+#endif
+
+ /* we are cheating here because parse_name will in fact set the realm.
+ * We don't care as the only caller of smb_krb5_parse_name_norealm
+ * ignores the realm anyway when calling
+ * smb_krb5_principal_compare_any_realm later - Guenther */
+
+ return smb_krb5_parse_name(context, name, principal);
+}
+
+ bool smb_krb5_principal_compare_any_realm(krb5_context context,
+ krb5_const_principal princ1,
+ krb5_const_principal princ2)
+{
+#ifdef HAVE_KRB5_PRINCIPAL_COMPARE_ANY_REALM
+
+ return krb5_principal_compare_any_realm(context, princ1, princ2);
+
+/* krb5_princ_size is a macro in MIT */
+#elif defined(HAVE_KRB5_PRINC_SIZE) || defined(krb5_princ_size)
+
+ int i, len1, len2;
+ const krb5_data *p1, *p2;
+
+ len1 = krb5_princ_size(context, princ1);
+ len2 = krb5_princ_size(context, princ2);
+
+ if (len1 != len2)
+ return False;
+
+ for (i = 0; i < len1; i++) {
+
+ p1 = krb5_princ_component(context, CONST_DISCARD(krb5_principal, princ1), i);
+ p2 = krb5_princ_component(context, CONST_DISCARD(krb5_principal, princ2), i);
+
+ if (p1->length != p2->length || memcmp(p1->data, p2->data, p1->length))
+ return False;
+ }
+
+ return True;
+#else
+#error NO_SUITABLE_PRINCIPAL_COMPARE_FUNCTION
+#endif
+}
+
+ krb5_error_code smb_krb5_renew_ticket(const char *ccache_string, /* FILE:/tmp/krb5cc_0 */
+ const char *client_string, /* gd@BER.SUSE.DE */
+ const char *service_string, /* krbtgt/BER.SUSE.DE@BER.SUSE.DE */
+ time_t *expire_time)
+{
+ krb5_error_code ret;
+ krb5_context context = NULL;
+ krb5_ccache ccache = NULL;
+ krb5_principal client = NULL;
+ krb5_creds creds, creds_in, *creds_out = NULL;
+
+ ZERO_STRUCT(creds);
+ ZERO_STRUCT(creds_in);
+
+ initialize_krb5_error_table();
+ ret = krb5_init_context(&context);
+ if (ret) {
+ goto done;
+ }
+
+ if (!ccache_string) {
+ ccache_string = krb5_cc_default_name(context);
+ }
+
+ if (!ccache_string) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ DEBUG(10,("smb_krb5_renew_ticket: using %s as ccache\n", ccache_string));
+
+ /* FIXME: we should not fall back to defaults */
+ ret = krb5_cc_resolve(context, CONST_DISCARD(char *, ccache_string), &ccache);
+ if (ret) {
+ goto done;
+ }
+
+ if (client_string) {
+ ret = smb_krb5_parse_name(context, client_string, &client);
+ if (ret) {
+ goto done;
+ }
+ } else {
+ ret = krb5_cc_get_principal(context, ccache, &client);
+ if (ret) {
+ goto done;
+ }
+ }
+
+#ifdef HAVE_KRB5_GET_RENEWED_CREDS /* MIT */
+ {
+ ret = krb5_get_renewed_creds(context, &creds, client, ccache, CONST_DISCARD(char *, service_string));
+ if (ret) {
+ DEBUG(10,("smb_krb5_renew_ticket: krb5_get_kdc_cred failed: %s\n", error_message(ret)));
+ goto done;
+ }
+ }
+#elif defined(HAVE_KRB5_GET_KDC_CRED) /* Heimdal */
+ {
+ krb5_kdc_flags flags;
+ krb5_realm *client_realm = NULL;
+
+ ret = krb5_copy_principal(context, client, &creds_in.client);
+ if (ret) {
+ goto done;
+ }
+
+ if (service_string) {
+ ret = smb_krb5_parse_name(context, service_string, &creds_in.server);
+ if (ret) {
+ goto done;
+ }
+ } else {
+ /* build tgt service by default */
+ client_realm = krb5_princ_realm(context, creds_in.client);
+ if (!client_realm) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = krb5_make_principal(context, &creds_in.server, *client_realm, KRB5_TGS_NAME, *client_realm, NULL);
+ if (ret) {
+ goto done;
+ }
+ }
+
+ flags.i = 0;
+ flags.b.renewable = flags.b.renew = True;
+
+ ret = krb5_get_kdc_cred(context, ccache, flags, NULL, NULL, &creds_in, &creds_out);
+ if (ret) {
+ DEBUG(10,("smb_krb5_renew_ticket: krb5_get_kdc_cred failed: %s\n", error_message(ret)));
+ goto done;
+ }
+
+ creds = *creds_out;
+ }
+#else
+#error NO_SUITABLE_KRB5_TICKET_RENEW_FUNCTION_AVAILABLE
+#endif
+
+ /* hm, doesn't that create a new one if the old one wasn't there? - Guenther */
+ ret = krb5_cc_initialize(context, ccache, client);
+ if (ret) {
+ goto done;
+ }
+
+ ret = krb5_cc_store_cred(context, ccache, &creds);
+
+ if (expire_time) {
+ *expire_time = (time_t) creds.times.endtime;
+ }
+
+done:
+ krb5_free_cred_contents(context, &creds_in);
+
+ if (creds_out) {
+ krb5_free_creds(context, creds_out);
+ } else {
+ krb5_free_cred_contents(context, &creds);
+ }
+
+ if (client) {
+ krb5_free_principal(context, client);
+ }
+ if (ccache) {
+ krb5_cc_close(context, ccache);
+ }
+ if (context) {
+ krb5_free_context(context);
+ }
+
+ return ret;
+}
+
+ krb5_error_code smb_krb5_free_addresses(krb5_context context, smb_krb5_addresses *addr)
+{
+ krb5_error_code ret = 0;
+ if (addr == NULL) {
+ return ret;
+ }
+#if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
+ krb5_free_addresses(context, addr->addrs);
+#elif defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS) /* Heimdal */
+ ret = krb5_free_addresses(context, addr->addrs);
+ SAFE_FREE(addr->addrs);
+#endif
+ SAFE_FREE(addr);
+ addr = NULL;
+ return ret;
+}
+
+ krb5_error_code smb_krb5_gen_netbios_krb5_address(smb_krb5_addresses **kerb_addr)
+{
+ krb5_error_code ret = 0;
+ nstring buf;
+#if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
+ krb5_address **addrs = NULL;
+#elif defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS) /* Heimdal */
+ krb5_addresses *addrs = NULL;
+#endif
+
+ *kerb_addr = (smb_krb5_addresses *)SMB_MALLOC(sizeof(smb_krb5_addresses));
+ if (*kerb_addr == NULL) {
+ return ENOMEM;
+ }
+
+ put_name(buf, global_myname(), ' ', 0x20);
+
+#if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
+ {
+ int num_addr = 2;
+
+ addrs = (krb5_address **)SMB_MALLOC(sizeof(krb5_address *) * num_addr);
+ if (addrs == NULL) {
+ SAFE_FREE(kerb_addr);
+ return ENOMEM;
+ }
+
+ memset(addrs, 0, sizeof(krb5_address *) * num_addr);
+
+ addrs[0] = (krb5_address *)SMB_MALLOC(sizeof(krb5_address));
+ if (addrs[0] == NULL) {
+ SAFE_FREE(addrs);
+ SAFE_FREE(kerb_addr);
+ return ENOMEM;
+ }
+
+ addrs[0]->magic = KV5M_ADDRESS;
+ addrs[0]->addrtype = KRB5_ADDR_NETBIOS;
+ addrs[0]->length = MAX_NETBIOSNAME_LEN;
+ addrs[0]->contents = (unsigned char *)SMB_MALLOC(addrs[0]->length);
+ if (addrs[0]->contents == NULL) {
+ SAFE_FREE(addrs[0]);
+ SAFE_FREE(addrs);
+ SAFE_FREE(kerb_addr);
+ return ENOMEM;
+ }
+
+ memcpy(addrs[0]->contents, buf, addrs[0]->length);
+
+ addrs[1] = NULL;
+ }
+#elif defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS) /* Heimdal */
+ {
+ addrs = (krb5_addresses *)SMB_MALLOC(sizeof(krb5_addresses));
+ if (addrs == NULL) {
+ SAFE_FREE(kerb_addr);
+ return ENOMEM;
+ }
+
+ memset(addrs, 0, sizeof(krb5_addresses));
+
+ addrs->len = 1;
+ addrs->val = (krb5_address *)SMB_MALLOC(sizeof(krb5_address));
+ if (addrs->val == NULL) {
+ SAFE_FREE(addrs);
+ SAFE_FREE(kerb_addr);
+ return ENOMEM;
+ }
+
+ addrs->val[0].addr_type = KRB5_ADDR_NETBIOS;
+ addrs->val[0].address.length = MAX_NETBIOSNAME_LEN;
+ addrs->val[0].address.data = (unsigned char *)SMB_MALLOC(addrs->val[0].address.length);
+ if (addrs->val[0].address.data == NULL) {
+ SAFE_FREE(addrs->val);
+ SAFE_FREE(addrs);
+ SAFE_FREE(kerb_addr);
+ return ENOMEM;
+ }
+
+ memcpy(addrs->val[0].address.data, buf, addrs->val[0].address.length);
+ }
+#else
+#error UNKNOWN_KRB5_ADDRESS_FORMAT
+#endif
+ (*kerb_addr)->addrs = addrs;
+
+ return ret;
+}
+
+ void smb_krb5_free_error(krb5_context context, krb5_error *krberror)
+{
+#ifdef HAVE_KRB5_FREE_ERROR_CONTENTS /* Heimdal */
+ krb5_free_error_contents(context, krberror);
+#else /* MIT */
+ krb5_free_error(context, krberror);
+#endif
+}
+
+ krb5_error_code handle_krberror_packet(krb5_context context,
+ krb5_data *packet)
+{
+ krb5_error_code ret;
+ bool got_error_code = False;
+
+ DEBUG(10,("handle_krberror_packet: got error packet\n"));
+
+#ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR /* Heimdal */
+ {
+ krb5_error krberror;
+
+ if ((ret = krb5_rd_error(context, packet, &krberror))) {
+ DEBUG(10,("handle_krberror_packet: krb5_rd_error failed with: %s\n",
+ error_message(ret)));
+ return ret;
+ }
+
+ if (krberror.e_data == NULL || krberror.e_data->data == NULL) {
+ ret = (krb5_error_code) krberror.error_code;
+ got_error_code = True;
+ }
+
+ smb_krb5_free_error(context, &krberror);
+ }
+#else /* MIT */
+ {
+ krb5_error *krberror;
+
+ if ((ret = krb5_rd_error(context, packet, &krberror))) {
+ DEBUG(10,("handle_krberror_packet: krb5_rd_error failed with: %s\n",
+ error_message(ret)));
+ return ret;
+ }
+
+ if (krberror->e_data.data == NULL) {
+ ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error;
+ got_error_code = True;
+ }
+ smb_krb5_free_error(context, krberror);
+ }
+#endif
+ if (got_error_code) {
+ DEBUG(5,("handle_krberror_packet: got KERBERR from kpasswd: %s (%d)\n",
+ error_message(ret), ret));
+ }
+ return ret;
+}
+
+ krb5_error_code smb_krb5_get_init_creds_opt_alloc(krb5_context context,
+ krb5_get_init_creds_opt **opt)
+{
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
+ /* Heimdal or modern MIT version */
+ return krb5_get_init_creds_opt_alloc(context, opt);
+#else
+ /* Historical MIT version */
+ krb5_get_init_creds_opt *my_opt;
+
+ *opt = NULL;
+
+ if ((my_opt = SMB_MALLOC_P(krb5_get_init_creds_opt)) == NULL) {
+ return ENOMEM;
+ }
+
+ krb5_get_init_creds_opt_init(my_opt);
+
+ *opt = my_opt;
+ return 0;
+#endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC */
+}
+
+ void smb_krb5_get_init_creds_opt_free(krb5_context context,
+ krb5_get_init_creds_opt *opt)
+{
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_FREE
+
+#ifdef KRB5_CREDS_OPT_FREE_REQUIRES_CONTEXT
+ /* Modern MIT or Heimdal version */
+ krb5_get_init_creds_opt_free(context, opt);
+#else
+ /* Heimdal version */
+ krb5_get_init_creds_opt_free(opt);
+#endif /* KRB5_CREDS_OPT_FREE_REQUIRES_CONTEXT */
+
+#else /* HAVE_KRB5_GET_INIT_CREDS_OPT_FREE */
+ /* Historical MIT version */
+ SAFE_FREE(opt);
+ opt = NULL;
+#endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_FREE */
+}
+
+ krb5_enctype smb_get_enctype_from_kt_entry(krb5_keytab_entry *kt_entry)
+{
+ return KRB5_KEY_TYPE(KRB5_KT_KEY(kt_entry));
+}
+
+
+/* caller needs to free etype_s */
+ krb5_error_code smb_krb5_enctype_to_string(krb5_context context,
+ krb5_enctype enctype,
+ char **etype_s)
+{
+#ifdef HAVE_KRB5_ENCTYPE_TO_STRING_WITH_KRB5_CONTEXT_ARG
+ return krb5_enctype_to_string(context, enctype, etype_s); /* Heimdal */
+#elif defined(HAVE_KRB5_ENCTYPE_TO_STRING_WITH_SIZE_T_ARG)
+ char buf[256];
+ krb5_error_code ret = krb5_enctype_to_string(enctype, buf, 256); /* MIT */
+ if (ret) {
+ return ret;
+ }
+ *etype_s = SMB_STRDUP(buf);
+ if (!*etype_s) {
+ return ENOMEM;
+ }
+ return ret;
+#else
+#error UNKNOWN_KRB5_ENCTYPE_TO_STRING_FUNCTION
+#endif
+}
+
+ krb5_error_code smb_krb5_mk_error(krb5_context context,
+ krb5_error_code error_code,
+ const krb5_principal server,
+ krb5_data *reply)
+{
+#ifdef HAVE_SHORT_KRB5_MK_ERROR_INTERFACE /* MIT */
+ /*
+ * The MIT interface is *terrible*.
+ * We have to construct this ourselves...
+ */
+ krb5_error e;
+
+ memset(&e, 0, sizeof(e));
+ krb5_us_timeofday(context, &e.stime, &e.susec);
+ e.server = server;
+#if defined(krb5_err_base)
+ e.error = error_code - krb5_err_base;
+#elif defined(ERROR_TABLE_BASE_krb5)
+ e.error = error_code - ERROR_TABLE_BASE_krb5;
+#else
+ e.error = error_code; /* Almost certainly wrong, but what can we do... ? */
+#endif
+
+ return krb5_mk_error(context, &e, reply);
+#else /* Heimdal. */
+ return krb5_mk_error(context,
+ error_code,
+ NULL,
+ NULL, /* e_data */
+ NULL,
+ server,
+ NULL,
+ NULL,
+ reply);
+#endif
+}
+
+/**********************************************************************
+ * Open a krb5 keytab with flags, handles readonly or readwrite access and
+ * allows to process non-default keytab names.
+ * @param context krb5_context
+ * @param keytab_name_req string
+ * @param write_access bool if writable keytab is required
+ * @param krb5_keytab pointer to krb5_keytab (close with krb5_kt_close())
+ * @return krb5_error_code
+**********************************************************************/
+
+/* This MAX_NAME_LEN is a constant defined in krb5.h */
+#ifndef MAX_KEYTAB_NAME_LEN
+#define MAX_KEYTAB_NAME_LEN 1100
+#endif
+
+ krb5_error_code smb_krb5_open_keytab(krb5_context context,
+ const char *keytab_name_req,
+ bool write_access,
+ krb5_keytab *keytab)
+{
+ krb5_error_code ret = 0;
+ TALLOC_CTX *mem_ctx;
+ char keytab_string[MAX_KEYTAB_NAME_LEN];
+ char *kt_str = NULL;
+ bool found_valid_name = False;
+ const char *pragma = "FILE";
+ const char *tmp = NULL;
+
+ if (!write_access && !keytab_name_req) {
+ /* caller just wants to read the default keytab readonly, so be it */
+ return krb5_kt_default(context, keytab);
+ }
+
+ mem_ctx = talloc_init("smb_krb5_open_keytab");
+ if (!mem_ctx) {
+ return ENOMEM;
+ }
+
+#ifdef HAVE_WRFILE_KEYTAB
+ if (write_access) {
+ pragma = "WRFILE";
+ }
+#endif
+
+ if (keytab_name_req) {
+
+ if (strlen(keytab_name_req) > MAX_KEYTAB_NAME_LEN) {
+ ret = KRB5_CONFIG_NOTENUFSPACE;
+ goto out;
+ }
+
+ if ((strncmp(keytab_name_req, "WRFILE:/", 8) == 0) ||
+ (strncmp(keytab_name_req, "FILE:/", 6) == 0)) {
+ tmp = keytab_name_req;
+ goto resolve;
+ }
+
+ if (keytab_name_req[0] != '/') {
+ ret = KRB5_KT_BADNAME;
+ goto out;
+ }
+
+ tmp = talloc_asprintf(mem_ctx, "%s:%s", pragma, keytab_name_req);
+ if (!tmp) {
+ ret = ENOMEM;
+ goto out;
+ }
+
+ goto resolve;
+ }
+
+ /* we need to handle more complex keytab_strings, like:
+ * "ANY:FILE:/etc/krb5.keytab,krb4:/etc/srvtab" */
+
+ ret = krb5_kt_default_name(context, &keytab_string[0], MAX_KEYTAB_NAME_LEN - 2);
+ if (ret) {
+ goto out;
+ }
+
+ DEBUG(10,("smb_krb5_open_keytab: krb5_kt_default_name returned %s\n", keytab_string));
+
+ tmp = talloc_strdup(mem_ctx, keytab_string);
+ if (!tmp) {
+ ret = ENOMEM;
+ goto out;
+ }
+
+ if (strncmp(tmp, "ANY:", 4) == 0) {
+ tmp += 4;
+ }
+
+ memset(&keytab_string, '\0', sizeof(keytab_string));
+
+ while (next_token_talloc(mem_ctx, &tmp, &kt_str, ",")) {
+ if (strncmp(kt_str, "WRFILE:", 7) == 0) {
+ found_valid_name = True;
+ tmp = kt_str;
+ tmp += 7;
+ }
+
+ if (strncmp(kt_str, "FILE:", 5) == 0) {
+ found_valid_name = True;
+ tmp = kt_str;
+ tmp += 5;
+ }
+
+ if (found_valid_name) {
+ if (tmp[0] != '/') {
+ ret = KRB5_KT_BADNAME;
+ goto out;
+ }
+
+ tmp = talloc_asprintf(mem_ctx, "%s:%s", pragma, tmp);
+ if (!tmp) {
+ ret = ENOMEM;
+ goto out;
+ }
+ break;
+ }
+ }
+
+ if (!found_valid_name) {
+ ret = KRB5_KT_UNKNOWN_TYPE;
+ goto out;
+ }
+
+ resolve:
+ DEBUG(10,("smb_krb5_open_keytab: resolving: %s\n", tmp));
+ ret = krb5_kt_resolve(context, tmp, keytab);
+
+ out:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+krb5_error_code smb_krb5_keytab_name(TALLOC_CTX *mem_ctx,
+ krb5_context context,
+ krb5_keytab keytab,
+ const char **keytab_name)
+{
+ char keytab_string[MAX_KEYTAB_NAME_LEN];
+ krb5_error_code ret = 0;
+
+ ret = krb5_kt_get_name(context, keytab,
+ keytab_string, MAX_KEYTAB_NAME_LEN - 2);
+ if (ret) {
+ return ret;
+ }
+
+ *keytab_name = talloc_strdup(mem_ctx, keytab_string);
+ if (!*keytab_name) {
+ return ENOMEM;
+ }
+
+ return ret;
+}
+
+#if defined(TKT_FLG_OK_AS_DELEGATE ) && defined(HAVE_KRB5_FWD_TGT_CREDS) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE) && defined(KRB5_AUTH_CONTEXT_USE_SUBKEY)
+/**************************************************************
+Routine: ads_krb5_get_fwd_ticket
+ Description:
+ When a service ticket is flagged as trusted
+ for delegation we should provide a forwardable
+ ticket so that the remote host can act on our
+ behalf. This is done by taking the 2nd forwardable
+ TGT and storing it in the GSS-API authenticator
+ "checksum". This routine will populate
+ the krb5_data authenticator with this TGT.
+ Parameters:
+ krb5_context context: The kerberos context for this authentication.
+ krb5_auth_context: The authentication context.
+ krb5_creds *credsp: The ticket credentials (AS-REP).
+ krb5_ccache ccache: The credentials cache.
+ krb5_data &authenticator: The checksum field that will store the TGT, and
+ authenticator.data must be freed by the caller.
+
+ Returns:
+ krb5_error_code: 0 if no errors, otherwise set.
+**************************************************************/
+
+static krb5_error_code ads_krb5_get_fwd_ticket( krb5_context context,
+ krb5_auth_context *auth_context,
+ krb5_creds *credsp,
+ krb5_ccache ccache,
+ krb5_data *authenticator)
+{
+ krb5_data fwdData;
+ krb5_error_code retval = 0;
+ char *pChksum = NULL;
+ char *p = NULL;
+
+ ZERO_STRUCT(fwdData);
+ ZERO_STRUCTP(authenticator);
+
+ retval = krb5_fwd_tgt_creds(context,/* Krb5 context [in] */
+ *auth_context, /* Authentication context [in] */
+ CONST_DISCARD(char *, KRB5_TGS_NAME), /* Ticket service name ("krbtgt") [in] */
+ credsp->client, /* Client principal for the tgt [in] */
+ credsp->server, /* Server principal for the tgt [in] */
+ ccache, /* Credential cache to use for storage [in] */
+ 1, /* Turn on for "Forwardable ticket" [in] */
+ &fwdData ); /* Resulting response [out] */
+
+
+ if (retval) {
+ DEBUG(1,("ads_krb5_get_fwd_ticket: krb5_fwd_tgt_creds failed (%s)\n",
+ error_message(retval)));
+ goto out;
+ }
+
+ if ((unsigned int)GSSAPI_CHECKSUM_SIZE + (unsigned int)fwdData.length <
+ (unsigned int)GSSAPI_CHECKSUM_SIZE) {
+ retval = EINVAL;
+ goto out;
+ }
+
+ /* We're going to allocate a gssChecksum structure with a little
+ extra data the length of the kerberos credentials length
+ (APPLICATION 22) so that we can pack it on the end of the structure.
+ */
+
+ pChksum = (char *)SMB_MALLOC(GSSAPI_CHECKSUM_SIZE + fwdData.length );
+ if (!pChksum) {
+ retval = ENOMEM;
+ goto out;
+ }
+
+ p = pChksum;
+
+ SIVAL(p, 0, GSSAPI_BNDLENGTH);
+ p += 4;
+
+ /* Zero out the bindings fields */
+ memset(p, '\0', GSSAPI_BNDLENGTH );
+ p += GSSAPI_BNDLENGTH;
+
+ SIVAL(p, 0, GSS_C_DELEG_FLAG );
+ p += 4;
+ SSVAL(p, 0, 1 );
+ p += 2;
+ SSVAL(p, 0, fwdData.length );
+ p += 2;
+
+ /* Migrate the kerberos KRB_CRED data to the checksum delegation */
+ memcpy(p, fwdData.data, fwdData.length );
+ p += fwdData.length;
+
+ /* We need to do this in order to allow our GSS-API */
+ retval = krb5_auth_con_set_req_cksumtype( context, *auth_context, GSSAPI_CHECKSUM );
+ if (retval) {
+ goto out;
+ }
+
+ /* We now have a service ticket, now turn it into an AP-REQ. */
+ authenticator->length = fwdData.length + GSSAPI_CHECKSUM_SIZE;
+
+ /* Caller should call free() when they're done with this. */
+ authenticator->data = (char *)pChksum;
+
+ out:
+
+ /* Remove that input data, we never needed it anyway. */
+ if (fwdData.length > 0) {
+ krb5_free_data_contents( context, &fwdData );
+ }
+
+ return retval;
+}
+#endif
+
+#else /* HAVE_KRB5 */
+ /* this saves a few linking headaches */
+ int cli_krb5_get_ticket(const char *principal, time_t time_offset,
+ DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts,
+ const char *ccname, time_t *tgs_expire)
+{
+ DEBUG(0,("NO KERBEROS SUPPORT\n"));
+ return 1;
+}
+
+#endif
diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c
new file mode 100644
index 0000000000..50918458b0
--- /dev/null
+++ b/source3/libsmb/clilist.c
@@ -0,0 +1,683 @@
+/*
+ Unix SMB/CIFS implementation.
+ client directory list routines
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Calculate a safe next_entry_offset.
+****************************************************************************/
+
+static size_t calc_next_entry_offset(const char *base, const char *pdata_end)
+{
+ size_t next_entry_offset = (size_t)IVAL(base,0);
+
+ if (next_entry_offset == 0 ||
+ base + next_entry_offset < base ||
+ base + next_entry_offset > pdata_end) {
+ next_entry_offset = pdata_end - base;
+ }
+ return next_entry_offset;
+}
+
+/****************************************************************************
+ 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 size_t interpret_long_filename(TALLOC_CTX *ctx,
+ struct cli_state *cli,
+ int level,
+ const char *p,
+ const char *pdata_end,
+ file_info *finfo,
+ uint32 *p_resume_key,
+ DATA_BLOB *p_last_name_raw)
+{
+ int len;
+ size_t ret;
+ const char *base = p;
+
+ data_blob_free(p_last_name_raw);
+
+ if (p_resume_key) {
+ *p_resume_key = 0;
+ }
+ ZERO_STRUCTP(finfo);
+ finfo->cli = cli;
+
+ switch (level) {
+ case 1: /* OS/2 understands this */
+ /* these dates are converted to GMT by
+ make_unix_date */
+ if (pdata_end - base < 27) {
+ return pdata_end - base;
+ }
+ finfo->ctime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+4));
+ finfo->atime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+8));
+ finfo->mtime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+12));
+ finfo->size = IVAL(p,16);
+ finfo->mode = CVAL(p,24);
+ len = CVAL(p, 26);
+ p += 27;
+ p += clistr_align_in(cli, p, 0);
+
+ /* We can safely use +1 here (which is required by OS/2)
+ * instead of +2 as the STR_TERMINATE flag below is
+ * actually used as the length calculation.
+ * The len+2 is merely an upper bound.
+ * Due to the explicit 2 byte null termination
+ * in cli_receive_trans/cli_receive_nt_trans
+ * we know this is safe. JRA + kukks
+ */
+
+ if (p + len + 1 > pdata_end) {
+ return pdata_end - base;
+ }
+
+ /* the len+2 below looks strange but it is
+ important to cope with the differences
+ between win2000 and win9x for this call
+ (tridge) */
+ ret = clistr_pull_talloc(ctx,
+ cli,
+ &finfo->name,
+ p,
+ len+2,
+ STR_TERMINATE);
+ if (ret == (size_t)-1) {
+ return pdata_end - base;
+ }
+ p += ret;
+ return PTR_DIFF(p, base);
+
+ case 2: /* this is what OS/2 uses mostly */
+ /* these dates are converted to GMT by
+ make_unix_date */
+ if (pdata_end - base < 31) {
+ return pdata_end - base;
+ }
+ finfo->ctime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+4));
+ finfo->atime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+8));
+ finfo->mtime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+12));
+ finfo->size = IVAL(p,16);
+ finfo->mode = CVAL(p,24);
+ len = CVAL(p, 30);
+ p += 31;
+ /* check for unisys! */
+ if (p + len + 1 > pdata_end) {
+ return pdata_end - base;
+ }
+ ret = clistr_pull_talloc(ctx,
+ cli,
+ &finfo->name,
+ p,
+ len,
+ STR_NOALIGN);
+ if (ret == (size_t)-1) {
+ return pdata_end - base;
+ }
+ p += ret;
+ return PTR_DIFF(p, base) + 1;
+
+ case 260: /* NT uses this, but also accepts 2 */
+ {
+ size_t namelen, slen;
+
+ if (pdata_end - base < 94) {
+ return pdata_end - base;
+ }
+
+ p += 4; /* next entry offset */
+
+ if (p_resume_key) {
+ *p_resume_key = IVAL(p,0);
+ }
+ p += 4; /* fileindex */
+
+ /* Offset zero is "create time", not "change time". */
+ p += 8;
+ finfo->atime_ts = interpret_long_date(p);
+ p += 8;
+ finfo->mtime_ts = interpret_long_date(p);
+ p += 8;
+ finfo->ctime_ts = interpret_long_date(p);
+ p += 8;
+ finfo->size = IVAL2_TO_SMB_BIG_UINT(p,0);
+ p += 8;
+ p += 8; /* alloc size */
+ finfo->mode = CVAL(p,0);
+ p += 4;
+ namelen = IVAL(p,0);
+ p += 4;
+ p += 4; /* EA size */
+ slen = SVAL(p, 0);
+ if (slen > 24) {
+ /* Bad short name length. */
+ return pdata_end - base;
+ }
+ p += 2;
+ {
+ /* stupid NT bugs. grr */
+ int flags = 0;
+ if (p[1] == 0 && namelen > 1) flags |= STR_UNICODE;
+ clistr_pull(cli, finfo->short_name, p,
+ sizeof(finfo->short_name),
+ slen, flags);
+ }
+ p += 24; /* short name? */
+ if (p + namelen < p || p + namelen > pdata_end) {
+ return pdata_end - base;
+ }
+ ret = clistr_pull_talloc(ctx,
+ cli,
+ &finfo->name,
+ p,
+ namelen,
+ 0);
+ if (ret == (size_t)-1) {
+ return pdata_end - base;
+ }
+
+ /* To be robust in the face of unicode conversion failures
+ we need to copy the raw bytes of the last name seen here.
+ Namelen doesn't include the terminating unicode null, so
+ copy it here. */
+
+ if (p_last_name_raw) {
+ *p_last_name_raw = data_blob(NULL, namelen+2);
+ memcpy(p_last_name_raw->data, p, namelen);
+ SSVAL(p_last_name_raw->data, namelen, 0);
+ }
+ return calc_next_entry_offset(base, pdata_end);
+ }
+ }
+
+ DEBUG(1,("Unknown long filename format %d\n",level));
+ return calc_next_entry_offset(base, pdata_end);
+}
+
+/****************************************************************************
+ Do a directory listing, calling fn on each file found.
+****************************************************************************/
+
+int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
+ void (*fn)(const char *, file_info *, const char *, void *), void *state)
+{
+#if 1
+ int max_matches = 1366; /* Match W2k - was 512. */
+#else
+ int max_matches = 512;
+#endif
+ int info_level;
+ char *p, *p2, *rdata_end;
+ char *mask = NULL;
+ file_info finfo;
+ int i;
+ char *dirlist = NULL;
+ int dirlist_len = 0;
+ int total_received = -1;
+ bool First = True;
+ int ff_searchcount=0;
+ int ff_eos=0;
+ int ff_dir_handle=0;
+ int loop_count = 0;
+ char *rparam=NULL, *rdata=NULL;
+ unsigned int param_len, data_len;
+ uint16 setup;
+ char *param;
+ const char *mnt;
+ uint32 resume_key = 0;
+ TALLOC_CTX *frame = talloc_stackframe();
+ DATA_BLOB last_name_raw = data_blob(NULL, 0);
+
+ /* NT uses 260, OS/2 uses 2. Both accept 1. */
+ info_level = (cli->capabilities&CAP_NT_SMBS)?260:1;
+
+ mask = SMB_STRDUP(Mask);
+ if (!mask) {
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ while (ff_eos == 0) {
+ size_t nlen = 2*(strlen(mask)+1);
+
+ loop_count++;
+ if (loop_count > 200) {
+ DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
+ break;
+ }
+
+ param = SMB_MALLOC_ARRAY(char, 12+nlen+last_name_raw.length+2);
+ if (!param) {
+ break;
+ }
+
+ if (First) {
+ setup = TRANSACT2_FINDFIRST;
+ SSVAL(param,0,attribute); /* attribute */
+ SSVAL(param,2,max_matches); /* max count */
+ SSVAL(param,4,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END)); /* resume required + close on end */
+ SSVAL(param,6,info_level);
+ SIVAL(param,8,0);
+ p = param+12;
+ p += clistr_push(cli, param+12, mask,
+ nlen, STR_TERMINATE);
+ } else {
+ setup = TRANSACT2_FINDNEXT;
+ SSVAL(param,0,ff_dir_handle);
+ SSVAL(param,2,max_matches); /* max count */
+ SSVAL(param,4,info_level);
+ /* For W2K servers serving out FAT filesystems we *must* set the
+ resume key. If it's not FAT then it's returned as zero. */
+ SIVAL(param,6,resume_key); /* ff_resume_key */
+ /* NB. *DON'T* use continue here. If you do it seems that W2K and bretheren
+ can miss filenames. Use last filename continue instead. JRA */
+ SSVAL(param,10,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END)); /* resume required + close on end */
+ p = param+12;
+ if (last_name_raw.length) {
+ memcpy(p, last_name_raw.data, last_name_raw.length);
+ p += last_name_raw.length;
+ } else {
+ p += clistr_push(cli, param+12, mask,
+ nlen, STR_TERMINATE);
+ }
+ }
+
+ param_len = PTR_DIFF(p, param);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* Name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 10, /* param, length, max */
+ NULL, 0,
+#if 0
+ /* w2k value. */
+ MIN(16384,cli->max_xmit) /* data, length, max. */
+#else
+ cli->max_xmit /* data, length, max. */
+#endif
+ )) {
+ SAFE_FREE(param);
+ TALLOC_FREE(frame);
+ break;
+ }
+
+ SAFE_FREE(param);
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len) &&
+ cli_is_dos_error(cli)) {
+ /* We need to work around a Win95 bug - sometimes
+ it gives ERRSRV/ERRerror temprarily */
+ uint8 eclass;
+ uint32 ecode;
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ cli_dos_error(cli, &eclass, &ecode);
+
+ /*
+ * OS/2 might return "no more files",
+ * which just tells us, that searchcount is zero
+ * in this search.
+ * Guenter Kukkukk <linux@kukkukk.com>
+ */
+
+ if (eclass == ERRDOS && ecode == ERRnofiles) {
+ ff_searchcount = 0;
+ cli_reset_error(cli);
+ break;
+ }
+
+ if (eclass != ERRSRV || ecode != ERRerror)
+ break;
+ smb_msleep(100);
+ continue;
+ }
+
+ if (cli_is_error(cli) || !rdata || !rparam) {
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ break;
+ }
+
+ if (total_received == -1)
+ total_received = 0;
+
+ /* parse out some important return info */
+ p = rparam;
+ if (First) {
+ ff_dir_handle = SVAL(p,0);
+ ff_searchcount = SVAL(p,2);
+ ff_eos = SVAL(p,4);
+ } else {
+ ff_searchcount = SVAL(p,0);
+ ff_eos = SVAL(p,2);
+ }
+
+ if (ff_searchcount == 0) {
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ break;
+ }
+
+ /* point to the data bytes */
+ p = rdata;
+ rdata_end = rdata + data_len;
+
+ /* we might need the lastname for continuations */
+ for (p2=p,i=0;i<ff_searchcount && p2 < rdata_end;i++) {
+ if ((info_level == 260) && (i == ff_searchcount-1)) {
+ /* Last entry - fixup the last offset length. */
+ SIVAL(p2,0,PTR_DIFF((rdata + data_len),p2));
+ }
+ p2 += interpret_long_filename(frame,
+ cli,
+ info_level,
+ p2,
+ rdata_end,
+ &finfo,
+ &resume_key,
+ &last_name_raw);
+
+ if (!finfo.name) {
+ DEBUG(0,("cli_list_new: Error: unable to parse name from info level %d\n",
+ info_level));
+ ff_eos = 1;
+ break;
+ }
+ if (!First && *mask && strcsequal(finfo.name, mask)) {
+ DEBUG(0,("Error: Looping in FIND_NEXT as name %s has already been seen?\n",
+ finfo.name));
+ ff_eos = 1;
+ break;
+ }
+ }
+
+ SAFE_FREE(mask);
+ if (ff_searchcount > 0) {
+ mask = SMB_STRDUP(finfo.name);
+ } else {
+ mask = SMB_STRDUP("");
+ }
+ if (!mask) {
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ break;
+ }
+
+ /* grab the data for later use */
+ /* and add them to the dirlist pool */
+ dirlist = (char *)SMB_REALLOC(dirlist,dirlist_len + data_len);
+
+ if (!dirlist) {
+ DEBUG(0,("cli_list_new: Failed to expand dirlist\n"));
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ break;
+ }
+
+ memcpy(dirlist+dirlist_len,p,data_len);
+ dirlist_len += data_len;
+
+ total_received += ff_searchcount;
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ DEBUG(3,("received %d entries (eos=%d)\n",
+ ff_searchcount,ff_eos));
+
+ if (ff_searchcount > 0)
+ loop_count = 0;
+
+ First = False;
+ }
+
+ mnt = cli_cm_get_mntpoint( cli );
+
+ /* see if the server disconnected or the connection otherwise failed */
+ if (cli_is_error(cli)) {
+ total_received = -1;
+ } else {
+ /* no connection problem. let user function add each entry */
+ rdata_end = dirlist + dirlist_len;
+ for (p=dirlist,i=0;i<total_received;i++) {
+ p += interpret_long_filename(frame,
+ cli,
+ info_level,
+ p,
+ rdata_end,
+ &finfo,
+ NULL,
+ NULL);
+ if (!finfo.name) {
+ DEBUG(0,("cli_list_new: unable to parse name from info level %d\n",
+ info_level));
+ break;
+ }
+ fn(mnt,&finfo, Mask, state);
+ }
+ }
+
+ /* free up the dirlist buffer and last name raw blob */
+ SAFE_FREE(dirlist);
+ data_blob_free(&last_name_raw);
+ SAFE_FREE(mask);
+ TALLOC_FREE(frame);
+ return(total_received);
+}
+
+/****************************************************************************
+ Interpret a short filename structure.
+ The length of the structure is returned.
+****************************************************************************/
+
+static bool interpret_short_filename(TALLOC_CTX *ctx,
+ struct cli_state *cli,
+ char *p,
+ file_info *finfo)
+{
+ size_t ret;
+ ZERO_STRUCTP(finfo);
+
+ finfo->cli = cli;
+ finfo->mode = CVAL(p,21);
+
+ /* this date is converted to GMT by make_unix_date */
+ finfo->ctime_ts.tv_sec = cli_make_unix_date(cli, p+22);
+ finfo->ctime_ts.tv_nsec = 0;
+ finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec;
+ finfo->mtime_ts.tv_nsec = finfo->atime_ts.tv_nsec = 0;
+ finfo->size = IVAL(p,26);
+ ret = clistr_pull_talloc(ctx,
+ cli,
+ &finfo->name,
+ p+30,
+ 12,
+ STR_ASCII);
+ if (ret == (size_t)-1) {
+ return false;
+ }
+
+ if (finfo->name) {
+ strlcpy(finfo->short_name,
+ finfo->name,
+ sizeof(finfo->short_name));
+ }
+ return true;
+ return(DIR_STRUCT_SIZE);
+}
+
+/****************************************************************************
+ Do a directory listing, calling fn on each file found.
+ this uses the old SMBsearch interface. It is needed for testing Samba,
+ but should otherwise not be used.
+****************************************************************************/
+
+int cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute,
+ void (*fn)(const char *, file_info *, const char *, void *), void *state)
+{
+ char *p;
+ int received = 0;
+ bool first = True;
+ char status[21];
+ int num_asked = (cli->max_xmit - 100)/DIR_STRUCT_SIZE;
+ int num_received = 0;
+ int i;
+ char *dirlist = NULL;
+ char *mask = NULL;
+ TALLOC_CTX *frame = NULL;
+
+ ZERO_ARRAY(status);
+
+ mask = SMB_STRDUP(Mask);
+ if (!mask) {
+ return -1;
+ }
+
+ while (1) {
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,2,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBsearch);
+
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,num_asked);
+ SSVAL(cli->outbuf,smb_vwv1,attribute);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+
+ p += clistr_push(cli, p, first?mask:"",
+ cli->bufsize - PTR_DIFF(p,cli->outbuf),
+ STR_TERMINATE);
+ *p++ = 5;
+ if (first) {
+ SSVAL(p,0,0);
+ p += 2;
+ } else {
+ SSVAL(p,0,21);
+ p += 2;
+ memcpy(p,status,21);
+ p += 21;
+ }
+
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) break;
+
+ received = SVAL(cli->inbuf,smb_vwv0);
+ if (received <= 0) break;
+
+ /* Ensure we received enough data. */
+ if ((cli->inbuf+4+smb_len(cli->inbuf) - (smb_buf(cli->inbuf)+3)) <
+ received*DIR_STRUCT_SIZE) {
+ break;
+ }
+
+ first = False;
+
+ dirlist = (char *)SMB_REALLOC(
+ dirlist,(num_received + received)*DIR_STRUCT_SIZE);
+ if (!dirlist) {
+ DEBUG(0,("cli_list_old: failed to expand dirlist"));
+ SAFE_FREE(mask);
+ return 0;
+ }
+
+ p = smb_buf(cli->inbuf) + 3;
+
+ memcpy(dirlist+num_received*DIR_STRUCT_SIZE,
+ p,received*DIR_STRUCT_SIZE);
+
+ memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21);
+
+ num_received += received;
+
+ if (cli_is_error(cli)) break;
+ }
+
+ if (!first) {
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,2,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBfclose);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf, smb_vwv0, 0); /* find count? */
+ SSVAL(cli->outbuf, smb_vwv1, attribute);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ fstrcpy(p, "");
+ p += strlen(p) + 1;
+ *p++ = 5;
+ SSVAL(p, 0, 21);
+ p += 2;
+ memcpy(p,status,21);
+ p += 21;
+
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ DEBUG(0,("Error closing search: %s\n",cli_errstr(cli)));
+ }
+ }
+
+ frame = talloc_stackframe();
+ for (p=dirlist,i=0;i<num_received;i++) {
+ file_info finfo;
+ if (!interpret_short_filename(frame, cli, p, &finfo)) {
+ break;
+ }
+ p += DIR_STRUCT_SIZE;
+ fn("\\", &finfo, Mask, state);
+ }
+ TALLOC_FREE(frame);
+
+ SAFE_FREE(mask);
+ SAFE_FREE(dirlist);
+ return(num_received);
+}
+
+/****************************************************************************
+ Do a directory listing, calling fn on each file found.
+ This auto-switches between old and new style.
+****************************************************************************/
+
+int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute,
+ void (*fn)(const char *, file_info *, const char *, void *), void *state)
+{
+ if (cli->protocol <= PROTOCOL_LANMAN1)
+ return cli_list_old(cli, Mask, attribute, fn, state);
+ return cli_list_new(cli, Mask, attribute, fn, state);
+}
diff --git a/source3/libsmb/climessage.c b/source3/libsmb/climessage.c
new file mode 100644
index 0000000000..808190e79c
--- /dev/null
+++ b/source3/libsmb/climessage.c
@@ -0,0 +1,162 @@
+/*
+ Unix SMB/CIFS implementation.
+ client message handling routines
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Start a message sequence.
+****************************************************************************/
+
+int cli_message_start_build(struct cli_state *cli, const char *host, const char *username)
+{
+ char *p;
+
+ /* construct a SMBsendstrt command */
+ memset(cli->outbuf,'\0',smb_size);
+ cli_set_message(cli->outbuf,0,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBsendstrt);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, username,
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_ASCII|STR_TERMINATE);
+ *p++ = 4;
+ p += clistr_push(cli, p, host,
+ cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_ASCII|STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ return(PTR_DIFF(p, cli->outbuf));
+}
+
+bool cli_message_start(struct cli_state *cli, const char *host, const char *username,
+ int *grp)
+{
+ cli_message_start_build(cli, host, username);
+ cli_send_smb(cli);
+
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) return False;
+
+ *grp = SVAL(cli->inbuf,smb_vwv0);
+
+ return True;
+}
+
+/****************************************************************************
+ Send a message
+****************************************************************************/
+
+int cli_message_text_build(struct cli_state *cli, const char *msg, int len, int grp)
+{
+ char *msgdos;
+ size_t lendos;
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ cli_set_message(cli->outbuf,1,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBsendtxt);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,grp);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 1;
+
+ if (!convert_string_allocate(NULL, CH_UNIX, CH_DOS, msg, len,
+ (void **)(void *)&msgdos, &lendos, True) || !msgdos) {
+ DEBUG(3,("Conversion failed, sending message in UNIX charset\n"));
+ SSVAL(p, 0, len); p += 2;
+ if (len > cli->bufsize - PTR_DIFF(p,cli->outbuf)) {
+ return -1;
+ }
+ memcpy(p, msg, len);
+ p += len;
+ } else {
+ SSVAL(p, 0, lendos); p += 2;
+ if (lendos > cli->bufsize - PTR_DIFF(p,cli->outbuf)) {
+ return -1;
+ }
+ memcpy(p, msgdos, lendos);
+ p += lendos;
+ SAFE_FREE(msgdos);
+ }
+
+ cli_setup_bcc(cli, p);
+
+ return(PTR_DIFF(p, cli->outbuf));
+}
+
+bool cli_message_text(struct cli_state *cli, const char *msg, int len, int grp)
+{
+ cli_message_text_build(cli, msg, len, grp);
+
+ cli_send_smb(cli);
+
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) return False;
+
+ return True;
+}
+
+/****************************************************************************
+ End a message.
+****************************************************************************/
+
+int cli_message_end_build(struct cli_state *cli, int grp)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ cli_set_message(cli->outbuf,1,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBsendend);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+
+ SSVAL(cli->outbuf,smb_vwv0,grp);
+
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+
+ return(PTR_DIFF(p, cli->outbuf));
+}
+
+bool cli_message_end(struct cli_state *cli, int grp)
+{
+ cli_message_end_build(cli, grp);
+
+ cli_send_smb(cli);
+
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) return False;
+
+ return True;
+}
diff --git a/source3/libsmb/clioplock.c b/source3/libsmb/clioplock.c
new file mode 100644
index 0000000000..ef8b396461
--- /dev/null
+++ b/source3/libsmb/clioplock.c
@@ -0,0 +1,66 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client oplock functions
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+send an ack for an oplock break request
+****************************************************************************/
+
+bool cli_oplock_ack(struct cli_state *cli, int fnum, unsigned char level)
+{
+ char *oldbuf = cli->outbuf;
+ char buf[smb_size+16];
+ bool ret;
+
+ cli->outbuf = buf;
+
+ memset(buf,'\0',smb_size);
+ cli_set_message(buf,8,0,True);
+
+ SCVAL(buf,smb_com,SMBlockingX);
+ SSVAL(buf,smb_tid, cli->cnum);
+ cli_setup_packet(cli);
+ SSVAL(buf,smb_vwv0,0xFF);
+ SSVAL(buf,smb_vwv1,0);
+ SSVAL(buf,smb_vwv2,fnum);
+ if (level == 1)
+ SSVAL(buf,smb_vwv3,0x102); /* levelII oplock break ack */
+ else
+ SSVAL(buf,smb_vwv3,2); /* exclusive oplock break ack */
+ SIVAL(buf,smb_vwv4,0); /* timoeut */
+ SSVAL(buf,smb_vwv6,0); /* unlockcount */
+ SSVAL(buf,smb_vwv7,0); /* lockcount */
+
+ ret = cli_send_smb(cli);
+
+ cli->outbuf = oldbuf;
+
+ return ret;
+}
+
+
+/****************************************************************************
+set the oplock handler for a connection
+****************************************************************************/
+void cli_oplock_handler(struct cli_state *cli,
+ bool (*handler)(struct cli_state *, int, unsigned char))
+{
+ cli->oplock_handler = handler;
+}
diff --git a/source3/libsmb/cliprint.c b/source3/libsmb/cliprint.c
new file mode 100644
index 0000000000..223ddb4186
--- /dev/null
+++ b/source3/libsmb/cliprint.c
@@ -0,0 +1,260 @@
+/*
+ Unix SMB/CIFS implementation.
+ client print routines
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*****************************************************************************
+ Convert a character pointer in a cli_call_api() response to a form we can use.
+ This function contains code to prevent core dumps if the server returns
+ invalid data.
+*****************************************************************************/
+static const char *fix_char_ptr(unsigned int datap, unsigned int converter,
+ char *rdata, int rdrcnt)
+{
+ if (datap == 0) {
+ /* turn NULL pointers into zero length strings */
+ return "";
+ } else {
+ unsigned int offset = datap - converter;
+
+ if (offset >= rdrcnt) {
+ DEBUG(1,("bad char ptr: datap=%u, converter=%u rdrcnt=%d>",
+ datap, converter, rdrcnt));
+ return "<ERROR>";
+ } else {
+ return &rdata[offset];
+ }
+ }
+}
+
+/****************************************************************************
+call fn() on each entry in a print queue
+****************************************************************************/
+
+int cli_print_queue(struct cli_state *cli,
+ void (*fn)(struct print_job_info *))
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt, rprcnt;
+ char param[1024];
+ int result_code=0;
+ int i = -1;
+
+ memset(param,'\0',sizeof(param));
+
+ p = param;
+ SSVAL(p,0,76); /* API function number 76 (DosPrintJobEnum) */
+ p += 2;
+ safe_strcpy_base(p,"zWrLeh", param, sizeof(param)); /* parameter description? */
+ p = skip_string(param,sizeof(param),p);
+ safe_strcpy_base(p,"WWzWWDDzz", param, sizeof(param)); /* returned data format */
+ p = skip_string(param,sizeof(param),p);
+ safe_strcpy_base(p,cli->share, param, sizeof(param)); /* name of queue */
+ p = skip_string(param,sizeof(param),p);
+ 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;
+ safe_strcpy_base(p,"", param,sizeof(param)); /* subformat */
+ p = skip_string(param,sizeof(param),p);
+
+ DEBUG(4,("doing cli_print_queue for %s\n", cli->share));
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) { /* return data, length */
+ int converter;
+ result_code = SVAL(rparam,0);
+ converter = SVAL(rparam,2); /* conversion factor */
+
+ if (result_code == 0) {
+ struct print_job_info job;
+
+ p = rdata;
+
+ for (i = 0; i < SVAL(rparam,4); ++i) {
+ job.id = SVAL(p,0);
+ job.priority = SVAL(p,2);
+ fstrcpy(job.user,
+ fix_char_ptr(SVAL(p,4), converter,
+ rdata, rdrcnt));
+ job.t = cli_make_unix_date3(cli, p + 12);
+ job.size = IVAL(p,16);
+ fstrcpy(job.name,fix_char_ptr(SVAL(p,24),
+ converter,
+ rdata, rdrcnt));
+ fn(&job);
+ p += 28;
+ }
+ }
+ }
+
+ /* If any parameters or data were returned, free the storage. */
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return i;
+}
+
+/****************************************************************************
+ cancel a print job
+ ****************************************************************************/
+
+int cli_printjob_del(struct cli_state *cli, int job)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ int ret = -1;
+ char param[1024];
+
+ memset(param,'\0',sizeof(param));
+
+ p = param;
+ SSVAL(p,0,81); /* DosPrintJobDel() */
+ p += 2;
+ safe_strcpy_base(p,"W", param,sizeof(param));
+ p = skip_string(param,sizeof(param),p);
+ safe_strcpy_base(p,"", param,sizeof(param));
+ p = skip_string(param,sizeof(param),p);
+ SSVAL(p,0,job);
+ p += 2;
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) { /* return data, length */
+ ret = SVAL(rparam,0);
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return ret;
+}
+
+
+/****************************************************************************
+ Open a spool file
+****************************************************************************/
+
+int cli_spl_open(struct cli_state *cli, const char *fname, int flags, int share_mode)
+{
+ char *p;
+ unsigned openfn=0;
+ unsigned accessmode=0;
+
+ if (flags & O_CREAT)
+ openfn |= (1<<4);
+ if (!(flags & O_EXCL)) {
+ if (flags & O_TRUNC)
+ openfn |= (1<<1);
+ else
+ openfn |= (1<<0);
+ }
+
+ accessmode = (share_mode<<4);
+
+ if ((flags & O_ACCMODE) == O_RDWR) {
+ accessmode |= 2;
+ } else if ((flags & O_ACCMODE) == O_WRONLY) {
+ accessmode |= 1;
+ }
+
+#if defined(O_SYNC)
+ if ((flags & O_SYNC) == O_SYNC) {
+ accessmode |= (1<<14);
+ }
+#endif /* O_SYNC */
+
+ if (share_mode == DENY_FCB) {
+ accessmode = 0xFF;
+ }
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,15,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBsplopen);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
+ SSVAL(cli->outbuf,smb_vwv3,accessmode);
+ SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
+ SSVAL(cli->outbuf,smb_vwv5,0);
+ SSVAL(cli->outbuf,smb_vwv8,openfn);
+
+ if (cli->use_oplocks) {
+ /* if using oplocks then ask for a batch oplock via
+ core and extended methods */
+ SCVAL(cli->outbuf,smb_flg, CVAL(cli->outbuf,smb_flg)|
+ FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK);
+ SSVAL(cli->outbuf,smb_vwv2,SVAL(cli->outbuf,smb_vwv2) | 6);
+ }
+
+ p = smb_buf(cli->outbuf);
+ p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return -1;
+ }
+
+ if (cli_is_error(cli)) {
+ return -1;
+ }
+
+ return SVAL(cli->inbuf,smb_vwv2);
+}
+
+/****************************************************************************
+ Close a file.
+****************************************************************************/
+
+bool cli_spl_close(struct cli_state *cli, int fnum)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,3,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBsplclose);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,fnum);
+ SIVALS(cli->outbuf,smb_vwv1,-1);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ return !cli_is_error(cli);
+}
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
new file mode 100644
index 0000000000..f369d28dff
--- /dev/null
+++ b/source3/libsmb/cliquota.c
@@ -0,0 +1,642 @@
+/*
+ Unix SMB/CIFS implementation.
+ client quota functions
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+bool cli_get_quota_handle(struct cli_state *cli, int *quota_fnum)
+{
+ *quota_fnum = cli_nt_create_full(cli, FAKE_FILE_NAME_QUOTA_WIN32,
+ 0x00000016, DESIRED_ACCESS_PIPE,
+ 0x00000000, FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN, 0x00000000, 0x03);
+
+ if (*quota_fnum == (-1)) {
+ return False;
+ }
+
+ return True;
+}
+
+void free_ntquota_list(SMB_NTQUOTA_LIST **qt_list)
+{
+ if (!qt_list)
+ return;
+
+ if ((*qt_list)->mem_ctx)
+ talloc_destroy((*qt_list)->mem_ctx);
+
+ (*qt_list) = NULL;
+
+ return;
+}
+
+static bool parse_user_quota_record(const char *rdata, unsigned int rdata_count, unsigned int *offset, SMB_NTQUOTA_STRUCT *pqt)
+{
+ int sid_len;
+ SMB_NTQUOTA_STRUCT qt;
+
+ ZERO_STRUCT(qt);
+
+ if (!rdata||!offset||!pqt) {
+ smb_panic("parse_quota_record: called with NULL POINTER!");
+ }
+
+ if (rdata_count < 40) {
+ return False;
+ }
+
+ /* offset to next quota record.
+ * 4 bytes IVAL(rdata,0)
+ * unused here...
+ */
+ *offset = IVAL(rdata,0);
+
+ /* sid len */
+ sid_len = IVAL(rdata,4);
+
+ if (rdata_count < 40+sid_len) {
+ return False;
+ }
+
+ /* unknown 8 bytes in pdata
+ * maybe its the change time in NTTIME
+ */
+
+ /* the used space 8 bytes (SMB_BIG_UINT)*/
+ qt.usedspace = (SMB_BIG_UINT)IVAL(rdata,16);
+#ifdef LARGE_SMB_OFF_T
+ qt.usedspace |= (((SMB_BIG_UINT)IVAL(rdata,20)) << 32);
+#else /* LARGE_SMB_OFF_T */
+ if ((IVAL(rdata,20) != 0)&&
+ ((qt.usedspace != 0xFFFFFFFF)||
+ (IVAL(rdata,20)!=0xFFFFFFFF))) {
+ /* more than 32 bits? */
+ return False;
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ /* the soft quotas 8 bytes (SMB_BIG_UINT)*/
+ qt.softlim = (SMB_BIG_UINT)IVAL(rdata,24);
+#ifdef LARGE_SMB_OFF_T
+ qt.softlim |= (((SMB_BIG_UINT)IVAL(rdata,28)) << 32);
+#else /* LARGE_SMB_OFF_T */
+ if ((IVAL(rdata,28) != 0)&&
+ ((qt.softlim != 0xFFFFFFFF)||
+ (IVAL(rdata,28)!=0xFFFFFFFF))) {
+ /* more than 32 bits? */
+ return False;
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ /* the hard quotas 8 bytes (SMB_BIG_UINT)*/
+ qt.hardlim = (SMB_BIG_UINT)IVAL(rdata,32);
+#ifdef LARGE_SMB_OFF_T
+ qt.hardlim |= (((SMB_BIG_UINT)IVAL(rdata,36)) << 32);
+#else /* LARGE_SMB_OFF_T */
+ if ((IVAL(rdata,36) != 0)&&
+ ((qt.hardlim != 0xFFFFFFFF)||
+ (IVAL(rdata,36)!=0xFFFFFFFF))) {
+ /* more than 32 bits? */
+ return False;
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ sid_parse(rdata+40,sid_len,&qt.sid);
+
+ qt.qtype = SMB_USER_QUOTA_TYPE;
+
+ *pqt = qt;
+
+ return True;
+}
+
+bool cli_get_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt)
+{
+ bool ret = False;
+ uint16 setup;
+ char params[16];
+ unsigned int data_len;
+ char data[SID_MAX_SIZE+8];
+ char *rparam=NULL, *rdata=NULL;
+ unsigned int rparam_count=0, rdata_count=0;
+ unsigned int sid_len;
+ unsigned int offset;
+
+ if (!cli||!pqt) {
+ smb_panic("cli_get_user_quota() called with NULL Pointer!");
+ }
+
+ setup = NT_TRANSACT_GET_USER_QUOTA;
+
+ SSVAL(params, 0,quota_fnum);
+ SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_FOR_SID);
+ SIVAL(params, 4,0x00000024);
+ SIVAL(params, 8,0x00000000);
+ SIVAL(params,12,0x00000024);
+
+ sid_len = ndr_size_dom_sid(&pqt->sid, 0);
+ data_len = sid_len+8;
+ SIVAL(data, 0, 0x00000000);
+ SIVAL(data, 4, sid_len);
+ sid_linearize(data+8, sid_len, &pqt->sid);
+
+ if (!cli_send_nt_trans(cli,
+ NT_TRANSACT_GET_USER_QUOTA,
+ 0,
+ &setup, 1, 0,
+ params, 16, 4,
+ data, data_len, 112)) {
+ DEBUG(1,("Failed to send NT_TRANSACT_GET_USER_QUOTA\n"));
+ goto cleanup;
+ }
+
+
+ if (!cli_receive_nt_trans(cli,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ DEBUG(1,("Failed to recv NT_TRANSACT_GET_USER_QUOTA\n"));
+ goto cleanup;
+ }
+
+ if (cli_is_error(cli)) {
+ ret = False;
+ goto cleanup;
+ } else {
+ ret = True;
+ }
+
+ if ((rparam&&rdata)&&(rparam_count>=4&&rdata_count>=8)) {
+ ret = parse_user_quota_record(rdata, rdata_count, &offset, pqt);
+ } else {
+ DEBUG(0,("Got INVALID NT_TRANSACT_GET_USER_QUOTA reply.\n"));
+ ret = False;
+ }
+
+ cleanup:
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+ return ret;
+}
+
+bool cli_set_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt)
+{
+ bool ret = False;
+ uint16 setup;
+ char params[2];
+ char data[112];
+ char *rparam=NULL, *rdata=NULL;
+ unsigned int rparam_count=0, rdata_count=0;
+ unsigned int sid_len;
+ memset(data,'\0',112);
+
+ if (!cli||!pqt) {
+ smb_panic("cli_set_user_quota() called with NULL Pointer!");
+ }
+
+ setup = NT_TRANSACT_SET_USER_QUOTA;
+
+ SSVAL(params,0,quota_fnum);
+
+ sid_len = ndr_size_dom_sid(&pqt->sid, 0);
+ SIVAL(data,0,0);
+ SIVAL(data,4,sid_len);
+ SBIG_UINT(data, 8,(SMB_BIG_UINT)0);
+ SBIG_UINT(data,16,pqt->usedspace);
+ SBIG_UINT(data,24,pqt->softlim);
+ SBIG_UINT(data,32,pqt->hardlim);
+ sid_linearize(data+40, sid_len, &pqt->sid);
+
+ if (!cli_send_nt_trans(cli,
+ NT_TRANSACT_SET_USER_QUOTA,
+ 0,
+ &setup, 1, 0,
+ params, 2, 0,
+ data, 112, 0)) {
+ DEBUG(1,("Failed to send NT_TRANSACT_SET_USER_QUOTA\n"));
+ goto cleanup;
+ }
+
+
+ if (!cli_receive_nt_trans(cli,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ DEBUG(1,("NT_TRANSACT_SET_USER_QUOTA failed\n"));
+ goto cleanup;
+ }
+
+ if (cli_is_error(cli)) {
+ ret = False;
+ goto cleanup;
+ } else {
+ ret = True;
+ }
+
+ cleanup:
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+ return ret;
+}
+
+bool cli_list_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_LIST **pqt_list)
+{
+ bool ret = False;
+ uint16 setup;
+ char params[16];
+ char *rparam=NULL, *rdata=NULL;
+ unsigned int rparam_count=0, rdata_count=0;
+ unsigned int offset;
+ const char *curdata = NULL;
+ unsigned int curdata_count = 0;
+ TALLOC_CTX *mem_ctx = NULL;
+ SMB_NTQUOTA_STRUCT qt;
+ SMB_NTQUOTA_LIST *tmp_list_ent;
+
+ if (!cli||!pqt_list) {
+ smb_panic("cli_list_user_quota() called with NULL Pointer!");
+ }
+
+ setup = NT_TRANSACT_GET_USER_QUOTA;
+
+ SSVAL(params, 0,quota_fnum);
+ SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_START);
+ SIVAL(params, 4,0x00000000);
+ SIVAL(params, 8,0x00000000);
+ SIVAL(params,12,0x00000000);
+
+ if (!cli_send_nt_trans(cli,
+ NT_TRANSACT_GET_USER_QUOTA,
+ 0,
+ &setup, 1, 0,
+ params, 16, 4,
+ NULL, 0, 2048)) {
+ DEBUG(1,("Failed to send NT_TRANSACT_GET_USER_QUOTA\n"));
+ goto cleanup;
+ }
+
+
+ if (!cli_receive_nt_trans(cli,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ DEBUG(1,("Failed to recv NT_TRANSACT_GET_USER_QUOTA\n"));
+ goto cleanup;
+ }
+
+ if (cli_is_error(cli)) {
+ ret = False;
+ goto cleanup;
+ } else {
+ ret = True;
+ }
+
+ if (rdata_count == 0) {
+ *pqt_list = NULL;
+ return True;
+ }
+
+ if ((mem_ctx=talloc_init("SMB_USER_QUOTA_LIST"))==NULL) {
+ DEBUG(0,("talloc_init() failed\n"));
+ return (-1);
+ }
+
+ offset = 1;
+ for (curdata=rdata,curdata_count=rdata_count;
+ ((curdata)&&(curdata_count>=8)&&(offset>0));
+ curdata +=offset,curdata_count -= offset) {
+ ZERO_STRUCT(qt);
+ if (!parse_user_quota_record(curdata, curdata_count, &offset, &qt)) {
+ DEBUG(1,("Failed to parse the quota record\n"));
+ goto cleanup;
+ }
+
+ if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
+ DEBUG(0,("TALLOC_ZERO() failed\n"));
+ talloc_destroy(mem_ctx);
+ return (-1);
+ }
+
+ if ((tmp_list_ent->quotas=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
+ DEBUG(0,("TALLOC_ZERO() failed\n"));
+ talloc_destroy(mem_ctx);
+ return (-1);
+ }
+
+ memcpy(tmp_list_ent->quotas,&qt,sizeof(qt));
+ tmp_list_ent->mem_ctx = mem_ctx;
+
+ DLIST_ADD((*pqt_list),tmp_list_ent);
+ }
+
+ SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_CONTINUE);
+ while(1) {
+ if (!cli_send_nt_trans(cli,
+ NT_TRANSACT_GET_USER_QUOTA,
+ 0,
+ &setup, 1, 0,
+ params, 16, 4,
+ NULL, 0, 2048)) {
+ DEBUG(1,("Failed to send NT_TRANSACT_GET_USER_QUOTA\n"));
+ goto cleanup;
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+ if (!cli_receive_nt_trans(cli,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ DEBUG(1,("Failed to recv NT_TRANSACT_GET_USER_QUOTA\n"));
+ goto cleanup;
+ }
+
+ if (cli_is_error(cli)) {
+ ret = False;
+ goto cleanup;
+ } else {
+ ret = True;
+ }
+
+ if (rdata_count == 0) {
+ break;
+ }
+
+ offset = 1;
+ for (curdata=rdata,curdata_count=rdata_count;
+ ((curdata)&&(curdata_count>=8)&&(offset>0));
+ curdata +=offset,curdata_count -= offset) {
+ ZERO_STRUCT(qt);
+ if (!parse_user_quota_record(curdata, curdata_count, &offset, &qt)) {
+ DEBUG(1,("Failed to parse the quota record\n"));
+ goto cleanup;
+ }
+
+ if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
+ DEBUG(0,("TALLOC_ZERO() failed\n"));
+ talloc_destroy(mem_ctx);
+ goto cleanup;
+ }
+
+ if ((tmp_list_ent->quotas=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
+ DEBUG(0,("TALLOC_ZERO() failed\n"));
+ talloc_destroy(mem_ctx);
+ goto cleanup;
+ }
+
+ memcpy(tmp_list_ent->quotas,&qt,sizeof(qt));
+ tmp_list_ent->mem_ctx = mem_ctx;
+
+ DLIST_ADD((*pqt_list),tmp_list_ent);
+ }
+ }
+
+
+ ret = True;
+ cleanup:
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return ret;
+}
+
+bool cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt)
+{
+ bool ret = False;
+ uint16 setup;
+ char param[2];
+ char *rparam=NULL, *rdata=NULL;
+ unsigned int rparam_count=0, rdata_count=0;
+ SMB_NTQUOTA_STRUCT qt;
+ ZERO_STRUCT(qt);
+
+ if (!cli||!pqt) {
+ smb_panic("cli_get_fs_quota_info() called with NULL Pointer!");
+ }
+
+ setup = TRANSACT2_QFSINFO;
+
+ SSVAL(param,0,SMB_FS_QUOTA_INFORMATION);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL,
+ 0, 0,
+ &setup, 1, 0,
+ param, 2, 0,
+ NULL, 0, 560)) {
+ goto cleanup;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ goto cleanup;
+ }
+
+ if (cli_is_error(cli)) {
+ ret = False;
+ goto cleanup;
+ } else {
+ ret = True;
+ }
+
+ if (rdata_count < 48) {
+ goto cleanup;
+ }
+
+ /* unknown_1 24 NULL bytes in pdata*/
+
+ /* the soft quotas 8 bytes (SMB_BIG_UINT)*/
+ qt.softlim = (SMB_BIG_UINT)IVAL(rdata,24);
+#ifdef LARGE_SMB_OFF_T
+ qt.softlim |= (((SMB_BIG_UINT)IVAL(rdata,28)) << 32);
+#else /* LARGE_SMB_OFF_T */
+ if ((IVAL(rdata,28) != 0)&&
+ ((qt.softlim != 0xFFFFFFFF)||
+ (IVAL(rdata,28)!=0xFFFFFFFF))) {
+ /* more than 32 bits? */
+ goto cleanup;
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ /* the hard quotas 8 bytes (SMB_BIG_UINT)*/
+ qt.hardlim = (SMB_BIG_UINT)IVAL(rdata,32);
+#ifdef LARGE_SMB_OFF_T
+ qt.hardlim |= (((SMB_BIG_UINT)IVAL(rdata,36)) << 32);
+#else /* LARGE_SMB_OFF_T */
+ if ((IVAL(rdata,36) != 0)&&
+ ((qt.hardlim != 0xFFFFFFFF)||
+ (IVAL(rdata,36)!=0xFFFFFFFF))) {
+ /* more than 32 bits? */
+ goto cleanup;
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ /* quota_flags 2 bytes **/
+ qt.qflags = SVAL(rdata,40);
+
+ qt.qtype = SMB_USER_FS_QUOTA_TYPE;
+
+ *pqt = qt;
+
+ ret = True;
+cleanup:
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return ret;
+}
+
+bool cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt)
+{
+ bool ret = False;
+ uint16 setup;
+ char param[4];
+ char data[48];
+ char *rparam=NULL, *rdata=NULL;
+ unsigned int rparam_count=0, rdata_count=0;
+ SMB_NTQUOTA_STRUCT qt;
+ ZERO_STRUCT(qt);
+ memset(data,'\0',48);
+
+ if (!cli||!pqt) {
+ smb_panic("cli_set_fs_quota_info() called with NULL Pointer!");
+ }
+
+ setup = TRANSACT2_SETFSINFO;
+
+ SSVAL(param,0,quota_fnum);
+ SSVAL(param,2,SMB_FS_QUOTA_INFORMATION);
+
+ /* Unknown1 24 NULL bytes*/
+
+ /* Default Soft Quota 8 bytes */
+ SBIG_UINT(data,24,pqt->softlim);
+
+ /* Default Hard Quota 8 bytes */
+ SBIG_UINT(data,32,pqt->hardlim);
+
+ /* Quota flag 2 bytes */
+ SSVAL(data,40,pqt->qflags);
+
+ /* Unknown3 6 NULL bytes */
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL,
+ 0, 0,
+ &setup, 1, 0,
+ param, 4, 0,
+ data, 48, 0)) {
+ goto cleanup;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ goto cleanup;
+ }
+
+ if (cli_is_error(cli)) {
+ ret = False;
+ goto cleanup;
+ } else {
+ ret = True;
+ }
+
+cleanup:
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return ret;
+}
+
+static const char *quota_str_static(SMB_BIG_UINT val, bool special, bool _numeric)
+{
+ const char *result;
+
+ if (!_numeric&&special&&(val == SMB_NTQUOTAS_NO_LIMIT)) {
+ return "NO LIMIT";
+ }
+#if defined(HAVE_LONGLONG)
+ result = talloc_asprintf(talloc_tos(), "%llu", val);
+#else
+ result = talloc_asprintf(talloc_tos(), "%lu", val);
+#endif
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+void dump_ntquota(SMB_NTQUOTA_STRUCT *qt, bool _verbose, bool _numeric, void (*_sidtostring)(fstring str, DOM_SID *sid, bool _numeric))
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!qt) {
+ smb_panic("dump_ntquota() called with NULL pointer");
+ }
+
+ switch (qt->qtype) {
+ case SMB_USER_FS_QUOTA_TYPE:
+ {
+ d_printf("File System QUOTAS:\n");
+ d_printf("Limits:\n");
+ d_printf(" Default Soft Limit: %15s\n",quota_str_static(qt->softlim,True,_numeric));
+ d_printf(" Default Hard Limit: %15s\n",quota_str_static(qt->hardlim,True,_numeric));
+ d_printf("Quota Flags:\n");
+ d_printf(" Quotas Enabled: %s\n",
+ ((qt->qflags&QUOTAS_ENABLED)||(qt->qflags&QUOTAS_DENY_DISK))?"On":"Off");
+ d_printf(" Deny Disk: %s\n",(qt->qflags&QUOTAS_DENY_DISK)?"On":"Off");
+ d_printf(" Log Soft Limit: %s\n",(qt->qflags&QUOTAS_LOG_THRESHOLD)?"On":"Off");
+ d_printf(" Log Hard Limit: %s\n",(qt->qflags&QUOTAS_LOG_LIMIT)?"On":"Off");
+ }
+ break;
+ case SMB_USER_QUOTA_TYPE:
+ {
+ fstring username_str = {0};
+
+ if (_sidtostring) {
+ _sidtostring(username_str,&qt->sid,_numeric);
+ } else {
+ sid_to_fstring(username_str, &qt->sid);
+ }
+
+ if (_verbose) {
+ d_printf("Quotas for User: %s\n",username_str);
+ d_printf("Used Space: %15s\n",quota_str_static(qt->usedspace,False,_numeric));
+ d_printf("Soft Limit: %15s\n",quota_str_static(qt->softlim,True,_numeric));
+ d_printf("Hard Limit: %15s\n",quota_str_static(qt->hardlim,True,_numeric));
+ } else {
+ d_printf("%-30s: ",username_str);
+ d_printf("%15s/",quota_str_static(qt->usedspace,False,_numeric));
+ d_printf("%15s/",quota_str_static(qt->softlim,True,_numeric));
+ d_printf("%15s\n",quota_str_static(qt->hardlim,True,_numeric));
+ }
+ }
+ break;
+ default:
+ d_printf("dump_ntquota() invalid qtype(%d)\n",qt->qtype);
+ }
+ TALLOC_FREE(frame);
+ return;
+}
+
+void dump_ntquota_list(SMB_NTQUOTA_LIST **qtl, bool _verbose, bool _numeric, void (*_sidtostring)(fstring str, DOM_SID *sid, bool _numeric))
+{
+ SMB_NTQUOTA_LIST *cur;
+
+ for (cur = *qtl;cur;cur = cur->next) {
+ if (cur->quotas)
+ dump_ntquota(cur->quotas,_verbose,_numeric,_sidtostring);
+ }
+}
diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c
new file mode 100644
index 0000000000..eee8636fdd
--- /dev/null
+++ b/source3/libsmb/clirap.c
@@ -0,0 +1,1264 @@
+/*
+ Unix SMB/CIFS implementation.
+ client RAP calls
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Gerald (Jerry) Carter 2004
+ Copyright (C) James Peach 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Call a remote api on an arbitrary pipe. takes param, data and setup buffers.
+****************************************************************************/
+
+bool cli_api_pipe(struct cli_state *cli, const char *pipe_name,
+ uint16 *setup, uint32 setup_count, uint32 max_setup_count,
+ char *params, uint32 param_count, uint32 max_param_count,
+ char *data, uint32 data_count, uint32 max_data_count,
+ char **rparam, uint32 *rparam_count,
+ char **rdata, uint32 *rdata_count)
+{
+ cli_send_trans(cli, SMBtrans,
+ pipe_name,
+ 0,0, /* fid, flags */
+ setup, setup_count, max_setup_count,
+ params, param_count, max_param_count,
+ data, data_count, max_data_count);
+
+ return (cli_receive_trans(cli, SMBtrans,
+ rparam, (unsigned int *)rparam_count,
+ rdata, (unsigned 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, unsigned int *rprcnt,
+ char **rdata, unsigned int *rdrcnt)
+{
+ cli_send_trans(cli,SMBtrans,
+ PIPE_LANMAN, /* Name */
+ 0,0, /* fid, flags */
+ NULL,0,0, /* Setup, length, max */
+ param, prcnt, mprcnt, /* Params, length, max */
+ data, drcnt, mdrcnt /* Data, length, max */
+ );
+
+ return (cli_receive_trans(cli,SMBtrans,
+ rparam, rprcnt,
+ rdata, rdrcnt));
+}
+
+/****************************************************************************
+ Perform a NetWkstaUserLogon.
+****************************************************************************/
+
+bool cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ char param[1024];
+
+ memset(param, 0, sizeof(param));
+
+ /* send a SMBtrans command with api NetWkstaUserLogon */
+ p = param;
+ SSVAL(p,0,132); /* api number */
+ p += 2;
+ strlcpy(p,"OOWb54WrLh",sizeof(param)-PTR_DIFF(p,param));
+ p = skip_string(param,sizeof(param),p);
+ strlcpy(p,"WB21BWDWWDDDDDDDzzzD",sizeof(param)-PTR_DIFF(p,param));
+ p = skip_string(param,sizeof(param),p);
+ SSVAL(p,0,1);
+ p += 2;
+ strlcpy(p,user,sizeof(param)-PTR_DIFF(p,param));
+ strupper_m(p);
+ p += 21;
+ p++;
+ p += 15;
+ p++;
+ strlcpy(p, workstation,sizeof(param)-PTR_DIFF(p,param));
+ strupper_m(p);
+ p += 16;
+ SSVAL(p, 0, CLI_BUFFER_SIZE);
+ p += 2;
+ SSVAL(p, 0, CLI_BUFFER_SIZE);
+ p += 2;
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),1024, /* param, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+ cli->rap_error = rparam? SVAL(rparam,0) : -1;
+ p = rdata;
+
+ if (cli->rap_error == 0) {
+ DEBUG(4,("NetWkstaUserLogon success\n"));
+ cli->privileges = SVAL(p, 24);
+ /* The cli->eff_name field used to be set here
+ but it wasn't used anywhere else. */
+ } else {
+ DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+ return (cli->rap_error == 0);
+}
+
+/****************************************************************************
+ Call a NetShareEnum - try and browse available connections on a host.
+****************************************************************************/
+
+int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ char param[1024];
+ int count = -1;
+
+ /* now send a SMBtrans command with api RNetShareEnum */
+ p = param;
+ SSVAL(p,0,0); /* api number */
+ p += 2;
+ strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
+ p = skip_string(param,sizeof(param),p);
+ strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
+ p = skip_string(param,sizeof(param),p);
+ SSVAL(p,0,1);
+ /*
+ * Win2k needs a *smaller* buffer than 0xFFFF here -
+ * it returns "out of server memory" with 0xFFFF !!! JRA.
+ */
+ SSVAL(p,2,0xFFE0);
+ p += 4;
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 0xFFE0, /* data, length, maxlen - Win2k needs a small buffer here too ! */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ int res = rparam? SVAL(rparam,0) : -1;
+
+ if (res == 0 || res == ERRmoredata) {
+ int converter=SVAL(rparam,2);
+ int i;
+ char *rdata_end = rdata + rdrcnt;
+
+ count=SVAL(rparam,4);
+ p = rdata;
+
+ for (i=0;i<count;i++,p+=20) {
+ char *sname;
+ int type;
+ int comment_offset;
+ const char *cmnt;
+ const char *p1;
+ char *s1, *s2;
+ size_t len;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (p + 20 > rdata_end) {
+ TALLOC_FREE(frame);
+ break;
+ }
+
+ sname = p;
+ type = SVAL(p,14);
+ comment_offset = (IVAL(p,16) & 0xFFFF) - converter;
+ if (comment_offset < 0 ||
+ comment_offset > (int)rdrcnt) {
+ TALLOC_FREE(frame);
+ break;
+ }
+ cmnt = comment_offset?(rdata+comment_offset):"";
+
+ /* Work out the comment length. */
+ for (p1 = cmnt, len = 0; *p1 &&
+ p1 < rdata_end; len++)
+ p1++;
+ if (!*p1) {
+ len++;
+ }
+ pull_string_talloc(frame,rdata,0,
+ &s1,sname,14,STR_ASCII);
+ pull_string_talloc(frame,rdata,0,
+ &s2,cmnt,len,STR_ASCII);
+ if (!s1 || !s2) {
+ TALLOC_FREE(frame);
+ continue;
+ }
+
+ fn(s1, type, s2, state);
+
+ TALLOC_FREE(frame);
+ }
+ } else {
+ DEBUG(4,("NetShareEnum res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetShareEnum failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return count;
+}
+
+/****************************************************************************
+ Call a NetServerEnum for the specified workgroup and servertype mask. This
+ function then calls the specified callback function for each name returned.
+
+ The callback function takes 4 arguments: the machine name, the server type,
+ the comment and a state pointer.
+****************************************************************************/
+
+bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
+ void (*fn)(const char *, uint32, const char *, void *),
+ void *state)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *rdata_end = NULL;
+ unsigned int rdrcnt,rprcnt;
+ char *p;
+ char param[1024];
+ int uLevel = 1;
+ size_t len;
+ uint32 func = RAP_NetServerEnum2;
+ char *last_entry = NULL;
+ int total_cnt = 0;
+ int return_cnt = 0;
+ int res;
+
+ errno = 0; /* reset */
+
+ /*
+ * This may take more than one transaction, so we should loop until
+ * we no longer get a more data to process or we have all of the
+ * items.
+ */
+ do {
+ /* send a SMBtrans command with api NetServerEnum */
+ p = param;
+ SIVAL(p,0,func); /* api number */
+ p += 2;
+ /* Next time through we need to use the continue api */
+ func = RAP_NetServerEnum3;
+
+ if (last_entry) {
+ strlcpy(p,"WrLehDOz", sizeof(param)-PTR_DIFF(p,param));
+ } else {
+ strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
+ }
+
+ p = skip_string(param, sizeof(param), p);
+ strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
+
+ p = skip_string(param, sizeof(param), p);
+ SSVAL(p,0,uLevel);
+ SSVAL(p,2,CLI_BUFFER_SIZE);
+ p += 4;
+ SIVAL(p,0,stype);
+ p += 4;
+
+ /* If we have more data, tell the server where
+ * to continue from.
+ */
+ len = push_ascii(p,
+ last_entry ? last_entry : workgroup,
+ sizeof(param) - PTR_DIFF(p,param) - 1,
+ STR_TERMINATE|STR_UPPER);
+
+ if (len == (size_t)-1) {
+ SAFE_FREE(last_entry);
+ return false;
+ }
+ p += len;
+
+ if (!cli_api(cli,
+ param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt)) { /* return data, return size */
+
+ /* break out of the loop on error */
+ res = -1;
+ break;
+ }
+
+ rdata_end = rdata + rdrcnt;
+ res = rparam ? SVAL(rparam,0) : -1;
+
+ if (res == 0 || res == ERRmoredata ||
+ (res != -1 && cli_errno(cli) == 0)) {
+ char *sname = NULL;
+ int i, count;
+ int converter=SVAL(rparam,2);
+
+ /* Get the number of items returned in this buffer */
+ count = SVAL(rparam, 4);
+
+ /* The next field contains the number of items left,
+ * including those returned in this buffer. So the
+ * first time through this should contain all of the
+ * entries.
+ */
+ if (total_cnt == 0) {
+ total_cnt = SVAL(rparam, 6);
+ }
+
+ /* Keep track of how many we have read */
+ return_cnt += count;
+ p = rdata;
+
+ /* The last name in the previous NetServerEnum reply is
+ * sent back to server in the NetServerEnum3 request
+ * (last_entry). The next reply should repeat this entry
+ * as the first element. We have no proof that this is
+ * always true, but from traces that seems to be the
+ * behavior from Window Servers. So first lets do a lot
+ * of checking, just being paranoid. If the string
+ * matches then we already saw this entry so skip it.
+ *
+ * NOTE: sv1_name field must be null terminated and has
+ * a max size of 16 (NetBIOS Name).
+ */
+ if (last_entry && count && p &&
+ (strncmp(last_entry, p, 16) == 0)) {
+ count -= 1; /* Skip this entry */
+ return_cnt = -1; /* Not part of total, so don't count. */
+ p = rdata + 26; /* Skip the whole record */
+ }
+
+ for (i = 0; i < count; i++, p += 26) {
+ int comment_offset;
+ const char *cmnt;
+ const char *p1;
+ char *s1, *s2;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (p + 26 > rdata_end) {
+ TALLOC_FREE(frame);
+ break;
+ }
+
+ sname = p;
+ comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
+ cmnt = comment_offset?(rdata+comment_offset):"";
+
+ if (comment_offset < 0 || comment_offset > (int)rdrcnt) {
+ TALLOC_FREE(frame);
+ continue;
+ }
+
+ /* Work out the comment length. */
+ for (p1 = cmnt, len = 0; *p1 &&
+ p1 < rdata_end; len++)
+ p1++;
+ if (!*p1) {
+ len++;
+ }
+
+ stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ pull_string_talloc(frame,rdata,0,
+ &s1,sname,16,STR_ASCII);
+ pull_string_talloc(frame,rdata,0,
+ &s2,cmnt,len,STR_ASCII);
+
+ if (!s1 || !s2) {
+ TALLOC_FREE(frame);
+ continue;
+ }
+
+ fn(s1, stype, s2, state);
+ TALLOC_FREE(frame);
+ }
+
+ /* We are done with the old last entry, so now we can free it */
+ if (last_entry) {
+ SAFE_FREE(last_entry); /* This will set it to null */
+ }
+
+ /* We always make a copy of the last entry if we have one */
+ if (sname) {
+ last_entry = smb_xstrdup(sname);
+ }
+
+ /* If we have more data, but no last entry then error out */
+ if (!last_entry && (res == ERRmoredata)) {
+ errno = EINVAL;
+ res = 0;
+ }
+
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+ } while ((res == ERRmoredata) && (total_cnt > return_cnt));
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+ SAFE_FREE(last_entry);
+
+ if (res == -1) {
+ errno = cli_errno(cli);
+ } else {
+ if (!return_cnt) {
+ /* this is a very special case, when the domain master for the
+ work group isn't part of the work group itself, there is something
+ wild going on */
+ errno = ENOENT;
+ }
+ }
+
+ return(return_cnt > 0);
+}
+
+/****************************************************************************
+ Send a SamOEMChangePassword command.
+****************************************************************************/
+
+bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
+ const char *old_password)
+{
+ char param[1024];
+ unsigned char data[532];
+ char *p = param;
+ unsigned char old_pw_hash[16];
+ unsigned char new_pw_hash[16];
+ unsigned int data_len;
+ unsigned int param_len = 0;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned 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;
+ }
+
+ SSVAL(p,0,214); /* SamOEMChangePassword command. */
+ p += 2;
+ strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
+ p = skip_string(param,sizeof(param),p);
+ strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
+ p = skip_string(param,sizeof(param),p);
+ strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
+ p = skip_string(param,sizeof(param),p);
+ SSVAL(p,0,532);
+ p += 2;
+
+ param_len = PTR_DIFF(p,param);
+
+ /*
+ * Get the Lanman hash of the old password, we
+ * use this as the key to make_oem_passwd_hash().
+ */
+ E_deshash(old_password, old_pw_hash);
+
+ encode_pw_buffer(data, new_password, STR_ASCII);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("make_oem_passwd_hash\n"));
+ dump_data(100, data, 516);
+#endif
+ SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
+
+ /*
+ * Now place the old password hash in the data.
+ */
+ E_deshash(new_password, new_pw_hash);
+
+ E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
+
+ data_len = 532;
+
+ if (cli_send_trans(cli,SMBtrans,
+ PIPE_LANMAN, /* name */
+ 0,0, /* fid, flags */
+ NULL,0,0, /* setup, length, max */
+ param,param_len,2, /* param, length, max */
+ (char *)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)) {
+ DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n",
+ user ));
+ return False;
+ }
+
+ if (rparam) {
+ cli->rap_error = SVAL(rparam,0);
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return (cli->rap_error == 0);
+}
+
+/****************************************************************************
+ Send a qpathinfo call.
+****************************************************************************/
+
+bool cli_qpathinfo(struct cli_state *cli,
+ const char *fname,
+ time_t *change_time,
+ time_t *access_time,
+ time_t *write_time,
+ SMB_OFF_T *size,
+ uint16 *mode)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ unsigned int rparam_len, rdata_len;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ char *param;
+ char *rparam=NULL, *rdata=NULL;
+ int count=8;
+ bool ret;
+ time_t (*date_fn)(struct cli_state *, const void *);
+ char *p;
+ size_t nlen = 2*(strlen(fname)+1);
+
+ param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
+ if (!param) {
+ return false;
+ }
+ p = param;
+ memset(p, '\0', 6);
+ SSVAL(p, 0, SMB_INFO_STANDARD);
+ p += 6;
+ p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+ do {
+ ret = (cli_send_trans(cli, SMBtrans2,
+ NULL, /* Name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 10, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ ) &&
+ cli_receive_trans(cli, SMBtrans2,
+ &rparam, &rparam_len,
+ &rdata, &rdata_len));
+ if (!cli_is_dos_error(cli)) break;
+ if (!ret) {
+ /* we need to work around a Win95 bug - sometimes
+ it gives ERRSRV/ERRerror temprarily */
+ uint8 eclass;
+ uint32 ecode;
+ cli_dos_error(cli, &eclass, &ecode);
+ if (eclass != ERRSRV || ecode != ERRerror) break;
+ smb_msleep(100);
+ }
+ } while (count-- && ret==False);
+
+ SAFE_FREE(param);
+ if (!ret || !rdata || rdata_len < 22) {
+ return False;
+ }
+
+ if (cli->win95) {
+ date_fn = cli_make_unix_date;
+ } else {
+ date_fn = cli_make_unix_date2;
+ }
+
+ if (change_time) {
+ *change_time = date_fn(cli, rdata+0);
+ }
+ if (access_time) {
+ *access_time = date_fn(cli, rdata+4);
+ }
+ if (write_time) {
+ *write_time = date_fn(cli, rdata+8);
+ }
+ if (size) {
+ *size = IVAL(rdata, 12);
+ }
+ if (mode) {
+ *mode = SVAL(rdata,l1_attrFile);
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return True;
+}
+
+/****************************************************************************
+ Send a setpathinfo call.
+****************************************************************************/
+
+bool cli_setpathinfo(struct cli_state *cli, const char *fname,
+ time_t create_time,
+ time_t access_time,
+ time_t write_time,
+ time_t change_time,
+ uint16 mode)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ unsigned int rparam_len, rdata_len;
+ uint16 setup = TRANSACT2_SETPATHINFO;
+ char *param;
+ char data[40];
+ char *rparam=NULL, *rdata=NULL;
+ int count=8;
+ bool ret;
+ char *p;
+ size_t nlen = 2*(strlen(fname)+1);
+
+ param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
+ if (!param) {
+ return false;
+ }
+ memset(param, '\0', 6);
+ memset(data, 0, sizeof(data));
+
+ p = param;
+
+ /* Add the information level */
+ SSVAL(p, 0, SMB_FILE_BASIC_INFORMATION);
+
+ /* Skip reserved */
+ p += 6;
+
+ /* Add the file name */
+ p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
+
+ param_len = PTR_DIFF(p, param);
+
+ p = data;
+
+ /*
+ * Add the create, last access, modification, and status change times
+ */
+ put_long_date(p, create_time);
+ p += 8;
+
+ put_long_date(p, access_time);
+ p += 8;
+
+ put_long_date(p, write_time);
+ p += 8;
+
+ put_long_date(p, change_time);
+ p += 8;
+
+ /* Add attributes */
+ SIVAL(p, 0, mode);
+ p += 4;
+
+ /* Add padding */
+ SIVAL(p, 0, 0);
+ p += 4;
+
+ data_len = PTR_DIFF(p, data);
+
+ do {
+ ret = (cli_send_trans(cli, SMBtrans2,
+ NULL, /* Name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 10, /* param, length, max */
+ data, data_len, cli->max_xmit /* data, length, max */
+ ) &&
+ cli_receive_trans(cli, SMBtrans2,
+ &rparam, &rparam_len,
+ &rdata, &rdata_len));
+ if (!cli_is_dos_error(cli)) break;
+ if (!ret) {
+ /* we need to work around a Win95 bug - sometimes
+ it gives ERRSRV/ERRerror temprarily */
+ uint8 eclass;
+ uint32 ecode;
+ cli_dos_error(cli, &eclass, &ecode);
+ if (eclass != ERRSRV || ecode != ERRerror) break;
+ smb_msleep(100);
+ }
+ } while (count-- && ret==False);
+
+ SAFE_FREE(param);
+ if (!ret) {
+ return False;
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return True;
+}
+
+/****************************************************************************
+ Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
+****************************************************************************/
+
+bool cli_qpathinfo2(struct cli_state *cli, const char *fname,
+ struct timespec *create_time,
+ struct timespec *access_time,
+ struct timespec *write_time,
+ struct timespec *change_time,
+ SMB_OFF_T *size, uint16 *mode,
+ SMB_INO_T *ino)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ char *param;
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+ size_t nlen = 2*(strlen(fname)+1);
+
+ param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
+ if (!param) {
+ return false;
+ }
+ p = param;
+ memset(param, '\0', 6);
+ SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
+ p += 6;
+ p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
+
+ param_len = PTR_DIFF(p, param);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 10, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ SAFE_FREE(param);
+ return False;
+ }
+
+ SAFE_FREE(param);
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ if (!rdata || data_len < 22) {
+ return False;
+ }
+
+ if (create_time) {
+ *create_time = interpret_long_date(rdata+0);
+ }
+ if (access_time) {
+ *access_time = interpret_long_date(rdata+8);
+ }
+ if (write_time) {
+ *write_time = interpret_long_date(rdata+16);
+ }
+ if (change_time) {
+ *change_time = interpret_long_date(rdata+24);
+ }
+ if (mode) {
+ *mode = SVAL(rdata, 32);
+ }
+ if (size) {
+ *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
+ }
+ if (ino) {
+ *ino = IVAL(rdata, 64);
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return True;
+}
+
+/****************************************************************************
+ Get the stream info
+****************************************************************************/
+
+bool cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *pnum_streams,
+ struct stream_struct **pstreams)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ char *param;
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+ unsigned int num_streams;
+ struct stream_struct *streams;
+ unsigned int ofs;
+ size_t namelen = 2*(strlen(fname)+1);
+
+ param = SMB_MALLOC_ARRAY(char, 6+namelen+2);
+ if (param == NULL) {
+ return false;
+ }
+ p = param;
+ memset(p, 0, 6);
+ SSVAL(p, 0, SMB_FILE_STREAM_INFORMATION);
+ p += 6;
+ p += clistr_push(cli, p, fname, namelen, STR_TERMINATE);
+
+ param_len = PTR_DIFF(p, param);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, len, max */
+ param, param_len, 10, /* param, len, max */
+ NULL, data_len, cli->max_xmit /* data, len, max */
+ )) {
+ return false;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return false;
+ }
+
+ if (!rdata) {
+ SAFE_FREE(rparam);
+ return false;
+ }
+
+ num_streams = 0;
+ streams = NULL;
+ ofs = 0;
+
+ while ((data_len > ofs) && (data_len - ofs >= 24)) {
+ uint32_t nlen, len;
+ size_t size;
+ void *vstr;
+ struct stream_struct *tmp;
+ uint8_t *tmp_buf;
+
+ tmp = TALLOC_REALLOC_ARRAY(mem_ctx, streams,
+ struct stream_struct,
+ num_streams+1);
+
+ if (tmp == NULL) {
+ goto fail;
+ }
+ streams = tmp;
+
+ nlen = IVAL(rdata, ofs + 0x04);
+
+ streams[num_streams].size = IVAL_TO_SMB_OFF_T(
+ rdata, ofs + 0x08);
+ streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T(
+ rdata, ofs + 0x10);
+
+ if (nlen > data_len - (ofs + 24)) {
+ goto fail;
+ }
+
+ /*
+ * We need to null-terminate src, how do I do this with
+ * convert_string_talloc??
+ */
+
+ tmp_buf = TALLOC_ARRAY(streams, uint8_t, nlen+2);
+ if (tmp_buf == NULL) {
+ goto fail;
+ }
+
+ memcpy(tmp_buf, rdata+ofs+24, nlen);
+ tmp_buf[nlen] = 0;
+ tmp_buf[nlen+1] = 0;
+
+ if (!convert_string_talloc(streams, CH_UTF16, CH_UNIX, tmp_buf,
+ nlen+2, &vstr, &size, false))
+ {
+ TALLOC_FREE(tmp_buf);
+ goto fail;
+ }
+
+ TALLOC_FREE(tmp_buf);
+ streams[num_streams].name = (char *)vstr;
+ num_streams++;
+
+ len = IVAL(rdata, ofs);
+ if (len > data_len - ofs) {
+ goto fail;
+ }
+ if (len == 0) break;
+ ofs += len;
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ *pnum_streams = num_streams;
+ *pstreams = streams;
+ return true;
+
+ fail:
+ TALLOC_FREE(streams);
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return false;
+}
+
+/****************************************************************************
+ Send a qfileinfo QUERY_FILE_NAME_INFO call.
+****************************************************************************/
+
+bool cli_qfilename(struct cli_state *cli, int fnum, char *name, size_t namelen)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ uint16 setup = TRANSACT2_QFILEINFO;
+ char param[4];
+ char *rparam=NULL, *rdata=NULL;
+
+ param_len = 4;
+ SSVAL(param, 0, fnum);
+ SSVAL(param, 2, SMB_QUERY_FILE_NAME_INFO);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ if (!rdata || data_len < 4) {
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+ return False;
+ }
+
+ clistr_pull(cli, name, rdata+4, namelen, IVAL(rdata, 0), STR_UNICODE);
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return True;
+}
+
+/****************************************************************************
+ Send a qfileinfo call.
+****************************************************************************/
+
+bool cli_qfileinfo(struct cli_state *cli, int fnum,
+ uint16 *mode, SMB_OFF_T *size,
+ struct timespec *create_time,
+ struct timespec *access_time,
+ struct timespec *write_time,
+ struct timespec *change_time,
+ SMB_INO_T *ino)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ uint16 setup;
+ uint8_t param[4];
+ uint8_t *rparam=NULL, *rdata=NULL;
+ NTSTATUS status;
+
+ /* if its a win95 server then fail this - win95 totally screws it
+ up */
+ if (cli->win95) return False;
+
+ param_len = 4;
+
+ SSVAL(param, 0, fnum);
+ SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
+
+ SSVAL(&setup, 0, TRANSACT2_QFILEINFO);
+
+ status = cli_trans(talloc_tos(), cli, SMBtrans2,
+ NULL, -1, 0, 0, /* name, fid, function, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ NULL, 0, MIN(cli->max_xmit, 0xffff), /* data, length, max */
+ NULL, NULL, /* rsetup, length */
+ &rparam, &param_len, /* rparam, length */
+ &rdata, &data_len);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ if (!rdata || data_len < 68) {
+ return False;
+ }
+
+ if (create_time) {
+ *create_time = interpret_long_date((char *)rdata+0);
+ }
+ if (access_time) {
+ *access_time = interpret_long_date((char *)rdata+8);
+ }
+ if (write_time) {
+ *write_time = interpret_long_date((char *)rdata+16);
+ }
+ if (change_time) {
+ *change_time = interpret_long_date((char *)rdata+24);
+ }
+ if (mode) {
+ *mode = SVAL(rdata, 32);
+ }
+ if (size) {
+ *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
+ }
+ if (ino) {
+ *ino = IVAL(rdata, 64);
+ }
+
+ TALLOC_FREE(rdata);
+ TALLOC_FREE(rparam);
+ return True;
+}
+
+/****************************************************************************
+ Send a qpathinfo BASIC_INFO call.
+****************************************************************************/
+
+bool cli_qpathinfo_basic( struct cli_state *cli, const char *name,
+ SMB_STRUCT_STAT *sbuf, uint32 *attributes )
+{
+ unsigned int param_len = 0;
+ unsigned int data_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ char *param;
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+ char *path;
+ int len;
+ size_t nlen;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ path = talloc_strdup(frame, name);
+ if (!path) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+ /* cleanup */
+
+ len = strlen(path);
+ if ( path[len-1] == '\\' || path[len-1] == '/') {
+ path[len-1] = '\0';
+ }
+ nlen = 2*(strlen(path)+1);
+
+ param = TALLOC_ARRAY(frame,char,6+nlen+2);
+ if (!param) {
+ return false;
+ }
+ p = param;
+ memset(param, '\0', 6);
+
+ SSVAL(p, 0, SMB_QUERY_FILE_BASIC_INFO);
+ p += 6;
+ p += clistr_push(cli, p, path, nlen, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ NULL, 0, cli->max_xmit /* data, length, max */
+ )) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ TALLOC_FREE(frame);
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ if (data_len < 36) {
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return False;
+ }
+
+ set_atimespec(sbuf, interpret_long_date( rdata+8 )); /* Access time. */
+ set_mtimespec(sbuf, interpret_long_date( rdata+16 )); /* Write time. */
+ set_ctimespec(sbuf, interpret_long_date( rdata+24 )); /* Change time. */
+
+ *attributes = IVAL( rdata, 32 );
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return True;
+}
+
+/****************************************************************************
+ Send a qfileinfo call.
+****************************************************************************/
+
+bool cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutdata, uint32 *poutlen)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ uint16 setup = TRANSACT2_QFILEINFO;
+ char param[4];
+ char *rparam=NULL, *rdata=NULL;
+
+ *poutdata = NULL;
+ *poutlen = 0;
+
+ /* if its a win95 server then fail this - win95 totally screws it
+ up */
+ if (cli->win95)
+ return False;
+
+ param_len = 4;
+
+ SSVAL(param, 0, fnum);
+ SSVAL(param, 2, level);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ *poutdata = (char *)memdup(rdata, data_len);
+ if (!*poutdata) {
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return False;
+ }
+
+ *poutlen = data_len;
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return True;
+}
+
+/****************************************************************************
+ Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
+****************************************************************************/
+
+NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ char *param;
+ char *rparam=NULL, *rdata=NULL;
+ int count=8;
+ char *p;
+ bool ret;
+ unsigned int len;
+ size_t nlen = 2*(strlen(fname)+1);
+
+ param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
+ if (!param) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ p = param;
+ memset(param, '\0', 6);
+ SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
+ p += 6;
+ p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+ do {
+ ret = (cli_send_trans(cli, SMBtrans2,
+ NULL, /* Name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 10, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ ) &&
+ cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len));
+ if (!ret && cli_is_dos_error(cli)) {
+ /* we need to work around a Win95 bug - sometimes
+ it gives ERRSRV/ERRerror temprarily */
+ uint8 eclass;
+ uint32 ecode;
+ cli_dos_error(cli, &eclass, &ecode);
+ if (eclass != ERRSRV || ecode != ERRerror) break;
+ smb_msleep(100);
+ }
+ } while (count-- && ret==False);
+
+ SAFE_FREE(param);
+
+ if (!ret || !rdata || data_len < 4) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ len = IVAL(rdata, 0);
+
+ if (len > data_len - 4) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ clistr_pull(cli, alt_name, rdata+4, sizeof(fstring), len, STR_UNICODE);
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/libsmb/clirap2.c b/source3/libsmb/clirap2.c
new file mode 100644
index 0000000000..a15fa5f7d8
--- /dev/null
+++ b/source3/libsmb/clirap2.c
@@ -0,0 +1,2675 @@
+/*
+ Samba Unix/Linux SMB client library
+ More client RAP (SMB Remote Procedure Calls) functions
+ Copyright (C) 2001 Steve French (sfrench@us.ibm.com)
+ Copyright (C) 2001 Jim McDonough (jmcd@us.ibm.com)
+ Copyright (C) 2007 Jeremy Allison. jra@samba.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*****************************************************/
+/* */
+/* Additional RAP functionality */
+/* */
+/* RAP is the original SMB RPC, documented */
+/* by Microsoft and X/Open in the 1990s and */
+/* supported by most SMB/CIFS servers although */
+/* it is unlikely that any one implementation */
+/* supports all RAP command codes since some */
+/* are quite obsolete and a few are specific */
+/* to a particular network operating system */
+/* */
+/* Although it has largely been replaced */
+/* for complex remote admistration and management */
+/* (of servers) by the relatively newer */
+/* DCE/RPC based remote API (which better handles */
+/* large >64K data structures), there are many */
+/* important administrative and resource location */
+/* tasks and user tasks (e.g. password change) */
+/* that are performed via RAP. */
+/* */
+/* Although a few of the RAP calls are implemented */
+/* in the Samba client library already (clirap.c) */
+/* the new ones are in clirap2.c for easy patching */
+/* and integration and a corresponding header */
+/* file, rap.h, has been created. */
+/* */
+/* This is based on data from the CIFS spec */
+/* and the LAN Server and LAN Manager */
+/* Programming Reference books and published */
+/* RAP document and CIFS forum postings and */
+/* lots of trial and error */
+/* */
+/* Function names changed from API_ (as they are */
+/* in the CIFS specification) to RAP_ in order */
+/* to avoid confusion with other API calls */
+/* sent via DCE RPC */
+/* */
+/*****************************************************/
+
+/*****************************************************/
+/* */
+/* cifsrap.c already includes support for: */
+/* */
+/* WshareEnum ( API number 0, level 1) */
+/* NetServerEnum2 (API num 104, level 1) */
+/* WWkstaUserLogon (132) */
+/* SamOEMchgPasswordUser2_P (214) */
+/* */
+/* cifsprint.c already includes support for: */
+/* */
+/* WPrintJobEnum (API num 76, level 2) */
+/* WPrintJobDel (API num 81) */
+/* */
+/*****************************************************/
+
+#include "includes.h"
+
+#define WORDSIZE 2
+#define DWORDSIZE 4
+
+#define PUTBYTE(p,b) do {SCVAL(p,0,b); p++;} while(0)
+
+#define GETBYTE(p,b,endp) \
+ do {\
+ if (p+1 < endp) {\
+ b = CVAL(p,0);\
+ }\
+ p++;\
+ } while(0)
+
+#define PUTWORD(p,w) do {SSVAL(p,0,w); p += WORDSIZE;} while(0)
+
+#define GETWORD(p,w,endp) \
+ do {\
+ if (p+WORDSIZE < endp) {\
+ w = SVAL(p,0);\
+ }\
+ p += WORDSIZE;\
+ } while(0)
+
+#define PUTDWORD(p,d) do {SIVAL(p,0,d); p += DWORDSIZE;} while(0)
+
+#define GETDWORD(p,d,endp) \
+ do {\
+ if (p+DWORDSIZE < endp) {\
+ d = IVAL(p,0);\
+ }\
+ p += DWORDSIZE;\
+ } while(0)
+
+#define GETRES(p,endp) ((p && p+2 < endp) ? SVAL(p,0) : -1)
+
+/* put string s at p with max len n and increment p past string */
+#define PUTSTRING(p,s,n) \
+ do {\
+ push_ascii(p,s?s:"",n?n:256,STR_TERMINATE);\
+ p = push_skip_string(p);\
+ } while(0)
+
+/* put string s and p, using fixed len l, and increment p by l */
+#define PUTSTRINGF(p,s,l) \
+ do {\
+ push_ascii(p,s?s:"",l,STR_TERMINATE);\
+ p += l;\
+ } while (0)
+
+/* put string pointer at p, supplying offset o from rdata r, store */
+/* dword offset at p, increment p by 4 and o by length of s. This */
+/* means on the first call, you must calc the offset yourself! */
+
+#define PUTSTRINGP(p,s,r,o) \
+ do {\
+ if (s) {\
+ push_ascii(r+o,s,strlen(s)+1,STR_TERMINATE);\
+ PUTDWORD(p,o);\
+ o += strlen(s) + 1;\
+ } else {\
+ PUTDWORD(p,0);\
+ }\
+ }while(0);
+
+/* get asciiz string dest from src, return increment past string */
+
+static size_t rap_getstring(TALLOC_CTX *ctx, char *src, char **dest, const char *endp)
+{
+ char *p1;
+ size_t len;
+
+ *dest = NULL;
+ for (p1 = src, len = 0; *p1 && p1 < endp; len++)
+ p1++;
+ if (!*p1) {
+ len++;
+ }
+ pull_string_talloc(ctx,src,0,dest,src,len,STR_ASCII);
+ return len;
+}
+
+/* get fixed length l string dest from src, return increment for src */
+
+static size_t rap_getstringf(char *src, char *dest, size_t l, size_t dlen, char *endp)
+{
+ char *p1;
+ size_t len;
+
+ if (dlen) {
+ dest[0] = '\0';
+ }
+ for (p1 = src, len = 0; *p1 && p1 < endp; len++) {
+ p1++;
+ }
+ if (!*p1) {
+ len++;
+ }
+ if (len > l) {
+ len = l;
+ }
+ if (len) {
+ pull_ascii(dest,src,len,len,STR_ASCII);
+ }
+ return l;
+}
+
+/* get string dest from offset (obtained at p) from rdata r - converter c */
+static size_t rap_getstringp(TALLOC_CTX *ctx, char *p, char **dest, char *r, uint16_t c, char *endp)
+{
+ uint32_t off = 0;
+ const char *src;
+ size_t len=0;
+
+ *dest = NULL;
+ if (p+4 < endp) {
+ GETDWORD(p,off,endp);
+ off &= 0x0000FFFF; /* mask the obsolete segment number from the offset */
+ off -= c;
+ }
+ if (r+off > endp || r+off < r) {
+ src="";
+ len=1;
+ } else {
+ const char *p1;
+ src=r+off;
+ for (p1 = src, len = 0; *p1 && p1 < endp; len++) {
+ p1++;
+ }
+ if (!*p1) {
+ len++;
+ }
+ }
+ pull_string_talloc(ctx,src,0,dest,src,len,STR_ASCII);
+ return len;
+}
+
+static char *make_header(char *param, uint16 apinum, const char *reqfmt, const char *datafmt)
+{
+ PUTWORD(param,apinum);
+ if (reqfmt)
+ PUTSTRING(param,reqfmt,0);
+ else
+ *param++ = (char) 0;
+
+ if (datafmt)
+ PUTSTRING(param,datafmt,0);
+ else
+ *param++ = (char) 0;
+
+ return param;
+}
+
+/****************************************************************************
+ call a NetGroupDelete - delete user group from remote server
+****************************************************************************/
+
+int cli_NetGroupDelete(struct cli_state *cli, const char *group_name)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ int res = -1;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupDel_REQ) /* parm string */
+ +1 /* no ret string */
+ +RAP_GROUPNAME_LEN /* group to del */
+ +WORDSIZE]; /* reserved word */
+
+ /* now send a SMBtrans command with api GroupDel */
+ p = make_header(param, RAP_WGroupDel, RAP_NetGroupDel_REQ, NULL);
+ PUTSTRING(p, group_name, RAP_GROUPNAME_LEN);
+ PUTWORD(p,0); /* reserved word MBZ on input */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam,endp);
+
+ if (res == 0) {
+ /* nothing to do */
+ } else if ((res == 5) || (res == 65)) {
+ DEBUG(1, ("Access Denied\n"));
+ } else if (res == 2220) {
+ DEBUG (1, ("Group does not exist\n"));
+ } else {
+ DEBUG(4,("NetGroupDelete res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetGroupDelete failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ call a NetGroupAdd - add user group to remote server
+****************************************************************************/
+
+int cli_NetGroupAdd(struct cli_state *cli, RAP_GROUP_INFO_1 *grinfo)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ int res = -1;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupAdd_REQ) /* req string */
+ +sizeof(RAP_GROUP_INFO_L1) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* reserved word */
+
+ /* offset into data of free format strings. Will be updated */
+ /* by PUTSTRINGP macro and end up with total data length. */
+ int soffset = RAP_GROUPNAME_LEN + 1 + DWORDSIZE;
+ char *data;
+ size_t data_size;
+
+ /* Allocate data. */
+ data_size = MAX(soffset + strlen(grinfo->comment) + 1, 1024);
+
+ data = SMB_MALLOC_ARRAY(char, data_size);
+ if (!data) {
+ DEBUG (1, ("Malloc fail\n"));
+ return -1;
+ }
+
+ /* now send a SMBtrans command with api WGroupAdd */
+
+ p = make_header(param, RAP_WGroupAdd,
+ RAP_NetGroupAdd_REQ, RAP_GROUP_INFO_L1);
+ PUTWORD(p, 1); /* info level */
+ PUTWORD(p, 0); /* reserved word 0 */
+
+ p = data;
+ PUTSTRINGF(p, grinfo->group_name, RAP_GROUPNAME_LEN);
+ PUTBYTE(p, 0); /* pad byte 0 */
+ PUTSTRINGP(p, grinfo->comment, data, soffset);
+
+ if (cli_api(cli,
+ param, sizeof(param), 1024, /* Param, length, maxlen */
+ data, soffset, sizeof(data), /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam, endp);
+
+ if (res == 0) {
+ /* nothing to do */
+ } else if ((res == 5) || (res == 65)) {
+ DEBUG(1, ("Access Denied\n"));
+ } else if (res == 2223) {
+ DEBUG (1, ("Group already exists\n"));
+ } else {
+ DEBUG(4,("NetGroupAdd res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetGroupAdd failed\n"));
+ }
+
+ SAFE_FREE(data);
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ Call a NetGroupEnum - try and list user groups on a different host.
+****************************************************************************/
+
+int cli_RNetGroupEnum(struct cli_state *cli, void (*fn)(const char *, const char *, void *), void *state)
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupEnum_REQ) /* parm string */
+ +sizeof(RAP_GROUP_INFO_L1) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rprcnt, rdrcnt;
+ int res = -1;
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WGroupEnum,
+ RAP_NetGroupEnum_REQ, RAP_GROUP_INFO_L1);
+ PUTWORD(p,1); /* Info level 1 */ /* add level 0 */
+ PUTWORD(p,0xFFE0); /* Return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),8,
+ NULL, 0, 0xFFE0 /* data area size */,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ char *endp = rparam + rdrcnt;
+
+ res = GETRES(rparam, endp);
+ cli->rap_error = res;
+ if(cli->rap_error == 234) {
+ DEBUG(1,("Not all group names were returned (such as those longer than 21 characters)\n"));
+ } else if (cli->rap_error != 0) {
+ DEBUG(1,("NetGroupEnum gave error %d\n", cli->rap_error));
+ }
+ }
+
+ if (!rdata) {
+ DEBUG(4,("NetGroupEnum no data returned\n"));
+ goto out;
+ }
+
+ if (res == 0 || res == ERRmoredata) {
+ char *endp = rparam + rprcnt;
+ int i, converter = 0, count = 0;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ p = rparam + WORDSIZE; /* skip result */
+ GETWORD(p, converter, endp);
+ GETWORD(p, count, endp);
+
+ endp = rdata + rdrcnt;
+ for (i=0,p=rdata; i<count && p < endp;i++) {
+ char *comment = NULL;
+ char groupname[RAP_GROUPNAME_LEN];
+
+ p += rap_getstringf(p,
+ groupname,
+ RAP_GROUPNAME_LEN,
+ RAP_GROUPNAME_LEN,
+ endp);
+ p++; /* pad byte */
+ p += rap_getstringp(frame,
+ p,
+ &comment,
+ rdata,
+ converter,
+ endp);
+
+ if (!comment || !groupname[0]) {
+ break;
+ }
+
+ fn(groupname, comment, cli);
+ }
+ TALLOC_FREE(frame);
+ } else {
+ DEBUG(4,("NetGroupEnum res=%d\n", res));
+ }
+
+ out:
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+int cli_RNetGroupEnum0(struct cli_state *cli,
+ void (*fn)(const char *, void *),
+ void *state)
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupEnum_REQ) /* parm string */
+ +sizeof(RAP_GROUP_INFO_L0) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rprcnt, rdrcnt;
+ int res = -1;
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WGroupEnum,
+ RAP_NetGroupEnum_REQ, RAP_GROUP_INFO_L0);
+ PUTWORD(p,0); /* Info level 0 */ /* Hmmm. I *very* much suspect this
+ is the resume count, at least
+ that's what smbd believes... */
+ PUTWORD(p,0xFFE0); /* Return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),8,
+ NULL, 0, 0xFFE0 /* data area size */,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ char *endp = rparam+rprcnt;
+ res = GETRES(rparam,endp);
+ cli->rap_error = res;
+ if(cli->rap_error == 234) {
+ DEBUG(1,("Not all group names were returned (such as those longer than 21 characters)\n"));
+ } else if (cli->rap_error != 0) {
+ DEBUG(1,("NetGroupEnum gave error %d\n", cli->rap_error));
+ }
+ }
+
+ if (!rdata) {
+ DEBUG(4,("NetGroupEnum no data returned\n"));
+ goto out;
+ }
+
+ if (res == 0 || res == ERRmoredata) {
+ char *endp = rparam + rprcnt;
+ int i, count = 0;
+
+ p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
+ GETWORD(p, count, endp);
+
+ endp = rdata + rdrcnt;
+ for (i=0,p=rdata; i<count && p < endp;i++) {
+ char groupname[RAP_GROUPNAME_LEN];
+
+ p += rap_getstringf(p,
+ groupname,
+ RAP_GROUPNAME_LEN,
+ RAP_GROUPNAME_LEN,
+ endp);
+ if (groupname[0]) {
+ fn(groupname, cli);
+ }
+ }
+ } else {
+ DEBUG(4,("NetGroupEnum res=%d\n", res));
+ }
+
+ out:
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+int cli_NetGroupDelUser(struct cli_state * cli, const char *group_name, const char *user_name)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ int res = -1;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupDelUser_REQ) /* parm string */
+ +1 /* no ret string */
+ +RAP_GROUPNAME_LEN /* group name */
+ +RAP_USERNAME_LEN]; /* user to del */
+
+ /* now send a SMBtrans command with api GroupMemberAdd */
+ p = make_header(param, RAP_WGroupDelUser, RAP_NetGroupDelUser_REQ, NULL);
+ PUTSTRING(p,group_name,RAP_GROUPNAME_LEN);
+ PUTSTRING(p,user_name,RAP_USERNAME_LEN);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam,endp);
+
+ switch(res) {
+ case 0:
+ break;
+ case 5:
+ case 65:
+ DEBUG(1, ("Access Denied\n"));
+ break;
+ case 50:
+ DEBUG(1, ("Not supported by server\n"));
+ break;
+ case 2220:
+ DEBUG(1, ("Group does not exist\n"));
+ break;
+ case 2221:
+ DEBUG(1, ("User does not exist\n"));
+ break;
+ case 2237:
+ DEBUG(1, ("User is not in group\n"));
+ break;
+ default:
+ DEBUG(4,("NetGroupDelUser res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetGroupDelUser failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+int cli_NetGroupAddUser(struct cli_state * cli, const char *group_name, const char *user_name)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ int res = -1;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupAddUser_REQ) /* parm string */
+ +1 /* no ret string */
+ +RAP_GROUPNAME_LEN /* group name */
+ +RAP_USERNAME_LEN]; /* user to add */
+
+ /* now send a SMBtrans command with api GroupMemberAdd */
+ p = make_header(param, RAP_WGroupAddUser, RAP_NetGroupAddUser_REQ, NULL);
+ PUTSTRING(p,group_name,RAP_GROUPNAME_LEN);
+ PUTSTRING(p,user_name,RAP_USERNAME_LEN);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam,endp);
+
+ switch(res) {
+ case 0:
+ break;
+ case 5:
+ case 65:
+ DEBUG(1, ("Access Denied\n"));
+ break;
+ case 50:
+ DEBUG(1, ("Not supported by server\n"));
+ break;
+ case 2220:
+ DEBUG(1, ("Group does not exist\n"));
+ break;
+ case 2221:
+ DEBUG(1, ("User does not exist\n"));
+ break;
+ default:
+ DEBUG(4,("NetGroupAddUser res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetGroupAddUser failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+
+int cli_NetGroupGetUsers(struct cli_state * cli, const char *group_name, void (*fn)(const char *, void *), void *state )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ int res = -1;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupGetUsers_REQ)/* parm string */
+ +sizeof(RAP_GROUP_USERS_INFO_0) /* return string */
+ +RAP_GROUPNAME_LEN /* group name */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+
+ /* now send a SMBtrans command with api GroupGetUsers */
+ p = make_header(param, RAP_WGroupGetUsers,
+ RAP_NetGroupGetUsers_REQ, RAP_GROUP_USERS_INFO_0);
+ PUTSTRING(p,group_name,RAP_GROUPNAME_LEN-1);
+ PUTWORD(p,0); /* info level 0 */
+ PUTWORD(p,0xFFE0); /* return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),PTR_DIFF(p,param),
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam,endp);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetGroupGetUsers gave error %d\n", res));
+ }
+ }
+
+ if (!rdata) {
+ DEBUG(4,("NetGroupGetUsers no data returned\n"));
+ goto out;
+ }
+
+ if (res == 0 || res == ERRmoredata) {
+ char *endp = rparam + rprcnt;
+ int i, count = 0;
+ char username[RAP_USERNAME_LEN];
+
+ p = rparam + WORDSIZE + WORDSIZE;
+ GETWORD(p, count, endp);
+
+ endp = rdata + rdrcnt;
+ for (i=0,p=rdata; i<count && p < endp; i++) {
+ p += rap_getstringf(p,
+ username,
+ RAP_USERNAME_LEN,
+ RAP_USERNAME_LEN,
+ endp);
+ if (username[0]) {
+ fn(username, state);
+ }
+ }
+ } else {
+ DEBUG(4,("NetGroupGetUsers res=%d\n", res));
+ }
+
+ out:
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return res;
+}
+
+int cli_NetUserGetGroups(struct cli_state * cli, const char *user_name, void (*fn)(const char *, void *), void *state )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ int res = -1;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetUserGetGroups_REQ)/* parm string */
+ +sizeof(RAP_GROUP_USERS_INFO_0) /* return string */
+ +RAP_USERNAME_LEN /* user name */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+
+ /* now send a SMBtrans command with api GroupGetUsers */
+ p = make_header(param, RAP_WUserGetGroups,
+ RAP_NetUserGetGroups_REQ, RAP_GROUP_USERS_INFO_0);
+ PUTSTRING(p,user_name,RAP_USERNAME_LEN-1);
+ PUTWORD(p,0); /* info level 0 */
+ PUTWORD(p,0xFFE0); /* return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),PTR_DIFF(p,param),
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam,endp);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetUserGetGroups gave error %d\n", res));
+ }
+ }
+
+ if (!rdata) {
+ DEBUG(4,("NetUserGetGroups no data returned\n"));
+ goto out;
+ }
+
+ if (res == 0 || res == ERRmoredata) {
+ char *endp = rparam + rprcnt;
+ int i, count = 0;
+ char groupname[RAP_GROUPNAME_LEN];
+
+ p = rparam + WORDSIZE + WORDSIZE;
+ GETWORD(p, count, endp);
+
+ endp = rdata + rdrcnt;
+ for (i=0,p=rdata; i<count && p < endp; i++) {
+ p += rap_getstringf(p,
+ groupname,
+ RAP_GROUPNAME_LEN,
+ RAP_GROUPNAME_LEN,
+ endp);
+ if (groupname[0]) {
+ fn(groupname, state);
+ }
+ }
+ } else {
+ DEBUG(4,("NetUserGetGroups res=%d\n", res));
+ }
+
+ out:
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return res;
+}
+
+/****************************************************************************
+ Call a NetUserDelete - delete user from remote server.
+****************************************************************************/
+
+int cli_NetUserDelete(struct cli_state *cli, const char * user_name )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ int res = -1;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupDel_REQ) /* parm string */
+ +1 /* no ret string */
+ +RAP_USERNAME_LEN /* user to del */
+ +WORDSIZE]; /* reserved word */
+
+ /* now send a SMBtrans command with api UserDel */
+ p = make_header(param, RAP_WUserDel, RAP_NetGroupDel_REQ, NULL);
+ PUTSTRING(p, user_name, RAP_USERNAME_LEN);
+ PUTWORD(p,0); /* reserved word MBZ on input */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam,endp);
+
+ if (res == 0) {
+ /* nothing to do */
+ } else if ((res == 5) || (res == 65)) {
+ DEBUG(1, ("Access Denied\n"));
+ } else if (res == 2221) {
+ DEBUG (1, ("User does not exist\n"));
+ } else {
+ DEBUG(4,("NetUserDelete res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetUserDelete failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ Call a NetUserAdd - add user to remote server.
+****************************************************************************/
+
+int cli_NetUserAdd(struct cli_state *cli, RAP_USER_INFO_1 * userinfo )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ int res = -1;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetUserAdd2_REQ) /* req string */
+ +sizeof(RAP_USER_INFO_L1) /* data string */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer length */
+ +WORDSIZE]; /* reserved */
+
+ char data[1024];
+ /* offset into data of free format strings. Will be updated */
+ /* by PUTSTRINGP macro and end up with total data length. */
+ int soffset=RAP_USERNAME_LEN+1 /* user name + pad */
+ + RAP_UPASSWD_LEN /* password */
+ + DWORDSIZE /* password age */
+ + WORDSIZE /* privilege */
+ + DWORDSIZE /* home dir ptr */
+ + DWORDSIZE /* comment ptr */
+ + WORDSIZE /* flags */
+ + DWORDSIZE; /* login script ptr*/
+
+ /* now send a SMBtrans command with api NetUserAdd */
+ p = make_header(param, RAP_WUserAdd2,
+ RAP_NetUserAdd2_REQ, RAP_USER_INFO_L1);
+
+ PUTWORD(p, 1); /* info level */
+ PUTWORD(p, 0); /* pwencrypt */
+ if(userinfo->passwrd)
+ PUTWORD(p,MIN(strlen(userinfo->passwrd), RAP_UPASSWD_LEN));
+ else
+ PUTWORD(p, 0); /* password length */
+
+ p = data;
+ memset(data, '\0', soffset);
+
+ PUTSTRINGF(p, userinfo->user_name, RAP_USERNAME_LEN);
+ PUTBYTE(p, 0); /* pad byte 0 */
+ PUTSTRINGF(p, userinfo->passwrd, RAP_UPASSWD_LEN);
+ PUTDWORD(p, 0); /* pw age - n.a. on user add */
+ PUTWORD(p, userinfo->priv);
+ PUTSTRINGP(p, userinfo->home_dir, data, soffset);
+ PUTSTRINGP(p, userinfo->comment, data, soffset);
+ PUTWORD(p, userinfo->userflags);
+ PUTSTRINGP(p, userinfo->logon_script, data, soffset);
+
+ if (cli_api(cli,
+ param, sizeof(param), 1024, /* Param, length, maxlen */
+ data, soffset, sizeof(data), /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam, endp);
+
+ if (res == 0) {
+ /* nothing to do */
+ } else if ((res == 5) || (res == 65)) {
+ DEBUG(1, ("Access Denied\n"));
+ } else if (res == 2224) {
+ DEBUG (1, ("User already exists\n"));
+ } else {
+ DEBUG(4,("NetUserAdd res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetUserAdd failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+call a NetUserEnum - try and list users on a different host
+****************************************************************************/
+
+int cli_RNetUserEnum(struct cli_state *cli, void (*fn)(const char *, const char *, const char *, const char *, void *), void *state)
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetUserEnum_REQ) /* parm string */
+ +sizeof(RAP_USER_INFO_L1) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rprcnt, rdrcnt;
+ int res = -1;
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WUserEnum,
+ RAP_NetUserEnum_REQ, RAP_USER_INFO_L1);
+ PUTWORD(p,1); /* Info level 1 */
+ PUTWORD(p,0xFF00); /* Return buffer size */
+
+ /* BB Fix handling of large numbers of users to be returned */
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),8,
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam,endp);
+ cli->rap_error = res;
+ if (cli->rap_error != 0) {
+ DEBUG(1,("NetUserEnum gave error %d\n", cli->rap_error));
+ }
+ }
+
+ if (!rdata) {
+ DEBUG(4,("NetUserEnum no data returned\n"));
+ goto out;
+ }
+
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter = 0, count = 0;
+ char username[RAP_USERNAME_LEN];
+ char userpw[RAP_UPASSWD_LEN];
+ char *endp = rparam + rprcnt;
+ char *comment, *homedir, *logonscript;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ p = rparam + WORDSIZE; /* skip result */
+ GETWORD(p, converter, endp);
+ GETWORD(p, count, endp);
+
+ endp = rdata + rdrcnt;
+ for (i=0,p=rdata;i<count && p < endp;i++) {
+ p += rap_getstringf(p,
+ username,
+ RAP_USERNAME_LEN,
+ RAP_USERNAME_LEN,
+ endp);
+ p++; /* pad byte */
+ p += rap_getstringf(p,
+ userpw,
+ RAP_UPASSWD_LEN,
+ RAP_UPASSWD_LEN,
+ endp);
+ p += DWORDSIZE; /* skip password age */
+ p += WORDSIZE; /* skip priv: 0=guest, 1=user, 2=admin */
+ p += rap_getstringp(frame,
+ p,
+ &homedir,
+ rdata,
+ converter,
+ endp);
+ p += rap_getstringp(frame,
+ p,
+ &comment,
+ rdata,
+ converter,
+ endp);
+ p += WORDSIZE; /* skip flags */
+ p += rap_getstringp(frame,
+ p,
+ &logonscript,
+ rdata,
+ converter,
+ endp);
+ if (username[0] && comment &&
+ homedir && logonscript) {
+ fn(username,
+ comment,
+ homedir,
+ logonscript,
+ cli);
+ }
+ }
+ TALLOC_FREE(frame);
+ } else {
+ DEBUG(4,("NetUserEnum res=%d\n", res));
+ }
+
+ out:
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+int cli_RNetUserEnum0(struct cli_state *cli,
+ void (*fn)(const char *, void *),
+ void *state)
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetUserEnum_REQ) /* parm string */
+ +sizeof(RAP_USER_INFO_L0) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rprcnt, rdrcnt;
+ int res = -1;
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WUserEnum,
+ RAP_NetUserEnum_REQ, RAP_USER_INFO_L0);
+ PUTWORD(p,0); /* Info level 1 */
+ PUTWORD(p,0xFF00); /* Return buffer size */
+
+ /* BB Fix handling of large numbers of users to be returned */
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),8,
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam,endp);
+ cli->rap_error = res;
+ if (cli->rap_error != 0) {
+ DEBUG(1,("NetUserEnum gave error %d\n", cli->rap_error));
+ }
+ }
+
+ if (!rdata) {
+ DEBUG(4,("NetUserEnum no data returned\n"));
+ goto out;
+ }
+
+ if (res == 0 || res == ERRmoredata) {
+ int i, count = 0;
+ char *endp = rparam + rprcnt;
+ char username[RAP_USERNAME_LEN];
+
+ p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
+ GETWORD(p, count, endp);
+
+ endp = rdata + rdrcnt;
+ for (i=0,p=rdata;i<count && p < endp;i++) {
+ p += rap_getstringf(p,
+ username,
+ RAP_USERNAME_LEN,
+ RAP_USERNAME_LEN,
+ endp);
+ if (username[0]) {
+ fn(username, cli);
+ }
+ }
+ } else {
+ DEBUG(4,("NetUserEnum res=%d\n", res));
+ }
+
+ out:
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ Call a NetFileClose2 - close open file on another session to server.
+****************************************************************************/
+
+int cli_NetFileClose(struct cli_state *cli, uint32 file_id )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WFileClose2_REQ) /* req string */
+ +1 /* no ret string */
+ +DWORDSIZE]; /* file ID */
+ int res = -1;
+
+ /* now send a SMBtrans command with api RNetShareEnum */
+ p = make_header(param, RAP_WFileClose2, RAP_WFileClose2_REQ, NULL);
+ PUTDWORD(p, file_id);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam, endp);
+
+ if (res == 0) {
+ /* nothing to do */
+ } else if (res == 2314){
+ DEBUG(1, ("NetFileClose2 - attempt to close non-existant file open instance\n"));
+ } else {
+ DEBUG(4,("NetFileClose2 res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetFileClose2 failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ Call a NetFileGetInfo - get information about server file opened from other
+ workstation.
+****************************************************************************/
+
+int cli_NetFileGetInfo(struct cli_state *cli, uint32 file_id, void (*fn)(const char *, const char *, uint16, uint16, uint32))
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ int res = -1;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WFileGetInfo2_REQ) /* req string */
+ +sizeof(RAP_FILE_INFO_L3) /* return string */
+ +DWORDSIZE /* file ID */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+
+ /* now send a SMBtrans command with api RNetShareEnum */
+ p = make_header(param, RAP_WFileGetInfo2,
+ RAP_WFileGetInfo2_REQ, RAP_FILE_INFO_L3);
+ PUTDWORD(p, file_id);
+ PUTWORD(p, 3); /* info level */
+ PUTWORD(p, 0x1000); /* buffer size */
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 0x1000, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam,endp);
+ if (res == 0 || res == ERRmoredata) {
+ TALLOC_CTX *frame = talloc_stackframe();
+ int converter = 0,id = 0, perms = 0, locks = 0;
+ char *fpath, *fuser;
+
+ p = rparam + WORDSIZE; /* skip result */
+ GETWORD(p, converter, endp);
+
+ p = rdata;
+ endp = rdata + rdrcnt;
+
+ GETDWORD(p, id, endp);
+ GETWORD(p, perms, endp);
+ GETWORD(p, locks, endp);
+
+ p += rap_getstringp(frame,
+ p,
+ &fpath,
+ rdata,
+ converter,
+ endp);
+ p += rap_getstringp(frame,
+ p,
+ &fuser,
+ rdata,
+ converter,
+ endp);
+
+ if (fpath && fuser) {
+ fn(fpath, fuser, perms, locks, id);
+ }
+
+ TALLOC_FREE(frame);
+ } else {
+ DEBUG(4,("NetFileGetInfo2 res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetFileGetInfo2 failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+* Call a NetFileEnum2 - list open files on an SMB server
+*
+* PURPOSE: Remotes a NetFileEnum API call to the current server or target
+* server listing the files open via the network (and their
+* corresponding open instance ids)
+*
+* Dependencies: none
+*
+* Parameters:
+* cli - pointer to cli_state structure
+* user - if present, return only files opened by this remote user
+* base_path - if present, return only files opened below this
+* base path
+* fn - display function to invoke for each entry in the result
+*
+*
+* Returns:
+* True - success
+* False - failure
+*
+****************************************************************************/
+
+int cli_NetFileEnum(struct cli_state *cli, const char * user,
+ const char * base_path,
+ void (*fn)(const char *, const char *, uint16, uint16,
+ uint32))
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WFileEnum2_REQ) /* req string */
+ +sizeof(RAP_FILE_INFO_L3) /* return string */
+ +1024 /* base path (opt) */
+ +RAP_USERNAME_LEN /* user name (opt) */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer size */
+ +DWORDSIZE /* resume key ? */
+ +DWORDSIZE]; /* resume key ? */
+ int count = -1;
+ int res = -1;
+
+ /* now send a SMBtrans command with api RNetShareEnum */
+ p = make_header(param, RAP_WFileEnum2,
+ RAP_WFileEnum2_REQ, RAP_FILE_INFO_L3);
+
+ PUTSTRING(p, base_path, 1024);
+ PUTSTRING(p, user, RAP_USERNAME_LEN);
+ PUTWORD(p, 3); /* info level */
+ PUTWORD(p, 0xFF00); /* buffer size */
+ PUTDWORD(p, 0); /* zero out the resume key */
+ PUTDWORD(p, 0); /* or is this one the resume key? */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 0xFF00, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam, endp);
+
+ if (res == 0 || res == ERRmoredata) {
+ TALLOC_CTX *frame = talloc_stackframe();
+ int converter = 0, i;
+
+ p = rparam + WORDSIZE; /* skip result */
+ GETWORD(p, converter, endp);
+ GETWORD(p, count, endp);
+
+ p = rdata;
+ endp = rdata + rdrcnt;
+ for (i=0; i<count && p < endp; i++) {
+ int id = 0, perms = 0, locks = 0;
+ char *fpath, *fuser;
+
+ GETDWORD(p, id, endp);
+ GETWORD(p, perms, endp);
+ GETWORD(p, locks, endp);
+ p += rap_getstringp(frame,
+ p,
+ &fpath,
+ rdata,
+ converter,
+ endp);
+ p += rap_getstringp(frame,
+ p,
+ &fuser,
+ rdata,
+ converter,
+ endp);
+
+ if (fpath && fuser) {
+ fn(fpath, fuser, perms, locks, id);
+ }
+ } /* BB fix ERRmoredata case to send resume request */
+ TALLOC_FREE(frame);
+ } else {
+ DEBUG(4,("NetFileEnum2 res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetFileEnum2 failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return count;
+}
+
+/****************************************************************************
+ Call a NetShareAdd - share/export directory on remote server.
+****************************************************************************/
+
+int cli_NetShareAdd(struct cli_state *cli, RAP_SHARE_INFO_2 * sinfo )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ int res = -1;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WShareAdd_REQ) /* req string */
+ +sizeof(RAP_SHARE_INFO_L2) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* reserved word */
+ char data[1024];
+ /* offset to free format string section following fixed length data. */
+ /* will be updated by PUTSTRINGP macro and will end up with total len */
+ int soffset = RAP_SHARENAME_LEN + 1 /* share name + pad */
+ + WORDSIZE /* share type */
+ + DWORDSIZE /* comment pointer */
+ + WORDSIZE /* permissions */
+ + WORDSIZE /* max users */
+ + WORDSIZE /* active users */
+ + DWORDSIZE /* share path */
+ + RAP_SPASSWD_LEN + 1; /* share password + pad */
+
+ memset(param,'\0',sizeof(param));
+ /* now send a SMBtrans command with api RNetShareAdd */
+ p = make_header(param, RAP_WshareAdd,
+ RAP_WShareAdd_REQ, RAP_SHARE_INFO_L2);
+ PUTWORD(p, 2); /* info level */
+ PUTWORD(p, 0); /* reserved word 0 */
+
+ p = data;
+ PUTSTRINGF(p, sinfo->share_name, RAP_SHARENAME_LEN);
+ PUTBYTE(p, 0); /* pad byte 0 */
+
+ PUTWORD(p, sinfo->share_type);
+ PUTSTRINGP(p, sinfo->comment, data, soffset);
+ PUTWORD(p, sinfo->perms);
+ PUTWORD(p, sinfo->maximum_users);
+ PUTWORD(p, sinfo->active_users);
+ PUTSTRINGP(p, sinfo->path, data, soffset);
+ PUTSTRINGF(p, sinfo->password, RAP_SPASSWD_LEN);
+ SCVAL(p,-1,0x0A); /* required 0x0A at end of password */
+
+ if (cli_api(cli,
+ param, sizeof(param), 1024, /* Param, length, maxlen */
+ data, soffset, sizeof(data), /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam, endp);
+
+ if (res == 0) {
+ /* nothing to do */
+ } else {
+ DEBUG(4,("NetShareAdd res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetShareAdd failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ Call a NetShareDelete - unshare exported directory on remote server.
+****************************************************************************/
+
+int cli_NetShareDelete(struct cli_state *cli, const char * share_name )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ int res = -1;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WShareDel_REQ) /* req string */
+ +1 /* no ret string */
+ +RAP_SHARENAME_LEN /* share to del */
+ +WORDSIZE]; /* reserved word */
+
+ /* now send a SMBtrans command with api RNetShareDelete */
+ p = make_header(param, RAP_WshareDel, RAP_WShareDel_REQ, NULL);
+ PUTSTRING(p,share_name,RAP_SHARENAME_LEN);
+ PUTWORD(p,0); /* reserved word MBZ on input */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam, endp);
+
+ if (res == 0) {
+ /* nothing to do */
+ } else {
+ DEBUG(4,("NetShareDelete res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetShareDelete failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/*************************************************************************
+*
+* Function Name: cli_get_pdc_name
+*
+* PURPOSE: Remotes a NetServerEnum API call to the current server
+* requesting the name of a server matching the server
+* type of SV_TYPE_DOMAIN_CTRL (PDC).
+*
+* Dependencies: none
+*
+* Parameters:
+* cli - pointer to cli_state structure
+* workgroup - pointer to string containing name of domain
+* pdc_name - pointer to string that will contain PDC name
+* on successful return
+*
+* Returns:
+* True - success
+* False - failure
+*
+************************************************************************/
+
+bool cli_get_pdc_name(struct cli_state *cli, const char *workgroup, char **pdc_name)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rdrcnt,rprcnt;
+ char *p;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetServerEnum2_REQ) /* req string */
+ +sizeof(RAP_SERVER_INFO_L1) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer size */
+ +DWORDSIZE /* server type */
+ +RAP_MACHNAME_LEN]; /* workgroup */
+ int count = -1;
+ int res = -1;
+
+ *pdc_name = NULL;
+
+ /* send a SMBtrans command with api NetServerEnum */
+ p = make_header(param, RAP_NetServerEnum2,
+ RAP_NetServerEnum2_REQ, RAP_SERVER_INFO_L1);
+ PUTWORD(p, 1); /* info level */
+ PUTWORD(p, CLI_BUFFER_SIZE);
+ PUTDWORD(p, SV_TYPE_DOMAIN_CTRL);
+ PUTSTRING(p, workgroup, RAP_MACHNAME_LEN);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam, endp);
+ cli->rap_error = res;
+
+ /*
+ * We only really care to copy a name if the
+ * API succeeded and we got back a name.
+ */
+ if (cli->rap_error == 0) {
+ p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
+ GETWORD(p, count, endp);
+ p = rdata;
+ endp = rdata + rdrcnt;
+
+ if (count > 0) {
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *dcname;
+ p += rap_getstring(frame,
+ p,
+ &dcname,
+ endp);
+ if (dcname) {
+ *pdc_name = SMB_STRDUP(dcname);
+ }
+ TALLOC_FREE(frame);
+ }
+ } else {
+ DEBUG(4,("cli_get_pdc_name: machine %s failed the NetServerEnum call. "
+ "Error was : %s.\n", cli->desthost, cli_errstr(cli) ));
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return(count > 0);
+}
+
+/*************************************************************************
+*
+* Function Name: cli_get_server_domain
+*
+* PURPOSE: Remotes a NetWkstaGetInfo API call to the current server
+* requesting wksta_info_10 level information to determine
+* the domain the server belongs to. On success, this
+* routine sets the server_domain field in the cli_state structure
+* to the server's domain name.
+*
+* Dependencies: none
+*
+* Parameters:
+* cli - pointer to cli_state structure
+*
+* Returns:
+* True - success
+* False - failure
+*
+* Origins: samba 2.0.6 source/libsmb/clientgen.c cli_NetServerEnum()
+*
+************************************************************************/
+
+bool cli_get_server_domain(struct cli_state *cli)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rdrcnt,rprcnt;
+ char *p;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WWkstaGetInfo_REQ) /* req string */
+ +sizeof(RAP_WKSTA_INFO_L10) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ int res = -1;
+
+ /* send a SMBtrans command with api NetWkstaGetInfo */
+ p = make_header(param, RAP_WWkstaGetInfo,
+ RAP_WWkstaGetInfo_REQ, RAP_WKSTA_INFO_L10);
+ PUTWORD(p, 10); /* info level */
+ PUTWORD(p, CLI_BUFFER_SIZE);
+
+ if (cli_api(cli, param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt)) { /* return data, return size */
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam, endp);
+
+ if (res == 0) {
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *server_domain;
+ int converter = 0;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter, endp);
+
+ p = rdata + DWORDSIZE + DWORDSIZE; /* skip computer & user names */
+ endp = rdata + rdrcnt;
+ p += rap_getstringp(frame,
+ p,
+ &server_domain,
+ rdata,
+ converter,
+ endp);
+
+ if (server_domain) {
+ fstrcpy(cli->server_domain, server_domain);
+ }
+ TALLOC_FREE(frame);
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return(res == 0);
+}
+
+/*************************************************************************
+*
+* Function Name: cli_get_server_type
+*
+* PURPOSE: Remotes a NetServerGetInfo API call to the current server
+* requesting server_info_1 level information to retrieve
+* the server type.
+*
+* Dependencies: none
+*
+* Parameters:
+* cli - pointer to cli_state structure
+* pstype - pointer to uint32 to contain returned server type
+*
+* Returns:
+* True - success
+* False - failure
+*
+* Origins: samba 2.0.6 source/libsmb/clientgen.c cli_NetServerEnum()
+*
+************************************************************************/
+
+bool cli_get_server_type(struct cli_state *cli, uint32 *pstype)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rdrcnt,rprcnt;
+ char *p;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WserverGetInfo_REQ) /* req string */
+ +sizeof(RAP_SERVER_INFO_L1) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ int res = -1;
+
+ /* send a SMBtrans command with api NetServerGetInfo */
+ p = make_header(param, RAP_WserverGetInfo,
+ RAP_WserverGetInfo_REQ, RAP_SERVER_INFO_L1);
+ PUTWORD(p, 1); /* info level */
+ PUTWORD(p, CLI_BUFFER_SIZE);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam,endp);
+
+ if (res == 0 || res == ERRmoredata) {
+ p = rdata;
+ endp = rparam + rprcnt;
+ p += 18;
+ GETDWORD(p,*pstype,endp);
+ *pstype &= ~SV_TYPE_LOCAL_LIST_ONLY;
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return(res == 0 || res == ERRmoredata);
+}
+
+bool cli_get_server_name(TALLOC_CTX *mem_ctx, struct cli_state *cli,
+ char **servername)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rdrcnt,rprcnt;
+ char *p;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WserverGetInfo_REQ) /* req string */
+ +sizeof(RAP_SERVER_INFO_L1) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ bool res = false;
+ char *endp;
+ fstring tmp;
+
+ /* send a SMBtrans command with api NetServerGetInfo */
+ p = make_header(param, RAP_WserverGetInfo,
+ RAP_WserverGetInfo_REQ, RAP_SERVER_INFO_L1);
+ PUTWORD(p, 1); /* info level */
+ PUTWORD(p, CLI_BUFFER_SIZE);
+
+ if (!cli_api(cli,
+ param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+ goto failed;
+ }
+
+ endp = rparam + rprcnt;
+ if (GETRES(rparam, endp) != 0) {
+ goto failed;
+ }
+
+ if (rdrcnt < 16) {
+ DEBUG(10, ("invalid data count %d, expected >= 16\n", rdrcnt));
+ goto failed;
+ }
+
+ if (pull_ascii(tmp, rdata, sizeof(tmp)-1, 16, STR_TERMINATE) == -1) {
+ DEBUG(10, ("pull_ascii failed\n"));
+ goto failed;
+ }
+
+ if (!(*servername = talloc_strdup(mem_ctx, tmp))) {
+ DEBUG(1, ("talloc_strdup failed\n"));
+ goto failed;
+ }
+
+ res = true;
+
+ failed:
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+ return res;
+}
+
+/*************************************************************************
+*
+* Function Name: cli_ns_check_server_type
+*
+* PURPOSE: Remotes a NetServerEnum2 API call to the current server
+* requesting server_info_0 level information of machines
+* matching the given server type. If the returned server
+* list contains the machine name contained in cli->desthost
+* then we conclude the server type checks out. This routine
+* is useful to retrieve list of server's of a certain
+* type when all you have is a null session connection and
+* can't remote API calls such as NetWkstaGetInfo or
+* NetServerGetInfo.
+*
+* Dependencies: none
+*
+* Parameters:
+* cli - pointer to cli_state structure
+* workgroup - pointer to string containing domain
+* stype - server type
+*
+* Returns:
+* True - success
+* False - failure
+*
+************************************************************************/
+
+bool cli_ns_check_server_type(struct cli_state *cli, char *workgroup, uint32 stype)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rdrcnt,rprcnt;
+ char *p;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetServerEnum2_REQ) /* req string */
+ +sizeof(RAP_SERVER_INFO_L0) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer size */
+ +DWORDSIZE /* server type */
+ +RAP_MACHNAME_LEN]; /* workgroup */
+ bool found_server = false;
+ int res = -1;
+
+ /* send a SMBtrans command with api NetServerEnum */
+ p = make_header(param, RAP_NetServerEnum2,
+ RAP_NetServerEnum2_REQ, RAP_SERVER_INFO_L0);
+ PUTWORD(p, 0); /* info level 0 */
+ PUTWORD(p, CLI_BUFFER_SIZE);
+ PUTDWORD(p, stype);
+ PUTSTRING(p, workgroup, RAP_MACHNAME_LEN);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam,endp);
+ cli->rap_error = res;
+
+ if (res == 0 || res == ERRmoredata) {
+ int i, count = 0;
+
+ p = rparam + WORDSIZE + WORDSIZE;
+ GETWORD(p, count,endp);
+
+ p = rdata;
+ endp = rdata + rdrcnt;
+ for (i = 0;i < count && p < endp;i++, p += 16) {
+ char ret_server[RAP_MACHNAME_LEN];
+
+ p += rap_getstringf(p,
+ ret_server,
+ RAP_MACHNAME_LEN,
+ RAP_MACHNAME_LEN,
+ endp);
+ if (strequal(ret_server, cli->desthost)) {
+ found_server = true;
+ break;
+ }
+ }
+ } else {
+ DEBUG(4,("cli_ns_check_server_type: machine %s failed the NetServerEnum call. "
+ "Error was : %s.\n", cli->desthost, cli_errstr(cli) ));
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return found_server;
+}
+
+/****************************************************************************
+ Perform a NetWkstaUserLogoff.
+****************************************************************************/
+
+bool cli_NetWkstaUserLogoff(struct cli_state *cli, const char *user, const char *workstation)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ unsigned int rdrcnt,rprcnt;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetWkstaUserLogoff_REQ) /* req string */
+ +sizeof(RAP_USER_LOGOFF_INFO_L1) /* return string */
+ +RAP_USERNAME_LEN+1 /* user name+pad */
+ +RAP_MACHNAME_LEN /* wksta name */
+ +WORDSIZE /* buffer size */
+ +WORDSIZE]; /* buffer size? */
+ char upperbuf[MAX(RAP_USERNAME_LEN,RAP_MACHNAME_LEN)];
+ int res = -1;
+ char *tmp = NULL;
+
+ memset(param, 0, sizeof(param));
+
+ /* send a SMBtrans command with api NetWkstaUserLogoff */
+ p = make_header(param, RAP_WWkstaUserLogoff,
+ RAP_NetWkstaUserLogoff_REQ, RAP_USER_LOGOFF_INFO_L1);
+ PUTDWORD(p, 0); /* Null pointer */
+ PUTDWORD(p, 0); /* Null pointer */
+ strlcpy(upperbuf, user, sizeof(upperbuf));
+ strupper_m(upperbuf);
+ tmp = upperbuf;
+ PUTSTRINGF(p, tmp, RAP_USERNAME_LEN);
+ p++; /* strange format, but ok */
+ strlcpy(upperbuf, workstation, sizeof(upperbuf));
+ strupper_m(upperbuf);
+ tmp = upperbuf;
+ PUTSTRINGF(p, tmp, RAP_MACHNAME_LEN);
+ PUTWORD(p, CLI_BUFFER_SIZE);
+ PUTWORD(p, CLI_BUFFER_SIZE);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),1024, /* param, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam,endp);
+ cli->rap_error = res;
+
+ if (cli->rap_error != 0) {
+ DEBUG(4,("NetwkstaUserLogoff gave error %d\n", cli->rap_error));
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+ return (cli->rap_error == 0);
+}
+
+int cli_NetPrintQEnum(struct cli_state *cli,
+ void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
+ void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,uint,uint,const char*))
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetPrintQEnum_REQ) /* req string */
+ +sizeof(RAP_PRINTQ_INFO_L2) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer size */
+ +sizeof(RAP_SMB_PRINT_JOB_L1)]; /* more ret data */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rprcnt, rdrcnt;
+ int res = -1;
+
+ memset(param, '\0',sizeof(param));
+ p = make_header(param, RAP_WPrintQEnum,
+ RAP_NetPrintQEnum_REQ, RAP_PRINTQ_INFO_L2);
+ PUTWORD(p,2); /* Info level 2 */
+ PUTWORD(p,0xFFE0); /* Return buffer size */
+ PUTSTRING(p, RAP_SMB_PRINT_JOB_L1, 0);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),1024,
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam, endp);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetPrintQEnum gave error %d\n", res));
+ }
+ }
+
+ if (!rdata) {
+ DEBUG(4,("NetPrintQEnum no data returned\n"));
+ goto out;
+ }
+
+ if (res == 0 || res == ERRmoredata) {
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *endp = rparam + rprcnt;
+ int i, converter = 0, count = 0;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter, endp);
+ GETWORD(p, count, endp);
+
+ p = rdata;
+ endp = rdata + rdrcnt;
+ for (i=0;i<count && p < endp;i++) {
+ char qname[RAP_SHARENAME_LEN];
+ char *sep_file, *print_proc, *dest, *parms, *comment;
+ uint16_t jobcount = 0, priority = 0;
+ uint16_t start_time = 0, until_time = 0, status = 0;
+
+ p += rap_getstringf(p,
+ qname,
+ RAP_SHARENAME_LEN,
+ RAP_SHARENAME_LEN,
+ endp);
+ p++; /* pad */
+ GETWORD(p, priority, endp);
+ GETWORD(p, start_time, endp);
+ GETWORD(p, until_time, endp);
+ p += rap_getstringp(frame,
+ p,
+ &sep_file,
+ rdata,
+ converter,
+ endp);
+ p += rap_getstringp(frame,
+ p,
+ &print_proc,
+ rdata,
+ converter,
+ endp);
+ p += rap_getstringp(frame,
+ p,
+ &dest,
+ rdata,
+ converter,
+ endp);
+ p += rap_getstringp(frame,
+ p,
+ &parms,
+ rdata,
+ converter,
+ endp);
+ p += rap_getstringp(frame,
+ p,
+ &comment,
+ rdata,
+ converter,
+ endp);
+ GETWORD(p, status, endp);
+ GETWORD(p, jobcount, endp);
+
+ if (sep_file && print_proc && dest && parms &&
+ comment) {
+ qfn(qname, priority, start_time, until_time, sep_file, print_proc,
+ dest, parms, comment, status, jobcount);
+ }
+
+ if (jobcount) {
+ int j;
+ for (j=0;j<jobcount;j++) {
+ uint16 jid = 0, pos = 0, fsstatus = 0;
+ char ownername[RAP_USERNAME_LEN];
+ char notifyname[RAP_MACHNAME_LEN];
+ char datatype[RAP_DATATYPE_LEN];
+ char *jparms, *jstatus, *jcomment;
+ unsigned int submitted = 0, jsize = 0;
+
+ GETWORD(p, jid, endp);
+ p += rap_getstringf(p,
+ ownername,
+ RAP_USERNAME_LEN,
+ RAP_USERNAME_LEN,
+ endp);
+ p++; /* pad byte */
+ p += rap_getstringf(p,
+ notifyname,
+ RAP_MACHNAME_LEN,
+ RAP_MACHNAME_LEN,
+ endp);
+ p += rap_getstringf(p,
+ datatype,
+ RAP_DATATYPE_LEN,
+ RAP_DATATYPE_LEN,
+ endp);
+ p += rap_getstringp(frame,
+ p,
+ &jparms,
+ rdata,
+ converter,
+ endp);
+ GETWORD(p, pos, endp);
+ GETWORD(p, fsstatus, endp);
+ p += rap_getstringp(frame,
+ p,
+ &jstatus,
+ rdata,
+ converter,
+ endp);
+ GETDWORD(p, submitted, endp);
+ GETDWORD(p, jsize, endp);
+ p += rap_getstringp(frame,
+ p,
+ &jcomment,
+ rdata,
+ converter,
+ endp);
+
+ if (jparms && jstatus && jcomment) {
+ jfn(jid, ownername, notifyname, datatype, jparms, pos, fsstatus,
+ jstatus, submitted, jsize, jcomment);
+ }
+ }
+ }
+ }
+ TALLOC_FREE(frame);
+ } else {
+ DEBUG(4,("NetPrintQEnum res=%d\n", res));
+ }
+
+ out:
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+int cli_NetPrintQGetInfo(struct cli_state *cli, const char *printer,
+ void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
+ void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,uint,uint,const char*))
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetPrintQGetInfo_REQ) /* req string */
+ +sizeof(RAP_PRINTQ_INFO_L2) /* return string */
+ +RAP_SHARENAME_LEN /* printer name */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer size */
+ +sizeof(RAP_SMB_PRINT_JOB_L1)]; /* more ret data */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rprcnt, rdrcnt;
+ int res = -1;
+
+ memset(param, '\0',sizeof(param));
+ p = make_header(param, RAP_WPrintQGetInfo,
+ RAP_NetPrintQGetInfo_REQ, RAP_PRINTQ_INFO_L2);
+ PUTSTRING(p, printer, RAP_SHARENAME_LEN-1);
+ PUTWORD(p, 2); /* Info level 2 */
+ PUTWORD(p,0xFFE0); /* Return buffer size */
+ PUTSTRING(p, RAP_SMB_PRINT_JOB_L1, 0);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),1024,
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam, endp);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetPrintQGetInfo gave error %d\n", res));
+ }
+ }
+
+ if (!rdata) {
+ DEBUG(4,("NetPrintQGetInfo no data returned\n"));
+ goto out;
+ }
+
+ if (res == 0 || res == ERRmoredata) {
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *endp = rparam + rprcnt;
+ int rsize = 0, converter = 0;
+ char qname[RAP_SHARENAME_LEN];
+ char *sep_file, *print_proc, *dest, *parms, *comment;
+ uint16_t jobcount = 0, priority = 0;
+ uint16_t start_time = 0, until_time = 0, status = 0;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter, endp);
+ GETWORD(p, rsize, endp);
+
+ p = rdata;
+ endp = rdata + rdrcnt;
+ p += rap_getstringf(p,
+ qname,
+ RAP_SHARENAME_LEN,
+ RAP_SHARENAME_LEN,
+ endp);
+ p++; /* pad */
+ GETWORD(p, priority, endp);
+ GETWORD(p, start_time, endp);
+ GETWORD(p, until_time, endp);
+ p += rap_getstringp(frame,
+ p,
+ &sep_file,
+ rdata,
+ converter,
+ endp);
+ p += rap_getstringp(frame,
+ p,
+ &print_proc,
+ rdata,
+ converter,
+ endp);
+ p += rap_getstringp(frame,
+ p,
+ &dest,
+ rdata,
+ converter,
+ endp);
+ p += rap_getstringp(frame,
+ p,
+ &parms,
+ rdata,
+ converter,
+ endp);
+ p += rap_getstringp(frame,
+ p,
+ &comment,
+ rdata,
+ converter,
+ endp);
+ GETWORD(p, status, endp);
+ GETWORD(p, jobcount, endp);
+
+ if (sep_file && print_proc && dest &&
+ parms && comment) {
+ qfn(qname, priority, start_time, until_time, sep_file, print_proc,
+ dest, parms, comment, status, jobcount);
+ }
+ if (jobcount) {
+ int j;
+ for (j=0;(j<jobcount)&&(PTR_DIFF(p,rdata)< rsize)&&
+ p<endp;j++) {
+ uint16_t jid = 0, pos = 0, fsstatus = 0;
+ char ownername[RAP_USERNAME_LEN];
+ char notifyname[RAP_MACHNAME_LEN];
+ char datatype[RAP_DATATYPE_LEN];
+ char *jparms, *jstatus, *jcomment;
+ unsigned int submitted = 0, jsize = 0;
+
+ GETWORD(p, jid, endp);
+ p += rap_getstringf(p,
+ ownername,
+ RAP_USERNAME_LEN,
+ RAP_USERNAME_LEN,
+ endp);
+ p++; /* pad byte */
+ p += rap_getstringf(p,
+ notifyname,
+ RAP_MACHNAME_LEN,
+ RAP_MACHNAME_LEN,
+ endp);
+ p += rap_getstringf(p,
+ datatype,
+ RAP_DATATYPE_LEN,
+ RAP_DATATYPE_LEN,
+ endp);
+ p += rap_getstringp(frame,
+ p,
+ &jparms,
+ rdata,
+ converter,
+ endp);
+ GETWORD(p, pos,endp);
+ GETWORD(p, fsstatus,endp);
+ p += rap_getstringp(frame,
+ p,
+ &jstatus,
+ rdata,
+ converter,
+ endp);
+ GETDWORD(p, submitted,endp);
+ GETDWORD(p, jsize,endp);
+ p += rap_getstringp(frame,
+ p,
+ &jcomment,
+ rdata,
+ converter,
+ endp);
+
+ if (jparms && jstatus && jcomment) {
+ jfn(jid, ownername, notifyname, datatype, jparms, pos, fsstatus,
+ jstatus, submitted, jsize, jcomment);
+ }
+ }
+ }
+ TALLOC_FREE(frame);
+ } else {
+ DEBUG(4,("NetPrintQGetInfo res=%d\n", res));
+ }
+
+ out:
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ Call a NetServiceEnum - list running services on a different host.
+****************************************************************************/
+
+int cli_RNetServiceEnum(struct cli_state *cli, void (*fn)(const char *, const char *, void *), void *state)
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetServiceEnum_REQ) /* parm string */
+ +sizeof(RAP_SERVICE_INFO_L2) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rprcnt, rdrcnt;
+ int res = -1;
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WServiceEnum,
+ RAP_NetServiceEnum_REQ, RAP_SERVICE_INFO_L2);
+ PUTWORD(p,2); /* Info level 2 */
+ PUTWORD(p,0xFFE0); /* Return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),8,
+ NULL, 0, 0xFFE0 /* data area size */,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam, endp);
+ cli->rap_error = res;
+ if(cli->rap_error == 234) {
+ DEBUG(1,("Not all service names were returned (such as those longer than 15 characters)\n"));
+ } else if (cli->rap_error != 0) {
+ DEBUG(1,("NetServiceEnum gave error %d\n", cli->rap_error));
+ }
+ }
+
+ if (!rdata) {
+ DEBUG(4,("NetServiceEnum no data returned\n"));
+ goto out;
+ }
+
+ if (res == 0 || res == ERRmoredata) {
+ char *endp = rparam + rprcnt;
+ int i, count = 0;
+
+ p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
+ GETWORD(p, count,endp);
+
+ endp = rdata + rdrcnt;
+ for (i=0,p=rdata;i<count && p < endp;i++) {
+ char comment[RAP_SRVCCMNT_LEN];
+ char servicename[RAP_SRVCNAME_LEN];
+
+ p += rap_getstringf(p,
+ servicename,
+ RAP_SRVCNAME_LEN,
+ RAP_SRVCNAME_LEN,
+ endp);
+ p+=8; /* pass status words */
+ p += rap_getstringf(p,
+ comment,
+ RAP_SRVCCMNT_LEN,
+ RAP_SRVCCMNT_LEN,
+ endp);
+
+ if (servicename[0]) {
+ fn(servicename, comment, cli); /* BB add status too */
+ }
+ }
+ } else {
+ DEBUG(4,("NetServiceEnum res=%d\n", res));
+ }
+
+ out:
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ Call a NetSessionEnum - list workstations with sessions to an SMB server.
+****************************************************************************/
+
+int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16, uint16, uint16, uint, uint, uint, char *))
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetSessionEnum_REQ) /* parm string */
+ +sizeof(RAP_SESSION_INFO_L2) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rprcnt, rdrcnt;
+ int res = -1;
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WsessionEnum,
+ RAP_NetSessionEnum_REQ, RAP_SESSION_INFO_L2);
+ PUTWORD(p,2); /* Info level 2 */
+ PUTWORD(p,0xFF); /* Return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),8,
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam, endp);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetSessionEnum gave error %d\n", res));
+ }
+ }
+
+ if (!rdata) {
+ DEBUG(4,("NetSesssionEnum no data returned\n"));
+ goto out;
+ }
+
+ if (res == 0 || res == ERRmoredata) {
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *endp = rparam + rprcnt;
+ int i, converter = 0, count = 0;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter, endp);
+ GETWORD(p, count, endp);
+
+ endp = rdata + rdrcnt;
+ for (i=0,p=rdata;i<count && p < endp;i++) {
+ char *wsname, *username, *clitype_name;
+ uint16_t num_conns = 0, num_opens = 0, num_users = 0;
+ unsigned int sess_time = 0, idle_time = 0, user_flags = 0;
+
+ p += rap_getstringp(frame,
+ p,
+ &wsname,
+ rdata,
+ converter,
+ endp);
+ p += rap_getstringp(frame,
+ p,
+ &username,
+ rdata,
+ converter,
+ endp);
+ GETWORD(p, num_conns, endp);
+ GETWORD(p, num_opens, endp);
+ GETWORD(p, num_users, endp);
+ GETDWORD(p, sess_time, endp);
+ GETDWORD(p, idle_time, endp);
+ GETDWORD(p, user_flags, endp);
+ p += rap_getstringp(frame,
+ p,
+ &clitype_name,
+ rdata,
+ converter,
+ endp);
+
+ if (wsname && username && clitype_name) {
+ fn(wsname, username, num_conns, num_opens, num_users, sess_time,
+ idle_time, user_flags, clitype_name);
+ }
+ }
+ TALLOC_FREE(frame);
+ } else {
+ DEBUG(4,("NetSessionEnum res=%d\n", res));
+ }
+
+ out:
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ Call a NetSessionGetInfo - get information about other session to an SMB server.
+****************************************************************************/
+
+int cli_NetSessionGetInfo(struct cli_state *cli, const char *workstation,
+ void (*fn)(const char *, const char *, uint16, uint16, uint16, uint, uint, uint, const char *))
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetSessionGetInfo_REQ) /* req string */
+ +sizeof(RAP_SESSION_INFO_L2) /* return string */
+ +RAP_MACHNAME_LEN /* wksta name */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rprcnt, rdrcnt;
+ char *endp;
+ int res = -1;
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WsessionGetInfo,
+ RAP_NetSessionGetInfo_REQ, RAP_SESSION_INFO_L2);
+ PUTSTRING(p, workstation, RAP_MACHNAME_LEN-1);
+ PUTWORD(p,2); /* Info level 2 */
+ PUTWORD(p,0xFF); /* Return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),PTR_DIFF(p,param),
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ endp = rparam + rprcnt;
+ res = GETRES(rparam, endp);
+ cli->rap_error = res;
+ if (cli->rap_error != 0) {
+ DEBUG(1,("NetSessionGetInfo gave error %d\n", cli->rap_error));
+ }
+ }
+
+ if (!rdata) {
+ DEBUG(4,("NetSessionGetInfo no data returned\n"));
+ goto out;
+ }
+
+ endp = rparam + rprcnt;
+ res = GETRES(rparam, endp);
+
+ if (res == 0 || res == ERRmoredata) {
+ TALLOC_CTX *frame = talloc_stackframe();
+ int converter = 0;
+ char *wsname, *username, *clitype_name;
+ uint16_t num_conns = 0, num_opens = 0, num_users = 0;
+ unsigned int sess_time = 0, idle_time = 0, user_flags = 0;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter,endp);
+ p += WORDSIZE; /* skip rsize */
+
+ p = rdata;
+ endp = rdata + rdrcnt;
+ p += rap_getstringp(frame,
+ p,
+ &wsname,
+ rdata,
+ converter,
+ endp);
+ p += rap_getstringp(frame,
+ p,
+ &username,
+ rdata,
+ converter,
+ endp);
+ GETWORD(p, num_conns, endp);
+ GETWORD(p, num_opens, endp);
+ GETWORD(p, num_users, endp);
+ GETDWORD(p, sess_time, endp);
+ GETDWORD(p, idle_time, endp);
+ GETDWORD(p, user_flags, endp);
+ p += rap_getstringp(frame,
+ p,
+ &clitype_name,
+ rdata,
+ converter,
+ endp);
+
+ if (wsname && username && clitype_name) {
+ fn(wsname, username, num_conns, num_opens, num_users, sess_time,
+ idle_time, user_flags, clitype_name);
+ }
+ TALLOC_FREE(frame);
+ } else {
+ DEBUG(4,("NetSessionGetInfo res=%d\n", res));
+ }
+
+ out:
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ Call a NetSessionDel - close a session to an SMB server.
+****************************************************************************/
+
+int cli_NetSessionDel(struct cli_state *cli, const char *workstation)
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetSessionDel_REQ) /* req string */
+ +1 /* no return string */
+ +RAP_MACHNAME_LEN /* workstation name */
+ +WORDSIZE]; /* reserved (0) */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rprcnt, rdrcnt;
+ int res = -1;
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WsessionDel, RAP_NetSessionDel_REQ, NULL);
+ PUTSTRING(p, workstation, RAP_MACHNAME_LEN-1);
+ PUTWORD(p,0); /* reserved word of 0 */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam, endp);
+ cli->rap_error = res;
+
+ if (res == 0) {
+ /* nothing to do */
+ } else {
+ DEBUG(4,("NetFileClose2 res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetFileClose2 failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+int cli_NetConnectionEnum(struct cli_state *cli, const char *qualifier,
+ void (*fn)(uint16_t conid, uint16_t contype,
+ uint16_t numopens, uint16_t numusers,
+ uint32_t contime, const char *username,
+ const char *netname))
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetConnectionEnum_REQ) /* req string */
+ +sizeof(RAP_CONNECTION_INFO_L1) /* return string */
+ +RAP_MACHNAME_LEN /* wksta name */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rprcnt, rdrcnt;
+ int res = -1;
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WconnectionEnum,
+ RAP_NetConnectionEnum_REQ, RAP_CONNECTION_INFO_L1);
+ PUTSTRING(p, qualifier, RAP_MACHNAME_LEN-1);/* Workstation name */
+ PUTWORD(p,1); /* Info level 1 */
+ PUTWORD(p,0xFFE0); /* Return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),PTR_DIFF(p,param),
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ char *endp = rparam + rprcnt;
+ res = GETRES(rparam, endp);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetConnectionEnum gave error %d\n", res));
+ }
+ }
+
+ if (!rdata) {
+ DEBUG(4,("NetConnectionEnum no data returned\n"));
+ goto out;
+ }
+
+ if (res == 0 || res == ERRmoredata) {
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *endp = rparam + rprcnt;
+ int i, converter = 0, count = 0;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter, endp);
+ GETWORD(p, count, endp);
+
+ endp = rdata + rdrcnt;
+ for (i=0,p=rdata;i<count && p < endp;i++) {
+ char *netname, *username;
+ uint16_t conn_id = 0, conn_type = 0, num_opens = 0, num_users = 0;
+ unsigned int conn_time = 0;
+
+ GETWORD(p,conn_id, endp);
+ GETWORD(p,conn_type, endp);
+ GETWORD(p,num_opens, endp);
+ GETWORD(p,num_users, endp);
+ GETDWORD(p,conn_time, endp);
+ p += rap_getstringp(frame,
+ p,
+ &username,
+ rdata,
+ converter,
+ endp);
+ p += rap_getstringp(frame,
+ p,
+ &netname,
+ rdata,
+ converter,
+ endp);
+
+ if (username && netname) {
+ fn(conn_id, conn_type, num_opens, num_users, conn_time,
+ username, netname);
+ }
+ }
+ TALLOC_FREE(frame);
+ } else {
+ DEBUG(4,("NetConnectionEnum res=%d\n", res));
+ }
+
+ out:
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return res;
+}
diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c
new file mode 100644
index 0000000000..ec63281630
--- /dev/null
+++ b/source3/libsmb/clireadwrite.c
@@ -0,0 +1,717 @@
+/*
+ Unix SMB/CIFS implementation.
+ client file read/write routines
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Calculate the recommended read buffer size
+****************************************************************************/
+static size_t cli_read_max_bufsize(struct cli_state *cli)
+{
+ if (!client_is_signing_on(cli) && !cli_encryption_on(cli)
+ && (cli->posix_capabilities & CIFS_UNIX_LARGE_READ_CAP)) {
+ return CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE;
+ }
+ if (cli->capabilities & CAP_LARGE_READX) {
+ return cli->is_samba
+ ? CLI_SAMBA_MAX_LARGE_READX_SIZE
+ : CLI_WINDOWS_MAX_LARGE_READX_SIZE;
+ }
+ return (cli->max_xmit - (smb_size+32)) & ~1023;
+}
+
+/*
+ * Send a read&x request
+ */
+
+struct async_req *cli_read_andx_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli, int fnum,
+ off_t offset, size_t size)
+{
+ struct async_req *result;
+ struct cli_request *req;
+ bool bigoffset = False;
+
+ uint16_t vwv[12];
+ uint8_t wct = 10;
+
+ if (size > cli_read_max_bufsize(cli)) {
+ DEBUG(0, ("cli_read_andx_send got size=%d, can only handle "
+ "size=%d\n", (int)size,
+ (int)cli_read_max_bufsize(cli)));
+ return NULL;
+ }
+
+ SCVAL(vwv + 0, 0, 0xFF);
+ SCVAL(vwv + 0, 1, 0);
+ SSVAL(vwv + 1, 0, 0);
+ SSVAL(vwv + 2, 0, fnum);
+ SIVAL(vwv + 3, 0, offset);
+ SSVAL(vwv + 5, 0, size);
+ SSVAL(vwv + 6, 0, size);
+ SSVAL(vwv + 7, 0, (size >> 16));
+ SSVAL(vwv + 8, 0, 0);
+ SSVAL(vwv + 9, 0, 0);
+
+ if ((SMB_BIG_UINT)offset >> 32) {
+ bigoffset = True;
+ SIVAL(vwv + 10, 0,
+ (((SMB_BIG_UINT)offset)>>32) & 0xffffffff);
+ wct += 2;
+ }
+
+ result = cli_request_send(mem_ctx, ev, cli, SMBreadX, 0, wct, vwv,
+ 0, NULL);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ req = talloc_get_type_abort(result->private_data, struct cli_request);
+
+ req->data.read.ofs = offset;
+ req->data.read.size = size;
+ req->data.read.received = 0;
+ req->data.read.rcvbuf = NULL;
+
+ return result;
+}
+
+/*
+ * Pull the data out of a finished async read_and_x request. rcvbuf is
+ * talloced from the request, so better make sure that you copy it away before
+ * you talloc_free(req). "rcvbuf" is NOT a talloc_ctx of its own, so do not
+ * talloc_move it!
+ */
+
+NTSTATUS cli_read_andx_recv(struct async_req *req, ssize_t *received,
+ uint8_t **rcvbuf)
+{
+ struct cli_request *cli_req = talloc_get_type_abort(
+ req->private_data, struct cli_request);
+ uint8_t wct;
+ uint16_t *vwv;
+ uint16_t num_bytes;
+ uint8_t *bytes;
+ NTSTATUS status;
+ size_t size;
+
+ SMB_ASSERT(req->state >= ASYNC_REQ_DONE);
+ if (req->state == ASYNC_REQ_ERROR) {
+ return req->status;
+ }
+
+ status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ if (wct < 12) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /* size is the number of bytes the server returned.
+ * Might be zero. */
+ size = SVAL(vwv + 5, 0);
+ size |= (((unsigned int)SVAL(vwv + 7, 0)) << 16);
+
+ if (size > cli_req->data.read.size) {
+ DEBUG(5,("server returned more than we wanted!\n"));
+ return NT_STATUS_UNEXPECTED_IO_ERROR;
+ }
+
+ *rcvbuf = (uint8_t *)(smb_base(cli_req->inbuf) + SVAL(vwv + 6, 0));
+ *received = size;
+ return NT_STATUS_OK;
+}
+
+/*
+ * Parallel read support.
+ *
+ * cli_pull sends as many read&x requests as the server would allow via
+ * max_mux at a time. When replies flow back in, the data is written into
+ * the callback function "sink" in the right order.
+ */
+
+struct cli_pull_state {
+ struct async_req *req;
+
+ struct event_context *ev;
+ struct cli_state *cli;
+ uint16_t fnum;
+ off_t start_offset;
+ SMB_OFF_T size;
+
+ NTSTATUS (*sink)(char *buf, size_t n, void *priv);
+ void *priv;
+
+ size_t chunk_size;
+
+ /*
+ * Outstanding requests
+ */
+ int num_reqs;
+ struct async_req **reqs;
+
+ /*
+ * For how many bytes did we send requests already?
+ */
+ SMB_OFF_T requested;
+
+ /*
+ * Next request index to push into "sink". This walks around the "req"
+ * array, taking care that the requests are pushed to "sink" in the
+ * right order. If necessary (i.e. replies don't come in in the right
+ * order), replies are held back in "reqs".
+ */
+ int top_req;
+
+ /*
+ * How many bytes did we push into "sink"?
+ */
+
+ SMB_OFF_T pushed;
+};
+
+static char *cli_pull_print(TALLOC_CTX *mem_ctx, struct async_req *req)
+{
+ struct cli_pull_state *state = talloc_get_type_abort(
+ req->private_data, struct cli_pull_state);
+ char *result;
+
+ result = async_req_print(mem_ctx, req);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ return talloc_asprintf_append_buffer(
+ result, "num_reqs=%d, top_req=%d",
+ state->num_reqs, state->top_req);
+}
+
+static void cli_pull_read_done(struct async_req *read_req);
+
+/*
+ * Prepare an async pull request
+ */
+
+struct async_req *cli_pull_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ uint16_t fnum, off_t start_offset,
+ SMB_OFF_T size, size_t window_size,
+ NTSTATUS (*sink)(char *buf, size_t n,
+ void *priv),
+ void *priv)
+{
+ struct async_req *result;
+ struct cli_pull_state *state;
+ int i;
+
+ result = async_req_new(mem_ctx, ev);
+ if (result == NULL) {
+ goto failed;
+ }
+ state = talloc(result, struct cli_pull_state);
+ if (state == NULL) {
+ goto failed;
+ }
+ result->private_data = state;
+ result->print = cli_pull_print;
+ state->req = result;
+
+ state->cli = cli;
+ state->ev = ev;
+ state->fnum = fnum;
+ state->start_offset = start_offset;
+ state->size = size;
+ state->sink = sink;
+ state->priv = priv;
+
+ state->pushed = 0;
+ state->top_req = 0;
+
+ if (size == 0) {
+ if (!async_post_status(result, NT_STATUS_OK)) {
+ goto failed;
+ }
+ return result;
+ }
+
+ state->chunk_size = cli_read_max_bufsize(cli);
+
+ state->num_reqs = MAX(window_size/state->chunk_size, 1);
+ state->num_reqs = MIN(state->num_reqs, cli->max_mux);
+
+ state->reqs = TALLOC_ZERO_ARRAY(state, struct async_req *,
+ state->num_reqs);
+ if (state->reqs == NULL) {
+ goto failed;
+ }
+
+ state->requested = 0;
+
+ for (i=0; i<state->num_reqs; i++) {
+ SMB_OFF_T size_left;
+ size_t request_thistime;
+
+ if (state->requested >= size) {
+ state->num_reqs = i;
+ break;
+ }
+
+ size_left = size - state->requested;
+ request_thistime = MIN(size_left, state->chunk_size);
+
+ state->reqs[i] = cli_read_andx_send(
+ state->reqs, ev, cli, fnum,
+ state->start_offset + state->requested,
+ request_thistime);
+
+ if (state->reqs[i] == NULL) {
+ goto failed;
+ }
+
+ state->reqs[i]->async.fn = cli_pull_read_done;
+ state->reqs[i]->async.priv = result;
+
+ state->requested += request_thistime;
+ }
+ return result;
+
+failed:
+ TALLOC_FREE(result);
+ return NULL;
+}
+
+/*
+ * Handle incoming read replies, push the data into sink and send out new
+ * requests if necessary.
+ */
+
+static void cli_pull_read_done(struct async_req *read_req)
+{
+ struct async_req *pull_req = talloc_get_type_abort(
+ read_req->async.priv, struct async_req);
+ struct cli_pull_state *state = talloc_get_type_abort(
+ pull_req->private_data, struct cli_pull_state);
+ struct cli_request *read_state = talloc_get_type_abort(
+ read_req->private_data, struct cli_request);
+ NTSTATUS status;
+
+ status = cli_read_andx_recv(read_req, &read_state->data.read.received,
+ &read_state->data.read.rcvbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ async_req_error(state->req, status);
+ return;
+ }
+
+ /*
+ * This loop is the one to take care of out-of-order replies. All
+ * pending requests are in state->reqs, state->reqs[top_req] is the
+ * one that is to be pushed next. If however a request later than
+ * top_req is replied to, then we can't push yet. If top_req is
+ * replied to at a later point then, we need to push all the finished
+ * requests.
+ */
+
+ while (state->reqs[state->top_req] != NULL) {
+ struct cli_request *top_read;
+
+ DEBUG(11, ("cli_pull_read_done: top_req = %d\n",
+ state->top_req));
+
+ if (state->reqs[state->top_req]->state < ASYNC_REQ_DONE) {
+ DEBUG(11, ("cli_pull_read_done: top request not yet "
+ "done\n"));
+ return;
+ }
+
+ top_read = talloc_get_type_abort(
+ state->reqs[state->top_req]->private_data,
+ struct cli_request);
+
+ DEBUG(10, ("cli_pull_read_done: Pushing %d bytes, %d already "
+ "pushed\n", (int)top_read->data.read.received,
+ (int)state->pushed));
+
+ status = state->sink((char *)top_read->data.read.rcvbuf,
+ top_read->data.read.received,
+ state->priv);
+ if (!NT_STATUS_IS_OK(status)) {
+ async_req_error(state->req, status);
+ return;
+ }
+ state->pushed += top_read->data.read.received;
+
+ TALLOC_FREE(state->reqs[state->top_req]);
+
+ if (state->requested < state->size) {
+ struct async_req *new_req;
+ SMB_OFF_T size_left;
+ size_t request_thistime;
+
+ size_left = state->size - state->requested;
+ request_thistime = MIN(size_left, state->chunk_size);
+
+ DEBUG(10, ("cli_pull_read_done: Requesting %d bytes "
+ "at %d, position %d\n",
+ (int)request_thistime,
+ (int)(state->start_offset
+ + state->requested),
+ state->top_req));
+
+ new_req = cli_read_andx_send(
+ state->reqs, state->ev, state->cli,
+ state->fnum,
+ state->start_offset + state->requested,
+ request_thistime);
+
+ if (async_req_nomem(new_req, state->req)) {
+ return;
+ }
+
+ new_req->async.fn = cli_pull_read_done;
+ new_req->async.priv = pull_req;
+
+ state->reqs[state->top_req] = new_req;
+ state->requested += request_thistime;
+ }
+
+ state->top_req = (state->top_req+1) % state->num_reqs;
+ }
+
+ async_req_done(pull_req);
+}
+
+NTSTATUS cli_pull_recv(struct async_req *req, SMB_OFF_T *received)
+{
+ struct cli_pull_state *state = talloc_get_type_abort(
+ req->private_data, struct cli_pull_state);
+
+ SMB_ASSERT(req->state >= ASYNC_REQ_DONE);
+ if (req->state == ASYNC_REQ_ERROR) {
+ return req->status;
+ }
+ *received = state->pushed;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum,
+ off_t start_offset, SMB_OFF_T size, size_t window_size,
+ NTSTATUS (*sink)(char *buf, size_t n, void *priv),
+ void *priv, SMB_OFF_T *received)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct async_req *req;
+ NTSTATUS result = NT_STATUS_NO_MEMORY;
+
+ if (cli->fd_event != NULL) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ goto nomem;
+ }
+
+ req = cli_pull_send(frame, ev, cli, fnum, start_offset, size,
+ window_size, sink, priv);
+ if (req == NULL) {
+ goto nomem;
+ }
+
+ while (req->state < ASYNC_REQ_DONE) {
+ event_loop_once(ev);
+ }
+
+ result = cli_pull_recv(req, received);
+ nomem:
+ TALLOC_FREE(frame);
+ return result;
+}
+
+static NTSTATUS cli_read_sink(char *buf, size_t n, void *priv)
+{
+ char **pbuf = (char **)priv;
+ memcpy(*pbuf, buf, n);
+ *pbuf += n;
+ return NT_STATUS_OK;
+}
+
+ssize_t cli_read(struct cli_state *cli, int fnum, char *buf,
+ off_t offset, size_t size)
+{
+ NTSTATUS status;
+ SMB_OFF_T ret;
+
+ status = cli_pull(cli, fnum, offset, size, size,
+ cli_read_sink, &buf, &ret);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ return -1;
+ }
+ return ret;
+}
+
+/****************************************************************************
+ Issue a single SMBwrite and don't wait for a reply.
+****************************************************************************/
+
+static bool cli_issue_write(struct cli_state *cli,
+ int fnum,
+ off_t offset,
+ uint16 mode,
+ const char *buf,
+ size_t size,
+ int i)
+{
+ char *p;
+ bool large_writex = false;
+ /* We can only do direct writes if not signing and not encrypting. */
+ bool direct_writes = !client_is_signing_on(cli) && !cli_encryption_on(cli);
+
+ if (!direct_writes && size + 1 > cli->bufsize) {
+ cli->outbuf = (char *)SMB_REALLOC(cli->outbuf, size + 1024);
+ if (!cli->outbuf) {
+ return False;
+ }
+ cli->inbuf = (char *)SMB_REALLOC(cli->inbuf, size + 1024);
+ if (cli->inbuf == NULL) {
+ SAFE_FREE(cli->outbuf);
+ return False;
+ }
+ cli->bufsize = size + 1024;
+ }
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ if (cli->capabilities & CAP_LARGE_FILES) {
+ large_writex = True;
+ }
+
+ if (large_writex) {
+ cli_set_message(cli->outbuf,14,0,True);
+ } else {
+ cli_set_message(cli->outbuf,12,0,True);
+ }
+
+ SCVAL(cli->outbuf,smb_com,SMBwriteX);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+
+ SIVAL(cli->outbuf,smb_vwv3,offset);
+ SIVAL(cli->outbuf,smb_vwv5,0);
+ SSVAL(cli->outbuf,smb_vwv7,mode);
+
+ SSVAL(cli->outbuf,smb_vwv8,(mode & 0x0008) ? size : 0);
+ /*
+ * According to CIFS-TR-1p00, this following field should only
+ * be set if CAP_LARGE_WRITEX is set. We should check this
+ * locally. However, this check might already have been
+ * done by our callers.
+ */
+ SSVAL(cli->outbuf,smb_vwv9,(size>>16));
+ SSVAL(cli->outbuf,smb_vwv10,size);
+ /* +1 is pad byte. */
+ SSVAL(cli->outbuf,smb_vwv11,
+ smb_buf(cli->outbuf) - smb_base(cli->outbuf) + 1);
+
+ if (large_writex) {
+ SIVAL(cli->outbuf,smb_vwv12,(((SMB_BIG_UINT)offset)>>32) & 0xffffffff);
+ }
+
+ p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11) -1;
+ *p++ = '\0'; /* pad byte. */
+ if (!direct_writes) {
+ memcpy(p, buf, size);
+ }
+ if (size > 0x1FFFF) {
+ /* This is a POSIX 14 word large write. */
+ set_message_bcc(cli->outbuf, 0); /* Set bcc to zero. */
+ _smb_setlen_large(cli->outbuf,smb_size + 28 + 1 /* pad */ + size - 4);
+ } else {
+ cli_setup_bcc(cli, p+size);
+ }
+
+ SSVAL(cli->outbuf,smb_mid,cli->mid + i);
+
+ show_msg(cli->outbuf);
+ if (direct_writes) {
+ /* For direct writes we now need to write the data
+ * directly out of buf. */
+ return cli_send_smb_direct_writeX(cli, buf, size);
+ } else {
+ return cli_send_smb(cli);
+ }
+}
+
+/****************************************************************************
+ write to a file
+ write_mode: 0x0001 disallow write cacheing
+ 0x0002 return bytes remaining
+ 0x0004 use raw named pipe protocol
+ 0x0008 start of message mode named pipe protocol
+****************************************************************************/
+
+ssize_t cli_write(struct cli_state *cli,
+ int fnum, uint16 write_mode,
+ const char *buf, off_t offset, size_t size)
+{
+ ssize_t bwritten = 0;
+ unsigned int issued = 0;
+ unsigned int received = 0;
+ int mpx = 1;
+ size_t writesize;
+ int blocks;
+
+ if(cli->max_mux > 1) {
+ mpx = cli->max_mux-1;
+ } else {
+ mpx = 1;
+ }
+
+ /* Default (small) writesize. */
+ writesize = (cli->max_xmit - (smb_size+32)) & ~1023;
+
+ if (write_mode == 0 &&
+ !client_is_signing_on(cli) &&
+ !cli_encryption_on(cli) &&
+ (cli->posix_capabilities & CIFS_UNIX_LARGE_WRITE_CAP) &&
+ (cli->capabilities & CAP_LARGE_FILES)) {
+ /* Only do massive writes if we can do them direct
+ * with no signing or encrypting - not on a pipe. */
+ writesize = CLI_SAMBA_MAX_POSIX_LARGE_WRITEX_SIZE;
+ } else if ((cli->capabilities & CAP_LARGE_WRITEX) &&
+ (strcmp(cli->dev, "LPT1:") != 0)) {
+
+ /* Printer devices are restricted to max_xmit
+ * writesize in Vista and XPSP3. */
+
+ if (cli->is_samba) {
+ writesize = CLI_SAMBA_MAX_LARGE_WRITEX_SIZE;
+ } else if (!client_is_signing_on(cli)) {
+ /* Windows restricts signed writes to max_xmit.
+ * Found by Volker. */
+ writesize = CLI_WINDOWS_MAX_LARGE_WRITEX_SIZE;
+ }
+ }
+
+ blocks = (size + (writesize-1)) / writesize;
+
+ while (received < blocks) {
+
+ while ((issued - received < mpx) && (issued < blocks)) {
+ ssize_t bsent = issued * writesize;
+ ssize_t size1 = MIN(writesize, size - bsent);
+
+ if (!cli_issue_write(cli, fnum, offset + bsent,
+ write_mode,
+ buf + bsent,
+ size1, issued))
+ return -1;
+ issued++;
+ }
+
+ if (!cli_receive_smb(cli)) {
+ return bwritten;
+ }
+
+ received++;
+
+ if (cli_is_error(cli))
+ break;
+
+ bwritten += SVAL(cli->inbuf, smb_vwv2);
+ if (writesize > 0xFFFF) {
+ bwritten += (((int)(SVAL(cli->inbuf, smb_vwv4)))<<16);
+ }
+ }
+
+ while (received < issued && cli_receive_smb(cli)) {
+ received++;
+ }
+
+ return bwritten;
+}
+
+/****************************************************************************
+ write to a file using a SMBwrite and not bypassing 0 byte writes
+****************************************************************************/
+
+ssize_t cli_smbwrite(struct cli_state *cli,
+ int fnum, char *buf, off_t offset, size_t size1)
+{
+ char *p;
+ ssize_t total = 0;
+
+ do {
+ size_t size = MIN(size1, cli->max_xmit - 48);
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ cli_set_message(cli->outbuf,5, 0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBwrite);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,fnum);
+ SSVAL(cli->outbuf,smb_vwv1,size);
+ SIVAL(cli->outbuf,smb_vwv2,offset);
+ SSVAL(cli->outbuf,smb_vwv4,0);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 1;
+ SSVAL(p, 0, size); p += 2;
+ memcpy(p, buf + total, size); p += size;
+
+ cli_setup_bcc(cli, p);
+
+ if (!cli_send_smb(cli))
+ return -1;
+
+ if (!cli_receive_smb(cli))
+ return -1;
+
+ if (cli_is_error(cli))
+ return -1;
+
+ size = SVAL(cli->inbuf,smb_vwv0);
+ if (size == 0)
+ break;
+
+ size1 -= size;
+ total += size;
+ offset += size;
+
+ } while (size1);
+
+ return total;
+}
diff --git a/source3/libsmb/clisecdesc.c b/source3/libsmb/clisecdesc.c
new file mode 100644
index 0000000000..f0b786c899
--- /dev/null
+++ b/source3/libsmb/clisecdesc.c
@@ -0,0 +1,130 @@
+/*
+ Unix SMB/CIFS implementation.
+ client security descriptor functions
+ Copyright (C) Andrew Tridgell 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ query the security descriptor for a open file
+ ****************************************************************************/
+SEC_DESC *cli_query_secdesc(struct cli_state *cli, int fnum,
+ TALLOC_CTX *mem_ctx)
+{
+ uint8_t param[8];
+ uint8_t *rparam=NULL, *rdata=NULL;
+ unsigned int rparam_count=0, rdata_count=0;
+ SEC_DESC *psd = NULL;
+ NTSTATUS status;
+
+ SIVAL(param, 0, fnum);
+ SIVAL(param, 4, 0x7);
+
+ status = cli_trans(talloc_tos(), cli, SMBnttrans,
+ NULL, -1, /* name, fid */
+ NT_TRANSACT_QUERY_SECURITY_DESC, 0, /* function, flags */
+ NULL, 0, 0, /* setup, length, max */
+ param, 8, 4, /* param, length, max */
+ NULL, 0, 0x10000, /* data, length, max */
+ NULL, NULL, /* rsetup, length */
+ &rparam, &rparam_count,
+ &rdata, &rdata_count);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("NT_TRANSACT_QUERY_SECURITY_DESC failed: %s\n",
+ nt_errstr(status)));
+ goto cleanup;
+ }
+
+ status = unmarshall_sec_desc(mem_ctx, (uint8 *)rdata, rdata_count,
+ &psd);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("unmarshall_sec_desc failed: %s\n",
+ nt_errstr(status)));
+ goto cleanup;
+ }
+
+ cleanup:
+
+ TALLOC_FREE(rparam);
+ TALLOC_FREE(rdata);
+
+ return psd;
+}
+
+/****************************************************************************
+ set the security descriptor for a open file
+ ****************************************************************************/
+bool cli_set_secdesc(struct cli_state *cli, int fnum, SEC_DESC *sd)
+{
+ char param[8];
+ char *rparam=NULL, *rdata=NULL;
+ unsigned int rparam_count=0, rdata_count=0;
+ uint32 sec_info = 0;
+ TALLOC_CTX *frame = talloc_stackframe();
+ bool ret = False;
+ uint8 *data;
+ size_t len;
+ NTSTATUS status;
+
+ status = marshall_sec_desc(talloc_tos(), sd, &data, &len);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("marshall_sec_desc failed: %s\n",
+ nt_errstr(status)));
+ goto cleanup;
+ }
+
+ SIVAL(param, 0, fnum);
+
+ if (sd->dacl)
+ sec_info |= DACL_SECURITY_INFORMATION;
+ if (sd->owner_sid)
+ sec_info |= OWNER_SECURITY_INFORMATION;
+ if (sd->group_sid)
+ sec_info |= GROUP_SECURITY_INFORMATION;
+ SSVAL(param, 4, sec_info);
+
+ if (!cli_send_nt_trans(cli,
+ NT_TRANSACT_SET_SECURITY_DESC,
+ 0,
+ NULL, 0, 0,
+ param, 8, 0,
+ (char *)data, len, 0)) {
+ DEBUG(1,("Failed to send NT_TRANSACT_SET_SECURITY_DESC\n"));
+ goto cleanup;
+ }
+
+
+ if (!cli_receive_nt_trans(cli,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ DEBUG(1,("NT_TRANSACT_SET_SECURITY_DESC failed\n"));
+ goto cleanup;
+ }
+
+ ret = True;
+
+ cleanup:
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ TALLOC_FREE(frame);
+
+ return ret;
+}
diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c
new file mode 100644
index 0000000000..fa9dba098f
--- /dev/null
+++ b/source3/libsmb/clispnego.c
@@ -0,0 +1,600 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple kerberos5/SPNEGO routines
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
+ Copyright (C) Luke Howard 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*
+ generate a negTokenInit packet given a GUID, a list of supported
+ OIDs (the mechanisms) and a principal name string
+*/
+DATA_BLOB spnego_gen_negTokenInit(char guid[16],
+ const char *OIDs[],
+ const char *principal)
+{
+ int i;
+ ASN1_DATA data;
+ DATA_BLOB ret;
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_write(&data, guid, 16);
+ asn1_push_tag(&data,ASN1_APPLICATION(0));
+ asn1_write_OID(&data,OID_SPNEGO);
+ asn1_push_tag(&data,ASN1_CONTEXT(0));
+ asn1_push_tag(&data,ASN1_SEQUENCE(0));
+
+ asn1_push_tag(&data,ASN1_CONTEXT(0));
+ asn1_push_tag(&data,ASN1_SEQUENCE(0));
+ for (i=0; OIDs[i]; i++) {
+ asn1_write_OID(&data,OIDs[i]);
+ }
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+ asn1_write_GeneralString(&data,principal);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(1,("Failed to build negTokenInit at offset %d\n", (int)data.ofs));
+ asn1_free(&data);
+ }
+
+ ret = data_blob(data.data, data.length);
+ asn1_free(&data);
+
+ return ret;
+}
+
+/*
+ Generate a negTokenInit as used by the client side ... It has a mechType
+ (OID), and a mechToken (a security blob) ...
+
+ Really, we need to break out the NTLMSSP stuff as well, because it could be
+ raw in the packets!
+*/
+DATA_BLOB gen_negTokenInit(const char *OID, DATA_BLOB blob)
+{
+ ASN1_DATA data;
+ DATA_BLOB ret;
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_push_tag(&data, ASN1_APPLICATION(0));
+ asn1_write_OID(&data,OID_SPNEGO);
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+ asn1_write_OID(&data, OID);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data, ASN1_CONTEXT(2));
+ asn1_write_OctetString(&data,blob.data,blob.length);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(1,("Failed to build negTokenInit at offset %d\n", (int)data.ofs));
+ asn1_free(&data);
+ }
+
+ ret = data_blob(data.data, data.length);
+ asn1_free(&data);
+
+ return ret;
+}
+
+/*
+ parse a negTokenInit packet giving a GUID, a list of supported
+ OIDs (the mechanisms) and a principal name string
+*/
+bool spnego_parse_negTokenInit(DATA_BLOB blob,
+ char *OIDs[ASN1_MAX_OIDS],
+ char **principal)
+{
+ int i;
+ bool ret;
+ ASN1_DATA data;
+
+ asn1_load(&data, blob);
+
+ asn1_start_tag(&data,ASN1_APPLICATION(0));
+ asn1_check_OID(&data,OID_SPNEGO);
+ asn1_start_tag(&data,ASN1_CONTEXT(0));
+ asn1_start_tag(&data,ASN1_SEQUENCE(0));
+
+ asn1_start_tag(&data,ASN1_CONTEXT(0));
+ asn1_start_tag(&data,ASN1_SEQUENCE(0));
+ for (i=0; asn1_tag_remaining(&data) > 0 && i < ASN1_MAX_OIDS-1; i++) {
+ char *oid_str = NULL;
+ asn1_read_OID(&data,&oid_str);
+ OIDs[i] = oid_str;
+ }
+ OIDs[i] = NULL;
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ *principal = NULL;
+ if (asn1_tag_remaining(&data) > 0) {
+ asn1_start_tag(&data, ASN1_CONTEXT(3));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_CONTEXT(0));
+ asn1_read_GeneralString(&data,principal);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ }
+
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ asn1_end_tag(&data);
+
+ ret = !data.has_error;
+ if (data.has_error) {
+ int j;
+ SAFE_FREE(*principal);
+ for(j = 0; j < i && j < ASN1_MAX_OIDS-1; j++) {
+ SAFE_FREE(OIDs[j]);
+ }
+ }
+
+ asn1_free(&data);
+ return ret;
+}
+
+/*
+ generate a negTokenTarg packet given a list of OIDs and a security blob
+*/
+DATA_BLOB gen_negTokenTarg(const char *OIDs[], DATA_BLOB blob)
+{
+ int i;
+ ASN1_DATA data;
+ DATA_BLOB ret;
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_push_tag(&data, ASN1_APPLICATION(0));
+ asn1_write_OID(&data,OID_SPNEGO);
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+ for (i=0; OIDs[i]; i++) {
+ asn1_write_OID(&data,OIDs[i]);
+ }
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data, ASN1_CONTEXT(2));
+ asn1_write_OctetString(&data,blob.data,blob.length);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(1,("Failed to build negTokenTarg at offset %d\n", (int)data.ofs));
+ asn1_free(&data);
+ }
+
+ ret = data_blob(data.data, data.length);
+ asn1_free(&data);
+
+ return ret;
+}
+
+/*
+ parse a negTokenTarg packet giving a list of OIDs and a security blob
+*/
+bool parse_negTokenTarg(DATA_BLOB blob, char *OIDs[ASN1_MAX_OIDS], DATA_BLOB *secblob)
+{
+ int i;
+ ASN1_DATA data;
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data, ASN1_APPLICATION(0));
+ asn1_check_OID(&data,OID_SPNEGO);
+ asn1_start_tag(&data, ASN1_CONTEXT(0));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+
+ asn1_start_tag(&data, ASN1_CONTEXT(0));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ for (i=0; asn1_tag_remaining(&data) > 0 && i < ASN1_MAX_OIDS-1; i++) {
+ char *oid_str = NULL;
+ asn1_read_OID(&data,&oid_str);
+ OIDs[i] = oid_str;
+ }
+ OIDs[i] = NULL;
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ /* Skip any optional req_flags that are sent per RFC 4178 */
+ if (asn1_check_tag(&data, ASN1_CONTEXT(1))) {
+ uint8 flags;
+
+ asn1_start_tag(&data, ASN1_CONTEXT(1));
+ asn1_start_tag(&data, ASN1_BITFIELD);
+ while (asn1_tag_remaining(&data) > 0)
+ asn1_read_uint8(&data, &flags);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ }
+
+ asn1_start_tag(&data, ASN1_CONTEXT(2));
+ asn1_read_OctetString(&data,secblob);
+ asn1_end_tag(&data);
+
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ asn1_end_tag(&data);
+
+ if (data.has_error) {
+ int j;
+ data_blob_free(secblob);
+ for(j = 0; j < i && j < ASN1_MAX_OIDS-1; j++) {
+ SAFE_FREE(OIDs[j]);
+ }
+ DEBUG(1,("Failed to parse negTokenTarg at offset %d\n", (int)data.ofs));
+ asn1_free(&data);
+ return False;
+ }
+
+ asn1_free(&data);
+ return True;
+}
+
+/*
+ generate a krb5 GSS-API wrapper packet given a ticket
+*/
+DATA_BLOB spnego_gen_krb5_wrap(const DATA_BLOB ticket, const uint8 tok_id[2])
+{
+ ASN1_DATA data;
+ DATA_BLOB ret;
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_push_tag(&data, ASN1_APPLICATION(0));
+ asn1_write_OID(&data, OID_KERBEROS5);
+
+ asn1_write(&data, tok_id, 2);
+ asn1_write(&data, ticket.data, ticket.length);
+ asn1_pop_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(1,("Failed to build krb5 wrapper at offset %d\n", (int)data.ofs));
+ asn1_free(&data);
+ }
+
+ ret = data_blob(data.data, data.length);
+ asn1_free(&data);
+
+ return ret;
+}
+
+/*
+ parse a krb5 GSS-API wrapper packet giving a ticket
+*/
+bool spnego_parse_krb5_wrap(DATA_BLOB blob, DATA_BLOB *ticket, uint8 tok_id[2])
+{
+ bool ret;
+ ASN1_DATA data;
+ int data_remaining;
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data, ASN1_APPLICATION(0));
+ asn1_check_OID(&data, OID_KERBEROS5);
+
+ data_remaining = asn1_tag_remaining(&data);
+
+ if (data_remaining < 3) {
+ data.has_error = True;
+ } else {
+ asn1_read(&data, tok_id, 2);
+ data_remaining -= 2;
+ *ticket = data_blob(NULL, data_remaining);
+ asn1_read(&data, ticket->data, ticket->length);
+ }
+
+ asn1_end_tag(&data);
+
+ ret = !data.has_error;
+
+ if (data.has_error) {
+ data_blob_free(ticket);
+ }
+
+ asn1_free(&data);
+
+ return ret;
+}
+
+
+/*
+ generate a SPNEGO negTokenTarg packet, ready for a EXTENDED_SECURITY
+ kerberos session setup
+*/
+int spnego_gen_negTokenTarg(const char *principal, int time_offset,
+ DATA_BLOB *targ,
+ DATA_BLOB *session_key_krb5, uint32 extra_ap_opts,
+ time_t *expire_time)
+{
+ int retval;
+ DATA_BLOB tkt, tkt_wrapped;
+ const char *krb_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
+
+ /* get a kerberos ticket for the service and extract the session key */
+ retval = cli_krb5_get_ticket(principal, time_offset,
+ &tkt, session_key_krb5, extra_ap_opts, NULL,
+ expire_time);
+
+ if (retval)
+ return retval;
+
+ /* wrap that up in a nice GSS-API wrapping */
+ tkt_wrapped = spnego_gen_krb5_wrap(tkt, TOK_ID_KRB_AP_REQ);
+
+ /* and wrap that in a shiny SPNEGO wrapper */
+ *targ = gen_negTokenTarg(krb_mechs, tkt_wrapped);
+
+ data_blob_free(&tkt_wrapped);
+ data_blob_free(&tkt);
+
+ return retval;
+}
+
+
+/*
+ parse a spnego NTLMSSP challenge packet giving two security blobs
+*/
+bool spnego_parse_challenge(const DATA_BLOB blob,
+ DATA_BLOB *chal1, DATA_BLOB *chal2)
+{
+ bool ret;
+ ASN1_DATA data;
+
+ ZERO_STRUCTP(chal1);
+ ZERO_STRUCTP(chal2);
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data,ASN1_CONTEXT(1));
+ asn1_start_tag(&data,ASN1_SEQUENCE(0));
+
+ asn1_start_tag(&data,ASN1_CONTEXT(0));
+ asn1_check_enumerated(&data,1);
+ asn1_end_tag(&data);
+
+ asn1_start_tag(&data,ASN1_CONTEXT(1));
+ asn1_check_OID(&data, OID_NTLMSSP);
+ asn1_end_tag(&data);
+
+ asn1_start_tag(&data,ASN1_CONTEXT(2));
+ asn1_read_OctetString(&data, chal1);
+ asn1_end_tag(&data);
+
+ /* the second challenge is optional (XP doesn't send it) */
+ if (asn1_tag_remaining(&data)) {
+ asn1_start_tag(&data,ASN1_CONTEXT(3));
+ asn1_read_OctetString(&data, chal2);
+ asn1_end_tag(&data);
+ }
+
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ ret = !data.has_error;
+
+ if (data.has_error) {
+ data_blob_free(chal1);
+ data_blob_free(chal2);
+ }
+
+ asn1_free(&data);
+ return ret;
+}
+
+
+/*
+ generate a SPNEGO auth packet. This will contain the encrypted passwords
+*/
+DATA_BLOB spnego_gen_auth(DATA_BLOB blob)
+{
+ ASN1_DATA data;
+ DATA_BLOB ret;
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_push_tag(&data, ASN1_CONTEXT(1));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+ asn1_push_tag(&data, ASN1_CONTEXT(2));
+ asn1_write_OctetString(&data,blob.data,blob.length);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ ret = data_blob(data.data, data.length);
+
+ asn1_free(&data);
+
+ return ret;
+}
+
+/*
+ parse a SPNEGO auth packet. This contains the encrypted passwords
+*/
+bool spnego_parse_auth(DATA_BLOB blob, DATA_BLOB *auth)
+{
+ ASN1_DATA data;
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data, ASN1_CONTEXT(1));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_CONTEXT(2));
+ asn1_read_OctetString(&data,auth);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(3,("spnego_parse_auth failed at %d\n", (int)data.ofs));
+ data_blob_free(auth);
+ asn1_free(&data);
+ return False;
+ }
+
+ asn1_free(&data);
+ return True;
+}
+
+/*
+ generate a minimal SPNEGO response packet. Doesn't contain much.
+*/
+DATA_BLOB spnego_gen_auth_response(DATA_BLOB *reply, NTSTATUS nt_status,
+ const char *mechOID)
+{
+ ASN1_DATA data;
+ DATA_BLOB ret;
+ uint8 negResult;
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ negResult = SPNEGO_NEG_RESULT_ACCEPT;
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ negResult = SPNEGO_NEG_RESULT_INCOMPLETE;
+ } else {
+ negResult = SPNEGO_NEG_RESULT_REJECT;
+ }
+
+ ZERO_STRUCT(data);
+
+ asn1_push_tag(&data, ASN1_CONTEXT(1));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+ asn1_write_enumerated(&data, negResult);
+ asn1_pop_tag(&data);
+
+ if (mechOID) {
+ asn1_push_tag(&data,ASN1_CONTEXT(1));
+ asn1_write_OID(&data, mechOID);
+ asn1_pop_tag(&data);
+ }
+
+ if (reply && reply->data != NULL) {
+ asn1_push_tag(&data,ASN1_CONTEXT(2));
+ asn1_write_OctetString(&data, reply->data, reply->length);
+ asn1_pop_tag(&data);
+ }
+
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ ret = data_blob(data.data, data.length);
+ asn1_free(&data);
+ return ret;
+}
+
+/*
+ parse a SPNEGO auth packet. This contains the encrypted passwords
+*/
+bool spnego_parse_auth_response(DATA_BLOB blob, NTSTATUS nt_status,
+ const char *mechOID,
+ DATA_BLOB *auth)
+{
+ ASN1_DATA data;
+ uint8 negResult;
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ negResult = SPNEGO_NEG_RESULT_ACCEPT;
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ negResult = SPNEGO_NEG_RESULT_INCOMPLETE;
+ } else {
+ negResult = SPNEGO_NEG_RESULT_REJECT;
+ }
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data, ASN1_CONTEXT(1));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_CONTEXT(0));
+ asn1_check_enumerated(&data, negResult);
+ asn1_end_tag(&data);
+
+ *auth = data_blob_null;
+
+ if (asn1_tag_remaining(&data)) {
+ asn1_start_tag(&data,ASN1_CONTEXT(1));
+ asn1_check_OID(&data, mechOID);
+ asn1_end_tag(&data);
+
+ if (asn1_tag_remaining(&data)) {
+ asn1_start_tag(&data,ASN1_CONTEXT(2));
+ asn1_read_OctetString(&data, auth);
+ asn1_end_tag(&data);
+ }
+ } else if (negResult == SPNEGO_NEG_RESULT_INCOMPLETE) {
+ data.has_error = 1;
+ }
+
+ /* Binding against Win2K DC returns a duplicate of the responseToken in
+ * the optional mechListMIC field. This is a bug in Win2K. We ignore
+ * this field if it exists. Win2K8 may return a proper mechListMIC at
+ * which point we need to implement the integrity checking. */
+ if (asn1_tag_remaining(&data)) {
+ DATA_BLOB mechList = data_blob_null;
+ asn1_start_tag(&data, ASN1_CONTEXT(3));
+ asn1_read_OctetString(&data, &mechList);
+ asn1_end_tag(&data);
+ data_blob_free(&mechList);
+ DEBUG(5,("spnego_parse_auth_response received mechListMIC, "
+ "ignoring.\n"));
+ }
+
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(3,("spnego_parse_auth_response failed at %d\n", (int)data.ofs));
+ asn1_free(&data);
+ data_blob_free(auth);
+ return False;
+ }
+
+ asn1_free(&data);
+ return True;
+}
diff --git a/source3/libsmb/clistr.c b/source3/libsmb/clistr.c
new file mode 100644
index 0000000000..5d20d632aa
--- /dev/null
+++ b/source3/libsmb/clistr.c
@@ -0,0 +1,94 @@
+/*
+ Unix SMB/CIFS implementation.
+ client string routines
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+size_t clistr_push_fn(const char *function,
+ unsigned int line,
+ struct cli_state *cli,
+ void *dest,
+ const char *src,
+ int dest_len,
+ int flags)
+{
+ size_t buf_used = PTR_DIFF(dest, cli->outbuf);
+ if (dest_len == -1) {
+ if (((ptrdiff_t)dest < (ptrdiff_t)cli->outbuf) || (buf_used > cli->bufsize)) {
+ DEBUG(0, ("Pushing string of 'unlimited' length into non-SMB buffer!\n"));
+ return push_string_fn(function, line,
+ cli->outbuf,
+ SVAL(cli->outbuf, smb_flg2),
+ dest, src, -1, flags);
+ }
+ return push_string_fn(function, line, cli->outbuf,
+ SVAL(cli->outbuf, smb_flg2),
+ dest, src, cli->bufsize - buf_used,
+ flags);
+ }
+
+ /* 'normal' push into size-specified buffer */
+ return push_string_fn(function, line, cli->outbuf,
+ SVAL(cli->outbuf, smb_flg2),
+ dest, src, dest_len, flags);
+}
+
+size_t clistr_pull_fn(const char *function,
+ unsigned int line,
+ struct cli_state *cli,
+ char *dest,
+ const void *src,
+ int dest_len,
+ int src_len,
+ int flags)
+{
+ return pull_string_fn(function, line, cli->inbuf,
+ SVAL(cli->inbuf, smb_flg2), dest, src, dest_len,
+ src_len, flags);
+}
+
+size_t clistr_pull_talloc_fn(const char *function,
+ unsigned int line,
+ TALLOC_CTX *ctx,
+ struct cli_state *cli,
+ char **pp_dest,
+ const void *src,
+ int src_len,
+ int flags)
+{
+ return pull_string_talloc_fn(function,
+ line,
+ ctx,
+ cli->inbuf,
+ SVAL(cli->inbuf, smb_flg2),
+ pp_dest,
+ src,
+ src_len,
+ flags);
+}
+
+size_t clistr_align_out(struct cli_state *cli, const void *p, int flags)
+{
+ return align_string(cli->outbuf, (const char *)p, flags);
+}
+
+size_t clistr_align_in(struct cli_state *cli, const void *p, int flags)
+{
+ return align_string(cli->inbuf, (const char *)p, flags);
+}
diff --git a/source3/libsmb/clitrans.c b/source3/libsmb/clitrans.c
new file mode 100644
index 0000000000..c929f0b7a9
--- /dev/null
+++ b/source3/libsmb/clitrans.c
@@ -0,0 +1,1409 @@
+/*
+ Unix SMB/CIFS implementation.
+ client transaction calls
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+
+/****************************************************************************
+ Send a SMB trans or trans2 request.
+****************************************************************************/
+
+bool cli_send_trans(struct cli_state *cli, int trans,
+ const char *pipe_name,
+ int fid, int flags,
+ uint16 *setup, unsigned int lsetup, unsigned int msetup,
+ const char *param, unsigned int lparam, unsigned int mparam,
+ const char *data, unsigned int ldata, unsigned int mdata)
+{
+ unsigned int i;
+ unsigned int this_ldata,this_lparam;
+ unsigned int tot_data=0,tot_param=0;
+ char *outdata,*outparam;
+ char *p;
+ int pipe_name_len=0;
+ uint16 mid;
+
+ this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
+ this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
+
+ memset(cli->outbuf,'\0',smb_size);
+ cli_set_message(cli->outbuf,14+lsetup,0,True);
+ SCVAL(cli->outbuf,smb_com,trans);
+ SSVAL(cli->outbuf,smb_tid, cli->cnum);
+ cli_setup_packet(cli);
+
+ /*
+ * Save the mid we're using. We need this for finding
+ * signing replies.
+ */
+
+ mid = cli->mid;
+
+ if (pipe_name) {
+ pipe_name_len = clistr_push(cli, smb_buf(cli->outbuf), pipe_name, -1, STR_TERMINATE);
+ }
+
+ outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len : 3);
+ outdata = outparam+this_lparam;
+
+ /* primary request */
+ SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
+ SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
+ SSVAL(cli->outbuf,smb_mprcnt,mparam); /* mprcnt */
+ SSVAL(cli->outbuf,smb_mdrcnt,mdata); /* mdrcnt */
+ SCVAL(cli->outbuf,smb_msrcnt,msetup); /* msrcnt */
+ SSVAL(cli->outbuf,smb_flags,flags); /* flags */
+ SIVAL(cli->outbuf,smb_timeout,0); /* timeout */
+ SSVAL(cli->outbuf,smb_pscnt,this_lparam); /* pscnt */
+ SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
+ SSVAL(cli->outbuf,smb_dscnt,this_ldata); /* dscnt */
+ SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
+ SCVAL(cli->outbuf,smb_suwcnt,lsetup); /* suwcnt */
+ for (i=0;i<lsetup;i++) /* setup[] */
+ SSVAL(cli->outbuf,smb_setup+i*2,setup[i]);
+ p = smb_buf(cli->outbuf);
+ if (trans != SMBtrans) {
+ *p++ = 0; /* put in a null smb_name */
+ *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
+ }
+ if (this_lparam) /* param[] */
+ memcpy(outparam,param,this_lparam);
+ if (this_ldata) /* data[] */
+ memcpy(outdata,data,this_ldata);
+ cli_setup_bcc(cli, outdata+this_ldata);
+
+ show_msg(cli->outbuf);
+
+ if (!cli_send_smb(cli)) {
+ return False;
+ }
+
+ /* Note we're in a trans state. Save the sequence
+ * numbers for replies. */
+ client_set_trans_sign_state_on(cli, mid);
+
+ if (this_ldata < ldata || this_lparam < lparam) {
+ /* receive interim response */
+ if (!cli_receive_smb(cli) || cli_is_error(cli)) {
+ client_set_trans_sign_state_off(cli, mid);
+ 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));
+
+ client_set_trans_sign_state_off(cli, mid);
+ client_set_trans_sign_state_on(cli, mid);
+
+ cli_set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
+ SCVAL(cli->outbuf,smb_com,(trans==SMBtrans ? SMBtranss : SMBtranss2));
+
+ outparam = smb_buf(cli->outbuf);
+ outdata = outparam+this_lparam;
+
+ /* secondary request */
+ SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
+ SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
+ SSVAL(cli->outbuf,smb_spscnt,this_lparam); /* pscnt */
+ SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
+ SSVAL(cli->outbuf,smb_spsdisp,tot_param); /* psdisp */
+ SSVAL(cli->outbuf,smb_sdscnt,this_ldata); /* dscnt */
+ SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
+ SSVAL(cli->outbuf,smb_sdsdisp,tot_data); /* dsdisp */
+ if (trans==SMBtrans2)
+ SSVALS(cli->outbuf,smb_sfid,fid); /* fid */
+ if (this_lparam) /* param[] */
+ memcpy(outparam,param+tot_param,this_lparam);
+ if (this_ldata) /* data[] */
+ memcpy(outdata,data+tot_data,this_ldata);
+ cli_setup_bcc(cli, outdata+this_ldata);
+
+ /*
+ * Save the mid we're using. We need this for finding
+ * signing replies.
+ */
+ mid = cli->mid;
+
+ show_msg(cli->outbuf);
+ if (!cli_send_smb(cli)) {
+ client_set_trans_sign_state_off(cli, mid);
+ return False;
+ }
+
+ /* Ensure we use the same mid for the secondaries. */
+ cli->mid = mid;
+
+ tot_data += this_ldata;
+ tot_param += this_lparam;
+ }
+ }
+
+ return(True);
+}
+
+/****************************************************************************
+ Receive a SMB trans or trans2 response allocating the necessary memory.
+****************************************************************************/
+
+bool cli_receive_trans(struct cli_state *cli,int trans,
+ char **param, unsigned int *param_len,
+ char **data, unsigned int *data_len)
+{
+ unsigned int total_data=0;
+ unsigned int total_param=0;
+ unsigned int this_data,this_param;
+ NTSTATUS status;
+ bool ret = False;
+
+ *data_len = *param_len = 0;
+
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ show_msg(cli->inbuf);
+
+ /* sanity check */
+ if (CVAL(cli->inbuf,smb_com) != trans) {
+ DEBUG(0,("Expected %s response, got command 0x%02x\n",
+ trans==SMBtrans?"SMBtrans":"SMBtrans2",
+ CVAL(cli->inbuf,smb_com)));
+ return False;
+ }
+
+ /*
+ * An NT RPC pipe call can return ERRDOS, ERRmoredata
+ * to a trans call. This is not an error and should not
+ * be treated as such. Note that STATUS_NO_MORE_FILES is
+ * returned when a trans2 findfirst/next finishes.
+ * When setting up an encrypted transport we can also
+ * see NT_STATUS_MORE_PROCESSING_REQUIRED here.
+ *
+ * Vista returns NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT if the folder
+ * "<share>/Users/All Users" is enumerated. This is a special pseudo
+ * folder, and the response does not have parameters (nor a parameter
+ * length).
+ */
+ status = cli_nt_error(cli);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ if (NT_STATUS_IS_ERR(status) ||
+ NT_STATUS_EQUAL(status,STATUS_NO_MORE_FILES) ||
+ NT_STATUS_EQUAL(status,NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT)) {
+ goto out;
+ }
+ }
+
+ /* parse out the lengths */
+ total_data = SVAL(cli->inbuf,smb_tdrcnt);
+ total_param = SVAL(cli->inbuf,smb_tprcnt);
+
+ /* allocate it */
+ if (total_data!=0) {
+ /* We know adding 2 is safe as total_data is an
+ * SVAL <= 0xFFFF. */
+ *data = (char *)SMB_REALLOC(*data,total_data+2);
+ if (!(*data)) {
+ DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n"));
+ goto out;
+ }
+ }
+
+ if (total_param!=0) {
+ /* We know adding 2 is safe as total_param is an
+ * SVAL <= 0xFFFF. */
+ *param = (char *)SMB_REALLOC(*param,total_param+2);
+ if (!(*param)) {
+ DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n"));
+ goto out;
+ }
+ }
+
+ for (;;) {
+ 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"));
+ goto out;
+ }
+
+ if (this_data + *data_len < this_data ||
+ this_data + *data_len < *data_len ||
+ this_param + *param_len < this_param ||
+ this_param + *param_len < *param_len) {
+ DEBUG(1,("Data overflow in cli_receive_trans\n"));
+ goto out;
+ }
+
+ if (this_data) {
+ unsigned int data_offset_out = SVAL(cli->inbuf,smb_drdisp);
+ unsigned int data_offset_in = SVAL(cli->inbuf,smb_droff);
+
+ if (data_offset_out > total_data ||
+ data_offset_out + this_data > total_data ||
+ data_offset_out + this_data < data_offset_out ||
+ data_offset_out + this_data < this_data) {
+ DEBUG(1,("Data overflow in cli_receive_trans\n"));
+ goto out;
+ }
+ if (data_offset_in > cli->bufsize ||
+ data_offset_in + this_data > cli->bufsize ||
+ data_offset_in + this_data < data_offset_in ||
+ data_offset_in + this_data < this_data) {
+ DEBUG(1,("Data overflow in cli_receive_trans\n"));
+ goto out;
+ }
+
+ memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
+ }
+ if (this_param) {
+ unsigned int param_offset_out = SVAL(cli->inbuf,smb_prdisp);
+ unsigned int param_offset_in = SVAL(cli->inbuf,smb_proff);
+
+ if (param_offset_out > total_param ||
+ param_offset_out + this_param > total_param ||
+ param_offset_out + this_param < param_offset_out ||
+ param_offset_out + this_param < this_param) {
+ DEBUG(1,("Param overflow in cli_receive_trans\n"));
+ goto out;
+ }
+ if (param_offset_in > cli->bufsize ||
+ param_offset_in + this_param > cli->bufsize ||
+ param_offset_in + this_param < param_offset_in ||
+ param_offset_in + this_param < this_param) {
+ DEBUG(1,("Param overflow in cli_receive_trans\n"));
+ goto out;
+ }
+
+ memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
+ }
+ *data_len += this_data;
+ *param_len += this_param;
+
+ if (total_data <= *data_len && total_param <= *param_len) {
+ ret = True;
+ break;
+ }
+
+ if (!cli_receive_smb(cli)) {
+ goto out;
+ }
+
+ 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)));
+ goto out;
+ }
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ if (NT_STATUS_IS_ERR(cli_nt_error(cli))) {
+ goto out;
+ }
+ }
+
+ /* parse out the total lengths again - they can shrink! */
+ if (SVAL(cli->inbuf,smb_tdrcnt) < total_data)
+ total_data = SVAL(cli->inbuf,smb_tdrcnt);
+ if (SVAL(cli->inbuf,smb_tprcnt) < total_param)
+ total_param = SVAL(cli->inbuf,smb_tprcnt);
+
+ if (total_data <= *data_len && total_param <= *param_len) {
+ ret = True;
+ break;
+ }
+ }
+
+ out:
+
+ if (ret) {
+ /* Ensure the last 2 bytes of param and data are 2 null
+ * bytes. These are malloc'ed, but not included in any
+ * length counts. This allows cli_XX string reading functions
+ * to safely null terminate. */
+ if (total_data) {
+ SSVAL(*data,total_data,0);
+ }
+ if (total_param) {
+ SSVAL(*param,total_param,0);
+ }
+ }
+
+ client_set_trans_sign_state_off(cli, SVAL(cli->inbuf,smb_mid));
+ return ret;
+}
+
+/****************************************************************************
+ Send a SMB nttrans request.
+****************************************************************************/
+
+bool cli_send_nt_trans(struct cli_state *cli,
+ int function,
+ int flags,
+ uint16 *setup, unsigned int lsetup, unsigned int msetup,
+ char *param, unsigned int lparam, unsigned int mparam,
+ char *data, unsigned int ldata, unsigned int mdata)
+{
+ unsigned int i;
+ unsigned int this_ldata,this_lparam;
+ unsigned int tot_data=0,tot_param=0;
+ uint16 mid;
+ char *outdata,*outparam;
+
+ this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
+ this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
+
+ memset(cli->outbuf,'\0',smb_size);
+ cli_set_message(cli->outbuf,19+lsetup,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBnttrans);
+ SSVAL(cli->outbuf,smb_tid, cli->cnum);
+ cli_setup_packet(cli);
+
+ /*
+ * Save the mid we're using. We need this for finding
+ * signing replies.
+ */
+
+ mid = cli->mid;
+
+ outparam = smb_buf(cli->outbuf)+3;
+ outdata = outparam+this_lparam;
+
+ /* primary request */
+ SCVAL(cli->outbuf,smb_nt_MaxSetupCount,msetup);
+ SCVAL(cli->outbuf,smb_nt_Flags,flags);
+ SIVAL(cli->outbuf,smb_nt_TotalParameterCount, lparam);
+ SIVAL(cli->outbuf,smb_nt_TotalDataCount, ldata);
+ SIVAL(cli->outbuf,smb_nt_MaxParameterCount, mparam);
+ SIVAL(cli->outbuf,smb_nt_MaxDataCount, mdata);
+ SIVAL(cli->outbuf,smb_nt_ParameterCount, this_lparam);
+ SIVAL(cli->outbuf,smb_nt_ParameterOffset, smb_offset(outparam,cli->outbuf));
+ SIVAL(cli->outbuf,smb_nt_DataCount, this_ldata);
+ SIVAL(cli->outbuf,smb_nt_DataOffset, smb_offset(outdata,cli->outbuf));
+ SIVAL(cli->outbuf,smb_nt_SetupCount, lsetup);
+ SIVAL(cli->outbuf,smb_nt_Function, function);
+ for (i=0;i<lsetup;i++) /* setup[] */
+ SSVAL(cli->outbuf,smb_nt_SetupStart+i*2,setup[i]);
+
+ if (this_lparam) /* param[] */
+ memcpy(outparam,param,this_lparam);
+ if (this_ldata) /* data[] */
+ memcpy(outdata,data,this_ldata);
+
+ cli_setup_bcc(cli, outdata+this_ldata);
+
+ show_msg(cli->outbuf);
+ if (!cli_send_smb(cli)) {
+ return False;
+ }
+
+ /* Note we're in a trans state. Save the sequence
+ * numbers for replies. */
+ client_set_trans_sign_state_on(cli, mid);
+
+ if (this_ldata < ldata || this_lparam < lparam) {
+ /* receive interim response */
+ if (!cli_receive_smb(cli) || cli_is_error(cli)) {
+ client_set_trans_sign_state_off(cli, mid);
+ 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));
+
+ cli_set_message(cli->outbuf,18,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBnttranss);
+
+ /* XXX - these should probably be aligned */
+ outparam = smb_buf(cli->outbuf);
+ outdata = outparam+this_lparam;
+
+ /* secondary request */
+ SIVAL(cli->outbuf,smb_nts_TotalParameterCount,lparam);
+ SIVAL(cli->outbuf,smb_nts_TotalDataCount,ldata);
+ SIVAL(cli->outbuf,smb_nts_ParameterCount,this_lparam);
+ SIVAL(cli->outbuf,smb_nts_ParameterOffset,smb_offset(outparam,cli->outbuf));
+ SIVAL(cli->outbuf,smb_nts_ParameterDisplacement,tot_param);
+ SIVAL(cli->outbuf,smb_nts_DataCount,this_ldata);
+ SIVAL(cli->outbuf,smb_nts_DataOffset,smb_offset(outdata,cli->outbuf));
+ SIVAL(cli->outbuf,smb_nts_DataDisplacement,tot_data);
+ if (this_lparam) /* param[] */
+ memcpy(outparam,param+tot_param,this_lparam);
+ if (this_ldata) /* data[] */
+ memcpy(outdata,data+tot_data,this_ldata);
+ cli_setup_bcc(cli, outdata+this_ldata);
+
+ /*
+ * Save the mid we're using. We need this for finding
+ * signing replies.
+ */
+ mid = cli->mid;
+
+ show_msg(cli->outbuf);
+
+ if (!cli_send_smb(cli)) {
+ client_set_trans_sign_state_off(cli, mid);
+ return False;
+ }
+
+ /* Ensure we use the same mid for the secondaries. */
+ cli->mid = mid;
+
+ tot_data += this_ldata;
+ tot_param += this_lparam;
+ }
+ }
+
+ return(True);
+}
+
+/****************************************************************************
+ Receive a SMB nttrans response allocating the necessary memory.
+****************************************************************************/
+
+bool cli_receive_nt_trans(struct cli_state *cli,
+ char **param, unsigned int *param_len,
+ char **data, unsigned int *data_len)
+{
+ unsigned int total_data=0;
+ unsigned int total_param=0;
+ unsigned int this_data,this_param;
+ uint8 eclass;
+ uint32 ecode;
+ bool ret = False;
+
+ *data_len = *param_len = 0;
+
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ show_msg(cli->inbuf);
+
+ /* sanity check */
+ if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
+ DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
+ CVAL(cli->inbuf,smb_com)));
+ return(False);
+ }
+
+ /*
+ * An NT RPC pipe call can return ERRDOS, ERRmoredata
+ * to a trans call. This is not an error and should not
+ * be treated as such.
+ */
+ if (cli_is_dos_error(cli)) {
+ cli_dos_error(cli, &eclass, &ecode);
+ if (!(eclass == ERRDOS && ecode == ERRmoredata)) {
+ goto out;
+ }
+ }
+
+ /*
+ * Likewise for NT_STATUS_BUFFER_TOO_SMALL
+ */
+ if (cli_is_nt_error(cli)) {
+ if (!NT_STATUS_EQUAL(cli_nt_error(cli),
+ NT_STATUS_BUFFER_TOO_SMALL)) {
+ goto out;
+ }
+ }
+
+ /* parse out the lengths */
+ total_data = IVAL(cli->inbuf,smb_ntr_TotalDataCount);
+ total_param = IVAL(cli->inbuf,smb_ntr_TotalParameterCount);
+ /* Only allow 16 megs. */
+ if (total_param > 16*1024*1024) {
+ DEBUG(0,("cli_receive_nt_trans: param buffer too large %d\n",
+ total_param));
+ goto out;
+ }
+ if (total_data > 16*1024*1024) {
+ DEBUG(0,("cli_receive_nt_trans: data buffer too large %d\n",
+ total_data));
+ goto out;
+ }
+
+ /* allocate it */
+ if (total_data) {
+ /* We know adding 2 is safe as total_data is less
+ * than 16mb (above). */
+ *data = (char *)SMB_REALLOC(*data,total_data+2);
+ if (!(*data)) {
+ DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data));
+ goto out;
+ }
+ }
+
+ if (total_param) {
+ /* We know adding 2 is safe as total_param is less
+ * than 16mb (above). */
+ *param = (char *)SMB_REALLOC(*param,total_param+2);
+ if (!(*param)) {
+ DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param));
+ goto out;
+ }
+ }
+
+ while (1) {
+ this_data = SVAL(cli->inbuf,smb_ntr_DataCount);
+ this_param = SVAL(cli->inbuf,smb_ntr_ParameterCount);
+
+ if (this_data + *data_len > total_data ||
+ this_param + *param_len > total_param) {
+ DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
+ goto out;
+ }
+
+ if (this_data + *data_len < this_data ||
+ this_data + *data_len < *data_len ||
+ this_param + *param_len < this_param ||
+ this_param + *param_len < *param_len) {
+ DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
+ goto out;
+ }
+
+ if (this_data) {
+ unsigned int data_offset_out = SVAL(cli->inbuf,smb_ntr_DataDisplacement);
+ unsigned int data_offset_in = SVAL(cli->inbuf,smb_ntr_DataOffset);
+
+ if (data_offset_out > total_data ||
+ data_offset_out + this_data > total_data ||
+ data_offset_out + this_data < data_offset_out ||
+ data_offset_out + this_data < this_data) {
+ DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
+ goto out;
+ }
+ if (data_offset_in > cli->bufsize ||
+ data_offset_in + this_data > cli->bufsize ||
+ data_offset_in + this_data < data_offset_in ||
+ data_offset_in + this_data < this_data) {
+ DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
+ goto out;
+ }
+
+ memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
+ }
+
+ if (this_param) {
+ unsigned int param_offset_out = SVAL(cli->inbuf,smb_ntr_ParameterDisplacement);
+ unsigned int param_offset_in = SVAL(cli->inbuf,smb_ntr_ParameterOffset);
+
+ if (param_offset_out > total_param ||
+ param_offset_out + this_param > total_param ||
+ param_offset_out + this_param < param_offset_out ||
+ param_offset_out + this_param < this_param) {
+ DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
+ goto out;
+ }
+ if (param_offset_in > cli->bufsize ||
+ param_offset_in + this_param > cli->bufsize ||
+ param_offset_in + this_param < param_offset_in ||
+ param_offset_in + this_param < this_param) {
+ DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
+ goto out;
+ }
+
+ memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
+ }
+
+ *data_len += this_data;
+ *param_len += this_param;
+
+ if (total_data <= *data_len && total_param <= *param_len) {
+ ret = True;
+ break;
+ }
+
+ if (!cli_receive_smb(cli)) {
+ goto out;
+ }
+
+ show_msg(cli->inbuf);
+
+ /* sanity check */
+ if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
+ DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
+ CVAL(cli->inbuf,smb_com)));
+ goto out;
+ }
+ if (cli_is_dos_error(cli)) {
+ cli_dos_error(cli, &eclass, &ecode);
+ if(!(eclass == ERRDOS && ecode == ERRmoredata)) {
+ goto out;
+ }
+ }
+ /*
+ * Likewise for NT_STATUS_BUFFER_TOO_SMALL
+ */
+ if (cli_is_nt_error(cli)) {
+ if (!NT_STATUS_EQUAL(cli_nt_error(cli),
+ NT_STATUS_BUFFER_TOO_SMALL)) {
+ goto out;
+ }
+ }
+
+ /* parse out the total lengths again - they can shrink! */
+ if (IVAL(cli->inbuf,smb_ntr_TotalDataCount) < total_data)
+ total_data = IVAL(cli->inbuf,smb_ntr_TotalDataCount);
+ if (IVAL(cli->inbuf,smb_ntr_TotalParameterCount) < total_param)
+ total_param = IVAL(cli->inbuf,smb_ntr_TotalParameterCount);
+
+ if (total_data <= *data_len && total_param <= *param_len) {
+ ret = True;
+ break;
+ }
+ }
+
+ out:
+
+ if (ret) {
+ /* Ensure the last 2 bytes of param and data are 2 null
+ * bytes. These are malloc'ed, but not included in any
+ * length counts. This allows cli_XX string reading functions
+ * to safely null terminate. */
+ if (total_data) {
+ SSVAL(*data,total_data,0);
+ }
+ if (total_param) {
+ SSVAL(*param,total_param,0);
+ }
+ }
+
+ client_set_trans_sign_state_off(cli, SVAL(cli->inbuf,smb_mid));
+ return ret;
+}
+
+struct trans_recvblob {
+ uint8_t *data;
+ uint32_t max, total, received;
+};
+
+struct cli_trans_state {
+ struct cli_state *cli;
+ struct event_context *ev;
+ uint8_t cmd;
+ uint16_t mid;
+ const char *pipe_name;
+ uint16_t fid;
+ uint16_t function;
+ int flags;
+ uint16_t *setup;
+ uint8_t num_setup, max_setup;
+ uint8_t *param;
+ uint32_t num_param, param_sent;
+ uint8_t *data;
+ uint32_t num_data, data_sent;
+
+ uint8_t num_rsetup;
+ uint16_t *rsetup;
+ struct trans_recvblob rparam;
+ struct trans_recvblob rdata;
+
+ TALLOC_CTX *secondary_request_ctx;
+};
+
+static void cli_trans_recv_helper(struct async_req *req);
+
+static struct async_req *cli_ship_trans(TALLOC_CTX *mem_ctx,
+ struct cli_trans_state *state)
+{
+ TALLOC_CTX *frame;
+ struct async_req *result = NULL;
+ struct cli_request *cli_req;
+ uint8_t wct;
+ uint16_t *vwv;
+ uint8_t *bytes = NULL;
+ uint16_t param_offset;
+ uint16_t this_param = 0;
+ uint16_t this_data = 0;
+ uint32_t useable_space;
+ uint8_t cmd;
+
+ frame = talloc_stackframe();
+
+ cmd = state->cmd;
+
+ if ((state->param_sent != 0) || (state->data_sent != 0)) {
+ /* The secondary commands are one after the primary ones */
+ cmd += 1;
+ }
+
+ param_offset = smb_size - 4;
+
+ switch (cmd) {
+ case SMBtrans:
+ bytes = TALLOC_ZERO_P(talloc_tos(), uint8_t); /* padding */
+ if (bytes == NULL) {
+ goto fail;
+ }
+ bytes = smb_bytes_push_str(
+ bytes, (state->cli->capabilities & CAP_UNICODE) != 0,
+ state->pipe_name);
+ if (bytes == NULL) {
+ goto fail;
+ }
+ wct = 14 + state->num_setup;
+ param_offset += talloc_get_size(bytes);
+ break;
+ case SMBtrans2:
+ bytes = TALLOC_ARRAY(talloc_tos(), uint8_t, 3); /* padding */
+ if (bytes == NULL) {
+ goto fail;
+ }
+ bytes[0] = 0;
+ bytes[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
+ bytes[2] = ' ';
+ wct = 14 + state->num_setup;
+ param_offset += talloc_get_size(bytes);
+ break;
+ case SMBtranss:
+ wct = 8;
+ break;
+ case SMBtranss2:
+ wct = 9;
+ break;
+ case SMBnttrans:
+ wct = 19 + state->num_setup;
+ break;
+ case SMBnttranss:
+ wct = 18;
+ break;
+ default:
+ goto fail;
+ }
+
+ useable_space = state->cli->max_xmit - smb_size - sizeof(uint16_t)*wct;
+
+ if (state->param_sent < state->num_param) {
+ this_param = MIN(state->num_param - state->param_sent,
+ useable_space);
+ }
+
+ if (state->data_sent < state->num_data) {
+ this_data = MIN(state->num_data - state->data_sent,
+ useable_space - this_param);
+ }
+
+ vwv = TALLOC_ARRAY(talloc_tos(), uint16_t, wct);
+ if (vwv == NULL) {
+ goto fail;
+ }
+ param_offset += wct * sizeof(uint16_t);
+
+ DEBUG(10, ("num_setup=%u, max_setup=%u, "
+ "param_total=%u, this_param=%u, max_param=%u, "
+ "data_total=%u, this_data=%u, max_data=%u, "
+ "param_offset=%u, param_disp=%u, data_disp=%u\n",
+ (unsigned)state->num_setup, (unsigned)state->max_setup,
+ (unsigned)state->num_param, (unsigned)this_param,
+ (unsigned)state->rparam.max,
+ (unsigned)state->num_data, (unsigned)this_data,
+ (unsigned)state->rdata.max,
+ (unsigned)param_offset,
+ (unsigned)state->param_sent, (unsigned)state->data_sent));
+
+ switch (cmd) {
+ case SMBtrans:
+ case SMBtrans2:
+ SSVAL(vwv + 0, 0, state->num_param);
+ SSVAL(vwv + 1, 0, state->num_data);
+ SSVAL(vwv + 2, 0, state->rparam.max);
+ SSVAL(vwv + 3, 0, state->rdata.max);
+ SCVAL(vwv + 4, 0, state->max_setup);
+ SCVAL(vwv + 4, 1, 0); /* reserved */
+ SSVAL(vwv + 5, 0, state->flags);
+ SIVAL(vwv + 6, 0, 0); /* timeout */
+ SSVAL(vwv + 8, 0, 0); /* reserved */
+ SSVAL(vwv + 9, 0, this_param);
+ SSVAL(vwv +10, 0, param_offset);
+ SSVAL(vwv +11, 0, this_data);
+ SSVAL(vwv +12, 0, param_offset + this_param);
+ SCVAL(vwv +13, 0, state->num_setup);
+ SCVAL(vwv +13, 1, 0); /* reserved */
+ memcpy(vwv + 14, state->setup,
+ sizeof(uint16_t) * state->num_setup);
+ break;
+ case SMBtranss:
+ case SMBtranss2:
+ SSVAL(vwv + 0, 0, state->num_param);
+ SSVAL(vwv + 1, 0, state->num_data);
+ SSVAL(vwv + 2, 0, this_param);
+ SSVAL(vwv + 3, 0, param_offset);
+ SSVAL(vwv + 4, 0, state->param_sent);
+ SSVAL(vwv + 5, 0, this_data);
+ SSVAL(vwv + 6, 0, param_offset + this_param);
+ SSVAL(vwv + 7, 0, state->data_sent);
+ if (cmd == SMBtranss2) {
+ SSVAL(vwv + 8, 0, state->fid);
+ }
+ break;
+ case SMBnttrans:
+ SCVAL(vwv, 0, state->max_setup);
+ SSVAL(vwv, 1, 0); /* reserved */
+ SIVAL(vwv, 3, state->num_param);
+ SIVAL(vwv, 7, state->num_data);
+ SIVAL(vwv, 11, state->rparam.max);
+ SIVAL(vwv, 15, state->rdata.max);
+ SIVAL(vwv, 19, this_param);
+ SIVAL(vwv, 23, param_offset);
+ SIVAL(vwv, 27, this_data);
+ SIVAL(vwv, 31, param_offset + this_param);
+ SCVAL(vwv, 35, state->num_setup);
+ SSVAL(vwv, 36, state->function);
+ memcpy(vwv + 19, state->setup,
+ sizeof(uint16_t) * state->num_setup);
+ break;
+ case SMBnttranss:
+ SSVAL(vwv, 0, 0); /* reserved */
+ SCVAL(vwv, 2, 0); /* reserved */
+ SIVAL(vwv, 3, state->num_param);
+ SIVAL(vwv, 7, state->num_data);
+ SIVAL(vwv, 11, this_param);
+ SIVAL(vwv, 15, param_offset);
+ SIVAL(vwv, 19, state->param_sent);
+ SIVAL(vwv, 23, this_data);
+ SIVAL(vwv, 27, param_offset + this_param);
+ SIVAL(vwv, 31, state->data_sent);
+ SCVAL(vwv, 35, 0); /* reserved */
+ break;
+ }
+
+ bytes = (uint8_t *)talloc_append_blob(
+ talloc_tos(), bytes,
+ data_blob_const(state->param + state->param_sent, this_param));
+ if (bytes == NULL) {
+ goto fail;
+ }
+ state->param_sent += this_param;
+
+ bytes = (uint8_t *)talloc_append_blob(
+ talloc_tos(), bytes,
+ data_blob_const(state->data + state->data_sent, this_data));
+ if (bytes == NULL) {
+ goto fail;
+ }
+ state->data_sent += this_data;
+
+ if ((cmd == SMBtrans) || (cmd == SMBtrans2) || (cmd == SMBnttrans)) {
+ /*
+ * Primary request, retrieve our mid
+ */
+ result = cli_request_send(mem_ctx, state->ev, state->cli,
+ cmd, 0, wct, vwv,
+ talloc_get_size(bytes), bytes);
+ if (result == NULL) {
+ goto fail;
+ }
+ cli_req = talloc_get_type_abort(result->private_data,
+ struct cli_request);
+ state->mid = cli_req->mid;
+ } else {
+ uint16_t num_bytes = talloc_get_size(bytes);
+ /*
+ * Secondary request, we have to fix up the mid. Thus we do
+ * the chain_cork/chain/uncork ourselves.
+ */
+ if (!cli_chain_cork(state->cli, state->ev,
+ wct * sizeof(uint16_t) + num_bytes + 3)) {
+ goto fail;
+ }
+ result = cli_request_send(mem_ctx, state->ev, state->cli,
+ cmd, 0, wct, vwv, num_bytes, bytes);
+ if (result == NULL) {
+ goto fail;
+ }
+ cli_req = talloc_get_type_abort(result->private_data,
+ struct cli_request);
+ cli_req->recv_helper.fn = cli_trans_recv_helper;
+ cli_req->recv_helper.priv = state;
+ cli_req->mid = state->mid;
+ client_set_trans_sign_state_off(state->cli, state->mid);
+ cli_chain_uncork(state->cli);
+ }
+
+ client_set_trans_sign_state_on(state->cli, state->mid);
+
+ fail:
+ TALLOC_FREE(frame);
+ return result;
+}
+
+static void cli_trans_ship_rest(struct async_req *req,
+ struct cli_trans_state *state)
+{
+ state->secondary_request_ctx = talloc_new(state);
+ if (state->secondary_request_ctx == NULL) {
+ async_req_error(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+
+ while ((state->param_sent < state->num_param)
+ || (state->data_sent < state->num_data)) {
+ struct async_req *cli_req;
+
+ cli_req = cli_ship_trans(state->secondary_request_ctx, state);
+ if (cli_req == NULL) {
+ async_req_error(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ }
+}
+
+static bool cli_trans_oob(uint32_t bufsize, uint32_t offset, uint32_t length)
+{
+ if ((offset + length < offset) || (offset + length < length)) {
+ /* wrap */
+ return true;
+ }
+ if ((offset > bufsize) || (offset + length > bufsize)) {
+ /* overflow */
+ return true;
+ }
+ return false;
+}
+
+static NTSTATUS cli_pull_trans(struct async_req *req,
+ struct cli_request *cli_req,
+ uint8_t smb_cmd, bool expect_first_reply,
+ uint8_t *pnum_setup, uint16_t **psetup,
+ uint32_t *ptotal_param, uint32_t *pnum_param,
+ uint32_t *pparam_disp, uint8_t **pparam,
+ uint32_t *ptotal_data, uint32_t *pnum_data,
+ uint32_t *pdata_disp, uint8_t **pdata)
+{
+ uint32_t param_ofs, data_ofs;
+ uint8_t wct;
+ uint16_t *vwv;
+ uint16_t num_bytes;
+ uint8_t *bytes;
+ NTSTATUS status;
+
+ status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
+
+ /*
+ * We can receive something like STATUS_MORE_ENTRIES, so don't use
+ * !NT_STATUS_IS_OK(status) here.
+ */
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ if (expect_first_reply) {
+ if ((wct != 0) || (num_bytes != 0)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ return NT_STATUS_OK;
+ }
+
+ switch (smb_cmd) {
+ case SMBtrans:
+ case SMBtrans2:
+ if (wct < 10) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ *ptotal_param = SVAL(vwv + 0, 0);
+ *ptotal_data = SVAL(vwv + 1, 0);
+ *pnum_param = SVAL(vwv + 3, 0);
+ param_ofs = SVAL(vwv + 4, 0);
+ *pparam_disp = SVAL(vwv + 5, 0);
+ *pnum_data = SVAL(vwv + 6, 0);
+ data_ofs = SVAL(vwv + 7, 0);
+ *pdata_disp = SVAL(vwv + 8, 0);
+ *pnum_setup = CVAL(vwv + 9, 0);
+ if (wct < 10 + (*pnum_setup)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ *psetup = vwv + 10;
+
+ break;
+ case SMBnttrans:
+ if (wct < 18) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ *ptotal_param = IVAL(vwv, 3);
+ *ptotal_data = IVAL(vwv, 7);
+ *pnum_param = IVAL(vwv, 11);
+ param_ofs = IVAL(vwv, 15);
+ *pparam_disp = IVAL(vwv, 19);
+ *pnum_data = IVAL(vwv, 23);
+ data_ofs = IVAL(vwv, 27);
+ *pdata_disp = IVAL(vwv, 31);
+ *pnum_setup = CVAL(vwv, 35);
+ *psetup = vwv + 18;
+ break;
+
+ default:
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /*
+ * Check for buffer overflows. data_ofs needs to be checked against
+ * the incoming buffer length, data_disp against the total
+ * length. Likewise for param_ofs/param_disp.
+ */
+
+ if (cli_trans_oob(smb_len(cli_req->inbuf), param_ofs, *pnum_param)
+ || cli_trans_oob(*ptotal_param, *pparam_disp, *pnum_param)
+ || cli_trans_oob(smb_len(cli_req->inbuf), data_ofs, *pnum_data)
+ || cli_trans_oob(*ptotal_data, *pdata_disp, *pnum_data)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ *pparam = (uint8_t *)cli_req->inbuf + 4 + param_ofs;
+ *pdata = (uint8_t *)cli_req->inbuf + 4 + data_ofs;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cli_trans_pull_blob(TALLOC_CTX *mem_ctx,
+ struct trans_recvblob *blob,
+ uint32_t total, uint32_t thistime,
+ uint8_t *buf, uint32_t displacement)
+{
+ if (blob->data == NULL) {
+ if (total > blob->max) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ blob->total = total;
+ blob->data = TALLOC_ARRAY(mem_ctx, uint8_t, total);
+ if (blob->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (total > blob->total) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (thistime) {
+ memcpy(blob->data + displacement, buf, thistime);
+ blob->received += thistime;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static void cli_trans_recv_helper(struct async_req *req)
+{
+ struct cli_request *cli_req = talloc_get_type_abort(
+ req->private_data, struct cli_request);
+ struct cli_trans_state *state = talloc_get_type_abort(
+ cli_req->recv_helper.priv, struct cli_trans_state);
+ uint8_t num_setup = 0;
+ uint16_t *setup = NULL;
+ uint32_t total_param = 0;
+ uint32_t num_param = 0;
+ uint32_t param_disp = 0;
+ uint32_t total_data = 0;
+ uint32_t num_data = 0;
+ uint32_t data_disp = 0;
+ uint8_t *param = NULL;
+ uint8_t *data = NULL;
+ bool sent_all;
+ NTSTATUS status;
+
+ sent_all = (state->param_sent == state->num_param)
+ && (state->data_sent == state->num_data);
+
+ status = cli_pull_trans(
+ req, cli_req, state->cmd, !sent_all, &num_setup, &setup,
+ &total_param, &num_param, &param_disp, &param,
+ &total_data, &num_data, &data_disp, &data);
+
+ /*
+ * We can receive something like STATUS_MORE_ENTRIES, so don't use
+ * !NT_STATUS_IS_OK(status) here.
+ */
+
+ if (NT_STATUS_IS_ERR(status)) {
+ async_req_error(req, status);
+ return;
+ }
+
+ if (!sent_all) {
+ cli_trans_ship_rest(req, state);
+ return;
+ }
+
+ /*
+ * We've just received a real response. This means that we don't need
+ * the secondary cli_request structures anymore, they have all been
+ * shipped to the server.
+ */
+ TALLOC_FREE(state->secondary_request_ctx);
+
+ if (num_setup != 0) {
+ TALLOC_FREE(state->rsetup);
+ state->rsetup = (uint16_t *)TALLOC_MEMDUP(
+ state, setup, sizeof(uint16_t) * num_setup);
+ if (state->rsetup == NULL) {
+ async_req_error(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ }
+
+ status = cli_trans_pull_blob(
+ state, &state->rparam, total_param, num_param, param,
+ param_disp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status)));
+ async_req_error(req, status);
+ return;
+ }
+
+ status = cli_trans_pull_blob(
+ state, &state->rdata, total_data, num_data, data,
+ data_disp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status)));
+ async_req_error(req, status);
+ return;
+ }
+
+ if ((state->rparam.total == state->rparam.received)
+ && (state->rdata.total == state->rdata.received)) {
+ client_set_trans_sign_state_off(state->cli, state->mid);
+ async_req_done(req);
+ }
+}
+
+struct async_req *cli_trans_send(
+ TALLOC_CTX *mem_ctx, struct event_context *ev,
+ struct cli_state *cli, uint8_t trans_cmd,
+ const char *pipe_name, uint16_t fid, uint16_t function, int flags,
+ uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
+ uint8_t *param, uint32_t num_param, uint32_t max_param,
+ uint8_t *data, uint32_t num_data, uint32_t max_data)
+{
+ struct async_req *req;
+ struct cli_request *cli_req;
+ struct cli_trans_state *state;
+
+ /*
+ * We can't use it in a chained request chain, we'd get the offset
+ * calculations wrong.
+ */
+
+ if (cli_in_chain(cli)) {
+ return NULL;
+ }
+
+ if ((trans_cmd == SMBtrans) || (trans_cmd == SMBtrans2)) {
+ if ((num_param > 0xffff) || (max_param > 0xffff)
+ || (num_data > 0xffff) || (max_data > 0xffff)) {
+ DEBUG(3, ("Attempt to send invalid trans2 request "
+ "(setup %u, params %u/%u, data %u/%u)\n",
+ (unsigned)num_setup,
+ (unsigned)num_param, (unsigned)max_param,
+ (unsigned)num_data, (unsigned)max_data));
+ return NULL;
+ }
+ }
+
+ state = talloc(mem_ctx, struct cli_trans_state);
+ if (state == NULL) {
+ goto nomem;
+ }
+
+ state->cli = cli;
+ state->ev = ev;
+ state->cmd = trans_cmd;
+ state->num_rsetup = 0;
+ state->rsetup = NULL;
+ ZERO_STRUCT(state->rparam);
+ ZERO_STRUCT(state->rdata);
+ state->secondary_request_ctx = NULL;
+
+ if (trans_cmd == SMBtrans) {
+ state->pipe_name = talloc_strdup(state, pipe_name);
+ if (state->pipe_name == NULL) {
+ goto nomem;
+ }
+ }
+ if (trans_cmd == SMBtrans2) {
+ state->fid = fid;
+ }
+ if (trans_cmd == SMBnttrans) {
+ state->function = function;
+ }
+
+ state->flags = flags;
+
+ if (setup != NULL) {
+ state->setup = (uint16_t *)TALLOC_MEMDUP(
+ state, setup, sizeof(*setup) * num_setup);
+ if (state->setup == NULL) {
+ goto nomem;
+ }
+ state->num_setup = num_setup;
+ } else {
+ state->setup = NULL;
+ state->num_setup = 0;
+ }
+
+ state->max_setup = max_setup;
+
+ if (param != NULL) {
+ state->param = (uint8_t *)TALLOC_MEMDUP(state, param,
+ num_param);
+ if (state->param == NULL) {
+ goto nomem;
+ }
+ state->num_param = num_param;
+ } else {
+ state->param = NULL;
+ state->num_param = 0;
+ }
+
+ state->param_sent = 0;
+ state->rparam.max = max_param;
+
+ if (data != NULL) {
+ state->data = (uint8_t *)TALLOC_MEMDUP(state, data, num_data);
+ if (state->data == NULL) {
+ goto nomem;
+ }
+ state->num_data = num_data;
+ } else {
+ state->data = NULL;
+ state->num_data = 0;
+ }
+
+ state->data_sent = 0;
+ state->rdata.max = max_data;
+
+ req = cli_ship_trans(state, state);
+ if (req == NULL) {
+ goto nomem;
+ }
+
+ cli_req = talloc_get_type_abort(req->private_data, struct cli_request);
+ cli_req->recv_helper.fn = cli_trans_recv_helper;
+ cli_req->recv_helper.priv = state;
+
+ return req;
+
+ nomem:
+ TALLOC_FREE(state);
+ return NULL;
+}
+
+NTSTATUS cli_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
+ uint16_t **setup, uint8_t *num_setup,
+ uint8_t **param, uint32_t *num_param,
+ uint8_t **data, uint32_t *num_data)
+{
+ struct cli_request *cli_req = talloc_get_type_abort(
+ req->private_data, struct cli_request);
+ struct cli_trans_state *state = talloc_get_type_abort(
+ cli_req->recv_helper.priv, struct cli_trans_state);
+
+ SMB_ASSERT(req->state >= ASYNC_REQ_DONE);
+ if (req->state == ASYNC_REQ_ERROR) {
+ return req->status;
+ }
+
+ if (setup != NULL) {
+ *setup = talloc_move(mem_ctx, &state->rsetup);
+ *num_setup = state->num_rsetup;
+ } else {
+ TALLOC_FREE(state->rsetup);
+ }
+
+ if (param != NULL) {
+ *param = talloc_move(mem_ctx, &state->rparam.data);
+ *num_param = state->rparam.total;
+ } else {
+ TALLOC_FREE(state->rparam.data);
+ }
+
+ if (data != NULL) {
+ *data = talloc_move(mem_ctx, &state->rdata.data);
+ *num_data = state->rdata.total;
+ } else {
+ TALLOC_FREE(state->rdata.data);
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS cli_trans(TALLOC_CTX *mem_ctx, struct cli_state *cli,
+ uint8_t trans_cmd,
+ const char *pipe_name, uint16_t fid, uint16_t function,
+ int flags,
+ uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
+ uint8_t *param, uint32_t num_param, uint32_t max_param,
+ uint8_t *data, uint32_t num_data, uint32_t max_data,
+ uint16_t **rsetup, uint8_t *num_rsetup,
+ uint8_t **rparam, uint32_t *num_rparam,
+ uint8_t **rdata, uint32_t *num_rdata)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct async_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (cli->fd_event != NULL) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ cli_set_error(cli, NT_STATUS_INVALID_PARAMETER);
+ goto fail;
+ }
+
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+
+ req = cli_trans_send(frame, ev, cli, trans_cmd,
+ pipe_name, fid, function, flags,
+ setup, num_setup, max_setup,
+ param, num_param, max_param,
+ data, num_data, max_data);
+ if (req == NULL) {
+ goto fail;
+ }
+
+ while (req->state < ASYNC_REQ_DONE) {
+ event_loop_once(ev);
+ }
+
+ status = cli_trans_recv(req, mem_ctx, rsetup, num_rsetup,
+ rparam, num_rparam, rdata, num_rdata);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/source3/libsmb/conncache.c b/source3/libsmb/conncache.c
new file mode 100644
index 0000000000..b440d61048
--- /dev/null
+++ b/source3/libsmb/conncache.c
@@ -0,0 +1,256 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon connection manager
+
+ Copyright (C) Tim Potter 2001
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Gerald (Jerry) Carter 2003
+ Copyright (C) Marc VanHeyningen 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+
+/**
+ * @file
+ * Negative connection cache implemented in terms of gencache API
+ *
+ * The negative connection cache stores names of servers which have
+ * been unresponsive so that we don't waste time repeatedly trying
+ * to contact them. It used to use an in-memory linked list, but
+ * this limited its utility to a single process
+ */
+
+
+/**
+ * prefix used for all entries put into the general cache
+ */
+static const char NEGATIVE_CONN_CACHE_PREFIX[] = "NEG_CONN_CACHE";
+
+/**
+ * Marshalls the domain and server name into the key for the gencache
+ * record
+ *
+ * @param[in] domain required
+ * @param[in] server may be a FQDN or an IP address
+ * @return the resulting string, which the caller is responsible for
+ * SAFE_FREE()ing
+ * @retval NULL returned on error
+ */
+static char *negative_conn_cache_keystr(const char *domain, const char *server)
+{
+ const char NEGATIVE_CONN_CACHE_KEY_FMT[] = "%s/%s,%s";
+ char *keystr = NULL;
+
+ SMB_ASSERT(domain != NULL);
+ if (server == NULL)
+ server = "";
+
+ keystr = talloc_asprintf(talloc_tos(),NEGATIVE_CONN_CACHE_KEY_FMT,
+ NEGATIVE_CONN_CACHE_PREFIX, domain, server);
+ if (keystr == NULL) {
+ DEBUG(0, ("negative_conn_cache_keystr: malloc error\n"));
+ }
+
+ return keystr;
+}
+
+/**
+ * Marshalls the NT status into a printable value field for the gencache
+ * record
+ *
+ * @param[in] status
+ * @return the resulting string, which the caller is responsible for
+ * SAFE_FREE()ing
+ * @retval NULL returned on error
+ */
+static char *negative_conn_cache_valuestr(NTSTATUS status)
+{
+ char *valuestr = NULL;
+
+ valuestr = talloc_asprintf(talloc_tos(), "%x", NT_STATUS_V(status));
+ if (valuestr == NULL) {
+ DEBUG(0, ("negative_conn_cache_valuestr: malloc error\n"));
+ }
+
+ return valuestr;
+}
+
+/**
+ * Un-marshalls the NT status from a printable field for the gencache
+ * record
+ *
+ * @param[in] value The value field from the record
+ * @return the decoded NT status
+ * @retval NT_STATUS_OK returned on error
+ */
+static NTSTATUS negative_conn_cache_valuedecode(const char *value)
+{
+ NTSTATUS result = NT_STATUS_OK;
+
+ SMB_ASSERT(value != NULL);
+ if (sscanf(value, "%x", &(NT_STATUS_V(result))) != 1)
+ DEBUG(0, ("negative_conn_cache_valuestr: unable to parse "
+ "value field '%s'\n", value));
+ return result;
+}
+
+/**
+ * Function passed to gencache_iterate to remove any matching items
+ * from the list
+ *
+ * @param[in] key Key to the record found and to be deleted
+ * @param[in] value Value to the record (ignored)
+ * @param[in] timeout Timeout remaining for the record (ignored)
+ * @param[in] dptr Handle for passing additional data (ignored)
+ */
+static void delete_matches(const char *key, const char *value,
+ time_t timeout, void *dptr)
+{
+ gencache_del(key);
+}
+
+
+/**
+ * Checks for a given domain/server record in the negative cache
+ *
+ * @param[in] domain
+ * @param[in] server may be either a FQDN or an IP address
+ * @return The cached failure status
+ * @retval NT_STATUS_OK returned if no record is found or an error occurs
+ */
+NTSTATUS check_negative_conn_cache( const char *domain, const char *server)
+{
+ NTSTATUS result = NT_STATUS_OK;
+ char *key = NULL;
+ char *value = NULL;
+
+ key = negative_conn_cache_keystr(domain, server);
+ if (key == NULL)
+ goto done;
+
+ if (gencache_get(key, &value, (time_t *) NULL))
+ result = negative_conn_cache_valuedecode(value);
+ done:
+ DEBUG(9,("check_negative_conn_cache returning result %d for domain %s "
+ "server %s\n", NT_STATUS_V(result), domain, server));
+ TALLOC_FREE(key);
+ SAFE_FREE(value);
+ return result;
+}
+
+/**
+ * Delete any negative cache entry for the given domain/server
+ *
+ * @param[in] domain
+ * @param[in] server may be either a FQDN or an IP address
+ */
+void delete_negative_conn_cache(const char *domain, const char *server)
+{
+ char *key = NULL;
+
+ key = negative_conn_cache_keystr(domain, server);
+ if (key == NULL)
+ goto done;
+
+ gencache_del(key);
+ DEBUG(9,("delete_negative_conn_cache removing domain %s server %s\n",
+ domain, server));
+ done:
+ TALLOC_FREE(key);
+ return;
+}
+
+
+/**
+ * Add an entry to the failed connection cache
+ *
+ * @param[in] domain
+ * @param[in] server may be a FQDN or an IP addr in printable form
+ * @param[in] result error to cache; must not be NT_STATUS_OK
+ */
+void add_failed_connection_entry(const char *domain, const char *server,
+ NTSTATUS result)
+{
+ char *key = NULL;
+ char *value = NULL;
+
+ SMB_ASSERT(!NT_STATUS_IS_OK(result));
+
+ key = negative_conn_cache_keystr(domain, server);
+ if (key == NULL) {
+ DEBUG(0, ("add_failed_connection_entry: key creation error\n"));
+ goto done;
+ }
+
+ value = negative_conn_cache_valuestr(result);
+ if (value == NULL) {
+ DEBUG(0, ("add_failed_connection_entry: value creation error\n"));
+ goto done;
+ }
+
+ if (gencache_set(key, value,
+ time((time_t *) NULL)
+ + FAILED_CONNECTION_CACHE_TIMEOUT))
+ DEBUG(9,("add_failed_connection_entry: added domain %s (%s) "
+ "to failed conn cache\n", domain, server ));
+ else
+ DEBUG(1,("add_failed_connection_entry: failed to add "
+ "domain %s (%s) to failed conn cache\n",
+ domain, server));
+
+ done:
+ TALLOC_FREE(key);
+ TALLOC_FREE(value);
+ return;
+}
+
+/**
+ * Deletes all records from the negative connection cache in all domains
+ */
+void flush_negative_conn_cache( void )
+{
+ flush_negative_conn_cache_for_domain("*");
+}
+
+
+/**
+ * Deletes all records for a specified domain from the negative connection
+ * cache
+ *
+ * @param[in] domain String to match against domain portion of keys, or "*"
+ * to match all domains
+ */
+void flush_negative_conn_cache_for_domain(const char *domain)
+{
+ char *key_pattern = NULL;
+
+ key_pattern = negative_conn_cache_keystr(domain,"*");
+ if (key_pattern == NULL) {
+ DEBUG(0, ("flush_negative_conn_cache_for_domain: "
+ "key creation error\n"));
+ goto done;
+ }
+
+ gencache_iterate(delete_matches, (void *) NULL, key_pattern);
+ DEBUG(8, ("flush_negative_conn_cache_for_domain: flushed domain %s\n",
+ domain));
+
+ done:
+ TALLOC_FREE(key_pattern);
+ return;
+}
diff --git a/source3/libsmb/credentials.c b/source3/libsmb/credentials.c
new file mode 100644
index 0000000000..9d33e6d93d
--- /dev/null
+++ b/source3/libsmb/credentials.c
@@ -0,0 +1,361 @@
+/*
+ Unix SMB/CIFS implementation.
+ code to manipulate domain credentials
+ Copyright (C) Andrew Tridgell 1997-1998
+ Largely rewritten by Jeremy Allison 2005.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Represent a credential as a string.
+****************************************************************************/
+
+char *credstr(const unsigned char *cred)
+{
+ char *result;
+ result = talloc_asprintf(talloc_tos(),
+ "%02X%02X%02X%02X%02X%02X%02X%02X",
+ cred[0], cred[1], cred[2], cred[3],
+ cred[4], cred[5], cred[6], cred[7]);
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+/****************************************************************************
+ Setup the session key and the client and server creds in dc.
+ ADS-style 128 bit session keys.
+ Used by both client and server creds setup.
+****************************************************************************/
+
+static void creds_init_128(struct dcinfo *dc,
+ const struct netr_Credential *clnt_chal_in,
+ const struct netr_Credential *srv_chal_in,
+ const unsigned char mach_pw[16])
+{
+ unsigned char zero[4], tmp[16];
+ HMACMD5Context ctx;
+ struct MD5Context md5;
+
+ /* Just in case this isn't already there */
+ memcpy(dc->mach_pw, mach_pw, 16);
+
+ ZERO_STRUCT(dc->sess_key);
+
+ memset(zero, 0, sizeof(zero));
+
+ hmac_md5_init_rfc2104(mach_pw, 16, &ctx);
+ MD5Init(&md5);
+ MD5Update(&md5, zero, sizeof(zero));
+ MD5Update(&md5, clnt_chal_in->data, 8);
+ MD5Update(&md5, srv_chal_in->data, 8);
+ MD5Final(tmp, &md5);
+ hmac_md5_update(tmp, sizeof(tmp), &ctx);
+ hmac_md5_final(dc->sess_key, &ctx);
+
+ /* debug output */
+ DEBUG(5,("creds_init_128\n"));
+ DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
+ DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
+ dump_data_pw("\tsession_key ", (const unsigned char *)dc->sess_key, 16);
+
+ /* Generate the next client and server creds. */
+
+ des_crypt112(dc->clnt_chal.data, /* output */
+ clnt_chal_in->data, /* input */
+ dc->sess_key, /* input */
+ 1);
+
+ des_crypt112(dc->srv_chal.data, /* output */
+ srv_chal_in->data, /* input */
+ dc->sess_key, /* input */
+ 1);
+
+ /* Seed is the client chal. */
+ memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
+}
+
+/****************************************************************************
+ Setup the session key and the client and server creds in dc.
+ Used by both client and server creds setup.
+****************************************************************************/
+
+static void creds_init_64(struct dcinfo *dc,
+ const struct netr_Credential *clnt_chal_in,
+ const struct netr_Credential *srv_chal_in,
+ const unsigned char mach_pw[16])
+{
+ uint32 sum[2];
+ unsigned char sum2[8];
+
+ /* Just in case this isn't already there */
+ if (dc->mach_pw != mach_pw) {
+ memcpy(dc->mach_pw, mach_pw, 16);
+ }
+
+ sum[0] = IVAL(clnt_chal_in->data, 0) + IVAL(srv_chal_in->data, 0);
+ sum[1] = IVAL(clnt_chal_in->data, 4) + IVAL(srv_chal_in->data, 4);
+
+ SIVAL(sum2,0,sum[0]);
+ SIVAL(sum2,4,sum[1]);
+
+ ZERO_STRUCT(dc->sess_key);
+
+ des_crypt128(dc->sess_key, sum2, dc->mach_pw);
+
+ /* debug output */
+ DEBUG(5,("creds_init_64\n"));
+ DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
+ DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
+ DEBUG(5,("\tclnt+srv : %s\n", credstr(sum2)));
+ DEBUG(5,("\tsess_key_out : %s\n", credstr(dc->sess_key)));
+
+ /* Generate the next client and server creds. */
+
+ des_crypt112(dc->clnt_chal.data, /* output */
+ clnt_chal_in->data, /* input */
+ dc->sess_key, /* input */
+ 1);
+
+ des_crypt112(dc->srv_chal.data, /* output */
+ srv_chal_in->data, /* input */
+ dc->sess_key, /* input */
+ 1);
+
+ /* Seed is the client chal. */
+ memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
+}
+
+/****************************************************************************
+ Utility function to step credential chain one forward.
+ Deliberately doesn't update the seed. See reseed comment below.
+****************************************************************************/
+
+static void creds_step(struct dcinfo *dc)
+{
+ DOM_CHAL time_chal;
+
+ DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
+
+ DEBUG(5,("\tseed: %s\n", credstr(dc->seed_chal.data) ));
+
+ SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence);
+ SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
+
+ DEBUG(5,("\tseed+seq %s\n", credstr(time_chal.data) ));
+
+ des_crypt112(dc->clnt_chal.data, time_chal.data, dc->sess_key, 1);
+
+ DEBUG(5,("\tCLIENT %s\n", credstr(dc->clnt_chal.data) ));
+
+ SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
+ SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
+
+ DEBUG(5,("\tseed+seq+1 %s\n", credstr(time_chal.data) ));
+
+ des_crypt112(dc->srv_chal.data, time_chal.data, dc->sess_key, 1);
+
+ DEBUG(5,("\tSERVER %s\n", credstr(dc->srv_chal.data) ));
+}
+
+/****************************************************************************
+ Create a server credential struct.
+****************************************************************************/
+
+void creds_server_init(uint32 neg_flags,
+ struct dcinfo *dc,
+ struct netr_Credential *clnt_chal,
+ struct netr_Credential *srv_chal,
+ const unsigned char mach_pw[16],
+ struct netr_Credential *init_chal_out)
+{
+ DEBUG(10,("creds_server_init: neg_flags : %x\n", (unsigned int)neg_flags));
+ DEBUG(10,("creds_server_init: client chal : %s\n", credstr(clnt_chal->data) ));
+ DEBUG(10,("creds_server_init: server chal : %s\n", credstr(srv_chal->data) ));
+ dump_data_pw("creds_server_init: machine pass", mach_pw, 16);
+
+ /* Generate the session key and the next client and server creds. */
+ if (neg_flags & NETLOGON_NEG_128BIT) {
+ creds_init_128(dc,
+ clnt_chal,
+ srv_chal,
+ mach_pw);
+ } else {
+ creds_init_64(dc,
+ clnt_chal,
+ srv_chal,
+ mach_pw);
+ }
+
+ dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
+
+ DEBUG(10,("creds_server_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
+ DEBUG(10,("creds_server_init: server : %s\n", credstr(dc->srv_chal.data) ));
+ DEBUG(10,("creds_server_init: seed : %s\n", credstr(dc->seed_chal.data) ));
+
+ memcpy(init_chal_out->data, dc->srv_chal.data, 8);
+}
+
+/****************************************************************************
+ Check a credential sent by the client.
+****************************************************************************/
+
+bool netlogon_creds_server_check(const struct dcinfo *dc,
+ const struct netr_Credential *rcv_cli_chal_in)
+{
+ if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) {
+ DEBUG(5,("netlogon_creds_server_check: challenge : %s\n",
+ credstr(rcv_cli_chal_in->data)));
+ DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data)));
+ DEBUG(2,("netlogon_creds_server_check: credentials check failed.\n"));
+ return false;
+ }
+
+ DEBUG(10,("netlogon_creds_server_check: credentials check OK.\n"));
+
+ return true;
+}
+/****************************************************************************
+ Replace current seed chal. Internal function - due to split server step below.
+****************************************************************************/
+
+static void creds_reseed(struct dcinfo *dc)
+{
+ struct netr_Credential time_chal;
+
+ SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
+ SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
+
+ dc->seed_chal = time_chal;
+
+ DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
+}
+
+/****************************************************************************
+ Step the server credential chain one forward.
+****************************************************************************/
+
+bool netlogon_creds_server_step(struct dcinfo *dc,
+ const struct netr_Authenticator *received_cred,
+ struct netr_Authenticator *cred_out)
+{
+ bool ret;
+ struct dcinfo tmp_dc = *dc;
+
+ /* Do all operations on a temporary copy of the dc,
+ which we throw away if the checks fail. */
+
+ tmp_dc.sequence = received_cred->timestamp;
+
+ creds_step(&tmp_dc);
+
+ /* Create the outgoing credentials */
+ cred_out->timestamp = tmp_dc.sequence + 1;
+ memcpy(&cred_out->cred, &tmp_dc.srv_chal, sizeof(cred_out->cred));
+
+ creds_reseed(&tmp_dc);
+
+ ret = netlogon_creds_server_check(&tmp_dc, &received_cred->cred);
+ if (!ret) {
+ return false;
+ }
+
+ /* creds step succeeded - replace the current creds. */
+ *dc = tmp_dc;
+ return true;
+}
+
+/****************************************************************************
+ Create a client credential struct.
+****************************************************************************/
+
+void creds_client_init(uint32 neg_flags,
+ struct dcinfo *dc,
+ struct netr_Credential *clnt_chal,
+ struct netr_Credential *srv_chal,
+ const unsigned char mach_pw[16],
+ struct netr_Credential *init_chal_out)
+{
+ dc->sequence = time(NULL);
+
+ DEBUG(10,("creds_client_init: neg_flags : %x\n", (unsigned int)neg_flags));
+ DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) ));
+ DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) ));
+ dump_data_pw("creds_client_init: machine pass", (const unsigned char *)mach_pw, 16);
+
+ /* Generate the session key and the next client and server creds. */
+ if (neg_flags & NETLOGON_NEG_128BIT) {
+ creds_init_128(dc,
+ clnt_chal,
+ srv_chal,
+ mach_pw);
+ } else {
+ creds_init_64(dc,
+ clnt_chal,
+ srv_chal,
+ mach_pw);
+ }
+
+ dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
+
+ DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
+ DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) ));
+ DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) ));
+
+ memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
+}
+
+/****************************************************************************
+ Check a credential returned by the server.
+****************************************************************************/
+
+bool netlogon_creds_client_check(const struct dcinfo *dc,
+ const struct netr_Credential *rcv_srv_chal_in)
+{
+ if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data,
+ sizeof(dc->srv_chal.data))) {
+
+ DEBUG(0,("netlogon_creds_client_check: credentials check failed.\n"));
+ DEBUGADD(5,("netlogon_creds_client_check: challenge : %s\n",
+ credstr(rcv_srv_chal_in->data)));
+ DEBUGADD(5,("calculated: %s\n", credstr(dc->srv_chal.data)));
+ return false;
+ }
+
+ DEBUG(10,("netlogon_creds_client_check: credentials check OK.\n"));
+
+ return true;
+}
+
+
+/****************************************************************************
+ Step the client credentials to the next element in the chain, updating the
+ current client and server credentials and the seed
+ produce the next authenticator in the sequence ready to send to
+ the server
+****************************************************************************/
+
+void netlogon_creds_client_step(struct dcinfo *dc,
+ struct netr_Authenticator *next_cred_out)
+{
+ dc->sequence += 2;
+ creds_step(dc);
+ creds_reseed(dc);
+
+ memcpy(&next_cred_out->cred.data, &dc->clnt_chal.data,
+ sizeof(next_cred_out->cred.data));
+ next_cred_out->timestamp = dc->sequence;
+}
diff --git a/source3/libsmb/dcerpc_err.c b/source3/libsmb/dcerpc_err.c
new file mode 100644
index 0000000000..900b8d769f
--- /dev/null
+++ b/source3/libsmb/dcerpc_err.c
@@ -0,0 +1,55 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Stefan Metzmacher 2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+struct dcerpc_fault_table {
+ const char *errstr;
+ uint32_t faultcode;
+};
+
+static const struct dcerpc_fault_table dcerpc_faults[] =
+{
+ { "DCERPC_FAULT_OP_RNG_ERROR", DCERPC_FAULT_OP_RNG_ERROR },
+ { "DCERPC_FAULT_UNK_IF", DCERPC_FAULT_UNK_IF },
+ { "DCERPC_FAULT_NDR", DCERPC_FAULT_NDR },
+ { "DCERPC_FAULT_INVALID_TAG", DCERPC_FAULT_INVALID_TAG },
+ { "DCERPC_FAULT_CONTEXT_MISMATCH", DCERPC_FAULT_CONTEXT_MISMATCH },
+ { "DCERPC_FAULT_OTHER", DCERPC_FAULT_OTHER },
+ { "DCERPC_FAULT_ACCESS_DENIED", DCERPC_FAULT_ACCESS_DENIED },
+
+ { NULL, 0}
+};
+
+const char *dcerpc_errstr(uint32 fault_code)
+{
+ char *result;
+ int idx = 0;
+
+ while (dcerpc_faults[idx].errstr != NULL) {
+ if (dcerpc_faults[idx].faultcode == fault_code) {
+ return dcerpc_faults[idx].errstr;
+ }
+ idx++;
+ }
+
+ result = talloc_asprintf(talloc_tos(), "DCERPC fault 0x%08x",
+ fault_code);
+ SMB_ASSERT(result != NULL);
+ return result;
+}
diff --git a/source3/libsmb/doserr.c b/source3/libsmb/doserr.c
new file mode 100644
index 0000000000..2716e04d91
--- /dev/null
+++ b/source3/libsmb/doserr.c
@@ -0,0 +1,202 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * DOS error routines
+ * Copyright (C) Tim Potter 2002.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* DOS error codes. please read doserr.h */
+
+#include "includes.h"
+
+typedef const struct {
+ const char *dos_errstr;
+ WERROR werror;
+} werror_code_struct;
+
+typedef const struct {
+ WERROR werror;
+ const char *friendly_errstr;
+} werror_str_struct;
+
+werror_code_struct dos_errs[] =
+{
+ { "WERR_OK", WERR_OK },
+ { "WERR_GENERAL_FAILURE", WERR_GENERAL_FAILURE },
+ { "WERR_BADFILE", WERR_BADFILE },
+ { "WERR_ACCESS_DENIED", WERR_ACCESS_DENIED },
+ { "WERR_BADFID", WERR_BADFID },
+ { "WERR_BADFUNC", WERR_BADFUNC },
+ { "WERR_INSUFFICIENT_BUFFER", WERR_INSUFFICIENT_BUFFER },
+ { "WERR_SEM_TIMEOUT", WERR_SEM_TIMEOUT },
+ { "WERR_NO_SUCH_SHARE", WERR_NO_SUCH_SHARE },
+ { "WERR_ALREADY_EXISTS", WERR_ALREADY_EXISTS },
+ { "WERR_INVALID_PARAM", WERR_INVALID_PARAM },
+ { "WERR_NOT_SUPPORTED", WERR_NOT_SUPPORTED },
+ { "WERR_BAD_PASSWORD", WERR_BAD_PASSWORD },
+ { "WERR_NOMEM", WERR_NOMEM },
+ { "WERR_INVALID_NAME", WERR_INVALID_NAME },
+ { "WERR_UNKNOWN_LEVEL", WERR_UNKNOWN_LEVEL },
+ { "WERR_OBJECT_PATH_INVALID", WERR_OBJECT_PATH_INVALID },
+ { "WERR_NO_MORE_ITEMS", WERR_NO_MORE_ITEMS },
+ { "WERR_MORE_DATA", WERR_MORE_DATA },
+ { "WERR_UNKNOWN_PRINTER_DRIVER", WERR_UNKNOWN_PRINTER_DRIVER },
+ { "WERR_INVALID_PRINTER_NAME", WERR_INVALID_PRINTER_NAME },
+ { "WERR_PRINTER_ALREADY_EXISTS", WERR_PRINTER_ALREADY_EXISTS },
+ { "WERR_INVALID_DATATYPE", WERR_INVALID_DATATYPE },
+ { "WERR_INVALID_ENVIRONMENT", WERR_INVALID_ENVIRONMENT },
+ { "WERR_INVALID_FORM_NAME", WERR_INVALID_FORM_NAME },
+ { "WERR_INVALID_FORM_SIZE", WERR_INVALID_FORM_SIZE },
+ { "WERR_BUF_TOO_SMALL", WERR_BUF_TOO_SMALL },
+ { "WERR_JOB_NOT_FOUND", WERR_JOB_NOT_FOUND },
+ { "WERR_DEST_NOT_FOUND", WERR_DEST_NOT_FOUND },
+ { "WERR_GROUP_NOT_FOUND", WERR_GROUP_NOT_FOUND },
+ { "WERR_USER_NOT_FOUND", WERR_USER_NOT_FOUND },
+ { "WERR_NOT_LOCAL_DOMAIN", WERR_NOT_LOCAL_DOMAIN },
+ { "WERR_USER_EXISTS", WERR_USER_EXISTS },
+ { "WERR_REVISION_MISMATCH", WERR_REVISION_MISMATCH },
+ { "WERR_NO_LOGON_SERVERS", WERR_NO_LOGON_SERVERS },
+ { "WERR_NO_SUCH_LOGON_SESSION", WERR_NO_SUCH_LOGON_SESSION },
+ { "WERR_USER_ALREADY_EXISTS", WERR_USER_ALREADY_EXISTS },
+ { "WERR_NO_SUCH_USER", WERR_NO_SUCH_USER },
+ { "WERR_GROUP_EXISTS", WERR_GROUP_EXISTS },
+ { "WERR_MEMBER_IN_GROUP", WERR_MEMBER_IN_GROUP },
+ { "WERR_USER_NOT_IN_GROUP", WERR_USER_NOT_IN_GROUP },
+ { "WERR_PRINTER_DRIVER_IN_USE", WERR_PRINTER_DRIVER_IN_USE },
+ { "WERR_STATUS_MORE_ENTRIES ", WERR_STATUS_MORE_ENTRIES },
+ { "WERR_DFS_NO_SUCH_VOL", WERR_DFS_NO_SUCH_VOL },
+ { "WERR_DFS_NO_SUCH_SHARE", WERR_DFS_NO_SUCH_SHARE },
+ { "WERR_DFS_NO_SUCH_SERVER", WERR_DFS_NO_SUCH_SERVER },
+ { "WERR_DFS_INTERNAL_ERROR", WERR_DFS_INTERNAL_ERROR },
+ { "WERR_DFS_CANT_CREATE_JUNCT", WERR_DFS_CANT_CREATE_JUNCT },
+ { "WERR_INVALID_COMPUTER_NAME", WERR_INVALID_COMPUTER_NAME },
+ { "WERR_INVALID_DOMAINNAME", WERR_INVALID_DOMAINNAME },
+ { "WERR_MACHINE_LOCKED", WERR_MACHINE_LOCKED },
+ { "WERR_DC_NOT_FOUND", WERR_DC_NOT_FOUND },
+ { "WERR_SETUP_NOT_JOINED", WERR_SETUP_NOT_JOINED },
+ { "WERR_SETUP_ALREADY_JOINED", WERR_SETUP_ALREADY_JOINED },
+ { "WERR_SETUP_DOMAIN_CONTROLLER", WERR_SETUP_DOMAIN_CONTROLLER },
+ { "WERR_DEFAULT_JOIN_REQUIRED", WERR_DEFAULT_JOIN_REQUIRED },
+ { "WERR_DEVICE_NOT_AVAILABLE", WERR_DEVICE_NOT_AVAILABLE },
+ { "WERR_LOGON_FAILURE", WERR_LOGON_FAILURE },
+ { "WERR_WRONG_PASSWORD", WERR_WRONG_PASSWORD },
+ { "WERR_PASSWORD_RESTRICTION", WERR_PASSWORD_RESTRICTION },
+ { "WERR_NO_SUCH_DOMAIN", WERR_NO_SUCH_DOMAIN },
+ { "WERR_NONE_MAPPED", WERR_NONE_MAPPED },
+ { "WERR_INVALID_SECURITY_DESCRIPTOR", WERR_INVALID_SECURITY_DESCRIPTOR },
+ { "WERR_INVALID_DOMAIN_STATE", WERR_INVALID_DOMAIN_STATE },
+ { "WERR_INVALID_DOMAIN_ROLE", WERR_INVALID_DOMAIN_ROLE },
+ { "WERR_SPECIAL_ACCOUNT", WERR_SPECIAL_ACCOUNT },
+ { "WERR_ALIAS_EXISTS", WERR_ALIAS_EXISTS },
+ { "WERR_NO_SUCH_ALIAS", WERR_NO_SUCH_ALIAS },
+ { "WERR_MEMBER_IN_ALIAS", WERR_MEMBER_IN_ALIAS },
+ { "WERR_TIME_SKEW", WERR_TIME_SKEW },
+ { "WERR_INVALID_OWNER", WERR_INVALID_OWNER },
+ { "WERR_SERVER_UNAVAILABLE", WERR_SERVER_UNAVAILABLE },
+ { "WERR_IO_PENDING", WERR_IO_PENDING },
+ { "WERR_INVALID_SERVICE_CONTROL", WERR_INVALID_SERVICE_CONTROL },
+ { "WERR_SERVICE_ALREADY_RUNNING", WERR_SERVICE_ALREADY_RUNNING },
+ { "WERR_NET_NAME_NOT_FOUND", WERR_NET_NAME_NOT_FOUND },
+ { "WERR_REG_CORRUPT", WERR_REG_CORRUPT },
+ { "WERR_REG_IO_FAILURE", WERR_REG_IO_FAILURE },
+ { "WERR_REG_FILE_INVALID", WERR_REG_FILE_INVALID },
+ { "WERR_NO_SUCH_SERVICE", WERR_NO_SUCH_SERVICE },
+ { "WERR_SERVICE_DISABLED", WERR_SERVICE_DISABLED },
+ { "WERR_SERVICE_NEVER_STARTED", WERR_SERVICE_NEVER_STARTED },
+ { "WERR_NOT_FOUND", WERR_NOT_FOUND },
+ { "WERR_CAN_NOT_COMPLETE", WERR_CAN_NOT_COMPLETE},
+ { "WERR_INVALID_FLAGS", WERR_INVALID_FLAGS},
+ { "WERR_PASSWORD_MUST_CHANGE", WERR_PASSWORD_MUST_CHANGE },
+ { "WERR_DOMAIN_CONTROLLER_NOT_FOUND", WERR_DOMAIN_CONTROLLER_NOT_FOUND },
+ { "WERR_ACCOUNT_LOCKED_OUT", WERR_ACCOUNT_LOCKED_OUT },
+ { "WERR_DS_DRA_BAD_DN", WERR_DS_DRA_BAD_DN },
+ { "WERR_DS_DRA_BAD_NC", WERR_DS_DRA_BAD_NC },
+ { NULL, W_ERROR(0) }
+};
+
+werror_str_struct dos_err_strs[] = {
+ { WERR_OK, "Success" },
+ { WERR_ACCESS_DENIED, "Access is denied" },
+ { WERR_INVALID_PARAM, "Invalid parameter" },
+ { WERR_NOT_SUPPORTED, "Not supported" },
+ { WERR_BAD_PASSWORD, "A bad password was supplied" },
+ { WERR_NOMEM, "Out of memory" },
+ { WERR_NO_LOGON_SERVERS, "No logon servers found" },
+ { WERR_NO_SUCH_LOGON_SESSION, "No such logon session" },
+ { WERR_DOMAIN_CONTROLLER_NOT_FOUND, "A domain controller could not be found" },
+ { WERR_DC_NOT_FOUND, "A domain controller could not be found" },
+ { WERR_SETUP_NOT_JOINED, "Join failed" },
+ { WERR_SETUP_ALREADY_JOINED, "Machine is already joined" },
+ { WERR_SETUP_DOMAIN_CONTROLLER, "Machine is a Domain Controller" },
+ { WERR_LOGON_FAILURE, "Invalid logon credentials" },
+ { WERR_USER_EXISTS, "User account already exists" },
+ { WERR_PASSWORD_MUST_CHANGE, "The password must be changed" },
+ { WERR_ACCOUNT_LOCKED_OUT, "Account locked out" },
+ { WERR_TIME_SKEW, "Time difference between client and server" },
+ { WERR_USER_ALREADY_EXISTS, "User already exists" },
+ { WERR_PASSWORD_RESTRICTION, "Password does not meet restrictions" },
+ { WERR_NONE_MAPPED, "Could not map names to SIDs" },
+ { WERR_NO_SUCH_USER, "No such User" },
+ { WERR_GROUP_EXISTS, "Group already exists" },
+ { WERR_DS_DRA_BAD_DN, "An invalid distinguished name was specified for this replication" },
+ { WERR_DS_DRA_BAD_NC, "An invalid naming context was specified for this replication operation" },
+ { WERR_WRONG_PASSWORD, "The current password is incorrect" }
+};
+
+/*****************************************************************************
+ Returns a DOS error message. not amazingly helpful, but better than a number.
+ *****************************************************************************/
+
+const char *dos_errstr(WERROR werror)
+{
+ char *result;
+ int idx = 0;
+
+ while (dos_errs[idx].dos_errstr != NULL) {
+ if (W_ERROR_V(dos_errs[idx].werror) ==
+ W_ERROR_V(werror))
+ return dos_errs[idx].dos_errstr;
+ idx++;
+ }
+
+ result = talloc_asprintf(talloc_tos(), "DOS code 0x%08x",
+ W_ERROR_V(werror));
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+/*****************************************************************************
+ Get friendly error string for WERRORs
+ *****************************************************************************/
+
+const char *get_friendly_werror_msg(WERROR werror)
+{
+ int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(dos_err_strs); i++) {
+ if (W_ERROR_V(dos_err_strs[i].werror) ==
+ W_ERROR_V(werror)) {
+ return dos_err_strs[i].friendly_errstr;
+ }
+ }
+
+ return dos_errstr(werror);
+}
+
+/* compat function for samba4 */
+const char *win_errstr(WERROR werror)
+{
+ return dos_errstr(werror);
+}
diff --git a/source3/libsmb/dsgetdcname.c b/source3/libsmb/dsgetdcname.c
new file mode 100644
index 0000000000..2a445cbd5a
--- /dev/null
+++ b/source3/libsmb/dsgetdcname.c
@@ -0,0 +1,1449 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dsgetdcname
+
+ Copyright (C) Gerald Carter 2006
+ Copyright (C) Guenther Deschner 2007-2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#define DSGETDCNAME_FMT "DSGETDCNAME/DOMAIN/%s"
+/* 15 minutes */
+#define DSGETDCNAME_CACHE_TTL 60*15
+
+struct ip_service_name {
+ struct sockaddr_storage ss;
+ unsigned port;
+ const char *hostname;
+};
+
+static NTSTATUS make_dc_info_from_cldap_reply(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct sockaddr_storage *ss,
+ uint32_t nt_version,
+ union nbt_cldap_netlogon *r,
+ struct netr_DsRGetDCNameInfo **info);
+
+/****************************************************************
+****************************************************************/
+
+void debug_dsdcinfo_flags(int lvl, uint32_t flags)
+{
+ DEBUG(lvl,("debug_dsdcinfo_flags: 0x%08x\n\t", flags));
+
+ if (flags & DS_FORCE_REDISCOVERY)
+ DEBUGADD(lvl,("DS_FORCE_REDISCOVERY "));
+ if (flags & 0x000000002)
+ DEBUGADD(lvl,("0x00000002 "));
+ if (flags & 0x000000004)
+ DEBUGADD(lvl,("0x00000004 "));
+ if (flags & 0x000000008)
+ DEBUGADD(lvl,("0x00000008 "));
+ if (flags & DS_DIRECTORY_SERVICE_REQUIRED)
+ DEBUGADD(lvl,("DS_DIRECTORY_SERVICE_REQUIRED "));
+ if (flags & DS_DIRECTORY_SERVICE_PREFERRED)
+ DEBUGADD(lvl,("DS_DIRECTORY_SERVICE_PREFERRED "));
+ if (flags & DS_GC_SERVER_REQUIRED)
+ DEBUGADD(lvl,("DS_GC_SERVER_REQUIRED "));
+ if (flags & DS_PDC_REQUIRED)
+ DEBUGADD(lvl,("DS_PDC_REQUIRED "));
+ if (flags & DS_BACKGROUND_ONLY)
+ DEBUGADD(lvl,("DS_BACKGROUND_ONLY "));
+ if (flags & DS_IP_REQUIRED)
+ DEBUGADD(lvl,("DS_IP_REQUIRED "));
+ if (flags & DS_KDC_REQUIRED)
+ DEBUGADD(lvl,("DS_KDC_REQUIRED "));
+ if (flags & DS_TIMESERV_REQUIRED)
+ DEBUGADD(lvl,("DS_TIMESERV_REQUIRED "));
+ if (flags & DS_WRITABLE_REQUIRED)
+ DEBUGADD(lvl,("DS_WRITABLE_REQUIRED "));
+ if (flags & DS_GOOD_TIMESERV_PREFERRED)
+ DEBUGADD(lvl,("DS_GOOD_TIMESERV_PREFERRED "));
+ if (flags & DS_AVOID_SELF)
+ DEBUGADD(lvl,("DS_AVOID_SELF "));
+ if (flags & DS_ONLY_LDAP_NEEDED)
+ DEBUGADD(lvl,("DS_ONLY_LDAP_NEEDED "));
+ if (flags & DS_IS_FLAT_NAME)
+ DEBUGADD(lvl,("DS_IS_FLAT_NAME "));
+ if (flags & DS_IS_DNS_NAME)
+ DEBUGADD(lvl,("DS_IS_DNS_NAME "));
+ if (flags & 0x00040000)
+ DEBUGADD(lvl,("0x00040000 "));
+ if (flags & 0x00080000)
+ DEBUGADD(lvl,("0x00080000 "));
+ if (flags & 0x00100000)
+ DEBUGADD(lvl,("0x00100000 "));
+ if (flags & 0x00200000)
+ DEBUGADD(lvl,("0x00200000 "));
+ if (flags & 0x00400000)
+ DEBUGADD(lvl,("0x00400000 "));
+ if (flags & 0x00800000)
+ DEBUGADD(lvl,("0x00800000 "));
+ if (flags & 0x01000000)
+ DEBUGADD(lvl,("0x01000000 "));
+ if (flags & 0x02000000)
+ DEBUGADD(lvl,("0x02000000 "));
+ if (flags & 0x04000000)
+ DEBUGADD(lvl,("0x04000000 "));
+ if (flags & 0x08000000)
+ DEBUGADD(lvl,("0x08000000 "));
+ if (flags & 0x10000000)
+ DEBUGADD(lvl,("0x10000000 "));
+ if (flags & 0x20000000)
+ DEBUGADD(lvl,("0x20000000 "));
+ if (flags & DS_RETURN_DNS_NAME)
+ DEBUGADD(lvl,("DS_RETURN_DNS_NAME "));
+ if (flags & DS_RETURN_FLAT_NAME)
+ DEBUGADD(lvl,("DS_RETURN_FLAT_NAME "));
+ if (flags)
+ DEBUGADD(lvl,("\n"));
+}
+
+/****************************************************************
+****************************************************************/
+
+static char *dsgetdcname_cache_key(TALLOC_CTX *mem_ctx, const char *domain)
+{
+ if (!domain) {
+ return NULL;
+ }
+
+ return talloc_asprintf_strupper_m(mem_ctx, DSGETDCNAME_FMT, domain);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS dsgetdcname_cache_delete(TALLOC_CTX *mem_ctx,
+ const char *domain_name)
+{
+ char *key;
+
+ if (!gencache_init()) {
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ key = dsgetdcname_cache_key(mem_ctx, domain_name);
+ if (!key) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!gencache_del(key)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS dsgetdcname_cache_store(TALLOC_CTX *mem_ctx,
+ const char *domain_name,
+ const DATA_BLOB *blob)
+{
+ time_t expire_time;
+ char *key;
+ bool ret = false;
+
+ if (!gencache_init()) {
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ key = dsgetdcname_cache_key(mem_ctx, domain_name);
+ if (!key) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ expire_time = time(NULL) + DSGETDCNAME_CACHE_TTL;
+
+ if (gencache_lock_entry(key) != 0) {
+ return NT_STATUS_LOCK_NOT_GRANTED;
+ }
+
+ ret = gencache_set_data_blob(key, blob, expire_time);
+
+ gencache_unlock_entry(key);
+
+ return ret ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+/****************************************************************
+****************************************************************/
+
+#define SET_STRING(x) \
+ talloc_strdup(mem_ctx, x); \
+ NT_STATUS_HAVE_NO_MEMORY(x);
+
+static NTSTATUS map_logon29_from_cldap_reply(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct sockaddr_storage *ss,
+ uint32_t nt_version,
+ union nbt_cldap_netlogon *r,
+ struct nbt_cldap_netlogon_29 *p)
+{
+ char addr[INET6_ADDRSTRLEN];
+
+ ZERO_STRUCTP(p);
+
+ print_sockaddr(addr, sizeof(addr), ss);
+
+ /* FIXME */
+ p->dc_sock_addr_size = 0x10; /* the w32 winsock addr size */
+ p->dc_sock_addr.family = 2; /* AF_INET */
+ p->dc_sock_addr.pdc_ip = talloc_strdup(mem_ctx, addr);
+
+ switch (nt_version & 0x0000001f) {
+ case 0:
+ return NT_STATUS_INVALID_PARAMETER;
+ case 1:
+ case 16:
+ case 17:
+ p->pdc_name = SET_STRING(r->logon1.pdc_name);
+ p->domain = SET_STRING(r->logon1.domain_name);
+
+ if (flags & DS_PDC_REQUIRED) {
+ p->server_type = NBT_SERVER_WRITABLE |
+ NBT_SERVER_PDC;
+ }
+ break;
+ case 2:
+ case 3:
+ case 18:
+ case 19:
+ p->pdc_name = SET_STRING(r->logon3.pdc_name);
+ p->domain = SET_STRING(r->logon3.domain_name);
+ p->pdc_dns_name = SET_STRING(r->logon3.pdc_dns_name);
+ p->dns_domain = SET_STRING(r->logon3.dns_domain);
+ p->server_type = r->logon3.server_type;
+ p->forest = SET_STRING(r->logon3.forest);
+ p->domain_uuid = r->logon3.domain_uuid;
+
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ p->pdc_name = SET_STRING(r->logon5.pdc_name);
+ p->domain = SET_STRING(r->logon5.domain);
+ p->pdc_dns_name = SET_STRING(r->logon5.pdc_dns_name);
+ p->dns_domain = SET_STRING(r->logon5.dns_domain);
+ p->server_type = r->logon5.server_type;
+ p->forest = SET_STRING(r->logon5.forest);
+ p->domain_uuid = r->logon5.domain_uuid;
+ p->server_site = SET_STRING(r->logon5.server_site);
+ p->client_site = SET_STRING(r->logon5.client_site);
+
+ break;
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ p->pdc_name = SET_STRING(r->logon13.pdc_name);
+ p->domain = SET_STRING(r->logon13.domain);
+ p->pdc_dns_name = SET_STRING(r->logon13.pdc_dns_name);
+ p->dns_domain = SET_STRING(r->logon13.dns_domain);
+ p->server_type = r->logon13.server_type;
+ p->forest = SET_STRING(r->logon13.forest);
+ p->domain_uuid = r->logon13.domain_uuid;
+ p->server_site = SET_STRING(r->logon13.server_site);
+ p->client_site = SET_STRING(r->logon13.client_site);
+
+ break;
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ p->pdc_name = SET_STRING(r->logon15.pdc_name);
+ p->domain = SET_STRING(r->logon15.domain);
+ p->pdc_dns_name = SET_STRING(r->logon15.pdc_dns_name);
+ p->dns_domain = SET_STRING(r->logon15.dns_domain);
+ p->server_type = r->logon15.server_type;
+ p->forest = SET_STRING(r->logon15.forest);
+ p->domain_uuid = r->logon15.domain_uuid;
+ p->server_site = SET_STRING(r->logon15.server_site);
+ p->client_site = SET_STRING(r->logon15.client_site);
+
+ break;
+ case 29:
+ case 30:
+ case 31:
+ p->pdc_name = SET_STRING(r->logon29.pdc_name);
+ p->domain = SET_STRING(r->logon29.domain);
+ p->pdc_dns_name = SET_STRING(r->logon29.pdc_dns_name);
+ p->dns_domain = SET_STRING(r->logon29.dns_domain);
+ p->server_type = r->logon29.server_type;
+ p->forest = SET_STRING(r->logon29.forest);
+ p->domain_uuid = r->logon29.domain_uuid;
+ p->server_site = SET_STRING(r->logon29.server_site);
+ p->client_site = SET_STRING(r->logon29.client_site);
+ p->next_closest_site = SET_STRING(r->logon29.next_closest_site);
+
+ break;
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS store_cldap_reply(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct sockaddr_storage *ss,
+ uint32_t nt_version,
+ union nbt_cldap_netlogon *r)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ NTSTATUS status;
+ struct nbt_cldap_netlogon_29 logon29;
+
+ status = map_logon29_from_cldap_reply(mem_ctx, flags, ss,
+ nt_version, r, &logon29);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &logon29,
+ (ndr_push_flags_fn_t)ndr_push_nbt_cldap_netlogon_29);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ if (logon29.domain) {
+ status = dsgetdcname_cache_store(mem_ctx, logon29.domain, &blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ if (logon29.client_site) {
+ sitename_store(logon29.domain, logon29.client_site);
+ }
+ }
+ if (logon29.dns_domain) {
+ status = dsgetdcname_cache_store(mem_ctx, logon29.dns_domain, &blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ if (logon29.client_site) {
+ sitename_store(logon29.dns_domain, logon29.client_site);
+ }
+ }
+
+ done:
+ data_blob_free(&blob);
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS dsgetdcname_cache_refresh(TALLOC_CTX *mem_ctx,
+ struct messaging_context *msg_ctx,
+ const char *domain_name,
+ struct GUID *domain_guid,
+ uint32_t flags,
+ const char *site_name,
+ struct netr_DsRGetDCNameInfo *info)
+{
+ struct netr_DsRGetDCNameInfo *dc_info;
+
+ return dsgetdcname(mem_ctx,
+ msg_ctx,
+ domain_name,
+ domain_guid,
+ site_name,
+ flags | DS_FORCE_REDISCOVERY,
+ &dc_info);
+}
+
+/****************************************************************
+****************************************************************/
+
+static uint32_t get_cldap_reply_server_flags(union nbt_cldap_netlogon *r,
+ uint32_t nt_version)
+{
+ switch (nt_version & 0x0000001f) {
+ case 0:
+ case 1:
+ case 16:
+ case 17:
+ return 0;
+ case 2:
+ case 3:
+ case 18:
+ case 19:
+ return r->logon3.server_type;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ return r->logon5.server_type;
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ return r->logon13.server_type;
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ return r->logon15.server_type;
+ case 29:
+ case 30:
+ case 31:
+ return r->logon29.server_type;
+ default:
+ return 0;
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+#define RETURN_ON_FALSE(x) if (!x) return false;
+
+static bool check_cldap_reply_required_flags(uint32_t ret_flags,
+ uint32_t req_flags)
+{
+ if (ret_flags == 0) {
+ return true;
+ }
+
+ if (req_flags & DS_PDC_REQUIRED)
+ RETURN_ON_FALSE(ret_flags & NBT_SERVER_PDC);
+
+ if (req_flags & DS_GC_SERVER_REQUIRED)
+ RETURN_ON_FALSE(ret_flags & NBT_SERVER_GC);
+
+ if (req_flags & DS_ONLY_LDAP_NEEDED)
+ RETURN_ON_FALSE(ret_flags & NBT_SERVER_LDAP);
+
+ if ((req_flags & DS_DIRECTORY_SERVICE_REQUIRED) ||
+ (req_flags & DS_DIRECTORY_SERVICE_PREFERRED))
+ RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS);
+
+ if (req_flags & DS_KDC_REQUIRED)
+ RETURN_ON_FALSE(ret_flags & NBT_SERVER_KDC);
+
+ if (req_flags & DS_TIMESERV_REQUIRED)
+ RETURN_ON_FALSE(ret_flags & NBT_SERVER_TIMESERV);
+
+ if (req_flags & DS_WRITABLE_REQUIRED)
+ RETURN_ON_FALSE(ret_flags & NBT_SERVER_WRITABLE);
+
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS dsgetdcname_cache_fetch(TALLOC_CTX *mem_ctx,
+ const char *domain_name,
+ struct GUID *domain_guid,
+ uint32_t flags,
+ const char *site_name,
+ struct netr_DsRGetDCNameInfo **info_p,
+ bool *expired)
+{
+ char *key;
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ struct netr_DsRGetDCNameInfo *info;
+ union nbt_cldap_netlogon p;
+ struct nbt_cldap_netlogon_29 r;
+ NTSTATUS status;
+
+ if (!gencache_init()) {
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ key = dsgetdcname_cache_key(mem_ctx, domain_name);
+ if (!key) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!gencache_get_data_blob(key, &blob, expired)) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ info = TALLOC_ZERO_P(mem_ctx, struct netr_DsRGetDCNameInfo);
+ if (!info) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
+ (ndr_pull_flags_fn_t)ndr_pull_nbt_cldap_netlogon_29);
+
+ data_blob_free(&blob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ dsgetdcname_cache_delete(mem_ctx, domain_name);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ p.logon29 = r;
+
+ status = make_dc_info_from_cldap_reply(mem_ctx, flags, NULL,
+ 29,
+ &p, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(netr_DsRGetDCNameInfo, info);
+ }
+
+ /* check flags */
+ if (!check_cldap_reply_required_flags(info->dc_flags, flags)) {
+ DEBUG(10,("invalid flags\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if ((flags & DS_IP_REQUIRED) &&
+ (info->dc_address_type != DS_ADDRESS_TYPE_INET)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ *info_p = info;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS dsgetdcname_cached(TALLOC_CTX *mem_ctx,
+ struct messaging_context *msg_ctx,
+ const char *domain_name,
+ struct GUID *domain_guid,
+ uint32_t flags,
+ const char *site_name,
+ struct netr_DsRGetDCNameInfo **info)
+{
+ NTSTATUS status;
+ bool expired = false;
+
+ status = dsgetdcname_cache_fetch(mem_ctx, domain_name, domain_guid,
+ flags, site_name, info, &expired);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("dsgetdcname_cached: cache fetch failed with: %s\n",
+ nt_errstr(status)));
+ return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+ }
+
+ if (flags & DS_BACKGROUND_ONLY) {
+ return status;
+ }
+
+ if (expired) {
+ status = dsgetdcname_cache_refresh(mem_ctx, msg_ctx,
+ domain_name,
+ domain_guid, flags,
+ site_name, *info);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool check_allowed_required_flags(uint32_t flags,
+ const char *site_name)
+{
+ uint32_t return_type = flags & (DS_RETURN_FLAT_NAME|DS_RETURN_DNS_NAME);
+ uint32_t offered_type = flags & (DS_IS_FLAT_NAME|DS_IS_DNS_NAME);
+ uint32_t query_type = flags & (DS_BACKGROUND_ONLY|DS_FORCE_REDISCOVERY);
+
+ /* FIXME: check for DSGETDC_VALID_FLAGS and check for excluse bits
+ * (DS_PDC_REQUIRED, DS_KDC_REQUIRED, DS_GC_SERVER_REQUIRED) */
+
+ debug_dsdcinfo_flags(10, flags);
+
+ if ((flags & DS_TRY_NEXTCLOSEST_SITE) && site_name) {
+ return false;
+ }
+
+ if (return_type == (DS_RETURN_FLAT_NAME|DS_RETURN_DNS_NAME)) {
+ return false;
+ }
+
+ if (offered_type == (DS_IS_DNS_NAME|DS_IS_FLAT_NAME)) {
+ return false;
+ }
+
+ if (query_type == (DS_BACKGROUND_ONLY|DS_FORCE_REDISCOVERY)) {
+ return false;
+ }
+
+#if 0
+ if ((flags & DS_RETURN_DNS_NAME) && (!(flags & DS_IP_REQUIRED))) {
+ printf("gd: here5 \n");
+ return false;
+ }
+#endif
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS discover_dc_netbios(TALLOC_CTX *mem_ctx,
+ const char *domain_name,
+ uint32_t flags,
+ struct ip_service_name **returned_dclist,
+ int *returned_count)
+{
+ NTSTATUS status;
+ enum nbt_name_type name_type = NBT_NAME_LOGON;
+ struct ip_service *iplist;
+ int i;
+ struct ip_service_name *dclist = NULL;
+ int count;
+
+ *returned_dclist = NULL;
+ *returned_count = 0;
+
+ if (lp_disable_netbios()) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ if (flags & DS_PDC_REQUIRED) {
+ name_type = NBT_NAME_PDC;
+ }
+
+ status = internal_resolve_name(domain_name, name_type, NULL,
+ &iplist, &count,
+ "lmhosts wins bcast");
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("discover_dc_netbios: failed to find DC\n"));
+ return status;
+ }
+
+ dclist = TALLOC_ZERO_ARRAY(mem_ctx, struct ip_service_name, count);
+ if (!dclist) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<count; i++) {
+
+ char addr[INET6_ADDRSTRLEN];
+ struct ip_service_name *r = &dclist[i];
+
+ print_sockaddr(addr, sizeof(addr),
+ &iplist[i].ss);
+
+ r->ss = iplist[i].ss;
+ r->port = iplist[i].port;
+ r->hostname = talloc_strdup(mem_ctx, addr);
+ if (!r->hostname) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ }
+
+ *returned_dclist = dclist;
+ *returned_count = count;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS discover_dc_dns(TALLOC_CTX *mem_ctx,
+ const char *domain_name,
+ struct GUID *domain_guid,
+ uint32_t flags,
+ const char *site_name,
+ struct ip_service_name **returned_dclist,
+ int *return_count)
+{
+ int i, j;
+ NTSTATUS status;
+ struct dns_rr_srv *dcs = NULL;
+ int numdcs = 0;
+ int numaddrs = 0;
+ struct ip_service_name *dclist = NULL;
+ int count = 0;
+
+ if (flags & DS_PDC_REQUIRED) {
+ status = ads_dns_query_pdc(mem_ctx, domain_name,
+ &dcs, &numdcs);
+ } else if (flags & DS_GC_SERVER_REQUIRED) {
+ status = ads_dns_query_gcs(mem_ctx, domain_name, site_name,
+ &dcs, &numdcs);
+ } else if (flags & DS_KDC_REQUIRED) {
+ status = ads_dns_query_kdcs(mem_ctx, domain_name, site_name,
+ &dcs, &numdcs);
+ } else if (flags & DS_DIRECTORY_SERVICE_REQUIRED) {
+ status = ads_dns_query_dcs(mem_ctx, domain_name, site_name,
+ &dcs, &numdcs);
+ } else if (domain_guid) {
+ status = ads_dns_query_dcs_guid(mem_ctx, domain_name,
+ domain_guid, &dcs, &numdcs);
+ } else {
+ status = ads_dns_query_dcs(mem_ctx, domain_name, site_name,
+ &dcs, &numdcs);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (numdcs == 0) {
+ return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+ }
+
+ for (i=0;i<numdcs;i++) {
+ numaddrs += MAX(dcs[i].num_ips,1);
+ }
+
+ dclist = TALLOC_ZERO_ARRAY(mem_ctx,
+ struct ip_service_name,
+ numaddrs);
+ if (!dclist) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* now unroll the list of IP addresses */
+
+ *return_count = 0;
+ i = 0;
+ j = 0;
+
+ while ((i < numdcs) && (count < numaddrs)) {
+
+ struct ip_service_name *r = &dclist[count];
+
+ r->port = dcs[count].port;
+ r->hostname = dcs[count].hostname;
+
+ /* If we don't have an IP list for a name, lookup it up */
+
+ if (!dcs[i].ss_s) {
+ interpret_string_addr(&r->ss, dcs[i].hostname, 0);
+ i++;
+ j = 0;
+ } else {
+ /* use the IP addresses from the SRV sresponse */
+
+ if (j >= dcs[i].num_ips) {
+ i++;
+ j = 0;
+ continue;
+ }
+
+ r->ss = dcs[i].ss_s[j];
+ j++;
+ }
+
+ /* make sure it is a valid IP. I considered checking the
+ * negative connection cache, but this is the wrong place for
+ * it. Maybe only as a hac. After think about it, if all of
+ * the IP addresses retuend from DNS are dead, what hope does a
+ * netbios name lookup have? The standard reason for falling
+ * back to netbios lookups is that our DNS server doesn't know
+ * anything about the DC's -- jerry */
+
+ if (!is_zero_addr(&r->ss)) {
+ count++;
+ continue;
+ }
+ }
+
+ *returned_dclist = dclist;
+ *return_count = count;
+
+ if (count > 0) {
+ return NT_STATUS_OK;
+ }
+
+ return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS make_domain_controller_info(TALLOC_CTX *mem_ctx,
+ const char *dc_unc,
+ const char *dc_address,
+ uint32_t dc_address_type,
+ const struct GUID *domain_guid,
+ const char *domain_name,
+ const char *forest_name,
+ uint32_t flags,
+ const char *dc_site_name,
+ const char *client_site_name,
+ struct netr_DsRGetDCNameInfo **info_out)
+{
+ struct netr_DsRGetDCNameInfo *info;
+
+ info = TALLOC_ZERO_P(mem_ctx, struct netr_DsRGetDCNameInfo);
+ NT_STATUS_HAVE_NO_MEMORY(info);
+
+ if (dc_unc) {
+ info->dc_unc = talloc_strdup(mem_ctx, dc_unc);
+ NT_STATUS_HAVE_NO_MEMORY(info->dc_unc);
+ }
+
+ if (dc_address) {
+ if (!(dc_address[0] == '\\' && dc_address[1] == '\\')) {
+ info->dc_address = talloc_asprintf(mem_ctx, "\\\\%s",
+ dc_address);
+ } else {
+ info->dc_address = talloc_strdup(mem_ctx, dc_address);
+ }
+ NT_STATUS_HAVE_NO_MEMORY(info->dc_address);
+ }
+
+ info->dc_address_type = dc_address_type;
+
+ if (domain_guid) {
+ info->domain_guid = *domain_guid;
+ }
+
+ if (domain_name) {
+ info->domain_name = talloc_strdup(mem_ctx, domain_name);
+ NT_STATUS_HAVE_NO_MEMORY(info->domain_name);
+ }
+
+ if (forest_name && *forest_name) {
+ info->forest_name = talloc_strdup(mem_ctx, forest_name);
+ NT_STATUS_HAVE_NO_MEMORY(info->forest_name);
+ flags |= DS_DNS_FOREST;
+ }
+
+ info->dc_flags = flags;
+
+ if (dc_site_name) {
+ info->dc_site_name = talloc_strdup(mem_ctx, dc_site_name);
+ NT_STATUS_HAVE_NO_MEMORY(info->dc_site_name);
+ }
+
+ if (client_site_name) {
+ info->client_site_name = talloc_strdup(mem_ctx,
+ client_site_name);
+ NT_STATUS_HAVE_NO_MEMORY(info->client_site_name);
+ }
+
+ *info_out = info;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static void map_dc_and_domain_names(uint32_t flags,
+ const char *dc_name,
+ const char *domain_name,
+ const char *dns_dc_name,
+ const char *dns_domain_name,
+ uint32_t *dc_flags,
+ const char **hostname_p,
+ const char **domain_p)
+{
+ switch (flags & 0xf0000000) {
+ case DS_RETURN_FLAT_NAME:
+ if (dc_name && domain_name &&
+ *dc_name && *domain_name) {
+ *hostname_p = dc_name;
+ *domain_p = domain_name;
+ break;
+ }
+ case DS_RETURN_DNS_NAME:
+ default:
+ if (dns_dc_name && dns_domain_name &&
+ *dns_dc_name && *dns_domain_name) {
+ *hostname_p = dns_dc_name;
+ *domain_p = dns_domain_name;
+ *dc_flags |= DS_DNS_DOMAIN | DS_DNS_CONTROLLER;
+ break;
+ }
+ if (dc_name && domain_name &&
+ *dc_name && *domain_name) {
+ *hostname_p = dc_name;
+ *domain_p = domain_name;
+ break;
+ }
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS make_dc_info_from_cldap_reply(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct sockaddr_storage *ss,
+ uint32_t nt_version,
+ union nbt_cldap_netlogon *r,
+ struct netr_DsRGetDCNameInfo **info)
+{
+ const char *dc_hostname = NULL;
+ const char *dc_domain_name = NULL;
+ const char *dc_address = NULL;
+ const char *dc_forest = NULL;
+ uint32_t dc_address_type = 0;
+ uint32_t dc_flags = 0;
+ struct GUID *dc_domain_guid = NULL;
+ const char *dc_server_site = NULL;
+ const char *dc_client_site = NULL;
+
+ char addr[INET6_ADDRSTRLEN];
+
+ if (ss) {
+ print_sockaddr(addr, sizeof(addr), ss);
+ dc_address = addr;
+ dc_address_type = DS_ADDRESS_TYPE_INET;
+ }
+
+ switch (nt_version & 0x0000001f) {
+ case 0:
+ case 1:
+ case 16:
+ case 17:
+ if (!ss) {
+ dc_address = r->logon1.pdc_name;
+ dc_address_type = DS_ADDRESS_TYPE_NETBIOS;
+ }
+
+ map_dc_and_domain_names(flags,
+ r->logon1.pdc_name,
+ r->logon1.domain_name,
+ NULL,
+ NULL,
+ &dc_flags,
+ &dc_hostname,
+ &dc_domain_name);
+
+ if (flags & DS_PDC_REQUIRED) {
+ dc_flags = NBT_SERVER_WRITABLE | NBT_SERVER_PDC;
+ }
+ break;
+ case 2:
+ case 3:
+ case 18:
+ case 19:
+ if (!ss) {
+ dc_address = r->logon3.pdc_ip;
+ dc_address_type = DS_ADDRESS_TYPE_INET;
+ }
+
+ map_dc_and_domain_names(flags,
+ r->logon3.pdc_name,
+ r->logon3.domain_name,
+ r->logon3.pdc_dns_name,
+ r->logon3.dns_domain,
+ &dc_flags,
+ &dc_hostname,
+ &dc_domain_name);
+
+ dc_flags |= r->logon3.server_type;
+ dc_forest = r->logon3.forest;
+ dc_domain_guid = &r->logon3.domain_uuid;
+
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ if (!ss) {
+ dc_address = r->logon5.pdc_name;
+ dc_address_type = DS_ADDRESS_TYPE_NETBIOS;
+ }
+
+ map_dc_and_domain_names(flags,
+ r->logon5.pdc_name,
+ r->logon5.domain,
+ r->logon5.pdc_dns_name,
+ r->logon5.dns_domain,
+ &dc_flags,
+ &dc_hostname,
+ &dc_domain_name);
+
+ dc_flags |= r->logon5.server_type;
+ dc_forest = r->logon5.forest;
+ dc_domain_guid = &r->logon5.domain_uuid;
+ dc_server_site = r->logon5.server_site;
+ dc_client_site = r->logon5.client_site;
+
+ break;
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ if (!ss) {
+ dc_address = r->logon13.dc_sock_addr.pdc_ip;
+ dc_address_type = DS_ADDRESS_TYPE_INET;
+ }
+
+ map_dc_and_domain_names(flags,
+ r->logon13.pdc_name,
+ r->logon13.domain,
+ r->logon13.pdc_dns_name,
+ r->logon13.dns_domain,
+ &dc_flags,
+ &dc_hostname,
+ &dc_domain_name);
+
+ dc_flags |= r->logon13.server_type;
+ dc_forest = r->logon13.forest;
+ dc_domain_guid = &r->logon13.domain_uuid;
+ dc_server_site = r->logon13.server_site;
+ dc_client_site = r->logon13.client_site;
+
+ break;
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ if (!ss) {
+ dc_address = r->logon15.pdc_name;
+ dc_address_type = DS_ADDRESS_TYPE_NETBIOS;
+ }
+
+ map_dc_and_domain_names(flags,
+ r->logon15.pdc_name,
+ r->logon15.domain,
+ r->logon15.pdc_dns_name,
+ r->logon15.dns_domain,
+ &dc_flags,
+ &dc_hostname,
+ &dc_domain_name);
+
+ dc_flags |= r->logon15.server_type;
+ dc_forest = r->logon15.forest;
+ dc_domain_guid = &r->logon15.domain_uuid;
+ dc_server_site = r->logon15.server_site;
+ dc_client_site = r->logon15.client_site;
+
+ break;
+ case 29:
+ case 30:
+ case 31:
+ if (!ss) {
+ dc_address = r->logon29.dc_sock_addr.pdc_ip;
+ dc_address_type = DS_ADDRESS_TYPE_INET;
+ }
+
+ map_dc_and_domain_names(flags,
+ r->logon29.pdc_name,
+ r->logon29.domain,
+ r->logon29.pdc_dns_name,
+ r->logon29.dns_domain,
+ &dc_flags,
+ &dc_hostname,
+ &dc_domain_name);
+
+ dc_flags |= r->logon29.server_type;
+ dc_forest = r->logon29.forest;
+ dc_domain_guid = &r->logon29.domain_uuid;
+ dc_server_site = r->logon29.server_site;
+ dc_client_site = r->logon29.client_site;
+
+ break;
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ return make_domain_controller_info(mem_ctx,
+ dc_hostname,
+ dc_address,
+ dc_address_type,
+ dc_domain_guid,
+ dc_domain_name,
+ dc_forest,
+ dc_flags,
+ dc_server_site,
+ dc_client_site,
+ info);
+}
+
+/****************************************************************
+****************************************************************/
+
+static uint32_t map_ds_flags_to_nt_version(uint32_t flags)
+{
+ uint32_t nt_version = 0;
+
+ if (flags & DS_PDC_REQUIRED) {
+ nt_version |= NETLOGON_VERSION_PDC;
+ }
+
+ if (flags & DS_GC_SERVER_REQUIRED) {
+ nt_version |= NETLOGON_VERSION_GC;
+ }
+
+ if (flags & DS_TRY_NEXTCLOSEST_SITE) {
+ nt_version |= NETLOGON_VERSION_WITH_CLOSEST_SITE;
+ }
+
+ if (flags & DS_IP_REQUIRED) {
+ nt_version |= NETLOGON_VERSION_IP;
+ }
+
+ return nt_version;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS process_dc_dns(TALLOC_CTX *mem_ctx,
+ const char *domain_name,
+ uint32_t flags,
+ struct ip_service_name *dclist,
+ int num_dcs,
+ struct netr_DsRGetDCNameInfo **info)
+{
+ int i = 0;
+ bool valid_dc = false;
+ union nbt_cldap_netlogon *r = NULL;
+ uint32_t nt_version = NETLOGON_VERSION_5 |
+ NETLOGON_VERSION_5EX;
+ uint32_t ret_flags = 0;
+ NTSTATUS status;
+
+ nt_version |= map_ds_flags_to_nt_version(flags);
+
+ for (i=0; i<num_dcs; i++) {
+
+ DEBUG(10,("LDAP ping to %s\n", dclist[i].hostname));
+
+ if (ads_cldap_netlogon(mem_ctx, dclist[i].hostname,
+ domain_name,
+ &nt_version,
+ &r))
+ {
+ ret_flags = get_cldap_reply_server_flags(r, nt_version);
+
+ if (check_cldap_reply_required_flags(ret_flags, flags)) {
+ valid_dc = true;
+ break;
+ }
+ }
+
+ continue;
+ }
+
+ if (!valid_dc) {
+ return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+ }
+
+ status = make_dc_info_from_cldap_reply(mem_ctx, flags, &dclist[i].ss,
+ nt_version, r, info);
+ if (NT_STATUS_IS_OK(status)) {
+ return store_cldap_reply(mem_ctx, flags, &dclist[i].ss,
+ nt_version, r);
+ }
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+static struct event_context *ev_context(void)
+{
+ static struct event_context *ctx;
+
+ if (!ctx && !(ctx = event_context_init(NULL))) {
+ smb_panic("Could not init event context");
+ }
+ return ctx;
+}
+
+/****************************************************************
+****************************************************************/
+
+static struct messaging_context *msg_context(TALLOC_CTX *mem_ctx)
+{
+ static struct messaging_context *ctx;
+
+ if (!ctx && !(ctx = messaging_init(mem_ctx, server_id_self(),
+ ev_context()))) {
+ smb_panic("Could not init messaging context");
+ }
+ return ctx;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS process_dc_netbios(TALLOC_CTX *mem_ctx,
+ struct messaging_context *msg_ctx,
+ const char *domain_name,
+ uint32_t flags,
+ struct ip_service_name *dclist,
+ int num_dcs,
+ struct netr_DsRGetDCNameInfo **info)
+{
+ struct sockaddr_storage ss;
+ struct ip_service ip_list;
+ enum nbt_name_type name_type = NBT_NAME_LOGON;
+ NTSTATUS status;
+ int i;
+ const char *dc_name = NULL;
+ fstring tmp_dc_name;
+ union nbt_cldap_netlogon *r = NULL;
+ bool store_cache = false;
+ uint32_t nt_version = NETLOGON_VERSION_1 |
+ NETLOGON_VERSION_5 |
+ NETLOGON_VERSION_5EX_WITH_IP;
+
+ if (!msg_ctx) {
+ msg_ctx = msg_context(mem_ctx);
+ }
+
+ if (flags & DS_PDC_REQUIRED) {
+ name_type = NBT_NAME_PDC;
+ }
+
+ nt_version |= map_ds_flags_to_nt_version(flags);
+
+ DEBUG(10,("process_dc_netbios\n"));
+
+ for (i=0; i<num_dcs; i++) {
+
+ ip_list.ss = dclist[i].ss;
+ ip_list.port = 0;
+
+ if (!interpret_string_addr(&ss, dclist[i].hostname, AI_NUMERICHOST)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (send_getdc_request(mem_ctx, msg_ctx,
+ &dclist[i].ss, domain_name,
+ NULL, nt_version))
+ {
+ int k;
+ smb_msleep(300);
+ for (k=0; k<5; k++) {
+ if (receive_getdc_response(mem_ctx,
+ &dclist[i].ss,
+ domain_name,
+ &nt_version,
+ &dc_name,
+ &r)) {
+ store_cache = true;
+ namecache_store(dc_name, NBT_NAME_SERVER, 1, &ip_list);
+ goto make_reply;
+ }
+ smb_msleep(1500);
+ }
+ }
+
+ if (name_status_find(domain_name,
+ name_type,
+ NBT_NAME_SERVER,
+ &dclist[i].ss,
+ tmp_dc_name))
+ {
+ struct nbt_cldap_netlogon_1 logon1;
+
+ r = TALLOC_ZERO_P(mem_ctx, union nbt_cldap_netlogon);
+ NT_STATUS_HAVE_NO_MEMORY(r);
+
+ ZERO_STRUCT(logon1);
+
+ nt_version = NETLOGON_VERSION_1;
+
+ logon1.nt_version = nt_version;
+ logon1.pdc_name = tmp_dc_name;
+ logon1.domain_name = talloc_strdup_upper(mem_ctx, domain_name);
+ NT_STATUS_HAVE_NO_MEMORY(logon1.domain_name);
+
+ r->logon1 = logon1;
+
+ namecache_store(tmp_dc_name, NBT_NAME_SERVER, 1, &ip_list);
+
+ goto make_reply;
+ }
+ }
+
+ return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+
+ make_reply:
+
+ status = make_dc_info_from_cldap_reply(mem_ctx, flags, &dclist[i].ss,
+ nt_version, r, info);
+ if (NT_STATUS_IS_OK(status) && store_cache) {
+ return store_cldap_reply(mem_ctx, flags, &dclist[i].ss,
+ nt_version, r);
+ }
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS dsgetdcname_rediscover(TALLOC_CTX *mem_ctx,
+ struct messaging_context *msg_ctx,
+ const char *domain_name,
+ struct GUID *domain_guid,
+ uint32_t flags,
+ const char *site_name,
+ struct netr_DsRGetDCNameInfo **info)
+{
+ NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+ struct ip_service_name *dclist = NULL;
+ int num_dcs;
+
+ DEBUG(10,("dsgetdcname_rediscover\n"));
+
+ if (flags & DS_IS_FLAT_NAME) {
+
+ status = discover_dc_netbios(mem_ctx, domain_name, flags,
+ &dclist, &num_dcs);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ return process_dc_netbios(mem_ctx, msg_ctx, domain_name, flags,
+ dclist, num_dcs, info);
+ }
+
+ if (flags & DS_IS_DNS_NAME) {
+
+ status = discover_dc_dns(mem_ctx, domain_name, domain_guid,
+ flags, site_name, &dclist, &num_dcs);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ return process_dc_dns(mem_ctx, domain_name, flags,
+ dclist, num_dcs, info);
+ }
+
+ status = discover_dc_dns(mem_ctx, domain_name, domain_guid, flags,
+ site_name, &dclist, &num_dcs);
+
+ if (NT_STATUS_IS_OK(status) && num_dcs != 0) {
+
+ status = process_dc_dns(mem_ctx, domain_name, flags, dclist,
+ num_dcs, info);
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ status = discover_dc_netbios(mem_ctx, domain_name, flags, &dclist,
+ &num_dcs);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ return process_dc_netbios(mem_ctx, msg_ctx, domain_name, flags, dclist,
+ num_dcs, info);
+}
+
+/********************************************************************
+ dsgetdcname.
+
+ This will be the only public function here.
+********************************************************************/
+
+NTSTATUS dsgetdcname(TALLOC_CTX *mem_ctx,
+ struct messaging_context *msg_ctx,
+ const char *domain_name,
+ struct GUID *domain_guid,
+ const char *site_name,
+ uint32_t flags,
+ struct netr_DsRGetDCNameInfo **info)
+{
+ NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+ struct netr_DsRGetDCNameInfo *myinfo = NULL;
+ char *query_site = NULL;
+
+ DEBUG(10,("dsgetdcname: domain_name: %s, "
+ "domain_guid: %s, site_name: %s, flags: 0x%08x\n",
+ domain_name,
+ domain_guid ? GUID_string(mem_ctx, domain_guid) : "(null)",
+ site_name, flags));
+
+ *info = NULL;
+
+ if (!check_allowed_required_flags(flags, site_name)) {
+ DEBUG(0,("invalid flags specified\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!site_name) {
+ query_site = sitename_fetch(domain_name);
+ } else {
+ query_site = SMB_STRDUP(site_name);
+ }
+
+ if (flags & DS_FORCE_REDISCOVERY) {
+ goto rediscover;
+ }
+
+ status = dsgetdcname_cached(mem_ctx, msg_ctx, domain_name, domain_guid,
+ flags, query_site, &myinfo);
+ if (NT_STATUS_IS_OK(status)) {
+ *info = myinfo;
+ goto done;
+ }
+
+ if (flags & DS_BACKGROUND_ONLY) {
+ goto done;
+ }
+
+ rediscover:
+ status = dsgetdcname_rediscover(mem_ctx, msg_ctx, domain_name,
+ domain_guid, flags, query_site,
+ &myinfo);
+
+ if (NT_STATUS_IS_OK(status)) {
+ *info = myinfo;
+ }
+
+ done:
+ SAFE_FREE(query_site);
+
+ return status;
+}
diff --git a/source3/libsmb/errormap.c b/source3/libsmb/errormap.c
new file mode 100644
index 0000000000..4ec30f7e17
--- /dev/null
+++ b/source3/libsmb/errormap.c
@@ -0,0 +1,1609 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * error mapping functions
+ * Copyright (C) Andrew Tridgell 2001
+ * Copyright (C) Andrew Bartlett 2001
+ * Copyright (C) Tim Potter 2000
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/* This map was extracted by the ERRMAPEXTRACT smbtorture command.
+ The setup was a Samba HEAD (2002-01-03) PDC and an Win2k member
+ workstation. The PDC was modified (by using the 'name_to_nt_status'
+ authentication module) to convert the username (in hex) into the
+ corresponding NTSTATUS error return.
+
+ By opening two nbt sessions to the Win2k workstation, one negotiating
+ DOS and one negotiating NT errors it was possible to extract the
+ error mapping. (Because the server only supplies NT errors, the
+ NT4 workstation had to use its own error tables to convert these
+ to dos errors).
+
+ Some errors show up as 'squashed' because the NT error connection
+ got back a different error to the one it sent, so a mapping could
+ not be determined (a guess has been made in this case, to map the
+ error as squashed). This is done mainly to prevent users from getting
+ NT_STATUS_WRONG_PASSWORD and NT_STATUS_NO_SUCH_USER errors (they get
+ NT_STATUS_LOGON_FAILURE instead.
+
+ -- abartlet (2002-01-03)
+*/
+
+/* NT status -> dos error map */
+static const struct {
+ uint8 dos_class;
+ uint32 dos_code;
+ NTSTATUS ntstatus;
+} ntstatus_to_dos_map[] = {
+ {ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL},
+ {ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED},
+ {ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS},
+ {ERRDOS, 24, NT_STATUS_INFO_LENGTH_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS_ACCESS_VIOLATION},
+ {ERRHRD, ERRgeneral, NT_STATUS_IN_PAGE_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA},
+ {ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_INITIAL_STACK},
+ {ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC},
+ {ERRDOS, 87, NT_STATUS_INVALID_CID},
+ {ERRHRD, ERRgeneral, NT_STATUS_TIMER_NOT_CANCELED},
+ {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER},
+ {ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_DEVICE},
+ {ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE},
+ {ERRDOS, ERRbadfunc, NT_STATUS_INVALID_DEVICE_REQUEST},
+ {ERRDOS, 38, NT_STATUS_END_OF_FILE},
+ {ERRDOS, 34, NT_STATUS_WRONG_VOLUME},
+ {ERRDOS, 21, NT_STATUS_NO_MEDIA_IN_DEVICE},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_MEDIA},
+ {ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR},
+/** Session setup succeeded. This shouldn't happen...*/
+/** Session setup succeeded. This shouldn't happen...*/
+/** NT error on DOS connection! (NT_STATUS_OK) */
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_MORE_PROCESSING_REQUIRED to NT_STATUS_OK
+ during the session setup }
+*/
+#if 0
+ {SUCCESS, 0, NT_STATUS_OK},
+#endif
+ {ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY},
+ {ERRDOS, 487, NT_STATUS_CONFLICTING_ADDRESSES},
+ {ERRDOS, 487, NT_STATUS_NOT_MAPPED_VIEW},
+ {ERRDOS, 87, NT_STATUS_UNABLE_TO_FREE_VM},
+ {ERRDOS, 87, NT_STATUS_UNABLE_TO_DELETE_SECTION},
+ {ERRDOS, 2142, NT_STATUS_INVALID_SYSTEM_SERVICE},
+ {ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_INSTRUCTION},
+ {ERRDOS, ERRnoaccess, NT_STATUS_INVALID_LOCK_SEQUENCE},
+ {ERRDOS, ERRnoaccess, NT_STATUS_INVALID_VIEW_SIZE},
+ {ERRDOS, 193, NT_STATUS_INVALID_FILE_FOR_SECTION},
+ {ERRDOS, ERRnoaccess, NT_STATUS_ALREADY_COMMITTED},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_ACCESS_DENIED to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE
+ during the session setup }
+*/
+ {ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED},
+ {ERRDOS, 111, NT_STATUS_BUFFER_TOO_SMALL},
+/*
+ * Not an official error, as only bit 0x80000000, not bits 0xC0000000 are set.
+ */
+ {ERRDOS, ERRmoredata, STATUS_BUFFER_OVERFLOW},
+ {ERRDOS, ERRnofiles, STATUS_NO_MORE_FILES},
+ {ERRDOS, ERRbadfid, NT_STATUS_OBJECT_TYPE_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS_NONCONTINUABLE_EXCEPTION},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_DISPOSITION},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNWIND},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_STACK},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_UNWIND_TARGET},
+ {ERRDOS, 158, NT_STATUS_NOT_LOCKED},
+ {ERRHRD, ERRgeneral, NT_STATUS_PARITY_ERROR},
+ {ERRDOS, 487, NT_STATUS_UNABLE_TO_DECOMMIT_VM},
+ {ERRDOS, 487, NT_STATUS_NOT_COMMITTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_PORT_ATTRIBUTES},
+ {ERRHRD, ERRgeneral, NT_STATUS_PORT_MESSAGE_TOO_LONG},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_MIX},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_QUOTA_LOWER},
+ {ERRHRD, ERRgeneral, NT_STATUS_DISK_CORRUPT_ERROR},
+ {ERRDOS, ERRinvalidname, NT_STATUS_OBJECT_NAME_INVALID},
+ {ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND},
+ {ERRDOS, 183, NT_STATUS_OBJECT_NAME_COLLISION},
+ {ERRHRD, ERRgeneral, NT_STATUS_HANDLE_NOT_WAITABLE},
+ {ERRDOS, ERRbadfid, NT_STATUS_PORT_DISCONNECTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_ALREADY_ATTACHED},
+ {ERRDOS, ERRinvalidpath, NT_STATUS_OBJECT_PATH_INVALID},
+ {ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND},
+ {ERRDOS, ERRinvalidpath, NT_STATUS_OBJECT_PATH_SYNTAX_BAD},
+ {ERRHRD, ERRgeneral, NT_STATUS_DATA_OVERRUN},
+ {ERRHRD, ERRgeneral, NT_STATUS_DATA_LATE_ERROR},
+ {ERRDOS, 23, NT_STATUS_DATA_ERROR},
+ {ERRDOS, 23, NT_STATUS_CRC_ERROR},
+ {ERRDOS, ERRnomem, NT_STATUS_SECTION_TOO_BIG},
+ {ERRDOS, ERRnoaccess, NT_STATUS_PORT_CONNECTION_REFUSED},
+ {ERRDOS, ERRbadfid, NT_STATUS_INVALID_PORT_HANDLE},
+ {ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION},
+ {ERRHRD, ERRgeneral, NT_STATUS_QUOTA_EXCEEDED},
+ {ERRDOS, 87, NT_STATUS_INVALID_PAGE_PROTECTION},
+ {ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED},
+ {ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
+ {ERRDOS, 87, NT_STATUS_PORT_ALREADY_SET},
+ {ERRDOS, 87, NT_STATUS_SECTION_NOT_IMAGE},
+ {ERRDOS, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED},
+ {ERRDOS, ERRnoaccess, NT_STATUS_THREAD_IS_TERMINATING},
+ {ERRDOS, 87, NT_STATUS_BAD_WORKING_SET_LIMIT},
+ {ERRDOS, 87, NT_STATUS_INCOMPATIBLE_FILE_MAP},
+ {ERRDOS, 87, NT_STATUS_SECTION_PROTECTION},
+ {ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED},
+ {ERRDOS, 255, NT_STATUS_EA_TOO_LARGE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_EAS_ON_FILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_EA_CORRUPT_ERROR},
+ {ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT},
+ {ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED},
+ {ERRDOS, ERRnoaccess, NT_STATUS_DELETE_PENDING},
+ {ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNKNOWN_REVISION},
+ {ERRHRD, ERRgeneral, NT_STATUS_REVISION_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_OWNER},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_PRIMARY_GROUP},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_IMPERSONATION_TOKEN},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANT_DISABLE_MANDATORY},
+ {ERRDOS, 2215, NT_STATUS_NO_LOGON_SERVERS},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_LOGON_SESSION},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PRIVILEGE},
+ {ERRDOS, ERRnoaccess, NT_STATUS_PRIVILEGE_NOT_HELD},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACCOUNT_NAME},
+ {ERRHRD, ERRgeneral, NT_STATUS_USER_EXISTS},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE
+ during the session setup }
+*/
+ {ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER},
+ {ERRHRD, ERRgeneral, NT_STATUS_GROUP_EXISTS},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_GROUP},
+ {ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_GROUP},
+ {ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_GROUP},
+ {ERRHRD, ERRgeneral, NT_STATUS_LAST_ADMIN},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_WRONG_PASSWORD to NT_STATUS_LOGON_FAILURE
+ during the session setup }
+*/
+ {ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD},
+ {ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_PASSWORD},
+ {ERRHRD, ERRgeneral, NT_STATUS_PASSWORD_RESTRICTION},
+ {ERRDOS, ERRnoaccess, NT_STATUS_LOGON_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION},
+ {ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS},
+ {ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION},
+ {ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED},
+ {ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_LUIDS_EXHAUSTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_SUB_AUTHORITY},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACL},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_SID},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_SECURITY_DESCR},
+ {ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_FORMAT},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_TOKEN},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_INHERITANCE_ACL},
+ {ERRDOS, 158, NT_STATUS_RANGE_NOT_LOCKED},
+ {ERRDOS, 112, NT_STATUS_DISK_FULL},
+ {ERRHRD, ERRgeneral, NT_STATUS_SERVER_DISABLED},
+ {ERRHRD, ERRgeneral, NT_STATUS_SERVER_NOT_DISABLED},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED},
+ {ERRDOS, 259, NT_STATUS_GUIDS_EXHAUSTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ID_AUTHORITY},
+ {ERRDOS, 259, NT_STATUS_AGENTS_EXHAUSTED},
+ {ERRDOS, 154, NT_STATUS_INVALID_VOLUME_LABEL},
+ {ERRDOS, ERRres, NT_STATUS_SECTION_NOT_EXTENDED},
+ {ERRDOS, 487, NT_STATUS_NOT_MAPPED_DATA},
+ {ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_DATA_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_TYPE_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_NAME_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_ARRAY_BOUNDS_EXCEEDED},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DENORMAL_OPERAND},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DIVIDE_BY_ZERO},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INEXACT_RESULT},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INVALID_OPERATION},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_OVERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_STACK_CHECK},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_UNDERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_INTEGER_DIVIDE_BY_ZERO},
+ {ERRDOS, 534, NT_STATUS_INTEGER_OVERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_PRIVILEGED_INSTRUCTION},
+ {ERRDOS, ERRnomem, NT_STATUS_TOO_MANY_PAGING_FILES},
+ {ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID},
+ {ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_INSUFFICIENT_RESOURCES to NT_STATUS_INSUFF_SERVER_RESOURCES
+ during the session setup }
+*/
+ {ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES},
+ {ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND},
+ {ERRDOS, 23, NT_STATUS_DEVICE_DATA_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_CONNECTED},
+ {ERRDOS, 21, NT_STATUS_DEVICE_POWER_FAILURE},
+ {ERRDOS, 487, NT_STATUS_FREE_VM_NOT_AT_BASE},
+ {ERRDOS, 487, NT_STATUS_MEMORY_NOT_ALLOCATED},
+ {ERRHRD, ERRgeneral, NT_STATUS_WORKING_SET_QUOTA},
+ {ERRDOS, 19, NT_STATUS_MEDIA_WRITE_PROTECTED},
+ {ERRDOS, 21, NT_STATUS_DEVICE_NOT_READY},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_GROUP_ATTRIBUTES},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_IMPERSONATION_LEVEL},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANT_OPEN_ANONYMOUS},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_VALIDATION_CLASS},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_TOKEN_TYPE},
+ {ERRDOS, 87, NT_STATUS_BAD_MASTER_BOOT_RECORD},
+ {ERRHRD, ERRgeneral, NT_STATUS_INSTRUCTION_MISALIGNMENT},
+ {ERRDOS, ERRpipebusy, NT_STATUS_INSTANCE_NOT_AVAILABLE},
+ {ERRDOS, ERRpipebusy, NT_STATUS_PIPE_NOT_AVAILABLE},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PIPE_STATE},
+ {ERRDOS, ERRpipebusy, NT_STATUS_PIPE_BUSY},
+ {ERRDOS, ERRbadfunc, NT_STATUS_ILLEGAL_FUNCTION},
+ {ERRDOS, ERRnotconnected, NT_STATUS_PIPE_DISCONNECTED},
+ {ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_CLOSING},
+ {ERRHRD, ERRgeneral, NT_STATUS_PIPE_CONNECTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_PIPE_LISTENING},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_READ_MODE},
+ {ERRDOS, 121, NT_STATUS_IO_TIMEOUT},
+ {ERRDOS, 38, NT_STATUS_FILE_FORCED_CLOSED},
+ {ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STARTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STOPPED},
+ {ERRHRD, ERRgeneral, NT_STATUS_COULD_NOT_INTERPRET},
+ {ERRDOS, ERRnoaccess, NT_STATUS_FILE_IS_A_DIRECTORY},
+ {ERRDOS, ERRunsup, NT_STATUS_NOT_SUPPORTED},
+ {ERRDOS, 51, NT_STATUS_REMOTE_NOT_LISTENING},
+ {ERRDOS, 52, NT_STATUS_DUPLICATE_NAME},
+ {ERRDOS, 53, NT_STATUS_BAD_NETWORK_PATH},
+ {ERRDOS, 54, NT_STATUS_NETWORK_BUSY},
+ {ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST},
+ {ERRDOS, 56, NT_STATUS_TOO_MANY_COMMANDS},
+ {ERRDOS, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR},
+ {ERRDOS, 58, NT_STATUS_INVALID_NETWORK_RESPONSE},
+ {ERRDOS, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR},
+ {ERRDOS, 60, NT_STATUS_BAD_REMOTE_ADAPTER},
+ {ERRDOS, 61, NT_STATUS_PRINT_QUEUE_FULL},
+ {ERRDOS, 62, NT_STATUS_NO_SPOOL_SPACE},
+ {ERRDOS, 63, NT_STATUS_PRINT_CANCELLED},
+ {ERRDOS, 64, NT_STATUS_NETWORK_NAME_DELETED},
+ {ERRDOS, 65, NT_STATUS_NETWORK_ACCESS_DENIED},
+ {ERRDOS, 66, NT_STATUS_BAD_DEVICE_TYPE},
+ {ERRDOS, ERRnosuchshare, NT_STATUS_BAD_NETWORK_NAME},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_NAMES},
+ {ERRDOS, 69, NT_STATUS_TOO_MANY_SESSIONS},
+ {ERRDOS, 70, NT_STATUS_SHARING_PAUSED},
+ {ERRDOS, 71, NT_STATUS_REQUEST_NOT_ACCEPTED},
+ {ERRDOS, 72, NT_STATUS_REDIRECTOR_PAUSED},
+ {ERRDOS, 88, NT_STATUS_NET_WRITE_FAULT},
+ {ERRHRD, ERRgeneral, NT_STATUS_PROFILING_AT_LIMIT},
+ {ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE},
+ {ERRDOS, ERRnoaccess, NT_STATUS_FILE_RENAMED},
+ {ERRDOS, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SECURITY_ON_OBJECT},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANT_WAIT},
+ {ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_EMPTY},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANT_ACCESS_DOMAIN_INFO},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANT_TERMINATE_SELF},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_SERVER_STATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_STATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_ROLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_DOMAIN},
+ {ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_EXISTS},
+ {ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_LIMIT_EXCEEDED},
+ {ERRDOS, 300, NT_STATUS_OPLOCK_NOT_GRANTED},
+ {ERRDOS, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL},
+ {ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_CORRUPTION},
+ {ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_GENERIC_NOT_MAPPED},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_DESCRIPTOR_FORMAT},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_USER_BUFFER},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_IO_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_CREATE_ERR},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_MAP_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_EXTEND_ERR},
+ {ERRHRD, ERRgeneral, NT_STATUS_NOT_LOGON_PROCESS},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_EXISTS},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_1},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_2},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_3},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_4},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_5},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_6},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_7},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_8},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_9},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_10},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_11},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_12},
+ {ERRDOS, ERRbadpath, NT_STATUS_REDIRECTOR_NOT_STARTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_REDIRECTOR_STARTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PACKAGE},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_FUNCTION_TABLE},
+ {ERRDOS, 203, NT_STATUS(0xc0000100)},
+ {ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {ERRHRD, ERRgeneral, NT_STATUS_FILE_CORRUPT_ERROR},
+ {ERRDOS, ERRbaddirectory, NT_STATUS_NOT_A_DIRECTORY},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_LOGON_SESSION_STATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_COLLISION},
+ {ERRDOS, 206, NT_STATUS_NAME_TOO_LONG},
+ {ERRDOS, 2401, NT_STATUS_FILES_OPEN},
+ {ERRDOS, 2404, NT_STATUS_CONNECTION_IN_USE},
+ {ERRHRD, ERRgeneral, NT_STATUS_MESSAGE_NOT_FOUND},
+ {ERRDOS, ERRnoaccess, NT_STATUS_PROCESS_IS_TERMINATING},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LOGON_TYPE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_GUID_TRANSLATION},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANNOT_IMPERSONATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_IMAGE_ALREADY_LOADED},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_PRESENT},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_NOT_EXIST},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_ALREADY_OWNED},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_LID_OWNER},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_COMMAND},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_LID},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_SELECTOR},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_LDT},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_SIZE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_OFFSET},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_DESCRIPTOR},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NE_FORMAT},
+ {ERRHRD, ERRgeneral, NT_STATUS_RXACT_INVALID_STATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_RXACT_COMMIT_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_MAPPED_FILE_SIZE_ZERO},
+ {ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANCELLED},
+ {ERRDOS, ERRnoaccess, NT_STATUS_CANNOT_DELETE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_COMPUTER_NAME},
+ {ERRDOS, ERRnoaccess, NT_STATUS_FILE_DELETED},
+ {ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_ACCOUNT},
+ {ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_GROUP},
+ {ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_USER},
+ {ERRHRD, ERRgeneral, NT_STATUS_MEMBERS_PRIMARY_GROUP},
+ {ERRDOS, ERRbadfid, NT_STATUS_FILE_CLOSED},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_THREADS},
+ {ERRHRD, ERRgeneral, NT_STATUS_THREAD_NOT_IN_PROCESS},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOKEN_ALREADY_IN_USE},
+ {ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA_EXCEEDED},
+ {ERRHRD, ERRgeneral, NT_STATUS_COMMITMENT_LIMIT},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_LE_FORMAT},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NOT_MZ},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_PROTECT},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_WIN_16},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGON_SERVER_CONFLICT},
+ {ERRHRD, ERRgeneral, NT_STATUS_TIME_DIFFERENCE_AT_DC},
+ {ERRHRD, ERRgeneral, NT_STATUS_SYNCHRONIZATION_REQUIRED},
+ {ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_OPEN_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_IO_PRIVILEGE_FAILED},
+ {ERRDOS, 182, NT_STATUS_ORDINAL_NOT_FOUND},
+ {ERRDOS, 127, NT_STATUS_ENTRYPOINT_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONTROL_C_EXIT},
+ {ERRDOS, 64, NT_STATUS_LOCAL_DISCONNECT},
+ {ERRDOS, 64, NT_STATUS_REMOTE_DISCONNECT},
+ {ERRDOS, 51, NT_STATUS_REMOTE_RESOURCES},
+ {ERRDOS, 59, NT_STATUS_LINK_FAILED},
+ {ERRDOS, 59, NT_STATUS_LINK_TIMEOUT},
+ {ERRDOS, 59, NT_STATUS_INVALID_CONNECTION},
+ {ERRDOS, 59, NT_STATUS_INVALID_ADDRESS},
+ {ERRHRD, ERRgeneral, NT_STATUS_DLL_INIT_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_MISSING_SYSTEMFILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNHANDLED_EXCEPTION},
+ {ERRHRD, ERRgeneral, NT_STATUS_APP_INIT_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_CREATE_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_PAGEFILE},
+ {ERRDOS, ERRunknownlevel, NT_STATUS_INVALID_LEVEL},
+ {ERRDOS, 86, NT_STATUS_WRONG_PASSWORD_CORE},
+ {ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_FLOAT_CONTEXT},
+ {ERRDOS, 109, NT_STATUS_PIPE_BROKEN},
+ {ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_CORRUPT},
+ {ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_IO_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_EVENT_PAIR},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_VOLUME},
+ {ERRHRD, ERRgeneral, NT_STATUS_SERIAL_NO_DEVICE_INITED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_ALIAS},
+ {ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_ALIAS},
+ {ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_ALIAS},
+ {ERRHRD, ERRgeneral, NT_STATUS_ALIAS_EXISTS},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGON_NOT_GRANTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SECRETS},
+ {ERRHRD, ERRgeneral, NT_STATUS_SECRET_TOO_LONG},
+ {ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_FULLSCREEN_MODE},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_CONTEXT_IDS},
+ {ERRDOS, ERRnoaccess, NT_STATUS_LOGON_TYPE_NOT_GRANTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NOT_REGISTRY_FILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED},
+ {ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_FT_MISSING_MEMBER},
+ {ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_SERVICE_ENTRY},
+ {ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_CHARACTER},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNMAPPABLE_CHARACTER},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNDEFINED_CHARACTER},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_VOLUME},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_WRONG_CYLINDER},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_UNKNOWN_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_BAD_REGISTERS},
+ {ERRHRD, ERRgeneral, NT_STATUS_DISK_RECALIBRATE_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_DISK_OPERATION_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_DISK_RESET_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_SHARED_IRQ_BUSY},
+ {ERRHRD, ERRgeneral, NT_STATUS_FT_ORPHANING},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000016e)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000016f)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc0000170)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc0000171)},
+ {ERRHRD, ERRgeneral, NT_STATUS_PARTITION_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_BLOCK_LENGTH},
+ {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_PARTITIONED},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_LOCK_MEDIA},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_UNLOAD_MEDIA},
+ {ERRHRD, ERRgeneral, NT_STATUS_EOM_OVERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_MEDIA},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc0000179)},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_MEMBER},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_MEMBER},
+ {ERRHRD, ERRgeneral, NT_STATUS_KEY_DELETED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_LOG_SPACE},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SIDS},
+ {ERRHRD, ERRgeneral, NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED},
+ {ERRHRD, ERRgeneral, NT_STATUS_KEY_HAS_CHILDREN},
+ {ERRHRD, ERRgeneral, NT_STATUS_CHILD_MUST_BE_VOLATILE},
+ {ERRDOS, 87, NT_STATUS_DEVICE_CONFIGURATION_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_DRIVER_INTERNAL_ERROR},
+ {ERRDOS, 22, NT_STATUS_INVALID_DEVICE_STATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_PROTOCOL_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_BACKUP_CONTROLLER},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOG_FILE_FULL},
+ {ERRDOS, 19, NT_STATUS_TOO_LATE},
+ {ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_NO_TRUST_SAM_ACCOUNT to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE
+ during the session setup }
+*/
+ {ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT},
+ {ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE},
+ {ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CORRUPT},
+ {ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_CANT_START},
+ {ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED},
+ {ERRDOS, ERRinvgroup, NT_STATUS_NETLOGON_NOT_STARTED},
+ {ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED},
+ {ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK},
+ {ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT},
+ {ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT},
+ {ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CHANGED},
+ {ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT},
+ {ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT},
+ {ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_DOMAIN_TRUST_INCONSISTENT to NT_STATUS_LOGON_FAILURE
+ during the session setup }
+*/
+ {ERRDOS, ERRnoaccess, NT_STATUS_DOMAIN_TRUST_INCONSISTENT},
+ {ERRHRD, ERRgeneral, NT_STATUS_FS_DRIVER_REQUIRED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_USER_SESSION_KEY},
+ {ERRDOS, 59, NT_STATUS_USER_SESSION_DELETED},
+ {ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_LANG_NOT_FOUND},
+ {ERRDOS, ERRnomem, NT_STATUS_INSUFF_SERVER_RESOURCES},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_BUFFER_SIZE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_COMPONENT},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_WILDCARD},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_ADDRESSES},
+ {ERRDOS, 52, NT_STATUS_ADDRESS_ALREADY_EXISTS},
+ {ERRDOS, 64, NT_STATUS_ADDRESS_CLOSED},
+ {ERRDOS, 64, NT_STATUS_CONNECTION_DISCONNECTED},
+ {ERRDOS, 64, NT_STATUS_CONNECTION_RESET},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_NODES},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_ABORTED},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_TIMED_OUT},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_NO_RELEASE},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_NO_MATCH},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_RESPONDED},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_ID},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_TYPE},
+ {ERRDOS, ERRunsup, NT_STATUS_NOT_SERVER_SESSION},
+ {ERRDOS, ERRunsup, NT_STATUS_NOT_CLIENT_SESSION},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANNOT_LOAD_REGISTRY_FILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_DEBUG_ATTACH_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_SYSTEM_PROCESS_TERMINATED},
+ {ERRHRD, ERRgeneral, NT_STATUS_DATA_NOT_ACCEPTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_BROWSER_SERVERS_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_VDM_HARD_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_DRIVER_CANCEL_TIMEOUT},
+ {ERRHRD, ERRgeneral, NT_STATUS_REPLY_MESSAGE_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS_MAPPED_ALIGNMENT},
+ {ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA},
+ {ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID},
+ {ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM},
+ {ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW_READ},
+ {ERRHRD, ERRgeneral, NT_STATUS_FAIL_CHECK},
+ {ERRHRD, ERRgeneral, NT_STATUS_DUPLICATE_OBJECTID},
+ {ERRHRD, ERRgeneral, NT_STATUS_OBJECTID_EXISTS},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONVERT_TO_LARGE},
+ {ERRHRD, ERRgeneral, NT_STATUS_RETRY},
+ {ERRHRD, ERRgeneral, NT_STATUS_FOUND_OUT_OF_SCOPE},
+ {ERRHRD, ERRgeneral, NT_STATUS_ALLOCATE_BUCKET},
+ {ERRHRD, ERRgeneral, NT_STATUS_PROPSET_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_MARSHALL_OVERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_VARIANT},
+ {ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND},
+ {ERRDOS, ERRnoaccess, NT_STATUS_ACCOUNT_LOCKED_OUT},
+ {ERRDOS, ERRbadfid, NT_STATUS_HANDLE_NOT_CLOSABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_REFUSED},
+ {ERRHRD, ERRgeneral, NT_STATUS_GRACEFUL_DISCONNECT},
+ {ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED},
+ {ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_NOT_ASSOCIATED},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_INVALID},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ACTIVE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NETWORK_UNREACHABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_HOST_UNREACHABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_PROTOCOL_UNREACHABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_PORT_UNREACHABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_REQUEST_ABORTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ABORTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_COMPRESSION_BUFFER},
+ {ERRHRD, ERRgeneral, NT_STATUS_USER_MAPPED_FILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_AUDIT_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_TIMER_RESOLUTION_NOT_SET},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_COUNT_LIMIT},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGIN_TIME_RESTRICTION},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGIN_WKSTA_RESTRICTION},
+ {ERRDOS, 193, NT_STATUS_IMAGE_MP_UP_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024a)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024b)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024c)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024d)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024e)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024f)},
+ {ERRHRD, ERRgeneral, NT_STATUS_INSUFFICIENT_LOGON_INFO},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_DLL_ENTRYPOINT},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_SERVICE_ENTRYPOINT},
+ {ERRHRD, ERRgeneral, NT_STATUS_LPC_REPLY_LOST},
+ {ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT1},
+ {ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT2},
+ {ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_QUOTA_LIMIT},
+ {ERRSRV, ERRbadtype, NT_STATUS_PATH_NOT_COVERED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_CALLBACK_ACTIVE},
+ {ERRHRD, ERRgeneral, NT_STATUS_LICENSE_QUOTA_EXCEEDED},
+ {ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_SHORT},
+ {ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_RECENT},
+ {ERRHRD, ERRgeneral, NT_STATUS_PWD_HISTORY_CONFLICT},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000025d)},
+ {ERRHRD, ERRgeneral, NT_STATUS_PLUGPLAY_NO_DEVICE},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNSUPPORTED_COMPRESSION},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_HW_PROFILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH},
+ {ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND},
+ {ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND},
+ {ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LINKS},
+ {ERRHRD, ERRgeneral, NT_STATUS_QUOTA_LIST_INCONSISTENT},
+ {ERRHRD, ERRgeneral, NT_STATUS_FILE_IS_OFFLINE},
+ {ERRDOS, 21, NT_STATUS(0xc000026e)},
+ {ERRDOS, 161, NT_STATUS(0xc0000281)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc000028a)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc000028b)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000028c)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc000028d)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc000028e)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc000028f)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc0000290)},
+ {ERRDOS, ERRbadfunc, NT_STATUS(0xc000029c)},
+};
+
+
+/* dos -> nt status error map */
+static const struct {
+ uint8 dos_class;
+ uint32 dos_code;
+ NTSTATUS ntstatus;
+} dos_to_ntstatus_map[] = {
+ {ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED},
+ {ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE},
+ {ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND},
+ {ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES},
+ {ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED},
+ {ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE},
+ {ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES},
+ {ERRDOS, ERRbadaccess, NT_STATUS_ACCESS_DENIED},
+ {ERRDOS, ERRbaddata, NT_STATUS_DATA_ERROR},
+ {ERRDOS, 14, NT_STATUS_SECTION_NOT_EXTENDED},
+ {ERRDOS, ERRremcd, NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE},
+ {ERRDOS, ERRnofiles, STATUS_NO_MORE_FILES},
+ {ERRDOS, 19, NT_STATUS_MEDIA_WRITE_PROTECTED},
+ {ERRDOS, 21, NT_STATUS_NO_MEDIA_IN_DEVICE},
+ {ERRDOS, 22, NT_STATUS_INVALID_DEVICE_STATE},
+ {ERRDOS, 23, NT_STATUS_DATA_ERROR},
+ {ERRDOS, 24, NT_STATUS_DATA_ERROR},
+ {ERRDOS, 26, NT_STATUS_DISK_CORRUPT_ERROR},
+ {ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR},
+ {ERRDOS, 28, NT_STATUS(0x8000000e)},
+ {ERRDOS, 31, NT_STATUS_UNSUCCESSFUL},
+ {ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION},
+ {ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT},
+ {ERRDOS, 34, NT_STATUS_WRONG_VOLUME},
+ {ERRDOS, 38, NT_STATUS_END_OF_FILE},
+ {ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED},
+ {ERRDOS, 51, NT_STATUS_REMOTE_NOT_LISTENING},
+ {ERRDOS, 52, NT_STATUS_DUPLICATE_NAME},
+ {ERRDOS, 53, NT_STATUS_BAD_NETWORK_PATH},
+ {ERRDOS, 54, NT_STATUS_NETWORK_BUSY},
+ {ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST},
+ {ERRDOS, 56, NT_STATUS_TOO_MANY_COMMANDS},
+ {ERRDOS, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR},
+ {ERRDOS, 58, NT_STATUS_INVALID_NETWORK_RESPONSE},
+ {ERRDOS, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR},
+ {ERRDOS, 60, NT_STATUS_BAD_REMOTE_ADAPTER},
+ {ERRDOS, 61, NT_STATUS_PRINT_QUEUE_FULL},
+ {ERRDOS, 62, NT_STATUS_NO_SPOOL_SPACE},
+ {ERRDOS, 63, NT_STATUS_PRINT_CANCELLED},
+ {ERRDOS, 64, NT_STATUS_NETWORK_NAME_DELETED},
+ {ERRDOS, 65, NT_STATUS_NETWORK_ACCESS_DENIED},
+ {ERRDOS, 66, NT_STATUS_BAD_DEVICE_TYPE},
+ {ERRDOS, ERRnosuchshare, NT_STATUS_BAD_NETWORK_NAME},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED},
+ {ERRDOS, 69, NT_STATUS_TOO_MANY_SESSIONS},
+ {ERRDOS, 70, NT_STATUS_SHARING_PAUSED},
+ {ERRDOS, 71, NT_STATUS_REQUEST_NOT_ACCEPTED},
+ {ERRDOS, 72, NT_STATUS_REDIRECTOR_PAUSED},
+ {ERRDOS, ERRfilexists, NT_STATUS_OBJECT_NAME_COLLISION},
+ {ERRDOS, 86, NT_STATUS_WRONG_PASSWORD},
+ {ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS},
+ {ERRDOS, 88, NT_STATUS_NET_WRITE_FAULT},
+ {ERRDOS, 109, NT_STATUS_PIPE_BROKEN},
+ {ERRDOS, 111, STATUS_MORE_ENTRIES},
+ {ERRDOS, 112, NT_STATUS_DISK_FULL},
+ {ERRDOS, 121, NT_STATUS_IO_TIMEOUT},
+ {ERRDOS, 122, NT_STATUS_BUFFER_TOO_SMALL},
+ {ERRDOS, ERRinvalidname, NT_STATUS_OBJECT_NAME_INVALID},
+ {ERRDOS, ERRunknownlevel, NT_STATUS_INVALID_LEVEL},
+ {ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND},
+ {ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND},
+ {ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {ERRDOS, 154, NT_STATUS_INVALID_VOLUME_LABEL},
+ {ERRDOS, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED},
+ {ERRDOS, 158, NT_STATUS_NOT_LOCKED},
+ {ERRDOS, 161, NT_STATUS_OBJECT_PATH_INVALID},
+ {ERRDOS, 170, NT_STATUS(0x80000011)},
+ {ERRDOS, 182, NT_STATUS_ORDINAL_NOT_FOUND},
+ {ERRDOS, 183, NT_STATUS_OBJECT_NAME_COLLISION},
+ {ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC},
+ {ERRDOS, 203, NT_STATUS(0xc0000100)},
+ {ERRDOS, 206, NT_STATUS_NAME_TOO_LONG},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_INFO_CLASS},
+ {ERRDOS, ERRpipebusy, NT_STATUS_INSTANCE_NOT_AVAILABLE},
+ {ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_CLOSING},
+ {ERRDOS, ERRnotconnected, NT_STATUS_PIPE_DISCONNECTED},
+ {ERRDOS, ERRmoredata, NT_STATUS_MORE_PROCESSING_REQUIRED},
+ {ERRDOS, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED},
+ {ERRDOS, 254, NT_STATUS(0x80000013)},
+ {ERRDOS, 255, NT_STATUS_EA_TOO_LARGE},
+ {ERRDOS, 259, NT_STATUS_GUIDS_EXHAUSTED},
+ {ERRDOS, 267, NT_STATUS_NOT_A_DIRECTORY},
+ {ERRDOS, 275, NT_STATUS_EA_TOO_LARGE},
+ {ERRDOS, 276, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRDOS, 277, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRDOS, 278, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED},
+ {ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED},
+ {ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
+ {ERRDOS, 299, NT_STATUS(0x8000000d)},
+ {ERRDOS, 300, NT_STATUS_OPLOCK_NOT_GRANTED},
+ {ERRDOS, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL},
+ {ERRDOS, 487, NT_STATUS_CONFLICTING_ADDRESSES},
+ {ERRDOS, 534, NT_STATUS_INTEGER_OVERFLOW},
+ {ERRDOS, 535, NT_STATUS_PIPE_CONNECTED},
+ {ERRDOS, 536, NT_STATUS_PIPE_LISTENING},
+ {ERRDOS, 995, NT_STATUS_CANCELLED},
+ {ERRDOS, 997, NT_STATUS(0x00000103)},
+ {ERRDOS, 998, NT_STATUS_ACCESS_VIOLATION},
+ {ERRDOS, 999, NT_STATUS_IN_PAGE_ERROR},
+ {ERRDOS, 1001, NT_STATUS_BAD_INITIAL_STACK},
+ {ERRDOS, 1005, NT_STATUS_UNRECOGNIZED_VOLUME},
+ {ERRDOS, 1006, NT_STATUS_FILE_INVALID},
+ {ERRDOS, 1007, NT_STATUS_FULLSCREEN_MODE},
+ {ERRDOS, 1008, NT_STATUS_NO_TOKEN},
+ {ERRDOS, 1009, NT_STATUS_REGISTRY_CORRUPT},
+ {ERRDOS, 1016, NT_STATUS_REGISTRY_IO_FAILED},
+ {ERRDOS, 1017, NT_STATUS_NOT_REGISTRY_FILE},
+ {ERRDOS, 1018, NT_STATUS_KEY_DELETED},
+ {ERRDOS, 1019, NT_STATUS_NO_LOG_SPACE},
+ {ERRDOS, 1020, NT_STATUS_KEY_HAS_CHILDREN},
+ {ERRDOS, 1021, NT_STATUS_CHILD_MUST_BE_VOLATILE},
+ {ERRDOS, 1022, NT_STATUS(0x0000010c)},
+ {ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD},
+ {ERRSRV, ERRbadtype, NT_STATUS_BAD_DEVICE_TYPE},
+ {ERRSRV, ERRaccess, NT_STATUS_NETWORK_ACCESS_DENIED},
+ {ERRSRV, ERRinvnid, NT_STATUS_NETWORK_NAME_DELETED},
+ {ERRSRV, ERRinvnetname, NT_STATUS_BAD_NETWORK_NAME},
+ {ERRSRV, ERRinvdevice, NT_STATUS_BAD_DEVICE_TYPE},
+ {ERRSRV, ERRqfull, NT_STATUS_PRINT_QUEUE_FULL},
+ {ERRSRV, ERRqtoobig, NT_STATUS_NO_SPOOL_SPACE},
+ {ERRSRV, ERRinvpfid, NT_STATUS_PRINT_CANCELLED},
+ {ERRSRV, ERRsmbcmd, NT_STATUS_NOT_IMPLEMENTED},
+ {ERRSRV, ERRbadpermits, NT_STATUS_NETWORK_ACCESS_DENIED},
+ {ERRSRV, ERRpaused, NT_STATUS_SHARING_PAUSED},
+ {ERRSRV, ERRmsgoff, NT_STATUS_REQUEST_NOT_ACCEPTED},
+ {ERRSRV, ERRnoroom, NT_STATUS_DISK_FULL},
+ {ERRSRV, ERRnoresource, NT_STATUS_REQUEST_NOT_ACCEPTED},
+ {ERRSRV, ERRtoomanyuids, NT_STATUS_TOO_MANY_SESSIONS},
+ {ERRSRV, 123, NT_STATUS_OBJECT_NAME_INVALID},
+ {ERRSRV, 206, NT_STATUS_OBJECT_NAME_INVALID},
+ {ERRHRD, 1, NT_STATUS_NOT_IMPLEMENTED},
+ {ERRHRD, 2, NT_STATUS_NO_SUCH_DEVICE},
+ {ERRHRD, 3, NT_STATUS_OBJECT_PATH_NOT_FOUND},
+ {ERRHRD, 4, NT_STATUS_TOO_MANY_OPENED_FILES},
+ {ERRHRD, 5, NT_STATUS_INVALID_LOCK_SEQUENCE},
+ {ERRHRD, 6, NT_STATUS_INVALID_HANDLE},
+ {ERRHRD, 8, NT_STATUS_INSUFFICIENT_RESOURCES},
+ {ERRHRD, 12, NT_STATUS_INVALID_LOCK_SEQUENCE},
+ {ERRHRD, 13, NT_STATUS_DATA_ERROR},
+ {ERRHRD, 14, NT_STATUS_SECTION_NOT_EXTENDED},
+ {ERRHRD, 16, NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {ERRHRD, 17, NT_STATUS_NOT_SAME_DEVICE},
+ {ERRHRD, 18, NT_STATUS(0x80000006)},
+ {ERRHRD, ERRnowrite, NT_STATUS_MEDIA_WRITE_PROTECTED},
+ {ERRHRD, ERRnotready, NT_STATUS_NO_MEDIA_IN_DEVICE},
+ {ERRHRD, ERRbadcmd, NT_STATUS_INVALID_DEVICE_STATE},
+ {ERRHRD, ERRdata, NT_STATUS_DATA_ERROR},
+ {ERRHRD, ERRbadreq, NT_STATUS_DATA_ERROR},
+ {ERRHRD, ERRbadmedia, NT_STATUS_DISK_CORRUPT_ERROR},
+ {ERRHRD, ERRbadsector, NT_STATUS_NONEXISTENT_SECTOR},
+ {ERRHRD, ERRnopaper, NT_STATUS(0x8000000e)},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNSUCCESSFUL},
+ {ERRHRD, ERRbadshare, NT_STATUS_SHARING_VIOLATION},
+ {ERRHRD, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT},
+ {ERRHRD, ERRwrongdisk, NT_STATUS_WRONG_VOLUME},
+ {ERRHRD, 38, NT_STATUS_END_OF_FILE},
+ {ERRHRD, ERRdiskfull, NT_STATUS_DISK_FULL},
+ {ERRHRD, 50, NT_STATUS_CTL_FILE_NOT_SUPPORTED},
+ {ERRHRD, 51, NT_STATUS_REMOTE_NOT_LISTENING},
+ {ERRHRD, 52, NT_STATUS_DUPLICATE_NAME},
+ {ERRHRD, 53, NT_STATUS_BAD_NETWORK_PATH},
+ {ERRHRD, 54, NT_STATUS_NETWORK_BUSY},
+ {ERRHRD, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST},
+ {ERRHRD, 56, NT_STATUS_TOO_MANY_COMMANDS},
+ {ERRHRD, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR},
+ {ERRHRD, 58, NT_STATUS_INVALID_NETWORK_RESPONSE},
+ {ERRHRD, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR},
+ {ERRHRD, 60, NT_STATUS_BAD_REMOTE_ADAPTER},
+ {ERRHRD, 61, NT_STATUS_PRINT_QUEUE_FULL},
+ {ERRHRD, 62, NT_STATUS_NO_SPOOL_SPACE},
+ {ERRHRD, 63, NT_STATUS_PRINT_CANCELLED},
+ {ERRHRD, 64, NT_STATUS_NETWORK_NAME_DELETED},
+ {ERRHRD, 65, NT_STATUS_NETWORK_ACCESS_DENIED},
+ {ERRHRD, 66, NT_STATUS_BAD_DEVICE_TYPE},
+ {ERRHRD, 67, NT_STATUS_BAD_NETWORK_NAME},
+ {ERRHRD, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED},
+ {ERRHRD, 69, NT_STATUS_TOO_MANY_SESSIONS},
+ {ERRHRD, 70, NT_STATUS_SHARING_PAUSED},
+ {ERRHRD, 71, NT_STATUS_REQUEST_NOT_ACCEPTED},
+ {ERRHRD, 72, NT_STATUS_REDIRECTOR_PAUSED},
+ {ERRHRD, 80, NT_STATUS_OBJECT_NAME_COLLISION},
+ {ERRHRD, 86, NT_STATUS_WRONG_PASSWORD},
+ {ERRHRD, 87, NT_STATUS_INVALID_INFO_CLASS},
+ {ERRHRD, 88, NT_STATUS_NET_WRITE_FAULT},
+ {ERRHRD, 109, NT_STATUS_PIPE_BROKEN},
+ {ERRHRD, 111, STATUS_MORE_ENTRIES},
+ {ERRHRD, 112, NT_STATUS_DISK_FULL},
+ {ERRHRD, 121, NT_STATUS_IO_TIMEOUT},
+ {ERRHRD, 122, NT_STATUS_BUFFER_TOO_SMALL},
+ {ERRHRD, 123, NT_STATUS_OBJECT_NAME_INVALID},
+ {ERRHRD, 124, NT_STATUS_INVALID_LEVEL},
+ {ERRHRD, 126, NT_STATUS_DLL_NOT_FOUND},
+ {ERRHRD, 127, NT_STATUS_PROCEDURE_NOT_FOUND},
+ {ERRHRD, 145, NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {ERRHRD, 154, NT_STATUS_INVALID_VOLUME_LABEL},
+ {ERRHRD, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED},
+ {ERRHRD, 158, NT_STATUS_NOT_LOCKED},
+ {ERRHRD, 161, NT_STATUS_OBJECT_PATH_INVALID},
+ {ERRHRD, 170, NT_STATUS(0x80000011)},
+ {ERRHRD, 182, NT_STATUS_ORDINAL_NOT_FOUND},
+ {ERRHRD, 183, NT_STATUS_OBJECT_NAME_COLLISION},
+ {ERRHRD, 193, NT_STATUS_BAD_INITIAL_PC},
+ {ERRHRD, 203, NT_STATUS(0xc0000100)},
+ {ERRHRD, 206, NT_STATUS_NAME_TOO_LONG},
+ {ERRHRD, 230, NT_STATUS_INVALID_INFO_CLASS},
+ {ERRHRD, 231, NT_STATUS_INSTANCE_NOT_AVAILABLE},
+ {ERRHRD, 232, NT_STATUS_PIPE_CLOSING},
+ {ERRHRD, 233, NT_STATUS_PIPE_DISCONNECTED},
+ {ERRHRD, 234, STATUS_MORE_ENTRIES},
+ {ERRHRD, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED},
+ {ERRHRD, 254, NT_STATUS(0x80000013)},
+ {ERRHRD, 255, NT_STATUS_EA_TOO_LARGE},
+ {ERRHRD, 259, NT_STATUS_GUIDS_EXHAUSTED},
+ {ERRHRD, 267, NT_STATUS_NOT_A_DIRECTORY},
+ {ERRHRD, 275, NT_STATUS_EA_TOO_LARGE},
+ {ERRHRD, 276, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRHRD, 277, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRHRD, 278, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRHRD, 282, NT_STATUS_EAS_NOT_SUPPORTED},
+ {ERRHRD, 288, NT_STATUS_MUTANT_NOT_OWNED},
+ {ERRHRD, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
+ {ERRHRD, 299, NT_STATUS(0x8000000d)},
+ {ERRHRD, 300, NT_STATUS_OPLOCK_NOT_GRANTED},
+ {ERRHRD, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL},
+ {ERRHRD, 487, NT_STATUS_CONFLICTING_ADDRESSES},
+ {ERRHRD, 534, NT_STATUS_INTEGER_OVERFLOW},
+ {ERRHRD, 535, NT_STATUS_PIPE_CONNECTED},
+ {ERRHRD, 536, NT_STATUS_PIPE_LISTENING},
+ {ERRHRD, 995, NT_STATUS_CANCELLED},
+ {ERRHRD, 997, NT_STATUS(0x00000103)},
+ {ERRHRD, 998, NT_STATUS_ACCESS_VIOLATION},
+ {ERRHRD, 999, NT_STATUS_IN_PAGE_ERROR},
+ {ERRHRD, 1001, NT_STATUS_BAD_INITIAL_STACK},
+ {ERRHRD, 1005, NT_STATUS_UNRECOGNIZED_VOLUME},
+ {ERRHRD, 1006, NT_STATUS_FILE_INVALID},
+ {ERRHRD, 1007, NT_STATUS_FULLSCREEN_MODE},
+ {ERRHRD, 1008, NT_STATUS_NO_TOKEN},
+ {ERRHRD, 1009, NT_STATUS_REGISTRY_CORRUPT},
+ {ERRHRD, 1016, NT_STATUS_REGISTRY_IO_FAILED},
+ {ERRHRD, 1017, NT_STATUS_NOT_REGISTRY_FILE},
+ {ERRHRD, 1018, NT_STATUS_KEY_DELETED},
+ {ERRHRD, 1019, NT_STATUS_NO_LOG_SPACE},
+ {ERRHRD, 1020, NT_STATUS_KEY_HAS_CHILDREN},
+ {ERRHRD, 1021, NT_STATUS_CHILD_MUST_BE_VOLATILE},
+ {ERRHRD, 1022, NT_STATUS(0x0000010c)},
+};
+
+/* errmap NTSTATUS->Win32 */
+static const struct {
+ NTSTATUS ntstatus;
+ WERROR werror;
+} ntstatus_to_werror_map[] = {
+ {NT_STATUS(0x103), W_ERROR(0x3e5)},
+ {NT_STATUS(0x105), W_ERROR(0xea)},
+ {NT_STATUS(0x106), W_ERROR(0x514)},
+ {NT_STATUS(0x107), W_ERROR(0x515)},
+ {NT_STATUS(0x10c), W_ERROR(0x3fe)},
+ {NT_STATUS(0x10d), W_ERROR(0x516)},
+ {NT_STATUS(0x121), W_ERROR(0x2009)},
+ {NT_STATUS(0xc0000001), W_ERROR(0x1f)},
+ {NT_STATUS(0xc0000002), W_ERROR(0x1)},
+ {NT_STATUS(0xc0000003), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000004), W_ERROR(0x18)},
+ {NT_STATUS(0xc0000005), W_ERROR(0x3e6)},
+ {NT_STATUS(0xc0000006), W_ERROR(0x3e7)},
+ {NT_STATUS(0xc0000007), W_ERROR(0x5ae)},
+ {NT_STATUS(0xc0000008), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000009), W_ERROR(0x3e9)},
+ {NT_STATUS(0xc000000a), W_ERROR(0xc1)},
+ {NT_STATUS(0xc000000b), W_ERROR(0x57)},
+ {NT_STATUS(0xc000000d), W_ERROR(0x57)},
+ {NT_STATUS(0xc000000e), W_ERROR(0x2)},
+ {NT_STATUS(0xc000000f), W_ERROR(0x2)},
+ {NT_STATUS(0xc0000010), W_ERROR(0x1)},
+ {NT_STATUS(0xc0000011), W_ERROR(0x26)},
+ {NT_STATUS(0xc0000012), W_ERROR(0x22)},
+ {NT_STATUS(0xc0000013), W_ERROR(0x15)},
+ {NT_STATUS(0xc0000014), W_ERROR(0x6f9)},
+ {NT_STATUS(0xc0000015), W_ERROR(0x1b)},
+ {NT_STATUS(0xc0000016), W_ERROR(0xea)},
+ {NT_STATUS(0xc0000017), W_ERROR(0x8)},
+ {NT_STATUS(0xc0000018), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc0000019), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc000001a), W_ERROR(0x57)},
+ {NT_STATUS(0xc000001b), W_ERROR(0x57)},
+ {NT_STATUS(0xc000001c), W_ERROR(0x1)},
+ {NT_STATUS(0xc000001d), W_ERROR(0xc000001d)},
+ {NT_STATUS(0xc000001e), W_ERROR(0x5)},
+ {NT_STATUS(0xc000001f), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000020), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000021), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000022), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000023), W_ERROR(0x7a)},
+ {NT_STATUS(0xc0000024), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000025), W_ERROR(0xc0000025)},
+ {NT_STATUS(0xc0000026), W_ERROR(0xc0000026)},
+ {NT_STATUS(0xc000002a), W_ERROR(0x9e)},
+ {NT_STATUS(0xc000002b), W_ERROR(0xc000002b)},
+ {NT_STATUS(0xc000002c), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc000002d), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc0000030), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000032), W_ERROR(0x571)},
+ {NT_STATUS(0xc0000033), W_ERROR(0x7b)},
+ {NT_STATUS(0xc0000034), W_ERROR(0x2)},
+ {NT_STATUS(0xc0000035), W_ERROR(0xb7)},
+ {NT_STATUS(0xc0000037), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000039), W_ERROR(0xa1)},
+ {NT_STATUS(0xc000003a), W_ERROR(0x3)},
+ {NT_STATUS(0xc000003b), W_ERROR(0xa1)},
+ {NT_STATUS(0xc000003c), W_ERROR(0x45d)},
+ {NT_STATUS(0xc000003d), W_ERROR(0x45d)},
+ {NT_STATUS(0xc000003e), W_ERROR(0x17)},
+ {NT_STATUS(0xc000003f), W_ERROR(0x17)},
+ {NT_STATUS(0xc0000040), W_ERROR(0x8)},
+ {NT_STATUS(0xc0000041), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000042), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000043), W_ERROR(0x20)},
+ {NT_STATUS(0xc0000044), W_ERROR(0x718)},
+ {NT_STATUS(0xc0000045), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000046), W_ERROR(0x120)},
+ {NT_STATUS(0xc0000047), W_ERROR(0x12a)},
+ {NT_STATUS(0xc0000048), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000049), W_ERROR(0x57)},
+ {NT_STATUS(0xc000004a), W_ERROR(0x9c)},
+ {NT_STATUS(0xc000004b), W_ERROR(0x5)},
+ {NT_STATUS(0xc000004c), W_ERROR(0x57)},
+ {NT_STATUS(0xc000004d), W_ERROR(0x57)},
+ {NT_STATUS(0xc000004e), W_ERROR(0x57)},
+ {NT_STATUS(0xc000004f), W_ERROR(0x11a)},
+ {NT_STATUS(0xc0000050), W_ERROR(0xff)},
+ {NT_STATUS(0xc0000051), W_ERROR(0x570)},
+ {NT_STATUS(0xc0000052), W_ERROR(0x570)},
+ {NT_STATUS(0xc0000053), W_ERROR(0x570)},
+ {NT_STATUS(0xc0000054), W_ERROR(0x21)},
+ {NT_STATUS(0xc0000055), W_ERROR(0x21)},
+ {NT_STATUS(0xc0000056), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000057), W_ERROR(0x32)},
+ {NT_STATUS(0xc0000058), W_ERROR(0x519)},
+ {NT_STATUS(0xc0000059), W_ERROR(0x51a)},
+ {NT_STATUS(0xc000005a), W_ERROR(0x51b)},
+ {NT_STATUS(0xc000005b), W_ERROR(0x51c)},
+ {NT_STATUS(0xc000005c), W_ERROR(0x51d)},
+ {NT_STATUS(0xc000005d), W_ERROR(0x51e)},
+ {NT_STATUS(0xc000005e), W_ERROR(0x51f)},
+ {NT_STATUS(0xc000005f), W_ERROR(0x520)},
+ {NT_STATUS(0xc0000060), W_ERROR(0x521)},
+ {NT_STATUS(0xc0000061), W_ERROR(0x522)},
+ {NT_STATUS(0xc0000062), W_ERROR(0x523)},
+ {NT_STATUS(0xc0000063), W_ERROR(0x524)},
+ {NT_STATUS(0xc0000064), W_ERROR(0x525)},
+ {NT_STATUS(0xc0000065), W_ERROR(0x526)},
+ {NT_STATUS(0xc0000066), W_ERROR(0x527)},
+ {NT_STATUS(0xc0000067), W_ERROR(0x528)},
+ {NT_STATUS(0xc0000068), W_ERROR(0x529)},
+ {NT_STATUS(0xc0000069), W_ERROR(0x52a)},
+ {NT_STATUS(0xc000006a), W_ERROR(0x56)},
+ {NT_STATUS(0xc000006b), W_ERROR(0x52c)},
+ {NT_STATUS(0xc000006c), W_ERROR(0x52d)},
+ {NT_STATUS(0xc000006d), W_ERROR(0x52e)},
+ {NT_STATUS(0xc000006e), W_ERROR(0x52f)},
+ {NT_STATUS(0xc000006f), W_ERROR(0x530)},
+ {NT_STATUS(0xc0000070), W_ERROR(0x531)},
+ {NT_STATUS(0xc0000071), W_ERROR(0x532)},
+ {NT_STATUS(0xc0000072), W_ERROR(0x533)},
+ {NT_STATUS(0xc0000073), W_ERROR(0x534)},
+ {NT_STATUS(0xc0000074), W_ERROR(0x535)},
+ {NT_STATUS(0xc0000075), W_ERROR(0x536)},
+ {NT_STATUS(0xc0000076), W_ERROR(0x537)},
+ {NT_STATUS(0xc0000077), W_ERROR(0x538)},
+ {NT_STATUS(0xc0000078), W_ERROR(0x539)},
+ {NT_STATUS(0xc0000079), W_ERROR(0x53a)},
+ {NT_STATUS(0xc000007a), W_ERROR(0x7f)},
+ {NT_STATUS(0xc000007b), W_ERROR(0xc1)},
+ {NT_STATUS(0xc000007c), W_ERROR(0x3f0)},
+ {NT_STATUS(0xc000007d), W_ERROR(0x53c)},
+ {NT_STATUS(0xc000007e), W_ERROR(0x9e)},
+ {NT_STATUS(0xc000007f), W_ERROR(0x70)},
+ {NT_STATUS(0xc0000080), W_ERROR(0x53d)},
+ {NT_STATUS(0xc0000081), W_ERROR(0x53e)},
+ {NT_STATUS(0xc0000082), W_ERROR(0x44)},
+ {NT_STATUS(0xc0000083), W_ERROR(0x103)},
+ {NT_STATUS(0xc0000084), W_ERROR(0x53f)},
+ {NT_STATUS(0xc0000085), W_ERROR(0x103)},
+ {NT_STATUS(0xc0000086), W_ERROR(0x9a)},
+ {NT_STATUS(0xc0000087), W_ERROR(0xe)},
+ {NT_STATUS(0xc0000088), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc0000089), W_ERROR(0x714)},
+ {NT_STATUS(0xc000008a), W_ERROR(0x715)},
+ {NT_STATUS(0xc000008b), W_ERROR(0x716)},
+ {NT_STATUS(0xc000008c), W_ERROR(0xc000008c)},
+ {NT_STATUS(0xc000008d), W_ERROR(0xc000008d)},
+ {NT_STATUS(0xc000008e), W_ERROR(0xc000008e)},
+ {NT_STATUS(0xc000008f), W_ERROR(0xc000008f)},
+ {NT_STATUS(0xc0000090), W_ERROR(0xc0000090)},
+ {NT_STATUS(0xc0000091), W_ERROR(0xc0000091)},
+ {NT_STATUS(0xc0000092), W_ERROR(0xc0000092)},
+ {NT_STATUS(0xc0000093), W_ERROR(0xc0000093)},
+ {NT_STATUS(0xc0000094), W_ERROR(0xc0000094)},
+ {NT_STATUS(0xc0000095), W_ERROR(0x216)},
+ {NT_STATUS(0xc0000096), W_ERROR(0xc0000096)},
+ {NT_STATUS(0xc0000097), W_ERROR(0x8)},
+ {NT_STATUS(0xc0000098), W_ERROR(0x3ee)},
+ {NT_STATUS(0xc0000099), W_ERROR(0x540)},
+ {NT_STATUS(0xc000009a), W_ERROR(0x5aa)},
+ {NT_STATUS(0xc000009b), W_ERROR(0x3)},
+ {NT_STATUS(0xc000009c), W_ERROR(0x17)},
+ {NT_STATUS(0xc000009d), W_ERROR(0x48f)},
+ {NT_STATUS(0xc000009e), W_ERROR(0x15)},
+ {NT_STATUS(0xc000009f), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc00000a0), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc00000a1), W_ERROR(0x5ad)},
+ {NT_STATUS(0xc00000a2), W_ERROR(0x13)},
+ {NT_STATUS(0xc00000a3), W_ERROR(0x15)},
+ {NT_STATUS(0xc00000a4), W_ERROR(0x541)},
+ {NT_STATUS(0xc00000a5), W_ERROR(0x542)},
+ {NT_STATUS(0xc00000a6), W_ERROR(0x543)},
+ {NT_STATUS(0xc00000a7), W_ERROR(0x544)},
+ {NT_STATUS(0xc00000a8), W_ERROR(0x545)},
+ {NT_STATUS(0xc00000a9), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000ab), W_ERROR(0xe7)},
+ {NT_STATUS(0xc00000ac), W_ERROR(0xe7)},
+ {NT_STATUS(0xc00000ad), W_ERROR(0xe6)},
+ {NT_STATUS(0xc00000ae), W_ERROR(0xe7)},
+ {NT_STATUS(0xc00000af), W_ERROR(0x1)},
+ {NT_STATUS(0xc00000b0), W_ERROR(0xe9)},
+ {NT_STATUS(0xc00000b1), W_ERROR(0xe8)},
+ {NT_STATUS(0xc00000b2), W_ERROR(0x217)},
+ {NT_STATUS(0xc00000b3), W_ERROR(0x218)},
+ {NT_STATUS(0xc00000b4), W_ERROR(0xe6)},
+ {NT_STATUS(0xc00000b5), W_ERROR(0x79)},
+ {NT_STATUS(0xc00000b6), W_ERROR(0x26)},
+ {NT_STATUS(0xc00000ba), W_ERROR(0x5)},
+ {NT_STATUS(0xc00000bb), W_ERROR(0x32)},
+ {NT_STATUS(0xc00000bc), W_ERROR(0x33)},
+ {NT_STATUS(0xc00000bd), W_ERROR(0x34)},
+ {NT_STATUS(0xc00000be), W_ERROR(0x35)},
+ {NT_STATUS(0xc00000bf), W_ERROR(0x36)},
+ {NT_STATUS(0xc00000c0), W_ERROR(0x37)},
+ {NT_STATUS(0xc00000c1), W_ERROR(0x38)},
+ {NT_STATUS(0xc00000c2), W_ERROR(0x39)},
+ {NT_STATUS(0xc00000c3), W_ERROR(0x3a)},
+ {NT_STATUS(0xc00000c4), W_ERROR(0x3b)},
+ {NT_STATUS(0xc00000c5), W_ERROR(0x3c)},
+ {NT_STATUS(0xc00000c6), W_ERROR(0x3d)},
+ {NT_STATUS(0xc00000c7), W_ERROR(0x3e)},
+ {NT_STATUS(0xc00000c8), W_ERROR(0x3f)},
+ {NT_STATUS(0xc00000c9), W_ERROR(0x40)},
+ {NT_STATUS(0xc00000ca), W_ERROR(0x41)},
+ {NT_STATUS(0xc00000cb), W_ERROR(0x42)},
+ {NT_STATUS(0xc00000cc), W_ERROR(0x43)},
+ {NT_STATUS(0xc00000cd), W_ERROR(0x44)},
+ {NT_STATUS(0xc00000ce), W_ERROR(0x45)},
+ {NT_STATUS(0xc00000cf), W_ERROR(0x46)},
+ {NT_STATUS(0xc00000d0), W_ERROR(0x47)},
+ {NT_STATUS(0xc00000d1), W_ERROR(0x48)},
+ {NT_STATUS(0xc00000d2), W_ERROR(0x58)},
+ {NT_STATUS(0xc00000d4), W_ERROR(0x11)},
+ {NT_STATUS(0xc00000d5), W_ERROR(0x5)},
+ {NT_STATUS(0xc00000d6), W_ERROR(0xf0)},
+ {NT_STATUS(0xc00000d7), W_ERROR(0x546)},
+ {NT_STATUS(0xc00000d9), W_ERROR(0xe8)},
+ {NT_STATUS(0xc00000da), W_ERROR(0x547)},
+ {NT_STATUS(0xc00000dc), W_ERROR(0x548)},
+ {NT_STATUS(0xc00000dd), W_ERROR(0x549)},
+ {NT_STATUS(0xc00000de), W_ERROR(0x54a)},
+ {NT_STATUS(0xc00000df), W_ERROR(0x54b)},
+ {NT_STATUS(0xc00000e0), W_ERROR(0x54c)},
+ {NT_STATUS(0xc00000e1), W_ERROR(0x54d)},
+ {NT_STATUS(0xc00000e2), W_ERROR(0x12c)},
+ {NT_STATUS(0xc00000e3), W_ERROR(0x12d)},
+ {NT_STATUS(0xc00000e4), W_ERROR(0x54e)},
+ {NT_STATUS(0xc00000e5), W_ERROR(0x54f)},
+ {NT_STATUS(0xc00000e6), W_ERROR(0x550)},
+ {NT_STATUS(0xc00000e7), W_ERROR(0x551)},
+ {NT_STATUS(0xc00000e8), W_ERROR(0x6f8)},
+ {NT_STATUS(0xc00000ed), W_ERROR(0x552)},
+ {NT_STATUS(0xc00000ee), W_ERROR(0x553)},
+ {NT_STATUS(0xc00000ef), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f0), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f1), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f2), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f3), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f4), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f5), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f6), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f7), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f8), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f9), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000fa), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000fb), W_ERROR(0x3)},
+ {NT_STATUS(0xc00000fd), W_ERROR(0x3e9)},
+ {NT_STATUS(0xc00000fe), W_ERROR(0x554)},
+ {NT_STATUS(0xc0000100), W_ERROR(0xcb)},
+ {NT_STATUS(0xc0000101), W_ERROR(0x91)},
+ {NT_STATUS(0xc0000102), W_ERROR(0x570)},
+ {NT_STATUS(0xc0000103), W_ERROR(0x10b)},
+ {NT_STATUS(0xc0000104), W_ERROR(0x555)},
+ {NT_STATUS(0xc0000105), W_ERROR(0x556)},
+ {NT_STATUS(0xc0000106), W_ERROR(0xce)},
+ {NT_STATUS(0xc0000107), W_ERROR(0x961)},
+ {NT_STATUS(0xc0000108), W_ERROR(0x964)},
+ {NT_STATUS(0xc000010a), W_ERROR(0x5)},
+ {NT_STATUS(0xc000010b), W_ERROR(0x557)},
+ {NT_STATUS(0xc000010d), W_ERROR(0x558)},
+ {NT_STATUS(0xc000010e), W_ERROR(0x420)},
+ {NT_STATUS(0xc0000117), W_ERROR(0x5a4)},
+ {NT_STATUS(0xc000011b), W_ERROR(0xc1)},
+ {NT_STATUS(0xc000011c), W_ERROR(0x559)},
+ {NT_STATUS(0xc000011d), W_ERROR(0x55a)},
+ {NT_STATUS(0xc000011e), W_ERROR(0x3ee)},
+ {NT_STATUS(0xc000011f), W_ERROR(0x4)},
+ {NT_STATUS(0xc0000120), W_ERROR(0x3e3)},
+ {NT_STATUS(0xc0000121), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000122), W_ERROR(0x4ba)},
+ {NT_STATUS(0xc0000123), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000124), W_ERROR(0x55b)},
+ {NT_STATUS(0xc0000125), W_ERROR(0x55c)},
+ {NT_STATUS(0xc0000126), W_ERROR(0x55d)},
+ {NT_STATUS(0xc0000127), W_ERROR(0x55e)},
+ {NT_STATUS(0xc0000128), W_ERROR(0x6)},
+ {NT_STATUS(0xc000012b), W_ERROR(0x55f)},
+ {NT_STATUS(0xc000012d), W_ERROR(0x5af)},
+ {NT_STATUS(0xc000012e), W_ERROR(0xc1)},
+ {NT_STATUS(0xc000012f), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000130), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000131), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000133), W_ERROR(0x576)},
+ {NT_STATUS(0xc0000135), W_ERROR(0x7e)},
+ {NT_STATUS(0xc0000138), W_ERROR(0xb6)},
+ {NT_STATUS(0xc0000139), W_ERROR(0x7f)},
+ {NT_STATUS(0xc000013b), W_ERROR(0x40)},
+ {NT_STATUS(0xc000013c), W_ERROR(0x40)},
+ {NT_STATUS(0xc000013d), W_ERROR(0x33)},
+ {NT_STATUS(0xc000013e), W_ERROR(0x3b)},
+ {NT_STATUS(0xc000013f), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000140), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000141), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000142), W_ERROR(0x45a)},
+ {NT_STATUS(0xc0000148), W_ERROR(0x7c)},
+ {NT_STATUS(0xc0000149), W_ERROR(0x56)},
+ {NT_STATUS(0xc000014b), W_ERROR(0x6d)},
+ {NT_STATUS(0xc000014c), W_ERROR(0x3f1)},
+ {NT_STATUS(0xc000014d), W_ERROR(0x3f8)},
+ {NT_STATUS(0xc000014f), W_ERROR(0x3ed)},
+ {NT_STATUS(0xc0000150), W_ERROR(0x45e)},
+ {NT_STATUS(0xc0000151), W_ERROR(0x560)},
+ {NT_STATUS(0xc0000152), W_ERROR(0x561)},
+ {NT_STATUS(0xc0000153), W_ERROR(0x562)},
+ {NT_STATUS(0xc0000154), W_ERROR(0x563)},
+ {NT_STATUS(0xc0000155), W_ERROR(0x564)},
+ {NT_STATUS(0xc0000156), W_ERROR(0x565)},
+ {NT_STATUS(0xc0000157), W_ERROR(0x566)},
+ {NT_STATUS(0xc0000158), W_ERROR(0x567)},
+ {NT_STATUS(0xc0000159), W_ERROR(0x3ef)},
+ {NT_STATUS(0xc000015a), W_ERROR(0x568)},
+ {NT_STATUS(0xc000015b), W_ERROR(0x569)},
+ {NT_STATUS(0xc000015c), W_ERROR(0x3f9)},
+ {NT_STATUS(0xc000015d), W_ERROR(0x56a)},
+ {NT_STATUS(0xc000015f), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000162), W_ERROR(0x459)},
+ {NT_STATUS(0xc0000165), W_ERROR(0x462)},
+ {NT_STATUS(0xc0000166), W_ERROR(0x463)},
+ {NT_STATUS(0xc0000167), W_ERROR(0x464)},
+ {NT_STATUS(0xc0000168), W_ERROR(0x465)},
+ {NT_STATUS(0xc0000169), W_ERROR(0x466)},
+ {NT_STATUS(0xc000016a), W_ERROR(0x467)},
+ {NT_STATUS(0xc000016b), W_ERROR(0x468)},
+ {NT_STATUS(0xc000016c), W_ERROR(0x45f)},
+ {NT_STATUS(0xc000016d), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000172), W_ERROR(0x451)},
+ {NT_STATUS(0xc0000173), W_ERROR(0x452)},
+ {NT_STATUS(0xc0000174), W_ERROR(0x453)},
+ {NT_STATUS(0xc0000175), W_ERROR(0x454)},
+ {NT_STATUS(0xc0000176), W_ERROR(0x455)},
+ {NT_STATUS(0xc0000177), W_ERROR(0x469)},
+ {NT_STATUS(0xc0000178), W_ERROR(0x458)},
+ {NT_STATUS(0xc000017a), W_ERROR(0x56b)},
+ {NT_STATUS(0xc000017b), W_ERROR(0x56c)},
+ {NT_STATUS(0xc000017c), W_ERROR(0x3fa)},
+ {NT_STATUS(0xc000017d), W_ERROR(0x3fb)},
+ {NT_STATUS(0xc000017e), W_ERROR(0x56d)},
+ {NT_STATUS(0xc000017f), W_ERROR(0x56e)},
+ {NT_STATUS(0xc0000180), W_ERROR(0x3fc)},
+ {NT_STATUS(0xc0000181), W_ERROR(0x3fd)},
+ {NT_STATUS(0xc0000182), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000183), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000184), W_ERROR(0x16)},
+ {NT_STATUS(0xc0000185), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000186), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000188), W_ERROR(0x5de)},
+ {NT_STATUS(0xc0000189), W_ERROR(0x13)},
+ {NT_STATUS(0xc000018a), W_ERROR(0x6fa)},
+ {NT_STATUS(0xc000018b), W_ERROR(0x6fb)},
+ {NT_STATUS(0xc000018c), W_ERROR(0x6fc)},
+ {NT_STATUS(0xc000018d), W_ERROR(0x6fd)},
+ {NT_STATUS(0xc000018e), W_ERROR(0x5dc)},
+ {NT_STATUS(0xc000018f), W_ERROR(0x5dd)},
+ {NT_STATUS(0xc0000190), W_ERROR(0x6fe)},
+ {NT_STATUS(0xc0000192), W_ERROR(0x700)},
+ {NT_STATUS(0xc0000193), W_ERROR(0x701)},
+ {NT_STATUS(0xc0000194), W_ERROR(0x46b)},
+ {NT_STATUS(0xc0000195), W_ERROR(0x4c3)},
+ {NT_STATUS(0xc0000196), W_ERROR(0x4c4)},
+ {NT_STATUS(0xc0000197), W_ERROR(0x5df)},
+ {NT_STATUS(0xc0000198), W_ERROR(0x70f)},
+ {NT_STATUS(0xc0000199), W_ERROR(0x710)},
+ {NT_STATUS(0xc000019a), W_ERROR(0x711)},
+ {NT_STATUS(0xc000019b), W_ERROR(0x712)},
+ {NT_STATUS(0xc0000202), W_ERROR(0x572)},
+ {NT_STATUS(0xc0000203), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000204), W_ERROR(0x717)},
+ {NT_STATUS(0xc0000205), W_ERROR(0x46a)},
+ {NT_STATUS(0xc0000206), W_ERROR(0x6f8)},
+ {NT_STATUS(0xc0000207), W_ERROR(0x4be)},
+ {NT_STATUS(0xc0000208), W_ERROR(0x4be)},
+ {NT_STATUS(0xc0000209), W_ERROR(0x44)},
+ {NT_STATUS(0xc000020a), W_ERROR(0x34)},
+ {NT_STATUS(0xc000020b), W_ERROR(0x40)},
+ {NT_STATUS(0xc000020c), W_ERROR(0x40)},
+ {NT_STATUS(0xc000020d), W_ERROR(0x40)},
+ {NT_STATUS(0xc000020e), W_ERROR(0x44)},
+ {NT_STATUS(0xc000020f), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000210), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000211), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000212), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000213), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000214), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000215), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000216), W_ERROR(0x32)},
+ {NT_STATUS(0xc0000217), W_ERROR(0x32)},
+ {NT_STATUS(0xc000021c), W_ERROR(0x17e6)},
+ {NT_STATUS(0xc0000220), W_ERROR(0x46c)},
+ {NT_STATUS(0xc0000221), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000224), W_ERROR(0x773)},
+ {NT_STATUS(0xc0000225), W_ERROR(0x490)},
+ {NT_STATUS(0xc000022a), W_ERROR(0xc000022a)},
+ {NT_STATUS(0xc000022b), W_ERROR(0xc000022b)},
+ {NT_STATUS(0xc000022d), W_ERROR(0x4d5)},
+ {NT_STATUS(0xc0000230), W_ERROR(0x492)},
+ {NT_STATUS(0xc0000233), W_ERROR(0x774)},
+ {NT_STATUS(0xc0000234), W_ERROR(0x775)},
+ {NT_STATUS(0xc0000235), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000236), W_ERROR(0x4c9)},
+ {NT_STATUS(0xc0000237), W_ERROR(0x4ca)},
+ {NT_STATUS(0xc0000238), W_ERROR(0x4cb)},
+ {NT_STATUS(0xc0000239), W_ERROR(0x4cc)},
+ {NT_STATUS(0xc000023a), W_ERROR(0x4cd)},
+ {NT_STATUS(0xc000023b), W_ERROR(0x4ce)},
+ {NT_STATUS(0xc000023c), W_ERROR(0x4cf)},
+ {NT_STATUS(0xc000023d), W_ERROR(0x4d0)},
+ {NT_STATUS(0xc000023e), W_ERROR(0x4d1)},
+ {NT_STATUS(0xc000023f), W_ERROR(0x4d2)},
+ {NT_STATUS(0xc0000240), W_ERROR(0x4d3)},
+ {NT_STATUS(0xc0000241), W_ERROR(0x4d4)},
+ {NT_STATUS(0xc0000243), W_ERROR(0x4c8)},
+ {NT_STATUS(0xc0000246), W_ERROR(0x4d6)},
+ {NT_STATUS(0xc0000247), W_ERROR(0x4d7)},
+ {NT_STATUS(0xc0000248), W_ERROR(0x4d8)},
+ {NT_STATUS(0xc0000249), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000253), W_ERROR(0x54f)},
+ {NT_STATUS(0xc0000257), W_ERROR(0x4d0)},
+ {NT_STATUS(0xc0000259), W_ERROR(0x573)},
+ {NT_STATUS(0xc000025e), W_ERROR(0x422)},
+ {NT_STATUS(0xc0000262), W_ERROR(0xb6)},
+ {NT_STATUS(0xc0000263), W_ERROR(0x7f)},
+ {NT_STATUS(0xc0000264), W_ERROR(0x120)},
+ {NT_STATUS(0xc0000265), W_ERROR(0x476)},
+ {NT_STATUS(0xc0000267), W_ERROR(0x10fe)},
+ {NT_STATUS(0xc000026c), W_ERROR(0x7d1)},
+ {NT_STATUS(0xc000026d), W_ERROR(0x4b1)},
+ {NT_STATUS(0xc000026e), W_ERROR(0x15)},
+ {NT_STATUS(0xc0000272), W_ERROR(0x491)},
+ {NT_STATUS(0xc0000275), W_ERROR(0x1126)},
+ {NT_STATUS(0xc0000276), W_ERROR(0x1129)},
+ {NT_STATUS(0xc0000277), W_ERROR(0x112a)},
+ {NT_STATUS(0xc0000278), W_ERROR(0x1128)},
+ {NT_STATUS(0xc0000279), W_ERROR(0x780)},
+ {NT_STATUS(0xc0000280), W_ERROR(0x781)},
+ {NT_STATUS(0xc0000281), W_ERROR(0xa1)},
+ {NT_STATUS(0xc0000283), W_ERROR(0x488)},
+ {NT_STATUS(0xc0000284), W_ERROR(0x489)},
+ {NT_STATUS(0xc0000285), W_ERROR(0x48a)},
+ {NT_STATUS(0xc0000286), W_ERROR(0x48b)},
+ {NT_STATUS(0xc0000287), W_ERROR(0x48c)},
+ {NT_STATUS(0xc000028a), W_ERROR(0x5)},
+ {NT_STATUS(0xc000028b), W_ERROR(0x5)},
+ {NT_STATUS(0xc000028d), W_ERROR(0x5)},
+ {NT_STATUS(0xc000028e), W_ERROR(0x5)},
+ {NT_STATUS(0xc000028f), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000290), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000291), W_ERROR(0x1777)},
+ {NT_STATUS(0xc0000292), W_ERROR(0x1778)},
+ {NT_STATUS(0xc0000293), W_ERROR(0x1772)},
+ {NT_STATUS(0xc0000295), W_ERROR(0x1068)},
+ {NT_STATUS(0xc0000296), W_ERROR(0x1069)},
+ {NT_STATUS(0xc0000297), W_ERROR(0x106a)},
+ {NT_STATUS(0xc0000298), W_ERROR(0x106b)},
+ {NT_STATUS(0xc0000299), W_ERROR(0x201a)},
+ {NT_STATUS(0xc000029a), W_ERROR(0x201b)},
+ {NT_STATUS(0xc000029b), W_ERROR(0x201c)},
+ {NT_STATUS(0xc000029c), W_ERROR(0x1)},
+ {NT_STATUS(0xc000029d), W_ERROR(0x10ff)},
+ {NT_STATUS(0xc000029e), W_ERROR(0x1100)},
+ {NT_STATUS(0xc000029f), W_ERROR(0x494)},
+ {NT_STATUS(0xc00002a1), W_ERROR(0x200a)},
+ {NT_STATUS(0xc00002a2), W_ERROR(0x200b)},
+ {NT_STATUS(0xc00002a3), W_ERROR(0x200c)},
+ {NT_STATUS(0xc00002a4), W_ERROR(0x200d)},
+ {NT_STATUS(0xc00002a5), W_ERROR(0x200e)},
+ {NT_STATUS(0xc00002a6), W_ERROR(0x200f)},
+ {NT_STATUS(0xc00002a7), W_ERROR(0x2010)},
+ {NT_STATUS(0xc00002a8), W_ERROR(0x2011)},
+ {NT_STATUS(0xc00002a9), W_ERROR(0x2012)},
+ {NT_STATUS(0xc00002aa), W_ERROR(0x2013)},
+ {NT_STATUS(0xc00002ab), W_ERROR(0x2014)},
+ {NT_STATUS(0xc00002ac), W_ERROR(0x2015)},
+ {NT_STATUS(0xc00002ad), W_ERROR(0x2016)},
+ {NT_STATUS(0xc00002ae), W_ERROR(0x2017)},
+ {NT_STATUS(0xc00002af), W_ERROR(0x2018)},
+ {NT_STATUS(0xc00002b0), W_ERROR(0x2019)},
+ {NT_STATUS(0xc00002b1), W_ERROR(0x211e)},
+ {NT_STATUS(0xc00002b2), W_ERROR(0x1127)},
+ {NT_STATUS(0xc00002b6), W_ERROR(0x651)},
+ {NT_STATUS(0xc00002b7), W_ERROR(0x49a)},
+ {NT_STATUS(0xc00002b8), W_ERROR(0x49b)},
+ {NT_STATUS(0xc00002c1), W_ERROR(0x2024)},
+ {NT_STATUS(0xc00002c3), W_ERROR(0x575)},
+ {NT_STATUS(0xc00002c5), W_ERROR(0x3e6)},
+ {NT_STATUS(0xc00002c6), W_ERROR(0x1075)},
+ {NT_STATUS(0xc00002c7), W_ERROR(0x1076)},
+ {NT_STATUS(0xc00002ca), W_ERROR(0x10e8)},
+ {NT_STATUS(0xc00002cb), W_ERROR(0x2138)},
+ {NT_STATUS(0xc00002cc), W_ERROR(0x4e3)},
+ {NT_STATUS(0xc00002cd), W_ERROR(0x2139)},
+ {NT_STATUS(0xc00002cf), W_ERROR(0x49d)},
+ {NT_STATUS(0xc00002d0), W_ERROR(0x213a)},
+ {NT_STATUS(0xc00002d4), W_ERROR(0x2141)},
+ {NT_STATUS(0xc00002d5), W_ERROR(0x2142)},
+ {NT_STATUS(0xc00002d6), W_ERROR(0x2143)},
+ {NT_STATUS(0xc00002d7), W_ERROR(0x2144)},
+ {NT_STATUS(0xc00002d8), W_ERROR(0x2145)},
+ {NT_STATUS(0xc00002d9), W_ERROR(0x2146)},
+ {NT_STATUS(0xc00002da), W_ERROR(0x2147)},
+ {NT_STATUS(0xc00002db), W_ERROR(0x2148)},
+ {NT_STATUS(0xc00002dc), W_ERROR(0x2149)},
+ {NT_STATUS(0xc00002dd), W_ERROR(0x32)},
+ {NT_STATUS(0xc00002df), W_ERROR(0x2151)},
+ {NT_STATUS(0xc00002e0), W_ERROR(0x2152)},
+ {NT_STATUS(0xc00002e1), W_ERROR(0x2153)},
+ {NT_STATUS(0xc00002e2), W_ERROR(0x2154)},
+ {NT_STATUS(0xc00002e3), W_ERROR(0x215d)},
+ {NT_STATUS(0xc00002e4), W_ERROR(0x2163)},
+ {NT_STATUS(0xc00002e5), W_ERROR(0x2164)},
+ {NT_STATUS(0xc00002e6), W_ERROR(0x2165)},
+ {NT_STATUS(0xc00002e7), W_ERROR(0x216d)},
+ {NT_STATUS(0xc00002fe), W_ERROR(0x45b)},
+ {NT_STATUS(0xc00002ff), W_ERROR(0x4e7)},
+ {NT_STATUS(0xc0000300), W_ERROR(0x4e6)},
+ {NT_STATUS(0x80000001), W_ERROR(0x80000001)},
+ {NT_STATUS(0x80000002), W_ERROR(0x3e6)},
+ {NT_STATUS(0x80000003), W_ERROR(0x80000003)},
+ {NT_STATUS(0x80000004), W_ERROR(0x80000004)},
+ {NT_STATUS(0x80000005), W_ERROR(0xea)},
+ {NT_STATUS(0x80000006), W_ERROR(0x12)},
+ {NT_STATUS(0x8000000b), W_ERROR(0x56f)},
+ {NT_STATUS(0x8000000d), W_ERROR(0x12b)},
+ {NT_STATUS(0x8000000e), W_ERROR(0x1c)},
+ {NT_STATUS(0x8000000f), W_ERROR(0x15)},
+ {NT_STATUS(0x80000010), W_ERROR(0x15)},
+ {NT_STATUS(0x80000011), W_ERROR(0xaa)},
+ {NT_STATUS(0x80000012), W_ERROR(0x103)},
+ {NT_STATUS(0x80000013), W_ERROR(0xfe)},
+ {NT_STATUS(0x80000014), W_ERROR(0xff)},
+ {NT_STATUS(0x80000015), W_ERROR(0xff)},
+ {NT_STATUS(0x80000016), W_ERROR(0x456)},
+ {NT_STATUS(0x8000001a), W_ERROR(0x103)},
+ {NT_STATUS(0x8000001b), W_ERROR(0x44d)},
+ {NT_STATUS(0x8000001c), W_ERROR(0x456)},
+ {NT_STATUS(0x8000001d), W_ERROR(0x457)},
+ {NT_STATUS(0x8000001e), W_ERROR(0x44c)},
+ {NT_STATUS(0x8000001f), W_ERROR(0x44e)},
+ {NT_STATUS(0x80000021), W_ERROR(0x44f)},
+ {NT_STATUS(0x80000022), W_ERROR(0x450)},
+ {NT_STATUS(0x80000025), W_ERROR(0x962)},
+ {NT_STATUS(0x80000288), W_ERROR(0x48d)},
+ {NT_STATUS(0x80000289), W_ERROR(0x48e)},
+ {NT_STATUS_OK, WERR_OK}};
+
+static const struct {
+ WERROR werror;
+ NTSTATUS ntstatus;
+} werror_to_ntstatus_map[] = {
+ { W_ERROR(0x5), NT_STATUS_ACCESS_DENIED },
+ { WERR_OK, NT_STATUS_OK }
+};
+
+/*****************************************************************************
+convert a dos eclas/ecode to a NT status32 code
+ *****************************************************************************/
+NTSTATUS dos_to_ntstatus(uint8 eclass, uint32 ecode)
+{
+ int i;
+ if (eclass == 0 && ecode == 0) return NT_STATUS_OK;
+ for (i=0; NT_STATUS_V(dos_to_ntstatus_map[i].ntstatus); i++) {
+ if (eclass == dos_to_ntstatus_map[i].dos_class &&
+ ecode == dos_to_ntstatus_map[i].dos_code) {
+ return dos_to_ntstatus_map[i].ntstatus;
+ }
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+
+/*****************************************************************************
+convert a NT status code to a dos class/code
+ *****************************************************************************/
+void ntstatus_to_dos(NTSTATUS ntstatus, uint8 *eclass, uint32 *ecode)
+{
+ int i;
+ if (NT_STATUS_IS_OK(ntstatus)) {
+ *eclass = 0;
+ *ecode = 0;
+ return;
+ }
+ for (i=0; NT_STATUS_V(ntstatus_to_dos_map[i].ntstatus); i++) {
+ if (NT_STATUS_V(ntstatus) ==
+ NT_STATUS_V(ntstatus_to_dos_map[i].ntstatus)) {
+ *eclass = ntstatus_to_dos_map[i].dos_class;
+ *ecode = ntstatus_to_dos_map[i].dos_code;
+ return;
+ }
+ }
+ *eclass = ERRHRD;
+ *ecode = ERRgeneral;
+}
+
+
+/*****************************************************************************
+convert a WERROR to a NT status32 code
+ *****************************************************************************/
+NTSTATUS werror_to_ntstatus(WERROR error)
+{
+ int i;
+ if (W_ERROR_IS_OK(error)) return NT_STATUS_OK;
+
+ for (i=0; !W_ERROR_IS_OK(werror_to_ntstatus_map[i].werror); i++) {
+ if (W_ERROR_V(error) ==
+ W_ERROR_V(werror_to_ntstatus_map[i].werror)) {
+ return werror_to_ntstatus_map[i].ntstatus;
+ }
+ }
+
+ for (i=0; NT_STATUS_V(ntstatus_to_werror_map[i].ntstatus); i++) {
+ if (W_ERROR_V(error) ==
+ W_ERROR_V(ntstatus_to_werror_map[i].werror)) {
+ return ntstatus_to_werror_map[i].ntstatus;
+ }
+ }
+
+ /* just guess ... */
+ return NT_STATUS(W_ERROR_V(error) | 0xc0000000);
+}
+
+/*****************************************************************************
+convert a NTSTATUS to a WERROR
+ *****************************************************************************/
+WERROR ntstatus_to_werror(NTSTATUS error)
+{
+ int i;
+ if (NT_STATUS_IS_OK(error)) return WERR_OK;
+ for (i=0; NT_STATUS_V(ntstatus_to_werror_map[i].ntstatus); i++) {
+ if (NT_STATUS_V(error) ==
+ NT_STATUS_V(ntstatus_to_werror_map[i].ntstatus)) {
+ return ntstatus_to_werror_map[i].werror;
+ }
+ }
+
+ /* a lame guess */
+ return W_ERROR(NT_STATUS_V(error) & 0xffff);
+}
+
+#if defined(HAVE_GSSAPI)
+/*******************************************************************************
+ Map between gssapi errors and NT status. I made these up :-(. JRA.
+*******************************************************************************/
+
+static const struct {
+ unsigned long gss_err;
+ NTSTATUS ntstatus;
+} gss_to_ntstatus_errormap[] = {
+#if defined(GSS_S_CALL_INACCESSIBLE_READ)
+ {GSS_S_CALL_INACCESSIBLE_READ, NT_STATUS_INVALID_PARAMETER},
+#endif
+#if defined(GSS_S_CALL_INACCESSIBLE_WRITE)
+ {GSS_S_CALL_INACCESSIBLE_WRITE, NT_STATUS_INVALID_PARAMETER},
+#endif
+#if defined(GSS_S_CALL_BAD_STRUCTURE)
+ {GSS_S_CALL_BAD_STRUCTURE, NT_STATUS_INVALID_PARAMETER},
+#endif
+#if defined(GSS_S_BAD_MECH)
+ {GSS_S_BAD_MECH, NT_STATUS_INVALID_PARAMETER},
+#endif
+#if defined(GSS_S_BAD_NAME)
+ {GSS_S_BAD_NAME, NT_STATUS_INVALID_ACCOUNT_NAME},
+#endif
+#if defined(GSS_S_BAD_NAMETYPE)
+ {GSS_S_BAD_NAMETYPE, NT_STATUS_INVALID_PARAMETER},
+#endif
+#if defined(GSS_S_BAD_BINDINGS)
+ {GSS_S_BAD_BINDINGS, NT_STATUS_INVALID_PARAMETER},
+#endif
+#if defined(GSS_S_BAD_STATUS)
+ {GSS_S_BAD_STATUS, NT_STATUS_UNSUCCESSFUL},
+#endif
+#if defined(GSS_S_BAD_SIG)
+ {GSS_S_BAD_SIG, NT_STATUS_ACCESS_DENIED},
+#endif
+#if defined(GSS_S_NO_CRED)
+ {GSS_S_NO_CRED, NT_STATUS_ACCESS_DENIED},
+#endif
+#if defined(GSS_S_NO_CONTEXT)
+ {GSS_S_NO_CONTEXT, NT_STATUS_ACCESS_DENIED},
+#endif
+#if defined(GSS_S_DEFECTIVE_TOKEN)
+ {GSS_S_DEFECTIVE_TOKEN, NT_STATUS_ACCESS_DENIED},
+#endif
+#if defined(GSS_S_DEFECTIVE_CREDENTIAL)
+ {GSS_S_DEFECTIVE_CREDENTIAL, NT_STATUS_ACCESS_DENIED},
+#endif
+#if defined(GSS_S_CREDENTIALS_EXPIRED)
+ {GSS_S_CREDENTIALS_EXPIRED, NT_STATUS_PASSWORD_EXPIRED},
+#endif
+#if defined(GSS_S_CONTEXT_EXPIRED)
+ {GSS_S_CONTEXT_EXPIRED, NT_STATUS_PASSWORD_EXPIRED},
+#endif
+#if defined(GSS_S_BAD_QOP)
+ {GSS_S_BAD_QOP, NT_STATUS_ACCESS_DENIED},
+#endif
+#if defined(GSS_S_UNAUTHORIZED)
+ {GSS_S_UNAUTHORIZED, NT_STATUS_ACCESS_DENIED},
+#endif
+#if defined(GSS_S_UNAVAILABLE)
+ {GSS_S_UNAVAILABLE, NT_STATUS_UNSUCCESSFUL},
+#endif
+#if defined(GSS_S_DUPLICATE_ELEMENT)
+ {GSS_S_DUPLICATE_ELEMENT, NT_STATUS_INVALID_PARAMETER},
+#endif
+#if defined(GSS_S_NAME_NOT_MN)
+ {GSS_S_NAME_NOT_MN, NT_STATUS_INVALID_PARAMETER},
+#endif
+ { 0, NT_STATUS_OK }
+};
+
+/*********************************************************************
+ Map an NT error code from a gssapi error code.
+*********************************************************************/
+
+NTSTATUS map_nt_error_from_gss(uint32 gss_maj, uint32 minor)
+{
+ int i = 0;
+
+ if (gss_maj == GSS_S_COMPLETE) {
+ return NT_STATUS_OK;
+ }
+
+ if (gss_maj == GSS_S_CONTINUE_NEEDED) {
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ if (gss_maj == GSS_S_FAILURE) {
+ return map_nt_error_from_unix((int)minor);
+ }
+
+ /* Look through list */
+ while(gss_to_ntstatus_errormap[i].gss_err != 0) {
+ if (gss_to_ntstatus_errormap[i].gss_err == gss_maj) {
+ return gss_to_ntstatus_errormap[i].ntstatus;
+ }
+ i++;
+ }
+
+ /* Default return */
+ return NT_STATUS_ACCESS_DENIED;
+}
+#endif
diff --git a/source3/libsmb/libsmb_cache.c b/source3/libsmb/libsmb_cache.c
new file mode 100644
index 0000000000..bfacea368d
--- /dev/null
+++ b/source3/libsmb/libsmb_cache.c
@@ -0,0 +1,244 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client library implementation (server cache)
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000
+ Copyright (C) John Terpstra 2000
+ Copyright (C) Tom Jansen (Ninja ISD) 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libsmbclient.h"
+#include "libsmb_internal.h"
+
+/*
+ * Structure we use if internal caching mechanism is used
+ * nothing fancy here.
+ */
+struct smbc_server_cache {
+ char *server_name;
+ char *share_name;
+ char *workgroup;
+ char *username;
+ SMBCSRV *server;
+
+ struct smbc_server_cache *next, *prev;
+};
+
+
+
+/*
+ * Add a new connection to the server cache.
+ * This function is only used if the external cache is not enabled
+ */
+int
+SMBC_add_cached_server(SMBCCTX * context,
+ SMBCSRV * newsrv,
+ const char * server,
+ const char * share,
+ const char * workgroup,
+ const char * username)
+{
+ struct smbc_server_cache * srvcache = NULL;
+
+ if (!(srvcache = SMB_MALLOC_P(struct smbc_server_cache))) {
+ errno = ENOMEM;
+ DEBUG(3, ("Not enough space for server cache allocation\n"));
+ return 1;
+ }
+
+ ZERO_STRUCTP(srvcache);
+
+ srvcache->server = newsrv;
+
+ srvcache->server_name = SMB_STRDUP(server);
+ if (!srvcache->server_name) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ srvcache->share_name = SMB_STRDUP(share);
+ if (!srvcache->share_name) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ srvcache->workgroup = SMB_STRDUP(workgroup);
+ if (!srvcache->workgroup) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ srvcache->username = SMB_STRDUP(username);
+ if (!srvcache->username) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ DLIST_ADD(context->internal->server_cache, srvcache);
+ return 0;
+
+failed:
+ SAFE_FREE(srvcache->server_name);
+ SAFE_FREE(srvcache->share_name);
+ SAFE_FREE(srvcache->workgroup);
+ SAFE_FREE(srvcache->username);
+ SAFE_FREE(srvcache);
+
+ return 1;
+}
+
+
+
+/*
+ * Search the server cache for a server
+ * returns server handle on success, NULL on error (not found)
+ * This function is only used if the external cache is not enabled
+ */
+SMBCSRV *
+SMBC_get_cached_server(SMBCCTX * context,
+ const char * server,
+ const char * share,
+ const char * workgroup,
+ const char * user)
+{
+ struct smbc_server_cache * srv = NULL;
+
+ /* Search the cache lines */
+ for (srv = context->internal->server_cache; srv; srv = srv->next) {
+
+ if (strcmp(server,srv->server_name) == 0 &&
+ strcmp(workgroup,srv->workgroup) == 0 &&
+ strcmp(user, srv->username) == 0) {
+
+ /* If the share name matches, we're cool */
+ if (strcmp(share, srv->share_name) == 0) {
+ return srv->server;
+ }
+
+ /*
+ * We only return an empty share name or the attribute
+ * server on an exact match (which would have been
+ * caught above).
+ */
+ if (*share == '\0' || strcmp(share, "*IPC$") == 0)
+ continue;
+
+ /*
+ * Never return an empty share name or the attribute
+ * server if it wasn't what was requested.
+ */
+ if (*srv->share_name == '\0' ||
+ strcmp(srv->share_name, "*IPC$") == 0)
+ continue;
+
+ /*
+ * If we're only allowing one share per server, then
+ * a connection to the server (other than the
+ * attribute server connection) is cool.
+ */
+ if (smbc_getOptionOneSharePerServer(context)) {
+ /*
+ * The currently connected share name
+ * doesn't match the requested share, so
+ * disconnect from the current share.
+ */
+ if (! cli_tdis(srv->server->cli)) {
+ /* Sigh. Couldn't disconnect. */
+ cli_shutdown(srv->server->cli);
+ srv->server->cli = NULL;
+ smbc_getFunctionRemoveCachedServer(context)(context, srv->server);
+ continue;
+ }
+
+ /*
+ * Save the new share name. We've
+ * disconnected from the old share, and are
+ * about to connect to the new one.
+ */
+ SAFE_FREE(srv->share_name);
+ srv->share_name = SMB_STRDUP(share);
+ if (!srv->share_name) {
+ /* Out of memory. */
+ cli_shutdown(srv->server->cli);
+ srv->server->cli = NULL;
+ smbc_getFunctionRemoveCachedServer(context)(context, srv->server);
+ continue;
+ }
+
+
+ return srv->server;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+/*
+ * Search the server cache for a server and remove it
+ * returns 0 on success
+ * This function is only used if the external cache is not enabled
+ */
+int
+SMBC_remove_cached_server(SMBCCTX * context,
+ SMBCSRV * server)
+{
+ struct smbc_server_cache * srv = NULL;
+
+ for (srv = context->internal->server_cache; srv; srv = srv->next) {
+ if (server == srv->server) {
+
+ /* remove this sucker */
+ DLIST_REMOVE(context->internal->server_cache, srv);
+ SAFE_FREE(srv->server_name);
+ SAFE_FREE(srv->share_name);
+ SAFE_FREE(srv->workgroup);
+ SAFE_FREE(srv->username);
+ SAFE_FREE(srv);
+ return 0;
+ }
+ }
+ /* server not found */
+ return 1;
+}
+
+
+/*
+ * Try to remove all the servers in cache
+ * returns 1 on failure and 0 if all servers could be removed.
+ */
+int
+SMBC_purge_cached_servers(SMBCCTX * context)
+{
+ struct smbc_server_cache * srv;
+ struct smbc_server_cache * next;
+ int could_not_purge_all = 0;
+
+ for (srv = context->internal->server_cache,
+ next = (srv ? srv->next :NULL);
+ srv;
+ srv = next,
+ next = (srv ? srv->next : NULL)) {
+
+ if (SMBC_remove_unused_server(context, srv->server)) {
+ /* could not be removed */
+ could_not_purge_all = 1;
+ }
+ }
+ return could_not_purge_all;
+}
diff --git a/source3/libsmb/libsmb_compat.c b/source3/libsmb/libsmb_compat.c
new file mode 100644
index 0000000000..ad8fd922db
--- /dev/null
+++ b/source3/libsmb/libsmb_compat.c
@@ -0,0 +1,542 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client library implementation (Old interface compatibility)
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000
+ Copyright (C) John Terpstra 2000
+ Copyright (C) Tom Jansen (Ninja ISD) 2002
+ Copyright (C) Derrell Lipman 2003, 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+#include "libsmb_internal.h"
+
+struct smbc_compat_fdlist {
+ SMBCFILE * file;
+ int fd;
+ struct smbc_compat_fdlist *next, *prev;
+};
+
+static SMBCCTX * statcont = NULL;
+static int smbc_compat_initialized = 0;
+static int smbc_compat_nextfd = 0;
+static struct smbc_compat_fdlist * smbc_compat_fd_in_use = NULL;
+static struct smbc_compat_fdlist * smbc_compat_fd_avail = NULL;
+
+/* Find an fd and return the SMBCFILE * or NULL on failure */
+static SMBCFILE *
+find_fd(int fd)
+{
+ struct smbc_compat_fdlist * f = smbc_compat_fd_in_use;
+ while (f) {
+ if (f->fd == fd)
+ return f->file;
+ f = f->next;
+ }
+ return NULL;
+}
+
+/* Add an fd, returns 0 on success, -1 on error with errno set */
+static int
+add_fd(SMBCFILE * file)
+{
+ struct smbc_compat_fdlist * f = smbc_compat_fd_avail;
+
+ if (f) {
+ /* We found one that's available */
+ DLIST_REMOVE(smbc_compat_fd_avail, f);
+
+ } else {
+ /*
+ * None were available, so allocate one. Keep the number of
+ * file descriptors determinate. This allows the application
+ * to allocate bitmaps or mapping of file descriptors based on
+ * a known maximum number of file descriptors that will ever
+ * be returned.
+ */
+ if (smbc_compat_nextfd >= FD_SETSIZE) {
+ errno = EMFILE;
+ return -1;
+ }
+
+ f = SMB_MALLOC_P(struct smbc_compat_fdlist);
+ if (!f) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ f->fd = SMBC_BASE_FD + smbc_compat_nextfd++;
+ }
+
+ f->file = file;
+ DLIST_ADD(smbc_compat_fd_in_use, f);
+
+ return f->fd;
+}
+
+
+
+/* Delete an fd, returns 0 on success */
+static int
+del_fd(int fd)
+{
+ struct smbc_compat_fdlist * f = smbc_compat_fd_in_use;
+
+ while (f) {
+ if (f->fd == fd)
+ break;
+ f = f->next;
+ }
+
+ if (f) {
+ /* found */
+ DLIST_REMOVE(smbc_compat_fd_in_use, f);
+ f->file = NULL;
+ DLIST_ADD(smbc_compat_fd_avail, f);
+ return 0;
+ }
+ return 1;
+}
+
+
+
+int
+smbc_init(smbc_get_auth_data_fn fn,
+ int debug)
+{
+ if (!smbc_compat_initialized) {
+ statcont = smbc_new_context();
+ if (!statcont)
+ return -1;
+
+ smbc_setDebug(statcont, debug);
+ smbc_setFunctionAuthData(statcont, fn);
+
+ if (!smbc_init_context(statcont)) {
+ smbc_free_context(statcont, False);
+ return -1;
+ }
+
+ smbc_compat_initialized = 1;
+
+ return 0;
+ }
+ return 0;
+}
+
+
+SMBCCTX *
+smbc_set_context(SMBCCTX * context)
+{
+ SMBCCTX *old_context = statcont;
+
+ if (context) {
+ /* Save provided context. It must have been initialized! */
+ statcont = context;
+
+ /* You'd better know what you're doing. We won't help you. */
+ smbc_compat_initialized = 1;
+ }
+
+ return old_context;
+}
+
+
+int
+smbc_open(const char *furl,
+ int flags,
+ mode_t mode)
+{
+ SMBCFILE * file;
+ int fd;
+
+ file = smbc_getFunctionOpen(statcont)(statcont, furl, flags, mode);
+ if (!file)
+ return -1;
+
+ fd = add_fd(file);
+ if (fd == -1)
+ smbc_getFunctionClose(statcont)(statcont, file);
+ return fd;
+}
+
+
+int
+smbc_creat(const char *furl,
+ mode_t mode)
+{
+ SMBCFILE * file;
+ int fd;
+
+ file = smbc_getFunctionCreat(statcont)(statcont, furl, mode);
+ if (!file)
+ return -1;
+
+ fd = add_fd(file);
+ if (fd == -1) {
+ /* Hmm... should we delete the file too ? I guess we could try */
+ smbc_getFunctionClose(statcont)(statcont, file);
+ smbc_getFunctionUnlink(statcont)(statcont, furl);
+ }
+ return fd;
+}
+
+
+ssize_t
+smbc_read(int fd,
+ void *buf,
+ size_t bufsize)
+{
+ SMBCFILE * file = find_fd(fd);
+ return smbc_getFunctionRead(statcont)(statcont, file, buf, bufsize);
+}
+
+ssize_t
+smbc_write(int fd,
+ const void *buf,
+ size_t bufsize)
+{
+ SMBCFILE * file = find_fd(fd);
+ return smbc_getFunctionWrite(statcont)(statcont, file, buf, bufsize);
+}
+
+off_t
+smbc_lseek(int fd,
+ off_t offset,
+ int whence)
+{
+ SMBCFILE * file = find_fd(fd);
+ return smbc_getFunctionLseek(statcont)(statcont, file, offset, whence);
+}
+
+int
+smbc_close(int fd)
+{
+ SMBCFILE * file = find_fd(fd);
+ del_fd(fd);
+ return smbc_getFunctionClose(statcont)(statcont, file);
+}
+
+int
+smbc_unlink(const char *fname)
+{
+ return smbc_getFunctionUnlink(statcont)(statcont, fname);
+}
+
+int
+smbc_rename(const char *ourl,
+ const char *nurl)
+{
+ return smbc_getFunctionRename(statcont)(statcont, ourl,
+ statcont, nurl);
+}
+
+int
+smbc_opendir(const char *durl)
+{
+ SMBCFILE * file;
+ int fd;
+
+ file = smbc_getFunctionOpendir(statcont)(statcont, durl);
+ if (!file)
+ return -1;
+
+ fd = add_fd(file);
+ if (fd == -1)
+ smbc_getFunctionClosedir(statcont)(statcont, file);
+
+ return fd;
+}
+
+int
+smbc_closedir(int dh)
+{
+ SMBCFILE * file = find_fd(dh);
+ del_fd(dh);
+ return smbc_getFunctionClosedir(statcont)(statcont, file);
+}
+
+int
+smbc_getdents(unsigned int dh,
+ struct smbc_dirent *dirp,
+ int count)
+{
+ SMBCFILE * file = find_fd(dh);
+ return smbc_getFunctionGetdents(statcont)(statcont, file, dirp, count);
+}
+
+struct smbc_dirent *
+smbc_readdir(unsigned int dh)
+{
+ SMBCFILE * file = find_fd(dh);
+ return smbc_getFunctionReaddir(statcont)(statcont, file);
+}
+
+off_t
+smbc_telldir(int dh)
+{
+ SMBCFILE * file = find_fd(dh);
+ return smbc_getFunctionTelldir(statcont)(statcont, file);
+}
+
+int
+smbc_lseekdir(int fd,
+ off_t offset)
+{
+ SMBCFILE * file = find_fd(fd);
+ return smbc_getFunctionLseekdir(statcont)(statcont, file, offset);
+}
+
+int
+smbc_mkdir(const char *durl,
+ mode_t mode)
+{
+ return smbc_getFunctionMkdir(statcont)(statcont, durl, mode);
+}
+
+int
+smbc_rmdir(const char *durl)
+{
+ return smbc_getFunctionRmdir(statcont)(statcont, durl);
+}
+
+int
+smbc_stat(const char *url,
+ struct stat *st)
+{
+ return smbc_getFunctionStat(statcont)(statcont, url, st);
+}
+
+int
+smbc_fstat(int fd,
+ struct stat *st)
+{
+ SMBCFILE * file = find_fd(fd);
+ return smbc_getFunctionFstat(statcont)(statcont, file, st);
+}
+
+int
+smbc_ftruncate(int fd,
+ off_t size)
+{
+ SMBCFILE * file = find_fd(fd);
+ return smbc_getFunctionFtruncate(statcont)(statcont, file, size);
+}
+
+int
+smbc_chmod(const char *url,
+ mode_t mode)
+{
+ return smbc_getFunctionChmod(statcont)(statcont, url, mode);
+}
+
+int
+smbc_utimes(const char *fname,
+ struct timeval *tbuf)
+{
+ return smbc_getFunctionUtimes(statcont)(statcont, fname, tbuf);
+}
+
+#ifdef HAVE_UTIME_H
+int
+smbc_utime(const char *fname,
+ struct utimbuf *utbuf)
+{
+ struct timeval tv[2];
+
+ if (utbuf == NULL)
+ return smbc_getFunctionUtimes(statcont)(statcont, fname, NULL);
+
+ tv[0].tv_sec = utbuf->actime;
+ tv[1].tv_sec = utbuf->modtime;
+ tv[0].tv_usec = tv[1].tv_usec = 0;
+
+ return smbc_getFunctionUtimes(statcont)(statcont, fname, tv);
+}
+#endif
+
+int
+smbc_setxattr(const char *fname,
+ const char *name,
+ const void *value,
+ size_t size,
+ int flags)
+{
+ return smbc_getFunctionSetxattr(statcont)(statcont,
+ fname, name,
+ value, size, flags);
+}
+
+int
+smbc_lsetxattr(const char *fname,
+ const char *name,
+ const void *value,
+ size_t size,
+ int flags)
+{
+ return smbc_getFunctionSetxattr(statcont)(statcont,
+ fname, name,
+ value, size, flags);
+}
+
+int
+smbc_fsetxattr(int fd,
+ const char *name,
+ const void *value,
+ size_t size,
+ int flags)
+{
+ SMBCFILE * file = find_fd(fd);
+ if (file == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+ return smbc_getFunctionSetxattr(statcont)(statcont,
+ file->fname, name,
+ value, size, flags);
+}
+
+int
+smbc_getxattr(const char *fname,
+ const char *name,
+ const void *value,
+ size_t size)
+{
+ return smbc_getFunctionGetxattr(statcont)(statcont,
+ fname, name,
+ value, size);
+}
+
+int
+smbc_lgetxattr(const char *fname,
+ const char *name,
+ const void *value,
+ size_t size)
+{
+ return smbc_getFunctionGetxattr(statcont)(statcont,
+ fname, name,
+ value, size);
+}
+
+int
+smbc_fgetxattr(int fd,
+ const char *name,
+ const void *value,
+ size_t size)
+{
+ SMBCFILE * file = find_fd(fd);
+ if (file == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+ return smbc_getFunctionGetxattr(statcont)(statcont,
+ file->fname, name,
+ value, size);
+}
+
+int
+smbc_removexattr(const char *fname,
+ const char *name)
+{
+ return smbc_getFunctionRemovexattr(statcont)(statcont, fname, name);
+}
+
+int
+smbc_lremovexattr(const char *fname,
+ const char *name)
+{
+ return smbc_getFunctionRemovexattr(statcont)(statcont, fname, name);
+}
+
+int
+smbc_fremovexattr(int fd,
+ const char *name)
+{
+ SMBCFILE * file = find_fd(fd);
+ if (file == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+ return smbc_getFunctionRemovexattr(statcont)(statcont,
+ file->fname, name);
+}
+
+int
+smbc_listxattr(const char *fname,
+ char *list,
+ size_t size)
+{
+ return smbc_getFunctionListxattr(statcont)(statcont,
+ fname, list, size);
+}
+
+int
+smbc_llistxattr(const char *fname,
+ char *list,
+ size_t size)
+{
+ return smbc_getFunctionListxattr(statcont)(statcont,
+ fname, list, size);
+}
+
+int
+smbc_flistxattr(int fd,
+ char *list,
+ size_t size)
+{
+ SMBCFILE * file = find_fd(fd);
+ if (file == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+ return smbc_getFunctionListxattr(statcont)(statcont,
+ file->fname, list, size);
+}
+
+int
+smbc_print_file(const char *fname,
+ const char *printq)
+{
+ return smbc_getFunctionPrintFile(statcont)(statcont, fname,
+ statcont, printq);
+}
+
+int
+smbc_open_print_job(const char *fname)
+{
+ SMBCFILE * file;
+
+ file = smbc_getFunctionOpenPrintJob(statcont)(statcont, fname);
+ if (!file) return -1;
+ return file->cli_fd;
+}
+
+int
+smbc_list_print_jobs(const char *purl,
+ smbc_list_print_job_fn fn)
+{
+ return smbc_getFunctionListPrintJobs(statcont)(statcont, purl, fn);
+}
+
+int
+smbc_unlink_print_job(const char *purl,
+ int id)
+{
+ return smbc_getFunctionUnlinkPrintJob(statcont)(statcont, purl, id);
+}
+
+
diff --git a/source3/libsmb/libsmb_context.c b/source3/libsmb/libsmb_context.c
new file mode 100644
index 0000000000..19843383de
--- /dev/null
+++ b/source3/libsmb/libsmb_context.c
@@ -0,0 +1,645 @@
+/*
+ Unix SMB/Netbios implementation.
+ SMB client library implementation
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000, 2002
+ Copyright (C) John Terpstra 2000
+ Copyright (C) Tom Jansen (Ninja ISD) 2002
+ Copyright (C) Derrell Lipman 2003-2008
+ Copyright (C) Jeremy Allison 2007, 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libsmbclient.h"
+#include "libsmb_internal.h"
+
+
+/*
+ * Is the logging working / configfile read ?
+ */
+static bool SMBC_initialized;
+static unsigned int initialized_ctx_count;
+
+/*
+ * Get a new empty handle to fill in with your own info
+ */
+SMBCCTX *
+smbc_new_context(void)
+{
+ SMBCCTX *context;
+
+ /*
+ * All newly added context fields should be placed in
+ * SMBC_internal_data, not directly in SMBCCTX.
+ */
+ context = SMB_MALLOC_P(SMBCCTX);
+ if (!context) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ ZERO_STRUCTP(context);
+
+ context->internal = SMB_MALLOC_P(struct SMBC_internal_data);
+ if (!context->internal) {
+ SAFE_FREE(context);
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ /* Initialize the context and establish reasonable defaults */
+ ZERO_STRUCTP(context->internal);
+
+ smbc_setDebug(context, 0);
+ smbc_setTimeout(context, 20000);
+
+ smbc_setOptionFullTimeNames(context, False);
+ smbc_setOptionOpenShareMode(context, SMBC_SHAREMODE_DENY_NONE);
+ smbc_setOptionSmbEncryptionLevel(context, SMBC_ENCRYPTLEVEL_NONE);
+ smbc_setOptionBrowseMaxLmbCount(context, 3); /* # LMBs to query */
+ smbc_setOptionUrlEncodeReaddirEntries(context, False);
+ smbc_setOptionOneSharePerServer(context, False);
+
+ smbc_setFunctionAuthData(context, SMBC_get_auth_data);
+ smbc_setFunctionCheckServer(context, SMBC_check_server);
+ smbc_setFunctionRemoveUnusedServer(context, SMBC_remove_unused_server);
+
+ smbc_setOptionUserData(context, NULL);
+ smbc_setFunctionAddCachedServer(context, SMBC_add_cached_server);
+ smbc_setFunctionGetCachedServer(context, SMBC_get_cached_server);
+ smbc_setFunctionRemoveCachedServer(context, SMBC_remove_cached_server);
+ smbc_setFunctionPurgeCachedServers(context, SMBC_purge_cached_servers);
+
+ smbc_setFunctionOpen(context, SMBC_open_ctx);
+ smbc_setFunctionCreat(context, SMBC_creat_ctx);
+ smbc_setFunctionRead(context, SMBC_read_ctx);
+ smbc_setFunctionWrite(context, SMBC_write_ctx);
+ smbc_setFunctionClose(context, SMBC_close_ctx);
+ smbc_setFunctionUnlink(context, SMBC_unlink_ctx);
+ smbc_setFunctionRename(context, SMBC_rename_ctx);
+ smbc_setFunctionLseek(context, SMBC_lseek_ctx);
+ smbc_setFunctionFtruncate(context, SMBC_ftruncate_ctx);
+ smbc_setFunctionStat(context, SMBC_stat_ctx);
+ smbc_setFunctionFstat(context, SMBC_fstat_ctx);
+ smbc_setFunctionOpendir(context, SMBC_opendir_ctx);
+ smbc_setFunctionClosedir(context, SMBC_closedir_ctx);
+ smbc_setFunctionReaddir(context, SMBC_readdir_ctx);
+ smbc_setFunctionGetdents(context, SMBC_getdents_ctx);
+ smbc_setFunctionMkdir(context, SMBC_mkdir_ctx);
+ smbc_setFunctionRmdir(context, SMBC_rmdir_ctx);
+ smbc_setFunctionTelldir(context, SMBC_telldir_ctx);
+ smbc_setFunctionLseekdir(context, SMBC_lseekdir_ctx);
+ smbc_setFunctionFstatdir(context, SMBC_fstatdir_ctx);
+ smbc_setFunctionChmod(context, SMBC_chmod_ctx);
+ smbc_setFunctionUtimes(context, SMBC_utimes_ctx);
+ smbc_setFunctionSetxattr(context, SMBC_setxattr_ctx);
+ smbc_setFunctionGetxattr(context, SMBC_getxattr_ctx);
+ smbc_setFunctionRemovexattr(context, SMBC_removexattr_ctx);
+ smbc_setFunctionListxattr(context, SMBC_listxattr_ctx);
+
+ smbc_setFunctionOpenPrintJob(context, SMBC_open_print_job_ctx);
+ smbc_setFunctionPrintFile(context, SMBC_print_file_ctx);
+ smbc_setFunctionListPrintJobs(context, SMBC_list_print_jobs_ctx);
+ smbc_setFunctionUnlinkPrintJob(context, SMBC_unlink_print_job_ctx);
+
+ return context;
+}
+
+/*
+ * Free a context
+ *
+ * Returns 0 on success. Otherwise returns 1, the SMBCCTX is _not_ freed
+ * and thus you'll be leaking memory if not handled properly.
+ *
+ */
+int
+smbc_free_context(SMBCCTX *context,
+ int shutdown_ctx)
+{
+ if (!context) {
+ errno = EBADF;
+ return 1;
+ }
+
+ if (shutdown_ctx) {
+ SMBCFILE * f;
+ DEBUG(1,("Performing aggressive shutdown.\n"));
+
+ f = context->internal->files;
+ while (f) {
+ smbc_getFunctionClose(context)(context, f);
+ f = f->next;
+ }
+ context->internal->files = NULL;
+
+ /* First try to remove the servers the nice way. */
+ if (smbc_getFunctionPurgeCachedServers(context)(context)) {
+ SMBCSRV * s;
+ SMBCSRV * next;
+ DEBUG(1, ("Could not purge all servers, "
+ "Nice way shutdown failed.\n"));
+ s = context->internal->servers;
+ while (s) {
+ DEBUG(1, ("Forced shutdown: %p (fd=%d)\n",
+ s, s->cli->fd));
+ cli_shutdown(s->cli);
+ smbc_getFunctionRemoveCachedServer(context)(context,
+ s);
+ next = s->next;
+ DLIST_REMOVE(context->internal->servers, s);
+ SAFE_FREE(s);
+ s = next;
+ }
+ context->internal->servers = NULL;
+ }
+ }
+ else {
+ /* This is the polite way */
+ if (smbc_getFunctionPurgeCachedServers(context)(context)) {
+ DEBUG(1, ("Could not purge all servers, "
+ "free_context failed.\n"));
+ errno = EBUSY;
+ return 1;
+ }
+ if (context->internal->servers) {
+ DEBUG(1, ("Active servers in context, "
+ "free_context failed.\n"));
+ errno = EBUSY;
+ return 1;
+ }
+ if (context->internal->files) {
+ DEBUG(1, ("Active files in context, "
+ "free_context failed.\n"));
+ errno = EBUSY;
+ return 1;
+ }
+ }
+
+ /* Things we have to clean up */
+ free(smbc_getWorkgroup(context));
+ smbc_setWorkgroup(context, NULL);
+
+ free(smbc_getNetbiosName(context));
+ smbc_setNetbiosName(context, NULL);
+
+ free(smbc_getUser(context));
+ smbc_setUser(context, NULL);
+
+ DEBUG(3, ("Context %p successfully freed\n", context));
+
+ SAFE_FREE(context->internal);
+ SAFE_FREE(context);
+
+ if (initialized_ctx_count) {
+ initialized_ctx_count--;
+ }
+
+ if (initialized_ctx_count == 0 && SMBC_initialized) {
+ gencache_shutdown();
+ secrets_shutdown();
+ gfree_all();
+ SMBC_initialized = false;
+ }
+ return 0;
+}
+
+
+/**
+ * Deprecated interface. Do not use. Instead, use the various
+ * smbc_setOption*() functions or smbc_setFunctionAuthDataWithContext().
+ */
+void
+smbc_option_set(SMBCCTX *context,
+ char *option_name,
+ ... /* option_value */)
+{
+ va_list ap;
+ union {
+ int i;
+ bool b;
+ smbc_get_auth_data_with_context_fn auth_fn;
+ void *v;
+ const char *s;
+ } option_value;
+
+ va_start(ap, option_name);
+
+ if (strcmp(option_name, "debug_to_stderr") == 0) {
+ option_value.b = (bool) va_arg(ap, int);
+ smbc_setOptionDebugToStderr(context, option_value.b);
+
+ } else if (strcmp(option_name, "full_time_names") == 0) {
+ option_value.b = (bool) va_arg(ap, int);
+ smbc_setOptionFullTimeNames(context, option_value.b);
+
+ } else if (strcmp(option_name, "open_share_mode") == 0) {
+ option_value.i = va_arg(ap, int);
+ smbc_setOptionOpenShareMode(context, option_value.i);
+
+ } else if (strcmp(option_name, "auth_function") == 0) {
+ option_value.auth_fn =
+ va_arg(ap, smbc_get_auth_data_with_context_fn);
+ smbc_setFunctionAuthDataWithContext(context, option_value.auth_fn);
+
+ } else if (strcmp(option_name, "user_data") == 0) {
+ option_value.v = va_arg(ap, void *);
+ smbc_setOptionUserData(context, option_value.v);
+
+ } else if (strcmp(option_name, "smb_encrypt_level") == 0) {
+ option_value.s = va_arg(ap, const char *);
+ if (strcmp(option_value.s, "none") == 0) {
+ smbc_setOptionSmbEncryptionLevel(context,
+ SMBC_ENCRYPTLEVEL_NONE);
+ } else if (strcmp(option_value.s, "request") == 0) {
+ smbc_setOptionSmbEncryptionLevel(context,
+ SMBC_ENCRYPTLEVEL_REQUEST);
+ } else if (strcmp(option_value.s, "require") == 0) {
+ smbc_setOptionSmbEncryptionLevel(context,
+ SMBC_ENCRYPTLEVEL_REQUIRE);
+ }
+
+ } else if (strcmp(option_name, "browse_max_lmb_count") == 0) {
+ option_value.i = va_arg(ap, int);
+ smbc_setOptionBrowseMaxLmbCount(context, option_value.i);
+
+ } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) {
+ option_value.b = (bool) va_arg(ap, int);
+ smbc_setOptionUrlEncodeReaddirEntries(context, option_value.b);
+
+ } else if (strcmp(option_name, "one_share_per_server") == 0) {
+ option_value.b = (bool) va_arg(ap, int);
+ smbc_setOptionOneSharePerServer(context, option_value.b);
+
+ } else if (strcmp(option_name, "use_kerberos") == 0) {
+ option_value.b = (bool) va_arg(ap, int);
+ smbc_setOptionUseKerberos(context, option_value.b);
+
+ } else if (strcmp(option_name, "fallback_after_kerberos") == 0) {
+ option_value.b = (bool) va_arg(ap, int);
+ smbc_setOptionFallbackAfterKerberos(context, option_value.b);
+
+ } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) {
+ option_value.b = (bool) va_arg(ap, int);
+ smbc_setOptionNoAutoAnonymousLogin(context, option_value.b);
+ }
+
+ va_end(ap);
+}
+
+
+/*
+ * Deprecated interface. Do not use. Instead, use the various
+ * smbc_getOption*() functions.
+ */
+void *
+smbc_option_get(SMBCCTX *context,
+ char *option_name)
+{
+ if (strcmp(option_name, "debug_stderr") == 0) {
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+ return (void *) (intptr_t) smbc_getOptionDebugToStderr(context);
+#else
+ return (void *) smbc_getOptionDebugToStderr(context);
+#endif
+
+ } else if (strcmp(option_name, "full_time_names") == 0) {
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+ return (void *) (intptr_t) smbc_getOptionFullTimeNames(context);
+#else
+ return (void *) smbc_getOptionFullTimeNames(context);
+#endif
+
+ } else if (strcmp(option_name, "open_share_mode") == 0) {
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+ return (void *) (intptr_t) smbc_getOptionOpenShareMode(context);
+#else
+ return (void *) smbc_getOptionOpenShareMode(context);
+#endif
+
+ } else if (strcmp(option_name, "auth_function") == 0) {
+ return (void *) smbc_getFunctionAuthDataWithContext(context);
+
+ } else if (strcmp(option_name, "user_data") == 0) {
+ return smbc_getOptionUserData(context);
+
+ } else if (strcmp(option_name, "smb_encrypt_level") == 0) {
+ switch(smbc_getOptionSmbEncryptionLevel(context))
+ {
+ case 0:
+ return (void *) "none";
+ case 1:
+ return (void *) "request";
+ case 2:
+ return (void *) "require";
+ }
+
+ } else if (strcmp(option_name, "smb_encrypt_on") == 0) {
+ SMBCSRV *s;
+ unsigned int num_servers = 0;
+
+ for (s = context->internal->servers; s; s = s->next) {
+ num_servers++;
+ if (s->cli->trans_enc_state == NULL) {
+ return (void *)false;
+ }
+ }
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+ return (void *) (intptr_t) (bool) (num_servers > 0);
+#else
+ return (void *) (bool) (num_servers > 0);
+#endif
+
+ } else if (strcmp(option_name, "browse_max_lmb_count") == 0) {
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+ return (void *) (intptr_t) smbc_getOptionBrowseMaxLmbCount(context);
+#else
+ return (void *) smbc_getOptionBrowseMaxLmbCount(context);
+#endif
+
+ } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) {
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+ return (void *)(intptr_t) smbc_getOptionUrlEncodeReaddirEntries(context);
+#else
+ return (void *) (bool) smbc_getOptionUrlEncodeReaddirEntries(context);
+#endif
+
+ } else if (strcmp(option_name, "one_share_per_server") == 0) {
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+ return (void *) (intptr_t) smbc_getOptionOneSharePerServer(context);
+#else
+ return (void *) (bool) smbc_getOptionOneSharePerServer(context);
+#endif
+
+ } else if (strcmp(option_name, "use_kerberos") == 0) {
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+ return (void *) (intptr_t) smbc_getOptionUseKerberos(context);
+#else
+ return (void *) (bool) smbc_getOptionUseKerberos(context);
+#endif
+
+ } else if (strcmp(option_name, "fallback_after_kerberos") == 0) {
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+ return (void *)(intptr_t) smbc_getOptionFallbackAfterKerberos(context);
+#else
+ return (void *) (bool) smbc_getOptionFallbackAfterKerberos(context);
+#endif
+
+ } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) {
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+ return (void *) (intptr_t) smbc_getOptionNoAutoAnonymousLogin(context);
+#else
+ return (void *) (bool) smbc_getOptionNoAutoAnonymousLogin(context);
+#endif
+ }
+
+ return NULL;
+}
+
+
+/*
+ * Initialize the library, etc.
+ *
+ * We accept a struct containing handle information.
+ * valid values for info->debug from 0 to 100,
+ * and insist that info->fn must be non-null.
+ */
+SMBCCTX *
+smbc_init_context(SMBCCTX *context)
+{
+ int pid;
+ char *user = NULL;
+ char *home = NULL;
+
+ if (!context) {
+ errno = EBADF;
+ return NULL;
+ }
+
+ /* Do not initialise the same client twice */
+ if (context->internal->initialized) {
+ return NULL;
+ }
+
+ if ((!smbc_getFunctionAuthData(context) &&
+ !smbc_getFunctionAuthDataWithContext(context)) ||
+ smbc_getDebug(context) < 0 ||
+ smbc_getDebug(context) > 100) {
+
+ errno = EINVAL;
+ return NULL;
+
+ }
+
+ if (!SMBC_initialized) {
+ /*
+ * Do some library-wide intializations the first time we get
+ * called
+ */
+ bool conf_loaded = False;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ load_case_tables();
+
+ setup_logging("libsmbclient", True);
+ if (context->internal->debug_stderr) {
+ dbf = x_stderr;
+ x_setbuf(x_stderr, NULL);
+ }
+
+ /* Here we would open the smb.conf file if needed ... */
+
+ lp_set_in_client(True);
+
+ home = getenv("HOME");
+ if (home) {
+ char *conf = NULL;
+ if (asprintf(&conf, "%s/.smb/smb.conf", home) > 0) {
+ if (lp_load(conf, True, False, False, True)) {
+ conf_loaded = True;
+ } else {
+ DEBUG(5, ("Could not load config file: %s\n",
+ conf));
+ }
+ SAFE_FREE(conf);
+ }
+ }
+
+ if (!conf_loaded) {
+ /*
+ * Well, if that failed, try the get_dyn_CONFIGFILE
+ * Which points to the standard locn, and if that
+ * fails, silently ignore it and use the internal
+ * defaults ...
+ */
+
+ if (!lp_load(get_dyn_CONFIGFILE(), True, False, False, False)) {
+ DEBUG(5, ("Could not load config file: %s\n",
+ get_dyn_CONFIGFILE()));
+ } else if (home) {
+ char *conf;
+ /*
+ * We loaded the global config file. Now lets
+ * load user-specific modifications to the
+ * global config.
+ */
+ if (asprintf(&conf,
+ "%s/.smb/smb.conf.append",
+ home) > 0) {
+ if (!lp_load(conf, True, False, False, False)) {
+ DEBUG(10,
+ ("Could not append config file: "
+ "%s\n",
+ conf));
+ }
+ SAFE_FREE(conf);
+ }
+ }
+ }
+
+ load_interfaces(); /* Load the list of interfaces ... */
+
+ reopen_logs(); /* Get logging working ... */
+
+ /*
+ * Block SIGPIPE (from lib/util_sock.c: write())
+ * It is not needed and should not stop execution
+ */
+ BlockSignals(True, SIGPIPE);
+
+ /* Done with one-time initialisation */
+ SMBC_initialized = true;
+
+ TALLOC_FREE(frame);
+ }
+
+ if (!smbc_getUser(context)) {
+ /*
+ * FIXME: Is this the best way to get the user info?
+ */
+ user = getenv("USER");
+ /* walk around as "guest" if no username can be found */
+ if (!user) {
+ user = SMB_STRDUP("guest");
+ } else {
+ user = SMB_STRDUP(user);
+ }
+
+ if (!user) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ smbc_setUser(context, user);
+ }
+
+ if (!smbc_getNetbiosName(context)) {
+ /*
+ * We try to get our netbios name from the config. If that
+ * fails we fall back on constructing our netbios name from
+ * our hostname etc
+ */
+ char *netbios_name;
+ if (global_myname()) {
+ netbios_name = SMB_STRDUP(global_myname());
+ } else {
+ /*
+ * Hmmm, I want to get hostname as well, but I am too
+ * lazy for the moment
+ */
+ pid = sys_getpid();
+ netbios_name = (char *)SMB_MALLOC(17);
+ if (!netbios_name) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ slprintf(netbios_name, 16,
+ "smbc%s%d", smbc_getUser(context), pid);
+ }
+
+ if (!netbios_name) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ smbc_setNetbiosName(context, netbios_name);
+ }
+
+ DEBUG(1, ("Using netbios name %s.\n", smbc_getNetbiosName(context)));
+
+ if (!smbc_getWorkgroup(context)) {
+ char *workgroup;
+
+ if (lp_workgroup()) {
+ workgroup = SMB_STRDUP(lp_workgroup());
+ }
+ else {
+ /* TODO: Think about a decent default workgroup */
+ workgroup = SMB_STRDUP("samba");
+ }
+
+ if (!workgroup) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ smbc_setWorkgroup(context, workgroup);
+ }
+
+ DEBUG(1, ("Using workgroup %s.\n", smbc_getWorkgroup(context)));
+
+ /* shortest timeout is 1 second */
+ if (smbc_getTimeout(context) > 0 && smbc_getTimeout(context) < 1000)
+ smbc_setTimeout(context, 1000);
+
+ /*
+ * FIXME: Should we check the function pointers here?
+ */
+
+ context->internal->initialized = True;
+ initialized_ctx_count++;
+
+ return context;
+}
+
+
+/* Return the verion of samba, and thus libsmbclient */
+const char *
+smbc_version(void)
+{
+ return SAMBA_VERSION_STRING;
+}
+
+
+/*
+ * Set the credentials so DFS will work when following referrals.
+ */
+void
+smbc_set_credentials(char *workgroup,
+ char *user,
+ char *password,
+ smbc_bool use_kerberos,
+ char *signing_state)
+{
+
+ set_cmdline_auth_info_username(user);
+ set_cmdline_auth_info_password(password);
+ set_cmdline_auth_info_use_kerberos(use_kerberos);
+ if (! set_cmdline_auth_info_signing_state(signing_state)) {
+ DEBUG(0, ("Invalid signing state: %s", signing_state));
+ }
+ set_global_myworkgroup(workgroup);
+ cli_cm_set_credentials();
+}
diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c
new file mode 100644
index 0000000000..aa313f2c05
--- /dev/null
+++ b/source3/libsmb/libsmb_dir.c
@@ -0,0 +1,1949 @@
+/*
+ Unix SMB/Netbios implementation.
+ SMB client library implementation
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000, 2002
+ Copyright (C) John Terpstra 2000
+ Copyright (C) Tom Jansen (Ninja ISD) 2002
+ Copyright (C) Derrell Lipman 2003-2008
+ Copyright (C) Jeremy Allison 2007, 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libsmbclient.h"
+#include "libsmb_internal.h"
+
+
+/*
+ * Routine to open a directory
+ * We accept the URL syntax explained in SMBC_parse_path(), above.
+ */
+
+static void
+remove_dir(SMBCFILE *dir)
+{
+ struct smbc_dir_list *d,*f;
+
+ d = dir->dir_list;
+ while (d) {
+
+ f = d; d = d->next;
+
+ SAFE_FREE(f->dirent);
+ SAFE_FREE(f);
+
+ }
+
+ dir->dir_list = dir->dir_end = dir->dir_next = NULL;
+
+}
+
+static int
+add_dirent(SMBCFILE *dir,
+ const char *name,
+ const char *comment,
+ uint32 type)
+{
+ struct smbc_dirent *dirent;
+ int size;
+ int name_length = (name == NULL ? 0 : strlen(name));
+ int comment_len = (comment == NULL ? 0 : strlen(comment));
+
+ /*
+ * Allocate space for the dirent, which must be increased by the
+ * size of the name and the comment and 1 each for the null terminator.
+ */
+
+ size = sizeof(struct smbc_dirent) + name_length + comment_len + 2;
+
+ dirent = (struct smbc_dirent *)SMB_MALLOC(size);
+
+ if (!dirent) {
+
+ dir->dir_error = ENOMEM;
+ return -1;
+
+ }
+
+ ZERO_STRUCTP(dirent);
+
+ if (dir->dir_list == NULL) {
+
+ dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list);
+ if (!dir->dir_list) {
+
+ SAFE_FREE(dirent);
+ dir->dir_error = ENOMEM;
+ return -1;
+
+ }
+ ZERO_STRUCTP(dir->dir_list);
+
+ dir->dir_end = dir->dir_next = dir->dir_list;
+ }
+ else {
+
+ dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list);
+
+ if (!dir->dir_end->next) {
+
+ SAFE_FREE(dirent);
+ dir->dir_error = ENOMEM;
+ return -1;
+
+ }
+ ZERO_STRUCTP(dir->dir_end->next);
+
+ dir->dir_end = dir->dir_end->next;
+ }
+
+ dir->dir_end->next = NULL;
+ dir->dir_end->dirent = dirent;
+
+ dirent->smbc_type = type;
+ dirent->namelen = name_length;
+ dirent->commentlen = comment_len;
+ dirent->dirlen = size;
+
+ /*
+ * dirent->namelen + 1 includes the null (no null termination needed)
+ * Ditto for dirent->commentlen.
+ * The space for the two null bytes was allocated.
+ */
+ strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
+ dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
+ strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
+
+ return 0;
+
+}
+
+static void
+list_unique_wg_fn(const char *name,
+ uint32 type,
+ const char *comment,
+ void *state)
+{
+ SMBCFILE *dir = (SMBCFILE *)state;
+ struct smbc_dir_list *dir_list;
+ struct smbc_dirent *dirent;
+ int dirent_type;
+ int do_remove = 0;
+
+ dirent_type = dir->dir_type;
+
+ if (add_dirent(dir, name, comment, dirent_type) < 0) {
+
+ /* An error occurred, what do we do? */
+ /* FIXME: Add some code here */
+ }
+
+ /* Point to the one just added */
+ dirent = dir->dir_end->dirent;
+
+ /* See if this was a duplicate */
+ for (dir_list = dir->dir_list;
+ dir_list != dir->dir_end;
+ dir_list = dir_list->next) {
+ if (! do_remove &&
+ strcmp(dir_list->dirent->name, dirent->name) == 0) {
+ /* Duplicate. End end of list need to be removed. */
+ do_remove = 1;
+ }
+
+ if (do_remove && dir_list->next == dir->dir_end) {
+ /* Found the end of the list. Remove it. */
+ dir->dir_end = dir_list;
+ free(dir_list->next);
+ free(dirent);
+ dir_list->next = NULL;
+ break;
+ }
+ }
+}
+
+static void
+list_fn(const char *name,
+ uint32 type,
+ const char *comment,
+ void *state)
+{
+ SMBCFILE *dir = (SMBCFILE *)state;
+ int dirent_type;
+
+ /*
+ * We need to process the type a little ...
+ *
+ * Disk share = 0x00000000
+ * Print share = 0x00000001
+ * Comms share = 0x00000002 (obsolete?)
+ * IPC$ share = 0x00000003
+ *
+ * administrative shares:
+ * ADMIN$, IPC$, C$, D$, E$ ... are type |= 0x80000000
+ */
+
+ if (dir->dir_type == SMBC_FILE_SHARE) {
+ switch (type) {
+ case 0 | 0x80000000:
+ case 0:
+ dirent_type = SMBC_FILE_SHARE;
+ break;
+
+ case 1:
+ dirent_type = SMBC_PRINTER_SHARE;
+ break;
+
+ case 2:
+ dirent_type = SMBC_COMMS_SHARE;
+ break;
+
+ case 3 | 0x80000000:
+ case 3:
+ dirent_type = SMBC_IPC_SHARE;
+ break;
+
+ default:
+ dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
+ break;
+ }
+ }
+ else {
+ dirent_type = dir->dir_type;
+ }
+
+ if (add_dirent(dir, name, comment, dirent_type) < 0) {
+
+ /* An error occurred, what do we do? */
+ /* FIXME: Add some code here */
+
+ }
+}
+
+static void
+dir_list_fn(const char *mnt,
+ file_info *finfo,
+ const char *mask,
+ void *state)
+{
+
+ if (add_dirent((SMBCFILE *)state, finfo->name, "",
+ (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) {
+
+ /* Handle an error ... */
+
+ /* FIXME: Add some code ... */
+
+ }
+
+}
+
+static int
+net_share_enum_rpc(struct cli_state *cli,
+ void (*fn)(const char *name,
+ uint32 type,
+ const char *comment,
+ void *state),
+ void *state)
+{
+ int i;
+ WERROR result;
+ uint32 preferred_len = 0xffffffff;
+ uint32 type;
+ struct srvsvc_NetShareInfoCtr info_ctr;
+ struct srvsvc_NetShareCtr1 ctr1;
+ fstring name = "";
+ fstring comment = "";
+ struct rpc_pipe_client *pipe_hnd;
+ NTSTATUS nt_status;
+ uint32_t resume_handle = 0;
+ uint32_t total_entries = 0;
+
+ /* Open the server service pipe */
+ nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc.syntax_id,
+ &pipe_hnd);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1, ("net_share_enum_rpc pipe open fail!\n"));
+ return -1;
+ }
+
+ ZERO_STRUCT(info_ctr);
+ ZERO_STRUCT(ctr1);
+
+ info_ctr.level = 1;
+ info_ctr.ctr.ctr1 = &ctr1;
+
+ /* Issue the NetShareEnum RPC call and retrieve the response */
+ nt_status = rpccli_srvsvc_NetShareEnumAll(pipe_hnd, talloc_tos(),
+ pipe_hnd->desthost,
+ &info_ctr,
+ preferred_len,
+ &total_entries,
+ &resume_handle,
+ &result);
+
+ /* Was it successful? */
+ if (!NT_STATUS_IS_OK(nt_status) || !W_ERROR_IS_OK(result) ||
+ total_entries == 0) {
+ /* Nope. Go clean up. */
+ goto done;
+ }
+
+ /* For each returned entry... */
+ for (i = 0; i < total_entries; i++) {
+
+ /* pull out the share name */
+ fstrcpy(name, info_ctr.ctr.ctr1->array[i].name);
+
+ /* pull out the share's comment */
+ fstrcpy(comment, info_ctr.ctr.ctr1->array[i].comment);
+
+ /* Get the type value */
+ type = info_ctr.ctr.ctr1->array[i].type;
+
+ /* Add this share to the list */
+ (*fn)(name, type, comment, state);
+ }
+
+done:
+ /* Close the server service pipe */
+ TALLOC_FREE(pipe_hnd);
+
+ /* Tell 'em if it worked */
+ return W_ERROR_IS_OK(result) ? 0 : -1;
+}
+
+
+/*
+ * Verify that the options specified in a URL are valid
+ */
+int
+SMBC_check_options(char *server,
+ char *share,
+ char *path,
+ char *options)
+{
+ DEBUG(4, ("SMBC_check_options(): server='%s' share='%s' "
+ "path='%s' options='%s'\n",
+ server, share, path, options));
+
+ /* No options at all is always ok */
+ if (! *options) return 0;
+
+ /* Currently, we don't support any options. */
+ return -1;
+}
+
+
+SMBCFILE *
+SMBC_opendir_ctx(SMBCCTX *context,
+ const char *fname)
+{
+ int saved_errno;
+ char *server = NULL;
+ char *share = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *options = NULL;
+ char *workgroup = NULL;
+ char *path = NULL;
+ uint16 mode;
+ char *p = NULL;
+ SMBCSRV *srv = NULL;
+ SMBCFILE *dir = NULL;
+ struct sockaddr_storage rem_ss;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+ DEBUG(4, ("no valid context\n"));
+ errno = EINVAL + 8192;
+ TALLOC_FREE(frame);
+ return NULL;
+
+ }
+
+ if (!fname) {
+ DEBUG(4, ("no valid fname\n"));
+ errno = EINVAL + 8193;
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ if (SMBC_parse_path(frame,
+ context,
+ fname,
+ &workgroup,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ &options)) {
+ DEBUG(4, ("no valid path\n"));
+ errno = EINVAL + 8194;
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
+ "path='%s' options='%s'\n",
+ fname, server, share, path, options));
+
+ /* Ensure the options are valid */
+ if (SMBC_check_options(server, share, path, options)) {
+ DEBUG(4, ("unacceptable options (%s)\n", options));
+ errno = EINVAL + 8195;
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ if (!user || user[0] == (char)0) {
+ user = talloc_strdup(frame, smbc_getUser(context));
+ if (!user) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+ }
+
+ dir = SMB_MALLOC_P(SMBCFILE);
+
+ if (!dir) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ ZERO_STRUCTP(dir);
+
+ dir->cli_fd = 0;
+ dir->fname = SMB_STRDUP(fname);
+ dir->srv = NULL;
+ dir->offset = 0;
+ dir->file = False;
+ dir->dir_list = dir->dir_next = dir->dir_end = NULL;
+
+ if (server[0] == (char)0) {
+
+ int i;
+ int count;
+ int max_lmb_count;
+ struct ip_service *ip_list;
+ struct ip_service server_addr;
+ struct user_auth_info u_info;
+
+ if (share[0] != (char)0 || path[0] != (char)0) {
+
+ errno = EINVAL + 8196;
+ if (dir) {
+ SAFE_FREE(dir->fname);
+ SAFE_FREE(dir);
+ }
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ /* Determine how many local master browsers to query */
+ max_lmb_count = (smbc_getOptionBrowseMaxLmbCount(context) == 0
+ ? INT_MAX
+ : smbc_getOptionBrowseMaxLmbCount(context));
+
+ memset(&u_info, '\0', sizeof(u_info));
+ u_info.username = talloc_strdup(frame,user);
+ u_info.password = talloc_strdup(frame,password);
+ if (!u_info.username || !u_info.password) {
+ if (dir) {
+ SAFE_FREE(dir->fname);
+ SAFE_FREE(dir);
+ }
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ /*
+ * We have server and share and path empty but options
+ * requesting that we scan all master browsers for their list
+ * of workgroups/domains. This implies that we must first try
+ * broadcast queries to find all master browsers, and if that
+ * doesn't work, then try our other methods which return only
+ * a single master browser.
+ */
+
+ ip_list = NULL;
+ if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list,
+ &count)))
+ {
+
+ SAFE_FREE(ip_list);
+
+ if (!find_master_ip(workgroup, &server_addr.ss)) {
+
+ if (dir) {
+ SAFE_FREE(dir->fname);
+ SAFE_FREE(dir);
+ }
+ errno = ENOENT;
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ ip_list = (struct ip_service *)memdup(
+ &server_addr, sizeof(server_addr));
+ if (ip_list == NULL) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+ count = 1;
+ }
+
+ for (i = 0; i < count && i < max_lmb_count; i++) {
+ char addr[INET6_ADDRSTRLEN];
+ char *wg_ptr = NULL;
+ struct cli_state *cli = NULL;
+
+ print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
+ DEBUG(99, ("Found master browser %d of %d: %s\n",
+ i+1, MAX(count, max_lmb_count),
+ addr));
+
+ cli = get_ipc_connect_master_ip(talloc_tos(),
+ &ip_list[i],
+ &u_info,
+ &wg_ptr);
+ /* cli == NULL is the master browser refused to talk or
+ could not be found */
+ if (!cli) {
+ continue;
+ }
+
+ workgroup = talloc_strdup(frame, wg_ptr);
+ server = talloc_strdup(frame, cli->desthost);
+
+ cli_shutdown(cli);
+
+ if (!workgroup || !server) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ DEBUG(4, ("using workgroup %s %s\n",
+ workgroup, server));
+
+ /*
+ * For each returned master browser IP address, get a
+ * connection to IPC$ on the server if we do not
+ * already have one, and determine the
+ * workgroups/domains that it knows about.
+ */
+
+ srv = SMBC_server(frame, context, True, server, "IPC$",
+ &workgroup, &user, &password);
+ if (!srv) {
+ continue;
+ }
+
+ dir->srv = srv;
+ dir->dir_type = SMBC_WORKGROUP;
+
+ /* Now, list the stuff ... */
+
+ if (!cli_NetServerEnum(srv->cli,
+ workgroup,
+ SV_TYPE_DOMAIN_ENUM,
+ list_unique_wg_fn,
+ (void *)dir)) {
+ continue;
+ }
+ }
+
+ SAFE_FREE(ip_list);
+ } else {
+ /*
+ * Server not an empty string ... Check the rest and see what
+ * gives
+ */
+ if (*share == '\0') {
+ if (*path != '\0') {
+
+ /* Should not have empty share with path */
+ errno = EINVAL + 8197;
+ if (dir) {
+ SAFE_FREE(dir->fname);
+ SAFE_FREE(dir);
+ }
+ TALLOC_FREE(frame);
+ return NULL;
+
+ }
+
+ /*
+ * We don't know if <server> is really a server name
+ * or is a workgroup/domain name. If we already have
+ * a server structure for it, we'll use it.
+ * Otherwise, check to see if <server><1D>,
+ * <server><1B>, or <server><20> translates. We check
+ * to see if <server> is an IP address first.
+ */
+
+ /*
+ * See if we have an existing server. Do not
+ * establish a connection if one does not already
+ * exist.
+ */
+ srv = SMBC_server(frame, context, False,
+ server, "IPC$",
+ &workgroup, &user, &password);
+
+ /*
+ * If no existing server and not an IP addr, look for
+ * LMB or DMB
+ */
+ if (!srv &&
+ !is_ipaddress(server) &&
+ (resolve_name(server, &rem_ss, 0x1d) || /* LMB */
+ resolve_name(server, &rem_ss, 0x1b) )) { /* DMB */
+
+ fstring buserver;
+
+ dir->dir_type = SMBC_SERVER;
+
+ /*
+ * Get the backup list ...
+ */
+ if (!name_status_find(server, 0, 0,
+ &rem_ss, buserver)) {
+
+ DEBUG(0,("Could not get name of "
+ "local/domain master browser "
+ "for server %s\n", server));
+ if (dir) {
+ SAFE_FREE(dir->fname);
+ SAFE_FREE(dir);
+ }
+ errno = EPERM;
+ TALLOC_FREE(frame);
+ return NULL;
+
+ }
+
+ /*
+ * Get a connection to IPC$ on the server if
+ * we do not already have one
+ */
+ srv = SMBC_server(frame, context, True,
+ buserver, "IPC$",
+ &workgroup,
+ &user, &password);
+ if (!srv) {
+ DEBUG(0, ("got no contact to IPC$\n"));
+ if (dir) {
+ SAFE_FREE(dir->fname);
+ SAFE_FREE(dir);
+ }
+ TALLOC_FREE(frame);
+ return NULL;
+
+ }
+
+ dir->srv = srv;
+
+ /* Now, list the servers ... */
+ if (!cli_NetServerEnum(srv->cli, server,
+ 0x0000FFFE, list_fn,
+ (void *)dir)) {
+
+ if (dir) {
+ SAFE_FREE(dir->fname);
+ SAFE_FREE(dir);
+ }
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+ } else if (srv ||
+ (resolve_name(server, &rem_ss, 0x20))) {
+
+ /*
+ * If we hadn't found the server, get one now
+ */
+ if (!srv) {
+ srv = SMBC_server(frame, context, True,
+ server, "IPC$",
+ &workgroup,
+ &user, &password);
+ }
+
+ if (!srv) {
+ if (dir) {
+ SAFE_FREE(dir->fname);
+ SAFE_FREE(dir);
+ }
+ TALLOC_FREE(frame);
+ return NULL;
+
+ }
+
+ dir->dir_type = SMBC_FILE_SHARE;
+ dir->srv = srv;
+
+ /* List the shares ... */
+
+ if (net_share_enum_rpc(
+ srv->cli,
+ list_fn,
+ (void *) dir) < 0 &&
+ cli_RNetShareEnum(
+ srv->cli,
+ list_fn,
+ (void *)dir) < 0) {
+
+ errno = cli_errno(srv->cli);
+ if (dir) {
+ SAFE_FREE(dir->fname);
+ SAFE_FREE(dir);
+ }
+ TALLOC_FREE(frame);
+ return NULL;
+
+ }
+ } else {
+ /* Neither the workgroup nor server exists */
+ errno = ECONNREFUSED;
+ if (dir) {
+ SAFE_FREE(dir->fname);
+ SAFE_FREE(dir);
+ }
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ }
+ else {
+ /*
+ * The server and share are specified ... work from
+ * there ...
+ */
+ char *targetpath;
+ struct cli_state *targetcli;
+
+ /* We connect to the server and list the directory */
+ dir->dir_type = SMBC_FILE_SHARE;
+
+ srv = SMBC_server(frame, context, True, server, share,
+ &workgroup, &user, &password);
+
+ if (!srv) {
+ if (dir) {
+ SAFE_FREE(dir->fname);
+ SAFE_FREE(dir);
+ }
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ dir->srv = srv;
+
+ /* Now, list the files ... */
+
+ p = path + strlen(path);
+ path = talloc_asprintf_append(path, "\\*");
+ if (!path) {
+ if (dir) {
+ SAFE_FREE(dir->fname);
+ SAFE_FREE(dir);
+ }
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ if (!cli_resolve_path(frame, "", srv->cli, path,
+ &targetcli, &targetpath)) {
+ d_printf("Could not resolve %s\n", path);
+ if (dir) {
+ SAFE_FREE(dir->fname);
+ SAFE_FREE(dir);
+ }
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ if (cli_list(targetcli, targetpath,
+ aDIR | aSYSTEM | aHIDDEN,
+ dir_list_fn, (void *)dir) < 0) {
+
+ if (dir) {
+ SAFE_FREE(dir->fname);
+ SAFE_FREE(dir);
+ }
+ saved_errno = SMBC_errno(context, targetcli);
+
+ if (saved_errno == EINVAL) {
+ /*
+ * See if they asked to opendir
+ * something other than a directory.
+ * If so, the converted error value we
+ * got would have been EINVAL rather
+ * than ENOTDIR.
+ */
+ *p = '\0'; /* restore original path */
+
+ if (SMBC_getatr(context, srv, path,
+ &mode, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL) &&
+ ! IS_DOS_DIR(mode)) {
+
+ /* It is. Correct the error value */
+ saved_errno = ENOTDIR;
+ }
+ }
+
+ /*
+ * If there was an error and the server is no
+ * good any more...
+ */
+ if (cli_is_error(targetcli) &&
+ smbc_getFunctionCheckServer(context)(context, srv)) {
+
+ /* ... then remove it. */
+ if (smbc_getFunctionRemoveUnusedServer(context)(context,
+ srv)) {
+ /*
+ * We could not remove the
+ * server completely, remove
+ * it from the cache so we
+ * will not get it again. It
+ * will be removed when the
+ * last file/dir is closed.
+ */
+ smbc_getFunctionRemoveCachedServer(context)(context, srv);
+ }
+ }
+
+ errno = saved_errno;
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+ }
+
+ }
+
+ DLIST_ADD(context->internal->files, dir);
+ TALLOC_FREE(frame);
+ return dir;
+
+}
+
+/*
+ * Routine to close a directory
+ */
+
+int
+SMBC_closedir_ctx(SMBCCTX *context,
+ SMBCFILE *dir)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
+ errno = EBADF;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ remove_dir(dir); /* Clean it up */
+
+ DLIST_REMOVE(context->internal->files, dir);
+
+ if (dir) {
+
+ SAFE_FREE(dir->fname);
+ SAFE_FREE(dir); /* Free the space too */
+ }
+
+ TALLOC_FREE(frame);
+ return 0;
+
+}
+
+static void
+smbc_readdir_internal(SMBCCTX * context,
+ struct smbc_dirent *dest,
+ struct smbc_dirent *src,
+ int max_namebuf_len)
+{
+ if (smbc_getOptionUrlEncodeReaddirEntries(context)) {
+
+ /* url-encode the name. get back remaining buffer space */
+ max_namebuf_len =
+ SMBC_urlencode(dest->name, src->name, max_namebuf_len);
+
+ /* We now know the name length */
+ dest->namelen = strlen(dest->name);
+
+ /* Save the pointer to the beginning of the comment */
+ dest->comment = dest->name + dest->namelen + 1;
+
+ /* Copy the comment */
+ strncpy(dest->comment, src->comment, max_namebuf_len - 1);
+ dest->comment[max_namebuf_len - 1] = '\0';
+
+ /* Save other fields */
+ dest->smbc_type = src->smbc_type;
+ dest->commentlen = strlen(dest->comment);
+ dest->dirlen = ((dest->comment + dest->commentlen + 1) -
+ (char *) dest);
+ } else {
+
+ /* No encoding. Just copy the entry as is. */
+ memcpy(dest, src, src->dirlen);
+ dest->comment = (char *)(&dest->name + src->namelen + 1);
+ }
+
+}
+
+/*
+ * Routine to get a directory entry
+ */
+
+struct smbc_dirent *
+SMBC_readdir_ctx(SMBCCTX *context,
+ SMBCFILE *dir)
+{
+ int maxlen;
+ struct smbc_dirent *dirp, *dirent;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ /* Check that all is ok first ... */
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ DEBUG(0, ("Invalid context in SMBC_readdir_ctx()\n"));
+ TALLOC_FREE(frame);
+ return NULL;
+
+ }
+
+ if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
+
+ errno = EBADF;
+ DEBUG(0, ("Invalid dir in SMBC_readdir_ctx()\n"));
+ TALLOC_FREE(frame);
+ return NULL;
+
+ }
+
+ if (dir->file != False) { /* FIXME, should be dir, perhaps */
+
+ errno = ENOTDIR;
+ DEBUG(0, ("Found file vs directory in SMBC_readdir_ctx()\n"));
+ TALLOC_FREE(frame);
+ return NULL;
+
+ }
+
+ if (!dir->dir_next) {
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ dirent = dir->dir_next->dirent;
+ if (!dirent) {
+
+ errno = ENOENT;
+ TALLOC_FREE(frame);
+ return NULL;
+
+ }
+
+ dirp = (struct smbc_dirent *)context->internal->dirent;
+ maxlen = (sizeof(context->internal->dirent) -
+ sizeof(struct smbc_dirent));
+
+ smbc_readdir_internal(context, dirp, dirent, maxlen);
+
+ dir->dir_next = dir->dir_next->next;
+
+ TALLOC_FREE(frame);
+ return dirp;
+}
+
+/*
+ * Routine to get directory entries
+ */
+
+int
+SMBC_getdents_ctx(SMBCCTX *context,
+ SMBCFILE *dir,
+ struct smbc_dirent *dirp,
+ int count)
+{
+ int rem = count;
+ int reqd;
+ int maxlen;
+ char *ndir = (char *)dirp;
+ struct smbc_dir_list *dirlist;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ /* Check that all is ok first ... */
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
+
+ errno = EBADF;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ if (dir->file != False) { /* FIXME, should be dir, perhaps */
+
+ errno = ENOTDIR;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ /*
+ * Now, retrieve the number of entries that will fit in what was passed
+ * We have to figure out if the info is in the list, or we need to
+ * send a request to the server to get the info.
+ */
+
+ while ((dirlist = dir->dir_next)) {
+ struct smbc_dirent *dirent;
+
+ if (!dirlist->dirent) {
+
+ errno = ENOENT; /* Bad error */
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ /* Do urlencoding of next entry, if so selected */
+ dirent = (struct smbc_dirent *)context->internal->dirent;
+ maxlen = (sizeof(context->internal->dirent) -
+ sizeof(struct smbc_dirent));
+ smbc_readdir_internal(context, dirent,
+ dirlist->dirent, maxlen);
+
+ reqd = dirent->dirlen;
+
+ if (rem < reqd) {
+
+ if (rem < count) { /* We managed to copy something */
+
+ errno = 0;
+ TALLOC_FREE(frame);
+ return count - rem;
+
+ }
+ else { /* Nothing copied ... */
+
+ errno = EINVAL; /* Not enough space ... */
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ }
+
+ memcpy(ndir, dirent, reqd); /* Copy the data in ... */
+
+ ((struct smbc_dirent *)ndir)->comment =
+ (char *)(&((struct smbc_dirent *)ndir)->name +
+ dirent->namelen +
+ 1);
+
+ ndir += reqd;
+
+ rem -= reqd;
+
+ dir->dir_next = dirlist = dirlist -> next;
+ }
+
+ TALLOC_FREE(frame);
+
+ if (rem == count)
+ return 0;
+ else
+ return count - rem;
+
+}
+
+/*
+ * Routine to create a directory ...
+ */
+
+int
+SMBC_mkdir_ctx(SMBCCTX *context,
+ const char *fname,
+ mode_t mode)
+{
+ SMBCSRV *srv = NULL;
+ char *server = NULL;
+ char *share = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *workgroup = NULL;
+ char *path = NULL;
+ char *targetpath = NULL;
+ struct cli_state *targetcli = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!fname) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ DEBUG(4, ("smbc_mkdir(%s)\n", fname));
+
+ if (SMBC_parse_path(frame,
+ context,
+ fname,
+ &workgroup,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!user || user[0] == (char)0) {
+ user = talloc_strdup(frame, smbc_getUser(context));
+ if (!user) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ }
+
+ srv = SMBC_server(frame, context, True,
+ server, share, &workgroup, &user, &password);
+
+ if (!srv) {
+
+ TALLOC_FREE(frame);
+ return -1; /* errno set by SMBC_server */
+
+ }
+
+ /*d_printf(">>>mkdir: resolving %s\n", path);*/
+ if (!cli_resolve_path(frame, "", srv->cli, path,
+ &targetcli, &targetpath)) {
+ d_printf("Could not resolve %s\n", path);
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/
+
+ if (!cli_mkdir(targetcli, targetpath)) {
+
+ errno = SMBC_errno(context, targetcli);
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ TALLOC_FREE(frame);
+ return 0;
+
+}
+
+/*
+ * Our list function simply checks to see if a directory is not empty
+ */
+
+static int smbc_rmdir_dirempty = True;
+
+static void
+rmdir_list_fn(const char *mnt,
+ file_info *finfo,
+ const char *mask,
+ void *state)
+{
+ if (strncmp(finfo->name, ".", 1) != 0 &&
+ strncmp(finfo->name, "..", 2) != 0) {
+ smbc_rmdir_dirempty = False;
+ }
+}
+
+/*
+ * Routine to remove a directory
+ */
+
+int
+SMBC_rmdir_ctx(SMBCCTX *context,
+ const char *fname)
+{
+ SMBCSRV *srv = NULL;
+ char *server = NULL;
+ char *share = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *workgroup = NULL;
+ char *path = NULL;
+ char *targetpath = NULL;
+ struct cli_state *targetcli = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!fname) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ DEBUG(4, ("smbc_rmdir(%s)\n", fname));
+
+ if (SMBC_parse_path(frame,
+ context,
+ fname,
+ &workgroup,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!user || user[0] == (char)0) {
+ user = talloc_strdup(frame, smbc_getUser(context));
+ if (!user) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ }
+
+ srv = SMBC_server(frame, context, True,
+ server, share, &workgroup, &user, &password);
+
+ if (!srv) {
+
+ TALLOC_FREE(frame);
+ return -1; /* errno set by SMBC_server */
+
+ }
+
+ /*d_printf(">>>rmdir: resolving %s\n", path);*/
+ if (!cli_resolve_path(frame, "", srv->cli, path,
+ &targetcli, &targetpath)) {
+ d_printf("Could not resolve %s\n", path);
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/
+
+
+ if (!cli_rmdir(targetcli, targetpath)) {
+
+ errno = SMBC_errno(context, targetcli);
+
+ if (errno == EACCES) { /* Check if the dir empty or not */
+
+ /* Local storage to avoid buffer overflows */
+ char *lpath;
+
+ smbc_rmdir_dirempty = True; /* Make this so ... */
+
+ lpath = talloc_asprintf(frame, "%s\\*",
+ targetpath);
+ if (!lpath) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (cli_list(targetcli, lpath,
+ aDIR | aSYSTEM | aHIDDEN,
+ rmdir_list_fn, NULL) < 0) {
+
+ /* Fix errno to ignore latest error ... */
+ DEBUG(5, ("smbc_rmdir: "
+ "cli_list returned an error: %d\n",
+ SMBC_errno(context, targetcli)));
+ errno = EACCES;
+
+ }
+
+ if (smbc_rmdir_dirempty)
+ errno = EACCES;
+ else
+ errno = ENOTEMPTY;
+
+ }
+
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ TALLOC_FREE(frame);
+ return 0;
+
+}
+
+/*
+ * Routine to return the current directory position
+ */
+
+off_t
+SMBC_telldir_ctx(SMBCCTX *context,
+ SMBCFILE *dir)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
+
+ errno = EBADF;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ if (dir->file != False) { /* FIXME, should be dir, perhaps */
+
+ errno = ENOTDIR;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ /* See if we're already at the end. */
+ if (dir->dir_next == NULL) {
+ /* We are. */
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ /*
+ * We return the pointer here as the offset
+ */
+ TALLOC_FREE(frame);
+ return (off_t)(long)dir->dir_next->dirent;
+}
+
+/*
+ * A routine to run down the list and see if the entry is OK
+ */
+
+static struct smbc_dir_list *
+check_dir_ent(struct smbc_dir_list *list,
+ struct smbc_dirent *dirent)
+{
+
+ /* Run down the list looking for what we want */
+
+ if (dirent) {
+
+ struct smbc_dir_list *tmp = list;
+
+ while (tmp) {
+
+ if (tmp->dirent == dirent)
+ return tmp;
+
+ tmp = tmp->next;
+
+ }
+
+ }
+
+ return NULL; /* Not found, or an error */
+
+}
+
+
+/*
+ * Routine to seek on a directory
+ */
+
+int
+SMBC_lseekdir_ctx(SMBCCTX *context,
+ SMBCFILE *dir,
+ off_t offset)
+{
+ long int l_offset = offset; /* Handle problems of size */
+ struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset;
+ struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ if (dir->file != False) { /* FIXME, should be dir, perhaps */
+
+ errno = ENOTDIR;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ /* Now, check what we were passed and see if it is OK ... */
+
+ if (dirent == NULL) { /* Seek to the begining of the list */
+
+ dir->dir_next = dir->dir_list;
+ TALLOC_FREE(frame);
+ return 0;
+
+ }
+
+ if (offset == -1) { /* Seek to the end of the list */
+ dir->dir_next = NULL;
+ TALLOC_FREE(frame);
+ return 0;
+ }
+
+ /* Now, run down the list and make sure that the entry is OK */
+ /* This may need to be changed if we change the format of the list */
+
+ if ((list_ent = check_dir_ent(dir->dir_list, dirent)) == NULL) {
+ errno = EINVAL; /* Bad entry */
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ dir->dir_next = list_ent;
+
+ TALLOC_FREE(frame);
+ return 0;
+}
+
+/*
+ * Routine to fstat a dir
+ */
+
+int
+SMBC_fstatdir_ctx(SMBCCTX *context,
+ SMBCFILE *dir,
+ struct stat *st)
+{
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* No code yet ... */
+ return 0;
+}
+
+int
+SMBC_chmod_ctx(SMBCCTX *context,
+ const char *fname,
+ mode_t newmode)
+{
+ SMBCSRV *srv = NULL;
+ char *server = NULL;
+ char *share = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *workgroup = NULL;
+ char *path = NULL;
+ uint16 mode;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!fname) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, newmode));
+
+ if (SMBC_parse_path(frame,
+ context,
+ fname,
+ &workgroup,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!user || user[0] == (char)0) {
+ user = talloc_strdup(frame, smbc_getUser(context));
+ if (!user) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ }
+
+ srv = SMBC_server(frame, context, True,
+ server, share, &workgroup, &user, &password);
+
+ if (!srv) {
+ TALLOC_FREE(frame);
+ return -1; /* errno set by SMBC_server */
+ }
+
+ mode = 0;
+
+ if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY;
+ if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH;
+ if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM;
+ if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN;
+
+ if (!cli_setatr(srv->cli, path, mode, 0)) {
+ errno = SMBC_errno(context, srv->cli);
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ TALLOC_FREE(frame);
+ return 0;
+}
+
+int
+SMBC_utimes_ctx(SMBCCTX *context,
+ const char *fname,
+ struct timeval *tbuf)
+{
+ SMBCSRV *srv = NULL;
+ char *server = NULL;
+ char *share = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *workgroup = NULL;
+ char *path = NULL;
+ time_t access_time;
+ time_t write_time;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!fname) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (tbuf == NULL) {
+ access_time = write_time = time(NULL);
+ } else {
+ access_time = tbuf[0].tv_sec;
+ write_time = tbuf[1].tv_sec;
+ }
+
+ if (DEBUGLVL(4)) {
+ char *p;
+ char atimebuf[32];
+ char mtimebuf[32];
+
+ strncpy(atimebuf, ctime(&access_time), sizeof(atimebuf) - 1);
+ atimebuf[sizeof(atimebuf) - 1] = '\0';
+ if ((p = strchr(atimebuf, '\n')) != NULL) {
+ *p = '\0';
+ }
+
+ strncpy(mtimebuf, ctime(&write_time), sizeof(mtimebuf) - 1);
+ mtimebuf[sizeof(mtimebuf) - 1] = '\0';
+ if ((p = strchr(mtimebuf, '\n')) != NULL) {
+ *p = '\0';
+ }
+
+ dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n",
+ fname, atimebuf, mtimebuf);
+ }
+
+ if (SMBC_parse_path(frame,
+ context,
+ fname,
+ &workgroup,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!user || user[0] == (char)0) {
+ user = talloc_strdup(frame, smbc_getUser(context));
+ if (!user) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ }
+
+ srv = SMBC_server(frame, context, True,
+ server, share, &workgroup, &user, &password);
+
+ if (!srv) {
+ TALLOC_FREE(frame);
+ return -1; /* errno set by SMBC_server */
+ }
+
+ if (!SMBC_setatr(context, srv, path,
+ 0, access_time, write_time, 0, 0)) {
+ TALLOC_FREE(frame);
+ return -1; /* errno set by SMBC_setatr */
+ }
+
+ TALLOC_FREE(frame);
+ return 0;
+}
+
+/*
+ * Routine to unlink() a file
+ */
+
+int
+SMBC_unlink_ctx(SMBCCTX *context,
+ const char *fname)
+{
+ char *server = NULL;
+ char *share = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *workgroup = NULL;
+ char *path = NULL;
+ char *targetpath = NULL;
+ struct cli_state *targetcli = NULL;
+ SMBCSRV *srv = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ if (!fname) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ if (SMBC_parse_path(frame,
+ context,
+ fname,
+ &workgroup,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!user || user[0] == (char)0) {
+ user = talloc_strdup(frame, smbc_getUser(context));
+ if (!user) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ }
+
+ srv = SMBC_server(frame, context, True,
+ server, share, &workgroup, &user, &password);
+
+ if (!srv) {
+ TALLOC_FREE(frame);
+ return -1; /* SMBC_server sets errno */
+
+ }
+
+ /*d_printf(">>>unlink: resolving %s\n", path);*/
+ if (!cli_resolve_path(frame, "", srv->cli, path,
+ &targetcli, &targetpath)) {
+ d_printf("Could not resolve %s\n", path);
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/
+
+ if (!cli_unlink(targetcli, targetpath)) {
+
+ errno = SMBC_errno(context, targetcli);
+
+ if (errno == EACCES) { /* Check if the file is a directory */
+
+ int saverr = errno;
+ SMB_OFF_T size = 0;
+ uint16 mode = 0;
+ struct timespec write_time_ts;
+ struct timespec access_time_ts;
+ struct timespec change_time_ts;
+ SMB_INO_T ino = 0;
+
+ if (!SMBC_getatr(context, srv, path, &mode, &size,
+ NULL,
+ &access_time_ts,
+ &write_time_ts,
+ &change_time_ts,
+ &ino)) {
+
+ /* Hmmm, bad error ... What? */
+
+ errno = SMBC_errno(context, targetcli);
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+ else {
+
+ if (IS_DOS_DIR(mode))
+ errno = EISDIR;
+ else
+ errno = saverr; /* Restore this */
+
+ }
+ }
+
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ TALLOC_FREE(frame);
+ return 0; /* Success ... */
+
+}
+
+/*
+ * Routine to rename() a file
+ */
+
+int
+SMBC_rename_ctx(SMBCCTX *ocontext,
+ const char *oname,
+ SMBCCTX *ncontext,
+ const char *nname)
+{
+ char *server1 = NULL;
+ char *share1 = NULL;
+ char *server2 = NULL;
+ char *share2 = NULL;
+ char *user1 = NULL;
+ char *user2 = NULL;
+ char *password1 = NULL;
+ char *password2 = NULL;
+ char *workgroup = NULL;
+ char *path1 = NULL;
+ char *path2 = NULL;
+ char *targetpath1 = NULL;
+ char *targetpath2 = NULL;
+ struct cli_state *targetcli1 = NULL;
+ struct cli_state *targetcli2 = NULL;
+ SMBCSRV *srv = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!ocontext || !ncontext ||
+ !ocontext->internal->initialized ||
+ !ncontext->internal->initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!oname || !nname) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
+
+ if (SMBC_parse_path(frame,
+ ocontext,
+ oname,
+ &workgroup,
+ &server1,
+ &share1,
+ &path1,
+ &user1,
+ &password1,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!user1 || user1[0] == (char)0) {
+ user1 = talloc_strdup(frame, smbc_getUser(ocontext));
+ if (!user1) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ }
+
+ if (SMBC_parse_path(frame,
+ ncontext,
+ nname,
+ NULL,
+ &server2,
+ &share2,
+ &path2,
+ &user2,
+ &password2,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!user2 || user2[0] == (char)0) {
+ user2 = talloc_strdup(frame, smbc_getUser(ncontext));
+ if (!user2) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ }
+
+ if (strcmp(server1, server2) || strcmp(share1, share2) ||
+ strcmp(user1, user2)) {
+ /* Can't rename across file systems, or users?? */
+ errno = EXDEV;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ srv = SMBC_server(frame, ocontext, True,
+ server1, share1, &workgroup, &user1, &password1);
+ if (!srv) {
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ /*d_printf(">>>rename: resolving %s\n", path1);*/
+ if (!cli_resolve_path(frame, "", srv->cli, path1,
+ &targetcli1, &targetpath1)) {
+ d_printf("Could not resolve %s\n", path1);
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/
+ /*d_printf(">>>rename: resolving %s\n", path2);*/
+ if (!cli_resolve_path(frame, "", srv->cli, path2,
+ &targetcli2, &targetpath2)) {
+ d_printf("Could not resolve %s\n", path2);
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/
+
+ if (strcmp(targetcli1->desthost, targetcli2->desthost) ||
+ strcmp(targetcli1->share, targetcli2->share))
+ {
+ /* can't rename across file systems */
+ errno = EXDEV;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!cli_rename(targetcli1, targetpath1, targetpath2)) {
+ int eno = SMBC_errno(ocontext, targetcli1);
+
+ if (eno != EEXIST ||
+ !cli_unlink(targetcli1, targetpath2) ||
+ !cli_rename(targetcli1, targetpath1, targetpath2)) {
+
+ errno = eno;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+ }
+
+ TALLOC_FREE(frame);
+ return 0; /* Success */
+}
+
diff --git a/source3/libsmb/libsmb_file.c b/source3/libsmb/libsmb_file.c
new file mode 100644
index 0000000000..7b287096c2
--- /dev/null
+++ b/source3/libsmb/libsmb_file.c
@@ -0,0 +1,864 @@
+/*
+ Unix SMB/Netbios implementation.
+ SMB client library implementation
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000, 2002
+ Copyright (C) John Terpstra 2000
+ Copyright (C) Tom Jansen (Ninja ISD) 2002
+ Copyright (C) Derrell Lipman 2003-2008
+ Copyright (C) Jeremy Allison 2007, 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libsmbclient.h"
+#include "libsmb_internal.h"
+
+
+/*
+ * Routine to open() a file ...
+ */
+
+SMBCFILE *
+SMBC_open_ctx(SMBCCTX *context,
+ const char *fname,
+ int flags,
+ mode_t mode)
+{
+ char *server = NULL;
+ char *share = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *workgroup = NULL;
+ char *path = NULL;
+ char *targetpath = NULL;
+ struct cli_state *targetcli = NULL;
+ SMBCSRV *srv = NULL;
+ SMBCFILE *file = NULL;
+ int fd;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ TALLOC_FREE(frame);
+ return NULL;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return NULL;
+
+ }
+
+ if (SMBC_parse_path(frame,
+ context,
+ fname,
+ &workgroup,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ if (!user || user[0] == (char)0) {
+ user = talloc_strdup(frame, smbc_getUser(context));
+ if (!user) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+ }
+
+ srv = SMBC_server(frame, context, True,
+ server, share, &workgroup, &user, &password);
+
+ if (!srv) {
+ if (errno == EPERM) errno = EACCES;
+ TALLOC_FREE(frame);
+ return NULL; /* SMBC_server sets errno */
+ }
+
+ /* Hmmm, the test for a directory is suspect here ... FIXME */
+
+ if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') {
+ fd = -1;
+ } else {
+ file = SMB_MALLOC_P(SMBCFILE);
+
+ if (!file) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ ZERO_STRUCTP(file);
+
+ /*d_printf(">>>open: resolving %s\n", path);*/
+ if (!cli_resolve_path(frame, "", srv->cli, path,
+ &targetcli, &targetpath)) {
+ d_printf("Could not resolve %s\n", path);
+ SAFE_FREE(file);
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+ /*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/
+
+ if ((fd = cli_open(targetcli, targetpath, flags,
+ context->internal->share_mode)) < 0) {
+
+ /* Handle the error ... */
+
+ SAFE_FREE(file);
+ errno = SMBC_errno(context, targetcli);
+ TALLOC_FREE(frame);
+ return NULL;
+
+ }
+
+ /* Fill in file struct */
+
+ file->cli_fd = fd;
+ file->fname = SMB_STRDUP(fname);
+ file->srv = srv;
+ file->offset = 0;
+ file->file = True;
+
+ DLIST_ADD(context->internal->files, file);
+
+ /*
+ * If the file was opened in O_APPEND mode, all write
+ * operations should be appended to the file. To do that,
+ * though, using this protocol, would require a getattrE()
+ * call for each and every write, to determine where the end
+ * of the file is. (There does not appear to be an append flag
+ * in the protocol.) Rather than add all of that overhead of
+ * retrieving the current end-of-file offset prior to each
+ * write operation, we'll assume that most append operations
+ * will continuously write, so we'll just set the offset to
+ * the end of the file now and hope that's adequate.
+ *
+ * Note to self: If this proves inadequate, and O_APPEND
+ * should, in some cases, be forced for each write, add a
+ * field in the context options structure, for
+ * "strict_append_mode" which would select between the current
+ * behavior (if FALSE) or issuing a getattrE() prior to each
+ * write and forcing the write to the end of the file (if
+ * TRUE). Adding that capability will likely require adding
+ * an "append" flag into the _SMBCFILE structure to track
+ * whether a file was opened in O_APPEND mode. -- djl
+ */
+ if (flags & O_APPEND) {
+ if (SMBC_lseek_ctx(context, file, 0, SEEK_END) < 0) {
+ (void) SMBC_close_ctx(context, file);
+ errno = ENXIO;
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+ }
+
+ TALLOC_FREE(frame);
+ return file;
+
+ }
+
+ /* Check if opendir needed ... */
+
+ if (fd == -1) {
+ int eno = 0;
+
+ eno = SMBC_errno(context, srv->cli);
+ file = smbc_getFunctionOpendir(context)(context, fname);
+ if (!file) errno = eno;
+ TALLOC_FREE(frame);
+ return file;
+
+ }
+
+ errno = EINVAL; /* FIXME, correct errno ? */
+ TALLOC_FREE(frame);
+ return NULL;
+
+}
+
+/*
+ * Routine to create a file
+ */
+
+SMBCFILE *
+SMBC_creat_ctx(SMBCCTX *context,
+ const char *path,
+ mode_t mode)
+{
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ return NULL;
+
+ }
+
+ return SMBC_open_ctx(context, path,
+ O_WRONLY | O_CREAT | O_TRUNC, mode);
+}
+
+/*
+ * Routine to read() a file ...
+ */
+
+ssize_t
+SMBC_read_ctx(SMBCCTX *context,
+ SMBCFILE *file,
+ void *buf,
+ size_t count)
+{
+ int ret;
+ char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
+ char *path = NULL;
+ char *targetpath = NULL;
+ struct cli_state *targetcli = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ /*
+ * offset:
+ *
+ * Compiler bug (possibly) -- gcc (GCC) 3.3.5 (Debian 1:3.3.5-2) --
+ * appears to pass file->offset (which is type off_t) differently than
+ * a local variable of type off_t. Using local variable "offset" in
+ * the call to cli_read() instead of file->offset fixes a problem
+ * retrieving data at an offset greater than 4GB.
+ */
+ off_t offset;
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count));
+
+ if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
+ errno = EBADF;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ offset = file->offset;
+
+ /* Check that the buffer exists ... */
+
+ if (buf == NULL) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ /*d_printf(">>>read: parsing %s\n", file->fname);*/
+ if (SMBC_parse_path(frame,
+ context,
+ file->fname,
+ NULL,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ /*d_printf(">>>read: resolving %s\n", path);*/
+ if (!cli_resolve_path(frame, "", file->srv->cli, path,
+ &targetcli, &targetpath)) {
+ d_printf("Could not resolve %s\n", path);
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
+
+ ret = cli_read(targetcli, file->cli_fd, (char *)buf, offset, count);
+
+ if (ret < 0) {
+
+ errno = SMBC_errno(context, targetcli);
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ file->offset += ret;
+
+ DEBUG(4, (" --> %d\n", ret));
+
+ TALLOC_FREE(frame);
+ return ret; /* Success, ret bytes of data ... */
+
+}
+
+/*
+ * Routine to write() a file ...
+ */
+
+ssize_t
+SMBC_write_ctx(SMBCCTX *context,
+ SMBCFILE *file,
+ const void *buf,
+ size_t count)
+{
+ int ret;
+ off_t offset;
+ char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
+ char *path = NULL;
+ char *targetpath = NULL;
+ struct cli_state *targetcli = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ /* First check all pointers before dereferencing them */
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
+ errno = EBADF;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ /* Check that the buffer exists ... */
+
+ if (buf == NULL) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ offset = file->offset; /* See "offset" comment in SMBC_read_ctx() */
+
+ /*d_printf(">>>write: parsing %s\n", file->fname);*/
+ if (SMBC_parse_path(frame,
+ context,
+ file->fname,
+ NULL,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ /*d_printf(">>>write: resolving %s\n", path);*/
+ if (!cli_resolve_path(frame, "", file->srv->cli, path,
+ &targetcli, &targetpath)) {
+ d_printf("Could not resolve %s\n", path);
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ /*d_printf(">>>write: resolved path as %s\n", targetpath);*/
+
+ ret = cli_write(targetcli, file->cli_fd,
+ 0, (char *)buf, offset, count);
+
+ if (ret <= 0) {
+ errno = SMBC_errno(context, targetcli);
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ file->offset += ret;
+
+ TALLOC_FREE(frame);
+ return ret; /* Success, 0 bytes of data ... */
+}
+
+/*
+ * Routine to close() a file ...
+ */
+
+int
+SMBC_close_ctx(SMBCCTX *context,
+ SMBCFILE *file)
+{
+ SMBCSRV *srv;
+ char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
+ char *path = NULL;
+ char *targetpath = NULL;
+ struct cli_state *targetcli = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
+ errno = EBADF;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ /* IS a dir ... */
+ if (!file->file) {
+ TALLOC_FREE(frame);
+ return smbc_getFunctionClosedir(context)(context, file);
+ }
+
+ /*d_printf(">>>close: parsing %s\n", file->fname);*/
+ if (SMBC_parse_path(frame,
+ context,
+ file->fname,
+ NULL,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ /*d_printf(">>>close: resolving %s\n", path);*/
+ if (!cli_resolve_path(frame, "", file->srv->cli, path,
+ &targetcli, &targetpath)) {
+ d_printf("Could not resolve %s\n", path);
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ /*d_printf(">>>close: resolved path as %s\n", targetpath);*/
+
+ if (!cli_close(targetcli, file->cli_fd)) {
+
+ DEBUG(3, ("cli_close failed on %s. purging server.\n",
+ file->fname));
+ /* Deallocate slot and remove the server
+ * from the server cache if unused */
+ errno = SMBC_errno(context, targetcli);
+ srv = file->srv;
+ DLIST_REMOVE(context->internal->files, file);
+ SAFE_FREE(file->fname);
+ SAFE_FREE(file);
+ smbc_getFunctionRemoveUnusedServer(context)(context, srv);
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ DLIST_REMOVE(context->internal->files, file);
+ SAFE_FREE(file->fname);
+ SAFE_FREE(file);
+ TALLOC_FREE(frame);
+
+ return 0;
+}
+
+/*
+ * Get info from an SMB server on a file. Use a qpathinfo call first
+ * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo
+ */
+bool
+SMBC_getatr(SMBCCTX * context,
+ SMBCSRV *srv,
+ char *path,
+ uint16 *mode,
+ SMB_OFF_T *size,
+ struct timespec *create_time_ts,
+ struct timespec *access_time_ts,
+ struct timespec *write_time_ts,
+ struct timespec *change_time_ts,
+ SMB_INO_T *ino)
+{
+ char *fixedpath = NULL;
+ char *targetpath = NULL;
+ struct cli_state *targetcli = NULL;
+ time_t write_time;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ /* path fixup for . and .. */
+ if (strequal(path, ".") || strequal(path, "..")) {
+ fixedpath = talloc_strdup(frame, "\\");
+ if (!fixedpath) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ } else {
+ fixedpath = talloc_strdup(frame, path);
+ if (!fixedpath) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ trim_string(fixedpath, NULL, "\\..");
+ trim_string(fixedpath, NULL, "\\.");
+ }
+ DEBUG(4,("SMBC_getatr: sending qpathinfo\n"));
+
+ if (!cli_resolve_path(frame, "", srv->cli, fixedpath,
+ &targetcli, &targetpath)) {
+ d_printf("Couldn't resolve %s\n", path);
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ if (!srv->no_pathinfo2 &&
+ cli_qpathinfo2(targetcli, targetpath,
+ create_time_ts,
+ access_time_ts,
+ write_time_ts,
+ change_time_ts,
+ size, mode, ino)) {
+ TALLOC_FREE(frame);
+ return True;
+ }
+
+ /* if this is NT then don't bother with the getatr */
+ if (targetcli->capabilities & CAP_NT_SMBS) {
+ errno = EPERM;
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ if (cli_getatr(targetcli, targetpath, mode, size, &write_time)) {
+
+ struct timespec w_time_ts;
+
+ w_time_ts = convert_time_t_to_timespec(write_time);
+
+ if (write_time_ts != NULL) {
+ *write_time_ts = w_time_ts;
+ }
+
+ if (create_time_ts != NULL) {
+ *create_time_ts = w_time_ts;
+ }
+
+ if (access_time_ts != NULL) {
+ *access_time_ts = w_time_ts;
+ }
+
+ if (change_time_ts != NULL) {
+ *change_time_ts = w_time_ts;
+ }
+
+ srv->no_pathinfo2 = True;
+ TALLOC_FREE(frame);
+ return True;
+ }
+
+ errno = EPERM;
+ TALLOC_FREE(frame);
+ return False;
+
+}
+
+/*
+ * Set file info on an SMB server. Use setpathinfo call first. If that
+ * fails, use setattrE..
+ *
+ * Access and modification time parameters are always used and must be
+ * provided. Create time, if zero, will be determined from the actual create
+ * time of the file. If non-zero, the create time will be set as well.
+ *
+ * "mode" (attributes) parameter may be set to -1 if it is not to be set.
+ */
+bool
+SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path,
+ time_t create_time,
+ time_t access_time,
+ time_t write_time,
+ time_t change_time,
+ uint16 mode)
+{
+ int fd;
+ int ret;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ /*
+ * First, try setpathinfo (if qpathinfo succeeded), for it is the
+ * modern function for "new code" to be using, and it works given a
+ * filename rather than requiring that the file be opened to have its
+ * attributes manipulated.
+ */
+ if (srv->no_pathinfo ||
+ ! cli_setpathinfo(srv->cli, path,
+ create_time,
+ access_time,
+ write_time,
+ change_time,
+ mode)) {
+
+ /*
+ * setpathinfo is not supported; go to plan B.
+ *
+ * cli_setatr() does not work on win98, and it also doesn't
+ * support setting the access time (only the modification
+ * time), so in all cases, we open the specified file and use
+ * cli_setattrE() which should work on all OS versions, and
+ * supports both times.
+ */
+
+ /* Don't try {q,set}pathinfo() again, with this server */
+ srv->no_pathinfo = True;
+
+ /* Open the file */
+ if ((fd = cli_open(srv->cli, path, O_RDWR, DENY_NONE)) < 0) {
+
+ errno = SMBC_errno(context, srv->cli);
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ /* Set the new attributes */
+ ret = cli_setattrE(srv->cli, fd,
+ change_time,
+ access_time,
+ write_time);
+
+ /* Close the file */
+ cli_close(srv->cli, fd);
+
+ /*
+ * Unfortunately, setattrE() doesn't have a provision for
+ * setting the access mode (attributes). We'll have to try
+ * cli_setatr() for that, and with only this parameter, it
+ * seems to work on win98.
+ */
+ if (ret && mode != (uint16) -1) {
+ ret = cli_setatr(srv->cli, path, mode, 0);
+ }
+
+ if (! ret) {
+ errno = SMBC_errno(context, srv->cli);
+ TALLOC_FREE(frame);
+ return False;
+ }
+ }
+
+ TALLOC_FREE(frame);
+ return True;
+}
+
+/*
+ * A routine to lseek() a file
+ */
+
+off_t
+SMBC_lseek_ctx(SMBCCTX *context,
+ SMBCFILE *file,
+ off_t offset,
+ int whence)
+{
+ SMB_OFF_T size;
+ char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
+ char *path = NULL;
+ char *targetpath = NULL;
+ struct cli_state *targetcli = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
+
+ errno = EBADF;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ if (!file->file) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1; /* Can't lseek a dir ... */
+
+ }
+
+ switch (whence) {
+ case SEEK_SET:
+ file->offset = offset;
+ break;
+
+ case SEEK_CUR:
+ file->offset += offset;
+ break;
+
+ case SEEK_END:
+ /*d_printf(">>>lseek: parsing %s\n", file->fname);*/
+ if (SMBC_parse_path(frame,
+ context,
+ file->fname,
+ NULL,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ /*d_printf(">>>lseek: resolving %s\n", path);*/
+ if (!cli_resolve_path(frame, "", file->srv->cli, path,
+ &targetcli, &targetpath)) {
+ d_printf("Could not resolve %s\n", path);
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ /*d_printf(">>>lseek: resolved path as %s\n", targetpath);*/
+
+ if (!cli_qfileinfo(targetcli, file->cli_fd, NULL,
+ &size, NULL, NULL, NULL, NULL, NULL))
+ {
+ SMB_OFF_T b_size = size;
+ if (!cli_getattrE(targetcli, file->cli_fd,
+ NULL, &b_size, NULL, NULL, NULL))
+ {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ } else
+ size = b_size;
+ }
+ file->offset = size + offset;
+ break;
+
+ default:
+ errno = EINVAL;
+ break;
+
+ }
+
+ TALLOC_FREE(frame);
+ return file->offset;
+
+}
+
+
+/*
+ * Routine to truncate a file given by its file descriptor, to a specified size
+ */
+
+int
+SMBC_ftruncate_ctx(SMBCCTX *context,
+ SMBCFILE *file,
+ off_t length)
+{
+ SMB_OFF_T size = length;
+ char *server = NULL;
+ char *share = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *path = NULL;
+ char *targetpath = NULL;
+ struct cli_state *targetcli = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
+ errno = EBADF;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!file->file) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ /*d_printf(">>>fstat: parsing %s\n", file->fname);*/
+ if (SMBC_parse_path(frame,
+ context,
+ file->fname,
+ NULL,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ /*d_printf(">>>fstat: resolving %s\n", path);*/
+ if (!cli_resolve_path(frame, "", file->srv->cli, path,
+ &targetcli, &targetpath)) {
+ d_printf("Could not resolve %s\n", path);
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
+
+ if (!cli_ftruncate(targetcli, file->cli_fd, size)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ TALLOC_FREE(frame);
+ return 0;
+
+}
diff --git a/source3/libsmb/libsmb_misc.c b/source3/libsmb/libsmb_misc.c
new file mode 100644
index 0000000000..dd7add5a61
--- /dev/null
+++ b/source3/libsmb/libsmb_misc.c
@@ -0,0 +1,73 @@
+/*
+ Unix SMB/Netbios implementation.
+ SMB client library implementation
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000, 2002
+ Copyright (C) John Terpstra 2000
+ Copyright (C) Tom Jansen (Ninja ISD) 2002
+ Copyright (C) Derrell Lipman 2003-2008
+ Copyright (C) Jeremy Allison 2007, 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libsmbclient.h"
+#include "libsmb_internal.h"
+
+
+/*
+ * check if an element is part of the list.
+ */
+int
+SMBC_dlist_contains(SMBCFILE * list, SMBCFILE *p)
+{
+ if (!p || !list) return False;
+ do {
+ if (p == list) return True;
+ list = list->next;
+ } while (list);
+ return False;
+}
+
+
+/*
+ * Convert an SMB error into a UNIX error ...
+ */
+int
+SMBC_errno(SMBCCTX *context,
+ struct cli_state *c)
+{
+ int ret = cli_errno(c);
+
+ if (cli_is_dos_error(c)) {
+ uint8 eclass;
+ uint32 ecode;
+
+ cli_dos_error(c, &eclass, &ecode);
+
+ DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n",
+ (int)eclass, (int)ecode, (int)ecode, ret));
+ } else {
+ NTSTATUS status;
+
+ status = cli_nt_error(c);
+
+ DEBUG(3,("smbc errno %s -> %d\n",
+ nt_errstr(status), ret));
+ }
+
+ return ret;
+}
+
diff --git a/source3/libsmb/libsmb_path.c b/source3/libsmb/libsmb_path.c
new file mode 100644
index 0000000000..2c3a5f8866
--- /dev/null
+++ b/source3/libsmb/libsmb_path.c
@@ -0,0 +1,400 @@
+/*
+ Unix SMB/Netbios implementation.
+ SMB client library implementation
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000, 2002
+ Copyright (C) John Terpstra 2000
+ Copyright (C) Tom Jansen (Ninja ISD) 2002
+ Copyright (C) Derrell Lipman 2003-2008
+ Copyright (C) Jeremy Allison 2007, 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libsmbclient.h"
+#include "libsmb_internal.h"
+
+
+/* Used by urldecode_talloc() */
+static int
+hex2int( unsigned int _char )
+{
+ if ( _char >= 'A' && _char <='F')
+ return _char - 'A' + 10;
+ if ( _char >= 'a' && _char <='f')
+ return _char - 'a' + 10;
+ if ( _char >= '0' && _char <='9')
+ return _char - '0';
+ return -1;
+}
+
+/*
+ * SMBC_urldecode()
+ * and urldecode_talloc() (internal fn.)
+ *
+ * Convert strings of %xx to their single character equivalent. Each 'x' must
+ * be a valid hexadecimal digit, or that % sequence is left undecoded.
+ *
+ * dest may, but need not be, the same pointer as src.
+ *
+ * Returns the number of % sequences which could not be converted due to lack
+ * of two following hexadecimal digits.
+ */
+static int
+urldecode_talloc(TALLOC_CTX *ctx, char **pp_dest, const char *src)
+{
+ int old_length = strlen(src);
+ int i = 0;
+ int err_count = 0;
+ size_t newlen = 1;
+ char *p, *dest;
+
+ if (old_length == 0) {
+ return 0;
+ }
+
+ *pp_dest = NULL;
+ for (i = 0; i < old_length; ) {
+ unsigned char character = src[i++];
+
+ if (character == '%') {
+ int a = i+1 < old_length ? hex2int(src[i]) : -1;
+ int b = i+1 < old_length ? hex2int(src[i+1]) : -1;
+
+ /* Replace valid sequence */
+ if (a != -1 && b != -1) {
+ /* Replace valid %xx sequence with %dd */
+ character = (a * 16) + b;
+ if (character == '\0') {
+ break; /* Stop at %00 */
+ }
+ i += 2;
+ } else {
+ err_count++;
+ }
+ }
+ newlen++;
+ }
+
+ dest = TALLOC_ARRAY(ctx, char, newlen);
+ if (!dest) {
+ return err_count;
+ }
+
+ err_count = 0;
+ for (p = dest, i = 0; i < old_length; ) {
+ unsigned char character = src[i++];
+
+ if (character == '%') {
+ int a = i+1 < old_length ? hex2int(src[i]) : -1;
+ int b = i+1 < old_length ? hex2int(src[i+1]) : -1;
+
+ /* Replace valid sequence */
+ if (a != -1 && b != -1) {
+ /* Replace valid %xx sequence with %dd */
+ character = (a * 16) + b;
+ if (character == '\0') {
+ break; /* Stop at %00 */
+ }
+ i += 2;
+ } else {
+ err_count++;
+ }
+ }
+ *p++ = character;
+ }
+
+ *p = '\0';
+ *pp_dest = dest;
+ return err_count;
+}
+
+int
+SMBC_urldecode(char *dest,
+ char *src,
+ size_t max_dest_len)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *pdest;
+ int ret = urldecode_talloc(frame, &pdest, src);
+
+ if (pdest) {
+ strlcpy(dest, pdest, max_dest_len);
+ }
+ TALLOC_FREE(frame);
+ return ret;
+}
+
+/*
+ * SMBC_urlencode()
+ *
+ * Convert any characters not specifically allowed in a URL into their %xx
+ * equivalent.
+ *
+ * Returns the remaining buffer length.
+ */
+int
+SMBC_urlencode(char *dest,
+ char *src,
+ int max_dest_len)
+{
+ char hex[] = "0123456789ABCDEF";
+
+ for (; *src != '\0' && max_dest_len >= 3; src++) {
+
+ if ((*src < '0' &&
+ *src != '-' &&
+ *src != '.') ||
+ (*src > '9' &&
+ *src < 'A') ||
+ (*src > 'Z' &&
+ *src < 'a' &&
+ *src != '_') ||
+ (*src > 'z')) {
+ *dest++ = '%';
+ *dest++ = hex[(*src >> 4) & 0x0f];
+ *dest++ = hex[*src & 0x0f];
+ max_dest_len -= 3;
+ } else {
+ *dest++ = *src;
+ max_dest_len--;
+ }
+ }
+
+ *dest++ = '\0';
+ max_dest_len--;
+
+ return max_dest_len;
+}
+
+/*
+ * Function to parse a path and turn it into components
+ *
+ * The general format of an SMB URI is explain in Christopher Hertel's CIFS
+ * book, at http://ubiqx.org/cifs/Appendix-D.html. We accept a subset of the
+ * general format ("smb:" only; we do not look for "cifs:").
+ *
+ *
+ * We accept:
+ * smb://[[[domain;]user[:password]@]server[/share[/path[/file]]]][?options]
+ *
+ * Meaning of URLs:
+ *
+ * smb:// Show all workgroups.
+ *
+ * The method of locating the list of workgroups varies
+ * depending upon the setting of the context variable
+ * context->options.browse_max_lmb_count. This value
+ * determines the maximum number of local master browsers to
+ * query for the list of workgroups. In order to ensure that
+ * a complete list of workgroups is obtained, all master
+ * browsers must be queried, but if there are many
+ * workgroups, the time spent querying can begin to add up.
+ * For small networks (not many workgroups), it is suggested
+ * that this variable be set to 0, indicating query all local
+ * master browsers. When the network has many workgroups, a
+ * reasonable setting for this variable might be around 3.
+ *
+ * smb://name/ if name<1D> or name<1B> exists, list servers in
+ * workgroup, else, if name<20> exists, list all shares
+ * for server ...
+ *
+ * If "options" are provided, this function returns the entire option list as a
+ * string, for later parsing by the caller. Note that currently, no options
+ * are supported.
+ */
+
+static const char *smbc_prefix = "smb:";
+
+int
+SMBC_parse_path(TALLOC_CTX *ctx,
+ SMBCCTX *context,
+ const char *fname,
+ char **pp_workgroup,
+ char **pp_server,
+ char **pp_share,
+ char **pp_path,
+ char **pp_user,
+ char **pp_password,
+ char **pp_options)
+{
+ char *s;
+ const char *p;
+ char *q, *r;
+ int len;
+
+ /* Ensure these returns are at least valid pointers. */
+ *pp_server = talloc_strdup(ctx, "");
+ *pp_share = talloc_strdup(ctx, "");
+ *pp_path = talloc_strdup(ctx, "");
+ *pp_user = talloc_strdup(ctx, "");
+ *pp_password = talloc_strdup(ctx, "");
+
+ if (!*pp_server || !*pp_share || !*pp_path ||
+ !*pp_user || !*pp_password) {
+ return -1;
+ }
+
+ /*
+ * Assume we wont find an authentication domain to parse, so default
+ * to the workgroup in the provided context.
+ */
+ if (pp_workgroup != NULL) {
+ *pp_workgroup =
+ talloc_strdup(ctx, smbc_getWorkgroup(context));
+ }
+
+ if (pp_options) {
+ *pp_options = talloc_strdup(ctx, "");
+ }
+ s = talloc_strdup(ctx, fname);
+
+ /* see if it has the right prefix */
+ len = strlen(smbc_prefix);
+ if (strncmp(s,smbc_prefix,len) || (s[len] != '/' && s[len] != 0)) {
+ return -1; /* What about no smb: ? */
+ }
+
+ p = s + len;
+
+ /* Watch the test below, we are testing to see if we should exit */
+
+ if (strncmp(p, "//", 2) && strncmp(p, "\\\\", 2)) {
+ DEBUG(1, ("Invalid path (does not begin with smb://"));
+ return -1;
+ }
+
+ p += 2; /* Skip the double slash */
+
+ /* See if any options were specified */
+ if ((q = strrchr(p, '?')) != NULL ) {
+ /* There are options. Null terminate here and point to them */
+ *q++ = '\0';
+
+ DEBUG(4, ("Found options '%s'", q));
+
+ /* Copy the options */
+ if (*pp_options != NULL) {
+ TALLOC_FREE(*pp_options);
+ *pp_options = talloc_strdup(ctx, q);
+ }
+ }
+
+ if (*p == '\0') {
+ goto decoding;
+ }
+
+ if (*p == '/') {
+ int wl = strlen(smbc_getWorkgroup(context));
+
+ if (wl > 16) {
+ wl = 16;
+ }
+
+ *pp_server = talloc_strdup(ctx, smbc_getWorkgroup(context));
+ if (!*pp_server) {
+ return -1;
+ }
+ *pp_server[wl] = '\0';
+ return 0;
+ }
+
+ /*
+ * ok, its for us. Now parse out the server, share etc.
+ *
+ * However, we want to parse out [[domain;]user[:password]@] if it
+ * exists ...
+ */
+
+ /* check that '@' occurs before '/', if '/' exists at all */
+ q = strchr_m(p, '@');
+ r = strchr_m(p, '/');
+ if (q && (!r || q < r)) {
+ char *userinfo = NULL;
+ const char *u;
+
+ next_token_no_ltrim_talloc(ctx, &p, &userinfo, "@");
+ if (!userinfo) {
+ return -1;
+ }
+ u = userinfo;
+
+ if (strchr_m(u, ';')) {
+ char *workgroup;
+ next_token_no_ltrim_talloc(ctx, &u, &workgroup, ";");
+ if (!workgroup) {
+ return -1;
+ }
+ if (pp_workgroup) {
+ *pp_workgroup = workgroup;
+ }
+ }
+
+ if (strchr_m(u, ':')) {
+ next_token_no_ltrim_talloc(ctx, &u, pp_user, ":");
+ if (!*pp_user) {
+ return -1;
+ }
+ *pp_password = talloc_strdup(ctx, u);
+ if (!*pp_password) {
+ return -1;
+ }
+ } else {
+ *pp_user = talloc_strdup(ctx, u);
+ if (!*pp_user) {
+ return -1;
+ }
+ }
+ }
+
+ if (!next_token_talloc(ctx, &p, pp_server, "/")) {
+ return -1;
+ }
+
+ if (*p == (char)0) {
+ goto decoding; /* That's it ... */
+ }
+
+ if (!next_token_talloc(ctx, &p, pp_share, "/")) {
+ return -1;
+ }
+
+ /*
+ * Prepend a leading slash if there's a file path, as required by
+ * NetApp filers.
+ */
+ if (*p != '\0') {
+ *pp_path = talloc_asprintf(ctx,
+ "\\%s",
+ p);
+ } else {
+ *pp_path = talloc_strdup(ctx, "");
+ }
+ if (!*pp_path) {
+ return -1;
+ }
+ string_replace(*pp_path, '/', '\\');
+
+decoding:
+
+ (void) urldecode_talloc(ctx, pp_path, *pp_path);
+ (void) urldecode_talloc(ctx, pp_server, *pp_server);
+ (void) urldecode_talloc(ctx, pp_share, *pp_share);
+ (void) urldecode_talloc(ctx, pp_user, *pp_user);
+ (void) urldecode_talloc(ctx, pp_password, *pp_password);
+
+ return 0;
+}
+
diff --git a/source3/libsmb/libsmb_printjob.c b/source3/libsmb/libsmb_printjob.c
new file mode 100644
index 0000000000..c8d7ad039d
--- /dev/null
+++ b/source3/libsmb/libsmb_printjob.c
@@ -0,0 +1,336 @@
+/*
+ Unix SMB/Netbios implementation.
+ SMB client library implementation
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000, 2002
+ Copyright (C) John Terpstra 2000
+ Copyright (C) Tom Jansen (Ninja ISD) 2002
+ Copyright (C) Derrell Lipman 2003-2008
+ Copyright (C) Jeremy Allison 2007, 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libsmbclient.h"
+#include "libsmb_internal.h"
+
+
+/*
+ * Open a print file to be written to by other calls
+ */
+
+SMBCFILE *
+SMBC_open_print_job_ctx(SMBCCTX *context,
+ const char *fname)
+{
+ char *server = NULL;
+ char *share = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *path = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ if (!fname) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ DEBUG(4, ("SMBC_open_print_job_ctx(%s)\n", fname));
+
+ if (SMBC_parse_path(frame,
+ context,
+ fname,
+ NULL,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ /* What if the path is empty, or the file exists? */
+
+ TALLOC_FREE(frame);
+ return smbc_getFunctionOpen(context)(context, fname, O_WRONLY, 666);
+}
+
+/*
+ * Routine to print a file on a remote server ...
+ *
+ * We open the file, which we assume to be on a remote server, and then
+ * copy it to a print file on the share specified by printq.
+ */
+
+int
+SMBC_print_file_ctx(SMBCCTX *c_file,
+ const char *fname,
+ SMBCCTX *c_print,
+ const char *printq)
+{
+ SMBCFILE *fid1;
+ SMBCFILE *fid2;
+ int bytes;
+ int saverr;
+ int tot_bytes = 0;
+ char buf[4096];
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!c_file || !c_file->internal->initialized ||
+ !c_print || !c_print->internal->initialized) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ if (!fname && !printq) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ /* Try to open the file for reading ... */
+
+ if ((long)(fid1 = smbc_getFunctionOpen(c_file)(c_file, fname,
+ O_RDONLY, 0666)) < 0) {
+ DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno));
+ TALLOC_FREE(frame);
+ return -1; /* smbc_open sets errno */
+ }
+
+ /* Now, try to open the printer file for writing */
+
+ if ((long)(fid2 = smbc_getFunctionOpenPrintJob(c_print)(c_print,
+ printq)) < 0) {
+
+ saverr = errno; /* Save errno */
+ smbc_getFunctionClose(c_file)(c_file, fid1);
+ errno = saverr;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ while ((bytes = smbc_getFunctionRead(c_file)(c_file, fid1,
+ buf, sizeof(buf))) > 0) {
+
+ tot_bytes += bytes;
+
+ if ((smbc_getFunctionWrite(c_print)(c_print, fid2,
+ buf, bytes)) < 0) {
+
+ saverr = errno;
+ smbc_getFunctionClose(c_file)(c_file, fid1);
+ smbc_getFunctionClose(c_print)(c_print, fid2);
+ errno = saverr;
+
+ }
+
+ }
+
+ saverr = errno;
+
+ smbc_getFunctionClose(c_file)(c_file, fid1);
+ smbc_getFunctionClose(c_print)(c_print, fid2);
+
+ if (bytes < 0) {
+
+ errno = saverr;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ TALLOC_FREE(frame);
+ return tot_bytes;
+
+}
+
+/*
+ * Routine to list print jobs on a printer share ...
+ */
+
+int
+SMBC_list_print_jobs_ctx(SMBCCTX *context,
+ const char *fname,
+ smbc_list_print_job_fn fn)
+{
+ SMBCSRV *srv = NULL;
+ char *server = NULL;
+ char *share = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *workgroup = NULL;
+ char *path = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!fname) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname));
+
+ if (SMBC_parse_path(frame,
+ context,
+ fname,
+ &workgroup,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!user || user[0] == (char)0) {
+ user = talloc_strdup(frame, smbc_getUser(context));
+ if (!user) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ }
+
+ srv = SMBC_server(frame, context, True,
+ server, share, &workgroup, &user, &password);
+
+ if (!srv) {
+ TALLOC_FREE(frame);
+ return -1; /* errno set by SMBC_server */
+ }
+
+ if (cli_print_queue(srv->cli,
+ (void (*)(struct print_job_info *))fn) < 0) {
+ errno = SMBC_errno(context, srv->cli);
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ TALLOC_FREE(frame);
+ return 0;
+
+}
+
+/*
+ * Delete a print job from a remote printer share
+ */
+
+int
+SMBC_unlink_print_job_ctx(SMBCCTX *context,
+ const char *fname,
+ int id)
+{
+ SMBCSRV *srv = NULL;
+ char *server = NULL;
+ char *share = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *workgroup = NULL;
+ char *path = NULL;
+ int err;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!fname) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname));
+
+ if (SMBC_parse_path(frame,
+ context,
+ fname,
+ &workgroup,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!user || user[0] == (char)0) {
+ user = talloc_strdup(frame, smbc_getUser(context));
+ if (!user) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ }
+
+ srv = SMBC_server(frame, context, True,
+ server, share, &workgroup, &user, &password);
+
+ if (!srv) {
+
+ TALLOC_FREE(frame);
+ return -1; /* errno set by SMBC_server */
+
+ }
+
+ if ((err = cli_printjob_del(srv->cli, id)) != 0) {
+
+ if (err < 0)
+ errno = SMBC_errno(context, srv->cli);
+ else if (err == ERRnosuchprintjob)
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+
+ }
+
+ TALLOC_FREE(frame);
+ return 0;
+
+}
+
diff --git a/source3/libsmb/libsmb_server.c b/source3/libsmb/libsmb_server.c
new file mode 100644
index 0000000000..aeec255350
--- /dev/null
+++ b/source3/libsmb/libsmb_server.c
@@ -0,0 +1,699 @@
+/*
+ Unix SMB/Netbios implementation.
+ SMB client library implementation
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000, 2002
+ Copyright (C) John Terpstra 2000
+ Copyright (C) Tom Jansen (Ninja ISD) 2002
+ Copyright (C) Derrell Lipman 2003-2008
+ Copyright (C) Jeremy Allison 2007, 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libsmbclient.h"
+#include "libsmb_internal.h"
+
+
+/*
+ * Check a server for being alive and well.
+ * returns 0 if the server is in shape. Returns 1 on error
+ *
+ * Also useable outside libsmbclient to enable external cache
+ * to do some checks too.
+ */
+int
+SMBC_check_server(SMBCCTX * context,
+ SMBCSRV * server)
+{
+ socklen_t size;
+ struct sockaddr addr;
+
+ size = sizeof(addr);
+ return (getpeername(server->cli->fd, &addr, &size) == -1);
+}
+
+/*
+ * Remove a server from the cached server list it's unused.
+ * On success, 0 is returned. 1 is returned if the server could not be removed.
+ *
+ * Also useable outside libsmbclient
+ */
+int
+SMBC_remove_unused_server(SMBCCTX * context,
+ SMBCSRV * srv)
+{
+ SMBCFILE * file;
+
+ /* are we being fooled ? */
+ if (!context || !context->internal->initialized || !srv) {
+ return 1;
+ }
+
+ /* Check all open files/directories for a relation with this server */
+ for (file = context->internal->files; file; file = file->next) {
+ if (file->srv == srv) {
+ /* Still used */
+ DEBUG(3, ("smbc_remove_usused_server: "
+ "%p still used by %p.\n",
+ srv, file));
+ return 1;
+ }
+ }
+
+ DLIST_REMOVE(context->internal->servers, srv);
+
+ cli_shutdown(srv->cli);
+ srv->cli = NULL;
+
+ DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv));
+
+ smbc_getFunctionRemoveCachedServer(context)(context, srv);
+
+ SAFE_FREE(srv);
+ return 0;
+}
+
+/****************************************************************
+ * Call the auth_fn with fixed size (fstring) buffers.
+ ***************************************************************/
+void
+SMBC_call_auth_fn(TALLOC_CTX *ctx,
+ SMBCCTX *context,
+ const char *server,
+ const char *share,
+ char **pp_workgroup,
+ char **pp_username,
+ char **pp_password)
+{
+ fstring workgroup;
+ fstring username;
+ fstring password;
+ smbc_get_auth_data_with_context_fn auth_with_context_fn;
+
+ strlcpy(workgroup, *pp_workgroup, sizeof(workgroup));
+ strlcpy(username, *pp_username, sizeof(username));
+ strlcpy(password, *pp_password, sizeof(password));
+
+ /* See if there's an authentication with context function provided */
+ auth_with_context_fn = smbc_getFunctionAuthDataWithContext(context);
+ if (auth_with_context_fn)
+ {
+ (* auth_with_context_fn)(context,
+ server, share,
+ workgroup, sizeof(workgroup),
+ username, sizeof(username),
+ password, sizeof(password));
+ }
+ else
+ {
+ smbc_getFunctionAuthData(context)(server, share,
+ workgroup, sizeof(workgroup),
+ username, sizeof(username),
+ password, sizeof(password));
+ }
+
+ TALLOC_FREE(*pp_workgroup);
+ TALLOC_FREE(*pp_username);
+ TALLOC_FREE(*pp_password);
+
+ *pp_workgroup = talloc_strdup(ctx, workgroup);
+ *pp_username = talloc_strdup(ctx, username);
+ *pp_password = talloc_strdup(ctx, password);
+}
+
+
+void
+SMBC_get_auth_data(const char *server, const char *share,
+ char *workgroup_buf, int workgroup_buf_len,
+ char *username_buf, int username_buf_len,
+ char *password_buf, int password_buf_len)
+{
+ /* Default function just uses provided data. Nothing to do. */
+}
+
+
+
+SMBCSRV *
+SMBC_find_server(TALLOC_CTX *ctx,
+ SMBCCTX *context,
+ const char *server,
+ const char *share,
+ char **pp_workgroup,
+ char **pp_username,
+ char **pp_password)
+{
+ SMBCSRV *srv;
+ int auth_called = 0;
+
+ if (!pp_workgroup || !pp_username || !pp_password) {
+ return NULL;
+ }
+
+check_server_cache:
+
+ srv = smbc_getFunctionGetCachedServer(context)(context,
+ server, share,
+ *pp_workgroup,
+ *pp_username);
+
+ if (!auth_called && !srv && (!*pp_username || !(*pp_username)[0] ||
+ !*pp_password || !(*pp_password)[0])) {
+ SMBC_call_auth_fn(ctx, context, server, share,
+ pp_workgroup, pp_username, pp_password);
+
+ /*
+ * However, smbc_auth_fn may have picked up info relating to
+ * an existing connection, so try for an existing connection
+ * again ...
+ */
+ auth_called = 1;
+ goto check_server_cache;
+
+ }
+
+ if (srv) {
+ if (smbc_getFunctionCheckServer(context)(context, srv)) {
+ /*
+ * This server is no good anymore
+ * Try to remove it and check for more possible
+ * servers in the cache
+ */
+ if (smbc_getFunctionRemoveUnusedServer(context)(context,
+ srv)) {
+ /*
+ * We could not remove the server completely,
+ * remove it from the cache so we will not get
+ * it again. It will be removed when the last
+ * file/dir is closed.
+ */
+ smbc_getFunctionRemoveCachedServer(context)(context,
+ srv);
+ }
+
+ /*
+ * Maybe there are more cached connections to this
+ * server
+ */
+ goto check_server_cache;
+ }
+
+ return srv;
+ }
+
+ return NULL;
+}
+
+/*
+ * Connect to a server, possibly on an existing connection
+ *
+ * Here, what we want to do is: If the server and username
+ * match an existing connection, reuse that, otherwise, establish a
+ * new connection.
+ *
+ * If we have to create a new connection, call the auth_fn to get the
+ * info we need, unless the username and password were passed in.
+ */
+
+SMBCSRV *
+SMBC_server(TALLOC_CTX *ctx,
+ SMBCCTX *context,
+ bool connect_if_not_found,
+ const char *server,
+ const char *share,
+ char **pp_workgroup,
+ char **pp_username,
+ char **pp_password)
+{
+ SMBCSRV *srv=NULL;
+ struct cli_state *c;
+ struct nmb_name called, calling;
+ const char *server_n = server;
+ struct sockaddr_storage ss;
+ int tried_reverse = 0;
+ int port_try_first;
+ int port_try_next;
+ const char *username_used;
+ NTSTATUS status;
+
+ zero_addr(&ss);
+ ZERO_STRUCT(c);
+
+ if (server[0] == 0) {
+ errno = EPERM;
+ return NULL;
+ }
+
+ /* Look for a cached connection */
+ srv = SMBC_find_server(ctx, context, server, share,
+ pp_workgroup, pp_username, pp_password);
+
+ /*
+ * If we found a connection and we're only allowed one share per
+ * server...
+ */
+ if (srv &&
+ *share != '\0' &&
+ smbc_getOptionOneSharePerServer(context)) {
+
+ /*
+ * ... then if there's no current connection to the share,
+ * connect to it. SMBC_find_server(), or rather the function
+ * pointed to by context->get_cached_srv_fn which
+ * was called by SMBC_find_server(), will have issued a tree
+ * disconnect if the requested share is not the same as the
+ * one that was already connected.
+ */
+ if (srv->cli->cnum == (uint16) -1) {
+ /* Ensure we have accurate auth info */
+ SMBC_call_auth_fn(ctx, context, server, share,
+ pp_workgroup,
+ pp_username,
+ pp_password);
+
+ if (!*pp_workgroup || !*pp_username || !*pp_password) {
+ errno = ENOMEM;
+ cli_shutdown(srv->cli);
+ srv->cli = NULL;
+ smbc_getFunctionRemoveCachedServer(context)(context,
+ srv);
+ return NULL;
+ }
+
+ /*
+ * We don't need to renegotiate encryption
+ * here as the encryption context is not per
+ * tid.
+ */
+
+ if (!cli_send_tconX(srv->cli, share, "?????",
+ *pp_password,
+ strlen(*pp_password)+1)) {
+
+ errno = SMBC_errno(context, srv->cli);
+ cli_shutdown(srv->cli);
+ srv->cli = NULL;
+ smbc_getFunctionRemoveCachedServer(context)(context,
+ srv);
+ srv = NULL;
+ }
+
+ /*
+ * Regenerate the dev value since it's based on both
+ * server and share
+ */
+ if (srv) {
+ srv->dev = (dev_t)(str_checksum(server) ^
+ str_checksum(share));
+ }
+ }
+ }
+
+ /* If we have a connection... */
+ if (srv) {
+
+ /* ... then we're done here. Give 'em what they came for. */
+ return srv;
+ }
+
+ /* If we're not asked to connect when a connection doesn't exist... */
+ if (! connect_if_not_found) {
+ /* ... then we're done here. */
+ return NULL;
+ }
+
+ if (!*pp_workgroup || !*pp_username || !*pp_password) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ make_nmb_name(&calling, smbc_getNetbiosName(context), 0x0);
+ make_nmb_name(&called , server, 0x20);
+
+ DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server));
+
+ DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
+
+again:
+
+ zero_addr(&ss);
+
+ /* have to open a new connection */
+ if ((c = cli_initialise()) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ if (smbc_getOptionUseKerberos(context)) {
+ c->use_kerberos = True;
+ }
+
+ if (smbc_getOptionFallbackAfterKerberos(context)) {
+ c->fallback_after_kerberos = True;
+ }
+
+ c->timeout = smbc_getTimeout(context);
+
+ /*
+ * Force use of port 139 for first try if share is $IPC, empty, or
+ * null, so browse lists can work
+ */
+ if (share == NULL || *share == '\0' || strcmp(share, "IPC$") == 0) {
+ port_try_first = 139;
+ port_try_next = 445;
+ } else {
+ port_try_first = 445;
+ port_try_next = 139;
+ }
+
+ c->port = port_try_first;
+
+ status = cli_connect(c, server_n, &ss);
+ if (!NT_STATUS_IS_OK(status)) {
+
+ /* First connection attempt failed. Try alternate port. */
+ c->port = port_try_next;
+
+ status = cli_connect(c, server_n, &ss);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_shutdown(c);
+ errno = ETIMEDOUT;
+ return NULL;
+ }
+ }
+
+ if (!cli_session_request(c, &calling, &called)) {
+ cli_shutdown(c);
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ } else { /* Try one more time, but ensure we don't loop */
+
+ /* Only try this if server is an IP address ... */
+
+ if (is_ipaddress(server) && !tried_reverse) {
+ fstring remote_name;
+ struct sockaddr_storage rem_ss;
+
+ if (!interpret_string_addr(&rem_ss, server,
+ NI_NUMERICHOST)) {
+ DEBUG(4, ("Could not convert IP address "
+ "%s to struct sockaddr_storage\n",
+ server));
+ errno = ETIMEDOUT;
+ return NULL;
+ }
+
+ tried_reverse++; /* Yuck */
+
+ if (name_status_find("*", 0, 0,
+ &rem_ss, remote_name)) {
+ make_nmb_name(&called,
+ remote_name,
+ 0x20);
+ goto again;
+ }
+ }
+ }
+ errno = ETIMEDOUT;
+ return NULL;
+ }
+
+ DEBUG(4,(" session request ok\n"));
+
+ if (!cli_negprot(c)) {
+ cli_shutdown(c);
+ errno = ETIMEDOUT;
+ return NULL;
+ }
+
+ username_used = *pp_username;
+
+ if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used,
+ *pp_password,
+ strlen(*pp_password),
+ *pp_password,
+ strlen(*pp_password),
+ *pp_workgroup))) {
+
+ /* Failed. Try an anonymous login, if allowed by flags. */
+ username_used = "";
+
+ if (smbc_getOptionNoAutoAnonymousLogin(context) ||
+ !NT_STATUS_IS_OK(cli_session_setup(c, username_used,
+ *pp_password, 1,
+ *pp_password, 0,
+ *pp_workgroup))) {
+
+ cli_shutdown(c);
+ errno = EPERM;
+ return NULL;
+ }
+ }
+
+ DEBUG(4,(" session setup ok\n"));
+
+ if (!cli_send_tconX(c, share, "?????",
+ *pp_password, strlen(*pp_password)+1)) {
+ errno = SMBC_errno(context, c);
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ DEBUG(4,(" tconx ok\n"));
+
+ if (context->internal->smb_encryption_level) {
+ /* Attempt UNIX smb encryption. */
+ if (!NT_STATUS_IS_OK(cli_force_encryption(c,
+ username_used,
+ *pp_password,
+ *pp_workgroup))) {
+
+ /*
+ * context->smb_encryption_level == 1
+ * means don't fail if encryption can't be negotiated,
+ * == 2 means fail if encryption can't be negotiated.
+ */
+
+ DEBUG(4,(" SMB encrypt failed\n"));
+
+ if (context->internal->smb_encryption_level == 2) {
+ cli_shutdown(c);
+ errno = EPERM;
+ return NULL;
+ }
+ }
+ DEBUG(4,(" SMB encrypt ok\n"));
+ }
+
+ /*
+ * Ok, we have got a nice connection
+ * Let's allocate a server structure.
+ */
+
+ srv = SMB_MALLOC_P(SMBCSRV);
+ if (!srv) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ ZERO_STRUCTP(srv);
+ srv->cli = c;
+ srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
+ srv->no_pathinfo = False;
+ srv->no_pathinfo2 = False;
+ srv->no_nt_session = False;
+
+ /* now add it to the cache (internal or external) */
+ /* Let the cache function set errno if it wants to */
+ errno = 0;
+ if (smbc_getFunctionAddCachedServer(context)(context, srv,
+ server, share,
+ *pp_workgroup,
+ *pp_username)) {
+ int saved_errno = errno;
+ DEBUG(3, (" Failed to add server to cache\n"));
+ errno = saved_errno;
+ if (errno == 0) {
+ errno = ENOMEM;
+ }
+ goto failed;
+ }
+
+ DEBUG(2, ("Server connect ok: //%s/%s: %p\n",
+ server, share, srv));
+
+ DLIST_ADD(context->internal->servers, srv);
+ return srv;
+
+failed:
+ cli_shutdown(c);
+ if (!srv) {
+ return NULL;
+ }
+
+ SAFE_FREE(srv);
+ return NULL;
+}
+
+/*
+ * Connect to a server for getting/setting attributes, possibly on an existing
+ * connection. This works similarly to SMBC_server().
+ */
+SMBCSRV *
+SMBC_attr_server(TALLOC_CTX *ctx,
+ SMBCCTX *context,
+ const char *server,
+ const char *share,
+ char **pp_workgroup,
+ char **pp_username,
+ char **pp_password)
+{
+ int flags;
+ struct sockaddr_storage ss;
+ struct cli_state *ipc_cli;
+ struct rpc_pipe_client *pipe_hnd;
+ NTSTATUS nt_status;
+ SMBCSRV *ipc_srv=NULL;
+
+ /*
+ * See if we've already created this special connection. Reference
+ * our "special" share name '*IPC$', which is an impossible real share
+ * name due to the leading asterisk.
+ */
+ ipc_srv = SMBC_find_server(ctx, context, server, "*IPC$",
+ pp_workgroup, pp_username, pp_password);
+ if (!ipc_srv) {
+
+ /* We didn't find a cached connection. Get the password */
+ if (!*pp_password || (*pp_password)[0] == '\0') {
+ /* ... then retrieve it now. */
+ SMBC_call_auth_fn(ctx, context, server, share,
+ pp_workgroup,
+ pp_username,
+ pp_password);
+ if (!*pp_workgroup || !*pp_username || !*pp_password) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ }
+
+ flags = 0;
+ if (smbc_getOptionUseKerberos(context)) {
+ flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
+ }
+
+ zero_addr(&ss);
+ nt_status = cli_full_connection(&ipc_cli,
+ global_myname(), server,
+ &ss, 0, "IPC$", "?????",
+ *pp_username,
+ *pp_workgroup,
+ *pp_password,
+ flags,
+ Undefined, NULL);
+ if (! NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1,("cli_full_connection failed! (%s)\n",
+ nt_errstr(nt_status)));
+ errno = ENOTSUP;
+ return NULL;
+ }
+
+ if (context->internal->smb_encryption_level) {
+ /* Attempt UNIX smb encryption. */
+ if (!NT_STATUS_IS_OK(cli_force_encryption(ipc_cli,
+ *pp_username,
+ *pp_password,
+ *pp_workgroup))) {
+
+ /*
+ * context->smb_encryption_level ==
+ * 1 means don't fail if encryption can't be
+ * negotiated, == 2 means fail if encryption
+ * can't be negotiated.
+ */
+
+ DEBUG(4,(" SMB encrypt failed on IPC$\n"));
+
+ if (context->internal->smb_encryption_level == 2) {
+ cli_shutdown(ipc_cli);
+ errno = EPERM;
+ return NULL;
+ }
+ }
+ DEBUG(4,(" SMB encrypt ok on IPC$\n"));
+ }
+
+ ipc_srv = SMB_MALLOC_P(SMBCSRV);
+ if (!ipc_srv) {
+ errno = ENOMEM;
+ cli_shutdown(ipc_cli);
+ return NULL;
+ }
+
+ ZERO_STRUCTP(ipc_srv);
+ ipc_srv->cli = ipc_cli;
+
+ nt_status = cli_rpc_pipe_open_noauth(
+ ipc_srv->cli, &ndr_table_lsarpc.syntax_id, &pipe_hnd);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1, ("cli_nt_session_open fail!\n"));
+ errno = ENOTSUP;
+ cli_shutdown(ipc_srv->cli);
+ free(ipc_srv);
+ return NULL;
+ }
+
+ /*
+ * Some systems don't support
+ * SEC_RIGHTS_MAXIMUM_ALLOWED, but NT sends 0x2000000
+ * so we might as well do it too.
+ */
+
+ nt_status = rpccli_lsa_open_policy(
+ pipe_hnd,
+ talloc_tos(),
+ True,
+ GENERIC_EXECUTE_ACCESS,
+ &ipc_srv->pol);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ errno = SMBC_errno(context, ipc_srv->cli);
+ cli_shutdown(ipc_srv->cli);
+ return NULL;
+ }
+
+ /* now add it to the cache (internal or external) */
+
+ errno = 0; /* let cache function set errno if it likes */
+ if (smbc_getFunctionAddCachedServer(context)(context, ipc_srv,
+ server,
+ "*IPC$",
+ *pp_workgroup,
+ *pp_username)) {
+ DEBUG(3, (" Failed to add server to cache\n"));
+ if (errno == 0) {
+ errno = ENOMEM;
+ }
+ cli_shutdown(ipc_srv->cli);
+ free(ipc_srv);
+ return NULL;
+ }
+
+ DLIST_ADD(context->internal->servers, ipc_srv);
+ }
+
+ return ipc_srv;
+}
diff --git a/source3/libsmb/libsmb_setget.c b/source3/libsmb/libsmb_setget.c
new file mode 100644
index 0000000000..d0823bd77e
--- /dev/null
+++ b/source3/libsmb/libsmb_setget.c
@@ -0,0 +1,905 @@
+/*
+ Unix SMB/Netbios implementation.
+ SMB client library implementation
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000, 2002
+ Copyright (C) John Terpstra 2000
+ Copyright (C) Tom Jansen (Ninja ISD) 2002
+ Copyright (C) Derrell Lipman 2003-2008
+ Copyright (C) Jeremy Allison 2007, 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#define __LIBSMBCLIENT_INTERNAL__
+#include "libsmbclient.h"
+#include "libsmb_internal.h"
+
+
+/** Get the netbios name used for making connections */
+char *
+smbc_getNetbiosName(SMBCCTX *c)
+{
+ return c->netbios_name;
+}
+
+/** Set the netbios name used for making connections */
+void
+smbc_setNetbiosName(SMBCCTX *c, char * netbios_name)
+{
+ c->netbios_name = netbios_name;
+}
+
+/** Get the workgroup used for making connections */
+char *
+smbc_getWorkgroup(SMBCCTX *c)
+{
+ return c->workgroup;
+}
+
+/** Set the workgroup used for making connections */
+void
+smbc_setWorkgroup(SMBCCTX *c, char * workgroup)
+{
+ c->workgroup = workgroup;
+}
+
+/** Get the username used for making connections */
+char *
+smbc_getUser(SMBCCTX *c)
+{
+ return c->user;
+}
+
+/** Set the username used for making connections */
+void
+smbc_setUser(SMBCCTX *c, char * user)
+{
+ c->user = user;
+}
+
+/** Get the debug level */
+int
+smbc_getDebug(SMBCCTX *c)
+{
+ return c->debug;
+}
+
+/** Set the debug level */
+void
+smbc_setDebug(SMBCCTX *c, int debug)
+{
+ c->debug = debug;
+ DEBUGLEVEL = debug;
+}
+
+/**
+ * Get the timeout used for waiting on connections and response data
+ * (in milliseconds)
+ */
+int
+smbc_getTimeout(SMBCCTX *c)
+{
+ return c->timeout;
+}
+
+/**
+ * Set the timeout used for waiting on connections and response data
+ * (in milliseconds)
+ */
+void
+smbc_setTimeout(SMBCCTX *c, int timeout)
+{
+ c->timeout = timeout;
+}
+
+/** Get whether to log to standard error instead of standard output */
+smbc_bool
+smbc_getOptionDebugToStderr(SMBCCTX *c)
+{
+ return c->internal->debug_stderr;
+}
+
+/** Set whether to log to standard error instead of standard output */
+void
+smbc_setOptionDebugToStderr(SMBCCTX *c, smbc_bool b)
+{
+ c->internal->debug_stderr = b;
+}
+
+/**
+ * Get whether to use new-style time attribute names, e.g. WRITE_TIME rather
+ * than the old-style names such as M_TIME. This allows also setting/getting
+ * CREATE_TIME which was previously unimplemented. (Note that the old C_TIME
+ * was supposed to be CHANGE_TIME but was confused and sometimes referred to
+ * CREATE_TIME.)
+ */
+smbc_bool
+smbc_getOptionFullTimeNames(SMBCCTX *c)
+{
+ return c->internal->full_time_names;
+}
+
+/**
+ * Set whether to use new-style time attribute names, e.g. WRITE_TIME rather
+ * than the old-style names such as M_TIME. This allows also setting/getting
+ * CREATE_TIME which was previously unimplemented. (Note that the old C_TIME
+ * was supposed to be CHANGE_TIME but was confused and sometimes referred to
+ * CREATE_TIME.)
+ */
+void
+smbc_setOptionFullTimeNames(SMBCCTX *c, smbc_bool b)
+{
+ c->internal->full_time_names = b;
+}
+
+/**
+ * Get the share mode to use for files opened with SMBC_open_ctx(). The
+ * default is SMBC_SHAREMODE_DENY_NONE.
+ */
+smbc_share_mode
+smbc_getOptionOpenShareMode(SMBCCTX *c)
+{
+ return c->internal->share_mode;
+}
+
+/**
+ * Set the share mode to use for files opened with SMBC_open_ctx(). The
+ * default is SMBC_SHAREMODE_DENY_NONE.
+ */
+void
+smbc_setOptionOpenShareMode(SMBCCTX *c, smbc_share_mode share_mode)
+{
+ c->internal->share_mode = share_mode;
+}
+
+/** Retrieve a previously set user data handle */
+void *
+smbc_getOptionUserData(SMBCCTX *c)
+{
+ return c->internal->user_data;
+}
+
+/** Save a user data handle */
+void
+smbc_setOptionUserData(SMBCCTX *c, void *user_data)
+{
+ c->internal->user_data = user_data;
+}
+
+/** Get the encoded value for encryption level. */
+smbc_smb_encrypt_level
+smbc_getOptionSmbEncryptionLevel(SMBCCTX *c)
+{
+ return c->internal->smb_encryption_level;
+}
+
+/** Set the encoded value for encryption level. */
+void
+smbc_setOptionSmbEncryptionLevel(SMBCCTX *c, smbc_smb_encrypt_level level)
+{
+ c->internal->smb_encryption_level = level;
+}
+
+/**
+ * Get from how many local master browsers should the list of workgroups be
+ * retrieved. It can take up to 12 minutes or longer after a server becomes a
+ * local master browser, for it to have the entire browse list (the list of
+ * workgroups/domains) from an entire network. Since a client never knows
+ * which local master browser will be found first, the one which is found
+ * first and used to retrieve a browse list may have an incomplete or empty
+ * browse list. By requesting the browse list from multiple local master
+ * browsers, a more complete list can be generated. For small networks (few
+ * workgroups), it is recommended that this value be set to 0, causing the
+ * browse lists from all found local master browsers to be retrieved and
+ * merged. For networks with many workgroups, a suitable value for this
+ * variable is probably somewhere around 3. (Default: 3).
+ */
+int
+smbc_getOptionBrowseMaxLmbCount(SMBCCTX *c)
+{
+ return c->options.browse_max_lmb_count;
+}
+
+/**
+ * Set from how many local master browsers should the list of workgroups be
+ * retrieved. It can take up to 12 minutes or longer after a server becomes a
+ * local master browser, for it to have the entire browse list (the list of
+ * workgroups/domains) from an entire network. Since a client never knows
+ * which local master browser will be found first, the one which is found
+ * first and used to retrieve a browse list may have an incomplete or empty
+ * browse list. By requesting the browse list from multiple local master
+ * browsers, a more complete list can be generated. For small networks (few
+ * workgroups), it is recommended that this value be set to 0, causing the
+ * browse lists from all found local master browsers to be retrieved and
+ * merged. For networks with many workgroups, a suitable value for this
+ * variable is probably somewhere around 3. (Default: 3).
+ */
+void
+smbc_setOptionBrowseMaxLmbCount(SMBCCTX *c, int count)
+{
+ c->options.browse_max_lmb_count = count;
+}
+
+/**
+ * Get whether to url-encode readdir entries.
+ *
+ * There is a difference in the desired return strings from
+ * smbc_readdir() depending upon whether the filenames are to
+ * be displayed to the user, or whether they are to be
+ * appended to the path name passed to smbc_opendir() to call
+ * a further smbc_ function (e.g. open the file with
+ * smbc_open()). In the former case, the filename should be
+ * in "human readable" form. In the latter case, the smbc_
+ * functions expect a URL which must be url-encoded. Those
+ * functions decode the URL. If, for example, smbc_readdir()
+ * returned a file name of "abc%20def.txt", passing a path
+ * with this file name attached to smbc_open() would cause
+ * smbc_open to attempt to open the file "abc def.txt" since
+ * the %20 is decoded into a space.
+ *
+ * Set this option to True if the names returned by
+ * smbc_readdir() should be url-encoded such that they can be
+ * passed back to another smbc_ call. Set it to False if the
+ * names returned by smbc_readdir() are to be presented to the
+ * user.
+ *
+ * For backwards compatibility, this option defaults to False.
+ */
+smbc_bool
+smbc_getOptionUrlEncodeReaddirEntries(SMBCCTX *c)
+{
+ return c->options.urlencode_readdir_entries;
+}
+
+/**
+ * Set whether to url-encode readdir entries.
+ *
+ * There is a difference in the desired return strings from
+ * smbc_readdir() depending upon whether the filenames are to
+ * be displayed to the user, or whether they are to be
+ * appended to the path name passed to smbc_opendir() to call
+ * a further smbc_ function (e.g. open the file with
+ * smbc_open()). In the former case, the filename should be
+ * in "human readable" form. In the latter case, the smbc_
+ * functions expect a URL which must be url-encoded. Those
+ * functions decode the URL. If, for example, smbc_readdir()
+ * returned a file name of "abc%20def.txt", passing a path
+ * with this file name attached to smbc_open() would cause
+ * smbc_open to attempt to open the file "abc def.txt" since
+ * the %20 is decoded into a space.
+ *
+ * Set this option to True if the names returned by
+ * smbc_readdir() should be url-encoded such that they can be
+ * passed back to another smbc_ call. Set it to False if the
+ * names returned by smbc_readdir() are to be presented to the
+ * user.
+ *
+ * For backwards compatibility, this option defaults to False.
+ */
+void
+smbc_setOptionUrlEncodeReaddirEntries(SMBCCTX *c, smbc_bool b)
+{
+ c->options.urlencode_readdir_entries = b;
+}
+
+/**
+ * Get whether to use the same connection for all shares on a server.
+ *
+ * Some Windows versions appear to have a limit to the number
+ * of concurrent SESSIONs and/or TREE CONNECTions. In
+ * one-shot programs (i.e. the program runs and then quickly
+ * ends, thereby shutting down all connections), it is
+ * probably reasonable to establish a new connection for each
+ * share. In long-running applications, the limitation can be
+ * avoided by using only a single connection to each server,
+ * and issuing a new TREE CONNECT when the share is accessed.
+ */
+smbc_bool
+smbc_getOptionOneSharePerServer(SMBCCTX *c)
+{
+ return c->options.one_share_per_server;
+}
+
+/**
+ * Set whether to use the same connection for all shares on a server.
+ *
+ * Some Windows versions appear to have a limit to the number
+ * of concurrent SESSIONs and/or TREE CONNECTions. In
+ * one-shot programs (i.e. the program runs and then quickly
+ * ends, thereby shutting down all connections), it is
+ * probably reasonable to establish a new connection for each
+ * share. In long-running applications, the limitation can be
+ * avoided by using only a single connection to each server,
+ * and issuing a new TREE CONNECT when the share is accessed.
+ */
+void
+smbc_setOptionOneSharePerServer(SMBCCTX *c, smbc_bool b)
+{
+ c->options.one_share_per_server = b;
+}
+
+/** Get whether to enable use of kerberos */
+smbc_bool
+smbc_getOptionUseKerberos(SMBCCTX *c)
+{
+ return c->flags & SMB_CTX_FLAG_USE_KERBEROS ? True : False;
+}
+
+/** Set whether to enable use of kerberos */
+void
+smbc_setOptionUseKerberos(SMBCCTX *c, smbc_bool b)
+{
+ if (b) {
+ c->flags |= SMB_CTX_FLAG_USE_KERBEROS;
+ } else {
+ c->flags &= ~SMB_CTX_FLAG_USE_KERBEROS;
+ }
+}
+
+/** Get whether to fallback after kerberos */
+smbc_bool
+smbc_getOptionFallbackAfterKerberos(SMBCCTX *c)
+{
+ return c->flags & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS ? True : False;
+}
+
+/** Set whether to fallback after kerberos */
+void
+smbc_setOptionFallbackAfterKerberos(SMBCCTX *c, smbc_bool b)
+{
+ if (b) {
+ c->flags |= SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS;
+ } else {
+ c->flags &= ~SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS;
+ }
+}
+
+/** Get whether to automatically select anonymous login */
+smbc_bool
+smbc_getOptionNoAutoAnonymousLogin(SMBCCTX *c)
+{
+ return c->flags & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON ? True : False;
+}
+
+/** Set whether to automatically select anonymous login */
+void
+smbc_setOptionNoAutoAnonymousLogin(SMBCCTX *c, smbc_bool b)
+{
+ if (b) {
+ c->flags |= SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON;
+ } else {
+ c->flags &= ~SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON;
+ }
+}
+
+/** Get the function for obtaining authentication data */
+smbc_get_auth_data_fn
+smbc_getFunctionAuthData(SMBCCTX *c)
+{
+ return c->callbacks.auth_fn;
+}
+
+/** Set the function for obtaining authentication data */
+void
+smbc_setFunctionAuthData(SMBCCTX *c, smbc_get_auth_data_fn fn)
+{
+ c->internal->auth_fn_with_context = NULL;
+ c->callbacks.auth_fn = fn;
+}
+
+/** Get the new-style authentication function which includes the context. */
+smbc_get_auth_data_with_context_fn
+smbc_getFunctionAuthDataWithContext(SMBCCTX *c)
+{
+ return c->internal->auth_fn_with_context;
+}
+
+/** Set the new-style authentication function which includes the context. */
+void
+smbc_setFunctionAuthDataWithContext(SMBCCTX *c,
+ smbc_get_auth_data_with_context_fn fn)
+{
+ c->callbacks.auth_fn = NULL;
+ c->internal->auth_fn_with_context = fn;
+}
+
+/** Get the function for checking if a server is still good */
+smbc_check_server_fn
+smbc_getFunctionCheckServer(SMBCCTX *c)
+{
+ return c->callbacks.check_server_fn;
+}
+
+/** Set the function for checking if a server is still good */
+void
+smbc_setFunctionCheckServer(SMBCCTX *c, smbc_check_server_fn fn)
+{
+ c->callbacks.check_server_fn = fn;
+}
+
+/** Get the function for removing a server if unused */
+smbc_remove_unused_server_fn
+smbc_getFunctionRemoveUnusedServer(SMBCCTX *c)
+{
+ return c->callbacks.remove_unused_server_fn;
+}
+
+/** Set the function for removing a server if unused */
+void
+smbc_setFunctionRemoveUnusedServer(SMBCCTX *c,
+ smbc_remove_unused_server_fn fn)
+{
+ c->callbacks.remove_unused_server_fn = fn;
+}
+
+/** Get the function for adding a cached server */
+smbc_add_cached_srv_fn
+smbc_getFunctionAddCachedServer(SMBCCTX *c)
+{
+ return c->callbacks.add_cached_srv_fn;
+}
+
+/** Set the function for adding a cached server */
+void
+smbc_setFunctionAddCachedServer(SMBCCTX *c, smbc_add_cached_srv_fn fn)
+{
+ c->callbacks.add_cached_srv_fn = fn;
+}
+
+/** Get the function for server cache lookup */
+smbc_get_cached_srv_fn
+smbc_getFunctionGetCachedServer(SMBCCTX *c)
+{
+ return c->callbacks.get_cached_srv_fn;
+}
+
+/** Set the function for server cache lookup */
+void
+smbc_setFunctionGetCachedServer(SMBCCTX *c, smbc_get_cached_srv_fn fn)
+{
+ c->callbacks.get_cached_srv_fn = fn;
+}
+
+/** Get the function for server cache removal */
+smbc_remove_cached_srv_fn
+smbc_getFunctionRemoveCachedServer(SMBCCTX *c)
+{
+ return c->callbacks.remove_cached_srv_fn;
+}
+
+/** Set the function for server cache removal */
+void
+smbc_setFunctionRemoveCachedServer(SMBCCTX *c,
+ smbc_remove_cached_srv_fn fn)
+{
+ c->callbacks.remove_cached_srv_fn = fn;
+}
+
+/**
+ * Get the function for server cache purging. This function tries to
+ * remove all cached servers (e.g. on disconnect)
+ */
+smbc_purge_cached_fn
+smbc_getFunctionPurgeCachedServers(SMBCCTX *c)
+{
+ return c->callbacks.purge_cached_fn;
+}
+
+/** Set the function to store private data of the server cache */
+void smbc_setServerCacheData(SMBCCTX *c, struct smbc_server_cache * cache)
+{
+ c->internal->server_cache = cache;
+}
+
+/** Get the function to store private data of the server cache */
+struct smbc_server_cache * smbc_getServerCacheData(SMBCCTX *c)
+{
+ return c->internal->server_cache;
+}
+
+
+/**
+ * Set the function for server cache purging. This function tries to
+ * remove all cached servers (e.g. on disconnect)
+ */
+void
+smbc_setFunctionPurgeCachedServers(SMBCCTX *c, smbc_purge_cached_fn fn)
+{
+ c->callbacks.purge_cached_fn = fn;
+}
+
+/**
+ * Callable functions for files.
+ */
+
+smbc_open_fn
+smbc_getFunctionOpen(SMBCCTX *c)
+{
+ return c->open;
+}
+
+void
+smbc_setFunctionOpen(SMBCCTX *c, smbc_open_fn fn)
+{
+ c->open = fn;
+}
+
+smbc_creat_fn
+smbc_getFunctionCreat(SMBCCTX *c)
+{
+ return c->creat;
+}
+
+void
+smbc_setFunctionCreat(SMBCCTX *c, smbc_creat_fn fn)
+{
+ c->creat = fn;
+}
+
+smbc_read_fn
+smbc_getFunctionRead(SMBCCTX *c)
+{
+ return c->read;
+}
+
+void
+smbc_setFunctionRead(SMBCCTX *c, smbc_read_fn fn)
+{
+ c->read = fn;
+}
+
+smbc_write_fn
+smbc_getFunctionWrite(SMBCCTX *c)
+{
+ return c->write;
+}
+
+void
+smbc_setFunctionWrite(SMBCCTX *c, smbc_write_fn fn)
+{
+ c->write = fn;
+}
+
+smbc_unlink_fn
+smbc_getFunctionUnlink(SMBCCTX *c)
+{
+ return c->unlink;
+}
+
+void
+smbc_setFunctionUnlink(SMBCCTX *c, smbc_unlink_fn fn)
+{
+ c->unlink = fn;
+}
+
+smbc_rename_fn
+smbc_getFunctionRename(SMBCCTX *c)
+{
+ return c->rename;
+}
+
+void
+smbc_setFunctionRename(SMBCCTX *c, smbc_rename_fn fn)
+{
+ c->rename = fn;
+}
+
+smbc_lseek_fn
+smbc_getFunctionLseek(SMBCCTX *c)
+{
+ return c->lseek;
+}
+
+void
+smbc_setFunctionLseek(SMBCCTX *c, smbc_lseek_fn fn)
+{
+ c->lseek = fn;
+}
+
+smbc_stat_fn
+smbc_getFunctionStat(SMBCCTX *c)
+{
+ return c->stat;
+}
+
+void
+smbc_setFunctionStat(SMBCCTX *c, smbc_stat_fn fn)
+{
+ c->stat = fn;
+}
+
+smbc_fstat_fn
+smbc_getFunctionFstat(SMBCCTX *c)
+{
+ return c->fstat;
+}
+
+void
+smbc_setFunctionFstat(SMBCCTX *c, smbc_fstat_fn fn)
+{
+ c->fstat = fn;
+}
+
+smbc_ftruncate_fn
+smbc_getFunctionFtruncate(SMBCCTX *c)
+{
+ return c->internal->posix_emu.ftruncate_fn;
+}
+
+void
+smbc_setFunctionFtruncate(SMBCCTX *c, smbc_ftruncate_fn fn)
+{
+ c->internal->posix_emu.ftruncate_fn = fn;
+}
+
+smbc_close_fn
+smbc_getFunctionClose(SMBCCTX *c)
+{
+ return c->close_fn;
+}
+
+void
+smbc_setFunctionClose(SMBCCTX *c, smbc_close_fn fn)
+{
+ c->close_fn = fn;
+}
+
+
+/**
+ * Callable functions for directories.
+ */
+
+smbc_opendir_fn
+smbc_getFunctionOpendir(SMBCCTX *c)
+{
+ return c->opendir;
+}
+
+void
+smbc_setFunctionOpendir(SMBCCTX *c, smbc_opendir_fn fn)
+{
+ c->opendir = fn;
+}
+
+smbc_closedir_fn
+smbc_getFunctionClosedir(SMBCCTX *c)
+{
+ return c->closedir;
+}
+
+void
+smbc_setFunctionClosedir(SMBCCTX *c, smbc_closedir_fn fn)
+{
+ c->closedir = fn;
+}
+
+smbc_readdir_fn
+smbc_getFunctionReaddir(SMBCCTX *c)
+{
+ return c->readdir;
+}
+
+void
+smbc_setFunctionReaddir(SMBCCTX *c, smbc_readdir_fn fn)
+{
+ c->readdir = fn;
+}
+
+smbc_getdents_fn
+smbc_getFunctionGetdents(SMBCCTX *c)
+{
+ return c->getdents;
+}
+
+void
+smbc_setFunctionGetdents(SMBCCTX *c, smbc_getdents_fn fn)
+{
+ c->getdents = fn;
+}
+
+smbc_mkdir_fn
+smbc_getFunctionMkdir(SMBCCTX *c)
+{
+ return c->mkdir;
+}
+
+void
+smbc_setFunctionMkdir(SMBCCTX *c, smbc_mkdir_fn fn)
+{
+ c->mkdir = fn;
+}
+
+smbc_rmdir_fn
+smbc_getFunctionRmdir(SMBCCTX *c)
+{
+ return c->rmdir;
+}
+
+void
+smbc_setFunctionRmdir(SMBCCTX *c, smbc_rmdir_fn fn)
+{
+ c->rmdir = fn;
+}
+
+smbc_telldir_fn
+smbc_getFunctionTelldir(SMBCCTX *c)
+{
+ return c->telldir;
+}
+
+void
+smbc_setFunctionTelldir(SMBCCTX *c, smbc_telldir_fn fn)
+{
+ c->telldir = fn;
+}
+
+smbc_lseekdir_fn
+smbc_getFunctionLseekdir(SMBCCTX *c)
+{
+ return c->lseekdir;
+}
+
+void
+smbc_setFunctionLseekdir(SMBCCTX *c, smbc_lseekdir_fn fn)
+{
+ c->lseekdir = fn;
+}
+
+smbc_fstatdir_fn
+smbc_getFunctionFstatdir(SMBCCTX *c)
+{
+ return c->fstatdir;
+}
+
+void
+smbc_setFunctionFstatdir(SMBCCTX *c, smbc_fstatdir_fn fn)
+{
+ c->fstatdir = fn;
+}
+
+
+/**
+ * Callable functions applicable to both files and directories.
+ */
+
+smbc_chmod_fn
+smbc_getFunctionChmod(SMBCCTX *c)
+{
+ return c->chmod;
+}
+
+void
+smbc_setFunctionChmod(SMBCCTX *c, smbc_chmod_fn fn)
+{
+ c->chmod = fn;
+}
+
+smbc_utimes_fn
+smbc_getFunctionUtimes(SMBCCTX *c)
+{
+ return c->utimes;
+}
+
+void
+smbc_setFunctionUtimes(SMBCCTX *c, smbc_utimes_fn fn)
+{
+ c->utimes = fn;
+}
+
+smbc_setxattr_fn
+smbc_getFunctionSetxattr(SMBCCTX *c)
+{
+ return c->setxattr;
+}
+
+void
+smbc_setFunctionSetxattr(SMBCCTX *c, smbc_setxattr_fn fn)
+{
+ c->setxattr = fn;
+}
+
+smbc_getxattr_fn
+smbc_getFunctionGetxattr(SMBCCTX *c)
+{
+ return c->getxattr;
+}
+
+void
+smbc_setFunctionGetxattr(SMBCCTX *c, smbc_getxattr_fn fn)
+{
+ c->getxattr = fn;
+}
+
+smbc_removexattr_fn
+smbc_getFunctionRemovexattr(SMBCCTX *c)
+{
+ return c->removexattr;
+}
+
+void
+smbc_setFunctionRemovexattr(SMBCCTX *c, smbc_removexattr_fn fn)
+{
+ c->removexattr = fn;
+}
+
+smbc_listxattr_fn
+smbc_getFunctionListxattr(SMBCCTX *c)
+{
+ return c->listxattr;
+}
+
+void
+smbc_setFunctionListxattr(SMBCCTX *c, smbc_listxattr_fn fn)
+{
+ c->listxattr = fn;
+}
+
+
+/**
+ * Callable functions related to printing
+ */
+
+smbc_print_file_fn
+smbc_getFunctionPrintFile(SMBCCTX *c)
+{
+ return c->print_file;
+}
+
+void
+smbc_setFunctionPrintFile(SMBCCTX *c, smbc_print_file_fn fn)
+{
+ c->print_file = fn;
+}
+
+smbc_open_print_job_fn
+smbc_getFunctionOpenPrintJob(SMBCCTX *c)
+{
+ return c->open_print_job;
+}
+
+void
+smbc_setFunctionOpenPrintJob(SMBCCTX *c,
+ smbc_open_print_job_fn fn)
+{
+ c->open_print_job = fn;
+}
+
+smbc_list_print_jobs_fn
+smbc_getFunctionListPrintJobs(SMBCCTX *c)
+{
+ return c->list_print_jobs;
+}
+
+void
+smbc_setFunctionListPrintJobs(SMBCCTX *c,
+ smbc_list_print_jobs_fn fn)
+{
+ c->list_print_jobs = fn;
+}
+
+smbc_unlink_print_job_fn
+smbc_getFunctionUnlinkPrintJob(SMBCCTX *c)
+{
+ return c->unlink_print_job;
+}
+
+void
+smbc_setFunctionUnlinkPrintJob(SMBCCTX *c,
+ smbc_unlink_print_job_fn fn)
+{
+ c->unlink_print_job = fn;
+}
+
diff --git a/source3/libsmb/libsmb_stat.c b/source3/libsmb/libsmb_stat.c
new file mode 100644
index 0000000000..27546f687e
--- /dev/null
+++ b/source3/libsmb/libsmb_stat.c
@@ -0,0 +1,302 @@
+/*
+ Unix SMB/Netbios implementation.
+ SMB client library implementation
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000, 2002
+ Copyright (C) John Terpstra 2000
+ Copyright (C) Tom Jansen (Ninja ISD) 2002
+ Copyright (C) Derrell Lipman 2003-2008
+ Copyright (C) Jeremy Allison 2007, 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libsmbclient.h"
+#include "libsmb_internal.h"
+
+
+/*
+ * Generate an inode number from file name for those things that need it
+ */
+
+static ino_t
+generate_inode(SMBCCTX *context,
+ const char *name)
+{
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!*name) return 2; /* FIXME, why 2 ??? */
+ return (ino_t)str_checksum(name);
+
+}
+
+/*
+ * Routine to put basic stat info into a stat structure ... Used by stat and
+ * fstat below.
+ */
+
+static int
+setup_stat(SMBCCTX *context,
+ struct stat *st,
+ char *fname,
+ SMB_OFF_T size,
+ int mode)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ st->st_mode = 0;
+
+ if (IS_DOS_DIR(mode)) {
+ st->st_mode = SMBC_DIR_MODE;
+ } else {
+ st->st_mode = SMBC_FILE_MODE;
+ }
+
+ if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR;
+ if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP;
+ if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH;
+ if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR;
+
+ st->st_size = size;
+#ifdef HAVE_STAT_ST_BLKSIZE
+ st->st_blksize = 512;
+#endif
+#ifdef HAVE_STAT_ST_BLOCKS
+ st->st_blocks = (size+511)/512;
+#endif
+#ifdef HAVE_STRUCT_STAT_ST_RDEV
+ st->st_rdev = 0;
+#endif
+ st->st_uid = getuid();
+ st->st_gid = getgid();
+
+ if (IS_DOS_DIR(mode)) {
+ st->st_nlink = 2;
+ } else {
+ st->st_nlink = 1;
+ }
+
+ if (st->st_ino == 0) {
+ st->st_ino = generate_inode(context, fname);
+ }
+
+ TALLOC_FREE(frame);
+ return True; /* FIXME: Is this needed ? */
+
+}
+
+/*
+ * Routine to stat a file given a name
+ */
+
+int
+SMBC_stat_ctx(SMBCCTX *context,
+ const char *fname,
+ struct stat *st)
+{
+ SMBCSRV *srv = NULL;
+ char *server = NULL;
+ char *share = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *workgroup = NULL;
+ char *path = NULL;
+ struct timespec write_time_ts;
+ struct timespec access_time_ts;
+ struct timespec change_time_ts;
+ SMB_OFF_T size = 0;
+ uint16 mode = 0;
+ SMB_INO_T ino = 0;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!fname) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ DEBUG(4, ("smbc_stat(%s)\n", fname));
+
+ if (SMBC_parse_path(frame,
+ context,
+ fname,
+ &workgroup,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!user || user[0] == (char)0) {
+ user = talloc_strdup(frame, smbc_getUser(context));
+ if (!user) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ }
+
+ srv = SMBC_server(frame, context, True,
+ server, share, &workgroup, &user, &password);
+
+ if (!srv) {
+ TALLOC_FREE(frame);
+ return -1; /* errno set by SMBC_server */
+ }
+
+ if (!SMBC_getatr(context, srv, path, &mode, &size,
+ NULL,
+ &access_time_ts,
+ &write_time_ts,
+ &change_time_ts,
+ &ino)) {
+ errno = SMBC_errno(context, srv->cli);
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ st->st_ino = ino;
+
+ setup_stat(context, st, (char *) fname, size, mode);
+
+ set_atimespec(st, access_time_ts);
+ set_ctimespec(st, change_time_ts);
+ set_mtimespec(st, write_time_ts);
+ st->st_dev = srv->dev;
+
+ TALLOC_FREE(frame);
+ return 0;
+
+}
+
+/*
+ * Routine to stat a file given an fd
+ */
+
+int
+SMBC_fstat_ctx(SMBCCTX *context,
+ SMBCFILE *file,
+ struct stat *st)
+{
+ struct timespec change_time_ts;
+ struct timespec access_time_ts;
+ struct timespec write_time_ts;
+ SMB_OFF_T size;
+ uint16 mode;
+ char *server = NULL;
+ char *share = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *path = NULL;
+ char *targetpath = NULL;
+ struct cli_state *targetcli = NULL;
+ SMB_INO_T ino = 0;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
+ errno = EBADF;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!file->file) {
+ TALLOC_FREE(frame);
+ return smbc_getFunctionFstatdir(context)(context, file, st);
+ }
+
+ /*d_printf(">>>fstat: parsing %s\n", file->fname);*/
+ if (SMBC_parse_path(frame,
+ context,
+ file->fname,
+ NULL,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ /*d_printf(">>>fstat: resolving %s\n", path);*/
+ if (!cli_resolve_path(frame, "", file->srv->cli, path,
+ &targetcli, &targetpath)) {
+ d_printf("Could not resolve %s\n", path);
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
+
+ if (!cli_qfileinfo(targetcli, file->cli_fd, &mode, &size,
+ NULL,
+ &access_time_ts,
+ &write_time_ts,
+ &change_time_ts,
+ &ino)) {
+
+ time_t change_time, access_time, write_time;
+
+ if (!cli_getattrE(targetcli, file->cli_fd, &mode, &size,
+ &change_time, &access_time, &write_time)) {
+
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ change_time_ts = convert_time_t_to_timespec(change_time);
+ access_time_ts = convert_time_t_to_timespec(access_time);
+ write_time_ts = convert_time_t_to_timespec(write_time);
+ }
+
+ st->st_ino = ino;
+
+ setup_stat(context, st, file->fname, size, mode);
+
+ set_atimespec(st, access_time_ts);
+ set_ctimespec(st, change_time_ts);
+ set_mtimespec(st, write_time_ts);
+ st->st_dev = file->srv->dev;
+
+ TALLOC_FREE(frame);
+ return 0;
+
+}
diff --git a/source3/libsmb/libsmb_xattr.c b/source3/libsmb/libsmb_xattr.c
new file mode 100644
index 0000000000..f1b3d1415e
--- /dev/null
+++ b/source3/libsmb/libsmb_xattr.c
@@ -0,0 +1,2323 @@
+/*
+ Unix SMB/Netbios implementation.
+ SMB client library implementation
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000, 2002
+ Copyright (C) John Terpstra 2000
+ Copyright (C) Tom Jansen (Ninja ISD) 2002
+ Copyright (C) Derrell Lipman 2003-2008
+ Copyright (C) Jeremy Allison 2007, 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libsmbclient.h"
+#include "libsmb_internal.h"
+
+
+/*
+ * Find an lsa pipe handle associated with a cli struct.
+ */
+static struct rpc_pipe_client *
+find_lsa_pipe_hnd(struct cli_state *ipc_cli)
+{
+ struct rpc_pipe_client *pipe_hnd;
+
+ for (pipe_hnd = ipc_cli->pipe_list;
+ pipe_hnd;
+ pipe_hnd = pipe_hnd->next) {
+
+ if (ndr_syntax_id_equal(&pipe_hnd->abstract_syntax,
+ &ndr_table_lsarpc.syntax_id)) {
+ return pipe_hnd;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Sort ACEs according to the documentation at
+ * http://support.microsoft.com/kb/269175, at least as far as it defines the
+ * order.
+ */
+
+static int
+ace_compare(SEC_ACE *ace1,
+ SEC_ACE *ace2)
+{
+ bool b1;
+ bool b2;
+
+ /* If the ACEs are equal, we have nothing more to do. */
+ if (sec_ace_equal(ace1, ace2)) {
+ return 0;
+ }
+
+ /* Inherited follow non-inherited */
+ b1 = ((ace1->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0);
+ b2 = ((ace2->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0);
+ if (b1 != b2) {
+ return (b1 ? 1 : -1);
+ }
+
+ /*
+ * What shall we do with AUDITs and ALARMs? It's undefined. We'll
+ * sort them after DENY and ALLOW.
+ */
+ b1 = (ace1->type != SEC_ACE_TYPE_ACCESS_ALLOWED &&
+ ace1->type != SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT &&
+ ace1->type != SEC_ACE_TYPE_ACCESS_DENIED &&
+ ace1->type != SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
+ b2 = (ace2->type != SEC_ACE_TYPE_ACCESS_ALLOWED &&
+ ace2->type != SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT &&
+ ace2->type != SEC_ACE_TYPE_ACCESS_DENIED &&
+ ace2->type != SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
+ if (b1 != b2) {
+ return (b1 ? 1 : -1);
+ }
+
+ /* Allowed ACEs follow denied ACEs */
+ b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED ||
+ ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT);
+ b2 = (ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED ||
+ ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT);
+ if (b1 != b2) {
+ return (b1 ? 1 : -1);
+ }
+
+ /*
+ * ACEs applying to an entity's object follow those applying to the
+ * entity itself
+ */
+ b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
+ ace1->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
+ b2 = (ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
+ ace2->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
+ if (b1 != b2) {
+ return (b1 ? 1 : -1);
+ }
+
+ /*
+ * If we get this far, the ACEs are similar as far as the
+ * characteristics we typically care about (those defined by the
+ * referenced MS document). We'll now sort by characteristics that
+ * just seems reasonable.
+ */
+
+ if (ace1->type != ace2->type) {
+ return ace2->type - ace1->type;
+ }
+
+ if (sid_compare(&ace1->trustee, &ace2->trustee)) {
+ return sid_compare(&ace1->trustee, &ace2->trustee);
+ }
+
+ if (ace1->flags != ace2->flags) {
+ return ace1->flags - ace2->flags;
+ }
+
+ if (ace1->access_mask != ace2->access_mask) {
+ return ace1->access_mask - ace2->access_mask;
+ }
+
+ if (ace1->size != ace2->size) {
+ return ace1->size - ace2->size;
+ }
+
+ return memcmp(ace1, ace2, sizeof(SEC_ACE));
+}
+
+
+static void
+sort_acl(SEC_ACL *the_acl)
+{
+ uint32 i;
+ if (!the_acl) return;
+
+ qsort(the_acl->aces, the_acl->num_aces, sizeof(the_acl->aces[0]),
+ QSORT_CAST ace_compare);
+
+ for (i=1;i<the_acl->num_aces;) {
+ if (sec_ace_equal(&the_acl->aces[i-1], &the_acl->aces[i])) {
+ int j;
+ for (j=i; j<the_acl->num_aces-1; j++) {
+ the_acl->aces[j] = the_acl->aces[j+1];
+ }
+ the_acl->num_aces--;
+ } else {
+ i++;
+ }
+ }
+}
+
+/* convert a SID to a string, either numeric or username/group */
+static void
+convert_sid_to_string(struct cli_state *ipc_cli,
+ POLICY_HND *pol,
+ fstring str,
+ bool numeric,
+ DOM_SID *sid)
+{
+ char **domains = NULL;
+ char **names = NULL;
+ enum lsa_SidType *types = NULL;
+ struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
+ TALLOC_CTX *ctx;
+
+ sid_to_fstring(str, sid);
+
+ if (numeric) {
+ return; /* no lookup desired */
+ }
+
+ if (!pipe_hnd) {
+ return;
+ }
+
+ /* Ask LSA to convert the sid to a name */
+
+ ctx = talloc_stackframe();
+
+ if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(pipe_hnd, ctx,
+ pol, 1, sid, &domains,
+ &names, &types)) ||
+ !domains || !domains[0] || !names || !names[0]) {
+ TALLOC_FREE(ctx);
+ return;
+ }
+
+ TALLOC_FREE(ctx);
+ /* Converted OK */
+
+ slprintf(str, sizeof(fstring) - 1, "%s%s%s",
+ domains[0], lp_winbind_separator(),
+ names[0]);
+}
+
+/* convert a string to a SID, either numeric or username/group */
+static bool
+convert_string_to_sid(struct cli_state *ipc_cli,
+ POLICY_HND *pol,
+ bool numeric,
+ DOM_SID *sid,
+ const char *str)
+{
+ enum lsa_SidType *types = NULL;
+ DOM_SID *sids = NULL;
+ bool result = True;
+ TALLOC_CTX *ctx = NULL;
+ struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
+
+ if (!pipe_hnd) {
+ return False;
+ }
+
+ if (numeric) {
+ if (strncmp(str, "S-", 2) == 0) {
+ return string_to_sid(sid, str);
+ }
+
+ result = False;
+ goto done;
+ }
+
+ ctx = talloc_stackframe();
+ if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_names(pipe_hnd, ctx,
+ pol, 1, &str,
+ NULL, 1, &sids,
+ &types))) {
+ result = False;
+ goto done;
+ }
+
+ sid_copy(sid, &sids[0]);
+done:
+
+ TALLOC_FREE(ctx);
+ return result;
+}
+
+
+/* parse an ACE in the same format as print_ace() */
+static bool
+parse_ace(struct cli_state *ipc_cli,
+ POLICY_HND *pol,
+ SEC_ACE *ace,
+ bool numeric,
+ char *str)
+{
+ char *p;
+ const char *cp;
+ char *tok;
+ unsigned int atype;
+ unsigned int aflags;
+ unsigned int amask;
+ DOM_SID sid;
+ SEC_ACCESS mask;
+ const struct perm_value *v;
+ struct perm_value {
+ const char *perm;
+ uint32 mask;
+ };
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ /* These values discovered by inspection */
+ static const struct perm_value special_values[] = {
+ { "R", 0x00120089 },
+ { "W", 0x00120116 },
+ { "X", 0x001200a0 },
+ { "D", 0x00010000 },
+ { "P", 0x00040000 },
+ { "O", 0x00080000 },
+ { NULL, 0 },
+ };
+
+ static const struct perm_value standard_values[] = {
+ { "READ", 0x001200a9 },
+ { "CHANGE", 0x001301bf },
+ { "FULL", 0x001f01ff },
+ { NULL, 0 },
+ };
+
+
+ ZERO_STRUCTP(ace);
+ p = strchr_m(str,':');
+ if (!p) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+ *p = '\0';
+ p++;
+ /* Try to parse numeric form */
+
+ if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 &&
+ convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) {
+ goto done;
+ }
+
+ /* Try to parse text form */
+
+ if (!convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ cp = p;
+ if (!next_token_talloc(frame, &cp, &tok, "/")) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ if (StrnCaseCmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
+ atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ } else if (StrnCaseCmp(tok, "DENIED", strlen("DENIED")) == 0) {
+ atype = SEC_ACE_TYPE_ACCESS_DENIED;
+ } else {
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ /* Only numeric form accepted for flags at present */
+
+ if (!(next_token_talloc(frame, &cp, &tok, "/") &&
+ sscanf(tok, "%i", &aflags))) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ if (!next_token_talloc(frame, &cp, &tok, "/")) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ if (strncmp(tok, "0x", 2) == 0) {
+ if (sscanf(tok, "%i", &amask) != 1) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+ goto done;
+ }
+
+ for (v = standard_values; v->perm; v++) {
+ if (strcmp(tok, v->perm) == 0) {
+ amask = v->mask;
+ goto done;
+ }
+ }
+
+ p = tok;
+
+ while(*p) {
+ bool found = False;
+
+ for (v = special_values; v->perm; v++) {
+ if (v->perm[0] == *p) {
+ amask |= v->mask;
+ found = True;
+ }
+ }
+
+ if (!found) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+ p++;
+ }
+
+ if (*p) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+done:
+ mask = amask;
+ init_sec_ace(ace, &sid, atype, mask, aflags);
+ TALLOC_FREE(frame);
+ return true;
+}
+
+/* add an ACE to a list of ACEs in a SEC_ACL */
+static bool
+add_ace(SEC_ACL **the_acl,
+ SEC_ACE *ace,
+ TALLOC_CTX *ctx)
+{
+ SEC_ACL *newacl;
+ SEC_ACE *aces;
+
+ if (! *the_acl) {
+ (*the_acl) = make_sec_acl(ctx, 3, 1, ace);
+ return True;
+ }
+
+ if ((aces = SMB_CALLOC_ARRAY(SEC_ACE,
+ 1+(*the_acl)->num_aces)) == NULL) {
+ return False;
+ }
+ memcpy(aces, (*the_acl)->aces, (*the_acl)->num_aces * sizeof(SEC_ACE));
+ memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE));
+ newacl = make_sec_acl(ctx, (*the_acl)->revision,
+ 1+(*the_acl)->num_aces, aces);
+ SAFE_FREE(aces);
+ (*the_acl) = newacl;
+ return True;
+}
+
+
+/* parse a ascii version of a security descriptor */
+static SEC_DESC *
+sec_desc_parse(TALLOC_CTX *ctx,
+ struct cli_state *ipc_cli,
+ POLICY_HND *pol,
+ bool numeric,
+ char *str)
+{
+ const char *p = str;
+ char *tok;
+ SEC_DESC *ret = NULL;
+ size_t sd_size;
+ DOM_SID *group_sid=NULL;
+ DOM_SID *owner_sid=NULL;
+ SEC_ACL *dacl=NULL;
+ int revision=1;
+
+ while (next_token_talloc(ctx, &p, &tok, "\t,\r\n")) {
+
+ if (StrnCaseCmp(tok,"REVISION:", 9) == 0) {
+ revision = strtol(tok+9, NULL, 16);
+ continue;
+ }
+
+ if (StrnCaseCmp(tok,"OWNER:", 6) == 0) {
+ if (owner_sid) {
+ DEBUG(5,("OWNER specified more than once!\n"));
+ goto done;
+ }
+ owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
+ if (!owner_sid ||
+ !convert_string_to_sid(ipc_cli, pol,
+ numeric,
+ owner_sid, tok+6)) {
+ DEBUG(5, ("Failed to parse owner sid\n"));
+ goto done;
+ }
+ continue;
+ }
+
+ if (StrnCaseCmp(tok,"OWNER+:", 7) == 0) {
+ if (owner_sid) {
+ DEBUG(5,("OWNER specified more than once!\n"));
+ goto done;
+ }
+ owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
+ if (!owner_sid ||
+ !convert_string_to_sid(ipc_cli, pol,
+ False,
+ owner_sid, tok+7)) {
+ DEBUG(5, ("Failed to parse owner sid\n"));
+ goto done;
+ }
+ continue;
+ }
+
+ if (StrnCaseCmp(tok,"GROUP:", 6) == 0) {
+ if (group_sid) {
+ DEBUG(5,("GROUP specified more than once!\n"));
+ goto done;
+ }
+ group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
+ if (!group_sid ||
+ !convert_string_to_sid(ipc_cli, pol,
+ numeric,
+ group_sid, tok+6)) {
+ DEBUG(5, ("Failed to parse group sid\n"));
+ goto done;
+ }
+ continue;
+ }
+
+ if (StrnCaseCmp(tok,"GROUP+:", 7) == 0) {
+ if (group_sid) {
+ DEBUG(5,("GROUP specified more than once!\n"));
+ goto done;
+ }
+ group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
+ if (!group_sid ||
+ !convert_string_to_sid(ipc_cli, pol,
+ False,
+ group_sid, tok+6)) {
+ DEBUG(5, ("Failed to parse group sid\n"));
+ goto done;
+ }
+ continue;
+ }
+
+ if (StrnCaseCmp(tok,"ACL:", 4) == 0) {
+ SEC_ACE ace;
+ if (!parse_ace(ipc_cli, pol, &ace, numeric, tok+4)) {
+ DEBUG(5, ("Failed to parse ACL %s\n", tok));
+ goto done;
+ }
+ if(!add_ace(&dacl, &ace, ctx)) {
+ DEBUG(5, ("Failed to add ACL %s\n", tok));
+ goto done;
+ }
+ continue;
+ }
+
+ if (StrnCaseCmp(tok,"ACL+:", 5) == 0) {
+ SEC_ACE ace;
+ if (!parse_ace(ipc_cli, pol, &ace, False, tok+5)) {
+ DEBUG(5, ("Failed to parse ACL %s\n", tok));
+ goto done;
+ }
+ if(!add_ace(&dacl, &ace, ctx)) {
+ DEBUG(5, ("Failed to add ACL %s\n", tok));
+ goto done;
+ }
+ continue;
+ }
+
+ DEBUG(5, ("Failed to parse security descriptor\n"));
+ goto done;
+ }
+
+ ret = make_sec_desc(ctx, revision, SEC_DESC_SELF_RELATIVE,
+ owner_sid, group_sid, NULL, dacl, &sd_size);
+
+done:
+ SAFE_FREE(group_sid);
+ SAFE_FREE(owner_sid);
+
+ return ret;
+}
+
+
+/* Obtain the current dos attributes */
+static DOS_ATTR_DESC *
+dos_attr_query(SMBCCTX *context,
+ TALLOC_CTX *ctx,
+ const char *filename,
+ SMBCSRV *srv)
+{
+ struct timespec create_time_ts;
+ struct timespec write_time_ts;
+ struct timespec access_time_ts;
+ struct timespec change_time_ts;
+ SMB_OFF_T size = 0;
+ uint16 mode = 0;
+ SMB_INO_T inode = 0;
+ DOS_ATTR_DESC *ret;
+
+ ret = TALLOC_P(ctx, DOS_ATTR_DESC);
+ if (!ret) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ /* Obtain the DOS attributes */
+ if (!SMBC_getatr(context, srv, CONST_DISCARD(char *, filename),
+ &mode, &size,
+ &create_time_ts,
+ &access_time_ts,
+ &write_time_ts,
+ &change_time_ts,
+ &inode)) {
+ errno = SMBC_errno(context, srv->cli);
+ DEBUG(5, ("dos_attr_query Failed to query old attributes\n"));
+ return NULL;
+ }
+
+ ret->mode = mode;
+ ret->size = size;
+ ret->create_time = convert_timespec_to_time_t(create_time_ts);
+ ret->access_time = convert_timespec_to_time_t(access_time_ts);
+ ret->write_time = convert_timespec_to_time_t(write_time_ts);
+ ret->change_time = convert_timespec_to_time_t(change_time_ts);
+ ret->inode = inode;
+
+ return ret;
+}
+
+
+/* parse a ascii version of a security descriptor */
+static void
+dos_attr_parse(SMBCCTX *context,
+ DOS_ATTR_DESC *dad,
+ SMBCSRV *srv,
+ char *str)
+{
+ int n;
+ const char *p = str;
+ char *tok = NULL;
+ TALLOC_CTX *frame = NULL;
+ struct {
+ const char * create_time_attr;
+ const char * access_time_attr;
+ const char * write_time_attr;
+ const char * change_time_attr;
+ } attr_strings;
+
+ /* Determine whether to use old-style or new-style attribute names */
+ if (context->internal->full_time_names) {
+ /* new-style names */
+ attr_strings.create_time_attr = "CREATE_TIME";
+ attr_strings.access_time_attr = "ACCESS_TIME";
+ attr_strings.write_time_attr = "WRITE_TIME";
+ attr_strings.change_time_attr = "CHANGE_TIME";
+ } else {
+ /* old-style names */
+ attr_strings.create_time_attr = NULL;
+ attr_strings.access_time_attr = "A_TIME";
+ attr_strings.write_time_attr = "M_TIME";
+ attr_strings.change_time_attr = "C_TIME";
+ }
+
+ /* if this is to set the entire ACL... */
+ if (*str == '*') {
+ /* ... then increment past the first colon if there is one */
+ if ((p = strchr(str, ':')) != NULL) {
+ ++p;
+ } else {
+ p = str;
+ }
+ }
+
+ frame = talloc_stackframe();
+ while (next_token_talloc(frame, &p, &tok, "\t,\r\n")) {
+ if (StrnCaseCmp(tok, "MODE:", 5) == 0) {
+ long request = strtol(tok+5, NULL, 16);
+ if (request == 0) {
+ dad->mode = (request |
+ (IS_DOS_DIR(dad->mode)
+ ? FILE_ATTRIBUTE_DIRECTORY
+ : FILE_ATTRIBUTE_NORMAL));
+ } else {
+ dad->mode = request;
+ }
+ continue;
+ }
+
+ if (StrnCaseCmp(tok, "SIZE:", 5) == 0) {
+ dad->size = (SMB_OFF_T)atof(tok+5);
+ continue;
+ }
+
+ n = strlen(attr_strings.access_time_attr);
+ if (StrnCaseCmp(tok, attr_strings.access_time_attr, n) == 0) {
+ dad->access_time = (time_t)strtol(tok+n+1, NULL, 10);
+ continue;
+ }
+
+ n = strlen(attr_strings.change_time_attr);
+ if (StrnCaseCmp(tok, attr_strings.change_time_attr, n) == 0) {
+ dad->change_time = (time_t)strtol(tok+n+1, NULL, 10);
+ continue;
+ }
+
+ n = strlen(attr_strings.write_time_attr);
+ if (StrnCaseCmp(tok, attr_strings.write_time_attr, n) == 0) {
+ dad->write_time = (time_t)strtol(tok+n+1, NULL, 10);
+ continue;
+ }
+
+ if (attr_strings.create_time_attr != NULL) {
+ n = strlen(attr_strings.create_time_attr);
+ if (StrnCaseCmp(tok, attr_strings.create_time_attr,
+ n) == 0) {
+ dad->create_time = (time_t)strtol(tok+n+1,
+ NULL, 10);
+ continue;
+ }
+ }
+
+ if (StrnCaseCmp(tok, "INODE:", 6) == 0) {
+ dad->inode = (SMB_INO_T)atof(tok+6);
+ continue;
+ }
+ }
+ TALLOC_FREE(frame);
+}
+
+/*****************************************************
+ Retrieve the acls for a file.
+*******************************************************/
+
+static int
+cacl_get(SMBCCTX *context,
+ TALLOC_CTX *ctx,
+ SMBCSRV *srv,
+ struct cli_state *ipc_cli,
+ POLICY_HND *pol,
+ char *filename,
+ char *attr_name,
+ char *buf,
+ int bufsize)
+{
+ uint32 i;
+ int n = 0;
+ int n_used;
+ bool all;
+ bool all_nt;
+ bool all_nt_acls;
+ bool all_dos;
+ bool some_nt;
+ bool some_dos;
+ bool exclude_nt_revision = False;
+ bool exclude_nt_owner = False;
+ bool exclude_nt_group = False;
+ bool exclude_nt_acl = False;
+ bool exclude_dos_mode = False;
+ bool exclude_dos_size = False;
+ bool exclude_dos_create_time = False;
+ bool exclude_dos_access_time = False;
+ bool exclude_dos_write_time = False;
+ bool exclude_dos_change_time = False;
+ bool exclude_dos_inode = False;
+ bool numeric = True;
+ bool determine_size = (bufsize == 0);
+ int fnum = -1;
+ SEC_DESC *sd;
+ fstring sidstr;
+ fstring name_sandbox;
+ char *name;
+ char *pExclude;
+ char *p;
+ struct timespec create_time_ts;
+ struct timespec write_time_ts;
+ struct timespec access_time_ts;
+ struct timespec change_time_ts;
+ time_t create_time = (time_t)0;
+ time_t write_time = (time_t)0;
+ time_t access_time = (time_t)0;
+ time_t change_time = (time_t)0;
+ SMB_OFF_T size = 0;
+ uint16 mode = 0;
+ SMB_INO_T ino = 0;
+ struct cli_state *cli = srv->cli;
+ struct {
+ const char * create_time_attr;
+ const char * access_time_attr;
+ const char * write_time_attr;
+ const char * change_time_attr;
+ } attr_strings;
+ struct {
+ const char * create_time_attr;
+ const char * access_time_attr;
+ const char * write_time_attr;
+ const char * change_time_attr;
+ } excl_attr_strings;
+
+ /* Determine whether to use old-style or new-style attribute names */
+ if (context->internal->full_time_names) {
+ /* new-style names */
+ attr_strings.create_time_attr = "CREATE_TIME";
+ attr_strings.access_time_attr = "ACCESS_TIME";
+ attr_strings.write_time_attr = "WRITE_TIME";
+ attr_strings.change_time_attr = "CHANGE_TIME";
+
+ excl_attr_strings.create_time_attr = "CREATE_TIME";
+ excl_attr_strings.access_time_attr = "ACCESS_TIME";
+ excl_attr_strings.write_time_attr = "WRITE_TIME";
+ excl_attr_strings.change_time_attr = "CHANGE_TIME";
+ } else {
+ /* old-style names */
+ attr_strings.create_time_attr = NULL;
+ attr_strings.access_time_attr = "A_TIME";
+ attr_strings.write_time_attr = "M_TIME";
+ attr_strings.change_time_attr = "C_TIME";
+
+ excl_attr_strings.create_time_attr = NULL;
+ excl_attr_strings.access_time_attr = "dos_attr.A_TIME";
+ excl_attr_strings.write_time_attr = "dos_attr.M_TIME";
+ excl_attr_strings.change_time_attr = "dos_attr.C_TIME";
+ }
+
+ /* Copy name so we can strip off exclusions (if any are specified) */
+ strncpy(name_sandbox, attr_name, sizeof(name_sandbox) - 1);
+
+ /* Ensure name is null terminated */
+ name_sandbox[sizeof(name_sandbox) - 1] = '\0';
+
+ /* Play in the sandbox */
+ name = name_sandbox;
+
+ /* If there are any exclusions, point to them and mask them from name */
+ if ((pExclude = strchr(name, '!')) != NULL)
+ {
+ *pExclude++ = '\0';
+ }
+
+ all = (StrnCaseCmp(name, "system.*", 8) == 0);
+ all_nt = (StrnCaseCmp(name, "system.nt_sec_desc.*", 20) == 0);
+ all_nt_acls = (StrnCaseCmp(name, "system.nt_sec_desc.acl.*", 24) == 0);
+ all_dos = (StrnCaseCmp(name, "system.dos_attr.*", 17) == 0);
+ some_nt = (StrnCaseCmp(name, "system.nt_sec_desc.", 19) == 0);
+ some_dos = (StrnCaseCmp(name, "system.dos_attr.", 16) == 0);
+ numeric = (* (name + strlen(name) - 1) != '+');
+
+ /* Look for exclusions from "all" requests */
+ if (all || all_nt || all_dos) {
+
+ /* Exclusions are delimited by '!' */
+ for (;
+ pExclude != NULL;
+ pExclude = (p == NULL ? NULL : p + 1)) {
+
+ /* Find end of this exclusion name */
+ if ((p = strchr(pExclude, '!')) != NULL)
+ {
+ *p = '\0';
+ }
+
+ /* Which exclusion name is this? */
+ if (StrCaseCmp(pExclude,
+ "nt_sec_desc.revision") == 0) {
+ exclude_nt_revision = True;
+ }
+ else if (StrCaseCmp(pExclude,
+ "nt_sec_desc.owner") == 0) {
+ exclude_nt_owner = True;
+ }
+ else if (StrCaseCmp(pExclude,
+ "nt_sec_desc.group") == 0) {
+ exclude_nt_group = True;
+ }
+ else if (StrCaseCmp(pExclude,
+ "nt_sec_desc.acl") == 0) {
+ exclude_nt_acl = True;
+ }
+ else if (StrCaseCmp(pExclude,
+ "dos_attr.mode") == 0) {
+ exclude_dos_mode = True;
+ }
+ else if (StrCaseCmp(pExclude,
+ "dos_attr.size") == 0) {
+ exclude_dos_size = True;
+ }
+ else if (excl_attr_strings.create_time_attr != NULL &&
+ StrCaseCmp(pExclude,
+ excl_attr_strings.change_time_attr) == 0) {
+ exclude_dos_create_time = True;
+ }
+ else if (StrCaseCmp(pExclude,
+ excl_attr_strings.access_time_attr) == 0) {
+ exclude_dos_access_time = True;
+ }
+ else if (StrCaseCmp(pExclude,
+ excl_attr_strings.write_time_attr) == 0) {
+ exclude_dos_write_time = True;
+ }
+ else if (StrCaseCmp(pExclude,
+ excl_attr_strings.change_time_attr) == 0) {
+ exclude_dos_change_time = True;
+ }
+ else if (StrCaseCmp(pExclude, "dos_attr.inode") == 0) {
+ exclude_dos_inode = True;
+ }
+ else {
+ DEBUG(5, ("cacl_get received unknown exclusion: %s\n",
+ pExclude));
+ errno = ENOATTR;
+ return -1;
+ }
+ }
+ }
+
+ n_used = 0;
+
+ /*
+ * If we are (possibly) talking to an NT or new system and some NT
+ * attributes have been requested...
+ */
+ if (ipc_cli && (all || some_nt || all_nt_acls)) {
+ char *targetpath = NULL;
+ struct cli_state *targetcli = NULL;
+
+ /* Point to the portion after "system.nt_sec_desc." */
+ name += 19; /* if (all) this will be invalid but unused */
+
+ if (!cli_resolve_path(ctx, "", cli, filename,
+ &targetcli, &targetpath)) {
+ DEBUG(5, ("cacl_get Could not resolve %s\n",
+ filename));
+ errno = ENOENT;
+ return -1;
+ }
+
+ /* ... then obtain any NT attributes which were requested */
+ fnum = cli_nt_create(targetcli, targetpath, CREATE_ACCESS_READ);
+
+ if (fnum == -1) {
+ DEBUG(5, ("cacl_get failed to open %s: %s\n",
+ targetpath, cli_errstr(targetcli)));
+ errno = 0;
+ return -1;
+ }
+
+ sd = cli_query_secdesc(targetcli, fnum, ctx);
+
+ if (!sd) {
+ DEBUG(5,
+ ("cacl_get Failed to query old descriptor\n"));
+ errno = 0;
+ return -1;
+ }
+
+ cli_close(targetcli, fnum);
+
+ if (! exclude_nt_revision) {
+ if (all || all_nt) {
+ if (determine_size) {
+ p = talloc_asprintf(ctx,
+ "REVISION:%d",
+ sd->revision);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ "REVISION:%d",
+ sd->revision);
+ }
+ } else if (StrCaseCmp(name, "revision") == 0) {
+ if (determine_size) {
+ p = talloc_asprintf(ctx, "%d",
+ sd->revision);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize, "%d",
+ sd->revision);
+ }
+ }
+
+ if (!determine_size && n > bufsize) {
+ errno = ERANGE;
+ return -1;
+ }
+ buf += n;
+ n_used += n;
+ bufsize -= n;
+ n = 0;
+ }
+
+ if (! exclude_nt_owner) {
+ /* Get owner and group sid */
+ if (sd->owner_sid) {
+ convert_sid_to_string(ipc_cli, pol,
+ sidstr,
+ numeric,
+ sd->owner_sid);
+ } else {
+ fstrcpy(sidstr, "");
+ }
+
+ if (all || all_nt) {
+ if (determine_size) {
+ p = talloc_asprintf(ctx, ",OWNER:%s",
+ sidstr);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else if (sidstr[0] != '\0') {
+ n = snprintf(buf, bufsize,
+ ",OWNER:%s", sidstr);
+ }
+ } else if (StrnCaseCmp(name, "owner", 5) == 0) {
+ if (determine_size) {
+ p = talloc_asprintf(ctx, "%s", sidstr);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize, "%s",
+ sidstr);
+ }
+ }
+
+ if (!determine_size && n > bufsize) {
+ errno = ERANGE;
+ return -1;
+ }
+ buf += n;
+ n_used += n;
+ bufsize -= n;
+ n = 0;
+ }
+
+ if (! exclude_nt_group) {
+ if (sd->group_sid) {
+ convert_sid_to_string(ipc_cli, pol,
+ sidstr, numeric,
+ sd->group_sid);
+ } else {
+ fstrcpy(sidstr, "");
+ }
+
+ if (all || all_nt) {
+ if (determine_size) {
+ p = talloc_asprintf(ctx, ",GROUP:%s",
+ sidstr);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else if (sidstr[0] != '\0') {
+ n = snprintf(buf, bufsize,
+ ",GROUP:%s", sidstr);
+ }
+ } else if (StrnCaseCmp(name, "group", 5) == 0) {
+ if (determine_size) {
+ p = talloc_asprintf(ctx, "%s", sidstr);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ "%s", sidstr);
+ }
+ }
+
+ if (!determine_size && n > bufsize) {
+ errno = ERANGE;
+ return -1;
+ }
+ buf += n;
+ n_used += n;
+ bufsize -= n;
+ n = 0;
+ }
+
+ if (! exclude_nt_acl) {
+ /* Add aces to value buffer */
+ for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
+
+ SEC_ACE *ace = &sd->dacl->aces[i];
+ convert_sid_to_string(ipc_cli, pol,
+ sidstr, numeric,
+ &ace->trustee);
+
+ if (all || all_nt) {
+ if (determine_size) {
+ p = talloc_asprintf(
+ ctx,
+ ",ACL:"
+ "%s:%d/%d/0x%08x",
+ sidstr,
+ ace->type,
+ ace->flags,
+ ace->access_mask);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(
+ buf, bufsize,
+ ",ACL:%s:%d/%d/0x%08x",
+ sidstr,
+ ace->type,
+ ace->flags,
+ ace->access_mask);
+ }
+ } else if ((StrnCaseCmp(name, "acl", 3) == 0 &&
+ StrCaseCmp(name+3, sidstr) == 0) ||
+ (StrnCaseCmp(name, "acl+", 4) == 0 &&
+ StrCaseCmp(name+4, sidstr) == 0)) {
+ if (determine_size) {
+ p = talloc_asprintf(
+ ctx,
+ "%d/%d/0x%08x",
+ ace->type,
+ ace->flags,
+ ace->access_mask);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ "%d/%d/0x%08x",
+ ace->type,
+ ace->flags,
+ ace->access_mask);
+ }
+ } else if (all_nt_acls) {
+ if (determine_size) {
+ p = talloc_asprintf(
+ ctx,
+ "%s%s:%d/%d/0x%08x",
+ i ? "," : "",
+ sidstr,
+ ace->type,
+ ace->flags,
+ ace->access_mask);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ "%s%s:%d/%d/0x%08x",
+ i ? "," : "",
+ sidstr,
+ ace->type,
+ ace->flags,
+ ace->access_mask);
+ }
+ }
+ if (!determine_size && n > bufsize) {
+ errno = ERANGE;
+ return -1;
+ }
+ buf += n;
+ n_used += n;
+ bufsize -= n;
+ n = 0;
+ }
+ }
+
+ /* Restore name pointer to its original value */
+ name -= 19;
+ }
+
+ if (all || some_dos) {
+ /* Point to the portion after "system.dos_attr." */
+ name += 16; /* if (all) this will be invalid but unused */
+
+ /* Obtain the DOS attributes */
+ if (!SMBC_getatr(context, srv, filename, &mode, &size,
+ &create_time_ts,
+ &access_time_ts,
+ &write_time_ts,
+ &change_time_ts,
+ &ino)) {
+
+ errno = SMBC_errno(context, srv->cli);
+ return -1;
+
+ }
+
+ create_time = convert_timespec_to_time_t(create_time_ts);
+ access_time = convert_timespec_to_time_t(access_time_ts);
+ write_time = convert_timespec_to_time_t(write_time_ts);
+ change_time = convert_timespec_to_time_t(change_time_ts);
+
+ if (! exclude_dos_mode) {
+ if (all || all_dos) {
+ if (determine_size) {
+ p = talloc_asprintf(ctx,
+ "%sMODE:0x%x",
+ (ipc_cli &&
+ (all || some_nt)
+ ? ","
+ : ""),
+ mode);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ "%sMODE:0x%x",
+ (ipc_cli &&
+ (all || some_nt)
+ ? ","
+ : ""),
+ mode);
+ }
+ } else if (StrCaseCmp(name, "mode") == 0) {
+ if (determine_size) {
+ p = talloc_asprintf(ctx, "0x%x", mode);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ "0x%x", mode);
+ }
+ }
+
+ if (!determine_size && n > bufsize) {
+ errno = ERANGE;
+ return -1;
+ }
+ buf += n;
+ n_used += n;
+ bufsize -= n;
+ n = 0;
+ }
+
+ if (! exclude_dos_size) {
+ if (all || all_dos) {
+ if (determine_size) {
+ p = talloc_asprintf(
+ ctx,
+ ",SIZE:%.0f",
+ (double)size);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ ",SIZE:%.0f",
+ (double)size);
+ }
+ } else if (StrCaseCmp(name, "size") == 0) {
+ if (determine_size) {
+ p = talloc_asprintf(
+ ctx,
+ "%.0f",
+ (double)size);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ "%.0f",
+ (double)size);
+ }
+ }
+
+ if (!determine_size && n > bufsize) {
+ errno = ERANGE;
+ return -1;
+ }
+ buf += n;
+ n_used += n;
+ bufsize -= n;
+ n = 0;
+ }
+
+ if (! exclude_dos_create_time &&
+ attr_strings.create_time_attr != NULL) {
+ if (all || all_dos) {
+ if (determine_size) {
+ p = talloc_asprintf(ctx,
+ ",%s:%lu",
+ attr_strings.create_time_attr,
+ create_time);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ ",%s:%lu",
+ attr_strings.create_time_attr,
+ create_time);
+ }
+ } else if (StrCaseCmp(name, attr_strings.create_time_attr) == 0) {
+ if (determine_size) {
+ p = talloc_asprintf(ctx, "%lu", create_time);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ "%lu", create_time);
+ }
+ }
+
+ if (!determine_size && n > bufsize) {
+ errno = ERANGE;
+ return -1;
+ }
+ buf += n;
+ n_used += n;
+ bufsize -= n;
+ n = 0;
+ }
+
+ if (! exclude_dos_access_time) {
+ if (all || all_dos) {
+ if (determine_size) {
+ p = talloc_asprintf(ctx,
+ ",%s:%lu",
+ attr_strings.access_time_attr,
+ access_time);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ ",%s:%lu",
+ attr_strings.access_time_attr,
+ access_time);
+ }
+ } else if (StrCaseCmp(name, attr_strings.access_time_attr) == 0) {
+ if (determine_size) {
+ p = talloc_asprintf(ctx, "%lu", access_time);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ "%lu", access_time);
+ }
+ }
+
+ if (!determine_size && n > bufsize) {
+ errno = ERANGE;
+ return -1;
+ }
+ buf += n;
+ n_used += n;
+ bufsize -= n;
+ n = 0;
+ }
+
+ if (! exclude_dos_write_time) {
+ if (all || all_dos) {
+ if (determine_size) {
+ p = talloc_asprintf(ctx,
+ ",%s:%lu",
+ attr_strings.write_time_attr,
+ write_time);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ ",%s:%lu",
+ attr_strings.write_time_attr,
+ write_time);
+ }
+ } else if (StrCaseCmp(name, attr_strings.write_time_attr) == 0) {
+ if (determine_size) {
+ p = talloc_asprintf(ctx, "%lu", write_time);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ "%lu", write_time);
+ }
+ }
+
+ if (!determine_size && n > bufsize) {
+ errno = ERANGE;
+ return -1;
+ }
+ buf += n;
+ n_used += n;
+ bufsize -= n;
+ n = 0;
+ }
+
+ if (! exclude_dos_change_time) {
+ if (all || all_dos) {
+ if (determine_size) {
+ p = talloc_asprintf(ctx,
+ ",%s:%lu",
+ attr_strings.change_time_attr,
+ change_time);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ ",%s:%lu",
+ attr_strings.change_time_attr,
+ change_time);
+ }
+ } else if (StrCaseCmp(name, attr_strings.change_time_attr) == 0) {
+ if (determine_size) {
+ p = talloc_asprintf(ctx, "%lu", change_time);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ "%lu", change_time);
+ }
+ }
+
+ if (!determine_size && n > bufsize) {
+ errno = ERANGE;
+ return -1;
+ }
+ buf += n;
+ n_used += n;
+ bufsize -= n;
+ n = 0;
+ }
+
+ if (! exclude_dos_inode) {
+ if (all || all_dos) {
+ if (determine_size) {
+ p = talloc_asprintf(
+ ctx,
+ ",INODE:%.0f",
+ (double)ino);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ ",INODE:%.0f",
+ (double) ino);
+ }
+ } else if (StrCaseCmp(name, "inode") == 0) {
+ if (determine_size) {
+ p = talloc_asprintf(
+ ctx,
+ "%.0f",
+ (double) ino);
+ if (!p) {
+ errno = ENOMEM;
+ return -1;
+ }
+ n = strlen(p);
+ } else {
+ n = snprintf(buf, bufsize,
+ "%.0f",
+ (double) ino);
+ }
+ }
+
+ if (!determine_size && n > bufsize) {
+ errno = ERANGE;
+ return -1;
+ }
+ buf += n;
+ n_used += n;
+ bufsize -= n;
+ n = 0;
+ }
+
+ /* Restore name pointer to its original value */
+ name -= 16;
+ }
+
+ if (n_used == 0) {
+ errno = ENOATTR;
+ return -1;
+ }
+
+ return n_used;
+}
+
+/*****************************************************
+set the ACLs on a file given an ascii description
+*******************************************************/
+static int
+cacl_set(TALLOC_CTX *ctx,
+ struct cli_state *cli,
+ struct cli_state *ipc_cli,
+ POLICY_HND *pol,
+ const char *filename,
+ const char *the_acl,
+ int mode,
+ int flags)
+{
+ int fnum;
+ int err = 0;
+ SEC_DESC *sd = NULL, *old;
+ SEC_ACL *dacl = NULL;
+ DOM_SID *owner_sid = NULL;
+ DOM_SID *group_sid = NULL;
+ uint32 i, j;
+ size_t sd_size;
+ int ret = 0;
+ char *p;
+ bool numeric = True;
+ char *targetpath = NULL;
+ struct cli_state *targetcli = NULL;
+
+ /* the_acl will be null for REMOVE_ALL operations */
+ if (the_acl) {
+ numeric = ((p = strchr(the_acl, ':')) != NULL &&
+ p > the_acl &&
+ p[-1] != '+');
+
+ /* if this is to set the entire ACL... */
+ if (*the_acl == '*') {
+ /* ... then increment past the first colon */
+ the_acl = p + 1;
+ }
+
+ sd = sec_desc_parse(ctx, ipc_cli, pol, numeric,
+ CONST_DISCARD(char *, the_acl));
+
+ if (!sd) {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ /* SMBC_XATTR_MODE_REMOVE_ALL is the only caller
+ that doesn't deref sd */
+
+ if (!sd && (mode != SMBC_XATTR_MODE_REMOVE_ALL)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!cli_resolve_path(ctx, "", cli, filename,
+ &targetcli, &targetpath)) {
+ DEBUG(5,("cacl_set: Could not resolve %s\n", filename));
+ errno = ENOENT;
+ return -1;
+ }
+
+ /* The desired access below is the only one I could find that works
+ with NT4, W2KP and Samba */
+
+ fnum = cli_nt_create(targetcli, targetpath, CREATE_ACCESS_READ);
+
+ if (fnum == -1) {
+ DEBUG(5, ("cacl_set failed to open %s: %s\n",
+ targetpath, cli_errstr(targetcli)));
+ errno = 0;
+ return -1;
+ }
+
+ old = cli_query_secdesc(targetcli, fnum, ctx);
+
+ if (!old) {
+ DEBUG(5, ("cacl_set Failed to query old descriptor\n"));
+ errno = 0;
+ return -1;
+ }
+
+ cli_close(targetcli, fnum);
+
+ switch (mode) {
+ case SMBC_XATTR_MODE_REMOVE_ALL:
+ old->dacl->num_aces = 0;
+ dacl = old->dacl;
+ break;
+
+ case SMBC_XATTR_MODE_REMOVE:
+ for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
+ bool found = False;
+
+ for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
+ if (sec_ace_equal(&sd->dacl->aces[i],
+ &old->dacl->aces[j])) {
+ uint32 k;
+ for (k=j; k<old->dacl->num_aces-1;k++) {
+ old->dacl->aces[k] =
+ old->dacl->aces[k+1];
+ }
+ old->dacl->num_aces--;
+ found = True;
+ dacl = old->dacl;
+ break;
+ }
+ }
+
+ if (!found) {
+ err = ENOATTR;
+ ret = -1;
+ goto failed;
+ }
+ }
+ break;
+
+ case SMBC_XATTR_MODE_ADD:
+ for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
+ bool found = False;
+
+ for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
+ if (sid_equal(&sd->dacl->aces[i].trustee,
+ &old->dacl->aces[j].trustee)) {
+ if (!(flags & SMBC_XATTR_FLAG_CREATE)) {
+ err = EEXIST;
+ ret = -1;
+ goto failed;
+ }
+ old->dacl->aces[j] = sd->dacl->aces[i];
+ ret = -1;
+ found = True;
+ }
+ }
+
+ if (!found && (flags & SMBC_XATTR_FLAG_REPLACE)) {
+ err = ENOATTR;
+ ret = -1;
+ goto failed;
+ }
+
+ for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
+ add_ace(&old->dacl, &sd->dacl->aces[i], ctx);
+ }
+ }
+ dacl = old->dacl;
+ break;
+
+ case SMBC_XATTR_MODE_SET:
+ old = sd;
+ owner_sid = old->owner_sid;
+ group_sid = old->group_sid;
+ dacl = old->dacl;
+ break;
+
+ case SMBC_XATTR_MODE_CHOWN:
+ owner_sid = sd->owner_sid;
+ break;
+
+ case SMBC_XATTR_MODE_CHGRP:
+ group_sid = sd->group_sid;
+ break;
+ }
+
+ /* Denied ACE entries must come before allowed ones */
+ sort_acl(old->dacl);
+
+ /* Create new security descriptor and set it */
+ sd = make_sec_desc(ctx, old->revision, SEC_DESC_SELF_RELATIVE,
+ owner_sid, group_sid, NULL, dacl, &sd_size);
+
+ fnum = cli_nt_create(targetcli, targetpath,
+ WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS);
+
+ if (fnum == -1) {
+ DEBUG(5, ("cacl_set failed to open %s: %s\n",
+ targetpath, cli_errstr(targetcli)));
+ errno = 0;
+ return -1;
+ }
+
+ if (!cli_set_secdesc(targetcli, fnum, sd)) {
+ DEBUG(5, ("ERROR: secdesc set failed: %s\n",
+ cli_errstr(targetcli)));
+ ret = -1;
+ }
+
+ /* Clean up */
+
+failed:
+ cli_close(targetcli, fnum);
+
+ if (err != 0) {
+ errno = err;
+ }
+
+ return ret;
+}
+
+
+int
+SMBC_setxattr_ctx(SMBCCTX *context,
+ const char *fname,
+ const char *name,
+ const void *value,
+ size_t size,
+ int flags)
+{
+ int ret;
+ int ret2;
+ SMBCSRV *srv = NULL;
+ SMBCSRV *ipc_srv = NULL;
+ char *server = NULL;
+ char *share = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *workgroup = NULL;
+ char *path = NULL;
+ DOS_ATTR_DESC *dad = NULL;
+ struct {
+ const char * create_time_attr;
+ const char * access_time_attr;
+ const char * write_time_attr;
+ const char * change_time_attr;
+ } attr_strings;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!fname) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ DEBUG(4, ("smbc_setxattr(%s, %s, %.*s)\n",
+ fname, name, (int) size, (const char*)value));
+
+ if (SMBC_parse_path(frame,
+ context,
+ fname,
+ &workgroup,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!user || user[0] == (char)0) {
+ user = talloc_strdup(frame, smbc_getUser(context));
+ if (!user) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ }
+
+ srv = SMBC_server(frame, context, True,
+ server, share, &workgroup, &user, &password);
+ if (!srv) {
+ TALLOC_FREE(frame);
+ return -1; /* errno set by SMBC_server */
+ }
+
+ if (! srv->no_nt_session) {
+ ipc_srv = SMBC_attr_server(frame, context, server, share,
+ &workgroup, &user, &password);
+ if (! ipc_srv) {
+ srv->no_nt_session = True;
+ }
+ } else {
+ ipc_srv = NULL;
+ }
+
+ /*
+ * Are they asking to set the entire set of known attributes?
+ */
+ if (StrCaseCmp(name, "system.*") == 0 ||
+ StrCaseCmp(name, "system.*+") == 0) {
+ /* Yup. */
+ char *namevalue =
+ talloc_asprintf(talloc_tos(), "%s:%s",
+ name+7, (const char *) value);
+ if (! namevalue) {
+ errno = ENOMEM;
+ ret = -1;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (ipc_srv) {
+ ret = cacl_set(talloc_tos(), srv->cli,
+ ipc_srv->cli, &ipc_srv->pol, path,
+ namevalue,
+ (*namevalue == '*'
+ ? SMBC_XATTR_MODE_SET
+ : SMBC_XATTR_MODE_ADD),
+ flags);
+ } else {
+ ret = 0;
+ }
+
+ /* get a DOS Attribute Descriptor with current attributes */
+ dad = dos_attr_query(context, talloc_tos(), path, srv);
+ if (dad) {
+ /* Overwrite old with new, using what was provided */
+ dos_attr_parse(context, dad, srv, namevalue);
+
+ /* Set the new DOS attributes */
+ if (! SMBC_setatr(context, srv, path,
+ dad->create_time,
+ dad->access_time,
+ dad->write_time,
+ dad->change_time,
+ dad->mode)) {
+
+ /* cause failure if NT failed too */
+ dad = NULL;
+ }
+ }
+
+ /* we only fail if both NT and DOS sets failed */
+ if (ret < 0 && ! dad) {
+ ret = -1; /* in case dad was null */
+ }
+ else {
+ ret = 0;
+ }
+
+ TALLOC_FREE(frame);
+ return ret;
+ }
+
+ /*
+ * Are they asking to set an access control element or to set
+ * the entire access control list?
+ */
+ if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 ||
+ StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 ||
+ StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 ||
+ StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 ||
+ StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) {
+
+ /* Yup. */
+ char *namevalue =
+ talloc_asprintf(talloc_tos(), "%s:%s",
+ name+19, (const char *) value);
+
+ if (! ipc_srv) {
+ ret = -1; /* errno set by SMBC_server() */
+ }
+ else if (! namevalue) {
+ errno = ENOMEM;
+ ret = -1;
+ } else {
+ ret = cacl_set(talloc_tos(), srv->cli,
+ ipc_srv->cli, &ipc_srv->pol, path,
+ namevalue,
+ (*namevalue == '*'
+ ? SMBC_XATTR_MODE_SET
+ : SMBC_XATTR_MODE_ADD),
+ flags);
+ }
+ TALLOC_FREE(frame);
+ return ret;
+ }
+
+ /*
+ * Are they asking to set the owner?
+ */
+ if (StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 ||
+ StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0) {
+
+ /* Yup. */
+ char *namevalue =
+ talloc_asprintf(talloc_tos(), "%s:%s",
+ name+19, (const char *) value);
+
+ if (! ipc_srv) {
+ ret = -1; /* errno set by SMBC_server() */
+ }
+ else if (! namevalue) {
+ errno = ENOMEM;
+ ret = -1;
+ } else {
+ ret = cacl_set(talloc_tos(), srv->cli,
+ ipc_srv->cli, &ipc_srv->pol, path,
+ namevalue, SMBC_XATTR_MODE_CHOWN, 0);
+ }
+ TALLOC_FREE(frame);
+ return ret;
+ }
+
+ /*
+ * Are they asking to set the group?
+ */
+ if (StrCaseCmp(name, "system.nt_sec_desc.group") == 0 ||
+ StrCaseCmp(name, "system.nt_sec_desc.group+") == 0) {
+
+ /* Yup. */
+ char *namevalue =
+ talloc_asprintf(talloc_tos(), "%s:%s",
+ name+19, (const char *) value);
+
+ if (! ipc_srv) {
+ /* errno set by SMBC_server() */
+ ret = -1;
+ }
+ else if (! namevalue) {
+ errno = ENOMEM;
+ ret = -1;
+ } else {
+ ret = cacl_set(talloc_tos(), srv->cli,
+ ipc_srv->cli, &ipc_srv->pol, path,
+ namevalue, SMBC_XATTR_MODE_CHGRP, 0);
+ }
+ TALLOC_FREE(frame);
+ return ret;
+ }
+
+ /* Determine whether to use old-style or new-style attribute names */
+ if (context->internal->full_time_names) {
+ /* new-style names */
+ attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME";
+ attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME";
+ attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME";
+ attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME";
+ } else {
+ /* old-style names */
+ attr_strings.create_time_attr = NULL;
+ attr_strings.access_time_attr = "system.dos_attr.A_TIME";
+ attr_strings.write_time_attr = "system.dos_attr.M_TIME";
+ attr_strings.change_time_attr = "system.dos_attr.C_TIME";
+ }
+
+ /*
+ * Are they asking to set a DOS attribute?
+ */
+ if (StrCaseCmp(name, "system.dos_attr.*") == 0 ||
+ StrCaseCmp(name, "system.dos_attr.mode") == 0 ||
+ (attr_strings.create_time_attr != NULL &&
+ StrCaseCmp(name, attr_strings.create_time_attr) == 0) ||
+ StrCaseCmp(name, attr_strings.access_time_attr) == 0 ||
+ StrCaseCmp(name, attr_strings.write_time_attr) == 0 ||
+ StrCaseCmp(name, attr_strings.change_time_attr) == 0) {
+
+ /* get a DOS Attribute Descriptor with current attributes */
+ dad = dos_attr_query(context, talloc_tos(), path, srv);
+ if (dad) {
+ char *namevalue =
+ talloc_asprintf(talloc_tos(), "%s:%s",
+ name+16, (const char *) value);
+ if (! namevalue) {
+ errno = ENOMEM;
+ ret = -1;
+ } else {
+ /* Overwrite old with provided new params */
+ dos_attr_parse(context, dad, srv, namevalue);
+
+ /* Set the new DOS attributes */
+ ret2 = SMBC_setatr(context, srv, path,
+ dad->create_time,
+ dad->access_time,
+ dad->write_time,
+ dad->change_time,
+ dad->mode);
+
+ /* ret2 has True (success) / False (failure) */
+ if (ret2) {
+ ret = 0;
+ } else {
+ ret = -1;
+ }
+ }
+ } else {
+ ret = -1;
+ }
+
+ TALLOC_FREE(frame);
+ return ret;
+ }
+
+ /* Unsupported attribute name */
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+}
+
+int
+SMBC_getxattr_ctx(SMBCCTX *context,
+ const char *fname,
+ const char *name,
+ const void *value,
+ size_t size)
+{
+ int ret;
+ SMBCSRV *srv = NULL;
+ SMBCSRV *ipc_srv = NULL;
+ char *server = NULL;
+ char *share = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *workgroup = NULL;
+ char *path = NULL;
+ struct {
+ const char * create_time_attr;
+ const char * access_time_attr;
+ const char * write_time_attr;
+ const char * change_time_attr;
+ } attr_strings;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!fname) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ DEBUG(4, ("smbc_getxattr(%s, %s)\n", fname, name));
+
+ if (SMBC_parse_path(frame,
+ context,
+ fname,
+ &workgroup,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!user || user[0] == (char)0) {
+ user = talloc_strdup(frame, smbc_getUser(context));
+ if (!user) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ }
+
+ srv = SMBC_server(frame, context, True,
+ server, share, &workgroup, &user, &password);
+ if (!srv) {
+ TALLOC_FREE(frame);
+ return -1; /* errno set by SMBC_server */
+ }
+
+ if (! srv->no_nt_session) {
+ ipc_srv = SMBC_attr_server(frame, context, server, share,
+ &workgroup, &user, &password);
+ if (! ipc_srv) {
+ srv->no_nt_session = True;
+ }
+ } else {
+ ipc_srv = NULL;
+ }
+
+ /* Determine whether to use old-style or new-style attribute names */
+ if (context->internal->full_time_names) {
+ /* new-style names */
+ attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME";
+ attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME";
+ attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME";
+ attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME";
+ } else {
+ /* old-style names */
+ attr_strings.create_time_attr = NULL;
+ attr_strings.access_time_attr = "system.dos_attr.A_TIME";
+ attr_strings.write_time_attr = "system.dos_attr.M_TIME";
+ attr_strings.change_time_attr = "system.dos_attr.C_TIME";
+ }
+
+ /* Are they requesting a supported attribute? */
+ if (StrCaseCmp(name, "system.*") == 0 ||
+ StrnCaseCmp(name, "system.*!", 9) == 0 ||
+ StrCaseCmp(name, "system.*+") == 0 ||
+ StrnCaseCmp(name, "system.*+!", 10) == 0 ||
+ StrCaseCmp(name, "system.nt_sec_desc.*") == 0 ||
+ StrnCaseCmp(name, "system.nt_sec_desc.*!", 21) == 0 ||
+ StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 ||
+ StrnCaseCmp(name, "system.nt_sec_desc.*+!", 22) == 0 ||
+ StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 ||
+ StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 ||
+ StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 ||
+ StrCaseCmp(name, "system.nt_sec_desc.group") == 0 ||
+ StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 ||
+ StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 ||
+ StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0 ||
+ StrCaseCmp(name, "system.dos_attr.*") == 0 ||
+ StrnCaseCmp(name, "system.dos_attr.*!", 18) == 0 ||
+ StrCaseCmp(name, "system.dos_attr.mode") == 0 ||
+ StrCaseCmp(name, "system.dos_attr.size") == 0 ||
+ (attr_strings.create_time_attr != NULL &&
+ StrCaseCmp(name, attr_strings.create_time_attr) == 0) ||
+ StrCaseCmp(name, attr_strings.access_time_attr) == 0 ||
+ StrCaseCmp(name, attr_strings.write_time_attr) == 0 ||
+ StrCaseCmp(name, attr_strings.change_time_attr) == 0 ||
+ StrCaseCmp(name, "system.dos_attr.inode") == 0) {
+
+ /* Yup. */
+ ret = cacl_get(context, talloc_tos(), srv,
+ ipc_srv == NULL ? NULL : ipc_srv->cli,
+ &ipc_srv->pol, path,
+ CONST_DISCARD(char *, name),
+ CONST_DISCARD(char *, value), size);
+ if (ret < 0 && errno == 0) {
+ errno = SMBC_errno(context, srv->cli);
+ }
+ TALLOC_FREE(frame);
+ return ret;
+ }
+
+ /* Unsupported attribute name */
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+}
+
+
+int
+SMBC_removexattr_ctx(SMBCCTX *context,
+ const char *fname,
+ const char *name)
+{
+ int ret;
+ SMBCSRV *srv = NULL;
+ SMBCSRV *ipc_srv = NULL;
+ char *server = NULL;
+ char *share = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *workgroup = NULL;
+ char *path = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!context || !context->internal->initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!fname) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ DEBUG(4, ("smbc_removexattr(%s, %s)\n", fname, name));
+
+ if (SMBC_parse_path(frame,
+ context,
+ fname,
+ &workgroup,
+ &server,
+ &share,
+ &path,
+ &user,
+ &password,
+ NULL)) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (!user || user[0] == (char)0) {
+ user = talloc_strdup(frame, smbc_getUser(context));
+ if (!user) {
+ errno = ENOMEM;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ }
+
+ srv = SMBC_server(frame, context, True,
+ server, share, &workgroup, &user, &password);
+ if (!srv) {
+ TALLOC_FREE(frame);
+ return -1; /* errno set by SMBC_server */
+ }
+
+ if (! srv->no_nt_session) {
+ ipc_srv = SMBC_attr_server(frame, context, server, share,
+ &workgroup, &user, &password);
+ if (! ipc_srv) {
+ srv->no_nt_session = True;
+ }
+ } else {
+ ipc_srv = NULL;
+ }
+
+ if (! ipc_srv) {
+ TALLOC_FREE(frame);
+ return -1; /* errno set by SMBC_attr_server */
+ }
+
+ /* Are they asking to set the entire ACL? */
+ if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 ||
+ StrCaseCmp(name, "system.nt_sec_desc.*+") == 0) {
+
+ /* Yup. */
+ ret = cacl_set(talloc_tos(), srv->cli,
+ ipc_srv->cli, &ipc_srv->pol, path,
+ NULL, SMBC_XATTR_MODE_REMOVE_ALL, 0);
+ TALLOC_FREE(frame);
+ return ret;
+ }
+
+ /*
+ * Are they asking to remove one or more spceific security descriptor
+ * attributes?
+ */
+ if (StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 ||
+ StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 ||
+ StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 ||
+ StrCaseCmp(name, "system.nt_sec_desc.group") == 0 ||
+ StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 ||
+ StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 ||
+ StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) {
+
+ /* Yup. */
+ ret = cacl_set(talloc_tos(), srv->cli,
+ ipc_srv->cli, &ipc_srv->pol, path,
+ name + 19, SMBC_XATTR_MODE_REMOVE, 0);
+ TALLOC_FREE(frame);
+ return ret;
+ }
+
+ /* Unsupported attribute name */
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+}
+
+int
+SMBC_listxattr_ctx(SMBCCTX *context,
+ const char *fname,
+ char *list,
+ size_t size)
+{
+ /*
+ * This isn't quite what listxattr() is supposed to do. This returns
+ * the complete set of attribute names, always, rather than only those
+ * attribute names which actually exist for a file. Hmmm...
+ */
+ size_t retsize;
+ const char supported_old[] =
+ "system.*\0"
+ "system.*+\0"
+ "system.nt_sec_desc.revision\0"
+ "system.nt_sec_desc.owner\0"
+ "system.nt_sec_desc.owner+\0"
+ "system.nt_sec_desc.group\0"
+ "system.nt_sec_desc.group+\0"
+ "system.nt_sec_desc.acl.*\0"
+ "system.nt_sec_desc.acl\0"
+ "system.nt_sec_desc.acl+\0"
+ "system.nt_sec_desc.*\0"
+ "system.nt_sec_desc.*+\0"
+ "system.dos_attr.*\0"
+ "system.dos_attr.mode\0"
+ "system.dos_attr.c_time\0"
+ "system.dos_attr.a_time\0"
+ "system.dos_attr.m_time\0"
+ ;
+ const char supported_new[] =
+ "system.*\0"
+ "system.*+\0"
+ "system.nt_sec_desc.revision\0"
+ "system.nt_sec_desc.owner\0"
+ "system.nt_sec_desc.owner+\0"
+ "system.nt_sec_desc.group\0"
+ "system.nt_sec_desc.group+\0"
+ "system.nt_sec_desc.acl.*\0"
+ "system.nt_sec_desc.acl\0"
+ "system.nt_sec_desc.acl+\0"
+ "system.nt_sec_desc.*\0"
+ "system.nt_sec_desc.*+\0"
+ "system.dos_attr.*\0"
+ "system.dos_attr.mode\0"
+ "system.dos_attr.create_time\0"
+ "system.dos_attr.access_time\0"
+ "system.dos_attr.write_time\0"
+ "system.dos_attr.change_time\0"
+ ;
+ const char * supported;
+
+ if (context->internal->full_time_names) {
+ supported = supported_new;
+ retsize = sizeof(supported_new);
+ } else {
+ supported = supported_old;
+ retsize = sizeof(supported_old);
+ }
+
+ if (size == 0) {
+ return retsize;
+ }
+
+ if (retsize > size) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ /* this can't be strcpy() because there are embedded null characters */
+ memcpy(list, supported, retsize);
+ return retsize;
+}
diff --git a/source3/libsmb/namecache.c b/source3/libsmb/namecache.c
new file mode 100644
index 0000000000..ba706e5ee2
--- /dev/null
+++ b/source3/libsmb/namecache.c
@@ -0,0 +1,394 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ NetBIOS name cache module on top of gencache mechanism.
+
+ Copyright (C) Tim Potter 2002
+ Copyright (C) Rafal Szczesniak 2002
+ Copyright (C) Jeremy Allison 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#define NBTKEY_FMT "NBT/%s#%02X"
+
+/**
+ * Initialise namecache system. Function calls gencache
+ * initialisation function to perform necessary actions
+ *
+ * @return true upon successful initialisation of the cache or
+ * false on failure
+ **/
+
+bool namecache_enable(void)
+{
+ /*
+ * Check if name caching disabled by setting the name cache
+ * timeout to zero.
+ */
+
+ if (lp_name_cache_timeout() == 0) {
+ DEBUG(5, ("namecache_enable: disabling netbios name cache\n"));
+ return False;
+ }
+
+ /* Init namecache by calling gencache initialisation */
+
+ if (!gencache_init()) {
+ DEBUG(2, ("namecache_enable: "
+ "Couldn't initialise namecache on top of gencache.\n"));
+ return False;
+ }
+
+ /* I leave it for now, though I don't think we really
+ * need this (mimir, 27.09.2002) */
+ DEBUG(5, ("namecache_enable: enabling netbios namecache, timeout %d "
+ "seconds\n", lp_name_cache_timeout()));
+
+ return True;
+}
+
+/**
+ * Shutdown namecache. Routine calls gencache close function
+ * to safely close gencache file.
+ *
+ * @return true upon successful shutdown of the cache or
+ * false on failure
+ **/
+
+bool namecache_shutdown(void)
+{
+ if (!gencache_shutdown()) {
+ DEBUG(2, ("namecache_shutdown: "
+ "Couldn't close namecache on top of gencache.\n"));
+ return False;
+ }
+
+ DEBUG(5, ("namecache_shutdown: "
+ "netbios namecache closed successfully.\n"));
+ return True;
+}
+
+/**
+ * Generates a key for netbios name lookups on basis of
+ * netbios name and type.
+ * The caller must free returned key string when finished.
+ *
+ * @param name netbios name string (case insensitive)
+ * @param name_type netbios type of the name being looked up
+ *
+ * @return string consisted of uppercased name and appended
+ * type number
+ */
+
+static char* namecache_key(const char *name,
+ int name_type)
+{
+ char *keystr;
+ asprintf_strupper_m(&keystr, NBTKEY_FMT, name, name_type);
+
+ return keystr;
+}
+
+/**
+ * Store a name(s) in the name cache
+ *
+ * @param name netbios names array
+ * @param name_type integer netbios name type
+ * @param num_names number of names being stored
+ * @param ip_list array of in_addr structures containing
+ * ip addresses being stored
+ **/
+
+bool namecache_store(const char *name,
+ int name_type,
+ int num_names,
+ struct ip_service *ip_list)
+{
+ time_t expiry;
+ char *key, *value_string;
+ int i;
+ bool ret;
+
+ /*
+ * we use gecache call to avoid annoying debug messages about
+ * initialised namecache again and again...
+ */
+ if (!gencache_init()) {
+ return False;
+ }
+
+ if (name_type > 255) {
+ return False; /* Don't store non-real name types. */
+ }
+
+ if ( DEBUGLEVEL >= 5 ) {
+ TALLOC_CTX *ctx = talloc_stackframe();
+ char *addr = NULL;
+
+ DEBUG(5, ("namecache_store: storing %d address%s for %s#%02x: ",
+ num_names, num_names == 1 ? "": "es", name, name_type));
+
+ for (i = 0; i < num_names; i++) {
+ addr = print_canonical_sockaddr(ctx,
+ &ip_list[i].ss);
+ if (!addr) {
+ continue;
+ }
+ DEBUGADD(5, ("%s%s", addr,
+ (i == (num_names - 1) ? "" : ",")));
+
+ }
+ DEBUGADD(5, ("\n"));
+ TALLOC_FREE(ctx);
+ }
+
+ key = namecache_key(name, name_type);
+ if (!key) {
+ return False;
+ }
+
+ expiry = time(NULL) + lp_name_cache_timeout();
+
+ /*
+ * Generate string representation of ip addresses list
+ * First, store the number of ip addresses and then
+ * place each single ip
+ */
+ if (!ipstr_list_make(&value_string, ip_list, num_names)) {
+ SAFE_FREE(key);
+ SAFE_FREE(value_string);
+ return false;
+ }
+
+ /* set the entry */
+ ret = gencache_set(key, value_string, expiry);
+ SAFE_FREE(key);
+ SAFE_FREE(value_string);
+ return ret;
+}
+
+/**
+ * Look up a name in the cache.
+ *
+ * @param name netbios name to look up for
+ * @param name_type netbios name type of @param name
+ * @param ip_list mallocated list of IP addresses if found in the cache,
+ * NULL otherwise
+ * @param num_names number of entries found
+ *
+ * @return true upon successful fetch or
+ * false if name isn't found in the cache or has expired
+ **/
+
+bool namecache_fetch(const char *name,
+ int name_type,
+ struct ip_service **ip_list,
+ int *num_names)
+{
+ char *key, *value;
+ time_t timeout;
+
+ /* exit now if null pointers were passed as they're required further */
+ if (!ip_list || !num_names) {
+ return False;
+ }
+
+ if (!gencache_init()) {
+ return False;
+ }
+
+ if (name_type > 255) {
+ return False; /* Don't fetch non-real name types. */
+ }
+
+ *num_names = 0;
+
+ /*
+ * Use gencache interface - lookup the key
+ */
+ key = namecache_key(name, name_type);
+ if (!key) {
+ return False;
+ }
+
+ if (!gencache_get(key, &value, &timeout)) {
+ DEBUG(5, ("no entry for %s#%02X found.\n", name, name_type));
+ SAFE_FREE(key);
+ return False;
+ } else {
+ DEBUG(5, ("name %s#%02X found.\n", name, name_type));
+ }
+
+ /*
+ * Split up the stored value into the list of IP adresses
+ */
+ *num_names = ipstr_list_parse(value, ip_list);
+
+ SAFE_FREE(key);
+ SAFE_FREE(value);
+
+ return *num_names > 0; /* true only if some ip has been fetched */
+}
+
+/**
+ * Remove a namecache entry. Needed for site support.
+ *
+ **/
+
+bool namecache_delete(const char *name, int name_type)
+{
+ bool ret;
+ char *key;
+
+ if (!gencache_init())
+ return False;
+
+ if (name_type > 255) {
+ return False; /* Don't fetch non-real name types. */
+ }
+
+ key = namecache_key(name, name_type);
+ if (!key) {
+ return False;
+ }
+ ret = gencache_del(key);
+ SAFE_FREE(key);
+ return ret;
+}
+
+/**
+ * Delete single namecache entry. Look at the
+ * gencache_iterate definition.
+ *
+ **/
+
+static void flush_netbios_name(const char *key,
+ const char *value,
+ time_t timeout,
+ void *dptr)
+{
+ gencache_del(key);
+ DEBUG(5, ("Deleting entry %s\n", key));
+}
+
+/**
+ * Flush all names from the name cache.
+ * It's done by gencache_iterate()
+ *
+ * @return true upon successful deletion or
+ * false in case of an error
+ **/
+
+void namecache_flush(void)
+{
+ if (!gencache_init()) {
+ return;
+ }
+
+ /*
+ * iterate through each NBT cache's entry and flush it
+ * by flush_netbios_name function
+ */
+ gencache_iterate(flush_netbios_name, NULL, "NBT/*");
+ DEBUG(5, ("Namecache flushed\n"));
+}
+
+/* Construct a name status record key. */
+
+static char *namecache_status_record_key(const char *name,
+ int name_type1,
+ int name_type2,
+ const struct sockaddr_storage *keyip)
+{
+ char addr[INET6_ADDRSTRLEN];
+ char *keystr;
+
+ print_sockaddr(addr, sizeof(addr), keyip);
+ asprintf_strupper_m(&keystr, "NBT/%s#%02X.%02X.%s", name,
+ name_type1, name_type2, addr);
+ return keystr;
+}
+
+/* Store a name status record. */
+
+bool namecache_status_store(const char *keyname, int keyname_type,
+ int name_type, const struct sockaddr_storage *keyip,
+ const char *srvname)
+{
+ char *key;
+ time_t expiry;
+ bool ret;
+
+ if (!gencache_init()) {
+ return False;
+ }
+
+ key = namecache_status_record_key(keyname, keyname_type,
+ name_type, keyip);
+ if (!key)
+ return False;
+
+ expiry = time(NULL) + lp_name_cache_timeout();
+ ret = gencache_set(key, srvname, expiry);
+
+ if (ret) {
+ DEBUG(5, ("namecache_status_store: entry %s -> %s\n",
+ key, srvname ));
+ } else {
+ DEBUG(5, ("namecache_status_store: entry %s store failed.\n",
+ key ));
+ }
+
+ SAFE_FREE(key);
+ return ret;
+}
+
+/* Fetch a name status record. */
+
+bool namecache_status_fetch(const char *keyname,
+ int keyname_type,
+ int name_type,
+ const struct sockaddr_storage *keyip,
+ char *srvname_out)
+{
+ char *key = NULL;
+ char *value = NULL;
+ time_t timeout;
+
+ if (!gencache_init())
+ return False;
+
+ key = namecache_status_record_key(keyname, keyname_type,
+ name_type, keyip);
+ if (!key)
+ return False;
+
+ if (!gencache_get(key, &value, &timeout)) {
+ DEBUG(5, ("namecache_status_fetch: no entry for %s found.\n",
+ key));
+ SAFE_FREE(key);
+ return False;
+ } else {
+ DEBUG(5, ("namecache_status_fetch: key %s -> %s\n",
+ key, value ));
+ }
+
+ strlcpy(srvname_out, value, 16);
+ SAFE_FREE(key);
+ SAFE_FREE(value);
+ return True;
+}
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
new file mode 100644
index 0000000000..24d7ee1a9c
--- /dev/null
+++ b/source3/libsmb/namequery.c
@@ -0,0 +1,2145 @@
+/*
+ Unix SMB/CIFS implementation.
+ name query routines
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Jeremy Allison 2007.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* nmbd.c sets this to True. */
+bool global_in_nmbd = False;
+
+/****************************
+ * SERVER AFFINITY ROUTINES *
+ ****************************/
+
+ /* Server affinity is the concept of preferring the last domain
+ controller with whom you had a successful conversation */
+
+/****************************************************************************
+****************************************************************************/
+#define SAFKEY_FMT "SAF/DOMAIN/%s"
+#define SAF_TTL 900
+
+static char *saf_key(const char *domain)
+{
+ char *keystr;
+
+ asprintf_strupper_m(&keystr, SAFKEY_FMT, domain);
+
+ return keystr;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+bool saf_store( const char *domain, const char *servername )
+{
+ char *key;
+ time_t expire;
+ bool ret = False;
+
+ if ( !domain || !servername ) {
+ DEBUG(2,("saf_store: "
+ "Refusing to store empty domain or servername!\n"));
+ return False;
+ }
+
+ if ( (strlen(domain) == 0) || (strlen(servername) == 0) ) {
+ DEBUG(0,("saf_store: "
+ "refusing to store 0 length domain or servername!\n"));
+ return False;
+ }
+
+ if ( !gencache_init() )
+ return False;
+
+ key = saf_key( domain );
+ expire = time( NULL ) + SAF_TTL;
+
+ DEBUG(10,("saf_store: domain = [%s], server = [%s], expire = [%u]\n",
+ domain, servername, (unsigned int)expire ));
+
+ ret = gencache_set( key, servername, expire );
+
+ SAFE_FREE( key );
+
+ return ret;
+}
+
+bool saf_delete( const char *domain )
+{
+ char *key;
+ bool ret = False;
+
+ if ( !domain ) {
+ DEBUG(2,("saf_delete: Refusing to delete empty domain\n"));
+ return False;
+ }
+
+ if ( !gencache_init() )
+ return False;
+
+ key = saf_key(domain);
+ ret = gencache_del(key);
+
+ if (ret) {
+ DEBUG(10,("saf_delete: domain = [%s]\n", domain ));
+ }
+
+ SAFE_FREE( key );
+
+ return ret;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+char *saf_fetch( const char *domain )
+{
+ char *server = NULL;
+ time_t timeout;
+ bool ret = False;
+ char *key = NULL;
+
+ if ( !domain || strlen(domain) == 0) {
+ DEBUG(2,("saf_fetch: Empty domain name!\n"));
+ return NULL;
+ }
+
+ if ( !gencache_init() )
+ return False;
+
+ key = saf_key( domain );
+
+ ret = gencache_get( key, &server, &timeout );
+
+ SAFE_FREE( key );
+
+ if ( !ret ) {
+ DEBUG(5,("saf_fetch: failed to find server for \"%s\" domain\n",
+ domain ));
+ } else {
+ DEBUG(5,("saf_fetch: Returning \"%s\" for \"%s\" domain\n",
+ server, domain ));
+ }
+
+ return server;
+}
+
+/****************************************************************************
+ Generate a random trn_id.
+****************************************************************************/
+
+static int generate_trn_id(void)
+{
+ uint16 id;
+
+ generate_random_buffer((uint8 *)&id, sizeof(id));
+
+ return id % (unsigned)0x7FFF;
+}
+
+/****************************************************************************
+ Parse a node status response into an array of structures.
+****************************************************************************/
+
+static NODE_STATUS_STRUCT *parse_node_status(char *p,
+ int *num_names,
+ struct node_status_extra *extra)
+{
+ NODE_STATUS_STRUCT *ret;
+ int i;
+
+ *num_names = CVAL(p,0);
+
+ if (*num_names == 0)
+ return NULL;
+
+ ret = SMB_MALLOC_ARRAY(NODE_STATUS_STRUCT,*num_names);
+ if (!ret)
+ return NULL;
+
+ p++;
+ for (i=0;i< *num_names;i++) {
+ StrnCpy(ret[i].name,p,15);
+ trim_char(ret[i].name,'\0',' ');
+ ret[i].type = CVAL(p,15);
+ ret[i].flags = p[16];
+ p += 18;
+ DEBUG(10, ("%s#%02x: flags = 0x%02x\n", ret[i].name,
+ ret[i].type, ret[i].flags));
+ }
+ /*
+ * Also, pick up the MAC address ...
+ */
+ if (extra) {
+ memcpy(&extra->mac_addr, p, 6); /* Fill in the mac addr */
+ }
+ return ret;
+}
+
+
+/****************************************************************************
+ Do a NBT node status query on an open socket and return an array of
+ structures holding the returned names or NULL if the query failed.
+**************************************************************************/
+
+NODE_STATUS_STRUCT *node_status_query(int fd,
+ struct nmb_name *name,
+ const struct sockaddr_storage *to_ss,
+ int *num_names,
+ struct node_status_extra *extra)
+{
+ bool found=False;
+ int retries = 2;
+ int retry_time = 2000;
+ struct timeval tval;
+ struct packet_struct p;
+ struct packet_struct *p2;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ NODE_STATUS_STRUCT *ret;
+
+ ZERO_STRUCT(p);
+
+ if (to_ss->ss_family != AF_INET) {
+ /* Can't do node status to IPv6 */
+ return NULL;
+ }
+ nmb->header.name_trn_id = generate_trn_id();
+ nmb->header.opcode = 0;
+ nmb->header.response = false;
+ nmb->header.nm_flags.bcast = false;
+ nmb->header.nm_flags.recursion_available = false;
+ nmb->header.nm_flags.recursion_desired = false;
+ nmb->header.nm_flags.trunc = false;
+ nmb->header.nm_flags.authoritative = false;
+ nmb->header.rcode = 0;
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+ nmb->question.question_name = *name;
+ nmb->question.question_type = 0x21;
+ nmb->question.question_class = 0x1;
+
+ p.ip = ((const struct sockaddr_in *)to_ss)->sin_addr;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ GetTimeOfDay(&tval);
+
+ if (!send_packet(&p))
+ return NULL;
+
+ retries--;
+
+ while (1) {
+ struct timeval tval2;
+ GetTimeOfDay(&tval2);
+ if (TvalDiff(&tval,&tval2) > retry_time) {
+ if (!retries)
+ break;
+ if (!found && !send_packet(&p))
+ return NULL;
+ GetTimeOfDay(&tval);
+ retries--;
+ }
+
+ if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) {
+ struct nmb_packet *nmb2 = &p2->packet.nmb;
+ debug_nmb_packet(p2);
+
+ if (nmb2->header.opcode != 0 ||
+ nmb2->header.nm_flags.bcast ||
+ nmb2->header.rcode ||
+ !nmb2->header.ancount ||
+ nmb2->answers->rr_type != 0x21) {
+ /* XXXX what do we do with this? could be a
+ redirect, but we'll discard it for the
+ moment */
+ free_packet(p2);
+ continue;
+ }
+
+ ret = parse_node_status(&nmb2->answers->rdata[0],
+ num_names, extra);
+ free_packet(p2);
+ return ret;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Find the first type XX name in a node status reply - used for finding
+ a servers name given its IP. Return the matched name in *name.
+**************************************************************************/
+
+bool name_status_find(const char *q_name,
+ int q_type,
+ int type,
+ const struct sockaddr_storage *to_ss,
+ fstring name)
+{
+ char addr[INET6_ADDRSTRLEN];
+ struct sockaddr_storage ss;
+ NODE_STATUS_STRUCT *status = NULL;
+ struct nmb_name nname;
+ int count, i;
+ int sock;
+ bool result = false;
+
+ if (lp_disable_netbios()) {
+ DEBUG(5,("name_status_find(%s#%02x): netbios is disabled\n",
+ q_name, q_type));
+ return False;
+ }
+
+ print_sockaddr(addr, sizeof(addr), to_ss);
+
+ DEBUG(10, ("name_status_find: looking up %s#%02x at %s\n", q_name,
+ q_type, addr));
+
+ /* Check the cache first. */
+
+ if (namecache_status_fetch(q_name, q_type, type, to_ss, name)) {
+ return True;
+ }
+
+ if (to_ss->ss_family != AF_INET) {
+ /* Can't do node status to IPv6 */
+ return false;
+ }
+
+ if (!interpret_string_addr(&ss, lp_socket_address(),
+ AI_NUMERICHOST|AI_PASSIVE)) {
+ zero_addr(&ss);
+ }
+
+ sock = open_socket_in(SOCK_DGRAM, 0, 3, &ss, True);
+ if (sock == -1)
+ goto done;
+
+ /* W2K PDC's seem not to respond to '*'#0. JRA */
+ make_nmb_name(&nname, q_name, q_type);
+ status = node_status_query(sock, &nname, to_ss, &count, NULL);
+ close(sock);
+ if (!status)
+ goto done;
+
+ for (i=0;i<count;i++) {
+ if (status[i].type == type)
+ break;
+ }
+ if (i == count)
+ goto done;
+
+ pull_ascii_nstring(name, sizeof(fstring), status[i].name);
+
+ /* Store the result in the cache. */
+ /* but don't store an entry for 0x1c names here. Here we have
+ a single host and DOMAIN<0x1c> names should be a list of hosts */
+
+ if ( q_type != 0x1c ) {
+ namecache_status_store(q_name, q_type, type, to_ss, name);
+ }
+
+ result = true;
+
+ done:
+ SAFE_FREE(status);
+
+ DEBUG(10, ("name_status_find: name %sfound", result ? "" : "not "));
+
+ if (result)
+ DEBUGADD(10, (", name %s ip address is %s", name, addr));
+
+ DEBUG(10, ("\n"));
+
+ return result;
+}
+
+/*
+ comparison function used by sort_addr_list
+*/
+
+static int addr_compare(const struct sockaddr_storage *ss1,
+ const struct sockaddr_storage *ss2)
+{
+ int max_bits1=0, max_bits2=0;
+ int num_interfaces = iface_count();
+ int i;
+
+ /* Sort IPv6 addresses first. */
+ if (ss1->ss_family != ss2->ss_family) {
+ if (ss2->ss_family == AF_INET) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+
+ /* Here we know both addresses are of the same
+ * family. */
+
+ for (i=0;i<num_interfaces;i++) {
+ const struct sockaddr_storage *pss = iface_n_bcast(i);
+ unsigned char *p_ss1 = NULL;
+ unsigned char *p_ss2 = NULL;
+ unsigned char *p_if = NULL;
+ size_t len = 0;
+ int bits1, bits2;
+
+ if (pss->ss_family != ss1->ss_family) {
+ /* Ignore interfaces of the wrong type. */
+ continue;
+ }
+ if (pss->ss_family == AF_INET) {
+ p_if = (unsigned char *)
+ &((const struct sockaddr_in *)pss)->sin_addr;
+ p_ss1 = (unsigned char *)
+ &((const struct sockaddr_in *)ss1)->sin_addr;
+ p_ss2 = (unsigned char *)
+ &((const struct sockaddr_in *)ss2)->sin_addr;
+ len = 4;
+ }
+#if defined(HAVE_IPV6)
+ if (pss->ss_family == AF_INET6) {
+ p_if = (unsigned char *)
+ &((const struct sockaddr_in6 *)pss)->sin6_addr;
+ p_ss1 = (unsigned char *)
+ &((const struct sockaddr_in6 *)ss1)->sin6_addr;
+ p_ss2 = (unsigned char *)
+ &((const struct sockaddr_in6 *)ss2)->sin6_addr;
+ len = 16;
+ }
+#endif
+ if (!p_ss1 || !p_ss2 || !p_if || len == 0) {
+ continue;
+ }
+ bits1 = matching_len_bits(p_ss1, p_if, len);
+ bits2 = matching_len_bits(p_ss2, p_if, len);
+ max_bits1 = MAX(bits1, max_bits1);
+ max_bits2 = MAX(bits2, max_bits2);
+ }
+
+ /* Bias towards directly reachable IPs */
+ if (iface_local(ss1)) {
+ if (ss1->ss_family == AF_INET) {
+ max_bits1 += 32;
+ } else {
+ max_bits1 += 128;
+ }
+ }
+ if (iface_local(ss2)) {
+ if (ss2->ss_family == AF_INET) {
+ max_bits2 += 32;
+ } else {
+ max_bits2 += 128;
+ }
+ }
+ return max_bits2 - max_bits1;
+}
+
+/*******************************************************************
+ compare 2 ldap IPs by nearness to our interfaces - used in qsort
+*******************************************************************/
+
+int ip_service_compare(struct ip_service *ss1, struct ip_service *ss2)
+{
+ int result;
+
+ if ((result = addr_compare(&ss1->ss, &ss2->ss)) != 0) {
+ return result;
+ }
+
+ if (ss1->port > ss2->port) {
+ return 1;
+ }
+
+ if (ss1->port < ss2->port) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ sort an IP list so that names that are close to one of our interfaces
+ are at the top. This prevents the problem where a WINS server returns an IP
+ that is not reachable from our subnet as the first match
+*/
+
+static void sort_addr_list(struct sockaddr_storage *sslist, int count)
+{
+ if (count <= 1) {
+ return;
+ }
+
+ qsort(sslist, count, sizeof(struct sockaddr_storage),
+ QSORT_CAST addr_compare);
+}
+
+static void sort_service_list(struct ip_service *servlist, int count)
+{
+ if (count <= 1) {
+ return;
+ }
+
+ qsort(servlist, count, sizeof(struct ip_service),
+ QSORT_CAST ip_service_compare);
+}
+
+/**********************************************************************
+ Remove any duplicate address/port pairs in the list
+ *********************************************************************/
+
+static int remove_duplicate_addrs2(struct ip_service *iplist, int count )
+{
+ int i, j;
+
+ DEBUG(10,("remove_duplicate_addrs2: "
+ "looking for duplicate address/port pairs\n"));
+
+ /* one loop to remove duplicates */
+ for ( i=0; i<count; i++ ) {
+ if ( is_zero_addr(&iplist[i].ss)) {
+ continue;
+ }
+
+ for ( j=i+1; j<count; j++ ) {
+ if (addr_equal(&iplist[i].ss, &iplist[j].ss) &&
+ iplist[i].port == iplist[j].port) {
+ zero_addr(&iplist[j].ss);
+ }
+ }
+ }
+
+ /* one loop to clean up any holes we left */
+ /* first ip should never be a zero_ip() */
+ for (i = 0; i<count; ) {
+ if (is_zero_addr(&iplist[i].ss) ) {
+ if (i != count-1) {
+ memmove(&iplist[i], &iplist[i+1],
+ (count - i - 1)*sizeof(iplist[i]));
+ }
+ count--;
+ continue;
+ }
+ i++;
+ }
+
+ return count;
+}
+
+/****************************************************************************
+ 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.
+ *timed_out is set if we failed by timing out
+****************************************************************************/
+
+struct sockaddr_storage *name_query(int fd,
+ const char *name,
+ int name_type,
+ bool bcast,
+ bool recurse,
+ const struct sockaddr_storage *to_ss,
+ int *count,
+ int *flags,
+ bool *timed_out)
+{
+ bool found=false;
+ int i, retries = 3;
+ int retry_time = bcast?250:2000;
+ struct timeval tval;
+ struct packet_struct p;
+ struct packet_struct *p2;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ struct sockaddr_storage *ss_list = NULL;
+
+ if (lp_disable_netbios()) {
+ DEBUG(5,("name_query(%s#%02x): netbios is disabled\n",
+ name, name_type));
+ return NULL;
+ }
+
+ if (to_ss->ss_family != AF_INET) {
+ return NULL;
+ }
+
+ if (timed_out) {
+ *timed_out = false;
+ }
+
+ memset((char *)&p,'\0',sizeof(p));
+ (*count) = 0;
+ (*flags) = 0;
+
+ nmb->header.name_trn_id = generate_trn_id();
+ nmb->header.opcode = 0;
+ nmb->header.response = false;
+ nmb->header.nm_flags.bcast = bcast;
+ nmb->header.nm_flags.recursion_available = false;
+ nmb->header.nm_flags.recursion_desired = recurse;
+ nmb->header.nm_flags.trunc = false;
+ nmb->header.nm_flags.authoritative = false;
+ nmb->header.rcode = 0;
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+
+ make_nmb_name(&nmb->question.question_name,name,name_type);
+
+ nmb->question.question_type = 0x20;
+ nmb->question.question_class = 0x1;
+
+ p.ip = ((struct sockaddr_in *)to_ss)->sin_addr;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ GetTimeOfDay(&tval);
+
+ if (!send_packet(&p))
+ return NULL;
+
+ retries--;
+
+ while (1) {
+ struct timeval tval2;
+
+ GetTimeOfDay(&tval2);
+ if (TvalDiff(&tval,&tval2) > retry_time) {
+ if (!retries)
+ break;
+ if (!found && !send_packet(&p))
+ return NULL;
+ GetTimeOfDay(&tval);
+ retries--;
+ }
+
+ if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) {
+ struct nmb_packet *nmb2 = &p2->packet.nmb;
+ debug_nmb_packet(p2);
+
+ /* If we get a Negative Name Query Response from a WINS
+ * server, we should report it and give up.
+ */
+ if( 0 == nmb2->header.opcode /* A query response */
+ && !(bcast) /* from a WINS server */
+ && nmb2->header.rcode /* Error returned */
+ ) {
+
+ if( DEBUGLVL( 3 ) ) {
+ /* Only executed if DEBUGLEVEL >= 3 */
+ dbgtext( "Negative name query "
+ "response, rcode 0x%02x: ",
+ nmb2->header.rcode );
+ switch( nmb2->header.rcode ) {
+ case 0x01:
+ dbgtext( "Request "
+ "was invalidly formatted.\n" );
+ break;
+ case 0x02:
+ dbgtext( "Problem with NBNS, "
+ "cannot process name.\n");
+ break;
+ case 0x03:
+ dbgtext( "The name requested "
+ "does not exist.\n" );
+ break;
+ case 0x04:
+ dbgtext( "Unsupported request "
+ "error.\n" );
+ break;
+ case 0x05:
+ dbgtext( "Query refused "
+ "error.\n" );
+ break;
+ default:
+ dbgtext( "Unrecognized error "
+ "code.\n" );
+ break;
+ }
+ }
+ free_packet(p2);
+ return( NULL );
+ }
+
+ if (nmb2->header.opcode != 0 ||
+ nmb2->header.nm_flags.bcast ||
+ nmb2->header.rcode ||
+ !nmb2->header.ancount) {
+ /*
+ * XXXX what do we do with this? Could be a
+ * redirect, but we'll discard it for the
+ * moment.
+ */
+ free_packet(p2);
+ continue;
+ }
+
+ ss_list = SMB_REALLOC_ARRAY(ss_list,
+ struct sockaddr_storage,
+ (*count) +
+ nmb2->answers->rdlength/6);
+
+ if (!ss_list) {
+ DEBUG(0,("name_query: Realloc failed.\n"));
+ free_packet(p2);
+ return NULL;
+ }
+
+ DEBUG(2,("Got a positive name query response "
+ "from %s ( ",
+ inet_ntoa(p2->ip)));
+
+ for (i=0;i<nmb2->answers->rdlength/6;i++) {
+ struct in_addr ip;
+ putip((char *)&ip,&nmb2->answers->rdata[2+i*6]);
+ in_addr_to_sockaddr_storage(&ss_list[(*count)],
+ ip);
+ DEBUGADD(2,("%s ",inet_ntoa(ip)));
+ (*count)++;
+ }
+ DEBUGADD(2,(")\n"));
+
+ found=true;
+ retries=0;
+ /* We add the flags back ... */
+ if (nmb2->header.response)
+ (*flags) |= NM_FLAGS_RS;
+ if (nmb2->header.nm_flags.authoritative)
+ (*flags) |= NM_FLAGS_AA;
+ if (nmb2->header.nm_flags.trunc)
+ (*flags) |= NM_FLAGS_TC;
+ if (nmb2->header.nm_flags.recursion_desired)
+ (*flags) |= NM_FLAGS_RD;
+ if (nmb2->header.nm_flags.recursion_available)
+ (*flags) |= NM_FLAGS_RA;
+ if (nmb2->header.nm_flags.bcast)
+ (*flags) |= NM_FLAGS_B;
+ free_packet(p2);
+ /*
+ * If we're doing a unicast lookup we only
+ * expect one reply. Don't wait the full 2
+ * seconds if we got one. JRA.
+ */
+ if(!bcast && found)
+ break;
+ }
+ }
+
+ /* only set timed_out if we didn't fund what we where looking for*/
+
+ if ( !found && timed_out ) {
+ *timed_out = true;
+ }
+
+ /* sort the ip list so we choose close servers first if possible */
+ sort_addr_list(ss_list, *count);
+
+ return ss_list;
+}
+
+/********************************************************
+ Start parsing the lmhosts file.
+*********************************************************/
+
+XFILE *startlmhosts(const char *fname)
+{
+ XFILE *fp = x_fopen(fname,O_RDONLY, 0);
+ if (!fp) {
+ DEBUG(4,("startlmhosts: Can't open lmhosts file %s. "
+ "Error was %s\n",
+ fname, strerror(errno)));
+ return NULL;
+ }
+ return fp;
+}
+
+/********************************************************
+ Parse the next line in the lmhosts file.
+*********************************************************/
+
+bool getlmhostsent(TALLOC_CTX *ctx, XFILE *fp, char **pp_name, int *name_type,
+ struct sockaddr_storage *pss)
+{
+ char line[1024];
+
+ *pp_name = NULL;
+
+ while(!x_feof(fp) && !x_ferror(fp)) {
+ char *ip = NULL;
+ char *flags = NULL;
+ char *extra = NULL;
+ char *name = NULL;
+ const char *ptr;
+ char *ptr1 = NULL;
+ int count = 0;
+
+ *name_type = -1;
+
+ if (!fgets_slash(line,sizeof(line),fp)) {
+ continue;
+ }
+
+ if (*line == '#') {
+ continue;
+ }
+
+ ptr = line;
+
+ if (next_token_talloc(ctx, &ptr, &ip, NULL))
+ ++count;
+ if (next_token_talloc(ctx, &ptr, &name, NULL))
+ ++count;
+ if (next_token_talloc(ctx, &ptr, &flags, NULL))
+ ++count;
+ if (next_token_talloc(ctx, &ptr, &extra, NULL))
+ ++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;
+ }
+
+ if (!flags) {
+ flags = talloc_strdup(ctx, "");
+ if (!flags) {
+ continue;
+ }
+ }
+
+ DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n",
+ ip, name, flags));
+
+ if (strchr_m(flags,'G') || strchr_m(flags,'S')) {
+ DEBUG(0,("getlmhostsent: group flag "
+ "in lmhosts ignored (obsolete)\n"));
+ continue;
+ }
+
+ if (!interpret_string_addr(pss, ip, AI_NUMERICHOST)) {
+ DEBUG(0,("getlmhostsent: invalid address "
+ "%s.\n", ip));
+ }
+
+ /* Extra feature. If the name ends in '#XX',
+ * where XX is a hex number, then only add that name type. */
+ if((ptr1 = strchr_m(name, '#')) != NULL) {
+ char *endptr;
+ ptr1++;
+
+ *name_type = (int)strtol(ptr1, &endptr, 16);
+ if(!*ptr1 || (endptr == ptr1)) {
+ DEBUG(0,("getlmhostsent: invalid name "
+ "%s containing '#'.\n", name));
+ continue;
+ }
+
+ *(--ptr1) = '\0'; /* Truncate at the '#' */
+ }
+
+ *pp_name = talloc_strdup(ctx, name);
+ if (!*pp_name) {
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+/********************************************************
+ Finish parsing the lmhosts file.
+*********************************************************/
+
+void endlmhosts(XFILE *fp)
+{
+ x_fclose(fp);
+}
+
+/********************************************************
+ convert an array if struct sockaddr_storage to struct ip_service
+ return false on failure. Port is set to PORT_NONE;
+*********************************************************/
+
+static bool convert_ss2service(struct ip_service **return_iplist,
+ const struct sockaddr_storage *ss_list,
+ int count)
+{
+ int i;
+
+ if ( count==0 || !ss_list )
+ return False;
+
+ /* copy the ip address; port will be PORT_NONE */
+ if ((*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, count)) ==
+ NULL) {
+ DEBUG(0,("convert_ip2service: malloc failed "
+ "for %d enetries!\n", count ));
+ return False;
+ }
+
+ for ( i=0; i<count; i++ ) {
+ (*return_iplist)[i].ss = ss_list[i];
+ (*return_iplist)[i].port = PORT_NONE;
+ }
+
+ return true;
+}
+
+/********************************************************
+ Resolve via "bcast" method.
+*********************************************************/
+
+NTSTATUS name_resolve_bcast(const char *name,
+ int name_type,
+ struct ip_service **return_iplist,
+ int *return_count)
+{
+ int sock, i;
+ int num_interfaces = iface_count();
+ struct sockaddr_storage *ss_list;
+ struct sockaddr_storage ss;
+ NTSTATUS status;
+
+ if (lp_disable_netbios()) {
+ DEBUG(5,("name_resolve_bcast(%s#%02x): netbios is disabled\n",
+ name, name_type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ *return_iplist = NULL;
+ *return_count = 0;
+
+ /*
+ * "bcast" means do a broadcast lookup on all the local interfaces.
+ */
+
+ DEBUG(3,("name_resolve_bcast: Attempting broadcast lookup "
+ "for name %s<0x%x>\n", name, name_type));
+
+ if (!interpret_string_addr(&ss, lp_socket_address(),
+ AI_NUMERICHOST|AI_PASSIVE)) {
+ zero_addr(&ss);
+ }
+
+ sock = open_socket_in( SOCK_DGRAM, 0, 3, &ss, true );
+ if (sock == -1) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ set_socket_options(sock,"SO_BROADCAST");
+ /*
+ * Lookup the name on all the interfaces, return on
+ * the first successful match.
+ */
+ for( i = num_interfaces-1; i >= 0; i--) {
+ const struct sockaddr_storage *pss = iface_n_bcast(i);
+ int flags;
+
+ /* Done this way to fix compiler error on IRIX 5.x */
+ if (!pss) {
+ continue;
+ }
+ ss_list = name_query(sock, name, name_type, true,
+ true, pss, return_count, &flags, NULL);
+ if (ss_list) {
+ goto success;
+ }
+ }
+
+ /* failed - no response */
+
+ close(sock);
+ return NT_STATUS_UNSUCCESSFUL;
+
+success:
+
+ status = NT_STATUS_OK;
+ if (!convert_ss2service(return_iplist, ss_list, *return_count) )
+ status = NT_STATUS_INVALID_PARAMETER;
+
+ SAFE_FREE(ss_list);
+ close(sock);
+ return status;
+}
+
+/********************************************************
+ Resolve via "wins" method.
+*********************************************************/
+
+NTSTATUS resolve_wins(const char *name,
+ int name_type,
+ struct ip_service **return_iplist,
+ int *return_count)
+{
+ int sock, t, i;
+ char **wins_tags;
+ struct sockaddr_storage src_ss, *ss_list = NULL;
+ struct in_addr src_ip;
+ NTSTATUS status;
+
+ if (lp_disable_netbios()) {
+ DEBUG(5,("resolve_wins(%s#%02x): netbios is disabled\n",
+ name, name_type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ *return_iplist = NULL;
+ *return_count = 0;
+
+ DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n",
+ name, name_type));
+
+ if (wins_srv_count() < 1) {
+ DEBUG(3,("resolve_wins: WINS server resolution selected "
+ "and no WINS servers listed.\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* we try a lookup on each of the WINS tags in turn */
+ wins_tags = wins_srv_tags();
+
+ if (!wins_tags) {
+ /* huh? no tags?? give up in disgust */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* the address we will be sending from */
+ if (!interpret_string_addr(&src_ss, lp_socket_address(),
+ AI_NUMERICHOST|AI_PASSIVE)) {
+ zero_addr(&src_ss);
+ }
+
+ if (src_ss.ss_family != AF_INET) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr), &src_ss);
+ DEBUG(3,("resolve_wins: cannot receive WINS replies "
+ "on IPv6 address %s\n",
+ addr));
+ wins_srv_tags_free(wins_tags);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ src_ip = ((struct sockaddr_in *)&src_ss)->sin_addr;
+
+ /* in the worst case we will try every wins server with every
+ tag! */
+ for (t=0; wins_tags && wins_tags[t]; t++) {
+ int srv_count = wins_srv_count_tag(wins_tags[t]);
+ for (i=0; i<srv_count; i++) {
+ struct sockaddr_storage wins_ss;
+ struct in_addr wins_ip;
+ int flags;
+ bool timed_out;
+
+ wins_ip = wins_srv_ip_tag(wins_tags[t], src_ip);
+
+ if (global_in_nmbd && ismyip_v4(wins_ip)) {
+ /* yikes! we'll loop forever */
+ continue;
+ }
+
+ /* skip any that have been unresponsive lately */
+ if (wins_srv_is_dead(wins_ip, src_ip)) {
+ continue;
+ }
+
+ DEBUG(3,("resolve_wins: using WINS server %s "
+ "and tag '%s'\n",
+ inet_ntoa(wins_ip), wins_tags[t]));
+
+ sock = open_socket_in(SOCK_DGRAM, 0, 3, &src_ss, true);
+ if (sock == -1) {
+ continue;
+ }
+
+ in_addr_to_sockaddr_storage(&wins_ss, wins_ip);
+ ss_list = name_query(sock,
+ name,
+ name_type,
+ false,
+ true,
+ &wins_ss,
+ return_count,
+ &flags,
+ &timed_out);
+
+ /* exit loop if we got a list of addresses */
+
+ if (ss_list)
+ goto success;
+
+ close(sock);
+
+ if (timed_out) {
+ /* Timed out wating for WINS server to respond.
+ * Mark it dead. */
+ wins_srv_died(wins_ip, src_ip);
+ } else {
+ /* The name definately isn't in this
+ group of WINS servers.
+ goto the next group */
+ break;
+ }
+ }
+ }
+
+ wins_srv_tags_free(wins_tags);
+ return NT_STATUS_NO_LOGON_SERVERS;
+
+success:
+
+ status = NT_STATUS_OK;
+ if (!convert_ss2service(return_iplist, ss_list, *return_count))
+ status = NT_STATUS_INVALID_PARAMETER;
+
+ SAFE_FREE(ss_list);
+ wins_srv_tags_free(wins_tags);
+ close(sock);
+
+ return status;
+}
+
+/********************************************************
+ Resolve via "lmhosts" method.
+*********************************************************/
+
+static NTSTATUS resolve_lmhosts(const char *name, int name_type,
+ struct ip_service **return_iplist,
+ int *return_count)
+{
+ /*
+ * "lmhosts" means parse the local lmhosts file.
+ */
+
+ XFILE *fp;
+ char *lmhost_name = NULL;
+ int name_type2;
+ struct sockaddr_storage return_ss;
+ NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+ TALLOC_CTX *ctx = NULL;
+
+ *return_iplist = NULL;
+ *return_count = 0;
+
+ DEBUG(3,("resolve_lmhosts: "
+ "Attempting lmhosts lookup for name %s<0x%x>\n",
+ name, name_type));
+
+ fp = startlmhosts(get_dyn_LMHOSTSFILE());
+
+ if ( fp == NULL )
+ return NT_STATUS_NO_SUCH_FILE;
+
+ ctx = talloc_init("resolve_lmhosts");
+ if (!ctx) {
+ endlmhosts(fp);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ while (getlmhostsent(ctx, fp, &lmhost_name, &name_type2, &return_ss)) {
+
+ if (!strequal(name, lmhost_name)) {
+ TALLOC_FREE(lmhost_name);
+ continue;
+ }
+
+ if ((name_type2 != -1) && (name_type != name_type2)) {
+ TALLOC_FREE(lmhost_name);
+ continue;
+ }
+
+ *return_iplist = SMB_REALLOC_ARRAY((*return_iplist),
+ struct ip_service,
+ (*return_count)+1);
+
+ if ((*return_iplist) == NULL) {
+ TALLOC_FREE(ctx);
+ endlmhosts(fp);
+ DEBUG(3,("resolve_lmhosts: malloc fail !\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*return_iplist)[*return_count].ss = return_ss;
+ (*return_iplist)[*return_count].port = PORT_NONE;
+ *return_count += 1;
+
+ /* we found something */
+ status = NT_STATUS_OK;
+
+ /* Multiple names only for DC lookup */
+ if (name_type != 0x1c)
+ break;
+ }
+
+ TALLOC_FREE(ctx);
+ endlmhosts(fp);
+ return status;
+}
+
+
+/********************************************************
+ Resolve via "hosts" method.
+*********************************************************/
+
+static NTSTATUS resolve_hosts(const char *name, int name_type,
+ struct ip_service **return_iplist,
+ int *return_count)
+{
+ /*
+ * "host" means do a localhost, or dns lookup.
+ */
+ struct addrinfo hints;
+ struct addrinfo *ailist = NULL;
+ struct addrinfo *res = NULL;
+ int ret = -1;
+ int i = 0;
+
+ if ( name_type != 0x20 && name_type != 0x0) {
+ DEBUG(5, ("resolve_hosts: not appropriate "
+ "for name type <0x%x>\n",
+ name_type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ *return_iplist = NULL;
+ *return_count = 0;
+
+ DEBUG(3,("resolve_hosts: Attempting host lookup for name %s<0x%x>\n",
+ name, name_type));
+
+ ZERO_STRUCT(hints);
+ /* By default make sure it supports TCP. */
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_ADDRCONFIG;
+
+#if !defined(HAVE_IPV6)
+ /* Unless we have IPv6, we really only want IPv4 addresses back. */
+ hints.ai_family = AF_INET;
+#endif
+
+ ret = getaddrinfo(name,
+ NULL,
+ &hints,
+ &ailist);
+ if (ret) {
+ DEBUG(3,("resolve_hosts: getaddrinfo failed for name %s [%s]\n",
+ name,
+ gai_strerror(ret) ));
+ }
+
+ for (res = ailist; res; res = res->ai_next) {
+ struct sockaddr_storage ss;
+
+ if (!res->ai_addr || res->ai_addrlen == 0) {
+ continue;
+ }
+
+ ZERO_STRUCT(ss);
+ memcpy(&ss, res->ai_addr, res->ai_addrlen);
+
+ *return_count += 1;
+
+ *return_iplist = SMB_REALLOC_ARRAY(*return_iplist,
+ struct ip_service,
+ *return_count);
+ if (!*return_iplist) {
+ DEBUG(3,("resolve_hosts: malloc fail !\n"));
+ freeaddrinfo(ailist);
+ return NT_STATUS_NO_MEMORY;
+ }
+ (*return_iplist)[i].ss = ss;
+ (*return_iplist)[i].port = PORT_NONE;
+ i++;
+ }
+ if (ailist) {
+ freeaddrinfo(ailist);
+ }
+ if (*return_count) {
+ return NT_STATUS_OK;
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/********************************************************
+ Resolve via "ADS" method.
+*********************************************************/
+
+static NTSTATUS resolve_ads(const char *name,
+ int name_type,
+ const char *sitename,
+ struct ip_service **return_iplist,
+ int *return_count)
+{
+ int i, j;
+ NTSTATUS status;
+ TALLOC_CTX *ctx;
+ struct dns_rr_srv *dcs = NULL;
+ int numdcs = 0;
+ int numaddrs = 0;
+
+ if ((name_type != 0x1c) && (name_type != KDC_NAME_TYPE) &&
+ (name_type != 0x1b)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if ( (ctx = talloc_init("resolve_ads")) == NULL ) {
+ DEBUG(0,("resolve_ads: talloc_init() failed!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* The DNS code needs fixing to find IPv6 addresses... JRA. */
+
+ switch (name_type) {
+ case 0x1b:
+ DEBUG(5,("resolve_ads: Attempting to resolve "
+ "PDC for %s using DNS\n", name));
+ status = ads_dns_query_pdc(ctx, name, &dcs, &numdcs);
+ break;
+
+ case 0x1c:
+ DEBUG(5,("resolve_ads: Attempting to resolve "
+ "DCs for %s using DNS\n", name));
+ status = ads_dns_query_dcs(ctx, name, sitename, &dcs,
+ &numdcs);
+ break;
+ case KDC_NAME_TYPE:
+ DEBUG(5,("resolve_ads: Attempting to resolve "
+ "KDCs for %s using DNS\n", name));
+ status = ads_dns_query_kdcs(ctx, name, sitename, &dcs,
+ &numdcs);
+ break;
+ default:
+ status = NT_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ if ( !NT_STATUS_IS_OK( status ) ) {
+ talloc_destroy(ctx);
+ return status;
+ }
+
+ for (i=0;i<numdcs;i++) {
+ numaddrs += MAX(dcs[i].num_ips,1);
+ }
+
+ if ((*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, numaddrs)) ==
+ NULL ) {
+ DEBUG(0,("resolve_ads: malloc failed for %d entries\n",
+ numaddrs ));
+ talloc_destroy(ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* now unroll the list of IP addresses */
+
+ *return_count = 0;
+ i = 0;
+ j = 0;
+ while ( i < numdcs && (*return_count<numaddrs) ) {
+ struct ip_service *r = &(*return_iplist)[*return_count];
+
+ r->port = dcs[i].port;
+
+ /* If we don't have an IP list for a name, lookup it up */
+
+ if (!dcs[i].ss_s) {
+ interpret_string_addr(&r->ss, dcs[i].hostname, 0);
+ i++;
+ j = 0;
+ } else {
+ /* use the IP addresses from the SRV sresponse */
+
+ if ( j >= dcs[i].num_ips ) {
+ i++;
+ j = 0;
+ continue;
+ }
+
+ r->ss = dcs[i].ss_s[j];
+ j++;
+ }
+
+ /* make sure it is a valid IP. I considered checking the
+ * negative connection cache, but this is the wrong place
+ * for it. Maybe only as a hack. After think about it, if
+ * all of the IP addresses returned from DNS are dead, what
+ * hope does a netbios name lookup have ? The standard reason
+ * for falling back to netbios lookups is that our DNS server
+ * doesn't know anything about the DC's -- jerry */
+
+ if (!is_zero_addr(&r->ss)) {
+ (*return_count)++;
+ }
+ }
+
+ talloc_destroy(ctx);
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Internal interface to resolve a name into an IP address.
+ Use this function if the string is either an IP address, DNS
+ or host name or NetBIOS name. This uses the name switch in the
+ smb.conf to determine the order of name resolution.
+
+ Added support for ip addr/port to support ADS ldap servers.
+ the only place we currently care about the port is in the
+ resolve_hosts() when looking up DC's via SRV RR entries in DNS
+**********************************************************************/
+
+NTSTATUS internal_resolve_name(const char *name,
+ int name_type,
+ const char *sitename,
+ struct ip_service **return_iplist,
+ int *return_count,
+ const char *resolve_order)
+{
+ char *tok;
+ const char *ptr;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ int i;
+ TALLOC_CTX *frame = NULL;
+
+ *return_iplist = NULL;
+ *return_count = 0;
+
+ DEBUG(10, ("internal_resolve_name: looking up %s#%x (sitename %s)\n",
+ name, name_type, sitename ? sitename : NULL));
+
+ if (is_ipaddress(name)) {
+ if ((*return_iplist = SMB_MALLOC_P(struct ip_service)) ==
+ NULL) {
+ DEBUG(0,("internal_resolve_name: malloc fail !\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* ignore the port here */
+ (*return_iplist)->port = PORT_NONE;
+
+ /* if it's in the form of an IP address then get the lib to interpret it */
+ if (!interpret_string_addr(&(*return_iplist)->ss,
+ name, AI_NUMERICHOST)) {
+ DEBUG(1,("internal_resolve_name: interpret_string_addr "
+ "failed on %s\n",
+ name));
+ SAFE_FREE(*return_iplist);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ *return_count = 1;
+ return NT_STATUS_OK;
+ }
+
+ /* Check name cache */
+
+ if (namecache_fetch(name, name_type, return_iplist, return_count)) {
+ /* This could be a negative response */
+ if (*return_count > 0) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ /* set the name resolution order */
+
+ if (strcmp( resolve_order, "NULL") == 0) {
+ DEBUG(8,("internal_resolve_name: all lookups disabled\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!resolve_order[0]) {
+ ptr = "host";
+ } else {
+ ptr = resolve_order;
+ }
+
+ /* iterate through the name resolution backends */
+
+ frame = talloc_stackframe();
+ while (next_token_talloc(frame, &ptr, &tok, LIST_SEP)) {
+ if((strequal(tok, "host") || strequal(tok, "hosts"))) {
+ status = resolve_hosts(name, name_type, return_iplist,
+ return_count);
+ if (NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ } else if(strequal( tok, "kdc")) {
+ /* deal with KDC_NAME_TYPE names here.
+ * This will result in a SRV record lookup */
+ status = resolve_ads(name, KDC_NAME_TYPE, sitename,
+ return_iplist, return_count);
+ if (NT_STATUS_IS_OK(status)) {
+ /* Ensure we don't namecache
+ * this with the KDC port. */
+ name_type = KDC_NAME_TYPE;
+ goto done;
+ }
+ } else if(strequal( tok, "ads")) {
+ /* deal with 0x1c and 0x1b names here.
+ * This will result in a SRV record lookup */
+ status = resolve_ads(name, name_type, sitename,
+ return_iplist, return_count);
+ if (NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ } else if(strequal( tok, "lmhosts")) {
+ status = resolve_lmhosts(name, name_type,
+ return_iplist, return_count);
+ if (NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ } else if(strequal( tok, "wins")) {
+ /* don't resolve 1D via WINS */
+ if (name_type != 0x1D) {
+ status = resolve_wins(name, name_type,
+ return_iplist,
+ return_count);
+ if (NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ }
+ } else if(strequal( tok, "bcast")) {
+ status = name_resolve_bcast(name, name_type,
+ return_iplist,
+ return_count);
+ if (NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ } else {
+ DEBUG(0,("resolve_name: unknown name switch type %s\n",
+ tok));
+ }
+ }
+
+ /* All of the resolve_* functions above have returned false. */
+
+ TALLOC_FREE(frame);
+ SAFE_FREE(*return_iplist);
+ *return_count = 0;
+
+ return NT_STATUS_UNSUCCESSFUL;
+
+ done:
+
+ /* Remove duplicate entries. Some queries, notably #1c (domain
+ controllers) return the PDC in iplist[0] and then all domain
+ controllers including the PDC in iplist[1..n]. Iterating over
+ the iplist when the PDC is down will cause two sets of timeouts. */
+
+ if ( *return_count ) {
+ *return_count = remove_duplicate_addrs2(*return_iplist,
+ *return_count );
+ }
+
+ /* Save in name cache */
+ if ( DEBUGLEVEL >= 100 ) {
+ for (i = 0; i < *return_count && DEBUGLEVEL == 100; i++) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr),
+ &(*return_iplist)[i].ss);
+ DEBUG(100, ("Storing name %s of type %d (%s:%d)\n",
+ name,
+ name_type,
+ addr,
+ (*return_iplist)[i].port));
+ }
+ }
+
+ namecache_store(name, name_type, *return_count, *return_iplist);
+
+ /* Display some debugging info */
+
+ if ( DEBUGLEVEL >= 10 ) {
+ DEBUG(10, ("internal_resolve_name: returning %d addresses: ",
+ *return_count));
+
+ for (i = 0; i < *return_count; i++) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr),
+ &(*return_iplist)[i].ss);
+ DEBUGADD(10, ("%s:%d ",
+ addr,
+ (*return_iplist)[i].port));
+ }
+ DEBUG(10, ("\n"));
+ }
+
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/********************************************************
+ Internal interface to resolve a name into one IP address.
+ Use this function if the string is either an IP address, DNS
+ or host name or NetBIOS name. This uses the name switch in the
+ smb.conf to determine the order of name resolution.
+*********************************************************/
+
+bool resolve_name(const char *name,
+ struct sockaddr_storage *return_ss,
+ int name_type)
+{
+ struct ip_service *ss_list = NULL;
+ char *sitename = NULL;
+ int count = 0;
+
+ if (is_ipaddress(name)) {
+ return interpret_string_addr(return_ss, name, AI_NUMERICHOST);
+ }
+
+ sitename = sitename_fetch(lp_realm()); /* wild guess */
+
+ if (NT_STATUS_IS_OK(internal_resolve_name(name, name_type, sitename,
+ &ss_list, &count,
+ lp_name_resolve_order()))) {
+ int i;
+
+ /* only return valid addresses for TCP connections */
+ for (i=0; i<count; i++) {
+ if (!is_zero_addr(&ss_list[i].ss) &&
+ !is_broadcast_addr(&ss_list[i].ss)) {
+ *return_ss = ss_list[i].ss;
+ SAFE_FREE(ss_list);
+ SAFE_FREE(sitename);
+ return True;
+ }
+ }
+ }
+
+ SAFE_FREE(ss_list);
+ SAFE_FREE(sitename);
+ return False;
+}
+
+/********************************************************
+ Internal interface to resolve a name into a list of IP addresses.
+ 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.
+*********************************************************/
+
+NTSTATUS resolve_name_list(TALLOC_CTX *ctx,
+ const char *name,
+ int name_type,
+ struct sockaddr_storage **return_ss_arr,
+ unsigned int *p_num_entries)
+{
+ struct ip_service *ss_list = NULL;
+ char *sitename = NULL;
+ int count = 0;
+ int i;
+ unsigned int num_entries;
+ NTSTATUS status;
+
+ *p_num_entries = 0;
+ *return_ss_arr = NULL;
+
+ if (is_ipaddress(name)) {
+ *return_ss_arr = TALLOC_P(ctx, struct sockaddr_storage);
+ if (!*return_ss_arr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (!interpret_string_addr(*return_ss_arr, name, AI_NUMERICHOST)) {
+ TALLOC_FREE(*return_ss_arr);
+ return NT_STATUS_BAD_NETWORK_NAME;
+ }
+ *p_num_entries = 1;
+ return NT_STATUS_OK;
+ }
+
+ sitename = sitename_fetch(lp_realm()); /* wild guess */
+
+ status = internal_resolve_name(name, name_type, sitename,
+ &ss_list, &count,
+ lp_name_resolve_order());
+ SAFE_FREE(sitename);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* only return valid addresses for TCP connections */
+ for (i=0, num_entries = 0; i<count; i++) {
+ if (!is_zero_addr(&ss_list[i].ss) &&
+ !is_broadcast_addr(&ss_list[i].ss)) {
+ num_entries++;
+ }
+ }
+ if (num_entries == 0) {
+ SAFE_FREE(ss_list);
+ return NT_STATUS_BAD_NETWORK_NAME;
+ }
+
+ *return_ss_arr = TALLOC_ARRAY(ctx,
+ struct sockaddr_storage,
+ num_entries);
+ if (!(*return_ss_arr)) {
+ SAFE_FREE(ss_list);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0, num_entries = 0; i<count; i++) {
+ if (!is_zero_addr(&ss_list[i].ss) &&
+ !is_broadcast_addr(&ss_list[i].ss)) {
+ (*return_ss_arr)[num_entries++] = ss_list[i].ss;
+ }
+ }
+
+ status = NT_STATUS_OK;
+ *p_num_entries = num_entries;
+
+ SAFE_FREE(ss_list);
+ return NT_STATUS_OK;
+}
+
+/********************************************************
+ Find the IP address of the master browser or DMB for a workgroup.
+*********************************************************/
+
+bool find_master_ip(const char *group, struct sockaddr_storage *master_ss)
+{
+ struct ip_service *ip_list = NULL;
+ int count = 0;
+ NTSTATUS status;
+
+ if (lp_disable_netbios()) {
+ DEBUG(5,("find_master_ip(%s): netbios is disabled\n", group));
+ return false;
+ }
+
+ status = internal_resolve_name(group, 0x1D, NULL, &ip_list, &count,
+ lp_name_resolve_order());
+ if (NT_STATUS_IS_OK(status)) {
+ *master_ss = ip_list[0].ss;
+ SAFE_FREE(ip_list);
+ return true;
+ }
+
+ status = internal_resolve_name(group, 0x1B, NULL, &ip_list, &count,
+ lp_name_resolve_order());
+ if (NT_STATUS_IS_OK(status)) {
+ *master_ss = ip_list[0].ss;
+ SAFE_FREE(ip_list);
+ return true;
+ }
+
+ SAFE_FREE(ip_list);
+ return false;
+}
+
+/********************************************************
+ Get the IP address list of the primary domain controller
+ for a domain.
+*********************************************************/
+
+bool get_pdc_ip(const char *domain, struct sockaddr_storage *pss)
+{
+ struct ip_service *ip_list = NULL;
+ int count = 0;
+ NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+
+ /* Look up #1B name */
+
+ if (lp_security() == SEC_ADS) {
+ status = internal_resolve_name(domain, 0x1b, NULL, &ip_list,
+ &count, "ads");
+ }
+
+ if (!NT_STATUS_IS_OK(status) || count == 0) {
+ status = internal_resolve_name(domain, 0x1b, NULL, &ip_list,
+ &count,
+ lp_name_resolve_order());
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ }
+
+ /* if we get more than 1 IP back we have to assume it is a
+ multi-homed PDC and not a mess up */
+
+ if ( count > 1 ) {
+ DEBUG(6,("get_pdc_ip: PDC has %d IP addresses!\n", count));
+ sort_service_list(ip_list, count);
+ }
+
+ *pss = ip_list[0].ss;
+ SAFE_FREE(ip_list);
+ return true;
+}
+
+/* Private enum type for lookups. */
+
+enum dc_lookup_type { DC_NORMAL_LOOKUP, DC_ADS_ONLY, DC_KDC_ONLY };
+
+/********************************************************
+ Get the IP address list of the domain controllers for
+ a domain.
+*********************************************************/
+
+static NTSTATUS get_dc_list(const char *domain,
+ const char *sitename,
+ struct ip_service **ip_list,
+ int *count,
+ enum dc_lookup_type lookup_type,
+ bool *ordered)
+{
+ char *resolve_order = NULL;
+ char *saf_servername = NULL;
+ char *pserver = NULL;
+ const char *p;
+ char *port_str = NULL;
+ int port;
+ char *name;
+ int num_addresses = 0;
+ int local_count, i, j;
+ struct ip_service *return_iplist = NULL;
+ struct ip_service *auto_ip_list = NULL;
+ bool done_auto_lookup = false;
+ int auto_count = 0;
+ NTSTATUS status;
+ TALLOC_CTX *ctx = talloc_init("get_dc_list");
+
+ *ip_list = NULL;
+ *count = 0;
+
+ if (!ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *ordered = False;
+
+ /* if we are restricted to solely using DNS for looking
+ up a domain controller, make sure that host lookups
+ are enabled for the 'name resolve order'. If host lookups
+ are disabled and ads_only is True, then set the string to
+ NULL. */
+
+ resolve_order = talloc_strdup(ctx, lp_name_resolve_order());
+ if (!resolve_order) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+ strlower_m(resolve_order);
+ if (lookup_type == DC_ADS_ONLY) {
+ if (strstr( resolve_order, "host")) {
+ resolve_order = talloc_strdup(ctx, "ads");
+
+ /* DNS SRV lookups used by the ads resolver
+ are already sorted by priority and weight */
+ *ordered = true;
+ } else {
+ resolve_order = talloc_strdup(ctx, "NULL");
+ }
+ } else if (lookup_type == DC_KDC_ONLY) {
+ /* DNS SRV lookups used by the ads/kdc resolver
+ are already sorted by priority and weight */
+ *ordered = true;
+ resolve_order = talloc_strdup(ctx, "kdc");
+ }
+ if (!resolve_order) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ /* fetch the server we have affinity for. Add the
+ 'password server' list to a search for our domain controllers */
+
+ saf_servername = saf_fetch( domain);
+
+ if (strequal(domain, lp_workgroup()) || strequal(domain, lp_realm())) {
+ pserver = talloc_asprintf(NULL, "%s, %s",
+ saf_servername ? saf_servername : "",
+ lp_passwordserver());
+ } else {
+ pserver = talloc_asprintf(NULL, "%s, *",
+ saf_servername ? saf_servername : "");
+ }
+
+ SAFE_FREE(saf_servername);
+ if (!pserver) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ /* if we are starting from scratch, just lookup DOMAIN<0x1c> */
+
+ if (!*pserver ) {
+ DEBUG(10,("get_dc_list: no preferred domain controllers.\n"));
+ status = internal_resolve_name(domain, 0x1C, sitename, ip_list,
+ count, resolve_order);
+ goto out;
+ }
+
+ DEBUG(3,("get_dc_list: preferred server list: \"%s\"\n", pserver ));
+
+ /*
+ * if '*' appears in the "password server" list then add
+ * an auto lookup to the list of manually configured
+ * DC's. If any DC is listed by name, then the list should be
+ * considered to be ordered
+ */
+
+ p = pserver;
+ while (next_token_talloc(ctx, &p, &name, LIST_SEP)) {
+ if (!done_auto_lookup && strequal(name, "*")) {
+ status = internal_resolve_name(domain, 0x1C, sitename,
+ &auto_ip_list,
+ &auto_count,
+ resolve_order);
+ if (NT_STATUS_IS_OK(status)) {
+ num_addresses += auto_count;
+ }
+ done_auto_lookup = true;
+ DEBUG(8,("Adding %d DC's from auto lookup\n",
+ auto_count));
+ } else {
+ num_addresses++;
+ }
+ }
+
+ /* if we have no addresses and haven't done the auto lookup, then
+ just return the list of DC's. Or maybe we just failed. */
+
+ if ((num_addresses == 0)) {
+ if (done_auto_lookup) {
+ DEBUG(4,("get_dc_list: no servers found\n"));
+ status = NT_STATUS_NO_LOGON_SERVERS;
+ goto out;
+ }
+ status = internal_resolve_name(domain, 0x1C, sitename, ip_list,
+ count, resolve_order);
+ goto out;
+ }
+
+ if ((return_iplist = SMB_MALLOC_ARRAY(struct ip_service,
+ num_addresses)) == NULL) {
+ DEBUG(3,("get_dc_list: malloc fail !\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ p = pserver;
+ local_count = 0;
+
+ /* fill in the return list now with real IP's */
+
+ while ((local_count<num_addresses) &&
+ next_token_talloc(ctx, &p, &name, LIST_SEP)) {
+ struct sockaddr_storage name_ss;
+
+ /* copy any addersses from the auto lookup */
+
+ if (strequal(name, "*")) {
+ for (j=0; j<auto_count; j++) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr,
+ sizeof(addr),
+ &auto_ip_list[j].ss);
+ /* Check for and don't copy any
+ * known bad DC IP's. */
+ if(!NT_STATUS_IS_OK(check_negative_conn_cache(
+ domain,
+ addr))) {
+ DEBUG(5,("get_dc_list: "
+ "negative entry %s removed "
+ "from DC list\n",
+ addr));
+ continue;
+ }
+ return_iplist[local_count].ss =
+ auto_ip_list[j].ss;
+ return_iplist[local_count].port =
+ auto_ip_list[j].port;
+ local_count++;
+ }
+ continue;
+ }
+
+ /* added support for address:port syntax for ads
+ * (not that I think anyone will ever run the LDAP
+ * server in an AD domain on something other than
+ * port 389 */
+
+ port = (lp_security() == SEC_ADS) ? LDAP_PORT : PORT_NONE;
+ if ((port_str=strchr(name, ':')) != NULL) {
+ *port_str = '\0';
+ port_str++;
+ port = atoi(port_str);
+ }
+
+ /* explicit lookup; resolve_name() will
+ * handle names & IP addresses */
+ if (resolve_name( name, &name_ss, 0x20 )) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr,
+ sizeof(addr),
+ &name_ss);
+
+ /* Check for and don't copy any known bad DC IP's. */
+ if( !NT_STATUS_IS_OK(check_negative_conn_cache(domain,
+ addr)) ) {
+ DEBUG(5,("get_dc_list: negative entry %s "
+ "removed from DC list\n",
+ name ));
+ continue;
+ }
+
+ return_iplist[local_count].ss = name_ss;
+ return_iplist[local_count].port = port;
+ local_count++;
+ *ordered = true;
+ }
+ }
+
+ /* need to remove duplicates in the list if we have any
+ explicit password servers */
+
+ if (local_count) {
+ local_count = remove_duplicate_addrs2(return_iplist,
+ local_count );
+ }
+
+ if ( DEBUGLEVEL >= 4 ) {
+ DEBUG(4,("get_dc_list: returning %d ip addresses "
+ "in an %sordered list\n",
+ local_count,
+ *ordered ? "":"un"));
+ DEBUG(4,("get_dc_list: "));
+ for ( i=0; i<local_count; i++ ) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr,
+ sizeof(addr),
+ &return_iplist[i].ss);
+ DEBUGADD(4,("%s:%d ", addr, return_iplist[i].port ));
+ }
+ DEBUGADD(4,("\n"));
+ }
+
+ *ip_list = return_iplist;
+ *count = local_count;
+
+ status = ( *count != 0 ? NT_STATUS_OK : NT_STATUS_NO_LOGON_SERVERS );
+
+ out:
+
+ if (!NT_STATUS_IS_OK(status)) {
+ SAFE_FREE(return_iplist);
+ *ip_list = NULL;
+ *count = 0;
+ }
+
+ SAFE_FREE(auto_ip_list);
+ TALLOC_FREE(ctx);
+ return status;
+}
+
+/*********************************************************************
+ Small wrapper function to get the DC list and sort it if neccessary.
+*********************************************************************/
+
+NTSTATUS get_sorted_dc_list( const char *domain,
+ const char *sitename,
+ struct ip_service **ip_list,
+ int *count,
+ bool ads_only )
+{
+ bool ordered;
+ NTSTATUS status;
+ enum dc_lookup_type lookup_type = DC_NORMAL_LOOKUP;
+
+ *ip_list = NULL;
+ *count = 0;
+
+ DEBUG(8,("get_sorted_dc_list: attempting lookup "
+ "for name %s (sitename %s) using [%s]\n",
+ domain,
+ sitename ? sitename : "NULL",
+ (ads_only ? "ads" : lp_name_resolve_order())));
+
+ if (ads_only) {
+ lookup_type = DC_ADS_ONLY;
+ }
+
+ status = get_dc_list(domain, sitename, ip_list,
+ count, lookup_type, &ordered);
+ if (!NT_STATUS_IS_OK(status)) {
+ SAFE_FREE(*ip_list);
+ *count = 0;
+ return status;
+ }
+
+ /* only sort if we don't already have an ordered list */
+ if (!ordered) {
+ sort_service_list(*ip_list, *count);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Get the KDC list - re-use all the logic in get_dc_list.
+*********************************************************************/
+
+NTSTATUS get_kdc_list( const char *realm,
+ const char *sitename,
+ struct ip_service **ip_list,
+ int *count)
+{
+ bool ordered;
+ NTSTATUS status;
+
+ *count = 0;
+ *ip_list = NULL;
+
+ status = get_dc_list(realm, sitename, ip_list,
+ count, DC_KDC_ONLY, &ordered);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ SAFE_FREE(*ip_list);
+ *count = 0;
+ return status;
+ }
+
+ /* only sort if we don't already have an ordered list */
+ if ( !ordered ) {
+ sort_service_list(*ip_list, *count);
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/libsmb/namequery_dc.c b/source3/libsmb/namequery_dc.c
new file mode 100644
index 0000000000..d080f8f0b7
--- /dev/null
+++ b/source3/libsmb/namequery_dc.c
@@ -0,0 +1,247 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon connection manager
+
+ Copyright (C) Tim Potter 2001
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Gerald Carter 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+
+/**********************************************************************
+ Is this our primary domain ?
+**********************************************************************/
+
+#ifdef HAVE_KRB5
+static bool is_our_primary_domain(const char *domain)
+{
+ int role = lp_server_role();
+
+ if ((role == ROLE_DOMAIN_MEMBER) && strequal(lp_workgroup(), domain)) {
+ return True;
+ } else if (strequal(get_global_sam_name(), domain)) {
+ return True;
+ }
+ return False;
+}
+#endif
+
+/**************************************************************************
+ Find the name and IP address for a server in the realm/domain
+ *************************************************************************/
+
+static bool ads_dc_name(const char *domain,
+ const char *realm,
+ struct sockaddr_storage *dc_ss,
+ fstring srv_name)
+{
+ ADS_STRUCT *ads;
+ char *sitename;
+ int i;
+ char addr[INET6_ADDRSTRLEN];
+
+ if (!realm && strequal(domain, lp_workgroup())) {
+ realm = lp_realm();
+ }
+
+ sitename = sitename_fetch(realm);
+
+ /* Try this 3 times then give up. */
+ for( i =0 ; i < 3; i++) {
+ ads = ads_init(realm, domain, NULL);
+ if (!ads) {
+ SAFE_FREE(sitename);
+ return False;
+ }
+
+ DEBUG(4,("ads_dc_name: domain=%s\n", domain));
+
+#ifdef HAVE_ADS
+ /* we don't need to bind, just connect */
+ ads->auth.flags |= ADS_AUTH_NO_BIND;
+ ads_connect(ads);
+#endif
+
+ if (!ads->config.realm) {
+ SAFE_FREE(sitename);
+ ads_destroy(&ads);
+ return False;
+ }
+
+ /* Now we've found a server, see if our sitename
+ has changed. If so, we need to re-do the DNS query
+ to ensure we only find servers in our site. */
+
+ if (stored_sitename_changed(realm, sitename)) {
+ SAFE_FREE(sitename);
+ sitename = sitename_fetch(realm);
+ ads_destroy(&ads);
+ /* Ensure we don't cache the DC we just connected to. */
+ namecache_delete(realm, 0x1C);
+ namecache_delete(domain, 0x1C);
+ continue;
+ }
+
+#ifdef HAVE_KRB5
+ if (is_our_primary_domain(domain) && (ads->config.flags & NBT_SERVER_KDC)) {
+ if (ads_closest_dc(ads)) {
+ /* We're going to use this KDC for this realm/domain.
+ If we are using sites, then force the krb5 libs
+ to use this KDC. */
+
+ create_local_private_krb5_conf_for_domain(realm,
+ domain,
+ sitename,
+ &ads->ldap.ss);
+ } else {
+ create_local_private_krb5_conf_for_domain(realm,
+ domain,
+ NULL,
+ &ads->ldap.ss);
+ }
+ }
+#endif
+ break;
+ }
+
+ if (i == 3) {
+ DEBUG(1,("ads_dc_name: sitename (now \"%s\") keeps changing ???\n",
+ sitename ? sitename : ""));
+ SAFE_FREE(sitename);
+ return False;
+ }
+
+ SAFE_FREE(sitename);
+
+ fstrcpy(srv_name, ads->config.ldap_server_name);
+ strupper_m(srv_name);
+#ifdef HAVE_ADS
+ *dc_ss = ads->ldap.ss;
+#else
+ zero_addr(dc_ss);
+#endif
+ ads_destroy(&ads);
+
+ print_sockaddr(addr, sizeof(addr), dc_ss);
+ DEBUG(4,("ads_dc_name: using server='%s' IP=%s\n",
+ srv_name, addr));
+
+ return True;
+}
+
+/****************************************************************************
+ Utility function to return the name of a DC. The name is guaranteed to be
+ valid since we have already done a name_status_find on it
+ ***************************************************************************/
+
+static bool rpc_dc_name(const char *domain,
+ fstring srv_name,
+ struct sockaddr_storage *ss_out)
+{
+ struct ip_service *ip_list = NULL;
+ struct sockaddr_storage dc_ss;
+ int count, i;
+ NTSTATUS result;
+ char addr[INET6_ADDRSTRLEN];
+
+ /* get a list of all domain controllers */
+
+ if (!NT_STATUS_IS_OK(get_sorted_dc_list(domain, NULL, &ip_list, &count,
+ False))) {
+ DEBUG(3, ("Could not look up dc's for domain %s\n", domain));
+ return False;
+ }
+
+ /* Remove the entry we've already failed with (should be the PDC). */
+
+ for (i = 0; i < count; i++) {
+ if (is_zero_addr(&ip_list[i].ss))
+ continue;
+
+ if (name_status_find(domain, 0x1c, 0x20, &ip_list[i].ss, srv_name)) {
+ result = check_negative_conn_cache( domain, srv_name );
+ if ( NT_STATUS_IS_OK(result) ) {
+ dc_ss = ip_list[i].ss;
+ goto done;
+ }
+ }
+ }
+
+ SAFE_FREE(ip_list);
+
+ /* No-one to talk to )-: */
+ return False; /* Boo-hoo */
+
+ done:
+ /* We have the netbios name and IP address of a domain controller.
+ Ideally we should sent a SAMLOGON request to determine whether
+ the DC is alive and kicking. If we can catch a dead DC before
+ performing a cli_connect() we can avoid a 30-second timeout. */
+
+ print_sockaddr(addr, sizeof(addr), &dc_ss);
+ DEBUG(3, ("rpc_dc_name: Returning DC %s (%s) for domain %s\n", srv_name,
+ addr, domain));
+
+ *ss_out = dc_ss;
+ SAFE_FREE(ip_list);
+
+ return True;
+}
+
+/**********************************************************************
+ wrapper around ads and rpc methods of finds DC's
+**********************************************************************/
+
+bool get_dc_name(const char *domain,
+ const char *realm,
+ fstring srv_name,
+ struct sockaddr_storage *ss_out)
+{
+ struct sockaddr_storage dc_ss;
+ bool ret;
+ bool our_domain = False;
+
+ zero_addr(&dc_ss);
+
+ ret = False;
+
+ if ( strequal(lp_workgroup(), domain) || strequal(lp_realm(), realm) )
+ our_domain = True;
+
+ /* always try to obey what the admin specified in smb.conf
+ (for the local domain) */
+
+ if ( (our_domain && lp_security()==SEC_ADS) || realm ) {
+ ret = ads_dc_name(domain, realm, &dc_ss, srv_name);
+ }
+
+ if (!domain) {
+ /* if we have only the realm we can't do anything else */
+ return False;
+ }
+
+ if (!ret) {
+ /* fall back on rpc methods if the ADS methods fail */
+ ret = rpc_dc_name(domain, srv_name, &dc_ss);
+ }
+
+ *ss_out = dc_ss;
+
+ return ret;
+}
diff --git a/source3/libsmb/nmblib.c b/source3/libsmb/nmblib.c
new file mode 100644
index 0000000000..bfe5e7b97b
--- /dev/null
+++ b/source3/libsmb/nmblib.c
@@ -0,0 +1,1400 @@
+/*
+ Unix SMB/CIFS implementation.
+ NBT netbios library routines
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Jeremy Allison 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+int num_good_sends = 0;
+int num_good_receives = 0;
+
+static const struct opcode_names {
+ const 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 const char *lookup_opcode_name( int opcode )
+{
+ const struct opcode_names *op_namep;
+ int i;
+
+ for(i = 0; nmb_header_opcode_names[i].nmb_opcode_name != 0; i++) {
+ op_namep = &nmb_header_opcode_names[i];
+ if(opcode == op_namep->opcode)
+ return op_namep->nmb_opcode_name;
+ }
+ return "<unknown opcode>";
+}
+
+/****************************************************************************
+ Print out a res_rec structure.
+****************************************************************************/
+
+static void debug_nmb_res_rec(struct res_rec *res, const char *hdr)
+{
+ int i, j;
+
+ DEBUGADD( 4, ( " %s: nmb_name=%s rr_type=%d rr_class=%d ttl=%d\n",
+ hdr,
+ nmb_namestr(&res->rr_name),
+ res->rr_type,
+ res->rr_class,
+ res->ttl ) );
+
+ if( res->rdlength == 0 || res->rdata == NULL )
+ return;
+
+ for (i = 0; i < res->rdlength; i+= MAX_NETBIOSNAME_LEN) {
+ DEBUGADD(4, (" %s %3x char ", hdr, i));
+
+ for (j = 0; j < MAX_NETBIOSNAME_LEN; 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 < MAX_NETBIOSNAME_LEN; 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",
+ nmb_namestr(&nmb->question.question_name),
+ nmb->question.question_type,
+ nmb->question.question_class) );
+ }
+
+ if (nmb->answers && nmb->header.ancount) {
+ debug_nmb_res_rec(nmb->answers,"answers");
+ }
+ if (nmb->nsrecs && nmb->header.nscount) {
+ debug_nmb_res_rec(nmb->nsrecs,"nsrecs");
+ }
+ if (nmb->additional && nmb->header.arcount) {
+ debug_nmb_res_rec(nmb->additional,"additional");
+ }
+}
+
+/*******************************************************************
+ Handle "compressed" name pointers.
+******************************************************************/
+
+static bool handle_name_ptrs(unsigned char *ubuf,int *offset,int length,
+ bool *got_pointer,int *ret)
+{
+ int loop_count=0;
+
+ while ((ubuf[*offset] & 0xC0) == 0xC0) {
+ if (!*got_pointer)
+ (*ret) += 2;
+ (*got_pointer)=True;
+ (*offset) = ((ubuf[*offset] & ~0xC0)<<8) | ubuf[(*offset)+1];
+ if (loop_count++ == 10 ||
+ (*offset) < 0 || (*offset)>(length-2)) {
+ return False;
+ }
+ }
+ return True;
+}
+
+/*******************************************************************
+ 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 ofs,int length, struct nmb_name *name)
+{
+ int m,n=0;
+ unsigned char *ubuf = (unsigned char *)inbuf;
+ int ret = 0;
+ bool got_pointer=False;
+ int loop_count=0;
+ int offset = ofs;
+
+ if (length - offset < 2)
+ return(0);
+
+ /* handle initial name pointers */
+ if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
+ return(0);
+
+ m = ubuf[offset];
+
+ if (!m)
+ return(0);
+ if ((m & 0xC0) || offset+m+2 > length)
+ return(0);
+
+ memset((char *)name,'\0',sizeof(*name));
+
+ /* the "compressed" part */
+ if (!got_pointer)
+ ret += m + 2;
+ offset++;
+ while (m > 0) {
+ unsigned char c1,c2;
+ c1 = ubuf[offset++]-'A';
+ c2 = ubuf[offset++]-'A';
+ if ((c1 & 0xF0) || (c2 & 0xF0) || (n > sizeof(name->name)-1))
+ return(0);
+ name->name[n++] = (c1<<4) | c2;
+ m -= 2;
+ }
+ name->name[n] = 0;
+
+ if (n==MAX_NETBIOSNAME_LEN) {
+ /* parse out the name type, its always
+ * in the 16th byte of the name */
+ name->name_type = ((unsigned char)name->name[15]) & 0xff;
+
+ /* remove trailing spaces */
+ name->name[15] = 0;
+ n = 14;
+ while (n && name->name[n]==' ')
+ name->name[n--] = 0;
+ }
+
+ /* now the domain parts (if any) */
+ n = 0;
+ while (ubuf[offset]) {
+ /* we can have pointers within the domain part as well */
+ if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
+ return(0);
+
+ m = ubuf[offset];
+ /*
+ * Don't allow null domain parts.
+ */
+ if (!m)
+ return(0);
+ if (!got_pointer)
+ ret += m+1;
+ if (n)
+ name->scope[n++] = '.';
+ if (m+2+offset>length || n+m+1>sizeof(name->scope))
+ return(0);
+ offset++;
+ while (m--)
+ name->scope[n++] = (char)ubuf[offset++];
+
+ /*
+ * Watch for malicious loops.
+ */
+ if (loop_count++ == 10)
+ return 0;
+ }
+ name->scope[n++] = 0;
+
+ return(ret);
+}
+
+/****************************************************************************
+ Put a netbios name, padding(s) and a name type into a 16 character buffer.
+ name is already in DOS charset.
+ [15 bytes name + padding][1 byte name type].
+****************************************************************************/
+
+void put_name(char *dest, const char *name, int pad, unsigned int name_type)
+{
+ size_t len = strlen(name);
+
+ memcpy(dest, name, (len < MAX_NETBIOSNAME_LEN) ?
+ len : MAX_NETBIOSNAME_LEN - 1);
+ if (len < MAX_NETBIOSNAME_LEN - 1) {
+ memset(dest + len, pad, MAX_NETBIOSNAME_LEN - 1 - len);
+ }
+ dest[MAX_NETBIOSNAME_LEN - 1] = name_type;
+}
+
+/*******************************************************************
+ Put a compressed nmb name into a buffer. Return the length of the
+ compressed name.
+
+ Compressed names are really weird. The "compression" doubles the
+ size. The idea is that it also means that compressed names conform
+ to the doman name system. See RFC1002.
+
+ If buf == NULL this is a length calculation.
+******************************************************************/
+
+static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
+{
+ int ret,m;
+ nstring buf1;
+ char *p;
+
+ if (strcmp(name->name,"*") == 0) {
+ /* special case for wildcard name */
+ put_name(buf1, "*", '\0', name->name_type);
+ } else {
+ put_name(buf1, name->name, ' ', name->name_type);
+ }
+
+ if (buf) {
+ buf[offset] = 0x20;
+ }
+
+ ret = 34;
+
+ for (m=0;m<MAX_NETBIOSNAME_LEN;m++) {
+ if (buf) {
+ buf[offset+1+2*m] = 'A' + ((buf1[m]>>4)&0xF);
+ buf[offset+2+2*m] = 'A' + (buf1[m]&0xF);
+ }
+ }
+ offset += 33;
+
+ if (buf) {
+ buf[offset] = 0;
+ }
+
+ if (name->scope[0]) {
+ /* XXXX this scope handling needs testing */
+ ret += strlen(name->scope) + 1;
+ if (buf) {
+ safe_strcpy(&buf[offset+1],name->scope,
+ sizeof(name->scope));
+
+ p = &buf[offset+1];
+ while ((p = strchr_m(p,'.'))) {
+ buf[offset] = PTR_DIFF(p,&buf[offset+1]);
+ offset += (buf[offset] + 1);
+ p = &buf[offset+1];
+ }
+ buf[offset] = strlen(&buf[offset+1]);
+ }
+ }
+
+ return ret;
+}
+
+/*******************************************************************
+ Useful for debugging messages.
+******************************************************************/
+
+char *nmb_namestr(const struct nmb_name *n)
+{
+ fstring name;
+ char *result;
+
+ pull_ascii_fstring(name, n->name);
+ if (!n->scope[0])
+ result = talloc_asprintf(talloc_tos(), "%s<%02x>", name,
+ n->name_type);
+ else
+ result = talloc_asprintf(talloc_tos(), "%s<%02x>.%s", name,
+ n->name_type, n->scope);
+
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+/*******************************************************************
+ Allocate and parse some resource records.
+******************************************************************/
+
+static bool parse_alloc_res_rec(char *inbuf,int *offset,int length,
+ struct res_rec **recs, int count)
+{
+ int i;
+
+ *recs = SMB_MALLOC_ARRAY(struct res_rec, count);
+ if (!*recs)
+ return(False);
+
+ memset((char *)*recs,'\0',sizeof(**recs)*count);
+
+ for (i=0;i<count;i++) {
+ int l = parse_nmb_name(inbuf,*offset,length,
+ &(*recs)[i].rr_name);
+ (*offset) += l;
+ if (!l || (*offset)+10 > length) {
+ SAFE_FREE(*recs);
+ return(False);
+ }
+ (*recs)[i].rr_type = RSVAL(inbuf,(*offset));
+ (*recs)[i].rr_class = RSVAL(inbuf,(*offset)+2);
+ (*recs)[i].ttl = RIVAL(inbuf,(*offset)+4);
+ (*recs)[i].rdlength = RSVAL(inbuf,(*offset)+8);
+ (*offset) += 10;
+ if ((*recs)[i].rdlength>sizeof((*recs)[i].rdata) ||
+ (*offset)+(*recs)[i].rdlength > length) {
+ SAFE_FREE(*recs);
+ return(False);
+ }
+ memcpy((*recs)[i].rdata,inbuf+(*offset),(*recs)[i].rdlength);
+ (*offset) += (*recs)[i].rdlength;
+ }
+ return(True);
+}
+
+/*******************************************************************
+ Put a resource record into a packet.
+ If buf == NULL this is a length calculation.
+******************************************************************/
+
+static int put_res_rec(char *buf,int offset,struct res_rec *recs,int count)
+{
+ int ret=0;
+ int i;
+
+ for (i=0;i<count;i++) {
+ int l = put_nmb_name(buf,offset,&recs[i].rr_name);
+ offset += l;
+ ret += l;
+ if (buf) {
+ RSSVAL(buf,offset,recs[i].rr_type);
+ RSSVAL(buf,offset+2,recs[i].rr_class);
+ RSIVAL(buf,offset+4,recs[i].ttl);
+ RSSVAL(buf,offset+8,recs[i].rdlength);
+ memcpy(buf+offset+10,recs[i].rdata,recs[i].rdlength);
+ }
+ offset += 10+recs[i].rdlength;
+ ret += 10+recs[i].rdlength;
+ }
+
+ return ret;
+}
+
+/*******************************************************************
+ Put a compressed name pointer record into a packet.
+ If buf == NULL this is a length calculation.
+******************************************************************/
+
+static int put_compressed_name_ptr(unsigned char *buf,
+ int offset,
+ struct res_rec *rec,
+ int ptr_offset)
+{
+ int ret=0;
+ if (buf) {
+ buf[offset] = (0xC0 | ((ptr_offset >> 8) & 0xFF));
+ buf[offset+1] = (ptr_offset & 0xFF);
+ }
+ offset += 2;
+ ret += 2;
+ if (buf) {
+ 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.
+
+ This is documented in section 4.4.1 of RFC1002.
+******************************************************************/
+
+static bool parse_dgram(char *inbuf,int length,struct dgram_packet *dgram)
+{
+ int offset;
+ int flags;
+
+ memset((char *)dgram,'\0',sizeof(*dgram));
+
+ if (length < 14)
+ return(False);
+
+ dgram->header.msg_type = CVAL(inbuf,0);
+ flags = CVAL(inbuf,1);
+ dgram->header.flags.node_type = (enum node_type)((flags>>2)&3);
+ if (flags & 1)
+ dgram->header.flags.more = True;
+ if (flags & 2)
+ dgram->header.flags.first = True;
+ dgram->header.dgm_id = RSVAL(inbuf,2);
+ putip((char *)&dgram->header.source_ip,inbuf+4);
+ dgram->header.source_port = RSVAL(inbuf,8);
+ dgram->header.dgm_length = RSVAL(inbuf,10);
+ dgram->header.packet_offset = RSVAL(inbuf,12);
+
+ offset = 14;
+
+ if (dgram->header.msg_type == 0x10 ||
+ dgram->header.msg_type == 0x11 ||
+ dgram->header.msg_type == 0x12) {
+ offset += parse_nmb_name(inbuf,offset,length,
+ &dgram->source_name);
+ offset += parse_nmb_name(inbuf,offset,length,
+ &dgram->dest_name);
+ }
+
+ if (offset >= length || (length-offset > sizeof(dgram->data)))
+ return(False);
+
+ dgram->datasize = length-offset;
+ memcpy(dgram->data,inbuf+offset,dgram->datasize);
+
+ /* Paranioa. Ensure the last 2 bytes in the dgram buffer are
+ zero. This should be true anyway, just enforce it for
+ paranioa sake. JRA. */
+ SMB_ASSERT(dgram->datasize <= (sizeof(dgram->data)-2));
+ memset(&dgram->data[sizeof(dgram->data)-2], '\0', 2);
+
+ return(True);
+}
+
+/*******************************************************************
+ Parse a nmb packet. Return False if the packet can't be parsed
+ or is invalid for some reason, True otherwise.
+******************************************************************/
+
+static bool parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
+{
+ int nm_flags,offset;
+
+ memset((char *)nmb,'\0',sizeof(*nmb));
+
+ if (length < 12)
+ return(False);
+
+ /* parse the header */
+ nmb->header.name_trn_id = RSVAL(inbuf,0);
+
+ DEBUG(10,("parse_nmb: packet id = %d\n", nmb->header.name_trn_id));
+
+ nmb->header.opcode = (CVAL(inbuf,2) >> 3) & 0xF;
+ nmb->header.response = ((CVAL(inbuf,2)>>7)&1)?True:False;
+ nm_flags = ((CVAL(inbuf,2) & 0x7) << 4) + (CVAL(inbuf,3)>>4);
+ nmb->header.nm_flags.bcast = (nm_flags&1)?True:False;
+ 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.rcode = CVAL(inbuf,3) & 0xF;
+ nmb->header.qdcount = RSVAL(inbuf,4);
+ nmb->header.ancount = RSVAL(inbuf,6);
+ nmb->header.nscount = RSVAL(inbuf,8);
+ nmb->header.arcount = RSVAL(inbuf,10);
+
+ if (nmb->header.qdcount) {
+ offset = parse_nmb_name(inbuf,12,length,
+ &nmb->question.question_name);
+ if (!offset)
+ return(False);
+
+ if (length - (12+offset) < 4)
+ return(False);
+ nmb->question.question_type = RSVAL(inbuf,12+offset);
+ nmb->question.question_class = RSVAL(inbuf,12+offset+2);
+
+ offset += 12+4;
+ } else {
+ offset = 12;
+ }
+
+ /* and any resource records */
+ if (nmb->header.ancount &&
+ !parse_alloc_res_rec(inbuf,&offset,length,&nmb->answers,
+ nmb->header.ancount))
+ return(False);
+
+ if (nmb->header.nscount &&
+ !parse_alloc_res_rec(inbuf,&offset,length,&nmb->nsrecs,
+ nmb->header.nscount))
+ return(False);
+
+ if (nmb->header.arcount &&
+ !parse_alloc_res_rec(inbuf,&offset,length,
+ &nmb->additional, nmb->header.arcount))
+ return(False);
+
+ return(True);
+}
+
+/*******************************************************************
+ '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 = SMB_MALLOC_P(struct packet_struct)) == 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 = SMB_MALLOC_ARRAY(
+ struct res_rec,nmb->header.ancount)) == 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 = SMB_MALLOC_ARRAY(
+ struct res_rec, nmb->header.nscount)) == 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 = SMB_MALLOC_ARRAY(
+ struct res_rec, nmb->header.arcount)) == NULL)
+ goto free_and_exit;
+ memcpy((char *)copy_nmb->additional, (char *)nmb->additional,
+ nmb->header.arcount * sizeof(struct res_rec));
+ }
+
+ return pkt_copy;
+
+ free_and_exit:
+
+ SAFE_FREE(copy_nmb->answers);
+ SAFE_FREE(copy_nmb->nsrecs);
+ SAFE_FREE(copy_nmb->additional);
+ SAFE_FREE(pkt_copy);
+
+ DEBUG(0,("copy_nmb_packet: malloc fail in resource records.\n"));
+ return NULL;
+}
+
+/*******************************************************************
+ 'Copy constructor' for a dgram packet.
+******************************************************************/
+
+static struct packet_struct *copy_dgram_packet(struct packet_struct *packet)
+{
+ struct packet_struct *pkt_copy;
+
+ if(( pkt_copy = SMB_MALLOC_P(struct packet_struct)) == 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.
+******************************************************************/
+
+static void free_nmb_packet(struct nmb_packet *nmb)
+{
+ SAFE_FREE(nmb->answers);
+ SAFE_FREE(nmb->nsrecs);
+ SAFE_FREE(nmb->additional);
+}
+
+/*******************************************************************
+ Free up any resources associated with a dgram packet.
+******************************************************************/
+
+static void free_dgram_packet(struct dgram_packet *nmb)
+{
+ /* We have nothing to do for a dgram packet. */
+}
+
+/*******************************************************************
+ 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);
+ ZERO_STRUCTPN(packet);
+ SAFE_FREE(packet);
+}
+
+/*******************************************************************
+ Parse a packet buffer into a packet structure.
+******************************************************************/
+
+struct packet_struct *parse_packet(char *buf,int length,
+ enum packet_type packet_type,
+ struct in_addr ip,
+ int port)
+{
+ struct packet_struct *p;
+ bool ok=False;
+
+ p = SMB_MALLOC_P(struct packet_struct);
+ if (!p)
+ return(NULL);
+
+ ZERO_STRUCTP(p); /* initialize for possible padding */
+
+ p->next = NULL;
+ p->prev = NULL;
+ p->ip = ip;
+ p->port = port;
+ p->locked = False;
+ p->timestamp = time(NULL);
+ p->packet_type = packet_type;
+
+ switch (packet_type) {
+ case NMB_PACKET:
+ ok = parse_nmb(buf,length,&p->packet.nmb);
+ break;
+
+ case DGRAM_PACKET:
+ ok = parse_dgram(buf,length,&p->packet.dgram);
+ break;
+ }
+
+ if (!ok) {
+ free_packet(p);
+ return NULL;
+ }
+
+ return p;
+}
+
+/*******************************************************************
+ Read a packet from a socket and parse it, returning a packet ready
+ to be used or put on the queue. This assumes a UDP socket.
+******************************************************************/
+
+struct packet_struct *read_packet(int fd,enum packet_type packet_type)
+{
+ struct packet_struct *packet;
+ struct sockaddr_storage sa;
+ struct sockaddr_in *si = (struct sockaddr_in *)&sa;
+ char buf[MAX_DGRAM_SIZE];
+ int length;
+
+ length = read_udp_v4_socket(fd,buf,sizeof(buf),&sa);
+ if (length < MIN_DGRAM_SIZE || sa.ss_family != AF_INET) {
+ return NULL;
+ }
+
+ packet = parse_packet(buf,
+ length,
+ packet_type,
+ si->sin_addr,
+ ntohs(si->sin_port));
+ if (!packet)
+ return NULL;
+
+ packet->fd = fd;
+
+ num_good_receives++;
+
+ DEBUG(5,("Received a packet of len %d from (%s) port %d\n",
+ length, inet_ntoa(packet->ip), packet->port ) );
+
+ return(packet);
+}
+
+/*******************************************************************
+ Send a udp packet on a already open socket.
+******************************************************************/
+
+static bool send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
+{
+ bool ret = False;
+ int i;
+ struct sockaddr_in sock_out;
+
+ /* set the address and port */
+ memset((char *)&sock_out,'\0',sizeof(sock_out));
+ putip((char *)&sock_out.sin_addr,(char *)&ip);
+ sock_out.sin_port = htons( port );
+ sock_out.sin_family = AF_INET;
+
+ DEBUG( 5, ( "Sending a packet of len %d to (%s) on port %d\n",
+ len, inet_ntoa(ip), port ) );
+
+ /*
+ * Patch to fix asynch error notifications from Linux kernel.
+ */
+
+ for (i = 0; i < 5; i++) {
+ ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out,
+ sizeof(sock_out)) >= 0);
+ if (ret || errno != ECONNREFUSED)
+ break;
+ }
+
+ if (!ret)
+ DEBUG(0,("Packet send failed to %s(%d) ERRNO=%s\n",
+ inet_ntoa(ip),port,strerror(errno)));
+
+ if (ret)
+ num_good_sends++;
+
+ return(ret);
+}
+
+/*******************************************************************
+ Build a dgram packet ready for sending.
+ If buf == NULL this is a length calculation.
+******************************************************************/
+
+static int build_dgram(char *buf, size_t len, struct dgram_packet *dgram)
+{
+ unsigned char *ubuf = (unsigned char *)buf;
+ int offset=0;
+
+ /* put in the header */
+ if (buf) {
+ ubuf[0] = dgram->header.msg_type;
+ ubuf[1] = (((int)dgram->header.flags.node_type)<<2);
+ if (dgram->header.flags.more)
+ ubuf[1] |= 1;
+ if (dgram->header.flags.first)
+ ubuf[1] |= 2;
+ RSSVAL(ubuf,2,dgram->header.dgm_id);
+ putip(ubuf+4,(char *)&dgram->header.source_ip);
+ RSSVAL(ubuf,8,dgram->header.source_port);
+ RSSVAL(ubuf,12,dgram->header.packet_offset);
+ }
+
+ offset = 14;
+
+ if (dgram->header.msg_type == 0x10 ||
+ dgram->header.msg_type == 0x11 ||
+ dgram->header.msg_type == 0x12) {
+ offset += put_nmb_name((char *)ubuf,offset,&dgram->source_name);
+ offset += put_nmb_name((char *)ubuf,offset,&dgram->dest_name);
+ }
+
+ if (buf) {
+ memcpy(ubuf+offset,dgram->data,dgram->datasize);
+ }
+ offset += dgram->datasize;
+
+ /* automatically set the dgm_length
+ * NOTE: RFC1002 says the dgm_length does *not*
+ * include the fourteen-byte header. crh
+ */
+ dgram->header.dgm_length = (offset - 14);
+ if (buf) {
+ RSSVAL(ubuf,10,dgram->header.dgm_length);
+ }
+
+ return offset;
+}
+
+/*******************************************************************
+ Build a nmb name
+*******************************************************************/
+
+void make_nmb_name( struct nmb_name *n, const char *name, int type)
+{
+ fstring unix_name;
+ memset( (char *)n, '\0', sizeof(struct nmb_name) );
+ fstrcpy(unix_name, name);
+ strupper_m(unix_name);
+ push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
+ n->name_type = (unsigned int)type & 0xFF;
+ push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
+}
+
+/*******************************************************************
+ 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.
+ If buf == NULL this is a length calculation.
+******************************************************************/
+
+static int build_nmb(char *buf, size_t len, struct nmb_packet *nmb)
+{
+ unsigned char *ubuf = (unsigned char *)buf;
+ int offset=0;
+
+ if (len && len < 12) {
+ return 0;
+ }
+
+ /* put in the header */
+ if (buf) {
+ 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 &&
+ 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 &&
+ 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);
+ RSSVAL(ubuf,offset+10,nmb->header.arcount);
+ }
+
+ offset += 12;
+ if (nmb->header.qdcount) {
+ /* XXXX this doesn't handle a qdcount of > 1 */
+ if (len) {
+ /* Length check. */
+ int extra = put_nmb_name(NULL,offset,
+ &nmb->question.question_name);
+ if (offset + extra > len) {
+ return 0;
+ }
+ }
+ offset += put_nmb_name((char *)ubuf,offset,
+ &nmb->question.question_name);
+ if (buf) {
+ RSSVAL(ubuf,offset,nmb->question.question_type);
+ RSSVAL(ubuf,offset+2,nmb->question.question_class);
+ }
+ offset += 4;
+ }
+
+ if (nmb->header.ancount) {
+ if (len) {
+ /* Length check. */
+ int extra = put_res_rec(NULL,offset,nmb->answers,
+ nmb->header.ancount);
+ if (offset + extra > len) {
+ return 0;
+ }
+ }
+ offset += put_res_rec((char *)ubuf,offset,nmb->answers,
+ nmb->header.ancount);
+ }
+
+ if (nmb->header.nscount) {
+ if (len) {
+ /* Length check. */
+ int extra = put_res_rec(NULL,offset,nmb->nsrecs,
+ nmb->header.nscount);
+ if (offset + extra > len) {
+ return 0;
+ }
+ }
+ offset += put_res_rec((char *)ubuf,offset,nmb->nsrecs,
+ nmb->header.nscount);
+ }
+
+ /*
+ * 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)) {
+
+ if (len) {
+ /* Length check. */
+ int extra = put_compressed_name_ptr(NULL,offset,
+ nmb->additional,12);
+ if (offset + extra > len) {
+ return 0;
+ }
+ }
+ offset += put_compressed_name_ptr(ubuf,offset,
+ nmb->additional,12);
+ } else if (nmb->header.arcount) {
+ if (len) {
+ /* Length check. */
+ int extra = put_res_rec(NULL,offset,nmb->additional,
+ nmb->header.arcount);
+ if (offset + extra > len) {
+ return 0;
+ }
+ }
+ offset += put_res_rec((char *)ubuf,offset,nmb->additional,
+ nmb->header.arcount);
+ }
+ return offset;
+}
+
+/*******************************************************************
+ Linearise a packet.
+******************************************************************/
+
+int build_packet(char *buf, size_t buflen, struct packet_struct *p)
+{
+ int len = 0;
+
+ switch (p->packet_type) {
+ case NMB_PACKET:
+ len = build_nmb(buf,buflen,&p->packet.nmb);
+ break;
+
+ case DGRAM_PACKET:
+ len = build_dgram(buf,buflen,&p->packet.dgram);
+ break;
+ }
+
+ return len;
+}
+
+/*******************************************************************
+ Send a packet_struct.
+******************************************************************/
+
+bool send_packet(struct packet_struct *p)
+{
+ char buf[1024];
+ int len=0;
+
+ memset(buf,'\0',sizeof(buf));
+
+ len = build_packet(buf, sizeof(buf), p);
+
+ if (!len)
+ return(False);
+
+ return(send_udp(p->fd,buf,len,p->ip,p->port));
+}
+
+/****************************************************************************
+ Receive a packet with timeout on a open UDP filedescriptor.
+ The timeout is in milliseconds
+***************************************************************************/
+
+struct packet_struct *receive_packet(int fd,enum packet_type type,int t)
+{
+ fd_set fds;
+ struct timeval timeout;
+ int ret;
+
+ FD_ZERO(&fds);
+ FD_SET(fd,&fds);
+ timeout.tv_sec = t/1000;
+ timeout.tv_usec = 1000*(t%1000);
+
+ if ((ret = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout)) == -1) {
+ /* errno should be EBADF or EINVAL. */
+ DEBUG(0,("select returned -1, errno = %s (%d)\n",
+ strerror(errno), errno));
+ return NULL;
+ }
+
+ if (ret == 0) /* timeout */
+ return NULL;
+
+ if (FD_ISSET(fd,&fds))
+ return(read_packet(fd,type));
+
+ return(NULL);
+}
+
+/****************************************************************************
+ Receive a UDP/137 packet either via UDP or from the unexpected packet
+ queue. The packet must be a reply packet and have the specified trn_id.
+ The timeout is in milliseconds.
+***************************************************************************/
+
+struct packet_struct *receive_nmb_packet(int fd, int t, int trn_id)
+{
+ struct packet_struct *p;
+
+ p = receive_packet(fd, NMB_PACKET, t);
+
+ if (p && p->packet.nmb.header.response &&
+ p->packet.nmb.header.name_trn_id == trn_id) {
+ return p;
+ }
+ if (p)
+ free_packet(p);
+
+ /* try the unexpected packet queue */
+ return receive_unexpected(NMB_PACKET, trn_id, NULL);
+}
+
+/****************************************************************************
+ Receive a UDP/138 packet either via UDP or from the unexpected packet
+ queue. The packet must be a reply packet and have the specified mailslot name
+ The timeout is in milliseconds.
+***************************************************************************/
+
+struct packet_struct *receive_dgram_packet(int fd, int t,
+ const char *mailslot_name)
+{
+ struct packet_struct *p;
+
+ p = receive_packet(fd, DGRAM_PACKET, t);
+
+ if (p && match_mailslot_name(p, mailslot_name)) {
+ return p;
+ }
+ if (p)
+ free_packet(p);
+
+ /* try the unexpected packet queue */
+ return receive_unexpected(DGRAM_PACKET, 0, mailslot_name);
+}
+
+/****************************************************************************
+ See if a datagram has the right mailslot name.
+***************************************************************************/
+
+bool match_mailslot_name(struct packet_struct *p, const char *mailslot_name)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ char *buf;
+
+ buf = &dgram->data[0];
+ buf -= 4;
+
+ buf = smb_buf(buf);
+
+ if (memcmp(buf, mailslot_name, strlen(mailslot_name)+1) == 0) {
+ return True;
+ }
+
+ return False;
+}
+
+/****************************************************************************
+ Return the number of bits that match between two len character buffers
+***************************************************************************/
+
+int matching_len_bits(unsigned char *p1, unsigned char *p2, size_t len)
+{
+ size_t i, j;
+ int ret = 0;
+ for (i=0; i<len; i++) {
+ if (p1[i] != p2[i])
+ break;
+ ret += 8;
+ }
+
+ if (i==len)
+ return ret;
+
+ for (j=0; j<8; j++) {
+ if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j))))
+ break;
+ ret++;
+ }
+
+ return ret;
+}
+
+static unsigned char sort_ip[4];
+
+/****************************************************************************
+ Compare two query reply records.
+***************************************************************************/
+
+static int name_query_comp(unsigned char *p1, unsigned char *p2)
+{
+ return matching_len_bits(p2+2, sort_ip, 4) -
+ matching_len_bits(p1+2, sort_ip, 4);
+}
+
+/****************************************************************************
+ Sort a set of 6 byte name query response records so that the IPs that
+ have the most leading bits in common with the specified address come first.
+***************************************************************************/
+
+void sort_query_replies(char *data, int n, struct in_addr ip)
+{
+ if (n <= 1)
+ return;
+
+ putip(sort_ip, (char *)&ip);
+
+ qsort(data, n, 6, QSORT_CAST name_query_comp);
+}
+
+/****************************************************************************
+ Interpret the weird netbios "name" into a unix fstring. Return the name type.
+****************************************************************************/
+
+static int name_interpret(char *in, fstring name)
+{
+ int ret;
+ int len = (*in++) / 2;
+ fstring out_string;
+ char *out = out_string;
+
+ *out=0;
+
+ if (len > 30 || len<1)
+ return(0);
+
+ while (len--) {
+ if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
+ *out = 0;
+ return(0);
+ }
+ *out = ((in[0]-'A')<<4) + (in[1]-'A');
+ in += 2;
+ out++;
+ }
+ ret = out[-1];
+ out[-1] = 0;
+
+#ifdef NETBIOS_SCOPE
+ /* Handle any scope names */
+ while(*in) {
+ *out++ = '.'; /* Scope names are separated by periods */
+ len = *(unsigned char *)in++;
+ StrnCpy(out, in, len);
+ out += len;
+ *out=0;
+ in += len;
+ }
+#endif
+ pull_ascii_fstring(name, out_string);
+
+ return(ret);
+}
+
+/****************************************************************************
+ 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 )
+{
+ int i;
+ int len;
+ nstring buf;
+ char *p = Out;
+
+ /* Safely copy the input string, In, into buf[]. */
+ if (strcmp(In,"*") == 0)
+ put_name(buf, "*", '\0', 0x00);
+ else {
+ /* We use an fstring here as mb dos names can expend x3 when
+ going to utf8. */
+ fstring buf_unix;
+ nstring buf_dos;
+
+ pull_ascii_fstring(buf_unix, In);
+ strupper_m(buf_unix);
+
+ push_ascii_nstring(buf_dos, buf_unix);
+ put_name(buf, buf_dos, ' ', name_type);
+ }
+
+ /* Place the length of the first field into the output buffer. */
+ p[0] = 32;
+ p++;
+
+ /* Now convert the name to the rfc1001/1002 format. */
+ for( i = 0; i < MAX_NETBIOSNAME_LEN; i++ ) {
+ p[i*2] = ( (buf[i] >> 4) & 0x000F ) + 'A';
+ p[(i*2)+1] = (buf[i] & 0x000F) + 'A';
+ }
+ p += 32;
+ p[0] = '\0';
+
+ /* Add the scope string. */
+ for( i = 0, len = 0; *(global_scope()) != '\0'; i++, len++ ) {
+ switch( (global_scope())[i] ) {
+ case '\0':
+ p[0] = len;
+ if( len > 0 )
+ p[len+1] = 0;
+ return( name_len(Out) );
+ case '.':
+ p[0] = len;
+ p += (len + 1);
+ len = -1;
+ break;
+ default:
+ p[len+1] = (global_scope())[i];
+ break;
+ }
+ }
+
+ return( name_len(Out) );
+}
+
+/****************************************************************************
+ Find a pointer to a netbios name.
+****************************************************************************/
+
+static char *name_ptr(char *buf,int ofs)
+{
+ unsigned char c = *(unsigned char *)(buf+ofs);
+
+ if ((c & 0xC0) == 0xC0) {
+ uint16 l = RSVAL(buf, ofs) & 0x3FFF;
+ DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l));
+ return(buf + l);
+ } else {
+ return(buf+ofs);
+ }
+}
+
+/****************************************************************************
+ Extract a netbios name from a buf (into a unix string) return name type.
+****************************************************************************/
+
+int name_extract(char *buf,int ofs, fstring name)
+{
+ char *p = name_ptr(buf,ofs);
+ int d = PTR_DIFF(p,buf+ofs);
+
+ name[0] = '\0';
+ if (d < -50 || d > 50)
+ return(0);
+ return(name_interpret(p,name));
+}
+
+/****************************************************************************
+ Return the total storage length of a mangled name.
+****************************************************************************/
+
+int name_len(char *s1)
+{
+ /* NOTE: this argument _must_ be unsigned */
+ unsigned char *s = (unsigned char *)s1;
+ int len;
+
+ /* If the two high bits of the byte are set, return 2. */
+ if (0xC0 == (*s & 0xC0))
+ return(2);
+
+ /* Add up the length bytes. */
+ for (len = 1; (*s); s += (*s) + 1) {
+ len += *s + 1;
+ SMB_ASSERT(len < 80);
+ }
+
+ return(len);
+}
diff --git a/source3/libsmb/nterr.c b/source3/libsmb/nterr.c
new file mode 100644
index 0000000000..fc6340342f
--- /dev/null
+++ b/source3/libsmb/nterr.c
@@ -0,0 +1,759 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Luke Kenneth Casson Leighton 1997-2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* NT error codes. please read nterr.h */
+
+#include "includes.h"
+
+typedef struct
+{
+ const char *nt_errstr;
+ NTSTATUS nt_errcode;
+} nt_err_code_struct;
+
+static const nt_err_code_struct nt_errs[] =
+{
+ { "NT_STATUS_OK", NT_STATUS_OK },
+ { "NT_STATUS_UNSUCCESSFUL", NT_STATUS_UNSUCCESSFUL },
+ { "NT_STATUS_NOT_IMPLEMENTED", NT_STATUS_NOT_IMPLEMENTED },
+ { "NT_STATUS_INVALID_INFO_CLASS", NT_STATUS_INVALID_INFO_CLASS },
+ { "NT_STATUS_INFO_LENGTH_MISMATCH", NT_STATUS_INFO_LENGTH_MISMATCH },
+ { "NT_STATUS_ACCESS_VIOLATION", NT_STATUS_ACCESS_VIOLATION },
+ { "STATUS_BUFFER_OVERFLOW", STATUS_BUFFER_OVERFLOW },
+ { "NT_STATUS_IN_PAGE_ERROR", NT_STATUS_IN_PAGE_ERROR },
+ { "NT_STATUS_PAGEFILE_QUOTA", NT_STATUS_PAGEFILE_QUOTA },
+ { "NT_STATUS_INVALID_HANDLE", NT_STATUS_INVALID_HANDLE },
+ { "NT_STATUS_BAD_INITIAL_STACK", NT_STATUS_BAD_INITIAL_STACK },
+ { "NT_STATUS_BAD_INITIAL_PC", NT_STATUS_BAD_INITIAL_PC },
+ { "NT_STATUS_INVALID_CID", NT_STATUS_INVALID_CID },
+ { "NT_STATUS_TIMER_NOT_CANCELED", NT_STATUS_TIMER_NOT_CANCELED },
+ { "NT_STATUS_INVALID_PARAMETER", NT_STATUS_INVALID_PARAMETER },
+ { "NT_STATUS_NO_SUCH_DEVICE", NT_STATUS_NO_SUCH_DEVICE },
+ { "NT_STATUS_NO_SUCH_FILE", NT_STATUS_NO_SUCH_FILE },
+ { "NT_STATUS_INVALID_DEVICE_REQUEST", NT_STATUS_INVALID_DEVICE_REQUEST },
+ { "NT_STATUS_END_OF_FILE", NT_STATUS_END_OF_FILE },
+ { "NT_STATUS_WRONG_VOLUME", NT_STATUS_WRONG_VOLUME },
+ { "NT_STATUS_NO_MEDIA_IN_DEVICE", NT_STATUS_NO_MEDIA_IN_DEVICE },
+ { "NT_STATUS_UNRECOGNIZED_MEDIA", NT_STATUS_UNRECOGNIZED_MEDIA },
+ { "NT_STATUS_NONEXISTENT_SECTOR", NT_STATUS_NONEXISTENT_SECTOR },
+ { "NT_STATUS_MORE_PROCESSING_REQUIRED", NT_STATUS_MORE_PROCESSING_REQUIRED },
+ { "NT_STATUS_NO_MEMORY", NT_STATUS_NO_MEMORY },
+ { "NT_STATUS_CONFLICTING_ADDRESSES", NT_STATUS_CONFLICTING_ADDRESSES },
+ { "NT_STATUS_NOT_MAPPED_VIEW", NT_STATUS_NOT_MAPPED_VIEW },
+ { "NT_STATUS_UNABLE_TO_FREE_VM", NT_STATUS_UNABLE_TO_FREE_VM },
+ { "NT_STATUS_UNABLE_TO_DELETE_SECTION", NT_STATUS_UNABLE_TO_DELETE_SECTION },
+ { "NT_STATUS_INVALID_SYSTEM_SERVICE", NT_STATUS_INVALID_SYSTEM_SERVICE },
+ { "NT_STATUS_ILLEGAL_INSTRUCTION", NT_STATUS_ILLEGAL_INSTRUCTION },
+ { "NT_STATUS_INVALID_LOCK_SEQUENCE", NT_STATUS_INVALID_LOCK_SEQUENCE },
+ { "NT_STATUS_INVALID_VIEW_SIZE", NT_STATUS_INVALID_VIEW_SIZE },
+ { "NT_STATUS_INVALID_FILE_FOR_SECTION", NT_STATUS_INVALID_FILE_FOR_SECTION },
+ { "NT_STATUS_ALREADY_COMMITTED", NT_STATUS_ALREADY_COMMITTED },
+ { "NT_STATUS_ACCESS_DENIED", NT_STATUS_ACCESS_DENIED },
+ { "NT_STATUS_BUFFER_TOO_SMALL", NT_STATUS_BUFFER_TOO_SMALL },
+ { "NT_STATUS_OBJECT_TYPE_MISMATCH", NT_STATUS_OBJECT_TYPE_MISMATCH },
+ { "NT_STATUS_NONCONTINUABLE_EXCEPTION", NT_STATUS_NONCONTINUABLE_EXCEPTION },
+ { "NT_STATUS_INVALID_DISPOSITION", NT_STATUS_INVALID_DISPOSITION },
+ { "NT_STATUS_UNWIND", NT_STATUS_UNWIND },
+ { "NT_STATUS_BAD_STACK", NT_STATUS_BAD_STACK },
+ { "NT_STATUS_INVALID_UNWIND_TARGET", NT_STATUS_INVALID_UNWIND_TARGET },
+ { "NT_STATUS_NOT_LOCKED", NT_STATUS_NOT_LOCKED },
+ { "NT_STATUS_PARITY_ERROR", NT_STATUS_PARITY_ERROR },
+ { "NT_STATUS_UNABLE_TO_DECOMMIT_VM", NT_STATUS_UNABLE_TO_DECOMMIT_VM },
+ { "NT_STATUS_NOT_COMMITTED", NT_STATUS_NOT_COMMITTED },
+ { "NT_STATUS_INVALID_PORT_ATTRIBUTES", NT_STATUS_INVALID_PORT_ATTRIBUTES },
+ { "NT_STATUS_PORT_MESSAGE_TOO_LONG", NT_STATUS_PORT_MESSAGE_TOO_LONG },
+ { "NT_STATUS_INVALID_PARAMETER_MIX", NT_STATUS_INVALID_PARAMETER_MIX },
+ { "NT_STATUS_INVALID_QUOTA_LOWER", NT_STATUS_INVALID_QUOTA_LOWER },
+ { "NT_STATUS_DISK_CORRUPT_ERROR", NT_STATUS_DISK_CORRUPT_ERROR },
+ { "NT_STATUS_OBJECT_NAME_INVALID", NT_STATUS_OBJECT_NAME_INVALID },
+ { "NT_STATUS_OBJECT_NAME_NOT_FOUND", NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { "NT_STATUS_OBJECT_NAME_COLLISION", NT_STATUS_OBJECT_NAME_COLLISION },
+ { "NT_STATUS_HANDLE_NOT_WAITABLE", NT_STATUS_HANDLE_NOT_WAITABLE },
+ { "NT_STATUS_PORT_DISCONNECTED", NT_STATUS_PORT_DISCONNECTED },
+ { "NT_STATUS_DEVICE_ALREADY_ATTACHED", NT_STATUS_DEVICE_ALREADY_ATTACHED },
+ { "NT_STATUS_OBJECT_PATH_INVALID", NT_STATUS_OBJECT_PATH_INVALID },
+ { "NT_STATUS_OBJECT_PATH_NOT_FOUND", NT_STATUS_OBJECT_PATH_NOT_FOUND },
+ { "NT_STATUS_OBJECT_PATH_SYNTAX_BAD", NT_STATUS_OBJECT_PATH_SYNTAX_BAD },
+ { "NT_STATUS_DATA_OVERRUN", NT_STATUS_DATA_OVERRUN },
+ { "NT_STATUS_DATA_LATE_ERROR", NT_STATUS_DATA_LATE_ERROR },
+ { "NT_STATUS_DATA_ERROR", NT_STATUS_DATA_ERROR },
+ { "NT_STATUS_CRC_ERROR", NT_STATUS_CRC_ERROR },
+ { "NT_STATUS_SECTION_TOO_BIG", NT_STATUS_SECTION_TOO_BIG },
+ { "NT_STATUS_PORT_CONNECTION_REFUSED", NT_STATUS_PORT_CONNECTION_REFUSED },
+ { "NT_STATUS_INVALID_PORT_HANDLE", NT_STATUS_INVALID_PORT_HANDLE },
+ { "NT_STATUS_SHARING_VIOLATION", NT_STATUS_SHARING_VIOLATION },
+ { "NT_STATUS_QUOTA_EXCEEDED", NT_STATUS_QUOTA_EXCEEDED },
+ { "NT_STATUS_INVALID_PAGE_PROTECTION", NT_STATUS_INVALID_PAGE_PROTECTION },
+ { "NT_STATUS_MUTANT_NOT_OWNED", NT_STATUS_MUTANT_NOT_OWNED },
+ { "NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED", NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED },
+ { "NT_STATUS_PORT_ALREADY_SET", NT_STATUS_PORT_ALREADY_SET },
+ { "NT_STATUS_SECTION_NOT_IMAGE", NT_STATUS_SECTION_NOT_IMAGE },
+ { "NT_STATUS_SUSPEND_COUNT_EXCEEDED", NT_STATUS_SUSPEND_COUNT_EXCEEDED },
+ { "NT_STATUS_THREAD_IS_TERMINATING", NT_STATUS_THREAD_IS_TERMINATING },
+ { "NT_STATUS_BAD_WORKING_SET_LIMIT", NT_STATUS_BAD_WORKING_SET_LIMIT },
+ { "NT_STATUS_INCOMPATIBLE_FILE_MAP", NT_STATUS_INCOMPATIBLE_FILE_MAP },
+ { "NT_STATUS_SECTION_PROTECTION", NT_STATUS_SECTION_PROTECTION },
+ { "NT_STATUS_EAS_NOT_SUPPORTED", NT_STATUS_EAS_NOT_SUPPORTED },
+ { "NT_STATUS_EA_TOO_LARGE", NT_STATUS_EA_TOO_LARGE },
+ { "NT_STATUS_NONEXISTENT_EA_ENTRY", NT_STATUS_NONEXISTENT_EA_ENTRY },
+ { "NT_STATUS_NO_EAS_ON_FILE", NT_STATUS_NO_EAS_ON_FILE },
+ { "NT_STATUS_EA_CORRUPT_ERROR", NT_STATUS_EA_CORRUPT_ERROR },
+ { "NT_STATUS_FILE_LOCK_CONFLICT", NT_STATUS_FILE_LOCK_CONFLICT },
+ { "NT_STATUS_LOCK_NOT_GRANTED", NT_STATUS_LOCK_NOT_GRANTED },
+ { "NT_STATUS_DELETE_PENDING", NT_STATUS_DELETE_PENDING },
+ { "NT_STATUS_CTL_FILE_NOT_SUPPORTED", NT_STATUS_CTL_FILE_NOT_SUPPORTED },
+ { "NT_STATUS_UNKNOWN_REVISION", NT_STATUS_UNKNOWN_REVISION },
+ { "NT_STATUS_REVISION_MISMATCH", NT_STATUS_REVISION_MISMATCH },
+ { "NT_STATUS_INVALID_OWNER", NT_STATUS_INVALID_OWNER },
+ { "NT_STATUS_INVALID_PRIMARY_GROUP", NT_STATUS_INVALID_PRIMARY_GROUP },
+ { "NT_STATUS_NO_IMPERSONATION_TOKEN", NT_STATUS_NO_IMPERSONATION_TOKEN },
+ { "NT_STATUS_CANT_DISABLE_MANDATORY", NT_STATUS_CANT_DISABLE_MANDATORY },
+ { "NT_STATUS_NO_LOGON_SERVERS", NT_STATUS_NO_LOGON_SERVERS },
+ { "NT_STATUS_NO_SUCH_LOGON_SESSION", NT_STATUS_NO_SUCH_LOGON_SESSION },
+ { "NT_STATUS_NO_SUCH_PRIVILEGE", NT_STATUS_NO_SUCH_PRIVILEGE },
+ { "NT_STATUS_PRIVILEGE_NOT_HELD", NT_STATUS_PRIVILEGE_NOT_HELD },
+ { "NT_STATUS_INVALID_ACCOUNT_NAME", NT_STATUS_INVALID_ACCOUNT_NAME },
+ { "NT_STATUS_USER_EXISTS", NT_STATUS_USER_EXISTS },
+ { "NT_STATUS_NO_SUCH_USER", NT_STATUS_NO_SUCH_USER },
+ { "NT_STATUS_GROUP_EXISTS", NT_STATUS_GROUP_EXISTS },
+ { "NT_STATUS_NO_SUCH_GROUP", NT_STATUS_NO_SUCH_GROUP },
+ { "NT_STATUS_MEMBER_IN_GROUP", NT_STATUS_MEMBER_IN_GROUP },
+ { "NT_STATUS_MEMBER_NOT_IN_GROUP", NT_STATUS_MEMBER_NOT_IN_GROUP },
+ { "NT_STATUS_LAST_ADMIN", NT_STATUS_LAST_ADMIN },
+ { "NT_STATUS_WRONG_PASSWORD", NT_STATUS_WRONG_PASSWORD },
+ { "NT_STATUS_ILL_FORMED_PASSWORD", NT_STATUS_ILL_FORMED_PASSWORD },
+ { "NT_STATUS_PASSWORD_RESTRICTION", NT_STATUS_PASSWORD_RESTRICTION },
+ { "NT_STATUS_LOGON_FAILURE", NT_STATUS_LOGON_FAILURE },
+ { "NT_STATUS_ACCOUNT_RESTRICTION", NT_STATUS_ACCOUNT_RESTRICTION },
+ { "NT_STATUS_INVALID_LOGON_HOURS", NT_STATUS_INVALID_LOGON_HOURS },
+ { "NT_STATUS_INVALID_WORKSTATION", NT_STATUS_INVALID_WORKSTATION },
+ { "NT_STATUS_PASSWORD_EXPIRED", NT_STATUS_PASSWORD_EXPIRED },
+ { "NT_STATUS_ACCOUNT_DISABLED", NT_STATUS_ACCOUNT_DISABLED },
+ { "NT_STATUS_NONE_MAPPED", NT_STATUS_NONE_MAPPED },
+ { "NT_STATUS_TOO_MANY_LUIDS_REQUESTED", NT_STATUS_TOO_MANY_LUIDS_REQUESTED },
+ { "NT_STATUS_LUIDS_EXHAUSTED", NT_STATUS_LUIDS_EXHAUSTED },
+ { "NT_STATUS_INVALID_SUB_AUTHORITY", NT_STATUS_INVALID_SUB_AUTHORITY },
+ { "NT_STATUS_INVALID_ACL", NT_STATUS_INVALID_ACL },
+ { "NT_STATUS_INVALID_SID", NT_STATUS_INVALID_SID },
+ { "NT_STATUS_INVALID_SECURITY_DESCR", NT_STATUS_INVALID_SECURITY_DESCR },
+ { "NT_STATUS_PROCEDURE_NOT_FOUND", NT_STATUS_PROCEDURE_NOT_FOUND },
+ { "NT_STATUS_INVALID_IMAGE_FORMAT", NT_STATUS_INVALID_IMAGE_FORMAT },
+ { "NT_STATUS_NO_TOKEN", NT_STATUS_NO_TOKEN },
+ { "NT_STATUS_BAD_INHERITANCE_ACL", NT_STATUS_BAD_INHERITANCE_ACL },
+ { "NT_STATUS_RANGE_NOT_LOCKED", NT_STATUS_RANGE_NOT_LOCKED },
+ { "NT_STATUS_DISK_FULL", NT_STATUS_DISK_FULL },
+ { "NT_STATUS_SERVER_DISABLED", NT_STATUS_SERVER_DISABLED },
+ { "NT_STATUS_SERVER_NOT_DISABLED", NT_STATUS_SERVER_NOT_DISABLED },
+ { "NT_STATUS_TOO_MANY_GUIDS_REQUESTED", NT_STATUS_TOO_MANY_GUIDS_REQUESTED },
+ { "NT_STATUS_GUIDS_EXHAUSTED", NT_STATUS_GUIDS_EXHAUSTED },
+ { "NT_STATUS_INVALID_ID_AUTHORITY", NT_STATUS_INVALID_ID_AUTHORITY },
+ { "NT_STATUS_AGENTS_EXHAUSTED", NT_STATUS_AGENTS_EXHAUSTED },
+ { "NT_STATUS_INVALID_VOLUME_LABEL", NT_STATUS_INVALID_VOLUME_LABEL },
+ { "NT_STATUS_SECTION_NOT_EXTENDED", NT_STATUS_SECTION_NOT_EXTENDED },
+ { "NT_STATUS_NOT_MAPPED_DATA", NT_STATUS_NOT_MAPPED_DATA },
+ { "NT_STATUS_RESOURCE_DATA_NOT_FOUND", NT_STATUS_RESOURCE_DATA_NOT_FOUND },
+ { "NT_STATUS_RESOURCE_TYPE_NOT_FOUND", NT_STATUS_RESOURCE_TYPE_NOT_FOUND },
+ { "NT_STATUS_RESOURCE_NAME_NOT_FOUND", NT_STATUS_RESOURCE_NAME_NOT_FOUND },
+ { "NT_STATUS_ARRAY_BOUNDS_EXCEEDED", NT_STATUS_ARRAY_BOUNDS_EXCEEDED },
+ { "NT_STATUS_FLOAT_DENORMAL_OPERAND", NT_STATUS_FLOAT_DENORMAL_OPERAND },
+ { "NT_STATUS_FLOAT_DIVIDE_BY_ZERO", NT_STATUS_FLOAT_DIVIDE_BY_ZERO },
+ { "NT_STATUS_FLOAT_INEXACT_RESULT", NT_STATUS_FLOAT_INEXACT_RESULT },
+ { "NT_STATUS_FLOAT_INVALID_OPERATION", NT_STATUS_FLOAT_INVALID_OPERATION },
+ { "NT_STATUS_FLOAT_OVERFLOW", NT_STATUS_FLOAT_OVERFLOW },
+ { "NT_STATUS_FLOAT_STACK_CHECK", NT_STATUS_FLOAT_STACK_CHECK },
+ { "NT_STATUS_FLOAT_UNDERFLOW", NT_STATUS_FLOAT_UNDERFLOW },
+ { "NT_STATUS_INTEGER_DIVIDE_BY_ZERO", NT_STATUS_INTEGER_DIVIDE_BY_ZERO },
+ { "NT_STATUS_INTEGER_OVERFLOW", NT_STATUS_INTEGER_OVERFLOW },
+ { "NT_STATUS_PRIVILEGED_INSTRUCTION", NT_STATUS_PRIVILEGED_INSTRUCTION },
+ { "NT_STATUS_TOO_MANY_PAGING_FILES", NT_STATUS_TOO_MANY_PAGING_FILES },
+ { "NT_STATUS_FILE_INVALID", NT_STATUS_FILE_INVALID },
+ { "NT_STATUS_ALLOTTED_SPACE_EXCEEDED", NT_STATUS_ALLOTTED_SPACE_EXCEEDED },
+ { "NT_STATUS_INSUFFICIENT_RESOURCES", NT_STATUS_INSUFFICIENT_RESOURCES },
+ { "NT_STATUS_DFS_EXIT_PATH_FOUND", NT_STATUS_DFS_EXIT_PATH_FOUND },
+ { "NT_STATUS_DEVICE_DATA_ERROR", NT_STATUS_DEVICE_DATA_ERROR },
+ { "NT_STATUS_DEVICE_NOT_CONNECTED", NT_STATUS_DEVICE_NOT_CONNECTED },
+ { "NT_STATUS_DEVICE_POWER_FAILURE", NT_STATUS_DEVICE_POWER_FAILURE },
+ { "NT_STATUS_FREE_VM_NOT_AT_BASE", NT_STATUS_FREE_VM_NOT_AT_BASE },
+ { "NT_STATUS_MEMORY_NOT_ALLOCATED", NT_STATUS_MEMORY_NOT_ALLOCATED },
+ { "NT_STATUS_WORKING_SET_QUOTA", NT_STATUS_WORKING_SET_QUOTA },
+ { "NT_STATUS_MEDIA_WRITE_PROTECTED", NT_STATUS_MEDIA_WRITE_PROTECTED },
+ { "NT_STATUS_DEVICE_NOT_READY", NT_STATUS_DEVICE_NOT_READY },
+ { "NT_STATUS_INVALID_GROUP_ATTRIBUTES", NT_STATUS_INVALID_GROUP_ATTRIBUTES },
+ { "NT_STATUS_BAD_IMPERSONATION_LEVEL", NT_STATUS_BAD_IMPERSONATION_LEVEL },
+ { "NT_STATUS_CANT_OPEN_ANONYMOUS", NT_STATUS_CANT_OPEN_ANONYMOUS },
+ { "NT_STATUS_BAD_VALIDATION_CLASS", NT_STATUS_BAD_VALIDATION_CLASS },
+ { "NT_STATUS_BAD_TOKEN_TYPE", NT_STATUS_BAD_TOKEN_TYPE },
+ { "NT_STATUS_BAD_MASTER_BOOT_RECORD", NT_STATUS_BAD_MASTER_BOOT_RECORD },
+ { "NT_STATUS_INSTRUCTION_MISALIGNMENT", NT_STATUS_INSTRUCTION_MISALIGNMENT },
+ { "NT_STATUS_INSTANCE_NOT_AVAILABLE", NT_STATUS_INSTANCE_NOT_AVAILABLE },
+ { "NT_STATUS_PIPE_NOT_AVAILABLE", NT_STATUS_PIPE_NOT_AVAILABLE },
+ { "NT_STATUS_INVALID_PIPE_STATE", NT_STATUS_INVALID_PIPE_STATE },
+ { "NT_STATUS_PIPE_BUSY", NT_STATUS_PIPE_BUSY },
+ { "NT_STATUS_ILLEGAL_FUNCTION", NT_STATUS_ILLEGAL_FUNCTION },
+ { "NT_STATUS_PIPE_DISCONNECTED", NT_STATUS_PIPE_DISCONNECTED },
+ { "NT_STATUS_PIPE_CLOSING", NT_STATUS_PIPE_CLOSING },
+ { "NT_STATUS_PIPE_CONNECTED", NT_STATUS_PIPE_CONNECTED },
+ { "NT_STATUS_PIPE_LISTENING", NT_STATUS_PIPE_LISTENING },
+ { "NT_STATUS_INVALID_READ_MODE", NT_STATUS_INVALID_READ_MODE },
+ { "NT_STATUS_IO_TIMEOUT", NT_STATUS_IO_TIMEOUT },
+ { "NT_STATUS_FILE_FORCED_CLOSED", NT_STATUS_FILE_FORCED_CLOSED },
+ { "NT_STATUS_PROFILING_NOT_STARTED", NT_STATUS_PROFILING_NOT_STARTED },
+ { "NT_STATUS_PROFILING_NOT_STOPPED", NT_STATUS_PROFILING_NOT_STOPPED },
+ { "NT_STATUS_COULD_NOT_INTERPRET", NT_STATUS_COULD_NOT_INTERPRET },
+ { "NT_STATUS_FILE_IS_A_DIRECTORY", NT_STATUS_FILE_IS_A_DIRECTORY },
+ { "NT_STATUS_NOT_SUPPORTED", NT_STATUS_NOT_SUPPORTED },
+ { "NT_STATUS_REMOTE_NOT_LISTENING", NT_STATUS_REMOTE_NOT_LISTENING },
+ { "NT_STATUS_DUPLICATE_NAME", NT_STATUS_DUPLICATE_NAME },
+ { "NT_STATUS_BAD_NETWORK_PATH", NT_STATUS_BAD_NETWORK_PATH },
+ { "NT_STATUS_NETWORK_BUSY", NT_STATUS_NETWORK_BUSY },
+ { "NT_STATUS_DEVICE_DOES_NOT_EXIST", NT_STATUS_DEVICE_DOES_NOT_EXIST },
+ { "NT_STATUS_TOO_MANY_COMMANDS", NT_STATUS_TOO_MANY_COMMANDS },
+ { "NT_STATUS_ADAPTER_HARDWARE_ERROR", NT_STATUS_ADAPTER_HARDWARE_ERROR },
+ { "NT_STATUS_INVALID_NETWORK_RESPONSE", NT_STATUS_INVALID_NETWORK_RESPONSE },
+ { "NT_STATUS_UNEXPECTED_NETWORK_ERROR", NT_STATUS_UNEXPECTED_NETWORK_ERROR },
+ { "NT_STATUS_BAD_REMOTE_ADAPTER", NT_STATUS_BAD_REMOTE_ADAPTER },
+ { "NT_STATUS_PRINT_QUEUE_FULL", NT_STATUS_PRINT_QUEUE_FULL },
+ { "NT_STATUS_NO_SPOOL_SPACE", NT_STATUS_NO_SPOOL_SPACE },
+ { "NT_STATUS_PRINT_CANCELLED", NT_STATUS_PRINT_CANCELLED },
+ { "NT_STATUS_NETWORK_NAME_DELETED", NT_STATUS_NETWORK_NAME_DELETED },
+ { "NT_STATUS_NETWORK_ACCESS_DENIED", NT_STATUS_NETWORK_ACCESS_DENIED },
+ { "NT_STATUS_BAD_DEVICE_TYPE", NT_STATUS_BAD_DEVICE_TYPE },
+ { "NT_STATUS_BAD_NETWORK_NAME", NT_STATUS_BAD_NETWORK_NAME },
+ { "NT_STATUS_TOO_MANY_NAMES", NT_STATUS_TOO_MANY_NAMES },
+ { "NT_STATUS_TOO_MANY_SESSIONS", NT_STATUS_TOO_MANY_SESSIONS },
+ { "NT_STATUS_SHARING_PAUSED", NT_STATUS_SHARING_PAUSED },
+ { "NT_STATUS_REQUEST_NOT_ACCEPTED", NT_STATUS_REQUEST_NOT_ACCEPTED },
+ { "NT_STATUS_REDIRECTOR_PAUSED", NT_STATUS_REDIRECTOR_PAUSED },
+ { "NT_STATUS_NET_WRITE_FAULT", NT_STATUS_NET_WRITE_FAULT },
+ { "NT_STATUS_PROFILING_AT_LIMIT", NT_STATUS_PROFILING_AT_LIMIT },
+ { "NT_STATUS_NOT_SAME_DEVICE", NT_STATUS_NOT_SAME_DEVICE },
+ { "NT_STATUS_FILE_RENAMED", NT_STATUS_FILE_RENAMED },
+ { "NT_STATUS_VIRTUAL_CIRCUIT_CLOSED", NT_STATUS_VIRTUAL_CIRCUIT_CLOSED },
+ { "NT_STATUS_NO_SECURITY_ON_OBJECT", NT_STATUS_NO_SECURITY_ON_OBJECT },
+ { "NT_STATUS_CANT_WAIT", NT_STATUS_CANT_WAIT },
+ { "NT_STATUS_PIPE_EMPTY", NT_STATUS_PIPE_EMPTY },
+ { "NT_STATUS_CANT_ACCESS_DOMAIN_INFO", NT_STATUS_CANT_ACCESS_DOMAIN_INFO },
+ { "NT_STATUS_CANT_TERMINATE_SELF", NT_STATUS_CANT_TERMINATE_SELF },
+ { "NT_STATUS_INVALID_SERVER_STATE", NT_STATUS_INVALID_SERVER_STATE },
+ { "NT_STATUS_INVALID_DOMAIN_STATE", NT_STATUS_INVALID_DOMAIN_STATE },
+ { "NT_STATUS_INVALID_DOMAIN_ROLE", NT_STATUS_INVALID_DOMAIN_ROLE },
+ { "NT_STATUS_NO_SUCH_DOMAIN", NT_STATUS_NO_SUCH_DOMAIN },
+ { "NT_STATUS_DOMAIN_EXISTS", NT_STATUS_DOMAIN_EXISTS },
+ { "NT_STATUS_DOMAIN_LIMIT_EXCEEDED", NT_STATUS_DOMAIN_LIMIT_EXCEEDED },
+ { "NT_STATUS_OPLOCK_NOT_GRANTED", NT_STATUS_OPLOCK_NOT_GRANTED },
+ { "NT_STATUS_INVALID_OPLOCK_PROTOCOL", NT_STATUS_INVALID_OPLOCK_PROTOCOL },
+ { "NT_STATUS_INTERNAL_DB_CORRUPTION", NT_STATUS_INTERNAL_DB_CORRUPTION },
+ { "NT_STATUS_INTERNAL_ERROR", NT_STATUS_INTERNAL_ERROR },
+ { "NT_STATUS_GENERIC_NOT_MAPPED", NT_STATUS_GENERIC_NOT_MAPPED },
+ { "NT_STATUS_BAD_DESCRIPTOR_FORMAT", NT_STATUS_BAD_DESCRIPTOR_FORMAT },
+ { "NT_STATUS_INVALID_USER_BUFFER", NT_STATUS_INVALID_USER_BUFFER },
+ { "NT_STATUS_UNEXPECTED_IO_ERROR", NT_STATUS_UNEXPECTED_IO_ERROR },
+ { "NT_STATUS_UNEXPECTED_MM_CREATE_ERR", NT_STATUS_UNEXPECTED_MM_CREATE_ERR },
+ { "NT_STATUS_UNEXPECTED_MM_MAP_ERROR", NT_STATUS_UNEXPECTED_MM_MAP_ERROR },
+ { "NT_STATUS_UNEXPECTED_MM_EXTEND_ERR", NT_STATUS_UNEXPECTED_MM_EXTEND_ERR },
+ { "NT_STATUS_NOT_LOGON_PROCESS", NT_STATUS_NOT_LOGON_PROCESS },
+ { "NT_STATUS_LOGON_SESSION_EXISTS", NT_STATUS_LOGON_SESSION_EXISTS },
+ { "NT_STATUS_INVALID_PARAMETER_1", NT_STATUS_INVALID_PARAMETER_1 },
+ { "NT_STATUS_INVALID_PARAMETER_2", NT_STATUS_INVALID_PARAMETER_2 },
+ { "NT_STATUS_INVALID_PARAMETER_3", NT_STATUS_INVALID_PARAMETER_3 },
+ { "NT_STATUS_INVALID_PARAMETER_4", NT_STATUS_INVALID_PARAMETER_4 },
+ { "NT_STATUS_INVALID_PARAMETER_5", NT_STATUS_INVALID_PARAMETER_5 },
+ { "NT_STATUS_INVALID_PARAMETER_6", NT_STATUS_INVALID_PARAMETER_6 },
+ { "NT_STATUS_INVALID_PARAMETER_7", NT_STATUS_INVALID_PARAMETER_7 },
+ { "NT_STATUS_INVALID_PARAMETER_8", NT_STATUS_INVALID_PARAMETER_8 },
+ { "NT_STATUS_INVALID_PARAMETER_9", NT_STATUS_INVALID_PARAMETER_9 },
+ { "NT_STATUS_INVALID_PARAMETER_10", NT_STATUS_INVALID_PARAMETER_10 },
+ { "NT_STATUS_INVALID_PARAMETER_11", NT_STATUS_INVALID_PARAMETER_11 },
+ { "NT_STATUS_INVALID_PARAMETER_12", NT_STATUS_INVALID_PARAMETER_12 },
+ { "NT_STATUS_REDIRECTOR_NOT_STARTED", NT_STATUS_REDIRECTOR_NOT_STARTED },
+ { "NT_STATUS_REDIRECTOR_STARTED", NT_STATUS_REDIRECTOR_STARTED },
+ { "NT_STATUS_STACK_OVERFLOW", NT_STATUS_STACK_OVERFLOW },
+ { "NT_STATUS_NO_SUCH_PACKAGE", NT_STATUS_NO_SUCH_PACKAGE },
+ { "NT_STATUS_BAD_FUNCTION_TABLE", NT_STATUS_BAD_FUNCTION_TABLE },
+ { "NT_STATUS_DIRECTORY_NOT_EMPTY", NT_STATUS_DIRECTORY_NOT_EMPTY },
+ { "NT_STATUS_FILE_CORRUPT_ERROR", NT_STATUS_FILE_CORRUPT_ERROR },
+ { "NT_STATUS_NOT_A_DIRECTORY", NT_STATUS_NOT_A_DIRECTORY },
+ { "NT_STATUS_BAD_LOGON_SESSION_STATE", NT_STATUS_BAD_LOGON_SESSION_STATE },
+ { "NT_STATUS_LOGON_SESSION_COLLISION", NT_STATUS_LOGON_SESSION_COLLISION },
+ { "NT_STATUS_NAME_TOO_LONG", NT_STATUS_NAME_TOO_LONG },
+ { "NT_STATUS_FILES_OPEN", NT_STATUS_FILES_OPEN },
+ { "NT_STATUS_CONNECTION_IN_USE", NT_STATUS_CONNECTION_IN_USE },
+ { "NT_STATUS_MESSAGE_NOT_FOUND", NT_STATUS_MESSAGE_NOT_FOUND },
+ { "NT_STATUS_PROCESS_IS_TERMINATING", NT_STATUS_PROCESS_IS_TERMINATING },
+ { "NT_STATUS_INVALID_LOGON_TYPE", NT_STATUS_INVALID_LOGON_TYPE },
+ { "NT_STATUS_NO_GUID_TRANSLATION", NT_STATUS_NO_GUID_TRANSLATION },
+ { "NT_STATUS_CANNOT_IMPERSONATE", NT_STATUS_CANNOT_IMPERSONATE },
+ { "NT_STATUS_IMAGE_ALREADY_LOADED", NT_STATUS_IMAGE_ALREADY_LOADED },
+ { "NT_STATUS_ABIOS_NOT_PRESENT", NT_STATUS_ABIOS_NOT_PRESENT },
+ { "NT_STATUS_ABIOS_LID_NOT_EXIST", NT_STATUS_ABIOS_LID_NOT_EXIST },
+ { "NT_STATUS_ABIOS_LID_ALREADY_OWNED", NT_STATUS_ABIOS_LID_ALREADY_OWNED },
+ { "NT_STATUS_ABIOS_NOT_LID_OWNER", NT_STATUS_ABIOS_NOT_LID_OWNER },
+ { "NT_STATUS_ABIOS_INVALID_COMMAND", NT_STATUS_ABIOS_INVALID_COMMAND },
+ { "NT_STATUS_ABIOS_INVALID_LID", NT_STATUS_ABIOS_INVALID_LID },
+ { "NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE", NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE },
+ { "NT_STATUS_ABIOS_INVALID_SELECTOR", NT_STATUS_ABIOS_INVALID_SELECTOR },
+ { "NT_STATUS_NO_LDT", NT_STATUS_NO_LDT },
+ { "NT_STATUS_INVALID_LDT_SIZE", NT_STATUS_INVALID_LDT_SIZE },
+ { "NT_STATUS_INVALID_LDT_OFFSET", NT_STATUS_INVALID_LDT_OFFSET },
+ { "NT_STATUS_INVALID_LDT_DESCRIPTOR", NT_STATUS_INVALID_LDT_DESCRIPTOR },
+ { "NT_STATUS_INVALID_IMAGE_NE_FORMAT", NT_STATUS_INVALID_IMAGE_NE_FORMAT },
+ { "NT_STATUS_RXACT_INVALID_STATE", NT_STATUS_RXACT_INVALID_STATE },
+ { "NT_STATUS_RXACT_COMMIT_FAILURE", NT_STATUS_RXACT_COMMIT_FAILURE },
+ { "NT_STATUS_MAPPED_FILE_SIZE_ZERO", NT_STATUS_MAPPED_FILE_SIZE_ZERO },
+ { "NT_STATUS_TOO_MANY_OPENED_FILES", NT_STATUS_TOO_MANY_OPENED_FILES },
+ { "NT_STATUS_CANCELLED", NT_STATUS_CANCELLED },
+ { "NT_STATUS_CANNOT_DELETE", NT_STATUS_CANNOT_DELETE },
+ { "NT_STATUS_INVALID_COMPUTER_NAME", NT_STATUS_INVALID_COMPUTER_NAME },
+ { "NT_STATUS_FILE_DELETED", NT_STATUS_FILE_DELETED },
+ { "NT_STATUS_SPECIAL_ACCOUNT", NT_STATUS_SPECIAL_ACCOUNT },
+ { "NT_STATUS_SPECIAL_GROUP", NT_STATUS_SPECIAL_GROUP },
+ { "NT_STATUS_SPECIAL_USER", NT_STATUS_SPECIAL_USER },
+ { "NT_STATUS_MEMBERS_PRIMARY_GROUP", NT_STATUS_MEMBERS_PRIMARY_GROUP },
+ { "NT_STATUS_FILE_CLOSED", NT_STATUS_FILE_CLOSED },
+ { "NT_STATUS_TOO_MANY_THREADS", NT_STATUS_TOO_MANY_THREADS },
+ { "NT_STATUS_THREAD_NOT_IN_PROCESS", NT_STATUS_THREAD_NOT_IN_PROCESS },
+ { "NT_STATUS_TOKEN_ALREADY_IN_USE", NT_STATUS_TOKEN_ALREADY_IN_USE },
+ { "NT_STATUS_PAGEFILE_QUOTA_EXCEEDED", NT_STATUS_PAGEFILE_QUOTA_EXCEEDED },
+ { "NT_STATUS_COMMITMENT_LIMIT", NT_STATUS_COMMITMENT_LIMIT },
+ { "NT_STATUS_INVALID_IMAGE_LE_FORMAT", NT_STATUS_INVALID_IMAGE_LE_FORMAT },
+ { "NT_STATUS_INVALID_IMAGE_NOT_MZ", NT_STATUS_INVALID_IMAGE_NOT_MZ },
+ { "NT_STATUS_INVALID_IMAGE_PROTECT", NT_STATUS_INVALID_IMAGE_PROTECT },
+ { "NT_STATUS_INVALID_IMAGE_WIN_16", NT_STATUS_INVALID_IMAGE_WIN_16 },
+ { "NT_STATUS_LOGON_SERVER_CONFLICT", NT_STATUS_LOGON_SERVER_CONFLICT },
+ { "NT_STATUS_TIME_DIFFERENCE_AT_DC", NT_STATUS_TIME_DIFFERENCE_AT_DC },
+ { "NT_STATUS_SYNCHRONIZATION_REQUIRED", NT_STATUS_SYNCHRONIZATION_REQUIRED },
+ { "NT_STATUS_DLL_NOT_FOUND", NT_STATUS_DLL_NOT_FOUND },
+ { "NT_STATUS_OPEN_FAILED", NT_STATUS_OPEN_FAILED },
+ { "NT_STATUS_IO_PRIVILEGE_FAILED", NT_STATUS_IO_PRIVILEGE_FAILED },
+ { "NT_STATUS_ORDINAL_NOT_FOUND", NT_STATUS_ORDINAL_NOT_FOUND },
+ { "NT_STATUS_ENTRYPOINT_NOT_FOUND", NT_STATUS_ENTRYPOINT_NOT_FOUND },
+ { "NT_STATUS_CONTROL_C_EXIT", NT_STATUS_CONTROL_C_EXIT },
+ { "NT_STATUS_LOCAL_DISCONNECT", NT_STATUS_LOCAL_DISCONNECT },
+ { "NT_STATUS_REMOTE_DISCONNECT", NT_STATUS_REMOTE_DISCONNECT },
+ { "NT_STATUS_REMOTE_RESOURCES", NT_STATUS_REMOTE_RESOURCES },
+ { "NT_STATUS_LINK_FAILED", NT_STATUS_LINK_FAILED },
+ { "NT_STATUS_LINK_TIMEOUT", NT_STATUS_LINK_TIMEOUT },
+ { "NT_STATUS_INVALID_CONNECTION", NT_STATUS_INVALID_CONNECTION },
+ { "NT_STATUS_INVALID_ADDRESS", NT_STATUS_INVALID_ADDRESS },
+ { "NT_STATUS_DLL_INIT_FAILED", NT_STATUS_DLL_INIT_FAILED },
+ { "NT_STATUS_MISSING_SYSTEMFILE", NT_STATUS_MISSING_SYSTEMFILE },
+ { "NT_STATUS_UNHANDLED_EXCEPTION", NT_STATUS_UNHANDLED_EXCEPTION },
+ { "NT_STATUS_APP_INIT_FAILURE", NT_STATUS_APP_INIT_FAILURE },
+ { "NT_STATUS_PAGEFILE_CREATE_FAILED", NT_STATUS_PAGEFILE_CREATE_FAILED },
+ { "NT_STATUS_NO_PAGEFILE", NT_STATUS_NO_PAGEFILE },
+ { "NT_STATUS_INVALID_LEVEL", NT_STATUS_INVALID_LEVEL },
+ { "NT_STATUS_WRONG_PASSWORD_CORE", NT_STATUS_WRONG_PASSWORD_CORE },
+ { "NT_STATUS_ILLEGAL_FLOAT_CONTEXT", NT_STATUS_ILLEGAL_FLOAT_CONTEXT },
+ { "NT_STATUS_PIPE_BROKEN", NT_STATUS_PIPE_BROKEN },
+ { "NT_STATUS_REGISTRY_CORRUPT", NT_STATUS_REGISTRY_CORRUPT },
+ { "NT_STATUS_REGISTRY_IO_FAILED", NT_STATUS_REGISTRY_IO_FAILED },
+ { "NT_STATUS_NO_EVENT_PAIR", NT_STATUS_NO_EVENT_PAIR },
+ { "NT_STATUS_UNRECOGNIZED_VOLUME", NT_STATUS_UNRECOGNIZED_VOLUME },
+ { "NT_STATUS_SERIAL_NO_DEVICE_INITED", NT_STATUS_SERIAL_NO_DEVICE_INITED },
+ { "NT_STATUS_NO_SUCH_ALIAS", NT_STATUS_NO_SUCH_ALIAS },
+ { "NT_STATUS_MEMBER_NOT_IN_ALIAS", NT_STATUS_MEMBER_NOT_IN_ALIAS },
+ { "NT_STATUS_MEMBER_IN_ALIAS", NT_STATUS_MEMBER_IN_ALIAS },
+ { "NT_STATUS_ALIAS_EXISTS", NT_STATUS_ALIAS_EXISTS },
+ { "NT_STATUS_LOGON_NOT_GRANTED", NT_STATUS_LOGON_NOT_GRANTED },
+ { "NT_STATUS_TOO_MANY_SECRETS", NT_STATUS_TOO_MANY_SECRETS },
+ { "NT_STATUS_SECRET_TOO_LONG", NT_STATUS_SECRET_TOO_LONG },
+ { "NT_STATUS_INTERNAL_DB_ERROR", NT_STATUS_INTERNAL_DB_ERROR },
+ { "NT_STATUS_FULLSCREEN_MODE", NT_STATUS_FULLSCREEN_MODE },
+ { "NT_STATUS_TOO_MANY_CONTEXT_IDS", NT_STATUS_TOO_MANY_CONTEXT_IDS },
+ { "NT_STATUS_LOGON_TYPE_NOT_GRANTED", NT_STATUS_LOGON_TYPE_NOT_GRANTED },
+ { "NT_STATUS_NOT_REGISTRY_FILE", NT_STATUS_NOT_REGISTRY_FILE },
+ { "NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED", NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED },
+ { "NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR", NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR },
+ { "NT_STATUS_FT_MISSING_MEMBER", NT_STATUS_FT_MISSING_MEMBER },
+ { "NT_STATUS_ILL_FORMED_SERVICE_ENTRY", NT_STATUS_ILL_FORMED_SERVICE_ENTRY },
+ { "NT_STATUS_ILLEGAL_CHARACTER", NT_STATUS_ILLEGAL_CHARACTER },
+ { "NT_STATUS_UNMAPPABLE_CHARACTER", NT_STATUS_UNMAPPABLE_CHARACTER },
+ { "NT_STATUS_UNDEFINED_CHARACTER", NT_STATUS_UNDEFINED_CHARACTER },
+ { "NT_STATUS_FLOPPY_VOLUME", NT_STATUS_FLOPPY_VOLUME },
+ { "NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND", NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND },
+ { "NT_STATUS_FLOPPY_WRONG_CYLINDER", NT_STATUS_FLOPPY_WRONG_CYLINDER },
+ { "NT_STATUS_FLOPPY_UNKNOWN_ERROR", NT_STATUS_FLOPPY_UNKNOWN_ERROR },
+ { "NT_STATUS_FLOPPY_BAD_REGISTERS", NT_STATUS_FLOPPY_BAD_REGISTERS },
+ { "NT_STATUS_DISK_RECALIBRATE_FAILED", NT_STATUS_DISK_RECALIBRATE_FAILED },
+ { "NT_STATUS_DISK_OPERATION_FAILED", NT_STATUS_DISK_OPERATION_FAILED },
+ { "NT_STATUS_DISK_RESET_FAILED", NT_STATUS_DISK_RESET_FAILED },
+ { "NT_STATUS_SHARED_IRQ_BUSY", NT_STATUS_SHARED_IRQ_BUSY },
+ { "NT_STATUS_FT_ORPHANING", NT_STATUS_FT_ORPHANING },
+ { "NT_STATUS_PARTITION_FAILURE", NT_STATUS_PARTITION_FAILURE },
+ { "NT_STATUS_INVALID_BLOCK_LENGTH", NT_STATUS_INVALID_BLOCK_LENGTH },
+ { "NT_STATUS_DEVICE_NOT_PARTITIONED", NT_STATUS_DEVICE_NOT_PARTITIONED },
+ { "NT_STATUS_UNABLE_TO_LOCK_MEDIA", NT_STATUS_UNABLE_TO_LOCK_MEDIA },
+ { "NT_STATUS_UNABLE_TO_UNLOAD_MEDIA", NT_STATUS_UNABLE_TO_UNLOAD_MEDIA },
+ { "NT_STATUS_EOM_OVERFLOW", NT_STATUS_EOM_OVERFLOW },
+ { "NT_STATUS_NO_MEDIA", NT_STATUS_NO_MEDIA },
+ { "NT_STATUS_NO_SUCH_MEMBER", NT_STATUS_NO_SUCH_MEMBER },
+ { "NT_STATUS_INVALID_MEMBER", NT_STATUS_INVALID_MEMBER },
+ { "NT_STATUS_KEY_DELETED", NT_STATUS_KEY_DELETED },
+ { "NT_STATUS_NO_LOG_SPACE", NT_STATUS_NO_LOG_SPACE },
+ { "NT_STATUS_TOO_MANY_SIDS", NT_STATUS_TOO_MANY_SIDS },
+ { "NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED", NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED },
+ { "NT_STATUS_KEY_HAS_CHILDREN", NT_STATUS_KEY_HAS_CHILDREN },
+ { "NT_STATUS_CHILD_MUST_BE_VOLATILE", NT_STATUS_CHILD_MUST_BE_VOLATILE },
+ { "NT_STATUS_DEVICE_CONFIGURATION_ERROR", NT_STATUS_DEVICE_CONFIGURATION_ERROR },
+ { "NT_STATUS_DRIVER_INTERNAL_ERROR", NT_STATUS_DRIVER_INTERNAL_ERROR },
+ { "NT_STATUS_INVALID_DEVICE_STATE", NT_STATUS_INVALID_DEVICE_STATE },
+ { "NT_STATUS_IO_DEVICE_ERROR", NT_STATUS_IO_DEVICE_ERROR },
+ { "NT_STATUS_DEVICE_PROTOCOL_ERROR", NT_STATUS_DEVICE_PROTOCOL_ERROR },
+ { "NT_STATUS_BACKUP_CONTROLLER", NT_STATUS_BACKUP_CONTROLLER },
+ { "NT_STATUS_LOG_FILE_FULL", NT_STATUS_LOG_FILE_FULL },
+ { "NT_STATUS_TOO_LATE", NT_STATUS_TOO_LATE },
+ { "NT_STATUS_NO_TRUST_LSA_SECRET", NT_STATUS_NO_TRUST_LSA_SECRET },
+ { "NT_STATUS_NO_TRUST_SAM_ACCOUNT", NT_STATUS_NO_TRUST_SAM_ACCOUNT },
+ { "NT_STATUS_TRUSTED_DOMAIN_FAILURE", NT_STATUS_TRUSTED_DOMAIN_FAILURE },
+ { "NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE", NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE },
+ { "NT_STATUS_EVENTLOG_FILE_CORRUPT", NT_STATUS_EVENTLOG_FILE_CORRUPT },
+ { "NT_STATUS_EVENTLOG_CANT_START", NT_STATUS_EVENTLOG_CANT_START },
+ { "NT_STATUS_TRUST_FAILURE", NT_STATUS_TRUST_FAILURE },
+ { "NT_STATUS_MUTANT_LIMIT_EXCEEDED", NT_STATUS_MUTANT_LIMIT_EXCEEDED },
+ { "NT_STATUS_NETLOGON_NOT_STARTED", NT_STATUS_NETLOGON_NOT_STARTED },
+ { "NT_STATUS_ACCOUNT_EXPIRED", NT_STATUS_ACCOUNT_EXPIRED },
+ { "NT_STATUS_POSSIBLE_DEADLOCK", NT_STATUS_POSSIBLE_DEADLOCK },
+ { "NT_STATUS_NETWORK_CREDENTIAL_CONFLICT", NT_STATUS_NETWORK_CREDENTIAL_CONFLICT },
+ { "NT_STATUS_REMOTE_SESSION_LIMIT", NT_STATUS_REMOTE_SESSION_LIMIT },
+ { "NT_STATUS_EVENTLOG_FILE_CHANGED", NT_STATUS_EVENTLOG_FILE_CHANGED },
+ { "NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT },
+ { "NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT", NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT },
+ { "NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT", NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT },
+ { "NT_STATUS_DOMAIN_TRUST_INCONSISTENT", NT_STATUS_DOMAIN_TRUST_INCONSISTENT },
+ { "NT_STATUS_FS_DRIVER_REQUIRED", NT_STATUS_FS_DRIVER_REQUIRED },
+ { "NT_STATUS_NO_USER_SESSION_KEY", NT_STATUS_NO_USER_SESSION_KEY },
+ { "NT_STATUS_USER_SESSION_DELETED", NT_STATUS_USER_SESSION_DELETED },
+ { "NT_STATUS_RESOURCE_LANG_NOT_FOUND", NT_STATUS_RESOURCE_LANG_NOT_FOUND },
+ { "NT_STATUS_INSUFF_SERVER_RESOURCES", NT_STATUS_INSUFF_SERVER_RESOURCES },
+ { "NT_STATUS_INVALID_BUFFER_SIZE", NT_STATUS_INVALID_BUFFER_SIZE },
+ { "NT_STATUS_INVALID_ADDRESS_COMPONENT", NT_STATUS_INVALID_ADDRESS_COMPONENT },
+ { "NT_STATUS_INVALID_ADDRESS_WILDCARD", NT_STATUS_INVALID_ADDRESS_WILDCARD },
+ { "NT_STATUS_TOO_MANY_ADDRESSES", NT_STATUS_TOO_MANY_ADDRESSES },
+ { "NT_STATUS_ADDRESS_ALREADY_EXISTS", NT_STATUS_ADDRESS_ALREADY_EXISTS },
+ { "NT_STATUS_ADDRESS_CLOSED", NT_STATUS_ADDRESS_CLOSED },
+ { "NT_STATUS_CONNECTION_DISCONNECTED", NT_STATUS_CONNECTION_DISCONNECTED },
+ { "NT_STATUS_CONNECTION_RESET", NT_STATUS_CONNECTION_RESET },
+ { "NT_STATUS_TOO_MANY_NODES", NT_STATUS_TOO_MANY_NODES },
+ { "NT_STATUS_TRANSACTION_ABORTED", NT_STATUS_TRANSACTION_ABORTED },
+ { "NT_STATUS_TRANSACTION_TIMED_OUT", NT_STATUS_TRANSACTION_TIMED_OUT },
+ { "NT_STATUS_TRANSACTION_NO_RELEASE", NT_STATUS_TRANSACTION_NO_RELEASE },
+ { "NT_STATUS_TRANSACTION_NO_MATCH", NT_STATUS_TRANSACTION_NO_MATCH },
+ { "NT_STATUS_TRANSACTION_RESPONDED", NT_STATUS_TRANSACTION_RESPONDED },
+ { "NT_STATUS_TRANSACTION_INVALID_ID", NT_STATUS_TRANSACTION_INVALID_ID },
+ { "NT_STATUS_TRANSACTION_INVALID_TYPE", NT_STATUS_TRANSACTION_INVALID_TYPE },
+ { "NT_STATUS_NOT_SERVER_SESSION", NT_STATUS_NOT_SERVER_SESSION },
+ { "NT_STATUS_NOT_CLIENT_SESSION", NT_STATUS_NOT_CLIENT_SESSION },
+ { "NT_STATUS_CANNOT_LOAD_REGISTRY_FILE", NT_STATUS_CANNOT_LOAD_REGISTRY_FILE },
+ { "NT_STATUS_DEBUG_ATTACH_FAILED", NT_STATUS_DEBUG_ATTACH_FAILED },
+ { "NT_STATUS_SYSTEM_PROCESS_TERMINATED", NT_STATUS_SYSTEM_PROCESS_TERMINATED },
+ { "NT_STATUS_DATA_NOT_ACCEPTED", NT_STATUS_DATA_NOT_ACCEPTED },
+ { "NT_STATUS_NO_BROWSER_SERVERS_FOUND", NT_STATUS_NO_BROWSER_SERVERS_FOUND },
+ { "NT_STATUS_VDM_HARD_ERROR", NT_STATUS_VDM_HARD_ERROR },
+ { "NT_STATUS_DRIVER_CANCEL_TIMEOUT", NT_STATUS_DRIVER_CANCEL_TIMEOUT },
+ { "NT_STATUS_REPLY_MESSAGE_MISMATCH", NT_STATUS_REPLY_MESSAGE_MISMATCH },
+ { "NT_STATUS_MAPPED_ALIGNMENT", NT_STATUS_MAPPED_ALIGNMENT },
+ { "NT_STATUS_IMAGE_CHECKSUM_MISMATCH", NT_STATUS_IMAGE_CHECKSUM_MISMATCH },
+ { "NT_STATUS_LOST_WRITEBEHIND_DATA", NT_STATUS_LOST_WRITEBEHIND_DATA },
+ { "NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID", NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID },
+ { "NT_STATUS_PASSWORD_MUST_CHANGE", NT_STATUS_PASSWORD_MUST_CHANGE },
+ { "NT_STATUS_NOT_FOUND", NT_STATUS_NOT_FOUND },
+ { "NT_STATUS_NOT_TINY_STREAM", NT_STATUS_NOT_TINY_STREAM },
+ { "NT_STATUS_RECOVERY_FAILURE", NT_STATUS_RECOVERY_FAILURE },
+ { "NT_STATUS_STACK_OVERFLOW_READ", NT_STATUS_STACK_OVERFLOW_READ },
+ { "NT_STATUS_FAIL_CHECK", NT_STATUS_FAIL_CHECK },
+ { "NT_STATUS_DUPLICATE_OBJECTID", NT_STATUS_DUPLICATE_OBJECTID },
+ { "NT_STATUS_OBJECTID_EXISTS", NT_STATUS_OBJECTID_EXISTS },
+ { "NT_STATUS_CONVERT_TO_LARGE", NT_STATUS_CONVERT_TO_LARGE },
+ { "NT_STATUS_RETRY", NT_STATUS_RETRY },
+ { "NT_STATUS_FOUND_OUT_OF_SCOPE", NT_STATUS_FOUND_OUT_OF_SCOPE },
+ { "NT_STATUS_ALLOCATE_BUCKET", NT_STATUS_ALLOCATE_BUCKET },
+ { "NT_STATUS_PROPSET_NOT_FOUND", NT_STATUS_PROPSET_NOT_FOUND },
+ { "NT_STATUS_MARSHALL_OVERFLOW", NT_STATUS_MARSHALL_OVERFLOW },
+ { "NT_STATUS_INVALID_VARIANT", NT_STATUS_INVALID_VARIANT },
+ { "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND", NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND },
+ { "NT_STATUS_ACCOUNT_LOCKED_OUT", NT_STATUS_ACCOUNT_LOCKED_OUT },
+ { "NT_STATUS_HANDLE_NOT_CLOSABLE", NT_STATUS_HANDLE_NOT_CLOSABLE },
+ { "NT_STATUS_CONNECTION_REFUSED", NT_STATUS_CONNECTION_REFUSED },
+ { "NT_STATUS_GRACEFUL_DISCONNECT", NT_STATUS_GRACEFUL_DISCONNECT },
+ { "NT_STATUS_ADDRESS_ALREADY_ASSOCIATED", NT_STATUS_ADDRESS_ALREADY_ASSOCIATED },
+ { "NT_STATUS_ADDRESS_NOT_ASSOCIATED", NT_STATUS_ADDRESS_NOT_ASSOCIATED },
+ { "NT_STATUS_CONNECTION_INVALID", NT_STATUS_CONNECTION_INVALID },
+ { "NT_STATUS_CONNECTION_ACTIVE", NT_STATUS_CONNECTION_ACTIVE },
+ { "NT_STATUS_NETWORK_UNREACHABLE", NT_STATUS_NETWORK_UNREACHABLE },
+ { "NT_STATUS_HOST_UNREACHABLE", NT_STATUS_HOST_UNREACHABLE },
+ { "NT_STATUS_PROTOCOL_UNREACHABLE", NT_STATUS_PROTOCOL_UNREACHABLE },
+ { "NT_STATUS_PORT_UNREACHABLE", NT_STATUS_PORT_UNREACHABLE },
+ { "NT_STATUS_REQUEST_ABORTED", NT_STATUS_REQUEST_ABORTED },
+ { "NT_STATUS_CONNECTION_ABORTED", NT_STATUS_CONNECTION_ABORTED },
+ { "NT_STATUS_BAD_COMPRESSION_BUFFER", NT_STATUS_BAD_COMPRESSION_BUFFER },
+ { "NT_STATUS_USER_MAPPED_FILE", NT_STATUS_USER_MAPPED_FILE },
+ { "NT_STATUS_AUDIT_FAILED", NT_STATUS_AUDIT_FAILED },
+ { "NT_STATUS_TIMER_RESOLUTION_NOT_SET", NT_STATUS_TIMER_RESOLUTION_NOT_SET },
+ { "NT_STATUS_CONNECTION_COUNT_LIMIT", NT_STATUS_CONNECTION_COUNT_LIMIT },
+ { "NT_STATUS_LOGIN_TIME_RESTRICTION", NT_STATUS_LOGIN_TIME_RESTRICTION },
+ { "NT_STATUS_LOGIN_WKSTA_RESTRICTION", NT_STATUS_LOGIN_WKSTA_RESTRICTION },
+ { "NT_STATUS_IMAGE_MP_UP_MISMATCH", NT_STATUS_IMAGE_MP_UP_MISMATCH },
+ { "NT_STATUS_INSUFFICIENT_LOGON_INFO", NT_STATUS_INSUFFICIENT_LOGON_INFO },
+ { "NT_STATUS_BAD_DLL_ENTRYPOINT", NT_STATUS_BAD_DLL_ENTRYPOINT },
+ { "NT_STATUS_BAD_SERVICE_ENTRYPOINT", NT_STATUS_BAD_SERVICE_ENTRYPOINT },
+ { "NT_STATUS_LPC_REPLY_LOST", NT_STATUS_LPC_REPLY_LOST },
+ { "NT_STATUS_IP_ADDRESS_CONFLICT1", NT_STATUS_IP_ADDRESS_CONFLICT1 },
+ { "NT_STATUS_IP_ADDRESS_CONFLICT2", NT_STATUS_IP_ADDRESS_CONFLICT2 },
+ { "NT_STATUS_REGISTRY_QUOTA_LIMIT", NT_STATUS_REGISTRY_QUOTA_LIMIT },
+ { "NT_STATUS_PATH_NOT_COVERED", NT_STATUS_PATH_NOT_COVERED },
+ { "NT_STATUS_NO_CALLBACK_ACTIVE", NT_STATUS_NO_CALLBACK_ACTIVE },
+ { "NT_STATUS_LICENSE_QUOTA_EXCEEDED", NT_STATUS_LICENSE_QUOTA_EXCEEDED },
+ { "NT_STATUS_PWD_TOO_SHORT", NT_STATUS_PWD_TOO_SHORT },
+ { "NT_STATUS_PWD_TOO_RECENT", NT_STATUS_PWD_TOO_RECENT },
+ { "NT_STATUS_PWD_HISTORY_CONFLICT", NT_STATUS_PWD_HISTORY_CONFLICT },
+ { "NT_STATUS_PLUGPLAY_NO_DEVICE", NT_STATUS_PLUGPLAY_NO_DEVICE },
+ { "NT_STATUS_UNSUPPORTED_COMPRESSION", NT_STATUS_UNSUPPORTED_COMPRESSION },
+ { "NT_STATUS_INVALID_HW_PROFILE", NT_STATUS_INVALID_HW_PROFILE },
+ { "NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH", NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH },
+ { "NT_STATUS_DRIVER_ORDINAL_NOT_FOUND", NT_STATUS_DRIVER_ORDINAL_NOT_FOUND },
+ { "NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND", NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND },
+ { "NT_STATUS_RESOURCE_NOT_OWNED", NT_STATUS_RESOURCE_NOT_OWNED },
+ { "NT_STATUS_TOO_MANY_LINKS", NT_STATUS_TOO_MANY_LINKS },
+ { "NT_STATUS_QUOTA_LIST_INCONSISTENT", NT_STATUS_QUOTA_LIST_INCONSISTENT },
+ { "NT_STATUS_FILE_IS_OFFLINE", NT_STATUS_FILE_IS_OFFLINE },
+ { "NT_STATUS_DS_NO_MORE_RIDS", NT_STATUS_DS_NO_MORE_RIDS },
+ { "NT_STATUS_NOT_A_REPARSE_POINT", NT_STATUS_NOT_A_REPARSE_POINT },
+ { "NT_STATUS_DOWNGRADE_DETECTED", NT_STATUS_DOWNGRADE_DETECTED },
+ { "NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES },
+ { "STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES },
+ { "STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED },
+ { "STATUS_NO_MORE_FILES", STATUS_NO_MORE_FILES },
+ { "NT_STATUS_RPC_CANNOT_SUPPORT", NT_STATUS_RPC_CANNOT_SUPPORT },
+ { NULL, NT_STATUS(0) }
+};
+
+/* These need sorting..... */
+
+nt_err_code_struct nt_err_desc[] =
+{
+ { "Success", NT_STATUS_OK },
+ { "Undetermined error", NT_STATUS_UNSUCCESSFUL },
+ { "Access denied", NT_STATUS_ACCESS_DENIED },
+ { "Account locked out", NT_STATUS_ACCOUNT_LOCKED_OUT },
+ { "Must change password", NT_STATUS_PASSWORD_MUST_CHANGE },
+ { "Password is too short", NT_STATUS_PWD_TOO_SHORT },
+ { "Password is too recent", NT_STATUS_PWD_TOO_RECENT },
+ { "Password history conflict", NT_STATUS_PWD_HISTORY_CONFLICT },
+ { "No logon servers", NT_STATUS_NO_LOGON_SERVERS },
+ { "Improperly formed account name", NT_STATUS_INVALID_ACCOUNT_NAME },
+ { "User exists", NT_STATUS_USER_EXISTS },
+ { "No such user", NT_STATUS_NO_SUCH_USER },
+ { "Group exists", NT_STATUS_GROUP_EXISTS },
+ { "No such group", NT_STATUS_NO_SUCH_GROUP },
+ { "Member not in group", NT_STATUS_MEMBER_NOT_IN_GROUP },
+ { "Wrong Password", NT_STATUS_WRONG_PASSWORD },
+ { "Ill formed password", NT_STATUS_ILL_FORMED_PASSWORD },
+ { "Password restriction", NT_STATUS_PASSWORD_RESTRICTION },
+ { "Logon failure", NT_STATUS_LOGON_FAILURE },
+ { "Account restriction", NT_STATUS_ACCOUNT_RESTRICTION },
+ { "Invalid logon hours", NT_STATUS_INVALID_LOGON_HOURS },
+ { "Invalid workstation", NT_STATUS_INVALID_WORKSTATION },
+ { "Password expired", NT_STATUS_PASSWORD_EXPIRED },
+ { "Account disabled", NT_STATUS_ACCOUNT_DISABLED },
+ { "Memory allocation error", NT_STATUS_NO_MEMORY },
+ { "No domain controllers located", NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND },
+ { "Named pipe not available", NT_STATUS_PIPE_NOT_AVAILABLE },
+ { "Not implemented", NT_STATUS_NOT_IMPLEMENTED },
+ { "Invalid information class", NT_STATUS_INVALID_INFO_CLASS },
+ { "Information length mismatch", NT_STATUS_INFO_LENGTH_MISMATCH },
+ { "Access violation", NT_STATUS_ACCESS_VIOLATION },
+ { "Invalid handle", NT_STATUS_INVALID_HANDLE },
+ { "Invalid parameter", NT_STATUS_INVALID_PARAMETER },
+ { "No memory", NT_STATUS_NO_MEMORY },
+ { "Buffer too small", NT_STATUS_BUFFER_TOO_SMALL },
+ { "Revision mismatch", NT_STATUS_REVISION_MISMATCH },
+ { "No such logon session", NT_STATUS_NO_SUCH_LOGON_SESSION },
+ { "No such privilege", NT_STATUS_NO_SUCH_PRIVILEGE },
+ { "Procedure not found", NT_STATUS_PROCEDURE_NOT_FOUND },
+ { "Server disabled", NT_STATUS_SERVER_DISABLED },
+ { "Invalid pipe state", NT_STATUS_INVALID_PIPE_STATE },
+ { "Named pipe busy", NT_STATUS_PIPE_BUSY },
+ { "Illegal function", NT_STATUS_ILLEGAL_FUNCTION },
+ { "Named pipe dicconnected", NT_STATUS_PIPE_DISCONNECTED },
+ { "Named pipe closing", NT_STATUS_PIPE_CLOSING },
+ { "Remote host not listening", NT_STATUS_REMOTE_NOT_LISTENING },
+ { "Duplicate name on network", NT_STATUS_DUPLICATE_NAME },
+ { "Print queue is full", NT_STATUS_PRINT_QUEUE_FULL },
+ { "No print spool space available", NT_STATUS_NO_SPOOL_SPACE },
+ { "The network name cannot be found", NT_STATUS_BAD_NETWORK_NAME },
+ { "The connection was refused", NT_STATUS_CONNECTION_REFUSED },
+ { "Too many names", NT_STATUS_TOO_MANY_NAMES },
+ { "Too many sessions", NT_STATUS_TOO_MANY_SESSIONS },
+ { "Invalid server state", NT_STATUS_INVALID_SERVER_STATE },
+ { "Invalid domain state", NT_STATUS_INVALID_DOMAIN_STATE },
+ { "Invalid domain role", NT_STATUS_INVALID_DOMAIN_ROLE },
+ { "No such domain", NT_STATUS_NO_SUCH_DOMAIN },
+ { "Domain exists", NT_STATUS_DOMAIN_EXISTS },
+ { "Domain limit exceeded", NT_STATUS_DOMAIN_LIMIT_EXCEEDED },
+ { "Bad logon session state", NT_STATUS_BAD_LOGON_SESSION_STATE },
+ { "Logon session collision", NT_STATUS_LOGON_SESSION_COLLISION },
+ { "Invalid logon type", NT_STATUS_INVALID_LOGON_TYPE },
+ { "Cancelled", NT_STATUS_CANCELLED },
+ { "Invalid computer name", NT_STATUS_INVALID_COMPUTER_NAME },
+ { "Logon server conflict", NT_STATUS_LOGON_SERVER_CONFLICT },
+ { "Time difference at domain controller", NT_STATUS_TIME_DIFFERENCE_AT_DC },
+ { "Pipe broken", NT_STATUS_PIPE_BROKEN },
+ { "Registry corrupt", NT_STATUS_REGISTRY_CORRUPT },
+ { "Too many secrets", NT_STATUS_TOO_MANY_SECRETS },
+ { "Too many SIDs", NT_STATUS_TOO_MANY_SIDS },
+ { "Lanmanager cross encryption required", NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED },
+ { "Log file full", NT_STATUS_LOG_FILE_FULL },
+ { "No trusted LSA secret", NT_STATUS_NO_TRUST_LSA_SECRET },
+ { "No trusted SAM account", NT_STATUS_NO_TRUST_SAM_ACCOUNT },
+ { "Trusted domain failure", NT_STATUS_TRUSTED_DOMAIN_FAILURE },
+ { "Trust relationship failure", NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE },
+ { "Trust failure", NT_STATUS_TRUST_FAILURE },
+ { "Netlogon service not started", NT_STATUS_NETLOGON_NOT_STARTED },
+ { "Account expired", NT_STATUS_ACCOUNT_EXPIRED },
+ { "Network credential conflict", NT_STATUS_NETWORK_CREDENTIAL_CONFLICT },
+ { "Remote session limit", NT_STATUS_REMOTE_SESSION_LIMIT },
+ { "No logon interdomain trust account", NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT },
+ { "No logon workstation trust account", NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT },
+ { "No logon server trust account", NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT },
+ { "Domain trust inconsistent", NT_STATUS_DOMAIN_TRUST_INCONSISTENT },
+ { "No user session key available", NT_STATUS_NO_USER_SESSION_KEY },
+ { "User session deleted", NT_STATUS_USER_SESSION_DELETED },
+ { "Insufficient server resources", NT_STATUS_INSUFF_SERVER_RESOURCES },
+ { "Insufficient logon information", NT_STATUS_INSUFFICIENT_LOGON_INFO },
+
+ { "License quota exceeded", NT_STATUS_LICENSE_QUOTA_EXCEEDED },
+ { "No more files", STATUS_NO_MORE_FILES },
+
+ { NULL, NT_STATUS(0) }
+};
+
+/*****************************************************************************
+ Returns an NT error message. not amazingly helpful, but better than a number.
+ *****************************************************************************/
+
+const char *nt_errstr(NTSTATUS nt_code)
+{
+ int idx = 0;
+ char *result;
+
+#ifdef HAVE_LDAP
+ if (NT_STATUS_TYPE(nt_code) == NT_STATUS_TYPE_LDAP) {
+ return ldap_err2string(NT_STATUS_LDAP_CODE(nt_code));
+ }
+#endif
+
+ while (nt_errs[idx].nt_errstr != NULL) {
+ if (NT_STATUS_EQUAL(nt_errs[idx].nt_errcode, nt_code)) {
+ return nt_errs[idx].nt_errstr;
+ }
+ idx++;
+ }
+
+ result = talloc_asprintf(talloc_tos(), "NT code 0x%08x",
+ NT_STATUS_V(nt_code));
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+/************************************************************************
+ Print friendler version fo NT error code
+ ***********************************************************************/
+
+const char *get_friendly_nt_error_msg(NTSTATUS nt_code)
+{
+ int idx = 0;
+
+ while (nt_err_desc[idx].nt_errstr != NULL) {
+ if (NT_STATUS_V(nt_err_desc[idx].nt_errcode) == NT_STATUS_V(nt_code)) {
+ return nt_err_desc[idx].nt_errstr;
+ }
+ idx++;
+ }
+
+ /* fall back to NT_STATUS_XXX string */
+
+ return nt_errstr(nt_code);
+}
+
+/*****************************************************************************
+ Returns an NT_STATUS constant as a string for inclusion in autogen C code.
+ *****************************************************************************/
+
+const char *get_nt_error_c_code(NTSTATUS nt_code)
+{
+ char *result;
+ int idx = 0;
+
+ while (nt_errs[idx].nt_errstr != NULL) {
+ if (NT_STATUS_V(nt_errs[idx].nt_errcode) ==
+ NT_STATUS_V(nt_code)) {
+ return nt_errs[idx].nt_errstr;
+ }
+ idx++;
+ }
+
+ result = talloc_asprintf(talloc_tos(), "NT_STATUS(0x%08x)",
+ NT_STATUS_V(nt_code));
+ SMB_ASSERT(result);
+ return result;
+}
+
+/*****************************************************************************
+ Returns the NT_STATUS constant matching the string supplied (as an NTSTATUS)
+ *****************************************************************************/
+
+NTSTATUS nt_status_string_to_code(char *nt_status_str)
+{
+ int idx = 0;
+
+ while (nt_errs[idx].nt_errstr != NULL) {
+ if (strcmp(nt_errs[idx].nt_errstr, nt_status_str) == 0) {
+ return nt_errs[idx].nt_errcode;
+ }
+ idx++;
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/**
+ * Squash an NT_STATUS in line with security requirements.
+ * In an attempt to avoid giving the whole game away when users
+ * are authenticating, NT replaces both NT_STATUS_NO_SUCH_USER and
+ * NT_STATUS_WRONG_PASSWORD with NT_STATUS_LOGON_FAILURE in certain situations
+ * (session setups in particular).
+ *
+ * @param nt_status NTSTATUS input for squashing.
+ * @return the 'squashed' nt_status
+ **/
+
+NTSTATUS nt_status_squash(NTSTATUS nt_status)
+{
+ if NT_STATUS_IS_OK(nt_status) {
+ return nt_status;
+ } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) {
+ /* Match WinXP and don't give the game away */
+ return NT_STATUS_LOGON_FAILURE;
+
+ } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) {
+ /* Match WinXP and don't give the game away */
+ return NT_STATUS_LOGON_FAILURE;
+ } else {
+ return nt_status;
+ }
+}
diff --git a/source3/libsmb/ntlm_check.c b/source3/libsmb/ntlm_check.c
new file mode 100644
index 0000000000..ae10d7373d
--- /dev/null
+++ b/source3/libsmb/ntlm_check.c
@@ -0,0 +1,463 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Andrew Bartlett 2001-2003
+ Copyright (C) Gerald Carter 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+/****************************************************************************
+ Core of smb password checking routine.
+****************************************************************************/
+
+static bool smb_pwd_check_ntlmv1(const DATA_BLOB *nt_response,
+ const uchar *part_passwd,
+ const DATA_BLOB *sec_blob,
+ DATA_BLOB *user_sess_key)
+{
+ /* Finish the encryption of part_passwd. */
+ uchar p24[24];
+
+ if (part_passwd == NULL) {
+ DEBUG(10,("No password set - DISALLOWING access\n"));
+ /* No password set - always false ! */
+ return False;
+ }
+
+ if (sec_blob->length != 8) {
+ DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect challenge size (%lu)\n",
+ (unsigned long)sec_blob->length));
+ return False;
+ }
+
+ if (nt_response->length != 24) {
+ DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect password length (%lu)\n",
+ (unsigned long)nt_response->length));
+ return False;
+ }
+
+ SMBOWFencrypt(part_passwd, sec_blob->data, p24);
+ if (user_sess_key != NULL) {
+ *user_sess_key = data_blob(NULL, 16);
+ SMBsesskeygen_ntv1(part_passwd, NULL, user_sess_key->data);
+ }
+
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("Part password (P16) was |\n"));
+ dump_data(100, part_passwd, 16);
+ DEBUGADD(100,("Password from client was |\n"));
+ dump_data(100, nt_response->data, nt_response->length);
+ DEBUGADD(100,("Given challenge was |\n"));
+ dump_data(100, sec_blob->data, sec_blob->length);
+ DEBUGADD(100,("Value from encryption was |\n"));
+ dump_data(100, p24, 24);
+#endif
+ return (memcmp(p24, nt_response->data, 24) == 0);
+}
+
+/****************************************************************************
+ Core of smb password checking routine. (NTLMv2, LMv2)
+ Note: The same code works with both NTLMv2 and LMv2.
+****************************************************************************/
+
+static bool smb_pwd_check_ntlmv2(const DATA_BLOB *ntv2_response,
+ const uchar *part_passwd,
+ const DATA_BLOB *sec_blob,
+ const char *user, const char *domain,
+ bool upper_case_domain, /* should the domain be transformed into upper case? */
+ DATA_BLOB *user_sess_key)
+{
+ /* Finish the encryption of part_passwd. */
+ uchar kr[16];
+ uchar value_from_encryption[16];
+ uchar client_response[16];
+ DATA_BLOB client_key_data;
+ bool res;
+
+ if (part_passwd == NULL) {
+ DEBUG(10,("No password set - DISALLOWING access\n"));
+ /* No password set - always False */
+ return False;
+ }
+
+ if (sec_blob->length != 8) {
+ DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect challenge size (%lu)\n",
+ (unsigned long)sec_blob->length));
+ return False;
+ }
+
+ if (ntv2_response->length < 24) {
+ /* We MUST have more than 16 bytes, or the stuff below will go
+ crazy. No known implementation sends less than the 24 bytes
+ for LMv2, let alone NTLMv2. */
+ DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect password length (%lu)\n",
+ (unsigned long)ntv2_response->length));
+ return False;
+ }
+
+ client_key_data = data_blob(ntv2_response->data+16, ntv2_response->length-16);
+ /*
+ todo: should we be checking this for anything? We can't for LMv2,
+ but for NTLMv2 it is meant to contain the current time etc.
+ */
+
+ memcpy(client_response, ntv2_response->data, sizeof(client_response));
+
+ if (!ntv2_owf_gen(part_passwd, user, domain, upper_case_domain, kr)) {
+ return False;
+ }
+
+ SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption);
+ if (user_sess_key != NULL) {
+ *user_sess_key = data_blob(NULL, 16);
+ SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key->data);
+ }
+
+#if DEBUG_PASSWORD
+ DEBUG(100,("Part password (P16) was |\n"));
+ dump_data(100, part_passwd, 16);
+ DEBUGADD(100,("Password from client was |\n"));
+ dump_data(100, ntv2_response->data, ntv2_response->length);
+ DEBUGADD(100,("Variable data from client was |\n"));
+ dump_data(100, client_key_data.data, client_key_data.length);
+ DEBUGADD(100,("Given challenge was |\n"));
+ dump_data(100, sec_blob->data, sec_blob->length);
+ DEBUGADD(100,("Value from encryption was |\n"));
+ dump_data(100, value_from_encryption, 16);
+#endif
+ data_blob_clear_free(&client_key_data);
+ res = (memcmp(value_from_encryption, client_response, 16) == 0);
+ if ((!res) && (user_sess_key != NULL))
+ data_blob_clear_free(user_sess_key);
+ return res;
+}
+
+/**
+ * Check a challenge-response password against the value of the NT or
+ * LM password hash.
+ *
+ * @param mem_ctx talloc context
+ * @param challenge 8-byte challenge. If all zero, forces plaintext comparison
+ * @param nt_response 'unicode' NT response to the challenge, or unicode password
+ * @param lm_response ASCII or LANMAN response to the challenge, or password in DOS code page
+ * @param username internal Samba username, for log messages
+ * @param client_username username the client used
+ * @param client_domain domain name the client used (may be mapped)
+ * @param nt_pw MD4 unicode password from our passdb or similar
+ * @param lm_pw LANMAN ASCII password from our passdb or similar
+ * @param user_sess_key User session key
+ * @param lm_sess_key LM session key (first 8 bytes of the LM hash)
+ */
+
+NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *challenge,
+ const DATA_BLOB *lm_response,
+ const DATA_BLOB *nt_response,
+ const DATA_BLOB *lm_interactive_pwd,
+ const DATA_BLOB *nt_interactive_pwd,
+ const char *username,
+ const char *client_username,
+ const char *client_domain,
+ const uint8 *lm_pw, const uint8 *nt_pw,
+ DATA_BLOB *user_sess_key,
+ DATA_BLOB *lm_sess_key)
+{
+ unsigned char zeros[8];
+
+ ZERO_STRUCT(zeros);
+
+ if (nt_pw == NULL) {
+ DEBUG(3,("ntlm_password_check: NO NT password stored for user %s.\n",
+ username));
+ }
+
+ if (nt_interactive_pwd && nt_interactive_pwd->length && nt_pw) {
+ if (nt_interactive_pwd->length != 16) {
+ DEBUG(3,("ntlm_password_check: Interactive logon: Invalid NT password length (%d) supplied for user %s\n", (int)nt_interactive_pwd->length,
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ if (memcmp(nt_interactive_pwd->data, nt_pw, 16) == 0) {
+ if (user_sess_key) {
+ *user_sess_key = data_blob(NULL, 16);
+ SMBsesskeygen_ntv1(nt_pw, NULL, user_sess_key->data);
+ }
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("ntlm_password_check: Interactive logon: NT password check failed for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ } else if (lm_interactive_pwd && lm_interactive_pwd->length && lm_pw) {
+ if (lm_interactive_pwd->length != 16) {
+ DEBUG(3,("ntlm_password_check: Interactive logon: Invalid LANMAN password length (%d) supplied for user %s\n", (int)lm_interactive_pwd->length,
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ if (!lp_lanman_auth()) {
+ DEBUG(3,("ntlm_password_check: Interactive logon: only LANMAN password supplied for user %s, and LM passwords are disabled!\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ if (memcmp(lm_interactive_pwd->data, lm_pw, 16) == 0) {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("ntlm_password_check: Interactive logon: LANMAN password check failed for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ }
+
+ /* Check for cleartext netlogon. Used by Exchange 5.5. */
+ if (challenge->length == sizeof(zeros) &&
+ (memcmp(challenge->data, zeros, challenge->length) == 0 )) {
+
+ DEBUG(4,("ntlm_password_check: checking plaintext passwords for user %s\n",
+ username));
+ if (nt_pw && nt_response->length) {
+ unsigned char pwhash[16];
+ mdfour(pwhash, nt_response->data, nt_response->length);
+ if (memcmp(pwhash, nt_pw, sizeof(pwhash)) == 0) {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("ntlm_password_check: NT (Unicode) plaintext password check failed for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ } else if (!lp_lanman_auth()) {
+ DEBUG(3,("ntlm_password_check: (plaintext password check) LANMAN passwords NOT PERMITTED for user %s\n",
+ username));
+
+ } else if (lm_pw && lm_response->length) {
+ uchar dospwd[14];
+ uchar p16[16];
+ ZERO_STRUCT(dospwd);
+
+ memcpy(dospwd, lm_response->data, MIN(lm_response->length, sizeof(dospwd)));
+ /* Only the fisrt 14 chars are considered, password need not be null terminated. */
+
+ /* we *might* need to upper-case the string here */
+ E_P16((const unsigned char *)dospwd, p16);
+
+ if (memcmp(p16, lm_pw, sizeof(p16)) == 0) {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("ntlm_password_check: LANMAN (ASCII) plaintext password check failed for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ } else {
+ DEBUG(3, ("Plaintext authentication for user %s attempted, but neither NT nor LM passwords available\n", username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ }
+
+ if (nt_response->length != 0 && nt_response->length < 24) {
+ DEBUG(2,("ntlm_password_check: invalid NT password length (%lu) for user %s\n",
+ (unsigned long)nt_response->length, username));
+ }
+
+ if (nt_response->length >= 24 && nt_pw) {
+ if (nt_response->length > 24) {
+ /* We have the NT MD4 hash challenge available - see if we can
+ use it
+ */
+ DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with domain [%s]\n", client_domain));
+ if (smb_pwd_check_ntlmv2( nt_response,
+ nt_pw, challenge,
+ client_username,
+ client_domain,
+ False,
+ user_sess_key)) {
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with uppercased version of domain [%s]\n", client_domain));
+ if (smb_pwd_check_ntlmv2( nt_response,
+ nt_pw, challenge,
+ client_username,
+ client_domain,
+ True,
+ user_sess_key)) {
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(4,("ntlm_password_check: Checking NTLMv2 password without a domain\n"));
+ if (smb_pwd_check_ntlmv2( nt_response,
+ nt_pw, challenge,
+ client_username,
+ "",
+ False,
+ user_sess_key)) {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("ntlm_password_check: NTLMv2 password check failed\n"));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ }
+
+ if (lp_ntlm_auth()) {
+ /* We have the NT MD4 hash challenge available - see if we can
+ use it (ie. does it exist in the smbpasswd file).
+ */
+ DEBUG(4,("ntlm_password_check: Checking NT MD4 password\n"));
+ if (smb_pwd_check_ntlmv1(nt_response,
+ nt_pw, challenge,
+ user_sess_key)) {
+ /* The LM session key for this response is not very secure,
+ so use it only if we otherwise allow LM authentication */
+
+ if (lp_lanman_auth() && lm_pw) {
+ uint8 first_8_lm_hash[16];
+ memcpy(first_8_lm_hash, lm_pw, 8);
+ memset(first_8_lm_hash + 8, '\0', 8);
+ if (lm_sess_key) {
+ *lm_sess_key = data_blob(first_8_lm_hash, 16);
+ }
+ }
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("ntlm_password_check: NT MD4 password check failed for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ } else {
+ DEBUG(2,("ntlm_password_check: NTLMv1 passwords NOT PERMITTED for user %s\n",
+ username));
+ /* no return, becouse we might pick up LMv2 in the LM field */
+ }
+ }
+
+ if (lm_response->length == 0) {
+ DEBUG(3,("ntlm_password_check: NEITHER LanMan nor NT password supplied for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ if (lm_response->length < 24) {
+ DEBUG(2,("ntlm_password_check: invalid LanMan password length (%lu) for user %s\n",
+ (unsigned long)nt_response->length, username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ if (!lp_lanman_auth()) {
+ DEBUG(3,("ntlm_password_check: Lanman passwords NOT PERMITTED for user %s\n",
+ username));
+ } else if (!lm_pw) {
+ DEBUG(3,("ntlm_password_check: NO LanMan password set for user %s (and no NT password supplied)\n",
+ username));
+ } else {
+ DEBUG(4,("ntlm_password_check: Checking LM password\n"));
+ if (smb_pwd_check_ntlmv1(lm_response,
+ lm_pw, challenge,
+ NULL)) {
+ uint8 first_8_lm_hash[16];
+ memcpy(first_8_lm_hash, lm_pw, 8);
+ memset(first_8_lm_hash + 8, '\0', 8);
+ if (user_sess_key) {
+ *user_sess_key = data_blob(first_8_lm_hash, 16);
+ }
+
+ if (lm_sess_key) {
+ *lm_sess_key = data_blob(first_8_lm_hash, 16);
+ }
+ return NT_STATUS_OK;
+ }
+ }
+
+ if (!nt_pw) {
+ DEBUG(4,("ntlm_password_check: LM password check failed for user, no NT password %s\n",username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /* This is for 'LMv2' authentication. almost NTLMv2 but limited to 24 bytes.
+ - related to Win9X, legacy NAS pass-though authentication
+ */
+ DEBUG(4,("ntlm_password_check: Checking LMv2 password with domain %s\n", client_domain));
+ if (smb_pwd_check_ntlmv2( lm_response,
+ nt_pw, challenge,
+ client_username,
+ client_domain,
+ False,
+ NULL)) {
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(4,("ntlm_password_check: Checking LMv2 password with upper-cased version of domain %s\n", client_domain));
+ if (smb_pwd_check_ntlmv2( lm_response,
+ nt_pw, challenge,
+ client_username,
+ client_domain,
+ True,
+ NULL)) {
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(4,("ntlm_password_check: Checking LMv2 password without a domain\n"));
+ if (smb_pwd_check_ntlmv2( lm_response,
+ nt_pw, challenge,
+ client_username,
+ "",
+ False,
+ NULL)) {
+ return NT_STATUS_OK;
+ }
+
+ /* Apparently NT accepts NT responses in the LM field
+ - I think this is related to Win9X pass-though authentication
+ */
+ DEBUG(4,("ntlm_password_check: Checking NT MD4 password in LM field\n"));
+ if (lp_ntlm_auth()) {
+ if (smb_pwd_check_ntlmv1(lm_response,
+ nt_pw, challenge,
+ NULL)) {
+ /* The session key for this response is still very odd.
+ It not very secure, so use it only if we otherwise
+ allow LM authentication */
+
+ if (lp_lanman_auth() && lm_pw) {
+ uint8 first_8_lm_hash[16];
+ memcpy(first_8_lm_hash, lm_pw, 8);
+ memset(first_8_lm_hash + 8, '\0', 8);
+ if (user_sess_key) {
+ *user_sess_key = data_blob(first_8_lm_hash, 16);
+ }
+
+ if (lm_sess_key) {
+ *lm_sess_key = data_blob(first_8_lm_hash, 16);
+ }
+ }
+ return NT_STATUS_OK;
+ }
+ DEBUG(3,("ntlm_password_check: LM password, NT MD4 password in LM field and LMv2 failed for user %s\n",username));
+ } else {
+ DEBUG(3,("ntlm_password_check: LM password and LMv2 failed for user %s, and NT MD4 password in LM field not permitted\n",username));
+ }
+ return NT_STATUS_WRONG_PASSWORD;
+}
+
diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c
new file mode 100644
index 0000000000..a0e54ce769
--- /dev/null
+++ b/source3/libsmb/ntlmssp.c
@@ -0,0 +1,1251 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ handle NLTMSSP, server side
+
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Andrew Bartlett 2001-2003
+ Copyright (C) Andrew Bartlett 2005 (Updated from gensec).
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static NTSTATUS ntlmssp_client_initial(struct ntlmssp_state *ntlmssp_state,
+ DATA_BLOB reply, DATA_BLOB *next_request);
+static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
+ const DATA_BLOB in, DATA_BLOB *out);
+static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state,
+ const DATA_BLOB reply, DATA_BLOB *next_request);
+static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
+ const DATA_BLOB request, DATA_BLOB *reply);
+
+/**
+ * Callbacks for NTLMSSP - for both client and server operating modes
+ *
+ */
+
+static const struct ntlmssp_callbacks {
+ enum NTLMSSP_ROLE role;
+ enum NTLM_MESSAGE_TYPE ntlmssp_command;
+ NTSTATUS (*fn)(struct ntlmssp_state *ntlmssp_state,
+ DATA_BLOB in, DATA_BLOB *out);
+} ntlmssp_callbacks[] = {
+ {NTLMSSP_CLIENT, NTLMSSP_INITIAL, ntlmssp_client_initial},
+ {NTLMSSP_SERVER, NTLMSSP_NEGOTIATE, ntlmssp_server_negotiate},
+ {NTLMSSP_CLIENT, NTLMSSP_CHALLENGE, ntlmssp_client_challenge},
+ {NTLMSSP_SERVER, NTLMSSP_AUTH, ntlmssp_server_auth},
+ {NTLMSSP_CLIENT, NTLMSSP_UNKNOWN, NULL},
+ {NTLMSSP_SERVER, NTLMSSP_UNKNOWN, NULL}
+};
+
+
+/**
+ * Print out the NTLMSSP flags for debugging
+ * @param neg_flags The flags from the packet
+ */
+
+void debug_ntlmssp_flags(uint32 neg_flags)
+{
+ DEBUG(3,("Got NTLMSSP neg_flags=0x%08x\n", neg_flags));
+
+ if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_UNICODE\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_OEM)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_OEM\n"));
+ if (neg_flags & NTLMSSP_REQUEST_TARGET)
+ DEBUGADD(4, (" NTLMSSP_REQUEST_TARGET\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_SIGN)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SIGN\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_SEAL)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SEAL\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_DATAGRAM_STYLE)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_DATAGRAM_STYLE\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_LM_KEY\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_NETWARE)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NETWARE\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_NTLM)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_ALWAYS_SIGN\n"));
+ if (neg_flags & NTLMSSP_CHAL_ACCEPT_RESPONSE)
+ DEBUGADD(4, (" NTLMSSP_CHAL_ACCEPT_RESPONSE\n"));
+ if (neg_flags & NTLMSSP_CHAL_NON_NT_SESSION_KEY)
+ DEBUGADD(4, (" NTLMSSP_CHAL_NON_NT_SESSION_KEY\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM2\n"));
+ if (neg_flags & NTLMSSP_CHAL_TARGET_INFO)
+ DEBUGADD(4, (" NTLMSSP_CHAL_TARGET_INFO\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_VERSION)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_VERSION\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_128)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_128\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_KEY_EXCH\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_56)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_56\n"));
+}
+
+/**
+ * Default challenge generation code.
+ *
+ */
+
+static const uint8 *get_challenge(const struct ntlmssp_state *ntlmssp_state)
+{
+ static uchar chal[8];
+ generate_random_buffer(chal, sizeof(chal));
+
+ return chal;
+}
+
+/**
+ * Default 'we can set the challenge to anything we like' implementation
+ *
+ */
+
+static bool may_set_challenge(const struct ntlmssp_state *ntlmssp_state)
+{
+ return True;
+}
+
+/**
+ * Default 'we can set the challenge to anything we like' implementation
+ *
+ * Does not actually do anything, as the value is always in the structure anyway.
+ *
+ */
+
+static NTSTATUS set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge)
+{
+ SMB_ASSERT(challenge->length == 8);
+ return NT_STATUS_OK;
+}
+
+/**
+ * Set a username on an NTLMSSP context - ensures it is talloc()ed
+ *
+ */
+
+NTSTATUS ntlmssp_set_username(NTLMSSP_STATE *ntlmssp_state, const char *user)
+{
+ ntlmssp_state->user = talloc_strdup(ntlmssp_state->mem_ctx, user ? user : "" );
+ if (!ntlmssp_state->user) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ * Store NT and LM hashes on an NTLMSSP context - ensures they are talloc()ed
+ *
+ */
+NTSTATUS ntlmssp_set_hashes(NTLMSSP_STATE *ntlmssp_state,
+ const unsigned char lm_hash[16],
+ const unsigned char nt_hash[16])
+{
+ ntlmssp_state->lm_hash = (unsigned char *)
+ TALLOC_MEMDUP(ntlmssp_state->mem_ctx, lm_hash, 16);
+ ntlmssp_state->nt_hash = (unsigned char *)
+ TALLOC_MEMDUP(ntlmssp_state->mem_ctx, nt_hash, 16);
+ if (!ntlmssp_state->lm_hash || !ntlmssp_state->nt_hash) {
+ TALLOC_FREE(ntlmssp_state->lm_hash);
+ TALLOC_FREE(ntlmssp_state->nt_hash);
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ * Converts a password to the hashes on an NTLMSSP context.
+ *
+ */
+NTSTATUS ntlmssp_set_password(NTLMSSP_STATE *ntlmssp_state, const char *password)
+{
+ if (!password) {
+ ntlmssp_state->lm_hash = NULL;
+ ntlmssp_state->nt_hash = NULL;
+ } else {
+ unsigned char lm_hash[16];
+ unsigned char nt_hash[16];
+
+ E_deshash(password, lm_hash);
+ E_md4hash(password, nt_hash);
+ return ntlmssp_set_hashes(ntlmssp_state, lm_hash, nt_hash);
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ * Set a domain on an NTLMSSP context - ensures it is talloc()ed
+ *
+ */
+NTSTATUS ntlmssp_set_domain(NTLMSSP_STATE *ntlmssp_state, const char *domain)
+{
+ ntlmssp_state->domain = talloc_strdup(ntlmssp_state->mem_ctx, domain ? domain : "" );
+ if (!ntlmssp_state->domain) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ * Set a workstation on an NTLMSSP context - ensures it is talloc()ed
+ *
+ */
+NTSTATUS ntlmssp_set_workstation(NTLMSSP_STATE *ntlmssp_state, const char *workstation)
+{
+ ntlmssp_state->workstation = talloc_strdup(ntlmssp_state->mem_ctx, workstation);
+ if (!ntlmssp_state->workstation) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ * Store a DATA_BLOB containing an NTLMSSP response, for use later.
+ * This copies the data blob
+ */
+
+NTSTATUS ntlmssp_store_response(NTLMSSP_STATE *ntlmssp_state,
+ DATA_BLOB response)
+{
+ ntlmssp_state->stored_response = data_blob_talloc(ntlmssp_state->mem_ctx,
+ response.data, response.length);
+ return NT_STATUS_OK;
+}
+
+/**
+ * Request features for the NTLMSSP negotiation
+ *
+ * @param ntlmssp_state NTLMSSP state
+ * @param feature_list List of space seperated features requested from NTLMSSP.
+ */
+void ntlmssp_want_feature_list(NTLMSSP_STATE *ntlmssp_state, char *feature_list)
+{
+ /*
+ * We need to set this to allow a later SetPassword
+ * via the SAMR pipe to succeed. Strange.... We could
+ * also add NTLMSSP_NEGOTIATE_SEAL here. JRA.
+ */
+ if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, True)) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ }
+ if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, True)) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ }
+ if(in_list("NTLMSSP_FEATURE_SEAL", feature_list, True)) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
+ }
+}
+
+/**
+ * Request a feature for the NTLMSSP negotiation
+ *
+ * @param ntlmssp_state NTLMSSP state
+ * @param feature Bit flag specifying the requested feature
+ */
+void ntlmssp_want_feature(NTLMSSP_STATE *ntlmssp_state, uint32 feature)
+{
+ /* As per JRA's comment above */
+ if (feature & NTLMSSP_FEATURE_SESSION_KEY) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ }
+ if (feature & NTLMSSP_FEATURE_SIGN) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ }
+ if (feature & NTLMSSP_FEATURE_SEAL) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
+ }
+}
+
+/**
+ * Next state function for the NTLMSSP state machine
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param in The packet in from the NTLMSSP partner, as a DATA_BLOB
+ * @param out The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors, NT_STATUS_MORE_PROCESSING_REQUIRED or NT_STATUS_OK.
+ */
+
+NTSTATUS ntlmssp_update(NTLMSSP_STATE *ntlmssp_state,
+ const DATA_BLOB in, DATA_BLOB *out)
+{
+ DATA_BLOB input;
+ uint32 ntlmssp_command;
+ int i;
+
+ if (ntlmssp_state->expected_state == NTLMSSP_DONE) {
+ /* Called update after negotiations finished. */
+ DEBUG(1, ("Called NTLMSSP after state machine was 'done'\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ *out = data_blob_null;
+
+ if (!in.length && ntlmssp_state->stored_response.length) {
+ input = ntlmssp_state->stored_response;
+
+ /* we only want to read the stored response once - overwrite it */
+ ntlmssp_state->stored_response = data_blob_null;
+ } else {
+ input = in;
+ }
+
+ if (!input.length) {
+ switch (ntlmssp_state->role) {
+ case NTLMSSP_CLIENT:
+ ntlmssp_command = NTLMSSP_INITIAL;
+ break;
+ case NTLMSSP_SERVER:
+ /* 'datagram' mode - no neg packet */
+ ntlmssp_command = NTLMSSP_NEGOTIATE;
+ break;
+ }
+ } else {
+ if (!msrpc_parse(&input, "Cd",
+ "NTLMSSP",
+ &ntlmssp_command)) {
+ DEBUG(1, ("Failed to parse NTLMSSP packet, could not extract NTLMSSP command\n"));
+ dump_data(2, input.data, input.length);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ if (ntlmssp_command != ntlmssp_state->expected_state) {
+ DEBUG(1, ("got NTLMSSP command %u, expected %u\n", ntlmssp_command, ntlmssp_state->expected_state));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ for (i=0; ntlmssp_callbacks[i].fn; i++) {
+ if (ntlmssp_callbacks[i].role == ntlmssp_state->role
+ && ntlmssp_callbacks[i].ntlmssp_command == ntlmssp_command) {
+ return ntlmssp_callbacks[i].fn(ntlmssp_state, input, out);
+ }
+ }
+
+ DEBUG(1, ("failed to find NTLMSSP callback for NTLMSSP mode %u, command %u\n",
+ ntlmssp_state->role, ntlmssp_command));
+
+ return NT_STATUS_INVALID_PARAMETER;
+}
+
+/**
+ * End an NTLMSSP state machine
+ *
+ * @param ntlmssp_state NTLMSSP State, free()ed by this function
+ */
+
+void ntlmssp_end(NTLMSSP_STATE **ntlmssp_state)
+{
+ TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
+
+ (*ntlmssp_state)->ref_count--;
+
+ if ((*ntlmssp_state)->ref_count == 0) {
+ data_blob_free(&(*ntlmssp_state)->chal);
+ data_blob_free(&(*ntlmssp_state)->lm_resp);
+ data_blob_free(&(*ntlmssp_state)->nt_resp);
+
+ talloc_destroy(mem_ctx);
+ }
+
+ *ntlmssp_state = NULL;
+ return;
+}
+
+/**
+ * Determine correct target name flags for reply, given server role
+ * and negotiated flags
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param neg_flags The flags from the packet
+ * @param chal_flags The flags to be set in the reply packet
+ * @return The 'target name' string.
+ */
+
+static const char *ntlmssp_target_name(struct ntlmssp_state *ntlmssp_state,
+ uint32 neg_flags, uint32 *chal_flags)
+{
+ if (neg_flags & NTLMSSP_REQUEST_TARGET) {
+ *chal_flags |= NTLMSSP_CHAL_TARGET_INFO;
+ *chal_flags |= NTLMSSP_REQUEST_TARGET;
+ if (ntlmssp_state->server_role == ROLE_STANDALONE) {
+ *chal_flags |= NTLMSSP_TARGET_TYPE_SERVER;
+ return ntlmssp_state->get_global_myname();
+ } else {
+ *chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;
+ return ntlmssp_state->get_domain();
+ };
+ } else {
+ return "";
+ }
+}
+
+static void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state,
+ uint32 neg_flags, bool allow_lm) {
+ if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM;
+ ntlmssp_state->unicode = True;
+ } else {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
+ ntlmssp_state->unicode = False;
+ }
+
+ if ((neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) && allow_lm) {
+ /* other end forcing us to use LM */
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
+ ntlmssp_state->use_ntlmv2 = False;
+ } else {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
+ }
+
+ if (!(neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
+ }
+
+ if (!(neg_flags & NTLMSSP_NEGOTIATE_NTLM2)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
+ }
+
+ if (!(neg_flags & NTLMSSP_NEGOTIATE_128)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128;
+ }
+
+ if (!(neg_flags & NTLMSSP_NEGOTIATE_56)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_56;
+ }
+
+ if (!(neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_KEY_EXCH;
+ }
+
+ if (!(neg_flags & NTLMSSP_NEGOTIATE_SIGN)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
+ }
+
+ if (!(neg_flags & NTLMSSP_NEGOTIATE_SEAL)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SEAL;
+ }
+
+ /* Woop Woop - unknown flag for Windows compatibility...
+ What does this really do ? JRA. */
+ if (!(neg_flags & NTLMSSP_NEGOTIATE_VERSION)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_VERSION;
+ }
+
+ if ((neg_flags & NTLMSSP_REQUEST_TARGET)) {
+ ntlmssp_state->neg_flags |= NTLMSSP_REQUEST_TARGET;
+ }
+}
+
+/**
+ Weaken NTLMSSP keys to cope with down-level clients and servers.
+
+ We probably should have some parameters to control this, but as
+ it only occours for LM_KEY connections, and this is controlled
+ by the client lanman auth/lanman auth parameters, it isn't too bad.
+*/
+
+DATA_BLOB ntlmssp_weaken_keys(NTLMSSP_STATE *ntlmssp_state, TALLOC_CTX *mem_ctx)
+{
+ DATA_BLOB weakened_key = data_blob_talloc(mem_ctx,
+ ntlmssp_state->session_key.data,
+ ntlmssp_state->session_key.length);
+
+ /* Nothing to weaken. We certainly don't want to 'extend' the length... */
+ if (weakened_key.length < 16) {
+ /* perhaps there was no key? */
+ return weakened_key;
+ }
+
+ /* Key weakening not performed on the master key for NTLM2
+ and does not occour for NTLM1. Therefore we only need
+ to do this for the LM_KEY.
+ */
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) {
+ /* LM key doesn't support 128 bit crypto, so this is
+ * the best we can do. If you negotiate 128 bit, but
+ * not 56, you end up with 40 bit... */
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) {
+ weakened_key.data[7] = 0xa0;
+ } else { /* forty bits */
+ weakened_key.data[5] = 0xe5;
+ weakened_key.data[6] = 0x38;
+ weakened_key.data[7] = 0xb0;
+ }
+ weakened_key.length = 8;
+ }
+ return weakened_key;
+}
+
+/**
+ * Next state function for the Negotiate packet
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or MORE_PROCESSING_REQUIRED if a reply is sent.
+ */
+
+static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
+ const DATA_BLOB request, DATA_BLOB *reply)
+{
+ DATA_BLOB struct_blob;
+ const char *dnsname;
+ char *dnsdomname = NULL;
+ uint32 neg_flags = 0;
+ uint32 ntlmssp_command, chal_flags;
+ const uint8 *cryptkey;
+ const char *target_name;
+
+ /* parse the NTLMSSP packet */
+#if 0
+ file_save("ntlmssp_negotiate.dat", request.data, request.length);
+#endif
+
+ if (request.length) {
+ if ((request.length < 16) || !msrpc_parse(&request, "Cdd",
+ "NTLMSSP",
+ &ntlmssp_command,
+ &neg_flags)) {
+ DEBUG(1, ("ntlmssp_server_negotiate: failed to parse NTLMSSP Negotiate of length %u\n",
+ (unsigned int)request.length));
+ dump_data(2, request.data, request.length);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ debug_ntlmssp_flags(neg_flags);
+ }
+
+ ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, lp_lanman_auth());
+
+ /* Ask our caller what challenge they would like in the packet */
+ cryptkey = ntlmssp_state->get_challenge(ntlmssp_state);
+
+ /* Check if we may set the challenge */
+ if (!ntlmssp_state->may_set_challenge(ntlmssp_state)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
+ }
+
+ /* The flags we send back are not just the negotiated flags,
+ * they are also 'what is in this packet'. Therfore, we
+ * operate on 'chal_flags' from here on
+ */
+
+ chal_flags = ntlmssp_state->neg_flags;
+
+ /* get the right name to fill in as 'target' */
+ target_name = ntlmssp_target_name(ntlmssp_state,
+ neg_flags, &chal_flags);
+ if (target_name == NULL)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ ntlmssp_state->chal = data_blob_talloc(ntlmssp_state->mem_ctx, cryptkey, 8);
+ ntlmssp_state->internal_chal = data_blob_talloc(ntlmssp_state->mem_ctx, cryptkey, 8);
+
+ /* This should be a 'netbios domain -> DNS domain' mapping */
+ dnsdomname = get_mydnsdomname(ntlmssp_state->mem_ctx);
+ if (!dnsdomname) {
+ dnsdomname = talloc_strdup(ntlmssp_state->mem_ctx, "");
+ }
+ if (!dnsdomname) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ strlower_m(dnsdomname);
+
+ dnsname = get_mydnsfullname();
+ if (!dnsname) {
+ dnsname = "";
+ }
+
+ /* This creates the 'blob' of names that appears at the end of the packet */
+ if (chal_flags & NTLMSSP_CHAL_TARGET_INFO)
+ {
+ msrpc_gen(&struct_blob, "aaaaa",
+ NTLMSSP_NAME_TYPE_DOMAIN, target_name,
+ NTLMSSP_NAME_TYPE_SERVER, ntlmssp_state->get_global_myname(),
+ NTLMSSP_NAME_TYPE_DOMAIN_DNS, dnsdomname,
+ NTLMSSP_NAME_TYPE_SERVER_DNS, dnsname,
+ 0, "");
+ } else {
+ struct_blob = data_blob_null;
+ }
+
+ {
+ /* Marshel the packet in the right format, be it unicode or ASCII */
+ const char *gen_string;
+ if (ntlmssp_state->unicode) {
+ gen_string = "CdUdbddB";
+ } else {
+ gen_string = "CdAdbddB";
+ }
+
+ msrpc_gen(reply, gen_string,
+ "NTLMSSP",
+ NTLMSSP_CHALLENGE,
+ target_name,
+ chal_flags,
+ cryptkey, 8,
+ 0, 0,
+ struct_blob.data, struct_blob.length);
+ }
+
+ data_blob_free(&struct_blob);
+
+ ntlmssp_state->expected_state = NTLMSSP_AUTH;
+
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+/**
+ * Next state function for the Authenticate packet
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or NT_STATUS_OK.
+ */
+
+static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
+ const DATA_BLOB request, DATA_BLOB *reply)
+{
+ DATA_BLOB encrypted_session_key = data_blob_null;
+ DATA_BLOB user_session_key = data_blob_null;
+ DATA_BLOB lm_session_key = data_blob_null;
+ DATA_BLOB session_key = data_blob_null;
+ uint32 ntlmssp_command, auth_flags;
+ NTSTATUS nt_status = NT_STATUS_OK;
+
+ /* used by NTLM2 */
+ bool doing_ntlm2 = False;
+
+ uchar session_nonce[16];
+ uchar session_nonce_hash[16];
+
+ const char *parse_string;
+ char *domain = NULL;
+ char *user = NULL;
+ char *workstation = NULL;
+
+ /* parse the NTLMSSP packet */
+ *reply = data_blob_null;
+
+#if 0
+ file_save("ntlmssp_auth.dat", request.data, request.length);
+#endif
+
+ if (ntlmssp_state->unicode) {
+ parse_string = "CdBBUUUBd";
+ } else {
+ parse_string = "CdBBAAABd";
+ }
+
+ data_blob_free(&ntlmssp_state->lm_resp);
+ data_blob_free(&ntlmssp_state->nt_resp);
+
+ ntlmssp_state->user = NULL;
+ ntlmssp_state->domain = NULL;
+ ntlmssp_state->workstation = NULL;
+
+ /* now the NTLMSSP encoded auth hashes */
+ if (!msrpc_parse(&request, parse_string,
+ "NTLMSSP",
+ &ntlmssp_command,
+ &ntlmssp_state->lm_resp,
+ &ntlmssp_state->nt_resp,
+ &domain,
+ &user,
+ &workstation,
+ &encrypted_session_key,
+ &auth_flags)) {
+ SAFE_FREE(domain);
+ SAFE_FREE(user);
+ SAFE_FREE(workstation);
+ data_blob_free(&encrypted_session_key);
+ auth_flags = 0;
+
+ /* Try again with a shorter string (Win9X truncates this packet) */
+ if (ntlmssp_state->unicode) {
+ parse_string = "CdBBUUU";
+ } else {
+ parse_string = "CdBBAAA";
+ }
+
+ /* now the NTLMSSP encoded auth hashes */
+ if (!msrpc_parse(&request, parse_string,
+ "NTLMSSP",
+ &ntlmssp_command,
+ &ntlmssp_state->lm_resp,
+ &ntlmssp_state->nt_resp,
+ &domain,
+ &user,
+ &workstation)) {
+ DEBUG(1, ("ntlmssp_server_auth: failed to parse NTLMSSP (tried both formats):\n"));
+ dump_data(2, request.data, request.length);
+ SAFE_FREE(domain);
+ SAFE_FREE(user);
+ SAFE_FREE(workstation);
+
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ if (auth_flags)
+ ntlmssp_handle_neg_flags(ntlmssp_state, auth_flags, lp_lanman_auth());
+
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) {
+ SAFE_FREE(domain);
+ SAFE_FREE(user);
+ SAFE_FREE(workstation);
+ data_blob_free(&encrypted_session_key);
+ return nt_status;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
+ SAFE_FREE(domain);
+ SAFE_FREE(user);
+ SAFE_FREE(workstation);
+ data_blob_free(&encrypted_session_key);
+ return nt_status;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_workstation(ntlmssp_state, workstation))) {
+ SAFE_FREE(domain);
+ SAFE_FREE(user);
+ SAFE_FREE(workstation);
+ data_blob_free(&encrypted_session_key);
+ return nt_status;
+ }
+
+ SAFE_FREE(domain);
+ SAFE_FREE(user);
+ SAFE_FREE(workstation);
+
+ DEBUG(3,("Got user=[%s] domain=[%s] workstation=[%s] len1=%lu len2=%lu\n",
+ ntlmssp_state->user, ntlmssp_state->domain, ntlmssp_state->workstation, (unsigned long)ntlmssp_state->lm_resp.length, (unsigned long)ntlmssp_state->nt_resp.length));
+
+#if 0
+ file_save("nthash1.dat", &ntlmssp_state->nt_resp.data, &ntlmssp_state->nt_resp.length);
+ file_save("lmhash1.dat", &ntlmssp_state->lm_resp.data, &ntlmssp_state->lm_resp.length);
+#endif
+
+ /* NTLM2 uses a 'challenge' that is made of up both the server challenge, and a
+ client challenge
+
+ However, the NTLM2 flag may still be set for the real NTLMv2 logins, be careful.
+ */
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ if (ntlmssp_state->nt_resp.length == 24 && ntlmssp_state->lm_resp.length == 24) {
+ struct MD5Context md5_session_nonce_ctx;
+ SMB_ASSERT(ntlmssp_state->internal_chal.data && ntlmssp_state->internal_chal.length == 8);
+
+ doing_ntlm2 = True;
+
+ memcpy(session_nonce, ntlmssp_state->internal_chal.data, 8);
+ memcpy(&session_nonce[8], ntlmssp_state->lm_resp.data, 8);
+
+ MD5Init(&md5_session_nonce_ctx);
+ MD5Update(&md5_session_nonce_ctx, session_nonce, 16);
+ MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
+
+ ntlmssp_state->chal = data_blob_talloc(ntlmssp_state->mem_ctx, session_nonce_hash, 8);
+
+ /* LM response is no longer useful */
+ data_blob_free(&ntlmssp_state->lm_resp);
+
+ /* We changed the effective challenge - set it */
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_state->set_challenge(ntlmssp_state, &ntlmssp_state->chal))) {
+ data_blob_free(&encrypted_session_key);
+ return nt_status;
+ }
+
+ /* LM Key is incompatible. */
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
+ }
+ }
+
+ /*
+ * Note we don't check here for NTLMv2 auth settings. If NTLMv2 auth
+ * is required (by "ntlm auth = no" and "lm auth = no" being set in the
+ * smb.conf file) and no NTLMv2 response was sent then the password check
+ * will fail here. JRA.
+ */
+
+ /* Finally, actually ask if the password is OK */
+
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_state->check_password(ntlmssp_state,
+ &user_session_key, &lm_session_key))) {
+ data_blob_free(&encrypted_session_key);
+ return nt_status;
+ }
+
+ dump_data_pw("NT session key:\n", user_session_key.data, user_session_key.length);
+ dump_data_pw("LM first-8:\n", lm_session_key.data, lm_session_key.length);
+
+ /* Handle the different session key derivation for NTLM2 */
+ if (doing_ntlm2) {
+ if (user_session_key.data && user_session_key.length == 16) {
+ session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
+ hmac_md5(user_session_key.data, session_nonce,
+ sizeof(session_nonce), session_key.data);
+ DEBUG(10,("ntlmssp_server_auth: Created NTLM2 session key.\n"));
+ dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
+
+ } else {
+ DEBUG(10,("ntlmssp_server_auth: Failed to create NTLM2 session key.\n"));
+ session_key = data_blob_null;
+ }
+ } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) {
+ if (lm_session_key.data && lm_session_key.length >= 8) {
+ if (ntlmssp_state->lm_resp.data && ntlmssp_state->lm_resp.length == 24) {
+ session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
+ if (session_key.data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ SMBsesskeygen_lm_sess_key(lm_session_key.data, ntlmssp_state->lm_resp.data,
+ session_key.data);
+ DEBUG(10,("ntlmssp_server_auth: Created NTLM session key.\n"));
+ } else {
+ uint8 zeros[24];
+ ZERO_STRUCT(zeros);
+ session_key = data_blob_talloc(
+ ntlmssp_state->mem_ctx, NULL, 16);
+ if (session_key.data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ SMBsesskeygen_lm_sess_key(
+ lm_session_key.data, zeros,
+ session_key.data);
+ }
+ dump_data_pw("LM session key:\n", session_key.data,
+ session_key.length);
+ } else {
+ DEBUG(10,("ntlmssp_server_auth: Failed to create NTLM session key.\n"));
+ session_key = data_blob_null;
+ }
+ } else if (user_session_key.data) {
+ session_key = user_session_key;
+ DEBUG(10,("ntlmssp_server_auth: Using unmodified nt session key.\n"));
+ dump_data_pw("unmodified session key:\n", session_key.data, session_key.length);
+ } else if (lm_session_key.data) {
+ session_key = lm_session_key;
+ DEBUG(10,("ntlmssp_server_auth: Using unmodified lm session key.\n"));
+ dump_data_pw("unmodified session key:\n", session_key.data, session_key.length);
+ } else {
+ DEBUG(10,("ntlmssp_server_auth: Failed to create unmodified session key.\n"));
+ session_key = data_blob_null;
+ }
+
+ /* With KEY_EXCH, the client supplies the proposed session key,
+ but encrypts it with the long-term key */
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+ if (!encrypted_session_key.data || encrypted_session_key.length != 16) {
+ data_blob_free(&encrypted_session_key);
+ DEBUG(1, ("Client-supplied KEY_EXCH session key was of invalid length (%u)!\n",
+ (unsigned int)encrypted_session_key.length));
+ return NT_STATUS_INVALID_PARAMETER;
+ } else if (!session_key.data || session_key.length != 16) {
+ DEBUG(5, ("server session key is invalid (len == %u), cannot do KEY_EXCH!\n",
+ (unsigned int)session_key.length));
+ ntlmssp_state->session_key = session_key;
+ } else {
+ dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);
+ SamOEMhash(encrypted_session_key.data,
+ session_key.data,
+ encrypted_session_key.length);
+ ntlmssp_state->session_key = data_blob_talloc(ntlmssp_state->mem_ctx,
+ encrypted_session_key.data,
+ encrypted_session_key.length);
+ dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data,
+ encrypted_session_key.length);
+ }
+ } else {
+ ntlmssp_state->session_key = session_key;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ ntlmssp_state->session_key = data_blob_null;
+ } else if (ntlmssp_state->session_key.length) {
+ nt_status = ntlmssp_sign_init(ntlmssp_state);
+ }
+
+ data_blob_free(&encrypted_session_key);
+
+ /* Only one authentication allowed per server state. */
+ ntlmssp_state->expected_state = NTLMSSP_DONE;
+
+ return nt_status;
+}
+
+/**
+ * Create an NTLMSSP state machine
+ *
+ * @param ntlmssp_state NTLMSSP State, allocated by this function
+ */
+
+NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
+{
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("NTLMSSP context");
+
+ *ntlmssp_state = TALLOC_ZERO_P(mem_ctx, NTLMSSP_STATE);
+ if (!*ntlmssp_state) {
+ DEBUG(0,("ntlmssp_server_start: talloc failed!\n"));
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*ntlmssp_state)->role = NTLMSSP_SERVER;
+
+ (*ntlmssp_state)->mem_ctx = mem_ctx;
+ (*ntlmssp_state)->get_challenge = get_challenge;
+ (*ntlmssp_state)->set_challenge = set_challenge;
+ (*ntlmssp_state)->may_set_challenge = may_set_challenge;
+
+ (*ntlmssp_state)->get_global_myname = global_myname;
+ (*ntlmssp_state)->get_domain = lp_workgroup;
+ (*ntlmssp_state)->server_role = ROLE_DOMAIN_MEMBER; /* a good default */
+
+ (*ntlmssp_state)->expected_state = NTLMSSP_NEGOTIATE;
+
+ (*ntlmssp_state)->ref_count = 1;
+
+ (*ntlmssp_state)->neg_flags =
+ NTLMSSP_NEGOTIATE_128 |
+ NTLMSSP_NEGOTIATE_56 |
+ NTLMSSP_NEGOTIATE_VERSION |
+ NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
+ NTLMSSP_NEGOTIATE_NTLM |
+ NTLMSSP_NEGOTIATE_NTLM2 |
+ NTLMSSP_NEGOTIATE_KEY_EXCH |
+ NTLMSSP_NEGOTIATE_SIGN |
+ NTLMSSP_NEGOTIATE_SEAL;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Client side NTLMSSP
+*********************************************************************/
+
+/**
+ * Next state function for the Initial packet
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB. reply.data must be NULL
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or NT_STATUS_OK.
+ */
+
+static NTSTATUS ntlmssp_client_initial(struct ntlmssp_state *ntlmssp_state,
+ DATA_BLOB reply, DATA_BLOB *next_request)
+{
+ if (ntlmssp_state->unicode) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
+ } else {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
+ }
+
+ if (ntlmssp_state->use_ntlmv2) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
+ }
+
+ /* generate the ntlmssp negotiate packet */
+ msrpc_gen(next_request, "CddAA",
+ "NTLMSSP",
+ NTLMSSP_NEGOTIATE,
+ ntlmssp_state->neg_flags,
+ ntlmssp_state->get_domain(),
+ ntlmssp_state->get_global_myname());
+
+ ntlmssp_state->expected_state = NTLMSSP_CHALLENGE;
+
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+/**
+ * Next state function for the Challenge Packet. Generate an auth packet.
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB. reply.data must be NULL
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or NT_STATUS_OK.
+ */
+
+static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state,
+ const DATA_BLOB reply, DATA_BLOB *next_request)
+{
+ uint32 chal_flags, ntlmssp_command, unkn1, unkn2;
+ DATA_BLOB server_domain_blob;
+ DATA_BLOB challenge_blob;
+ DATA_BLOB struct_blob = data_blob_null;
+ char *server_domain;
+ const char *chal_parse_string;
+ const char *auth_gen_string;
+ DATA_BLOB lm_response = data_blob_null;
+ DATA_BLOB nt_response = data_blob_null;
+ DATA_BLOB session_key = data_blob_null;
+ DATA_BLOB encrypted_session_key = data_blob_null;
+ NTSTATUS nt_status = NT_STATUS_OK;
+
+ if (!msrpc_parse(&reply, "CdBd",
+ "NTLMSSP",
+ &ntlmssp_command,
+ &server_domain_blob,
+ &chal_flags)) {
+ DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
+ dump_data(2, reply.data, reply.length);
+
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ data_blob_free(&server_domain_blob);
+
+ DEBUG(3, ("Got challenge flags:\n"));
+ debug_ntlmssp_flags(chal_flags);
+
+ ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, lp_client_lanman_auth());
+
+ if (ntlmssp_state->unicode) {
+ if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
+ chal_parse_string = "CdUdbddB";
+ } else {
+ chal_parse_string = "CdUdbdd";
+ }
+ auth_gen_string = "CdBBUUUBd";
+ } else {
+ if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
+ chal_parse_string = "CdAdbddB";
+ } else {
+ chal_parse_string = "CdAdbdd";
+ }
+
+ auth_gen_string = "CdBBAAABd";
+ }
+
+ DEBUG(3, ("NTLMSSP: Set final flags:\n"));
+ debug_ntlmssp_flags(ntlmssp_state->neg_flags);
+
+ if (!msrpc_parse(&reply, chal_parse_string,
+ "NTLMSSP",
+ &ntlmssp_command,
+ &server_domain,
+ &chal_flags,
+ &challenge_blob, 8,
+ &unkn1, &unkn2,
+ &struct_blob)) {
+ DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));
+ dump_data(2, reply.data, reply.length);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ntlmssp_state->server_domain = talloc_strdup(ntlmssp_state->mem_ctx,
+ server_domain);
+
+ SAFE_FREE(server_domain);
+ if (challenge_blob.length != 8) {
+ data_blob_free(&struct_blob);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!ntlmssp_state->nt_hash || !ntlmssp_state->lm_hash) {
+ uchar zeros[16];
+ /* do nothing - blobs are zero length */
+
+ ZERO_STRUCT(zeros);
+
+ /* session key is all zeros */
+ session_key = data_blob_talloc(ntlmssp_state->mem_ctx, zeros, 16);
+
+ /* not doing NLTM2 without a password */
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
+ } else if (ntlmssp_state->use_ntlmv2) {
+
+ if (!struct_blob.length) {
+ /* be lazy, match win2k - we can't do NTLMv2 without it */
+ DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* TODO: if the remote server is standalone, then we should replace 'domain'
+ with the server name as supplied above */
+
+ if (!SMBNTLMv2encrypt_hash(ntlmssp_state->user,
+ ntlmssp_state->domain,
+ ntlmssp_state->nt_hash, &challenge_blob,
+ &struct_blob,
+ &lm_response, &nt_response, &session_key)) {
+ data_blob_free(&challenge_blob);
+ data_blob_free(&struct_blob);
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ struct MD5Context md5_session_nonce_ctx;
+ uchar session_nonce[16];
+ uchar session_nonce_hash[16];
+ uchar user_session_key[16];
+
+ lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
+ generate_random_buffer(lm_response.data, 8);
+ memset(lm_response.data+8, 0, 16);
+
+ memcpy(session_nonce, challenge_blob.data, 8);
+ memcpy(&session_nonce[8], lm_response.data, 8);
+
+ MD5Init(&md5_session_nonce_ctx);
+ MD5Update(&md5_session_nonce_ctx, challenge_blob.data, 8);
+ MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
+ MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
+
+ DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
+ DEBUG(5, ("challenge is: \n"));
+ dump_data(5, session_nonce_hash, 8);
+
+ nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
+ SMBNTencrypt_hash(ntlmssp_state->nt_hash,
+ session_nonce_hash,
+ nt_response.data);
+
+ session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
+
+ SMBsesskeygen_ntv1(ntlmssp_state->nt_hash, NULL, user_session_key);
+ hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
+ dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
+ } else {
+ /* lanman auth is insecure, it may be disabled */
+ if (lp_client_lanman_auth()) {
+ lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
+ SMBencrypt_hash(ntlmssp_state->lm_hash,challenge_blob.data,
+ lm_response.data);
+ }
+
+ nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
+ SMBNTencrypt_hash(ntlmssp_state->nt_hash,challenge_blob.data,
+ nt_response.data);
+
+ session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
+ if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
+ && lp_client_lanman_auth()) {
+ SMBsesskeygen_lm_sess_key(ntlmssp_state->lm_hash, lm_response.data,
+ session_key.data);
+ dump_data_pw("LM session key\n", session_key.data, session_key.length);
+ } else {
+ SMBsesskeygen_ntv1(ntlmssp_state->nt_hash, NULL, session_key.data);
+ dump_data_pw("NT session key:\n", session_key.data, session_key.length);
+ }
+ }
+ data_blob_free(&struct_blob);
+
+ /* Key exchange encryptes a new client-generated session key with
+ the password-derived key */
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+ /* Make up a new session key */
+ uint8 client_session_key[16];
+ generate_random_buffer(client_session_key, sizeof(client_session_key));
+
+ /* Encrypt the new session key with the old one */
+ encrypted_session_key = data_blob(client_session_key, sizeof(client_session_key));
+ dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length);
+ SamOEMhash(encrypted_session_key.data, session_key.data, encrypted_session_key.length);
+ dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);
+
+ /* Mark the new session key as the 'real' session key */
+ data_blob_free(&session_key);
+ session_key = data_blob_talloc(ntlmssp_state->mem_ctx, client_session_key, sizeof(client_session_key));
+ }
+
+ /* this generates the actual auth packet */
+ if (!msrpc_gen(next_request, auth_gen_string,
+ "NTLMSSP",
+ NTLMSSP_AUTH,
+ lm_response.data, lm_response.length,
+ nt_response.data, nt_response.length,
+ ntlmssp_state->domain,
+ ntlmssp_state->user,
+ ntlmssp_state->get_global_myname(),
+ encrypted_session_key.data, encrypted_session_key.length,
+ ntlmssp_state->neg_flags)) {
+
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ data_blob_free(&encrypted_session_key);
+
+ data_blob_free(&ntlmssp_state->chal);
+
+ ntlmssp_state->session_key = session_key;
+
+ ntlmssp_state->chal = challenge_blob;
+ ntlmssp_state->lm_resp = lm_response;
+ ntlmssp_state->nt_resp = nt_response;
+
+ ntlmssp_state->expected_state = NTLMSSP_DONE;
+
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_sign_init(ntlmssp_state))) {
+ DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", nt_errstr(nt_status)));
+ }
+
+ return nt_status;
+}
+
+NTSTATUS ntlmssp_client_start(NTLMSSP_STATE **ntlmssp_state)
+{
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("NTLMSSP Client context");
+
+ *ntlmssp_state = TALLOC_ZERO_P(mem_ctx, NTLMSSP_STATE);
+ if (!*ntlmssp_state) {
+ DEBUG(0,("ntlmssp_client_start: talloc failed!\n"));
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*ntlmssp_state)->role = NTLMSSP_CLIENT;
+
+ (*ntlmssp_state)->mem_ctx = mem_ctx;
+
+ (*ntlmssp_state)->get_global_myname = global_myname;
+ (*ntlmssp_state)->get_domain = lp_workgroup;
+
+ (*ntlmssp_state)->unicode = True;
+
+ (*ntlmssp_state)->use_ntlmv2 = lp_client_ntlmv2_auth();
+
+ (*ntlmssp_state)->expected_state = NTLMSSP_INITIAL;
+
+ (*ntlmssp_state)->ref_count = 1;
+
+ (*ntlmssp_state)->neg_flags =
+ NTLMSSP_NEGOTIATE_128 |
+ NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
+ NTLMSSP_NEGOTIATE_NTLM |
+ NTLMSSP_NEGOTIATE_NTLM2 |
+ NTLMSSP_NEGOTIATE_KEY_EXCH |
+ NTLMSSP_REQUEST_TARGET;
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/libsmb/ntlmssp_parse.c b/source3/libsmb/ntlmssp_parse.c
new file mode 100644
index 0000000000..70377cba7d
--- /dev/null
+++ b/source3/libsmb/ntlmssp_parse.c
@@ -0,0 +1,384 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple kerberos5/SPNEGO routines
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
+ Copyright (C) Andrew Bartlett 2002-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*
+ this is a tiny msrpc packet generator. I am only using this to
+ avoid tying this code to a particular varient of our rpc code. This
+ generator is not general enough for all our rpc needs, its just
+ enough for the spnego/ntlmssp code
+
+ format specifiers are:
+
+ U = unicode string (input is unix string)
+ a = address (input is char *unix_string)
+ (1 byte type, 1 byte length, unicode/ASCII string, all inline)
+ A = ASCII string (input is unix string)
+ B = data blob (pointer + length)
+ b = data blob in header (pointer + length)
+ D
+ d = word (4 bytes)
+ C = constant ascii string
+ */
+bool msrpc_gen(DATA_BLOB *blob,
+ const char *format, ...)
+{
+ int i, n;
+ va_list ap;
+ char *s;
+ uint8 *b;
+ int head_size=0, data_size=0;
+ int head_ofs, data_ofs;
+
+ /* first scan the format to work out the header and body size */
+ va_start(ap, format);
+ for (i=0; format[i]; i++) {
+ switch (format[i]) {
+ case 'U':
+ s = va_arg(ap, char *);
+ head_size += 8;
+ data_size += str_charnum(s) * 2;
+ break;
+ case 'A':
+ s = va_arg(ap, char *);
+ head_size += 8;
+ data_size += str_ascii_charnum(s);
+ break;
+ case 'a':
+ n = va_arg(ap, int);
+ s = va_arg(ap, char *);
+ data_size += (str_charnum(s) * 2) + 4;
+ break;
+ case 'B':
+ b = va_arg(ap, uint8 *);
+ head_size += 8;
+ data_size += va_arg(ap, int);
+ break;
+ case 'b':
+ b = va_arg(ap, uint8 *);
+ head_size += va_arg(ap, int);
+ break;
+ case 'd':
+ n = va_arg(ap, int);
+ head_size += 4;
+ break;
+ case 'C':
+ s = va_arg(ap, char *);
+ head_size += str_charnum(s) + 1;
+ break;
+ }
+ }
+ va_end(ap);
+
+ /* allocate the space, then scan the format
+ * again to fill in the values */
+
+ *blob = data_blob(NULL, head_size + data_size);
+
+ head_ofs = 0;
+ data_ofs = head_size;
+
+ va_start(ap, format);
+ for (i=0; format[i]; i++) {
+ switch (format[i]) {
+ case 'U':
+ s = va_arg(ap, char *);
+ n = str_charnum(s);
+ SSVAL(blob->data, head_ofs, n*2); head_ofs += 2;
+ SSVAL(blob->data, head_ofs, n*2); head_ofs += 2;
+ SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
+ push_string(NULL, blob->data+data_ofs,
+ s, n*2, STR_UNICODE|STR_NOALIGN);
+ data_ofs += n*2;
+ break;
+ case 'A':
+ s = va_arg(ap, char *);
+ n = str_ascii_charnum(s);
+ SSVAL(blob->data, head_ofs, n); head_ofs += 2;
+ SSVAL(blob->data, head_ofs, n); head_ofs += 2;
+ SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
+ push_string(NULL, blob->data+data_ofs,
+ s, n, STR_ASCII|STR_NOALIGN);
+ data_ofs += n;
+ break;
+ case 'a':
+ n = va_arg(ap, int);
+ SSVAL(blob->data, data_ofs, n); data_ofs += 2;
+ s = va_arg(ap, char *);
+ n = str_charnum(s);
+ SSVAL(blob->data, data_ofs, n*2); data_ofs += 2;
+ if (0 < n) {
+ push_string(NULL, blob->data+data_ofs, s, n*2,
+ STR_UNICODE|STR_NOALIGN);
+ }
+ data_ofs += n*2;
+ break;
+
+ case 'B':
+ b = va_arg(ap, uint8 *);
+ n = va_arg(ap, int);
+ SSVAL(blob->data, head_ofs, n); head_ofs += 2;
+ SSVAL(blob->data, head_ofs, n); head_ofs += 2;
+ SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
+ if (n && b) /* don't follow null pointers... */
+ memcpy(blob->data+data_ofs, b, n);
+ data_ofs += n;
+ break;
+ case 'd':
+ n = va_arg(ap, int);
+ SIVAL(blob->data, head_ofs, n); head_ofs += 4;
+ break;
+ case 'b':
+ b = va_arg(ap, uint8 *);
+ n = va_arg(ap, int);
+ memcpy(blob->data + head_ofs, b, n);
+ head_ofs += n;
+ break;
+ case 'C':
+ s = va_arg(ap, char *);
+ n = str_charnum(s) + 1;
+ head_ofs += push_string(NULL, blob->data+head_ofs, s, n,
+ STR_ASCII|STR_TERMINATE);
+ break;
+ }
+ }
+ va_end(ap);
+
+ return true;
+}
+
+
+/* a helpful macro to avoid running over the end of our blob */
+#define NEED_DATA(amount) \
+if ((head_ofs + amount) > blob->length) { \
+ va_end(ap); \
+ return False; \
+}
+
+/*
+ this is a tiny msrpc packet parser. This the the partner of msrpc_gen
+
+ format specifiers are:
+
+ U = unicode string (output is unix string)
+ A = ascii string
+ B = data blob
+ b = data blob in header
+ d = word (4 bytes)
+ C = constant ascii string
+ */
+
+bool msrpc_parse(const DATA_BLOB *blob,
+ const char *format, ...)
+{
+ int i;
+ va_list ap;
+ char **ps, *s;
+ DATA_BLOB *b;
+ size_t head_ofs = 0;
+ uint16 len1, len2;
+ uint32 ptr;
+ uint32 *v;
+
+ va_start(ap, format);
+ for (i=0; format[i]; i++) {
+ switch (format[i]) {
+ case 'U':
+ NEED_DATA(8);
+ len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
+
+ ps = va_arg(ap, char **);
+ if (len1 == 0 && len2 == 0) {
+ *ps = smb_xstrdup("");
+ } else {
+ /* make sure its in the right format
+ * be strict */
+ if ((len1 != len2) || (ptr + len1 < ptr) ||
+ (ptr + len1 < len1) ||
+ (ptr + len1 > blob->length)) {
+ va_end(ap);
+ return false;
+ }
+ if (len1 & 1) {
+ /* if odd length and unicode */
+ va_end(ap);
+ return false;
+ }
+ if (blob->data + ptr <
+ (uint8 *)(unsigned long)ptr ||
+ blob->data + ptr < blob->data) {
+ va_end(ap);
+ return false;
+ }
+
+ if (0 < len1) {
+ char *p = NULL;
+ pull_string_talloc(talloc_tos(),
+ NULL,
+ 0,
+ &p,
+ blob->data + ptr,
+ len1,
+ STR_UNICODE|STR_NOALIGN);
+ if (p) {
+ (*ps) = smb_xstrdup(p);
+ TALLOC_FREE(p);
+ } else {
+ (*ps) = smb_xstrdup("");
+ }
+ } else {
+ (*ps) = smb_xstrdup("");
+ }
+ }
+ break;
+ case 'A':
+ NEED_DATA(8);
+ len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
+
+ ps = va_arg(ap, char **);
+ /* make sure its in the right format - be strict */
+ if (len1 == 0 && len2 == 0) {
+ *ps = smb_xstrdup("");
+ } else {
+ if ((len1 != len2) || (ptr + len1 < ptr) ||
+ (ptr + len1 < len1) ||
+ (ptr + len1 > blob->length)) {
+ va_end(ap);
+ return false;
+ }
+
+ if (blob->data + ptr <
+ (uint8 *)(unsigned long)ptr ||
+ blob->data + ptr < blob->data) {
+ va_end(ap);
+ return false;
+ }
+
+ if (0 < len1) {
+ char *p = NULL;
+ pull_string_talloc(talloc_tos(),
+ NULL,
+ 0,
+ &p,
+ blob->data + ptr,
+ len1,
+ STR_ASCII|STR_NOALIGN);
+ if (p) {
+ (*ps) = smb_xstrdup(p);
+ TALLOC_FREE(p);
+ } else {
+ (*ps) = smb_xstrdup("");
+ }
+ } else {
+ (*ps) = smb_xstrdup("");
+ }
+ }
+ break;
+ case 'B':
+ NEED_DATA(8);
+ len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
+
+ b = (DATA_BLOB *)va_arg(ap, void *);
+ if (len1 == 0 && len2 == 0) {
+ *b = data_blob_null;
+ } else {
+ /* make sure its in the right format
+ * be strict */
+ if ((len1 != len2) || (ptr + len1 < ptr) ||
+ (ptr + len1 < len1) ||
+ (ptr + len1 > blob->length)) {
+ va_end(ap);
+ return false;
+ }
+
+ if (blob->data + ptr <
+ (uint8 *)(unsigned long)ptr ||
+ blob->data + ptr < blob->data) {
+ va_end(ap);
+ return false;
+ }
+
+ *b = data_blob(blob->data + ptr, len1);
+ }
+ break;
+ case 'b':
+ b = (DATA_BLOB *)va_arg(ap, void *);
+ len1 = va_arg(ap, unsigned);
+ /* make sure its in the right format - be strict */
+ NEED_DATA(len1);
+ if (blob->data + head_ofs < (uint8 *)head_ofs ||
+ blob->data + head_ofs < blob->data) {
+ va_end(ap);
+ return false;
+ }
+
+ *b = data_blob(blob->data + head_ofs, len1);
+ head_ofs += len1;
+ break;
+ case 'd':
+ v = va_arg(ap, uint32 *);
+ NEED_DATA(4);
+ *v = IVAL(blob->data, head_ofs); head_ofs += 4;
+ break;
+ case 'C':
+ s = va_arg(ap, char *);
+
+ if (blob->data + head_ofs < (uint8 *)head_ofs ||
+ blob->data + head_ofs < blob->data) {
+ va_end(ap);
+ return false;
+ }
+
+ {
+ char *p = NULL;
+ size_t ret = pull_string_talloc(talloc_tos(),
+ NULL,
+ 0,
+ &p,
+ blob->data+head_ofs,
+ blob->length - head_ofs,
+ STR_ASCII|STR_TERMINATE);
+ if (ret == (size_t)-1 || p == NULL) {
+ va_end(ap);
+ return false;
+ }
+ head_ofs += ret;
+ if (strcmp(s, p) != 0) {
+ TALLOC_FREE(p);
+ va_end(ap);
+ return false;
+ }
+ TALLOC_FREE(p);
+ }
+ break;
+ }
+ }
+ va_end(ap);
+
+ return True;
+}
diff --git a/source3/libsmb/ntlmssp_sign.c b/source3/libsmb/ntlmssp_sign.c
new file mode 100644
index 0000000000..8413c8066b
--- /dev/null
+++ b/source3/libsmb/ntlmssp_sign.c
@@ -0,0 +1,468 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Version 3.0
+ * NTLMSSP Signing routines
+ * Copyright (C) Andrew Bartlett 2003-2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#define CLI_SIGN "session key to client-to-server signing key magic constant"
+#define CLI_SEAL "session key to client-to-server sealing key magic constant"
+#define SRV_SIGN "session key to server-to-client signing key magic constant"
+#define SRV_SEAL "session key to server-to-client sealing key magic constant"
+
+/**
+ * Some notes on then NTLM2 code:
+ *
+ * NTLM2 is a AEAD system. This means that the data encrypted is not
+ * all the data that is signed. In DCE-RPC case, the headers of the
+ * DCE-RPC packets are also signed. This prevents some of the
+ * fun-and-games one might have by changing them.
+ *
+ */
+
+static void calc_ntlmv2_key(unsigned char subkey[16],
+ DATA_BLOB session_key,
+ const char *constant)
+{
+ struct MD5Context ctx3;
+ MD5Init(&ctx3);
+ MD5Update(&ctx3, session_key.data, session_key.length);
+ MD5Update(&ctx3, (const unsigned char *)constant, strlen(constant)+1);
+ MD5Final(subkey, &ctx3);
+}
+
+enum ntlmssp_direction {
+ NTLMSSP_SEND,
+ NTLMSSP_RECEIVE
+};
+
+static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_STATE *ntlmssp_state,
+ const uchar *data, size_t length,
+ const uchar *whole_pdu, size_t pdu_length,
+ enum ntlmssp_direction direction,
+ DATA_BLOB *sig,
+ bool encrypt_sig)
+{
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ HMACMD5Context ctx;
+ uchar seq_num[4];
+ uchar digest[16];
+
+ *sig = data_blob(NULL, NTLMSSP_SIG_SIZE);
+ if (!sig->data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ switch (direction) {
+ case NTLMSSP_SEND:
+ DEBUG(100,("ntlmssp_make_packet_signature: SEND seq = %u, len = %u, pdu_len = %u\n",
+ ntlmssp_state->ntlm2_send_seq_num,
+ (unsigned int)length,
+ (unsigned int)pdu_length));
+
+ SIVAL(seq_num, 0, ntlmssp_state->ntlm2_send_seq_num);
+ ntlmssp_state->ntlm2_send_seq_num++;
+ hmac_md5_init_limK_to_64(ntlmssp_state->send_sign_key, 16, &ctx);
+ break;
+ case NTLMSSP_RECEIVE:
+
+ DEBUG(100,("ntlmssp_make_packet_signature: RECV seq = %u, len = %u, pdu_len = %u\n",
+ ntlmssp_state->ntlm2_recv_seq_num,
+ (unsigned int)length,
+ (unsigned int)pdu_length));
+
+ SIVAL(seq_num, 0, ntlmssp_state->ntlm2_recv_seq_num);
+ ntlmssp_state->ntlm2_recv_seq_num++;
+ hmac_md5_init_limK_to_64(ntlmssp_state->recv_sign_key, 16, &ctx);
+ break;
+ }
+
+ dump_data_pw("pdu data ", whole_pdu, pdu_length);
+
+ hmac_md5_update(seq_num, 4, &ctx);
+ hmac_md5_update(whole_pdu, pdu_length, &ctx);
+ hmac_md5_final(digest, &ctx);
+
+ if (encrypt_sig && (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
+ switch (direction) {
+ case NTLMSSP_SEND:
+ smb_arc4_crypt(ntlmssp_state->send_seal_arc4_state, digest, 8);
+ break;
+ case NTLMSSP_RECEIVE:
+ smb_arc4_crypt(ntlmssp_state->recv_seal_arc4_state, digest, 8);
+ break;
+ }
+ }
+
+ SIVAL(sig->data, 0, NTLMSSP_SIGN_VERSION);
+ memcpy(sig->data + 4, digest, 8);
+ memcpy(sig->data + 12, seq_num, 4);
+
+ dump_data_pw("ntlmssp v2 sig ", sig->data, sig->length);
+
+ } else {
+ uint32 crc;
+ crc = crc32_calc_buffer((const char *)data, length);
+ if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmv1_seq_num)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ntlmssp_state->ntlmv1_seq_num++;
+
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmv1_arc4_state,
+ sizeof(ntlmssp_state->ntlmv1_arc4_state));
+ smb_arc4_crypt(ntlmssp_state->ntlmv1_arc4_state, sig->data+4, sig->length-4);
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS ntlmssp_sign_packet(NTLMSSP_STATE *ntlmssp_state,
+ const uchar *data, size_t length,
+ const uchar *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig)
+{
+ NTSTATUS nt_status;
+
+ if (!(ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN)) {
+ DEBUG(3, ("NTLMSSP Signing not negotiated - cannot sign packet!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!ntlmssp_state->session_key.length) {
+ DEBUG(3, ("NO session key, cannot check sign packet\n"));
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ nt_status = ntlmssp_make_packet_signature(ntlmssp_state,
+ data, length,
+ whole_pdu, pdu_length,
+ NTLMSSP_SEND, sig, True);
+
+ return nt_status;
+}
+
+/**
+ * Check the signature of an incoming packet
+ * @note caller *must* check that the signature is the size it expects
+ *
+ */
+
+NTSTATUS ntlmssp_check_packet(NTLMSSP_STATE *ntlmssp_state,
+ const uchar *data, size_t length,
+ const uchar *whole_pdu, size_t pdu_length,
+ const DATA_BLOB *sig)
+{
+ DATA_BLOB local_sig;
+ NTSTATUS nt_status;
+
+ if (!ntlmssp_state->session_key.length) {
+ DEBUG(3, ("NO session key, cannot check packet signature\n"));
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ if (sig->length < 8) {
+ DEBUG(0, ("NTLMSSP packet check failed due to short signature (%lu bytes)!\n",
+ (unsigned long)sig->length));
+ }
+
+ nt_status = ntlmssp_make_packet_signature(ntlmssp_state,
+ data, length,
+ whole_pdu, pdu_length,
+ NTLMSSP_RECEIVE, &local_sig, True);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("NTLMSSP packet check failed with %s\n", nt_errstr(nt_status)));
+ data_blob_free(&local_sig);
+ return nt_status;
+ }
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ if (local_sig.length != sig->length ||
+ memcmp(local_sig.data, sig->data, sig->length) != 0) {
+ DEBUG(5, ("BAD SIG NTLM2: wanted signature of\n"));
+ dump_data(5, local_sig.data, local_sig.length);
+
+ DEBUG(5, ("BAD SIG: got signature of\n"));
+ dump_data(5, sig->data, sig->length);
+
+ DEBUG(0, ("NTLMSSP NTLM2 packet check failed due to invalid signature!\n"));
+ data_blob_free(&local_sig);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ } else {
+ if (local_sig.length != sig->length ||
+ memcmp(local_sig.data + 8, sig->data + 8, sig->length - 8) != 0) {
+ DEBUG(5, ("BAD SIG NTLM1: wanted signature of\n"));
+ dump_data(5, local_sig.data, local_sig.length);
+
+ DEBUG(5, ("BAD SIG: got signature of\n"));
+ dump_data(5, sig->data, sig->length);
+
+ DEBUG(0, ("NTLMSSP NTLM1 packet check failed due to invalid signature!\n"));
+ data_blob_free(&local_sig);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+ dump_data_pw("checked ntlmssp signature\n", sig->data, sig->length);
+ DEBUG(10,("ntlmssp_check_packet: NTLMSSP signature OK !\n"));
+
+ data_blob_free(&local_sig);
+ return NT_STATUS_OK;
+}
+
+/**
+ * Seal data with the NTLMSSP algorithm
+ *
+ */
+
+NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state,
+ uchar *data, size_t length,
+ uchar *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig)
+{
+ if (!(ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL)) {
+ DEBUG(3, ("NTLMSSP Sealing not negotiated - cannot seal packet!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!ntlmssp_state->session_key.length) {
+ DEBUG(3, ("NO session key, cannot seal packet\n"));
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ DEBUG(10,("ntlmssp_seal_data: seal\n"));
+ dump_data_pw("ntlmssp clear data\n", data, length);
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ /* The order of these two operations matters - we must first seal the packet,
+ then seal the sequence number - this is becouse the send_seal_hash is not
+ constant, but is is rather updated with each iteration */
+ NTSTATUS nt_status = ntlmssp_make_packet_signature(ntlmssp_state,
+ data, length,
+ whole_pdu, pdu_length,
+ NTLMSSP_SEND, sig, False);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ smb_arc4_crypt(ntlmssp_state->send_seal_arc4_state, data, length);
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+ smb_arc4_crypt(ntlmssp_state->send_seal_arc4_state, sig->data+4, 8);
+ }
+ } else {
+ uint32 crc;
+ crc = crc32_calc_buffer((const char *)data, length);
+ if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmv1_seq_num)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* The order of these two operations matters - we must first seal the packet,
+ then seal the sequence number - this is becouse the ntlmv1_arc4_state is not
+ constant, but is is rather updated with each iteration */
+
+ dump_data_pw("ntlmv1 arc4 state:\n", ntlmssp_state->ntlmv1_arc4_state,
+ sizeof(ntlmssp_state->ntlmv1_arc4_state));
+ smb_arc4_crypt(ntlmssp_state->ntlmv1_arc4_state, data, length);
+
+ dump_data_pw("ntlmv1 arc4 state:\n", ntlmssp_state->ntlmv1_arc4_state,
+ sizeof(ntlmssp_state->ntlmv1_arc4_state));
+
+ smb_arc4_crypt(ntlmssp_state->ntlmv1_arc4_state, sig->data+4, sig->length-4);
+
+ ntlmssp_state->ntlmv1_seq_num++;
+ }
+ dump_data_pw("ntlmssp signature\n", sig->data, sig->length);
+ dump_data_pw("ntlmssp sealed data\n", data, length);
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Unseal data with the NTLMSSP algorithm
+ *
+ */
+
+NTSTATUS ntlmssp_unseal_packet(NTLMSSP_STATE *ntlmssp_state,
+ uchar *data, size_t length,
+ uchar *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig)
+{
+ if (!ntlmssp_state->session_key.length) {
+ DEBUG(3, ("NO session key, cannot unseal packet\n"));
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ DEBUG(10,("ntlmssp_unseal_packet: seal\n"));
+ dump_data_pw("ntlmssp sealed data\n", data, length);
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ /* First unseal the data. */
+ smb_arc4_crypt(ntlmssp_state->recv_seal_arc4_state, data, length);
+ dump_data_pw("ntlmv2 clear data\n", data, length);
+ } else {
+ smb_arc4_crypt(ntlmssp_state->ntlmv1_arc4_state, data, length);
+ dump_data_pw("ntlmv1 clear data\n", data, length);
+ }
+ return ntlmssp_check_packet(ntlmssp_state, data, length, whole_pdu, pdu_length, sig);
+}
+
+/**
+ Initialise the state for NTLMSSP signing.
+*/
+NTSTATUS ntlmssp_sign_init(NTLMSSP_STATE *ntlmssp_state)
+{
+ unsigned char p24[24];
+ TALLOC_CTX *mem_ctx;
+ ZERO_STRUCT(p24);
+
+ mem_ctx = talloc_init("weak_keys");
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(3, ("NTLMSSP Sign/Seal - Initialising with flags:\n"));
+ debug_ntlmssp_flags(ntlmssp_state->neg_flags);
+
+ if (ntlmssp_state->session_key.length < 8) {
+ TALLOC_FREE(mem_ctx);
+ DEBUG(3, ("NO session key, cannot intialise signing\n"));
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ DATA_BLOB weak_session_key = ntlmssp_state->session_key;
+ const char *send_sign_const;
+ const char *send_seal_const;
+ const char *recv_sign_const;
+ const char *recv_seal_const;
+
+ switch (ntlmssp_state->role) {
+ case NTLMSSP_CLIENT:
+ send_sign_const = CLI_SIGN;
+ send_seal_const = CLI_SEAL;
+ recv_sign_const = SRV_SIGN;
+ recv_seal_const = SRV_SEAL;
+ break;
+ case NTLMSSP_SERVER:
+ send_sign_const = SRV_SIGN;
+ send_seal_const = SRV_SEAL;
+ recv_sign_const = CLI_SIGN;
+ recv_seal_const = CLI_SEAL;
+ break;
+ default:
+ TALLOC_FREE(mem_ctx);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /**
+ Weaken NTLMSSP keys to cope with down-level clients, servers and export restrictions.
+ We probably should have some parameters to control this, once we get NTLM2 working.
+ */
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_128) {
+ ;
+ } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) {
+ weak_session_key.length = 7;
+ } else { /* forty bits */
+ weak_session_key.length = 5;
+ }
+
+ dump_data_pw("NTLMSSP weakend master key:\n",
+ weak_session_key.data,
+ weak_session_key.length);
+
+ /* SEND: sign key */
+ calc_ntlmv2_key(ntlmssp_state->send_sign_key,
+ ntlmssp_state->session_key, send_sign_const);
+ dump_data_pw("NTLMSSP send sign key:\n",
+ ntlmssp_state->send_sign_key, 16);
+
+ /* SEND: seal ARCFOUR pad */
+ calc_ntlmv2_key(ntlmssp_state->send_seal_key,
+ weak_session_key, send_seal_const);
+ dump_data_pw("NTLMSSP send seal key:\n",
+ ntlmssp_state->send_seal_key, 16);
+
+ smb_arc4_init(ntlmssp_state->send_seal_arc4_state,
+ ntlmssp_state->send_seal_key, 16);
+
+ dump_data_pw("NTLMSSP send seal arc4 state:\n",
+ ntlmssp_state->send_seal_arc4_state,
+ sizeof(ntlmssp_state->send_seal_arc4_state));
+
+ /* RECV: sign key */
+ calc_ntlmv2_key(ntlmssp_state->recv_sign_key,
+ ntlmssp_state->session_key, recv_sign_const);
+ dump_data_pw("NTLMSSP recv send sign key:\n",
+ ntlmssp_state->recv_sign_key, 16);
+
+ /* RECV: seal ARCFOUR pad */
+ calc_ntlmv2_key(ntlmssp_state->recv_seal_key,
+ weak_session_key, recv_seal_const);
+
+ dump_data_pw("NTLMSSP recv seal key:\n",
+ ntlmssp_state->recv_seal_key, 16);
+
+ smb_arc4_init(ntlmssp_state->recv_seal_arc4_state,
+ ntlmssp_state->recv_seal_key, 16);
+
+ dump_data_pw("NTLMSSP recv seal arc4 state:\n",
+ ntlmssp_state->recv_seal_arc4_state,
+ sizeof(ntlmssp_state->recv_seal_arc4_state));
+
+ ntlmssp_state->ntlm2_send_seq_num = 0;
+ ntlmssp_state->ntlm2_recv_seq_num = 0;
+
+
+ } else {
+#if 0
+ /* Hmmm. Shouldn't we also weaken keys for ntlmv1 ? JRA. */
+
+ DATA_BLOB weak_session_key = ntlmssp_state->session_key;
+ /**
+ Weaken NTLMSSP keys to cope with down-level clients, servers and export restrictions.
+ We probably should have some parameters to control this, once we get NTLM2 working.
+ */
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_128) {
+ ;
+ } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) {
+ weak_session_key.length = 6;
+ } else { /* forty bits */
+ weak_session_key.length = 5;
+ }
+ dump_data_pw("NTLMSSP weakend master key:\n",
+ weak_session_key.data,
+ weak_session_key.length);
+#endif
+
+ DATA_BLOB weak_session_key = ntlmssp_weaken_keys(ntlmssp_state, mem_ctx);
+
+ DEBUG(5, ("NTLMSSP Sign/Seal - using NTLM1\n"));
+
+ smb_arc4_init(ntlmssp_state->ntlmv1_arc4_state,
+ weak_session_key.data, weak_session_key.length);
+
+ dump_data_pw("NTLMv1 arc4 state:\n", ntlmssp_state->ntlmv1_arc4_state,
+ sizeof(ntlmssp_state->ntlmv1_arc4_state));
+
+ ntlmssp_state->ntlmv1_seq_num = 0;
+ }
+
+ TALLOC_FREE(mem_ctx);
+ return NT_STATUS_OK;
+}
diff --git a/source3/libsmb/passchange.c b/source3/libsmb/passchange.c
new file mode 100644
index 0000000000..4c76234e0c
--- /dev/null
+++ b/source3/libsmb/passchange.c
@@ -0,0 +1,257 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client password change routine
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*************************************************************
+ Change a password on a remote machine using IPC calls.
+*************************************************************/
+
+NTSTATUS remote_password_change(const char *remote_machine, const char *user_name,
+ const char *old_passwd, const char *new_passwd,
+ char **err_str)
+{
+ struct nmb_name calling, called;
+ struct cli_state *cli;
+ struct rpc_pipe_client *pipe_hnd;
+ struct sockaddr_storage ss;
+
+ NTSTATUS result;
+ bool pass_must_change = False;
+
+ *err_str = NULL;
+
+ if(!resolve_name( remote_machine, &ss, 0x20)) {
+ asprintf(err_str, "Unable to find an IP address for machine "
+ "%s.\n", remote_machine);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ cli = cli_initialise();
+ if (!cli) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result = cli_connect(cli, remote_machine, &ss);
+ if (!NT_STATUS_IS_OK(result)) {
+ asprintf(err_str, "Unable to connect to SMB server on "
+ "machine %s. Error was : %s.\n",
+ remote_machine, nt_errstr(result));
+ cli_shutdown(cli);
+ return result;
+ }
+
+ make_nmb_name(&calling, global_myname() , 0x0);
+ make_nmb_name(&called , remote_machine, 0x20);
+
+ if (!cli_session_request(cli, &calling, &called)) {
+ asprintf(err_str, "machine %s rejected the session setup. "
+ "Error was : %s.\n",
+ remote_machine, cli_errstr(cli) );
+ result = cli_nt_error(cli);
+ cli_shutdown(cli);
+ return result;
+ }
+
+ cli->protocol = PROTOCOL_NT1;
+
+ if (!cli_negprot(cli)) {
+ asprintf(err_str, "machine %s rejected the negotiate "
+ "protocol. Error was : %s.\n",
+ remote_machine, cli_errstr(cli) );
+ result = cli_nt_error(cli);
+ cli_shutdown(cli);
+ return result;
+ }
+
+ /* Given things like SMB signing, restrict anonymous and the like,
+ try an authenticated connection first */
+ result = cli_session_setup(cli, user_name,
+ old_passwd, strlen(old_passwd)+1,
+ old_passwd, strlen(old_passwd)+1, "");
+
+ if (!NT_STATUS_IS_OK(result)) {
+
+ /* Password must change or Password expired are the only valid
+ * error conditions here from where we can proceed, the rest like
+ * account locked out or logon failure will lead to errors later
+ * anyway */
+
+ if (!NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) &&
+ !NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED)) {
+ asprintf(err_str, "Could not connect to machine %s: "
+ "%s\n", remote_machine, cli_errstr(cli));
+ cli_shutdown(cli);
+ return result;
+ }
+
+ pass_must_change = True;
+
+ /*
+ * We should connect as the anonymous user here, in case
+ * the server has "must change password" checked...
+ * Thanks to <Nicholas.S.Jenkins@cdc.com> for this fix.
+ */
+
+ result = cli_session_setup(cli, "", "", 0, "", 0, "");
+
+ if (!NT_STATUS_IS_OK(result)) {
+ asprintf(err_str, "machine %s rejected the session "
+ "setup. Error was : %s.\n",
+ remote_machine, cli_errstr(cli) );
+ cli_shutdown(cli);
+ return result;
+ }
+
+ cli_init_creds(cli, "", "", NULL);
+ } else {
+ cli_init_creds(cli, user_name, "", old_passwd);
+ }
+
+ if (!cli_send_tconX(cli, "IPC$", "IPC", "", 1)) {
+ asprintf(err_str, "machine %s rejected the tconX on the IPC$ "
+ "share. Error was : %s.\n",
+ remote_machine, cli_errstr(cli) );
+ result = cli_nt_error(cli);
+ cli_shutdown(cli);
+ return result;
+ }
+
+ /* Try not to give the password away too easily */
+
+ if (!pass_must_change) {
+ result = cli_rpc_pipe_open_ntlmssp(cli,
+ &ndr_table_samr.syntax_id,
+ PIPE_AUTH_LEVEL_PRIVACY,
+ "", /* what domain... ? */
+ user_name,
+ old_passwd,
+ &pipe_hnd);
+ } else {
+ /*
+ * If the user password must be changed the ntlmssp bind will
+ * fail the same way as the session setup above did. The
+ * difference ist that with a pipe bind we don't get a good
+ * error message, the result will be that the rpc call below
+ * will just fail. So we do it anonymously, there's no other
+ * way.
+ */
+ result = cli_rpc_pipe_open_noauth(
+ cli, &ndr_table_samr.syntax_id, &pipe_hnd);
+ }
+
+ if (!NT_STATUS_IS_OK(result)) {
+ if (lp_client_lanman_auth()) {
+ /* Use the old RAP method. */
+ if (!cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) {
+ asprintf(err_str, "machine %s rejected the "
+ "password change: Error was : %s.\n",
+ remote_machine, cli_errstr(cli) );
+ result = cli_nt_error(cli);
+ cli_shutdown(cli);
+ return result;
+ }
+ } else {
+ asprintf(err_str, "SAMR connection to machine %s "
+ "failed. Error was %s, but LANMAN password "
+ "changed are disabled\n",
+ nt_errstr(result), remote_machine);
+ result = cli_nt_error(cli);
+ cli_shutdown(cli);
+ return result;
+ }
+ }
+
+ result = rpccli_samr_chgpasswd_user2(pipe_hnd, talloc_tos(),
+ user_name, new_passwd, old_passwd);
+ if (NT_STATUS_IS_OK(result)) {
+ /* Great - it all worked! */
+ cli_shutdown(cli);
+ return NT_STATUS_OK;
+
+ } else if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)
+ || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) {
+ /* it failed, but for reasons such as wrong password, too short etc ... */
+
+ asprintf(err_str, "machine %s rejected the password change: "
+ "Error was : %s.\n",
+ remote_machine, get_friendly_nt_error_msg(result));
+ cli_shutdown(cli);
+ return result;
+ }
+
+ /* OK, that failed, so try again... */
+ TALLOC_FREE(pipe_hnd);
+
+ /* Try anonymous NTLMSSP... */
+ cli_init_creds(cli, "", "", NULL);
+
+ result = NT_STATUS_UNSUCCESSFUL;
+
+ /* OK, this is ugly, but... try an anonymous pipe. */
+ result = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
+ &pipe_hnd);
+
+ if ( NT_STATUS_IS_OK(result) &&
+ (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user2(
+ pipe_hnd, talloc_tos(), user_name,
+ new_passwd, old_passwd)))) {
+ /* Great - it all worked! */
+ cli_shutdown(cli);
+ return NT_STATUS_OK;
+ } else {
+ if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)
+ || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) {
+ /* it failed, but again it was due to things like new password too short */
+
+ asprintf(err_str, "machine %s rejected the "
+ "(anonymous) password change: Error was : "
+ "%s.\n", remote_machine,
+ get_friendly_nt_error_msg(result));
+ cli_shutdown(cli);
+ return result;
+ }
+
+ /* We have failed to change the user's password, and we think the server
+ just might not support SAMR password changes, so fall back */
+
+ if (lp_client_lanman_auth()) {
+ /* Use the old RAP method. */
+ if (cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) {
+ /* SAMR failed, but the old LanMan protocol worked! */
+
+ cli_shutdown(cli);
+ return NT_STATUS_OK;
+ }
+ asprintf(err_str, "machine %s rejected the password "
+ "change: Error was : %s.\n",
+ remote_machine, cli_errstr(cli) );
+ result = cli_nt_error(cli);
+ cli_shutdown(cli);
+ return result;
+ } else {
+ asprintf(err_str, "SAMR connection to machine %s "
+ "failed. Error was %s, but LANMAN password "
+ "changed are disabled\n",
+ nt_errstr(result), remote_machine);
+ cli_shutdown(cli);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+}
diff --git a/source3/libsmb/pwd_cache.c b/source3/libsmb/pwd_cache.c
new file mode 100644
index 0000000000..071e729e8c
--- /dev/null
+++ b/source3/libsmb/pwd_cache.c
@@ -0,0 +1,61 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Initialises a password structure.
+****************************************************************************/
+
+static void pwd_init(struct pwd_info *pwd)
+{
+ memset((char *)pwd->password , '\0', sizeof(pwd->password ));
+
+ pwd->null_pwd = True; /* safest option... */
+}
+
+/****************************************************************************
+ Stores a cleartext password.
+****************************************************************************/
+
+void pwd_set_cleartext(struct pwd_info *pwd, const char *clr)
+{
+ pwd_init(pwd);
+ if (clr) {
+ fstrcpy(pwd->password, clr);
+ pwd->null_pwd = False;
+ } else {
+ pwd->null_pwd = True;
+ }
+
+ pwd->cleartext = True;
+}
+
+/****************************************************************************
+ Gets a cleartext password.
+****************************************************************************/
+
+void pwd_get_cleartext(struct pwd_info *pwd, fstring clr)
+{
+ if (pwd->cleartext)
+ fstrcpy(clr, pwd->password);
+ else
+ clr[0] = 0;
+
+}
diff --git a/source3/libsmb/samlogon_cache.c b/source3/libsmb/samlogon_cache.c
new file mode 100644
index 0000000000..4abe5bb6de
--- /dev/null
+++ b/source3/libsmb/samlogon_cache.c
@@ -0,0 +1,258 @@
+/*
+ Unix SMB/CIFS implementation.
+ Net_sam_logon info3 helpers
+ Copyright (C) Alexander Bokovoy 2002.
+ Copyright (C) Andrew Bartlett 2002.
+ Copyright (C) Gerald Carter 2003.
+ Copyright (C) Tim Potter 2003.
+ Copyright (C) Guenther Deschner 2008.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#define NETSAMLOGON_TDB "netsamlogon_cache.tdb"
+
+static TDB_CONTEXT *netsamlogon_tdb = NULL;
+
+/***********************************************************************
+ open the tdb
+ ***********************************************************************/
+
+bool netsamlogon_cache_init(void)
+{
+ if (!netsamlogon_tdb) {
+ netsamlogon_tdb = tdb_open_log(lock_path(NETSAMLOGON_TDB), 0,
+ TDB_DEFAULT, O_RDWR | O_CREAT, 0600);
+ }
+
+ return (netsamlogon_tdb != NULL);
+}
+
+
+/***********************************************************************
+ Shutdown samlogon_cache database
+***********************************************************************/
+
+bool netsamlogon_cache_shutdown(void)
+{
+ if (netsamlogon_tdb) {
+ return (tdb_close(netsamlogon_tdb) == 0);
+ }
+
+ return true;
+}
+
+/***********************************************************************
+ Clear cache getpwnam and getgroups entries from the winbindd cache
+***********************************************************************/
+
+void netsamlogon_clear_cached_user(struct netr_SamInfo3 *info3)
+{
+ DOM_SID user_sid;
+ fstring keystr, tmp;
+
+ if (!info3) {
+ return;
+ }
+
+ if (!netsamlogon_cache_init()) {
+ DEBUG(0,("netsamlogon_clear_cached_user: cannot open "
+ "%s for write!\n",
+ NETSAMLOGON_TDB));
+ return;
+ }
+ sid_copy(&user_sid, info3->base.domain_sid);
+ sid_append_rid(&user_sid, info3->base.rid);
+
+ /* Prepare key as DOMAIN-SID/USER-RID string */
+ slprintf(keystr, sizeof(keystr), "%s", sid_to_fstring(tmp, &user_sid));
+
+ DEBUG(10,("netsamlogon_clear_cached_user: SID [%s]\n", keystr));
+
+ tdb_delete_bystring(netsamlogon_tdb, keystr);
+}
+
+/***********************************************************************
+ Store a netr_SamInfo3 structure in a tdb for later user
+ username should be in UTF-8 format
+***********************************************************************/
+
+bool netsamlogon_cache_store(const char *username, struct netr_SamInfo3 *info3)
+{
+ TDB_DATA data;
+ fstring keystr, tmp;
+ bool result = false;
+ DOM_SID user_sid;
+ time_t t = time(NULL);
+ TALLOC_CTX *mem_ctx;
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ struct netsamlogoncache_entry r;
+
+ if (!info3) {
+ return false;
+ }
+
+ if (!netsamlogon_cache_init()) {
+ DEBUG(0,("netsamlogon_cache_store: cannot open %s for write!\n",
+ NETSAMLOGON_TDB));
+ return false;
+ }
+
+ sid_copy(&user_sid, info3->base.domain_sid);
+ sid_append_rid(&user_sid, info3->base.rid);
+
+ /* Prepare key as DOMAIN-SID/USER-RID string */
+ slprintf(keystr, sizeof(keystr), "%s", sid_to_fstring(tmp, &user_sid));
+
+ DEBUG(10,("netsamlogon_cache_store: SID [%s]\n", keystr));
+
+ /* Prepare data */
+
+ if (!(mem_ctx = TALLOC_P( NULL, int))) {
+ DEBUG(0,("netsamlogon_cache_store: talloc() failed!\n"));
+ return false;
+ }
+
+ /* only Samba fills in the username, not sure why NT doesn't */
+ /* so we fill it in since winbindd_getpwnam() makes use of it */
+
+ if (!info3->base.account_name.string) {
+ info3->base.account_name.string = talloc_strdup(info3, username);
+ }
+
+ r.timestamp = t;
+ r.info3 = *info3;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(netsamlogoncache_entry, &r);
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &r,
+ (ndr_push_flags_fn_t)ndr_push_netsamlogoncache_entry);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0,("netsamlogon_cache_store: failed to push entry to cache\n"));
+ TALLOC_FREE(mem_ctx);
+ return false;
+ }
+
+ data.dsize = blob.length;
+ data.dptr = blob.data;
+
+ if (tdb_store_bystring(netsamlogon_tdb, keystr, data, TDB_REPLACE) != -1) {
+ result = true;
+ }
+
+ TALLOC_FREE(mem_ctx);
+
+ return result;
+}
+
+/***********************************************************************
+ Retrieves a netr_SamInfo3 structure from a tdb. Caller must
+ free the user_info struct (malloc()'d memory)
+***********************************************************************/
+
+struct netr_SamInfo3 *netsamlogon_cache_get(TALLOC_CTX *mem_ctx, const DOM_SID *user_sid)
+{
+ struct netr_SamInfo3 *info3 = NULL;
+ TDB_DATA data;
+ fstring keystr, tmp;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netsamlogoncache_entry r;
+
+ if (!netsamlogon_cache_init()) {
+ DEBUG(0,("netsamlogon_cache_get: cannot open %s for write!\n",
+ NETSAMLOGON_TDB));
+ return false;
+ }
+
+ /* Prepare key as DOMAIN-SID/USER-RID string */
+ slprintf(keystr, sizeof(keystr), "%s", sid_to_fstring(tmp, user_sid));
+ DEBUG(10,("netsamlogon_cache_get: SID [%s]\n", keystr));
+ data = tdb_fetch_bystring( netsamlogon_tdb, keystr );
+
+ if (!data.dptr) {
+ return NULL;
+ }
+
+ info3 = TALLOC_ZERO_P(mem_ctx, struct netr_SamInfo3);
+ if (!info3) {
+ goto done;
+ }
+
+ blob = data_blob_const(data.dptr, data.dsize);
+
+ ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
+ (ndr_pull_flags_fn_t)ndr_pull_netsamlogoncache_entry);
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(netsamlogoncache_entry, &r);
+ }
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0,("netsamlogon_cache_get: failed to pull entry from cache\n"));
+ tdb_delete(netsamlogon_tdb, data);
+ TALLOC_FREE(info3);
+ goto done;
+ }
+
+ info3 = (struct netr_SamInfo3 *)talloc_memdup(mem_ctx, &r.info3,
+ sizeof(r.info3));
+
+ done:
+ SAFE_FREE(data.dptr);
+
+ return info3;
+
+#if 0 /* The netsamlogon cache needs to hang around. Something about
+ this feels wrong, but it is the only way we can get all of the
+ groups. The old universal groups cache didn't expire either.
+ --jerry */
+ {
+ time_t now = time(NULL);
+ uint32 time_diff;
+
+ /* is the entry expired? */
+ time_diff = now - t;
+
+ if ( (time_diff < 0 ) || (time_diff > lp_winbind_cache_time()) ) {
+ DEBUG(10,("netsamlogon_cache_get: cache entry expired \n"));
+ tdb_delete( netsamlogon_tdb, key );
+ TALLOC_FREE( user );
+ }
+ }
+#endif
+}
+
+bool netsamlogon_cache_have(const DOM_SID *user_sid)
+{
+ TALLOC_CTX *mem_ctx = talloc_init("netsamlogon_cache_have");
+ struct netr_SamInfo3 *info3 = NULL;
+ bool result;
+
+ if (!mem_ctx)
+ return False;
+
+ info3 = netsamlogon_cache_get(mem_ctx, user_sid);
+
+ result = (info3 != NULL);
+
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
diff --git a/source3/libsmb/smb_seal.c b/source3/libsmb/smb_seal.c
new file mode 100644
index 0000000000..a81ae9afd5
--- /dev/null
+++ b/source3/libsmb/smb_seal.c
@@ -0,0 +1,497 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Transport encryption (sealing) code.
+ Copyright (C) Jeremy Allison 2007.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/******************************************************************************
+ Pull out the encryption context for this packet. 0 means global context.
+******************************************************************************/
+
+NTSTATUS get_enc_ctx_num(const uint8_t *buf, uint16 *p_enc_ctx_num)
+{
+ if (smb_len(buf) < 8) {
+ return NT_STATUS_INVALID_BUFFER_SIZE;
+ }
+
+ if (buf[4] == 0xFF) {
+ if (buf[5] == 'S' && buf [6] == 'M' && buf[7] == 'B') {
+ /* Not an encrypted buffer. */
+ return NT_STATUS_NOT_FOUND;
+ }
+ if (buf[5] == 'E') {
+ *p_enc_ctx_num = SVAL(buf,6);
+ return NT_STATUS_OK;
+ }
+ }
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ Is encryption turned on ?
+******************************************************************************/
+
+bool common_encryption_on(struct smb_trans_enc_state *es)
+{
+ return ((es != NULL) && es->enc_on);
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ NTLM decrypt an incoming buffer.
+ Abartlett tells me that SSPI puts the signature first before the encrypted
+ output, so cope with the same for compatibility.
+******************************************************************************/
+
+NTSTATUS common_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf)
+{
+ NTSTATUS status;
+ size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
+ size_t data_len;
+ char *inbuf;
+ DATA_BLOB sig;
+
+ if (buf_len < 8 + NTLMSSP_SIG_SIZE) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ inbuf = (char *)smb_xmemdup(buf, buf_len);
+
+ /* Adjust for the signature. */
+ data_len = buf_len - 8 - NTLMSSP_SIG_SIZE;
+
+ /* Point at the signature. */
+ sig = data_blob_const(inbuf+8, NTLMSSP_SIG_SIZE);
+
+ status = ntlmssp_unseal_packet(ntlmssp_state,
+ (unsigned char *)inbuf + 8 + NTLMSSP_SIG_SIZE, /* 4 byte len + 0xFF 'E' <enc> <ctx> */
+ data_len,
+ (unsigned char *)inbuf + 8 + NTLMSSP_SIG_SIZE,
+ data_len,
+ &sig);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ SAFE_FREE(inbuf);
+ return status;
+ }
+
+ memcpy(buf + 8, inbuf + 8 + NTLMSSP_SIG_SIZE, data_len);
+
+ /* Reset the length and overwrite the header. */
+ smb_setlen(buf,data_len + 4);
+
+ SAFE_FREE(inbuf);
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ NTLM encrypt an outgoing buffer. Return the encrypted pointer in ppbuf_out.
+ Abartlett tells me that SSPI puts the signature first before the encrypted
+ output, so do the same for compatibility.
+******************************************************************************/
+
+NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state,
+ uint16 enc_ctx_num,
+ char *buf,
+ char **ppbuf_out)
+{
+ NTSTATUS status;
+ char *buf_out;
+ size_t data_len = smb_len(buf) - 4; /* Ignore the 0xFF SMB bytes. */
+ DATA_BLOB sig;
+
+ *ppbuf_out = NULL;
+
+ if (data_len == 0) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /*
+ * We know smb_len can't return a value > 128k, so no int overflow
+ * check needed.
+ */
+
+ buf_out = SMB_XMALLOC_ARRAY(char, 8 + NTLMSSP_SIG_SIZE + data_len);
+
+ /* Copy the data from the original buffer. */
+
+ memcpy(buf_out + 8 + NTLMSSP_SIG_SIZE, buf + 8, data_len);
+
+ smb_set_enclen(buf_out, smb_len(buf) + NTLMSSP_SIG_SIZE, enc_ctx_num);
+
+ sig = data_blob(NULL, NTLMSSP_SIG_SIZE);
+
+ status = ntlmssp_seal_packet(ntlmssp_state,
+ (unsigned char *)buf_out + 8 + NTLMSSP_SIG_SIZE, /* 4 byte len + 0xFF 'S' <enc> <ctx> */
+ data_len,
+ (unsigned char *)buf_out + 8 + NTLMSSP_SIG_SIZE,
+ data_len,
+ &sig);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ data_blob_free(&sig);
+ SAFE_FREE(buf_out);
+ return status;
+ }
+
+ /* First 16 data bytes are signature for SSPI compatibility. */
+ memcpy(buf_out + 8, sig.data, NTLMSSP_SIG_SIZE);
+ *ppbuf_out = buf_out;
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ gss-api decrypt an incoming buffer. We insist that the size of the
+ unwrapped buffer must be smaller or identical to the incoming buffer.
+******************************************************************************/
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+static NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_state, char *buf)
+{
+ gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
+ OM_uint32 ret = 0;
+ OM_uint32 minor = 0;
+ int flags_got = 0;
+ gss_buffer_desc in_buf, out_buf;
+ size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
+
+ if (buf_len < 8) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ in_buf.value = buf + 8;
+ in_buf.length = buf_len - 8;
+
+ ret = gss_unwrap(&minor,
+ gss_ctx,
+ &in_buf,
+ &out_buf,
+ &flags_got, /* did we get sign+seal ? */
+ (gss_qop_t *) NULL);
+
+ if (ret != GSS_S_COMPLETE) {
+ ADS_STATUS adss = ADS_ERROR_GSS(ret, minor);
+ DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap failed. Error %s\n",
+ ads_errstr(adss) ));
+ return map_nt_error_from_gss(ret, minor);
+ }
+
+ if (out_buf.length > in_buf.length) {
+ DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap size (%u) too large (%u) !\n",
+ (unsigned int)out_buf.length,
+ (unsigned int)in_buf.length ));
+ gss_release_buffer(&minor, &out_buf);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ memcpy(buf + 8, out_buf.value, out_buf.length);
+ /* Reset the length and overwrite the header. */
+ smb_setlen(buf, out_buf.length + 4);
+
+ gss_release_buffer(&minor, &out_buf);
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ gss-api encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
+******************************************************************************/
+
+static NTSTATUS common_gss_encrypt_buffer(struct smb_tran_enc_state_gss *gss_state,
+ uint16 enc_ctx_num,
+ char *buf,
+ char **ppbuf_out)
+{
+ gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
+ OM_uint32 ret = 0;
+ OM_uint32 minor = 0;
+ int flags_got = 0;
+ gss_buffer_desc in_buf, out_buf;
+ size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
+
+ *ppbuf_out = NULL;
+
+ if (buf_len < 8) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ in_buf.value = buf + 8;
+ in_buf.length = buf_len - 8;
+
+ ret = gss_wrap(&minor,
+ gss_ctx,
+ true, /* we want sign+seal. */
+ GSS_C_QOP_DEFAULT,
+ &in_buf,
+ &flags_got, /* did we get sign+seal ? */
+ &out_buf);
+
+ if (ret != GSS_S_COMPLETE) {
+ ADS_STATUS adss = ADS_ERROR_GSS(ret, minor);
+ DEBUG(0,("common_gss_encrypt_buffer: gss_wrap failed. Error %s\n",
+ ads_errstr(adss) ));
+ return map_nt_error_from_gss(ret, minor);
+ }
+
+ if (!flags_got) {
+ /* Sign+seal not supported. */
+ gss_release_buffer(&minor, &out_buf);
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ /* Ya see - this is why I *hate* gss-api. I don't
+ * want to have to malloc another buffer of the
+ * same size + 8 bytes just to get a continuous
+ * header + buffer, but gss won't let me pass in
+ * a pre-allocated buffer. Bastards (and you know
+ * who you are....). I might fix this by
+ * going to "encrypt_and_send" passing in a file
+ * descriptor and doing scatter-gather write with
+ * TCP cork on Linux. But I shouldn't have to
+ * bother :-*(. JRA.
+ */
+
+ *ppbuf_out = (char *)SMB_MALLOC(out_buf.length + 8); /* We know this can't wrap. */
+ if (!*ppbuf_out) {
+ gss_release_buffer(&minor, &out_buf);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ memcpy(*ppbuf_out+8, out_buf.value, out_buf.length);
+ smb_set_enclen(*ppbuf_out, out_buf.length + 4, enc_ctx_num);
+
+ gss_release_buffer(&minor, &out_buf);
+ return NT_STATUS_OK;
+}
+#endif
+
+/******************************************************************************
+ Generic code for client and server.
+ Encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
+******************************************************************************/
+
+NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out)
+{
+ if (!common_encryption_on(es)) {
+ /* Not encrypting. */
+ *buf_out = buffer;
+ return NT_STATUS_OK;
+ }
+
+ switch (es->smb_enc_type) {
+ case SMB_TRANS_ENC_NTLM:
+ return common_ntlm_encrypt_buffer(es->s.ntlmssp_state, es->enc_ctx_num, buffer, buf_out);
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+ case SMB_TRANS_ENC_GSS:
+ return common_gss_encrypt_buffer(es->s.gss_state, es->enc_ctx_num, buffer, buf_out);
+#endif
+ default:
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ Decrypt an incoming SMB buffer. Replaces the data within it.
+ New data must be less than or equal to the current length.
+******************************************************************************/
+
+NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
+{
+ if (!common_encryption_on(es)) {
+ /* Not decrypting. */
+ return NT_STATUS_OK;
+ }
+
+ switch (es->smb_enc_type) {
+ case SMB_TRANS_ENC_NTLM:
+ return common_ntlm_decrypt_buffer(es->s.ntlmssp_state, buf);
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+ case SMB_TRANS_ENC_GSS:
+ return common_gss_decrypt_buffer(es->s.gss_state, buf);
+#endif
+ default:
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+}
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+/******************************************************************************
+ Shutdown a gss encryption state.
+******************************************************************************/
+
+static void common_free_gss_state(struct smb_tran_enc_state_gss **pp_gss_state)
+{
+ OM_uint32 minor = 0;
+ struct smb_tran_enc_state_gss *gss_state = *pp_gss_state;
+
+ if (gss_state->creds != GSS_C_NO_CREDENTIAL) {
+ gss_release_cred(&minor, &gss_state->creds);
+ }
+ if (gss_state->gss_ctx != GSS_C_NO_CONTEXT) {
+ gss_delete_sec_context(&minor, &gss_state->gss_ctx, NULL);
+ }
+ SAFE_FREE(*pp_gss_state);
+}
+#endif
+
+/******************************************************************************
+ Shutdown an encryption state.
+******************************************************************************/
+
+void common_free_encryption_state(struct smb_trans_enc_state **pp_es)
+{
+ struct smb_trans_enc_state *es = *pp_es;
+
+ if (es == NULL) {
+ return;
+ }
+
+ if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
+ if (es->s.ntlmssp_state) {
+ ntlmssp_end(&es->s.ntlmssp_state);
+ }
+ }
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+ if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
+ /* Free the gss context handle. */
+ if (es->s.gss_state) {
+ common_free_gss_state(&es->s.gss_state);
+ }
+ }
+#endif
+ SAFE_FREE(es);
+ *pp_es = NULL;
+}
+
+/******************************************************************************
+ Free an encryption-allocated buffer.
+******************************************************************************/
+
+void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf)
+{
+ if (!common_encryption_on(es)) {
+ return;
+ }
+
+ if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
+ SAFE_FREE(buf);
+ return;
+ }
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+ if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
+ OM_uint32 min;
+ gss_buffer_desc rel_buf;
+ rel_buf.value = buf;
+ rel_buf.length = smb_len(buf) + 4;
+ gss_release_buffer(&min, &rel_buf);
+ }
+#endif
+}
+
+/******************************************************************************
+ Client side encryption.
+******************************************************************************/
+
+/******************************************************************************
+ Is client encryption on ?
+******************************************************************************/
+
+bool cli_encryption_on(struct cli_state *cli)
+{
+ /* If we supported multiple encrytion contexts
+ * here we'd look up based on tid.
+ */
+ return common_encryption_on(cli->trans_enc_state);
+}
+
+/******************************************************************************
+ Shutdown a client encryption state.
+******************************************************************************/
+
+void cli_free_encryption_context(struct cli_state *cli)
+{
+ common_free_encryption_state(&cli->trans_enc_state);
+}
+
+/******************************************************************************
+ Free an encryption-allocated buffer.
+******************************************************************************/
+
+void cli_free_enc_buffer(struct cli_state *cli, char *buf)
+{
+ /* We know this is an smb buffer, and we
+ * didn't malloc, only copy, for a keepalive,
+ * so ignore non-session messages. */
+
+ if(CVAL(buf,0)) {
+ return;
+ }
+
+ /* If we supported multiple encrytion contexts
+ * here we'd look up based on tid.
+ */
+ common_free_enc_buffer(cli->trans_enc_state, buf);
+}
+
+/******************************************************************************
+ Decrypt an incoming buffer.
+******************************************************************************/
+
+NTSTATUS cli_decrypt_message(struct cli_state *cli)
+{
+ NTSTATUS status;
+ uint16 enc_ctx_num;
+
+ /* Ignore non-session messages. */
+ if(CVAL(cli->inbuf,0)) {
+ return NT_STATUS_OK;
+ }
+
+ status = get_enc_ctx_num((const uint8_t *)cli->inbuf, &enc_ctx_num);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (enc_ctx_num != cli->trans_enc_state->enc_ctx_num) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ return common_decrypt_buffer(cli->trans_enc_state, cli->inbuf);
+}
+
+/******************************************************************************
+ Encrypt an outgoing buffer. Return the encrypted pointer in buf_out.
+******************************************************************************/
+
+NTSTATUS cli_encrypt_message(struct cli_state *cli, char *buf, char **buf_out)
+{
+ /* Ignore non-session messages. */
+ if (CVAL(buf,0)) {
+ return NT_STATUS_OK;
+ }
+
+ /* If we supported multiple encrytion contexts
+ * here we'd look up based on tid.
+ */
+ return common_encrypt_buffer(cli->trans_enc_state, buf, buf_out);
+}
diff --git a/source3/libsmb/smb_share_modes.c b/source3/libsmb/smb_share_modes.c
new file mode 100644
index 0000000000..16b3b10925
--- /dev/null
+++ b/source3/libsmb/smb_share_modes.c
@@ -0,0 +1,520 @@
+/*
+ Samba share mode database library external interface library.
+ Used by non-Samba products needing access to the Samba share mode db.
+
+ Copyright (C) Jeremy Allison 2005 - 2006
+
+ sharemodes_procid functions (C) Copyright (C) Volker Lendecke 2005
+
+ ** NOTE! The following LGPL license applies to this module only.
+ ** This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "smb_share_modes.h"
+
+/* Database context handle. */
+struct smbdb_ctx {
+ TDB_CONTEXT *smb_tdb;
+};
+
+/* Remove the paranoid malloc checker. */
+#ifdef malloc
+#undef malloc
+#endif
+
+int smb_create_share_mode_entry_ex(struct smbdb_ctx *db_ctx, uint64_t dev,
+ uint64_t ino, const struct smb_share_mode_entry *new_entry,
+ const char *sharepath, const char *filename);
+
+static bool sharemodes_procid_equal(const struct server_id *p1, const struct server_id *p2)
+{
+ return (p1->pid == p2->pid);
+}
+
+static pid_t sharemodes_procid_to_pid(const struct server_id *proc)
+{
+ return proc->pid;
+}
+
+/*
+ * open/close sharemode database.
+ */
+
+struct smbdb_ctx *smb_share_mode_db_open(const char *db_path)
+{
+ struct smbdb_ctx *smb_db = (struct smbdb_ctx *)malloc(sizeof(struct smbdb_ctx));
+
+ if (!smb_db) {
+ return NULL;
+ }
+
+ memset(smb_db, '\0', sizeof(struct smbdb_ctx));
+
+ smb_db->smb_tdb = tdb_open(db_path,
+ 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST,
+ O_RDWR|O_CREAT,
+ 0644);
+
+ if (!smb_db->smb_tdb) {
+ free(smb_db);
+ return NULL;
+ }
+
+ /* Should check that this is the correct version.... */
+ return smb_db;
+}
+
+/* key and data records in the tdb locking database */
+struct locking_key {
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+};
+
+int smb_share_mode_db_close(struct smbdb_ctx *db_ctx)
+{
+ int ret = tdb_close(db_ctx->smb_tdb);
+ free(db_ctx);
+ return ret;
+}
+
+static TDB_DATA get_locking_key(uint64_t dev, uint64_t ino)
+{
+ static struct locking_key lk;
+ TDB_DATA ld;
+
+ memset(&lk, '\0', sizeof(struct locking_key));
+ lk.dev = (SMB_DEV_T)dev;
+ lk.inode = (SMB_INO_T)ino;
+ ld.dptr = (uint8 *)&lk;
+ ld.dsize = sizeof(lk);
+ return ld;
+}
+
+/*
+ * lock/unlock entry in sharemode database.
+ */
+
+int smb_lock_share_mode_entry(struct smbdb_ctx *db_ctx,
+ uint64_t dev,
+ uint64_t ino)
+{
+ return tdb_chainlock(db_ctx->smb_tdb, get_locking_key(dev, ino));
+}
+
+int smb_unlock_share_mode_entry(struct smbdb_ctx *db_ctx,
+ uint64_t dev,
+ uint64_t ino)
+{
+ return tdb_chainunlock(db_ctx->smb_tdb, get_locking_key(dev, ino));
+}
+
+/*
+ * Check if an external smb_share_mode_entry and an internal share_mode entry match.
+ */
+
+static int share_mode_entry_equal(const struct smb_share_mode_entry *e_entry,
+ const struct share_mode_entry *entry)
+{
+ return (sharemodes_procid_equal(&e_entry->pid, &entry->pid) &&
+ e_entry->file_id == (uint32_t)entry->share_file_id &&
+ e_entry->open_time.tv_sec == entry->time.tv_sec &&
+ e_entry->open_time.tv_usec == entry->time.tv_usec &&
+ e_entry->share_access == (uint32_t)entry->share_access &&
+ e_entry->access_mask == (uint32_t)entry->access_mask &&
+ e_entry->dev == entry->id.devid &&
+ e_entry->ino == entry->id.inode);
+}
+
+/*
+ * Create an internal Samba share_mode entry from an external smb_share_mode_entry.
+ */
+
+static void create_share_mode_entry(struct share_mode_entry *out,
+ const struct smb_share_mode_entry *in)
+{
+ memset(out, '\0', sizeof(struct share_mode_entry));
+
+ out->pid = in->pid;
+ out->share_file_id = (unsigned long)in->file_id;
+ out->time.tv_sec = in->open_time.tv_sec;
+ out->time.tv_usec = in->open_time.tv_usec;
+ out->share_access = in->share_access;
+ out->access_mask = in->access_mask;
+ out->id.devid = in->dev;
+ out->id.inode = in->ino;
+ out->uid = (uint32)geteuid();
+ out->flags = 0;
+}
+
+/*
+ * Return the current share mode list for an open file.
+ * This uses similar (but simplified) logic to locking/locking.c
+ */
+
+int smb_get_share_mode_entries(struct smbdb_ctx *db_ctx,
+ uint64_t dev,
+ uint64_t ino,
+ struct smb_share_mode_entry **pp_list,
+ unsigned char *p_delete_on_close)
+{
+ TDB_DATA db_data;
+ struct smb_share_mode_entry *list = NULL;
+ int num_share_modes = 0;
+ struct locking_data *ld = NULL; /* internal samba db state. */
+ struct share_mode_entry *shares = NULL;
+ size_t i;
+ int list_num;
+
+ *pp_list = NULL;
+ *p_delete_on_close = 0;
+
+ db_data = tdb_fetch(db_ctx->smb_tdb, get_locking_key(dev, ino));
+ if (!db_data.dptr) {
+ return 0;
+ }
+
+ ld = (struct locking_data *)db_data.dptr;
+ num_share_modes = ld->u.s.num_share_mode_entries;
+
+ if (!num_share_modes) {
+ free(db_data.dptr);
+ return 0;
+ }
+
+ list = (struct smb_share_mode_entry *)malloc(sizeof(struct smb_share_mode_entry)*num_share_modes);
+ if (!list) {
+ free(db_data.dptr);
+ return -1;
+ }
+
+ memset(list, '\0', num_share_modes * sizeof(struct smb_share_mode_entry));
+
+ shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct locking_data));
+
+ list_num = 0;
+ for (i = 0; i < num_share_modes; i++) {
+ struct share_mode_entry *share = &shares[i];
+ struct smb_share_mode_entry *sme = &list[list_num];
+ struct server_id pid = share->pid;
+
+ /* Check this process really exists. */
+ if (kill(sharemodes_procid_to_pid(&pid), 0) == -1 && (errno == ESRCH)) {
+ continue; /* No longer exists. */
+ }
+
+ /* Ignore deferred open entries. */
+ if (share->op_type == DEFERRED_OPEN_ENTRY) {
+ continue;
+ }
+
+ /* Copy into the external list. */
+ sme->dev = share->id.devid;
+ sme->ino = share->id.inode;
+ sme->share_access = (uint32_t)share->share_access;
+ sme->access_mask = (uint32_t)share->access_mask;
+ sme->open_time.tv_sec = share->time.tv_sec;
+ sme->open_time.tv_usec = share->time.tv_usec;
+ sme->file_id = (uint32_t)share->share_file_id;
+ sme->pid = share->pid;
+ list_num++;
+ }
+
+ if (list_num == 0) {
+ free(db_data.dptr);
+ free(list);
+ return 0;
+ }
+
+ *p_delete_on_close = ld->u.s.delete_on_close;
+ *pp_list = list;
+ free(db_data.dptr);
+ return list_num;
+}
+
+/*
+ * Create an entry in the Samba share mode db.
+ */
+
+int smb_create_share_mode_entry_ex(struct smbdb_ctx *db_ctx,
+ uint64_t dev,
+ uint64_t ino,
+ const struct smb_share_mode_entry *new_entry,
+ const char *sharepath, /* Must be absolute utf8 path. */
+ const char *filename) /* Must be relative utf8 path. */
+{
+ TDB_DATA db_data;
+ TDB_DATA locking_key = get_locking_key(dev, ino);
+ int orig_num_share_modes = 0;
+ struct locking_data *ld = NULL; /* internal samba db state. */
+ struct share_mode_entry *shares = NULL;
+ uint8 *new_data_p = NULL;
+ size_t new_data_size = 0;
+
+ db_data = tdb_fetch(db_ctx->smb_tdb, locking_key);
+ if (!db_data.dptr) {
+ /* We must create the entry. */
+ db_data.dptr = (uint8 *)malloc(
+ sizeof(struct locking_data) +
+ sizeof(struct share_mode_entry) +
+ strlen(sharepath) + 1 +
+ strlen(filename) + 1);
+ if (!db_data.dptr) {
+ return -1;
+ }
+ ld = (struct locking_data *)db_data.dptr;
+ memset(ld, '\0', sizeof(struct locking_data));
+ ld->u.s.num_share_mode_entries = 1;
+ ld->u.s.delete_on_close = 0;
+ ld->u.s.delete_token_size = 0;
+ shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct locking_data));
+ create_share_mode_entry(shares, new_entry);
+
+ memcpy(db_data.dptr + sizeof(struct locking_data) + sizeof(struct share_mode_entry),
+ sharepath,
+ strlen(sharepath) + 1);
+ memcpy(db_data.dptr + sizeof(struct locking_data) + sizeof(struct share_mode_entry) +
+ strlen(sharepath) + 1,
+ filename,
+ strlen(filename) + 1);
+
+ db_data.dsize = sizeof(struct locking_data) + sizeof(struct share_mode_entry) +
+ strlen(sharepath) + 1 +
+ strlen(filename) + 1;
+ if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_INSERT) == -1) {
+ free(db_data.dptr);
+ return -1;
+ }
+ free(db_data.dptr);
+ return 0;
+ }
+
+ /* Entry exists, we must add a new entry. */
+ new_data_p = (uint8 *)malloc(
+ db_data.dsize + sizeof(struct share_mode_entry));
+ if (!new_data_p) {
+ free(db_data.dptr);
+ return -1;
+ }
+
+ ld = (struct locking_data *)db_data.dptr;
+ orig_num_share_modes = ld->u.s.num_share_mode_entries;
+
+ /* Copy the original data. */
+ memcpy(new_data_p, db_data.dptr, sizeof(struct locking_data) + (orig_num_share_modes * sizeof(struct share_mode_entry)));
+
+ /* Add in the new share mode */
+ shares = (struct share_mode_entry *)(new_data_p + sizeof(struct locking_data) +
+ (orig_num_share_modes * sizeof(struct share_mode_entry)));
+
+ create_share_mode_entry(shares, new_entry);
+
+ ld = (struct locking_data *)new_data_p;
+ ld->u.s.num_share_mode_entries++;
+
+ /* Append the original delete_token and filenames. */
+ memcpy(new_data_p + sizeof(struct locking_data) + (ld->u.s.num_share_mode_entries * sizeof(struct share_mode_entry)),
+ db_data.dptr + sizeof(struct locking_data) + (orig_num_share_modes * sizeof(struct share_mode_entry)),
+ db_data.dsize - sizeof(struct locking_data) - (orig_num_share_modes * sizeof(struct share_mode_entry)));
+
+ new_data_size = db_data.dsize + sizeof(struct share_mode_entry);
+
+ free(db_data.dptr);
+
+ db_data.dptr = new_data_p;
+ db_data.dsize = new_data_size;
+
+ if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_REPLACE) == -1) {
+ free(db_data.dptr);
+ return -1;
+ }
+ free(db_data.dptr);
+ return 0;
+}
+
+/*
+ * Create an entry in the Samba share mode db. Original interface - doesn't
+ * Distinguish between share path and filename. Fudge this by using a
+ * sharepath of / and a relative filename of (filename+1).
+ */
+
+int smb_create_share_mode_entry(struct smbdb_ctx *db_ctx,
+ uint64_t dev,
+ uint64_t ino,
+ const struct smb_share_mode_entry *new_entry,
+ const char *filename) /* Must be absolute utf8 path. */
+{
+ if (*filename != '/') {
+ abort();
+ }
+ return smb_create_share_mode_entry_ex(db_ctx, dev, ino, new_entry,
+ "/", &filename[1]);
+}
+
+int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx,
+ uint64_t dev,
+ uint64_t ino,
+ const struct smb_share_mode_entry *del_entry)
+{
+ TDB_DATA db_data;
+ TDB_DATA locking_key = get_locking_key(dev, ino);
+ int orig_num_share_modes = 0;
+ struct locking_data *ld = NULL; /* internal samba db state. */
+ struct share_mode_entry *shares = NULL;
+ uint8 *new_data_p = NULL;
+ size_t remaining_size = 0;
+ size_t i, num_share_modes;
+ const uint8 *remaining_ptr = NULL;
+
+ db_data = tdb_fetch(db_ctx->smb_tdb, locking_key);
+ if (!db_data.dptr) {
+ return -1; /* Error - missing entry ! */
+ }
+
+ ld = (struct locking_data *)db_data.dptr;
+ orig_num_share_modes = ld->u.s.num_share_mode_entries;
+ shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct locking_data));
+
+ if (orig_num_share_modes == 1) {
+ /* Only one entry - better be ours... */
+ if (!share_mode_entry_equal(del_entry, shares)) {
+ /* Error ! We can't delete someone else's entry ! */
+ free(db_data.dptr);
+ return -1;
+ }
+ /* It's ours - just remove the entire record. */
+ free(db_data.dptr);
+ return tdb_delete(db_ctx->smb_tdb, locking_key);
+ }
+
+ /* More than one - allocate a new record minus the one we'll delete. */
+ new_data_p = (uint8 *)malloc(
+ db_data.dsize - sizeof(struct share_mode_entry));
+ if (!new_data_p) {
+ free(db_data.dptr);
+ return -1;
+ }
+
+ /* Copy the header. */
+ memcpy(new_data_p, db_data.dptr, sizeof(struct locking_data));
+
+ num_share_modes = 0;
+ for (i = 0; i < orig_num_share_modes; i++) {
+ struct share_mode_entry *share = &shares[i];
+ struct server_id pid = share->pid;
+
+ /* Check this process really exists. */
+ if (kill(sharemodes_procid_to_pid(&pid), 0) == -1 && (errno == ESRCH)) {
+ continue; /* No longer exists. */
+ }
+
+ if (share_mode_entry_equal(del_entry, share)) {
+ continue; /* This is our delete taget. */
+ }
+
+ memcpy(new_data_p + sizeof(struct locking_data) +
+ (num_share_modes * sizeof(struct share_mode_entry)),
+ share, sizeof(struct share_mode_entry) );
+
+ num_share_modes++;
+ }
+
+ if (num_share_modes == 0) {
+ /* None left after pruning. Delete record. */
+ free(db_data.dptr);
+ free(new_data_p);
+ return tdb_delete(db_ctx->smb_tdb, locking_key);
+ }
+
+ /* Copy any delete token plus the terminating filenames. */
+ remaining_ptr = db_data.dptr + sizeof(struct locking_data) + (orig_num_share_modes * sizeof(struct share_mode_entry));
+ remaining_size = db_data.dsize - (remaining_ptr - db_data.dptr);
+
+ memcpy(new_data_p + sizeof(struct locking_data) + (num_share_modes * sizeof(struct share_mode_entry)),
+ remaining_ptr,
+ remaining_size);
+
+ free(db_data.dptr);
+
+ db_data.dptr = new_data_p;
+
+ /* Re-save smaller record. */
+ ld = (struct locking_data *)db_data.dptr;
+ ld->u.s.num_share_mode_entries = num_share_modes;
+
+ db_data.dsize = sizeof(struct locking_data) + (num_share_modes * sizeof(struct share_mode_entry)) + remaining_size;
+
+ if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_REPLACE) == -1) {
+ free(db_data.dptr);
+ return -1;
+ }
+ free(db_data.dptr);
+ return 0;
+}
+
+int smb_change_share_mode_entry(struct smbdb_ctx *db_ctx,
+ uint64_t dev,
+ uint64_t ino,
+ const struct smb_share_mode_entry *set_entry,
+ const struct smb_share_mode_entry *new_entry)
+{
+ TDB_DATA db_data;
+ TDB_DATA locking_key = get_locking_key(dev, ino);
+ int num_share_modes = 0;
+ struct locking_data *ld = NULL; /* internal samba db state. */
+ struct share_mode_entry *shares = NULL;
+ size_t i;
+ int found_entry = 0;
+
+ db_data = tdb_fetch(db_ctx->smb_tdb, locking_key);
+ if (!db_data.dptr) {
+ return -1; /* Error - missing entry ! */
+ }
+
+ ld = (struct locking_data *)db_data.dptr;
+ num_share_modes = ld->u.s.num_share_mode_entries;
+ shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct locking_data));
+
+ for (i = 0; i < num_share_modes; i++) {
+ struct share_mode_entry *share = &shares[i];
+ struct server_id pid = share->pid;
+
+ /* Check this process really exists. */
+ if (kill(sharemodes_procid_to_pid(&pid), 0) == -1 && (errno == ESRCH)) {
+ continue; /* No longer exists. */
+ }
+
+ if (share_mode_entry_equal(set_entry, share)) {
+ create_share_mode_entry(share, new_entry);
+ found_entry = 1;
+ break;
+ }
+ }
+
+ if (!found_entry) {
+ free(db_data.dptr);
+ return -1;
+ }
+
+ /* Save modified data. */
+ if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_REPLACE) == -1) {
+ free(db_data.dptr);
+ return -1;
+ }
+ free(db_data.dptr);
+ return 0;
+}
diff --git a/source3/libsmb/smb_signing.c b/source3/libsmb/smb_signing.c
new file mode 100644
index 0000000000..ea1eb05cfb
--- /dev/null
+++ b/source3/libsmb/smb_signing.c
@@ -0,0 +1,1004 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Signing Code
+ Copyright (C) Jeremy Allison 2003.
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* Lookup a packet's MID (multiplex id) and figure out it's sequence number */
+struct outstanding_packet_lookup {
+ struct outstanding_packet_lookup *prev, *next;
+ uint16 mid;
+ uint32 reply_seq_num;
+ bool can_delete; /* Set to False in trans state. */
+};
+
+struct smb_basic_signing_context {
+ DATA_BLOB mac_key;
+ uint32 send_seq_num;
+ struct outstanding_packet_lookup *outstanding_packet_list;
+};
+
+static bool store_sequence_for_reply(struct outstanding_packet_lookup **list,
+ uint16 mid, uint32 reply_seq_num)
+{
+ struct outstanding_packet_lookup *t;
+
+ /* Ensure we only add a mid once. */
+ for (t = *list; t; t = t->next) {
+ if (t->mid == mid) {
+ return False;
+ }
+ }
+
+ t = SMB_XMALLOC_P(struct outstanding_packet_lookup);
+ ZERO_STRUCTP(t);
+
+ t->mid = mid;
+ t->reply_seq_num = reply_seq_num;
+ t->can_delete = True;
+
+ /*
+ * Add to the *start* of the list not the end of the list.
+ * This ensures that the *last* send sequence with this mid
+ * is returned by preference.
+ * This can happen if the mid wraps and one of the early
+ * mid numbers didn't get a reply and is still lurking on
+ * the list. JRA. Found by Fran Fabrizio <fran@cis.uab.edu>.
+ */
+
+ DLIST_ADD(*list, t);
+ DEBUG(10,("store_sequence_for_reply: stored seq = %u mid = %u\n",
+ (unsigned int)reply_seq_num, (unsigned int)mid ));
+ return True;
+}
+
+static bool get_sequence_for_reply(struct outstanding_packet_lookup **list,
+ uint16 mid, uint32 *reply_seq_num)
+{
+ struct outstanding_packet_lookup *t;
+
+ for (t = *list; t; t = t->next) {
+ if (t->mid == mid) {
+ *reply_seq_num = t->reply_seq_num;
+ DEBUG(10,("get_sequence_for_reply: found seq = %u mid = %u\n",
+ (unsigned int)t->reply_seq_num, (unsigned int)t->mid ));
+ if (t->can_delete) {
+ DLIST_REMOVE(*list, t);
+ SAFE_FREE(t);
+ }
+ return True;
+ }
+ }
+ return False;
+}
+
+static bool set_sequence_can_delete_flag(struct outstanding_packet_lookup **list, uint16 mid, bool can_delete_entry)
+{
+ struct outstanding_packet_lookup *t;
+
+ for (t = *list; t; t = t->next) {
+ if (t->mid == mid) {
+ t->can_delete = can_delete_entry;
+ return True;
+ }
+ }
+ return False;
+}
+
+/***********************************************************
+ SMB signing - Common code before we set a new signing implementation
+************************************************************/
+
+static bool cli_set_smb_signing_common(struct cli_state *cli)
+{
+ if (!cli->sign_info.allow_smb_signing) {
+ return False;
+ }
+
+ if (!cli->sign_info.negotiated_smb_signing
+ && !cli->sign_info.mandatory_signing) {
+ return False;
+ }
+
+ if (cli->sign_info.doing_signing) {
+ return False;
+ }
+
+ if (cli->sign_info.free_signing_context)
+ cli->sign_info.free_signing_context(&cli->sign_info);
+
+ /* These calls are INCOMPATIBLE with SMB signing */
+ cli->readbraw_supported = False;
+ cli->writebraw_supported = False;
+
+ return True;
+}
+
+/***********************************************************
+ SMB signing - Common code for 'real' implementations
+************************************************************/
+
+static bool set_smb_signing_real_common(struct smb_sign_info *si)
+{
+ if (si->mandatory_signing) {
+ DEBUG(5, ("Mandatory SMB signing enabled!\n"));
+ }
+
+ si->doing_signing = True;
+ DEBUG(5, ("SMB signing enabled!\n"));
+
+ return True;
+}
+
+static void mark_packet_signed(char *outbuf)
+{
+ uint16 flags2;
+ flags2 = SVAL(outbuf,smb_flg2);
+ flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
+ SSVAL(outbuf,smb_flg2, flags2);
+}
+
+/***********************************************************
+ SMB signing - NULL implementation - calculate a MAC to send.
+************************************************************/
+
+static void null_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
+{
+ /* we can't zero out the sig, as we might be trying to send a
+ session request - which is NBT-level, not SMB level and doesn't
+ have the field */
+ return;
+}
+
+/***********************************************************
+ SMB signing - NULL implementation - check a MAC sent by server.
+************************************************************/
+
+static bool null_check_incoming_message(const char *inbuf,
+ struct smb_sign_info *si,
+ bool must_be_ok)
+{
+ return True;
+}
+
+/***********************************************************
+ SMB signing - NULL implementation - free signing context
+************************************************************/
+
+static void null_free_signing_context(struct smb_sign_info *si)
+{
+ return;
+}
+
+/**
+ SMB signing - NULL implementation - setup the MAC key.
+
+ @note Used as an initialisation only - it will not correctly
+ shut down a real signing mechanism
+*/
+
+static bool null_set_signing(struct smb_sign_info *si)
+{
+ si->signing_context = NULL;
+
+ si->sign_outgoing_message = null_sign_outgoing_message;
+ si->check_incoming_message = null_check_incoming_message;
+ si->free_signing_context = null_free_signing_context;
+
+ return True;
+}
+
+/**
+ * Free the signing context
+ */
+
+static void free_signing_context(struct smb_sign_info *si)
+{
+ if (si->free_signing_context) {
+ si->free_signing_context(si);
+ si->signing_context = NULL;
+ }
+
+ null_set_signing(si);
+}
+
+
+static bool signing_good(const char *inbuf, struct smb_sign_info *si,
+ bool good, uint32 seq, bool must_be_ok)
+{
+ if (good) {
+
+ if (!si->doing_signing) {
+ si->doing_signing = True;
+ }
+
+ if (!si->seen_valid) {
+ si->seen_valid = True;
+ }
+
+ } else {
+ if (!si->mandatory_signing && !si->seen_valid) {
+
+ if (!must_be_ok) {
+ return True;
+ }
+ /* Non-mandatory signing - just turn off if this is the first bad packet.. */
+ DEBUG(5, ("srv_check_incoming_message: signing negotiated but not required and peer\n"
+ "isn't sending correct signatures. Turning off.\n"));
+ si->negotiated_smb_signing = False;
+ si->allow_smb_signing = False;
+ si->doing_signing = False;
+ free_signing_context(si);
+ return True;
+ } else if (!must_be_ok) {
+ /* This packet is known to be unsigned */
+ return True;
+ } else {
+ /* Mandatory signing or bad packet after signing started - fail and disconnect. */
+ if (seq)
+ DEBUG(0, ("signing_good: BAD SIG: seq %u\n", (unsigned int)seq));
+ return False;
+ }
+ }
+ return True;
+}
+
+/***********************************************************
+ SMB signing - Simple implementation - calculate a MAC on the packet
+************************************************************/
+
+static void simple_packet_signature(struct smb_basic_signing_context *data,
+ const uchar *buf, uint32 seq_number,
+ unsigned char calc_md5_mac[16])
+{
+ const size_t offset_end_of_sig = (smb_ss_field + 8);
+ unsigned char sequence_buf[8];
+ struct MD5Context md5_ctx;
+#if 0
+ /* JRA - apparently this is incorrect. */
+ unsigned char key_buf[16];
+#endif
+
+ /*
+ * Firstly put the sequence number into the first 4 bytes.
+ * and zero out the next 4 bytes.
+ *
+ * We do this here, to avoid modifying the packet.
+ */
+
+ DEBUG(10,("simple_packet_signature: sequence number %u\n", seq_number ));
+
+ SIVAL(sequence_buf, 0, seq_number);
+ SIVAL(sequence_buf, 4, 0);
+
+ /* Calculate the 16 byte MAC - but don't alter the data in the
+ incoming packet.
+
+ This makes for a bit of fussing about, but it's not too bad.
+ */
+ MD5Init(&md5_ctx);
+
+ /* intialise with the key */
+ MD5Update(&md5_ctx, data->mac_key.data, data->mac_key.length);
+#if 0
+ /* JRA - apparently this is incorrect. */
+ /* NB. When making and verifying SMB signatures, Windows apparently
+ zero-pads the key to 128 bits if it isn't long enough.
+ From Nalin Dahyabhai <nalin@redhat.com> */
+ if (data->mac_key.length < sizeof(key_buf)) {
+ memset(key_buf, 0, sizeof(key_buf));
+ MD5Update(&md5_ctx, key_buf, sizeof(key_buf) - data->mac_key.length);
+ }
+#endif
+
+ /* copy in the first bit of the SMB header */
+ MD5Update(&md5_ctx, buf + 4, smb_ss_field - 4);
+
+ /* copy in the sequence number, instead of the signature */
+ MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
+
+ /* copy in the rest of the packet in, skipping the signature */
+ MD5Update(&md5_ctx, buf + offset_end_of_sig,
+ smb_len(buf) - (offset_end_of_sig - 4));
+
+ /* calculate the MD5 sig */
+ MD5Final(calc_md5_mac, &md5_ctx);
+}
+
+
+/***********************************************************
+ SMB signing - Client implementation - send the MAC.
+************************************************************/
+
+static void client_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
+{
+ unsigned char calc_md5_mac[16];
+ struct smb_basic_signing_context *data =
+ (struct smb_basic_signing_context *)si->signing_context;
+
+ if (!si->doing_signing)
+ return;
+
+ /* JRA Paranioa test - we should be able to get rid of this... */
+ if (smb_len(outbuf) < (smb_ss_field + 8 - 4)) {
+ DEBUG(1, ("client_sign_outgoing_message: Logic error. Can't check signature on short packet! smb_len = %u\n",
+ smb_len(outbuf) ));
+ abort();
+ }
+
+ /* mark the packet as signed - BEFORE we sign it...*/
+ mark_packet_signed(outbuf);
+
+ simple_packet_signature(data, (const unsigned char *)outbuf,
+ data->send_seq_num, calc_md5_mac);
+
+ DEBUG(10, ("client_sign_outgoing_message: sent SMB signature of\n"));
+ dump_data(10, calc_md5_mac, 8);
+
+ memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8);
+
+/* cli->outbuf[smb_ss_field+2]=0;
+ Uncomment this to test if the remote server actually verifies signatures...*/
+
+ /* Instead of re-introducing the trans_info_conect we
+ used to have here, we use the fact that during a
+ SMBtrans/SMBtrans2/SMBnttrans send that the mid stays
+ constant. This means that calling store_sequence_for_reply()
+ will return False for all trans secondaries, as the mid is already
+ on the stored sequence list. As the send_seqence_number must
+ remain constant for all primary+secondary trans sends, we
+ only increment the send sequence number when we successfully
+ add a new entry to the outstanding sequence list. This means
+ I can isolate the fix here rather than re-adding the trans
+ signing on/off calls in libsmb/clitrans2.c JRA.
+ */
+
+ if (store_sequence_for_reply(&data->outstanding_packet_list, SVAL(outbuf,smb_mid), data->send_seq_num + 1)) {
+ data->send_seq_num += 2;
+ }
+}
+
+/***********************************************************
+ SMB signing - Client implementation - check a MAC sent by server.
+************************************************************/
+
+static bool client_check_incoming_message(const char *inbuf,
+ struct smb_sign_info *si,
+ bool must_be_ok)
+{
+ bool good;
+ uint32 reply_seq_number;
+ unsigned char calc_md5_mac[16];
+ unsigned char *server_sent_mac;
+
+ struct smb_basic_signing_context *data =
+ (struct smb_basic_signing_context *)si->signing_context;
+
+ if (!si->doing_signing)
+ return True;
+
+ if (smb_len(inbuf) < (smb_ss_field + 8 - 4)) {
+ DEBUG(1, ("client_check_incoming_message: Can't check signature on short packet! smb_len = %u\n", smb_len(inbuf)));
+ return False;
+ }
+
+ if (!get_sequence_for_reply(&data->outstanding_packet_list, SVAL(inbuf, smb_mid), &reply_seq_number)) {
+ DEBUG(1, ("client_check_incoming_message: received message "
+ "with mid %u with no matching send record.\n", (unsigned int)SVAL(inbuf, smb_mid) ));
+ return False;
+ }
+
+ simple_packet_signature(data, (const unsigned char *)inbuf,
+ reply_seq_number, calc_md5_mac);
+
+ server_sent_mac = (unsigned char *)&inbuf[smb_ss_field];
+ good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
+
+ if (!good) {
+ DEBUG(5, ("client_check_incoming_message: BAD SIG: wanted SMB signature of\n"));
+ dump_data(5, calc_md5_mac, 8);
+
+ DEBUG(5, ("client_check_incoming_message: BAD SIG: got SMB signature of\n"));
+ dump_data(5, server_sent_mac, 8);
+#if 1 /* JRATEST */
+ {
+ int i;
+ for (i = -5; i < 5; i++) {
+ simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number+i, calc_md5_mac);
+ if (memcmp(server_sent_mac, calc_md5_mac, 8) == 0) {
+ DEBUG(0,("client_check_incoming_message: out of seq. seq num %u matches. \
+We were expecting seq %u\n", reply_seq_number+i, reply_seq_number ));
+ break;
+ }
+ }
+ }
+#endif /* JRATEST */
+
+ } else {
+ DEBUG(10, ("client_check_incoming_message: seq %u: got good SMB signature of\n", (unsigned int)reply_seq_number));
+ dump_data(10, server_sent_mac, 8);
+ }
+ return signing_good(inbuf, si, good, reply_seq_number, must_be_ok);
+}
+
+/***********************************************************
+ SMB signing - Simple implementation - free signing context
+************************************************************/
+
+static void simple_free_signing_context(struct smb_sign_info *si)
+{
+ struct smb_basic_signing_context *data =
+ (struct smb_basic_signing_context *)si->signing_context;
+ struct outstanding_packet_lookup *list;
+ struct outstanding_packet_lookup *next;
+
+ for (list = data->outstanding_packet_list; list; list = next) {
+ next = list->next;
+ DLIST_REMOVE(data->outstanding_packet_list, list);
+ SAFE_FREE(list);
+ }
+
+ data_blob_free(&data->mac_key);
+
+ SAFE_FREE(si->signing_context);
+
+ return;
+}
+
+/***********************************************************
+ SMB signing - Simple implementation - setup the MAC key.
+************************************************************/
+
+bool cli_simple_set_signing(struct cli_state *cli,
+ const DATA_BLOB user_session_key,
+ const DATA_BLOB response)
+{
+ struct smb_basic_signing_context *data;
+
+ if (!user_session_key.length)
+ return False;
+
+ if (!cli_set_smb_signing_common(cli)) {
+ return False;
+ }
+
+ if (!set_smb_signing_real_common(&cli->sign_info)) {
+ return False;
+ }
+
+ data = SMB_XMALLOC_P(struct smb_basic_signing_context);
+ memset(data, '\0', sizeof(*data));
+
+ cli->sign_info.signing_context = data;
+
+ data->mac_key = data_blob(NULL, response.length + user_session_key.length);
+
+ memcpy(&data->mac_key.data[0], user_session_key.data, user_session_key.length);
+
+ DEBUG(10, ("cli_simple_set_signing: user_session_key\n"));
+ dump_data(10, user_session_key.data, user_session_key.length);
+
+ if (response.length) {
+ memcpy(&data->mac_key.data[user_session_key.length],response.data, response.length);
+ DEBUG(10, ("cli_simple_set_signing: response_data\n"));
+ dump_data(10, response.data, response.length);
+ } else {
+ DEBUG(10, ("cli_simple_set_signing: NULL response_data\n"));
+ }
+
+ dump_data_pw("MAC ssession key is:\n", data->mac_key.data, data->mac_key.length);
+
+ /* Initialise the sequence number */
+ data->send_seq_num = 0;
+
+ /* Initialise the list of outstanding packets */
+ data->outstanding_packet_list = NULL;
+
+ cli->sign_info.sign_outgoing_message = client_sign_outgoing_message;
+ cli->sign_info.check_incoming_message = client_check_incoming_message;
+ cli->sign_info.free_signing_context = simple_free_signing_context;
+
+ return True;
+}
+
+/***********************************************************
+ SMB signing - TEMP implementation - calculate a MAC to send.
+************************************************************/
+
+static void temp_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
+{
+ /* mark the packet as signed - BEFORE we sign it...*/
+ mark_packet_signed(outbuf);
+
+ /* I wonder what BSRSPYL stands for - but this is what MS
+ actually sends! */
+ memcpy(&outbuf[smb_ss_field], "BSRSPYL ", 8);
+ return;
+}
+
+/***********************************************************
+ SMB signing - TEMP implementation - check a MAC sent by server.
+************************************************************/
+
+static bool temp_check_incoming_message(const char *inbuf,
+ struct smb_sign_info *si, bool foo)
+{
+ return True;
+}
+
+/***********************************************************
+ SMB signing - TEMP implementation - free signing context
+************************************************************/
+
+static void temp_free_signing_context(struct smb_sign_info *si)
+{
+ return;
+}
+
+/***********************************************************
+ SMB signing - NULL implementation - setup the MAC key.
+************************************************************/
+
+bool cli_null_set_signing(struct cli_state *cli)
+{
+ return null_set_signing(&cli->sign_info);
+}
+
+/***********************************************************
+ SMB signing - temp implementation - setup the MAC key.
+************************************************************/
+
+bool cli_temp_set_signing(struct cli_state *cli)
+{
+ if (!cli_set_smb_signing_common(cli)) {
+ return False;
+ }
+
+ cli->sign_info.signing_context = NULL;
+
+ cli->sign_info.sign_outgoing_message = temp_sign_outgoing_message;
+ cli->sign_info.check_incoming_message = temp_check_incoming_message;
+ cli->sign_info.free_signing_context = temp_free_signing_context;
+
+ return True;
+}
+
+void cli_free_signing_context(struct cli_state *cli)
+{
+ free_signing_context(&cli->sign_info);
+}
+
+/**
+ * Sign a packet with the current mechanism
+ */
+
+void cli_calculate_sign_mac(struct cli_state *cli, char *buf)
+{
+ cli->sign_info.sign_outgoing_message(buf, &cli->sign_info);
+}
+
+/**
+ * Check a packet with the current mechanism
+ * @return False if we had an established signing connection
+ * which had a bad checksum, True otherwise.
+ */
+
+bool cli_check_sign_mac(struct cli_state *cli, char *buf)
+{
+ if (!cli->sign_info.check_incoming_message(buf, &cli->sign_info, True)) {
+ free_signing_context(&cli->sign_info);
+ return False;
+ }
+ return True;
+}
+
+/***********************************************************
+ Enter trans/trans2/nttrans state.
+************************************************************/
+
+bool client_set_trans_sign_state_on(struct cli_state *cli, uint16 mid)
+{
+ struct smb_sign_info *si = &cli->sign_info;
+ struct smb_basic_signing_context *data = (struct smb_basic_signing_context *)si->signing_context;
+
+ if (!si->doing_signing) {
+ return True;
+ }
+
+ if (!data) {
+ return False;
+ }
+
+ if (!set_sequence_can_delete_flag(&data->outstanding_packet_list, mid, False)) {
+ return False;
+ }
+
+ return True;
+}
+
+/***********************************************************
+ Leave trans/trans2/nttrans state.
+************************************************************/
+
+bool client_set_trans_sign_state_off(struct cli_state *cli, uint16 mid)
+{
+ uint32 reply_seq_num;
+ struct smb_sign_info *si = &cli->sign_info;
+ struct smb_basic_signing_context *data = (struct smb_basic_signing_context *)si->signing_context;
+
+ if (!si->doing_signing) {
+ return True;
+ }
+
+ if (!data) {
+ return False;
+ }
+
+ if (!set_sequence_can_delete_flag(&data->outstanding_packet_list, mid, True)) {
+ return False;
+ }
+
+ /* Now delete the stored mid entry. */
+ if (!get_sequence_for_reply(&data->outstanding_packet_list, mid, &reply_seq_num)) {
+ return False;
+ }
+
+ return True;
+}
+
+/***********************************************************
+ Is client signing on ?
+************************************************************/
+
+bool client_is_signing_on(struct cli_state *cli)
+{
+ struct smb_sign_info *si = &cli->sign_info;
+ return si->doing_signing;
+}
+
+/***********************************************************
+ SMB signing - Server implementation - send the MAC.
+************************************************************/
+
+static void srv_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
+{
+ unsigned char calc_md5_mac[16];
+ struct smb_basic_signing_context *data =
+ (struct smb_basic_signing_context *)si->signing_context;
+ uint32 send_seq_number = data->send_seq_num-1;
+ uint16 mid;
+
+ if (!si->doing_signing) {
+ return;
+ }
+
+ /* JRA Paranioa test - we should be able to get rid of this... */
+ if (smb_len(outbuf) < (smb_ss_field + 8 - 4)) {
+ DEBUG(1, ("srv_sign_outgoing_message: Logic error. Can't send signature on short packet! smb_len = %u\n",
+ smb_len(outbuf) ));
+ abort();
+ }
+
+ /* mark the packet as signed - BEFORE we sign it...*/
+ mark_packet_signed(outbuf);
+
+ mid = SVAL(outbuf, smb_mid);
+
+ /* See if this is a reply for a deferred packet. */
+ get_sequence_for_reply(&data->outstanding_packet_list, mid, &send_seq_number);
+
+ simple_packet_signature(data, (const unsigned char *)outbuf, send_seq_number, calc_md5_mac);
+
+ DEBUG(10, ("srv_sign_outgoing_message: seq %u: sent SMB signature of\n", (unsigned int)send_seq_number));
+ dump_data(10, calc_md5_mac, 8);
+
+ memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8);
+
+/* cli->outbuf[smb_ss_field+2]=0;
+ Uncomment this to test if the remote client actually verifies signatures...*/
+}
+
+/***********************************************************
+ SMB signing - Server implementation - check a MAC sent by server.
+************************************************************/
+
+static bool srv_check_incoming_message(const char *inbuf,
+ struct smb_sign_info *si,
+ bool must_be_ok)
+{
+ bool good;
+ struct smb_basic_signing_context *data =
+ (struct smb_basic_signing_context *)si->signing_context;
+ uint32 reply_seq_number = data->send_seq_num;
+ uint32 saved_seq;
+ unsigned char calc_md5_mac[16];
+ unsigned char *server_sent_mac;
+
+ if (!si->doing_signing)
+ return True;
+
+ if (smb_len(inbuf) < (smb_ss_field + 8 - 4)) {
+ DEBUG(1, ("srv_check_incoming_message: Can't check signature on short packet! smb_len = %u\n", smb_len(inbuf)));
+ return False;
+ }
+
+ /* We always increment the sequence number. */
+ data->send_seq_num += 2;
+
+ saved_seq = reply_seq_number;
+ simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number, calc_md5_mac);
+
+ server_sent_mac = (unsigned char *)&inbuf[smb_ss_field];
+ good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
+
+ if (!good) {
+
+ if (saved_seq) {
+ DEBUG(0, ("srv_check_incoming_message: BAD SIG: seq %u wanted SMB signature of\n",
+ (unsigned int)saved_seq));
+ dump_data(5, calc_md5_mac, 8);
+
+ DEBUG(0, ("srv_check_incoming_message: BAD SIG: seq %u got SMB signature of\n",
+ (unsigned int)reply_seq_number));
+ dump_data(5, server_sent_mac, 8);
+ }
+
+#if 1 /* JRATEST */
+ {
+ int i;
+ reply_seq_number -= 5;
+ for (i = 0; i < 10; i++, reply_seq_number++) {
+ simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number, calc_md5_mac);
+ if (memcmp(server_sent_mac, calc_md5_mac, 8) == 0) {
+ DEBUG(0,("srv_check_incoming_message: out of seq. seq num %u matches. \
+We were expecting seq %u\n", reply_seq_number, saved_seq ));
+ break;
+ }
+ }
+ }
+#endif /* JRATEST */
+
+ } else {
+ DEBUG(10, ("srv_check_incoming_message: seq %u: (current is %u) got good SMB signature of\n", (unsigned int)reply_seq_number, (unsigned int)data->send_seq_num));
+ dump_data(10, server_sent_mac, 8);
+ }
+
+ return (signing_good(inbuf, si, good, saved_seq, must_be_ok));
+}
+
+/***********************************************************
+ SMB signing - server API's.
+************************************************************/
+
+static struct smb_sign_info srv_sign_info = {
+ null_sign_outgoing_message,
+ null_check_incoming_message,
+ null_free_signing_context,
+ NULL,
+ False,
+ False,
+ False,
+ False
+};
+
+/***********************************************************
+ Turn signing off or on for oplock break code.
+************************************************************/
+
+bool srv_oplock_set_signing(bool onoff)
+{
+ bool ret = srv_sign_info.doing_signing;
+ srv_sign_info.doing_signing = onoff;
+ return ret;
+}
+
+/***********************************************************
+ Called to validate an incoming packet from the client.
+************************************************************/
+
+bool srv_check_sign_mac(const char *inbuf, bool must_be_ok)
+{
+ /* Check if it's a non-session message. */
+ if(CVAL(inbuf,0)) {
+ return True;
+ }
+
+ return srv_sign_info.check_incoming_message(inbuf, &srv_sign_info, must_be_ok);
+}
+
+/***********************************************************
+ Called to sign an outgoing packet to the client.
+************************************************************/
+
+void srv_calculate_sign_mac(char *outbuf)
+{
+ /* Check if it's a non-session message. */
+ if(CVAL(outbuf,0)) {
+ return;
+ }
+
+ srv_sign_info.sign_outgoing_message(outbuf, &srv_sign_info);
+}
+
+/***********************************************************
+ Called by server to defer an outgoing packet.
+************************************************************/
+
+void srv_defer_sign_response(uint16 mid)
+{
+ struct smb_basic_signing_context *data;
+
+ if (!srv_sign_info.doing_signing)
+ return;
+
+ data = (struct smb_basic_signing_context *)srv_sign_info.signing_context;
+
+ if (!data)
+ return;
+
+ /*
+ * Ensure we only store this mid reply once...
+ */
+
+ store_sequence_for_reply(&data->outstanding_packet_list, mid,
+ data->send_seq_num-1);
+}
+
+/***********************************************************
+ Called to remove sequence records when a deferred packet is
+ cancelled by mid. This should never find one....
+************************************************************/
+
+void srv_cancel_sign_response(uint16 mid)
+{
+ struct smb_basic_signing_context *data;
+ uint32 dummy_seq;
+
+ if (!srv_sign_info.doing_signing)
+ return;
+
+ data = (struct smb_basic_signing_context *)srv_sign_info.signing_context;
+
+ if (!data)
+ return;
+
+ DEBUG(10,("srv_cancel_sign_response: for mid %u\n", (unsigned int)mid ));
+
+ while (get_sequence_for_reply(&data->outstanding_packet_list, mid, &dummy_seq))
+ ;
+
+ /* cancel doesn't send a reply so doesn't burn a sequence number. */
+ data->send_seq_num -= 1;
+}
+
+/***********************************************************
+ Called by server negprot when signing has been negotiated.
+************************************************************/
+
+void srv_set_signing_negotiated(void)
+{
+ srv_sign_info.allow_smb_signing = True;
+ srv_sign_info.negotiated_smb_signing = True;
+ if (lp_server_signing() == Required)
+ srv_sign_info.mandatory_signing = True;
+
+ srv_sign_info.sign_outgoing_message = temp_sign_outgoing_message;
+ srv_sign_info.check_incoming_message = temp_check_incoming_message;
+ srv_sign_info.free_signing_context = temp_free_signing_context;
+}
+
+/***********************************************************
+ Returns whether signing is active. We can't use sendfile or raw
+ reads/writes if it is.
+************************************************************/
+
+bool srv_is_signing_active(void)
+{
+ return srv_sign_info.doing_signing;
+}
+
+
+/***********************************************************
+ Returns whether signing is negotiated. We can't use it unless it was
+ in the negprot.
+************************************************************/
+
+bool srv_is_signing_negotiated(void)
+{
+ return srv_sign_info.negotiated_smb_signing;
+}
+
+/***********************************************************
+ Returns whether signing is actually happening
+************************************************************/
+
+bool srv_signing_started(void)
+{
+ struct smb_basic_signing_context *data;
+
+ if (!srv_sign_info.doing_signing) {
+ return False;
+ }
+
+ data = (struct smb_basic_signing_context *)srv_sign_info.signing_context;
+ if (!data)
+ return False;
+
+ if (data->send_seq_num == 0) {
+ return False;
+ }
+
+ return True;
+}
+
+/***********************************************************
+ Turn on signing from this packet onwards.
+************************************************************/
+
+void srv_set_signing(const DATA_BLOB user_session_key, const DATA_BLOB response)
+{
+ struct smb_basic_signing_context *data;
+
+ if (!user_session_key.length)
+ return;
+
+ if (!srv_sign_info.negotiated_smb_signing && !srv_sign_info.mandatory_signing) {
+ DEBUG(5,("srv_set_signing: signing negotiated = %u, mandatory_signing = %u. Not allowing smb signing.\n",
+ (unsigned int)srv_sign_info.negotiated_smb_signing,
+ (unsigned int)srv_sign_info.mandatory_signing ));
+ return;
+ }
+
+ /* Once we've turned on, ignore any more sessionsetups. */
+ if (srv_sign_info.doing_signing) {
+ return;
+ }
+
+ if (srv_sign_info.free_signing_context)
+ srv_sign_info.free_signing_context(&srv_sign_info);
+
+ srv_sign_info.doing_signing = True;
+
+ data = SMB_XMALLOC_P(struct smb_basic_signing_context);
+ memset(data, '\0', sizeof(*data));
+
+ srv_sign_info.signing_context = data;
+
+ data->mac_key = data_blob(NULL, response.length + user_session_key.length);
+
+ memcpy(&data->mac_key.data[0], user_session_key.data, user_session_key.length);
+ if (response.length)
+ memcpy(&data->mac_key.data[user_session_key.length],response.data, response.length);
+
+ dump_data_pw("MAC ssession key is:\n", data->mac_key.data, data->mac_key.length);
+
+ DEBUG(3,("srv_set_signing: turning on SMB signing: signing negotiated = %s, mandatory_signing = %s.\n",
+ BOOLSTR(srv_sign_info.negotiated_smb_signing),
+ BOOLSTR(srv_sign_info.mandatory_signing) ));
+
+ /* Initialise the sequence number */
+ data->send_seq_num = 0;
+
+ /* Initialise the list of outstanding packets */
+ data->outstanding_packet_list = NULL;
+
+ srv_sign_info.sign_outgoing_message = srv_sign_outgoing_message;
+ srv_sign_info.check_incoming_message = srv_check_incoming_message;
+ srv_sign_info.free_signing_context = simple_free_signing_context;
+}
diff --git a/source3/libsmb/smbdes.c b/source3/libsmb/smbdes.c
new file mode 100644
index 0000000000..98d5cd05b7
--- /dev/null
+++ b/source3/libsmb/smbdes.c
@@ -0,0 +1,420 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* NOTES:
+
+ This code makes no attempt to be fast! In fact, it is a very
+ slow implementation
+
+ This code is NOT a complete DES implementation. It implements only
+ the minimum necessary for SMB authentication, as used by all SMB
+ products (including every copy of Microsoft Windows95 ever sold)
+
+ In particular, it can only do a unchained forward DES pass. This
+ means it is not possible to use this code for encryption/decryption
+ of data, instead it is only useful as a "hash" algorithm.
+
+ There is no entry point into this code that allows normal DES operation.
+
+ I believe this means that this code does not come under ITAR
+ regulations but this is NOT a legal opinion. If you are concerned
+ about the applicability of ITAR regulations to this code then you
+ should confirm it for yourself (and maybe let me know if you come
+ up with a different answer to the one above)
+*/
+
+
+#define uchar unsigned char
+
+static const 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 const 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 const 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 const 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 const 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 const 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 const uchar sc[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
+
+static const 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, const char *in, const 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 x_or(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);
+
+ x_or(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);
+
+ x_or(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);
+}
+
+/* Convert a 7 byte string to an 8 byte key. */
+static void str_to_key(const unsigned char str[7], unsigned char key[8])
+{
+ 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);
+ }
+}
+
+
+void des_crypt56(unsigned char *out, const unsigned char *in, const unsigned char *key, int forw)
+{
+ int i;
+ char outb[64];
+ char inb[64];
+ char keyb[64];
+ unsigned char key2[8];
+
+ str_to_key(key, key2);
+
+ for (i=0;i<64;i++) {
+ inb[i] = (in[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
+ keyb[i] = (key2[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
+ outb[i] = 0;
+ }
+
+ dohash(outb, inb, keyb, forw);
+
+ for (i=0;i<8;i++) {
+ out[i] = 0;
+ }
+
+ for (i=0;i<64;i++) {
+ if (outb[i])
+ out[i/8] |= (1<<(7-(i%8)));
+ }
+}
+
+void E_P16(const unsigned char *p14,unsigned char *p16)
+{
+ unsigned char sp8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
+ des_crypt56(p16, sp8, p14, 1);
+ des_crypt56(p16+8, sp8, p14+7, 1);
+}
+
+void E_P24(const unsigned char *p21, const unsigned char *c8, unsigned char *p24)
+{
+ des_crypt56(p24, c8, p21, 1);
+ des_crypt56(p24+8, c8, p21+7, 1);
+ des_crypt56(p24+16, c8, p21+14, 1);
+}
+
+void D_P16(const unsigned char *p14, const unsigned char *in, unsigned char *out)
+{
+ des_crypt56(out, in, p14, 0);
+ des_crypt56(out+8, in+8, p14+7, 0);
+}
+
+void E_old_pw_hash( unsigned char *p14, const unsigned char *in, unsigned char *out)
+{
+ des_crypt56(out, in, p14, 1);
+ des_crypt56(out+8, in+8, p14+7, 1);
+}
+
+/* forward des encryption with a 128 bit key */
+void des_crypt128(unsigned char out[8], const unsigned char in[8], const unsigned char key[16])
+{
+ unsigned char buf[8];
+
+ des_crypt56(buf, in, key, 1);
+ des_crypt56(out, buf, key+9, 1);
+}
+
+/* forward des encryption with a 64 bit key */
+void des_crypt64(unsigned char out[8], const unsigned char in[8], const unsigned char key[8])
+{
+ unsigned char buf[8];
+ unsigned char key2[8];
+
+ memset(key2,'\0',8);
+ des_crypt56(buf, in, key, 1);
+ key2[0] = key[7];
+ des_crypt56(out, buf, key2, 1);
+}
+
+/* des encryption with a 112 bit (14 byte) key */
+/* Note that if the forw is 1, and key is actually 8 bytes of key, followed by 6 bytes of zeros,
+ this is identical to des_crypt64(). JRA. */
+
+void des_crypt112(unsigned char out[8], const unsigned char in[8], const unsigned char key[14], int forw)
+{
+ unsigned char buf[8];
+ des_crypt56(buf, in, key, forw);
+ des_crypt56(out, buf, key+7, forw);
+}
+
+void cred_hash3(unsigned char *out, const unsigned char *in, const unsigned char *key, int forw)
+{
+ unsigned char key2[8];
+
+ memset(key2,'\0',8);
+ des_crypt56(out, in, key, forw);
+ key2[0] = key[7];
+ des_crypt56(out + 8, in + 8, key2, forw);
+}
+
+/* des encryption of a 16 byte lump of data with a 112 bit key */
+/* Note that if the key is actually 8 bytes of key, followed by 6 bytes of zeros,
+ this is identical to cred_hash3(). JRA. */
+
+void des_crypt112_16(unsigned char out[16], unsigned char in[16], const unsigned char key[14], int forw)
+{
+ des_crypt56(out, in, key, forw);
+ des_crypt56(out + 8, in + 8, key+7, forw);
+}
+
+/*****************************************************************
+ arc4 crypt/decrypt with a 16 byte key.
+*****************************************************************/
+
+void SamOEMhash( unsigned char *data, const unsigned char key[16], size_t len)
+{
+ unsigned char arc4_state[258];
+
+ smb_arc4_init(arc4_state, key, 16);
+ smb_arc4_crypt(arc4_state, data, len);
+}
+
+void SamOEMhashBlob( unsigned char *data, size_t len, DATA_BLOB *key)
+{
+ unsigned char arc4_state[258];
+
+ smb_arc4_init(arc4_state, key->data, key->length);
+ smb_arc4_crypt(arc4_state, data, len);
+}
+
+/* Decode a sam password hash into a password. The password hash is the
+ same method used to store passwords in the NT registry. The DES key
+ used is based on the RID of the user. */
+
+void sam_pwd_hash(unsigned int rid, const uchar *in, uchar *out, int forw)
+{
+ uchar s[14];
+
+ s[0] = s[4] = s[8] = s[12] = (uchar)(rid & 0xFF);
+ s[1] = s[5] = s[9] = s[13] = (uchar)((rid >> 8) & 0xFF);
+ s[2] = s[6] = s[10] = (uchar)((rid >> 16) & 0xFF);
+ s[3] = s[7] = s[11] = (uchar)((rid >> 24) & 0xFF);
+
+ des_crypt56(out, in, s, forw);
+ des_crypt56(out+8, in+8, s+7, forw);
+}
diff --git a/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c
new file mode 100644
index 0000000000..0742976635
--- /dev/null
+++ b/source3/libsmb/smbencrypt.c
@@ -0,0 +1,898 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1998
+ Modified by Jeremy Allison 1995.
+ Copyright (C) Jeremy Allison 1995-2000.
+ Copyright (C) Luke Kennethc Casson Leighton 1996-2000.
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "byteorder.h"
+
+void SMBencrypt_hash(const uchar lm_hash[16], const uchar *c8, uchar p24[24])
+{
+ uchar p21[21];
+
+ memset(p21,'\0',21);
+ memcpy(p21, lm_hash, 16);
+
+ SMBOWFencrypt(p21, c8, p24);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("SMBencrypt_hash: lm#, challenge, response\n"));
+ dump_data(100, p21, 16);
+ dump_data(100, c8, 8);
+ dump_data(100, p24, 24);
+#endif
+}
+
+/*
+ This implements the X/Open SMB password encryption
+ It takes a password ('unix' string), a 8 byte "crypt key"
+ and puts 24 bytes of encrypted password into p24
+
+ Returns False if password must have been truncated to create LM hash
+*/
+
+bool SMBencrypt(const char *passwd, const uchar *c8, uchar p24[24])
+{
+ bool ret;
+ uchar lm_hash[16];
+
+ ret = E_deshash(passwd, lm_hash);
+ SMBencrypt_hash(lm_hash, c8, p24);
+ return ret;
+}
+
+/**
+ * Creates the MD4 Hash of the users password in NT UNICODE.
+ * @param passwd password in 'unix' charset.
+ * @param p16 return password hashed with md4, caller allocated 16 byte buffer
+ */
+
+void E_md4hash(const char *passwd, uchar p16[16])
+{
+ int len;
+ smb_ucs2_t wpwd[129];
+
+ /* Password must be converted to NT unicode - null terminated. */
+ push_ucs2(NULL, wpwd, (const char *)passwd, 256, STR_UNICODE|STR_NOALIGN|STR_TERMINATE);
+ /* Calculate length in bytes */
+ len = strlen_w(wpwd) * sizeof(int16);
+
+ mdfour(p16, (unsigned char *)wpwd, len);
+ ZERO_STRUCT(wpwd);
+}
+
+/**
+ * Creates the MD5 Hash of a combination of 16 byte salt and 16 byte NT hash.
+ * @param 16 byte salt.
+ * @param 16 byte NT hash.
+ * @param 16 byte return hashed with md5, caller allocated 16 byte buffer
+ */
+
+void E_md5hash(const uchar salt[16], const uchar nthash[16], uchar hash_out[16])
+{
+ struct MD5Context tctx;
+ uchar array[32];
+
+ memset(hash_out, '\0', 16);
+ memcpy(array, salt, 16);
+ memcpy(&array[16], nthash, 16);
+ MD5Init(&tctx);
+ MD5Update(&tctx, array, 32);
+ MD5Final(hash_out, &tctx);
+}
+
+/**
+ * Creates the DES forward-only Hash of the users password in DOS ASCII charset
+ * @param passwd password in 'unix' charset.
+ * @param p16 return password hashed with DES, caller allocated 16 byte buffer
+ * @return False if password was > 14 characters, and therefore may be incorrect, otherwise True
+ * @note p16 is filled in regardless
+ */
+
+bool E_deshash(const char *passwd, uchar p16[16])
+{
+ bool ret = True;
+ fstring dospwd;
+ ZERO_STRUCT(dospwd);
+
+ /* Password must be converted to DOS charset - null terminated, uppercase. */
+ push_ascii(dospwd, passwd, sizeof(dospwd), STR_UPPER|STR_TERMINATE);
+
+ /* Only the fisrt 14 chars are considered, password need not be null terminated. */
+ E_P16((const unsigned char *)dospwd, p16);
+
+ if (strlen(dospwd) > 14) {
+ ret = False;
+ }
+
+ ZERO_STRUCT(dospwd);
+
+ return ret;
+}
+
+/**
+ * Creates the MD4 and DES (LM) Hash of the users password.
+ * MD4 is of the NT Unicode, DES is of the DOS UPPERCASE password.
+ * @param passwd password in 'unix' charset.
+ * @param nt_p16 return password hashed with md4, caller allocated 16 byte buffer
+ * @param p16 return password hashed with des, caller allocated 16 byte buffer
+ */
+
+/* Does both the NT and LM owfs of a user's password */
+void nt_lm_owf_gen(const char *pwd, uchar nt_p16[16], uchar p16[16])
+{
+ /* Calculate the MD4 hash (NT compatible) of the password */
+ memset(nt_p16, '\0', 16);
+ E_md4hash(pwd, nt_p16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nt_lm_owf_gen: pwd, nt#\n"));
+ dump_data(120, (uint8 *)pwd, strlen(pwd));
+ dump_data(100, nt_p16, 16);
+#endif
+
+ E_deshash(pwd, (uchar *)p16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nt_lm_owf_gen: pwd, lm#\n"));
+ dump_data(120, (uint8 *)pwd, strlen(pwd));
+ dump_data(100, p16, 16);
+#endif
+}
+
+/* Does both the NTLMv2 owfs of a user's password */
+bool ntv2_owf_gen(const uchar owf[16],
+ const char *user_in, const char *domain_in,
+ bool upper_case_domain, /* Transform the domain into UPPER case */
+ uchar kr_buf[16])
+{
+ smb_ucs2_t *user;
+ smb_ucs2_t *domain;
+
+ size_t user_byte_len;
+ size_t domain_byte_len;
+
+ HMACMD5Context ctx;
+
+ if (!push_ucs2_allocate(&user, user_in, &user_byte_len)) {
+ DEBUG(0, ("push_uss2_allocate() for user failed: %s\n",
+ strerror(errno)));
+ return False;
+ }
+
+ if (!push_ucs2_allocate(&domain, domain_in, &domain_byte_len)) {
+ DEBUG(0, ("push_uss2_allocate() for domain failed: %s\n",
+ strerror(errno)));
+ SAFE_FREE(user);
+ return False;
+ }
+
+ strupper_w(user);
+
+ if (upper_case_domain)
+ strupper_w(domain);
+
+ SMB_ASSERT(user_byte_len >= 2);
+ SMB_ASSERT(domain_byte_len >= 2);
+
+ /* We don't want null termination */
+ user_byte_len = user_byte_len - 2;
+ domain_byte_len = domain_byte_len - 2;
+
+ hmac_md5_init_limK_to_64(owf, 16, &ctx);
+ hmac_md5_update((const unsigned char *)user, user_byte_len, &ctx);
+ hmac_md5_update((const unsigned char *)domain, domain_byte_len, &ctx);
+ hmac_md5_final(kr_buf, &ctx);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("ntv2_owf_gen: user, domain, owfkey, kr\n"));
+ dump_data(100, (uint8 *)user, user_byte_len);
+ dump_data(100, (uint8 *)domain, domain_byte_len);
+ dump_data(100, (uint8 *)owf, 16);
+ dump_data(100, (uint8 *)kr_buf, 16);
+#endif
+
+ SAFE_FREE(user);
+ SAFE_FREE(domain);
+ return True;
+}
+
+/* Does the des encryption from the NT or LM MD4 hash. */
+void SMBOWFencrypt(const uchar passwd[16], const uchar *c8, uchar p24[24])
+{
+ uchar p21[21];
+
+ ZERO_STRUCT(p21);
+
+ memcpy(p21, passwd, 16);
+ E_P24(p21, c8, p24);
+}
+
+/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
+void NTLMSSPOWFencrypt(const uchar passwd[8], const uchar *ntlmchalresp, uchar p24[24])
+{
+ uchar p21[21];
+
+ memset(p21,'\0',21);
+ memcpy(p21, passwd, 8);
+ memset(p21 + 8, 0xbd, 8);
+
+ E_P24(p21, ntlmchalresp, p24);
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("NTLMSSPOWFencrypt: p21, c8, p24\n"));
+ dump_data(100, p21, 21);
+ dump_data(100, ntlmchalresp, 8);
+ dump_data(100, p24, 24);
+#endif
+}
+
+
+/* Does the des encryption. */
+
+void SMBNTencrypt_hash(const uchar nt_hash[16], uchar *c8, uchar *p24)
+{
+ uchar p21[21];
+
+ memset(p21,'\0',21);
+ memcpy(p21, nt_hash, 16);
+ SMBOWFencrypt(p21, c8, p24);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("SMBNTencrypt: nt#, challenge, response\n"));
+ dump_data(100, p21, 16);
+ dump_data(100, c8, 8);
+ dump_data(100, p24, 24);
+#endif
+}
+
+/* Does the NT MD4 hash then des encryption. Plaintext version of the above. */
+
+void SMBNTencrypt(const char *passwd, uchar *c8, uchar *p24)
+{
+ uchar nt_hash[16];
+ E_md4hash(passwd, nt_hash);
+ SMBNTencrypt_hash(nt_hash, c8, p24);
+}
+
+/* Does the md5 encryption from the Key Response for NTLMv2. */
+void SMBOWFencrypt_ntv2(const uchar kr[16],
+ const DATA_BLOB *srv_chal,
+ const DATA_BLOB *cli_chal,
+ uchar resp_buf[16])
+{
+ HMACMD5Context ctx;
+
+ hmac_md5_init_limK_to_64(kr, 16, &ctx);
+ hmac_md5_update(srv_chal->data, srv_chal->length, &ctx);
+ hmac_md5_update(cli_chal->data, cli_chal->length, &ctx);
+ hmac_md5_final(resp_buf, &ctx);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, cli_chal, resp_buf\n"));
+ dump_data(100, srv_chal->data, srv_chal->length);
+ dump_data(100, cli_chal->data, cli_chal->length);
+ dump_data(100, resp_buf, 16);
+#endif
+}
+
+void SMBsesskeygen_ntv2(const uchar kr[16],
+ const uchar * nt_resp, uint8 sess_key[16])
+{
+ /* a very nice, 128 bit, variable session key */
+
+ HMACMD5Context ctx;
+
+ hmac_md5_init_limK_to_64(kr, 16, &ctx);
+ hmac_md5_update(nt_resp, 16, &ctx);
+ hmac_md5_final((unsigned char *)sess_key, &ctx);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_ntv2:\n"));
+ dump_data(100, sess_key, 16);
+#endif
+}
+
+void SMBsesskeygen_ntv1(const uchar kr[16],
+ const uchar * nt_resp, uint8 sess_key[16])
+{
+ /* yes, this session key does not change - yes, this
+ is a problem - but it is 128 bits */
+
+ mdfour((unsigned char *)sess_key, kr, 16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_ntv1:\n"));
+ dump_data(100, sess_key, 16);
+#endif
+}
+
+void SMBsesskeygen_lm_sess_key(const uchar lm_hash[16],
+ const uchar lm_resp[24], /* only uses 8 */
+ uint8 sess_key[16])
+{
+ uchar p24[24];
+ uchar partial_lm_hash[16];
+
+ memcpy(partial_lm_hash, lm_hash, 8);
+ memset(partial_lm_hash + 8, 0xbd, 8);
+
+ SMBOWFencrypt(partial_lm_hash, lm_resp, p24);
+
+ memcpy(sess_key, p24, 16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_lmv1_jerry:\n"));
+ dump_data(100, sess_key, 16);
+#endif
+}
+
+DATA_BLOB NTLMv2_generate_names_blob(const char *hostname,
+ const char *domain)
+{
+ DATA_BLOB names_blob = data_blob_null;
+
+ msrpc_gen(&names_blob, "aaa",
+ NTLMSSP_NAME_TYPE_DOMAIN, domain,
+ NTLMSSP_NAME_TYPE_SERVER, hostname,
+ 0, "");
+ return names_blob;
+}
+
+static DATA_BLOB NTLMv2_generate_client_data(const DATA_BLOB *names_blob)
+{
+ uchar client_chal[8];
+ DATA_BLOB response = data_blob_null;
+ char long_date[8];
+
+ generate_random_buffer(client_chal, sizeof(client_chal));
+
+ put_long_date(long_date, time(NULL));
+
+ /* See http://www.ubiqx.org/cifs/SMB.html#SMB.8.5 */
+
+ msrpc_gen(&response, "ddbbdb",
+ 0x00000101, /* Header */
+ 0, /* 'Reserved' */
+ long_date, 8, /* Timestamp */
+ client_chal, 8, /* client challenge */
+ 0, /* Unknown */
+ names_blob->data, names_blob->length); /* End of name list */
+
+ return response;
+}
+
+static DATA_BLOB NTLMv2_generate_response(const uchar ntlm_v2_hash[16],
+ const DATA_BLOB *server_chal,
+ const DATA_BLOB *names_blob)
+{
+ uchar ntlmv2_response[16];
+ DATA_BLOB ntlmv2_client_data;
+ DATA_BLOB final_response;
+
+ /* NTLMv2 */
+ /* generate some data to pass into the response function - including
+ the hostname and domain name of the server */
+ ntlmv2_client_data = NTLMv2_generate_client_data(names_blob);
+
+ /* Given that data, and the challenge from the server, generate a response */
+ SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, &ntlmv2_client_data, ntlmv2_response);
+
+ final_response = data_blob(NULL, sizeof(ntlmv2_response) + ntlmv2_client_data.length);
+
+ memcpy(final_response.data, ntlmv2_response, sizeof(ntlmv2_response));
+
+ memcpy(final_response.data+sizeof(ntlmv2_response),
+ ntlmv2_client_data.data, ntlmv2_client_data.length);
+
+ data_blob_free(&ntlmv2_client_data);
+
+ return final_response;
+}
+
+static DATA_BLOB LMv2_generate_response(const uchar ntlm_v2_hash[16],
+ const DATA_BLOB *server_chal)
+{
+ uchar lmv2_response[16];
+ DATA_BLOB lmv2_client_data = data_blob(NULL, 8);
+ DATA_BLOB final_response = data_blob(NULL, 24);
+
+ /* LMv2 */
+ /* client-supplied random data */
+ generate_random_buffer(lmv2_client_data.data, lmv2_client_data.length);
+
+ /* Given that data, and the challenge from the server, generate a response */
+ SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, &lmv2_client_data, lmv2_response);
+ memcpy(final_response.data, lmv2_response, sizeof(lmv2_response));
+
+ /* after the first 16 bytes is the random data we generated above,
+ so the server can verify us with it */
+ memcpy(final_response.data+sizeof(lmv2_response),
+ lmv2_client_data.data, lmv2_client_data.length);
+
+ data_blob_free(&lmv2_client_data);
+
+ return final_response;
+}
+
+bool SMBNTLMv2encrypt_hash(const char *user, const char *domain, const uchar nt_hash[16],
+ const DATA_BLOB *server_chal,
+ const DATA_BLOB *names_blob,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *user_session_key)
+{
+ uchar ntlm_v2_hash[16];
+
+ /* We don't use the NT# directly. Instead we use it mashed up with
+ the username and domain.
+ This prevents username swapping during the auth exchange
+ */
+ if (!ntv2_owf_gen(nt_hash, user, domain, False, ntlm_v2_hash)) {
+ return False;
+ }
+
+ if (nt_response) {
+ *nt_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal,
+ names_blob);
+ if (user_session_key) {
+ *user_session_key = data_blob(NULL, 16);
+
+ /* The NTLMv2 calculations also provide a session key, for signing etc later */
+ /* use only the first 16 bytes of nt_response for session key */
+ SMBsesskeygen_ntv2(ntlm_v2_hash, nt_response->data, user_session_key->data);
+ }
+ }
+
+ /* LMv2 */
+
+ if (lm_response) {
+ *lm_response = LMv2_generate_response(ntlm_v2_hash, server_chal);
+ }
+
+ return True;
+}
+
+/* Plaintext version of the above. */
+
+bool SMBNTLMv2encrypt(const char *user, const char *domain, const char *password,
+ const DATA_BLOB *server_chal,
+ const DATA_BLOB *names_blob,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *user_session_key)
+{
+ uchar nt_hash[16];
+ E_md4hash(password, nt_hash);
+
+ return SMBNTLMv2encrypt_hash(user, domain, nt_hash,
+ server_chal,
+ names_blob,
+ lm_response, nt_response,
+ user_session_key);
+}
+
+/***********************************************************
+ encode a password buffer with a unicode password. The buffer
+ is filled with random data to make it harder to attack.
+************************************************************/
+bool encode_pw_buffer(uint8 buffer[516], const char *password, int string_flags)
+{
+ uchar new_pw[512];
+ size_t new_pw_len;
+
+ /* the incoming buffer can be any alignment. */
+ string_flags |= STR_NOALIGN;
+
+ new_pw_len = push_string(NULL, new_pw,
+ password,
+ sizeof(new_pw), string_flags);
+
+ memcpy(&buffer[512 - new_pw_len], new_pw, new_pw_len);
+
+ generate_random_buffer(buffer, 512 - new_pw_len);
+
+ /*
+ * The length of the new password is in the last 4 bytes of
+ * the data buffer.
+ */
+ SIVAL(buffer, 512, new_pw_len);
+ ZERO_STRUCT(new_pw);
+ return True;
+}
+
+
+/***********************************************************
+ decode a password buffer
+ *new_pw_len is the length in bytes of the possibly mulitbyte
+ returned password including termination.
+************************************************************/
+
+bool decode_pw_buffer(TALLOC_CTX *ctx,
+ uint8 in_buffer[516],
+ char **pp_new_pwrd,
+ uint32 *new_pw_len,
+ int string_flags)
+{
+ int byte_len=0;
+
+ *pp_new_pwrd = NULL;
+ *new_pw_len = 0;
+
+ /* the incoming buffer can be any alignment. */
+ string_flags |= STR_NOALIGN;
+
+ /*
+ Warning !!! : This function is called from some rpc call.
+ The password IN the buffer may be a UNICODE string.
+ The password IN new_pwrd is an ASCII string
+ If you reuse that code somewhere else check first.
+ */
+
+ /* The length of the new password is in the last 4 bytes of the data buffer. */
+
+ byte_len = IVAL(in_buffer, 512);
+
+#ifdef DEBUG_PASSWORD
+ dump_data(100, in_buffer, 516);
+#endif
+
+ /* Password cannot be longer than the size of the password buffer */
+ if ( (byte_len < 0) || (byte_len > 512)) {
+ DEBUG(0, ("decode_pw_buffer: incorrect password length (%d).\n", byte_len));
+ DEBUG(0, ("decode_pw_buffer: check that 'encrypt passwords = yes'\n"));
+ return false;
+ }
+
+ /* decode into the return buffer. */
+ *new_pw_len = pull_string_talloc(ctx,
+ NULL,
+ 0,
+ pp_new_pwrd,
+ &in_buffer[512 - byte_len],
+ byte_len,
+ string_flags);
+
+ if (!*pp_new_pwrd || *new_pw_len == 0) {
+ DEBUG(0, ("decode_pw_buffer: pull_string_talloc failed\n"));
+ return false;
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("decode_pw_buffer: new_pwrd: "));
+ dump_data(100, (uint8 *)*pp_new_pwrd, *new_pw_len);
+ DEBUG(100,("multibyte len:%d\n", *new_pw_len));
+ DEBUG(100,("original char len:%d\n", byte_len/2));
+#endif
+
+ return true;
+}
+
+/***********************************************************
+ Decode an arc4 encrypted password change buffer.
+************************************************************/
+
+void encode_or_decode_arc4_passwd_buffer(unsigned char pw_buf[532], const DATA_BLOB *psession_key)
+{
+ struct MD5Context tctx;
+ unsigned char key_out[16];
+
+ /* Confounder is last 16 bytes. */
+
+ MD5Init(&tctx);
+ MD5Update(&tctx, &pw_buf[516], 16);
+ MD5Update(&tctx, psession_key->data, psession_key->length);
+ MD5Final(key_out, &tctx);
+ /* arc4 with key_out. */
+ SamOEMhash(pw_buf, key_out, 516);
+}
+
+/***********************************************************
+ Encrypt/Decrypt used for LSA secrets and trusted domain
+ passwords.
+************************************************************/
+
+void sess_crypt_blob(DATA_BLOB *out, const DATA_BLOB *in, const DATA_BLOB *session_key, int forward)
+{
+ int i, k;
+
+ for (i=0,k=0;
+ i<in->length;
+ i += 8, k += 7) {
+ uint8 bin[8], bout[8], key[7];
+
+ memset(bin, 0, 8);
+ memcpy(bin, &in->data[i], MIN(8, in->length-i));
+
+ if (k + 7 > session_key->length) {
+ k = (session_key->length - k);
+ }
+ memcpy(key, &session_key->data[k], 7);
+
+ des_crypt56(bout, bin, key, forward?1:0);
+
+ memcpy(&out->data[i], bout, MIN(8, in->length-i));
+ }
+}
+
+/* Decrypts password-blob with session-key
+ * @param nt_hash NT hash for the session key
+ * @param data_in DATA_BLOB encrypted password
+ *
+ * Returns cleartext password in CH_UNIX
+ * Caller must free the returned string
+ */
+
+char *decrypt_trustdom_secret(uint8_t nt_hash[16], DATA_BLOB *data_in)
+{
+ DATA_BLOB data_out, sess_key;
+ uint32_t length;
+ uint32_t version;
+ fstring cleartextpwd;
+
+ if (!data_in || !nt_hash)
+ return NULL;
+
+ /* hashed twice with md4 */
+ mdfour(nt_hash, nt_hash, 16);
+
+ /* 16-Byte session-key */
+ sess_key = data_blob(nt_hash, 16);
+ if (sess_key.data == NULL)
+ return NULL;
+
+ data_out = data_blob(NULL, data_in->length);
+ if (data_out.data == NULL)
+ return NULL;
+
+ /* decrypt with des3 */
+ sess_crypt_blob(&data_out, data_in, &sess_key, 0);
+
+ /* 4 Byte length, 4 Byte version */
+ length = IVAL(data_out.data, 0);
+ version = IVAL(data_out.data, 4);
+
+ if (length > data_in->length - 8) {
+ DEBUG(0,("decrypt_trustdom_secret: invalid length (%d)\n", length));
+ return NULL;
+ }
+
+ if (version != 1) {
+ DEBUG(0,("decrypt_trustdom_secret: unknown version number (%d)\n", version));
+ return NULL;
+ }
+
+ rpcstr_pull(cleartextpwd, data_out.data + 8, sizeof(fstring), length, 0 );
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("decrypt_trustdom_secret: length is: %d, version is: %d, password is: %s\n",
+ length, version, cleartextpwd));
+#endif
+
+ data_blob_free(&data_out);
+ data_blob_free(&sess_key);
+
+ return SMB_STRDUP(cleartextpwd);
+
+}
+
+/* encode a wkssvc_PasswordBuffer:
+ *
+ * similar to samr_CryptPasswordEx. Different: 8byte confounder (instead of
+ * 16byte), confounder in front of the 516 byte buffer (instead of after that
+ * buffer), calling MD5Update() first with session_key and then with confounder
+ * (vice versa in samr) - Guenther */
+
+void encode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx,
+ const char *pwd,
+ DATA_BLOB *session_key,
+ struct wkssvc_PasswordBuffer **pwd_buf)
+{
+ uint8_t buffer[516];
+ struct MD5Context ctx;
+ struct wkssvc_PasswordBuffer *my_pwd_buf = NULL;
+ DATA_BLOB confounded_session_key;
+ int confounder_len = 8;
+ uint8_t confounder[8];
+
+ my_pwd_buf = talloc_zero(mem_ctx, struct wkssvc_PasswordBuffer);
+ if (!my_pwd_buf) {
+ return;
+ }
+
+ confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16);
+
+ encode_pw_buffer(buffer, pwd, STR_UNICODE);
+
+ generate_random_buffer((uint8_t *)confounder, confounder_len);
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, session_key->data, session_key->length);
+ MD5Update(&ctx, confounder, confounder_len);
+ MD5Final(confounded_session_key.data, &ctx);
+
+ SamOEMhashBlob(buffer, 516, &confounded_session_key);
+
+ memcpy(&my_pwd_buf->data[0], confounder, confounder_len);
+ memcpy(&my_pwd_buf->data[8], buffer, 516);
+
+ data_blob_free(&confounded_session_key);
+
+ *pwd_buf = my_pwd_buf;
+}
+
+WERROR decode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx,
+ struct wkssvc_PasswordBuffer *pwd_buf,
+ DATA_BLOB *session_key,
+ char **pwd)
+{
+ uint8_t buffer[516];
+ struct MD5Context ctx;
+ uint32_t pwd_len;
+
+ DATA_BLOB confounded_session_key;
+
+ int confounder_len = 8;
+ uint8_t confounder[8];
+
+ *pwd = NULL;
+
+ if (!pwd_buf) {
+ return WERR_BAD_PASSWORD;
+ }
+
+ if (session_key->length != 16) {
+ DEBUG(10,("invalid session key\n"));
+ return WERR_BAD_PASSWORD;
+ }
+
+ confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16);
+
+ memcpy(&confounder, &pwd_buf->data[0], confounder_len);
+ memcpy(&buffer, &pwd_buf->data[8], 516);
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, session_key->data, session_key->length);
+ MD5Update(&ctx, confounder, confounder_len);
+ MD5Final(confounded_session_key.data, &ctx);
+
+ SamOEMhashBlob(buffer, 516, &confounded_session_key);
+
+ if (!decode_pw_buffer(mem_ctx, buffer, pwd, &pwd_len, STR_UNICODE)) {
+ data_blob_free(&confounded_session_key);
+ return WERR_BAD_PASSWORD;
+ }
+
+ data_blob_free(&confounded_session_key);
+
+ return WERR_OK;
+}
+
+DATA_BLOB decrypt_drsuapi_blob(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *session_key,
+ bool rcrypt,
+ uint32_t rid,
+ const DATA_BLOB *buffer)
+{
+ DATA_BLOB confounder;
+ DATA_BLOB enc_buffer;
+
+ struct MD5Context md5;
+ uint8_t _enc_key[16];
+ DATA_BLOB enc_key;
+
+ DATA_BLOB dec_buffer;
+
+ uint32_t crc32_given;
+ uint32_t crc32_calc;
+ DATA_BLOB checked_buffer;
+
+ DATA_BLOB plain_buffer;
+
+ /*
+ * the combination "c[3] s[1] e[1] d[0]..."
+ * was successful!!!!!!!!!!!!!!!!!!!!!!!!!!
+ */
+
+ /*
+ * the first 16 bytes at the beginning are the confounder
+ * followed by the 4 byte crc32 checksum
+ */
+ if (buffer->length < 20) {
+ return data_blob_const(NULL, 0);
+ }
+ confounder = data_blob_const(buffer->data, 16);
+ enc_buffer = data_blob_const(buffer->data + 16, buffer->length - 16);
+
+ /*
+ * build the encryption key md5 over the session key followed
+ * by the confounder
+ *
+ * here the gensec session key is used and
+ * not the dcerpc ncacn_ip_tcp "SystemLibraryDTC" key!
+ */
+ enc_key = data_blob_const(_enc_key, sizeof(_enc_key));
+ MD5Init(&md5);
+ MD5Update(&md5, session_key->data, session_key->length);
+ MD5Update(&md5, confounder.data, confounder.length);
+ MD5Final(enc_key.data, &md5);
+
+ /*
+ * copy the encrypted buffer part and
+ * decrypt it using the created encryption key using arcfour
+ */
+ dec_buffer = data_blob_talloc(mem_ctx, enc_buffer.data, enc_buffer.length);
+ if (!dec_buffer.data) {
+ return data_blob_const(NULL, 0);
+ }
+ SamOEMhashBlob(dec_buffer.data, dec_buffer.length, &enc_key);
+
+ /*
+ * the first 4 byte are the crc32 checksum
+ * of the remaining bytes
+ */
+ crc32_given = IVAL(dec_buffer.data, 0);
+ crc32_calc = crc32_calc_buffer((const char *)dec_buffer.data + 4 , dec_buffer.length - 4);
+ if (crc32_given != crc32_calc) {
+ DEBUG(1,("CRC32: given[0x%08X] calc[0x%08X]\n",
+ crc32_given, crc32_calc));
+ return data_blob_const(NULL, 0);
+ }
+ checked_buffer = data_blob_talloc(mem_ctx, dec_buffer.data + 4, dec_buffer.length - 4);
+ if (!checked_buffer.data) {
+ return data_blob_const(NULL, 0);
+ }
+
+ /*
+ * some attributes seem to be in a usable form after this decryption
+ * (supplementalCredentials, priorValue, currentValue, trustAuthOutgoing,
+ * trustAuthIncoming, initialAuthOutgoing, initialAuthIncoming)
+ * At least supplementalCredentials contains plaintext
+ * like "Primary:Kerberos" (in unicode form)
+ *
+ * some attributes seem to have some additional encryption
+ * dBCSPwd, unicodePwd, ntPwdHistory, lmPwdHistory
+ *
+ * it's the sam_rid_crypt() function, as the value is constant,
+ * so it doesn't depend on sessionkeys.
+ */
+ if (rcrypt) {
+ uint32_t i, num_hashes;
+
+ if ((checked_buffer.length % 16) != 0) {
+ return data_blob_const(NULL, 0);
+ }
+
+ plain_buffer = data_blob_talloc(mem_ctx, checked_buffer.data, checked_buffer.length);
+ if (!plain_buffer.data) {
+ return data_blob_const(NULL, 0);
+ }
+
+ num_hashes = plain_buffer.length / 16;
+ for (i = 0; i < num_hashes; i++) {
+ uint32_t offset = i * 16;
+ sam_pwd_hash(rid, checked_buffer.data + offset, plain_buffer.data + offset, 0);
+ }
+ } else {
+ plain_buffer = checked_buffer;
+ }
+
+ return plain_buffer;
+}
+
+
diff --git a/source3/libsmb/smberr.c b/source3/libsmb/smberr.c
new file mode 100644
index 0000000000..f4a13983f0
--- /dev/null
+++ b/source3/libsmb/smberr.c
@@ -0,0 +1,266 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* error code stuff - put together by Merik Karman
+ merik@blackadder.dsh.oz.au */
+
+
+/* There is a big list of error codes and their meanings at:
+
+ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/errlist_7oz7.asp
+
+ and if you don't like MSDN try:
+
+ http://www.siris.gr/computers/library/error.htm
+
+*/
+
+typedef const struct
+{
+ const char *name;
+ int code;
+ const char *message;
+} err_code_struct;
+
+/* Dos Error Messages */
+err_code_struct dos_msgs[] = {
+ {"ERRbadfunc",ERRbadfunc,"Invalid function."},
+ {"ERRbadfile",ERRbadfile,"File not found."},
+ {"ERRbadpath",ERRbadpath,"Directory invalid."},
+ {"ERRnofids",ERRnofids,"No file descriptors available"},
+ {"ERRnoaccess",ERRnoaccess,"Access denied."},
+ {"ERRbadfid",ERRbadfid,"Invalid file handle."},
+ {"ERRbadmcb",ERRbadmcb,"Memory control blocks destroyed."},
+ {"ERRnomem",ERRnomem,"Insufficient server memory to perform the requested function."},
+ {"ERRbadmem",ERRbadmem,"Invalid memory block address."},
+ {"ERRbadenv",ERRbadenv,"Invalid environment."},
+ {"ERRbadformat",11,"Invalid format."},
+ {"ERRbadaccess",ERRbadaccess,"Invalid open mode."},
+ {"ERRbaddata",ERRbaddata,"Invalid data."},
+ {"ERRres",ERRres,"reserved."},
+ {"ERRbaddrive",ERRbaddrive,"Invalid drive specified."},
+ {"ERRremcd",ERRremcd,"A Delete Directory request attempted to remove the server's current directory."},
+ {"ERRdiffdevice",ERRdiffdevice,"Not same device."},
+ {"ERRnofiles",ERRnofiles,"A File Search command can find no more files matching the specified criteria."},
+ {"ERRbadshare",ERRbadshare,"The sharing mode specified for an Open conflicts with existing FIDs on the file."},
+ {"ERRlock",ERRlock,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
+ {"ERRunsup", ERRunsup, "The operation is unsupported"},
+ {"ERRnosuchshare", ERRnosuchshare, "You specified an invalid share name"},
+ {"ERRfilexists",ERRfilexists,"The file named in a Create Directory, Make New File or Link request already exists."},
+ {"ERRinvalidname",ERRinvalidname, "Invalid name"},
+ {"ERRbadpipe",ERRbadpipe,"Pipe invalid."},
+ {"ERRpipebusy",ERRpipebusy,"All instances of the requested pipe are busy."},
+ {"ERRpipeclosing",ERRpipeclosing,"Pipe close in progress."},
+ {"ERRnotconnected",ERRnotconnected,"No process on other end of pipe."},
+ {"ERRmoredata",ERRmoredata,"There is more data to be returned."},
+ {"ERRinvgroup",ERRinvgroup,"Invalid workgroup (try the -W option)"},
+ {"ERRlogonfailure",ERRlogonfailure,"Logon failure"},
+ {"ERRdiskfull",ERRdiskfull,"Disk full"},
+ {"ERRgeneral",ERRgeneral, "General failure"},
+ {"ERRbaddirectory", ERRbaddirectory, "Bad directory name"},
+ {"ERRunknownlevel",ERRunknownlevel, "Unknown info level"},
+ {NULL,-1,NULL}};
+
+/* Server Error Messages */
+err_code_struct server_msgs[] = {
+ {"ERRerror",1,"Non-specific error code."},
+ {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
+ {"ERRbadtype",3,"reserved."},
+ {"ERRaccess",4,"The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."},
+ {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
+ {"ERRinvnetname",6,"Invalid network name in tree connect."},
+ {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."},
+ {"ERRqfull",49,"Print queue full (files) -- returned by open print file."},
+ {"ERRqtoobig",50,"Print queue full -- no space."},
+ {"ERRqeof",51,"EOF on print queue dump."},
+ {"ERRinvpfid",52,"Invalid print file FID."},
+ {"ERRsmbcmd",64,"The server did not recognize the command received."},
+ {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
+ {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid combination of values."},
+ {"ERRreserved",68,"reserved."},
+ {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."},
+ {"ERRreserved",70,"reserved."},
+ {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
+ {"ERRpaused",81,"Server is paused."},
+ {"ERRmsgoff",82,"Not receiving messages."},
+ {"ERRnoroom",83,"No room to buffer message."},
+ {"ERRrmuns",87,"Too many remote user names."},
+ {"ERRtimeout",88,"Operation timed out."},
+ {"ERRnoresource",89,"No resources currently available for request."},
+ {"ERRtoomanyuids",90,"Too many UIDs active on this session."},
+ {"ERRbaduid",91,"The UID is not known as a valid ID on this session."},
+ {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
+ {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
+ {"ERRcontmpx",252,"Continue in MPX mode."},
+ {"ERRreserved",253,"reserved."},
+ {"ERRreserved",254,"reserved."},
+ {"ERRnosupport",0xFFFF,"Function not supported."},
+ {NULL,-1,NULL}};
+
+/* Hard Error Messages */
+err_code_struct hard_msgs[] = {
+ {"ERRnowrite",19,"Attempt to write on write-protected diskette."},
+ {"ERRbadunit",20,"Unknown unit."},
+ {"ERRnotready",21,"Drive not ready."},
+ {"ERRbadcmd",22,"Unknown command."},
+ {"ERRdata",23,"Data error (CRC)."},
+ {"ERRbadreq",24,"Bad request structure length."},
+ {"ERRseek",25 ,"Seek error."},
+ {"ERRbadmedia",26,"Unknown media type."},
+ {"ERRbadsector",27,"Sector not found."},
+ {"ERRnopaper",28,"Printer out of paper."},
+ {"ERRwrite",29,"Write fault."},
+ {"ERRread",30,"Read fault."},
+ {"ERRgeneral",31,"General failure."},
+ {"ERRbadshare",32,"An open conflicts with an existing open."},
+ {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
+ {"ERRwrongdisk",34,"The wrong disk was found in a drive."},
+ {"ERRFCBUnavail",35,"No FCBs are available to process request."},
+ {"ERRsharebufexc",36,"A sharing buffer has been exceeded."},
+ {NULL,-1,NULL}};
+
+
+const struct
+{
+ int code;
+ const char *e_class;
+ err_code_struct *err_msgs;
+} err_classes[] = {
+ {0,"SUCCESS",NULL},
+ {0x01,"ERRDOS",dos_msgs},
+ {0x02,"ERRSRV",server_msgs},
+ {0x03,"ERRHRD",hard_msgs},
+ {0x04,"ERRXOS",NULL},
+ {0xE1,"ERRRMX1",NULL},
+ {0xE2,"ERRRMX2",NULL},
+ {0xE3,"ERRRMX3",NULL},
+ {0xFF,"ERRCMD",NULL},
+ {-1,NULL,NULL}};
+
+
+/****************************************************************************
+return a SMB error name from a class and code
+****************************************************************************/
+const char *smb_dos_err_name(uint8 e_class, uint16 num)
+{
+ char *result;
+ int i,j;
+
+ for (i=0;err_classes[i].e_class;i++)
+ if (err_classes[i].code == e_class) {
+ if (err_classes[i].err_msgs) {
+ err_code_struct *err = err_classes[i].err_msgs;
+ for (j=0;err[j].name;j++)
+ if (num == err[j].code) {
+ return err[j].name;
+ }
+ }
+ result = talloc_asprintf(talloc_tos(), "%d", num);
+ SMB_ASSERT(result != NULL);
+ return result;
+ }
+
+ result = talloc_asprintf(talloc_tos(), "Error: Unknown error class "
+ "(%d,%d)", e_class,num);
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+/* Return a string for a DOS error */
+
+const char *get_dos_error_msg(WERROR result)
+{
+ uint16 errnum;
+
+ errnum = W_ERROR_V(result);
+
+ return smb_dos_err_name(ERRDOS, errnum);
+}
+
+/****************************************************************************
+return a SMB error class name as a string.
+****************************************************************************/
+const char *smb_dos_err_class(uint8 e_class)
+{
+ char *result;
+ int i;
+
+ for (i=0;err_classes[i].e_class;i++) {
+ if (err_classes[i].code == e_class) {
+ return err_classes[i].e_class;
+ }
+ }
+
+ result = talloc_asprintf(talloc_tos(), "Error: Unknown class (%d)",
+ e_class);
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+/****************************************************************************
+return a SMB string from an SMB buffer
+****************************************************************************/
+char *smb_dos_errstr(char *inbuf)
+{
+ char *result;
+ int e_class = CVAL(inbuf,smb_rcls);
+ int num = SVAL(inbuf,smb_err);
+ int i,j;
+
+ for (i=0;err_classes[i].e_class;i++)
+ if (err_classes[i].code == e_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)
+ result = talloc_asprintf(
+ talloc_tos(), "%s - %s (%s)",
+ err_classes[i].e_class,
+ err[j].name,err[j].message);
+ else
+ result = talloc_asprintf(
+ talloc_tos(), "%s - %s",
+ err_classes[i].e_class,
+ err[j].name);
+ goto done;
+ }
+ }
+
+ result = talloc_asprintf(talloc_tos(), "%s - %d",
+ err_classes[i].e_class, num);
+ goto done;
+ }
+
+ result = talloc_asprintf(talloc_tos(), "Error: Unknown error (%d,%d)",
+ e_class, num);
+ done:
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+/*****************************************************************************
+map a unix errno to a win32 error
+ *****************************************************************************/
+WERROR map_werror_from_unix(int error)
+{
+ NTSTATUS status = map_nt_error_from_unix(error);
+ return ntstatus_to_werror(status);
+}
diff --git a/source3/libsmb/spnego.c b/source3/libsmb/spnego.c
new file mode 100644
index 0000000000..57b2d8060b
--- /dev/null
+++ b/source3/libsmb/spnego.c
@@ -0,0 +1,346 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ RFC2478 Compliant SPNEGO implementation
+
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+static bool read_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
+{
+ ZERO_STRUCTP(token);
+
+ asn1_start_tag(asn1, ASN1_CONTEXT(0));
+ asn1_start_tag(asn1, ASN1_SEQUENCE(0));
+
+ while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
+ int i;
+
+ switch (asn1->data[asn1->ofs]) {
+ /* Read mechTypes */
+ case ASN1_CONTEXT(0):
+ asn1_start_tag(asn1, ASN1_CONTEXT(0));
+ asn1_start_tag(asn1, ASN1_SEQUENCE(0));
+
+ token->mechTypes = SMB_MALLOC_P(const char *);
+ for (i = 0; !asn1->has_error &&
+ 0 < asn1_tag_remaining(asn1); i++) {
+ char *p_oid = NULL;
+ token->mechTypes =
+ SMB_REALLOC_ARRAY(token->mechTypes, const char *, i + 2);
+ if (!token->mechTypes) {
+ asn1->has_error = True;
+ return False;
+ }
+ asn1_read_OID(asn1, &p_oid);
+ token->mechTypes[i] = p_oid;
+ }
+ token->mechTypes[i] = NULL;
+
+ asn1_end_tag(asn1);
+ asn1_end_tag(asn1);
+ break;
+ /* Read reqFlags */
+ case ASN1_CONTEXT(1):
+ asn1_start_tag(asn1, ASN1_CONTEXT(1));
+ asn1_read_Integer(asn1, &token->reqFlags);
+ token->reqFlags |= SPNEGO_REQ_FLAG;
+ asn1_end_tag(asn1);
+ break;
+ /* Read mechToken */
+ case ASN1_CONTEXT(2):
+ asn1_start_tag(asn1, ASN1_CONTEXT(2));
+ asn1_read_OctetString(asn1, &token->mechToken);
+ asn1_end_tag(asn1);
+ break;
+ /* Read mecListMIC */
+ case ASN1_CONTEXT(3):
+ asn1_start_tag(asn1, ASN1_CONTEXT(3));
+ if (asn1->data[asn1->ofs] == ASN1_OCTET_STRING) {
+ asn1_read_OctetString(asn1,
+ &token->mechListMIC);
+ } else {
+ /* RFC 2478 says we have an Octet String here,
+ but W2k sends something different... */
+ char *mechListMIC;
+ asn1_push_tag(asn1, ASN1_SEQUENCE(0));
+ asn1_push_tag(asn1, ASN1_CONTEXT(0));
+ asn1_read_GeneralString(asn1, &mechListMIC);
+ asn1_pop_tag(asn1);
+ asn1_pop_tag(asn1);
+
+ token->mechListMIC =
+ data_blob(mechListMIC, strlen(mechListMIC));
+ SAFE_FREE(mechListMIC);
+ }
+ asn1_end_tag(asn1);
+ break;
+ default:
+ asn1->has_error = True;
+ break;
+ }
+ }
+
+ asn1_end_tag(asn1);
+ asn1_end_tag(asn1);
+
+ return !asn1->has_error;
+}
+
+static bool write_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
+{
+ asn1_push_tag(asn1, ASN1_CONTEXT(0));
+ asn1_push_tag(asn1, ASN1_SEQUENCE(0));
+
+ /* Write mechTypes */
+ if (token->mechTypes && *token->mechTypes) {
+ int i;
+
+ asn1_push_tag(asn1, ASN1_CONTEXT(0));
+ asn1_push_tag(asn1, ASN1_SEQUENCE(0));
+ for (i = 0; token->mechTypes[i]; i++) {
+ asn1_write_OID(asn1, token->mechTypes[i]);
+ }
+ asn1_pop_tag(asn1);
+ asn1_pop_tag(asn1);
+ }
+
+ /* write reqFlags */
+ if (token->reqFlags & SPNEGO_REQ_FLAG) {
+ int flags = token->reqFlags & ~SPNEGO_REQ_FLAG;
+
+ asn1_push_tag(asn1, ASN1_CONTEXT(1));
+ asn1_write_Integer(asn1, flags);
+ asn1_pop_tag(asn1);
+ }
+
+ /* write mechToken */
+ if (token->mechToken.data) {
+ asn1_push_tag(asn1, ASN1_CONTEXT(2));
+ asn1_write_OctetString(asn1, token->mechToken.data,
+ token->mechToken.length);
+ asn1_pop_tag(asn1);
+ }
+
+ /* write mechListMIC */
+ if (token->mechListMIC.data) {
+ asn1_push_tag(asn1, ASN1_CONTEXT(3));
+#if 0
+ /* This is what RFC 2478 says ... */
+ asn1_write_OctetString(asn1, token->mechListMIC.data,
+ token->mechListMIC.length);
+#else
+ /* ... but unfortunately this is what Windows
+ sends/expects */
+ asn1_push_tag(asn1, ASN1_SEQUENCE(0));
+ asn1_push_tag(asn1, ASN1_CONTEXT(0));
+ asn1_push_tag(asn1, ASN1_GENERAL_STRING);
+ asn1_write(asn1, token->mechListMIC.data,
+ token->mechListMIC.length);
+ asn1_pop_tag(asn1);
+ asn1_pop_tag(asn1);
+ asn1_pop_tag(asn1);
+#endif
+ asn1_pop_tag(asn1);
+ }
+
+ asn1_pop_tag(asn1);
+ asn1_pop_tag(asn1);
+
+ return !asn1->has_error;
+}
+
+static bool read_negTokenTarg(ASN1_DATA *asn1, negTokenTarg_t *token)
+{
+ ZERO_STRUCTP(token);
+
+ asn1_start_tag(asn1, ASN1_CONTEXT(1));
+ asn1_start_tag(asn1, ASN1_SEQUENCE(0));
+
+ while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
+ switch (asn1->data[asn1->ofs]) {
+ case ASN1_CONTEXT(0):
+ asn1_start_tag(asn1, ASN1_CONTEXT(0));
+ asn1_start_tag(asn1, ASN1_ENUMERATED);
+ asn1_read_uint8(asn1, &token->negResult);
+ asn1_end_tag(asn1);
+ asn1_end_tag(asn1);
+ break;
+ case ASN1_CONTEXT(1):
+ asn1_start_tag(asn1, ASN1_CONTEXT(1));
+ asn1_read_OID(asn1, &token->supportedMech);
+ asn1_end_tag(asn1);
+ break;
+ case ASN1_CONTEXT(2):
+ asn1_start_tag(asn1, ASN1_CONTEXT(2));
+ asn1_read_OctetString(asn1, &token->responseToken);
+ asn1_end_tag(asn1);
+ break;
+ case ASN1_CONTEXT(3):
+ asn1_start_tag(asn1, ASN1_CONTEXT(3));
+ asn1_read_OctetString(asn1, &token->mechListMIC);
+ asn1_end_tag(asn1);
+ break;
+ default:
+ asn1->has_error = True;
+ break;
+ }
+ }
+
+ asn1_end_tag(asn1);
+ asn1_end_tag(asn1);
+
+ return !asn1->has_error;
+}
+
+static bool write_negTokenTarg(ASN1_DATA *asn1, negTokenTarg_t *token)
+{
+ asn1_push_tag(asn1, ASN1_CONTEXT(1));
+ asn1_push_tag(asn1, ASN1_SEQUENCE(0));
+
+ asn1_push_tag(asn1, ASN1_CONTEXT(0));
+ asn1_write_enumerated(asn1, token->negResult);
+ asn1_pop_tag(asn1);
+
+ if (token->supportedMech) {
+ asn1_push_tag(asn1, ASN1_CONTEXT(1));
+ asn1_write_OID(asn1, token->supportedMech);
+ asn1_pop_tag(asn1);
+ }
+
+ if (token->responseToken.data) {
+ asn1_push_tag(asn1, ASN1_CONTEXT(2));
+ asn1_write_OctetString(asn1, token->responseToken.data,
+ token->responseToken.length);
+ asn1_pop_tag(asn1);
+ }
+
+ if (token->mechListMIC.data) {
+ asn1_push_tag(asn1, ASN1_CONTEXT(3));
+ asn1_write_OctetString(asn1, token->mechListMIC.data,
+ token->mechListMIC.length);
+ asn1_pop_tag(asn1);
+ }
+
+ asn1_pop_tag(asn1);
+ asn1_pop_tag(asn1);
+
+ return !asn1->has_error;
+}
+
+ssize_t read_spnego_data(DATA_BLOB data, SPNEGO_DATA *token)
+{
+ ASN1_DATA asn1;
+ ssize_t ret = -1;
+
+ ZERO_STRUCTP(token);
+ ZERO_STRUCT(asn1);
+ asn1_load(&asn1, data);
+
+ switch (asn1.data[asn1.ofs]) {
+ case ASN1_APPLICATION(0):
+ asn1_start_tag(&asn1, ASN1_APPLICATION(0));
+ asn1_check_OID(&asn1, OID_SPNEGO);
+ if (read_negTokenInit(&asn1, &token->negTokenInit)) {
+ token->type = SPNEGO_NEG_TOKEN_INIT;
+ }
+ asn1_end_tag(&asn1);
+ break;
+ case ASN1_CONTEXT(1):
+ if (read_negTokenTarg(&asn1, &token->negTokenTarg)) {
+ token->type = SPNEGO_NEG_TOKEN_TARG;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!asn1.has_error) ret = asn1.ofs;
+ asn1_free(&asn1);
+
+ return ret;
+}
+
+ssize_t write_spnego_data(DATA_BLOB *blob, SPNEGO_DATA *spnego)
+{
+ ASN1_DATA asn1;
+ ssize_t ret = -1;
+
+ ZERO_STRUCT(asn1);
+
+ switch (spnego->type) {
+ case SPNEGO_NEG_TOKEN_INIT:
+ asn1_push_tag(&asn1, ASN1_APPLICATION(0));
+ asn1_write_OID(&asn1, OID_SPNEGO);
+ write_negTokenInit(&asn1, &spnego->negTokenInit);
+ asn1_pop_tag(&asn1);
+ break;
+ case SPNEGO_NEG_TOKEN_TARG:
+ write_negTokenTarg(&asn1, &spnego->negTokenTarg);
+ break;
+ default:
+ asn1.has_error = True;
+ break;
+ }
+
+ if (!asn1.has_error) {
+ *blob = data_blob(asn1.data, asn1.length);
+ ret = asn1.ofs;
+ }
+ asn1_free(&asn1);
+
+ return ret;
+}
+
+bool free_spnego_data(SPNEGO_DATA *spnego)
+{
+ bool ret = True;
+
+ if (!spnego) goto out;
+
+ switch(spnego->type) {
+ case SPNEGO_NEG_TOKEN_INIT:
+ if (spnego->negTokenInit.mechTypes) {
+ int i;
+ for (i = 0; spnego->negTokenInit.mechTypes[i]; i++) {
+ free(CONST_DISCARD(char *,spnego->negTokenInit.mechTypes[i]));
+ }
+ free(spnego->negTokenInit.mechTypes);
+ }
+ data_blob_free(&spnego->negTokenInit.mechToken);
+ data_blob_free(&spnego->negTokenInit.mechListMIC);
+ break;
+ case SPNEGO_NEG_TOKEN_TARG:
+ if (spnego->negTokenTarg.supportedMech) {
+ free(spnego->negTokenTarg.supportedMech);
+ }
+ data_blob_free(&spnego->negTokenTarg.responseToken);
+ data_blob_free(&spnego->negTokenTarg.mechListMIC);
+ break;
+ default:
+ ret = False;
+ break;
+ }
+ ZERO_STRUCTP(spnego);
+out:
+ return ret;
+}
diff --git a/source3/libsmb/trustdom_cache.c b/source3/libsmb/trustdom_cache.c
new file mode 100644
index 0000000000..6755de3814
--- /dev/null
+++ b/source3/libsmb/trustdom_cache.c
@@ -0,0 +1,338 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Trusted domain names cache on top of gencache.
+
+ Copyright (C) Rafal Szczesniak 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_ALL /* there's no proper class yet */
+
+#define TDOMKEY_FMT "TDOM/%s"
+#define TDOMTSKEY "TDOMCACHE/TIMESTAMP"
+
+
+/**
+ * @file trustdom_cache.c
+ *
+ * Implementation of trusted domain names cache useful when
+ * samba acts as domain member server. In such case, caching
+ * domain names currently trusted gives a performance gain
+ * because there's no need to query PDC each time we need
+ * list of trusted domains
+ **/
+
+
+/**
+ * Initialise trustdom name caching system. Call gencache
+ * initialisation routine to perform necessary activities.
+ *
+ * @return true upon successful cache initialisation or
+ * false if cache init failed
+ **/
+
+bool trustdom_cache_enable(void)
+{
+ /* Init trustdom cache by calling gencache initialisation */
+ if (!gencache_init()) {
+ DEBUG(2, ("trustdomcache_enable: Couldn't initialise trustdom cache on top of gencache.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/**
+ * Shutdown trustdom name caching system. Calls gencache
+ * shutdown function.
+ *
+ * @return true upon successful cache close or
+ * false if it failed
+ **/
+
+bool trustdom_cache_shutdown(void)
+{
+ /* Close trustdom cache by calling gencache shutdown */
+ if (!gencache_shutdown()) {
+ DEBUG(2, ("trustdomcache_shutdown: Couldn't shutdown trustdom cache on top of gencache.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/**
+ * Form up trustdom name key. It is based only
+ * on domain name now.
+ *
+ * @param name trusted domain name
+ * @return cache key for use in gencache mechanism
+ **/
+
+static char* trustdom_cache_key(const char* name)
+{
+ char* keystr = NULL;
+ asprintf_strupper_m(&keystr, TDOMKEY_FMT, name);
+
+ return keystr;
+}
+
+
+/**
+ * Store trusted domain in gencache as the domain name (key)
+ * and trusted domain's SID (value)
+ *
+ * @param name trusted domain name
+ * @param alt_name alternative trusted domain name (used in ADS domains)
+ * @param sid trusted domain's SID
+ * @param timeout cache entry expiration time
+ * @return true upon successful value storing or
+ * false if store attempt failed
+ **/
+
+bool trustdom_cache_store(char* name, char* alt_name, const DOM_SID *sid,
+ time_t timeout)
+{
+ char *key, *alt_key;
+ fstring sid_string;
+ bool ret;
+
+ /*
+ * we use gecache call to avoid annoying debug messages
+ * about initialised trustdom
+ */
+ if (!gencache_init())
+ return False;
+
+ DEBUG(5, ("trustdom_store: storing SID %s of domain %s\n",
+ sid_string_dbg(sid), name));
+
+ key = trustdom_cache_key(name);
+ alt_key = alt_name ? trustdom_cache_key(alt_name) : NULL;
+
+ /* Generate string representation domain SID */
+ sid_to_fstring(sid_string, sid);
+
+ /*
+ * try to put the names in the cache
+ */
+ if (alt_key) {
+ ret = gencache_set(alt_key, sid_string, timeout);
+ if ( ret ) {
+ ret = gencache_set(key, sid_string, timeout);
+ }
+ SAFE_FREE(alt_key);
+ SAFE_FREE(key);
+ return ret;
+ }
+
+ ret = gencache_set(key, sid_string, timeout);
+ SAFE_FREE(key);
+ return ret;
+}
+
+
+/**
+ * Fetch trusted domain's SID from the gencache.
+ * This routine can also be used to check whether given
+ * domain is currently trusted one.
+ *
+ * @param name trusted domain name
+ * @param sid trusted domain's SID to be returned
+ * @return true if entry is found or
+ * false if has expired/doesn't exist
+ **/
+
+bool trustdom_cache_fetch(const char* name, DOM_SID* sid)
+{
+ char *key = NULL, *value = NULL;
+ time_t timeout;
+
+ /* init the cache */
+ if (!gencache_init())
+ return False;
+
+ /* exit now if null pointers were passed as they're required further */
+ if (!sid)
+ return False;
+
+ /* prepare a key and get the value */
+ key = trustdom_cache_key(name);
+ if (!key)
+ return False;
+
+ if (!gencache_get(key, &value, &timeout)) {
+ DEBUG(5, ("no entry for trusted domain %s found.\n", name));
+ SAFE_FREE(key);
+ return False;
+ } else {
+ SAFE_FREE(key);
+ DEBUG(5, ("trusted domain %s found (%s)\n", name, value));
+ }
+
+ /* convert sid string representation into DOM_SID structure */
+ if(! string_to_sid(sid, value)) {
+ sid = NULL;
+ SAFE_FREE(value);
+ return False;
+ }
+
+ SAFE_FREE(value);
+ return True;
+}
+
+
+/*******************************************************************
+ fetch the timestamp from the last update
+*******************************************************************/
+
+uint32 trustdom_cache_fetch_timestamp( void )
+{
+ char *value = NULL;
+ time_t timeout;
+ uint32 timestamp;
+
+ /* init the cache */
+ if (!gencache_init())
+ return False;
+
+ if (!gencache_get(TDOMTSKEY, &value, &timeout)) {
+ DEBUG(5, ("no timestamp for trusted domain cache located.\n"));
+ SAFE_FREE(value);
+ return 0;
+ }
+
+ timestamp = atoi(value);
+
+ SAFE_FREE(value);
+ return timestamp;
+}
+
+/*******************************************************************
+ store the timestamp from the last update
+*******************************************************************/
+
+bool trustdom_cache_store_timestamp( uint32 t, time_t timeout )
+{
+ fstring value;
+
+ /* init the cache */
+ if (!gencache_init())
+ return False;
+
+ fstr_sprintf(value, "%d", t );
+
+ if (!gencache_set(TDOMTSKEY, value, timeout)) {
+ DEBUG(5, ("failed to set timestamp for trustdom_cache\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/**
+ * Delete single trustdom entry. Look at the
+ * gencache_iterate definition.
+ *
+ **/
+
+static void flush_trustdom_name(const char* key, const char *value, time_t timeout, void* dptr)
+{
+ gencache_del(key);
+ DEBUG(5, ("Deleting entry %s\n", key));
+}
+
+
+/**
+ * Flush all the trusted domains entries from the cache.
+ **/
+
+void trustdom_cache_flush(void)
+{
+ if (!gencache_init())
+ return;
+
+ /*
+ * iterate through each TDOM cache's entry and flush it
+ * by flush_trustdom_name function
+ */
+ gencache_iterate(flush_trustdom_name, NULL, trustdom_cache_key("*"));
+ DEBUG(5, ("Trusted domains cache flushed\n"));
+}
+
+/********************************************************************
+ update the trustdom_cache if needed
+********************************************************************/
+#define TRUSTDOM_UPDATE_INTERVAL 600
+
+void update_trustdom_cache( void )
+{
+ char **domain_names;
+ DOM_SID *dom_sids;
+ uint32 num_domains;
+ uint32 last_check;
+ int time_diff;
+ TALLOC_CTX *mem_ctx = NULL;
+ time_t now = time(NULL);
+ int i;
+
+ /* get the timestamp. We have to initialise it if the last timestamp == 0 */
+ if ( (last_check = trustdom_cache_fetch_timestamp()) == 0 )
+ trustdom_cache_store_timestamp(0, now+TRUSTDOM_UPDATE_INTERVAL);
+
+ time_diff = (int) (now - last_check);
+
+ if ( (time_diff > 0) && (time_diff < TRUSTDOM_UPDATE_INTERVAL) ) {
+ DEBUG(10,("update_trustdom_cache: not time to update trustdom_cache yet\n"));
+ return;
+ }
+
+ /* note that we don't lock the timestamp. This prevents this
+ smbd from blocking all other smbd daemons while we
+ enumerate the trusted domains */
+ trustdom_cache_store_timestamp(now, now+TRUSTDOM_UPDATE_INTERVAL);
+
+ if ( !(mem_ctx = talloc_init("update_trustdom_cache")) ) {
+ DEBUG(0,("update_trustdom_cache: talloc_init() failed!\n"));
+ goto done;
+ }
+
+ /* get the domains and store them */
+
+ if ( enumerate_domain_trusts(mem_ctx, lp_workgroup(), &domain_names,
+ &num_domains, &dom_sids)) {
+ for ( i=0; i<num_domains; i++ ) {
+ trustdom_cache_store( domain_names[i], NULL, &dom_sids[i],
+ now+TRUSTDOM_UPDATE_INTERVAL);
+ }
+ } else {
+ /* we failed to fetch the list of trusted domains - restore the old
+ timestamp */
+ trustdom_cache_store_timestamp(last_check,
+ last_check+TRUSTDOM_UPDATE_INTERVAL);
+ }
+
+done:
+ talloc_destroy( mem_ctx );
+
+ return;
+}
diff --git a/source3/libsmb/trusts_util.c b/source3/libsmb/trusts_util.c
new file mode 100644
index 0000000000..08a49930b4
--- /dev/null
+++ b/source3/libsmb/trusts_util.c
@@ -0,0 +1,283 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Routines to operate on various trust relationships
+ * Copyright (C) Andrew Bartlett 2001
+ * Copyright (C) Rafal Szczesniak 2003
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/*********************************************************
+ Change the domain password on the PDC.
+
+ Just changes the password betwen the two values specified.
+
+ Caller must have the cli connected to the netlogon pipe
+ already.
+**********************************************************/
+
+static NTSTATUS just_change_the_password(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ const unsigned char orig_trust_passwd_hash[16],
+ const char *new_trust_pwd_cleartext,
+ const unsigned char new_trust_passwd_hash[16],
+ uint32 sec_channel_type)
+{
+ NTSTATUS result;
+ uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+
+ result = rpccli_netlogon_setup_creds(cli,
+ cli->desthost, /* server name */
+ lp_workgroup(), /* domain */
+ global_myname(), /* client name */
+ global_myname(), /* machine account name */
+ orig_trust_passwd_hash,
+ sec_channel_type,
+ &neg_flags);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3,("just_change_the_password: unable to setup creds (%s)!\n",
+ nt_errstr(result)));
+ return result;
+ }
+
+ if (neg_flags & NETLOGON_NEG_PASSWORD_SET2) {
+
+ struct netr_Authenticator clnt_creds, srv_cred;
+ struct netr_CryptPassword new_password;
+ struct samr_CryptPassword password_buf;
+
+ netlogon_creds_client_step(cli->dc, &clnt_creds);
+
+ encode_pw_buffer(password_buf.data, new_trust_pwd_cleartext, STR_UNICODE);
+
+ SamOEMhash(password_buf.data, cli->dc->sess_key, 516);
+ memcpy(new_password.data, password_buf.data, 512);
+ new_password.length = IVAL(password_buf.data, 512);
+
+ result = rpccli_netr_ServerPasswordSet2(cli, mem_ctx,
+ cli->dc->remote_machine,
+ cli->dc->mach_acct,
+ sec_channel_type,
+ global_myname(),
+ &clnt_creds,
+ &srv_cred,
+ &new_password);
+
+ /* Always check returned credentials. */
+ if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
+ DEBUG(0,("rpccli_netr_ServerPasswordSet2: "
+ "credentials chain check failed\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ } else {
+
+ struct netr_Authenticator clnt_creds, srv_cred;
+ struct samr_Password new_password;
+
+ netlogon_creds_client_step(cli->dc, &clnt_creds);
+
+ cred_hash3(new_password.hash,
+ new_trust_passwd_hash,
+ cli->dc->sess_key, 1);
+
+ result = rpccli_netr_ServerPasswordSet(cli, mem_ctx,
+ cli->dc->remote_machine,
+ cli->dc->mach_acct,
+ sec_channel_type,
+ global_myname(),
+ &clnt_creds,
+ &srv_cred,
+ &new_password);
+
+ /* Always check returned credentials. */
+ if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
+ DEBUG(0,("rpccli_netr_ServerPasswordSet: "
+ "credentials chain check failed\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("just_change_the_password: unable to change password (%s)!\n",
+ nt_errstr(result)));
+ }
+ return result;
+}
+
+/*********************************************************
+ Change the domain password on the PDC.
+ Store the password ourselves, but use the supplied password
+ Caller must have already setup the connection to the NETLOGON pipe
+**********************************************************/
+
+NTSTATUS trust_pw_change_and_store_it(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ const char *domain,
+ unsigned char orig_trust_passwd_hash[16],
+ uint32 sec_channel_type)
+{
+ unsigned char new_trust_passwd_hash[16];
+ char *new_trust_passwd;
+ char *str;
+ NTSTATUS nt_status;
+
+ /* Create a random machine account password */
+ str = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
+
+ if ((new_trust_passwd = talloc_strdup(mem_ctx, str)) == NULL) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ E_md4hash(new_trust_passwd, new_trust_passwd_hash);
+
+ nt_status = just_change_the_password(cli, mem_ctx,
+ orig_trust_passwd_hash,
+ new_trust_passwd,
+ new_trust_passwd_hash,
+ sec_channel_type);
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(3,("%s : trust_pw_change_and_store_it: Changed password.\n",
+ current_timestring(debug_ctx(), False)));
+ /*
+ * Return the result of trying to write the new password
+ * back into the trust account file.
+ */
+ if (!secrets_store_machine_password(new_trust_passwd, domain, sec_channel_type)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ return nt_status;
+}
+
+/*********************************************************
+ Change the domain password on the PDC.
+ Do most of the legwork ourselfs. Caller must have
+ already setup the connection to the NETLOGON pipe
+**********************************************************/
+
+NTSTATUS trust_pw_find_change_and_store_it(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *domain)
+{
+ unsigned char old_trust_passwd_hash[16];
+ uint32 sec_channel_type = 0;
+
+ if (!secrets_fetch_trust_account_password(domain,
+ old_trust_passwd_hash,
+ NULL, &sec_channel_type)) {
+ DEBUG(0, ("could not fetch domain secrets for domain %s!\n", domain));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return trust_pw_change_and_store_it(cli, mem_ctx, domain,
+ old_trust_passwd_hash,
+ sec_channel_type);
+}
+
+/*********************************************************************
+ Enumerate the list of trusted domains from a DC
+*********************************************************************/
+
+bool enumerate_domain_trusts( TALLOC_CTX *mem_ctx, const char *domain,
+ char ***domain_names, uint32 *num_domains,
+ DOM_SID **sids )
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ fstring dc_name;
+ struct sockaddr_storage dc_ss;
+ uint32 enum_ctx = 0;
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *lsa_pipe;
+ bool retry;
+ struct lsa_DomainList dom_list;
+ int i;
+
+ *domain_names = NULL;
+ *num_domains = 0;
+ *sids = NULL;
+
+ /* lookup a DC first */
+
+ if ( !get_dc_name(domain, NULL, dc_name, &dc_ss) ) {
+ DEBUG(3,("enumerate_domain_trusts: can't locate a DC for domain %s\n",
+ domain));
+ return False;
+ }
+
+ /* setup the anonymous connection */
+
+ result = cli_full_connection( &cli, global_myname(), dc_name, &dc_ss, 0, "IPC$", "IPC",
+ "", "", "", 0, Undefined, &retry);
+ if ( !NT_STATUS_IS_OK(result) )
+ goto done;
+
+ /* open the LSARPC_PIPE */
+
+ result = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
+ &lsa_pipe);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* get a handle */
+
+ result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, True,
+ LSA_POLICY_VIEW_LOCAL_INFORMATION, &pol);
+ if ( !NT_STATUS_IS_OK(result) )
+ goto done;
+
+ /* Lookup list of trusted domains */
+
+ result = rpccli_lsa_EnumTrustDom(lsa_pipe, mem_ctx,
+ &pol,
+ &enum_ctx,
+ &dom_list,
+ (uint32_t)-1);
+ if ( !NT_STATUS_IS_OK(result) )
+ goto done;
+
+ *num_domains = dom_list.count;
+
+ *domain_names = TALLOC_ZERO_ARRAY(mem_ctx, char *, *num_domains);
+ if (!*domain_names) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ *sids = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, *num_domains);
+ if (!*sids) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i=0; i< *num_domains; i++) {
+ (*domain_names)[i] = CONST_DISCARD(char *, dom_list.domains[i].name.string);
+ (*sids)[i] = *dom_list.domains[i].sid;
+ }
+
+done:
+ /* cleanup */
+ if (cli) {
+ DEBUG(10,("enumerate_domain_trusts: shutting down connection...\n"));
+ cli_shutdown( cli );
+ }
+
+ return NT_STATUS_IS_OK(result);
+}
diff --git a/source3/libsmb/unexpected.c b/source3/libsmb/unexpected.c
new file mode 100644
index 0000000000..df4d2119e2
--- /dev/null
+++ b/source3/libsmb/unexpected.c
@@ -0,0 +1,202 @@
+/*
+ Unix SMB/CIFS implementation.
+ handle unexpected packets
+ Copyright (C) Andrew Tridgell 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+static TDB_CONTEXT *tdbd = NULL;
+
+/* the key type used in the unexpected packet database */
+struct unexpected_key {
+ enum packet_type packet_type;
+ time_t timestamp;
+ int count;
+};
+
+/****************************************************************************
+ All unexpected packets are passed in here, to be stored in a unexpected
+ packet database. This allows nmblookup and other tools to receive packets
+ erroneously sent to the wrong port by broken MS systems.
+**************************************************************************/
+
+void unexpected_packet(struct packet_struct *p)
+{
+ static int count;
+ TDB_DATA kbuf, dbuf;
+ struct unexpected_key key;
+ char buf[1024];
+ int len=0;
+ uint32_t enc_ip;
+
+ if (!tdbd) {
+ tdbd = tdb_open_log(lock_path("unexpected.tdb"), 0,
+ TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
+ O_RDWR | O_CREAT, 0644);
+ if (!tdbd) {
+ DEBUG(0,("Failed to open unexpected.tdb\n"));
+ return;
+ }
+ }
+
+ memset(buf,'\0',sizeof(buf));
+
+ /* Encode the ip addr and port. */
+ enc_ip = ntohl(p->ip.s_addr);
+ SIVAL(buf,0,enc_ip);
+ SSVAL(buf,4,p->port);
+
+ len = build_packet(&buf[6], sizeof(buf)-6, p) + 6;
+
+ ZERO_STRUCT(key); /* needed for potential alignment */
+
+ key.packet_type = p->packet_type;
+ key.timestamp = p->timestamp;
+ key.count = count++;
+
+ kbuf.dptr = (uint8_t *)&key;
+ kbuf.dsize = sizeof(key);
+ dbuf.dptr = (uint8_t *)buf;
+ dbuf.dsize = len;
+
+ tdb_store(tdbd, kbuf, dbuf, TDB_REPLACE);
+}
+
+
+static time_t lastt;
+
+/****************************************************************************
+ Delete the record if it is too old.
+**************************************************************************/
+
+static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct unexpected_key key;
+
+ if (kbuf.dsize != sizeof(key)) {
+ tdb_delete(ttdb, kbuf);
+ }
+
+ memcpy(&key, kbuf.dptr, sizeof(key));
+
+ if (lastt - key.timestamp > NMBD_UNEXPECTED_TIMEOUT) {
+ tdb_delete(ttdb, kbuf);
+ }
+
+ return 0;
+}
+
+
+/****************************************************************************
+ Delete all old unexpected packets.
+**************************************************************************/
+
+void clear_unexpected(time_t t)
+{
+ if (!tdbd) return;
+
+ if ((lastt != 0) && (t < lastt + NMBD_UNEXPECTED_TIMEOUT))
+ return;
+
+ lastt = t;
+
+ tdb_traverse(tdbd, traverse_fn, NULL);
+}
+
+struct receive_unexpected_state {
+ struct packet_struct *matched_packet;
+ int match_id;
+ enum packet_type match_type;
+ const char *match_name;
+};
+
+/****************************************************************************
+ tdb traversal fn to find a matching 137 packet.
+**************************************************************************/
+
+static int traverse_match(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf,
+ void *private_data)
+{
+ struct receive_unexpected_state *state =
+ (struct receive_unexpected_state *)private_data;
+ struct unexpected_key key;
+ struct in_addr ip;
+ uint32_t enc_ip;
+ int port;
+ struct packet_struct *p;
+
+ if (kbuf.dsize != sizeof(key)) {
+ return 0;
+ }
+
+ memcpy(&key, kbuf.dptr, sizeof(key));
+
+ if (key.packet_type != state->match_type) return 0;
+
+ if (dbuf.dsize < 6) {
+ return 0;
+ }
+
+ /* Decode the ip addr and port. */
+ enc_ip = IVAL(dbuf.dptr,0);
+ ip.s_addr = htonl(enc_ip);
+ port = SVAL(dbuf.dptr,4);
+
+ p = parse_packet((char *)&dbuf.dptr[6],
+ dbuf.dsize-6,
+ state->match_type,
+ ip,
+ port);
+
+ if ((state->match_type == NMB_PACKET &&
+ p->packet.nmb.header.name_trn_id == state->match_id) ||
+ (state->match_type == DGRAM_PACKET &&
+ match_mailslot_name(p, state->match_name))) {
+ state->matched_packet = p;
+ return -1;
+ }
+
+ free_packet(p);
+
+ return 0;
+}
+
+/****************************************************************************
+ Check for a particular packet in the unexpected packet queue.
+**************************************************************************/
+
+struct packet_struct *receive_unexpected(enum packet_type packet_type, int id,
+ const char *mailslot_name)
+{
+ TDB_CONTEXT *tdb2;
+ struct receive_unexpected_state state;
+
+ tdb2 = tdb_open_log(lock_path("unexpected.tdb"), 0, 0, O_RDONLY, 0);
+ if (!tdb2) return NULL;
+
+ state.matched_packet = NULL;
+ state.match_id = id;
+ state.match_type = packet_type;
+ state.match_name = mailslot_name;
+
+ tdb_traverse(tdb2, traverse_match, &state);
+
+ tdb_close(tdb2);
+
+ return state.matched_packet;
+}
diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c
new file mode 100644
index 0000000000..032aaa56b6
--- /dev/null
+++ b/source3/locking/brlock.c
@@ -0,0 +1,1807 @@
+/*
+ Unix SMB/CIFS implementation.
+ byte range locking code
+ Updated to handle range splits/merges.
+
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Jeremy Allison 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This module implements a tdb based byte range locking service,
+ replacing the fcntl() based byte range locking previously
+ used. This allows us to provide the same semantics as NT */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_LOCKING
+
+#define ZERO_ZERO 0
+
+/* The open brlock.tdb database. */
+
+static struct db_context *brlock_db;
+
+/****************************************************************************
+ Debug info at level 10 for lock struct.
+****************************************************************************/
+
+static void print_lock_struct(unsigned int i, struct lock_struct *pls)
+{
+ DEBUG(10,("[%u]: smbpid = %u, tid = %u, pid = %u, ",
+ i,
+ (unsigned int)pls->context.smbpid,
+ (unsigned int)pls->context.tid,
+ (unsigned int)procid_to_pid(&pls->context.pid) ));
+
+ DEBUG(10,("start = %.0f, size = %.0f, fnum = %d, %s %s\n",
+ (double)pls->start,
+ (double)pls->size,
+ pls->fnum,
+ lock_type_name(pls->lock_type),
+ lock_flav_name(pls->lock_flav) ));
+}
+
+/****************************************************************************
+ See if two locking contexts are equal.
+****************************************************************************/
+
+bool brl_same_context(const struct lock_context *ctx1,
+ const struct lock_context *ctx2)
+{
+ return (procid_equal(&ctx1->pid, &ctx2->pid) &&
+ (ctx1->smbpid == ctx2->smbpid) &&
+ (ctx1->tid == ctx2->tid));
+}
+
+/****************************************************************************
+ See if lck1 and lck2 overlap.
+****************************************************************************/
+
+static bool brl_overlap(const struct lock_struct *lck1,
+ const struct lock_struct *lck2)
+{
+ /* this extra check is not redundent - it copes with locks
+ that go beyond the end of 64 bit file space */
+ if (lck1->size != 0 &&
+ lck1->start == lck2->start &&
+ lck1->size == lck2->size) {
+ return True;
+ }
+
+ if (lck1->start >= (lck2->start+lck2->size) ||
+ lck2->start >= (lck1->start+lck1->size)) {
+ return False;
+ }
+ return True;
+}
+
+/****************************************************************************
+ See if lock2 can be added when lock1 is in place.
+****************************************************************************/
+
+static bool brl_conflict(const struct lock_struct *lck1,
+ const struct lock_struct *lck2)
+{
+ /* Ignore PENDING locks. */
+ if (IS_PENDING_LOCK(lck1->lock_type) || IS_PENDING_LOCK(lck2->lock_type))
+ return False;
+
+ /* Read locks never conflict. */
+ if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
+ return False;
+ }
+
+ if (brl_same_context(&lck1->context, &lck2->context) &&
+ lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
+ return False;
+ }
+
+ return brl_overlap(lck1, lck2);
+}
+
+/****************************************************************************
+ See if lock2 can be added when lock1 is in place - when both locks are POSIX
+ flavour. POSIX locks ignore fnum - they only care about dev/ino which we
+ know already match.
+****************************************************************************/
+
+static bool brl_conflict_posix(const struct lock_struct *lck1,
+ const struct lock_struct *lck2)
+{
+#if defined(DEVELOPER)
+ SMB_ASSERT(lck1->lock_flav == POSIX_LOCK);
+ SMB_ASSERT(lck2->lock_flav == POSIX_LOCK);
+#endif
+
+ /* Ignore PENDING locks. */
+ if (IS_PENDING_LOCK(lck1->lock_type) || IS_PENDING_LOCK(lck2->lock_type))
+ return False;
+
+ /* Read locks never conflict. */
+ if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
+ return False;
+ }
+
+ /* Locks on the same context con't conflict. Ignore fnum. */
+ if (brl_same_context(&lck1->context, &lck2->context)) {
+ return False;
+ }
+
+ /* One is read, the other write, or the context is different,
+ do they overlap ? */
+ return brl_overlap(lck1, lck2);
+}
+
+#if ZERO_ZERO
+static bool brl_conflict1(const struct lock_struct *lck1,
+ const struct lock_struct *lck2)
+{
+ if (IS_PENDING_LOCK(lck1->lock_type) || IS_PENDING_LOCK(lck2->lock_type))
+ return False;
+
+ if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
+ return False;
+ }
+
+ if (brl_same_context(&lck1->context, &lck2->context) &&
+ lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
+ return False;
+ }
+
+ if (lck2->start == 0 && lck2->size == 0 && lck1->size != 0) {
+ return True;
+ }
+
+ if (lck1->start >= (lck2->start + lck2->size) ||
+ lck2->start >= (lck1->start + lck1->size)) {
+ return False;
+ }
+
+ return True;
+}
+#endif
+
+/****************************************************************************
+ Check to see if this lock conflicts, but ignore our own locks on the
+ same fnum only. This is the read/write lock check code path.
+ This is never used in the POSIX lock case.
+****************************************************************************/
+
+static bool brl_conflict_other(const struct lock_struct *lck1, const struct lock_struct *lck2)
+{
+ if (IS_PENDING_LOCK(lck1->lock_type) || IS_PENDING_LOCK(lck2->lock_type))
+ return False;
+
+ if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK)
+ return False;
+
+ /* POSIX flavour locks never conflict here - this is only called
+ in the read/write path. */
+
+ if (lck1->lock_flav == POSIX_LOCK && lck2->lock_flav == POSIX_LOCK)
+ return False;
+
+ /*
+ * Incoming WRITE locks conflict with existing READ locks even
+ * if the context is the same. JRA. See LOCKTEST7 in smbtorture.
+ */
+
+ if (!(lck2->lock_type == WRITE_LOCK && lck1->lock_type == READ_LOCK)) {
+ if (brl_same_context(&lck1->context, &lck2->context) &&
+ lck1->fnum == lck2->fnum)
+ return False;
+ }
+
+ return brl_overlap(lck1, lck2);
+}
+
+/****************************************************************************
+ Check if an unlock overlaps a pending lock.
+****************************************************************************/
+
+static bool brl_pending_overlap(const struct lock_struct *lock, const struct lock_struct *pend_lock)
+{
+ if ((lock->start <= pend_lock->start) && (lock->start + lock->size > pend_lock->start))
+ return True;
+ if ((lock->start >= pend_lock->start) && (lock->start <= pend_lock->start + pend_lock->size))
+ return True;
+ return False;
+}
+
+/****************************************************************************
+ Amazingly enough, w2k3 "remembers" whether the last lock failure on a fnum
+ is the same as this one and changes its error code. I wonder if any
+ app depends on this ?
+****************************************************************************/
+
+static NTSTATUS brl_lock_failed(files_struct *fsp, const struct lock_struct *lock, bool blocking_lock)
+{
+ if (lock->start >= 0xEF000000 && (lock->start >> 63) == 0) {
+ /* amazing the little things you learn with a test
+ suite. Locks beyond this offset (as a 64 bit
+ number!) always generate the conflict error code,
+ unless the top bit is set */
+ if (!blocking_lock) {
+ fsp->last_lock_failure = *lock;
+ }
+ return NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+
+ if (procid_equal(&lock->context.pid, &fsp->last_lock_failure.context.pid) &&
+ lock->context.tid == fsp->last_lock_failure.context.tid &&
+ lock->fnum == fsp->last_lock_failure.fnum &&
+ lock->start == fsp->last_lock_failure.start) {
+ return NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+
+ if (!blocking_lock) {
+ fsp->last_lock_failure = *lock;
+ }
+ return NT_STATUS_LOCK_NOT_GRANTED;
+}
+
+/****************************************************************************
+ Open up the brlock.tdb database.
+****************************************************************************/
+
+void brl_init(bool read_only)
+{
+ if (brlock_db) {
+ return;
+ }
+ brlock_db = db_open(NULL, lock_path("brlock.tdb"),
+ lp_open_files_db_hash_size(),
+ TDB_DEFAULT|TDB_VOLATILE|TDB_CLEAR_IF_FIRST,
+ read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644 );
+ if (!brlock_db) {
+ DEBUG(0,("Failed to open byte range locking database %s\n",
+ lock_path("brlock.tdb")));
+ return;
+ }
+}
+
+/****************************************************************************
+ Close down the brlock.tdb database.
+****************************************************************************/
+
+void brl_shutdown(void)
+{
+ TALLOC_FREE(brlock_db);
+}
+
+#if ZERO_ZERO
+/****************************************************************************
+ Compare two locks for sorting.
+****************************************************************************/
+
+static int lock_compare(const struct lock_struct *lck1,
+ const struct lock_struct *lck2)
+{
+ if (lck1->start != lck2->start) {
+ return (lck1->start - lck2->start);
+ }
+ if (lck2->size != lck1->size) {
+ return ((int)lck1->size - (int)lck2->size);
+ }
+ return 0;
+}
+#endif
+
+/****************************************************************************
+ Lock a range of bytes - Windows lock semantics.
+****************************************************************************/
+
+static NTSTATUS brl_lock_windows(struct byte_range_lock *br_lck,
+ struct lock_struct *plock, bool blocking_lock)
+{
+ unsigned int i;
+ files_struct *fsp = br_lck->fsp;
+ struct lock_struct *locks = br_lck->lock_data;
+
+ for (i=0; i < br_lck->num_locks; i++) {
+ /* Do any Windows or POSIX locks conflict ? */
+ if (brl_conflict(&locks[i], plock)) {
+ /* Remember who blocked us. */
+ plock->context.smbpid = locks[i].context.smbpid;
+ return brl_lock_failed(fsp,plock,blocking_lock);
+ }
+#if ZERO_ZERO
+ if (plock->start == 0 && plock->size == 0 &&
+ locks[i].size == 0) {
+ break;
+ }
+#endif
+ }
+
+ /* We can get the Windows lock, now see if it needs to
+ be mapped into a lower level POSIX one, and if so can
+ we get it ? */
+
+ if (!IS_PENDING_LOCK(plock->lock_type) && lp_posix_locking(fsp->conn->params)) {
+ int errno_ret;
+ if (!set_posix_lock_windows_flavour(fsp,
+ plock->start,
+ plock->size,
+ plock->lock_type,
+ &plock->context,
+ locks,
+ br_lck->num_locks,
+ &errno_ret)) {
+
+ /* We don't know who blocked us. */
+ plock->context.smbpid = 0xFFFFFFFF;
+
+ if (errno_ret == EACCES || errno_ret == EAGAIN) {
+ return NT_STATUS_FILE_LOCK_CONFLICT;
+ } else {
+ return map_nt_error_from_unix(errno);
+ }
+ }
+ }
+
+ /* no conflicts - add it to the list of locks */
+ locks = (struct lock_struct *)SMB_REALLOC(locks, (br_lck->num_locks + 1) * sizeof(*locks));
+ if (!locks) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ memcpy(&locks[br_lck->num_locks], plock, sizeof(struct lock_struct));
+ br_lck->num_locks += 1;
+ br_lck->lock_data = locks;
+ br_lck->modified = True;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Cope with POSIX range splits and merges.
+****************************************************************************/
+
+static unsigned int brlock_posix_split_merge(struct lock_struct *lck_arr, /* Output array. */
+ const struct lock_struct *ex, /* existing lock. */
+ const struct lock_struct *plock, /* proposed lock. */
+ bool *lock_was_added)
+{
+ bool lock_types_differ = (ex->lock_type != plock->lock_type);
+
+ /* We can't merge non-conflicting locks on different context - ignore fnum. */
+
+ if (!brl_same_context(&ex->context, &plock->context)) {
+ /* Just copy. */
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ return 1;
+ }
+
+ /* We now know we have the same context. */
+
+ /* Did we overlap ? */
+
+/*********************************************
+ +---------+
+ | ex |
+ +---------+
+ +-------+
+ | plock |
+ +-------+
+OR....
+ +---------+
+ | ex |
+ +---------+
+**********************************************/
+
+ if ( (ex->start > (plock->start + plock->size)) ||
+ (plock->start > (ex->start + ex->size))) {
+ /* No overlap with this lock - copy existing. */
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ return 1;
+ }
+
+/*********************************************
+ +---------------------------+
+ | ex |
+ +---------------------------+
+ +---------------------------+
+ | plock | -> replace with plock.
+ +---------------------------+
+**********************************************/
+
+ if ( (ex->start >= plock->start) &&
+ (ex->start + ex->size <= plock->start + plock->size) ) {
+ memcpy(&lck_arr[0], plock, sizeof(struct lock_struct));
+ *lock_was_added = True;
+ return 1;
+ }
+
+/*********************************************
+ +-----------------------+
+ | ex |
+ +-----------------------+
+ +---------------+
+ | plock |
+ +---------------+
+OR....
+ +-------+
+ | ex |
+ +-------+
+ +---------------+
+ | plock |
+ +---------------+
+
+BECOMES....
+ +---------------+-------+
+ | plock | ex | - different lock types.
+ +---------------+-------+
+OR.... (merge)
+ +-----------------------+
+ | ex | - same lock type.
+ +-----------------------+
+**********************************************/
+
+ if ( (ex->start >= plock->start) &&
+ (ex->start <= plock->start + plock->size) &&
+ (ex->start + ex->size > plock->start + plock->size) ) {
+
+ *lock_was_added = True;
+
+ /* If the lock types are the same, we merge, if different, we
+ add the new lock before the old. */
+
+ if (lock_types_differ) {
+ /* Add new. */
+ memcpy(&lck_arr[0], plock, sizeof(struct lock_struct));
+ memcpy(&lck_arr[1], ex, sizeof(struct lock_struct));
+ /* Adjust existing start and size. */
+ lck_arr[1].start = plock->start + plock->size;
+ lck_arr[1].size = (ex->start + ex->size) - (plock->start + plock->size);
+ return 2;
+ } else {
+ /* Merge. */
+ memcpy(&lck_arr[0], plock, sizeof(struct lock_struct));
+ /* Set new start and size. */
+ lck_arr[0].start = plock->start;
+ lck_arr[0].size = (ex->start + ex->size) - plock->start;
+ return 1;
+ }
+ }
+
+/*********************************************
+ +-----------------------+
+ | ex |
+ +-----------------------+
+ +---------------+
+ | plock |
+ +---------------+
+OR....
+ +-------+
+ | ex |
+ +-------+
+ +---------------+
+ | plock |
+ +---------------+
+BECOMES....
+ +-------+---------------+
+ | ex | plock | - different lock types
+ +-------+---------------+
+
+OR.... (merge)
+ +-----------------------+
+ | ex | - same lock type.
+ +-----------------------+
+
+**********************************************/
+
+ if ( (ex->start < plock->start) &&
+ (ex->start + ex->size >= plock->start) &&
+ (ex->start + ex->size <= plock->start + plock->size) ) {
+
+ *lock_was_added = True;
+
+ /* If the lock types are the same, we merge, if different, we
+ add the new lock after the old. */
+
+ if (lock_types_differ) {
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ memcpy(&lck_arr[1], plock, sizeof(struct lock_struct));
+ /* Adjust existing size. */
+ lck_arr[0].size = plock->start - ex->start;
+ return 2;
+ } else {
+ /* Merge. */
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ /* Adjust existing size. */
+ lck_arr[0].size = (plock->start + plock->size) - ex->start;
+ return 1;
+ }
+ }
+
+/*********************************************
+ +---------------------------+
+ | ex |
+ +---------------------------+
+ +---------+
+ | plock |
+ +---------+
+BECOMES.....
+ +-------+---------+---------+
+ | ex | plock | ex | - different lock types.
+ +-------+---------+---------+
+OR
+ +---------------------------+
+ | ex | - same lock type.
+ +---------------------------+
+**********************************************/
+
+ if ( (ex->start < plock->start) && (ex->start + ex->size > plock->start + plock->size) ) {
+ *lock_was_added = True;
+
+ if (lock_types_differ) {
+
+ /* We have to split ex into two locks here. */
+
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ memcpy(&lck_arr[1], plock, sizeof(struct lock_struct));
+ memcpy(&lck_arr[2], ex, sizeof(struct lock_struct));
+
+ /* Adjust first existing size. */
+ lck_arr[0].size = plock->start - ex->start;
+
+ /* Adjust second existing start and size. */
+ lck_arr[2].start = plock->start + plock->size;
+ lck_arr[2].size = (ex->start + ex->size) - (plock->start + plock->size);
+ return 3;
+ } else {
+ /* Just eat plock. */
+ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+ return 1;
+ }
+ }
+
+ /* Never get here. */
+ smb_panic("brlock_posix_split_merge");
+ /* Notreached. */
+
+ /* Keep some compilers happy. */
+ return 0;
+}
+
+/****************************************************************************
+ Lock a range of bytes - POSIX lock semantics.
+ We must cope with range splits and merges.
+****************************************************************************/
+
+static NTSTATUS brl_lock_posix(struct messaging_context *msg_ctx,
+ struct byte_range_lock *br_lck,
+ struct lock_struct *plock)
+{
+ unsigned int i, count;
+ struct lock_struct *locks = br_lck->lock_data;
+ struct lock_struct *tp;
+ bool lock_was_added = False;
+ bool signal_pending_read = False;
+
+ /* No zero-zero locks for POSIX. */
+ if (plock->start == 0 && plock->size == 0) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Don't allow 64-bit lock wrap. */
+ if (plock->start + plock->size < plock->start ||
+ plock->start + plock->size < plock->size) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* The worst case scenario here is we have to split an
+ existing POSIX lock range into two, and add our lock,
+ so we need at most 2 more entries. */
+
+ tp = SMB_MALLOC_ARRAY(struct lock_struct, (br_lck->num_locks + 2));
+ if (!tp) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ count = 0;
+ for (i=0; i < br_lck->num_locks; i++) {
+ struct lock_struct *curr_lock = &locks[i];
+
+ /* If we have a pending read lock, a lock downgrade should
+ trigger a lock re-evaluation. */
+ if (curr_lock->lock_type == PENDING_READ_LOCK &&
+ brl_pending_overlap(plock, curr_lock)) {
+ signal_pending_read = True;
+ }
+
+ if (curr_lock->lock_flav == WINDOWS_LOCK) {
+ /* Do any Windows flavour locks conflict ? */
+ if (brl_conflict(curr_lock, plock)) {
+ /* No games with error messages. */
+ SAFE_FREE(tp);
+ /* Remember who blocked us. */
+ plock->context.smbpid = curr_lock->context.smbpid;
+ return NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+ /* Just copy the Windows lock into the new array. */
+ memcpy(&tp[count], curr_lock, sizeof(struct lock_struct));
+ count++;
+ } else {
+ /* POSIX conflict semantics are different. */
+ if (brl_conflict_posix(curr_lock, plock)) {
+ /* Can't block ourselves with POSIX locks. */
+ /* No games with error messages. */
+ SAFE_FREE(tp);
+ /* Remember who blocked us. */
+ plock->context.smbpid = curr_lock->context.smbpid;
+ return NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+
+ /* Work out overlaps. */
+ count += brlock_posix_split_merge(&tp[count], curr_lock, plock, &lock_was_added);
+ }
+ }
+
+ if (!lock_was_added) {
+ memcpy(&tp[count], plock, sizeof(struct lock_struct));
+ count++;
+ }
+
+ /* We can get the POSIX lock, now see if it needs to
+ be mapped into a lower level POSIX one, and if so can
+ we get it ? */
+
+ if (!IS_PENDING_LOCK(plock->lock_type) && lp_posix_locking(br_lck->fsp->conn->params)) {
+ int errno_ret;
+
+ /* The lower layer just needs to attempt to
+ get the system POSIX lock. We've weeded out
+ any conflicts above. */
+
+ if (!set_posix_lock_posix_flavour(br_lck->fsp,
+ plock->start,
+ plock->size,
+ plock->lock_type,
+ &errno_ret)) {
+
+ /* We don't know who blocked us. */
+ plock->context.smbpid = 0xFFFFFFFF;
+
+ if (errno_ret == EACCES || errno_ret == EAGAIN) {
+ SAFE_FREE(tp);
+ return NT_STATUS_FILE_LOCK_CONFLICT;
+ } else {
+ SAFE_FREE(tp);
+ return map_nt_error_from_unix(errno);
+ }
+ }
+ }
+
+ /* Realloc so we don't leak entries per lock call. */
+ tp = (struct lock_struct *)SMB_REALLOC(tp, count * sizeof(*locks));
+ if (!tp) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ br_lck->num_locks = count;
+ SAFE_FREE(br_lck->lock_data);
+ br_lck->lock_data = tp;
+ locks = tp;
+ br_lck->modified = True;
+
+ /* A successful downgrade from write to read lock can trigger a lock
+ re-evalutation where waiting readers can now proceed. */
+
+ if (signal_pending_read) {
+ /* Send unlock messages to any pending read waiters that overlap. */
+ for (i=0; i < br_lck->num_locks; i++) {
+ struct lock_struct *pend_lock = &locks[i];
+
+ /* Ignore non-pending locks. */
+ if (!IS_PENDING_LOCK(pend_lock->lock_type)) {
+ continue;
+ }
+
+ if (pend_lock->lock_type == PENDING_READ_LOCK &&
+ brl_pending_overlap(plock, pend_lock)) {
+ DEBUG(10,("brl_lock_posix: sending unlock message to pid %s\n",
+ procid_str_static(&pend_lock->context.pid )));
+
+ messaging_send(msg_ctx, pend_lock->context.pid,
+ MSG_SMB_UNLOCK, &data_blob_null);
+ }
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Lock a range of bytes.
+****************************************************************************/
+
+NTSTATUS brl_lock(struct messaging_context *msg_ctx,
+ struct byte_range_lock *br_lck,
+ uint32 smbpid,
+ struct server_id pid,
+ br_off start,
+ br_off size,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ bool blocking_lock,
+ uint32 *psmbpid)
+{
+ NTSTATUS ret;
+ struct lock_struct lock;
+
+#if !ZERO_ZERO
+ if (start == 0 && size == 0) {
+ DEBUG(0,("client sent 0/0 lock - please report this\n"));
+ }
+#endif
+
+#ifdef DEVELOPER
+ /* Quieten valgrind on test. */
+ memset(&lock, '\0', sizeof(lock));
+#endif
+
+ lock.context.smbpid = smbpid;
+ lock.context.pid = pid;
+ lock.context.tid = br_lck->fsp->conn->cnum;
+ lock.start = start;
+ lock.size = size;
+ lock.fnum = br_lck->fsp->fnum;
+ lock.lock_type = lock_type;
+ lock.lock_flav = lock_flav;
+
+ if (lock_flav == WINDOWS_LOCK) {
+ ret = brl_lock_windows(br_lck, &lock, blocking_lock);
+ } else {
+ ret = brl_lock_posix(msg_ctx, br_lck, &lock);
+ }
+
+#if ZERO_ZERO
+ /* sort the lock list */
+ qsort(br_lck->lock_data, (size_t)br_lck->num_locks, sizeof(lock), lock_compare);
+#endif
+
+ /* If we're returning an error, return who blocked us. */
+ if (!NT_STATUS_IS_OK(ret) && psmbpid) {
+ *psmbpid = lock.context.smbpid;
+ }
+ return ret;
+}
+
+/****************************************************************************
+ Unlock a range of bytes - Windows semantics.
+****************************************************************************/
+
+static bool brl_unlock_windows(struct messaging_context *msg_ctx,
+ struct byte_range_lock *br_lck,
+ const struct lock_struct *plock)
+{
+ unsigned int i, j;
+ struct lock_struct *locks = br_lck->lock_data;
+ enum brl_type deleted_lock_type = READ_LOCK; /* shut the compiler up.... */
+
+#if ZERO_ZERO
+ /* Delete write locks by preference... The lock list
+ is sorted in the zero zero case. */
+
+ for (i = 0; i < br_lck->num_locks; i++) {
+ struct lock_struct *lock = &locks[i];
+
+ if (lock->lock_type == WRITE_LOCK &&
+ brl_same_context(&lock->context, &plock->context) &&
+ lock->fnum == plock->fnum &&
+ lock->lock_flav == WINDOWS_LOCK &&
+ lock->start == plock->start &&
+ lock->size == plock->size) {
+
+ /* found it - delete it */
+ deleted_lock_type = lock->lock_type;
+ break;
+ }
+ }
+
+ if (i != br_lck->num_locks) {
+ /* We found it - don't search again. */
+ goto unlock_continue;
+ }
+#endif
+
+ for (i = 0; i < br_lck->num_locks; i++) {
+ struct lock_struct *lock = &locks[i];
+
+ /* Only remove our own locks that match in start, size, and flavour. */
+ if (brl_same_context(&lock->context, &plock->context) &&
+ lock->fnum == plock->fnum &&
+ lock->lock_flav == WINDOWS_LOCK &&
+ lock->start == plock->start &&
+ lock->size == plock->size ) {
+ deleted_lock_type = lock->lock_type;
+ break;
+ }
+ }
+
+ if (i == br_lck->num_locks) {
+ /* we didn't find it */
+ return False;
+ }
+
+#if ZERO_ZERO
+ unlock_continue:
+#endif
+
+ /* Actually delete the lock. */
+ if (i < br_lck->num_locks - 1) {
+ memmove(&locks[i], &locks[i+1],
+ sizeof(*locks)*((br_lck->num_locks-1) - i));
+ }
+
+ br_lck->num_locks -= 1;
+ br_lck->modified = True;
+
+ /* Unlock the underlying POSIX regions. */
+ if(lp_posix_locking(br_lck->fsp->conn->params)) {
+ release_posix_lock_windows_flavour(br_lck->fsp,
+ plock->start,
+ plock->size,
+ deleted_lock_type,
+ &plock->context,
+ locks,
+ br_lck->num_locks);
+ }
+
+ /* Send unlock messages to any pending waiters that overlap. */
+ for (j=0; j < br_lck->num_locks; j++) {
+ struct lock_struct *pend_lock = &locks[j];
+
+ /* Ignore non-pending locks. */
+ if (!IS_PENDING_LOCK(pend_lock->lock_type)) {
+ continue;
+ }
+
+ /* We could send specific lock info here... */
+ if (brl_pending_overlap(plock, pend_lock)) {
+ DEBUG(10,("brl_unlock: sending unlock message to pid %s\n",
+ procid_str_static(&pend_lock->context.pid )));
+
+ messaging_send(msg_ctx, pend_lock->context.pid,
+ MSG_SMB_UNLOCK, &data_blob_null);
+ }
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Unlock a range of bytes - POSIX semantics.
+****************************************************************************/
+
+static bool brl_unlock_posix(struct messaging_context *msg_ctx,
+ struct byte_range_lock *br_lck,
+ const struct lock_struct *plock)
+{
+ unsigned int i, j, count;
+ struct lock_struct *tp;
+ struct lock_struct *locks = br_lck->lock_data;
+ bool overlap_found = False;
+
+ /* No zero-zero locks for POSIX. */
+ if (plock->start == 0 && plock->size == 0) {
+ return False;
+ }
+
+ /* Don't allow 64-bit lock wrap. */
+ if (plock->start + plock->size < plock->start ||
+ plock->start + plock->size < plock->size) {
+ DEBUG(10,("brl_unlock_posix: lock wrap\n"));
+ return False;
+ }
+
+ /* The worst case scenario here is we have to split an
+ existing POSIX lock range into two, so we need at most
+ 1 more entry. */
+
+ tp = SMB_MALLOC_ARRAY(struct lock_struct, (br_lck->num_locks + 1));
+ if (!tp) {
+ DEBUG(10,("brl_unlock_posix: malloc fail\n"));
+ return False;
+ }
+
+ count = 0;
+ for (i = 0; i < br_lck->num_locks; i++) {
+ struct lock_struct *lock = &locks[i];
+ struct lock_struct tmp_lock[3];
+ bool lock_was_added = False;
+ unsigned int tmp_count;
+
+ /* Only remove our own locks - ignore fnum. */
+ if (IS_PENDING_LOCK(lock->lock_type) ||
+ !brl_same_context(&lock->context, &plock->context)) {
+ memcpy(&tp[count], lock, sizeof(struct lock_struct));
+ count++;
+ continue;
+ }
+
+ /* Work out overlaps. */
+ tmp_count = brlock_posix_split_merge(&tmp_lock[0], &locks[i], plock, &lock_was_added);
+
+ if (tmp_count == 1) {
+ /* Ether the locks didn't overlap, or the unlock completely
+ overlapped this lock. If it didn't overlap, then there's
+ no change in the locks. */
+ if (tmp_lock[0].lock_type != UNLOCK_LOCK) {
+ SMB_ASSERT(tmp_lock[0].lock_type == locks[i].lock_type);
+ /* No change in this lock. */
+ memcpy(&tp[count], &tmp_lock[0], sizeof(struct lock_struct));
+ count++;
+ } else {
+ SMB_ASSERT(tmp_lock[0].lock_type == UNLOCK_LOCK);
+ overlap_found = True;
+ }
+ continue;
+ } else if (tmp_count == 2) {
+ /* The unlock overlapped an existing lock. Copy the truncated
+ lock into the lock array. */
+ if (tmp_lock[0].lock_type != UNLOCK_LOCK) {
+ SMB_ASSERT(tmp_lock[0].lock_type == locks[i].lock_type);
+ SMB_ASSERT(tmp_lock[1].lock_type == UNLOCK_LOCK);
+ memcpy(&tp[count], &tmp_lock[0], sizeof(struct lock_struct));
+ if (tmp_lock[0].size != locks[i].size) {
+ overlap_found = True;
+ }
+ } else {
+ SMB_ASSERT(tmp_lock[0].lock_type == UNLOCK_LOCK);
+ SMB_ASSERT(tmp_lock[1].lock_type == locks[i].lock_type);
+ memcpy(&tp[count], &tmp_lock[1], sizeof(struct lock_struct));
+ if (tmp_lock[1].start != locks[i].start) {
+ overlap_found = True;
+ }
+ }
+ count++;
+ continue;
+ } else {
+ /* tmp_count == 3 - (we split a lock range in two). */
+ SMB_ASSERT(tmp_lock[0].lock_type == locks[i].lock_type);
+ SMB_ASSERT(tmp_lock[1].lock_type == UNLOCK_LOCK);
+ SMB_ASSERT(tmp_lock[2].lock_type == locks[i].lock_type);
+
+ memcpy(&tp[count], &tmp_lock[0], sizeof(struct lock_struct));
+ count++;
+ memcpy(&tp[count], &tmp_lock[2], sizeof(struct lock_struct));
+ count++;
+ overlap_found = True;
+ /* Optimisation... */
+ /* We know we're finished here as we can't overlap any
+ more POSIX locks. Copy the rest of the lock array. */
+ if (i < br_lck->num_locks - 1) {
+ memcpy(&tp[count], &locks[i+1],
+ sizeof(*locks)*((br_lck->num_locks-1) - i));
+ count += ((br_lck->num_locks-1) - i);
+ }
+ break;
+ }
+ }
+
+ if (!overlap_found) {
+ /* Just ignore - no change. */
+ SAFE_FREE(tp);
+ DEBUG(10,("brl_unlock_posix: No overlap - unlocked.\n"));
+ return True;
+ }
+
+ /* Unlock any POSIX regions. */
+ if(lp_posix_locking(br_lck->fsp->conn->params)) {
+ release_posix_lock_posix_flavour(br_lck->fsp,
+ plock->start,
+ plock->size,
+ &plock->context,
+ tp,
+ count);
+ }
+
+ /* Realloc so we don't leak entries per unlock call. */
+ if (count) {
+ tp = (struct lock_struct *)SMB_REALLOC(tp, count * sizeof(*locks));
+ if (!tp) {
+ DEBUG(10,("brl_unlock_posix: realloc fail\n"));
+ return False;
+ }
+ } else {
+ /* We deleted the last lock. */
+ SAFE_FREE(tp);
+ tp = NULL;
+ }
+
+ br_lck->num_locks = count;
+ SAFE_FREE(br_lck->lock_data);
+ locks = tp;
+ br_lck->lock_data = tp;
+ br_lck->modified = True;
+
+ /* Send unlock messages to any pending waiters that overlap. */
+
+ for (j=0; j < br_lck->num_locks; j++) {
+ struct lock_struct *pend_lock = &locks[j];
+
+ /* Ignore non-pending locks. */
+ if (!IS_PENDING_LOCK(pend_lock->lock_type)) {
+ continue;
+ }
+
+ /* We could send specific lock info here... */
+ if (brl_pending_overlap(plock, pend_lock)) {
+ DEBUG(10,("brl_unlock: sending unlock message to pid %s\n",
+ procid_str_static(&pend_lock->context.pid )));
+
+ messaging_send(msg_ctx, pend_lock->context.pid,
+ MSG_SMB_UNLOCK, &data_blob_null);
+ }
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Unlock a range of bytes.
+****************************************************************************/
+
+bool brl_unlock(struct messaging_context *msg_ctx,
+ struct byte_range_lock *br_lck,
+ uint32 smbpid,
+ struct server_id pid,
+ br_off start,
+ br_off size,
+ enum brl_flavour lock_flav)
+{
+ struct lock_struct lock;
+
+ lock.context.smbpid = smbpid;
+ lock.context.pid = pid;
+ lock.context.tid = br_lck->fsp->conn->cnum;
+ lock.start = start;
+ lock.size = size;
+ lock.fnum = br_lck->fsp->fnum;
+ lock.lock_type = UNLOCK_LOCK;
+ lock.lock_flav = lock_flav;
+
+ if (lock_flav == WINDOWS_LOCK) {
+ return brl_unlock_windows(msg_ctx, br_lck, &lock);
+ } else {
+ return brl_unlock_posix(msg_ctx, br_lck, &lock);
+ }
+}
+
+/****************************************************************************
+ Test if we could add a lock if we wanted to.
+ Returns True if the region required is currently unlocked, False if locked.
+****************************************************************************/
+
+bool brl_locktest(struct byte_range_lock *br_lck,
+ uint32 smbpid,
+ struct server_id pid,
+ br_off start,
+ br_off size,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav)
+{
+ bool ret = True;
+ unsigned int i;
+ struct lock_struct lock;
+ const struct lock_struct *locks = br_lck->lock_data;
+ files_struct *fsp = br_lck->fsp;
+
+ lock.context.smbpid = smbpid;
+ lock.context.pid = pid;
+ lock.context.tid = br_lck->fsp->conn->cnum;
+ lock.start = start;
+ lock.size = size;
+ lock.fnum = fsp->fnum;
+ lock.lock_type = lock_type;
+ lock.lock_flav = lock_flav;
+
+ /* Make sure existing locks don't conflict */
+ for (i=0; i < br_lck->num_locks; i++) {
+ /*
+ * Our own locks don't conflict.
+ */
+ if (brl_conflict_other(&locks[i], &lock)) {
+ return False;
+ }
+ }
+
+ /*
+ * There is no lock held by an SMB daemon, check to
+ * see if there is a POSIX lock from a UNIX or NFS process.
+ * This only conflicts with Windows locks, not POSIX locks.
+ */
+
+ if(lp_posix_locking(fsp->conn->params) && (lock_flav == WINDOWS_LOCK)) {
+ ret = is_posix_locked(fsp, &start, &size, &lock_type, WINDOWS_LOCK);
+
+ DEBUG(10,("brl_locktest: posix start=%.0f len=%.0f %s for fnum %d file %s\n",
+ (double)start, (double)size, ret ? "locked" : "unlocked",
+ fsp->fnum, fsp->fsp_name ));
+
+ /* We need to return the inverse of is_posix_locked. */
+ ret = !ret;
+ }
+
+ /* no conflicts - we could have added it */
+ return ret;
+}
+
+/****************************************************************************
+ Query for existing locks.
+****************************************************************************/
+
+NTSTATUS brl_lockquery(struct byte_range_lock *br_lck,
+ uint32 *psmbpid,
+ struct server_id pid,
+ br_off *pstart,
+ br_off *psize,
+ enum brl_type *plock_type,
+ enum brl_flavour lock_flav)
+{
+ unsigned int i;
+ struct lock_struct lock;
+ const struct lock_struct *locks = br_lck->lock_data;
+ files_struct *fsp = br_lck->fsp;
+
+ lock.context.smbpid = *psmbpid;
+ lock.context.pid = pid;
+ lock.context.tid = br_lck->fsp->conn->cnum;
+ lock.start = *pstart;
+ lock.size = *psize;
+ lock.fnum = fsp->fnum;
+ lock.lock_type = *plock_type;
+ lock.lock_flav = lock_flav;
+
+ /* Make sure existing locks don't conflict */
+ for (i=0; i < br_lck->num_locks; i++) {
+ const struct lock_struct *exlock = &locks[i];
+ bool conflict = False;
+
+ if (exlock->lock_flav == WINDOWS_LOCK) {
+ conflict = brl_conflict(exlock, &lock);
+ } else {
+ conflict = brl_conflict_posix(exlock, &lock);
+ }
+
+ if (conflict) {
+ *psmbpid = exlock->context.smbpid;
+ *pstart = exlock->start;
+ *psize = exlock->size;
+ *plock_type = exlock->lock_type;
+ return NT_STATUS_LOCK_NOT_GRANTED;
+ }
+ }
+
+ /*
+ * There is no lock held by an SMB daemon, check to
+ * see if there is a POSIX lock from a UNIX or NFS process.
+ */
+
+ if(lp_posix_locking(fsp->conn->params)) {
+ bool ret = is_posix_locked(fsp, pstart, psize, plock_type, POSIX_LOCK);
+
+ DEBUG(10,("brl_lockquery: posix start=%.0f len=%.0f %s for fnum %d file %s\n",
+ (double)*pstart, (double)*psize, ret ? "locked" : "unlocked",
+ fsp->fnum, fsp->fsp_name ));
+
+ if (ret) {
+ /* Hmmm. No clue what to set smbpid to - use -1. */
+ *psmbpid = 0xFFFF;
+ return NT_STATUS_LOCK_NOT_GRANTED;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Remove a particular pending lock.
+****************************************************************************/
+
+bool brl_lock_cancel(struct byte_range_lock *br_lck,
+ uint32 smbpid,
+ struct server_id pid,
+ br_off start,
+ br_off size,
+ enum brl_flavour lock_flav)
+{
+ unsigned int i;
+ struct lock_struct *locks = br_lck->lock_data;
+ struct lock_context context;
+
+ context.smbpid = smbpid;
+ context.pid = pid;
+ context.tid = br_lck->fsp->conn->cnum;
+
+ for (i = 0; i < br_lck->num_locks; i++) {
+ struct lock_struct *lock = &locks[i];
+
+ /* For pending locks we *always* care about the fnum. */
+ if (brl_same_context(&lock->context, &context) &&
+ lock->fnum == br_lck->fsp->fnum &&
+ IS_PENDING_LOCK(lock->lock_type) &&
+ lock->lock_flav == lock_flav &&
+ lock->start == start &&
+ lock->size == size) {
+ break;
+ }
+ }
+
+ if (i == br_lck->num_locks) {
+ /* Didn't find it. */
+ return False;
+ }
+
+ if (i < br_lck->num_locks - 1) {
+ /* Found this particular pending lock - delete it */
+ memmove(&locks[i], &locks[i+1],
+ sizeof(*locks)*((br_lck->num_locks-1) - i));
+ }
+
+ br_lck->num_locks -= 1;
+ br_lck->modified = True;
+ return True;
+}
+
+/****************************************************************************
+ Remove any locks associated with a open file.
+ We return True if this process owns any other Windows locks on this
+ fd and so we should not immediately close the fd.
+****************************************************************************/
+
+void brl_close_fnum(struct messaging_context *msg_ctx,
+ struct byte_range_lock *br_lck)
+{
+ files_struct *fsp = br_lck->fsp;
+ uint16 tid = fsp->conn->cnum;
+ int fnum = fsp->fnum;
+ unsigned int i, j, dcount=0;
+ int num_deleted_windows_locks = 0;
+ struct lock_struct *locks = br_lck->lock_data;
+ struct server_id pid = procid_self();
+ bool unlock_individually = False;
+
+ if(lp_posix_locking(fsp->conn->params)) {
+
+ /* Check if there are any Windows locks associated with this dev/ino
+ pair that are not this fnum. If so we need to call unlock on each
+ one in order to release the system POSIX locks correctly. */
+
+ for (i=0; i < br_lck->num_locks; i++) {
+ struct lock_struct *lock = &locks[i];
+
+ if (!procid_equal(&lock->context.pid, &pid)) {
+ continue;
+ }
+
+ if (lock->lock_type != READ_LOCK && lock->lock_type != WRITE_LOCK) {
+ continue; /* Ignore pending. */
+ }
+
+ if (lock->context.tid != tid || lock->fnum != fnum) {
+ unlock_individually = True;
+ break;
+ }
+ }
+
+ if (unlock_individually) {
+ struct lock_struct *locks_copy;
+ unsigned int num_locks_copy;
+
+ /* Copy the current lock array. */
+ if (br_lck->num_locks) {
+ locks_copy = (struct lock_struct *)TALLOC_MEMDUP(br_lck, locks, br_lck->num_locks * sizeof(struct lock_struct));
+ if (!locks_copy) {
+ smb_panic("brl_close_fnum: talloc failed");
+ }
+ } else {
+ locks_copy = NULL;
+ }
+
+ num_locks_copy = br_lck->num_locks;
+
+ for (i=0; i < num_locks_copy; i++) {
+ struct lock_struct *lock = &locks_copy[i];
+
+ if (lock->context.tid == tid && procid_equal(&lock->context.pid, &pid) &&
+ (lock->fnum == fnum)) {
+ brl_unlock(msg_ctx,
+ br_lck,
+ lock->context.smbpid,
+ pid,
+ lock->start,
+ lock->size,
+ lock->lock_flav);
+ }
+ }
+ return;
+ }
+ }
+
+ /* We can bulk delete - any POSIX locks will be removed when the fd closes. */
+
+ /* Remove any existing locks for this fnum (or any fnum if they're POSIX). */
+
+ for (i=0; i < br_lck->num_locks; i++) {
+ struct lock_struct *lock = &locks[i];
+ bool del_this_lock = False;
+
+ if (lock->context.tid == tid && procid_equal(&lock->context.pid, &pid)) {
+ if ((lock->lock_flav == WINDOWS_LOCK) && (lock->fnum == fnum)) {
+ del_this_lock = True;
+ num_deleted_windows_locks++;
+ } else if (lock->lock_flav == POSIX_LOCK) {
+ del_this_lock = True;
+ }
+ }
+
+ if (del_this_lock) {
+ /* Send unlock messages to any pending waiters that overlap. */
+ for (j=0; j < br_lck->num_locks; j++) {
+ struct lock_struct *pend_lock = &locks[j];
+
+ /* Ignore our own or non-pending locks. */
+ if (!IS_PENDING_LOCK(pend_lock->lock_type)) {
+ continue;
+ }
+
+ /* Optimisation - don't send to this fnum as we're
+ closing it. */
+ if (pend_lock->context.tid == tid &&
+ procid_equal(&pend_lock->context.pid, &pid) &&
+ pend_lock->fnum == fnum) {
+ continue;
+ }
+
+ /* We could send specific lock info here... */
+ if (brl_pending_overlap(lock, pend_lock)) {
+ messaging_send(msg_ctx, pend_lock->context.pid,
+ MSG_SMB_UNLOCK, &data_blob_null);
+ }
+ }
+
+ /* found it - delete it */
+ if (br_lck->num_locks > 1 && i < br_lck->num_locks - 1) {
+ memmove(&locks[i], &locks[i+1],
+ sizeof(*locks)*((br_lck->num_locks-1) - i));
+ }
+ br_lck->num_locks--;
+ br_lck->modified = True;
+ i--;
+ dcount++;
+ }
+ }
+
+ if(lp_posix_locking(fsp->conn->params) && num_deleted_windows_locks) {
+ /* Reduce the Windows lock POSIX reference count on this dev/ino pair. */
+ reduce_windows_lock_ref_count(fsp, num_deleted_windows_locks);
+ }
+}
+
+/****************************************************************************
+ Ensure this set of lock entries is valid.
+****************************************************************************/
+
+static bool validate_lock_entries(unsigned int *pnum_entries, struct lock_struct **pplocks)
+{
+ unsigned int i;
+ unsigned int num_valid_entries = 0;
+ struct lock_struct *locks = *pplocks;
+
+ for (i = 0; i < *pnum_entries; i++) {
+ struct lock_struct *lock_data = &locks[i];
+ if (!process_exists(lock_data->context.pid)) {
+ /* This process no longer exists - mark this
+ entry as invalid by zeroing it. */
+ ZERO_STRUCTP(lock_data);
+ } else {
+ num_valid_entries++;
+ }
+ }
+
+ if (num_valid_entries != *pnum_entries) {
+ struct lock_struct *new_lock_data = NULL;
+
+ if (num_valid_entries) {
+ new_lock_data = SMB_MALLOC_ARRAY(struct lock_struct, num_valid_entries);
+ if (!new_lock_data) {
+ DEBUG(3, ("malloc fail\n"));
+ return False;
+ }
+
+ num_valid_entries = 0;
+ for (i = 0; i < *pnum_entries; i++) {
+ struct lock_struct *lock_data = &locks[i];
+ if (lock_data->context.smbpid &&
+ lock_data->context.tid) {
+ /* Valid (nonzero) entry - copy it. */
+ memcpy(&new_lock_data[num_valid_entries],
+ lock_data, sizeof(struct lock_struct));
+ num_valid_entries++;
+ }
+ }
+ }
+
+ SAFE_FREE(*pplocks);
+ *pplocks = new_lock_data;
+ *pnum_entries = num_valid_entries;
+ }
+
+ return True;
+}
+
+struct brl_forall_cb {
+ void (*fn)(struct file_id id, struct server_id pid,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ br_off start, br_off size,
+ void *private_data);
+ void *private_data;
+};
+
+/****************************************************************************
+ Traverse the whole database with this function, calling traverse_callback
+ on each lock.
+****************************************************************************/
+
+static int traverse_fn(struct db_record *rec, void *state)
+{
+ struct brl_forall_cb *cb = (struct brl_forall_cb *)state;
+ struct lock_struct *locks;
+ struct file_id *key;
+ unsigned int i;
+ unsigned int num_locks = 0;
+ unsigned int orig_num_locks = 0;
+
+ /* In a traverse function we must make a copy of
+ dbuf before modifying it. */
+
+ locks = (struct lock_struct *)memdup(rec->value.dptr,
+ rec->value.dsize);
+ if (!locks) {
+ return -1; /* Terminate traversal. */
+ }
+
+ key = (struct file_id *)rec->key.dptr;
+ orig_num_locks = num_locks = rec->value.dsize/sizeof(*locks);
+
+ /* Ensure the lock db is clean of entries from invalid processes. */
+
+ if (!validate_lock_entries(&num_locks, &locks)) {
+ SAFE_FREE(locks);
+ return -1; /* Terminate traversal */
+ }
+
+ if (orig_num_locks != num_locks) {
+ if (num_locks) {
+ TDB_DATA data;
+ data.dptr = (uint8_t *)locks;
+ data.dsize = num_locks*sizeof(struct lock_struct);
+ rec->store(rec, data, TDB_REPLACE);
+ } else {
+ rec->delete_rec(rec);
+ }
+ }
+
+ if (cb->fn) {
+ for ( i=0; i<num_locks; i++) {
+ cb->fn(*key,
+ locks[i].context.pid,
+ locks[i].lock_type,
+ locks[i].lock_flav,
+ locks[i].start,
+ locks[i].size,
+ cb->private_data);
+ }
+ }
+
+ SAFE_FREE(locks);
+ return 0;
+}
+
+/*******************************************************************
+ Call the specified function on each lock in the database.
+********************************************************************/
+
+int brl_forall(void (*fn)(struct file_id id, struct server_id pid,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ br_off start, br_off size,
+ void *private_data),
+ void *private_data)
+{
+ struct brl_forall_cb cb;
+
+ if (!brlock_db) {
+ return 0;
+ }
+ cb.fn = fn;
+ cb.private_data = private_data;
+ return brlock_db->traverse(brlock_db, traverse_fn, &cb);
+}
+
+/*******************************************************************
+ Store a potentially modified set of byte range lock data back into
+ the database.
+ Unlock the record.
+********************************************************************/
+
+static int byte_range_lock_destructor(struct byte_range_lock *br_lck)
+{
+ if (br_lck->read_only) {
+ SMB_ASSERT(!br_lck->modified);
+ }
+
+ if (!br_lck->modified) {
+ goto done;
+ }
+
+ if (br_lck->num_locks == 0) {
+ /* No locks - delete this entry. */
+ NTSTATUS status = br_lck->record->delete_rec(br_lck->record);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("delete_rec returned %s\n",
+ nt_errstr(status)));
+ smb_panic("Could not delete byte range lock entry");
+ }
+ } else {
+ TDB_DATA data;
+ NTSTATUS status;
+
+ data.dptr = (uint8 *)br_lck->lock_data;
+ data.dsize = br_lck->num_locks * sizeof(struct lock_struct);
+
+ status = br_lck->record->store(br_lck->record, data,
+ TDB_REPLACE);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("store returned %s\n", nt_errstr(status)));
+ smb_panic("Could not store byte range mode entry");
+ }
+ }
+
+ done:
+
+ SAFE_FREE(br_lck->lock_data);
+ TALLOC_FREE(br_lck->record);
+ return 0;
+}
+
+/*******************************************************************
+ Fetch a set of byte range lock data from the database.
+ Leave the record locked.
+ TALLOC_FREE(brl) will release the lock in the destructor.
+********************************************************************/
+
+static struct byte_range_lock *brl_get_locks_internal(TALLOC_CTX *mem_ctx,
+ files_struct *fsp, bool read_only)
+{
+ TDB_DATA key, data;
+ struct byte_range_lock *br_lck = TALLOC_P(mem_ctx, struct byte_range_lock);
+
+ if (br_lck == NULL) {
+ return NULL;
+ }
+
+ br_lck->fsp = fsp;
+ br_lck->num_locks = 0;
+ br_lck->modified = False;
+ memset(&br_lck->key, '\0', sizeof(struct file_id));
+ br_lck->key = fsp->file_id;
+
+ key.dptr = (uint8 *)&br_lck->key;
+ key.dsize = sizeof(struct file_id);
+
+ if (!fsp->lockdb_clean) {
+ /* We must be read/write to clean
+ the dead entries. */
+ read_only = False;
+ }
+
+ if (read_only) {
+ if (brlock_db->fetch(brlock_db, br_lck, key, &data) == -1) {
+ DEBUG(3, ("Could not fetch byte range lock record\n"));
+ TALLOC_FREE(br_lck);
+ return NULL;
+ }
+ br_lck->record = NULL;
+ }
+ else {
+ br_lck->record = brlock_db->fetch_locked(brlock_db, br_lck, key);
+
+ if (br_lck->record == NULL) {
+ DEBUG(3, ("Could not lock byte range lock entry\n"));
+ TALLOC_FREE(br_lck);
+ return NULL;
+ }
+
+ data = br_lck->record->value;
+ }
+
+ br_lck->read_only = read_only;
+ br_lck->lock_data = NULL;
+
+ talloc_set_destructor(br_lck, byte_range_lock_destructor);
+
+ br_lck->num_locks = data.dsize / sizeof(struct lock_struct);
+
+ if (br_lck->num_locks != 0) {
+ br_lck->lock_data = SMB_MALLOC_ARRAY(struct lock_struct,
+ br_lck->num_locks);
+ if (br_lck->lock_data == NULL) {
+ DEBUG(0, ("malloc failed\n"));
+ TALLOC_FREE(br_lck);
+ return NULL;
+ }
+
+ memcpy(br_lck->lock_data, data.dptr, data.dsize);
+ }
+
+ if (!fsp->lockdb_clean) {
+ int orig_num_locks = br_lck->num_locks;
+
+ /* This is the first time we've accessed this. */
+ /* Go through and ensure all entries exist - remove any that don't. */
+ /* Makes the lockdb self cleaning at low cost. */
+
+ if (!validate_lock_entries(&br_lck->num_locks,
+ &br_lck->lock_data)) {
+ SAFE_FREE(br_lck->lock_data);
+ TALLOC_FREE(br_lck);
+ return NULL;
+ }
+
+ /* Ensure invalid locks are cleaned up in the destructor. */
+ if (orig_num_locks != br_lck->num_locks) {
+ br_lck->modified = True;
+ }
+
+ /* Mark the lockdb as "clean" as seen from this open file. */
+ fsp->lockdb_clean = True;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ unsigned int i;
+ struct lock_struct *locks = br_lck->lock_data;
+ DEBUG(10,("brl_get_locks_internal: %u current locks on file_id %s\n",
+ br_lck->num_locks,
+ file_id_string_tos(&fsp->file_id)));
+ for( i = 0; i < br_lck->num_locks; i++) {
+ print_lock_struct(i, &locks[i]);
+ }
+ }
+ return br_lck;
+}
+
+struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx,
+ files_struct *fsp)
+{
+ return brl_get_locks_internal(mem_ctx, fsp, False);
+}
+
+struct byte_range_lock *brl_get_locks_readonly(TALLOC_CTX *mem_ctx,
+ files_struct *fsp)
+{
+ return brl_get_locks_internal(mem_ctx, fsp, True);
+}
+
+struct brl_revalidate_state {
+ ssize_t array_size;
+ uint32 num_pids;
+ struct server_id *pids;
+};
+
+/*
+ * Collect PIDs of all processes with pending entries
+ */
+
+static void brl_revalidate_collect(struct file_id id, struct server_id pid,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ br_off start, br_off size,
+ void *private_data)
+{
+ struct brl_revalidate_state *state =
+ (struct brl_revalidate_state *)private_data;
+
+ if (!IS_PENDING_LOCK(lock_type)) {
+ return;
+ }
+
+ add_to_large_array(state, sizeof(pid), (void *)&pid,
+ &state->pids, &state->num_pids,
+ &state->array_size);
+}
+
+/*
+ * qsort callback to sort the processes
+ */
+
+static int compare_procids(const void *p1, const void *p2)
+{
+ const struct server_id *i1 = (struct server_id *)p1;
+ const struct server_id *i2 = (struct server_id *)p2;
+
+ if (i1->pid < i2->pid) return -1;
+ if (i2->pid > i2->pid) return 1;
+ return 0;
+}
+
+/*
+ * Send a MSG_SMB_UNLOCK message to all processes with pending byte range
+ * locks so that they retry. Mainly used in the cluster code after a node has
+ * died.
+ *
+ * Done in two steps to avoid double-sends: First we collect all entries in an
+ * array, then qsort that array and only send to non-dupes.
+ */
+
+static void brl_revalidate(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct brl_revalidate_state *state;
+ uint32 i;
+ struct server_id last_pid;
+
+ if (!(state = TALLOC_ZERO_P(NULL, struct brl_revalidate_state))) {
+ DEBUG(0, ("talloc failed\n"));
+ return;
+ }
+
+ brl_forall(brl_revalidate_collect, state);
+
+ if (state->array_size == -1) {
+ DEBUG(0, ("talloc failed\n"));
+ goto done;
+ }
+
+ if (state->num_pids == 0) {
+ goto done;
+ }
+
+ qsort(state->pids, state->num_pids, sizeof(state->pids[0]),
+ compare_procids);
+
+ ZERO_STRUCT(last_pid);
+
+ for (i=0; i<state->num_pids; i++) {
+ if (procid_equal(&last_pid, &state->pids[i])) {
+ /*
+ * We've seen that one already
+ */
+ continue;
+ }
+
+ messaging_send(msg_ctx, state->pids[i], MSG_SMB_UNLOCK,
+ &data_blob_null);
+ last_pid = state->pids[i];
+ }
+
+ done:
+ TALLOC_FREE(state);
+ return;
+}
+
+void brl_register_msgs(struct messaging_context *msg_ctx)
+{
+ messaging_register(msg_ctx, NULL, MSG_SMB_BRL_VALIDATE,
+ brl_revalidate);
+}
diff --git a/source3/locking/locking.c b/source3/locking/locking.c
new file mode 100644
index 0000000000..368ab1687c
--- /dev/null
+++ b/source3/locking/locking.c
@@ -0,0 +1,1511 @@
+/*
+ Unix SMB/CIFS implementation.
+ Locking functions
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Jeremy Allison 1992-2006
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Revision History:
+
+ 12 aug 96: Erik.Devriendt@te6.siemens.be
+ added support for shared memory implementation of share mode locking
+
+ May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
+ locking to deal with multiple share modes per open file.
+
+ September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
+ support.
+
+ rewrtten completely to use new tdb code. Tridge, Dec '99
+
+ Added POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000.
+ Added Unix Extensions POSIX locking support. Jeremy Allison Mar 2006.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_LOCKING
+
+#define NO_LOCKING_COUNT (-1)
+
+/* the locking database handle */
+static struct db_context *lock_db;
+
+/****************************************************************************
+ Debugging aids :-).
+****************************************************************************/
+
+const char *lock_type_name(enum brl_type lock_type)
+{
+ switch (lock_type) {
+ case READ_LOCK:
+ return "READ";
+ case WRITE_LOCK:
+ return "WRITE";
+ case PENDING_READ_LOCK:
+ return "PENDING_READ";
+ case PENDING_WRITE_LOCK:
+ return "PENDING_WRITE";
+ default:
+ return "other";
+ }
+}
+
+const char *lock_flav_name(enum brl_flavour lock_flav)
+{
+ return (lock_flav == WINDOWS_LOCK) ? "WINDOWS_LOCK" : "POSIX_LOCK";
+}
+
+/****************************************************************************
+ Utility function called to see if a file region is locked.
+ Called in the read/write codepath.
+****************************************************************************/
+
+bool is_locked(files_struct *fsp,
+ uint32 smbpid,
+ SMB_BIG_UINT count,
+ SMB_BIG_UINT offset,
+ enum brl_type lock_type)
+{
+ int strict_locking = lp_strict_locking(fsp->conn->params);
+ enum brl_flavour lock_flav = lp_posix_cifsu_locktype(fsp);
+ bool ret = True;
+
+ if (count == 0) {
+ return False;
+ }
+
+ if (!lp_locking(fsp->conn->params) || !strict_locking) {
+ return False;
+ }
+
+ if (strict_locking == Auto) {
+ if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && (lock_type == READ_LOCK || lock_type == WRITE_LOCK)) {
+ DEBUG(10,("is_locked: optimisation - exclusive oplock on file %s\n", fsp->fsp_name ));
+ ret = False;
+ } else if ((fsp->oplock_type == LEVEL_II_OPLOCK) &&
+ (lock_type == READ_LOCK)) {
+ DEBUG(10,("is_locked: optimisation - level II oplock on file %s\n", fsp->fsp_name ));
+ ret = False;
+ } else {
+ struct byte_range_lock *br_lck = brl_get_locks_readonly(talloc_tos(), fsp);
+ if (!br_lck) {
+ return False;
+ }
+ ret = !brl_locktest(br_lck,
+ smbpid,
+ procid_self(),
+ offset,
+ count,
+ lock_type,
+ lock_flav);
+ TALLOC_FREE(br_lck);
+ }
+ } else {
+ struct byte_range_lock *br_lck = brl_get_locks_readonly(talloc_tos(), fsp);
+ if (!br_lck) {
+ return False;
+ }
+ ret = !brl_locktest(br_lck,
+ smbpid,
+ procid_self(),
+ offset,
+ count,
+ lock_type,
+ lock_flav);
+ TALLOC_FREE(br_lck);
+ }
+
+ DEBUG(10,("is_locked: flavour = %s brl start=%.0f len=%.0f %s for fnum %d file %s\n",
+ lock_flav_name(lock_flav),
+ (double)offset, (double)count, ret ? "locked" : "unlocked",
+ fsp->fnum, fsp->fsp_name ));
+
+ return ret;
+}
+
+/****************************************************************************
+ Find out if a lock could be granted - return who is blocking us if we can't.
+****************************************************************************/
+
+NTSTATUS query_lock(files_struct *fsp,
+ uint32 *psmbpid,
+ SMB_BIG_UINT *pcount,
+ SMB_BIG_UINT *poffset,
+ enum brl_type *plock_type,
+ enum brl_flavour lock_flav)
+{
+ struct byte_range_lock *br_lck = NULL;
+ NTSTATUS status = NT_STATUS_LOCK_NOT_GRANTED;
+
+ if (!fsp->can_lock) {
+ return fsp->is_directory ? NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE;
+ }
+
+ if (!lp_locking(fsp->conn->params)) {
+ return NT_STATUS_OK;
+ }
+
+ br_lck = brl_get_locks_readonly(talloc_tos(), fsp);
+ if (!br_lck) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = brl_lockquery(br_lck,
+ psmbpid,
+ procid_self(),
+ poffset,
+ pcount,
+ plock_type,
+ lock_flav);
+
+ TALLOC_FREE(br_lck);
+ return status;
+}
+
+/****************************************************************************
+ Utility function called by locking requests.
+****************************************************************************/
+
+struct byte_range_lock *do_lock(struct messaging_context *msg_ctx,
+ files_struct *fsp,
+ uint32 lock_pid,
+ SMB_BIG_UINT count,
+ SMB_BIG_UINT offset,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ bool blocking_lock,
+ NTSTATUS *perr,
+ uint32 *plock_pid)
+{
+ struct byte_range_lock *br_lck = NULL;
+
+ if (!fsp->can_lock) {
+ *perr = fsp->is_directory ? NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE;
+ return NULL;
+ }
+
+ if (!lp_locking(fsp->conn->params)) {
+ *perr = NT_STATUS_OK;
+ return NULL;
+ }
+
+ /* NOTE! 0 byte long ranges ARE allowed and should be stored */
+
+ DEBUG(10,("do_lock: lock flavour %s lock type %s start=%.0f len=%.0f requested for fnum %d file %s\n",
+ lock_flav_name(lock_flav), lock_type_name(lock_type),
+ (double)offset, (double)count, fsp->fnum, fsp->fsp_name ));
+
+ br_lck = brl_get_locks(talloc_tos(), fsp);
+ if (!br_lck) {
+ *perr = NT_STATUS_NO_MEMORY;
+ return NULL;
+ }
+
+ *perr = brl_lock(msg_ctx,
+ br_lck,
+ lock_pid,
+ procid_self(),
+ offset,
+ count,
+ lock_type,
+ lock_flav,
+ blocking_lock,
+ plock_pid);
+
+ if (lock_flav == WINDOWS_LOCK &&
+ fsp->current_lock_count != NO_LOCKING_COUNT) {
+ /* blocking ie. pending, locks also count here,
+ * as this is an efficiency counter to avoid checking
+ * the lock db. on close. JRA. */
+
+ fsp->current_lock_count++;
+ } else {
+ /* Notice that this has had a POSIX lock request.
+ * We can't count locks after this so forget them.
+ */
+ fsp->current_lock_count = NO_LOCKING_COUNT;
+ }
+
+ return br_lck;
+}
+
+/****************************************************************************
+ Utility function called by unlocking requests.
+****************************************************************************/
+
+NTSTATUS do_unlock(struct messaging_context *msg_ctx,
+ files_struct *fsp,
+ uint32 lock_pid,
+ SMB_BIG_UINT count,
+ SMB_BIG_UINT offset,
+ enum brl_flavour lock_flav)
+{
+ bool ok = False;
+ struct byte_range_lock *br_lck = NULL;
+
+ if (!fsp->can_lock) {
+ return fsp->is_directory ? NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE;
+ }
+
+ if (!lp_locking(fsp->conn->params)) {
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for fnum %d file %s\n",
+ (double)offset, (double)count, fsp->fnum, fsp->fsp_name ));
+
+ br_lck = brl_get_locks(talloc_tos(), fsp);
+ if (!br_lck) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ok = brl_unlock(msg_ctx,
+ br_lck,
+ lock_pid,
+ procid_self(),
+ offset,
+ count,
+ lock_flav);
+
+ TALLOC_FREE(br_lck);
+
+ if (!ok) {
+ DEBUG(10,("do_unlock: returning ERRlock.\n" ));
+ return NT_STATUS_RANGE_NOT_LOCKED;
+ }
+
+ if (lock_flav == WINDOWS_LOCK &&
+ fsp->current_lock_count != NO_LOCKING_COUNT) {
+ SMB_ASSERT(fsp->current_lock_count > 0);
+ fsp->current_lock_count--;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Cancel any pending blocked locks.
+****************************************************************************/
+
+NTSTATUS do_lock_cancel(files_struct *fsp,
+ uint32 lock_pid,
+ SMB_BIG_UINT count,
+ SMB_BIG_UINT offset,
+ enum brl_flavour lock_flav)
+{
+ bool ok = False;
+ struct byte_range_lock *br_lck = NULL;
+
+ if (!fsp->can_lock) {
+ return fsp->is_directory ?
+ NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE;
+ }
+
+ if (!lp_locking(fsp->conn->params)) {
+ return NT_STATUS_DOS(ERRDOS, ERRcancelviolation);
+ }
+
+ DEBUG(10,("do_lock_cancel: cancel start=%.0f len=%.0f requested for fnum %d file %s\n",
+ (double)offset, (double)count, fsp->fnum, fsp->fsp_name ));
+
+ br_lck = brl_get_locks(talloc_tos(), fsp);
+ if (!br_lck) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ok = brl_lock_cancel(br_lck,
+ lock_pid,
+ procid_self(),
+ offset,
+ count,
+ lock_flav);
+
+ TALLOC_FREE(br_lck);
+
+ if (!ok) {
+ DEBUG(10,("do_lock_cancel: returning ERRcancelviolation.\n" ));
+ return NT_STATUS_DOS(ERRDOS, ERRcancelviolation);
+ }
+
+ if (lock_flav == WINDOWS_LOCK &&
+ fsp->current_lock_count != NO_LOCKING_COUNT) {
+ SMB_ASSERT(fsp->current_lock_count > 0);
+ fsp->current_lock_count--;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Remove any locks on this fd. Called from file_close().
+****************************************************************************/
+
+void locking_close_file(struct messaging_context *msg_ctx,
+ files_struct *fsp)
+{
+ struct byte_range_lock *br_lck;
+
+ if (!lp_locking(fsp->conn->params)) {
+ return;
+ }
+
+ /* If we have not outstanding locks or pending
+ * locks then we don't need to look in the lock db.
+ */
+
+ if (fsp->current_lock_count == 0) {
+ return;
+ }
+
+ br_lck = brl_get_locks(talloc_tos(),fsp);
+
+ if (br_lck) {
+ cancel_pending_lock_requests_by_fid(fsp, br_lck);
+ brl_close_fnum(msg_ctx, br_lck);
+ TALLOC_FREE(br_lck);
+ }
+}
+
+/****************************************************************************
+ Initialise the locking functions.
+****************************************************************************/
+
+static bool locking_init_internal(bool read_only)
+{
+ brl_init(read_only);
+
+ if (lock_db)
+ return True;
+
+ lock_db = db_open(NULL, lock_path("locking.tdb"),
+ lp_open_files_db_hash_size(),
+ TDB_DEFAULT|TDB_VOLATILE|TDB_CLEAR_IF_FIRST,
+ read_only?O_RDONLY:O_RDWR|O_CREAT, 0644);
+
+ if (!lock_db) {
+ DEBUG(0,("ERROR: Failed to initialise locking database\n"));
+ return False;
+ }
+
+ if (!posix_locking_init(read_only))
+ return False;
+
+ return True;
+}
+
+bool locking_init(void)
+{
+ return locking_init_internal(false);
+}
+
+bool locking_init_readonly(void)
+{
+ return locking_init_internal(true);
+}
+
+/*******************************************************************
+ Deinitialize the share_mode management.
+******************************************************************/
+
+bool locking_end(void)
+{
+ brl_shutdown();
+ TALLOC_FREE(lock_db);
+ return true;
+}
+
+/*******************************************************************
+ Form a static locking key for a dev/inode pair.
+******************************************************************/
+
+static TDB_DATA locking_key(const struct file_id *id, struct file_id *tmp)
+{
+ *tmp = *id;
+ return make_tdb_data((const uint8_t *)tmp, sizeof(*tmp));
+}
+
+/*******************************************************************
+ Print out a share mode.
+********************************************************************/
+
+char *share_mode_str(TALLOC_CTX *ctx, int num, const struct share_mode_entry *e)
+{
+ return talloc_asprintf(ctx, "share_mode_entry[%d]: %s "
+ "pid = %s, share_access = 0x%x, private_options = 0x%x, "
+ "access_mask = 0x%x, mid = 0x%x, type= 0x%x, gen_id = %lu, "
+ "uid = %u, flags = %u, file_id %s",
+ num,
+ e->op_type == UNUSED_SHARE_MODE_ENTRY ? "UNUSED" : "",
+ procid_str_static(&e->pid),
+ e->share_access, e->private_options,
+ e->access_mask, e->op_mid, e->op_type, e->share_file_id,
+ (unsigned int)e->uid, (unsigned int)e->flags,
+ file_id_string_tos(&e->id));
+}
+
+/*******************************************************************
+ Print out a share mode table.
+********************************************************************/
+
+static void print_share_mode_table(struct locking_data *data)
+{
+ int num_share_modes = data->u.s.num_share_mode_entries;
+ struct share_mode_entry *shares =
+ (struct share_mode_entry *)(data + 1);
+ int i;
+
+ for (i = 0; i < num_share_modes; i++) {
+ struct share_mode_entry entry;
+ char *str;
+
+ /*
+ * We need to memcpy the entry here due to alignment
+ * restrictions that are not met when directly accessing
+ * shares[i]
+ */
+
+ memcpy(&entry, &shares[i], sizeof(struct share_mode_entry));
+ str = share_mode_str(talloc_tos(), i, &entry);
+
+ DEBUG(10,("print_share_mode_table: %s\n", str ? str : ""));
+ TALLOC_FREE(str);
+ }
+}
+
+/*******************************************************************
+ Get all share mode entries for a dev/inode pair.
+********************************************************************/
+
+static bool parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck)
+{
+ struct locking_data data;
+ int i;
+
+ if (dbuf.dsize < sizeof(struct locking_data)) {
+ smb_panic("parse_share_modes: buffer too short");
+ }
+
+ memcpy(&data, dbuf.dptr, sizeof(data));
+
+ lck->delete_on_close = data.u.s.delete_on_close;
+ lck->old_write_time = data.u.s.old_write_time;
+ lck->changed_write_time = data.u.s.changed_write_time;
+ lck->num_share_modes = data.u.s.num_share_mode_entries;
+
+ DEBUG(10, ("parse_share_modes: delete_on_close: %d, owrt: %s, "
+ "cwrt: %s, tok: %u, num_share_modes: %d\n",
+ lck->delete_on_close,
+ timestring(debug_ctx(),
+ convert_timespec_to_time_t(lck->old_write_time)),
+ timestring(debug_ctx(),
+ convert_timespec_to_time_t(
+ lck->changed_write_time)),
+ (unsigned int)data.u.s.delete_token_size,
+ lck->num_share_modes));
+
+ if ((lck->num_share_modes < 0) || (lck->num_share_modes > 1000000)) {
+ DEBUG(0, ("invalid number of share modes: %d\n",
+ lck->num_share_modes));
+ smb_panic("parse_share_modes: invalid number of share modes");
+ }
+
+ lck->share_modes = NULL;
+
+ if (lck->num_share_modes != 0) {
+
+ if (dbuf.dsize < (sizeof(struct locking_data) +
+ (lck->num_share_modes *
+ sizeof(struct share_mode_entry)))) {
+ smb_panic("parse_share_modes: buffer too short");
+ }
+
+ lck->share_modes = (struct share_mode_entry *)
+ TALLOC_MEMDUP(lck,
+ dbuf.dptr+sizeof(struct locking_data),
+ lck->num_share_modes *
+ sizeof(struct share_mode_entry));
+
+ if (lck->share_modes == NULL) {
+ smb_panic("parse_share_modes: talloc failed");
+ }
+ }
+
+ /* Get any delete token. */
+ if (data.u.s.delete_token_size) {
+ uint8 *p = dbuf.dptr + sizeof(struct locking_data) +
+ (lck->num_share_modes *
+ sizeof(struct share_mode_entry));
+
+ if ((data.u.s.delete_token_size < sizeof(uid_t) + sizeof(gid_t)) ||
+ ((data.u.s.delete_token_size - sizeof(uid_t)) % sizeof(gid_t)) != 0) {
+ DEBUG(0, ("parse_share_modes: invalid token size %d\n",
+ data.u.s.delete_token_size));
+ smb_panic("parse_share_modes: invalid token size");
+ }
+
+ lck->delete_token = TALLOC_P(lck, UNIX_USER_TOKEN);
+ if (!lck->delete_token) {
+ smb_panic("parse_share_modes: talloc failed");
+ }
+
+ /* Copy out the uid and gid. */
+ memcpy(&lck->delete_token->uid, p, sizeof(uid_t));
+ p += sizeof(uid_t);
+ memcpy(&lck->delete_token->gid, p, sizeof(gid_t));
+ p += sizeof(gid_t);
+
+ /* Any supplementary groups ? */
+ lck->delete_token->ngroups = (data.u.s.delete_token_size > (sizeof(uid_t) + sizeof(gid_t))) ?
+ ((data.u.s.delete_token_size -
+ (sizeof(uid_t) + sizeof(gid_t)))/sizeof(gid_t)) : 0;
+
+ if (lck->delete_token->ngroups) {
+ /* Make this a talloc child of lck->delete_token. */
+ lck->delete_token->groups = TALLOC_ARRAY(lck->delete_token, gid_t,
+ lck->delete_token->ngroups);
+ if (!lck->delete_token) {
+ smb_panic("parse_share_modes: talloc failed");
+ }
+
+ for (i = 0; i < lck->delete_token->ngroups; i++) {
+ memcpy(&lck->delete_token->groups[i], p, sizeof(gid_t));
+ p += sizeof(gid_t);
+ }
+ }
+
+ } else {
+ lck->delete_token = NULL;
+ }
+
+ /* Save off the associated service path and filename. */
+ lck->servicepath = (const char *)dbuf.dptr + sizeof(struct locking_data) +
+ (lck->num_share_modes * sizeof(struct share_mode_entry)) +
+ data.u.s.delete_token_size;
+
+ lck->filename = (const char *)dbuf.dptr + sizeof(struct locking_data) +
+ (lck->num_share_modes * sizeof(struct share_mode_entry)) +
+ data.u.s.delete_token_size +
+ strlen(lck->servicepath) + 1;
+
+ /*
+ * Ensure that each entry has a real process attached.
+ */
+
+ for (i = 0; i < lck->num_share_modes; i++) {
+ struct share_mode_entry *entry_p = &lck->share_modes[i];
+ char *str = NULL;
+ if (DEBUGLEVEL >= 10) {
+ str = share_mode_str(NULL, i, entry_p);
+ }
+ DEBUG(10,("parse_share_modes: %s\n",
+ str ? str : ""));
+ if (!process_exists(entry_p->pid)) {
+ DEBUG(10,("parse_share_modes: deleted %s\n",
+ str ? str : ""));
+ entry_p->op_type = UNUSED_SHARE_MODE_ENTRY;
+ lck->modified = True;
+ }
+ TALLOC_FREE(str);
+ }
+
+ return True;
+}
+
+static TDB_DATA unparse_share_modes(struct share_mode_lock *lck)
+{
+ TDB_DATA result;
+ int num_valid = 0;
+ int i;
+ struct locking_data *data;
+ ssize_t offset;
+ ssize_t sp_len;
+ uint32 delete_token_size;
+
+ result.dptr = NULL;
+ result.dsize = 0;
+
+ for (i=0; i<lck->num_share_modes; i++) {
+ if (!is_unused_share_mode_entry(&lck->share_modes[i])) {
+ num_valid += 1;
+ }
+ }
+
+ if (num_valid == 0) {
+ return result;
+ }
+
+ sp_len = strlen(lck->servicepath);
+ delete_token_size = (lck->delete_token ?
+ (sizeof(uid_t) + sizeof(gid_t) + (lck->delete_token->ngroups*sizeof(gid_t))) : 0);
+
+ result.dsize = sizeof(*data) +
+ lck->num_share_modes * sizeof(struct share_mode_entry) +
+ delete_token_size +
+ sp_len + 1 +
+ strlen(lck->filename) + 1;
+ result.dptr = TALLOC_ARRAY(lck, uint8, result.dsize);
+
+ if (result.dptr == NULL) {
+ smb_panic("talloc failed");
+ }
+
+ data = (struct locking_data *)result.dptr;
+ ZERO_STRUCTP(data);
+ data->u.s.num_share_mode_entries = lck->num_share_modes;
+ data->u.s.delete_on_close = lck->delete_on_close;
+ data->u.s.old_write_time = lck->old_write_time;
+ data->u.s.changed_write_time = lck->changed_write_time;
+ data->u.s.delete_token_size = delete_token_size;
+
+ DEBUG(10,("unparse_share_modes: del: %d, owrt: %s cwrt: %s, tok: %u, "
+ "num: %d\n", data->u.s.delete_on_close,
+ timestring(debug_ctx(),
+ convert_timespec_to_time_t(lck->old_write_time)),
+ timestring(debug_ctx(),
+ convert_timespec_to_time_t(
+ lck->changed_write_time)),
+ (unsigned int)data->u.s.delete_token_size,
+ data->u.s.num_share_mode_entries));
+
+ memcpy(result.dptr + sizeof(*data), lck->share_modes,
+ sizeof(struct share_mode_entry)*lck->num_share_modes);
+ offset = sizeof(*data) +
+ sizeof(struct share_mode_entry)*lck->num_share_modes;
+
+ /* Store any delete on close token. */
+ if (lck->delete_token) {
+ uint8 *p = result.dptr + offset;
+
+ memcpy(p, &lck->delete_token->uid, sizeof(uid_t));
+ p += sizeof(uid_t);
+
+ memcpy(p, &lck->delete_token->gid, sizeof(gid_t));
+ p += sizeof(gid_t);
+
+ for (i = 0; i < lck->delete_token->ngroups; i++) {
+ memcpy(p, &lck->delete_token->groups[i], sizeof(gid_t));
+ p += sizeof(gid_t);
+ }
+ offset = p - result.dptr;
+ }
+
+ safe_strcpy((char *)result.dptr + offset, lck->servicepath,
+ result.dsize - offset - 1);
+ offset += sp_len + 1;
+ safe_strcpy((char *)result.dptr + offset, lck->filename,
+ result.dsize - offset - 1);
+
+ if (DEBUGLEVEL >= 10) {
+ print_share_mode_table(data);
+ }
+
+ return result;
+}
+
+static int share_mode_lock_destructor(struct share_mode_lock *lck)
+{
+ NTSTATUS status;
+ TDB_DATA data;
+
+ if (!lck->modified) {
+ return 0;
+ }
+
+ data = unparse_share_modes(lck);
+
+ if (data.dptr == NULL) {
+ if (!lck->fresh) {
+ /* There has been an entry before, delete it */
+
+ status = lck->record->delete_rec(lck->record);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("delete_rec returned %s\n",
+ nt_errstr(status)));
+ smb_panic("could not delete share entry");
+ }
+ }
+ goto done;
+ }
+
+ status = lck->record->store(lck->record, data, TDB_REPLACE);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("store returned %s\n", nt_errstr(status)));
+ smb_panic("could not store share mode entry");
+ }
+
+ done:
+
+ return 0;
+}
+
+static bool fill_share_mode_lock(struct share_mode_lock *lck,
+ struct file_id id,
+ const char *servicepath,
+ const char *fname,
+ TDB_DATA share_mode_data,
+ const struct timespec *old_write_time)
+{
+ /* Ensure we set every field here as the destructor must be
+ valid even if parse_share_modes fails. */
+
+ lck->servicepath = NULL;
+ lck->filename = NULL;
+ lck->id = id;
+ lck->num_share_modes = 0;
+ lck->share_modes = NULL;
+ lck->delete_token = NULL;
+ lck->delete_on_close = False;
+ ZERO_STRUCT(lck->old_write_time);
+ ZERO_STRUCT(lck->changed_write_time);
+ lck->fresh = False;
+ lck->modified = False;
+
+ lck->fresh = (share_mode_data.dptr == NULL);
+
+ if (lck->fresh) {
+ if (fname == NULL || servicepath == NULL
+ || old_write_time == NULL) {
+ return False;
+ }
+ lck->filename = talloc_strdup(lck, fname);
+ lck->servicepath = talloc_strdup(lck, servicepath);
+ if (lck->filename == NULL || lck->servicepath == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return False;
+ }
+ lck->old_write_time = *old_write_time;
+ } else {
+ if (!parse_share_modes(share_mode_data, lck)) {
+ DEBUG(0, ("Could not parse share modes\n"));
+ return False;
+ }
+ }
+
+ return True;
+}
+
+struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx,
+ const struct file_id id,
+ const char *servicepath,
+ const char *fname,
+ const struct timespec *old_write_time)
+{
+ struct share_mode_lock *lck;
+ struct file_id tmp;
+ TDB_DATA key = locking_key(&id, &tmp);
+
+ if (!(lck = TALLOC_P(mem_ctx, struct share_mode_lock))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ if (!(lck->record = lock_db->fetch_locked(lock_db, lck, key))) {
+ DEBUG(3, ("Could not lock share entry\n"));
+ TALLOC_FREE(lck);
+ return NULL;
+ }
+
+ if (!fill_share_mode_lock(lck, id, servicepath, fname,
+ lck->record->value, old_write_time)) {
+ DEBUG(3, ("fill_share_mode_lock failed\n"));
+ TALLOC_FREE(lck);
+ return NULL;
+ }
+
+ talloc_set_destructor(lck, share_mode_lock_destructor);
+
+ return lck;
+}
+
+struct share_mode_lock *fetch_share_mode_unlocked(TALLOC_CTX *mem_ctx,
+ const struct file_id id,
+ const char *servicepath,
+ const char *fname)
+{
+ struct share_mode_lock *lck;
+ struct file_id tmp;
+ TDB_DATA key = locking_key(&id, &tmp);
+ TDB_DATA data;
+
+ if (!(lck = TALLOC_P(mem_ctx, struct share_mode_lock))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ if (lock_db->fetch(lock_db, lck, key, &data) == -1) {
+ DEBUG(3, ("Could not fetch share entry\n"));
+ TALLOC_FREE(lck);
+ return NULL;
+ }
+
+ if (!fill_share_mode_lock(lck, id, servicepath, fname, data, NULL)) {
+ DEBUG(3, ("fill_share_mode_lock failed\n"));
+ TALLOC_FREE(lck);
+ return NULL;
+ }
+
+ return lck;
+}
+
+/*******************************************************************
+ Sets the service name and filename for rename.
+ At this point we emit "file renamed" messages to all
+ process id's that have this file open.
+ Based on an initial code idea from SATOH Fumiyasu <fumiya@samba.gr.jp>
+********************************************************************/
+
+bool rename_share_filename(struct messaging_context *msg_ctx,
+ struct share_mode_lock *lck,
+ const char *servicepath,
+ const char *newname)
+{
+ size_t sp_len;
+ size_t fn_len;
+ size_t msg_len;
+ char *frm = NULL;
+ int i;
+
+ DEBUG(10, ("rename_share_filename: servicepath %s newname %s\n",
+ servicepath, newname));
+
+ /*
+ * rename_internal_fsp() and rename_internals() add './' to
+ * head of newname if newname does not contain a '/'.
+ */
+ while (newname[0] && newname[1] && newname[0] == '.' && newname[1] == '/') {
+ newname += 2;
+ }
+
+ lck->servicepath = talloc_strdup(lck, servicepath);
+ lck->filename = talloc_strdup(lck, newname);
+ if (lck->filename == NULL || lck->servicepath == NULL) {
+ DEBUG(0, ("rename_share_filename: talloc failed\n"));
+ return False;
+ }
+ lck->modified = True;
+
+ sp_len = strlen(lck->servicepath);
+ fn_len = strlen(lck->filename);
+
+ msg_len = MSG_FILE_RENAMED_MIN_SIZE + sp_len + 1 + fn_len + 1;
+
+ /* Set up the name changed message. */
+ frm = TALLOC_ARRAY(lck, char, msg_len);
+ if (!frm) {
+ return False;
+ }
+
+ push_file_id_16(frm, &lck->id);
+
+ DEBUG(10,("rename_share_filename: msg_len = %u\n", (unsigned int)msg_len ));
+
+ safe_strcpy(&frm[16], lck->servicepath, sp_len);
+ safe_strcpy(&frm[16 + sp_len + 1], lck->filename, fn_len);
+
+ /* Send the messages. */
+ for (i=0; i<lck->num_share_modes; i++) {
+ struct share_mode_entry *se = &lck->share_modes[i];
+ if (!is_valid_share_mode_entry(se)) {
+ continue;
+ }
+ /* But not to ourselves... */
+ if (procid_is_me(&se->pid)) {
+ continue;
+ }
+
+ DEBUG(10,("rename_share_filename: sending rename message to pid %s "
+ "file_id %s sharepath %s newname %s\n",
+ procid_str_static(&se->pid),
+ file_id_string_tos(&lck->id),
+ lck->servicepath, lck->filename ));
+
+ messaging_send_buf(msg_ctx, se->pid, MSG_SMB_FILE_RENAME,
+ (uint8 *)frm, msg_len);
+ }
+
+ return True;
+}
+
+void get_file_infos(struct file_id id,
+ bool *delete_on_close,
+ struct timespec *write_time)
+{
+ struct share_mode_lock *lck;
+
+ if (delete_on_close) {
+ *delete_on_close = false;
+ }
+
+ if (write_time) {
+ ZERO_STRUCTP(write_time);
+ }
+
+ if (!(lck = fetch_share_mode_unlocked(talloc_tos(), id, NULL, NULL))) {
+ return;
+ }
+
+ if (delete_on_close) {
+ *delete_on_close = lck->delete_on_close;
+ }
+
+ if (write_time) {
+ struct timespec wt;
+
+ wt = lck->changed_write_time;
+ if (null_timespec(wt)) {
+ wt = lck->old_write_time;
+ }
+
+ *write_time = wt;
+ }
+
+ TALLOC_FREE(lck);
+}
+
+bool is_valid_share_mode_entry(const struct share_mode_entry *e)
+{
+ int num_props = 0;
+
+ if (e->op_type == UNUSED_SHARE_MODE_ENTRY) {
+ /* cope with dead entries from the process not
+ existing. These should not be considered valid,
+ otherwise we end up doing zero timeout sharing
+ violation */
+ return False;
+ }
+
+ num_props += ((e->op_type == NO_OPLOCK) ? 1 : 0);
+ num_props += (EXCLUSIVE_OPLOCK_TYPE(e->op_type) ? 1 : 0);
+ num_props += (LEVEL_II_OPLOCK_TYPE(e->op_type) ? 1 : 0);
+
+ SMB_ASSERT(num_props <= 1);
+ return (num_props != 0);
+}
+
+bool is_deferred_open_entry(const struct share_mode_entry *e)
+{
+ return (e->op_type == DEFERRED_OPEN_ENTRY);
+}
+
+bool is_unused_share_mode_entry(const struct share_mode_entry *e)
+{
+ return (e->op_type == UNUSED_SHARE_MODE_ENTRY);
+}
+
+/*******************************************************************
+ Fill a share mode entry.
+********************************************************************/
+
+static void fill_share_mode_entry(struct share_mode_entry *e,
+ files_struct *fsp,
+ uid_t uid, uint16 mid, uint16 op_type)
+{
+ ZERO_STRUCTP(e);
+ e->pid = procid_self();
+ e->share_access = fsp->share_access;
+ e->private_options = fsp->fh->private_options;
+ e->access_mask = fsp->access_mask;
+ e->op_mid = mid;
+ e->op_type = op_type;
+ e->time.tv_sec = fsp->open_time.tv_sec;
+ e->time.tv_usec = fsp->open_time.tv_usec;
+ e->id = fsp->file_id;
+ e->share_file_id = fsp->fh->gen_id;
+ e->uid = (uint32)uid;
+ e->flags = fsp->posix_open ? SHARE_MODE_FLAG_POSIX_OPEN : 0;
+}
+
+static void fill_deferred_open_entry(struct share_mode_entry *e,
+ const struct timeval request_time,
+ struct file_id id, uint16 mid)
+{
+ ZERO_STRUCTP(e);
+ e->pid = procid_self();
+ e->op_mid = mid;
+ e->op_type = DEFERRED_OPEN_ENTRY;
+ e->time.tv_sec = request_time.tv_sec;
+ e->time.tv_usec = request_time.tv_usec;
+ e->id = id;
+ e->uid = (uint32)-1;
+ e->flags = 0;
+}
+
+static void add_share_mode_entry(struct share_mode_lock *lck,
+ const struct share_mode_entry *entry)
+{
+ int i;
+
+ for (i=0; i<lck->num_share_modes; i++) {
+ struct share_mode_entry *e = &lck->share_modes[i];
+ if (is_unused_share_mode_entry(e)) {
+ *e = *entry;
+ break;
+ }
+ }
+
+ if (i == lck->num_share_modes) {
+ /* No unused entry found */
+ ADD_TO_ARRAY(lck, struct share_mode_entry, *entry,
+ &lck->share_modes, &lck->num_share_modes);
+ }
+ lck->modified = True;
+}
+
+void set_share_mode(struct share_mode_lock *lck, files_struct *fsp,
+ uid_t uid, uint16 mid, uint16 op_type, bool initial_delete_on_close_allowed)
+{
+ struct share_mode_entry entry;
+ fill_share_mode_entry(&entry, fsp, uid, mid, op_type);
+ if (initial_delete_on_close_allowed) {
+ entry.flags |= SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE;
+ }
+ add_share_mode_entry(lck, &entry);
+}
+
+void add_deferred_open(struct share_mode_lock *lck, uint16 mid,
+ struct timeval request_time,
+ struct file_id id)
+{
+ struct share_mode_entry entry;
+ fill_deferred_open_entry(&entry, request_time, id, mid);
+ add_share_mode_entry(lck, &entry);
+}
+
+/*******************************************************************
+ Check if two share mode entries are identical, ignoring oplock
+ and mid info and desired_access. (Removed paranoia test - it's
+ not automatically a logic error if they are identical. JRA.)
+********************************************************************/
+
+static bool share_modes_identical(struct share_mode_entry *e1,
+ struct share_mode_entry *e2)
+{
+ /* We used to check for e1->share_access == e2->share_access here
+ as well as the other fields but 2 different DOS or FCB opens
+ sharing the same share mode entry may validly differ in
+ fsp->share_access field. */
+
+ return (procid_equal(&e1->pid, &e2->pid) &&
+ file_id_equal(&e1->id, &e2->id) &&
+ e1->share_file_id == e2->share_file_id );
+}
+
+static bool deferred_open_identical(struct share_mode_entry *e1,
+ struct share_mode_entry *e2)
+{
+ return (procid_equal(&e1->pid, &e2->pid) &&
+ (e1->op_mid == e2->op_mid) &&
+ file_id_equal(&e1->id, &e2->id));
+}
+
+static struct share_mode_entry *find_share_mode_entry(struct share_mode_lock *lck,
+ struct share_mode_entry *entry)
+{
+ int i;
+
+ for (i=0; i<lck->num_share_modes; i++) {
+ struct share_mode_entry *e = &lck->share_modes[i];
+ if (is_valid_share_mode_entry(entry) &&
+ is_valid_share_mode_entry(e) &&
+ share_modes_identical(e, entry)) {
+ return e;
+ }
+ if (is_deferred_open_entry(entry) &&
+ is_deferred_open_entry(e) &&
+ deferred_open_identical(e, entry)) {
+ return e;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************
+ Del the share mode of a file for this process. Return the number of
+ entries left.
+********************************************************************/
+
+bool del_share_mode(struct share_mode_lock *lck, files_struct *fsp)
+{
+ struct share_mode_entry entry, *e;
+
+ /* Don't care about the pid owner being correct here - just a search. */
+ fill_share_mode_entry(&entry, fsp, (uid_t)-1, 0, NO_OPLOCK);
+
+ e = find_share_mode_entry(lck, &entry);
+ if (e == NULL) {
+ return False;
+ }
+
+ e->op_type = UNUSED_SHARE_MODE_ENTRY;
+ lck->modified = True;
+ return True;
+}
+
+void del_deferred_open_entry(struct share_mode_lock *lck, uint16 mid)
+{
+ struct share_mode_entry entry, *e;
+
+ fill_deferred_open_entry(&entry, timeval_zero(),
+ lck->id, mid);
+
+ e = find_share_mode_entry(lck, &entry);
+ if (e == NULL) {
+ return;
+ }
+
+ e->op_type = UNUSED_SHARE_MODE_ENTRY;
+ lck->modified = True;
+}
+
+/*******************************************************************
+ Remove an oplock mid and mode entry from a share mode.
+********************************************************************/
+
+bool remove_share_oplock(struct share_mode_lock *lck, files_struct *fsp)
+{
+ struct share_mode_entry entry, *e;
+
+ /* Don't care about the pid owner being correct here - just a search. */
+ fill_share_mode_entry(&entry, fsp, (uid_t)-1, 0, NO_OPLOCK);
+
+ e = find_share_mode_entry(lck, &entry);
+ if (e == NULL) {
+ return False;
+ }
+
+ e->op_mid = 0;
+ e->op_type = NO_OPLOCK;
+ lck->modified = True;
+ return True;
+}
+
+/*******************************************************************
+ Downgrade a oplock type from exclusive to level II.
+********************************************************************/
+
+bool downgrade_share_oplock(struct share_mode_lock *lck, files_struct *fsp)
+{
+ struct share_mode_entry entry, *e;
+
+ /* Don't care about the pid owner being correct here - just a search. */
+ fill_share_mode_entry(&entry, fsp, (uid_t)-1, 0, NO_OPLOCK);
+
+ e = find_share_mode_entry(lck, &entry);
+ if (e == NULL) {
+ return False;
+ }
+
+ e->op_type = LEVEL_II_OPLOCK;
+ lck->modified = True;
+ return True;
+}
+
+/****************************************************************************
+ Deal with the internal needs of setting the delete on close flag. Note that
+ as the tdb locking is recursive, it is safe to call this from within
+ open_file_ntcreate. JRA.
+****************************************************************************/
+
+NTSTATUS can_set_delete_on_close(files_struct *fsp, bool delete_on_close,
+ uint32 dosmode)
+{
+ if (!delete_on_close) {
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * Only allow delete on close for writable files.
+ */
+
+ if ((dosmode & aRONLY) &&
+ !lp_delete_readonly(SNUM(fsp->conn))) {
+ DEBUG(10,("can_set_delete_on_close: file %s delete on close "
+ "flag set but file attribute is readonly.\n",
+ fsp->fsp_name ));
+ return NT_STATUS_CANNOT_DELETE;
+ }
+
+ /*
+ * Only allow delete on close for writable shares.
+ */
+
+ if (!CAN_WRITE(fsp->conn)) {
+ DEBUG(10,("can_set_delete_on_close: file %s delete on "
+ "close flag set but write access denied on share.\n",
+ fsp->fsp_name ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /*
+ * Only allow delete on close for files/directories opened with delete
+ * intent.
+ */
+
+ if (!(fsp->access_mask & DELETE_ACCESS)) {
+ DEBUG(10,("can_set_delete_on_close: file %s delete on "
+ "close flag set but delete access denied.\n",
+ fsp->fsp_name ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* Don't allow delete on close for non-empty directories. */
+ if (fsp->is_directory) {
+ return can_delete_directory(fsp->conn, fsp->fsp_name);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Do we have an open file handle that created this entry ?
+****************************************************************************/
+
+bool can_set_initial_delete_on_close(const struct share_mode_lock *lck)
+{
+ int i;
+
+ for (i=0; i<lck->num_share_modes; i++) {
+ if (lck->share_modes[i].flags & SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE) {
+ return True;
+ }
+ }
+ return False;
+}
+
+/*************************************************************************
+ Return a talloced copy of a UNIX_USER_TOKEN. NULL on fail.
+ (Should this be in locking.c.... ?).
+*************************************************************************/
+
+static UNIX_USER_TOKEN *copy_unix_token(TALLOC_CTX *ctx, UNIX_USER_TOKEN *tok)
+{
+ UNIX_USER_TOKEN *cpy;
+
+ if (tok == NULL) {
+ return NULL;
+ }
+
+ cpy = TALLOC_P(ctx, UNIX_USER_TOKEN);
+ if (!cpy) {
+ return NULL;
+ }
+
+ cpy->uid = tok->uid;
+ cpy->gid = tok->gid;
+ cpy->ngroups = tok->ngroups;
+ if (tok->ngroups) {
+ /* Make this a talloc child of cpy. */
+ cpy->groups = TALLOC_ARRAY(cpy, gid_t, tok->ngroups);
+ if (!cpy->groups) {
+ return NULL;
+ }
+ memcpy(cpy->groups, tok->groups, tok->ngroups * sizeof(gid_t));
+ }
+ return cpy;
+}
+
+/****************************************************************************
+ Replace the delete on close token.
+****************************************************************************/
+
+void set_delete_on_close_token(struct share_mode_lock *lck, UNIX_USER_TOKEN *tok)
+{
+ TALLOC_FREE(lck->delete_token); /* Also deletes groups... */
+
+ /* Copy the new token (can be NULL). */
+ lck->delete_token = copy_unix_token(lck, tok);
+ lck->modified = True;
+}
+
+/****************************************************************************
+ Sets the delete on close flag over all share modes on this file.
+ Modify the share mode entry for all files open
+ on this device and inode to tell other smbds we have
+ changed the delete on close flag. This will be noticed
+ in the close code, the last closer will delete the file
+ if flag is set.
+ This makes a copy of any UNIX_USER_TOKEN into the
+ lck entry. This function is used when the lock is already granted.
+****************************************************************************/
+
+void set_delete_on_close_lck(struct share_mode_lock *lck, bool delete_on_close, UNIX_USER_TOKEN *tok)
+{
+ if (lck->delete_on_close != delete_on_close) {
+ set_delete_on_close_token(lck, tok);
+ lck->delete_on_close = delete_on_close;
+ if (delete_on_close) {
+ SMB_ASSERT(lck->delete_token != NULL);
+ }
+ lck->modified = True;
+ }
+}
+
+bool set_delete_on_close(files_struct *fsp, bool delete_on_close, UNIX_USER_TOKEN *tok)
+{
+ struct share_mode_lock *lck;
+
+ DEBUG(10,("set_delete_on_close: %s delete on close flag for "
+ "fnum = %d, file %s\n",
+ delete_on_close ? "Adding" : "Removing", fsp->fnum,
+ fsp->fsp_name ));
+
+ lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
+ NULL);
+ if (lck == NULL) {
+ return False;
+ }
+
+ set_delete_on_close_lck(lck, delete_on_close, tok);
+
+ if (fsp->is_directory) {
+ send_stat_cache_delete_message(fsp->fsp_name);
+ }
+
+ TALLOC_FREE(lck);
+ return True;
+}
+
+/****************************************************************************
+ Sets the allow initial delete on close flag for this share mode.
+****************************************************************************/
+
+bool set_allow_initial_delete_on_close(struct share_mode_lock *lck, files_struct *fsp, bool delete_on_close)
+{
+ struct share_mode_entry entry, *e;
+
+ /* Don't care about the pid owner being correct here - just a search. */
+ fill_share_mode_entry(&entry, fsp, (uid_t)-1, 0, NO_OPLOCK);
+
+ e = find_share_mode_entry(lck, &entry);
+ if (e == NULL) {
+ return False;
+ }
+
+ if (delete_on_close) {
+ e->flags |= SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE;
+ } else {
+ e->flags &= ~SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE;
+ }
+ lck->modified = True;
+ return True;
+}
+
+bool set_sticky_write_time(struct file_id fileid, struct timespec write_time)
+{
+ struct share_mode_lock *lck;
+
+ DEBUG(5,("set_sticky_write_time: %s id=%s\n",
+ timestring(debug_ctx(),
+ convert_timespec_to_time_t(write_time)),
+ file_id_string_tos(&fileid)));
+
+ lck = get_share_mode_lock(NULL, fileid, NULL, NULL, NULL);
+ if (lck == NULL) {
+ return False;
+ }
+
+ if (timespec_compare(&lck->changed_write_time, &write_time) != 0) {
+ lck->modified = True;
+ lck->changed_write_time = write_time;
+ }
+
+ TALLOC_FREE(lck);
+ return True;
+}
+
+bool set_write_time(struct file_id fileid, struct timespec write_time)
+{
+ struct share_mode_lock *lck;
+
+ DEBUG(5,("set_write_time: %s id=%s\n",
+ timestring(debug_ctx(),
+ convert_timespec_to_time_t(write_time)),
+ file_id_string_tos(&fileid)));
+
+ lck = get_share_mode_lock(NULL, fileid, NULL, NULL, NULL);
+ if (lck == NULL) {
+ return False;
+ }
+
+ if (timespec_compare(&lck->old_write_time, &write_time) != 0) {
+ lck->modified = True;
+ lck->old_write_time = write_time;
+ }
+
+ TALLOC_FREE(lck);
+ return True;
+}
+
+
+struct forall_state {
+ void (*fn)(const struct share_mode_entry *entry,
+ const char *sharepath,
+ const char *fname,
+ void *private_data);
+ void *private_data;
+};
+
+static int traverse_fn(struct db_record *rec, void *_state)
+{
+ struct forall_state *state = (struct forall_state *)_state;
+ struct locking_data *data;
+ struct share_mode_entry *shares;
+ const char *sharepath;
+ const char *fname;
+ int i;
+
+ /* Ensure this is a locking_key record. */
+ if (rec->key.dsize != sizeof(struct file_id))
+ return 0;
+
+ data = (struct locking_data *)rec->value.dptr;
+ shares = (struct share_mode_entry *)(rec->value.dptr + sizeof(*data));
+ sharepath = (const char *)rec->value.dptr + sizeof(*data) +
+ data->u.s.num_share_mode_entries*sizeof(*shares) +
+ data->u.s.delete_token_size;
+ fname = (const char *)rec->value.dptr + sizeof(*data) +
+ data->u.s.num_share_mode_entries*sizeof(*shares) +
+ data->u.s.delete_token_size +
+ strlen(sharepath) + 1;
+
+ for (i=0;i<data->u.s.num_share_mode_entries;i++) {
+ state->fn(&shares[i], sharepath, fname,
+ state->private_data);
+ }
+ return 0;
+}
+
+/*******************************************************************
+ Call the specified function on each entry under management by the
+ share mode system.
+********************************************************************/
+
+int share_mode_forall(void (*fn)(const struct share_mode_entry *, const char *,
+ const char *, void *),
+ void *private_data)
+{
+ struct forall_state state;
+
+ if (lock_db == NULL)
+ return 0;
+
+ state.fn = fn;
+ state.private_data = private_data;
+
+ return lock_db->traverse_read(lock_db, traverse_fn, (void *)&state);
+}
diff --git a/source3/locking/posix.c b/source3/locking/posix.c
new file mode 100644
index 0000000000..32e1ee9fbf
--- /dev/null
+++ b/source3/locking/posix.c
@@ -0,0 +1,1309 @@
+/*
+ Unix SMB/CIFS implementation.
+ Locking functions
+ Copyright (C) Jeremy Allison 1992-2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Revision History:
+
+ POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_LOCKING
+
+/*
+ * The pending close database handle.
+ */
+
+static struct db_context *posix_pending_close_db;
+
+/****************************************************************************
+ First - the functions that deal with the underlying system locks - these
+ functions are used no matter if we're mapping CIFS Windows locks or CIFS
+ POSIX locks onto POSIX.
+****************************************************************************/
+
+/****************************************************************************
+ Utility function to map a lock type correctly depending on the open
+ mode of a file.
+****************************************************************************/
+
+static int map_posix_lock_type( files_struct *fsp, enum brl_type lock_type)
+{
+ if((lock_type == WRITE_LOCK) && !fsp->can_write) {
+ /*
+ * Many UNIX's cannot get a write lock on a file opened read-only.
+ * Win32 locking semantics allow this.
+ * Do the best we can and attempt a read-only lock.
+ */
+ DEBUG(10,("map_posix_lock_type: Downgrading write lock to read due to read-only file.\n"));
+ return F_RDLCK;
+ }
+
+ /*
+ * This return should be the most normal, as we attempt
+ * to always open files read/write.
+ */
+
+ return (lock_type == READ_LOCK) ? F_RDLCK : F_WRLCK;
+}
+
+/****************************************************************************
+ Debugging aid :-).
+****************************************************************************/
+
+static const char *posix_lock_type_name(int lock_type)
+{
+ return (lock_type == F_RDLCK) ? "READ" : "WRITE";
+}
+
+/****************************************************************************
+ Check to see if the given unsigned lock range is within the possible POSIX
+ range. Modifies the given args to be in range if possible, just returns
+ False if not.
+****************************************************************************/
+
+static bool posix_lock_in_range(SMB_OFF_T *offset_out, SMB_OFF_T *count_out,
+ SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count)
+{
+ SMB_OFF_T offset = (SMB_OFF_T)u_offset;
+ SMB_OFF_T count = (SMB_OFF_T)u_count;
+
+ /*
+ * For the type of system we are, attempt to
+ * find the maximum positive lock offset as an SMB_OFF_T.
+ */
+
+#if defined(MAX_POSITIVE_LOCK_OFFSET) /* Some systems have arbitrary limits. */
+
+ SMB_OFF_T max_positive_lock_offset = (MAX_POSITIVE_LOCK_OFFSET);
+
+#elif defined(LARGE_SMB_OFF_T) && !defined(HAVE_BROKEN_FCNTL64_LOCKS)
+
+ /*
+ * In this case SMB_OFF_T is 64 bits,
+ * and the underlying system can handle 64 bit signed locks.
+ */
+
+ SMB_OFF_T mask2 = ((SMB_OFF_T)0x4) << (SMB_OFF_T_BITS-4);
+ SMB_OFF_T mask = (mask2<<1);
+ SMB_OFF_T max_positive_lock_offset = ~mask;
+
+#else /* !LARGE_SMB_OFF_T || HAVE_BROKEN_FCNTL64_LOCKS */
+
+ /*
+ * In this case either SMB_OFF_T is 32 bits,
+ * or the underlying system cannot handle 64 bit signed locks.
+ * All offsets & counts must be 2^31 or less.
+ */
+
+ SMB_OFF_T max_positive_lock_offset = 0x7FFFFFFF;
+
+#endif /* !LARGE_SMB_OFF_T || HAVE_BROKEN_FCNTL64_LOCKS */
+
+ /*
+ * POSIX locks of length zero mean lock to end-of-file.
+ * Win32 locks of length zero are point probes. Ignore
+ * any Win32 locks of length zero. JRA.
+ */
+
+ if (count == (SMB_OFF_T)0) {
+ DEBUG(10,("posix_lock_in_range: count = 0, ignoring.\n"));
+ return False;
+ }
+
+ /*
+ * If the given offset was > max_positive_lock_offset then we cannot map this at all
+ * ignore this lock.
+ */
+
+ if (u_offset & ~((SMB_BIG_UINT)max_positive_lock_offset)) {
+ DEBUG(10,("posix_lock_in_range: (offset = %.0f) offset > %.0f and we cannot handle this. Ignoring lock.\n",
+ (double)u_offset, (double)((SMB_BIG_UINT)max_positive_lock_offset) ));
+ return False;
+ }
+
+ /*
+ * We must truncate the count to less than max_positive_lock_offset.
+ */
+
+ if (u_count & ~((SMB_BIG_UINT)max_positive_lock_offset)) {
+ count = max_positive_lock_offset;
+ }
+
+ /*
+ * Truncate count to end at max lock offset.
+ */
+
+ if (offset + count < 0 || offset + count > max_positive_lock_offset) {
+ count = max_positive_lock_offset - offset;
+ }
+
+ /*
+ * If we ate all the count, ignore this lock.
+ */
+
+ if (count == 0) {
+ DEBUG(10,("posix_lock_in_range: Count = 0. Ignoring lock u_offset = %.0f, u_count = %.0f\n",
+ (double)u_offset, (double)u_count ));
+ return False;
+ }
+
+ /*
+ * The mapping was successful.
+ */
+
+ DEBUG(10,("posix_lock_in_range: offset_out = %.0f, count_out = %.0f\n",
+ (double)offset, (double)count ));
+
+ *offset_out = offset;
+ *count_out = count;
+
+ return True;
+}
+
+/****************************************************************************
+ Actual function that does POSIX locks. Copes with 64 -> 32 bit cruft and
+ broken NFS implementations.
+****************************************************************************/
+
+static bool posix_fcntl_lock(files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
+{
+ bool ret;
+
+ DEBUG(8,("posix_fcntl_lock %d %d %.0f %.0f %d\n",fsp->fh->fd,op,(double)offset,(double)count,type));
+
+ ret = SMB_VFS_LOCK(fsp, op, offset, count, type);
+
+ if (!ret && ((errno == EFBIG) || (errno == ENOLCK) || (errno == EINVAL))) {
+
+ DEBUG(0,("posix_fcntl_lock: WARNING: lock request at offset %.0f, length %.0f returned\n",
+ (double)offset,(double)count));
+ DEBUGADD(0,("an %s error. This can happen when using 64 bit lock offsets\n", strerror(errno)));
+ DEBUGADD(0,("on 32 bit NFS mounted file systems.\n"));
+
+ /*
+ * If the offset is > 0x7FFFFFFF then this will cause problems on
+ * 32 bit NFS mounted filesystems. Just ignore it.
+ */
+
+ if (offset & ~((SMB_OFF_T)0x7fffffff)) {
+ DEBUG(0,("Offset greater than 31 bits. Returning success.\n"));
+ return True;
+ }
+
+ if (count & ~((SMB_OFF_T)0x7fffffff)) {
+ /* 32 bit NFS file system, retry with smaller offset */
+ DEBUG(0,("Count greater than 31 bits - retrying with 31 bit truncated length.\n"));
+ errno = 0;
+ count &= 0x7fffffff;
+ ret = SMB_VFS_LOCK(fsp, op, offset, count, type);
+ }
+ }
+
+ DEBUG(8,("posix_fcntl_lock: Lock call %s\n", ret ? "successful" : "failed"));
+ return ret;
+}
+
+/****************************************************************************
+ Actual function that gets POSIX locks. Copes with 64 -> 32 bit cruft and
+ broken NFS implementations.
+****************************************************************************/
+
+static bool posix_fcntl_getlock(files_struct *fsp, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype)
+{
+ pid_t pid;
+ bool ret;
+
+ DEBUG(8,("posix_fcntl_getlock %d %.0f %.0f %d\n",
+ fsp->fh->fd,(double)*poffset,(double)*pcount,*ptype));
+
+ ret = SMB_VFS_GETLOCK(fsp, poffset, pcount, ptype, &pid);
+
+ if (!ret && ((errno == EFBIG) || (errno == ENOLCK) || (errno == EINVAL))) {
+
+ DEBUG(0,("posix_fcntl_getlock: WARNING: lock request at offset %.0f, length %.0f returned\n",
+ (double)*poffset,(double)*pcount));
+ DEBUGADD(0,("an %s error. This can happen when using 64 bit lock offsets\n", strerror(errno)));
+ DEBUGADD(0,("on 32 bit NFS mounted file systems.\n"));
+
+ /*
+ * If the offset is > 0x7FFFFFFF then this will cause problems on
+ * 32 bit NFS mounted filesystems. Just ignore it.
+ */
+
+ if (*poffset & ~((SMB_OFF_T)0x7fffffff)) {
+ DEBUG(0,("Offset greater than 31 bits. Returning success.\n"));
+ return True;
+ }
+
+ if (*pcount & ~((SMB_OFF_T)0x7fffffff)) {
+ /* 32 bit NFS file system, retry with smaller offset */
+ DEBUG(0,("Count greater than 31 bits - retrying with 31 bit truncated length.\n"));
+ errno = 0;
+ *pcount &= 0x7fffffff;
+ ret = SMB_VFS_GETLOCK(fsp,poffset,pcount,ptype,&pid);
+ }
+ }
+
+ DEBUG(8,("posix_fcntl_getlock: Lock query call %s\n", ret ? "successful" : "failed"));
+ return ret;
+}
+
+/****************************************************************************
+ POSIX function to see if a file region is locked. Returns True if the
+ region is locked, False otherwise.
+****************************************************************************/
+
+bool is_posix_locked(files_struct *fsp,
+ SMB_BIG_UINT *pu_offset,
+ SMB_BIG_UINT *pu_count,
+ enum brl_type *plock_type,
+ enum brl_flavour lock_flav)
+{
+ SMB_OFF_T offset;
+ SMB_OFF_T count;
+ int posix_lock_type = map_posix_lock_type(fsp,*plock_type);
+
+ DEBUG(10,("is_posix_locked: File %s, offset = %.0f, count = %.0f, type = %s\n",
+ fsp->fsp_name, (double)*pu_offset, (double)*pu_count, posix_lock_type_name(*plock_type) ));
+
+ /*
+ * If the requested lock won't fit in the POSIX range, we will
+ * never set it, so presume it is not locked.
+ */
+
+ if(!posix_lock_in_range(&offset, &count, *pu_offset, *pu_count)) {
+ return False;
+ }
+
+ if (!posix_fcntl_getlock(fsp,&offset,&count,&posix_lock_type)) {
+ return False;
+ }
+
+ if (posix_lock_type == F_UNLCK) {
+ return False;
+ }
+
+ if (lock_flav == POSIX_LOCK) {
+ /* Only POSIX lock queries need to know the details. */
+ *pu_offset = (SMB_BIG_UINT)offset;
+ *pu_count = (SMB_BIG_UINT)count;
+ *plock_type = (posix_lock_type == F_RDLCK) ? READ_LOCK : WRITE_LOCK;
+ }
+ return True;
+}
+
+/****************************************************************************
+ Next - the functions that deal with in memory database storing representations
+ of either Windows CIFS locks or POSIX CIFS locks.
+****************************************************************************/
+
+/* The key used in the in-memory POSIX databases. */
+
+struct lock_ref_count_key {
+ struct file_id id;
+ char r;
+};
+
+/*******************************************************************
+ Form a static locking key for a dev/inode pair for the lock ref count
+******************************************************************/
+
+static TDB_DATA locking_ref_count_key_fsp(files_struct *fsp,
+ struct lock_ref_count_key *tmp)
+{
+ ZERO_STRUCTP(tmp);
+ tmp->id = fsp->file_id;
+ tmp->r = 'r';
+ return make_tdb_data((uint8_t *)tmp, sizeof(*tmp));
+}
+
+/*******************************************************************
+ Convenience function to get an fd_array key from an fsp.
+******************************************************************/
+
+static TDB_DATA fd_array_key_fsp(files_struct *fsp)
+{
+ return make_tdb_data((uint8 *)&fsp->file_id, sizeof(fsp->file_id));
+}
+
+/*******************************************************************
+ Create the in-memory POSIX lock databases.
+********************************************************************/
+
+bool posix_locking_init(bool read_only)
+{
+ if (posix_pending_close_db != NULL) {
+ return true;
+ }
+
+ posix_pending_close_db = db_open_rbt(NULL);
+
+ if (posix_pending_close_db == NULL) {
+ DEBUG(0,("Failed to open POSIX pending close database.\n"));
+ return false;
+ }
+
+ return true;
+}
+
+/*******************************************************************
+ Delete the in-memory POSIX lock databases.
+********************************************************************/
+
+bool posix_locking_end(void)
+{
+ /*
+ * Shouldn't we close all fd's here?
+ */
+ TALLOC_FREE(posix_pending_close_db);
+ return true;
+}
+
+/****************************************************************************
+ Next - the functions that deal with storing fd's that have outstanding
+ POSIX locks when closed.
+****************************************************************************/
+
+/****************************************************************************
+ The records in posix_pending_close_tdb are composed of an array of ints
+ keyed by dev/ino pair.
+ The first int is a reference count of the number of outstanding locks on
+ all open fd's on this dev/ino pair. Any subsequent ints are the fd's that
+ were open on this dev/ino pair that should have been closed, but can't as
+ the lock ref count is non zero.
+****************************************************************************/
+
+/****************************************************************************
+ Keep a reference count of the number of Windows locks open on this dev/ino
+ pair. Creates entry if it doesn't exist.
+****************************************************************************/
+
+static void increment_windows_lock_ref_count(files_struct *fsp)
+{
+ struct lock_ref_count_key tmp;
+ struct db_record *rec;
+ int lock_ref_count = 0;
+ NTSTATUS status;
+
+ rec = posix_pending_close_db->fetch_locked(
+ posix_pending_close_db, talloc_tos(),
+ locking_ref_count_key_fsp(fsp, &tmp));
+
+ SMB_ASSERT(rec != NULL);
+
+ if (rec->value.dptr != NULL) {
+ SMB_ASSERT(rec->value.dsize == sizeof(lock_ref_count));
+ memcpy(&lock_ref_count, rec->value.dptr,
+ sizeof(lock_ref_count));
+ }
+
+ lock_ref_count++;
+
+ status = rec->store(rec, make_tdb_data((uint8 *)&lock_ref_count,
+ sizeof(lock_ref_count)), 0);
+
+ SMB_ASSERT(NT_STATUS_IS_OK(status));
+
+ TALLOC_FREE(rec);
+
+ DEBUG(10,("increment_windows_lock_ref_count for file now %s = %d\n",
+ fsp->fsp_name, lock_ref_count ));
+}
+
+/****************************************************************************
+ Bulk delete - subtract as many locks as we've just deleted.
+****************************************************************************/
+
+void reduce_windows_lock_ref_count(files_struct *fsp, unsigned int dcount)
+{
+ struct lock_ref_count_key tmp;
+ struct db_record *rec;
+ int lock_ref_count = 0;
+ NTSTATUS status;
+
+ rec = posix_pending_close_db->fetch_locked(
+ posix_pending_close_db, talloc_tos(),
+ locking_ref_count_key_fsp(fsp, &tmp));
+
+ SMB_ASSERT((rec != NULL)
+ && (rec->value.dptr != NULL)
+ && (rec->value.dsize == sizeof(lock_ref_count)));
+
+ memcpy(&lock_ref_count, rec->value.dptr, sizeof(lock_ref_count));
+
+ SMB_ASSERT(lock_ref_count > 0);
+
+ lock_ref_count -= dcount;
+
+ status = rec->store(rec, make_tdb_data((uint8 *)&lock_ref_count,
+ sizeof(lock_ref_count)), 0);
+
+ SMB_ASSERT(NT_STATUS_IS_OK(status));
+
+ TALLOC_FREE(rec);
+
+ DEBUG(10,("reduce_windows_lock_ref_count for file now %s = %d\n",
+ fsp->fsp_name, lock_ref_count ));
+}
+
+static void decrement_windows_lock_ref_count(files_struct *fsp)
+{
+ reduce_windows_lock_ref_count(fsp, 1);
+}
+
+/****************************************************************************
+ Fetch the lock ref count.
+****************************************************************************/
+
+static int get_windows_lock_ref_count(files_struct *fsp)
+{
+ struct lock_ref_count_key tmp;
+ TDB_DATA dbuf;
+ int res;
+ int lock_ref_count = 0;
+
+ res = posix_pending_close_db->fetch(
+ posix_pending_close_db, talloc_tos(),
+ locking_ref_count_key_fsp(fsp, &tmp), &dbuf);
+
+ SMB_ASSERT(res == 0);
+
+ if (dbuf.dsize != 0) {
+ SMB_ASSERT(dbuf.dsize == sizeof(lock_ref_count));
+ memcpy(&lock_ref_count, dbuf.dptr, sizeof(lock_ref_count));
+ TALLOC_FREE(dbuf.dptr);
+ }
+
+ DEBUG(10,("get_windows_lock_count for file %s = %d\n",
+ fsp->fsp_name, lock_ref_count ));
+
+ return lock_ref_count;
+}
+
+/****************************************************************************
+ Delete a lock_ref_count entry.
+****************************************************************************/
+
+static void delete_windows_lock_ref_count(files_struct *fsp)
+{
+ struct lock_ref_count_key tmp;
+ struct db_record *rec;
+
+ rec = posix_pending_close_db->fetch_locked(
+ posix_pending_close_db, talloc_tos(),
+ locking_ref_count_key_fsp(fsp, &tmp));
+
+ SMB_ASSERT(rec != NULL);
+
+ /* Not a bug if it doesn't exist - no locks were ever granted. */
+
+ rec->delete_rec(rec);
+ TALLOC_FREE(rec);
+
+ DEBUG(10,("delete_windows_lock_ref_count for file %s\n",
+ fsp->fsp_name));
+}
+
+/****************************************************************************
+ Add an fd to the pending close tdb.
+****************************************************************************/
+
+static void add_fd_to_close_entry(files_struct *fsp)
+{
+ struct db_record *rec;
+ uint8_t *new_data;
+ NTSTATUS status;
+
+ rec = posix_pending_close_db->fetch_locked(
+ posix_pending_close_db, talloc_tos(),
+ fd_array_key_fsp(fsp));
+
+ SMB_ASSERT(rec != NULL);
+
+ new_data = TALLOC_ARRAY(
+ rec, uint8_t, rec->value.dsize + sizeof(fsp->fh->fd));
+
+ SMB_ASSERT(new_data != NULL);
+
+ memcpy(new_data, rec->value.dptr, rec->value.dsize);
+ memcpy(new_data + rec->value.dsize,
+ &fsp->fh->fd, sizeof(fsp->fh->fd));
+
+ status = rec->store(
+ rec, make_tdb_data(new_data,
+ rec->value.dsize + sizeof(fsp->fh->fd)), 0);
+
+ SMB_ASSERT(NT_STATUS_IS_OK(status));
+
+ TALLOC_FREE(rec);
+
+ DEBUG(10,("add_fd_to_close_entry: added fd %d file %s\n",
+ fsp->fh->fd, fsp->fsp_name ));
+}
+
+/****************************************************************************
+ Remove all fd entries for a specific dev/inode pair from the tdb.
+****************************************************************************/
+
+static void delete_close_entries(files_struct *fsp)
+{
+ struct db_record *rec;
+
+ rec = posix_pending_close_db->fetch_locked(
+ posix_pending_close_db, talloc_tos(),
+ fd_array_key_fsp(fsp));
+
+ SMB_ASSERT(rec != NULL);
+ rec->delete_rec(rec);
+ TALLOC_FREE(rec);
+}
+
+/****************************************************************************
+ Get the array of POSIX pending close records for an open fsp. Returns number
+ of entries.
+****************************************************************************/
+
+static size_t get_posix_pending_close_entries(TALLOC_CTX *mem_ctx,
+ files_struct *fsp, int **entries)
+{
+ TDB_DATA dbuf;
+ int res;
+
+ res = posix_pending_close_db->fetch(
+ posix_pending_close_db, mem_ctx, fd_array_key_fsp(fsp),
+ &dbuf);
+
+ SMB_ASSERT(res == 0);
+
+ if (dbuf.dsize == 0) {
+ *entries = NULL;
+ return 0;
+ }
+
+ *entries = (int *)dbuf.dptr;
+ return (size_t)(dbuf.dsize / sizeof(int));
+}
+
+/****************************************************************************
+ Deal with pending closes needed by POSIX locking support.
+ Note that posix_locking_close_file() is expected to have been called
+ to delete all locks on this fsp before this function is called.
+****************************************************************************/
+
+int fd_close_posix(struct files_struct *fsp)
+{
+ int saved_errno = 0;
+ int ret;
+ int *fd_array = NULL;
+ size_t count, i;
+
+ if (!lp_locking(fsp->conn->params) ||
+ !lp_posix_locking(fsp->conn->params))
+ {
+ /*
+ * No locking or POSIX to worry about or we want POSIX semantics
+ * which will lose all locks on all fd's open on this dev/inode,
+ * just close.
+ */
+ return close(fsp->fh->fd);
+ }
+
+ if (get_windows_lock_ref_count(fsp)) {
+
+ /*
+ * There are outstanding locks on this dev/inode pair on
+ * other fds. Add our fd to the pending close tdb and set
+ * fsp->fh->fd to -1.
+ */
+
+ add_fd_to_close_entry(fsp);
+ return 0;
+ }
+
+ /*
+ * No outstanding locks. Get the pending close fd's
+ * from the tdb and close them all.
+ */
+
+ count = get_posix_pending_close_entries(talloc_tos(), fsp, &fd_array);
+
+ if (count) {
+ DEBUG(10,("fd_close_posix: doing close on %u fd's.\n",
+ (unsigned int)count));
+
+ for(i = 0; i < count; i++) {
+ if (close(fd_array[i]) == -1) {
+ saved_errno = errno;
+ }
+ }
+
+ /*
+ * Delete all fd's stored in the tdb
+ * for this dev/inode pair.
+ */
+
+ delete_close_entries(fsp);
+ }
+
+ TALLOC_FREE(fd_array);
+
+ /* Don't need a lock ref count on this dev/ino anymore. */
+ delete_windows_lock_ref_count(fsp);
+
+ /*
+ * Finally close the fd associated with this fsp.
+ */
+
+ ret = close(fsp->fh->fd);
+
+ if (ret == 0 && saved_errno != 0) {
+ errno = saved_errno;
+ ret = -1;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Next - the functions that deal with the mapping CIFS Windows locks onto
+ the underlying system POSIX locks.
+****************************************************************************/
+
+/*
+ * Structure used when splitting a lock range
+ * into a POSIX lock range. Doubly linked list.
+ */
+
+struct lock_list {
+ struct lock_list *next;
+ struct lock_list *prev;
+ SMB_OFF_T start;
+ SMB_OFF_T size;
+};
+
+/****************************************************************************
+ Create a list of lock ranges that don't overlap a given range. Used in calculating
+ POSIX locks and unlocks. This is a difficult function that requires ASCII art to
+ understand it :-).
+****************************************************************************/
+
+static struct lock_list *posix_lock_list(TALLOC_CTX *ctx,
+ struct lock_list *lhead,
+ const struct lock_context *lock_ctx, /* Lock context lhead belongs to. */
+ files_struct *fsp,
+ const struct lock_struct *plocks,
+ int num_locks)
+{
+ int i;
+
+ /*
+ * Check the current lock list on this dev/inode pair.
+ * Quit if the list is deleted.
+ */
+
+ DEBUG(10,("posix_lock_list: curr: start=%.0f,size=%.0f\n",
+ (double)lhead->start, (double)lhead->size ));
+
+ for (i=0; i<num_locks && lhead; i++) {
+ const struct lock_struct *lock = &plocks[i];
+ struct lock_list *l_curr;
+
+ /* Ignore all but read/write locks. */
+ if (lock->lock_type != READ_LOCK && lock->lock_type != WRITE_LOCK) {
+ continue;
+ }
+
+ /* Ignore locks not owned by this process. */
+ if (!procid_equal(&lock->context.pid, &lock_ctx->pid)) {
+ continue;
+ }
+
+ /*
+ * Walk the lock list, checking for overlaps. Note that
+ * the lock list can expand within this loop if the current
+ * range being examined needs to be split.
+ */
+
+ for (l_curr = lhead; l_curr;) {
+
+ DEBUG(10,("posix_lock_list: lock: fnum=%d: start=%.0f,size=%.0f:type=%s", lock->fnum,
+ (double)lock->start, (double)lock->size, posix_lock_type_name(lock->lock_type) ));
+
+ if ( (l_curr->start >= (lock->start + lock->size)) ||
+ (lock->start >= (l_curr->start + l_curr->size))) {
+
+ /* No overlap with existing lock - leave this range alone. */
+/*********************************************
+ +---------+
+ | l_curr |
+ +---------+
+ +-------+
+ | lock |
+ +-------+
+OR....
+ +---------+
+ | l_curr |
+ +---------+
+**********************************************/
+
+ DEBUG(10,(" no overlap case.\n" ));
+
+ l_curr = l_curr->next;
+
+ } else if ( (l_curr->start >= lock->start) &&
+ (l_curr->start + l_curr->size <= lock->start + lock->size) ) {
+
+ /*
+ * This range is completely overlapped by this existing lock range
+ * and thus should have no effect. Delete it from the list.
+ */
+/*********************************************
+ +---------+
+ | l_curr |
+ +---------+
+ +---------------------------+
+ | lock |
+ +---------------------------+
+**********************************************/
+ /* Save the next pointer */
+ struct lock_list *ul_next = l_curr->next;
+
+ DEBUG(10,(" delete case.\n" ));
+
+ DLIST_REMOVE(lhead, l_curr);
+ if(lhead == NULL) {
+ break; /* No more list... */
+ }
+
+ l_curr = ul_next;
+
+ } else if ( (l_curr->start >= lock->start) &&
+ (l_curr->start < lock->start + lock->size) &&
+ (l_curr->start + l_curr->size > lock->start + lock->size) ) {
+
+ /*
+ * This range overlaps the existing lock range at the high end.
+ * Truncate by moving start to existing range end and reducing size.
+ */
+/*********************************************
+ +---------------+
+ | l_curr |
+ +---------------+
+ +---------------+
+ | lock |
+ +---------------+
+BECOMES....
+ +-------+
+ | l_curr|
+ +-------+
+**********************************************/
+
+ l_curr->size = (l_curr->start + l_curr->size) - (lock->start + lock->size);
+ l_curr->start = lock->start + lock->size;
+
+ DEBUG(10,(" truncate high case: start=%.0f,size=%.0f\n",
+ (double)l_curr->start, (double)l_curr->size ));
+
+ l_curr = l_curr->next;
+
+ } else if ( (l_curr->start < lock->start) &&
+ (l_curr->start + l_curr->size > lock->start) &&
+ (l_curr->start + l_curr->size <= lock->start + lock->size) ) {
+
+ /*
+ * This range overlaps the existing lock range at the low end.
+ * Truncate by reducing size.
+ */
+/*********************************************
+ +---------------+
+ | l_curr |
+ +---------------+
+ +---------------+
+ | lock |
+ +---------------+
+BECOMES....
+ +-------+
+ | l_curr|
+ +-------+
+**********************************************/
+
+ l_curr->size = lock->start - l_curr->start;
+
+ DEBUG(10,(" truncate low case: start=%.0f,size=%.0f\n",
+ (double)l_curr->start, (double)l_curr->size ));
+
+ l_curr = l_curr->next;
+
+ } else if ( (l_curr->start < lock->start) &&
+ (l_curr->start + l_curr->size > lock->start + lock->size) ) {
+ /*
+ * Worst case scenario. Range completely overlaps an existing
+ * lock range. Split the request into two, push the new (upper) request
+ * into the dlink list, and continue with the entry after l_new (as we
+ * know that l_new will not overlap with this lock).
+ */
+/*********************************************
+ +---------------------------+
+ | l_curr |
+ +---------------------------+
+ +---------+
+ | lock |
+ +---------+
+BECOMES.....
+ +-------+ +---------+
+ | l_curr| | l_new |
+ +-------+ +---------+
+**********************************************/
+ struct lock_list *l_new = TALLOC_P(ctx, struct lock_list);
+
+ if(l_new == NULL) {
+ DEBUG(0,("posix_lock_list: talloc fail.\n"));
+ return NULL; /* The talloc_destroy takes care of cleanup. */
+ }
+
+ ZERO_STRUCTP(l_new);
+ l_new->start = lock->start + lock->size;
+ l_new->size = l_curr->start + l_curr->size - l_new->start;
+
+ /* Truncate the l_curr. */
+ l_curr->size = lock->start - l_curr->start;
+
+ DEBUG(10,(" split case: curr: start=%.0f,size=%.0f \
+new: start=%.0f,size=%.0f\n", (double)l_curr->start, (double)l_curr->size,
+ (double)l_new->start, (double)l_new->size ));
+
+ /*
+ * Add into the dlink list after the l_curr point - NOT at lhead.
+ * Note we can't use DLINK_ADD here as this inserts at the head of the given list.
+ */
+
+ l_new->prev = l_curr;
+ l_new->next = l_curr->next;
+ l_curr->next = l_new;
+
+ /* And move after the link we added. */
+ l_curr = l_new->next;
+
+ } else {
+
+ /*
+ * This logic case should never happen. Ensure this is the
+ * case by forcing an abort.... Remove in production.
+ */
+ char *msg = NULL;
+
+ /* Don't check if alloc succeeds here - we're
+ * forcing a core dump anyway. */
+
+ asprintf(&msg, "logic flaw in cases: l_curr: start = %.0f, size = %.0f : \
+lock: start = %.0f, size = %.0f", (double)l_curr->start, (double)l_curr->size, (double)lock->start, (double)lock->size );
+
+ smb_panic(msg);
+ }
+ } /* end for ( l_curr = lhead; l_curr;) */
+ } /* end for (i=0; i<num_locks && ul_head; i++) */
+
+ return lhead;
+}
+
+/****************************************************************************
+ POSIX function to acquire a lock. Returns True if the
+ lock could be granted, False if not.
+****************************************************************************/
+
+bool set_posix_lock_windows_flavour(files_struct *fsp,
+ SMB_BIG_UINT u_offset,
+ SMB_BIG_UINT u_count,
+ enum brl_type lock_type,
+ const struct lock_context *lock_ctx,
+ const struct lock_struct *plocks,
+ int num_locks,
+ int *errno_ret)
+{
+ SMB_OFF_T offset;
+ SMB_OFF_T count;
+ int posix_lock_type = map_posix_lock_type(fsp,lock_type);
+ bool ret = True;
+ size_t lock_count;
+ TALLOC_CTX *l_ctx = NULL;
+ struct lock_list *llist = NULL;
+ struct lock_list *ll = NULL;
+
+ DEBUG(5,("set_posix_lock_windows_flavour: File %s, offset = %.0f, count = %.0f, type = %s\n",
+ fsp->fsp_name, (double)u_offset, (double)u_count, posix_lock_type_name(lock_type) ));
+
+ /*
+ * If the requested lock won't fit in the POSIX range, we will
+ * pretend it was successful.
+ */
+
+ if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) {
+ increment_windows_lock_ref_count(fsp);
+ return True;
+ }
+
+ /*
+ * Windows is very strange. It allows read locks to be overlayed
+ * (even over a write lock), but leaves the write lock in force until the first
+ * unlock. It also reference counts the locks. This means the following sequence :
+ *
+ * process1 process2
+ * ------------------------------------------------------------------------
+ * WRITE LOCK : start = 2, len = 10
+ * READ LOCK: start =0, len = 10 - FAIL
+ * READ LOCK : start = 0, len = 14
+ * READ LOCK: start =0, len = 10 - FAIL
+ * UNLOCK : start = 2, len = 10
+ * READ LOCK: start =0, len = 10 - OK
+ *
+ * Under POSIX, the same sequence in steps 1 and 2 would not be reference counted, but
+ * would leave a single read lock over the 0-14 region.
+ */
+
+ if ((l_ctx = talloc_init("set_posix_lock")) == NULL) {
+ DEBUG(0,("set_posix_lock_windows_flavour: unable to init talloc context.\n"));
+ return False;
+ }
+
+ if ((ll = TALLOC_P(l_ctx, struct lock_list)) == NULL) {
+ DEBUG(0,("set_posix_lock_windows_flavour: unable to talloc unlock list.\n"));
+ talloc_destroy(l_ctx);
+ return False;
+ }
+
+ /*
+ * Create the initial list entry containing the
+ * lock we want to add.
+ */
+
+ ZERO_STRUCTP(ll);
+ ll->start = offset;
+ ll->size = count;
+
+ DLIST_ADD(llist, ll);
+
+ /*
+ * The following call calculates if there are any
+ * overlapping locks held by this process on
+ * fd's open on the same file and splits this list
+ * into a list of lock ranges that do not overlap with existing
+ * POSIX locks.
+ */
+
+ llist = posix_lock_list(l_ctx,
+ llist,
+ lock_ctx, /* Lock context llist belongs to. */
+ fsp,
+ plocks,
+ num_locks);
+
+ /*
+ * Add the POSIX locks on the list of ranges returned.
+ * As the lock is supposed to be added atomically, we need to
+ * back out all the locks if any one of these calls fail.
+ */
+
+ for (lock_count = 0, ll = llist; ll; ll = ll->next, lock_count++) {
+ offset = ll->start;
+ count = ll->size;
+
+ DEBUG(5,("set_posix_lock_windows_flavour: Real lock: Type = %s: offset = %.0f, count = %.0f\n",
+ posix_lock_type_name(posix_lock_type), (double)offset, (double)count ));
+
+ if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,posix_lock_type)) {
+ *errno_ret = errno;
+ DEBUG(5,("set_posix_lock_windows_flavour: Lock fail !: Type = %s: offset = %.0f, count = %.0f. Errno = %s\n",
+ posix_lock_type_name(posix_lock_type), (double)offset, (double)count, strerror(errno) ));
+ ret = False;
+ break;
+ }
+ }
+
+ if (!ret) {
+
+ /*
+ * Back out all the POSIX locks we have on fail.
+ */
+
+ for (ll = llist; lock_count; ll = ll->next, lock_count--) {
+ offset = ll->start;
+ count = ll->size;
+
+ DEBUG(5,("set_posix_lock_windows_flavour: Backing out locks: Type = %s: offset = %.0f, count = %.0f\n",
+ posix_lock_type_name(posix_lock_type), (double)offset, (double)count ));
+
+ posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK);
+ }
+ } else {
+ /* Remember the number of Windows locks we have on this dev/ino pair. */
+ increment_windows_lock_ref_count(fsp);
+ }
+
+ talloc_destroy(l_ctx);
+ return ret;
+}
+
+/****************************************************************************
+ POSIX function to release a lock. Returns True if the
+ lock could be released, False if not.
+****************************************************************************/
+
+bool release_posix_lock_windows_flavour(files_struct *fsp,
+ SMB_BIG_UINT u_offset,
+ SMB_BIG_UINT u_count,
+ enum brl_type deleted_lock_type,
+ const struct lock_context *lock_ctx,
+ const struct lock_struct *plocks,
+ int num_locks)
+{
+ SMB_OFF_T offset;
+ SMB_OFF_T count;
+ bool ret = True;
+ TALLOC_CTX *ul_ctx = NULL;
+ struct lock_list *ulist = NULL;
+ struct lock_list *ul = NULL;
+
+ DEBUG(5,("release_posix_lock_windows_flavour: File %s, offset = %.0f, count = %.0f\n",
+ fsp->fsp_name, (double)u_offset, (double)u_count ));
+
+ /* Remember the number of Windows locks we have on this dev/ino pair. */
+ decrement_windows_lock_ref_count(fsp);
+
+ /*
+ * If the requested lock won't fit in the POSIX range, we will
+ * pretend it was successful.
+ */
+
+ if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) {
+ return True;
+ }
+
+ if ((ul_ctx = talloc_init("release_posix_lock")) == NULL) {
+ DEBUG(0,("release_posix_lock_windows_flavour: unable to init talloc context.\n"));
+ return False;
+ }
+
+ if ((ul = TALLOC_P(ul_ctx, struct lock_list)) == NULL) {
+ DEBUG(0,("release_posix_lock_windows_flavour: unable to talloc unlock list.\n"));
+ talloc_destroy(ul_ctx);
+ return False;
+ }
+
+ /*
+ * Create the initial list entry containing the
+ * lock we want to remove.
+ */
+
+ ZERO_STRUCTP(ul);
+ ul->start = offset;
+ ul->size = count;
+
+ DLIST_ADD(ulist, ul);
+
+ /*
+ * The following call calculates if there are any
+ * overlapping locks held by this process on
+ * fd's open on the same file and creates a
+ * list of unlock ranges that will allow
+ * POSIX lock ranges to remain on the file whilst the
+ * unlocks are performed.
+ */
+
+ ulist = posix_lock_list(ul_ctx,
+ ulist,
+ lock_ctx, /* Lock context ulist belongs to. */
+ fsp,
+ plocks,
+ num_locks);
+
+ /*
+ * If there were any overlapped entries (list is > 1 or size or start have changed),
+ * and the lock_type we just deleted from
+ * the upper layer tdb was a write lock, then before doing the unlock we need to downgrade
+ * the POSIX lock to a read lock. This allows any overlapping read locks
+ * to be atomically maintained.
+ */
+
+ if (deleted_lock_type == WRITE_LOCK &&
+ (!ulist || ulist->next != NULL || ulist->start != offset || ulist->size != count)) {
+
+ DEBUG(5,("release_posix_lock_windows_flavour: downgrading lock to READ: offset = %.0f, count = %.0f\n",
+ (double)offset, (double)count ));
+
+ if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_RDLCK)) {
+ DEBUG(0,("release_posix_lock_windows_flavour: downgrade of lock failed with error %s !\n", strerror(errno) ));
+ talloc_destroy(ul_ctx);
+ return False;
+ }
+ }
+
+ /*
+ * Release the POSIX locks on the list of ranges returned.
+ */
+
+ for(; ulist; ulist = ulist->next) {
+ offset = ulist->start;
+ count = ulist->size;
+
+ DEBUG(5,("release_posix_lock_windows_flavour: Real unlock: offset = %.0f, count = %.0f\n",
+ (double)offset, (double)count ));
+
+ if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK)) {
+ ret = False;
+ }
+ }
+
+ talloc_destroy(ul_ctx);
+ return ret;
+}
+
+/****************************************************************************
+ Next - the functions that deal with mapping CIFS POSIX locks onto
+ the underlying system POSIX locks.
+****************************************************************************/
+
+/****************************************************************************
+ POSIX function to acquire a lock. Returns True if the
+ lock could be granted, False if not.
+ As POSIX locks don't stack or conflict (they just overwrite)
+ we can map the requested lock directly onto a system one. We
+ know it doesn't conflict with locks on other contexts as the
+ upper layer would have refused it.
+****************************************************************************/
+
+bool set_posix_lock_posix_flavour(files_struct *fsp,
+ SMB_BIG_UINT u_offset,
+ SMB_BIG_UINT u_count,
+ enum brl_type lock_type,
+ int *errno_ret)
+{
+ SMB_OFF_T offset;
+ SMB_OFF_T count;
+ int posix_lock_type = map_posix_lock_type(fsp,lock_type);
+
+ DEBUG(5,("set_posix_lock_posix_flavour: File %s, offset = %.0f, count = %.0f, type = %s\n",
+ fsp->fsp_name, (double)u_offset, (double)u_count, posix_lock_type_name(lock_type) ));
+
+ /*
+ * If the requested lock won't fit in the POSIX range, we will
+ * pretend it was successful.
+ */
+
+ if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) {
+ return True;
+ }
+
+ if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,posix_lock_type)) {
+ *errno_ret = errno;
+ DEBUG(5,("set_posix_lock_posix_flavour: Lock fail !: Type = %s: offset = %.0f, count = %.0f. Errno = %s\n",
+ posix_lock_type_name(posix_lock_type), (double)offset, (double)count, strerror(errno) ));
+ return False;
+ }
+ return True;
+}
+
+/****************************************************************************
+ POSIX function to release a lock. Returns True if the
+ lock could be released, False if not.
+ We are given a complete lock state from the upper layer which is what the lock
+ state should be after the unlock has already been done, so what
+ we do is punch out holes in the unlock range where locks owned by this process
+ have a different lock context.
+****************************************************************************/
+
+bool release_posix_lock_posix_flavour(files_struct *fsp,
+ SMB_BIG_UINT u_offset,
+ SMB_BIG_UINT u_count,
+ const struct lock_context *lock_ctx,
+ const struct lock_struct *plocks,
+ int num_locks)
+{
+ bool ret = True;
+ SMB_OFF_T offset;
+ SMB_OFF_T count;
+ TALLOC_CTX *ul_ctx = NULL;
+ struct lock_list *ulist = NULL;
+ struct lock_list *ul = NULL;
+
+ DEBUG(5,("release_posix_lock_posix_flavour: File %s, offset = %.0f, count = %.0f\n",
+ fsp->fsp_name, (double)u_offset, (double)u_count ));
+
+ /*
+ * If the requested lock won't fit in the POSIX range, we will
+ * pretend it was successful.
+ */
+
+ if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) {
+ return True;
+ }
+
+ if ((ul_ctx = talloc_init("release_posix_lock")) == NULL) {
+ DEBUG(0,("release_posix_lock_windows_flavour: unable to init talloc context.\n"));
+ return False;
+ }
+
+ if ((ul = TALLOC_P(ul_ctx, struct lock_list)) == NULL) {
+ DEBUG(0,("release_posix_lock_windows_flavour: unable to talloc unlock list.\n"));
+ talloc_destroy(ul_ctx);
+ return False;
+ }
+
+ /*
+ * Create the initial list entry containing the
+ * lock we want to remove.
+ */
+
+ ZERO_STRUCTP(ul);
+ ul->start = offset;
+ ul->size = count;
+
+ DLIST_ADD(ulist, ul);
+
+ /*
+ * Walk the given array creating a linked list
+ * of unlock requests.
+ */
+
+ ulist = posix_lock_list(ul_ctx,
+ ulist,
+ lock_ctx, /* Lock context ulist belongs to. */
+ fsp,
+ plocks,
+ num_locks);
+
+ /*
+ * Release the POSIX locks on the list of ranges returned.
+ */
+
+ for(; ulist; ulist = ulist->next) {
+ offset = ulist->start;
+ count = ulist->size;
+
+ DEBUG(5,("release_posix_lock_posix_flavour: Real unlock: offset = %.0f, count = %.0f\n",
+ (double)offset, (double)count ));
+
+ if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK)) {
+ ret = False;
+ }
+ }
+
+ talloc_destroy(ul_ctx);
+ return ret;
+}
diff --git a/source3/m4/aclocal.m4 b/source3/m4/aclocal.m4
new file mode 100644
index 0000000000..9a4213d976
--- /dev/null
+++ b/source3/m4/aclocal.m4
@@ -0,0 +1,889 @@
+dnl test whether dirent has a d_off member
+AC_DEFUN(AC_DIRENT_D_OFF,
+[AC_CACHE_CHECK([for d_off in dirent], ac_cv_dirent_d_off,
+[AC_TRY_COMPILE([
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>], [struct dirent d; d.d_off;],
+ac_cv_dirent_d_off=yes, ac_cv_dirent_d_off=no)])
+if test $ac_cv_dirent_d_off = yes; then
+ AC_DEFINE(HAVE_DIRENT_D_OFF,1,[Whether dirent has a d_off member])
+fi
+])
+
+dnl Mark specified module as shared
+dnl SMB_MODULE(name,static_files,shared_files,subsystem,whatif-static,whatif-shared)
+AC_DEFUN(SMB_MODULE,
+[
+ AC_MSG_CHECKING([how to build $1])
+ if test "$[MODULE_][$1]"; then
+ DEST=$[MODULE_][$1]
+ elif test "$[MODULE_]translit([$4], [A-Z], [a-z])" -a "$[MODULE_DEFAULT_][$1]"; then
+ DEST=$[MODULE_]translit([$4], [A-Z], [a-z])
+ else
+ DEST=$[MODULE_DEFAULT_][$1]
+ fi
+
+ if test x"$DEST" = xSHARED; then
+ AC_DEFINE([$1][_init], [init_samba_module], [Whether to build $1 as shared module])
+ $4_MODULES="$$4_MODULES $3"
+ AC_MSG_RESULT([shared])
+ [$6]
+ string_shared_modules="$string_shared_modules $1"
+ elif test x"$DEST" = xSTATIC; then
+ [init_static_modules_]translit([$4], [A-Z], [a-z])="$[init_static_modules_]translit([$4], [A-Z], [a-z]) $1_init();"
+ [decl_static_modules_]translit([$4], [A-Z], [a-z])="$[decl_static_modules_]translit([$4], [A-Z], [a-z]) extern NTSTATUS $1_init(void);"
+ string_static_modules="$string_static_modules $1"
+ $4_STATIC="$$4_STATIC $2"
+ AC_SUBST($4_STATIC)
+ [$5]
+ AC_MSG_RESULT([static])
+ else
+ string_ignored_modules="$string_ignored_modules $1"
+ AC_MSG_RESULT([not])
+ fi
+])
+
+AC_DEFUN(SMB_SUBSYSTEM,
+[
+ AC_SUBST($1_STATIC)
+ AC_SUBST($1_MODULES)
+ AC_DEFINE_UNQUOTED([static_init_]translit([$1], [A-Z], [a-z]), [{$init_static_modules_]translit([$1], [A-Z], [a-z])[}], [Static init functions])
+ AC_DEFINE_UNQUOTED([static_decl_]translit([$1], [A-Z], [a-z]), [$decl_static_modules_]translit([$1], [A-Z], [a-z]), [Decl of Static init functions])
+ ifelse([$2], , :, [rm -f $2])
+])
+
+
+dnl SMB_LIBRARY(name, version, default, reason)
+dnl
+dnl configure build and use of an (internal) shared library
+dnl
+AC_DEFUN([SMB_LIBRARY],
+[
+m4_pushdef([LIBNAME], [lib$1])
+m4_pushdef([LIBUC], [m4_toupper(LIBNAME)])
+m4_pushdef([LIBLIBS], [-l$1])
+
+LIBUC[_SHARED_TARGET]=bin/LIBNAME.$SHLIBEXT
+LIBUC[_STATIC_TARGET]=bin/LIBNAME.a
+LIBUC[_SHARED]=
+LIBUC[_STATIC]=
+LIBUC[_LIBS]=
+[INSTALL_]LIBUC=
+[UNINSTALL_]LIBUC=
+
+m4_if([$2], [], [LIBUC[_SOVER]=0], [LIBUC[_SOVER]=$2])
+
+AC_SUBST(LIBUC[_SHARED_TARGET])
+AC_SUBST(LIBUC[_STATIC_TARGET])
+AC_SUBST(LIBUC[_SHARED])
+AC_SUBST(LIBUC[_STATIC])
+AC_SUBST(LIBUC[_LIBS])
+AC_SUBST([INSTALL_]LIBUC)
+AC_SUBST([UNINSTALL_]LIBUC)
+AC_SUBST(LIBUC[_SOVER])
+
+AC_MSG_CHECKING([whether to build the LIBNAME shared library])
+m4_if([$3], [no], [
+dnl set the default to not build the shared lib
+AC_ARG_WITH(LIBNAME,
+AS_HELP_STRING([--with-]LIBNAME,
+ m4_if([$4], [],
+ [Build the LIBNAME shared library (default=no)],
+ [Build the LIBNAME shared library (default=no ($4))])),
+[
+case "$withval" in
+ yes)
+ build_lib=yes
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ build_lib=no
+ ;;
+esac
+],
+[
+# if unspecified, default is not to build
+AC_MSG_RESULT(yes)
+build_lib=no
+]
+)
+],[
+dnl by default, try to build the shared lib
+AC_ARG_WITH(LIBNAME,
+AS_HELP_STRING([--with-]LIBNAME,
+ [Build the LIBNAME shared library (default=yes if shared libs supported)]),
+[
+case "$withval" in
+ no)
+ AC_MSG_RESULT(no)
+ build_lib=no
+ ;;
+ *)
+ build_lib=yes
+ ;;
+esac
+],
+[
+# if unspecified, default is to build it if possible.
+build_lib=yes
+]
+)
+])
+
+if eval test x"$build_lib" = "xyes" ; then
+ # only set the install targets if the user chose the library
+ [INSTALL_]LIBUC=[install]LIBNAME
+ [UNINSTALL_]LIBUC=[uninstall]LIBNAME
+ if eval $BLDSHARED = true; then
+ LIBUC[_SHARED]=$LIBUC[_SHARED_TARGET]
+ AC_MSG_RESULT(yes)
+ if test x"$USESHARED" != x"true" -o x"$[LINK_]LIBUC" = "xSTATIC" ; then
+ enable_static=yes
+ else
+ LIBUC[_LIBS]=LIBLIBS
+ fi
+ else
+ enable_static=yes
+ AC_MSG_RESULT(no shared library support -- will supply static library)
+ fi
+else
+ enable_static=yes
+ AC_MSG_RESULT(shared library not selected, but will supply static library)
+fi
+if test $enable_static = yes; then
+ LIBUC[_STATIC]=[\$\(]LIBUC[_OBJ0\)]
+fi
+
+m4_popdef([LIBNAME])
+m4_popdef([LIBUC])
+m4_popdef([LIBLIBS])
+
+])
+
+
+dnl AC_LIBTESTFUNC(lib, function, [actions if found], [actions if not found])
+dnl Check for a function in a library, but don't keep adding the same library
+dnl to the LIBS variable. Check whether the function is available in the
+dnl current LIBS before adding the library which prevents us spuriously
+dnl adding libraries for symbols that are in libc.
+dnl
+dnl On success, the default actions ensure that HAVE_FOO is defined. The lib
+dnl is always added to $LIBS if it was found to be necessary. The caller
+dnl can use SMB_REMOVE_LIB to strp this if necessary.
+AC_DEFUN([AC_LIBTESTFUNC],
+[
+ AC_CHECK_FUNCS($2,
+ [
+ # $2 was found in libc or existing $LIBS
+ m4_ifval([$3],
+ [
+ $3
+ ],
+ [
+ AC_DEFINE(translit([HAVE_$2], [a-z], [A-Z]), 1,
+ [Whether $2 is available])
+ ])
+ ],
+ [
+ # $2 was not found, try adding lib$1
+ case " $LIBS " in
+ *\ -l$1\ *)
+ m4_ifval([$4],
+ [
+ $4
+ ],
+ [
+ # $2 was not found and we already had lib$1
+ # nothing to do here by default
+ true
+ ])
+ ;;
+ *)
+ # $2 was not found, try adding lib$1
+ AC_CHECK_LIB($1, $2,
+ [
+ LIBS="-l$1 $LIBS"
+ m4_ifval([$3],
+ [
+ $3
+ ],
+ [
+ AC_DEFINE(translit([HAVE_$2], [a-z], [A-Z]), 1,
+ [Whether $2 is available])
+ ])
+ ],
+ [
+ m4_ifval([$4],
+ [
+ $4
+ ],
+ [
+ # $2 was not found in lib$1
+ # nothing to do here by default
+ true
+ ])
+ ])
+ ;;
+ esac
+ ])
+])
+
+# AC_CHECK_LIB_EXT(LIBRARY, [EXT_LIBS], [FUNCTION],
+# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND],
+# [ADD-ACTION-IF-FOUND],[OTHER-LIBRARIES])
+# ------------------------------------------------------
+#
+# Use a cache variable name containing both the library and function name,
+# because the test really is for library $1 defining function $3, not
+# just for library $1. Separate tests with the same $1 and different $3s
+# may have different results.
+#
+# Note that using directly AS_VAR_PUSHDEF([ac_Lib], [ac_cv_lib_$1_$3])
+# is asking for trouble, since AC_CHECK_LIB($lib, fun) would give
+# ac_cv_lib_$lib_fun, which is definitely not what was meant. Hence
+# the AS_LITERAL_IF indirection.
+#
+# FIXME: This macro is extremely suspicious. It DEFINEs unconditionally,
+# whatever the FUNCTION, in addition to not being a *S macro. Note
+# that the cache does depend upon the function we are looking for.
+#
+# It is on purpose we used `ac_check_lib_ext_save_LIBS' and not just
+# `ac_save_LIBS': there are many macros which don't want to see `LIBS'
+# changed but still want to use AC_CHECK_LIB_EXT, so they save `LIBS'.
+# And ``ac_save_LIBS' is too tempting a name, so let's leave them some
+# freedom.
+AC_DEFUN([AC_CHECK_LIB_EXT],
+[
+AH_CHECK_LIB_EXT([$1])
+ac_check_lib_ext_save_LIBS=$LIBS
+LIBS="-l$1 $$2 $7 $LIBS"
+AS_LITERAL_IF([$1],
+ [AS_VAR_PUSHDEF([ac_Lib_ext], [ac_cv_lib_ext_$1])],
+ [AS_VAR_PUSHDEF([ac_Lib_ext], [ac_cv_lib_ext_$1''])])dnl
+
+m4_ifval([$3],
+ [
+ AH_CHECK_FUNC_EXT([$3])
+ AS_LITERAL_IF([$1],
+ [AS_VAR_PUSHDEF([ac_Lib_func], [ac_cv_lib_ext_$1_$3])],
+ [AS_VAR_PUSHDEF([ac_Lib_func], [ac_cv_lib_ext_$1''_$3])])dnl
+ AC_CACHE_CHECK([for $3 in -l$1], ac_Lib_func,
+ [AC_TRY_LINK_FUNC($3,
+ [AS_VAR_SET(ac_Lib_func, yes);
+ AS_VAR_SET(ac_Lib_ext, yes)],
+ [AS_VAR_SET(ac_Lib_func, no);
+ AS_VAR_SET(ac_Lib_ext, no)])
+ ])
+ AS_IF([test AS_VAR_GET(ac_Lib_func) = yes],
+ [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$3))])dnl
+ AS_VAR_POPDEF([ac_Lib_func])dnl
+ ],[
+ AC_CACHE_CHECK([for -l$1], ac_Lib_ext,
+ [AC_TRY_LINK_FUNC([main],
+ [AS_VAR_SET(ac_Lib_ext, yes)],
+ [AS_VAR_SET(ac_Lib_ext, no)])
+ ])
+ ])
+LIBS=$ac_check_lib_ext_save_LIBS
+
+AS_IF([test AS_VAR_GET(ac_Lib_ext) = yes],
+ [m4_default([$4],
+ [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_LIB$1))
+ case "$$2" in
+ *-l$1*)
+ ;;
+ *)
+ $2="-l$1 $$2"
+ ;;
+ esac])
+ [$6]
+ ],
+ [$5])dnl
+AS_VAR_POPDEF([ac_Lib_ext])dnl
+])# AC_CHECK_LIB_EXT
+
+# AH_CHECK_LIB_EXT(LIBNAME)
+# ---------------------
+m4_define([AH_CHECK_LIB_EXT],
+[AH_TEMPLATE(AS_TR_CPP(HAVE_LIB$1),
+ [Define to 1 if you have the `]$1[' library (-l]$1[).])])
+
+# AC_CHECK_FUNCS_EXT(FUNCTION, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# -----------------------------------------------------------------
+dnl check for a function in a $LIBS and $OTHER_LIBS libraries variable.
+dnl AC_CHECK_FUNC_EXT(func,OTHER_LIBS,IF-TRUE,IF-FALSE)
+AC_DEFUN([AC_CHECK_FUNC_EXT],
+[
+ AH_CHECK_FUNC_EXT($1)
+ ac_check_func_ext_save_LIBS=$LIBS
+ LIBS="$2 $LIBS"
+ AS_VAR_PUSHDEF([ac_var], [ac_cv_func_ext_$1])dnl
+ AC_CACHE_CHECK([for $1], ac_var,
+ [AC_LINK_IFELSE([AC_LANG_FUNC_LINK_TRY([$1])],
+ [AS_VAR_SET(ac_var, yes)],
+ [AS_VAR_SET(ac_var, no)])])
+ LIBS=$ac_check_func_ext_save_LIBS
+ AS_IF([test AS_VAR_GET(ac_var) = yes],
+ [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_$1])) $3],
+ [$4])dnl
+AS_VAR_POPDEF([ac_var])dnl
+])# AC_CHECK_FUNC
+
+# AH_CHECK_FUNC_EXT(FUNCNAME)
+# ---------------------
+m4_define([AH_CHECK_FUNC_EXT],
+[AH_TEMPLATE(AS_TR_CPP(HAVE_$1),
+ [Define to 1 if you have the `]$1[' function.])])
+
+dnl Define an AC_DEFINE with ifndef guard.
+dnl AC_N_DEFINE(VARIABLE [, VALUE])
+define(AC_N_DEFINE,
+[cat >> confdefs.h <<\EOF
+[#ifndef] $1
+[#define] $1 ifelse($#, 2, [$2], $#, 3, [$2], 1)
+[#endif]
+EOF
+])
+
+dnl Add an #include
+dnl AC_ADD_INCLUDE(VARIABLE)
+define(AC_ADD_INCLUDE,
+[cat >> confdefs.h <<\EOF
+[#include] $1
+EOF
+])
+
+dnl Copied from libtool.m4
+AC_DEFUN(AC_PROG_LD_GNU,
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
+ ac_cv_prog_gnu_ld=yes
+else
+ ac_cv_prog_gnu_ld=no
+fi])
+])
+
+dnl Removes -I/usr/include/? from given variable
+AC_DEFUN(CFLAGS_REMOVE_USR_INCLUDE,[
+ ac_new_flags=""
+ for i in [$]$1; do
+ case [$]i in
+ -I/usr/include|-I/usr/include/) ;;
+ *) ac_new_flags="[$]ac_new_flags [$]i" ;;
+ esac
+ done
+ $1=[$]ac_new_flags
+])
+
+dnl Removes '-L/usr/lib[/]', '-Wl,-rpath,/usr/lib[/]'
+dnl and '-Wl,-rpath -Wl,/usr/lib[/]' from given variable
+AC_DEFUN(LIB_REMOVE_USR_LIB,[
+ ac_new_flags=""
+ l=""
+ for i in [$]$1; do
+ case [$]l[$]i in
+ -L/usr/lib) ;;
+ -L/usr/lib/) ;;
+ -Wl,-rpath,/usr/lib) ;;
+ -Wl,-rpath,/usr/lib/) ;;
+ -Wl,-rpath) l=[$]i;;
+ -Wl,-rpath-Wl,/usr/lib) l="";;
+ -Wl,-rpath-Wl,/usr/lib/) l="";;
+ *)
+ s=" "
+ if test x"[$]ac_new_flags" = x""; then
+ s="";
+ fi
+ if test x"[$]l" = x""; then
+ ac_new_flags="[$]ac_new_flags[$]s[$]i";
+ else
+ ac_new_flags="[$]ac_new_flags[$]s[$]l [$]i";
+ fi
+ l=""
+ ;;
+ esac
+ done
+ $1=[$]ac_new_flags
+])
+
+dnl From Bruno Haible.
+
+AC_DEFUN(jm_ICONV,
+[
+ dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and
+ dnl those with the standalone portable libiconv installed).
+ AC_MSG_CHECKING(for iconv in $1)
+ jm_cv_func_iconv="no"
+ jm_cv_lib_iconv=""
+ jm_cv_giconv=no
+ jm_save_LIBS="$LIBS"
+
+ dnl Check for include in funny place but no lib needed
+ if test "$jm_cv_func_iconv" != yes; then
+ AC_TRY_LINK([#include <stdlib.h>
+#include <giconv.h>],
+ [iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);],
+ jm_cv_func_iconv=yes
+ jm_cv_include="giconv.h"
+ jm_cv_giconv="yes"
+ jm_cv_lib_iconv="")
+
+ dnl Standard iconv.h include, lib in glibc or libc ...
+ if test "$jm_cv_func_iconv" != yes; then
+ AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+ [iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);],
+ jm_cv_include="iconv.h"
+ jm_cv_func_iconv=yes
+ jm_cv_lib_iconv="")
+
+ if test "$jm_cv_lib_iconv" != yes; then
+ jm_save_LIBS="$LIBS"
+ LIBS="$LIBS -lgiconv"
+ AC_TRY_LINK([#include <stdlib.h>
+#include <giconv.h>],
+ [iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);],
+ jm_cv_lib_iconv=yes
+ jm_cv_func_iconv=yes
+ jm_cv_include="giconv.h"
+ jm_cv_giconv=yes
+ jm_cv_lib_iconv="giconv")
+
+ LIBS="$jm_save_LIBS"
+
+ if test "$jm_cv_func_iconv" != yes; then
+ jm_save_LIBS="$LIBS"
+ LIBS="$LIBS -liconv"
+ AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+ [iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);],
+ jm_cv_include="iconv.h"
+ jm_cv_func_iconv=yes
+ jm_cv_lib_iconv="iconv")
+ LIBS="$jm_save_LIBS"
+
+ if test "$jm_cv_lib_iconv" != yes; then
+ jm_save_LIBS="$LIBS"
+ LIBS="$LIBS -lbiconv"
+ AC_TRY_LINK([#include <stdlib.h>
+#include <biconv.h>],
+ [iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);],
+ jm_cv_lib_iconv=yes
+ jm_cv_func_iconv=yes
+ jm_cv_include="biconv.h"
+ jm_cv_biconv=yes
+ jm_cv_lib_iconv="biconv")
+
+ LIBS="$jm_save_LIBS"
+ fi
+ fi
+ fi
+ fi
+ fi
+ if test "$jm_cv_func_iconv" = yes; then
+ if test "$jm_cv_giconv" = yes; then
+ AC_DEFINE(HAVE_GICONV, 1, [What header to include for iconv() function: giconv.h])
+ AC_MSG_RESULT(yes)
+ ICONV_FOUND=yes
+ else
+ if test "$jm_cv_biconv" = yes; then
+ AC_DEFINE(HAVE_BICONV, 1, [What header to include for iconv() function: biconv.h])
+ AC_MSG_RESULT(yes)
+ ICONV_FOUND=yes
+ else
+ AC_DEFINE(HAVE_ICONV, 1, [What header to include for iconv() function: iconv.h])
+ AC_MSG_RESULT(yes)
+ ICONV_FOUND=yes
+ fi
+ fi
+ else
+ AC_MSG_RESULT(no)
+ fi
+])
+
+AC_DEFUN(rjs_CHARSET,[
+ dnl Find out if we can convert from $1 to UCS2-LE
+ AC_MSG_CHECKING([can we convert from $1 to UCS2-LE?])
+ AC_TRY_RUN([
+#include <$jm_cv_include>
+main(){
+ iconv_t cd = iconv_open("$1", "UCS-2LE");
+ if (cd == 0 || cd == (iconv_t)-1) {
+ return -1;
+ }
+ return 0;
+}
+ ],ICONV_CHARSET=$1,ICONV_CHARSET=no,ICONV_CHARSET=cross)
+ AC_MSG_RESULT($ICONV_CHARSET)
+])
+
+dnl AC_ENABLE_SHARED - implement the --enable-shared flag
+dnl Usage: AC_ENABLE_SHARED[(DEFAULT)]
+dnl Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
+dnl `yes'.
+AC_DEFUN([AC_ENABLE_SHARED],
+[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE(shared,
+changequote(<<, >>)dnl
+<< --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT],
+changequote([, ])dnl
+[p=${PACKAGE-default}
+case $enableval in
+yes) enable_shared=yes ;;
+no) enable_shared=no ;;
+*)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+ for pkg in $enableval; do
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac],
+enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl
+])
+
+dnl AC_ENABLE_STATIC - implement the --enable-static flag
+dnl Usage: AC_ENABLE_STATIC[(DEFAULT)]
+dnl Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
+dnl `yes'.
+AC_DEFUN([AC_ENABLE_STATIC],
+[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE(static,
+changequote(<<, >>)dnl
+<< --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT],
+changequote([, ])dnl
+[p=${PACKAGE-default}
+case $enableval in
+yes) enable_static=yes ;;
+no) enable_static=no ;;
+*)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+ for pkg in $enableval; do
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac],
+enable_static=AC_ENABLE_STATIC_DEFAULT)dnl
+])
+
+dnl AC_DISABLE_STATIC - set the default static flag to --disable-static
+AC_DEFUN([AC_DISABLE_STATIC],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_STATIC(no)])
+
+dnl AC_TRY_RUN_STRICT(PROGRAM,CFLAGS,CPPFLAGS,LDFLAGS,
+dnl [ACTION-IF-TRUE],[ACTION-IF-FALSE],
+dnl [ACTION-IF-CROSS-COMPILING = RUNTIME-ERROR])
+AC_DEFUN( [AC_TRY_RUN_STRICT],
+[
+ old_CFLAGS="$CFLAGS";
+ CFLAGS="$2";
+ export CFLAGS;
+ old_CPPFLAGS="$CPPFLAGS";
+ CPPFLAGS="$3";
+ export CPPFLAGS;
+ old_LDFLAGS="$LDFLAGS";
+ LDFLAGS="$4";
+ export LDFLAGS;
+ AC_TRY_RUN([$1],[$5],[$6],[$7])
+ CFLAGS="$old_CFLAGS";
+ old_CFLAGS="";
+ export CFLAGS;
+ CPPFLAGS="$old_CPPFLAGS";
+ old_CPPFLAGS="";
+ export CPPFLAGS;
+ LDFLAGS="$old_LDFLAGS";
+ old_LDFLAGS="";
+ export LDFLAGS;
+])
+
+dnl SMB_CHECK_SYSCONF(varname)
+dnl Tests whether the sysconf(3) variable "varname" is available.
+AC_DEFUN([SMB_CHECK_SYSCONF],
+[
+ AC_CACHE_CHECK([for sysconf($1)],
+ samba_cv_SYSCONF$1,
+ [
+ AC_TRY_LINK([#include <unistd.h>],
+ [ return sysconf($1) == -1 ? 1 : 0; ],
+ [ samba_cv_SYSCONF$1=yes ],
+ [ samba_cv_SYSCONF$1=no ])
+ ])
+
+ if test x"$samba_cv_SYSCONF$1" = x"yes" ; then
+ AC_DEFINE(SYSCONF$1, 1, [Whether sysconf($1) is available])
+ fi
+])
+
+dnl SMB_IS_LIBPTHREAD_LINKED([actions if true], [actions if false])
+dnl Test whether the current LIBS results in libpthread being present.
+dnl Execute the corresponding user action list.
+AC_DEFUN([SMB_IS_LIBPTHREAD_LINKED],
+[
+ AC_MSG_CHECKING(if libpthread is linked)
+ AC_TRY_LINK([],
+ [return pthread_create(0, 0, 0, 0);],
+ [
+ AC_MSG_RESULT(yes)
+ $1
+ ],
+ [
+ AC_MSG_RESULT(no)
+ $2
+ ])
+])
+
+dnl SMB_REMOVE_LIB(lib)
+dnl Remove the given library from $LIBS
+AC_DEFUN([SMB_REMOVE_LIB],
+[
+ LIBS=`echo $LIBS | sed '-es/-l$1//g'`
+])
+
+dnl SMB_CHECK_DMAPI([actions if true], [actions if false])
+dnl Check whether DMAPI is available and is a version that we know
+dnl how to deal with. The default truth action is to set samba_dmapi_libs
+dnl to the list of necessary libraries, and to define USE_DMAPI.
+AC_DEFUN([SMB_CHECK_DMAPI],
+[
+ samba_dmapi_libs=""
+
+ if test x"$samba_dmapi_libs" = x"" ; then
+ AC_CHECK_LIB(dm, dm_get_eventlist,
+ [ samba_dmapi_libs="-ldm"], [])
+ fi
+
+ if test x"$samba_dmapi_libs" = x"" ; then
+ AC_CHECK_LIB(jfsdm, dm_get_eventlist,
+ [samba_dmapi_libs="-ljfsdm"], [])
+ fi
+
+ if test x"$samba_dmapi_libs" = x"" ; then
+ AC_CHECK_LIB(xdsm, dm_get_eventlist,
+ [samba_dmapi_libs="-lxdsm"], [])
+ fi
+
+ if test x"$samba_dmapi_libs" = x"" ; then
+ AC_CHECK_LIB(dmapi, dm_get_eventlist,
+ [samba_dmapi_libs="-ldmapi"], [])
+ fi
+
+
+ # Only bother to test ehaders if we have a candidate DMAPI library
+ if test x"$samba_dmapi_libs" != x"" ; then
+ AC_CHECK_HEADERS(sys/dmi.h xfs/dmapi.h sys/jfsdmapi.h sys/dmapi.h dmapi.h)
+ fi
+
+ if test x"$samba_dmapi_libs" != x"" ; then
+ samba_dmapi_save_LIBS="$LIBS"
+ LIBS="$LIBS $samba_dmapi_libs"
+ AC_TRY_LINK(
+ [
+#include <time.h> /* needed by Tru64 */
+#include <sys/types.h> /* needed by AIX */
+#ifdef HAVE_XFS_DMAPI_H
+#include <xfs/dmapi.h>
+#elif defined(HAVE_SYS_DMI_H)
+#include <sys/dmi.h>
+#elif defined(HAVE_SYS_JFSDMAPI_H)
+#include <sys/jfsdmapi.h>
+#elif defined(HAVE_SYS_DMAPI_H)
+#include <sys/dmapi.h>
+#elif defined(HAVE_DMAPI_H)
+#include <dmapi.h>
+#endif
+ ],
+ [
+/* This link test is designed to fail on IRI 6.4, but should
+ * succeed on Linux, IRIX 6.5 and AIX.
+ */
+ char * version;
+ dm_eventset_t events;
+ /* This doesn't take an argument on IRIX 6.4. */
+ dm_init_service(&version);
+ /* IRIX 6.4 expects events to be a pointer. */
+ DMEV_ISSET(DM_EVENT_READ, events);
+ ],
+ [
+ true # DMAPI link test succeeded
+ ],
+ [
+ # DMAPI link failure
+ samba_dmapi_libs=
+ ])
+ LIBS="$samba_dmapi_save_LIBS"
+ fi
+
+ if test x"$samba_dmapi_libs" = x"" ; then
+ # DMAPI detection failure actions begin
+ ifelse($2, [],
+ [
+ AC_ERROR(Failed to detect a supported DMAPI implementation)
+ ],
+ [
+ $2
+ ])
+ # DMAPI detection failure actions end
+ else
+ # DMAPI detection success actions start
+ ifelse($1, [],
+ [
+ AC_DEFINE(USE_DMAPI, 1,
+ [Whether we should build DMAPI integration components])
+ AC_MSG_NOTICE(Found DMAPI support in $samba_dmapi_libs)
+ ],
+ [
+ $1
+ ])
+ # DMAPI detection success actions end
+ fi
+
+])
+
+dnl SMB_CHECK_CLOCK_ID(clockid)
+dnl Test whether the specified clock_gettime clock ID is available. If it
+dnl is, we define HAVE_clockid
+AC_DEFUN([SMB_CHECK_CLOCK_ID],
+[
+ AC_MSG_CHECKING(for $1)
+ AC_TRY_LINK([
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+ ],
+ [
+clockid_t clk = $1;
+ ],
+ [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_$1, 1,
+ [Whether the clock_gettime clock ID $1 is available])
+ ],
+ [
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl SMB_IF_RTSIGNAL_BUG([actions if true],
+dnl [actions if false],
+dnl [actions if cross compiling])
+dnl Test whether we can call sigaction with RT_SIGNAL_NOTIFY and
+dnl RT_SIGNAL_LEASE (also RT_SIGNAL_AIO for good measure, though
+dnl I don't believe that triggers any bug.
+dnl
+dnl See the samba-technical thread titled "Failed to setup
+dnl RT_SIGNAL_NOTIFY handler" for details on the bug in question.
+AC_DEFUN([SMB_IF_RTSIGNAL_BUG],
+[
+ rt_signal_notify_works=yes
+ rt_signal_lease_works=yes
+ rt_signal_aio_works=yes
+
+ AC_MSG_CHECKING(if sigaction works with realtime signals)
+ AC_TRY_RUN(
+ [
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+
+/* from smbd/notify_kernel.c */
+#ifndef RT_SIGNAL_NOTIFY
+#define RT_SIGNAL_NOTIFY (SIGRTMIN+2)
+#endif
+
+/* from smbd/aio.c */
+#ifndef RT_SIGNAL_AIO
+#define RT_SIGNAL_AIO (SIGRTMIN+3)
+#endif
+
+/* from smbd/oplock_linux.c */
+#ifndef RT_SIGNAL_LEASE
+#define RT_SIGNAL_LEASE (SIGRTMIN+1)
+#endif
+
+static void signal_handler(int sig, siginfo_t *info, void *unused)
+{
+ int do_nothing = 0;
+}
+
+int main(void)
+{
+ int result = 0;
+ struct sigaction act = {0};
+
+ act.sa_sigaction = signal_handler;
+ act.sa_flags = SA_SIGINFO;
+ sigemptyset( &act.sa_mask );
+
+ if (sigaction(RT_SIGNAL_LEASE, &act, 0) != 0) {
+ /* Failed to setup RT_SIGNAL_LEASE handler */
+ result += 1;
+ }
+
+ if (sigaction(RT_SIGNAL_NOTIFY, &act, 0) != 0) {
+ /* Failed to setup RT_SIGNAL_NOTIFY handler */
+ result += 10;
+ }
+
+ if (sigaction(RT_SIGNAL_AIO, &act, 0) != 0) {
+ /* Failed to setup RT_SIGNAL_AIO handler */
+ result += 100;
+ }
+
+ /* zero on success */
+ return result;
+}
+ ],
+ [
+ AC_MSG_RESULT(yes)
+ $2
+ ],
+ [
+ AC_MSG_RESULT(no)
+ case "$ac_status" in
+ 1|11|101|111) rt_signal_lease_ok=no ;;
+ esac
+ case "$ac_status" in
+ 10|11|110|111) rt_signal_notify_ok=no ;;
+ esac
+ case "$ac_status" in
+ 100|110|101|111) rt_signal_aio_ok=no ;;
+ esac
+ $2
+ ],
+ [
+ AC_MSG_RESULT(cross)
+ $3
+ ])
+])
+
+m4_include(lib/replace/libreplace.m4)
diff --git a/source3/m4/check_path.m4 b/source3/m4/check_path.m4
new file mode 100644
index 0000000000..7aa8c213e0
--- /dev/null
+++ b/source3/m4/check_path.m4
@@ -0,0 +1,327 @@
+dnl
+dnl Samba3 build environment path checks
+dnl
+dnl Copyright (C) Michael Adam 2008
+dnl
+dnl Released under the GNU General Public License
+dnl http://www.gnu.org/licenses/
+dnl
+
+AC_LIBREPLACE_LOCATION_CHECKS
+
+#################################################
+# Directory handling stuff to support both the
+# legacy SAMBA directories and FHS compliant
+# ones...
+AC_PREFIX_DEFAULT(/usr/local/samba)
+
+rootsbindir="\${SBINDIR}"
+lockdir="\${VARDIR}/locks"
+piddir="\${VARDIR}/locks"
+test "${mandir}" || mandir="\${prefix}/man"
+logfilebase="\${VARDIR}"
+privatedir="\${prefix}/private"
+test "${libdir}" || libdir="\${prefix}/lib"
+modulesdir="${libdir}"
+pammodulesdir="${libdir}/security"
+configdir="${libdir}"
+swatdir="\${prefix}/swat"
+codepagedir="\${MODULESDIR}"
+statedir="\${LOCKDIR}"
+cachedir="\${LOCKDIR}"
+
+AC_ARG_WITH(fhs,
+[AS_HELP_STRING([--with-fhs],[Use FHS-compliant paths (default=no)])],
+[ case "$withval" in
+ yes)
+ lockdir="\${VARDIR}/lib/samba"
+ piddir="\${VARDIR}/run"
+ mandir="\${prefix}/share/man"
+ logfilebase="\${VARDIR}/log/samba"
+ privatedir="\${CONFIGDIR}/private"
+ test "${libdir}" || libdir="\${prefix}/lib"
+ modulesdir="${libdir}/samba"
+ configdir="\${sysconfdir}/samba"
+ swatdir="\${DATADIR}/samba/swat"
+ codepagedir="\${MODULESDIR}"
+ statedir="\${VARDIR}/lib/samba"
+ cachedir="\${VARDIR}/lib/samba"
+ AC_DEFINE(FHS_COMPATIBLE, 1, [Whether to use fully FHS-compatible paths])
+ ;;
+ esac])
+
+#################################################
+# set private directory location
+AC_ARG_WITH(privatedir,
+[AS_HELP_STRING([--with-privatedir=DIR], [Where to put smbpasswd ($ac_default_prefix/private)])],
+[ case "$withval" in
+ yes|no)
+ #
+ # Just in case anybody calls it without argument
+ #
+ AC_MSG_WARN([--with-privatedir called without argument - will use default])
+ ;;
+ * )
+ privatedir="$withval"
+ ;;
+ esac])
+
+#################################################
+# set root sbin directory location
+AC_ARG_WITH(rootsbindir,
+[AS_HELP_STRING([--with-rootsbindir=DIR], [Which directory to use for root sbin ($ac_default_prefix/sbin)])],
+[ case "$withval" in
+ yes|no)
+ #
+ # Just in case anybody calls it without argument
+ #
+ AC_MSG_WARN([--with-rootsbindir called without argument - will use default])
+ ;;
+ * )
+ rootsbindir="$withval"
+ ;;
+ esac])
+
+#################################################
+# set lock directory location
+AC_ARG_WITH(lockdir,
+[AS_HELP_STRING([--with-lockdir=DIR], [Where to put lock files ($ac_default_prefix/var/locks)])],
+[ case "$withval" in
+ yes|no)
+ #
+ # Just in case anybody calls it without argument
+ #
+ AC_MSG_WARN([--with-lockdir called without argument - will use default])
+ ;;
+ * )
+ lockdir="$withval"
+ ;;
+ esac])
+
+#################################################
+# set pid directory location
+AC_ARG_WITH(piddir,
+[AS_HELP_STRING([--with-piddir=DIR], [Where to put pid files ($ac_default_prefix/var/locks)])],
+[ case "$withval" in
+ yes|no)
+ #
+ # Just in case anybody calls it without argument
+ #
+ AC_MSG_WARN([--with-piddir called without argument - will use default])
+ ;;
+ * )
+ piddir="$withval"
+ ;;
+ esac])
+
+#################################################
+# set SWAT directory location
+AC_ARG_WITH(swatdir,
+[AS_HELP_STRING([--with-swatdir=DIR], [Where to put SWAT files ($ac_default_prefix/swat)])],
+[ case "$withval" in
+ yes|no)
+ #
+ # Just in case anybody does it
+ #
+ AC_MSG_WARN([--with-swatdir called without argument - will use default])
+ ;;
+ * )
+ swatdir="$withval"
+ ;;
+ esac])
+
+#################################################
+# set configuration directory location
+AC_ARG_WITH(configdir,
+[AS_HELP_STRING([--with-configdir=DIR], [Where to put configuration files ($libdir)])],
+[ case "$withval" in
+ yes|no)
+ #
+ # Just in case anybody does it
+ #
+ AC_MSG_WARN([--with-configdir called without argument - will use default])
+ ;;
+ * )
+ configdir="$withval"
+ ;;
+ esac])
+
+#################################################
+# set log directory location
+AC_ARG_WITH(logfilebase,
+[AS_HELP_STRING([--with-logfilebase=DIR], [Where to put log files ($VARDIR)])],
+[ case "$withval" in
+ yes|no)
+ #
+ # Just in case anybody does it
+ #
+ AC_MSG_WARN([--with-logfilebase called without argument - will use default])
+ ;;
+ * )
+ logfilebase="$withval"
+ ;;
+ esac])
+
+
+#################################################
+# set ctdb source directory location
+AC_ARG_WITH(ctdb,
+[AS_HELP_STRING([--with-ctdb=DIR], [Where to find ctdb sources])],
+[ case "$withval" in
+ yes|no)
+ AC_MSG_WARN([--with-ctdb called without argument])
+ ;;
+ * )
+ ctdbdir="$withval"
+ ;;
+ esac])
+
+#################################################
+# set shared modules (internal lib) directory location
+AC_ARG_WITH(modulesdir,
+[AS_HELP_STRING([--with-modulesdir=DIR], [Where to put shared modules ($libdir)])],
+[ case "$withval" in
+ yes|no)
+ #
+ # Just in case anybody does it
+ #
+ AC_MSG_WARN([--with-modulesdir without argument - will use default])
+ ;;
+ * )
+ modulesdir="$withval"
+ ;;
+ esac])
+
+#################################################
+# set PAM modules directory location
+AC_ARG_WITH(pammodulesdir,
+[AS_HELP_STRING([--with-pammodulesdir=DIR], [Which directory to use for PAM modules ($ac_default_prefix/$libdir/security)])],
+[ case "$withval" in
+ yes|no)
+ #
+ # Just in case anybody calls it without argument
+ #
+ AC_MSG_WARN([--with-pammodulesdir called without argument - will use default])
+ ;;
+ * )
+ pammodulesdir="$withval"
+ ;;
+ esac])
+
+#################################################
+# set man directory location
+AC_ARG_WITH(mandir,
+[AS_HELP_STRING([--with-mandir=DIR], [Where to put man pages ($mandir)])],
+[ case "$withval" in
+ yes|no)
+ #
+ # Just in case anybody does it
+ #
+ AC_MSG_WARN([--with-mandir without argument - will use default])
+ ;;
+ * )
+ mandir="$withval"
+ ;;
+ esac])
+
+AC_SUBST(configdir)
+AC_SUBST(lockdir)
+AC_SUBST(piddir)
+AC_SUBST(logfilebase)
+AC_SUBST(ctdbdir)
+AC_SUBST(privatedir)
+AC_SUBST(swatdir)
+AC_SUBST(bindir)
+AC_SUBST(sbindir)
+AC_SUBST(codepagedir)
+AC_SUBST(statedir)
+AC_SUBST(cachedir)
+AC_SUBST(rootsbindir)
+AC_SUBST(pammodulesdir)
+AC_SUBST(modulesdir)
+
+#################################################
+# set prefix for 'make test'
+selftest_prefix="./st"
+AC_SUBST(selftest_prefix)
+AC_ARG_WITH(selftest-prefix,
+[AS_HELP_STRING([--with-selftest-prefix=DIR], [The prefix where make test will be run ($selftest_prefix)])],
+[ case "$withval" in
+ yes|no)
+ AC_MSG_WARN([--with-selftest-prefix called without argument - will use default])
+ ;;
+ * )
+ selftest_prefix="$withval"
+ ;;
+ esac
+])
+
+#################################################
+# set path of samba4's smbtorture
+smbtorture4_path=""
+AC_SUBST(smbtorture4_path)
+AC_ARG_WITH(smbtorture4_path,
+[AS_HELP_STRING([--with-smbtorture4-path=PATH], [The path to a samba4 smbtorture for make test (none)])],
+[ case "$withval" in
+ yes|no)
+ AC_MSG_ERROR([--with-smbtorture4-path should take a path])
+ ;;
+ * )
+ smbtorture4_path="$withval"
+ if test -z "$smbtorture4_path" -a ! -f $smbtorture4_path; then
+ AC_MSG_ERROR(['$smbtorture_path' does not exist!])
+ fi
+ ;;
+ esac
+])
+
+## check for --enable-debug first before checking CFLAGS before
+## so that we don't mix -O and -g
+debug=no
+AC_ARG_ENABLE(debug,
+[AS_HELP_STRING([--enable-debug], [Turn on compiler debugging information (default=no)])],
+ [if eval "test x$enable_debug = xyes"; then
+ debug=yes
+ fi])
+
+developer=no
+AC_ARG_ENABLE(developer, [AS_HELP_STRING([--enable-developer], [Turn on developer warnings and debugging (default=no)])],
+ [if eval "test x$enable_developer = xyes"; then
+ debug=yes
+ developer=yes
+ fi])
+
+krb5developer=no
+AC_ARG_ENABLE(krb5developer, [AS_HELP_STRING([--enable-krb5developer], [Turn on developer warnings and debugging, except -Wstrict-prototypes (default=no)])],
+ [if eval "test x$enable_krb5developer = xyes"; then
+ debug=yes
+ developer=yes
+ krb5_developer=yes
+ fi])
+
+picky_developer=no
+AC_ARG_ENABLE(picky-developer, [AS_HELP_STRING([--enable-picky-developer], [Halt compilation on warnings])],
+ [if eval "test x$enable_picky_developer = xyes"; then
+ debug=yes
+ developer=yes
+ picky_developer=yes
+ fi])
+
+AC_ARG_WITH(cfenc,
+[AS_HELP_STRING([--with-cfenc=HEADERDIR], [Use internal CoreFoundation encoding API for optimization (Mac OS X/Darwin only)])],
+[
+# May be in source $withval/CoreFoundation/StringEncodings.subproj.
+# Should have been in framework $withval/CoreFoundation.framework/Headers.
+for d in \
+ $withval/CoreFoundation/StringEncodings.subproj \
+ $withval/StringEncodings.subproj \
+ $withval/CoreFoundation.framework/Headers \
+ $withval/Headers \
+ $withval
+do
+ if test -r $d/CFStringEncodingConverter.h; then
+ ln -sfh $d include/CoreFoundation
+ fi
+done
+])
+
diff --git a/source3/m4/samba_version.m4 b/source3/m4/samba_version.m4
new file mode 100644
index 0000000000..4d749e9bb9
--- /dev/null
+++ b/source3/m4/samba_version.m4
@@ -0,0 +1,29 @@
+dnl
+dnl Samba3 build environment - Samba version variables
+dnl
+dnl Copyright (C) Michael Adam 2008
+dnl
+dnl Released under the GNU General Public License
+dnl http://www.gnu.org/licenses/
+dnl
+dnl
+
+SMB_VERSION_STRING=`cat $srcdir/include/version.h | grep 'SAMBA_VERSION_OFFICIAL_STRING' | cut -d '"' -f2`
+echo "SAMBA VERSION: ${SMB_VERSION_STRING}"
+
+SAMBA_VERSION_GIT_COMMIT_FULLREV=`cat $srcdir/include/version.h | grep 'SAMBA_VERSION_GIT_COMMIT_FULLREV' | cut -d ' ' -f3- | cut -d '"' -f2`
+if test -n "${SAMBA_VERSION_GIT_COMMIT_FULLREV}";then
+ echo "BUILD COMMIT REVISION: ${SAMBA_VERSION_GIT_COMMIT_FULLREV}"
+fi
+SAMBA_VERSION_GIT_COMMIT_DATE=`cat $srcdir/include/version.h | grep 'SAMBA_VERSION_GIT_COMMIT_DATE' | cut -d ' ' -f3-`
+if test -n "${SAMBA_VERSION_GIT_COMMIT_DATE}";then
+ echo "BUILD COMMIT DATE: ${SAMBA_VERSION_GIT_COMMIT_DATE}"
+fi
+SAMBA_VERSION_GIT_COMMIT_TIME=`cat $srcdir/include/version.h | grep 'SAMBA_VERSION_GIT_COMMIT_TIME' | cut -d ' ' -f3-`
+if test -n "${SAMBA_VERSION_GIT_COMMIT_TIME}";then
+ echo "BUILD COMMIT TIME: ${SAMBA_VERSION_GIT_COMMIT_TIME}"
+
+ # just to keep the build-farm gui happy for now...
+ echo "BUILD REVISION: ${SAMBA_VERSION_GIT_COMMIT_TIME}"
+fi
+
diff --git a/source3/m4/swat.m4 b/source3/m4/swat.m4
new file mode 100644
index 0000000000..2fdd82eda2
--- /dev/null
+++ b/source3/m4/swat.m4
@@ -0,0 +1,27 @@
+dnl
+dnl Samba3 build environment SWAT configuration
+dnl
+dnl Copyright (C) Michael Adam 2008
+dnl
+dnl Released under the GNU General Public License
+dnl http://www.gnu.org/licenses/
+dnl
+
+
+SWAT_SBIN_TARGETS='bin/swat$(EXEEXT)'
+SWAT_INSTALL_TARGETS=installswat
+
+AC_ARG_ENABLE(swat,
+[AS_HELP_STRING([--enable-swat], [Build the SWAT tool (default=yes)])],
+[
+ case "$enable_swat" in
+ no)
+ SWAT_SBIN_TARGETS=''
+ SWAT_INSTALL_TARGETS=''
+ ;;
+ esac
+])
+
+AC_SUBST(SWAT_SBIN_TARGETS)
+AC_SUBST(SWAT_INSTALL_TARGETS)
+
diff --git a/source3/mainpage.dox b/source3/mainpage.dox
new file mode 100644
index 0000000000..8b72f80462
--- /dev/null
+++ b/source3/mainpage.dox
@@ -0,0 +1,7 @@
+/**
+
+@mainpage
+
+@li \ref CodingSuggestions
+
+**/
diff --git a/source3/modules/CP437.c b/source3/modules/CP437.c
new file mode 100644
index 0000000000..96d14b1f02
--- /dev/null
+++ b/source3/modules/CP437.c
@@ -0,0 +1,135 @@
+/*
+ * Conversion table for CP437 charset also known as IBM437
+ *
+ * Copyright (C) Alexander Bokovoy 2003
+ *
+ * Conversion tables are generated using GNU libc 2.2.5's
+ * localedata/charmaps/IBM437 table and source/script/gen-8bit-gap.sh script
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+static const uint16 to_ucs2[256] = {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+ 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+ 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0,
+};
+
+static const struct charset_gap_table from_idx[] = {
+ { 0x0000, 0x007f, 0 },
+ { 0x00a0, 0x00c9, -32 },
+ { 0x00d1, 0x00ff, -39 },
+ { 0x0192, 0x0192, -185 },
+ { 0x0393, 0x0398, -697 },
+ { 0x03a3, 0x03a9, -707 },
+ { 0x03b1, 0x03b5, -714 },
+ { 0x03c0, 0x03c6, -724 },
+ { 0x207f, 0x207f, -8076 },
+ { 0x20a7, 0x20a7, -8115 },
+ { 0x2219, 0x221e, -8484 },
+ { 0x2229, 0x2229, -8494 },
+ { 0x2248, 0x2248, -8524 },
+ { 0x2261, 0x2265, -8548 },
+ { 0x2310, 0x2310, -8718 },
+ { 0x2320, 0x2321, -8733 },
+ { 0x2500, 0x2502, -9211 },
+ { 0x250c, 0x251c, -9220 },
+ { 0x2524, 0x2524, -9227 },
+ { 0x252c, 0x252c, -9234 },
+ { 0x2534, 0x2534, -9241 },
+ { 0x253c, 0x253c, -9248 },
+ { 0x2550, 0x256c, -9267 },
+ { 0x2580, 0x2593, -9286 },
+ { 0x25a0, 0x25a0, -9298 },
+ { 0xffff, 0xffff, 0 }
+};
+
+static const unsigned char from_ucs2[] = {
+
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0xff, 0xad, 0x9b, 0x9c, 0x00, 0x9d, 0x00, 0x00,
+ 0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00,
+ 0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa,
+ 0x00, 0x00, 0xa7, 0xaf, 0xac, 0xab, 0x00, 0xa8,
+ 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x80,
+ 0x00, 0x90, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x99,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00,
+ 0xe1, 0x85, 0xa0, 0x83, 0x00, 0x84, 0x86, 0x91,
+ 0x87, 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c,
+ 0x8b, 0x00, 0xa4, 0x95, 0xa2, 0x93, 0x00, 0x94,
+ 0xf6, 0x00, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00,
+ 0x98, 0x9f, 0xe2, 0x00, 0x00, 0x00, 0x00, 0xe9,
+ 0xe4, 0x00, 0x00, 0xe8, 0x00, 0x00, 0xea, 0xe0,
+ 0x00, 0x00, 0xeb, 0xee, 0xe3, 0x00, 0x00, 0xe5,
+ 0xe7, 0x00, 0xed, 0xfc, 0x9e, 0xf9, 0xfb, 0x00,
+ 0x00, 0x00, 0xec, 0xef, 0xf7, 0xf0, 0x00, 0x00,
+ 0xf3, 0xf2, 0xa9, 0xf4, 0xf5, 0xc4, 0x00, 0xb3,
+ 0xda, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00,
+ 0xc0, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00,
+ 0xc3, 0xb4, 0xc2, 0xc1, 0xc5, 0xcd, 0xba, 0xd5,
+ 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, 0xd4, 0xd3, 0xc8,
+ 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, 0xcc, 0xb5, 0xb6,
+ 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, 0xd0, 0xca, 0xd8,
+ 0xd7, 0xce, 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00,
+ 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00,
+ 0x00, 0x00, 0xde, 0xb0, 0xb1, 0xb2, 0xfe,
+};
+
+SMB_GENERATE_CHARSET_MODULE_8_BIT_GAP(CP437)
diff --git a/source3/modules/CP850.c b/source3/modules/CP850.c
new file mode 100644
index 0000000000..40730c0d8d
--- /dev/null
+++ b/source3/modules/CP850.c
@@ -0,0 +1,121 @@
+/*
+ * Conversion table for CP850 charset also known as IBM850.
+ *
+ * Copyright (C) Alexander Bokovoy 2003
+ *
+ * Conversion tables are generated using GNU libc 2.2.5's
+ * localedata/charmaps/IBM850 table and source/script/gen-8bit-gap.sh script
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+static const uint16 to_ucs2[256] = {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+ 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE,
+ 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
+ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
+ 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
+ 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+ 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0,
+};
+
+static const struct charset_gap_table from_idx[] = {
+ /* start, end, idx */
+ { 0x0000, 0x007f, 0 },
+ { 0x00a0, 0x00ff, -32 },
+ { 0x0131, 0x0131, -81 },
+ { 0x0192, 0x0192, -177 },
+ { 0x2017, 0x2017, -7989 },
+ { 0x2500, 0x2502, -9245 },
+ { 0x250c, 0x251c, -9254 },
+ { 0x2524, 0x2524, -9261 },
+ { 0x252c, 0x252c, -9268 },
+ { 0x2534, 0x2534, -9275 },
+ { 0x253c, 0x253c, -9282 },
+ { 0x2550, 0x256c, -9301 },
+ { 0x2580, 0x2588, -9320 },
+ { 0x2591, 0x2593, -9328 },
+ { 0x25a0, 0x25a0, -9340 },
+ { 0xffff, 0xffff, 0 }
+};
+static const unsigned char from_ucs2[] = {
+
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0xff, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5,
+ 0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee,
+ 0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa,
+ 0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8,
+ 0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80,
+ 0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8,
+ 0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e,
+ 0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1,
+ 0x85, 0xa0, 0x83, 0xc6, 0x84, 0x86, 0x91, 0x87,
+ 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b,
+ 0xd0, 0xa4, 0x95, 0xa2, 0x93, 0xe4, 0x94, 0xf6,
+ 0x9b, 0x97, 0xa3, 0x96, 0x81, 0xec, 0xe7, 0x98,
+ 0xd5, 0x9f, 0xf2, 0xc4, 0x00, 0xb3, 0xda, 0x00,
+ 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00,
+ 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0xc3, 0xb4,
+ 0xc2, 0xc1, 0xc5, 0xcd, 0xba, 0x00, 0x00, 0xc9,
+ 0x00, 0x00, 0xbb, 0x00, 0x00, 0xc8, 0x00, 0x00,
+ 0xbc, 0x00, 0x00, 0xcc, 0x00, 0x00, 0xb9, 0x00,
+ 0x00, 0xcb, 0x00, 0x00, 0xca, 0x00, 0x00, 0xce,
+ 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00,
+ 0xdb, 0xb0, 0xb1, 0xb2, 0xfe,
+};
+
+SMB_GENERATE_CHARSET_MODULE_8_BIT_GAP(CP850)
+
diff --git a/source3/modules/README-gpfs-acl.txt b/source3/modules/README-gpfs-acl.txt
new file mode 100644
index 0000000000..49f3259c1e
--- /dev/null
+++ b/source3/modules/README-gpfs-acl.txt
@@ -0,0 +1,82 @@
+This patch has been taken against SAMBA_3_0 Release 20028.
+
+The patch basically moves the GPFS-ACL functionalities into the new GPFS VFS module( vfs_gpfs ).
+
+Please read SAMBA_3_0/source/modules/README.nfs4acls.txt - generalised README file on Samba support for NFS4-ACLS.
+This README file is specific for GPFS only.
+
+Configuring GPFS ACL support
+===============================
+
+Binary: (default install path is [samba]/lib/vfs/)
+- gpfs.so
+
+Its compiled by default, no additional configure option needed.
+
+To enable/use/load this module, include "vfs objects = gpfs" in the smb.conf file under concerned share-name.
+
+Example of smb.conf:
+
+[smbtest]
+path = /gpfs-test
+vfs objects = gpfs
+nfs4: mode = special
+nfs4: chown = yes
+nfs4: acedup = merge
+
+Adding "vfs objects = gpfs" to a share should be done only in case when NFS4 is really supported by the filesystem.
+(Otherwise you may get performance loss.)
+
+==================================================
+Below are some limitations listed for this module:
+==================================================
+1. When a child file or child directory is created, the results are a bit different from windows as specified below:
+
+Eg: Prent directory is set to have 2 ACES - full access for owner and everyone
+
+Default ACL for Windows: 2 aces: allow ACE for owner and everyone
+Default ACL for GPFS: 6 aces: allow and deny ACEs for owner, group and everyone
+
+The below mentioned inheritance flags and its combinations are applied only to the owner ACE and not to everyone ACE
+
+"fi"------>File Inherit
+"di"------>Directory Inherit
+"oi"------>Inherit Only
+
+
+Parent dir: no inheritance flag set
+ Windows: index=0: GPFS(special mode): index=0: GPFS(simple mode): index=0:
+child File: default acl: 2 aces child file: default acl: 6 aces child file: default acl: 6 aces
+child dir: default acl: 2 aces child dir: default acl: 6 aces child dir: default acl: 6 aces
+
+
+Parent dir: "fi" flag set
+ Windows: index=1: GPFS(special mode): index=1: GPFS(simple mode): index=1:
+child file: no flag set child file: "fi" flag set child file: default acl: 6 aces
+child dir: "fioi" flag set child dir: "fi" flag set child dir: "fi" flag set
+
+
+Parent dir: "di" flag set
+ Windows: index=2: GPFS(special mode): index=2: GPFS(simple mode): index=2:
+child file: default acl: 2 aces child file: default acl: 6 aces child file: default acl: 6 aces
+
+
+Parent dir: "fidi" flag set
+ Windows: index=3: GPFS(special mode): index=3: GPFS(simple mode): index=3:
+child file: no flag set child file: "fidi" flag set child file: default acl: 6 aces
+
+
+Parent dir: "fioi" flag set
+ Windows: index=4: GPFS(special mode): index=4: GPFS(simple mode): index=4:
+child file: no flag set child file: "fi" flag set child file: default acl: 6 aces
+child dir: "fioi" flag set child dir: "fi" flag set child dir: "fi" flag set
+
+
+Parent dir: "dioi" flag set
+ Windows: index=5: GPFS(special mode): index=5: GPFS(simple mode): index=5:
+child file: default acl: 2 aces child file: default acl: 6 aces child file: default acl: 6 aces
+
+
+Parent dir: "fidioi" flag set
+ Windows: index=6: GPFS(special mode): index=6: GPFS(simple mode): index=6:
+child file: no flag set child file: "fidi" flag set child file: default acl: 6 aces
diff --git a/source3/modules/README.nfs4acls.txt b/source3/modules/README.nfs4acls.txt
new file mode 100644
index 0000000000..1cb08877d3
--- /dev/null
+++ b/source3/modules/README.nfs4acls.txt
@@ -0,0 +1,82 @@
+Configuring NFS4 ACLs in Samba3
+===============================
+Created: Peter Somogyi, 2006-JUN-06
+Last modified: Peter Somogyi, 2006-JUL-20
+Revision no.: 4
+-------------------------------
+
+
+Parameters in smb.conf:
+=======================
+
+Each parameter must have a prefix "nfs4:".
+Each one affects the behaviour only when _setting_ an acl on a file/dir:
+
+mode = [simple|special]
+- simple: don't use OWNER@ and GROUP@ special IDs in ACEs. - default
+- special: use OWNER@ and GROUP@ special IDs in ACEs instead of simple user&group ids.
+Note: EVERYONE@ is always processed (if found such an ACE).
+Note2: special mode will have side effect when _only_ chown is performed. Later this may be worked out.
+
+Use "simple" mode when the share is used mainly by windows users and unix side is not significant. You will loose unix bits in this case.
+It's strongly advised setting "store dos attributes = yes" in smb.conf.
+
+chown = [true|false]
+- true => enable changing owner and group - default.
+- false => disable support for changing owner or group
+
+acedup = [dontcare|reject|ignore|merge]
+- dontcare: copy ACEs as they come, don't care with "duplicate" records. Default.
+- reject: stop operation, exit acl setter operation with an error
+- ignore: don't include the second matching ACE
+- merge: OR 2 ace.flag fields and 2 ace.mask fields of the 2 duplicate ACEs into 1 ACE
+
+Two ACEs are considered here "duplicate" when their type and id fields are matching.
+
+Example:
+
+[smbtest]
+path = /tests/psomogyi/smbtest
+writable = yes
+vfs objects = aixacl2
+nfs4: mode = special
+nfs4: chown = yes
+nfs4: acedup = merge
+
+Configuring AIX ACL support
+==============================
+
+Binaries: (default install path is [samba]/lib/vfs/)
+- aixacl.so: provides AIXC ACL support only, can be compiled and works on all AIX platforms
+- aixacl2.so: provides AIXC and JFS2-NFS4 ACL support, can be compiled and works only under AIX 5.3 and newer.
+NFS4 acl currently has support only under JFS2 (ext. attr. format must be set to v2).
+aixacl2.so always detects support for NFS4 acls and redirects to POSIX ACL handling automatically when NFS4 is not supported for a path.
+
+Adding "vfs objects = aixacl2" to a share should be done only in case when NFS4 is really supported by the filesystem.
+(Otherwise you may get performance loss.)
+
+For configuration see also the example above.
+
+General notes
+=============
+
+NFS4 handling logic is separated from AIX/jfs2 ACL parsing.
+
+Samba and its VFS modules dosn't reorder ACEs. Windows clients do that (and the smbcacl tool). MSDN also says deny ACEs must come first.
+NFS4 ACL's validity is checked by the system API, not by Samba.
+NFS4 ACL rights are enforced by the OS or filesystem, not by Samba.
+
+The flag INHERITED_ACE is never set (not required, as doesn't do WinNT/98/me, only since Win2k).
+Win2k GUI behaves strangely when detecting inheritance (sometimes it doesn't detect,
+but after adding an ace it shows that - it's some GUI error).
+
+Unknown (unmappable) SIDs are not accepted.
+
+TODOs
+=====
+- Creator Owner & Group SID handling (same way as posix)
+- the 4 generic rights bits support (GENERIC_RIGHT_READ_ACCESS, WRITE, EXEC, ALL)
+- chown & no ACL, but we have ONWER@ and GROUP@
+- DIALUP, ANONYMOUS, ... builtin SIDs
+- audit & alarm support - in theory it's forwarded so it should work, but currently there's no platform which supports them to test
+- support for a real NFS4 client (we don't have an accepted API yet)
diff --git a/source3/modules/charset_macosxfs.c b/source3/modules/charset_macosxfs.c
new file mode 100644
index 0000000000..baf2a0071c
--- /dev/null
+++ b/source3/modules/charset_macosxfs.c
@@ -0,0 +1,601 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba charset module for Mac OS X/Darwin
+ Copyright (C) Benjamin Riefenstahl 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * modules/charset_macosxfs.c
+ *
+ * A Samba charset module to use on Mac OS X/Darwin as the filesystem
+ * and display encoding.
+ *
+ * Actually two implementations are provided here. The default
+ * implementation is based on the official CFString API. The other is
+ * based on internal CFString APIs as defined in the OpenDarwin
+ * source.
+ */
+
+#include "includes.h"
+
+/*
+ * Include OS frameworks. These are only needed in this module.
+ */
+#include <CoreFoundation/CFString.h>
+
+/*
+ * See if autoconf has found us the internal headers in some form.
+ */
+#if HAVE_COREFOUNDATION_CFSTRINGENCODINGCONVERTER_H
+# include <CoreFoundation/CFStringEncodingConverter.h>
+# include <CoreFoundation/CFUnicodePrecomposition.h>
+# define USE_INTERNAL_API 1
+#elif HAVE_CFSTRINGENCODINGCONVERTER_H
+# include <CFStringEncodingConverter.h>
+# include <CFUnicodePrecomposition.h>
+# define USE_INTERNAL_API 1
+#endif
+
+/*
+ * Compile time configuration: Do we want debug output?
+ */
+/* #define DEBUG_STRINGS 1 */
+
+/*
+ * A simple, but efficient memory provider for our buffers.
+ */
+static inline void *resize_buffer (void *buffer, size_t *size, size_t newsize)
+{
+ if (newsize > *size) {
+ *size = newsize + 128;
+ buffer = SMB_REALLOC(buffer, *size);
+ }
+ return buffer;
+}
+
+/*
+ * While there is a version of OpenDarwin for intel, the usual case is
+ * big-endian PPC. So we need byte swapping to handle the
+ * little-endian byte order of the network protocol. We also need an
+ * additional dynamic buffer to do this work for incoming data blocks,
+ * because we have to consider the original data as constant.
+ *
+ * We abstract the differences away by providing a simple facade with
+ * these functions/macros:
+ *
+ * le_to_native(dst,src,len)
+ * native_to_le(cp,len)
+ * set_ucbuffer_with_le(buffer,bufsize,data,size)
+ * set_ucbuffer_with_le_copy(buffer,bufsize,data,size,reserve)
+ */
+#ifdef WORDS_BIGENDIAN
+
+static inline void swap_bytes (char * dst, const char * src, size_t len)
+{
+ const char *srcend = src + len;
+ while (src < srcend) {
+ dst[0] = src[1];
+ dst[1] = src[0];
+ dst += 2;
+ src += 2;
+ }
+}
+static inline void swap_bytes_inplace (char * cp, size_t len)
+{
+ char temp;
+ char *end = cp + len;
+ while (cp < end) {
+ temp = cp[1];
+ cp[1] = cp[0];
+ cp[0] = temp;
+ cp += 2;
+ }
+}
+
+#define le_to_native(dst,src,len) swap_bytes(dst,src,len)
+#define native_to_le(cp,len) swap_bytes_inplace(cp,len)
+#define set_ucbuffer_with_le(buffer,bufsize,data,size) \
+ set_ucbuffer_with_le_copy(buffer,bufsize,data,size,0)
+
+#else /* ! WORDS_BIGENDIAN */
+
+#define le_to_native(dst,src,len) memcpy(dst,src,len)
+#define native_to_le(cp,len) /* nothing */
+#define set_ucbuffer_with_le(buffer,bufsize,data,size) \
+ (((void)(bufsize)),(UniChar*)(data))
+
+#endif
+
+static inline UniChar *set_ucbuffer_with_le_copy (
+ UniChar *buffer, size_t *bufsize,
+ const void *data, size_t size, size_t reserve)
+{
+ buffer = resize_buffer(buffer, bufsize, size+reserve);
+ le_to_native((char*)buffer,data,size);
+ return buffer;
+}
+
+
+/*
+ * A simple hexdump function for debugging error conditions.
+ */
+#define debug_out(s) DEBUG(0,(s))
+
+#ifdef DEBUG_STRINGS
+
+static void hexdump( const char * label, const char * s, size_t len )
+{
+ size_t restlen = len;
+ debug_out("<<<<<<<\n");
+ debug_out(label);
+ debug_out("\n");
+ while (restlen > 0) {
+ char line[100];
+ size_t i, j;
+ char * d = line;
+#undef sprintf
+ d += sprintf(d, "%04X ", (unsigned)(len-restlen));
+ *d++ = ' ';
+ for( i = 0; i<restlen && i<8; ++i ) {
+ d += sprintf(d, "%02X ", ((unsigned)s[i]) & 0xFF);
+ }
+ for( j = i; j<8; ++j ) {
+ d += sprintf(d, " ");
+ }
+ *d++ = ' ';
+ for( i = 8; i<restlen && i<16; ++i ) {
+ d += sprintf(d, "%02X ", ((unsigned)s[i]) & 0xFF);
+ }
+ for( j = i; j<16; ++j ) {
+ d += sprintf(d, " ");
+ }
+ *d++ = ' ';
+ for( i = 0; i<restlen && i<16; ++i ) {
+ if(s[i] < ' ' || s[i] >= 0x7F || !isprint(s[i]))
+ *d++ = '.';
+ else
+ *d++ = s[i];
+ }
+ *d++ = '\n';
+ *d = 0;
+ restlen -= i;
+ s += i;
+ debug_out(line);
+ }
+ debug_out(">>>>>>>\n");
+}
+
+#else /* !DEBUG_STRINGS */
+
+#define hexdump(label,s,len) /* nothing */
+
+#endif
+
+
+#if !USE_INTERNAL_API
+
+/*
+ * An implementation based on documented Mac OS X APIs.
+ *
+ * This does a certain amount of memory management, creating and
+ * manipulating CFString objects. We try to minimize the impact by
+ * keeping those objects around and re-using them. We also use
+ * external backing store for the CFStrings where this is possible and
+ * benficial.
+ *
+ * The Unicode normalizations forms available at this level are
+ * generic, not specifically for the file system. So they may not be
+ * perfect fits.
+ */
+static size_t macosxfs_encoding_pull(
+ void *cd, /* Encoder handle */
+ char **inbuf, size_t *inbytesleft, /* Script string */
+ char **outbuf, size_t *outbytesleft) /* UTF-16-LE string */
+{
+ static const int script_code = kCFStringEncodingUTF8;
+ static CFMutableStringRef cfstring = NULL;
+ size_t outsize;
+ CFRange range;
+
+ (void) cd; /* UNUSED */
+
+ if (0 == *inbytesleft) {
+ return 0;
+ }
+
+ if (NULL == cfstring) {
+ /*
+ * A version with an external backing store as in the
+ * push function should have been more efficient, but
+ * testing shows, that it is actually slower (!).
+ * Maybe kCFAllocatorDefault gets shortcut evaluation
+ * internally, while kCFAllocatorNull doesn't.
+ */
+ cfstring = CFStringCreateMutable(kCFAllocatorDefault,0);
+ }
+
+ /*
+ * Three methods of appending to a CFString, choose the most
+ * efficient.
+ */
+ if (0 == (*inbuf)[*inbytesleft-1]) {
+ CFStringAppendCString(cfstring, *inbuf, script_code);
+ } else if (*inbytesleft <= 255) {
+ Str255 buffer;
+ buffer[0] = *inbytesleft;
+ memcpy(buffer+1, *inbuf, buffer[0]);
+ CFStringAppendPascalString(cfstring, buffer, script_code);
+ } else {
+ /*
+ * We would like to use a fixed buffer and a loop
+ * here, but than we can't garantee that the input is
+ * well-formed UTF-8, as we are supposed to do.
+ */
+ static char *buffer = NULL;
+ static size_t buflen = 0;
+ buffer = resize_buffer(buffer, &buflen, *inbytesleft+1);
+ memcpy(buffer, *inbuf, *inbytesleft);
+ buffer[*inbytesleft] = 0;
+ CFStringAppendCString(cfstring, *inbuf, script_code);
+ }
+
+ /*
+ * Compose characters, using the non-canonical composition
+ * form.
+ */
+ CFStringNormalize(cfstring, kCFStringNormalizationFormC);
+
+ outsize = CFStringGetLength(cfstring);
+ range = CFRangeMake(0,outsize);
+
+ if (outsize == 0) {
+ /*
+ * HACK: smbd/mangle_hash2.c:is_legal_name() expects
+ * errors here. That function will always pass 2
+ * characters. smbd/open.c:check_for_pipe() cuts a
+ * patchname to 10 characters blindly. Suppress the
+ * debug output in those cases.
+ */
+ if(2 != *inbytesleft && 10 != *inbytesleft) {
+ debug_out("String conversion: "
+ "An unknown error occurred\n");
+ hexdump("UTF8->UTF16LE (old) input",
+ *inbuf, *inbytesleft);
+ }
+ errno = EILSEQ; /* Not sure, but this is what we have
+ * actually seen. */
+ return -1;
+ }
+ if (outsize*2 > *outbytesleft) {
+ CFStringDelete(cfstring, range);
+ debug_out("String conversion: "
+ "Output buffer too small\n");
+ hexdump("UTF8->UTF16LE (old) input",
+ *inbuf, *inbytesleft);
+ errno = E2BIG;
+ return -1;
+ }
+
+ CFStringGetCharacters(cfstring, range, (UniChar*)*outbuf);
+ CFStringDelete(cfstring, range);
+
+ native_to_le(*outbuf, outsize*2);
+
+ /*
+ * Add a converted null byte, if the CFString conversions
+ * prevented that until now.
+ */
+ if (0 == (*inbuf)[*inbytesleft-1] &&
+ (0 != (*outbuf)[outsize*2-1] || 0 != (*outbuf)[outsize*2-2])) {
+
+ if ((outsize*2+2) > *outbytesleft) {
+ debug_out("String conversion: "
+ "Output buffer too small\n");
+ hexdump("UTF8->UTF16LE (old) input",
+ *inbuf, *inbytesleft);
+ errno = E2BIG;
+ return -1;
+ }
+
+ (*outbuf)[outsize*2] = (*outbuf)[outsize*2+1] = 0;
+ outsize += 2;
+ }
+
+ *inbuf += *inbytesleft;
+ *inbytesleft = 0;
+ *outbuf += outsize*2;
+ *outbytesleft -= outsize*2;
+
+ return 0;
+}
+
+static size_t macosxfs_encoding_push(
+ void *cd, /* Encoder handle */
+ char **inbuf, size_t *inbytesleft, /* UTF-16-LE string */
+ char **outbuf, size_t *outbytesleft) /* Script string */
+{
+ static const int script_code = kCFStringEncodingUTF8;
+ static CFMutableStringRef cfstring = NULL;
+ static UniChar *buffer = NULL;
+ static size_t buflen = 0;
+ CFIndex outsize, cfsize, charsconverted;
+
+ (void) cd; /* UNUSED */
+
+ if (0 == *inbytesleft) {
+ return 0;
+ }
+
+ /*
+ * We need a buffer that can hold 4 times the original data,
+ * because that is the theoretical maximum that decomposition
+ * can create currently (in Unicode 4.0).
+ */
+ buffer = set_ucbuffer_with_le_copy(
+ buffer, &buflen, *inbuf, *inbytesleft, 3 * *inbytesleft);
+
+ if (NULL == cfstring) {
+ cfstring = CFStringCreateMutableWithExternalCharactersNoCopy(
+ kCFAllocatorDefault,
+ buffer, *inbytesleft/2, buflen/2,
+ kCFAllocatorNull);
+ } else {
+ CFStringSetExternalCharactersNoCopy(
+ cfstring,
+ buffer, *inbytesleft/2, buflen/2);
+ }
+
+ /*
+ * Decompose characters, using the non-canonical decomposition
+ * form.
+ *
+ * NB: This isn't exactly what HFS+ wants (see note on
+ * kCFStringEncodingUseHFSPlusCanonical in
+ * CFStringEncodingConverter.h), but AFAIK it's the best that
+ * the official API can do.
+ */
+ CFStringNormalize(cfstring, kCFStringNormalizationFormD);
+
+ cfsize = CFStringGetLength(cfstring);
+ charsconverted = CFStringGetBytes(
+ cfstring, CFRangeMake(0,cfsize),
+ script_code, 0, False,
+ *outbuf, *outbytesleft, &outsize);
+
+ if (0 == charsconverted) {
+ debug_out("String conversion: "
+ "Buffer too small or not convertable\n");
+ hexdump("UTF16LE->UTF8 (old) input",
+ *inbuf, *inbytesleft);
+ errno = EILSEQ; /* Probably more likely. */
+ return -1;
+ }
+
+ /*
+ * Add a converted null byte, if the CFString conversions
+ * prevented that until now.
+ */
+ if (0 == (*inbuf)[*inbytesleft-1] && 0 == (*inbuf)[*inbytesleft-2] &&
+ (0 != (*outbuf)[outsize-1])) {
+
+ if (((size_t)outsize+1) > *outbytesleft) {
+ debug_out("String conversion: "
+ "Output buffer too small\n");
+ hexdump("UTF16LE->UTF8 (old) input",
+ *inbuf, *inbytesleft);
+ errno = E2BIG;
+ return -1;
+ }
+
+ (*outbuf)[outsize] = 0;
+ ++outsize;
+ }
+
+ *inbuf += *inbytesleft;
+ *inbytesleft = 0;
+ *outbuf += outsize;
+ *outbytesleft -= outsize;
+
+ return 0;
+}
+
+#else /* USE_INTERNAL_API */
+
+/*
+ * An implementation based on internal code as known from the
+ * OpenDarwin CVS.
+ *
+ * This code doesn't need much memory management because it uses
+ * functions that operate on the raw memory directly.
+ *
+ * The push routine here is faster and more compatible with HFS+ than
+ * the other implementation above. The pull routine is only faster
+ * for some strings, slightly slower for others. The pull routine
+ * looses because it has to iterate over the data twice, once to
+ * decode UTF-8 and than to do the character composition required by
+ * Windows.
+ */
+static size_t macosxfs_encoding_pull(
+ void *cd, /* Encoder handle */
+ char **inbuf, size_t *inbytesleft, /* Script string */
+ char **outbuf, size_t *outbytesleft) /* UTF-16-LE string */
+{
+ static const int script_code = kCFStringEncodingUTF8;
+ UInt32 srcCharsUsed = 0;
+ UInt32 dstCharsUsed = 0;
+ UInt32 result;
+ uint32_t dstDecomposedUsed = 0;
+ uint32_t dstPrecomposedUsed = 0;
+
+ (void) cd; /* UNUSED */
+
+ if (0 == *inbytesleft) {
+ return 0;
+ }
+
+ result = CFStringEncodingBytesToUnicode(
+ script_code, kCFStringEncodingComposeCombinings,
+ *inbuf, *inbytesleft, &srcCharsUsed,
+ (UniChar*)*outbuf, *outbytesleft, &dstCharsUsed);
+
+ switch(result) {
+ case kCFStringEncodingConversionSuccess:
+ if (*inbytesleft == srcCharsUsed)
+ break;
+ else
+ ; /*fall through*/
+ case kCFStringEncodingInsufficientOutputBufferLength:
+ debug_out("String conversion: "
+ "Output buffer too small\n");
+ hexdump("UTF8->UTF16LE (new) input",
+ *inbuf, *inbytesleft);
+ errno = E2BIG;
+ return -1;
+ case kCFStringEncodingInvalidInputStream:
+ /*
+ * HACK: smbd/mangle_hash2.c:is_legal_name() expects
+ * errors here. That function will always pass 2
+ * characters. smbd/open.c:check_for_pipe() cuts a
+ * patchname to 10 characters blindly. Suppress the
+ * debug output in those cases.
+ */
+ if(2 != *inbytesleft && 10 != *inbytesleft) {
+ debug_out("String conversion: "
+ "Invalid input sequence\n");
+ hexdump("UTF8->UTF16LE (new) input",
+ *inbuf, *inbytesleft);
+ }
+ errno = EILSEQ;
+ return -1;
+ case kCFStringEncodingConverterUnavailable:
+ debug_out("String conversion: "
+ "Unknown encoding\n");
+ hexdump("UTF8->UTF16LE (new) input",
+ *inbuf, *inbytesleft);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * It doesn't look like CFStringEncodingBytesToUnicode() can
+ * produce precomposed characters (flags=ComposeCombinings
+ * doesn't do it), so we need another pass over the data here.
+ * We can do this in-place, as the string can only get
+ * shorter.
+ *
+ * (Actually in theory there should be an internal
+ * decomposition and reordering before the actual composition
+ * step. But we should be able to rely on that we always get
+ * fully decomposed strings for input, so this can't create
+ * problems in reality.)
+ */
+ CFUniCharPrecompose(
+ (const UTF16Char *)*outbuf, dstCharsUsed, &dstDecomposedUsed,
+ (UTF16Char *)*outbuf, dstCharsUsed, &dstPrecomposedUsed);
+
+ native_to_le(*outbuf, dstPrecomposedUsed*2);
+
+ *inbuf += srcCharsUsed;
+ *inbytesleft -= srcCharsUsed;
+ *outbuf += dstPrecomposedUsed*2;
+ *outbytesleft -= dstPrecomposedUsed*2;
+
+ return 0;
+}
+
+static size_t macosxfs_encoding_push(
+ void *cd, /* Encoder handle */
+ char **inbuf, size_t *inbytesleft, /* UTF-16-LE string */
+ char **outbuf, size_t *outbytesleft) /* Script string */
+{
+ static const int script_code = kCFStringEncodingUTF8;
+ static UniChar *buffer = NULL;
+ static size_t buflen = 0;
+ UInt32 srcCharsUsed=0, dstCharsUsed=0, result;
+
+ (void) cd; /* UNUSED */
+
+ if (0 == *inbytesleft) {
+ return 0;
+ }
+
+ buffer = set_ucbuffer_with_le(
+ buffer, &buflen, *inbuf, *inbytesleft);
+
+ result = CFStringEncodingUnicodeToBytes(
+ script_code, kCFStringEncodingUseHFSPlusCanonical,
+ buffer, *inbytesleft/2, &srcCharsUsed,
+ *outbuf, *outbytesleft, &dstCharsUsed);
+
+ switch(result) {
+ case kCFStringEncodingConversionSuccess:
+ if (*inbytesleft/2 == srcCharsUsed)
+ break;
+ else
+ ; /*fall through*/
+ case kCFStringEncodingInsufficientOutputBufferLength:
+ debug_out("String conversion: "
+ "Output buffer too small\n");
+ hexdump("UTF16LE->UTF8 (new) input",
+ *inbuf, *inbytesleft);
+ errno = E2BIG;
+ return -1;
+ case kCFStringEncodingInvalidInputStream:
+ /*
+ * HACK: smbd/open.c:check_for_pipe():is_legal_name()
+ * cuts a pathname to 10 characters blindly. Suppress
+ * the debug output in those cases.
+ */
+ if(10 != *inbytesleft) {
+ debug_out("String conversion: "
+ "Invalid input sequence\n");
+ hexdump("UTF16LE->UTF8 (new) input",
+ *inbuf, *inbytesleft);
+ }
+ errno = EILSEQ;
+ return -1;
+ case kCFStringEncodingConverterUnavailable:
+ debug_out("String conversion: "
+ "Unknown encoding\n");
+ hexdump("UTF16LE->UTF8 (new) input",
+ *inbuf, *inbytesleft);
+ errno = EINVAL;
+ return -1;
+ }
+
+ *inbuf += srcCharsUsed*2;
+ *inbytesleft -= srcCharsUsed*2;
+ *outbuf += dstCharsUsed;
+ *outbytesleft -= dstCharsUsed;
+
+ return 0;
+}
+
+#endif /* USE_INTERNAL_API */
+
+/*
+ * For initialization, actually install the encoding as "macosxfs".
+ */
+static struct charset_functions macosxfs_encoding_functions = {
+ "MACOSXFS", macosxfs_encoding_pull, macosxfs_encoding_push
+};
+
+NTSTATUS charset_macosxfs_init(void)
+{
+ return smb_register_charset(&macosxfs_encoding_functions);
+}
+
+/* eof */
diff --git a/source3/modules/developer.c b/source3/modules/developer.c
new file mode 100644
index 0000000000..37019256db
--- /dev/null
+++ b/source3/modules/developer.c
@@ -0,0 +1,131 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba module with developer tools
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jelmer Vernooij 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static struct {
+ char from;
+ char *to;
+ int len;
+} weird_table[] = {
+ {'q', "^q^", 3},
+ {'Q', "^Q^", 3},
+ {0, NULL}
+};
+
+static size_t weird_pull(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+ int i;
+ int done = 0;
+ for (i=0;weird_table[i].from;i++) {
+ if (strncmp((*inbuf),
+ weird_table[i].to,
+ weird_table[i].len) == 0) {
+ if (*inbytesleft < weird_table[i].len) {
+ DEBUG(0,("ERROR: truncated weird string\n"));
+ /* smb_panic("weird_pull"); */
+
+ } else {
+ (*outbuf)[0] = weird_table[i].from;
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= weird_table[i].len;
+ (*outbytesleft) -= 2;
+ (*inbuf) += weird_table[i].len;
+ (*outbuf) += 2;
+ done = 1;
+ break;
+ }
+ }
+ }
+ if (done) continue;
+ (*outbuf)[0] = (*inbuf)[0];
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= 1;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 1;
+ (*outbuf) += 2;
+ }
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t weird_push(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int ir_count=0;
+
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ int i;
+ int done=0;
+ for (i=0;weird_table[i].from;i++) {
+ if ((*inbuf)[0] == weird_table[i].from &&
+ (*inbuf)[1] == 0) {
+ if (*outbytesleft < weird_table[i].len) {
+ DEBUG(0,("No room for weird character\n"));
+ /* smb_panic("weird_push"); */
+ } else {
+ memcpy(*outbuf, weird_table[i].to,
+ weird_table[i].len);
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= weird_table[i].len;
+ (*inbuf) += 2;
+ (*outbuf) += weird_table[i].len;
+ done = 1;
+ break;
+ }
+ }
+ }
+ if (done) continue;
+
+ (*outbuf)[0] = (*inbuf)[0];
+ if ((*inbuf)[1]) ir_count++;
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 1;
+ (*inbuf) += 2;
+ (*outbuf) += 1;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return ir_count;
+}
+
+struct charset_functions weird_functions = {"WEIRD", weird_pull, weird_push};
+
+int charset_weird_init(void)
+{
+ smb_register_charset(&weird_functions);
+ return True;
+}
diff --git a/source3/modules/getdate.c b/source3/modules/getdate.c
new file mode 100644
index 0000000000..149a3e1ab9
--- /dev/null
+++ b/source3/modules/getdate.c
@@ -0,0 +1,2458 @@
+/* A Bison parser, made by GNU Bison 1.875a. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ tAGO = 258,
+ tDST = 259,
+ tDAY = 260,
+ tDAY_UNIT = 261,
+ tDAYZONE = 262,
+ tHOUR_UNIT = 263,
+ tLOCAL_ZONE = 264,
+ tMERIDIAN = 265,
+ tMINUTE_UNIT = 266,
+ tMONTH = 267,
+ tMONTH_UNIT = 268,
+ tSEC_UNIT = 269,
+ tYEAR_UNIT = 270,
+ tZONE = 271,
+ tSNUMBER = 272,
+ tUNUMBER = 273
+ };
+#endif
+#define tAGO 258
+#define tDST 259
+#define tDAY 260
+#define tDAY_UNIT 261
+#define tDAYZONE 262
+#define tHOUR_UNIT 263
+#define tLOCAL_ZONE 264
+#define tMERIDIAN 265
+#define tMINUTE_UNIT 266
+#define tMONTH 267
+#define tMONTH_UNIT 268
+#define tSEC_UNIT 269
+#define tYEAR_UNIT 270
+#define tZONE 271
+#define tSNUMBER 272
+#define tUNUMBER 273
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 1 "getdate.y"
+
+/* Parse a string into an internal time stamp.
+ Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+/* Originally written by Steven M. Bellovin <smb@research.att.com> while
+ at the University of North Carolina at Chapel Hill. Later tweaked by
+ a couple of people on Usenet. Completely overhauled by Rich $alz
+ <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.
+
+ Modified by Paul Eggert <eggert@twinsun.com> in August 1999 to do
+ the right thing about local DST. Unlike previous versions, this
+ version is reentrant. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+# ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+# endif
+#endif
+
+/* Since the code of getdate.y is not included in the Emacs executable
+ itself, there is no need to #define static in this file. Even if
+ the code were included in the Emacs executable, it probably
+ wouldn't do any harm to #undef it here; this will only cause
+ problems if we try to write to a static variable, which I don't
+ think this code needs to do. */
+#ifdef emacs
+# undef static
+#endif
+
+#include <ctype.h>
+#include <string.h>
+
+#if HAVE_STDLIB_H
+# include <stdlib.h> /* for `free'; used by Bison 1.27 */
+#endif
+
+#if STDC_HEADERS || (! defined isascii && ! HAVE_ISASCII)
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) isascii (c)
+#endif
+
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
+#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c))
+#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
+
+/* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
+ - Its arg may be any int or unsigned int; it need not be an unsigned char.
+ - It's guaranteed to evaluate its argument exactly once.
+ - It's typically faster.
+ POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
+ ISDIGIT_LOCALE unless it's important to use the locale's definition
+ of `digit' even when the host does not conform to POSIX. */
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+
+#if STDC_HEADERS || HAVE_STRING_H
+# include <string.h>
+#endif
+
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
+# define __attribute__(x)
+#endif
+
+#ifndef ATTRIBUTE_UNUSED
+# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif
+
+#define EPOCH_YEAR 1970
+#define TM_YEAR_BASE 1900
+
+#define HOUR(x) ((x) * 60)
+
+/* An integer value, and the number of digits in its textual
+ representation. */
+typedef struct
+{
+ int value;
+ int digits;
+} textint;
+
+/* An entry in the lexical lookup table. */
+typedef struct
+{
+ char const *name;
+ int type;
+ int value;
+} table;
+
+/* Meridian: am, pm, or 24-hour style. */
+enum { MERam, MERpm, MER24 };
+
+/* Information passed to and from the parser. */
+typedef struct
+{
+ /* The input string remaining to be parsed. */
+ const char *input;
+
+ /* N, if this is the Nth Tuesday. */
+ int day_ordinal;
+
+ /* Day of week; Sunday is 0. */
+ int day_number;
+
+ /* tm_isdst flag for the local zone. */
+ int local_isdst;
+
+ /* Time zone, in minutes east of UTC. */
+ int time_zone;
+
+ /* Style used for time. */
+ int meridian;
+
+ /* Gregorian year, month, day, hour, minutes, and seconds. */
+ textint year;
+ int month;
+ int day;
+ int hour;
+ int minutes;
+ int seconds;
+
+ /* Relative year, month, day, hour, minutes, and seconds. */
+ int rel_year;
+ int rel_month;
+ int rel_day;
+ int rel_hour;
+ int rel_minutes;
+ int rel_seconds;
+
+ /* Counts of nonterminals of various flavors parsed so far. */
+ int dates_seen;
+ int days_seen;
+ int local_zones_seen;
+ int rels_seen;
+ int times_seen;
+ int zones_seen;
+
+ /* Table of local time zone abbrevations, terminated by a null entry. */
+ table local_time_zone_table[3];
+} parser_control;
+
+#define PC (* (parser_control *) parm)
+#define YYLEX_PARAM parm
+#define YYPARSE_PARAM parm
+
+static int yyerror ();
+static int yylex ();
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 172 "getdate.y"
+typedef union YYSTYPE {
+ int intval;
+ textint textintval;
+} YYSTYPE;
+/* Line 191 of yacc.c. */
+#line 281 "getdate.c"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 214 of yacc.c. */
+#line 293 "getdate.c"
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# if YYSTACK_USE_ALLOCA
+# define YYSTACK_ALLOC alloca
+# else
+# ifndef YYSTACK_USE_ALLOCA
+# if defined (alloca) || defined (_ALLOCA_H)
+# define YYSTACK_ALLOC alloca
+# else
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+# define YYSTACK_ALLOC malloc
+# define YYSTACK_FREE free
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ register YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 52
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 22
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 12
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 54
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 64
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 273
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned char yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 20, 2, 2, 21, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 19, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned char yyprhs[] =
+{
+ 0, 0, 3, 4, 7, 9, 11, 13, 15, 17,
+ 19, 21, 24, 29, 34, 41, 48, 50, 53, 55,
+ 57, 60, 62, 65, 68, 72, 78, 82, 86, 89,
+ 94, 97, 101, 104, 106, 109, 112, 114, 117, 120,
+ 122, 125, 128, 130, 133, 136, 138, 141, 144, 146,
+ 149, 152, 154, 156, 157
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 23, 0, -1, -1, 23, 24, -1, 25, -1, 26,
+ -1, 27, -1, 29, -1, 28, -1, 30, -1, 32,
+ -1, 18, 10, -1, 18, 19, 18, 33, -1, 18,
+ 19, 18, 17, -1, 18, 19, 18, 19, 18, 33,
+ -1, 18, 19, 18, 19, 18, 17, -1, 9, -1,
+ 9, 4, -1, 16, -1, 7, -1, 16, 4, -1,
+ 5, -1, 5, 20, -1, 18, 5, -1, 18, 21,
+ 18, -1, 18, 21, 18, 21, 18, -1, 18, 17,
+ 17, -1, 18, 12, 17, -1, 12, 18, -1, 12,
+ 18, 20, 18, -1, 18, 12, -1, 18, 12, 18,
+ -1, 31, 3, -1, 31, -1, 18, 15, -1, 17,
+ 15, -1, 15, -1, 18, 13, -1, 17, 13, -1,
+ 13, -1, 18, 6, -1, 17, 6, -1, 6, -1,
+ 18, 8, -1, 17, 8, -1, 8, -1, 18, 11,
+ -1, 17, 11, -1, 11, -1, 18, 14, -1, 17,
+ 14, -1, 14, -1, 18, -1, -1, 10, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned short yyrline[] =
+{
+ 0, 188, 188, 190, 194, 196, 198, 200, 202, 204,
+ 206, 210, 217, 224, 232, 239, 251, 253, 258, 260,
+ 262, 267, 272, 277, 285, 290, 310, 317, 325, 330,
+ 336, 341, 350, 359, 363, 365, 367, 369, 371, 373,
+ 375, 377, 379, 381, 383, 385, 387, 389, 391, 393,
+ 395, 397, 402, 439, 440
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "tAGO", "tDST", "tDAY", "tDAY_UNIT",
+ "tDAYZONE", "tHOUR_UNIT", "tLOCAL_ZONE", "tMERIDIAN", "tMINUTE_UNIT",
+ "tMONTH", "tMONTH_UNIT", "tSEC_UNIT", "tYEAR_UNIT", "tZONE", "tSNUMBER",
+ "tUNUMBER", "':'", "','", "'/'", "$accept", "spec", "item", "time",
+ "local_zone", "zone", "day", "date", "rel", "relunit", "number",
+ "o_merid", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 58,
+ 44, 47
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 22, 23, 23, 24, 24, 24, 24, 24, 24,
+ 24, 25, 25, 25, 25, 25, 26, 26, 27, 27,
+ 27, 28, 28, 28, 29, 29, 29, 29, 29, 29,
+ 29, 29, 30, 30, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 32, 33, 33
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 0, 2, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 4, 6, 6, 1, 2, 1, 1,
+ 2, 1, 2, 2, 3, 5, 3, 3, 2, 4,
+ 2, 3, 2, 1, 2, 2, 1, 2, 2, 1,
+ 2, 2, 1, 2, 2, 1, 2, 2, 1, 2,
+ 2, 1, 1, 0, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 2, 0, 1, 21, 42, 19, 45, 16, 48, 0,
+ 39, 51, 36, 18, 0, 52, 3, 4, 5, 6,
+ 8, 7, 9, 33, 10, 22, 17, 28, 20, 41,
+ 44, 47, 38, 50, 35, 23, 40, 43, 11, 46,
+ 30, 37, 49, 34, 0, 0, 0, 32, 0, 27,
+ 31, 26, 53, 24, 29, 54, 13, 0, 12, 0,
+ 53, 25, 15, 14
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yysigned_char yydefgoto[] =
+{
+ -1, 1, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 58
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -17
+static const yysigned_char yypact[] =
+{
+ -17, 0, -17, 1, -17, -17, -17, 19, -17, -14,
+ -17, -17, -17, 32, 26, 14, -17, -17, -17, -17,
+ -17, -17, -17, 27, -17, -17, -17, 22, -17, -17,
+ -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
+ -16, -17, -17, -17, 29, 25, 30, -17, 31, -17,
+ -17, -17, 28, 23, -17, -17, -17, 33, -17, 34,
+ -7, -17, -17, -17
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yysigned_char yypgoto[] =
+{
+ -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
+ -17, -10
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const unsigned char yytable[] =
+{
+ 2, 49, 50, 55, 27, 3, 4, 5, 6, 7,
+ 62, 8, 9, 10, 11, 12, 13, 14, 15, 35,
+ 36, 25, 37, 26, 38, 39, 40, 41, 42, 43,
+ 47, 44, 29, 45, 30, 46, 28, 31, 55, 32,
+ 33, 34, 48, 52, 59, 56, 51, 57, 53, 54,
+ 63, 60, 61
+};
+
+static const unsigned char yycheck[] =
+{
+ 0, 17, 18, 10, 18, 5, 6, 7, 8, 9,
+ 17, 11, 12, 13, 14, 15, 16, 17, 18, 5,
+ 6, 20, 8, 4, 10, 11, 12, 13, 14, 15,
+ 3, 17, 6, 19, 8, 21, 4, 11, 10, 13,
+ 14, 15, 20, 18, 21, 17, 17, 19, 18, 18,
+ 60, 18, 18
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 23, 0, 5, 6, 7, 8, 9, 11, 12,
+ 13, 14, 15, 16, 17, 18, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 20, 4, 18, 4, 6,
+ 8, 11, 13, 14, 15, 5, 6, 8, 10, 11,
+ 12, 13, 14, 15, 17, 19, 21, 3, 20, 17,
+ 18, 17, 18, 18, 18, 10, 17, 19, 33, 21,
+ 18, 18, 17, 33
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrlab1
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror ("syntax error: cannot back up");\
+ YYERROR; \
+ } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+ are run). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ Current.first_line = Rhs[1].first_line; \
+ Current.first_column = Rhs[1].first_column; \
+ Current.last_line = Rhs[N].last_line; \
+ Current.last_column = Rhs[N].last_column;
+#endif
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval)
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YYDSYMPRINT(Args) \
+do { \
+ if (yydebug) \
+ yysymprint Args; \
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Token, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (cinluded). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short *bottom, short *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short *bottom;
+ short *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned int yylineno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+ yyrule - 1, yylineno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#if YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ register const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ register char *yyd = yydest;
+ register const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ {
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ }
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+ /* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+ register int yystate;
+ register int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ short yyssa[YYINITDEPTH];
+ short *yyss = yyssa;
+ register short *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK (yyvsp--, yyssp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyoverflowlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyoverflowlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyoverflowlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+ YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+#line 195 "getdate.y"
+ { PC.times_seen++; }
+ break;
+
+ case 5:
+#line 197 "getdate.y"
+ { PC.local_zones_seen++; }
+ break;
+
+ case 6:
+#line 199 "getdate.y"
+ { PC.zones_seen++; }
+ break;
+
+ case 7:
+#line 201 "getdate.y"
+ { PC.dates_seen++; }
+ break;
+
+ case 8:
+#line 203 "getdate.y"
+ { PC.days_seen++; }
+ break;
+
+ case 9:
+#line 205 "getdate.y"
+ { PC.rels_seen++; }
+ break;
+
+ case 11:
+#line 211 "getdate.y"
+ {
+ PC.hour = yyvsp[-1].textintval.value;
+ PC.minutes = 0;
+ PC.seconds = 0;
+ PC.meridian = yyvsp[0].intval;
+ }
+ break;
+
+ case 12:
+#line 218 "getdate.y"
+ {
+ PC.hour = yyvsp[-3].textintval.value;
+ PC.minutes = yyvsp[-1].textintval.value;
+ PC.seconds = 0;
+ PC.meridian = yyvsp[0].intval;
+ }
+ break;
+
+ case 13:
+#line 225 "getdate.y"
+ {
+ PC.hour = yyvsp[-3].textintval.value;
+ PC.minutes = yyvsp[-1].textintval.value;
+ PC.meridian = MER24;
+ PC.zones_seen++;
+ PC.time_zone = yyvsp[0].textintval.value % 100 + (yyvsp[0].textintval.value / 100) * 60;
+ }
+ break;
+
+ case 14:
+#line 233 "getdate.y"
+ {
+ PC.hour = yyvsp[-5].textintval.value;
+ PC.minutes = yyvsp[-3].textintval.value;
+ PC.seconds = yyvsp[-1].textintval.value;
+ PC.meridian = yyvsp[0].intval;
+ }
+ break;
+
+ case 15:
+#line 240 "getdate.y"
+ {
+ PC.hour = yyvsp[-5].textintval.value;
+ PC.minutes = yyvsp[-3].textintval.value;
+ PC.seconds = yyvsp[-1].textintval.value;
+ PC.meridian = MER24;
+ PC.zones_seen++;
+ PC.time_zone = yyvsp[0].textintval.value % 100 + (yyvsp[0].textintval.value / 100) * 60;
+ }
+ break;
+
+ case 16:
+#line 252 "getdate.y"
+ { PC.local_isdst = yyvsp[0].intval; }
+ break;
+
+ case 17:
+#line 254 "getdate.y"
+ { PC.local_isdst = yyvsp[-1].intval < 0 ? 1 : yyvsp[-1].intval + 1; }
+ break;
+
+ case 18:
+#line 259 "getdate.y"
+ { PC.time_zone = yyvsp[0].intval; }
+ break;
+
+ case 19:
+#line 261 "getdate.y"
+ { PC.time_zone = yyvsp[0].intval + 60; }
+ break;
+
+ case 20:
+#line 263 "getdate.y"
+ { PC.time_zone = yyvsp[-1].intval + 60; }
+ break;
+
+ case 21:
+#line 268 "getdate.y"
+ {
+ PC.day_ordinal = 1;
+ PC.day_number = yyvsp[0].intval;
+ }
+ break;
+
+ case 22:
+#line 273 "getdate.y"
+ {
+ PC.day_ordinal = 1;
+ PC.day_number = yyvsp[-1].intval;
+ }
+ break;
+
+ case 23:
+#line 278 "getdate.y"
+ {
+ PC.day_ordinal = yyvsp[-1].textintval.value;
+ PC.day_number = yyvsp[0].intval;
+ }
+ break;
+
+ case 24:
+#line 286 "getdate.y"
+ {
+ PC.month = yyvsp[-2].textintval.value;
+ PC.day = yyvsp[0].textintval.value;
+ }
+ break;
+
+ case 25:
+#line 291 "getdate.y"
+ {
+ /* Interpret as YYYY/MM/DD if the first value has 4 or more digits,
+ otherwise as MM/DD/YY.
+ The goal in recognizing YYYY/MM/DD is solely to support legacy
+ machine-generated dates like those in an RCS log listing. If
+ you want portability, use the ISO 8601 format. */
+ if (4 <= yyvsp[-4].textintval.digits)
+ {
+ PC.year = yyvsp[-4].textintval;
+ PC.month = yyvsp[-2].textintval.value;
+ PC.day = yyvsp[0].textintval.value;
+ }
+ else
+ {
+ PC.month = yyvsp[-4].textintval.value;
+ PC.day = yyvsp[-2].textintval.value;
+ PC.year = yyvsp[0].textintval;
+ }
+ }
+ break;
+
+ case 26:
+#line 311 "getdate.y"
+ {
+ /* ISO 8601 format. YYYY-MM-DD. */
+ PC.year = yyvsp[-2].textintval;
+ PC.month = -yyvsp[-1].textintval.value;
+ PC.day = -yyvsp[0].textintval.value;
+ }
+ break;
+
+ case 27:
+#line 318 "getdate.y"
+ {
+ /* e.g. 17-JUN-1992. */
+ PC.day = yyvsp[-2].textintval.value;
+ PC.month = yyvsp[-1].intval;
+ PC.year.value = -yyvsp[0].textintval.value;
+ PC.year.digits = yyvsp[0].textintval.digits;
+ }
+ break;
+
+ case 28:
+#line 326 "getdate.y"
+ {
+ PC.month = yyvsp[-1].intval;
+ PC.day = yyvsp[0].textintval.value;
+ }
+ break;
+
+ case 29:
+#line 331 "getdate.y"
+ {
+ PC.month = yyvsp[-3].intval;
+ PC.day = yyvsp[-2].textintval.value;
+ PC.year = yyvsp[0].textintval;
+ }
+ break;
+
+ case 30:
+#line 337 "getdate.y"
+ {
+ PC.day = yyvsp[-1].textintval.value;
+ PC.month = yyvsp[0].intval;
+ }
+ break;
+
+ case 31:
+#line 342 "getdate.y"
+ {
+ PC.day = yyvsp[-2].textintval.value;
+ PC.month = yyvsp[-1].intval;
+ PC.year = yyvsp[0].textintval;
+ }
+ break;
+
+ case 32:
+#line 351 "getdate.y"
+ {
+ PC.rel_seconds = -PC.rel_seconds;
+ PC.rel_minutes = -PC.rel_minutes;
+ PC.rel_hour = -PC.rel_hour;
+ PC.rel_day = -PC.rel_day;
+ PC.rel_month = -PC.rel_month;
+ PC.rel_year = -PC.rel_year;
+ }
+ break;
+
+ case 34:
+#line 364 "getdate.y"
+ { PC.rel_year += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 35:
+#line 366 "getdate.y"
+ { PC.rel_year += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 36:
+#line 368 "getdate.y"
+ { PC.rel_year += yyvsp[0].intval; }
+ break;
+
+ case 37:
+#line 370 "getdate.y"
+ { PC.rel_month += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 38:
+#line 372 "getdate.y"
+ { PC.rel_month += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 39:
+#line 374 "getdate.y"
+ { PC.rel_month += yyvsp[0].intval; }
+ break;
+
+ case 40:
+#line 376 "getdate.y"
+ { PC.rel_day += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 41:
+#line 378 "getdate.y"
+ { PC.rel_day += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 42:
+#line 380 "getdate.y"
+ { PC.rel_day += yyvsp[0].intval; }
+ break;
+
+ case 43:
+#line 382 "getdate.y"
+ { PC.rel_hour += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 44:
+#line 384 "getdate.y"
+ { PC.rel_hour += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 45:
+#line 386 "getdate.y"
+ { PC.rel_hour += yyvsp[0].intval; }
+ break;
+
+ case 46:
+#line 388 "getdate.y"
+ { PC.rel_minutes += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 47:
+#line 390 "getdate.y"
+ { PC.rel_minutes += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 48:
+#line 392 "getdate.y"
+ { PC.rel_minutes += yyvsp[0].intval; }
+ break;
+
+ case 49:
+#line 394 "getdate.y"
+ { PC.rel_seconds += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 50:
+#line 396 "getdate.y"
+ { PC.rel_seconds += yyvsp[-1].textintval.value * yyvsp[0].intval; }
+ break;
+
+ case 51:
+#line 398 "getdate.y"
+ { PC.rel_seconds += yyvsp[0].intval; }
+ break;
+
+ case 52:
+#line 403 "getdate.y"
+ {
+ if (PC.dates_seen
+ && ! PC.rels_seen && (PC.times_seen || 2 < yyvsp[0].textintval.digits))
+ PC.year = yyvsp[0].textintval;
+ else
+ {
+ if (4 < yyvsp[0].textintval.digits)
+ {
+ PC.dates_seen++;
+ PC.day = yyvsp[0].textintval.value % 100;
+ PC.month = (yyvsp[0].textintval.value / 100) % 100;
+ PC.year.value = yyvsp[0].textintval.value / 10000;
+ PC.year.digits = yyvsp[0].textintval.digits - 4;
+ }
+ else
+ {
+ PC.times_seen++;
+ if (yyvsp[0].textintval.digits <= 2)
+ {
+ PC.hour = yyvsp[0].textintval.value;
+ PC.minutes = 0;
+ }
+ else
+ {
+ PC.hour = yyvsp[0].textintval.value / 100;
+ PC.minutes = yyvsp[0].textintval.value % 100;
+ }
+ PC.seconds = 0;
+ PC.meridian = MER24;
+ }
+ }
+ }
+ break;
+
+ case 53:
+#line 439 "getdate.y"
+ { yyval.intval = MER24; }
+ break;
+
+ case 54:
+#line 441 "getdate.y"
+ { yyval.intval = yyvsp[0].intval; }
+ break;
+
+
+ }
+
+/* Line 999 of yacc.c. */
+#line 1593 "getdate.c"
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ YYSIZE_T yysize = 0;
+ int yytype = YYTRANSLATE (yychar);
+ char *yymsg;
+ int yyx, yycount;
+
+ yycount = 0;
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ yysize += yystrlen (yytname[yyx]) + 15, yycount++;
+ yysize += yystrlen ("syntax error, unexpected ") + 1;
+ yysize += yystrlen (yytname[yytype]);
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
+ {
+ char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[yytype]);
+
+ if (yycount < 5)
+ {
+ yycount = 0;
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *));
+ yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ const char *yyq = ! yycount ? ", expecting " : " or ";
+ yyp = yystpcpy (yyp, yyq);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yycount++;
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ yyerror ("syntax error; also virtual memory exhausted");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror ("syntax error");
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ {
+ /* Pop the error token. */
+ YYPOPSTACK;
+ /* Pop the rest of the stack. */
+ while (yyss < yyssp)
+ {
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[*yyssp], yyvsp);
+ YYPOPSTACK;
+ }
+ YYABORT;
+ }
+
+ YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+ yydestruct (yytoken, &yylval);
+ yychar = YYEMPTY;
+
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*----------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action. |
+`----------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[yystate], yyvsp);
+ yyvsp--;
+ yystate = *--yyssp;
+
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ YYDPRINTF ((stderr, "Shifting error token, "));
+
+ *++yyvsp = yylval;
+
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here. |
+`----------------------------------------------*/
+yyoverflowlab:
+ yyerror ("parser stack overflow");
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+#line 444 "getdate.y"
+
+
+/* Include this file down here because bison inserts code above which
+ may define-away `const'. We want the prototype for get_date to have
+ the same signature as the function definition. */
+#include "modules/getdate.h"
+
+#ifndef gmtime
+struct tm *gmtime ();
+#endif
+#ifndef localtime
+struct tm *localtime ();
+#endif
+#ifndef mktime
+time_t mktime ();
+#endif
+
+static table const meridian_table[] =
+{
+ { "AM", tMERIDIAN, MERam },
+ { "A.M.", tMERIDIAN, MERam },
+ { "PM", tMERIDIAN, MERpm },
+ { "P.M.", tMERIDIAN, MERpm },
+ { 0, 0, 0 }
+};
+
+static table const dst_table[] =
+{
+ { "DST", tDST, 0 }
+};
+
+static table const month_and_day_table[] =
+{
+ { "JANUARY", tMONTH, 1 },
+ { "FEBRUARY", tMONTH, 2 },
+ { "MARCH", tMONTH, 3 },
+ { "APRIL", tMONTH, 4 },
+ { "MAY", tMONTH, 5 },
+ { "JUNE", tMONTH, 6 },
+ { "JULY", tMONTH, 7 },
+ { "AUGUST", tMONTH, 8 },
+ { "SEPTEMBER",tMONTH, 9 },
+ { "SEPT", tMONTH, 9 },
+ { "OCTOBER", tMONTH, 10 },
+ { "NOVEMBER", tMONTH, 11 },
+ { "DECEMBER", tMONTH, 12 },
+ { "SUNDAY", tDAY, 0 },
+ { "MONDAY", tDAY, 1 },
+ { "TUESDAY", tDAY, 2 },
+ { "TUES", tDAY, 2 },
+ { "WEDNESDAY",tDAY, 3 },
+ { "WEDNES", tDAY, 3 },
+ { "THURSDAY", tDAY, 4 },
+ { "THUR", tDAY, 4 },
+ { "THURS", tDAY, 4 },
+ { "FRIDAY", tDAY, 5 },
+ { "SATURDAY", tDAY, 6 },
+ { 0, 0, 0 }
+};
+
+static table const time_units_table[] =
+{
+ { "YEAR", tYEAR_UNIT, 1 },
+ { "MONTH", tMONTH_UNIT, 1 },
+ { "FORTNIGHT",tDAY_UNIT, 14 },
+ { "WEEK", tDAY_UNIT, 7 },
+ { "DAY", tDAY_UNIT, 1 },
+ { "HOUR", tHOUR_UNIT, 1 },
+ { "MINUTE", tMINUTE_UNIT, 1 },
+ { "MIN", tMINUTE_UNIT, 1 },
+ { "SECOND", tSEC_UNIT, 1 },
+ { "SEC", tSEC_UNIT, 1 },
+ { 0, 0, 0 }
+};
+
+/* Assorted relative-time words. */
+static table const relative_time_table[] =
+{
+ { "TOMORROW", tMINUTE_UNIT, 24 * 60 },
+ { "YESTERDAY",tMINUTE_UNIT, - (24 * 60) },
+ { "TODAY", tMINUTE_UNIT, 0 },
+ { "NOW", tMINUTE_UNIT, 0 },
+ { "LAST", tUNUMBER, -1 },
+ { "THIS", tUNUMBER, 0 },
+ { "NEXT", tUNUMBER, 1 },
+ { "FIRST", tUNUMBER, 1 },
+/*{ "SECOND", tUNUMBER, 2 }, */
+ { "THIRD", tUNUMBER, 3 },
+ { "FOURTH", tUNUMBER, 4 },
+ { "FIFTH", tUNUMBER, 5 },
+ { "SIXTH", tUNUMBER, 6 },
+ { "SEVENTH", tUNUMBER, 7 },
+ { "EIGHTH", tUNUMBER, 8 },
+ { "NINTH", tUNUMBER, 9 },
+ { "TENTH", tUNUMBER, 10 },
+ { "ELEVENTH", tUNUMBER, 11 },
+ { "TWELFTH", tUNUMBER, 12 },
+ { "AGO", tAGO, 1 },
+ { 0, 0, 0 }
+};
+
+/* The time zone table. This table is necessarily incomplete, as time
+ zone abbreviations are ambiguous; e.g. Australians interpret "EST"
+ as Eastern time in Australia, not as US Eastern Standard Time.
+ You cannot rely on getdate to handle arbitrary time zone
+ abbreviations; use numeric abbreviations like `-0500' instead. */
+static table const time_zone_table[] =
+{
+ { "GMT", tZONE, HOUR ( 0) }, /* Greenwich Mean */
+ { "UT", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */
+ { "UTC", tZONE, HOUR ( 0) },
+ { "WET", tZONE, HOUR ( 0) }, /* Western European */
+ { "WEST", tDAYZONE, HOUR ( 0) }, /* Western European Summer */
+ { "BST", tDAYZONE, HOUR ( 0) }, /* British Summer */
+ { "ART", tZONE, -HOUR ( 3) }, /* Argentina */
+ { "BRT", tZONE, -HOUR ( 3) }, /* Brazil */
+ { "BRST", tDAYZONE, -HOUR ( 3) }, /* Brazil Summer */
+ { "NST", tZONE, -(HOUR ( 3) + 30) }, /* Newfoundland Standard */
+ { "NDT", tDAYZONE,-(HOUR ( 3) + 30) }, /* Newfoundland Daylight */
+ { "AST", tZONE, -HOUR ( 4) }, /* Atlantic Standard */
+ { "ADT", tDAYZONE, -HOUR ( 4) }, /* Atlantic Daylight */
+ { "CLT", tZONE, -HOUR ( 4) }, /* Chile */
+ { "CLST", tDAYZONE, -HOUR ( 4) }, /* Chile Summer */
+ { "EST", tZONE, -HOUR ( 5) }, /* Eastern Standard */
+ { "EDT", tDAYZONE, -HOUR ( 5) }, /* Eastern Daylight */
+ { "CST", tZONE, -HOUR ( 6) }, /* Central Standard */
+ { "CDT", tDAYZONE, -HOUR ( 6) }, /* Central Daylight */
+ { "MST", tZONE, -HOUR ( 7) }, /* Mountain Standard */
+ { "MDT", tDAYZONE, -HOUR ( 7) }, /* Mountain Daylight */
+ { "PST", tZONE, -HOUR ( 8) }, /* Pacific Standard */
+ { "PDT", tDAYZONE, -HOUR ( 8) }, /* Pacific Daylight */
+ { "AKST", tZONE, -HOUR ( 9) }, /* Alaska Standard */
+ { "AKDT", tDAYZONE, -HOUR ( 9) }, /* Alaska Daylight */
+ { "HST", tZONE, -HOUR (10) }, /* Hawaii Standard */
+ { "HAST", tZONE, -HOUR (10) }, /* Hawaii-Aleutian Standard */
+ { "HADT", tDAYZONE, -HOUR (10) }, /* Hawaii-Aleutian Daylight */
+ { "SST", tZONE, -HOUR (12) }, /* Samoa Standard */
+ { "WAT", tZONE, HOUR ( 1) }, /* West Africa */
+ { "CET", tZONE, HOUR ( 1) }, /* Central European */
+ { "CEST", tDAYZONE, HOUR ( 1) }, /* Central European Summer */
+ { "MET", tZONE, HOUR ( 1) }, /* Middle European */
+ { "MEZ", tZONE, HOUR ( 1) }, /* Middle European */
+ { "MEST", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */
+ { "MESZ", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */
+ { "EET", tZONE, HOUR ( 2) }, /* Eastern European */
+ { "EEST", tDAYZONE, HOUR ( 2) }, /* Eastern European Summer */
+ { "CAT", tZONE, HOUR ( 2) }, /* Central Africa */
+ { "SAST", tZONE, HOUR ( 2) }, /* South Africa Standard */
+ { "EAT", tZONE, HOUR ( 3) }, /* East Africa */
+ { "MSK", tZONE, HOUR ( 3) }, /* Moscow */
+ { "MSD", tDAYZONE, HOUR ( 3) }, /* Moscow Daylight */
+ { "IST", tZONE, (HOUR ( 5) + 30) }, /* India Standard */
+ { "SGT", tZONE, HOUR ( 8) }, /* Singapore */
+ { "KST", tZONE, HOUR ( 9) }, /* Korea Standard */
+ { "JST", tZONE, HOUR ( 9) }, /* Japan Standard */
+ { "GST", tZONE, HOUR (10) }, /* Guam Standard */
+ { "NZST", tZONE, HOUR (12) }, /* New Zealand Standard */
+ { "NZDT", tDAYZONE, HOUR (12) }, /* New Zealand Daylight */
+ { 0, 0, 0 }
+};
+
+/* Military time zone table. */
+static table const military_table[] =
+{
+ { "A", tZONE, -HOUR ( 1) },
+ { "B", tZONE, -HOUR ( 2) },
+ { "C", tZONE, -HOUR ( 3) },
+ { "D", tZONE, -HOUR ( 4) },
+ { "E", tZONE, -HOUR ( 5) },
+ { "F", tZONE, -HOUR ( 6) },
+ { "G", tZONE, -HOUR ( 7) },
+ { "H", tZONE, -HOUR ( 8) },
+ { "I", tZONE, -HOUR ( 9) },
+ { "K", tZONE, -HOUR (10) },
+ { "L", tZONE, -HOUR (11) },
+ { "M", tZONE, -HOUR (12) },
+ { "N", tZONE, HOUR ( 1) },
+ { "O", tZONE, HOUR ( 2) },
+ { "P", tZONE, HOUR ( 3) },
+ { "Q", tZONE, HOUR ( 4) },
+ { "R", tZONE, HOUR ( 5) },
+ { "S", tZONE, HOUR ( 6) },
+ { "T", tZONE, HOUR ( 7) },
+ { "U", tZONE, HOUR ( 8) },
+ { "V", tZONE, HOUR ( 9) },
+ { "W", tZONE, HOUR (10) },
+ { "X", tZONE, HOUR (11) },
+ { "Y", tZONE, HOUR (12) },
+ { "Z", tZONE, HOUR ( 0) },
+ { 0, 0, 0 }
+};
+
+
+
+static int
+to_hour (int hours, int meridian)
+{
+ switch (meridian)
+ {
+ case MER24:
+ return 0 <= hours && hours < 24 ? hours : -1;
+ case MERam:
+ return 0 < hours && hours < 12 ? hours : hours == 12 ? 0 : -1;
+ case MERpm:
+ return 0 < hours && hours < 12 ? hours + 12 : hours == 12 ? 12 : -1;
+ default:
+ abort ();
+ }
+ /* NOTREACHED */
+ return 0;
+}
+
+static int
+to_year (textint textyear)
+{
+ int year = textyear.value;
+
+ if (year < 0)
+ year = -year;
+
+ /* XPG4 suggests that years 00-68 map to 2000-2068, and
+ years 69-99 map to 1969-1999. */
+ if (textyear.digits == 2)
+ year += year < 69 ? 2000 : 1900;
+
+ return year;
+}
+
+static table const *
+lookup_zone (parser_control const *pc, char const *name)
+{
+ table const *tp;
+
+ /* Try local zone abbreviations first; they're more likely to be right. */
+ for (tp = pc->local_time_zone_table; tp->name; tp++)
+ if (strcmp (name, tp->name) == 0)
+ return tp;
+
+ for (tp = time_zone_table; tp->name; tp++)
+ if (strcmp (name, tp->name) == 0)
+ return tp;
+
+ return 0;
+}
+
+#if ! HAVE_TM_GMTOFF
+/* Yield the difference between *A and *B,
+ measured in seconds, ignoring leap seconds.
+ The body of this function is taken directly from the GNU C Library;
+ see src/strftime.c. */
+static int
+tm_diff (struct tm const *a, struct tm const *b)
+{
+ /* Compute intervening leap days correctly even if year is negative.
+ Take care to avoid int overflow in leap day calculations,
+ but it's OK to assume that A and B are close to each other. */
+ int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
+ int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
+ int a100 = a4 / 25 - (a4 % 25 < 0);
+ int b100 = b4 / 25 - (b4 % 25 < 0);
+ int a400 = a100 >> 2;
+ int b400 = b100 >> 2;
+ int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+ int years = a->tm_year - b->tm_year;
+ int days = (365 * years + intervening_leap_days
+ + (a->tm_yday - b->tm_yday));
+ return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+ + (a->tm_min - b->tm_min))
+ + (a->tm_sec - b->tm_sec));
+}
+#endif /* ! HAVE_TM_GMTOFF */
+
+static table const *
+lookup_word (parser_control const *pc, char *word)
+{
+ char *p;
+ char *q;
+ size_t wordlen;
+ table const *tp;
+ int i;
+ int abbrev;
+
+ /* Make it uppercase. */
+ for (p = word; *p; p++)
+ if (ISLOWER ((unsigned char) *p))
+ *p = toupper ((unsigned char) *p);
+
+ for (tp = meridian_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+
+ /* See if we have an abbreviation for a month. */
+ wordlen = strlen (word);
+ abbrev = wordlen == 3 || (wordlen == 4 && word[3] == '.');
+
+ for (tp = month_and_day_table; tp->name; tp++)
+ if ((abbrev ? strncmp (word, tp->name, 3) : strcmp (word, tp->name)) == 0)
+ return tp;
+
+ if ((tp = lookup_zone (pc, word)))
+ return tp;
+
+ if (strcmp (word, dst_table[0].name) == 0)
+ return dst_table;
+
+ for (tp = time_units_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+
+ /* Strip off any plural and try the units table again. */
+ if (word[wordlen - 1] == 'S')
+ {
+ word[wordlen - 1] = '\0';
+ for (tp = time_units_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+ word[wordlen - 1] = 'S'; /* For "this" in relative_time_table. */
+ }
+
+ for (tp = relative_time_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+
+ /* Military time zones. */
+ if (wordlen == 1)
+ for (tp = military_table; tp->name; tp++)
+ if (word[0] == tp->name[0])
+ return tp;
+
+ /* Drop out any periods and try the time zone table again. */
+ for (i = 0, p = q = word; (*p = *q); q++)
+ if (*q == '.')
+ i = 1;
+ else
+ p++;
+ if (i && (tp = lookup_zone (pc, word)))
+ return tp;
+
+ return 0;
+}
+
+static int
+yylex (YYSTYPE *lvalp, parser_control *pc)
+{
+ unsigned char c;
+ int count;
+
+ for (;;)
+ {
+ while (c = *pc->input, ISSPACE (c))
+ pc->input++;
+
+ if (ISDIGIT (c) || c == '-' || c == '+')
+ {
+ char const *p;
+ int sign;
+ int value;
+ if (c == '-' || c == '+')
+ {
+ sign = c == '-' ? -1 : 1;
+ c = *++pc->input;
+ if (! ISDIGIT (c))
+ /* skip the '-' sign */
+ continue;
+ }
+ else
+ sign = 0;
+ p = pc->input;
+ value = 0;
+ do
+ {
+ value = 10 * value + c - '0';
+ c = *++p;
+ }
+ while (ISDIGIT (c));
+ lvalp->textintval.value = sign < 0 ? -value : value;
+ lvalp->textintval.digits = p - pc->input;
+ pc->input = p;
+ return sign ? tSNUMBER : tUNUMBER;
+ }
+
+ if (ISALPHA (c))
+ {
+ char buff[20];
+ char *p = buff;
+ table const *tp;
+
+ do
+ {
+ if (p < buff + sizeof buff - 1)
+ *p++ = c;
+ c = *++pc->input;
+ }
+ while (ISALPHA (c) || c == '.');
+
+ *p = '\0';
+ tp = lookup_word (pc, buff);
+ if (! tp)
+ return '?';
+ lvalp->intval = tp->value;
+ return tp->type;
+ }
+
+ if (c != '(')
+ return *pc->input++;
+ count = 0;
+ do
+ {
+ c = *pc->input++;
+ if (c == '\0')
+ return c;
+ if (c == '(')
+ count++;
+ else if (c == ')')
+ count--;
+ }
+ while (count > 0);
+ }
+}
+
+/* Do nothing if the parser reports an error. */
+static int
+yyerror (char *s ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+/* Parse a date/time string P. Return the corresponding time_t value,
+ or (time_t) -1 if there is an error. P can be an incomplete or
+ relative time specification; if so, use *NOW as the basis for the
+ returned time. */
+time_t
+get_date (const char *p, const time_t *now)
+{
+ time_t Start = now ? *now : time (0);
+ struct tm *tmp = localtime (&Start);
+ struct tm tm;
+ struct tm tm0;
+ parser_control pc;
+
+ if (! tmp)
+ return -1;
+
+ pc.input = p;
+ pc.year.value = tmp->tm_year + TM_YEAR_BASE;
+ pc.year.digits = 4;
+ pc.month = tmp->tm_mon + 1;
+ pc.day = tmp->tm_mday;
+ pc.hour = tmp->tm_hour;
+ pc.minutes = tmp->tm_min;
+ pc.seconds = tmp->tm_sec;
+ tm.tm_isdst = tmp->tm_isdst;
+
+ pc.meridian = MER24;
+ pc.rel_seconds = 0;
+ pc.rel_minutes = 0;
+ pc.rel_hour = 0;
+ pc.rel_day = 0;
+ pc.rel_month = 0;
+ pc.rel_year = 0;
+ pc.dates_seen = 0;
+ pc.days_seen = 0;
+ pc.rels_seen = 0;
+ pc.times_seen = 0;
+ pc.local_zones_seen = 0;
+ pc.zones_seen = 0;
+
+#if HAVE_STRUCT_TM_TM_ZONE
+ pc.local_time_zone_table[0].name = tmp->tm_zone;
+ pc.local_time_zone_table[0].type = tLOCAL_ZONE;
+ pc.local_time_zone_table[0].value = tmp->tm_isdst;
+ pc.local_time_zone_table[1].name = 0;
+
+ /* Probe the names used in the next three calendar quarters, looking
+ for a tm_isdst different from the one we already have. */
+ {
+ int quarter;
+ for (quarter = 1; quarter <= 3; quarter++)
+ {
+ time_t probe = Start + quarter * (90 * 24 * 60 * 60);
+ struct tm *probe_tm = localtime (&probe);
+ if (probe_tm && probe_tm->tm_zone
+ && probe_tm->tm_isdst != pc.local_time_zone_table[0].value)
+ {
+ {
+ pc.local_time_zone_table[1].name = probe_tm->tm_zone;
+ pc.local_time_zone_table[1].type = tLOCAL_ZONE;
+ pc.local_time_zone_table[1].value = probe_tm->tm_isdst;
+ pc.local_time_zone_table[2].name = 0;
+ }
+ break;
+ }
+ }
+ }
+#else
+#if HAVE_TZNAME
+ {
+# ifndef tzname
+ extern char *tzname[];
+# endif
+ int i;
+ for (i = 0; i < 2; i++)
+ {
+ pc.local_time_zone_table[i].name = tzname[i];
+ pc.local_time_zone_table[i].type = tLOCAL_ZONE;
+ pc.local_time_zone_table[i].value = i;
+ }
+ pc.local_time_zone_table[i].name = 0;
+ }
+#else
+ pc.local_time_zone_table[0].name = 0;
+#endif
+#endif
+
+ if (pc.local_time_zone_table[0].name && pc.local_time_zone_table[1].name
+ && ! strcmp (pc.local_time_zone_table[0].name,
+ pc.local_time_zone_table[1].name))
+ {
+ /* This locale uses the same abbrevation for standard and
+ daylight times. So if we see that abbreviation, we don't
+ know whether it's daylight time. */
+ pc.local_time_zone_table[0].value = -1;
+ pc.local_time_zone_table[1].name = 0;
+ }
+
+ if (yyparse (&pc) != 0
+ || 1 < pc.times_seen || 1 < pc.dates_seen || 1 < pc.days_seen
+ || 1 < (pc.local_zones_seen + pc.zones_seen)
+ || (pc.local_zones_seen && 1 < pc.local_isdst))
+ return -1;
+
+ tm.tm_year = to_year (pc.year) - TM_YEAR_BASE + pc.rel_year;
+ tm.tm_mon = pc.month - 1 + pc.rel_month;
+ tm.tm_mday = pc.day + pc.rel_day;
+ if (pc.times_seen || (pc.rels_seen && ! pc.dates_seen && ! pc.days_seen))
+ {
+ tm.tm_hour = to_hour (pc.hour, pc.meridian);
+ if (tm.tm_hour < 0)
+ return -1;
+ tm.tm_min = pc.minutes;
+ tm.tm_sec = pc.seconds;
+ }
+ else
+ {
+ tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+ }
+
+ /* Let mktime deduce tm_isdst if we have an absolute time stamp,
+ or if the relative time stamp mentions days, months, or years. */
+ if (pc.dates_seen | pc.days_seen | pc.times_seen | pc.rel_day
+ | pc.rel_month | pc.rel_year)
+ tm.tm_isdst = -1;
+
+ /* But if the input explicitly specifies local time with or without
+ DST, give mktime that information. */
+ if (pc.local_zones_seen)
+ tm.tm_isdst = pc.local_isdst;
+
+ tm0 = tm;
+
+ Start = mktime (&tm);
+
+ if (Start == (time_t) -1)
+ {
+
+ /* Guard against falsely reporting errors near the time_t boundaries
+ when parsing times in other time zones. For example, if the min
+ time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead
+ of UTC, then the min localtime value is 1970-01-01 08:00:00; if
+ we apply mktime to 1970-01-01 00:00:00 we will get an error, so
+ we apply mktime to 1970-01-02 08:00:00 instead and adjust the time
+ zone by 24 hours to compensate. This algorithm assumes that
+ there is no DST transition within a day of the time_t boundaries. */
+ if (pc.zones_seen)
+ {
+ tm = tm0;
+ if (tm.tm_year <= EPOCH_YEAR - TM_YEAR_BASE)
+ {
+ tm.tm_mday++;
+ pc.time_zone += 24 * 60;
+ }
+ else
+ {
+ tm.tm_mday--;
+ pc.time_zone -= 24 * 60;
+ }
+ Start = mktime (&tm);
+ }
+
+ if (Start == (time_t) -1)
+ return Start;
+ }
+
+ if (pc.days_seen && ! pc.dates_seen)
+ {
+ tm.tm_mday += ((pc.day_number - tm.tm_wday + 7) % 7
+ + 7 * (pc.day_ordinal - (0 < pc.day_ordinal)));
+ tm.tm_isdst = -1;
+ Start = mktime (&tm);
+ if (Start == (time_t) -1)
+ return Start;
+ }
+
+ if (pc.zones_seen)
+ {
+ int delta = pc.time_zone * 60;
+#ifdef HAVE_TM_GMTOFF
+ delta -= tm.tm_gmtoff;
+#else
+ struct tm *gmt = gmtime (&Start);
+ if (! gmt)
+ return -1;
+ delta -= tm_diff (&tm, gmt);
+#endif
+ if ((Start < Start - delta) != (delta < 0))
+ return -1; /* time_t overflow */
+ Start -= delta;
+ }
+
+ /* Add relative hours, minutes, and seconds. Ignore leap seconds;
+ i.e. "+ 10 minutes" means 600 seconds, even if one of them is a
+ leap second. Typically this is not what the user wants, but it's
+ too hard to do it the other way, because the time zone indicator
+ must be applied before relative times, and if mktime is applied
+ again the time zone will be lost. */
+ {
+ time_t t0 = Start;
+ long d1 = 60 * 60 * (long) pc.rel_hour;
+ time_t t1 = t0 + d1;
+ long d2 = 60 * (long) pc.rel_minutes;
+ time_t t2 = t1 + d2;
+ int d3 = pc.rel_seconds;
+ time_t t3 = t2 + d3;
+ if ((d1 / (60 * 60) ^ pc.rel_hour)
+ | (d2 / 60 ^ pc.rel_minutes)
+ | ((t0 + d1 < t0) ^ (d1 < 0))
+ | ((t1 + d2 < t1) ^ (d2 < 0))
+ | ((t2 + d3 < t2) ^ (d3 < 0)))
+ return -1;
+ Start = t3;
+ }
+
+ return Start;
+}
+
+#if TEST
+
+#include <stdio.h>
+
+int
+main (int ac, char **av)
+{
+ char buff[BUFSIZ];
+ time_t d;
+
+ printf ("Enter date, or blank line to exit.\n\t> ");
+ fflush (stdout);
+
+ buff[BUFSIZ - 1] = 0;
+ while (fgets (buff, BUFSIZ - 1, stdin) && buff[0])
+ {
+ d = get_date (buff, 0);
+ if (d == (time_t) -1)
+ printf ("Bad format - couldn't convert.\n");
+ else
+ printf ("%s", ctime (&d));
+ printf ("\t> ");
+ fflush (stdout);
+ }
+ return 0;
+}
+#endif /* defined TEST */
+
+
diff --git a/source3/modules/getdate.h b/source3/modules/getdate.h
new file mode 100644
index 0000000000..93d95ddde0
--- /dev/null
+++ b/source3/modules/getdate.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 1995, 1997, 1998 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+#endif
+
+#ifdef vms
+# include <types.h>
+# include <time.h>
+#else
+# include <sys/types.h>
+# if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+# endif
+#endif /* defined (vms) */
+
+time_t get_date PARAMS ((const char *p, const time_t *now));
diff --git a/source3/modules/getdate.y b/source3/modules/getdate.y
new file mode 100644
index 0000000000..edfb9d5ad7
--- /dev/null
+++ b/source3/modules/getdate.y
@@ -0,0 +1,1115 @@
+%{
+/* Parse a string into an internal time stamp.
+ Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+/* Originally written by Steven M. Bellovin <smb@research.att.com> while
+ at the University of North Carolina at Chapel Hill. Later tweaked by
+ a couple of people on Usenet. Completely overhauled by Rich $alz
+ <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.
+
+ Modified by Paul Eggert <eggert@twinsun.com> in August 1999 to do
+ the right thing about local DST. Unlike previous versions, this
+ version is reentrant. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+# ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+# endif
+#endif
+
+/* Since the code of getdate.y is not included in the Emacs executable
+ itself, there is no need to #define static in this file. Even if
+ the code were included in the Emacs executable, it probably
+ wouldn't do any harm to #undef it here; this will only cause
+ problems if we try to write to a static variable, which I don't
+ think this code needs to do. */
+#ifdef emacs
+# undef static
+#endif
+
+#include <ctype.h>
+#include <string.h>
+
+#if HAVE_STDLIB_H
+# include <stdlib.h> /* for `free'; used by Bison 1.27 */
+#endif
+
+#if STDC_HEADERS || (! defined isascii && ! HAVE_ISASCII)
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) isascii (c)
+#endif
+
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
+#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c))
+#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
+
+/* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
+ - Its arg may be any int or unsigned int; it need not be an unsigned char.
+ - It's guaranteed to evaluate its argument exactly once.
+ - It's typically faster.
+ POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
+ ISDIGIT_LOCALE unless it's important to use the locale's definition
+ of `digit' even when the host does not conform to POSIX. */
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+
+#if STDC_HEADERS || HAVE_STRING_H
+# include <string.h>
+#endif
+
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
+# define __attribute__(x)
+#endif
+
+#ifndef ATTRIBUTE_UNUSED
+# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif
+
+#define EPOCH_YEAR 1970
+#define TM_YEAR_BASE 1900
+
+#define HOUR(x) ((x) * 60)
+
+/* An integer value, and the number of digits in its textual
+ representation. */
+typedef struct
+{
+ int value;
+ int digits;
+} textint;
+
+/* An entry in the lexical lookup table. */
+typedef struct
+{
+ char const *name;
+ int type;
+ int value;
+} table;
+
+/* Meridian: am, pm, or 24-hour style. */
+enum { MERam, MERpm, MER24 };
+
+/* Information passed to and from the parser. */
+typedef struct
+{
+ /* The input string remaining to be parsed. */
+ const char *input;
+
+ /* N, if this is the Nth Tuesday. */
+ int day_ordinal;
+
+ /* Day of week; Sunday is 0. */
+ int day_number;
+
+ /* tm_isdst flag for the local zone. */
+ int local_isdst;
+
+ /* Time zone, in minutes east of UTC. */
+ int time_zone;
+
+ /* Style used for time. */
+ int meridian;
+
+ /* Gregorian year, month, day, hour, minutes, and seconds. */
+ textint year;
+ int month;
+ int day;
+ int hour;
+ int minutes;
+ int seconds;
+
+ /* Relative year, month, day, hour, minutes, and seconds. */
+ int rel_year;
+ int rel_month;
+ int rel_day;
+ int rel_hour;
+ int rel_minutes;
+ int rel_seconds;
+
+ /* Counts of nonterminals of various flavors parsed so far. */
+ int dates_seen;
+ int days_seen;
+ int local_zones_seen;
+ int rels_seen;
+ int times_seen;
+ int zones_seen;
+
+ /* Table of local time zone abbrevations, terminated by a null entry. */
+ table local_time_zone_table[3];
+} parser_control;
+
+#define PC (* (parser_control *) parm)
+#define YYLEX_PARAM parm
+#define YYPARSE_PARAM parm
+
+static int yyerror ();
+static int yylex ();
+
+%}
+
+/* We want a reentrant parser. */
+%pure_parser
+
+/* This grammar has 13 shift/reduce conflicts. */
+%expect 13
+
+%union
+{
+ int intval;
+ textint textintval;
+}
+
+%token tAGO tDST
+
+%token <intval> tDAY tDAY_UNIT tDAYZONE tHOUR_UNIT tLOCAL_ZONE tMERIDIAN
+%token <intval> tMINUTE_UNIT tMONTH tMONTH_UNIT tSEC_UNIT tYEAR_UNIT tZONE
+
+%token <textintval> tSNUMBER tUNUMBER
+
+%type <intval> o_merid
+
+%%
+
+spec:
+ /* empty */
+ | spec item
+ ;
+
+item:
+ time
+ { PC.times_seen++; }
+ | local_zone
+ { PC.local_zones_seen++; }
+ | zone
+ { PC.zones_seen++; }
+ | date
+ { PC.dates_seen++; }
+ | day
+ { PC.days_seen++; }
+ | rel
+ { PC.rels_seen++; }
+ | number
+ ;
+
+time:
+ tUNUMBER tMERIDIAN
+ {
+ PC.hour = $1.value;
+ PC.minutes = 0;
+ PC.seconds = 0;
+ PC.meridian = $2;
+ }
+ | tUNUMBER ':' tUNUMBER o_merid
+ {
+ PC.hour = $1.value;
+ PC.minutes = $3.value;
+ PC.seconds = 0;
+ PC.meridian = $4;
+ }
+ | tUNUMBER ':' tUNUMBER tSNUMBER
+ {
+ PC.hour = $1.value;
+ PC.minutes = $3.value;
+ PC.meridian = MER24;
+ PC.zones_seen++;
+ PC.time_zone = $4.value % 100 + ($4.value / 100) * 60;
+ }
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid
+ {
+ PC.hour = $1.value;
+ PC.minutes = $3.value;
+ PC.seconds = $5.value;
+ PC.meridian = $6;
+ }
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER
+ {
+ PC.hour = $1.value;
+ PC.minutes = $3.value;
+ PC.seconds = $5.value;
+ PC.meridian = MER24;
+ PC.zones_seen++;
+ PC.time_zone = $6.value % 100 + ($6.value / 100) * 60;
+ }
+ ;
+
+local_zone:
+ tLOCAL_ZONE
+ { PC.local_isdst = $1; }
+ | tLOCAL_ZONE tDST
+ { PC.local_isdst = $1 < 0 ? 1 : $1 + 1; }
+ ;
+
+zone:
+ tZONE
+ { PC.time_zone = $1; }
+ | tDAYZONE
+ { PC.time_zone = $1 + 60; }
+ | tZONE tDST
+ { PC.time_zone = $1 + 60; }
+ ;
+
+day:
+ tDAY
+ {
+ PC.day_ordinal = 1;
+ PC.day_number = $1;
+ }
+ | tDAY ','
+ {
+ PC.day_ordinal = 1;
+ PC.day_number = $1;
+ }
+ | tUNUMBER tDAY
+ {
+ PC.day_ordinal = $1.value;
+ PC.day_number = $2;
+ }
+ ;
+
+date:
+ tUNUMBER '/' tUNUMBER
+ {
+ PC.month = $1.value;
+ PC.day = $3.value;
+ }
+ | tUNUMBER '/' tUNUMBER '/' tUNUMBER
+ {
+ /* Interpret as YYYY/MM/DD if the first value has 4 or more digits,
+ otherwise as MM/DD/YY.
+ The goal in recognizing YYYY/MM/DD is solely to support legacy
+ machine-generated dates like those in an RCS log listing. If
+ you want portability, use the ISO 8601 format. */
+ if (4 <= $1.digits)
+ {
+ PC.year = $1;
+ PC.month = $3.value;
+ PC.day = $5.value;
+ }
+ else
+ {
+ PC.month = $1.value;
+ PC.day = $3.value;
+ PC.year = $5;
+ }
+ }
+ | tUNUMBER tSNUMBER tSNUMBER
+ {
+ /* ISO 8601 format. YYYY-MM-DD. */
+ PC.year = $1;
+ PC.month = -$2.value;
+ PC.day = -$3.value;
+ }
+ | tUNUMBER tMONTH tSNUMBER
+ {
+ /* e.g. 17-JUN-1992. */
+ PC.day = $1.value;
+ PC.month = $2;
+ PC.year.value = -$3.value;
+ PC.year.digits = $3.digits;
+ }
+ | tMONTH tUNUMBER
+ {
+ PC.month = $1;
+ PC.day = $2.value;
+ }
+ | tMONTH tUNUMBER ',' tUNUMBER
+ {
+ PC.month = $1;
+ PC.day = $2.value;
+ PC.year = $4;
+ }
+ | tUNUMBER tMONTH
+ {
+ PC.day = $1.value;
+ PC.month = $2;
+ }
+ | tUNUMBER tMONTH tUNUMBER
+ {
+ PC.day = $1.value;
+ PC.month = $2;
+ PC.year = $3;
+ }
+ ;
+
+rel:
+ relunit tAGO
+ {
+ PC.rel_seconds = -PC.rel_seconds;
+ PC.rel_minutes = -PC.rel_minutes;
+ PC.rel_hour = -PC.rel_hour;
+ PC.rel_day = -PC.rel_day;
+ PC.rel_month = -PC.rel_month;
+ PC.rel_year = -PC.rel_year;
+ }
+ | relunit
+ ;
+
+relunit:
+ tUNUMBER tYEAR_UNIT
+ { PC.rel_year += $1.value * $2; }
+ | tSNUMBER tYEAR_UNIT
+ { PC.rel_year += $1.value * $2; }
+ | tYEAR_UNIT
+ { PC.rel_year += $1; }
+ | tUNUMBER tMONTH_UNIT
+ { PC.rel_month += $1.value * $2; }
+ | tSNUMBER tMONTH_UNIT
+ { PC.rel_month += $1.value * $2; }
+ | tMONTH_UNIT
+ { PC.rel_month += $1; }
+ | tUNUMBER tDAY_UNIT
+ { PC.rel_day += $1.value * $2; }
+ | tSNUMBER tDAY_UNIT
+ { PC.rel_day += $1.value * $2; }
+ | tDAY_UNIT
+ { PC.rel_day += $1; }
+ | tUNUMBER tHOUR_UNIT
+ { PC.rel_hour += $1.value * $2; }
+ | tSNUMBER tHOUR_UNIT
+ { PC.rel_hour += $1.value * $2; }
+ | tHOUR_UNIT
+ { PC.rel_hour += $1; }
+ | tUNUMBER tMINUTE_UNIT
+ { PC.rel_minutes += $1.value * $2; }
+ | tSNUMBER tMINUTE_UNIT
+ { PC.rel_minutes += $1.value * $2; }
+ | tMINUTE_UNIT
+ { PC.rel_minutes += $1; }
+ | tUNUMBER tSEC_UNIT
+ { PC.rel_seconds += $1.value * $2; }
+ | tSNUMBER tSEC_UNIT
+ { PC.rel_seconds += $1.value * $2; }
+ | tSEC_UNIT
+ { PC.rel_seconds += $1; }
+ ;
+
+number:
+ tUNUMBER
+ {
+ if (PC.dates_seen
+ && ! PC.rels_seen && (PC.times_seen || 2 < $1.digits))
+ PC.year = $1;
+ else
+ {
+ if (4 < $1.digits)
+ {
+ PC.dates_seen++;
+ PC.day = $1.value % 100;
+ PC.month = ($1.value / 100) % 100;
+ PC.year.value = $1.value / 10000;
+ PC.year.digits = $1.digits - 4;
+ }
+ else
+ {
+ PC.times_seen++;
+ if ($1.digits <= 2)
+ {
+ PC.hour = $1.value;
+ PC.minutes = 0;
+ }
+ else
+ {
+ PC.hour = $1.value / 100;
+ PC.minutes = $1.value % 100;
+ }
+ PC.seconds = 0;
+ PC.meridian = MER24;
+ }
+ }
+ }
+ ;
+
+o_merid:
+ /* empty */
+ { $$ = MER24; }
+ | tMERIDIAN
+ { $$ = $1; }
+ ;
+
+%%
+
+/* Include this file down here because bison inserts code above which
+ may define-away `const'. We want the prototype for get_date to have
+ the same signature as the function definition. */
+#include "modules/getdate.h"
+
+#ifndef gmtime
+struct tm *gmtime ();
+#endif
+#ifndef localtime
+struct tm *localtime ();
+#endif
+#ifndef mktime
+time_t mktime ();
+#endif
+
+static table const meridian_table[] =
+{
+ { "AM", tMERIDIAN, MERam },
+ { "A.M.", tMERIDIAN, MERam },
+ { "PM", tMERIDIAN, MERpm },
+ { "P.M.", tMERIDIAN, MERpm },
+ { 0, 0, 0 }
+};
+
+static table const dst_table[] =
+{
+ { "DST", tDST, 0 }
+};
+
+static table const month_and_day_table[] =
+{
+ { "JANUARY", tMONTH, 1 },
+ { "FEBRUARY", tMONTH, 2 },
+ { "MARCH", tMONTH, 3 },
+ { "APRIL", tMONTH, 4 },
+ { "MAY", tMONTH, 5 },
+ { "JUNE", tMONTH, 6 },
+ { "JULY", tMONTH, 7 },
+ { "AUGUST", tMONTH, 8 },
+ { "SEPTEMBER",tMONTH, 9 },
+ { "SEPT", tMONTH, 9 },
+ { "OCTOBER", tMONTH, 10 },
+ { "NOVEMBER", tMONTH, 11 },
+ { "DECEMBER", tMONTH, 12 },
+ { "SUNDAY", tDAY, 0 },
+ { "MONDAY", tDAY, 1 },
+ { "TUESDAY", tDAY, 2 },
+ { "TUES", tDAY, 2 },
+ { "WEDNESDAY",tDAY, 3 },
+ { "WEDNES", tDAY, 3 },
+ { "THURSDAY", tDAY, 4 },
+ { "THUR", tDAY, 4 },
+ { "THURS", tDAY, 4 },
+ { "FRIDAY", tDAY, 5 },
+ { "SATURDAY", tDAY, 6 },
+ { 0, 0, 0 }
+};
+
+static table const time_units_table[] =
+{
+ { "YEAR", tYEAR_UNIT, 1 },
+ { "MONTH", tMONTH_UNIT, 1 },
+ { "FORTNIGHT",tDAY_UNIT, 14 },
+ { "WEEK", tDAY_UNIT, 7 },
+ { "DAY", tDAY_UNIT, 1 },
+ { "HOUR", tHOUR_UNIT, 1 },
+ { "MINUTE", tMINUTE_UNIT, 1 },
+ { "MIN", tMINUTE_UNIT, 1 },
+ { "SECOND", tSEC_UNIT, 1 },
+ { "SEC", tSEC_UNIT, 1 },
+ { 0, 0, 0 }
+};
+
+/* Assorted relative-time words. */
+static table const relative_time_table[] =
+{
+ { "TOMORROW", tMINUTE_UNIT, 24 * 60 },
+ { "YESTERDAY",tMINUTE_UNIT, - (24 * 60) },
+ { "TODAY", tMINUTE_UNIT, 0 },
+ { "NOW", tMINUTE_UNIT, 0 },
+ { "LAST", tUNUMBER, -1 },
+ { "THIS", tUNUMBER, 0 },
+ { "NEXT", tUNUMBER, 1 },
+ { "FIRST", tUNUMBER, 1 },
+/*{ "SECOND", tUNUMBER, 2 }, */
+ { "THIRD", tUNUMBER, 3 },
+ { "FOURTH", tUNUMBER, 4 },
+ { "FIFTH", tUNUMBER, 5 },
+ { "SIXTH", tUNUMBER, 6 },
+ { "SEVENTH", tUNUMBER, 7 },
+ { "EIGHTH", tUNUMBER, 8 },
+ { "NINTH", tUNUMBER, 9 },
+ { "TENTH", tUNUMBER, 10 },
+ { "ELEVENTH", tUNUMBER, 11 },
+ { "TWELFTH", tUNUMBER, 12 },
+ { "AGO", tAGO, 1 },
+ { 0, 0, 0 }
+};
+
+/* The time zone table. This table is necessarily incomplete, as time
+ zone abbreviations are ambiguous; e.g. Australians interpret "EST"
+ as Eastern time in Australia, not as US Eastern Standard Time.
+ You cannot rely on getdate to handle arbitrary time zone
+ abbreviations; use numeric abbreviations like `-0500' instead. */
+static table const time_zone_table[] =
+{
+ { "GMT", tZONE, HOUR ( 0) }, /* Greenwich Mean */
+ { "UT", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */
+ { "UTC", tZONE, HOUR ( 0) },
+ { "WET", tZONE, HOUR ( 0) }, /* Western European */
+ { "WEST", tDAYZONE, HOUR ( 0) }, /* Western European Summer */
+ { "BST", tDAYZONE, HOUR ( 0) }, /* British Summer */
+ { "ART", tZONE, -HOUR ( 3) }, /* Argentina */
+ { "BRT", tZONE, -HOUR ( 3) }, /* Brazil */
+ { "BRST", tDAYZONE, -HOUR ( 3) }, /* Brazil Summer */
+ { "NST", tZONE, -(HOUR ( 3) + 30) }, /* Newfoundland Standard */
+ { "NDT", tDAYZONE,-(HOUR ( 3) + 30) }, /* Newfoundland Daylight */
+ { "AST", tZONE, -HOUR ( 4) }, /* Atlantic Standard */
+ { "ADT", tDAYZONE, -HOUR ( 4) }, /* Atlantic Daylight */
+ { "CLT", tZONE, -HOUR ( 4) }, /* Chile */
+ { "CLST", tDAYZONE, -HOUR ( 4) }, /* Chile Summer */
+ { "EST", tZONE, -HOUR ( 5) }, /* Eastern Standard */
+ { "EDT", tDAYZONE, -HOUR ( 5) }, /* Eastern Daylight */
+ { "CST", tZONE, -HOUR ( 6) }, /* Central Standard */
+ { "CDT", tDAYZONE, -HOUR ( 6) }, /* Central Daylight */
+ { "MST", tZONE, -HOUR ( 7) }, /* Mountain Standard */
+ { "MDT", tDAYZONE, -HOUR ( 7) }, /* Mountain Daylight */
+ { "PST", tZONE, -HOUR ( 8) }, /* Pacific Standard */
+ { "PDT", tDAYZONE, -HOUR ( 8) }, /* Pacific Daylight */
+ { "AKST", tZONE, -HOUR ( 9) }, /* Alaska Standard */
+ { "AKDT", tDAYZONE, -HOUR ( 9) }, /* Alaska Daylight */
+ { "HST", tZONE, -HOUR (10) }, /* Hawaii Standard */
+ { "HAST", tZONE, -HOUR (10) }, /* Hawaii-Aleutian Standard */
+ { "HADT", tDAYZONE, -HOUR (10) }, /* Hawaii-Aleutian Daylight */
+ { "SST", tZONE, -HOUR (12) }, /* Samoa Standard */
+ { "WAT", tZONE, HOUR ( 1) }, /* West Africa */
+ { "CET", tZONE, HOUR ( 1) }, /* Central European */
+ { "CEST", tDAYZONE, HOUR ( 1) }, /* Central European Summer */
+ { "MET", tZONE, HOUR ( 1) }, /* Middle European */
+ { "MEZ", tZONE, HOUR ( 1) }, /* Middle European */
+ { "MEST", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */
+ { "MESZ", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */
+ { "EET", tZONE, HOUR ( 2) }, /* Eastern European */
+ { "EEST", tDAYZONE, HOUR ( 2) }, /* Eastern European Summer */
+ { "CAT", tZONE, HOUR ( 2) }, /* Central Africa */
+ { "SAST", tZONE, HOUR ( 2) }, /* South Africa Standard */
+ { "EAT", tZONE, HOUR ( 3) }, /* East Africa */
+ { "MSK", tZONE, HOUR ( 3) }, /* Moscow */
+ { "MSD", tDAYZONE, HOUR ( 3) }, /* Moscow Daylight */
+ { "IST", tZONE, (HOUR ( 5) + 30) }, /* India Standard */
+ { "SGT", tZONE, HOUR ( 8) }, /* Singapore */
+ { "KST", tZONE, HOUR ( 9) }, /* Korea Standard */
+ { "JST", tZONE, HOUR ( 9) }, /* Japan Standard */
+ { "GST", tZONE, HOUR (10) }, /* Guam Standard */
+ { "NZST", tZONE, HOUR (12) }, /* New Zealand Standard */
+ { "NZDT", tDAYZONE, HOUR (12) }, /* New Zealand Daylight */
+ { 0, 0, 0 }
+};
+
+/* Military time zone table. */
+static table const military_table[] =
+{
+ { "A", tZONE, -HOUR ( 1) },
+ { "B", tZONE, -HOUR ( 2) },
+ { "C", tZONE, -HOUR ( 3) },
+ { "D", tZONE, -HOUR ( 4) },
+ { "E", tZONE, -HOUR ( 5) },
+ { "F", tZONE, -HOUR ( 6) },
+ { "G", tZONE, -HOUR ( 7) },
+ { "H", tZONE, -HOUR ( 8) },
+ { "I", tZONE, -HOUR ( 9) },
+ { "K", tZONE, -HOUR (10) },
+ { "L", tZONE, -HOUR (11) },
+ { "M", tZONE, -HOUR (12) },
+ { "N", tZONE, HOUR ( 1) },
+ { "O", tZONE, HOUR ( 2) },
+ { "P", tZONE, HOUR ( 3) },
+ { "Q", tZONE, HOUR ( 4) },
+ { "R", tZONE, HOUR ( 5) },
+ { "S", tZONE, HOUR ( 6) },
+ { "T", tZONE, HOUR ( 7) },
+ { "U", tZONE, HOUR ( 8) },
+ { "V", tZONE, HOUR ( 9) },
+ { "W", tZONE, HOUR (10) },
+ { "X", tZONE, HOUR (11) },
+ { "Y", tZONE, HOUR (12) },
+ { "Z", tZONE, HOUR ( 0) },
+ { 0, 0, 0 }
+};
+
+
+
+static int
+to_hour (int hours, int meridian)
+{
+ switch (meridian)
+ {
+ case MER24:
+ return 0 <= hours && hours < 24 ? hours : -1;
+ case MERam:
+ return 0 < hours && hours < 12 ? hours : hours == 12 ? 0 : -1;
+ case MERpm:
+ return 0 < hours && hours < 12 ? hours + 12 : hours == 12 ? 12 : -1;
+ default:
+ abort ();
+ }
+ /* NOTREACHED */
+ return 0;
+}
+
+static int
+to_year (textint textyear)
+{
+ int year = textyear.value;
+
+ if (year < 0)
+ year = -year;
+
+ /* XPG4 suggests that years 00-68 map to 2000-2068, and
+ years 69-99 map to 1969-1999. */
+ if (textyear.digits == 2)
+ year += year < 69 ? 2000 : 1900;
+
+ return year;
+}
+
+static table const *
+lookup_zone (parser_control const *pc, char const *name)
+{
+ table const *tp;
+
+ /* Try local zone abbreviations first; they're more likely to be right. */
+ for (tp = pc->local_time_zone_table; tp->name; tp++)
+ if (strcmp (name, tp->name) == 0)
+ return tp;
+
+ for (tp = time_zone_table; tp->name; tp++)
+ if (strcmp (name, tp->name) == 0)
+ return tp;
+
+ return 0;
+}
+
+#if ! HAVE_TM_GMTOFF
+/* Yield the difference between *A and *B,
+ measured in seconds, ignoring leap seconds.
+ The body of this function is taken directly from the GNU C Library;
+ see src/strftime.c. */
+static int
+tm_diff (struct tm const *a, struct tm const *b)
+{
+ /* Compute intervening leap days correctly even if year is negative.
+ Take care to avoid int overflow in leap day calculations,
+ but it's OK to assume that A and B are close to each other. */
+ int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
+ int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
+ int a100 = a4 / 25 - (a4 % 25 < 0);
+ int b100 = b4 / 25 - (b4 % 25 < 0);
+ int a400 = a100 >> 2;
+ int b400 = b100 >> 2;
+ int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+ int years = a->tm_year - b->tm_year;
+ int days = (365 * years + intervening_leap_days
+ + (a->tm_yday - b->tm_yday));
+ return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+ + (a->tm_min - b->tm_min))
+ + (a->tm_sec - b->tm_sec));
+}
+#endif /* ! HAVE_TM_GMTOFF */
+
+static table const *
+lookup_word (parser_control const *pc, char *word)
+{
+ char *p;
+ char *q;
+ size_t wordlen;
+ table const *tp;
+ int i;
+ int abbrev;
+
+ /* Make it uppercase. */
+ for (p = word; *p; p++)
+ if (ISLOWER ((unsigned char) *p))
+ *p = toupper ((unsigned char) *p);
+
+ for (tp = meridian_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+
+ /* See if we have an abbreviation for a month. */
+ wordlen = strlen (word);
+ abbrev = wordlen == 3 || (wordlen == 4 && word[3] == '.');
+
+ for (tp = month_and_day_table; tp->name; tp++)
+ if ((abbrev ? strncmp (word, tp->name, 3) : strcmp (word, tp->name)) == 0)
+ return tp;
+
+ if ((tp = lookup_zone (pc, word)))
+ return tp;
+
+ if (strcmp (word, dst_table[0].name) == 0)
+ return dst_table;
+
+ for (tp = time_units_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+
+ /* Strip off any plural and try the units table again. */
+ if (word[wordlen - 1] == 'S')
+ {
+ word[wordlen - 1] = '\0';
+ for (tp = time_units_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+ word[wordlen - 1] = 'S'; /* For "this" in relative_time_table. */
+ }
+
+ for (tp = relative_time_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+
+ /* Military time zones. */
+ if (wordlen == 1)
+ for (tp = military_table; tp->name; tp++)
+ if (word[0] == tp->name[0])
+ return tp;
+
+ /* Drop out any periods and try the time zone table again. */
+ for (i = 0, p = q = word; (*p = *q); q++)
+ if (*q == '.')
+ i = 1;
+ else
+ p++;
+ if (i && (tp = lookup_zone (pc, word)))
+ return tp;
+
+ return 0;
+}
+
+static int
+yylex (YYSTYPE *lvalp, parser_control *pc)
+{
+ unsigned char c;
+ int count;
+
+ for (;;)
+ {
+ while (c = *pc->input, ISSPACE (c))
+ pc->input++;
+
+ if (ISDIGIT (c) || c == '-' || c == '+')
+ {
+ char const *p;
+ int sign;
+ int value;
+ if (c == '-' || c == '+')
+ {
+ sign = c == '-' ? -1 : 1;
+ c = *++pc->input;
+ if (! ISDIGIT (c))
+ /* skip the '-' sign */
+ continue;
+ }
+ else
+ sign = 0;
+ p = pc->input;
+ value = 0;
+ do
+ {
+ value = 10 * value + c - '0';
+ c = *++p;
+ }
+ while (ISDIGIT (c));
+ lvalp->textintval.value = sign < 0 ? -value : value;
+ lvalp->textintval.digits = p - pc->input;
+ pc->input = p;
+ return sign ? tSNUMBER : tUNUMBER;
+ }
+
+ if (ISALPHA (c))
+ {
+ char buff[20];
+ char *p = buff;
+ table const *tp;
+
+ do
+ {
+ if (p < buff + sizeof buff - 1)
+ *p++ = c;
+ c = *++pc->input;
+ }
+ while (ISALPHA (c) || c == '.');
+
+ *p = '\0';
+ tp = lookup_word (pc, buff);
+ if (! tp)
+ return '?';
+ lvalp->intval = tp->value;
+ return tp->type;
+ }
+
+ if (c != '(')
+ return *pc->input++;
+ count = 0;
+ do
+ {
+ c = *pc->input++;
+ if (c == '\0')
+ return c;
+ if (c == '(')
+ count++;
+ else if (c == ')')
+ count--;
+ }
+ while (count > 0);
+ }
+}
+
+/* Do nothing if the parser reports an error. */
+static int
+yyerror (char *s ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+/* Parse a date/time string P. Return the corresponding time_t value,
+ or (time_t) -1 if there is an error. P can be an incomplete or
+ relative time specification; if so, use *NOW as the basis for the
+ returned time. */
+time_t
+get_date (const char *p, const time_t *now)
+{
+ time_t Start = now ? *now : time (0);
+ struct tm *tmp = localtime (&Start);
+ struct tm tm;
+ struct tm tm0;
+ parser_control pc;
+
+ if (! tmp)
+ return -1;
+
+ pc.input = p;
+ pc.year.value = tmp->tm_year + TM_YEAR_BASE;
+ pc.year.digits = 4;
+ pc.month = tmp->tm_mon + 1;
+ pc.day = tmp->tm_mday;
+ pc.hour = tmp->tm_hour;
+ pc.minutes = tmp->tm_min;
+ pc.seconds = tmp->tm_sec;
+ tm.tm_isdst = tmp->tm_isdst;
+
+ pc.meridian = MER24;
+ pc.rel_seconds = 0;
+ pc.rel_minutes = 0;
+ pc.rel_hour = 0;
+ pc.rel_day = 0;
+ pc.rel_month = 0;
+ pc.rel_year = 0;
+ pc.dates_seen = 0;
+ pc.days_seen = 0;
+ pc.rels_seen = 0;
+ pc.times_seen = 0;
+ pc.local_zones_seen = 0;
+ pc.zones_seen = 0;
+
+#if HAVE_STRUCT_TM_TM_ZONE
+ pc.local_time_zone_table[0].name = tmp->tm_zone;
+ pc.local_time_zone_table[0].type = tLOCAL_ZONE;
+ pc.local_time_zone_table[0].value = tmp->tm_isdst;
+ pc.local_time_zone_table[1].name = 0;
+
+ /* Probe the names used in the next three calendar quarters, looking
+ for a tm_isdst different from the one we already have. */
+ {
+ int quarter;
+ for (quarter = 1; quarter <= 3; quarter++)
+ {
+ time_t probe = Start + quarter * (90 * 24 * 60 * 60);
+ struct tm *probe_tm = localtime (&probe);
+ if (probe_tm && probe_tm->tm_zone
+ && probe_tm->tm_isdst != pc.local_time_zone_table[0].value)
+ {
+ {
+ pc.local_time_zone_table[1].name = probe_tm->tm_zone;
+ pc.local_time_zone_table[1].type = tLOCAL_ZONE;
+ pc.local_time_zone_table[1].value = probe_tm->tm_isdst;
+ pc.local_time_zone_table[2].name = 0;
+ }
+ break;
+ }
+ }
+ }
+#else
+#if HAVE_TZNAME
+ {
+# ifndef tzname
+ extern char *tzname[];
+# endif
+ int i;
+ for (i = 0; i < 2; i++)
+ {
+ pc.local_time_zone_table[i].name = tzname[i];
+ pc.local_time_zone_table[i].type = tLOCAL_ZONE;
+ pc.local_time_zone_table[i].value = i;
+ }
+ pc.local_time_zone_table[i].name = 0;
+ }
+#else
+ pc.local_time_zone_table[0].name = 0;
+#endif
+#endif
+
+ if (pc.local_time_zone_table[0].name && pc.local_time_zone_table[1].name
+ && ! strcmp (pc.local_time_zone_table[0].name,
+ pc.local_time_zone_table[1].name))
+ {
+ /* This locale uses the same abbrevation for standard and
+ daylight times. So if we see that abbreviation, we don't
+ know whether it's daylight time. */
+ pc.local_time_zone_table[0].value = -1;
+ pc.local_time_zone_table[1].name = 0;
+ }
+
+ if (yyparse (&pc) != 0
+ || 1 < pc.times_seen || 1 < pc.dates_seen || 1 < pc.days_seen
+ || 1 < (pc.local_zones_seen + pc.zones_seen)
+ || (pc.local_zones_seen && 1 < pc.local_isdst))
+ return -1;
+
+ tm.tm_year = to_year (pc.year) - TM_YEAR_BASE + pc.rel_year;
+ tm.tm_mon = pc.month - 1 + pc.rel_month;
+ tm.tm_mday = pc.day + pc.rel_day;
+ if (pc.times_seen || (pc.rels_seen && ! pc.dates_seen && ! pc.days_seen))
+ {
+ tm.tm_hour = to_hour (pc.hour, pc.meridian);
+ if (tm.tm_hour < 0)
+ return -1;
+ tm.tm_min = pc.minutes;
+ tm.tm_sec = pc.seconds;
+ }
+ else
+ {
+ tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+ }
+
+ /* Let mktime deduce tm_isdst if we have an absolute time stamp,
+ or if the relative time stamp mentions days, months, or years. */
+ if (pc.dates_seen | pc.days_seen | pc.times_seen | pc.rel_day
+ | pc.rel_month | pc.rel_year)
+ tm.tm_isdst = -1;
+
+ /* But if the input explicitly specifies local time with or without
+ DST, give mktime that information. */
+ if (pc.local_zones_seen)
+ tm.tm_isdst = pc.local_isdst;
+
+ tm0 = tm;
+
+ Start = mktime (&tm);
+
+ if (Start == (time_t) -1)
+ {
+
+ /* Guard against falsely reporting errors near the time_t boundaries
+ when parsing times in other time zones. For example, if the min
+ time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead
+ of UTC, then the min localtime value is 1970-01-01 08:00:00; if
+ we apply mktime to 1970-01-01 00:00:00 we will get an error, so
+ we apply mktime to 1970-01-02 08:00:00 instead and adjust the time
+ zone by 24 hours to compensate. This algorithm assumes that
+ there is no DST transition within a day of the time_t boundaries. */
+ if (pc.zones_seen)
+ {
+ tm = tm0;
+ if (tm.tm_year <= EPOCH_YEAR - TM_YEAR_BASE)
+ {
+ tm.tm_mday++;
+ pc.time_zone += 24 * 60;
+ }
+ else
+ {
+ tm.tm_mday--;
+ pc.time_zone -= 24 * 60;
+ }
+ Start = mktime (&tm);
+ }
+
+ if (Start == (time_t) -1)
+ return Start;
+ }
+
+ if (pc.days_seen && ! pc.dates_seen)
+ {
+ tm.tm_mday += ((pc.day_number - tm.tm_wday + 7) % 7
+ + 7 * (pc.day_ordinal - (0 < pc.day_ordinal)));
+ tm.tm_isdst = -1;
+ Start = mktime (&tm);
+ if (Start == (time_t) -1)
+ return Start;
+ }
+
+ if (pc.zones_seen)
+ {
+ int delta = pc.time_zone * 60;
+#ifdef HAVE_TM_GMTOFF
+ delta -= tm.tm_gmtoff;
+#else
+ struct tm *gmt = gmtime (&Start);
+ if (! gmt)
+ return -1;
+ delta -= tm_diff (&tm, gmt);
+#endif
+ if ((Start < Start - delta) != (delta < 0))
+ return -1; /* time_t overflow */
+ Start -= delta;
+ }
+
+ /* Add relative hours, minutes, and seconds. Ignore leap seconds;
+ i.e. "+ 10 minutes" means 600 seconds, even if one of them is a
+ leap second. Typically this is not what the user wants, but it's
+ too hard to do it the other way, because the time zone indicator
+ must be applied before relative times, and if mktime is applied
+ again the time zone will be lost. */
+ {
+ time_t t0 = Start;
+ long d1 = 60 * 60 * (long) pc.rel_hour;
+ time_t t1 = t0 + d1;
+ long d2 = 60 * (long) pc.rel_minutes;
+ time_t t2 = t1 + d2;
+ int d3 = pc.rel_seconds;
+ time_t t3 = t2 + d3;
+ if ((d1 / (60 * 60) ^ pc.rel_hour)
+ | (d2 / 60 ^ pc.rel_minutes)
+ | ((t0 + d1 < t0) ^ (d1 < 0))
+ | ((t1 + d2 < t1) ^ (d2 < 0))
+ | ((t2 + d3 < t2) ^ (d3 < 0)))
+ return -1;
+ Start = t3;
+ }
+
+ return Start;
+}
+
+#if TEST
+
+#include <stdio.h>
+
+int
+main (int ac, char **av)
+{
+ char buff[BUFSIZ];
+ time_t d;
+
+ printf ("Enter date, or blank line to exit.\n\t> ");
+ fflush (stdout);
+
+ buff[BUFSIZ - 1] = 0;
+ while (fgets (buff, BUFSIZ - 1, stdin) && buff[0])
+ {
+ d = get_date (buff, 0);
+ if (d == (time_t) -1)
+ printf ("Bad format - couldn't convert.\n");
+ else
+ printf ("%s", ctime (&d));
+ printf ("\t> ");
+ fflush (stdout);
+ }
+ return 0;
+}
+#endif /* defined TEST */
diff --git a/source3/modules/gpfs.c b/source3/modules/gpfs.c
new file mode 100644
index 0000000000..590dbac26f
--- /dev/null
+++ b/source3/modules/gpfs.c
@@ -0,0 +1,236 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Provide a connection to GPFS specific features
+ * Copyright (C) Volker Lendecke 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#ifdef HAVE_GPFS
+
+#include "gpfs_gpl.h"
+#include "vfs_gpfs.h"
+
+static void *libgpfs_handle = NULL;
+static bool gpfs_share_modes;
+static bool gpfs_leases;
+
+static int (*gpfs_set_share_fn)(int fd, unsigned int allow, unsigned int deny);
+static int (*gpfs_set_lease_fn)(int fd, unsigned int leaseType);
+static int (*gpfs_getacl_fn)(char *pathname, int flags, void *acl);
+static int (*gpfs_putacl_fn)(char *pathname, int flags, void *acl);
+
+
+bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask,
+ uint32 share_access)
+{
+ unsigned int allow = GPFS_SHARE_NONE;
+ unsigned int deny = GPFS_DENY_NONE;
+ int result;
+
+ if (!gpfs_share_modes) {
+ return True;
+ }
+
+ if (gpfs_set_share_fn == NULL) {
+ return False;
+ }
+
+ if ((fsp == NULL) || (fsp->fh == NULL) || (fsp->fh->fd < 0)) {
+ /* No real file, don't disturb */
+ return True;
+ }
+
+ allow |= (access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA|
+ DELETE_ACCESS)) ? GPFS_SHARE_WRITE : 0;
+ allow |= (access_mask & (FILE_READ_DATA|FILE_EXECUTE)) ?
+ GPFS_SHARE_READ : 0;
+
+ if (allow == GPFS_SHARE_NONE) {
+ DEBUG(10, ("special case am=no_access:%x\n",access_mask));
+ }
+ else {
+ deny |= (share_access & FILE_SHARE_WRITE) ?
+ 0 : GPFS_DENY_WRITE;
+ deny |= (share_access & (FILE_SHARE_READ)) ?
+ 0 : GPFS_DENY_READ;
+ }
+ DEBUG(10, ("am=%x, allow=%d, sa=%x, deny=%d\n",
+ access_mask, allow, share_access, deny));
+
+ result = gpfs_set_share_fn(fsp->fh->fd, allow, deny);
+ if (result != 0) {
+ if (errno == ENOSYS) {
+ DEBUG(5, ("VFS module vfs_gpfs loaded, but no gpfs "
+ "support has been compiled into Samba. Allowing access\n"));
+ return True;
+ } else {
+ DEBUG(10, ("gpfs_set_share failed: %s\n",
+ strerror(errno)));
+ }
+ }
+
+ return (result == 0);
+}
+
+int set_gpfs_lease(int fd, int leasetype)
+{
+ int gpfs_type = GPFS_LEASE_NONE;
+
+ if (!gpfs_leases) {
+ return True;
+ }
+
+ if (gpfs_set_lease_fn == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (leasetype == F_RDLCK) {
+ gpfs_type = GPFS_LEASE_READ;
+ }
+ if (leasetype == F_WRLCK) {
+ gpfs_type = GPFS_LEASE_WRITE;
+ }
+
+ /* we unconditionally set CAP_LEASE, rather than looking for
+ -1/EACCES as there is a bug in some versions of
+ libgpfs_gpl.so which results in a leaked fd on /dev/ss0
+ each time we try this with the wrong capabilities set
+ */
+ linux_set_lease_capability();
+ return gpfs_set_lease_fn(fd, gpfs_type);
+}
+
+int smbd_gpfs_getacl(char *pathname, int flags, void *acl)
+{
+ if (gpfs_getacl_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_getacl_fn(pathname, flags, acl);
+}
+
+int smbd_gpfs_putacl(char *pathname, int flags, void *acl)
+{
+ if (gpfs_putacl_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_putacl_fn(pathname, flags, acl);
+}
+
+void init_gpfs(void)
+{
+ if (libgpfs_handle != NULL) {
+ return;
+ }
+
+ libgpfs_handle = sys_dlopen("libgpfs_gpl.so", RTLD_LAZY);
+
+ if (libgpfs_handle == NULL) {
+ DEBUG(10, ("sys_dlopen for libgpfs_gpl failed: %s\n",
+ strerror(errno)));
+ return;
+ }
+
+ DEBUG(10, ("libgpfs_gpl.so loaded\n"));
+
+ gpfs_set_share_fn = sys_dlsym(libgpfs_handle, "gpfs_set_share");
+ if (gpfs_set_share_fn == NULL) {
+ DEBUG(3, ("libgpfs_gpl.so does not contain the symbol "
+ "'gpfs_set_share'\n"));
+ goto failed;
+ }
+
+ gpfs_set_lease_fn = sys_dlsym(libgpfs_handle, "gpfs_set_lease");
+ if (gpfs_set_lease_fn == NULL) {
+ DEBUG(3, ("libgpfs_gpl.so does not contain the symbol "
+ "'gpfs_set_lease'\n"));
+ sys_dlclose(libgpfs_handle);
+
+ goto failed;
+ }
+
+ gpfs_getacl_fn = sys_dlsym(libgpfs_handle, "gpfs_getacl");
+ if (gpfs_getacl_fn == NULL) {
+ DEBUG(3, ("libgpfs_gpl.so does not contain the symbol "
+ "'gpfs_getacl'\n"));
+ goto failed;
+ }
+
+ gpfs_putacl_fn = sys_dlsym(libgpfs_handle, "gpfs_putacl");
+ if (gpfs_putacl_fn == NULL) {
+ DEBUG(3, ("libgpfs_gpl.so does not contain the symbol "
+ "'gpfs_putacl'\n"));
+ goto failed;
+ }
+
+ gpfs_share_modes = lp_parm_bool(-1, "gpfs", "sharemodes", True);
+ gpfs_leases = lp_parm_bool(-1, "gpfs", "leases", True);
+
+ return;
+
+failed:
+ sys_dlclose(libgpfs_handle);
+ /* leave libgpfs_handle != NULL around, no point
+ in trying twice */
+ gpfs_set_share_fn = NULL;
+ gpfs_set_lease_fn = NULL;
+ gpfs_getacl_fn = NULL;
+ gpfs_putacl_fn = NULL;
+}
+
+#else
+
+int set_gpfs_lease(int snum, int leasetype)
+{
+ DEBUG(0, ("'VFS module smbgpfs loaded, without gpfs support compiled\n"));
+
+ /* We need to indicate that no GPFS is around by returning ENOSYS, so
+ * that the normal linux kernel oplock code is called. */
+ errno = ENOSYS;
+ return -1;
+}
+
+bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask,
+ uint32 share_access)
+{
+ DEBUG(0, ("VFS module - smbgpfs.so loaded, without gpfs support compiled\n"));
+ /* Don't disturb but complain */
+ return True;
+}
+
+int smbd_gpfs_getacl(char *pathname, int flags, void *acl)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int smbd_gpfs_putacl(char *pathname, int flags, void *acl)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+void init_gpfs(void)
+{
+ return;
+}
+
+#endif /* HAVE_GPFS */
diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c
new file mode 100644
index 0000000000..9e28db8b39
--- /dev/null
+++ b/source3/modules/nfs4_acls.c
@@ -0,0 +1,792 @@
+/*
+ * NFS4 ACL handling
+ *
+ * Copyright (C) Jim McDonough, 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "nfs4_acls.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_ACLS
+
+#define SMBACL4_PARAM_TYPE_NAME "nfs4"
+
+extern const struct generic_mapping file_generic_mapping;
+
+#define SMB_ACE4_INT_MAGIC 0x76F8A967
+typedef struct _SMB_ACE4_INT_T
+{
+ uint32 magic;
+ SMB_ACE4PROP_T prop;
+ void *next;
+} SMB_ACE4_INT_T;
+
+#define SMB_ACL4_INT_MAGIC 0x29A3E792
+typedef struct _SMB_ACL4_INT_T
+{
+ uint32 magic;
+ uint32 naces;
+ SMB_ACE4_INT_T *first;
+ SMB_ACE4_INT_T *last;
+} SMB_ACL4_INT_T;
+
+extern int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid);
+extern NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp,
+ uint32 security_info_sent, SEC_DESC *psd);
+
+static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *acl)
+{
+ SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)acl;
+ if (acl==NULL)
+ {
+ DEBUG(2, ("acl is NULL\n"));
+ errno = EINVAL;
+ return NULL;
+ }
+ if (aclint->magic!=SMB_ACL4_INT_MAGIC)
+ {
+ DEBUG(2, ("aclint bad magic 0x%x\n", aclint->magic));
+ errno = EINVAL;
+ return NULL;
+ }
+ return aclint;
+}
+
+static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace)
+{
+ SMB_ACE4_INT_T *aceint = (SMB_ACE4_INT_T *)ace;
+ if (ace==NULL)
+ {
+ DEBUG(2, ("ace is NULL\n"));
+ errno = EINVAL;
+ return NULL;
+ }
+ if (aceint->magic!=SMB_ACE4_INT_MAGIC)
+ {
+ DEBUG(2, ("aceint bad magic 0x%x\n", aceint->magic));
+ errno = EINVAL;
+ return NULL;
+ }
+ return aceint;
+}
+
+SMB4ACL_T *smb_create_smb4acl(void)
+{
+ TALLOC_CTX *mem_ctx = talloc_tos();
+ SMB_ACL4_INT_T *acl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(mem_ctx, sizeof(SMB_ACL4_INT_T));
+ if (acl==NULL)
+ {
+ DEBUG(0, ("TALLOC_SIZE failed\n"));
+ errno = ENOMEM;
+ return NULL;
+ }
+ acl->magic = SMB_ACL4_INT_MAGIC;
+ /* acl->first, last = NULL not needed */
+ return (SMB4ACL_T *)acl;
+}
+
+SMB4ACE_T *smb_add_ace4(SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
+{
+ SMB_ACL4_INT_T *aclint = get_validated_aclint(acl);
+ TALLOC_CTX *mem_ctx = talloc_tos();
+ SMB_ACE4_INT_T *ace;
+
+ ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(mem_ctx, sizeof(SMB_ACE4_INT_T));
+ if (ace==NULL)
+ {
+ DEBUG(0, ("TALLOC_SIZE failed\n"));
+ errno = ENOMEM;
+ return NULL;
+ }
+ ace->magic = SMB_ACE4_INT_MAGIC;
+ /* ace->next = NULL not needed */
+ memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
+
+ if (aclint->first==NULL)
+ {
+ aclint->first = ace;
+ aclint->last = ace;
+ } else {
+ aclint->last->next = (void *)ace;
+ aclint->last = ace;
+ }
+ aclint->naces++;
+
+ return (SMB4ACE_T *)ace;
+}
+
+SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
+{
+ SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
+ if (aceint==NULL)
+ return NULL;
+
+ return &aceint->prop;
+}
+
+SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
+{
+ SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
+ if (aceint==NULL)
+ return NULL;
+
+ return (SMB4ACE_T *)aceint->next;
+}
+
+SMB4ACE_T *smb_first_ace4(SMB4ACL_T *acl)
+{
+ SMB_ACL4_INT_T *aclint = get_validated_aclint(acl);
+ if (aclint==NULL)
+ return NULL;
+
+ return (SMB4ACE_T *)aclint->first;
+}
+
+uint32 smb_get_naces(SMB4ACL_T *acl)
+{
+ SMB_ACL4_INT_T *aclint = get_validated_aclint(acl);
+ if (aclint==NULL)
+ return 0;
+
+ return aclint->naces;
+}
+
+static int smbacl4_GetFileOwner(struct connection_struct *conn,
+ const char *filename,
+ SMB_STRUCT_STAT *psbuf)
+{
+ memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
+
+ /* Get the stat struct for the owner info. */
+ if (SMB_VFS_STAT(conn, filename, psbuf) != 0)
+ {
+ DEBUG(8, ("SMB_VFS_STAT failed with error %s\n",
+ strerror(errno)));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
+{
+ memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
+
+ if (fsp->is_directory || fsp->fh->fd == -1) {
+ return smbacl4_GetFileOwner(fsp->conn, fsp->fsp_name, psbuf);
+ }
+ if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
+ {
+ DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
+ strerror(errno)));
+ return -1;
+ }
+
+ return 0;
+}
+
+static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *acl, /* in */
+ DOM_SID *psid_owner, /* in */
+ DOM_SID *psid_group, /* in */
+ SEC_ACE **ppnt_ace_list, /* out */
+ int *pgood_aces /* out */
+)
+{
+ SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)acl;
+ SMB_ACE4_INT_T *aceint;
+ SEC_ACE *nt_ace_list = NULL;
+ int good_aces = 0;
+
+ DEBUG(10, ("smbacl_nfs42win entered"));
+
+ aclint = get_validated_aclint(acl);
+ /* We do not check for naces being 0 or acl being NULL here because it is done upstream */
+ /* in smb_get_nt_acl_nfs4(). */
+ nt_ace_list = (SEC_ACE *)TALLOC_ZERO_SIZE(mem_ctx, aclint->naces * sizeof(SEC_ACE));
+ if (nt_ace_list==NULL)
+ {
+ DEBUG(10, ("talloc error"));
+ errno = ENOMEM;
+ return False;
+ }
+
+ for (aceint=aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
+ SEC_ACCESS mask;
+ DOM_SID sid;
+ SMB_ACE4PROP_T *ace = &aceint->prop;
+
+ DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, mask: %x, "
+ "who: %d\n", aceint->magic, ace->aceType, ace->flags,
+ ace->aceFlags, ace->aceMask, ace->who.id));
+
+ SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
+
+ if (ace->flags & SMB_ACE4_ID_SPECIAL) {
+ switch (ace->who.special_id) {
+ case SMB_ACE4_WHO_OWNER:
+ sid_copy(&sid, psid_owner);
+ break;
+ case SMB_ACE4_WHO_GROUP:
+ sid_copy(&sid, psid_group);
+ break;
+ case SMB_ACE4_WHO_EVERYONE:
+ sid_copy(&sid, &global_sid_World);
+ break;
+ default:
+ DEBUG(8, ("invalid special who id %d "
+ "ignored\n", ace->who.special_id));
+ }
+ } else {
+ if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
+ gid_to_sid(&sid, ace->who.gid);
+ } else {
+ uid_to_sid(&sid, ace->who.uid);
+ }
+ }
+ DEBUG(10, ("mapped %d to %s\n", ace->who.id,
+ sid_string_dbg(&sid)));
+
+ init_sec_access(&mask, ace->aceMask);
+ init_sec_ace(&nt_ace_list[good_aces++], &sid,
+ ace->aceType, mask,
+ ace->aceFlags & 0xf);
+ }
+
+ *ppnt_ace_list = nt_ace_list;
+ *pgood_aces = good_aces;
+
+ return True;
+}
+
+static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
+ uint32 security_info,
+ SEC_DESC **ppdesc, SMB4ACL_T *acl)
+{
+ int good_aces = 0;
+ DOM_SID sid_owner, sid_group;
+ size_t sd_size = 0;
+ SEC_ACE *nt_ace_list = NULL;
+ SEC_ACL *psa = NULL;
+ TALLOC_CTX *mem_ctx = talloc_tos();
+
+ if (acl==NULL || smb_get_naces(acl)==0)
+ return NT_STATUS_ACCESS_DENIED; /* special because we
+ * shouldn't alloc 0 for
+ * win */
+
+ uid_to_sid(&sid_owner, sbuf->st_uid);
+ gid_to_sid(&sid_group, sbuf->st_gid);
+
+ if (smbacl4_nfs42win(mem_ctx, acl, &sid_owner, &sid_group, &nt_ace_list, &good_aces)==False) {
+ DEBUG(8,("smbacl4_nfs42win failed\n"));
+ return map_nt_error_from_unix(errno);
+ }
+
+ psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, good_aces, nt_ace_list);
+ if (psa == NULL) {
+ DEBUG(2,("make_sec_acl failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(10,("after make sec_acl\n"));
+ *ppdesc = make_sec_desc(mem_ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
+ (security_info & OWNER_SECURITY_INFORMATION) ? &sid_owner : NULL,
+ (security_info & GROUP_SECURITY_INFORMATION) ? &sid_group : NULL,
+ NULL, psa, &sd_size);
+ if (*ppdesc==NULL) {
+ DEBUG(2,("make_sec_desc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with sd_size %d\n",
+ ndr_size_security_descriptor(*ppdesc, 0)));
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
+ uint32 security_info,
+ SEC_DESC **ppdesc, SMB4ACL_T *acl)
+{
+ SMB_STRUCT_STAT sbuf;
+
+ DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp->fsp_name));
+
+ if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, acl);
+}
+
+NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
+ const char *name,
+ uint32 security_info,
+ SEC_DESC **ppdesc, SMB4ACL_T *acl)
+{
+ SMB_STRUCT_STAT sbuf;
+
+ DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
+
+ if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, acl);
+}
+
+enum smbacl4_mode_enum {e_simple=0, e_special=1};
+enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
+
+typedef struct _smbacl4_vfs_params {
+ enum smbacl4_mode_enum mode;
+ bool do_chown;
+ enum smbacl4_acedup_enum acedup;
+ struct db_context *sid_mapping_table;
+} smbacl4_vfs_params;
+
+/*
+ * Gather special parameters for NFS4 ACL handling
+ */
+static int smbacl4_get_vfs_params(
+ const char *type_name,
+ files_struct *fsp,
+ smbacl4_vfs_params *params
+)
+{
+ static const struct enum_list enum_smbacl4_modes[] = {
+ { e_simple, "simple" },
+ { e_special, "special" }
+ };
+ static const struct enum_list enum_smbacl4_acedups[] = {
+ { e_dontcare, "dontcare" },
+ { e_reject, "reject" },
+ { e_ignore, "ignore" },
+ { e_merge, "merge" },
+ };
+
+ memset(params, 0, sizeof(smbacl4_vfs_params));
+ params->mode = (enum smbacl4_mode_enum)lp_parm_enum(
+ SNUM(fsp->conn), type_name,
+ "mode", enum_smbacl4_modes, e_simple);
+ params->do_chown = lp_parm_bool(SNUM(fsp->conn), type_name,
+ "chown", True);
+ params->acedup = (enum smbacl4_acedup_enum)lp_parm_enum(
+ SNUM(fsp->conn), type_name,
+ "acedup", enum_smbacl4_acedups, e_dontcare);
+
+ DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s\n",
+ enum_smbacl4_modes[params->mode].name,
+ params->do_chown ? "true" : "false",
+ enum_smbacl4_acedups[params->acedup].name));
+
+ return 0;
+}
+
+static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *acl)
+{
+ SMB_ACL4_INT_T *aclint = get_validated_aclint(acl);
+ SMB_ACE4_INT_T *aceint;
+
+ DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
+
+ for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
+ SMB_ACE4PROP_T *ace = &aceint->prop;
+
+ DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, mask=0x%x, id=%d\n",
+ ace->aceType,
+ ace->aceFlags, ace->flags,
+ ace->aceMask,
+ ace->who.id));
+ }
+}
+
+/*
+ * Find 2 NFS4 who-special ACE property (non-copy!!!)
+ * match nonzero if "special" and who is equal
+ * return ace if found matching; otherwise NULL
+ */
+static SMB_ACE4PROP_T *smbacl4_find_equal_special(
+ SMB4ACL_T *acl,
+ SMB_ACE4PROP_T *aceNew)
+{
+ SMB_ACL4_INT_T *aclint = get_validated_aclint(acl);
+ SMB_ACE4_INT_T *aceint;
+
+ for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
+ SMB_ACE4PROP_T *ace = &aceint->prop;
+
+ if (ace->flags == aceNew->flags &&
+ ace->aceType==aceNew->aceType &&
+ (ace->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)==
+ (aceNew->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)
+ ) {
+ /* keep type safety; e.g. gid is an u.short */
+ if (ace->flags & SMB_ACE4_ID_SPECIAL)
+ {
+ if (ace->who.special_id==aceNew->who.special_id)
+ return ace;
+ } else {
+ if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
+ {
+ if (ace->who.gid==aceNew->who.gid)
+ return ace;
+ } else {
+ if (ace->who.uid==aceNew->who.uid)
+ return ace;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static bool nfs4_map_sid(smbacl4_vfs_params *params, const DOM_SID *src,
+ DOM_SID *dst)
+{
+ static struct db_context *mapping_db = NULL;
+ TDB_DATA data;
+
+ if (mapping_db == NULL) {
+ const char *dbname = lp_parm_const_string(
+ -1, SMBACL4_PARAM_TYPE_NAME, "sidmap", NULL);
+
+ if (dbname == NULL) {
+ DEBUG(10, ("%s:sidmap not defined\n",
+ SMBACL4_PARAM_TYPE_NAME));
+ return False;
+ }
+
+ become_root();
+ mapping_db = db_open(NULL, dbname, 0, TDB_DEFAULT,
+ O_RDONLY, 0600);
+ unbecome_root();
+
+ if (mapping_db == NULL) {
+ DEBUG(1, ("could not open sidmap: %s\n",
+ strerror(errno)));
+ return False;
+ }
+ }
+
+ if (mapping_db->fetch(mapping_db, NULL,
+ string_term_tdb_data(sid_string_tos(src)),
+ &data) == -1) {
+ DEBUG(10, ("could not find mapping for SID %s\n",
+ sid_string_dbg(src)));
+ return False;
+ }
+
+ if ((data.dptr == NULL) || (data.dsize <= 0)
+ || (data.dptr[data.dsize-1] != '\0')) {
+ DEBUG(5, ("invalid mapping for SID %s\n",
+ sid_string_dbg(src)));
+ TALLOC_FREE(data.dptr);
+ return False;
+ }
+
+ if (!string_to_sid(dst, (char *)data.dptr)) {
+ DEBUG(1, ("invalid mapping %s for SID %s\n",
+ (char *)data.dptr, sid_string_dbg(src)));
+ TALLOC_FREE(data.dptr);
+ return False;
+ }
+
+ TALLOC_FREE(data.dptr);
+
+ return True;
+}
+
+static bool smbacl4_fill_ace4(
+ TALLOC_CTX *mem_ctx,
+ const char *filename,
+ smbacl4_vfs_params *params,
+ uid_t ownerUID,
+ gid_t ownerGID,
+ SEC_ACE *ace_nt, /* input */
+ SMB_ACE4PROP_T *ace_v4 /* output */
+)
+{
+ DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
+
+ memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
+ ace_v4->aceType = ace_nt->type; /* only ACCESS|DENY supported right now */
+ ace_v4->aceFlags = ace_nt->flags & SEC_ACE_FLAG_VALID_INHERIT;
+ ace_v4->aceMask = ace_nt->access_mask &
+ (STD_RIGHT_ALL_ACCESS | SA_RIGHT_FILE_ALL_ACCESS);
+
+ se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
+
+ if (ace_v4->aceFlags!=ace_nt->flags)
+ DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
+ ace_v4->aceFlags, ace_nt->flags));
+
+ if (ace_v4->aceMask!=ace_nt->access_mask)
+ DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
+ ace_v4->aceMask, ace_nt->access_mask));
+
+ if (sid_equal(&ace_nt->trustee, &global_sid_World)) {
+ ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
+ ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
+ } else {
+ const char *dom, *name;
+ enum lsa_SidType type;
+ uid_t uid;
+ gid_t gid;
+ DOM_SID sid;
+
+ sid_copy(&sid, &ace_nt->trustee);
+
+ if (!lookup_sid(mem_ctx, &sid, &dom, &name, &type)) {
+
+ DOM_SID mapped;
+
+ if (!nfs4_map_sid(params, &sid, &mapped)) {
+ DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
+ "unknown\n", filename, sid_string_dbg(&sid)));
+ errno = EINVAL;
+ return False;
+ }
+
+ DEBUG(2, ("nfs4_acls.c: file [%s]: mapped SID %s "
+ "to %s\n", filename, sid_string_dbg(&sid), sid_string_dbg(&mapped)));
+
+ if (!lookup_sid(mem_ctx, &mapped, &dom,
+ &name, &type)) {
+ DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
+ "mapped from %s is unknown\n",
+ filename, sid_string_dbg(&mapped), sid_string_dbg(&sid)));
+ errno = EINVAL;
+ return False;
+ }
+
+ sid_copy(&sid, &mapped);
+ }
+
+ if (type == SID_NAME_USER) {
+ if (!sid_to_uid(&sid, &uid)) {
+ DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
+ "convert %s to uid\n", filename,
+ sid_string_dbg(&sid)));
+ return False;
+ }
+
+ if (params->mode==e_special && uid==ownerUID) {
+ ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
+ ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
+ } else {
+ ace_v4->who.uid = uid;
+ }
+ } else { /* else group? - TODO check it... */
+ if (!sid_to_gid(&sid, &gid)) {
+ DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
+ "convert %s to gid\n", filename,
+ sid_string_dbg(&sid)));
+ return False;
+ }
+
+ ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
+
+ if (params->mode==e_special && gid==ownerGID) {
+ ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
+ ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
+ } else {
+ ace_v4->who.gid = gid;
+ }
+ }
+ }
+
+ return True; /* OK */
+}
+
+static int smbacl4_MergeIgnoreReject(
+ enum smbacl4_acedup_enum acedup,
+ SMB4ACL_T *acl, /* may modify it */
+ SMB_ACE4PROP_T *ace, /* the "new" ACE */
+ bool *paddNewACE,
+ int i
+)
+{
+ int result = 0;
+ SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(acl, ace);
+ if (ace4found)
+ {
+ switch(acedup)
+ {
+ case e_merge: /* "merge" flags */
+ *paddNewACE = False;
+ ace4found->aceFlags |= ace->aceFlags;
+ ace4found->aceMask |= ace->aceMask;
+ break;
+ case e_ignore: /* leave out this record */
+ *paddNewACE = False;
+ break;
+ case e_reject: /* do an error */
+ DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
+ errno = EINVAL; /* SHOULD be set on any _real_ error */
+ result = -1;
+ break;
+ default:
+ break;
+ }
+ }
+ return result;
+}
+
+static SMB4ACL_T *smbacl4_win2nfs4(
+ const char *filename,
+ SEC_ACL *dacl,
+ smbacl4_vfs_params *pparams,
+ uid_t ownerUID,
+ gid_t ownerGID
+)
+{
+ SMB4ACL_T *acl;
+ uint32 i;
+ TALLOC_CTX *mem_ctx = talloc_tos();
+
+ DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
+
+ acl = smb_create_smb4acl();
+ if (acl==NULL)
+ return NULL;
+
+ for(i=0; i<dacl->num_aces; i++) {
+ SMB_ACE4PROP_T ace_v4;
+ bool addNewACE = True;
+
+ if (!smbacl4_fill_ace4(mem_ctx, filename, pparams,
+ ownerUID, ownerGID,
+ dacl->aces + i, &ace_v4)) {
+ DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
+ filename,
+ sid_string_dbg(&((dacl->aces+i)->trustee))));
+ continue;
+ }
+
+ if (pparams->acedup!=e_dontcare) {
+ if (smbacl4_MergeIgnoreReject(pparams->acedup, acl,
+ &ace_v4, &addNewACE, i))
+ return NULL;
+ }
+
+ if (addNewACE)
+ smb_add_ace4(acl, &ace_v4);
+ }
+
+ return acl;
+}
+
+NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
+ uint32 security_info_sent,
+ SEC_DESC *psd,
+ set_nfs4acl_native_fn_t set_nfs4_native)
+{
+ smbacl4_vfs_params params;
+ SMB4ACL_T *acl = NULL;
+ bool result;
+
+ SMB_STRUCT_STAT sbuf;
+ bool need_chown = False;
+ uid_t newUID = (uid_t)-1;
+ gid_t newGID = (gid_t)-1;
+
+ DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp->fsp_name));
+
+ if ((security_info_sent & (DACL_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION)) == 0)
+ {
+ DEBUG(9, ("security_info_sent (0x%x) ignored\n",
+ security_info_sent));
+ return NT_STATUS_OK; /* won't show error - later to be refined... */
+ }
+
+ /* Special behaviours */
+ if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp, &params))
+ return NT_STATUS_NO_MEMORY;
+
+ if (smbacl4_fGetFileOwner(fsp, &sbuf))
+ return map_nt_error_from_unix(errno);
+
+ if (params.do_chown) {
+ /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
+ NTSTATUS status = unpack_nt_owners(SNUM(fsp->conn), &newUID, &newGID, security_info_sent, psd);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(8, ("unpack_nt_owners failed"));
+ return status;
+ }
+ if (((newUID != (uid_t)-1) && (sbuf.st_uid != newUID)) ||
+ ((newGID != (gid_t)-1) && (sbuf.st_gid != newGID))) {
+ need_chown = True;
+ }
+ if (need_chown) {
+ if ((newUID == (uid_t)-1
+ || newUID == fsp->conn->server_info->utok.uid)) {
+ if(try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) {
+ DEBUG(3,("chown %s, %u, %u failed. Error = %s.\n",
+ fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID,
+ strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+
+ DEBUG(10,("chown %s, %u, %u succeeded.\n",
+ fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
+ if (smbacl4_GetFileOwner(fsp->conn, fsp->fsp_name, &sbuf))
+ return map_nt_error_from_unix(errno);
+ need_chown = False;
+ } else { /* chown is needed, but _after_ changing acl */
+ sbuf.st_uid = newUID; /* OWNER@ in case of e_special */
+ sbuf.st_gid = newGID; /* GROUP@ in case of e_special */
+ }
+ }
+ }
+
+ if ((security_info_sent & DACL_SECURITY_INFORMATION)!=0 && psd->dacl!=NULL)
+ {
+ acl = smbacl4_win2nfs4(fsp->fsp_name, psd->dacl, &params, sbuf.st_uid, sbuf.st_gid);
+ if (!acl)
+ return map_nt_error_from_unix(errno);
+
+ smbacl4_dump_nfs4acl(10, acl);
+
+ result = set_nfs4_native(fsp, acl);
+ if (result!=True)
+ {
+ DEBUG(10, ("set_nfs4_native failed with %s\n", strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+ } else
+ DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n", security_info_sent));
+
+ /* Any chown pending? */
+ if (need_chown) {
+ DEBUG(3,("chown#2 %s. uid = %u, gid = %u.\n",
+ fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
+ if (try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) {
+ DEBUG(2,("chown#2 %s, %u, %u failed. Error = %s.\n",
+ fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID,
+ strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+ DEBUG(10,("chown#2 %s, %u, %u succeeded.\n",
+ fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
+ }
+
+ DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
+ return NT_STATUS_OK;
+}
diff --git a/source3/modules/nfs4_acls.h b/source3/modules/nfs4_acls.h
new file mode 100644
index 0000000000..0f783aa977
--- /dev/null
+++ b/source3/modules/nfs4_acls.h
@@ -0,0 +1,150 @@
+/*
+ * NFS4 ACL handling
+ *
+ * Copyright (C) Jim McDonough, 2006
+ * Reused & renamed some parts of AIX 5.3 sys/acl.h structures
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NFS4_ACLS_H__
+#define __NFS4_ACLS_H__
+
+#define SMB_ACLTYPE_NONE 0
+#define SMB_ACLTYPE_UNKNOWN 1
+#define SMB_ACLTYPE_POSIX 2
+#define SMB_ACLTYPE_NFS4 4
+
+/*
+ * Following union captures the identity as
+ * used in the NFS4 ACL structures.
+ */
+typedef union _SMB_NFS4_ACEWHOID_T {
+ uid_t uid; /* User id */
+ gid_t gid; /* Group id */
+ uint32 special_id; /* Identifies special identities in NFS4 */
+
+#define SMB_ACE4_WHO_OWNER 0x00000001 /*The owner of the file. */
+#define SMB_ACE4_WHO_GROUP 0x00000002 /*The group associated with the file. */
+#define SMB_ACE4_WHO_EVERYONE 0x00000003 /*The world. */
+#define SMB_ACE4_WHO_INTERACTIVE 0x00000004 /*Accessed from an interactive terminal. */
+#define SMB_ACE4_WHO_NETWORK 0x00000005 /*Accessed via the network. */
+#define SMB_ACE4_WHO_DIALUP 0x00000006 /*Accessed as a dialup user to the server. */
+#define SMB_ACE4_WHO_BATCH 0x00000007 /*Accessed from a batch job. */
+#define SMB_ACE4_WHO_ANONYMOUS 0x00000008 /*Accessed without any authentication. */
+#define SMB_ACE4_WHO_AUTHENTICATED 0x00000009 /*Any authenticated user (opposite of ANONYMOUS) */
+#define SMB_ACE4_WHO_SERVICE 0x0000000A /*Access from a system service. */
+#define SMB_ACE4_WHO_MAX SMB_ACE4_WHO_SERVICE /* largest valid ACE4_WHO */
+ uint32 id;
+} SMB_NFS4_ACEWHOID_T;
+
+typedef struct _SMB_ACE4PROP_T {
+ uint32 flags; /* Bit mask defining details of ACE */
+/*The following are constants for flags field */
+/* #define SMB_ACE4_ID_NOT_VALID 0x00000001 - from aix/jfs2 */
+#define SMB_ACE4_ID_SPECIAL 0x00000002
+
+ SMB_NFS4_ACEWHOID_T who; /* Identifies to whom this ACE applies */
+
+ /* The following part of ACE has the same layout as NFSv4 wire format. */
+
+ uint32 aceType; /* Type of ACE PERMIT/ALLOW etc*/
+/*The constants used for the type field (acetype4) are as follows: */
+#define SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE 0x00000000
+#define SMB_ACE4_ACCESS_DENIED_ACE_TYPE 0x00000001
+#define SMB_ACE4_SYSTEM_AUDIT_ACE_TYPE 0x00000002
+#define SMB_ACE4_SYSTEM_ALARM_ACE_TYPE 0x00000003
+#define SMB_ACE4_MAX_TYPE ACE4_SYSTEM_ALARM_ACE_TYPE /* largest valid ACE4_TYPE */
+
+ uint32 aceFlags; /* Controls Inheritance and such */
+/*The bitmask constants used for the flag field are as follows: */
+#define SMB_ACE4_FILE_INHERIT_ACE 0x00000001
+#define SMB_ACE4_DIRECTORY_INHERIT_ACE 0x00000002
+#define SMB_ACE4_NO_PROPAGATE_INHERIT_ACE 0x00000004
+#define SMB_ACE4_INHERIT_ONLY_ACE 0x00000008
+#define SMB_ACE4_SUCCESSFUL_ACCESS_ACE_FLAG 0x00000010
+#define SMB_ACE4_FAILED_ACCESS_ACE_FLAG 0x00000020
+#define SMB_ACE4_IDENTIFIER_GROUP 0x00000040
+#define SMB_ACE4_ALL_FLAGS ( SMB_ACE4_FILE_INHERIT_ACE | SMB_ACE4_DIRECTORY_INHERIT_ACE \
+| SMB_ACE4_NO_PROPAGATE_INHERIT_ACE | SMB_ACE4_INHERIT_ONLY_ACE | SMB_ACE4_SUCCESSFUL_ACCESS_ACE_FLAG \
+| SMB_ACE4_FAILED_ACCESS_ACE_FLAG | SMB_ACE4_IDENTIFIER_GROUP )
+
+ uint32 aceMask; /* Access rights */
+/*The bitmask constants used for the access mask field are as follows: */
+#define SMB_ACE4_READ_DATA 0x00000001
+#define SMB_ACE4_LIST_DIRECTORY 0x00000001
+#define SMB_ACE4_WRITE_DATA 0x00000002
+#define SMB_ACE4_ADD_FILE 0x00000002
+#define SMB_ACE4_APPEND_DATA 0x00000004
+#define SMB_ACE4_ADD_SUBDIRECTORY 0x00000004
+#define SMB_ACE4_READ_NAMED_ATTRS 0x00000008
+#define SMB_ACE4_WRITE_NAMED_ATTRS 0x00000010
+#define SMB_ACE4_EXECUTE 0x00000020
+#define SMB_ACE4_DELETE_CHILD 0x00000040
+#define SMB_ACE4_READ_ATTRIBUTES 0x00000080
+#define SMB_ACE4_WRITE_ATTRIBUTES 0x00000100
+#define SMB_ACE4_DELETE 0x00010000
+#define SMB_ACE4_READ_ACL 0x00020000
+#define SMB_ACE4_WRITE_ACL 0x00040000
+#define SMB_ACE4_WRITE_OWNER 0x00080000
+#define SMB_ACE4_SYNCHRONIZE 0x00100000
+#define SMB_ACE4_ALL_MASKS ( SMB_ACE4_READ_DATA | SMB_ACE4_LIST_DIRECTORY \
+| SMB_ACE4_WRITE_DATA | SMB_ACE4_ADD_FILE | SMB_ACE4_APPEND_DATA | SMB_ACE4_ADD_SUBDIRECTORY \
+| SMB_ACE4_READ_NAMED_ATTRS | SMB_ACE4_WRITE_NAMED_ATTRS | SMB_ACE4_EXECUTE | SMB_ACE4_DELETE_CHILD \
+| SMB_ACE4_READ_ATTRIBUTES | SMB_ACE4_WRITE_ATTRIBUTES | SMB_ACE4_DELETE | SMB_ACE4_READ_ACL \
+| SMB_ACE4_WRITE_ACL | SMB_ACE4_WRITE_OWNER | SMB_ACE4_SYNCHRONIZE )
+} SMB_ACE4PROP_T;
+
+/*
+ * Never allocate these structures on your own
+ * use create_smb4acl instead
+ */
+typedef struct _SMB4ACL_T {char dontuse;} SMB4ACL_T;
+typedef struct _SMB4ACE_T {char dontuse;} SMB4ACE_T;
+
+SMB4ACL_T *smb_create_smb4acl(void);
+
+/* prop's contents are copied */
+/* it doesn't change the order, appends */
+SMB4ACE_T *smb_add_ace4(SMB4ACL_T *acl, SMB_ACE4PROP_T *prop);
+
+SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace);
+
+/* Returns NULL if none - or error */
+SMB4ACE_T *smb_first_ace4(SMB4ACL_T *acl);
+
+/* Returns NULL in the end - or error */
+SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace);
+
+uint32 smb_get_naces(SMB4ACL_T *acl);
+
+NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
+ uint32 security_info,
+ SEC_DESC **ppdesc, SMB4ACL_T *acl);
+
+NTSTATUS smb_get_nt_acl_nfs4(connection_struct *conn,
+ const char *name,
+ uint32 security_info,
+ SEC_DESC **ppdesc, SMB4ACL_T *acl);
+
+/* Callback function needed to set the native acl
+ * when applicable */
+typedef bool (*set_nfs4acl_native_fn_t)(files_struct *, SMB4ACL_T *);
+
+NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
+ uint32 security_info_sent,
+ SEC_DESC *psd,
+ set_nfs4acl_native_fn_t set_nfs4_native);
+
+#endif /* __NFS4_ACLS_H__ */
diff --git a/source3/modules/vfs_afsacl.c b/source3/modules/vfs_afsacl.c
new file mode 100644
index 0000000000..9409f3fa20
--- /dev/null
+++ b/source3/modules/vfs_afsacl.c
@@ -0,0 +1,1081 @@
+/*
+ * Convert AFS acls to NT acls and vice versa.
+ *
+ * Copyright (C) Volker Lendecke, 2003
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+#include <afs/stds.h>
+#include <afs/afs.h>
+#include <afs/auth.h>
+#include <afs/venus.h>
+#include <afs/prs_fs.h>
+
+#define MAXSIZE 2048
+
+extern const DOM_SID global_sid_World;
+extern const DOM_SID global_sid_Builtin_Administrators;
+extern const DOM_SID global_sid_Builtin_Backup_Operators;
+extern const DOM_SID global_sid_Authenticated_Users;
+extern const DOM_SID global_sid_NULL;
+
+static char space_replacement = '%';
+
+/* Do we expect SIDs as pts names? */
+static bool sidpts;
+
+extern int afs_syscall(int, char *, int, char *, int);
+
+struct afs_ace {
+ bool positive;
+ char *name;
+ DOM_SID sid;
+ enum lsa_SidType type;
+ uint32 rights;
+ struct afs_ace *next;
+};
+
+struct afs_acl {
+ TALLOC_CTX *ctx;
+ int type;
+ int num_aces;
+ struct afs_ace *acelist;
+};
+
+struct afs_iob {
+ char *in, *out;
+ uint16 in_size, out_size;
+};
+
+
+static bool init_afs_acl(struct afs_acl *acl)
+{
+ ZERO_STRUCT(*acl);
+ acl->ctx = talloc_init("afs_acl");
+ if (acl->ctx == NULL) {
+ DEBUG(10, ("Could not init afs_acl"));
+ return False;
+ }
+ return True;
+}
+
+static void free_afs_acl(struct afs_acl *acl)
+{
+ if (acl->ctx != NULL)
+ talloc_destroy(acl->ctx);
+ acl->ctx = NULL;
+ acl->num_aces = 0;
+ acl->acelist = NULL;
+}
+
+static struct afs_ace *clone_afs_ace(TALLOC_CTX *mem_ctx, struct afs_ace *ace)
+{
+ struct afs_ace *result = TALLOC_P(mem_ctx, struct afs_ace);
+
+ if (result == NULL)
+ return NULL;
+
+ *result = *ace;
+
+ result->next = NULL;
+ result->name = talloc_strdup(mem_ctx, ace->name);
+
+ if (result->name == NULL) {
+ return NULL;
+ }
+
+ return result;
+}
+
+static struct afs_ace *new_afs_ace(TALLOC_CTX *mem_ctx,
+ bool positive,
+ const char *name, uint32 rights)
+{
+ DOM_SID sid;
+ enum lsa_SidType type;
+ struct afs_ace *result;
+
+ if (strcmp(name, "system:administrators") == 0) {
+
+ sid_copy(&sid, &global_sid_Builtin_Administrators);
+ type = SID_NAME_ALIAS;
+
+ } else if (strcmp(name, "system:anyuser") == 0) {
+
+ sid_copy(&sid, &global_sid_World);
+ type = SID_NAME_ALIAS;
+
+ } else if (strcmp(name, "system:authuser") == 0) {
+
+ sid_copy(&sid, &global_sid_Authenticated_Users);
+ type = SID_NAME_WKN_GRP;
+
+ } else if (strcmp(name, "system:backup") == 0) {
+
+ sid_copy(&sid, &global_sid_Builtin_Backup_Operators);
+ type = SID_NAME_ALIAS;
+
+ } else if (sidpts) {
+ /* All PTS users/groups are expressed as SIDs */
+
+ sid_copy(&sid, &global_sid_NULL);
+ type = SID_NAME_UNKNOWN;
+
+ if (string_to_sid(&sid, name)) {
+ const char *user, *domain;
+ /* We have to find the type, look up the SID */
+ lookup_sid(talloc_tos(), &sid,
+ &domain, &user, &type);
+ }
+
+ } else {
+
+ const char *domain, *uname;
+ char *p;
+
+ p = strchr_m(name, *lp_winbind_separator());
+ if (p != NULL) {
+ *p = '\\';
+ }
+
+ if (!lookup_name(talloc_tos(), name, LOOKUP_NAME_ALL,
+ &domain, &uname, &sid, &type)) {
+ DEBUG(10, ("Could not find AFS user %s\n", name));
+
+ sid_copy(&sid, &global_sid_NULL);
+ type = SID_NAME_UNKNOWN;
+
+ }
+ }
+
+ result = TALLOC_P(mem_ctx, struct afs_ace);
+
+ if (result == NULL) {
+ DEBUG(0, ("Could not talloc AFS ace\n"));
+ return NULL;
+ }
+
+ result->name = talloc_strdup(mem_ctx, name);
+ if (result->name == NULL) {
+ DEBUG(0, ("Could not talloc AFS ace name\n"));
+ return NULL;
+ }
+
+ result->sid = sid;
+ result->type = type;
+
+ result->positive = positive;
+ result->rights = rights;
+
+ return result;
+}
+
+static void add_afs_ace(struct afs_acl *acl,
+ bool positive,
+ const char *name, uint32 rights)
+{
+ struct afs_ace *ace;
+
+ for (ace = acl->acelist; ace != NULL; ace = ace->next) {
+ if ((ace->positive == positive) &&
+ (strequal(ace->name, name))) {
+ ace->rights |= rights;
+ return;
+ }
+ }
+
+ ace = new_afs_ace(acl->ctx, positive, name, rights);
+
+ ace->next = acl->acelist;
+ acl->acelist = ace;
+
+ acl->num_aces += 1;
+
+ DEBUG(10, ("add_afs_ace: Added %s entry for %s with rights %d\n",
+ ace->positive?"positive":"negative",
+ ace->name, ace->rights));
+
+ return;
+}
+
+/* AFS ACLs in string form are a long string of fields delimited with \n.
+ *
+ * First line: Number of positive entries
+ * Second line: Number of negative entries
+ * Third and following lines: The entries themselves
+ *
+ * An ACE is a line of two fields, delimited by \t.
+ *
+ * First field: Name
+ * Second field: Rights
+ */
+
+static bool parse_afs_acl(struct afs_acl *acl, const char *acl_str)
+{
+ int nplus, nminus;
+ int aces;
+
+ char str[MAXSIZE+1];
+ char *p = str;
+
+ strncpy(str, acl_str, MAXSIZE);
+
+ if (sscanf(p, "%d", &nplus) != 1)
+ return False;
+
+ DEBUG(10, ("Found %d positive entries\n", nplus));
+
+ if ((p = strchr(p, '\n')) == NULL)
+ return False;
+ p += 1;
+
+ if (sscanf(p, "%d", &nminus) != 1)
+ return False;
+
+ DEBUG(10, ("Found %d negative entries\n", nminus));
+
+ if ((p = strchr(p, '\n')) == NULL)
+ return False;
+ p += 1;
+
+ for (aces = nplus+nminus; aces > 0; aces--)
+ {
+
+ const char *namep;
+ fstring name;
+ uint32 rights;
+ char *space;
+
+ namep = p;
+
+ if ((p = strchr(p, '\t')) == NULL)
+ return False;
+ *p = '\0';
+ p += 1;
+
+ if (sscanf(p, "%d", &rights) != 1)
+ return False;
+
+ if ((p = strchr(p, '\n')) == NULL)
+ return False;
+ p += 1;
+
+ fstrcpy(name, namep);
+
+ while ((space = strchr_m(name, space_replacement)) != NULL)
+ *space = ' ';
+
+ add_afs_ace(acl, nplus>0, name, rights);
+
+ nplus -= 1;
+ }
+
+ return True;
+}
+
+static bool unparse_afs_acl(struct afs_acl *acl, char *acl_str)
+{
+ /* TODO: String length checks!!!! */
+
+ int positives = 0;
+ int negatives = 0;
+ fstring line;
+
+ *acl_str = 0;
+
+ struct afs_ace *ace = acl->acelist;
+
+ while (ace != NULL) {
+ if (ace->positive)
+ positives++;
+ else
+ negatives++;
+ ace = ace->next;
+ }
+
+ fstr_sprintf(line, "%d\n", positives);
+ safe_strcat(acl_str, line, MAXSIZE);
+
+ fstr_sprintf(line, "%d\n", negatives);
+ safe_strcat(acl_str, line, MAXSIZE);
+
+ ace = acl->acelist;
+
+ while (ace != NULL) {
+ fstr_sprintf(line, "%s\t%d\n", ace->name, ace->rights);
+ safe_strcat(acl_str, line, MAXSIZE);
+ ace = ace->next;
+ }
+ return True;
+}
+
+static uint32 afs_to_nt_file_rights(uint32 rights)
+{
+ uint32 result = 0;
+
+ if (rights & PRSFS_READ)
+ result |= FILE_READ_DATA | FILE_READ_EA |
+ FILE_EXECUTE | FILE_READ_ATTRIBUTES |
+ READ_CONTROL_ACCESS | SYNCHRONIZE_ACCESS;
+
+ if (rights & PRSFS_WRITE)
+ result |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES |
+ FILE_WRITE_EA | FILE_APPEND_DATA;
+
+ if (rights & PRSFS_LOCK)
+ result |= WRITE_OWNER_ACCESS;
+
+ if (rights & PRSFS_DELETE)
+ result |= DELETE_ACCESS;
+
+ return result;
+}
+
+static void afs_to_nt_dir_rights(uint32 afs_rights, uint32 *nt_rights,
+ uint8 *flag)
+{
+ *nt_rights = 0;
+ *flag = SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT;
+
+ if (afs_rights & PRSFS_INSERT)
+ *nt_rights |= FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY;
+
+ if (afs_rights & PRSFS_LOOKUP)
+ *nt_rights |= FILE_READ_DATA | FILE_READ_EA |
+ FILE_EXECUTE | FILE_READ_ATTRIBUTES |
+ READ_CONTROL_ACCESS | SYNCHRONIZE_ACCESS;
+
+ if (afs_rights & PRSFS_WRITE)
+ *nt_rights |= FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA |
+ FILE_APPEND_DATA | FILE_WRITE_EA;
+
+ if ((afs_rights & (PRSFS_INSERT|PRSFS_LOOKUP|PRSFS_DELETE)) ==
+ (PRSFS_INSERT|PRSFS_LOOKUP|PRSFS_DELETE))
+ *nt_rights |= FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA |
+ GENERIC_WRITE_ACCESS;
+
+ if (afs_rights & PRSFS_DELETE)
+ *nt_rights |= DELETE_ACCESS;
+
+ if (afs_rights & PRSFS_ADMINISTER)
+ *nt_rights |= FILE_DELETE_CHILD | WRITE_DAC_ACCESS |
+ WRITE_OWNER_ACCESS;
+
+ if ( (afs_rights & PRSFS_LOOKUP) ==
+ (afs_rights & (PRSFS_LOOKUP|PRSFS_READ)) ) {
+ /* Only lookup right */
+ *flag = SEC_ACE_FLAG_CONTAINER_INHERIT;
+ }
+
+ return;
+}
+
+#define AFS_FILE_RIGHTS (PRSFS_READ|PRSFS_WRITE|PRSFS_LOCK)
+#define AFS_DIR_RIGHTS (PRSFS_INSERT|PRSFS_LOOKUP|PRSFS_DELETE|PRSFS_ADMINISTER)
+
+static void split_afs_acl(struct afs_acl *acl,
+ struct afs_acl *dir_acl,
+ struct afs_acl *file_acl)
+{
+ struct afs_ace *ace;
+
+ init_afs_acl(dir_acl);
+ init_afs_acl(file_acl);
+
+ for (ace = acl->acelist; ace != NULL; ace = ace->next) {
+ if (ace->rights & AFS_FILE_RIGHTS) {
+ add_afs_ace(file_acl, ace->positive, ace->name,
+ ace->rights & AFS_FILE_RIGHTS);
+ }
+
+ if (ace->rights & AFS_DIR_RIGHTS) {
+ add_afs_ace(dir_acl, ace->positive, ace->name,
+ ace->rights & AFS_DIR_RIGHTS);
+ }
+ }
+ return;
+}
+
+static bool same_principal(struct afs_ace *x, struct afs_ace *y)
+{
+ return ( (x->positive == y->positive) &&
+ (sid_compare(&x->sid, &y->sid) == 0) );
+}
+
+static void merge_afs_acls(struct afs_acl *dir_acl,
+ struct afs_acl *file_acl,
+ struct afs_acl *target)
+{
+ struct afs_ace *ace;
+
+ init_afs_acl(target);
+
+ for (ace = dir_acl->acelist; ace != NULL; ace = ace->next) {
+ struct afs_ace *file_ace;
+ bool found = False;
+
+ for (file_ace = file_acl->acelist;
+ file_ace != NULL;
+ file_ace = file_ace->next) {
+ if (!same_principal(ace, file_ace))
+ continue;
+
+ add_afs_ace(target, ace->positive, ace->name,
+ ace->rights | file_ace->rights);
+ found = True;
+ break;
+ }
+ if (!found)
+ add_afs_ace(target, ace->positive, ace->name,
+ ace->rights);
+ }
+
+ for (ace = file_acl->acelist; ace != NULL; ace = ace->next) {
+ struct afs_ace *dir_ace;
+ bool already_seen = False;
+
+ for (dir_ace = dir_acl->acelist;
+ dir_ace != NULL;
+ dir_ace = dir_ace->next) {
+ if (!same_principal(ace, dir_ace))
+ continue;
+ already_seen = True;
+ break;
+ }
+ if (!already_seen)
+ add_afs_ace(target, ace->positive, ace->name,
+ ace->rights);
+ }
+}
+
+#define PERMS_READ 0x001200a9
+#define PERMS_CHANGE 0x001301bf
+#define PERMS_FULL 0x001f01ff
+
+static struct static_dir_ace_mapping {
+ uint8 type;
+ uint8 flags;
+ uint32 mask;
+ uint32 afs_rights;
+} ace_mappings[] = {
+
+ /* Full control */
+ { 0, SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT,
+ PERMS_FULL, 127 /* rlidwka */ },
+
+ /* Change (write) */
+ { 0, SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT,
+ PERMS_CHANGE, 63 /* rlidwk */ },
+
+ /* Read (including list folder content) */
+ { 0, SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT,
+ PERMS_READ, 9 /* rl */ },
+
+ /* Read without list folder content -- same as "l" */
+ { 0, SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT,
+ 0x00120089, 8 /* l */ },
+
+ /* some stupid workaround for preventing fallbacks */
+ { 0, 0x3, 0x0012019F, 9 /* rl */ },
+ { 0, 0x13, PERMS_FULL, 127 /* full */ },
+
+ /* read, delete and execute access plus synchronize */
+ { 0, 0x3, 0x001300A9, 9 /* should be rdl, set to rl */},
+ /* classical read list */
+ { 0, 0x13, 0x001200A9, 9 /* rl */},
+ /* almost full control, no delete */
+ { 0, 0x13, PERMS_CHANGE, 63 /* rwidlk */},
+
+ /* List folder */
+ { 0, SEC_ACE_FLAG_CONTAINER_INHERIT,
+ PERMS_READ, 8 /* l */ },
+
+ /* FULL without inheritance -- in all cases here we also get
+ the corresponding INHERIT_ONLY ACE in the same ACL */
+ { 0, 0, PERMS_FULL, 127 /* rlidwka */ },
+
+ /* FULL inherit only -- counterpart to previous one */
+ { 0, SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY,
+ PERMS_FULL | GENERIC_RIGHT_WRITE_ACCESS, 127 /* rlidwka */ },
+
+ /* CHANGE without inheritance -- in all cases here we also get
+ the corresponding INHERIT_ONLY ACE in the same ACL */
+ { 0, 0, PERMS_CHANGE, 63 /* rlidwk */ },
+
+ /* CHANGE inherit only -- counterpart to previous one */
+ { 0, SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY,
+ PERMS_CHANGE | GENERIC_RIGHT_WRITE_ACCESS, 63 /* rlidwk */ },
+
+ /* End marker, hopefully there's no afs right 9999 :-) */
+ { 0, 0, 0, 9999 }
+};
+
+static uint32 nt_to_afs_dir_rights(const char *filename, const SEC_ACE *ace)
+{
+ uint32 result = 0;
+ uint32 rights = ace->access_mask;
+ uint8 flags = ace->flags;
+
+ struct static_dir_ace_mapping *m;
+
+ for (m = &ace_mappings[0]; m->afs_rights != 9999; m++) {
+ if ( (ace->type == m->type) &&
+ (ace->flags == m->flags) &&
+ (ace->access_mask == m->mask) )
+ return m->afs_rights;
+ }
+
+ DEBUG(1, ("AFSACL FALLBACK: 0x%X 0x%X 0x%X %s %X\n",
+ ace->type, ace->flags, ace->access_mask, filename, rights));
+
+ if (rights & (GENERIC_ALL_ACCESS|WRITE_DAC_ACCESS)) {
+ result |= PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT |
+ PRSFS_LOOKUP | PRSFS_DELETE | PRSFS_LOCK |
+ PRSFS_ADMINISTER;
+ }
+
+ if (rights & (GENERIC_READ_ACCESS|FILE_READ_DATA)) {
+ result |= PRSFS_LOOKUP;
+ if (flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
+ result |= PRSFS_READ;
+ }
+ }
+
+ if (rights & (GENERIC_WRITE_ACCESS|FILE_WRITE_DATA)) {
+ result |= PRSFS_INSERT | PRSFS_DELETE;
+ if (flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
+ result |= PRSFS_WRITE | PRSFS_LOCK;
+ }
+ }
+
+ return result;
+}
+
+static uint32 nt_to_afs_file_rights(const char *filename, const SEC_ACE *ace)
+{
+ uint32 result = 0;
+ uint32 rights = ace->access_mask;
+
+ if (rights & (GENERIC_READ_ACCESS|FILE_READ_DATA)) {
+ result |= PRSFS_READ;
+ }
+
+ if (rights & (GENERIC_WRITE_ACCESS|FILE_WRITE_DATA)) {
+ result |= PRSFS_WRITE | PRSFS_LOCK;
+ }
+
+ return result;
+}
+
+static size_t afs_to_nt_acl_common(struct afs_acl *afs_acl,
+ SMB_STRUCT_STAT *psbuf,
+ uint32 security_info,
+ struct security_descriptor **ppdesc)
+{
+ SEC_ACE *nt_ace_list;
+ DOM_SID owner_sid, group_sid;
+ SEC_ACCESS mask;
+ SEC_ACL *psa = NULL;
+ int good_aces;
+ size_t sd_size;
+ TALLOC_CTX *mem_ctx = talloc_tos();
+
+ struct afs_ace *afs_ace;
+
+ uid_to_sid(&owner_sid, psbuf->st_uid);
+ gid_to_sid(&group_sid, psbuf->st_gid);
+
+ if (afs_acl->num_aces) {
+ nt_ace_list = TALLOC_ARRAY(mem_ctx, SEC_ACE, afs_acl->num_aces);
+
+ if (nt_ace_list == NULL)
+ return 0;
+ } else {
+ nt_ace_list = NULL;
+ }
+
+ afs_ace = afs_acl->acelist;
+ good_aces = 0;
+
+ while (afs_ace != NULL) {
+ uint32 nt_rights;
+ uint8 flag = SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT;
+
+ if (afs_ace->type == SID_NAME_UNKNOWN) {
+ DEBUG(10, ("Ignoring unknown name %s\n",
+ afs_ace->name));
+ afs_ace = afs_ace->next;
+ continue;
+ }
+
+ if (S_ISDIR(psbuf->st_mode))
+ afs_to_nt_dir_rights(afs_ace->rights, &nt_rights,
+ &flag);
+ else
+ nt_rights = afs_to_nt_file_rights(afs_ace->rights);
+
+ init_sec_access(&mask, nt_rights);
+ init_sec_ace(&nt_ace_list[good_aces++], &(afs_ace->sid),
+ SEC_ACE_TYPE_ACCESS_ALLOWED, mask, flag);
+ afs_ace = afs_ace->next;
+ }
+
+ psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION,
+ good_aces, nt_ace_list);
+ if (psa == NULL)
+ return 0;
+
+ *ppdesc = make_sec_desc(mem_ctx, SEC_DESC_REVISION,
+ SEC_DESC_SELF_RELATIVE,
+ (security_info & OWNER_SECURITY_INFORMATION)
+ ? &owner_sid : NULL,
+ (security_info & GROUP_SECURITY_INFORMATION)
+ ? &group_sid : NULL,
+ NULL, psa, &sd_size);
+
+ return sd_size;
+}
+
+static size_t afs_to_nt_acl(struct afs_acl *afs_acl,
+ struct connection_struct *conn,
+ const char *name,
+ uint32 security_info,
+ struct security_descriptor **ppdesc)
+{
+ SMB_STRUCT_STAT sbuf;
+
+ /* Get the stat struct for the owner info. */
+ if(SMB_VFS_STAT(conn, name, &sbuf) != 0) {
+ return 0;
+ }
+
+ return afs_to_nt_acl_common(afs_acl, &sbuf, security_info, ppdesc);
+}
+
+static size_t afs_fto_nt_acl(struct afs_acl *afs_acl,
+ struct files_struct *fsp,
+ uint32 security_info,
+ struct security_descriptor **ppdesc)
+{
+ SMB_STRUCT_STAT sbuf;
+
+ if (fsp->is_directory || fsp->fh->fd == -1) {
+ /* Get the stat struct for the owner info. */
+ return afs_to_nt_acl(afs_acl, fsp->conn, fsp->fsp_name,
+ security_info, ppdesc);
+ }
+
+ if(SMB_VFS_FSTAT(fsp, &sbuf) != 0) {
+ return 0;
+ }
+
+ return afs_to_nt_acl_common(afs_acl, &sbuf, security_info, ppdesc);
+}
+
+static bool mappable_sid(const DOM_SID *sid)
+{
+ DOM_SID domain_sid;
+
+ if (sid_compare(sid, &global_sid_Builtin_Administrators) == 0)
+ return True;
+
+ if (sid_compare(sid, &global_sid_World) == 0)
+ return True;
+
+ if (sid_compare(sid, &global_sid_Authenticated_Users) == 0)
+ return True;
+
+ if (sid_compare(sid, &global_sid_Builtin_Backup_Operators) == 0)
+ return True;
+
+ string_to_sid(&domain_sid, "S-1-5-21");
+
+ if (sid_compare_domain(sid, &domain_sid) == 0)
+ return True;
+
+ return False;
+}
+
+static bool nt_to_afs_acl(const char *filename,
+ uint32 security_info_sent,
+ struct security_descriptor *psd,
+ uint32 (*nt_to_afs_rights)(const char *filename,
+ const SEC_ACE *ace),
+ struct afs_acl *afs_acl)
+{
+ SEC_ACL *dacl;
+ int i;
+
+ /* Currently we *only* look at the dacl */
+
+ if (((security_info_sent & DACL_SECURITY_INFORMATION) == 0) ||
+ (psd->dacl == NULL))
+ return True;
+
+ if (!init_afs_acl(afs_acl))
+ return False;
+
+ dacl = psd->dacl;
+
+ for (i = 0; i < dacl->num_aces; i++) {
+ SEC_ACE *ace = &(dacl->aces[i]);
+ const char *dom_name, *name;
+ enum lsa_SidType name_type;
+ char *p;
+
+ if (ace->type != SEC_ACE_TYPE_ACCESS_ALLOWED) {
+ /* First cut: Only positive ACEs */
+ return False;
+ }
+
+ if (!mappable_sid(&ace->trustee)) {
+ DEBUG(10, ("Ignoring unmappable SID %s\n",
+ sid_string_dbg(&ace->trustee)));
+ continue;
+ }
+
+ if (sid_compare(&ace->trustee,
+ &global_sid_Builtin_Administrators) == 0) {
+
+ name = "system:administrators";
+
+ } else if (sid_compare(&ace->trustee,
+ &global_sid_World) == 0) {
+
+ name = "system:anyuser";
+
+ } else if (sid_compare(&ace->trustee,
+ &global_sid_Authenticated_Users) == 0) {
+
+ name = "system:authuser";
+
+ } else if (sid_compare(&ace->trustee,
+ &global_sid_Builtin_Backup_Operators)
+ == 0) {
+
+ name = "system:backup";
+
+ } else {
+
+ if (!lookup_sid(talloc_tos(), &ace->trustee,
+ &dom_name, &name, &name_type)) {
+ DEBUG(1, ("AFSACL: Could not lookup SID %s on file %s\n",
+ sid_string_dbg(&ace->trustee),
+ filename));
+ continue;
+ }
+
+ if ( (name_type == SID_NAME_USER) ||
+ (name_type == SID_NAME_DOM_GRP) ||
+ (name_type == SID_NAME_ALIAS) ) {
+ char *tmp;
+ tmp = talloc_asprintf(talloc_tos(), "%s%s%s",
+ dom_name, lp_winbind_separator(),
+ name);
+ if (tmp == NULL) {
+ return False;
+ }
+ strlower_m(tmp);
+ name = tmp;
+ }
+
+ if (sidpts) {
+ /* Expect all users/groups in pts as SIDs */
+ name = talloc_strdup(
+ talloc_tos(),
+ sid_string_tos(&ace->trustee));
+ if (name == NULL) {
+ return False;
+ }
+ }
+ }
+
+ while ((p = strchr_m(name, ' ')) != NULL)
+ *p = space_replacement;
+
+ add_afs_ace(afs_acl, True, name,
+ nt_to_afs_rights(filename, ace));
+ }
+
+ return True;
+}
+
+static bool afs_get_afs_acl(char *filename, struct afs_acl *acl)
+{
+ struct afs_iob iob;
+
+ int ret;
+
+ char space[MAXSIZE];
+
+ DEBUG(5, ("afs_get_afs_acl: %s\n", filename));
+
+ iob.in_size = 0;
+ iob.out_size = MAXSIZE;
+ iob.in = iob.out = space;
+
+ ret = afs_syscall(AFSCALL_PIOCTL, filename, VIOCGETAL,
+ (char *)&iob, 0);
+
+ if (ret) {
+ DEBUG(1, ("got error from PIOCTL: %d\n", ret));
+ return False;
+ }
+
+ if (!init_afs_acl(acl))
+ return False;
+
+ if (!parse_afs_acl(acl, space)) {
+ DEBUG(1, ("Could not parse AFS acl\n"));
+ free_afs_acl(acl);
+ return False;
+ }
+
+ return True;
+}
+
+/* For setting an AFS ACL we have to take care of the ACEs we could
+ * not properly map to SIDs. Merge all of them into the new ACL. */
+
+static void merge_unknown_aces(struct afs_acl *src, struct afs_acl *dst)
+{
+ struct afs_ace *ace;
+
+ for (ace = src->acelist; ace != NULL; ace = ace->next)
+ {
+ struct afs_ace *copy;
+
+ if (ace->type != SID_NAME_UNKNOWN) {
+ DEBUG(10, ("Not merging known ACE for %s\n",
+ ace->name));
+ continue;
+ }
+
+ DEBUG(10, ("Merging unknown ACE for %s\n", ace->name));
+
+ copy = clone_afs_ace(dst->ctx, ace);
+
+ if (copy == NULL) {
+ DEBUG(0, ("Could not clone ACE for %s\n", ace->name));
+ continue;
+ }
+
+ copy->next = dst->acelist;
+ dst->acelist = copy;
+ dst->num_aces += 1;
+ }
+}
+
+static NTSTATUS afs_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
+ uint32 security_info_sent,
+ struct security_descriptor *psd)
+{
+ struct afs_acl old_afs_acl, new_afs_acl;
+ struct afs_acl dir_acl, file_acl;
+ char acl_string[2049];
+ struct afs_iob iob;
+ int ret = -1;
+ char *name = NULL;
+ const char *fileacls;
+
+ fileacls = lp_parm_const_string(SNUM(handle->conn), "afsacl", "fileacls",
+ "yes");
+
+ sidpts = lp_parm_bool(SNUM(handle->conn), "afsacl", "sidpts", False);
+
+ ZERO_STRUCT(old_afs_acl);
+ ZERO_STRUCT(new_afs_acl);
+ ZERO_STRUCT(dir_acl);
+ ZERO_STRUCT(file_acl);
+
+ name = talloc_strdup(talloc_tos(), fsp->fsp_name);
+ if (!name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!fsp->is_directory) {
+ /* We need to get the name of the directory containing the
+ * file, this is where the AFS acls live */
+ char *p = strrchr(name, '/');
+ if (p != NULL) {
+ *p = '\0';
+ } else {
+ name = talloc_strdup(talloc_tos(), ".");
+ if (!name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ }
+
+ if (!afs_get_afs_acl(name, &old_afs_acl)) {
+ DEBUG(3, ("Could not get old ACL of %s\n", fsp->fsp_name));
+ goto done;
+ }
+
+ split_afs_acl(&old_afs_acl, &dir_acl, &file_acl);
+
+ if (fsp->is_directory) {
+
+ if (!strequal(fileacls, "yes")) {
+ /* Throw away file acls, we depend on the
+ * inheritance ACEs that also give us file
+ * permissions */
+ free_afs_acl(&file_acl);
+ }
+
+ free_afs_acl(&dir_acl);
+ if (!nt_to_afs_acl(fsp->fsp_name, security_info_sent, psd,
+ nt_to_afs_dir_rights, &dir_acl))
+ goto done;
+ } else {
+ if (strequal(fileacls, "no")) {
+ ret = -1;
+ goto done;
+ }
+
+ if (strequal(fileacls, "ignore")) {
+ ret = 0;
+ goto done;
+ }
+
+ free_afs_acl(&file_acl);
+ if (!nt_to_afs_acl(fsp->fsp_name, security_info_sent, psd,
+ nt_to_afs_file_rights, &file_acl))
+ goto done;
+ }
+
+ merge_afs_acls(&dir_acl, &file_acl, &new_afs_acl);
+
+ merge_unknown_aces(&old_afs_acl, &new_afs_acl);
+
+ unparse_afs_acl(&new_afs_acl, acl_string);
+
+ iob.in = acl_string;
+ iob.in_size = 1+strlen(iob.in);
+ iob.out = NULL;
+ iob.out_size = 0;
+
+ DEBUG(10, ("trying to set acl '%s' on file %s\n", iob.in, name));
+
+ ret = afs_syscall(AFSCALL_PIOCTL, name, VIOCSETAL, (char *)&iob, 0);
+
+ if (ret != 0) {
+ DEBUG(10, ("VIOCSETAL returned %d\n", ret));
+ }
+
+ done:
+ free_afs_acl(&dir_acl);
+ free_afs_acl(&file_acl);
+ free_afs_acl(&old_afs_acl);
+ free_afs_acl(&new_afs_acl);
+
+ return (ret == 0) ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED;
+}
+
+static NTSTATUS afsacl_fget_nt_acl(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32 security_info,
+ struct security_descriptor **ppdesc)
+{
+ struct afs_acl acl;
+ size_t sd_size;
+
+ DEBUG(5, ("afsacl_fget_nt_acl: %s\n", fsp->fsp_name));
+
+ sidpts = lp_parm_bool(SNUM(fsp->conn), "afsacl", "sidpts", False);
+
+ if (!afs_get_afs_acl(fsp->fsp_name, &acl)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ sd_size = afs_fto_nt_acl(&acl, fsp, security_info, ppdesc);
+
+ free_afs_acl(&acl);
+
+ return (sd_size != 0) ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED;
+}
+
+static NTSTATUS afsacl_get_nt_acl(struct vfs_handle_struct *handle,
+ const char *name, uint32 security_info,
+ struct security_descriptor **ppdesc)
+{
+ struct afs_acl acl;
+ size_t sd_size;
+
+ DEBUG(5, ("afsacl_get_nt_acl: %s\n", name));
+
+ sidpts = lp_parm_bool(SNUM(handle->conn), "afsacl", "sidpts", False);
+
+ if (!afs_get_afs_acl(name, &acl)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ sd_size = afs_to_nt_acl(&acl, handle->conn, name, security_info,
+ ppdesc);
+
+ free_afs_acl(&acl);
+
+ return (sd_size != 0) ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED;
+}
+
+NTSTATUS afsacl_fset_nt_acl(vfs_handle_struct *handle,
+ files_struct *fsp,
+ uint32 security_info_sent,
+ SEC_DESC *psd)
+{
+ return afs_set_nt_acl(handle, fsp, security_info_sent, psd);
+}
+
+static int afsacl_connect(vfs_handle_struct *handle,
+ const char *service,
+ const char *user)
+{
+ const char *spc;
+
+ spc = lp_parm_const_string(SNUM(handle->conn), "afsacl", "space", "%");
+
+ if (spc != NULL)
+ space_replacement = spc[0];
+
+ return SMB_VFS_NEXT_CONNECT(handle, service, user);
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple afsacl_ops[] = {
+ {SMB_VFS_OP(afsacl_connect), SMB_VFS_OP_CONNECT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(afsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(afsacl_get_nt_acl), SMB_VFS_OP_GET_NT_ACL,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(afsacl_fset_nt_acl), SMB_VFS_OP_FSET_NT_ACL,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_afsacl_init(void);
+NTSTATUS vfs_afsacl_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "afsacl",
+ afsacl_ops);
+}
diff --git a/source3/modules/vfs_aio_fork.c b/source3/modules/vfs_aio_fork.c
new file mode 100644
index 0000000000..7914e8f401
--- /dev/null
+++ b/source3/modules/vfs_aio_fork.c
@@ -0,0 +1,729 @@
+/*
+ * Simulate the Posix AIO using mmap/fork
+ *
+ * Copyright (C) Volker Lendecke 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+struct mmap_area {
+ size_t size;
+ volatile void *ptr;
+};
+
+static int mmap_area_destructor(struct mmap_area *area)
+{
+ munmap((void *)area->ptr, area->size);
+ return 0;
+}
+
+static struct mmap_area *mmap_area_init(TALLOC_CTX *mem_ctx, size_t size)
+{
+ struct mmap_area *result;
+ int fd;
+
+ result = talloc(mem_ctx, struct mmap_area);
+ if (result == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ goto fail;
+ }
+
+ fd = open("/dev/zero", O_RDWR);
+ if (fd == -1) {
+ DEBUG(3, ("open(\"/dev/zero\") failed: %s\n",
+ strerror(errno)));
+ goto fail;
+ }
+
+ result->ptr = mmap(NULL, size, PROT_READ|PROT_WRITE,
+ MAP_SHARED|MAP_FILE, fd, 0);
+ if (result->ptr == MAP_FAILED) {
+ DEBUG(1, ("mmap failed: %s\n", strerror(errno)));
+ goto fail;
+ }
+
+ close(fd);
+
+ result->size = size;
+ talloc_set_destructor(result, mmap_area_destructor);
+
+ return result;
+
+fail:
+ TALLOC_FREE(result);
+ return NULL;
+}
+
+struct rw_cmd {
+ size_t n;
+ SMB_OFF_T offset;
+ bool read_cmd;
+};
+
+struct rw_ret {
+ ssize_t size;
+ int ret_errno;
+};
+
+struct aio_child_list;
+
+struct aio_child {
+ struct aio_child *prev, *next;
+ struct aio_child_list *list;
+ SMB_STRUCT_AIOCB *aiocb;
+ pid_t pid;
+ int sockfd;
+ struct fd_event *sock_event;
+ struct rw_ret retval;
+ struct mmap_area *map; /* ==NULL means write request */
+ bool dont_delete; /* Marked as in use since last cleanup */
+ bool cancelled;
+ bool read_cmd;
+};
+
+struct aio_child_list {
+ struct aio_child *children;
+ struct timed_event *cleanup_event;
+};
+
+static void free_aio_children(void **p)
+{
+ TALLOC_FREE(*p);
+}
+
+static ssize_t read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)
+{
+ struct msghdr msg;
+ struct iovec iov[1];
+ ssize_t n;
+#ifndef HAVE_MSGHDR_MSG_CONTROL
+ int newfd;
+#endif
+
+#ifdef HAVE_MSGHDR_MSG_CONTROL
+ union {
+ struct cmsghdr cm;
+ char control[CMSG_SPACE(sizeof(int))];
+ } control_un;
+ struct cmsghdr *cmptr;
+
+ msg.msg_control = control_un.control;
+ msg.msg_controllen = sizeof(control_un.control);
+#else
+#if HAVE_MSGHDR_MSG_ACCTRIGHTS
+ msg.msg_accrights = (caddr_t) &newfd;
+ msg.msg_accrightslen = sizeof(int);
+#else
+#error Can not pass file descriptors
+#endif
+#endif
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+
+ iov[0].iov_base = ptr;
+ iov[0].iov_len = nbytes;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+
+ if ( (n = recvmsg(fd, &msg, 0)) <= 0) {
+ return(n);
+ }
+
+#ifdef HAVE_MSGHDR_MSG_CONTROL
+ if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL
+ && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
+ if (cmptr->cmsg_level != SOL_SOCKET) {
+ DEBUG(10, ("control level != SOL_SOCKET"));
+ errno = EINVAL;
+ return -1;
+ }
+ if (cmptr->cmsg_type != SCM_RIGHTS) {
+ DEBUG(10, ("control type != SCM_RIGHTS"));
+ errno = EINVAL;
+ return -1;
+ }
+ *recvfd = *((int *) CMSG_DATA(cmptr));
+ } else {
+ *recvfd = -1; /* descriptor was not passed */
+ }
+#else
+ if (msg.msg_accrightslen == sizeof(int)) {
+ *recvfd = newfd;
+ }
+ else {
+ *recvfd = -1; /* descriptor was not passed */
+ }
+#endif
+
+ return(n);
+}
+
+static ssize_t write_fd(int fd, void *ptr, size_t nbytes, int sendfd)
+{
+ struct msghdr msg;
+ struct iovec iov[1];
+
+#ifdef HAVE_MSGHDR_MSG_CONTROL
+ union {
+ struct cmsghdr cm;
+ char control[CMSG_SPACE(sizeof(int))];
+ } control_un;
+ struct cmsghdr *cmptr;
+
+ ZERO_STRUCT(msg);
+ ZERO_STRUCT(control_un);
+
+ msg.msg_control = control_un.control;
+ msg.msg_controllen = sizeof(control_un.control);
+
+ cmptr = CMSG_FIRSTHDR(&msg);
+ cmptr->cmsg_len = CMSG_LEN(sizeof(int));
+ cmptr->cmsg_level = SOL_SOCKET;
+ cmptr->cmsg_type = SCM_RIGHTS;
+ *((int *) CMSG_DATA(cmptr)) = sendfd;
+#else
+ ZERO_STRUCT(msg);
+ msg.msg_accrights = (caddr_t) &sendfd;
+ msg.msg_accrightslen = sizeof(int);
+#endif
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+
+ ZERO_STRUCT(iov);
+ iov[0].iov_base = ptr;
+ iov[0].iov_len = nbytes;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+
+ return (sendmsg(fd, &msg, 0));
+}
+
+static void aio_child_cleanup(struct event_context *event_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ struct aio_child_list *list = talloc_get_type_abort(
+ private_data, struct aio_child_list);
+ struct aio_child *child, *next;
+
+ TALLOC_FREE(list->cleanup_event);
+
+ for (child = list->children; child != NULL; child = next) {
+ next = child->next;
+
+ if (child->aiocb != NULL) {
+ DEBUG(10, ("child %d currently active\n",
+ (int)child->pid));
+ continue;
+ }
+
+ if (child->dont_delete) {
+ DEBUG(10, ("Child %d was active since last cleanup\n",
+ (int)child->pid));
+ child->dont_delete = false;
+ continue;
+ }
+
+ DEBUG(10, ("Child %d idle for more than 30 seconds, "
+ "deleting\n", (int)child->pid));
+
+ TALLOC_FREE(child);
+ }
+
+ if (list->children != NULL) {
+ /*
+ * Re-schedule the next cleanup round
+ */
+ list->cleanup_event = event_add_timed(smbd_event_context(), list,
+ timeval_add(now, 30, 0),
+ "aio_child_cleanup",
+ aio_child_cleanup, list);
+
+ }
+}
+
+static struct aio_child_list *init_aio_children(struct vfs_handle_struct *handle)
+{
+ struct aio_child_list *data = NULL;
+
+ if (SMB_VFS_HANDLE_TEST_DATA(handle)) {
+ SMB_VFS_HANDLE_GET_DATA(handle, data, struct aio_child_list,
+ return NULL);
+ }
+
+ if (data == NULL) {
+ data = TALLOC_ZERO_P(NULL, struct aio_child_list);
+ if (data == NULL) {
+ return NULL;
+ }
+ }
+
+ /*
+ * Regardless of whether the child_list had been around or not, make
+ * sure that we have a cleanup timed event. This timed event will
+ * delete itself when it finds that no children are around anymore.
+ */
+
+ if (data->cleanup_event == NULL) {
+ data->cleanup_event = event_add_timed(smbd_event_context(), data,
+ timeval_current_ofs(30, 0),
+ "aio_child_cleanup",
+ aio_child_cleanup, data);
+ if (data->cleanup_event == NULL) {
+ TALLOC_FREE(data);
+ return NULL;
+ }
+ }
+
+ if (!SMB_VFS_HANDLE_TEST_DATA(handle)) {
+ SMB_VFS_HANDLE_SET_DATA(handle, data, free_aio_children,
+ struct aio_child_list, return False);
+ }
+
+ return data;
+}
+
+static void aio_child_loop(int sockfd, struct mmap_area *map)
+{
+ while (true) {
+ int fd = -1;
+ ssize_t ret;
+ struct rw_cmd cmd_struct;
+ struct rw_ret ret_struct;
+
+ ret = read_fd(sockfd, &cmd_struct, sizeof(cmd_struct), &fd);
+ if (ret != sizeof(cmd_struct)) {
+ DEBUG(10, ("read_fd returned %d: %s\n", (int)ret,
+ strerror(errno)));
+ exit(1);
+ }
+
+ DEBUG(10, ("aio_child_loop: %s %d bytes at %d from fd %d\n",
+ cmd_struct.read_cmd ? "read" : "write",
+ (int)cmd_struct.n, (int)cmd_struct.offset, fd));
+
+#ifdef ENABLE_BUILD_FARM_HACKS
+ {
+ /*
+ * In the build farm, we want erratic behaviour for
+ * async I/O times
+ */
+ uint8_t randval;
+ unsigned msecs;
+ /*
+ * use generate_random_buffer, we just forked from a
+ * common parent state
+ */
+ generate_random_buffer(&randval, sizeof(randval));
+ msecs = randval + 20;
+ DEBUG(10, ("delaying for %u msecs\n", msecs));
+ smb_msleep(msecs);
+ }
+#endif
+
+
+ ZERO_STRUCT(ret_struct);
+
+ if (cmd_struct.read_cmd) {
+ ret_struct.size = sys_pread(
+ fd, (void *)map->ptr, cmd_struct.n,
+ cmd_struct.offset);
+ }
+ else {
+ ret_struct.size = sys_pwrite(
+ fd, (void *)map->ptr, cmd_struct.n,
+ cmd_struct.offset);
+ }
+
+ DEBUG(10, ("aio_child_loop: syscall returned %d\n",
+ (int)ret_struct.size));
+
+ if (ret_struct.size == -1) {
+ ret_struct.ret_errno = errno;
+ }
+
+ ret = write_data(sockfd, (char *)&ret_struct,
+ sizeof(ret_struct));
+ if (ret != sizeof(ret_struct)) {
+ DEBUG(10, ("could not write ret_struct: %s\n",
+ strerror(errno)));
+ exit(2);
+ }
+
+ close(fd);
+ }
+}
+
+static void handle_aio_completion(struct event_context *event_ctx,
+ struct fd_event *event, uint16 flags,
+ void *p)
+{
+ struct aio_child *child = (struct aio_child *)p;
+ uint16 mid;
+
+ DEBUG(10, ("handle_aio_completion called with flags=%d\n", flags));
+
+ if ((flags & EVENT_FD_READ) == 0) {
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(read_data(child->sockfd,
+ (char *)&child->retval,
+ sizeof(child->retval)))) {
+ DEBUG(0, ("aio child %d died\n", (int)child->pid));
+ child->retval.size = -1;
+ child->retval.ret_errno = EIO;
+ }
+
+ if (child->cancelled) {
+ child->aiocb = NULL;
+ child->cancelled = false;
+ return;
+ }
+
+ if (child->read_cmd && (child->retval.size > 0)) {
+ SMB_ASSERT(child->retval.size <= child->aiocb->aio_nbytes);
+ memcpy((void *)child->aiocb->aio_buf, (void *)child->map->ptr,
+ child->retval.size);
+ }
+
+ mid = child->aiocb->aio_sigevent.sigev_value.sival_int;
+
+ DEBUG(10, ("mid %d finished\n", (int)mid));
+
+ aio_request_done(mid);
+ process_aio_queue();
+}
+
+static int aio_child_destructor(struct aio_child *child)
+{
+ SMB_ASSERT((child->aiocb == NULL) || child->cancelled);
+ close(child->sockfd);
+ DLIST_REMOVE(child->list->children, child);
+ return 0;
+}
+
+static NTSTATUS create_aio_child(struct aio_child_list *children,
+ size_t map_size,
+ struct aio_child **presult)
+{
+ struct aio_child *result;
+ int fdpair[2];
+ NTSTATUS status;
+
+ fdpair[0] = fdpair[1] = -1;
+
+ result = TALLOC_ZERO_P(children, struct aio_child);
+ NT_STATUS_HAVE_NO_MEMORY(result);
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) == -1) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(10, ("socketpair() failed: %s\n", strerror(errno)));
+ goto fail;
+ }
+
+ DEBUG(10, ("fdpair = %d/%d\n", fdpair[0], fdpair[1]));
+
+ result->map = mmap_area_init(result, map_size);
+ if (result->map == NULL) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(0, ("Could not create mmap area\n"));
+ goto fail;
+ }
+
+ result->pid = sys_fork();
+ if (result->pid == -1) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(0, ("fork failed: %s\n", strerror(errno)));
+ goto fail;
+ }
+
+ if (result->pid == 0) {
+ close(fdpair[0]);
+ result->sockfd = fdpair[1];
+ aio_child_loop(result->sockfd, result->map);
+ }
+
+ DEBUG(10, ("Child %d created\n", result->pid));
+
+ result->sockfd = fdpair[0];
+ close(fdpair[1]);
+
+ result->sock_event = event_add_fd(smbd_event_context(), result,
+ result->sockfd, EVENT_FD_READ,
+ handle_aio_completion,
+ result);
+ if (result->sock_event == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ DEBUG(0, ("event_add_fd failed\n"));
+ goto fail;
+ }
+
+ result->list = children;
+ DLIST_ADD(children->children, result);
+
+ talloc_set_destructor(result, aio_child_destructor);
+
+ *presult = result;
+
+ return NT_STATUS_OK;
+
+ fail:
+ if (fdpair[0] != -1) close(fdpair[0]);
+ if (fdpair[1] != -1) close(fdpair[1]);
+ TALLOC_FREE(result);
+
+ return status;
+}
+
+static NTSTATUS get_idle_child(struct vfs_handle_struct *handle,
+ struct aio_child **pchild)
+{
+ struct aio_child_list *children;
+ struct aio_child *child;
+ NTSTATUS status;
+
+ children = init_aio_children(handle);
+ if (children == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (child = children->children; child != NULL; child = child->next) {
+ if (child->aiocb == NULL) {
+ /* idle */
+ break;
+ }
+ }
+
+ if (child == NULL) {
+ DEBUG(10, ("no idle child found, creating new one\n"));
+
+ status = create_aio_child(children, 128*1024, &child);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("create_aio_child failed: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+ }
+
+ child->dont_delete = true;
+
+ *pchild = child;
+ return NT_STATUS_OK;
+}
+
+static int aio_fork_read(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
+{
+ struct aio_child *child;
+ struct rw_cmd cmd;
+ ssize_t ret;
+ NTSTATUS status;
+
+ if (aiocb->aio_nbytes > 128*1024) {
+ /* TODO: support variable buffers */
+ errno = EINVAL;
+ return -1;
+ }
+
+ status = get_idle_child(handle, &child);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Could not get an idle child\n"));
+ return -1;
+ }
+
+ child->read_cmd = true;
+ child->aiocb = aiocb;
+ child->retval.ret_errno = EINPROGRESS;
+
+ ZERO_STRUCT(cmd);
+ cmd.n = aiocb->aio_nbytes;
+ cmd.offset = aiocb->aio_offset;
+ cmd.read_cmd = child->read_cmd;
+
+ DEBUG(10, ("sending fd %d to child %d\n", fsp->fh->fd,
+ (int)child->pid));
+
+ ret = write_fd(child->sockfd, &cmd, sizeof(cmd), fsp->fh->fd);
+ if (ret == -1) {
+ DEBUG(10, ("write_fd failed: %s\n", strerror(errno)));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int aio_fork_write(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
+{
+ struct aio_child *child;
+ struct rw_cmd cmd;
+ ssize_t ret;
+ NTSTATUS status;
+
+ if (aiocb->aio_nbytes > 128*1024) {
+ /* TODO: support variable buffers */
+ errno = EINVAL;
+ return -1;
+ }
+
+ status = get_idle_child(handle, &child);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Could not get an idle child\n"));
+ return -1;
+ }
+
+ child->read_cmd = false;
+ child->aiocb = aiocb;
+ child->retval.ret_errno = EINPROGRESS;
+
+ memcpy((void *)child->map->ptr, (void *)aiocb->aio_buf,
+ aiocb->aio_nbytes);
+
+ ZERO_STRUCT(cmd);
+ cmd.n = aiocb->aio_nbytes;
+ cmd.offset = aiocb->aio_offset;
+ cmd.read_cmd = child->read_cmd;
+
+ DEBUG(10, ("sending fd %d to child %d\n", fsp->fh->fd,
+ (int)child->pid));
+
+ ret = write_fd(child->sockfd, &cmd, sizeof(cmd), fsp->fh->fd);
+ if (ret == -1) {
+ DEBUG(10, ("write_fd failed: %s\n", strerror(errno)));
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct aio_child *aio_fork_find_child(struct vfs_handle_struct *handle,
+ SMB_STRUCT_AIOCB *aiocb)
+{
+ struct aio_child_list *children;
+ struct aio_child *child;
+
+ children = init_aio_children(handle);
+ if (children == NULL) {
+ return NULL;
+ }
+
+ for (child = children->children; child != NULL; child = child->next) {
+ if (child->aiocb == aiocb) {
+ return child;
+ }
+ }
+
+ return NULL;
+}
+
+static ssize_t aio_fork_return_fn(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ SMB_STRUCT_AIOCB *aiocb)
+{
+ struct aio_child *child = aio_fork_find_child(handle, aiocb);
+
+ if (child == NULL) {
+ errno = EINVAL;
+ DEBUG(0, ("returning EINVAL\n"));
+ return -1;
+ }
+
+ child->aiocb = NULL;
+
+ if (child->retval.size == -1) {
+ errno = child->retval.ret_errno;
+ }
+
+ return child->retval.size;
+}
+
+static int aio_fork_cancel(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ SMB_STRUCT_AIOCB *aiocb)
+{
+ struct aio_child_list *children;
+ struct aio_child *child;
+
+ children = init_aio_children(handle);
+ if (children == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ for (child = children->children; child != NULL; child = child->next) {
+ if (child->aiocb == NULL) {
+ continue;
+ }
+ if (child->aiocb->aio_fildes != fsp->fh->fd) {
+ continue;
+ }
+ if ((aiocb != NULL) && (child->aiocb != aiocb)) {
+ continue;
+ }
+
+ /*
+ * We let the child do its job, but we discard the result when
+ * it's finished.
+ */
+
+ child->cancelled = true;
+ }
+
+ return AIO_CANCELED;
+}
+
+static int aio_fork_error_fn(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ SMB_STRUCT_AIOCB *aiocb)
+{
+ struct aio_child *child = aio_fork_find_child(handle, aiocb);
+
+ if (child == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return child->retval.ret_errno;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple aio_fork_ops[] = {
+ {SMB_VFS_OP(aio_fork_read), SMB_VFS_OP_AIO_READ,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(aio_fork_write), SMB_VFS_OP_AIO_WRITE,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(aio_fork_return_fn), SMB_VFS_OP_AIO_RETURN,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(aio_fork_cancel), SMB_VFS_OP_AIO_CANCEL,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(aio_fork_error_fn), SMB_VFS_OP_AIO_ERROR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP,
+ SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_aio_fork_init(void);
+NTSTATUS vfs_aio_fork_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
+ "aio_fork", aio_fork_ops);
+}
diff --git a/source3/modules/vfs_aixacl.c b/source3/modules/vfs_aixacl.c
new file mode 100644
index 0000000000..726a7f485e
--- /dev/null
+++ b/source3/modules/vfs_aixacl.c
@@ -0,0 +1,214 @@
+/*
+ Unix SMB/Netbios implementation.
+ VFS module to get and set posix acls
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern SMB_ACL_T aixacl_to_smbacl( struct acl *file_acl);
+extern struct acl *aixacl_smb_to_aixacl(SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl);
+
+SMB_ACL_T aixacl_sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ SMB_ACL_TYPE_T type)
+{
+ struct acl *file_acl = (struct acl *)NULL;
+ struct smb_acl_t *result = (struct smb_acl_t *)NULL;
+
+ int rc = 0;
+ uid_t user_id;
+
+ /* AIX has no DEFAULT */
+ if ( type == SMB_ACL_TYPE_DEFAULT )
+ return NULL;
+
+ /* Get the acl using statacl */
+
+ DEBUG(10,("Entering AIX sys_acl_get_file\n"));
+ DEBUG(10,("path_p is %s\n",path_p));
+
+ file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
+
+ if(file_acl == NULL) {
+ errno=ENOMEM;
+ DEBUG(0,("Error in AIX sys_acl_get_file: %d\n",errno));
+ return(NULL);
+ }
+
+ memset(file_acl,0,BUFSIZ);
+
+ rc = statacl((char *)path_p,0,file_acl,BUFSIZ);
+ if( (rc == -1) && (errno == ENOSPC)) {
+ struct acl *new_acl = SMB_MALLOC(file_acl->acl_len + sizeof(struct acl));
+ if( new_acl == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ return NULL;
+ }
+ file_acl = new_acl;
+ rc = statacl((char *)path_p,0,file_acl,file_acl->acl_len+sizeof(struct acl));
+ if( rc == -1) {
+ DEBUG(0,("statacl returned %d with errno %d\n",rc,errno));
+ SAFE_FREE(file_acl);
+ return(NULL);
+ }
+ }
+
+ DEBUG(10,("Got facl and returned it\n"));
+
+
+ result = aixacl_to_smbacl(file_acl);
+ SAFE_FREE(file_acl);
+ return result;
+
+ /*errno = ENOTSUP;
+ return NULL;*/
+}
+
+SMB_ACL_T aixacl_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp)
+{
+
+ struct acl *file_acl = (struct acl *)NULL;
+ struct smb_acl_t *result = (struct smb_acl_t *)NULL;
+
+ int rc = 0;
+ uid_t user_id;
+
+ /* Get the acl using fstatacl */
+
+ DEBUG(10,("Entering AIX sys_acl_get_fd\n"));
+ DEBUG(10,("fd is %d\n",fsp->fh->fd));
+ file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
+
+ if(file_acl == NULL) {
+ errno=ENOMEM;
+ DEBUG(0,("Error in AIX sys_acl_get_fd is %d\n",errno));
+ return(NULL);
+ }
+
+ memset(file_acl,0,BUFSIZ);
+
+ rc = fstatacl(fsp->fh->fd,0,file_acl,BUFSIZ);
+ if( (rc == -1) && (errno == ENOSPC)) {
+ struct acl *new_acl = SMB_MALLOC(file_acl->acl_len + sizeof(struct acl));
+ if( new_acl == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ return NULL;
+ }
+ file_acl = new_acl;
+ rc = fstatacl(fsp->fh->fd,0,file_acl,file_acl->acl_len + sizeof(struct acl));
+ if( rc == -1) {
+ DEBUG(0,("fstatacl returned %d with errno %d\n",rc,errno));
+ SAFE_FREE(file_acl);
+ return(NULL);
+ }
+ }
+
+ DEBUG(10,("Got facl and returned it\n"));
+
+ result = aixacl_to_smbacl(file_acl);
+ SAFE_FREE(file_acl);
+ return result;
+
+ /*errno = ENOTSUP;
+ return NULL;*/
+}
+
+int aixacl_sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl)
+{
+ struct acl *file_acl = NULL;
+ unsigned int rc;
+
+ file_acl = aixacl_smb_to_aixacl(type, theacl);
+ if (!file_acl)
+ return -1;
+
+ rc = chacl((char *)name,file_acl,file_acl->acl_len);
+ DEBUG(10,("errno is %d\n",errno));
+ DEBUG(10,("return code is %d\n",rc));
+ SAFE_FREE(file_acl);
+ DEBUG(10,("Exiting the aixacl_sys_acl_set_file\n"));
+
+ return rc;
+}
+
+int aixacl_sys_acl_set_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_T theacl)
+{
+ struct acl *file_acl = NULL;
+ unsigned int rc;
+
+ file_acl = aixacl_smb_to_aixacl(SMB_ACL_TYPE_ACCESS, theacl);
+ if (!file_acl)
+ return -1;
+
+ rc = fchacl(fsp->fh->fd,file_acl,file_acl->acl_len);
+ DEBUG(10,("errno is %d\n",errno));
+ DEBUG(10,("return code is %d\n",rc));
+ SAFE_FREE(file_acl);
+ DEBUG(10,("Exiting aixacl_sys_acl_set_fd\n"));
+
+ return rc;
+}
+
+int aixacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path)
+{
+ return 0; /* otherwise you can't set acl at upper level */
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple aixacl_op_tuples[] = {
+ /* Disk operations */
+ {SMB_VFS_OP(aixacl_sys_acl_get_file),
+ SMB_VFS_OP_SYS_ACL_GET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(aixacl_sys_acl_get_fd),
+ SMB_VFS_OP_SYS_ACL_GET_FD,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(aixacl_sys_acl_set_file),
+ SMB_VFS_OP_SYS_ACL_SET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(aixacl_sys_acl_set_fd),
+ SMB_VFS_OP_SYS_ACL_SET_FD,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(aixacl_sys_acl_delete_def_file),
+ SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(NULL),
+ SMB_VFS_OP_NOOP,
+ SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_aixacl_init(void);
+NTSTATUS vfs_aixacl_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "aixacl",
+ aixacl_op_tuples);
+}
diff --git a/source3/modules/vfs_aixacl2.c b/source3/modules/vfs_aixacl2.c
new file mode 100644
index 0000000000..23c4d88134
--- /dev/null
+++ b/source3/modules/vfs_aixacl2.c
@@ -0,0 +1,534 @@
+/*
+ * Convert JFS2 NFS4/AIXC acls to NT acls and vice versa.
+ *
+ * Copyright (C) Volker Lendecke, 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "nfs4_acls.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+#define AIXACL2_MODULE_NAME "aixacl2"
+
+extern int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid);
+
+extern SMB_ACL_T aixacl_to_smbacl( struct acl *file_acl);
+extern struct acl *aixacl_smb_to_aixacl(SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl);
+
+typedef union aixjfs2_acl_t {
+ nfs4_acl_int_t jfs2_acl[1];
+ aixc_acl_t aixc_acl[1];
+}AIXJFS2_ACL_T;
+
+static int32_t aixacl2_getlen(AIXJFS2_ACL_T *acl, acl_type_t *type)
+{
+ int32_t len;
+
+ if(type->u64 == ACL_NFS4) {
+ len = acl->jfs2_acl[0].aclLength;
+ }
+ else {
+ if(type->u64 == ACL_AIXC) {
+ len = acl->aixc_acl[0].acl_len;
+ } else {
+ DEBUG(0,("aixacl2_getlen:unknown type:%d\n",type->u64));
+ return False;
+ }
+ }
+ DEBUG(10,("aixacl2_getlen:%d\n",len));
+ return len;
+}
+
+static AIXJFS2_ACL_T *aixjfs2_getacl_alloc(const char *fname, acl_type_t *type)
+{
+ AIXJFS2_ACL_T *acl;
+ size_t len = 200;
+ mode_t mode;
+ int ret;
+ uint64_t ctl_flag=0;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_tos();
+ acl = (AIXJFS2_ACL_T *)TALLOC_SIZE(mem_ctx, len);
+ if (acl == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ if(type->u64 == ACL_ANY) {
+ ctl_flag = ctl_flag | GET_ACLINFO_ONLY;
+ }
+
+ ret = aclx_get((char *)fname, ctl_flag, type, acl, &len, &mode);
+ if ((ret != 0) && (errno == ENOSPC)) {
+ len = aixacl2_getlen(acl, type) + sizeof(AIXJFS2_ACL_T);
+ DEBUG(10,("aixjfs2_getacl_alloc - acl_len:%d\n",len));
+
+ acl = (AIXJFS2_ACL_T *)TALLOC_SIZE(mem_ctx, len);
+ if (acl == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ ret = aclx_get((char *)fname, ctl_flag, type, acl, &len, &mode);
+ }
+ if (ret != 0) {
+ DEBUG(8, ("aclx_get failed with %s\n", strerror(errno)));
+ return NULL;
+ }
+
+ return acl;
+}
+
+static bool aixjfs2_get_nfs4_acl(const char *name,
+ SMB4ACL_T **ppacl, bool *pretryPosix)
+{
+ int32_t i;
+
+ AIXJFS2_ACL_T *pacl = NULL;
+ nfs4_acl_int_t *jfs2_acl = NULL;
+ nfs4_ace_int_t *jfs2_ace = NULL;
+ acl_type_t type;
+
+ DEBUG(10,("jfs2 get_nt_acl invoked for %s\n", name));
+
+ memset(&type, 0, sizeof(acl_type_t));
+ type.u64 = ACL_NFS4;
+
+ pacl = aixjfs2_getacl_alloc(name, &type);
+ if (pacl == NULL) {
+ DEBUG(9, ("aixjfs2_getacl_alloc failed for %s with %s\n",
+ name, strerror(errno)));
+ if (errno==ENOSYS)
+ *pretryPosix = True;
+ return False;
+ }
+
+ jfs2_acl = &pacl->jfs2_acl[0];
+ DEBUG(10, ("len: %d, version: %d, nace: %d, type: 0x%x\n",
+ jfs2_acl->aclLength, jfs2_acl->aclVersion, jfs2_acl->aclEntryN, type.u64));
+
+ *ppacl = smb_create_smb4acl();
+ if (*ppacl==NULL)
+ return False;
+
+ jfs2_ace = &jfs2_acl->aclEntry[0];
+ for (i=0; i<jfs2_acl->aclEntryN; i++) {
+ SMB_ACE4PROP_T aceprop;
+
+ DEBUG(10, ("type: %d, iflags: %x, flags: %x, mask: %x, "
+ "who: %d, aclLen: %d\n", jfs2_ace->aceType, jfs2_ace->flags,
+ jfs2_ace->aceFlags, jfs2_ace->aceMask, jfs2_ace->aceWho.id, jfs2_ace->entryLen));
+
+ aceprop.aceType = jfs2_ace->aceType;
+ aceprop.aceFlags = jfs2_ace->aceFlags;
+ aceprop.aceMask = jfs2_ace->aceMask;
+ aceprop.flags = (jfs2_ace->flags&ACE4_ID_SPECIAL) ? SMB_ACE4_ID_SPECIAL : 0;
+
+ /* don't care it's real content is only 16 or 32 bit */
+ aceprop.who.id = jfs2_ace->aceWho.id;
+
+ if (smb_add_ace4(*ppacl, &aceprop)==NULL)
+ return False;
+
+ /* iterate to the next jfs2 ace */
+ jfs2_ace = (nfs4_ace_int_t *)(((char *)jfs2_ace) + jfs2_ace->entryLen);
+ }
+
+ DEBUG(10,("jfs2 get_nt_acl finished successfully\n"));
+
+ return True;
+}
+
+static NTSTATUS aixjfs2_fget_nt_acl(vfs_handle_struct *handle,
+ files_struct *fsp, uint32 security_info,
+ SEC_DESC **ppdesc)
+{
+ SMB4ACL_T *pacl = NULL;
+ bool result;
+ bool retryPosix = False;
+
+ *ppdesc = NULL;
+ result = aixjfs2_get_nfs4_acl(fsp->fsp_name, &pacl, &retryPosix);
+ if (retryPosix)
+ {
+ DEBUG(10, ("retrying with posix acl...\n"));
+ return posix_fget_nt_acl(fsp, security_info, ppdesc);
+ }
+ if (result==False)
+ return NT_STATUS_ACCESS_DENIED;
+
+ return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
+}
+
+static NTSTATUS aixjfs2_get_nt_acl(vfs_handle_struct *handle,
+ const char *name,
+ uint32 security_info, SEC_DESC **ppdesc)
+{
+ SMB4ACL_T *pacl = NULL;
+ bool result;
+ bool retryPosix = False;
+
+ *ppdesc = NULL;
+ result = aixjfs2_get_nfs4_acl(name, &pacl, &retryPosix);
+ if (retryPosix)
+ {
+ DEBUG(10, ("retrying with posix acl...\n"));
+ return posix_get_nt_acl(handle->conn, name, security_info,
+ ppdesc);
+ }
+ if (result==False)
+ return NT_STATUS_ACCESS_DENIED;
+
+ return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc,
+ pacl);
+}
+
+static SMB_ACL_T aixjfs2_get_posix_acl(const char *path, acl_type_t type)
+{
+ aixc_acl_t *pacl;
+ AIXJFS2_ACL_T *acl;
+ SMB_ACL_T result = NULL;
+ int ret;
+
+ acl = aixjfs2_getacl_alloc(path, &type);
+
+ if (acl == NULL) {
+ DEBUG(10, ("aixjfs2_getacl failed for %s with %s\n",
+ path, strerror(errno)));
+ if (errno == 0) {
+ errno = EINVAL;
+ }
+ goto done;
+ }
+
+ pacl = &acl->aixc_acl[0];
+ DEBUG(10, ("len: %d, mode: %d\n",
+ pacl->acl_len, pacl->acl_mode));
+
+ result = aixacl_to_smbacl(pacl);
+ if (result == NULL) {
+ goto done;
+ }
+
+ done:
+ if (errno != 0) {
+ SAFE_FREE(result);
+ }
+ return result;
+}
+
+SMB_ACL_T aixjfs2_sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ SMB_ACL_TYPE_T type)
+{
+ acl_type_t aixjfs2_type;
+
+ switch(type) {
+ case SMB_ACL_TYPE_ACCESS:
+ aixjfs2_type.u64 = ACL_AIXC;
+ break;
+ case SMB_ACL_TYPE_DEFAULT:
+ DEBUG(0, ("Got AIX JFS2 unsupported type: %d\n", type));
+ return NULL;
+ default:
+ DEBUG(0, ("Got invalid type: %d\n", type));
+ smb_panic("exiting");
+ }
+
+ return aixjfs2_get_posix_acl(path_p, aixjfs2_type);
+}
+
+SMB_ACL_T aixjfs2_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp)
+{
+ acl_type_t aixjfs2_type;
+ aixjfs2_type.u64 = ACL_AIXC;
+
+ return aixjfs2_get_posix_acl(fsp->fsp_name, aixjfs2_type);
+}
+
+/*
+ * Test whether we have that aclType support on the given path
+ */
+static int aixjfs2_query_acl_support(
+ char *filepath,
+ uint64_t aclType,
+ acl_type_t *pacl_type_info
+)
+{
+ acl_types_list_t acl_type_list;
+ size_t acl_type_list_len = sizeof(acl_types_list_t);
+ uint32_t i;
+
+ memset(&acl_type_list, 0, sizeof(acl_type_list));
+
+ if (aclx_gettypes(filepath, &acl_type_list, &acl_type_list_len)) {
+ DEBUG(2, ("aclx_gettypes failed with error %s for %s\n",
+ strerror(errno), filepath));
+ return -1;
+ }
+
+ for(i=0; i<acl_type_list.num_entries; i++) {
+ if (acl_type_list.entries[i].u64==aclType) {
+ memcpy(pacl_type_info, acl_type_list.entries + i, sizeof(acl_type_t));
+ DEBUG(10, ("found %s ACL support for %s\n",
+ pacl_type_info->acl_type, filepath));
+ return 0;
+ }
+ }
+
+ return 1; /* haven't found that ACL type. */
+}
+
+static bool aixjfs2_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
+{
+ SMB4ACE_T *smbace;
+ TALLOC_CTX *mem_ctx;
+ nfs4_acl_int_t *jfs2acl;
+ int32_t entryLen;
+ uint32 aclLen, naces;
+ int rc;
+ acl_type_t acltype;
+
+ DEBUG(10, ("jfs2_process_smbacl invoked on %s\n", fsp->fsp_name));
+
+ /* no need to be freed which is alloced with mem_ctx */
+ mem_ctx = talloc_tos();
+
+ entryLen = sizeof(nfs4_ace_int_t);
+ if (entryLen & 0x03)
+ entryLen = entryLen + 4 - (entryLen%4);
+
+ naces = smb_get_naces(smbacl);
+ aclLen = ACL_V4_SIZ + naces * entryLen;
+ jfs2acl = (nfs4_acl_int_t *)TALLOC_SIZE(mem_ctx, aclLen);
+ if (jfs2acl==NULL) {
+ DEBUG(0, ("TALLOC_SIZE failed\n"));
+ errno = ENOMEM;
+ return False;
+ }
+
+ jfs2acl->aclLength = ACL_V4_SIZ;
+ jfs2acl->aclVersion = NFS4_ACL_INT_STRUCT_VERSION;
+ jfs2acl->aclEntryN = 0;
+
+ for(smbace = smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace))
+ {
+ SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
+ nfs4_ace_int_t *jfs2_ace = (nfs4_ace_int_t *)(((char *)jfs2acl) + jfs2acl->aclLength);
+
+ memset(jfs2_ace, 0, entryLen);
+ jfs2_ace->entryLen = entryLen; /* won't store textual "who" */
+ jfs2_ace->aceType = aceprop->aceType; /* only ACCES|DENY supported by jfs2 */
+ jfs2_ace->aceFlags = aceprop->aceFlags;
+ jfs2_ace->aceMask = aceprop->aceMask;
+ jfs2_ace->flags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_ID_SPECIAL : 0;
+
+ /* don't care it's real content is only 16 or 32 bit */
+ jfs2_ace->aceWho.id = aceprop->who.id;
+
+ /* iterate to the next jfs2 ace */
+ jfs2acl->aclLength += jfs2_ace->entryLen;
+ jfs2acl->aclEntryN++;
+ }
+ SMB_ASSERT(jfs2acl->aclEntryN==naces);
+
+ /* Don't query it (again) */
+ memset(&acltype, 0, sizeof(acl_type_t));
+ acltype.u64 = ACL_NFS4;
+
+ /* won't set S_ISUID - the only one JFS2/NFS4 accepts */
+ rc = aclx_put(
+ fsp->fsp_name,
+ SET_ACL, /* set only the ACL, not mode bits */
+ acltype, /* not a pointer !!! */
+ jfs2acl,
+ jfs2acl->aclLength,
+ 0 /* don't set here mode bits */
+ );
+ if (rc) {
+ DEBUG(8, ("aclx_put failed with %s\n", strerror(errno)));
+ return False;
+ }
+
+ DEBUG(10, ("jfs2_process_smbacl succeeded.\n"));
+ return True;
+}
+
+static NTSTATUS aixjfs2_set_nt_acl_common(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
+{
+ acl_type_t acl_type_info;
+ NTSTATUS result = NT_STATUS_ACCESS_DENIED;
+ int rc;
+
+ rc = aixjfs2_query_acl_support(
+ fsp->fsp_name,
+ ACL_NFS4,
+ &acl_type_info);
+
+ if (rc==0)
+ {
+ result = smb_set_nt_acl_nfs4(
+ fsp, security_info_sent, psd,
+ aixjfs2_process_smbacl);
+ } else if (rc==1) { /* assume POSIX ACL - by default... */
+ result = set_nt_acl(fsp, security_info_sent, psd);
+ } else
+ result = map_nt_error_from_unix(errno); /* query failed */
+
+ return result;
+}
+
+NTSTATUS aixjfs2_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
+{
+ return aixjfs2_set_nt_acl_common(fsp, security_info_sent, psd);
+}
+
+int aixjfs2_sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl)
+{
+ struct acl *acl_aixc;
+ acl_type_t acl_type_info;
+ int rc;
+
+ DEBUG(10, ("aixjfs2_sys_acl_set_file invoked for %s", name));
+
+ rc = aixjfs2_query_acl_support((char *)name, ACL_AIXC, &acl_type_info);
+ if (rc) {
+ DEBUG(8, ("jfs2_set_nt_acl: AIXC support not found\n"));
+ return -1;
+ }
+
+ acl_aixc = aixacl_smb_to_aixacl(type, theacl);
+ if (!acl_aixc)
+ return -1;
+
+ rc = aclx_put(
+ (char *)name,
+ SET_ACL, /* set only the ACL, not mode bits */
+ acl_type_info,
+ acl_aixc,
+ acl_aixc->acl_len,
+ 0
+ );
+ if (rc) {
+ DEBUG(2, ("aclx_put failed with %s for %s\n",
+ strerror(errno), name));
+ return -1;
+ }
+
+ return 0;
+}
+
+int aixjfs2_sys_acl_set_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_T theacl)
+{
+ struct acl *acl_aixc;
+ acl_type_t acl_type_info;
+ int rc;
+
+ DEBUG(10, ("aixjfs2_sys_acl_set_fd invoked for %s", fsp->fsp_name));
+
+ rc = aixjfs2_query_acl_support(fsp->fsp_name, ACL_AIXC, &acl_type_info);
+ if (rc) {
+ DEBUG(8, ("jfs2_set_nt_acl: AIXC support not found\n"));
+ return -1;
+ }
+
+ acl_aixc = aixacl_smb_to_aixacl(SMB_ACL_TYPE_ACCESS, theacl);
+ if (!acl_aixc)
+ return -1;
+
+ rc = aclx_fput(
+ fsp->fh->fd,
+ SET_ACL, /* set only the ACL, not mode bits */
+ acl_type_info,
+ acl_aixc,
+ acl_aixc->acl_len,
+ 0
+ );
+ if (rc) {
+ DEBUG(2, ("aclx_fput failed with %s for %s\n",
+ strerror(errno), fsp->fsp_name));
+ return -1;
+ }
+
+ return 0;
+}
+
+int aixjfs2_sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path)
+{
+ /* Not available under AIXC ACL */
+ /* Don't report here any error otherwise */
+ /* upper layer will break the normal execution */
+ return 0;
+}
+
+
+/* VFS operations structure */
+
+static vfs_op_tuple aixjfs2_ops[] =
+{
+ {SMB_VFS_OP(aixjfs2_fget_nt_acl),
+ SMB_VFS_OP_FGET_NT_ACL,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(aixjfs2_get_nt_acl),
+ SMB_VFS_OP_GET_NT_ACL,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(aixjfs2_fset_nt_acl),
+ SMB_VFS_OP_FSET_NT_ACL,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(aixjfs2_sys_acl_get_file),
+ SMB_VFS_OP_SYS_ACL_GET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(aixjfs2_sys_acl_get_fd),
+ SMB_VFS_OP_SYS_ACL_GET_FD,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(aixjfs2_sys_acl_set_file),
+ SMB_VFS_OP_SYS_ACL_SET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(aixjfs2_sys_acl_set_fd),
+ SMB_VFS_OP_SYS_ACL_SET_FD,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(aixjfs2_sys_acl_delete_def_file),
+ SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(NULL),
+ SMB_VFS_OP_NOOP,
+ SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_aixacl2_init(void);
+NTSTATUS vfs_aixacl2_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, AIXACL2_MODULE_NAME,
+ aixjfs2_ops);
+}
diff --git a/source3/modules/vfs_aixacl_util.c b/source3/modules/vfs_aixacl_util.c
new file mode 100644
index 0000000000..b2329fe9c6
--- /dev/null
+++ b/source3/modules/vfs_aixacl_util.c
@@ -0,0 +1,296 @@
+/*
+ Unix SMB/Netbios implementation.
+ VFS module to get and set posix acls
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+SMB_ACL_T aixacl_to_smbacl(struct acl *file_acl)
+{
+ struct acl_entry *acl_entry;
+ struct ace_id *idp;
+
+ struct smb_acl_t *result = SMB_MALLOC_P(struct smb_acl_t);
+ struct smb_acl_entry *ace;
+ int i;
+
+ if (result == NULL) {
+ return NULL;
+ }
+ ZERO_STRUCTP(result);
+
+ /* Point to the first acl entry in the acl */
+ acl_entry = file_acl->acl_ext;
+
+
+
+ DEBUG(10,("acl_entry is %d\n",acl_entry));
+ DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
+
+ /* Check if the extended acl bit is on. *
+ * If it isn't, do not show the *
+ * contents of the acl since AIX intends *
+ * the extended info to remain unused */
+
+ if(file_acl->acl_mode & S_IXACL){
+ /* while we are not pointing to the very end */
+ while(acl_entry < acl_last(file_acl)) {
+ /* before we malloc anything, make sure this is */
+ /* a valid acl entry and one that we want to map */
+ idp = id_nxt(acl_entry->ace_id);
+ if((acl_entry->ace_type == ACC_SPECIFY ||
+ (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
+ acl_entry = acl_nxt(acl_entry);
+ continue;
+ }
+
+ idp = acl_entry->ace_id;
+ DEBUG(10,("idp->id_data is %d\n",idp->id_data[0]));
+
+ result = SMB_REALLOC(result, sizeof(struct smb_acl_t) +
+ (sizeof(struct smb_acl_entry) *
+ (result->count+1)));
+ if (result == NULL) {
+ DEBUG(0, ("SMB_REALLOC failed\n"));
+ errno = ENOMEM;
+ return NULL;
+ }
+
+
+ DEBUG(10,("idp->id_type is %d\n",idp->id_type));
+ ace = &result->acl[result->count];
+
+ ace->a_type = idp->id_type;
+
+ switch(ace->a_type) {
+ case ACEID_USER: {
+ ace->uid = idp->id_data[0];
+ DEBUG(10,("case ACEID_USER ace->uid is %d\n",ace->uid));
+ ace->a_type = SMB_ACL_USER;
+ break;
+ }
+
+ case ACEID_GROUP: {
+ ace->gid = idp->id_data[0];
+ DEBUG(10,("case ACEID_GROUP ace->gid is %d\n",ace->gid));
+ ace->a_type = SMB_ACL_GROUP;
+ break;
+ }
+ default:
+ break;
+ }
+ /* The access in the acl entries must be left shifted by *
+ * three bites, because they will ultimately be compared *
+ * to S_IRUSR, S_IWUSR, and S_IXUSR. */
+
+ switch(acl_entry->ace_type){
+ case ACC_PERMIT:
+ case ACC_SPECIFY:
+ ace->a_perm = acl_entry->ace_access;
+ ace->a_perm <<= 6;
+ DEBUG(10,("ace->a_perm is %d\n",ace->a_perm));
+ break;
+ case ACC_DENY:
+ /* Since there is no way to return a DENY acl entry *
+ * change to PERMIT and then shift. */
+ DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
+ ace->a_perm = ~acl_entry->ace_access & 7;
+ DEBUG(10,("ace->a_perm is %d\n",ace->a_perm));
+ ace->a_perm <<= 6;
+ break;
+ default:
+ DEBUG(0, ("unknown ace->type\n"));
+ SAFE_FREE(result);
+ return(0);
+ }
+
+ result->count++;
+ ace->a_perm |= (ace->a_perm & S_IRUSR) ? SMB_ACL_READ : 0;
+ ace->a_perm |= (ace->a_perm & S_IWUSR) ? SMB_ACL_WRITE : 0;
+ ace->a_perm |= (ace->a_perm & S_IXUSR) ? SMB_ACL_EXECUTE : 0;
+ DEBUG(10,("ace->a_perm is %d\n",ace->a_perm));
+
+ DEBUG(10,("acl_entry = %d\n",acl_entry));
+ DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
+
+ acl_entry = acl_nxt(acl_entry);
+ }
+ } /* end of if enabled */
+
+ /* Since owner, group, other acl entries are not *
+ * part of the acl entries in an acl, they must *
+ * be dummied up to become part of the list. */
+
+ for( i = 1; i < 4; i++) {
+ DEBUG(10,("i is %d\n",i));
+
+ result = SMB_REALLOC(result, sizeof(struct smb_acl_t) +
+ (sizeof(struct smb_acl_entry) *
+ (result->count+1)));
+ if (result == NULL) {
+ DEBUG(0, ("SMB_REALLOC failed\n"));
+ errno = ENOMEM;
+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
+ return NULL;
+ }
+
+ ace = &result->acl[result->count];
+
+ ace->uid = 0;
+ ace->gid = 0;
+ DEBUG(10,("ace->uid = %d\n",ace->uid));
+
+ switch(i) {
+ case 2:
+ ace->a_perm = file_acl->g_access << 6;
+ ace->a_type = SMB_ACL_GROUP_OBJ;
+ break;
+
+ case 3:
+ ace->a_perm = file_acl->o_access << 6;
+ ace->a_type = SMB_ACL_OTHER;
+ break;
+
+ case 1:
+ ace->a_perm = file_acl->u_access << 6;
+ ace->a_type = SMB_ACL_USER_OBJ;
+ break;
+
+ default:
+ return(NULL);
+
+ }
+ ace->a_perm |= ((ace->a_perm & S_IRUSR) ? SMB_ACL_READ : 0);
+ ace->a_perm |= ((ace->a_perm & S_IWUSR) ? SMB_ACL_WRITE : 0);
+ ace->a_perm |= ((ace->a_perm & S_IXUSR) ? SMB_ACL_EXECUTE : 0);
+
+ memcpy(&result->acl[result->count],ace,sizeof(struct smb_acl_entry));
+ result->count++;
+ DEBUG(10,("ace->a_perm = %d\n",ace->a_perm));
+ DEBUG(10,("ace->a_type = %d\n",ace->a_type));
+ }
+
+
+ return result;
+
+
+}
+
+static ushort aixacl_smb_to_aixperm(SMB_ACL_PERM_T a_perm)
+{
+ ushort ret = (ushort)0;
+ if (a_perm & SMB_ACL_READ)
+ ret |= R_ACC;
+ if (a_perm & SMB_ACL_WRITE)
+ ret |= W_ACC;
+ if (a_perm & SMB_ACL_EXECUTE)
+ ret |= X_ACC;
+ return ret;
+}
+
+struct acl *aixacl_smb_to_aixacl(SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
+{
+ struct smb_acl_entry *smb_entry = NULL;
+ struct acl *file_acl = NULL;
+ struct acl *file_acl_temp = NULL;
+ struct acl_entry *acl_entry = NULL;
+ struct ace_id *ace_id = NULL;
+ unsigned int id_type;
+ unsigned int user_id;
+ unsigned int acl_length;
+ int i;
+
+ DEBUG(10,("Entering aixacl_smb_to_aixacl\n"));
+ /* AIX has no default ACL */
+ if(acltype == SMB_ACL_TYPE_DEFAULT)
+ return NULL;
+
+ acl_length = BUFSIZ;
+ file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
+ if(file_acl == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in aixacl_smb_to_aixacl is %d\n",errno));
+ return NULL;
+ }
+
+ memset(file_acl,0,BUFSIZ);
+
+ file_acl->acl_len = ACL_SIZ;
+ file_acl->acl_mode = S_IXACL;
+
+ for(i=0; i<theacl->count; i++ ) {
+ smb_entry = &(theacl->acl[i]);
+ id_type = smb_entry->a_type;
+ DEBUG(10,("The id_type is %d\n",id_type));
+
+ switch(id_type) {
+ case SMB_ACL_USER_OBJ:
+ file_acl->u_access = aixacl_smb_to_aixperm(smb_entry->a_perm);
+ continue;
+ case SMB_ACL_GROUP_OBJ:
+ file_acl->g_access = aixacl_smb_to_aixperm(smb_entry->a_perm);
+ continue;
+ case SMB_ACL_OTHER:
+ file_acl->o_access = aixacl_smb_to_aixperm(smb_entry->a_perm);
+ continue;
+ case SMB_ACL_MASK:
+ continue;
+ case SMB_ACL_GROUP:
+ break; /* process this */
+ case SMB_ACL_USER:
+ break; /* process this */
+ default: /* abnormal case */
+ DEBUG(10,("The id_type is unknown !\n"));
+ continue;
+ }
+
+ if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
+ acl_length += sizeof(struct acl_entry);
+ file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
+ if(file_acl_temp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in aixacl_smb_to_aixacl is %d\n",errno));
+ return NULL;
+ }
+
+ memcpy(file_acl_temp,file_acl,file_acl->acl_len);
+ SAFE_FREE(file_acl);
+ file_acl = file_acl_temp;
+ }
+
+ acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
+ file_acl->acl_len += sizeof(struct acl_entry);
+ acl_entry->ace_len = sizeof(struct acl_entry); /* contains 1 ace_id */
+ acl_entry->ace_access = aixacl_smb_to_aixperm(smb_entry->a_perm);
+
+ /* In order to use this, we'll need to wait until we can get denies */
+ /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
+ acl_entry->ace_type = ACC_SPECIFY; */
+
+ acl_entry->ace_type = ACC_SPECIFY;
+
+ ace_id = acl_entry->ace_id;
+
+ ace_id->id_type = (smb_entry->a_type==SMB_ACL_GROUP) ? ACEID_GROUP : ACEID_USER;
+ DEBUG(10,("The id type is %d\n",ace_id->id_type));
+ ace_id->id_len = sizeof(struct ace_id); /* contains 1 id_data */
+ ace_id->id_data[0] = (smb_entry->a_type==SMB_ACL_GROUP) ? smb_entry->gid : smb_entry->uid;
+ }
+
+ return file_acl;
+}
diff --git a/source3/modules/vfs_audit.c b/source3/modules/vfs_audit.c
new file mode 100644
index 0000000000..4000580c42
--- /dev/null
+++ b/source3/modules/vfs_audit.c
@@ -0,0 +1,307 @@
+/*
+ * Auditing VFS module for samba. Log selected file operations to syslog
+ * facility.
+ *
+ * Copyright (C) Tim Potter 1999-2000
+ * Copyright (C) Alexander Bokovoy 2002
+ * Copyright (C) Stefan (metze) Metzmacher 2002
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+/* Function prototypes */
+
+static int audit_connect(vfs_handle_struct *handle, const char *svc, const char *user);
+static void audit_disconnect(vfs_handle_struct *handle);
+static SMB_STRUCT_DIR *audit_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr);
+static int audit_mkdir(vfs_handle_struct *handle, const char *path, mode_t mode);
+static int audit_rmdir(vfs_handle_struct *handle, const char *path);
+static int audit_open(vfs_handle_struct *handle, const char *fname, files_struct *fsp, int flags, mode_t mode);
+static int audit_close(vfs_handle_struct *handle, files_struct *fsp);
+static int audit_rename(vfs_handle_struct *handle, const char *oldname, const char *newname);
+static int audit_unlink(vfs_handle_struct *handle, const char *path);
+static int audit_chmod(vfs_handle_struct *handle, const char *path, mode_t mode);
+static int audit_chmod_acl(vfs_handle_struct *handle, const char *name, mode_t mode);
+static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode);
+static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode);
+
+/* VFS operations */
+
+static vfs_op_tuple audit_op_tuples[] = {
+
+ /* Disk operations */
+
+ {SMB_VFS_OP(audit_connect), SMB_VFS_OP_CONNECT, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_disconnect), SMB_VFS_OP_DISCONNECT, SMB_VFS_LAYER_LOGGER},
+
+ /* Directory operations */
+
+ {SMB_VFS_OP(audit_opendir), SMB_VFS_OP_OPENDIR, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_mkdir), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_rmdir), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_LOGGER},
+
+ /* File operations */
+
+ {SMB_VFS_OP(audit_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_close), SMB_VFS_OP_CLOSE, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_rename), SMB_VFS_OP_RENAME, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_unlink), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_chmod), SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_fchmod), SMB_VFS_OP_FCHMOD, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_chmod_acl), SMB_VFS_OP_CHMOD_ACL, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_fchmod_acl), SMB_VFS_OP_FCHMOD_ACL, SMB_VFS_LAYER_LOGGER},
+
+ /* Finish VFS operations definition */
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+
+static int audit_syslog_facility(vfs_handle_struct *handle)
+{
+ static const struct enum_list enum_log_facilities[] = {
+ { LOG_USER, "USER" },
+ { LOG_LOCAL0, "LOCAL0" },
+ { LOG_LOCAL1, "LOCAL1" },
+ { LOG_LOCAL2, "LOCAL2" },
+ { LOG_LOCAL3, "LOCAL3" },
+ { LOG_LOCAL4, "LOCAL4" },
+ { LOG_LOCAL5, "LOCAL5" },
+ { LOG_LOCAL6, "LOCAL6" },
+ { LOG_LOCAL7, "LOCAL7" }
+ };
+
+ int facility;
+
+ facility = lp_parm_enum(SNUM(handle->conn), "audit", "facility", enum_log_facilities, LOG_USER);
+
+ return facility;
+}
+
+
+static int audit_syslog_priority(vfs_handle_struct *handle)
+{
+ static const struct enum_list enum_log_priorities[] = {
+ { LOG_EMERG, "EMERG" },
+ { LOG_ALERT, "ALERT" },
+ { LOG_CRIT, "CRIT" },
+ { LOG_ERR, "ERR" },
+ { LOG_WARNING, "WARNING" },
+ { LOG_NOTICE, "NOTICE" },
+ { LOG_INFO, "INFO" },
+ { LOG_DEBUG, "DEBUG" }
+ };
+
+ int priority;
+
+ priority = lp_parm_enum(SNUM(handle->conn), "audit", "priority",
+ enum_log_priorities, LOG_NOTICE);
+ if (priority == -1) {
+ priority = LOG_WARNING;
+ }
+
+ return priority;
+}
+
+/* Implementation of vfs_ops. Pass everything on to the default
+ operation but log event first. */
+
+static int audit_connect(vfs_handle_struct *handle, const char *svc, const char *user)
+{
+ int result;
+
+ openlog("smbd_audit", LOG_PID, audit_syslog_facility(handle));
+
+ syslog(audit_syslog_priority(handle), "connect to service %s by user %s\n",
+ svc, user);
+
+ result = SMB_VFS_NEXT_CONNECT(handle, svc, user);
+
+ return result;
+}
+
+static void audit_disconnect(vfs_handle_struct *handle)
+{
+ syslog(audit_syslog_priority(handle), "disconnected\n");
+ SMB_VFS_NEXT_DISCONNECT(handle);
+
+ return;
+}
+
+static SMB_STRUCT_DIR *audit_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr)
+{
+ SMB_STRUCT_DIR *result;
+
+ result = SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
+
+ syslog(audit_syslog_priority(handle), "opendir %s %s%s\n",
+ fname,
+ (result == NULL) ? "failed: " : "",
+ (result == NULL) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_mkdir(vfs_handle_struct *handle, const char *path, mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_MKDIR(handle, path, mode);
+
+ syslog(audit_syslog_priority(handle), "mkdir %s %s%s\n",
+ path,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_rmdir(vfs_handle_struct *handle, const char *path)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_RMDIR(handle, path);
+
+ syslog(audit_syslog_priority(handle), "rmdir %s %s%s\n",
+ path,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_open(vfs_handle_struct *handle, const char *fname, files_struct *fsp, int flags, mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+
+ syslog(audit_syslog_priority(handle), "open %s (fd %d) %s%s%s\n",
+ fname, result,
+ ((flags & O_WRONLY) || (flags & O_RDWR)) ? "for writing " : "",
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_close(vfs_handle_struct *handle, files_struct *fsp)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_CLOSE(handle, fsp);
+
+ syslog(audit_syslog_priority(handle), "close fd %d %s%s\n",
+ fsp->fh->fd,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_rename(vfs_handle_struct *handle, const char *oldname, const char *newname)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_RENAME(handle, oldname, newname);
+
+ syslog(audit_syslog_priority(handle), "rename %s -> %s %s%s\n",
+ oldname, newname,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_unlink(vfs_handle_struct *handle, const char *path)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_UNLINK(handle, path);
+
+ syslog(audit_syslog_priority(handle), "unlink %s %s%s\n",
+ path,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_CHMOD(handle, path, mode);
+
+ syslog(audit_syslog_priority(handle), "chmod %s mode 0x%x %s%s\n",
+ path, mode,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_chmod_acl(vfs_handle_struct *handle, const char *path, mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_CHMOD_ACL(handle, path, mode);
+
+ syslog(audit_syslog_priority(handle), "chmod_acl %s mode 0x%x %s%s\n",
+ path, mode,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
+
+ syslog(audit_syslog_priority(handle), "fchmod %s mode 0x%x %s%s\n",
+ fsp->fsp_name, mode,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
+
+ syslog(audit_syslog_priority(handle), "fchmod_acl %s mode 0x%x %s%s\n",
+ fsp->fsp_name, mode,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+NTSTATUS vfs_audit_init(void);
+NTSTATUS vfs_audit_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "audit", audit_op_tuples);
+}
diff --git a/source3/modules/vfs_cacheprime.c b/source3/modules/vfs_cacheprime.c
new file mode 100644
index 0000000000..fed051ca8d
--- /dev/null
+++ b/source3/modules/vfs_cacheprime.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) James Peach 2005-2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/* Cache priming module.
+ *
+ * The purpose of this module is to do RAID stripe width reads to prime the
+ * buffer cache to do zero-copy I/O for subsequent sendfile calls. The idea is
+ * to do a single large read at the start of the file to make sure that most or
+ * all of the file is pulled into the buffer cache. Subsequent I/Os have
+ * reduced latency.
+ *
+ * Tunables.
+ *
+ * cacheprime:rsize Amount of readahead in bytes. This should be a
+ * multiple of the RAID stripe width.
+ * cacheprime:debug Debug level at which to emit messages.
+ */
+
+#define READAHEAD_MIN (128 * 1024) /* min is 128 KiB */
+#define READAHEAD_MAX (100 * 1024 * 1024) /* max is 100 MiB */
+
+#define MODULE "cacheprime"
+
+static int module_debug;
+static ssize_t g_readsz = 0;
+static void * g_readbuf = NULL;
+
+/* Prime the kernel buffer cache with data from the specified file. We use
+ * per-fsp data to make sure we only ever do this once. If pread is being
+ * emulated by seek/read/seek, when this will suck quite a lot.
+ */
+static bool prime_cache(
+ struct vfs_handle_struct * handle,
+ files_struct * fsp,
+ SMB_OFF_T offset,
+ size_t count)
+{
+ SMB_OFF_T * last;
+ ssize_t nread;
+
+ last = (SMB_OFF_T *)VFS_ADD_FSP_EXTENSION(handle, fsp, SMB_OFF_T);
+ if (!last) {
+ return False;
+ }
+
+ if (*last == -1) {
+ /* Readahead disabled. */
+ return False;
+ }
+
+ if ((*last + g_readsz) > (offset + count)) {
+ /* Skip readahead ... we've already been here. */
+ return False;
+ }
+
+ DEBUG(module_debug,
+ ("%s: doing readahead of %lld bytes at %lld for %s\n",
+ MODULE, (long long)g_readsz, (long long)*last,
+ fsp->fsp_name));
+
+ nread = sys_pread(fsp->fh->fd, g_readbuf, g_readsz, *last);
+ if (nread < 0) {
+ *last = -1;
+ return False;
+ }
+
+ *last += nread;
+ return True;
+}
+
+static int cprime_connect(
+ struct vfs_handle_struct * handle,
+ const char * service,
+ const char * user)
+{
+ module_debug = lp_parm_int(SNUM(handle->conn), MODULE, "debug", 100);
+ if (g_readbuf) {
+ /* Only allocate g_readbuf once. If the config changes and
+ * another client multiplexes onto this smbd, we don't want
+ * to risk memory corruption.
+ */
+ return SMB_VFS_NEXT_CONNECT(handle, service, user);
+ }
+
+ g_readsz = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
+ MODULE, "rsize", NULL));
+
+ if (g_readsz < READAHEAD_MIN) {
+ DEBUG(module_debug, ("%s: %ld bytes of readahead "
+ "requested, using minimum of %u\n",
+ MODULE, (long)g_readsz, READAHEAD_MIN));
+ g_readsz = READAHEAD_MIN;
+ } else if (g_readsz > READAHEAD_MAX) {
+ DEBUG(module_debug, ("%s: %ld bytes of readahead "
+ "requested, using maximum of %u\n",
+ MODULE, (long)g_readsz, READAHEAD_MAX));
+ g_readsz = READAHEAD_MAX;
+ }
+
+ if ((g_readbuf = SMB_MALLOC(g_readsz)) == NULL) {
+ /* Turn off readahead if we can't get a buffer. */
+ g_readsz = 0;
+ }
+
+ return SMB_VFS_NEXT_CONNECT(handle, service, user);
+}
+
+static ssize_t cprime_sendfile(
+ struct vfs_handle_struct * handle,
+ int tofd,
+ files_struct * fromfsp,
+ const DATA_BLOB * header,
+ SMB_OFF_T offset,
+ size_t count)
+{
+ if (g_readbuf && offset == 0) {
+ prime_cache(handle, fromfsp, offset, count);
+ }
+
+ return SMB_VFS_NEXT_SENDFILE(handle, tofd, fromfsp,
+ header, offset, count);
+}
+
+static ssize_t cprime_read(
+ vfs_handle_struct * handle,
+ files_struct * fsp,
+ void * data,
+ size_t count)
+{
+ SMB_OFF_T offset;
+
+ offset = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
+ if (offset >= 0 && g_readbuf) {
+ prime_cache(handle, fsp, offset, count);
+ SMB_VFS_LSEEK(fsp, offset, SEEK_SET);
+ }
+
+ return SMB_VFS_NEXT_READ(handle, fsp, data, count);
+}
+
+static ssize_t cprime_pread(
+ vfs_handle_struct * handle,
+ files_struct * fsp,
+ void * data,
+ size_t count,
+ SMB_OFF_T offset)
+{
+ if (g_readbuf) {
+ prime_cache(handle, fsp, offset, count);
+ }
+
+ return SMB_VFS_NEXT_PREAD(handle, fsp, data, count, offset);
+}
+
+static vfs_op_tuple cprime_ops [] =
+{
+ {SMB_VFS_OP(cprime_sendfile),
+ SMB_VFS_OP_SENDFILE, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cprime_pread),
+ SMB_VFS_OP_PREAD, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cprime_read),
+ SMB_VFS_OP_READ, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cprime_connect),
+ SMB_VFS_OP_CONNECT, SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+/* -------------------------------------------------------------------------
+ * Samba module initialisation entry point.
+ * -------------------------------------------------------------------------
+ */
+
+NTSTATUS vfs_cacheprime_init(void);
+NTSTATUS vfs_cacheprime_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, MODULE, cprime_ops);
+}
+
+/* vim: set sw=4 ts=4 tw=79 et: */
diff --git a/source3/modules/vfs_cap.c b/source3/modules/vfs_cap.c
new file mode 100644
index 0000000000..79537367d6
--- /dev/null
+++ b/source3/modules/vfs_cap.c
@@ -0,0 +1,624 @@
+/*
+ * CAP VFS module for Samba 3.x Version 0.3
+ *
+ * Copyright (C) Tim Potter, 1999-2000
+ * Copyright (C) Alexander Bokovoy, 2002-2003
+ * Copyright (C) Stefan (metze) Metzmacher, 2003
+ * Copyright (C) TAKAHASHI Motonobu (monyo), 2003
+ * Copyright (C) Jeremy Allison, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "includes.h"
+
+/* cap functions */
+static char *capencode(TALLOC_CTX *ctx, const char *from);
+static char *capdecode(TALLOC_CTX *ctx, const char *from);
+
+static SMB_BIG_UINT cap_disk_free(vfs_handle_struct *handle, const char *path,
+ bool small_query, SMB_BIG_UINT *bsize,
+ SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return (SMB_BIG_UINT)-1;
+ }
+ return SMB_VFS_NEXT_DISK_FREE(handle, cappath, small_query, bsize,
+ dfree, dsize);
+}
+
+static SMB_STRUCT_DIR *cap_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr)
+{
+ char *capname = capencode(talloc_tos(), fname);
+
+ if (!capname) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return SMB_VFS_NEXT_OPENDIR(handle, capname, mask, attr);
+}
+
+static SMB_STRUCT_DIRENT *cap_readdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp)
+{
+ SMB_STRUCT_DIRENT *result;
+ SMB_STRUCT_DIRENT *newdirent;
+ char *newname;
+ size_t newnamelen;
+ DEBUG(3,("cap: cap_readdir\n"));
+
+ result = SMB_VFS_NEXT_READDIR(handle, dirp);
+ if (!result) {
+ return NULL;
+ }
+
+ newname = capdecode(talloc_tos(), result->d_name);
+ if (!newname) {
+ return NULL;
+ }
+ DEBUG(3,("cap: cap_readdir: %s\n", newname));
+ newnamelen = strlen(newname)+1;
+ newdirent = (SMB_STRUCT_DIRENT *)TALLOC_ARRAY(talloc_tos(),
+ char,
+ sizeof(SMB_STRUCT_DIRENT)+
+ newnamelen);
+ if (!newdirent) {
+ return NULL;
+ }
+ memcpy(newdirent, result, sizeof(SMB_STRUCT_DIRENT));
+ memcpy(&newdirent->d_name, newname, newnamelen);
+ return newdirent;
+}
+
+static int cap_mkdir(vfs_handle_struct *handle, const char *path, mode_t mode)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_MKDIR(handle, cappath, mode);
+}
+
+static int cap_rmdir(vfs_handle_struct *handle, const char *path)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_RMDIR(handle, cappath);
+}
+
+static int cap_open(vfs_handle_struct *handle, const char *fname, files_struct *fsp, int flags, mode_t mode)
+{
+ char *cappath = capencode(talloc_tos(), fname);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ DEBUG(3,("cap: cap_open for %s\n", fname));
+ return SMB_VFS_NEXT_OPEN(handle, cappath, fsp, flags, mode);
+}
+
+static int cap_rename(vfs_handle_struct *handle, const char *oldname, const char *newname)
+{
+ char *capold = capencode(talloc_tos(), oldname);
+ char *capnew = capencode(talloc_tos(), newname);
+
+ if (!capold || !capnew) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_RENAME(handle, capold, capnew);
+}
+
+static int cap_stat(vfs_handle_struct *handle, const char *path, SMB_STRUCT_STAT *sbuf)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_STAT(handle, cappath, sbuf);
+}
+
+static int cap_lstat(vfs_handle_struct *handle, const char *path, SMB_STRUCT_STAT *sbuf)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_LSTAT(handle, cappath, sbuf);
+}
+
+static int cap_unlink(vfs_handle_struct *handle, const char *path)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_UNLINK(handle, cappath);
+}
+
+static int cap_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_CHMOD(handle, cappath, mode);
+}
+
+static int cap_chown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_CHOWN(handle, cappath, uid, gid);
+}
+
+static int cap_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_LCHOWN(handle, cappath, uid, gid);
+}
+
+static int cap_chdir(vfs_handle_struct *handle, const char *path)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ DEBUG(3,("cap: cap_chdir for %s\n", path));
+ return SMB_VFS_NEXT_CHDIR(handle, cappath);
+}
+
+static int cap_ntimes(vfs_handle_struct *handle, const char *path, const struct timespec ts[2])
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_NTIMES(handle, cappath, ts);
+}
+
+
+static bool cap_symlink(vfs_handle_struct *handle, const char *oldpath, const char *newpath)
+{
+ char *capold = capencode(talloc_tos(), oldpath);
+ char *capnew = capencode(talloc_tos(), newpath);
+
+ if (!capold || !capnew) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_SYMLINK(handle, capold, capnew);
+}
+
+static bool cap_readlink(vfs_handle_struct *handle, const char *path, char *buf, size_t bufsiz)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_READLINK(handle, cappath, buf, bufsiz);
+}
+
+static int cap_link(vfs_handle_struct *handle, const char *oldpath, const char *newpath)
+{
+ char *capold = capencode(talloc_tos(), oldpath);
+ char *capnew = capencode(talloc_tos(), newpath);
+
+ if (!capold || !capnew) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_LINK(handle, capold, capnew);
+}
+
+static int cap_mknod(vfs_handle_struct *handle, const char *path, mode_t mode, SMB_DEV_T dev)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_MKNOD(handle, cappath, mode, dev);
+}
+
+static char *cap_realpath(vfs_handle_struct *handle, const char *path, char *resolved_path)
+{
+ /* monyo need capencode'ed and capdecode'ed? */
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return SMB_VFS_NEXT_REALPATH(handle, path, resolved_path);
+}
+
+static int cap_chmod_acl(vfs_handle_struct *handle, const char *path, mode_t mode)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ /* If the underlying VFS doesn't have ACL support... */
+ if (!handle->vfs_next.ops.chmod_acl) {
+ errno = ENOSYS;
+ return -1;
+ }
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_CHMOD_ACL(handle, cappath, mode);
+}
+
+static SMB_ACL_T cap_sys_acl_get_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T type)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return (SMB_ACL_T)NULL;
+ }
+ return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, cappath, type);
+}
+
+static int cap_sys_acl_set_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, cappath, acltype, theacl);
+}
+
+static int cap_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, cappath);
+}
+
+static ssize_t cap_getxattr(vfs_handle_struct *handle, const char *path, const char *name, void *value, size_t size)
+{
+ char *cappath = capencode(talloc_tos(), path);
+ char *capname = capencode(talloc_tos(), name);
+
+ if (!cappath || !capname) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_GETXATTR(handle, cappath, capname, value, size);
+}
+
+static ssize_t cap_lgetxattr(vfs_handle_struct *handle, const char *path, const char *name, void *value, size_t
+size)
+{
+ char *cappath = capencode(talloc_tos(), path);
+ char *capname = capencode(talloc_tos(), name);
+
+ if (!cappath || !capname) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_LGETXATTR(handle, cappath, capname, value, size);
+}
+
+static ssize_t cap_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, void *value, size_t size)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_FGETXATTR(handle, fsp, cappath, value, size);
+}
+
+static ssize_t cap_listxattr(vfs_handle_struct *handle, const char *path, char *list, size_t size)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_LISTXATTR(handle, cappath, list, size);
+}
+
+static ssize_t cap_llistxattr(vfs_handle_struct *handle, const char *path, char *list, size_t size)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_LLISTXATTR(handle, cappath, list, size);
+}
+
+static int cap_removexattr(vfs_handle_struct *handle, const char *path, const char *name)
+{
+ char *cappath = capencode(talloc_tos(), path);
+ char *capname = capencode(talloc_tos(), name);
+
+ if (!cappath || !capname) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_REMOVEXATTR(handle, cappath, capname);
+}
+
+static int cap_lremovexattr(vfs_handle_struct *handle, const char *path, const char *name)
+{
+ char *cappath = capencode(talloc_tos(), path);
+ char *capname = capencode(talloc_tos(), name);
+
+ if (!cappath || !capname) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_LREMOVEXATTR(handle, cappath, capname);
+}
+
+static int cap_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, cappath);
+}
+
+static int cap_setxattr(vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
+{
+ char *cappath = capencode(talloc_tos(), path);
+ char *capname = capencode(talloc_tos(), name);
+
+ if (!cappath || !capname) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_SETXATTR(handle, cappath, capname, value, size, flags);
+}
+
+static int cap_lsetxattr(vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
+{
+ char *cappath = capencode(talloc_tos(), path);
+ char *capname = capencode(talloc_tos(), name);
+
+ if (!cappath || !capname) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_LSETXATTR(handle, cappath, capname, value, size, flags);
+}
+
+static int cap_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, const void *value, size_t size, int flags)
+{
+ char *cappath = capencode(talloc_tos(), path);
+
+ if (!cappath) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_FSETXATTR(handle, fsp, cappath, value, size, flags);
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple cap_op_tuples[] = {
+
+ /* Disk operations */
+
+ {SMB_VFS_OP(cap_disk_free), SMB_VFS_OP_DISK_FREE, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* Directory operations */
+
+ {SMB_VFS_OP(cap_opendir), SMB_VFS_OP_OPENDIR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_readdir), SMB_VFS_OP_READDIR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_mkdir), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_rmdir), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* File operations */
+
+ {SMB_VFS_OP(cap_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_rename), SMB_VFS_OP_RENAME, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_stat), SMB_VFS_OP_STAT, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_lstat), SMB_VFS_OP_LSTAT, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_unlink), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_chmod), SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_chown), SMB_VFS_OP_CHOWN, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_lchown), SMB_VFS_OP_LCHOWN, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_chdir), SMB_VFS_OP_CHDIR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_ntimes), SMB_VFS_OP_NTIMES, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_symlink), SMB_VFS_OP_SYMLINK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_readlink), SMB_VFS_OP_READLINK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_link), SMB_VFS_OP_LINK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_mknod), SMB_VFS_OP_MKNOD, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_realpath), SMB_VFS_OP_REALPATH, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* POSIX ACL operations */
+
+ {SMB_VFS_OP(cap_chmod_acl), SMB_VFS_OP_CHMOD_ACL, SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(cap_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_sys_acl_set_file), SMB_VFS_OP_SYS_ACL_SET_FILE, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_sys_acl_delete_def_file), SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* EA operations. */
+ {SMB_VFS_OP(cap_getxattr), SMB_VFS_OP_GETXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_lgetxattr), SMB_VFS_OP_LGETXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_fgetxattr), SMB_VFS_OP_FGETXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_listxattr), SMB_VFS_OP_LISTXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_llistxattr), SMB_VFS_OP_LLISTXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_removexattr), SMB_VFS_OP_REMOVEXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_lremovexattr), SMB_VFS_OP_LREMOVEXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_fremovexattr), SMB_VFS_OP_FREMOVEXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_setxattr), SMB_VFS_OP_SETXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_lsetxattr), SMB_VFS_OP_LSETXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(cap_fsetxattr), SMB_VFS_OP_FSETXATTR, SMB_VFS_LAYER_TRANSPARENT},
+
+ {NULL, SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_cap_init(void);
+NTSTATUS vfs_cap_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "cap", cap_op_tuples);
+}
+
+/* For CAP functions */
+#define hex_tag ':'
+#define hex2bin(c) hex2bin_table[(unsigned char)(c)]
+#define bin2hex(c) bin2hex_table[(unsigned char)(c)]
+#define is_hex(s) ((s)[0] == hex_tag)
+
+static unsigned char hex2bin_table[256] = {
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
+0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
+0000, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0000, /* 0x40 */
+0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
+0000, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0000, /* 0x60 */
+0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 */
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 */
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 */
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 */
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 */
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 */
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 */
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0 */
+};
+static unsigned char bin2hex_table[256] = "0123456789abcdef";
+
+/*******************************************************************
+ original code -> ":xx" - CAP format
+********************************************************************/
+
+static char *capencode(TALLOC_CTX *ctx, const char *from)
+{
+ char *out = NULL;
+ const char *p1;
+ char *to = NULL;
+ size_t len = 0;
+
+ for (p1 = from; *p1; p1++) {
+ if ((unsigned char)*p1 >= 0x80) {
+ len += 3;
+ } else {
+ len++;
+ }
+ }
+ len++;
+
+ to = TALLOC_ARRAY(ctx, char, len);
+ if (!to) {
+ return NULL;
+ }
+
+ for (out = to; *from;) {
+ /* buffer husoku error */
+ if ((unsigned char)*from >= 0x80) {
+ *out++ = hex_tag;
+ *out++ = bin2hex (((*from)>>4)&0x0f);
+ *out++ = bin2hex ((*from)&0x0f);
+ from++;
+ } else {
+ *out++ = *from++;
+ }
+ }
+ *out = '\0';
+ return to;
+}
+
+/*******************************************************************
+ CAP -> original code
+********************************************************************/
+/* ":xx" -> a byte */
+
+static char *capdecode(TALLOC_CTX *ctx, const char *from)
+{
+ const char *p1;
+ char *out = NULL;
+ char *to = NULL;
+ size_t len = 0;
+
+ for (p1 = from; *p1; len++) {
+ if (is_hex(from)) {
+ p1 += 3;
+ } else {
+ p1++;
+ }
+ }
+
+ to = TALLOC_ARRAY(ctx, char, len);
+ if (!to) {
+ return NULL;
+ }
+
+ for (out = to; *from;) {
+ if (is_hex(from)) {
+ *out++ = (hex2bin(from[1])<<4) | (hex2bin(from[2]));
+ from += 3;
+ } else {
+ *out++ = *from++;
+ }
+ }
+ *out = '\0';
+ return to;
+}
diff --git a/source3/modules/vfs_catia.c b/source3/modules/vfs_catia.c
new file mode 100644
index 0000000000..47d178a33f
--- /dev/null
+++ b/source3/modules/vfs_catia.c
@@ -0,0 +1,374 @@
+/*
+ * Catia VFS module
+ *
+ * Implement a fixed mapping of forbidden NT characters in filenames that are
+ * used a lot by the CAD package Catia.
+ *
+ * Yes, this a BAD BAD UGLY INCOMPLETE hack, but it helps quite some people
+ * out there. Catia V4 on AIX uses characters like "<*$ a *lot*, all forbidden
+ * under Windows...
+ *
+ * Copyright (C) Volker Lendecke, 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "includes.h"
+
+static char *catia_string_replace(TALLOC_CTX *ctx,
+ const char *s,
+ unsigned char oldc,
+ unsigned char newc)
+{
+ smb_ucs2_t *tmpbuf = NULL;
+ smb_ucs2_t *ptr = NULL;
+ smb_ucs2_t old = oldc;
+ char *ret = NULL;
+ size_t converted_size;
+
+ if (!s) {
+ return NULL;
+ }
+
+ if (!push_ucs2_talloc(ctx, &tmpbuf, s, &converted_size)) {
+ return NULL;
+ }
+
+ ptr = tmpbuf;
+
+ for (;*ptr;ptr++) {
+ if (*ptr==old) {
+ *ptr=newc;
+ }
+ }
+
+ if (!pull_ucs2_talloc(ctx, &ret, tmpbuf, &converted_size)) {
+ TALLOC_FREE(tmpbuf);
+ return NULL;
+ }
+ TALLOC_FREE(tmpbuf);
+ return ret;
+}
+
+static char *from_unix(TALLOC_CTX *ctx, const char *s)
+{
+ char *ret = catia_string_replace(ctx, s, '\x22', '\xa8');
+ ret = catia_string_replace(ctx, ret, '\x2a', '\xa4');
+ ret = catia_string_replace(ctx, ret, '\x2f', '\xf8');
+ ret = catia_string_replace(ctx, ret, '\x3a', '\xf7');
+ ret = catia_string_replace(ctx, ret, '\x3c', '\xab');
+ ret = catia_string_replace(ctx, ret, '\x3e', '\xbb');
+ ret = catia_string_replace(ctx, ret, '\x3f', '\xbf');
+ ret = catia_string_replace(ctx, ret, '\x5c', '\xff');
+ ret = catia_string_replace(ctx, ret, '\x7c', '\xa6');
+ return catia_string_replace(ctx, ret, ' ', '\xb1');
+}
+
+static char *to_unix(TALLOC_CTX *ctx, const char *s)
+{
+ char *ret = catia_string_replace(ctx, s, '\xa8', '\x22');
+ ret = catia_string_replace(ctx, ret, '\xa4', '\x2a');
+ ret = catia_string_replace(ctx, ret, '\xf8', '\x2f');
+ ret = catia_string_replace(ctx, ret, '\xf7', '\x3a');
+ ret = catia_string_replace(ctx, ret, '\xab', '\x3c');
+ ret = catia_string_replace(ctx, ret, '\xbb', '\x3e');
+ ret = catia_string_replace(ctx, ret, '\xbf', '\x3f');
+ ret = catia_string_replace(ctx, ret, '\xff', '\x5c');
+ ret = catia_string_replace(ctx, ret, '\xa6', '\x7c');
+ return catia_string_replace(ctx, ret, '\xb1', ' ');
+}
+
+static SMB_STRUCT_DIR *catia_opendir(vfs_handle_struct *handle,
+ const char *fname, const char *mask, uint32 attr)
+{
+ char *name = to_unix(talloc_tos(), fname);
+
+ if (!name) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return SMB_VFS_NEXT_OPENDIR(handle, name, mask, attr);
+}
+
+static SMB_STRUCT_DIRENT *catia_readdir(vfs_handle_struct *handle,
+ SMB_STRUCT_DIR *dirp)
+{
+ SMB_STRUCT_DIRENT *result = SMB_VFS_NEXT_READDIR(handle, dirp);
+ SMB_STRUCT_DIRENT *newdirent;
+ char *newname;
+ size_t newnamelen;
+
+ if (result == NULL) {
+ return result;
+ }
+
+ newname = from_unix(talloc_tos(), result->d_name);
+ if (!newname) {
+ return NULL;
+ }
+ newnamelen = strlen(newname)+1;
+ newdirent = (SMB_STRUCT_DIRENT *)TALLOC_ARRAY(talloc_tos(),
+ char,
+ sizeof(SMB_STRUCT_DIRENT)+
+ newnamelen);
+ if (!newdirent) {
+ return NULL;
+ }
+ memcpy(newdirent, result, sizeof(SMB_STRUCT_DIRENT));
+ memcpy(&newdirent->d_name, newname, newnamelen);
+ return newdirent;
+}
+
+static int catia_open(vfs_handle_struct *handle,
+ const char *fname,
+ files_struct *fsp,
+ int flags,
+ mode_t mode)
+{
+ char *name = to_unix(talloc_tos(), fname);
+
+ if (!name) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_OPEN(handle, name, fsp, flags, mode);
+}
+
+static int catia_rename(vfs_handle_struct *handle,
+ const char *oldname, const char *newname)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *oname = to_unix(ctx, oldname);
+ char *nname = to_unix(ctx, newname);
+
+ if (!oname || !nname) {
+ errno = ENOMEM;
+ return -1;
+ }
+ DEBUG(10, ("converted old name: %s\n", oname));
+ DEBUG(10, ("converted new name: %s\n", nname));
+
+ return SMB_VFS_NEXT_RENAME(handle, oname, nname);
+}
+
+static int catia_stat(vfs_handle_struct *handle,
+ const char *fname, SMB_STRUCT_STAT *sbuf)
+{
+ char *name = to_unix(talloc_tos(), fname);
+
+ if (!name) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_STAT(handle, name, sbuf);
+}
+
+static int catia_lstat(vfs_handle_struct *handle,
+ const char *path, SMB_STRUCT_STAT *sbuf)
+{
+ char *name = to_unix(talloc_tos(), path);
+
+ if (!name) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_LSTAT(handle, name, sbuf);
+}
+
+static int catia_unlink(vfs_handle_struct *handle, const char *path)
+{
+ char *name = to_unix(talloc_tos(), path);
+
+ if (!name) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_UNLINK(handle, name);
+}
+
+static int catia_chmod(vfs_handle_struct *handle,
+ const char *path, mode_t mode)
+{
+ char *name = to_unix(talloc_tos(), path);
+
+ if (!name) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_CHMOD(handle, name, mode);
+}
+
+static int catia_chown(vfs_handle_struct *handle,
+ const char *path, uid_t uid, gid_t gid)
+{
+ char *name = to_unix(talloc_tos(), path);
+
+ if (!name) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_CHOWN(handle, name, uid, gid);
+}
+
+static int catia_lchown(vfs_handle_struct *handle,
+ const char *path, uid_t uid, gid_t gid)
+{
+ char *name = to_unix(talloc_tos(), path);
+
+ if (!name) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_LCHOWN(handle, name, uid, gid);
+}
+
+static int catia_chdir(vfs_handle_struct *handle,
+ const char *path)
+{
+ char *name = to_unix(talloc_tos(), path);
+
+ if (!name) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return SMB_VFS_NEXT_CHDIR(handle, name);
+}
+
+static char *catia_getwd(vfs_handle_struct *handle, char *buf)
+{
+ return SMB_VFS_NEXT_GETWD(handle, buf);
+}
+
+static int catia_ntimes(vfs_handle_struct *handle,
+ const char *path, const struct timespec ts[2])
+{
+ return SMB_VFS_NEXT_NTIMES(handle, path, ts);
+}
+
+static bool catia_symlink(vfs_handle_struct *handle,
+ const char *oldpath, const char *newpath)
+{
+ return SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath);
+}
+
+static bool catia_readlink(vfs_handle_struct *handle,
+ const char *path, char *buf, size_t bufsiz)
+{
+ return SMB_VFS_NEXT_READLINK(handle, path, buf, bufsiz);
+}
+
+static int catia_link(vfs_handle_struct *handle,
+ const char *oldpath, const char *newpath)
+{
+ return SMB_VFS_NEXT_LINK(handle, oldpath, newpath);
+}
+
+static int catia_mknod(vfs_handle_struct *handle,
+ const char *path, mode_t mode, SMB_DEV_T dev)
+{
+ return SMB_VFS_NEXT_MKNOD(handle, path, mode, dev);
+}
+
+static char *catia_realpath(vfs_handle_struct *handle,
+ const char *path, char *resolved_path)
+{
+ return SMB_VFS_NEXT_REALPATH(handle, path, resolved_path);
+}
+
+static NTSTATUS catia_get_nt_acl(vfs_handle_struct *handle,
+ const char *name, uint32 security_info,
+ struct security_descriptor **ppdesc)
+{
+ return SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info, ppdesc);
+}
+
+static int catia_chmod_acl(vfs_handle_struct *handle,
+ const char *name, mode_t mode)
+{
+ /* If the underlying VFS doesn't have ACL support... */
+ if (!handle->vfs_next.ops.chmod_acl) {
+ errno = ENOSYS;
+ return -1;
+ }
+ return SMB_VFS_NEXT_CHMOD_ACL(handle, name, mode);
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple catia_op_tuples[] = {
+
+ /* Directory operations */
+
+ {SMB_VFS_OP(catia_opendir), SMB_VFS_OP_OPENDIR,
+SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(catia_readdir), SMB_VFS_OP_READDIR,
+SMB_VFS_LAYER_TRANSPARENT},
+
+ /* File operations */
+
+ {SMB_VFS_OP(catia_open), SMB_VFS_OP_OPEN,
+SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(catia_rename), SMB_VFS_OP_RENAME,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(catia_stat), SMB_VFS_OP_STAT,
+SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(catia_lstat), SMB_VFS_OP_LSTAT,
+SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(catia_unlink), SMB_VFS_OP_UNLINK,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(catia_chmod), SMB_VFS_OP_CHMOD,
+SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(catia_chown), SMB_VFS_OP_CHOWN,
+SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(catia_lchown), SMB_VFS_OP_LCHOWN,
+SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(catia_chdir), SMB_VFS_OP_CHDIR,
+SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(catia_getwd), SMB_VFS_OP_GETWD,
+SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(catia_ntimes), SMB_VFS_OP_NTIMES,
+SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(catia_symlink), SMB_VFS_OP_SYMLINK,
+SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(catia_readlink), SMB_VFS_OP_READLINK,
+SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(catia_link), SMB_VFS_OP_LINK,
+SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(catia_mknod), SMB_VFS_OP_MKNOD,
+SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(catia_realpath), SMB_VFS_OP_REALPATH,
+SMB_VFS_LAYER_TRANSPARENT},
+
+ /* NT File ACL operations */
+
+ {SMB_VFS_OP(catia_get_nt_acl), SMB_VFS_OP_GET_NT_ACL,
+SMB_VFS_LAYER_TRANSPARENT},
+
+ /* POSIX ACL operations */
+
+ {SMB_VFS_OP(catia_chmod_acl), SMB_VFS_OP_CHMOD_ACL,
+SMB_VFS_LAYER_TRANSPARENT},
+
+
+ {NULL, SMB_VFS_OP_NOOP,
+SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_catia_init(void);
+NTSTATUS vfs_catia_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "catia",
+catia_op_tuples);
+}
diff --git a/source3/modules/vfs_commit.c b/source3/modules/vfs_commit.c
new file mode 100644
index 0000000000..1cef6d0243
--- /dev/null
+++ b/source3/modules/vfs_commit.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) James Peach 2006, 2007
+ * Copyright (c) David Losada Carballo 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/* Commit data module.
+ *
+ * The purpose of this module is to flush data to disk at regular intervals,
+ * just like the NFS commit operation. There's two rationales for this. First,
+ * it minimises the data loss in case of a power outage without incurring
+ * the poor performance of synchronous I/O. Second, a steady flush rate
+ * can produce better throughput than suddenly dumping massive amounts of
+ * writes onto a disk.
+ *
+ * Tunables:
+ *
+ * commit: dthresh Amount of dirty data that can accumulate
+ * before we commit (sync) it.
+ *
+ * commit: debug Debug level at which to emit messages.
+ *
+ * commit: eof mode String. Tunes how the module tries to guess when
+ * the client has written the last bytes of the file.
+ * Possible values (default = hinted):
+ *
+ * (*) = hinted Some clients (i.e. Windows Explorer) declare the
+ * size of the file before transferring it. With this
+ * option, we remember that hint, and commit after
+ * writing in that file position. If the client
+ * doesn't declare the size of file, commiting on EOF
+ * is not triggered.
+ *
+ * = growth Commits after a write operation has made the file
+ * size grow. If the client declares a file size, it
+ * refrains to commit until the file has reached it.
+ * Useful for defeating writeback on NFS shares.
+ *
+ */
+
+#define MODULE "commit"
+
+static int module_debug;
+
+enum eof_mode
+{
+ EOF_NONE = 0x0000,
+ EOF_HINTED = 0x0001,
+ EOF_GROWTH = 0x0002
+};
+
+struct commit_info
+{
+ /* For chunk-based commits */
+ SMB_OFF_T dbytes; /* Dirty (uncommitted) bytes */
+ SMB_OFF_T dthresh; /* Dirty data threshold */
+ /* For commits on EOF */
+ enum eof_mode on_eof;
+ SMB_OFF_T eof; /* Expected file size */
+};
+
+static int commit_do(
+ struct commit_info * c,
+ int fd)
+{
+ int result;
+
+ DEBUG(module_debug,
+ ("%s: flushing %lu dirty bytes\n",
+ MODULE, (unsigned long)c->dbytes));
+
+#if HAVE_FDATASYNC
+ result = fdatasync(fd);
+#elif HAVE_FSYNC
+ result = fsync(fd);
+#else
+ result = 0
+#endif
+ if (result == 0) {
+ c->dbytes = 0; /* on success, no dirty bytes */
+ }
+ return result;
+}
+
+static int commit_all(
+ struct vfs_handle_struct * handle,
+ files_struct * fsp)
+{
+ struct commit_info *c;
+
+ if ((c = VFS_FETCH_FSP_EXTENSION(handle, fsp))) {
+ if (c->dbytes) {
+ DEBUG(module_debug,
+ ("%s: flushing %lu dirty bytes\n",
+ MODULE, (unsigned long)c->dbytes));
+
+ return commit_do(c, fsp->fh->fd);
+ }
+ }
+ return 0;
+}
+
+static int commit(
+ struct vfs_handle_struct * handle,
+ files_struct * fsp,
+ SMB_OFF_T offset,
+ ssize_t last_write)
+{
+ struct commit_info *c;
+
+ if ((c = VFS_FETCH_FSP_EXTENSION(handle, fsp)) == NULL) {
+ return 0;
+ }
+
+ c->dbytes += last_write; /* dirty bytes always counted */
+
+ if (c->dthresh && (c->dbytes > c->dthresh)) {
+ return commit_do(c, fsp->fh->fd);
+ }
+
+ /* Return if we are not in EOF mode or if we have temporarily opted
+ * out of it.
+ */
+ if (c->on_eof == EOF_NONE || c->eof < 0) {
+ return 0;
+ }
+
+ /* This write hit or went past our cache the file size. */
+ if ((offset + last_write) >= c->eof) {
+ if (commit_do(c, fsp->fh->fd) == -1) {
+ return -1;
+ }
+
+ /* Hinted mode only commits the first time we hit EOF. */
+ if (c->on_eof == EOF_HINTED) {
+ c->eof = -1;
+ } else if (c->on_eof == EOF_GROWTH) {
+ c->eof = offset + last_write;
+ }
+ }
+
+ return 0;
+}
+
+static int commit_connect(
+ struct vfs_handle_struct * handle,
+ const char * service,
+ const char * user)
+{
+ module_debug = lp_parm_int(SNUM(handle->conn), MODULE, "debug", 100);
+ return SMB_VFS_NEXT_CONNECT(handle, service, user);
+}
+
+static int commit_open(
+ vfs_handle_struct * handle,
+ const char * fname,
+ files_struct * fsp,
+ int flags,
+ mode_t mode)
+{
+ SMB_OFF_T dthresh;
+ const char *eof_mode;
+ struct commit_info *c = NULL;
+ int fd;
+
+ /* Don't bother with read-only files. */
+ if ((flags & O_ACCMODE) == O_RDONLY) {
+ return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+ }
+
+ /* Read and check module configuration */
+ dthresh = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
+ MODULE, "dthresh", NULL));
+
+ eof_mode = lp_parm_const_string(SNUM(handle->conn),
+ MODULE, "eof mode", "none");
+
+ if (dthresh > 0 || !strequal(eof_mode, "none")) {
+ c = VFS_ADD_FSP_EXTENSION(handle, fsp, struct commit_info);
+ /* Process main tunables */
+ if (c) {
+ c->dthresh = dthresh;
+ c->dbytes = 0;
+ c->on_eof = EOF_NONE;
+ c->eof = 0;
+ }
+ }
+ /* Process eof_mode tunable */
+ if (c) {
+ if (strequal(eof_mode, "hinted")) {
+ c->on_eof = EOF_HINTED;
+ } else if (strequal(eof_mode, "growth")) {
+ c->on_eof = EOF_GROWTH;
+ }
+ }
+
+ fd = SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+ if (fd == -1) {
+ VFS_REMOVE_FSP_EXTENSION(handle, fsp);
+ return fd;
+ }
+
+ /* EOF commit modes require us to know the initial file size. */
+ if (c && (c->on_eof != EOF_NONE)) {
+ SMB_STRUCT_STAT st;
+ if (SMB_VFS_FSTAT(fsp, &st) == -1) {
+ return -1;
+ }
+ c->eof = st.st_size;
+ }
+
+ return 0;
+}
+
+static ssize_t commit_write(
+ vfs_handle_struct * handle,
+ files_struct * fsp,
+ void * data,
+ size_t count)
+{
+ ssize_t ret;
+ ret = SMB_VFS_NEXT_WRITE(handle, fsp, data, count);
+
+ if (ret > 0) {
+ if (commit(handle, fsp, fsp->fh->pos, ret) == -1) {
+ return -1;
+ }
+ }
+
+ return ret;
+}
+
+static ssize_t commit_pwrite(
+ vfs_handle_struct * handle,
+ files_struct * fsp,
+ void * data,
+ size_t count,
+ SMB_OFF_T offset)
+{
+ ssize_t ret;
+
+ ret = SMB_VFS_NEXT_PWRITE(handle, fsp, data, count, offset);
+ if (ret > 0) {
+ if (commit(handle, fsp, offset, ret) == -1) {
+ return -1;
+ }
+ }
+
+ return ret;
+}
+
+static int commit_close(
+ vfs_handle_struct * handle,
+ files_struct * fsp)
+{
+ /* Commit errors not checked, close() will find them again */
+ commit_all(handle, fsp);
+ return SMB_VFS_NEXT_CLOSE(handle, fsp);
+}
+
+static int commit_ftruncate(
+ vfs_handle_struct * handle,
+ files_struct * fsp,
+ SMB_OFF_T len)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len);
+ if (result == 0) {
+ struct commit_info *c;
+ if ((c = VFS_FETCH_FSP_EXTENSION(handle, fsp))) {
+ commit(handle, fsp, len, 0);
+ c->eof = len;
+ }
+ }
+
+ return result;
+}
+
+static vfs_op_tuple commit_ops [] =
+{
+ {SMB_VFS_OP(commit_open),
+ SMB_VFS_OP_OPEN, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(commit_close),
+ SMB_VFS_OP_CLOSE, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(commit_write),
+ SMB_VFS_OP_WRITE, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(commit_pwrite),
+ SMB_VFS_OP_PWRITE, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(commit_connect),
+ SMB_VFS_OP_CONNECT, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(commit_ftruncate),
+ SMB_VFS_OP_FTRUNCATE, SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_commit_init(void);
+NTSTATUS vfs_commit_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, MODULE, commit_ops);
+}
+
+
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
new file mode 100644
index 0000000000..381aa18561
--- /dev/null
+++ b/source3/modules/vfs_default.c
@@ -0,0 +1,1564 @@
+/*
+ Unix SMB/CIFS implementation.
+ Wrap disk only vfs functions to sidestep dodgy compilers.
+ Copyright (C) Tim Potter 1998
+ Copyright (C) Jeremy Allison 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+/* Check for NULL pointer parameters in vfswrap_* functions */
+
+/* We don't want to have NULL function pointers lying around. Someone
+ is sure to try and execute them. These stubs are used to prevent
+ this possibility. */
+
+static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
+{
+ return 0; /* Return >= 0 for success */
+}
+
+static void vfswrap_disconnect(vfs_handle_struct *handle)
+{
+}
+
+/* Disk operations */
+
+static SMB_BIG_UINT vfswrap_disk_free(vfs_handle_struct *handle, const char *path, bool small_query, SMB_BIG_UINT *bsize,
+ SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ SMB_BIG_UINT result;
+
+ result = sys_disk_free(handle->conn, path, small_query, bsize, dfree, dsize);
+ return result;
+}
+
+static int vfswrap_get_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
+{
+#ifdef HAVE_SYS_QUOTAS
+ int result;
+
+ START_PROFILE(syscall_get_quota);
+ result = sys_get_quota(handle->conn->connectpath, qtype, id, qt);
+ END_PROFILE(syscall_get_quota);
+ return result;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+static int vfswrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
+{
+#ifdef HAVE_SYS_QUOTAS
+ int result;
+
+ START_PROFILE(syscall_set_quota);
+ result = sys_set_quota(handle->conn->connectpath, qtype, id, qt);
+ END_PROFILE(syscall_set_quota);
+ return result;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle, struct files_struct *fsp, SHADOW_COPY_DATA *shadow_copy_data, bool labels)
+{
+ errno = ENOSYS;
+ return -1; /* Not implemented. */
+}
+
+static int vfswrap_statvfs(struct vfs_handle_struct *handle, const char *path, vfs_statvfs_struct *statbuf)
+{
+ return sys_statvfs(path, statbuf);
+}
+
+static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle)
+{
+#if defined(DARWINOS)
+ struct vfs_statvfs_struct statbuf;
+ ZERO_STRUCT(statbuf);
+ sys_statvfs(handle->conn->connectpath, &statbuf);
+ return statbuf.FsCapabilities;
+#endif
+ return FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
+}
+
+/* Directory operations */
+
+static SMB_STRUCT_DIR *vfswrap_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr)
+{
+ SMB_STRUCT_DIR *result;
+
+ START_PROFILE(syscall_opendir);
+ result = sys_opendir(fname);
+ END_PROFILE(syscall_opendir);
+ return result;
+}
+
+static SMB_STRUCT_DIRENT *vfswrap_readdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp)
+{
+ SMB_STRUCT_DIRENT *result;
+
+ START_PROFILE(syscall_readdir);
+ result = sys_readdir(dirp);
+ END_PROFILE(syscall_readdir);
+ return result;
+}
+
+static void vfswrap_seekdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp, long offset)
+{
+ START_PROFILE(syscall_seekdir);
+ sys_seekdir(dirp, offset);
+ END_PROFILE(syscall_seekdir);
+}
+
+static long vfswrap_telldir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp)
+{
+ long result;
+ START_PROFILE(syscall_telldir);
+ result = sys_telldir(dirp);
+ END_PROFILE(syscall_telldir);
+ return result;
+}
+
+static void vfswrap_rewinddir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp)
+{
+ START_PROFILE(syscall_rewinddir);
+ sys_rewinddir(dirp);
+ END_PROFILE(syscall_rewinddir);
+}
+
+static int vfswrap_mkdir(vfs_handle_struct *handle, const char *path, mode_t mode)
+{
+ int result;
+ bool has_dacl = False;
+
+ START_PROFILE(syscall_mkdir);
+
+ if (lp_inherit_acls(SNUM(handle->conn)) && (has_dacl = directory_has_default_acl(handle->conn, parent_dirname(path))))
+ mode = 0777;
+
+ result = mkdir(path, mode);
+
+ if (result == 0 && !has_dacl) {
+ /*
+ * We need to do this as the default behavior of POSIX ACLs
+ * is to set the mask to be the requested group permission
+ * bits, not the group permission bits to be the requested
+ * group permission bits. This is not what we want, as it will
+ * mess up any inherited ACL bits that were set. JRA.
+ */
+ int saved_errno = errno; /* We may get ENOSYS */
+ if ((SMB_VFS_CHMOD_ACL(handle->conn, path, mode) == -1) && (errno == ENOSYS))
+ errno = saved_errno;
+ }
+
+ END_PROFILE(syscall_mkdir);
+ return result;
+}
+
+static int vfswrap_rmdir(vfs_handle_struct *handle, const char *path)
+{
+ int result;
+
+ START_PROFILE(syscall_rmdir);
+ result = rmdir(path);
+ END_PROFILE(syscall_rmdir);
+ return result;
+}
+
+static int vfswrap_closedir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp)
+{
+ int result;
+
+ START_PROFILE(syscall_closedir);
+ result = sys_closedir(dirp);
+ END_PROFILE(syscall_closedir);
+ return result;
+}
+
+/* File operations */
+
+static int vfswrap_open(vfs_handle_struct *handle, const char *fname,
+ files_struct *fsp, int flags, mode_t mode)
+{
+ int result;
+
+ START_PROFILE(syscall_open);
+ result = sys_open(fname, flags, mode);
+ END_PROFILE(syscall_open);
+ return result;
+}
+
+static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
+{
+ int result;
+
+ START_PROFILE(syscall_close);
+ result = fd_close_posix(fsp);
+ END_PROFILE(syscall_close);
+ return result;
+}
+
+static ssize_t vfswrap_read(vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n)
+{
+ ssize_t result;
+
+ START_PROFILE_BYTES(syscall_read, n);
+ result = sys_read(fsp->fh->fd, data, n);
+ END_PROFILE(syscall_read);
+ return result;
+}
+
+static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
+ size_t n, SMB_OFF_T offset)
+{
+ ssize_t result;
+
+#if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
+ START_PROFILE_BYTES(syscall_pread, n);
+ result = sys_pread(fsp->fh->fd, data, n, offset);
+ END_PROFILE(syscall_pread);
+
+ if (result == -1 && errno == ESPIPE) {
+ /* Maintain the fiction that pipes can be seeked (sought?) on. */
+ result = SMB_VFS_READ(fsp, data, n);
+ fsp->fh->pos = 0;
+ }
+
+#else /* HAVE_PREAD */
+ SMB_OFF_T curr;
+ int lerrno;
+
+ curr = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
+ if (curr == -1 && errno == ESPIPE) {
+ /* Maintain the fiction that pipes can be seeked (sought?) on. */
+ result = SMB_VFS_READ(fsp, data, n);
+ fsp->fh->pos = 0;
+ return result;
+ }
+
+ if (SMB_VFS_LSEEK(fsp, offset, SEEK_SET) == -1) {
+ return -1;
+ }
+
+ errno = 0;
+ result = SMB_VFS_READ(fsp, data, n);
+ lerrno = errno;
+
+ SMB_VFS_LSEEK(fsp, curr, SEEK_SET);
+ errno = lerrno;
+
+#endif /* HAVE_PREAD */
+
+ return result;
+}
+
+static ssize_t vfswrap_write(vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n)
+{
+ ssize_t result;
+
+ START_PROFILE_BYTES(syscall_write, n);
+ result = sys_write(fsp->fh->fd, data, n);
+ END_PROFILE(syscall_write);
+ return result;
+}
+
+static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
+ size_t n, SMB_OFF_T offset)
+{
+ ssize_t result;
+
+#if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
+ START_PROFILE_BYTES(syscall_pwrite, n);
+ result = sys_pwrite(fsp->fh->fd, data, n, offset);
+ END_PROFILE(syscall_pwrite);
+
+ if (result == -1 && errno == ESPIPE) {
+ /* Maintain the fiction that pipes can be sought on. */
+ result = SMB_VFS_WRITE(fsp, data, n);
+ }
+
+#else /* HAVE_PWRITE */
+ SMB_OFF_T curr;
+ int lerrno;
+
+ curr = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
+ if (curr == -1) {
+ return -1;
+ }
+
+ if (SMB_VFS_LSEEK(fsp, offset, SEEK_SET) == -1) {
+ return -1;
+ }
+
+ result = SMB_VFS_WRITE(fsp, data, n);
+ lerrno = errno;
+
+ SMB_VFS_LSEEK(fsp, curr, SEEK_SET);
+ errno = lerrno;
+
+#endif /* HAVE_PWRITE */
+
+ return result;
+}
+
+static SMB_OFF_T vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T offset, int whence)
+{
+ SMB_OFF_T result = 0;
+
+ START_PROFILE(syscall_lseek);
+
+ /* Cope with 'stat' file opens. */
+ if (fsp->fh->fd != -1)
+ result = sys_lseek(fsp->fh->fd, offset, whence);
+
+ /*
+ * We want to maintain the fiction that we can seek
+ * on a fifo for file system purposes. This allows
+ * people to set up UNIX fifo's that feed data to Windows
+ * applications. JRA.
+ */
+
+ if((result == -1) && (errno == ESPIPE)) {
+ result = 0;
+ errno = 0;
+ }
+
+ END_PROFILE(syscall_lseek);
+ return result;
+}
+
+static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
+ SMB_OFF_T offset, size_t n)
+{
+ ssize_t result;
+
+ START_PROFILE_BYTES(syscall_sendfile, n);
+ result = sys_sendfile(tofd, fromfsp->fh->fd, hdr, offset, n);
+ END_PROFILE(syscall_sendfile);
+ return result;
+}
+
+static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
+ int fromfd,
+ files_struct *tofsp,
+ SMB_OFF_T offset,
+ size_t n)
+{
+ ssize_t result;
+
+ START_PROFILE_BYTES(syscall_recvfile, n);
+ result = sys_recvfile(fromfd, tofsp->fh->fd, offset, n);
+ END_PROFILE(syscall_recvfile);
+ return result;
+}
+
+/*********************************************************
+ For rename across filesystems Patch from Warren Birnbaum
+ <warrenb@hpcvscdp.cv.hp.com>
+**********************************************************/
+
+static int copy_reg(const char *source, const char *dest)
+{
+ SMB_STRUCT_STAT source_stats;
+ int saved_errno;
+ int ifd = -1;
+ int ofd = -1;
+
+ if (sys_lstat (source, &source_stats) == -1)
+ return -1;
+
+ if (!S_ISREG (source_stats.st_mode))
+ return -1;
+
+ if((ifd = sys_open (source, O_RDONLY, 0)) < 0)
+ return -1;
+
+ if (unlink (dest) && errno != ENOENT)
+ return -1;
+
+#ifdef O_NOFOLLOW
+ if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0600)) < 0 )
+#else
+ if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC , 0600)) < 0 )
+#endif
+ goto err;
+
+ if (transfer_file(ifd, ofd, (size_t)-1) == -1)
+ goto err;
+
+ /*
+ * 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.
+ */
+
+#ifdef HAVE_FCHOWN
+ if ((fchown(ofd, source_stats.st_uid, source_stats.st_gid) == -1) && (errno != EPERM))
+#else
+ if ((chown(dest, source_stats.st_uid, source_stats.st_gid) == -1) && (errno != EPERM))
+#endif
+ goto err;
+
+ /*
+ * fchown turns off set[ug]id bits for non-root,
+ * so do the chmod last.
+ */
+
+#if defined(HAVE_FCHMOD)
+ if (fchmod (ofd, source_stats.st_mode & 07777))
+#else
+ if (chmod (dest, source_stats.st_mode & 07777))
+#endif
+ goto err;
+
+ if (close (ifd) == -1)
+ goto err;
+
+ if (close (ofd) == -1)
+ return -1;
+
+ /* 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;
+ utime(dest, &tv);
+ }
+
+ if (unlink (source) == -1)
+ return -1;
+
+ return 0;
+
+ err:
+
+ saved_errno = errno;
+ if (ifd != -1)
+ close(ifd);
+ if (ofd != -1)
+ close(ofd);
+ errno = saved_errno;
+ return -1;
+}
+
+static int vfswrap_rename(vfs_handle_struct *handle, const char *oldname, const char *newname)
+{
+ int result;
+
+ START_PROFILE(syscall_rename);
+ result = rename(oldname, newname);
+ if ((result == -1) && (errno == EXDEV)) {
+ /* Rename across filesystems needed. */
+ result = copy_reg(oldname, newname);
+ }
+
+ END_PROFILE(syscall_rename);
+ return result;
+}
+
+static int vfswrap_fsync(vfs_handle_struct *handle, files_struct *fsp)
+{
+#ifdef HAVE_FSYNC
+ int result;
+
+ START_PROFILE(syscall_fsync);
+ result = fsync(fsp->fh->fd);
+ END_PROFILE(syscall_fsync);
+ return result;
+#else
+ return 0;
+#endif
+}
+
+static int vfswrap_stat(vfs_handle_struct *handle, const char *fname, SMB_STRUCT_STAT *sbuf)
+{
+ int result;
+
+ START_PROFILE(syscall_stat);
+ result = sys_stat(fname, sbuf);
+ END_PROFILE(syscall_stat);
+ return result;
+}
+
+static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
+{
+ int result;
+
+ START_PROFILE(syscall_fstat);
+ result = sys_fstat(fsp->fh->fd, sbuf);
+ END_PROFILE(syscall_fstat);
+ return result;
+}
+
+int vfswrap_lstat(vfs_handle_struct *handle, const char *path, SMB_STRUCT_STAT *sbuf)
+{
+ int result;
+
+ START_PROFILE(syscall_lstat);
+ result = sys_lstat(path, sbuf);
+ END_PROFILE(syscall_lstat);
+ return result;
+}
+
+static int vfswrap_unlink(vfs_handle_struct *handle, const char *path)
+{
+ int result;
+
+ START_PROFILE(syscall_unlink);
+ result = unlink(path);
+ END_PROFILE(syscall_unlink);
+ return result;
+}
+
+static int vfswrap_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
+{
+ int result;
+
+ START_PROFILE(syscall_chmod);
+
+ /*
+ * We need to do this due to the fact that the default POSIX ACL
+ * chmod modifies the ACL *mask* for the group owner, not the
+ * group owner bits directly. JRA.
+ */
+
+
+ {
+ int saved_errno = errno; /* We might get ENOSYS */
+ if ((result = SMB_VFS_CHMOD_ACL(handle->conn, path, mode)) == 0) {
+ END_PROFILE(syscall_chmod);
+ return result;
+ }
+ /* Error - return the old errno. */
+ errno = saved_errno;
+ }
+
+ result = chmod(path, mode);
+ END_PROFILE(syscall_chmod);
+ return result;
+}
+
+static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
+{
+ int result;
+
+ START_PROFILE(syscall_fchmod);
+
+ /*
+ * We need to do this due to the fact that the default POSIX ACL
+ * chmod modifies the ACL *mask* for the group owner, not the
+ * group owner bits directly. JRA.
+ */
+
+ {
+ int saved_errno = errno; /* We might get ENOSYS */
+ if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
+ END_PROFILE(syscall_fchmod);
+ return result;
+ }
+ /* Error - return the old errno. */
+ errno = saved_errno;
+ }
+
+#if defined(HAVE_FCHMOD)
+ result = fchmod(fsp->fh->fd, mode);
+#else
+ result = -1;
+ errno = ENOSYS;
+#endif
+
+ END_PROFILE(syscall_fchmod);
+ return result;
+}
+
+static int vfswrap_chown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
+{
+ int result;
+
+ START_PROFILE(syscall_chown);
+ result = sys_chown(path, uid, gid);
+ END_PROFILE(syscall_chown);
+ return result;
+}
+
+static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
+{
+#ifdef HAVE_FCHOWN
+ int result;
+
+ START_PROFILE(syscall_fchown);
+ result = fchown(fsp->fh->fd, uid, gid);
+ END_PROFILE(syscall_fchown);
+ return result;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+static int vfswrap_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
+{
+ int result;
+
+ START_PROFILE(syscall_lchown);
+ result = sys_lchown(path, uid, gid);
+ END_PROFILE(syscall_lchown);
+ return result;
+}
+
+static int vfswrap_chdir(vfs_handle_struct *handle, const char *path)
+{
+ int result;
+
+ START_PROFILE(syscall_chdir);
+ result = chdir(path);
+ END_PROFILE(syscall_chdir);
+ return result;
+}
+
+static char *vfswrap_getwd(vfs_handle_struct *handle, char *path)
+{
+ char *result;
+
+ START_PROFILE(syscall_getwd);
+ result = sys_getwd(path);
+ END_PROFILE(syscall_getwd);
+ return result;
+}
+
+/*********************************************************************
+ nsec timestamp resolution call. Convert down to whatever the underlying
+ system will support.
+**********************************************************************/
+
+static int vfswrap_ntimes(vfs_handle_struct *handle, const char *path, const struct timespec ts[2])
+{
+ int result;
+
+ START_PROFILE(syscall_ntimes);
+#if defined(HAVE_UTIMES)
+ if (ts != NULL) {
+ struct timeval tv[2];
+ tv[0] = convert_timespec_to_timeval(ts[0]);
+ tv[1] = convert_timespec_to_timeval(ts[1]);
+ result = utimes(path, tv);
+ } else {
+ result = utimes(path, NULL);
+ }
+#elif defined(HAVE_UTIME)
+ if (ts != NULL) {
+ struct utimbuf times;
+ times.actime = convert_timespec_to_time_t(ts[0]);
+ times.modtime = convert_timespec_to_time_t(ts[1]);
+ result = utime(path, times);
+ } else {
+ result = utime(path, NULL);
+ }
+#else
+ errno = ENOSYS;
+ result = -1;
+#endif
+ END_PROFILE(syscall_ntimes);
+ return result;
+}
+
+/*********************************************************************
+ A version of ftruncate that will write the space on disk if strict
+ allocate is set.
+**********************************************************************/
+
+static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T len)
+{
+ SMB_STRUCT_STAT st;
+ SMB_OFF_T currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
+ unsigned char zero_space[4096];
+ SMB_OFF_T space_to_write;
+
+ if (currpos == -1)
+ return -1;
+
+ if (SMB_VFS_FSTAT(fsp, &st) == -1)
+ return -1;
+
+ space_to_write = len - st.st_size;
+
+#ifdef S_ISFIFO
+ if (S_ISFIFO(st.st_mode))
+ return 0;
+#endif
+
+ if (st.st_size == len)
+ return 0;
+
+ /* Shrink - just ftruncate. */
+ if (st.st_size > len)
+ return sys_ftruncate(fsp->fh->fd, len);
+
+ /* Write out the real space on disk. */
+ if (SMB_VFS_LSEEK(fsp, st.st_size, SEEK_SET) != st.st_size)
+ return -1;
+
+ space_to_write = len - st.st_size;
+
+ memset(zero_space, '\0', sizeof(zero_space));
+ while ( space_to_write > 0) {
+ SMB_OFF_T retlen;
+ SMB_OFF_T current_len_to_write = MIN(sizeof(zero_space),space_to_write);
+
+ retlen = SMB_VFS_WRITE(fsp,(char *)zero_space,current_len_to_write);
+ if (retlen <= 0)
+ return -1;
+
+ space_to_write -= retlen;
+ }
+
+ /* Seek to where we were */
+ if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos)
+ return -1;
+
+ return 0;
+}
+
+static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T len)
+{
+ int result = -1;
+ SMB_STRUCT_STAT st;
+ char c = 0;
+ SMB_OFF_T currpos;
+
+ START_PROFILE(syscall_ftruncate);
+
+ if (lp_strict_allocate(SNUM(fsp->conn))) {
+ result = strict_allocate_ftruncate(handle, fsp, len);
+ END_PROFILE(syscall_ftruncate);
+ return result;
+ }
+
+ /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
+ sys_ftruncate if the system supports it. Then I discovered that
+ you can have some filesystems that support ftruncate
+ expansion and some that don't! On Linux fat can't do
+ ftruncate extend but ext2 can. */
+
+ result = sys_ftruncate(fsp->fh->fd, len);
+ if (result == 0)
+ goto done;
+
+ /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
+ extend a file with ftruncate. Provide alternate implementation
+ for this */
+ currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
+ if (currpos == -1) {
+ goto done;
+ }
+
+ /* Do an fstat to see if the file is longer than the requested
+ size in which case the ftruncate above should have
+ succeeded or shorter, in which case seek to len - 1 and
+ write 1 byte of zero */
+ if (SMB_VFS_FSTAT(fsp, &st) == -1) {
+ goto done;
+ }
+
+#ifdef S_ISFIFO
+ if (S_ISFIFO(st.st_mode)) {
+ result = 0;
+ goto done;
+ }
+#endif
+
+ if (st.st_size == len) {
+ result = 0;
+ goto done;
+ }
+
+ if (st.st_size > len) {
+ /* the sys_ftruncate should have worked */
+ goto done;
+ }
+
+ if (SMB_VFS_LSEEK(fsp, len-1, SEEK_SET) != len -1)
+ goto done;
+
+ if (SMB_VFS_WRITE(fsp, &c, 1)!=1)
+ goto done;
+
+ /* Seek to where we were */
+ if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos)
+ goto done;
+ result = 0;
+
+ done:
+
+ END_PROFILE(syscall_ftruncate);
+ return result;
+}
+
+static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
+{
+ bool result;
+
+ START_PROFILE(syscall_fcntl_lock);
+ result = fcntl_lock(fsp->fh->fd, op, offset, count, type);
+ END_PROFILE(syscall_fcntl_lock);
+ return result;
+}
+
+static int vfswrap_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
+ uint32 share_mode)
+{
+ START_PROFILE(syscall_kernel_flock);
+ kernel_flock(fsp->fh->fd, share_mode);
+ END_PROFILE(syscall_kernel_flock);
+ return 0;
+}
+
+static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
+{
+ bool result;
+
+ START_PROFILE(syscall_fcntl_getlock);
+ result = fcntl_getlock(fsp->fh->fd, poffset, pcount, ptype, ppid);
+ END_PROFILE(syscall_fcntl_getlock);
+ return result;
+}
+
+static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
+ int leasetype)
+{
+ int result = -1;
+
+ START_PROFILE(syscall_linux_setlease);
+
+#ifdef HAVE_KERNEL_OPLOCKS_LINUX
+ /* first set the signal handler */
+ if(linux_set_lease_sighandler(fsp->fh->fd) == -1) {
+ return -1;
+ }
+
+ result = linux_setlease(fsp->fh->fd, leasetype);
+#else
+ errno = ENOSYS;
+#endif
+ END_PROFILE(syscall_linux_setlease);
+ return result;
+}
+
+static int vfswrap_symlink(vfs_handle_struct *handle, const char *oldpath, const char *newpath)
+{
+ int result;
+
+ START_PROFILE(syscall_symlink);
+ result = sys_symlink(oldpath, newpath);
+ END_PROFILE(syscall_symlink);
+ return result;
+}
+
+static int vfswrap_readlink(vfs_handle_struct *handle, const char *path, char *buf, size_t bufsiz)
+{
+ int result;
+
+ START_PROFILE(syscall_readlink);
+ result = sys_readlink(path, buf, bufsiz);
+ END_PROFILE(syscall_readlink);
+ return result;
+}
+
+static int vfswrap_link(vfs_handle_struct *handle, const char *oldpath, const char *newpath)
+{
+ int result;
+
+ START_PROFILE(syscall_link);
+ result = sys_link(oldpath, newpath);
+ END_PROFILE(syscall_link);
+ return result;
+}
+
+static int vfswrap_mknod(vfs_handle_struct *handle, const char *pathname, mode_t mode, SMB_DEV_T dev)
+{
+ int result;
+
+ START_PROFILE(syscall_mknod);
+ result = sys_mknod(pathname, mode, dev);
+ END_PROFILE(syscall_mknod);
+ return result;
+}
+
+static char *vfswrap_realpath(vfs_handle_struct *handle, const char *path, char *resolved_path)
+{
+ char *result;
+
+ START_PROFILE(syscall_realpath);
+ result = sys_realpath(path, resolved_path);
+ END_PROFILE(syscall_realpath);
+ return result;
+}
+
+static NTSTATUS vfswrap_notify_watch(vfs_handle_struct *vfs_handle,
+ struct sys_notify_context *ctx,
+ struct notify_entry *e,
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev),
+ void *private_data, void *handle)
+{
+ /*
+ * So far inotify is the only supported default notify mechanism. If
+ * another platform like the the BSD's or a proprietary Unix comes
+ * along and wants another default, we can play the same trick we
+ * played with Posix ACLs.
+ *
+ * Until that is the case, hard-code inotify here.
+ */
+#ifdef HAVE_INOTIFY
+ if (lp_kernel_change_notify(ctx->conn->params)) {
+ return inotify_watch(ctx, e, callback, private_data, handle);
+ }
+#endif
+ /*
+ * Do nothing, leave everything to notify_internal.c
+ */
+ return NT_STATUS_OK;
+}
+
+static int vfswrap_chflags(vfs_handle_struct *handle, const char *path, int flags)
+{
+#ifdef HAVE_CHFLAGS
+ return chflags(path, flags);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle, SMB_DEV_T dev, SMB_INO_T inode)
+{
+ return file_id_create_dev(dev, inode);
+}
+
+static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *fname,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *pnum_streams,
+ struct stream_struct **pstreams)
+{
+ SMB_STRUCT_STAT sbuf;
+ unsigned int num_streams = 0;
+ struct stream_struct *streams = NULL;
+ int ret;
+
+ if ((fsp != NULL) && (fsp->is_directory)) {
+ /*
+ * No default streams on directories
+ */
+ goto done;
+ }
+
+ if ((fsp != NULL) && (fsp->fh->fd != -1)) {
+ ret = SMB_VFS_FSTAT(fsp, &sbuf);
+ }
+ else {
+ ret = SMB_VFS_STAT(handle->conn, fname, &sbuf);
+ }
+
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ if (S_ISDIR(sbuf.st_mode)) {
+ goto done;
+ }
+
+ streams = talloc(mem_ctx, struct stream_struct);
+
+ if (streams == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ streams->size = sbuf.st_size;
+ streams->alloc_size = get_allocation_size(handle->conn, fsp, &sbuf);
+
+ streams->name = talloc_strdup(streams, "::$DATA");
+ if (streams->name == NULL) {
+ TALLOC_FREE(streams);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ num_streams = 1;
+ done:
+ *pnum_streams = num_streams;
+ *pstreams = streams;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
+ files_struct *fsp,
+ uint32 security_info, SEC_DESC **ppdesc)
+{
+ NTSTATUS result;
+
+ START_PROFILE(fget_nt_acl);
+ result = posix_fget_nt_acl(fsp, security_info, ppdesc);
+ END_PROFILE(fget_nt_acl);
+ return result;
+}
+
+static NTSTATUS vfswrap_get_nt_acl(vfs_handle_struct *handle,
+ const char *name,
+ uint32 security_info, SEC_DESC **ppdesc)
+{
+ NTSTATUS result;
+
+ START_PROFILE(get_nt_acl);
+ result = posix_get_nt_acl(handle->conn, name, security_info, ppdesc);
+ END_PROFILE(get_nt_acl);
+ return result;
+}
+
+static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
+{
+ NTSTATUS result;
+
+ START_PROFILE(fset_nt_acl);
+ result = set_nt_acl(fsp, security_info_sent, psd);
+ END_PROFILE(fset_nt_acl);
+ return result;
+}
+
+static int vfswrap_chmod_acl(vfs_handle_struct *handle, const char *name, mode_t mode)
+{
+#ifdef HAVE_NO_ACL
+ errno = ENOSYS;
+ return -1;
+#else
+ int result;
+
+ START_PROFILE(chmod_acl);
+ result = chmod_acl(handle->conn, name, mode);
+ END_PROFILE(chmod_acl);
+ return result;
+#endif
+}
+
+static int vfswrap_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
+{
+#ifdef HAVE_NO_ACL
+ errno = ENOSYS;
+ return -1;
+#else
+ int result;
+
+ START_PROFILE(fchmod_acl);
+ result = fchmod_acl(fsp, mode);
+ END_PROFILE(fchmod_acl);
+ return result;
+#endif
+}
+
+static int vfswrap_sys_acl_get_entry(vfs_handle_struct *handle, SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+{
+ return sys_acl_get_entry(theacl, entry_id, entry_p);
+}
+
+static int vfswrap_sys_acl_get_tag_type(vfs_handle_struct *handle, SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
+{
+ return sys_acl_get_tag_type(entry_d, tag_type_p);
+}
+
+static int vfswrap_sys_acl_get_permset(vfs_handle_struct *handle, SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
+{
+ return sys_acl_get_permset(entry_d, permset_p);
+}
+
+static void * vfswrap_sys_acl_get_qualifier(vfs_handle_struct *handle, SMB_ACL_ENTRY_T entry_d)
+{
+ return sys_acl_get_qualifier(entry_d);
+}
+
+static SMB_ACL_T vfswrap_sys_acl_get_file(vfs_handle_struct *handle, const char *path_p, SMB_ACL_TYPE_T type)
+{
+ return sys_acl_get_file(handle, path_p, type);
+}
+
+static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp)
+{
+ return sys_acl_get_fd(handle, fsp);
+}
+
+static int vfswrap_sys_acl_clear_perms(vfs_handle_struct *handle, SMB_ACL_PERMSET_T permset)
+{
+ return sys_acl_clear_perms(permset);
+}
+
+static int vfswrap_sys_acl_add_perm(vfs_handle_struct *handle, SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+ return sys_acl_add_perm(permset, perm);
+}
+
+static char * vfswrap_sys_acl_to_text(vfs_handle_struct *handle, SMB_ACL_T theacl, ssize_t *plen)
+{
+ return sys_acl_to_text(theacl, plen);
+}
+
+static SMB_ACL_T vfswrap_sys_acl_init(vfs_handle_struct *handle, int count)
+{
+ return sys_acl_init(count);
+}
+
+static int vfswrap_sys_acl_create_entry(vfs_handle_struct *handle, SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
+{
+ return sys_acl_create_entry(pacl, pentry);
+}
+
+static int vfswrap_sys_acl_set_tag_type(vfs_handle_struct *handle, SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
+{
+ return sys_acl_set_tag_type(entry, tagtype);
+}
+
+static int vfswrap_sys_acl_set_qualifier(vfs_handle_struct *handle, SMB_ACL_ENTRY_T entry, void *qual)
+{
+ return sys_acl_set_qualifier(entry, qual);
+}
+
+static int vfswrap_sys_acl_set_permset(vfs_handle_struct *handle, SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
+{
+ return sys_acl_set_permset(entry, permset);
+}
+
+static int vfswrap_sys_acl_valid(vfs_handle_struct *handle, SMB_ACL_T theacl )
+{
+ return sys_acl_valid(theacl );
+}
+
+static int vfswrap_sys_acl_set_file(vfs_handle_struct *handle, const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
+{
+ return sys_acl_set_file(handle, name, acltype, theacl);
+}
+
+static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, SMB_ACL_T theacl)
+{
+ return sys_acl_set_fd(handle, fsp, theacl);
+}
+
+static int vfswrap_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
+{
+ return sys_acl_delete_def_file(handle, path);
+}
+
+static int vfswrap_sys_acl_get_perm(vfs_handle_struct *handle, SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+ return sys_acl_get_perm(permset, perm);
+}
+
+static int vfswrap_sys_acl_free_text(vfs_handle_struct *handle, char *text)
+{
+ return sys_acl_free_text(text);
+}
+
+static int vfswrap_sys_acl_free_acl(vfs_handle_struct *handle, SMB_ACL_T posix_acl)
+{
+ return sys_acl_free_acl(posix_acl);
+}
+
+static int vfswrap_sys_acl_free_qualifier(vfs_handle_struct *handle, void *qualifier, SMB_ACL_TAG_T tagtype)
+{
+ return sys_acl_free_qualifier(qualifier, tagtype);
+}
+
+/****************************************************************
+ Extended attribute operations.
+*****************************************************************/
+
+static ssize_t vfswrap_getxattr(struct vfs_handle_struct *handle,const char *path, const char *name, void *value, size_t size)
+{
+ return sys_getxattr(path, name, value, size);
+}
+
+static ssize_t vfswrap_lgetxattr(struct vfs_handle_struct *handle,const char *path, const char *name, void *value, size_t size)
+{
+ return sys_lgetxattr(path, name, value, size);
+}
+
+static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
+{
+ return sys_fgetxattr(fsp->fh->fd, name, value, size);
+}
+
+static ssize_t vfswrap_listxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
+{
+ return sys_listxattr(path, list, size);
+}
+
+ssize_t vfswrap_llistxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
+{
+ return sys_llistxattr(path, list, size);
+}
+
+ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
+{
+ return sys_flistxattr(fsp->fh->fd, list, size);
+}
+
+static int vfswrap_removexattr(struct vfs_handle_struct *handle, const char *path, const char *name)
+{
+ return sys_removexattr(path, name);
+}
+
+static int vfswrap_lremovexattr(struct vfs_handle_struct *handle, const char *path, const char *name)
+{
+ return sys_lremovexattr(path, name);
+}
+
+static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
+{
+ return sys_fremovexattr(fsp->fh->fd, name);
+}
+
+static int vfswrap_setxattr(struct vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
+{
+ return sys_setxattr(path, name, value, size, flags);
+}
+
+static int vfswrap_lsetxattr(struct vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
+{
+ return sys_lsetxattr(path, name, value, size, flags);
+}
+
+static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
+{
+ return sys_fsetxattr(fsp->fh->fd, name, value, size, flags);
+}
+
+static int vfswrap_aio_read(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
+{
+ return sys_aio_read(aiocb);
+}
+
+static int vfswrap_aio_write(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
+{
+ return sys_aio_write(aiocb);
+}
+
+static ssize_t vfswrap_aio_return(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
+{
+ return sys_aio_return(aiocb);
+}
+
+static int vfswrap_aio_cancel(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
+{
+ return sys_aio_cancel(fsp->fh->fd, aiocb);
+}
+
+static int vfswrap_aio_error(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
+{
+ return sys_aio_error(aiocb);
+}
+
+static int vfswrap_aio_fsync(struct vfs_handle_struct *handle, struct files_struct *fsp, int op, SMB_STRUCT_AIOCB *aiocb)
+{
+ return sys_aio_fsync(op, aiocb);
+}
+
+static int vfswrap_aio_suspend(struct vfs_handle_struct *handle, struct files_struct *fsp, const SMB_STRUCT_AIOCB * const aiocb[], int n, const struct timespec *timeout)
+{
+ return sys_aio_suspend(aiocb, n, timeout);
+}
+
+static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
+{
+ return false;
+}
+
+static bool vfswrap_is_offline(struct vfs_handle_struct *handle, const char *path, SMB_STRUCT_STAT *sbuf)
+{
+ if (ISDOT(path) || ISDOTDOT(path)) {
+ return false;
+ }
+
+ if (!lp_dmapi_support(SNUM(handle->conn)) || !dmapi_have_session()) {
+#if defined(ENOTSUP)
+ errno = ENOTSUP;
+#endif
+ return false;
+ }
+
+ return (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
+}
+
+static int vfswrap_set_offline(struct vfs_handle_struct *handle, const char *path)
+{
+ /* We don't know how to set offline bit by default, needs to be overriden in the vfs modules */
+#if defined(ENOTSUP)
+ errno = ENOTSUP;
+#endif
+ return -1;
+}
+
+static vfs_op_tuple vfs_default_ops[] = {
+
+ /* Disk operations */
+
+ {SMB_VFS_OP(vfswrap_connect), SMB_VFS_OP_CONNECT,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_disconnect), SMB_VFS_OP_DISCONNECT,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_disk_free), SMB_VFS_OP_DISK_FREE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_get_quota), SMB_VFS_OP_GET_QUOTA,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_set_quota), SMB_VFS_OP_SET_QUOTA,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_get_shadow_copy_data), SMB_VFS_OP_GET_SHADOW_COPY_DATA,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_statvfs), SMB_VFS_OP_STATVFS,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES,
+ SMB_VFS_LAYER_OPAQUE},
+
+ /* Directory operations */
+
+ {SMB_VFS_OP(vfswrap_opendir), SMB_VFS_OP_OPENDIR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_readdir), SMB_VFS_OP_READDIR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_seekdir), SMB_VFS_OP_SEEKDIR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_telldir), SMB_VFS_OP_TELLDIR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_rewinddir), SMB_VFS_OP_REWINDDIR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_mkdir), SMB_VFS_OP_MKDIR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_rmdir), SMB_VFS_OP_RMDIR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_closedir), SMB_VFS_OP_CLOSEDIR,
+ SMB_VFS_LAYER_OPAQUE},
+
+ /* File operations */
+
+ {SMB_VFS_OP(vfswrap_open), SMB_VFS_OP_OPEN,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_close), SMB_VFS_OP_CLOSE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_read), SMB_VFS_OP_READ,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_pread), SMB_VFS_OP_PREAD,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_write), SMB_VFS_OP_WRITE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_pwrite), SMB_VFS_OP_PWRITE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_lseek), SMB_VFS_OP_LSEEK,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sendfile), SMB_VFS_OP_SENDFILE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_recvfile), SMB_VFS_OP_RECVFILE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_rename), SMB_VFS_OP_RENAME,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_fsync), SMB_VFS_OP_FSYNC,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_stat), SMB_VFS_OP_STAT,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_fstat), SMB_VFS_OP_FSTAT,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_lstat), SMB_VFS_OP_LSTAT,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_unlink), SMB_VFS_OP_UNLINK,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_chmod), SMB_VFS_OP_CHMOD,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_fchmod), SMB_VFS_OP_FCHMOD,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_chown), SMB_VFS_OP_CHOWN,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_fchown), SMB_VFS_OP_FCHOWN,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_lchown), SMB_VFS_OP_LCHOWN,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_chdir), SMB_VFS_OP_CHDIR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_getwd), SMB_VFS_OP_GETWD,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_ntimes), SMB_VFS_OP_NTIMES,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_ftruncate), SMB_VFS_OP_FTRUNCATE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_lock), SMB_VFS_OP_LOCK,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_kernel_flock), SMB_VFS_OP_KERNEL_FLOCK,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_linux_setlease), SMB_VFS_OP_LINUX_SETLEASE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_getlock), SMB_VFS_OP_GETLOCK,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_symlink), SMB_VFS_OP_SYMLINK,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_readlink), SMB_VFS_OP_READLINK,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_link), SMB_VFS_OP_LINK,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_mknod), SMB_VFS_OP_MKNOD,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_realpath), SMB_VFS_OP_REALPATH,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_notify_watch), SMB_VFS_OP_NOTIFY_WATCH,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_chflags), SMB_VFS_OP_CHFLAGS,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_file_id_create), SMB_VFS_OP_FILE_ID_CREATE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_streaminfo), SMB_VFS_OP_STREAMINFO,
+ SMB_VFS_LAYER_OPAQUE},
+
+ /* NT ACL operations. */
+
+ {SMB_VFS_OP(vfswrap_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_get_nt_acl), SMB_VFS_OP_GET_NT_ACL,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_fset_nt_acl), SMB_VFS_OP_FSET_NT_ACL,
+ SMB_VFS_LAYER_OPAQUE},
+
+ /* POSIX ACL operations. */
+
+ {SMB_VFS_OP(vfswrap_chmod_acl), SMB_VFS_OP_CHMOD_ACL,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_fchmod_acl), SMB_VFS_OP_FCHMOD_ACL,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_get_entry), SMB_VFS_OP_SYS_ACL_GET_ENTRY,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_get_tag_type), SMB_VFS_OP_SYS_ACL_GET_TAG_TYPE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_get_permset), SMB_VFS_OP_SYS_ACL_GET_PERMSET,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_get_qualifier), SMB_VFS_OP_SYS_ACL_GET_QUALIFIER,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_get_fd), SMB_VFS_OP_SYS_ACL_GET_FD,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_clear_perms), SMB_VFS_OP_SYS_ACL_CLEAR_PERMS,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_add_perm), SMB_VFS_OP_SYS_ACL_ADD_PERM,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_to_text), SMB_VFS_OP_SYS_ACL_TO_TEXT,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_init), SMB_VFS_OP_SYS_ACL_INIT,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_create_entry), SMB_VFS_OP_SYS_ACL_CREATE_ENTRY,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_set_tag_type), SMB_VFS_OP_SYS_ACL_SET_TAG_TYPE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_set_qualifier), SMB_VFS_OP_SYS_ACL_SET_QUALIFIER,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_set_permset), SMB_VFS_OP_SYS_ACL_SET_PERMSET,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_valid), SMB_VFS_OP_SYS_ACL_VALID,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_set_file), SMB_VFS_OP_SYS_ACL_SET_FILE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_set_fd), SMB_VFS_OP_SYS_ACL_SET_FD,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_delete_def_file), SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_get_perm), SMB_VFS_OP_SYS_ACL_GET_PERM,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_free_text), SMB_VFS_OP_SYS_ACL_FREE_TEXT,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_free_acl), SMB_VFS_OP_SYS_ACL_FREE_ACL,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_sys_acl_free_qualifier), SMB_VFS_OP_SYS_ACL_FREE_QUALIFIER,
+ SMB_VFS_LAYER_OPAQUE},
+
+ /* EA operations. */
+
+ {SMB_VFS_OP(vfswrap_getxattr), SMB_VFS_OP_GETXATTR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_lgetxattr), SMB_VFS_OP_LGETXATTR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_fgetxattr), SMB_VFS_OP_FGETXATTR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_listxattr), SMB_VFS_OP_LISTXATTR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_llistxattr), SMB_VFS_OP_LLISTXATTR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_flistxattr), SMB_VFS_OP_FLISTXATTR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_removexattr), SMB_VFS_OP_REMOVEXATTR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_lremovexattr), SMB_VFS_OP_LREMOVEXATTR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_fremovexattr), SMB_VFS_OP_FREMOVEXATTR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_setxattr), SMB_VFS_OP_SETXATTR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_lsetxattr), SMB_VFS_OP_LSETXATTR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_fsetxattr), SMB_VFS_OP_FSETXATTR,
+ SMB_VFS_LAYER_OPAQUE},
+
+ {SMB_VFS_OP(vfswrap_aio_read), SMB_VFS_OP_AIO_READ,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_aio_write), SMB_VFS_OP_AIO_WRITE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_aio_return), SMB_VFS_OP_AIO_RETURN,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_aio_cancel), SMB_VFS_OP_AIO_CANCEL,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_aio_error), SMB_VFS_OP_AIO_ERROR,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_aio_fsync), SMB_VFS_OP_AIO_FSYNC,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_aio_suspend),SMB_VFS_OP_AIO_SUSPEND,
+ SMB_VFS_LAYER_OPAQUE},
+
+ {SMB_VFS_OP(vfswrap_aio_force), SMB_VFS_OP_AIO_FORCE,
+ SMB_VFS_LAYER_OPAQUE},
+
+ {SMB_VFS_OP(vfswrap_is_offline),SMB_VFS_OP_IS_OFFLINE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_set_offline),SMB_VFS_OP_SET_OFFLINE,
+ SMB_VFS_LAYER_OPAQUE},
+
+ /* Finish VFS operations definition */
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP,
+ SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_default_init(void);
+NTSTATUS vfs_default_init(void)
+{
+ unsigned int needed = SMB_VFS_OP_LAST + 1; /* convert from index to count */
+
+ if (ARRAY_SIZE(vfs_default_ops) != needed) {
+ DEBUG(0, ("%s: %u ops registered, but %u ops are required\n",
+ DEFAULT_VFS_MODULE_NAME, (unsigned int)ARRAY_SIZE(vfs_default_ops), needed));
+ smb_panic("operation(s) missing from default VFS module");
+ }
+
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
+ DEFAULT_VFS_MODULE_NAME, vfs_default_ops);
+}
diff --git a/source3/modules/vfs_default_quota.c b/source3/modules/vfs_default_quota.c
new file mode 100644
index 0000000000..6dbbad75fa
--- /dev/null
+++ b/source3/modules/vfs_default_quota.c
@@ -0,0 +1,230 @@
+/*
+ * Store default Quotas in a specified quota record
+ *
+ * Copyright (C) Stefan (metze) Metzmacher 2003
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This module allows the default quota values,
+ * in the windows explorer GUI, to be stored on a samba server.
+ * The problem is that linux filesystems only store quotas
+ * for users and groups, but no default quotas.
+ *
+ * Samba returns NO_LIMIT as the default quotas by default
+ * and refuses to update them.
+ *
+ * With this module you can store the default quotas that are reported to
+ * a windows client, in the quota record of a user. By default the root user
+ * is taken because quota limits for root are typically not enforced.
+ *
+ * This module takes 2 parametric parameters in smb.conf:
+ * (the default prefix for them is 'default_quota',
+ * it can be overwrittem when you load the module in
+ * the 'vfs objects' parameter like this:
+ * vfs objects = default_quota:myprefix)
+ *
+ * "<myprefix>:uid" parameter takes a integer argument,
+ * it specifies the uid of the quota record, that will be taken for
+ * storing the default USER-quotas.
+ *
+ * - default value: '0' (for root user)
+ * - e.g.: default_quota:uid = 65534
+ *
+ * "<myprefix>:uid nolimit" parameter takes a boolean argument,
+ * it specifies if we should report the stored default quota values,
+ * also for the user record, or if you should just report NO_LIMIT
+ * to the windows client for the user specified by the "<prefix>:uid" parameter.
+ *
+ * - default value: yes (that means to report NO_LIMIT)
+ * - e.g.: default_quota:uid nolimit = no
+ *
+ * "<myprefix>:gid" parameter takes a integer argument,
+ * it's just like "<prefix>:uid" but for group quotas.
+ * (NOTE: group quotas are not supported from the windows explorer!)
+ *
+ * - default value: '0' (for root group)
+ * - e.g.: default_quota:gid = 65534
+ *
+ * "<myprefix>:gid nolimit" parameter takes a boolean argument,
+ * it's just like "<prefix>:uid nolimit" but for group quotas.
+ * (NOTE: group quotas are not supported from the windows explorer!)
+ *
+ * - default value: yes (that means to report NO_LIMIT)
+ * - e.g.: default_quota:uid nolimit = no
+ *
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_QUOTA
+
+#define DEFAULT_QUOTA_NAME "default_quota"
+
+#define DEFAULT_QUOTA_UID_DEFAULT 0
+#define DEFAULT_QUOTA_UID_NOLIMIT_DEFAULT True
+#define DEFAULT_QUOTA_GID_DEFAULT 0
+#define DEFAULT_QUOTA_GID_NOLIMIT_DEFAULT True
+
+#define DEFAULT_QUOTA_UID(handle) \
+ (uid_t)lp_parm_int(SNUM((handle)->conn),DEFAULT_QUOTA_NAME,"uid",DEFAULT_QUOTA_UID_DEFAULT)
+
+#define DEFAULT_QUOTA_UID_NOLIMIT(handle) \
+ lp_parm_bool(SNUM((handle)->conn),DEFAULT_QUOTA_NAME,"uid nolimit",DEFAULT_QUOTA_UID_NOLIMIT_DEFAULT)
+
+#define DEFAULT_QUOTA_GID(handle) \
+ (gid_t)lp_parm_int(SNUM((handle)->conn),DEFAULT_QUOTA_NAME,"gid",DEFAULT_QUOTA_GID_DEFAULT)
+
+#define DEFAULT_QUOTA_GID_NOLIMIT(handle) \
+ lp_parm_bool(SNUM((handle)->conn),DEFAULT_QUOTA_NAME,"gid nolimit",DEFAULT_QUOTA_GID_NOLIMIT_DEFAULT)
+
+static int default_quota_get_quota(vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dq)
+{
+ int ret = -1;
+
+ if ((ret=SMB_VFS_NEXT_GET_QUOTA(handle, qtype, id, dq))!=0) {
+ return ret;
+ }
+
+ switch (qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ /* we use id.uid == 0 for default quotas */
+ if ((id.uid==DEFAULT_QUOTA_UID(handle)) &&
+ DEFAULT_QUOTA_UID_NOLIMIT(handle)) {
+ SMB_QUOTAS_SET_NO_LIMIT(dq);
+ }
+ break;
+#ifdef HAVE_GROUP_QUOTA
+ case SMB_GROUP_QUOTA_TYPE:
+ /* we use id.gid == 0 for default quotas */
+ if ((id.gid==DEFAULT_QUOTA_GID(handle)) &&
+ DEFAULT_QUOTA_GID_NOLIMIT(handle)) {
+ SMB_QUOTAS_SET_NO_LIMIT(dq);
+ }
+ break;
+#endif /* HAVE_GROUP_QUOTA */
+ case SMB_USER_FS_QUOTA_TYPE:
+ {
+ unid_t qid;
+ uint32 qflags = dq->qflags;
+ qid.uid = DEFAULT_QUOTA_UID(handle);
+ SMB_VFS_NEXT_GET_QUOTA(handle, SMB_USER_QUOTA_TYPE, qid, dq);
+ dq->qflags = qflags;
+ }
+ break;
+#ifdef HAVE_GROUP_QUOTA
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ {
+ unid_t qid;
+ uint32 qflags = dq->qflags;
+ qid.gid = DEFAULT_QUOTA_GID(handle);
+ SMB_VFS_NEXT_GET_QUOTA(handle, SMB_GROUP_QUOTA_TYPE, qid, dq);
+ dq->qflags = qflags;
+ }
+ break;
+#endif /* HAVE_GROUP_QUOTA */
+ default:
+ errno = ENOSYS;
+ return -1;
+ break;
+ }
+
+ return ret;
+}
+
+static int default_quota_set_quota(vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dq)
+{
+ int ret = -1;
+
+ switch (qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ /* we use id.uid == 0 for default quotas */
+ if ((id.uid==DEFAULT_QUOTA_UID(handle)) &&
+ DEFAULT_QUOTA_UID_NOLIMIT(handle)) {
+ return -1;
+ }
+ break;
+#ifdef HAVE_GROUP_QUOTA
+ case SMB_GROUP_QUOTA_TYPE:
+ /* we use id.gid == 0 for default quotas */
+ if ((id.gid==DEFAULT_QUOTA_GID(handle)) &&
+ DEFAULT_QUOTA_GID_NOLIMIT(handle)) {
+ return -1;
+ }
+ break;
+#endif /* HAVE_GROUP_QUOTA */
+ case SMB_USER_FS_QUOTA_TYPE:
+ break;
+#ifdef HAVE_GROUP_QUOTA
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ break;
+#endif /* HAVE_GROUP_QUOTA */
+ default:
+ errno = ENOSYS;
+ return -1;
+ break;
+ }
+
+ if ((ret=SMB_VFS_NEXT_SET_QUOTA(handle, qtype, id, dq))!=0) {
+ return ret;
+ }
+
+ switch (qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ break;
+#ifdef HAVE_GROUP_QUOTA
+ case SMB_GROUP_QUOTA_TYPE:
+ break;
+#endif /* HAVE_GROUP_QUOTA */
+ case SMB_USER_FS_QUOTA_TYPE:
+ {
+ unid_t qid;
+ qid.uid = DEFAULT_QUOTA_UID(handle);
+ ret = SMB_VFS_NEXT_SET_QUOTA(handle, SMB_USER_QUOTA_TYPE, qid, dq);
+ }
+ break;
+#ifdef HAVE_GROUP_QUOTA
+ case SMB_GROUP_FS_QUOTA_TYPE:
+ {
+ unid_t qid;
+ qid.gid = DEFAULT_QUOTA_GID(handle);
+ ret = SMB_VFS_NEXT_SET_QUOTA(handle, SMB_GROUP_QUOTA_TYPE, qid, dq);
+ }
+ break;
+#endif /* HAVE_GROUP_QUOTA */
+ default:
+ errno = ENOSYS;
+ return -1;
+ break;
+ }
+
+ return ret;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple default_quota_ops[] = {
+ {SMB_VFS_OP(default_quota_get_quota), SMB_VFS_OP_GET_QUOTA, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(default_quota_set_quota), SMB_VFS_OP_SET_QUOTA, SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_default_quota_init(void);
+NTSTATUS vfs_default_quota_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, DEFAULT_QUOTA_NAME, default_quota_ops);
+}
diff --git a/source3/modules/vfs_expand_msdfs.c b/source3/modules/vfs_expand_msdfs.c
new file mode 100644
index 0000000000..0d09d213e1
--- /dev/null
+++ b/source3/modules/vfs_expand_msdfs.c
@@ -0,0 +1,215 @@
+/*
+ * Expand msdfs targets based on client IP
+ *
+ * Copyright (C) Volker Lendecke, 2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+/**********************************************************
+ Under mapfile we expect a table of the following format:
+
+ IP-Prefix whitespace expansion
+
+ For example:
+ 192.168.234 local.samba.org
+ 192.168 remote.samba.org
+ default.samba.org
+
+ This is to redirect a DFS client to a host close to it.
+***********************************************************/
+
+static char *read_target_host(TALLOC_CTX *ctx, const char *mapfile)
+{
+ XFILE *f;
+ char buf[1024];
+ char *space = buf;
+ bool found = false;
+
+ f = x_fopen(mapfile, O_RDONLY, 0);
+
+ if (f == NULL) {
+ DEBUG(0,("can't open IP map %s. Error %s\n",
+ mapfile, strerror(errno) ));
+ return NULL;
+ }
+
+ DEBUG(10, ("Scanning mapfile [%s]\n", mapfile));
+
+ while (x_fgets(buf, sizeof(buf), f) != NULL) {
+ char addr[INET6_ADDRSTRLEN];
+
+ if ((strlen(buf) > 0) && (buf[strlen(buf)-1] == '\n'))
+ buf[strlen(buf)-1] = '\0';
+
+ DEBUG(10, ("Scanning line [%s]\n", buf));
+
+ space = strchr_m(buf, ' ');
+
+ if (space == NULL) {
+ DEBUG(0, ("Ignoring invalid line %s\n", buf));
+ continue;
+ }
+
+ *space = '\0';
+
+ if (strncmp(client_addr(get_client_fd(),addr,sizeof(addr)),
+ buf, strlen(buf)) == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ x_fclose(f);
+
+ if (!found) {
+ return NULL;
+ }
+
+ space += 1;
+
+ while (isspace(*space))
+ space += 1;
+
+ return talloc_strdup(ctx, space);
+}
+
+/**********************************************************
+
+ Expand the msdfs target host using read_target_host
+ explained above. The syntax used in the msdfs link is
+
+ msdfs:@table-filename@/share
+
+ Everything between and including the two @-signs is
+ replaced by the substitution string found in the table
+ described above.
+
+***********************************************************/
+
+static char *expand_msdfs_target(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ char *target)
+{
+ char *mapfilename = NULL;
+ char *filename_start = strchr_m(target, '@');
+ char *filename_end = NULL;
+ int filename_len = 0;
+ char *targethost = NULL;
+ char *new_target = NULL;
+
+ if (filename_start == NULL) {
+ DEBUG(10, ("No filename start in %s\n", target));
+ return NULL;
+ }
+
+ filename_end = strchr_m(filename_start+1, '@');
+
+ if (filename_end == NULL) {
+ DEBUG(10, ("No filename end in %s\n", target));
+ return NULL;
+ }
+
+ filename_len = PTR_DIFF(filename_end, filename_start+1);
+ mapfilename = talloc_strdup(ctx, filename_start+1);
+ if (!mapfilename) {
+ return NULL;
+ }
+ mapfilename[filename_len] = '\0';
+
+ DEBUG(10, ("Expanding from table [%s]\n", mapfilename));
+
+ if ((targethost = read_target_host(ctx, mapfilename)) == NULL) {
+ DEBUG(1, ("Could not expand target host from file %s\n",
+ mapfilename));
+ return NULL;
+ }
+
+ targethost = talloc_sub_advanced(ctx,
+ lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name,
+ conn->connectpath,
+ conn->server_info->utok.gid,
+ conn->server_info->sanitized_username,
+ pdb_get_domain(conn->server_info->sam_account),
+ targethost);
+
+ DEBUG(10, ("Expanded targethost to %s\n", targethost));
+
+ /* Replace the part between '@...@' */
+ *filename_start = '\0';
+ new_target = talloc_asprintf(ctx,
+ "%s%s%s",
+ target,
+ targethost,
+ filename_end+1);
+ if (!new_target) {
+ return NULL;
+ }
+
+ DEBUG(10, ("New DFS target: %s\n", new_target));
+ return new_target;
+}
+
+static int expand_msdfs_readlink(struct vfs_handle_struct *handle,
+ const char *path, char *buf, size_t bufsiz)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ int result;
+ char *target = TALLOC_ARRAY(ctx, char, PATH_MAX+1);
+
+ if (!target) {
+ errno = ENOMEM;
+ return -1;
+ }
+ result = SMB_VFS_NEXT_READLINK(handle, path, target,
+ PATH_MAX);
+
+ if (result < 0)
+ return result;
+
+ target[result] = '\0';
+
+ if ((strncmp(target, "msdfs:", strlen("msdfs:")) == 0) &&
+ (strchr_m(target, '@') != NULL)) {
+ target = expand_msdfs_target(ctx, handle->conn, target);
+ if (!target) {
+ errno = ENOENT;
+ return -1;
+ }
+ }
+
+ safe_strcpy(buf, target, bufsiz-1);
+ return strlen(buf);
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple expand_msdfs_ops[] = {
+ {SMB_VFS_OP(expand_msdfs_readlink), SMB_VFS_OP_READLINK,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_expand_msdfs_init(void);
+NTSTATUS vfs_expand_msdfs_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "expand_msdfs",
+ expand_msdfs_ops);
+}
diff --git a/source3/modules/vfs_extd_audit.c b/source3/modules/vfs_extd_audit.c
new file mode 100644
index 0000000000..7516cba1d3
--- /dev/null
+++ b/source3/modules/vfs_extd_audit.c
@@ -0,0 +1,370 @@
+/*
+ * Auditing VFS module for samba. Log selected file operations to syslog
+ * facility.
+ *
+ * Copyright (C) Tim Potter, 1999-2000
+ * Copyright (C) Alexander Bokovoy, 2002
+ * Copyright (C) John H Terpstra, 2003
+ * Copyright (C) Stefan (metze) Metzmacher, 2003
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "includes.h"
+
+static int vfs_extd_audit_debug_level = DBGC_VFS;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS vfs_extd_audit_debug_level
+
+/* Function prototypes */
+
+static int audit_connect(vfs_handle_struct *handle, const char *svc, const char *user);
+static void audit_disconnect(vfs_handle_struct *handle);
+static SMB_STRUCT_DIR *audit_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr);
+static int audit_mkdir(vfs_handle_struct *handle, const char *path, mode_t mode);
+static int audit_rmdir(vfs_handle_struct *handle, const char *path);
+static int audit_open(vfs_handle_struct *handle, const char *fname, files_struct *fsp, int flags, mode_t mode);
+static int audit_close(vfs_handle_struct *handle, files_struct *fsp);
+static int audit_rename(vfs_handle_struct *handle, const char *oldname, const char *newname);
+static int audit_unlink(vfs_handle_struct *handle, const char *path);
+static int audit_chmod(vfs_handle_struct *handle, const char *path, mode_t mode);
+static int audit_chmod_acl(vfs_handle_struct *handle, const char *name, mode_t mode);
+static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode);
+static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode);
+
+/* VFS operations */
+
+static vfs_op_tuple audit_op_tuples[] = {
+
+ /* Disk operations */
+
+ {SMB_VFS_OP(audit_connect), SMB_VFS_OP_CONNECT, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_disconnect), SMB_VFS_OP_DISCONNECT, SMB_VFS_LAYER_LOGGER},
+
+ /* Directory operations */
+
+ {SMB_VFS_OP(audit_opendir), SMB_VFS_OP_OPENDIR, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_mkdir), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_rmdir), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_LOGGER},
+
+ /* File operations */
+
+ {SMB_VFS_OP(audit_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_close), SMB_VFS_OP_CLOSE, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_rename), SMB_VFS_OP_RENAME, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_unlink), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_chmod), SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_fchmod), SMB_VFS_OP_FCHMOD, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_chmod_acl), SMB_VFS_OP_CHMOD_ACL, SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(audit_fchmod_acl), SMB_VFS_OP_FCHMOD_ACL, SMB_VFS_LAYER_LOGGER},
+
+ /* Finish VFS operations definition */
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+
+static int audit_syslog_facility(vfs_handle_struct *handle)
+{
+ static const struct enum_list enum_log_facilities[] = {
+ { LOG_USER, "USER" },
+ { LOG_LOCAL0, "LOCAL0" },
+ { LOG_LOCAL1, "LOCAL1" },
+ { LOG_LOCAL2, "LOCAL2" },
+ { LOG_LOCAL3, "LOCAL3" },
+ { LOG_LOCAL4, "LOCAL4" },
+ { LOG_LOCAL5, "LOCAL5" },
+ { LOG_LOCAL6, "LOCAL6" },
+ { LOG_LOCAL7, "LOCAL7" }
+ };
+
+ int facility;
+
+ facility = lp_parm_enum(SNUM(handle->conn), "extd_audit", "facility", enum_log_facilities, LOG_USER);
+
+ return facility;
+}
+
+
+static int audit_syslog_priority(vfs_handle_struct *handle)
+{
+ static const struct enum_list enum_log_priorities[] = {
+ { LOG_EMERG, "EMERG" },
+ { LOG_ALERT, "ALERT" },
+ { LOG_CRIT, "CRIT" },
+ { LOG_ERR, "ERR" },
+ { LOG_WARNING, "WARNING" },
+ { LOG_NOTICE, "NOTICE" },
+ { LOG_INFO, "INFO" },
+ { LOG_DEBUG, "DEBUG" }
+ };
+
+ int priority;
+
+ priority = lp_parm_enum(SNUM(handle->conn), "extd_audit", "priority",
+ enum_log_priorities, LOG_NOTICE);
+ if (priority == -1) {
+ priority = LOG_WARNING;
+ }
+
+ return priority;
+}
+
+/* Implementation of vfs_ops. Pass everything on to the default
+ operation but log event first. */
+
+static int audit_connect(vfs_handle_struct *handle, const char *svc, const char *user)
+{
+ int result;
+
+ openlog("smbd_audit", LOG_PID, audit_syslog_facility(handle));
+
+ syslog(audit_syslog_priority(handle), "connect to service %s by user %s\n",
+ svc, user);
+ DEBUG(10, ("Connected to service %s as user %s\n",
+ svc, user));
+
+ result = SMB_VFS_NEXT_CONNECT(handle, svc, user);
+
+ return result;
+}
+
+static void audit_disconnect(vfs_handle_struct *handle)
+{
+ syslog(audit_syslog_priority(handle), "disconnected\n");
+ DEBUG(10, ("Disconnected from VFS module extd_audit\n"));
+ SMB_VFS_NEXT_DISCONNECT(handle);
+
+ return;
+}
+
+static SMB_STRUCT_DIR *audit_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr)
+{
+ SMB_STRUCT_DIR *result;
+
+ result = SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
+
+ syslog(audit_syslog_priority(handle), "opendir %s %s%s\n",
+ fname,
+ (result == NULL) ? "failed: " : "",
+ (result == NULL) ? strerror(errno) : "");
+ DEBUG(1, ("vfs_extd_audit: opendir %s %s %s\n",
+ fname,
+ (result == NULL) ? "failed: " : "",
+ (result == NULL) ? strerror(errno) : ""));
+
+ return result;
+}
+
+static int audit_mkdir(vfs_handle_struct *handle, const char *path, mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_MKDIR(handle, path, mode);
+
+ syslog(audit_syslog_priority(handle), "mkdir %s %s%s\n",
+ path,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+ DEBUG(0, ("vfs_extd_audit: mkdir %s %s %s\n",
+ path,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : ""));
+
+ return result;
+}
+
+static int audit_rmdir(vfs_handle_struct *handle, const char *path)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_RMDIR(handle, path);
+
+ syslog(audit_syslog_priority(handle), "rmdir %s %s%s\n",
+ path,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+ DEBUG(0, ("vfs_extd_audit: rmdir %s %s %s\n",
+ path,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : ""));
+
+ return result;
+}
+
+static int audit_open(vfs_handle_struct *handle, const char *fname, files_struct *fsp, int flags, mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+
+ syslog(audit_syslog_priority(handle), "open %s (fd %d) %s%s%s\n",
+ fname, result,
+ ((flags & O_WRONLY) || (flags & O_RDWR)) ? "for writing " : "",
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+ DEBUG(2, ("vfs_extd_audit: open %s %s %s\n",
+ fname,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : ""));
+
+ return result;
+}
+
+static int audit_close(vfs_handle_struct *handle, files_struct *fsp)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_CLOSE(handle, fsp);
+
+ syslog(audit_syslog_priority(handle), "close fd %d %s%s\n",
+ fsp->fh->fd,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+ DEBUG(2, ("vfs_extd_audit: close fd %d %s %s\n",
+ fsp->fh->fd,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : ""));
+
+ return result;
+}
+
+static int audit_rename(vfs_handle_struct *handle, const char *oldname, const char *newname)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_RENAME(handle, oldname, newname);
+
+ syslog(audit_syslog_priority(handle), "rename %s -> %s %s%s\n",
+ oldname, newname,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+ DEBUG(1, ("vfs_extd_audit: rename old: %s newname: %s %s %s\n",
+ oldname, newname,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : ""));
+
+ return result;
+}
+
+static int audit_unlink(vfs_handle_struct *handle, const char *path)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_UNLINK(handle, path);
+
+ syslog(audit_syslog_priority(handle), "unlink %s %s%s\n",
+ path,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+ DEBUG(0, ("vfs_extd_audit: unlink %s %s %s\n",
+ path,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : ""));
+
+ return result;
+}
+
+static int audit_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_CHMOD(handle, path, mode);
+
+ syslog(audit_syslog_priority(handle), "chmod %s mode 0x%x %s%s\n",
+ path, mode,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+ DEBUG(1, ("vfs_extd_audit: chmod %s mode 0x%x %s %s\n",
+ path, mode,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : ""));
+
+ return result;
+}
+
+static int audit_chmod_acl(vfs_handle_struct *handle, const char *path, mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_CHMOD_ACL(handle, path, mode);
+
+ syslog(audit_syslog_priority(handle), "chmod_acl %s mode 0x%x %s%s\n",
+ path, mode,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+ DEBUG(1, ("vfs_extd_audit: chmod_acl %s mode 0x%x %s %s\n",
+ path, mode,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : ""));
+
+ return result;
+}
+
+static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
+
+ syslog(audit_syslog_priority(handle), "fchmod %s mode 0x%x %s%s\n",
+ fsp->fsp_name, mode,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+ DEBUG(1, ("vfs_extd_audit: fchmod %s mode 0x%x %s %s",
+ fsp->fsp_name, mode,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : ""));
+
+ return result;
+}
+
+static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
+
+ syslog(audit_syslog_priority(handle), "fchmod_acl %s mode 0x%x %s%s\n",
+ fsp->fsp_name, mode,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+ DEBUG(1, ("vfs_extd_audit: fchmod_acl %s mode 0x%x %s %s",
+ fsp->fsp_name, mode,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : ""));
+
+ return result;
+}
+
+NTSTATUS vfs_extd_audit_init(void);
+NTSTATUS vfs_extd_audit_init(void)
+{
+ NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "extd_audit", audit_op_tuples);
+
+ if (!NT_STATUS_IS_OK(ret))
+ return ret;
+
+ vfs_extd_audit_debug_level = debug_add_class("extd_audit");
+ if (vfs_extd_audit_debug_level == -1) {
+ vfs_extd_audit_debug_level = DBGC_VFS;
+ DEBUG(0, ("vfs_extd_audit: Couldn't register custom debugging class!\n"));
+ } else {
+ DEBUG(10, ("vfs_extd_audit: Debug class number of 'extd_audit': %d\n", vfs_extd_audit_debug_level));
+ }
+
+ return ret;
+}
diff --git a/source3/modules/vfs_fake_perms.c b/source3/modules/vfs_fake_perms.c
new file mode 100644
index 0000000000..2989322147
--- /dev/null
+++ b/source3/modules/vfs_fake_perms.c
@@ -0,0 +1,77 @@
+/*
+ * Fake Perms VFS module. Implements passthrough operation of all VFS
+ * calls to disk functions, except for file permissions, which are now
+ * mode 0700 for the current uid/gid.
+ *
+ * Copyright (C) Tim Potter, 1999-2000
+ * Copyright (C) Alexander Bokovoy, 2002
+ * Copyright (C) Andrew Bartlett, 2002
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+static int fake_perms_stat(vfs_handle_struct *handle, const char *fname, SMB_STRUCT_STAT *sbuf)
+{
+ int ret = -1;
+
+ ret = SMB_VFS_NEXT_STAT(handle, fname, sbuf);
+ if (ret == 0) {
+ if (S_ISDIR(sbuf->st_mode)) {
+ sbuf->st_mode = S_IFDIR | S_IRWXU;
+ } else {
+ sbuf->st_mode = S_IRWXU;
+ }
+ sbuf->st_uid = handle->conn->server_info->utok.uid;
+ sbuf->st_gid = handle->conn->server_info->utok.gid;
+ }
+
+ return ret;
+}
+
+static int fake_perms_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
+{
+ int ret = -1;
+
+ ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+ if (ret == 0) {
+ if (S_ISDIR(sbuf->st_mode)) {
+ sbuf->st_mode = S_IFDIR | S_IRWXU;
+ } else {
+ sbuf->st_mode = S_IRWXU;
+ }
+ sbuf->st_uid = handle->conn->server_info->utok.uid;
+ sbuf->st_gid = handle->conn->server_info->utok.gid;
+ }
+ return ret;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple fake_perms_ops[] = {
+ {SMB_VFS_OP(fake_perms_stat), SMB_VFS_OP_STAT, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(fake_perms_fstat), SMB_VFS_OP_FSTAT, SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_fake_perms_init(void);
+NTSTATUS vfs_fake_perms_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fake_perms", fake_perms_ops);
+}
diff --git a/source3/modules/vfs_fileid.c b/source3/modules/vfs_fileid.c
new file mode 100644
index 0000000000..8ab4ac3793
--- /dev/null
+++ b/source3/modules/vfs_fileid.c
@@ -0,0 +1,288 @@
+/*
+ * VFS module to alter the algorithm to calculate
+ * the struct file_id used as key for the share mode
+ * and byte range locking db's.
+ *
+ * Copyright (C) 2007, Stefan Metzmacher
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+static int vfs_fileid_debug_level = DBGC_VFS;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS vfs_fileid_debug_level
+
+struct fileid_mount_entry {
+ SMB_DEV_T device;
+ const char *mnt_fsname;
+ fsid_t fsid;
+ uint64_t devid;
+};
+
+struct fileid_handle_data {
+ uint64_t (*device_mapping_fn)(struct fileid_handle_data *data,
+ SMB_DEV_T dev);
+ unsigned num_mount_entries;
+ struct fileid_mount_entry *mount_entries;
+};
+
+/* load all the mount entries from the mtab */
+static void fileid_load_mount_entries(struct fileid_handle_data *data)
+{
+ FILE *f;
+ struct mntent *m;
+
+ data->num_mount_entries = 0;
+ TALLOC_FREE(data->mount_entries);
+
+ f = setmntent("/etc/mtab", "r");
+ if (!f) return;
+
+ while ((m = getmntent(f))) {
+ struct stat st;
+ struct statfs sfs;
+ struct fileid_mount_entry *cur;
+
+ if (stat(m->mnt_dir, &st) != 0) continue;
+ if (statfs(m->mnt_dir, &sfs) != 0) continue;
+
+ if (strncmp(m->mnt_fsname, "/dev/", 5) == 0) {
+ m->mnt_fsname += 5;
+ }
+
+ data->mount_entries = TALLOC_REALLOC_ARRAY(data,
+ data->mount_entries,
+ struct fileid_mount_entry,
+ data->num_mount_entries+1);
+ if (data->mount_entries == NULL) {
+ goto nomem;
+ }
+
+ cur = &data->mount_entries[data->num_mount_entries];
+ cur->device = st.st_dev;
+ cur->mnt_fsname = talloc_strdup(data->mount_entries,
+ m->mnt_fsname);
+ if (!cur->mnt_fsname) goto nomem;
+ cur->fsid = sfs.f_fsid;
+ cur->devid = (uint64_t)-1;
+
+ data->num_mount_entries++;
+ }
+ endmntent(f);
+ return;
+
+nomem:
+ if (f) endmntent(f);
+
+ data->num_mount_entries = 0;
+ TALLOC_FREE(data->mount_entries);
+
+ return;
+}
+
+/* find a mount entry given a dev_t */
+static struct fileid_mount_entry *fileid_find_mount_entry(struct fileid_handle_data *data,
+ SMB_DEV_T dev)
+{
+ int i;
+
+ if (data->num_mount_entries == 0) {
+ fileid_load_mount_entries(data);
+ }
+ for (i=0;i<data->num_mount_entries;i++) {
+ if (data->mount_entries[i].device == dev) {
+ return &data->mount_entries[i];
+ }
+ }
+ /* 2nd pass after reloading */
+ fileid_load_mount_entries(data);
+ for (i=0;i<data->num_mount_entries;i++) {
+ if (data->mount_entries[i].device == dev) {
+ return &data->mount_entries[i];
+ }
+ }
+ return NULL;
+}
+
+
+/* a 64 bit hash, based on the one in tdb */
+static uint64_t fileid_uint64_hash(const uint8_t *s, size_t len)
+{
+ uint64_t value; /* Used to compute the hash value. */
+ uint32_t i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AFLL * len, i=0; i < len; i++)
+ value = (value + (s[i] << (i*5 % 24)));
+
+ return (1103515243LL * value + 12345LL);
+}
+
+/* a device mapping using a fsname */
+static uint64_t fileid_device_mapping_fsname(struct fileid_handle_data *data,
+ SMB_DEV_T dev)
+{
+ struct fileid_mount_entry *m;
+
+ m = fileid_find_mount_entry(data, dev);
+ if (!m) return dev;
+
+ if (m->devid == (uint64_t)-1) {
+ m->devid = fileid_uint64_hash((uint8_t *)m->mnt_fsname,
+ strlen(m->mnt_fsname));
+ }
+
+ return m->devid;
+}
+
+/* device mapping functions using a fsid */
+static uint64_t fileid_device_mapping_fsid(struct fileid_handle_data *data,
+ SMB_DEV_T dev)
+{
+ struct fileid_mount_entry *m;
+
+ m = fileid_find_mount_entry(data, dev);
+ if (!m) return dev;
+
+ if (m->devid == (uint64_t)-1) {
+ if (sizeof(fsid_t) > sizeof(uint64_t)) {
+ m->devid = fileid_uint64_hash((uint8_t *)&m->fsid,
+ sizeof(m->fsid));
+ } else {
+ union {
+ uint64_t ret;
+ fsid_t fsid;
+ } u;
+ ZERO_STRUCT(u);
+ u.fsid = m->fsid;
+ m->devid = u.ret;
+ }
+ }
+
+ return m->devid;
+}
+
+static int fileid_connect(struct vfs_handle_struct *handle,
+ const char *service, const char *user)
+{
+ struct fileid_handle_data *data;
+ const char *algorithm;
+
+ data = talloc_zero(handle->conn, struct fileid_handle_data);
+ if (!data) {
+ DEBUG(0, ("talloc_zero() failed\n"));
+ return -1;
+ }
+
+ data->device_mapping_fn = fileid_device_mapping_fsid;
+ algorithm = lp_parm_const_string(SNUM(handle->conn),
+ "fileid", "mapping",
+ "fsname");
+ if (strcmp("fsname", algorithm) == 0) {
+ data->device_mapping_fn = fileid_device_mapping_fsname;
+ } else if (strcmp("fsid", algorithm) == 0) {
+ data->device_mapping_fn = fileid_device_mapping_fsid;
+ } else {
+ DEBUG(0,("fileid_connect(): unknown algorithm[%s]\n", algorithm));
+ return -1;
+ }
+
+ SMB_VFS_HANDLE_SET_DATA(handle, data, NULL,
+ struct fileid_handle_data,
+ return -1);
+
+ DEBUG(10, ("fileid_connect(): connect to service[%s] with algorithm[%s]\n",
+ service, algorithm));
+
+ return SMB_VFS_NEXT_CONNECT(handle, service, user);
+}
+
+static void fileid_disconnect(struct vfs_handle_struct *handle)
+{
+ DEBUG(10,("fileid_disconnect() connect to service[%s].\n",
+ lp_servicename(SNUM(handle->conn))));
+
+ SMB_VFS_NEXT_DISCONNECT(handle);
+}
+
+static struct file_id fileid_file_id_create(struct vfs_handle_struct *handle,
+ SMB_DEV_T dev, SMB_INO_T inode)
+{
+ struct fileid_handle_data *data;
+ struct file_id id;
+
+ ZERO_STRUCT(id);
+
+ SMB_VFS_HANDLE_GET_DATA(handle, data,
+ struct fileid_handle_data,
+ return id);
+
+ id.devid = data->device_mapping_fn(data, dev);
+ id.inode = inode;
+
+ return id;
+}
+
+static vfs_op_tuple fileid_ops[] = {
+
+ /* Disk operations */
+ {
+ SMB_VFS_OP(fileid_connect),
+ SMB_VFS_OP_CONNECT,
+ SMB_VFS_LAYER_TRANSPARENT
+ },
+ {
+ SMB_VFS_OP(fileid_disconnect),
+ SMB_VFS_OP_DISCONNECT,
+ SMB_VFS_LAYER_TRANSPARENT
+ },
+
+ /* File operations */
+ {
+ SMB_VFS_OP(fileid_file_id_create),
+ SMB_VFS_OP_FILE_ID_CREATE,
+ SMB_VFS_LAYER_OPAQUE
+ },
+
+ /* End marker */
+ {
+ SMB_VFS_OP(NULL),
+ SMB_VFS_OP_NOOP,
+ SMB_VFS_LAYER_NOOP
+ }
+};
+
+NTSTATUS vfs_fileid_init(void);
+NTSTATUS vfs_fileid_init(void)
+{
+ NTSTATUS ret;
+
+ ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fileid", fileid_ops);
+ if (!NT_STATUS_IS_OK(ret)) {
+ return ret;
+ }
+
+ vfs_fileid_debug_level = debug_add_class("fileid");
+ if (vfs_fileid_debug_level == -1) {
+ vfs_fileid_debug_level = DBGC_VFS;
+ DEBUG(0, ("vfs_fileid: Couldn't register custom debugging class!\n"));
+ } else {
+ DEBUG(10, ("vfs_fileid: Debug class number of 'fileid': %d\n", vfs_fileid_debug_level));
+ }
+
+ return ret;
+}
diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c
new file mode 100644
index 0000000000..1224ec3edb
--- /dev/null
+++ b/source3/modules/vfs_full_audit.c
@@ -0,0 +1,2209 @@
+/*
+ * Auditing VFS module for samba. Log selected file operations to syslog
+ * facility.
+ *
+ * Copyright (C) Tim Potter, 1999-2000
+ * Copyright (C) Alexander Bokovoy, 2002
+ * Copyright (C) John H Terpstra, 2003
+ * Copyright (C) Stefan (metze) Metzmacher, 2003
+ * Copyright (C) Volker Lendecke, 2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This module implements parseable logging for all Samba VFS operations.
+ *
+ * You use it as follows:
+ *
+ * [tmp]
+ * path = /tmp
+ * vfs objects = full_audit
+ * full_audit:prefix = %u|%I
+ * full_audit:success = open opendir
+ * full_audit:failure = all
+ *
+ * vfs op can be "all" which means log all operations.
+ * vfs op can be "none" which means no logging.
+ *
+ * This leads to syslog entries of the form:
+ * smbd_audit: nobody|192.168.234.1|opendir|ok|.
+ * smbd_audit: nobody|192.168.234.1|open|fail (File not found)|r|x.txt
+ *
+ * where "nobody" is the connected username and "192.168.234.1" is the
+ * client's IP address.
+ *
+ * Options:
+ *
+ * prefix: A macro expansion template prepended to the syslog entry.
+ *
+ * success: A list of VFS operations for which a successful completion should
+ * be logged. Defaults to no logging at all. The special operation "all" logs
+ * - you guessed it - everything.
+ *
+ * failure: A list of VFS operations for which failure to complete should be
+ * logged. Defaults to logging everything.
+ */
+
+
+#include "includes.h"
+
+static int vfs_full_audit_debug_level = DBGC_VFS;
+
+struct vfs_full_audit_private_data {
+ struct bitmap *success_ops;
+ struct bitmap *failure_ops;
+};
+
+#undef DBGC_CLASS
+#define DBGC_CLASS vfs_full_audit_debug_level
+
+/* Function prototypes */
+
+static int smb_full_audit_connect(vfs_handle_struct *handle,
+ const char *svc, const char *user);
+static void smb_full_audit_disconnect(vfs_handle_struct *handle);
+static SMB_BIG_UINT smb_full_audit_disk_free(vfs_handle_struct *handle,
+ const char *path,
+ bool small_query, SMB_BIG_UINT *bsize,
+ SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
+static int smb_full_audit_get_quota(struct vfs_handle_struct *handle,
+ enum SMB_QUOTA_TYPE qtype, unid_t id,
+ SMB_DISK_QUOTA *qt);
+static int smb_full_audit_set_quota(struct vfs_handle_struct *handle,
+ enum SMB_QUOTA_TYPE qtype, unid_t id,
+ SMB_DISK_QUOTA *qt);
+static int smb_full_audit_get_shadow_copy_data(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ SHADOW_COPY_DATA *shadow_copy_data, bool labels);
+static int smb_full_audit_statvfs(struct vfs_handle_struct *handle,
+ const char *path,
+ struct vfs_statvfs_struct *statbuf);
+
+static SMB_STRUCT_DIR *smb_full_audit_opendir(vfs_handle_struct *handle,
+ const char *fname, const char *mask, uint32 attr);
+static SMB_STRUCT_DIRENT *smb_full_audit_readdir(vfs_handle_struct *handle,
+ SMB_STRUCT_DIR *dirp);
+static void smb_full_audit_seekdir(vfs_handle_struct *handle,
+ SMB_STRUCT_DIR *dirp, long offset);
+static long smb_full_audit_telldir(vfs_handle_struct *handle,
+ SMB_STRUCT_DIR *dirp);
+static void smb_full_audit_rewinddir(vfs_handle_struct *handle,
+ SMB_STRUCT_DIR *dirp);
+static int smb_full_audit_mkdir(vfs_handle_struct *handle,
+ const char *path, mode_t mode);
+static int smb_full_audit_rmdir(vfs_handle_struct *handle,
+ const char *path);
+static int smb_full_audit_closedir(vfs_handle_struct *handle,
+ SMB_STRUCT_DIR *dirp);
+static int smb_full_audit_open(vfs_handle_struct *handle,
+ const char *fname, files_struct *fsp, int flags, mode_t mode);
+static int smb_full_audit_close(vfs_handle_struct *handle, files_struct *fsp);
+static ssize_t smb_full_audit_read(vfs_handle_struct *handle, files_struct *fsp,
+ void *data, size_t n);
+static ssize_t smb_full_audit_pread(vfs_handle_struct *handle, files_struct *fsp,
+ void *data, size_t n, SMB_OFF_T offset);
+static ssize_t smb_full_audit_write(vfs_handle_struct *handle, files_struct *fsp,
+ const void *data, size_t n);
+static ssize_t smb_full_audit_pwrite(vfs_handle_struct *handle, files_struct *fsp,
+ const void *data, size_t n,
+ SMB_OFF_T offset);
+static SMB_OFF_T smb_full_audit_lseek(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_OFF_T offset, int whence);
+static ssize_t smb_full_audit_sendfile(vfs_handle_struct *handle, int tofd,
+ files_struct *fromfsp,
+ const DATA_BLOB *hdr, SMB_OFF_T offset,
+ size_t n);
+static ssize_t smb_full_audit_recvfile(vfs_handle_struct *handle, int fromfd,
+ files_struct *tofsp,
+ SMB_OFF_T offset,
+ size_t n);
+static int smb_full_audit_rename(vfs_handle_struct *handle,
+ const char *oldname, const char *newname);
+static int smb_full_audit_fsync(vfs_handle_struct *handle, files_struct *fsp);
+static int smb_full_audit_stat(vfs_handle_struct *handle,
+ const char *fname, SMB_STRUCT_STAT *sbuf);
+static int smb_full_audit_fstat(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_STRUCT_STAT *sbuf);
+static int smb_full_audit_lstat(vfs_handle_struct *handle,
+ const char *path, SMB_STRUCT_STAT *sbuf);
+static int smb_full_audit_unlink(vfs_handle_struct *handle,
+ const char *path);
+static int smb_full_audit_chmod(vfs_handle_struct *handle,
+ const char *path, mode_t mode);
+static int smb_full_audit_fchmod(vfs_handle_struct *handle, files_struct *fsp,
+ mode_t mode);
+static int smb_full_audit_chown(vfs_handle_struct *handle,
+ const char *path, uid_t uid, gid_t gid);
+static int smb_full_audit_fchown(vfs_handle_struct *handle, files_struct *fsp,
+ uid_t uid, gid_t gid);
+static int smb_full_audit_lchown(vfs_handle_struct *handle,
+ const char *path, uid_t uid, gid_t gid);
+static int smb_full_audit_chdir(vfs_handle_struct *handle,
+ const char *path);
+static char *smb_full_audit_getwd(vfs_handle_struct *handle,
+ char *path);
+static int smb_full_audit_ntimes(vfs_handle_struct *handle,
+ const char *path, const struct timespec ts[2]);
+static int smb_full_audit_ftruncate(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_OFF_T len);
+static bool smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp,
+ int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
+static int smb_full_audit_kernel_flock(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32 share_mode);
+static int smb_full_audit_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
+ int leasetype);
+static bool smb_full_audit_getlock(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid);
+static int smb_full_audit_symlink(vfs_handle_struct *handle,
+ const char *oldpath, const char *newpath);
+static int smb_full_audit_readlink(vfs_handle_struct *handle,
+ const char *path, char *buf, size_t bufsiz);
+static int smb_full_audit_link(vfs_handle_struct *handle,
+ const char *oldpath, const char *newpath);
+static int smb_full_audit_mknod(vfs_handle_struct *handle,
+ const char *pathname, mode_t mode, SMB_DEV_T dev);
+static char *smb_full_audit_realpath(vfs_handle_struct *handle,
+ const char *path, char *resolved_path);
+static NTSTATUS smb_full_audit_notify_watch(struct vfs_handle_struct *handle,
+ struct sys_notify_context *ctx,
+ struct notify_entry *e,
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev),
+ void *private_data, void *handle_p);
+static int smb_full_audit_chflags(vfs_handle_struct *handle,
+ const char *path, unsigned int flags);
+static struct file_id smb_full_audit_file_id_create(struct vfs_handle_struct *handle,
+ SMB_DEV_T dev, SMB_INO_T inode);
+static NTSTATUS smb_full_audit_streaminfo(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *fname,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *pnum_streams,
+ struct stream_struct **pstreams);
+static NTSTATUS smb_full_audit_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
+ uint32 security_info,
+ SEC_DESC **ppdesc);
+static NTSTATUS smb_full_audit_get_nt_acl(vfs_handle_struct *handle,
+ const char *name, uint32 security_info,
+ SEC_DESC **ppdesc);
+static NTSTATUS smb_full_audit_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
+ uint32 security_info_sent,
+ SEC_DESC *psd);
+static int smb_full_audit_chmod_acl(vfs_handle_struct *handle,
+ const char *path, mode_t mode);
+static int smb_full_audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp,
+ mode_t mode);
+static int smb_full_audit_sys_acl_get_entry(vfs_handle_struct *handle,
+ SMB_ACL_T theacl, int entry_id,
+ SMB_ACL_ENTRY_T *entry_p);
+static int smb_full_audit_sys_acl_get_tag_type(vfs_handle_struct *handle,
+ SMB_ACL_ENTRY_T entry_d,
+ SMB_ACL_TAG_T *tag_type_p);
+static int smb_full_audit_sys_acl_get_permset(vfs_handle_struct *handle,
+ SMB_ACL_ENTRY_T entry_d,
+ SMB_ACL_PERMSET_T *permset_p);
+static void * smb_full_audit_sys_acl_get_qualifier(vfs_handle_struct *handle,
+ SMB_ACL_ENTRY_T entry_d);
+static SMB_ACL_T smb_full_audit_sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ SMB_ACL_TYPE_T type);
+static SMB_ACL_T smb_full_audit_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp);
+static int smb_full_audit_sys_acl_clear_perms(vfs_handle_struct *handle,
+ SMB_ACL_PERMSET_T permset);
+static int smb_full_audit_sys_acl_add_perm(vfs_handle_struct *handle,
+ SMB_ACL_PERMSET_T permset,
+ SMB_ACL_PERM_T perm);
+static char * smb_full_audit_sys_acl_to_text(vfs_handle_struct *handle,
+ SMB_ACL_T theacl,
+ ssize_t *plen);
+static SMB_ACL_T smb_full_audit_sys_acl_init(vfs_handle_struct *handle,
+ int count);
+static int smb_full_audit_sys_acl_create_entry(vfs_handle_struct *handle,
+ SMB_ACL_T *pacl,
+ SMB_ACL_ENTRY_T *pentry);
+static int smb_full_audit_sys_acl_set_tag_type(vfs_handle_struct *handle,
+ SMB_ACL_ENTRY_T entry,
+ SMB_ACL_TAG_T tagtype);
+static int smb_full_audit_sys_acl_set_qualifier(vfs_handle_struct *handle,
+ SMB_ACL_ENTRY_T entry,
+ void *qual);
+static int smb_full_audit_sys_acl_set_permset(vfs_handle_struct *handle,
+ SMB_ACL_ENTRY_T entry,
+ SMB_ACL_PERMSET_T permset);
+static int smb_full_audit_sys_acl_valid(vfs_handle_struct *handle,
+ SMB_ACL_T theacl );
+static int smb_full_audit_sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name, SMB_ACL_TYPE_T acltype,
+ SMB_ACL_T theacl);
+static int smb_full_audit_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_ACL_T theacl);
+static int smb_full_audit_sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path);
+static int smb_full_audit_sys_acl_get_perm(vfs_handle_struct *handle,
+ SMB_ACL_PERMSET_T permset,
+ SMB_ACL_PERM_T perm);
+static int smb_full_audit_sys_acl_free_text(vfs_handle_struct *handle,
+ char *text);
+static int smb_full_audit_sys_acl_free_acl(vfs_handle_struct *handle,
+ SMB_ACL_T posix_acl);
+static int smb_full_audit_sys_acl_free_qualifier(vfs_handle_struct *handle,
+ void *qualifier,
+ SMB_ACL_TAG_T tagtype);
+static ssize_t smb_full_audit_getxattr(struct vfs_handle_struct *handle,
+ const char *path,
+ const char *name, void *value, size_t size);
+static ssize_t smb_full_audit_lgetxattr(struct vfs_handle_struct *handle,
+ const char *path, const char *name,
+ void *value, size_t size);
+static ssize_t smb_full_audit_fgetxattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *name, void *value, size_t size);
+static ssize_t smb_full_audit_listxattr(struct vfs_handle_struct *handle,
+ const char *path, char *list, size_t size);
+static ssize_t smb_full_audit_llistxattr(struct vfs_handle_struct *handle,
+ const char *path, char *list, size_t size);
+static ssize_t smb_full_audit_flistxattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, char *list,
+ size_t size);
+static int smb_full_audit_removexattr(struct vfs_handle_struct *handle,
+ const char *path,
+ const char *name);
+static int smb_full_audit_lremovexattr(struct vfs_handle_struct *handle,
+ const char *path,
+ const char *name);
+static int smb_full_audit_fremovexattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *name);
+static int smb_full_audit_setxattr(struct vfs_handle_struct *handle,
+ const char *path,
+ const char *name, const void *value, size_t size,
+ int flags);
+static int smb_full_audit_lsetxattr(struct vfs_handle_struct *handle,
+ const char *path,
+ const char *name, const void *value, size_t size,
+ int flags);
+static int smb_full_audit_fsetxattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, const char *name,
+ const void *value, size_t size, int flags);
+
+static int smb_full_audit_aio_read(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
+static int smb_full_audit_aio_write(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
+static ssize_t smb_full_audit_aio_return(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
+static int smb_full_audit_aio_cancel(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
+static int smb_full_audit_aio_error(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
+static int smb_full_audit_aio_fsync(struct vfs_handle_struct *handle, struct files_struct *fsp, int op, SMB_STRUCT_AIOCB *aiocb);
+static int smb_full_audit_aio_suspend(struct vfs_handle_struct *handle, struct files_struct *fsp, const SMB_STRUCT_AIOCB * const aiocb[], int n, const struct timespec *ts);
+
+/* VFS operations */
+
+static vfs_op_tuple audit_op_tuples[] = {
+
+ /* Disk operations */
+
+ {SMB_VFS_OP(smb_full_audit_connect), SMB_VFS_OP_CONNECT,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_disconnect), SMB_VFS_OP_DISCONNECT,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_disk_free), SMB_VFS_OP_DISK_FREE,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_get_quota), SMB_VFS_OP_GET_QUOTA,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_set_quota), SMB_VFS_OP_SET_QUOTA,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_get_shadow_copy_data), SMB_VFS_OP_GET_SHADOW_COPY_DATA,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_statvfs), SMB_VFS_OP_STATVFS,
+ SMB_VFS_LAYER_LOGGER},
+
+ /* Directory operations */
+
+ {SMB_VFS_OP(smb_full_audit_opendir), SMB_VFS_OP_OPENDIR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_readdir), SMB_VFS_OP_READDIR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_seekdir), SMB_VFS_OP_SEEKDIR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_telldir), SMB_VFS_OP_TELLDIR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_rewinddir), SMB_VFS_OP_REWINDDIR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_mkdir), SMB_VFS_OP_MKDIR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_rmdir), SMB_VFS_OP_RMDIR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_closedir), SMB_VFS_OP_CLOSEDIR,
+ SMB_VFS_LAYER_LOGGER},
+
+ /* File operations */
+
+ {SMB_VFS_OP(smb_full_audit_open), SMB_VFS_OP_OPEN,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_close), SMB_VFS_OP_CLOSE,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_read), SMB_VFS_OP_READ,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_pread), SMB_VFS_OP_PREAD,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_write), SMB_VFS_OP_WRITE,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_pwrite), SMB_VFS_OP_PWRITE,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_lseek), SMB_VFS_OP_LSEEK,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sendfile), SMB_VFS_OP_SENDFILE,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_recvfile), SMB_VFS_OP_RECVFILE,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_rename), SMB_VFS_OP_RENAME,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_fsync), SMB_VFS_OP_FSYNC,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_stat), SMB_VFS_OP_STAT,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_fstat), SMB_VFS_OP_FSTAT,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_lstat), SMB_VFS_OP_LSTAT,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_unlink), SMB_VFS_OP_UNLINK,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_chmod), SMB_VFS_OP_CHMOD,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_fchmod), SMB_VFS_OP_FCHMOD,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_chown), SMB_VFS_OP_CHOWN,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_fchown), SMB_VFS_OP_FCHOWN,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_lchown), SMB_VFS_OP_LCHOWN,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_chdir), SMB_VFS_OP_CHDIR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_getwd), SMB_VFS_OP_GETWD,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_ntimes), SMB_VFS_OP_NTIMES,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_ftruncate), SMB_VFS_OP_FTRUNCATE,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_lock), SMB_VFS_OP_LOCK,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_kernel_flock), SMB_VFS_OP_KERNEL_FLOCK,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_linux_setlease), SMB_VFS_OP_LINUX_SETLEASE,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_getlock), SMB_VFS_OP_GETLOCK,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_symlink), SMB_VFS_OP_SYMLINK,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_readlink), SMB_VFS_OP_READLINK,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_link), SMB_VFS_OP_LINK,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_mknod), SMB_VFS_OP_MKNOD,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_realpath), SMB_VFS_OP_REALPATH,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_notify_watch),SMB_VFS_OP_NOTIFY_WATCH,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_chflags), SMB_VFS_OP_CHFLAGS,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_file_id_create), SMB_VFS_OP_FILE_ID_CREATE,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_streaminfo), SMB_VFS_OP_STREAMINFO,
+ SMB_VFS_LAYER_LOGGER},
+
+ /* NT ACL operations. */
+
+ {SMB_VFS_OP(smb_full_audit_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_get_nt_acl), SMB_VFS_OP_GET_NT_ACL,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_fset_nt_acl), SMB_VFS_OP_FSET_NT_ACL,
+ SMB_VFS_LAYER_LOGGER},
+
+ /* POSIX ACL operations. */
+
+ {SMB_VFS_OP(smb_full_audit_chmod_acl), SMB_VFS_OP_CHMOD_ACL,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_fchmod_acl), SMB_VFS_OP_FCHMOD_ACL,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_get_entry), SMB_VFS_OP_SYS_ACL_GET_ENTRY,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_get_tag_type), SMB_VFS_OP_SYS_ACL_GET_TAG_TYPE,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_get_permset), SMB_VFS_OP_SYS_ACL_GET_PERMSET,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_get_qualifier), SMB_VFS_OP_SYS_ACL_GET_QUALIFIER,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE,
+ SMB_VFS_LAYER_LOGGER},
+{SMB_VFS_OP(smb_full_audit_sys_acl_get_fd), SMB_VFS_OP_SYS_ACL_GET_FD,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_clear_perms), SMB_VFS_OP_SYS_ACL_CLEAR_PERMS,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_add_perm), SMB_VFS_OP_SYS_ACL_ADD_PERM,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_to_text), SMB_VFS_OP_SYS_ACL_TO_TEXT,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_init), SMB_VFS_OP_SYS_ACL_INIT,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_create_entry), SMB_VFS_OP_SYS_ACL_CREATE_ENTRY,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_set_tag_type), SMB_VFS_OP_SYS_ACL_SET_TAG_TYPE,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_set_qualifier), SMB_VFS_OP_SYS_ACL_SET_QUALIFIER,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_set_permset), SMB_VFS_OP_SYS_ACL_SET_PERMSET,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_valid), SMB_VFS_OP_SYS_ACL_VALID,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_set_file), SMB_VFS_OP_SYS_ACL_SET_FILE,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_set_fd), SMB_VFS_OP_SYS_ACL_SET_FD,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_delete_def_file), SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_get_perm), SMB_VFS_OP_SYS_ACL_GET_PERM,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_free_text), SMB_VFS_OP_SYS_ACL_FREE_TEXT,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_free_acl), SMB_VFS_OP_SYS_ACL_FREE_ACL,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_sys_acl_free_qualifier), SMB_VFS_OP_SYS_ACL_FREE_QUALIFIER,
+ SMB_VFS_LAYER_LOGGER},
+
+ /* EA operations. */
+
+ {SMB_VFS_OP(smb_full_audit_getxattr), SMB_VFS_OP_GETXATTR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_lgetxattr), SMB_VFS_OP_LGETXATTR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_fgetxattr), SMB_VFS_OP_FGETXATTR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_listxattr), SMB_VFS_OP_LISTXATTR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_llistxattr), SMB_VFS_OP_LLISTXATTR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_flistxattr), SMB_VFS_OP_FLISTXATTR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_removexattr), SMB_VFS_OP_REMOVEXATTR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_lremovexattr), SMB_VFS_OP_LREMOVEXATTR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_fremovexattr), SMB_VFS_OP_FREMOVEXATTR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_setxattr), SMB_VFS_OP_SETXATTR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_lsetxattr), SMB_VFS_OP_LSETXATTR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_fsetxattr), SMB_VFS_OP_FSETXATTR,
+ SMB_VFS_LAYER_LOGGER},
+
+ {SMB_VFS_OP(smb_full_audit_aio_read), SMB_VFS_OP_AIO_READ,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_aio_write), SMB_VFS_OP_AIO_WRITE,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_aio_return), SMB_VFS_OP_AIO_RETURN,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_aio_cancel), SMB_VFS_OP_AIO_CANCEL,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_aio_error), SMB_VFS_OP_AIO_ERROR,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_aio_fsync), SMB_VFS_OP_AIO_FSYNC,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_aio_suspend),SMB_VFS_OP_AIO_SUSPEND,
+ SMB_VFS_LAYER_LOGGER},
+
+ /* Finish VFS operations definition */
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP,
+ SMB_VFS_LAYER_NOOP}
+};
+
+/* The following array *must* be in the same order as defined in vfs.h */
+
+static struct {
+ vfs_op_type type;
+ const char *name;
+} vfs_op_names[] = {
+ { SMB_VFS_OP_CONNECT, "connect" },
+ { SMB_VFS_OP_DISCONNECT, "disconnect" },
+ { SMB_VFS_OP_DISK_FREE, "disk_free" },
+ { SMB_VFS_OP_GET_QUOTA, "get_quota" },
+ { SMB_VFS_OP_SET_QUOTA, "set_quota" },
+ { SMB_VFS_OP_GET_SHADOW_COPY_DATA, "get_shadow_copy_data" },
+ { SMB_VFS_OP_STATVFS, "statvfs" },
+ { SMB_VFS_OP_FS_CAPABILITIES, "fs_capabilities" },
+ { SMB_VFS_OP_OPENDIR, "opendir" },
+ { SMB_VFS_OP_READDIR, "readdir" },
+ { SMB_VFS_OP_SEEKDIR, "seekdir" },
+ { SMB_VFS_OP_TELLDIR, "telldir" },
+ { SMB_VFS_OP_REWINDDIR, "rewinddir" },
+ { SMB_VFS_OP_MKDIR, "mkdir" },
+ { SMB_VFS_OP_RMDIR, "rmdir" },
+ { SMB_VFS_OP_CLOSEDIR, "closedir" },
+ { SMB_VFS_OP_OPEN, "open" },
+ { SMB_VFS_OP_CLOSE, "close" },
+ { SMB_VFS_OP_READ, "read" },
+ { SMB_VFS_OP_PREAD, "pread" },
+ { SMB_VFS_OP_WRITE, "write" },
+ { SMB_VFS_OP_PWRITE, "pwrite" },
+ { SMB_VFS_OP_LSEEK, "lseek" },
+ { SMB_VFS_OP_SENDFILE, "sendfile" },
+ { SMB_VFS_OP_RECVFILE, "recvfile" },
+ { SMB_VFS_OP_RENAME, "rename" },
+ { SMB_VFS_OP_FSYNC, "fsync" },
+ { SMB_VFS_OP_STAT, "stat" },
+ { SMB_VFS_OP_FSTAT, "fstat" },
+ { SMB_VFS_OP_LSTAT, "lstat" },
+ { SMB_VFS_OP_UNLINK, "unlink" },
+ { SMB_VFS_OP_CHMOD, "chmod" },
+ { SMB_VFS_OP_FCHMOD, "fchmod" },
+ { SMB_VFS_OP_CHOWN, "chown" },
+ { SMB_VFS_OP_FCHOWN, "fchown" },
+ { SMB_VFS_OP_LCHOWN, "lchown" },
+ { SMB_VFS_OP_CHDIR, "chdir" },
+ { SMB_VFS_OP_GETWD, "getwd" },
+ { SMB_VFS_OP_NTIMES, "ntimes" },
+ { SMB_VFS_OP_FTRUNCATE, "ftruncate" },
+ { SMB_VFS_OP_LOCK, "lock" },
+ { SMB_VFS_OP_KERNEL_FLOCK, "kernel_flock" },
+ { SMB_VFS_OP_LINUX_SETLEASE, "linux_setlease" },
+ { SMB_VFS_OP_GETLOCK, "getlock" },
+ { SMB_VFS_OP_SYMLINK, "symlink" },
+ { SMB_VFS_OP_READLINK, "readlink" },
+ { SMB_VFS_OP_LINK, "link" },
+ { SMB_VFS_OP_MKNOD, "mknod" },
+ { SMB_VFS_OP_REALPATH, "realpath" },
+ { SMB_VFS_OP_NOTIFY_WATCH, "notify_watch" },
+ { SMB_VFS_OP_CHFLAGS, "chflags" },
+ { SMB_VFS_OP_FILE_ID_CREATE, "file_id_create" },
+ { SMB_VFS_OP_STREAMINFO, "streaminfo" },
+ { SMB_VFS_OP_FGET_NT_ACL, "fget_nt_acl" },
+ { SMB_VFS_OP_GET_NT_ACL, "get_nt_acl" },
+ { SMB_VFS_OP_FSET_NT_ACL, "fset_nt_acl" },
+ { SMB_VFS_OP_CHMOD_ACL, "chmod_acl" },
+ { SMB_VFS_OP_FCHMOD_ACL, "fchmod_acl" },
+ { SMB_VFS_OP_SYS_ACL_GET_ENTRY, "sys_acl_get_entry" },
+ { SMB_VFS_OP_SYS_ACL_GET_TAG_TYPE, "sys_acl_get_tag_type" },
+ { SMB_VFS_OP_SYS_ACL_GET_PERMSET, "sys_acl_get_permset" },
+ { SMB_VFS_OP_SYS_ACL_GET_QUALIFIER, "sys_acl_get_qualifier" },
+ { SMB_VFS_OP_SYS_ACL_GET_FILE, "sys_acl_get_file" },
+ { SMB_VFS_OP_SYS_ACL_GET_FD, "sys_acl_get_fd" },
+ { SMB_VFS_OP_SYS_ACL_CLEAR_PERMS, "sys_acl_clear_perms" },
+ { SMB_VFS_OP_SYS_ACL_ADD_PERM, "sys_acl_add_perm" },
+ { SMB_VFS_OP_SYS_ACL_TO_TEXT, "sys_acl_to_text" },
+ { SMB_VFS_OP_SYS_ACL_INIT, "sys_acl_init" },
+ { SMB_VFS_OP_SYS_ACL_CREATE_ENTRY, "sys_acl_create_entry" },
+ { SMB_VFS_OP_SYS_ACL_SET_TAG_TYPE, "sys_acl_set_tag_type" },
+ { SMB_VFS_OP_SYS_ACL_SET_QUALIFIER, "sys_acl_set_qualifier" },
+ { SMB_VFS_OP_SYS_ACL_SET_PERMSET, "sys_acl_set_permset" },
+ { SMB_VFS_OP_SYS_ACL_VALID, "sys_acl_valid" },
+ { SMB_VFS_OP_SYS_ACL_SET_FILE, "sys_acl_set_file" },
+ { SMB_VFS_OP_SYS_ACL_SET_FD, "sys_acl_set_fd" },
+ { SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, "sys_acl_delete_def_file" },
+ { SMB_VFS_OP_SYS_ACL_GET_PERM, "sys_acl_get_perm" },
+ { SMB_VFS_OP_SYS_ACL_FREE_TEXT, "sys_acl_free_text" },
+ { SMB_VFS_OP_SYS_ACL_FREE_ACL, "sys_acl_free_acl" },
+ { SMB_VFS_OP_SYS_ACL_FREE_QUALIFIER, "sys_acl_free_qualifier" },
+ { SMB_VFS_OP_GETXATTR, "getxattr" },
+ { SMB_VFS_OP_LGETXATTR, "lgetxattr" },
+ { SMB_VFS_OP_FGETXATTR, "fgetxattr" },
+ { SMB_VFS_OP_LISTXATTR, "listxattr" },
+ { SMB_VFS_OP_LLISTXATTR, "llistxattr" },
+ { SMB_VFS_OP_FLISTXATTR, "flistxattr" },
+ { SMB_VFS_OP_REMOVEXATTR, "removexattr" },
+ { SMB_VFS_OP_LREMOVEXATTR, "lremovexattr" },
+ { SMB_VFS_OP_FREMOVEXATTR, "fremovexattr" },
+ { SMB_VFS_OP_SETXATTR, "setxattr" },
+ { SMB_VFS_OP_LSETXATTR, "lsetxattr" },
+ { SMB_VFS_OP_FSETXATTR, "fsetxattr" },
+ { SMB_VFS_OP_AIO_READ, "aio_read" },
+ { SMB_VFS_OP_AIO_WRITE, "aio_write" },
+ { SMB_VFS_OP_AIO_RETURN,"aio_return" },
+ { SMB_VFS_OP_AIO_CANCEL,"aio_cancel" },
+ { SMB_VFS_OP_AIO_ERROR, "aio_error" },
+ { SMB_VFS_OP_AIO_FSYNC, "aio_fsync" },
+ { SMB_VFS_OP_AIO_SUSPEND,"aio_suspend" },
+ { SMB_VFS_OP_AIO_FORCE, "aio_force" },
+ { SMB_VFS_OP_IS_OFFLINE, "aio_is_offline" },
+ { SMB_VFS_OP_SET_OFFLINE, "aio_set_offline" },
+ { SMB_VFS_OP_LAST, NULL }
+};
+
+static int audit_syslog_facility(vfs_handle_struct *handle)
+{
+ static const struct enum_list enum_log_facilities[] = {
+ { LOG_USER, "USER" },
+ { LOG_LOCAL0, "LOCAL0" },
+ { LOG_LOCAL1, "LOCAL1" },
+ { LOG_LOCAL2, "LOCAL2" },
+ { LOG_LOCAL3, "LOCAL3" },
+ { LOG_LOCAL4, "LOCAL4" },
+ { LOG_LOCAL5, "LOCAL5" },
+ { LOG_LOCAL6, "LOCAL6" },
+ { LOG_LOCAL7, "LOCAL7" }
+ };
+
+ int facility;
+
+ facility = lp_parm_enum(SNUM(handle->conn), "full_audit", "facility", enum_log_facilities, LOG_USER);
+
+ return facility;
+}
+
+static int audit_syslog_priority(vfs_handle_struct *handle)
+{
+ static const struct enum_list enum_log_priorities[] = {
+ { LOG_EMERG, "EMERG" },
+ { LOG_ALERT, "ALERT" },
+ { LOG_CRIT, "CRIT" },
+ { LOG_ERR, "ERR" },
+ { LOG_WARNING, "WARNING" },
+ { LOG_NOTICE, "NOTICE" },
+ { LOG_INFO, "INFO" },
+ { LOG_DEBUG, "DEBUG" }
+ };
+
+ int priority;
+
+ priority = lp_parm_enum(SNUM(handle->conn), "full_audit", "priority",
+ enum_log_priorities, LOG_NOTICE);
+ if (priority == -1) {
+ priority = LOG_WARNING;
+ }
+
+ return priority;
+}
+
+static char *audit_prefix(TALLOC_CTX *ctx, connection_struct *conn)
+{
+ char *prefix = NULL;
+
+ prefix = talloc_strdup(ctx,
+ lp_parm_const_string(SNUM(conn), "full_audit",
+ "prefix", "%u|%I"));
+ if (!prefix) {
+ return NULL;
+ }
+ return talloc_sub_advanced(ctx,
+ lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name,
+ conn->connectpath,
+ conn->server_info->utok.gid,
+ conn->server_info->sanitized_username,
+ pdb_get_domain(conn->server_info->sam_account),
+ prefix);
+}
+
+static bool log_success(vfs_handle_struct *handle, vfs_op_type op)
+{
+ struct vfs_full_audit_private_data *pd = NULL;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, pd,
+ struct vfs_full_audit_private_data,
+ return True);
+
+ if (pd->success_ops == NULL) {
+ return True;
+ }
+
+ return bitmap_query(pd->success_ops, op);
+}
+
+static bool log_failure(vfs_handle_struct *handle, vfs_op_type op)
+{
+ struct vfs_full_audit_private_data *pd = NULL;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, pd,
+ struct vfs_full_audit_private_data,
+ return True);
+
+ if (pd->failure_ops == NULL)
+ return True;
+
+ return bitmap_query(pd->failure_ops, op);
+}
+
+static void init_bitmap(struct bitmap **bm, const char **ops)
+{
+ bool log_all = False;
+
+ if (*bm != NULL)
+ return;
+
+ *bm = bitmap_allocate(SMB_VFS_OP_LAST);
+
+ if (*bm == NULL) {
+ DEBUG(0, ("Could not alloc bitmap -- "
+ "defaulting to logging everything\n"));
+ return;
+ }
+
+ while (*ops != NULL) {
+ int i;
+ bool found = False;
+
+ if (strequal(*ops, "all")) {
+ log_all = True;
+ break;
+ }
+
+ if (strequal(*ops, "none")) {
+ break;
+ }
+
+ for (i=0; i<SMB_VFS_OP_LAST; i++) {
+ if (vfs_op_names[i].name == NULL) {
+ smb_panic("vfs_full_audit.c: name table not "
+ "in sync with vfs.h\n");
+ }
+
+ if (strequal(*ops, vfs_op_names[i].name)) {
+ bitmap_set(*bm, i);
+ found = True;
+ }
+ }
+ if (!found) {
+ DEBUG(0, ("Could not find opname %s, logging all\n",
+ *ops));
+ log_all = True;
+ break;
+ }
+ ops += 1;
+ }
+
+ if (log_all) {
+ /* The query functions default to True */
+ bitmap_free(*bm);
+ *bm = NULL;
+ }
+}
+
+static const char *audit_opname(vfs_op_type op)
+{
+ if (op >= SMB_VFS_OP_LAST)
+ return "INVALID VFS OP";
+ return vfs_op_names[op].name;
+}
+
+static void do_log(vfs_op_type op, bool success, vfs_handle_struct *handle,
+ const char *format, ...)
+{
+ fstring err_msg;
+ char *audit_pre = NULL;
+ va_list ap;
+ char *op_msg = NULL;
+
+ if (success && (!log_success(handle, op)))
+ return;
+
+ if (!success && (!log_failure(handle, op)))
+ return;
+
+ if (success)
+ fstrcpy(err_msg, "ok");
+ else
+ fstr_sprintf(err_msg, "fail (%s)", strerror(errno));
+
+ va_start(ap, format);
+ op_msg = talloc_vasprintf(NULL, format, ap);
+ va_end(ap);
+
+ if (!op_msg) {
+ return;
+ }
+
+ audit_pre = audit_prefix(NULL, handle->conn);
+ syslog(audit_syslog_priority(handle), "%s|%s|%s|%s\n",
+ audit_pre ? audit_pre : "",
+ audit_opname(op), err_msg, op_msg);
+
+ TALLOC_FREE(audit_pre);
+ TALLOC_FREE(op_msg);
+
+ return;
+}
+
+/* Free function for the private data. */
+
+static void free_private_data(void **p_data)
+{
+ struct vfs_full_audit_private_data *pd = *(struct vfs_full_audit_private_data **)p_data;
+
+ if (pd->success_ops) {
+ bitmap_free(pd->success_ops);
+ }
+ if (pd->failure_ops) {
+ bitmap_free(pd->failure_ops);
+ }
+ SAFE_FREE(pd);
+ *p_data = NULL;
+}
+
+/* Implementation of vfs_ops. Pass everything on to the default
+ operation but log event first. */
+
+static int smb_full_audit_connect(vfs_handle_struct *handle,
+ const char *svc, const char *user)
+{
+ int result;
+ struct vfs_full_audit_private_data *pd = NULL;
+ const char *none[] = { NULL };
+ const char *all [] = { "all" };
+
+ if (!handle) {
+ return -1;
+ }
+
+ pd = SMB_MALLOC_P(struct vfs_full_audit_private_data);
+ if (!pd) {
+ return -1;
+ }
+ ZERO_STRUCTP(pd);
+
+ openlog("smbd_audit", 0, audit_syslog_facility(handle));
+
+ init_bitmap(&pd->success_ops,
+ lp_parm_string_list(SNUM(handle->conn), "full_audit", "success",
+ none));
+ init_bitmap(&pd->failure_ops,
+ lp_parm_string_list(SNUM(handle->conn), "full_audit", "failure",
+ all));
+
+ /* Store the private data. */
+ SMB_VFS_HANDLE_SET_DATA(handle, pd, free_private_data,
+ struct vfs_full_audit_private_data, return -1);
+
+ result = SMB_VFS_NEXT_CONNECT(handle, svc, user);
+
+ do_log(SMB_VFS_OP_CONNECT, True, handle,
+ "%s", svc);
+
+ return result;
+}
+
+static void smb_full_audit_disconnect(vfs_handle_struct *handle)
+{
+ SMB_VFS_NEXT_DISCONNECT(handle);
+
+ do_log(SMB_VFS_OP_DISCONNECT, True, handle,
+ "%s", lp_servicename(SNUM(handle->conn)));
+
+ /* The bitmaps will be disconnected when the private
+ data is deleted. */
+
+ return;
+}
+
+static SMB_BIG_UINT smb_full_audit_disk_free(vfs_handle_struct *handle,
+ const char *path,
+ bool small_query, SMB_BIG_UINT *bsize,
+ SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ SMB_BIG_UINT result;
+
+ result = SMB_VFS_NEXT_DISK_FREE(handle, path, small_query, bsize,
+ dfree, dsize);
+
+ /* Don't have a reasonable notion of failure here */
+
+ do_log(SMB_VFS_OP_DISK_FREE, True, handle, "%s", path);
+
+ return result;
+}
+
+static int smb_full_audit_get_quota(struct vfs_handle_struct *handle,
+ enum SMB_QUOTA_TYPE qtype, unid_t id,
+ SMB_DISK_QUOTA *qt)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_GET_QUOTA(handle, qtype, id, qt);
+
+ do_log(SMB_VFS_OP_GET_QUOTA, (result >= 0), handle, "");
+
+ return result;
+}
+
+
+static int smb_full_audit_set_quota(struct vfs_handle_struct *handle,
+ enum SMB_QUOTA_TYPE qtype, unid_t id,
+ SMB_DISK_QUOTA *qt)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SET_QUOTA(handle, qtype, id, qt);
+
+ do_log(SMB_VFS_OP_SET_QUOTA, (result >= 0), handle, "");
+
+ return result;
+}
+
+static int smb_full_audit_get_shadow_copy_data(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ SHADOW_COPY_DATA *shadow_copy_data, bool labels)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_GET_SHADOW_COPY_DATA(handle, fsp, shadow_copy_data, labels);
+
+ do_log(SMB_VFS_OP_GET_SHADOW_COPY_DATA, (result >= 0), handle, "");
+
+ return result;
+}
+
+static int smb_full_audit_statvfs(struct vfs_handle_struct *handle,
+ const char *path,
+ struct vfs_statvfs_struct *statbuf)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_STATVFS(handle, path, statbuf);
+
+ do_log(SMB_VFS_OP_STATVFS, (result >= 0), handle, "");
+
+ return result;
+}
+
+static SMB_STRUCT_DIR *smb_full_audit_opendir(vfs_handle_struct *handle,
+ const char *fname, const char *mask, uint32 attr)
+{
+ SMB_STRUCT_DIR *result;
+
+ result = SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
+
+ do_log(SMB_VFS_OP_OPENDIR, (result != NULL), handle, "%s", fname);
+
+ return result;
+}
+
+static SMB_STRUCT_DIRENT *smb_full_audit_readdir(vfs_handle_struct *handle,
+ SMB_STRUCT_DIR *dirp)
+{
+ SMB_STRUCT_DIRENT *result;
+
+ result = SMB_VFS_NEXT_READDIR(handle, dirp);
+
+ /* This operation has no reasonable error condition
+ * (End of dir is also failure), so always succeed.
+ */
+ do_log(SMB_VFS_OP_READDIR, True, handle, "");
+
+ return result;
+}
+
+static void smb_full_audit_seekdir(vfs_handle_struct *handle,
+ SMB_STRUCT_DIR *dirp, long offset)
+{
+ SMB_VFS_NEXT_SEEKDIR(handle, dirp, offset);
+
+ do_log(SMB_VFS_OP_SEEKDIR, True, handle, "");
+ return;
+}
+
+static long smb_full_audit_telldir(vfs_handle_struct *handle,
+ SMB_STRUCT_DIR *dirp)
+{
+ long result;
+
+ result = SMB_VFS_NEXT_TELLDIR(handle, dirp);
+
+ do_log(SMB_VFS_OP_TELLDIR, True, handle, "");
+
+ return result;
+}
+
+static void smb_full_audit_rewinddir(vfs_handle_struct *handle,
+ SMB_STRUCT_DIR *dirp)
+{
+ SMB_VFS_NEXT_REWINDDIR(handle, dirp);
+
+ do_log(SMB_VFS_OP_REWINDDIR, True, handle, "");
+ return;
+}
+
+static int smb_full_audit_mkdir(vfs_handle_struct *handle,
+ const char *path, mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_MKDIR(handle, path, mode);
+
+ do_log(SMB_VFS_OP_MKDIR, (result >= 0), handle, "%s", path);
+
+ return result;
+}
+
+static int smb_full_audit_rmdir(vfs_handle_struct *handle,
+ const char *path)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_RMDIR(handle, path);
+
+ do_log(SMB_VFS_OP_RMDIR, (result >= 0), handle, "%s", path);
+
+ return result;
+}
+
+static int smb_full_audit_closedir(vfs_handle_struct *handle,
+ SMB_STRUCT_DIR *dirp)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_CLOSEDIR(handle, dirp);
+
+ do_log(SMB_VFS_OP_CLOSEDIR, (result >= 0), handle, "");
+
+ return result;
+}
+
+static int smb_full_audit_open(vfs_handle_struct *handle,
+ const char *fname, files_struct *fsp, int flags, mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+
+ do_log(SMB_VFS_OP_OPEN, (result >= 0), handle, "%s|%s",
+ ((flags & O_WRONLY) || (flags & O_RDWR))?"w":"r",
+ fname);
+
+ return result;
+}
+
+static int smb_full_audit_close(vfs_handle_struct *handle, files_struct *fsp)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_CLOSE(handle, fsp);
+
+ do_log(SMB_VFS_OP_CLOSE, (result >= 0), handle, "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static ssize_t smb_full_audit_read(vfs_handle_struct *handle, files_struct *fsp,
+ void *data, size_t n)
+{
+ ssize_t result;
+
+ result = SMB_VFS_NEXT_READ(handle, fsp, data, n);
+
+ do_log(SMB_VFS_OP_READ, (result >= 0), handle, "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static ssize_t smb_full_audit_pread(vfs_handle_struct *handle, files_struct *fsp,
+ void *data, size_t n, SMB_OFF_T offset)
+{
+ ssize_t result;
+
+ result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
+
+ do_log(SMB_VFS_OP_PREAD, (result >= 0), handle, "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static ssize_t smb_full_audit_write(vfs_handle_struct *handle, files_struct *fsp,
+ const void *data, size_t n)
+{
+ ssize_t result;
+
+ result = SMB_VFS_NEXT_WRITE(handle, fsp, data, n);
+
+ do_log(SMB_VFS_OP_WRITE, (result >= 0), handle, "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static ssize_t smb_full_audit_pwrite(vfs_handle_struct *handle, files_struct *fsp,
+ const void *data, size_t n,
+ SMB_OFF_T offset)
+{
+ ssize_t result;
+
+ result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+
+ do_log(SMB_VFS_OP_PWRITE, (result >= 0), handle, "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static SMB_OFF_T smb_full_audit_lseek(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_OFF_T offset, int whence)
+{
+ ssize_t result;
+
+ result = SMB_VFS_NEXT_LSEEK(handle, fsp, offset, whence);
+
+ do_log(SMB_VFS_OP_LSEEK, (result != (ssize_t)-1), handle,
+ "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static ssize_t smb_full_audit_sendfile(vfs_handle_struct *handle, int tofd,
+ files_struct *fromfsp,
+ const DATA_BLOB *hdr, SMB_OFF_T offset,
+ size_t n)
+{
+ ssize_t result;
+
+ result = SMB_VFS_NEXT_SENDFILE(handle, tofd, fromfsp, hdr, offset, n);
+
+ do_log(SMB_VFS_OP_SENDFILE, (result >= 0), handle,
+ "%s", fromfsp->fsp_name);
+
+ return result;
+}
+
+static ssize_t smb_full_audit_recvfile(vfs_handle_struct *handle, int fromfd,
+ files_struct *tofsp,
+ SMB_OFF_T offset,
+ size_t n)
+{
+ ssize_t result;
+
+ result = SMB_VFS_NEXT_RECVFILE(handle, fromfd, tofsp, offset, n);
+
+ do_log(SMB_VFS_OP_RECVFILE, (result >= 0), handle,
+ "%s", tofsp->fsp_name);
+
+ return result;
+}
+
+static int smb_full_audit_rename(vfs_handle_struct *handle,
+ const char *oldname, const char *newname)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_RENAME(handle, oldname, newname);
+
+ do_log(SMB_VFS_OP_RENAME, (result >= 0), handle, "%s|%s", oldname, newname);
+
+ return result;
+}
+
+static int smb_full_audit_fsync(vfs_handle_struct *handle, files_struct *fsp)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_FSYNC(handle, fsp);
+
+ do_log(SMB_VFS_OP_FSYNC, (result >= 0), handle, "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static int smb_full_audit_stat(vfs_handle_struct *handle,
+ const char *fname, SMB_STRUCT_STAT *sbuf)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_STAT(handle, fname, sbuf);
+
+ do_log(SMB_VFS_OP_STAT, (result >= 0), handle, "%s", fname);
+
+ return result;
+}
+
+static int smb_full_audit_fstat(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_STRUCT_STAT *sbuf)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+
+ do_log(SMB_VFS_OP_FSTAT, (result >= 0), handle, "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static int smb_full_audit_lstat(vfs_handle_struct *handle,
+ const char *path, SMB_STRUCT_STAT *sbuf)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_LSTAT(handle, path, sbuf);
+
+ do_log(SMB_VFS_OP_LSTAT, (result >= 0), handle, "%s", path);
+
+ return result;
+}
+
+static int smb_full_audit_unlink(vfs_handle_struct *handle,
+ const char *path)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_UNLINK(handle, path);
+
+ do_log(SMB_VFS_OP_UNLINK, (result >= 0), handle, "%s", path);
+
+ return result;
+}
+
+static int smb_full_audit_chmod(vfs_handle_struct *handle,
+ const char *path, mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_CHMOD(handle, path, mode);
+
+ do_log(SMB_VFS_OP_CHMOD, (result >= 0), handle, "%s|%o", path, mode);
+
+ return result;
+}
+
+static int smb_full_audit_fchmod(vfs_handle_struct *handle, files_struct *fsp,
+ mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
+
+ do_log(SMB_VFS_OP_FCHMOD, (result >= 0), handle,
+ "%s|%o", fsp->fsp_name, mode);
+
+ return result;
+}
+
+static int smb_full_audit_chown(vfs_handle_struct *handle,
+ const char *path, uid_t uid, gid_t gid)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_CHOWN(handle, path, uid, gid);
+
+ do_log(SMB_VFS_OP_CHOWN, (result >= 0), handle, "%s|%ld|%ld",
+ path, (long int)uid, (long int)gid);
+
+ return result;
+}
+
+static int smb_full_audit_fchown(vfs_handle_struct *handle, files_struct *fsp,
+ uid_t uid, gid_t gid)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid);
+
+ do_log(SMB_VFS_OP_FCHOWN, (result >= 0), handle, "%s|%ld|%ld",
+ fsp->fsp_name, (long int)uid, (long int)gid);
+
+ return result;
+}
+
+static int smb_full_audit_lchown(vfs_handle_struct *handle,
+ const char *path, uid_t uid, gid_t gid)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid);
+
+ do_log(SMB_VFS_OP_LCHOWN, (result >= 0), handle, "%s|%ld|%ld",
+ path, (long int)uid, (long int)gid);
+
+ return result;
+}
+
+static int smb_full_audit_chdir(vfs_handle_struct *handle,
+ const char *path)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_CHDIR(handle, path);
+
+ do_log(SMB_VFS_OP_CHDIR, (result >= 0), handle, "chdir|%s", path);
+
+ return result;
+}
+
+static char *smb_full_audit_getwd(vfs_handle_struct *handle,
+ char *path)
+{
+ char *result;
+
+ result = SMB_VFS_NEXT_GETWD(handle, path);
+
+ do_log(SMB_VFS_OP_GETWD, (result != NULL), handle, "%s", path);
+
+ return result;
+}
+
+static int smb_full_audit_ntimes(vfs_handle_struct *handle,
+ const char *path, const struct timespec ts[2])
+{
+ int result;
+
+ result = SMB_VFS_NEXT_NTIMES(handle, path, ts);
+
+ do_log(SMB_VFS_OP_NTIMES, (result >= 0), handle, "%s", path);
+
+ return result;
+}
+
+static int smb_full_audit_ftruncate(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_OFF_T len)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len);
+
+ do_log(SMB_VFS_OP_FTRUNCATE, (result >= 0), handle,
+ "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static bool smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp,
+ int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
+{
+ bool result;
+
+ result = SMB_VFS_NEXT_LOCK(handle, fsp, op, offset, count, type);
+
+ do_log(SMB_VFS_OP_LOCK, result, handle, "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static int smb_full_audit_kernel_flock(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32 share_mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_KERNEL_FLOCK(handle, fsp, share_mode);
+
+ do_log(SMB_VFS_OP_KERNEL_FLOCK, (result >= 0), handle, "%s",
+ fsp->fsp_name);
+
+ return result;
+}
+
+static int smb_full_audit_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
+ int leasetype)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, leasetype);
+
+ do_log(SMB_VFS_OP_LINUX_SETLEASE, (result >= 0), handle, "%s",
+ fsp->fsp_name);
+
+ return result;
+}
+
+static bool smb_full_audit_getlock(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
+{
+ bool result;
+
+ result = SMB_VFS_NEXT_GETLOCK(handle, fsp, poffset, pcount, ptype, ppid);
+
+ do_log(SMB_VFS_OP_GETLOCK, result, handle, "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static int smb_full_audit_symlink(vfs_handle_struct *handle,
+ const char *oldpath, const char *newpath)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath);
+
+ do_log(SMB_VFS_OP_SYMLINK, (result >= 0), handle,
+ "%s|%s", oldpath, newpath);
+
+ return result;
+}
+
+static int smb_full_audit_readlink(vfs_handle_struct *handle,
+ const char *path, char *buf, size_t bufsiz)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_READLINK(handle, path, buf, bufsiz);
+
+ do_log(SMB_VFS_OP_READLINK, (result >= 0), handle, "%s", path);
+
+ return result;
+}
+
+static int smb_full_audit_link(vfs_handle_struct *handle,
+ const char *oldpath, const char *newpath)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_LINK(handle, oldpath, newpath);
+
+ do_log(SMB_VFS_OP_LINK, (result >= 0), handle,
+ "%s|%s", oldpath, newpath);
+
+ return result;
+}
+
+static int smb_full_audit_mknod(vfs_handle_struct *handle,
+ const char *pathname, mode_t mode, SMB_DEV_T dev)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_MKNOD(handle, pathname, mode, dev);
+
+ do_log(SMB_VFS_OP_MKNOD, (result >= 0), handle, "%s", pathname);
+
+ return result;
+}
+
+static char *smb_full_audit_realpath(vfs_handle_struct *handle,
+ const char *path, char *resolved_path)
+{
+ char *result;
+
+ result = SMB_VFS_NEXT_REALPATH(handle, path, resolved_path);
+
+ do_log(SMB_VFS_OP_REALPATH, (result != NULL), handle, "%s", path);
+
+ return result;
+}
+
+static NTSTATUS smb_full_audit_notify_watch(struct vfs_handle_struct *handle,
+ struct sys_notify_context *ctx,
+ struct notify_entry *e,
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev),
+ void *private_data, void *handle_p)
+{
+ NTSTATUS result;
+
+ result = SMB_VFS_NEXT_NOTIFY_WATCH(handle, ctx, e, callback, private_data, handle_p);
+
+ do_log(SMB_VFS_OP_NOTIFY_WATCH, NT_STATUS_IS_OK(result), handle, "");
+
+ return result;
+}
+
+static int smb_full_audit_chflags(vfs_handle_struct *handle,
+ const char *path, unsigned int flags)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_CHFLAGS(handle, path, flags);
+
+ do_log(SMB_VFS_OP_CHFLAGS, (result != 0), handle, "%s", path);
+
+ return result;
+}
+
+static struct file_id smb_full_audit_file_id_create(struct vfs_handle_struct *handle,
+ SMB_DEV_T dev, SMB_INO_T inode)
+{
+ struct file_id id_zero;
+ struct file_id result;
+
+ ZERO_STRUCT(id_zero);
+
+ result = SMB_VFS_NEXT_FILE_ID_CREATE(handle, dev, inode);
+
+ do_log(SMB_VFS_OP_FILE_ID_CREATE,
+ !file_id_equal(&id_zero, &result),
+ handle, "%s", file_id_string_tos(&result));
+
+ return result;
+}
+
+static NTSTATUS smb_full_audit_streaminfo(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *fname,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *pnum_streams,
+ struct stream_struct **pstreams)
+{
+ NTSTATUS result;
+
+ result = SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname, mem_ctx,
+ pnum_streams, pstreams);
+
+ do_log(SMB_VFS_OP_STREAMINFO, NT_STATUS_IS_OK(result), handle,
+ "%s", fname);
+
+ return result;
+}
+
+static NTSTATUS smb_full_audit_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
+ uint32 security_info,
+ SEC_DESC **ppdesc)
+{
+ NTSTATUS result;
+
+ result = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, ppdesc);
+
+ do_log(SMB_VFS_OP_FGET_NT_ACL, NT_STATUS_IS_OK(result), handle,
+ "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static NTSTATUS smb_full_audit_get_nt_acl(vfs_handle_struct *handle,
+ const char *name,
+ uint32 security_info,
+ SEC_DESC **ppdesc)
+{
+ NTSTATUS result;
+
+ result = SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info, ppdesc);
+
+ do_log(SMB_VFS_OP_GET_NT_ACL, NT_STATUS_IS_OK(result), handle,
+ "%s", name);
+
+ return result;
+}
+
+static NTSTATUS smb_full_audit_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
+ uint32 security_info_sent,
+ SEC_DESC *psd)
+{
+ NTSTATUS result;
+
+ result = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
+
+ do_log(SMB_VFS_OP_FSET_NT_ACL, NT_STATUS_IS_OK(result), handle, "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static int smb_full_audit_chmod_acl(vfs_handle_struct *handle,
+ const char *path, mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_CHMOD_ACL(handle, path, mode);
+
+ do_log(SMB_VFS_OP_CHMOD_ACL, (result >= 0), handle,
+ "%s|%o", path, mode);
+
+ return result;
+}
+
+static int smb_full_audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp,
+ mode_t mode)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
+
+ do_log(SMB_VFS_OP_FCHMOD_ACL, (result >= 0), handle,
+ "%s|%o", fsp->fsp_name, mode);
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_get_entry(vfs_handle_struct *handle,
+
+ SMB_ACL_T theacl, int entry_id,
+ SMB_ACL_ENTRY_T *entry_p)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_GET_ENTRY(handle, theacl, entry_id,
+ entry_p);
+
+ do_log(SMB_VFS_OP_SYS_ACL_GET_ENTRY, (result >= 0), handle,
+ "");
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_get_tag_type(vfs_handle_struct *handle,
+
+ SMB_ACL_ENTRY_T entry_d,
+ SMB_ACL_TAG_T *tag_type_p)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_GET_TAG_TYPE(handle, entry_d,
+ tag_type_p);
+
+ do_log(SMB_VFS_OP_SYS_ACL_GET_TAG_TYPE, (result >= 0), handle,
+ "");
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_get_permset(vfs_handle_struct *handle,
+
+ SMB_ACL_ENTRY_T entry_d,
+ SMB_ACL_PERMSET_T *permset_p)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_GET_PERMSET(handle, entry_d,
+ permset_p);
+
+ do_log(SMB_VFS_OP_SYS_ACL_GET_PERMSET, (result >= 0), handle,
+ "");
+
+ return result;
+}
+
+static void * smb_full_audit_sys_acl_get_qualifier(vfs_handle_struct *handle,
+
+ SMB_ACL_ENTRY_T entry_d)
+{
+ void *result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_GET_QUALIFIER(handle, entry_d);
+
+ do_log(SMB_VFS_OP_SYS_ACL_GET_QUALIFIER, (result != NULL), handle,
+ "");
+
+ return result;
+}
+
+static SMB_ACL_T smb_full_audit_sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ SMB_ACL_TYPE_T type)
+{
+ SMB_ACL_T result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, path_p, type);
+
+ do_log(SMB_VFS_OP_SYS_ACL_GET_FILE, (result != NULL), handle,
+ "%s", path_p);
+
+ return result;
+}
+
+static SMB_ACL_T smb_full_audit_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp)
+{
+ SMB_ACL_T result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp);
+
+ do_log(SMB_VFS_OP_SYS_ACL_GET_FD, (result != NULL), handle,
+ "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_clear_perms(vfs_handle_struct *handle,
+
+ SMB_ACL_PERMSET_T permset)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_CLEAR_PERMS(handle, permset);
+
+ do_log(SMB_VFS_OP_SYS_ACL_CLEAR_PERMS, (result >= 0), handle,
+ "");
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_add_perm(vfs_handle_struct *handle,
+
+ SMB_ACL_PERMSET_T permset,
+ SMB_ACL_PERM_T perm)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_ADD_PERM(handle, permset, perm);
+
+ do_log(SMB_VFS_OP_SYS_ACL_ADD_PERM, (result >= 0), handle,
+ "");
+
+ return result;
+}
+
+static char * smb_full_audit_sys_acl_to_text(vfs_handle_struct *handle,
+ SMB_ACL_T theacl,
+ ssize_t *plen)
+{
+ char * result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_TO_TEXT(handle, theacl, plen);
+
+ do_log(SMB_VFS_OP_SYS_ACL_TO_TEXT, (result != NULL), handle,
+ "");
+
+ return result;
+}
+
+static SMB_ACL_T smb_full_audit_sys_acl_init(vfs_handle_struct *handle,
+
+ int count)
+{
+ SMB_ACL_T result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_INIT(handle, count);
+
+ do_log(SMB_VFS_OP_SYS_ACL_INIT, (result != NULL), handle,
+ "");
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_create_entry(vfs_handle_struct *handle,
+ SMB_ACL_T *pacl,
+ SMB_ACL_ENTRY_T *pentry)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_CREATE_ENTRY(handle, pacl, pentry);
+
+ do_log(SMB_VFS_OP_SYS_ACL_CREATE_ENTRY, (result >= 0), handle,
+ "");
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_set_tag_type(vfs_handle_struct *handle,
+
+ SMB_ACL_ENTRY_T entry,
+ SMB_ACL_TAG_T tagtype)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_SET_TAG_TYPE(handle, entry,
+ tagtype);
+
+ do_log(SMB_VFS_OP_SYS_ACL_SET_TAG_TYPE, (result >= 0), handle,
+ "");
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_set_qualifier(vfs_handle_struct *handle,
+
+ SMB_ACL_ENTRY_T entry,
+ void *qual)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_SET_QUALIFIER(handle, entry, qual);
+
+ do_log(SMB_VFS_OP_SYS_ACL_SET_QUALIFIER, (result >= 0), handle,
+ "");
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_set_permset(vfs_handle_struct *handle,
+
+ SMB_ACL_ENTRY_T entry,
+ SMB_ACL_PERMSET_T permset)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_SET_PERMSET(handle, entry, permset);
+
+ do_log(SMB_VFS_OP_SYS_ACL_SET_PERMSET, (result >= 0), handle,
+ "");
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_valid(vfs_handle_struct *handle,
+
+ SMB_ACL_T theacl )
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_VALID(handle, theacl);
+
+ do_log(SMB_VFS_OP_SYS_ACL_VALID, (result >= 0), handle,
+ "");
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_set_file(vfs_handle_struct *handle,
+
+ const char *name, SMB_ACL_TYPE_T acltype,
+ SMB_ACL_T theacl)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, name, acltype,
+ theacl);
+
+ do_log(SMB_VFS_OP_SYS_ACL_SET_FILE, (result >= 0), handle,
+ "%s", name);
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_ACL_T theacl)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, theacl);
+
+ do_log(SMB_VFS_OP_SYS_ACL_SET_FD, (result >= 0), handle,
+ "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_delete_def_file(vfs_handle_struct *handle,
+
+ const char *path)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, path);
+
+ do_log(SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, (result >= 0), handle,
+ "%s", path);
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_get_perm(vfs_handle_struct *handle,
+
+ SMB_ACL_PERMSET_T permset,
+ SMB_ACL_PERM_T perm)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_GET_PERM(handle, permset, perm);
+
+ do_log(SMB_VFS_OP_SYS_ACL_GET_PERM, (result >= 0), handle,
+ "");
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_free_text(vfs_handle_struct *handle,
+
+ char *text)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_FREE_TEXT(handle, text);
+
+ do_log(SMB_VFS_OP_SYS_ACL_FREE_TEXT, (result >= 0), handle,
+ "");
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_free_acl(vfs_handle_struct *handle,
+
+ SMB_ACL_T posix_acl)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_FREE_ACL(handle, posix_acl);
+
+ do_log(SMB_VFS_OP_SYS_ACL_FREE_ACL, (result >= 0), handle,
+ "");
+
+ return result;
+}
+
+static int smb_full_audit_sys_acl_free_qualifier(vfs_handle_struct *handle,
+ void *qualifier,
+ SMB_ACL_TAG_T tagtype)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SYS_ACL_FREE_QUALIFIER(handle, qualifier,
+ tagtype);
+
+ do_log(SMB_VFS_OP_SYS_ACL_FREE_QUALIFIER, (result >= 0), handle,
+ "");
+
+ return result;
+}
+
+static ssize_t smb_full_audit_getxattr(struct vfs_handle_struct *handle,
+ const char *path,
+ const char *name, void *value, size_t size)
+{
+ ssize_t result;
+
+ result = SMB_VFS_NEXT_GETXATTR(handle, path, name, value, size);
+
+ do_log(SMB_VFS_OP_GETXATTR, (result >= 0), handle,
+ "%s|%s", path, name);
+
+ return result;
+}
+
+static ssize_t smb_full_audit_lgetxattr(struct vfs_handle_struct *handle,
+ const char *path, const char *name,
+ void *value, size_t size)
+{
+ ssize_t result;
+
+ result = SMB_VFS_NEXT_LGETXATTR(handle, path, name, value, size);
+
+ do_log(SMB_VFS_OP_LGETXATTR, (result >= 0), handle,
+ "%s|%s", path, name);
+
+ return result;
+}
+
+static ssize_t smb_full_audit_fgetxattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *name, void *value, size_t size)
+{
+ ssize_t result;
+
+ result = SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, value, size);
+
+ do_log(SMB_VFS_OP_FGETXATTR, (result >= 0), handle,
+ "%s|%s", fsp->fsp_name, name);
+
+ return result;
+}
+
+static ssize_t smb_full_audit_listxattr(struct vfs_handle_struct *handle,
+ const char *path, char *list, size_t size)
+{
+ ssize_t result;
+
+ result = SMB_VFS_NEXT_LISTXATTR(handle, path, list, size);
+
+ do_log(SMB_VFS_OP_LISTXATTR, (result >= 0), handle, "%s", path);
+
+ return result;
+}
+
+static ssize_t smb_full_audit_llistxattr(struct vfs_handle_struct *handle,
+ const char *path, char *list, size_t size)
+{
+ ssize_t result;
+
+ result = SMB_VFS_NEXT_LLISTXATTR(handle, path, list, size);
+
+ do_log(SMB_VFS_OP_LLISTXATTR, (result >= 0), handle, "%s", path);
+
+ return result;
+}
+
+static ssize_t smb_full_audit_flistxattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, char *list,
+ size_t size)
+{
+ ssize_t result;
+
+ result = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, list, size);
+
+ do_log(SMB_VFS_OP_FLISTXATTR, (result >= 0), handle,
+ "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static int smb_full_audit_removexattr(struct vfs_handle_struct *handle,
+ const char *path,
+ const char *name)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
+
+ do_log(SMB_VFS_OP_REMOVEXATTR, (result >= 0), handle,
+ "%s|%s", path, name);
+
+ return result;
+}
+
+static int smb_full_audit_lremovexattr(struct vfs_handle_struct *handle,
+ const char *path,
+ const char *name)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_LREMOVEXATTR(handle, path, name);
+
+ do_log(SMB_VFS_OP_LREMOVEXATTR, (result >= 0), handle,
+ "%s|%s", path, name);
+
+ return result;
+}
+
+static int smb_full_audit_fremovexattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *name)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, name);
+
+ do_log(SMB_VFS_OP_FREMOVEXATTR, (result >= 0), handle,
+ "%s|%s", fsp->fsp_name, name);
+
+ return result;
+}
+
+static int smb_full_audit_setxattr(struct vfs_handle_struct *handle,
+ const char *path,
+ const char *name, const void *value, size_t size,
+ int flags)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_SETXATTR(handle, path, name, value, size,
+ flags);
+
+ do_log(SMB_VFS_OP_SETXATTR, (result >= 0), handle,
+ "%s|%s", path, name);
+
+ return result;
+}
+
+static int smb_full_audit_lsetxattr(struct vfs_handle_struct *handle,
+ const char *path,
+ const char *name, const void *value, size_t size,
+ int flags)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_LSETXATTR(handle, path, name, value, size,
+ flags);
+
+ do_log(SMB_VFS_OP_LSETXATTR, (result >= 0), handle,
+ "%s|%s", path, name);
+
+ return result;
+}
+
+static int smb_full_audit_fsetxattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, const char *name,
+ const void *value, size_t size, int flags)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, value, size, flags);
+
+ do_log(SMB_VFS_OP_FSETXATTR, (result >= 0), handle,
+ "%s|%s", fsp->fsp_name, name);
+
+ return result;
+}
+
+static int smb_full_audit_aio_read(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_AIO_READ(handle, fsp, aiocb);
+ do_log(SMB_VFS_OP_AIO_READ, (result >= 0), handle,
+ "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static int smb_full_audit_aio_write(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_AIO_WRITE(handle, fsp, aiocb);
+ do_log(SMB_VFS_OP_AIO_WRITE, (result >= 0), handle,
+ "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static ssize_t smb_full_audit_aio_return(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_AIO_RETURN(handle, fsp, aiocb);
+ do_log(SMB_VFS_OP_AIO_RETURN, (result >= 0), handle,
+ "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static int smb_full_audit_aio_cancel(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_AIO_CANCEL(handle, fsp, aiocb);
+ do_log(SMB_VFS_OP_AIO_CANCEL, (result >= 0), handle,
+ "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static int smb_full_audit_aio_error(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_AIO_ERROR(handle, fsp, aiocb);
+ do_log(SMB_VFS_OP_AIO_ERROR, (result >= 0), handle,
+ "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static int smb_full_audit_aio_fsync(struct vfs_handle_struct *handle, struct files_struct *fsp, int op, SMB_STRUCT_AIOCB *aiocb)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_AIO_FSYNC(handle, fsp, op, aiocb);
+ do_log(SMB_VFS_OP_AIO_FSYNC, (result >= 0), handle,
+ "%s", fsp->fsp_name);
+
+ return result;
+}
+
+static int smb_full_audit_aio_suspend(struct vfs_handle_struct *handle, struct files_struct *fsp, const SMB_STRUCT_AIOCB * const aiocb[], int n, const struct timespec *ts)
+{
+ int result;
+
+ result = SMB_VFS_NEXT_AIO_SUSPEND(handle, fsp, aiocb, n, ts);
+ do_log(SMB_VFS_OP_AIO_SUSPEND, (result >= 0), handle,
+ "%s", fsp->fsp_name);
+
+ return result;
+}
+
+
+NTSTATUS vfs_full_audit_init(void);
+NTSTATUS vfs_full_audit_init(void)
+{
+ NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
+ "full_audit", audit_op_tuples);
+
+ if (!NT_STATUS_IS_OK(ret))
+ return ret;
+
+ vfs_full_audit_debug_level = debug_add_class("full_audit");
+ if (vfs_full_audit_debug_level == -1) {
+ vfs_full_audit_debug_level = DBGC_VFS;
+ DEBUG(0, ("vfs_full_audit: Couldn't register custom debugging "
+ "class!\n"));
+ } else {
+ DEBUG(10, ("vfs_full_audit: Debug class number of "
+ "'full_audit': %d\n", vfs_full_audit_debug_level));
+ }
+
+ return ret;
+}
diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c
new file mode 100644
index 0000000000..39d2bb6c38
--- /dev/null
+++ b/source3/modules/vfs_gpfs.c
@@ -0,0 +1,877 @@
+/*
+ Unix SMB/CIFS implementation.
+ Wrap gpfs calls in vfs functions.
+
+ Copyright (C) Christian Ambach <cambach1@de.ibm.com> 2006
+
+ Major code contributions by Chetan Shringarpure <chetan.sh@in.ibm.com>
+ and Gomati Mohanan <gomati.mohanan@in.ibm.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+#include <gpfs_gpl.h>
+#include "nfs4_acls.h"
+#include "vfs_gpfs.h"
+
+static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
+ uint32 share_mode)
+{
+
+ START_PROFILE(syscall_kernel_flock);
+
+ kernel_flock(fsp->fh->fd, share_mode);
+
+ if (!set_gpfs_sharemode(fsp, fsp->access_mask, fsp->share_access)) {
+
+ return -1;
+
+ }
+
+ END_PROFILE(syscall_kernel_flock);
+
+ return 0;
+}
+
+static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp,
+ int leasetype)
+{
+ int ret;
+
+ START_PROFILE(syscall_linux_setlease);
+
+ if ( linux_set_lease_sighandler(fsp->fh->fd) == -1)
+ return -1;
+
+ ret = set_gpfs_lease(fsp->fh->fd,leasetype);
+
+ if ( ret < 0 ) {
+ /* This must have come from GPFS not being available */
+ /* or some other error, hence call the default */
+ ret = linux_setlease(fsp->fh->fd, leasetype);
+ }
+
+ END_PROFILE(syscall_linux_setlease);
+
+ return ret;
+}
+
+
+
+static void gpfs_dumpacl(int level, struct gpfs_acl *gacl)
+{
+ int i;
+ if (gacl==NULL)
+ {
+ DEBUG(0, ("gpfs acl is NULL\n"));
+ return;
+ }
+
+ DEBUG(level, ("gpfs acl: nace: %d, type:%d, version:%d, level:%d, len:%d\n",
+ gacl->acl_nace, gacl->acl_type, gacl->acl_version, gacl->acl_level, gacl->acl_len));
+ for(i=0; i<gacl->acl_nace; i++)
+ {
+ struct gpfs_ace_v4 *gace = gacl->ace_v4 + i;
+ DEBUG(level, ("\tace[%d]: type:%d, flags:0x%x, mask:0x%x, iflags:0x%x, who:%u\n",
+ i, gace->aceType, gace->aceFlags, gace->aceMask,
+ gace->aceIFlags, gace->aceWho));
+ }
+}
+
+static struct gpfs_acl *gpfs_getacl_alloc(const char *fname, gpfs_aclType_t type)
+{
+ struct gpfs_acl *acl;
+ size_t len = 200;
+ int ret;
+ TALLOC_CTX *mem_ctx = talloc_tos();
+
+ acl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, len);
+ if (acl == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ acl->acl_len = len;
+ acl->acl_level = 0;
+ acl->acl_version = 0;
+ acl->acl_type = type;
+
+ ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT | GPFS_ACL_SAMBA, acl);
+ if ((ret != 0) && (errno == ENOSPC)) {
+ struct gpfs_acl *new_acl = (struct gpfs_acl *)TALLOC_SIZE(
+ mem_ctx, acl->acl_len + sizeof(struct gpfs_acl));
+ if (new_acl == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ new_acl->acl_len = acl->acl_len;
+ new_acl->acl_level = acl->acl_level;
+ new_acl->acl_version = acl->acl_version;
+ new_acl->acl_type = acl->acl_type;
+ acl = new_acl;
+
+ ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT | GPFS_ACL_SAMBA, acl);
+ }
+ if (ret != 0)
+ {
+ DEBUG(8, ("smbd_gpfs_getacl failed with %s\n",strerror(errno)));
+ return NULL;
+ }
+
+ return acl;
+}
+
+/* Tries to get nfs4 acls and returns SMB ACL allocated.
+ * On failure returns 1 if it got non-NFSv4 ACL to prompt
+ * retry with POSIX ACL checks.
+ * On failure returns -1 if there is system (GPFS) error, check errno.
+ * Returns 0 on success
+ */
+static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl)
+{
+ int i;
+ struct gpfs_acl *gacl = NULL;
+ DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname));
+
+ /* First get the real acl length */
+ gacl = gpfs_getacl_alloc(fname, 0);
+ if (gacl == NULL) {
+ DEBUG(9, ("gpfs_getacl failed for %s with %s\n",
+ fname, strerror(errno)));
+ return -1;
+ }
+
+ if (gacl->acl_type != GPFS_ACL_TYPE_NFS4) {
+ DEBUG(10, ("Got non-nfsv4 acl\n"));
+ /* Retry with POSIX ACLs check */
+ return 1;
+ }
+
+ *ppacl = smb_create_smb4acl();
+
+ DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
+ gacl->acl_len, gacl->acl_level, gacl->acl_version,
+ gacl->acl_nace));
+
+ for (i=0; i<gacl->acl_nace; i++) {
+ struct gpfs_ace_v4 *gace = &gacl->ace_v4[i];
+ SMB_ACE4PROP_T smbace;
+ DEBUG(10, ("type: %d, iflags: %x, flags: %x, mask: %x, "
+ "who: %d\n", gace->aceType, gace->aceIFlags,
+ gace->aceFlags, gace->aceMask, gace->aceWho));
+
+ memset(&smbace, 0, sizeof(SMB4ACE_T));
+ if (gace->aceIFlags & ACE4_IFLAG_SPECIAL_ID) {
+ smbace.flags |= SMB_ACE4_ID_SPECIAL;
+ switch (gace->aceWho) {
+ case ACE4_SPECIAL_OWNER:
+ smbace.who.special_id = SMB_ACE4_WHO_OWNER;
+ break;
+ case ACE4_SPECIAL_GROUP:
+ smbace.who.special_id = SMB_ACE4_WHO_GROUP;
+ break;
+ case ACE4_SPECIAL_EVERYONE:
+ smbace.who.special_id = SMB_ACE4_WHO_EVERYONE;
+ break;
+ default:
+ DEBUG(8, ("invalid special gpfs id %d "
+ "ignored\n", gace->aceWho));
+ continue; /* don't add it */
+ }
+ } else {
+ if (gace->aceFlags & ACE4_FLAG_GROUP_ID)
+ smbace.who.gid = gace->aceWho;
+ else
+ smbace.who.uid = gace->aceWho;
+ }
+
+ /* remove redundent deny entries */
+ if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) {
+ struct gpfs_ace_v4 *prev = &gacl->ace_v4[i-1];
+ if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE &&
+ prev->aceFlags == gace->aceFlags &&
+ prev->aceIFlags == gace->aceIFlags &&
+ (gace->aceMask & prev->aceMask) == 0 &&
+ gace->aceWho == prev->aceWho) {
+ /* its redundent - skip it */
+ continue;
+ }
+ }
+
+ smbace.aceType = gace->aceType;
+ smbace.aceFlags = gace->aceFlags;
+ smbace.aceMask = gace->aceMask;
+ smb_add_ace4(*ppacl, &smbace);
+ }
+
+ return 0;
+}
+
+static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
+ files_struct *fsp, uint32 security_info,
+ SEC_DESC **ppdesc)
+{
+ SMB4ACL_T *pacl = NULL;
+ int result;
+
+ *ppdesc = NULL;
+ result = gpfs_get_nfs4_acl(fsp->fsp_name, &pacl);
+
+ if (result == 0)
+ return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
+
+ if (result > 0) {
+ DEBUG(10, ("retrying with posix acl...\n"));
+ return posix_fget_nt_acl(fsp, security_info, ppdesc);
+ }
+
+ /* GPFS ACL was not read, something wrong happened, error code is set in errno */
+ return map_nt_error_from_unix(errno);
+}
+
+static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
+ const char *name,
+ uint32 security_info, SEC_DESC **ppdesc)
+{
+ SMB4ACL_T *pacl = NULL;
+ int result;
+
+ *ppdesc = NULL;
+ result = gpfs_get_nfs4_acl(name, &pacl);
+
+ if (result == 0)
+ return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc, pacl);
+
+ if (result > 0) {
+ DEBUG(10, ("retrying with posix acl...\n"));
+ return posix_get_nt_acl(handle->conn, name, security_info, ppdesc);
+ }
+
+ /* GPFS ACL was not read, something wrong happened, error code is set in errno */
+ return map_nt_error_from_unix(errno);
+}
+
+static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
+{
+ int ret;
+ gpfs_aclLen_t gacl_len;
+ SMB4ACE_T *smbace;
+ struct gpfs_acl *gacl;
+ TALLOC_CTX *mem_ctx = talloc_tos();
+
+ gacl_len = sizeof(struct gpfs_acl) +
+ (smb_get_naces(smbacl)-1)*sizeof(gpfs_ace_v4_t);
+
+ gacl = TALLOC_SIZE(mem_ctx, gacl_len);
+ if (gacl == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ errno = ENOMEM;
+ return False;
+ }
+
+ gacl->acl_len = gacl_len;
+ gacl->acl_level = 0;
+ gacl->acl_version = GPFS_ACL_VERSION_NFS4;
+ gacl->acl_type = GPFS_ACL_TYPE_NFS4;
+ gacl->acl_nace = 0; /* change later... */
+
+ for (smbace=smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
+ struct gpfs_ace_v4 *gace = &gacl->ace_v4[gacl->acl_nace];
+ SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
+
+ gace->aceType = aceprop->aceType;
+ gace->aceFlags = aceprop->aceFlags;
+ gace->aceMask = aceprop->aceMask;
+
+ /*
+ * GPFS can't distinguish between WRITE and APPEND on
+ * files, so one being set without the other is an
+ * error. Sorry for the many ()'s :-)
+ */
+
+ if (!fsp->is_directory
+ &&
+ ((((gace->aceMask & ACE4_MASK_WRITE) == 0)
+ && ((gace->aceMask & ACE4_MASK_APPEND) != 0))
+ ||
+ (((gace->aceMask & ACE4_MASK_WRITE) != 0)
+ && ((gace->aceMask & ACE4_MASK_APPEND) == 0)))
+ &&
+ lp_parm_bool(fsp->conn->params->service, "gpfs",
+ "merge_writeappend", True)) {
+ DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains "
+ "WRITE^APPEND, setting WRITE|APPEND\n",
+ fsp->fsp_name));
+ gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND;
+ }
+
+ gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0;
+
+ if (aceprop->flags&SMB_ACE4_ID_SPECIAL)
+ {
+ switch(aceprop->who.special_id)
+ {
+ case SMB_ACE4_WHO_EVERYONE:
+ gace->aceWho = ACE4_SPECIAL_EVERYONE;
+ break;
+ case SMB_ACE4_WHO_OWNER:
+ gace->aceWho = ACE4_SPECIAL_OWNER;
+ break;
+ case SMB_ACE4_WHO_GROUP:
+ gace->aceWho = ACE4_SPECIAL_GROUP;
+ break;
+ default:
+ DEBUG(8, ("unsupported special_id %d\n", aceprop->who.special_id));
+ continue; /* don't add it !!! */
+ }
+ } else {
+ /* just only for the type safety... */
+ if (aceprop->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)
+ gace->aceWho = aceprop->who.gid;
+ else
+ gace->aceWho = aceprop->who.uid;
+ }
+
+ gacl->acl_nace++;
+ }
+
+ ret = smbd_gpfs_putacl(fsp->fsp_name, GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gacl);
+ if (ret != 0) {
+ DEBUG(8, ("gpfs_putacl failed with %s\n", strerror(errno)));
+ gpfs_dumpacl(8, gacl);
+ return False;
+ }
+
+ DEBUG(10, ("gpfs_putacl succeeded\n"));
+ return True;
+}
+
+static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
+{
+ struct gpfs_acl *acl;
+ NTSTATUS result = NT_STATUS_ACCESS_DENIED;
+
+ acl = gpfs_getacl_alloc(fsp->fsp_name, 0);
+ if (acl == NULL)
+ return result;
+
+ if (acl->acl_version&GPFS_ACL_VERSION_NFS4)
+ {
+ result = smb_set_nt_acl_nfs4(
+ fsp, security_info_sent, psd,
+ gpfsacl_process_smbacl);
+ } else { /* assume POSIX ACL - by default... */
+ result = set_nt_acl(fsp, security_info_sent, psd);
+ }
+
+ return result;
+}
+
+static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
+{
+ return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd);
+}
+
+static SMB_ACL_T gpfs2smb_acl(const struct gpfs_acl *pacl)
+{
+ SMB_ACL_T result;
+ int i;
+
+ result = sys_acl_init(pacl->acl_nace);
+ if (result == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ result->count = pacl->acl_nace;
+
+ for (i=0; i<pacl->acl_nace; i++) {
+ struct smb_acl_entry *ace = &result->acl[i];
+ const struct gpfs_ace_v1 *g_ace = &pacl->ace_v1[i];
+
+ DEBUG(10, ("Converting type %d id %lu perm %x\n",
+ (int)g_ace->ace_type, (unsigned long)g_ace->ace_who,
+ (int)g_ace->ace_perm));
+
+ switch (g_ace->ace_type) {
+ case GPFS_ACL_USER:
+ ace->a_type = SMB_ACL_USER;
+ ace->uid = (uid_t)g_ace->ace_who;
+ break;
+ case GPFS_ACL_USER_OBJ:
+ ace->a_type = SMB_ACL_USER_OBJ;
+ break;
+ case GPFS_ACL_GROUP:
+ ace->a_type = SMB_ACL_GROUP;
+ ace->gid = (gid_t)g_ace->ace_who;
+ break;
+ case GPFS_ACL_GROUP_OBJ:
+ ace->a_type = SMB_ACL_GROUP_OBJ;
+ break;
+ case GPFS_ACL_OTHER:
+ ace->a_type = SMB_ACL_OTHER;
+ break;
+ case GPFS_ACL_MASK:
+ ace->a_type = SMB_ACL_MASK;
+ break;
+ default:
+ DEBUG(10, ("Got invalid ace_type: %d\n",
+ g_ace->ace_type));
+ errno = EINVAL;
+ SAFE_FREE(result);
+ return NULL;
+ }
+
+ ace->a_perm = 0;
+ ace->a_perm |= (g_ace->ace_perm & ACL_PERM_READ) ?
+ SMB_ACL_READ : 0;
+ ace->a_perm |= (g_ace->ace_perm & ACL_PERM_WRITE) ?
+ SMB_ACL_WRITE : 0;
+ ace->a_perm |= (g_ace->ace_perm & ACL_PERM_EXECUTE) ?
+ SMB_ACL_EXECUTE : 0;
+
+ DEBUGADD(10, ("Converted to %d perm %x\n",
+ ace->a_type, ace->a_perm));
+ }
+
+ return result;
+}
+
+static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type)
+{
+ struct gpfs_acl *pacl;
+ SMB_ACL_T result = NULL;
+
+ pacl = gpfs_getacl_alloc(path, type);
+
+ if (pacl == NULL) {
+ DEBUG(10, ("gpfs_getacl failed for %s with %s\n",
+ path, strerror(errno)));
+ if (errno == 0) {
+ errno = EINVAL;
+ }
+ goto done;
+ }
+
+ if (pacl->acl_version != GPFS_ACL_VERSION_POSIX) {
+ DEBUG(10, ("Got acl version %d, expected %d\n",
+ pacl->acl_version, GPFS_ACL_VERSION_POSIX));
+ errno = EINVAL;
+ goto done;
+ }
+
+ DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
+ pacl->acl_len, pacl->acl_level, pacl->acl_version,
+ pacl->acl_nace));
+
+ result = gpfs2smb_acl(pacl);
+ if (result == NULL) {
+ goto done;
+ }
+
+ done:
+
+ if (errno != 0) {
+ SAFE_FREE(result);
+ }
+ return result;
+}
+
+SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle,
+
+ const char *path_p,
+ SMB_ACL_TYPE_T type)
+{
+ gpfs_aclType_t gpfs_type;
+
+ switch(type) {
+ case SMB_ACL_TYPE_ACCESS:
+ gpfs_type = GPFS_ACL_TYPE_ACCESS;
+ break;
+ case SMB_ACL_TYPE_DEFAULT:
+ gpfs_type = GPFS_ACL_TYPE_DEFAULT;
+ break;
+ default:
+ DEBUG(0, ("Got invalid type: %d\n", type));
+ smb_panic("exiting");
+ }
+
+ return gpfsacl_get_posix_acl(path_p, gpfs_type);
+}
+
+SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp)
+{
+ return gpfsacl_get_posix_acl(fsp->fsp_name, GPFS_ACL_TYPE_ACCESS);
+}
+
+static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl,
+ SMB_ACL_TYPE_T type)
+{
+ gpfs_aclLen_t len;
+ struct gpfs_acl *result;
+ int i;
+ union gpfs_ace_union
+ {
+ gpfs_ace_v1_t ace_v1[1]; /* when GPFS_ACL_VERSION_POSIX */
+ gpfs_ace_v4_t ace_v4[1]; /* when GPFS_ACL_VERSION_NFS4 */
+ };
+
+ DEBUG(10, ("smb2gpfs_acl: Got ACL with %d entries\n", pacl->count));
+
+ len = sizeof(struct gpfs_acl) - sizeof(union gpfs_ace_union) +
+ (pacl->count)*sizeof(gpfs_ace_v1_t);
+
+ result = SMB_MALLOC(len);
+ if (result == NULL) {
+ errno = ENOMEM;
+ return result;
+ }
+
+ result->acl_len = len;
+ result->acl_level = 0;
+ result->acl_version = GPFS_ACL_VERSION_POSIX;
+ result->acl_type = (type == SMB_ACL_TYPE_DEFAULT) ?
+ GPFS_ACL_TYPE_DEFAULT : GPFS_ACL_TYPE_ACCESS;
+ result->acl_nace = pacl->count;
+
+ for (i=0; i<pacl->count; i++) {
+ const struct smb_acl_entry *ace = &pacl->acl[i];
+ struct gpfs_ace_v1 *g_ace = &result->ace_v1[i];
+
+ DEBUG(10, ("Converting type %d perm %x\n",
+ (int)ace->a_type, (int)ace->a_perm));
+
+ g_ace->ace_perm = 0;
+
+ switch(ace->a_type) {
+ case SMB_ACL_USER:
+ g_ace->ace_type = GPFS_ACL_USER;
+ g_ace->ace_who = (gpfs_uid_t)ace->uid;
+ break;
+ case SMB_ACL_USER_OBJ:
+ g_ace->ace_type = GPFS_ACL_USER_OBJ;
+ g_ace->ace_perm |= ACL_PERM_CONTROL;
+ g_ace->ace_who = 0;
+ break;
+ case SMB_ACL_GROUP:
+ g_ace->ace_type = GPFS_ACL_GROUP;
+ g_ace->ace_who = (gpfs_uid_t)ace->gid;
+ break;
+ case SMB_ACL_GROUP_OBJ:
+ g_ace->ace_type = GPFS_ACL_GROUP_OBJ;
+ g_ace->ace_who = 0;
+ break;
+ case SMB_ACL_MASK:
+ g_ace->ace_type = GPFS_ACL_MASK;
+ g_ace->ace_perm = 0x8f;
+ g_ace->ace_who = 0;
+ break;
+ case SMB_ACL_OTHER:
+ g_ace->ace_type = GPFS_ACL_OTHER;
+ g_ace->ace_who = 0;
+ break;
+ default:
+ DEBUG(10, ("Got invalid ace_type: %d\n", ace->a_type));
+ errno = EINVAL;
+ SAFE_FREE(result);
+ return NULL;
+ }
+
+ g_ace->ace_perm |= (ace->a_perm & SMB_ACL_READ) ?
+ ACL_PERM_READ : 0;
+ g_ace->ace_perm |= (ace->a_perm & SMB_ACL_WRITE) ?
+ ACL_PERM_WRITE : 0;
+ g_ace->ace_perm |= (ace->a_perm & SMB_ACL_EXECUTE) ?
+ ACL_PERM_EXECUTE : 0;
+
+ DEBUGADD(10, ("Converted to %d id %d perm %x\n",
+ g_ace->ace_type, g_ace->ace_who, g_ace->ace_perm));
+ }
+
+ return result;
+}
+
+int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle,
+
+ const char *name,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl)
+{
+ struct gpfs_acl *gpfs_acl;
+ int result;
+
+ gpfs_acl = smb2gpfs_acl(theacl, type);
+ if (gpfs_acl == NULL) {
+ return -1;
+ }
+
+ result = smbd_gpfs_putacl((char *)name, GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gpfs_acl);
+
+ SAFE_FREE(gpfs_acl);
+ return result;
+}
+
+int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_T theacl)
+{
+ return gpfsacl_sys_acl_set_file(handle, fsp->fsp_name, SMB_ACL_TYPE_ACCESS, theacl);
+}
+
+int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
+
+ const char *path)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+/*
+ * Assumed: mode bits are shiftable and standard
+ * Output: the new aceMask field for an smb nfs4 ace
+ */
+static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx)
+{
+ const uint32 posix_nfs4map[3] = {
+ SMB_ACE4_EXECUTE, /* execute */
+ SMB_ACE4_WRITE_DATA | SMB_ACE4_APPEND_DATA, /* write; GPFS specific */
+ SMB_ACE4_READ_DATA /* read */
+ };
+ int i;
+ uint32_t posix_mask = 0x01;
+ uint32_t posix_bit;
+ uint32_t nfs4_bits;
+
+ for(i=0; i<3; i++) {
+ nfs4_bits = posix_nfs4map[i];
+ posix_bit = rwx & posix_mask;
+
+ if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
+ if (posix_bit)
+ aceMask |= nfs4_bits;
+ else
+ aceMask &= ~nfs4_bits;
+ } else {
+ /* add deny bits when suitable */
+ if (!posix_bit)
+ aceMask |= nfs4_bits;
+ else
+ aceMask &= ~nfs4_bits;
+ } /* other ace types are unexpected */
+
+ posix_mask <<= 1;
+ }
+
+ return aceMask;
+}
+
+static int gpfsacl_emu_chmod(const char *path, mode_t mode)
+{
+ SMB4ACL_T *pacl = NULL;
+ int result;
+ bool haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
+ int i;
+ files_struct fake_fsp; /* TODO: rationalize parametrization */
+ SMB4ACE_T *smbace;
+
+ DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
+
+ result = gpfs_get_nfs4_acl(path, &pacl);
+ if (result)
+ return result;
+
+ if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) {
+ DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path));
+ }
+
+ for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
+ SMB_ACE4PROP_T *ace = smb_get_ace4(smbace);
+ uint32_t specid = ace->who.special_id;
+
+ if (ace->flags&SMB_ACE4_ID_SPECIAL &&
+ ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
+ specid <= SMB_ACE4_WHO_EVERYONE) {
+
+ uint32_t newMask;
+
+ if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE)
+ haveAllowEntry[specid] = True;
+
+ /* mode >> 6 for @owner, mode >> 3 for @group,
+ * mode >> 0 for @everyone */
+ newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask,
+ mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3));
+ if (ace->aceMask!=newMask) {
+ DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n",
+ path, ace->aceMask, newMask, specid));
+ }
+ ace->aceMask = newMask;
+ }
+ }
+
+ /* make sure we have at least ALLOW entries
+ * for all the 3 special ids (@EVERYONE, @OWNER, @GROUP)
+ * - if necessary
+ */
+ for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) {
+ SMB_ACE4PROP_T ace;
+
+ if (haveAllowEntry[i]==True)
+ continue;
+
+ memset(&ace, 0, sizeof(SMB_ACE4PROP_T));
+ ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
+ ace.flags |= SMB_ACE4_ID_SPECIAL;
+ ace.who.special_id = i;
+
+ if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */
+ ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
+
+ ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask,
+ mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3));
+
+ /* don't add unnecessary aces */
+ if (!ace.aceMask)
+ continue;
+
+ /* we add it to the END - as windows expects allow aces */
+ smb_add_ace4(pacl, &ace);
+ DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n",
+ path, mode, i, ace.aceMask));
+ }
+
+ /* don't add complementary DENY ACEs here */
+ memset(&fake_fsp, 0, sizeof(struct files_struct));
+ fake_fsp.fsp_name = (char *)path; /* no file_new is needed here */
+
+ /* put the acl */
+ if (gpfsacl_process_smbacl(&fake_fsp, pacl) == False)
+ return -1;
+ return 0; /* ok for [f]chmod */
+}
+
+static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
+{
+ SMB_STRUCT_STAT st;
+ int rc;
+
+ if (SMB_VFS_NEXT_STAT(handle, path, &st) != 0) {
+ return -1;
+ }
+
+ /* avoid chmod() if possible, to preserve acls */
+ if ((st.st_mode & ~S_IFMT) == mode) {
+ return 0;
+ }
+
+ rc = gpfsacl_emu_chmod(path, mode);
+ if (rc == 1)
+ return SMB_VFS_NEXT_CHMOD(handle, path, mode);
+ return rc;
+}
+
+static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
+{
+ SMB_STRUCT_STAT st;
+ int rc;
+
+ if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) {
+ return -1;
+ }
+
+ /* avoid chmod() if possible, to preserve acls */
+ if ((st.st_mode & ~S_IFMT) == mode) {
+ return 0;
+ }
+
+ rc = gpfsacl_emu_chmod(fsp->fsp_name, mode);
+ if (rc == 1)
+ return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
+ return rc;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple gpfs_op_tuples[] = {
+
+ { SMB_VFS_OP(vfs_gpfs_kernel_flock),
+ SMB_VFS_OP_KERNEL_FLOCK,
+ SMB_VFS_LAYER_OPAQUE },
+
+ { SMB_VFS_OP(vfs_gpfs_setlease),
+ SMB_VFS_OP_LINUX_SETLEASE,
+ SMB_VFS_LAYER_OPAQUE },
+
+ { SMB_VFS_OP(gpfsacl_fget_nt_acl),
+ SMB_VFS_OP_FGET_NT_ACL,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(gpfsacl_get_nt_acl),
+ SMB_VFS_OP_GET_NT_ACL,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(gpfsacl_fset_nt_acl),
+ SMB_VFS_OP_FSET_NT_ACL,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(gpfsacl_sys_acl_get_file),
+ SMB_VFS_OP_SYS_ACL_GET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(gpfsacl_sys_acl_get_fd),
+ SMB_VFS_OP_SYS_ACL_GET_FD,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(gpfsacl_sys_acl_set_file),
+ SMB_VFS_OP_SYS_ACL_SET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(gpfsacl_sys_acl_set_fd),
+ SMB_VFS_OP_SYS_ACL_SET_FD,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(gpfsacl_sys_acl_delete_def_file),
+ SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(vfs_gpfs_chmod),
+ SMB_VFS_OP_CHMOD,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(vfs_gpfs_fchmod),
+ SMB_VFS_OP_FCHMOD,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP }
+
+};
+
+
+NTSTATUS vfs_gpfs_init(void);
+NTSTATUS vfs_gpfs_init(void)
+{
+ init_gpfs();
+
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs",
+ gpfs_op_tuples);
+}
diff --git a/source3/modules/vfs_gpfs.h b/source3/modules/vfs_gpfs.h
new file mode 100644
index 0000000000..3c499b0850
--- /dev/null
+++ b/source3/modules/vfs_gpfs.h
@@ -0,0 +1,32 @@
+/*
+ Unix SMB/CIFS implementation.
+ Wrap gpfs calls in vfs functions.
+
+ Copyright (C) Christian Ambach <cambach1@de.ibm.com> 2006
+
+ Major code contributions by Chetan Shringarpure <chetan.sh@in.ibm.com>
+ and Gomati Mohanan <gomati.mohanan@in.ibm.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+*/
+
+bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask,
+ uint32 share_access);
+int set_gpfs_lease(int fd, int leasetype);
+int smbd_gpfs_getacl(char *pathname, int flags, void *acl);
+int smbd_gpfs_putacl(char *pathname, int flags, void *acl);
+void init_gpfs(void);
diff --git a/source3/modules/vfs_hpuxacl.c b/source3/modules/vfs_hpuxacl.c
new file mode 100644
index 0000000000..f9293405fb
--- /dev/null
+++ b/source3/modules/vfs_hpuxacl.c
@@ -0,0 +1,1184 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * VFS module to get and set HP-UX ACLs
+ * Copyright (C) Michael Adam 2006,2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This module supports JFS (POSIX) ACLs on VxFS (Veritas * Filesystem).
+ * These are available on HP-UX 11.00 if JFS 3.3 is installed.
+ * On HP-UX 11i (11.11 and above) these ACLs are supported out of
+ * the box.
+ *
+ * There is another form of ACLs on HFS. These ACLs have a
+ * completely different API and their own set of userland tools.
+ * Since HFS seems to be considered deprecated, HFS acls
+ * are not supported. (They could be supported through a separate
+ * vfs-module if there is demand.)
+ */
+
+/* =================================================================
+ * NOTE:
+ *
+ * The original hpux-acl code in lib/sysacls.c was based upon the
+ * solaris acl code in the same file. Now for the new modularized
+ * acl implementation, I have taken the code from vfs_solarisacls.c
+ * and did similar adaptations as were done before, essentially
+ * reusing the original internal aclsort functions.
+ * The check for the presence of the acl() call has been adopted, and
+ * a check for the presence of the aclsort() call has been added.
+ *
+ * Michael Adam <obnox@samba.org>
+ *
+ * ================================================================= */
+
+
+#include "includes.h"
+
+/*
+ * including standard header <sys/aclv.h>
+ *
+ * included here as a quick hack for the special HP-UX-situation:
+ *
+ * The problem is that, on HP-UX, jfs/posix acls are
+ * defined in <sys/aclv.h>, while the deprecated hfs acls
+ * are defined inside <sys/acl.h>.
+ *
+ */
+/* GROUP is defined somewhere else so undef it here... */
+#undef GROUP
+#include <sys/aclv.h>
+/* dl.h: needed to check for acl call via shl_findsym */
+#include <dl.h>
+
+typedef struct acl HPUX_ACE_T;
+typedef struct acl *HPUX_ACL_T;
+typedef int HPUX_ACL_TAG_T; /* the type of an ACL entry */
+typedef ushort HPUX_PERM_T;
+
+/* Structure to capture the count for each type of ACE.
+ * (for hpux_internal_aclsort */
+struct hpux_acl_types {
+ int n_user;
+ int n_def_user;
+ int n_user_obj;
+ int n_def_user_obj;
+
+ int n_group;
+ int n_def_group;
+ int n_group_obj;
+ int n_def_group_obj;
+
+ int n_other;
+ int n_other_obj;
+ int n_def_other_obj;
+
+ int n_class_obj;
+ int n_def_class_obj;
+
+ int n_illegal_obj;
+};
+
+/* for convenience: check if hpux acl entry is a default entry? */
+#define _IS_DEFAULT(ace) ((ace).a_type & ACL_DEFAULT)
+#define _IS_OF_TYPE(ace, type) ( \
+ (((type) == SMB_ACL_TYPE_ACCESS) && !_IS_DEFAULT(ace)) \
+ || \
+ (((type) == SMB_ACL_TYPE_DEFAULT) && _IS_DEFAULT(ace)) \
+)
+
+
+/* prototypes for private functions */
+
+static HPUX_ACL_T hpux_acl_init(int count);
+static bool smb_acl_to_hpux_acl(SMB_ACL_T smb_acl,
+ HPUX_ACL_T *solariacl, int *count,
+ SMB_ACL_TYPE_T type);
+static SMB_ACL_T hpux_acl_to_smb_acl(HPUX_ACL_T hpuxacl, int count,
+ SMB_ACL_TYPE_T type);
+static HPUX_ACL_TAG_T smb_tag_to_hpux_tag(SMB_ACL_TAG_T smb_tag);
+static SMB_ACL_TAG_T hpux_tag_to_smb_tag(HPUX_ACL_TAG_T hpux_tag);
+static bool hpux_add_to_acl(HPUX_ACL_T *hpux_acl, int *count,
+ HPUX_ACL_T add_acl, int add_count, SMB_ACL_TYPE_T type);
+static bool hpux_acl_get_file(const char *name, HPUX_ACL_T *hpuxacl,
+ int *count);
+static SMB_ACL_PERM_T hpux_perm_to_smb_perm(const HPUX_PERM_T perm);
+static HPUX_PERM_T smb_perm_to_hpux_perm(const SMB_ACL_PERM_T perm);
+#if 0
+static bool hpux_acl_check(HPUX_ACL_T hpux_acl, int count);
+#endif
+/* aclsort (internal) and helpers: */
+static bool hpux_acl_sort(HPUX_ACL_T acl, int count);
+static int hpux_internal_aclsort(int acl_count, int calclass, HPUX_ACL_T aclp);
+static void hpux_count_obj(int acl_count, HPUX_ACL_T aclp,
+ struct hpux_acl_types *acl_type_count);
+static void hpux_swap_acl_entries(HPUX_ACE_T *aclp0, HPUX_ACE_T *aclp1);
+static bool hpux_prohibited_duplicate_type(int acl_type);
+
+static bool hpux_acl_call_present(void);
+static bool hpux_aclsort_call_present(void);
+
+
+/* public functions - the api */
+
+SMB_ACL_T hpuxacl_sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ SMB_ACL_TYPE_T type)
+{
+ SMB_ACL_T result = NULL;
+ int count;
+ HPUX_ACL_T hpux_acl = NULL;
+
+ DEBUG(10, ("hpuxacl_sys_acl_get_file called for file '%s'.\n",
+ path_p));
+
+ if(hpux_acl_call_present() == False) {
+ /* Looks like we don't have the acl() system call on HPUX.
+ * May be the system doesn't have the latest version of JFS.
+ */
+ goto done;
+ }
+
+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
+ DEBUG(10, ("invalid SMB_ACL_TYPE given (%d)\n", type));
+ errno = EINVAL;
+ goto done;
+ }
+
+ DEBUGADD(10, ("getting %s acl\n",
+ ((type == SMB_ACL_TYPE_ACCESS) ? "access" : "default")));
+
+ if (!hpux_acl_get_file(path_p, &hpux_acl, &count)) {
+ goto done;
+ }
+ result = hpux_acl_to_smb_acl(hpux_acl, count, type);
+ if (result == NULL) {
+ DEBUG(10, ("conversion hpux_acl -> smb_acl failed (%s).\n",
+ strerror(errno)));
+ }
+
+ done:
+ DEBUG(10, ("hpuxacl_sys_acl_get_file %s.\n",
+ ((result == NULL) ? "failed" : "succeeded" )));
+ SAFE_FREE(hpux_acl);
+ return result;
+}
+
+
+/*
+ * get the access ACL of a file referred to by a fd
+ */
+SMB_ACL_T hpuxacl_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp)
+{
+ /*
+ * HPUX doesn't have the facl call. Fake it using the path.... JRA.
+ */
+ /* For all I see, the info should already be in the fsp
+ * parameter, but get it again to be safe --- necessary? */
+ files_struct *file_struct_p = file_find_fd(fsp->fh->fd);
+ if (file_struct_p == NULL) {
+ errno = EBADF;
+ return NULL;
+ }
+ /*
+ * We know we're in the same conn context. So we
+ * can use the relative path.
+ */
+ DEBUG(10, ("redirecting call of hpuxacl_sys_acl_get_fd to "
+ "hpuxacl_sys_acl_get_file (no facl syscall on HPUX).\n"));
+
+ return hpuxacl_sys_acl_get_file(handle, file_struct_p->fsp_name,
+ SMB_ACL_TYPE_ACCESS);
+}
+
+
+int hpuxacl_sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl)
+{
+ int ret = -1;
+ SMB_STRUCT_STAT s;
+ HPUX_ACL_T hpux_acl = NULL;
+ int count;
+
+ DEBUG(10, ("hpuxacl_sys_acl_set_file called for file '%s'\n",
+ name));
+
+
+ if(hpux_acl_call_present() == False) {
+ /* Looks like we don't have the acl() system call on HPUX.
+ * May be the system doesn't have the latest version of JFS.
+ */
+ goto done;
+ }
+
+ if ((type != SMB_ACL_TYPE_ACCESS) && (type != SMB_ACL_TYPE_DEFAULT)) {
+ errno = EINVAL;
+ DEBUG(10, ("invalid smb acl type given (%d).\n", type));
+ goto done;
+ }
+ DEBUGADD(10, ("setting %s acl\n",
+ ((type == SMB_ACL_TYPE_ACCESS) ? "access" : "default")));
+
+ if(!smb_acl_to_hpux_acl(theacl, &hpux_acl, &count, type)) {
+ DEBUG(10, ("conversion smb_acl -> hpux_acl failed (%s).\n",
+ strerror(errno)));
+ goto done;
+ }
+
+ /*
+ * if the file is a directory, there is extra work to do:
+ * since the hpux acl call stores both the access acl and
+ * the default acl as provided, we have to get the acl part
+ * that has _not_ been specified in "type" from the file first
+ * and concatenate it with the acl provided.
+ */
+ if (SMB_VFS_STAT(handle->conn, name, &s) != 0) {
+ DEBUG(10, ("Error in stat call: %s\n", strerror(errno)));
+ goto done;
+ }
+ if (S_ISDIR(s.st_mode)) {
+ HPUX_ACL_T other_acl;
+ int other_count;
+ SMB_ACL_TYPE_T other_type;
+
+ other_type = (type == SMB_ACL_TYPE_ACCESS)
+ ? SMB_ACL_TYPE_DEFAULT
+ : SMB_ACL_TYPE_ACCESS;
+ DEBUGADD(10, ("getting acl from filesystem\n"));
+ if (!hpux_acl_get_file(name, &other_acl, &other_count)) {
+ DEBUG(10, ("error getting acl from directory\n"));
+ goto done;
+ }
+ DEBUG(10, ("adding %s part of fs acl to given acl\n",
+ ((other_type == SMB_ACL_TYPE_ACCESS)
+ ? "access"
+ : "default")));
+ if (!hpux_add_to_acl(&hpux_acl, &count, other_acl,
+ other_count, other_type))
+ {
+ DEBUG(10, ("error adding other acl.\n"));
+ SAFE_FREE(other_acl);
+ goto done;
+ }
+ SAFE_FREE(other_acl);
+ }
+ else if (type != SMB_ACL_TYPE_ACCESS) {
+ errno = EINVAL;
+ goto done;
+ }
+
+ if (!hpux_acl_sort(hpux_acl, count)) {
+ DEBUG(10, ("resulting acl is not valid!\n"));
+ goto done;
+ }
+ DEBUG(10, ("resulting acl is valid.\n"));
+
+ ret = acl(CONST_DISCARD(char *, name), ACL_SET, count, hpux_acl);
+ if (ret != 0) {
+ DEBUG(0, ("ERROR calling acl: %s\n", strerror(errno)));
+ }
+
+ done:
+ DEBUG(10, ("hpuxacl_sys_acl_set_file %s.\n",
+ ((ret != 0) ? "failed" : "succeeded")));
+ SAFE_FREE(hpux_acl);
+ return ret;
+}
+
+/*
+ * set the access ACL on the file referred to by a fd
+ */
+int hpuxacl_sys_acl_set_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_T theacl)
+{
+ /*
+ * HPUX doesn't have the facl call. Fake it using the path.... JRA.
+ */
+ /* For all I see, the info should already be in the fsp
+ * parameter, but get it again to be safe --- necessary? */
+ files_struct *file_struct_p = file_find_fd(fsp->fh->fd);
+ if (file_struct_p == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+ /*
+ * We know we're in the same conn context. So we
+ * can use the relative path.
+ */
+ DEBUG(10, ("redirecting call of hpuxacl_sys_acl_set_fd to "
+ "hpuxacl_sys_acl_set_file (no facl syscall on HPUX)\n"));
+
+ return hpuxacl_sys_acl_set_file(handle, file_struct_p->fsp_name,
+ SMB_ACL_TYPE_ACCESS, theacl);
+}
+
+
+/*
+ * delete the default ACL of a directory
+ *
+ * This is achieved by fetching the access ACL and rewriting it
+ * directly, via the hpux system call: the ACL_SET call on
+ * directories writes both the access and the default ACL as provided.
+ *
+ * XXX: posix acl_delete_def_file returns an error if
+ * the file referred to by path is not a directory.
+ * this function does not complain but the actions
+ * have no effect on a file other than a directory.
+ * But sys_acl_delete_default_file is only called in
+ * smbd/posixacls.c after having checked that the file
+ * is a directory, anyways. So implementing the extra
+ * check is considered unnecessary. --- Agreed? XXX
+ */
+int hpuxacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path)
+{
+ SMB_ACL_T smb_acl;
+ int ret = -1;
+ HPUX_ACL_T hpux_acl;
+ int count;
+
+ DEBUG(10, ("entering hpuxacl_sys_acl_delete_def_file.\n"));
+
+ smb_acl = hpuxacl_sys_acl_get_file(handle, path,
+ SMB_ACL_TYPE_ACCESS);
+ if (smb_acl == NULL) {
+ DEBUG(10, ("getting file acl failed!\n"));
+ goto done;
+ }
+ if (!smb_acl_to_hpux_acl(smb_acl, &hpux_acl, &count,
+ SMB_ACL_TYPE_ACCESS))
+ {
+ DEBUG(10, ("conversion smb_acl -> hpux_acl failed.\n"));
+ goto done;
+ }
+ if (!hpux_acl_sort(hpux_acl, count)) {
+ DEBUG(10, ("resulting acl is not valid!\n"));
+ goto done;
+ }
+ ret = acl(CONST_DISCARD(char *, path), ACL_SET, count, hpux_acl);
+ if (ret != 0) {
+ DEBUG(10, ("settinge file acl failed!\n"));
+ }
+
+ done:
+ DEBUG(10, ("hpuxacl_sys_acl_delete_def_file %s.\n",
+ ((ret != 0) ? "failed" : "succeeded" )));
+ SAFE_FREE(smb_acl);
+ return ret;
+}
+
+
+/*
+ * private functions
+ */
+
+static HPUX_ACL_T hpux_acl_init(int count)
+{
+ HPUX_ACL_T hpux_acl =
+ (HPUX_ACL_T)SMB_MALLOC(sizeof(HPUX_ACE_T) * count);
+ if (hpux_acl == NULL) {
+ errno = ENOMEM;
+ }
+ return hpux_acl;
+}
+
+/*
+ * Convert the SMB acl to the ACCESS or DEFAULT part of a
+ * hpux ACL, as desired.
+ */
+static bool smb_acl_to_hpux_acl(SMB_ACL_T smb_acl,
+ HPUX_ACL_T *hpux_acl, int *count,
+ SMB_ACL_TYPE_T type)
+{
+ bool ret = False;
+ int i;
+ int check_which, check_rc;
+
+ DEBUG(10, ("entering smb_acl_to_hpux_acl\n"));
+
+ *hpux_acl = NULL;
+ *count = 0;
+
+ for (i = 0; i < smb_acl->count; i++) {
+ const struct smb_acl_entry *smb_entry = &(smb_acl->acl[i]);
+ HPUX_ACE_T hpux_entry;
+
+ ZERO_STRUCT(hpux_entry);
+
+ hpux_entry.a_type = smb_tag_to_hpux_tag(smb_entry->a_type);
+ if (hpux_entry.a_type == 0) {
+ DEBUG(10, ("smb_tag to hpux_tag failed\n"));
+ goto fail;
+ }
+ switch(hpux_entry.a_type) {
+ case USER:
+ DEBUG(10, ("got tag type USER with uid %d\n",
+ smb_entry->uid));
+ hpux_entry.a_id = (uid_t)smb_entry->uid;
+ break;
+ case GROUP:
+ DEBUG(10, ("got tag type GROUP with gid %d\n",
+ smb_entry->gid));
+ hpux_entry.a_id = (uid_t)smb_entry->gid;
+ break;
+ default:
+ break;
+ }
+ if (type == SMB_ACL_TYPE_DEFAULT) {
+ DEBUG(10, ("adding default bit to hpux ace\n"));
+ hpux_entry.a_type |= ACL_DEFAULT;
+ }
+
+ hpux_entry.a_perm =
+ smb_perm_to_hpux_perm(smb_entry->a_perm);
+ DEBUG(10, ("assembled the following hpux ace:\n"));
+ DEBUGADD(10, (" - type: 0x%04x\n", hpux_entry.a_type));
+ DEBUGADD(10, (" - id: %d\n", hpux_entry.a_id));
+ DEBUGADD(10, (" - perm: o%o\n", hpux_entry.a_perm));
+ if (!hpux_add_to_acl(hpux_acl, count, &hpux_entry,
+ 1, type))
+ {
+ DEBUG(10, ("error adding acl entry\n"));
+ goto fail;
+ }
+ DEBUG(10, ("count after adding: %d (i: %d)\n", *count, i));
+ DEBUG(10, ("test, if entry has been copied into acl:\n"));
+ DEBUGADD(10, (" - type: 0x%04x\n",
+ (*hpux_acl)[(*count)-1].a_type));
+ DEBUGADD(10, (" - id: %d\n",
+ (*hpux_acl)[(*count)-1].a_id));
+ DEBUGADD(10, (" - perm: o%o\n",
+ (*hpux_acl)[(*count)-1].a_perm));
+ }
+
+ ret = True;
+ goto done;
+
+ fail:
+ SAFE_FREE(*hpux_acl);
+ done:
+ DEBUG(10, ("smb_acl_to_hpux_acl %s\n",
+ ((ret == True) ? "succeeded" : "failed")));
+ return ret;
+}
+
+/*
+ * convert either the access or the default part of a
+ * soaris acl to the SMB_ACL format.
+ */
+static SMB_ACL_T hpux_acl_to_smb_acl(HPUX_ACL_T hpux_acl, int count,
+ SMB_ACL_TYPE_T type)
+{
+ SMB_ACL_T result;
+ int i;
+
+ if ((result = sys_acl_init(0)) == NULL) {
+ DEBUG(10, ("error allocating memory for SMB_ACL\n"));
+ goto fail;
+ }
+ for (i = 0; i < count; i++) {
+ SMB_ACL_ENTRY_T smb_entry;
+ SMB_ACL_PERM_T smb_perm;
+
+ if (!_IS_OF_TYPE(hpux_acl[i], type)) {
+ continue;
+ }
+ result = SMB_REALLOC(result,
+ sizeof(struct smb_acl_t) +
+ (sizeof(struct smb_acl_entry) *
+ (result->count + 1)));
+ if (result == NULL) {
+ DEBUG(10, ("error reallocating memory for SMB_ACL\n"));
+ goto fail;
+ }
+ smb_entry = &result->acl[result->count];
+ if (sys_acl_set_tag_type(smb_entry,
+ hpux_tag_to_smb_tag(hpux_acl[i].a_type)) != 0)
+ {
+ DEBUG(10, ("invalid tag type given: 0x%04x\n",
+ hpux_acl[i].a_type));
+ goto fail;
+ }
+ /* intentionally not checking return code here: */
+ sys_acl_set_qualifier(smb_entry, (void *)&hpux_acl[i].a_id);
+ smb_perm = hpux_perm_to_smb_perm(hpux_acl[i].a_perm);
+ if (sys_acl_set_permset(smb_entry, &smb_perm) != 0) {
+ DEBUG(10, ("invalid permset given: %d\n",
+ hpux_acl[i].a_perm));
+ goto fail;
+ }
+ result->count += 1;
+ }
+ goto done;
+
+ fail:
+ SAFE_FREE(result);
+ done:
+ DEBUG(10, ("hpux_acl_to_smb_acl %s\n",
+ ((result == NULL) ? "failed" : "succeeded")));
+ return result;
+}
+
+
+
+static HPUX_ACL_TAG_T smb_tag_to_hpux_tag(SMB_ACL_TAG_T smb_tag)
+{
+ HPUX_ACL_TAG_T hpux_tag = 0;
+
+ DEBUG(10, ("smb_tag_to_hpux_tag\n"));
+ DEBUGADD(10, (" --> got smb tag 0x%04x\n", smb_tag));
+
+ switch (smb_tag) {
+ case SMB_ACL_USER:
+ hpux_tag = USER;
+ break;
+ case SMB_ACL_USER_OBJ:
+ hpux_tag = USER_OBJ;
+ break;
+ case SMB_ACL_GROUP:
+ hpux_tag = GROUP;
+ break;
+ case SMB_ACL_GROUP_OBJ:
+ hpux_tag = GROUP_OBJ;
+ break;
+ case SMB_ACL_OTHER:
+ hpux_tag = OTHER_OBJ;
+ break;
+ case SMB_ACL_MASK:
+ hpux_tag = CLASS_OBJ;
+ break;
+ default:
+ DEBUGADD(10, (" !!! unknown smb tag type 0x%04x\n", smb_tag));
+ break;
+ }
+
+ DEBUGADD(10, (" --> determined hpux tag 0x%04x\n", hpux_tag));
+
+ return hpux_tag;
+}
+
+static SMB_ACL_TAG_T hpux_tag_to_smb_tag(HPUX_ACL_TAG_T hpux_tag)
+{
+ SMB_ACL_TAG_T smb_tag = 0;
+
+ DEBUG(10, ("hpux_tag_to_smb_tag:\n"));
+ DEBUGADD(10, (" --> got hpux tag 0x%04x\n", hpux_tag));
+
+ hpux_tag &= ~ACL_DEFAULT;
+
+ switch (hpux_tag) {
+ case USER:
+ smb_tag = SMB_ACL_USER;
+ break;
+ case USER_OBJ:
+ smb_tag = SMB_ACL_USER_OBJ;
+ break;
+ case GROUP:
+ smb_tag = SMB_ACL_GROUP;
+ break;
+ case GROUP_OBJ:
+ smb_tag = SMB_ACL_GROUP_OBJ;
+ break;
+ case OTHER_OBJ:
+ smb_tag = SMB_ACL_OTHER;
+ break;
+ case CLASS_OBJ:
+ smb_tag = SMB_ACL_MASK;
+ break;
+ default:
+ DEBUGADD(10, (" !!! unknown hpux tag type: 0x%04x\n",
+ hpux_tag));
+ break;
+ }
+
+ DEBUGADD(10, (" --> determined smb tag 0x%04x\n", smb_tag));
+
+ return smb_tag;
+}
+
+
+/*
+ * The permission bits used in the following two permission conversion
+ * functions are same, but the functions make us independent of the concrete
+ * permission data types.
+ */
+static SMB_ACL_PERM_T hpux_perm_to_smb_perm(const HPUX_PERM_T perm)
+{
+ SMB_ACL_PERM_T smb_perm = 0;
+ smb_perm |= ((perm & SMB_ACL_READ) ? SMB_ACL_READ : 0);
+ smb_perm |= ((perm & SMB_ACL_WRITE) ? SMB_ACL_WRITE : 0);
+ smb_perm |= ((perm & SMB_ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
+ return smb_perm;
+}
+
+
+static HPUX_PERM_T smb_perm_to_hpux_perm(const SMB_ACL_PERM_T perm)
+{
+ HPUX_PERM_T hpux_perm = 0;
+ hpux_perm |= ((perm & SMB_ACL_READ) ? SMB_ACL_READ : 0);
+ hpux_perm |= ((perm & SMB_ACL_WRITE) ? SMB_ACL_WRITE : 0);
+ hpux_perm |= ((perm & SMB_ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
+ return hpux_perm;
+}
+
+
+static bool hpux_acl_get_file(const char *name, HPUX_ACL_T *hpux_acl,
+ int *count)
+{
+ bool result = False;
+ static HPUX_ACE_T dummy_ace;
+
+ DEBUG(10, ("hpux_acl_get_file called for file '%s'\n", name));
+
+ /*
+ * The original code tries some INITIAL_ACL_SIZE
+ * and only did the ACL_CNT call upon failure
+ * (for performance reasons).
+ * For the sake of simplicity, I skip this for now.
+ *
+ * NOTE: There is a catch here on HP-UX: acl with cmd parameter
+ * ACL_CNT fails with errno EINVAL when called with a NULL
+ * pointer as last argument. So we need to use a dummy acl
+ * struct here (we make it static so it does not need to be
+ * instantiated or malloced each time this function is
+ * called). Btw: the count parameter does not seem to matter...
+ */
+ *count = acl(CONST_DISCARD(char *, name), ACL_CNT, 0, &dummy_ace);
+ if (*count < 0) {
+ DEBUG(10, ("acl ACL_CNT failed: %s\n", strerror(errno)));
+ goto done;
+ }
+ *hpux_acl = hpux_acl_init(*count);
+ if (*hpux_acl == NULL) {
+ DEBUG(10, ("error allocating memory for hpux acl...\n"));
+ goto done;
+ }
+ *count = acl(CONST_DISCARD(char *, name), ACL_GET, *count, *hpux_acl);
+ if (*count < 0) {
+ DEBUG(10, ("acl ACL_GET failed: %s\n", strerror(errno)));
+ goto done;
+ }
+ result = True;
+
+ done:
+ DEBUG(10, ("hpux_acl_get_file %s.\n",
+ ((result == True) ? "succeeded" : "failed" )));
+ return result;
+}
+
+
+
+
+/*
+ * Add entries to a hpux ACL.
+ *
+ * Entries are directly added to the hpuxacl parameter.
+ * if memory allocation fails, this may result in hpuxacl
+ * being NULL. if the resulting acl is to be checked and is
+ * not valid, it is kept in hpuxacl but False is returned.
+ *
+ * The type of ACEs (access/default) to be added to the ACL can
+ * be selected via the type parameter.
+ * I use the SMB_ACL_TYPE_T type here. Since SMB_ACL_TYPE_ACCESS
+ * is defined as "0", this means that one can only add either
+ * access or default ACEs from the given ACL, not both at the same
+ * time. If it should become necessary to add all of an ACL, one
+ * would have to replace this parameter by another type.
+ */
+static bool hpux_add_to_acl(HPUX_ACL_T *hpux_acl, int *count,
+ HPUX_ACL_T add_acl, int add_count,
+ SMB_ACL_TYPE_T type)
+{
+ int i;
+
+ if ((type != SMB_ACL_TYPE_ACCESS) && (type != SMB_ACL_TYPE_DEFAULT))
+ {
+ DEBUG(10, ("invalid acl type given: %d\n", type));
+ errno = EINVAL;
+ return False;
+ }
+ for (i = 0; i < add_count; i++) {
+ if (!_IS_OF_TYPE(add_acl[i], type)) {
+ continue;
+ }
+ ADD_TO_ARRAY(NULL, HPUX_ACE_T, add_acl[i],
+ hpux_acl, count);
+ if (hpux_acl == NULL) {
+ DEBUG(10, ("error enlarging acl.\n"));
+ errno = ENOMEM;
+ return False;
+ }
+ }
+ return True;
+}
+
+
+/*
+ * sort the ACL and check it for validity
+ *
+ * [original comment from lib/sysacls.c:]
+ *
+ * if it's a minimal ACL with only 4 entries then we
+ * need to recalculate the mask permissions to make
+ * sure that they are the same as the GROUP_OBJ
+ * permissions as required by the UnixWare acl() system call.
+ *
+ * (note: since POSIX allows minimal ACLs which only contain
+ * 3 entries - ie there is no mask entry - we should, in theory,
+ * check for this and add a mask entry if necessary - however
+ * we "know" that the caller of this interface always specifies
+ * a mask, so in practice "this never happens" (tm) - if it *does*
+ * happen aclsort() will fail and return an error and someone will
+ * have to fix it...)
+ */
+static bool hpux_acl_sort(HPUX_ACL_T hpux_acl, int count)
+{
+ int fixmask = (count <= 4);
+
+ if (hpux_internal_aclsort(count, fixmask, hpux_acl) != 0) {
+ errno = EINVAL;
+ return False;
+ }
+ return True;
+}
+
+
+/*
+ * Helpers for hpux_internal_aclsort:
+ * - hpux_count_obj
+ * - hpux_swap_acl_entries
+ * - hpux_prohibited_duplicate_type
+ * - hpux_get_needed_class_perm
+ */
+
+/* hpux_count_obj:
+ * Counts the different number of objects in a given array of ACL
+ * structures.
+ * Inputs:
+ *
+ * acl_count - Count of ACLs in the array of ACL strucutres.
+ * aclp - Array of ACL structures.
+ * acl_type_count - Pointer to acl_types structure. Should already be
+ * allocated.
+ * Output:
+ *
+ * acl_type_count - This structure is filled up with counts of various
+ * acl types.
+ */
+
+static void hpux_count_obj(int acl_count, HPUX_ACL_T aclp, struct hpux_acl_types *acl_type_count)
+{
+ int i;
+
+ memset(acl_type_count, 0, sizeof(struct hpux_acl_types));
+
+ for(i=0;i<acl_count;i++) {
+ switch(aclp[i].a_type) {
+ case USER:
+ acl_type_count->n_user++;
+ break;
+ case USER_OBJ:
+ acl_type_count->n_user_obj++;
+ break;
+ case DEF_USER_OBJ:
+ acl_type_count->n_def_user_obj++;
+ break;
+ case GROUP:
+ acl_type_count->n_group++;
+ break;
+ case GROUP_OBJ:
+ acl_type_count->n_group_obj++;
+ break;
+ case DEF_GROUP_OBJ:
+ acl_type_count->n_def_group_obj++;
+ break;
+ case OTHER_OBJ:
+ acl_type_count->n_other_obj++;
+ break;
+ case DEF_OTHER_OBJ:
+ acl_type_count->n_def_other_obj++;
+ break;
+ case CLASS_OBJ:
+ acl_type_count->n_class_obj++;
+ break;
+ case DEF_CLASS_OBJ:
+ acl_type_count->n_def_class_obj++;
+ break;
+ case DEF_USER:
+ acl_type_count->n_def_user++;
+ break;
+ case DEF_GROUP:
+ acl_type_count->n_def_group++;
+ break;
+ default:
+ acl_type_count->n_illegal_obj++;
+ break;
+ }
+ }
+}
+
+/* hpux_swap_acl_entries: Swaps two ACL entries.
+ *
+ * Inputs: aclp0, aclp1 - ACL entries to be swapped.
+ */
+
+static void hpux_swap_acl_entries(HPUX_ACE_T *aclp0, HPUX_ACE_T *aclp1)
+{
+ HPUX_ACE_T temp_acl;
+
+ temp_acl.a_type = aclp0->a_type;
+ temp_acl.a_id = aclp0->a_id;
+ temp_acl.a_perm = aclp0->a_perm;
+
+ aclp0->a_type = aclp1->a_type;
+ aclp0->a_id = aclp1->a_id;
+ aclp0->a_perm = aclp1->a_perm;
+
+ aclp1->a_type = temp_acl.a_type;
+ aclp1->a_id = temp_acl.a_id;
+ aclp1->a_perm = temp_acl.a_perm;
+}
+
+/* hpux_prohibited_duplicate_type
+ * Identifies if given ACL type can have duplicate entries or
+ * not.
+ *
+ * Inputs: acl_type - ACL Type.
+ *
+ * Outputs:
+ *
+ * Return..
+ *
+ * True - If the ACL type matches any of the prohibited types.
+ * False - If the ACL type doesn't match any of the prohibited types.
+ */
+
+static bool hpux_prohibited_duplicate_type(int acl_type)
+{
+ switch(acl_type) {
+ case USER:
+ case GROUP:
+ case DEF_USER:
+ case DEF_GROUP:
+ return True;
+ default:
+ return False;
+ }
+}
+
+/* hpux_get_needed_class_perm
+ * Returns the permissions of a ACL structure only if the ACL
+ * type matches one of the pre-determined types for computing
+ * CLASS_OBJ permissions.
+ *
+ * Inputs: aclp - Pointer to ACL structure.
+ */
+
+static int hpux_get_needed_class_perm(struct acl *aclp)
+{
+ switch(aclp->a_type) {
+ case USER:
+ case GROUP_OBJ:
+ case GROUP:
+ case DEF_USER_OBJ:
+ case DEF_USER:
+ case DEF_GROUP_OBJ:
+ case DEF_GROUP:
+ case DEF_CLASS_OBJ:
+ case DEF_OTHER_OBJ:
+ return aclp->a_perm;
+ default:
+ return 0;
+ }
+}
+
+/* hpux_internal_aclsort: aclsort for HPUX.
+ *
+ * -> The aclsort() system call is availabe on the latest HPUX General
+ * -> Patch Bundles. So for HPUX, we developed our version of aclsort
+ * -> function. Because, we don't want to update to a new
+ * -> HPUX GR bundle just for aclsort() call.
+ *
+ * aclsort sorts the array of ACL structures as per the description in
+ * aclsort man page. Refer to aclsort man page for more details
+ *
+ * Inputs:
+ *
+ * acl_count - Count of ACLs in the array of ACL structures.
+ * calclass - If this is not zero, then we compute the CLASS_OBJ
+ * permissions.
+ * aclp - Array of ACL structures.
+ *
+ * Outputs:
+ *
+ * aclp - Sorted array of ACL structures.
+ *
+ * Outputs:
+ *
+ * Returns 0 for success -1 for failure. Prints a message to the Samba
+ * debug log in case of failure.
+ */
+
+static int hpux_internal_aclsort(int acl_count, int calclass, HPUX_ACL_T aclp)
+{
+ struct hpux_acl_types acl_obj_count;
+ int n_class_obj_perm = 0;
+ int i, j;
+
+ DEBUG(10,("Entering hpux_internal_aclsort. (calclass = %d)\n", calclass));
+
+ if (hpux_aclsort_call_present()) {
+ DEBUG(10, ("calling hpux aclsort\n"));
+ return aclsort(acl_count, calclass, aclp);
+ }
+
+ DEBUG(10, ("using internal aclsort\n"));
+
+ if(!acl_count) {
+ DEBUG(10,("Zero acl count passed. Returning Success\n"));
+ return 0;
+ }
+
+ if(aclp == NULL) {
+ DEBUG(0,("Null ACL pointer in hpux_acl_sort. Returning Failure. \n"));
+ return -1;
+ }
+
+ /* Count different types of ACLs in the ACLs array */
+
+ hpux_count_obj(acl_count, aclp, &acl_obj_count);
+
+ /* There should be only one entry each of type USER_OBJ, GROUP_OBJ,
+ * CLASS_OBJ and OTHER_OBJ
+ */
+
+ if ( (acl_obj_count.n_user_obj != 1) ||
+ (acl_obj_count.n_group_obj != 1) ||
+ (acl_obj_count.n_class_obj != 1) ||
+ (acl_obj_count.n_other_obj != 1) )
+ {
+ DEBUG(0,("hpux_internal_aclsort: More than one entry or no entries for \
+USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n"));
+ return -1;
+ }
+
+ /* If any of the default objects are present, there should be only
+ * one of them each.
+ */
+
+ if ( (acl_obj_count.n_def_user_obj > 1) ||
+ (acl_obj_count.n_def_group_obj > 1) ||
+ (acl_obj_count.n_def_other_obj > 1) ||
+ (acl_obj_count.n_def_class_obj > 1) )
+ {
+ DEBUG(0,("hpux_internal_aclsort: More than one entry for DEF_CLASS_OBJ \
+or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
+ return -1;
+ }
+
+ /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl
+ * structures.
+ *
+ * Sorting crieteria - First sort by ACL type. If there are multiple entries of
+ * same ACL type, sort by ACL id.
+ *
+ * I am using the trival kind of sorting method here because, performance isn't
+ * really effected by the ACLs feature. More over there aren't going to be more
+ * than 17 entries on HPUX.
+ */
+
+ for(i=0; i<acl_count;i++) {
+ for (j=i+1; j<acl_count; j++) {
+ if( aclp[i].a_type > aclp[j].a_type ) {
+ /* ACL entries out of order, swap them */
+ hpux_swap_acl_entries((aclp+i), (aclp+j));
+ } else if ( aclp[i].a_type == aclp[j].a_type ) {
+ /* ACL entries of same type, sort by id */
+ if(aclp[i].a_id > aclp[j].a_id) {
+ hpux_swap_acl_entries((aclp+i), (aclp+j));
+ } else if (aclp[i].a_id == aclp[j].a_id) {
+ /* We have a duplicate entry. */
+ if(hpux_prohibited_duplicate_type(aclp[i].a_type)) {
+ DEBUG(0, ("hpux_internal_aclsort: Duplicate entry: Type(hex): %x Id: %d\n",
+ aclp[i].a_type, aclp[i].a_id));
+ return -1;
+ }
+ }
+ }
+ }
+ }
+
+ /* set the class obj permissions to the computed one. */
+ if(calclass) {
+ int n_class_obj_index = -1;
+
+ for(i=0;i<acl_count;i++) {
+ n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i));
+
+ if(aclp[i].a_type == CLASS_OBJ)
+ n_class_obj_index = i;
+ }
+ aclp[n_class_obj_index].a_perm = n_class_obj_perm;
+ }
+
+ return 0;
+}
+
+
+/*
+ * hpux_acl_call_present:
+ *
+ * This checks if the POSIX ACL system call is defined
+ * which basically corresponds to whether JFS 3.3 or
+ * higher is installed. If acl() was called when it
+ * isn't defined, it causes the process to core dump
+ * so it is important to check this and avoid acl()
+ * calls if it isn't there.
+ */
+
+static bool hpux_acl_call_present(void)
+{
+
+ shl_t handle = NULL;
+ void *value;
+ int ret_val=0;
+ static bool already_checked = False;
+
+ if(already_checked)
+ return True;
+
+ errno = 0;
+
+ ret_val = shl_findsym(&handle, "acl", TYPE_PROCEDURE, &value);
+
+ if(ret_val != 0) {
+ DEBUG(5, ("hpux_acl_call_present: shl_findsym() returned %d, errno = %d, error %s\n",
+ ret_val, errno, strerror(errno)));
+ DEBUG(5,("hpux_acl_call_present: acl() system call is not present. Check if you have JFS 3.3 and above?\n"));
+ errno = ENOSYS;
+ return False;
+ }
+
+ DEBUG(10,("hpux_acl_call_present: acl() system call is present. We have JFS 3.3 or above \n"));
+
+ already_checked = True;
+ return True;
+}
+
+/*
+ * runtime check for presence of aclsort library call.
+ * same code as for acl call. if there are more of these,
+ * a dispatcher function could be handy...
+ */
+
+static bool hpux_aclsort_call_present(void)
+{
+ shl_t handle = NULL;
+ void *value;
+ int ret_val = 0;
+ static bool already_checked = False;
+
+ if (already_checked) {
+ return True;
+ }
+
+ errno = 0;
+ ret_val = shl_findsym(&handle, "aclsort", TYPE_PROCEDURE, &value);
+ if (ret_val != 0) {
+ DEBUG(5, ("hpux_aclsort_call_present: shl_findsym "
+ "returned %d, errno = %d, error %s",
+ ret_val, errno, strerror(errno)));
+ DEBUG(5, ("hpux_aclsort_call_present: "
+ "aclsort() function not available.\n"));
+ return False;
+ }
+ DEBUG(10,("hpux_aclsort_call_present: aclsort() function present.\n"));
+ already_checked = True;
+ return True;
+}
+
+#if 0
+/*
+ * acl check function:
+ * unused at the moment but could be used to get more
+ * concrete error messages for debugging...
+ * (acl sort just says that the acl is invalid...)
+ */
+static bool hpux_acl_check(HPUX_ACL_T hpux_acl, int count)
+{
+ int check_rc;
+ int check_which;
+
+ check_rc = aclcheck(hpux_acl, count, &check_which);
+ if (check_rc != 0) {
+ DEBUG(10, ("acl is not valid:\n"));
+ DEBUGADD(10, (" - return code: %d\n", check_rc));
+ DEBUGADD(10, (" - which: %d\n", check_which));
+ if (check_which != -1) {
+ DEBUGADD(10, (" - invalid entry:\n"));
+ DEBUGADD(10, (" * type: %d:\n",
+ hpux_acl[check_which].a_type));
+ DEBUGADD(10, (" * id: %d\n",
+ hpux_acl[check_which].a_id));
+ DEBUGADD(10, (" * perm: 0o%o\n",
+ hpux_acl[check_which].a_perm));
+ }
+ return False;
+ }
+ return True;
+}
+#endif
+
+/* VFS operations structure */
+
+static vfs_op_tuple hpuxacl_op_tuples[] = {
+ /* Disk operations */
+ {SMB_VFS_OP(hpuxacl_sys_acl_get_file),
+ SMB_VFS_OP_SYS_ACL_GET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(hpuxacl_sys_acl_get_fd),
+ SMB_VFS_OP_SYS_ACL_GET_FD,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(hpuxacl_sys_acl_set_file),
+ SMB_VFS_OP_SYS_ACL_SET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(hpuxacl_sys_acl_set_fd),
+ SMB_VFS_OP_SYS_ACL_SET_FD,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(hpuxacl_sys_acl_delete_def_file),
+ SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(NULL),
+ SMB_VFS_OP_NOOP,
+ SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_hpuxacl_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "hpuxacl",
+ hpuxacl_op_tuples);
+}
+
+/* ENTE */
diff --git a/source3/modules/vfs_hpuxacl.h b/source3/modules/vfs_hpuxacl.h
new file mode 100644
index 0000000000..07b32d628c
--- /dev/null
+++ b/source3/modules/vfs_hpuxacl.h
@@ -0,0 +1,58 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * VFS module to get and set HP-UX ACLs - prototype header
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This module supports JFS (POSIX) ACLs on VxFS (Veritas * Filesystem).
+ * These are available on HP-UX 11.00 if JFS 3.3 is installed.
+ * On HP-UX 11i (11.11 and above) these ACLs are supported out of
+ * the box.
+ *
+ * There is another form of ACLs on HFS. These ACLs have a
+ * completely different API and their own set of userland tools.
+ * Since HFS seems to be considered deprecated, HFS acls
+ * are not supported. (They could be supported through a separate
+ * vfs-module if there is demand.)
+ */
+
+#ifndef __VFS_HPUXACL_H__
+#define __VFS_HPUXACL_H__
+
+SMB_ACL_T hpuxacl_sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ SMB_ACL_TYPE_T type);
+
+SMB_ACL_T hpuxacl_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp);
+
+int hpuxacl_sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl);
+
+int hpuxacl_sys_acl_set_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_T theacl);
+
+int hpuxacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path);
+
+NTSTATUS vfs_hpuxacl_init(void);
+
+#endif
+
diff --git a/source3/modules/vfs_irixacl.c b/source3/modules/vfs_irixacl.c
new file mode 100644
index 0000000000..6484e8f3eb
--- /dev/null
+++ b/source3/modules/vfs_irixacl.c
@@ -0,0 +1,103 @@
+/*
+ Unix SMB/Netbios implementation.
+ VFS module to get and set irix acls
+ Copyright (C) Michael Adam 2006,2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* prototypes for private functions first - for clarity */
+
+/* public functions - the api */
+
+SMB_ACL_T irixacl_sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ SMB_ACL_TYPE_T type)
+{
+ errno = ENOTSUP;
+ return NULL;
+}
+
+SMB_ACL_T irixacl_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp)
+{
+ errno = ENOTSUP;
+ return NULL;
+}
+
+int irixacl_sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+int irixacl_sys_acl_set_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_T theacl)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+int irixacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+/* private functions */
+
+/* VFS operations structure */
+
+static vfs_op_tuple irixacl_op_tuples[] = {
+ /* Disk operations */
+ {SMB_VFS_OP(irixacl_sys_acl_get_file),
+ SMB_VFS_OP_SYS_ACL_GET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(irixacl_sys_acl_get_fd),
+ SMB_VFS_OP_SYS_ACL_GET_FD,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(irixacl_sys_acl_set_file),
+ SMB_VFS_OP_SYS_ACL_SET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(irixacl_sys_acl_set_fd),
+ SMB_VFS_OP_SYS_ACL_SET_FD,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(irixacl_sys_acl_delete_def_file),
+ SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(NULL),
+ SMB_VFS_OP_NOOP,
+ SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_irixacl_init(void);
+NTSTATUS vfs_irixacl_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "irixacl",
+ irixacl_op_tuples);
+}
+
+/* ENTE */
diff --git a/source3/modules/vfs_irixacl.h b/source3/modules/vfs_irixacl.h
new file mode 100644
index 0000000000..2a4abd94fc
--- /dev/null
+++ b/source3/modules/vfs_irixacl.h
@@ -0,0 +1,45 @@
+/*
+ Unix SMB/Netbios implementation.
+ VFS module to get and set irix acls - prototype header
+ Copyright (C) Michael Adam 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __VFS_IRIXACL_H__
+#define __VFS_IRIXACL_H__
+
+SMB_ACL_T irixacl_sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ SMB_ACL_TYPE_T type);
+
+SMB_ACL_T irixacl_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp);
+
+int irixacl_sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl);
+
+int irixacl_sys_acl_set_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_T theacl);
+
+int irixacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path);
+
+NTSTATUS vfs_irixacl_init(void);
+
+#endif
+
diff --git a/source3/modules/vfs_netatalk.c b/source3/modules/vfs_netatalk.c
new file mode 100644
index 0000000000..2cc4a6c4ba
--- /dev/null
+++ b/source3/modules/vfs_netatalk.c
@@ -0,0 +1,433 @@
+/*
+ * AppleTalk VFS module for Samba-3.x
+ *
+ * Copyright (C) Alexei Kotovich, 2002
+ * Copyright (C) Stefan (metze) Metzmacher, 2003
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+#define APPLEDOUBLE ".AppleDouble"
+#define ADOUBLEMODE 0777
+
+/* atalk functions */
+
+static int atalk_build_paths(TALLOC_CTX *ctx, const char *path,
+ const char *fname, char **adbl_path, char **orig_path,
+ SMB_STRUCT_STAT *adbl_info, SMB_STRUCT_STAT *orig_info);
+
+static int atalk_unlink_file(const char *path);
+
+static int atalk_get_path_ptr(char *path)
+{
+ int i = 0;
+ int ptr = 0;
+
+ for (i = 0; path[i]; i ++) {
+ if (path[i] == '/')
+ ptr = i;
+ /* get out some 'spam';) from win32's file name */
+ else if (path[i] == ':') {
+ path[i] = '\0';
+ break;
+ }
+ }
+
+ return ptr;
+}
+
+static int atalk_build_paths(TALLOC_CTX *ctx, const char *path, const char *fname,
+ char **adbl_path, char **orig_path,
+ SMB_STRUCT_STAT *adbl_info, SMB_STRUCT_STAT *orig_info)
+{
+ int ptr0 = 0;
+ int ptr1 = 0;
+ char *dname = 0;
+ char *name = 0;
+
+ if (!ctx || !path || !fname || !adbl_path || !orig_path ||
+ !adbl_info || !orig_info)
+ return -1;
+#if 0
+ DEBUG(3, ("ATALK: PATH: %s[%s]\n", path, fname));
+#endif
+ if (strstr(path, APPLEDOUBLE) || strstr(fname, APPLEDOUBLE)) {
+ DEBUG(3, ("ATALK: path %s[%s] already contains %s\n", path, fname, APPLEDOUBLE));
+ return -1;
+ }
+
+ if (fname[0] == '.') ptr0 ++;
+ if (fname[1] == '/') ptr0 ++;
+
+ *orig_path = talloc_asprintf(ctx, "%s/%s", path, &fname[ptr0]);
+
+ /* get pointer to last '/' */
+ ptr1 = atalk_get_path_ptr(*orig_path);
+
+ sys_lstat(*orig_path, orig_info);
+
+ if (S_ISDIR(orig_info->st_mode)) {
+ *adbl_path = talloc_asprintf(ctx, "%s/%s/%s/",
+ path, &fname[ptr0], APPLEDOUBLE);
+ } else {
+ dname = talloc_strdup(ctx, *orig_path);
+ dname[ptr1] = '\0';
+ name = *orig_path;
+ *adbl_path = talloc_asprintf(ctx, "%s/%s/%s",
+ dname, APPLEDOUBLE, &name[ptr1 + 1]);
+ }
+#if 0
+ DEBUG(3, ("ATALK: DEBUG:\n%s\n%s\n", *orig_path, *adbl_path));
+#endif
+ sys_lstat(*adbl_path, adbl_info);
+ return 0;
+}
+
+static int atalk_unlink_file(const char *path)
+{
+ int ret = 0;
+
+ become_root();
+ ret = unlink(path);
+ unbecome_root();
+
+ return ret;
+}
+
+static void atalk_add_to_list(name_compare_entry **list)
+{
+ int i, count = 0;
+ name_compare_entry *new_list = 0;
+ name_compare_entry *cur_list = 0;
+
+ cur_list = *list;
+
+ if (cur_list) {
+ for (i = 0, count = 0; cur_list[i].name; i ++, count ++) {
+ if (strstr(cur_list[i].name, APPLEDOUBLE))
+ return;
+ }
+ }
+
+ if (!(new_list = SMB_CALLOC_ARRAY(name_compare_entry, (count == 0 ? 1 : count + 1))))
+ return;
+
+ for (i = 0; i < count; i ++) {
+ new_list[i].name = SMB_STRDUP(cur_list[i].name);
+ new_list[i].is_wild = cur_list[i].is_wild;
+ }
+
+ new_list[i].name = SMB_STRDUP(APPLEDOUBLE);
+ new_list[i].is_wild = False;
+
+ free_namearray(*list);
+
+ *list = new_list;
+ new_list = 0;
+ cur_list = 0;
+}
+
+static void atalk_rrmdir(TALLOC_CTX *ctx, char *path)
+{
+ char *dpath;
+ SMB_STRUCT_DIRENT *dent = 0;
+ SMB_STRUCT_DIR *dir;
+
+ if (!path) return;
+
+ dir = sys_opendir(path);
+ if (!dir) return;
+
+ while (NULL != (dent = sys_readdir(dir))) {
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+ if (!(dpath = talloc_asprintf(ctx, "%s/%s",
+ path, dent->d_name)))
+ continue;
+ atalk_unlink_file(dpath);
+ }
+
+ sys_closedir(dir);
+}
+
+/* Disk operations */
+
+/* Directory operations */
+
+static SMB_STRUCT_DIR *atalk_opendir(struct vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr)
+{
+ SMB_STRUCT_DIR *ret = 0;
+
+ ret = SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
+
+ /*
+ * when we try to perform delete operation upon file which has fork
+ * in ./.AppleDouble and this directory wasn't hidden by Samba,
+ * MS Windows explorer causes the error: "Cannot find the specified file"
+ * There is some workaround to avoid this situation, i.e. if
+ * connection has not .AppleDouble entry in either veto or hide
+ * list then it would be nice to add one.
+ */
+
+ atalk_add_to_list(&handle->conn->hide_list);
+ atalk_add_to_list(&handle->conn->veto_list);
+
+ return ret;
+}
+
+static int atalk_rmdir(struct vfs_handle_struct *handle, const char *path)
+{
+ bool add = False;
+ TALLOC_CTX *ctx = 0;
+ char *dpath;
+
+ if (!handle->conn->origpath || !path) goto exit_rmdir;
+
+ /* due to there is no way to change bDeleteVetoFiles variable
+ * from this module, gotta use talloc stuff..
+ */
+
+ strstr(path, APPLEDOUBLE) ? (add = False) : (add = True);
+
+ if (!(ctx = talloc_init("remove_directory")))
+ goto exit_rmdir;
+
+ if (!(dpath = talloc_asprintf(ctx, "%s/%s%s",
+ handle->conn->origpath, path, add ? "/"APPLEDOUBLE : "")))
+ goto exit_rmdir;
+
+ atalk_rrmdir(ctx, dpath);
+
+exit_rmdir:
+ talloc_destroy(ctx);
+ return SMB_VFS_NEXT_RMDIR(handle, path);
+}
+
+/* File operations */
+
+static int atalk_rename(struct vfs_handle_struct *handle, const char *oldname, const char *newname)
+{
+ int ret = 0;
+ char *adbl_path = 0;
+ char *orig_path = 0;
+ SMB_STRUCT_STAT adbl_info;
+ SMB_STRUCT_STAT orig_info;
+ TALLOC_CTX *ctx;
+
+ ret = SMB_VFS_NEXT_RENAME(handle, oldname, newname);
+
+ if (!oldname) return ret;
+
+ if (!(ctx = talloc_init("rename_file")))
+ return ret;
+
+ if (atalk_build_paths(ctx, handle->conn->origpath, oldname, &adbl_path, &orig_path,
+ &adbl_info, &orig_info) != 0)
+ goto exit_rename;
+
+ if (S_ISDIR(orig_info.st_mode) || S_ISREG(orig_info.st_mode)) {
+ DEBUG(3, ("ATALK: %s has passed..\n", adbl_path));
+ goto exit_rename;
+ }
+
+ atalk_unlink_file(adbl_path);
+
+exit_rename:
+ talloc_destroy(ctx);
+ return ret;
+}
+
+static int atalk_unlink(struct vfs_handle_struct *handle, const char *path)
+{
+ int ret = 0, i;
+ char *adbl_path = 0;
+ char *orig_path = 0;
+ SMB_STRUCT_STAT adbl_info;
+ SMB_STRUCT_STAT orig_info;
+ TALLOC_CTX *ctx;
+
+ ret = SMB_VFS_NEXT_UNLINK(handle, path);
+
+ if (!path) return ret;
+
+ /* no .AppleDouble sync if veto or hide list is empty,
+ * otherwise "Cannot find the specified file" error will be caused
+ */
+
+ if (!handle->conn->veto_list) return ret;
+ if (!handle->conn->hide_list) return ret;
+
+ for (i = 0; handle->conn->veto_list[i].name; i ++) {
+ if (strstr(handle->conn->veto_list[i].name, APPLEDOUBLE))
+ break;
+ }
+
+ if (!handle->conn->veto_list[i].name) {
+ for (i = 0; handle->conn->hide_list[i].name; i ++) {
+ if (strstr(handle->conn->hide_list[i].name, APPLEDOUBLE))
+ break;
+ else {
+ DEBUG(3, ("ATALK: %s is not hidden, skipped..\n",
+ APPLEDOUBLE));
+ return ret;
+ }
+ }
+ }
+
+ if (!(ctx = talloc_init("unlink_file")))
+ return ret;
+
+ if (atalk_build_paths(ctx, handle->conn->origpath, path, &adbl_path, &orig_path,
+ &adbl_info, &orig_info) != 0)
+ goto exit_unlink;
+
+ if (S_ISDIR(orig_info.st_mode) || S_ISREG(orig_info.st_mode)) {
+ DEBUG(3, ("ATALK: %s has passed..\n", adbl_path));
+ goto exit_unlink;
+ }
+
+ atalk_unlink_file(adbl_path);
+
+exit_unlink:
+ talloc_destroy(ctx);
+ return ret;
+}
+
+static int atalk_chmod(struct vfs_handle_struct *handle, const char *path, mode_t mode)
+{
+ int ret = 0;
+ char *adbl_path = 0;
+ char *orig_path = 0;
+ SMB_STRUCT_STAT adbl_info;
+ SMB_STRUCT_STAT orig_info;
+ TALLOC_CTX *ctx;
+
+ ret = SMB_VFS_NEXT_CHMOD(handle, path, mode);
+
+ if (!path) return ret;
+
+ if (!(ctx = talloc_init("chmod_file")))
+ return ret;
+
+ if (atalk_build_paths(ctx, handle->conn->origpath, path, &adbl_path, &orig_path,
+ &adbl_info, &orig_info) != 0)
+ goto exit_chmod;
+
+ if (!S_ISDIR(orig_info.st_mode) && !S_ISREG(orig_info.st_mode)) {
+ DEBUG(3, ("ATALK: %s has passed..\n", orig_path));
+ goto exit_chmod;
+ }
+
+ chmod(adbl_path, ADOUBLEMODE);
+
+exit_chmod:
+ talloc_destroy(ctx);
+ return ret;
+}
+
+static int atalk_chown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
+{
+ int ret = 0;
+ char *adbl_path = 0;
+ char *orig_path = 0;
+ SMB_STRUCT_STAT adbl_info;
+ SMB_STRUCT_STAT orig_info;
+ TALLOC_CTX *ctx;
+
+ ret = SMB_VFS_NEXT_CHOWN(handle, path, uid, gid);
+
+ if (!path) return ret;
+
+ if (!(ctx = talloc_init("chown_file")))
+ return ret;
+
+ if (atalk_build_paths(ctx, handle->conn->origpath, path, &adbl_path, &orig_path,
+ &adbl_info, &orig_info) != 0)
+ goto exit_chown;
+
+ if (!S_ISDIR(orig_info.st_mode) && !S_ISREG(orig_info.st_mode)) {
+ DEBUG(3, ("ATALK: %s has passed..\n", orig_path));
+ goto exit_chown;
+ }
+
+ chown(adbl_path, uid, gid);
+
+exit_chown:
+ talloc_destroy(ctx);
+ return ret;
+}
+
+static int atalk_lchown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
+{
+ int ret = 0;
+ char *adbl_path = 0;
+ char *orig_path = 0;
+ SMB_STRUCT_STAT adbl_info;
+ SMB_STRUCT_STAT orig_info;
+ TALLOC_CTX *ctx;
+
+ ret = SMB_VFS_NEXT_CHOWN(handle, path, uid, gid);
+
+ if (!path) return ret;
+
+ if (!(ctx = talloc_init("lchown_file")))
+ return ret;
+
+ if (atalk_build_paths(ctx, handle->conn->origpath, path, &adbl_path, &orig_path,
+ &adbl_info, &orig_info) != 0)
+ goto exit_lchown;
+
+ if (!S_ISDIR(orig_info.st_mode) && !S_ISREG(orig_info.st_mode)) {
+ DEBUG(3, ("ATALK: %s has passed..\n", orig_path));
+ goto exit_lchown;
+ }
+
+ sys_lchown(adbl_path, uid, gid);
+
+exit_lchown:
+ talloc_destroy(ctx);
+ return ret;
+}
+
+static vfs_op_tuple atalk_ops[] = {
+
+ /* Directory operations */
+
+ {SMB_VFS_OP(atalk_opendir), SMB_VFS_OP_OPENDIR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(atalk_rmdir), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* File operations */
+
+ {SMB_VFS_OP(atalk_rename), SMB_VFS_OP_RENAME, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(atalk_unlink), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(atalk_chmod), SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(atalk_chown), SMB_VFS_OP_CHOWN, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(atalk_lchown), SMB_VFS_OP_LCHOWN, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* Finish VFS operations definition */
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_netatalk_init(void);
+NTSTATUS vfs_netatalk_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "netatalk", atalk_ops);
+}
diff --git a/source3/modules/vfs_notify_fam.c b/source3/modules/vfs_notify_fam.c
new file mode 100644
index 0000000000..aacc52e68c
--- /dev/null
+++ b/source3/modules/vfs_notify_fam.c
@@ -0,0 +1,304 @@
+/*
+ * FAM file notification support.
+ *
+ * Copyright (c) James Peach 2005
+ * Copyright (c) Volker Lendecke 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#include <fam.h>
+
+#if !defined(HAVE_FAM_H_FAMCODES_TYPEDEF)
+/* Gamin provides this typedef which means we can't use 'enum FAMCodes' as per
+ * every other FAM implementation. Phooey.
+ */
+typedef enum FAMCodes FAMCodes;
+#endif
+
+/* NOTE: There are multiple versions of FAM floating around the net, each with
+ * slight differences from the original SGI FAM implementation. In this file,
+ * we rely only on the SGI features and do not assume any extensions. For
+ * example, we do not look at FAMErrno, because it is not set by the original
+ * implementation.
+ *
+ * Random FAM links:
+ * http://oss.sgi.com/projects/fam/
+ * http://savannah.nongnu.org/projects/fam/
+ * http://sourceforge.net/projects/bsdfam/
+ */
+
+/* ------------------------------------------------------------------------- */
+
+struct fam_watch_context {
+ struct fam_watch_context *prev, *next;
+ FAMConnection *fam_connection;
+ struct FAMRequest fr;
+ struct sys_notify_context *sys_ctx;
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev);
+ void *private_data;
+ uint32_t mask; /* the inotify mask */
+ uint32_t filter; /* the windows completion filter */
+ const char *path;
+};
+
+
+/*
+ * We want one FAM connection per smbd, not one per tcon.
+ */
+static FAMConnection fam_connection;
+static bool fam_connection_initialized = False;
+
+static struct fam_watch_context *fam_notify_list;
+static void fam_handler(struct event_context *event_ctx,
+ struct fd_event *fd_event,
+ uint16 flags,
+ void *private_data);
+
+static NTSTATUS fam_open_connection(FAMConnection *fam_conn,
+ struct event_context *event_ctx)
+{
+ int res;
+ char *name;
+
+ ZERO_STRUCTP(fam_conn);
+ FAMCONNECTION_GETFD(fam_conn) = -1;
+
+ if (asprintf(&name, "smbd (%lu)", (unsigned long)sys_getpid()) == -1) {
+ DEBUG(0, ("No memory\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ res = FAMOpen2(fam_conn, name);
+ SAFE_FREE(name);
+
+ if (res < 0) {
+ DEBUG(10, ("FAM file change notifications not available\n"));
+ /*
+ * No idea how to get NT_STATUS from a FAM result
+ */
+ FAMCONNECTION_GETFD(fam_conn) = -1;
+ return NT_STATUS_UNEXPECTED_IO_ERROR;
+ }
+
+ if (event_add_fd(event_ctx, event_ctx,
+ FAMCONNECTION_GETFD(fam_conn),
+ EVENT_FD_READ, fam_handler,
+ (void *)fam_conn) == NULL) {
+ DEBUG(0, ("event_add_fd failed\n"));
+ FAMClose(fam_conn);
+ FAMCONNECTION_GETFD(fam_conn) = -1;
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static void fam_reopen(FAMConnection *fam_conn,
+ struct event_context *event_ctx,
+ struct fam_watch_context *notify_list)
+{
+ struct fam_watch_context *ctx;
+
+ DEBUG(5, ("Re-opening FAM connection\n"));
+
+ FAMClose(fam_conn);
+
+ if (!NT_STATUS_IS_OK(fam_open_connection(fam_conn, event_ctx))) {
+ DEBUG(5, ("Re-opening fam connection failed\n"));
+ return;
+ }
+
+ for (ctx = notify_list; ctx; ctx = ctx->next) {
+ FAMMonitorDirectory(fam_conn, ctx->path, &ctx->fr, NULL);
+ }
+}
+
+static void fam_handler(struct event_context *event_ctx,
+ struct fd_event *fd_event,
+ uint16 flags,
+ void *private_data)
+{
+ FAMConnection *fam_conn = (FAMConnection *)private_data;
+ FAMEvent fam_event;
+ struct fam_watch_context *ctx;
+ struct notify_event ne;
+
+ if (FAMPending(fam_conn) == 0) {
+ DEBUG(10, ("fam_handler called but nothing pending\n"));
+ return;
+ }
+
+ if (FAMNextEvent(fam_conn, &fam_event) != 1) {
+ DEBUG(5, ("FAMNextEvent returned an error\n"));
+ TALLOC_FREE(fd_event);
+ fam_reopen(fam_conn, event_ctx, fam_notify_list);
+ return;
+ }
+
+ DEBUG(10, ("Got FAMCode %d for %s\n", fam_event.code,
+ fam_event.filename));
+
+ switch (fam_event.code) {
+ case FAMChanged:
+ ne.action = NOTIFY_ACTION_MODIFIED;
+ break;
+ case FAMCreated:
+ ne.action = NOTIFY_ACTION_ADDED;
+ break;
+ case FAMDeleted:
+ ne.action = NOTIFY_ACTION_REMOVED;
+ break;
+ default:
+ DEBUG(10, ("Ignoring code FAMCode %d for file %s\n",
+ (int)fam_event.code, fam_event.filename));
+ return;
+ }
+
+ for (ctx = fam_notify_list; ctx; ctx = ctx->next) {
+ if (memcmp(&fam_event.fr, &ctx->fr, sizeof(FAMRequest)) == 0) {
+ break;
+ }
+ }
+
+ if (ctx == NULL) {
+ DEBUG(5, ("Discarding event for file %s\n",
+ fam_event.filename));
+ return;
+ }
+
+ if ((ne.path = strrchr_m(fam_event.filename, '\\')) == NULL) {
+ ne.path = fam_event.filename;
+ }
+
+ ctx->callback(ctx->sys_ctx, ctx->private_data, &ne);
+}
+
+static int fam_watch_context_destructor(struct fam_watch_context *ctx)
+{
+ if (FAMCONNECTION_GETFD(ctx->fam_connection) != -1) {
+ FAMCancelMonitor(&fam_connection, &ctx->fr);
+ }
+ DLIST_REMOVE(fam_notify_list, ctx);
+ return 0;
+}
+
+/*
+ add a watch. The watch is removed when the caller calls
+ talloc_free() on *handle
+*/
+static NTSTATUS fam_watch(vfs_handle_struct *vfs_handle,
+ struct sys_notify_context *ctx,
+ struct notify_entry *e,
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev),
+ void *private_data,
+ void *handle_p)
+{
+ const uint32 fam_mask = (FILE_NOTIFY_CHANGE_FILE_NAME|
+ FILE_NOTIFY_CHANGE_DIR_NAME);
+ struct fam_watch_context *watch;
+ void **handle = (void **)handle_p;
+
+ if ((e->filter & fam_mask) == 0) {
+ DEBUG(10, ("filter = %u, ignoring in FAM\n", e->filter));
+ return NT_STATUS_OK;
+ }
+
+ if (!fam_connection_initialized) {
+ if (!NT_STATUS_IS_OK(fam_open_connection(&fam_connection,
+ ctx->ev))) {
+ /*
+ * Just let smbd do all the work itself
+ */
+ return NT_STATUS_OK;
+ }
+ fam_connection_initialized = True;
+ }
+
+ if (!(watch = TALLOC_P(ctx, struct fam_watch_context))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ watch->fam_connection = &fam_connection;
+
+ watch->callback = callback;
+ watch->private_data = private_data;
+ watch->sys_ctx = ctx;
+
+ if (!(watch->path = talloc_strdup(watch, e->path))) {
+ DEBUG(0, ("talloc_asprintf failed\n"));
+ TALLOC_FREE(watch);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * The FAM module in this early state will only take care of
+ * FAMCreated and FAMDeleted events, Leave the rest to
+ * notify_internal.c
+ */
+
+ watch->filter = fam_mask;
+ e->filter &= ~fam_mask;
+
+ DLIST_ADD(fam_notify_list, watch);
+ talloc_set_destructor(watch, fam_watch_context_destructor);
+
+ /*
+ * Only directories monitored so far
+ */
+
+ if (FAMCONNECTION_GETFD(watch->fam_connection) != -1) {
+ FAMMonitorDirectory(watch->fam_connection, watch->path,
+ &watch->fr, NULL);
+ }
+ else {
+ /*
+ * If the re-open is successful, this will establish the
+ * FAMMonitor from the list
+ */
+ fam_reopen(watch->fam_connection, ctx->ev, fam_notify_list);
+ }
+
+ *handle = (void *)watch;
+
+ return NT_STATUS_OK;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple notify_fam_op_tuples[] = {
+
+ {SMB_VFS_OP(fam_watch),
+ SMB_VFS_OP_NOTIFY_WATCH,
+ SMB_VFS_LAYER_OPAQUE},
+
+ {SMB_VFS_OP(NULL),
+ SMB_VFS_OP_NOOP,
+ SMB_VFS_LAYER_NOOP}
+
+};
+
+
+NTSTATUS vfs_notify_fam_init(void);
+NTSTATUS vfs_notify_fam_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "notify_fam",
+ notify_fam_op_tuples);
+}
diff --git a/source3/modules/vfs_posixacl.c b/source3/modules/vfs_posixacl.c
new file mode 100644
index 0000000000..21fb2ada31
--- /dev/null
+++ b/source3/modules/vfs_posixacl.c
@@ -0,0 +1,396 @@
+/*
+ Unix SMB/Netbios implementation.
+ VFS module to get and set posix acls
+ Copyright (C) Volker Lendecke 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+
+/* prototypes for static functions first - for clarity */
+
+static bool smb_ace_to_internal(acl_entry_t posix_ace,
+ struct smb_acl_entry *ace);
+static struct smb_acl_t *smb_acl_to_internal(acl_t acl);
+static int smb_acl_set_mode(acl_entry_t entry, SMB_ACL_PERM_T perm);
+static acl_t smb_acl_to_posix(const struct smb_acl_t *acl);
+
+
+/* public functions - the api */
+
+SMB_ACL_T posixacl_sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ SMB_ACL_TYPE_T type)
+{
+ struct smb_acl_t *result;
+ acl_type_t acl_type;
+ acl_t acl;
+
+ switch(type) {
+ case SMB_ACL_TYPE_ACCESS:
+ acl_type = ACL_TYPE_ACCESS;
+ break;
+ case SMB_ACL_TYPE_DEFAULT:
+ acl_type = ACL_TYPE_DEFAULT;
+ break;
+ default:
+ errno = EINVAL;
+ return NULL;
+ }
+
+ acl = acl_get_file(path_p, acl_type);
+
+ if (acl == NULL) {
+ return NULL;
+ }
+
+ result = smb_acl_to_internal(acl);
+ acl_free(acl);
+ return result;
+}
+
+SMB_ACL_T posixacl_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp)
+{
+ struct smb_acl_t *result;
+ acl_t acl = acl_get_fd(fsp->fh->fd);
+
+ if (acl == NULL) {
+ return NULL;
+ }
+
+ result = smb_acl_to_internal(acl);
+ acl_free(acl);
+ return result;
+}
+
+int posixacl_sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl)
+{
+ int res;
+ acl_type_t acl_type;
+ acl_t acl;
+
+ DEBUG(10, ("Calling acl_set_file: %s, %d\n", name, type));
+
+ switch(type) {
+ case SMB_ACL_TYPE_ACCESS:
+ acl_type = ACL_TYPE_ACCESS;
+ break;
+ case SMB_ACL_TYPE_DEFAULT:
+ acl_type = ACL_TYPE_DEFAULT;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((acl = smb_acl_to_posix(theacl)) == NULL) {
+ return -1;
+ }
+ res = acl_set_file(name, acl_type, acl);
+ if (res != 0) {
+ DEBUG(10, ("acl_set_file failed: %s\n", strerror(errno)));
+ }
+ acl_free(acl);
+ return res;
+}
+
+int posixacl_sys_acl_set_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_T theacl)
+{
+ int res;
+ acl_t acl = smb_acl_to_posix(theacl);
+ if (acl == NULL) {
+ return -1;
+ }
+ res = acl_set_fd(fsp->fh->fd, acl);
+ acl_free(acl);
+ return res;
+}
+
+int posixacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path)
+{
+ return acl_delete_def_file(path);
+}
+
+
+/* private functions */
+
+static bool smb_ace_to_internal(acl_entry_t posix_ace,
+ struct smb_acl_entry *ace)
+{
+ acl_tag_t tag;
+ acl_permset_t permset;
+
+ if (acl_get_tag_type(posix_ace, &tag) != 0) {
+ DEBUG(0, ("smb_acl_get_tag_type failed\n"));
+ return False;
+ }
+
+ switch(tag) {
+ case ACL_USER:
+ ace->a_type = SMB_ACL_USER;
+ break;
+ case ACL_USER_OBJ:
+ ace->a_type = SMB_ACL_USER_OBJ;
+ break;
+ case ACL_GROUP:
+ ace->a_type = SMB_ACL_GROUP;
+ break;
+ case ACL_GROUP_OBJ:
+ ace->a_type = SMB_ACL_GROUP_OBJ;
+ break;
+ case ACL_OTHER:
+ ace->a_type = SMB_ACL_OTHER;
+ break;
+ case ACL_MASK:
+ ace->a_type = SMB_ACL_MASK;
+ break;
+ default:
+ DEBUG(0, ("unknown tag type %d\n", (unsigned int)tag));
+ return False;
+ }
+ switch(ace->a_type) {
+ case SMB_ACL_USER: {
+ uid_t *puid = (uid_t *)acl_get_qualifier(posix_ace);
+ if (puid == NULL) {
+ DEBUG(0, ("smb_acl_get_qualifier failed\n"));
+ return False;
+ }
+ ace->uid = *puid;
+ acl_free(puid);
+ break;
+ }
+
+ case SMB_ACL_GROUP: {
+ gid_t *pgid = (uid_t *)acl_get_qualifier(posix_ace);
+ if (pgid == NULL) {
+ DEBUG(0, ("smb_acl_get_qualifier failed\n"));
+ return False;
+ }
+ ace->gid = *pgid;
+ acl_free(pgid);
+ break;
+ }
+ default:
+ break;
+ }
+ if (acl_get_permset(posix_ace, &permset) != 0) {
+ DEBUG(0, ("smb_acl_get_mode failed\n"));
+ return False;
+ }
+ ace->a_perm = 0;
+#ifdef HAVE_ACL_GET_PERM_NP
+ ace->a_perm |= (acl_get_perm_np(permset, ACL_READ) ? SMB_ACL_READ : 0);
+ ace->a_perm |= (acl_get_perm_np(permset, ACL_WRITE) ? SMB_ACL_WRITE : 0);
+ ace->a_perm |= (acl_get_perm_np(permset, ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
+#else
+ ace->a_perm |= (acl_get_perm(permset, ACL_READ) ? SMB_ACL_READ : 0);
+ ace->a_perm |= (acl_get_perm(permset, ACL_WRITE) ? SMB_ACL_WRITE : 0);
+ ace->a_perm |= (acl_get_perm(permset, ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
+#endif
+ return True;
+}
+
+static struct smb_acl_t *smb_acl_to_internal(acl_t acl)
+{
+ struct smb_acl_t *result = SMB_MALLOC_P(struct smb_acl_t);
+ int entry_id = ACL_FIRST_ENTRY;
+ acl_entry_t e;
+ if (result == NULL) {
+ return NULL;
+ }
+ ZERO_STRUCTP(result);
+ while (acl_get_entry(acl, entry_id, &e) == 1) {
+
+ entry_id = ACL_NEXT_ENTRY;
+
+ result = (struct smb_acl_t *)SMB_REALLOC(
+ result, sizeof(struct smb_acl_t) +
+ (sizeof(struct smb_acl_entry) * (result->count+1)));
+ if (result == NULL) {
+ DEBUG(0, ("SMB_REALLOC failed\n"));
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ if (!smb_ace_to_internal(e, &result->acl[result->count])) {
+ SAFE_FREE(result);
+ return NULL;
+ }
+
+ result->count += 1;
+ }
+ return result;
+}
+
+static int smb_acl_set_mode(acl_entry_t entry, SMB_ACL_PERM_T perm)
+{
+ int ret;
+ acl_permset_t permset;
+
+ if ((ret = acl_get_permset(entry, &permset)) != 0) {
+ return ret;
+ }
+ if ((ret = acl_clear_perms(permset)) != 0) {
+ return ret;
+ }
+ if ((perm & SMB_ACL_READ) &&
+ ((ret = acl_add_perm(permset, ACL_READ)) != 0)) {
+ return ret;
+ }
+ if ((perm & SMB_ACL_WRITE) &&
+ ((ret = acl_add_perm(permset, ACL_WRITE)) != 0)) {
+ return ret;
+ }
+ if ((perm & SMB_ACL_EXECUTE) &&
+ ((ret = acl_add_perm(permset, ACL_EXECUTE)) != 0)) {
+ return ret;
+ }
+ return acl_set_permset(entry, permset);
+}
+
+static acl_t smb_acl_to_posix(const struct smb_acl_t *acl)
+{
+ acl_t result;
+ int i;
+
+ result = acl_init(acl->count);
+ if (result == NULL) {
+ DEBUG(10, ("acl_init failed\n"));
+ return NULL;
+ }
+
+ for (i=0; i<acl->count; i++) {
+ const struct smb_acl_entry *entry = &acl->acl[i];
+ acl_entry_t e;
+ acl_tag_t tag;
+
+ if (acl_create_entry(&result, &e) != 0) {
+ DEBUG(1, ("acl_create_entry failed: %s\n",
+ strerror(errno)));
+ goto fail;
+ }
+
+ switch (entry->a_type) {
+ case SMB_ACL_USER:
+ tag = ACL_USER;
+ break;
+ case SMB_ACL_USER_OBJ:
+ tag = ACL_USER_OBJ;
+ break;
+ case SMB_ACL_GROUP:
+ tag = ACL_GROUP;
+ break;
+ case SMB_ACL_GROUP_OBJ:
+ tag = ACL_GROUP_OBJ;
+ break;
+ case SMB_ACL_OTHER:
+ tag = ACL_OTHER;
+ break;
+ case SMB_ACL_MASK:
+ tag = ACL_MASK;
+ break;
+ default:
+ DEBUG(1, ("Unknown tag value %d\n", entry->a_type));
+ goto fail;
+ }
+
+ if (acl_set_tag_type(e, tag) != 0) {
+ DEBUG(10, ("acl_set_tag_type(%d) failed: %s\n",
+ tag, strerror(errno)));
+ goto fail;
+ }
+
+ switch (entry->a_type) {
+ case SMB_ACL_USER:
+ if (acl_set_qualifier(e, &entry->uid) != 0) {
+ DEBUG(1, ("acl_set_qualifiier failed: %s\n",
+ strerror(errno)));
+ goto fail;
+ }
+ break;
+ case SMB_ACL_GROUP:
+ if (acl_set_qualifier(e, &entry->gid) != 0) {
+ DEBUG(1, ("acl_set_qualifiier failed: %s\n",
+ strerror(errno)));
+ goto fail;
+ }
+ break;
+ default: /* Shut up, compiler! :-) */
+ break;
+ }
+
+ if (smb_acl_set_mode(e, entry->a_perm) != 0) {
+ goto fail;
+ }
+ }
+
+ if (acl_valid(result) != 0) {
+ DEBUG(0, ("smb_acl_to_posix: ACL is invalid for set (%s)\n",
+ strerror(errno)));
+ goto fail;
+ }
+
+ return result;
+
+ fail:
+ if (result != NULL) {
+ acl_free(result);
+ }
+ return NULL;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple posixacl_op_tuples[] = {
+ /* Disk operations */
+ {SMB_VFS_OP(posixacl_sys_acl_get_file),
+ SMB_VFS_OP_SYS_ACL_GET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(posixacl_sys_acl_get_fd),
+ SMB_VFS_OP_SYS_ACL_GET_FD,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(posixacl_sys_acl_set_file),
+ SMB_VFS_OP_SYS_ACL_SET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(posixacl_sys_acl_set_fd),
+ SMB_VFS_OP_SYS_ACL_SET_FD,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(posixacl_sys_acl_delete_def_file),
+ SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(NULL),
+ SMB_VFS_OP_NOOP,
+ SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_posixacl_init(void);
+NTSTATUS vfs_posixacl_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "posixacl",
+ posixacl_op_tuples);
+}
diff --git a/source3/modules/vfs_posixacl.h b/source3/modules/vfs_posixacl.h
new file mode 100644
index 0000000000..9ef3f86620
--- /dev/null
+++ b/source3/modules/vfs_posixacl.h
@@ -0,0 +1,46 @@
+/*
+ Unix SMB/Netbios implementation.
+ VFS module to get and set posix acls
+ Copyright (C) Volker Lendecke 2006
+ Copyright (C) Michael Adam 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __VFS_POSIXACL_H__
+#define __VFS_POSIXACL_H__
+
+SMB_ACL_T posixacl_sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ SMB_ACL_TYPE_T type);
+
+SMB_ACL_T posixacl_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp);
+
+int posixacl_sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl);
+
+int posixacl_sys_acl_set_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_T theacl);
+
+int posixacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path);
+
+NTSTATUS vfs_posixacl_init(void);
+
+#endif
+
diff --git a/source3/modules/vfs_prealloc.c b/source3/modules/vfs_prealloc.c
new file mode 100644
index 0000000000..2a06e3d81b
--- /dev/null
+++ b/source3/modules/vfs_prealloc.c
@@ -0,0 +1,220 @@
+/*
+ * XFS preallocation support module.
+ *
+ * Copyright (c) James Peach 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/* Extent preallocation module.
+ *
+ * The purpose of this module is to preallocate space on the filesystem when
+ * we have a good idea of how large files are supposed to be. This lets writes
+ * proceed without having to allocate new extents and results in better file
+ * layouts on disk.
+ *
+ * Currently only implemented for XFS. This module is based on an original idea
+ * and implementation by Sebastian Brings.
+ *
+ * Tunables.
+ *
+ * prealloc: <ext> Number of bytes to preallocate for a file with
+ * the matching extension.
+ * prealloc:debug Debug level at which to emit messages.
+ *
+ * Example.
+ *
+ * prealloc:mpeg = 500M # Preallocate *.mpeg to 500 MiB.
+ */
+
+#ifdef HAVE_XFS_LIBXFS_H
+#include <xfs/libxfs.h>
+#define lock_type xfs_flock64_t
+#else
+#define lock_type struct flock64
+#endif
+
+#ifdef HAVE_GPFS
+#include "gpfs_gpl.h"
+#endif
+
+#define MODULE "prealloc"
+static int module_debug;
+
+static int preallocate_space(int fd, SMB_OFF_T size)
+{
+#ifndef HAVE_GPFS
+ lock_type fl = {0};
+ int err;
+
+ if (size <= 0) {
+ return 0;
+ }
+
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = size;
+
+ /* IMPORTANT: We use RESVSP because we want the extents to be
+ * allocated, but we don't want the allocation to show up in
+ * st_size or persist after the close(2).
+ */
+
+#if defined(XFS_IOC_RESVSP64)
+ /* On Linux this comes in via libxfs.h. */
+ err = xfsctl(NULL, fd, XFS_IOC_RESVSP64, &fl);
+#elif defined(F_RESVSP64)
+ /* On IRIX, this comes from fcntl.h. */
+ err = fcntl(fd, F_RESVSP64, &fl);
+#else
+ err = -1;
+ errno = ENOSYS;
+#endif
+#else /* GPFS uses completely different interface */
+ err = gpfs_prealloc(fd, (gpfs_off64_t)0, (gpfs_off64_t)size);
+#endif
+
+ if (err) {
+ DEBUG(module_debug,
+ ("%s: preallocate failed on fd=%d size=%lld: %s\n",
+ MODULE, fd, (long long)size, strerror(errno)));
+ }
+
+ return err;
+}
+
+static int prealloc_connect(
+ struct vfs_handle_struct * handle,
+ const char * service,
+ const char * user)
+{
+ module_debug = lp_parm_int(SNUM(handle->conn),
+ MODULE, "debug", 100);
+
+ return SMB_VFS_NEXT_CONNECT(handle, service, user);
+}
+
+static int prealloc_open(vfs_handle_struct* handle,
+ const char * fname,
+ files_struct * fsp,
+ int flags,
+ mode_t mode)
+{
+ int fd;
+ off64_t size = 0;
+
+ const char * dot;
+ char fext[10];
+
+ if (!(flags & (O_CREAT|O_TRUNC))) {
+ /* Caller is not intending to rewrite the file. Let's not mess
+ * with the allocation in this case.
+ */
+ goto normal_open;
+ }
+
+ *fext = '\0';
+ dot = strrchr(fname, '.');
+ if (dot && *++dot) {
+ if (strlen(dot) < sizeof(fext)) {
+ strncpy(fext, dot, sizeof(fext));
+ strnorm(fext, CASE_LOWER);
+ }
+ }
+
+ if (*fext == '\0') {
+ goto normal_open;
+ }
+
+ /* Syntax for specifying preallocation size is:
+ * MODULE: <extension> = <size>
+ * where
+ * <extension> is the file extension in lower case
+ * <size> is a size like 10, 10K, 10M
+ */
+ size = conv_str_size(lp_parm_const_string(SNUM(handle->conn), MODULE,
+ fext, NULL));
+ if (size <= 0) {
+ /* No need to preallocate this file. */
+ goto normal_open;
+ }
+
+ fd = SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+ if (fd < 0) {
+ return fd;
+ }
+
+ /* Prellocate only if the file is being created or replaced. Note that
+ * Samba won't ever pass down O_TRUNC, which is why we have to handle
+ * truncate calls specially.
+ */
+ if ((flags & O_CREAT) || (flags & O_TRUNC)) {
+ SMB_OFF_T * psize;
+
+ psize = VFS_ADD_FSP_EXTENSION(handle, fsp, SMB_OFF_T);
+ if (psize == NULL || *psize == -1) {
+ return fd;
+ }
+
+ DEBUG(module_debug,
+ ("%s: preallocating %s (fd=%d) to %lld bytes\n",
+ MODULE, fname, fd, (long long)size));
+
+ *psize = size;
+ if (preallocate_space(fd, *psize) < 0) {
+ VFS_REMOVE_FSP_EXTENSION(handle, fsp);
+ }
+ }
+
+ return fd;
+
+normal_open:
+ /* We are not creating or replacing a file. Skip the
+ * preallocation.
+ */
+ DEBUG(module_debug, ("%s: skipping preallocation for %s\n",
+ MODULE, fname));
+ return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+}
+
+static int prealloc_ftruncate(vfs_handle_struct * handle,
+ files_struct * fsp,
+ SMB_OFF_T offset)
+{
+ SMB_OFF_T *psize;
+ int ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
+
+ /* Maintain the allocated space even in the face of truncates. */
+ if ((psize = VFS_FETCH_FSP_EXTENSION(handle, fsp))) {
+ preallocate_space(fsp->fh->fd, *psize);
+ }
+
+ return ret;
+}
+
+static vfs_op_tuple prealloc_op_tuples[] = {
+ {SMB_VFS_OP(prealloc_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(prealloc_ftruncate), SMB_VFS_OP_FTRUNCATE, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(prealloc_connect), SMB_VFS_OP_CONNECT, SMB_VFS_LAYER_TRANSPARENT},
+ {NULL, SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_prealloc_init(void);
+NTSTATUS vfs_prealloc_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
+ MODULE, prealloc_op_tuples);
+}
diff --git a/source3/modules/vfs_readahead.c b/source3/modules/vfs_readahead.c
new file mode 100644
index 0000000000..df75814b72
--- /dev/null
+++ b/source3/modules/vfs_readahead.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) Jeremy Allison 2007.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+struct readahead_data {
+ SMB_OFF_T off_bound;
+ SMB_OFF_T len;
+ bool didmsg;
+};
+
+/*
+ * This module copes with Vista AIO read requests on Linux
+ * by detecting the initial 0x80000 boundary reads and causing
+ * the buffer cache to be filled in advance.
+ */
+
+/*******************************************************************
+ sendfile wrapper that does readahead/posix_fadvise.
+*******************************************************************/
+
+static ssize_t readahead_sendfile(struct vfs_handle_struct *handle,
+ int tofd,
+ files_struct *fromfsp,
+ const DATA_BLOB *header,
+ SMB_OFF_T offset,
+ size_t count)
+{
+ struct readahead_data *rhd = (struct readahead_data *)handle->data;
+
+ if ( offset % rhd->off_bound == 0) {
+#if defined(HAVE_LINUX_READAHEAD)
+ int err = readahead(fromfsp->fh->fd, offset, (size_t)rhd->len);
+ DEBUG(10,("readahead_sendfile: readahead on fd %u, offset %llu, len %u returned %d\n",
+ (unsigned int)fromfsp->fh->fd,
+ (unsigned long long)offset,
+ (unsigned int)rhd->len,
+ err ));
+#elif defined(HAVE_POSIX_FADVISE)
+ int err = posix_fadvise(fromfsp->fh->fd, offset, (off_t)rhd->len, POSIX_FADV_WILLNEED);
+ DEBUG(10,("readahead_sendfile: posix_fadvise on fd %u, offset %llu, len %u returned %d\n",
+ (unsigned int)fromfsp->fh->fd,
+ (unsigned long long)offset,
+ (unsigned int)rhd->len,
+ err ));
+#else
+ if (!rhd->didmsg) {
+ DEBUG(0,("readahead_sendfile: no readahead on this platform\n"));
+ rhd->didmsg = True;
+ }
+#endif
+ }
+ return SMB_VFS_NEXT_SENDFILE(handle,
+ tofd,
+ fromfsp,
+ header,
+ offset,
+ count);
+}
+
+/*******************************************************************
+ pread wrapper that does readahead/posix_fadvise.
+*******************************************************************/
+
+static ssize_t readahead_pread(vfs_handle_struct *handle,
+ files_struct *fsp,
+ void *data,
+ size_t count,
+ SMB_OFF_T offset)
+{
+ struct readahead_data *rhd = (struct readahead_data *)handle->data;
+
+ if ( offset % rhd->off_bound == 0) {
+#if defined(HAVE_LINUX_READAHEAD)
+ int err = readahead(fsp->fh->fd, offset, (size_t)rhd->len);
+ DEBUG(10,("readahead_pread: readahead on fd %u, offset %llu, len %u returned %d\n",
+ (unsigned int)fsp->fh->fd,
+ (unsigned long long)offset,
+ (unsigned int)rhd->len,
+ err ));
+#elif defined(HAVE_POSIX_FADVISE)
+ int err = posix_fadvise(fsp->fh->fd, offset, (off_t)rhd->len, POSIX_FADV_WILLNEED);
+ DEBUG(10,("readahead_pread: posix_fadvise on fd %u, offset %llu, len %u returned %d\n",
+ (unsigned int)fsp->fh->fd,
+ (unsigned long long)offset,
+ (unsigned int)rhd->len,
+ err ));
+#else
+ if (!rhd->didmsg) {
+ DEBUG(0,("readahead_pread: no readahead on this platform\n"));
+ rhd->didmsg = True;
+ }
+#endif
+ }
+ return SMB_VFS_NEXT_PREAD(handle, fsp, data, count, offset);
+}
+
+/*******************************************************************
+ Directly called from main smbd when freeing handle.
+*******************************************************************/
+
+static void free_readahead_data(void **pptr)
+{
+ SAFE_FREE(*pptr);
+}
+
+/*******************************************************************
+ Allocate the handle specific data so we don't call the expensive
+ conv_str_size function for each sendfile/pread.
+*******************************************************************/
+
+static int readahead_connect(struct vfs_handle_struct *handle,
+ const char *service,
+ const char *user)
+{
+ struct readahead_data *rhd = SMB_MALLOC_P(struct readahead_data);
+ if (!rhd) {
+ DEBUG(0,("readahead_connect: out of memory\n"));
+ return -1;
+ }
+ ZERO_STRUCTP(rhd);
+
+ rhd->didmsg = False;
+ rhd->off_bound = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
+ "readahead",
+ "offset",
+ NULL));
+ if (rhd->off_bound == 0) {
+ rhd->off_bound = 0x80000;
+ }
+ rhd->len = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
+ "readahead",
+ "length",
+ NULL));
+ if (rhd->len == 0) {
+ rhd->len = rhd->off_bound;
+ }
+
+ handle->data = (void *)rhd;
+ handle->free_data = free_readahead_data;
+ return SMB_VFS_NEXT_CONNECT(handle, service, user);
+}
+
+/*******************************************************************
+ Functions we're replacing.
+ We don't replace read as it isn't used from smbd to read file
+ data.
+*******************************************************************/
+
+static vfs_op_tuple readahead_ops [] =
+{
+ {SMB_VFS_OP(readahead_sendfile), SMB_VFS_OP_SENDFILE, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(readahead_pread), SMB_VFS_OP_PREAD, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(readahead_connect), SMB_VFS_OP_CONNECT, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+/*******************************************************************
+ Module initialization boilerplate.
+*******************************************************************/
+
+NTSTATUS vfs_readahead_init(void);
+NTSTATUS vfs_readahead_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "readahead", readahead_ops);
+}
diff --git a/source3/modules/vfs_readonly.c b/source3/modules/vfs_readonly.c
new file mode 100644
index 0000000000..d4ddf32e3a
--- /dev/null
+++ b/source3/modules/vfs_readonly.c
@@ -0,0 +1,97 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ VFS module to perform read-only limitation based on a time period
+ Copyright (C) Alexander Bokovoy 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ This work was sponsored by Optifacio Software Services, Inc.
+*/
+
+#include "includes.h"
+#include "getdate.h"
+
+/*
+ This module performs a read-only limitation for specified share
+ (or all of them if it is loaded in a [global] section) based on period
+ definition in smb.conf. You can stack this module multiple times under
+ different names to get multiple limit intervals.
+
+ The module uses get_date() function from coreutils' date utility to parse
+ specified dates according to date(1) rules. Look into info page for date(1)
+ to understand the syntax.
+
+ The module accepts one parameter:
+
+ readonly: period = "begin date","end date"
+
+ where "begin date" and "end date" are mandatory and should comply with date(1)
+ syntax for date strings.
+
+ Example:
+
+ readonly: period = "today 14:00","today 15:00"
+
+ Default:
+
+ readonly: period = "today 0:0:0","tomorrow 0:0:0"
+
+ The default covers whole day thus making the share readonly
+
+ */
+
+#define MODULE_NAME "readonly"
+static int readonly_connect(vfs_handle_struct *handle,
+ const char *service,
+ const char *user)
+{
+ const char *period_def[] = {"today 0:0:0", "tomorrow 0:0:0"};
+
+ const char **period = lp_parm_string_list(SNUM(handle->conn),
+ (handle->param ? handle->param : MODULE_NAME),
+ "period", period_def);
+
+ if (period && period[0] && period[1]) {
+ time_t current_time = time(NULL);
+ time_t begin_period = get_date(period[0], &current_time);
+ time_t end_period = get_date(period[1], &current_time);
+
+ if ((current_time >= begin_period) && (current_time <= end_period)) {
+ handle->conn->read_only = True;
+ }
+
+ return SMB_VFS_NEXT_CONNECT(handle, service, user);
+
+ } else {
+
+ return 1;
+
+ }
+}
+
+
+/* VFS operations structure */
+
+static vfs_op_tuple readonly_op_tuples[] = {
+ /* Disk operations */
+ {SMB_VFS_OP(readonly_connect), SMB_VFS_OP_CONNECT, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_readonly_init(void);
+NTSTATUS vfs_readonly_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, MODULE_NAME, readonly_op_tuples);
+}
diff --git a/source3/modules/vfs_recycle.c b/source3/modules/vfs_recycle.c
new file mode 100644
index 0000000000..acc1936e5f
--- /dev/null
+++ b/source3/modules/vfs_recycle.c
@@ -0,0 +1,604 @@
+/*
+ * Recycle bin VFS module for Samba.
+ *
+ * Copyright (C) 2001, Brandon Stone, Amherst College, <bbstone@amherst.edu>.
+ * Copyright (C) 2002, Jeremy Allison - modified to make a VFS module.
+ * Copyright (C) 2002, Alexander Bokovoy - cascaded VFS adoption,
+ * Copyright (C) 2002, Juergen Hasch - added some options.
+ * Copyright (C) 2002, Simo Sorce
+ * Copyright (C) 2002, Stefan (metze) Metzmacher
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#define ALLOC_CHECK(ptr, label) do { if ((ptr) == NULL) { DEBUG(0, ("recycle.bin: out of memory!\n")); errno = ENOMEM; goto label; } } while(0)
+
+static int vfs_recycle_debug_level = DBGC_VFS;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS vfs_recycle_debug_level
+
+static int recycle_connect(vfs_handle_struct *handle, const char *service, const char *user);
+static void recycle_disconnect(vfs_handle_struct *handle);
+static int recycle_unlink(vfs_handle_struct *handle, const char *name);
+
+static vfs_op_tuple recycle_ops[] = {
+
+ /* Disk operations */
+ {SMB_VFS_OP(recycle_connect), SMB_VFS_OP_CONNECT, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(recycle_disconnect), SMB_VFS_OP_DISCONNECT, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* File operations */
+ {SMB_VFS_OP(recycle_unlink), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+static int recycle_connect(vfs_handle_struct *handle, const char *service, const char *user)
+{
+ DEBUG(10,("recycle_connect() connect to service[%s] as user[%s].\n",
+ service,user));
+
+ return SMB_VFS_NEXT_CONNECT(handle, service, user);
+}
+
+static void recycle_disconnect(vfs_handle_struct *handle)
+{
+ DEBUG(10,("recycle_disconnect() connect to service[%s].\n",
+ lp_servicename(SNUM(handle->conn))));
+
+ SMB_VFS_NEXT_DISCONNECT(handle);
+}
+
+static const char *recycle_repository(vfs_handle_struct *handle)
+{
+ const char *tmp_str = NULL;
+
+
+ tmp_str = lp_parm_const_string(SNUM(handle->conn), "recycle", "repository",".recycle");
+
+ DEBUG(10, ("recycle: repository = %s\n", tmp_str));
+
+ return tmp_str;
+}
+
+static bool recycle_keep_dir_tree(vfs_handle_struct *handle)
+{
+ bool ret;
+
+ ret = lp_parm_bool(SNUM(handle->conn), "recycle", "keeptree", False);
+
+ DEBUG(10, ("recycle_bin: keeptree = %s\n", ret?"True":"False"));
+
+ return ret;
+}
+
+static bool recycle_versions(vfs_handle_struct *handle)
+{
+ bool ret;
+
+ ret = lp_parm_bool(SNUM(handle->conn), "recycle", "versions", False);
+
+ DEBUG(10, ("recycle: versions = %s\n", ret?"True":"False"));
+
+ return ret;
+}
+
+static bool recycle_touch(vfs_handle_struct *handle)
+{
+ bool ret;
+
+ ret = lp_parm_bool(SNUM(handle->conn), "recycle", "touch", False);
+
+ DEBUG(10, ("recycle: touch = %s\n", ret?"True":"False"));
+
+ return ret;
+}
+
+static bool recycle_touch_mtime(vfs_handle_struct *handle)
+{
+ bool ret;
+
+ ret = lp_parm_bool(SNUM(handle->conn), "recycle", "touch_mtime", False);
+
+ DEBUG(10, ("recycle: touch_mtime = %s\n", ret?"True":"False"));
+
+ return ret;
+}
+
+static const char **recycle_exclude(vfs_handle_struct *handle)
+{
+ const char **tmp_lp;
+
+ tmp_lp = lp_parm_string_list(SNUM(handle->conn), "recycle", "exclude", NULL);
+
+ DEBUG(10, ("recycle: exclude = %s ...\n", tmp_lp?*tmp_lp:""));
+
+ return tmp_lp;
+}
+
+static const char **recycle_exclude_dir(vfs_handle_struct *handle)
+{
+ const char **tmp_lp;
+
+ tmp_lp = lp_parm_string_list(SNUM(handle->conn), "recycle", "exclude_dir", NULL);
+
+ DEBUG(10, ("recycle: exclude_dir = %s ...\n", tmp_lp?*tmp_lp:""));
+
+ return tmp_lp;
+}
+
+static const char **recycle_noversions(vfs_handle_struct *handle)
+{
+ const char **tmp_lp;
+
+ tmp_lp = lp_parm_string_list(SNUM(handle->conn), "recycle", "noversions", NULL);
+
+ DEBUG(10, ("recycle: noversions = %s\n", tmp_lp?*tmp_lp:""));
+
+ return tmp_lp;
+}
+
+static SMB_OFF_T recycle_maxsize(vfs_handle_struct *handle)
+{
+ SMB_OFF_T maxsize;
+
+ maxsize = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
+ "recycle", "maxsize", NULL));
+
+ DEBUG(10, ("recycle: maxsize = %lu\n", (long unsigned int)maxsize));
+
+ return maxsize;
+}
+
+static SMB_OFF_T recycle_minsize(vfs_handle_struct *handle)
+{
+ SMB_OFF_T minsize;
+
+ minsize = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
+ "recycle", "minsize", NULL));
+
+ DEBUG(10, ("recycle: minsize = %lu\n", (long unsigned int)minsize));
+
+ return minsize;
+}
+
+static mode_t recycle_directory_mode(vfs_handle_struct *handle)
+{
+ int dirmode;
+ const char *buff;
+
+ buff = lp_parm_const_string(SNUM(handle->conn), "recycle", "directory_mode", NULL);
+
+ if (buff != NULL ) {
+ sscanf(buff, "%o", &dirmode);
+ } else {
+ dirmode=S_IRUSR | S_IWUSR | S_IXUSR;
+ }
+
+ DEBUG(10, ("recycle: directory_mode = %o\n", dirmode));
+ return (mode_t)dirmode;
+}
+
+static mode_t recycle_subdir_mode(vfs_handle_struct *handle)
+{
+ int dirmode;
+ const char *buff;
+
+ buff = lp_parm_const_string(SNUM(handle->conn), "recycle", "subdir_mode", NULL);
+
+ if (buff != NULL ) {
+ sscanf(buff, "%o", &dirmode);
+ } else {
+ dirmode=recycle_directory_mode(handle);
+ }
+
+ DEBUG(10, ("recycle: subdir_mode = %o\n", dirmode));
+ return (mode_t)dirmode;
+}
+
+static bool recycle_directory_exist(vfs_handle_struct *handle, const char *dname)
+{
+ SMB_STRUCT_STAT st;
+
+ if (SMB_VFS_NEXT_STAT(handle, dname, &st) == 0) {
+ if (S_ISDIR(st.st_mode)) {
+ return True;
+ }
+ }
+
+ return False;
+}
+
+static bool recycle_file_exist(vfs_handle_struct *handle, const char *fname)
+{
+ SMB_STRUCT_STAT st;
+
+ if (SMB_VFS_NEXT_STAT(handle, fname, &st) == 0) {
+ if (S_ISREG(st.st_mode)) {
+ return True;
+ }
+ }
+
+ return False;
+}
+
+/**
+ * Return file size
+ * @param conn connection
+ * @param fname file name
+ * @return size in bytes
+ **/
+static SMB_OFF_T recycle_get_file_size(vfs_handle_struct *handle, const char *fname)
+{
+ SMB_STRUCT_STAT st;
+
+ if (SMB_VFS_NEXT_STAT(handle, fname, &st) != 0) {
+ DEBUG(0,("recycle: stat for %s returned %s\n", fname, strerror(errno)));
+ return (SMB_OFF_T)0;
+ }
+
+ return(st.st_size);
+}
+
+/**
+ * Create directory tree
+ * @param conn connection
+ * @param dname Directory tree to be created
+ * @return Returns True for success
+ **/
+static bool recycle_create_dir(vfs_handle_struct *handle, const char *dname)
+{
+ size_t len;
+ mode_t mode;
+ char *new_dir = NULL;
+ char *tmp_str = NULL;
+ char *token;
+ char *tok_str;
+ bool ret = False;
+ char *saveptr;
+
+ mode = recycle_directory_mode(handle);
+
+ tmp_str = SMB_STRDUP(dname);
+ ALLOC_CHECK(tmp_str, done);
+ tok_str = tmp_str;
+
+ len = strlen(dname)+1;
+ new_dir = (char *)SMB_MALLOC(len + 1);
+ ALLOC_CHECK(new_dir, done);
+ *new_dir = '\0';
+ if (dname[0] == '/') {
+ /* Absolute path. */
+ safe_strcat(new_dir,"/",len);
+ }
+
+ /* Create directory tree if neccessary */
+ for(token = strtok_r(tok_str, "/", &saveptr); token;
+ token = strtok_r(NULL, "/", &saveptr)) {
+ safe_strcat(new_dir, token, len);
+ if (recycle_directory_exist(handle, new_dir))
+ DEBUG(10, ("recycle: dir %s already exists\n", new_dir));
+ else {
+ DEBUG(5, ("recycle: creating new dir %s\n", new_dir));
+ if (SMB_VFS_NEXT_MKDIR(handle, new_dir, mode) != 0) {
+ DEBUG(1,("recycle: mkdir failed for %s with error: %s\n", new_dir, strerror(errno)));
+ ret = False;
+ goto done;
+ }
+ }
+ safe_strcat(new_dir, "/", len);
+ mode = recycle_subdir_mode(handle);
+ }
+
+ ret = True;
+done:
+ SAFE_FREE(tmp_str);
+ SAFE_FREE(new_dir);
+ return ret;
+}
+
+/**
+ * Check if any of the components of "exclude_list" are contained in path.
+ * Return True if found
+ **/
+
+static bool matchdirparam(const char **dir_exclude_list, char *path)
+{
+ char *startp = NULL, *endp = NULL;
+
+ if (dir_exclude_list == NULL || dir_exclude_list[0] == NULL ||
+ *dir_exclude_list[0] == '\0' || path == NULL || *path == '\0') {
+ return False;
+ }
+
+ /*
+ * Walk the components of path, looking for matches with the
+ * exclude list on each component.
+ */
+
+ for (startp = path; startp; startp = endp) {
+ int i;
+
+ while (*startp == '/') {
+ startp++;
+ }
+ endp = strchr(startp, '/');
+ if (endp) {
+ *endp = '\0';
+ }
+
+ for(i=0; dir_exclude_list[i] ; i++) {
+ if(unix_wild_match(dir_exclude_list[i], startp)) {
+ /* Repair path. */
+ if (endp) {
+ *endp = '/';
+ }
+ return True;
+ }
+ }
+
+ /* Repair path. */
+ if (endp) {
+ *endp = '/';
+ }
+ }
+
+ return False;
+}
+
+/**
+ * Check if needle is contained in haystack, * and ? patterns are resolved
+ * @param haystack list of parameters separated by delimimiter character
+ * @param needle string to be matched exectly to haystack including pattern matching
+ * @return True if found
+ **/
+static bool matchparam(const char **haystack_list, const char *needle)
+{
+ int i;
+
+ if (haystack_list == NULL || haystack_list[0] == NULL ||
+ *haystack_list[0] == '\0' || needle == NULL || *needle == '\0') {
+ return False;
+ }
+
+ for(i=0; haystack_list[i] ; i++) {
+ if(unix_wild_match(haystack_list[i], needle)) {
+ return True;
+ }
+ }
+
+ return False;
+}
+
+/**
+ * Touch access or modify date
+ **/
+static void recycle_do_touch(vfs_handle_struct *handle, const char *fname,
+ bool touch_mtime)
+{
+ SMB_STRUCT_STAT st;
+ struct timespec ts[2];
+ int ret, err;
+
+ if (SMB_VFS_NEXT_STAT(handle, fname, &st) != 0) {
+ DEBUG(0,("recycle: stat for %s returned %s\n",
+ fname, strerror(errno)));
+ return;
+ }
+ ts[0] = timespec_current(); /* atime */
+ ts[1] = touch_mtime ? ts[0] : get_mtimespec(&st); /* mtime */
+
+ become_root();
+ ret = SMB_VFS_NEXT_NTIMES(handle, fname, ts);
+ err = errno;
+ unbecome_root();
+ if (ret == -1 ) {
+ DEBUG(0, ("recycle: touching %s failed, reason = %s\n",
+ fname, strerror(err)));
+ }
+}
+
+/**
+ * Check if file should be recycled
+ **/
+static int recycle_unlink(vfs_handle_struct *handle, const char *file_name)
+{
+ connection_struct *conn = handle->conn;
+ char *path_name = NULL;
+ char *temp_name = NULL;
+ char *final_name = NULL;
+ const char *base;
+ char *repository = NULL;
+ int i = 1;
+ SMB_OFF_T maxsize, minsize;
+ SMB_OFF_T file_size; /* space_avail; */
+ bool exist;
+ int rc = -1;
+
+ repository = talloc_sub_advanced(NULL, lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name,
+ conn->connectpath,
+ conn->server_info->utok.gid,
+ conn->server_info->sanitized_username,
+ pdb_get_domain(conn->server_info->sam_account),
+ recycle_repository(handle));
+ ALLOC_CHECK(repository, done);
+ /* shouldn't we allow absolute path names here? --metze */
+ /* Yes :-). JRA. */
+ trim_char(repository, '\0', '/');
+
+ if(!repository || *(repository) == '\0') {
+ DEBUG(3, ("recycle: repository path not set, purging %s...\n", file_name));
+ rc = SMB_VFS_NEXT_UNLINK(handle, file_name);
+ goto done;
+ }
+
+ /* we don't recycle the recycle bin... */
+ if (strncmp(file_name, repository, strlen(repository)) == 0) {
+ DEBUG(3, ("recycle: File is within recycling bin, unlinking ...\n"));
+ rc = SMB_VFS_NEXT_UNLINK(handle, file_name);
+ goto done;
+ }
+
+ file_size = recycle_get_file_size(handle, file_name);
+ /* it is wrong to purge filenames only because they are empty imho
+ * --- simo
+ *
+ if(fsize == 0) {
+ DEBUG(3, ("recycle: File %s is empty, purging...\n", file_name));
+ rc = SMB_VFS_NEXT_UNLINK(handle,file_name);
+ goto done;
+ }
+ */
+
+ /* FIXME: this is wrong, we should check the whole size of the recycle bin is
+ * not greater then maxsize, not the size of the single file, also it is better
+ * to remove older files
+ */
+ maxsize = recycle_maxsize(handle);
+ if(maxsize > 0 && file_size > maxsize) {
+ DEBUG(3, ("recycle: File %s exceeds maximum recycle size, purging... \n", file_name));
+ rc = SMB_VFS_NEXT_UNLINK(handle, file_name);
+ goto done;
+ }
+ minsize = recycle_minsize(handle);
+ if(minsize > 0 && file_size < minsize) {
+ DEBUG(3, ("recycle: File %s lowers minimum recycle size, purging... \n", file_name));
+ rc = SMB_VFS_NEXT_UNLINK(handle, file_name);
+ goto done;
+ }
+
+ /* FIXME: this is wrong: moving files with rename does not change the disk space
+ * allocation
+ *
+ space_avail = SMB_VFS_NEXT_DISK_FREE(handle, ".", True, &bsize, &dfree, &dsize) * 1024L;
+ DEBUG(5, ("space_avail = %Lu, file_size = %Lu\n", space_avail, file_size));
+ if(space_avail < file_size) {
+ DEBUG(3, ("recycle: Not enough diskspace, purging file %s\n", file_name));
+ rc = SMB_VFS_NEXT_UNLINK(handle, file_name);
+ goto done;
+ }
+ */
+
+ /* extract filename and path */
+ base = strrchr(file_name, '/');
+ if (base == NULL) {
+ base = file_name;
+ path_name = SMB_STRDUP("/");
+ ALLOC_CHECK(path_name, done);
+ }
+ else {
+ path_name = SMB_STRDUP(file_name);
+ ALLOC_CHECK(path_name, done);
+ path_name[base - file_name] = '\0';
+ base++;
+ }
+
+ DEBUG(10, ("recycle: fname = %s\n", file_name)); /* original filename with path */
+ DEBUG(10, ("recycle: fpath = %s\n", path_name)); /* original path */
+ DEBUG(10, ("recycle: base = %s\n", base)); /* filename without path */
+
+ if (matchparam(recycle_exclude(handle), base)) {
+ DEBUG(3, ("recycle: file %s is excluded \n", base));
+ rc = SMB_VFS_NEXT_UNLINK(handle, file_name);
+ goto done;
+ }
+
+ if (matchdirparam(recycle_exclude_dir(handle), path_name)) {
+ DEBUG(3, ("recycle: directory %s is excluded \n", path_name));
+ rc = SMB_VFS_NEXT_UNLINK(handle, file_name);
+ goto done;
+ }
+
+ if (recycle_keep_dir_tree(handle) == True) {
+ asprintf(&temp_name, "%s/%s", repository, path_name);
+ } else {
+ temp_name = SMB_STRDUP(repository);
+ }
+ ALLOC_CHECK(temp_name, done);
+
+ exist = recycle_directory_exist(handle, temp_name);
+ if (exist) {
+ DEBUG(10, ("recycle: Directory already exists\n"));
+ } else {
+ DEBUG(10, ("recycle: Creating directory %s\n", temp_name));
+ if (recycle_create_dir(handle, temp_name) == False) {
+ DEBUG(3, ("recycle: Could not create directory, purging %s...\n", file_name));
+ rc = SMB_VFS_NEXT_UNLINK(handle, file_name);
+ goto done;
+ }
+ }
+
+ asprintf(&final_name, "%s/%s", temp_name, base);
+ ALLOC_CHECK(final_name, done);
+ DEBUG(10, ("recycle: recycled file name: %s\n", final_name)); /* new filename with path */
+
+ /* check if we should delete file from recycle bin */
+ if (recycle_file_exist(handle, final_name)) {
+ if (recycle_versions(handle) == False || matchparam(recycle_noversions(handle), base) == True) {
+ DEBUG(3, ("recycle: Removing old file %s from recycle bin\n", final_name));
+ if (SMB_VFS_NEXT_UNLINK(handle, final_name) != 0) {
+ DEBUG(1, ("recycle: Error deleting old file: %s\n", strerror(errno)));
+ }
+ }
+ }
+
+ /* rename file we move to recycle bin */
+ i = 1;
+ while (recycle_file_exist(handle, final_name)) {
+ SAFE_FREE(final_name);
+ asprintf(&final_name, "%s/Copy #%d of %s", temp_name, i++, base);
+ }
+
+ DEBUG(10, ("recycle: Moving %s to %s\n", file_name, final_name));
+ rc = SMB_VFS_NEXT_RENAME(handle, file_name, final_name);
+ if (rc != 0) {
+ DEBUG(3, ("recycle: Move error %d (%s), purging file %s (%s)\n", errno, strerror(errno), file_name, final_name));
+ rc = SMB_VFS_NEXT_UNLINK(handle, file_name);
+ goto done;
+ }
+
+ /* touch access date of moved file */
+ if (recycle_touch(handle) == True || recycle_touch_mtime(handle))
+ recycle_do_touch(handle, final_name, recycle_touch_mtime(handle));
+
+done:
+ SAFE_FREE(path_name);
+ SAFE_FREE(temp_name);
+ SAFE_FREE(final_name);
+ TALLOC_FREE(repository);
+ return rc;
+}
+
+NTSTATUS vfs_recycle_init(void);
+NTSTATUS vfs_recycle_init(void)
+{
+ NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "recycle", recycle_ops);
+
+ if (!NT_STATUS_IS_OK(ret))
+ return ret;
+
+ vfs_recycle_debug_level = debug_add_class("recycle");
+ if (vfs_recycle_debug_level == -1) {
+ vfs_recycle_debug_level = DBGC_VFS;
+ DEBUG(0, ("vfs_recycle: Couldn't register custom debugging class!\n"));
+ } else {
+ DEBUG(10, ("vfs_recycle: Debug class number of 'recycle': %d\n", vfs_recycle_debug_level));
+ }
+
+ return ret;
+}
diff --git a/source3/modules/vfs_shadow_copy.c b/source3/modules/vfs_shadow_copy.c
new file mode 100644
index 0000000000..fbd2960aba
--- /dev/null
+++ b/source3/modules/vfs_shadow_copy.c
@@ -0,0 +1,249 @@
+/*
+ * implementation of an Shadow Copy module
+ *
+ * Copyright (C) Stefan Metzmacher 2003-2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/*
+ Please read the VFS module Samba-HowTo-Collection.
+ there's a chapter about this module
+
+ For this share
+ Z:\
+
+ the ShadowCopies are in this directories
+
+ Z:\@GMT-2003.08.05-12.00.00\
+ Z:\@GMT-2003.08.05-12.01.00\
+ Z:\@GMT-2003.08.05-12.02.00\
+
+ e.g.
+
+ Z:\testfile.txt
+ Z:\@GMT-2003.08.05-12.02.00\testfile.txt
+
+ or:
+
+ Z:\testdir\testfile.txt
+ Z:\@GMT-2003.08.05-12.02.00\testdir\testfile.txt
+
+
+ Note: Files must differ to be displayed via Windows Explorer!
+ Directories are always displayed...
+*/
+
+static int vfs_shadow_copy_debug_level = DBGC_VFS;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS vfs_shadow_copy_debug_level
+
+#define SHADOW_COPY_PREFIX "@GMT-"
+#define SHADOW_COPY_SAMPLE "@GMT-2004.02.18-15.44.00"
+
+typedef struct {
+ int pos;
+ int num;
+ SMB_STRUCT_DIRENT *dirs;
+} shadow_copy_Dir;
+
+static bool shadow_copy_match_name(const char *name)
+{
+ if (strncmp(SHADOW_COPY_PREFIX,name, sizeof(SHADOW_COPY_PREFIX)-1)==0 &&
+ (strlen(SHADOW_COPY_SAMPLE) == strlen(name))) {
+ return True;
+ }
+
+ return False;
+}
+
+static SMB_STRUCT_DIR *shadow_copy_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr)
+{
+ shadow_copy_Dir *dirp;
+ SMB_STRUCT_DIR *p = SMB_VFS_NEXT_OPENDIR(handle,fname,mask,attr);
+
+ if (!p) {
+ DEBUG(0,("shadow_copy_opendir: SMB_VFS_NEXT_OPENDIR() failed for [%s]\n",fname));
+ return NULL;
+ }
+
+ dirp = SMB_MALLOC_P(shadow_copy_Dir);
+ if (!dirp) {
+ DEBUG(0,("shadow_copy_opendir: Out of memory\n"));
+ SMB_VFS_NEXT_CLOSEDIR(handle,p);
+ return NULL;
+ }
+
+ ZERO_STRUCTP(dirp);
+
+ while (True) {
+ SMB_STRUCT_DIRENT *d;
+
+ d = SMB_VFS_NEXT_READDIR(handle, p);
+ if (d == NULL) {
+ break;
+ }
+
+ if (shadow_copy_match_name(d->d_name)) {
+ DEBUG(8,("shadow_copy_opendir: hide [%s]\n",d->d_name));
+ continue;
+ }
+
+ DEBUG(10,("shadow_copy_opendir: not hide [%s]\n",d->d_name));
+
+ dirp->dirs = SMB_REALLOC_ARRAY(dirp->dirs,SMB_STRUCT_DIRENT, dirp->num+1);
+ if (!dirp->dirs) {
+ DEBUG(0,("shadow_copy_opendir: Out of memory\n"));
+ break;
+ }
+
+ dirp->dirs[dirp->num++] = *d;
+ }
+
+ SMB_VFS_NEXT_CLOSEDIR(handle,p);
+ return((SMB_STRUCT_DIR *)dirp);
+}
+
+static SMB_STRUCT_DIRENT *shadow_copy_readdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *_dirp)
+{
+ shadow_copy_Dir *dirp = (shadow_copy_Dir *)_dirp;
+
+ if (dirp->pos < dirp->num) {
+ return &(dirp->dirs[dirp->pos++]);
+ }
+
+ return NULL;
+}
+
+static void shadow_copy_seekdir(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *_dirp, long offset)
+{
+ shadow_copy_Dir *dirp = (shadow_copy_Dir *)_dirp;
+
+ if (offset < dirp->num) {
+ dirp->pos = offset ;
+ }
+}
+
+static long shadow_copy_telldir(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *_dirp)
+{
+ shadow_copy_Dir *dirp = (shadow_copy_Dir *)_dirp;
+ return( dirp->pos ) ;
+}
+
+static void shadow_copy_rewinddir(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *_dirp)
+{
+ shadow_copy_Dir *dirp = (shadow_copy_Dir *)_dirp;
+ dirp->pos = 0 ;
+}
+
+static int shadow_copy_closedir(vfs_handle_struct *handle, SMB_STRUCT_DIR *_dirp)
+{
+ shadow_copy_Dir *dirp = (shadow_copy_Dir *)_dirp;
+
+ SAFE_FREE(dirp->dirs);
+ SAFE_FREE(dirp);
+
+ return 0;
+}
+
+static int shadow_copy_get_shadow_copy_data(vfs_handle_struct *handle, files_struct *fsp, SHADOW_COPY_DATA *shadow_copy_data, bool labels)
+{
+ SMB_STRUCT_DIR *p = SMB_VFS_NEXT_OPENDIR(handle,fsp->conn->connectpath,NULL,0);
+
+ shadow_copy_data->num_volumes = 0;
+ shadow_copy_data->labels = NULL;
+
+ if (!p) {
+ DEBUG(0,("shadow_copy_get_shadow_copy_data: SMB_VFS_NEXT_OPENDIR() failed for [%s]\n",fsp->conn->connectpath));
+ return -1;
+ }
+
+ while (True) {
+ SHADOW_COPY_LABEL *tlabels;
+ SMB_STRUCT_DIRENT *d;
+
+ d = SMB_VFS_NEXT_READDIR(handle, p);
+ if (d == NULL) {
+ break;
+ }
+
+ /* */
+ if (!shadow_copy_match_name(d->d_name)) {
+ DEBUG(10,("shadow_copy_get_shadow_copy_data: ignore [%s]\n",d->d_name));
+ continue;
+ }
+
+ DEBUG(7,("shadow_copy_get_shadow_copy_data: not ignore [%s]\n",d->d_name));
+
+ if (!labels) {
+ shadow_copy_data->num_volumes++;
+ continue;
+ }
+
+ tlabels = (SHADOW_COPY_LABEL *)TALLOC_REALLOC(shadow_copy_data->mem_ctx,
+ shadow_copy_data->labels,
+ (shadow_copy_data->num_volumes+1)*sizeof(SHADOW_COPY_LABEL));
+ if (tlabels == NULL) {
+ DEBUG(0,("shadow_copy_get_shadow_copy_data: Out of memory\n"));
+ SMB_VFS_NEXT_CLOSEDIR(handle,p);
+ return -1;
+ }
+
+ snprintf(tlabels[shadow_copy_data->num_volumes++], sizeof(*tlabels), "%s",d->d_name);
+
+ shadow_copy_data->labels = tlabels;
+ }
+
+ SMB_VFS_NEXT_CLOSEDIR(handle,p);
+ return 0;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple shadow_copy_ops[] = {
+ {SMB_VFS_OP(shadow_copy_opendir), SMB_VFS_OP_OPENDIR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy_readdir), SMB_VFS_OP_READDIR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy_seekdir), SMB_VFS_OP_SEEKDIR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy_telldir), SMB_VFS_OP_TELLDIR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy_rewinddir), SMB_VFS_OP_REWINDDIR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy_closedir), SMB_VFS_OP_CLOSEDIR, SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(shadow_copy_get_shadow_copy_data), SMB_VFS_OP_GET_SHADOW_COPY_DATA,SMB_VFS_LAYER_OPAQUE},
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_shadow_copy_init(void);
+NTSTATUS vfs_shadow_copy_init(void)
+{
+ NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "shadow_copy", shadow_copy_ops);
+
+ if (!NT_STATUS_IS_OK(ret))
+ return ret;
+
+ vfs_shadow_copy_debug_level = debug_add_class("shadow_copy");
+ if (vfs_shadow_copy_debug_level == -1) {
+ vfs_shadow_copy_debug_level = DBGC_VFS;
+ DEBUG(0, ("%s: Couldn't register custom debugging class!\n",
+ "vfs_shadow_copy_init"));
+ } else {
+ DEBUG(10, ("%s: Debug class number of '%s': %d\n",
+ "vfs_shadow_copy_init","shadow_copy",vfs_shadow_copy_debug_level));
+ }
+
+ return ret;
+}
diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
new file mode 100644
index 0000000000..c95600b642
--- /dev/null
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -0,0 +1,629 @@
+/*
+ * implementation of an Shadow Copy module - version 2
+ *
+ * Copyright (C) Andrew Tridgell 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/*
+
+ This is a 2nd implemetation of a shadow copy module for exposing
+ snapshots to windows clients as shadow copies. This version has the
+ following features:
+
+ 1) you don't need to populate your shares with symlinks to the
+ snapshots. This can be very important when you have thousands of
+ shares, or use [homes]
+
+ 2) the inode number of the files is altered so it is different
+ from the original. This allows the 'restore' button to work
+ without a sharing violation
+
+ Module options:
+
+ shadow:snapdir = <directory where snapshots are kept>
+
+ This is the directory containing the @GMT-* snapshot directories. If it is an absolute
+ path it is used as-is. If it is a relative path, then it is taken relative to the mount
+ point of the filesystem that the root of this share is on
+
+ shadow:basedir = <base directory that snapshots are from>
+
+ This is an optional parameter that specifies the directory that
+ the snapshots are relative to. It defaults to the filesystem
+ mount point
+
+ shadow:fixinodes = yes/no
+
+ If you enable shadow:fixinodes then this module will modify the
+ apparent inode number of files in the snapshot directories using
+ a hash of the files path. This is needed for snapshot systems
+ where the snapshots have the same device:inode number as the
+ original files (such as happens with GPFS snapshots). If you
+ don't set this option then the 'restore' button in the shadow
+ copy UI will fail with a sharing violation.
+
+ Note that the directory names in the snapshot directory must take the form
+ @GMT-YYYY.MM.DD-HH.MM.SS
+
+ The following command would generate a correctly formatted directory name:
+ date -u +@GMT-%Y.%m.%d-%H.%M.%S
+
+ */
+
+static int vfs_shadow_copy2_debug_level = DBGC_VFS;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS vfs_shadow_copy2_debug_level
+
+#define GMT_NAME_LEN 24 /* length of a @GMT- name */
+
+/*
+ make very sure it is one of our special names
+ */
+static inline bool shadow_copy2_match_name(const char *name)
+{
+ unsigned year, month, day, hr, min, sec;
+ if (name[0] != '@') return False;
+ if (strncmp(name, "@GMT-", 5) != 0) return False;
+ if (sscanf(name, "@GMT-%04u.%02u.%02u-%02u.%02u.%02u", &year, &month,
+ &day, &hr, &min, &sec) != 6) {
+ return False;
+ }
+ if (name[24] != 0 && name[24] != '/') {
+ return False;
+ }
+ return True;
+}
+
+/*
+ convert a name to the shadow directory
+ */
+
+#define _SHADOW2_NEXT(op, args, rtype, eret, extra) do { \
+ const char *name = fname; \
+ if (shadow_copy2_match_name(fname)) { \
+ char *name2; \
+ rtype ret; \
+ name2 = convert_shadow2_name(handle, fname); \
+ if (name2 == NULL) { \
+ errno = EINVAL; \
+ return eret; \
+ } \
+ name = name2; \
+ ret = SMB_VFS_NEXT_ ## op args; \
+ talloc_free(name2); \
+ if (ret != eret) extra; \
+ return ret; \
+ } else { \
+ return SMB_VFS_NEXT_ ## op args; \
+ } \
+} while (0)
+
+/*
+ convert a name to the shadow directory: NTSTATUS-specific handling
+ */
+
+#define _SHADOW2_NTSTATUS_NEXT(op, args, eret, extra) do { \
+ const char *name = fname; \
+ if (shadow_copy2_match_name(fname)) { \
+ char *name2; \
+ NTSTATUS ret; \
+ name2 = convert_shadow2_name(handle, fname); \
+ if (name2 == NULL) { \
+ errno = EINVAL; \
+ return eret; \
+ } \
+ name = name2; \
+ ret = SMB_VFS_NEXT_ ## op args; \
+ talloc_free(name2); \
+ if (!NT_STATUS_EQUAL(ret, eret)) extra; \
+ return ret; \
+ } else { \
+ return SMB_VFS_NEXT_ ## op args; \
+ } \
+} while (0)
+
+#define SHADOW2_NTSTATUS_NEXT(op, args, eret) _SHADOW2_NTSTATUS_NEXT(op, args, eret, )
+
+#define SHADOW2_NEXT(op, args, rtype, eret) _SHADOW2_NEXT(op, args, rtype, eret, )
+
+#define SHADOW2_NEXT2(op, args) do { \
+ if (shadow_copy2_match_name(oldname) || shadow_copy2_match_name(newname)) { \
+ errno = EROFS; \
+ return -1; \
+ } else { \
+ return SMB_VFS_NEXT_ ## op args; \
+ } \
+} while (0)
+
+
+/*
+ find the mount point of a filesystem
+ */
+static char *find_mount_point(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
+{
+ char *path = talloc_strdup(mem_ctx, handle->conn->connectpath);
+ dev_t dev;
+ struct stat st;
+ char *p;
+
+ if (stat(path, &st) != 0) {
+ talloc_free(path);
+ return NULL;
+ }
+
+ dev = st.st_dev;
+
+ while ((p = strrchr(path, '/')) && p > path) {
+ *p = 0;
+ if (stat(path, &st) != 0) {
+ talloc_free(path);
+ return NULL;
+ }
+ if (st.st_dev != dev) {
+ *p = '/';
+ break;
+ }
+ }
+
+ return path;
+}
+
+/*
+ work out the location of the snapshot for this share
+ */
+static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
+{
+ const char *snapdir;
+ char *mount_point;
+ const char *ret;
+
+ snapdir = lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir", NULL);
+ if (snapdir == NULL) {
+ return NULL;
+ }
+ /* if its an absolute path, we're done */
+ if (*snapdir == '/') {
+ return snapdir;
+ }
+
+ /* other its relative to the filesystem mount point */
+ mount_point = find_mount_point(mem_ctx, handle);
+ if (mount_point == NULL) {
+ return NULL;
+ }
+
+ ret = talloc_asprintf(mem_ctx, "%s/%s", mount_point, snapdir);
+ talloc_free(mount_point);
+ return ret;
+}
+
+/*
+ work out the location of the base directory for snapshots of this share
+ */
+static const char *shadow_copy2_find_basedir(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
+{
+ const char *basedir = lp_parm_const_string(SNUM(handle->conn), "shadow", "basedir", NULL);
+
+ /* other its the filesystem mount point */
+ if (basedir == NULL) {
+ basedir = find_mount_point(mem_ctx, handle);
+ }
+
+ return basedir;
+}
+
+/*
+ convert a filename from a share relative path, to a path in the
+ snapshot directory
+ */
+static char *convert_shadow2_name(vfs_handle_struct *handle, const char *fname)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(handle->data);
+ const char *snapdir, *relpath, *baseoffset, *basedir;
+ size_t baselen;
+ char *ret;
+
+ snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
+ if (snapdir == NULL) {
+ DEBUG(2,("no snapdir found for share at %s\n", handle->conn->connectpath));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ basedir = shadow_copy2_find_basedir(tmp_ctx, handle);
+ if (basedir == NULL) {
+ DEBUG(2,("no basedir found for share at %s\n", handle->conn->connectpath));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ relpath = fname + GMT_NAME_LEN;
+ baselen = strlen(basedir);
+ baseoffset = handle->conn->connectpath + baselen;
+
+ /* some sanity checks */
+ if (strncmp(basedir, handle->conn->connectpath, baselen) != 0 ||
+ (handle->conn->connectpath[baselen] != 0 && handle->conn->connectpath[baselen] != '/')) {
+ DEBUG(0,("convert_shadow2_name: basedir %s is not a parent of %s\n",
+ basedir, handle->conn->connectpath));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ if (*relpath == '/') relpath++;
+ if (*baseoffset == '/') baseoffset++;
+
+ ret = talloc_asprintf(handle->data, "%s/%.*s/%s/%s",
+ snapdir,
+ GMT_NAME_LEN, fname,
+ baseoffset,
+ relpath);
+ DEBUG(6,("convert_shadow2_name: '%s' -> '%s'\n", fname, ret));
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+
+/*
+ simple string hash
+ */
+static uint32 string_hash(const char *s)
+{
+ uint32 n = 0;
+ while (*s) {
+ n = ((n << 5) + n) ^ (uint32)(*s++);
+ }
+ return n;
+}
+
+/*
+ modify a sbuf return to ensure that inodes in the shadow directory
+ are different from those in the main directory
+ */
+static void convert_sbuf(vfs_handle_struct *handle, const char *fname, SMB_STRUCT_STAT *sbuf)
+{
+ if (lp_parm_bool(SNUM(handle->conn), "shadow", "fixinodes", False)) {
+ /* some snapshot systems, like GPFS, return the name
+ device:inode for the snapshot files as the current
+ files. That breaks the 'restore' button in the shadow copy
+ GUI, as the client gets a sharing violation.
+
+ This is a crude way of allowing both files to be
+ open at once. It has a slight chance of inode
+ number collision, but I can't see a better approach
+ without significant VFS changes
+ */
+ uint32_t shash = string_hash(fname) & 0xFF000000;
+ if (shash == 0) {
+ shash = 1;
+ }
+ sbuf->st_ino ^= shash;
+ }
+}
+
+static int shadow_copy2_rename(vfs_handle_struct *handle,
+ const char *oldname, const char *newname)
+{
+ SHADOW2_NEXT2(RENAME, (handle, oldname, newname));
+}
+
+static int shadow_copy2_symlink(vfs_handle_struct *handle,
+ const char *oldname, const char *newname)
+{
+ SHADOW2_NEXT2(SYMLINK, (handle, oldname, newname));
+}
+
+static int shadow_copy2_link(vfs_handle_struct *handle,
+ const char *oldname, const char *newname)
+{
+ SHADOW2_NEXT2(LINK, (handle, oldname, newname));
+}
+
+static int shadow_copy2_open(vfs_handle_struct *handle,
+ const char *fname, files_struct *fsp, int flags, mode_t mode)
+{
+ SHADOW2_NEXT(OPEN, (handle, name, fsp, flags, mode), int, -1);
+}
+
+static SMB_STRUCT_DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
+ const char *fname, const char *mask, uint32 attr)
+{
+ SHADOW2_NEXT(OPENDIR, (handle, name, mask, attr), SMB_STRUCT_DIR *, NULL);
+}
+
+static int shadow_copy2_stat(vfs_handle_struct *handle,
+ const char *fname, SMB_STRUCT_STAT *sbuf)
+{
+ _SHADOW2_NEXT(STAT, (handle, name, sbuf), int, -1, convert_sbuf(handle, fname, sbuf));
+}
+
+static int shadow_copy2_lstat(vfs_handle_struct *handle,
+ const char *fname, SMB_STRUCT_STAT *sbuf)
+{
+ _SHADOW2_NEXT(LSTAT, (handle, name, sbuf), int, -1, convert_sbuf(handle, fname, sbuf));
+}
+
+static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
+{
+ int ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+ if (ret == 0 && shadow_copy2_match_name(fsp->fsp_name)) {
+ convert_sbuf(handle, fsp->fsp_name, sbuf);
+ }
+ return ret;
+}
+
+static int shadow_copy2_unlink(vfs_handle_struct *handle, const char *fname)
+{
+ SHADOW2_NEXT(UNLINK, (handle, name), int, -1);
+}
+
+static int shadow_copy2_chmod(vfs_handle_struct *handle,
+ const char *fname, mode_t mode)
+{
+ SHADOW2_NEXT(CHMOD, (handle, name, mode), int, -1);
+}
+
+static int shadow_copy2_chown(vfs_handle_struct *handle,
+ const char *fname, uid_t uid, gid_t gid)
+{
+ SHADOW2_NEXT(CHOWN, (handle, name, uid, gid), int, -1);
+}
+
+static int shadow_copy2_chdir(vfs_handle_struct *handle,
+ const char *fname)
+{
+ SHADOW2_NEXT(CHDIR, (handle, name), int, -1);
+}
+
+static int shadow_copy2_ntimes(vfs_handle_struct *handle,
+ const char *fname, const struct timespec ts[2])
+{
+ SHADOW2_NEXT(NTIMES, (handle, name, ts), int, -1);
+}
+
+static int shadow_copy2_readlink(vfs_handle_struct *handle,
+ const char *fname, char *buf, size_t bufsiz)
+{
+ SHADOW2_NEXT(READLINK, (handle, name, buf, bufsiz), int, -1);
+}
+
+static int shadow_copy2_mknod(vfs_handle_struct *handle,
+ const char *fname, mode_t mode, SMB_DEV_T dev)
+{
+ SHADOW2_NEXT(MKNOD, (handle, name, mode, dev), int, -1);
+}
+
+static char *shadow_copy2_realpath(vfs_handle_struct *handle,
+ const char *fname, char *resolved_path)
+{
+ SHADOW2_NEXT(REALPATH, (handle, name, resolved_path), char *, NULL);
+}
+
+static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
+ const char *fname, uint32 security_info,
+ struct security_descriptor **ppdesc)
+{
+ SHADOW2_NTSTATUS_NEXT(GET_NT_ACL, (handle, name, security_info, ppdesc), NT_STATUS_ACCESS_DENIED);
+}
+
+static int shadow_copy2_mkdir(vfs_handle_struct *handle, const char *fname, mode_t mode)
+{
+ SHADOW2_NEXT(MKDIR, (handle, name, mode), int, -1);
+}
+
+static int shadow_copy2_rmdir(vfs_handle_struct *handle, const char *fname)
+{
+ SHADOW2_NEXT(RMDIR, (handle, name), int, -1);
+}
+
+static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname, int flags)
+{
+ SHADOW2_NEXT(CHFLAGS, (handle, name, flags), int, -1);
+}
+
+static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
+ const char *fname, const char *aname, void *value, size_t size)
+{
+ SHADOW2_NEXT(GETXATTR, (handle, name, aname, value, size), ssize_t, -1);
+}
+
+static ssize_t shadow_copy2_lgetxattr(vfs_handle_struct *handle,
+ const char *fname, const char *aname, void *value, size_t size)
+{
+ SHADOW2_NEXT(LGETXATTR, (handle, name, aname, value, size), ssize_t, -1);
+}
+
+static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle, const char *fname,
+ char *list, size_t size)
+{
+ SHADOW2_NEXT(LISTXATTR, (handle, name, list, size), ssize_t, -1);
+}
+
+static int shadow_copy2_removexattr(struct vfs_handle_struct *handle, const char *fname,
+ const char *aname)
+{
+ SHADOW2_NEXT(REMOVEXATTR, (handle, name, aname), int, -1);
+}
+
+static int shadow_copy2_lremovexattr(struct vfs_handle_struct *handle, const char *fname,
+ const char *aname)
+{
+ SHADOW2_NEXT(LREMOVEXATTR, (handle, name, aname), int, -1);
+}
+
+static int shadow_copy2_setxattr(struct vfs_handle_struct *handle, const char *fname,
+ const char *aname, const void *value, size_t size, int flags)
+{
+ SHADOW2_NEXT(SETXATTR, (handle, name, aname, value, size, flags), int, -1);
+}
+
+static int shadow_copy2_lsetxattr(struct vfs_handle_struct *handle, const char *fname,
+ const char *aname, const void *value, size_t size, int flags)
+{
+ SHADOW2_NEXT(LSETXATTR, (handle, name, aname, value, size, flags), int, -1);
+}
+
+static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
+ const char *fname, mode_t mode)
+{
+ /* If the underlying VFS doesn't have ACL support... */
+ if (!handle->vfs_next.ops.chmod_acl) {
+ errno = ENOSYS;
+ return -1;
+ }
+ SHADOW2_NEXT(CHMOD_ACL, (handle, name, mode), int, -1);
+}
+
+static int shadow_copy2_get_shadow_copy2_data(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SHADOW_COPY_DATA *shadow_copy2_data,
+ bool labels)
+{
+ SMB_STRUCT_DIR *p;
+ const char *snapdir;
+ SMB_STRUCT_DIRENT *d;
+ TALLOC_CTX *tmp_ctx = talloc_new(handle->data);
+
+ snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
+ if (snapdir == NULL) {
+ DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
+ handle->conn->connectpath));
+ errno = EINVAL;
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0);
+
+ if (!p) {
+ DEBUG(0,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s' - %s\n",
+ snapdir, strerror(errno)));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ talloc_free(tmp_ctx);
+
+ shadow_copy2_data->num_volumes = 0;
+ shadow_copy2_data->labels = NULL;
+
+ while ((d = SMB_VFS_NEXT_READDIR(handle, p))) {
+ SHADOW_COPY_LABEL *tlabels;
+
+ /* ignore names not of the right form in the snapshot directory */
+ if (!shadow_copy2_match_name(d->d_name)) {
+ continue;
+ }
+
+ if (!labels) {
+ /* the caller doesn't want the labels */
+ shadow_copy2_data->num_volumes++;
+ continue;
+ }
+
+ tlabels = talloc_realloc(shadow_copy2_data->mem_ctx,
+ shadow_copy2_data->labels,
+ SHADOW_COPY_LABEL, shadow_copy2_data->num_volumes+1);
+ if (tlabels == NULL) {
+ DEBUG(0,("shadow_copy2: out of memory\n"));
+ SMB_VFS_NEXT_CLOSEDIR(handle, p);
+ return -1;
+ }
+
+ strlcpy(tlabels[shadow_copy2_data->num_volumes], d->d_name, sizeof(*tlabels));
+ shadow_copy2_data->num_volumes++;
+ shadow_copy2_data->labels = tlabels;
+ }
+
+ SMB_VFS_NEXT_CLOSEDIR(handle,p);
+ return 0;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple shadow_copy2_ops[] = {
+ {SMB_VFS_OP(shadow_copy2_opendir), SMB_VFS_OP_OPENDIR, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* directory operations */
+ {SMB_VFS_OP(shadow_copy2_mkdir), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_rmdir), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* xattr and flags operations */
+ {SMB_VFS_OP(shadow_copy2_chflags), SMB_VFS_OP_CHFLAGS, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_getxattr), SMB_VFS_OP_GETXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_lgetxattr), SMB_VFS_OP_LGETXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_listxattr), SMB_VFS_OP_LISTXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_removexattr), SMB_VFS_OP_REMOVEXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_lremovexattr),SMB_VFS_OP_LREMOVEXATTR,SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_setxattr), SMB_VFS_OP_SETXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_lsetxattr), SMB_VFS_OP_LSETXATTR, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* File operations */
+ {SMB_VFS_OP(shadow_copy2_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_rename), SMB_VFS_OP_RENAME, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_stat), SMB_VFS_OP_STAT, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_lstat), SMB_VFS_OP_LSTAT, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_fstat), SMB_VFS_OP_FSTAT, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_unlink), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_chmod), SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_chown), SMB_VFS_OP_CHOWN, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_chdir), SMB_VFS_OP_CHDIR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_ntimes), SMB_VFS_OP_NTIMES, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_symlink), SMB_VFS_OP_SYMLINK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_readlink), SMB_VFS_OP_READLINK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_link), SMB_VFS_OP_LINK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_mknod), SMB_VFS_OP_MKNOD, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_realpath), SMB_VFS_OP_REALPATH, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* NT File ACL operations */
+ {SMB_VFS_OP(shadow_copy2_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* POSIX ACL operations */
+ {SMB_VFS_OP(shadow_copy2_chmod_acl), SMB_VFS_OP_CHMOD_ACL, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* special shadown copy op */
+ {SMB_VFS_OP(shadow_copy2_get_shadow_copy2_data),
+ SMB_VFS_OP_GET_SHADOW_COPY_DATA,SMB_VFS_LAYER_OPAQUE},
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_shadow_copy2_init(void);
+NTSTATUS vfs_shadow_copy2_init(void)
+{
+ NTSTATUS ret;
+
+ ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "shadow_copy2", shadow_copy2_ops);
+
+ if (!NT_STATUS_IS_OK(ret))
+ return ret;
+
+ vfs_shadow_copy2_debug_level = debug_add_class("shadow_copy2");
+ if (vfs_shadow_copy2_debug_level == -1) {
+ vfs_shadow_copy2_debug_level = DBGC_VFS;
+ DEBUG(0, ("%s: Couldn't register custom debugging class!\n",
+ "vfs_shadow_copy2_init"));
+ } else {
+ DEBUG(10, ("%s: Debug class number of '%s': %d\n",
+ "vfs_shadow_copy2_init","shadow_copy2",vfs_shadow_copy2_debug_level));
+ }
+
+ return ret;
+}
diff --git a/source3/modules/vfs_solarisacl.c b/source3/modules/vfs_solarisacl.c
new file mode 100644
index 0000000000..7bdfe8465b
--- /dev/null
+++ b/source3/modules/vfs_solarisacl.c
@@ -0,0 +1,787 @@
+/*
+ Unix SMB/Netbios implementation.
+ VFS module to get and set Solaris ACLs
+ Copyright (C) Michael Adam 2006,2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+
+
+/* typedef struct acl SOLARIS_ACE_T; */
+typedef aclent_t SOLARIS_ACE_T;
+typedef aclent_t *SOLARIS_ACL_T;
+typedef int SOLARIS_ACL_TAG_T; /* the type of an ACL entry */
+typedef o_mode_t SOLARIS_PERM_T;
+
+/* for convenience: check if solaris acl entry is a default entry? */
+#define _IS_DEFAULT(ace) ((ace).a_type & ACL_DEFAULT)
+#define _IS_OF_TYPE(ace, type) ( \
+ (((type) == SMB_ACL_TYPE_ACCESS) && !_IS_DEFAULT(ace)) \
+ || \
+ (((type) == SMB_ACL_TYPE_DEFAULT) && _IS_DEFAULT(ace)) \
+)
+
+
+/* prototypes for private functions */
+
+static SOLARIS_ACL_T solaris_acl_init(int count);
+static bool smb_acl_to_solaris_acl(SMB_ACL_T smb_acl,
+ SOLARIS_ACL_T *solariacl, int *count,
+ SMB_ACL_TYPE_T type);
+static SMB_ACL_T solaris_acl_to_smb_acl(SOLARIS_ACL_T solarisacl, int count,
+ SMB_ACL_TYPE_T type);
+static SOLARIS_ACL_TAG_T smb_tag_to_solaris_tag(SMB_ACL_TAG_T smb_tag);
+static SMB_ACL_TAG_T solaris_tag_to_smb_tag(SOLARIS_ACL_TAG_T solaris_tag);
+static bool solaris_add_to_acl(SOLARIS_ACL_T *solaris_acl, int *count,
+ SOLARIS_ACL_T add_acl, int add_count, SMB_ACL_TYPE_T type);
+static bool solaris_acl_get_file(const char *name, SOLARIS_ACL_T *solarisacl,
+ int *count);
+static bool solaris_acl_get_fd(int fd, SOLARIS_ACL_T *solarisacl, int *count);
+static bool solaris_acl_sort(SOLARIS_ACL_T acl, int count);
+static SMB_ACL_PERM_T solaris_perm_to_smb_perm(const SOLARIS_PERM_T perm);
+static SOLARIS_PERM_T smb_perm_to_solaris_perm(const SMB_ACL_PERM_T perm);
+static bool solaris_acl_check(SOLARIS_ACL_T solaris_acl, int count);
+
+
+/* public functions - the api */
+
+SMB_ACL_T solarisacl_sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ SMB_ACL_TYPE_T type)
+{
+ SMB_ACL_T result = NULL;
+ int count;
+ SOLARIS_ACL_T solaris_acl = NULL;
+
+ DEBUG(10, ("solarisacl_sys_acl_get_file called for file '%s'.\n",
+ path_p));
+
+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
+ DEBUG(10, ("invalid SMB_ACL_TYPE given (%d)\n", type));
+ errno = EINVAL;
+ goto done;
+ }
+
+ DEBUGADD(10, ("getting %s acl\n",
+ ((type == SMB_ACL_TYPE_ACCESS) ? "access" : "default")));
+
+ if (!solaris_acl_get_file(path_p, &solaris_acl, &count)) {
+ goto done;
+ }
+ result = solaris_acl_to_smb_acl(solaris_acl, count, type);
+ if (result == NULL) {
+ DEBUG(10, ("conversion solaris_acl -> smb_acl failed (%s).\n",
+ strerror(errno)));
+ }
+
+ done:
+ DEBUG(10, ("solarisacl_sys_acl_get_file %s.\n",
+ ((result == NULL) ? "failed" : "succeeded" )));
+ SAFE_FREE(solaris_acl);
+ return result;
+}
+
+
+/*
+ * get the access ACL of a file referred to by a fd
+ */
+SMB_ACL_T solarisacl_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp)
+{
+ SMB_ACL_T result = NULL;
+ int count;
+ SOLARIS_ACL_T solaris_acl = NULL;
+
+ DEBUG(10, ("entering solarisacl_sys_acl_get_fd.\n"));
+
+ if (!solaris_acl_get_fd(fsp->fh->fd, &solaris_acl, &count)) {
+ goto done;
+ }
+ /*
+ * The facl call returns both ACCESS and DEFAULT acls (as present).
+ * The posix acl_get_fd function returns only the
+ * access acl. So we need to filter this out here.
+ */
+ result = solaris_acl_to_smb_acl(solaris_acl, count,
+ SMB_ACL_TYPE_ACCESS);
+ if (result == NULL) {
+ DEBUG(10, ("conversion solaris_acl -> smb_acl failed (%s).\n",
+ strerror(errno)));
+ }
+
+ done:
+ DEBUG(10, ("solarisacl_sys_acl_get_fd %s.\n",
+ ((result == NULL) ? "failed" : "succeeded")));
+ SAFE_FREE(solaris_acl);
+ return result;
+}
+
+int solarisacl_sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl)
+{
+ int ret = -1;
+ struct stat s;
+ SOLARIS_ACL_T solaris_acl = NULL;
+ int count;
+
+ DEBUG(10, ("solarisacl_sys_acl_set_file called for file '%s'\n",
+ name));
+
+ if ((type != SMB_ACL_TYPE_ACCESS) && (type != SMB_ACL_TYPE_DEFAULT)) {
+ errno = EINVAL;
+ DEBUG(10, ("invalid smb acl type given (%d).\n", type));
+ goto done;
+ }
+ DEBUGADD(10, ("setting %s acl\n",
+ ((type == SMB_ACL_TYPE_ACCESS) ? "access" : "default")));
+
+ if(!smb_acl_to_solaris_acl(theacl, &solaris_acl, &count, type)) {
+ DEBUG(10, ("conversion smb_acl -> solaris_acl failed (%s).\n",
+ strerror(errno)));
+ goto done;
+ }
+
+ /*
+ * if the file is a directory, there is extra work to do:
+ * since the solaris acl call stores both the access acl and
+ * the default acl as provided, we have to get the acl part
+ * that has not been specified in "type" from the file first
+ * and concatenate it with the acl provided.
+ */
+ if (SMB_VFS_STAT(handle->conn, name, &s) != 0) {
+ DEBUG(10, ("Error in stat call: %s\n", strerror(errno)));
+ goto done;
+ }
+ if (S_ISDIR(s.st_mode)) {
+ SOLARIS_ACL_T other_acl;
+ int other_count;
+ SMB_ACL_TYPE_T other_type;
+
+ other_type = (type == SMB_ACL_TYPE_ACCESS)
+ ? SMB_ACL_TYPE_DEFAULT
+ : SMB_ACL_TYPE_ACCESS;
+ DEBUGADD(10, ("getting acl from filesystem\n"));
+ if (!solaris_acl_get_file(name, &other_acl, &other_count)) {
+ DEBUG(10, ("error getting acl from directory\n"));
+ goto done;
+ }
+ DEBUG(10, ("adding %s part of fs acl to given acl\n",
+ ((other_type == SMB_ACL_TYPE_ACCESS)
+ ? "access"
+ : "default")));
+ if (!solaris_add_to_acl(&solaris_acl, &count, other_acl,
+ other_count, other_type))
+ {
+ DEBUG(10, ("error adding other acl.\n"));
+ SAFE_FREE(other_acl);
+ goto done;
+ }
+ SAFE_FREE(other_acl);
+ }
+ else if (type != SMB_ACL_TYPE_ACCESS) {
+ errno = EINVAL;
+ goto done;
+ }
+
+ if (!solaris_acl_sort(solaris_acl, count)) {
+ DEBUG(10, ("resulting acl is not valid!\n"));
+ goto done;
+ }
+
+ ret = acl(name, SETACL, count, solaris_acl);
+
+ done:
+ DEBUG(10, ("solarisacl_sys_acl_set_file %s.\n",
+ ((ret != 0) ? "failed" : "succeeded")));
+ SAFE_FREE(solaris_acl);
+ return ret;
+}
+
+/*
+ * set the access ACL on the file referred to by a fd
+ */
+int solarisacl_sys_acl_set_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_T theacl)
+{
+ SOLARIS_ACL_T solaris_acl = NULL;
+ SOLARIS_ACL_T default_acl = NULL;
+ int count, default_count;
+ int ret = -1;
+
+ DEBUG(10, ("entering solarisacl_sys_acl_set_fd\n"));
+
+ /*
+ * the posix acl_set_fd call sets the access acl of the
+ * file referred to by fd. the solaris facl-SETACL call
+ * sets the access and default acl as provided, so we
+ * have to retrieve the default acl of the file and
+ * concatenate it with the access acl provided.
+ */
+ if (!smb_acl_to_solaris_acl(theacl, &solaris_acl, &count,
+ SMB_ACL_TYPE_ACCESS))
+ {
+ DEBUG(10, ("conversion smb_acl -> solaris_acl failed (%s).\n",
+ strerror(errno)));
+ goto done;
+ }
+ if (!solaris_acl_get_fd(fsp->fh->fd, &default_acl, &default_count)) {
+ DEBUG(10, ("error getting (default) acl from fd\n"));
+ goto done;
+ }
+ if (!solaris_add_to_acl(&solaris_acl, &count,
+ default_acl, default_count,
+ SMB_ACL_TYPE_DEFAULT))
+ {
+ DEBUG(10, ("error adding default acl to solaris acl\n"));
+ goto done;
+ }
+ if (!solaris_acl_sort(solaris_acl, count)) {
+ DEBUG(10, ("resulting acl is not valid!\n"));
+ goto done;
+ }
+
+ ret = facl(fsp->fh->fd, SETACL, count, solaris_acl);
+ if (ret != 0) {
+ DEBUG(10, ("call of facl failed (%s).\n", strerror(errno)));
+ }
+
+ done:
+ DEBUG(10, ("solarisacl_sys_acl_set_fd %s.\n",
+ ((ret == 0) ? "succeeded" : "failed" )));
+ SAFE_FREE(solaris_acl);
+ SAFE_FREE(default_acl);
+ return ret;
+}
+
+/*
+ * delete the default ACL of a directory
+ *
+ * This is achieved by fetching the access ACL and rewriting it
+ * directly, via the solaris system call: the SETACL call on
+ * directories writes both the access and the default ACL as provided.
+ *
+ * XXX: posix acl_delete_def_file returns an error if
+ * the file referred to by path is not a directory.
+ * this function does not complain but the actions
+ * have no effect on a file other than a directory.
+ * But sys_acl_delete_default_file is only called in
+ * smbd/posixacls.c after having checked that the file
+ * is a directory, anyways. So implementing the extra
+ * check is considered unnecessary. --- Agreed? XXX
+ */
+int solarisacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path)
+{
+ SMB_ACL_T smb_acl;
+ int ret = -1;
+ SOLARIS_ACL_T solaris_acl = NULL;
+ int count;
+
+ DEBUG(10, ("entering solarisacl_sys_acl_delete_def_file.\n"));
+
+ smb_acl = solarisacl_sys_acl_get_file(handle, path,
+ SMB_ACL_TYPE_ACCESS);
+ if (smb_acl == NULL) {
+ DEBUG(10, ("getting file acl failed!\n"));
+ goto done;
+ }
+ if (!smb_acl_to_solaris_acl(smb_acl, &solaris_acl, &count,
+ SMB_ACL_TYPE_ACCESS))
+ {
+ DEBUG(10, ("conversion smb_acl -> solaris_acl failed.\n"));
+ goto done;
+ }
+ if (!solaris_acl_sort(solaris_acl, count)) {
+ DEBUG(10, ("resulting acl is not valid!\n"));
+ goto done;
+ }
+ ret = acl(path, SETACL, count, solaris_acl);
+ if (ret != 0) {
+ DEBUG(10, ("settinge file acl failed!\n"));
+ }
+
+ done:
+ DEBUG(10, ("solarisacl_sys_acl_delete_def_file %s.\n",
+ ((ret != 0) ? "failed" : "succeeded" )));
+ SAFE_FREE(smb_acl);
+ return ret;
+}
+
+
+/* private functions */
+
+static SOLARIS_ACL_T solaris_acl_init(int count)
+{
+ SOLARIS_ACL_T solaris_acl =
+ (SOLARIS_ACL_T)SMB_MALLOC(sizeof(aclent_t) * count);
+ if (solaris_acl == NULL) {
+ errno = ENOMEM;
+ }
+ return solaris_acl;
+}
+
+/*
+ * Convert the SMB acl to the ACCESS or DEFAULT part of a
+ * solaris ACL, as desired.
+ */
+static bool smb_acl_to_solaris_acl(SMB_ACL_T smb_acl,
+ SOLARIS_ACL_T *solaris_acl, int *count,
+ SMB_ACL_TYPE_T type)
+{
+ bool ret = False;
+ int i;
+ int check_which, check_rc;
+
+ DEBUG(10, ("entering smb_acl_to_solaris_acl\n"));
+
+ *solaris_acl = NULL;
+ *count = 0;
+
+ for (i = 0; i < smb_acl->count; i++) {
+ const struct smb_acl_entry *smb_entry = &(smb_acl->acl[i]);
+ SOLARIS_ACE_T solaris_entry;
+
+ ZERO_STRUCT(solaris_entry);
+
+ solaris_entry.a_type = smb_tag_to_solaris_tag(smb_entry->a_type);
+ if (solaris_entry.a_type == 0) {
+ DEBUG(10, ("smb_tag to solaris_tag failed\n"));
+ goto fail;
+ }
+ switch(solaris_entry.a_type) {
+ case USER:
+ DEBUG(10, ("got tag type USER with uid %d\n",
+ smb_entry->uid));
+ solaris_entry.a_id = (uid_t)smb_entry->uid;
+ break;
+ case GROUP:
+ DEBUG(10, ("got tag type GROUP with gid %d\n",
+ smb_entry->gid));
+ solaris_entry.a_id = (uid_t)smb_entry->gid;
+ break;
+ default:
+ break;
+ }
+ if (type == SMB_ACL_TYPE_DEFAULT) {
+ DEBUG(10, ("adding default bit to solaris ace\n"));
+ solaris_entry.a_type |= ACL_DEFAULT;
+ }
+
+ solaris_entry.a_perm =
+ smb_perm_to_solaris_perm(smb_entry->a_perm);
+ DEBUG(10, ("assembled the following solaris ace:\n"));
+ DEBUGADD(10, (" - type: 0x%04x\n", solaris_entry.a_type));
+ DEBUGADD(10, (" - id: %d\n", solaris_entry.a_id));
+ DEBUGADD(10, (" - perm: o%o\n", solaris_entry.a_perm));
+ if (!solaris_add_to_acl(solaris_acl, count, &solaris_entry,
+ 1, type))
+ {
+ DEBUG(10, ("error adding acl entry\n"));
+ goto fail;
+ }
+ DEBUG(10, ("count after adding: %d (i: %d)\n", *count, i));
+ DEBUG(10, ("test, if entry has been copied into acl:\n"));
+ DEBUGADD(10, (" - type: 0x%04x\n",
+ (*solaris_acl)[(*count)-1].a_type));
+ DEBUGADD(10, (" - id: %d\n",
+ (*solaris_acl)[(*count)-1].a_id));
+ DEBUGADD(10, (" - perm: o%o\n",
+ (*solaris_acl)[(*count)-1].a_perm));
+ }
+
+ ret = True;
+ goto done;
+
+ fail:
+ SAFE_FREE(*solaris_acl);
+ done:
+ DEBUG(10, ("smb_acl_to_solaris_acl %s\n",
+ ((ret == True) ? "succeeded" : "failed")));
+ return ret;
+}
+
+/*
+ * convert either the access or the default part of a
+ * soaris acl to the SMB_ACL format.
+ */
+static SMB_ACL_T solaris_acl_to_smb_acl(SOLARIS_ACL_T solaris_acl, int count,
+ SMB_ACL_TYPE_T type)
+{
+ SMB_ACL_T result;
+ int i;
+
+ if ((result = sys_acl_init(0)) == NULL) {
+ DEBUG(10, ("error allocating memory for SMB_ACL\n"));
+ goto fail;
+ }
+ for (i = 0; i < count; i++) {
+ SMB_ACL_ENTRY_T smb_entry;
+ SMB_ACL_PERM_T smb_perm;
+
+ if (!_IS_OF_TYPE(solaris_acl[i], type)) {
+ continue;
+ }
+ result = SMB_REALLOC(result,
+ sizeof(struct smb_acl_t) +
+ (sizeof(struct smb_acl_entry) *
+ (result->count + 1)));
+ if (result == NULL) {
+ DEBUG(10, ("error reallocating memory for SMB_ACL\n"));
+ goto fail;
+ }
+ smb_entry = &result->acl[result->count];
+ if (sys_acl_set_tag_type(smb_entry,
+ solaris_tag_to_smb_tag(solaris_acl[i].a_type)) != 0)
+ {
+ DEBUG(10, ("invalid tag type given: 0x%04x\n",
+ solaris_acl[i].a_type));
+ goto fail;
+ }
+ /* intentionally not checking return code here: */
+ sys_acl_set_qualifier(smb_entry, (void *)&solaris_acl[i].a_id);
+ smb_perm = solaris_perm_to_smb_perm(solaris_acl[i].a_perm);
+ if (sys_acl_set_permset(smb_entry, &smb_perm) != 0) {
+ DEBUG(10, ("invalid permset given: %d\n",
+ solaris_acl[i].a_perm));
+ goto fail;
+ }
+ result->count += 1;
+ }
+ goto done;
+
+ fail:
+ SAFE_FREE(result);
+ done:
+ DEBUG(10, ("solaris_acl_to_smb_acl %s\n",
+ ((result == NULL) ? "failed" : "succeeded")));
+ return result;
+}
+
+
+
+static SOLARIS_ACL_TAG_T smb_tag_to_solaris_tag(SMB_ACL_TAG_T smb_tag)
+{
+ SOLARIS_ACL_TAG_T solaris_tag = 0;
+
+ DEBUG(10, ("smb_tag_to_solaris_tag\n"));
+ DEBUGADD(10, (" --> got smb tag 0x%04x\n", smb_tag));
+
+ switch (smb_tag) {
+ case SMB_ACL_USER:
+ solaris_tag = USER;
+ break;
+ case SMB_ACL_USER_OBJ:
+ solaris_tag = USER_OBJ;
+ break;
+ case SMB_ACL_GROUP:
+ solaris_tag = GROUP;
+ break;
+ case SMB_ACL_GROUP_OBJ:
+ solaris_tag = GROUP_OBJ;
+ break;
+ case SMB_ACL_OTHER:
+ solaris_tag = OTHER_OBJ;
+ break;
+ case SMB_ACL_MASK:
+ solaris_tag = CLASS_OBJ;
+ break;
+ default:
+ DEBUGADD(10, (" !!! unknown smb tag type 0x%04x\n", smb_tag));
+ break;
+ }
+
+ DEBUGADD(10, (" --> determined solaris tag 0x%04x\n", solaris_tag));
+
+ return solaris_tag;
+}
+
+static SMB_ACL_TAG_T solaris_tag_to_smb_tag(SOLARIS_ACL_TAG_T solaris_tag)
+{
+ SMB_ACL_TAG_T smb_tag = 0;
+
+ DEBUG(10, ("solaris_tag_to_smb_tag:\n"));
+ DEBUGADD(10, (" --> got solaris tag 0x%04x\n", solaris_tag));
+
+ solaris_tag &= ~ACL_DEFAULT;
+
+ switch (solaris_tag) {
+ case USER:
+ smb_tag = SMB_ACL_USER;
+ break;
+ case USER_OBJ:
+ smb_tag = SMB_ACL_USER_OBJ;
+ break;
+ case GROUP:
+ smb_tag = SMB_ACL_GROUP;
+ break;
+ case GROUP_OBJ:
+ smb_tag = SMB_ACL_GROUP_OBJ;
+ break;
+ case OTHER_OBJ:
+ smb_tag = SMB_ACL_OTHER;
+ break;
+ case CLASS_OBJ:
+ smb_tag = SMB_ACL_MASK;
+ break;
+ default:
+ DEBUGADD(10, (" !!! unknown solaris tag type: 0x%04x\n",
+ solaris_tag));
+ break;
+ }
+
+ DEBUGADD(10, (" --> determined smb tag 0x%04x\n", smb_tag));
+
+ return smb_tag;
+}
+
+
+static SMB_ACL_PERM_T solaris_perm_to_smb_perm(const SOLARIS_PERM_T perm)
+{
+ SMB_ACL_PERM_T smb_perm = 0;
+ smb_perm |= ((perm & SMB_ACL_READ) ? SMB_ACL_READ : 0);
+ smb_perm |= ((perm & SMB_ACL_WRITE) ? SMB_ACL_WRITE : 0);
+ smb_perm |= ((perm & SMB_ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
+ return smb_perm;
+}
+
+
+static SOLARIS_PERM_T smb_perm_to_solaris_perm(const SMB_ACL_PERM_T perm)
+{
+ SOLARIS_PERM_T solaris_perm = 0;
+ solaris_perm |= ((perm & SMB_ACL_READ) ? SMB_ACL_READ : 0);
+ solaris_perm |= ((perm & SMB_ACL_WRITE) ? SMB_ACL_WRITE : 0);
+ solaris_perm |= ((perm & SMB_ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
+ return solaris_perm;
+}
+
+
+static bool solaris_acl_get_file(const char *name, SOLARIS_ACL_T *solaris_acl,
+ int *count)
+{
+ bool result = False;
+
+ DEBUG(10, ("solaris_acl_get_file called for file '%s'\n", name));
+
+ /*
+ * The original code tries some INITIAL_ACL_SIZE
+ * and only did the GETACLCNT call upon failure
+ * (for performance reasons).
+ * For the sake of simplicity, I skip this for now.
+ */
+ *count = acl(name, GETACLCNT, 0, NULL);
+ if (*count < 0) {
+ DEBUG(10, ("acl GETACLCNT failed: %s\n", strerror(errno)));
+ goto done;
+ }
+ *solaris_acl = solaris_acl_init(*count);
+ if (*solaris_acl == NULL) {
+ DEBUG(10, ("error allocating memory for solaris acl...\n"));
+ goto done;
+ }
+ *count = acl(name, GETACL, *count, *solaris_acl);
+ if (*count < 0) {
+ DEBUG(10, ("acl GETACL failed: %s\n", strerror(errno)));
+ goto done;
+ }
+ result = True;
+
+ done:
+ DEBUG(10, ("solaris_acl_get_file %s.\n",
+ ((result == True) ? "succeeded" : "failed" )));
+ return result;
+}
+
+
+static bool solaris_acl_get_fd(int fd, SOLARIS_ACL_T *solaris_acl, int *count)
+{
+ bool ret = False;
+
+ DEBUG(10, ("entering solaris_acl_get_fd\n"));
+
+ /*
+ * see solaris_acl_get_file for comment about omission
+ * of INITIAL_ACL_SIZE...
+ */
+ *count = facl(fd, GETACLCNT, 0, NULL);
+ if (*count < 0) {
+ DEBUG(10, ("facl GETACLCNT failed: %s\n", strerror(errno)));
+ goto done;
+ }
+ *solaris_acl = solaris_acl_init(*count);
+ if (*solaris_acl == NULL) {
+ DEBUG(10, ("error allocating memory for solaris acl...\n"));
+ goto done;
+ }
+ *count = facl(fd, GETACL, *count, *solaris_acl);
+ if (*count < 0) {
+ DEBUG(10, ("facl GETACL failed: %s\n", strerror(errno)));
+ goto done;
+ }
+ ret = True;
+
+ done:
+ DEBUG(10, ("solaris_acl_get_fd %s\n",
+ ((ret == True) ? "succeeded" : "failed")));
+ return ret;
+}
+
+
+
+/*
+ * Add entries to a solaris ACL.
+ *
+ * Entries are directly added to the solarisacl parameter.
+ * if memory allocation fails, this may result in solarisacl
+ * being NULL. if the resulting acl is to be checked and is
+ * not valid, it is kept in solarisacl but False is returned.
+ *
+ * The type of ACEs (access/default) to be added to the ACL can
+ * be selected via the type parameter.
+ * I use the SMB_ACL_TYPE_T type here. Since SMB_ACL_TYPE_ACCESS
+ * is defined as "0", this means that one can only add either
+ * access or default ACEs, not both at the same time. If it
+ * should become necessary to add all of an ACL, one would have
+ * to replace this parameter by another type.
+ */
+static bool solaris_add_to_acl(SOLARIS_ACL_T *solaris_acl, int *count,
+ SOLARIS_ACL_T add_acl, int add_count,
+ SMB_ACL_TYPE_T type)
+{
+ int i;
+
+ if ((type != SMB_ACL_TYPE_ACCESS) && (type != SMB_ACL_TYPE_DEFAULT))
+ {
+ DEBUG(10, ("invalid acl type given: %d\n", type));
+ errno = EINVAL;
+ return False;
+ }
+ for (i = 0; i < add_count; i++) {
+ if (!_IS_OF_TYPE(add_acl[i], type)) {
+ continue;
+ }
+ ADD_TO_ARRAY(NULL, SOLARIS_ACE_T, add_acl[i],
+ solaris_acl, count);
+ if (solaris_acl == NULL) {
+ DEBUG(10, ("error enlarging acl.\n"));
+ errno = ENOMEM;
+ return False;
+ }
+ }
+ return True;
+}
+
+
+/*
+ * sort the ACL and check it for validity
+ *
+ * [original comment from lib/sysacls.c:]
+ *
+ * if it's a minimal ACL with only 4 entries then we
+ * need to recalculate the mask permissions to make
+ * sure that they are the same as the GROUP_OBJ
+ * permissions as required by the UnixWare acl() system call.
+ *
+ * (note: since POSIX allows minimal ACLs which only contain
+ * 3 entries - ie there is no mask entry - we should, in theory,
+ * check for this and add a mask entry if necessary - however
+ * we "know" that the caller of this interface always specifies
+ * a mask, so in practice "this never happens" (tm) - if it *does*
+ * happen aclsort() will fail and return an error and someone will
+ * have to fix it...)
+ */
+static bool solaris_acl_sort(SOLARIS_ACL_T solaris_acl, int count)
+{
+ int fixmask = (count <= 4);
+
+ if (aclsort(count, fixmask, solaris_acl) != 0) {
+ errno = EINVAL;
+ return False;
+ }
+ return True;
+}
+
+/*
+ * acl check function:
+ * unused at the moment but could be used to get more
+ * concrete error messages for debugging...
+ * (acl sort just says that the acl is invalid...)
+ */
+static bool solaris_acl_check(SOLARIS_ACL_T solaris_acl, int count)
+{
+ int check_rc;
+ int check_which;
+
+ check_rc = aclcheck(solaris_acl, count, &check_which);
+ if (check_rc != 0) {
+ DEBUG(10, ("acl is not valid:\n"));
+ DEBUGADD(10, (" - return code: %d\n", check_rc));
+ DEBUGADD(10, (" - which: %d\n", check_which));
+ if (check_which != -1) {
+ DEBUGADD(10, (" - invalid entry:\n"));
+ DEBUGADD(10, (" * type: %d:\n",
+ solaris_acl[check_which].a_type));
+ DEBUGADD(10, (" * id: %d\n",
+ solaris_acl[check_which].a_id));
+ DEBUGADD(10, (" * perm: 0o%o\n",
+ solaris_acl[check_which].a_perm));
+ }
+ return False;
+ }
+ return True;
+}
+
+
+/* VFS operations structure */
+
+static vfs_op_tuple solarisacl_op_tuples[] = {
+ /* Disk operations */
+ {SMB_VFS_OP(solarisacl_sys_acl_get_file),
+ SMB_VFS_OP_SYS_ACL_GET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(solarisacl_sys_acl_get_fd),
+ SMB_VFS_OP_SYS_ACL_GET_FD,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(solarisacl_sys_acl_set_file),
+ SMB_VFS_OP_SYS_ACL_SET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(solarisacl_sys_acl_set_fd),
+ SMB_VFS_OP_SYS_ACL_SET_FD,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(solarisacl_sys_acl_delete_def_file),
+ SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(NULL),
+ SMB_VFS_OP_NOOP,
+ SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_solarisacl_init(void);
+NTSTATUS vfs_solarisacl_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "solarisacl",
+ solarisacl_op_tuples);
+}
+
+/* ENTE */
diff --git a/source3/modules/vfs_solarisacl.h b/source3/modules/vfs_solarisacl.h
new file mode 100644
index 0000000000..84c2cb7ff7
--- /dev/null
+++ b/source3/modules/vfs_solarisacl.h
@@ -0,0 +1,45 @@
+/*
+ Unix SMB/Netbios implementation.
+ VFS module to get and set Solaris ACLs - prototype header
+ Copyright (C) Michael Adam 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __VFS_SOLARISACL_H__
+#define __VFS_SOLARISACL_H__
+
+SMB_ACL_T solarisacl_sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ SMB_ACL_TYPE_T type);
+
+SMB_ACL_T solarisacl_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp);
+
+int solarisacl_sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl);
+
+int solarisacl_sys_acl_set_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_T theacl);
+
+int solarisacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path);
+
+NTSTATUS vfs_solarisacl_init(void);
+
+#endif
+
diff --git a/source3/modules/vfs_streams_depot.c b/source3/modules/vfs_streams_depot.c
new file mode 100644
index 0000000000..d8c476f96f
--- /dev/null
+++ b/source3/modules/vfs_streams_depot.c
@@ -0,0 +1,641 @@
+/*
+ * Store streams in a separate subdirectory
+ *
+ * Copyright (C) Volker Lendecke, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+/*
+ * Excerpt from a mail from tridge:
+ *
+ * Volker, what I'm thinking of is this:
+ * /mount-point/.streams/XX/YY/aaaa.bbbb/namedstream1
+ * /mount-point/.streams/XX/YY/aaaa.bbbb/namedstream2
+ *
+ * where XX/YY is a 2 level hash based on the fsid/inode. "aaaa.bbbb"
+ * is the fsid/inode. "namedstreamX" is a file named after the stream
+ * name.
+ */
+
+static uint32_t hash_fn(DATA_BLOB key)
+{
+ uint32_t value; /* Used to compute the hash value. */
+ uint32_t i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * key.length, i=0; i < key.length; i++)
+ value = (value + (key.data[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345);
+}
+
+/*
+ * With the hashing scheme based on the inode we need to protect against
+ * streams showing up on files with re-used inodes. This can happen if we
+ * create a stream directory from within Samba, and a local process or NFS
+ * client deletes the file without deleting the streams directory. When the
+ * inode is re-used and the stream directory is still around, the streams in
+ * there would be show up as belonging to the new file.
+ *
+ * There are several workarounds for this, probably the easiest one is on
+ * systems which have a true birthtime stat element: When the file has a later
+ * birthtime than the streams directory, then we have to recreate the
+ * directory.
+ *
+ * The other workaround is to somehow mark the file as generated by Samba with
+ * something that a NFS client would not do. The closest one is a special
+ * xattr value being set. On systems which do not support xattrs, it might be
+ * an option to put in a special ACL entry for a non-existing group.
+ */
+
+#define SAMBA_XATTR_MARKER "user.SAMBA_STREAMS"
+
+static bool file_is_valid(vfs_handle_struct *handle, const char *path)
+{
+ char buf;
+
+ DEBUG(10, ("file_is_valid (%s) called\n", path));
+
+ if (SMB_VFS_NEXT_GETXATTR(handle, path, SAMBA_XATTR_MARKER,
+ &buf, sizeof(buf)) != sizeof(buf)) {
+ DEBUG(10, ("GETXATTR failed: %s\n", strerror(errno)));
+ return false;
+ }
+
+ if (buf != '1') {
+ DEBUG(10, ("got wrong buffer content: '%c'\n", buf));
+ return false;
+ }
+
+ return true;
+}
+
+static bool mark_file_valid(vfs_handle_struct *handle, const char *path)
+{
+ char buf = '1';
+ int ret;
+
+ DEBUG(10, ("marking file %s as valid\n", path));
+
+ ret = SMB_VFS_NEXT_SETXATTR(handle, path, SAMBA_XATTR_MARKER,
+ &buf, sizeof(buf), 0);
+
+ if (ret == -1) {
+ DEBUG(10, ("SETXATTR failed: %s\n", strerror(errno)));
+ return false;
+ }
+
+ return true;
+}
+
+static char *stream_dir(vfs_handle_struct *handle, const char *base_path,
+ const SMB_STRUCT_STAT *base_sbuf, bool create_it)
+{
+ uint32_t hash;
+ char *result = NULL;
+ SMB_STRUCT_STAT sbuf;
+ uint8_t first, second;
+ char *tmp;
+ char *id_hex;
+ struct file_id id;
+ uint8 id_buf[16];
+
+ const char *rootdir = lp_parm_const_string(
+ SNUM(handle->conn), "streams_depot", "directory",
+ handle->conn->connectpath);
+
+ if (base_sbuf == NULL) {
+ if (SMB_VFS_NEXT_STAT(handle, base_path, &sbuf) == -1) {
+ /*
+ * base file is not there
+ */
+ goto fail;
+ }
+ base_sbuf = &sbuf;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, base_sbuf->st_dev,
+ base_sbuf->st_ino);
+
+ push_file_id_16((char *)id_buf, &id);
+
+ hash = hash_fn(data_blob_const(id_buf, sizeof(id_buf)));
+
+ first = hash & 0xff;
+ second = (hash >> 8) & 0xff;
+
+ id_hex = hex_encode(talloc_tos(), id_buf, sizeof(id_buf));
+
+ if (id_hex == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ result = talloc_asprintf(talloc_tos(), "%s/%2.2X/%2.2X/%s", rootdir,
+ first, second, id_hex);
+
+ TALLOC_FREE(id_hex);
+
+ if (result == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ if (SMB_VFS_NEXT_STAT(handle, result, &sbuf) == 0) {
+ char *newname;
+
+ if (!S_ISDIR(sbuf.st_mode)) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ if (file_is_valid(handle, base_path)) {
+ return result;
+ }
+
+ /*
+ * Someone has recreated a file under an existing inode
+ * without deleting the streams directory. For now, just move
+ * it away.
+ */
+
+ again:
+ newname = talloc_asprintf(talloc_tos(), "lost-%lu", random());
+ if (newname == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ if (SMB_VFS_NEXT_RENAME(handle, result, newname) == -1) {
+ if ((errno == EEXIST) || (errno == ENOTEMPTY)) {
+ TALLOC_FREE(newname);
+ goto again;
+ }
+ goto fail;
+ }
+
+ TALLOC_FREE(newname);
+ }
+
+ if (!create_it) {
+ errno = ENOENT;
+ goto fail;
+ }
+
+ if ((SMB_VFS_NEXT_MKDIR(handle, rootdir, 0755) != 0)
+ && (errno != EEXIST)) {
+ goto fail;
+ }
+
+ tmp = talloc_asprintf(result, "%s/%2.2X", rootdir, first);
+ if (tmp == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ if ((SMB_VFS_NEXT_MKDIR(handle, tmp, 0755) != 0)
+ && (errno != EEXIST)) {
+ goto fail;
+ }
+
+ TALLOC_FREE(tmp);
+
+ tmp = talloc_asprintf(result, "%s/%2.2X/%2.2X", rootdir, first,
+ second);
+ if (tmp == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ if ((SMB_VFS_NEXT_MKDIR(handle, tmp, 0755) != 0)
+ && (errno != EEXIST)) {
+ goto fail;
+ }
+
+ TALLOC_FREE(tmp);
+
+ if ((SMB_VFS_NEXT_MKDIR(handle, result, 0755) != 0)
+ && (errno != EEXIST)) {
+ goto fail;
+ }
+
+ if (!mark_file_valid(handle, base_path)) {
+ goto fail;
+ }
+
+ return result;
+
+ fail:
+ TALLOC_FREE(result);
+ return NULL;
+}
+
+static char *stream_name(vfs_handle_struct *handle, const char *fname,
+ bool create_dir)
+{
+ char *base = NULL;
+ char *sname = NULL;
+ char *id_hex = NULL;
+ char *dirname, *stream_fname;
+
+ if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), fname,
+ &base, &sname))) {
+ DEBUG(10, ("split_ntfs_stream_name failed\n"));
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ dirname = stream_dir(handle, base, NULL, create_dir);
+
+ if (dirname == NULL) {
+ goto fail;
+ }
+
+ stream_fname = talloc_asprintf(talloc_tos(), "%s/:%s", dirname, sname);
+
+ if (stream_fname == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ DEBUG(10, ("stream filename = %s\n", stream_fname));
+
+ TALLOC_FREE(base);
+ TALLOC_FREE(sname);
+ TALLOC_FREE(id_hex);
+
+ return stream_fname;
+
+ fail:
+ DEBUG(5, ("stream_name failed: %s\n", strerror(errno)));
+ TALLOC_FREE(base);
+ TALLOC_FREE(sname);
+ TALLOC_FREE(id_hex);
+ return NULL;
+}
+
+static NTSTATUS walk_streams(vfs_handle_struct *handle,
+ const char *fname,
+ const SMB_STRUCT_STAT *sbuf,
+ char **pdirname,
+ bool (*fn)(const char *dirname,
+ const char *dirent,
+ void *private_data),
+ void *private_data)
+{
+ char *dirname;
+ SMB_STRUCT_DIR *dirhandle = NULL;
+ char *dirent;
+
+ dirname = stream_dir(handle, fname, sbuf, false);
+
+ if (dirname == NULL) {
+ if (errno == ENOENT) {
+ /*
+ * no stream around
+ */
+ return NT_STATUS_OK;
+ }
+ return map_nt_error_from_unix(errno);
+ }
+
+ DEBUG(10, ("walk_streams: dirname=%s\n", dirname));
+
+ dirhandle = SMB_VFS_NEXT_OPENDIR(handle, dirname, NULL, 0);
+
+ if (dirhandle == NULL) {
+ TALLOC_FREE(dirname);
+ return map_nt_error_from_unix(errno);
+ }
+
+ while ((dirent = vfs_readdirname(handle->conn, dirhandle)) != NULL) {
+
+ if (ISDOT(dirent) || ISDOTDOT(dirent)) {
+ continue;
+ }
+
+ DEBUG(10, ("walk_streams: dirent=%s\n", dirent));
+
+ if (!fn(dirname, dirent, private_data)) {
+ break;
+ }
+ }
+
+ SMB_VFS_NEXT_CLOSEDIR(handle, dirhandle);
+
+ if (pdirname != NULL) {
+ *pdirname = dirname;
+ }
+ else {
+ TALLOC_FREE(dirname);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static int streams_depot_stat(vfs_handle_struct *handle, const char *fname,
+ SMB_STRUCT_STAT *sbuf)
+{
+ char *stream_fname;
+ int ret = -1;
+
+ DEBUG(10, ("streams_depot_stat called for [%s]\n", fname));
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_STAT(handle, fname, sbuf);
+ }
+
+ stream_fname = stream_name(handle, fname, false);
+ if (stream_fname == NULL) {
+ goto done;
+ }
+
+ ret = SMB_VFS_NEXT_STAT(handle, stream_fname, sbuf);
+
+ done:
+ TALLOC_FREE(stream_fname);
+ return ret;
+}
+
+static int streams_depot_lstat(vfs_handle_struct *handle, const char *fname,
+ SMB_STRUCT_STAT *sbuf)
+{
+ char *stream_fname;
+ int ret = -1;
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_LSTAT(handle, fname, sbuf);
+ }
+
+ stream_fname = stream_name(handle, fname, false);
+ if (stream_fname == NULL) {
+ goto done;
+ }
+
+ ret = SMB_VFS_NEXT_LSTAT(handle, stream_fname, sbuf);
+
+ done:
+ TALLOC_FREE(stream_fname);
+ return ret;
+}
+
+static int streams_depot_open(vfs_handle_struct *handle, const char *fname,
+ files_struct *fsp, int flags, mode_t mode)
+{
+ TALLOC_CTX *frame;
+ char *base = NULL;
+ SMB_STRUCT_STAT base_sbuf;
+ char *stream_fname;
+ int ret = -1;
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+ }
+
+ frame = talloc_stackframe();
+
+ if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), fname,
+ &base, NULL))) {
+ errno = ENOMEM;
+ goto done;
+ }
+
+ ret = SMB_VFS_NEXT_STAT(handle, base, &base_sbuf);
+
+ if (ret == -1) {
+ goto done;
+ }
+
+ TALLOC_FREE(base);
+
+ stream_fname = stream_name(handle, fname, true);
+ if (stream_fname == NULL) {
+ goto done;
+ }
+
+ ret = SMB_VFS_NEXT_OPEN(handle, stream_fname, fsp, flags, mode);
+
+ done:
+ TALLOC_FREE(frame);
+ return ret;
+}
+
+static int streams_depot_unlink(vfs_handle_struct *handle, const char *fname)
+{
+ int ret = -1;
+ SMB_STRUCT_STAT sbuf;
+
+ DEBUG(10, ("streams_depot_unlink called for %s\n", fname));
+
+ if (is_ntfs_stream_name(fname)) {
+ char *stream_fname;
+
+ stream_fname = stream_name(handle, fname, false);
+ if (stream_fname == NULL) {
+ return -1;
+ }
+
+ ret = SMB_VFS_NEXT_UNLINK(handle, stream_fname);
+
+ TALLOC_FREE(stream_fname);
+ return ret;
+ }
+
+ /*
+ * We potentially need to delete the per-inode streams directory
+ */
+
+ if (SMB_VFS_NEXT_STAT(handle, fname, &sbuf) == -1) {
+ return -1;
+ }
+
+ if (sbuf.st_nlink == 1) {
+ char *dirname = stream_dir(handle, fname, &sbuf, false);
+
+ if (dirname != NULL) {
+ SMB_VFS_NEXT_RMDIR(handle, dirname);
+ }
+ TALLOC_FREE(dirname);
+ }
+
+ return SMB_VFS_NEXT_UNLINK(handle, fname);
+}
+
+static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
+ struct stream_struct **streams,
+ const char *name, SMB_OFF_T size,
+ SMB_OFF_T alloc_size)
+{
+ struct stream_struct *tmp;
+
+ tmp = TALLOC_REALLOC_ARRAY(mem_ctx, *streams, struct stream_struct,
+ (*num_streams)+1);
+ if (tmp == NULL) {
+ return false;
+ }
+
+ tmp[*num_streams].name = talloc_strdup(tmp, name);
+ if (tmp[*num_streams].name == NULL) {
+ return false;
+ }
+
+ tmp[*num_streams].size = size;
+ tmp[*num_streams].alloc_size = alloc_size;
+
+ *streams = tmp;
+ *num_streams += 1;
+ return true;
+}
+
+struct streaminfo_state {
+ TALLOC_CTX *mem_ctx;
+ vfs_handle_struct *handle;
+ unsigned int num_streams;
+ struct stream_struct *streams;
+ NTSTATUS status;
+};
+
+static bool collect_one_stream(const char *dirname,
+ const char *dirent,
+ void *private_data)
+{
+ struct streaminfo_state *state =
+ (struct streaminfo_state *)private_data;
+ char *full_sname;
+ SMB_STRUCT_STAT sbuf;
+
+ if (asprintf(&full_sname, "%s/%s", dirname, dirent) == -1) {
+ state->status = NT_STATUS_NO_MEMORY;
+ return false;
+ }
+ if (SMB_VFS_NEXT_STAT(state->handle, full_sname, &sbuf) == -1) {
+ DEBUG(10, ("Could not stat %s: %s\n", full_sname,
+ strerror(errno)));
+ SAFE_FREE(full_sname);
+ return true;
+ }
+
+ SAFE_FREE(full_sname);
+
+ if (!add_one_stream(state->mem_ctx,
+ &state->num_streams, &state->streams,
+ dirent, sbuf.st_size,
+ get_allocation_size(
+ state->handle->conn, NULL, &sbuf))) {
+ state->status = NT_STATUS_NO_MEMORY;
+ return false;
+ }
+
+ return true;
+}
+
+static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *fname,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *pnum_streams,
+ struct stream_struct **pstreams)
+{
+ SMB_STRUCT_STAT sbuf;
+ int ret;
+ NTSTATUS status;
+ struct streaminfo_state state;
+
+ if ((fsp != NULL) && (fsp->fh->fd != -1)) {
+ if (is_ntfs_stream_name(fsp->fsp_name)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf);
+ }
+ else {
+ if (is_ntfs_stream_name(fname)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ret = SMB_VFS_NEXT_STAT(handle, fname, &sbuf);
+ }
+
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ state.streams = NULL;
+ state.num_streams = 0;
+
+ if (!S_ISDIR(sbuf.st_mode)) {
+ if (!add_one_stream(mem_ctx,
+ &state.num_streams, &state.streams,
+ "::$DATA", sbuf.st_size,
+ get_allocation_size(handle->conn, fsp,
+ &sbuf))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ state.mem_ctx = mem_ctx;
+ state.handle = handle;
+ state.status = NT_STATUS_OK;
+
+ status = walk_streams(handle, fname, &sbuf, NULL, collect_one_stream,
+ &state);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(state.streams);
+ return status;
+ }
+
+ if (!NT_STATUS_IS_OK(state.status)) {
+ TALLOC_FREE(state.streams);
+ return state.status;
+ }
+
+ *pnum_streams = state.num_streams;
+ *pstreams = state.streams;
+ return NT_STATUS_OK;
+}
+
+static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle)
+{
+ return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple streams_depot_ops[] = {
+ {SMB_VFS_OP(streams_depot_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_depot_open), SMB_VFS_OP_OPEN,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_depot_stat), SMB_VFS_OP_STAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_depot_lstat), SMB_VFS_OP_LSTAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_depot_unlink), SMB_VFS_OP_UNLINK,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_depot_streaminfo), SMB_VFS_OP_STREAMINFO,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_streams_depot_init(void);
+NTSTATUS vfs_streams_depot_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_depot",
+ streams_depot_ops);
+}
diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c
new file mode 100644
index 0000000000..b74c4f7902
--- /dev/null
+++ b/source3/modules/vfs_streams_xattr.c
@@ -0,0 +1,685 @@
+/*
+ * Store streams in xattrs
+ *
+ * Copyright (C) Volker Lendecke, 2008
+ *
+ * Partly based on James Peach's Darwin module, which is
+ *
+ * Copyright (C) James Peach 2006-2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+struct stream_io {
+ char *base;
+ char *xattr_name;
+};
+
+static SMB_INO_T stream_inode(const SMB_STRUCT_STAT *sbuf, const char *sname)
+{
+ struct MD5Context ctx;
+ unsigned char hash[16];
+ SMB_INO_T result;
+ char *upper_sname;
+
+ DEBUG(10, ("stream_inode called for %lu/%lu [%s]\n",
+ (unsigned long)sbuf->st_dev,
+ (unsigned long)sbuf->st_ino, sname));
+
+ upper_sname = talloc_strdup_upper(talloc_tos(), sname);
+ SMB_ASSERT(upper_sname != NULL);
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, (unsigned char *)&(sbuf->st_dev),
+ sizeof(sbuf->st_dev));
+ MD5Update(&ctx, (unsigned char *)&(sbuf->st_ino),
+ sizeof(sbuf->st_ino));
+ MD5Update(&ctx, (unsigned char *)upper_sname,
+ talloc_get_size(upper_sname)-1);
+ MD5Final(hash, &ctx);
+
+ TALLOC_FREE(upper_sname);
+
+ /* Hopefully all the variation is in the lower 4 (or 8) bytes! */
+ memcpy(&result, hash, sizeof(result));
+
+ DEBUG(10, ("stream_inode returns %lu\n", (unsigned long)result));
+
+ return result;
+}
+
+static ssize_t get_xattr_size(connection_struct *conn, const char *fname,
+ const char *xattr_name)
+{
+ NTSTATUS status;
+ struct ea_struct ea;
+ ssize_t result;
+
+ status = get_ea_value(talloc_tos(), conn, NULL, fname,
+ xattr_name, &ea);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ result = ea.value.length-1;
+ TALLOC_FREE(ea.value.data);
+ return result;
+}
+
+
+static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_STRUCT_STAT *sbuf)
+{
+ struct stream_io *io = (struct stream_io *)
+ VFS_FETCH_FSP_EXTENSION(handle, fsp);
+
+ DEBUG(10, ("streams_xattr_fstat called for %d\n", fsp->fh->fd));
+
+ if (io == NULL) {
+ return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+ }
+
+ if (SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf) == -1) {
+ return -1;
+ }
+
+ sbuf->st_size = get_xattr_size(handle->conn, io->base, io->xattr_name);
+ if (sbuf->st_size == -1) {
+ return -1;
+ }
+
+ DEBUG(10, ("sbuf->st_size = %d\n", (int)sbuf->st_size));
+
+ sbuf->st_ino = stream_inode(sbuf, io->xattr_name);
+ sbuf->st_mode &= ~S_IFMT;
+ sbuf->st_mode |= S_IFREG;
+ sbuf->st_blocks = sbuf->st_size % STAT_ST_BLOCKSIZE + 1;
+
+ return 0;
+}
+
+static int streams_xattr_stat(vfs_handle_struct *handle, const char *fname,
+ SMB_STRUCT_STAT *sbuf)
+{
+ NTSTATUS status;
+ char *base = NULL, *sname = NULL;
+ int result = -1;
+ char *xattr_name;
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_STAT(handle, fname, sbuf);
+ }
+
+ status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (SMB_VFS_STAT(handle->conn, base, sbuf) == -1) {
+ goto fail;
+ }
+
+ xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
+ SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
+ if (xattr_name == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ sbuf->st_size = get_xattr_size(handle->conn, base, xattr_name);
+ if (sbuf->st_size == -1) {
+ errno = ENOENT;
+ goto fail;
+ }
+
+ sbuf->st_ino = stream_inode(sbuf, xattr_name);
+ sbuf->st_mode &= ~S_IFMT;
+ sbuf->st_mode |= S_IFREG;
+ sbuf->st_blocks = sbuf->st_size % STAT_ST_BLOCKSIZE + 1;
+
+ result = 0;
+ fail:
+ TALLOC_FREE(base);
+ TALLOC_FREE(sname);
+ return result;
+}
+
+static int streams_xattr_lstat(vfs_handle_struct *handle, const char *fname,
+ SMB_STRUCT_STAT *sbuf)
+{
+ NTSTATUS status;
+ char *base, *sname;
+ int result = -1;
+ char *xattr_name;
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_LSTAT(handle, fname, sbuf);
+ }
+
+ status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ if (SMB_VFS_LSTAT(handle->conn, base, sbuf) == -1) {
+ goto fail;
+ }
+
+ xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
+ SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
+ if (xattr_name == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ sbuf->st_size = get_xattr_size(handle->conn, base, xattr_name);
+ if (sbuf->st_size == -1) {
+ errno = ENOENT;
+ goto fail;
+ }
+
+ sbuf->st_ino = stream_inode(sbuf, xattr_name);
+ sbuf->st_mode &= ~S_IFMT;
+ sbuf->st_mode |= S_IFREG;
+ sbuf->st_blocks = sbuf->st_size % STAT_ST_BLOCKSIZE + 1;
+
+ result = 0;
+ fail:
+ TALLOC_FREE(base);
+ TALLOC_FREE(sname);
+ return result;
+}
+
+static int streams_xattr_open(vfs_handle_struct *handle, const char *fname,
+ files_struct *fsp, int flags, mode_t mode)
+{
+ TALLOC_CTX *frame;
+ NTSTATUS status;
+ struct stream_io *sio;
+ char *base, *sname;
+ struct ea_struct ea;
+ char *xattr_name;
+ int baseflags;
+ int hostfd = -1;
+
+ DEBUG(10, ("streams_xattr_open called for %s\n", fname));
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+ }
+
+ frame = talloc_stackframe();
+
+ status = split_ntfs_stream_name(talloc_tos(), fname,
+ &base, &sname);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
+ SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
+ if (xattr_name == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ /*
+ * We use baseflags to turn off nasty side-effects when opening the
+ * underlying file.
+ */
+ baseflags = flags;
+ baseflags &= ~O_TRUNC;
+ baseflags &= ~O_EXCL;
+ baseflags &= ~O_CREAT;
+
+ hostfd = SMB_VFS_OPEN(handle->conn, base, fsp, baseflags, mode);
+
+ /* It is legit to open a stream on a directory, but the base
+ * fd has to be read-only.
+ */
+ if ((hostfd == -1) && (errno == EISDIR)) {
+ baseflags &= ~O_ACCMODE;
+ baseflags |= O_RDONLY;
+ hostfd = SMB_VFS_OPEN(handle->conn, fname, fsp, baseflags,
+ mode);
+ }
+
+ if (hostfd == -1) {
+ goto fail;
+ }
+
+ status = get_ea_value(talloc_tos(), handle->conn, NULL, base,
+ xattr_name, &ea);
+
+ DEBUG(10, ("get_ea_value returned %s\n", nt_errstr(status)));
+
+ if (!NT_STATUS_IS_OK(status)
+ && !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+ /*
+ * The base file is not there. This is an error even if we got
+ * O_CREAT, the higher levels should have created the base
+ * file for us.
+ */
+ DEBUG(10, ("streams_xattr_open: base file %s not around, "
+ "returning ENOENT\n", base));
+ errno = ENOENT;
+ goto fail;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * The attribute does not exist
+ */
+
+ if (flags & O_CREAT) {
+ /*
+ * Darn, xattrs need at least 1 byte
+ */
+ char null = '\0';
+
+ DEBUG(10, ("creating attribute %s on file %s\n",
+ xattr_name, base));
+
+ if (SMB_VFS_SETXATTR(
+ handle->conn, base, xattr_name,
+ &null, sizeof(null),
+ flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
+ goto fail;
+ }
+ }
+ }
+
+ if (flags & O_TRUNC) {
+ char null = '\0';
+ if (SMB_VFS_SETXATTR(
+ handle->conn, base, xattr_name,
+ &null, sizeof(null),
+ flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
+ goto fail;
+ }
+ }
+
+ sio = (struct stream_io *)VFS_ADD_FSP_EXTENSION(handle, fsp,
+ struct stream_io);
+ if (sio == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
+ xattr_name);
+ sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
+ base);
+
+ if ((sio->xattr_name == NULL) || (sio->base == NULL)) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ TALLOC_FREE(frame);
+ return hostfd;
+
+ fail:
+ if (hostfd >= 0) {
+ /*
+ * BUGBUGBUG -- we would need to call fd_close_posix here, but
+ * we don't have a full fsp yet
+ */
+ SMB_VFS_CLOSE(fsp);
+ }
+
+ TALLOC_FREE(frame);
+ return -1;
+}
+
+static int streams_xattr_unlink(vfs_handle_struct *handle, const char *fname)
+{
+ NTSTATUS status;
+ char *base = NULL;
+ char *sname = NULL;
+ int ret = -1;
+ char *xattr_name;
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_UNLINK(handle, fname);
+ }
+
+ status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
+ SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
+ if (xattr_name == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ ret = SMB_VFS_REMOVEXATTR(handle->conn, base, xattr_name);
+
+ if ((ret == -1) && (errno == ENOATTR)) {
+ errno = ENOENT;
+ goto fail;
+ }
+
+ ret = 0;
+
+ fail:
+ TALLOC_FREE(base);
+ TALLOC_FREE(sname);
+ return ret;
+}
+
+static NTSTATUS walk_xattr_streams(connection_struct *conn, files_struct *fsp,
+ const char *fname,
+ bool (*fn)(struct ea_struct *ea,
+ void *private_data),
+ void *private_data)
+{
+ NTSTATUS status;
+ char **names;
+ size_t i, num_names;
+ size_t prefix_len = strlen(SAMBA_XATTR_DOSSTREAM_PREFIX);
+
+ status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
+ &names, &num_names);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ for (i=0; i<num_names; i++) {
+ struct ea_struct ea;
+
+ if (strncmp(names[i], SAMBA_XATTR_DOSSTREAM_PREFIX,
+ prefix_len) != 0) {
+ continue;
+ }
+
+ status = get_ea_value(names, conn, fsp, fname, names[i], &ea);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Could not get ea %s for file %s: %s\n",
+ names[i], fname, nt_errstr(status)));
+ continue;
+ }
+
+ ea.name = talloc_asprintf(ea.value.data, ":%s",
+ names[i] + prefix_len);
+ if (ea.name == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ continue;
+ }
+
+ if (!fn(&ea, private_data)) {
+ TALLOC_FREE(ea.value.data);
+ return NT_STATUS_OK;
+ }
+
+ TALLOC_FREE(ea.value.data);
+ }
+
+ TALLOC_FREE(names);
+ return NT_STATUS_OK;
+}
+
+static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
+ struct stream_struct **streams,
+ const char *name, SMB_OFF_T size,
+ SMB_OFF_T alloc_size)
+{
+ struct stream_struct *tmp;
+
+ tmp = TALLOC_REALLOC_ARRAY(mem_ctx, *streams, struct stream_struct,
+ (*num_streams)+1);
+ if (tmp == NULL) {
+ return false;
+ }
+
+ tmp[*num_streams].name = talloc_strdup(tmp, name);
+ if (tmp[*num_streams].name == NULL) {
+ return false;
+ }
+
+ tmp[*num_streams].size = size;
+ tmp[*num_streams].alloc_size = alloc_size;
+
+ *streams = tmp;
+ *num_streams += 1;
+ return true;
+}
+
+struct streaminfo_state {
+ TALLOC_CTX *mem_ctx;
+ vfs_handle_struct *handle;
+ unsigned int num_streams;
+ struct stream_struct *streams;
+ NTSTATUS status;
+};
+
+static bool collect_one_stream(struct ea_struct *ea, void *private_data)
+{
+ struct streaminfo_state *state =
+ (struct streaminfo_state *)private_data;
+
+ if (!add_one_stream(state->mem_ctx,
+ &state->num_streams, &state->streams,
+ ea->name, ea->value.length-1,
+ smb_roundup(state->handle->conn,
+ ea->value.length-1))) {
+ state->status = NT_STATUS_NO_MEMORY;
+ return false;
+ }
+
+ return true;
+}
+
+static NTSTATUS streams_xattr_streaminfo(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *fname,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *pnum_streams,
+ struct stream_struct **pstreams)
+{
+ SMB_STRUCT_STAT sbuf;
+ int ret;
+ NTSTATUS status;
+ struct streaminfo_state state;
+
+ if ((fsp != NULL) && (fsp->fh->fd != -1)) {
+ if (is_ntfs_stream_name(fsp->fsp_name)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ret = SMB_VFS_FSTAT(fsp, &sbuf);
+ }
+ else {
+ if (is_ntfs_stream_name(fname)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ret = SMB_VFS_STAT(handle->conn, fname, &sbuf);
+ }
+
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ state.streams = NULL;
+ state.num_streams = 0;
+
+ if (!S_ISDIR(sbuf.st_mode)) {
+ if (!add_one_stream(mem_ctx,
+ &state.num_streams, &state.streams,
+ "::$DATA", sbuf.st_size,
+ get_allocation_size(handle->conn, fsp,
+ &sbuf))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ state.mem_ctx = mem_ctx;
+ state.handle = handle;
+ state.status = NT_STATUS_OK;
+
+ status = walk_xattr_streams(handle->conn, fsp, fname,
+ collect_one_stream, &state);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(state.streams);
+ return status;
+ }
+
+ if (!NT_STATUS_IS_OK(state.status)) {
+ TALLOC_FREE(state.streams);
+ return state.status;
+ }
+
+ *pnum_streams = state.num_streams;
+ *pstreams = state.streams;
+ return NT_STATUS_OK;
+}
+
+static uint32_t streams_xattr_fs_capabilities(struct vfs_handle_struct *handle)
+{
+ return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS;
+}
+
+static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
+ files_struct *fsp, const void *data,
+ size_t n, SMB_OFF_T offset)
+{
+ struct stream_io *sio =
+ (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct ea_struct ea;
+ NTSTATUS status;
+ int ret;
+
+ DEBUG(10, ("streams_xattr_pwrite called for %d bytes\n", (int)n));
+
+ if (sio == NULL) {
+ return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+ }
+
+ status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
+ sio->base, sio->xattr_name, &ea);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ if ((offset + n) > ea.value.length-1) {
+ uint8 *tmp;
+
+ tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), ea.value.data, uint8,
+ offset + n + 1);
+
+ if (tmp == NULL) {
+ TALLOC_FREE(ea.value.data);
+ errno = ENOMEM;
+ return -1;
+ }
+ ea.value.data = tmp;
+ ea.value.length = offset + n + 1;
+ ea.value.data[offset+n] = 0;
+ }
+
+ memcpy(ea.value.data + offset, data, n);
+
+ ret = SMB_VFS_SETXATTR(fsp->conn, fsp->base_fsp->fsp_name,
+ sio->xattr_name,
+ ea.value.data, ea.value.length, 0);
+
+ TALLOC_FREE(ea.value.data);
+
+ if (ret == -1) {
+ return -1;
+ }
+
+ return n;
+}
+
+static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
+ files_struct *fsp, void *data,
+ size_t n, SMB_OFF_T offset)
+{
+ struct stream_io *sio =
+ (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct ea_struct ea;
+ NTSTATUS status;
+ size_t length, overlap;
+
+ if (sio == NULL) {
+ return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
+ }
+
+ status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
+ sio->base, sio->xattr_name, &ea);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ length = ea.value.length-1;
+
+ /* Attempt to read past EOF. */
+ if (length <= offset) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ overlap = (offset + n) > length ? (length - offset) : n;
+ memcpy(data, ea.value.data + offset, overlap);
+
+ TALLOC_FREE(ea.value.data);
+ return overlap;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple streams_xattr_ops[] = {
+ {SMB_VFS_OP(streams_xattr_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_open), SMB_VFS_OP_OPEN,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_stat), SMB_VFS_OP_STAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_fstat), SMB_VFS_OP_FSTAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_lstat), SMB_VFS_OP_LSTAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_pread), SMB_VFS_OP_PREAD,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_pwrite), SMB_VFS_OP_PWRITE,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_lstat), SMB_VFS_OP_LSTAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_unlink), SMB_VFS_OP_UNLINK,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_streaminfo), SMB_VFS_OP_STREAMINFO,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_streams_xattr_init(void);
+NTSTATUS vfs_streams_xattr_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_xattr",
+ streams_xattr_ops);
+}
diff --git a/source3/modules/vfs_syncops.c b/source3/modules/vfs_syncops.c
new file mode 100644
index 0000000000..d3f7868400
--- /dev/null
+++ b/source3/modules/vfs_syncops.c
@@ -0,0 +1,210 @@
+/*
+ * ensure meta data operations are performed synchronously
+ *
+ * Copyright (C) Andrew Tridgell 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/*
+
+ Some filesystems (even some journaled filesystems) require that a
+ fsync() be performed on many meta data operations to ensure that the
+ operation is guaranteed to remain in the filesystem after a power
+ failure. This is particularly important for some cluster filesystems
+ which are participating in a node failover system with clustered
+ Samba
+
+ On those filesystems this module provides a way to perform those
+ operations safely.
+ */
+
+/*
+ most of the performance loss with this module is in fsync on close().
+ You can disable that with syncops:onclose = no
+ */
+static bool sync_onclose;
+
+/*
+ given a filename, find the parent directory
+ */
+static char *parent_dir(TALLOC_CTX *mem_ctx, const char *name)
+{
+ const char *p = strrchr(name, '/');
+ if (p == NULL) {
+ return talloc_strdup(mem_ctx, ".");
+ }
+ return talloc_strndup(mem_ctx, name, (p+1) - name);
+}
+
+/*
+ fsync a directory by name
+ */
+static void syncops_sync_directory(const char *dname)
+{
+#ifdef O_DIRECTORY
+ int fd = open(dname, O_DIRECTORY|O_RDONLY);
+ if (fd != -1) {
+ fsync(fd);
+ close(fd);
+ }
+#else
+ DIR *d = opendir(dname);
+ if (d != NULL) {
+ fsync(dirfd(d));
+ closedir(d);
+ }
+#endif
+}
+
+/*
+ sync two meta data changes for 2 names
+ */
+static void syncops_two_names(const char *name1, const char *name2)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ char *parent1, *parent2;
+ parent1 = parent_dir(tmp_ctx, name1);
+ parent2 = parent_dir(tmp_ctx, name2);
+ if (!parent1 || !parent2) {
+ talloc_free(tmp_ctx);
+ return;
+ }
+ syncops_sync_directory(parent1);
+ if (strcmp(parent1, parent2) != 0) {
+ syncops_sync_directory(parent2);
+ }
+ talloc_free(tmp_ctx);
+}
+
+/*
+ sync two meta data changes for 1 names
+ */
+static void syncops_name(const char *name)
+{
+ char *parent;
+ parent = parent_dir(NULL, name);
+ if (parent) {
+ syncops_sync_directory(parent);
+ talloc_free(parent);
+ }
+}
+
+
+/*
+ rename needs special handling, as we may need to fsync two directories
+ */
+static int syncops_rename(vfs_handle_struct *handle,
+ const char *oldname, const char *newname)
+{
+ int ret = SMB_VFS_NEXT_RENAME(handle, oldname, newname);
+ if (ret == 0) {
+ syncops_two_names(oldname, newname);
+ }
+ return ret;
+}
+
+/* handle the rest with a macro */
+#define SYNCOPS_NEXT(op, fname, args) do { \
+ int ret = SMB_VFS_NEXT_ ## op args; \
+ if (ret == 0 && fname) syncops_name(fname); \
+ return ret; \
+} while (0)
+
+static int syncops_symlink(vfs_handle_struct *handle,
+ const char *oldname, const char *newname)
+{
+ SYNCOPS_NEXT(SYMLINK, newname, (handle, oldname, newname));
+}
+
+static int syncops_link(vfs_handle_struct *handle,
+ const char *oldname, const char *newname)
+{
+ SYNCOPS_NEXT(LINK, newname, (handle, oldname, newname));
+}
+
+static int syncops_open(vfs_handle_struct *handle,
+ const char *fname, files_struct *fsp, int flags, mode_t mode)
+{
+ SYNCOPS_NEXT(OPEN, (flags&O_CREAT?fname:NULL), (handle, fname, fsp, flags, mode));
+}
+
+static int syncops_unlink(vfs_handle_struct *handle, const char *fname)
+{
+ SYNCOPS_NEXT(UNLINK, fname, (handle, fname));
+}
+
+static int syncops_mknod(vfs_handle_struct *handle,
+ const char *fname, mode_t mode, SMB_DEV_T dev)
+{
+ SYNCOPS_NEXT(MKNOD, fname, (handle, fname, mode, dev));
+}
+
+static int syncops_mkdir(vfs_handle_struct *handle, const char *fname, mode_t mode)
+{
+ SYNCOPS_NEXT(MKDIR, fname, (handle, fname, mode));
+}
+
+static int syncops_rmdir(vfs_handle_struct *handle, const char *fname)
+{
+ SYNCOPS_NEXT(RMDIR, fname, (handle, fname));
+}
+
+/* close needs to be handled specially */
+static int syncops_close(vfs_handle_struct *handle, files_struct *fsp)
+{
+ if (fsp->can_write && sync_onclose) {
+ /* ideally we'd only do this if we have written some
+ data, but there is no flag for that in fsp yet. */
+ fsync(fsp->fh->fd);
+ }
+ return SMB_VFS_NEXT_CLOSE(handle, fsp);
+}
+
+
+/* VFS operations structure */
+
+static vfs_op_tuple syncops_ops[] = {
+ /* directory operations */
+ {SMB_VFS_OP(syncops_mkdir), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(syncops_rmdir), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* File operations */
+ {SMB_VFS_OP(syncops_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(syncops_rename), SMB_VFS_OP_RENAME, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(syncops_unlink), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(syncops_symlink), SMB_VFS_OP_SYMLINK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(syncops_link), SMB_VFS_OP_LINK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(syncops_mknod), SMB_VFS_OP_MKNOD, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(syncops_close), SMB_VFS_OP_CLOSE, SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_syncops_init(void)
+{
+ NTSTATUS ret;
+
+ ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "syncops", syncops_ops);
+
+ if (!NT_STATUS_IS_OK(ret))
+ return ret;
+
+ sync_onclose = lp_parm_bool(-1, "syncops", "onclose", true);
+
+ return ret;
+}
diff --git a/source3/modules/vfs_tru64acl.c b/source3/modules/vfs_tru64acl.c
new file mode 100644
index 0000000000..b23a7ddcfa
--- /dev/null
+++ b/source3/modules/vfs_tru64acl.c
@@ -0,0 +1,503 @@
+/*
+ Unix SMB/Netbios implementation.
+ VFS module to get and set Tru64 acls
+ Copyright (C) Michael Adam 2006,2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* prototypes for private functions first - for clarity */
+
+static struct smb_acl_t *tru64_acl_to_smb_acl(const struct acl *tru64_acl);
+static bool tru64_ace_to_smb_ace(acl_entry_t tru64_ace,
+ struct smb_acl_entry *smb_ace);
+static acl_t smb_acl_to_tru64_acl(const SMB_ACL_T smb_acl);
+static acl_tag_t smb_tag_to_tru64(SMB_ACL_TAG_T smb_tag);
+static SMB_ACL_TAG_T tru64_tag_to_smb(acl_tag_t tru64_tag);
+static acl_perm_t smb_permset_to_tru64(SMB_ACL_PERM_T smb_permset);
+static SMB_ACL_PERM_T tru64_permset_to_smb(const acl_perm_t tru64_permset);
+
+
+/* public functions - the api */
+
+SMB_ACL_T tru64acl_sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ SMB_ACL_TYPE_T type)
+{
+ struct smb_acl_t *result;
+ acl_type_t the_acl_type;
+ acl_t tru64_acl;
+
+ DEBUG(10, ("Hi! This is tru64acl_sys_acl_get_file.\n"));
+
+ switch(type) {
+ case SMB_ACL_TYPE_ACCESS:
+ the_acl_type = ACL_TYPE_ACCESS;
+ break;
+ case SMB_ACL_TYPE_DEFAULT:
+ the_acl_type = ACL_TYPE_DEFAULT;
+ break;
+ default:
+ errno = EINVAL;
+ return NULL;
+ }
+
+ tru64_acl = acl_get_file((char *)path_p, the_acl_type);
+
+ if (tru64_acl == NULL) {
+ return NULL;
+ }
+
+ result = tru64_acl_to_smb_acl(tru64_acl);
+ acl_free(tru64_acl);
+ return result;
+}
+
+SMB_ACL_T tru64acl_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp)
+{
+ struct smb_acl_t *result;
+ acl_t tru64_acl = acl_get_fd(fsp->fh->fd, ACL_TYPE_ACCESS);
+
+ if (tru64_acl == NULL) {
+ return NULL;
+ }
+
+ result = tru64_acl_to_smb_acl(tru64_acl);
+ acl_free(tru64_acl);
+ return result;
+}
+
+int tru64acl_sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl)
+{
+ int res;
+ acl_type_t the_acl_type;
+ acl_t tru64_acl;
+
+ DEBUG(10, ("tru64acl_sys_acl_set_file called with name %s, type %d\n",
+ name, type));
+
+ switch(type) {
+ case SMB_ACL_TYPE_ACCESS:
+ DEBUGADD(10, ("got acl type ACL_TYPE_ACCESS\n"));
+ the_acl_type = ACL_TYPE_ACCESS;
+ break;
+ case SMB_ACL_TYPE_DEFAULT:
+ DEBUGADD(10, ("got acl type ACL_TYPE_DEFAULT\n"));
+ the_acl_type = ACL_TYPE_DEFAULT;
+ break;
+ default:
+ DEBUGADD(10, ("invalid acl type\n"));
+ errno = EINVAL;
+ goto fail;
+ }
+
+ tru64_acl = smb_acl_to_tru64_acl(theacl);
+ if (tru64_acl == NULL) {
+ DEBUG(10, ("smb_acl_to_tru64_acl failed!\n"));
+ goto fail;
+ }
+ DEBUG(10, ("got tru64 acl...\n"));
+ res = acl_set_file((char *)name, the_acl_type, tru64_acl);
+ acl_free(tru64_acl);
+ if (res != 0) {
+ DEBUG(10, ("acl_set_file failed: %s\n", strerror(errno)));
+ goto fail;
+ }
+ return res;
+fail:
+ DEBUG(1, ("tru64acl_sys_acl_set_file failed!\n"));
+ return -1;
+}
+
+int tru64acl_sys_acl_set_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_T theacl)
+{
+ int res;
+ acl_t tru64_acl = smb_acl_to_tru64_acl(theacl);
+ if (tru64_acl == NULL) {
+ return -1;
+ }
+ res = acl_set_fd(fsp->fh->fd, ACL_TYPE_ACCESS, tru64_acl);
+ acl_free(tru64_acl);
+ return res;
+
+}
+
+int tru64acl_sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path)
+{
+ return acl_delete_def_file((char *)path);
+}
+
+
+/* private functions */
+
+static struct smb_acl_t *tru64_acl_to_smb_acl(const struct acl *tru64_acl)
+{
+ struct smb_acl_t *result;
+ acl_entry_t entry;
+
+ DEBUG(10, ("Hi! This is tru64_acl_to_smb_acl.\n"));
+
+ if ((result = SMB_MALLOC_P(struct smb_acl_t)) == NULL) {
+ DEBUG(0, ("SMB_MALLOC_P failed in tru64_acl_to_smb_acl\n"));
+ errno = ENOMEM;
+ goto fail;
+ }
+ ZERO_STRUCTP(result);
+ if (acl_first_entry((struct acl *)tru64_acl) != 0) {
+ DEBUG(10, ("acl_first_entry failed: %s\n", strerror(errno)));
+ goto fail;
+ }
+ while ((entry = acl_get_entry((struct acl *)tru64_acl)) != NULL) {
+ result = SMB_REALLOC(result, sizeof(struct smb_acl_t) +
+ (sizeof(struct smb_acl_entry) *
+ (result->count + 1)));
+ if (result == NULL) {
+ DEBUG(0, ("SMB_REALLOC failed in tru64_acl_to_smb_acl\n"));
+ errno = ENOMEM;
+ goto fail;
+ }
+ /* XYZ */
+ if (!tru64_ace_to_smb_ace(entry, &result->acl[result->count])) {
+ SAFE_FREE(result);
+ goto fail;
+ }
+ result->count += 1;
+ }
+ return result;
+
+fail:
+ if (result != NULL) {
+ SAFE_FREE(result);
+ }
+ DEBUG(1, ("tru64_acl_to_smb_acl failed!\n"));
+ return NULL;
+}
+
+static bool tru64_ace_to_smb_ace(acl_entry_t tru64_ace,
+ struct smb_acl_entry *smb_ace)
+{
+ acl_tag_t tru64_tag;
+ acl_permset_t permset;
+ SMB_ACL_TAG_T smb_tag_type;
+ SMB_ACL_PERM_T smb_permset;
+ void *qualifier;
+
+ if (acl_get_tag_type(tru64_ace, &tru64_tag) != 0) {
+ DEBUG(0, ("acl_get_tag_type failed: %s\n", strerror(errno)));
+ return False;
+ }
+
+ /* On could set the tag type directly to save a function call,
+ * but I like this better... */
+ smb_tag_type = tru64_tag_to_smb(tru64_tag);
+ if (smb_tag_type == 0) {
+ DEBUG(3, ("invalid tag type given: %d\n", tru64_tag));
+ return False;
+ }
+ if (sys_acl_set_tag_type(smb_ace, smb_tag_type) != 0) {
+ DEBUG(3, ("sys_acl_set_tag_type failed: %s\n",
+ strerror(errno)));
+ return False;
+ }
+ qualifier = acl_get_qualifier(tru64_ace);
+ if (qualifier != NULL) {
+ if (sys_acl_set_qualifier(smb_ace, qualifier) != 0) {
+ DEBUG(3, ("sys_acl_set_qualifier failed\n"));
+ return False;
+ }
+ }
+ if (acl_get_permset(tru64_ace, &permset) != 0) {
+ DEBUG(3, ("acl_get_permset failed: %s\n", strerror(errno)));
+ return False;
+ }
+ smb_permset = tru64_permset_to_smb(*permset);
+ if (sys_acl_set_permset(smb_ace, &smb_permset) != 0) {
+ DEBUG(3, ("sys_acl_set_permset failed: %s\n", strerror(errno)));
+ return False;
+ }
+ return True;
+}
+
+static acl_t smb_acl_to_tru64_acl(const SMB_ACL_T smb_acl)
+{
+ acl_t result;
+ acl_entry_t tru64_entry;
+ int i;
+ char *acl_text;
+ ssize_t acl_text_len;
+
+ /* The tru64 acl_init function takes a size_t value
+ * instead of a count of entries (as with posix).
+ * the size parameter "Specifies the size of the working
+ * storage in bytes" (according to the man page).
+ * But it is unclear to me, how this size is to be
+ * calculated.
+ *
+ * It should not matter, since acl_create_entry enlarges
+ * the working storage at need. ... */
+
+ DEBUG(10, ("Hi! This is smb_acl_to_tru64_acl.\n"));
+
+ result = acl_init(1);
+
+ if (result == NULL) {
+ DEBUG(3, ("acl_init failed!\n"));
+ goto fail;
+ }
+
+ DEBUGADD(10, ("parsing acl entries...\n"));
+ for (i = 0; i < smb_acl->count; i++) {
+ /* XYZ - maybe eliminate this direct access? */
+ const struct smb_acl_entry *smb_entry = &smb_acl->acl[i];
+ acl_tag_t tru64_tag;
+ acl_perm_t tru64_permset;
+
+ tru64_tag = smb_tag_to_tru64(smb_entry->a_type);
+ if (tru64_tag == -1) {
+ DEBUG(3, ("smb_tag_to_tru64 failed!\n"));
+ goto fail;
+ }
+
+ if (tru64_tag == ACL_MASK) {
+ DEBUGADD(10, (" - acl type ACL_MASK: not implemented on Tru64 ==> skipping\n"));
+ continue;
+ }
+
+ tru64_entry = acl_create_entry(&result);
+ if (tru64_entry == NULL) {
+ DEBUG(3, ("acl_create_entry failed: %s\n",
+ strerror(errno)));
+ goto fail;
+ }
+
+ if (acl_set_tag_type(tru64_entry, tru64_tag) != 0) {
+ DEBUG(3, ("acl_set_tag_type(%d) failed: %s\n",
+ strerror(errno)));
+ goto fail;
+ }
+
+ switch (smb_entry->a_type) {
+ case SMB_ACL_USER:
+ if (acl_set_qualifier(tru64_entry,
+ (int *)&smb_entry->uid) != 0)
+ {
+ DEBUG(3, ("acl_set_qualifier failed: %s\n",
+ strerror(errno)));
+ goto fail;
+ }
+ DEBUGADD(10, (" - setting uid to %d\n", smb_entry->uid));
+ break;
+ case SMB_ACL_GROUP:
+ if (acl_set_qualifier(tru64_entry,
+ (int *)&smb_entry->gid) != 0)
+ {
+ DEBUG(3, ("acl_set_qualifier failed: %s\n",
+ strerror(errno)));
+ goto fail;
+ }
+ DEBUGADD(10, (" - setting gid to %d\n", smb_entry->gid));
+ break;
+ default:
+ break;
+ }
+
+ tru64_permset = smb_permset_to_tru64(smb_entry->a_perm);
+ if (tru64_permset == -1) {
+ DEBUG(3, ("smb_permset_to_tru64 failed!\n"));
+ goto fail;
+ }
+ DEBUGADD(10, (" - setting perms to %0d\n", tru64_permset));
+ if (acl_set_permset(tru64_entry, &tru64_permset) != 0)
+ {
+ DEBUG(3, ("acl_set_permset failed: %s\n", strerror(errno)));
+ goto fail;
+ }
+ } /* for */
+ DEBUGADD(10, ("done parsing acl entries\n"));
+
+ tru64_entry = NULL;
+ if (acl_valid(result, &tru64_entry) != 0) {
+ DEBUG(1, ("smb_acl_to_tru64_acl: ACL is invalid (%s)\n",
+ strerror(errno)));
+ if (tru64_entry != NULL) {
+ DEBUGADD(1, ("the acl contains duplicate entries\n"));
+ }
+ goto fail;
+ }
+ DEBUGADD(10, ("acl is valid\n"));
+
+ acl_text = acl_to_text(result, &acl_text_len);
+ if (acl_text == NULL) {
+ DEBUG(3, ("acl_to_text failed: %s\n", strerror(errno)));
+ goto fail;
+ }
+ DEBUG(1, ("acl_text: %s\n", acl_text));
+ free(acl_text);
+
+ return result;
+
+fail:
+ if (result != NULL) {
+ acl_free(result);
+ }
+ DEBUG(1, ("smb_acl_to_tru64_acl failed!\n"));
+ return NULL;
+}
+
+static acl_tag_t smb_tag_to_tru64(SMB_ACL_TAG_T smb_tag)
+{
+ acl_tag_t result;
+ switch (smb_tag) {
+ case SMB_ACL_USER:
+ result = ACL_USER;
+ DEBUGADD(10, ("got acl type ACL_USER\n"));
+ break;
+ case SMB_ACL_USER_OBJ:
+ result = ACL_USER_OBJ;
+ DEBUGADD(10, ("got acl type ACL_USER_OBJ\n"));
+ break;
+ case SMB_ACL_GROUP:
+ result = ACL_GROUP;
+ DEBUGADD(10, ("got acl type ACL_GROUP\n"));
+ break;
+ case SMB_ACL_GROUP_OBJ:
+ result = ACL_GROUP_OBJ;
+ DEBUGADD(10, ("got acl type ACL_GROUP_OBJ\n"));
+ break;
+ case SMB_ACL_OTHER:
+ result = ACL_OTHER;
+ DEBUGADD(10, ("got acl type ACL_OTHER\n"));
+ break;
+ case SMB_ACL_MASK:
+ result = ACL_MASK;
+ DEBUGADD(10, ("got acl type ACL_MASK\n"));
+ break;
+ default:
+ DEBUG(1, ("Unknown tag type %d\n", smb_tag));
+ result = -1;
+ }
+ return result;
+}
+
+
+static SMB_ACL_TAG_T tru64_tag_to_smb(acl_tag_t tru64_tag)
+{
+ SMB_ACL_TAG_T smb_tag_type;
+ switch(tru64_tag) {
+ case ACL_USER:
+ smb_tag_type = SMB_ACL_USER;
+ DEBUGADD(10, ("got smb acl tag type SMB_ACL_USER\n"));
+ break;
+ case ACL_USER_OBJ:
+ smb_tag_type = SMB_ACL_USER_OBJ;
+ DEBUGADD(10, ("got smb acl tag type SMB_ACL_USER_OBJ\n"));
+ break;
+ case ACL_GROUP:
+ smb_tag_type = SMB_ACL_GROUP;
+ DEBUGADD(10, ("got smb acl tag type SMB_ACL_GROUP\n"));
+ break;
+ case ACL_GROUP_OBJ:
+ smb_tag_type = SMB_ACL_GROUP_OBJ;
+ DEBUGADD(10, ("got smb acl tag type SMB_ACL_GROUP_OBJ\n"));
+ break;
+ case ACL_OTHER:
+ smb_tag_type = SMB_ACL_OTHER;
+ DEBUGADD(10, ("got smb acl tag type SMB_ACL_OTHER\n"));
+ break;
+ case ACL_MASK:
+ smb_tag_type = SMB_ACL_MASK;
+ DEBUGADD(10, ("got smb acl tag type SMB_ACL_MASK\n"));
+ break;
+ default:
+ DEBUG(0, ("Unknown tag type %d\n", (unsigned int)tru64_tag));
+ smb_tag_type = 0;
+ }
+ return smb_tag_type;
+}
+
+static acl_perm_t smb_permset_to_tru64(SMB_ACL_PERM_T smb_permset)
+{
+ /* originally, I thought that acl_clear_perm was the
+ * proper way to reset the permset to 0. but without
+ * initializing it to 0, acl_clear_perm fails.
+ * so probably, acl_clear_perm is not necessary here... ?! */
+ acl_perm_t tru64_permset = 0;
+ if (acl_clear_perm(&tru64_permset) != 0) {
+ DEBUG(5, ("acl_clear_perm failed: %s\n", strerror(errno)));
+ return -1;
+ }
+ /* according to original lib/sysacls.c, acl_add_perm is
+ * broken on tru64 ... */
+ tru64_permset |= ((smb_permset & SMB_ACL_READ) ? ACL_READ : 0);
+ tru64_permset |= ((smb_permset & SMB_ACL_WRITE) ? ACL_WRITE : 0);
+ tru64_permset |= ((smb_permset & SMB_ACL_EXECUTE) ? ACL_EXECUTE : 0);
+ return tru64_permset;
+}
+
+static SMB_ACL_PERM_T tru64_permset_to_smb(const acl_perm_t tru64_permset)
+{
+ SMB_ACL_PERM_T smb_permset = 0;
+ smb_permset |= ((tru64_permset & ACL_READ) ? SMB_ACL_READ : 0);
+ smb_permset |= ((tru64_permset & ACL_WRITE) ? SMB_ACL_WRITE : 0);
+ smb_permset |= ((tru64_permset & ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
+ return smb_permset;
+}
+
+
+/* VFS operations structure */
+
+static vfs_op_tuple tru64acl_op_tuples[] = {
+ /* Disk operations */
+ {SMB_VFS_OP(tru64acl_sys_acl_get_file),
+ SMB_VFS_OP_SYS_ACL_GET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(tru64acl_sys_acl_get_fd),
+ SMB_VFS_OP_SYS_ACL_GET_FD,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(tru64acl_sys_acl_set_file),
+ SMB_VFS_OP_SYS_ACL_SET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(tru64acl_sys_acl_set_fd),
+ SMB_VFS_OP_SYS_ACL_SET_FD,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(tru64acl_sys_acl_delete_def_file),
+ SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(NULL),
+ SMB_VFS_OP_NOOP,
+ SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_tru64acl_init(void);
+NTSTATUS vfs_tru64acl_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "tru64acl",
+ tru64acl_op_tuples);
+}
+
+/* ENTE */
diff --git a/source3/modules/vfs_tru64acl.h b/source3/modules/vfs_tru64acl.h
new file mode 100644
index 0000000000..af79e2f9b6
--- /dev/null
+++ b/source3/modules/vfs_tru64acl.h
@@ -0,0 +1,45 @@
+/*
+ Unix SMB/Netbios implementation.
+ VFS module to get and set Tru64 acls - prototype header
+ Copyright (C) Michael Adam 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __VFS_TRU64ACL_H__
+#define __VFS_TRU64ACL_H__
+
+SMB_ACL_T tru64acl_sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ SMB_ACL_TYPE_T type);
+
+SMB_ACL_T tru64acl_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp);
+
+int tru64acl_sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl);
+
+int tru64acl_sys_acl_set_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_T theacl);
+
+int tru64acl_sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path);
+
+NTSTATUS vfs_tru64acl_init(void);
+
+#endif
+
diff --git a/source3/modules/vfs_tsmsm.c b/source3/modules/vfs_tsmsm.c
new file mode 100644
index 0000000000..ee958b1be5
--- /dev/null
+++ b/source3/modules/vfs_tsmsm.c
@@ -0,0 +1,396 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba VFS module for handling offline files
+ with Tivoli Storage Manager Space Management
+
+ (c) Alexander Bokovoy, 2007, 2008
+ (c) Andrew Tridgell, 2007, 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ This VFS module accepts following options:
+ tsmsm: hsm script = <path to hsm script> (default does nothing)
+ hsm script should point to a shell script which accepts two arguments:
+ <operation> <filepath>
+ where <operation> is currently 'offline' to set offline status of the <filepath>
+
+ tsmsm: online ratio = ratio to check reported size against actual file size (0.5 by default)
+ tsmsm: attribute name = name of DMAPI attribute that is present when a file is offline.
+ Default is "IBMobj" (which is what GPFS uses)
+
+ The TSMSM VFS module tries to avoid calling expensive DMAPI calls with some heuristics
+ based on the fact that number of blocks reported of a file multiplied by 512 will be
+ bigger than 'online ratio' of actual size for online (non-migrated) files.
+
+ If checks fail, we call DMAPI and ask for specific attribute which present for
+ offline (migrated) files. If this attribute presents, we consider file offline.
+ */
+
+#include "includes.h"
+
+#ifndef USE_DMAPI
+#error "This module requires DMAPI support!"
+#endif
+
+#ifdef HAVE_XFS_DMAPI_H
+#include <xfs/dmapi.h>
+#elif defined(HAVE_SYS_DMI_H)
+#include <sys/dmi.h>
+#elif defined(HAVE_SYS_JFSDMAPI_H)
+#include <sys/jfsdmapi.h>
+#elif defined(HAVE_SYS_DMAPI_H)
+#include <sys/dmapi.h>
+#elif defined(HAVE_DMAPI_H)
+#include <dmapi.h>
+#endif
+
+#ifndef _ISOC99_SOURCE
+#define _ISOC99_SOURCE
+#endif
+
+#include <math.h>
+
+/* optimisation tunables - used to avoid the DMAPI slow path */
+#define FILE_IS_ONLINE_RATIO 0.5
+
+/* default attribute name to look for */
+#define DM_ATTRIB_OBJECT "IBMObj"
+
+struct tsmsm_struct {
+ float online_ratio;
+ char *hsmscript;
+ const char *attrib_name;
+ const char *attrib_value;
+};
+
+static void tsmsm_free_data(void **pptr) {
+ struct tsmsm_struct **tsmd = (struct tsmsm_struct **)pptr;
+ if(!tsmd) return;
+ TALLOC_FREE(*tsmd);
+}
+
+/*
+ called when a client connects to a share
+*/
+static int tsmsm_connect(struct vfs_handle_struct *handle,
+ const char *service,
+ const char *user) {
+ struct tsmsm_struct *tsmd = TALLOC_ZERO_P(handle, struct tsmsm_struct);
+ const char *fres;
+ const char *tsmname;
+
+ if (!tsmd) {
+ DEBUG(0,("tsmsm_connect: out of memory!\n"));
+ return -1;
+ }
+
+ if (!dmapi_have_session()) {
+ DEBUG(0,("tsmsm_connect: no DMAPI session for Samba is available!\n"));
+ TALLOC_FREE(tsmd);
+ return -1;
+ }
+
+ tsmname = (handle->param ? handle->param : "tsmsm");
+
+ /* Get 'hsm script' and 'dmapi attribute' parameters to tsmd context */
+ tsmd->hsmscript = lp_parm_talloc_string(SNUM(handle->conn), tsmname,
+ "hsm script", NULL);
+ talloc_steal(tsmd, tsmd->hsmscript);
+
+ tsmd->attrib_name = lp_parm_talloc_string(SNUM(handle->conn), tsmname,
+ "dmapi attribute", DM_ATTRIB_OBJECT);
+ talloc_steal(tsmd, tsmd->attrib_name);
+
+ tsmd->attrib_value = lp_parm_talloc_string(SNUM(handle->conn), "tsmsm",
+ "dmapi value", NULL);
+ talloc_steal(tsmd, tsmd->attrib_value);
+
+ /* retrieve 'online ratio'. In case of error default to FILE_IS_ONLINE_RATIO */
+ fres = lp_parm_const_string(SNUM(handle->conn), tsmname,
+ "online ratio", NULL);
+ if (fres == NULL) {
+ tsmd->online_ratio = FILE_IS_ONLINE_RATIO;
+ } else {
+ tsmd->online_ratio = strtof(fres, NULL);
+ if (tsmd->online_ratio > 1.0 ||
+ tsmd->online_ratio <= 0.0) {
+ DEBUG(1, ("tsmsm_connect: invalid online ration %f - using %f.\n",
+ tsmd->online_ratio, (float)FILE_IS_ONLINE_RATIO));
+ }
+ }
+
+ /* Store the private data. */
+ SMB_VFS_HANDLE_SET_DATA(handle, tsmd, tsmsm_free_data,
+ struct tsmsm_struct, return -1);
+ return SMB_VFS_NEXT_CONNECT(handle, service, user);
+}
+
+static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
+ const char *path,
+ SMB_STRUCT_STAT *stbuf) {
+ struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data;
+ const dm_sessid_t *dmsession_id;
+ void *dmhandle = NULL;
+ size_t dmhandle_len = 0;
+ size_t rlen;
+ dm_attrname_t dmname;
+ int ret, lerrno;
+ bool offline;
+ char *buf;
+ size_t buflen;
+
+ /* if the file has more than FILE_IS_ONLINE_RATIO of blocks available,
+ then assume it is not offline (it may not be 100%, as it could be sparse) */
+ if (512 * (off_t)stbuf->st_blocks >= stbuf->st_size * tsmd->online_ratio) {
+ DEBUG(10,("%s not offline: st_blocks=%ld st_size=%ld "
+ "online_ratio=%.2f\n", path, (long)stbuf->st_blocks,
+ (long)stbuf->st_size, tsmd->online_ratio));
+ return false;
+ }
+
+ dmsession_id = dmapi_get_current_session();
+ if (dmsession_id == NULL) {
+ DEBUG(2, ("tsmsm_is_offline: no DMAPI session available? "
+ "Assume file is online.\n"));
+ return false;
+ }
+
+ /* using POSIX capabilities does not work here. It's a slow path, so
+ * become_root() is just as good anyway (tridge)
+ */
+
+ /* Also, AIX has DMAPI but no POSIX capablities support. In this case,
+ * we need to be root to do DMAPI manipulations.
+ */
+ become_root();
+
+ /* go the slow DMAPI route */
+ if (dm_path_to_handle((char*)path, &dmhandle, &dmhandle_len) != 0) {
+ DEBUG(2,("dm_path_to_handle failed - assuming offline (%s) - %s\n",
+ path, strerror(errno)));
+ offline = true;
+ goto done;
+ }
+
+ memset(&dmname, 0, sizeof(dmname));
+ strlcpy((char *)&dmname.an_chars[0], tsmd->attrib_name, sizeof(dmname.an_chars));
+
+ if (tsmd->attrib_value != NULL) {
+ buflen = strlen(tsmd->attrib_value);
+ } else {
+ buflen = 1;
+ }
+ buf = talloc_zero_size(tsmd, buflen);
+ if (buf == NULL) {
+ DEBUG(0,("out of memory in tsmsm_is_offline -- assuming online (%s)\n", path));
+ errno = ENOMEM;
+ offline = false;
+ goto done;
+ }
+
+ do {
+ lerrno = 0;
+
+ ret = dm_get_dmattr(*dmsession_id, dmhandle, dmhandle_len,
+ DM_NO_TOKEN, &dmname, buflen, buf, &rlen);
+ if (ret == -1 && errno == EINVAL) {
+ DEBUG(0, ("Stale DMAPI session, re-creating it.\n"));
+ lerrno = EINVAL;
+ if (dmapi_new_session()) {
+ dmsession_id = dmapi_get_current_session();
+ } else {
+ DEBUG(0,
+ ("Unable to re-create DMAPI session, assuming offline (%s) - %s\n",
+ path, strerror(errno)));
+ offline = true;
+ dm_handle_free(dmhandle, dmhandle_len);
+ goto done;
+ }
+ }
+ } while (ret == -1 && lerrno == EINVAL);
+
+ /* check if we need a specific attribute value */
+ if (tsmd->attrib_value != NULL) {
+ offline = (ret == 0 && rlen == buflen &&
+ memcmp(buf, tsmd->attrib_value, buflen) == 0);
+ } else {
+ /* its offline if the specified DMAPI attribute exists */
+ offline = (ret == 0 || (ret == -1 && errno == E2BIG));
+ }
+
+ DEBUG(10,("dm_get_dmattr %s ret=%d (%s)\n", path, ret, strerror(errno)));
+
+ ret = 0;
+
+ dm_handle_free(dmhandle, dmhandle_len);
+
+done:
+ talloc_free(buf);
+ unbecome_root();
+ return offline;
+}
+
+
+static bool tsmsm_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data;
+ /* see if the file might be offline. This is called before each IO
+ to ensure we use AIO if the file is offline. We don't do the full dmapi
+ call as that would be too slow, instead we err on the side of using AIO
+ if the file might be offline
+ */
+ if(SMB_VFS_FSTAT(fsp, &sbuf) == 0) {
+ DEBUG(10,("tsmsm_aio_force st_blocks=%ld st_size=%ld "
+ "online_ratio=%.2f\n", (long)sbuf.st_blocks,
+ (long)sbuf.st_size, tsmd->online_ratio));
+ return !(512 * (off_t)sbuf.st_blocks >= sbuf.st_size * tsmd->online_ratio);
+ }
+ return false;
+}
+
+static ssize_t tsmsm_aio_return(struct vfs_handle_struct *handle, struct files_struct *fsp,
+ SMB_STRUCT_AIOCB *aiocb)
+{
+ ssize_t result;
+
+ result = SMB_VFS_NEXT_AIO_RETURN(handle, fsp, aiocb);
+ if(result >= 0) {
+ notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES,
+ fsp->fsp_name);
+ }
+
+ return result;
+}
+
+static ssize_t tsmsm_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fsp, const DATA_BLOB *hdr,
+ SMB_OFF_T offset, size_t n)
+{
+ bool file_offline = tsmsm_aio_force(handle, fsp);
+
+ if (file_offline) {
+ DEBUG(10,("tsmsm_sendfile on offline file - rejecting\n"));
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, hdr, offset, n);
+}
+
+/* We do overload pread to allow notification when file becomes online after offline status */
+/* We don't intercept SMB_VFS_READ here because all file I/O now goes through SMB_VFS_PREAD instead */
+static ssize_t tsmsm_pread(struct vfs_handle_struct *handle, struct files_struct *fsp,
+ void *data, size_t n, SMB_OFF_T offset) {
+ ssize_t result;
+ bool notify_online = tsmsm_aio_force(handle, fsp);
+
+ result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
+ if((result != -1) && notify_online) {
+ /* We can't actually force AIO at this point (came here not from reply_read_and_X)
+ what we can do is to send notification that file became online
+ */
+ notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES,
+ fsp->fsp_name);
+ }
+
+ return result;
+}
+
+static ssize_t tsmsm_pwrite(struct vfs_handle_struct *handle, struct files_struct *fsp,
+ void *data, size_t n, SMB_OFF_T offset) {
+ ssize_t result;
+ bool notify_online = tsmsm_aio_force(handle, fsp);
+
+ result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+ if((result != -1) && notify_online) {
+ /* We can't actually force AIO at this point (came here not from reply_read_and_X)
+ what we can do is to send notification that file became online
+ */
+ notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES,
+ fsp->fsp_name);
+ }
+
+ return result;
+}
+
+static int tsmsm_set_offline(struct vfs_handle_struct *handle,
+ const char *path) {
+ struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data;
+ int result = 0;
+ char *command;
+
+ if (tsmd->hsmscript == NULL) {
+ /* no script enabled */
+ DEBUG(1, ("tsmsm_set_offline: No 'tsmsm:hsm script' configured\n"));
+ return 0;
+ }
+
+ /* Now, call the script */
+ command = talloc_asprintf(tsmd, "%s offline \"%s\"", tsmd->hsmscript, path);
+ if(!command) {
+ DEBUG(1, ("tsmsm_set_offline: can't allocate memory to run hsm script"));
+ return -1;
+ }
+ DEBUG(10, ("tsmsm_set_offline: Running [%s]\n", command));
+ if((result = smbrun(command, NULL)) != 0) {
+ DEBUG(1,("tsmsm_set_offline: Running [%s] returned %d\n", command, result));
+ }
+ TALLOC_FREE(command);
+ return result;
+}
+
+static uint32_t tsmsm_fs_capabilities(struct vfs_handle_struct *handle)
+{
+ return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_SUPPORTS_REMOTE_STORAGE | FILE_SUPPORTS_REPARSE_POINTS;
+}
+
+static vfs_op_tuple vfs_tsmsm_ops[] = {
+
+ /* Disk operations */
+
+ {SMB_VFS_OP(tsmsm_connect), SMB_VFS_OP_CONNECT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(tsmsm_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(tsmsm_aio_force), SMB_VFS_OP_AIO_FORCE,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(tsmsm_aio_return), SMB_VFS_OP_AIO_RETURN,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(tsmsm_pread), SMB_VFS_OP_PREAD,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(tsmsm_pwrite), SMB_VFS_OP_PWRITE,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(tsmsm_sendfile), SMB_VFS_OP_SENDFILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(tsmsm_is_offline), SMB_VFS_OP_IS_OFFLINE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(tsmsm_set_offline), SMB_VFS_OP_SET_OFFLINE,
+ SMB_VFS_LAYER_OPAQUE},
+
+ /* Finish VFS operations definition */
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP,
+ SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_tsmsm_init(void);
+NTSTATUS vfs_tsmsm_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
+ "tsmsm", vfs_tsmsm_ops);
+}
diff --git a/source3/modules/vfs_xattr_tdb.c b/source3/modules/vfs_xattr_tdb.c
new file mode 100644
index 0000000000..7b5e510747
--- /dev/null
+++ b/source3/modules/vfs_xattr_tdb.c
@@ -0,0 +1,759 @@
+/*
+ * Store posix-level xattrs in a tdb
+ *
+ * Copyright (C) Volker Lendecke, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/xattr.h"
+#include "librpc/gen_ndr/ndr_xattr.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+/*
+ * unmarshall tdb_xattrs
+ */
+
+static NTSTATUS xattr_tdb_pull_attrs(TALLOC_CTX *mem_ctx,
+ const TDB_DATA *data,
+ struct tdb_xattrs **presult)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ struct tdb_xattrs *result;
+
+ if (!(result = TALLOC_ZERO_P(mem_ctx, struct tdb_xattrs))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (data->dsize == 0) {
+ *presult = result;
+ return NT_STATUS_OK;
+ }
+
+ blob = data_blob_const(data->dptr, data->dsize);
+
+ ndr_err = ndr_pull_struct_blob(
+ &blob, result, result,
+ (ndr_pull_flags_fn_t)ndr_pull_tdb_xattrs);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_pull_tdb_xattrs failed: %s\n",
+ ndr_errstr(ndr_err)));
+ TALLOC_FREE(result);
+ return ndr_map_error2ntstatus(ndr_err);;
+ }
+
+ *presult = result;
+ return NT_STATUS_OK;
+}
+
+/*
+ * marshall tdb_xattrs
+ */
+
+static NTSTATUS xattr_tdb_push_attrs(TALLOC_CTX *mem_ctx,
+ const struct tdb_xattrs *attribs,
+ TDB_DATA *data)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_push_struct_blob(
+ &blob, mem_ctx, attribs,
+ (ndr_push_flags_fn_t)ndr_push_tdb_xattrs);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_push_tdb_xattrs failed: %s\n",
+ ndr_errstr(ndr_err)));
+ return ndr_map_error2ntstatus(ndr_err);;
+ }
+
+ *data = make_tdb_data(blob.data, blob.length);
+ return NT_STATUS_OK;
+}
+
+/*
+ * Load tdb_xattrs for a file from the tdb
+ */
+
+static NTSTATUS xattr_tdb_load_attrs(TALLOC_CTX *mem_ctx,
+ struct db_context *db_ctx,
+ const struct file_id *id,
+ struct tdb_xattrs **presult)
+{
+ uint8 id_buf[16];
+ NTSTATUS status;
+ TDB_DATA data;
+
+ push_file_id_16((char *)id_buf, id);
+
+ if (db_ctx->fetch(db_ctx, mem_ctx,
+ make_tdb_data(id_buf, sizeof(id_buf)),
+ &data) == -1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ status = xattr_tdb_pull_attrs(mem_ctx, &data, presult);
+ TALLOC_FREE(data.dptr);
+ return status;
+}
+
+/*
+ * fetch_lock the tdb_ea record for a file
+ */
+
+static struct db_record *xattr_tdb_lock_attrs(TALLOC_CTX *mem_ctx,
+ struct db_context *db_ctx,
+ const struct file_id *id)
+{
+ uint8 id_buf[16];
+ push_file_id_16((char *)id_buf, id);
+ return db_ctx->fetch_locked(db_ctx, mem_ctx,
+ make_tdb_data(id_buf, sizeof(id_buf)));
+}
+
+/*
+ * Save tdb_xattrs to a previously fetch_locked record
+ */
+
+static NTSTATUS xattr_tdb_save_attrs(struct db_record *rec,
+ const struct tdb_xattrs *attribs)
+{
+ TDB_DATA data = tdb_null;
+ NTSTATUS status;
+
+ status = xattr_tdb_push_attrs(talloc_tos(), attribs, &data);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("xattr_tdb_push_attrs failed: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ status = rec->store(rec, data, 0);
+
+ TALLOC_FREE(data.dptr);
+
+ return status;
+}
+
+/*
+ * Worker routine for getxattr and fgetxattr
+ */
+
+static ssize_t xattr_tdb_getattr(struct db_context *db_ctx,
+ const struct file_id *id,
+ const char *name, void *value, size_t size)
+{
+ struct tdb_xattrs *attribs;
+ uint32_t i;
+ ssize_t result = -1;
+ NTSTATUS status;
+
+ DEBUG(10, ("xattr_tdb_getattr called for file %s, name %s\n",
+ file_id_string_tos(id), name));
+
+ status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
+ nt_errstr(status)));
+ errno = EINVAL;
+ return -1;
+ }
+
+ for (i=0; i<attribs->num_xattrs; i++) {
+ if (strcmp(attribs->xattrs[i].name, name) == 0) {
+ break;
+ }
+ }
+
+ if (i == attribs->num_xattrs) {
+ errno = ENOATTR;
+ goto fail;
+ }
+
+ if (attribs->xattrs[i].value.length > size) {
+ errno = ERANGE;
+ goto fail;
+ }
+
+ memcpy(value, attribs->xattrs[i].value.data,
+ attribs->xattrs[i].value.length);
+ result = attribs->xattrs[i].value.length;
+
+ fail:
+ TALLOC_FREE(attribs);
+ return result;
+}
+
+static ssize_t xattr_tdb_getxattr(struct vfs_handle_struct *handle,
+ const char *path, const char *name,
+ void *value, size_t size)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ return xattr_tdb_getattr(db, &id, name, value, size);
+}
+
+static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *name, void *value, size_t size)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ return xattr_tdb_getattr(db, &id, name, value, size);
+}
+
+/*
+ * Worker routine for setxattr and fsetxattr
+ */
+
+static int xattr_tdb_setattr(struct db_context *db_ctx,
+ const struct file_id *id, const char *name,
+ const void *value, size_t size, int flags)
+{
+ NTSTATUS status;
+ struct db_record *rec;
+ struct tdb_xattrs *attribs;
+ uint32_t i;
+
+ DEBUG(10, ("xattr_tdb_setattr called for file %s, name %s\n",
+ file_id_string_tos(id), name));
+
+ rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
+
+ if (rec == NULL) {
+ DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
+ errno = EINVAL;
+ return -1;
+ }
+
+ status = xattr_tdb_pull_attrs(rec, &rec->value, &attribs);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(rec);
+ return -1;
+ }
+
+ for (i=0; i<attribs->num_xattrs; i++) {
+ if (strcmp(attribs->xattrs[i].name, name) == 0) {
+ if (flags & XATTR_CREATE) {
+ TALLOC_FREE(rec);
+ errno = EEXIST;
+ return -1;
+ }
+ break;
+ }
+ }
+
+ if (i == attribs->num_xattrs) {
+ struct tdb_xattr *tmp;
+
+ if (flags & XATTR_REPLACE) {
+ TALLOC_FREE(rec);
+ errno = ENOATTR;
+ return -1;
+ }
+
+ tmp = TALLOC_REALLOC_ARRAY(
+ attribs, attribs->xattrs, struct tdb_xattr,
+ attribs->num_xattrs + 1);
+
+ if (tmp == NULL) {
+ DEBUG(0, ("TALLOC_REALLOC_ARRAY failed\n"));
+ TALLOC_FREE(rec);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ attribs->xattrs = tmp;
+ attribs->num_xattrs += 1;
+ }
+
+ attribs->xattrs[i].name = name;
+ attribs->xattrs[i].value.data = CONST_DISCARD(uint8 *, value);
+ attribs->xattrs[i].value.length = size;
+
+ status = xattr_tdb_save_attrs(rec, attribs);
+
+ TALLOC_FREE(rec);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int xattr_tdb_setxattr(struct vfs_handle_struct *handle,
+ const char *path, const char *name,
+ const void *value, size_t size, int flags)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ return xattr_tdb_setattr(db, &id, name, value, size, flags);
+}
+
+static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *name, const void *value,
+ size_t size, int flags)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ return xattr_tdb_setattr(db, &id, name, value, size, flags);
+}
+
+/*
+ * Worker routine for listxattr and flistxattr
+ */
+
+static ssize_t xattr_tdb_listattr(struct db_context *db_ctx,
+ const struct file_id *id, char *list,
+ size_t size)
+{
+ NTSTATUS status;
+ struct tdb_xattrs *attribs;
+ uint32_t i;
+ size_t len = 0;
+
+ status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
+ nt_errstr(status)));
+ errno = EINVAL;
+ return -1;
+ }
+
+ DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
+ attribs->num_xattrs));
+
+ for (i=0; i<attribs->num_xattrs; i++) {
+ size_t tmp;
+
+ DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
+ attribs->xattrs[i].name));
+
+ tmp = strlen(attribs->xattrs[i].name);
+
+ /*
+ * Try to protect against overflow
+ */
+
+ if (len + (tmp+1) < len) {
+ TALLOC_FREE(attribs);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Take care of the terminating NULL
+ */
+ len += (tmp + 1);
+ }
+
+ if (len > size) {
+ TALLOC_FREE(attribs);
+ errno = ERANGE;
+ return -1;
+ }
+
+ len = 0;
+
+ for (i=0; i<attribs->num_xattrs; i++) {
+ strlcpy(list+len, attribs->xattrs[i].name,
+ size-len);
+ len += (strlen(attribs->xattrs[i].name) + 1);
+ }
+
+ TALLOC_FREE(attribs);
+ return len;
+}
+
+static ssize_t xattr_tdb_listxattr(struct vfs_handle_struct *handle,
+ const char *path, char *list, size_t size)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ return xattr_tdb_listattr(db, &id, list, size);
+}
+
+static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, char *list,
+ size_t size)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ return xattr_tdb_listattr(db, &id, list, size);
+}
+
+/*
+ * Worker routine for removexattr and fremovexattr
+ */
+
+static int xattr_tdb_removeattr(struct db_context *db_ctx,
+ const struct file_id *id, const char *name)
+{
+ NTSTATUS status;
+ struct db_record *rec;
+ struct tdb_xattrs *attribs;
+ uint32_t i;
+
+ rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
+
+ if (rec == NULL) {
+ DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
+ errno = EINVAL;
+ return -1;
+ }
+
+ status = xattr_tdb_pull_attrs(rec, &rec->value, &attribs);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(rec);
+ return -1;
+ }
+
+ for (i=0; i<attribs->num_xattrs; i++) {
+ if (strcmp(attribs->xattrs[i].name, name) == 0) {
+ break;
+ }
+ }
+
+ if (i == attribs->num_xattrs) {
+ TALLOC_FREE(rec);
+ errno = ENOATTR;
+ return -1;
+ }
+
+ attribs->xattrs[i] =
+ attribs->xattrs[attribs->num_xattrs-1];
+ attribs->num_xattrs -= 1;
+
+ if (attribs->num_xattrs == 0) {
+ rec->delete_rec(rec);
+ TALLOC_FREE(rec);
+ return 0;
+ }
+
+ status = xattr_tdb_save_attrs(rec, attribs);
+
+ TALLOC_FREE(rec);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int xattr_tdb_removexattr(struct vfs_handle_struct *handle,
+ const char *path, const char *name)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ return xattr_tdb_removeattr(db, &id, name);
+}
+
+static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, const char *name)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ return xattr_tdb_removeattr(db, &id, name);
+}
+
+/*
+ * Open the tdb file upon VFS_CONNECT
+ */
+
+static bool xattr_tdb_init(int snum, struct db_context **p_db)
+{
+ struct db_context *db;
+ const char *dbname;
+
+ dbname = lp_parm_const_string(snum, "xattr_tdb", "file",
+ lock_path("xattr.tdb"));
+
+ if (dbname == NULL) {
+ errno = ENOSYS;
+ return false;
+ }
+
+ become_root();
+ db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ unbecome_root();
+
+ if (db == NULL) {
+#if defined(ENOTSUP)
+ errno = ENOTSUP;
+#else
+ errno = ENOSYS;
+#endif
+ return false;
+ }
+
+ *p_db = db;
+ return true;
+}
+
+/*
+ * On unlink we need to delete the tdb record
+ */
+static int xattr_tdb_unlink(vfs_handle_struct *handle, const char *path)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+ struct db_record *rec;
+ int ret;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+ return -1;
+ }
+
+ ret = SMB_VFS_NEXT_UNLINK(handle, path);
+
+ if (ret == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id);
+
+ /*
+ * If rec == NULL there's not much we can do about it
+ */
+
+ if (rec != NULL) {
+ rec->delete_rec(rec);
+ TALLOC_FREE(rec);
+ }
+
+ return 0;
+}
+
+/*
+ * On rmdir we need to delete the tdb record
+ */
+static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+ struct db_record *rec;
+ int ret;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+ return -1;
+ }
+
+ ret = SMB_VFS_NEXT_RMDIR(handle, path);
+
+ if (ret == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id);
+
+ /*
+ * If rec == NULL there's not much we can do about it
+ */
+
+ if (rec != NULL) {
+ rec->delete_rec(rec);
+ TALLOC_FREE(rec);
+ }
+
+ return 0;
+}
+
+/*
+ * Destructor for the VFS private data
+ */
+
+static void close_xattr_db(void **data)
+{
+ struct db_context **p_db = (struct db_context **)data;
+ TALLOC_FREE(*p_db);
+}
+
+static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
+ const char *user)
+{
+ fstring sname;
+ int res, snum;
+ struct db_context *db;
+
+ res = SMB_VFS_NEXT_CONNECT(handle, service, user);
+ if (res < 0) {
+ return res;
+ }
+
+ fstrcpy(sname, service);
+ snum = find_service(sname);
+ if (snum == -1) {
+ /*
+ * Should not happen, but we should not fail just *here*.
+ */
+ return 0;
+ }
+
+ if (!xattr_tdb_init(snum, &db)) {
+ DEBUG(5, ("Could not init xattr tdb\n"));
+ lp_do_parameter(snum, "ea support", "False");
+ return 0;
+ }
+
+ lp_do_parameter(snum, "ea support", "True");
+
+ SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
+ struct db_context, return -1);
+
+ return 0;
+}
+
+/* VFS operations structure */
+
+static const vfs_op_tuple xattr_tdb_ops[] = {
+ {SMB_VFS_OP(xattr_tdb_getxattr), SMB_VFS_OP_GETXATTR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_fgetxattr), SMB_VFS_OP_FGETXATTR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_setxattr), SMB_VFS_OP_SETXATTR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_fsetxattr), SMB_VFS_OP_FSETXATTR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_listxattr), SMB_VFS_OP_LISTXATTR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_flistxattr), SMB_VFS_OP_FLISTXATTR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_removexattr), SMB_VFS_OP_REMOVEXATTR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_fremovexattr), SMB_VFS_OP_FREMOVEXATTR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_unlink), SMB_VFS_OP_UNLINK,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_rmdir), SMB_VFS_OP_RMDIR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_connect), SMB_VFS_OP_CONNECT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_xattr_tdb_init(void);
+NTSTATUS vfs_xattr_tdb_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "xattr_tdb",
+ xattr_tdb_ops);
+}
diff --git a/source3/modules/vfs_zfsacl.c b/source3/modules/vfs_zfsacl.c
new file mode 100644
index 0000000000..e933e47317
--- /dev/null
+++ b/source3/modules/vfs_zfsacl.c
@@ -0,0 +1,232 @@
+/*
+ * Convert ZFS/NFSv4 acls to NT acls and vice versa.
+ *
+ * Copyright (C) Jiri Sasek, 2007
+ * based on the foobar.c module which is copyrighted by Volker Lendecke
+ *
+ * Many thanks to Axel Apitz for help to fix the special ace's handling
+ * issues.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "includes.h"
+#include "nfs4_acls.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+#define ZFSACL_MODULE_NAME "zfsacl"
+
+/* zfs_get_nt_acl()
+ * read the local file's acls and return it in NT form
+ * using the NFSv4 format conversion
+ */
+static NTSTATUS zfs_get_nt_acl_common(const char *name,
+ uint32 security_info,
+ SMB4ACL_T **ppacl)
+{
+ int naces, i;
+ ace_t *acebuf;
+ SMB4ACL_T *pacl;
+ TALLOC_CTX *mem_ctx;
+
+ /* read the number of file aces */
+ if((naces = acl(name, ACE_GETACLCNT, 0, NULL)) == -1) {
+ if(errno == ENOSYS) {
+ DEBUG(9, ("acl(ACE_GETACLCNT, %s): Operation is not "
+ "supported on the filesystem where the file "
+ "reside", name));
+ } else {
+ DEBUG(9, ("acl(ACE_GETACLCNT, %s): %s ", name,
+ strerror(errno)));
+ }
+ return map_nt_error_from_unix(errno);
+ }
+ /* allocate the field of ZFS aces */
+ mem_ctx = talloc_tos();
+ acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces);
+ if(acebuf == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ /* read the aces into the field */
+ if(acl(name, ACE_GETACL, naces, acebuf) < 0) {
+ DEBUG(9, ("acl(ACE_GETACL, %s): %s ", name,
+ strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+ /* create SMB4ACL data */
+ if((pacl = smb_create_smb4acl()) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ for(i=0; i<naces; i++) {
+ SMB_ACE4PROP_T aceprop;
+
+ aceprop.aceType = (uint32) acebuf[i].a_type;
+ aceprop.aceFlags = (uint32) acebuf[i].a_flags;
+ aceprop.aceMask = (uint32) acebuf[i].a_access_mask;
+ aceprop.who.id = (uint32) acebuf[i].a_who;
+
+ if(aceprop.aceFlags & ACE_OWNER) {
+ aceprop.flags = SMB_ACE4_ID_SPECIAL;
+ aceprop.who.special_id = SMB_ACE4_WHO_OWNER;
+ } else if(aceprop.aceFlags & ACE_GROUP) {
+ aceprop.flags = SMB_ACE4_ID_SPECIAL;
+ aceprop.who.special_id = SMB_ACE4_WHO_GROUP;
+ } else if(aceprop.aceFlags & ACE_EVERYONE) {
+ aceprop.flags = SMB_ACE4_ID_SPECIAL;
+ aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE;
+ } else {
+ aceprop.flags = 0;
+ }
+ if(smb_add_ace4(pacl, &aceprop) == NULL)
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *ppacl = pacl;
+ return NT_STATUS_OK;
+}
+
+/* call-back function processing the NT acl -> ZFS acl using NFSv4 conv. */
+static bool zfs_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
+{
+ int naces = smb_get_naces(smbacl), i;
+ ace_t *acebuf;
+ SMB4ACE_T *smbace;
+ TALLOC_CTX *mem_ctx;
+
+ /* allocate the field of ZFS aces */
+ mem_ctx = talloc_tos();
+ acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces);
+ if(acebuf == NULL) {
+ errno = ENOMEM;
+ return False;
+ }
+ /* handle all aces */
+ for(smbace = smb_first_ace4(smbacl), i = 0;
+ smbace!=NULL;
+ smbace = smb_next_ace4(smbace), i++) {
+ SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
+
+ acebuf[i].a_type = aceprop->aceType;
+ acebuf[i].a_flags = aceprop->aceFlags;
+ acebuf[i].a_access_mask = aceprop->aceMask;
+ acebuf[i].a_who = aceprop->who.id;
+ if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
+ switch(aceprop->who.special_id) {
+ case SMB_ACE4_WHO_EVERYONE:
+ acebuf[i].a_flags |= ACE_EVERYONE;
+ break;
+ case SMB_ACE4_WHO_OWNER:
+ acebuf[i].a_flags |= ACE_OWNER;
+ break;
+ case SMB_ACE4_WHO_GROUP:
+ acebuf[i].a_flags |= ACE_GROUP;
+ break;
+ default:
+ DEBUG(8, ("unsupported special_id %d\n", \
+ aceprop->who.special_id));
+ continue; /* don't add it !!! */
+ }
+ }
+ }
+ SMB_ASSERT(i == naces);
+
+ /* store acl */
+ if(acl(fsp->fsp_name, ACE_SETACL, naces, acebuf)) {
+ if(errno == ENOSYS) {
+ DEBUG(9, ("acl(ACE_SETACL, %s): Operation is not "
+ "supported on the filesystem where the file "
+ "reside", fsp->fsp_name));
+ } else {
+ DEBUG(9, ("acl(ACE_SETACL, %s): %s ", fsp->fsp_name,
+ strerror(errno)));
+ }
+ return 0;
+ }
+
+ return True;
+}
+
+/* zfs_set_nt_acl()
+ * set the local file's acls obtaining it in NT form
+ * using the NFSv4 format conversion
+ */
+static NTSTATUS zfs_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
+ uint32 security_info_sent,
+ struct security_descriptor *psd)
+{
+ return smb_set_nt_acl_nfs4(fsp, security_info_sent, psd,
+ zfs_process_smbacl);
+}
+
+static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32 security_info,
+ struct security_descriptor **ppdesc)
+{
+ SMB4ACL_T *pacl;
+ NTSTATUS status;
+
+ status = zfs_get_nt_acl_common(fsp->fsp_name, security_info, &pacl);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
+}
+
+static NTSTATUS zfsacl_get_nt_acl(struct vfs_handle_struct *handle,
+ const char *name, uint32 security_info,
+ struct security_descriptor **ppdesc)
+{
+ SMB4ACL_T *pacl;
+ NTSTATUS status;
+
+ status = zfs_get_nt_acl_common(name, security_info, &pacl);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc,
+ pacl);
+}
+
+static NTSTATUS zfsacl_fset_nt_acl(vfs_handle_struct *handle,
+ files_struct *fsp,
+ uint32 security_info_sent,
+ SEC_DESC *psd)
+{
+ return zfs_set_nt_acl(handle, fsp, security_info_sent, psd);
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple zfsacl_ops[] = {
+ {SMB_VFS_OP(zfsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(zfsacl_get_nt_acl), SMB_VFS_OP_GET_NT_ACL,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(zfsacl_fset_nt_acl), SMB_VFS_OP_FSET_NT_ACL,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_zfsacl_init(void);
+NTSTATUS vfs_zfsacl_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "zfsacl",
+ zfsacl_ops);
+}
diff --git a/source3/modules/weird.c b/source3/modules/weird.c
new file mode 100644
index 0000000000..eab17ce50e
--- /dev/null
+++ b/source3/modules/weird.c
@@ -0,0 +1,131 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba module with developer tools
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jelmer Vernooij 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static struct {
+ char from;
+ const char *to;
+ int len;
+} weird_table[] = {
+ {'q', "^q^", 3},
+ {'Q', "^Q^", 3},
+ {0, NULL}
+};
+
+static size_t weird_pull(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+ int i;
+ int done = 0;
+ for (i=0;weird_table[i].from;i++) {
+ if (strncmp((*inbuf),
+ weird_table[i].to,
+ weird_table[i].len) == 0) {
+ if (*inbytesleft < weird_table[i].len) {
+ DEBUG(0,("ERROR: truncated weird string\n"));
+ /* smb_panic("weird_pull"); */
+
+ } else {
+ (*outbuf)[0] = weird_table[i].from;
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= weird_table[i].len;
+ (*outbytesleft) -= 2;
+ (*inbuf) += weird_table[i].len;
+ (*outbuf) += 2;
+ done = 1;
+ break;
+ }
+ }
+ }
+ if (done) continue;
+ (*outbuf)[0] = (*inbuf)[0];
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= 1;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 1;
+ (*outbuf) += 2;
+ }
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t weird_push(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int ir_count=0;
+
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ int i;
+ int done=0;
+ for (i=0;weird_table[i].from;i++) {
+ if ((*inbuf)[0] == weird_table[i].from &&
+ (*inbuf)[1] == 0) {
+ if (*outbytesleft < weird_table[i].len) {
+ DEBUG(0,("No room for weird character\n"));
+ /* smb_panic("weird_push"); */
+ } else {
+ memcpy(*outbuf, weird_table[i].to,
+ weird_table[i].len);
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= weird_table[i].len;
+ (*inbuf) += 2;
+ (*outbuf) += weird_table[i].len;
+ done = 1;
+ break;
+ }
+ }
+ }
+ if (done) continue;
+
+ (*outbuf)[0] = (*inbuf)[0];
+ if ((*inbuf)[1]) ir_count++;
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 1;
+ (*inbuf) += 2;
+ (*outbuf) += 1;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return ir_count;
+}
+
+struct charset_functions weird_functions = {"WEIRD", weird_pull, weird_push};
+
+NTSTATUS charset_weird_init(void);
+NTSTATUS charset_weird_init(void)
+{
+ return smb_register_charset(&weird_functions);
+}
diff --git a/source3/nmbd/asyncdns.c b/source3/nmbd/asyncdns.c
new file mode 100644
index 0000000000..ab9b1ed740
--- /dev/null
+++ b/source3/nmbd/asyncdns.c
@@ -0,0 +1,365 @@
+/*
+ Unix SMB/CIFS 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/***************************************************************************
+ Add a DNS result to the name cache.
+****************************************************************************/
+
+static struct name_record *add_dns_result(struct nmb_name *question, struct in_addr addr)
+{
+ int name_type = question->name_type;
+ unstring qname;
+
+ pull_ascii_nstring(qname, sizeof(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));
+ 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)));
+
+ add_name_to_subnet( wins_server_subnet, qname, name_type,
+ NB_ACTIVE, 2*60*60, DNS_NAME, 1, &addr);
+
+ return find_name_on_subnet(wins_server_subnet, question, FIND_ANY_NAME);
+}
+
+#ifndef SYNC_DNS
+
+static int fd_in = -1, fd_out = -1;
+static pid_t child_pid = -1;
+static int in_dns;
+
+/* this is the structure that is passed between the parent and child */
+struct query_record {
+ struct nmb_name name;
+ struct in_addr result;
+};
+
+/* a queue of pending requests waiting to be sent to the DNS child */
+static struct packet_struct *dns_queue;
+
+/* the packet currently being processed by the dns child */
+static struct packet_struct *dns_current;
+
+
+/***************************************************************************
+ return the fd used to gather async dns replies. This is added to the select
+ loop
+ ****************************************************************************/
+
+int asyncdns_fd(void)
+{
+ return fd_in;
+}
+
+/***************************************************************************
+ handle DNS queries arriving from the parent
+ ****************************************************************************/
+static void asyncdns_process(void)
+{
+ struct query_record r;
+ unstring qname;
+
+ DEBUGLEVEL = -1;
+
+ while (1) {
+ NTSTATUS status;
+
+ status = read_data(fd_in, (char *)&r, sizeof(r));
+
+ if (!NT_STATUS_IS_OK(status)) {
+ break;
+ }
+
+ pull_ascii_nstring( qname, sizeof(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) {
+ kill(child_pid, SIGTERM);
+ child_pid = -1;
+ }
+}
+
+/***************************************************************************
+ create a child process to handle DNS lookups
+ ****************************************************************************/
+void start_async_dns(void)
+{
+ int fd1[2], fd2[2];
+
+ CatchChild();
+
+ if (pipe(fd1) || pipe(fd2)) {
+ DEBUG(0,("can't create asyncdns pipes\n"));
+ return;
+ }
+
+ child_pid = sys_fork();
+
+ if (child_pid) {
+ fd_in = fd1[0];
+ fd_out = fd2[1];
+ close(fd1[1]);
+ close(fd2[0]);
+ DEBUG(0,("started asyncdns process %d\n", (int)child_pid));
+ return;
+ }
+
+ fd_in = fd2[0];
+ fd_out = fd1[1];
+
+ CatchSignal(SIGUSR2, SIG_IGN);
+ CatchSignal(SIGUSR1, SIG_IGN);
+ CatchSignal(SIGHUP, SIG_IGN);
+ CatchSignal(SIGTERM, SIGNAL_CAST sig_term );
+
+ if (!reinit_after_fork(nmbd_messaging_context(), true)) {
+ DEBUG(0,("reinit_after_fork() failed\n"));
+ smb_panic("reinit_after_fork() failed");
+ }
+
+ 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;
+ NTSTATUS status;
+
+ if (fd_in == -1)
+ return;
+
+ /* Allow SIGTERM to kill us. */
+ BlockSignals(False, SIGTERM);
+
+ if (!process_exists_by_pid(child_pid)) {
+ close(fd_in);
+ close(fd_out);
+ start_async_dns();
+ }
+
+ status = read_data(fd_in, (char *)&r, sizeof(r));
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("read from child failed: %s\n", nt_errstr(status)));
+ 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)
+{
+ if (in_dns || fd_in == -1)
+ return False;
+
+ if (!dns_current) {
+ if (!write_child(p)) {
+ DEBUG(3,("failed to send DNS query to child!\n"));
+ return False;
+ }
+ dns_current = p;
+ p->locked = True;
+ } else {
+ p->locked = True;
+ p->next = dns_queue;
+ p->prev = NULL;
+ if (p->next)
+ p->next->prev = p;
+ dns_queue = p;
+ }
+
+ DEBUG(3,("added DNS query for %s\n", nmb_namestr(question)));
+ return True;
+}
+
+#else
+
+
+/***************************************************************************
+ we use this when we can't do async DNS lookups
+ ****************************************************************************/
+
+bool queue_dns_query(struct packet_struct *p,struct nmb_name *question)
+{
+ struct name_record *namerec = NULL;
+ struct in_addr dns_ip;
+ unstring qname;
+
+ pull_ascii_nstring(qname, sizeof(qname), question->name);
+
+ DEBUG(3,("DNS search for %s - ", nmb_namestr(question)));
+
+ /* Unblock TERM signal so we can be killed in DNS lookup. */
+ BlockSignals(False, SIGTERM);
+
+ dns_ip.s_addr = interpret_addr(qname);
+
+ /* Re-block TERM signal. */
+ BlockSignals(True, SIGTERM);
+
+ namerec = add_dns_result(question, dns_ip);
+ if(namerec == NULL) {
+ send_wins_name_query_response(NAM_ERR, p, NULL);
+ } else {
+ send_wins_name_query_response(0, p, namerec);
+ }
+ return False;
+}
+
+/***************************************************************************
+ With sync dns there is no child to kill on SIGTERM.
+ ****************************************************************************/
+
+void kill_async_dns_child(void)
+{
+ return;
+}
+#endif
diff --git a/source3/nmbd/nmbd.c b/source3/nmbd/nmbd.c
new file mode 100644
index 0000000000..d9f2af4c10
--- /dev/null
+++ b/source3/nmbd/nmbd.c
@@ -0,0 +1,993 @@
+/*
+ Unix SMB/CIFS implementation.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Jeremy Allison 1997-2002
+ Copyright (C) Jelmer Vernooij 2002,2003 (Conversion to popt)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+int ClientNMB = -1;
+int ClientDGRAM = -1;
+int global_nmb_port = -1;
+
+extern bool rescan_listen_set;
+extern bool global_in_nmbd;
+
+extern bool override_logfile;
+
+/* have we found LanMan clients yet? */
+bool found_lm_clients = False;
+
+/* what server type are we currently */
+
+time_t StartupTime = 0;
+
+struct event_context *nmbd_event_context(void)
+{
+ static struct event_context *ctx;
+
+ if (!ctx && !(ctx = event_context_init(NULL))) {
+ smb_panic("Could not init nmbd event context");
+ }
+ return ctx;
+}
+
+struct messaging_context *nmbd_messaging_context(void)
+{
+ static struct messaging_context *ctx;
+
+ if (ctx == NULL) {
+ ctx = messaging_init(NULL, server_id_self(),
+ nmbd_event_context());
+ }
+ if (ctx == NULL) {
+ DEBUG(0, ("Could not init nmbd messaging context.\n"));
+ }
+ return ctx;
+}
+
+/**************************************************************************** **
+ Handle a SIGTERM in band.
+ **************************************************************************** */
+
+static void terminate(void)
+{
+ DEBUG(0,("Got SIGTERM: going down...\n"));
+
+ /* Write out wins.dat file if samba is a WINS server */
+ wins_write_database(0,False);
+
+ /* Remove all SELF registered names from WINS */
+ release_wins_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);
+}
+
+/**************************************************************************** **
+ Handle a SHUTDOWN message from smbcontrol.
+ **************************************************************************** */
+
+static void nmbd_terminate(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ terminate();
+}
+
+/**************************************************************************** **
+ Catch a SIGTERM signal.
+ **************************************************************************** */
+
+static SIG_ATOMIC_T got_sig_term;
+
+static void sig_term(int sig)
+{
+ got_sig_term = 1;
+ sys_select_signal(SIGTERM);
+}
+
+/**************************************************************************** **
+ Catch a SIGHUP signal.
+ **************************************************************************** */
+
+static SIG_ATOMIC_T reload_after_sighup;
+
+static void sig_hup(int sig)
+{
+ reload_after_sighup = 1;
+ sys_select_signal(SIGHUP);
+}
+
+/**************************************************************************** **
+ Possibly continue after a fault.
+ **************************************************************************** */
+
+static void fault_continue(void)
+{
+ dump_core();
+}
+
+/**************************************************************************** **
+ 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);
+}
+
+/************************************************************************** **
+ Reload the list of network interfaces.
+ Doesn't return until a network interface is up.
+ ************************************************************************** */
+
+static void reload_interfaces(time_t t)
+{
+ static time_t lastt;
+ int n;
+ bool print_waiting_msg = true;
+ struct subnet_record *subrec;
+
+ if (t && ((t - lastt) < NMBD_INTERFACES_RELOAD)) {
+ return;
+ }
+
+ lastt = t;
+
+ if (!interfaces_changed()) {
+ return;
+ }
+
+ try_again:
+
+ /* the list of probed interfaces has changed, we may need to add/remove
+ some subnets */
+ load_interfaces();
+
+ /* find any interfaces that need adding */
+ for (n=iface_count() - 1; n >= 0; n--) {
+ char str[INET6_ADDRSTRLEN];
+ const struct interface *iface = get_interface(n);
+ struct in_addr ip, nmask;
+
+ if (!iface) {
+ DEBUG(2,("reload_interfaces: failed to get interface %d\n", n));
+ continue;
+ }
+
+ /* Ensure we're only dealing with IPv4 here. */
+ if (iface->ip.ss_family != AF_INET) {
+ DEBUG(2,("reload_interfaces: "
+ "ignoring non IPv4 interface.\n"));
+ continue;
+ }
+
+ ip = ((struct sockaddr_in *)&iface->ip)->sin_addr;
+ nmask = ((struct sockaddr_in *)&iface->netmask)->sin_addr;
+
+ /*
+ * We don't want to add a loopback interface, in case
+ * someone has added 127.0.0.1 for smbd, nmbd needs to
+ * ignore it here. JRA.
+ */
+
+ if (is_loopback_addr(&iface->ip)) {
+ DEBUG(2,("reload_interfaces: Ignoring loopback "
+ "interface %s\n",
+ print_sockaddr(str, sizeof(str), &iface->ip) ));
+ continue;
+ }
+
+ for (subrec=subnetlist; subrec; subrec=subrec->next) {
+ if (ip_equal_v4(ip, subrec->myip) &&
+ ip_equal_v4(nmask, subrec->mask_ip)) {
+ break;
+ }
+ }
+
+ if (!subrec) {
+ /* it wasn't found! add it */
+ DEBUG(2,("Found new interface %s\n",
+ print_sockaddr(str,
+ sizeof(str), &iface->ip) ));
+ subrec = make_normal_subnet(iface);
+ if (subrec)
+ register_my_workgroup_one_subnet(subrec);
+ }
+ }
+
+ /* find any interfaces that need deleting */
+ for (subrec=subnetlist; subrec; subrec=subrec->next) {
+ for (n=iface_count() - 1; n >= 0; n--) {
+ struct interface *iface = get_interface(n);
+ struct in_addr ip, nmask;
+ if (!iface) {
+ continue;
+ }
+ /* Ensure we're only dealing with IPv4 here. */
+ if (iface->ip.ss_family != AF_INET) {
+ DEBUG(2,("reload_interfaces: "
+ "ignoring non IPv4 interface.\n"));
+ continue;
+ }
+ ip = ((struct sockaddr_in *)&iface->ip)->sin_addr;
+ nmask = ((struct sockaddr_in *)&iface->netmask)->sin_addr;
+ if (ip_equal_v4(ip, subrec->myip) &&
+ ip_equal_v4(nmask, subrec->mask_ip)) {
+ break;
+ }
+ }
+ if (n == -1) {
+ /* oops, an interface has disapeared. This is
+ tricky, we don't dare actually free the
+ interface as it could be being used, so
+ instead we just wear the memory leak and
+ remove it from the list of interfaces without
+ freeing it */
+ DEBUG(2,("Deleting dead interface %s\n",
+ inet_ntoa(subrec->myip)));
+ close_subnet(subrec);
+ }
+ }
+
+ rescan_listen_set = True;
+
+ /* We need to wait if there are no subnets... */
+ if (FIRST_SUBNET == NULL) {
+
+ if (print_waiting_msg) {
+ DEBUG(0,("reload_interfaces: "
+ "No subnets to listen to. Waiting..\n"));
+ print_waiting_msg = false;
+ }
+
+ /*
+ * Whilst we're waiting for an interface, allow SIGTERM to
+ * cause us to exit.
+ */
+
+ BlockSignals(false, SIGTERM);
+
+ /* We only count IPv4, non-loopback interfaces here. */
+ while (iface_count_v4_nl() == 0 && !got_sig_term) {
+ sleep(5);
+ load_interfaces();
+ }
+
+ /*
+ * Handle termination inband.
+ */
+
+ if (got_sig_term) {
+ got_sig_term = 0;
+ terminate();
+ }
+
+ /*
+ * We got an interface, go back to blocking term.
+ */
+
+ BlockSignals(true, SIGTERM);
+ goto try_again;
+ }
+}
+
+/**************************************************************************** **
+ Reload the services file.
+ **************************************************************************** */
+
+static bool reload_nmbd_services(bool test)
+{
+ bool ret;
+
+ set_remote_machine_name("nmbd", False);
+
+ if ( lp_loaded() ) {
+ const char *fname = lp_configfile();
+ if (file_exist(fname,NULL) && !strcsequal(fname,get_dyn_CONFIGFILE())) {
+ set_dyn_CONFIGFILE(fname);
+ test = False;
+ }
+ }
+
+ if ( test && !lp_file_list_changed() )
+ return(True);
+
+ ret = lp_load(get_dyn_CONFIGFILE(), True , False, False, True);
+
+ /* perhaps the config filename is now set */
+ if ( !test ) {
+ DEBUG( 3, ( "services not loaded\n" ) );
+ reload_nmbd_services( True );
+ }
+
+ return(ret);
+}
+
+/**************************************************************************** **
+ * React on 'smbcontrol nmbd reload-config' in the same way as to SIGHUP
+ **************************************************************************** */
+
+static void msg_reload_nmbd_services(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ write_browse_list( 0, True );
+ dump_all_namelists();
+ reload_nmbd_services( True );
+ reopen_logs();
+ reload_interfaces(0);
+}
+
+static void msg_nmbd_send_packet(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ DATA_BLOB *data)
+{
+ struct packet_struct *p = (struct packet_struct *)data->data;
+ struct subnet_record *subrec;
+ struct sockaddr_storage ss;
+ const struct sockaddr_storage *pss;
+ const struct in_addr *local_ip;
+
+ DEBUG(10, ("Received send_packet from %d\n", procid_to_pid(&src)));
+
+ if (data->length != sizeof(struct packet_struct)) {
+ DEBUG(2, ("Discarding invalid packet length from %d\n",
+ procid_to_pid(&src)));
+ return;
+ }
+
+ if ((p->packet_type != NMB_PACKET) &&
+ (p->packet_type != DGRAM_PACKET)) {
+ DEBUG(2, ("Discarding invalid packet type from %d: %d\n",
+ procid_to_pid(&src), p->packet_type));
+ return;
+ }
+
+ in_addr_to_sockaddr_storage(&ss, p->ip);
+ pss = iface_ip(&ss);
+
+ if (pss == NULL) {
+ DEBUG(2, ("Could not find ip for packet from %d\n",
+ procid_to_pid(&src)));
+ return;
+ }
+
+ local_ip = &((const struct sockaddr_in *)pss)->sin_addr;
+ subrec = FIRST_SUBNET;
+
+ p->fd = (p->packet_type == NMB_PACKET) ?
+ subrec->nmb_sock : subrec->dgram_sock;
+
+ for (subrec = FIRST_SUBNET; subrec != NULL;
+ subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+ if (ip_equal_v4(*local_ip, subrec->myip)) {
+ p->fd = (p->packet_type == NMB_PACKET) ?
+ subrec->nmb_sock : subrec->dgram_sock;
+ break;
+ }
+ }
+
+ if (p->packet_type == DGRAM_PACKET) {
+ p->port = 138;
+ p->packet.dgram.header.source_ip.s_addr = local_ip->s_addr;
+ p->packet.dgram.header.source_port = 138;
+ }
+
+ send_packet(p);
+}
+
+/**************************************************************************** **
+ The main select loop.
+ **************************************************************************** */
+
+static void process(void)
+{
+ bool run_election;
+
+ while( True ) {
+ time_t t = time(NULL);
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ /* Check for internal messages */
+
+ message_dispatch(nmbd_messaging_context());
+
+ /*
+ * 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)) {
+ TALLOC_FREE(frame);
+ return;
+ }
+
+ /*
+ * Handle termination inband.
+ */
+
+ if (got_sig_term) {
+ got_sig_term = 0;
+ terminate();
+ }
+
+ /*
+ * Process all incoming packets
+ * read above. This calls the success and
+ * failure functions registered when response
+ * packets arrrive, and also deals with request
+ * packets from other sources.
+ * (nmbd_packets.c)
+ */
+
+ run_packet_queue();
+
+ /*
+ * Run any elections - initiate becoming
+ * a local master browser if we have won.
+ * (nmbd_elections.c)
+ */
+
+ run_elections(t);
+
+ /*
+ * Send out any broadcast announcements
+ * of our server names. This also announces
+ * the workgroup name if we are a local
+ * master browser.
+ * (nmbd_sendannounce.c)
+ */
+
+ announce_my_server_names(t);
+
+ /*
+ * Send out any LanMan broadcast announcements
+ * of our server names.
+ * (nmbd_sendannounce.c)
+ */
+
+ announce_my_lm_server_names(t);
+
+ /*
+ * If we are a local master browser, periodically
+ * announce ourselves to the domain master browser.
+ * This also deals with syncronising the domain master
+ * browser server lists with ourselves as a local
+ * master browser.
+ * (nmbd_sendannounce.c)
+ */
+
+ announce_myself_to_domain_master_browser(t);
+
+ /*
+ * Fullfill any remote announce requests.
+ * (nmbd_sendannounce.c)
+ */
+
+ announce_remote(t);
+
+ /*
+ * Fullfill any remote browse sync announce requests.
+ * (nmbd_sendannounce.c)
+ */
+
+ browse_sync_remote(t);
+
+ /*
+ * Scan the broadcast subnets, and WINS client
+ * namelists and refresh any that need refreshing.
+ * (nmbd_mynames.c)
+ */
+
+ refresh_my_names(t);
+
+ /*
+ * Scan the subnet namelists and server lists and
+ * expire thos that have timed out.
+ * (nmbd.c)
+ */
+
+ expire_names_and_servers(t);
+
+ /*
+ * Write out a snapshot of our current browse list into
+ * the browse.dat file. This is used by smbd to service
+ * incoming NetServerEnum calls - used to synchronise
+ * browse lists over subnets.
+ * (nmbd_serverlistdb.c)
+ */
+
+ write_browse_list(t, False);
+
+ /*
+ * If we are a domain master browser, we have a list of
+ * local master browsers we should synchronise browse
+ * lists with (these are added by an incoming local
+ * master browser announcement packet). Expire any of
+ * these that are no longer current, and pull the server
+ * lists from each of these known local master browsers.
+ * (nmbd_browsesync.c)
+ */
+
+ dmb_expire_and_sync_browser_lists(t);
+
+ /*
+ * Check that there is a local master browser for our
+ * workgroup for all our broadcast subnets. If one
+ * is not found, start an election (which we ourselves
+ * may or may not participate in, depending on the
+ * setting of the 'local master' parameter.
+ * (nmbd_elections.c)
+ */
+
+ check_master_browser_exists(t);
+
+ /*
+ * If we are configured as a logon server, attempt to
+ * register the special NetBIOS names to become such
+ * (WORKGROUP<1c> name) on all broadcast subnets and
+ * with the WINS server (if used). If we are configured
+ * to become a domain master browser, attempt to register
+ * the special NetBIOS name (WORKGROUP<1b> name) to
+ * become such.
+ * (nmbd_become_dmb.c)
+ */
+
+ add_domain_names(t);
+
+ /*
+ * If we are a WINS server, do any timer dependent
+ * processing required.
+ * (nmbd_winsserver.c)
+ */
+
+ initiate_wins_processing(t);
+
+ /*
+ * If we are a domain master browser, attempt to contact the
+ * WINS server to get a list of all known WORKGROUPS/DOMAINS.
+ * This will only work to a Samba WINS server.
+ * (nmbd_browsesync.c)
+ */
+
+ if (lp_enhanced_browsing())
+ collect_all_workgroup_names_from_wins_server(t);
+
+ /*
+ * Go through the response record queue and time out or re-transmit
+ * and expired entries.
+ * (nmbd_packets.c)
+ */
+
+ retransmit_or_expire_response_records(t);
+
+ /*
+ * check to see if any remote browse sync child processes have completed
+ */
+
+ sync_check_completion();
+
+ /*
+ * regularly sync with any other DMBs we know about
+ */
+
+ if (lp_enhanced_browsing())
+ sync_all_dmbs(t);
+
+ /*
+ * clear the unexpected packet queue
+ */
+
+ clear_unexpected(t);
+
+ /*
+ * Reload the services file if we got a sighup.
+ */
+
+ if(reload_after_sighup) {
+ DEBUG( 0, ( "Got SIGHUP dumping debug info.\n" ) );
+ msg_reload_nmbd_services(nmbd_messaging_context(),
+ NULL, MSG_SMB_CONF_UPDATED,
+ procid_self(), NULL);
+
+ reload_after_sighup = 0;
+ }
+
+ /* check for new network interfaces */
+
+ reload_interfaces(t);
+
+ /* free up temp memory */
+ TALLOC_FREE(frame);
+ }
+}
+
+/**************************************************************************** **
+ Open the socket communication.
+ **************************************************************************** */
+
+static bool open_sockets(bool isdaemon, int port)
+{
+ struct sockaddr_storage ss;
+ const char *sock_addr = lp_socket_address();
+
+ /*
+ * 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 (!interpret_string_addr(&ss, sock_addr,
+ AI_NUMERICHOST|AI_PASSIVE)) {
+ DEBUG(0,("open_sockets: unable to get socket address "
+ "from string %s", sock_addr));
+ return false;
+ }
+ if (ss.ss_family != AF_INET) {
+ DEBUG(0,("open_sockets: unable to use IPv6 socket"
+ "%s in nmbd\n",
+ sock_addr));
+ return false;
+ }
+
+ if (isdaemon) {
+ ClientNMB = open_socket_in(SOCK_DGRAM, port,
+ 0, &ss,
+ true);
+ } else {
+ ClientNMB = 0;
+ }
+
+ if (ClientNMB == -1) {
+ return false;
+ }
+
+ ClientDGRAM = open_socket_in(SOCK_DGRAM, DGRAM_PORT,
+ 3, &ss,
+ true);
+
+ if (ClientDGRAM == -1) {
+ if (ClientNMB != 0) {
+ close(ClientNMB);
+ }
+ return false;
+ }
+
+ /* we are never interested in SIGPIPE */
+ BlockSignals(True,SIGPIPE);
+
+ set_socket_options( ClientNMB, "SO_BROADCAST" );
+ set_socket_options( ClientDGRAM, "SO_BROADCAST" );
+
+ /* Ensure we're non-blocking. */
+ set_blocking( ClientNMB, False);
+ set_blocking( ClientDGRAM, False);
+
+ DEBUG( 3, ( "open_sockets: Broadcast sockets opened.\n" ) );
+ return( True );
+}
+
+/**************************************************************************** **
+ main program
+ **************************************************************************** */
+
+ int main(int argc, const char *argv[])
+{
+ static bool is_daemon;
+ static bool opt_interactive;
+ static bool Fork = true;
+ static bool no_process_group;
+ static bool log_stdout;
+ poptContext pc;
+ char *p_lmhosts = NULL;
+ int opt;
+ enum {
+ OPT_DAEMON = 1000,
+ OPT_INTERACTIVE,
+ OPT_FORK,
+ OPT_NO_PROCESS_GROUP,
+ OPT_LOG_STDOUT
+ };
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"daemon", 'D', POPT_ARG_NONE, NULL, OPT_DAEMON, "Become a daemon(default)" },
+ {"interactive", 'i', POPT_ARG_NONE, NULL, OPT_INTERACTIVE, "Run interactive (not a daemon)" },
+ {"foreground", 'F', POPT_ARG_NONE, NULL, OPT_FORK, "Run daemon in foreground (for daemontools & etc)" },
+ {"no-process-group", 0, POPT_ARG_NONE, NULL, OPT_NO_PROCESS_GROUP, "Don't create a new process group" },
+ {"log-stdout", 'S', POPT_ARG_NONE, NULL, OPT_LOG_STDOUT, "Log to stdout" },
+ {"hosts", 'H', POPT_ARG_STRING, &p_lmhosts, 'H', "Load a netbios hosts file"},
+ {"port", 'p', POPT_ARG_INT, &global_nmb_port, NMB_PORT, "Listen on the specified port" },
+ POPT_COMMON_SAMBA
+ { NULL }
+ };
+ TALLOC_CTX *frame = talloc_stackframe(); /* Setup tos. */
+
+ load_case_tables();
+
+ global_nmb_port = NMB_PORT;
+
+ pc = poptGetContext("nmbd", argc, argv, long_options, 0);
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case OPT_DAEMON:
+ is_daemon = true;
+ break;
+ case OPT_INTERACTIVE:
+ opt_interactive = true;
+ break;
+ case OPT_FORK:
+ Fork = false;
+ break;
+ case OPT_NO_PROCESS_GROUP:
+ no_process_group = true;
+ break;
+ case OPT_LOG_STDOUT:
+ log_stdout = true;
+ break;
+ default:
+ d_fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+ };
+ poptFreeContext(pc);
+
+ global_in_nmbd = true;
+
+ StartupTime = time(NULL);
+
+ sys_srandom(time(NULL) ^ sys_getpid());
+
+ if (!override_logfile) {
+ char *logfile = NULL;
+ if (asprintf(&logfile, "%s/log.nmbd", get_dyn_LOGFILEBASE()) < 0) {
+ exit(1);
+ }
+ lp_set_logfile(logfile);
+ SAFE_FREE(logfile);
+ }
+
+ fault_setup((void (*)(void *))fault_continue );
+ dump_core_setup("nmbd");
+
+ /* POSIX demands that signals are inherited. If the invoking process has
+ * these signals masked, we will have problems, as we won't receive them. */
+ BlockSignals(False, SIGHUP);
+ BlockSignals(False, SIGUSR1);
+ BlockSignals(False, SIGTERM);
+
+ CatchSignal( SIGHUP, SIGNAL_CAST sig_hup );
+ CatchSignal( SIGTERM, SIGNAL_CAST sig_term );
+
+#if defined(SIGFPE)
+ /* we are never interested in SIGFPE */
+ BlockSignals(True,SIGFPE);
+#endif
+
+ /* We no longer use USR2... */
+#if defined(SIGUSR2)
+ BlockSignals(True, SIGUSR2);
+#endif
+
+ if ( opt_interactive ) {
+ Fork = False;
+ log_stdout = True;
+ }
+
+ if ( log_stdout && Fork ) {
+ DEBUG(0,("ERROR: Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n"));
+ exit(1);
+ }
+
+ setup_logging( argv[0], log_stdout );
+
+ reopen_logs();
+
+ DEBUG(0,("nmbd version %s started.\n", SAMBA_VERSION_STRING));
+ DEBUGADD(0,("%s\n", COPYRIGHT_STARTUP_MESSAGE));
+
+ if (!lp_load_initial_only(get_dyn_CONFIGFILE())) {
+ DEBUG(0, ("error opening config file\n"));
+ exit(1);
+ }
+
+ if (nmbd_messaging_context() == NULL) {
+ return 1;
+ }
+
+ if ( !reload_nmbd_services(False) )
+ return(-1);
+
+ if(!init_names())
+ return -1;
+
+ reload_nmbd_services( True );
+
+ if (strequal(lp_workgroup(),"*")) {
+ DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
+ exit(1);
+ }
+
+ set_samba_nb_type();
+
+ if (!is_daemon && !is_a_socket(0)) {
+ DEBUG(0,("standard input is not a socket, assuming -D option\n"));
+ is_daemon = True;
+ }
+
+ if (is_daemon && !opt_interactive) {
+ DEBUG( 2, ( "Becoming a daemon.\n" ) );
+ become_daemon(Fork, no_process_group);
+ }
+
+#if HAVE_SETPGID
+ /*
+ * If we're interactive we want to set our own process group for
+ * signal management.
+ */
+ if (opt_interactive && !no_process_group)
+ setpgid( (pid_t)0, (pid_t)0 );
+#endif
+
+ if (nmbd_messaging_context() == NULL) {
+ return 1;
+ }
+
+#ifndef SYNC_DNS
+ /* Setup the async dns. We do it here so it doesn't have all the other
+ stuff initialised and thus chewing memory and sockets */
+ if(lp_we_are_a_wins_server() && lp_dns_proxy()) {
+ start_async_dns();
+ }
+#endif
+
+ if (!directory_exist(lp_lockdir(), NULL)) {
+ mkdir(lp_lockdir(), 0755);
+ }
+
+ pidfile_create("nmbd");
+
+ if (!reinit_after_fork(nmbd_messaging_context(), false)) {
+ DEBUG(0,("reinit_after_fork() failed\n"));
+ exit(1);
+ }
+
+ /* get broadcast messages */
+ claim_connection(NULL,"",FLAG_MSG_GENERAL|FLAG_MSG_DBWRAP);
+
+ messaging_register(nmbd_messaging_context(), NULL,
+ MSG_FORCE_ELECTION, nmbd_message_election);
+#if 0
+ /* Until winsrepl is done. */
+ messaging_register(nmbd_messaging_context(), NULL,
+ MSG_WINS_NEW_ENTRY, nmbd_wins_new_entry);
+#endif
+ messaging_register(nmbd_messaging_context(), NULL,
+ MSG_SHUTDOWN, nmbd_terminate);
+ messaging_register(nmbd_messaging_context(), NULL,
+ MSG_SMB_CONF_UPDATED, msg_reload_nmbd_services);
+ messaging_register(nmbd_messaging_context(), NULL,
+ MSG_SEND_PACKET, msg_nmbd_send_packet);
+
+ TimeInit();
+
+ DEBUG( 3, ( "Opening sockets %d\n", global_nmb_port ) );
+
+ if ( !open_sockets( is_daemon, global_nmb_port ) ) {
+ kill_async_dns_child();
+ 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"));
+ kill_async_dns_child();
+ exit(1);
+ }
+
+ /* Load in any static local names. */
+ if (p_lmhosts) {
+ set_dyn_LMHOSTSFILE(p_lmhosts);
+ }
+ load_lmhosts_file(get_dyn_LMHOSTSFILE());
+ DEBUG(3,("Loaded hosts file %s\n", get_dyn_LMHOSTSFILE()));
+
+ /* If we are acting as a WINS server, initialise data structures. */
+ if( !initialise_wins() ) {
+ DEBUG( 0, ( "nmbd: Failed when initialising WINS server.\n" ) );
+ kill_async_dns_child();
+ 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"));
+ kill_async_dns_child();
+ exit(1);
+ }
+
+ /* We can only take signals in the select. */
+ BlockSignals( True, SIGTERM );
+
+ TALLOC_FREE(frame);
+ process();
+
+ if (dbf)
+ x_fclose(dbf);
+ kill_async_dns_child();
+ return(0);
+}
diff --git a/source3/nmbd/nmbd_become_dmb.c b/source3/nmbd/nmbd_become_dmb.c
new file mode 100644
index 0000000000..a0b2ef15f8
--- /dev/null
+++ b/source3/nmbd/nmbd_become_dmb.c
@@ -0,0 +1,395 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
+
+static void become_domain_master_browser_bcast(const 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)
+{
+ unstring failname;
+ struct work_record *work;
+ struct server_record *servrec;
+
+ pull_ascii_nstring(failname, sizeof(failname), fail_name->name);
+ work = find_workgroup_on_subnet(subrec, failname);
+ if(!work) {
+ DEBUG(0,("become_domain_master_fail: Error - cannot find \
+workgroup %s on subnet %s\n", failname, subrec->subnet_name));
+ return;
+ }
+
+ /* Set the state back to DOMAIN_NONE. */
+ work->dom_state = DOMAIN_NONE;
+
+ if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
+ DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+ global_myname(), work->work_group, subrec->subnet_name));
+ return;
+ }
+
+ /* Update our server status. */
+ servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
+
+ /* Tell the namelist writer to write out a change. */
+ subrec->work_changed = True;
+
+ DEBUG(0,("become_domain_master_fail: Failed to become a domain master browser for \
+workgroup %s on subnet %s. Couldn't register name %s.\n",
+ work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
+}
+
+/****************************************************************************
+ Become a Domain Master Browser on a subnet.
+ ****************************************************************************/
+
+static void become_domain_master_stage2(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *registered_name,
+ uint16 nb_flags,
+ int ttl, struct in_addr registered_ip)
+{
+ unstring regname;
+ struct work_record *work;
+ struct server_record *servrec;
+
+ pull_ascii_nstring(regname, sizeof(regname), registered_name->name);
+ work = find_workgroup_on_subnet( subrec, regname);
+
+ if(!work) {
+ DEBUG(0,("become_domain_master_stage2: Error - cannot find \
+workgroup %s on subnet %s\n", regname, 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(), regname, 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;
+ const struct in_addr *nip;
+
+ /* Put our name and first IP address into the
+ workgroup struct as domain master browser. This
+ will stop us syncing with ourself if we are also
+ a local master browser. */
+
+ make_nmb_name(&nmbname, global_myname(), 0x20);
+
+ work->dmb_name = nmbname;
+
+ /* Pick the first interface IPv4 address as the domain master browser ip. */
+ nip = first_ipv4_iface();
+ if (!nip) {
+ DEBUG(0,("become_domain_master_stage2: "
+ "Error. get_interface returned NULL\n"));
+ return;
+ }
+ my_first_ip = *nip;
+
+ putip((char *)&work->dmb_addr, &my_first_ip);
+
+ /* We successfully registered by unicast with the
+ WINS server. We now expect to become the domain
+ master on the local subnets. If this fails, it's
+ probably a 1.9.16p2 to 1.9.16p11 server's fault.
+
+ This is a configuration issue that should be addressed
+ by the network administrator - you shouldn't have
+ several machines configured as a domain master browser
+ for the same WINS scope (except if they are 1.9.17 or
+ greater, and you know what you're doing.
+
+ see docs/DOMAIN.txt.
+
+ */
+ become_domain_master_browser_bcast(work->work_group);
+ } else {
+ /*
+ * Now we are a domain master on a broadcast subnet, we need to add
+ * the WORKGROUP<1b> name to the unicast subnet so that we can answer
+ * unicast requests sent to this name. This bug wasn't found for a while
+ * as it is strange to have a DMB without using WINS. JRA.
+ */
+ insert_permanent_name_into_unicast(subrec, registered_name, nb_flags);
+ }
+}
+
+/****************************************************************************
+ Start the name registration process when becoming a Domain Master Browser
+ on a subnet.
+****************************************************************************/
+
+static void become_domain_master_stage1(struct subnet_record *subrec, const 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)
+{
+ unstring name;
+ struct in_addr allones_ip;
+
+ pull_ascii_nstring(name, sizeof(name), nmbname->name);
+
+ /* 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. */
+
+ allones_ip.s_addr = htonl(INADDR_BROADCAST);
+
+ if(ismyip_v4(ip) || ip_equal_v4(allones_ip, ip) || is_zero_ip_v4(ip)) {
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "become_domain_master_query_success():\n" );
+ dbgtext( "Our address (%s) ", inet_ntoa(ip) );
+ dbgtext( "returned in query for name %s ", nmb_namestr(nmbname) );
+ dbgtext( "(domain master browser name) " );
+ dbgtext( "on subnet %s.\n", subrec->subnet_name );
+ dbgtext( "Continuing with domain master code.\n" );
+ }
+
+ become_domain_master_stage1(subrec, 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), 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)
+{
+ unstring name;
+
+ /* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
+ then this is a failure. Otherwise, not finding the name is what we want. */
+
+ if((subrec == unicast_subnet) && (fail_code != NAM_ERR)) {
+ DEBUG(0,("become_domain_master_query_fail: Error %d returned when \
+querying WINS server for name %s.\n",
+ fail_code, nmb_namestr(question_name)));
+ return;
+ }
+
+ /* Otherwise - not having the name allows us to register it. */
+ pull_ascii_nstring(name, sizeof(name), question_name->name);
+ become_domain_master_stage1(subrec, name);
+}
+
+/****************************************************************************
+ Attempt to become a domain master browser on all broadcast subnets.
+ ****************************************************************************/
+
+static void become_domain_master_browser_bcast(const char *workgroup_name)
+{
+ struct subnet_record *subrec;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+ struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
+
+ if (work && (work->dom_state == DOMAIN_NONE)) {
+ struct nmb_name nmbname;
+ make_nmb_name(&nmbname,workgroup_name,0x1b);
+
+ /*
+ * Check for our name on the given broadcast subnet first, only initiate
+ * further processing if we cannot find it.
+ */
+
+ if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "become_domain_master_browser_bcast:\n" );
+ dbgtext( "Attempting to become domain master browser on " );
+ dbgtext( "workgroup %s on subnet %s\n",
+ workgroup_name, subrec->subnet_name );
+ }
+
+ /* Send out a query to establish whether there's a
+ domain controller on the local subnet. If not,
+ we can become a domain controller.
+ */
+
+ DEBUG(0,("become_domain_master_browser_bcast: querying subnet %s \
+for domain master browser on workgroup %s\n", subrec->subnet_name, workgroup_name));
+
+ query_name(subrec, workgroup_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(const char *workgroup_name)
+{
+ struct work_record *work;
+
+ work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
+
+ if (work && (work->dom_state == DOMAIN_NONE)) {
+ struct nmb_name nmbname;
+
+ make_nmb_name(&nmbname,workgroup_name,0x1b);
+
+ /*
+ * Check for our name on the unicast subnet first, only initiate
+ * further processing if we cannot find it.
+ */
+
+ if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "become_domain_master_browser_wins:\n" );
+ dbgtext( "Attempting to become domain master browser " );
+ dbgtext( "on workgroup %s, subnet %s.\n",
+ workgroup_name, unicast_subnet->subnet_name );
+ }
+
+ /* Send out a query to establish whether there's a
+ domain master broswer registered with WINS. If not,
+ we can become a domain master browser.
+ */
+
+ DEBUG(0,("become_domain_master_browser_wins: querying WINS server from IP %s \
+for domain master browser name %s on workgroup %s\n",
+ inet_ntoa(unicast_subnet->myip), nmb_namestr(&nmbname), workgroup_name));
+
+ query_name(unicast_subnet, workgroup_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(lp_workgroup());
+ } else {
+ become_domain_master_browser_bcast(lp_workgroup());
+ }
+ }
+}
diff --git a/source3/nmbd/nmbd_become_lmb.c b/source3/nmbd/nmbd_become_lmb.c
new file mode 100644
index 0000000000..8aedd2c478
--- /dev/null
+++ b/source3/nmbd/nmbd_become_lmb.c
@@ -0,0 +1,593 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+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 )
+{
+ unstring name;
+ struct name_record *namerec;
+
+ if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) == NULL) {
+ pull_ascii_nstring(name, sizeof(name), nmbname->name);
+ /* The name needs to be created on the unicast subnet. */
+ (void)add_name_to_subnet( unicast_subnet, 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, const char *workgroup_name,
+ bool force_new_election )
+{
+ struct work_record *work;
+ struct server_record *servrec;
+ struct nmb_name nmbname;
+
+ if((work = find_workgroup_on_subnet( subrec, workgroup_name)) == NULL) {
+ DEBUG(0,("reset_workgroup_state: Error - cannot find workgroup %s on \
+subnet %s.\n", workgroup_name, subrec->subnet_name ));
+ return;
+ }
+
+ if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
+ DEBUG(0,("reset_workgroup_state: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+ global_myname(), work->work_group, subrec->subnet_name));
+ work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+ return;
+ }
+
+ /* Update our server status - remove any master flag and replace
+ it with the potential browser flag. */
+ servrec->serv.type &= ~SV_TYPE_MASTER_BROWSER;
+ servrec->serv.type |= (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0);
+
+ /* Tell the namelist writer to write out a change. */
+ subrec->work_changed = True;
+
+ /* Reset our election flags. */
+ work->ElectionCriterion &= ~0x4;
+
+ work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+
+ /* Forget who the local master browser was for
+ this workgroup. */
+
+ set_workgroup_local_master_browser_name( work, "");
+
+ /*
+ * Ensure the IP address of this subnet is not registered as one
+ * of the IP addresses of the WORKGROUP<1d> name on the unicast
+ * subnet. This undoes what we did below when we became a local
+ * master browser.
+ */
+
+ make_nmb_name(&nmbname, work->work_group, 0x1d);
+
+ remove_permanent_name_from_unicast( subrec, &nmbname);
+
+ if(force_new_election)
+ work->needelection = True;
+}
+
+/*******************************************************************
+ Unbecome the local master browser name release success function.
+******************************************************************/
+
+static void unbecome_local_master_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *released_name,
+ struct in_addr released_ip)
+{
+ bool force_new_election = False;
+ unstring relname;
+
+ memcpy((char *)&force_new_election, userdata->data, sizeof(bool));
+
+ DEBUG(3,("unbecome_local_master_success: released name %s.\n",
+ nmb_namestr(released_name)));
+
+ /* Now reset the workgroup and server state. */
+ pull_ascii_nstring(relname, sizeof(relname), released_name->name);
+ reset_workgroup_state( subrec, relname, 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 ", relname );
+ 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;
+ unstring failname;
+
+ memcpy((char *)&force_new_election, userdata->data, sizeof(bool));
+
+ DEBUG(0,("unbecome_local_master_fail: failed to release name %s. \
+Removing from namelist anyway.\n", nmb_namestr(fail_name)));
+
+ /* Do it anyway. */
+ namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
+ if(namerec)
+ remove_name_from_namelist(subrec, namerec);
+
+ /* Now reset the workgroup and server state. */
+ pull_ascii_nstring(failname, sizeof(failname), fail_name->name);
+ reset_workgroup_state( subrec, failname, 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 ", failname );
+ 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, const char *workgroup_name,
+ bool force_new_election)
+{
+ struct nmb_name nmbname;
+ struct name_record *namerec;
+
+ make_nmb_name(&nmbname, workgroup_name, 0x1d);
+ if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL) {
+ struct userdata_struct *userdata;
+ size_t size = sizeof(struct userdata_struct) + sizeof(bool);
+
+ if((userdata = (struct userdata_struct *)SMB_MALLOC(size)) == NULL) {
+ DEBUG(0,("release_1d_name: malloc fail.\n"));
+ return;
+ }
+
+ userdata->copy_fn = NULL;
+ userdata->free_fn = NULL;
+ userdata->userdata_len = sizeof(bool);
+ memcpy((char *)userdata->data, &force_new_election, sizeof(bool));
+
+ release_name(subrec, namerec,
+ unbecome_local_master_success,
+ unbecome_local_master_fail,
+ userdata);
+
+ zero_free(userdata, size);
+ }
+}
+
+/*******************************************************************
+ Unbecome the local master browser MSBROWSE name release success function.
+******************************************************************/
+
+static void release_msbrowse_name_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *released_name,
+ struct in_addr released_ip)
+{
+ DEBUG(4,("release_msbrowse_name_success: Released name %s on subnet %s\n.",
+ nmb_namestr(released_name), subrec->subnet_name ));
+
+ /* Remove the permanent MSBROWSE name added into the unicast subnet. */
+ remove_permanent_name_from_unicast( subrec, released_name);
+}
+
+/*******************************************************************
+ Unbecome the local master browser MSBROWSE name release fail function.
+******************************************************************/
+
+static void release_msbrowse_name_fail( struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *fail_name)
+{
+ struct name_record *namerec;
+
+ DEBUG(4,("release_msbrowse_name_fail: Failed to release name %s on subnet %s\n.",
+ nmb_namestr(fail_name), subrec->subnet_name ));
+
+ /* Release the name anyway. */
+ namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
+ if(namerec)
+ remove_name_from_namelist(subrec, namerec);
+
+ /* Remove the permanent MSBROWSE name added into the unicast subnet. */
+ remove_permanent_name_from_unicast( subrec, fail_name);
+}
+
+/*******************************************************************
+ Unbecome the local master browser. If force_new_election is true, restart
+ the election process after we've unbecome the local master.
+******************************************************************/
+
+void unbecome_local_master_browser(struct subnet_record *subrec, struct work_record *work,
+ bool force_new_election)
+{
+ struct name_record *namerec;
+ struct nmb_name nmbname;
+
+ /* Sanity check. */
+
+ DEBUG(2,("unbecome_local_master_browser: unbecoming local master for workgroup %s \
+on subnet %s\n",work->work_group, subrec->subnet_name));
+
+ if(find_server_in_workgroup( work, global_myname()) == NULL) {
+ DEBUG(0,("unbecome_local_master_browser: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+ global_myname(), work->work_group, subrec->subnet_name));
+ work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+ return;
+ }
+
+ /* Set the state to unbecoming. */
+ work->mst_state = MST_UNBECOMING_MASTER;
+
+ /*
+ * Release the WORKGROUP<1d> name asap to allow another machine to
+ * claim it.
+ */
+
+ release_1d_name( subrec, work->work_group, force_new_election);
+
+ /* Deregister any browser names we may have. */
+ make_nmb_name(&nmbname, MSBROWSE, 0x1);
+ if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL) {
+ release_name(subrec, namerec,
+ release_msbrowse_name_success,
+ release_msbrowse_name_fail,
+ NULL);
+ }
+
+ /*
+ * Ensure we have sent and processed these release packets
+ * before returning - we don't want to process any election
+ * packets before dealing with the 1d release.
+ */
+
+ retransmit_or_expire_response_records(time(NULL));
+}
+
+/****************************************************************************
+ Success in registering the WORKGROUP<1d> name.
+ We are now *really* a local master browser.
+ ****************************************************************************/
+
+static void become_local_master_stage2(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *registered_name,
+ uint16 nb_flags,
+ int ttl, struct in_addr registered_ip)
+{
+ int i = 0;
+ struct server_record *sl;
+ struct work_record *work;
+ struct server_record *servrec;
+ unstring regname;
+
+ pull_ascii_nstring(regname, sizeof(regname), registered_name->name);
+ work = find_workgroup_on_subnet( subrec, regname);
+
+ if(!work) {
+ DEBUG(0,("become_local_master_stage2: Error - cannot find \
+workgroup %s on subnet %s\n", regname, 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(), regname, 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)
+{
+ unstring failname;
+ struct work_record *work;
+
+ DEBUG(0,("become_local_master_fail2: failed to register name %s on subnet %s. \
+Failed to become a local master browser.\n", nmb_namestr(fail_name), subrec->subnet_name));
+
+ pull_ascii_nstring(failname, sizeof(failname), fail_name->name);
+ work = find_workgroup_on_subnet( subrec, failname);
+
+ if(!work) {
+ DEBUG(0,("become_local_master_fail2: Error - cannot find \
+workgroup %s on subnet %s\n", failname, 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 \
+ %s on subnet %s\n", work_name, subrec->subnet_name));
+ return;
+ }
+
+ DEBUG(3,("become_local_master_stage1: go to stage 2: register the %s<1d> name.\n",
+ work->work_group));
+
+ work->mst_state = MST_MSB; /* Registering MSBROWSE was successful. */
+
+ /*
+ * We registered the MSBROWSE name on a broadcast subnet, now need to add
+ * the MSBROWSE name to the unicast subnet so that we can answer
+ * unicast requests sent to this name. We create this name directly on
+ * the unicast subnet.
+ */
+
+ insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
+
+ /* Attempt to register the WORKGROUP<1d> name. */
+ register_name(subrec, work->work_group,0x1d,samba_nb_type,
+ become_local_master_stage2,
+ become_local_master_fail2,
+ NULL);
+}
+
+/****************************************************************************
+ Failed to register the MSBROWSE name.
+ ****************************************************************************/
+
+static void become_local_master_fail1(struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *fail_name)
+{
+ char *work_name = rrec->userdata->data;
+ struct work_record *work = find_workgroup_on_subnet(subrec, work_name);
+
+ if(!work) {
+ DEBUG(0,("become_local_master_fail1: Error - cannot find \
+workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
+ return;
+ }
+
+ if(find_server_in_workgroup(work, global_myname()) == NULL) {
+ DEBUG(0,("become_local_master_fail1: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+ global_myname(), work->work_group, subrec->subnet_name));
+ return;
+ }
+
+ reset_workgroup_state( subrec, work->work_group, False );
+
+ DEBUG(0,("become_local_master_fail1: Failed to become a local master browser for \
+workgroup %s on subnet %s. Couldn't register name %s.\n",
+ work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
+}
+
+/******************************************************************
+ Become the local master browser on a subnet.
+ This gets called if we win an election on this subnet.
+
+ Stage 1: mst_state was MST_POTENTIAL - go to MST_BACK register ^1^2__MSBROWSE__^2^1.
+ Stage 2: mst_state was MST_BACKUP - go to MST_MSB and register WORKGROUP<1d>.
+ Stage 3: mst_state was MST_MSB - go to MST_BROWSER.
+******************************************************************/
+
+void become_local_master_browser(struct subnet_record *subrec, struct work_record *work)
+{
+ struct userdata_struct *userdata;
+ size_t 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 *)SMB_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;
+ overmalloc_safe_strcpy(userdata->data, work->work_group, size - sizeof(*userdata) - 1);
+
+ /* 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, const 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
+
+ unstrcpy(work->local_master_browser_name, newname);
+}
diff --git a/source3/nmbd/nmbd_browserdb.c b/source3/nmbd/nmbd_browserdb.c
new file mode 100644
index 0000000000..a279364978
--- /dev/null
+++ b/source3/nmbd/nmbd_browserdb.c
@@ -0,0 +1,175 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+/* -------------------------------------------------------------------------- **
+ * Modified July 1998 by CRH.
+ * I converted this module to use the canned doubly-linked lists. I also
+ * added comments above the functions where possible.
+ */
+
+#include "includes.h"
+
+/* -------------------------------------------------------------------------- **
+ * Variables...
+ *
+ * lmb_browserlist - This is our local master browser list.
+ */
+
+struct browse_cache_record *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 )
+{
+ DLIST_REMOVE(lmb_browserlist, browc);
+ SAFE_FREE(browc);
+}
+
+/* ************************************************************************** **
+ * 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 );
+}
+
+/* ************************************************************************** **
+ * 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( const char *work_name,
+ const char *browser_name,
+ struct in_addr ip )
+{
+ struct browse_cache_record *browc;
+ time_t now = time( NULL );
+
+ browc = SMB_MALLOC_P(struct browse_cache_record);
+
+ if( NULL == browc ) {
+ DEBUG( 0, ("create_browser_in_lmb_cache: malloc fail !\n") );
+ return( NULL );
+ }
+
+ memset( (char *)browc, '\0', sizeof( *browc ) );
+
+ /* For a new lmb entry we want to sync with it after one minute. This
+ will allow it time to send out a local announce and build its
+ browse list.
+ */
+
+ browc->sync_time = now + 60;
+
+ /* Allow the new lmb to miss an announce period before we remove it. */
+ browc->death_time = now + ( (CHECK_TIME_MST_ANNOUNCE + 2) * 60 );
+
+ unstrcpy( browc->lmb_name, browser_name);
+ unstrcpy( browc->work_group, work_name);
+ strupper_m( browc->lmb_name );
+ strupper_m( browc->work_group );
+
+ browc->ip = ip;
+
+ DLIST_ADD_END(lmb_browserlist, browc, struct browse_cache_record *);
+
+ 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 );
+}
+
+/* ************************************************************************** **
+ * 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( const char *browser_name )
+{
+ struct browse_cache_record *browc;
+
+ for( browc = lmb_browserlist; browc; browc = browc->next ) {
+ if( strequal( browser_name, browc->lmb_name ) ) {
+ break;
+ }
+ }
+
+ return browc;
+}
+
+/* ************************************************************************** **
+ * 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 = lmb_browserlist; browc; browc = nextbrowc) {
+ nextbrowc = browc->next;
+
+ 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 );
+ }
+ }
+}
diff --git a/source3/nmbd/nmbd_browsesync.c b/source3/nmbd/nmbd_browsesync.c
new file mode 100644
index 0000000000..b630fd234d
--- /dev/null
+++ b/source3/nmbd/nmbd_browsesync.c
@@ -0,0 +1,676 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+/* This is our local master browser list database. */
+extern struct browse_cache_record *lmb_browserlist;
+
+/****************************************************************************
+As a domain master browser, do a sync with a local master browser.
+**************************************************************************/
+
+static void sync_with_lmb(struct browse_cache_record *browc)
+{
+ struct work_record *work;
+
+ if( !(work = find_workgroup_on_subnet(unicast_subnet, browc->work_group)) ) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "sync_with_lmb:\n" );
+ dbgtext( "Failed to get a workgroup for a local master browser " );
+ dbgtext( "cache entry workgroup " );
+ dbgtext( "%s, server %s\n", browc->work_group, browc->lmb_name );
+ }
+ return;
+ }
+
+ /* We should only be doing this if we are a domain master browser for
+ the given workgroup. Ensure this is so. */
+
+ if(!AM_DOMAIN_MASTER_BROWSER(work)) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "sync_with_lmb:\n" );
+ dbgtext( "We are trying to sync with a local master browser " );
+ dbgtext( "%s for workgroup %s\n", browc->lmb_name, browc->work_group );
+ dbgtext( "and we are not a domain master browser on this workgroup.\n" );
+ dbgtext( "Error!\n" );
+ }
+ return;
+ }
+
+ if( DEBUGLVL( 2 ) ) {
+ dbgtext( "sync_with_lmb:\n" );
+ dbgtext( "Initiating sync with local master browser " );
+ dbgtext( "%s<0x20> at IP %s ", browc->lmb_name, inet_ntoa(browc->ip) );
+ dbgtext( "for workgroup %s\n", browc->work_group );
+ }
+
+ sync_browse_lists(work, browc->lmb_name, 0x20, browc->ip, True, True);
+
+ browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60);
+}
+
+/****************************************************************************
+Sync or expire any local master browsers.
+**************************************************************************/
+
+void dmb_expire_and_sync_browser_lists(time_t t)
+{
+ static time_t last_run = 0;
+ struct browse_cache_record *browc;
+
+ /* Only do this every 20 seconds. */
+ if (t - last_run < 20)
+ return;
+
+ last_run = t;
+
+ expire_lmb_browsers(t);
+
+ for( browc = lmb_browserlist; browc; browc = browc->next ) {
+ 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)
+{
+ char outbuf[1024];
+ unstring myname;
+ unstring dmb_name;
+ char *p;
+
+ if(ismyip_v4(work->dmb_addr)) {
+ if( DEBUGLVL( 2 ) ) {
+ dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
+ dbgtext( "We are both a domain and a local master browser for " );
+ dbgtext( "workgroup %s. ", work->work_group );
+ dbgtext( "Do not announce to ourselves.\n" );
+ }
+ return;
+ }
+
+ memset(outbuf,'\0',sizeof(outbuf));
+ p = outbuf;
+ SCVAL(p,0,ANN_MasterAnnouncement);
+ p++;
+
+ unstrcpy(myname, global_myname());
+ strupper_m(myname);
+ myname[15]='\0';
+ /* The call below does CH_UNIX -> CH_DOS conversion. JRA */
+ push_ascii(p, myname, sizeof(outbuf)-PTR_DIFF(p,outbuf)-1, STR_TERMINATE);
+
+ p = skip_string(outbuf,sizeof(outbuf),p);
+
+ if( DEBUGLVL( 4 ) ) {
+ dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
+ dbgtext( "Sending local master announce to " );
+ dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name),
+ work->work_group );
+ }
+
+ /* Target name for send_mailslot must be in UNIX charset. */
+ pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
+ send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
+ global_myname(), 0x0, dmb_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)
+{
+ unstring dmb_name;
+
+ if( DEBUGLVL( 2 ) ) {
+ dbgtext( "sync_with_dmb:\n" );
+ dbgtext( "Initiating sync with domain master browser " );
+ dbgtext( "%s ", nmb_namestr(&work->dmb_name) );
+ dbgtext( "at IP %s ", inet_ntoa(work->dmb_addr) );
+ dbgtext( "for workgroup %s\n", work->work_group );
+ }
+
+ pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
+ sync_browse_lists(work, dmb_name, work->dmb_name.name_type,
+ work->dmb_addr, False, True);
+}
+
+/****************************************************************************
+ Function called when a node status query to a domain master browser IP succeeds.
+****************************************************************************/
+
+static void domain_master_node_status_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct res_rec *answers,
+ struct in_addr from_ip)
+{
+ struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
+
+ if( work == NULL ) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "domain_master_node_status_success:\n" );
+ dbgtext( "Unable to find workgroup " );
+ dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );
+ }
+ return;
+ }
+
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "domain_master_node_status_success:\n" );
+ dbgtext( "Success in node status for workgroup " );
+ dbgtext( "%s from ip %s\n", work->work_group, inet_ntoa(from_ip) );
+ }
+
+ /* Go through the list of names found at answers->rdata and look for
+ the first SERVER<0x20> name. */
+
+ if(answers->rdata != NULL) {
+ char *p = answers->rdata;
+ int numnames = CVAL(p, 0);
+
+ p += 1;
+
+ while (numnames--) {
+ unstring qname;
+ uint16 nb_flags;
+ int name_type;
+
+ pull_ascii_nstring(qname, sizeof(qname), p);
+ name_type = CVAL(p,15);
+ nb_flags = get_nb_flags(&p[16]);
+ trim_char(qname,'\0',' ');
+
+ p += 18;
+
+ if(!(nb_flags & NB_GROUP) && (name_type == 0x20)) {
+ struct nmb_name nmbname;
+
+ make_nmb_name(&nmbname, qname, name_type);
+
+ /* Copy the dmb name and IP address
+ into the workgroup struct. */
+
+ work->dmb_name = nmbname;
+ putip((char *)&work->dmb_addr, &from_ip);
+
+ /* Do the local master browser announcement to the domain
+ master browser name and IP. */
+ announce_local_master_browser_to_domain_master_browser( work );
+
+ /* Now synchronise lists with the domain master browser. */
+ sync_with_dmb(work);
+ break;
+ }
+ }
+ } else if( DEBUGLVL( 0 ) ) {
+ dbgtext( "domain_master_node_status_success:\n" );
+ dbgtext( "Failed to find a SERVER<0x20> name in reply from IP " );
+ dbgtext( "%s.\n", inet_ntoa(from_ip) );
+ }
+}
+
+/****************************************************************************
+ Function called when a node status query to a domain master browser IP fails.
+****************************************************************************/
+
+static void domain_master_node_status_fail(struct subnet_record *subrec,
+ struct response_record *rrec)
+{
+ struct userdata_struct *userdata = rrec->userdata;
+
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "domain_master_node_status_fail:\n" );
+ dbgtext( "Doing a node status request to the domain master browser\n" );
+ dbgtext( "for workgroup %s ", userdata ? userdata->data : "NULL" );
+ dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
+ dbgtext( "Cannot sync browser lists.\n" );
+ }
+}
+
+/****************************************************************************
+ Function called when a query for a WORKGROUP<1b> name succeeds.
+****************************************************************************/
+
+static void find_domain_master_name_query_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata_in,
+ struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
+{
+ /*
+ * Unfortunately, finding the IP address of the Domain Master Browser,
+ * as we have here, is not enough. We need to now do a sync to the
+ * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
+ * respond to the SMBSERVER name. To get this name from IP
+ * address we do a Node status request, and look for the first
+ * NAME<0x20> in the response, and take that as the server name.
+ * We also keep a cache of the Domain Master Browser name for this
+ * workgroup in the Workgroup struct, so that if the same IP addess
+ * is returned every time, we don't need to do the node status
+ * request.
+ */
+
+ struct work_record *work;
+ struct nmb_name nmbname;
+ struct userdata_struct *userdata;
+ size_t size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
+ unstring qname;
+
+ pull_ascii_nstring(qname, sizeof(qname), q_name->name);
+ if( !(work = find_workgroup_on_subnet(subrec, qname)) ) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "find_domain_master_name_query_success:\n" );
+ dbgtext( "Failed to find workgroup %s\n", qname);
+ }
+ return;
+ }
+
+ /* First check if we already have a dmb for this workgroup. */
+
+ if(!is_zero_ip_v4(work->dmb_addr) && ip_equal_v4(work->dmb_addr, answer_ip)) {
+ /* Do the local master browser announcement to the domain
+ master browser name and IP. */
+ announce_local_master_browser_to_domain_master_browser( work );
+
+ /* Now synchronise lists with the domain master browser. */
+ sync_with_dmb(work);
+ return;
+ } else {
+ zero_ip_v4(&work->dmb_addr);
+ }
+
+ /* Now initiate the node status request. */
+
+ /* We used to use the name "*",0x0 here, but some Windows
+ * servers don't answer that name. However we *know* they
+ * have the name workgroup#1b (as we just looked it up).
+ * So do the node status request on this name instead.
+ * Found at LBL labs. JRA.
+ */
+
+ make_nmb_name(&nmbname,work->work_group,0x1b);
+
+ /* 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 *)SMB_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;
+ overmalloc_safe_strcpy(userdata->data, work->work_group, size - sizeof(*userdata) - 1);
+
+ node_status( subrec, &nmbname, answer_ip,
+ domain_master_node_status_success,
+ domain_master_node_status_fail,
+ userdata);
+
+ zero_free(userdata, size);
+}
+
+/****************************************************************************
+ Function called when a query for a WORKGROUP<1b> name fails.
+ ****************************************************************************/
+
+static void find_domain_master_name_query_fail(struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *question_name, int fail_code)
+{
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "find_domain_master_name_query_fail:\n" );
+ dbgtext( "Unable to find the Domain Master Browser name " );
+ dbgtext( "%s for the workgroup %s.\n",
+ nmb_namestr(question_name), question_name->name );
+ dbgtext( "Unable to sync browse lists in this workgroup.\n" );
+ }
+}
+
+/****************************************************************************
+As a local master browser for a workgroup find the domain master browser
+name, announce ourselves as local master browser to it and then pull the
+full domain browse lists from it onto the given subnet.
+**************************************************************************/
+
+void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
+ struct work_record *work)
+{
+ /* Only do this if we are using a WINS server. */
+ if(we_are_a_wins_client() == False) {
+ if( DEBUGLVL( 10 ) ) {
+ dbgtext( "announce_and_sync_with_domain_master_browser:\n" );
+ dbgtext( "Ignoring, as we are not a WINS client.\n" );
+ }
+ return;
+ }
+
+ /* First, query for the WORKGROUP<1b> name from the WINS server. */
+ query_name(unicast_subnet, work->work_group, 0x1b,
+ 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;
+ unstring server_name;
+
+ server_name[0] = 0;
+
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "get_domain_master_name_node_status_success:\n" );
+ dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
+ }
+
+ /*
+ * Go through the list of names found at answers->rdata and look for
+ * the first WORKGROUP<0x1b> name.
+ */
+
+ if(answers->rdata != NULL) {
+ char *p = answers->rdata;
+ int numnames = CVAL(p, 0);
+
+ p += 1;
+
+ while (numnames--) {
+ unstring qname;
+ uint16 nb_flags;
+ int name_type;
+
+ pull_ascii_nstring(qname, sizeof(qname), p);
+ name_type = CVAL(p,15);
+ nb_flags = get_nb_flags(&p[16]);
+ trim_char(qname,'\0',' ');
+
+ p += 18;
+
+ if(!(nb_flags & NB_GROUP) && (name_type == 0x00) &&
+ server_name[0] == 0) {
+ /* this is almost certainly the server netbios name */
+ unstrcpy(server_name, qname);
+ continue;
+ }
+
+ if(!(nb_flags & NB_GROUP) && (name_type == 0x1b)) {
+ if( DEBUGLVL( 5 ) ) {
+ dbgtext( "get_domain_master_name_node_status_success:\n" );
+ dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
+ dbgtext( "is a domain master browser for workgroup " );
+ dbgtext( "%s. Adding this name.\n", qname );
+ }
+
+ /*
+ * If we don't already know about this workgroup, add it
+ * to the workgroup list on the unicast_subnet.
+ */
+
+ if((work = find_workgroup_on_subnet( subrec, qname)) == NULL) {
+ struct nmb_name nmbname;
+ /*
+ * Add it - with an hour in the cache.
+ */
+ if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
+ return;
+
+ /* remember who the master is */
+ unstrcpy(work->local_master_browser_name, server_name);
+ make_nmb_name(&nmbname, server_name, 0x20);
+ work->dmb_name = nmbname;
+ work->dmb_addr = from_ip;
+ }
+ break;
+ }
+ }
+ } else if( DEBUGLVL( 0 ) ) {
+ dbgtext( "get_domain_master_name_node_status_success:\n" );
+ dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " );
+ dbgtext( "%s.\n", inet_ntoa(from_ip) );
+ }
+}
+
+/****************************************************************************
+ Function called when a node status query to a domain master browser IP fails.
+****************************************************************************/
+
+static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
+ struct response_record *rrec)
+{
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "get_domain_master_name_node_status_fail:\n" );
+ dbgtext( "Doing a node status request to the domain master browser " );
+ dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
+ dbgtext( "Cannot get workgroup name.\n" );
+ }
+}
+
+/****************************************************************************
+ Function called when a query for *<1b> name succeeds.
+****************************************************************************/
+
+static void find_all_domain_master_names_query_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata_in,
+ struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
+{
+ /*
+ * We now have a list of all the domain master browsers for all workgroups
+ * that have registered with the WINS server. Now do a node status request
+ * to each one and look for the first 1b name in the reply. This will be
+ * the workgroup name that we will add to the unicast subnet as a 'non-local'
+ * workgroup.
+ */
+
+ struct nmb_name nmbname;
+ struct in_addr send_ip;
+ int i;
+
+ if( DEBUGLVL( 5 ) ) {
+ dbgtext( "find_all_domain_master_names_query_succes:\n" );
+ dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
+ dbgtext( "IP addresses for Domain Master Browsers.\n" );
+ }
+
+ for(i = 0; i < rrec->rdlength / 6; i++) {
+ /* Initiate the node status requests. */
+ make_nmb_name(&nmbname, "*", 0);
+
+ putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
+
+ /*
+ * Don't send node status requests to ourself.
+ */
+
+ if(ismyip_v4( send_ip )) {
+ if( DEBUGLVL( 5 ) ) {
+ dbgtext( "find_all_domain_master_names_query_succes:\n" );
+ dbgtext( "Not sending node status to our own IP " );
+ dbgtext( "%s.\n", inet_ntoa(send_ip) );
+ }
+ continue;
+ }
+
+ if( DEBUGLVL( 5 ) ) {
+ dbgtext( "find_all_domain_master_names_query_success:\n" );
+ dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
+ }
+
+ node_status( subrec, &nmbname, send_ip,
+ get_domain_master_name_node_status_success,
+ get_domain_master_name_node_status_fail,
+ NULL);
+ }
+}
+
+/****************************************************************************
+ Function called when a query for *<1b> name fails.
+ ****************************************************************************/
+static void find_all_domain_master_names_query_fail(struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *question_name, int fail_code)
+{
+ if( DEBUGLVL( 10 ) ) {
+ dbgtext( "find_domain_master_name_query_fail:\n" );
+ dbgtext( "WINS server did not reply to a query for name " );
+ dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
+ dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" );
+ }
+}
+
+/****************************************************************************
+ If we are a domain master browser on the unicast subnet, do a query to the
+ WINS server for the *<1b> name. This will only work to a Samba WINS server,
+ so ignore it if we fail. If we succeed, contact each of the IP addresses in
+ turn and do a node status request to them. If this succeeds then look for a
+ <1b> name in the reply - this is the workgroup name. Add this to the unicast
+ subnet. This is expensive, so we only do this every 15 minutes.
+**************************************************************************/
+
+void collect_all_workgroup_names_from_wins_server(time_t t)
+{
+ static time_t lastrun = 0;
+ struct work_record *work;
+
+ /* 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, lp_workgroup())) == NULL) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
+ dbgtext( "Cannot find my workgroup %s ", lp_workgroup() );
+ dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
+ }
+ return;
+ }
+
+ if(!AM_DOMAIN_MASTER_BROWSER(work))
+ return;
+
+ if ((lastrun != 0) && (t < lastrun + (15 * 60)))
+ return;
+
+ lastrun = t;
+
+ /* First, query for the *<1b> name from the WINS server. */
+ query_name(unicast_subnet, "*", 0x1b,
+ 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, lp_workgroup());
+ 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(lp_workgroup(), work->work_group)) {
+ count++;
+ }
+ }
+
+ /* sync with a probability of 1/count */
+ for (work=unicast_subnet->workgrouplist; work; work = work->next) {
+ if (strcmp(lp_workgroup(), work->work_group)) {
+ unstring dmb_name;
+
+ 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);
+ }
+
+ pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
+
+ DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
+ dmb_name, inet_ntoa(work->dmb_addr)));
+
+ sync_browse_lists(work,
+ dmb_name,
+ work->dmb_name.name_type,
+ work->dmb_addr, False, False);
+ }
+ }
+}
diff --git a/source3/nmbd/nmbd_elections.c b/source3/nmbd/nmbd_elections.c
new file mode 100644
index 0000000000..b50d215b91
--- /dev/null
+++ b/source3/nmbd/nmbd_elections.c
@@ -0,0 +1,400 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+/* Election parameters. */
+extern time_t StartupTime;
+
+/****************************************************************************
+ Send an election datagram packet.
+**************************************************************************/
+
+static void send_election_dgram(struct subnet_record *subrec, const char *workgroup_name,
+ uint32 criterion, int timeup,const char *server_name)
+{
+ char outbuf[1024];
+ unstring srv_name;
+ char *p;
+
+ DEBUG(2,("send_election_dgram: Sending election packet for workgroup %s on subnet %s\n",
+ workgroup_name, subrec->subnet_name ));
+
+ memset(outbuf,'\0',sizeof(outbuf));
+ p = outbuf;
+ SCVAL(p,0,ANN_Election); /* Election opcode. */
+ p++;
+
+ SCVAL(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;
+ unstrcpy(srv_name, server_name);
+ strupper_m(srv_name);
+ /* The following call does UNIX -> DOS charset conversion. */
+ push_ascii(p, srv_name, sizeof(outbuf)-PTR_DIFF(p,outbuf)-1, STR_TERMINATE);
+ p = skip_string(outbuf,sizeof(outbuf),p);
+
+ 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)
+{
+ unstring aname;
+ pull_ascii_nstring(aname, sizeof(aname), answer_name->name);
+ DEBUG(3,("check_for_master_browser_success: Local master browser for workgroup %s exists at \
+IP %s (just checking).\n", aname, 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)
+{
+ unstring workgroup_name;
+ struct work_record *work;
+
+ pull_ascii_nstring(workgroup_name,sizeof(workgroup_name),question_name->name);
+
+ 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, lp_workgroup())) {
+
+ 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;
+ const char *workgroup_name = lp_workgroup();
+
+ 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;
+
+ START_PROFILE(run_elections);
+
+ /* Send election packets once every 2 seconds - note */
+ if (lastime && (t - lastime < 2)) {
+ END_PROFILE(run_elections);
+ 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);
+ if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) {
+ DEBUG(8,("run_elections: Cannot send election packet yet as name %s not \
+yet registered on subnet %s\n", nmb_namestr(&nmbname), subrec->subnet_name ));
+ continue;
+ }
+
+ send_election_dgram(subrec, work->work_group, work->ElectionCriterion,
+ t - StartupTime, global_myname());
+
+ if (work->ElectionCount++ >= 4) {
+ /* Won election (4 packets were sent out uncontested. */
+ DEBUG(2,("run_elections: >>> Won election for workgroup %s on subnet %s <<<\n",
+ work->work_group, subrec->subnet_name ));
+
+ work->RunningElection = False;
+
+ become_local_master_browser(subrec, work);
+ }
+ }
+ }
+ }
+ END_PROFILE(run_elections);
+}
+
+/*******************************************************************
+ Determine if I win an election.
+******************************************************************/
+
+static bool win_election(struct work_record *work, int version,
+ uint32 criterion, int timeup, const 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;
+ unstring server_name;
+ struct work_record *work;
+ unstring workgroup_name;
+
+ START_PROFILE(election);
+
+ pull_ascii_nstring(server_name, sizeof(server_name), buf+13);
+ pull_ascii_nstring(workgroup_name, sizeof(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 ));
+ goto done;
+ }
+
+ if (!strequal(work->work_group, lp_workgroup())) {
+ DEBUG(3,("process_election: ignoring election request for workgroup %s on subnet %s as this \
+is not my workgroup.\n", work->work_group, subrec->subnet_name ));
+ goto done;
+ }
+
+ if (win_election(work, version,criterion,timeup,server_name)) {
+ /* We take precedence over the requesting server. */
+ if (!work->RunningElection) {
+ /* We weren't running an election - start running one. */
+
+ work->needelection = True;
+ work->ElectionCount=0;
+ }
+
+ /* Note that if we were running an election for this workgroup on this
+ subnet already, we just ignore the server we take precedence over. */
+ } else {
+ /* We lost. Stop participating. */
+ work->needelection = False;
+
+ if (work->RunningElection || AM_LOCAL_MASTER_BROWSER(work)) {
+ work->RunningElection = False;
+ DEBUG(3,("process_election: >>> Lost election for workgroup %s on subnet %s <<<\n",
+ work->work_group, subrec->subnet_name ));
+ if (AM_LOCAL_MASTER_BROWSER(work))
+ unbecome_local_master_browser(subrec, work, False);
+ }
+ }
+done:
+
+ END_PROFILE(election);
+}
+
+/****************************************************************************
+ This function looks over all the workgroups known on all the broadcast
+ subnets and decides if a browser election is to be run on that workgroup.
+ It returns True if any election packets need to be sent (this will then
+ be done by run_elections().
+***************************************************************************/
+
+bool check_elections(void)
+{
+ struct subnet_record *subrec;
+ bool run_any_election = False;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+ struct work_record *work;
+ for (work = subrec->workgrouplist; work; work = work->next) {
+ if (work->RunningElection) {
+ run_any_election = work->RunningElection;
+ }
+
+ /*
+ * Start an election if we have any chance of winning.
+ * Note this is a change to the previous code, that would
+ * only run an election if nmbd was in the potential browser
+ * state. We need to run elections in any state if we're told
+ * to. JRA.
+ */
+
+ if (work->needelection && !work->RunningElection && lp_local_master()) {
+ /*
+ * We can only run an election for a workgroup if we have
+ * registered the WORKGROUP<1e> name, as that's the name
+ * we must listen to.
+ */
+ struct nmb_name nmbname;
+
+ make_nmb_name(&nmbname, work->work_group, 0x1e);
+ if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) {
+ DEBUG(8,("check_elections: Cannot send election packet yet as name %s not \
+yet registered on subnet %s\n", nmb_namestr(&nmbname), subrec->subnet_name ));
+ continue;
+ }
+
+ DEBUG(3,("check_elections: >>> Starting election for workgroup %s on subnet %s <<<\n",
+ work->work_group, subrec->subnet_name ));
+
+ work->ElectionCount = 0;
+ work->RunningElection = True;
+ work->needelection = False;
+ }
+ }
+ }
+ return run_any_election;
+}
+
+/****************************************************************************
+ Process a internal Samba message forcing an election.
+***************************************************************************/
+
+void nmbd_message_election(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct subnet_record *subrec;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+ struct work_record *work;
+ for (work = subrec->workgrouplist; work; work = work->next) {
+ if (strequal(work->work_group, lp_workgroup())) {
+ work->needelection = True;
+ work->ElectionCount=0;
+ work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+ }
+ }
+ }
+}
diff --git a/source3/nmbd/nmbd_incomingdgrams.c b/source3/nmbd/nmbd_incomingdgrams.c
new file mode 100644
index 0000000000..75ab9419c2
--- /dev/null
+++ b/source3/nmbd/nmbd_incomingdgrams.c
@@ -0,0 +1,847 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+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;
+ unstring announce_name;
+ uint32 servertype = IVAL(buf,23);
+ fstring comment;
+ struct work_record *work;
+ struct server_record *servrec;
+ unstring work_name;
+ unstring source_name;
+
+ START_PROFILE(host_announce);
+
+ pull_ascii_fstring(comment, buf+31);
+
+ pull_ascii_nstring(announce_name, sizeof(announce_name), buf+5);
+ pull_ascii_nstring(source_name, sizeof(source_name), dgram->source_name.name);
+
+ DEBUG(3,("process_host_announce: from %s<%02x> IP %s to \
+%s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
+ nmb_namestr(&dgram->dest_name),announce_name));
+
+ DEBUG(5,("process_host_announce: ttl=%d server type=%08x comment=%s\n",
+ ttl, servertype,comment));
+
+ /* Filter servertype to remove impossible bits. */
+ servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
+
+ /* A host announcement must be sent to the name WORKGROUP<1d>. */
+ if(dgram->dest_name.name_type != 0x1d) {
+ DEBUG(2,("process_host_announce: incorrect name type for destination from IP %s \
+(was %02x) should be 0x1d. Allowing packet anyway.\n",
+ inet_ntoa(p->ip), dgram->dest_name.name_type));
+ /* Change it so it was. */
+ dgram->dest_name.name_type = 0x1d;
+ }
+
+ /* For a host announce the workgroup name is the destination name. */
+ pull_ascii_nstring(work_name, sizeof(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()))
+ unstrcpy(work_name,lp_workgroup());
+
+ /*
+ * We are being very agressive here in adding a workgroup
+ * name on the basis of a host announcing itself as being
+ * in that workgroup. Maybe we should wait for the workgroup
+ * announce instead ? JRA.
+ */
+
+ work = find_workgroup_on_subnet(subrec, work_name);
+
+ if(servertype != 0) {
+ if (work ==NULL ) {
+ /* We have no record of this workgroup. Add it. */
+ if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
+ goto done;
+ }
+
+ if((servrec = find_server_in_workgroup( work, announce_name))==NULL) {
+ /* If this server is not already in the workgroup, add it. */
+ create_server_on_workgroup(work, announce_name,
+ servertype|SV_TYPE_LOCAL_LIST_ONLY,
+ ttl, comment);
+ } else {
+ /* Update the record. */
+ servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
+ update_server_ttl( servrec, ttl);
+ fstrcpy(servrec->serv.comment,comment);
+ }
+ } else {
+ /*
+ * This server is announcing it is going down. Remove it from the
+ * workgroup.
+ */
+ if(!is_myname(announce_name) && (work != NULL) &&
+ ((servrec = find_server_in_workgroup( work, announce_name))!=NULL)) {
+ remove_server_from_workgroup( work, servrec);
+ }
+ }
+
+ subrec->work_changed = True;
+done:
+
+ END_PROFILE(host_announce);
+}
+
+/*******************************************************************
+ Process an incoming WORKGROUP announcement packet.
+*******************************************************************/
+
+void process_workgroup_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int ttl = IVAL(buf,1)/1000;
+ unstring workgroup_announce_name;
+ unstring master_name;
+ uint32 servertype = IVAL(buf,23);
+ struct work_record *work;
+ unstring source_name;
+ unstring dest_name;
+
+ START_PROFILE(workgroup_announce);
+
+ pull_ascii_nstring(workgroup_announce_name,sizeof(workgroup_announce_name),buf+5);
+ pull_ascii_nstring(master_name,sizeof(master_name),buf+31);
+ pull_ascii_nstring(source_name,sizeof(source_name),dgram->source_name.name);
+ pull_ascii_nstring(dest_name,sizeof(dest_name),dgram->dest_name.name);
+
+ DEBUG(3,("process_workgroup_announce: from %s<%02x> IP %s to \
+%s for workgroup %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
+ nmb_namestr(&dgram->dest_name),workgroup_announce_name));
+
+ DEBUG(5,("process_workgroup_announce: ttl=%d server type=%08x master browser=%s\n",
+ ttl, servertype, master_name));
+
+ /* Workgroup announcements must only go to the MSBROWSE name. */
+ if (!strequal(dest_name, MSBROWSE) || (dgram->dest_name.name_type != 0x1)) {
+ DEBUG(0,("process_workgroup_announce: from IP %s should be to __MSBROWSE__<0x01> not %s\n",
+ inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
+ goto done;
+ }
+
+ if ((work = find_workgroup_on_subnet(subrec, workgroup_announce_name))==NULL) {
+ /* We have no record of this workgroup. Add it. */
+ if((work = create_workgroup_on_subnet(subrec, workgroup_announce_name, ttl))==NULL)
+ goto done;
+ } else {
+ /* Update the workgroup death_time. */
+ update_workgroup_ttl(work, ttl);
+ }
+
+ if(*work->local_master_browser_name == '\0') {
+ /* Set the master browser name. */
+ set_workgroup_local_master_browser_name( work, master_name );
+ }
+
+ subrec->work_changed = True;
+
+done:
+
+ END_PROFILE(workgroup_announce);
+}
+
+/*******************************************************************
+ Process an incoming local master browser announcement packet.
+*******************************************************************/
+
+void process_local_master_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int ttl = IVAL(buf,1)/1000;
+ unstring server_name;
+ uint32 servertype = IVAL(buf,23);
+ fstring comment;
+ unstring work_name;
+ struct work_record *work = NULL;
+ struct server_record *servrec;
+ unstring source_name;
+
+ START_PROFILE(local_master_announce);
+
+ pull_ascii_nstring(server_name,sizeof(server_name),buf+5);
+ pull_ascii_fstring(comment, buf+31);
+ pull_ascii_nstring(source_name, sizeof(source_name), dgram->source_name.name);
+ pull_ascii_nstring(work_name, sizeof(work_name), dgram->dest_name.name);
+
+ DEBUG(3,("process_local_master_announce: from %s<%02x> IP %s to \
+%s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
+ nmb_namestr(&dgram->dest_name),server_name));
+
+ DEBUG(5,("process_local_master_announce: ttl=%d server type=%08x comment=%s\n",
+ ttl, servertype, comment));
+
+ /* A local master announcement must be sent to the name WORKGROUP<1e>. */
+ if(dgram->dest_name.name_type != 0x1e) {
+ DEBUG(0,("process_local_master_announce: incorrect name type for destination from IP %s \
+(was %02x) should be 0x1e. Ignoring packet.\n",
+ inet_ntoa(p->ip), dgram->dest_name.name_type));
+ goto done;
+ }
+
+ /* Filter servertype to remove impossible bits. */
+ servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
+
+ /* For a local master announce the workgroup name is the destination name. */
+
+ if ((work = find_workgroup_on_subnet(subrec, work_name))==NULL) {
+ /* Don't bother adding if it's a local master release announce. */
+ if(servertype == 0)
+ goto done;
+
+ /* We have no record of this workgroup. Add it. */
+ if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
+ goto done;
+ }
+
+ /* If we think we're the local master browser for this workgroup,
+ we should never have got this packet. We don't see our own
+ packets.
+ */
+ if(AM_LOCAL_MASTER_BROWSER(work)) {
+ DEBUG(0,("process_local_master_announce: Server %s at IP %s is announcing itself as \
+a local master browser for workgroup %s and we think we are master. Forcing election.\n",
+ server_name, inet_ntoa(p->ip), work_name));
+
+ /* Samba nmbd versions 1.9.17 to 1.9.17p4 have a bug in that when
+ they have become a local master browser once, they will never
+ stop sending local master announcements. To fix this we send
+ them a reset browser packet, with level 0x2 on the __SAMBA__
+ name that only they should be listening to. */
+
+ send_browser_reset( 0x2, "__SAMBA__" , 0x20, p->ip);
+
+ /* We should demote ourself and force an election. */
+
+ unbecome_local_master_browser( subrec, work, True);
+
+ /* The actual election requests are handled in nmbd_election.c */
+ goto done;
+ }
+
+ /* Find the server record on this workgroup. If it doesn't exist, add it. */
+
+ if(servertype != 0) {
+ if((servrec = find_server_in_workgroup( work, server_name))==NULL) {
+ /* If this server is not already in the workgroup, add it. */
+ create_server_on_workgroup(work, server_name,
+ servertype|SV_TYPE_LOCAL_LIST_ONLY,
+ ttl, comment);
+ } else {
+ /* Update the record. */
+ servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
+ update_server_ttl(servrec, ttl);
+ fstrcpy(servrec->serv.comment,comment);
+ }
+
+ 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) &&
+ ((servrec = find_server_in_workgroup( work, server_name))!=NULL)) {
+ remove_server_from_workgroup( work, servrec);
+ }
+ }
+
+ subrec->work_changed = True;
+done:
+
+ END_PROFILE(local_master_announce);
+}
+
+/*******************************************************************
+ Process a domain master announcement frame.
+ Domain master browsers receive these from local masters. The Domain
+ master should then issue a sync with the local master, asking for
+ that machines local server list.
+******************************************************************/
+
+void process_master_browser_announce(struct subnet_record *subrec,
+ struct packet_struct *p,char *buf)
+{
+ unstring local_master_name;
+ struct work_record *work;
+ struct browse_cache_record *browrec;
+
+ START_PROFILE(master_browser_announce);
+
+ pull_ascii_nstring(local_master_name,sizeof(local_master_name),buf);
+
+ DEBUG(3,("process_master_browser_announce: Local master announce from %s IP %s.\n",
+ local_master_name, inet_ntoa(p->ip)));
+
+ if (!lp_domain_master()) {
+ DEBUG(0,("process_master_browser_announce: Not configured as domain \
+master - ignoring master announce.\n"));
+ goto done;
+ }
+
+ if((work = find_workgroup_on_subnet(subrec, lp_workgroup())) == NULL) {
+ DEBUG(0,("process_master_browser_announce: Cannot find workgroup %s on subnet %s\n",
+ lp_workgroup(), subrec->subnet_name));
+ goto done;
+ }
+
+ if(!AM_DOMAIN_MASTER_BROWSER(work)) {
+ DEBUG(0,("process_master_browser_announce: Local master announce made to us from \
+%s IP %s and we are not a domain master browser.\n", local_master_name, inet_ntoa(p->ip)));
+ goto done;
+ }
+
+ /* Add this host as a local master browser entry on the browse lists.
+ This causes a sync request to be made to it at a later date.
+ */
+
+ if((browrec = find_browser_in_lmb_cache( local_master_name )) == NULL) {
+ /* Add it. */
+ create_browser_in_lmb_cache( work->work_group, local_master_name, p->ip);
+ } else {
+ update_browser_death_time(browrec);
+ }
+
+done:
+
+ END_PROFILE(master_browser_announce);
+}
+
+/*******************************************************************
+ Process an incoming LanMan host announcement packet.
+*******************************************************************/
+
+void process_lm_host_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf, int len)
+{
+ 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);
+ unstring announce_name;
+ struct work_record *work;
+ struct server_record *servrec;
+ unstring work_name;
+ unstring source_name;
+ fstring comment;
+ char *s = get_safe_str_ptr(buf,len,buf,9);
+
+ START_PROFILE(lm_host_announce);
+ if (!s) {
+ goto done;
+ }
+ s = skip_string(buf,len,s);
+ if (!s) {
+ goto done;
+ }
+ pull_ascii(comment, s, sizeof(fstring), 43, STR_TERMINATE);
+
+ pull_ascii_nstring(announce_name,sizeof(announce_name),buf+9);
+ pull_ascii_nstring(source_name,sizeof(source_name),dgram->source_name.name);
+ /* For a LanMan host announce the workgroup name is the destination name. */
+ pull_ascii_nstring(work_name,sizeof(work_name),dgram->dest_name.name);
+
+ DEBUG(3,("process_lm_host_announce: LM Announcement from %s IP %s to \
+%s for server %s.\n", nmb_namestr(&dgram->source_name), inet_ntoa(p->ip),
+ nmb_namestr(&dgram->dest_name),announce_name));
+
+ DEBUG(5,("process_lm_host_announce: os=(%d,%d) ttl=%d server type=%08x comment=%s\n",
+ osmajor, osminor, ttl, servertype,comment));
+
+ if ((osmajor < 36) || (osmajor > 38) || (osminor !=0)) {
+ DEBUG(5,("process_lm_host_announce: LM Announcement packet does not \
+originate from OS/2 Warp client. Ignoring packet.\n"));
+ /* Could have been from a Windows machine (with its LM Announce enabled),
+ or a Samba server. Then don't disrupt the current browse list. */
+ goto done;
+ }
+
+ /* Filter servertype to remove impossible bits. */
+ servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
+
+ /* A LanMan host announcement must be sent to the name WORKGROUP<00>. */
+ if(dgram->dest_name.name_type != 0x00) {
+ DEBUG(2,("process_lm_host_announce: incorrect name type for destination from IP %s \
+(was %02x) should be 0x00. Allowing packet anyway.\n",
+ inet_ntoa(p->ip), dgram->dest_name.name_type));
+ /* Change it so it was. */
+ dgram->dest_name.name_type = 0x00;
+ }
+
+ /*
+ * 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()))
+ unstrcpy(work_name,lp_workgroup());
+
+ /*
+ * We are being very agressive here in adding a workgroup
+ * name on the basis of a host announcing itself as being
+ * in that workgroup. Maybe we should wait for the workgroup
+ * announce instead ? JRA.
+ */
+
+ work = find_workgroup_on_subnet(subrec, work_name);
+
+ if(servertype != 0) {
+ if (work == NULL) {
+ /* We have no record of this workgroup. Add it. */
+ if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
+ goto done;
+ }
+
+ if((servrec = find_server_in_workgroup( work, announce_name))==NULL) {
+ /* If this server is not already in the workgroup, add it. */
+ create_server_on_workgroup(work, announce_name,
+ servertype|SV_TYPE_LOCAL_LIST_ONLY,
+ ttl, comment);
+ } else {
+ /* Update the record. */
+ servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
+ update_server_ttl( servrec, ttl);
+ fstrcpy(servrec->serv.comment,comment);
+ }
+ } else {
+ /*
+ * This server is announcing it is going down. Remove it from the
+ * workgroup.
+ */
+ if(!is_myname(announce_name) && (work != NULL) &&
+ ((servrec = find_server_in_workgroup( work, announce_name))!=NULL)) {
+ remove_server_from_workgroup( work, servrec);
+ }
+ }
+
+ subrec->work_changed = True;
+ found_lm_clients = True;
+
+done:
+
+ END_PROFILE(lm_host_announce);
+}
+
+/****************************************************************************
+ Send a backup list response.
+*****************************************************************************/
+
+static void send_backup_list_response(struct subnet_record *subrec,
+ struct work_record *work,
+ struct nmb_name *send_to_name,
+ unsigned char max_number_requested,
+ uint32 token, struct in_addr sendto_ip,
+ int port)
+{
+ char outbuf[1024];
+ char *p, *countptr;
+ unsigned int count = 0;
+ unstring send_to_namestr;
+#if 0
+ struct server_record *servrec;
+#endif
+ unstring myname;
+
+ memset(outbuf,'\0',sizeof(outbuf));
+
+ DEBUG(3,("send_backup_list_response: sending backup list for workgroup %s to %s IP %s\n",
+ work->work_group, nmb_namestr(send_to_name), inet_ntoa(sendto_ip)));
+
+ p = outbuf;
+
+ SCVAL(p,0,ANN_GetBackupListResp); /* Backup list response opcode. */
+ p++;
+
+ countptr = p;
+ p++;
+
+ SIVAL(p,0,token); /* The sender's unique info. */
+ p += 4;
+
+ /* We always return at least one name - our own. */
+ count = 1;
+ unstrcpy(myname, global_myname());
+ strupper_m(myname);
+ myname[15]='\0';
+ push_ascii(p, myname, sizeof(outbuf)-PTR_DIFF(p,outbuf)-1, STR_TERMINATE);
+
+ p = skip_string(outbuf,sizeof(outbuf),p);
+
+ /* Look for backup browsers in this workgroup. */
+
+#if 0
+ /* we don't currently send become_backup requests so we should never
+ send any other servers names out as backups for our
+ workgroup. That's why this is commented out (tridge) */
+
+ /*
+ * NB. Note that the struct work_record here is not neccessarily
+ * attached to the subnet *subrec.
+ */
+
+ for (servrec = work->serverlist; servrec; servrec = servrec->next)
+ {
+ int len = PTR_DIFF(p, outbuf);
+ if((sizeof(outbuf) - len) < 16)
+ break;
+
+ if(count >= (unsigned int)max_number_requested)
+ break;
+
+ if(strnequal(servrec->serv.name, global_myname(),15))
+ continue;
+
+ if(!(servrec->serv.type & SV_TYPE_BACKUP_BROWSER))
+ continue;
+
+ StrnCpy(p, servrec->serv.name, 15);
+ strupper_m(p);
+ count++;
+
+ DEBUG(5,("send_backup_list_response: Adding server %s number %d\n",
+ p, count));
+
+ p = skip_string(outbuf,sizeof(outbuf),p);
+ }
+#endif
+
+ SCVAL(countptr, 0, count);
+
+ pull_ascii_nstring(send_to_namestr, sizeof(send_to_namestr), send_to_name->name);
+
+ DEBUG(4,("send_backup_list_response: sending response to %s<00> IP %s with %d servers.\n",
+ send_to_namestr, inet_ntoa(sendto_ip), count));
+
+ send_mailslot(True, BROWSE_MAILSLOT,
+ outbuf,PTR_DIFF(p,outbuf),
+ global_myname(), 0,
+ send_to_namestr,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;
+ unstring workgroup_name;
+ struct subnet_record *search_subrec = subrec;
+
+ START_PROFILE(get_backup_list);
+ pull_ascii_nstring(workgroup_name, sizeof(workgroup_name), dgram->dest_name.name);
+
+ DEBUG(3,("process_get_backup_list_request: request from %s IP %s to %s.\n",
+ nmb_namestr(&dgram->source_name), inet_ntoa(p->ip),
+ nmb_namestr(&dgram->dest_name)));
+
+ /* We have to be a master browser, or a domain master browser
+ for the requested workgroup. That means it must be our
+ workgroup. */
+
+ if(strequal(workgroup_name, lp_workgroup()) == False) {
+ DEBUG(7,("process_get_backup_list_request: Ignoring announce request for workgroup %s.\n",
+ workgroup_name));
+ goto done;
+ }
+
+ if((work = find_workgroup_on_subnet(search_subrec, workgroup_name)) == NULL) {
+ DEBUG(0,("process_get_backup_list_request: Cannot find workgroup %s on \
+subnet %s.\n", workgroup_name, search_subrec->subnet_name));
+ goto done;
+ }
+
+ /*
+ * If the packet was sent to WORKGROUP<1b> instead
+ * of WORKGROUP<1d> then it was unicast to us a domain master
+ * browser. Change search subrec to unicast.
+ */
+
+ if(name_type == 0x1b) {
+ /* We must be a domain master browser in order to
+ process this packet. */
+
+ if(!AM_DOMAIN_MASTER_BROWSER(work)) {
+ DEBUG(0,("process_get_backup_list_request: domain list requested for workgroup %s \
+and I am not a domain master browser.\n", workgroup_name));
+ goto done;
+ }
+
+ search_subrec = unicast_subnet;
+ } else if (name_type == 0x1d) {
+ /* We must be a local master browser in order to process this packet. */
+
+ if(!AM_LOCAL_MASTER_BROWSER(work)) {
+ DEBUG(0,("process_get_backup_list_request: domain list requested for workgroup %s \
+and I am not a local master browser.\n", workgroup_name));
+ goto done;
+ }
+ } else {
+ DEBUG(0,("process_get_backup_list_request: Invalid name type %x - should be 0x1b or 0x1d.\n",
+ name_type));
+ goto done;
+ }
+
+ send_backup_list_response(subrec, work, &dgram->source_name,
+ max_number_requested, token, p->ip, p->port);
+
+done:
+
+ END_PROFILE(get_backup_list);
+}
+
+/*******************************************************************
+ Process a reset browser state packet.
+
+ Diagnostic packet:
+ 0x1 - Stop being a master browser and become a backup browser.
+ 0x2 - Discard browse lists, stop being a master browser, try again.
+ 0x4 - Stop being a master browser forever.
+
+******************************************************************/
+
+void process_reset_browser(struct subnet_record *subrec,
+ struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int state = CVAL(buf,0);
+ struct subnet_record *sr;
+
+ START_PROFILE(reset_browser);
+
+ DEBUG(1,("process_reset_browser: received diagnostic browser reset \
+request from %s IP %s state=0x%X\n",
+ nmb_namestr(&dgram->source_name), inet_ntoa(p->ip), state));
+
+ /* Stop being a local master browser on all our broadcast subnets. */
+ if (state & 0x1) {
+ for (sr = FIRST_SUBNET; sr; sr = NEXT_SUBNET_EXCLUDING_UNICAST(sr)) {
+ struct work_record *work;
+ for (work = sr->workgrouplist; work; work = work->next) {
+ if (AM_LOCAL_MASTER_BROWSER(work))
+ unbecome_local_master_browser(sr, work, True);
+ }
+ }
+ }
+
+ /* Discard our browse lists. */
+ if (state & 0x2) {
+ /*
+ * Calling expire_workgroups_and_servers with a -1
+ * time causes all servers not marked with a PERMANENT_TTL
+ * on the workgroup lists to be discarded, and all
+ * workgroups with empty server lists to be discarded.
+ * This means we keep our own server names and workgroup
+ * as these have a PERMANENT_TTL.
+ */
+
+ expire_workgroups_and_servers(-1);
+ }
+
+ /* Request to stop browsing altogether. */
+ if (state & 0x4)
+ DEBUG(1,("process_reset_browser: ignoring request to stop being a browser.\n"));
+
+ END_PROFILE(reset_browser);
+}
+
+/*******************************************************************
+ Process an announcement request packet.
+ We don't respond immediately, we just check it's a request for
+ our workgroup and then set the flag telling the announce code
+ in nmbd_sendannounce.c:announce_my_server_names that an
+ announcement is needed soon.
+******************************************************************/
+
+void process_announce_request(struct subnet_record *subrec, struct packet_struct *p, char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct work_record *work;
+ unstring workgroup_name;
+
+ START_PROFILE(announce_request);
+
+ pull_ascii_nstring(workgroup_name, sizeof(workgroup_name), dgram->dest_name.name);
+ DEBUG(3,("process_announce_request: Announce request from %s IP %s to %s.\n",
+ nmb_namestr(&dgram->source_name), inet_ntoa(p->ip),
+ nmb_namestr(&dgram->dest_name)));
+
+ /* We only send announcement requests on our workgroup. */
+ if(strequal(workgroup_name, lp_workgroup()) == False) {
+ DEBUG(7,("process_announce_request: Ignoring announce request for workgroup %s.\n",
+ workgroup_name));
+ goto done;
+ }
+
+ if((work = find_workgroup_on_subnet(subrec, workgroup_name)) == NULL) {
+ DEBUG(0,("process_announce_request: Unable to find workgroup %s on subnet !\n",
+ workgroup_name));
+ goto done;
+ }
+
+ work->needannounce = True;
+done:
+
+ END_PROFILE(announce_request);
+}
+
+/*******************************************************************
+ 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, int len)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ unstring workgroup_name;
+
+ START_PROFILE(lm_announce_request);
+
+ pull_ascii_nstring(workgroup_name, sizeof(workgroup_name), dgram->dest_name.name);
+ DEBUG(3,("process_lm_announce_request: Announce request from %s IP %s to %s.\n",
+ nmb_namestr(&dgram->source_name), inet_ntoa(p->ip),
+ nmb_namestr(&dgram->dest_name)));
+
+ /* We only send announcement requests on our workgroup. */
+ if(strequal(workgroup_name, lp_workgroup()) == False) {
+ DEBUG(7,("process_lm_announce_request: Ignoring announce request for workgroup %s.\n",
+ workgroup_name));
+ goto done;
+ }
+
+ if(find_workgroup_on_subnet(subrec, workgroup_name) == NULL) {
+ DEBUG(0,("process_announce_request: Unable to find workgroup %s on subnet !\n",
+ workgroup_name));
+ goto done;
+ }
+
+ found_lm_clients = True;
+
+done:
+
+ END_PROFILE(lm_announce_request);
+}
diff --git a/source3/nmbd/nmbd_incomingrequests.c b/source3/nmbd/nmbd_incomingrequests.c
new file mode 100644
index 0000000000..ebe1948141
--- /dev/null
+++ b/source3/nmbd/nmbd_incomingrequests.c
@@ -0,0 +1,586 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ 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"
+
+/****************************************************************************
+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;
+ unstring qname;
+ bool bcast = nmb->header.nm_flags.bcast;
+ uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+ bool group = (nb_flags & NB_GROUP) ? True : False;
+ struct name_record *namerec;
+ int rcode = 0;
+
+ putip((char *)&owner_ip,&nmb->additional->rdata[2]);
+
+ if(!bcast) {
+ /* We should only get broadcast name release packets here.
+ Anyone trying to release unicast should be going to a WINS
+ server. If the code gets here, then either we are not a wins
+ server and they sent it anyway, or we are a WINS server and
+ the request was malformed. Either way, log an error here.
+ and send an error reply back.
+ */
+ DEBUG(0,("process_name_release_request: unicast name release request \
+received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
+ nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name));
+
+ send_name_release_response(FMT_ERR, p);
+ return;
+ }
+
+ DEBUG(3,("process_name_release_request: Name release on name %s, \
+subnet %s from owner IP %s\n",
+ nmb_namestr(&nmb->question.question_name),
+ subrec->subnet_name, inet_ntoa(owner_ip)));
+
+ /* If someone is releasing a broadcast group name, just ignore it. */
+ if( group && !ismyip_v4(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* !!!!!
+ */
+
+ pull_ascii_nstring(qname, sizeof(qname), question->name);
+ if( !group && !ismyip_v4(owner_ip) && strequal(qname, lp_workgroup()) &&
+ ((question->name_type == 0x0) || (question->name_type == 0x1e))) {
+ DEBUG(6,("process_name_release_request: FTP OnNet bug workaround. Ignoring \
+group release name %s from IP %s on subnet %s with no group bit set.\n",
+ nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name ));
+ return;
+ }
+
+ namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+ /* We only care about someone trying to release one of our names. */
+ if( namerec && ( (namerec->data.source == SELF_NAME)
+ || (namerec->data.source == PERMANENT_NAME) ) ) {
+ rcode = ACT_ERR;
+ DEBUG(0, ("process_name_release_request: Attempt to release name %s from IP %s \
+on subnet %s being rejected as it is one of our names.\n",
+ nmb_namestr(&nmb->question.question_name), inet_ntoa(owner_ip), subrec->subnet_name));
+ }
+
+ if(rcode == 0)
+ return;
+
+ /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
+ send_name_release_response(rcode, p);
+}
+
+/****************************************************************************
+Send a name registration response.
+**************************************************************************/
+
+static void send_name_registration_response(int rcode, int ttl, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ char rdata[6];
+
+ memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
+
+ reply_netbios_packet(p, /* Packet to reply to. */
+ rcode, /* Result code. */
+ NMB_REG, /* nmbd type code. */
+ NMB_NAME_REG_OPCODE, /* opcode. */
+ ttl, /* ttl. */
+ rdata, /* data to send. */
+ 6); /* data length. */
+}
+
+/****************************************************************************
+Process a name refresh request on a broadcast subnet.
+**************************************************************************/
+
+void process_name_refresh_request(struct subnet_record *subrec,
+ struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ bool bcast = nmb->header.nm_flags.bcast;
+ struct in_addr from_ip;
+
+ putip((char *)&from_ip,&nmb->additional->rdata[2]);
+
+ if(!bcast) {
+ /* We should only get broadcast name refresh packets here.
+ Anyone trying to refresh unicast should be going to a WINS
+ server. If the code gets here, then either we are not a wins
+ server and they sent it anyway, or we are a WINS server and
+ the request was malformed. Either way, log an error here.
+ and send an error reply back.
+ */
+ DEBUG(0,("process_name_refresh_request: unicast name registration request \
+received for name %s from IP %s on subnet %s.\n",
+ nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+ DEBUG(0,("Error - should be sent to WINS server\n"));
+
+ send_name_registration_response(FMT_ERR, 0, p);
+ return;
+ }
+
+ /* Just log a message. We really don't care about broadcast name refreshes. */
+
+ DEBUG(3,("process_name_refresh_request: Name refresh for name %s \
+IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+}
+
+/****************************************************************************
+Process a name registration request on a broadcast subnet.
+**************************************************************************/
+
+void process_name_registration_request(struct subnet_record *subrec,
+ struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ bool bcast = nmb->header.nm_flags.bcast;
+ uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+ bool group = (nb_flags & NB_GROUP) ? True : False;
+ struct name_record *namerec = NULL;
+ int ttl = nmb->additional->ttl;
+ struct in_addr from_ip;
+
+ putip((char *)&from_ip,&nmb->additional->rdata[2]);
+
+ if(!bcast) {
+ /* We should only get broadcast name registration packets here.
+ Anyone trying to register unicast should be going to a WINS
+ server. If the code gets here, then either we are not a wins
+ server and they sent it anyway, or we are a WINS server and
+ the request was malformed. Either way, log an error here.
+ and send an error reply back.
+ */
+ DEBUG(0,("process_name_registration_request: unicast name registration request \
+received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
+ nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+
+ send_name_registration_response(FMT_ERR, 0, p);
+ return;
+ }
+
+ DEBUG(3,("process_name_registration_request: Name registration for name %s \
+IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+
+ /* See if the name already exists. */
+ namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+ /*
+ * If the name being registered exists and is a WINS_PROXY_NAME
+ * then delete the WINS proxy name entry so we don't reply erroneously
+ * later to queries.
+ */
+
+ if((namerec != NULL) && (namerec->data.source == WINS_PROXY_NAME)) {
+ remove_name_from_namelist( subrec, namerec );
+ namerec = NULL;
+ }
+
+ if (!group) {
+ /* Unique name. */
+
+ if( (namerec != NULL)
+ && ( (namerec->data.source == SELF_NAME)
+ || (namerec->data.source == PERMANENT_NAME)
+ || NAME_GROUP(namerec) ) ) {
+ /* No-one can register one of Samba's names, nor can they
+ register a name that's a group name as a unique name */
+
+ send_name_registration_response(ACT_ERR, 0, p);
+ return;
+ } else if(namerec != NULL) {
+ /* Update the namelist record with the new information. */
+ namerec->data.ip[0] = from_ip;
+ update_name_ttl(namerec, ttl);
+
+ DEBUG(3,("process_name_registration_request: Updated name record %s \
+with IP %s on subnet %s\n",nmb_namestr(&namerec->name),inet_ntoa(from_ip), subrec->subnet_name));
+ return;
+ }
+ } else {
+ /* Group name. */
+
+ if( (namerec != NULL)
+ && !NAME_GROUP(namerec)
+ && ( (namerec->data.source == SELF_NAME)
+ || (namerec->data.source == PERMANENT_NAME) ) ) {
+ /* Disallow group names when we have a unique name. */
+ send_name_registration_response(ACT_ERR, 0, p);
+ return;
+ }
+ }
+}
+
+/****************************************************************************
+This is used to sort names for a name status into a sensible order.
+We put our own names first, then in alphabetical order.
+**************************************************************************/
+
+static int status_compare(char *n1,char *n2)
+{
+ unstring name1, name2;
+ int l1,l2,l3;
+
+ memset(name1, '\0', sizeof(name1));
+ memset(name2, '\0', sizeof(name2));
+ pull_ascii_nstring(name1, sizeof(name1), n1);
+ pull_ascii_nstring(name2, sizeof(name2), n2);
+ n1 = name1;
+ n2 = name2;
+
+ /* 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,sizeof(name1));
+}
+
+/****************************************************************************
+ 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;
+ unstring qname;
+ 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;
+
+ pull_ascii_nstring(qname, sizeof(qname), nmb->question.question_name.name);
+
+ DEBUG(3,("process_node_status_request: status request for name %s from IP %s on \
+subnet %s.\n", nmb_namestr(&nmb->question.question_name), inet_ntoa(p->ip), subrec->subnet_name));
+
+ if((namerec = find_name_on_subnet(subrec, &nmb->question.question_name, FIND_SELF_NAME)) == 0) {
+ DEBUG(1,("process_node_status_request: status request for name %s from IP %s on \
+subnet %s - name not found.\n", nmb_namestr(&nmb->question.question_name),
+ inet_ntoa(p->ip), subrec->subnet_name));
+
+ return;
+ }
+
+ /* this is not an exact calculation. the 46 is for the stats buffer
+ and the 60 is to leave room for the header etc */
+ bufend = &rdata[MAX_DGRAM_SIZE-1] - (18 + 46 + 60);
+ countptr = buf = rdata;
+ buf += 1;
+ buf0 = buf;
+
+ names_added = 0;
+
+ namerec = subrec->namelist;
+
+ while (buf < bufend) {
+ if( (namerec->data.source == SELF_NAME) || (namerec->data.source == PERMANENT_NAME) ) {
+ int name_type = namerec->name.name_type;
+ unstring name;
+
+ pull_ascii_nstring(name, sizeof(name), namerec->name.name);
+ strupper_m(name);
+ if (!strequal(name,"*") &&
+ !strequal(name,"__SAMBA__") &&
+ (name_type < 0x1b || name_type >= 0x20 ||
+ ques_type < 0x1b || ques_type >= 0x20 ||
+ strequal(qname, name))) {
+ /* Start with the name. */
+ size_t len;
+ push_ascii_nstring(buf, name);
+ len = strlen(buf);
+ memset(buf + len, ' ', MAX_NETBIOSNAME_LEN - len - 1);
+ buf[MAX_NETBIOSNAME_LEN - 1] = '\0';
+
+ /* Put the name type and netbios flags in the buffer. */
+
+ buf[15] = name_type;
+ set_nb_flags( &buf[16],namerec->data.nb_flags );
+ buf[16] |= NB_ACTIVE; /* all our names are active */
+
+ buf += 18;
+
+ names_added++;
+ }
+ }
+
+ /* Remove duplicate names. */
+ if (names_added > 1) {
+ qsort( buf0, names_added, 18, QSORT_CAST status_compare );
+ }
+
+ for( i=1; i < names_added ; i++ ) {
+ if (memcmp(buf0 + 18*i,buf0 + 18*(i-1),16) == 0) {
+ names_added--;
+ if (names_added == i)
+ break;
+ memmove(buf0 + 18*i,buf0 + 18*(i+1),18*(names_added-i));
+ i--;
+ }
+ }
+
+ buf = buf0 + 18*names_added;
+
+ namerec = namerec->next;
+
+ 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 = subrec->namelist;
+ }
+ }
+ if (!namerec)
+ break;
+
+ }
+
+ SCVAL(countptr,0,names_added);
+
+ /* We don't send any stats as they could be used to attack
+ the protocol. */
+ memset(buf,'\0',46);
+
+ buf += 46;
+
+ /* Send a NODE STATUS RESPONSE */
+ reply_netbios_packet(p, /* Packet to reply to. */
+ 0, /* Result code. */
+ NMB_STATUS, /* nmbd type code. */
+ NMB_NAME_QUERY_OPCODE, /* opcode. */
+ 0, /* ttl. */
+ rdata, /* data to send. */
+ PTR_DIFF(buf,rdata)); /* data length. */
+}
+
+
+/***************************************************************************
+Process a name query.
+
+For broadcast name queries:
+
+ - Only reply if the query is for one of YOUR names.
+ - NEVER send a negative response to a broadcast query.
+
+****************************************************************************/
+
+void process_name_query_request(struct subnet_record *subrec, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ int name_type = question->name_type;
+ bool bcast = nmb->header.nm_flags.bcast;
+ int ttl=0;
+ int rcode = 0;
+ char *prdata = NULL;
+ char rdata[6];
+ bool success = False;
+ struct name_record *namerec = NULL;
+ int reply_data_len = 0;
+ int i;
+
+ DEBUG(3,("process_name_query_request: Name query from %s on subnet %s for name %s\n",
+ inet_ntoa(p->ip), subrec->subnet_name, nmb_namestr(question)));
+
+ /* Look up the name in the cache - if the request is a broadcast request that
+ came from a subnet we don't know about then search all the broadcast subnets
+ for a match (as we don't know what interface the request came in on). */
+
+ if(subrec == remote_broadcast_subnet)
+ namerec = find_name_for_remote_broadcast_subnet( question, FIND_ANY_NAME);
+ else
+ namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+ /* Check if it is a name that expired */
+ if (namerec &&
+ ((namerec->data.death_time != PERMANENT_TTL) &&
+ (namerec->data.death_time < p->timestamp))) {
+ DEBUG(5,("process_name_query_request: expired name %s\n", nmb_namestr(&namerec->name)));
+ namerec = NULL;
+ }
+
+ if (namerec) {
+ /*
+ * Always respond to unicast queries.
+ * Don't respond to broadcast queries unless the query is for
+ * a name we own, a Primary Domain Controller name, or a WINS_PROXY
+ * name with type 0 or 0x20. WINS_PROXY names are only ever added
+ * into the namelist if we were configured as a WINS proxy.
+ */
+
+ if (!bcast ||
+ (bcast && ((name_type == 0x1b) ||
+ (namerec->data.source == SELF_NAME) ||
+ (namerec->data.source == PERMANENT_NAME) ||
+ ((namerec->data.source == WINS_PROXY_NAME) &&
+ ((name_type == 0) || (name_type == 0x20)))))) {
+ /* The requested name is a directed query, or it's SELF or PERMANENT or WINS_PROXY,
+ or it's a Domain Master type. */
+
+ /*
+ * If this is a WINS_PROXY_NAME, then ceck that none of the IP
+ * addresses we are returning is on the same broadcast subnet
+ * as the requesting packet. If it is then don't reply as the
+ * actual machine will be replying also and we don't want two
+ * replies to a broadcast query.
+ */
+
+ if (namerec->data.source == WINS_PROXY_NAME) {
+ for( i = 0; i < namerec->data.num_ips; i++) {
+ if (same_net_v4(namerec->data.ip[i], subrec->myip, subrec->mask_ip)) {
+ DEBUG(5,("process_name_query_request: name %s is a WINS proxy name and is also on the same subnet (%s) as the requestor. Not replying.\n",
+ nmb_namestr(&namerec->name), subrec->subnet_name ));
+ return;
+ }
+ }
+ }
+
+ ttl = (namerec->data.death_time != PERMANENT_TTL) ?
+ namerec->data.death_time - p->timestamp : lp_max_ttl();
+
+ /* Copy all known ip addresses into the return data. */
+ /* Optimise for the common case of one IP address so
+ we don't need a malloc. */
+
+ if (namerec->data.num_ips == 1) {
+ prdata = rdata;
+ } else {
+ if ((prdata = (char *)SMB_MALLOC( namerec->data.num_ips * 6 )) == NULL) {
+ DEBUG(0,("process_name_query_request: malloc fail !\n"));
+ return;
+ }
+ }
+
+ for (i = 0; i < namerec->data.num_ips; i++) {
+ set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
+ putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
+ }
+
+ sort_query_replies(prdata, i, p->ip);
+
+ reply_data_len = namerec->data.num_ips * 6;
+ success = True;
+ }
+ }
+
+ /*
+ * If a machine is broadcasting a name lookup request and we have lp_wins_proxy()
+ * set we should initiate a WINS query here. On success we add the resolved name
+ * into our namelist with a type of WINS_PROXY_NAME and then reply to the query.
+ */
+
+ if(!success && (namerec == NULL) && we_are_a_wins_client() && lp_wins_proxy() &&
+ bcast && (subrec != remote_broadcast_subnet)) {
+ make_wins_proxy_name_query_request( subrec, p, question );
+ return;
+ }
+
+ if (!success && bcast) {
+ if(prdata != rdata)
+ SAFE_FREE(prdata);
+ return; /* Never reply with a negative response to broadcasts. */
+ }
+
+ /*
+ * Final check. From observation, if a unicast packet is sent
+ * to a non-WINS server with the recursion desired bit set
+ * then never send a negative response.
+ */
+
+ if(!success && !bcast && nmb->header.nm_flags.recursion_desired) {
+ if(prdata != rdata)
+ SAFE_FREE(prdata);
+ return;
+ }
+
+ if (success) {
+ rcode = 0;
+ DEBUG(3,("OK\n"));
+ } else {
+ rcode = NAM_ERR;
+ DEBUG(3,("UNKNOWN\n"));
+ }
+
+ /* See rfc1002.txt 4.2.13. */
+
+ reply_netbios_packet(p, /* Packet to reply to. */
+ rcode, /* Result code. */
+ NMB_QUERY, /* nmbd type code. */
+ NMB_NAME_QUERY_OPCODE, /* opcode. */
+ ttl, /* ttl. */
+ prdata, /* data to send. */
+ reply_data_len); /* data length. */
+
+ if(prdata != rdata)
+ SAFE_FREE(prdata);
+}
diff --git a/source3/nmbd/nmbd_lmhosts.c b/source3/nmbd/nmbd_lmhosts.c
new file mode 100644
index 0000000000..75c03bb398
--- /dev/null
+++ b/source3/nmbd/nmbd_lmhosts.c
@@ -0,0 +1,103 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Revision History:
+
+ Handle lmhosts file reading.
+
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+Load a lmhosts file.
+****************************************************************************/
+
+void load_lmhosts_file(const char *fname)
+{
+ char *name = NULL;
+ int name_type;
+ struct sockaddr_storage ss;
+ TALLOC_CTX *ctx = talloc_init("load_lmhosts_file");
+ XFILE *fp = startlmhosts( fname );
+
+ if (!fp) {
+ DEBUG(2,("load_lmhosts_file: Can't open lmhosts file %s. Error was %s\n",
+ fname, strerror(errno)));
+ TALLOC_FREE(ctx);
+ return;
+ }
+
+ while (getlmhostsent(ctx, fp, &name, &name_type, &ss) ) {
+ struct in_addr ipaddr;
+ struct subnet_record *subrec = NULL;
+ enum name_source source = LMHOSTS_NAME;
+
+ if (ss.ss_family != AF_INET) {
+ TALLOC_FREE(name);
+ continue;
+ }
+
+ ipaddr = ((struct sockaddr_in *)&ss)->sin_addr;
+
+ /* 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_v4(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);
+ }
+ }
+
+ TALLOC_FREE(ctx);
+ 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/source3/nmbd/nmbd_logonnames.c b/source3/nmbd/nmbd_logonnames.c
new file mode 100644
index 0000000000..f0350af3b8
--- /dev/null
+++ b/source3/nmbd/nmbd_logonnames.c
@@ -0,0 +1,170 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+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)
+{
+ unstring failname;
+ struct work_record *work;
+ struct server_record *servrec;
+
+ pull_ascii_nstring(failname, sizeof(failname), fail_name->name);
+ work = find_workgroup_on_subnet(subrec, failname);
+ if(!work) {
+ DEBUG(0,("become_logon_server_fail: Error - cannot find \
+workgroup %s on subnet %s\n", failname, 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(), failname, subrec->subnet_name));
+ work->log_state = LOGON_NONE;
+ return;
+ }
+
+ /* Set the state back to LOGON_NONE. */
+ work->log_state = LOGON_NONE;
+
+ servrec->serv.type &= ~SV_TYPE_DOMAIN_CTRL;
+
+ DEBUG(0,("become_logon_server_fail: Failed to become a domain master for \
+workgroup %s on subnet %s. Couldn't register name %s.\n",
+ work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
+
+}
+
+/****************************************************************************
+ Become a Logon server on a subnet.
+ ****************************************************************************/
+
+static void become_logon_server_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *registered_name,
+ uint16 nb_flags,
+ int ttl, struct in_addr registered_ip)
+{
+ unstring reg_name;
+ struct work_record *work;
+ struct server_record *servrec;
+
+ pull_ascii_nstring(reg_name, sizeof(reg_name), registered_name->name);
+ work = find_workgroup_on_subnet( subrec, reg_name);
+ if(!work) {
+ DEBUG(0,("become_logon_server_success: Error - cannot find \
+workgroup %s on subnet %s\n", reg_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(), reg_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;
+
+ /*
+ * Add the WORKGROUP<1C> name to the UNICAST subnet with the IP address
+ * for this subnet so we will respond to queries on this name.
+ */
+
+ {
+ struct nmb_name nmbname;
+ make_nmb_name(&nmbname,lp_workgroup(),0x1c);
+ insert_permanent_name_into_unicast(subrec, &nmbname, 0x1c);
+ }
+
+ 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, lp_workgroup());
+
+ if (work && (work->log_state == LOGON_NONE)) {
+ struct nmb_name nmbname;
+ make_nmb_name(&nmbname,lp_workgroup(),0x1c);
+
+ if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "add_domain_logon_names:\n" );
+ dbgtext( "Attempting to become logon server " );
+ dbgtext( "for workgroup %s ", lp_workgroup() );
+ dbgtext( "on subnet %s\n", subrec->subnet_name );
+ }
+ become_logon_server(subrec, work);
+ }
+ }
+ }
+}
diff --git a/source3/nmbd/nmbd_mynames.c b/source3/nmbd/nmbd_mynames.c
new file mode 100644
index 0000000000..62c8dd0cf0
--- /dev/null
+++ b/source3/nmbd/nmbd_mynames.c
@@ -0,0 +1,252 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
+
+/****************************************************************************
+ Fail funtion when registering my netbios names.
+**************************************************************************/
+
+static void my_name_register_failed(struct subnet_record *subrec,
+ struct response_record *rrec, struct nmb_name *nmbname)
+{
+ DEBUG(0,("my_name_register_failed: Failed to register my name %s on subnet %s.\n",
+ nmb_namestr(nmbname), subrec->subnet_name));
+}
+
+
+/****************************************************************************
+ Add my workgroup and my given names to one subnet
+ Also add the magic Samba names.
+**************************************************************************/
+
+void register_my_workgroup_one_subnet(struct subnet_record *subrec)
+{
+ int i;
+
+ struct work_record *work;
+
+ /* Create the workgroup on the subnet. */
+ if((work = create_workgroup_on_subnet(subrec, lp_workgroup(),
+ PERMANENT_TTL)) == NULL) {
+ DEBUG(0,("register_my_workgroup_and_names: Failed to create my workgroup %s on subnet %s. \
+Exiting.\n", lp_workgroup(), subrec->subnet_name));
+ return;
+ }
+
+ /* Each subnet entry, except for the wins_server_subnet has
+ the magic Samba names. */
+ add_samba_names_to_subnet(subrec);
+
+ /* Register all our names including aliases. */
+ for (i=0; my_netbios_names(i); i++) {
+ register_name(subrec, my_netbios_names(i),0x20,samba_nb_type,
+ NULL,
+ my_name_register_failed, NULL);
+ register_name(subrec, my_netbios_names(i),0x03,samba_nb_type,
+ NULL,
+ my_name_register_failed, NULL);
+ register_name(subrec, my_netbios_names(i),0x00,samba_nb_type,
+ NULL,
+ my_name_register_failed, NULL);
+ }
+
+ /* Initiate election processing, register the workgroup names etc. */
+ initiate_myworkgroup_startup(subrec, work);
+}
+
+/*******************************************************************
+ Utility function to add a name to the unicast subnet, or add in
+ our IP address if it already exists.
+******************************************************************/
+
+static void insert_refresh_name_into_unicast( struct subnet_record *subrec,
+ struct nmb_name *nmbname, uint16 nb_type )
+{
+ struct name_record *namerec;
+
+ if (!we_are_a_wins_client()) {
+ insert_permanent_name_into_unicast(subrec, nmbname, nb_type);
+ return;
+ }
+
+ if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) == NULL) {
+ unstring name;
+ pull_ascii_nstring(name, sizeof(name), nmbname->name);
+ /* The name needs to be created on the unicast subnet. */
+ (void)add_name_to_subnet( unicast_subnet, name,
+ nmbname->name_type, nb_type,
+ MIN(lp_max_ttl(), MAX_REFRESH_TIME), SELF_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);
+ }
+}
+
+/****************************************************************************
+ Add my workgroup and my given names to the subnet lists.
+ Also add the magic Samba names.
+**************************************************************************/
+
+bool register_my_workgroup_and_names(void)
+{
+ struct subnet_record *subrec;
+ int i;
+ const char **cluster_addresses = NULL;
+
+ for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
+ register_my_workgroup_one_subnet(subrec);
+ }
+
+ /* 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. */
+
+ add_samba_names_to_subnet(unicast_subnet);
+
+ for (i=0; my_netbios_names(i); i++) {
+ for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+ /*
+ * Ensure all the IP addresses are added if we are multihomed.
+ */
+ struct nmb_name nmbname;
+
+ make_nmb_name(&nmbname, my_netbios_names(i),0x20);
+ insert_refresh_name_into_unicast(subrec, &nmbname, samba_nb_type);
+
+ make_nmb_name(&nmbname, my_netbios_names(i),0x3);
+ insert_refresh_name_into_unicast(subrec, &nmbname, samba_nb_type);
+
+ make_nmb_name(&nmbname, my_netbios_names(i),0x0);
+ insert_refresh_name_into_unicast(subrec, &nmbname, samba_nb_type);
+ }
+ }
+
+ /*
+ * add in any cluster addresses. We need to response to these,
+ * but not listen on them. This allows us to run nmbd on every
+ * node in the cluster, and have all of them register with a
+ * WINS server correctly
+ */
+ if (lp_clustering()) {
+ cluster_addresses = lp_cluster_addresses();
+ }
+ if (cluster_addresses) {
+ int a, n;
+ unsigned name_types[] = {0x20, 0x3, 0x0};
+
+ for (i=0; my_netbios_names(i); i++) {
+ for(subrec = FIRST_SUBNET; subrec; subrec = subrec->next) {
+ for (n=0;n<ARRAY_SIZE(name_types);n++) {
+ struct name_record *namerec;
+ struct nmb_name nmbname;
+ struct in_addr ip;
+ make_nmb_name(&nmbname, my_netbios_names(i), name_types[n]);
+ namerec = find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME);
+ if (namerec == NULL) continue;
+ for (a=0;cluster_addresses[a];a++) {
+ add_ip_to_name_record(namerec, *interpret_addr2(&ip, cluster_addresses[a]));
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * 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, lp_workgroup(), 0x0);
+ insert_refresh_name_into_unicast(subrec, &nmbname, samba_nb_type|NB_GROUP);
+
+ make_nmb_name(&nmbname, lp_workgroup(), 0x1e);
+ insert_refresh_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_wins_names(void)
+{
+ struct subnet_record *subrec = unicast_subnet;
+ struct name_record *namerec, *nextnamerec;
+
+ for (namerec = subrec->namelist; namerec; namerec = nextnamerec) {
+ nextnamerec = namerec->next;
+ if( (namerec->data.source == SELF_NAME)
+ && !NAME_IS_DEREGISTERING(namerec) )
+ release_name( subrec, namerec, standard_success_release,
+ NULL, NULL);
+ }
+}
+
+/*******************************************************************
+ Refresh our registered names with WINS
+******************************************************************/
+
+void refresh_my_names(time_t t)
+{
+ struct name_record *namerec;
+
+ if (wins_srv_count() < 1)
+ return;
+
+ for (namerec = unicast_subnet->namelist; namerec; namerec = namerec->next) {
+ /* 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(unicast_subnet, namerec)) {
+ wins_refresh_name(namerec);
+ }
+ namerec->data.death_time = t + lp_max_ttl();
+ namerec->data.refresh_time = t + MIN(lp_max_ttl()/2, MAX_REFRESH_TIME);
+ }
+ }
+}
diff --git a/source3/nmbd/nmbd_namelistdb.c b/source3/nmbd/nmbd_namelistdb.c
new file mode 100644
index 0000000000..6570fd4ec7
--- /dev/null
+++ b/source3/nmbd/nmbd_namelistdb.c
@@ -0,0 +1,660 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+uint16 samba_nb_type = 0; /* samba's NetBIOS name type */
+
+
+/**************************************************************************
+ Set Samba's NetBIOS name type.
+***************************************************************************/
+
+void set_samba_nb_type(void)
+{
+ if( lp_wins_support() || wins_srv_count() ) {
+ samba_nb_type = NB_HFLAG; /* samba is a 'hybrid' node type. */
+ } else {
+ samba_nb_type = NB_BFLAG; /* samba is broadcast-only node type. */
+ }
+}
+
+/***************************************************************************
+ Convert a NetBIOS name to upper case.
+***************************************************************************/
+
+static void upcase_name( struct nmb_name *target, const struct nmb_name *source )
+{
+ int i;
+ unstring targ;
+ fstring scope;
+
+ if( NULL != source ) {
+ memcpy( target, source, sizeof( struct nmb_name ) );
+ }
+
+ pull_ascii_nstring(targ, sizeof(targ), target->name);
+ strupper_m( targ );
+ push_ascii_nstring( target->name, targ);
+
+ pull_ascii(scope, target->scope, 64, -1, STR_TERMINATE);
+ strupper_m( scope );
+ push_ascii(target->scope, scope, 64, STR_TERMINATE);
+
+ /* 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';
+ }
+}
+
+/**************************************************************************
+ Remove a name from the namelist.
+***************************************************************************/
+
+void remove_name_from_namelist(struct subnet_record *subrec,
+ struct name_record *namerec )
+{
+ if (subrec == wins_server_subnet)
+ remove_name_from_wins_namelist(namerec);
+ else {
+ subrec->namelist_changed = True;
+ DLIST_REMOVE(subrec->namelist, namerec);
+ }
+
+ SAFE_FREE(namerec->data.ip);
+ ZERO_STRUCTP(namerec);
+ SAFE_FREE(namerec);
+}
+
+/**************************************************************************
+ Find a name in a subnet.
+**************************************************************************/
+
+struct name_record *find_name_on_subnet(struct subnet_record *subrec,
+ const struct nmb_name *nmbname,
+ bool self_only)
+{
+ struct nmb_name uc_name;
+ struct name_record *name_ret;
+
+ upcase_name( &uc_name, nmbname );
+
+ if (subrec == wins_server_subnet) {
+ return find_name_on_wins_subnet(&uc_name, self_only);
+ }
+
+ for( name_ret = subrec->namelist; name_ret; name_ret = name_ret->next) {
+ if (memcmp(&uc_name, &name_ret->name, sizeof(struct nmb_name)) == 0) {
+ break;
+ }
+ }
+
+ if( name_ret ) {
+ /* Self names only - these include permanent names. */
+ if( self_only && (name_ret->data.source != SELF_NAME) && (name_ret->data.source != PERMANENT_NAME) ) {
+ DEBUG( 9, ( "find_name_on_subnet: on subnet %s - self name %s NOT FOUND\n",
+ subrec->subnet_name, nmb_namestr(nmbname) ) );
+ return NULL;
+ }
+
+ DEBUG( 9, ("find_name_on_subnet: on subnet %s - found name %s source=%d\n",
+ subrec->subnet_name, nmb_namestr(nmbname), name_ret->data.source) );
+
+ return name_ret;
+ }
+
+ DEBUG( 9, ( "find_name_on_subnet: on subnet %s - name %s NOT FOUND\n",
+ subrec->subnet_name, nmb_namestr(nmbname) ) );
+
+ return NULL;
+}
+
+/**************************************************************************
+ Find 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;
+
+ for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) ) {
+ namerec = find_name_on_subnet(subrec, nmbname, self_only);
+ if (namerec) {
+ return namerec;
+ }
+ }
+
+ return NULL;
+}
+
+/**************************************************************************
+ 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);
+
+ if (namerec->subnet == wins_server_subnet) {
+ wins_store_changed_namerec(namerec);
+ } else {
+ namerec->subnet->namelist_changed = True;
+ }
+}
+
+/**************************************************************************
+ Add an entry to a subnet name list.
+***********************************************************************/
+
+bool add_name_to_subnet( struct subnet_record *subrec,
+ const char *name,
+ int type,
+ uint16 nb_flags,
+ int ttl,
+ enum name_source source,
+ int num_ips,
+ struct in_addr *iplist)
+{
+ bool ret = False;
+ struct name_record *namerec;
+ time_t time_now = time(NULL);
+
+ if (num_ips == 0) {
+ return false;
+ }
+
+ namerec = SMB_MALLOC_P(struct name_record);
+ if( NULL == namerec ) {
+ DEBUG( 0, ( "add_name_to_subnet: malloc fail.\n" ) );
+ return False;
+ }
+
+ memset( (char *)namerec, '\0', sizeof(*namerec) );
+ namerec->data.ip = SMB_MALLOC_ARRAY( struct in_addr, num_ips );
+ if( NULL == namerec->data.ip ) {
+ DEBUG( 0, ( "add_name_to_subnet: malloc fail when creating ip_flgs.\n" ) );
+ ZERO_STRUCTP(namerec);
+ SAFE_FREE(namerec);
+ return False;
+ }
+
+ namerec->subnet = subrec;
+
+ make_nmb_name(&namerec->name, name, type);
+ upcase_name(&namerec->name, NULL );
+
+ /* Enter the name as active. */
+ namerec->data.nb_flags = nb_flags | NB_ACTIVE;
+ namerec->data.wins_flags = WINS_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);
+
+ DEBUG( 3, ( "add_name_to_subnet: Added netbios name %s with first IP %s \
+ttl=%d nb_flags=%2x to subnet %s\n",
+ nmb_namestr( &namerec->name ),
+ inet_ntoa( *iplist ),
+ ttl,
+ (unsigned int)nb_flags,
+ subrec->subnet_name ) );
+
+ /* Now add the record to the name list. */
+
+ if (subrec == wins_server_subnet) {
+ ret = add_name_to_wins_subnet(namerec);
+ /* Free namerec - it's stored in the tdb. */
+ SAFE_FREE(namerec->data.ip);
+ SAFE_FREE(namerec);
+ } else {
+ DLIST_ADD(subrec->namelist, namerec);
+ subrec->namelist_changed = True;
+ ret = True;
+ }
+
+ return ret;
+}
+
+/*******************************************************************
+ 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 (namerec == NULL) {
+ unstring name;
+ pull_ascii_nstring(name, sizeof(name), nmbname->name);
+ add_name_to_subnet( subrec, 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 nmb_name *nmbname )
+{
+ struct name_record *namerec;
+
+ namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME);
+
+ DEBUG( 0, ( "standard_fail_register: Failed to register/refresh name %s \
+on subnet %s\n", nmb_namestr(nmbname), subrec->subnet_name) );
+
+ /* Remove the name from the subnet. */
+ if( namerec ) {
+ remove_name_from_namelist(subrec, namerec);
+ }
+}
+
+/*******************************************************************
+ Utility function to remove an IP address from a name record.
+ ******************************************************************/
+
+static void remove_nth_ip_in_record( struct name_record *namerec, int ind)
+{
+ if( ind != namerec->data.num_ips ) {
+ memmove( (char *)(&namerec->data.ip[ind]),
+ (char *)(&namerec->data.ip[ind+1]),
+ ( namerec->data.num_ips - ind - 1) * sizeof(struct in_addr) );
+ }
+
+ namerec->data.num_ips--;
+ if (namerec->subnet == wins_server_subnet) {
+ wins_store_changed_namerec(namerec);
+ } else {
+ 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_v4( 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 = SMB_MALLOC_ARRAY( struct in_addr, namerec->data.num_ips + 1);
+ if( NULL == new_list ) {
+ DEBUG(0,("add_ip_to_name_record: Malloc fail !\n"));
+ return;
+ }
+
+ memcpy( (char *)new_list, (char *)namerec->data.ip, namerec->data.num_ips * sizeof(struct in_addr) );
+ new_list[namerec->data.num_ips] = new_ip;
+
+ SAFE_FREE(namerec->data.ip);
+ namerec->data.ip = new_list;
+ namerec->data.num_ips += 1;
+
+ if (namerec->subnet == wins_server_subnet) {
+ wins_store_changed_namerec(namerec);
+ } else {
+ 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_v4( remove_ip, namerec->data.ip[i]) ) {
+ remove_nth_ip_in_record( namerec, i);
+ break;
+ }
+ }
+}
+
+/*******************************************************************
+ Utility function that release_name callers can plug into as the
+ success function when a name release is successful. Used to save
+ duplication of success_function code.
+ ******************************************************************/
+
+void standard_success_release( struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ struct in_addr released_ip )
+{
+ struct name_record *namerec;
+
+ namerec = find_name_on_subnet( subrec, nmbname, FIND_ANY_NAME );
+ if( namerec == NULL ) {
+ DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \
+on subnet %s. Name was not found on subnet.\n", nmb_namestr(nmbname), inet_ntoa(released_ip),
+ subrec->subnet_name) );
+ return;
+ } else {
+ int orig_num = namerec->data.num_ips;
+
+ remove_ip_from_name_record( namerec, released_ip );
+
+ if( namerec->data.num_ips == orig_num ) {
+ DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \
+on subnet %s. This ip is not known for this name.\n", nmb_namestr(nmbname), inet_ntoa(released_ip), subrec->subnet_name ) );
+ }
+ }
+
+ if( namerec->data.num_ips == 0 ) {
+ remove_name_from_namelist( subrec, namerec );
+ }
+}
+
+/*******************************************************************
+ Expires old names in a subnet namelist.
+ NB. Does not touch the wins_subnet - no wins specific processing here.
+******************************************************************/
+
+static void expire_names_on_subnet(struct subnet_record *subrec, time_t t)
+{
+ struct name_record *namerec;
+ struct name_record *next_namerec;
+
+ for( namerec = subrec->namelist; namerec; namerec = next_namerec ) {
+ next_namerec = namerec->next;
+ if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
+ if( namerec->data.source == SELF_NAME ) {
+ DEBUG( 3, ( "expire_names_on_subnet: Subnet %s not expiring SELF \
+name %s\n", subrec->subnet_name, nmb_namestr(&namerec->name) ) );
+ namerec->data.death_time += 300;
+ namerec->subnet->namelist_changed = True;
+ continue;
+ }
+
+ DEBUG(3,("expire_names_on_subnet: Subnet %s - removing expired name %s\n",
+ subrec->subnet_name, nmb_namestr(&namerec->name)));
+
+ remove_name_from_namelist(subrec, namerec );
+ }
+ }
+}
+
+/*******************************************************************
+ Expires old names in all subnet namelists.
+ NB. Does not touch the wins_subnet.
+******************************************************************/
+
+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 = SMB_MALLOC_ARRAY( struct in_addr, num_ips);
+ if( NULL == iplist ) {
+ DEBUG(0,("add_samba_names_to_subnet: Malloc fail !\n"));
+ return;
+ }
+
+ for( bcast_subrecs = FIRST_SUBNET, i = 0; bcast_subrecs &&
+ i < num_ips;
+ bcast_subrecs = NEXT_SUBNET_EXCLUDING_UNICAST(bcast_subrecs), i++ ) {
+ iplist[i] = bcast_subrecs->myip;
+ }
+ num_ips = i;
+ }
+
+ add_name_to_subnet(subrec,"*",0x0,samba_nb_type, PERMANENT_TTL,
+ PERMANENT_NAME, num_ips, iplist);
+ add_name_to_subnet(subrec,"*",0x20,samba_nb_type,PERMANENT_TTL,
+ PERMANENT_NAME, num_ips, iplist);
+ add_name_to_subnet(subrec,"__SAMBA__",0x20,samba_nb_type,PERMANENT_TTL,
+ PERMANENT_NAME, num_ips, iplist);
+ add_name_to_subnet(subrec,"__SAMBA__",0x00,samba_nb_type,PERMANENT_TTL,
+ PERMANENT_NAME, num_ips, iplist);
+
+ if(iplist != &subrec->myip) {
+ SAFE_FREE(iplist);
+ }
+}
+
+/****************************************************************************
+ Dump a name_record struct.
+**************************************************************************/
+
+void dump_name_record( struct name_record *namerec, XFILE *fp)
+{
+ const char *src_type;
+ struct tm *tm;
+ int i;
+
+ x_fprintf(fp,"\tName = %s\t", nmb_namestr(&namerec->name));
+ switch(namerec->data.source) {
+ case LMHOSTS_NAME:
+ src_type = "LMHOSTS_NAME";
+ break;
+ case WINS_PROXY_NAME:
+ src_type = "WINS_PROXY_NAME";
+ break;
+ case REGISTER_NAME:
+ src_type = "REGISTER_NAME";
+ break;
+ case SELF_NAME:
+ src_type = "SELF_NAME";
+ break;
+ case DNS_NAME:
+ src_type = "DNS_NAME";
+ break;
+ case DNSFAIL_NAME:
+ src_type = "DNSFAIL_NAME";
+ break;
+ case PERMANENT_NAME:
+ src_type = "PERMANENT_NAME";
+ break;
+ default:
+ src_type = "unknown!";
+ break;
+ }
+
+ x_fprintf(fp,"Source = %s\nb_flags = %x\t", src_type, namerec->data.nb_flags);
+
+ if(namerec->data.death_time != PERMANENT_TTL) {
+ const char *asct;
+ tm = localtime(&namerec->data.death_time);
+ if (!tm) {
+ return;
+ }
+ asct = asctime(tm);
+ if (!asct) {
+ return;
+ }
+ x_fprintf(fp, "death_time = %s\t", asct);
+ } else {
+ x_fprintf(fp, "death_time = PERMANENT\t");
+ }
+
+ if(namerec->data.refresh_time != PERMANENT_TTL) {
+ const char *asct;
+ tm = localtime(&namerec->data.refresh_time);
+ if (!tm) {
+ return;
+ }
+ asct = asctime(tm);
+ if (!asct) {
+ return;
+ }
+ x_fprintf(fp, "refresh_time = %s\n", asct);
+ } else {
+ x_fprintf(fp, "refresh_time = PERMANENT\n");
+ }
+
+ x_fprintf(fp, "\t\tnumber of IPS = %d", namerec->data.num_ips);
+ for(i = 0; i < namerec->data.num_ips; i++) {
+ x_fprintf(fp, "\t%s", inet_ntoa(namerec->data.ip[i]));
+ }
+
+ x_fprintf(fp, "\n\n");
+
+}
+
+/****************************************************************************
+ Dump the contents of the namelists on all the subnets (including unicast)
+ into a file. Initiated by SIGHUP - used to debug the state of the namelists.
+**************************************************************************/
+
+static void dump_subnet_namelist( struct subnet_record *subrec, XFILE *fp)
+{
+ struct name_record *namerec;
+ x_fprintf(fp, "Subnet %s\n----------------------\n", subrec->subnet_name);
+ for( namerec = subrec->namelist; namerec; namerec = namerec->next) {
+ dump_name_record(namerec, fp);
+ }
+}
+
+/****************************************************************************
+ Dump the contents of the namelists on all the subnets (including unicast)
+ into a file. Initiated by SIGHUP - used to debug the state of the namelists.
+**************************************************************************/
+
+void dump_all_namelists(void)
+{
+ XFILE *fp;
+ struct subnet_record *subrec;
+
+ fp = x_fopen(lock_path("namelist.debug"),O_WRONLY|O_CREAT|O_TRUNC, 0644);
+
+ if (!fp) {
+ DEBUG(0,("dump_all_namelists: Can't open file %s. Error was %s\n",
+ "namelist.debug",strerror(errno)));
+ return;
+ }
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
+ dump_subnet_namelist( subrec, fp );
+ }
+
+ if (!we_are_a_wins_client()) {
+ dump_subnet_namelist( unicast_subnet, fp );
+ }
+
+ if (remote_broadcast_subnet->namelist != NULL) {
+ dump_subnet_namelist( remote_broadcast_subnet, fp );
+ }
+
+ if (wins_server_subnet != NULL) {
+ dump_wins_subnet_namelist(fp );
+ }
+
+ x_fclose( fp );
+}
diff --git a/source3/nmbd/nmbd_namequery.c b/source3/nmbd/nmbd_namequery.c
new file mode 100644
index 0000000000..c1c5f5238a
--- /dev/null
+++ b/source3/nmbd/nmbd_namequery.c
@@ -0,0 +1,275 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Deal with a response packet when querying a name.
+****************************************************************************/
+
+static void query_name_response( struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ bool success = False;
+ struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
+ struct in_addr answer_ip;
+
+ zero_ip_v4(&answer_ip);
+
+ /* Ensure we don't retry the query but leave the response record cleanup
+ to the timeout code. We may get more answer responses in which case
+ we should mark the name in conflict.. */
+ rrec->repeat_count = 0;
+
+ if(rrec->num_msgs == 1) {
+ /* This is the first response. */
+
+ if(nmb->header.opcode == NMB_WACK_OPCODE) {
+ /* WINS server is telling us to wait. Pretend we didn't get
+ the response but don't send out any more query requests. */
+
+ if( DEBUGLVL( 5 ) ) {
+ dbgtext( "query_name_response: " );
+ dbgtext( "WACK from WINS server %s ", inet_ntoa(p->ip) );
+ dbgtext( "in querying name %s ", nmb_namestr(question_name) );
+ dbgtext( "on subnet %s.\n", subrec->subnet_name );
+ }
+
+ rrec->repeat_count = 0;
+ /* How long we should wait for. */
+ if (nmb->answers) {
+ rrec->repeat_time = p->timestamp + nmb->answers->ttl;
+ } else {
+ /* No answer - this is probably a corrupt
+ packet.... */
+ DEBUG(0,("query_name_response: missing answer record in "
+ "NMB_WACK_OPCODE response.\n"));
+ rrec->repeat_time = p->timestamp + 10;
+ }
+ rrec->num_msgs--;
+ return;
+ } else if(nmb->header.rcode != 0) {
+
+ success = False;
+
+ if( DEBUGLVL( 5 ) ) {
+ dbgtext( "query_name_response: On subnet %s ", subrec->subnet_name );
+ dbgtext( "- negative response from IP %s ", inet_ntoa(p->ip) );
+ dbgtext( "for name %s. ", nmb_namestr(question_name) );
+ dbgtext( "Error code was %d.\n", nmb->header.rcode );
+ }
+ } else {
+ if (!nmb->answers) {
+ dbgtext( "query_name_response: On subnet %s ", subrec->subnet_name );
+ dbgtext( "IP %s ", inet_ntoa(p->ip) );
+ dbgtext( "returned a success response with no answer\n" );
+ return;
+ }
+
+ success = True;
+
+ putip((char *)&answer_ip,&nmb->answers->rdata[2]);
+
+ if( DEBUGLVL( 5 ) ) {
+ dbgtext( "query_name_response: On subnet %s ", subrec->subnet_name );
+ dbgtext( "- positive response from IP %s ", inet_ntoa(p->ip) );
+ dbgtext( "for name %s. ", nmb_namestr(question_name) );
+ dbgtext( "IP of that name is %s\n", inet_ntoa(answer_ip) );
+ }
+
+ /* Interestingly, we could add these names to our namelists, and
+ change nmbd to a model that checked its own name cache first,
+ before sending out a query. This is a task for another day, though.
+ */
+ }
+ } else if( rrec->num_msgs > 1) {
+
+ if( DEBUGLVL( 0 ) ) {
+ if (nmb->answers)
+ putip( (char *)&answer_ip, &nmb->answers->rdata[2] );
+ dbgtext( "query_name_response: " );
+ dbgtext( "Multiple (%d) responses ", rrec->num_msgs );
+ dbgtext( "received for a query on subnet %s ", subrec->subnet_name );
+ dbgtext( "for name %s.\nThis response ", nmb_namestr(question_name) );
+ dbgtext( "was from IP %s, reporting ", inet_ntoa(p->ip) );
+ dbgtext( "an IP address of %s.\n", inet_ntoa(answer_ip) );
+ }
+
+ /* We have already called the success or fail function, so we
+ don't call again here. Leave the response record around in
+ case we get more responses. */
+
+ return;
+ }
+
+ if(success && rrec->success_fn)
+ (*(query_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, answer_ip, nmb->answers);
+ else if( rrec->fail_fn)
+ (*(query_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name, nmb->header.rcode);
+
+}
+
+/****************************************************************************
+ Deal with a timeout when querying a name.
+****************************************************************************/
+
+static void query_name_timeout_response(struct subnet_record *subrec,
+ struct response_record *rrec)
+{
+ struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+ /* We can only fail here, never succeed. */
+ bool failed = True;
+ struct nmb_name *question_name = &sent_nmb->question.question_name;
+
+ if(rrec->num_msgs != 0) {
+ /* We got at least one response, and have called the success/fail
+ function already. */
+
+ failed = False;
+ }
+
+ if(failed) {
+ if( DEBUGLVL( 5 ) ) {
+ dbgtext( "query_name_timeout_response: No response to " );
+ dbgtext( "query for name %s ", nmb_namestr(question_name) );
+ dbgtext( "on subnet %s.\n", subrec->subnet_name );
+ }
+
+ if(rrec->fail_fn)
+ (*(query_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name, 0);
+ }
+
+ remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Lookup a name on our local namelists. We check the lmhosts file first. If the
+ name is not there we look for the name on the given subnet.
+****************************************************************************/
+
+static bool query_local_namelists(struct subnet_record *subrec, struct nmb_name *nmbname,
+ struct name_record **namerecp)
+{
+ struct name_record *namerec;
+
+ *namerecp = NULL;
+
+ if(find_name_in_lmhosts(nmbname, namerecp))
+ return True;
+
+ if((namerec = find_name_on_subnet(subrec, nmbname, FIND_ANY_NAME))==NULL)
+ return False;
+
+ if( NAME_IS_ACTIVE(namerec) && ( (namerec->data.source == SELF_NAME) || (namerec->data.source == LMHOSTS_NAME) ) ) {
+ *namerecp = namerec;
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************************
+ Try and query for a name.
+****************************************************************************/
+
+bool query_name(struct subnet_record *subrec, const char *name, int type,
+ query_name_success_function success_fn,
+ query_name_fail_function fail_fn,
+ struct userdata_struct *userdata)
+{
+ struct nmb_name nmbname;
+ struct name_record *namerec;
+
+ make_nmb_name(&nmbname, name, type);
+
+ /*
+ * We need to check our local namelists first.
+ * It may be an magic name, lmhosts name or just
+ * a name we have registered.
+ */
+
+ if(query_local_namelists(subrec, &nmbname, &namerec) == True) {
+ struct res_rec rrec;
+ int i;
+
+ memset((char *)&rrec, '\0', sizeof(struct res_rec));
+
+ /* Fake up the needed res_rec just in case it's used. */
+ rrec.rr_name = nmbname;
+ rrec.rr_type = RR_TYPE_NB;
+ rrec.rr_class = RR_CLASS_IN;
+ rrec.ttl = PERMANENT_TTL;
+ rrec.rdlength = namerec->data.num_ips * 6;
+ if(rrec.rdlength > MAX_DGRAM_SIZE) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "query_name: nmbd internal error - " );
+ dbgtext( "there are %d ip addresses ", namerec->data.num_ips );
+ dbgtext( "for name %s.\n", nmb_namestr(&nmbname) );
+ }
+ return False;
+ }
+
+ for( i = 0; i < namerec->data.num_ips; i++) {
+ set_nb_flags( &rrec.rdata[i*6], namerec->data.nb_flags );
+ putip( &rrec.rdata[(i*6) + 2], (char *)&namerec->data.ip[i]);
+ }
+
+ /* Call the success function directly. */
+ if(success_fn)
+ (*(query_name_success_function)success_fn)(subrec, userdata, &nmbname, namerec->data.ip[0], &rrec);
+ return False;
+ }
+
+ if(queue_query_name( subrec, query_name_response, query_name_timeout_response, success_fn, fail_fn, userdata, &nmbname) == NULL) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "query_name: Failed to send packet " );
+ dbgtext( "trying to query name %s\n", nmb_namestr(&nmbname) );
+ }
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************************
+ Try and query for a name from nmbd acting as a WINS server.
+****************************************************************************/
+
+bool query_name_from_wins_server(struct in_addr ip_to,
+ const char *name, int type,
+ query_name_success_function success_fn,
+ query_name_fail_function fail_fn,
+ struct userdata_struct *userdata)
+{
+ struct nmb_name nmbname;
+
+ make_nmb_name(&nmbname, name, type);
+
+ if(queue_query_name_from_wins_server( ip_to, query_name_response, query_name_timeout_response, success_fn, fail_fn, userdata, &nmbname) == NULL) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "query_name_from_wins_server: Failed to send packet " );
+ dbgtext( "trying to query name %s\n", nmb_namestr(&nmbname) );
+ }
+ return True;
+ }
+ return False;
+}
diff --git a/source3/nmbd/nmbd_nameregister.c b/source3/nmbd/nmbd_nameregister.c
new file mode 100644
index 0000000000..98f129aa89
--- /dev/null
+++ b/source3/nmbd/nmbd_nameregister.c
@@ -0,0 +1,538 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+/* forward declarations */
+static void wins_next_registration(struct response_record *rrec);
+
+
+/****************************************************************************
+ 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;
+ struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+ int ttl = 0;
+ uint16 nb_flags = 0;
+ struct in_addr register_ip;
+ fstring reg_name;
+
+ putip(&register_ip,&sent_nmb->additional->rdata[2]);
+ fstrcpy(reg_name, inet_ntoa(register_ip));
+
+ if (subrec == unicast_subnet) {
+ /* we know that this wins server is definately alive - for the moment! */
+ wins_srv_alive(rrec->packet->ip, register_ip);
+ }
+
+ /* Sanity check. Ensure that the answer name in the incoming packet is the
+ same as the requested name in the outgoing packet. */
+
+ if(!question_name || !answer_name) {
+ DEBUG(0,("register_name_response: malformed response (%s is NULL).\n",
+ question_name ? "question_name" : "answer_name" ));
+ return;
+ }
+
+ if(!nmb_name_equal(question_name, answer_name)) {
+ DEBUG(0,("register_name_response: Answer name %s differs from question name %s.\n",
+ nmb_namestr(answer_name), nmb_namestr(question_name)));
+ return;
+ }
+
+ if(bcast) {
+ /*
+ * Special hack to cope with old Samba nmbd's.
+ * Earlier versions of Samba (up to 1.9.16p11) respond
+ * to a broadcast name registration of WORKGROUP<1b> when
+ * they should not. Hence, until these versions are gone,
+ * we should treat such errors as success for this particular
+ * case only. jallison@whistle.com.
+ */
+
+#if 1 /* OLD_SAMBA_SERVER_HACK */
+ unstring ans_name;
+ pull_ascii_nstring(ans_name, sizeof(ans_name), answer_name->name);
+ if((nmb->header.rcode == ACT_ERR) && strequal(lp_workgroup(), ans_name) &&
+ (answer_name->name_type == 0x1b)) {
+ /* Pretend we did not get this. */
+ rrec->num_msgs--;
+
+ DEBUG(5,("register_name_response: Ignoring broadcast response to registration of name %s due to old Samba server bug.\n",
+ nmb_namestr(answer_name)));
+ return;
+ }
+#endif /* OLD_SAMBA_SERVER_HACK */
+
+ /* Someone else has the name. Log the problem. */
+ DEBUG(1,("register_name_response: Failed to register name %s IP %s on subnet %s via broadcast. Error code was %d. Reject came from IP %s\n",
+ nmb_namestr(answer_name),
+ reg_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.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 IP %s\n",
+ inet_ntoa(p->ip), nmb_namestr(answer_name), reg_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) {
+ /* Error code - we didn't get the name. */
+ success = False;
+
+ DEBUG(0,("register_name_response: %sserver at IP %s rejected our name registration of %s IP %s with error code %d.\n",
+ subrec==unicast_subnet?"WINS ":"",
+ inet_ntoa(p->ip),
+ nmb_namestr(answer_name),
+ reg_name,
+ nmb->header.rcode));
+ } else {
+ success = True;
+ /* Get the data we need to pass to the success function. */
+ nb_flags = get_nb_flags(nmb->answers->rdata);
+ ttl = nmb->answers->ttl;
+
+ /* send off a registration for the next IP, if any */
+ wins_next_registration(rrec);
+ }
+ }
+
+ DEBUG(5,("register_name_response: %s in registering %sname %s IP %s with %s.\n",
+ success ? "success" : "failure",
+ subrec==unicast_subnet?"WINS ":"",
+ nmb_namestr(answer_name),
+ reg_name,
+ inet_ntoa(rrec->packet->ip)));
+
+ 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, register_ip);
+ if( rrec->success_fn)
+ (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, nb_flags, ttl, register_ip);
+ } else {
+ struct nmb_name qname = *question_name;
+ if( rrec->fail_fn)
+ (*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name);
+ /* Remove the name. */
+ standard_fail_register( subrec, &qname);
+ }
+
+ /* Ensure we don't retry. */
+ remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Deal with a timeout of a WINS registration request
+****************************************************************************/
+
+static void wins_registration_timeout(struct subnet_record *subrec,
+ struct response_record *rrec)
+{
+ struct userdata_struct *userdata = rrec->userdata;
+ struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+ struct nmb_name *nmbname = &sent_nmb->question.question_name;
+ struct in_addr register_ip;
+ fstring src_addr;
+
+ putip(&register_ip,&sent_nmb->additional->rdata[2]);
+
+ fstrcpy(src_addr, inet_ntoa(register_ip));
+
+ DEBUG(2,("wins_registration_timeout: WINS server %s timed out registering IP %s\n",
+ inet_ntoa(rrec->packet->ip), src_addr));
+
+ /* mark it temporarily dead for this source address */
+ wins_srv_died(rrec->packet->ip, register_ip);
+
+ /* if we have some userdata then use that to work out what
+ wins server to try next */
+ if (userdata) {
+ const char *tag = (const char *)userdata->data;
+
+ /* try the next wins server in our failover list for
+ this tag */
+ rrec->packet->ip = wins_srv_ip_tag(tag, register_ip);
+ }
+
+ /* if we have run out of wins servers for this tag then they
+ must all have timed out. We treat this as *success*, not
+ failure, and go into our standard name refresh mode. This
+ copes with all the wins servers being down */
+ if (wins_srv_is_dead(rrec->packet->ip, register_ip)) {
+ uint16 nb_flags = get_nb_flags(sent_nmb->additional->rdata);
+ int ttl = sent_nmb->additional->ttl;
+
+ standard_success_register(subrec, userdata, nmbname, nb_flags, ttl, register_ip);
+ if(rrec->success_fn) {
+ (*(register_name_success_function)rrec->success_fn)(subrec,
+ rrec->userdata,
+ nmbname,
+ nb_flags,
+ ttl,
+ register_ip);
+ }
+
+ /* send off a registration for the next IP, if any */
+ wins_next_registration(rrec);
+
+ /* don't need to send this packet any more */
+ remove_response_record(subrec, rrec);
+ return;
+ }
+
+ /* we will be moving to the next WINS server for this group,
+ send it immediately */
+ rrec->repeat_count = 2;
+ rrec->repeat_time = time(NULL) + 1;
+ rrec->in_expiration_processing = False;
+
+ DEBUG(6,("Retrying register of name %s IP %s with WINS server %s\n",
+ nmb_namestr(nmbname), src_addr, inet_ntoa(rrec->packet->ip)));
+
+ /* notice that we don't remove the response record. This keeps
+ us trying to register with each of our failover wins servers */
+}
+
+/****************************************************************************
+ 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 {
+ /* wins timeouts are special */
+ wins_registration_timeout(subrec, rrec);
+ return;
+ }
+
+ DEBUG(5,("register_name_timeout_response: %s in registering name %s on subnet %s.\n",
+ success ? "success" : "failure", nmb_namestr(question_name), subrec->subnet_name));
+ if(success) {
+ /* Enter the registered name into the subnet name database before calling
+ the success function. */
+ standard_success_register(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip);
+ if( rrec->success_fn)
+ (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip);
+ } else {
+ struct nmb_name qname = *question_name;
+ if( rrec->fail_fn)
+ (*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name);
+ /* Remove the name. */
+ standard_fail_register( subrec, &qname);
+ }
+
+ /* Ensure we don't retry. */
+ remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Initiate one multi-homed name registration packet.
+****************************************************************************/
+
+static void multihomed_register_one(struct nmb_name *nmbname,
+ uint16 nb_flags,
+ register_name_success_function success_fn,
+ register_name_fail_function fail_fn,
+ struct in_addr ip,
+ const char *tag)
+{
+ struct userdata_struct *userdata;
+ struct in_addr wins_ip = wins_srv_ip_tag(tag, ip);
+ fstring ip_str;
+
+ userdata = (struct userdata_struct *)SMB_MALLOC(sizeof(*userdata) + strlen(tag) + 1);
+ if (!userdata) {
+ DEBUG(0,("Failed to allocate userdata structure!\n"));
+ return;
+ }
+ ZERO_STRUCTP(userdata);
+ userdata->userdata_len = strlen(tag) + 1;
+ strlcpy(userdata->data, tag, userdata->userdata_len);
+
+ fstrcpy(ip_str, inet_ntoa(ip));
+
+ DEBUG(6,("Registering name %s IP %s with WINS server %s using tag '%s'\n",
+ nmb_namestr(nmbname), ip_str, inet_ntoa(wins_ip), tag));
+
+ if (queue_register_multihomed_name(unicast_subnet,
+ register_name_response,
+ register_name_timeout_response,
+ success_fn,
+ fail_fn,
+ userdata,
+ nmbname,
+ nb_flags,
+ ip,
+ wins_ip) == NULL) {
+ DEBUG(0,("multihomed_register_one: Failed to send packet trying to register name %s IP %s\n",
+ nmb_namestr(nmbname), inet_ntoa(ip)));
+ }
+
+ free(userdata);
+}
+
+/****************************************************************************
+ We have finished the registration of one IP and need to see if we have
+ any more IPs left to register with this group of wins server for this name.
+****************************************************************************/
+
+static void wins_next_registration(struct response_record *rrec)
+{
+ struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+ struct nmb_name *nmbname = &sent_nmb->question.question_name;
+ uint16 nb_flags = get_nb_flags(sent_nmb->additional->rdata);
+ struct userdata_struct *userdata = rrec->userdata;
+ const char *tag;
+ struct in_addr last_ip;
+ struct subnet_record *subrec;
+
+ putip(&last_ip,&sent_nmb->additional->rdata[2]);
+
+ if (!userdata) {
+ /* it wasn't multi-homed */
+ return;
+ }
+
+ tag = (const char *)userdata->data;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+ if (ip_equal_v4(last_ip, subrec->myip)) {
+ subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec);
+ break;
+ }
+ }
+
+ if (!subrec) {
+ /* no more to do! */
+ return;
+ }
+
+ switch (sent_nmb->header.opcode) {
+ case NMB_NAME_MULTIHOMED_REG_OPCODE:
+ multihomed_register_one(nmbname, nb_flags, NULL, NULL, subrec->myip, tag);
+ break;
+ case NMB_NAME_REFRESH_OPCODE_8:
+ queue_wins_refresh(nmbname,
+ register_name_response,
+ register_name_timeout_response,
+ nb_flags, subrec->myip, tag);
+ break;
+ }
+}
+
+/****************************************************************************
+ Try and register one of our names on the unicast subnet - multihomed.
+****************************************************************************/
+
+static void multihomed_register_name(struct nmb_name *nmbname, uint16 nb_flags,
+ register_name_success_function success_fn,
+ register_name_fail_function fail_fn)
+{
+ /*
+ 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, t;
+ struct subnet_record *subrec;
+ char **wins_tags;
+ struct in_addr *ip_list;
+ unstring name;
+
+ for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) )
+ num_ips++;
+
+ if((ip_list = SMB_MALLOC_ARRAY(struct in_addr, num_ips))==NULL) {
+ DEBUG(0,("multihomed_register_name: malloc fail !\n"));
+ return;
+ }
+
+ for (subrec = FIRST_SUBNET, i = 0;
+ subrec;
+ subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec), i++ ) {
+ ip_list[i] = subrec->myip;
+ }
+
+ pull_ascii_nstring(name, sizeof(name), nmbname->name);
+ add_name_to_subnet(unicast_subnet, name, nmbname->name_type,
+ nb_flags, lp_max_ttl(), SELF_NAME,
+ num_ips, ip_list);
+
+ /* get the list of wins tags - we try to register for each of them */
+ wins_tags = wins_srv_tags();
+
+ /* Now try and register the name for each wins tag. Note that
+ at this point we only register our first IP with each wins
+ group. We will register the rest from
+ wins_next_registration() when we get the reply for this
+ one. That follows the way W2K does things (tridge)
+ */
+ for (t=0; wins_tags && wins_tags[t]; t++) {
+ multihomed_register_one(nmbname, nb_flags,
+ success_fn, fail_fn,
+ ip_list[0],
+ wins_tags[t]);
+ }
+
+ wins_srv_tags_free(wins_tags);
+
+ SAFE_FREE(ip_list);
+}
+
+/****************************************************************************
+ Try and register one of our names.
+****************************************************************************/
+
+void register_name(struct subnet_record *subrec,
+ const 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;
+ nstring nname;
+
+ errno = 0;
+ push_ascii_nstring(nname, name);
+ if (errno == E2BIG) {
+ unstring tname;
+ pull_ascii_nstring(tname, sizeof(tname), nname);
+ DEBUG(0,("register_name: NetBIOS name %s is too long. Truncating to %s\n",
+ name, tname));
+ make_nmb_name(&nmbname, tname, type);
+ } else {
+ make_nmb_name(&nmbname, name, type);
+ }
+
+ /* Always set the NB_ACTIVE flag on the name we are
+ registering. Doesn't make sense without it.
+ */
+
+ nb_flags |= NB_ACTIVE;
+
+ if (subrec == unicast_subnet) {
+ /* we now always do multi-homed registration if we are
+ registering to a WINS server. This copes much
+ better with complex WINS setups */
+ multihomed_register_name(&nmbname, nb_flags,
+ success_fn, fail_fn);
+ return;
+ }
+
+ if (queue_register_name(subrec,
+ register_name_response,
+ register_name_timeout_response,
+ success_fn,
+ fail_fn,
+ userdata,
+ &nmbname,
+ nb_flags) == NULL) {
+ DEBUG(0,("register_name: Failed to send packet trying to register name %s\n",
+ nmb_namestr(&nmbname)));
+ }
+}
+
+/****************************************************************************
+ Try and refresh one of our names. This is *only* called for WINS refresh
+****************************************************************************/
+
+void wins_refresh_name(struct name_record *namerec)
+{
+ int t;
+ char **wins_tags;
+
+ /* get the list of wins tags - we try to refresh for each of them */
+ wins_tags = wins_srv_tags();
+
+ for (t=0; wins_tags && wins_tags[t]; t++) {
+ queue_wins_refresh(&namerec->name,
+ register_name_response,
+ register_name_timeout_response,
+ namerec->data.nb_flags,
+ namerec->data.ip[0], wins_tags[t]);
+ }
+
+ wins_srv_tags_free(wins_tags);
+}
diff --git a/source3/nmbd/nmbd_namerelease.c b/source3/nmbd/nmbd_namerelease.c
new file mode 100644
index 0000000000..4be7396f2e
--- /dev/null
+++ b/source3/nmbd/nmbd_namerelease.c
@@ -0,0 +1,221 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Deal with a response packet when releasing one of our names.
+****************************************************************************/
+
+static void release_name_response(struct subnet_record *subrec,
+ struct response_record *rrec, struct packet_struct *p)
+{
+ /*
+ * If we are releasing broadcast, then getting a response is an
+ * error. If we are releasing unicast, then we expect to get a response.
+ */
+ struct nmb_packet *nmb = &p->packet.nmb;
+ bool bcast = nmb->header.nm_flags.bcast;
+ bool success = True;
+ struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
+ struct nmb_name *answer_name = &nmb->answers->rr_name;
+ struct in_addr released_ip;
+
+ /* Sanity check. Ensure that the answer name in the incoming packet is the
+ same as the requested name in the outgoing packet. */
+ if (!nmb_name_equal(question_name, answer_name)) {
+ DEBUG(0,("release_name_response: Answer name %s differs from question name %s.\n",
+ nmb_namestr(answer_name), nmb_namestr(question_name)));
+ return;
+ }
+
+ if (bcast) {
+ /* Someone sent a response to a bcast release? ignore it. */
+ return;
+ }
+
+ /* Unicast - check to see if the response allows us to release the name. */
+ if (nmb->header.rcode != 0) {
+ /* Error code - we were told not to release the name ! What now ! */
+ success = False;
+
+ DEBUG(0,("release_name_response: WINS server at IP %s rejected our \
+name release of name %s with error code %d.\n",
+ inet_ntoa(p->ip),
+ nmb_namestr(answer_name), nmb->header.rcode));
+ } else if (nmb->header.opcode == NMB_WACK_OPCODE) {
+ /* WINS server is telling us to wait. Pretend we didn't get
+ the response but don't send out any more release requests. */
+
+ DEBUG(5,("release_name_response: WACK from WINS server %s in releasing \
+name %s on subnet %s.\n",
+ inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->subnet_name));
+
+ rrec->repeat_count = 0;
+ /* How long we should wait for. */
+ rrec->repeat_time = p->timestamp + nmb->answers->ttl;
+ rrec->num_msgs--;
+ return;
+ }
+
+ DEBUG(5,("release_name_response: %s in releasing name %s on subnet %s.\n",
+ success ? "success" : "failure", nmb_namestr(answer_name), subrec->subnet_name));
+ if (success) {
+ putip((char*)&released_ip ,&nmb->answers->rdata[2]);
+
+ if(rrec->success_fn)
+ (*(release_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, released_ip);
+ standard_success_release( subrec, rrec->userdata, answer_name, released_ip);
+ } else {
+ /* We have no standard_fail_release - maybe we should add one ? */
+ if (rrec->fail_fn) {
+ (*(release_name_fail_function)rrec->fail_fn)(subrec, rrec, answer_name);
+ }
+ }
+
+ remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Deal with a timeout when releasing one of our names.
+****************************************************************************/
+
+static void release_name_timeout_response(struct subnet_record *subrec,
+ struct response_record *rrec)
+{
+ /* a release is *always* considered to be successful when it
+ times out. This doesn't cause problems as if a WINS server
+ doesn't respond and someone else wants the name then the
+ normal WACK/name query from the WINS server will cope */
+ struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+ bool bcast = sent_nmb->header.nm_flags.bcast;
+ struct nmb_name *question_name = &sent_nmb->question.question_name;
+ struct in_addr released_ip;
+
+ /* Get the ip address we were trying to release. */
+ putip((char*)&released_ip ,&sent_nmb->additional->rdata[2]);
+
+ if (!bcast) {
+ /* mark the WINS server temporarily dead */
+ wins_srv_died(rrec->packet->ip, released_ip);
+ }
+
+ DEBUG(5,("release_name_timeout_response: success in releasing name %s on subnet %s.\n",
+ nmb_namestr(question_name), subrec->subnet_name));
+
+ if (rrec->success_fn) {
+ (*(release_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, released_ip);
+ }
+
+ standard_success_release( subrec, rrec->userdata, question_name, released_ip);
+ remove_response_record(subrec, rrec);
+}
+
+
+/*
+ when releasing a name with WINS we need to send the release to each of
+ the WINS groups
+*/
+static void wins_release_name(struct name_record *namerec,
+ release_name_success_function success_fn,
+ release_name_fail_function fail_fn,
+ struct userdata_struct *userdata)
+{
+ int t, i;
+ char **wins_tags;
+
+ /* get the list of wins tags - we try to release for each of them */
+ wins_tags = wins_srv_tags();
+
+ for (t=0;wins_tags && wins_tags[t]; t++) {
+ for (i = 0; i < namerec->data.num_ips; i++) {
+ struct in_addr wins_ip = wins_srv_ip_tag(wins_tags[t], namerec->data.ip[i]);
+
+ bool last_one = ((i==namerec->data.num_ips - 1) && !wins_tags[t+1]);
+ if (queue_release_name(unicast_subnet,
+ release_name_response,
+ release_name_timeout_response,
+ last_one?success_fn : NULL,
+ last_one? fail_fn : NULL,
+ last_one? userdata : NULL,
+ &namerec->name,
+ namerec->data.nb_flags,
+ namerec->data.ip[i],
+ wins_ip) == NULL) {
+ DEBUG(0,("release_name: Failed to send packet trying to release name %s IP %s\n",
+ nmb_namestr(&namerec->name), inet_ntoa(namerec->data.ip[i]) ));
+ }
+ }
+ }
+
+ wins_srv_tags_free(wins_tags);
+}
+
+
+/****************************************************************************
+ Try and release one of our names.
+****************************************************************************/
+
+void release_name(struct subnet_record *subrec, struct name_record *namerec,
+ release_name_success_function success_fn,
+ release_name_fail_function fail_fn,
+ struct userdata_struct *userdata)
+{
+ int i;
+
+ /* Ensure it's a SELF name, and in the ACTIVE state. */
+ if ((namerec->data.source != SELF_NAME) || !NAME_IS_ACTIVE(namerec)) {
+ DEBUG(0,("release_name: Cannot release name %s from subnet %s. Source was %d \n",
+ nmb_namestr(&namerec->name), subrec->subnet_name, namerec->data.source));
+ return;
+ }
+
+ /* Set the name into the deregistering state. */
+ namerec->data.nb_flags |= NB_DEREG;
+
+ /* wins releases are a bit different */
+ if (subrec == unicast_subnet) {
+ wins_release_name(namerec, success_fn, fail_fn, userdata);
+ return;
+ }
+
+ /*
+ * 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],
+ subrec->bcast_ip) == NULL) {
+ DEBUG(0,("release_name: Failed to send packet trying to release name %s IP %s\n",
+ nmb_namestr(&namerec->name), inet_ntoa(namerec->data.ip[i]) ));
+ }
+ }
+}
diff --git a/source3/nmbd/nmbd_nodestatus.c b/source3/nmbd/nmbd_nodestatus.c
new file mode 100644
index 0000000000..168ccf1ad4
--- /dev/null
+++ b/source3/nmbd/nmbd_nodestatus.c
@@ -0,0 +1,91 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Deal with a successful node status response.
+****************************************************************************/
+
+static void node_status_response(struct subnet_record *subrec,
+ struct response_record *rrec, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
+ struct nmb_name *answer_name = &nmb->answers->rr_name;
+
+ /* Sanity check. Ensure that the answer name in the incoming packet is the
+ same as the requested name in the outgoing packet. */
+
+ if(!nmb_name_equal(question_name, answer_name)) {
+ DEBUG(0,("node_status_response: Answer name %s differs from question \
+name %s.\n", nmb_namestr(answer_name), nmb_namestr(question_name)));
+ return;
+ }
+
+ DEBUG(5,("node_status_response: response from name %s on subnet %s.\n",
+ nmb_namestr(answer_name), subrec->subnet_name));
+
+ /* Just send the whole answer resource record for the success function to parse. */
+ if(rrec->success_fn)
+ (*(node_status_success_function)rrec->success_fn)(subrec, rrec->userdata, nmb->answers, p->ip);
+
+ /* Ensure we don't retry. */
+ remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Deal with a timeout when requesting a node status.
+****************************************************************************/
+
+static void node_status_timeout_response(struct subnet_record *subrec,
+ struct response_record *rrec)
+{
+ struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+ struct nmb_name *question_name = &sent_nmb->question.question_name;
+
+ DEBUG(5,("node_status_timeout_response: failed to get node status from name %s on subnet %s\n",
+ nmb_namestr(question_name), subrec->subnet_name));
+
+ if( rrec->fail_fn)
+ (*rrec->fail_fn)(subrec, rrec);
+
+ /* Ensure we don't retry. */
+ remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Try and do a node status to a name - given the name & IP address.
+****************************************************************************/
+
+bool node_status(struct subnet_record *subrec, struct nmb_name *nmbname,
+ struct in_addr send_ip, node_status_success_function success_fn,
+ node_status_fail_function fail_fn, struct userdata_struct *userdata)
+{
+ if(queue_node_status( subrec, node_status_response, node_status_timeout_response,
+ success_fn, fail_fn, userdata, nmbname, send_ip)==NULL) {
+ DEBUG(0,("node_status: Failed to send packet trying to get node status for \
+name %s, IP address %s\n", nmb_namestr(nmbname), inet_ntoa(send_ip)));
+ return True;
+ }
+ return False;
+}
diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c
new file mode 100644
index 0000000000..4b97819a14
--- /dev/null
+++ b/source3/nmbd/nmbd_packets.c
@@ -0,0 +1,1977 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+extern int global_nmb_port;
+
+extern int num_response_packets;
+
+bool rescan_listen_set = False;
+
+
+/*******************************************************************
+ The global packet linked-list. Incoming entries are
+ added to the end of this list. It is supposed to remain fairly
+ short so we won't bother with an end pointer.
+******************************************************************/
+
+static struct packet_struct *packet_queue = NULL;
+
+/***************************************************************************
+Utility function to find the specific fd to send a packet out on.
+**************************************************************************/
+
+static int find_subnet_fd_for_address( struct in_addr local_ip )
+{
+ struct subnet_record *subrec;
+
+ for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ if(ip_equal_v4(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_v4(local_ip, subrec->myip))
+ return subrec->dgram_sock;
+
+ return ClientDGRAM;
+}
+
+/***************************************************************************
+Get/Set problematic nb_flags as network byte order 16 bit int.
+**************************************************************************/
+
+uint16 get_nb_flags(char *buf)
+{
+ return ((((uint16)*buf)&0xFFFF) & NB_FLGMSK);
+}
+
+void set_nb_flags(char *buf, uint16 nb_flags)
+{
+ *buf++ = ((nb_flags & NB_FLGMSK) & 0xFF);
+ *buf = '\0';
+}
+
+/***************************************************************************
+Dumps out the browse packet data.
+**************************************************************************/
+
+static void debug_browse_data(char *outbuf, int len)
+{
+ int i,j;
+
+ DEBUG( 4, ( "debug_browse_data():\n" ) );
+ for (i = 0; i < len; i+= 16) {
+ DEBUGADD( 4, ( "%3x char ", i ) );
+
+ for (j = 0; j < 16; j++) {
+ unsigned char x;
+ if (i+j >= len)
+ break;
+
+ x = outbuf[i+j];
+ if (x < 32 || x > 127)
+ x = '.';
+
+ DEBUGADD( 4, ( "%c", x ) );
+ }
+
+ DEBUGADD( 4, ( "%*s hex", 16-j, "" ) );
+
+ for (j = 0; j < 16; j++) {
+ if (i+j >= len)
+ break;
+ DEBUGADD( 4, ( " %02x", (unsigned char)outbuf[i+j] ) );
+ }
+
+ DEBUGADD( 4, ("\n") );
+ }
+}
+
+/***************************************************************************
+ Generates the unique transaction identifier
+**************************************************************************/
+
+static uint16 name_trn_id=0;
+
+static uint16 generate_name_trn_id(void)
+{
+ if (!name_trn_id) {
+ name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + ((unsigned)sys_getpid()%(unsigned)100);
+ }
+ name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
+ return name_trn_id;
+}
+
+/***************************************************************************
+ Either loops back or sends out a completed NetBIOS packet.
+**************************************************************************/
+
+static bool send_netbios_packet(struct packet_struct *p)
+{
+ bool loopback_this_packet = False;
+
+ /* Check if we are sending to or from ourselves as a WINS server. */
+ if(ismyip_v4(p->ip) && (p->port == global_nmb_port))
+ loopback_this_packet = True;
+
+ if(loopback_this_packet) {
+ struct packet_struct *lo_packet = NULL;
+ DEBUG(5,("send_netbios_packet: sending packet to ourselves.\n"));
+ if((lo_packet = copy_packet(p)) == NULL)
+ return False;
+ queue_packet(lo_packet);
+ } else if (!send_packet(p)) {
+ DEBUG(0,("send_netbios_packet: send_packet() to IP %s port %d failed\n",
+ inet_ntoa(p->ip),p->port));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ Sets up the common elements of an outgoing NetBIOS packet.
+
+ Note: do not attempt to rationalise whether rec_des should be set or not
+ in a particular situation. Just follow rfc_1002 or look at examples from WinXX.
+ It does NOT follow the rule that requests to the wins server always have
+ rec_des true. See for example name releases and refreshes
+**************************************************************************/
+
+static struct packet_struct *create_and_init_netbios_packet(struct nmb_name *nmbname,
+ bool bcast, bool rec_des,
+ struct in_addr to_ip)
+{
+ struct packet_struct *packet = NULL;
+ struct nmb_packet *nmb = NULL;
+
+ /* Allocate the packet_struct we will return. */
+ if((packet = SMB_MALLOC_P(struct packet_struct)) == NULL) {
+ DEBUG(0,("create_and_init_netbios_packet: malloc fail (1) for packet struct.\n"));
+ return NULL;
+ }
+
+ memset((char *)packet,'\0',sizeof(*packet));
+
+ nmb = &packet->packet.nmb;
+
+ nmb->header.name_trn_id = generate_name_trn_id();
+ nmb->header.response = False;
+ nmb->header.nm_flags.recursion_desired = rec_des;
+ nmb->header.nm_flags.recursion_available = False;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = False;
+ nmb->header.nm_flags.bcast = bcast;
+
+ nmb->header.rcode = 0;
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+
+ nmb->question.question_name = *nmbname;
+ nmb->question.question_type = QUESTION_TYPE_NB_QUERY;
+ nmb->question.question_class = QUESTION_CLASS_IN;
+
+ packet->ip = to_ip;
+ packet->port = NMB_PORT;
+ packet->fd = ClientNMB;
+ packet->timestamp = time(NULL);
+ packet->packet_type = NMB_PACKET;
+ packet->locked = False;
+
+ return packet; /* Caller must free. */
+}
+
+/***************************************************************************
+ Sets up the common elements of register, refresh or release packet.
+**************************************************************************/
+
+static bool create_and_init_additional_record(struct packet_struct *packet,
+ uint16 nb_flags,
+ const struct in_addr *register_ip)
+{
+ struct nmb_packet *nmb = &packet->packet.nmb;
+
+ if((nmb->additional = SMB_MALLOC_P(struct res_rec)) == NULL) {
+ DEBUG(0,("create_and_init_additional_record: malloc fail for additional record.\n"));
+ return False;
+ }
+
+ memset((char *)nmb->additional,'\0',sizeof(struct res_rec));
+
+ nmb->additional->rr_name = nmb->question.question_name;
+ nmb->additional->rr_type = RR_TYPE_NB;
+ nmb->additional->rr_class = RR_CLASS_IN;
+
+ /* See RFC 1002, sections 5.1.1.1, 5.1.1.2 and 5.1.1.3 */
+ if (nmb->header.nm_flags.bcast)
+ nmb->additional->ttl = PERMANENT_TTL;
+ else
+ nmb->additional->ttl = lp_max_ttl();
+
+ nmb->additional->rdlength = 6;
+
+ set_nb_flags(nmb->additional->rdata,nb_flags);
+
+ /* Set the address for the name we are registering. */
+ putip(&nmb->additional->rdata[2], register_ip);
+
+ /*
+ it turns out that Jeremys code was correct, we are supposed
+ to send registrations from the IP we are registering. The
+ trick is what to do on timeouts! When we send on a
+ non-routable IP then the reply will timeout, and we should
+ treat this as success, not failure. That means we go into
+ our standard refresh cycle for that name which copes nicely
+ with disconnected networks.
+ */
+ packet->fd = find_subnet_fd_for_address(*register_ip);
+
+ return True;
+}
+
+/***************************************************************************
+ Sends out a name query.
+**************************************************************************/
+
+static bool initiate_name_query_packet( struct packet_struct *packet)
+{
+ struct nmb_packet *nmb = NULL;
+
+ nmb = &packet->packet.nmb;
+
+ nmb->header.opcode = NMB_NAME_QUERY_OPCODE;
+ nmb->header.arcount = 0;
+
+ nmb->header.nm_flags.recursion_desired = True;
+
+ DEBUG(4,("initiate_name_query_packet: sending query for name %s (bcast=%s) to IP %s\n",
+ nmb_namestr(&nmb->question.question_name),
+ BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+ return send_netbios_packet( packet );
+}
+
+/***************************************************************************
+ Sends out a name query - from a WINS server.
+**************************************************************************/
+
+static bool initiate_name_query_packet_from_wins_server( struct packet_struct *packet)
+{
+ struct nmb_packet *nmb = NULL;
+
+ nmb = &packet->packet.nmb;
+
+ nmb->header.opcode = NMB_NAME_QUERY_OPCODE;
+ nmb->header.arcount = 0;
+
+ nmb->header.nm_flags.recursion_desired = False;
+
+ DEBUG(4,("initiate_name_query_packet_from_wins_server: sending query for name %s (bcast=%s) to IP %s\n",
+ nmb_namestr(&nmb->question.question_name),
+ BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+ return send_netbios_packet( packet );
+}
+
+/***************************************************************************
+ Sends out a name register.
+**************************************************************************/
+
+static bool initiate_name_register_packet( struct packet_struct *packet,
+ uint16 nb_flags, const struct in_addr *register_ip)
+{
+ struct nmb_packet *nmb = &packet->packet.nmb;
+
+ nmb->header.opcode = NMB_NAME_REG_OPCODE;
+ nmb->header.arcount = 1;
+
+ nmb->header.nm_flags.recursion_desired = True;
+
+ if(create_and_init_additional_record(packet, nb_flags, register_ip) == False)
+ return False;
+
+ DEBUG(4,("initiate_name_register_packet: sending registration for name %s (bcast=%s) to IP %s\n",
+ nmb_namestr(&nmb->additional->rr_name),
+ BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+ return send_netbios_packet( packet );
+}
+
+/***************************************************************************
+ Sends out a multihomed name register.
+**************************************************************************/
+
+static bool initiate_multihomed_name_register_packet(struct packet_struct *packet,
+ uint16 nb_flags, struct in_addr *register_ip)
+{
+ struct nmb_packet *nmb = &packet->packet.nmb;
+ fstring second_ip_buf;
+
+ fstrcpy(second_ip_buf, inet_ntoa(packet->ip));
+
+ nmb->header.opcode = NMB_NAME_MULTIHOMED_REG_OPCODE;
+ nmb->header.arcount = 1;
+
+ nmb->header.nm_flags.recursion_desired = True;
+
+ if(create_and_init_additional_record(packet, nb_flags, register_ip) == False)
+ return False;
+
+ DEBUG(4,("initiate_multihomed_name_register_packet: sending registration \
+for name %s IP %s (bcast=%s) to IP %s\n",
+ nmb_namestr(&nmb->additional->rr_name), inet_ntoa(*register_ip),
+ BOOLSTR(nmb->header.nm_flags.bcast), second_ip_buf ));
+
+ return send_netbios_packet( packet );
+}
+
+/***************************************************************************
+ Sends out a name refresh.
+**************************************************************************/
+
+static bool initiate_name_refresh_packet( struct packet_struct *packet,
+ uint16 nb_flags, struct in_addr *refresh_ip)
+{
+ struct nmb_packet *nmb = &packet->packet.nmb;
+
+ nmb->header.opcode = NMB_NAME_REFRESH_OPCODE_8;
+ nmb->header.arcount = 1;
+
+ nmb->header.nm_flags.recursion_desired = False;
+
+ if(create_and_init_additional_record(packet, nb_flags, refresh_ip) == False)
+ return False;
+
+ DEBUG(4,("initiate_name_refresh_packet: sending refresh for name %s (bcast=%s) to IP %s\n",
+ nmb_namestr(&nmb->additional->rr_name),
+ BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+ return send_netbios_packet( packet );
+}
+
+/***************************************************************************
+ Sends out a name release.
+**************************************************************************/
+
+static bool initiate_name_release_packet( struct packet_struct *packet,
+ uint16 nb_flags, struct in_addr *release_ip)
+{
+ struct nmb_packet *nmb = &packet->packet.nmb;
+
+ nmb->header.opcode = NMB_NAME_RELEASE_OPCODE;
+ nmb->header.arcount = 1;
+
+ nmb->header.nm_flags.recursion_desired = False;
+
+ if(create_and_init_additional_record(packet, nb_flags, release_ip) == False)
+ return False;
+
+ DEBUG(4,("initiate_name_release_packet: sending release for name %s (bcast=%s) to IP %s\n",
+ nmb_namestr(&nmb->additional->rr_name),
+ BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+ return send_netbios_packet( packet );
+}
+
+/***************************************************************************
+ Sends out a node status.
+**************************************************************************/
+
+static bool initiate_node_status_packet( struct packet_struct *packet )
+{
+ struct nmb_packet *nmb = &packet->packet.nmb;
+
+ nmb->header.opcode = NMB_NAME_QUERY_OPCODE;
+ nmb->header.arcount = 0;
+
+ nmb->header.nm_flags.recursion_desired = False;
+
+ nmb->question.question_type = QUESTION_TYPE_NB_STATUS;
+
+ DEBUG(4,("initiate_node_status_packet: sending node status request for name %s to IP %s\n",
+ nmb_namestr(&nmb->question.question_name),
+ inet_ntoa(packet->ip)));
+
+ return send_netbios_packet( packet );
+}
+
+/****************************************************************************
+ Simplification functions for queuing standard packets.
+ These should be the only publicly callable functions for sending
+ out packets.
+****************************************************************************/
+
+/****************************************************************************
+ Assertion - we should never be sending nmbd packets on the remote
+ broadcast subnet.
+****************************************************************************/
+
+static bool assert_check_subnet(struct subnet_record *subrec)
+{
+ if( subrec == remote_broadcast_subnet) {
+ DEBUG(0,("assert_check_subnet: Attempt to send packet on remote broadcast subnet. \
+This is a bug.\n"));
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************************
+ Queue a register name packet to the broadcast address of a subnet.
+****************************************************************************/
+
+struct response_record *queue_register_name( struct subnet_record *subrec,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ register_name_success_function success_fn,
+ register_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ uint16 nb_flags)
+{
+ struct packet_struct *p;
+ struct response_record *rrec;
+ struct sockaddr_storage ss;
+ const struct sockaddr_storage *pss = NULL;
+ if(assert_check_subnet(subrec))
+ return NULL;
+
+ /* note that all name registration requests have RD set (rfc1002 - section 4.2.2 */
+ if ((p = create_and_init_netbios_packet(nmbname, (subrec != unicast_subnet), True,
+ subrec->bcast_ip)) == NULL)
+ return NULL;
+
+ in_addr_to_sockaddr_storage(&ss, subrec->bcast_ip);
+ pss = iface_ip(&ss);
+ if (!pss || pss->ss_family != AF_INET) {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ if(initiate_name_register_packet(p, nb_flags,
+ &((const struct sockaddr_in *)pss)->sin_addr) == 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 refresh name packet to the broadcast address of a subnet.
+****************************************************************************/
+
+void queue_wins_refresh(struct nmb_name *nmbname,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ uint16 nb_flags,
+ struct in_addr refresh_ip,
+ const char *tag)
+{
+ struct packet_struct *p;
+ struct response_record *rrec;
+ struct in_addr wins_ip;
+ struct userdata_struct *userdata;
+ fstring ip_str;
+
+ wins_ip = wins_srv_ip_tag(tag, refresh_ip);
+
+ if ((p = create_and_init_netbios_packet(nmbname, False, False, wins_ip)) == NULL) {
+ return;
+ }
+
+ if (!initiate_name_refresh_packet(p, nb_flags, &refresh_ip)) {
+ p->locked = False;
+ free_packet(p);
+ return;
+ }
+
+ fstrcpy(ip_str, inet_ntoa(refresh_ip));
+
+ DEBUG(6,("Refreshing name %s IP %s with WINS server %s using tag '%s'\n",
+ nmb_namestr(nmbname), ip_str, inet_ntoa(wins_ip), tag));
+
+ userdata = (struct userdata_struct *)SMB_MALLOC(sizeof(*userdata) + strlen(tag) + 1);
+ if (!userdata) {
+ p->locked = False;
+ free_packet(p);
+ DEBUG(0,("Failed to allocate userdata structure!\n"));
+ return;
+ }
+ ZERO_STRUCTP(userdata);
+ userdata->userdata_len = strlen(tag) + 1;
+ strlcpy(userdata->data, tag, userdata->userdata_len);
+
+ if ((rrec = make_response_record(unicast_subnet,
+ p,
+ resp_fn, timeout_fn,
+ NULL,
+ NULL,
+ userdata)) == NULL) {
+ p->locked = False;
+ free_packet(p);
+ return;
+ }
+
+ free(userdata);
+
+ /* we don't want to repeat refresh packets */
+ rrec->repeat_count = 0;
+}
+
+
+/****************************************************************************
+ Queue a multihomed register name packet to a given WINS server IP
+****************************************************************************/
+
+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 in_addr wins_ip)
+{
+ struct packet_struct *p;
+ struct response_record *rrec;
+ bool ret;
+
+ /* Sanity check. */
+ if(subrec != unicast_subnet) {
+ DEBUG(0,("queue_register_multihomed_name: should only be done on \
+unicast subnet. subnet is %s\n.", subrec->subnet_name ));
+ return NULL;
+ }
+
+ if(assert_check_subnet(subrec))
+ return NULL;
+
+ if ((p = create_and_init_netbios_packet(nmbname, False, True, wins_ip)) == NULL)
+ return NULL;
+
+ if (nb_flags & NB_GROUP)
+ ret = initiate_name_register_packet( p, nb_flags, &register_ip);
+ else
+ ret = initiate_multihomed_name_register_packet(p, nb_flags, &register_ip);
+
+ if (ret == False) {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ if ((rrec = make_response_record(subrec, /* subnet record. */
+ p, /* packet we sent. */
+ resp_fn, /* function to call on response. */
+ timeout_fn, /* function to call on timeout. */
+ (success_function)success_fn, /* function to call on operation success. */
+ (fail_function)fail_fn, /* function to call on operation fail. */
+ userdata)) == NULL) {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ return rrec;
+}
+
+/****************************************************************************
+ Queue a release name packet to the broadcast address of a subnet.
+****************************************************************************/
+
+struct response_record *queue_release_name( struct subnet_record *subrec,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ release_name_success_function success_fn,
+ release_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ uint16 nb_flags,
+ struct in_addr release_ip,
+ struct in_addr dest_ip)
+{
+ struct packet_struct *p;
+ struct response_record *rrec;
+
+ if(assert_check_subnet(subrec))
+ return NULL;
+
+ if ((p = create_and_init_netbios_packet(nmbname, (subrec != unicast_subnet), False, dest_ip)) == NULL)
+ return NULL;
+
+ if(initiate_name_release_packet( p, nb_flags, &release_ip) == False) {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ if((rrec = make_response_record(subrec, /* subnet record. */
+ p, /* packet we sent. */
+ resp_fn, /* function to call on response. */
+ timeout_fn, /* function to call on timeout. */
+ (success_function)success_fn, /* function to call on operation success. */
+ (fail_function)fail_fn, /* function to call on operation fail. */
+ userdata)) == NULL) {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ /*
+ * For a broadcast release packet, only send once.
+ * This will cause us to remove the name asap. JRA.
+ */
+
+ if (subrec != unicast_subnet) {
+ rrec->repeat_count = 0;
+ rrec->repeat_time = 0;
+ }
+
+ return rrec;
+}
+
+/****************************************************************************
+ Queue a 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;
+ struct in_addr to_ip;
+
+ if(assert_check_subnet(subrec))
+ return NULL;
+
+ to_ip = subrec->bcast_ip;
+
+ /* queries to the WINS server turn up here as queries to IP 0.0.0.0
+ These need to be handled a bit differently */
+ if (subrec->type == UNICAST_SUBNET && is_zero_ip_v4(to_ip)) {
+ /* What we really need to do is loop over each of our wins
+ * servers and wins server tags here, but that just doesn't
+ * fit our architecture at the moment (userdata may already
+ * be used when we get here). For now we just query the first
+ * active wins server on the first tag.
+ */
+ char **tags = wins_srv_tags();
+ if (!tags) {
+ return NULL;
+ }
+ to_ip = wins_srv_ip_tag(tags[0], to_ip);
+ wins_srv_tags_free(tags);
+ }
+
+ if(( p = create_and_init_netbios_packet(nmbname,
+ (subrec != unicast_subnet),
+ (subrec == unicast_subnet),
+ to_ip)) == NULL)
+ return NULL;
+
+ if(lp_bind_interfaces_only()) {
+ int i;
+
+ DEBUG(10,("queue_query_name: bind_interfaces_only is set, looking for suitable source IP\n"));
+ for(i = 0; i < iface_count(); i++) {
+ const struct in_addr *ifip = iface_n_ip_v4(i);
+
+ if (ifip == NULL) {
+ DEBUG(0,("queue_query_name: interface %d has NULL IP address !\n", i));
+ continue;
+ }
+
+ if (is_loopback_ip_v4(*ifip)) {
+ DEBUG(5,("queue_query_name: ignoring loopback interface (%d)\n", i));
+ continue;
+ }
+
+ DEBUG(10,("queue_query_name: using source IP %s\n",inet_ntoa(*ifip)));
+ p->fd = find_subnet_fd_for_address( *ifip );
+ break;
+ }
+ }
+
+ if(initiate_name_query_packet( p ) == False) {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ if((rrec = make_response_record(subrec, /* subnet record. */
+ p, /* packet we sent. */
+ resp_fn, /* function to call on response. */
+ timeout_fn, /* function to call on timeout. */
+ (success_function)success_fn, /* function to call on operation success. */
+ (fail_function)fail_fn, /* function to call on operation fail. */
+ userdata)) == NULL) {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ return rrec;
+}
+
+/****************************************************************************
+ Queue a query name packet to a given address from the WINS subnet.
+****************************************************************************/
+
+struct response_record *queue_query_name_from_wins_server( struct in_addr to_ip,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ query_name_success_function success_fn,
+ query_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname)
+{
+ struct packet_struct *p;
+ struct response_record *rrec;
+
+ if ((p = create_and_init_netbios_packet(nmbname, False, False, to_ip)) == NULL)
+ return NULL;
+
+ if(initiate_name_query_packet_from_wins_server( p ) == False) {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ if((rrec = make_response_record(wins_server_subnet, /* subnet record. */
+ p, /* packet we sent. */
+ resp_fn, /* function to call on response. */
+ timeout_fn, /* function to call on timeout. */
+ (success_function)success_fn, /* function to call on operation success. */
+ (fail_function)fail_fn, /* function to call on operation fail. */
+ userdata)) == NULL) {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ return rrec;
+}
+
+/****************************************************************************
+ Queue a node status packet to a given name and address.
+****************************************************************************/
+
+struct response_record *queue_node_status( struct subnet_record *subrec,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ node_status_success_function success_fn,
+ node_status_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ struct in_addr send_ip)
+{
+ struct packet_struct *p;
+ struct response_record *rrec;
+
+ /* Sanity check. */
+ if(subrec != unicast_subnet) {
+ DEBUG(0,("queue_register_multihomed_name: should only be done on \
+unicast subnet. subnet is %s\n.", subrec->subnet_name ));
+ return NULL;
+ }
+
+ if(assert_check_subnet(subrec))
+ return NULL;
+
+ if(( p = create_and_init_netbios_packet(nmbname, False, False, send_ip)) == NULL)
+ return NULL;
+
+ if(initiate_node_status_packet(p) == False) {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ if((rrec = make_response_record(subrec, /* subnet record. */
+ p, /* packet we sent. */
+ resp_fn, /* function to call on response. */
+ timeout_fn, /* function to call on timeout. */
+ (success_function)success_fn, /* function to call on operation success. */
+ (fail_function)fail_fn, /* function to call on operation fail. */
+ userdata)) == NULL) {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ return rrec;
+}
+
+/****************************************************************************
+ Reply to a netbios name packet. see rfc1002.txt
+****************************************************************************/
+
+void reply_netbios_packet(struct packet_struct *orig_packet,
+ int rcode, enum netbios_reply_type_code rcv_code, int opcode,
+ int ttl, char *data,int len)
+{
+ struct packet_struct packet;
+ struct nmb_packet *nmb = NULL;
+ struct res_rec answers;
+ struct nmb_packet *orig_nmb = &orig_packet->packet.nmb;
+ bool loopback_this_packet = False;
+ int rr_type = RR_TYPE_NB;
+ const char *packet_type = "unknown";
+
+ /* Check if we are sending to or from ourselves. */
+ if(ismyip_v4(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;
+ rr_type = RR_TYPE_NBSTAT;
+ break;
+ case NMB_QUERY:
+ packet_type = "nmb_query";
+ nmb->header.nm_flags.recursion_desired = True;
+ nmb->header.nm_flags.recursion_available = True;
+ if (rcode) {
+ rr_type = RR_TYPE_NULL;
+ }
+ 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;
+ rr_type = RR_TYPE_NULL;
+ 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;
+ if (rcode) {
+ rr_type = RR_TYPE_NULL;
+ }
+ break;
+ default:
+ DEBUG(0,("reply_netbios_packet: Unknown packet type: %s %s to ip %s\n",
+ packet_type, nmb_namestr(&orig_nmb->question.question_name),
+ inet_ntoa(packet.ip)));
+ return;
+ }
+
+ DEBUG(4,("reply_netbios_packet: sending a reply of packet type: %s %s to ip %s \
+for id %hu\n", packet_type, nmb_namestr(&orig_nmb->question.question_name),
+ inet_ntoa(packet.ip), orig_nmb->header.name_trn_id));
+
+ nmb->header.name_trn_id = orig_nmb->header.name_trn_id;
+ nmb->header.opcode = opcode;
+ nmb->header.response = True;
+ nmb->header.nm_flags.bcast = False;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = True;
+
+ nmb->header.rcode = rcode;
+ nmb->header.qdcount = 0;
+ nmb->header.ancount = 1;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+
+ memset((char*)&nmb->question,'\0',sizeof(nmb->question));
+
+ nmb->answers = &answers;
+ memset((char*)nmb->answers,'\0',sizeof(*nmb->answers));
+
+ nmb->answers->rr_name = orig_nmb->question.question_name;
+ nmb->answers->rr_type = rr_type;
+ nmb->answers->rr_class = RR_CLASS_IN;
+ nmb->answers->ttl = ttl;
+
+ if (data && len) {
+ if (len < 0 || len > sizeof(nmb->answers->rdata)) {
+ DEBUG(5,("reply_netbios_packet: "
+ "invalid packet len (%d)\n",
+ len ));
+ return;
+ }
+ 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
+******************************************************************/
+
+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_v4(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);
+ char scope[64];
+ unstring src_name;
+
+ /* Drop the packet if it's a different NetBIOS scope, or the source is from one of our names. */
+ pull_ascii(scope, dgram->dest_name.scope, 64, 64, STR_TERMINATE);
+ if (!strequal(scope, global_scope())) {
+ DEBUG(7,("process_browse_packet: Discarding datagram from IP %s. Scope (%s) \
+mismatch with our scope (%s).\n", inet_ntoa(p->ip), scope, global_scope()));
+ return;
+ }
+
+ pull_ascii_nstring(src_name, sizeof(src_name), dgram->source_name.name);
+ if (is_myname(src_name)) {
+ DEBUG(0,("process_browse_packet: Discarding datagram from IP %s. Source name \
+%s is one of our names !\n", inet_ntoa(p->ip), nmb_namestr(&dgram->source_name)));
+ return;
+ }
+
+ switch (command) {
+ case ANN_HostAnnouncement:
+ debug_browse_data(buf, len);
+ process_host_announce(subrec, p, buf+1);
+ break;
+ case ANN_DomainAnnouncement:
+ debug_browse_data(buf, len);
+ process_workgroup_announce(subrec, p, buf+1);
+ break;
+ case ANN_LocalMasterAnnouncement:
+ debug_browse_data(buf, len);
+ process_local_master_announce(subrec, p, buf+1);
+ break;
+ case ANN_AnnouncementRequest:
+ debug_browse_data(buf, len);
+ process_announce_request(subrec, p, buf+1);
+ break;
+ case ANN_Election:
+ debug_browse_data(buf, len);
+ process_election(subrec, p, buf+1);
+ break;
+ case ANN_GetBackupListReq:
+ debug_browse_data(buf, len);
+ process_get_backup_list_request(subrec, p, buf+1);
+ break;
+ case ANN_GetBackupListResp:
+ debug_browse_data(buf, len);
+ /* We never send ANN_GetBackupListReq so we should never get these. */
+ DEBUG(0,("process_browse_packet: Discarding GetBackupListResponse \
+packet from %s IP %s\n", nmb_namestr(&dgram->source_name), inet_ntoa(p->ip)));
+ break;
+ case ANN_ResetBrowserState:
+ debug_browse_data(buf, len);
+ process_reset_browser(subrec, p, buf+1);
+ break;
+ case ANN_MasterAnnouncement:
+ /* Master browser datagrams must be processed on the unicast subnet. */
+ subrec = unicast_subnet;
+
+ debug_browse_data(buf, len);
+ process_master_browser_announce(subrec, p, buf+1);
+ break;
+ case ANN_BecomeBackup:
+ /*
+ * We don't currently implement this. Log it just in case.
+ */
+ debug_browse_data(buf, len);
+ DEBUG(10,("process_browse_packet: On subnet %s ignoring browse packet \
+command ANN_BecomeBackup from %s IP %s to %s\n", subrec->subnet_name, nmb_namestr(&dgram->source_name),
+ inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
+ break;
+ default:
+ debug_browse_data(buf, len);
+ DEBUG(0,("process_browse_packet: On subnet %s ignoring browse packet \
+command code %d from %s IP %s to %s\n", subrec->subnet_name, command, nmb_namestr(&dgram->source_name),
+ inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
+ break;
+ }
+}
+
+/****************************************************************************
+ 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);
+ char scope[64];
+ unstring src_name;
+
+ /* Drop the packet if it's a different NetBIOS scope, or the source is from one of our names. */
+
+ pull_ascii(scope, dgram->dest_name.scope, 64, 64, STR_TERMINATE);
+ if (!strequal(scope, global_scope())) {
+ DEBUG(7,("process_lanman_packet: Discarding datagram from IP %s. Scope (%s) \
+mismatch with our scope (%s).\n", inet_ntoa(p->ip), scope, global_scope()));
+ return;
+ }
+
+ pull_ascii_nstring(src_name, sizeof(src_name), dgram->source_name.name);
+ if (is_myname(src_name)) {
+ DEBUG(0,("process_lanman_packet: Discarding datagram from IP %s. Source name \
+%s is one of our names !\n", inet_ntoa(p->ip), nmb_namestr(&dgram->source_name)));
+ return;
+ }
+
+ switch (command) {
+ case ANN_HostAnnouncement:
+ debug_browse_data(buf, len);
+ process_lm_host_announce(subrec, p, buf+1, len > 1 ? len-1 : 0);
+ break;
+ case ANN_AnnouncementRequest:
+ process_lm_announce_request(subrec, p, buf+1, len > 1 ? len-1 : 0);
+ break;
+ default:
+ DEBUG(0,("process_lanman_packet: On subnet %s ignoring browse packet \
+command code %d from %s IP %s to %s\n", subrec->subnet_name, command, nmb_namestr(&dgram->source_name),
+ inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
+ break;
+ }
+}
+
+/****************************************************************************
+ 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_v4(p->ip, subrec->bcast_ip, subrec->mask_ip))
+ break;
+ }
+
+ if(subrec == NULL)
+ subrec = unicast_subnet;
+
+ return (find_name_on_subnet(subrec, nbname, FIND_SELF_NAME) != NULL);
+}
+
+/****************************************************************************
+ Process udp 138 datagrams
+****************************************************************************/
+
+static void process_dgram(struct packet_struct *p)
+{
+ char *buf;
+ char *buf2;
+ int len;
+ struct dgram_packet *dgram = &p->packet.dgram;
+
+ /* If we aren't listening to the destination name then ignore the packet */
+ if (!listening(p,&dgram->dest_name)) {
+ unexpected_packet(p);
+ DEBUG(5,("process_dgram: ignoring dgram packet sent to name %s from %s\n",
+ nmb_namestr(&dgram->dest_name), inet_ntoa(p->ip)));
+ return;
+ }
+
+ if (dgram->header.msg_type != 0x10 && dgram->header.msg_type != 0x11 && dgram->header.msg_type != 0x12) {
+ unexpected_packet(p);
+ /* Don't process error packets etc yet */
+ DEBUG(5,("process_dgram: ignoring dgram packet sent to name %s from IP %s as it is \
+an error packet of type %x\n", nmb_namestr(&dgram->dest_name), inet_ntoa(p->ip), dgram->header.msg_type));
+ return;
+ }
+
+ /* Ensure we have a large enough packet before looking inside. */
+ if (dgram->datasize < (smb_vwv12 - 2)) {
+ /* That's the offset minus the 4 byte length + 2 bytes of offset. */
+ DEBUG(0,("process_dgram: ignoring too short dgram packet (%u) sent to name %s from IP %s\n",
+ (unsigned int)dgram->datasize,
+ nmb_namestr(&dgram->dest_name),
+ inet_ntoa(p->ip) ));
+ return;
+ }
+
+ buf = &dgram->data[0];
+ buf -= 4; /* XXXX for the pseudo tcp length - someday I need to get rid of this */
+
+ if (CVAL(buf,smb_com) != SMBtrans)
+ return;
+
+ len = SVAL(buf,smb_vwv11);
+ buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
+
+ if (len <= 0 || len > dgram->datasize) {
+ DEBUG(0,("process_dgram: ignoring malformed1 (datasize = %d, len = %d) datagram \
+packet sent to name %s from IP %s\n",
+ dgram->datasize,
+ len,
+ nmb_namestr(&dgram->dest_name),
+ inet_ntoa(p->ip) ));
+ return;
+ }
+
+ if (buf2 < dgram->data || (buf2 >= dgram->data + dgram->datasize)) {
+ DEBUG(0,("process_dgram: ignoring malformed2 (datasize = %d, len=%d, off=%d) datagram \
+packet sent to name %s from IP %s\n",
+ dgram->datasize,
+ len,
+ (int)PTR_DIFF(buf2, dgram->data),
+ nmb_namestr(&dgram->dest_name),
+ inet_ntoa(p->ip) ));
+ return;
+ }
+
+ if ((buf2 + len < dgram->data) || (buf2 + len > dgram->data + dgram->datasize)) {
+ DEBUG(0,("process_dgram: ignoring malformed3 (datasize = %d, len=%d, off=%d) datagram \
+packet sent to name %s from IP %s\n",
+ dgram->datasize,
+ len,
+ (int)PTR_DIFF(buf2, dgram->data),
+ nmb_namestr(&dgram->dest_name),
+ inet_ntoa(p->ip) ));
+ return;
+ }
+
+ DEBUG(4,("process_dgram: datagram from %s to %s IP %s for %s of type %d len=%d\n",
+ nmb_namestr(&dgram->source_name),nmb_namestr(&dgram->dest_name),
+ inet_ntoa(p->ip), smb_buf(buf),CVAL(buf2,0),len));
+
+ /* Datagram packet received for the browser mailslot */
+ if (strequal(smb_buf(buf),BROWSE_MAILSLOT)) {
+ process_browse_packet(p,buf2,len);
+ return;
+ }
+
+ /* Datagram packet received for the LAN Manager mailslot */
+ if (strequal(smb_buf(buf),LANMAN_MAILSLOT)) {
+ process_lanman_packet(p,buf2,len);
+ return;
+ }
+
+ /* Datagram packet received for the domain logon mailslot */
+ if (strequal(smb_buf(buf),NET_LOGON_MAILSLOT)) {
+ process_logon_packet(p,buf2,len,NET_LOGON_MAILSLOT);
+ return;
+ }
+
+ /* Datagram packet received for the NT domain logon mailslot */
+ if (strequal(smb_buf(buf),NT_LOGON_MAILSLOT)) {
+ process_logon_packet(p,buf2,len,NT_LOGON_MAILSLOT);
+ return;
+ }
+
+ unexpected_packet(p);
+}
+
+/****************************************************************************
+ Validate a response nmb packet.
+****************************************************************************/
+
+static bool validate_nmb_response_packet( struct nmb_packet *nmb )
+{
+ bool ignore = False;
+
+ switch (nmb->header.opcode) {
+ case NMB_NAME_REG_OPCODE:
+ case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
+ case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
+ if (nmb->header.ancount == 0) {
+ DEBUG(0,("validate_nmb_response_packet: Bad REG/REFRESH Packet. "));
+ ignore = True;
+ }
+ break;
+
+ case NMB_NAME_QUERY_OPCODE:
+ if ((nmb->header.ancount != 0) && (nmb->header.ancount != 1)) {
+ DEBUG(0,("validate_nmb_response_packet: Bad QUERY Packet. "));
+ ignore = True;
+ }
+ break;
+
+ case NMB_NAME_RELEASE_OPCODE:
+ if (nmb->header.ancount == 0) {
+ DEBUG(0,("validate_nmb_response_packet: Bad RELEASE Packet. "));
+ ignore = True;
+ }
+ break;
+
+ case NMB_WACK_OPCODE:
+ /* Check WACK response here. */
+ if (nmb->header.ancount != 1) {
+ DEBUG(0,("validate_nmb_response_packet: Bad WACK Packet. "));
+ ignore = True;
+ }
+ break;
+ default:
+ DEBUG(0,("validate_nmb_response_packet: Ignoring packet with unknown opcode %d.\n",
+ nmb->header.opcode));
+ return True;
+ }
+
+ if(ignore)
+ DEBUG(0,("Ignoring response packet with opcode %d.\n", nmb->header.opcode));
+
+ return ignore;
+}
+
+/****************************************************************************
+ Validate a request nmb packet.
+****************************************************************************/
+
+static bool validate_nmb_packet( struct nmb_packet *nmb )
+{
+ bool ignore = False;
+
+ switch (nmb->header.opcode) {
+ case NMB_NAME_REG_OPCODE:
+ case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
+ case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
+ case NMB_NAME_MULTIHOMED_REG_OPCODE:
+ if (nmb->header.qdcount==0 || nmb->header.arcount==0) {
+ DEBUG(0,("validate_nmb_packet: Bad REG/REFRESH Packet. "));
+ ignore = True;
+ }
+ break;
+
+ case NMB_NAME_QUERY_OPCODE:
+ if ((nmb->header.qdcount == 0) || ((nmb->question.question_type != QUESTION_TYPE_NB_QUERY) &&
+ (nmb->question.question_type != QUESTION_TYPE_NB_STATUS))) {
+ DEBUG(0,("validate_nmb_packet: Bad QUERY Packet. "));
+ ignore = True;
+ }
+ break;
+
+ case NMB_NAME_RELEASE_OPCODE:
+ if (nmb->header.qdcount==0 || nmb->header.arcount==0) {
+ DEBUG(0,("validate_nmb_packet: Bad RELEASE Packet. "));
+ ignore = True;
+ }
+ break;
+ default:
+ DEBUG(0,("validate_nmb_packet: Ignoring packet with unknown opcode %d.\n",
+ nmb->header.opcode));
+ return True;
+ }
+
+ if(ignore)
+ DEBUG(0,("validate_nmb_packet: Ignoring request packet with opcode %d.\n", nmb->header.opcode));
+
+ return ignore;
+}
+
+/****************************************************************************
+ Find a subnet (and potentially a response record) for a packet.
+****************************************************************************/
+
+static struct subnet_record *find_subnet_for_nmb_packet( struct packet_struct *p,
+ struct response_record **pprrec)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct response_record *rrec = NULL;
+ struct subnet_record *subrec = NULL;
+
+ if(pprrec != NULL)
+ *pprrec = NULL;
+
+ if(nmb->header.response) {
+ /* It's a response packet. Find a record for it or it's an error. */
+
+ rrec = find_response_record( &subrec, nmb->header.name_trn_id);
+ if(rrec == NULL) {
+ DEBUG(3,("find_subnet_for_nmb_packet: response record not found for response id %hu\n",
+ nmb->header.name_trn_id));
+ unexpected_packet(p);
+ return NULL;
+ }
+
+ if(subrec == NULL) {
+ DEBUG(0,("find_subnet_for_nmb_packet: subnet record not found for response id %hu\n",
+ nmb->header.name_trn_id));
+ return NULL;
+ }
+
+ if(pprrec != NULL)
+ *pprrec = rrec;
+ return subrec;
+ }
+
+ /* Try and see what subnet this packet belongs to. */
+
+ /* WINS server ? */
+ if(packet_is_for_wins_server(p))
+ return wins_server_subnet;
+
+ /* If it wasn't a broadcast packet then send to the UNICAST subnet. */
+ if(nmb->header.nm_flags.bcast == False)
+ return unicast_subnet;
+
+ /* Go through all the broadcast subnets and see if the mask matches. */
+ for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+ if(same_net_v4(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;
+
+ restart:
+
+ 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 = t + rrec->repeat_interval;
+ rrec->repeat_count--;
+ } else {
+ DEBUG(4,("retransmit_or_expire_response_records: timeout for packet id %hu to IP %s \
+on subnet %s\n", rrec->response_id, inet_ntoa(rrec->packet->ip), subrec->subnet_name));
+
+ /*
+ * Check the flag in this record to prevent recursion if we end
+ * up in this function again via the timeout function call.
+ */
+
+ if(!rrec->in_expiration_processing) {
+
+ /*
+ * Set the recursion protection flag in this record.
+ */
+
+ rrec->in_expiration_processing = True;
+
+ /* Call the timeout function. This will deal with removing the
+ timed out packet. */
+ if(rrec->timeout_fn) {
+ (*rrec->timeout_fn)(subrec, rrec);
+ } else {
+ /* We must remove the record ourself if there is
+ no timeout function. */
+ remove_response_record(subrec, rrec);
+ }
+ /* We have changed subrec->responselist,
+ * restart from the beginning of this list. */
+ goto restart;
+ } /* !rrec->in_expitation_processing */
+ } /* rrec->repeat_count > 0 */
+ } /* rrec->repeat_time <= t */
+ } /* end for rrec */
+ } /* end for subnet */
+}
+
+/****************************************************************************
+ Create an fd_set containing all the sockets in the subnet structures,
+ plus the broadcast sockets.
+***************************************************************************/
+
+static bool create_listen_fdset(fd_set **ppset, int **psock_array, int *listen_number, int *maxfd)
+{
+ int *sock_array = NULL;
+ struct subnet_record *subrec = NULL;
+ int count = 0;
+ int num = 0;
+ fd_set *pset = SMB_MALLOC_P(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));
+ SAFE_FREE(pset);
+ return True;
+ }
+
+ if((sock_array = SMB_MALLOC_ARRAY(int, (count*2) + 2)) == NULL) {
+ DEBUG(0,("create_listen_fdset: malloc fail for socket array.\n"));
+ SAFE_FREE(pset);
+ return True;
+ }
+
+ FD_ZERO(pset);
+
+ /* Add in the broadcast socket on 137. */
+ FD_SET(ClientNMB,pset);
+ sock_array[num++] = ClientNMB;
+ *maxfd = MAX( *maxfd, 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;
+ *maxfd = MAX( *maxfd, subrec->nmb_sock);
+ }
+
+ /* Add in the broadcast socket on 138. */
+ FD_SET(ClientDGRAM,pset);
+ sock_array[num++] = ClientDGRAM;
+ *maxfd = MAX( *maxfd, 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;
+ *maxfd = MAX( *maxfd, subrec->dgram_sock);
+ }
+
+ *listen_number = (count*2) + 2;
+
+ SAFE_FREE(*ppset);
+ SAFE_FREE(*psock_array);
+
+ *ppset = pset;
+ *psock_array = sock_array;
+
+ return False;
+}
+
+/****************************************************************************
+ Listens for NMB or DGRAM packets, and queues them.
+ return True if the socket is dead
+***************************************************************************/
+
+bool listen_for_packets(bool run_election)
+{
+ static fd_set *listen_set = NULL;
+ static int listen_number = 0;
+ static int *sock_array = NULL;
+ int i;
+ static int maxfd = 0;
+
+ fd_set r_fds;
+ fd_set w_fds;
+ int selrtn;
+ struct timeval timeout;
+#ifndef SYNC_DNS
+ int dns_fd;
+#endif
+
+ if(listen_set == NULL || rescan_listen_set) {
+ if(create_listen_fdset(&listen_set, &sock_array, &listen_number, &maxfd)) {
+ DEBUG(0,("listen_for_packets: Fatal error. unable to create listen set. Exiting.\n"));
+ return True;
+ }
+ rescan_listen_set = False;
+ }
+
+ memcpy((char *)&r_fds, (char *)listen_set, sizeof(fd_set));
+ FD_ZERO(&w_fds);
+
+#ifndef SYNC_DNS
+ dns_fd = asyncdns_fd();
+ if (dns_fd != -1) {
+ FD_SET(dns_fd, &r_fds);
+ maxfd = MAX( maxfd, dns_fd);
+ }
+#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;
+
+ {
+ struct timeval now = timeval_current();
+ event_add_to_select_args(nmbd_event_context(), &now,
+ &r_fds, &w_fds, &timeout, &maxfd);
+ }
+
+ if (timeval_is_zero(&timeout)) {
+ /* Process a timed event now... */
+ if (run_events(nmbd_event_context(), 0, NULL, NULL)) {
+ return False;
+ }
+ }
+
+ /* Prepare for the select - allow certain signals. */
+
+ BlockSignals(False, SIGTERM);
+
+ selrtn = sys_select(maxfd+1,&r_fds,&w_fds,NULL,&timeout);
+
+ /* We can only take signals when we are in the select - block them again here. */
+
+ BlockSignals(True, SIGTERM);
+
+ if(selrtn == -1) {
+ return False;
+ }
+
+ if (run_events(nmbd_event_context(), selrtn, &r_fds, &w_fds)) {
+ return False;
+ }
+
+#ifndef SYNC_DNS
+ if (dns_fd != -1 && FD_ISSET(dns_fd,&r_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],&r_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_v4(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 ((is_loopback_ip_v4(packet->ip) ||
+ ismyip_v4(packet->ip)) && packet->port == global_nmb_port &&
+ packet->packet.nmb.header.nm_flags.bcast) {
+ DEBUG(7,("discarding own bcast 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],&r_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_v4(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 ((is_loopback_ip_v4(packet->ip) ||
+ ismyip_v4(packet->ip)) && packet->port == DGRAM_PORT) {
+ DEBUG(7,("discarding own dgram packet from %s:%d\n",
+ inet_ntoa(packet->ip),packet->port));
+ free_packet(packet);
+ } else {
+ /* Save the file descriptor this packet came in on. */
+ packet->fd = sock_array[i];
+ queue_packet(packet);
+ }
+ }
+ }
+ } /* end processing 138 socket. */
+ } /* end for */
+ return False;
+}
+
+/****************************************************************************
+ Construct and send a netbios DGRAM.
+**************************************************************************/
+
+bool send_mailslot(bool unique, const char *mailslot,char *buf, size_t len,
+ const char *srcname, int src_type,
+ const char *dstname, int dest_type,
+ struct in_addr dest_ip,struct in_addr src_ip,
+ int dest_port)
+{
+ bool loopback_this_packet = False;
+ struct packet_struct p;
+ struct dgram_packet *dgram = &p.packet.dgram;
+ char *ptr,*p2;
+ char tmp[4];
+
+ memset((char *)&p,'\0',sizeof(p));
+
+ if(ismyip_v4(dest_ip) && (dest_port == DGRAM_PORT)) /* Only if to DGRAM_PORT */
+ loopback_this_packet = True;
+
+ /* generate_name_trn_id(); */ /* Not used, so gone, RJS */
+
+ /* DIRECT GROUP or UNIQUE datagram. */
+ dgram->header.msg_type = unique ? 0x10 : 0x11;
+ dgram->header.flags.node_type = M_NODE;
+ dgram->header.flags.first = True;
+ dgram->header.flags.more = False;
+ dgram->header.dgm_id = generate_name_trn_id();
+ dgram->header.source_ip = src_ip;
+ dgram->header.source_port = DGRAM_PORT;
+ dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
+ dgram->header.packet_offset = 0;
+
+ make_nmb_name(&dgram->source_name,srcname,src_type);
+ make_nmb_name(&dgram->dest_name,dstname,dest_type);
+
+ ptr = &dgram->data[0];
+
+ /* Setup the smb part. */
+ ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
+ memcpy(tmp,ptr,4);
+
+ if (smb_size + 17*2 + strlen(mailslot) + 1 + len > MAX_DGRAM_SIZE) {
+ DEBUG(0, ("send_mailslot: Cannot write beyond end of packet\n"));
+ return false;
+ }
+
+ cli_set_message(ptr,17,strlen(mailslot) + 1 + len,True);
+ memcpy(ptr,tmp,4);
+
+ SCVAL(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);
+ safe_strcpy_base(p2, mailslot, dgram->data, sizeof(dgram->data));
+ p2 = skip_string(ptr,MAX_DGRAM_SIZE,p2);
+
+ if (((p2+len) > dgram->data+sizeof(dgram->data)) || ((p2+len) < p2)) {
+ DEBUG(0, ("send_mailslot: Cannot write beyond end of packet\n"));
+ return False;
+ } else {
+ memcpy(p2,buf,len);
+ p2 += len;
+ }
+
+ dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
+
+ p.ip = dest_ip;
+ p.port = dest_port;
+ p.fd = find_subnet_mailslot_fd_for_address( src_ip );
+ p.timestamp = time(NULL);
+ p.packet_type = DGRAM_PACKET;
+
+ DEBUG(4,("send_mailslot: Sending to mailslot %s from %s IP %s ", mailslot,
+ nmb_namestr(&dgram->source_name), inet_ntoa(src_ip)));
+ DEBUG(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name), inet_ntoa(dest_ip)));
+
+ debug_browse_data(buf, len);
+
+ if(loopback_this_packet) {
+ struct packet_struct *lo_packet = NULL;
+ DEBUG(5,("send_mailslot: sending packet to ourselves.\n"));
+ if((lo_packet = copy_packet(&p)) == NULL)
+ return False;
+ queue_packet(lo_packet);
+ return True;
+ } else {
+ return(send_packet(&p));
+ }
+}
diff --git a/source3/nmbd/nmbd_processlogon.c b/source3/nmbd/nmbd_processlogon.c
new file mode 100644
index 0000000000..474ae1ca18
--- /dev/null
+++ b/source3/nmbd/nmbd_processlogon.c
@@ -0,0 +1,695 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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-2003
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Revision History:
+
+*/
+
+#include "includes.h"
+
+struct sam_database_info {
+ uint32 index;
+ uint32 serial_lo, serial_hi;
+ uint32 date_lo, date_hi;
+};
+
+/**
+ * check whether the client belongs to the hosts
+ * for which initial logon should be delayed...
+ */
+static bool delay_logon(const char *peer_name, const char *peer_addr)
+{
+ const char **delay_list = lp_init_logon_delayed_hosts();
+ const char *peer[2];
+
+ if (delay_list == NULL) {
+ return False;
+ }
+
+ peer[0] = peer_name;
+ peer[1] = peer_addr;
+
+ return list_match(delay_list, (const char *)peer, client_match);
+}
+
+static void delayed_init_logon_handler(struct event_context *event_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ struct packet_struct *p = (struct packet_struct *)private_data;
+
+ DEBUG(10, ("delayed_init_logon_handler (%lx): re-queuing packet.\n",
+ (unsigned long)te));
+
+ queue_packet(p);
+
+ TALLOC_FREE(te);
+}
+
+/****************************************************************************
+Process a domain logon packet
+**************************************************************************/
+
+void process_logon_packet(struct packet_struct *p, char *buf,int len,
+ const char *mailslot)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ fstring my_name;
+ fstring reply_name;
+ char outbuf[1024];
+ int code;
+ uint16 token = 0;
+ uint32 ntversion = 0;
+ uint16 lmnttoken = 0;
+ uint16 lm20token = 0;
+ uint32 domainsidsize;
+ bool short_request = False;
+ char *getdc;
+ char *uniuser; /* Unicode user name. */
+ fstring ascuser;
+ char *unicomp; /* Unicode computer name. */
+ size_t size;
+ struct sockaddr_storage ss;
+ const struct sockaddr_storage *pss;
+ struct in_addr ip;
+
+ in_addr_to_sockaddr_storage(&ss, p->ip);
+ pss = iface_ip(&ss);
+ if (!pss) {
+ DEBUG(5,("process_logon_packet:can't find outgoing interface "
+ "for packet from IP %s\n",
+ inet_ntoa(p->ip) ));
+ return;
+ }
+ ip = ((struct sockaddr_in *)pss)->sin_addr;
+
+ memset(outbuf, 0, sizeof(outbuf));
+
+ if (!lp_domain_logons()) {
+ DEBUG(5,("process_logon_packet: Logon packet received from IP %s and domain \
+logons are not enabled.\n", inet_ntoa(p->ip) ));
+ return;
+ }
+
+ fstrcpy(my_name, global_myname());
+
+ code = get_safe_SVAL(buf,len,buf,0,-1);
+ DEBUG(4,("process_logon_packet: Logon from %s: code = 0x%x\n", inet_ntoa(p->ip), code));
+
+ switch (code) {
+ case 0:
+ {
+ fstring mach_str, user_str, getdc_str;
+ char *q = buf + 2;
+ char *machine = q;
+ char *user = skip_string(buf,len,machine);
+
+ if (!user || PTR_DIFF(user, buf) >= len) {
+ DEBUG(0,("process_logon_packet: bad packet\n"));
+ return;
+ }
+ getdc = skip_string(buf,len,user);
+
+ if (!getdc || PTR_DIFF(getdc, buf) >= len) {
+ DEBUG(0,("process_logon_packet: bad packet\n"));
+ return;
+ }
+ q = skip_string(buf,len,getdc);
+
+ if (!q || PTR_DIFF(q + 5, buf) > len) {
+ DEBUG(0,("process_logon_packet: bad packet\n"));
+ return;
+ }
+ token = SVAL(q,3);
+
+ fstrcpy(reply_name,my_name);
+
+ pull_ascii_fstring(mach_str, machine);
+ pull_ascii_fstring(user_str, user);
+ pull_ascii_fstring(getdc_str, getdc);
+
+ DEBUG(5,("process_logon_packet: Domain login request from %s at IP %s user=%s token=%x\n",
+ mach_str,inet_ntoa(p->ip),user_str,token));
+
+ q = outbuf;
+ SSVAL(q, 0, 6);
+ q += 2;
+
+ fstrcpy(reply_name, "\\\\");
+ fstrcat(reply_name, my_name);
+ size = push_ascii(q,reply_name,
+ sizeof(outbuf)-PTR_DIFF(q, outbuf),
+ STR_TERMINATE);
+ if (size == (size_t)-1) {
+ return;
+ }
+ q = skip_string(outbuf,sizeof(outbuf),q); /* PDC name */
+
+ SSVAL(q, 0, token);
+ q += 2;
+
+ dump_data(4, (uint8 *)outbuf, PTR_DIFF(q, outbuf));
+
+ send_mailslot(True, getdc_str,
+ outbuf,PTR_DIFF(q,outbuf),
+ global_myname(), 0x0,
+ mach_str,
+ dgram->source_name.name_type,
+ p->ip, ip, p->port);
+ break;
+ }
+
+ case QUERYFORPDC:
+ {
+ fstring mach_str, getdc_str;
+ fstring source_name;
+ char *q = buf + 2;
+ char *machine = q;
+
+ if (!lp_domain_master()) {
+ /* We're not Primary Domain Controller -- ignore this */
+ return;
+ }
+
+ getdc = skip_string(buf,len,machine);
+
+ if (!getdc || PTR_DIFF(getdc, buf) >= len) {
+ DEBUG(0,("process_logon_packet: bad packet\n"));
+ return;
+ }
+ q = skip_string(buf,len,getdc);
+
+ if (!q || PTR_DIFF(q, buf) >= len) {
+ DEBUG(0,("process_logon_packet: bad packet\n"));
+ return;
+ }
+ q = ALIGN2(q, buf);
+
+ /* At this point we can work out if this is a W9X or NT style
+ request. Experiments show that the difference is wether the
+ packet ends here. For a W9X request we now end with a pair of
+ bytes (usually 0xFE 0xFF) whereas with NT we have two further
+ strings - the following is a simple way of detecting this */
+
+ if (len - PTR_DIFF(q, buf) <= 3) {
+ short_request = True;
+ } else {
+ unicomp = q;
+
+ if (PTR_DIFF(q, buf) >= len) {
+ DEBUG(0,("process_logon_packet: bad packet\n"));
+ return;
+ }
+
+ /* A full length (NT style) request */
+ q = skip_unibuf(unicomp, PTR_DIFF(buf + len, unicomp));
+
+ if (PTR_DIFF(q, buf) >= len) {
+ DEBUG(0,("process_logon_packet: bad packet\n"));
+ return;
+ }
+
+ if (len - PTR_DIFF(q, buf) > 8) {
+ /* with NT5 clients we can sometimes
+ get additional data - a length specificed string
+ containing the domain name, then 16 bytes of
+ data (no idea what it is) */
+ int dom_len = CVAL(q, 0);
+ q++;
+ if (dom_len != 0) {
+ q += dom_len + 1;
+ }
+ q += 16;
+ }
+
+ if (PTR_DIFF(q + 8, buf) > len) {
+ DEBUG(0,("process_logon_packet: bad packet\n"));
+ return;
+ }
+
+ ntversion = IVAL(q, 0);
+ lmnttoken = SVAL(q, 4);
+ lm20token = SVAL(q, 6);
+ }
+
+ /* Construct reply. */
+ q = outbuf;
+ SSVAL(q, 0, QUERYFORPDC_R);
+ q += 2;
+
+ fstrcpy(reply_name,my_name);
+ size = push_ascii(q, reply_name,
+ sizeof(outbuf)-PTR_DIFF(q, outbuf),
+ STR_TERMINATE);
+ if (size == (size_t)-1) {
+ return;
+ }
+ q = skip_string(outbuf,sizeof(outbuf),q); /* PDC name */
+
+ /* PDC and domain name */
+ if (!short_request) {
+ /* Make a full reply */
+ q = ALIGN2(q, outbuf);
+
+ q += dos_PutUniCode(q, my_name,
+ sizeof(outbuf) - PTR_DIFF(q, outbuf),
+ True); /* PDC name */
+ q += dos_PutUniCode(q, lp_workgroup(),
+ sizeof(outbuf) - PTR_DIFF(q, outbuf),
+ True); /* Domain name*/
+ if (sizeof(outbuf) - PTR_DIFF(q, outbuf) < 8) {
+ return;
+ }
+ SIVAL(q, 0, 1); /* our nt version */
+ SSVAL(q, 4, 0xffff); /* our lmnttoken */
+ SSVAL(q, 6, 0xffff); /* our lm20token */
+ q += 8;
+ }
+
+ /* RJS, 21-Feb-2000, we send a short reply if the request was short */
+
+ pull_ascii_fstring(mach_str, machine);
+
+ DEBUG(5,("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",
+ mach_str,inet_ntoa(p->ip), reply_name, lp_workgroup(),
+ QUERYFORPDC_R, (uint32)ntversion, (uint32)lmnttoken,
+ (uint32)lm20token ));
+
+ dump_data(4, (uint8 *)outbuf, PTR_DIFF(q, outbuf));
+
+ pull_ascii_fstring(getdc_str, getdc);
+ pull_ascii_nstring(source_name, sizeof(source_name), dgram->source_name.name);
+
+ send_mailslot(True, getdc_str,
+ outbuf,PTR_DIFF(q,outbuf),
+ global_myname(), 0x0,
+ source_name,
+ dgram->source_name.name_type,
+ p->ip, ip, p->port);
+ return;
+ }
+
+ case SAMLOGON:
+
+ {
+ fstring getdc_str;
+ fstring source_name;
+ char *source_addr;
+ char *q = buf + 2;
+ fstring asccomp;
+
+ q += 2;
+
+ if (PTR_DIFF(q, buf) >= len) {
+ DEBUG(0,("process_logon_packet: bad packet\n"));
+ return;
+ }
+
+ unicomp = q;
+ uniuser = skip_unibuf(unicomp, PTR_DIFF(buf+len, unicomp));
+
+ if (PTR_DIFF(uniuser, buf) >= len) {
+ DEBUG(0,("process_logon_packet: bad packet\n"));
+ return;
+ }
+
+ getdc = skip_unibuf(uniuser,PTR_DIFF(buf+len, uniuser));
+
+ if (PTR_DIFF(getdc, buf) >= len) {
+ DEBUG(0,("process_logon_packet: bad packet\n"));
+ return;
+ }
+
+ q = skip_string(buf,len,getdc);
+
+ if (!q || PTR_DIFF(q + 8, buf) >= len) {
+ DEBUG(0,("process_logon_packet: bad packet\n"));
+ return;
+ }
+
+ q += 4; /* Account Control Bits - indicating username type */
+ domainsidsize = IVAL(q, 0);
+ q += 4;
+
+ DEBUG(5,("process_logon_packet: SAMLOGON sidsize %d, len = %d\n", domainsidsize, len));
+
+ if (domainsidsize < (len - PTR_DIFF(q, buf)) && (domainsidsize != 0)) {
+ q += domainsidsize;
+ q = ALIGN4(q, buf);
+ }
+
+ DEBUG(5,("process_logon_packet: len = %d PTR_DIFF(q, buf) = %ld\n", len, (unsigned long)PTR_DIFF(q, buf) ));
+
+ if (len - PTR_DIFF(q, buf) > 8) {
+ /* with NT5 clients we can sometimes
+ get additional data - a length specificed string
+ containing the domain name, then 16 bytes of
+ data (no idea what it is) */
+ int dom_len = CVAL(q, 0);
+ q++;
+ if (dom_len < (len - PTR_DIFF(q, buf)) && (dom_len != 0)) {
+ q += dom_len + 1;
+ }
+ q += 16;
+ }
+
+ if (PTR_DIFF(q + 8, buf) > len) {
+ DEBUG(0,("process_logon_packet: bad packet\n"));
+ return;
+ }
+
+ ntversion = IVAL(q, 0);
+ lmnttoken = SVAL(q, 4);
+ lm20token = SVAL(q, 6);
+ q += 8;
+
+ DEBUG(3,("process_logon_packet: SAMLOGON sidsize %d ntv %d\n", domainsidsize, ntversion));
+
+ /*
+ * we respond regadless of whether the machine is in our password
+ * database. If it isn't then we let smbd send an appropriate error.
+ * Let's ignore the SID.
+ */
+ pull_ucs2_fstring(ascuser, uniuser);
+ pull_ucs2_fstring(asccomp, unicomp);
+ DEBUG(5,("process_logon_packet: SAMLOGON user %s\n", ascuser));
+
+ fstrcpy(reply_name, "\\\\"); /* Here it wants \\LOGONSERVER. */
+ fstrcat(reply_name, my_name);
+
+ DEBUG(5,("process_logon_packet: SAMLOGON request from %s(%s) for %s, returning logon svr %s domain %s code %x token=%x\n",
+ asccomp,inet_ntoa(p->ip), ascuser, reply_name, lp_workgroup(),
+ SAMLOGON_R ,lmnttoken));
+
+ /* Construct reply. */
+
+ q = outbuf;
+ /* we want the simple version unless we are an ADS PDC..which means */
+ /* never, at least for now */
+ if ((ntversion < 11) || (SEC_ADS != lp_security()) || (ROLE_DOMAIN_PDC != lp_server_role())) {
+ if (SVAL(uniuser, 0) == 0) {
+ SSVAL(q, 0, SAMLOGON_UNK_R); /* user unknown */
+ } else {
+ SSVAL(q, 0, SAMLOGON_R);
+ }
+
+ q += 2;
+
+ q += dos_PutUniCode(q, reply_name,
+ sizeof(outbuf) - PTR_DIFF(q, outbuf),
+ True);
+ q += dos_PutUniCode(q, ascuser,
+ sizeof(outbuf) - PTR_DIFF(q, outbuf),
+ True);
+ q += dos_PutUniCode(q, lp_workgroup(),
+ sizeof(outbuf) - PTR_DIFF(q, outbuf),
+ True);
+ }
+#ifdef HAVE_ADS
+ else {
+ struct GUID domain_guid;
+ UUID_FLAT flat_guid;
+ char *domain;
+ char *hostname;
+ char *component, *dc, *q1;
+ char *q_orig = q;
+ int str_offset;
+ char *saveptr = NULL;
+
+ domain = get_mydnsdomname(talloc_tos());
+ if (!domain) {
+ DEBUG(2,
+ ("get_mydnsdomname failed.\n"));
+ return;
+ }
+ hostname = get_myname(talloc_tos());
+ if (!hostname) {
+ DEBUG(2,
+ ("get_myname failed.\n"));
+ return;
+ }
+
+ if (sizeof(outbuf) - PTR_DIFF(q, outbuf) < 8) {
+ return;
+ }
+ if (SVAL(uniuser, 0) == 0) {
+ SIVAL(q, 0, SAMLOGON_AD_UNK_R); /* user unknown */
+ } else {
+ SIVAL(q, 0, SAMLOGON_AD_R);
+ }
+ q += 4;
+
+ SIVAL(q, 0, NBT_SERVER_PDC|NBT_SERVER_GC|NBT_SERVER_LDAP|NBT_SERVER_DS|
+ NBT_SERVER_KDC|NBT_SERVER_TIMESERV|NBT_SERVER_CLOSEST|NBT_SERVER_WRITABLE);
+ q += 4;
+
+ /* Push Domain GUID */
+ if (sizeof(outbuf) - PTR_DIFF(q, outbuf) < UUID_FLAT_SIZE) {
+ return;
+ }
+ if (False == secrets_fetch_domain_guid(domain, &domain_guid)) {
+ DEBUG(2, ("Could not fetch DomainGUID for %s\n", domain));
+ return;
+ }
+
+ smb_uuid_pack(domain_guid, &flat_guid);
+ memcpy(q, &flat_guid.info, UUID_FLAT_SIZE);
+ q += UUID_FLAT_SIZE;
+
+ /* Forest */
+ str_offset = q - q_orig;
+ dc = domain;
+ q1 = q;
+ while ((component = strtok_r(dc, ".", &saveptr)) != NULL) {
+ dc = NULL;
+ if (sizeof(outbuf) - PTR_DIFF(q, outbuf) < 1) {
+ return;
+ }
+ size = push_ascii(&q[1], component,
+ sizeof(outbuf) - PTR_DIFF(q+1, outbuf),
+ 0);
+ if (size == (size_t)-1 || size > 0xff) {
+ return;
+ }
+ SCVAL(q, 0, size);
+ q += (size + 1);
+ }
+
+ /* Unk0 */
+ if (sizeof(outbuf) - PTR_DIFF(q, outbuf) < 4) {
+ return;
+ }
+ SCVAL(q, 0, 0);
+ q++;
+
+ /* Domain */
+ SCVAL(q, 0, 0xc0 | ((str_offset >> 8) & 0x3F));
+ SCVAL(q, 1, str_offset & 0xFF);
+ q += 2;
+
+ /* Hostname */
+ size = push_ascii(&q[1], hostname,
+ sizeof(outbuf) - PTR_DIFF(q+1, outbuf),
+ 0);
+ if (size == (size_t)-1 || size > 0xff) {
+ return;
+ }
+ SCVAL(q, 0, size);
+ q += (size + 1);
+
+ if (sizeof(outbuf) - PTR_DIFF(q, outbuf) < 3) {
+ return;
+ }
+
+ SCVAL(q, 0, 0xc0 | ((str_offset >> 8) & 0x3F));
+ SCVAL(q, 1, str_offset & 0xFF);
+ q += 2;
+
+ /* NETBIOS of domain */
+ size = push_ascii(&q[1], lp_workgroup(),
+ sizeof(outbuf) - PTR_DIFF(q+1, outbuf),
+ STR_UPPER);
+ if (size == (size_t)-1 || size > 0xff) {
+ return;
+ }
+ SCVAL(q, 0, size);
+ q += (size + 1);
+
+ /* Unk1 */
+ if (sizeof(outbuf) - PTR_DIFF(q, outbuf) < 2) {
+ return;
+ }
+
+ SCVAL(q, 0, 0);
+ q++;
+
+ /* NETBIOS of hostname */
+ size = push_ascii(&q[1], my_name,
+ sizeof(outbuf) - PTR_DIFF(q+1, outbuf),
+ 0);
+ if (size == (size_t)-1 || size > 0xff) {
+ return;
+ }
+ SCVAL(q, 0, size);
+ q += (size + 1);
+
+ /* Unk2 */
+ if (sizeof(outbuf) - PTR_DIFF(q, outbuf) < 4) {
+ return;
+ }
+
+ SCVAL(q, 0, 0);
+ q++;
+
+ /* User name */
+ if (SVAL(uniuser, 0) != 0) {
+ size = push_ascii(&q[1], ascuser,
+ sizeof(outbuf) - PTR_DIFF(q+1, outbuf),
+ 0);
+ if (size == (size_t)-1 || size > 0xff) {
+ return;
+ }
+ SCVAL(q, 0, size);
+ q += (size + 1);
+ }
+
+ q_orig = q;
+ /* Site name */
+ if (sizeof(outbuf) - PTR_DIFF(q, outbuf) < 1) {
+ return;
+ }
+ size = push_ascii(&q[1], "Default-First-Site-Name",
+ sizeof(outbuf) - PTR_DIFF(q+1, outbuf),
+ 0);
+ if (size == (size_t)-1 || size > 0xff) {
+ return;
+ }
+ SCVAL(q, 0, size);
+ q += (size + 1);
+
+ if (sizeof(outbuf) - PTR_DIFF(q, outbuf) < 18) {
+ return;
+ }
+
+ /* Site name (2) */
+ str_offset = q - q_orig;
+ SCVAL(q, 0, 0xc0 | ((str_offset >> 8) & 0x3F));
+ SCVAL(q, 1, str_offset & 0xFF);
+ q += 2;
+
+ SCVAL(q, 0, PTR_DIFF(q,q1));
+ SCVAL(q, 1, 0x10); /* unknown */
+
+ SIVAL(q, 0, 0x00000002);
+ q += 4; /* unknown */
+ SIVAL(q, 0, ntohl(ip.s_addr));
+ q += 4;
+ SIVAL(q, 0, 0x00000000);
+ q += 4; /* unknown */
+ SIVAL(q, 0, 0x00000000);
+ q += 4; /* unknown */
+ }
+#endif
+
+ if (sizeof(outbuf) - PTR_DIFF(q, outbuf) < 8) {
+ return;
+ }
+
+ /* tell the client what version we are */
+ SIVAL(q, 0, ((ntversion < 11) || (SEC_ADS != lp_security())) ? 1 : 13);
+ /* our ntversion */
+ SSVAL(q, 4, 0xffff); /* our lmnttoken */
+ SSVAL(q, 6, 0xffff); /* our lm20token */
+ q += 8;
+
+ dump_data(4, (uint8 *)outbuf, PTR_DIFF(q, outbuf));
+
+ pull_ascii_fstring(getdc_str, getdc);
+ pull_ascii_nstring(source_name, sizeof(source_name), dgram->source_name.name);
+ source_addr = SMB_STRDUP(inet_ntoa(dgram->header.source_ip));
+ if (source_addr == NULL) {
+ DEBUG(3, ("out of memory copying client"
+ " address string\n"));
+ return;
+ }
+
+ /*
+ * handle delay.
+ * packets requeued after delay are marked as
+ * locked.
+ */
+ if ((p->locked == False) &&
+ (strlen(ascuser) == 0) &&
+ delay_logon(source_name, source_addr))
+ {
+ struct timeval when;
+
+ DEBUG(3, ("process_logon_packet: "
+ "delaying initial logon "
+ "reply for client %s(%s) for "
+ "%u milliseconds\n",
+ source_name, source_addr,
+ lp_init_logon_delay()));
+
+ when = timeval_current_ofs(0,
+ lp_init_logon_delay() * 1000);
+ p->locked = true;
+ event_add_timed(nmbd_event_context(),
+ NULL,
+ when,
+ "delayed_init_logon",
+ delayed_init_logon_handler,
+ p);
+ } else {
+ DEBUG(3, ("process_logon_packet: "
+ "processing delayed initial "
+ "logon reply for client "
+ "%s(%s)\n",
+ source_name, source_addr));
+
+ p->locked = false;
+ send_mailslot(true, getdc,
+ outbuf,PTR_DIFF(q,outbuf),
+ global_myname(), 0x0,
+ source_name,
+ dgram->source_name.name_type,
+ p->ip, ip, p->port);
+ }
+
+ SAFE_FREE(source_addr);
+
+ break;
+ }
+
+ /* Announce change to UAS or SAM. Send by the domain controller when a
+ replication event is required. */
+
+ case SAM_UAS_CHANGE:
+ DEBUG(5, ("Got SAM_UAS_CHANGE\n"));
+ break;
+
+ default:
+ DEBUG(3,("process_logon_packet: Unknown domain request %d\n",code));
+ return;
+ }
+}
diff --git a/source3/nmbd/nmbd_responserecordsdb.c b/source3/nmbd/nmbd_responserecordsdb.c
new file mode 100644
index 0000000000..b042fb41ed
--- /dev/null
+++ b/source3/nmbd/nmbd_responserecordsdb.c
@@ -0,0 +1,243 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+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)
+{
+ 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));
+
+ DLIST_ADD_END(subrec->responselist, rrec, struct response_record *);
+}
+
+/***************************************************************************
+ Remove an expected response record from the list
+ **************************************************************************/
+
+void remove_response_record(struct subnet_record *subrec,
+ struct response_record *rrec)
+{
+ /* It is possible this can be called twice,
+ with a rrec pointer that has been freed. So
+ before we inderect into rrec, search for it
+ on the responselist first. Bug #3617. JRA. */
+
+ struct response_record *p = NULL;
+
+ for (p = subrec->responselist; p; p = p->next) {
+ if (p == rrec) {
+ break;
+ }
+ }
+
+ if (p == NULL) {
+ /* We didn't find rrec on the list. */
+ return;
+ }
+
+ DLIST_REMOVE(subrec->responselist, rrec);
+
+ if(rrec->userdata) {
+ if(rrec->userdata->free_fn) {
+ (*rrec->userdata->free_fn)(rrec->userdata);
+ } else {
+ ZERO_STRUCTP(rrec->userdata);
+ SAFE_FREE(rrec->userdata);
+ }
+ }
+
+ /* Ensure we can delete. */
+ rrec->packet->locked = False;
+ free_packet(rrec->packet);
+
+ ZERO_STRUCTP(rrec);
+ SAFE_FREE(rrec);
+
+ num_response_packets--; /* count of total number of packets still around */
+}
+
+/****************************************************************************
+ Create a response record for an outgoing packet.
+ **************************************************************************/
+
+struct response_record *make_response_record( struct subnet_record *subrec,
+ struct packet_struct *p,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ success_function success_fn,
+ fail_function fail_fn,
+ struct userdata_struct *userdata)
+{
+ struct response_record *rrec;
+ struct nmb_packet *nmb = &p->packet.nmb;
+
+ if (!(rrec = SMB_MALLOC_P(struct response_record))) {
+ DEBUG(0,("make_response_queue_record: malloc fail for response_record.\n"));
+ return NULL;
+ }
+
+ memset((char *)rrec, '\0', sizeof(*rrec));
+
+ rrec->response_id = nmb->header.name_trn_id;
+
+ rrec->resp_fn = resp_fn;
+ rrec->timeout_fn = timeout_fn;
+ rrec->success_fn = success_fn;
+ rrec->fail_fn = fail_fn;
+
+ rrec->packet = p;
+
+ if(userdata) {
+ /* Intelligent userdata. */
+ if(userdata->copy_fn) {
+ if((rrec->userdata = (*userdata->copy_fn)(userdata)) == NULL) {
+ DEBUG(0,("make_response_queue_record: copy fail for userdata.\n"));
+ ZERO_STRUCTP(rrec);
+ SAFE_FREE(rrec);
+ return NULL;
+ }
+ } else {
+ /* Primitive userdata, do a memcpy. */
+ if((rrec->userdata = (struct userdata_struct *)
+ SMB_MALLOC(sizeof(struct userdata_struct)+userdata->userdata_len)) == NULL) {
+ DEBUG(0,("make_response_queue_record: malloc fail for userdata.\n"));
+ ZERO_STRUCTP(rrec);
+ SAFE_FREE(rrec);
+ return NULL;
+ }
+ rrec->userdata->copy_fn = userdata->copy_fn;
+ rrec->userdata->free_fn = userdata->free_fn;
+ rrec->userdata->userdata_len = userdata->userdata_len;
+ memcpy(rrec->userdata->data, userdata->data, userdata->userdata_len);
+ }
+ } else {
+ rrec->userdata = NULL;
+ }
+
+ rrec->num_msgs = 0;
+
+ if(!nmb->header.nm_flags.bcast)
+ rrec->repeat_interval = 5; /* 5 seconds for unicast packets. */
+ else
+ rrec->repeat_interval = 1; /* XXXX should be in ms */
+ rrec->repeat_count = 3; /* 3 retries */
+ rrec->repeat_time = time(NULL) + rrec->repeat_interval; /* initial retry time */
+
+ /* This packet is not being processed. */
+ rrec->in_expiration_processing = False;
+
+ /* Lock the packet so we won't lose it while it's on the list. */
+ p->locked = True;
+
+ add_response_record(subrec, rrec);
+
+ return rrec;
+}
+
+/****************************************************************************
+ Find a response in a subnet's name query response list.
+ **************************************************************************/
+
+static struct response_record *find_response_record_on_subnet(
+ struct subnet_record *subrec, uint16 id)
+{
+ struct response_record *rrec = NULL;
+
+ for (rrec = subrec->responselist; rrec; rrec = rrec->next) {
+ if (rrec->response_id == id) {
+ DEBUG(4, ("find_response_record: found response record id = %hu on subnet %s\n",
+ id, subrec->subnet_name));
+ break;
+ }
+ }
+ return rrec;
+}
+
+/****************************************************************************
+ Find a response in any subnet's name query response list.
+ **************************************************************************/
+
+struct response_record *find_response_record(struct subnet_record **ppsubrec,
+ uint16 id)
+{
+ struct response_record *rrec = NULL;
+
+ for ((*ppsubrec) = FIRST_SUBNET; (*ppsubrec);
+ (*ppsubrec) = NEXT_SUBNET_INCLUDING_UNICAST(*ppsubrec)) {
+ if((rrec = find_response_record_on_subnet(*ppsubrec, id)) != NULL)
+ return rrec;
+ }
+
+ /* There should never be response records on the remote_broadcast subnet.
+ Sanity check to ensure this is so. */
+ if(remote_broadcast_subnet->responselist != NULL) {
+ DEBUG(0,("find_response_record: response record found on subnet %s. This should \
+never happen !\n", remote_broadcast_subnet->subnet_name));
+ }
+
+ /* Now check the WINS server subnet if it exists. */
+ if(wins_server_subnet != NULL) {
+ *ppsubrec = wins_server_subnet;
+ if((rrec = find_response_record_on_subnet(*ppsubrec, id))!= NULL)
+ return rrec;
+ }
+
+ DEBUG(3,("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/source3/nmbd/nmbd_sendannounce.c b/source3/nmbd/nmbd_sendannounce.c
new file mode 100644
index 0000000000..3cc9bb52b0
--- /dev/null
+++ b/source3/nmbd/nmbd_sendannounce.c
@@ -0,0 +1,586 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+extern int updatecount;
+extern bool found_lm_clients;
+
+/****************************************************************************
+ Send a browser reset packet.
+**************************************************************************/
+
+void send_browser_reset(int reset_type, const char *to_name, int to_type, struct in_addr to_ip)
+{
+ char outbuf[1024];
+ char *p;
+
+ DEBUG(3,("send_browser_reset: sending reset request type %d to %s<%02x> IP %s.\n",
+ reset_type, to_name, to_type, inet_ntoa(to_ip) ));
+
+ memset(outbuf,'\0',sizeof(outbuf));
+ p = outbuf;
+ SCVAL(p,0,ANN_ResetBrowserState);
+ p++;
+ SCVAL(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)
+{
+ char outbuf[1024];
+ char *p;
+
+ work->needannounce = True;
+
+ DEBUG(3,("broadcast_announce_request: sending announce request for workgroup %s \
+to subnet %s\n", work->work_group, subrec->subnet_name));
+
+ memset(outbuf,'\0',sizeof(outbuf));
+ p = outbuf;
+ SCVAL(p,0,ANN_AnnouncementRequest);
+ p++;
+
+ SCVAL(p,0,work->token); /* (local) Unique workgroup token id. */
+ p++;
+ p += push_string(NULL, p+1, global_myname(), 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
+
+ send_mailslot(False, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
+ global_myname(), 0x0, work->work_group,0x1e, subrec->bcast_ip,
+ subrec->myip, DGRAM_PORT);
+}
+
+/****************************************************************************
+ Broadcast an announcement.
+ **************************************************************************/
+
+static void send_announcement(struct subnet_record *subrec, int announce_type,
+ const char *from_name, const char *to_name, int to_type, struct in_addr to_ip,
+ time_t announce_interval,
+ const char *server_name, int server_type, const char *server_comment)
+{
+ char outbuf[1024];
+ unstring upper_server_name;
+ char *p;
+
+ memset(outbuf,'\0',sizeof(outbuf));
+ p = outbuf+1;
+
+ SCVAL(outbuf,0,announce_type);
+
+ /* Announcement parameters. */
+ SCVAL(p,0,updatecount);
+ SIVAL(p,1,announce_interval*1000); /* Milliseconds - despite the spec. */
+
+ safe_strcpy(upper_server_name, server_name, sizeof(upper_server_name)-1);
+ strupper_m(upper_server_name);
+ push_string(NULL, p+5, upper_server_name, 16, STR_ASCII|STR_TERMINATE);
+
+ SCVAL(p,21,lp_major_announce_version()); /* Major version. */
+ SCVAL(p,22,lp_minor_announce_version()); /* Minor version. */
+
+ SIVAL(p,23,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
+ /* Browse version: got from NT/AS 4.00 - Value defined in smb.h (JHT). */
+ SSVAL(p,27,BROWSER_ELECTION_VERSION);
+ SSVAL(p,29,BROWSER_CONSTANT); /* Browse signature. */
+
+ p += 31 + push_string(NULL, p+31, server_comment, sizeof(outbuf) - (p + 31 - outbuf), STR_ASCII|STR_TERMINATE);
+
+ send_mailslot(False,BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
+ from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
+ DGRAM_PORT);
+}
+
+/****************************************************************************
+ Broadcast a LanMan announcement.
+**************************************************************************/
+
+static void send_lm_announcement(struct subnet_record *subrec, int announce_type,
+ char *from_name, char *to_name, int to_type, struct in_addr to_ip,
+ time_t announce_interval,
+ char *server_name, int server_type, char *server_comment)
+{
+ char outbuf[1024];
+ char *p=outbuf;
+
+ memset(outbuf,'\0',sizeof(outbuf));
+
+ SSVAL(p,0,announce_type);
+ SIVAL(p,2,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
+ SCVAL(p,6,lp_major_announce_version()); /* Major version. */
+ SCVAL(p,7,lp_minor_announce_version()); /* Minor version. */
+ SSVAL(p,8,announce_interval); /* In seconds - according to spec. */
+
+ p += 10;
+ p += push_string(NULL, p, server_name, 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
+ p += push_string(NULL, p, server_comment, sizeof(outbuf)- (p - outbuf), STR_ASCII|STR_UPPER|STR_TERMINATE);
+
+ send_mailslot(False,LANMAN_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
+ from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
+ DGRAM_PORT);
+}
+
+/****************************************************************************
+ We are a local master browser. Announce this to WORKGROUP<1e>.
+****************************************************************************/
+
+static void send_local_master_announcement(struct subnet_record *subrec, struct work_record *work,
+ struct server_record *servrec)
+{
+ /* Ensure we don't have the prohibited bit set. */
+ uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ DEBUG(3,("send_local_master_announcement: type %x for name %s on subnet %s for workgroup %s\n",
+ type, global_myname(), subrec->subnet_name, work->work_group));
+
+ send_announcement(subrec, ANN_LocalMasterAnnouncement,
+ global_myname(), /* From nbt name. */
+ work->work_group, 0x1e, /* To nbt name. */
+ subrec->bcast_ip, /* To ip. */
+ work->announce_interval, /* Time until next announce. */
+ global_myname(), /* Name to announce. */
+ type, /* Type field. */
+ servrec->serv.comment);
+}
+
+/****************************************************************************
+ Announce the workgroup WORKGROUP to MSBROWSE<01>.
+****************************************************************************/
+
+static void send_workgroup_announcement(struct subnet_record *subrec, struct work_record *work)
+{
+ DEBUG(3,("send_workgroup_announcement: on subnet %s for workgroup %s\n",
+ subrec->subnet_name, work->work_group));
+
+ send_announcement(subrec, ANN_DomainAnnouncement,
+ global_myname(), /* From nbt name. */
+ MSBROWSE, 0x1, /* To nbt name. */
+ subrec->bcast_ip, /* To ip. */
+ work->announce_interval, /* Time until next announce. */
+ work->work_group, /* Name to announce. */
+ SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT, /* workgroup announce flags. */
+ global_myname()); /* From name as comment. */
+}
+
+/****************************************************************************
+ Announce the given host to WORKGROUP<1d>.
+****************************************************************************/
+
+static void send_host_announcement(struct subnet_record *subrec, struct work_record *work,
+ struct server_record *servrec)
+{
+ /* Ensure we don't have the prohibited bits set. */
+ uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ DEBUG(3,("send_host_announcement: type %x for host %s on subnet %s for workgroup %s\n",
+ type, servrec->serv.name, subrec->subnet_name, work->work_group));
+
+ send_announcement(subrec, ANN_HostAnnouncement,
+ servrec->serv.name, /* From nbt name. */
+ work->work_group, 0x1d, /* To nbt name. */
+ subrec->bcast_ip, /* To ip. */
+ work->announce_interval, /* Time until next announce. */
+ servrec->serv.name, /* Name to announce. */
+ type, /* Type field. */
+ servrec->serv.comment);
+}
+
+/****************************************************************************
+ Announce the given LanMan host
+****************************************************************************/
+
+static void send_lm_host_announcement(struct subnet_record *subrec, struct work_record *work,
+ struct server_record *servrec, int lm_interval)
+{
+ /* Ensure we don't have the prohibited bits set. */
+ uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ DEBUG(3,("send_lm_host_announcement: type %x for host %s on subnet %s for workgroup %s, ttl: %d\n",
+ type, servrec->serv.name, subrec->subnet_name, work->work_group, lm_interval));
+
+ send_lm_announcement(subrec, ANN_HostAnnouncement,
+ servrec->serv.name, /* From nbt name. */
+ work->work_group, 0x00, /* To nbt name. */
+ subrec->bcast_ip, /* To ip. */
+ lm_interval, /* Time until next announce. */
+ servrec->serv.name, /* Name to announce (fstring not netbios name struct). */
+ 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, lp_workgroup());
+
+ 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, lp_workgroup());
+
+ 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;
+ const char *ptr;
+ static time_t last_time = 0;
+ char *s2;
+ struct in_addr addr;
+ char *comment;
+ int stype = lp_default_server_announce();
+ TALLOC_CTX *frame = NULL;
+
+ if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
+ return;
+
+ last_time = t;
+
+ s = lp_remote_announce();
+ if (!*s)
+ return;
+
+ comment = string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH);
+
+ frame = talloc_stackframe();
+ for (ptr=s; next_token_talloc(frame,&ptr,&s2,NULL); ) {
+ /* The entries are of the form a.b.c.d/WORKGROUP with
+ WORKGROUP being optional */
+ const char *wgroup;
+ char *pwgroup;
+ int i;
+
+ pwgroup = strchr_m(s2,'/');
+ if (pwgroup)
+ *pwgroup++ = 0;
+ if (!pwgroup || !*pwgroup)
+ wgroup = lp_workgroup();
+ else
+ wgroup = pwgroup;
+
+ (void)interpret_addr2(&addr,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++) {
+ const 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);
+ }
+ }
+ TALLOC_FREE(frame);
+}
+
+/****************************************************************************
+ 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;
+ const char *ptr;
+ static time_t last_time = 0;
+ char *s2;
+ struct in_addr addr;
+ struct work_record *work;
+ char outbuf[1024];
+ char *p;
+ unstring myname;
+ TALLOC_CTX *frame = NULL;
+
+ 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, lp_workgroup())) == NULL) {
+ DEBUG(0,("browse_sync_remote: Cannot find workgroup %s on subnet %s\n",
+ lp_workgroup(), 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", lp_workgroup(), FIRST_SUBNET->subnet_name ));
+ return;
+ }
+
+ memset(outbuf,'\0',sizeof(outbuf));
+ p = outbuf;
+ SCVAL(p,0,ANN_MasterAnnouncement);
+ p++;
+
+ unstrcpy(myname, global_myname());
+ strupper_m(myname);
+ myname[15]='\0';
+ push_ascii(p, myname, sizeof(outbuf)-PTR_DIFF(p,outbuf)-1, STR_TERMINATE);
+
+ p = skip_string(outbuf,sizeof(outbuf),p);
+
+ frame = talloc_stackframe();
+ for (ptr=s; next_token_talloc(frame,&ptr,&s2,NULL); ) {
+ /* The entries are of the form a.b.c.d */
+ (void)interpret_addr2(&addr,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);
+ }
+ TALLOC_FREE(frame);
+}
diff --git a/source3/nmbd/nmbd_serverlistdb.c b/source3/nmbd/nmbd_serverlistdb.c
new file mode 100644
index 0000000000..349c3f4df3
--- /dev/null
+++ b/source3/nmbd/nmbd_serverlistdb.c
@@ -0,0 +1,431 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+int updatecount = 0;
+
+/*******************************************************************
+ Remove all the servers in a work group.
+ ******************************************************************/
+
+void remove_all_servers(struct work_record *work)
+{
+ struct server_record *servrec;
+ struct server_record *nexts;
+
+ for (servrec = work->serverlist; servrec; servrec = nexts) {
+ DEBUG(7,("remove_all_servers: Removing server %s\n",servrec->serv.name));
+ nexts = servrec->next;
+
+ if (servrec->prev)
+ servrec->prev->next = servrec->next;
+ if (servrec->next)
+ servrec->next->prev = servrec->prev;
+
+ if (work->serverlist == servrec)
+ work->serverlist = servrec->next;
+
+ ZERO_STRUCTP(servrec);
+ SAFE_FREE(servrec);
+ }
+
+ work->subnet->work_changed = True;
+}
+
+/***************************************************************************
+ Add a server into the a workgroup serverlist.
+ **************************************************************************/
+
+static void add_server_to_workgroup(struct work_record *work,
+ struct server_record *servrec)
+{
+ struct server_record *servrec2;
+
+ if (!work->serverlist) {
+ work->serverlist = servrec;
+ servrec->prev = NULL;
+ servrec->next = NULL;
+ return;
+ }
+
+ for (servrec2 = work->serverlist; servrec2->next; servrec2 = servrec2->next)
+ ;
+
+ servrec2->next = servrec;
+ servrec->next = NULL;
+ servrec->prev = servrec2;
+ work->subnet->work_changed = True;
+}
+
+/****************************************************************************
+ Find a server in a server list.
+ **************************************************************************/
+
+struct server_record *find_server_in_workgroup(struct work_record *work, const char *name)
+{
+ struct server_record *ret;
+
+ for (ret = work->serverlist; ret; ret = ret->next) {
+ if (strequal(ret->serv.name,name))
+ return ret;
+ }
+ return NULL;
+}
+
+
+/****************************************************************************
+ Remove a server entry from this workgroup.
+ ****************************************************************************/
+
+void remove_server_from_workgroup(struct work_record *work, struct server_record *servrec)
+{
+ if (servrec->prev)
+ servrec->prev->next = servrec->next;
+ if (servrec->next)
+ servrec->next->prev = servrec->prev;
+
+ if (work->serverlist == servrec)
+ work->serverlist = servrec->next;
+
+ ZERO_STRUCTP(servrec);
+ SAFE_FREE(servrec);
+ work->subnet->work_changed = True;
+}
+
+/****************************************************************************
+ Create a server entry on this workgroup.
+ ****************************************************************************/
+
+struct server_record *create_server_on_workgroup(struct work_record *work,
+ const char *name,int servertype,
+ int ttl, const 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 = SMB_MALLOC_P(struct server_record)) == NULL) {
+ DEBUG(0,("create_server_entry_on_workgroup: malloc fail !\n"));
+ return NULL;
+ }
+
+ memset((char *)servrec,'\0',sizeof(*servrec));
+
+ servrec->subnet = work->subnet;
+
+ fstrcpy(servrec->serv.name,name);
+ fstrcpy(servrec->serv.comment,comment);
+ strupper_m(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 && (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 lp_workgroup() (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(lp_workgroup(), 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_entry(XFILE *fp, const char *name, uint32 rec_type,
+ const char *local_master_browser_name, const char *description)
+{
+ fstring tmp;
+
+ slprintf(tmp,sizeof(tmp)-1, "\"%s\"", name);
+ x_fprintf(fp, "%-25s ", tmp);
+ x_fprintf(fp, "%08x ", rec_type);
+ slprintf(tmp, sizeof(tmp)-1, "\"%s\" ", local_master_browser_name);
+ x_fprintf(fp, "%-30s", tmp);
+ x_fprintf(fp, "\"%s\"\n", description);
+}
+
+void write_browse_list(time_t t, bool force_write)
+{
+ struct subnet_record *subrec;
+ struct work_record *work;
+ struct server_record *servrec;
+ char *fname;
+ char *fnamenew;
+ uint32 stype;
+ int i;
+ XFILE *fp;
+ bool list_changed = force_write;
+ static time_t lasttime = 0;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ /* 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++;
+
+ fname = talloc_strdup(ctx, lp_lockdir());
+ if (!fname) {
+ return;
+ }
+ trim_char(fname,'\0' ,'/');
+ fname = talloc_asprintf_append(fname,
+ "/%s",
+ SERVER_LIST);
+ if (!fname) {
+ return;
+ }
+ fnamenew = talloc_asprintf(ctx, "%s.",
+ fname);
+ if (!fnamenew) {
+ return;
+ }
+
+ fp = x_fopen(fnamenew,O_WRONLY|O_CREAT|O_TRUNC, 0644);
+
+ if (!fp) {
+ DEBUG(0,("write_browse_list: Can't open file %s. Error was %s\n",
+ fnamenew,strerror(errno)));
+ return;
+ }
+
+ /*
+ * Write out a record for our workgroup. Use the record from the first
+ * subnet.
+ */
+
+ if((work = find_workgroup_on_subnet(FIRST_SUBNET, lp_workgroup())) == NULL) {
+ DEBUG(0,("write_browse_list: Fatal error - cannot find my workgroup %s\n",
+ lp_workgroup()));
+ x_fclose(fp);
+ return;
+ }
+
+ write_browse_list_entry(fp, work->work_group,
+ SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT|SV_TYPE_LOCAL_LIST_ONLY,
+ work->local_master_browser_name, 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, lp_workgroup() )) == 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. */
+ write_browse_list_entry(fp, my_netbios_names(i), stype,
+ string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH), lp_workgroup());
+ }
+
+ 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) {
+ write_browse_list_entry(fp, work->work_group, wg_type,
+ work->local_master_browser_name,
+ 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. */
+ write_browse_list_entry(fp, servrec->serv.name, serv_type,
+ servrec->serv.comment, work->work_group);
+ }
+ }
+ }
+ }
+
+ x_fclose(fp);
+ unlink(fname);
+ chmod(fnamenew,0644);
+ rename(fnamenew,fname);
+ DEBUG(3,("write_browse_list: Wrote browse list into file %s\n",fname));
+}
diff --git a/source3/nmbd/nmbd_subnetdb.c b/source3/nmbd/nmbd_subnetdb.c
new file mode 100644
index 0000000000..225def52cc
--- /dev/null
+++ b/source3/nmbd/nmbd_subnetdb.c
@@ -0,0 +1,389 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Revision History:
+
+*/
+
+#include "includes.h"
+
+extern int global_nmb_port;
+
+/* This is the broadcast subnets database. */
+struct subnet_record *subnetlist = NULL;
+
+/* Extra subnets - keep these separate so enumeration code doesn't
+ run onto it by mistake. */
+
+struct subnet_record *unicast_subnet = NULL;
+struct subnet_record *remote_broadcast_subnet = NULL;
+struct subnet_record *wins_server_subnet = NULL;
+
+extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
+
+/****************************************************************************
+ Add a subnet into the list.
+ **************************************************************************/
+
+static void add_subnet(struct subnet_record *subrec)
+{
+ DLIST_ADD(subnetlist, subrec);
+}
+
+/****************************************************************************
+stop listening on a subnet
+we don't free the record as we don't have proper reference counting for it
+yet and it may be in use by a response record
+ ****************************************************************************/
+
+void close_subnet(struct subnet_record *subrec)
+{
+ if (subrec->dgram_sock != -1) {
+ close(subrec->dgram_sock);
+ subrec->dgram_sock = -1;
+ }
+ if (subrec->nmb_sock != -1) {
+ close(subrec->nmb_sock);
+ subrec->nmb_sock = -1;
+ }
+
+ DLIST_REMOVE(subnetlist, subrec);
+}
+
+/****************************************************************************
+ Create a subnet entry.
+ ****************************************************************************/
+
+static struct subnet_record *make_subnet(const 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 {
+ struct sockaddr_storage ss;
+
+ in_addr_to_sockaddr_storage(&ss, myip);
+
+ /*
+ * 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, &ss,true)) == -1) {
+ if( DEBUGLVL( 0 ) ) {
+ Debug1( "nmbd_subnetdb:make_subnet()\n" );
+ Debug1( " Failed to open nmb socket on interface %s ", inet_ntoa(myip) );
+ Debug1( "for port %d. ", global_nmb_port );
+ Debug1( "Error was %s\n", strerror(errno) );
+ }
+ return NULL;
+ }
+
+ if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, &ss, true)) == -1) {
+ if( DEBUGLVL( 0 ) ) {
+ Debug1( "nmbd_subnetdb:make_subnet()\n" );
+ Debug1( " Failed to open dgram socket on interface %s ", inet_ntoa(myip) );
+ Debug1( "for port %d. ", DGRAM_PORT );
+ Debug1( "Error was %s\n", strerror(errno) );
+ }
+ return NULL;
+ }
+
+ /* Make sure we can broadcast from these sockets. */
+ set_socket_options(nmb_sock,"SO_BROADCAST");
+ set_socket_options(dgram_sock,"SO_BROADCAST");
+
+ /* Set them non-blocking. */
+ set_blocking(nmb_sock, False);
+ set_blocking(dgram_sock, False);
+ }
+
+ subrec = SMB_MALLOC_P(struct subnet_record);
+ if (!subrec) {
+ DEBUG(0,("make_subnet: malloc fail !\n"));
+ if (nmb_sock != -1) {
+ close(nmb_sock);
+ }
+ if (dgram_sock != -1) {
+ close(dgram_sock);
+ }
+ return(NULL);
+ }
+
+ ZERO_STRUCTP(subrec);
+
+ if((subrec->subnet_name = SMB_STRDUP(name)) == NULL) {
+ DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
+ if (nmb_sock != -1) {
+ close(nmb_sock);
+ }
+ if (dgram_sock != -1) {
+ close(dgram_sock);
+ }
+ ZERO_STRUCTP(subrec);
+ SAFE_FREE(subrec);
+ return(NULL);
+ }
+
+ DEBUG(2, ("making subnet name:%s ", name ));
+ DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip)));
+ DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip)));
+
+ subrec->namelist_changed = False;
+ subrec->work_changed = False;
+
+ subrec->bcast_ip = bcast_ip;
+ subrec->mask_ip = mask_ip;
+ subrec->myip = myip;
+ subrec->type = type;
+ subrec->nmb_sock = nmb_sock;
+ subrec->dgram_sock = dgram_sock;
+
+ return subrec;
+}
+
+/****************************************************************************
+ Create a normal subnet
+**************************************************************************/
+
+struct subnet_record *make_normal_subnet(const struct interface *iface)
+{
+
+ struct subnet_record *subrec;
+ const struct in_addr *pip = &((const struct sockaddr_in *)&iface->ip)->sin_addr;
+ const struct in_addr *pbcast = &((const struct sockaddr_in *)&iface->bcast)->sin_addr;
+ const struct in_addr *pnmask = &((const struct sockaddr_in *)&iface->netmask)->sin_addr;
+
+ subrec = make_subnet(inet_ntoa(*pip), NORMAL_SUBNET,
+ *pip, *pbcast, *pnmask);
+ if (subrec) {
+ add_subnet(subrec);
+ }
+ return subrec;
+}
+
+/****************************************************************************
+ Create subnet entries.
+**************************************************************************/
+
+bool create_subnets(void)
+{
+ /* We only count IPv4 interfaces whilst we're waiting. */
+ int num_interfaces;
+ int i;
+ struct in_addr unicast_ip, ipzero;
+
+ try_interfaces_again:
+
+ /* Only count IPv4, non-loopback interfaces. */
+ if (iface_count_v4_nl() == 0) {
+ DEBUG(0,("create_subnets: No local IPv4 non-loopback interfaces !\n"));
+ DEBUG(0,("create_subnets: Waiting for an interface to appear ...\n"));
+ }
+
+ /* We only count IPv4, non-loopback interfaces here. */
+ while (iface_count_v4_nl() == 0) {
+ void (*saved_handler)(int);
+
+ /*
+ * Whilst we're waiting for an interface, allow SIGTERM to
+ * cause us to exit.
+ */
+
+ saved_handler = CatchSignal( SIGTERM, SIGNAL_CAST SIG_DFL );
+
+ sleep(5);
+ load_interfaces();
+
+ /*
+ * We got an interface, restore our normal term handler.
+ */
+
+ CatchSignal( SIGTERM, SIGNAL_CAST saved_handler );
+ }
+
+ /*
+ * Here we count v4 and v6 - we know there's at least one
+ * IPv4 interface and we filter on it below.
+ */
+ num_interfaces = iface_count();
+
+ /*
+ * Create subnets from all the local interfaces and thread them onto
+ * the linked list.
+ */
+
+ for (i = 0 ; i < num_interfaces; i++) {
+ const struct interface *iface = get_interface(i);
+
+ if (!iface) {
+ DEBUG(2,("create_subnets: can't get interface %d.\n", i ));
+ continue;
+ }
+
+ /* Ensure we're only dealing with IPv4 here. */
+ if (iface->ip.ss_family != AF_INET) {
+ DEBUG(2,("create_subnets: "
+ "ignoring non IPv4 interface.\n"));
+ continue;
+ }
+
+ /*
+ * We don't want to add a loopback interface, in case
+ * someone has added 127.0.0.1 for smbd, nmbd needs to
+ * ignore it here. JRA.
+ */
+
+ if (is_loopback_addr(&iface->ip)) {
+ DEBUG(2,("create_subnets: Ignoring loopback interface.\n" ));
+ continue;
+ }
+
+ if (!make_normal_subnet(iface))
+ return False;
+ }
+
+ /* We must have at least one subnet. */
+ if (subnetlist == NULL) {
+ void (*saved_handler)(int);
+
+ DEBUG(0,("create_subnets: Unable to create any subnet from "
+ "given interfaces. Is your interface line in "
+ "smb.conf correct ?\n"));
+
+ saved_handler = CatchSignal( SIGTERM, SIGNAL_CAST SIG_DFL );
+
+ sleep(5);
+ load_interfaces();
+
+ CatchSignal( SIGTERM, SIGNAL_CAST saved_handler );
+ goto try_interfaces_again;
+ }
+
+ if (lp_we_are_a_wins_server()) {
+ /* Pick the first interface IPv4 address as the WINS server ip. */
+ const struct in_addr *nip = first_ipv4_iface();
+
+ if (!nip) {
+ return False;
+ }
+
+ unicast_ip = *nip;
+ } else {
+ /* note that we do not set the wins server IP here. We just
+ set it at zero and let the wins registration code cope
+ with getting the IPs right for each packet */
+ zero_ip_v4(&unicast_ip);
+ }
+
+ /*
+ * Create the unicast and remote broadcast subnets.
+ * Don't put these onto the linked list.
+ * The ip address of the unicast subnet is set to be
+ * the WINS server address, if it exists, or ipzero if not.
+ */
+
+ unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET,
+ unicast_ip, unicast_ip, unicast_ip);
+
+ zero_ip_v4(&ipzero);
+
+ remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
+ REMOTE_BROADCAST_SUBNET,
+ ipzero, ipzero, ipzero);
+
+ if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
+ return False;
+
+ /*
+ * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
+ * the linked list.
+ */
+
+ if (lp_we_are_a_wins_server()) {
+ if( (wins_server_subnet = make_subnet( "WINS_SERVER_SUBNET",
+ WINS_SERVER_SUBNET,
+ ipzero, ipzero, ipzero )) == NULL )
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+Function to tell us if we can use the unicast subnet.
+******************************************************************/
+
+bool we_are_a_wins_client(void)
+{
+ if (wins_srv_count() > 0) {
+ return True;
+ }
+
+ return False;
+}
+
+/*******************************************************************
+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/source3/nmbd/nmbd_synclists.c b/source3/nmbd/nmbd_synclists.c
new file mode 100644
index 0000000000..5a2f5c46b4
--- /dev/null
+++ b/source3/nmbd/nmbd_synclists.c
@@ -0,0 +1,325 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/* 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"
+
+struct sync_record {
+ struct sync_record *next, *prev;
+ unstring workgroup;
+ unstring server;
+ char *fname;
+ struct in_addr ip;
+ pid_t pid;
+};
+
+/* a linked list of current sync connections */
+static struct sync_record *syncs;
+
+static XFILE *fp;
+
+/*******************************************************************
+ This is the NetServerEnum callback.
+ Note sname and comment are in UNIX codepage format.
+ ******************************************************************/
+
+static void callback(const char *sname, uint32 stype,
+ const char *comment, void *state)
+{
+ x_fprintf(fp,"\"%s\" %08X \"%s\"\n", sname, stype, comment);
+}
+
+/*******************************************************************
+ Synchronise browse lists with another browse server.
+ Log in on the remote server's SMB port to their IPC$ service,
+ do a NetServerEnum and record the results in fname
+******************************************************************/
+
+static void sync_child(char *name, int nm_type,
+ char *workgroup,
+ struct in_addr ip, bool local, bool servers,
+ char *fname)
+{
+ fstring unix_workgroup;
+ struct cli_state *cli;
+ uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0;
+ struct nmb_name called, calling;
+ struct sockaddr_storage ss;
+ NTSTATUS status;
+
+ /* W2K DMB's return empty browse lists on port 445. Use 139.
+ * Patch from Andy Levine andyl@epicrealm.com.
+ */
+
+ cli = cli_initialise();
+ if (!cli) {
+ return;
+ }
+
+ if (!cli_set_port(cli, 139)) {
+ cli_shutdown(cli);
+ return;
+ }
+
+ in_addr_to_sockaddr_storage(&ss, ip);
+ status = cli_connect(cli, name, &ss);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_shutdown(cli);
+ return;
+ }
+
+ make_nmb_name(&calling, get_local_machine_name(), 0x0);
+ make_nmb_name(&called , name, nm_type);
+
+ if (!cli_session_request(cli, &calling, &called)) {
+ cli_shutdown(cli);
+ return;
+ }
+
+ if (!cli_negprot(cli)) {
+ cli_shutdown(cli);
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(cli_session_setup(cli, "", "", 1, "", 0,
+ workgroup))) {
+ cli_shutdown(cli);
+ return;
+ }
+
+ if (!cli_send_tconX(cli, "IPC$", "IPC", "", 1)) {
+ cli_shutdown(cli);
+ return;
+ }
+
+ /* All the cli_XX functions take UNIX character set. */
+ fstrcpy(unix_workgroup, cli->server_domain ? cli->server_domain : workgroup);
+
+ /* Fetch a workgroup list. */
+ cli_NetServerEnum(cli, unix_workgroup,
+ local_type|SV_TYPE_DOMAIN_ENUM,
+ callback, NULL);
+
+ /* Now fetch a server list. */
+ if (servers) {
+ fstrcpy(unix_workgroup, workgroup);
+ cli_NetServerEnum(cli, unix_workgroup,
+ local?SV_TYPE_LOCAL_LIST_ONLY:SV_TYPE_ALL,
+ callback, NULL);
+ }
+
+ cli_shutdown(cli);
+}
+
+/*******************************************************************
+ initialise a browse sync with another browse server. Log in on the
+ remote server's SMB port to their IPC$ service, do a NetServerEnum
+ and record the results
+******************************************************************/
+
+void sync_browse_lists(struct work_record *work,
+ char *name, int nm_type,
+ struct in_addr ip, bool local, bool servers)
+{
+ struct sync_record *s;
+ static int counter;
+
+ START_PROFILE(sync_browse_lists);
+ /* Check we're not trying to sync with ourselves. This can
+ happen if we are a domain *and* a local master browser. */
+ if (ismyip_v4(ip)) {
+done:
+ END_PROFILE(sync_browse_lists);
+ return;
+ }
+
+ s = SMB_MALLOC_P(struct sync_record);
+ if (!s) goto done;
+
+ ZERO_STRUCTP(s);
+
+ unstrcpy(s->workgroup, work->work_group);
+ unstrcpy(s->server, name);
+ s->ip = ip;
+
+ if (asprintf(&s->fname, "%s/sync.%d", lp_lockdir(), counter++) < 0) {
+ SAFE_FREE(s);
+ goto done;
+ }
+ /* Safe to use as 0 means no size change. */
+ all_string_sub(s->fname,"//", "/", 0);
+
+ DLIST_ADD(syncs, s);
+
+ /* the parent forks and returns, leaving the child to do the
+ actual sync and call END_PROFILE*/
+ CatchChild();
+ if ((s->pid = sys_fork())) return;
+
+ BlockSignals( False, SIGTERM );
+
+ DEBUG(2,("Initiating browse sync for %s to %s(%s)\n",
+ work->work_group, name, inet_ntoa(ip)));
+
+ fp = x_fopen(s->fname,O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (!fp) {
+ END_PROFILE(sync_browse_lists);
+ _exit(1);
+ }
+
+ sync_child(name, nm_type, work->work_group, ip, local, servers,
+ s->fname);
+
+ x_fclose(fp);
+ END_PROFILE(sync_browse_lists);
+ _exit(0);
+}
+
+/**********************************************************************
+ Handle one line from a completed sync file.
+ **********************************************************************/
+
+static void complete_one(struct sync_record *s,
+ char *sname, uint32 stype, char *comment)
+{
+ struct work_record *work;
+ struct server_record *servrec;
+
+ stype &= ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ if (stype & SV_TYPE_DOMAIN_ENUM) {
+ /* See if we can find the workgroup on this subnet. */
+ if((work=find_workgroup_on_subnet(unicast_subnet, sname))) {
+ /* We already know about this workgroup -
+ update the ttl. */
+ update_workgroup_ttl(work,lp_max_ttl());
+ } else {
+ /* Create the workgroup on the subnet. */
+ work = create_workgroup_on_subnet(unicast_subnet,
+ sname, lp_max_ttl());
+ if (work) {
+ /* remember who the master is */
+ unstrcpy(work->local_master_browser_name, comment);
+ }
+ }
+ return;
+ }
+
+ work = find_workgroup_on_subnet(unicast_subnet, s->workgroup);
+ if (!work) {
+ DEBUG(3,("workgroup %s doesn't exist on unicast subnet?\n",
+ s->workgroup));
+ return;
+ }
+
+ if ((servrec = find_server_in_workgroup( work, sname))) {
+ /* Check that this is not a locally known
+ server - if so ignore the entry. */
+ if(!(servrec->serv.type & SV_TYPE_LOCAL_LIST_ONLY)) {
+ /* We already know about this server - update
+ the ttl. */
+ update_server_ttl(servrec, lp_max_ttl());
+ /* Update the type. */
+ servrec->serv.type = stype;
+ }
+ return;
+ }
+
+ /* Create the server in the workgroup. */
+ create_server_on_workgroup(work, sname,stype, lp_max_ttl(), comment);
+}
+
+/**********************************************************************
+ Read the completed sync info.
+**********************************************************************/
+
+static void complete_sync(struct sync_record *s)
+{
+ XFILE *f;
+ char *server;
+ char *type_str;
+ unsigned type;
+ char *comment;
+ char line[1024];
+ const char *ptr;
+ int count=0;
+
+ f = x_fopen(s->fname,O_RDONLY, 0);
+
+ if (!f)
+ return;
+
+ while (!x_feof(f)) {
+ TALLOC_CTX *frame = NULL;
+
+ if (!fgets_slash(line,sizeof(line),f))
+ continue;
+
+ ptr = line;
+
+ frame = talloc_stackframe();
+ if (!next_token_talloc(frame,&ptr,&server,NULL) ||
+ !next_token_talloc(frame,&ptr,&type_str,NULL) ||
+ !next_token_talloc(frame,&ptr,&comment,NULL)) {
+ TALLOC_FREE(frame);
+ continue;
+ }
+
+ sscanf(type_str, "%X", &type);
+
+ complete_one(s, server, type, comment);
+
+ count++;
+ TALLOC_FREE(frame);
+ }
+ x_fclose(f);
+
+ unlink(s->fname);
+
+ DEBUG(2,("sync with %s(%s) for workgroup %s completed (%d records)\n",
+ s->server, inet_ntoa(s->ip), s->workgroup, count));
+}
+
+/**********************************************************************
+ Check for completion of any of the child processes.
+**********************************************************************/
+
+void sync_check_completion(void)
+{
+ struct sync_record *s, *next;
+
+ for (s=syncs;s;s=next) {
+ next = s->next;
+ if (!process_exists_by_pid(s->pid)) {
+ /* it has completed - grab the info */
+ complete_sync(s);
+ DLIST_REMOVE(syncs, s);
+ SAFE_FREE(s->fname);
+ SAFE_FREE(s);
+ }
+ }
+}
diff --git a/source3/nmbd/nmbd_winsproxy.c b/source3/nmbd/nmbd_winsproxy.c
new file mode 100644
index 0000000000..ff80c15fff
--- /dev/null
+++ b/source3/nmbd/nmbd_winsproxy.c
@@ -0,0 +1,232 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+Function called when the name lookup succeeded.
+****************************************************************************/
+
+static void wins_proxy_name_query_request_success( struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname, struct in_addr ip, struct res_rec *rrec)
+{
+ unstring name;
+ struct packet_struct *original_packet;
+ struct subnet_record *orig_broadcast_subnet;
+ struct name_record *namerec = NULL;
+ 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 *) );
+
+ if (rrec) {
+ nb_flags = get_nb_flags( rrec->rdata );
+ num_ips = rrec->rdlength / 6;
+ } else {
+ nb_flags = 0;
+ num_ips = 0;
+ }
+
+ if(num_ips == 0) {
+ DEBUG(0,("wins_proxy_name_query_request_success: Invalid number of IP records (0) \
+returned for name %s.\n", nmb_namestr(nmbname) ));
+ return;
+ }
+
+ if(num_ips == 1) {
+ iplist = &ip;
+ } else {
+ if((iplist = SMB_MALLOC_ARRAY( struct in_addr, num_ips )) == 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->ttl == PERMANENT_TTL) {
+ ttl = lp_max_ttl();
+ }
+
+ pull_ascii_nstring(name, sizeof(name), nmbname->name);
+ add_name_to_subnet( orig_broadcast_subnet, name,
+ nmbname->name_type, nb_flags, ttl,
+ WINS_PROXY_NAME, num_ips, iplist );
+
+ if(iplist != &ip) {
+ SAFE_FREE(iplist);
+ }
+
+ namerec = find_name_on_subnet(orig_broadcast_subnet, nmbname, FIND_ANY_NAME);
+ if (!namerec) {
+ DEBUG(0,("wins_proxy_name_query_request_success: failed to add "
+ "name %s to subnet %s !\n",
+ name,
+ orig_broadcast_subnet->subnet_name ));
+ return;
+ }
+
+ /*
+ * 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_v4( namerec->data.ip[i], orig_broadcast_subnet->myip,
+ orig_broadcast_subnet->mask_ip ) ) {
+ DEBUG( 5, ( "wins_proxy_name_query_request_success: name %s is a WINS \
+proxy name and is also on the same subnet (%s) as the requestor. \
+Not replying.\n", nmb_namestr(&namerec->name), orig_broadcast_subnet->subnet_name ) );
+ return;
+ }
+ }
+ }
+
+ /* Finally reply to the original name query. */
+ reply_netbios_packet(original_packet, /* Packet to reply to. */
+ 0, /* Result code. */
+ NMB_QUERY, /* nmbd type code. */
+ NMB_NAME_QUERY_OPCODE, /* opcode. */
+ ttl, /* ttl. */
+ rrec->rdata, /* data to send. */
+ rrec->rdlength); /* data length. */
+}
+
+/****************************************************************************
+Function called when the name lookup failed.
+****************************************************************************/
+
+static void wins_proxy_name_query_request_fail(struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *question_name, int fail_code)
+{
+ DEBUG(4,("wins_proxy_name_query_request_fail: WINS server returned error code %d for lookup \
+of name %s.\n", fail_code, nmb_namestr(question_name) ));
+}
+
+/****************************************************************************
+Function to make a deep copy of the userdata we will need when the WINS
+proxy query returns.
+****************************************************************************/
+
+static struct userdata_struct *wins_proxy_userdata_copy_fn(struct userdata_struct *userdata)
+{
+ struct packet_struct *p, *copy_of_p;
+ struct userdata_struct *new_userdata = (struct userdata_struct *)SMB_MALLOC( userdata->userdata_len );
+
+ if(new_userdata == NULL)
+ return NULL;
+
+ new_userdata->copy_fn = userdata->copy_fn;
+ new_userdata->free_fn = userdata->free_fn;
+ new_userdata->userdata_len = userdata->userdata_len;
+
+ /* Copy the subnet_record pointer. */
+ memcpy( new_userdata->data, userdata->data, sizeof(struct subnet_record *) );
+
+ /* Extract the pointer to the packet struct */
+ memcpy((char *)&p, &userdata->data[sizeof(struct subnet_record *)], sizeof(struct packet_struct *) );
+
+ /* Do a deep copy of the packet. */
+ if((copy_of_p = copy_packet(p)) == NULL) {
+ SAFE_FREE(new_userdata);
+ return NULL;
+ }
+
+ /* Lock the copy. */
+ copy_of_p->locked = True;
+
+ memcpy( &new_userdata->data[sizeof(struct subnet_record *)], (char *)&copy_of_p,
+ sizeof(struct packet_struct *) );
+
+ return new_userdata;
+}
+
+/****************************************************************************
+Function to free the deep copy of the userdata we used when the WINS
+proxy query returned.
+****************************************************************************/
+
+static void wins_proxy_userdata_free_fn(struct userdata_struct *userdata)
+{
+ struct packet_struct *p;
+
+ /* Extract the pointer to the packet struct */
+ memcpy((char *)&p, &userdata->data[sizeof(struct subnet_record *)],
+ sizeof(struct packet_struct *));
+
+ /* Unlock the packet. */
+ p->locked = False;
+
+ free_packet(p);
+ ZERO_STRUCTP(userdata);
+ SAFE_FREE(userdata);
+}
+
+/****************************************************************************
+ Make a WINS query on behalf of a broadcast client name query request.
+****************************************************************************/
+
+void make_wins_proxy_name_query_request( struct subnet_record *subrec,
+ struct packet_struct *incoming_packet,
+ struct nmb_name *question_name)
+{
+ union {
+ struct userdata_struct ud;
+ char c[sizeof(struct userdata_struct) + sizeof(struct subrec *) +
+ sizeof(struct packet_struct *)+sizeof(long*)];
+ } ud;
+ struct userdata_struct *userdata = &ud.ud;
+ unstring qname;
+
+ memset(&ud, '\0', sizeof(ud));
+
+ userdata->copy_fn = wins_proxy_userdata_copy_fn;
+ userdata->free_fn = wins_proxy_userdata_free_fn;
+ userdata->userdata_len = sizeof(ud);
+ memcpy( userdata->data, (char *)&subrec, sizeof(struct subnet_record *));
+ memcpy( &userdata->data[sizeof(struct subnet_record *)], (char *)&incoming_packet,
+ sizeof(struct packet_struct *));
+
+ /* Now use the unicast subnet to query the name with the WINS server. */
+ pull_ascii_nstring(qname, sizeof(qname), question_name->name);
+ query_name( unicast_subnet, qname, question_name->name_type,
+ wins_proxy_name_query_request_success,
+ wins_proxy_name_query_request_fail,
+ userdata);
+}
diff --git a/source3/nmbd/nmbd_winsserver.c b/source3/nmbd/nmbd_winsserver.c
new file mode 100644
index 0000000000..96938b011a
--- /dev/null
+++ b/source3/nmbd/nmbd_winsserver.c
@@ -0,0 +1,2568 @@
+/*
+ Unix SMB/CIFS implementation.
+ NBT netbios routines and daemon - version 2
+
+ Copyright (C) Jeremy Allison 1994-2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Converted to store WINS data in a tdb. Dec 2005. JRA.
+*/
+
+#include "includes.h"
+
+#define WINS_LIST "wins.dat"
+#define WINS_VERSION 1
+#define WINSDB_VERSION 1
+
+/****************************************************************************
+ We don't store the NetBIOS scope in the wins.tdb. We key off the (utf8) netbios
+ name (65 bytes with the last byte being the name type).
+*****************************************************************************/
+
+TDB_CONTEXT *wins_tdb;
+
+/****************************************************************************
+ Delete all the temporary name records on the in-memory linked list.
+*****************************************************************************/
+
+static void wins_delete_all_tmp_in_memory_records(void)
+{
+ struct name_record *nr = NULL;
+ struct name_record *nrnext = NULL;
+
+ /* Delete all temporary name records on the wins subnet linked list. */
+ for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
+ nrnext = nr->next;
+ DLIST_REMOVE(wins_server_subnet->namelist, nr);
+ SAFE_FREE(nr->data.ip);
+ SAFE_FREE(nr);
+ }
+}
+
+/****************************************************************************
+ Convert a wins.tdb record to a struct name_record. Add in our global_scope().
+*****************************************************************************/
+
+static struct name_record *wins_record_to_name_record(TDB_DATA key, TDB_DATA data)
+{
+ struct name_record *namerec = NULL;
+ uint16 nb_flags;
+ unsigned char nr_src;
+ uint32 death_time, refresh_time;
+ uint32 id_low, id_high;
+ uint32 saddr;
+ uint32 wins_flags;
+ uint32 num_ips;
+ size_t len;
+ int i;
+
+ if (data.dptr == NULL || data.dsize == 0) {
+ return NULL;
+ }
+
+ /* Min size is "wbddddddd" + 1 ip address (4). */
+ if (data.dsize < 2 + 1 + (7*4) + 4) {
+ return NULL;
+ }
+
+ len = tdb_unpack(data.dptr, data.dsize,
+ "wbddddddd",
+ &nb_flags,
+ &nr_src,
+ &death_time,
+ &refresh_time,
+ &id_low,
+ &id_high,
+ &saddr,
+ &wins_flags,
+ &num_ips );
+
+ namerec = SMB_MALLOC_P(struct name_record);
+ if (!namerec) {
+ return NULL;
+ }
+ ZERO_STRUCTP(namerec);
+
+ namerec->data.ip = SMB_MALLOC_ARRAY(struct in_addr, num_ips);
+ if (!namerec->data.ip) {
+ SAFE_FREE(namerec);
+ return NULL;
+ }
+
+ namerec->subnet = wins_server_subnet;
+ push_ascii_nstring(namerec->name.name, (const char *)key.dptr);
+ namerec->name.name_type = key.dptr[sizeof(unstring)];
+ /* Add the scope. */
+ push_ascii(namerec->name.scope, global_scope(), 64, STR_TERMINATE);
+
+ /* 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( namerec->name.name ); i < sizeof( namerec->name.name ); i++ ) {
+ namerec->name.name[i] = '\0';
+ }
+ for( i = strlen( namerec->name.scope ); i < sizeof( namerec->name.scope ); i++ ) {
+ namerec->name.scope[i] = '\0';
+ }
+
+ namerec->data.nb_flags = nb_flags;
+ namerec->data.source = (enum name_source)nr_src;
+ namerec->data.death_time = (time_t)death_time;
+ namerec->data.refresh_time = (time_t)refresh_time;
+ namerec->data.id = id_low;
+#if defined(HAVE_LONGLONG)
+ namerec->data.id |= ((SMB_BIG_UINT)id_high << 32);
+#endif
+ namerec->data.wins_ip.s_addr = saddr;
+ namerec->data.wins_flags = wins_flags,
+ namerec->data.num_ips = num_ips;
+
+ for (i = 0; i < num_ips; i++) {
+ namerec->data.ip[i].s_addr = IVAL(data.dptr, len + (i*4));
+ }
+
+ return namerec;
+}
+
+/****************************************************************************
+ Convert a struct name_record to a wins.tdb record. Ignore the scope.
+*****************************************************************************/
+
+static TDB_DATA name_record_to_wins_record(const struct name_record *namerec)
+{
+ TDB_DATA data;
+ size_t len = 0;
+ int i;
+ uint32 id_low = (namerec->data.id & 0xFFFFFFFF);
+#if defined(HAVE_LONGLONG)
+ uint32 id_high = (namerec->data.id >> 32) & 0xFFFFFFFF;
+#else
+ uint32 id_high = 0;
+#endif
+
+ ZERO_STRUCT(data);
+
+ len = (2 + 1 + (7*4)); /* "wbddddddd" */
+ len += (namerec->data.num_ips * 4);
+
+ data.dptr = (uint8 *)SMB_MALLOC(len);
+ if (!data.dptr) {
+ return data;
+ }
+ data.dsize = len;
+
+ len = tdb_pack(data.dptr, data.dsize, "wbddddddd",
+ namerec->data.nb_flags,
+ (unsigned char)namerec->data.source,
+ (uint32)namerec->data.death_time,
+ (uint32)namerec->data.refresh_time,
+ id_low,
+ id_high,
+ (uint32)namerec->data.wins_ip.s_addr,
+ (uint32)namerec->data.wins_flags,
+ (uint32)namerec->data.num_ips );
+
+ for (i = 0; i < namerec->data.num_ips; i++) {
+ SIVAL(data.dptr, len + (i*4), namerec->data.ip[i].s_addr);
+ }
+
+ return data;
+}
+
+/****************************************************************************
+ Create key. Key is UNIX codepage namestring (usually utf8 64 byte len) with 1 byte type.
+*****************************************************************************/
+
+static TDB_DATA name_to_key(const struct nmb_name *nmbname)
+{
+ static char keydata[sizeof(unstring) + 1];
+ TDB_DATA key;
+
+ memset(keydata, '\0', sizeof(keydata));
+
+ pull_ascii_nstring(keydata, sizeof(unstring), nmbname->name);
+ strupper_m(keydata);
+ keydata[sizeof(unstring)] = nmbname->name_type;
+ key.dptr = (uint8 *)keydata;
+ key.dsize = sizeof(keydata);
+
+ return key;
+}
+
+/****************************************************************************
+ Lookup a given name in the wins.tdb and create a temporary malloc'ed data struct
+ on the linked list. We will free this later in XXXX().
+*****************************************************************************/
+
+struct name_record *find_name_on_wins_subnet(const struct nmb_name *nmbname, bool self_only)
+{
+ TDB_DATA data, key;
+ struct name_record *nr = NULL;
+ struct name_record *namerec = NULL;
+
+ if (!wins_tdb) {
+ return NULL;
+ }
+
+ key = name_to_key(nmbname);
+ data = tdb_fetch(wins_tdb, key);
+
+ if (data.dsize == 0) {
+ return NULL;
+ }
+
+ namerec = wins_record_to_name_record(key, data);
+
+ /* done with the this */
+
+ SAFE_FREE( data.dptr );
+
+ if (!namerec) {
+ return NULL;
+ }
+
+ /* Self names only - these include permanent names. */
+ if( self_only && (namerec->data.source != SELF_NAME) && (namerec->data.source != PERMANENT_NAME) ) {
+ DEBUG( 9, ( "find_name_on_wins_subnet: self name %s NOT FOUND\n", nmb_namestr(nmbname) ) );
+ SAFE_FREE(namerec->data.ip);
+ SAFE_FREE(namerec);
+ return NULL;
+ }
+
+ /* Search for this name record on the list. Replace it if found. */
+
+ for( nr = wins_server_subnet->namelist; nr; nr = nr->next) {
+ if (memcmp(nmbname->name, nr->name.name, 16) == 0) {
+ /* Delete it. */
+ DLIST_REMOVE(wins_server_subnet->namelist, nr);
+ SAFE_FREE(nr->data.ip);
+ SAFE_FREE(nr);
+ break;
+ }
+ }
+
+ DLIST_ADD(wins_server_subnet->namelist, namerec);
+ return namerec;
+}
+
+/****************************************************************************
+ Overwrite or add a given name in the wins.tdb.
+*****************************************************************************/
+
+static bool store_or_replace_wins_namerec(const struct name_record *namerec, int tdb_flag)
+{
+ TDB_DATA key, data;
+ int ret;
+
+ if (!wins_tdb) {
+ return False;
+ }
+
+ key = name_to_key(&namerec->name);
+ data = name_record_to_wins_record(namerec);
+
+ if (data.dptr == NULL) {
+ return False;
+ }
+
+ ret = tdb_store(wins_tdb, key, data, tdb_flag);
+
+ SAFE_FREE(data.dptr);
+ return (ret == 0) ? True : False;
+}
+
+/****************************************************************************
+ Overwrite a given name in the wins.tdb.
+*****************************************************************************/
+
+bool wins_store_changed_namerec(const struct name_record *namerec)
+{
+ return store_or_replace_wins_namerec(namerec, TDB_REPLACE);
+}
+
+/****************************************************************************
+ Primary interface into creating and overwriting records in the wins.tdb.
+*****************************************************************************/
+
+bool add_name_to_wins_subnet(const struct name_record *namerec)
+{
+ return store_or_replace_wins_namerec(namerec, TDB_INSERT);
+}
+
+/****************************************************************************
+ Delete a given name in the tdb and remove the temporary malloc'ed data struct
+ on the linked list.
+*****************************************************************************/
+
+bool remove_name_from_wins_namelist(struct name_record *namerec)
+{
+ TDB_DATA key;
+ int ret;
+
+ if (!wins_tdb) {
+ return False;
+ }
+
+ key = name_to_key(&namerec->name);
+ ret = tdb_delete(wins_tdb, key);
+
+ DLIST_REMOVE(wins_server_subnet->namelist, namerec);
+
+ /* namerec must be freed by the caller */
+
+ return (ret == 0) ? True : False;
+}
+
+/****************************************************************************
+ Dump out the complete namelist.
+*****************************************************************************/
+
+static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct name_record *namerec = NULL;
+ XFILE *fp = (XFILE *)state;
+
+ if (kbuf.dsize != sizeof(unstring) + 1) {
+ return 0;
+ }
+
+ namerec = wins_record_to_name_record(kbuf, dbuf);
+ if (!namerec) {
+ return 0;
+ }
+
+ dump_name_record(namerec, fp);
+
+ SAFE_FREE(namerec->data.ip);
+ SAFE_FREE(namerec);
+ return 0;
+}
+
+void dump_wins_subnet_namelist(XFILE *fp)
+{
+ tdb_traverse(wins_tdb, traverse_fn, (void *)fp);
+}
+
+/****************************************************************************
+ Change the wins owner address in the record.
+*****************************************************************************/
+
+static void update_wins_owner(struct name_record *namerec, struct in_addr wins_ip)
+{
+ namerec->data.wins_ip=wins_ip;
+}
+
+/****************************************************************************
+ Create the wins flags based on the nb flags and the input value.
+*****************************************************************************/
+
+static void update_wins_flag(struct name_record *namerec, int flags)
+{
+ namerec->data.wins_flags=0x0;
+
+ /* if it's a group, it can be a normal or a special one */
+ if (namerec->data.nb_flags & NB_GROUP) {
+ if (namerec->name.name_type==0x1C) {
+ namerec->data.wins_flags|=WINS_SGROUP;
+ } else {
+ if (namerec->data.num_ips>1) {
+ namerec->data.wins_flags|=WINS_SGROUP;
+ } else {
+ namerec->data.wins_flags|=WINS_NGROUP;
+ }
+ }
+ } else {
+ /* can be unique or multi-homed */
+ if (namerec->data.num_ips>1) {
+ namerec->data.wins_flags|=WINS_MHOMED;
+ } else {
+ namerec->data.wins_flags|=WINS_UNIQUE;
+ }
+ }
+
+ /* the node type are the same bits */
+ namerec->data.wins_flags|=namerec->data.nb_flags&NB_NODETYPEMASK;
+
+ /* the static bit is elsewhere */
+ if (namerec->data.death_time == PERMANENT_TTL) {
+ namerec->data.wins_flags|=WINS_STATIC;
+ }
+
+ /* and add the given bits */
+ namerec->data.wins_flags|=flags;
+
+ DEBUG(8,("update_wins_flag: nbflags: 0x%x, ttl: 0x%d, flags: 0x%x, winsflags: 0x%x\n",
+ namerec->data.nb_flags, (int)namerec->data.death_time, flags, namerec->data.wins_flags));
+}
+
+/****************************************************************************
+ Return the general ID value and increase it if requested.
+*****************************************************************************/
+
+static void get_global_id_and_update(SMB_BIG_UINT *current_id, bool update)
+{
+ /*
+ * it's kept as a static here, to prevent people from messing
+ * with the value directly
+ */
+
+ static SMB_BIG_UINT general_id = 1;
+
+ DEBUG(5,("get_global_id_and_update: updating version ID: %d\n", (int)general_id));
+
+ *current_id = general_id;
+
+ if (update) {
+ general_id++;
+ }
+}
+
+/****************************************************************************
+ Possibly call the WINS hook external program when a WINS change is made.
+ Also stores the changed record back in the wins_tdb.
+*****************************************************************************/
+
+static void wins_hook(const char *operation, struct name_record *namerec, int ttl)
+{
+ char *command = NULL;
+ char *cmd = lp_wins_hook();
+ char *p, *namestr;
+ int i;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ wins_store_changed_namerec(namerec);
+
+ if (!cmd || !*cmd) {
+ return;
+ }
+
+ for (p=namerec->name.name; *p; p++) {
+ if (!(isalnum((int)*p) || strchr_m("._-",*p))) {
+ DEBUG(3,("not calling wins hook for invalid name %s\n", nmb_namestr(&namerec->name)));
+ return;
+ }
+ }
+
+ /* Use the name without the nametype (and scope) appended */
+
+ namestr = nmb_namestr(&namerec->name);
+ if ((p = strchr(namestr, '<'))) {
+ *p = 0;
+ }
+
+ command = talloc_asprintf(ctx,
+ "%s %s %s %02x %d",
+ cmd,
+ operation,
+ namestr,
+ namerec->name.name_type,
+ ttl);
+ if (!command) {
+ return;
+ }
+
+ for (i=0;i<namerec->data.num_ips;i++) {
+ command = talloc_asprintf_append(command,
+ " %s",
+ inet_ntoa(namerec->data.ip[i]));
+ if (!command) {
+ return;
+ }
+ }
+
+ DEBUG(3,("calling wins hook for %s\n", nmb_namestr(&namerec->name)));
+ smbrun(command, NULL);
+ TALLOC_FREE(command);
+}
+
+/****************************************************************************
+Determine if this packet should be allocated to the WINS server.
+*****************************************************************************/
+
+bool packet_is_for_wins_server(struct packet_struct *packet)
+{
+ struct nmb_packet *nmb = &packet->packet.nmb;
+
+ /* Only unicast packets go to a WINS server. */
+ if((wins_server_subnet == NULL) || (nmb->header.nm_flags.bcast == True)) {
+ DEBUG(10, ("packet_is_for_wins_server: failing WINS test #1.\n"));
+ return False;
+ }
+
+ /* Check for node status requests. */
+ if (nmb->question.question_type != QUESTION_TYPE_NB_QUERY) {
+ return False;
+ }
+
+ switch(nmb->header.opcode) {
+ /*
+ * A WINS server issues WACKS, not receives them.
+ */
+ case NMB_WACK_OPCODE:
+ DEBUG(10, ("packet_is_for_wins_server: failing WINS test #2 (WACK).\n"));
+ return False;
+ /*
+ * A WINS server only processes registration and
+ * release requests, not responses.
+ */
+ case NMB_NAME_REG_OPCODE:
+ case NMB_NAME_MULTIHOMED_REG_OPCODE:
+ case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
+ case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
+ if(nmb->header.response) {
+ DEBUG(10, ("packet_is_for_wins_server: failing WINS test #3 (response = 1).\n"));
+ return False;
+ }
+ break;
+
+ case NMB_NAME_RELEASE_OPCODE:
+ if(nmb->header.response) {
+ DEBUG(10, ("packet_is_for_wins_server: failing WINS test #4 (response = 1).\n"));
+ return False;
+ }
+ break;
+
+ /*
+ * Only process unicast name queries with rd = 1.
+ */
+ case NMB_NAME_QUERY_OPCODE:
+ if(!nmb->header.response && !nmb->header.nm_flags.recursion_desired) {
+ DEBUG(10, ("packet_is_for_wins_server: failing WINS test #5 (response = 1).\n"));
+ return False;
+ }
+ break;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+Utility function to decide what ttl to give a register/refresh request.
+*****************************************************************************/
+
+static int get_ttl_from_packet(struct nmb_packet *nmb)
+{
+ int ttl = nmb->additional->ttl;
+
+ if (ttl < lp_min_wins_ttl()) {
+ ttl = lp_min_wins_ttl();
+ }
+
+ if (ttl > lp_max_wins_ttl()) {
+ ttl = lp_max_wins_ttl();
+ }
+
+ return ttl;
+}
+
+/****************************************************************************
+Load or create the WINS database.
+*****************************************************************************/
+
+bool initialise_wins(void)
+{
+ time_t time_now = time(NULL);
+ XFILE *fp;
+ char line[1024];
+
+ if(!lp_we_are_a_wins_server()) {
+ return True;
+ }
+
+ /* Open the wins.tdb. */
+ wins_tdb = tdb_open_log(lock_path("wins.tdb"), 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST, O_CREAT|O_RDWR, 0600);
+ if (!wins_tdb) {
+ DEBUG(0,("initialise_wins: failed to open wins.tdb. Error was %s\n",
+ strerror(errno) ));
+ return False;
+ }
+
+ tdb_store_int32(wins_tdb, "WINSDB_VERSION", WINSDB_VERSION);
+
+ add_samba_names_to_subnet(wins_server_subnet);
+
+ if((fp = x_fopen(state_path(WINS_LIST),O_RDONLY,0)) == NULL) {
+ DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
+ WINS_LIST, strerror(errno) ));
+ return True;
+ }
+
+ while (!x_feof(fp)) {
+ char *name_str = NULL;
+ char *ip_str = NULL;
+ char *ttl_str = NULL, *nb_flags_str = NULL;
+ unsigned int num_ips;
+ char *name = NULL;
+ struct in_addr *ip_list = NULL;
+ int type = 0;
+ int nb_flags;
+ int ttl;
+ const char *ptr;
+ char *p = NULL;
+ bool got_token;
+ bool was_ip;
+ int i;
+ unsigned int hash;
+ int version;
+ TALLOC_CTX *frame = NULL;
+
+ /* Read a line from the wins.dat file. Strips whitespace
+ from the beginning and end of the line. */
+ if (!fgets_slash(line,sizeof(line),fp)) {
+ continue;
+ }
+
+ if (*line == '#') {
+ continue;
+ }
+
+ if (strncmp(line,"VERSION ", 8) == 0) {
+ if (sscanf(line,"VERSION %d %u", &version, &hash) != 2 ||
+ version != WINS_VERSION) {
+ DEBUG(0,("Discarding invalid wins.dat file [%s]\n",line));
+ x_fclose(fp);
+ return True;
+ }
+ continue;
+ }
+
+ ptr = line;
+
+ /*
+ * Now we handle multiple IP addresses per name we need
+ * to iterate over the line twice. The first time to
+ * determine how many IP addresses there are, the second
+ * time to actually parse them into the ip_list array.
+ */
+
+ frame = talloc_stackframe();
+ if (!next_token_talloc(frame,&ptr,&name_str,NULL)) {
+ DEBUG(0,("initialise_wins: Failed to parse name when parsing line %s\n", line ));
+ TALLOC_FREE(frame);
+ continue;
+ }
+
+ if (!next_token_talloc(frame,&ptr,&ttl_str,NULL)) {
+ DEBUG(0,("initialise_wins: Failed to parse time to live when parsing line %s\n", line ));
+ TALLOC_FREE(frame);
+ continue;
+ }
+
+ /*
+ * Determine the number of IP addresses per line.
+ */
+ num_ips = 0;
+ do {
+ got_token = next_token_talloc(frame,&ptr,&ip_str,NULL);
+ 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 ));
+ TALLOC_FREE(frame);
+ continue;
+ }
+
+ if(!got_token) {
+ DEBUG(0,("initialise_wins: Missing nb_flags when parsing line %s\n", line ));
+ TALLOC_FREE(frame);
+ continue;
+ }
+
+ /* Allocate the space for the ip_list. */
+ if((ip_list = SMB_MALLOC_ARRAY( struct in_addr, num_ips)) == NULL) {
+ DEBUG(0,("initialise_wins: Malloc fail !\n"));
+ x_fclose(fp);
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ /* Reset and re-parse the line. */
+ ptr = line;
+ next_token_talloc(frame,&ptr,&name_str,NULL);
+ next_token_talloc(frame,&ptr,&ttl_str,NULL);
+ for(i = 0; i < num_ips; i++) {
+ next_token_talloc(frame,&ptr, &ip_str, NULL);
+ (void)interpret_addr2(&ip_list[i], ip_str);
+ }
+ next_token_talloc(frame,&ptr,&nb_flags_str,NULL);
+
+ /*
+ * Deal with SELF or REGISTER name encoding. Default is REGISTER
+ * for compatibility with old nmbds.
+ */
+
+ if(nb_flags_str[strlen(nb_flags_str)-1] == 'S') {
+ DEBUG(5,("initialise_wins: Ignoring SELF name %s\n", line));
+ SAFE_FREE(ip_list);
+ TALLOC_FREE(frame);
+ 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 */
+ 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));
+ }
+
+ TALLOC_FREE(frame);
+ SAFE_FREE(ip_list);
+ }
+
+ x_fclose(fp);
+ return True;
+}
+
+/****************************************************************************
+Send a WINS WACK (Wait ACKnowledgement) response.
+**************************************************************************/
+
+static void send_wins_wack_response(int ttl, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ unsigned char rdata[2];
+
+ rdata[0] = rdata[1] = 0;
+
+ /* Taken from nmblib.c - we need to send back almost
+ identical bytes from the requesting packet header. */
+
+ rdata[0] = (nmb->header.opcode & 0xF) << 3;
+ if (nmb->header.nm_flags.authoritative && nmb->header.response) {
+ rdata[0] |= 0x4;
+ }
+ if (nmb->header.nm_flags.trunc) {
+ rdata[0] |= 0x2;
+ }
+ if (nmb->header.nm_flags.recursion_desired) {
+ rdata[0] |= 0x1;
+ }
+ if (nmb->header.nm_flags.recursion_available && nmb->header.response) {
+ rdata[1] |= 0x80;
+ }
+ if (nmb->header.nm_flags.bcast) {
+ rdata[1] |= 0x10;
+ }
+
+ reply_netbios_packet(p, /* Packet to reply to. */
+ 0, /* Result code. */
+ NMB_WAIT_ACK, /* nmbd type code. */
+ NMB_WACK_OPCODE, /* opcode. */
+ ttl, /* ttl. */
+ (char *)rdata, /* data to send. */
+ 2); /* data length. */
+}
+
+/****************************************************************************
+Send a WINS name registration response.
+**************************************************************************/
+
+static void send_wins_name_registration_response(int rcode, int ttl, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ char rdata[6];
+
+ memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
+
+ reply_netbios_packet(p, /* Packet to reply to. */
+ rcode, /* Result code. */
+ WINS_REG, /* nmbd type code. */
+ NMB_NAME_REG_OPCODE, /* opcode. */
+ ttl, /* ttl. */
+ rdata, /* data to send. */
+ 6); /* data length. */
+}
+
+/***********************************************************************
+ Deal with a name refresh request to a WINS server.
+************************************************************************/
+
+void wins_process_name_refresh_request( struct subnet_record *subrec,
+ struct packet_struct *p )
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ bool bcast = nmb->header.nm_flags.bcast;
+ uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+ bool group = (nb_flags & NB_GROUP) ? True : False;
+ struct name_record *namerec = NULL;
+ int ttl = get_ttl_from_packet(nmb);
+ struct in_addr from_ip;
+ struct in_addr our_fake_ip;
+
+ (void)interpret_addr2(&our_fake_ip, "0.0.0.0");
+ 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.
+ */
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "wins_process_name_refresh_request: " );
+ dbgtext( "Broadcast name refresh request received " );
+ dbgtext( "for name %s ", nmb_namestr(question) );
+ dbgtext( "from IP %s ", inet_ntoa(from_ip) );
+ dbgtext( "on subnet %s. ", subrec->subnet_name );
+ dbgtext( "Error - Broadcasts should not be sent " );
+ dbgtext( "to a WINS server\n" );
+ }
+ return;
+ }
+
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "wins_process_name_refresh_request: " );
+ dbgtext( "Name refresh for name %s IP %s\n",
+ nmb_namestr(question), inet_ntoa(from_ip) );
+ }
+
+ /*
+ * See if the name already exists.
+ * If not, handle it as a name registration and return.
+ */
+ 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) {
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "wins_process_name_refresh_request: " );
+ dbgtext( "Name refresh for name %s ",
+ nmb_namestr( question ) );
+ dbgtext( "and the name does not exist. Treating " );
+ dbgtext( "as registration.\n" );
+ }
+ wins_process_name_registration_request(subrec,p);
+ return;
+ }
+
+ /*
+ * if the name is present but not active, simply remove it
+ * and treat the refresh request as a registration & return.
+ */
+ if (namerec != NULL && !WINS_STATE_ACTIVE(namerec)) {
+ if( DEBUGLVL( 5 ) ) {
+ dbgtext( "wins_process_name_refresh_request: " );
+ dbgtext( "Name (%s) in WINS ", nmb_namestr(question) );
+ dbgtext( "was not active - removing it.\n" );
+ }
+ remove_name_from_namelist( subrec, namerec );
+ namerec = NULL;
+ 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 not, refuse the refresh.
+ * [crh: Why RFS_ERR instead of ACT_ERR? Is this what MS does?]
+ */
+ if( (namerec != NULL) &&
+ ( (group && !NAME_GROUP(namerec))
+ || (!group && NAME_GROUP(namerec)) ) ) {
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "wins_process_name_refresh_request: " );
+ dbgtext( "Name %s ", nmb_namestr(question) );
+ dbgtext( "group bit = %s does not match ",
+ group ? "True" : "False" );
+ dbgtext( "group bit in WINS for this name.\n" );
+ }
+ 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);
+
+ /*
+ * if the record is a replica:
+ * we take ownership and update the version ID.
+ */
+ if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
+ update_wins_owner(namerec, our_fake_ip);
+ get_global_id_and_update(&namerec->data.id, True);
+ }
+
+ send_wins_name_registration_response(0, ttl, p);
+ wins_hook("refresh", namerec, ttl);
+ return;
+ } else if((group && (question->name_type == 0x1c))) {
+ /*
+ * Added by crh for bug #1079.
+ * Fix from Bert Driehuis
+ */
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "wins_process_name_refresh_request: " );
+ dbgtext( "Name refresh for name %s, ",
+ nmb_namestr(question) );
+ dbgtext( "but IP address %s ", inet_ntoa(from_ip) );
+ dbgtext( "is not yet associated with " );
+ dbgtext( "that name. Treating as registration.\n" );
+ }
+ wins_process_name_registration_request(subrec,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);
+ wins_hook("refresh", 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.
+ */
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "wins_process_name_refresh_request: " );
+ dbgtext( "Name refresh for name %s with IP %s ",
+ nmb_namestr(question), inet_ntoa(from_ip) );
+ dbgtext( "and is IP is not known to the name.\n" );
+ }
+ send_wins_name_registration_response(RFS_ERR, 0, p);
+ return;
+ }
+}
+
+/***********************************************************************
+ Deal with a name registration request query success to a client that
+ owned the name.
+
+ We have a locked pointer to the original packet stashed away in the
+ userdata pointer. The success here is actually a failure as it means
+ the client we queried wants to keep the name, so we must return
+ a registration failure to the original requestor.
+************************************************************************/
+
+static void wins_register_query_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *question_name,
+ struct in_addr ip,
+ struct res_rec *answers)
+{
+ struct packet_struct *orig_reg_packet;
+
+ memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
+
+ DEBUG(3,("wins_register_query_success: Original client at IP %s still wants the \
+name %s. Rejecting registration request.\n", inet_ntoa(ip), nmb_namestr(question_name) ));
+
+ send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
+
+ orig_reg_packet->locked = False;
+ free_packet(orig_reg_packet);
+}
+
+/***********************************************************************
+ Deal with a name registration request query failure to a client that
+ owned the name.
+
+ We have a locked pointer to the original packet stashed away in the
+ userdata pointer. The failure here is actually a success as it means
+ the client we queried didn't want to keep the name, so we can remove
+ the old name record and then successfully add the new name.
+************************************************************************/
+
+static void wins_register_query_fail(struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *question_name,
+ int rcode)
+{
+ struct userdata_struct *userdata = rrec->userdata;
+ struct packet_struct *orig_reg_packet;
+ struct name_record *namerec = NULL;
+
+ memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
+
+ /*
+ * We want to just add the name, as we now know the original owner
+ * didn't want it. But we can't just do that as an arbitary
+ * amount of time may have taken place between the name query
+ * request and this timeout/error response. So we check that
+ * the name still exists and is in the same state - if so
+ * we remove it and call wins_process_name_registration_request()
+ * as we know it will do the right thing now.
+ */
+
+ namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
+
+ if ((namerec != NULL) && (namerec->data.source == REGISTER_NAME) &&
+ ip_equal_v4(rrec->packet->ip, *namerec->data.ip)) {
+ remove_name_from_namelist( subrec, namerec);
+ namerec = NULL;
+ }
+
+ if(namerec == NULL) {
+ wins_process_name_registration_request(subrec, orig_reg_packet);
+ } else {
+ DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between "
+ "querying for name %s in order to replace it and this reply.\n",
+ nmb_namestr(question_name) ));
+ }
+
+ orig_reg_packet->locked = False;
+ free_packet(orig_reg_packet);
+}
+
+/***********************************************************************
+ Deal with a name registration request to a WINS server.
+
+ Use the following pseudocode :
+
+ registering_group
+ |
+ |
+ +--------name exists
+ | |
+ | |
+ | +--- existing name is group
+ | | |
+ | | |
+ | | +--- add name (return).
+ | |
+ | |
+ | +--- exiting name is unique
+ | |
+ | |
+ | +--- query existing owner (return).
+ |
+ |
+ +--------name doesn't exist
+ |
+ |
+ +--- add name (return).
+
+ registering_unique
+ |
+ |
+ +--------name exists
+ | |
+ | |
+ | +--- existing name is group
+ | | |
+ | | |
+ | | +--- fail add (return).
+ | |
+ | |
+ | +--- exiting name is unique
+ | |
+ | |
+ | +--- query existing owner (return).
+ |
+ |
+ +--------name doesn't exist
+ |
+ |
+ +--- add name (return).
+
+ As can be seen from the above, the two cases may be collapsed onto each
+ other with the exception of the case where the name already exists and
+ is a group name. This case we handle with an if statement.
+
+************************************************************************/
+
+void wins_process_name_registration_request(struct subnet_record *subrec,
+ struct packet_struct *p)
+{
+ unstring name;
+ 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;
+ struct in_addr our_fake_ip;
+
+ (void)interpret_addr2(&our_fake_ip, "0.0.0.0");
+ putip((char *)&from_ip,&nmb->additional->rdata[2]);
+
+ if(bcast) {
+ /*
+ * We should only get unicast name registration packets here.
+ * Anyone trying to register broadcast should not be going to a WINS
+ * server. Log an error here.
+ */
+
+ DEBUG(0,("wins_process_name_registration_request: broadcast name registration request \
+received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
+ nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+ return;
+ }
+
+ DEBUG(3,("wins_process_name_registration_request: %s name registration for name %s \
+IP %s\n", registering_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
+
+ /*
+ * See if the name already exists.
+ */
+
+ namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+ /*
+ * if the record exists but NOT in active state,
+ * consider it dead.
+ */
+ if ( (namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
+ DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
+not active - removing it.\n", nmb_namestr(question) ));
+ remove_name_from_namelist( subrec, namerec );
+ namerec = NULL;
+ }
+
+ /*
+ * Deal with the case where the name found was a dns entry.
+ * Remove it as we now have a NetBIOS client registering the
+ * name.
+ */
+
+ if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
+ DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
+a dns lookup - removing it.\n", nmb_namestr(question) ));
+ remove_name_from_namelist( subrec, namerec );
+ namerec = NULL;
+ }
+
+ /*
+ * Reject if the name exists and is not a REGISTER_NAME.
+ * (ie. Don't allow any static names to be overwritten.
+ */
+
+ if((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) {
+ DEBUG( 3, ( "wins_process_name_registration_request: Attempt \
+to register name %s. Name already exists in WINS with source type %d.\n",
+ nmb_namestr(question), namerec->data.source ));
+ send_wins_name_registration_response(RFS_ERR, 0, p);
+ return;
+ }
+
+ /*
+ * Special policy decisions based on MS documentation.
+ * 1). All group names (except names ending in 0x1c) are added as 255.255.255.255.
+ * 2). All unique names ending in 0x1d are ignored, although a positive response is sent.
+ */
+
+ /*
+ * A group name is always added as the local broadcast address, except
+ * for group names ending in 0x1c.
+ * Group names with type 0x1c are registered with individual IP addresses.
+ */
+
+ if(registering_group_name && (question->name_type != 0x1c)) {
+ (void)interpret_addr2(&from_ip, "255.255.255.255");
+ }
+
+ /*
+ * Ignore all attempts to register a unique 0x1d name, although return success.
+ */
+
+ if(!registering_group_name && (question->name_type == 0x1d)) {
+ DEBUG(3,("wins_process_name_registration_request: Ignoring request \
+to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
+ send_wins_name_registration_response(0, ttl, p);
+ return;
+ }
+
+ /*
+ * Next two cases are the 'if statement' mentioned above.
+ */
+
+ if((namerec != NULL) && NAME_GROUP(namerec)) {
+ if(registering_group_name) {
+ /*
+ * If we are adding a group name, the name exists and is also a group entry just add this
+ * IP address to it and update the ttl.
+ */
+
+ DEBUG(3,("wins_process_name_registration_request: Adding IP %s to group name %s.\n",
+ inet_ntoa(from_ip), nmb_namestr(question) ));
+
+ /*
+ * Check the ip address is not already in the group.
+ */
+
+ if(!find_ip_in_name_record(namerec, from_ip)) {
+ add_ip_to_name_record(namerec, from_ip);
+ /* we need to update the record for replication */
+ get_global_id_and_update(&namerec->data.id, True);
+
+ /*
+ * if the record is a replica, we must change
+ * the wins owner to us to make the replication updates
+ * it on the other wins servers.
+ * And when the partner will receive this record,
+ * it will update its own record.
+ */
+
+ update_wins_owner(namerec, our_fake_ip);
+ }
+ update_name_ttl(namerec, ttl);
+ wins_hook("refresh", 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.
+ *
+ * explanation: groups have a higher priority than unique names.
+ */
+
+ DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
+already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
+ send_wins_name_registration_response(RFS_ERR, 0, p);
+ return;
+ }
+ }
+
+ /*
+ * From here on down we know that if the name exists in the WINS db it is
+ * a unique name, not a group name.
+ */
+
+ /*
+ * If the name exists and is one of our names then check the
+ * registering IP address. If it's not one of ours then automatically
+ * reject without doing the query - we know we will reject it.
+ */
+
+ if ( namerec != NULL ) {
+ pull_ascii_nstring(name, sizeof(name), namerec->name.name);
+ if( is_myname(name) ) {
+ if(!ismyip_v4(from_ip)) {
+ DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
+is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
+ send_wins_name_registration_response(RFS_ERR, 0, p);
+ return;
+ } else {
+ /*
+ * It's one of our names and one of our IP's - update the ttl.
+ */
+ update_name_ttl(namerec, ttl);
+ wins_hook("refresh", namerec, ttl);
+ send_wins_name_registration_response(0, ttl, p);
+ return;
+ }
+ }
+ } else {
+ name[0] = '\0';
+ }
+
+ /*
+ * If the name exists and it is a unique registration and the registering IP
+ * is the same as the (single) already registered IP then just update the ttl.
+ *
+ * But not if the record is an active replica. IF it's a replica, it means it can be
+ * the same client which has moved and not yet expired. So we don't update
+ * the ttl in this case and go beyond to do a WACK and query the old client
+ */
+
+ if( !registering_group_name
+ && (namerec != NULL)
+ && (namerec->data.num_ips == 1)
+ && ip_equal_v4( namerec->data.ip[0], from_ip )
+ && ip_equal_v4(namerec->data.wins_ip, our_fake_ip) ) {
+ update_name_ttl( namerec, ttl );
+ wins_hook("refresh", 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 ) {
+ long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
+ struct userdata_struct *userdata = (struct userdata_struct *)ud;
+
+ /*
+ * First send a WACK to the registering machine.
+ */
+
+ send_wins_wack_response(60, p);
+
+ /*
+ * When the reply comes back we need the original packet.
+ * Lock this so it won't be freed and then put it into
+ * the userdata structure.
+ */
+
+ p->locked = True;
+
+ userdata = (struct userdata_struct *)ud;
+
+ userdata->copy_fn = NULL;
+ userdata->free_fn = NULL;
+ userdata->userdata_len = sizeof(struct packet_struct *);
+ memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
+
+ /*
+ * Use the new call to send a query directly to an IP address.
+ * This sends the query directly to the IP address, and ensures
+ * the recursion desired flag is not set (you were right Luke :-).
+ * This function should *only* be called from the WINS server
+ * code. JRA.
+ */
+
+ pull_ascii_nstring(name, sizeof(name), question->name);
+ query_name_from_wins_server( *namerec->data.ip,
+ name,
+ question->name_type,
+ wins_register_query_success,
+ wins_register_query_fail,
+ userdata );
+ return;
+ }
+
+ /*
+ * Name did not exist - add it.
+ */
+
+ pull_ascii_nstring(name, sizeof(name), question->name);
+ add_name_to_subnet( subrec, name, question->name_type,
+ nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
+
+ if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
+ get_global_id_and_update(&namerec->data.id, True);
+ update_wins_owner(namerec, our_fake_ip);
+ update_wins_flag(namerec, WINS_ACTIVE);
+ wins_hook("add", namerec, ttl);
+ }
+
+ send_wins_name_registration_response(0, ttl, p);
+}
+
+/***********************************************************************
+ Deal with a mutihomed name query success to the machine that
+ requested the multihomed name registration.
+
+ We have a locked pointer to the original packet stashed away in the
+ userdata pointer.
+************************************************************************/
+
+static void wins_multihomed_register_query_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *question_name,
+ struct in_addr ip,
+ struct res_rec *answers)
+{
+ struct packet_struct *orig_reg_packet;
+ struct nmb_packet *nmb;
+ struct name_record *namerec = NULL;
+ struct in_addr from_ip;
+ int ttl;
+ struct in_addr our_fake_ip;
+
+ (void)interpret_addr2(&our_fake_ip, "0.0.0.0");
+ 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) || !WINS_STATE_ACTIVE(namerec) ) {
+ DEBUG(3,("wins_multihomed_register_query_success: name %s is not in the correct state to add \
+a subsequent IP address.\n", nmb_namestr(question_name) ));
+ send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
+
+ orig_reg_packet->locked = False;
+ free_packet(orig_reg_packet);
+
+ return;
+ }
+
+ if(!find_ip_in_name_record(namerec, from_ip)) {
+ add_ip_to_name_record(namerec, from_ip);
+ }
+
+ get_global_id_and_update(&namerec->data.id, True);
+ update_wins_owner(namerec, our_fake_ip);
+ update_wins_flag(namerec, WINS_ACTIVE);
+ update_name_ttl(namerec, ttl);
+ wins_hook("add", 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), nmb_namestr(question_name) ));
+ send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
+
+ orig_reg_packet->locked = False;
+ free_packet(orig_reg_packet);
+ return;
+}
+
+/***********************************************************************
+ Deal with a multihomed name registration request to a WINS server.
+ These cannot be group name registrations.
+***********************************************************************/
+
+void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
+ struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ bool bcast = nmb->header.nm_flags.bcast;
+ uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+ int ttl = get_ttl_from_packet(nmb);
+ struct name_record *namerec = NULL;
+ struct in_addr from_ip;
+ bool group = (nb_flags & NB_GROUP) ? True : False;
+ struct in_addr our_fake_ip;
+ unstring qname;
+
+ (void)interpret_addr2(&our_fake_ip, "0.0.0.0");
+ putip((char *)&from_ip,&nmb->additional->rdata[2]);
+
+ if(bcast) {
+ /*
+ * We should only get unicast name registration packets here.
+ * Anyone trying to register broadcast should not be going to a WINS
+ * server. Log an error here.
+ */
+
+ DEBUG(0,("wins_process_multihomed_name_registration_request: broadcast name registration request \
+received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
+ nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+ return;
+ }
+
+ /*
+ * Only unique names should be registered multihomed.
+ */
+
+ if(group) {
+ DEBUG(0,("wins_process_multihomed_name_registration_request: group name registration request \
+received for name %s from IP %s on subnet %s. Errror - group names should not be multihomed.\n",
+ nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+ return;
+ }
+
+ DEBUG(3,("wins_process_multihomed_name_registration_request: name registration for name %s \
+IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ));
+
+ /*
+ * Deal with policy regarding 0x1d names.
+ */
+
+ if(question->name_type == 0x1d) {
+ DEBUG(3,("wins_process_multihomed_name_registration_request: Ignoring request \
+to register name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
+ send_wins_name_registration_response(0, ttl, p);
+ return;
+ }
+
+ /*
+ * See if the name already exists.
+ */
+
+ namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+ /*
+ * if the record exists but NOT in active state,
+ * consider it dead.
+ */
+
+ if ((namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
+ DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was not active - removing it.\n", nmb_namestr(question)));
+ remove_name_from_namelist(subrec, namerec);
+ namerec = NULL;
+ }
+
+ /*
+ * Deal with the case where the name found was a dns entry.
+ * Remove it as we now have a NetBIOS client registering the
+ * name.
+ */
+
+ if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
+ DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was a dns lookup \
+- removing it.\n", nmb_namestr(question) ));
+ remove_name_from_namelist( subrec, namerec);
+ namerec = NULL;
+ }
+
+ /*
+ * Reject if the name exists and is not a REGISTER_NAME.
+ * (ie. Don't allow any static names to be overwritten.
+ */
+
+ if( (namerec != NULL) && (namerec->data.source != REGISTER_NAME) ) {
+ DEBUG( 3, ( "wins_process_multihomed_name_registration_request: Attempt \
+to register name %s. Name already exists in WINS with source type %d.\n",
+ nmb_namestr(question), namerec->data.source ));
+ send_wins_name_registration_response(RFS_ERR, 0, p);
+ return;
+ }
+
+ /*
+ * Reject if the name exists and is a GROUP name and is active.
+ */
+
+ if((namerec != NULL) && NAME_GROUP(namerec) && WINS_STATE_ACTIVE(namerec)) {
+ DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
+already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
+ send_wins_name_registration_response(RFS_ERR, 0, p);
+ return;
+ }
+
+ /*
+ * From here on down we know that if the name exists in the WINS db it is
+ * a unique name, not a group name.
+ */
+
+ /*
+ * If the name exists and is one of our names then check the
+ * registering IP address. If it's not one of ours then automatically
+ * reject without doing the query - we know we will reject it.
+ */
+
+ if((namerec != NULL) && (is_myname(namerec->name.name)) ) {
+ if(!ismyip_v4(from_ip)) {
+ DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
+is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
+ send_wins_name_registration_response(RFS_ERR, 0, p);
+ return;
+ } else {
+ /*
+ * It's one of our names and one of our IP's. Ensure the IP is in the record and
+ * update the ttl. Update the version ID to force replication.
+ */
+ update_name_ttl(namerec, ttl);
+
+ if(!find_ip_in_name_record(namerec, from_ip)) {
+ get_global_id_and_update(&namerec->data.id, True);
+ update_wins_owner(namerec, our_fake_ip);
+ update_wins_flag(namerec, WINS_ACTIVE);
+
+ add_ip_to_name_record(namerec, from_ip);
+ }
+
+ wins_hook("refresh", namerec, ttl);
+ send_wins_name_registration_response(0, ttl, p);
+ return;
+ }
+ }
+
+ /*
+ * If the name exists and is active, 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) && WINS_STATE_ACTIVE(namerec)) {
+ update_name_ttl(namerec, ttl);
+
+ /*
+ * If it's a replica, we need to become the wins owner
+ * to force the replication
+ */
+ if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
+ get_global_id_and_update(&namerec->data.id, True);
+ update_wins_owner(namerec, our_fake_ip);
+ update_wins_flag(namerec, WINS_ACTIVE);
+ }
+
+ wins_hook("refresh", 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) {
+ long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
+ struct userdata_struct *userdata = (struct userdata_struct *)ud;
+
+ /*
+ * First send a WACK to the registering machine.
+ */
+
+ send_wins_wack_response(60, p);
+
+ /*
+ * When the reply comes back we need the original packet.
+ * Lock this so it won't be freed and then put it into
+ * the userdata structure.
+ */
+
+ p->locked = True;
+
+ userdata = (struct userdata_struct *)ud;
+
+ userdata->copy_fn = NULL;
+ userdata->free_fn = NULL;
+ userdata->userdata_len = sizeof(struct packet_struct *);
+ memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
+
+ /*
+ * Use the new call to send a query directly to an IP address.
+ * This sends the query directly to the IP address, and ensures
+ * the recursion desired flag is not set (you were right Luke :-).
+ * This function should *only* be called from the WINS server
+ * code. JRA.
+ *
+ * Note that this packet is sent to the current owner of the name,
+ * not the person who sent the packet
+ */
+
+ pull_ascii_nstring( qname, sizeof(qname), question->name);
+ query_name_from_wins_server( namerec->data.ip[0],
+ qname,
+ question->name_type,
+ wins_multihomed_register_query_success,
+ wins_multihomed_register_query_fail,
+ userdata );
+
+ return;
+ }
+
+ /*
+ * Name did not exist - add it.
+ */
+
+ pull_ascii_nstring( qname, sizeof(qname), question->name);
+ add_name_to_subnet( subrec, qname, question->name_type,
+ nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
+
+ if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
+ get_global_id_and_update(&namerec->data.id, True);
+ update_wins_owner(namerec, our_fake_ip);
+ update_wins_flag(namerec, WINS_ACTIVE);
+ wins_hook("add", namerec, ttl);
+ }
+
+ send_wins_name_registration_response(0, ttl, p);
+}
+
+/***********************************************************************
+ Fetch all *<1b> names from the WINS db and store on the namelist.
+***********************************************************************/
+
+static int fetch_1b_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct name_record *namerec = NULL;
+
+ if (kbuf.dsize != sizeof(unstring) + 1) {
+ return 0;
+ }
+
+ /* Filter out all non-1b names. */
+ if (kbuf.dptr[sizeof(unstring)] != 0x1b) {
+ return 0;
+ }
+
+ namerec = wins_record_to_name_record(kbuf, dbuf);
+ if (!namerec) {
+ return 0;
+ }
+
+ DLIST_ADD(wins_server_subnet->namelist, namerec);
+ return 0;
+}
+
+void fetch_all_active_wins_1b_names(void)
+{
+ tdb_traverse(wins_tdb, fetch_1b_traverse_fn, NULL);
+}
+
+/***********************************************************************
+ 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 ACTIVE 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;
+
+ /* First, clear the in memory list - we're going to re-populate
+ it with the tdb_traversal in fetch_all_active_wins_1b_names. */
+
+ wins_delete_all_tmp_in_memory_records();
+
+ fetch_all_active_wins_1b_names();
+
+ for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
+ if( WINS_STATE_ACTIVE(namerec) && 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 *)SMB_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 = subrec->namelist; namerec; namerec = namerec->next ) {
+ if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
+ int i;
+ for(i = 0; i < namerec->data.num_ips; i++) {
+ set_nb_flags(&prdata[num_ips * 6],namerec->data.nb_flags);
+ putip((char *)&prdata[(num_ips * 6) + 2], &namerec->data.ip[i]);
+ num_ips++;
+ }
+ }
+ }
+
+ /*
+ * Send back the reply containing the IP list.
+ */
+
+ reply_netbios_packet(p, /* Packet to reply to. */
+ 0, /* Result code. */
+ WINS_QUERY, /* nmbd type code. */
+ NMB_NAME_QUERY_OPCODE, /* opcode. */
+ lp_min_wins_ttl(), /* ttl. */
+ prdata, /* data to send. */
+ num_ips*6); /* data length. */
+
+ SAFE_FREE(prdata);
+}
+
+/****************************************************************************
+Send a WINS name query response.
+**************************************************************************/
+
+void send_wins_name_query_response(int rcode, struct packet_struct *p,
+ struct name_record *namerec)
+{
+ char rdata[6];
+ char *prdata = rdata;
+ int reply_data_len = 0;
+ int ttl = 0;
+ int i;
+
+ memset(rdata,'\0',6);
+
+ if(rcode == 0) {
+ ttl = (namerec->data.death_time != PERMANENT_TTL) ? namerec->data.death_time - p->timestamp : lp_max_wins_ttl();
+
+ /* Copy all known ip addresses into the return data. */
+ /* Optimise for the common case of one IP address so we don't need a malloc. */
+
+ if( namerec->data.num_ips == 1 ) {
+ prdata = rdata;
+ } else {
+ if((prdata = (char *)SMB_MALLOC( namerec->data.num_ips * 6 )) == NULL) {
+ DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
+ return;
+ }
+ }
+
+ for(i = 0; i < namerec->data.num_ips; i++) {
+ set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
+ putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
+ }
+
+ sort_query_replies(prdata, i, p->ip);
+ reply_data_len = namerec->data.num_ips * 6;
+ }
+
+ reply_netbios_packet(p, /* Packet to reply to. */
+ rcode, /* Result code. */
+ WINS_QUERY, /* nmbd type code. */
+ NMB_NAME_QUERY_OPCODE, /* opcode. */
+ ttl, /* ttl. */
+ prdata, /* data to send. */
+ reply_data_len); /* data length. */
+
+ if(prdata != rdata) {
+ SAFE_FREE(prdata);
+ }
+}
+
+/***********************************************************************
+ Deal with a name query.
+***********************************************************************/
+
+void wins_process_name_query_request(struct subnet_record *subrec,
+ struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ struct name_record *namerec = NULL;
+ unstring qname;
+
+ DEBUG(3,("wins_process_name_query: name query for name %s from IP %s\n",
+ nmb_namestr(question), inet_ntoa(p->ip) ));
+
+ /*
+ * Special name code. If the queried name is *<1b> then search
+ * the entire WINS database and return a list of all the IP addresses
+ * registered to any <1b> name. This is to allow domain master browsers
+ * to discover other domains that may not have a presence on their subnet.
+ */
+
+ pull_ascii_nstring(qname, sizeof(qname), question->name);
+ if(strequal( qname, "*") && (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 the name is not anymore in active state then reply not found.
+ * it's fair even if we keep it in the cache for days.
+ */
+ if (!WINS_STATE_ACTIVE(namerec)) {
+ DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
+ nmb_namestr(question) ));
+ send_wins_name_query_response(NAM_ERR, p, namerec);
+ return;
+ }
+
+ /*
+ * If it's a DNSFAIL_NAME then reply name not found.
+ */
+
+ if( namerec->data.source == DNSFAIL_NAME ) {
+ DEBUG(3,("wins_process_name_query: name query for name %s returning DNS fail.\n",
+ nmb_namestr(question) ));
+ send_wins_name_query_response(NAM_ERR, p, namerec);
+ return;
+ }
+
+ /*
+ * If the name has expired then reply name not found.
+ */
+
+ if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < p->timestamp) ) {
+ DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
+ nmb_namestr(question) ));
+ send_wins_name_query_response(NAM_ERR, p, namerec);
+ return;
+ }
+
+ DEBUG(3,("wins_process_name_query: name query for name %s returning first IP %s.\n",
+ nmb_namestr(question), inet_ntoa(namerec->data.ip[0]) ));
+
+ send_wins_name_query_response(0, p, namerec);
+ return;
+ }
+
+ /*
+ * Name not found in WINS - try a dns query if it's a 0x20 name.
+ */
+
+ if(lp_dns_proxy() && ((question->name_type == 0x20) || question->name_type == 0)) {
+ DEBUG(3,("wins_process_name_query: name query for name %s not found - doing dns lookup.\n",
+ nmb_namestr(question) ));
+
+ queue_dns_query(p, question);
+ return;
+ }
+
+ /*
+ * Name not found - return error.
+ */
+
+ send_wins_name_query_response(NAM_ERR, p, NULL);
+}
+
+/****************************************************************************
+Send a WINS name release response.
+**************************************************************************/
+
+static void send_wins_name_release_response(int rcode, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ char rdata[6];
+
+ memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
+
+ reply_netbios_packet(p, /* Packet to reply to. */
+ rcode, /* Result code. */
+ NMB_REL, /* nmbd type code. */
+ NMB_NAME_RELEASE_OPCODE, /* opcode. */
+ 0, /* ttl. */
+ rdata, /* data to send. */
+ 6); /* data length. */
+}
+
+/***********************************************************************
+ Deal with a name release.
+***********************************************************************/
+
+void wins_process_name_release_request(struct subnet_record *subrec,
+ struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ bool bcast = nmb->header.nm_flags.bcast;
+ uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+ struct name_record *namerec = NULL;
+ struct in_addr from_ip;
+ bool releasing_group_name = (nb_flags & NB_GROUP) ? True : False;;
+
+ putip((char *)&from_ip,&nmb->additional->rdata[2]);
+
+ if(bcast) {
+ /*
+ * We should only get unicast name registration packets here.
+ * Anyone trying to register broadcast should not be going to a WINS
+ * server. Log an error here.
+ */
+
+ DEBUG(0,("wins_process_name_release_request: broadcast name registration request \
+received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
+ nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+ return;
+ }
+
+ DEBUG(3,("wins_process_name_release_request: %s name release for name %s \
+IP %s\n", releasing_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
+
+ /*
+ * Deal with policy regarding 0x1d names.
+ */
+
+ if(!releasing_group_name && (question->name_type == 0x1d)) {
+ DEBUG(3,("wins_process_name_release_request: Ignoring request \
+to release name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
+ send_wins_name_release_response(0, p);
+ return;
+ }
+
+ /*
+ * See if the name already exists.
+ */
+
+ namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+ if( (namerec == NULL) || ((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) ) {
+ send_wins_name_release_response(NAM_ERR, p);
+ return;
+ }
+
+ /*
+ * Check that the sending machine has permission to release this name.
+ * If it's a group name not ending in 0x1c then just say yes and let
+ * the group time out.
+ */
+
+ if(releasing_group_name && (question->name_type != 0x1c)) {
+ send_wins_name_release_response(0, p);
+ return;
+ }
+
+ /*
+ * Check that the releasing node is on the list of IP addresses
+ * for this name. Disallow the release if not.
+ */
+
+ if(!find_ip_in_name_record(namerec, from_ip)) {
+ DEBUG(3,("wins_process_name_release_request: Refusing request to \
+release name %s as IP %s is not one of the known IP's for this name.\n",
+ nmb_namestr(question), inet_ntoa(from_ip) ));
+ send_wins_name_release_response(NAM_ERR, p);
+ return;
+ }
+
+ /*
+ * Check if the record is active. IF it's already released
+ * or tombstoned, refuse the release.
+ */
+
+ if (!WINS_STATE_ACTIVE(namerec)) {
+ DEBUG(3,("wins_process_name_release_request: Refusing request to \
+release name %s as this record is not active anymore.\n", nmb_namestr(question) ));
+ send_wins_name_release_response(NAM_ERR, p);
+ return;
+ }
+
+ /*
+ * Check if the record is a 0x1c group
+ * and has more then one ip
+ * remove only this address.
+ */
+
+ if(releasing_group_name && (question->name_type == 0x1c) && (namerec->data.num_ips > 1)) {
+ remove_ip_from_name_record(namerec, from_ip);
+ DEBUG(3,("wins_process_name_release_request: Remove IP %s from NAME: %s\n",
+ inet_ntoa(from_ip),nmb_namestr(question)));
+ wins_hook("delete", namerec, 0);
+ send_wins_name_release_response(0, p);
+ return;
+ }
+
+ /*
+ * Send a release response.
+ * Flag the name as released and update the ttl
+ */
+
+ namerec->data.wins_flags |= WINS_RELEASED;
+ update_name_ttl(namerec, EXTINCTION_INTERVAL);
+
+ wins_hook("delete", namerec, 0);
+ send_wins_name_release_response(0, p);
+}
+
+/*******************************************************************
+ WINS time dependent processing.
+******************************************************************/
+
+static int wins_processing_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ time_t t = *(time_t *)state;
+ bool store_record = False;
+ struct name_record *namerec = NULL;
+ struct in_addr our_fake_ip;
+
+ (void)interpret_addr2(&our_fake_ip, "0.0.0.0");
+ if (kbuf.dsize != sizeof(unstring) + 1) {
+ return 0;
+ }
+
+ namerec = wins_record_to_name_record(kbuf, dbuf);
+ if (!namerec) {
+ return 0;
+ }
+
+ if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
+ if( namerec->data.source == SELF_NAME ) {
+ DEBUG( 3, ( "wins_processing_traverse_fn: Subnet %s not expiring SELF name %s\n",
+ wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) );
+ namerec->data.death_time += 300;
+ store_record = True;
+ goto done;
+ } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) {
+ DEBUG(3,("wins_processing_traverse_fn: deleting timed out DNS name %s\n",
+ nmb_namestr(&namerec->name)));
+ remove_name_from_wins_namelist(namerec );
+ goto done;
+ }
+
+ /* handle records, samba is the wins owner */
+ if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
+ switch (namerec->data.wins_flags & WINS_STATE_MASK) {
+ case WINS_ACTIVE:
+ namerec->data.wins_flags&=~WINS_STATE_MASK;
+ namerec->data.wins_flags|=WINS_RELEASED;
+ namerec->data.death_time = t + EXTINCTION_INTERVAL;
+ DEBUG(3,("wins_processing_traverse_fn: expiring %s\n",
+ nmb_namestr(&namerec->name)));
+ store_record = True;
+ goto done;
+ case WINS_RELEASED:
+ namerec->data.wins_flags&=~WINS_STATE_MASK;
+ namerec->data.wins_flags|=WINS_TOMBSTONED;
+ namerec->data.death_time = t + EXTINCTION_TIMEOUT;
+ get_global_id_and_update(&namerec->data.id, True);
+ DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
+ nmb_namestr(&namerec->name)));
+ store_record = True;
+ goto done;
+ case WINS_TOMBSTONED:
+ DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
+ nmb_namestr(&namerec->name)));
+ remove_name_from_wins_namelist(namerec );
+ goto done;
+ }
+ } else {
+ switch (namerec->data.wins_flags & WINS_STATE_MASK) {
+ case WINS_ACTIVE:
+ /* that's not as MS says it should be */
+ namerec->data.wins_flags&=~WINS_STATE_MASK;
+ namerec->data.wins_flags|=WINS_TOMBSTONED;
+ namerec->data.death_time = t + EXTINCTION_TIMEOUT;
+ DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
+ nmb_namestr(&namerec->name)));
+ store_record = True;
+ goto done;
+ case WINS_TOMBSTONED:
+ DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
+ nmb_namestr(&namerec->name)));
+ remove_name_from_wins_namelist(namerec );
+ goto done;
+ case WINS_RELEASED:
+ DEBUG(0,("wins_processing_traverse_fn: %s is in released state and\
+we are not the wins owner !\n", nmb_namestr(&namerec->name)));
+ goto done;
+ }
+ }
+ }
+
+ done:
+
+ if (store_record) {
+ wins_store_changed_namerec(namerec);
+ }
+
+ SAFE_FREE(namerec->data.ip);
+ SAFE_FREE(namerec);
+
+ return 0;
+}
+
+/*******************************************************************
+ Time dependent wins processing.
+******************************************************************/
+
+void initiate_wins_processing(time_t t)
+{
+ static time_t lasttime = 0;
+
+ if (!lasttime) {
+ lasttime = t;
+ }
+ if (t - lasttime < 20) {
+ return;
+ }
+
+ if(!lp_we_are_a_wins_server()) {
+ lasttime = t;
+ return;
+ }
+
+ tdb_traverse(wins_tdb, wins_processing_traverse_fn, &t);
+
+ wins_delete_all_tmp_in_memory_records();
+
+ wins_write_database(t, True);
+
+ lasttime = t;
+}
+
+/*******************************************************************
+ Write out one record.
+******************************************************************/
+
+void wins_write_name_record(struct name_record *namerec, XFILE *fp)
+{
+ int i;
+ struct tm *tm;
+
+ DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) ));
+
+ if( namerec->data.death_time != PERMANENT_TTL ) {
+ char *ts, *nl;
+
+ tm = localtime(&namerec->data.death_time);
+ if (!tm) {
+ return;
+ }
+ ts = asctime(tm);
+ if (!ts) {
+ return;
+ }
+ nl = strrchr( ts, '\n' );
+ if( NULL != nl ) {
+ *nl = '\0';
+ }
+ DEBUGADD(4,("TTL = %s ", ts ));
+ } else {
+ DEBUGADD(4,("TTL = PERMANENT "));
+ }
+
+ for (i = 0; i < namerec->data.num_ips; i++) {
+ DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) ));
+ }
+ DEBUGADD(4,("%2x\n", namerec->data.nb_flags ));
+
+ if( namerec->data.source == REGISTER_NAME ) {
+ unstring name;
+ pull_ascii_nstring(name, sizeof(name), namerec->name.name);
+ x_fprintf(fp, "\"%s#%02x\" %d ", name,namerec->name.name_type, /* Ignore scope. */
+ (int)namerec->data.death_time);
+
+ for (i = 0; i < namerec->data.num_ips; i++)
+ x_fprintf( fp, "%s ", inet_ntoa( namerec->data.ip[i] ) );
+ x_fprintf( fp, "%2xR\n", namerec->data.nb_flags );
+ }
+}
+
+/*******************************************************************
+ Write out the current WINS database.
+******************************************************************/
+
+static int wins_writedb_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct name_record *namerec = NULL;
+ XFILE *fp = (XFILE *)state;
+
+ if (kbuf.dsize != sizeof(unstring) + 1) {
+ return 0;
+ }
+
+ namerec = wins_record_to_name_record(kbuf, dbuf);
+ if (!namerec) {
+ return 0;
+ }
+
+ wins_write_name_record(namerec, fp);
+
+ SAFE_FREE(namerec->data.ip);
+ SAFE_FREE(namerec);
+ return 0;
+}
+
+
+void wins_write_database(time_t t, bool background)
+{
+ static time_t last_write_time = 0;
+ char *fname = NULL;
+ char *fnamenew = NULL;
+
+ XFILE *fp;
+
+ if (background) {
+ if (!last_write_time) {
+ last_write_time = t;
+ }
+ if (t - last_write_time < 120) {
+ return;
+ }
+
+ }
+
+ if(!lp_we_are_a_wins_server()) {
+ return;
+ }
+
+ /* We will do the writing in a child process to ensure that the parent doesn't block while this is done */
+ if (background) {
+ CatchChild();
+ if (sys_fork()) {
+ return;
+ }
+ if (tdb_reopen(wins_tdb)) {
+ DEBUG(0,("wins_write_database: tdb_reopen failed. Error was %s\n",
+ strerror(errno)));
+ _exit(0);
+ return;
+ }
+ }
+
+ if (asprintf(&fname, "%s/%s", get_dyn_STATEDIR(), WINS_LIST) < 0) {
+ goto err_exit;
+ }
+ /* This is safe as the 0 length means "don't expand". */
+ all_string_sub(fname,"//", "/", 0);
+
+ if (asprintf(&fnamenew, "%s.%u", fname, (unsigned int)sys_getpid()) < 0) {
+ goto err_exit;
+ }
+
+ if((fp = x_fopen(fnamenew,O_WRONLY|O_CREAT,0644)) == NULL) {
+ DEBUG(0,("wins_write_database: Can't open %s. Error was %s\n", fnamenew, strerror(errno)));
+ goto err_exit;
+ }
+
+ DEBUG(4,("wins_write_database: Dump of WINS name list.\n"));
+
+ x_fprintf(fp,"VERSION %d %u\n", WINS_VERSION, 0);
+
+ tdb_traverse(wins_tdb, wins_writedb_traverse_fn, fp);
+
+ x_fclose(fp);
+ chmod(fnamenew,0644);
+ unlink(fname);
+ rename(fnamenew,fname);
+
+ err_exit:
+
+ SAFE_FREE(fname);
+ SAFE_FREE(fnamenew);
+
+ if (background) {
+ _exit(0);
+ }
+}
+
+#if 0
+ Until winsrepl is done.
+/****************************************************************************
+ Process a internal Samba message receiving a wins record.
+***************************************************************************/
+
+void nmbd_wins_new_entry(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ WINS_RECORD *record;
+ struct name_record *namerec = NULL;
+ struct name_record *new_namerec = NULL;
+ struct nmb_name question;
+ bool overwrite=False;
+ struct in_addr our_fake_ip;
+ int i;
+
+ (void)interpret_addr2(&our_fake_ip, "0.0.0.0");
+ if (buf==NULL) {
+ return;
+ }
+
+ /* Record should use UNIX codepage. Ensure this is so in the wrepld code. JRA. */
+ record=(WINS_RECORD *)buf;
+
+ make_nmb_name(&question, record->name, record->type);
+
+ namerec = find_name_on_subnet(wins_server_subnet, &question, FIND_ANY_NAME);
+
+ /* record doesn't exist, add it */
+ if (namerec == NULL) {
+ DEBUG(3,("nmbd_wins_new_entry: adding new replicated record: %s<%02x> for wins server: %s\n",
+ record->name, record->type, inet_ntoa(record->wins_ip)));
+
+ new_namerec=add_name_to_subnet( wins_server_subnet,
+ record->name,
+ record->type,
+ record->nb_flags,
+ EXTINCTION_INTERVAL,
+ REGISTER_NAME,
+ record->num_ips,
+ record->ip);
+
+ if (new_namerec!=NULL) {
+ update_wins_owner(new_namerec, record->wins_ip);
+ update_wins_flag(new_namerec, record->wins_flags);
+ new_namerec->data.id=record->id;
+
+ wins_server_subnet->namelist_changed = True;
+ }
+ }
+
+ /* check if we have a conflict */
+ if (namerec != NULL) {
+ /* both records are UNIQUE */
+ if (namerec->data.wins_flags&WINS_UNIQUE && record->wins_flags&WINS_UNIQUE) {
+
+ /* the database record is a replica */
+ if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
+ if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED) {
+ if (ip_equal_v4(namerec->data.wins_ip, record->wins_ip))
+ overwrite=True;
+ } else
+ overwrite=True;
+ } else {
+ /* we are the wins owner of the database record */
+ /* the 2 records have the same IP address */
+ if (ip_equal_v4(namerec->data.ip[0], record->ip[0])) {
+ if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED)
+ get_global_id_and_update(&namerec->data.id, True);
+ else
+ overwrite=True;
+
+ } else {
+ /* the 2 records have different IP address */
+ if (namerec->data.wins_flags&WINS_ACTIVE) {
+ if (record->wins_flags&WINS_TOMBSTONED)
+ get_global_id_and_update(&namerec->data.id, True);
+ if (record->wins_flags&WINS_ACTIVE)
+ /* send conflict challenge to the replica node */
+ ;
+ } else
+ overwrite=True;
+ }
+
+ }
+ }
+
+ /* the replica is a standard group */
+ if (record->wins_flags&WINS_NGROUP || record->wins_flags&WINS_SGROUP) {
+ /* if the database record is unique and active force a name release */
+ if (namerec->data.wins_flags&WINS_UNIQUE)
+ /* send a release name to the unique node */
+ ;
+ overwrite=True;
+
+ }
+
+ /* the replica is a special group */
+ if (record->wins_flags&WINS_SGROUP && namerec->data.wins_flags&WINS_SGROUP) {
+ if (namerec->data.wins_flags&WINS_ACTIVE) {
+ for (i=0; i<record->num_ips; i++)
+ if(!find_ip_in_name_record(namerec, record->ip[i]))
+ add_ip_to_name_record(namerec, record->ip[i]);
+ } else {
+ overwrite=True;
+ }
+ }
+
+ /* the replica is a multihomed host */
+
+ /* I'm giving up on multi homed. Too much complex to understand */
+
+ if (record->wins_flags&WINS_MHOMED) {
+ if (! (namerec->data.wins_flags&WINS_ACTIVE)) {
+ if ( !(namerec->data.wins_flags&WINS_RELEASED) && !(namerec->data.wins_flags&WINS_NGROUP))
+ overwrite=True;
+ }
+ else {
+ if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
+ overwrite=True;
+
+ if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip))
+ if (namerec->data.wins_flags&WINS_UNIQUE)
+ get_global_id_and_update(&namerec->data.id, True);
+
+ }
+
+ if (record->wins_flags&WINS_ACTIVE && namerec->data.wins_flags&WINS_ACTIVE)
+ if (namerec->data.wins_flags&WINS_UNIQUE ||
+ namerec->data.wins_flags&WINS_MHOMED)
+ if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
+ overwrite=True;
+
+ }
+
+ if (overwrite == False)
+ DEBUG(3, ("nmbd_wins_new_entry: conflict in adding record: %s<%02x> from wins server: %s\n",
+ record->name, record->type, inet_ntoa(record->wins_ip)));
+ else {
+ DEBUG(3, ("nmbd_wins_new_entry: replacing record: %s<%02x> from wins server: %s\n",
+ record->name, record->type, inet_ntoa(record->wins_ip)));
+
+ /* remove the old record and add a new one */
+ remove_name_from_namelist( wins_server_subnet, namerec );
+ new_namerec=add_name_to_subnet( wins_server_subnet, record->name, record->type, record->nb_flags,
+ EXTINCTION_INTERVAL, REGISTER_NAME, record->num_ips, record->ip);
+ if (new_namerec!=NULL) {
+ update_wins_owner(new_namerec, record->wins_ip);
+ update_wins_flag(new_namerec, record->wins_flags);
+ new_namerec->data.id=record->id;
+
+ wins_server_subnet->namelist_changed = True;
+ }
+
+ wins_server_subnet->namelist_changed = True;
+ }
+
+ }
+}
+#endif
diff --git a/source3/nmbd/nmbd_workgroupdb.c b/source3/nmbd/nmbd_workgroupdb.c
new file mode 100644
index 0000000000..1845401d9e
--- /dev/null
+++ b/source3/nmbd/nmbd_workgroupdb.c
@@ -0,0 +1,329 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+extern uint16 samba_nb_type;
+
+int workgroup_count = 0; /* unique index key: one for each workgroup */
+
+/****************************************************************************
+ Add a workgroup into the list.
+**************************************************************************/
+
+static void add_workgroup(struct subnet_record *subrec, struct work_record *work)
+{
+ work->subnet = subrec;
+ DLIST_ADD(subrec->workgrouplist, work);
+ subrec->work_changed = True;
+}
+
+/****************************************************************************
+ Copy name to unstring. Used by create_workgroup() and find_workgroup_on_subnet().
+**************************************************************************/
+
+static void name_to_unstring(unstring unname, const char *name)
+{
+ nstring nname;
+
+ errno = 0;
+ push_ascii_nstring(nname, name);
+ if (errno == E2BIG) {
+ unstring tname;
+ pull_ascii_nstring(tname, sizeof(tname), nname);
+ unstrcpy(unname, tname);
+ DEBUG(0,("name_to_nstring: workgroup name %s is too long. Truncating to %s\n",
+ name, tname));
+ } else {
+ unstrcpy(unname, name);
+ }
+}
+
+/****************************************************************************
+ Create an empty workgroup.
+**************************************************************************/
+
+static struct work_record *create_workgroup(const char *name, int ttl)
+{
+ struct work_record *work;
+ struct subnet_record *subrec;
+ int t = -1;
+
+ if((work = SMB_MALLOC_P(struct work_record)) == NULL) {
+ DEBUG(0,("create_workgroup: malloc fail !\n"));
+ return NULL;
+ }
+ memset((char *)work, '\0', sizeof(*work));
+
+ name_to_unstring(work->work_group, name);
+
+ work->serverlist = NULL;
+
+ work->RunningElection = False;
+ work->ElectionCount = 0;
+ work->announce_interval = 0;
+ work->needelection = False;
+ work->needannounce = True;
+ work->lastannounce_time = time(NULL);
+ work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+ work->dom_state = DOMAIN_NONE;
+ work->log_state = LOGON_NONE;
+
+ work->death_time = (ttl != PERMANENT_TTL) ? time(NULL)+(ttl*3) : PERMANENT_TTL;
+
+ /* Make sure all token representations of workgroups are unique. */
+
+ for (subrec = FIRST_SUBNET; subrec && (t == -1); subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
+ struct work_record *w;
+ for (w = subrec->workgrouplist; w && t == -1; w = w->next) {
+ if (strequal(w->work_group, work->work_group))
+ t = w->token;
+ }
+ }
+
+ if (t == -1)
+ work->token = ++workgroup_count;
+ else
+ work->token = t;
+
+ /* No known local master browser as yet. */
+ *work->local_master_browser_name = '\0';
+
+ /* No known domain master browser as yet. */
+ *work->dmb_name.name = '\0';
+ zero_ip_v4(&work->dmb_addr);
+
+ /* WfWg uses 01040b01 */
+ /* Win95 uses 01041501 */
+ /* NTAS uses ???????? */
+ work->ElectionCriterion = (MAINTAIN_LIST)|(BROWSER_ELECTION_VERSION<<8);
+ work->ElectionCriterion |= (lp_os_level() << 24);
+ if (lp_domain_master())
+ work->ElectionCriterion |= 0x80;
+
+ return work;
+}
+
+/*******************************************************************
+ Remove a workgroup.
+******************************************************************/
+
+static struct work_record *remove_workgroup_from_subnet(struct subnet_record *subrec,
+ struct work_record *work)
+{
+ struct work_record *ret_work = NULL;
+
+ DEBUG(3,("remove_workgroup: Removing workgroup %s\n", work->work_group));
+
+ ret_work = work->next;
+
+ remove_all_servers(work);
+
+ if (!work->serverlist) {
+ if (work->prev)
+ work->prev->next = work->next;
+ if (work->next)
+ work->next->prev = work->prev;
+
+ if (subrec->workgrouplist == work)
+ subrec->workgrouplist = work->next;
+
+ ZERO_STRUCTP(work);
+ SAFE_FREE(work);
+ }
+
+ subrec->work_changed = True;
+
+ return ret_work;
+}
+
+/****************************************************************************
+ Find a workgroup in the workgroup list of a subnet.
+**************************************************************************/
+
+struct work_record *find_workgroup_on_subnet(struct subnet_record *subrec,
+ const char *name)
+{
+ struct work_record *ret;
+ unstring un_name;
+
+ DEBUG(4, ("find_workgroup_on_subnet: workgroup search for %s on subnet %s: ",
+ name, subrec->subnet_name));
+
+ name_to_unstring(un_name, name);
+
+ for (ret = subrec->workgrouplist; ret; ret = ret->next) {
+ if (strequal(ret->work_group,un_name)) {
+ DEBUGADD(4, ("found.\n"));
+ return(ret);
+ }
+ }
+ DEBUGADD(4, ("not found.\n"));
+ return NULL;
+}
+
+/****************************************************************************
+ Create a workgroup in the workgroup list of the subnet.
+**************************************************************************/
+
+struct work_record *create_workgroup_on_subnet(struct subnet_record *subrec,
+ const char *name, int ttl)
+{
+ struct work_record *work = NULL;
+
+ DEBUG(4,("create_workgroup_on_subnet: creating group %s on subnet %s\n",
+ name, subrec->subnet_name));
+
+ if ((work = create_workgroup(name, ttl))) {
+ add_workgroup(subrec, work);
+ subrec->work_changed = True;
+ return(work);
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Update a workgroup ttl.
+**************************************************************************/
+
+void update_workgroup_ttl(struct work_record *work, int ttl)
+{
+ if(work->death_time != PERMANENT_TTL)
+ work->death_time = time(NULL)+(ttl*3);
+ work->subnet->work_changed = True;
+}
+
+/****************************************************************************
+ Fail function called if we cannot register the WORKGROUP<0> and
+ WORKGROUP<1e> names on the net.
+**************************************************************************/
+
+static void fail_register(struct subnet_record *subrec, struct response_record *rrec,
+ struct nmb_name *nmbname)
+{
+ DEBUG(0,("fail_register: Failed to register name %s on subnet %s.\n",
+ nmb_namestr(nmbname), subrec->subnet_name));
+}
+
+/****************************************************************************
+ If the workgroup is our primary workgroup, add the required names to it.
+**************************************************************************/
+
+void initiate_myworkgroup_startup(struct subnet_record *subrec, struct work_record *work)
+{
+ int i;
+
+ if(!strequal(lp_workgroup(), 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,lp_workgroup(),0x0,samba_nb_type|NB_GROUP, NULL, fail_register,NULL);
+ register_name(subrec,lp_workgroup(),0x1e,samba_nb_type|NB_GROUP, NULL, fail_register,NULL);
+
+ for( i = 0; my_netbios_names(i); i++) {
+ const char *name = my_netbios_names(i);
+ int stype = lp_default_server_announce() | (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0 );
+
+ if(!strequal(global_myname(), name))
+ stype &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_POTENTIAL_BROWSER|SV_TYPE_DOMAIN_MASTER|SV_TYPE_DOMAIN_MEMBER);
+
+ create_server_on_workgroup(work,name,stype|SV_TYPE_LOCAL_LIST_ONLY, PERMANENT_TTL,
+ string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
+ DEBUG(3,("initiate_myworkgroup_startup: Added server name entry %s \
+on subnet %s\n", name, subrec->subnet_name));
+ }
+}
+
+/****************************************************************************
+ Dump a copy of the workgroup database into the log file.
+ **************************************************************************/
+
+void dump_workgroups(bool force_write)
+{
+ struct subnet_record *subrec;
+ int debuglevel = force_write ? 0 : 4;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
+ if (subrec->workgrouplist) {
+ struct work_record *work;
+
+ if( DEBUGLVL( debuglevel ) ) {
+ dbgtext( "dump_workgroups()\n " );
+ dbgtext( "dump workgroup on subnet %15s: ", subrec->subnet_name );
+ dbgtext( "netmask=%15s:\n", inet_ntoa(subrec->mask_ip) );
+ }
+
+ for (work = subrec->workgrouplist; work; work = work->next) {
+ DEBUGADD( debuglevel, ( "\t%s(%d) current master browser = %s\n", work->work_group,
+ work->token, *work->local_master_browser_name ? work->local_master_browser_name : "UNKNOWN" ) );
+ if (work->serverlist) {
+ struct server_record *servrec;
+ for (servrec = work->serverlist; servrec; servrec = servrec->next) {
+ DEBUGADD( debuglevel, ( "\t\t%s %8x (%s)\n",
+ servrec->serv.name,
+ servrec->serv.type,
+ servrec->serv.comment ) );
+ }
+ }
+ }
+ }
+ }
+}
+
+/****************************************************************************
+ Expire any dead servers on all workgroups. If the workgroup has expired
+ remove it.
+ **************************************************************************/
+
+void expire_workgroups_and_servers(time_t t)
+{
+ struct subnet_record *subrec;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
+ struct work_record *work;
+ struct work_record *nextwork;
+
+ for (work = subrec->workgrouplist; work; work = nextwork) {
+ nextwork = work->next;
+ expire_servers(work, t);
+
+ if ((work->serverlist == NULL) && (work->death_time != PERMANENT_TTL) &&
+ ((t == (time_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/source3/nsswitch/libwbclient/Doxyfile b/source3/nsswitch/libwbclient/Doxyfile
new file mode 100644
index 0000000000..e12c2b06f0
--- /dev/null
+++ b/source3/nsswitch/libwbclient/Doxyfile
@@ -0,0 +1,1297 @@
+# Doxyfile 1.5.3
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file that
+# follow. The default is UTF-8 which is also the encoding used for all text before
+# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into
+# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of
+# possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = Samba
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = HEAD
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = dox
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian,
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean,
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian,
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH = $(PWD)/
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be extracted
+# and appear in the documentation as a namespace called 'anonymous_namespace{file}',
+# where file will be replaced with the base name of the file that contains the anonymous
+# namespace. By default anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = NO
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = NO
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = NO
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text "
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = .
+
+# This tag can be used to specify the character encoding of the source files that
+# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default
+# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding.
+# See http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS = *.c \
+ *.h \
+ *.idl
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = include/includes.h \
+ include/proto.h
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the output.
+# The symbol name can be a fully qualified name, a word, or if the wildcard * is used,
+# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH
+# then you must also enable this option. If you don't then doxygen will produce
+# a warning and turn it on anyway
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 1
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = .
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 3
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = YES
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = NO
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to
+# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to
+# specify the directory where the mscgen tool resides. If left empty the tool is assumed to
+# be found in the default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will
+# generate a caller dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the number
+# of direct children of the root node in a graph is already larger than
+# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/source3/nsswitch/libwbclient/libwbclient.h b/source3/nsswitch/libwbclient/libwbclient.h
new file mode 100644
index 0000000000..74cba7e796
--- /dev/null
+++ b/source3/nsswitch/libwbclient/libwbclient.h
@@ -0,0 +1,46 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind client API
+
+ Copyright (C) Gerald (Jerry) Carter 2007
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _LIBWBCLIENT_H
+#define _LIBWBCLIENT_H
+
+/* Super header including necessary public and private header files
+ for building the wbclient library. __DO NOT__ define anything
+ in this file. Only include other headers. */
+
+/* Winbind headers */
+
+#include "nsswitch/winbind_nss_config.h"
+#include "nsswitch/winbind_struct_protocol.h"
+
+#include <talloc.h>
+
+/* Public headers */
+
+#include "wbclient.h"
+
+/* Private headers */
+
+#include "wbc_err_internal.h"
+#include "wbclient_internal.h"
+
+
+#endif /* _LIBWBCLIENT_H */
diff --git a/source3/nsswitch/libwbclient/wbc_err_internal.h b/source3/nsswitch/libwbclient/wbc_err_internal.h
new file mode 100644
index 0000000000..83364b8cd9
--- /dev/null
+++ b/source3/nsswitch/libwbclient/wbc_err_internal.h
@@ -0,0 +1,45 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind client API
+
+ Copyright (C) Gerald (Jerry) Carter 2007
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _WBC_ERR_INTERNAL_H
+#define _WBC_ERR_INTERNAL_H
+
+/* Private macros */
+
+#define BAIL_ON_WBC_ERROR(x) \
+ do { \
+ if (!WBC_ERROR_IS_OK(x)) { \
+ goto done; \
+ } \
+ } while(0);
+
+#define BAIL_ON_PTR_ERROR(x, status) \
+ do { \
+ if ((x) == NULL) { \
+ status = WBC_ERR_NO_MEMORY; \
+ goto done; \
+ } else { \
+ status = WBC_ERR_SUCCESS; \
+ } \
+ } while (0);
+
+
+#endif /* _WBC_ERR_INTERNAL_H */
diff --git a/source3/nsswitch/libwbclient/wbc_idmap.c b/source3/nsswitch/libwbclient/wbc_idmap.c
new file mode 100644
index 0000000000..e32d66cd71
--- /dev/null
+++ b/source3/nsswitch/libwbclient/wbc_idmap.c
@@ -0,0 +1,423 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind client API
+
+ Copyright (C) Gerald (Jerry) Carter 2007
+
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Required Headers */
+
+#include "libwbclient.h"
+
+/** @brief Convert a Windows SID to a Unix uid
+ *
+ * @param *sid Pointer to the domain SID to be resolved
+ * @param *puid Pointer to the resolved uid_t value
+ *
+ * @return #wbcErr
+ *
+ **/
+
+wbcErr wbcSidToUid(const struct wbcDomainSid *sid, uid_t *puid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ char *sid_string = NULL;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ if (!sid || !puid) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* Initialize request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ wbc_status = wbcSidToString(sid, &sid_string);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
+ wbcFreeMemory(sid_string);
+
+ /* Make request */
+
+ wbc_status = wbcRequestResponse(WINBINDD_SID_TO_UID,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ *puid = response.data.uid;
+
+ wbc_status = WBC_ERR_SUCCESS;
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Convert a Unix uid to a Windows SID
+ *
+ * @param uid Unix uid to be resolved
+ * @param *sid Pointer to the resolved domain SID
+ *
+ * @return #wbcErr
+ *
+ **/
+
+wbcErr wbcUidToSid(uid_t uid, struct wbcDomainSid *sid)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ if (!sid) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* Initialize request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.uid = uid;
+
+ /* Make request */
+
+ wbc_status = wbcRequestResponse(WINBINDD_UID_TO_SID,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ wbc_status = wbcStringToSid(response.data.sid.sid, sid);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+done:
+ return wbc_status;
+}
+
+/** @brief Convert a Windows SID to a Unix gid
+ *
+ * @param *sid Pointer to the domain SID to be resolved
+ * @param *pgid Pointer to the resolved gid_t value
+ *
+ * @return #wbcErr
+ *
+ **/
+
+wbcErr wbcSidToGid(const struct wbcDomainSid *sid, gid_t *pgid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ char *sid_string = NULL;
+
+ if (!sid || !pgid) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* Initialize request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ wbc_status = wbcSidToString(sid, &sid_string);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
+ wbcFreeMemory(sid_string);
+
+ /* Make request */
+
+ wbc_status = wbcRequestResponse(WINBINDD_SID_TO_GID,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ *pgid = response.data.gid;
+
+ wbc_status = WBC_ERR_SUCCESS;
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Convert a Unix uid to a Windows SID
+ *
+ * @param gid Unix gid to be resolved
+ * @param *sid Pointer to the resolved domain SID
+ *
+ * @return #wbcErr
+ *
+ **/
+
+wbcErr wbcGidToSid(gid_t gid, struct wbcDomainSid *sid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ if (!sid) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* Initialize request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.gid = gid;
+
+ /* Make request */
+
+ wbc_status = wbcRequestResponse(WINBINDD_GID_TO_SID,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ wbc_status = wbcStringToSid(response.data.sid.sid, sid);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+done:
+ return wbc_status;
+}
+
+/** @brief Obtain a new uid from Winbind
+ *
+ * @param *puid *pointer to the allocated uid
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcAllocateUid(uid_t *puid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ if (!puid)
+ return WBC_ERR_INVALID_PARAM;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Make request */
+
+ wbc_status = wbcRequestResponse(WINBINDD_ALLOCATE_UID,
+ &request, &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ /* Copy out result */
+ *puid = response.data.uid;
+
+ wbc_status = WBC_ERR_SUCCESS;
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Obtain a new gid from Winbind
+ *
+ * @param *pgid Pointer to the allocated gid
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcAllocateGid(gid_t *pgid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ if (!pgid)
+ return WBC_ERR_INVALID_PARAM;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Make request */
+
+ wbc_status = wbcRequestResponse(WINBINDD_ALLOCATE_GID,
+ &request, &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ /* Copy out result */
+ *pgid = response.data.gid;
+
+ wbc_status = WBC_ERR_SUCCESS;
+
+ done:
+ return wbc_status;
+}
+
+/* we can't include smb.h here... */
+#define _ID_TYPE_UID 1
+#define _ID_TYPE_GID 2
+
+/** @brief Set an user id mapping
+ *
+ * @param uid Uid of the desired mapping.
+ * @param *sid Pointer to the sid of the diresired mapping.
+ *
+ * @return #wbcErr
+ **/
+wbcErr wbcSetUidMapping(uid_t uid, const struct wbcDomainSid *sid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ char *sid_string = NULL;
+
+ if (!sid) {
+ return WBC_ERR_INVALID_PARAM;
+ }
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Make request */
+
+ request.data.dual_idmapset.id = uid;
+ request.data.dual_idmapset.type = _ID_TYPE_UID;
+
+ wbc_status = wbcSidToString(sid, &sid_string);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ strncpy(request.data.dual_idmapset.sid, sid_string,
+ sizeof(request.data.dual_idmapset.sid)-1);
+ wbcFreeMemory(sid_string);
+
+ wbc_status = wbcRequestResponse(WINBINDD_SET_MAPPING,
+ &request, &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Set a group id mapping
+ *
+ * @param gid Gid of the desired mapping.
+ * @param *sid Pointer to the sid of the diresired mapping.
+ *
+ * @return #wbcErr
+ **/
+wbcErr wbcSetGidMapping(gid_t gid, const struct wbcDomainSid *sid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ char *sid_string = NULL;
+
+ if (!sid) {
+ return WBC_ERR_INVALID_PARAM;
+ }
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Make request */
+
+ request.data.dual_idmapset.id = gid;
+ request.data.dual_idmapset.type = _ID_TYPE_GID;
+
+ wbc_status = wbcSidToString(sid, &sid_string);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ strncpy(request.data.dual_idmapset.sid, sid_string,
+ sizeof(request.data.dual_idmapset.sid)-1);
+ wbcFreeMemory(sid_string);
+
+ wbc_status = wbcRequestResponse(WINBINDD_SET_MAPPING,
+ &request, &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Set the highwater mark for allocated uids.
+ *
+ * @param uid_hwm The new uid highwater mark value
+ *
+ * @return #wbcErr
+ **/
+wbcErr wbcSetUidHwm(uid_t uid_hwm)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Make request */
+
+ request.data.dual_idmapset.id = uid_hwm;
+ request.data.dual_idmapset.type = _ID_TYPE_UID;
+
+ wbc_status = wbcRequestResponse(WINBINDD_SET_HWM,
+ &request, &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Set the highwater mark for allocated gids.
+ *
+ * @param uid_hwm The new gid highwater mark value
+ *
+ * @return #wbcErr
+ **/
+wbcErr wbcSetGidHwm(gid_t gid_hwm)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Make request */
+
+ request.data.dual_idmapset.id = gid_hwm;
+ request.data.dual_idmapset.type = _ID_TYPE_GID;
+
+ wbc_status = wbcRequestResponse(WINBINDD_SET_HWM,
+ &request, &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ done:
+ return wbc_status;
+}
diff --git a/source3/nsswitch/libwbclient/wbc_pam.c b/source3/nsswitch/libwbclient/wbc_pam.c
new file mode 100644
index 0000000000..20b42b6efb
--- /dev/null
+++ b/source3/nsswitch/libwbclient/wbc_pam.c
@@ -0,0 +1,796 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind client API
+
+ Copyright (C) Gerald (Jerry) Carter 2007
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Required Headers */
+
+#include "libwbclient.h"
+
+/** @brief Authenticate a username/password pair
+ *
+ * @param username Name of user to authenticate
+ * @param password Clear text password os user
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcAuthenticateUser(const char *username,
+ const char *password)
+{
+ wbcErr wbc_status = WBC_ERR_SUCCESS;
+ struct wbcAuthUserParams params;
+
+ ZERO_STRUCT(params);
+
+ params.account_name = username;
+ params.level = WBC_AUTH_USER_LEVEL_PLAIN;
+ params.password.plaintext = password;
+
+ wbc_status = wbcAuthenticateUserEx(&params, NULL, NULL);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+done:
+ return wbc_status;
+}
+
+static wbcErr wbc_create_auth_info(TALLOC_CTX *mem_ctx,
+ const struct winbindd_response *resp,
+ struct wbcAuthUserInfo **_i)
+{
+ wbcErr wbc_status = WBC_ERR_SUCCESS;
+ struct wbcAuthUserInfo *i;
+ struct wbcDomainSid domain_sid;
+ char *p;
+ uint32_t sn = 0;
+ uint32_t j;
+
+ i = talloc(mem_ctx, struct wbcAuthUserInfo);
+ BAIL_ON_PTR_ERROR(i, wbc_status);
+
+ i->user_flags = resp->data.auth.info3.user_flgs;
+
+ i->account_name = talloc_strdup(i, resp->data.auth.info3.user_name);
+ BAIL_ON_PTR_ERROR(i->account_name, wbc_status);
+ i->user_principal= NULL;
+ i->full_name = talloc_strdup(i, resp->data.auth.info3.full_name);
+ BAIL_ON_PTR_ERROR(i->full_name, wbc_status);
+ i->domain_name = talloc_strdup(i, resp->data.auth.info3.logon_dom);
+ BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
+ i->dns_domain_name= NULL;
+
+ i->acct_flags = resp->data.auth.info3.acct_flags;
+ memcpy(i->user_session_key,
+ resp->data.auth.user_session_key,
+ sizeof(i->user_session_key));
+ memcpy(i->lm_session_key,
+ resp->data.auth.first_8_lm_hash,
+ sizeof(i->lm_session_key));
+
+ i->logon_count = resp->data.auth.info3.logon_count;
+ i->bad_password_count = resp->data.auth.info3.bad_pw_count;
+
+ i->logon_time = resp->data.auth.info3.logon_time;
+ i->logoff_time = resp->data.auth.info3.logoff_time;
+ i->kickoff_time = resp->data.auth.info3.kickoff_time;
+ i->pass_last_set_time = resp->data.auth.info3.pass_last_set_time;
+ i->pass_can_change_time = resp->data.auth.info3.pass_can_change_time;
+ i->pass_must_change_time= resp->data.auth.info3.pass_must_change_time;
+
+ i->logon_server = talloc_strdup(i, resp->data.auth.info3.logon_srv);
+ BAIL_ON_PTR_ERROR(i->logon_server, wbc_status);
+ i->logon_script = talloc_strdup(i, resp->data.auth.info3.logon_script);
+ BAIL_ON_PTR_ERROR(i->logon_script, wbc_status);
+ i->profile_path = talloc_strdup(i, resp->data.auth.info3.profile_path);
+ BAIL_ON_PTR_ERROR(i->profile_path, wbc_status);
+ i->home_directory= talloc_strdup(i, resp->data.auth.info3.home_dir);
+ BAIL_ON_PTR_ERROR(i->home_directory, wbc_status);
+ i->home_drive = talloc_strdup(i, resp->data.auth.info3.dir_drive);
+ BAIL_ON_PTR_ERROR(i->home_drive, wbc_status);
+
+ i->num_sids = 2;
+ i->num_sids += resp->data.auth.info3.num_groups;
+ i->num_sids += resp->data.auth.info3.num_other_sids;
+
+ i->sids = talloc_array(i, struct wbcSidWithAttr, i->num_sids);
+ BAIL_ON_PTR_ERROR(i->sids, wbc_status);
+
+ wbc_status = wbcStringToSid(resp->data.auth.info3.dom_sid,
+ &domain_sid);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+#define _SID_COMPOSE(s, d, r, a) { \
+ (s).sid = d; \
+ if ((s).sid.num_auths < WBC_MAXSUBAUTHS) { \
+ (s).sid.sub_auths[(s).sid.num_auths++] = r; \
+ } else { \
+ wbc_status = WBC_ERR_INVALID_SID; \
+ BAIL_ON_WBC_ERROR(wbc_status); \
+ } \
+ (s).attributes = a; \
+} while (0)
+
+ sn = 0;
+ _SID_COMPOSE(i->sids[sn], domain_sid,
+ resp->data.auth.info3.user_rid,
+ 0);
+ sn++;
+ _SID_COMPOSE(i->sids[sn], domain_sid,
+ resp->data.auth.info3.group_rid,
+ 0);
+ sn++;
+
+ p = (char *)resp->extra_data.data;
+ if (!p) {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ for (j=0; j < resp->data.auth.info3.num_groups; j++) {
+ uint32_t rid;
+ uint32_t attrs;
+ int ret;
+ char *s = p;
+ char *e = strchr(p, '\n');
+ if (!e) {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ e[0] = '\0';
+ p = &e[1];
+
+ ret = sscanf(s, "0x%08X:0x%08X", &rid, &attrs);
+ if (ret != 2) {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ _SID_COMPOSE(i->sids[sn], domain_sid,
+ rid, attrs);
+ sn++;
+ }
+
+ for (j=0; j < resp->data.auth.info3.num_other_sids; j++) {
+ uint32_t attrs;
+ int ret;
+ char *s = p;
+ char *a;
+ char *e = strchr(p, '\n');
+ if (!e) {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ e[0] = '\0';
+ p = &e[1];
+
+ e = strchr(s, ':');
+ if (!e) {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ e[0] = '\0';
+ a = &e[1];
+
+ ret = sscanf(a, "0x%08X",
+ &attrs);
+ if (ret != 1) {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ wbc_status = wbcStringToSid(s, &i->sids[sn].sid);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ i->sids[sn].attributes = attrs;
+ sn++;
+ }
+
+ i->num_sids = sn;
+
+ *_i = i;
+ i = NULL;
+done:
+ talloc_free(i);
+ return wbc_status;
+}
+
+static wbcErr wbc_create_error_info(TALLOC_CTX *mem_ctx,
+ const struct winbindd_response *resp,
+ struct wbcAuthErrorInfo **_e)
+{
+ wbcErr wbc_status = WBC_ERR_SUCCESS;
+ struct wbcAuthErrorInfo *e;
+
+ e = talloc(mem_ctx, struct wbcAuthErrorInfo);
+ BAIL_ON_PTR_ERROR(e, wbc_status);
+
+ e->nt_status = resp->data.auth.nt_status;
+ e->pam_error = resp->data.auth.pam_error;
+ e->nt_string = talloc_strdup(e, resp->data.auth.nt_status_string);
+ BAIL_ON_PTR_ERROR(e->nt_string, wbc_status);
+
+ e->display_string = talloc_strdup(e, resp->data.auth.error_string);
+ BAIL_ON_PTR_ERROR(e->display_string, wbc_status);
+
+ *_e = e;
+ e = NULL;
+
+done:
+ talloc_free(e);
+ return wbc_status;
+}
+
+static wbcErr wbc_create_password_policy_info(TALLOC_CTX *mem_ctx,
+ const struct winbindd_response *resp,
+ struct wbcUserPasswordPolicyInfo **_i)
+{
+ wbcErr wbc_status = WBC_ERR_SUCCESS;
+ struct wbcUserPasswordPolicyInfo *i;
+
+ i = talloc(mem_ctx, struct wbcUserPasswordPolicyInfo);
+ BAIL_ON_PTR_ERROR(i, wbc_status);
+
+ i->min_passwordage = resp->data.auth.policy.min_passwordage;
+ i->min_length_password = resp->data.auth.policy.min_length_password;
+ i->password_history = resp->data.auth.policy.password_history;
+ i->password_properties = resp->data.auth.policy.password_properties;
+ i->expire = resp->data.auth.policy.expire;
+
+ *_i = i;
+ i = NULL;
+
+done:
+ talloc_free(i);
+ return wbc_status;
+}
+
+/** @brief Authenticate with more detailed information
+ *
+ * @param params Input parameters, WBC_AUTH_USER_LEVEL_HASH
+ * is not supported yet
+ * @param info Output details on WBC_ERR_SUCCESS
+ * @param error Output details on WBC_ERR_AUTH_ERROR
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
+ struct wbcAuthUserInfo **info,
+ struct wbcAuthErrorInfo **error)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ int cmd = 0;
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if (error) {
+ *error = NULL;
+ }
+
+ if (!params) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ if (!params->account_name) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* Initialize request */
+
+ switch (params->level) {
+ case WBC_AUTH_USER_LEVEL_PLAIN:
+ cmd = WINBINDD_PAM_AUTH;
+ request.flags = WBFLAG_PAM_INFO3_TEXT |
+ WBFLAG_PAM_USER_SESSION_KEY |
+ WBFLAG_PAM_LMKEY;
+
+ if (!params->password.plaintext) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ if (params->domain_name && params->domain_name[0]) {
+ /* We need to get the winbind separator :-( */
+ struct winbindd_response sep_response;
+
+ ZERO_STRUCT(sep_response);
+
+ wbc_status = wbcRequestResponse(WINBINDD_INFO,
+ NULL, &sep_response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ snprintf(request.data.auth.user,
+ sizeof(request.data.auth.user)-1,
+ "%s%c%s",
+ params->domain_name,
+ sep_response.data.info.winbind_separator,
+ params->account_name);
+ } else {
+ strncpy(request.data.auth.user,
+ params->account_name,
+ sizeof(request.data.auth.user)-1);
+ }
+ strncpy(request.data.auth.pass,
+ params->password.plaintext,
+ sizeof(request.data.auth.pass)-1);
+ break;
+
+ case WBC_AUTH_USER_LEVEL_HASH:
+ wbc_status = WBC_ERR_NOT_IMPLEMENTED;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ break;
+
+ case WBC_AUTH_USER_LEVEL_RESPONSE:
+ cmd = WINBINDD_PAM_AUTH_CRAP;
+ request.flags = WBFLAG_PAM_INFO3_TEXT |
+ WBFLAG_PAM_USER_SESSION_KEY |
+ WBFLAG_PAM_LMKEY;
+
+ if (params->password.response.lm_length &&
+ !params->password.response.lm_data) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ if (params->password.response.lm_length == 0 &&
+ params->password.response.lm_data) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ if (params->password.response.nt_length &&
+ !params->password.response.nt_data) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ if (params->password.response.nt_length == 0&&
+ params->password.response.nt_data) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ strncpy(request.data.auth_crap.user,
+ params->account_name,
+ sizeof(request.data.auth_crap.user)-1);
+ if (params->domain_name) {
+ strncpy(request.data.auth_crap.domain,
+ params->domain_name,
+ sizeof(request.data.auth_crap.domain)-1);
+ }
+ if (params->workstation_name) {
+ strncpy(request.data.auth_crap.workstation,
+ params->workstation_name,
+ sizeof(request.data.auth_crap.workstation)-1);
+ }
+
+ request.data.auth_crap.logon_parameters =
+ params->parameter_control;
+
+ memcpy(request.data.auth_crap.chal,
+ params->password.response.challenge,
+ sizeof(request.data.auth_crap.chal));
+
+ request.data.auth_crap.lm_resp_len =
+ MIN(params->password.response.lm_length,
+ sizeof(request.data.auth_crap.lm_resp));
+ request.data.auth_crap.nt_resp_len =
+ MIN(params->password.response.nt_length,
+ sizeof(request.data.auth_crap.nt_resp));
+ if (params->password.response.lm_data) {
+ memcpy(request.data.auth_crap.lm_resp,
+ params->password.response.lm_data,
+ request.data.auth_crap.lm_resp_len);
+ }
+ if (params->password.response.nt_data) {
+ memcpy(request.data.auth_crap.nt_resp,
+ params->password.response.nt_data,
+ request.data.auth_crap.nt_resp_len);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (cmd == 0) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ wbc_status = wbcRequestResponse(cmd,
+ &request,
+ &response);
+ if (response.data.auth.nt_status != 0) {
+ if (error) {
+ wbc_status = wbc_create_error_info(NULL,
+ &response,
+ error);
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ wbc_status = WBC_ERR_AUTH_ERROR;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ if (info) {
+ wbc_status = wbc_create_auth_info(NULL,
+ &response,
+ info);
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+done:
+ if (response.extra_data.data)
+ free(response.extra_data.data);
+
+ return wbc_status;
+}
+
+/** @brief Trigger a verification of the trust credentials of a specific domain
+ *
+ * @param *domain The name of the domain, only NULL for the default domain is
+ * supported yet. Other values than NULL will result in
+ * WBC_ERR_NOT_IMPLEMENTED.
+ * @param error Output details on WBC_ERR_AUTH_ERROR
+ *
+ * @return #wbcErr
+ *
+ **/
+wbcErr wbcCheckTrustCredentials(const char *domain,
+ struct wbcAuthErrorInfo **error)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ if (domain) {
+ /*
+ * the current protocol doesn't support
+ * specifying a domain
+ */
+ wbc_status = WBC_ERR_NOT_IMPLEMENTED;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Send request */
+
+ wbc_status = wbcRequestResponse(WINBINDD_CHECK_MACHACC,
+ &request,
+ &response);
+ if (response.data.auth.nt_status != 0) {
+ if (error) {
+ wbc_status = wbc_create_error_info(NULL,
+ &response,
+ error);
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ wbc_status = WBC_ERR_AUTH_ERROR;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Trigger a logoff notification to Winbind for a specific user
+ *
+ * @param username Name of user to remove from Winbind's list of
+ * logged on users.
+ * @param uid Uid assigned to the username
+ * @param ccfilename Absolute path to the Krb5 credentials cache to
+ * be removed
+ *
+ * @return #wbcErr
+ *
+ **/
+
+wbcErr wbcLogoffUser(const char *username,
+ uid_t uid,
+ const char *ccfilename)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ /* validate input */
+
+ if (!username) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ strncpy(request.data.logoff.user, username,
+ sizeof(request.data.logoff.user)-1);
+ request.data.logoff.uid = uid;
+
+ if (ccfilename) {
+ strncpy(request.data.logoff.krb5ccname, ccfilename,
+ sizeof(request.data.logoff.krb5ccname)-1);
+ }
+
+ /* Send request */
+
+ wbc_status = wbcRequestResponse(WINBINDD_PAM_LOGOFF,
+ &request,
+ &response);
+
+ /* Take the response above and return it to the caller */
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Change a password for a user with more detailed information upon
+ * failure
+ * @param params Input parameters
+ * @param error User output details on WBC_ERR_PWD_CHANGE_FAILED
+ * @param reject_reason New password reject reason on WBC_ERR_PWD_CHANGE_FAILED
+ * @param policy Password policy output details on WBC_ERR_PWD_CHANGE_FAILED
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params,
+ struct wbcAuthErrorInfo **error,
+ enum wbcPasswordChangeRejectReason *reject_reason,
+ struct wbcUserPasswordPolicyInfo **policy)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ int cmd = 0;
+
+ /* validate input */
+
+ if (!params->account_name) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ if (error) {
+ *error = NULL;
+ }
+
+ if (policy) {
+ *policy = NULL;
+ }
+
+ if (reject_reason) {
+ *reject_reason = -1;
+ }
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ switch (params->level) {
+ case WBC_CHANGE_PASSWORD_LEVEL_PLAIN:
+ cmd = WINBINDD_PAM_CHAUTHTOK;
+
+ if (!params->account_name) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ strncpy(request.data.chauthtok.user, params->account_name,
+ sizeof(request.data.chauthtok.user) - 1);
+
+ if (params->old_password.plaintext) {
+ strncpy(request.data.chauthtok.oldpass,
+ params->old_password.plaintext,
+ sizeof(request.data.chauthtok.oldpass) - 1);
+ }
+
+ if (params->new_password.plaintext) {
+ strncpy(request.data.chauthtok.newpass,
+ params->new_password.plaintext,
+ sizeof(request.data.chauthtok.newpass) - 1);
+ }
+ break;
+
+ case WBC_CHANGE_PASSWORD_LEVEL_RESPONSE:
+ cmd = WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP;
+
+ if (!params->account_name || !params->domain_name) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ if (params->old_password.response.old_lm_hash_enc_length &&
+ !params->old_password.response.old_lm_hash_enc_data) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ if (params->old_password.response.old_lm_hash_enc_length == 0 &&
+ params->old_password.response.old_lm_hash_enc_data) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ if (params->old_password.response.old_nt_hash_enc_length &&
+ !params->old_password.response.old_nt_hash_enc_data) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ if (params->old_password.response.old_nt_hash_enc_length == 0 &&
+ params->old_password.response.old_nt_hash_enc_data) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ if (params->new_password.response.lm_length &&
+ !params->new_password.response.lm_data) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ if (params->new_password.response.lm_length == 0 &&
+ params->new_password.response.lm_data) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ if (params->new_password.response.nt_length &&
+ !params->new_password.response.nt_data) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ if (params->new_password.response.nt_length == 0 &&
+ params->new_password.response.nt_data) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ strncpy(request.data.chng_pswd_auth_crap.user,
+ params->account_name,
+ sizeof(request.data.chng_pswd_auth_crap.user) - 1);
+
+ strncpy(request.data.chng_pswd_auth_crap.domain,
+ params->domain_name,
+ sizeof(request.data.chng_pswd_auth_crap.domain) - 1);
+
+ if (params->new_password.response.nt_data) {
+ memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd,
+ params->new_password.response.nt_data,
+ request.data.chng_pswd_auth_crap.new_nt_pswd_len);
+ request.data.chng_pswd_auth_crap.new_nt_pswd_len =
+ params->new_password.response.nt_length;
+ }
+
+ if (params->new_password.response.lm_data) {
+ memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd,
+ params->new_password.response.lm_data,
+ request.data.chng_pswd_auth_crap.new_lm_pswd_len);
+ request.data.chng_pswd_auth_crap.new_lm_pswd_len =
+ params->new_password.response.lm_length;
+ }
+
+ if (params->old_password.response.old_nt_hash_enc_data) {
+ memcpy(request.data.chng_pswd_auth_crap.old_nt_hash_enc,
+ params->old_password.response.old_nt_hash_enc_data,
+ request.data.chng_pswd_auth_crap.old_nt_hash_enc_len);
+ request.data.chng_pswd_auth_crap.old_nt_hash_enc_len =
+ params->old_password.response.old_nt_hash_enc_length;
+ }
+
+ if (params->old_password.response.old_lm_hash_enc_data) {
+ memcpy(request.data.chng_pswd_auth_crap.old_lm_hash_enc,
+ params->old_password.response.old_lm_hash_enc_data,
+ request.data.chng_pswd_auth_crap.old_lm_hash_enc_len);
+ request.data.chng_pswd_auth_crap.old_lm_hash_enc_len =
+ params->old_password.response.old_lm_hash_enc_length;
+ }
+
+ break;
+ default:
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ break;
+ }
+
+ if (cmd == 0) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* Send request */
+
+ wbc_status = wbcRequestResponse(cmd,
+ &request,
+ &response);
+ if (WBC_ERROR_IS_OK(wbc_status)) {
+ goto done;
+ }
+
+ /* Take the response above and return it to the caller */
+
+ if (response.data.auth.nt_status != 0) {
+ if (error) {
+ wbc_status = wbc_create_error_info(NULL,
+ &response,
+ error);
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ }
+
+ if (policy) {
+ wbc_status = wbc_create_password_policy_info(NULL,
+ &response,
+ policy);
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ if (reject_reason) {
+ *reject_reason = response.data.auth.reject_reason;
+ }
+
+ wbc_status = WBC_ERR_PWD_CHANGE_FAILED;
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Change a password for a user
+ *
+ * @param username Name of user to authenticate
+ * @param old_password Old clear text password of user
+ * @param new_password New clear text password of user
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcChangeUserPassword(const char *username,
+ const char *old_password,
+ const char *new_password)
+{
+ wbcErr wbc_status = WBC_ERR_SUCCESS;
+ struct wbcChangePasswordParams params;
+
+ ZERO_STRUCT(params);
+
+ params.account_name = username;
+ params.level = WBC_CHANGE_PASSWORD_LEVEL_PLAIN;
+ params.old_password.plaintext = old_password;
+ params.new_password.plaintext = new_password;
+
+ wbc_status = wbcChangeUserPasswordEx(&params,
+ NULL,
+ NULL,
+ NULL);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+done:
+ return wbc_status;
+}
diff --git a/source3/nsswitch/libwbclient/wbc_pwd.c b/source3/nsswitch/libwbclient/wbc_pwd.c
new file mode 100644
index 0000000000..b5f167369c
--- /dev/null
+++ b/source3/nsswitch/libwbclient/wbc_pwd.c
@@ -0,0 +1,438 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind client API
+
+ Copyright (C) Gerald (Jerry) Carter 2007
+
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Required Headers */
+
+#include "libwbclient.h"
+
+/**
+ *
+ **/
+
+static struct passwd *copy_passwd_entry(struct winbindd_pw *p)
+{
+ struct passwd *pwd = NULL;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ pwd = talloc(NULL, struct passwd);
+ BAIL_ON_PTR_ERROR(pwd, wbc_status);
+
+ pwd->pw_name = talloc_strdup(pwd,p->pw_name);
+ BAIL_ON_PTR_ERROR(pwd->pw_name, wbc_status);
+
+ pwd->pw_passwd = talloc_strdup(pwd, p->pw_passwd);
+ BAIL_ON_PTR_ERROR(pwd->pw_passwd, wbc_status);
+
+ pwd->pw_gecos = talloc_strdup(pwd, p->pw_gecos);
+ BAIL_ON_PTR_ERROR(pwd->pw_gecos, wbc_status);
+
+ pwd->pw_shell = talloc_strdup(pwd, p->pw_shell);
+ BAIL_ON_PTR_ERROR(pwd->pw_shell, wbc_status);
+
+ pwd->pw_dir = talloc_strdup(pwd, p->pw_dir);
+ BAIL_ON_PTR_ERROR(pwd->pw_dir, wbc_status);
+
+ pwd->pw_uid = p->pw_uid;
+ pwd->pw_gid = p->pw_gid;
+
+done:
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ talloc_free(pwd);
+ pwd = NULL;
+ }
+
+ return pwd;
+}
+
+/**
+ *
+ **/
+
+static struct group *copy_group_entry(struct winbindd_gr *g,
+ char *mem_buf)
+{
+ struct group *grp = NULL;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ int i;
+ char *mem_p, *mem_q;
+
+ grp = talloc(NULL, struct group);
+ BAIL_ON_PTR_ERROR(grp, wbc_status);
+
+ grp->gr_name = talloc_strdup(grp, g->gr_name);
+ BAIL_ON_PTR_ERROR(grp->gr_name, wbc_status);
+
+ grp->gr_passwd = talloc_strdup(grp, g->gr_passwd);
+ BAIL_ON_PTR_ERROR(grp->gr_passwd, wbc_status);
+
+ grp->gr_gid = g->gr_gid;
+
+ grp->gr_mem = talloc_array(grp, char*, g->num_gr_mem+1);
+
+ mem_p = mem_q = mem_buf;
+ for (i=0; i<g->num_gr_mem && mem_p; i++) {
+ if ((mem_q = strchr(mem_p, ',')) != NULL) {
+ *mem_q = '\0';
+ }
+
+ grp->gr_mem[i] = talloc_strdup(grp, mem_p);
+ BAIL_ON_PTR_ERROR(grp->gr_mem[i], wbc_status);
+
+ if (mem_q == NULL) {
+ i += 1;
+ break;
+ }
+ mem_p = mem_q + 1;
+ }
+ grp->gr_mem[i] = NULL;
+
+ wbc_status = WBC_ERR_SUCCESS;
+
+done:
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ talloc_free(grp);
+ grp = NULL;
+ }
+
+ return grp;
+}
+
+/** @brief Fill in a struct passwd* for a domain user based
+ * on username
+ *
+ * @param *name Username to lookup
+ * @param **pwd Pointer to resulting struct passwd* from the query.
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcGetpwnam(const char *name, struct passwd **pwd)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ if (!name || !pwd) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* Initialize request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* dst is already null terminated from the memset above */
+
+ strncpy(request.data.username, name, sizeof(request.data.username)-1);
+
+ wbc_status = wbcRequestResponse(WINBINDD_GETPWNAM,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ *pwd = copy_passwd_entry(&response.data.pw);
+ BAIL_ON_PTR_ERROR(*pwd, wbc_status);
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Fill in a struct passwd* for a domain user based
+ * on uid
+ *
+ * @param uid Uid to lookup
+ * @param **pwd Pointer to resulting struct passwd* from the query.
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcGetpwuid(uid_t uid, struct passwd **pwd)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ if (!pwd) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* Initialize request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.uid = uid;
+
+ wbc_status = wbcRequestResponse(WINBINDD_GETPWUID,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ *pwd = copy_passwd_entry(&response.data.pw);
+ BAIL_ON_PTR_ERROR(*pwd, wbc_status);
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Fill in a struct passwd* for a domain user based
+ * on username
+ *
+ * @param *name Username to lookup
+ * @param **grp Pointer to resulting struct group* from the query.
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcGetgrnam(const char *name, struct group **grp)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ /* Initialize request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if (!name || !grp) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* dst is already null terminated from the memset above */
+
+ strncpy(request.data.groupname, name, sizeof(request.data.groupname)-1);
+
+ wbc_status = wbcRequestResponse(WINBINDD_GETGRNAM,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ *grp = copy_group_entry(&response.data.gr,
+ (char*)response.extra_data.data);
+ BAIL_ON_PTR_ERROR(*grp, wbc_status);
+
+ done:
+ if (response.extra_data.data)
+ free(response.extra_data.data);
+
+ return wbc_status;
+}
+
+/** @brief Fill in a struct passwd* for a domain user based
+ * on uid
+ *
+ * @param gid Uid to lookup
+ * @param **grp Pointer to resulting struct group* from the query.
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcGetgrgid(gid_t gid, struct group **grp)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ /* Initialize request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if (!grp) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ request.data.gid = gid;
+
+ wbc_status = wbcRequestResponse(WINBINDD_GETGRGID,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ *grp = copy_group_entry(&response.data.gr,
+ (char*)response.extra_data.data);
+ BAIL_ON_PTR_ERROR(*grp, wbc_status);
+
+ done:
+ if (response.extra_data.data)
+ free(response.extra_data.data);
+
+ return wbc_status;
+}
+
+/** @brief Reset the passwd iterator
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcSetpwent(void)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ wbc_status = wbcRequestResponse(WINBINDD_SETPWENT,
+ NULL, NULL);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Close the passwd iterator
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcEndpwent(void)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ wbc_status = wbcRequestResponse(WINBINDD_ENDPWENT,
+ NULL, NULL);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Return the next struct passwd* entry from the pwent iterator
+ *
+ * @param **pwd Pointer to resulting struct group* from the query.
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcGetpwent(struct passwd **pwd)
+{
+ return WBC_ERR_NOT_IMPLEMENTED;
+}
+
+/** @brief Reset the group iterator
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcSetgrent(void)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ wbc_status = wbcRequestResponse(WINBINDD_SETGRENT,
+ NULL, NULL);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Close the group iterator
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcEndgrent(void)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ wbc_status = wbcRequestResponse(WINBINDD_ENDGRENT,
+ NULL, NULL);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Return the next struct passwd* entry from the pwent iterator
+ *
+ * @param **grp Pointer to resulting struct group* from the query.
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcGetgrent(struct group **grp)
+{
+ return WBC_ERR_NOT_IMPLEMENTED;
+}
+
+/** @brief Return the unix group array belonging to the given user
+ *
+ * @param *account The given user name
+ * @param *num_groups Number of elements returned in the groups array
+ * @param **groups Pointer to resulting gid_t array.
+ *
+ * @return #wbcErr
+ **/
+wbcErr wbcGetGroups(const char *account,
+ uint32_t *num_groups,
+ gid_t **_groups)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ uint32_t i;
+ gid_t *groups = NULL;
+
+ /* Initialize request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if (!account) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* Send request */
+
+ strncpy(request.data.username, account, sizeof(request.data.username)-1);
+
+ wbc_status = wbcRequestResponse(WINBINDD_GETGROUPS,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ groups = talloc_array(NULL, gid_t, response.data.num_entries);
+ BAIL_ON_PTR_ERROR(groups, wbc_status);
+
+ for (i = 0; i < response.data.num_entries; i++) {
+ groups[i] = ((gid_t *)response.extra_data.data)[i];
+ }
+
+ *num_groups = response.data.num_entries;
+ *_groups = groups;
+ groups = NULL;
+
+ wbc_status = WBC_ERR_SUCCESS;
+
+ done:
+ if (response.extra_data.data) {
+ free(response.extra_data.data);
+ }
+ if (groups) {
+ talloc_free(groups);
+ }
+
+ return wbc_status;
+}
diff --git a/source3/nsswitch/libwbclient/wbc_sid.c b/source3/nsswitch/libwbclient/wbc_sid.c
new file mode 100644
index 0000000000..f4ffa4e5ca
--- /dev/null
+++ b/source3/nsswitch/libwbclient/wbc_sid.c
@@ -0,0 +1,677 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind client API
+
+ Copyright (C) Gerald (Jerry) Carter 2007
+
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Required Headers */
+
+#include "libwbclient.h"
+
+
+/** @brief Convert a binary SID to a character string
+ *
+ * @param sid Binary Security Identifier
+ * @param **sid_string Resulting character string
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcSidToString(const struct wbcDomainSid *sid,
+ char **sid_string)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ uint32_t id_auth;
+ int i;
+ char *tmp = NULL;
+ TALLOC_CTX *ctx = NULL;
+
+ if (!sid) {
+ wbc_status = WBC_ERR_INVALID_SID;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ ctx = talloc_init("wbcSidToString");
+ BAIL_ON_PTR_ERROR(ctx, wbc_status);
+
+ id_auth = sid->id_auth[5] +
+ (sid->id_auth[4] << 8) +
+ (sid->id_auth[3] << 16) +
+ (sid->id_auth[2] << 24);
+
+ tmp = talloc_asprintf(ctx, "S-%d-%d", sid->sid_rev_num, id_auth);
+ BAIL_ON_PTR_ERROR(tmp, wbc_status);
+
+ for (i=0; i<sid->num_auths; i++) {
+ char *tmp2;
+ tmp2 = talloc_asprintf_append(tmp, "-%u", sid->sub_auths[i]);
+ BAIL_ON_PTR_ERROR(tmp2, wbc_status);
+
+ tmp = tmp2;
+ }
+
+ *sid_string=talloc_strdup(NULL, tmp);
+ BAIL_ON_PTR_ERROR((*sid_string), wbc_status);
+
+ wbc_status = WBC_ERR_SUCCESS;
+
+done:
+ talloc_free(ctx);
+
+ return wbc_status;
+}
+
+/** @brief Convert a character string to a binary SID
+ *
+ * @param *str Character string in the form of S-...
+ * @param sid Resulting binary SID
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcStringToSid(const char *str,
+ struct wbcDomainSid *sid)
+{
+ const char *p;
+ char *q;
+ uint32_t x;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ if (!sid) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* Sanity check for either "S-" or "s-" */
+
+ if (!str
+ || (str[0]!='S' && str[0]!='s')
+ || (str[1]!='-'))
+ {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* Get the SID revision number */
+
+ p = str+2;
+ x = (uint32_t)strtol(p, &q, 10);
+ if (x==0 || !q || *q!='-') {
+ wbc_status = WBC_ERR_INVALID_SID;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ sid->sid_rev_num = (uint8_t)x;
+
+ /* Next the Identifier Authority. This is stored in big-endian
+ in a 6 byte array. */
+
+ p = q+1;
+ x = (uint32_t)strtol(p, &q, 10);
+ if (!q || *q!='-') {
+ wbc_status = WBC_ERR_INVALID_SID;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ sid->id_auth[5] = (x & 0x000000ff);
+ sid->id_auth[4] = (x & 0x0000ff00) >> 8;
+ sid->id_auth[3] = (x & 0x00ff0000) >> 16;
+ sid->id_auth[2] = (x & 0xff000000) >> 24;
+ sid->id_auth[1] = 0;
+ sid->id_auth[0] = 0;
+
+ /* now read the the subauthorities */
+
+ p = q +1;
+ sid->num_auths = 0;
+ while (sid->num_auths < WBC_MAXSUBAUTHS) {
+ x=(uint32_t)strtoul(p, &q, 10);
+ if (p == q)
+ break;
+ if (q == NULL) {
+ wbc_status = WBC_ERR_INVALID_SID;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ sid->sub_auths[sid->num_auths++] = x;
+
+ if ((*q!='-') || (*q=='\0'))
+ break;
+ p = q + 1;
+ }
+
+ /* IF we ended early, then the SID could not be converted */
+
+ if (q && *q!='\0') {
+ wbc_status = WBC_ERR_INVALID_SID;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ wbc_status = WBC_ERR_SUCCESS;
+
+done:
+ return wbc_status;
+
+}
+
+/** @brief Convert a domain and name to SID
+ *
+ * @param domain Domain name (possibly "")
+ * @param name User or group name
+ * @param *sid Pointer to the resolved domain SID
+ * @param *name_type Pointet to the SID type
+ *
+ * @return #wbcErr
+ *
+ **/
+
+wbcErr wbcLookupName(const char *domain,
+ const char *name,
+ struct wbcDomainSid *sid,
+ enum wbcSidType *name_type)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ if (!sid || !name_type) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* Initialize request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* dst is already null terminated from the memset above */
+
+ strncpy(request.data.name.dom_name, domain,
+ sizeof(request.data.name.dom_name)-1);
+ strncpy(request.data.name.name, name,
+ sizeof(request.data.name.name)-1);
+
+ wbc_status = wbcRequestResponse(WINBINDD_LOOKUPNAME,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ wbc_status = wbcStringToSid(response.data.sid.sid, sid);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ *name_type = (enum wbcSidType)response.data.sid.type;
+
+ wbc_status = WBC_ERR_SUCCESS;
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Convert a SID to a domain and name
+ *
+ * @param *sid Pointer to the domain SID to be resolved
+ * @param domain Resolved Domain name (possibly "")
+ * @param name Resolved User or group name
+ * @param *name_type Pointet to the resolved SID type
+ *
+ * @return #wbcErr
+ *
+ **/
+
+wbcErr wbcLookupSid(const struct wbcDomainSid *sid,
+ char **pdomain,
+ char **pname,
+ enum wbcSidType *pname_type)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ char *sid_string = NULL;
+ char *domain = NULL;
+ char *name = NULL;
+ enum wbcSidType name_type = WBC_SID_NAME_USE_NONE;
+
+ if (!sid) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* Initialize request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* dst is already null terminated from the memset above */
+
+ wbc_status = wbcSidToString(sid, &sid_string);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
+ wbcFreeMemory(sid_string);
+
+ /* Make request */
+
+ wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSID,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ /* Copy out result */
+
+ domain = talloc_strdup(NULL, response.data.name.dom_name);
+ BAIL_ON_PTR_ERROR(domain, wbc_status);
+
+ name = talloc_strdup(NULL, response.data.name.name);
+ BAIL_ON_PTR_ERROR(name, wbc_status);
+
+ name_type = (enum wbcSidType)response.data.name.type;
+
+ wbc_status = WBC_ERR_SUCCESS;
+
+ done:
+ if (WBC_ERROR_IS_OK(wbc_status)) {
+ if (pdomain != NULL) {
+ *pdomain = domain;
+ }
+ if (pname != NULL) {
+ *pname = name;
+ }
+ if (pname_type != NULL) {
+ *pname_type = name_type;
+ }
+ }
+ else {
+#if 0
+ /*
+ * Found by Coverity: In this particular routine we can't end
+ * up here with a non-NULL name. Further up there are just two
+ * exit paths that lead here, neither of which leave an
+ * allocated name. If you add more paths up there, re-activate
+ * this.
+ */
+ if (name != NULL) {
+ talloc_free(name);
+ }
+#endif
+ if (domain != NULL) {
+ talloc_free(domain);
+ }
+ }
+
+ return wbc_status;
+}
+
+/** @brief Translate a collection of RIDs within a domain to names
+ *
+ **/
+
+wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
+ int num_rids,
+ uint32_t *rids,
+ const char **pp_domain_name,
+ const char ***pnames,
+ enum wbcSidType **ptypes)
+{
+ size_t i, len, ridbuf_size;
+ char *ridlist;
+ char *p;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ char *sid_string = NULL;
+ char *domain_name = NULL;
+ const char **names = NULL;
+ enum wbcSidType *types = NULL;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if (!dom_sid || (num_rids == 0)) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ wbc_status = wbcSidToString(dom_sid, &sid_string);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
+ wbcFreeMemory(sid_string);
+
+ /* Even if all the Rids were of maximum 32bit values,
+ we would only have 11 bytes per rid in the final array
+ ("4294967296" + \n). Add one more byte for the
+ terminating '\0' */
+
+ ridbuf_size = (sizeof(char)*11) * num_rids + 1;
+
+ ridlist = talloc_zero_array(NULL, char, ridbuf_size);
+ BAIL_ON_PTR_ERROR(ridlist, wbc_status);
+
+ len = 0;
+ for (i=0; i<num_rids && (len-1)>0; i++) {
+ char ridstr[12];
+
+ len = strlen(ridlist);
+ p = ridlist + len;
+
+ snprintf( ridstr, sizeof(ridstr)-1, "%u\n", rids[i]);
+ strncat(p, ridstr, ridbuf_size-len-1);
+ }
+
+ request.extra_data.data = ridlist;
+ request.extra_len = strlen(ridlist)+1;
+
+ wbc_status = wbcRequestResponse(WINBINDD_LOOKUPRIDS,
+ &request,
+ &response);
+ talloc_free(ridlist);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ domain_name = talloc_strdup(NULL, response.data.domain_name);
+ BAIL_ON_PTR_ERROR(domain_name, wbc_status);
+
+ names = talloc_array(NULL, const char*, num_rids);
+ BAIL_ON_PTR_ERROR(names, wbc_status);
+
+ types = talloc_array(NULL, enum wbcSidType, num_rids);
+ BAIL_ON_PTR_ERROR(types, wbc_status);
+
+ p = (char *)response.extra_data.data;
+
+ for (i=0; i<num_rids; i++) {
+ char *q;
+
+ if (*p == '\0') {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ types[i] = (enum wbcSidType)strtoul(p, &q, 10);
+
+ if (*q != ' ') {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ p = q+1;
+
+ if ((q = strchr(p, '\n')) == NULL) {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ *q = '\0';
+
+ names[i] = talloc_strdup(names, p);
+ BAIL_ON_PTR_ERROR(names[i], wbc_status);
+
+ p = q+1;
+ }
+
+ if (*p != '\0') {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ wbc_status = WBC_ERR_SUCCESS;
+
+ done:
+ if (response.extra_data.data) {
+ free(response.extra_data.data);
+ }
+
+ if (WBC_ERROR_IS_OK(wbc_status)) {
+ *pp_domain_name = domain_name;
+ *pnames = names;
+ *ptypes = types;
+ }
+ else {
+ if (domain_name)
+ talloc_free(domain_name);
+ if (names)
+ talloc_free(names);
+ if (types)
+ talloc_free(types);
+ }
+
+ return wbc_status;
+}
+
+/** @brief Get the groups a user belongs to
+ *
+ **/
+
+wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
+ bool domain_groups_only,
+ uint32_t *num_sids,
+ struct wbcDomainSid **_sids)
+{
+ uint32_t i;
+ const char *s;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ char *sid_string = NULL;
+ struct wbcDomainSid *sids = NULL;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ int cmd;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if (!user_sid) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ wbc_status = wbcSidToString(user_sid, &sid_string);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
+ wbcFreeMemory(sid_string);
+
+ if (domain_groups_only) {
+ cmd = WINBINDD_GETUSERDOMGROUPS;
+ } else {
+ cmd = WINBINDD_GETUSERSIDS;
+ }
+
+ wbc_status = wbcRequestResponse(cmd,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ if (response.data.num_entries &&
+ !response.extra_data.data) {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ sids = talloc_array(NULL, struct wbcDomainSid,
+ response.data.num_entries);
+ BAIL_ON_PTR_ERROR(sids, wbc_status);
+
+ s = (const char *)response.extra_data.data;
+ for (i = 0; i < response.data.num_entries; i++) {
+ char *n = strchr(s, '\n');
+ if (n) {
+ *n = '\0';
+ }
+ wbc_status = wbcStringToSid(s, &sids[i]);
+ BAIL_ON_WBC_ERROR(wbc_status);
+ s += strlen(s) + 1;
+ }
+
+ *num_sids = response.data.num_entries;
+ *_sids = sids;
+ sids = NULL;
+ wbc_status = WBC_ERR_SUCCESS;
+
+ done:
+ if (response.extra_data.data) {
+ free(response.extra_data.data);
+ }
+ if (sids) {
+ talloc_free(sids);
+ }
+
+ return wbc_status;
+}
+
+/** @brief Lists Users
+ *
+ **/
+
+wbcErr wbcListUsers(const char *domain_name,
+ uint32_t *_num_users,
+ const char ***_users)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ uint32_t num_users = 0;
+ const char **users = NULL;
+ const char *next;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if (domain_name) {
+ strncpy(request.domain_name, domain_name,
+ sizeof(request.domain_name)-1);
+ }
+
+ wbc_status = wbcRequestResponse(WINBINDD_LIST_USERS,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ /* Look through extra data */
+
+ next = (const char *)response.extra_data.data;
+ while (next) {
+ const char **tmp;
+ const char *current = next;
+ char *k = strchr(next, ',');
+ if (k) {
+ k[0] = '\0';
+ next = k+1;
+ } else {
+ next = NULL;
+ }
+
+ tmp = talloc_realloc(NULL, users,
+ const char *,
+ num_users+1);
+ BAIL_ON_PTR_ERROR(tmp, wbc_status);
+ users = tmp;
+
+ users[num_users] = talloc_strdup(users, current);
+ BAIL_ON_PTR_ERROR(users[num_users], wbc_status);
+
+ num_users++;
+ }
+
+ *_num_users = num_users;
+ *_users = users;
+ users = NULL;
+ wbc_status = WBC_ERR_SUCCESS;
+
+ done:
+ if (response.extra_data.data) {
+ free(response.extra_data.data);
+ }
+ if (users) {
+ talloc_free(users);
+ }
+ return wbc_status;
+}
+
+/** @brief Lists Groups
+ *
+ **/
+
+wbcErr wbcListGroups(const char *domain_name,
+ uint32_t *_num_groups,
+ const char ***_groups)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ uint32_t num_groups = 0;
+ const char **groups = NULL;
+ const char *next;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if (domain_name) {
+ strncpy(request.domain_name, domain_name,
+ sizeof(request.domain_name)-1);
+ }
+
+ wbc_status = wbcRequestResponse(WINBINDD_LIST_GROUPS,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ /* Look through extra data */
+
+ next = (const char *)response.extra_data.data;
+ while (next) {
+ const char **tmp;
+ const char *current = next;
+ char *k = strchr(next, ',');
+ if (k) {
+ k[0] = '\0';
+ next = k+1;
+ } else {
+ next = NULL;
+ }
+
+ tmp = talloc_realloc(NULL, groups,
+ const char *,
+ num_groups+1);
+ BAIL_ON_PTR_ERROR(tmp, wbc_status);
+ groups = tmp;
+
+ groups[num_groups] = talloc_strdup(groups, current);
+ BAIL_ON_PTR_ERROR(groups[num_groups], wbc_status);
+
+ num_groups++;
+ }
+
+ *_num_groups = num_groups;
+ *_groups = groups;
+ groups = NULL;
+ wbc_status = WBC_ERR_SUCCESS;
+
+ done:
+ if (response.extra_data.data) {
+ free(response.extra_data.data);
+ }
+ if (groups) {
+ talloc_free(groups);
+ }
+ return wbc_status;
+}
diff --git a/source3/nsswitch/libwbclient/wbc_util.c b/source3/nsswitch/libwbclient/wbc_util.c
new file mode 100644
index 0000000000..24568f9101
--- /dev/null
+++ b/source3/nsswitch/libwbclient/wbc_util.c
@@ -0,0 +1,552 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind client API
+
+ Copyright (C) Gerald (Jerry) Carter 2007-2008
+
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Required Headers */
+
+#include "libwbclient.h"
+
+
+
+/** @brief Ping winbindd to see if the daemon is running
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcPing(void)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ /* Initialize request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ return wbcRequestResponse(WINBINDD_PING, &request, &response);
+}
+
+wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct wbcInterfaceDetails *info;
+ struct wbcDomainInfo *domain = NULL;
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ /* Initialize request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ info = talloc(NULL, struct wbcInterfaceDetails);
+ BAIL_ON_PTR_ERROR(info, wbc_status);
+
+ /* first the interface version */
+ wbc_status = wbcRequestResponse(WINBINDD_INTERFACE_VERSION, NULL, &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+ info->interface_version = response.data.interface_version;
+
+ /* then the samba version and the winbind separator */
+ wbc_status = wbcRequestResponse(WINBINDD_INFO, NULL, &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ info->winbind_version = talloc_strdup(info,
+ response.data.info.samba_version);
+ BAIL_ON_PTR_ERROR(info->winbind_version, wbc_status);
+ info->winbind_separator = response.data.info.winbind_separator;
+
+ /* then the local netbios name */
+ wbc_status = wbcRequestResponse(WINBINDD_NETBIOS_NAME, NULL, &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ info->netbios_name = talloc_strdup(info,
+ response.data.netbios_name);
+ BAIL_ON_PTR_ERROR(info->netbios_name, wbc_status);
+
+ /* then the local workgroup name */
+ wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_NAME, NULL, &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ info->netbios_domain = talloc_strdup(info,
+ response.data.domain_name);
+ BAIL_ON_PTR_ERROR(info->netbios_domain, wbc_status);
+
+ wbc_status = wbcDomainInfo(info->netbios_domain, &domain);
+ if (wbc_status == WBC_ERR_DOMAIN_NOT_FOUND) {
+ /* maybe it's a standalone server */
+ domain = NULL;
+ wbc_status = WBC_ERR_SUCCESS;
+ } else {
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ if (domain) {
+ info->dns_domain = talloc_strdup(info,
+ domain->dns_name);
+ wbcFreeMemory(domain);
+ BAIL_ON_PTR_ERROR(info->dns_domain, wbc_status);
+ } else {
+ info->dns_domain = NULL;
+ }
+
+ *_details = info;
+ info = NULL;
+
+ wbc_status = WBC_ERR_SUCCESS;
+
+done:
+ talloc_free(info);
+ return wbc_status;
+}
+
+
+/** @brief Lookup the current status of a trusted domain
+ *
+ * @param domain Domain to query
+ * @param *dinfo Pointer to returned domain_info struct
+ *
+ * @return #wbcErr
+ *
+ **/
+
+
+wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct wbcDomainInfo *info = NULL;
+
+ if (!domain || !dinfo) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* Initialize request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ strncpy(request.domain_name, domain,
+ sizeof(request.domain_name)-1);
+
+ wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_INFO,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ info = talloc(NULL, struct wbcDomainInfo);
+ BAIL_ON_PTR_ERROR(info, wbc_status);
+
+ info->short_name = talloc_strdup(info,
+ response.data.domain_info.name);
+ BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
+
+ info->dns_name = talloc_strdup(info,
+ response.data.domain_info.alt_name);
+ BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
+
+ wbc_status = wbcStringToSid(response.data.domain_info.sid,
+ &info->sid);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ if (response.data.domain_info.native_mode)
+ info->domain_flags |= WBC_DOMINFO_DOMAIN_NATIVE;
+ if (response.data.domain_info.active_directory)
+ info->domain_flags |= WBC_DOMINFO_DOMAIN_AD;
+ if (response.data.domain_info.primary)
+ info->domain_flags |= WBC_DOMINFO_DOMAIN_PRIMARY;
+
+ *dinfo = info;
+
+ wbc_status = WBC_ERR_SUCCESS;
+
+ done:
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ talloc_free(info);
+ }
+
+ return wbc_status;
+}
+
+
+/** @brief Resolve a NetbiosName via WINS
+ *
+ * @param name Name to resolve
+ * @param *ip Pointer to the ip address string
+ *
+ * @return #wbcErr
+ *
+ **/
+wbcErr wbcResolveWinsByName(const char *name, char **ip)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ char *ipaddr;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Send request */
+
+ strncpy(request.data.winsreq, name,
+ sizeof(request.data.winsreq)-1);
+
+ wbc_status = wbcRequestResponse(WINBINDD_WINS_BYNAME,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ /* Display response */
+
+ ipaddr = talloc_strdup(NULL, response.data.winsresp);
+ BAIL_ON_PTR_ERROR(ipaddr, wbc_status);
+
+ *ip = ipaddr;
+ wbc_status = WBC_ERR_SUCCESS;
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Resolve an IP address via WINS into a NetbiosName
+ *
+ * @param ip The ip address string
+ * @param *name Pointer to the name
+ *
+ * @return #wbcErr
+ *
+ **/
+wbcErr wbcResolveWinsByIP(const char *ip, char **name)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ char *name_str;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Send request */
+
+ strncpy(request.data.winsreq, ip,
+ sizeof(request.data.winsreq)-1);
+
+ wbc_status = wbcRequestResponse(WINBINDD_WINS_BYIP,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ /* Display response */
+
+ name_str = talloc_strdup(NULL, response.data.winsresp);
+ BAIL_ON_PTR_ERROR(name_str, wbc_status);
+
+ *name = name_str;
+ wbc_status = WBC_ERR_SUCCESS;
+
+ done:
+ return wbc_status;
+}
+
+/**
+ */
+
+static wbcErr process_domain_info_string(TALLOC_CTX *ctx,
+ struct wbcDomainInfo *info,
+ char *info_string)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ char *r = NULL;
+ char *s = NULL;
+
+ if (!info || !info_string) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ r = info_string;
+
+ /* Short Name */
+ if ((s = strchr(r, '\\')) == NULL) {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ *s = '\0';
+ s++;
+
+ info->short_name = talloc_strdup(ctx, r);
+ BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
+
+
+ /* DNS Name */
+ r = s;
+ if ((s = strchr(r, '\\')) == NULL) {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ *s = '\0';
+ s++;
+
+ info->dns_name = talloc_strdup(ctx, r);
+ BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
+
+ /* SID */
+ r = s;
+ if ((s = strchr(r, '\\')) == NULL) {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ *s = '\0';
+ s++;
+
+ wbc_status = wbcStringToSid(r, &info->sid);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ /* Trust type */
+ r = s;
+ if ((s = strchr(r, '\\')) == NULL) {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ *s = '\0';
+ s++;
+
+ if (strcmp(r, "None") == 0) {
+ info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
+ } else if (strcmp(r, "External") == 0) {
+ info->trust_type = WBC_DOMINFO_TRUSTTYPE_EXTERNAL;
+ } else if (strcmp(r, "Forest") == 0) {
+ info->trust_type = WBC_DOMINFO_TRUSTTYPE_FOREST;
+ } else if (strcmp(r, "In Forest") == 0) {
+ info->trust_type = WBC_DOMINFO_TRUSTTYPE_IN_FOREST;
+ } else {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* Transitive */
+ r = s;
+ if ((s = strchr(r, '\\')) == NULL) {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ *s = '\0';
+ s++;
+
+ if (strcmp(r, "Yes") == 0) {
+ info->trust_flags |= WBC_DOMINFO_TRUST_TRANSITIVE;
+ }
+
+ /* Incoming */
+ r = s;
+ if ((s = strchr(r, '\\')) == NULL) {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ *s = '\0';
+ s++;
+
+ if (strcmp(r, "Yes") == 0) {
+ info->trust_flags |= WBC_DOMINFO_TRUST_INCOMING;
+ }
+
+ /* Outgoing */
+ r = s;
+ if ((s = strchr(r, '\\')) == NULL) {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ *s = '\0';
+ s++;
+
+ if (strcmp(r, "Yes") == 0) {
+ info->trust_flags |= WBC_DOMINFO_TRUST_OUTGOING;
+ }
+
+ /* Online/Offline status */
+
+ r = s;
+ if (r == NULL) {
+ wbc_status = WBC_ERR_INVALID_RESPONSE;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+ if ( strcmp(r, "Offline") == 0) {
+ info->domain_flags |= WBC_DOMINFO_DOMAIN_OFFLINE;
+ }
+
+ wbc_status = WBC_ERR_SUCCESS;
+
+ done:
+ return wbc_status;
+}
+
+/** @brief Enumerate the domain trusts known by Winbind
+ *
+ * @param **domains Pointer to the allocated domain list array
+ * @param *num_domains Pointer to number of domains returned
+ *
+ * @return #wbcErr
+ *
+ **/
+wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains)
+{
+ struct winbindd_response response;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ char *p = NULL;
+ char *q = NULL;
+ char *extra_data = NULL;
+ int count = 0;
+ struct wbcDomainInfo *d_list = NULL;
+ int i = 0;
+
+ *domains = NULL;
+ *num_domains = 0;
+
+ ZERO_STRUCT(response);
+
+ /* Send request */
+
+ wbc_status = wbcRequestResponse(WINBINDD_LIST_TRUSTDOM,
+ NULL,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ /* Decode the response */
+
+ p = (char *)response.extra_data.data;
+
+ if (strlen(p) == 0) {
+ /* We should always at least get back our
+ own SAM domain */
+
+ wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ /* Count number of domains */
+
+ count = 0;
+ while (p) {
+ count++;
+
+ if ((q = strchr(p, '\n')) != NULL)
+ q++;
+ p = q;
+ }
+
+ d_list = talloc_array(NULL, struct wbcDomainInfo, count);
+ BAIL_ON_PTR_ERROR(d_list, wbc_status);
+
+ extra_data = strdup((char*)response.extra_data.data);
+ BAIL_ON_PTR_ERROR(extra_data, wbc_status);
+
+ p = extra_data;
+
+ /* Outer loop processes the list of domain information */
+
+ for (i=0; i<count && p; i++) {
+ char *next = strchr(p, '\n');
+
+ if (next) {
+ *next = '\0';
+ next++;
+ }
+
+ wbc_status = process_domain_info_string(d_list, &d_list[i], p);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ p = next;
+ }
+
+ *domains = d_list;
+ *num_domains = i;
+
+ done:
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ if (d_list)
+ talloc_free(d_list);
+ if (extra_data)
+ free(extra_data);
+ }
+
+ return wbc_status;
+}
+
+/** @brief Enumerate the domain trusts known by Winbind
+ *
+ * @param domain Name of the domain to query for a DC
+ * @flags Bit flags used to control the domain location query
+ * @param *dc_info Pointer to the returned domain controller information
+ *
+ * @return #wbcErr
+ *
+ **/
+
+
+
+wbcErr wbcLookupDomainController(const char *domain,
+ uint32_t flags,
+ struct wbcDomainControllerInfo **dc_info)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ struct wbcDomainControllerInfo *dc = NULL;
+
+ /* validate input params */
+
+ if (!domain || !dc_info) {
+ wbc_status = WBC_ERR_INVALID_PARAM;
+ BAIL_ON_WBC_ERROR(wbc_status);
+ }
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ strncpy(request.domain_name, domain, sizeof(request.domain_name)-1);
+
+ request.flags = flags;
+
+ dc = talloc(NULL, struct wbcDomainControllerInfo);
+ BAIL_ON_PTR_ERROR(dc, wbc_status);
+
+ /* Send request */
+
+ wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
+ &request,
+ &response);
+ BAIL_ON_WBC_ERROR(wbc_status);
+
+ dc->dc_name = talloc_strdup(dc, response.data.dc_name);
+ BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status);
+
+ *dc_info = dc;
+
+done:
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ talloc_free(dc);
+ }
+
+ return wbc_status;
+}
diff --git a/source3/nsswitch/libwbclient/wbclient.c b/source3/nsswitch/libwbclient/wbclient.c
new file mode 100644
index 0000000000..bdde562a93
--- /dev/null
+++ b/source3/nsswitch/libwbclient/wbclient.c
@@ -0,0 +1,165 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind client API
+
+ Copyright (C) Gerald (Jerry) Carter 2007
+
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Required Headers */
+
+#include "libwbclient.h"
+
+/* From wb_common.c */
+
+NSS_STATUS winbindd_request_response(int req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response);
+
+/** @brief Wrapper around Winbind's send/receive API call
+ *
+ * @param cmd Winbind command operation to perform
+ * @param request Send structure
+ * @param response Receive structure
+ *
+ * @return #wbcErr
+ **/
+
+/**********************************************************************
+ result == NSS_STATUS_UNAVAIL: winbind not around
+ result == NSS_STATUS_NOTFOUND: winbind around, but domain missing
+
+ Due to a bad API NSS_STATUS_NOTFOUND is returned both when winbind_off
+ and when winbind return WINBINDD_ERROR. So the semantics of this
+ routine depends on winbind_on. Grepping for winbind_off I just
+ found 3 places where winbind is turned off, and this does not conflict
+ (as far as I have seen) with the callers of is_trusted_domains.
+
+ --Volker
+**********************************************************************/
+
+wbcErr wbcRequestResponse(int cmd,
+ struct winbindd_request *request,
+ struct winbindd_response *response)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ NSS_STATUS nss_status;
+
+ /* for some calls the request and/or response cna be NULL */
+
+ nss_status = winbindd_request_response(cmd, request, response);
+
+ switch (nss_status) {
+ case NSS_STATUS_SUCCESS:
+ wbc_status = WBC_ERR_SUCCESS;
+ break;
+ case NSS_STATUS_UNAVAIL:
+ wbc_status = WBC_ERR_WINBIND_NOT_AVAILABLE;
+ break;
+ case NSS_STATUS_NOTFOUND:
+ wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
+ break;
+ default:
+ wbc_status = WBC_ERR_NSS_ERROR;
+ break;
+ }
+
+ return wbc_status;
+}
+
+/** @brief Translate an error value into a string
+ *
+ * @param error
+ *
+ * @return a pointer to a static string
+ **/
+const char *wbcErrorString(wbcErr error)
+{
+ switch (error) {
+ case WBC_ERR_SUCCESS:
+ return "WBC_ERR_SUCCESS";
+ case WBC_ERR_NOT_IMPLEMENTED:
+ return "WBC_ERR_NOT_IMPLEMENTED";
+ case WBC_ERR_UNKNOWN_FAILURE:
+ return "WBC_ERR_UNKNOWN_FAILURE";
+ case WBC_ERR_NO_MEMORY:
+ return "WBC_ERR_NO_MEMORY";
+ case WBC_ERR_INVALID_SID:
+ return "WBC_ERR_INVALID_SID";
+ case WBC_ERR_INVALID_PARAM:
+ return "WBC_ERR_INVALID_PARAM";
+ case WBC_ERR_WINBIND_NOT_AVAILABLE:
+ return "WBC_ERR_WINBIND_NOT_AVAILABLE";
+ case WBC_ERR_DOMAIN_NOT_FOUND:
+ return "WBC_ERR_DOMAIN_NOT_FOUND";
+ case WBC_ERR_INVALID_RESPONSE:
+ return "WBC_ERR_INVALID_RESPONSE";
+ case WBC_ERR_NSS_ERROR:
+ return "WBC_ERR_NSS_ERROR";
+ case WBC_ERR_UNKNOWN_USER:
+ return "WBC_ERR_UNKNOWN_USER";
+ case WBC_ERR_UNKNOWN_GROUP:
+ return "WBC_ERR_UNKNOWN_GROUP";
+ case WBC_ERR_AUTH_ERROR:
+ return "WBC_ERR_AUTH_ERROR";
+ case WBC_ERR_PWD_CHANGE_FAILED:
+ return "WBC_ERR_PWD_CHANGE_FAILED";
+ }
+
+ return "unknown wbcErr value";
+}
+
+/** @brief Free library allocated memory
+ *
+ * @param *p Pointer to free
+ *
+ * @return void
+ **/
+
+void wbcFreeMemory(void *p)
+{
+ if (p)
+ talloc_free(p);
+
+ return;
+}
+
+wbcErr wbcLibraryDetails(struct wbcLibraryDetails **_details)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct wbcLibraryDetails *info;
+
+ info = talloc(NULL, struct wbcLibraryDetails);
+ BAIL_ON_PTR_ERROR(info, wbc_status);
+
+ info->major_version = WBCLIENT_MAJOR_VERSION;
+ info->minor_version = WBCLIENT_MINOR_VERSION;
+ info->vendor_version = talloc_strdup(info,
+ WBCLIENT_VENDOR_VERSION);
+ BAIL_ON_PTR_ERROR(info->vendor_version, wbc_status);
+
+ *_details = info;
+ info = NULL;
+
+ wbc_status = WBC_ERR_SUCCESS;
+
+done:
+ talloc_free(info);
+ return wbc_status;
+}
+
+
diff --git a/source3/nsswitch/libwbclient/wbclient.h b/source3/nsswitch/libwbclient/wbclient.h
new file mode 100644
index 0000000000..cae3feec5b
--- /dev/null
+++ b/source3/nsswitch/libwbclient/wbclient.h
@@ -0,0 +1,571 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind client API
+
+ Copyright (C) Gerald (Jerry) Carter 2007
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _WBCLIENT_H
+#define _WBCLIENT_H
+
+#include <pwd.h>
+#include <grp.h>
+
+/* Define error types */
+
+/**
+ * @brief Status codes returned from wbc functions
+ **/
+
+enum _wbcErrType {
+ WBC_ERR_SUCCESS = 0, /**< Successful completion **/
+ WBC_ERR_NOT_IMPLEMENTED,/**< Function not implemented **/
+ WBC_ERR_UNKNOWN_FAILURE,/**< General failure **/
+ WBC_ERR_NO_MEMORY, /**< Memory allocation error **/
+ WBC_ERR_INVALID_SID, /**< Invalid SID format **/
+ WBC_ERR_INVALID_PARAM, /**< An Invalid parameter was supplied **/
+ WBC_ERR_WINBIND_NOT_AVAILABLE, /**< Winbind daemon is not available **/
+ WBC_ERR_DOMAIN_NOT_FOUND, /**< Domain is not trusted or cannot be found **/
+ WBC_ERR_INVALID_RESPONSE, /**< Winbind returned an invalid response **/
+ WBC_ERR_NSS_ERROR, /**< NSS_STATUS error **/
+ WBC_ERR_AUTH_ERROR, /**< Authentication failed **/
+ WBC_ERR_UNKNOWN_USER, /**< User account cannot be found */
+ WBC_ERR_UNKNOWN_GROUP, /**< Group account cannot be found */
+ WBC_ERR_PWD_CHANGE_FAILED /**< Password Change has failed */
+};
+
+typedef enum _wbcErrType wbcErr;
+
+#define WBC_ERROR_IS_OK(x) ((x) == WBC_ERR_SUCCESS)
+
+const char *wbcErrorString(wbcErr error);
+
+/**
+ * @brief Some useful details about the wbclient library
+ *
+ **/
+#define WBCLIENT_MAJOR_VERSION 0
+#define WBCLIENT_MINOR_VERSION 1
+#define WBCLIENT_VENDOR_VERSION "Samba libwbclient"
+struct wbcLibraryDetails {
+ uint16_t major_version;
+ uint16_t minor_version;
+ const char *vendor_version;
+};
+
+/**
+ * @brief Some useful details about the running winbindd
+ *
+ **/
+struct wbcInterfaceDetails {
+ uint32_t interface_version;
+ const char *winbind_version;
+ char winbind_separator;
+ const char *netbios_name;
+ const char *netbios_domain;
+ const char *dns_domain;
+};
+
+/*
+ * Data types used by the Winbind Client API
+ */
+
+#ifndef WBC_MAXSUBAUTHS
+#define WBC_MAXSUBAUTHS 15 /* max sub authorities in a SID */
+#endif
+
+/**
+ * @brief Windows Security Identifier
+ *
+ **/
+
+struct wbcDomainSid {
+ uint8_t sid_rev_num;
+ uint8_t num_auths;
+ uint8_t id_auth[6];
+ uint32_t sub_auths[WBC_MAXSUBAUTHS];
+};
+
+/**
+ * @brief Security Identifier type
+ **/
+
+enum wbcSidType {
+ WBC_SID_NAME_USE_NONE=0,
+ WBC_SID_NAME_USER=1,
+ WBC_SID_NAME_DOM_GRP=2,
+ WBC_SID_NAME_DOMAIN=3,
+ WBC_SID_NAME_ALIAS=4,
+ WBC_SID_NAME_WKN_GRP=5,
+ WBC_SID_NAME_DELETED=6,
+ WBC_SID_NAME_INVALID=7,
+ WBC_SID_NAME_UNKNOWN=8,
+ WBC_SID_NAME_COMPUTER=9
+};
+
+/**
+ * @brief Security Identifier with attributes
+ **/
+
+struct wbcSidWithAttr {
+ struct wbcDomainSid sid;
+ uint32_t attributes;
+};
+
+/* wbcSidWithAttr->attributes */
+
+#define WBC_SID_ATTR_GROUP_MANDATORY 0x00000001
+#define WBC_SID_ATTR_GROUP_ENABLED_BY_DEFAULT 0x00000002
+#define WBC_SID_ATTR_GROUP_ENABLED 0x00000004
+#define WBC_SID_ATTR_GROUP_OWNER 0x00000008
+#define WBC_SID_ATTR_GROUP_USEFOR_DENY_ONLY 0x00000010
+#define WBC_SID_ATTR_GROUP_RESOURCE 0x20000000
+#define WBC_SID_ATTR_GROUP_LOGON_ID 0xC0000000
+
+/**
+ * @brief Domain Information
+ **/
+
+struct wbcDomainInfo {
+ char *short_name;
+ char *dns_name;
+ struct wbcDomainSid sid;
+ uint32_t domain_flags;
+ uint32_t trust_flags;
+ uint32_t trust_type;
+};
+
+/* wbcDomainInfo->domain_flags */
+
+#define WBC_DOMINFO_DOMAIN_UNKNOWN 0x00000000
+#define WBC_DOMINFO_DOMAIN_NATIVE 0x00000001
+#define WBC_DOMINFO_DOMAIN_AD 0x00000002
+#define WBC_DOMINFO_DOMAIN_PRIMARY 0x00000004
+#define WBC_DOMINFO_DOMAIN_OFFLINE 0x00000008
+
+/* wbcDomainInfo->trust_flags */
+
+#define WBC_DOMINFO_TRUST_TRANSITIVE 0x00000001
+#define WBC_DOMINFO_TRUST_INCOMING 0x00000002
+#define WBC_DOMINFO_TRUST_OUTGOING 0x00000004
+
+/* wbcDomainInfo->trust_type */
+
+#define WBC_DOMINFO_TRUSTTYPE_NONE 0x00000000
+#define WBC_DOMINFO_TRUSTTYPE_FOREST 0x00000001
+#define WBC_DOMINFO_TRUSTTYPE_IN_FOREST 0x00000002
+#define WBC_DOMINFO_TRUSTTYPE_EXTERNAL 0x00000003
+
+
+/**
+ * @brief Auth User Parameters
+ **/
+
+struct wbcAuthUserParams {
+ const char *account_name;
+ const char *domain_name;
+ const char *workstation_name;
+
+ uint32_t flags;
+
+ uint32_t parameter_control;
+
+ enum wbcAuthUserLevel {
+ WBC_AUTH_USER_LEVEL_PLAIN = 1,
+ WBC_AUTH_USER_LEVEL_HASH = 2,
+ WBC_AUTH_USER_LEVEL_RESPONSE = 3
+ } level;
+ union {
+ const char *plaintext;
+ struct {
+ uint8_t nt_hash[16];
+ uint8_t lm_hash[16];
+ } hash;
+ struct {
+ uint8_t challenge[8];
+ uint32_t nt_length;
+ uint8_t *nt_data;
+ uint32_t lm_length;
+ uint8_t *lm_data;
+ } response;
+ } password;
+};
+
+/**
+ * @brief ChangePassword Parameters
+ **/
+
+struct wbcChangePasswordParams {
+ const char *account_name;
+ const char *domain_name;
+
+ uint32_t flags;
+
+ enum wbcChangePasswordLevel {
+ WBC_CHANGE_PASSWORD_LEVEL_PLAIN = 1,
+ WBC_CHANGE_PASSWORD_LEVEL_RESPONSE = 2
+ } level;
+
+ union {
+ const char *plaintext;
+ struct {
+ uint32_t old_nt_hash_enc_length;
+ uint8_t *old_nt_hash_enc_data;
+ uint32_t old_lm_hash_enc_length;
+ uint8_t *old_lm_hash_enc_data;
+ } response;
+ } old_password;
+ union {
+ const char *plaintext;
+ struct {
+ uint32_t nt_length;
+ uint8_t *nt_data;
+ uint32_t lm_length;
+ uint8_t *lm_data;
+ } response;
+ } new_password;
+};
+
+/* wbcAuthUserParams->parameter_control */
+
+#define WBC_MSV1_0_CLEARTEXT_PASSWORD_ALLOWED 0x00000002
+#define WBC_MSV1_0_UPDATE_LOGON_STATISTICS 0x00000004
+#define WBC_MSV1_0_RETURN_USER_PARAMETERS 0x00000008
+#define WBC_MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT 0x00000020
+#define WBC_MSV1_0_RETURN_PROFILE_PATH 0x00000200
+#define WBC_MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT 0x00000800
+
+/* wbcAuthUserParams->flags */
+
+#define WBC_AUTH_PARAM_FLAGS_INTERACTIVE_LOGON 0x00000001
+
+/**
+ * @brief Auth User Information
+ *
+ * Some of the strings are maybe NULL
+ **/
+
+struct wbcAuthUserInfo {
+ uint32_t user_flags;
+
+ char *account_name;
+ char *user_principal;
+ char *full_name;
+ char *domain_name;
+ char *dns_domain_name;
+
+ uint32_t acct_flags;
+ uint8_t user_session_key[16];
+ uint8_t lm_session_key[8];
+
+ uint16_t logon_count;
+ uint16_t bad_password_count;
+
+ uint64_t logon_time;
+ uint64_t logoff_time;
+ uint64_t kickoff_time;
+ uint64_t pass_last_set_time;
+ uint64_t pass_can_change_time;
+ uint64_t pass_must_change_time;
+
+ char *logon_server;
+ char *logon_script;
+ char *profile_path;
+ char *home_directory;
+ char *home_drive;
+
+ /*
+ * the 1st one is the account sid
+ * the 2nd one is the primary_group sid
+ * followed by the rest of the groups
+ */
+ uint32_t num_sids;
+ struct wbcSidWithAttr *sids;
+};
+
+/* wbcAuthUserInfo->user_flags */
+
+#define WBC_AUTH_USER_INFO_GUEST 0x00000001
+#define WBC_AUTH_USER_INFO_NOENCRYPTION 0x00000002
+#define WBC_AUTH_USER_INFO_CACHED_ACCOUNT 0x00000004
+#define WBC_AUTH_USER_INFO_USED_LM_PASSWORD 0x00000008
+#define WBC_AUTH_USER_INFO_EXTRA_SIDS 0x00000020
+#define WBC_AUTH_USER_INFO_SUBAUTH_SESSION_KEY 0x00000040
+#define WBC_AUTH_USER_INFO_SERVER_TRUST_ACCOUNT 0x00000080
+#define WBC_AUTH_USER_INFO_NTLMV2_ENABLED 0x00000100
+#define WBC_AUTH_USER_INFO_RESOURCE_GROUPS 0x00000200
+#define WBC_AUTH_USER_INFO_PROFILE_PATH_RETURNED 0x00000400
+#define WBC_AUTH_USER_INFO_GRACE_LOGON 0x01000000
+
+/* wbcAuthUserInfo->acct_flags */
+
+#define WBC_ACB_DISABLED 0x00000001 /* 1 User account disabled */
+#define WBC_ACB_HOMDIRREQ 0x00000002 /* 1 Home directory required */
+#define WBC_ACB_PWNOTREQ 0x00000004 /* 1 User password not required */
+#define WBC_ACB_TEMPDUP 0x00000008 /* 1 Temporary duplicate account */
+#define WBC_ACB_NORMAL 0x00000010 /* 1 Normal user account */
+#define WBC_ACB_MNS 0x00000020 /* 1 MNS logon user account */
+#define WBC_ACB_DOMTRUST 0x00000040 /* 1 Interdomain trust account */
+#define WBC_ACB_WSTRUST 0x00000080 /* 1 Workstation trust account */
+#define WBC_ACB_SVRTRUST 0x00000100 /* 1 Server trust account */
+#define WBC_ACB_PWNOEXP 0x00000200 /* 1 User password does not expire */
+#define WBC_ACB_AUTOLOCK 0x00000400 /* 1 Account auto locked */
+#define WBC_ACB_ENC_TXT_PWD_ALLOWED 0x00000800 /* 1 Encryped text password is allowed */
+#define WBC_ACB_SMARTCARD_REQUIRED 0x00001000 /* 1 Smart Card required */
+#define WBC_ACB_TRUSTED_FOR_DELEGATION 0x00002000 /* 1 Trusted for Delegation */
+#define WBC_ACB_NOT_DELEGATED 0x00004000 /* 1 Not delegated */
+#define WBC_ACB_USE_DES_KEY_ONLY 0x00008000 /* 1 Use DES key only */
+#define WBC_ACB_DONT_REQUIRE_PREAUTH 0x00010000 /* 1 Preauth not required */
+#define WBC_ACB_PW_EXPIRED 0x00020000 /* 1 Password Expired */
+#define WBC_ACB_NO_AUTH_DATA_REQD 0x00080000 /* 1 = No authorization data required */
+
+struct wbcAuthErrorInfo {
+ uint32_t nt_status;
+ char *nt_string;
+ int32_t pam_error;
+ char *display_string;
+};
+
+/**
+ * @brief User Password Policy Information
+ **/
+
+/* wbcUserPasswordPolicyInfo->password_properties */
+
+#define WBC_DOMAIN_PASSWORD_COMPLEX 0x00000001
+#define WBC_DOMAIN_PASSWORD_NO_ANON_CHANGE 0x00000002
+#define WBC_DOMAIN_PASSWORD_NO_CLEAR_CHANGE 0x00000004
+#define WBC_DOMAIN_PASSWORD_LOCKOUT_ADMINS 0x00000008
+#define WBC_DOMAIN_PASSWORD_STORE_CLEARTEXT 0x00000010
+#define WBC_DOMAIN_REFUSE_PASSWORD_CHANGE 0x00000020
+
+struct wbcUserPasswordPolicyInfo {
+ uint32_t min_length_password;
+ uint32_t password_history;
+ uint32_t password_properties;
+ uint64_t expire;
+ uint64_t min_passwordage;
+};
+
+/**
+ * @brief Change Password Reject Reason
+ **/
+
+enum wbcPasswordChangeRejectReason {
+ WBC_PWD_CHANGE_REJECT_OTHER=0,
+ WBC_PWD_CHANGE_REJECT_TOO_SHORT=1,
+ WBC_PWD_CHANGE_REJECT_IN_HISTORY=2,
+ WBC_PWD_CHANGE_REJECT_COMPLEXITY=5
+};
+
+/*
+ * DomainControllerInfo struct
+ */
+struct wbcDomainControllerInfo {
+ char *dc_name;
+};
+
+
+
+/*
+ * Memory Management
+ */
+
+void wbcFreeMemory(void*);
+
+
+/*
+ * Utility functions for dealing with SIDs
+ */
+
+wbcErr wbcSidToString(const struct wbcDomainSid *sid,
+ char **sid_string);
+
+wbcErr wbcStringToSid(const char *sid_string,
+ struct wbcDomainSid *sid);
+
+wbcErr wbcPing(void);
+
+wbcErr wbcLibraryDetails(struct wbcLibraryDetails **details);
+
+wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **details);
+
+/*
+ * Name/SID conversion
+ */
+
+wbcErr wbcLookupName(const char *dom_name,
+ const char *name,
+ struct wbcDomainSid *sid,
+ enum wbcSidType *name_type);
+
+wbcErr wbcLookupSid(const struct wbcDomainSid *sid,
+ char **domain,
+ char **name,
+ enum wbcSidType *name_type);
+
+wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
+ int num_rids,
+ uint32_t *rids,
+ const char **domain_name,
+ const char ***names,
+ enum wbcSidType **types);
+
+wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
+ bool domain_groups_only,
+ uint32_t *num_sids,
+ struct wbcDomainSid **sids);
+
+wbcErr wbcListUsers(const char *domain_name,
+ uint32_t *num_users,
+ const char ***users);
+
+wbcErr wbcListGroups(const char *domain_name,
+ uint32_t *num_groups,
+ const char ***groups);
+
+/*
+ * SID/uid/gid Mappings
+ */
+
+wbcErr wbcSidToUid(const struct wbcDomainSid *sid,
+ uid_t *puid);
+
+wbcErr wbcUidToSid(uid_t uid,
+ struct wbcDomainSid *sid);
+
+wbcErr wbcSidToGid(const struct wbcDomainSid *sid,
+ gid_t *pgid);
+
+wbcErr wbcGidToSid(gid_t gid,
+ struct wbcDomainSid *sid);
+
+wbcErr wbcAllocateUid(uid_t *puid);
+
+wbcErr wbcAllocateGid(gid_t *pgid);
+
+wbcErr wbcSetUidMapping(uid_t uid, const struct wbcDomainSid *sid);
+
+wbcErr wbcSetGidMapping(gid_t gid, const struct wbcDomainSid *sid);
+
+wbcErr wbcSetUidHwm(uid_t uid_hwm);
+
+wbcErr wbcSetGidHwm(gid_t gid_hwm);
+
+/*
+ * NSS Lookup User/Group details
+ */
+
+wbcErr wbcGetpwnam(const char *name, struct passwd **pwd);
+
+wbcErr wbcGetpwuid(uid_t uid, struct passwd **pwd);
+
+wbcErr wbcGetgrnam(const char *name, struct group **grp);
+
+wbcErr wbcGetgrgid(gid_t gid, struct group **grp);
+
+wbcErr wbcSetpwent(void);
+
+wbcErr wbcEndpwent(void);
+
+wbcErr wbcGetpwent(struct passwd **pwd);
+
+wbcErr wbcSetgrent(void);
+
+wbcErr wbcEndgrent(void);
+
+wbcErr wbcGetgrent(struct group **grp);
+
+wbcErr wbcGetGroups(const char *account,
+ uint32_t *num_groups,
+ gid_t **_groups);
+
+
+/*
+ * Lookup Domain information
+ */
+
+wbcErr wbcDomainInfo(const char *domain,
+ struct wbcDomainInfo **info);
+
+wbcErr wbcListTrusts(struct wbcDomainInfo **domains,
+ size_t *num_domains);
+
+/* Flags for wbcLookupDomainController */
+
+#define WBC_LOOKUP_DC_FORCE_REDISCOVERY 0x00000001
+#define WBC_LOOKUP_DC_DS_REQUIRED 0x00000010
+#define WBC_LOOKUP_DC_DS_PREFERRED 0x00000020
+#define WBC_LOOKUP_DC_GC_SERVER_REQUIRED 0x00000040
+#define WBC_LOOKUP_DC_PDC_REQUIRED 0x00000080
+#define WBC_LOOKUP_DC_BACKGROUND_ONLY 0x00000100
+#define WBC_LOOKUP_DC_IP_REQUIRED 0x00000200
+#define WBC_LOOKUP_DC_KDC_REQUIRED 0x00000400
+#define WBC_LOOKUP_DC_TIMESERV_REQUIRED 0x00000800
+#define WBC_LOOKUP_DC_WRITABLE_REQUIRED 0x00001000
+#define WBC_LOOKUP_DC_GOOD_TIMESERV_PREFERRED 0x00002000
+#define WBC_LOOKUP_DC_AVOID_SELF 0x00004000
+#define WBC_LOOKUP_DC_ONLY_LDAP_NEEDED 0x00008000
+#define WBC_LOOKUP_DC_IS_FLAT_NAME 0x00010000
+#define WBC_LOOKUP_DC_IS_DNS_NAME 0x00020000
+#define WBC_LOOKUP_DC_TRY_NEXTCLOSEST_SITE 0x00040000
+#define WBC_LOOKUP_DC_DS_6_REQUIRED 0x00080000
+#define WBC_LOOKUP_DC_RETURN_DNS_NAME 0x40000000
+#define WBC_LOOKUP_DC_RETURN_FLAT_NAME 0x80000000
+
+wbcErr wbcLookupDomainController(const char *domain,
+ uint32_t flags,
+ struct wbcDomainControllerInfo **dc_info);
+
+/*
+ * Athenticate functions
+ */
+
+wbcErr wbcAuthenticateUser(const char *username,
+ const char *password);
+
+wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
+ struct wbcAuthUserInfo **info,
+ struct wbcAuthErrorInfo **error);
+
+wbcErr wbcLogoffUser(const char *username,
+ uid_t uid,
+ const char *ccfilename);
+
+wbcErr wbcChangeUserPassword(const char *username,
+ const char *old_password,
+ const char *new_password);
+
+wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params,
+ struct wbcAuthErrorInfo **error,
+ enum wbcPasswordChangeRejectReason *reject_reason,
+ struct wbcUserPasswordPolicyInfo **policy);
+
+/*
+ * Resolve functions
+ */
+wbcErr wbcResolveWinsByName(const char *name, char **ip);
+wbcErr wbcResolveWinsByIP(const char *ip, char **name);
+
+/*
+ * Trusted domain functions
+ */
+wbcErr wbcCheckTrustCredentials(const char *domain,
+ struct wbcAuthErrorInfo **error);
+
+
+#endif /* _WBCLIENT_H */
diff --git a/source3/nsswitch/libwbclient/wbclient_internal.h b/source3/nsswitch/libwbclient/wbclient_internal.h
new file mode 100644
index 0000000000..fc03c5409b
--- /dev/null
+++ b/source3/nsswitch/libwbclient/wbclient_internal.h
@@ -0,0 +1,32 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind client API
+
+ Copyright (C) Gerald (Jerry) Carter 2007
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _WBCLIENT_INTERNAL_H
+#define _WBCLIENT_INTERNAL_H
+
+/* Private functions */
+
+wbcErr wbcRequestResponse(int cmd,
+ struct winbindd_request *request,
+ struct winbindd_response *response);
+
+
+#endif /* _WBCLIENT_INTERNAL_H */
diff --git a/source3/nsswitch/pam_winbind.c b/source3/nsswitch/pam_winbind.c
new file mode 100644
index 0000000000..c28c5d2697
--- /dev/null
+++ b/source3/nsswitch/pam_winbind.c
@@ -0,0 +1,2817 @@
+/* pam_winbind module
+
+ Copyright Andrew Tridgell <tridge@samba.org> 2000
+ Copyright Tim Potter <tpot@samba.org> 2000
+ Copyright Andrew Bartlett <abartlet@samba.org> 2002
+ Copyright Guenther Deschner <gd@samba.org> 2005-2008
+
+ largely based on pam_userdb by Cristian Gafton <gafton@redhat.com> also
+ contains large slabs of code from pam_unix by Elliot Lee
+ <sopwith@redhat.com> (see copyright below for full details)
+*/
+
+#include "pam_winbind.h"
+
+static const char *_pam_error_code_str(int err)
+{
+ switch (err) {
+ case PAM_SUCCESS:
+ return "PAM_SUCCESS";
+ case PAM_OPEN_ERR:
+ return "PAM_OPEN_ERR";
+ case PAM_SYMBOL_ERR:
+ return "PAM_SYMBOL_ERR";
+ case PAM_SERVICE_ERR:
+ return "PAM_SERVICE_ERR";
+ case PAM_SYSTEM_ERR:
+ return "PAM_SYSTEM_ERR";
+ case PAM_BUF_ERR:
+ return "PAM_BUF_ERR";
+ case PAM_PERM_DENIED:
+ return "PAM_PERM_DENIED";
+ case PAM_AUTH_ERR:
+ return "PAM_AUTH_ERR";
+ case PAM_CRED_INSUFFICIENT:
+ return "PAM_CRED_INSUFFICIENT";
+ case PAM_AUTHINFO_UNAVAIL:
+ return "PAM_AUTHINFO_UNAVAIL";
+ case PAM_USER_UNKNOWN:
+ return "PAM_USER_UNKNOWN";
+ case PAM_MAXTRIES:
+ return "PAM_MAXTRIES";
+ case PAM_NEW_AUTHTOK_REQD:
+ return "PAM_NEW_AUTHTOK_REQD";
+ case PAM_ACCT_EXPIRED:
+ return "PAM_ACCT_EXPIRED";
+ case PAM_SESSION_ERR:
+ return "PAM_SESSION_ERR";
+ case PAM_CRED_UNAVAIL:
+ return "PAM_CRED_UNAVAIL";
+ case PAM_CRED_EXPIRED:
+ return "PAM_CRED_EXPIRED";
+ case PAM_CRED_ERR:
+ return "PAM_CRED_ERR";
+ case PAM_NO_MODULE_DATA:
+ return "PAM_NO_MODULE_DATA";
+ case PAM_CONV_ERR:
+ return "PAM_CONV_ERR";
+ case PAM_AUTHTOK_ERR:
+ return "PAM_AUTHTOK_ERR";
+ case PAM_AUTHTOK_RECOVERY_ERR:
+ return "PAM_AUTHTOK_RECOVERY_ERR";
+ case PAM_AUTHTOK_LOCK_BUSY:
+ return "PAM_AUTHTOK_LOCK_BUSY";
+ case PAM_AUTHTOK_DISABLE_AGING:
+ return "PAM_AUTHTOK_DISABLE_AGING";
+ case PAM_TRY_AGAIN:
+ return "PAM_TRY_AGAIN";
+ case PAM_IGNORE:
+ return "PAM_IGNORE";
+ case PAM_ABORT:
+ return "PAM_ABORT";
+ case PAM_AUTHTOK_EXPIRED:
+ return "PAM_AUTHTOK_EXPIRED";
+ case PAM_MODULE_UNKNOWN:
+ return "PAM_MODULE_UNKNOWN";
+ case PAM_BAD_ITEM:
+ return "PAM_BAD_ITEM";
+ case PAM_CONV_AGAIN:
+ return "PAM_CONV_AGAIN";
+ case PAM_INCOMPLETE:
+ return "PAM_INCOMPLETE";
+ default:
+ return NULL;
+ }
+}
+
+#define _PAM_LOG_FUNCTION_ENTER(function, ctx) \
+ do { \
+ _pam_log_debug(ctx, LOG_DEBUG, "[pamh: %p] ENTER: " \
+ function " (flags: 0x%04x)", ctx->pamh, ctx->flags); \
+ _pam_log_state(ctx); \
+ } while (0)
+
+#define _PAM_LOG_FUNCTION_LEAVE(function, ctx, retval) \
+ do { \
+ _pam_log_debug(ctx, LOG_DEBUG, "[pamh: %p] LEAVE: " \
+ function " returning %d (%s)", ctx->pamh, retval, \
+ _pam_error_code_str(retval)); \
+ _pam_log_state(ctx); \
+ } while (0)
+
+/* data tokens */
+
+#define MAX_PASSWD_TRIES 3
+
+/*
+ * Work around the pam API that has functions with void ** as parameters
+ * These lead to strict aliasing warnings with gcc.
+ */
+static int _pam_get_item(const pam_handle_t *pamh,
+ int item_type,
+ const void *_item)
+{
+ const void **item = (const void **)_item;
+ return pam_get_item(pamh, item_type, item);
+}
+static int _pam_get_data(const pam_handle_t *pamh,
+ const char *module_data_name,
+ const void *_data)
+{
+ const void **data = (const void **)_data;
+ return pam_get_data(pamh, module_data_name, data);
+}
+
+/* some syslogging */
+
+#ifdef HAVE_PAM_VSYSLOG
+static void _pam_log_int(const pam_handle_t *pamh,
+ int err,
+ const char *format,
+ va_list args)
+{
+ pam_vsyslog(pamh, err, format, args);
+}
+#else
+static void _pam_log_int(const pam_handle_t *pamh,
+ int err,
+ const char *format,
+ va_list args)
+{
+ char *format2 = NULL;
+ const char *service;
+
+ _pam_get_item(pamh, PAM_SERVICE, &service);
+
+ format2 = (char *)malloc(strlen(MODULE_NAME)+strlen(format)+strlen(service)+5);
+ if (format2 == NULL) {
+ /* what else todo ? */
+ vsyslog(err, format, args);
+ return;
+ }
+
+ sprintf(format2, "%s(%s): %s", MODULE_NAME, service, format);
+ vsyslog(err, format2, args);
+ SAFE_FREE(format2);
+}
+#endif /* HAVE_PAM_VSYSLOG */
+
+static bool _pam_log_is_silent(int ctrl)
+{
+ return on(ctrl, WINBIND_SILENT);
+}
+
+static void _pam_log(struct pwb_context *r, int err, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+static void _pam_log(struct pwb_context *r, int err, const char *format, ...)
+{
+ va_list args;
+
+ if (_pam_log_is_silent(r->ctrl)) {
+ return;
+ }
+
+ va_start(args, format);
+ _pam_log_int(r->pamh, err, format, args);
+ va_end(args);
+}
+static void __pam_log(const pam_handle_t *pamh, int ctrl, int err, const char *format, ...) PRINTF_ATTRIBUTE(4,5);
+static void __pam_log(const pam_handle_t *pamh, int ctrl, int err, const char *format, ...)
+{
+ va_list args;
+
+ if (_pam_log_is_silent(ctrl)) {
+ return;
+ }
+
+ va_start(args, format);
+ _pam_log_int(pamh, err, format, args);
+ va_end(args);
+}
+
+static bool _pam_log_is_debug_enabled(int ctrl)
+{
+ if (ctrl == -1) {
+ return false;
+ }
+
+ if (_pam_log_is_silent(ctrl)) {
+ return false;
+ }
+
+ if (!(ctrl & WINBIND_DEBUG_ARG)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool _pam_log_is_debug_state_enabled(int ctrl)
+{
+ if (!(ctrl & WINBIND_DEBUG_STATE)) {
+ return false;
+ }
+
+ return _pam_log_is_debug_enabled(ctrl);
+}
+
+static void _pam_log_debug(struct pwb_context *r, int err, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+static void _pam_log_debug(struct pwb_context *r, int err, const char *format, ...)
+{
+ va_list args;
+
+ if (!_pam_log_is_debug_enabled(r->ctrl)) {
+ return;
+ }
+
+ va_start(args, format);
+ _pam_log_int(r->pamh, err, format, args);
+ va_end(args);
+}
+static void __pam_log_debug(const pam_handle_t *pamh, int ctrl, int err, const char *format, ...) PRINTF_ATTRIBUTE(4,5);
+static void __pam_log_debug(const pam_handle_t *pamh, int ctrl, int err, const char *format, ...)
+{
+ va_list args;
+
+ if (!_pam_log_is_debug_enabled(ctrl)) {
+ return;
+ }
+
+ va_start(args, format);
+ _pam_log_int(pamh, err, format, args);
+ va_end(args);
+}
+
+static void _pam_log_state_datum(struct pwb_context *ctx,
+ int item_type,
+ const char *key,
+ int is_string)
+{
+ const void *data = NULL;
+ if (item_type != 0) {
+ pam_get_item(ctx->pamh, item_type, &data);
+ } else {
+ pam_get_data(ctx->pamh, key, &data);
+ }
+ if (data != NULL) {
+ const char *type = (item_type != 0) ? "ITEM" : "DATA";
+ if (is_string != 0) {
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "[pamh: %p] STATE: %s(%s) = \"%s\" (%p)",
+ ctx->pamh, type, key, (const char *)data,
+ data);
+ } else {
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "[pamh: %p] STATE: %s(%s) = %p",
+ ctx->pamh, type, key, data);
+ }
+ }
+}
+
+#define _PAM_LOG_STATE_DATA_POINTER(ctx, module_data_name) \
+ _pam_log_state_datum(ctx, 0, module_data_name, 0)
+
+#define _PAM_LOG_STATE_DATA_STRING(ctx, module_data_name) \
+ _pam_log_state_datum(ctx, 0, module_data_name, 1)
+
+#define _PAM_LOG_STATE_ITEM_POINTER(ctx, item_type) \
+ _pam_log_state_datum(ctx, item_type, #item_type, 0)
+
+#define _PAM_LOG_STATE_ITEM_STRING(ctx, item_type) \
+ _pam_log_state_datum(ctx, item_type, #item_type, 1)
+
+#ifdef DEBUG_PASSWORD
+#define _LOG_PASSWORD_AS_STRING 1
+#else
+#define _LOG_PASSWORD_AS_STRING 0
+#endif
+
+#define _PAM_LOG_STATE_ITEM_PASSWORD(ctx, item_type) \
+ _pam_log_state_datum(ctx, item_type, #item_type, \
+ _LOG_PASSWORD_AS_STRING)
+
+static void _pam_log_state(struct pwb_context *ctx)
+{
+ if (!_pam_log_is_debug_state_enabled(ctx->ctrl)) {
+ return;
+ }
+
+ _PAM_LOG_STATE_ITEM_STRING(ctx, PAM_SERVICE);
+ _PAM_LOG_STATE_ITEM_STRING(ctx, PAM_USER);
+ _PAM_LOG_STATE_ITEM_STRING(ctx, PAM_TTY);
+ _PAM_LOG_STATE_ITEM_STRING(ctx, PAM_RHOST);
+ _PAM_LOG_STATE_ITEM_STRING(ctx, PAM_RUSER);
+ _PAM_LOG_STATE_ITEM_PASSWORD(ctx, PAM_OLDAUTHTOK);
+ _PAM_LOG_STATE_ITEM_PASSWORD(ctx, PAM_AUTHTOK);
+ _PAM_LOG_STATE_ITEM_STRING(ctx, PAM_USER_PROMPT);
+ _PAM_LOG_STATE_ITEM_POINTER(ctx, PAM_CONV);
+#ifdef PAM_FAIL_DELAY
+ _PAM_LOG_STATE_ITEM_POINTER(ctx, PAM_FAIL_DELAY);
+#endif
+#ifdef PAM_REPOSITORY
+ _PAM_LOG_STATE_ITEM_POINTER(ctx, PAM_REPOSITORY);
+#endif
+
+ _PAM_LOG_STATE_DATA_STRING(ctx, PAM_WINBIND_HOMEDIR);
+ _PAM_LOG_STATE_DATA_STRING(ctx, PAM_WINBIND_LOGONSCRIPT);
+ _PAM_LOG_STATE_DATA_STRING(ctx, PAM_WINBIND_LOGONSERVER);
+ _PAM_LOG_STATE_DATA_STRING(ctx, PAM_WINBIND_PROFILEPATH);
+ _PAM_LOG_STATE_DATA_STRING(ctx,
+ PAM_WINBIND_NEW_AUTHTOK_REQD);
+ /* Use atoi to get PAM result code */
+ _PAM_LOG_STATE_DATA_STRING(ctx,
+ PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH);
+ _PAM_LOG_STATE_DATA_POINTER(ctx, PAM_WINBIND_PWD_LAST_SET);
+}
+
+static int _pam_parse(const pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv,
+ dictionary **result_d)
+{
+ int ctrl = 0;
+ const char *config_file = NULL;
+ int i;
+ const char **v;
+ dictionary *d = NULL;
+
+ if (flags & PAM_SILENT) {
+ ctrl |= WINBIND_SILENT;
+ }
+
+ for (i=argc,v=argv; i-- > 0; ++v) {
+ if (!strncasecmp(*v, "config", strlen("config"))) {
+ ctrl |= WINBIND_CONFIG_FILE;
+ config_file = v[i];
+ break;
+ }
+ }
+
+ if (config_file == NULL) {
+ config_file = PAM_WINBIND_CONFIG_FILE;
+ }
+
+ d = iniparser_load(config_file);
+ if (d == NULL) {
+ goto config_from_pam;
+ }
+
+ if (iniparser_getboolean(d, "global:debug", false)) {
+ ctrl |= WINBIND_DEBUG_ARG;
+ }
+
+ if (iniparser_getboolean(d, "global:debug_state", false)) {
+ ctrl |= WINBIND_DEBUG_STATE;
+ }
+
+ if (iniparser_getboolean(d, "global:cached_login", false)) {
+ ctrl |= WINBIND_CACHED_LOGIN;
+ }
+
+ if (iniparser_getboolean(d, "global:krb5_auth", false)) {
+ ctrl |= WINBIND_KRB5_AUTH;
+ }
+
+ if (iniparser_getboolean(d, "global:silent", false)) {
+ ctrl |= WINBIND_SILENT;
+ }
+
+ if (iniparser_getstr(d, "global:krb5_ccache_type") != NULL) {
+ ctrl |= WINBIND_KRB5_CCACHE_TYPE;
+ }
+
+ if ((iniparser_getstr(d, "global:require-membership-of") != NULL) ||
+ (iniparser_getstr(d, "global:require_membership_of") != NULL)) {
+ ctrl |= WINBIND_REQUIRED_MEMBERSHIP;
+ }
+
+ if (iniparser_getboolean(d, "global:try_first_pass", false)) {
+ ctrl |= WINBIND_TRY_FIRST_PASS_ARG;
+ }
+
+ if (iniparser_getint(d, "global:warn_pwd_expire", 0)) {
+ ctrl |= WINBIND_WARN_PWD_EXPIRE;
+ }
+
+config_from_pam:
+ /* step through arguments */
+ for (i=argc,v=argv; i-- > 0; ++v) {
+
+ /* generic options */
+ if (!strcmp(*v,"debug"))
+ ctrl |= WINBIND_DEBUG_ARG;
+ else if (!strcasecmp(*v, "debug_state"))
+ ctrl |= WINBIND_DEBUG_STATE;
+ else if (!strcasecmp(*v, "silent"))
+ ctrl |= WINBIND_SILENT;
+ else if (!strcasecmp(*v, "use_authtok"))
+ ctrl |= WINBIND_USE_AUTHTOK_ARG;
+ else if (!strcasecmp(*v, "use_first_pass"))
+ ctrl |= WINBIND_USE_FIRST_PASS_ARG;
+ else if (!strcasecmp(*v, "try_first_pass"))
+ ctrl |= WINBIND_TRY_FIRST_PASS_ARG;
+ else if (!strcasecmp(*v, "unknown_ok"))
+ ctrl |= WINBIND_UNKNOWN_OK_ARG;
+ else if (!strncasecmp(*v, "require_membership_of",
+ strlen("require_membership_of")))
+ ctrl |= WINBIND_REQUIRED_MEMBERSHIP;
+ else if (!strncasecmp(*v, "require-membership-of",
+ strlen("require-membership-of")))
+ ctrl |= WINBIND_REQUIRED_MEMBERSHIP;
+ else if (!strcasecmp(*v, "krb5_auth"))
+ ctrl |= WINBIND_KRB5_AUTH;
+ else if (!strncasecmp(*v, "krb5_ccache_type",
+ strlen("krb5_ccache_type")))
+ ctrl |= WINBIND_KRB5_CCACHE_TYPE;
+ else if (!strcasecmp(*v, "cached_login"))
+ ctrl |= WINBIND_CACHED_LOGIN;
+ else {
+ __pam_log(pamh, ctrl, LOG_ERR,
+ "pam_parse: unknown option: %s", *v);
+ return -1;
+ }
+
+ }
+
+ if (result_d) {
+ *result_d = d;
+ } else {
+ if (d) {
+ iniparser_freedict(d);
+ }
+ }
+
+ return ctrl;
+};
+
+static void _pam_winbind_free_context(struct pwb_context *ctx)
+{
+ if (ctx->dict) {
+ iniparser_freedict(ctx->dict);
+ }
+
+ SAFE_FREE(ctx);
+}
+
+static int _pam_winbind_init_context(pam_handle_t *pamh,
+ int flags,
+ int argc,
+ const char **argv,
+ struct pwb_context **ctx_p)
+{
+ struct pwb_context *r = NULL;
+
+ r = (struct pwb_context *)malloc(sizeof(struct pwb_context));
+ if (!r) {
+ return PAM_BUF_ERR;
+ }
+
+ ZERO_STRUCTP(r);
+
+ r->pamh = pamh;
+ r->flags = flags;
+ r->argc = argc;
+ r->argv = argv;
+ r->ctrl = _pam_parse(pamh, flags, argc, argv, &r->dict);
+ if (r->ctrl == -1) {
+ _pam_winbind_free_context(r);
+ return PAM_SYSTEM_ERR;
+ }
+
+ *ctx_p = r;
+
+ return PAM_SUCCESS;
+}
+
+static void _pam_winbind_cleanup_func(pam_handle_t *pamh,
+ void *data,
+ int error_status)
+{
+ int ctrl = _pam_parse(pamh, 0, 0, NULL, NULL);
+ if (_pam_log_is_debug_state_enabled(ctrl)) {
+ __pam_log_debug(pamh, ctrl, LOG_DEBUG,
+ "[pamh: %p] CLEAN: cleaning up PAM data %p "
+ "(error_status = %d)", pamh, data,
+ error_status);
+ }
+ SAFE_FREE(data);
+}
+
+
+static const struct ntstatus_errors {
+ const char *ntstatus_string;
+ const char *error_string;
+} ntstatus_errors[] = {
+ {"NT_STATUS_OK",
+ "Success"},
+ {"NT_STATUS_BACKUP_CONTROLLER",
+ "No primary Domain Controler available"},
+ {"NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND",
+ "No domain controllers found"},
+ {"NT_STATUS_NO_LOGON_SERVERS",
+ "No logon servers"},
+ {"NT_STATUS_PWD_TOO_SHORT",
+ "Password too short"},
+ {"NT_STATUS_PWD_TOO_RECENT",
+ "The password of this user is too recent to change"},
+ {"NT_STATUS_PWD_HISTORY_CONFLICT",
+ "Password is already in password history"},
+ {"NT_STATUS_PASSWORD_EXPIRED",
+ "Your password has expired"},
+ {"NT_STATUS_PASSWORD_MUST_CHANGE",
+ "You need to change your password now"},
+ {"NT_STATUS_INVALID_WORKSTATION",
+ "You are not allowed to logon from this workstation"},
+ {"NT_STATUS_INVALID_LOGON_HOURS",
+ "You are not allowed to logon at this time"},
+ {"NT_STATUS_ACCOUNT_EXPIRED",
+ "Your account has expired. "
+ "Please contact your System administrator"}, /* SCNR */
+ {"NT_STATUS_ACCOUNT_DISABLED",
+ "Your account is disabled. "
+ "Please contact your System administrator"}, /* SCNR */
+ {"NT_STATUS_ACCOUNT_LOCKED_OUT",
+ "Your account has been locked. "
+ "Please contact your System administrator"}, /* SCNR */
+ {"NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT",
+ "Invalid Trust Account"},
+ {"NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT",
+ "Invalid Trust Account"},
+ {"NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT",
+ "Invalid Trust Account"},
+ {"NT_STATUS_ACCESS_DENIED",
+ "Access is denied"},
+ {NULL, NULL}
+};
+
+static const char *_get_ntstatus_error_string(const char *nt_status_string)
+{
+ int i;
+ for (i=0; ntstatus_errors[i].ntstatus_string != NULL; i++) {
+ if (!strcasecmp(ntstatus_errors[i].ntstatus_string,
+ nt_status_string)) {
+ return ntstatus_errors[i].error_string;
+ }
+ }
+ return NULL;
+}
+
+/* --- authentication management functions --- */
+
+/* Attempt a conversation */
+
+static int converse(const pam_handle_t *pamh,
+ int nargs,
+ struct pam_message **message,
+ struct pam_response **response)
+{
+ int retval;
+ struct pam_conv *conv;
+
+ retval = _pam_get_item(pamh, PAM_CONV, &conv);
+ if (retval == PAM_SUCCESS) {
+ retval = conv->conv(nargs,
+ (const struct pam_message **)message,
+ response, conv->appdata_ptr);
+ }
+
+ return retval; /* propagate error status */
+}
+
+
+static int _make_remark(struct pwb_context *ctx,
+ int type,
+ const char *text)
+{
+ int retval = PAM_SUCCESS;
+
+ struct pam_message *pmsg[1], msg[1];
+ struct pam_response *resp;
+
+ if (ctx->flags & WINBIND_SILENT) {
+ return PAM_SUCCESS;
+ }
+
+ pmsg[0] = &msg[0];
+ msg[0].msg = discard_const_p(char, text);
+ msg[0].msg_style = type;
+
+ resp = NULL;
+ retval = converse(ctx->pamh, 1, pmsg, &resp);
+
+ if (resp) {
+ _pam_drop_reply(resp, 1);
+ }
+ return retval;
+}
+
+static int _make_remark_v(struct pwb_context *ctx,
+ int type,
+ const char *format,
+ va_list args)
+{
+ char *var;
+ int ret;
+
+ ret = vasprintf(&var, format, args);
+ if (ret < 0) {
+ _pam_log(ctx, LOG_ERR, "memory allocation failure");
+ return ret;
+ }
+
+ ret = _make_remark(ctx, type, var);
+ SAFE_FREE(var);
+ return ret;
+}
+
+static int _make_remark_format(struct pwb_context *ctx, int type, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+static int _make_remark_format(struct pwb_context *ctx, int type, const char *format, ...)
+{
+ int ret;
+ va_list args;
+
+ va_start(args, format);
+ ret = _make_remark_v(ctx, type, format, args);
+ va_end(args);
+ return ret;
+}
+
+static int pam_winbind_request(struct pwb_context *ctx,
+ enum winbindd_cmd req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response)
+{
+ /* Fill in request and send down pipe */
+ winbindd_init_request(request, req_type);
+
+ if (winbind_write_sock(request, sizeof(*request), 0, 0) == -1) {
+ _pam_log(ctx, LOG_ERR,
+ "pam_winbind_request: write to socket failed!");
+ winbind_close_sock();
+ return PAM_SERVICE_ERR;
+ }
+
+ /* Wait for reply */
+ if (winbindd_read_reply(response) == -1) {
+ _pam_log(ctx, LOG_ERR,
+ "pam_winbind_request: read from socket failed!");
+ winbind_close_sock();
+ return PAM_SERVICE_ERR;
+ }
+
+ /* We are done with the socket - close it and avoid mischeif */
+ winbind_close_sock();
+
+ /* Copy reply data from socket */
+ if (response->result == WINBINDD_OK) {
+ return PAM_SUCCESS;
+ }
+
+ /* no need to check for pam_error codes for getpwnam() */
+ switch (req_type) {
+
+ case WINBINDD_GETPWNAM:
+ case WINBINDD_LOOKUPNAME:
+ if (strlen(response->data.auth.nt_status_string) > 0) {
+ _pam_log(ctx, LOG_ERR,
+ "request failed, NT error was %s",
+ response->data.auth.nt_status_string);
+ } else {
+ _pam_log(ctx, LOG_ERR, "request failed");
+ }
+ return PAM_USER_UNKNOWN;
+ default:
+ break;
+ }
+
+ if (response->data.auth.pam_error != PAM_SUCCESS) {
+ _pam_log(ctx, LOG_ERR,
+ "request failed: %s, "
+ "PAM error was %s (%d), NT error was %s",
+ response->data.auth.error_string,
+ pam_strerror(ctx->pamh, response->data.auth.pam_error),
+ response->data.auth.pam_error,
+ response->data.auth.nt_status_string);
+ return response->data.auth.pam_error;
+ }
+
+ _pam_log(ctx, LOG_ERR, "request failed, but PAM error 0!");
+
+ return PAM_SERVICE_ERR;
+}
+
+static int pam_winbind_request_log(struct pwb_context *ctx,
+ enum winbindd_cmd req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response,
+ const char *user)
+{
+ int retval;
+
+ retval = pam_winbind_request(ctx, req_type, request, response);
+
+ switch (retval) {
+ case PAM_AUTH_ERR:
+ /* incorrect password */
+ _pam_log(ctx, LOG_WARNING, "user '%s' denied access "
+ "(incorrect password or invalid membership)", user);
+ return retval;
+ case PAM_ACCT_EXPIRED:
+ /* account expired */
+ _pam_log(ctx, LOG_WARNING, "user '%s' account expired",
+ user);
+ return retval;
+ case PAM_AUTHTOK_EXPIRED:
+ /* password expired */
+ _pam_log(ctx, LOG_WARNING, "user '%s' password expired",
+ user);
+ return retval;
+ case PAM_NEW_AUTHTOK_REQD:
+ /* new password required */
+ _pam_log(ctx, LOG_WARNING, "user '%s' new password "
+ "required", user);
+ return retval;
+ case PAM_USER_UNKNOWN:
+ /* the user does not exist */
+ _pam_log_debug(ctx, LOG_NOTICE, "user '%s' not found",
+ user);
+ if (ctx->ctrl & WINBIND_UNKNOWN_OK_ARG) {
+ return PAM_IGNORE;
+ }
+ return retval;
+ case PAM_SUCCESS:
+ /* Otherwise, the authentication looked good */
+ switch (req_type) {
+ case WINBINDD_INFO:
+ break;
+ case WINBINDD_PAM_AUTH:
+ _pam_log(ctx, LOG_NOTICE,
+ "user '%s' granted access", user);
+ break;
+ case WINBINDD_PAM_CHAUTHTOK:
+ _pam_log(ctx, LOG_NOTICE,
+ "user '%s' password changed", user);
+ break;
+ default:
+ _pam_log(ctx, LOG_NOTICE,
+ "user '%s' OK", user);
+ break;
+ }
+
+ return retval;
+ default:
+ /* we don't know anything about this return value */
+ _pam_log(ctx, LOG_ERR,
+ "internal module error (retval = %d, user = '%s')",
+ retval, user);
+ return retval;
+ }
+}
+
+/**
+ * send a password expiry message if required
+ *
+ * @param ctx PAM winbind context.
+ * @param next_change expected (calculated) next expiry date.
+ * @param already_expired pointer to a boolean to indicate if the password is
+ * already expired.
+ *
+ * @return boolean Returns true if message has been sent, false if not.
+ */
+
+static bool _pam_send_password_expiry_message(struct pwb_context *ctx,
+ time_t next_change,
+ time_t now,
+ int warn_pwd_expire,
+ bool *already_expired)
+{
+ int days = 0;
+ struct tm tm_now, tm_next_change;
+
+ if (already_expired) {
+ *already_expired = false;
+ }
+
+ if (next_change <= now) {
+ PAM_WB_REMARK_DIRECT(ctx, "NT_STATUS_PASSWORD_EXPIRED");
+ if (already_expired) {
+ *already_expired = true;
+ }
+ return true;
+ }
+
+ if ((next_change < 0) ||
+ (next_change > now + warn_pwd_expire * SECONDS_PER_DAY)) {
+ return false;
+ }
+
+ if ((localtime_r(&now, &tm_now) == NULL) ||
+ (localtime_r(&next_change, &tm_next_change) == NULL)) {
+ return false;
+ }
+
+ days = (tm_next_change.tm_yday+tm_next_change.tm_year*365) -
+ (tm_now.tm_yday+tm_now.tm_year*365);
+
+ if (days == 0) {
+ _make_remark(ctx, PAM_TEXT_INFO,
+ "Your password expires today");
+ return true;
+ }
+
+ if (days > 0 && days < warn_pwd_expire) {
+ _make_remark_format(ctx, PAM_TEXT_INFO,
+ "Your password will expire in %d %s",
+ days, (days > 1) ? "days":"day");
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Send a warning if the password expires in the near future
+ *
+ * @param ctx PAM winbind context.
+ * @param response The full authentication response structure.
+ * @param already_expired boolean, is the pwd already expired?
+ *
+ * @return void.
+ */
+
+static void _pam_warn_password_expiry(struct pwb_context *ctx,
+ const struct winbindd_response *response,
+ int warn_pwd_expire,
+ bool *already_expired)
+{
+ time_t now = time(NULL);
+ time_t next_change = 0;
+
+ if (already_expired) {
+ *already_expired = false;
+ }
+
+ /* accounts with ACB_PWNOEXP set never receive a warning */
+ if (response->data.auth.info3.acct_flags & ACB_PWNOEXP) {
+ return;
+ }
+
+ /* no point in sending a warning if this is a grace logon */
+ if (PAM_WB_GRACE_LOGON(response->data.auth.info3.user_flgs)) {
+ return;
+ }
+
+ /* check if the info3 must change timestamp has been set */
+ next_change = response->data.auth.info3.pass_must_change_time;
+
+ if (_pam_send_password_expiry_message(ctx, next_change, now,
+ warn_pwd_expire,
+ already_expired)) {
+ return;
+ }
+
+ /* now check for the global password policy */
+ /* good catch from Ralf Haferkamp: an expiry of "never" is translated
+ * to -1 */
+ if (response->data.auth.policy.expire <= 0) {
+ return;
+ }
+
+ next_change = response->data.auth.info3.pass_last_set_time +
+ response->data.auth.policy.expire;
+
+ if (_pam_send_password_expiry_message(ctx, next_change, now,
+ warn_pwd_expire,
+ already_expired)) {
+ return;
+ }
+
+ /* no warning sent */
+}
+
+#define IS_SID_STRING(name) (strncmp("S-", name, 2) == 0)
+
+/**
+ * Append a string, making sure not to overflow and to always return a
+ * NULL-terminated string.
+ *
+ * @param dest Destination string buffer (must already be NULL-terminated).
+ * @param src Source string buffer.
+ * @param dest_buffer_size Size of dest buffer in bytes.
+ *
+ * @return false if dest buffer is not big enough (no bytes copied), true on
+ * success.
+ */
+
+static bool safe_append_string(char *dest,
+ const char *src,
+ int dest_buffer_size)
+{
+ int dest_length = strlen(dest);
+ int src_length = strlen(src);
+
+ if (dest_length + src_length + 1 > dest_buffer_size) {
+ return false;
+ }
+
+ memcpy(dest + dest_length, src, src_length + 1);
+ return true;
+}
+
+/**
+ * Convert a names into a SID string, appending it to a buffer.
+ *
+ * @param ctx PAM winbind context.
+ * @param user User in PAM request.
+ * @param name Name to convert.
+ * @param sid_list_buffer Where to append the string sid.
+ * @param sid_list_buffer Size of sid_list_buffer (in bytes).
+ *
+ * @return false on failure, true on success.
+ */
+static bool winbind_name_to_sid_string(struct pwb_context *ctx,
+ const char *user,
+ const char *name,
+ char *sid_list_buffer,
+ int sid_list_buffer_size)
+{
+ const char* sid_string;
+ struct winbindd_response sid_response;
+
+ /* lookup name? */
+ if (IS_SID_STRING(name)) {
+ sid_string = name;
+ } else {
+ struct winbindd_request sid_request;
+
+ ZERO_STRUCT(sid_request);
+ ZERO_STRUCT(sid_response);
+
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "no sid given, looking up: %s\n", name);
+
+ /* fortunatly winbindd can handle non-separated names */
+ strncpy(sid_request.data.name.name, name,
+ sizeof(sid_request.data.name.name) - 1);
+
+ if (pam_winbind_request_log(ctx, WINBINDD_LOOKUPNAME,
+ &sid_request, &sid_response,
+ user)) {
+ _pam_log(ctx, LOG_INFO,
+ "could not lookup name: %s\n", name);
+ return false;
+ }
+
+ sid_string = sid_response.data.sid.sid;
+ }
+
+ if (!safe_append_string(sid_list_buffer, sid_string,
+ sid_list_buffer_size)) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Convert a list of names into a list of sids.
+ *
+ * @param ctx PAM winbind context.
+ * @param user User in PAM request.
+ * @param name_list List of names or string sids, separated by commas.
+ * @param sid_list_buffer Where to put the list of string sids.
+ * @param sid_list_buffer Size of sid_list_buffer (in bytes).
+ *
+ * @return false on failure, true on success.
+ */
+static bool winbind_name_list_to_sid_string_list(struct pwb_context *ctx,
+ const char *user,
+ const char *name_list,
+ char *sid_list_buffer,
+ int sid_list_buffer_size)
+{
+ bool result = false;
+ char *current_name = NULL;
+ const char *search_location;
+ const char *comma;
+
+ if (sid_list_buffer_size > 0) {
+ sid_list_buffer[0] = 0;
+ }
+
+ search_location = name_list;
+ while ((comma = strstr(search_location, ",")) != NULL) {
+ current_name = strndup(search_location,
+ comma - search_location);
+ if (NULL == current_name) {
+ goto out;
+ }
+
+ if (!winbind_name_to_sid_string(ctx, user,
+ current_name,
+ sid_list_buffer,
+ sid_list_buffer_size)) {
+ goto out;
+ }
+
+ SAFE_FREE(current_name);
+
+ if (!safe_append_string(sid_list_buffer, ",",
+ sid_list_buffer_size)) {
+ goto out;
+ }
+
+ search_location = comma + 1;
+ }
+
+ if (!winbind_name_to_sid_string(ctx, user, search_location,
+ sid_list_buffer,
+ sid_list_buffer_size)) {
+ goto out;
+ }
+
+ result = true;
+
+out:
+ SAFE_FREE(current_name);
+ return result;
+}
+
+/**
+ * put krb5ccname variable into environment
+ *
+ * @param ctx PAM winbind context.
+ * @param krb5ccname env variable retrieved from winbindd.
+ *
+ * @return void.
+ */
+
+static void _pam_setup_krb5_env(struct pwb_context *ctx,
+ const char *krb5ccname)
+{
+ char var[PATH_MAX];
+ int ret;
+
+ if (off(ctx->ctrl, WINBIND_KRB5_AUTH)) {
+ return;
+ }
+
+ if (!krb5ccname || (strlen(krb5ccname) == 0)) {
+ return;
+ }
+
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "request returned KRB5CCNAME: %s", krb5ccname);
+
+ if (snprintf(var, sizeof(var), "KRB5CCNAME=%s", krb5ccname) == -1) {
+ return;
+ }
+
+ ret = pam_putenv(ctx->pamh, var);
+ if (ret) {
+ _pam_log(ctx, LOG_ERR,
+ "failed to set KRB5CCNAME to %s: %s",
+ var, pam_strerror(ctx->pamh, ret));
+ }
+}
+
+/**
+ * Set string into the PAM stack.
+ *
+ * @param ctx PAM winbind context.
+ * @param data_name Key name for pam_set_data.
+ * @param value String value.
+ *
+ * @return void.
+ */
+
+static void _pam_set_data_string(struct pwb_context *ctx,
+ const char *data_name,
+ const char *value)
+{
+ int ret;
+
+ if (!data_name || !value || (strlen(data_name) == 0) ||
+ (strlen(value) == 0)) {
+ return;
+ }
+
+ ret = pam_set_data(ctx->pamh, data_name, (void *)strdup(value),
+ _pam_winbind_cleanup_func);
+ if (ret) {
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "Could not set data %s: %s\n",
+ data_name, pam_strerror(ctx->pamh, ret));
+ }
+
+}
+
+/**
+ * Set info3 strings into the PAM stack.
+ *
+ * @param ctx PAM winbind context.
+ * @param data_name Key name for pam_set_data.
+ * @param value String value.
+ *
+ * @return void.
+ */
+
+static void _pam_set_data_info3(struct pwb_context *ctx,
+ struct winbindd_response *response)
+{
+ _pam_set_data_string(ctx, PAM_WINBIND_HOMEDIR,
+ response->data.auth.info3.home_dir);
+ _pam_set_data_string(ctx, PAM_WINBIND_LOGONSCRIPT,
+ response->data.auth.info3.logon_script);
+ _pam_set_data_string(ctx, PAM_WINBIND_LOGONSERVER,
+ response->data.auth.info3.logon_srv);
+ _pam_set_data_string(ctx, PAM_WINBIND_PROFILEPATH,
+ response->data.auth.info3.profile_path);
+}
+
+/**
+ * Free info3 strings in the PAM stack.
+ *
+ * @param pamh PAM handle
+ *
+ * @return void.
+ */
+
+static void _pam_free_data_info3(pam_handle_t *pamh)
+{
+ pam_set_data(pamh, PAM_WINBIND_HOMEDIR, NULL, NULL);
+ pam_set_data(pamh, PAM_WINBIND_LOGONSCRIPT, NULL, NULL);
+ pam_set_data(pamh, PAM_WINBIND_LOGONSERVER, NULL, NULL);
+ pam_set_data(pamh, PAM_WINBIND_PROFILEPATH, NULL, NULL);
+}
+
+/**
+ * Send PAM_ERROR_MSG for cached or grace logons.
+ *
+ * @param ctx PAM winbind context.
+ * @param username User in PAM request.
+ * @param info3_user_flgs Info3 flags containing logon type bits.
+ *
+ * @return void.
+ */
+
+static void _pam_warn_logon_type(struct pwb_context *ctx,
+ const char *username,
+ uint32_t info3_user_flgs)
+{
+ /* inform about logon type */
+ if (PAM_WB_GRACE_LOGON(info3_user_flgs)) {
+
+ _make_remark(ctx, PAM_ERROR_MSG,
+ "Grace login. "
+ "Please change your password as soon you're "
+ "online again");
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "User %s logged on using grace logon\n",
+ username);
+
+ } else if (PAM_WB_CACHED_LOGON(info3_user_flgs)) {
+
+ _make_remark(ctx, PAM_ERROR_MSG,
+ "Domain Controller unreachable, "
+ "using cached credentials instead. "
+ "Network resources may be unavailable");
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "User %s logged on using cached credentials\n",
+ username);
+ }
+}
+
+/**
+ * Send PAM_ERROR_MSG for krb5 errors.
+ *
+ * @param ctx PAM winbind context.
+ * @param username User in PAM request.
+ * @param info3_user_flgs Info3 flags containing logon type bits.
+ *
+ * @return void.
+ */
+
+static void _pam_warn_krb5_failure(struct pwb_context *ctx,
+ const char *username,
+ uint32_t info3_user_flgs)
+{
+ if (PAM_WB_KRB5_CLOCK_SKEW(info3_user_flgs)) {
+ _make_remark(ctx, PAM_ERROR_MSG,
+ "Failed to establish your Kerberos Ticket cache "
+ "due time differences\n"
+ "with the domain controller. "
+ "Please verify the system time.\n");
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "User %s: Clock skew when getting Krb5 TGT\n",
+ username);
+ }
+}
+
+/**
+ * Compose Password Restriction String for a PAM_ERROR_MSG conversation.
+ *
+ * @param response The struct winbindd_response.
+ *
+ * @return string (caller needs to free).
+ */
+
+static char *_pam_compose_pwd_restriction_string(struct winbindd_response *response)
+{
+ char *str = NULL;
+ size_t offset = 0, ret = 0, str_size = 1024;
+
+ str = (char *)malloc(str_size);
+ if (!str) {
+ return NULL;
+ }
+
+ memset(str, '\0', str_size);
+
+ offset = snprintf(str, str_size, "Your password ");
+ if (offset == -1) {
+ goto failed;
+ }
+
+ if (response->data.auth.policy.min_length_password > 0) {
+ ret = snprintf(str+offset, str_size-offset,
+ "must be at least %d characters; ",
+ response->data.auth.policy.min_length_password);
+ if (ret == -1) {
+ goto failed;
+ }
+ offset += ret;
+ }
+
+ if (response->data.auth.policy.password_history > 0) {
+ ret = snprintf(str+offset, str_size-offset,
+ "cannot repeat any of your previous %d "
+ "passwords; ",
+ response->data.auth.policy.password_history);
+ if (ret == -1) {
+ goto failed;
+ }
+ offset += ret;
+ }
+
+ if (response->data.auth.policy.password_properties &
+ DOMAIN_PASSWORD_COMPLEX) {
+ ret = snprintf(str+offset, str_size-offset,
+ "must contain capitals, numerals "
+ "or punctuation; "
+ "and cannot contain your account "
+ "or full name; ");
+ if (ret == -1) {
+ goto failed;
+ }
+ offset += ret;
+ }
+
+ ret = snprintf(str+offset, str_size-offset,
+ "Please type a different password. "
+ "Type a password which meets these requirements in "
+ "both text boxes.");
+ if (ret == -1) {
+ goto failed;
+ }
+
+ return str;
+
+ failed:
+ SAFE_FREE(str);
+ return NULL;
+}
+
+/* talk to winbindd */
+static int winbind_auth_request(struct pwb_context *ctx,
+ const char *user,
+ const char *pass,
+ const char *member,
+ const char *cctype,
+ const int warn_pwd_expire,
+ struct winbindd_response *p_response,
+ time_t *pwd_last_set,
+ char **user_ret)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int ret;
+ bool already_expired = false;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if (pwd_last_set) {
+ *pwd_last_set = 0;
+ }
+
+ strncpy(request.data.auth.user, user,
+ sizeof(request.data.auth.user)-1);
+
+ strncpy(request.data.auth.pass, pass,
+ sizeof(request.data.auth.pass)-1);
+
+ request.data.auth.krb5_cc_type[0] = '\0';
+ request.data.auth.uid = -1;
+
+ request.flags = WBFLAG_PAM_INFO3_TEXT | WBFLAG_PAM_GET_PWD_POLICY;
+
+ /* Krb5 auth always has to go against the KDC of the user's realm */
+
+ if (ctx->ctrl & WINBIND_KRB5_AUTH) {
+ request.flags |= WBFLAG_PAM_CONTACT_TRUSTDOM;
+ }
+
+ if (ctx->ctrl & (WINBIND_KRB5_AUTH|WINBIND_CACHED_LOGIN)) {
+ struct passwd *pwd = NULL;
+
+ pwd = getpwnam(user);
+ if (pwd == NULL) {
+ return PAM_USER_UNKNOWN;
+ }
+ request.data.auth.uid = pwd->pw_uid;
+ }
+
+ if (ctx->ctrl & WINBIND_KRB5_AUTH) {
+
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "enabling krb5 login flag\n");
+
+ request.flags |= WBFLAG_PAM_KRB5 |
+ WBFLAG_PAM_FALLBACK_AFTER_KRB5;
+ }
+
+ if (ctx->ctrl & WINBIND_CACHED_LOGIN) {
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "enabling cached login flag\n");
+ request.flags |= WBFLAG_PAM_CACHED_LOGIN;
+ }
+
+ if (user_ret) {
+ *user_ret = NULL;
+ request.flags |= WBFLAG_PAM_UNIX_NAME;
+ }
+
+ if (cctype != NULL) {
+ strncpy(request.data.auth.krb5_cc_type, cctype,
+ sizeof(request.data.auth.krb5_cc_type) - 1);
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "enabling request for a %s krb5 ccache\n",
+ cctype);
+ }
+
+ request.data.auth.require_membership_of_sid[0] = '\0';
+
+ if (member != NULL) {
+
+ if (!winbind_name_list_to_sid_string_list(ctx, user,
+ member,
+ request.data.auth.require_membership_of_sid,
+ sizeof(request.data.auth.require_membership_of_sid))) {
+
+ _pam_log_debug(ctx, LOG_ERR,
+ "failed to serialize membership of sid "
+ "\"%s\"\n", member);
+ return PAM_AUTH_ERR;
+ }
+ }
+
+ ret = pam_winbind_request_log(ctx, WINBINDD_PAM_AUTH,
+ &request, &response, user);
+
+ if (pwd_last_set) {
+ *pwd_last_set = response.data.auth.info3.pass_last_set_time;
+ }
+
+ if (p_response) {
+ /* We want to process the response in the caller. */
+ *p_response = response;
+ return ret;
+ }
+
+ if (ret) {
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_PASSWORD_EXPIRED");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_PASSWORD_MUST_CHANGE");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_INVALID_WORKSTATION");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_INVALID_LOGON_HOURS");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_ACCOUNT_EXPIRED");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_ACCOUNT_DISABLED");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_ACCOUNT_LOCKED_OUT");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_NO_LOGON_SERVERS");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_WRONG_PASSWORD");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_ACCESS_DENIED");
+ }
+
+ if (ret == PAM_SUCCESS) {
+
+ /* warn a user if the password is about to expire soon */
+ _pam_warn_password_expiry(ctx, &response,
+ warn_pwd_expire,
+ &already_expired);
+
+ if (already_expired == true) {
+ SMB_TIME_T last_set;
+ last_set = response.data.auth.info3.pass_last_set_time;
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "Password has expired "
+ "(Password was last set: %lld, "
+ "the policy says it should expire here "
+ "%lld (now it's: %lu))\n",
+ (long long int)last_set,
+ (long long int)last_set +
+ response.data.auth.policy.expire,
+ time(NULL));
+
+ return PAM_AUTHTOK_EXPIRED;
+ }
+
+ /* inform about logon type */
+ _pam_warn_logon_type(ctx, user,
+ response.data.auth.info3.user_flgs);
+
+ /* inform about krb5 failures */
+ _pam_warn_krb5_failure(ctx, user,
+ response.data.auth.info3.user_flgs);
+
+ /* set some info3 info for other modules in the stack */
+ _pam_set_data_info3(ctx, &response);
+
+ /* put krb5ccname into env */
+ _pam_setup_krb5_env(ctx, response.data.auth.krb5ccname);
+
+ /* If winbindd returned a username, return the pointer to it
+ * here. */
+ if (user_ret && response.data.auth.unix_username[0]) {
+ /* We have to trust it's a null terminated string. */
+ *user_ret = strndup(response.data.auth.unix_username,
+ sizeof(response.data.auth.unix_username) - 1);
+ }
+ }
+
+ return ret;
+}
+
+/* talk to winbindd */
+static int winbind_chauthtok_request(struct pwb_context *ctx,
+ const char *user,
+ const char *oldpass,
+ const char *newpass,
+ time_t pwd_last_set)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int ret;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if (request.data.chauthtok.user == NULL) {
+ return -2;
+ }
+
+ strncpy(request.data.chauthtok.user, user,
+ sizeof(request.data.chauthtok.user) - 1);
+
+ if (oldpass != NULL) {
+ strncpy(request.data.chauthtok.oldpass, oldpass,
+ sizeof(request.data.chauthtok.oldpass) - 1);
+ } else {
+ request.data.chauthtok.oldpass[0] = '\0';
+ }
+
+ if (newpass != NULL) {
+ strncpy(request.data.chauthtok.newpass, newpass,
+ sizeof(request.data.chauthtok.newpass) - 1);
+ } else {
+ request.data.chauthtok.newpass[0] = '\0';
+ }
+
+ if (ctx->ctrl & WINBIND_KRB5_AUTH) {
+ request.flags = WBFLAG_PAM_KRB5 |
+ WBFLAG_PAM_CONTACT_TRUSTDOM;
+ }
+
+ if (ctx->ctrl & WINBIND_CACHED_LOGIN) {
+ request.flags |= WBFLAG_PAM_CACHED_LOGIN;
+ }
+
+ ret = pam_winbind_request_log(ctx, WINBINDD_PAM_CHAUTHTOK,
+ &request, &response, user);
+
+ if (ret == PAM_SUCCESS) {
+ return ret;
+ }
+
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_BACKUP_CONTROLLER");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_NO_LOGON_SERVERS");
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_ACCESS_DENIED");
+
+ /* TODO: tell the min pwd length ? */
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_PWD_TOO_SHORT");
+
+ /* TODO: tell the minage ? */
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_PWD_TOO_RECENT");
+
+ /* TODO: tell the history length ? */
+ PAM_WB_REMARK_CHECK_RESPONSE_RET(ctx, response,
+ "NT_STATUS_PWD_HISTORY_CONFLICT");
+
+ if (!strcasecmp(response.data.auth.nt_status_string,
+ "NT_STATUS_PASSWORD_RESTRICTION")) {
+
+ char *pwd_restriction_string = NULL;
+ SMB_TIME_T min_pwd_age;
+ uint32_t reject_reason = response.data.auth.reject_reason;
+ min_pwd_age = response.data.auth.policy.min_passwordage;
+
+ /* FIXME: avoid to send multiple PAM messages after another */
+ switch (reject_reason) {
+ case -1:
+ break;
+ case SAMR_REJECT_OTHER:
+ if ((min_pwd_age > 0) &&
+ (pwd_last_set + min_pwd_age > time(NULL))) {
+ PAM_WB_REMARK_DIRECT(ctx,
+ "NT_STATUS_PWD_TOO_RECENT");
+ }
+ break;
+ case SAMR_REJECT_TOO_SHORT:
+ PAM_WB_REMARK_DIRECT(ctx,
+ "NT_STATUS_PWD_TOO_SHORT");
+ break;
+ case SAMR_REJECT_IN_HISTORY:
+ PAM_WB_REMARK_DIRECT(ctx,
+ "NT_STATUS_PWD_HISTORY_CONFLICT");
+ break;
+ case SAMR_REJECT_COMPLEXITY:
+ _make_remark(ctx, PAM_ERROR_MSG,
+ "Password does not meet "
+ "complexity requirements");
+ break;
+ default:
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "unknown password change "
+ "reject reason: %d",
+ reject_reason);
+ break;
+ }
+
+ pwd_restriction_string =
+ _pam_compose_pwd_restriction_string(&response);
+ if (pwd_restriction_string) {
+ _make_remark(ctx, PAM_ERROR_MSG,
+ pwd_restriction_string);
+ SAFE_FREE(pwd_restriction_string);
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Checks if a user has an account
+ *
+ * return values:
+ * 1 = User not found
+ * 0 = OK
+ * -1 = System error
+ */
+static int valid_user(struct pwb_context *ctx,
+ const char *user)
+{
+ /* check not only if the user is available over NSS calls, also make
+ * sure it's really a winbind user, this is important when stacking PAM
+ * modules in the 'account' or 'password' facility. */
+
+ struct passwd *pwd = NULL;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int ret;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ pwd = getpwnam(user);
+ if (pwd == NULL) {
+ return 1;
+ }
+
+ strncpy(request.data.username, user,
+ sizeof(request.data.username) - 1);
+
+ ret = pam_winbind_request_log(ctx, WINBINDD_GETPWNAM,
+ &request, &response, user);
+
+ switch (ret) {
+ case PAM_USER_UNKNOWN:
+ return 1;
+ case PAM_SUCCESS:
+ return 0;
+ default:
+ break;
+ }
+ return -1;
+}
+
+static char *_pam_delete(register char *xx)
+{
+ _pam_overwrite(xx);
+ _pam_drop(xx);
+ return NULL;
+}
+
+/*
+ * obtain a password from the user
+ */
+
+static int _winbind_read_password(struct pwb_context *ctx,
+ unsigned int ctrl,
+ const char *comment,
+ const char *prompt1,
+ const char *prompt2,
+ const char **pass)
+{
+ int authtok_flag;
+ int retval;
+ const char *item;
+ char *token;
+
+ _pam_log(ctx, LOG_DEBUG, "getting password (0x%08x)", ctrl);
+
+ /*
+ * make sure nothing inappropriate gets returned
+ */
+
+ *pass = token = NULL;
+
+ /*
+ * which authentication token are we getting?
+ */
+
+ if (on(WINBIND__OLD_PASSWORD, ctrl)) {
+ authtok_flag = PAM_OLDAUTHTOK;
+ } else {
+ authtok_flag = PAM_AUTHTOK;
+ }
+
+ /*
+ * should we obtain the password from a PAM item ?
+ */
+
+ if (on(WINBIND_TRY_FIRST_PASS_ARG, ctrl) ||
+ on(WINBIND_USE_FIRST_PASS_ARG, ctrl)) {
+ retval = _pam_get_item(ctx->pamh, authtok_flag, &item);
+ if (retval != PAM_SUCCESS) {
+ /* very strange. */
+ _pam_log(ctx, LOG_ALERT,
+ "pam_get_item returned error "
+ "to unix-read-password");
+ return retval;
+ } else if (item != NULL) { /* we have a password! */
+ *pass = item;
+ item = NULL;
+ _pam_log(ctx, LOG_DEBUG,
+ "pam_get_item returned a password");
+ return PAM_SUCCESS;
+ } else if (on(WINBIND_USE_FIRST_PASS_ARG, ctrl)) {
+ return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */
+ } else if (on(WINBIND_USE_AUTHTOK_ARG, ctrl)
+ && off(WINBIND__OLD_PASSWORD, ctrl)) {
+ return PAM_AUTHTOK_RECOVER_ERR;
+ }
+ }
+ /*
+ * getting here implies we will have to get the password from the
+ * user directly.
+ */
+
+ {
+ struct pam_message msg[3], *pmsg[3];
+ struct pam_response *resp;
+ int i, replies;
+
+ /* prepare to converse */
+
+ if (comment != NULL && off(ctrl, WINBIND_SILENT)) {
+ pmsg[0] = &msg[0];
+ msg[0].msg_style = PAM_TEXT_INFO;
+ msg[0].msg = discard_const_p(char, comment);
+ i = 1;
+ } else {
+ i = 0;
+ }
+
+ pmsg[i] = &msg[i];
+ msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[i++].msg = discard_const_p(char, prompt1);
+ replies = 1;
+
+ if (prompt2 != NULL) {
+ pmsg[i] = &msg[i];
+ msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[i++].msg = discard_const_p(char, prompt2);
+ ++replies;
+ }
+ /* so call the conversation expecting i responses */
+ resp = NULL;
+ retval = converse(ctx->pamh, i, pmsg, &resp);
+ if (resp == NULL) {
+ if (retval == PAM_SUCCESS) {
+ retval = PAM_AUTHTOK_RECOVER_ERR;
+ }
+ goto done;
+ }
+ if (retval != PAM_SUCCESS) {
+ _pam_drop_reply(resp, i);
+ goto done;
+ }
+
+ /* interpret the response */
+
+ token = x_strdup(resp[i - replies].resp);
+ if (!token) {
+ _pam_log(ctx, LOG_NOTICE,
+ "could not recover "
+ "authentication token");
+ retval = PAM_AUTHTOK_RECOVER_ERR;
+ goto done;
+ }
+
+ if (replies == 2) {
+ /* verify that password entered correctly */
+ if (!resp[i - 1].resp ||
+ strcmp(token, resp[i - 1].resp)) {
+ _pam_delete(token); /* mistyped */
+ retval = PAM_AUTHTOK_RECOVER_ERR;
+ _make_remark(ctx, PAM_ERROR_MSG,
+ MISTYPED_PASS);
+ }
+ }
+
+ /*
+ * tidy up the conversation (resp_retcode) is ignored
+ * -- what is it for anyway? AGM
+ */
+ _pam_drop_reply(resp, i);
+ }
+
+ done:
+ if (retval != PAM_SUCCESS) {
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "unable to obtain a password");
+ return retval;
+ }
+ /* 'token' is the entered password */
+
+ /* we store this password as an item */
+
+ retval = pam_set_item(ctx->pamh, authtok_flag, token);
+ _pam_delete(token); /* clean it up */
+ if (retval != PAM_SUCCESS ||
+ (retval = _pam_get_item(ctx->pamh, authtok_flag, &item)) != PAM_SUCCESS) {
+
+ _pam_log(ctx, LOG_CRIT, "error manipulating password");
+ return retval;
+
+ }
+
+ *pass = item;
+ item = NULL; /* break link to password */
+
+ return PAM_SUCCESS;
+}
+
+static const char *get_conf_item_string(struct pwb_context *ctx,
+ const char *item,
+ int config_flag)
+{
+ int i = 0;
+ const char *parm_opt = NULL;
+
+ if (!(ctx->ctrl & config_flag)) {
+ goto out;
+ }
+
+ /* let the pam opt take precedence over the pam_winbind.conf option */
+ for (i=0; i<ctx->argc; i++) {
+
+ if ((strncmp(ctx->argv[i], item, strlen(item)) == 0)) {
+ char *p;
+
+ if ((p = strchr(ctx->argv[i], '=')) == NULL) {
+ _pam_log(ctx, LOG_INFO,
+ "no \"=\" delimiter for \"%s\" found\n",
+ item);
+ goto out;
+ }
+ _pam_log_debug(ctx, LOG_INFO,
+ "PAM config: %s '%s'\n", item, p+1);
+ return p + 1;
+ }
+ }
+
+ if (ctx->dict) {
+ char *key = NULL;
+
+ if (!asprintf(&key, "global:%s", item)) {
+ goto out;
+ }
+
+ parm_opt = iniparser_getstr(ctx->dict, key);
+ SAFE_FREE(key);
+
+ _pam_log_debug(ctx, LOG_INFO, "CONFIG file: %s '%s'\n",
+ item, parm_opt);
+ }
+out:
+ return parm_opt;
+}
+
+static int get_config_item_int(struct pwb_context *ctx,
+ const char *item,
+ int config_flag)
+{
+ int i, parm_opt = -1;
+
+ if (!(ctx->ctrl & config_flag)) {
+ goto out;
+ }
+
+ /* let the pam opt take precedence over the pam_winbind.conf option */
+ for (i = 0; i < ctx->argc; i++) {
+
+ if ((strncmp(ctx->argv[i], item, strlen(item)) == 0)) {
+ char *p;
+
+ if ((p = strchr(ctx->argv[i], '=')) == NULL) {
+ _pam_log(ctx, LOG_INFO,
+ "no \"=\" delimiter for \"%s\" found\n",
+ item);
+ goto out;
+ }
+ parm_opt = atoi(p + 1);
+ _pam_log_debug(ctx, LOG_INFO,
+ "PAM config: %s '%d'\n",
+ item, parm_opt);
+ return parm_opt;
+ }
+ }
+
+ if (ctx->dict) {
+ char *key = NULL;
+
+ if (!asprintf(&key, "global:%s", item)) {
+ goto out;
+ }
+
+ parm_opt = iniparser_getint(ctx->dict, key, -1);
+ SAFE_FREE(key);
+
+ _pam_log_debug(ctx, LOG_INFO,
+ "CONFIG file: %s '%d'\n",
+ item, parm_opt);
+ }
+out:
+ return parm_opt;
+}
+
+static const char *get_krb5_cc_type_from_config(struct pwb_context *ctx)
+{
+ return get_conf_item_string(ctx, "krb5_ccache_type",
+ WINBIND_KRB5_CCACHE_TYPE);
+}
+
+static const char *get_member_from_config(struct pwb_context *ctx)
+{
+ const char *ret = NULL;
+ ret = get_conf_item_string(ctx, "require_membership_of",
+ WINBIND_REQUIRED_MEMBERSHIP);
+ if (ret) {
+ return ret;
+ }
+ return get_conf_item_string(ctx, "require-membership-of",
+ WINBIND_REQUIRED_MEMBERSHIP);
+}
+
+static int get_warn_pwd_expire_from_config(struct pwb_context *ctx)
+{
+ int ret;
+ ret = get_config_item_int(ctx, "warn_pwd_expire",
+ WINBIND_WARN_PWD_EXPIRE);
+ /* no or broken setting */
+ if (ret <= 0) {
+ return DEFAULT_DAYS_TO_WARN_BEFORE_PWD_EXPIRES;
+ }
+ return ret;
+}
+
+/**
+ * Retrieve the winbind separator.
+ *
+ * @param ctx PAM winbind context.
+ *
+ * @return string separator character. NULL on failure.
+ */
+
+static char winbind_get_separator(struct pwb_context *ctx)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if (pam_winbind_request_log(ctx, WINBINDD_INFO,
+ &request, &response, NULL)) {
+ return '\0';
+ }
+
+ return response.data.info.winbind_separator;
+}
+
+/**
+ * Convert a upn to a name.
+ *
+ * @param ctx PAM winbind context.
+ * @param upn USer UPN to be trabslated.
+ *
+ * @return converted name. NULL pointer on failure. Caller needs to free.
+ */
+
+static char* winbind_upn_to_username(struct pwb_context *ctx,
+ const char *upn)
+{
+ struct winbindd_request req;
+ struct winbindd_response resp;
+ int retval;
+ char *account_name;
+ int account_name_len;
+ char sep;
+
+ /* This cannot work when the winbind separator = @ */
+
+ sep = winbind_get_separator(ctx);
+ if (!sep || sep == '@') {
+ return NULL;
+ }
+
+ /* Convert the UPN to a SID */
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(resp);
+
+ strncpy(req.data.name.dom_name, "",
+ sizeof(req.data.name.dom_name) - 1);
+ strncpy(req.data.name.name, upn,
+ sizeof(req.data.name.name) - 1);
+ retval = pam_winbind_request_log(ctx, WINBINDD_LOOKUPNAME,
+ &req, &resp, upn);
+ if (retval != PAM_SUCCESS) {
+ return NULL;
+ }
+
+ /* Convert the the SID back to the sAMAccountName */
+
+ ZERO_STRUCT(req);
+ strncpy(req.data.sid, resp.data.sid.sid, sizeof(req.data.sid)-1);
+ ZERO_STRUCT(resp);
+ retval = pam_winbind_request_log(ctx, WINBINDD_LOOKUPSID,
+ &req, &resp, upn);
+ if (retval != PAM_SUCCESS) {
+ return NULL;
+ }
+
+ account_name_len = asprintf(&account_name, "%s\\%s",
+ resp.data.name.dom_name,
+ resp.data.name.name);
+
+ return account_name;
+}
+
+PAM_EXTERN
+int pam_sm_authenticate(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ const char *username;
+ const char *password;
+ const char *member = NULL;
+ const char *cctype = NULL;
+ int warn_pwd_expire;
+ int retval = PAM_AUTH_ERR;
+ char *username_ret = NULL;
+ char *new_authtok_required = NULL;
+ char *real_username = NULL;
+ struct pwb_context *ctx = NULL;
+
+ retval = _pam_winbind_init_context(pamh, flags, argc, argv, &ctx);
+ if (retval) {
+ goto out;
+ }
+
+ _PAM_LOG_FUNCTION_ENTER("pam_sm_authenticate", ctx);
+
+ /* Get the username */
+ retval = pam_get_user(pamh, &username, NULL);
+ if ((retval != PAM_SUCCESS) || (!username)) {
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "can not get the username");
+ retval = PAM_SERVICE_ERR;
+ goto out;
+ }
+
+
+#if defined(AIX)
+ /* Decode the user name since AIX does not support logn user
+ names by default. The name is encoded as _#uid. */
+
+ if (username[0] == '_') {
+ uid_t id = atoi(&username[1]);
+ struct passwd *pw = NULL;
+
+ if ((id!=0) && ((pw = getpwuid(id)) != NULL)) {
+ real_username = strdup(pw->pw_name);
+ }
+ }
+#endif
+
+ if (!real_username) {
+ /* Just making a copy of the username we got from PAM */
+ if ((real_username = strdup(username)) == NULL) {
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "memory allocation failure when copying "
+ "username");
+ retval = PAM_SERVICE_ERR;
+ goto out;
+ }
+ }
+
+ /* Maybe this was a UPN */
+
+ if (strchr(real_username, '@') != NULL) {
+ char *samaccountname = NULL;
+
+ samaccountname = winbind_upn_to_username(ctx,
+ real_username);
+ if (samaccountname) {
+ free(real_username);
+ real_username = samaccountname;
+ }
+ }
+
+ retval = _winbind_read_password(ctx, ctx->ctrl, NULL,
+ "Password: ", NULL,
+ &password);
+
+ if (retval != PAM_SUCCESS) {
+ _pam_log(ctx, LOG_ERR,
+ "Could not retrieve user's password");
+ retval = PAM_AUTHTOK_ERR;
+ goto out;
+ }
+
+ /* Let's not give too much away in the log file */
+
+#ifdef DEBUG_PASSWORD
+ _pam_log_debug(ctx, LOG_INFO,
+ "Verify user '%s' with password '%s'",
+ real_username, password);
+#else
+ _pam_log_debug(ctx, LOG_INFO,
+ "Verify user '%s'", real_username);
+#endif
+
+ member = get_member_from_config(ctx);
+ cctype = get_krb5_cc_type_from_config(ctx);
+ warn_pwd_expire = get_warn_pwd_expire_from_config(ctx);
+
+ /* Now use the username to look up password */
+ retval = winbind_auth_request(ctx, real_username, password,
+ member, cctype, warn_pwd_expire, NULL,
+ NULL, &username_ret);
+
+ if (retval == PAM_NEW_AUTHTOK_REQD ||
+ retval == PAM_AUTHTOK_EXPIRED) {
+
+ char *new_authtok_required_during_auth = NULL;
+
+ if (!asprintf(&new_authtok_required, "%d", retval)) {
+ retval = PAM_BUF_ERR;
+ goto out;
+ }
+
+ pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD,
+ new_authtok_required,
+ _pam_winbind_cleanup_func);
+
+ retval = PAM_SUCCESS;
+
+ if (!asprintf(&new_authtok_required_during_auth, "%d", true)) {
+ retval = PAM_BUF_ERR;
+ goto out;
+ }
+
+ pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH,
+ new_authtok_required_during_auth,
+ _pam_winbind_cleanup_func);
+
+ goto out;
+ }
+
+out:
+ if (username_ret) {
+ pam_set_item (pamh, PAM_USER, username_ret);
+ _pam_log_debug(ctx, LOG_INFO,
+ "Returned user was '%s'", username_ret);
+ free(username_ret);
+ }
+
+ if (real_username) {
+ free(real_username);
+ }
+
+ if (!new_authtok_required) {
+ pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD, NULL, NULL);
+ }
+
+ if (retval != PAM_SUCCESS) {
+ _pam_free_data_info3(pamh);
+ }
+
+ _PAM_LOG_FUNCTION_LEAVE("pam_sm_authenticate", ctx, retval);
+
+ _pam_winbind_free_context(ctx);
+
+ return retval;
+}
+
+PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ int ret = PAM_SYSTEM_ERR;
+ struct pwb_context *ctx = NULL;
+
+ ret = _pam_winbind_init_context(pamh, flags, argc, argv, &ctx);
+ if (ret) {
+ goto out;
+ }
+
+ _PAM_LOG_FUNCTION_ENTER("pam_sm_setcred", ctx);
+
+ switch (flags & ~PAM_SILENT) {
+
+ case PAM_DELETE_CRED:
+ ret = pam_sm_close_session(pamh, flags, argc, argv);
+ break;
+ case PAM_REFRESH_CRED:
+ _pam_log_debug(ctx, LOG_WARNING,
+ "PAM_REFRESH_CRED not implemented");
+ ret = PAM_SUCCESS;
+ break;
+ case PAM_REINITIALIZE_CRED:
+ _pam_log_debug(ctx, LOG_WARNING,
+ "PAM_REINITIALIZE_CRED not implemented");
+ ret = PAM_SUCCESS;
+ break;
+ case PAM_ESTABLISH_CRED:
+ _pam_log_debug(ctx, LOG_WARNING,
+ "PAM_ESTABLISH_CRED not implemented");
+ ret = PAM_SUCCESS;
+ break;
+ default:
+ ret = PAM_SYSTEM_ERR;
+ break;
+ }
+
+ out:
+
+ _PAM_LOG_FUNCTION_LEAVE("pam_sm_setcred", ctx, ret);
+
+ _pam_winbind_free_context(ctx);
+
+ return ret;
+}
+
+/*
+ * Account management. We want to verify that the account exists
+ * before returning PAM_SUCCESS
+ */
+PAM_EXTERN
+int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ const char *username;
+ int ret = PAM_USER_UNKNOWN;
+ void *tmp = NULL;
+ struct pwb_context *ctx = NULL;
+
+ ret = _pam_winbind_init_context(pamh, flags, argc, argv, &ctx);
+ if (ret) {
+ goto out;
+ }
+
+ _PAM_LOG_FUNCTION_ENTER("pam_sm_acct_mgmt", ctx);
+
+
+ /* Get the username */
+ ret = pam_get_user(pamh, &username, NULL);
+ if ((ret != PAM_SUCCESS) || (!username)) {
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "can not get the username");
+ ret = PAM_SERVICE_ERR;
+ goto out;
+ }
+
+ /* Verify the username */
+ ret = valid_user(ctx, username);
+ switch (ret) {
+ case -1:
+ /* some sort of system error. The log was already printed */
+ ret = PAM_SERVICE_ERR;
+ goto out;
+ case 1:
+ /* the user does not exist */
+ _pam_log_debug(ctx, LOG_NOTICE, "user '%s' not found",
+ username);
+ if (ctx->ctrl & WINBIND_UNKNOWN_OK_ARG) {
+ ret = PAM_IGNORE;
+ goto out;
+ }
+ ret = PAM_USER_UNKNOWN;
+ goto out;
+ case 0:
+ pam_get_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD,
+ (const void **)&tmp);
+ if (tmp != NULL) {
+ ret = atoi((const char *)tmp);
+ switch (ret) {
+ case PAM_AUTHTOK_EXPIRED:
+ /* fall through, since new token is required in this case */
+ case PAM_NEW_AUTHTOK_REQD:
+ _pam_log(ctx, LOG_WARNING,
+ "pam_sm_acct_mgmt success but %s is set",
+ PAM_WINBIND_NEW_AUTHTOK_REQD);
+ _pam_log(ctx, LOG_NOTICE,
+ "user '%s' needs new password",
+ username);
+ /* PAM_AUTHTOKEN_REQD does not exist, but is documented in the manpage */
+ ret = PAM_NEW_AUTHTOK_REQD;
+ goto out;
+ default:
+ _pam_log(ctx, LOG_WARNING,
+ "pam_sm_acct_mgmt success");
+ _pam_log(ctx, LOG_NOTICE,
+ "user '%s' granted access", username);
+ ret = PAM_SUCCESS;
+ goto out;
+ }
+ }
+
+ /* Otherwise, the authentication looked good */
+ _pam_log(ctx, LOG_NOTICE,
+ "user '%s' granted access", username);
+ ret = PAM_SUCCESS;
+ goto out;
+ default:
+ /* we don't know anything about this return value */
+ _pam_log(ctx, LOG_ERR,
+ "internal module error (ret = %d, user = '%s')",
+ ret, username);
+ ret = PAM_SERVICE_ERR;
+ goto out;
+ }
+
+ /* should not be reached */
+ ret = PAM_IGNORE;
+
+ out:
+
+ _PAM_LOG_FUNCTION_LEAVE("pam_sm_acct_mgmt", ctx, ret);
+
+ _pam_winbind_free_context(ctx);
+
+ return ret;
+}
+
+PAM_EXTERN
+int pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ int ret = PAM_SYSTEM_ERR;
+ struct pwb_context *ctx = NULL;
+
+ ret = _pam_winbind_init_context(pamh, flags, argc, argv, &ctx);
+ if (ret) {
+ goto out;
+ }
+
+ _PAM_LOG_FUNCTION_ENTER("pam_sm_open_session", ctx);
+
+ ret = PAM_SUCCESS;
+
+ out:
+ _PAM_LOG_FUNCTION_LEAVE("pam_sm_open_session", ctx, ret);
+
+ _pam_winbind_free_context(ctx);
+
+ return ret;
+}
+
+PAM_EXTERN
+int pam_sm_close_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ int retval = PAM_SUCCESS;
+ struct pwb_context *ctx = NULL;
+
+ retval = _pam_winbind_init_context(pamh, flags, argc, argv, &ctx);
+ if (retval) {
+ goto out;
+ }
+
+ _PAM_LOG_FUNCTION_ENTER("pam_sm_close_session", ctx);
+
+ if (!(flags & PAM_DELETE_CRED)) {
+ retval = PAM_SUCCESS;
+ goto out;
+ }
+
+ if (ctx->ctrl & WINBIND_KRB5_AUTH) {
+
+ /* destroy the ccache here */
+ struct winbindd_request request;
+ struct winbindd_response response;
+ const char *user;
+ const char *ccname = NULL;
+ struct passwd *pwd = NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ retval = pam_get_user(pamh, &user, "Username: ");
+ if (retval) {
+ _pam_log(ctx, LOG_ERR,
+ "could not identify user");
+ goto out;
+ }
+
+ if (user == NULL) {
+ _pam_log(ctx, LOG_ERR,
+ "username was NULL!");
+ retval = PAM_USER_UNKNOWN;
+ goto out;
+ }
+
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "username [%s] obtained", user);
+
+ ccname = pam_getenv(pamh, "KRB5CCNAME");
+ if (ccname == NULL) {
+ _pam_log_debug(ctx, LOG_DEBUG,
+ "user has no KRB5CCNAME environment");
+ }
+
+ strncpy(request.data.logoff.user, user,
+ sizeof(request.data.logoff.user) - 1);
+
+ if (ccname) {
+ strncpy(request.data.logoff.krb5ccname, ccname,
+ sizeof(request.data.logoff.krb5ccname) - 1);
+ }
+
+ pwd = getpwnam(user);
+ if (pwd == NULL) {
+ retval = PAM_USER_UNKNOWN;
+ goto out;
+ }
+ request.data.logoff.uid = pwd->pw_uid;
+
+ request.flags = WBFLAG_PAM_KRB5 |
+ WBFLAG_PAM_CONTACT_TRUSTDOM;
+
+ retval = pam_winbind_request_log(ctx,
+ WINBINDD_PAM_LOGOFF,
+ &request, &response, user);
+ }
+
+out:
+
+ _PAM_LOG_FUNCTION_LEAVE("pam_sm_close_session", ctx, retval);
+
+ _pam_winbind_free_context(ctx);
+
+ return retval;
+}
+
+/**
+ * evaluate whether we need to re-authenticate with kerberos after a
+ * password change
+ *
+ * @param ctx PAM winbind context.
+ * @param user The username
+ *
+ * @return boolean Returns true if required, false if not.
+ */
+
+static bool _pam_require_krb5_auth_after_chauthtok(struct pwb_context *ctx,
+ const char *user)
+{
+
+ /* Make sure that we only do this if a) the chauthtok got initiated
+ * during a logon attempt (authenticate->acct_mgmt->chauthtok) b) any
+ * later password change via the "passwd" command if done by the user
+ * itself
+ * NB. If we login from gdm or xdm and the password expires,
+ * we change the password, but there is no memory cache.
+ * Thus, even for passthrough login, we should do the
+ * authentication again to update memory cache.
+ * --- BoYang
+ * */
+
+ char *new_authtok_reqd_during_auth = NULL;
+ struct passwd *pwd = NULL;
+
+ _pam_get_data(ctx->pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH,
+ &new_authtok_reqd_during_auth);
+ pam_set_data(ctx->pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH,
+ NULL, NULL);
+
+ if (new_authtok_reqd_during_auth) {
+ return true;
+ }
+
+ pwd = getpwnam(user);
+ if (!pwd) {
+ return false;
+ }
+
+ if (getuid() == pwd->pw_uid) {
+ return true;
+ }
+
+ return false;
+}
+
+
+PAM_EXTERN
+int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
+ int argc, const char **argv)
+{
+ unsigned int lctrl;
+ int ret;
+ bool cached_login = false;
+
+ /* <DO NOT free() THESE> */
+ const char *user;
+ char *pass_old, *pass_new;
+ /* </DO NOT free() THESE> */
+
+ char *Announce;
+
+ int retry = 0;
+ char *username_ret = NULL;
+ struct winbindd_response response;
+ struct pwb_context *ctx = NULL;
+
+ ZERO_STRUCT(response);
+
+ ret = _pam_winbind_init_context(pamh, flags, argc, argv, &ctx);
+ if (ret) {
+ goto out;
+ }
+
+ _PAM_LOG_FUNCTION_ENTER("pam_sm_chauthtok", ctx);
+
+ cached_login = (ctx->ctrl & WINBIND_CACHED_LOGIN);
+
+ /* clearing offline bit for auth */
+ ctx->ctrl &= ~WINBIND_CACHED_LOGIN;
+
+ /*
+ * First get the name of a user
+ */
+ ret = pam_get_user(pamh, &user, "Username: ");
+ if (ret) {
+ _pam_log(ctx, LOG_ERR,
+ "password - could not identify user");
+ goto out;
+ }
+
+ if (user == NULL) {
+ _pam_log(ctx, LOG_ERR, "username was NULL!");
+ ret = PAM_USER_UNKNOWN;
+ goto out;
+ }
+
+ _pam_log_debug(ctx, LOG_DEBUG, "username [%s] obtained", user);
+
+ /* check if this is really a user in winbindd, not only in NSS */
+ ret = valid_user(ctx, user);
+ switch (ret) {
+ case 1:
+ ret = PAM_USER_UNKNOWN;
+ goto out;
+ case -1:
+ ret = PAM_SYSTEM_ERR;
+ goto out;
+ default:
+ break;
+ }
+
+ /*
+ * obtain and verify the current password (OLDAUTHTOK) for
+ * the user.
+ */
+
+ if (flags & PAM_PRELIM_CHECK) {
+ time_t pwdlastset_prelim = 0;
+
+ /* instruct user what is happening */
+#define greeting "Changing password for "
+ Announce = (char *) malloc(sizeof(greeting) + strlen(user));
+ if (Announce == NULL) {
+ _pam_log(ctx, LOG_CRIT,
+ "password - out of memory");
+ ret = PAM_BUF_ERR;
+ goto out;
+ }
+ (void) strcpy(Announce, greeting);
+ (void) strcpy(Announce + sizeof(greeting) - 1, user);
+#undef greeting
+
+ lctrl = ctx->ctrl | WINBIND__OLD_PASSWORD;
+ ret = _winbind_read_password(ctx, lctrl,
+ Announce,
+ "(current) NT password: ",
+ NULL,
+ (const char **) &pass_old);
+ if (ret != PAM_SUCCESS) {
+ _pam_log(ctx, LOG_NOTICE,
+ "password - (old) token not obtained");
+ goto out;
+ }
+
+ /* verify that this is the password for this user */
+
+ ret = winbind_auth_request(ctx, user, pass_old,
+ NULL, NULL, 0, &response,
+ &pwdlastset_prelim, NULL);
+
+ if (ret != PAM_ACCT_EXPIRED &&
+ ret != PAM_AUTHTOK_EXPIRED &&
+ ret != PAM_NEW_AUTHTOK_REQD &&
+ ret != PAM_SUCCESS) {
+ pass_old = NULL;
+ goto out;
+ }
+
+ pam_set_data(pamh, PAM_WINBIND_PWD_LAST_SET,
+ (void *)pwdlastset_prelim, NULL);
+
+ ret = pam_set_item(pamh, PAM_OLDAUTHTOK,
+ (const void *) pass_old);
+ pass_old = NULL;
+ if (ret != PAM_SUCCESS) {
+ _pam_log(ctx, LOG_CRIT,
+ "failed to set PAM_OLDAUTHTOK");
+ }
+ } else if (flags & PAM_UPDATE_AUTHTOK) {
+
+ time_t pwdlastset_update = 0;
+
+ /*
+ * obtain the proposed password
+ */
+
+ /*
+ * get the old token back.
+ */
+
+ ret = _pam_get_item(pamh, PAM_OLDAUTHTOK, &pass_old);
+
+ if (ret != PAM_SUCCESS) {
+ _pam_log(ctx, LOG_NOTICE,
+ "user not authenticated");
+ goto out;
+ }
+
+ lctrl = ctx->ctrl & ~WINBIND_TRY_FIRST_PASS_ARG;
+
+ if (on(WINBIND_USE_AUTHTOK_ARG, lctrl)) {
+ lctrl |= WINBIND_USE_FIRST_PASS_ARG;
+ }
+ retry = 0;
+ ret = PAM_AUTHTOK_ERR;
+ while ((ret != PAM_SUCCESS) && (retry++ < MAX_PASSWD_TRIES)) {
+ /*
+ * use_authtok is to force the use of a previously entered
+ * password -- needed for pluggable password strength checking
+ */
+
+ ret = _winbind_read_password(ctx, lctrl,
+ NULL,
+ "Enter new NT password: ",
+ "Retype new NT password: ",
+ (const char **)&pass_new);
+
+ if (ret != PAM_SUCCESS) {
+ _pam_log_debug(ctx, LOG_ALERT,
+ "password - "
+ "new password not obtained");
+ pass_old = NULL;/* tidy up */
+ goto out;
+ }
+
+ /*
+ * At this point we know who the user is and what they
+ * propose as their new password. Verify that the new
+ * password is acceptable.
+ */
+
+ if (pass_new[0] == '\0') {/* "\0" password = NULL */
+ pass_new = NULL;
+ }
+ }
+
+ /*
+ * By reaching here we have approved the passwords and must now
+ * rebuild the password database file.
+ */
+ _pam_get_data(pamh, PAM_WINBIND_PWD_LAST_SET,
+ &pwdlastset_update);
+
+ /*
+ * if cached creds were enabled, make sure to set the
+ * WINBIND_CACHED_LOGIN bit here in order to have winbindd
+ * update the cached creds storage - gd
+ */
+ if (cached_login) {
+ ctx->ctrl |= WINBIND_CACHED_LOGIN;
+ }
+
+ ret = winbind_chauthtok_request(ctx, user, pass_old,
+ pass_new, pwdlastset_update);
+ if (ret) {
+ _pam_overwrite(pass_new);
+ _pam_overwrite(pass_old);
+ pass_old = pass_new = NULL;
+ goto out;
+ }
+
+ if (_pam_require_krb5_auth_after_chauthtok(ctx, user)) {
+
+ const char *member = NULL;
+ const char *cctype = NULL;
+ int warn_pwd_expire;
+
+ member = get_member_from_config(ctx);
+ cctype = get_krb5_cc_type_from_config(ctx);
+ warn_pwd_expire = get_warn_pwd_expire_from_config(ctx);
+
+ /* Keep WINBIND_CACHED_LOGIN bit for
+ * authentication after changing the password.
+ * This will update the cached credentials in case
+ * that winbindd_dual_pam_chauthtok() fails
+ * to update them.
+ * --- BoYang
+ * */
+
+ ret = winbind_auth_request(ctx, user, pass_new,
+ member, cctype, 0, &response,
+ NULL, &username_ret);
+ _pam_overwrite(pass_new);
+ _pam_overwrite(pass_old);
+ pass_old = pass_new = NULL;
+
+ if (ret == PAM_SUCCESS) {
+
+ /* warn a user if the password is about to
+ * expire soon */
+ _pam_warn_password_expiry(ctx, &response,
+ warn_pwd_expire,
+ NULL);
+
+ /* set some info3 info for other modules in the
+ * stack */
+ _pam_set_data_info3(ctx, &response);
+
+ /* put krb5ccname into env */
+ _pam_setup_krb5_env(ctx,
+ response.data.auth.krb5ccname);
+
+ if (username_ret) {
+ pam_set_item(pamh, PAM_USER,
+ username_ret);
+ _pam_log_debug(ctx, LOG_INFO,
+ "Returned user was '%s'",
+ username_ret);
+ free(username_ret);
+ }
+ }
+
+ goto out;
+ }
+ } else {
+ ret = PAM_SERVICE_ERR;
+ }
+
+out:
+
+ /* Deal with offline errors. */
+ PAM_WB_REMARK_CHECK_RESPONSE(ctx, response,
+ "NT_STATUS_NO_LOGON_SERVERS");
+ PAM_WB_REMARK_CHECK_RESPONSE(ctx, response,
+ "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND");
+ PAM_WB_REMARK_CHECK_RESPONSE(ctx, response,
+ "NT_STATUS_ACCESS_DENIED");
+
+ _PAM_LOG_FUNCTION_LEAVE("pam_sm_chauthtok", ctx, ret);
+
+ _pam_winbind_free_context(ctx);
+
+ return ret;
+}
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_winbind_modstruct = {
+ MODULE_NAME,
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ pam_sm_acct_mgmt,
+ pam_sm_open_session,
+ pam_sm_close_session,
+ pam_sm_chauthtok
+};
+
+#endif
+
+/*
+ * Copyright (c) Andrew Tridgell <tridge@samba.org> 2000
+ * Copyright (c) Tim Potter <tpot@samba.org> 2000
+ * Copyright (c) Andrew Bartlettt <abartlet@samba.org> 2002
+ * Copyright (c) Guenther Deschner <gd@samba.org> 2005-2008
+ * Copyright (c) Jan Rêkorajski 1999.
+ * Copyright (c) Andrew G. Morgan 1996-8.
+ * Copyright (c) Alex O. Yuriev, 1996.
+ * Copyright (c) Cristian Gafton 1996.
+ * Copyright (C) Elliot Lee <sopwith@redhat.com> 1996, Red Hat Software.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
diff --git a/source3/nsswitch/pam_winbind.h b/source3/nsswitch/pam_winbind.h
new file mode 100644
index 0000000000..c8c1910641
--- /dev/null
+++ b/source3/nsswitch/pam_winbind.h
@@ -0,0 +1,211 @@
+/* pam_winbind header file
+ (Solaris needs some macros from Linux for common PAM code)
+
+ Shirish Kalele 2000
+*/
+
+#include "lib/replace/replace.h"
+#include "system/syslog.h"
+#include "system/time.h"
+
+#define MODULE_NAME "pam_winbind"
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_PASSWORD
+#define PAM_SM_SESSION
+
+#ifndef PAM_WINBIND_CONFIG_FILE
+#define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
+#endif
+
+#include <iniparser.h>
+
+#ifndef LINUX
+
+/* Solaris always uses dynamic pam modules */
+#define PAM_EXTERN extern
+#if defined(HAVE_SECURITY_PAM_APPL_H)
+#include <security/pam_appl.h>
+#elif defined(HAVE_PAM_PAM_APPL_H)
+#include <pam/pam_appl.h>
+#endif
+
+#ifndef PAM_AUTHTOK_RECOVER_ERR
+#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR
+#endif
+
+#endif /* defined(SUNOS5) || defined(SUNOS4) || defined(HPUX) || defined(FREEBSD) || defined(AIX) */
+
+#if defined(HAVE_SECURITY_PAM_MODULES_H)
+#include <security/pam_modules.h>
+#elif defined(HAVE_PAM_PAM_MODULES_H)
+#include <pam/pam_modules.h>
+#endif
+
+#if defined(HAVE_SECURITY__PAM_MACROS_H)
+#include <security/_pam_macros.h>
+#elif defined(HAVE_PAM__PAM_MACROS_H)
+#include <pam/_pam_macros.h>
+#else
+/* Define required macros from (Linux PAM 0.68) security/_pam_macros.h */
+#define _pam_drop_reply(/* struct pam_response * */ reply, /* int */ replies) \
+do { \
+ int reply_i; \
+ \
+ for (reply_i=0; reply_i<replies; ++reply_i) { \
+ if (reply[reply_i].resp) { \
+ _pam_overwrite(reply[reply_i].resp); \
+ free(reply[reply_i].resp); \
+ } \
+ } \
+ if (reply) \
+ free(reply); \
+} while (0)
+
+#define _pam_overwrite(x) \
+do { \
+ register char *__xx__; \
+ if ((__xx__=(x))) \
+ while (*__xx__) \
+ *__xx__++ = '\0'; \
+} while (0)
+
+/*
+ * Don't just free it, forget it too.
+ */
+
+#define _pam_drop(X) SAFE_FREE(X)
+
+#define x_strdup(s) ( (s) ? strdup(s):NULL )
+#endif /* HAVE_SECURITY__PAM_MACROS_H */
+
+#ifdef HAVE_SECURITY_PAM_EXT_H
+#include <security/pam_ext.h>
+#endif
+
+#define WINBIND_DEBUG_ARG 0x00000001
+#define WINBIND_USE_AUTHTOK_ARG 0x00000002
+#define WINBIND_UNKNOWN_OK_ARG 0x00000004
+#define WINBIND_TRY_FIRST_PASS_ARG 0x00000008
+#define WINBIND_USE_FIRST_PASS_ARG 0x00000010
+#define WINBIND__OLD_PASSWORD 0x00000020
+#define WINBIND_REQUIRED_MEMBERSHIP 0x00000040
+#define WINBIND_KRB5_AUTH 0x00000080
+#define WINBIND_KRB5_CCACHE_TYPE 0x00000100
+#define WINBIND_CACHED_LOGIN 0x00000200
+#define WINBIND_CONFIG_FILE 0x00000400
+#define WINBIND_SILENT 0x00000800
+#define WINBIND_DEBUG_STATE 0x00001000
+#define WINBIND_WARN_PWD_EXPIRE 0x00002000
+
+/*
+ * here is the string to inform the user that the new passwords they
+ * typed were not the same.
+ */
+
+#define MISTYPED_PASS "Sorry, passwords do not match"
+
+#define on(x, y) (x & y)
+#define off(x, y) (!(x & y))
+
+#define PAM_WINBIND_NEW_AUTHTOK_REQD "PAM_WINBIND_NEW_AUTHTOK_REQD"
+#define PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH "PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH"
+#define PAM_WINBIND_HOMEDIR "PAM_WINBIND_HOMEDIR"
+#define PAM_WINBIND_LOGONSCRIPT "PAM_WINBIND_LOGONSCRIPT"
+#define PAM_WINBIND_LOGONSERVER "PAM_WINBIND_LOGONSERVER"
+#define PAM_WINBIND_PROFILEPATH "PAM_WINBIND_PROFILEPATH"
+#define PAM_WINBIND_PWD_LAST_SET "PAM_WINBIND_PWD_LAST_SET"
+
+#define SECONDS_PER_DAY 86400
+
+#define DEFAULT_DAYS_TO_WARN_BEFORE_PWD_EXPIRES 14
+
+#include "winbind_client.h"
+
+#define PAM_WB_REMARK_DIRECT(c,x)\
+{\
+ const char *error_string = NULL; \
+ error_string = _get_ntstatus_error_string(x);\
+ if (error_string != NULL) {\
+ _make_remark(c, PAM_ERROR_MSG, error_string);\
+ } else {\
+ _make_remark(c, PAM_ERROR_MSG, x);\
+ };\
+};
+
+#define PAM_WB_REMARK_DIRECT_RET(h,f,x)\
+{\
+ const char *error_string = NULL; \
+ error_string = _get_ntstatus_error_string(x);\
+ if (error_string != NULL) {\
+ _make_remark(h, f, PAM_ERROR_MSG, error_string);\
+ return ret;\
+ };\
+ _make_remark(h, f, PAM_ERROR_MSG, x);\
+ return ret;\
+};
+
+#define PAM_WB_REMARK_CHECK_RESPONSE(c,x,y)\
+{\
+ const char *ntstatus = x.data.auth.nt_status_string; \
+ const char *error_string = NULL; \
+ if (!strcasecmp(ntstatus,y)) {\
+ error_string = _get_ntstatus_error_string(y);\
+ if (error_string != NULL) {\
+ _make_remark(c, PAM_ERROR_MSG, error_string);\
+ };\
+ if (x.data.auth.error_string[0] != '\0') {\
+ _make_remark(c, PAM_ERROR_MSG, x.data.auth.error_string);\
+ };\
+ _make_remark(c, PAM_ERROR_MSG, y);\
+ };\
+};
+
+#define PAM_WB_REMARK_CHECK_RESPONSE_RET(c,x,y)\
+{\
+ const char *ntstatus = x.data.auth.nt_status_string; \
+ const char *error_string = NULL; \
+ if (!strcasecmp(ntstatus,y)) {\
+ error_string = _get_ntstatus_error_string(y);\
+ if (error_string != NULL) {\
+ _make_remark(c, PAM_ERROR_MSG, error_string);\
+ return ret;\
+ };\
+ if (x.data.auth.error_string[0] != '\0') {\
+ _make_remark(c, PAM_ERROR_MSG, x.data.auth.error_string);\
+ return ret;\
+ };\
+ _make_remark(c, PAM_ERROR_MSG, y);\
+ return ret;\
+ };\
+};
+
+/* from samr.idl */
+#define DOMAIN_PASSWORD_COMPLEX 0x00000001
+
+#define SAMR_REJECT_OTHER 0x00000000
+#define SAMR_REJECT_TOO_SHORT 0x00000001
+#define SAMR_REJECT_IN_HISTORY 0x00000002
+#define SAMR_REJECT_COMPLEXITY 0x00000005
+
+#define ACB_PWNOEXP 0x00000200
+
+/* from netlogon.idl */
+#define NETLOGON_CACHED_ACCOUNT 0x00000004
+#define NETLOGON_GRACE_LOGON 0x01000000
+
+/* from include/rpc_netlogon.h */
+#define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
+
+#define PAM_WB_CACHED_LOGON(x) (x & NETLOGON_CACHED_ACCOUNT)
+#define PAM_WB_KRB5_CLOCK_SKEW(x) (x & LOGON_KRB5_FAIL_CLOCK_SKEW)
+#define PAM_WB_GRACE_LOGON(x) ((NETLOGON_CACHED_ACCOUNT|NETLOGON_GRACE_LOGON) == ( x & (NETLOGON_CACHED_ACCOUNT|NETLOGON_GRACE_LOGON)))
+
+struct pwb_context {
+ pam_handle_t *pamh;
+ int flags;
+ int argc;
+ const char **argv;
+ dictionary *dict;
+ uint32_t ctrl;
+};
diff --git a/source3/nsswitch/wb_common.c b/source3/nsswitch/wb_common.c
new file mode 100644
index 0000000000..6e6d2bbbf8
--- /dev/null
+++ b/source3/nsswitch/wb_common.c
@@ -0,0 +1,690 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ winbind client common code
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Andrew Tridgell 2000
+ Copyright (C) Andrew Bartlett 2002
+
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "winbind_client.h"
+
+/* Global variables. These are effectively the client state information */
+
+int winbindd_fd = -1; /* fd for winbindd socket */
+static int is_privileged = 0;
+
+/* Free a response structure */
+
+void winbindd_free_response(struct winbindd_response *response)
+{
+ /* Free any allocated extra_data */
+
+ if (response)
+ SAFE_FREE(response->extra_data.data);
+}
+
+/* Initialise a request structure */
+
+void winbindd_init_request(struct winbindd_request *request, int request_type)
+{
+ request->length = sizeof(struct winbindd_request);
+
+ request->cmd = (enum winbindd_cmd)request_type;
+ request->pid = getpid();
+
+}
+
+/* Initialise a response structure */
+
+static void init_response(struct winbindd_response *response)
+{
+ /* Initialise return value */
+
+ response->result = WINBINDD_ERROR;
+}
+
+/* Close established socket */
+
+void winbind_close_sock(void)
+{
+ if (winbindd_fd != -1) {
+ close(winbindd_fd);
+ winbindd_fd = -1;
+ }
+}
+
+#define CONNECT_TIMEOUT 30
+
+/* Make sure socket handle isn't stdin, stdout or stderr */
+#define RECURSION_LIMIT 3
+
+static int make_nonstd_fd_internals(int fd, int limit /* Recursion limiter */)
+{
+ int new_fd;
+ if (fd >= 0 && fd <= 2) {
+#ifdef F_DUPFD
+ if ((new_fd = fcntl(fd, F_DUPFD, 3)) == -1) {
+ return -1;
+ }
+ /* Paranoia */
+ if (new_fd < 3) {
+ close(new_fd);
+ return -1;
+ }
+ close(fd);
+ return new_fd;
+#else
+ if (limit <= 0)
+ return -1;
+
+ new_fd = dup(fd);
+ if (new_fd == -1)
+ return -1;
+
+ /* use the program stack to hold our list of FDs to close */
+ new_fd = make_nonstd_fd_internals(new_fd, limit - 1);
+ close(fd);
+ return new_fd;
+#endif
+ }
+ return fd;
+}
+
+/****************************************************************************
+ Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
+ else
+ if SYSV use O_NDELAY
+ if BSD use FNDELAY
+ Set close on exec also.
+****************************************************************************/
+
+static int make_safe_fd(int fd)
+{
+ int result, flags;
+ int new_fd = make_nonstd_fd_internals(fd, RECURSION_LIMIT);
+ if (new_fd == -1) {
+ close(fd);
+ return -1;
+ }
+
+ /* Socket should be nonblocking. */
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+
+ if ((flags = fcntl(new_fd, F_GETFL)) == -1) {
+ close(new_fd);
+ return -1;
+ }
+
+ flags |= FLAG_TO_SET;
+ if (fcntl(new_fd, F_SETFL, flags) == -1) {
+ close(new_fd);
+ return -1;
+ }
+
+#undef FLAG_TO_SET
+
+ /* Socket should be closed on exec() */
+#ifdef FD_CLOEXEC
+ result = flags = fcntl(new_fd, F_GETFD, 0);
+ if (flags >= 0) {
+ flags |= FD_CLOEXEC;
+ result = fcntl( new_fd, F_SETFD, flags );
+ }
+ if (result < 0) {
+ close(new_fd);
+ return -1;
+ }
+#endif
+ return new_fd;
+}
+
+/* Connect to winbindd socket */
+
+static int winbind_named_pipe_sock(const char *dir)
+{
+ struct sockaddr_un sunaddr;
+ struct stat st;
+ char *path = NULL;
+ int fd;
+ int wait_time;
+ int slept;
+
+ /* Check permissions on unix socket directory */
+
+ if (lstat(dir, &st) == -1) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (!S_ISDIR(st.st_mode) ||
+ (st.st_uid != 0 && st.st_uid != geteuid())) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ /* Connect to socket */
+
+ if (asprintf(&path, "%s/%s", dir, WINBINDD_SOCKET_NAME) < 0) {
+ return -1;
+ }
+
+ ZERO_STRUCT(sunaddr);
+ sunaddr.sun_family = AF_UNIX;
+ strncpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path) - 1);
+
+ /* If socket file doesn't exist, don't bother trying to connect
+ with retry. This is an attempt to make the system usable when
+ the winbindd daemon is not running. */
+
+ if (lstat(path, &st) == -1) {
+ errno = ENOENT;
+ SAFE_FREE(path);
+ return -1;
+ }
+
+ SAFE_FREE(path);
+ /* Check permissions on unix socket file */
+
+ if (!S_ISSOCK(st.st_mode) ||
+ (st.st_uid != 0 && st.st_uid != geteuid())) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ /* Connect to socket */
+
+ if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ return -1;
+ }
+
+ /* Set socket non-blocking and close on exec. */
+
+ if ((fd = make_safe_fd( fd)) == -1) {
+ return fd;
+ }
+
+ for (wait_time = 0; connect(fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1;
+ wait_time += slept) {
+ struct timeval tv;
+ fd_set w_fds;
+ int ret;
+ int connect_errno = 0;
+ socklen_t errnosize;
+
+ if (wait_time >= CONNECT_TIMEOUT)
+ goto error_out;
+
+ switch (errno) {
+ case EINPROGRESS:
+ FD_ZERO(&w_fds);
+ FD_SET(fd, &w_fds);
+ tv.tv_sec = CONNECT_TIMEOUT - wait_time;
+ tv.tv_usec = 0;
+
+ ret = select(fd + 1, NULL, &w_fds, NULL, &tv);
+
+ if (ret > 0) {
+ errnosize = sizeof(connect_errno);
+
+ ret = getsockopt(fd, SOL_SOCKET,
+ SO_ERROR, &connect_errno, &errnosize);
+
+ if (ret >= 0 && connect_errno == 0) {
+ /* Connect succeed */
+ goto out;
+ }
+ }
+
+ slept = CONNECT_TIMEOUT;
+ break;
+ case EAGAIN:
+ slept = rand() % 3 + 1;
+ sleep(slept);
+ break;
+ default:
+ goto error_out;
+ }
+
+ }
+
+ out:
+
+ return fd;
+
+ error_out:
+
+ close(fd);
+ return -1;
+}
+
+static const char *winbindd_socket_dir(void)
+{
+#ifdef SOCKET_WRAPPER
+ const char *env_dir;
+
+ env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR);
+ if (env_dir) {
+ return env_dir;
+ }
+#endif
+
+ return WINBINDD_SOCKET_DIR;
+}
+
+/* Connect to winbindd socket */
+
+static int winbind_open_pipe_sock(int recursing, int need_priv)
+{
+#ifdef HAVE_UNIXSOCKET
+ static pid_t our_pid;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if (our_pid != getpid()) {
+ winbind_close_sock();
+ our_pid = getpid();
+ }
+
+ if ((need_priv != 0) && (is_privileged == 0)) {
+ winbind_close_sock();
+ }
+
+ if (winbindd_fd != -1) {
+ return winbindd_fd;
+ }
+
+ if (recursing) {
+ return -1;
+ }
+
+ if ((winbindd_fd = winbind_named_pipe_sock(winbindd_socket_dir())) == -1) {
+ return -1;
+ }
+
+ is_privileged = 0;
+
+ /* version-check the socket */
+
+ request.wb_flags = WBFLAG_RECURSE;
+ if ((winbindd_request_response(WINBINDD_INTERFACE_VERSION, &request, &response) != NSS_STATUS_SUCCESS) || (response.data.interface_version != WINBIND_INTERFACE_VERSION)) {
+ winbind_close_sock();
+ return -1;
+ }
+
+ /* try and get priv pipe */
+
+ request.wb_flags = WBFLAG_RECURSE;
+ if (winbindd_request_response(WINBINDD_PRIV_PIPE_DIR, &request, &response) == NSS_STATUS_SUCCESS) {
+ int fd;
+ if ((fd = winbind_named_pipe_sock((char *)response.extra_data.data)) != -1) {
+ close(winbindd_fd);
+ winbindd_fd = fd;
+ is_privileged = 1;
+ }
+ }
+
+ if ((need_priv != 0) && (is_privileged == 0)) {
+ return -1;
+ }
+
+ SAFE_FREE(response.extra_data.data);
+
+ return winbindd_fd;
+#else
+ return -1;
+#endif /* HAVE_UNIXSOCKET */
+}
+
+/* Write data to winbindd socket */
+
+int winbind_write_sock(void *buffer, int count, int recursing, int need_priv)
+{
+ int result, nwritten;
+
+ /* Open connection to winbind daemon */
+
+ restart:
+
+ if (winbind_open_pipe_sock(recursing, need_priv) == -1) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ /* Write data to socket */
+
+ nwritten = 0;
+
+ while(nwritten < count) {
+ struct timeval tv;
+ fd_set r_fds;
+
+ /* Catch pipe close on other end by checking if a read()
+ call would not block by calling select(). */
+
+ FD_ZERO(&r_fds);
+ FD_SET(winbindd_fd, &r_fds);
+ ZERO_STRUCT(tv);
+
+ if (select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv) == -1) {
+ winbind_close_sock();
+ return -1; /* Select error */
+ }
+
+ /* Write should be OK if fd not available for reading */
+
+ if (!FD_ISSET(winbindd_fd, &r_fds)) {
+
+ /* Do the write */
+
+ result = write(winbindd_fd,
+ (char *)buffer + nwritten,
+ count - nwritten);
+
+ if ((result == -1) || (result == 0)) {
+
+ /* Write failed */
+
+ winbind_close_sock();
+ return -1;
+ }
+
+ nwritten += result;
+
+ } else {
+
+ /* Pipe has closed on remote end */
+
+ winbind_close_sock();
+ goto restart;
+ }
+ }
+
+ return nwritten;
+}
+
+/* Read data from winbindd socket */
+
+int winbind_read_sock(void *buffer, int count)
+{
+ int nread = 0;
+ int total_time = 0, selret;
+
+ if (winbindd_fd == -1) {
+ return -1;
+ }
+
+ /* Read data from socket */
+ while(nread < count) {
+ struct timeval tv;
+ fd_set r_fds;
+
+ /* Catch pipe close on other end by checking if a read()
+ call would not block by calling select(). */
+
+ FD_ZERO(&r_fds);
+ FD_SET(winbindd_fd, &r_fds);
+ ZERO_STRUCT(tv);
+ /* Wait for 5 seconds for a reply. May need to parameterise this... */
+ tv.tv_sec = 5;
+
+ if ((selret = select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv)) == -1) {
+ winbind_close_sock();
+ return -1; /* Select error */
+ }
+
+ if (selret == 0) {
+ /* Not ready for read yet... */
+ if (total_time >= 30) {
+ /* Timeout */
+ winbind_close_sock();
+ return -1;
+ }
+ total_time += 5;
+ continue;
+ }
+
+ if (FD_ISSET(winbindd_fd, &r_fds)) {
+
+ /* Do the Read */
+
+ int result = read(winbindd_fd, (char *)buffer + nread,
+ count - nread);
+
+ if ((result == -1) || (result == 0)) {
+
+ /* Read failed. I think the only useful thing we
+ can do here is just return -1 and fail since the
+ transaction has failed half way through. */
+
+ winbind_close_sock();
+ return -1;
+ }
+
+ nread += result;
+
+ }
+ }
+
+ return nread;
+}
+
+/* Read reply */
+
+int winbindd_read_reply(struct winbindd_response *response)
+{
+ int result1, result2 = 0;
+
+ if (!response) {
+ return -1;
+ }
+
+ /* Read fixed length response */
+
+ result1 = winbind_read_sock(response,
+ sizeof(struct winbindd_response));
+ if (result1 == -1) {
+ return -1;
+ }
+
+ /* We actually send the pointer value of the extra_data field from
+ the server. This has no meaning in the client's address space
+ so we clear it out. */
+
+ response->extra_data.data = NULL;
+
+ /* Read variable length response */
+
+ if (response->length > sizeof(struct winbindd_response)) {
+ int extra_data_len = response->length -
+ sizeof(struct winbindd_response);
+
+ /* Mallocate memory for extra data */
+
+ if (!(response->extra_data.data = malloc(extra_data_len))) {
+ return -1;
+ }
+
+ result2 = winbind_read_sock(response->extra_data.data,
+ extra_data_len);
+ if (result2 == -1) {
+ winbindd_free_response(response);
+ return -1;
+ }
+ }
+
+ /* Return total amount of data read */
+
+ return result1 + result2;
+}
+
+/*
+ * send simple types of requests
+ */
+
+NSS_STATUS winbindd_send_request(int req_type, int need_priv,
+ struct winbindd_request *request)
+{
+ struct winbindd_request lrequest;
+
+ /* Check for our tricky environment variable */
+
+ if (winbind_env_set()) {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ if (!request) {
+ ZERO_STRUCT(lrequest);
+ request = &lrequest;
+ }
+
+ /* Fill in request and send down pipe */
+
+ winbindd_init_request(request, req_type);
+
+ if (winbind_write_sock(request, sizeof(*request),
+ request->wb_flags & WBFLAG_RECURSE,
+ need_priv) == -1)
+ {
+ /* Set ENOENT for consistency. Required by some apps */
+ errno = ENOENT;
+
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ if ((request->extra_len != 0) &&
+ (winbind_write_sock(request->extra_data.data,
+ request->extra_len,
+ request->wb_flags & WBFLAG_RECURSE,
+ need_priv) == -1))
+ {
+ /* Set ENOENT for consistency. Required by some apps */
+ errno = ENOENT;
+
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/*
+ * Get results from winbindd request
+ */
+
+NSS_STATUS winbindd_get_response(struct winbindd_response *response)
+{
+ struct winbindd_response lresponse;
+
+ if (!response) {
+ ZERO_STRUCT(lresponse);
+ response = &lresponse;
+ }
+
+ init_response(response);
+
+ /* Wait for reply */
+ if (winbindd_read_reply(response) == -1) {
+ /* Set ENOENT for consistency. Required by some apps */
+ errno = ENOENT;
+
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ /* Throw away extra data if client didn't request it */
+ if (response == &lresponse) {
+ winbindd_free_response(response);
+ }
+
+ /* Copy reply data from socket */
+ if (response->result != WINBINDD_OK) {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/* Handle simple types of requests */
+
+NSS_STATUS winbindd_request_response(int req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response)
+{
+ NSS_STATUS status = NSS_STATUS_UNAVAIL;
+ int count = 0;
+
+ while ((status == NSS_STATUS_UNAVAIL) && (count < 10)) {
+ status = winbindd_send_request(req_type, 0, request);
+ if (status != NSS_STATUS_SUCCESS)
+ return(status);
+ status = winbindd_get_response(response);
+ count += 1;
+ }
+
+ return status;
+}
+
+NSS_STATUS winbindd_priv_request_response(int req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response)
+{
+ NSS_STATUS status = NSS_STATUS_UNAVAIL;
+ int count = 0;
+
+ while ((status == NSS_STATUS_UNAVAIL) && (count < 10)) {
+ status = winbindd_send_request(req_type, 1, request);
+ if (status != NSS_STATUS_SUCCESS)
+ return(status);
+ status = winbindd_get_response(response);
+ count += 1;
+ }
+
+ return status;
+}
+
+/*************************************************************************
+ ************************************************************************/
+
+const char *nss_err_str(NSS_STATUS ret)
+{
+ switch (ret) {
+ case NSS_STATUS_TRYAGAIN:
+ return "NSS_STATUS_TRYAGAIN";
+ case NSS_STATUS_SUCCESS:
+ return "NSS_STATUS_SUCCESS";
+ case NSS_STATUS_NOTFOUND:
+ return "NSS_STATUS_NOTFOUND";
+ case NSS_STATUS_UNAVAIL:
+ return "NSS_STATUS_UNAVAIL";
+#ifdef NSS_STATUS_RETURN
+ case NSS_STATUS_RETURN:
+ return "NSS_STATUS_RETURN";
+#endif
+ default:
+ return "UNKNOWN RETURN CODE!!!!!!!";
+ }
+}
diff --git a/source3/nsswitch/wbinfo.c b/source3/nsswitch/wbinfo.c
new file mode 100644
index 0000000000..60524d1d1b
--- /dev/null
+++ b/source3/nsswitch/wbinfo.c
@@ -0,0 +1,1763 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind status program.
+
+ Copyright (C) Tim Potter 2000-2003
+ Copyright (C) Andrew Bartlett 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbind_client.h"
+#include "libwbclient/wbclient.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+static struct wbcInterfaceDetails *init_interface_details(void)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ static struct wbcInterfaceDetails *details;
+
+ if (details) {
+ return details;
+ }
+
+ wbc_status = wbcInterfaceDetails(&details);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ d_fprintf(stderr, "could not obtain winbind interface details!\n");
+ }
+
+ return details;
+}
+
+static char winbind_separator_int(bool strict)
+{
+ struct wbcInterfaceDetails *details;
+ static bool got_sep;
+ static char sep;
+
+ if (got_sep)
+ return sep;
+
+ details = init_interface_details();
+
+ if (!details) {
+ d_fprintf(stderr, "could not obtain winbind separator!\n");
+ if (strict) {
+ return 0;
+ }
+ /* HACK: (this module should not call lp_ funtions) */
+ return *lp_winbind_separator();
+ }
+
+ sep = details->winbind_separator;
+ got_sep = true;
+
+ if (!sep) {
+ d_fprintf(stderr, "winbind separator was NULL!\n");
+ if (strict) {
+ return 0;
+ }
+ /* HACK: (this module should not call lp_ funtions) */
+ sep = *lp_winbind_separator();
+ }
+
+ return sep;
+}
+
+static char winbind_separator(void)
+{
+ return winbind_separator_int(false);
+}
+
+static const char *get_winbind_domain(void)
+{
+ static struct wbcInterfaceDetails *details;
+
+ details = init_interface_details();
+
+ if (!details) {
+ d_fprintf(stderr, "could not obtain winbind domain name!\n");
+
+ /* HACK: (this module should not call lp_ functions) */
+ return lp_workgroup();
+ }
+
+ return details->netbios_domain;
+}
+
+/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
+ form DOMAIN/user into a domain and a user */
+
+static bool parse_wbinfo_domain_user(const char *domuser, fstring domain,
+ fstring user)
+{
+
+ char *p = strchr(domuser,winbind_separator());
+
+ if (!p) {
+ /* Maybe it was a UPN? */
+ if ((p = strchr(domuser, '@')) != NULL) {
+ fstrcpy(domain, "");
+ fstrcpy(user, domuser);
+ return true;
+ }
+
+ fstrcpy(user, domuser);
+ fstrcpy(domain, get_winbind_domain());
+ return true;
+ }
+
+ fstrcpy(user, p+1);
+ fstrcpy(domain, domuser);
+ domain[PTR_DIFF(p, domuser)] = 0;
+ strupper_m(domain);
+
+ return true;
+}
+
+/* pull pwent info for a given user */
+
+static bool wbinfo_get_userinfo(char *user)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct passwd *pwd = NULL;
+
+ wbc_status = wbcGetpwnam(user, &pwd);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ d_printf("%s:%s:%d:%d:%s:%s:%s\n",
+ pwd->pw_name,
+ pwd->pw_passwd,
+ pwd->pw_uid,
+ pwd->pw_gid,
+ pwd->pw_gecos,
+ pwd->pw_dir,
+ pwd->pw_shell);
+
+ return true;
+}
+
+/* pull pwent info for a given uid */
+static bool wbinfo_get_uidinfo(int uid)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct passwd *pwd = NULL;
+
+ wbc_status = wbcGetpwuid(uid, &pwd);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ d_printf("%s:%s:%d:%d:%s:%s:%s\n",
+ pwd->pw_name,
+ pwd->pw_passwd,
+ pwd->pw_uid,
+ pwd->pw_gid,
+ pwd->pw_gecos,
+ pwd->pw_dir,
+ pwd->pw_shell);
+
+ return true;
+}
+
+/* pull grent for a given group */
+static bool wbinfo_get_groupinfo(const char *group)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct group *grp;
+
+ wbc_status = wbcGetgrnam(group, &grp);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ d_printf("%s:%s:%d\n",
+ grp->gr_name,
+ grp->gr_passwd,
+ grp->gr_gid);
+
+ wbcFreeMemory(grp);
+
+ return true;
+}
+
+/* List groups a user is a member of */
+
+static bool wbinfo_get_usergroups(const char *user)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ uint32_t num_groups;
+ uint32_t i;
+ gid_t *groups = NULL;
+
+ /* Send request */
+
+ wbc_status = wbcGetGroups(user, &num_groups, &groups);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ for (i = 0; i < num_groups; i++) {
+ d_printf("%d\n", (int)groups[i]);
+ }
+
+ wbcFreeMemory(groups);
+
+ return true;
+}
+
+
+/* List group SIDs a user SID is a member of */
+static bool wbinfo_get_usersids(const char *user_sid_str)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ uint32_t num_sids;
+ uint32_t i;
+ struct wbcDomainSid user_sid, *sids = NULL;
+
+ /* Send request */
+
+ wbc_status = wbcStringToSid(user_sid_str, &user_sid);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ wbc_status = wbcLookupUserSids(&user_sid, false, &num_sids, &sids);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ for (i = 0; i < num_sids; i++) {
+ char *str = NULL;
+ wbc_status = wbcSidToString(&sids[i], &str);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ wbcFreeMemory(sids);
+ return false;
+ }
+ d_printf("%s\n", str);
+ wbcFreeMemory(str);
+ }
+
+ wbcFreeMemory(sids);
+
+ return true;
+}
+
+static bool wbinfo_get_userdomgroups(const char *user_sid_str)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ uint32_t num_sids;
+ uint32_t i;
+ struct wbcDomainSid user_sid, *sids = NULL;
+
+ /* Send request */
+
+ wbc_status = wbcStringToSid(user_sid_str, &user_sid);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ wbc_status = wbcLookupUserSids(&user_sid, true, &num_sids, &sids);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ for (i = 0; i < num_sids; i++) {
+ char *str = NULL;
+ wbc_status = wbcSidToString(&sids[i], &str);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ wbcFreeMemory(sids);
+ return false;
+ }
+ d_printf("%s\n", str);
+ wbcFreeMemory(str);
+ }
+
+ wbcFreeMemory(sids);
+
+ return true;
+}
+
+/* Convert NetBIOS name to IP */
+
+static bool wbinfo_wins_byname(const char *name)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ char *ip = NULL;
+
+ wbc_status = wbcResolveWinsByName(name, &ip);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ /* Display response */
+
+ d_printf("%s\n", ip);
+
+ wbcFreeMemory(ip);
+
+ return true;
+}
+
+/* Convert IP to NetBIOS name */
+
+static bool wbinfo_wins_byip(const char *ip)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ char *name = NULL;
+
+ wbc_status = wbcResolveWinsByIP(ip, &name);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ /* Display response */
+
+ d_printf("%s\n", name);
+
+ wbcFreeMemory(name);
+
+ return true;
+}
+
+/* List all/trusted domains */
+
+static bool wbinfo_list_domains(bool list_all_domains, bool verbose)
+{
+ struct wbcDomainInfo *domain_list = NULL;
+ size_t num_domains;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ bool print_all = !list_all_domains && verbose;
+ int i;
+
+ wbc_status = wbcListTrusts(&domain_list, &num_domains);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ if (print_all) {
+ d_printf("%-16s%-24s%-12s%-12s%-5s%-5s\n",
+ "Domain Name", "DNS Domain", "Trust Type",
+ "Transitive", "In", "Out");
+ }
+
+ for (i=0; i<num_domains; i++) {
+ if (print_all) {
+ d_printf("%-16s", domain_list[i].short_name);
+ } else {
+ d_printf("%s", domain_list[i].short_name);
+ d_printf("\n");
+ continue;
+ }
+
+ d_printf("%-24s", domain_list[i].dns_name);
+
+ switch(domain_list[i].trust_type) {
+ case WBC_DOMINFO_TRUSTTYPE_NONE:
+ d_printf("None ");
+ break;
+ case WBC_DOMINFO_TRUSTTYPE_FOREST:
+ d_printf("Forest ");
+ break;
+ case WBC_DOMINFO_TRUSTTYPE_EXTERNAL:
+ d_printf("External ");
+ break;
+ case WBC_DOMINFO_TRUSTTYPE_IN_FOREST:
+ d_printf("In-Forest ");
+ break;
+ }
+
+ if (domain_list[i].trust_flags & WBC_DOMINFO_TRUST_TRANSITIVE) {
+ d_printf("Yes ");
+ } else {
+ d_printf("No ");
+ }
+
+ if (domain_list[i].trust_flags & WBC_DOMINFO_TRUST_INCOMING) {
+ d_printf("Yes ");
+ } else {
+ d_printf("No ");
+ }
+
+ if (domain_list[i].trust_flags & WBC_DOMINFO_TRUST_OUTGOING) {
+ d_printf("Yes ");
+ } else {
+ d_printf("No ");
+ }
+
+ d_printf("\n");
+ }
+
+ return true;
+}
+
+/* List own domain */
+
+static bool wbinfo_list_own_domain(void)
+{
+ d_printf("%s\n", get_winbind_domain());
+
+ return true;
+}
+
+/* show sequence numbers */
+static bool wbinfo_show_sequence(const char *domain)
+{
+ d_printf("This command has been deprecated. Please use the --online-status option instead.\n");
+ return false;
+}
+
+/* show sequence numbers */
+static bool wbinfo_show_onlinestatus(const char *domain)
+{
+ struct wbcDomainInfo *domain_list = NULL;
+ size_t num_domains;
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ int i;
+
+ wbc_status = wbcListTrusts(&domain_list, &num_domains);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ for (i=0; i<num_domains; i++) {
+ bool is_offline;
+
+ if (domain) {
+ if (!strequal(domain_list[i].short_name, domain)) {
+ continue;
+ }
+ }
+
+ is_offline = (domain_list[i].domain_flags & WBC_DOMINFO_DOMAIN_OFFLINE);
+
+ d_printf("%s : %s\n",
+ domain_list[i].short_name,
+ is_offline ? "offline" : "online" );
+ }
+
+ return true;
+}
+
+
+/* Show domain info */
+
+static bool wbinfo_domain_info(const char *domain)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct wbcDomainInfo *dinfo = NULL;
+ char *sid_str = NULL;
+
+ if ((domain == NULL) || (strequal(domain, ".")) || (domain[0] == '\0')) {
+ domain = get_winbind_domain();
+ }
+
+ /* Send request */
+
+ wbc_status = wbcDomainInfo(domain, &dinfo);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ wbc_status = wbcSidToString(&dinfo->sid, &sid_str);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ wbcFreeMemory(dinfo);
+ return false;
+ }
+
+ /* Display response */
+
+ d_printf("Name : %s\n", dinfo->short_name);
+ d_printf("Alt_Name : %s\n", dinfo->dns_name);
+
+ d_printf("SID : %s\n", sid_str);
+
+ d_printf("Active Directory : %s\n",
+ (dinfo->domain_flags & WBC_DOMINFO_DOMAIN_AD) ? "Yes" : "No");
+ d_printf("Native : %s\n",
+ (dinfo->domain_flags & WBC_DOMINFO_DOMAIN_NATIVE) ? "Yes" : "No");
+
+ d_printf("Primary : %s\n",
+ (dinfo->domain_flags & WBC_DOMINFO_DOMAIN_PRIMARY) ? "Yes" : "No");
+
+ wbcFreeMemory(sid_str);
+ wbcFreeMemory(dinfo);
+
+ return true;
+}
+
+/* Get a foreign DC's name */
+static bool wbinfo_getdcname(const char *domain_name)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.domain_name, domain_name);
+
+ /* Send request */
+
+ if (winbindd_request_response(WINBINDD_GETDCNAME, &request, &response) !=
+ NSS_STATUS_SUCCESS) {
+ d_fprintf(stderr, "Could not get dc name for %s\n", domain_name);
+ return false;
+ }
+
+ /* Display response */
+
+ d_printf("%s\n", response.data.dc_name);
+
+ return true;
+}
+
+/* Find a DC */
+static bool wbinfo_dsgetdcname(const char *domain_name, uint32_t flags)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.domain_name, domain_name);
+ request.flags = flags;
+
+ request.flags |= DS_DIRECTORY_SERVICE_REQUIRED;
+
+ /* Send request */
+
+ if (winbindd_request_response(WINBINDD_DSGETDCNAME, &request, &response) !=
+ NSS_STATUS_SUCCESS) {
+ d_fprintf(stderr, "Could not find dc for %s\n", domain_name);
+ return false;
+ }
+
+ /* Display response */
+
+ d_printf("%s\n", response.data.dc_name);
+
+ return true;
+}
+
+/* Check trust account password */
+
+static bool wbinfo_check_secret(void)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct wbcAuthErrorInfo *error = NULL;
+
+ wbc_status = wbcCheckTrustCredentials(NULL, &error);
+
+ d_printf("checking the trust secret via RPC calls %s\n",
+ WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed");
+
+ if (wbc_status == WBC_ERR_AUTH_ERROR) {
+ d_fprintf(stderr, "error code was %s (0x%x)\n",
+ error->nt_string, error->nt_status);
+ wbcFreeMemory(error);
+ }
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ return true;
+}
+
+/* Convert uid to sid */
+
+static bool wbinfo_uid_to_sid(uid_t uid)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct wbcDomainSid sid;
+ char *sid_str = NULL;
+
+ /* Send request */
+
+ wbc_status = wbcUidToSid(uid, &sid);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ wbc_status = wbcSidToString(&sid, &sid_str);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ /* Display response */
+
+ d_printf("%s\n", sid_str);
+
+ wbcFreeMemory(sid_str);
+
+ return true;
+}
+
+/* Convert gid to sid */
+
+static bool wbinfo_gid_to_sid(gid_t gid)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct wbcDomainSid sid;
+ char *sid_str = NULL;
+
+ /* Send request */
+
+ wbc_status = wbcGidToSid(gid, &sid);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ wbc_status = wbcSidToString(&sid, &sid_str);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ /* Display response */
+
+ d_printf("%s\n", sid_str);
+
+ wbcFreeMemory(sid_str);
+
+ return true;
+}
+
+/* Convert sid to uid */
+
+static bool wbinfo_sid_to_uid(const char *sid_str)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct wbcDomainSid sid;
+ uid_t uid;
+
+ /* Send request */
+
+ wbc_status = wbcStringToSid(sid_str, &sid);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ wbc_status = wbcSidToUid(&sid, &uid);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ /* Display response */
+
+ d_printf("%d\n", (int)uid);
+
+ return true;
+}
+
+static bool wbinfo_sid_to_gid(const char *sid_str)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct wbcDomainSid sid;
+ gid_t gid;
+
+ /* Send request */
+
+ wbc_status = wbcStringToSid(sid_str, &sid);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ wbc_status = wbcSidToGid(&sid, &gid);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ /* Display response */
+
+ d_printf("%d\n", (int)gid);
+
+ return true;
+}
+
+static bool wbinfo_allocate_uid(void)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ uid_t uid;
+
+ /* Send request */
+
+ wbc_status = wbcAllocateUid(&uid);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ /* Display response */
+
+ d_printf("New uid: %d\n", uid);
+
+ return true;
+}
+
+static bool wbinfo_allocate_gid(void)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ gid_t gid;
+
+ /* Send request */
+
+ wbc_status = wbcAllocateGid(&gid);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ /* Display response */
+
+ d_printf("New gid: %d\n", gid);
+
+ return true;
+}
+
+/* Convert sid to string */
+
+static bool wbinfo_lookupsid(const char *sid_str)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct wbcDomainSid sid;
+ char *domain;
+ char *name;
+ enum wbcSidType type;
+
+ /* Send off request */
+
+ wbc_status = wbcStringToSid(sid_str, &sid);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ wbc_status = wbcLookupSid(&sid, &domain, &name, &type);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ /* Display response */
+
+ d_printf("%s%c%s %d\n",
+ domain, winbind_separator(), name, type);
+
+ return true;
+}
+
+/* Lookup a list of RIDs */
+
+static bool wbinfo_lookuprids(const char *domain, const char *arg)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct wbcDomainInfo *dinfo = NULL;
+ char *domain_name = NULL;
+ const char **names = NULL;
+ enum wbcSidType *types = NULL;
+ size_t i;
+ int num_rids;
+ uint32 *rids = NULL;
+ const char *p;
+ char *ridstr;
+ TALLOC_CTX *mem_ctx = NULL;
+ bool ret = false;
+
+ if ((domain == NULL) || (strequal(domain, ".")) || (domain[0] == '\0')) {
+ domain = get_winbind_domain();
+ }
+
+ /* Send request */
+
+ wbc_status = wbcDomainInfo(domain, &dinfo);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ d_printf("wbcDomainInfo(%s) failed: %s\n", domain,
+ wbcErrorString(wbc_status));
+ goto done;
+ }
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ d_printf("talloc_new failed\n");
+ goto done;
+ }
+
+ num_rids = 0;
+ rids = NULL;
+ p = arg;
+
+ while (next_token_talloc(mem_ctx, &p, &ridstr, " ,\n")) {
+ uint32 rid = strtoul(ridstr, NULL, 10);
+ ADD_TO_ARRAY(mem_ctx, uint32, rid, &rids, &num_rids);
+ }
+
+ if (rids == NULL) {
+ d_printf("no rids\n");
+ goto done;
+ }
+
+ wbc_status = wbcLookupRids(&dinfo->sid, num_rids, rids,
+ (const char **)&domain_name, &names, &types);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ d_printf("winbind_lookup_rids failed: %s\n",
+ wbcErrorString(wbc_status));
+ goto done;
+ }
+
+ d_printf("Domain: %s\n", domain_name);
+
+ for (i=0; i<num_rids; i++) {
+ d_printf("%8d: %s (%s)\n", rids[i], names[i],
+ sid_type_lookup(types[i]));
+ }
+
+ ret = true;
+done:
+ if (dinfo) {
+ wbcFreeMemory(dinfo);
+ }
+ if (domain_name) {
+ wbcFreeMemory(domain_name);
+ }
+ if (names) {
+ wbcFreeMemory(names);
+ }
+ if (types) {
+ wbcFreeMemory(types);
+ }
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+/* Convert string to sid */
+
+static bool wbinfo_lookupname(const char *full_name)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct wbcDomainSid sid;
+ char *sid_str;
+ enum wbcSidType type;
+ fstring domain_name;
+ fstring account_name;
+
+ /* Send off request */
+
+ parse_wbinfo_domain_user(full_name, domain_name,
+ account_name);
+
+ wbc_status = wbcLookupName(domain_name, account_name,
+ &sid, &type);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ wbc_status = wbcSidToString(&sid, &sid_str);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ /* Display response */
+
+ d_printf("%s %s (%d)\n", sid_str, sid_type_lookup(type), type);
+
+ wbcFreeMemory(sid_str);
+
+ return true;
+}
+
+static char *wbinfo_prompt_pass(const char *prefix,
+ const char *username)
+{
+ char *prompt;
+ const char *ret = NULL;
+
+ prompt = talloc_asprintf(talloc_tos(), "Enter %s's ", username);
+ if (!prompt) {
+ return NULL;
+ }
+ if (prefix) {
+ prompt = talloc_asprintf_append(prompt, "%s ", prefix);
+ if (!prompt) {
+ return NULL;
+ }
+ }
+ prompt = talloc_asprintf_append(prompt, "password: ");
+ if (!prompt) {
+ return NULL;
+ }
+
+ ret = getpass(prompt);
+ TALLOC_FREE(prompt);
+
+ return SMB_STRDUP(ret);
+}
+
+/* Authenticate a user with a plaintext password */
+
+static bool wbinfo_auth_krb5(char *username, const char *cctype, uint32 flags)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+ char *p;
+ char *password;
+
+ /* Send off request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ p = strchr(username, '%');
+
+ if (p) {
+ *p = 0;
+ fstrcpy(request.data.auth.user, username);
+ fstrcpy(request.data.auth.pass, p + 1);
+ *p = '%';
+ } else {
+ fstrcpy(request.data.auth.user, username);
+ password = wbinfo_prompt_pass(NULL, username);
+ fstrcpy(request.data.auth.pass, password);
+ SAFE_FREE(password);
+ }
+
+ request.flags = flags;
+
+ fstrcpy(request.data.auth.krb5_cc_type, cctype);
+
+ request.data.auth.uid = geteuid();
+
+ result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
+
+ /* Display response */
+
+ d_printf("plaintext kerberos password authentication for [%s] %s (requesting cctype: %s)\n",
+ username, (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed", cctype);
+
+ if (response.data.auth.nt_status)
+ d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n",
+ response.data.auth.nt_status_string,
+ response.data.auth.nt_status,
+ response.data.auth.error_string);
+
+ if (result == NSS_STATUS_SUCCESS) {
+
+ if (request.flags & WBFLAG_PAM_INFO3_TEXT) {
+ if (response.data.auth.info3.user_flgs & NETLOGON_CACHED_ACCOUNT) {
+ d_printf("user_flgs: NETLOGON_CACHED_ACCOUNT\n");
+ }
+ }
+
+ if (response.data.auth.krb5ccname[0] != '\0') {
+ d_printf("credentials were put in: %s\n", response.data.auth.krb5ccname);
+ } else {
+ d_printf("no credentials cached\n");
+ }
+ }
+
+ return result == NSS_STATUS_SUCCESS;
+}
+
+/* Authenticate a user with a plaintext password */
+
+static bool wbinfo_auth(char *username)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ char *s = NULL;
+ char *p = NULL;
+ char *password = NULL;
+ char *name = NULL;
+
+ if ((s = SMB_STRDUP(username)) == NULL) {
+ return false;
+ }
+
+ if ((p = strchr(s, '%')) != NULL) {
+ *p = 0;
+ p++;
+ password = SMB_STRDUP(p);
+ } else {
+ password = wbinfo_prompt_pass(NULL, username);
+ }
+
+ name = s;
+
+ wbc_status = wbcAuthenticateUser(name, password);
+
+ d_printf("plaintext password authentication %s\n",
+ WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed");
+
+#if 0
+ if (response.data.auth.nt_status)
+ d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n",
+ response.data.auth.nt_status_string,
+ response.data.auth.nt_status,
+ response.data.auth.error_string);
+#endif
+
+ SAFE_FREE(s);
+ SAFE_FREE(password);
+
+ return WBC_ERROR_IS_OK(wbc_status);
+}
+
+/* Authenticate a user with a challenge/response */
+
+static bool wbinfo_auth_crap(char *username)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ struct wbcAuthUserParams params;
+ struct wbcAuthUserInfo *info = NULL;
+ struct wbcAuthErrorInfo *err = NULL;
+ DATA_BLOB lm = data_blob_null;
+ DATA_BLOB nt = data_blob_null;
+ fstring name_user;
+ fstring name_domain;
+ char *pass;
+ char *p;
+
+ p = strchr(username, '%');
+
+ if (p) {
+ *p = 0;
+ pass = SMB_STRDUP(p + 1);
+ } else {
+ pass = wbinfo_prompt_pass(NULL, username);
+ }
+
+ parse_wbinfo_domain_user(username, name_domain, name_user);
+
+ params.account_name = name_user;
+ params.domain_name = name_domain;
+ params.workstation_name = NULL;
+
+ params.flags = 0;
+ params.parameter_control= WBC_MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT |
+ WBC_MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
+
+ params.level = WBC_AUTH_USER_LEVEL_RESPONSE;
+
+ generate_random_buffer(params.password.response.challenge, 8);
+
+ if (lp_client_ntlmv2_auth()) {
+ DATA_BLOB server_chal;
+ DATA_BLOB names_blob;
+
+ server_chal = data_blob(params.password.response.challenge, 8);
+
+ /* Pretend this is a login to 'us', for blob purposes */
+ names_blob = NTLMv2_generate_names_blob(global_myname(), lp_workgroup());
+
+ if (!SMBNTLMv2encrypt(name_user, name_domain, pass, &server_chal,
+ &names_blob,
+ &lm, &nt, NULL)) {
+ data_blob_free(&names_blob);
+ data_blob_free(&server_chal);
+ SAFE_FREE(pass);
+ return false;
+ }
+ data_blob_free(&names_blob);
+ data_blob_free(&server_chal);
+
+ } else {
+ if (lp_client_lanman_auth()) {
+ bool ok;
+ lm = data_blob(NULL, 24);
+ ok = SMBencrypt(pass, params.password.response.challenge,
+ lm.data);
+ if (!ok) {
+ data_blob_free(&lm);
+ }
+ }
+ nt = data_blob(NULL, 24);
+ SMBNTencrypt(pass, params.password.response.challenge,
+ nt.data);
+ }
+
+ params.password.response.nt_length = nt.length;
+ params.password.response.nt_data = nt.data;
+ params.password.response.lm_length = lm.length;
+ params.password.response.lm_data = lm.data;
+
+ wbc_status = wbcAuthenticateUserEx(&params, &info, &err);
+
+ /* Display response */
+
+ d_printf("challenge/response password authentication %s\n",
+ WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed");
+
+ if (wbc_status == WBC_ERR_AUTH_ERROR) {
+ d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n",
+ err->nt_string,
+ err->nt_status,
+ err->display_string);
+ wbcFreeMemory(err);
+ } else if (WBC_ERROR_IS_OK(wbc_status)) {
+ wbcFreeMemory(info);
+ }
+
+ data_blob_free(&nt);
+ data_blob_free(&lm);
+ SAFE_FREE(pass);
+
+ return WBC_ERROR_IS_OK(wbc_status);
+}
+
+/* Authenticate a user with a plaintext password and set a token */
+
+static bool wbinfo_klog(char *username)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+ char *p;
+
+ /* Send off request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ p = strchr(username, '%');
+
+ if (p) {
+ *p = 0;
+ fstrcpy(request.data.auth.user, username);
+ fstrcpy(request.data.auth.pass, p + 1);
+ *p = '%';
+ } else {
+ fstrcpy(request.data.auth.user, username);
+ fstrcpy(request.data.auth.pass, getpass("Password: "));
+ }
+
+ request.flags |= WBFLAG_PAM_AFS_TOKEN;
+
+ result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
+
+ /* Display response */
+
+ d_printf("plaintext password authentication %s\n",
+ (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed");
+
+ if (response.data.auth.nt_status)
+ d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n",
+ response.data.auth.nt_status_string,
+ response.data.auth.nt_status,
+ response.data.auth.error_string);
+
+ if (result != NSS_STATUS_SUCCESS)
+ return false;
+
+ if (response.extra_data.data == NULL) {
+ d_fprintf(stderr, "Did not get token data\n");
+ return false;
+ }
+
+ if (!afs_settoken_str((char *)response.extra_data.data)) {
+ d_fprintf(stderr, "Could not set token\n");
+ return false;
+ }
+
+ d_printf("Successfully created AFS token\n");
+ return true;
+}
+
+/* Print domain users */
+
+static bool print_domain_users(const char *domain)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ uint32_t i;
+ uint32_t num_users = 0;
+ const char **users = NULL;
+
+ /* Send request to winbind daemon */
+
+ /* '.' is the special sign for our own domain */
+ if (domain && strcmp(domain, ".") == 0) {
+ domain = get_winbind_domain();
+ }
+
+ wbc_status = wbcListUsers(domain, &num_users, &users);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ for (i=0; i < num_users; i++) {
+ d_printf("%s\n", users[i]);
+ }
+
+ wbcFreeMemory(users);
+
+ return true;
+}
+
+/* Print domain groups */
+
+static bool print_domain_groups(const char *domain)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ uint32_t i;
+ uint32_t num_groups = 0;
+ const char **groups = NULL;
+
+ /* Send request to winbind daemon */
+
+ /* '.' is the special sign for our own domain */
+ if (domain && strcmp(domain, ".") == 0) {
+ domain = get_winbind_domain();
+ }
+
+ wbc_status = wbcListGroups(domain, &num_groups, &groups);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ for (i=0; i < num_groups; i++) {
+ d_printf("%s\n", groups[i]);
+ }
+
+ wbcFreeMemory(groups);
+
+ return true;
+}
+
+/* Set the authorised user for winbindd access in secrets.tdb */
+
+static bool wbinfo_set_auth_user(char *username)
+{
+ const char *password;
+ char *p;
+ fstring user, domain;
+
+ /* Separate into user and password */
+
+ parse_wbinfo_domain_user(username, domain, user);
+
+ p = strchr(user, '%');
+
+ if (p != NULL) {
+ *p = 0;
+ password = p+1;
+ } else {
+ char *thepass = getpass("Password: ");
+ if (thepass) {
+ password = thepass;
+ } else
+ password = "";
+ }
+
+ /* Store or remove DOMAIN\username%password in secrets.tdb */
+
+ secrets_init();
+
+ if (user[0]) {
+
+ if (!secrets_store(SECRETS_AUTH_USER, user,
+ strlen(user) + 1)) {
+ d_fprintf(stderr, "error storing username\n");
+ return false;
+ }
+
+ /* We always have a domain name added by the
+ parse_wbinfo_domain_user() function. */
+
+ if (!secrets_store(SECRETS_AUTH_DOMAIN, domain,
+ strlen(domain) + 1)) {
+ d_fprintf(stderr, "error storing domain name\n");
+ return false;
+ }
+
+ } else {
+ secrets_delete(SECRETS_AUTH_USER);
+ secrets_delete(SECRETS_AUTH_DOMAIN);
+ }
+
+ if (password[0]) {
+
+ if (!secrets_store(SECRETS_AUTH_PASSWORD, password,
+ strlen(password) + 1)) {
+ d_fprintf(stderr, "error storing password\n");
+ return false;
+ }
+
+ } else
+ secrets_delete(SECRETS_AUTH_PASSWORD);
+
+ return true;
+}
+
+static void wbinfo_get_auth_user(void)
+{
+ char *user, *domain, *password;
+
+ /* Lift data from secrets file */
+
+ secrets_fetch_ipc_userpass(&user, &domain, &password);
+
+ if ((!user || !*user) && (!domain || !*domain ) && (!password || !*password)){
+
+ SAFE_FREE(user);
+ SAFE_FREE(domain);
+ SAFE_FREE(password);
+ d_printf("No authorised user configured\n");
+ return;
+ }
+
+ /* Pretty print authorised user info */
+
+ d_printf("%s%s%s%s%s\n", domain ? domain : "", domain ? lp_winbind_separator(): "",
+ user, password ? "%" : "", password ? password : "");
+
+ SAFE_FREE(user);
+ SAFE_FREE(domain);
+ SAFE_FREE(password);
+}
+
+static bool wbinfo_ping(void)
+{
+ wbcErr wbc_status;
+
+ wbc_status = wbcPing();
+
+ /* Display response */
+
+ d_printf("Ping to winbindd %s\n",
+ WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed");
+
+ return WBC_ERROR_IS_OK(wbc_status);
+}
+
+static bool wbinfo_change_user_password(const char *username)
+{
+ wbcErr wbc_status;
+ char *old_password = NULL;
+ char *new_password = NULL;
+
+ old_password = wbinfo_prompt_pass("old", username);
+ new_password = wbinfo_prompt_pass("new", username);
+
+ wbc_status = wbcChangeUserPassword(username, old_password, new_password);
+
+ /* Display response */
+
+ d_printf("Password change for user %s %s\n", username,
+ WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed");
+
+ SAFE_FREE(old_password);
+ SAFE_FREE(new_password);
+
+ return WBC_ERROR_IS_OK(wbc_status);
+}
+
+/* Main program */
+
+enum {
+ OPT_SET_AUTH_USER = 1000,
+ OPT_GET_AUTH_USER,
+ OPT_DOMAIN_NAME,
+ OPT_SEQUENCE,
+ OPT_GETDCNAME,
+ OPT_DSGETDCNAME,
+ OPT_USERDOMGROUPS,
+ OPT_USERSIDS,
+ OPT_ALLOCATE_UID,
+ OPT_ALLOCATE_GID,
+ OPT_SEPARATOR,
+ OPT_LIST_ALL_DOMAINS,
+ OPT_LIST_OWN_DOMAIN,
+ OPT_UID_INFO,
+ OPT_GROUP_INFO,
+ OPT_VERBOSE,
+ OPT_ONLINESTATUS,
+ OPT_CHANGE_USER_PASSWORD
+};
+
+int main(int argc, char **argv, char **envp)
+{
+ int opt;
+ TALLOC_CTX *frame = talloc_stackframe();
+ poptContext pc;
+ static char *string_arg;
+ static char *opt_domain_name;
+ static int int_arg;
+ int result = 1;
+ bool verbose = false;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+
+ /* longName, shortName, argInfo, argPtr, value, descrip,
+ argDesc */
+
+ { "domain-users", 'u', POPT_ARG_NONE, 0, 'u', "Lists all domain users", "domain"},
+ { "domain-groups", 'g', POPT_ARG_NONE, 0, 'g', "Lists all domain groups", "domain" },
+ { "WINS-by-name", 'N', POPT_ARG_STRING, &string_arg, 'N', "Converts NetBIOS name to IP", "NETBIOS-NAME" },
+ { "WINS-by-ip", 'I', POPT_ARG_STRING, &string_arg, 'I', "Converts IP address to NetBIOS name", "IP" },
+ { "name-to-sid", 'n', POPT_ARG_STRING, &string_arg, 'n', "Converts name to sid", "NAME" },
+ { "sid-to-name", 's', POPT_ARG_STRING, &string_arg, 's', "Converts sid to name", "SID" },
+ { "lookup-rids", 'R', POPT_ARG_STRING, &string_arg, 'R', "Converts RIDs to names", "RIDs" },
+ { "uid-to-sid", 'U', POPT_ARG_INT, &int_arg, 'U', "Converts uid to sid" , "UID" },
+ { "gid-to-sid", 'G', POPT_ARG_INT, &int_arg, 'G', "Converts gid to sid", "GID" },
+ { "sid-to-uid", 'S', POPT_ARG_STRING, &string_arg, 'S', "Converts sid to uid", "SID" },
+ { "sid-to-gid", 'Y', POPT_ARG_STRING, &string_arg, 'Y', "Converts sid to gid", "SID" },
+ { "allocate-uid", 0, POPT_ARG_NONE, 0, OPT_ALLOCATE_UID,
+ "Get a new UID out of idmap" },
+ { "allocate-gid", 0, POPT_ARG_NONE, 0, OPT_ALLOCATE_GID,
+ "Get a new GID out of idmap" },
+ { "check-secret", 't', POPT_ARG_NONE, 0, 't', "Check shared secret" },
+ { "trusted-domains", 'm', POPT_ARG_NONE, 0, 'm', "List trusted domains" },
+ { "all-domains", 0, POPT_ARG_NONE, 0, OPT_LIST_ALL_DOMAINS, "List all domains (trusted and own domain)" },
+ { "own-domain", 0, POPT_ARG_NONE, 0, OPT_LIST_OWN_DOMAIN, "List own domain" },
+ { "sequence", 0, POPT_ARG_NONE, 0, OPT_SEQUENCE, "Show sequence numbers of all domains" },
+ { "online-status", 0, POPT_ARG_NONE, 0, OPT_ONLINESTATUS, "Show whether domains are marked as online or offline"},
+ { "domain-info", 'D', POPT_ARG_STRING, &string_arg, 'D', "Show most of the info we have about the domain" },
+ { "user-info", 'i', POPT_ARG_STRING, &string_arg, 'i', "Get user info", "USER" },
+ { "uid-info", 0, POPT_ARG_INT, &int_arg, OPT_UID_INFO, "Get user info from uid", "UID" },
+ { "group-info", 0, POPT_ARG_STRING, &string_arg, OPT_GROUP_INFO, "Get group info", "GROUP" },
+ { "user-groups", 'r', POPT_ARG_STRING, &string_arg, 'r', "Get user groups", "USER" },
+ { "user-domgroups", 0, POPT_ARG_STRING, &string_arg,
+ OPT_USERDOMGROUPS, "Get user domain groups", "SID" },
+ { "user-sids", 0, POPT_ARG_STRING, &string_arg, OPT_USERSIDS, "Get user group sids for user SID", "SID" },
+ { "authenticate", 'a', POPT_ARG_STRING, &string_arg, 'a', "authenticate user", "user%password" },
+ { "set-auth-user", 0, POPT_ARG_STRING, &string_arg, OPT_SET_AUTH_USER, "Store user and password used by winbindd (root only)", "user%password" },
+ { "getdcname", 0, POPT_ARG_STRING, &string_arg, OPT_GETDCNAME,
+ "Get a DC name for a foreign domain", "domainname" },
+ { "dsgetdcname", 0, POPT_ARG_STRING, &string_arg, OPT_DSGETDCNAME, "Find a DC for a domain", "domainname" },
+ { "get-auth-user", 0, POPT_ARG_NONE, NULL, OPT_GET_AUTH_USER, "Retrieve user and password used by winbindd (root only)", NULL },
+ { "ping", 'p', POPT_ARG_NONE, 0, 'p', "Ping winbindd to see if it is alive" },
+ { "domain", 0, POPT_ARG_STRING, &opt_domain_name, OPT_DOMAIN_NAME, "Define to the domain to restrict operation", "domain" },
+#ifdef WITH_FAKE_KASERVER
+ { "klog", 'k', POPT_ARG_STRING, &string_arg, 'k', "set an AFS token from winbind", "user%password" },
+#endif
+#ifdef HAVE_KRB5
+ { "krb5auth", 'K', POPT_ARG_STRING, &string_arg, 'K', "authenticate user using Kerberos", "user%password" },
+ /* destroys wbinfo --help output */
+ /* "user%password,DOM\\user%password,user@EXAMPLE.COM,EXAMPLE.COM\\user%password" }, */
+#endif
+ { "separator", 0, POPT_ARG_NONE, 0, OPT_SEPARATOR, "Get the active winbind separator", NULL },
+ { "verbose", 0, POPT_ARG_NONE, 0, OPT_VERBOSE, "Print additional information per command", NULL },
+ { "change-user-password", 0, POPT_ARG_STRING, &string_arg, OPT_CHANGE_USER_PASSWORD, "Change the password for a user", NULL },
+ POPT_COMMON_CONFIGFILE
+ POPT_COMMON_VERSION
+ POPT_TABLEEND
+ };
+
+ /* Samba client initialisation */
+ load_case_tables();
+
+
+ /* Parse options */
+
+ pc = poptGetContext("wbinfo", argc, (const char **)argv, long_options, 0);
+
+ /* Parse command line options */
+
+ if (argc == 1) {
+ poptPrintHelp(pc, stderr, 0);
+ return 1;
+ }
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ /* get the generic configuration parameters like --domain */
+ switch (opt) {
+ case OPT_VERBOSE:
+ verbose = True;
+ break;
+ }
+ }
+
+ poptFreeContext(pc);
+
+ if (!lp_load(get_dyn_CONFIGFILE(), true, false, false, true)) {
+ d_fprintf(stderr, "wbinfo: error opening config file %s. Error was %s\n",
+ get_dyn_CONFIGFILE(), strerror(errno));
+ exit(1);
+ }
+
+ if (!init_names())
+ return 1;
+
+ load_interfaces();
+
+ pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'u':
+ if (!print_domain_users(opt_domain_name)) {
+ d_fprintf(stderr, "Error looking up domain users\n");
+ goto done;
+ }
+ break;
+ case 'g':
+ if (!print_domain_groups(opt_domain_name)) {
+ d_fprintf(stderr, "Error looking up domain groups\n");
+ goto done;
+ }
+ break;
+ case 's':
+ if (!wbinfo_lookupsid(string_arg)) {
+ d_fprintf(stderr, "Could not lookup sid %s\n", string_arg);
+ goto done;
+ }
+ break;
+ case 'R':
+ if (!wbinfo_lookuprids(opt_domain_name, string_arg)) {
+ d_fprintf(stderr, "Could not lookup RIDs %s\n", string_arg);
+ goto done;
+ }
+ break;
+ case 'n':
+ if (!wbinfo_lookupname(string_arg)) {
+ d_fprintf(stderr, "Could not lookup name %s\n", string_arg);
+ goto done;
+ }
+ break;
+ case 'N':
+ if (!wbinfo_wins_byname(string_arg)) {
+ d_fprintf(stderr, "Could not lookup WINS by name %s\n", string_arg);
+ goto done;
+ }
+ break;
+ case 'I':
+ if (!wbinfo_wins_byip(string_arg)) {
+ d_fprintf(stderr, "Could not lookup WINS by IP %s\n", string_arg);
+ goto done;
+ }
+ break;
+ case 'U':
+ if (!wbinfo_uid_to_sid(int_arg)) {
+ d_fprintf(stderr, "Could not convert uid %d to sid\n", int_arg);
+ goto done;
+ }
+ break;
+ case 'G':
+ if (!wbinfo_gid_to_sid(int_arg)) {
+ d_fprintf(stderr, "Could not convert gid %d to sid\n",
+ int_arg);
+ goto done;
+ }
+ break;
+ case 'S':
+ if (!wbinfo_sid_to_uid(string_arg)) {
+ d_fprintf(stderr, "Could not convert sid %s to uid\n",
+ string_arg);
+ goto done;
+ }
+ break;
+ case 'Y':
+ if (!wbinfo_sid_to_gid(string_arg)) {
+ d_fprintf(stderr, "Could not convert sid %s to gid\n",
+ string_arg);
+ goto done;
+ }
+ break;
+ case OPT_ALLOCATE_UID:
+ if (!wbinfo_allocate_uid()) {
+ d_fprintf(stderr, "Could not allocate a uid\n");
+ goto done;
+ }
+ break;
+ case OPT_ALLOCATE_GID:
+ if (!wbinfo_allocate_gid()) {
+ d_fprintf(stderr, "Could not allocate a gid\n");
+ goto done;
+ }
+ break;
+ case 't':
+ if (!wbinfo_check_secret()) {
+ d_fprintf(stderr, "Could not check secret\n");
+ goto done;
+ }
+ break;
+ case 'm':
+ if (!wbinfo_list_domains(false, verbose)) {
+ d_fprintf(stderr, "Could not list trusted domains\n");
+ goto done;
+ }
+ break;
+ case OPT_SEQUENCE:
+ if (!wbinfo_show_sequence(opt_domain_name)) {
+ d_fprintf(stderr, "Could not show sequence numbers\n");
+ goto done;
+ }
+ break;
+ case OPT_ONLINESTATUS:
+ if (!wbinfo_show_onlinestatus(opt_domain_name)) {
+ d_fprintf(stderr, "Could not show online-status\n");
+ goto done;
+ }
+ break;
+ case 'D':
+ if (!wbinfo_domain_info(string_arg)) {
+ d_fprintf(stderr, "Could not get domain info\n");
+ goto done;
+ }
+ break;
+ case 'i':
+ if (!wbinfo_get_userinfo(string_arg)) {
+ d_fprintf(stderr, "Could not get info for user %s\n",
+ string_arg);
+ goto done;
+ }
+ break;
+ case OPT_UID_INFO:
+ if ( !wbinfo_get_uidinfo(int_arg)) {
+ d_fprintf(stderr, "Could not get info for uid "
+ "%d\n", int_arg);
+ goto done;
+ }
+ break;
+ case OPT_GROUP_INFO:
+ if ( !wbinfo_get_groupinfo(string_arg)) {
+ d_fprintf(stderr, "Could not get info for "
+ "group %s\n", string_arg);
+ goto done;
+ }
+ break;
+ case 'r':
+ if (!wbinfo_get_usergroups(string_arg)) {
+ d_fprintf(stderr, "Could not get groups for user %s\n",
+ string_arg);
+ goto done;
+ }
+ break;
+ case OPT_USERSIDS:
+ if (!wbinfo_get_usersids(string_arg)) {
+ d_fprintf(stderr, "Could not get group SIDs for user SID %s\n",
+ string_arg);
+ goto done;
+ }
+ break;
+ case OPT_USERDOMGROUPS:
+ if (!wbinfo_get_userdomgroups(string_arg)) {
+ d_fprintf(stderr, "Could not get user's domain groups "
+ "for user SID %s\n", string_arg);
+ goto done;
+ }
+ break;
+ case 'a': {
+ bool got_error = false;
+
+ if (!wbinfo_auth(string_arg)) {
+ d_fprintf(stderr, "Could not authenticate user %s with "
+ "plaintext password\n", string_arg);
+ got_error = true;
+ }
+
+ if (!wbinfo_auth_crap(string_arg)) {
+ d_fprintf(stderr, "Could not authenticate user %s with "
+ "challenge/response\n", string_arg);
+ got_error = true;
+ }
+
+ if (got_error)
+ goto done;
+ break;
+ }
+ case 'K': {
+ uint32 flags = WBFLAG_PAM_KRB5 |
+ WBFLAG_PAM_CACHED_LOGIN |
+ WBFLAG_PAM_FALLBACK_AFTER_KRB5 |
+ WBFLAG_PAM_INFO3_TEXT;
+
+ if (!wbinfo_auth_krb5(string_arg, "FILE", flags)) {
+ d_fprintf(stderr, "Could not authenticate user [%s] with "
+ "Kerberos (ccache: %s)\n", string_arg, "FILE");
+ goto done;
+ }
+ break;
+ }
+ case 'k':
+ if (!wbinfo_klog(string_arg)) {
+ d_fprintf(stderr, "Could not klog user\n");
+ goto done;
+ }
+ break;
+ case 'p':
+ if (!wbinfo_ping()) {
+ d_fprintf(stderr, "could not ping winbindd!\n");
+ goto done;
+ }
+ break;
+ case OPT_SET_AUTH_USER:
+ if (!wbinfo_set_auth_user(string_arg)) {
+ goto done;
+ }
+ break;
+ case OPT_GET_AUTH_USER:
+ wbinfo_get_auth_user();
+ break;
+ case OPT_GETDCNAME:
+ if (!wbinfo_getdcname(string_arg)) {
+ goto done;
+ }
+ break;
+ case OPT_DSGETDCNAME:
+ if (!wbinfo_dsgetdcname(string_arg, 0)) {
+ goto done;
+ }
+ break;
+ case OPT_SEPARATOR: {
+ const char sep = winbind_separator_int(true);
+ if ( !sep ) {
+ goto done;
+ }
+ d_printf("%c\n", sep);
+ break;
+ }
+ case OPT_LIST_ALL_DOMAINS:
+ if (!wbinfo_list_domains(true, verbose)) {
+ goto done;
+ }
+ break;
+ case OPT_LIST_OWN_DOMAIN:
+ if (!wbinfo_list_own_domain()) {
+ goto done;
+ }
+ break;
+ case OPT_CHANGE_USER_PASSWORD:
+ if (!wbinfo_change_user_password(string_arg)) {
+ d_fprintf(stderr, "Could not change user password "
+ "for user %s\n", string_arg);
+ goto done;
+ }
+ break;
+
+ /* generic configuration options */
+ case OPT_DOMAIN_NAME:
+ break;
+ case OPT_VERBOSE:
+ break;
+ default:
+ d_fprintf(stderr, "Invalid option\n");
+ poptPrintHelp(pc, stderr, 0);
+ goto done;
+ }
+ }
+
+ result = 0;
+
+ /* Exit code */
+
+ done:
+ talloc_destroy(frame);
+
+ poptFreeContext(pc);
+ return result;
+}
diff --git a/source3/nsswitch/winbind_client.h b/source3/nsswitch/winbind_client.h
new file mode 100644
index 0000000000..757f5869e9
--- /dev/null
+++ b/source3/nsswitch/winbind_client.h
@@ -0,0 +1,30 @@
+#include "winbind_nss_config.h"
+#include "winbind_struct_protocol.h"
+
+void winbindd_init_request(struct winbindd_request *req,int rq_type);
+void winbindd_free_response(struct winbindd_response *response);
+NSS_STATUS winbindd_send_request(int req_type, int need_priv,
+ struct winbindd_request *request);
+NSS_STATUS winbindd_get_response(struct winbindd_response *response);
+NSS_STATUS winbindd_request_response(int req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response);
+NSS_STATUS winbindd_priv_request_response(int req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response);
+int winbindd_read_reply(struct winbindd_response *response);
+
+#define winbind_env_set() \
+ (strcmp(getenv(WINBINDD_DONT_ENV)?getenv(WINBINDD_DONT_ENV):"0","1") == 0)
+
+#define winbind_off() \
+ (setenv(WINBINDD_DONT_ENV, "1", 1) == 0)
+
+#define winbind_on() \
+ (setenv(WINBINDD_DONT_ENV, "0", 1) == 0)
+
+int winbind_write_sock(void *buffer, int count, int recursing, int need_priv);
+int winbind_read_sock(void *buffer, int count);
+void winbind_close_sock(void);
+
+const char *nss_err_str(NSS_STATUS ret);
diff --git a/source3/nsswitch/winbind_krb5_locator.c b/source3/nsswitch/winbind_krb5_locator.c
new file mode 100644
index 0000000000..990c2cae50
--- /dev/null
+++ b/source3/nsswitch/winbind_krb5_locator.c
@@ -0,0 +1,397 @@
+/*
+ Unix SMB/CIFS implementation.
+ kerberos locator plugin
+ Copyright (C) Guenther Deschner 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "nsswitch/winbind_client.h"
+
+#ifndef DEBUG_KRB5
+#undef DEBUG_KRB5
+#endif
+
+#if defined(HAVE_KRB5) && defined(HAVE_KRB5_LOCATE_PLUGIN_H)
+
+#include <krb5/locate_plugin.h>
+
+#ifndef KRB5_PLUGIN_NO_HANDLE
+#define KRB5_PLUGIN_NO_HANDLE KRB5_KDC_UNREACH /* Heimdal */
+#endif
+
+static const char *get_service_from_locate_service_type(enum locate_service_type svc)
+{
+ switch (svc) {
+ case locate_service_kdc:
+ case locate_service_master_kdc:
+ return "88";
+ case locate_service_kadmin:
+ case locate_service_krb524:
+ /* not supported */
+ return NULL;
+ case locate_service_kpasswd:
+ return "464";
+ default:
+ break;
+ }
+ return NULL;
+
+}
+
+#ifdef DEBUG_KRB5
+static const char *locate_service_type_name(enum locate_service_type svc)
+{
+ switch (svc) {
+ case locate_service_kdc:
+ return "locate_service_kdc";
+ case locate_service_master_kdc:
+ return "locate_service_master_kdc";
+ case locate_service_kadmin:
+ return "locate_service_kadmin";
+ case locate_service_krb524:
+ return "locate_service_krb524";
+ case locate_service_kpasswd:
+ return "locate_service_kpasswd";
+ default:
+ break;
+ }
+ return NULL;
+}
+
+static const char *socktype_name(int socktype)
+{
+ switch (socktype) {
+ case SOCK_STREAM:
+ return "SOCK_STREAM";
+ case SOCK_DGRAM:
+ return "SOCK_DGRAM";
+ default:
+ break;
+ }
+ return "unknown";
+}
+
+static const char *family_name(int family)
+{
+ switch (family) {
+ case AF_UNSPEC:
+ return "AF_UNSPEC";
+ case AF_INET:
+ return "AF_INET";
+#if defined(HAVE_IPV6)
+ case AF_INET6:
+ return "AF_INET6";
+#endif
+ default:
+ break;
+ }
+ return "unknown";
+}
+#endif
+
+/**
+ * Check input parameters, return KRB5_PLUGIN_NO_HANDLE for unsupported ones
+ *
+ * @param svc
+ * @param realm string
+ * @param socktype integer
+ * @param family integer
+ *
+ * @return integer.
+ */
+
+static int smb_krb5_locator_lookup_sanity_check(enum locate_service_type svc,
+ const char *realm,
+ int socktype,
+ int family)
+{
+ if (!realm || strlen(realm) == 0) {
+ return EINVAL;
+ }
+
+ switch (svc) {
+ case locate_service_kdc:
+ case locate_service_master_kdc:
+ case locate_service_kpasswd:
+ break;
+ case locate_service_kadmin:
+ case locate_service_krb524:
+ return KRB5_PLUGIN_NO_HANDLE;
+ default:
+ return EINVAL;
+ }
+
+ switch (family) {
+ case AF_UNSPEC:
+ case AF_INET:
+ break;
+#if defined(HAVE_IPV6)
+ case AF_INET6:
+ break;
+#endif
+ default:
+ return EINVAL;
+ }
+
+ switch (socktype) {
+ case SOCK_STREAM:
+ case SOCK_DGRAM:
+ case 0: /* Heimdal uses that */
+ break;
+ default:
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * Try to get addrinfo for a given host and call the krb5 callback
+ *
+ * @param name string
+ * @param service string
+ * @param in struct addrinfo hint
+ * @param cbfunc krb5 callback function
+ * @param cbdata void pointer cbdata
+ *
+ * @return krb5_error_code.
+ */
+
+static krb5_error_code smb_krb5_locator_call_cbfunc(const char *name,
+ const char *service,
+ struct addrinfo *in,
+ int (*cbfunc)(void *, int, struct sockaddr *),
+ void *cbdata)
+{
+ struct addrinfo *out = NULL;
+ int ret;
+ int count = 3;
+
+ while (count) {
+
+ ret = getaddrinfo(name, service, in, &out);
+ if (ret == 0) {
+ break;
+ }
+
+ if (ret == EAI_AGAIN) {
+ count--;
+ continue;
+ }
+
+#ifdef DEBUG_KRB5
+ fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
+ "getaddrinfo failed: %s (%d)\n",
+ (unsigned int)getpid(), gai_strerror(ret), ret);
+#endif
+
+ return KRB5_PLUGIN_NO_HANDLE;
+ }
+
+ ret = cbfunc(cbdata, out->ai_socktype, out->ai_addr);
+#ifdef DEBUG_KRB5
+ if (ret) {
+ fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
+ "failed to call callback: %s (%d)\n",
+ (unsigned int)getpid(), error_message(ret), ret);
+ }
+#endif
+
+ freeaddrinfo(out);
+ return ret;
+}
+
+/**
+ * PUBLIC INTERFACE: locate init
+ *
+ * @param context krb5_context
+ * @param privata_data pointer to private data pointer
+ *
+ * @return krb5_error_code.
+ */
+
+static krb5_error_code smb_krb5_locator_init(krb5_context context,
+ void **private_data)
+{
+ return 0;
+}
+
+/**
+ * PUBLIC INTERFACE: close locate
+ *
+ * @param private_data pointer to private data
+ *
+ * @return void.
+ */
+
+static void smb_krb5_locator_close(void *private_data)
+{
+ return;
+}
+
+
+static bool ask_winbind(const char *realm, char **dcname)
+{
+ NSS_STATUS status;
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.flags = 0x40020600;
+ /* DS_KDC_REQUIRED |
+ DS_IS_DNS_NAME |
+ DS_RETURN_DNS_NAME |
+ DS_IP_REQUIRED */
+
+ strncpy(request.domain_name, realm,
+ sizeof(request.domain_name)-1);
+
+ status = winbindd_request_response(WINBINDD_DSGETDCNAME,
+ &request, &response);
+ if (status != NSS_STATUS_SUCCESS) {
+#ifdef DEBUG_KRB5
+ fprintf(stderr,"[%5u]: smb_krb5_locator_lookup: failed with: %s\n",
+ (unsigned int)getpid(), nss_err_str(status));
+#endif
+ return false;
+ }
+
+ *dcname = strdup(response.data.dc_name);
+ if (!*dcname) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * PUBLIC INTERFACE: locate lookup
+ *
+ * @param private_data pointer to private data
+ * @param svc enum locate_service_type.
+ * @param realm string
+ * @param socktype integer
+ * @param family integer
+ * @param cbfunc callback function to send back entries
+ * @param cbdata void pointer to cbdata
+ *
+ * @return krb5_error_code.
+ */
+
+static krb5_error_code smb_krb5_locator_lookup(void *private_data,
+ enum locate_service_type svc,
+ const char *realm,
+ int socktype,
+ int family,
+ int (*cbfunc)(void *, int, struct sockaddr *),
+ void *cbdata)
+{
+ krb5_error_code ret;
+ struct addrinfo aihints;
+ char *kdc_name = NULL;
+ const char *service = get_service_from_locate_service_type(svc);
+
+ ZERO_STRUCT(aihints);
+
+#ifdef DEBUG_KRB5
+ fprintf(stderr,"[%5u]: smb_krb5_locator_lookup: called for '%s' "
+ "svc: '%s' (%d) "
+ "socktype: '%s' (%d), family: '%s' (%d)\n",
+ (unsigned int)getpid(), realm,
+ locate_service_type_name(svc), svc,
+ socktype_name(socktype), socktype,
+ family_name(family), family);
+#endif
+ ret = smb_krb5_locator_lookup_sanity_check(svc, realm, socktype,
+ family);
+ if (ret) {
+#ifdef DEBUG_KRB5
+ fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
+ "returning ret: %s (%d)\n",
+ (unsigned int)getpid(), error_message(ret), ret);
+#endif
+ return ret;
+ }
+
+ if (!winbind_env_set()) {
+ if (!ask_winbind(realm, &kdc_name)) {
+#ifdef DEBUG_KRB5
+ fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
+ "failed to query winbindd\n",
+ (unsigned int)getpid());
+#endif
+ goto failed;
+ }
+ } else {
+ const char *env = NULL;
+ char *var = NULL;
+ if (asprintf(&var, "%s_%s",
+ WINBINDD_LOCATOR_KDC_ADDRESS, realm) == -1) {
+ goto failed;
+ }
+ env = getenv(var);
+ if (!env) {
+#ifdef DEBUG_KRB5
+ fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
+ "failed to get kdc from env %s\n",
+ (unsigned int)getpid(), var);
+#endif
+ free(var);
+ goto failed;
+ }
+ free(var);
+
+ kdc_name = strdup(env);
+ if (!kdc_name) {
+ goto failed;
+ }
+ }
+#ifdef DEBUG_KRB5
+ fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
+ "got '%s' for '%s' from winbindd\n", (unsigned int)getpid(),
+ kdc_name, realm);
+#endif
+
+ aihints.ai_family = family;
+ aihints.ai_socktype = socktype;
+
+ ret = smb_krb5_locator_call_cbfunc(kdc_name,
+ service,
+ &aihints,
+ cbfunc, cbdata);
+ SAFE_FREE(kdc_name);
+
+ return ret;
+
+ failed:
+ return KRB5_PLUGIN_NO_HANDLE;
+}
+
+#ifdef HEIMDAL_KRB5_LOCATE_PLUGIN_H
+#define SMB_KRB5_LOCATOR_SYMBOL_NAME resolve /* Heimdal */
+#else
+#define SMB_KRB5_LOCATOR_SYMBOL_NAME service_locator /* MIT */
+#endif
+
+const krb5plugin_service_locate_ftable SMB_KRB5_LOCATOR_SYMBOL_NAME = {
+ 0, /* version */
+ smb_krb5_locator_init,
+ smb_krb5_locator_close,
+ smb_krb5_locator_lookup,
+};
+
+#endif
diff --git a/source3/nsswitch/winbind_nss.h b/source3/nsswitch/winbind_nss.h
new file mode 100644
index 0000000000..0a3bc7cefa
--- /dev/null
+++ b/source3/nsswitch/winbind_nss.h
@@ -0,0 +1,76 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ A common place to work out how to define NSS_STATUS on various
+ platforms.
+
+ Copyright (C) Tim Potter 2000
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NSSWITCH_NSS_H
+#define _NSSWITCH_NSS_H
+
+#ifdef HAVE_NSS_COMMON_H
+
+/*
+ * Sun Solaris
+ */
+
+#include "nsswitch/winbind_nss_solaris.h"
+
+#elif HAVE_NSS_H
+
+/*
+ * Linux (glibc)
+ */
+
+#include "nsswitch/winbind_nss_linux.h"
+
+#elif HAVE_NS_API_H
+
+/*
+ * SGI IRIX
+ */
+
+#include "nsswitch/winbind_nss_irix.h"
+
+#elif defined(HPUX) && defined(HAVE_NSSWITCH_H)
+
+/* HP-UX 11 */
+
+#include "nsswitch/winbind_nss_hpux.h"
+
+#elif defined(__NetBSD__) && defined(HAVE_GETPWENT_R)
+
+/*
+ * NetBSD 3 and newer
+ */
+
+#include "nsswitch/winbind_nss_netbsd.h"
+
+#else /* Nothing's defined. Neither gnu nor netbsd nor sun nor hp */
+
+typedef enum
+{
+ NSS_STATUS_SUCCESS=0,
+ NSS_STATUS_NOTFOUND=1,
+ NSS_STATUS_UNAVAIL=2,
+ NSS_STATUS_TRYAGAIN=3
+} NSS_STATUS;
+
+#endif
+
+#endif /* _NSSWITCH_NSS_H */
diff --git a/source3/nsswitch/winbind_nss_aix.c b/source3/nsswitch/winbind_nss_aix.c
new file mode 100644
index 0000000000..9c84e5f8aa
--- /dev/null
+++ b/source3/nsswitch/winbind_nss_aix.c
@@ -0,0 +1,1077 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ AIX loadable authentication module, providing identification and
+ authentication routines against Samba winbind/Windows NT Domain
+
+ Copyright (C) Tim Potter 2003
+ Copyright (C) Steve Roylance 2003
+ Copyright (C) Andrew Tridgell 2003-2004
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+
+ To install this module copy nsswitch/WINBIND to /usr/lib/security and add
+ "WINBIND" in /usr/lib/security/methods.cfg and /etc/security/user
+
+ Note that this module also provides authentication and password
+ changing routines, so you do not need to install the winbind PAM
+ module.
+
+ see
+ http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/aixprggd/kernextc/sec_load_mod.htm
+ for some information in the interface that this module implements
+
+ Many thanks to Julianne Haugh for explaining some of the finer
+ details of this interface.
+
+ To debug this module use uess_test.c (which you can get from tridge)
+ or set "options=debug" in /usr/lib/security/methods.cfg
+
+*/
+
+#include "winbind_client.h"
+#include <usersec.h>
+
+/* enable this to log which entry points have not been
+ completed yet */
+#define LOG_UNIMPLEMENTED_CALLS 0
+
+
+#define WB_AIX_ENCODED '_'
+
+static int debug_enabled;
+
+
+static void logit(const char *format, ...)
+{
+ va_list ap;
+ FILE *f;
+ if (!debug_enabled) {
+ return;
+ }
+ f = fopen("/tmp/WINBIND_DEBUG.log", "a");
+ if (!f) return;
+ va_start(ap, format);
+ vfprintf(f, format, ap);
+ va_end(ap);
+ fclose(f);
+}
+
+
+#define HANDLE_ERRORS(ret) do { \
+ if ((ret) == NSS_STATUS_NOTFOUND) { \
+ errno = ENOENT; \
+ return NULL; \
+ } else if ((ret) != NSS_STATUS_SUCCESS) { \
+ errno = EIO; \
+ return NULL; \
+ } \
+} while (0)
+
+#define STRCPY_RET(dest, src) \
+do { \
+ if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return -1; } \
+ strcpy(dest, src); \
+} while (0)
+
+#define STRCPY_RETNULL(dest, src) \
+do { \
+ if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return NULL; } \
+ strcpy(dest, src); \
+} while (0)
+
+
+/* free a passwd structure */
+static void free_pwd(struct passwd *pwd)
+{
+ free(pwd->pw_name);
+ free(pwd->pw_passwd);
+ free(pwd->pw_gecos);
+ free(pwd->pw_dir);
+ free(pwd->pw_shell);
+ free(pwd);
+}
+
+/* free a group structure */
+static void free_grp(struct group *grp)
+{
+ int i;
+
+ free(grp->gr_name);
+ free(grp->gr_passwd);
+
+ if (!grp->gr_mem) {
+ free(grp);
+ return;
+ }
+
+ for (i=0; grp->gr_mem[i]; i++) {
+ free(grp->gr_mem[i]);
+ }
+
+ free(grp->gr_mem);
+ free(grp);
+}
+
+
+/* replace commas with nulls, and null terminate */
+static void replace_commas(char *s)
+{
+ char *p, *p0=s;
+ for (p=strchr(s, ','); p; p = strchr(p+1, ',')) {
+ *p=0;
+ p0 = p+1;
+ }
+
+ p0[strlen(p0)+1] = 0;
+}
+
+
+/* the decode_*() routines are used to cope with the fact that AIX 5.2
+ and below cannot handle user or group names longer than 8
+ characters in some interfaces. We use the normalize method to
+ provide a mapping to a username that fits, by using the form '_UID'
+ or '_GID'.
+
+ this only works if you can guarantee that the WB_AIX_ENCODED char
+ is not used as the first char of any other username
+*/
+static unsigned decode_id(const char *name)
+{
+ unsigned id;
+ sscanf(name+1, "%u", &id);
+ return id;
+}
+
+static struct passwd *wb_aix_getpwuid(uid_t uid);
+
+static char *decode_user(const char *name)
+{
+ struct passwd *pwd;
+ unsigned id;
+ char *ret;
+
+ sscanf(name+1, "%u", &id);
+ pwd = wb_aix_getpwuid(id);
+ if (!pwd) {
+ return NULL;
+ }
+ ret = strdup(pwd->pw_name);
+
+ free_pwd(pwd);
+
+ logit("decoded '%s' -> '%s'\n", name, ret);
+
+ return ret;
+}
+
+
+/*
+ fill a struct passwd from a winbindd_pw struct, allocating as a single block
+*/
+static struct passwd *fill_pwent(struct winbindd_pw *pw)
+{
+ struct passwd *result;
+
+ result = calloc(1, sizeof(struct passwd));
+ if (!result) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ result->pw_uid = pw->pw_uid;
+ result->pw_gid = pw->pw_gid;
+ result->pw_name = strdup(pw->pw_name);
+ result->pw_passwd = strdup(pw->pw_passwd);
+ result->pw_gecos = strdup(pw->pw_gecos);
+ result->pw_dir = strdup(pw->pw_dir);
+ result->pw_shell = strdup(pw->pw_shell);
+
+ return result;
+}
+
+
+/*
+ fill a struct group from a winbindd_pw struct, allocating as a single block
+*/
+static struct group *fill_grent(struct winbindd_gr *gr, char *gr_mem)
+{
+ int i;
+ struct group *result;
+ char *p, *name;
+
+ result = calloc(1, sizeof(struct group));
+ if (!result) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ result->gr_gid = gr->gr_gid;
+
+ result->gr_name = strdup(gr->gr_name);
+ result->gr_passwd = strdup(gr->gr_passwd);
+
+ /* Group membership */
+ if ((gr->num_gr_mem < 0) || !gr_mem) {
+ gr->num_gr_mem = 0;
+ }
+
+ if (gr->num_gr_mem == 0) {
+ /* Group is empty */
+ return result;
+ }
+
+ result->gr_mem = (char **)malloc(sizeof(char *) * (gr->num_gr_mem+1));
+ if (!result->gr_mem) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ /* Start looking at extra data */
+ i=0;
+ for (name = strtok_r(gr_mem, ",", &p);
+ name;
+ name = strtok_r(NULL, ",", &p)) {
+ if (i == gr->num_gr_mem) {
+ break;
+ }
+ result->gr_mem[i] = strdup(name);
+ i++;
+ }
+
+ /* Terminate list */
+ result->gr_mem[i] = NULL;
+
+ return result;
+}
+
+
+
+/* take a group id and return a filled struct group */
+static struct group *wb_aix_getgrgid(gid_t gid)
+{
+ struct winbindd_response response;
+ struct winbindd_request request;
+ struct group *grp;
+ NSS_STATUS ret;
+
+ logit("getgrgid %d\n", gid);
+
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
+
+ request.data.gid = gid;
+
+ ret = winbindd_request_response(WINBINDD_GETGRGID, &request, &response);
+
+ logit("getgrgid ret=%d\n", ret);
+
+ HANDLE_ERRORS(ret);
+
+ grp = fill_grent(&response.data.gr, response.extra_data.data);
+
+ winbindd_free_response(&response);
+
+ return grp;
+}
+
+/* take a group name and return a filled struct group */
+static struct group *wb_aix_getgrnam(const char *name)
+{
+ struct winbindd_response response;
+ struct winbindd_request request;
+ NSS_STATUS ret;
+ struct group *grp;
+
+ if (*name == WB_AIX_ENCODED) {
+ return wb_aix_getgrgid(decode_id(name));
+ }
+
+ logit("getgrnam '%s'\n", name);
+
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
+
+ STRCPY_RETNULL(request.data.groupname, name);
+
+ ret = winbindd_request_response(WINBINDD_GETGRNAM, &request, &response);
+
+ HANDLE_ERRORS(ret);
+
+ grp = fill_grent(&response.data.gr, response.extra_data.data);
+
+ winbindd_free_response(&response);
+
+ return grp;
+}
+
+
+/* this call doesn't have to fill in the gr_mem, but we do anyway
+ for simplicity */
+static struct group *wb_aix_getgracct(void *id, int type)
+{
+ if (type == 1) {
+ return wb_aix_getgrnam((char *)id);
+ }
+ if (type == 0) {
+ return wb_aix_getgrgid(*(int *)id);
+ }
+ errno = EINVAL;
+ return NULL;
+}
+
+
+/* take a username and return a string containing a comma-separated
+ list of group id numbers to which the user belongs */
+static char *wb_aix_getgrset(char *user)
+{
+ struct winbindd_response response;
+ struct winbindd_request request;
+ NSS_STATUS ret;
+ int i, idx;
+ char *tmpbuf;
+ int num_gids;
+ gid_t *gid_list;
+ char *r_user = user;
+
+ if (*user == WB_AIX_ENCODED) {
+ r_user = decode_user(r_user);
+ if (!r_user) {
+ errno = ENOENT;
+ return NULL;
+ }
+ }
+
+ logit("getgrset '%s'\n", r_user);
+
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
+
+ STRCPY_RETNULL(request.data.username, r_user);
+
+ if (*user == WB_AIX_ENCODED) {
+ free(r_user);
+ }
+
+ ret = winbindd_request_response(WINBINDD_GETGROUPS, &request, &response);
+
+ HANDLE_ERRORS(ret);
+
+ num_gids = response.data.num_entries;
+ gid_list = (gid_t *)response.extra_data.data;
+
+ /* allocate a space large enough to contruct the string */
+ tmpbuf = malloc(num_gids*12);
+ if (!tmpbuf) {
+ return NULL;
+ }
+
+ for (idx=i=0; i < num_gids-1; i++) {
+ idx += sprintf(tmpbuf+idx, "%u,", gid_list[i]);
+ }
+ idx += sprintf(tmpbuf+idx, "%u", gid_list[i]);
+
+ winbindd_free_response(&response);
+
+ return tmpbuf;
+}
+
+
+/* take a uid and return a filled struct passwd */
+static struct passwd *wb_aix_getpwuid(uid_t uid)
+{
+ struct winbindd_response response;
+ struct winbindd_request request;
+ NSS_STATUS ret;
+ struct passwd *pwd;
+
+ logit("getpwuid '%d'\n", uid);
+
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
+
+ request.data.uid = uid;
+
+ ret = winbindd_request_response(WINBINDD_GETPWUID, &request, &response);
+
+ HANDLE_ERRORS(ret);
+
+ pwd = fill_pwent(&response.data.pw);
+
+ winbindd_free_response(&response);
+
+ logit("getpwuid gave ptr %p\n", pwd);
+
+ return pwd;
+}
+
+
+/* take a username and return a filled struct passwd */
+static struct passwd *wb_aix_getpwnam(const char *name)
+{
+ struct winbindd_response response;
+ struct winbindd_request request;
+ NSS_STATUS ret;
+ struct passwd *pwd;
+
+ if (*name == WB_AIX_ENCODED) {
+ return wb_aix_getpwuid(decode_id(name));
+ }
+
+ logit("getpwnam '%s'\n", name);
+
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
+
+ STRCPY_RETNULL(request.data.username, name);
+
+ ret = winbindd_request_response(WINBINDD_GETPWNAM, &request, &response);
+
+ HANDLE_ERRORS(ret);
+
+ pwd = fill_pwent(&response.data.pw);
+
+ winbindd_free_response(&response);
+
+ logit("getpwnam gave ptr %p\n", pwd);
+
+ return pwd;
+}
+
+/*
+ list users
+*/
+static int wb_aix_lsuser(char *attributes[], attrval_t results[], int size)
+{
+ NSS_STATUS ret;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int len;
+ char *s;
+
+ if (size != 1 || strcmp(attributes[0], S_USERS) != 0) {
+ logit("invalid lsuser op\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ ret = winbindd_request_response(WINBINDD_LIST_USERS, &request, &response);
+ if (ret != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ len = strlen(response.extra_data.data);
+
+ s = malloc(len+2);
+ if (!s) {
+ winbindd_free_response(&response);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ memcpy(s, response.extra_data.data, len+1);
+
+ replace_commas(s);
+
+ results[0].attr_un.au_char = s;
+ results[0].attr_flag = 0;
+
+ winbindd_free_response(&response);
+
+ return 0;
+}
+
+
+/*
+ list groups
+*/
+static int wb_aix_lsgroup(char *attributes[], attrval_t results[], int size)
+{
+ NSS_STATUS ret;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int len;
+ char *s;
+
+ if (size != 1 || strcmp(attributes[0], S_GROUPS) != 0) {
+ logit("invalid lsgroup op\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ ret = winbindd_request_response(WINBINDD_LIST_GROUPS, &request, &response);
+ if (ret != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ len = strlen(response.extra_data.data);
+
+ s = malloc(len+2);
+ if (!s) {
+ winbindd_free_response(&response);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ memcpy(s, response.extra_data.data, len+1);
+
+ replace_commas(s);
+
+ results[0].attr_un.au_char = s;
+ results[0].attr_flag = 0;
+
+ winbindd_free_response(&response);
+
+ return 0;
+}
+
+
+static attrval_t pwd_to_group(struct passwd *pwd)
+{
+ attrval_t r;
+ struct group *grp = wb_aix_getgrgid(pwd->pw_gid);
+
+ if (!grp) {
+ r.attr_flag = EINVAL;
+ } else {
+ r.attr_flag = 0;
+ r.attr_un.au_char = strdup(grp->gr_name);
+ free_grp(grp);
+ }
+
+ return r;
+}
+
+static attrval_t pwd_to_groupsids(struct passwd *pwd)
+{
+ attrval_t r;
+ char *s, *p;
+
+ if ( (s = wb_aix_getgrset(pwd->pw_name)) == NULL ) {
+ r.attr_flag = EINVAL;
+ return r;
+ }
+
+ if ( (p = malloc(strlen(s)+2)) == NULL ) {
+ r.attr_flag = ENOMEM;
+ return r;
+ }
+
+ strcpy(p, s);
+ replace_commas(p);
+ free(s);
+
+ r.attr_un.au_char = p;
+
+ return r;
+}
+
+static attrval_t pwd_to_sid(struct passwd *pwd)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ attrval_t r;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.uid = pwd->pw_uid;
+
+ if (winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response) !=
+ NSS_STATUS_SUCCESS) {
+ r.attr_flag = ENOENT;
+ } else {
+ r.attr_flag = 0;
+ r.attr_un.au_char = strdup(response.data.sid.sid);
+ }
+
+ return r;
+}
+
+static int wb_aix_user_attrib(const char *key, char *attributes[],
+ attrval_t results[], int size)
+{
+ struct passwd *pwd;
+ int i;
+
+ pwd = wb_aix_getpwnam(key);
+ if (!pwd) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ for (i=0;i<size;i++) {
+ results[i].attr_flag = 0;
+
+ if (strcmp(attributes[i], S_ID) == 0) {
+ results[i].attr_un.au_int = pwd->pw_uid;
+#ifdef _AIXVERSION_530
+ } else if (strcmp(attributes[i], S_PGID) == 0) {
+ results[i].attr_un.au_int = pwd->pw_gid;
+#endif
+ } else if (strcmp(attributes[i], S_PWD) == 0) {
+ results[i].attr_un.au_char = strdup(pwd->pw_passwd);
+ } else if (strcmp(attributes[i], S_HOME) == 0) {
+ results[i].attr_un.au_char = strdup(pwd->pw_dir);
+ } else if (strcmp(attributes[i], S_SHELL) == 0) {
+ results[i].attr_un.au_char = strdup(pwd->pw_shell);
+ } else if (strcmp(attributes[i], S_REGISTRY) == 0) {
+ results[i].attr_un.au_char = strdup("WINBIND");
+ } else if (strcmp(attributes[i], S_GECOS) == 0) {
+ results[i].attr_un.au_char = strdup(pwd->pw_gecos);
+ } else if (strcmp(attributes[i], S_PGRP) == 0) {
+ results[i] = pwd_to_group(pwd);
+ } else if (strcmp(attributes[i], S_GROUPS) == 0) {
+ results[i] = pwd_to_groupsids(pwd);
+ } else if (strcmp(attributes[i], "SID") == 0) {
+ results[i] = pwd_to_sid(pwd);
+ } else {
+ logit("Unknown user attribute '%s'\n", attributes[i]);
+ results[i].attr_flag = EINVAL;
+ }
+ }
+
+ free_pwd(pwd);
+
+ return 0;
+}
+
+static int wb_aix_group_attrib(const char *key, char *attributes[],
+ attrval_t results[], int size)
+{
+ struct group *grp;
+ int i;
+
+ grp = wb_aix_getgrnam(key);
+ if (!grp) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ for (i=0;i<size;i++) {
+ results[i].attr_flag = 0;
+
+ if (strcmp(attributes[i], S_PWD) == 0) {
+ results[i].attr_un.au_char = strdup(grp->gr_passwd);
+ } else if (strcmp(attributes[i], S_ID) == 0) {
+ results[i].attr_un.au_int = grp->gr_gid;
+ } else {
+ logit("Unknown group attribute '%s'\n", attributes[i]);
+ results[i].attr_flag = EINVAL;
+ }
+ }
+
+ free_grp(grp);
+
+ return 0;
+}
+
+
+/*
+ called for user/group enumerations
+*/
+static int wb_aix_getentry(char *key, char *table, char *attributes[],
+ attrval_t results[], int size)
+{
+ logit("Got getentry with key='%s' table='%s' size=%d attributes[0]='%s'\n",
+ key, table, size, attributes[0]);
+
+ if (strcmp(key, "ALL") == 0 &&
+ strcmp(table, "user") == 0) {
+ return wb_aix_lsuser(attributes, results, size);
+ }
+
+ if (strcmp(key, "ALL") == 0 &&
+ strcmp(table, "group") == 0) {
+ return wb_aix_lsgroup(attributes, results, size);
+ }
+
+ if (strcmp(table, "user") == 0) {
+ return wb_aix_user_attrib(key, attributes, results, size);
+ }
+
+ if (strcmp(table, "group") == 0) {
+ return wb_aix_group_attrib(key, attributes, results, size);
+ }
+
+ logit("Unknown getentry operation key='%s' table='%s'\n", key, table);
+
+ errno = ENOSYS;
+ return -1;
+}
+
+
+
+/*
+ called to start the backend
+*/
+static void *wb_aix_open(const char *name, const char *domain, int mode, char *options)
+{
+ if (strstr(options, "debug")) {
+ debug_enabled = 1;
+ }
+ logit("open name='%s' mode=%d domain='%s' options='%s'\n", name, domain,
+ mode, options);
+ return NULL;
+}
+
+static void wb_aix_close(void *token)
+{
+ logit("close\n");
+ return;
+}
+
+#ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
+/*
+ return a list of additional attributes supported by the backend
+*/
+static attrlist_t **wb_aix_attrlist(void)
+{
+ /* pretty confusing but we are allocating the array of pointers
+ and the structures we'll be pointing to all at once. So
+ you need N+1 pointers and N structures. */
+
+ attrlist_t **ret = NULL;
+ attrlist_t *offset = NULL;
+ int i;
+ int n;
+ size_t size;
+
+ struct attr_types {
+ const char *name;
+ int flags;
+ int type;
+ } attr_list[] = {
+ /* user attributes */
+ {S_ID, AL_USERATTR, SEC_INT},
+ {S_PGRP, AL_USERATTR, SEC_CHAR},
+ {S_HOME, AL_USERATTR, SEC_CHAR},
+ {S_SHELL, AL_USERATTR, SEC_CHAR},
+#ifdef _AIXVERSION_530
+ {S_PGID, AL_USERATTR, SEC_INT},
+#endif
+ {S_GECOS, AL_USERATTR, SEC_CHAR},
+ {S_SHELL, AL_USERATTR, SEC_CHAR},
+ {S_PGRP, AL_USERATTR, SEC_CHAR},
+ {S_GROUPS, AL_USERATTR, SEC_LIST},
+ {"SID", AL_USERATTR, SEC_CHAR},
+
+ /* group attributes */
+ {S_ID, AL_GROUPATTR, SEC_INT}
+ };
+
+ logit("method attrlist called\n");
+
+ n = sizeof(attr_list) / sizeof(struct attr_types);
+ size = (n*sizeof(attrlist_t *));
+
+ if ( (ret = malloc( size )) == NULL ) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ /* offset to where the structures start in the buffer */
+
+ offset = (attrlist_t *)(ret + n);
+
+ /* now loop over the user_attr_list[] array and add
+ all the members */
+
+ for ( i=0; i<n; i++ ) {
+ attrlist_t *a = malloc(sizeof(attrlist_t));
+
+ if ( !a ) {
+ /* this is bad. Just bail */
+ return NULL;
+ }
+
+ a->al_name = strdup(attr_list[i].name);
+ a->al_flags = attr_list[i].flags;
+ a->al_type = attr_list[i].type;
+
+ ret[i] = a;
+ }
+ ret[n] = NULL;
+
+ return ret;
+}
+#endif
+
+
+/*
+ turn a long username into a short one. Needed to cope with the 8 char
+ username limit in AIX 5.2 and below
+*/
+static int wb_aix_normalize(char *longname, char *shortname)
+{
+ struct passwd *pwd;
+
+ logit("normalize '%s'\n", longname);
+
+ /* automatically cope with AIX 5.3 with longer usernames
+ when it comes out */
+ if (S_NAMELEN > strlen(longname)) {
+ strcpy(shortname, longname);
+ return 1;
+ }
+
+ pwd = wb_aix_getpwnam(longname);
+ if (!pwd) {
+ errno = ENOENT;
+ return 0;
+ }
+
+ sprintf(shortname, "%c%07u", WB_AIX_ENCODED, pwd->pw_uid);
+
+ free_pwd(pwd);
+
+ return 1;
+}
+
+
+/*
+ authenticate a user
+ */
+static int wb_aix_authenticate(char *user, char *pass,
+ int *reenter, char **message)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+ char *r_user = user;
+
+ logit("authenticate '%s' response='%s'\n", user, pass);
+
+ *reenter = 0;
+ *message = NULL;
+
+ /* Send off request */
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if (*user == WB_AIX_ENCODED) {
+ r_user = decode_user(r_user);
+ if (!r_user) {
+ return AUTH_NOTFOUND;
+ }
+ }
+
+ STRCPY_RET(request.data.auth.user, r_user);
+ STRCPY_RET(request.data.auth.pass, pass);
+
+ if (*user == WB_AIX_ENCODED) {
+ free(r_user);
+ }
+
+ result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
+
+ winbindd_free_response(&response);
+
+ logit("auth result %d for '%s'\n", result, user);
+
+ if (result == NSS_STATUS_SUCCESS) {
+ errno = 0;
+ return AUTH_SUCCESS;
+ }
+
+ return AUTH_FAILURE;
+}
+
+
+/*
+ change a user password
+*/
+static int wb_aix_chpass(char *user, char *oldpass, char *newpass, char **message)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+ char *r_user = user;
+
+ if (*user == WB_AIX_ENCODED) {
+ r_user = decode_user(r_user);
+ if (!r_user) {
+ errno = ENOENT;
+ return -1;
+ }
+ }
+
+ logit("chpass '%s' old='%s' new='%s'\n", r_user, oldpass, newpass);
+
+ *message = NULL;
+
+ /* Send off request */
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ STRCPY_RET(request.data.chauthtok.user, r_user);
+ STRCPY_RET(request.data.chauthtok.oldpass, oldpass);
+ STRCPY_RET(request.data.chauthtok.newpass, newpass);
+
+ if (*user == WB_AIX_ENCODED) {
+ free(r_user);
+ }
+
+ result = winbindd_request_response(WINBINDD_PAM_CHAUTHTOK, &request, &response);
+
+ winbindd_free_response(&response);
+
+ if (result == NSS_STATUS_SUCCESS) {
+ errno = 0;
+ return 0;
+ }
+
+ errno = EINVAL;
+ return -1;
+}
+
+/*
+ don't do any password strength testing for now
+*/
+static int wb_aix_passwdrestrictions(char *user, char *newpass, char *oldpass,
+ char **message)
+{
+ logit("passwdresrictions called for '%s'\n", user);
+ return 0;
+}
+
+
+static int wb_aix_passwdexpired(char *user, char **message)
+{
+ logit("passwdexpired '%s'\n", user);
+ /* we should check the account bits here */
+ return 0;
+}
+
+
+/*
+ we can't return a crypt() password
+*/
+static char *wb_aix_getpasswd(char *user)
+{
+ logit("getpasswd '%s'\n", user);
+ errno = ENOSYS;
+ return NULL;
+}
+
+/*
+ this is called to update things like the last login time. We don't
+ currently pass this onto the DC
+*/
+static int wb_aix_putentry(char *key, char *table, char *attributes[],
+ attrval_t values[], int size)
+{
+ logit("putentry key='%s' table='%s' attrib='%s'\n",
+ key, table, size>=1?attributes[0]:"<null>");
+ errno = ENOSYS;
+ return -1;
+}
+
+static int wb_aix_commit(char *key, char *table)
+{
+ logit("commit key='%s' table='%s'\n");
+ errno = ENOSYS;
+ return -1;
+}
+
+static int wb_aix_getgrusers(char *group, void *result, int type, int *size)
+{
+ logit("getgrusers group='%s'\n", group);
+ errno = ENOSYS;
+ return -1;
+}
+
+
+#define DECL_METHOD(x) \
+int method_ ## x(void) \
+{ \
+ logit("UNIMPLEMENTED METHOD '%s'\n", #x); \
+ errno = EINVAL; \
+ return -1; \
+}
+
+#if LOG_UNIMPLEMENTED_CALLS
+DECL_METHOD(delgroup);
+DECL_METHOD(deluser);
+DECL_METHOD(newgroup);
+DECL_METHOD(newuser);
+DECL_METHOD(putgrent);
+DECL_METHOD(putgrusers);
+DECL_METHOD(putpwent);
+DECL_METHOD(lock);
+DECL_METHOD(unlock);
+DECL_METHOD(getcred);
+DECL_METHOD(setcred);
+DECL_METHOD(deletecred);
+#endif
+
+int wb_aix_init(struct secmethod_table *methods)
+{
+ ZERO_STRUCTP(methods);
+
+#ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_VERSION
+ methods->method_version = SECMETHOD_VERSION_520;
+#endif
+
+ methods->method_getgrgid = wb_aix_getgrgid;
+ methods->method_getgrnam = wb_aix_getgrnam;
+ methods->method_getgrset = wb_aix_getgrset;
+ methods->method_getpwnam = wb_aix_getpwnam;
+ methods->method_getpwuid = wb_aix_getpwuid;
+ methods->method_getentry = wb_aix_getentry;
+ methods->method_open = wb_aix_open;
+ methods->method_close = wb_aix_close;
+ methods->method_normalize = wb_aix_normalize;
+ methods->method_passwdexpired = wb_aix_passwdexpired;
+ methods->method_putentry = wb_aix_putentry;
+ methods->method_getpasswd = wb_aix_getpasswd;
+ methods->method_authenticate = wb_aix_authenticate;
+ methods->method_commit = wb_aix_commit;
+ methods->method_chpass = wb_aix_chpass;
+ methods->method_passwdrestrictions = wb_aix_passwdrestrictions;
+ methods->method_getgracct = wb_aix_getgracct;
+ methods->method_getgrusers = wb_aix_getgrusers;
+#ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
+ methods->method_attrlist = wb_aix_attrlist;
+#endif
+
+#if LOG_UNIMPLEMENTED_CALLS
+ methods->method_delgroup = method_delgroup;
+ methods->method_deluser = method_deluser;
+ methods->method_newgroup = method_newgroup;
+ methods->method_newuser = method_newuser;
+ methods->method_putgrent = method_putgrent;
+ methods->method_putgrusers = method_putgrusers;
+ methods->method_putpwent = method_putpwent;
+ methods->method_lock = method_lock;
+ methods->method_unlock = method_unlock;
+ methods->method_getcred = method_getcred;
+ methods->method_setcred = method_setcred;
+ methods->method_deletecred = method_deletecred;
+#endif
+
+ return AUTH_SUCCESS;
+}
+
diff --git a/source3/nsswitch/winbind_nss_config.h b/source3/nsswitch/winbind_nss_config.h
new file mode 100644
index 0000000000..64d52af771
--- /dev/null
+++ b/source3/nsswitch/winbind_nss_config.h
@@ -0,0 +1,69 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon for ntdom nss module
+
+ Copyright (C) Tim Potter 2000
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _WINBIND_NSS_CONFIG_H
+#define _WINBIND_NSS_CONFIG_H
+
+/* shutup the compiler warnings due to krb5.h on 64-bit sles9 */
+#ifdef SIZEOF_LONG
+#undef SIZEOF_LONG
+#endif
+
+/*
+ * we don't need socket wrapper
+ * nor nss wrapper here and we don't
+ * want to depend on swrap_close()
+ * so we better disable both
+ */
+#define SOCKET_WRAPPER_NOT_REPLACE
+#define NSS_WRAPPER_NOT_REPLACE
+
+/* Include header files from data in config.h file */
+
+#ifndef NO_CONFIG_H
+#include "lib/replace/replace.h"
+#endif
+
+#include "system/filesys.h"
+#include "system/network.h"
+#include "system/passwd.h"
+
+#include "nsswitch/winbind_nss.h"
+
+/* I'm trying really hard not to include anything from smb.h with the
+ result of some silly looking redeclaration of structures. */
+
+#ifndef FSTRING_LEN
+#define FSTRING_LEN 256
+typedef char fstring[FSTRING_LEN];
+#endif
+
+/* Some systems (SCO) treat UNIX domain sockets as FIFOs */
+
+#ifndef S_IFSOCK
+#define S_IFSOCK S_IFIFO
+#endif
+
+#ifndef S_ISSOCK
+#define S_ISSOCK(mode) ((mode & S_IFSOCK) == S_IFSOCK)
+#endif
+
+#endif
diff --git a/source3/nsswitch/winbind_nss_freebsd.c b/source3/nsswitch/winbind_nss_freebsd.c
new file mode 100644
index 0000000000..02e29f3131
--- /dev/null
+++ b/source3/nsswitch/winbind_nss_freebsd.c
@@ -0,0 +1,79 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ AIX loadable authentication module, providing identification
+ routines against Samba winbind/Windows NT Domain
+
+ Copyright (C) Aaron Collins 2003
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "winbind_client.h"
+
+/* Make sure that the module gets registered needed by freebsd 5.1 */
+
+extern enum nss_status _nss_winbind_getgrent_r(struct group *, char *, size_t,
+ int *);
+extern enum nss_status _nss_winbind_getgrnam_r(const char *, struct group *,
+ char *, size_t, int *);
+extern enum nss_status _nss_winbind_getgrgid_r(gid_t gid, struct group *, char *,
+ size_t, int *);
+extern enum nss_status _nss_winbind_setgrent(void);
+extern enum nss_status _nss_winbind_endgrent(void);
+
+extern enum nss_status _nss_winbind_getpwent_r(struct passwd *, char *, size_t,
+ int *);
+extern enum nss_status _nss_winbind_getpwnam_r(const char *, struct passwd *,
+ char *, size_t, int *);
+extern enum nss_status _nss_winbind_getpwuid_r(gid_t gid, struct passwd *, char *,
+ size_t, int *);
+extern enum nss_status _nss_winbind_setpwent(void);
+extern enum nss_status _nss_winbind_endpwent(void);
+
+NSS_METHOD_PROTOTYPE(__nss_compat_getgrnam_r);
+NSS_METHOD_PROTOTYPE(__nss_compat_getgrgid_r);
+NSS_METHOD_PROTOTYPE(__nss_compat_getgrent_r);
+NSS_METHOD_PROTOTYPE(__nss_compat_setgrent);
+NSS_METHOD_PROTOTYPE(__nss_compat_endgrent);
+
+NSS_METHOD_PROTOTYPE(__nss_compat_getpwnam_r);
+NSS_METHOD_PROTOTYPE(__nss_compat_getpwuid_r);
+NSS_METHOD_PROTOTYPE(__nss_compat_getpwent_r);
+NSS_METHOD_PROTOTYPE(__nss_compat_setpwent);
+NSS_METHOD_PROTOTYPE(__nss_compat_endpwent);
+
+static ns_mtab methods[] = {
+{ NSDB_GROUP, "getgrnam_r", __nss_compat_getgrnam_r, _nss_winbind_getgrnam_r },
+{ NSDB_GROUP, "getgrgid_r", __nss_compat_getgrgid_r, _nss_winbind_getgrgid_r },
+{ NSDB_GROUP, "getgrent_r", __nss_compat_getgrent_r, _nss_winbind_getgrent_r },
+{ NSDB_GROUP, "endgrent", __nss_compat_setgrent, _nss_winbind_setgrent },
+{ NSDB_GROUP, "setgrent", __nss_compat_endgrent, _nss_winbind_endgrent },
+
+{ NSDB_PASSWD, "getpwnam_r", __nss_compat_getpwnam_r, _nss_winbind_getpwnam_r },
+{ NSDB_PASSWD, "getpwuid_r", __nss_compat_getpwuid_r, _nss_winbind_getpwuid_r },
+{ NSDB_PASSWD, "getpwent_r", __nss_compat_getpwent_r, _nss_winbind_getpwent_r },
+{ NSDB_PASSWD, "endpwent", __nss_compat_setpwent, _nss_winbind_setpwent },
+{ NSDB_PASSWD, "setpwent", __nss_compat_endpwent, _nss_winbind_endpwent },
+
+};
+
+ns_mtab *
+nss_module_register(const char *source, unsigned int *mtabsize,
+ nss_module_unregister_fn *unreg)
+{
+ *mtabsize = sizeof(methods)/sizeof(methods[0]);
+ *unreg = NULL;
+ return (methods);
+}
diff --git a/source3/nsswitch/winbind_nss_hpux.h b/source3/nsswitch/winbind_nss_hpux.h
new file mode 100644
index 0000000000..62cf3c26c5
--- /dev/null
+++ b/source3/nsswitch/winbind_nss_hpux.h
@@ -0,0 +1,137 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Donated by HP to enable Winbindd to build on HPUX 11.x.
+ Copyright (C) Jeremy Allison 2002.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _WINBIND_NSS_HPUX_H
+#define _WINBIND_NSS_HPUX_H
+
+#include <nsswitch.h>
+
+#define NSS_STATUS_SUCCESS NSS_SUCCESS
+#define NSS_STATUS_NOTFOUND NSS_NOTFOUND
+#define NSS_STATUS_UNAVAIL NSS_UNAVAIL
+#define NSS_STATUS_TRYAGAIN NSS_TRYAGAIN
+
+#ifdef HAVE_SYNCH_H
+#include <synch.h>
+#endif
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+
+typedef enum {
+ NSS_SUCCESS,
+ NSS_NOTFOUND,
+ NSS_UNAVAIL,
+ NSS_TRYAGAIN
+} nss_status_t;
+
+typedef nss_status_t NSS_STATUS;
+
+struct nss_backend;
+
+typedef nss_status_t (*nss_backend_op_t)(struct nss_backend *, void *args);
+
+struct nss_backend {
+ nss_backend_op_t *ops;
+ int n_ops;
+};
+typedef struct nss_backend nss_backend_t;
+typedef int nss_dbop_t;
+
+#include <errno.h>
+#include <netdb.h>
+#include <limits.h>
+
+#ifndef NSS_INCLUDE_UNSAFE
+#define NSS_INCLUDE_UNSAFE 1 /* Build old, MT-unsafe interfaces, */
+#endif /* NSS_INCLUDE_UNSAFE */
+
+enum nss_netgr_argn {
+ NSS_NETGR_MACHINE,
+ NSS_NETGR_USER,
+ NSS_NETGR_DOMAIN,
+ NSS_NETGR_N
+};
+
+enum nss_netgr_status {
+ NSS_NETGR_FOUND,
+ NSS_NETGR_NO,
+ NSS_NETGR_NOMEM
+};
+
+typedef unsigned nss_innetgr_argc;
+typedef char **nss_innetgr_argv;
+
+struct nss_innetgr_1arg {
+ nss_innetgr_argc argc;
+ nss_innetgr_argv argv;
+};
+
+typedef struct {
+ void *result; /* "result" parameter to getXbyY_r() */
+ char *buffer; /* "buffer" " " */
+ int buflen; /* "buflen" " " */
+} nss_XbyY_buf_t;
+
+extern nss_XbyY_buf_t *_nss_XbyY_buf_alloc(int struct_size, int buffer_size);
+extern void _nss_XbyY_buf_free(nss_XbyY_buf_t *);
+
+union nss_XbyY_key {
+ uid_t uid;
+ gid_t gid;
+ const char *name;
+ int number;
+ struct {
+ long net;
+ int type;
+ } netaddr;
+ struct {
+ const char *addr;
+ int len;
+ int type;
+ } hostaddr;
+ struct {
+ union {
+ const char *name;
+ int port;
+ } serv;
+ const char *proto;
+ } serv;
+ void *ether;
+};
+
+typedef struct nss_XbyY_args {
+ nss_XbyY_buf_t buf;
+ int stayopen;
+ /*
+ * Support for setXXXent(stayopen)
+ * Used only in hosts, protocols,
+ * networks, rpc, and services.
+ */
+ int (*str2ent)(const char *instr, int instr_len, void *ent, char *buffer, int buflen);
+ union nss_XbyY_key key;
+
+ void *returnval;
+ int erange;
+ int h_errno;
+ nss_status_t status;
+} nss_XbyY_args_t;
+
+#endif /* _WINBIND_NSS_HPUX_H */
diff --git a/source3/nsswitch/winbind_nss_irix.c b/source3/nsswitch/winbind_nss_irix.c
new file mode 100644
index 0000000000..4726c1e13f
--- /dev/null
+++ b/source3/nsswitch/winbind_nss_irix.c
@@ -0,0 +1,634 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Windows NT Domain nsswitch module
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) James Peach 2006
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "winbind_client.h"
+
+#ifndef PRINTF_ATTRIBUTE
+#define PRINTF_ATTRIBUTE(m, n)
+#endif
+
+#ifndef HAVE_ASPRINTF_DECL
+/*PRINTFLIKE2 */
+int asprintf(char **,const char *, ...) PRINTF_ATTRIBUTE(2,3);
+#endif
+
+#ifdef HAVE_NS_API_H
+#undef VOLATILE
+#undef STATIC
+#undef DYNAMIC
+#include <ns_daemon.h>
+#endif
+
+/* Maximum number of users to pass back over the unix domain socket
+ per call. This is not a static limit on the total number of users
+ or groups returned in total. */
+
+#define MAX_GETPWENT_USERS 250
+#define MAX_GETGRENT_USERS 250
+
+/* Prototypes from wb_common.c */
+
+extern int winbindd_fd;
+
+#ifdef HAVE_NS_API_H
+
+/* IRIX version */
+
+static int send_next_request(nsd_file_t *, struct winbindd_request *);
+static int do_list(int state, nsd_file_t *rq);
+
+static nsd_file_t *current_rq = NULL;
+static int current_winbind_xid = 0;
+static int next_winbind_xid = 0;
+
+typedef struct winbind_xid {
+ int xid;
+ nsd_file_t *rq;
+ struct winbindd_request *request;
+ struct winbind_xid *next;
+} winbind_xid_t;
+
+static winbind_xid_t *winbind_xids = (winbind_xid_t *)0;
+
+static int
+winbind_xid_new(int xid, nsd_file_t *rq, struct winbindd_request *request)
+{
+ winbind_xid_t *new;
+
+ nsd_logprintf(NSD_LOG_LOW,
+ "entering winbind_xid_new xid = %d rq = 0x%x, request = 0x%x\n",
+ xid, rq, request);
+ new = (winbind_xid_t *)nsd_calloc(1,sizeof(winbind_xid_t));
+ if (!new) {
+ nsd_logprintf(NSD_LOG_RESOURCE,"winbind_xid_new: failed malloc\n");
+ return NSD_ERROR;
+ }
+
+ new->xid = xid;
+ new->rq = rq;
+ new->request = request;
+ new->next = winbind_xids;
+ winbind_xids = new;
+
+ return NSD_CONTINUE;
+}
+
+/*
+** This routine will look down the xid list and return the request
+** associated with an xid. We remove the record if it is found.
+*/
+nsd_file_t *
+winbind_xid_lookup(int xid, struct winbindd_request **requestp)
+{
+ winbind_xid_t **last, *dx;
+ nsd_file_t *result=0;
+
+ for (last = &winbind_xids, dx = winbind_xids; dx && (dx->xid != xid);
+ last = &dx->next, dx = dx->next);
+ if (dx) {
+ *last = dx->next;
+ result = dx->rq;
+ *requestp = dx->request;
+ SAFE_FREE(dx);
+ }
+ nsd_logprintf(NSD_LOG_LOW,
+ "entering winbind_xid_lookup xid = %d rq = 0x%x, request = 0x%x\n",
+ xid, result, dx->request);
+
+ return result;
+}
+
+static int
+winbind_startnext_timeout(nsd_file_t **rqp, nsd_times_t *to)
+{
+ nsd_file_t *rq;
+ struct winbindd_request *request;
+
+ nsd_logprintf(NSD_LOG_MIN, "timeout (winbind startnext)\n");
+ rq = to->t_file;
+ *rqp = rq;
+ nsd_timeout_remove(rq);
+ request = to->t_clientdata;
+ return(send_next_request(rq, request));
+}
+
+static void
+dequeue_request(void)
+{
+ nsd_file_t *rq;
+ struct winbindd_request *request;
+
+ /*
+ * Check for queued requests
+ */
+ if (winbind_xids) {
+ nsd_logprintf(NSD_LOG_MIN, "timeout (winbind) unqueue xid %d\n",
+ current_winbind_xid);
+ rq = winbind_xid_lookup(current_winbind_xid++, &request);
+ /* cause a timeout on the queued request so we can send it */
+ nsd_timeout_new(rq,1,winbind_startnext_timeout,request);
+ }
+}
+
+static int
+do_request(nsd_file_t *rq, struct winbindd_request *request)
+{
+ if (winbind_xids == NULL) {
+ /*
+ * No outstanding requests.
+ * Send off the request to winbindd
+ */
+ nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) sending request\n");
+ return(send_next_request(rq, request));
+ } else {
+ /*
+ * Just queue it up for now - previous callout or timout
+ * will start it up
+ */
+ nsd_logprintf(NSD_LOG_MIN,
+ "lookup (winbind): queue request xid = %d\n",
+ next_winbind_xid);
+ return(winbind_xid_new(next_winbind_xid++, rq, request));
+ }
+}
+
+static int
+winbind_callback(nsd_file_t **rqp, int fd)
+{
+ struct winbindd_response response;
+ nsd_file_t *rq;
+ NSS_STATUS status;
+ char * result = NULL;
+ size_t rlen;
+
+ dequeue_request();
+
+ nsd_logprintf(NSD_LOG_MIN, "entering callback (winbind)\n");
+
+ rq = current_rq;
+ *rqp = rq;
+
+ nsd_timeout_remove(rq);
+ nsd_callback_remove(fd);
+
+ ZERO_STRUCT(response);
+ status = winbindd_get_response(&response);
+
+ if (status != NSS_STATUS_SUCCESS) {
+ /* free any extra data area in response structure */
+ winbindd_free_response(&response);
+ nsd_logprintf(NSD_LOG_MIN,
+ "callback (winbind) returning not found, status = %d\n",
+ status);
+
+ switch (status) {
+ case NSS_STATUS_UNAVAIL:
+ rq->f_status = NS_UNAVAIL;
+ break;
+ case NSS_STATUS_TRYAGAIN:
+ rq->f_status = NS_TRYAGAIN;
+ break;
+ case NSS_STATUS_NOTFOUND:
+ /* FALLTHRU */
+ default:
+ rq->f_status = NS_NOTFOUND;
+ }
+
+ return NSD_NEXT;
+ }
+
+ switch ((int)rq->f_cmd_data) {
+ case WINBINDD_WINS_BYNAME:
+ case WINBINDD_WINS_BYIP:
+ nsd_logprintf(NSD_LOG_MIN,
+ "callback (winbind) WINS_BYNAME | WINS_BYIP\n");
+
+ rlen = asprintf(&result, "%s\n", response.data.winsresp);
+ if (rlen == 0 || result == NULL) {
+ return NSD_ERROR;
+ }
+
+ winbindd_free_response(&response);
+
+ nsd_logprintf(NSD_LOG_MIN, " %s\n", result);
+ nsd_set_result(rq, NS_SUCCESS, result, rlen, DYNAMIC);
+ return NSD_OK;
+
+ case WINBINDD_GETPWUID:
+ case WINBINDD_GETPWNAM:
+ {
+ struct winbindd_pw *pw = &response.data.pw;
+
+ nsd_logprintf(NSD_LOG_MIN,
+ "callback (winbind) GETPWUID | GETPWUID\n");
+
+ rlen = asprintf(&result,"%s:%s:%d:%d:%s:%s:%s\n",
+ pw->pw_name,
+ pw->pw_passwd,
+ pw->pw_uid,
+ pw->pw_gid,
+ pw->pw_gecos,
+ pw->pw_dir,
+ pw->pw_shell);
+ if (rlen == 0 || result == NULL)
+ return NSD_ERROR;
+
+ winbindd_free_response(&response);
+
+ nsd_logprintf(NSD_LOG_MIN, " %s\n", result);
+ nsd_set_result(rq, NS_SUCCESS, result, rlen, DYNAMIC);
+ return NSD_OK;
+ }
+
+ case WINBINDD_GETGRNAM:
+ case WINBINDD_GETGRGID:
+ {
+ const struct winbindd_gr *gr = &response.data.gr;
+ const char * members;
+
+ nsd_logprintf(NSD_LOG_MIN,
+ "callback (winbind) GETGRNAM | GETGRGID\n");
+
+ if (gr->num_gr_mem && response.extra_data.data) {
+ members = response.extra_data.data;
+ } else {
+ members = "";
+ }
+
+ rlen = asprintf(&result, "%s:%s:%d:%s\n",
+ gr->gr_name, gr->gr_passwd, gr->gr_gid, members);
+ if (rlen == 0 || result == NULL)
+ return NSD_ERROR;
+
+ winbindd_free_response(&response);
+
+ nsd_logprintf(NSD_LOG_MIN, " %s\n", result);
+ nsd_set_result(rq, NS_SUCCESS, result, rlen, DYNAMIC);
+ return NSD_OK;
+ }
+
+ case WINBINDD_SETGRENT:
+ case WINBINDD_SETPWENT:
+ nsd_logprintf(NSD_LOG_MIN,
+ "callback (winbind) SETGRENT | SETPWENT\n");
+ winbindd_free_response(&response);
+ return(do_list(1,rq));
+
+ case WINBINDD_GETGRENT:
+ case WINBINDD_GETGRLST:
+ {
+ int entries;
+
+ nsd_logprintf(NSD_LOG_MIN,
+ "callback (winbind) GETGRENT | GETGRLIST %d responses\n",
+ response.data.num_entries);
+
+ if (response.data.num_entries) {
+ const struct winbindd_gr *gr = &response.data.gr;
+ const char * members;
+ fstring grp_name;
+ int i;
+
+ gr = (struct winbindd_gr *)response.extra_data.data;
+ if (! gr ) {
+ nsd_logprintf(NSD_LOG_MIN, " no extra_data\n");
+ winbindd_free_response(&response);
+ return NSD_ERROR;
+ }
+
+ members = (char *)response.extra_data.data +
+ (response.data.num_entries * sizeof(struct winbindd_gr));
+
+ for (i = 0; i < response.data.num_entries; i++) {
+ snprintf(grp_name, sizeof(grp_name) - 1, "%s:%s:%d:",
+ gr->gr_name, gr->gr_passwd, gr->gr_gid);
+
+ nsd_append_element(rq, NS_SUCCESS, result, rlen);
+ nsd_append_result(rq, NS_SUCCESS,
+ &members[gr->gr_mem_ofs],
+ strlen(&members[gr->gr_mem_ofs]));
+
+ /* Don't log the whole list, because it might be
+ * _really_ long and we probably don't want to clobber
+ * the log with it.
+ */
+ nsd_logprintf(NSD_LOG_MIN, " %s (...)\n", grp_name);
+
+ gr++;
+ }
+ }
+
+ entries = response.data.num_entries;
+ winbindd_free_response(&response);
+ if (entries < MAX_GETPWENT_USERS)
+ return(do_list(2,rq));
+ else
+ return(do_list(1,rq));
+ }
+
+ case WINBINDD_GETPWENT:
+ {
+ int entries;
+
+ nsd_logprintf(NSD_LOG_MIN,
+ "callback (winbind) GETPWENT %d responses\n",
+ response.data.num_entries);
+
+ if (response.data.num_entries) {
+ struct winbindd_pw *pw = &response.data.pw;
+ int i;
+
+ pw = (struct winbindd_pw *)response.extra_data.data;
+ if (! pw ) {
+ nsd_logprintf(NSD_LOG_MIN, " no extra_data\n");
+ winbindd_free_response(&response);
+ return NSD_ERROR;
+ }
+ for (i = 0; i < response.data.num_entries; i++) {
+ result = NULL;
+ rlen = asprintf(&result, "%s:%s:%d:%d:%s:%s:%s",
+ pw->pw_name,
+ pw->pw_passwd,
+ pw->pw_uid,
+ pw->pw_gid,
+ pw->pw_gecos,
+ pw->pw_dir,
+ pw->pw_shell);
+
+ if (rlen != 0 && result != NULL) {
+ nsd_logprintf(NSD_LOG_MIN, " %s\n",result);
+ nsd_append_element(rq, NS_SUCCESS, result, rlen);
+ free(result);
+ }
+
+ pw++;
+ }
+ }
+
+ entries = response.data.num_entries;
+ winbindd_free_response(&response);
+ if (entries < MAX_GETPWENT_USERS)
+ return(do_list(2,rq));
+ else
+ return(do_list(1,rq));
+ }
+
+ case WINBINDD_ENDGRENT:
+ case WINBINDD_ENDPWENT:
+ nsd_logprintf(NSD_LOG_MIN, "callback (winbind) ENDGRENT | ENDPWENT\n");
+ nsd_append_element(rq, NS_SUCCESS, "\n", 1);
+ winbindd_free_response(&response);
+ return NSD_NEXT;
+
+ default:
+ winbindd_free_response(&response);
+ nsd_logprintf(NSD_LOG_MIN, "callback (winbind) invalid command %d\n", (int)rq->f_cmd_data);
+ return NSD_NEXT;
+ }
+}
+
+static int
+winbind_timeout(nsd_file_t **rqp, nsd_times_t *to)
+{
+ nsd_file_t *rq;
+
+ dequeue_request();
+
+ nsd_logprintf(NSD_LOG_MIN, "timeout (winbind)\n");
+
+ rq = to->t_file;
+ *rqp = rq;
+
+ /* Remove the callback and timeout */
+ nsd_callback_remove(winbindd_fd);
+ nsd_timeout_remove(rq);
+
+ rq->f_status = NS_NOTFOUND;
+ return NSD_NEXT;
+}
+
+static int
+send_next_request(nsd_file_t *rq, struct winbindd_request *request)
+{
+ NSS_STATUS status;
+ long timeout;
+
+ switch (rq->f_index) {
+ case LOOKUP:
+ timeout = nsd_attr_fetch_long(rq->f_attrs,
+ "lookup_timeout", 10, 10);
+ break;
+ case LIST:
+ timeout = nsd_attr_fetch_long(rq->f_attrs,
+ "list_timeout", 10, 10);
+ break;
+ default:
+ nsd_logprintf(NSD_LOG_OPER,
+ "send_next_request (winbind) "
+ "invalid request type %d\n", rq->f_index);
+ rq->f_status = NS_BADREQ;
+ return NSD_NEXT;
+ }
+
+ nsd_logprintf(NSD_LOG_MIN,
+ "send_next_request (winbind) %d, timeout = %d sec\n",
+ rq->f_cmd_data, timeout);
+ status = winbindd_send_request((int)rq->f_cmd_data,0,request);
+ SAFE_FREE(request);
+
+ if (status != NSS_STATUS_SUCCESS) {
+ nsd_logprintf(NSD_LOG_MIN,
+ "send_next_request (winbind) error status = %d\n",
+ status);
+ rq->f_status = status;
+ return NSD_NEXT;
+ }
+
+ current_rq = rq;
+
+ /*
+ * Set up callback and timeouts
+ */
+ nsd_logprintf(NSD_LOG_MIN, "send_next_request (winbind) fd = %d\n",
+ winbindd_fd);
+
+ nsd_callback_new(winbindd_fd, winbind_callback, NSD_READ);
+ nsd_timeout_new(rq, timeout * 1000, winbind_timeout, NULL);
+ return NSD_CONTINUE;
+}
+
+int init(void)
+{
+ nsd_logprintf(NSD_LOG_MIN, "entering init (winbind)\n");
+ return(NSD_OK);
+}
+
+int lookup(nsd_file_t *rq)
+{
+ char *map;
+ char *key;
+ struct winbindd_request *request;
+
+ nsd_logprintf(NSD_LOG_MIN, "entering lookup (winbind)\n");
+ if (! rq)
+ return NSD_ERROR;
+
+ map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
+ key = nsd_attr_fetch_string(rq->f_attrs, "key", (char*)0);
+ if (! map || ! key) {
+ nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) table or key not defined\n");
+ rq->f_status = NS_BADREQ;
+ return NSD_ERROR;
+ }
+
+ nsd_logprintf(NSD_LOG_MIN, "lookup (winbind %s)\n",map);
+
+ request = (struct winbindd_request *)nsd_calloc(1,sizeof(struct winbindd_request));
+ if (! request) {
+ nsd_logprintf(NSD_LOG_RESOURCE,
+ "lookup (winbind): failed malloc\n");
+ return NSD_ERROR;
+ }
+
+ if (strcasecmp(map,"passwd.byuid") == 0) {
+ request->data.uid = atoi(key);
+ rq->f_cmd_data = (void *)WINBINDD_GETPWUID;
+ } else if (strcasecmp(map,"passwd.byname") == 0) {
+ strncpy(request->data.username, key,
+ sizeof(request->data.username) - 1);
+ request->data.username[sizeof(request->data.username) - 1] = '\0';
+ rq->f_cmd_data = (void *)WINBINDD_GETPWNAM;
+ } else if (strcasecmp(map,"group.byname") == 0) {
+ strncpy(request->data.groupname, key,
+ sizeof(request->data.groupname) - 1);
+ request->data.groupname[sizeof(request->data.groupname) - 1] = '\0';
+ rq->f_cmd_data = (void *)WINBINDD_GETGRNAM;
+ } else if (strcasecmp(map,"group.bygid") == 0) {
+ request->data.gid = atoi(key);
+ rq->f_cmd_data = (void *)WINBINDD_GETGRGID;
+ } else if (strcasecmp(map,"hosts.byname") == 0) {
+ strncpy(request->data.winsreq, key, sizeof(request->data.winsreq) - 1);
+ request->data.winsreq[sizeof(request->data.winsreq) - 1] = '\0';
+ rq->f_cmd_data = (void *)WINBINDD_WINS_BYNAME;
+ } else if (strcasecmp(map,"hosts.byaddr") == 0) {
+ strncpy(request->data.winsreq, key, sizeof(request->data.winsreq) - 1);
+ request->data.winsreq[sizeof(request->data.winsreq) - 1] = '\0';
+ rq->f_cmd_data = (void *)WINBINDD_WINS_BYIP;
+ } else {
+ /*
+ * Don't understand this map - just return not found
+ */
+ nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) unknown table\n");
+ SAFE_FREE(request);
+ rq->f_status = NS_NOTFOUND;
+ return NSD_NEXT;
+ }
+
+ return(do_request(rq, request));
+}
+
+int list(nsd_file_t *rq)
+{
+ char *map;
+
+ nsd_logprintf(NSD_LOG_MIN, "entering list (winbind)\n");
+ if (! rq)
+ return NSD_ERROR;
+
+ map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
+ if (! map ) {
+ nsd_logprintf(NSD_LOG_MIN, "list (winbind) table not defined\n");
+ rq->f_status = NS_BADREQ;
+ return NSD_ERROR;
+ }
+
+ nsd_logprintf(NSD_LOG_MIN, "list (winbind %s)\n",map);
+
+ return (do_list(0,rq));
+}
+
+static int
+do_list(int state, nsd_file_t *rq)
+{
+ char *map;
+ struct winbindd_request *request;
+
+ nsd_logprintf(NSD_LOG_MIN, "entering do_list (winbind) state = %d\n",state);
+
+ map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
+ request = (struct winbindd_request *)nsd_calloc(1,sizeof(struct winbindd_request));
+ if (! request) {
+ nsd_logprintf(NSD_LOG_RESOURCE,
+ "do_list (winbind): failed malloc\n");
+ return NSD_ERROR;
+ }
+
+ if (strcasecmp(map,"passwd.byname") == 0) {
+ switch (state) {
+ case 0:
+ rq->f_cmd_data = (void *)WINBINDD_SETPWENT;
+ break;
+ case 1:
+ request->data.num_entries = MAX_GETPWENT_USERS;
+ rq->f_cmd_data = (void *)WINBINDD_GETPWENT;
+ break;
+ case 2:
+ rq->f_cmd_data = (void *)WINBINDD_ENDPWENT;
+ break;
+ default:
+ nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown state\n");
+ SAFE_FREE(request);
+ rq->f_status = NS_NOTFOUND;
+ return NSD_NEXT;
+ }
+ } else if (strcasecmp(map,"group.byname") == 0) {
+ switch (state) {
+ case 0:
+ rq->f_cmd_data = (void *)WINBINDD_SETGRENT;
+ break;
+ case 1:
+ request->data.num_entries = MAX_GETGRENT_USERS;
+ rq->f_cmd_data = (void *)WINBINDD_GETGRENT;
+ break;
+ case 2:
+ rq->f_cmd_data = (void *)WINBINDD_ENDGRENT;
+ break;
+ default:
+ nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown state\n");
+ SAFE_FREE(request);
+ rq->f_status = NS_NOTFOUND;
+ return NSD_NEXT;
+ }
+ } else {
+ /*
+ * Don't understand this map - just return not found
+ */
+ nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown table\n");
+ SAFE_FREE(request);
+ rq->f_status = NS_NOTFOUND;
+ return NSD_NEXT;
+ }
+
+ return(do_request(rq, request));
+}
+
+#endif /* HAVE_NS_API_H */
diff --git a/source3/nsswitch/winbind_nss_irix.h b/source3/nsswitch/winbind_nss_irix.h
new file mode 100644
index 0000000000..b40b14b0b0
--- /dev/null
+++ b/source3/nsswitch/winbind_nss_irix.h
@@ -0,0 +1,42 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon for ntdom nss module
+
+ Copyright (C) Tim Potter 2000
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _WINBIND_NSS_IRIX_H
+#define _WINBIND_NSS_IRIX_H
+
+/* following required to prevent warnings of double definition
+ * of datum from ns_api.h
+*/
+#ifdef DATUM
+#define _DATUM_DEFINED
+#endif
+
+#include <ns_api.h>
+
+typedef enum
+{
+ NSS_STATUS_SUCCESS=NS_SUCCESS,
+ NSS_STATUS_NOTFOUND=NS_NOTFOUND,
+ NSS_STATUS_UNAVAIL=NS_UNAVAIL,
+ NSS_STATUS_TRYAGAIN=NS_TRYAGAIN
+} NSS_STATUS;
+
+#endif /* _WINBIND_NSS_IRIX_H */
diff --git a/source3/nsswitch/winbind_nss_linux.c b/source3/nsswitch/winbind_nss_linux.c
new file mode 100644
index 0000000000..c11c18759e
--- /dev/null
+++ b/source3/nsswitch/winbind_nss_linux.c
@@ -0,0 +1,1477 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Windows NT Domain nsswitch module
+
+ Copyright (C) Tim Potter 2000
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "winbind_client.h"
+
+#if HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+
+#if HAVE_PTHREAD
+static pthread_mutex_t winbind_nss_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+/* Maximum number of users to pass back over the unix domain socket
+ per call. This is not a static limit on the total number of users
+ or groups returned in total. */
+
+#define MAX_GETPWENT_USERS 250
+#define MAX_GETGRENT_USERS 250
+
+NSS_STATUS _nss_winbind_setpwent(void);
+NSS_STATUS _nss_winbind_endpwent(void);
+NSS_STATUS _nss_winbind_getpwent_r(struct passwd *result, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result,
+ char *buffer, size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_getpwnam_r(const char *name, struct passwd *result,
+ char *buffer, size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_setgrent(void);
+NSS_STATUS _nss_winbind_endgrent(void);
+NSS_STATUS _nss_winbind_getgrent_r(struct group *result, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_getgrlst_r(struct group *result, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_getgrnam_r(const char *name, struct group *result,
+ char *buffer, size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_getgrgid_r(gid_t gid, struct group *result, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start,
+ long int *size, gid_t **groups,
+ long int limit, int *errnop);
+NSS_STATUS _nss_winbind_getusersids(const char *user_sid, char **group_sids,
+ int *num_groups, char *buffer, size_t buf_size,
+ int *errnop);
+NSS_STATUS _nss_winbind_nametosid(const char *name, char **sid, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_sidtoname(const char *sid, char **name, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_sidtouid(const char *sid, uid_t *uid, int *errnop);
+NSS_STATUS _nss_winbind_sidtogid(const char *sid, gid_t *gid, int *errnop);
+NSS_STATUS _nss_winbind_uidtosid(uid_t uid, char **sid, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_gidtosid(gid_t gid, char **sid, char *buffer,
+ size_t buflen, int *errnop);
+
+/* Prototypes from wb_common.c */
+
+/* Allocate some space from the nss static buffer. The buffer and buflen
+ are the pointers passed in by the C library to the _nss_ntdom_*
+ functions. */
+
+static char *get_static(char **buffer, size_t *buflen, size_t len)
+{
+ char *result;
+
+ /* Error check. We return false if things aren't set up right, or
+ there isn't enough buffer space left. */
+
+ if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
+ return NULL;
+ }
+
+ /* Return an index into the static buffer */
+
+ result = *buffer;
+ *buffer += len;
+ *buflen -= len;
+
+ return result;
+}
+
+/* I've copied the strtok() replacement function next_token_Xalloc() from
+ lib/util_str.c as I really don't want to have to link in any other
+ objects if I can possibly avoid it. */
+
+static bool next_token_alloc(const char **ptr,
+ char **pp_buff,
+ const char *sep)
+{
+ char *s;
+ char *saved_s;
+ char *pbuf;
+ bool quoted;
+ size_t len=1;
+
+ *pp_buff = NULL;
+ if (!ptr) {
+ return(false);
+ }
+
+ s = (char *)*ptr;
+
+ /* default to simple separators */
+ if (!sep) {
+ sep = " \t\n\r";
+ }
+
+ /* find the first non sep char */
+ while (*s && strchr(sep,*s)) {
+ s++;
+ }
+
+ /* nothing left? */
+ if (!*s) {
+ return false;
+ }
+
+ /* When restarting we need to go from here. */
+ saved_s = s;
+
+ /* Work out the length needed. */
+ for (quoted = false; *s &&
+ (quoted || !strchr(sep,*s)); s++) {
+ if (*s == '\"') {
+ quoted = !quoted;
+ } else {
+ len++;
+ }
+ }
+
+ /* We started with len = 1 so we have space for the nul. */
+ *pp_buff = (char *)malloc(len);
+ if (!*pp_buff) {
+ return false;
+ }
+
+ /* copy over the token */
+ pbuf = *pp_buff;
+ s = saved_s;
+ for (quoted = false; *s &&
+ (quoted || !strchr(sep,*s)); s++) {
+ if ( *s == '\"' ) {
+ quoted = !quoted;
+ } else {
+ *pbuf++ = *s;
+ }
+ }
+
+ *ptr = (*s) ? s+1 : s;
+ *pbuf = 0;
+
+ return true;
+}
+
+/* Fill a pwent structure from a winbindd_response structure. We use
+ the static data passed to us by libc to put strings and stuff in.
+ Return NSS_STATUS_TRYAGAIN if we run out of memory. */
+
+static NSS_STATUS fill_pwent(struct passwd *result,
+ struct winbindd_pw *pw,
+ char **buffer, size_t *buflen)
+{
+ /* User name */
+
+ if ((result->pw_name =
+ get_static(buffer, buflen, strlen(pw->pw_name) + 1)) == NULL) {
+
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ strcpy(result->pw_name, pw->pw_name);
+
+ /* Password */
+
+ if ((result->pw_passwd =
+ get_static(buffer, buflen, strlen(pw->pw_passwd) + 1)) == NULL) {
+
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ strcpy(result->pw_passwd, pw->pw_passwd);
+
+ /* [ug]id */
+
+ result->pw_uid = pw->pw_uid;
+ result->pw_gid = pw->pw_gid;
+
+ /* GECOS */
+
+ if ((result->pw_gecos =
+ get_static(buffer, buflen, strlen(pw->pw_gecos) + 1)) == NULL) {
+
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ strcpy(result->pw_gecos, pw->pw_gecos);
+
+ /* Home directory */
+
+ if ((result->pw_dir =
+ get_static(buffer, buflen, strlen(pw->pw_dir) + 1)) == NULL) {
+
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ strcpy(result->pw_dir, pw->pw_dir);
+
+ /* Logon shell */
+
+ if ((result->pw_shell =
+ get_static(buffer, buflen, strlen(pw->pw_shell) + 1)) == NULL) {
+
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ strcpy(result->pw_shell, pw->pw_shell);
+
+ /* The struct passwd for Solaris has some extra fields which must
+ be initialised or nscd crashes. */
+
+#if HAVE_PASSWD_PW_COMMENT
+ result->pw_comment = "";
+#endif
+
+#if HAVE_PASSWD_PW_AGE
+ result->pw_age = "";
+#endif
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/* Fill a grent structure from a winbindd_response structure. We use
+ the static data passed to us by libc to put strings and stuff in.
+ Return NSS_STATUS_TRYAGAIN if we run out of memory. */
+
+static NSS_STATUS fill_grent(struct group *result, struct winbindd_gr *gr,
+ char *gr_mem, char **buffer, size_t *buflen)
+{
+ char *name;
+ int i;
+ char *tst;
+
+ /* Group name */
+
+ if ((result->gr_name =
+ get_static(buffer, buflen, strlen(gr->gr_name) + 1)) == NULL) {
+
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ strcpy(result->gr_name, gr->gr_name);
+
+ /* Password */
+
+ if ((result->gr_passwd =
+ get_static(buffer, buflen, strlen(gr->gr_passwd) + 1)) == NULL) {
+
+ /* Out of memory */
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ strcpy(result->gr_passwd, gr->gr_passwd);
+
+ /* gid */
+
+ result->gr_gid = gr->gr_gid;
+
+ /* Group membership */
+
+ if ((gr->num_gr_mem < 0) || !gr_mem) {
+ gr->num_gr_mem = 0;
+ }
+
+ /* this next value is a pointer to a pointer so let's align it */
+
+ /* Calculate number of extra bytes needed to align on pointer size boundry */
+ if ((i = (unsigned long)(*buffer) % sizeof(char*)) != 0)
+ i = sizeof(char*) - i;
+
+ if ((tst = get_static(buffer, buflen, ((gr->num_gr_mem + 1) *
+ sizeof(char *)+i))) == NULL) {
+
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
+ result->gr_mem = (char **)(tst + i);
+
+ if (gr->num_gr_mem == 0) {
+
+ /* Group is empty */
+
+ *(result->gr_mem) = NULL;
+ return NSS_STATUS_SUCCESS;
+ }
+
+ /* Start looking at extra data */
+
+ i = 0;
+
+ while(next_token_alloc((const char **)&gr_mem, &name, ",")) {
+ /* Allocate space for member */
+ if (((result->gr_mem)[i] =
+ get_static(buffer, buflen, strlen(name) + 1)) == NULL) {
+ free(name);
+ /* Out of memory */
+ return NSS_STATUS_TRYAGAIN;
+ }
+ strcpy((result->gr_mem)[i], name);
+ free(name);
+ i++;
+ }
+
+ /* Terminate list */
+
+ (result->gr_mem)[i] = NULL;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/*
+ * NSS user functions
+ */
+
+static struct winbindd_response getpwent_response;
+
+static int ndx_pw_cache; /* Current index into pwd cache */
+static int num_pw_cache; /* Current size of pwd cache */
+
+/* Rewind "file pointer" to start of ntdom password database */
+
+NSS_STATUS
+_nss_winbind_setpwent(void)
+{
+ NSS_STATUS ret;
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: setpwent\n", getpid());
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ if (num_pw_cache > 0) {
+ ndx_pw_cache = num_pw_cache = 0;
+ winbindd_free_response(&getpwent_response);
+ }
+
+ ret = winbindd_request_response(WINBINDD_SETPWENT, NULL, NULL);
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: setpwent returns %s (%d)\n", getpid(),
+ nss_err_str(ret), ret);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+ return ret;
+}
+
+/* Close ntdom password database "file pointer" */
+
+NSS_STATUS
+_nss_winbind_endpwent(void)
+{
+ NSS_STATUS ret;
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: endpwent\n", getpid());
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ if (num_pw_cache > 0) {
+ ndx_pw_cache = num_pw_cache = 0;
+ winbindd_free_response(&getpwent_response);
+ }
+
+ ret = winbindd_request_response(WINBINDD_ENDPWENT, NULL, NULL);
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: endpwent returns %s (%d)\n", getpid(),
+ nss_err_str(ret), ret);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+
+ return ret;
+}
+
+/* Fetch the next password entry from ntdom password database */
+
+NSS_STATUS
+_nss_winbind_getpwent_r(struct passwd *result, char *buffer,
+ size_t buflen, int *errnop)
+{
+ NSS_STATUS ret;
+ struct winbindd_request request;
+ static int called_again;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getpwent\n", getpid());
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ /* Return an entry from the cache if we have one, or if we are
+ called again because we exceeded our static buffer. */
+
+ if ((ndx_pw_cache < num_pw_cache) || called_again) {
+ goto return_result;
+ }
+
+ /* Else call winbindd to get a bunch of entries */
+
+ if (num_pw_cache > 0) {
+ winbindd_free_response(&getpwent_response);
+ }
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(getpwent_response);
+
+ request.data.num_entries = MAX_GETPWENT_USERS;
+
+ ret = winbindd_request_response(WINBINDD_GETPWENT, &request,
+ &getpwent_response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ struct winbindd_pw *pw_cache;
+
+ /* Fill cache */
+
+ ndx_pw_cache = 0;
+ num_pw_cache = getpwent_response.data.num_entries;
+
+ /* Return a result */
+
+ return_result:
+
+ pw_cache = (struct winbindd_pw *)
+ getpwent_response.extra_data.data;
+
+ /* Check data is valid */
+
+ if (pw_cache == NULL) {
+ ret = NSS_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ ret = fill_pwent(result, &pw_cache[ndx_pw_cache],
+ &buffer, &buflen);
+
+ /* Out of memory - try again */
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ called_again = true;
+ *errnop = errno = ERANGE;
+ goto done;
+ }
+
+ *errnop = errno = 0;
+ called_again = false;
+ ndx_pw_cache++;
+
+ /* If we've finished with this lot of results free cache */
+
+ if (ndx_pw_cache == num_pw_cache) {
+ ndx_pw_cache = num_pw_cache = 0;
+ winbindd_free_response(&getpwent_response);
+ }
+ }
+ done:
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getpwent returns %s (%d)\n", getpid(),
+ nss_err_str(ret), ret);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+ return ret;
+}
+
+/* Return passwd struct from uid */
+
+NSS_STATUS
+_nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer,
+ size_t buflen, int *errnop)
+{
+ NSS_STATUS ret;
+ static struct winbindd_response response;
+ struct winbindd_request request;
+ static int keep_response;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getpwuid_r %d\n", getpid(), (unsigned int)uid);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ /* If our static buffer needs to be expanded we are called again */
+ if (!keep_response || uid != response.data.pw.pw_uid) {
+
+ /* Call for the first time */
+
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
+
+ request.data.uid = uid;
+
+ ret = winbindd_request_response(WINBINDD_GETPWUID, &request, &response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ ret = fill_pwent(result, &response.data.pw,
+ &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = true;
+ *errnop = errno = ERANGE;
+ goto done;
+ }
+ }
+
+ } else {
+
+ /* We've been called again */
+
+ ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ *errnop = errno = ERANGE;
+ goto done;
+ }
+
+ keep_response = false;
+ *errnop = errno = 0;
+ }
+
+ winbindd_free_response(&response);
+
+ done:
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getpwuid %d returns %s (%d)\n", getpid(),
+ (unsigned int)uid, nss_err_str(ret), ret);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+
+ return ret;
+}
+
+/* Return passwd struct from username */
+NSS_STATUS
+_nss_winbind_getpwnam_r(const char *name, struct passwd *result, char *buffer,
+ size_t buflen, int *errnop)
+{
+ NSS_STATUS ret;
+ static struct winbindd_response response;
+ struct winbindd_request request;
+ static int keep_response;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getpwnam_r %s\n", getpid(), name);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ /* If our static buffer needs to be expanded we are called again */
+
+ if (!keep_response || strcmp(name,response.data.pw.pw_name) != 0) {
+
+ /* Call for the first time */
+
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
+
+ strncpy(request.data.username, name,
+ sizeof(request.data.username) - 1);
+ request.data.username
+ [sizeof(request.data.username) - 1] = '\0';
+
+ ret = winbindd_request_response(WINBINDD_GETPWNAM, &request, &response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ ret = fill_pwent(result, &response.data.pw, &buffer,
+ &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = true;
+ *errnop = errno = ERANGE;
+ goto done;
+ }
+ }
+
+ } else {
+
+ /* We've been called again */
+
+ ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = true;
+ *errnop = errno = ERANGE;
+ goto done;
+ }
+
+ keep_response = false;
+ *errnop = errno = 0;
+ }
+
+ winbindd_free_response(&response);
+ done:
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getpwnam %s returns %s (%d)\n", getpid(),
+ name, nss_err_str(ret), ret);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+
+ return ret;
+}
+
+/*
+ * NSS group functions
+ */
+
+static struct winbindd_response getgrent_response;
+
+static int ndx_gr_cache; /* Current index into grp cache */
+static int num_gr_cache; /* Current size of grp cache */
+
+/* Rewind "file pointer" to start of ntdom group database */
+
+NSS_STATUS
+_nss_winbind_setgrent(void)
+{
+ NSS_STATUS ret;
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: setgrent\n", getpid());
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ if (num_gr_cache > 0) {
+ ndx_gr_cache = num_gr_cache = 0;
+ winbindd_free_response(&getgrent_response);
+ }
+
+ ret = winbindd_request_response(WINBINDD_SETGRENT, NULL, NULL);
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: setgrent returns %s (%d)\n", getpid(),
+ nss_err_str(ret), ret);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+
+ return ret;
+}
+
+/* Close "file pointer" for ntdom group database */
+
+NSS_STATUS
+_nss_winbind_endgrent(void)
+{
+ NSS_STATUS ret;
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: endgrent\n", getpid());
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ if (num_gr_cache > 0) {
+ ndx_gr_cache = num_gr_cache = 0;
+ winbindd_free_response(&getgrent_response);
+ }
+
+ ret = winbindd_request_response(WINBINDD_ENDGRENT, NULL, NULL);
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: endgrent returns %s (%d)\n", getpid(),
+ nss_err_str(ret), ret);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+
+ return ret;
+}
+
+/* Get next entry from ntdom group database */
+
+static NSS_STATUS
+winbind_getgrent(enum winbindd_cmd cmd,
+ struct group *result,
+ char *buffer, size_t buflen, int *errnop)
+{
+ NSS_STATUS ret;
+ static struct winbindd_request request;
+ static int called_again;
+
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getgrent\n", getpid());
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ /* Return an entry from the cache if we have one, or if we are
+ called again because we exceeded our static buffer. */
+
+ if ((ndx_gr_cache < num_gr_cache) || called_again) {
+ goto return_result;
+ }
+
+ /* Else call winbindd to get a bunch of entries */
+
+ if (num_gr_cache > 0) {
+ winbindd_free_response(&getgrent_response);
+ }
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(getgrent_response);
+
+ request.data.num_entries = MAX_GETGRENT_USERS;
+
+ ret = winbindd_request_response(cmd, &request,
+ &getgrent_response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ struct winbindd_gr *gr_cache;
+ int mem_ofs;
+
+ /* Fill cache */
+
+ ndx_gr_cache = 0;
+ num_gr_cache = getgrent_response.data.num_entries;
+
+ /* Return a result */
+
+ return_result:
+
+ gr_cache = (struct winbindd_gr *)
+ getgrent_response.extra_data.data;
+
+ /* Check data is valid */
+
+ if (gr_cache == NULL) {
+ ret = NSS_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ /* Fill group membership. The offset into the extra data
+ for the group membership is the reported offset plus the
+ size of all the winbindd_gr records returned. */
+
+ mem_ofs = gr_cache[ndx_gr_cache].gr_mem_ofs +
+ num_gr_cache * sizeof(struct winbindd_gr);
+
+ ret = fill_grent(result, &gr_cache[ndx_gr_cache],
+ ((char *)getgrent_response.extra_data.data)+mem_ofs,
+ &buffer, &buflen);
+
+ /* Out of memory - try again */
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ called_again = true;
+ *errnop = errno = ERANGE;
+ goto done;
+ }
+
+ *errnop = 0;
+ called_again = false;
+ ndx_gr_cache++;
+
+ /* If we've finished with this lot of results free cache */
+
+ if (ndx_gr_cache == num_gr_cache) {
+ ndx_gr_cache = num_gr_cache = 0;
+ winbindd_free_response(&getgrent_response);
+ }
+ }
+ done:
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getgrent returns %s (%d)\n", getpid(),
+ nss_err_str(ret), ret);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+
+ return ret;
+}
+
+
+NSS_STATUS
+_nss_winbind_getgrent_r(struct group *result,
+ char *buffer, size_t buflen, int *errnop)
+{
+ return winbind_getgrent(WINBINDD_GETGRENT, result, buffer, buflen, errnop);
+}
+
+NSS_STATUS
+_nss_winbind_getgrlst_r(struct group *result,
+ char *buffer, size_t buflen, int *errnop)
+{
+ return winbind_getgrent(WINBINDD_GETGRLST, result, buffer, buflen, errnop);
+}
+
+/* Return group struct from group name */
+
+NSS_STATUS
+_nss_winbind_getgrnam_r(const char *name,
+ struct group *result, char *buffer,
+ size_t buflen, int *errnop)
+{
+ NSS_STATUS ret;
+ static struct winbindd_response response;
+ struct winbindd_request request;
+ static int keep_response;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getgrnam %s\n", getpid(), name);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ /* If our static buffer needs to be expanded we are called again */
+ /* Or if the stored response group name differs from the request. */
+
+ if (!keep_response || strcmp(name,response.data.gr.gr_name) != 0) {
+
+ /* Call for the first time */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ strncpy(request.data.groupname, name,
+ sizeof(request.data.groupname));
+ request.data.groupname
+ [sizeof(request.data.groupname) - 1] = '\0';
+
+ ret = winbindd_request_response(WINBINDD_GETGRNAM, &request, &response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ ret = fill_grent(result, &response.data.gr,
+ (char *)response.extra_data.data,
+ &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = true;
+ *errnop = errno = ERANGE;
+ goto done;
+ }
+ }
+
+ } else {
+
+ /* We've been called again */
+
+ ret = fill_grent(result, &response.data.gr,
+ (char *)response.extra_data.data, &buffer,
+ &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = true;
+ *errnop = errno = ERANGE;
+ goto done;
+ }
+
+ keep_response = false;
+ *errnop = 0;
+ }
+
+ winbindd_free_response(&response);
+ done:
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getgrnam %s returns %s (%d)\n", getpid(),
+ name, nss_err_str(ret), ret);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+
+ return ret;
+}
+
+/* Return group struct from gid */
+
+NSS_STATUS
+_nss_winbind_getgrgid_r(gid_t gid,
+ struct group *result, char *buffer,
+ size_t buflen, int *errnop)
+{
+ NSS_STATUS ret;
+ static struct winbindd_response response;
+ struct winbindd_request request;
+ static int keep_response;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getgrgid %d\n", getpid(), gid);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ /* If our static buffer needs to be expanded we are called again */
+ /* Or if the stored response group name differs from the request. */
+
+ if (!keep_response || gid != response.data.gr.gr_gid) {
+
+ /* Call for the first time */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.gid = gid;
+
+ ret = winbindd_request_response(WINBINDD_GETGRGID, &request, &response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+
+ ret = fill_grent(result, &response.data.gr,
+ (char *)response.extra_data.data,
+ &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = true;
+ *errnop = errno = ERANGE;
+ goto done;
+ }
+ }
+
+ } else {
+
+ /* We've been called again */
+
+ ret = fill_grent(result, &response.data.gr,
+ (char *)response.extra_data.data, &buffer,
+ &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = true;
+ *errnop = errno = ERANGE;
+ goto done;
+ }
+
+ keep_response = false;
+ *errnop = 0;
+ }
+
+ winbindd_free_response(&response);
+ done:
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getgrgid %d returns %s (%d)\n", getpid(),
+ (unsigned int)gid, nss_err_str(ret), ret);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+ return ret;
+}
+
+/* Initialise supplementary groups */
+
+NSS_STATUS
+_nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start,
+ long int *size, gid_t **groups, long int limit,
+ int *errnop)
+{
+ NSS_STATUS ret;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int i;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: initgroups %s (%d)\n", getpid(),
+ user, group);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ strncpy(request.data.username, user,
+ sizeof(request.data.username) - 1);
+
+ ret = winbindd_request_response(WINBINDD_GETGROUPS, &request, &response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ int num_gids = response.data.num_entries;
+ gid_t *gid_list = (gid_t *)response.extra_data.data;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: initgroups %s: got NSS_STATUS_SUCCESS "
+ "and %d gids\n", getpid(),
+ user, num_gids);
+#endif
+ if (gid_list == NULL) {
+ ret = NSS_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ /* Copy group list to client */
+
+ for (i = 0; i < num_gids; i++) {
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: initgroups %s (%d): "
+ "processing gid %d \n", getpid(),
+ user, group, gid_list[i]);
+#endif
+
+ /* Skip primary group */
+
+ if (gid_list[i] == group) {
+ continue;
+ }
+
+ /* Filled buffer ? If so, resize. */
+
+ if (*start == *size) {
+ long int newsize;
+ gid_t *newgroups;
+
+ newsize = 2 * (*size);
+ if (limit > 0) {
+ if (*size == limit) {
+ goto done;
+ }
+ if (newsize > limit) {
+ newsize = limit;
+ }
+ }
+
+ newgroups = (gid_t *)
+ realloc((*groups),
+ newsize * sizeof(**groups));
+ if (!newgroups) {
+ *errnop = ENOMEM;
+ ret = NSS_STATUS_NOTFOUND;
+ goto done;
+ }
+ *groups = newgroups;
+ *size = newsize;
+ }
+
+ /* Add to buffer */
+
+ (*groups)[*start] = gid_list[i];
+ *start += 1;
+ }
+ }
+
+ /* Back to your regularly scheduled programming */
+
+ done:
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: initgroups %s returns %s (%d)\n", getpid(),
+ user, nss_err_str(ret), ret);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+
+ return ret;
+}
+
+
+/* return a list of group SIDs for a user SID */
+NSS_STATUS
+_nss_winbind_getusersids(const char *user_sid, char **group_sids,
+ int *num_groups,
+ char *buffer, size_t buf_size, int *errnop)
+{
+ NSS_STATUS ret;
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getusersids %s\n", getpid(), user_sid);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ strncpy(request.data.sid, user_sid,sizeof(request.data.sid) - 1);
+ request.data.sid[sizeof(request.data.sid) - 1] = '\0';
+
+ ret = winbindd_request_response(WINBINDD_GETUSERSIDS, &request, &response);
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (buf_size < response.length - sizeof(response)) {
+ ret = NSS_STATUS_TRYAGAIN;
+ errno = *errnop = ERANGE;
+ goto done;
+ }
+
+ *num_groups = response.data.num_entries;
+ *group_sids = buffer;
+ memcpy(buffer, response.extra_data.data, response.length - sizeof(response));
+ errno = *errnop = 0;
+
+ done:
+ winbindd_free_response(&response);
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+
+ return ret;
+}
+
+
+/* map a user or group name to a SID string */
+NSS_STATUS
+_nss_winbind_nametosid(const char *name, char **sid, char *buffer,
+ size_t buflen, int *errnop)
+{
+ NSS_STATUS ret;
+ struct winbindd_response response;
+ struct winbindd_request request;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: nametosid %s\n", getpid(), name);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
+
+ strncpy(request.data.name.name, name,
+ sizeof(request.data.name.name) - 1);
+ request.data.name.name[sizeof(request.data.name.name) - 1] = '\0';
+
+ ret = winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response);
+ if (ret != NSS_STATUS_SUCCESS) {
+ *errnop = errno = EINVAL;
+ goto failed;
+ }
+
+ if (buflen < strlen(response.data.sid.sid)+1) {
+ ret = NSS_STATUS_TRYAGAIN;
+ *errnop = errno = ERANGE;
+ goto failed;
+ }
+
+ *errnop = errno = 0;
+ *sid = buffer;
+ strcpy(*sid, response.data.sid.sid);
+
+failed:
+ winbindd_free_response(&response);
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+
+ return ret;
+}
+
+/* map a sid string to a user or group name */
+NSS_STATUS
+_nss_winbind_sidtoname(const char *sid, char **name, char *buffer,
+ size_t buflen, int *errnop)
+{
+ NSS_STATUS ret;
+ struct winbindd_response response;
+ struct winbindd_request request;
+ static char sep_char;
+ unsigned needed;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: sidtoname %s\n", getpid(), sid);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
+
+ /* we need to fetch the separator first time through */
+ if (!sep_char) {
+ ret = winbindd_request_response(WINBINDD_INFO, &request, &response);
+ if (ret != NSS_STATUS_SUCCESS) {
+ *errnop = errno = EINVAL;
+ goto failed;
+ }
+
+ sep_char = response.data.info.winbind_separator;
+ winbindd_free_response(&response);
+ }
+
+
+ strncpy(request.data.sid, sid,
+ sizeof(request.data.sid) - 1);
+ request.data.sid[sizeof(request.data.sid) - 1] = '\0';
+
+ ret = winbindd_request_response(WINBINDD_LOOKUPSID, &request, &response);
+ if (ret != NSS_STATUS_SUCCESS) {
+ *errnop = errno = EINVAL;
+ goto failed;
+ }
+
+ needed =
+ strlen(response.data.name.dom_name) +
+ strlen(response.data.name.name) + 2;
+
+ if (buflen < needed) {
+ ret = NSS_STATUS_TRYAGAIN;
+ *errnop = errno = ERANGE;
+ goto failed;
+ }
+
+ snprintf(buffer, needed, "%s%c%s",
+ response.data.name.dom_name,
+ sep_char,
+ response.data.name.name);
+
+ *name = buffer;
+ *errnop = errno = 0;
+
+failed:
+ winbindd_free_response(&response);
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+
+ return ret;
+}
+
+/* map a sid to a uid */
+NSS_STATUS
+_nss_winbind_sidtouid(const char *sid, uid_t *uid, int *errnop)
+{
+ NSS_STATUS ret;
+ struct winbindd_response response;
+ struct winbindd_request request;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: sidtouid %s\n", getpid(), sid);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ strncpy(request.data.sid, sid, sizeof(request.data.sid) - 1);
+ request.data.sid[sizeof(request.data.sid) - 1] = '\0';
+
+ ret = winbindd_request_response(WINBINDD_SID_TO_UID, &request, &response);
+ if (ret != NSS_STATUS_SUCCESS) {
+ *errnop = errno = EINVAL;
+ goto failed;
+ }
+
+ *uid = response.data.uid;
+
+failed:
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+
+ return ret;
+}
+
+/* map a sid to a gid */
+NSS_STATUS
+_nss_winbind_sidtogid(const char *sid, gid_t *gid, int *errnop)
+{
+ NSS_STATUS ret;
+ struct winbindd_response response;
+ struct winbindd_request request;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: sidtogid %s\n", getpid(), sid);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ strncpy(request.data.sid, sid, sizeof(request.data.sid) - 1);
+ request.data.sid[sizeof(request.data.sid) - 1] = '\0';
+
+ ret = winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response);
+ if (ret != NSS_STATUS_SUCCESS) {
+ *errnop = errno = EINVAL;
+ goto failed;
+ }
+
+ *gid = response.data.gid;
+
+failed:
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+
+ return ret;
+}
+
+/* map a uid to a SID string */
+NSS_STATUS
+_nss_winbind_uidtosid(uid_t uid, char **sid, char *buffer,
+ size_t buflen, int *errnop)
+{
+ NSS_STATUS ret;
+ struct winbindd_response response;
+ struct winbindd_request request;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5u]: uidtosid %u\n", (unsigned int)getpid(), (unsigned int)uid);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
+
+ request.data.uid = uid;
+
+ ret = winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response);
+ if (ret != NSS_STATUS_SUCCESS) {
+ *errnop = errno = EINVAL;
+ goto failed;
+ }
+
+ if (buflen < strlen(response.data.sid.sid)+1) {
+ ret = NSS_STATUS_TRYAGAIN;
+ *errnop = errno = ERANGE;
+ goto failed;
+ }
+
+ *errnop = errno = 0;
+ *sid = buffer;
+ strcpy(*sid, response.data.sid.sid);
+
+failed:
+ winbindd_free_response(&response);
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+
+ return ret;
+}
+
+/* map a gid to a SID string */
+NSS_STATUS
+_nss_winbind_gidtosid(gid_t gid, char **sid, char *buffer,
+ size_t buflen, int *errnop)
+{
+ NSS_STATUS ret;
+ struct winbindd_response response;
+ struct winbindd_request request;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5u]: gidtosid %u\n", (unsigned int)getpid(), (unsigned int)gid);
+#endif
+
+#if HAVE_PTHREAD
+ pthread_mutex_lock(&winbind_nss_mutex);
+#endif
+
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
+
+ request.data.gid = gid;
+
+ ret = winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response);
+ if (ret != NSS_STATUS_SUCCESS) {
+ *errnop = errno = EINVAL;
+ goto failed;
+ }
+
+ if (buflen < strlen(response.data.sid.sid)+1) {
+ ret = NSS_STATUS_TRYAGAIN;
+ *errnop = errno = ERANGE;
+ goto failed;
+ }
+
+ *errnop = errno = 0;
+ *sid = buffer;
+ strcpy(*sid, response.data.sid.sid);
+
+failed:
+ winbindd_free_response(&response);
+
+#if HAVE_PTHREAD
+ pthread_mutex_unlock(&winbind_nss_mutex);
+#endif
+
+ return ret;
+}
diff --git a/source3/nsswitch/winbind_nss_linux.h b/source3/nsswitch/winbind_nss_linux.h
new file mode 100644
index 0000000000..74aaec5ce6
--- /dev/null
+++ b/source3/nsswitch/winbind_nss_linux.h
@@ -0,0 +1,29 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon for ntdom nss module
+
+ Copyright (C) Tim Potter 2000
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _WINBIND_NSS_LINUX_H
+#define _WINBIND_NSS_LINUX_H
+
+#include <nss.h>
+
+typedef enum nss_status NSS_STATUS;
+
+#endif /* _WINBIND_NSS_LINUX_H */
diff --git a/source3/nsswitch/winbind_nss_netbsd.c b/source3/nsswitch/winbind_nss_netbsd.c
new file mode 100644
index 0000000000..9b8e0a2265
--- /dev/null
+++ b/source3/nsswitch/winbind_nss_netbsd.c
@@ -0,0 +1,442 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ NetBSD loadable authentication module, providing identification
+ routines against Samba winbind/Windows NT Domain
+
+ Copyright (C) Luke Mewburn 2004-2005
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "winbind_client.h"
+
+#include <sys/param.h>
+#include <stdarg.h>
+#include <syslog.h>
+
+ /* dynamic nsswitch with "new" getpw* nsdispatch API available */
+#if defined(NSS_MODULE_INTERFACE_VERSION) && defined(HAVE_GETPWENT_R)
+
+/*
+ group functions
+ ---------------
+*/
+
+static struct group _winbind_group;
+static char _winbind_groupbuf[1024];
+
+/*
+ * We need a proper prototype for this :-)
+ */
+
+NSS_STATUS _nss_winbind_setpwent(void);
+NSS_STATUS _nss_winbind_endpwent(void);
+NSS_STATUS _nss_winbind_getpwent_r(struct passwd *result, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result,
+ char *buffer, size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_getpwnam_r(const char *name, struct passwd *result,
+ char *buffer, size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_setgrent(void);
+NSS_STATUS _nss_winbind_endgrent(void);
+NSS_STATUS _nss_winbind_getgrent_r(struct group *result, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_getgrlst_r(struct group *result, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_getgrnam_r(const char *name, struct group *result,
+ char *buffer, size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_getgrgid_r(gid_t gid, struct group *result, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start,
+ long int *size, gid_t **groups,
+ long int limit, int *errnop);
+NSS_STATUS _nss_winbind_getusersids(const char *user_sid, char **group_sids,
+ int *num_groups, char *buffer, size_t buf_size,
+ int *errnop);
+NSS_STATUS _nss_winbind_nametosid(const char *name, char **sid, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_sidtoname(const char *sid, char **name, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_sidtouid(const char *sid, uid_t *uid, int *errnop);
+NSS_STATUS _nss_winbind_sidtogid(const char *sid, gid_t *gid, int *errnop);
+NSS_STATUS _nss_winbind_uidtosid(uid_t uid, char **sid, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_gidtosid(gid_t gid, char **sid, char *buffer,
+ size_t buflen, int *errnop);
+
+int
+netbsdwinbind_endgrent(void *nsrv, void *nscb, va_list ap)
+{
+ int rv;
+
+ rv = _nss_winbind_endgrent();
+ return rv;
+}
+
+int
+netbsdwinbind_setgrent(void *nsrv, void *nscb, va_list ap)
+{
+ int rv;
+
+ rv = _nss_winbind_setgrent();
+ return rv;
+}
+
+int
+netbsdwinbind_getgrent(void *nsrv, void *nscb, va_list ap)
+{
+ struct group **retval = va_arg(ap, struct group **);
+
+ int rv, rerrno;
+
+ *retval = NULL;
+ rv = _nss_winbind_getgrent_r(&_winbind_group,
+ _winbind_groupbuf, sizeof(_winbind_groupbuf), &rerrno);
+ if (rv == NS_SUCCESS)
+ *retval = &_winbind_group;
+ return rv;
+}
+
+int
+netbsdwinbind_getgrent_r(void *nsrv, void *nscb, va_list ap)
+{
+ int *retval = va_arg(ap, int *);
+ struct group *grp = va_arg(ap, struct group *);
+ char *buffer = va_arg(ap, char *);
+ size_t buflen = va_arg(ap, size_t);
+ struct group **result = va_arg(ap, struct group **);
+
+ int rv, rerrno;
+
+ *result = NULL;
+ rerrno = 0;
+
+ rv = _nss_winbind_getgrent_r(grp, buffer, buflen, rerrno);
+ if (rv == NS_SUCCESS)
+ *result = grp;
+ else
+ *retval = rerrno;
+ return rv;
+}
+
+int
+netbsdwinbind_getgrgid(void *nsrv, void *nscb, va_list ap)
+{
+ struct group **retval = va_arg(ap, struct group **);
+ gid_t gid = va_arg(ap, gid_t);
+
+ int rv, rerrno;
+
+ *retval = NULL;
+ rv = _nss_winbind_getgrgid_r(gid, &_winbind_group,
+ _winbind_groupbuf, sizeof(_winbind_groupbuf), &rerrno);
+ if (rv == NS_SUCCESS)
+ *retval = &_winbind_group;
+ return rv;
+}
+
+int
+netbsdwinbind_getgrgid_r(void *nsrv, void *nscb, va_list ap)
+{
+ int *retval = va_arg(ap, int *);
+ gid_t gid = va_arg(ap, gid_t);
+ struct group *grp = va_arg(ap, struct group *);
+ char *buffer = va_arg(ap, char *);
+ size_t buflen = va_arg(ap, size_t);
+ struct group **result = va_arg(ap, struct group **);
+
+ int rv, rerrno;
+
+ *result = NULL;
+ rerrno = 0;
+
+ rv = _nss_winbind_getgrgid_r(gid, grp, buffer, buflen, &rerrno);
+ if (rv == NS_SUCCESS)
+ *result = grp;
+ else
+ *retval = rerrno;
+ return rv;
+}
+
+int
+netbsdwinbind_getgrnam(void *nsrv, void *nscb, va_list ap)
+{
+ struct group **retval = va_arg(ap, struct group **);
+ const char *name = va_arg(ap, const char *);
+
+ int rv, rerrno;
+
+ *retval = NULL;
+ rv = _nss_winbind_getgrnam_r(name, &_winbind_group,
+ _winbind_groupbuf, sizeof(_winbind_groupbuf), &rerrno);
+ if (rv == NS_SUCCESS)
+ *retval = &_winbind_group;
+ return rv;
+}
+
+int
+netbsdwinbind_getgrnam_r(void *nsrv, void *nscb, va_list ap)
+{
+ int *retval = va_arg(ap, int *);
+ const char *name = va_arg(ap, const char *);
+ struct group *grp = va_arg(ap, struct group *);
+ char *buffer = va_arg(ap, char *);
+ size_t buflen = va_arg(ap, size_t);
+ struct group **result = va_arg(ap, struct group **);
+
+ int rv, rerrno;
+
+ *result = NULL;
+ rerrno = 0;
+
+ rv = _nss_winbind_getgrnam_r(name, grp, buffer, buflen, &rerrno);
+ if (rv == NS_SUCCESS)
+ *result = grp;
+ else
+ *retval = rerrno;
+ return rv;
+}
+
+int
+netbsdwinbind_getgroupmembership(void *nsrv, void *nscb, va_list ap)
+{
+ int *result = va_arg(ap, int *);
+ const char *uname = va_arg(ap, const char *);
+ gid_t agroup = va_arg(ap, gid_t);
+ gid_t *groups = va_arg(ap, gid_t *);
+ int maxgrp = va_arg(ap, int);
+ int *groupc = va_arg(ap, int *);
+
+ struct winbindd_request request;
+ struct winbindd_response response;
+ gid_t *wblistv;
+ int wblistc, i, isdup, dupc;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+ strncpy(request.data.username, uname,
+ sizeof(request.data.username) - 1);
+ i = winbindd_request_response(WINBINDD_GETGROUPS, &request, &response);
+ if (i != NSS_STATUS_SUCCESS)
+ return NS_NOTFOUND;
+ wblistv = (gid_t *)response.extra_data.data;
+ wblistc = response.data.num_entries;
+
+ for (i = 0; i < wblistc; i++) { /* add winbind gids */
+ isdup = 0; /* skip duplicates */
+ for (dupc = 0; dupc < MIN(maxgrp, *groupc); dupc++) {
+ if (groups[dupc] == wblistv[i]) {
+ isdup = 1;
+ break;
+ }
+ }
+ if (isdup)
+ continue;
+ if (*groupc < maxgrp) /* add this gid */
+ groups[*groupc] = wblistv[i];
+ else
+ *result = -1;
+ (*groupc)++;
+ }
+ SAFE_FREE(wblistv);
+ return NS_NOTFOUND;
+}
+
+
+/*
+ passwd functions
+ ----------------
+*/
+
+static struct passwd _winbind_passwd;
+static char _winbind_passwdbuf[1024];
+
+int
+netbsdwinbind_endpwent(void *nsrv, void *nscb, va_list ap)
+{
+ int rv;
+
+ rv = _nss_winbind_endpwent();
+ return rv;
+}
+
+int
+netbsdwinbind_setpwent(void *nsrv, void *nscb, va_list ap)
+{
+ int rv;
+
+ rv = _nss_winbind_setpwent();
+ return rv;
+}
+
+int
+netbsdwinbind_getpwent(void *nsrv, void *nscb, va_list ap)
+{
+ struct passwd **retval = va_arg(ap, struct passwd **);
+
+ int rv, rerrno;
+
+ *retval = NULL;
+
+ rv = _nss_winbind_getpwent_r(&_winbind_passwd,
+ _winbind_passwdbuf, sizeof(_winbind_passwdbuf), &rerrno);
+ if (rv == NS_SUCCESS)
+ *retval = &_winbind_passwd;
+ return rv;
+}
+
+int
+netbsdwinbind_getpwent_r(void *nsrv, void *nscb, va_list ap)
+{
+ int *retval = va_arg(ap, int *);
+ struct passwd *pw = va_arg(ap, struct passwd *);
+ char *buffer = va_arg(ap, char *);
+ size_t buflen = va_arg(ap, size_t);
+ struct passwd **result = va_arg(ap, struct passwd **);
+
+ int rv, rerrno;
+
+ *result = NULL;
+ rerrno = 0;
+
+ rv = _nss_winbind_getpwent_r(pw, buffer, buflen, rerrno);
+ if (rv == NS_SUCCESS)
+ *result = pw;
+ else
+ *retval = rerrno;
+ return rv;
+}
+
+int
+netbsdwinbind_getpwnam(void *nsrv, void *nscb, va_list ap)
+{
+ struct passwd **retval = va_arg(ap, struct passwd **);
+ const char *name = va_arg(ap, const char *);
+
+ int rv, rerrno;
+
+ *retval = NULL;
+ rv = _nss_winbind_getpwnam_r(name, &_winbind_passwd,
+ _winbind_passwdbuf, sizeof(_winbind_passwdbuf), &rerrno);
+ if (rv == NS_SUCCESS)
+ *retval = &_winbind_passwd;
+ return rv;
+}
+
+int
+netbsdwinbind_getpwnam_r(void *nsrv, void *nscb, va_list ap)
+{
+ int *retval = va_arg(ap, int *);
+ const char *name = va_arg(ap, const char *);
+ struct passwd *pw = va_arg(ap, struct passwd *);
+ char *buffer = va_arg(ap, char *);
+ size_t buflen = va_arg(ap, size_t);
+ struct passwd **result = va_arg(ap, struct passwd **);
+
+ int rv, rerrno;
+
+ *result = NULL;
+ rerrno = 0;
+
+ rv = _nss_winbind_getpwnam_r(name, pw, buffer, buflen, &rerrno);
+ if (rv == NS_SUCCESS)
+ *result = pw;
+ else
+ *retval = rerrno;
+ return rv;
+}
+
+int
+netbsdwinbind_getpwuid(void *nsrv, void *nscb, va_list ap)
+{
+ struct passwd **retval = va_arg(ap, struct passwd **);
+ uid_t uid = va_arg(ap, uid_t);
+
+ int rv, rerrno;
+
+ *retval = NULL;
+ rv = _nss_winbind_getpwuid_r(uid, &_winbind_passwd,
+ _winbind_passwdbuf, sizeof(_winbind_passwdbuf), &rerrno);
+ if (rv == NS_SUCCESS)
+ *retval = &_winbind_passwd;
+ return rv;
+}
+
+int
+netbsdwinbind_getpwuid_r(void *nsrv, void *nscb, va_list ap)
+{
+ int *retval = va_arg(ap, int *);
+ uid_t uid = va_arg(ap, uid_t);
+ struct passwd *pw = va_arg(ap, struct passwd *);
+ char *buffer = va_arg(ap, char *);
+ size_t buflen = va_arg(ap, size_t);
+ struct passwd **result = va_arg(ap, struct passwd **);
+
+ int rv, rerrno;
+
+ *result = NULL;
+ rerrno = 0;
+
+ rv = _nss_winbind_getpwuid_r(uid, pw, buffer, buflen, &rerrno);
+ if (rv == NS_SUCCESS)
+ *result = pw;
+ else
+ *retval = rerrno;
+ return rv;
+}
+
+
+/*
+ nsswitch module setup
+ ---------------------
+*/
+
+
+static ns_mtab winbind_methods[] = {
+
+{ NSDB_GROUP, "endgrent", netbsdwinbind_endgrent, NULL },
+{ NSDB_GROUP, "getgrent", netbsdwinbind_getgrent, NULL },
+{ NSDB_GROUP, "getgrent_r", netbsdwinbind_getgrent_r, NULL },
+{ NSDB_GROUP, "getgrgid", netbsdwinbind_getgrgid, NULL },
+{ NSDB_GROUP, "getgrgid_r", netbsdwinbind_getgrgid_r, NULL },
+{ NSDB_GROUP, "getgrnam", netbsdwinbind_getgrnam, NULL },
+{ NSDB_GROUP, "getgrnam_r", netbsdwinbind_getgrnam_r, NULL },
+{ NSDB_GROUP, "setgrent", netbsdwinbind_setgrent, NULL },
+{ NSDB_GROUP, "setgroupent", netbsdwinbind_setgrent, NULL },
+{ NSDB_GROUP, "getgroupmembership", netbsdwinbind_getgroupmembership, NULL },
+
+{ NSDB_PASSWD, "endpwent", netbsdwinbind_endpwent, NULL },
+{ NSDB_PASSWD, "getpwent", netbsdwinbind_getpwent, NULL },
+{ NSDB_PASSWD, "getpwent_r", netbsdwinbind_getpwent_r, NULL },
+{ NSDB_PASSWD, "getpwnam", netbsdwinbind_getpwnam, NULL },
+{ NSDB_PASSWD, "getpwnam_r", netbsdwinbind_getpwnam_r, NULL },
+{ NSDB_PASSWD, "getpwuid", netbsdwinbind_getpwuid, NULL },
+{ NSDB_PASSWD, "getpwuid_r", netbsdwinbind_getpwuid_r, NULL },
+{ NSDB_PASSWD, "setpassent", netbsdwinbind_setpwent, NULL },
+{ NSDB_PASSWD, "setpwent", netbsdwinbind_setpwent, NULL },
+
+};
+
+ns_mtab *
+nss_module_register(const char *source, unsigned int *mtabsize,
+ nss_module_unregister_fn *unreg)
+{
+ *mtabsize = sizeof(winbind_methods)/sizeof(winbind_methods[0]);
+ *unreg = NULL;
+ return (winbind_methods);
+}
+
+#endif /* NSS_MODULE_INTERFACE_VERSION && HAVE_GETPWENT_R */
diff --git a/source3/nsswitch/winbind_nss_netbsd.h b/source3/nsswitch/winbind_nss_netbsd.h
new file mode 100644
index 0000000000..dceb57c784
--- /dev/null
+++ b/source3/nsswitch/winbind_nss_netbsd.h
@@ -0,0 +1,40 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ NetBSD loadable authentication module, providing identification
+ routines against Samba winbind/Windows NT Domain
+
+ Copyright (C) Luke Mewburn 2004-2005
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _WINBIND_NSS_NETBSD_H
+#define _WINBIND_NSS_NETBSD_H
+
+#include <nsswitch.h>
+
+ /* dynamic nsswitch with "new" getpw* nsdispatch API available */
+#if defined(NSS_MODULE_INTERFACE_VERSION) && defined(HAVE_GETPWENT_R)
+
+typedef int NSS_STATUS;
+
+#define NSS_STATUS_SUCCESS NS_SUCCESS
+#define NSS_STATUS_NOTFOUND NS_NOTFOUND
+#define NSS_STATUS_UNAVAIL NS_UNAVAIL
+#define NSS_STATUS_TRYAGAIN NS_TRYAGAIN
+
+#endif /* NSS_MODULE_INTERFACE_VERSION && HAVE_GETPWENT_R */
+
+#endif /* _WINBIND_NSS_NETBSD_H */
diff --git a/source3/nsswitch/winbind_nss_solaris.c b/source3/nsswitch/winbind_nss_solaris.c
new file mode 100644
index 0000000000..865b6ebbb0
--- /dev/null
+++ b/source3/nsswitch/winbind_nss_solaris.c
@@ -0,0 +1,654 @@
+/*
+ Solaris NSS wrapper for winbind
+ - Shirish Kalele 2000
+
+ Based on Luke Howard's ldap_nss module for Solaris
+ */
+
+/*
+ Copyright (C) 1997-2003 Luke Howard.
+ This file is part of the nss_ldap library.
+
+ The nss_ldap library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 3 of the
+ License, or (at your option) any later version.
+
+ The nss_ldap 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 Lesser General Public
+ License along with the nss_ldap library; see the file COPYING.LIB. If not,
+ see <http://www.gnu.org/licenses/>.
+*/
+
+#undef DEVELOPER
+
+#include "winbind_client.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <string.h>
+#include <pwd.h>
+#include "includes.h"
+#include <syslog.h>
+#if !defined(HPUX)
+#include <sys/syslog.h>
+#endif /*hpux*/
+
+#if defined(HAVE_NSS_COMMON_H) || defined(HPUX)
+
+#undef NSS_DEBUG
+
+#ifdef NSS_DEBUG
+#define NSS_DEBUG(str) syslog(LOG_DEBUG, "nss_winbind: %s", str);
+#else
+#define NSS_DEBUG(str) ;
+#endif
+
+#define NSS_ARGS(args) ((nss_XbyY_args_t *)args)
+
+#ifdef HPUX
+
+/*
+ * HP-UX 11 has no definiton of the nss_groupsbymem structure. This
+ * definition is taken from the nss_ldap project at:
+ * http://www.padl.com/OSS/nss_ldap.html
+ */
+
+struct nss_groupsbymem {
+ const char *username;
+ gid_t *gid_array;
+ int maxgids;
+ int force_slow_way;
+ int (*str2ent)(const char *instr, int instr_len, void *ent,
+ char *buffer, int buflen);
+ nss_status_t (*process_cstr)(const char *instr, int instr_len,
+ struct nss_groupsbymem *);
+ int numgids;
+};
+
+#endif /* HPUX */
+
+#define make_pwent_str(dest, src) \
+{ \
+ if((dest = get_static(buffer, buflen, strlen(src)+1)) == NULL) \
+ { \
+ *errnop = ERANGE; \
+ NSS_DEBUG("ERANGE error"); \
+ return NSS_STATUS_TRYAGAIN; \
+ } \
+ strcpy(dest, src); \
+}
+
+static NSS_STATUS _nss_winbind_setpwent_solwrap (nss_backend_t* be, void* args)
+{
+ NSS_DEBUG("_nss_winbind_setpwent_solwrap");
+ return _nss_winbind_setpwent();
+}
+
+static NSS_STATUS
+_nss_winbind_endpwent_solwrap (nss_backend_t * be, void *args)
+{
+ NSS_DEBUG("_nss_winbind_endpwent_solwrap");
+ return _nss_winbind_endpwent();
+}
+
+static NSS_STATUS
+_nss_winbind_getpwent_solwrap (nss_backend_t* be, void *args)
+{
+ NSS_STATUS ret;
+ char* buffer = NSS_ARGS(args)->buf.buffer;
+ int buflen = NSS_ARGS(args)->buf.buflen;
+ struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
+ int* errnop = &NSS_ARGS(args)->erange;
+ char logmsg[80];
+
+ ret = _nss_winbind_getpwent_r(result, buffer,
+ buflen, errnop);
+
+ if(ret == NSS_STATUS_SUCCESS)
+ {
+ snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning user: %s\n",
+ result->pw_name);
+ NSS_DEBUG(logmsg);
+ NSS_ARGS(args)->returnval = (void*) result;
+ } else {
+ snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning error: %d.\n",ret);
+ NSS_DEBUG(logmsg);
+ }
+
+ return ret;
+}
+
+static NSS_STATUS
+_nss_winbind_getpwnam_solwrap (nss_backend_t* be, void* args)
+{
+ NSS_STATUS ret;
+ struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
+
+ NSS_DEBUG("_nss_winbind_getpwnam_solwrap");
+
+ ret = _nss_winbind_getpwnam_r (NSS_ARGS(args)->key.name,
+ result,
+ NSS_ARGS(args)->buf.buffer,
+ NSS_ARGS(args)->buf.buflen,
+ &NSS_ARGS(args)->erange);
+ if(ret == NSS_STATUS_SUCCESS)
+ NSS_ARGS(args)->returnval = (void*) result;
+
+ return ret;
+}
+
+static NSS_STATUS
+_nss_winbind_getpwuid_solwrap(nss_backend_t* be, void* args)
+{
+ NSS_STATUS ret;
+ struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
+
+ NSS_DEBUG("_nss_winbind_getpwuid_solwrap");
+ ret = _nss_winbind_getpwuid_r (NSS_ARGS(args)->key.uid,
+ result,
+ NSS_ARGS(args)->buf.buffer,
+ NSS_ARGS(args)->buf.buflen,
+ &NSS_ARGS(args)->erange);
+ if(ret == NSS_STATUS_SUCCESS)
+ NSS_ARGS(args)->returnval = (void*) result;
+
+ return ret;
+}
+
+static NSS_STATUS _nss_winbind_passwd_destr (nss_backend_t * be, void *args)
+{
+ SAFE_FREE(be);
+ NSS_DEBUG("_nss_winbind_passwd_destr");
+ return NSS_STATUS_SUCCESS;
+}
+
+static nss_backend_op_t passwd_ops[] =
+{
+ _nss_winbind_passwd_destr,
+ _nss_winbind_endpwent_solwrap, /* NSS_DBOP_ENDENT */
+ _nss_winbind_setpwent_solwrap, /* NSS_DBOP_SETENT */
+ _nss_winbind_getpwent_solwrap, /* NSS_DBOP_GETENT */
+ _nss_winbind_getpwnam_solwrap, /* NSS_DBOP_PASSWD_BYNAME */
+ _nss_winbind_getpwuid_solwrap /* NSS_DBOP_PASSWD_BYUID */
+};
+
+nss_backend_t*
+_nss_winbind_passwd_constr (const char* db_name,
+ const char* src_name,
+ const char* cfg_args)
+{
+ nss_backend_t *be;
+
+ if(!(be = SMB_MALLOC_P(nss_backend_t)) )
+ return NULL;
+
+ be->ops = passwd_ops;
+ be->n_ops = sizeof(passwd_ops) / sizeof(nss_backend_op_t);
+
+ NSS_DEBUG("Initialized nss_winbind passwd backend");
+ return be;
+}
+
+/*****************************************************************
+ GROUP database backend
+ *****************************************************************/
+
+static NSS_STATUS _nss_winbind_setgrent_solwrap (nss_backend_t* be, void* args)
+{
+ NSS_DEBUG("_nss_winbind_setgrent_solwrap");
+ return _nss_winbind_setgrent();
+}
+
+static NSS_STATUS
+_nss_winbind_endgrent_solwrap (nss_backend_t * be, void *args)
+{
+ NSS_DEBUG("_nss_winbind_endgrent_solwrap");
+ return _nss_winbind_endgrent();
+}
+
+static NSS_STATUS
+_nss_winbind_getgrent_solwrap(nss_backend_t* be, void* args)
+{
+ NSS_STATUS ret;
+ char* buffer = NSS_ARGS(args)->buf.buffer;
+ int buflen = NSS_ARGS(args)->buf.buflen;
+ struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
+ int* errnop = &NSS_ARGS(args)->erange;
+ char logmsg[80];
+
+ ret = _nss_winbind_getgrent_r(result, buffer,
+ buflen, errnop);
+
+ if(ret == NSS_STATUS_SUCCESS)
+ {
+ snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning group: %s\n", result->gr_name);
+ NSS_DEBUG(logmsg);
+ NSS_ARGS(args)->returnval = (void*) result;
+ } else {
+ snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning error: %d.\n", ret);
+ NSS_DEBUG(logmsg);
+ }
+
+ return ret;
+
+}
+
+static NSS_STATUS
+_nss_winbind_getgrnam_solwrap(nss_backend_t* be, void* args)
+{
+ NSS_STATUS ret;
+ struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
+
+ NSS_DEBUG("_nss_winbind_getgrnam_solwrap");
+ ret = _nss_winbind_getgrnam_r(NSS_ARGS(args)->key.name,
+ result,
+ NSS_ARGS(args)->buf.buffer,
+ NSS_ARGS(args)->buf.buflen,
+ &NSS_ARGS(args)->erange);
+
+ if(ret == NSS_STATUS_SUCCESS)
+ NSS_ARGS(args)->returnval = (void*) result;
+
+ return ret;
+}
+
+static NSS_STATUS
+_nss_winbind_getgrgid_solwrap(nss_backend_t* be, void* args)
+{
+ NSS_STATUS ret;
+ struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
+
+ NSS_DEBUG("_nss_winbind_getgrgid_solwrap");
+ ret = _nss_winbind_getgrgid_r (NSS_ARGS(args)->key.gid,
+ result,
+ NSS_ARGS(args)->buf.buffer,
+ NSS_ARGS(args)->buf.buflen,
+ &NSS_ARGS(args)->erange);
+
+ if(ret == NSS_STATUS_SUCCESS)
+ NSS_ARGS(args)->returnval = (void*) result;
+
+ return ret;
+}
+
+static NSS_STATUS
+_nss_winbind_getgroupsbymember_solwrap(nss_backend_t* be, void* args)
+{
+ int errnop;
+ struct nss_groupsbymem *gmem = (struct nss_groupsbymem *)args;
+
+ NSS_DEBUG("_nss_winbind_getgroupsbymember");
+
+ _nss_winbind_initgroups_dyn(gmem->username,
+ gmem->gid_array[0], /* Primary Group */
+ &gmem->numgids,
+ &gmem->maxgids,
+ &gmem->gid_array,
+ gmem->maxgids,
+ &errnop);
+
+ /*
+ * If the maximum number of gids have been found, return
+ * SUCCESS so the switch engine will stop searching. Otherwise
+ * return NOTFOUND so nsswitch will continue to get groups
+ * from the remaining database backends specified in the
+ * nsswitch.conf file.
+ */
+ return (gmem->numgids == gmem->maxgids ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND);
+}
+
+static NSS_STATUS
+_nss_winbind_group_destr (nss_backend_t* be, void* args)
+{
+ SAFE_FREE(be);
+ NSS_DEBUG("_nss_winbind_group_destr");
+ return NSS_STATUS_SUCCESS;
+}
+
+static nss_backend_op_t group_ops[] =
+{
+ _nss_winbind_group_destr,
+ _nss_winbind_endgrent_solwrap,
+ _nss_winbind_setgrent_solwrap,
+ _nss_winbind_getgrent_solwrap,
+ _nss_winbind_getgrnam_solwrap,
+ _nss_winbind_getgrgid_solwrap,
+ _nss_winbind_getgroupsbymember_solwrap
+};
+
+nss_backend_t*
+_nss_winbind_group_constr (const char* db_name,
+ const char* src_name,
+ const char* cfg_args)
+{
+ nss_backend_t* be;
+
+ if(!(be = SMB_MALLOC_P(nss_backend_t)) )
+ return NULL;
+
+ be->ops = group_ops;
+ be->n_ops = sizeof(group_ops) / sizeof(nss_backend_op_t);
+
+ NSS_DEBUG("Initialized nss_winbind group backend");
+ return be;
+}
+
+/*****************************************************************
+ hosts and ipnodes backend
+ *****************************************************************/
+#if defined(SUNOS5) /* not compatible with HP-UX */
+
+/* this parser is shared between get*byname and get*byaddr, as key type
+ in request is stored in different locations, I had to provide the
+ address family as an argument, caller must free the winbind response. */
+
+static NSS_STATUS
+parse_response(int af, nss_XbyY_args_t* argp, struct winbindd_response *response)
+{
+ struct hostent *he = (struct hostent *)argp->buf.result;
+ char *buffer = argp->buf.buffer;
+ int buflen = argp->buf.buflen;
+ NSS_STATUS ret;
+
+ char *p, *data;
+ int addrcount = 0;
+ int len = 0;
+ struct in_addr *addrp;
+#if defined(AF_INET6)
+ struct in6_addr *addrp6;
+#endif
+ int i;
+
+ /* response is tab separated list of ip addresses with hostname
+ and newline at the end. so at first we will strip newline
+ then construct list of addresses for hostent.
+ */
+ p = strchr(response->data.winsresp, '\n');
+ if(p) *p = '\0';
+ else {/* it must be broken */
+ argp->h_errno = NO_DATA;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ for(; p != response->data.winsresp; p--) {
+ if(*p == '\t') addrcount++;
+ }
+
+ if(addrcount == 0) {/* it must be broken */
+ argp->h_errno = NO_DATA;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ /* allocate space for addresses and h_addr_list */
+ he->h_addrtype = af;
+ if( he->h_addrtype == AF_INET) {
+ he->h_length = sizeof(struct in_addr);
+ addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen,
+ sizeof(struct in_addr));
+ addrp -= addrcount;
+ he->h_addr_list = (char **)ROUND_DOWN(addrp, sizeof (char*));
+ he->h_addr_list -= addrcount+1;
+ }
+#if defined(AF_INET6)
+ else {
+ he->h_length = sizeof(struct in6_addr);
+ addrp6 = (struct in6_addr *)ROUND_DOWN(buffer + buflen,
+ sizeof(struct in6_addr));
+ addrp6 -= addrcount;
+ he->h_addr_list = (char **)ROUND_DOWN(addrp6, sizeof (char*));
+ he->h_addr_list -= addrcount+1;
+ }
+#endif
+
+ /* buffer too small?! */
+ if((char *)he->h_addr_list < buffer ) {
+ argp->erange = 1;
+ return NSS_STR_PARSE_ERANGE;
+ }
+
+ data = response->data.winsresp;
+ for( i = 0; i < addrcount; i++) {
+ p = strchr(data, '\t');
+ if(p == NULL) break; /* just in case... */
+
+ *p = '\0'; /* terminate the string */
+ if(he->h_addrtype == AF_INET) {
+ he->h_addr_list[i] = (char *)&addrp[i];
+ if ((addrp[i].s_addr = inet_addr(data)) == -1) {
+ argp->erange = 1;
+ return NSS_STR_PARSE_ERANGE;
+ }
+ }
+#if defined(AF_INET6)
+ else {
+ he->h_addr_list[i] = (char *)&addrp6[i];
+ if (strchr(data, ':') != 0) {
+ if (inet_pton(AF_INET6, data, &addrp6[i]) != 1) {
+ argp->erange = 1;
+ return NSS_STR_PARSE_ERANGE;
+ }
+ } else {
+ struct in_addr in4;
+ if ((in4.s_addr = inet_addr(data)) == -1) {
+ argp->erange = 1;
+ return NSS_STR_PARSE_ERANGE;
+ }
+ IN6_INADDR_TO_V4MAPPED(&in4, &addrp6[i]);
+ }
+ }
+#endif
+ data = p+1;
+ }
+
+ he->h_addr_list[i] = (char *)NULL;
+
+ len = strlen(data);
+ if(len > he->h_addr_list - (char**)argp->buf.buffer) {
+ argp->erange = 1;
+ return NSS_STR_PARSE_ERANGE;
+ }
+
+ /* this is a bit overkill to use _nss_netdb_aliases here since
+ there seems to be no aliases but it will create all data for us */
+ he->h_aliases = _nss_netdb_aliases(data, len, buffer,
+ ((char*) he->h_addr_list) - buffer);
+ if(he->h_aliases == NULL) {
+ argp->erange = 1;
+ ret = NSS_STR_PARSE_ERANGE;
+ } else {
+ he->h_name = he->h_aliases[0];
+ he->h_aliases++;
+ ret = NSS_STR_PARSE_SUCCESS;
+ }
+
+ argp->returnval = (void*)he;
+ return ret;
+}
+
+static NSS_STATUS
+_nss_winbind_ipnodes_getbyname(nss_backend_t* be, void *args)
+{
+ nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args;
+ struct winbindd_response response;
+ struct winbindd_request request;
+ NSS_STATUS ret;
+ int af;
+
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
+
+ /* I assume there that AI_ADDRCONFIG cases are handled in nss
+ frontend code, at least it seems done so in solaris...
+
+ we will give NO_DATA for pure IPv6; IPv4 will be returned for
+ AF_INET or for AF_INET6 and AI_ALL|AI_V4MAPPED we have to map
+ IPv4 to IPv6.
+ */
+#if defined(AF_INET6)
+#ifdef HAVE_NSS_XBYY_KEY_IPNODE
+ af = argp->key.ipnode.af_family;
+ if(af == AF_INET6 && argp->key.ipnode.flags == 0) {
+ argp->h_errno = NO_DATA;
+ return NSS_STATUS_UNAVAIL;
+ }
+#else
+ /* I'm not that sure if this is correct, but... */
+ af = AF_INET6;
+#endif
+#endif
+
+ strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1);
+ request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0';
+
+ if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response))
+ == NSS_STATUS_SUCCESS ) {
+ ret = parse_response(af, argp, &response);
+ }
+
+ winbindd_free_response(&response);
+ return ret;
+}
+
+static NSS_STATUS
+_nss_winbind_hosts_getbyname(nss_backend_t* be, void *args)
+{
+ nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args;
+ struct winbindd_response response;
+ struct winbindd_request request;
+ NSS_STATUS ret;
+
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
+
+ strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1);
+ request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0';
+
+ if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response))
+ == NSS_STATUS_SUCCESS ) {
+ ret = parse_response(AF_INET, argp, &response);
+ }
+
+ winbindd_free_response(&response);
+ return ret;
+}
+
+static NSS_STATUS
+_nss_winbind_hosts_getbyaddr(nss_backend_t* be, void *args)
+{
+ NSS_STATUS ret;
+ struct winbindd_response response;
+ struct winbindd_request request;
+ nss_XbyY_args_t *argp = (nss_XbyY_args_t *)args;
+ const char *p;
+
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
+
+#if defined(AF_INET6)
+ /* winbindd currently does not resolve IPv6 */
+ if(argp->key.hostaddr.type == AF_INET6) {
+ argp->h_errno = NO_DATA;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ p = inet_ntop(argp->key.hostaddr.type, argp->key.hostaddr.addr,
+ request.data.winsreq, sizeof request.data.winsreq);
+#else
+ snprintf(request.data.winsreq, sizeof request.data.winsreq,
+ "%u.%u.%u.%u",
+ ((unsigned char *)argp->key.hostaddr.addr)[0],
+ ((unsigned char *)argp->key.hostaddr.addr)[1],
+ ((unsigned char *)argp->key.hostaddr.addr)[2],
+ ((unsigned char *)argp->key.hostaddr.addr)[3]);
+#endif
+
+ ret = winbindd_request_response(WINBINDD_WINS_BYIP, &request, &response);
+
+ if( ret == NSS_STATUS_SUCCESS) {
+ parse_response(argp->key.hostaddr.type, argp, &response);
+ }
+ winbindd_free_response(&response);
+ return ret;
+}
+
+/* winbind does not provide setent, getent, endent for wins */
+static NSS_STATUS
+_nss_winbind_common_endent(nss_backend_t* be, void *args)
+{
+ return (NSS_STATUS_UNAVAIL);
+}
+
+static NSS_STATUS
+_nss_winbind_common_setent(nss_backend_t* be, void *args)
+{
+ return (NSS_STATUS_UNAVAIL);
+}
+
+static NSS_STATUS
+_nss_winbind_common_getent(nss_backend_t* be, void *args)
+{
+ return (NSS_STATUS_UNAVAIL);
+}
+
+static nss_backend_t*
+_nss_winbind_common_constr (nss_backend_op_t ops[], int n_ops)
+{
+ nss_backend_t* be;
+
+ if(!(be = SMB_MALLOC_P(nss_backend_t)) )
+ return NULL;
+
+ be->ops = ops;
+ be->n_ops = n_ops;
+
+ return be;
+}
+
+static NSS_STATUS
+_nss_winbind_common_destr (nss_backend_t* be, void* args)
+{
+ SAFE_FREE(be);
+ return NSS_STATUS_SUCCESS;
+}
+
+static nss_backend_op_t ipnodes_ops[] = {
+ _nss_winbind_common_destr,
+ _nss_winbind_common_endent,
+ _nss_winbind_common_setent,
+ _nss_winbind_common_getent,
+ _nss_winbind_ipnodes_getbyname,
+ _nss_winbind_hosts_getbyaddr,
+};
+
+nss_backend_t *
+_nss_winbind_ipnodes_constr(dummy1, dummy2, dummy3)
+ const char *dummy1, *dummy2, *dummy3;
+{
+ return (_nss_winbind_common_constr(ipnodes_ops,
+ sizeof (ipnodes_ops) / sizeof (ipnodes_ops[0])));
+}
+
+static nss_backend_op_t host_ops[] = {
+ _nss_winbind_common_destr,
+ _nss_winbind_common_endent,
+ _nss_winbind_common_setent,
+ _nss_winbind_common_getent,
+ _nss_winbind_hosts_getbyname,
+ _nss_winbind_hosts_getbyaddr,
+};
+
+nss_backend_t *
+_nss_winbind_hosts_constr(dummy1, dummy2, dummy3)
+ const char *dummy1, *dummy2, *dummy3;
+{
+ return (_nss_winbind_common_constr(host_ops,
+ sizeof (host_ops) / sizeof (host_ops[0])));
+}
+
+#endif /* defined(SUNOS5) */
+#endif /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */
diff --git a/source3/nsswitch/winbind_nss_solaris.h b/source3/nsswitch/winbind_nss_solaris.h
new file mode 100644
index 0000000000..84062dbab4
--- /dev/null
+++ b/source3/nsswitch/winbind_nss_solaris.h
@@ -0,0 +1,85 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon for ntdom nss module
+
+ Copyright (C) Tim Potter 2000
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _WINBIND_NSS_SOLARIS_H
+#define _WINBIND_NSS_SOLARIS_H
+
+/* Solaris has a broken nss_common header file containing C++ reserved names. */
+#ifndef __cplusplus
+#undef class
+#undef private
+#undef public
+#undef protected
+#undef template
+#undef this
+#undef new
+#undef delete
+#undef friend
+#endif
+
+#include <nss_common.h>
+
+#ifndef __cplusplus
+#define class #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#define private #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#define public #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#define protected #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#define template #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#define this #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#define new #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#define delete #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#define friend #error DONT_USE_CPLUSPLUS_RESERVED_NAMES
+#endif
+
+#include <nss_dbdefs.h>
+#include <nsswitch.h>
+
+typedef nss_status_t NSS_STATUS;
+
+#define NSS_STATUS_SUCCESS NSS_SUCCESS
+#define NSS_STATUS_NOTFOUND NSS_NOTFOUND
+#define NSS_STATUS_UNAVAIL NSS_UNAVAIL
+#define NSS_STATUS_TRYAGAIN NSS_TRYAGAIN
+
+/* The solaris winbind is implemented as a wrapper around the linux
+ version. */
+
+NSS_STATUS _nss_winbind_setpwent(void);
+NSS_STATUS _nss_winbind_endpwent(void);
+NSS_STATUS _nss_winbind_getpwent_r(struct passwd* result, char* buffer,
+ size_t buflen, int* errnop);
+NSS_STATUS _nss_winbind_getpwuid_r(uid_t, struct passwd*, char* buffer,
+ size_t buflen, int* errnop);
+NSS_STATUS _nss_winbind_getpwnam_r(const char* name, struct passwd* result,
+ char* buffer, size_t buflen, int* errnop);
+
+NSS_STATUS _nss_winbind_setgrent(void);
+NSS_STATUS _nss_winbind_endgrent(void);
+NSS_STATUS _nss_winbind_getgrent_r(struct group* result, char* buffer,
+ size_t buflen, int* errnop);
+NSS_STATUS _nss_winbind_getgrnam_r(const char *name,
+ struct group *result, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_getgrgid_r(gid_t gid,
+ struct group *result, char *buffer,
+ size_t buflen, int *errnop);
+
+#endif /* _WINBIND_NSS_SOLARIS_H */
diff --git a/source3/nsswitch/winbind_struct_protocol.h b/source3/nsswitch/winbind_struct_protocol.h
new file mode 100644
index 0000000000..e81813c77b
--- /dev/null
+++ b/source3/nsswitch/winbind_struct_protocol.h
@@ -0,0 +1,493 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon for ntdom nss module
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Gerald Carter 2006
+
+ You are free to use this interface definition in any way you see
+ fit, including without restriction, using this header in your own
+ products. You do not need to give any attribution.
+*/
+
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) do { if(x) {free(x); x=NULL;} } while(0)
+#endif
+
+#ifndef _WINBINDD_NTDOM_H
+#define _WINBINDD_NTDOM_H
+
+#define WINBINDD_SOCKET_NAME "pipe" /* Name of PF_UNIX socket */
+
+/* Let the build environment override the public winbindd socket location. This
+ * is needed for launchd support -- jpeach.
+ */
+#ifndef WINBINDD_SOCKET_DIR
+#define WINBINDD_SOCKET_DIR "/tmp/.winbindd" /* Name of PF_UNIX dir */
+#endif
+
+/*
+ * when compiled with socket_wrapper support
+ * the location of the WINBINDD_SOCKET_DIR
+ * can be overwritten via an environment variable
+ */
+#define WINBINDD_SOCKET_DIR_ENVVAR "WINBINDD_SOCKET_DIR"
+
+#define WINBINDD_PRIV_SOCKET_SUBDIR "winbindd_privileged" /* name of subdirectory of lp_lockdir() to hold the 'privileged' pipe */
+#define WINBINDD_DOMAIN_ENV "WINBINDD_DOMAIN" /* Environment variables */
+#define WINBINDD_DONT_ENV "_NO_WINBINDD"
+#define WINBINDD_LOCATOR_KDC_ADDRESS "WINBINDD_LOCATOR_KDC_ADDRESS"
+
+/* Update this when you change the interface. */
+
+#define WINBIND_INTERFACE_VERSION 19
+
+/* Have to deal with time_t being 4 or 8 bytes due to structure alignment.
+ On a 64bit Linux box, we have to support a constant structure size
+ between /lib/libnss_winbind.so.2 and /li64/libnss_winbind.so.2.
+ The easiest way to do this is to always use 8byte values for time_t. */
+
+#define SMB_TIME_T int64_t
+
+/* Socket commands */
+
+enum winbindd_cmd {
+
+ WINBINDD_INTERFACE_VERSION, /* Always a well known value */
+
+ /* Get users and groups */
+
+ WINBINDD_GETPWNAM,
+ WINBINDD_GETPWUID,
+ WINBINDD_GETGRNAM,
+ WINBINDD_GETGRGID,
+ WINBINDD_GETGROUPS,
+
+ /* Enumerate users and groups */
+
+ WINBINDD_SETPWENT,
+ WINBINDD_ENDPWENT,
+ WINBINDD_GETPWENT,
+ WINBINDD_SETGRENT,
+ WINBINDD_ENDGRENT,
+ WINBINDD_GETGRENT,
+
+ /* PAM authenticate and password change */
+
+ WINBINDD_PAM_AUTH,
+ WINBINDD_PAM_AUTH_CRAP,
+ WINBINDD_PAM_CHAUTHTOK,
+ WINBINDD_PAM_LOGOFF,
+ WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP,
+
+ /* List various things */
+
+ WINBINDD_LIST_USERS, /* List w/o rid->id mapping */
+ WINBINDD_LIST_GROUPS, /* Ditto */
+ WINBINDD_LIST_TRUSTDOM,
+
+ /* SID conversion */
+
+ WINBINDD_LOOKUPSID,
+ WINBINDD_LOOKUPNAME,
+ WINBINDD_LOOKUPRIDS,
+
+ /* Lookup functions */
+
+ WINBINDD_SID_TO_UID,
+ WINBINDD_SID_TO_GID,
+ WINBINDD_SIDS_TO_XIDS,
+ WINBINDD_UID_TO_SID,
+ WINBINDD_GID_TO_SID,
+
+ WINBINDD_ALLOCATE_UID,
+ WINBINDD_ALLOCATE_GID,
+ WINBINDD_SET_MAPPING,
+ WINBINDD_SET_HWM,
+
+ /* Miscellaneous other stuff */
+
+ WINBINDD_CHECK_MACHACC, /* Check machine account pw works */
+ WINBINDD_PING, /* Just tell me winbind is running */
+ WINBINDD_INFO, /* Various bit of info. Currently just tidbits */
+ WINBINDD_DOMAIN_NAME, /* The domain this winbind server is a member of (lp_workgroup()) */
+
+ WINBINDD_DOMAIN_INFO, /* Most of what we know from
+ struct winbindd_domain */
+ WINBINDD_GETDCNAME, /* Issue a GetDCName Request */
+ WINBINDD_DSGETDCNAME, /* Issue a DsGetDCName Request */
+
+ WINBINDD_SHOW_SEQUENCE, /* display sequence numbers of domains */
+
+ /* WINS commands */
+
+ WINBINDD_WINS_BYIP,
+ WINBINDD_WINS_BYNAME,
+
+ /* this is like GETGRENT but gives an empty group list */
+ WINBINDD_GETGRLST,
+
+ WINBINDD_NETBIOS_NAME, /* The netbios name of the server */
+
+ /* find the location of our privileged pipe */
+ WINBINDD_PRIV_PIPE_DIR,
+
+ /* return a list of group sids for a user sid */
+ WINBINDD_GETUSERSIDS,
+
+ /* Various group queries */
+ WINBINDD_GETUSERDOMGROUPS,
+
+ /* Initialize connection in a child */
+ WINBINDD_INIT_CONNECTION,
+
+ /* Blocking calls that are not allowed on the main winbind pipe, only
+ * between parent and children */
+ WINBINDD_DUAL_SID2UID,
+ WINBINDD_DUAL_SID2GID,
+ WINBINDD_DUAL_SIDS2XIDS,
+ WINBINDD_DUAL_UID2SID,
+ WINBINDD_DUAL_GID2SID,
+ WINBINDD_DUAL_SET_MAPPING,
+ WINBINDD_DUAL_SET_HWM,
+
+ /* Wrapper around possibly blocking unix nss calls */
+ WINBINDD_DUAL_USERINFO,
+ WINBINDD_DUAL_GETSIDALIASES,
+
+ /* Complete the challenge phase of the NTLM authentication
+ protocol using cached password. */
+ WINBINDD_CCACHE_NTLMAUTH,
+
+ WINBINDD_NUM_CMDS
+};
+
+typedef struct winbindd_pw {
+ fstring pw_name;
+ fstring pw_passwd;
+ uid_t pw_uid;
+ gid_t pw_gid;
+ fstring pw_gecos;
+ fstring pw_dir;
+ fstring pw_shell;
+} WINBINDD_PW;
+
+
+typedef struct winbindd_gr {
+ fstring gr_name;
+ fstring gr_passwd;
+ gid_t gr_gid;
+ uint32_t num_gr_mem;
+ uint32_t gr_mem_ofs; /* offset to group membership */
+} WINBINDD_GR;
+
+/* PAM specific request flags */
+#define WBFLAG_PAM_INFO3_NDR 0x00000001
+#define WBFLAG_PAM_INFO3_TEXT 0x00000002
+#define WBFLAG_PAM_USER_SESSION_KEY 0x00000004
+#define WBFLAG_PAM_LMKEY 0x00000008
+#define WBFLAG_PAM_CONTACT_TRUSTDOM 0x00000010
+#define WBFLAG_PAM_UNIX_NAME 0x00000080
+#define WBFLAG_PAM_AFS_TOKEN 0x00000100
+#define WBFLAG_PAM_NT_STATUS_SQUASH 0x00000200
+#define WBFLAG_PAM_KRB5 0x00001000
+#define WBFLAG_PAM_FALLBACK_AFTER_KRB5 0x00002000
+#define WBFLAG_PAM_CACHED_LOGIN 0x00004000
+#define WBFLAG_PAM_GET_PWD_POLICY 0x00008000
+
+/* generic request flags */
+#define WBFLAG_QUERY_ONLY 0x00000020 /* not used */
+/* This is a flag that can only be sent from parent to child */
+#define WBFLAG_IS_PRIVILEGED 0x00000400 /* not used */
+/* Flag to say this is a winbindd internal send - don't recurse. */
+#define WBFLAG_RECURSE 0x00000800
+
+
+#define WINBINDD_MAX_EXTRA_DATA (128*1024)
+
+/* Winbind request structure */
+
+/*******************************************************************************
+ * This structure MUST be the same size in the 32bit and 64bit builds
+ * for compatibility between /lib64/libnss_winbind.so and /lib/libnss_winbind.so
+ *
+ * DO NOT CHANGE THIS STRUCTURE WITHOUT TESTING THE 32BIT NSS LIB AGAINST
+ * A 64BIT WINBINDD --jerry
+ ******************************************************************************/
+
+struct winbindd_request {
+ uint32_t length;
+ enum winbindd_cmd cmd; /* Winbindd command to execute */
+ enum winbindd_cmd original_cmd; /* Original Winbindd command
+ issued to parent process */
+ pid_t pid; /* pid of calling process */
+ uint32_t wb_flags; /* generic flags */
+ uint32_t flags; /* flags relevant *only* to a given request */
+ fstring domain_name; /* name of domain for which the request applies */
+
+ union {
+ fstring winsreq; /* WINS request */
+ fstring username; /* getpwnam */
+ fstring groupname; /* getgrnam */
+ uid_t uid; /* getpwuid, uid_to_sid */
+ gid_t gid; /* getgrgid, gid_to_sid */
+ struct {
+ /* We deliberatedly don't split into domain/user to
+ avoid having the client know what the separator
+ character is. */
+ fstring user;
+ fstring pass;
+ char require_membership_of_sid[1024];
+ fstring krb5_cc_type;
+ uid_t uid;
+ } auth; /* pam_winbind auth module */
+ struct {
+ uint8_t chal[8];
+ uint32_t logon_parameters;
+ fstring user;
+ fstring domain;
+ fstring lm_resp;
+ uint32_t lm_resp_len;
+ fstring nt_resp;
+ uint32_t nt_resp_len;
+ fstring workstation;
+ fstring require_membership_of_sid;
+ } auth_crap;
+ struct {
+ fstring user;
+ fstring oldpass;
+ fstring newpass;
+ } chauthtok; /* pam_winbind passwd module */
+ struct {
+ fstring user;
+ fstring domain;
+ uint8_t new_nt_pswd[516];
+ uint16_t new_nt_pswd_len;
+ uint8_t old_nt_hash_enc[16];
+ uint16_t old_nt_hash_enc_len;
+ uint8_t new_lm_pswd[516];
+ uint16_t new_lm_pswd_len;
+ uint8_t old_lm_hash_enc[16];
+ uint16_t old_lm_hash_enc_len;
+ } chng_pswd_auth_crap;/* pam_winbind passwd module */
+ struct {
+ fstring user;
+ fstring krb5ccname;
+ uid_t uid;
+ } logoff; /* pam_winbind session module */
+ fstring sid; /* lookupsid, sid_to_[ug]id */
+ struct {
+ fstring dom_name; /* lookupname */
+ fstring name;
+ } name;
+ uint32_t num_entries; /* getpwent, getgrent */
+ struct {
+ fstring username;
+ fstring groupname;
+ } acct_mgt;
+ struct {
+ bool is_primary;
+ fstring dcname;
+ } init_conn;
+ struct {
+ fstring sid;
+ fstring name;
+ } dual_sid2id;
+ struct {
+ fstring sid;
+ uint32_t type;
+ uint32_t id;
+ } dual_idmapset;
+ bool list_all_domains;
+
+ struct {
+ uid_t uid;
+ fstring user;
+ /* the effective uid of the client, must be the uid for 'user'.
+ This is checked by the main daemon, trusted by children. */
+ /* if the blobs are length zero, then this doesn't
+ produce an actual challenge response. It merely
+ succeeds if there are cached credentials available
+ that could be used. */
+ uint32_t initial_blob_len; /* blobs in extra_data */
+ uint32_t challenge_blob_len;
+ } ccache_ntlm_auth;
+
+ /* padding -- needed to fix alignment between 32bit and 64bit libs.
+ The size is the sizeof the union without the padding aligned on
+ an 8 byte boundary. --jerry */
+
+ char padding[1800];
+ } data;
+ union {
+ SMB_TIME_T padding;
+ char *data;
+ } extra_data;
+ uint32_t extra_len;
+ char null_term;
+};
+
+/* Response values */
+
+enum winbindd_result {
+ WINBINDD_ERROR,
+ WINBINDD_PENDING,
+ WINBINDD_OK
+};
+
+/* Winbind response structure */
+
+/*******************************************************************************
+ * This structure MUST be the same size in the 32bit and 64bit builds
+ * for compatibility between /lib64/libnss_winbind.so and /lib/libnss_winbind.so
+ *
+ * DO NOT CHANGE THIS STRUCTURE WITHOUT TESTING THE 32BIT NSS LIB AGAINST
+ * A 64BIT WINBINDD --jerry
+ ******************************************************************************/
+
+struct winbindd_response {
+
+ /* Header information */
+
+ uint32_t length; /* Length of response */
+ enum winbindd_result result; /* Result code */
+
+ /* Fixed length return data */
+
+ union {
+ int interface_version; /* Try to ensure this is always in the same spot... */
+
+ fstring winsresp; /* WINS response */
+
+ /* getpwnam, getpwuid */
+
+ struct winbindd_pw pw;
+
+ /* getgrnam, getgrgid */
+
+ struct winbindd_gr gr;
+
+ uint32_t num_entries; /* getpwent, getgrent */
+ struct winbindd_sid {
+ fstring sid; /* lookupname, [ug]id_to_sid */
+ int type;
+ } sid;
+ struct winbindd_name {
+ fstring dom_name; /* lookupsid */
+ fstring name;
+ int type;
+ } name;
+ uid_t uid; /* sid_to_uid */
+ gid_t gid; /* sid_to_gid */
+ struct winbindd_info {
+ char winbind_separator;
+ fstring samba_version;
+ } info;
+ fstring domain_name;
+ fstring netbios_name;
+ fstring dc_name;
+
+ struct auth_reply {
+ uint32_t nt_status;
+ fstring nt_status_string;
+ fstring error_string;
+ int pam_error;
+ char user_session_key[16];
+ char first_8_lm_hash[8];
+ fstring krb5ccname;
+ uint32_t reject_reason;
+ uint32_t padding;
+ struct policy_settings {
+ uint32_t min_length_password;
+ uint32_t password_history;
+ uint32_t password_properties;
+ uint32_t padding;
+ SMB_TIME_T expire;
+ SMB_TIME_T min_passwordage;
+ } policy;
+ struct info3_text {
+ SMB_TIME_T logon_time;
+ SMB_TIME_T logoff_time;
+ SMB_TIME_T kickoff_time;
+ SMB_TIME_T pass_last_set_time;
+ SMB_TIME_T pass_can_change_time;
+ SMB_TIME_T pass_must_change_time;
+ uint32_t logon_count;
+ uint32_t bad_pw_count;
+ uint32_t user_rid;
+ uint32_t group_rid;
+ uint32_t num_groups;
+ uint32_t user_flgs;
+ uint32_t acct_flags;
+ uint32_t num_other_sids;
+ fstring dom_sid;
+ fstring user_name;
+ fstring full_name;
+ fstring logon_script;
+ fstring profile_path;
+ fstring home_dir;
+ fstring dir_drive;
+ fstring logon_srv;
+ fstring logon_dom;
+ } info3;
+ fstring unix_username;
+ } auth;
+ struct {
+ fstring name;
+ fstring alt_name;
+ fstring sid;
+ bool native_mode;
+ bool active_directory;
+ bool primary;
+ } domain_info;
+ uint32_t sequence_number;
+ struct {
+ fstring acct_name;
+ fstring full_name;
+ fstring homedir;
+ fstring shell;
+ uint32_t primary_gid;
+ uint32_t group_rid;
+ } user_info;
+ struct {
+ uint32_t auth_blob_len; /* blob in extra_data */
+ } ccache_ntlm_auth;
+ } data;
+
+ /* Variable length return data */
+
+ union {
+ SMB_TIME_T padding;
+ void *data;
+ } extra_data;
+};
+
+struct WINBINDD_MEMORY_CREDS {
+ struct WINBINDD_MEMORY_CREDS *next, *prev;
+ const char *username; /* lookup key. */
+ uid_t uid;
+ int ref_count;
+ size_t len;
+ uint8_t *nt_hash; /* Base pointer for the following 2 */
+ uint8_t *lm_hash;
+ char *pass;
+};
+
+struct WINBINDD_CCACHE_ENTRY {
+ struct WINBINDD_CCACHE_ENTRY *next, *prev;
+ const char *principal_name;
+ const char *ccname;
+ const char *service;
+ const char *username;
+ const char *realm;
+ struct WINBINDD_MEMORY_CREDS *cred_ptr;
+ int ref_count;
+ uid_t uid;
+ time_t create_time;
+ time_t renew_until;
+ time_t refresh_time;
+ struct timed_event *event;
+};
+
+#endif
diff --git a/source3/nsswitch/wins.c b/source3/nsswitch/wins.c
new file mode 100644
index 0000000000..7d42381986
--- /dev/null
+++ b/source3/nsswitch/wins.c
@@ -0,0 +1,414 @@
+/*
+ Unix SMB/CIFS implementation.
+ a WINS nsswitch module
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#ifdef HAVE_NS_API_H
+#undef VOLATILE
+
+#include <ns_daemon.h>
+#endif
+
+#ifndef INADDRSZ
+#define INADDRSZ 4
+#endif
+
+static int initialised;
+
+extern bool AllowDebugChange;
+
+NSS_STATUS _nss_wins_gethostbyname_r(const char *hostname, struct hostent *he,
+ char *buffer, size_t buflen, int *h_errnop);
+NSS_STATUS _nss_wins_gethostbyname2_r(const char *name, int af, struct hostent *he,
+ char *buffer, size_t buflen, int *h_errnop);
+
+/* Use our own create socket code so we don't recurse.... */
+
+static int wins_lookup_open_socket_in(void)
+{
+ struct sockaddr_in sock;
+ int val=1;
+ int res;
+
+ memset((char *)&sock,'\0',sizeof(sock));
+
+#ifdef HAVE_SOCK_SIN_LEN
+ sock.sin_len = sizeof(sock);
+#endif
+ sock.sin_port = 0;
+ sock.sin_family = AF_INET;
+ sock.sin_addr.s_addr = interpret_addr("0.0.0.0");
+ res = socket(AF_INET, SOCK_DGRAM, 0);
+ if (res == -1)
+ return -1;
+
+ if (setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val)) != 0) {
+ close(res);
+ return -1;
+ }
+#ifdef SO_REUSEPORT
+ if (setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val)) != 0) {
+ close(res);
+ return -1;
+ }
+#endif /* SO_REUSEPORT */
+
+ /* now we've got a socket - we need to bind it */
+
+ if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) {
+ close(res);
+ return(-1);
+ }
+
+ set_socket_options(res,"SO_BROADCAST");
+
+ return res;
+}
+
+
+static void nss_wins_init(void)
+{
+ initialised = 1;
+ DEBUGLEVEL = 0;
+ AllowDebugChange = False;
+
+ TimeInit();
+ setup_logging("nss_wins",False);
+ load_case_tables();
+ lp_load(get_dyn_CONFIGFILE(),True,False,False,True);
+ load_interfaces();
+}
+
+static struct in_addr *lookup_byname_backend(const char *name, int *count)
+{
+ int fd = -1;
+ struct ip_service *address = NULL;
+ struct in_addr *ret = NULL;
+ int j, flags = 0;
+
+ if (!initialised) {
+ nss_wins_init();
+ }
+
+ *count = 0;
+
+ /* always try with wins first */
+ if (NT_STATUS_IS_OK(resolve_wins(name,0x00,&address,count))) {
+ if ( (ret = SMB_MALLOC_P(struct in_addr)) == NULL ) {
+ free( address );
+ return NULL;
+ }
+ if (address[0].ss.ss_family != AF_INET) {
+ free(address);
+ free(ret);
+ return NULL;
+ }
+ *ret = ((struct sockaddr_in *)&address[0].ss)->sin_addr;
+ free( address );
+ return ret;
+ }
+
+ fd = wins_lookup_open_socket_in();
+ if (fd == -1) {
+ return NULL;
+ }
+
+ /* uggh, we have to broadcast to each interface in turn */
+ for (j=iface_count() - 1;j >= 0;j--) {
+ const struct in_addr *bcast = iface_n_bcast_v4(j);
+ struct sockaddr_storage ss;
+ struct sockaddr_storage *pss;
+ if (!bcast) {
+ continue;
+ }
+ in_addr_to_sockaddr_storage(&ss, *bcast);
+ pss = name_query(fd,name,0x00,True,True,&ss,count, &flags, NULL);
+ if (pss) {
+ if ((ret = SMB_MALLOC_P(struct in_addr)) == NULL) {
+ return NULL;
+ }
+ *ret = ((struct sockaddr_in *)pss)->sin_addr;
+ break;
+ }
+ }
+
+ close(fd);
+ return ret;
+}
+
+#ifdef HAVE_NS_API_H
+
+static NODE_STATUS_STRUCT *lookup_byaddr_backend(char *addr, int *count)
+{
+ int fd;
+ struct sockaddr_storage ss;
+ struct nmb_name nname;
+ NODE_STATUS_STRUCT *status;
+
+ if (!initialised) {
+ nss_wins_init();
+ }
+
+ fd = wins_lookup_open_socket_in();
+ if (fd == -1)
+ return NULL;
+
+ make_nmb_name(&nname, "*", 0);
+ if (!interpret_string_addr(&ss, addr, AI_NUMERICHOST)) {
+ return NULL;
+ }
+ status = node_status_query(fd, &nname, &ss, count, NULL);
+
+ close(fd);
+ return status;
+}
+
+/* IRIX version */
+
+int init(void)
+{
+ nsd_logprintf(NSD_LOG_MIN, "entering init (wins)\n");
+ nss_wins_init();
+ return NSD_OK;
+}
+
+int lookup(nsd_file_t *rq)
+{
+ char *map;
+ char *key;
+ char *addr;
+ struct in_addr *ip_list;
+ NODE_STATUS_STRUCT *status;
+ int i, count, len, size;
+ char response[1024];
+ bool found = False;
+
+ nsd_logprintf(NSD_LOG_MIN, "entering lookup (wins)\n");
+ if (! rq)
+ return NSD_ERROR;
+
+ map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
+ if (! map) {
+ rq->f_status = NS_FATAL;
+ return NSD_ERROR;
+ }
+
+ key = nsd_attr_fetch_string(rq->f_attrs, "key", (char*)0);
+ if (! key || ! *key) {
+ rq->f_status = NS_FATAL;
+ return NSD_ERROR;
+ }
+
+ response[0] = '\0';
+ len = sizeof(response) - 2;
+
+ /*
+ * response needs to be a string of the following format
+ * ip_address[ ip_address]*\tname[ alias]*
+ */
+ if (StrCaseCmp(map,"hosts.byaddr") == 0) {
+ if ( status = lookup_byaddr_backend(key, &count)) {
+ size = strlen(key) + 1;
+ if (size > len) {
+ free(status);
+ return NSD_ERROR;
+ }
+ len -= size;
+ strncat(response,key,size);
+ strncat(response,"\t",1);
+ for (i = 0; i < count; i++) {
+ /* ignore group names */
+ if (status[i].flags & 0x80) continue;
+ if (status[i].type == 0x20) {
+ size = sizeof(status[i].name) + 1;
+ if (size > len) {
+ free(status);
+ return NSD_ERROR;
+ }
+ len -= size;
+ strncat(response, status[i].name, size);
+ strncat(response, " ", 1);
+ found = True;
+ }
+ }
+ response[strlen(response)-1] = '\n';
+ free(status);
+ }
+ } else if (StrCaseCmp(map,"hosts.byname") == 0) {
+ if (ip_list = lookup_byname_backend(key, &count)) {
+ for (i = count; i ; i--) {
+ addr = inet_ntoa(ip_list[i-1]);
+ size = strlen(addr) + 1;
+ if (size > len) {
+ free(ip_list);
+ return NSD_ERROR;
+ }
+ len -= size;
+ if (i != 0)
+ response[strlen(response)-1] = ' ';
+ strncat(response,addr,size);
+ strncat(response,"\t",1);
+ }
+ size = strlen(key) + 1;
+ if (size > len) {
+ free(ip_list);
+ return NSD_ERROR;
+ }
+ strncat(response,key,size);
+ strncat(response,"\n",1);
+ found = True;
+ free(ip_list);
+ }
+ }
+
+ if (found) {
+ nsd_logprintf(NSD_LOG_LOW, "lookup (wins %s) %s\n",map,response);
+ nsd_set_result(rq,NS_SUCCESS,response,strlen(response),VOLATILE);
+ return NSD_OK;
+ }
+ nsd_logprintf(NSD_LOG_LOW, "lookup (wins) not found\n");
+ rq->f_status = NS_NOTFOUND;
+ return NSD_NEXT;
+}
+
+#else
+
+/* Allocate some space from the nss static buffer. The buffer and buflen
+ are the pointers passed in by the C library to the _nss_*_*
+ functions. */
+
+static char *get_static(char **buffer, size_t *buflen, int len)
+{
+ char *result;
+
+ /* Error check. We return false if things aren't set up right, or
+ there isn't enough buffer space left. */
+
+ if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
+ return NULL;
+ }
+
+ /* Return an index into the static buffer */
+
+ result = *buffer;
+ *buffer += len;
+ *buflen -= len;
+
+ return result;
+}
+
+/****************************************************************************
+gethostbyname() - we ignore any domain portion of the name and only
+handle names that are at most 15 characters long
+ **************************************************************************/
+NSS_STATUS
+_nss_wins_gethostbyname_r(const char *hostname, struct hostent *he,
+ char *buffer, size_t buflen, int *h_errnop)
+{
+ struct in_addr *ip_list;
+ int i, count;
+ fstring name;
+ size_t namelen;
+
+ memset(he, '\0', sizeof(*he));
+ fstrcpy(name, hostname);
+
+ /* Do lookup */
+
+ ip_list = lookup_byname_backend(name, &count);
+
+ if (!ip_list)
+ return NSS_STATUS_NOTFOUND;
+
+ /* Copy h_name */
+
+ namelen = strlen(name) + 1;
+
+ if ((he->h_name = get_static(&buffer, &buflen, namelen)) == NULL) {
+ free(ip_list);
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ memcpy(he->h_name, name, namelen);
+
+ /* Copy h_addr_list, align to pointer boundary first */
+
+ if ((i = (unsigned long)(buffer) % sizeof(char*)) != 0)
+ i = sizeof(char*) - i;
+
+ if (get_static(&buffer, &buflen, i) == NULL) {
+ free(ip_list);
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ if ((he->h_addr_list = (char **)get_static(
+ &buffer, &buflen, (count + 1) * sizeof(char *))) == NULL) {
+ free(ip_list);
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ for (i = 0; i < count; i++) {
+ if ((he->h_addr_list[i] = get_static(&buffer, &buflen,
+ INADDRSZ)) == NULL) {
+ free(ip_list);
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(he->h_addr_list[i], &ip_list[i], INADDRSZ);
+ }
+
+ he->h_addr_list[count] = NULL;
+
+ free(ip_list);
+
+ /* Set h_addr_type and h_length */
+
+ he->h_addrtype = AF_INET;
+ he->h_length = INADDRSZ;
+
+ /* Set h_aliases */
+
+ if ((i = (unsigned long)(buffer) % sizeof(char*)) != 0)
+ i = sizeof(char*) - i;
+
+ if (get_static(&buffer, &buflen, i) == NULL)
+ return NSS_STATUS_TRYAGAIN;
+
+ if ((he->h_aliases = (char **)get_static(
+ &buffer, &buflen, sizeof(char *))) == NULL)
+ return NSS_STATUS_TRYAGAIN;
+
+ he->h_aliases[0] = NULL;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+
+NSS_STATUS
+_nss_wins_gethostbyname2_r(const char *name, int af, struct hostent *he,
+ char *buffer, size_t buflen, int *h_errnop)
+{
+ if(af!=AF_INET) {
+ *h_errnop = NO_DATA;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ return _nss_wins_gethostbyname_r(
+ name, he, buffer, buflen, h_errnop);
+}
+#endif
diff --git a/source3/pam_smbpass/CHANGELOG b/source3/pam_smbpass/CHANGELOG
new file mode 100644
index 0000000000..96ef784008
--- /dev/null
+++ b/source3/pam_smbpass/CHANGELOG
@@ -0,0 +1,31 @@
+version 0.7.5 25 Mar 2001
+ - Use Samba 2.2.0 (alpha) as the target codebase, since it doesn't look
+ like Samba will be offering shared libraries in the near future.
+ - added a Makefile and support scripts to make the build process easier.
+ - imported some Solaris fixes that I've been sitting on.
+
+version 0.7.4 20 Jan 2000
+ - added a 'migrate' option to the authentication code which makes no
+ effort to authenticate the user, or even to ask for a password, but
+ it can be useful for filling in an SMB password db.
+
+version 0.7.3 19 Jan 2000
+ - updated to use the SAMBA_TNG Samba branch, allowing us to dynamically
+ link against Luke's new shared libs (libsamba, libsmb).
+
+version 0.7.2 20 Jul 1999
+ - miscellaneous bugfixes. Cleanup of legacy pam_pwdb code.
+ - fixed return value of pam_sm_setcred function.
+ - fix to autoconf support
+ - clarified some of the messages being logged
+
+version 0.6, 15 Jul 1999
+ - updated to use the new Samba (2.0) password database API.
+ - added autoconf support. May now theoretically compile on more
+ platforms than PAM itself does.
+ - added support for account management functions (i.e., disabled
+ accounts)
+
+version 0.5, 4 Apr 1998
+ - added support for hashed passwords as input. Now capable of serving
+ as an authentication agent for encrypted network transactions.
diff --git a/source3/pam_smbpass/INSTALL b/source3/pam_smbpass/INSTALL
new file mode 100644
index 0000000000..ae2ba02bbb
--- /dev/null
+++ b/source3/pam_smbpass/INSTALL
@@ -0,0 +1,64 @@
+
+Because pam_smbpass is derived from the Samba smbpasswd utility, recent
+versions of pam_smbpass require a copy of the Samba source code to be
+available on the build system. Version 0.7.5 has been tested against
+Samba 2.2.0-alpha3, and this is the recommended version of Samba to use
+for building pam_smbpass. This only affects /building/ pam_smbpass; you
+can still run any version of the Samba server that you want, although
+clearly it saves some disk space to have only one copy of the source
+code on your system (Samba 2.2.0-alpha3 takes roughly 32MB of disk space
+to build pam_smbpass).
+
+Version 0.7.5 features a new build system to make it easier to build
+pam_smbpass.
+
+
+Using the new build system
+==========================
+
+If you don't have a copy of the Samba source code on your machine, and you
+don't have a preferred Samba version (or mirror site), you can build
+pam_smbpass by just typing 'make'.
+
+If you want to use a version other than 2.2.0-alpha3, or you want to
+download the source code from a faster Samba mirror (see
+<http://us1.samba.org/samba/> for a list of mirror sites), please download
+the source code and unpack it before running make. The build scripts will
+attempt to autodetect your Samba source directory, and if it can't be
+found automatically, you will be given the opportunity to specify an
+alternate directory for the Samba sources.
+
+Feedback is welcome if you try (or succeed!) to build pam_smbpass with
+other versions of Samba.
+
+
+Options to 'make'
+=================
+
+By default, pam_smbpass will configure the Samba build tree with the
+options
+
+ --with-fhs --with-privatedir=/etc --with-configdir=/etc
+
+This will configure pam_smbpass to look for the smbpasswd file as
+/etc/smbpasswd (or /etc/smbpasswd.tdb), and the smb.conf file as
+/etc/smb.conf. You can override these options by setting CONFIGOPTS when
+calling make. E.g., if you have your smb.conf file in /usr/etc and your
+smbpasswd file in /usr/etc/private, you might run
+
+ make CONFIGOPTS="--with-privatedir=/usr/etc/private --with-configdir=/usr/etc"
+
+For a complete list of available configuration options, see
+'./samba/configure --help'
+
+
+Installing the module
+=====================
+
+If all goes well in the build process, the file pam_smbpass.so will be
+created in the current directory. Simply install the module into your
+system's PAM module directory:
+
+ install -m 755 -s bin/pam_smbpass.so /lib/security
+
+and you're all set.
diff --git a/source3/pam_smbpass/README b/source3/pam_smbpass/README
new file mode 100644
index 0000000000..6cdb76f9c3
--- /dev/null
+++ b/source3/pam_smbpass/README
@@ -0,0 +1,60 @@
+25 Mar 2001
+
+pam_smbpass is a PAM module which can be used on conforming systems to
+keep the smbpasswd (Samba password) database in sync with the unix
+password file. PAM (Pluggable Authentication Modules) is an API supported
+under some Unices, such as Solaris, HPUX and Linux, that provides a
+generic interface to authentication mechanisms.
+
+For more information on PAM, see http://ftp.kernel.org/pub/linux/libs/pam/
+
+This module authenticates a local smbpasswd user database. If you require
+support for authenticating against a remote SMB server, or if you're
+concerned about the presence of suid root binaries on your system, it is
+recommended that you use pam_winbind instead.
+
+Options recognized by this module are as follows:
+
+ debug - log more debugging info
+ audit - like debug, but also logs unknown usernames
+ use_first_pass - don't prompt the user for passwords;
+ take them from PAM_ items instead
+ try_first_pass - try to get the password from a previous
+ PAM module, fall back to prompting the user
+ use_authtok - like try_first_pass, but *fail* if the new
+ PAM_AUTHTOK has not been previously set.
+ (intended for stacking password modules only)
+ not_set_pass - don't make passwords used by this module
+ available to other modules.
+ nodelay - don't insert ~1 second delays on authentication
+ failure.
+ nullok - null passwords are allowed.
+ nonull - null passwords are not allowed. Used to
+ override the Samba configuration.
+ migrate - only meaningful in an "auth" context;
+ used to update smbpasswd file with a
+ password used for successful authentication.
+ smbconf=<file> - specify an alternate path to the smb.conf
+ file.
+
+See the samples/ directory for example PAM configurations using this
+module.
+
+Thanks go to the following people:
+
+* Andrew Morgan <morgan@transmeta.com>, for providing the Linux-PAM
+framework, without which none of this would have happened
+
+* Christian Gafton <gafton@redhat.com> and Andrew Morgan again, for the
+pam_pwdb module upon which pam_smbpass was originally based
+
+* Luke Leighton <lkcl@switchboard.net> for being receptive to the idea,
+and for the occasional good-natured complaint about the project's status
+that keep me working on it :)
+
+* and of course, all the other members of the Samba team
+<http://www.samba.org/samba/team.html>, for creating a great product
+and for giving this project a purpose
+
+---------------------
+Stephen Langasek <vorlon@netexpress.net>
diff --git a/source3/pam_smbpass/TODO b/source3/pam_smbpass/TODO
new file mode 100644
index 0000000000..20cf4fb098
--- /dev/null
+++ b/source3/pam_smbpass/TODO
@@ -0,0 +1,7 @@
+This is a tentative TODO file which will probably get much longer before
+it gets much shorter.
+
+- Recognizing (and overriding) debug options in the smb.conf file
+- Support for 'name=value' parameters in the PAM config
+- Compliant handling of unrecognized PAM parameters (i.e., fail on error)
+-
diff --git a/source3/pam_smbpass/general.h b/source3/pam_smbpass/general.h
new file mode 100644
index 0000000000..320bdd0cc8
--- /dev/null
+++ b/source3/pam_smbpass/general.h
@@ -0,0 +1,134 @@
+#ifndef LINUX
+/* This is only needed by modules in the Sun implementation. */
+#if defined(HAVE_SECURITY_PAM_APPL_H)
+#include <security/pam_appl.h>
+#elif defined(HAVE_PAM_PAM_APPL_H)
+#include <pam/pam_appl.h>
+#endif
+#endif /* LINUX */
+
+#if defined(HAVE_SECURITY_PAM_MODULES_H)
+#include <security/pam_modules.h>
+#elif defined(HAVE_PAM_PAM_MODULES_H)
+#include <pam/pam_modules.h>
+#endif
+
+#ifndef PAM_AUTHTOK_RECOVER_ERR
+#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+/*
+ * here is the string to inform the user that the new passwords they
+ * typed were not the same.
+ */
+
+#define MISTYPED_PASS "Sorry, passwords do not match"
+
+/* type definition for the control options */
+
+typedef struct {
+ const char *token;
+ unsigned int mask; /* shall assume 32 bits of flags */
+ unsigned int flag;
+} SMB_Ctrls;
+
+#ifndef False
+#define False (0)
+#endif
+
+#ifndef True
+#define True (1)
+#endif
+
+/* macro to determine if a given flag is on */
+#define on(x,ctrl) (smb_args[x].flag & ctrl)
+
+/* macro to determine that a given flag is NOT on */
+#define off(x,ctrl) (!on(x,ctrl))
+
+/* macro to turn on/off a ctrl flag manually */
+#define set(x,ctrl) (ctrl = ((ctrl)&smb_args[x].mask)|smb_args[x].flag)
+#define unset(x,ctrl) (ctrl &= ~(smb_args[x].flag))
+
+/* the generic mask */
+#define _ALL_ON_ (~0U)
+
+/* end of macro definitions definitions for the control flags */
+
+/*
+ * These are the options supported by the smb password module, very
+ * similar to the pwdb options
+ */
+
+#define SMB__OLD_PASSWD 0 /* internal */
+#define SMB__VERIFY_PASSWD 1 /* internal */
+
+#define SMB_AUDIT 2 /* print more things than debug..
+ some information may be sensitive */
+#define SMB_USE_FIRST_PASS 3
+#define SMB_TRY_FIRST_PASS 4
+#define SMB_NOT_SET_PASS 5 /* don't set the AUTHTOK items */
+
+#define SMB__NONULL 6 /* internal */
+#define SMB__QUIET 7 /* internal */
+#define SMB_USE_AUTHTOK 8 /* insist on reading PAM_AUTHTOK */
+#define SMB__NULLOK 9 /* Null token ok */
+#define SMB_DEBUG 10 /* send more info to syslog(3) */
+#define SMB_NODELAY 11 /* admin does not want a fail-delay */
+#define SMB_MIGRATE 12 /* Does no authentication, just
+ updates the smb database. */
+#define SMB_CONF_FILE 13 /* Alternate location of smb.conf */
+
+#define SMB_CTRLS_ 14 /* number of ctrl arguments defined */
+
+static const SMB_Ctrls smb_args[SMB_CTRLS_] = {
+/* symbol token name ctrl mask ctrl *
+ * ------------------ ------------------ -------------- ---------- */
+
+/* SMB__OLD_PASSWD */ { NULL, _ALL_ON_, 01 },
+/* SMB__VERIFY_PASSWD */ { NULL, _ALL_ON_, 02 },
+/* SMB_AUDIT */ { "audit", _ALL_ON_, 04 },
+/* SMB_USE_FIRST_PASS */ { "use_first_pass", _ALL_ON_^(030), 010 },
+/* SMB_TRY_FIRST_PASS */ { "try_first_pass", _ALL_ON_^(030), 020 },
+/* SMB_NOT_SET_PASS */ { "not_set_pass", _ALL_ON_, 040 },
+/* SMB__NONULL */ { "nonull", _ALL_ON_, 0100 },
+/* SMB__QUIET */ { NULL, _ALL_ON_, 0200 },
+/* SMB_USE_AUTHTOK */ { "use_authtok", _ALL_ON_, 0400 },
+/* SMB__NULLOK */ { "nullok", _ALL_ON_^(0100), 0 },
+/* SMB_DEBUG */ { "debug", _ALL_ON_, 01000 },
+/* SMB_NODELAY */ { "nodelay", _ALL_ON_, 02000 },
+/* SMB_MIGRATE */ { "migrate", _ALL_ON_^(0100), 04000 },
+/* SMB_CONF_FILE */ { "smbconf=", _ALL_ON_, 0 },
+};
+
+#define SMB_DEFAULTS (smb_args[SMB__NONULL].flag)
+
+/*
+ * the following is used to keep track of the number of times a user fails
+ * to authenticate themself.
+ */
+
+#define FAIL_PREFIX "-SMB-FAIL-"
+#define SMB_MAX_RETRIES 3
+
+struct _pam_failed_auth {
+ char *user; /* user that's failed to be authenticated */
+ uid_t id; /* uid of requested user */
+ char *agent; /* attempt from user with name */
+ int count; /* number of failures so far */
+};
+
+/*
+ * General use functions go here
+ */
+
+/* from support.c */
+int make_remark(pam_handle_t *, unsigned int, int, const char *);
diff --git a/source3/pam_smbpass/pam_smb_acct.c b/source3/pam_smbpass/pam_smb_acct.c
new file mode 100644
index 0000000000..2a8bd26597
--- /dev/null
+++ b/source3/pam_smbpass/pam_smb_acct.c
@@ -0,0 +1,144 @@
+/* Unix NT password database implementation, version 0.7.5.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* indicate the following groups are defined */
+#define PAM_SM_ACCT
+
+#include "includes.h"
+
+#ifndef LINUX
+
+/* This is only used in the Sun implementation. */
+#if defined(HAVE_SECURITY_PAM_APPL_H)
+#include <security/pam_appl.h>
+#elif defined(HAVE_PAM_PAM_APPL_H)
+#include <pam/pam_appl.h>
+#endif
+
+#endif /* LINUX */
+
+#if defined(HAVE_SECURITY_PAM_MODULES_H)
+#include <security/pam_modules.h>
+#elif defined(HAVE_PAM_PAM_MODULES_H)
+#include <pam/pam_modules.h>
+#endif
+
+#include "general.h"
+
+#include "support.h"
+
+
+/*
+ * pam_sm_acct_mgmt() verifies whether or not the account is disabled.
+ *
+ */
+
+int pam_sm_acct_mgmt( pam_handle_t *pamh, int flags,
+ int argc, const char **argv )
+{
+ unsigned int ctrl;
+ int retval;
+
+ const char *name;
+ struct samu *sampass = NULL;
+ void (*oldsig_handler)(int);
+
+ /* Samba initialization. */
+ load_case_tables();
+ setup_logging( "pam_smbpass", False );
+ lp_set_in_client(True);
+
+ ctrl = set_ctrl( flags, argc, argv );
+
+ /* get the username */
+
+ retval = pam_get_user( pamh, &name, "Username: " );
+ if (retval != PAM_SUCCESS) {
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG, "acct: could not identify user" );
+ }
+ return retval;
+ }
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG, "acct: username [%s] obtained", name );
+ }
+
+ if (geteuid() != 0) {
+ _log_err( LOG_DEBUG, "Cannot access samba password database, not running as root.");
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ /* Getting into places that might use LDAP -- protect the app
+ from a SIGPIPE it's not expecting */
+ oldsig_handler = CatchSignal(SIGPIPE, SIGNAL_CAST SIG_IGN);
+ if (!initialize_password_db(True, NULL)) {
+ _log_err( LOG_ALERT, "Cannot access samba password database" );
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ /* Get the user's record. */
+
+ if (!(sampass = samu_new( NULL ))) {
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ /* malloc fail. */
+ return nt_status_to_pam(NT_STATUS_NO_MEMORY);
+ }
+
+ if (!pdb_getsampwnam(sampass, name )) {
+ _log_err( LOG_DEBUG, "acct: could not identify user" );
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ return PAM_USER_UNKNOWN;
+ }
+
+ /* check for lookup failure */
+ if (!strlen(pdb_get_username(sampass)) ) {
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ return PAM_USER_UNKNOWN;
+ }
+
+ if (pdb_get_acct_ctrl(sampass) & ACB_DISABLED) {
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG
+ , "acct: account %s is administratively disabled", name );
+ }
+ make_remark( pamh, ctrl, PAM_ERROR_MSG
+ , "Your account has been disabled; "
+ "please see your system administrator." );
+
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ return PAM_ACCT_EXPIRED;
+ }
+
+ /* TODO: support for expired passwords. */
+
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ return PAM_SUCCESS;
+}
+
+/* static module data */
+#ifdef PAM_STATIC
+struct pam_module _pam_smbpass_acct_modstruct = {
+ "pam_smbpass",
+ NULL,
+ NULL,
+ pam_sm_acct_mgmt,
+ NULL,
+ NULL,
+ NULL
+};
+#endif
+
diff --git a/source3/pam_smbpass/pam_smb_auth.c b/source3/pam_smbpass/pam_smb_auth.c
new file mode 100644
index 0000000000..3dceb52c7d
--- /dev/null
+++ b/source3/pam_smbpass/pam_smb_auth.c
@@ -0,0 +1,256 @@
+/* Unix NT password database implementation, version 0.7.5.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* indicate the following groups are defined */
+#define PAM_SM_AUTH
+
+#include "includes.h"
+#include "debug.h"
+
+#ifndef LINUX
+
+/* This is only used in the Sun implementation. */
+#if defined(HAVE_SECURITY_PAM_APPL_H)
+#include <security/pam_appl.h>
+#elif defined(HAVE_PAM_PAM_APPL_H)
+#include <pam/pam_appl.h>
+#endif
+
+#endif /* LINUX */
+
+#if defined(HAVE_SECURITY_PAM_MODULES_H)
+#include <security/pam_modules.h>
+#elif defined(HAVE_PAM_PAM_MODULES_H)
+#include <pam/pam_modules.h>
+#endif
+
+#include "general.h"
+
+#include "support.h"
+
+#define AUTH_RETURN \
+do { \
+ /* Restore application signal handler */ \
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler); \
+ if(ret_data) { \
+ *ret_data = retval; \
+ pam_set_data( pamh, "smb_setcred_return" \
+ , (void *) ret_data, NULL ); \
+ } \
+ return retval; \
+} while (0)
+
+static int _smb_add_user(pam_handle_t *pamh, unsigned int ctrl,
+ const char *name, struct samu *sampass, bool exist);
+
+
+/*
+ * pam_sm_authenticate() authenticates users against the samba password file.
+ *
+ * First, obtain the password from the user. Then use a
+ * routine in 'support.c' to authenticate the user.
+ */
+
+#define _SMB_AUTHTOK "-SMB-PASS"
+
+int pam_sm_authenticate(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ unsigned int ctrl;
+ int retval, *ret_data = NULL;
+ struct samu *sampass = NULL;
+ const char *name;
+ void (*oldsig_handler)(int) = NULL;
+ bool found;
+
+ /* Points to memory managed by the PAM library. Do not free. */
+ char *p = NULL;
+
+ /* Samba initialization. */
+ load_case_tables();
+ setup_logging("pam_smbpass",False);
+ lp_set_in_client(True);
+
+ ctrl = set_ctrl(flags, argc, argv);
+
+ /* Get a few bytes so we can pass our return value to
+ pam_sm_setcred(). */
+ ret_data = SMB_MALLOC_P(int);
+
+ /* we need to do this before we call AUTH_RETURN */
+ /* Getting into places that might use LDAP -- protect the app
+ from a SIGPIPE it's not expecting */
+ oldsig_handler = CatchSignal(SIGPIPE, SIGNAL_CAST SIG_IGN);
+
+ /* get the username */
+ retval = pam_get_user( pamh, &name, "Username: " );
+ if ( retval != PAM_SUCCESS ) {
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err(LOG_DEBUG, "auth: could not identify user");
+ }
+ AUTH_RETURN;
+ }
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG, "username [%s] obtained", name );
+ }
+
+ if (geteuid() != 0) {
+ _log_err( LOG_DEBUG, "Cannot access samba password database, not running as root.");
+ retval = PAM_AUTHINFO_UNAVAIL;
+ AUTH_RETURN;
+ }
+
+ if (!initialize_password_db(True, NULL)) {
+ _log_err( LOG_ALERT, "Cannot access samba password database" );
+ retval = PAM_AUTHINFO_UNAVAIL;
+ AUTH_RETURN;
+ }
+
+ sampass = samu_new( NULL );
+ if (!sampass) {
+ _log_err( LOG_ALERT, "Cannot talloc a samu struct" );
+ retval = nt_status_to_pam(NT_STATUS_NO_MEMORY);
+ AUTH_RETURN;
+ }
+
+ found = pdb_getsampwnam( sampass, name );
+
+ if (on( SMB_MIGRATE, ctrl )) {
+ retval = _smb_add_user(pamh, ctrl, name, sampass, found);
+ TALLOC_FREE(sampass);
+ AUTH_RETURN;
+ }
+
+ if (!found) {
+ _log_err(LOG_ALERT, "Failed to find entry for user %s.", name);
+ retval = PAM_USER_UNKNOWN;
+ TALLOC_FREE(sampass);
+ sampass = NULL;
+ AUTH_RETURN;
+ }
+
+ /* if this user does not have a password... */
+
+ if (_smb_blankpasswd( ctrl, sampass )) {
+ TALLOC_FREE(sampass);
+ retval = PAM_SUCCESS;
+ AUTH_RETURN;
+ }
+
+ /* get this user's authentication token */
+
+ retval = _smb_read_password(pamh, ctrl, NULL, "Password: ", NULL, _SMB_AUTHTOK, &p);
+ if (retval != PAM_SUCCESS ) {
+ _log_err(LOG_CRIT, "auth: no password provided for [%s]", name);
+ TALLOC_FREE(sampass);
+ AUTH_RETURN;
+ }
+
+ /* verify the password of this user */
+
+ retval = _smb_verify_password( pamh, sampass, p, ctrl );
+ TALLOC_FREE(sampass);
+ p = NULL;
+ AUTH_RETURN;
+}
+
+/*
+ * This function is for setting samba credentials. If anyone comes up
+ * with any credentials they think should be set, let me know.
+ */
+
+int pam_sm_setcred(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ int retval, *pretval = NULL;
+
+ retval = PAM_SUCCESS;
+
+ pam_get_data(pamh, "smb_setcred_return", (const void **) &pretval);
+ if(pretval) {
+ retval = *pretval;
+ SAFE_FREE(pretval);
+ }
+ pam_set_data(pamh, "smb_setcred_return", NULL, NULL);
+
+ return retval;
+}
+
+/* Helper function for adding a user to the db. */
+static int _smb_add_user(pam_handle_t *pamh, unsigned int ctrl,
+ const char *name, struct samu *sampass, bool exist)
+{
+ char *err_str = NULL;
+ char *msg_str = NULL;
+ const char *pass = NULL;
+ int retval;
+
+ /* Get the authtok; if we don't have one, silently fail. */
+ retval = pam_get_item( pamh, PAM_AUTHTOK, (const void **) &pass );
+
+ if (retval != PAM_SUCCESS) {
+ _log_err( LOG_ALERT
+ , "pam_get_item returned error to pam_sm_authenticate" );
+ return PAM_AUTHTOK_RECOVER_ERR;
+ } else if (pass == NULL) {
+ return PAM_AUTHTOK_RECOVER_ERR;
+ }
+
+ /* Add the user to the db if they aren't already there. */
+ if (!exist) {
+ retval = NT_STATUS_IS_OK(local_password_change(name, LOCAL_ADD_USER|LOCAL_SET_PASSWORD,
+ pass, &err_str, &msg_str));
+ if (!retval && err_str) {
+ make_remark(pamh, ctrl, PAM_ERROR_MSG, err_str );
+ } else if (msg_str) {
+ make_remark(pamh, ctrl, PAM_TEXT_INFO, msg_str );
+ }
+ pass = NULL;
+
+ SAFE_FREE(err_str);
+ SAFE_FREE(msg_str);
+ return PAM_IGNORE;
+ } else {
+ /* mimick 'update encrypted' as long as the 'no pw req' flag is not set */
+ if ( pdb_get_acct_ctrl(sampass) & ~ACB_PWNOTREQ ) {
+ retval = NT_STATUS_IS_OK(local_password_change(name, LOCAL_SET_PASSWORD,
+ pass, &err_str, &msg_str));
+ if (!retval && err_str) {
+ make_remark(pamh, ctrl, PAM_ERROR_MSG, err_str );
+ } else if (msg_str) {
+ make_remark(pamh, ctrl, PAM_TEXT_INFO, msg_str );
+ }
+ }
+ }
+
+ SAFE_FREE(err_str);
+ SAFE_FREE(msg_str);
+ pass = NULL;
+ return PAM_IGNORE;
+}
+
+/* static module data */
+#ifdef PAM_STATIC
+struct pam_module _pam_smbpass_auth_modstruct = {
+ "pam_smbpass",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+#endif
diff --git a/source3/pam_smbpass/pam_smb_passwd.c b/source3/pam_smbpass/pam_smb_passwd.c
new file mode 100644
index 0000000000..b6de43ff97
--- /dev/null
+++ b/source3/pam_smbpass/pam_smb_passwd.c
@@ -0,0 +1,358 @@
+/*
+ Unix SMB/CIFS implementation.
+ Use PAM to update user passwords in the local SAM
+ Copyright (C) Steve Langasek 1998-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/* indicate the following groups are defined */
+#define PAM_SM_PASSWORD
+
+#include "includes.h"
+
+/* This is only used in the Sun implementation. FIXME: we really
+ want a define here that distinguishes between the Solaris PAM
+ and others (including FreeBSD). */
+
+#ifndef LINUX
+#if defined(HAVE_SECURITY_PAM_APPL_H)
+#include <security/pam_appl.h>
+#elif defined(HAVE_PAM_PAM_APPL_H)
+#include <pam/pam_appl.h>
+#endif
+#endif
+
+#if defined(HAVE_SECURITY_PAM_MODULES_H)
+#include <security/pam_modules.h>
+#elif defined(HAVE_PAM_PAM_MODULES_H)
+#include <pam/pam_modules.h>
+#endif
+
+#include "general.h"
+
+#include "support.h"
+
+int smb_update_db( pam_handle_t *pamh, int ctrl, const char *user, const char *pass_new )
+{
+ int retval;
+ char *err_str = NULL;
+ char *msg_str = NULL;
+
+ retval = NT_STATUS_IS_OK(local_password_change(user, LOCAL_SET_PASSWORD, pass_new,
+ &err_str,
+ &msg_str));
+
+ if (!retval) {
+ if (err_str) {
+ make_remark(pamh, ctrl, PAM_ERROR_MSG, err_str );
+ }
+
+ /* FIXME: what value is appropriate here? */
+ retval = PAM_AUTHTOK_ERR;
+ } else {
+ if (msg_str) {
+ make_remark(pamh, ctrl, PAM_TEXT_INFO, msg_str );
+ }
+ retval = PAM_SUCCESS;
+ }
+
+ SAFE_FREE(err_str);
+ SAFE_FREE(msg_str);
+ return retval;
+}
+
+
+/* data tokens */
+
+#define _SMB_OLD_AUTHTOK "-SMB-OLD-PASS"
+#define _SMB_NEW_AUTHTOK "-SMB-NEW-PASS"
+
+/*
+ * FUNCTION: pam_sm_chauthtok()
+ *
+ * This function is called twice by the PAM library, once with
+ * PAM_PRELIM_CHECK set, and then again with PAM_UPDATE_AUTHTOK set. With
+ * Linux-PAM, these two passes generally involve first checking the old
+ * token and then changing the token. This is what we do here.
+ *
+ * Having obtained a new password. The function updates the
+ * SMB_PASSWD_FILE file (normally, $(LIBDIR)/smbpasswd).
+ */
+
+int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ unsigned int ctrl;
+ int retval;
+
+ struct samu *sampass = NULL;
+ void (*oldsig_handler)(int);
+ const char *user;
+ char *pass_old;
+ char *pass_new;
+
+ /* Samba initialization. */
+ load_case_tables();
+ setup_logging( "pam_smbpass", False );
+ lp_set_in_client(True);
+
+ ctrl = set_ctrl(flags, argc, argv);
+
+ /*
+ * First get the name of a user. No need to do anything if we can't
+ * determine this.
+ */
+
+ retval = pam_get_user( pamh, &user, "Username: " );
+ if (retval != PAM_SUCCESS) {
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG, "password: could not identify user" );
+ }
+ return retval;
+ }
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG, "username [%s] obtained", user );
+ }
+
+ if (geteuid() != 0) {
+ _log_err( LOG_DEBUG, "Cannot access samba password database, not running as root.");
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ /* Getting into places that might use LDAP -- protect the app
+ from a SIGPIPE it's not expecting */
+ oldsig_handler = CatchSignal(SIGPIPE, SIGNAL_CAST SIG_IGN);
+
+ if (!initialize_password_db(False, NULL)) {
+ _log_err( LOG_ALERT, "Cannot access samba password database" );
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ /* obtain user record */
+ if ( !(sampass = samu_new( NULL )) ) {
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ return nt_status_to_pam(NT_STATUS_NO_MEMORY);
+ }
+
+ if (!pdb_getsampwnam(sampass,user)) {
+ _log_err( LOG_ALERT, "Failed to find entry for user %s.", user );
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ return PAM_USER_UNKNOWN;
+ }
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG, "Located account for %s", user );
+ }
+
+ if (flags & PAM_PRELIM_CHECK) {
+ /*
+ * obtain and verify the current password (OLDAUTHTOK) for
+ * the user.
+ */
+
+ char *Announce;
+
+ if (_smb_blankpasswd( ctrl, sampass )) {
+
+ TALLOC_FREE(sampass);
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ return PAM_SUCCESS;
+ }
+
+ /* Password change by root, or for an expired token, doesn't
+ require authentication. Is this a good choice? */
+ if (getuid() != 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK)) {
+
+ /* tell user what is happening */
+#define greeting "Changing password for "
+ Announce = SMB_MALLOC_ARRAY(char, sizeof(greeting)+strlen(user));
+ if (Announce == NULL) {
+ _log_err(LOG_CRIT, "password: out of memory");
+ TALLOC_FREE(sampass);
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ return PAM_BUF_ERR;
+ }
+ strncpy( Announce, greeting, sizeof(greeting) );
+ strncpy( Announce+sizeof(greeting)-1, user, strlen(user)+1 );
+#undef greeting
+
+ set( SMB__OLD_PASSWD, ctrl );
+ retval = _smb_read_password( pamh, ctrl, Announce, "Current SMB password: ",
+ NULL, _SMB_OLD_AUTHTOK, &pass_old );
+ SAFE_FREE( Announce );
+
+ if (retval != PAM_SUCCESS) {
+ _log_err( LOG_NOTICE
+ , "password - (old) token not obtained" );
+ TALLOC_FREE(sampass);
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ return retval;
+ }
+
+ /* verify that this is the password for this user */
+
+ retval = _smb_verify_password( pamh, sampass, pass_old, ctrl );
+
+ } else {
+ pass_old = NULL;
+ retval = PAM_SUCCESS; /* root doesn't have to */
+ }
+
+ pass_old = NULL;
+ TALLOC_FREE(sampass);
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ return retval;
+
+ } else if (flags & PAM_UPDATE_AUTHTOK) {
+
+ /*
+ * obtain the proposed password
+ */
+
+ /*
+ * get the old token back. NULL was ok only if root [at this
+ * point we assume that this has already been enforced on a
+ * previous call to this function].
+ */
+
+ if (off( SMB_NOT_SET_PASS, ctrl )) {
+ retval = pam_get_item( pamh, PAM_OLDAUTHTOK,
+ (const void **)&pass_old );
+ } else {
+ retval = pam_get_data( pamh, _SMB_OLD_AUTHTOK,
+ (const void **)&pass_old );
+ if (retval == PAM_NO_MODULE_DATA) {
+ pass_old = NULL;
+ retval = PAM_SUCCESS;
+ }
+ }
+
+ if (retval != PAM_SUCCESS) {
+ _log_err( LOG_NOTICE, "password: user not authenticated" );
+ TALLOC_FREE(sampass);
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ return retval;
+ }
+
+ /*
+ * use_authtok is to force the use of a previously entered
+ * password -- needed for pluggable password strength checking
+ * or other module stacking
+ */
+
+ if (on( SMB_USE_AUTHTOK, ctrl )) {
+ set( SMB_USE_FIRST_PASS, ctrl );
+ }
+
+ retval = _smb_read_password( pamh, ctrl
+ , NULL
+ , "Enter new SMB password: "
+ , "Retype new SMB password: "
+ , _SMB_NEW_AUTHTOK
+ , &pass_new );
+
+ if (retval != PAM_SUCCESS) {
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_ALERT
+ , "password: new password not obtained" );
+ }
+ pass_old = NULL; /* tidy up */
+ TALLOC_FREE(sampass);
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ return retval;
+ }
+
+ /*
+ * At this point we know who the user is and what they
+ * propose as their new password. Verify that the new
+ * password is acceptable.
+ */
+
+ if (pass_new[0] == '\0') { /* "\0" password = NULL */
+ pass_new = NULL;
+ }
+
+ retval = _pam_smb_approve_pass(pamh, ctrl, pass_old, pass_new);
+
+ if (retval != PAM_SUCCESS) {
+ _log_err(LOG_NOTICE, "new password not acceptable");
+ pass_new = pass_old = NULL; /* tidy up */
+ TALLOC_FREE(sampass);
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ return retval;
+ }
+
+ /*
+ * By reaching here we have approved the passwords and must now
+ * rebuild the smb password file.
+ */
+
+ /* update the password database */
+
+ retval = smb_update_db(pamh, ctrl, user, pass_new);
+ if (retval == PAM_SUCCESS) {
+ uid_t uid;
+
+ /* password updated */
+ if (!sid_to_uid(pdb_get_user_sid(sampass), &uid)) {
+ _log_err( LOG_NOTICE, "Unable to get uid for user %s",
+ pdb_get_username(sampass));
+ _log_err( LOG_NOTICE, "password for (%s) changed by (%s/%d)",
+ user, uidtoname(getuid()), getuid());
+ } else {
+ _log_err( LOG_NOTICE, "password for (%s/%d) changed by (%s/%d)",
+ user, uid, uidtoname(getuid()), getuid());
+ }
+ } else {
+ _log_err( LOG_ERR, "password change failed for user %s", user);
+ }
+
+ pass_old = pass_new = NULL;
+ if (sampass) {
+ TALLOC_FREE(sampass);
+ sampass = NULL;
+ }
+
+ } else { /* something has broken with the library */
+
+ _log_err( LOG_ALERT, "password received unknown request" );
+ retval = PAM_ABORT;
+
+ }
+
+ if (sampass) {
+ TALLOC_FREE(sampass);
+ sampass = NULL;
+ }
+
+ TALLOC_FREE(sampass);
+ CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+ return retval;
+}
+
+/* static module data */
+#ifdef PAM_STATIC
+struct pam_module _pam_smbpass_passwd_modstruct = {
+ "pam_smbpass",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ pam_sm_chauthtok
+};
+#endif
+
diff --git a/source3/pam_smbpass/samples/README b/source3/pam_smbpass/samples/README
new file mode 100644
index 0000000000..d77603306f
--- /dev/null
+++ b/source3/pam_smbpass/samples/README
@@ -0,0 +1,3 @@
+This directory contains example configurations demonstrating various uses
+of pam_smbpass. These examples use Linux-style /etc/pam.d syntax, and
+must be modified for use on Solaris systems.
diff --git a/source3/pam_smbpass/samples/kdc-pdc b/source3/pam_smbpass/samples/kdc-pdc
new file mode 100644
index 0000000000..70f1998f32
--- /dev/null
+++ b/source3/pam_smbpass/samples/kdc-pdc
@@ -0,0 +1,15 @@
+#%PAM-1.0
+# kdc-pdc
+#
+# A sample PAM configuration that shows pam_smbpass used together with
+# pam_krb5. This could be useful on a Samba PDC that is also a member of
+# a Kerberos realm.
+
+auth requisite pam_nologin.so
+auth requisite pam_krb5.so
+auth optional pam_smbpass.so migrate
+account required pam_krb5.so
+password requisite pam_cracklib.so retry=3
+password optional pam_smbpass.so nullok use_authtok try_first_pass
+password required pam_krb5.so use_authtok try_first_pass
+session required pam_krb5.so
diff --git a/source3/pam_smbpass/samples/password-mature b/source3/pam_smbpass/samples/password-mature
new file mode 100644
index 0000000000..6d73e0906f
--- /dev/null
+++ b/source3/pam_smbpass/samples/password-mature
@@ -0,0 +1,14 @@
+#%PAM-1.0
+# password-mature
+#
+# A sample PAM configuration for a 'mature' smbpasswd installation.
+# private/smbpasswd is fully populated, and we consider it an error if
+# the smbpasswd doesn't exist or doesn't match the Unix password.
+
+auth requisite pam_nologin.so
+auth required pam_unix.so
+account required pam_unix.so
+password requisite pam_cracklib.so retry=3
+password requisite pam_unix.so shadow md5 use_authtok try_first_pass
+password required pam_smbpass.so use_authtok use_first_pass
+session required pam_unix.so
diff --git a/source3/pam_smbpass/samples/password-migration b/source3/pam_smbpass/samples/password-migration
new file mode 100644
index 0000000000..305cb53858
--- /dev/null
+++ b/source3/pam_smbpass/samples/password-migration
@@ -0,0 +1,18 @@
+#%PAM-1.0
+# password-migration
+#
+# A sample PAM configuration that shows the use of pam_smbpass to migrate
+# from plaintext to encrypted passwords for Samba. Unlike other methods,
+# this can be used for users who have never connected to Samba shares:
+# password migration takes place when users ftp in, login using ssh, pop
+# their mail, etc.
+
+auth requisite pam_nologin.so
+# pam_smbpass is called IFF pam_unix succeeds.
+auth requisite pam_unix.so
+auth optional pam_smbpass.so migrate
+account required pam_unix.so
+password requisite pam_cracklib.so retry=3
+password requisite pam_unix.so shadow md5 use_authtok try_first_pass
+password optional pam_smbpass.so nullok use_authtok try_first_pass
+session required pam_unix.so
diff --git a/source3/pam_smbpass/samples/password-sync b/source3/pam_smbpass/samples/password-sync
new file mode 100644
index 0000000000..0a950dd2e9
--- /dev/null
+++ b/source3/pam_smbpass/samples/password-sync
@@ -0,0 +1,15 @@
+#%PAM-1.0
+# password-sync
+#
+# A sample PAM configuration that shows the use of pam_smbpass to make
+# sure private/smbpasswd is kept in sync when /etc/passwd (/etc/shadow)
+# is changed. Useful when an expired password might be changed by an
+# application (such as ssh).
+
+auth requisite pam_nologin.so
+auth required pam_unix.so
+account required pam_unix.so
+password requisite pam_cracklib.so retry=3
+password requisite pam_unix.so shadow md5 use_authtok try_first_pass
+password required pam_smbpass.so nullok use_authtok try_first_pass
+session required pam_unix.so
diff --git a/source3/pam_smbpass/support.c b/source3/pam_smbpass/support.c
new file mode 100644
index 0000000000..8f537c4d8d
--- /dev/null
+++ b/source3/pam_smbpass/support.c
@@ -0,0 +1,632 @@
+/* Unix NT password database implementation, version 0.6.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "general.h"
+
+#include "support.h"
+
+
+#define _pam_overwrite(x) \
+do { \
+ register char *__xx__; \
+ if ((__xx__=(x))) \
+ while (*__xx__) \
+ *__xx__++ = '\0'; \
+} while (0)
+
+/*
+ * Don't just free it, forget it too.
+ */
+
+#define _pam_drop(X) \
+do { \
+ if (X) { \
+ free(X); \
+ X=NULL; \
+ } \
+} while (0)
+
+#define _pam_drop_reply(/* struct pam_response * */ reply, /* int */ replies) \
+do { \
+ int reply_i; \
+ \
+ for (reply_i=0; reply_i<replies; ++reply_i) { \
+ if (reply[reply_i].resp) { \
+ _pam_overwrite(reply[reply_i].resp); \
+ free(reply[reply_i].resp); \
+ } \
+ } \
+ if (reply) \
+ free(reply); \
+} while (0)
+
+
+int converse(pam_handle_t *, int, int, struct pam_message **,
+ struct pam_response **);
+int make_remark(pam_handle_t *, unsigned int, int, const char *);
+void _cleanup(pam_handle_t *, void *, int);
+char *_pam_delete(register char *);
+
+/* syslogging function for errors and other information */
+
+void _log_err( int err, const char *format, ... )
+{
+ va_list args;
+
+ va_start( args, format );
+ openlog( "PAM_smbpass", LOG_CONS | LOG_PID, LOG_AUTH );
+ vsyslog( err, format, args );
+ va_end( args );
+ closelog();
+}
+
+/* this is a front-end for module-application conversations */
+
+int converse( pam_handle_t * pamh, int ctrl, int nargs
+ , struct pam_message **message
+ , struct pam_response **response )
+{
+ int retval;
+ struct pam_conv *conv;
+
+ retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv);
+ if (retval == PAM_SUCCESS) {
+
+ retval = conv->conv(nargs, (const struct pam_message **) message
+ ,response, conv->appdata_ptr);
+
+ if (retval != PAM_SUCCESS && on(SMB_DEBUG, ctrl)) {
+ _log_err(LOG_DEBUG, "conversation failure [%s]"
+ ,pam_strerror(pamh, retval));
+ }
+ } else {
+ _log_err(LOG_ERR, "couldn't obtain coversation function [%s]"
+ ,pam_strerror(pamh, retval));
+ }
+
+ return retval; /* propagate error status */
+}
+
+int make_remark( pam_handle_t * pamh, unsigned int ctrl
+ , int type, const char *text )
+{
+ if (off(SMB__QUIET, ctrl)) {
+ struct pam_message *pmsg[1], msg[1];
+ struct pam_response *resp;
+
+ pmsg[0] = &msg[0];
+ msg[0].msg = CONST_DISCARD(char *, text);
+ msg[0].msg_style = type;
+ resp = NULL;
+
+ return converse(pamh, ctrl, 1, pmsg, &resp);
+ }
+ return PAM_SUCCESS;
+}
+
+
+/* set the control flags for the SMB module. */
+
+int set_ctrl( int flags, int argc, const char **argv )
+{
+ int i = 0;
+ const char *service_file = NULL;
+ unsigned int ctrl;
+
+ ctrl = SMB_DEFAULTS; /* the default selection of options */
+
+ /* set some flags manually */
+
+ /* A good, sane default (matches Samba's behavior). */
+ set( SMB__NONULL, ctrl );
+
+ /* initialize service file location */
+ service_file=get_dyn_CONFIGFILE();
+
+ if (flags & PAM_SILENT) {
+ set( SMB__QUIET, ctrl );
+ }
+
+ /* Run through the arguments once, looking for an alternate smb config
+ file location */
+ while (i < argc) {
+ int j;
+
+ for (j = 0; j < SMB_CTRLS_; ++j) {
+ if (smb_args[j].token
+ && !strncmp(argv[i], smb_args[j].token, strlen(smb_args[j].token)))
+ {
+ break;
+ }
+ }
+
+ if (j == SMB_CONF_FILE) {
+ service_file = argv[i] + 8;
+ }
+ i++;
+ }
+
+ /* Read some options from the Samba config. Can be overridden by
+ the PAM config. */
+ if(lp_load(service_file,True,False,False,True) == False) {
+ _log_err( LOG_ERR, "Error loading service file %s", service_file );
+ }
+
+ secrets_init();
+
+ if (lp_null_passwords()) {
+ set( SMB__NULLOK, ctrl );
+ }
+
+ /* now parse the rest of the arguments to this module */
+
+ while (argc-- > 0) {
+ int j;
+
+ for (j = 0; j < SMB_CTRLS_; ++j) {
+ if (smb_args[j].token
+ && !strncmp(*argv, smb_args[j].token, strlen(smb_args[j].token)))
+ {
+ break;
+ }
+ }
+
+ if (j >= SMB_CTRLS_) {
+ _log_err( LOG_ERR, "unrecognized option [%s]", *argv );
+ } else {
+ ctrl &= smb_args[j].mask; /* for turning things off */
+ ctrl |= smb_args[j].flag; /* for turning things on */
+ }
+
+ ++argv; /* step to next argument */
+ }
+
+ /* auditing is a more sensitive version of debug */
+
+ if (on( SMB_AUDIT, ctrl )) {
+ set( SMB_DEBUG, ctrl );
+ }
+ /* return the set of flags */
+
+ return ctrl;
+}
+
+/* use this to free strings. ESPECIALLY password strings */
+
+char * _pam_delete( register char *xx )
+{
+ _pam_overwrite( xx );
+ _pam_drop( xx );
+ return NULL;
+}
+
+void _cleanup( pam_handle_t * pamh, void *x, int error_status )
+{
+ x = _pam_delete( (char *) x );
+}
+
+/* JHT
+ *
+ * Safe duplication of character strings. "Paranoid"; don't leave
+ * evidence of old token around for later stack analysis.
+ *
+ */
+char * smbpXstrDup( const char *x )
+{
+ register char *newstr = NULL;
+
+ if (x != NULL) {
+ register int i;
+
+ for (i = 0; x[i]; ++i); /* length of string */
+ if ((newstr = SMB_MALLOC_ARRAY(char, ++i)) == NULL) {
+ i = 0;
+ _log_err( LOG_CRIT, "out of memory in smbpXstrDup" );
+ } else {
+ while (i-- > 0) {
+ newstr[i] = x[i];
+ }
+ }
+ x = NULL;
+ }
+ return newstr; /* return the duplicate or NULL on error */
+}
+
+/* ************************************************************** *
+ * Useful non-trivial functions *
+ * ************************************************************** */
+
+void _cleanup_failures( pam_handle_t * pamh, void *fl, int err )
+{
+ int quiet;
+ const char *service = NULL;
+ struct _pam_failed_auth *failure;
+
+#ifdef PAM_DATA_SILENT
+ quiet = err & PAM_DATA_SILENT; /* should we log something? */
+#else
+ quiet = 0;
+#endif
+#ifdef PAM_DATA_REPLACE
+ err &= PAM_DATA_REPLACE; /* are we just replacing data? */
+#endif
+ failure = (struct _pam_failed_auth *) fl;
+
+ if (failure != NULL) {
+
+#ifdef PAM_DATA_SILENT
+ if (!quiet && !err) { /* under advisement from Sun,may go away */
+#else
+ if (!quiet) { /* under advisement from Sun,may go away */
+#endif
+
+ /* log the number of authentication failures */
+ if (failure->count != 0) {
+ pam_get_item( pamh, PAM_SERVICE, (const void **) &service );
+ _log_err( LOG_NOTICE
+ , "%d authentication %s "
+ "from %s for service %s as %s(%d)"
+ , failure->count
+ , failure->count == 1 ? "failure" : "failures"
+ , failure->agent
+ , service == NULL ? "**unknown**" : service
+ , failure->user, failure->id );
+ if (failure->count > SMB_MAX_RETRIES) {
+ _log_err( LOG_ALERT
+ , "service(%s) ignoring max retries; %d > %d"
+ , service == NULL ? "**unknown**" : service
+ , failure->count
+ , SMB_MAX_RETRIES );
+ }
+ }
+ }
+ _pam_delete( failure->agent ); /* tidy up */
+ _pam_delete( failure->user ); /* tidy up */
+ SAFE_FREE( failure );
+ }
+}
+
+int _smb_verify_password( pam_handle_t * pamh, struct samu *sampass,
+ const char *p, unsigned int ctrl )
+{
+ uchar lm_pw[16];
+ uchar nt_pw[16];
+ int retval = PAM_AUTH_ERR;
+ char *data_name;
+ const char *name;
+
+ if (!sampass)
+ return PAM_ABORT;
+
+ name = pdb_get_username(sampass);
+
+#ifdef HAVE_PAM_FAIL_DELAY
+ if (off( SMB_NODELAY, ctrl )) {
+ (void) pam_fail_delay( pamh, 1000000 ); /* 1 sec delay for on failure */
+ }
+#endif
+
+ if (!pdb_get_nt_passwd(sampass))
+ {
+ _log_err( LOG_DEBUG, "user %s has null SMB password"
+ , name );
+
+ if (off( SMB__NONULL, ctrl )
+ && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ))
+ { /* this means we've succeeded */
+ return PAM_SUCCESS;
+ } else {
+ const char *service;
+
+ pam_get_item( pamh, PAM_SERVICE, (const void **)&service );
+ _log_err( LOG_NOTICE, "failed auth request by %s for service %s as %s",
+ uidtoname(getuid()), service ? service : "**unknown**", name);
+ return PAM_AUTH_ERR;
+ }
+ }
+
+ data_name = SMB_MALLOC_ARRAY(char, sizeof(FAIL_PREFIX) + strlen( name ));
+ if (data_name == NULL) {
+ _log_err( LOG_CRIT, "no memory for data-name" );
+ return PAM_AUTH_ERR;
+ }
+ strncpy( data_name, FAIL_PREFIX, sizeof(FAIL_PREFIX) );
+ strncpy( data_name + sizeof(FAIL_PREFIX) - 1, name, strlen( name ) + 1 );
+
+ /*
+ * The password we were given wasn't an encrypted password, or it
+ * didn't match the one we have. We encrypt the password now and try
+ * again.
+ */
+
+ nt_lm_owf_gen(p, nt_pw, lm_pw);
+
+ /* the moment of truth -- do we agree with the password? */
+
+ if (!memcmp( nt_pw, pdb_get_nt_passwd(sampass), 16 )) {
+
+ retval = PAM_SUCCESS;
+ if (data_name) { /* reset failures */
+ pam_set_data(pamh, data_name, NULL, _cleanup_failures);
+ }
+ } else {
+
+ const char *service;
+
+ pam_get_item( pamh, PAM_SERVICE, (const void **)&service );
+
+ if (data_name != NULL) {
+ struct _pam_failed_auth *newauth = NULL;
+ const struct _pam_failed_auth *old = NULL;
+
+ /* get a failure recorder */
+
+ newauth = SMB_MALLOC_P( struct _pam_failed_auth );
+
+ if (newauth != NULL) {
+
+ /* any previous failures for this user ? */
+ pam_get_data(pamh, data_name, (const void **) &old);
+
+ if (old != NULL) {
+ newauth->count = old->count + 1;
+ if (newauth->count >= SMB_MAX_RETRIES) {
+ retval = PAM_MAXTRIES;
+ }
+ } else {
+ _log_err(LOG_NOTICE,
+ "failed auth request by %s for service %s as %s",
+ uidtoname(getuid()),
+ service ? service : "**unknown**", name);
+ newauth->count = 1;
+ }
+ if (!sid_to_uid(pdb_get_user_sid(sampass), &(newauth->id))) {
+ _log_err(LOG_NOTICE,
+ "failed auth request by %s for service %s as %s",
+ uidtoname(getuid()),
+ service ? service : "**unknown**", name);
+ }
+ newauth->user = smbpXstrDup( name );
+ newauth->agent = smbpXstrDup( uidtoname( getuid() ) );
+ pam_set_data( pamh, data_name, newauth, _cleanup_failures );
+
+ } else {
+ _log_err( LOG_CRIT, "no memory for failure recorder" );
+ _log_err(LOG_NOTICE,
+ "failed auth request by %s for service %s as %s(%d)",
+ uidtoname(getuid()),
+ service ? service : "**unknown**", name);
+ }
+ }
+ _log_err(LOG_NOTICE,
+ "failed auth request by %s for service %s as %s(%d)",
+ uidtoname(getuid()),
+ service ? service : "**unknown**", name);
+ retval = PAM_AUTH_ERR;
+ }
+
+ _pam_delete( data_name );
+
+ return retval;
+}
+
+
+/*
+ * _smb_blankpasswd() is a quick check for a blank password
+ *
+ * returns TRUE if user does not have a password
+ * - to avoid prompting for one in such cases (CG)
+ */
+
+int _smb_blankpasswd( unsigned int ctrl, struct samu *sampass )
+{
+ int retval;
+
+ /*
+ * This function does not have to be too smart if something goes
+ * wrong, return FALSE and let this case to be treated somewhere
+ * else (CG)
+ */
+
+ if (on( SMB__NONULL, ctrl ))
+ return 0; /* will fail but don't let on yet */
+
+ if (!(pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ))
+ return 0;
+
+ if (pdb_get_nt_passwd(sampass) == NULL)
+ retval = 1;
+ else
+ retval = 0;
+
+ return retval;
+}
+
+/*
+ * obtain a password from the user
+ */
+
+int _smb_read_password( pam_handle_t * pamh, unsigned int ctrl,
+ const char *comment, const char *prompt1,
+ const char *prompt2, const char *data_name, char **pass )
+{
+ int authtok_flag;
+ int retval;
+ char *item = NULL;
+ char *token;
+
+ struct pam_message msg[3], *pmsg[3];
+ struct pam_response *resp;
+ int i, expect;
+
+
+ /* make sure nothing inappropriate gets returned */
+
+ *pass = token = NULL;
+
+ /* which authentication token are we getting? */
+
+ authtok_flag = on(SMB__OLD_PASSWD, ctrl) ? PAM_OLDAUTHTOK : PAM_AUTHTOK;
+
+ /* should we obtain the password from a PAM item ? */
+
+ if (on(SMB_TRY_FIRST_PASS, ctrl) || on(SMB_USE_FIRST_PASS, ctrl)) {
+ retval = pam_get_item( pamh, authtok_flag, (const void **) &item );
+ if (retval != PAM_SUCCESS) {
+ /* very strange. */
+ _log_err( LOG_ALERT
+ , "pam_get_item returned error to smb_read_password" );
+ return retval;
+ } else if (item != NULL) { /* we have a password! */
+ *pass = item;
+ item = NULL;
+ return PAM_SUCCESS;
+ } else if (on( SMB_USE_FIRST_PASS, ctrl )) {
+ return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */
+ } else if (on( SMB_USE_AUTHTOK, ctrl )
+ && off( SMB__OLD_PASSWD, ctrl ))
+ {
+ return PAM_AUTHTOK_RECOVER_ERR;
+ }
+ }
+
+ /*
+ * getting here implies we will have to get the password from the
+ * user directly.
+ */
+
+ /* prepare to converse */
+ if (comment != NULL && off(SMB__QUIET, ctrl)) {
+ pmsg[0] = &msg[0];
+ msg[0].msg_style = PAM_TEXT_INFO;
+ msg[0].msg = CONST_DISCARD(char *, comment);
+ i = 1;
+ } else {
+ i = 0;
+ }
+
+ pmsg[i] = &msg[i];
+ msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[i++].msg = CONST_DISCARD(char *, prompt1);
+
+ if (prompt2 != NULL) {
+ pmsg[i] = &msg[i];
+ msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[i++].msg = CONST_DISCARD(char *, prompt2);
+ expect = 2;
+ } else
+ expect = 1;
+
+ resp = NULL;
+
+ retval = converse( pamh, ctrl, i, pmsg, &resp );
+
+ if (resp != NULL) {
+ int j = comment ? 1 : 0;
+ /* interpret the response */
+
+ if (retval == PAM_SUCCESS) { /* a good conversation */
+
+ token = smbpXstrDup(resp[j++].resp);
+ if (token != NULL) {
+ if (expect == 2) {
+ /* verify that password entered correctly */
+ if (!resp[j].resp || strcmp( token, resp[j].resp )) {
+ _pam_delete( token );
+ retval = PAM_AUTHTOK_RECOVER_ERR;
+ make_remark( pamh, ctrl, PAM_ERROR_MSG
+ , MISTYPED_PASS );
+ }
+ }
+ } else {
+ _log_err(LOG_NOTICE, "could not recover authentication token");
+ }
+ }
+
+ /* tidy up */
+ _pam_drop_reply( resp, expect );
+
+ } else {
+ retval = (retval == PAM_SUCCESS) ? PAM_AUTHTOK_RECOVER_ERR : retval;
+ }
+
+ if (retval != PAM_SUCCESS) {
+ if (on( SMB_DEBUG, ctrl ))
+ _log_err( LOG_DEBUG, "unable to obtain a password" );
+ return retval;
+ }
+ /* 'token' is the entered password */
+
+ if (off( SMB_NOT_SET_PASS, ctrl )) {
+
+ /* we store this password as an item */
+
+ retval = pam_set_item( pamh, authtok_flag, (const void *)token );
+ _pam_delete( token ); /* clean it up */
+ if (retval != PAM_SUCCESS
+ || (retval = pam_get_item( pamh, authtok_flag
+ ,(const void **)&item )) != PAM_SUCCESS)
+ {
+ _log_err( LOG_CRIT, "error manipulating password" );
+ return retval;
+ }
+ } else {
+ /*
+ * then store it as data specific to this module. pam_end()
+ * will arrange to clean it up.
+ */
+
+ retval = pam_set_data( pamh, data_name, (void *) token, _cleanup );
+ if (retval != PAM_SUCCESS
+ || (retval = pam_get_data( pamh, data_name, (const void **)&item ))
+ != PAM_SUCCESS)
+ {
+ _log_err( LOG_CRIT, "error manipulating password data [%s]"
+ , pam_strerror( pamh, retval ));
+ _pam_delete( token );
+ item = NULL;
+ return retval;
+ }
+ token = NULL; /* break link to password */
+ }
+
+ *pass = item;
+ item = NULL; /* break link to password */
+
+ return PAM_SUCCESS;
+}
+
+int _pam_smb_approve_pass(pam_handle_t * pamh,
+ unsigned int ctrl,
+ const char *pass_old,
+ const char *pass_new )
+{
+
+ /* Further checks should be handled through module stacking. -SRL */
+ if (pass_new == NULL || (pass_old && !strcmp( pass_old, pass_new )))
+ {
+ if (on(SMB_DEBUG, ctrl)) {
+ _log_err( LOG_DEBUG,
+ "passwd: bad authentication token (null or unchanged)" );
+ }
+ make_remark( pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ?
+ "No password supplied" : "Password unchanged" );
+ return PAM_AUTHTOK_ERR;
+ }
+
+ return PAM_SUCCESS;
+}
diff --git a/source3/pam_smbpass/support.h b/source3/pam_smbpass/support.h
new file mode 100644
index 0000000000..5ac48c3afa
--- /dev/null
+++ b/source3/pam_smbpass/support.h
@@ -0,0 +1,50 @@
+/* syslogging function for errors and other information */
+extern void _log_err(int, const char *, ...);
+
+/* set the control flags for the UNIX module. */
+extern int set_ctrl(int, int, const char **);
+
+/* generic function for freeing pam data segments */
+extern void _cleanup(pam_handle_t *, void *, int);
+
+/*
+ * Safe duplication of character strings. "Paranoid"; don't leave
+ * evidence of old token around for later stack analysis.
+ */
+
+extern char *smbpXstrDup(const char *);
+
+/* ************************************************************** *
+ * Useful non-trivial functions *
+ * ************************************************************** */
+
+extern void _cleanup_failures(pam_handle_t *, void *, int);
+
+/* compare 2 strings */
+extern bool strequal(const char *, const char *);
+
+extern struct smb_passwd *
+_my_get_smbpwnam(FILE *, const char *, bool *, bool *, long *);
+
+extern int _smb_verify_password( pam_handle_t *pamh , struct samu *sampass,
+ const char *p, unsigned int ctrl );
+
+/*
+ * this function obtains the name of the current user and ensures
+ * that the PAM_USER item is set to this value
+ */
+
+extern int _smb_get_user(pam_handle_t *, unsigned int,
+ const char *, const char **);
+
+/* _smb_blankpasswd() is a quick check for a blank password */
+
+extern int _smb_blankpasswd(unsigned int, struct samu *);
+
+
+/* obtain a password from the user */
+extern int _smb_read_password( pam_handle_t *, unsigned int, const char*,
+ const char *, const char *, const char *, char **);
+
+extern int _pam_smb_approve_pass(pam_handle_t *, unsigned int, const char *,
+ const char *);
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
new file mode 100644
index 0000000000..60a1fa4858
--- /dev/null
+++ b/source3/param/loadparm.c
@@ -0,0 +1,9498 @@
+/*
+ Unix SMB/CIFS implementation.
+ Parameter loading functions
+ Copyright (C) Karl Auer 1993-1998
+
+ Largely re-written by Andrew Tridgell, September 1994
+
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Alexander Bokovoy 2002
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+ Copyright (C) Michael Adam 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Load parameters.
+ *
+ * This module provides suitable callback functions for the params
+ * module. It builds the internal table of service details which is
+ * then used by the rest of the server.
+ *
+ * To add a parameter:
+ *
+ * 1) add it to the global or service structure definition
+ * 2) add it to the parm_table
+ * 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
+ * 4) If it's a global then initialise it in init_globals. If a local
+ * (ie. service) parameter then initialise it in the sDefault structure
+ *
+ *
+ * Notes:
+ * The configuration file is processed sequentially for speed. It is NOT
+ * accessed randomly as happens in 'real' Windows. For this reason, there
+ * is a fair bit of sequence-dependent code here - ie., code which assumes
+ * that certain things happen before others. In particular, the code which
+ * happens at the boundary between sections is delicately poised, so be
+ * careful!
+ *
+ */
+
+#include "includes.h"
+
+bool bLoaded = False;
+
+extern enum protocol_types Protocol;
+extern userdom_struct current_user_info;
+
+#ifndef GLOBAL_NAME
+#define GLOBAL_NAME "global"
+#endif
+
+#ifndef PRINTERS_NAME
+#define PRINTERS_NAME "printers"
+#endif
+
+#ifndef HOMES_NAME
+#define HOMES_NAME "homes"
+#endif
+
+/* the special value for the include parameter
+ * to be interpreted not as a file name but to
+ * trigger loading of the global smb.conf options
+ * from registry. */
+#ifndef INCLUDE_REGISTRY_NAME
+#define INCLUDE_REGISTRY_NAME "registry"
+#endif
+
+static bool in_client = False; /* Not in the client by default */
+static struct smbconf_csn conf_last_csn;
+
+#define CONFIG_BACKEND_FILE 0
+#define CONFIG_BACKEND_REGISTRY 1
+
+static int config_backend = CONFIG_BACKEND_FILE;
+
+/* some helpful bits */
+#define LP_SNUM_OK(i) (((i) >= 0) && ((i) < iNumServices) && (ServicePtrs != NULL) && ServicePtrs[(i)]->valid)
+#define VALID(i) (ServicePtrs != NULL && ServicePtrs[i]->valid)
+
+#define USERSHARE_VALID 1
+#define USERSHARE_PENDING_DELETE 2
+
+extern int extra_time_offset;
+
+static bool defaults_saved = False;
+
+struct param_opt_struct {
+ struct param_opt_struct *prev, *next;
+ char *key;
+ char *value;
+ char **list;
+};
+
+/*
+ * This structure describes global (ie., server-wide) parameters.
+ */
+struct global {
+ int ConfigBackend;
+ char *smb_ports;
+ char *dos_charset;
+ char *unix_charset;
+ char *display_charset;
+ char *szPrintcapname;
+ char *szAddPortCommand;
+ char *szEnumPortsCommand;
+ char *szAddPrinterCommand;
+ char *szDeletePrinterCommand;
+ char *szOs2DriverMap;
+ char *szLockDir;
+ char *szPidDir;
+ char *szRootdir;
+ char *szDefaultService;
+ char *szGetQuota;
+ char *szSetQuota;
+ char *szMsgCommand;
+ char *szServerString;
+ char *szAutoServices;
+ char *szPasswdProgram;
+ char *szPasswdChat;
+ char *szLogFile;
+ char *szConfigFile;
+ char *szSMBPasswdFile;
+ char *szPrivateDir;
+ char *szPassdbBackend;
+ char **szPreloadModules;
+ char *szPasswordServer;
+ char *szSocketOptions;
+ char *szRealm;
+ char *szAfsUsernameMap;
+ int iAfsTokenLifetime;
+ char *szLogNtTokenCommand;
+ char *szUsernameMap;
+ char *szLogonScript;
+ char *szLogonPath;
+ char *szLogonDrive;
+ char *szLogonHome;
+ char **szWINSservers;
+ char **szInterfaces;
+ char *szRemoteAnnounce;
+ char *szRemoteBrowseSync;
+ char *szSocketAddress;
+ char *szNISHomeMapName;
+ char *szAnnounceVersion; /* This is initialised in init_globals */
+ char *szWorkgroup;
+ char *szNetbiosName;
+ char **szNetbiosAliases;
+ char *szNetbiosScope;
+ char *szNameResolveOrder;
+ char *szPanicAction;
+ char *szAddUserScript;
+ char *szRenameUserScript;
+ char *szDelUserScript;
+ char *szAddGroupScript;
+ char *szDelGroupScript;
+ char *szAddUserToGroupScript;
+ char *szDelUserFromGroupScript;
+ char *szSetPrimaryGroupScript;
+ char *szAddMachineScript;
+ char *szShutdownScript;
+ char *szAbortShutdownScript;
+ char *szUsernameMapScript;
+ char *szCheckPasswordScript;
+ char *szWINSHook;
+ char *szUtmpDir;
+ char *szWtmpDir;
+ bool bUtmp;
+ char *szIdmapUID;
+ char *szIdmapGID;
+ bool bPassdbExpandExplicit;
+ int AlgorithmicRidBase;
+ char *szTemplateHomedir;
+ char *szTemplateShell;
+ char *szWinbindSeparator;
+ bool bWinbindEnumUsers;
+ bool bWinbindEnumGroups;
+ bool bWinbindUseDefaultDomain;
+ bool bWinbindTrustedDomainsOnly;
+ bool bWinbindNestedGroups;
+ int winbind_expand_groups;
+ bool bWinbindRefreshTickets;
+ bool bWinbindOfflineLogon;
+ bool bWinbindNormalizeNames;
+ bool bWinbindRpcOnly;
+ char *szIdmapBackend;
+ char *szIdmapAllocBackend;
+ char *szAddShareCommand;
+ char *szChangeShareCommand;
+ char *szDeleteShareCommand;
+ char **szEventLogs;
+ char *szGuestaccount;
+ char *szManglingMethod;
+ char **szServicesList;
+ char *szUsersharePath;
+ char *szUsershareTemplateShare;
+ char **szUsersharePrefixAllowList;
+ char **szUsersharePrefixDenyList;
+ int mangle_prefix;
+ int max_log_size;
+ char *szLogLevel;
+ int max_xmit;
+ int max_mux;
+ int max_open_files;
+ int open_files_db_hash_size;
+ int pwordlevel;
+ int unamelevel;
+ int deadtime;
+ bool getwd_cache;
+ int maxprotocol;
+ int minprotocol;
+ int security;
+ char **AuthMethods;
+ bool paranoid_server_security;
+ int maxdisksize;
+ int lpqcachetime;
+ int iMaxSmbdProcesses;
+ bool bDisableSpoolss;
+ int syslog;
+ int os_level;
+ bool enhanced_browsing;
+ int max_ttl;
+ int max_wins_ttl;
+ int min_wins_ttl;
+ int lm_announce;
+ int lm_interval;
+ int announce_as; /* This is initialised in init_globals */
+ int machine_password_timeout;
+ int map_to_guest;
+ int oplock_break_wait_time;
+ int winbind_cache_time;
+ int winbind_reconnect_delay;
+ int winbind_max_idle_children;
+ char **szWinbindNssInfo;
+ int iLockSpinTime;
+ char *szLdapMachineSuffix;
+ char *szLdapUserSuffix;
+ char *szLdapIdmapSuffix;
+ char *szLdapGroupSuffix;
+ int ldap_ssl;
+ char *szLdapSuffix;
+ char *szLdapAdminDn;
+ int ldap_debug_level;
+ int ldap_debug_threshold;
+ int iAclCompat;
+ char *szCupsServer;
+ char *szIPrintServer;
+ char *ctdbdSocket;
+ char **szClusterAddresses;
+ bool clustering;
+ int ldap_passwd_sync;
+ int ldap_replication_sleep;
+ int ldap_timeout; /* This is initialised in init_globals */
+ int ldap_connection_timeout;
+ int ldap_page_size;
+ bool ldap_delete_dn;
+ bool bMsAddPrinterWizard;
+ bool bDNSproxy;
+ bool bWINSsupport;
+ bool bWINSproxy;
+ bool bLocalMaster;
+ int iPreferredMaster;
+ int iDomainMaster;
+ bool bDomainLogons;
+ char **szInitLogonDelayedHosts;
+ int InitLogonDelay;
+ bool bEncryptPasswords;
+ bool bUpdateEncrypt;
+ int clientSchannel;
+ int serverSchannel;
+ bool bNullPasswords;
+ bool bObeyPamRestrictions;
+ bool bLoadPrinters;
+ int PrintcapCacheTime;
+ bool bLargeReadwrite;
+ bool bReadRaw;
+ bool bWriteRaw;
+ bool bSyslogOnly;
+ bool bBrowseList;
+ bool bNISHomeMap;
+ bool bTimeServer;
+ bool bBindInterfacesOnly;
+ bool bPamPasswordChange;
+ bool bUnixPasswdSync;
+ bool bPasswdChatDebug;
+ int iPasswdChatTimeout;
+ bool bTimestampLogs;
+ bool bNTSmbSupport;
+ bool bNTPipeSupport;
+ bool bNTStatusSupport;
+ bool bStatCache;
+ int iMaxStatCacheSize;
+ bool bKernelOplocks;
+ bool bAllowTrustedDomains;
+ bool bLanmanAuth;
+ bool bNTLMAuth;
+ bool bUseSpnego;
+ bool bClientLanManAuth;
+ bool bClientNTLMv2Auth;
+ bool bClientPlaintextAuth;
+ bool bClientUseSpnego;
+ bool bDebugPrefixTimestamp;
+ bool bDebugHiresTimestamp;
+ bool bDebugPid;
+ bool bDebugUid;
+ bool bDebugClass;
+ bool bEnableCoreFiles;
+ bool bHostMSDfs;
+ bool bUseMmap;
+ bool bHostnameLookups;
+ bool bUnixExtensions;
+ bool bDisableNetbios;
+ bool bUseKerberosKeytab;
+ bool bDeferSharingViolations;
+ bool bEnablePrivileges;
+ bool bASUSupport;
+ bool bUsershareOwnerOnly;
+ bool bUsershareAllowGuests;
+ bool bRegistryShares;
+ int restrict_anonymous;
+ int name_cache_timeout;
+ int client_signing;
+ int server_signing;
+ int client_ldap_sasl_wrapping;
+ int iUsershareMaxShares;
+ int iIdmapCacheTime;
+ int iIdmapNegativeCacheTime;
+ bool bResetOnZeroVC;
+ int iKeepalive;
+ int iminreceivefile;
+ struct param_opt_struct *param_opt;
+};
+
+static struct global Globals;
+
+/*
+ * This structure describes a single service.
+ */
+struct service {
+ bool valid;
+ bool autoloaded;
+ int usershare;
+ time_t usershare_last_mod;
+ char *szService;
+ char *szPath;
+ char *szUsername;
+ char **szInvalidUsers;
+ char **szValidUsers;
+ char **szAdminUsers;
+ char *szCopy;
+ char *szInclude;
+ char *szPreExec;
+ char *szPostExec;
+ char *szRootPreExec;
+ char *szRootPostExec;
+ char *szCupsOptions;
+ char *szPrintcommand;
+ char *szLpqcommand;
+ char *szLprmcommand;
+ char *szLppausecommand;
+ char *szLpresumecommand;
+ char *szQueuepausecommand;
+ char *szQueueresumecommand;
+ char *szPrintername;
+ char *szPrintjobUsername;
+ char *szDontdescend;
+ char **szHostsallow;
+ char **szHostsdeny;
+ char *szMagicScript;
+ char *szMagicOutput;
+ char *szVetoFiles;
+ char *szHideFiles;
+ char *szVetoOplockFiles;
+ char *comment;
+ char *force_user;
+ char *force_group;
+ char **readlist;
+ char **writelist;
+ char **printer_admin;
+ char *volume;
+ char *fstype;
+ char **szVfsObjects;
+ char *szMSDfsProxy;
+ char *szAioWriteBehind;
+ char *szDfree;
+ int iMinPrintSpace;
+ int iMaxPrintJobs;
+ int iMaxReportedPrintJobs;
+ int iWriteCacheSize;
+ int iCreate_mask;
+ int iCreate_force_mode;
+ int iSecurity_mask;
+ int iSecurity_force_mode;
+ int iDir_mask;
+ int iDir_force_mode;
+ int iDir_Security_mask;
+ int iDir_Security_force_mode;
+ int iMaxConnections;
+ int iDefaultCase;
+ int iPrinting;
+ int iOplockContentionLimit;
+ int iCSCPolicy;
+ int iBlock_size;
+ int iDfreeCacheTime;
+ bool bPreexecClose;
+ bool bRootpreexecClose;
+ int iCaseSensitive;
+ bool bCasePreserve;
+ bool bShortCasePreserve;
+ bool bHideDotFiles;
+ bool bHideSpecialFiles;
+ bool bHideUnReadable;
+ bool bHideUnWriteableFiles;
+ bool bBrowseable;
+ bool bAvailable;
+ bool bRead_only;
+ bool bNo_set_dir;
+ bool bGuest_only;
+ bool bAdministrative_share;
+ bool bGuest_ok;
+ bool bPrint_ok;
+ bool bMap_system;
+ bool bMap_hidden;
+ bool bMap_archive;
+ bool bStoreDosAttributes;
+ bool bDmapiSupport;
+ bool bLocking;
+ int iStrictLocking;
+ bool bPosixLocking;
+ bool bShareModes;
+ bool bOpLocks;
+ bool bLevel2OpLocks;
+ bool bOnlyUser;
+ bool bMangledNames;
+ bool bWidelinks;
+ bool bSymlinks;
+ bool bSyncAlways;
+ bool bStrictAllocate;
+ bool bStrictSync;
+ char magic_char;
+ struct bitmap *copymap;
+ bool bDeleteReadonly;
+ bool bFakeOplocks;
+ bool bDeleteVetoFiles;
+ bool bDosFilemode;
+ bool bDosFiletimes;
+ bool bDosFiletimeResolution;
+ bool bFakeDirCreateTimes;
+ bool bBlockingLocks;
+ bool bInheritPerms;
+ bool bInheritACLS;
+ bool bInheritOwner;
+ bool bMSDfsRoot;
+ bool bUseClientDriver;
+ bool bDefaultDevmode;
+ bool bForcePrintername;
+ bool bNTAclSupport;
+ bool bForceUnknownAclUser;
+ bool bUseSendfile;
+ bool bProfileAcls;
+ bool bMap_acl_inherit;
+ bool bAfs_Share;
+ bool bEASupport;
+ bool bAclCheckPermissions;
+ bool bAclMapFullControl;
+ bool bAclGroupControl;
+ bool bChangeNotify;
+ bool bKernelChangeNotify;
+ int iallocation_roundup_size;
+ int iAioReadSize;
+ int iAioWriteSize;
+ int iMap_readonly;
+ int iDirectoryNameCacheSize;
+ int ismb_encrypt;
+ struct param_opt_struct *param_opt;
+
+ char dummy[3]; /* for alignment */
+};
+
+
+/* This is a default service used to prime a services structure */
+static struct service sDefault = {
+ True, /* valid */
+ False, /* not autoloaded */
+ 0, /* not a usershare */
+ (time_t)0, /* No last mod time */
+ NULL, /* szService */
+ NULL, /* szPath */
+ NULL, /* szUsername */
+ NULL, /* szInvalidUsers */
+ NULL, /* szValidUsers */
+ NULL, /* szAdminUsers */
+ NULL, /* szCopy */
+ NULL, /* szInclude */
+ NULL, /* szPreExec */
+ NULL, /* szPostExec */
+ NULL, /* szRootPreExec */
+ NULL, /* szRootPostExec */
+ NULL, /* szCupsOptions */
+ NULL, /* szPrintcommand */
+ NULL, /* szLpqcommand */
+ NULL, /* szLprmcommand */
+ NULL, /* szLppausecommand */
+ NULL, /* szLpresumecommand */
+ NULL, /* szQueuepausecommand */
+ NULL, /* szQueueresumecommand */
+ NULL, /* szPrintername */
+ NULL, /* szPrintjobUsername */
+ NULL, /* szDontdescend */
+ NULL, /* szHostsallow */
+ NULL, /* szHostsdeny */
+ NULL, /* szMagicScript */
+ NULL, /* szMagicOutput */
+ NULL, /* szVetoFiles */
+ NULL, /* szHideFiles */
+ NULL, /* szVetoOplockFiles */
+ NULL, /* comment */
+ NULL, /* force user */
+ NULL, /* force group */
+ NULL, /* readlist */
+ NULL, /* writelist */
+ NULL, /* printer admin */
+ NULL, /* volume */
+ NULL, /* fstype */
+ NULL, /* vfs objects */
+ NULL, /* szMSDfsProxy */
+ NULL, /* szAioWriteBehind */
+ NULL, /* szDfree */
+ 0, /* iMinPrintSpace */
+ 1000, /* iMaxPrintJobs */
+ 0, /* iMaxReportedPrintJobs */
+ 0, /* iWriteCacheSize */
+ 0744, /* iCreate_mask */
+ 0000, /* iCreate_force_mode */
+ 0777, /* iSecurity_mask */
+ 0, /* iSecurity_force_mode */
+ 0755, /* iDir_mask */
+ 0000, /* iDir_force_mode */
+ 0777, /* iDir_Security_mask */
+ 0, /* iDir_Security_force_mode */
+ 0, /* iMaxConnections */
+ CASE_LOWER, /* iDefaultCase */
+ DEFAULT_PRINTING, /* iPrinting */
+ 2, /* iOplockContentionLimit */
+ 0, /* iCSCPolicy */
+ 1024, /* iBlock_size */
+ 0, /* iDfreeCacheTime */
+ False, /* bPreexecClose */
+ False, /* bRootpreexecClose */
+ Auto, /* case sensitive */
+ True, /* case preserve */
+ True, /* short case preserve */
+ True, /* bHideDotFiles */
+ False, /* bHideSpecialFiles */
+ False, /* bHideUnReadable */
+ False, /* bHideUnWriteableFiles */
+ True, /* bBrowseable */
+ True, /* bAvailable */
+ True, /* bRead_only */
+ True, /* bNo_set_dir */
+ False, /* bGuest_only */
+ False, /* bAdministrative_share */
+ False, /* bGuest_ok */
+ False, /* bPrint_ok */
+ False, /* bMap_system */
+ False, /* bMap_hidden */
+ True, /* bMap_archive */
+ False, /* bStoreDosAttributes */
+ False, /* bDmapiSupport */
+ True, /* bLocking */
+ Auto, /* iStrictLocking */
+ True, /* bPosixLocking */
+ True, /* bShareModes */
+ True, /* bOpLocks */
+ True, /* bLevel2OpLocks */
+ False, /* bOnlyUser */
+ True, /* bMangledNames */
+ True, /* bWidelinks */
+ True, /* bSymlinks */
+ False, /* bSyncAlways */
+ False, /* bStrictAllocate */
+ False, /* bStrictSync */
+ '~', /* magic char */
+ NULL, /* copymap */
+ False, /* bDeleteReadonly */
+ False, /* bFakeOplocks */
+ False, /* bDeleteVetoFiles */
+ False, /* bDosFilemode */
+ True, /* bDosFiletimes */
+ False, /* bDosFiletimeResolution */
+ False, /* bFakeDirCreateTimes */
+ True, /* bBlockingLocks */
+ False, /* bInheritPerms */
+ False, /* bInheritACLS */
+ False, /* bInheritOwner */
+ False, /* bMSDfsRoot */
+ False, /* bUseClientDriver */
+ True, /* bDefaultDevmode */
+ False, /* bForcePrintername */
+ True, /* bNTAclSupport */
+ False, /* bForceUnknownAclUser */
+ False, /* bUseSendfile */
+ False, /* bProfileAcls */
+ False, /* bMap_acl_inherit */
+ False, /* bAfs_Share */
+ False, /* bEASupport */
+ True, /* bAclCheckPermissions */
+ True, /* bAclMapFullControl */
+ False, /* bAclGroupControl */
+ True, /* bChangeNotify */
+ True, /* bKernelChangeNotify */
+ SMB_ROUNDUP_ALLOCATION_SIZE, /* iallocation_roundup_size */
+ 0, /* iAioReadSize */
+ 0, /* iAioWriteSize */
+ MAP_READONLY_YES, /* iMap_readonly */
+#ifdef BROKEN_DIRECTORY_HANDLING
+ 0, /* iDirectoryNameCacheSize */
+#else
+ 100, /* iDirectoryNameCacheSize */
+#endif
+ Auto, /* ismb_encrypt */
+ NULL, /* Parametric options */
+
+ "" /* dummy */
+};
+
+/* local variables */
+static struct service **ServicePtrs = NULL;
+static int iNumServices = 0;
+static int iServiceIndex = 0;
+static struct db_context *ServiceHash;
+static int *invalid_services = NULL;
+static int num_invalid_services = 0;
+static bool bInGlobalSection = True;
+static bool bGlobalOnly = False;
+static int server_role;
+static int default_server_announce;
+
+#define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
+
+/* prototypes for the special type handlers */
+static bool handle_include( int snum, const char *pszParmValue, char **ptr);
+static bool handle_copy( int snum, const char *pszParmValue, char **ptr);
+static bool handle_netbios_name( int snum, const char *pszParmValue, char **ptr);
+static bool handle_idmap_uid( int snum, const char *pszParmValue, char **ptr);
+static bool handle_idmap_gid( int snum, const char *pszParmValue, char **ptr);
+static bool handle_debug_list( int snum, const char *pszParmValue, char **ptr );
+static bool handle_workgroup( int snum, const char *pszParmValue, char **ptr );
+static bool handle_netbios_aliases( int snum, const char *pszParmValue, char **ptr );
+static bool handle_netbios_scope( int snum, const char *pszParmValue, char **ptr );
+static bool handle_charset( int snum, const char *pszParmValue, char **ptr );
+static bool handle_printing( int snum, const char *pszParmValue, char **ptr);
+static bool handle_ldap_debug_level( int snum, const char *pszParmValue, char **ptr);
+
+static void set_server_role(void);
+static void set_default_server_announce_type(void);
+static void set_allowed_client_auth(void);
+
+static const 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 const struct enum_list enum_security[] = {
+ {SEC_SHARE, "SHARE"},
+ {SEC_USER, "USER"},
+ {SEC_SERVER, "SERVER"},
+ {SEC_DOMAIN, "DOMAIN"},
+#ifdef HAVE_ADS
+ {SEC_ADS, "ADS"},
+#endif
+ {-1, NULL}
+};
+
+static const 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_CUPS, "cups"},
+ {PRINT_IPRINT, "iprint"},
+ {PRINT_LPRNT, "nt"},
+ {PRINT_LPROS2, "os2"},
+#ifdef DEVELOPER
+ {PRINT_TEST, "test"},
+ {PRINT_VLP, "vlp"},
+#endif /* DEVELOPER */
+ {-1, NULL}
+};
+
+static const struct enum_list enum_ldap_sasl_wrapping[] = {
+ {0, "plain"},
+ {ADS_AUTH_SASL_SIGN, "sign"},
+ {ADS_AUTH_SASL_SEAL, "seal"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_ldap_ssl[] = {
+ {LDAP_SSL_OFF, "no"},
+ {LDAP_SSL_OFF, "No"},
+ {LDAP_SSL_OFF, "off"},
+ {LDAP_SSL_OFF, "Off"},
+ {LDAP_SSL_START_TLS, "start tls"},
+ {LDAP_SSL_START_TLS, "Start_tls"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_ldap_passwd_sync[] = {
+ {LDAP_PASSWD_SYNC_OFF, "no"},
+ {LDAP_PASSWD_SYNC_OFF, "No"},
+ {LDAP_PASSWD_SYNC_OFF, "off"},
+ {LDAP_PASSWD_SYNC_OFF, "Off"},
+ {LDAP_PASSWD_SYNC_ON, "Yes"},
+ {LDAP_PASSWD_SYNC_ON, "yes"},
+ {LDAP_PASSWD_SYNC_ON, "on"},
+ {LDAP_PASSWD_SYNC_ON, "On"},
+ {LDAP_PASSWD_SYNC_ONLY, "Only"},
+ {LDAP_PASSWD_SYNC_ONLY, "only"},
+ {-1, NULL}
+};
+
+/* Types of machine we can announce as. */
+#define ANNOUNCE_AS_NT_SERVER 1
+#define ANNOUNCE_AS_WIN95 2
+#define ANNOUNCE_AS_WFW 3
+#define ANNOUNCE_AS_NT_WORKSTATION 4
+
+static const struct enum_list enum_announce_as[] = {
+ {ANNOUNCE_AS_NT_SERVER, "NT"},
+ {ANNOUNCE_AS_NT_SERVER, "NT Server"},
+ {ANNOUNCE_AS_NT_WORKSTATION, "NT Workstation"},
+ {ANNOUNCE_AS_WIN95, "win95"},
+ {ANNOUNCE_AS_WFW, "WfW"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_map_readonly[] = {
+ {MAP_READONLY_NO, "no"},
+ {MAP_READONLY_NO, "false"},
+ {MAP_READONLY_NO, "0"},
+ {MAP_READONLY_YES, "yes"},
+ {MAP_READONLY_YES, "true"},
+ {MAP_READONLY_YES, "1"},
+ {MAP_READONLY_PERMISSIONS, "permissions"},
+ {MAP_READONLY_PERMISSIONS, "perms"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_case[] = {
+ {CASE_LOWER, "lower"},
+ {CASE_UPPER, "upper"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_bool_auto[] = {
+ {False, "No"},
+ {False, "False"},
+ {False, "0"},
+ {True, "Yes"},
+ {True, "True"},
+ {True, "1"},
+ {Auto, "Auto"},
+ {-1, NULL}
+};
+
+/* Client-side offline caching policy types */
+#define CSC_POLICY_MANUAL 0
+#define CSC_POLICY_DOCUMENTS 1
+#define CSC_POLICY_PROGRAMS 2
+#define CSC_POLICY_DISABLE 3
+
+static const struct enum_list enum_csc_policy[] = {
+ {CSC_POLICY_MANUAL, "manual"},
+ {CSC_POLICY_DOCUMENTS, "documents"},
+ {CSC_POLICY_PROGRAMS, "programs"},
+ {CSC_POLICY_DISABLE, "disable"},
+ {-1, NULL}
+};
+
+/* SMB signing types. */
+static const struct enum_list enum_smb_signing_vals[] = {
+ {False, "No"},
+ {False, "False"},
+ {False, "0"},
+ {False, "Off"},
+ {False, "disabled"},
+ {True, "Yes"},
+ {True, "True"},
+ {True, "1"},
+ {True, "On"},
+ {True, "enabled"},
+ {Auto, "auto"},
+ {Required, "required"},
+ {Required, "mandatory"},
+ {Required, "force"},
+ {Required, "forced"},
+ {Required, "enforced"},
+ {-1, NULL}
+};
+
+/* ACL compatibility options. */
+static const struct enum_list enum_acl_compat_vals[] = {
+ { ACL_COMPAT_AUTO, "auto" },
+ { ACL_COMPAT_WINNT, "winnt" },
+ { ACL_COMPAT_WIN2K, "win2k" },
+ { -1, NULL}
+};
+
+/*
+ Do you want session setups at user level security with a invalid
+ password to be rejected or allowed in as guest? WinNT rejects them
+ but it can be a pain as it means "net view" needs to use a password
+
+ You have 3 choices in the setting of map_to_guest:
+
+ "Never" means session setups with an invalid password
+ are rejected. This is the default.
+
+ "Bad User" means session setups with an invalid password
+ are rejected, unless the username does not exist, in which case it
+ is treated as a guest login
+
+ "Bad Password" means session setups with an invalid password
+ are treated as a guest login
+
+ Note that map_to_guest only has an effect in user or server
+ level security.
+*/
+
+static const struct enum_list enum_map_to_guest[] = {
+ {NEVER_MAP_TO_GUEST, "Never"},
+ {MAP_TO_GUEST_ON_BAD_USER, "Bad User"},
+ {MAP_TO_GUEST_ON_BAD_PASSWORD, "Bad Password"},
+ {MAP_TO_GUEST_ON_BAD_UID, "Bad Uid"},
+ {-1, NULL}
+};
+
+/* Config backend options */
+
+static const struct enum_list enum_config_backend[] = {
+ {CONFIG_BACKEND_FILE, "file"},
+ {CONFIG_BACKEND_REGISTRY, "registry"},
+ {-1, NULL}
+};
+
+/* Note: We do not initialise the defaults union - it is not allowed in ANSI C
+ *
+ * The FLAG_HIDE is explicit. Paramters set this way do NOT appear in any edit
+ * screen in SWAT. This is used to exclude parameters as well as to squash all
+ * parameters that have been duplicated by pseudonyms.
+ *
+ * NOTE: To display a parameter in BASIC view set FLAG_BASIC
+ * Any parameter that does NOT have FLAG_ADVANCED will not disply at all
+ * Set FLAG_SHARE and FLAG_PRINT to specifically display parameters in
+ * respective views.
+ *
+ * NOTE2: Handling of duplicated (synonym) paramters:
+ * Only the first occurance of a parameter should be enabled by FLAG_BASIC
+ * and/or FLAG_ADVANCED. All duplicates following the first mention should be
+ * set to FLAG_HIDE. ie: Make you must place the parameter that has the preferred
+ * name first, and all synonyms must follow it with the FLAG_HIDE attribute.
+ */
+
+static struct parm_struct parm_table[] = {
+ {N_("Base Options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "dos charset",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.dos_charset,
+ .special = handle_charset,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED
+ },
+ {
+ .label = "unix charset",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.unix_charset,
+ .special = handle_charset,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED
+ },
+ {
+ .label = "display charset",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.display_charset,
+ .special = handle_charset,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED
+ },
+ {
+ .label = "comment",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.comment,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT
+ },
+ {
+ .label = "path",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szPath,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT,
+ },
+ {
+ .label = "directory",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szPath,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "workgroup",
+ .type = P_USTRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szWorkgroup,
+ .special = handle_workgroup,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD,
+ },
+#ifdef WITH_ADS
+ {
+ .label = "realm",
+ .type = P_USTRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szRealm,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD,
+ },
+#endif
+ {
+ .label = "netbios name",
+ .type = P_USTRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szNetbiosName,
+ .special = handle_netbios_name,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD,
+ },
+ {
+ .label = "netbios aliases",
+ .type = P_LIST,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szNetbiosAliases,
+ .special = handle_netbios_aliases,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "netbios scope",
+ .type = P_USTRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szNetbiosScope,
+ .special = handle_netbios_scope,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "server string",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szServerString,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED,
+ },
+ {
+ .label = "interfaces",
+ .type = P_LIST,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szInterfaces,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD,
+ },
+ {
+ .label = "bind interfaces only",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bBindInterfacesOnly,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_WIZARD,
+ },
+ {
+ .label = "config backend",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.ConfigBackend,
+ .special = NULL,
+ .enum_list = enum_config_backend,
+ .flags = FLAG_ADVANCED,
+ },
+
+ {N_("Security Options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "security",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.security,
+ .special = NULL,
+ .enum_list = enum_security,
+ .flags = FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD,
+ },
+ {
+ .label = "auth methods",
+ .type = P_LIST,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.AuthMethods,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "encrypt passwords",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bEncryptPasswords,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD,
+ },
+ {
+ .label = "update encrypted",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bUpdateEncrypt,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "client schannel",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.clientSchannel,
+ .special = NULL,
+ .enum_list = enum_bool_auto,
+ .flags = FLAG_BASIC | FLAG_ADVANCED,
+ },
+ {
+ .label = "server schannel",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.serverSchannel,
+ .special = NULL,
+ .enum_list = enum_bool_auto,
+ .flags = FLAG_BASIC | FLAG_ADVANCED,
+ },
+ {
+ .label = "allow trusted domains",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bAllowTrustedDomains,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "map to guest",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.map_to_guest,
+ .special = NULL,
+ .enum_list = enum_map_to_guest,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "null passwords",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bNullPasswords,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "obey pam restrictions",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bObeyPamRestrictions,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "password server",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szPasswordServer,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_WIZARD,
+ },
+ {
+ .label = "smb passwd file",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szSMBPasswdFile,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "private dir",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szPrivateDir,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "passdb backend",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szPassdbBackend,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_WIZARD,
+ },
+ {
+ .label = "algorithmic rid base",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.AlgorithmicRidBase,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "root directory",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szRootdir,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "root dir",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szRootdir,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "root",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szRootdir,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "guest account",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szGuestaccount,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED,
+ },
+ {
+ .label = "enable privileges",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bEnablePrivileges,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+
+ {
+ .label = "pam password change",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bPamPasswordChange,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "passwd program",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szPasswdProgram,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "passwd chat",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szPasswdChat,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "passwd chat debug",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bPasswdChatDebug,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "passwd chat timeout",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.iPasswdChatTimeout,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "check password script",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szCheckPasswordScript,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "username map",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szUsernameMap,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "password level",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.pwordlevel,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "username level",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.unamelevel,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "unix password sync",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bUnixPasswdSync,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "restrict anonymous",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.restrict_anonymous,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "lanman auth",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bLanmanAuth,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "ntlm auth",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bNTLMAuth,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "client NTLMv2 auth",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bClientNTLMv2Auth,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "client lanman auth",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bClientLanManAuth,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "client plaintext auth",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bClientPlaintextAuth,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "username",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szUsername,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "user",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szUsername,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "users",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szUsername,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "invalid users",
+ .type = P_LIST,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szInvalidUsers,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "valid users",
+ .type = P_LIST,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szValidUsers,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "admin users",
+ .type = P_LIST,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szAdminUsers,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "read list",
+ .type = P_LIST,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.readlist,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "write list",
+ .type = P_LIST,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.writelist,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "printer admin",
+ .type = P_LIST,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.printer_admin,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_PRINT | FLAG_DEPRECATED,
+ },
+ {
+ .label = "force user",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.force_user,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "force group",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.force_group,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "group",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.force_group,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "read only",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bRead_only,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "write ok",
+ .type = P_BOOLREV,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bRead_only,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "writeable",
+ .type = P_BOOLREV,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bRead_only,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "writable",
+ .type = P_BOOLREV,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bRead_only,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "acl check permissions",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bAclCheckPermissions,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "acl group control",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bAclGroupControl,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "acl map full control",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bAclMapFullControl,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "create mask",
+ .type = P_OCTAL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iCreate_mask,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "create mode",
+ .type = P_OCTAL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iCreate_mask,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "force create mode",
+ .type = P_OCTAL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iCreate_force_mode,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "security mask",
+ .type = P_OCTAL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iSecurity_mask,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "force security mode",
+ .type = P_OCTAL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iSecurity_force_mode,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "directory mask",
+ .type = P_OCTAL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iDir_mask,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "directory mode",
+ .type = P_OCTAL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iDir_mask,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL,
+ },
+ {
+ .label = "force directory mode",
+ .type = P_OCTAL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iDir_force_mode,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "directory security mask",
+ .type = P_OCTAL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iDir_Security_mask,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "force directory security mode",
+ .type = P_OCTAL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iDir_Security_force_mode,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "force unknown acl user",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bForceUnknownAclUser,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "inherit permissions",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bInheritPerms,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "inherit acls",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bInheritACLS,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "inherit owner",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bInheritOwner,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "guest only",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bGuest_only,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "only guest",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bGuest_only,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "administrative share",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bAdministrative_share,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT,
+ },
+
+ {
+ .label = "guest ok",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bGuest_ok,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT,
+ },
+ {
+ .label = "public",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bGuest_ok,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "only user",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bOnlyUser,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_DEPRECATED,
+ },
+ {
+ .label = "hosts allow",
+ .type = P_LIST,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szHostsallow,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_GLOBAL | FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT,
+ },
+ {
+ .label = "allow hosts",
+ .type = P_LIST,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szHostsallow,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "hosts deny",
+ .type = P_LIST,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szHostsdeny,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_GLOBAL | FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT,
+ },
+ {
+ .label = "deny hosts",
+ .type = P_LIST,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szHostsdeny,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "preload modules",
+ .type = P_LIST,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szPreloadModules,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL,
+ },
+ {
+ .label = "use kerberos keytab",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bUseKerberosKeytab,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+
+ {N_("Logging Options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "log level",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szLogLevel,
+ .special = handle_debug_list,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "debuglevel",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szLogLevel,
+ .special = handle_debug_list,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "syslog",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.syslog,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "syslog only",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bSyslogOnly,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "log file",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szLogFile,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "max log size",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.max_log_size,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "debug timestamp",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bTimestampLogs,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "timestamp logs",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bTimestampLogs,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "debug prefix timestamp",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bDebugPrefixTimestamp,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "debug hires timestamp",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bDebugHiresTimestamp,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "debug pid",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bDebugPid,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "debug uid",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bDebugUid,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "debug class",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bDebugClass,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "enable core files",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bEnableCoreFiles,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+
+ {N_("Protocol Options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "allocation roundup size",
+ .type = P_INTEGER,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iallocation_roundup_size,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "aio read size",
+ .type = P_INTEGER,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iAioReadSize,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "aio write size",
+ .type = P_INTEGER,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iAioWriteSize,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "aio write behind",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szAioWriteBehind,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "smb ports",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.smb_ports,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "large readwrite",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bLargeReadwrite,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "max protocol",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.maxprotocol,
+ .special = NULL,
+ .enum_list = enum_protocol,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "protocol",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.maxprotocol,
+ .special = NULL,
+ .enum_list = enum_protocol,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "min protocol",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.minprotocol,
+ .special = NULL,
+ .enum_list = enum_protocol,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "min receivefile size",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.iminreceivefile,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "read raw",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bReadRaw,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "write raw",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bWriteRaw,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "disable netbios",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bDisableNetbios,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "reset on zero vc",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bResetOnZeroVC,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "acl compatibility",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.iAclCompat,
+ .special = NULL,
+ .enum_list = enum_acl_compat_vals,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "defer sharing violations",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bDeferSharingViolations,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL,
+ },
+ {
+ .label = "ea support",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bEASupport,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "nt acl support",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bNTAclSupport,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "nt pipe support",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bNTPipeSupport,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "nt status support",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bNTStatusSupport,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "profile acls",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bProfileAcls,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+ {
+ .label = "announce version",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szAnnounceVersion,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "announce as",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.announce_as,
+ .special = NULL,
+ .enum_list = enum_announce_as,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "map acl inherit",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bMap_acl_inherit,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "afs share",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bAfs_Share,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "max mux",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.max_mux,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "max xmit",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.max_xmit,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "name resolve order",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szNameResolveOrder,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_WIZARD,
+ },
+ {
+ .label = "max ttl",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.max_ttl,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "max wins ttl",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.max_wins_ttl,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "min wins ttl",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.min_wins_ttl,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "time server",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bTimeServer,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "unix extensions",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bUnixExtensions,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "use spnego",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bUseSpnego,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "client signing",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.client_signing,
+ .special = NULL,
+ .enum_list = enum_smb_signing_vals,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "server signing",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.server_signing,
+ .special = NULL,
+ .enum_list = enum_smb_signing_vals,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "smb encrypt",
+ .type = P_ENUM,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.ismb_encrypt,
+ .special = NULL,
+ .enum_list = enum_smb_signing_vals,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "client use spnego",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bClientUseSpnego,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "client ldap sasl wrapping",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.client_ldap_sasl_wrapping,
+ .special = NULL,
+ .enum_list = enum_ldap_sasl_wrapping,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "enable asu support",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bASUSupport,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "svcctl list",
+ .type = P_LIST,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szServicesList,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+
+ {N_("Tuning Options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "block size",
+ .type = P_INTEGER,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iBlock_size,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "deadtime",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.deadtime,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "getwd cache",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.getwd_cache,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "keepalive",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.iKeepalive,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "change notify",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bChangeNotify,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "directory name cache size",
+ .type = P_INTEGER,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iDirectoryNameCacheSize,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "kernel change notify",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bKernelChangeNotify,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "lpq cache time",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.lpqcachetime,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "max smbd processes",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.iMaxSmbdProcesses,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "max connections",
+ .type = P_INTEGER,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iMaxConnections,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "paranoid server security",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.paranoid_server_security,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "max disk size",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.maxdisksize,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "max open files",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.max_open_files,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "min print space",
+ .type = P_INTEGER,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iMinPrintSpace,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT,
+ },
+ {
+ .label = "socket options",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szSocketOptions,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "strict allocate",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bStrictAllocate,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "strict sync",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bStrictSync,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "sync always",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bSyncAlways,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "use mmap",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bUseMmap,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "use sendfile",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bUseSendfile,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "hostname lookups",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bHostnameLookups,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "write cache size",
+ .type = P_INTEGER,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iWriteCacheSize,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_DEPRECATED,
+ },
+ {
+ .label = "name cache timeout",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.name_cache_timeout,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "ctdbd socket",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.ctdbdSocket,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL,
+ },
+ {
+ .label = "cluster addresses",
+ .type = P_LIST,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szClusterAddresses,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL,
+ },
+ {
+ .label = "clustering",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.clustering,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL,
+ },
+
+ {N_("Printing Options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "max reported print jobs",
+ .type = P_INTEGER,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iMaxReportedPrintJobs,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT,
+ },
+ {
+ .label = "max print jobs",
+ .type = P_INTEGER,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iMaxPrintJobs,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT,
+ },
+ {
+ .label = "load printers",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bLoadPrinters,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT,
+ },
+ {
+ .label = "printcap cache time",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.PrintcapCacheTime,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT,
+ },
+ {
+ .label = "printcap name",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szPrintcapname,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT,
+ },
+ {
+ .label = "printcap",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szPrintcapname,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "printable",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bPrint_ok,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT,
+ },
+ {
+ .label = "print ok",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bPrint_ok,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "printing",
+ .type = P_ENUM,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iPrinting,
+ .special = handle_printing,
+ .enum_list = enum_printing,
+ .flags = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
+ },
+ {
+ .label = "cups options",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szCupsOptions,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
+ },
+ {
+ .label = "cups server",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szCupsServer,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
+ },
+ {
+ .label = "iprint server",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szIPrintServer,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
+ },
+ {
+ .label = "print command",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szPrintcommand,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
+ },
+ {
+ .label = "disable spoolss",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bDisableSpoolss,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
+ },
+ {
+ .label = "enable spoolss",
+ .type = P_BOOLREV,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bDisableSpoolss,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "lpq command",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szLpqcommand,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
+ },
+ {
+ .label = "lprm command",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szLprmcommand,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
+ },
+ {
+ .label = "lppause command",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szLppausecommand,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
+ },
+ {
+ .label = "lpresume command",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szLpresumecommand,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
+ },
+ {
+ .label = "queuepause command",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szQueuepausecommand,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
+ },
+ {
+ .label = "queueresume command",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szQueueresumecommand,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
+ },
+ {
+ .label = "addport command",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szAddPortCommand,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "enumports command",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szEnumPortsCommand,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "addprinter command",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szAddPrinterCommand,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "deleteprinter command",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szDeletePrinterCommand,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "show add printer wizard",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bMsAddPrinterWizard,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "os2 driver map",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szOs2DriverMap,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+
+ {
+ .label = "printer name",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szPrintername,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT,
+ },
+ {
+ .label = "printer",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szPrintername,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "use client driver",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bUseClientDriver,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT,
+ },
+ {
+ .label = "default devmode",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bDefaultDevmode,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT,
+ },
+ {
+ .label = "force printername",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bForcePrintername,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT,
+ },
+ {
+ .label = "printjob username",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szPrintjobUsername,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_PRINT,
+ },
+
+ {N_("Filename Handling"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "mangling method",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szManglingMethod,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "mangle prefix",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.mangle_prefix,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+
+ {
+ .label = "default case",
+ .type = P_ENUM,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iDefaultCase,
+ .special = NULL,
+ .enum_list = enum_case,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "case sensitive",
+ .type = P_ENUM,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iCaseSensitive,
+ .special = NULL,
+ .enum_list = enum_bool_auto,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "casesignames",
+ .type = P_ENUM,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iCaseSensitive,
+ .special = NULL,
+ .enum_list = enum_bool_auto,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL | FLAG_HIDE,
+ },
+ {
+ .label = "preserve case",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bCasePreserve,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "short preserve case",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bShortCasePreserve,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "mangling char",
+ .type = P_CHAR,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.magic_char,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "hide dot files",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bHideDotFiles,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "hide special files",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bHideSpecialFiles,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "hide unreadable",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bHideUnReadable,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "hide unwriteable files",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bHideUnWriteableFiles,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "delete veto files",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bDeleteVetoFiles,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "veto files",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szVetoFiles,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "hide files",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szHideFiles,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "veto oplock files",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szVetoOplockFiles,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "map archive",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bMap_archive,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "map hidden",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bMap_hidden,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "map system",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bMap_system,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "map readonly",
+ .type = P_ENUM,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iMap_readonly,
+ .special = NULL,
+ .enum_list = enum_map_readonly,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "mangled names",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bMangledNames,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "max stat cache size",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.iMaxStatCacheSize,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "stat cache",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bStatCache,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "store dos attributes",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bStoreDosAttributes,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "dmapi support",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bDmapiSupport,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+
+
+ {N_("Domain Options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "machine password timeout",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.machine_password_timeout,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_WIZARD,
+ },
+
+ {N_("Logon Options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "add user script",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szAddUserScript,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "rename user script",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szRenameUserScript,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "delete user script",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szDelUserScript,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "add group script",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szAddGroupScript,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "delete group script",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szDelGroupScript,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "add user to group script",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szAddUserToGroupScript,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "delete user from group script",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szDelUserFromGroupScript,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "set primary group script",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szSetPrimaryGroupScript,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "add machine script",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szAddMachineScript,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "shutdown script",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szShutdownScript,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "abort shutdown script",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szAbortShutdownScript,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "username map script",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szUsernameMapScript,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "logon script",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szLogonScript,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "logon path",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szLogonPath,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "logon drive",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szLogonDrive,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "logon home",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szLogonHome,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "domain logons",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bDomainLogons,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+
+ {
+ .label = "init logon delayed hosts",
+ .type = P_LIST,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szInitLogonDelayedHosts,
+ .flags = FLAG_ADVANCED,
+ },
+
+ {
+ .label = "init logon delay",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.InitLogonDelay,
+ .flags = FLAG_ADVANCED,
+
+ },
+
+ {N_("Browse Options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "os level",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.os_level,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED,
+ },
+ {
+ .label = "lm announce",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.lm_announce,
+ .special = NULL,
+ .enum_list = enum_bool_auto,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "lm interval",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.lm_interval,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "preferred master",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.iPreferredMaster,
+ .special = NULL,
+ .enum_list = enum_bool_auto,
+ .flags = FLAG_BASIC | FLAG_ADVANCED,
+ },
+ {
+ .label = "prefered master",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.iPreferredMaster,
+ .special = NULL,
+ .enum_list = enum_bool_auto,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "local master",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bLocalMaster,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED,
+ },
+ {
+ .label = "domain master",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.iDomainMaster,
+ .special = NULL,
+ .enum_list = enum_bool_auto,
+ .flags = FLAG_BASIC | FLAG_ADVANCED,
+ },
+ {
+ .label = "browse list",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bBrowseList,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "browseable",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bBrowseable,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT,
+ },
+ {
+ .label = "browsable",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bBrowseable,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "enhanced browsing",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.enhanced_browsing,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+
+ {N_("WINS Options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "dns proxy",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bDNSproxy,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "wins proxy",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bWINSproxy,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "wins server",
+ .type = P_LIST,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szWINSservers,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD,
+ },
+ {
+ .label = "wins support",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bWINSsupport,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD,
+ },
+ {
+ .label = "wins hook",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szWINSHook,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+
+ {N_("Locking Options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "blocking locks",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bBlockingLocks,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "csc policy",
+ .type = P_ENUM,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iCSCPolicy,
+ .special = NULL,
+ .enum_list = enum_csc_policy,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "fake oplocks",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bFakeOplocks,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "kernel oplocks",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bKernelOplocks,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL,
+ },
+ {
+ .label = "locking",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bLocking,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "lock spin time",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.iLockSpinTime,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL,
+ },
+ {
+ .label = "oplocks",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bOpLocks,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "level2 oplocks",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bLevel2OpLocks,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "oplock break wait time",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.oplock_break_wait_time,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL,
+ },
+ {
+ .label = "oplock contention limit",
+ .type = P_INTEGER,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iOplockContentionLimit,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "posix locking",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bPosixLocking,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "strict locking",
+ .type = P_ENUM,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iStrictLocking,
+ .special = NULL,
+ .enum_list = enum_bool_auto,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "share modes",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bShareModes,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+
+ {N_("Ldap Options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "ldap admin dn",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szLdapAdminDn,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "ldap delete dn",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.ldap_delete_dn,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "ldap group suffix",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szLdapGroupSuffix,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "ldap idmap suffix",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szLdapIdmapSuffix,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "ldap machine suffix",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szLdapMachineSuffix,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "ldap passwd sync",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.ldap_passwd_sync,
+ .special = NULL,
+ .enum_list = enum_ldap_passwd_sync,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "ldap password sync",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.ldap_passwd_sync,
+ .special = NULL,
+ .enum_list = enum_ldap_passwd_sync,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "ldap replication sleep",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.ldap_replication_sleep,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "ldap suffix",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szLdapSuffix,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "ldap ssl",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.ldap_ssl,
+ .special = NULL,
+ .enum_list = enum_ldap_ssl,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "ldap timeout",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.ldap_timeout,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "ldap connection timeout",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.ldap_connection_timeout,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "ldap page size",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.ldap_page_size,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "ldap user suffix",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szLdapUserSuffix,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "ldap debug level",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.ldap_debug_level,
+ .special = handle_ldap_debug_level,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "ldap debug threshold",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.ldap_debug_threshold,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+
+ {N_("EventLog Options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "eventlog list",
+ .type = P_LIST,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szEventLogs,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
+ },
+
+ {N_("Miscellaneous Options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "add share command",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szAddShareCommand,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "change share command",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szChangeShareCommand,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "delete share command",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szDeleteShareCommand,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "config file",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szConfigFile,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "preload",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szAutoServices,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "auto services",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szAutoServices,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "lock directory",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szLockDir,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "lock dir",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szLockDir,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "pid directory",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szPidDir,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+#ifdef WITH_UTMP
+ {
+ .label = "utmp directory",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szUtmpDir,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "wtmp directory",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szWtmpDir,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "utmp",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bUtmp,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+#endif
+ {
+ .label = "default service",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szDefaultService,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "default",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szDefaultService,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "message command",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szMsgCommand,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "dfree cache time",
+ .type = P_INTEGER,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.iDfreeCacheTime,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "dfree command",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szDfree,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "get quota command",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szGetQuota,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "set quota command",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szSetQuota,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "remote announce",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szRemoteAnnounce,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "remote browse sync",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szRemoteBrowseSync,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "socket address",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szSocketAddress,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "homedir map",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szNISHomeMapName,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "afs username map",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szAfsUsernameMap,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "afs token lifetime",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.iAfsTokenLifetime,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "log nt token command",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szLogNtTokenCommand,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "time offset",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &extra_time_offset,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "NIS homedir",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bNISHomeMap,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "-valid",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.valid,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "copy",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szCopy,
+ .special = handle_copy,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "include",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szInclude,
+ .special = handle_include,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "preexec",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szPreExec,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT,
+ },
+ {
+ .label = "exec",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szPreExec,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "preexec close",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bPreexecClose,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "postexec",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szPostExec,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT,
+ },
+ {
+ .label = "root preexec",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szRootPreExec,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT,
+ },
+ {
+ .label = "root preexec close",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bRootpreexecClose,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "root postexec",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szRootPostExec,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT,
+ },
+ {
+ .label = "available",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bAvailable,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT,
+ },
+ {
+ .label = "registry shares",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bRegistryShares,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "usershare allow guests",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bUsershareAllowGuests,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "usershare max shares",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.iUsershareMaxShares,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "usershare owner only",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bUsershareOwnerOnly,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "usershare path",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szUsersharePath,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "usershare prefix allow list",
+ .type = P_LIST,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szUsersharePrefixAllowList,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "usershare prefix deny list",
+ .type = P_LIST,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szUsersharePrefixDenyList,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "usershare template share",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szUsershareTemplateShare,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "volume",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.volume,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "fstype",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.fstype,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "set directory",
+ .type = P_BOOLREV,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bNo_set_dir,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "wide links",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bWidelinks,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "follow symlinks",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bSymlinks,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "dont descend",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szDontdescend,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "magic script",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szMagicScript,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "magic output",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szMagicOutput,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "delete readonly",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bDeleteReadonly,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "dos filemode",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bDosFilemode,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "dos filetimes",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bDosFiletimes,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "dos filetime resolution",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bDosFiletimeResolution,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "fake directory create times",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bFakeDirCreateTimes,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
+ },
+ {
+ .label = "panic action",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szPanicAction,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+
+ {N_("VFS module options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "vfs objects",
+ .type = P_LIST,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szVfsObjects,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "vfs object",
+ .type = P_LIST,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szVfsObjects,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+
+
+ {N_("MSDFS options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "msdfs root",
+ .type = P_BOOL,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.bMSDfsRoot,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "msdfs proxy",
+ .type = P_STRING,
+ .p_class = P_LOCAL,
+ .ptr = &sDefault.szMSDfsProxy,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED | FLAG_SHARE,
+ },
+ {
+ .label = "host msdfs",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bHostMSDfs,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+
+ {N_("Winbind options"), P_SEP, P_SEPARATOR},
+
+ {
+ .label = "passdb expand explicit",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bPassdbExpandExplicit,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "idmap backend",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szIdmapBackend,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "idmap alloc backend",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szIdmapAllocBackend,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "idmap cache time",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.iIdmapCacheTime,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "idmap negative cache time",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.iIdmapNegativeCacheTime,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "idmap uid",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szIdmapUID,
+ .special = handle_idmap_uid,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "winbind uid",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szIdmapUID,
+ .special = handle_idmap_uid,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "idmap gid",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szIdmapGID,
+ .special = handle_idmap_gid,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "winbind gid",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szIdmapGID,
+ .special = handle_idmap_gid,
+ .enum_list = NULL,
+ .flags = FLAG_HIDE,
+ },
+ {
+ .label = "template homedir",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szTemplateHomedir,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "template shell",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szTemplateShell,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "winbind separator",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szWinbindSeparator,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "winbind cache time",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.winbind_cache_time,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "winbind reconnect delay",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.winbind_reconnect_delay,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "winbind enum users",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bWinbindEnumUsers,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "winbind enum groups",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bWinbindEnumGroups,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "winbind use default domain",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bWinbindUseDefaultDomain,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "winbind trusted domains only",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bWinbindTrustedDomainsOnly,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "winbind nested groups",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bWinbindNestedGroups,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "winbind expand groups",
+ .type = P_INTEGER,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.winbind_expand_groups,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "winbind nss info",
+ .type = P_LIST,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szWinbindNssInfo,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "winbind refresh tickets",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bWinbindRefreshTickets,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "winbind offline logon",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bWinbindOfflineLogon,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "winbind normalize names",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bWinbindNormalizeNames,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
+ .label = "winbind rpc only",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bWinbindRpcOnly,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+
+ {NULL, P_BOOL, P_NONE, NULL, NULL, NULL, 0}
+};
+
+/***************************************************************************
+ Initialise the sDefault parameter structure for the printer values.
+***************************************************************************/
+
+static void init_printer_values(struct service *pService)
+{
+ /* choose defaults depending on the type of printing */
+ switch (pService->iPrinting) {
+ case PRINT_BSD:
+ case PRINT_AIX:
+ case PRINT_LPRNT:
+ case PRINT_LPROS2:
+ string_set(&pService->szLpqcommand, "lpq -P'%p'");
+ string_set(&pService->szLprmcommand, "lprm -P'%p' %j");
+ string_set(&pService->szPrintcommand, "lpr -r -P'%p' %s");
+ break;
+
+ case PRINT_LPRNG:
+ case PRINT_PLP:
+ string_set(&pService->szLpqcommand, "lpq -P'%p'");
+ string_set(&pService->szLprmcommand, "lprm -P'%p' %j");
+ string_set(&pService->szPrintcommand, "lpr -r -P'%p' %s");
+ string_set(&pService->szQueuepausecommand, "lpc stop '%p'");
+ string_set(&pService->szQueueresumecommand, "lpc start '%p'");
+ string_set(&pService->szLppausecommand, "lpc hold '%p' %j");
+ string_set(&pService->szLpresumecommand, "lpc release '%p' %j");
+ break;
+
+ case PRINT_CUPS:
+ case PRINT_IPRINT:
+#ifdef HAVE_CUPS
+ /* set the lpq command to contain the destination printer
+ name only. This is used by cups_queue_get() */
+ string_set(&pService->szLpqcommand, "%p");
+ string_set(&pService->szLprmcommand, "");
+ string_set(&pService->szPrintcommand, "");
+ string_set(&pService->szLppausecommand, "");
+ string_set(&pService->szLpresumecommand, "");
+ string_set(&pService->szQueuepausecommand, "");
+ string_set(&pService->szQueueresumecommand, "");
+#else
+ string_set(&pService->szLpqcommand, "lpq -P'%p'");
+ string_set(&pService->szLprmcommand, "lprm -P'%p' %j");
+ string_set(&pService->szPrintcommand, "lpr -P'%p' %s; rm %s");
+ string_set(&pService->szLppausecommand, "lp -i '%p-%j' -H hold");
+ string_set(&pService->szLpresumecommand, "lp -i '%p-%j' -H resume");
+ string_set(&pService->szQueuepausecommand, "disable '%p'");
+ string_set(&pService->szQueueresumecommand, "enable '%p'");
+#endif /* HAVE_CUPS */
+ break;
+
+ case PRINT_SYSV:
+ case PRINT_HPUX:
+ string_set(&pService->szLpqcommand, "lpstat -o%p");
+ string_set(&pService->szLprmcommand, "cancel %p-%j");
+ string_set(&pService->szPrintcommand, "lp -c -d%p %s; rm %s");
+ string_set(&pService->szQueuepausecommand, "disable %p");
+ string_set(&pService->szQueueresumecommand, "enable %p");
+#ifndef HPUX
+ string_set(&pService->szLppausecommand, "lp -i %p-%j -H hold");
+ string_set(&pService->szLpresumecommand, "lp -i %p-%j -H resume");
+#endif /* HPUX */
+ break;
+
+ case PRINT_QNX:
+ string_set(&pService->szLpqcommand, "lpq -P%p");
+ string_set(&pService->szLprmcommand, "lprm -P%p %j");
+ string_set(&pService->szPrintcommand, "lp -r -P%p %s");
+ break;
+
+#ifdef DEVELOPER
+ case PRINT_TEST:
+ case PRINT_VLP:
+ string_set(&pService->szPrintcommand, "vlp print %p %s");
+ string_set(&pService->szLpqcommand, "vlp lpq %p");
+ string_set(&pService->szLprmcommand, "vlp lprm %p %j");
+ string_set(&pService->szLppausecommand, "vlp lppause %p %j");
+ string_set(&pService->szLpresumecommand, "vlp lpresum %p %j");
+ string_set(&pService->szQueuepausecommand, "vlp queuepause %p");
+ string_set(&pService->szQueueresumecommand, "vlp queueresume %p");
+ break;
+#endif /* DEVELOPER */
+
+ }
+}
+
+/***************************************************************************
+ Initialise the global parameter structure.
+***************************************************************************/
+
+static void init_globals(bool first_time_only)
+{
+ static bool done_init = False;
+ char *s = NULL;
+ int i;
+
+ /* If requested to initialize only once and we've already done it... */
+ if (first_time_only && done_init) {
+ /* ... then we have nothing more to do */
+ return;
+ }
+
+ if (!done_init) {
+ /* The logfile can be set before this is invoked. Free it if so. */
+ if (Globals.szLogFile != NULL) {
+ string_free(&Globals.szLogFile);
+ Globals.szLogFile = NULL;
+ }
+ done_init = True;
+ } else {
+ for (i = 0; parm_table[i].label; i++) {
+ if ((parm_table[i].type == P_STRING ||
+ parm_table[i].type == P_USTRING) &&
+ parm_table[i].ptr)
+ {
+ string_free((char **)parm_table[i].ptr);
+ }
+ }
+ }
+
+ memset((void *)&Globals, '\0', sizeof(Globals));
+
+ for (i = 0; parm_table[i].label; i++) {
+ if ((parm_table[i].type == P_STRING ||
+ parm_table[i].type == P_USTRING) &&
+ parm_table[i].ptr)
+ {
+ string_set((char **)parm_table[i].ptr, "");
+ }
+ }
+
+ string_set(&sDefault.fstype, FSTYPE_STRING);
+ string_set(&sDefault.szPrintjobUsername, "%U");
+
+ init_printer_values(&sDefault);
+
+
+ DEBUG(3, ("Initialising global parameters\n"));
+
+ string_set(&Globals.szSMBPasswdFile, get_dyn_SMB_PASSWD_FILE());
+ string_set(&Globals.szPrivateDir, get_dyn_PRIVATE_DIR());
+
+ /* use the new 'hash2' method by default, with a prefix of 1 */
+ string_set(&Globals.szManglingMethod, "hash2");
+ Globals.mangle_prefix = 1;
+
+ string_set(&Globals.szGuestaccount, GUEST_ACCOUNT);
+
+ /* using UTF8 by default allows us to support all chars */
+ string_set(&Globals.unix_charset, DEFAULT_UNIX_CHARSET);
+
+#if defined(HAVE_NL_LANGINFO) && defined(CODESET)
+ /* If the system supports nl_langinfo(), try to grab the value
+ from the user's locale */
+ string_set(&Globals.display_charset, "LOCALE");
+#else
+ string_set(&Globals.display_charset, DEFAULT_DISPLAY_CHARSET);
+#endif
+
+ /* Use codepage 850 as a default for the dos character set */
+ string_set(&Globals.dos_charset, DEFAULT_DOS_CHARSET);
+
+ /*
+ * Allow the default PASSWD_CHAT to be overridden in local.h.
+ */
+ string_set(&Globals.szPasswdChat, DEFAULT_PASSWD_CHAT);
+
+ set_global_myname(myhostname());
+ string_set(&Globals.szNetbiosName,global_myname());
+
+ set_global_myworkgroup(WORKGROUP);
+ string_set(&Globals.szWorkgroup, lp_workgroup());
+
+ string_set(&Globals.szPasswdProgram, "");
+ string_set(&Globals.szPidDir, get_dyn_PIDDIR());
+ string_set(&Globals.szLockDir, get_dyn_LOCKDIR());
+ string_set(&Globals.szSocketAddress, "0.0.0.0");
+
+ if (asprintf(&s, "Samba %s", SAMBA_VERSION_STRING) < 0) {
+ smb_panic("init_globals: ENOMEM");
+ }
+ string_set(&Globals.szServerString, s);
+ SAFE_FREE(s);
+ if (asprintf(&s, "%d.%d", DEFAULT_MAJOR_VERSION,
+ DEFAULT_MINOR_VERSION) < 0) {
+ smb_panic("init_globals: ENOMEM");
+ }
+ string_set(&Globals.szAnnounceVersion, s);
+ SAFE_FREE(s);
+#ifdef DEVELOPER
+ string_set(&Globals.szPanicAction, "/bin/sleep 999999999");
+#endif
+
+ string_set(&Globals.szSocketOptions, DEFAULT_SOCKET_OPTIONS);
+
+ string_set(&Globals.szLogonDrive, "");
+ /* %N is the NIS auto.home server if -DAUTOHOME is used, else same as %L */
+ string_set(&Globals.szLogonHome, "\\\\%N\\%U");
+ string_set(&Globals.szLogonPath, "\\\\%N\\%U\\profile");
+
+ string_set(&Globals.szNameResolveOrder, "lmhosts wins host bcast");
+ string_set(&Globals.szPasswordServer, "*");
+
+ Globals.AlgorithmicRidBase = BASE_RID;
+
+ Globals.bLoadPrinters = True;
+ Globals.PrintcapCacheTime = 750; /* 12.5 minutes */
+
+ Globals.ConfigBackend = config_backend;
+
+ /* Was 65535 (0xFFFF). 0x4101 matches W2K and causes major speed improvements... */
+ /* Discovered by 2 days of pain by Don McCall @ HP :-). */
+ Globals.max_xmit = 0x4104;
+ Globals.max_mux = 50; /* This is *needed* for profile support. */
+ Globals.lpqcachetime = 30; /* changed to handle large print servers better -- jerry */
+ Globals.bDisableSpoolss = False;
+ Globals.iMaxSmbdProcesses = 0;/* no limit specified */
+ Globals.pwordlevel = 0;
+ Globals.unamelevel = 0;
+ Globals.deadtime = 0;
+ Globals.getwd_cache = true;
+ Globals.bLargeReadwrite = True;
+ Globals.max_log_size = 5000;
+ Globals.max_open_files = MAX_OPEN_FILES;
+ Globals.open_files_db_hash_size = SMB_OPEN_DATABASE_TDB_HASH_SIZE;
+ Globals.maxprotocol = PROTOCOL_NT1;
+ Globals.minprotocol = PROTOCOL_CORE;
+ Globals.security = SEC_USER;
+ Globals.paranoid_server_security = True;
+ Globals.bEncryptPasswords = True;
+ Globals.bUpdateEncrypt = False;
+ Globals.clientSchannel = Auto;
+ Globals.serverSchannel = Auto;
+ Globals.bReadRaw = True;
+ Globals.bWriteRaw = True;
+ Globals.bNullPasswords = False;
+ Globals.bObeyPamRestrictions = False;
+ Globals.syslog = 1;
+ Globals.bSyslogOnly = False;
+ Globals.bTimestampLogs = True;
+ string_set(&Globals.szLogLevel, "0");
+ Globals.bDebugPrefixTimestamp = False;
+ Globals.bDebugHiresTimestamp = False;
+ Globals.bDebugPid = False;
+ Globals.bDebugUid = False;
+ Globals.bDebugClass = False;
+ Globals.bEnableCoreFiles = 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.lm_announce = 2; /* = Auto: send only if LM clients found */
+ Globals.lm_interval = 60;
+ Globals.announce_as = ANNOUNCE_AS_NT_SERVER;
+#if (defined(HAVE_NETGROUP) && defined(WITH_AUTOMOUNT))
+ Globals.bNISHomeMap = False;
+#ifdef WITH_NISPLUS_HOME
+ string_set(&Globals.szNISHomeMapName, "auto_home.org_dir");
+#else
+ string_set(&Globals.szNISHomeMapName, "auto.home");
+#endif
+#endif
+ Globals.bTimeServer = False;
+ Globals.bBindInterfacesOnly = False;
+ Globals.bUnixPasswdSync = False;
+ Globals.bPamPasswordChange = False;
+ Globals.bPasswdChatDebug = False;
+ Globals.iPasswdChatTimeout = 2; /* 2 second default. */
+ Globals.bNTPipeSupport = True; /* Do NT pipes by default. */
+ Globals.bNTStatusSupport = True; /* Use NT status by default. */
+ Globals.bStatCache = True; /* use stat cache by default */
+ Globals.iMaxStatCacheSize = 256; /* 256k by default */
+ Globals.restrict_anonymous = 0;
+ Globals.bClientLanManAuth = False; /* Do NOT use the LanMan hash if it is available */
+ Globals.bClientPlaintextAuth = False; /* Do NOT use a plaintext password even if is requested by the server */
+ Globals.bLanmanAuth = False; /* Do NOT use the LanMan hash, even if it is supplied */
+ Globals.bNTLMAuth = True; /* Do use NTLMv1 if it is supplied by the client (otherwise NTLMv2) */
+ Globals.bClientNTLMv2Auth = False; /* Client should not use NTLMv2, as we can't tell that the server supports it. */
+ /* Note, that we will use NTLM2 session security (which is different), if it is available */
+
+ Globals.map_to_guest = 0; /* By Default, "Never" */
+ Globals.oplock_break_wait_time = 0; /* By Default, 0 msecs. */
+ Globals.enhanced_browsing = true;
+ Globals.iLockSpinTime = WINDOWS_MINIMUM_LOCK_TIMEOUT_MS; /* msec. */
+#ifdef MMAP_BLACKLIST
+ Globals.bUseMmap = False;
+#else
+ Globals.bUseMmap = True;
+#endif
+ Globals.bUnixExtensions = True;
+ Globals.bResetOnZeroVC = False;
+
+ /* hostname lookups can be very expensive and are broken on
+ a large number of sites (tridge) */
+ Globals.bHostnameLookups = False;
+
+ string_set(&Globals.szPassdbBackend, "smbpasswd");
+ string_set(&Globals.szLdapSuffix, "");
+ string_set(&Globals.szLdapMachineSuffix, "");
+ string_set(&Globals.szLdapUserSuffix, "");
+ string_set(&Globals.szLdapGroupSuffix, "");
+ string_set(&Globals.szLdapIdmapSuffix, "");
+
+ string_set(&Globals.szLdapAdminDn, "");
+ Globals.ldap_ssl = LDAP_SSL_ON;
+ Globals.ldap_passwd_sync = LDAP_PASSWD_SYNC_OFF;
+ Globals.ldap_delete_dn = False;
+ Globals.ldap_replication_sleep = 1000; /* wait 1 sec for replication */
+ Globals.ldap_timeout = LDAP_DEFAULT_TIMEOUT;
+ Globals.ldap_connection_timeout = LDAP_CONNECTION_DEFAULT_TIMEOUT;
+ Globals.ldap_page_size = LDAP_PAGE_SIZE;
+
+ Globals.ldap_debug_level = 0;
+ Globals.ldap_debug_threshold = 10;
+
+ /* This is what we tell the afs client. in reality we set the token
+ * to never expire, though, when this runs out the afs client will
+ * forget the token. Set to 0 to get NEVERDATE.*/
+ Globals.iAfsTokenLifetime = 604800;
+
+/* these parameters are set to defaults that are more appropriate
+ for the increasing samba install base:
+
+ as a member of the workgroup, that will possibly become a
+ _local_ master browser (lm = True). this is opposed to a forced
+ local master browser startup (pm = True).
+
+ doesn't provide WINS server service by default (wsupp = False),
+ and doesn't provide domain master browser services by default, either.
+
+*/
+
+ Globals.bMsAddPrinterWizard = True;
+ Globals.os_level = 20;
+ Globals.bLocalMaster = True;
+ Globals.iDomainMaster = Auto; /* depending on bDomainLogons */
+ Globals.bDomainLogons = False;
+ Globals.bBrowseList = True;
+ Globals.bWINSsupport = False;
+ Globals.bWINSproxy = False;
+
+ TALLOC_FREE(Globals.szInitLogonDelayedHosts);
+ Globals.InitLogonDelay = 100; /* 100 ms default delay */
+
+ Globals.bDNSproxy = True;
+
+ /* this just means to use them if they exist */
+ Globals.bKernelOplocks = True;
+
+ Globals.bAllowTrustedDomains = True;
+ string_set(&Globals.szIdmapBackend, "tdb");
+
+ string_set(&Globals.szTemplateShell, "/bin/false");
+ string_set(&Globals.szTemplateHomedir, "/home/%D/%U");
+ string_set(&Globals.szWinbindSeparator, "\\");
+
+ string_set(&Globals.szCupsServer, "");
+ string_set(&Globals.szIPrintServer, "");
+
+ string_set(&Globals.ctdbdSocket, "");
+ Globals.szClusterAddresses = NULL;
+ Globals.clustering = False;
+
+ Globals.winbind_cache_time = 300; /* 5 minutes */
+ Globals.winbind_reconnect_delay = 30; /* 30 seconds */
+ Globals.bWinbindEnumUsers = False;
+ Globals.bWinbindEnumGroups = False;
+ Globals.bWinbindUseDefaultDomain = False;
+ Globals.bWinbindTrustedDomainsOnly = False;
+ Globals.bWinbindNestedGroups = True;
+ Globals.winbind_expand_groups = 1;
+ Globals.szWinbindNssInfo = str_list_make(NULL, "template", NULL);
+ Globals.bWinbindRefreshTickets = False;
+ Globals.bWinbindOfflineLogon = False;
+
+ Globals.iIdmapCacheTime = 86400 * 7; /* a week by default */
+ Globals.iIdmapNegativeCacheTime = 120; /* 2 minutes by default */
+
+ Globals.bPassdbExpandExplicit = False;
+
+ Globals.name_cache_timeout = 660; /* In seconds */
+
+ Globals.bUseSpnego = True;
+ Globals.bClientUseSpnego = True;
+
+ Globals.client_signing = Auto;
+ Globals.server_signing = False;
+
+ Globals.bDeferSharingViolations = True;
+ string_set(&Globals.smb_ports, SMB_PORTS);
+
+ Globals.bEnablePrivileges = True;
+ Globals.bHostMSDfs = True;
+ Globals.bASUSupport = False;
+
+ /* User defined shares. */
+ if (asprintf(&s, "%s/usershares", get_dyn_STATEDIR()) < 0) {
+ smb_panic("init_globals: ENOMEM");
+ }
+ string_set(&Globals.szUsersharePath, s);
+ SAFE_FREE(s);
+ string_set(&Globals.szUsershareTemplateShare, "");
+ Globals.iUsershareMaxShares = 0;
+ /* By default disallow sharing of directories not owned by the sharer. */
+ Globals.bUsershareOwnerOnly = True;
+ /* By default disallow guest access to usershares. */
+ Globals.bUsershareAllowGuests = False;
+
+ Globals.iKeepalive = DEFAULT_KEEPALIVE;
+
+ /* By default no shares out of the registry */
+ Globals.bRegistryShares = False;
+
+ Globals.iminreceivefile = 0;
+}
+
+/*******************************************************************
+ Convenience routine to grab string parameters into temporary memory
+ and run standard_sub_basic on them. The buffers can be written to by
+ callers without affecting the source string.
+********************************************************************/
+
+static char *lp_string(const char *s)
+{
+ char *ret;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ /* The follow debug is useful for tracking down memory problems
+ especially if you have an inner loop that is calling a lp_*()
+ function that returns a string. Perhaps this debug should be
+ present all the time? */
+
+#if 0
+ DEBUG(10, ("lp_string(%s)\n", s));
+#endif
+
+ ret = talloc_sub_basic(ctx,
+ get_current_username(),
+ current_user_info.domain,
+ s);
+ if (trim_char(ret, '\"', '\"')) {
+ if (strchr(ret,'\"') != NULL) {
+ TALLOC_FREE(ret);
+ ret = talloc_sub_basic(ctx,
+ get_current_username(),
+ current_user_info.domain,
+ s);
+ }
+ }
+ return ret;
+}
+
+/*
+ In this section all the functions that are used to access the
+ parameters from the rest of the program are defined
+*/
+
+#define FN_GLOBAL_STRING(fn_name,ptr) \
+ char *fn_name(void) {return(lp_string(*(char **)(ptr) ? *(char **)(ptr) : ""));}
+#define FN_GLOBAL_CONST_STRING(fn_name,ptr) \
+ const char *fn_name(void) {return(*(const char **)(ptr) ? *(const char **)(ptr) : "");}
+#define FN_GLOBAL_LIST(fn_name,ptr) \
+ const char **fn_name(void) {return(*(const char ***)(ptr));}
+#define FN_GLOBAL_BOOL(fn_name,ptr) \
+ bool fn_name(void) {return(*(bool *)(ptr));}
+#define FN_GLOBAL_CHAR(fn_name,ptr) \
+ char fn_name(void) {return(*(char *)(ptr));}
+#define FN_GLOBAL_INTEGER(fn_name,ptr) \
+ int fn_name(void) {return(*(int *)(ptr));}
+
+#define FN_LOCAL_STRING(fn_name,val) \
+ char *fn_name(int i) {return(lp_string((LP_SNUM_OK(i) && ServicePtrs[(i)]->val) ? ServicePtrs[(i)]->val : sDefault.val));}
+#define FN_LOCAL_CONST_STRING(fn_name,val) \
+ const char *fn_name(int i) {return (const char *)((LP_SNUM_OK(i) && ServicePtrs[(i)]->val) ? ServicePtrs[(i)]->val : sDefault.val);}
+#define FN_LOCAL_LIST(fn_name,val) \
+ const char **fn_name(int i) {return(const char **)(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
+#define FN_LOCAL_BOOL(fn_name,val) \
+ bool fn_name(int i) {return(bool)(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
+#define FN_LOCAL_INTEGER(fn_name,val) \
+ int fn_name(int i) {return(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
+
+#define FN_LOCAL_PARM_BOOL(fn_name,val) \
+ bool fn_name(const struct share_params *p) {return(bool)(LP_SNUM_OK(p->service)? ServicePtrs[(p->service)]->val : sDefault.val);}
+#define FN_LOCAL_PARM_INTEGER(fn_name,val) \
+ int fn_name(const struct share_params *p) {return(LP_SNUM_OK(p->service)? ServicePtrs[(p->service)]->val : sDefault.val);}
+#define FN_LOCAL_PARM_STRING(fn_name,val) \
+ char *fn_name(const struct share_params *p) {return(lp_string((LP_SNUM_OK(p->service) && ServicePtrs[(p->service)]->val) ? ServicePtrs[(p->service)]->val : sDefault.val));}
+#define FN_LOCAL_CHAR(fn_name,val) \
+ char fn_name(const struct share_params *p) {return(LP_SNUM_OK(p->service)? ServicePtrs[(p->service)]->val : sDefault.val);}
+
+FN_GLOBAL_STRING(lp_smb_ports, &Globals.smb_ports)
+FN_GLOBAL_STRING(lp_dos_charset, &Globals.dos_charset)
+FN_GLOBAL_STRING(lp_unix_charset, &Globals.unix_charset)
+FN_GLOBAL_STRING(lp_display_charset, &Globals.display_charset)
+FN_GLOBAL_STRING(lp_logfile, &Globals.szLogFile)
+FN_GLOBAL_STRING(lp_configfile, &Globals.szConfigFile)
+FN_GLOBAL_STRING(lp_smb_passwd_file, &Globals.szSMBPasswdFile)
+FN_GLOBAL_STRING(lp_private_dir, &Globals.szPrivateDir)
+FN_GLOBAL_STRING(lp_serverstring, &Globals.szServerString)
+FN_GLOBAL_INTEGER(lp_printcap_cache_time, &Globals.PrintcapCacheTime)
+FN_GLOBAL_STRING(lp_addport_cmd, &Globals.szAddPortCommand)
+FN_GLOBAL_STRING(lp_enumports_cmd, &Globals.szEnumPortsCommand)
+FN_GLOBAL_STRING(lp_addprinter_cmd, &Globals.szAddPrinterCommand)
+FN_GLOBAL_STRING(lp_deleteprinter_cmd, &Globals.szDeletePrinterCommand)
+FN_GLOBAL_STRING(lp_os2_driver_map, &Globals.szOs2DriverMap)
+FN_GLOBAL_STRING(lp_lockdir, &Globals.szLockDir)
+FN_GLOBAL_STRING(lp_piddir, &Globals.szPidDir)
+FN_GLOBAL_STRING(lp_mangling_method, &Globals.szManglingMethod)
+FN_GLOBAL_INTEGER(lp_mangle_prefix, &Globals.mangle_prefix)
+FN_GLOBAL_STRING(lp_utmpdir, &Globals.szUtmpDir)
+FN_GLOBAL_STRING(lp_wtmpdir, &Globals.szWtmpDir)
+FN_GLOBAL_BOOL(lp_utmp, &Globals.bUtmp)
+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_get_quota_command, &Globals.szGetQuota)
+FN_GLOBAL_STRING(lp_set_quota_command, &Globals.szSetQuota)
+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_realm, &Globals.szRealm)
+FN_GLOBAL_CONST_STRING(lp_afs_username_map, &Globals.szAfsUsernameMap)
+FN_GLOBAL_INTEGER(lp_afs_token_lifetime, &Globals.iAfsTokenLifetime)
+FN_GLOBAL_STRING(lp_log_nt_token_command, &Globals.szLogNtTokenCommand)
+FN_GLOBAL_STRING(lp_username_map, &Globals.szUsernameMap)
+FN_GLOBAL_CONST_STRING(lp_logon_script, &Globals.szLogonScript)
+FN_GLOBAL_CONST_STRING(lp_logon_path, &Globals.szLogonPath)
+FN_GLOBAL_CONST_STRING(lp_logon_drive, &Globals.szLogonDrive)
+FN_GLOBAL_CONST_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_LIST(lp_wins_server_list, &Globals.szWINSservers)
+FN_GLOBAL_LIST(lp_interfaces, &Globals.szInterfaces)
+FN_GLOBAL_STRING(lp_socket_address, &Globals.szSocketAddress)
+FN_GLOBAL_STRING(lp_nis_home_map_name, &Globals.szNISHomeMapName)
+static FN_GLOBAL_STRING(lp_announce_version, &Globals.szAnnounceVersion)
+FN_GLOBAL_LIST(lp_netbios_aliases, &Globals.szNetbiosAliases)
+/* FN_GLOBAL_STRING(lp_passdb_backend, &Globals.szPassdbBackend)
+ * lp_passdb_backend() should be replace by the this macro again after
+ * some releases.
+ * */
+const char *lp_passdb_backend(void)
+{
+ char *delim, *quote;
+
+ delim = strchr( Globals.szPassdbBackend, ' ');
+ /* no space at all */
+ if (delim == NULL) {
+ goto out;
+ }
+
+ quote = strchr(Globals.szPassdbBackend, '"');
+ /* no quote char or non in the first part */
+ if (quote == NULL || quote > delim) {
+ *delim = '\0';
+ goto warn;
+ }
+
+ quote = strchr(quote+1, '"');
+ if (quote == NULL) {
+ DEBUG(0, ("WARNING: Your 'passdb backend' configuration is invalid due to a missing second \" char.\n"));
+ goto out;
+ } else if (*(quote+1) == '\0') {
+ /* space, fitting quote char, and one backend only */
+ goto out;
+ } else {
+ /* terminate string after the fitting quote char */
+ *(quote+1) = '\0';
+ }
+
+warn:
+ DEBUG(0, ("WARNING: Your 'passdb backend' configuration includes multiple backends. This\n"
+ "is deprecated since Samba 3.0.23. Please check WHATSNEW.txt or the section 'Passdb\n"
+ "Changes' from the ChangeNotes as part of the Samba HOWTO collection. Only the first\n"
+ "backend (%s) is used. The rest is ignored.\n", Globals.szPassdbBackend));
+
+out:
+ return Globals.szPassdbBackend;
+}
+FN_GLOBAL_LIST(lp_preload_modules, &Globals.szPreloadModules)
+FN_GLOBAL_STRING(lp_panic_action, &Globals.szPanicAction)
+FN_GLOBAL_STRING(lp_adduser_script, &Globals.szAddUserScript)
+FN_GLOBAL_STRING(lp_renameuser_script, &Globals.szRenameUserScript)
+FN_GLOBAL_STRING(lp_deluser_script, &Globals.szDelUserScript)
+
+FN_GLOBAL_CONST_STRING(lp_guestaccount, &Globals.szGuestaccount)
+FN_GLOBAL_STRING(lp_addgroup_script, &Globals.szAddGroupScript)
+FN_GLOBAL_STRING(lp_delgroup_script, &Globals.szDelGroupScript)
+FN_GLOBAL_STRING(lp_addusertogroup_script, &Globals.szAddUserToGroupScript)
+FN_GLOBAL_STRING(lp_deluserfromgroup_script, &Globals.szDelUserFromGroupScript)
+FN_GLOBAL_STRING(lp_setprimarygroup_script, &Globals.szSetPrimaryGroupScript)
+
+FN_GLOBAL_STRING(lp_addmachine_script, &Globals.szAddMachineScript)
+
+FN_GLOBAL_STRING(lp_shutdown_script, &Globals.szShutdownScript)
+FN_GLOBAL_STRING(lp_abort_shutdown_script, &Globals.szAbortShutdownScript)
+FN_GLOBAL_STRING(lp_username_map_script, &Globals.szUsernameMapScript)
+
+FN_GLOBAL_STRING(lp_check_password_script, &Globals.szCheckPasswordScript)
+
+FN_GLOBAL_STRING(lp_wins_hook, &Globals.szWINSHook)
+FN_GLOBAL_CONST_STRING(lp_template_homedir, &Globals.szTemplateHomedir)
+FN_GLOBAL_CONST_STRING(lp_template_shell, &Globals.szTemplateShell)
+FN_GLOBAL_CONST_STRING(lp_winbind_separator, &Globals.szWinbindSeparator)
+FN_GLOBAL_INTEGER(lp_acl_compatibility, &Globals.iAclCompat)
+FN_GLOBAL_BOOL(lp_winbind_enum_users, &Globals.bWinbindEnumUsers)
+FN_GLOBAL_BOOL(lp_winbind_enum_groups, &Globals.bWinbindEnumGroups)
+FN_GLOBAL_BOOL(lp_winbind_use_default_domain, &Globals.bWinbindUseDefaultDomain)
+FN_GLOBAL_BOOL(lp_winbind_trusted_domains_only, &Globals.bWinbindTrustedDomainsOnly)
+FN_GLOBAL_BOOL(lp_winbind_nested_groups, &Globals.bWinbindNestedGroups)
+FN_GLOBAL_INTEGER(lp_winbind_expand_groups, &Globals.winbind_expand_groups)
+FN_GLOBAL_BOOL(lp_winbind_refresh_tickets, &Globals.bWinbindRefreshTickets)
+FN_GLOBAL_BOOL(lp_winbind_offline_logon, &Globals.bWinbindOfflineLogon)
+FN_GLOBAL_BOOL(lp_winbind_normalize_names, &Globals.bWinbindNormalizeNames)
+FN_GLOBAL_BOOL(lp_winbind_rpc_only, &Globals.bWinbindRpcOnly)
+
+FN_GLOBAL_CONST_STRING(lp_idmap_backend, &Globals.szIdmapBackend)
+FN_GLOBAL_STRING(lp_idmap_alloc_backend, &Globals.szIdmapAllocBackend)
+FN_GLOBAL_INTEGER(lp_idmap_cache_time, &Globals.iIdmapCacheTime)
+FN_GLOBAL_INTEGER(lp_idmap_negative_cache_time, &Globals.iIdmapNegativeCacheTime)
+FN_GLOBAL_INTEGER(lp_keepalive, &Globals.iKeepalive)
+FN_GLOBAL_BOOL(lp_passdb_expand_explicit, &Globals.bPassdbExpandExplicit)
+
+FN_GLOBAL_STRING(lp_ldap_suffix, &Globals.szLdapSuffix)
+FN_GLOBAL_STRING(lp_ldap_admin_dn, &Globals.szLdapAdminDn)
+FN_GLOBAL_INTEGER(lp_ldap_ssl, &Globals.ldap_ssl)
+FN_GLOBAL_INTEGER(lp_ldap_passwd_sync, &Globals.ldap_passwd_sync)
+FN_GLOBAL_BOOL(lp_ldap_delete_dn, &Globals.ldap_delete_dn)
+FN_GLOBAL_INTEGER(lp_ldap_replication_sleep, &Globals.ldap_replication_sleep)
+FN_GLOBAL_INTEGER(lp_ldap_timeout, &Globals.ldap_timeout)
+FN_GLOBAL_INTEGER(lp_ldap_connection_timeout, &Globals.ldap_connection_timeout)
+FN_GLOBAL_INTEGER(lp_ldap_page_size, &Globals.ldap_page_size)
+FN_GLOBAL_INTEGER(lp_ldap_debug_level, &Globals.ldap_debug_level)
+FN_GLOBAL_INTEGER(lp_ldap_debug_threshold, &Globals.ldap_debug_threshold)
+FN_GLOBAL_STRING(lp_add_share_cmd, &Globals.szAddShareCommand)
+FN_GLOBAL_STRING(lp_change_share_cmd, &Globals.szChangeShareCommand)
+FN_GLOBAL_STRING(lp_delete_share_cmd, &Globals.szDeleteShareCommand)
+FN_GLOBAL_STRING(lp_usershare_path, &Globals.szUsersharePath)
+FN_GLOBAL_LIST(lp_usershare_prefix_allow_list, &Globals.szUsersharePrefixAllowList)
+FN_GLOBAL_LIST(lp_usershare_prefix_deny_list, &Globals.szUsersharePrefixDenyList)
+
+FN_GLOBAL_LIST(lp_eventlog_list, &Globals.szEventLogs)
+
+FN_GLOBAL_BOOL(lp_registry_shares, &Globals.bRegistryShares)
+FN_GLOBAL_BOOL(lp_usershare_allow_guests, &Globals.bUsershareAllowGuests)
+FN_GLOBAL_BOOL(lp_usershare_owner_only, &Globals.bUsershareOwnerOnly)
+FN_GLOBAL_BOOL(lp_disable_netbios, &Globals.bDisableNetbios)
+FN_GLOBAL_BOOL(lp_reset_on_zero_vc, &Globals.bResetOnZeroVC)
+FN_GLOBAL_BOOL(lp_ms_add_printer_wizard, &Globals.bMsAddPrinterWizard)
+FN_GLOBAL_BOOL(lp_dns_proxy, &Globals.bDNSproxy)
+FN_GLOBAL_BOOL(lp_wins_support, &Globals.bWINSsupport)
+FN_GLOBAL_BOOL(lp_we_are_a_wins_server, &Globals.bWINSsupport)
+FN_GLOBAL_BOOL(lp_wins_proxy, &Globals.bWINSproxy)
+FN_GLOBAL_BOOL(lp_local_master, &Globals.bLocalMaster)
+FN_GLOBAL_BOOL(lp_domain_logons, &Globals.bDomainLogons)
+FN_GLOBAL_LIST(lp_init_logon_delayed_hosts, &Globals.szInitLogonDelayedHosts)
+FN_GLOBAL_INTEGER(lp_init_logon_delay, &Globals.InitLogonDelay)
+FN_GLOBAL_BOOL(lp_load_printers, &Globals.bLoadPrinters)
+FN_GLOBAL_BOOL(lp_readraw, &Globals.bReadRaw)
+FN_GLOBAL_BOOL(lp_large_readwrite, &Globals.bLargeReadwrite)
+FN_GLOBAL_BOOL(lp_writeraw, &Globals.bWriteRaw)
+FN_GLOBAL_BOOL(lp_null_passwords, &Globals.bNullPasswords)
+FN_GLOBAL_BOOL(lp_obey_pam_restrictions, &Globals.bObeyPamRestrictions)
+FN_GLOBAL_BOOL(lp_encrypted_passwords, &Globals.bEncryptPasswords)
+FN_GLOBAL_BOOL(lp_update_encrypted, &Globals.bUpdateEncrypt)
+FN_GLOBAL_INTEGER(lp_client_schannel, &Globals.clientSchannel)
+FN_GLOBAL_INTEGER(lp_server_schannel, &Globals.serverSchannel)
+FN_GLOBAL_BOOL(lp_syslog_only, &Globals.bSyslogOnly)
+FN_GLOBAL_BOOL(lp_timestamp_logs, &Globals.bTimestampLogs)
+FN_GLOBAL_BOOL(lp_debug_prefix_timestamp, &Globals.bDebugPrefixTimestamp)
+FN_GLOBAL_BOOL(lp_debug_hires_timestamp, &Globals.bDebugHiresTimestamp)
+FN_GLOBAL_BOOL(lp_debug_pid, &Globals.bDebugPid)
+FN_GLOBAL_BOOL(lp_debug_uid, &Globals.bDebugUid)
+FN_GLOBAL_BOOL(lp_debug_class, &Globals.bDebugClass)
+FN_GLOBAL_BOOL(lp_enable_core_files, &Globals.bEnableCoreFiles)
+FN_GLOBAL_BOOL(lp_browse_list, &Globals.bBrowseList)
+FN_GLOBAL_BOOL(lp_nis_home_map, &Globals.bNISHomeMap)
+static FN_GLOBAL_BOOL(lp_time_server, &Globals.bTimeServer)
+FN_GLOBAL_BOOL(lp_bind_interfaces_only, &Globals.bBindInterfacesOnly)
+FN_GLOBAL_BOOL(lp_pam_password_change, &Globals.bPamPasswordChange)
+FN_GLOBAL_BOOL(lp_unix_password_sync, &Globals.bUnixPasswdSync)
+FN_GLOBAL_BOOL(lp_passwd_chat_debug, &Globals.bPasswdChatDebug)
+FN_GLOBAL_INTEGER(lp_passwd_chat_timeout, &Globals.iPasswdChatTimeout)
+FN_GLOBAL_BOOL(lp_nt_pipe_support, &Globals.bNTPipeSupport)
+FN_GLOBAL_BOOL(lp_nt_status_support, &Globals.bNTStatusSupport)
+FN_GLOBAL_BOOL(lp_stat_cache, &Globals.bStatCache)
+FN_GLOBAL_INTEGER(lp_max_stat_cache_size, &Globals.iMaxStatCacheSize)
+FN_GLOBAL_BOOL(lp_allow_trusted_domains, &Globals.bAllowTrustedDomains)
+FN_GLOBAL_INTEGER(lp_restrict_anonymous, &Globals.restrict_anonymous)
+FN_GLOBAL_BOOL(lp_lanman_auth, &Globals.bLanmanAuth)
+FN_GLOBAL_BOOL(lp_ntlm_auth, &Globals.bNTLMAuth)
+FN_GLOBAL_BOOL(lp_client_plaintext_auth, &Globals.bClientPlaintextAuth)
+FN_GLOBAL_BOOL(lp_client_lanman_auth, &Globals.bClientLanManAuth)
+FN_GLOBAL_BOOL(lp_client_ntlmv2_auth, &Globals.bClientNTLMv2Auth)
+FN_GLOBAL_BOOL(lp_host_msdfs, &Globals.bHostMSDfs)
+FN_GLOBAL_BOOL(lp_kernel_oplocks, &Globals.bKernelOplocks)
+FN_GLOBAL_BOOL(lp_enhanced_browsing, &Globals.enhanced_browsing)
+FN_GLOBAL_BOOL(lp_use_mmap, &Globals.bUseMmap)
+FN_GLOBAL_BOOL(lp_unix_extensions, &Globals.bUnixExtensions)
+FN_GLOBAL_BOOL(lp_use_spnego, &Globals.bUseSpnego)
+FN_GLOBAL_BOOL(lp_client_use_spnego, &Globals.bClientUseSpnego)
+FN_GLOBAL_BOOL(lp_hostname_lookups, &Globals.bHostnameLookups)
+FN_LOCAL_PARM_BOOL(lp_change_notify, bChangeNotify)
+FN_LOCAL_PARM_BOOL(lp_kernel_change_notify, bKernelChangeNotify)
+FN_GLOBAL_BOOL(lp_use_kerberos_keytab, &Globals.bUseKerberosKeytab)
+FN_GLOBAL_BOOL(lp_defer_sharing_violations, &Globals.bDeferSharingViolations)
+FN_GLOBAL_BOOL(lp_enable_privileges, &Globals.bEnablePrivileges)
+FN_GLOBAL_BOOL(lp_enable_asu_support, &Globals.bASUSupport)
+FN_GLOBAL_INTEGER(lp_os_level, &Globals.os_level)
+FN_GLOBAL_INTEGER(lp_max_ttl, &Globals.max_ttl)
+FN_GLOBAL_INTEGER(lp_max_wins_ttl, &Globals.max_wins_ttl)
+FN_GLOBAL_INTEGER(lp_min_wins_ttl, &Globals.min_wins_ttl)
+FN_GLOBAL_INTEGER(lp_max_log_size, &Globals.max_log_size)
+FN_GLOBAL_INTEGER(lp_max_open_files, &Globals.max_open_files)
+FN_GLOBAL_INTEGER(lp_open_files_db_hash_size, &Globals.open_files_db_hash_size)
+FN_GLOBAL_INTEGER(lp_maxxmit, &Globals.max_xmit)
+FN_GLOBAL_INTEGER(lp_maxmux, &Globals.max_mux)
+FN_GLOBAL_INTEGER(lp_passwordlevel, &Globals.pwordlevel)
+FN_GLOBAL_INTEGER(lp_usernamelevel, &Globals.unamelevel)
+FN_GLOBAL_INTEGER(lp_deadtime, &Globals.deadtime)
+FN_GLOBAL_BOOL(lp_getwd_cache, &Globals.getwd_cache)
+FN_GLOBAL_INTEGER(lp_maxprotocol, &Globals.maxprotocol)
+FN_GLOBAL_INTEGER(lp_minprotocol, &Globals.minprotocol)
+FN_GLOBAL_INTEGER(lp_security, &Globals.security)
+FN_GLOBAL_LIST(lp_auth_methods, &Globals.AuthMethods)
+FN_GLOBAL_BOOL(lp_paranoid_server_security, &Globals.paranoid_server_security)
+FN_GLOBAL_INTEGER(lp_maxdisksize, &Globals.maxdisksize)
+FN_GLOBAL_INTEGER(lp_lpqcachetime, &Globals.lpqcachetime)
+FN_GLOBAL_INTEGER(lp_max_smbd_processes, &Globals.iMaxSmbdProcesses)
+FN_GLOBAL_BOOL(_lp_disable_spoolss, &Globals.bDisableSpoolss)
+FN_GLOBAL_INTEGER(lp_syslog, &Globals.syslog)
+static FN_GLOBAL_INTEGER(lp_announce_as, &Globals.announce_as)
+FN_GLOBAL_INTEGER(lp_lm_announce, &Globals.lm_announce)
+FN_GLOBAL_INTEGER(lp_lm_interval, &Globals.lm_interval)
+FN_GLOBAL_INTEGER(lp_machine_password_timeout, &Globals.machine_password_timeout)
+FN_GLOBAL_INTEGER(lp_map_to_guest, &Globals.map_to_guest)
+FN_GLOBAL_INTEGER(lp_oplock_break_wait_time, &Globals.oplock_break_wait_time)
+FN_GLOBAL_INTEGER(lp_lock_spin_time, &Globals.iLockSpinTime)
+FN_GLOBAL_INTEGER(lp_usershare_max_shares, &Globals.iUsershareMaxShares)
+FN_GLOBAL_CONST_STRING(lp_socket_options, &Globals.szSocketOptions)
+FN_GLOBAL_INTEGER(lp_config_backend, &Globals.ConfigBackend)
+
+FN_LOCAL_STRING(lp_preexec, szPreExec)
+FN_LOCAL_STRING(lp_postexec, szPostExec)
+FN_LOCAL_STRING(lp_rootpreexec, szRootPreExec)
+FN_LOCAL_STRING(lp_rootpostexec, szRootPostExec)
+FN_LOCAL_STRING(lp_servicename, szService)
+FN_LOCAL_CONST_STRING(lp_const_servicename, szService)
+FN_LOCAL_STRING(lp_pathname, szPath)
+FN_LOCAL_STRING(lp_dontdescend, szDontdescend)
+FN_LOCAL_STRING(lp_username, szUsername)
+FN_LOCAL_LIST(lp_invalid_users, szInvalidUsers)
+FN_LOCAL_LIST(lp_valid_users, szValidUsers)
+FN_LOCAL_LIST(lp_admin_users, szAdminUsers)
+FN_GLOBAL_LIST(lp_svcctl_list, &Globals.szServicesList)
+FN_LOCAL_STRING(lp_cups_options, szCupsOptions)
+FN_GLOBAL_STRING(lp_cups_server, &Globals.szCupsServer)
+FN_GLOBAL_STRING(lp_iprint_server, &Globals.szIPrintServer)
+FN_GLOBAL_CONST_STRING(lp_ctdbd_socket, &Globals.ctdbdSocket)
+FN_GLOBAL_LIST(lp_cluster_addresses, &Globals.szClusterAddresses)
+FN_GLOBAL_BOOL(lp_clustering, &Globals.clustering)
+FN_LOCAL_STRING(lp_printcommand, szPrintcommand)
+FN_LOCAL_STRING(lp_lpqcommand, szLpqcommand)
+FN_LOCAL_STRING(lp_lprmcommand, szLprmcommand)
+FN_LOCAL_STRING(lp_lppausecommand, szLppausecommand)
+FN_LOCAL_STRING(lp_lpresumecommand, szLpresumecommand)
+FN_LOCAL_STRING(lp_queuepausecommand, szQueuepausecommand)
+FN_LOCAL_STRING(lp_queueresumecommand, szQueueresumecommand)
+static FN_LOCAL_STRING(_lp_printername, szPrintername)
+FN_LOCAL_CONST_STRING(lp_printjob_username, szPrintjobUsername)
+FN_LOCAL_LIST(lp_hostsallow, szHostsallow)
+FN_LOCAL_LIST(lp_hostsdeny, szHostsdeny)
+FN_LOCAL_STRING(lp_magicscript, szMagicScript)
+FN_LOCAL_STRING(lp_magicoutput, szMagicOutput)
+FN_LOCAL_STRING(lp_comment, comment)
+FN_LOCAL_STRING(lp_force_user, force_user)
+FN_LOCAL_STRING(lp_force_group, force_group)
+FN_LOCAL_LIST(lp_readlist, readlist)
+FN_LOCAL_LIST(lp_writelist, writelist)
+FN_LOCAL_LIST(lp_printer_admin, printer_admin)
+FN_LOCAL_STRING(lp_fstype, fstype)
+FN_LOCAL_LIST(lp_vfs_objects, szVfsObjects)
+FN_LOCAL_STRING(lp_msdfs_proxy, szMSDfsProxy)
+static FN_LOCAL_STRING(lp_volume, volume)
+FN_LOCAL_STRING(lp_veto_files, szVetoFiles)
+FN_LOCAL_STRING(lp_hide_files, szHideFiles)
+FN_LOCAL_STRING(lp_veto_oplocks, szVetoOplockFiles)
+FN_LOCAL_BOOL(lp_msdfs_root, bMSDfsRoot)
+FN_LOCAL_STRING(lp_aio_write_behind, szAioWriteBehind)
+FN_LOCAL_STRING(lp_dfree_command, szDfree)
+FN_LOCAL_BOOL(lp_autoloaded, autoloaded)
+FN_LOCAL_BOOL(lp_preexec_close, bPreexecClose)
+FN_LOCAL_BOOL(lp_rootpreexec_close, bRootpreexecClose)
+FN_LOCAL_INTEGER(lp_casesensitive, iCaseSensitive)
+FN_LOCAL_BOOL(lp_preservecase, bCasePreserve)
+FN_LOCAL_BOOL(lp_shortpreservecase, bShortCasePreserve)
+FN_LOCAL_BOOL(lp_hide_dot_files, bHideDotFiles)
+FN_LOCAL_BOOL(lp_hide_special_files, bHideSpecialFiles)
+FN_LOCAL_BOOL(lp_hideunreadable, bHideUnReadable)
+FN_LOCAL_BOOL(lp_hideunwriteable_files, bHideUnWriteableFiles)
+FN_LOCAL_BOOL(lp_browseable, bBrowseable)
+FN_LOCAL_BOOL(lp_readonly, bRead_only)
+FN_LOCAL_BOOL(lp_no_set_dir, bNo_set_dir)
+FN_LOCAL_BOOL(lp_guest_ok, bGuest_ok)
+FN_LOCAL_BOOL(lp_guest_only, bGuest_only)
+FN_LOCAL_BOOL(lp_administrative_share, bAdministrative_share)
+FN_LOCAL_BOOL(lp_print_ok, bPrint_ok)
+FN_LOCAL_BOOL(lp_map_hidden, bMap_hidden)
+FN_LOCAL_BOOL(lp_map_archive, bMap_archive)
+FN_LOCAL_BOOL(lp_store_dos_attributes, bStoreDosAttributes)
+FN_LOCAL_BOOL(lp_dmapi_support, bDmapiSupport)
+FN_LOCAL_PARM_BOOL(lp_locking, bLocking)
+FN_LOCAL_PARM_INTEGER(lp_strict_locking, iStrictLocking)
+FN_LOCAL_PARM_BOOL(lp_posix_locking, bPosixLocking)
+FN_LOCAL_BOOL(lp_share_modes, bShareModes)
+FN_LOCAL_BOOL(lp_oplocks, bOpLocks)
+FN_LOCAL_BOOL(lp_level2_oplocks, bLevel2OpLocks)
+FN_LOCAL_BOOL(lp_onlyuser, bOnlyUser)
+FN_LOCAL_PARM_BOOL(lp_manglednames, bMangledNames)
+FN_LOCAL_BOOL(lp_widelinks, bWidelinks)
+FN_LOCAL_BOOL(lp_symlinks, bSymlinks)
+FN_LOCAL_BOOL(lp_syncalways, bSyncAlways)
+FN_LOCAL_BOOL(lp_strict_allocate, bStrictAllocate)
+FN_LOCAL_BOOL(lp_strict_sync, bStrictSync)
+FN_LOCAL_BOOL(lp_map_system, bMap_system)
+FN_LOCAL_BOOL(lp_delete_readonly, bDeleteReadonly)
+FN_LOCAL_BOOL(lp_fake_oplocks, bFakeOplocks)
+FN_LOCAL_BOOL(lp_recursive_veto_delete, bDeleteVetoFiles)
+FN_LOCAL_BOOL(lp_dos_filemode, bDosFilemode)
+FN_LOCAL_BOOL(lp_dos_filetimes, bDosFiletimes)
+FN_LOCAL_BOOL(lp_dos_filetime_resolution, bDosFiletimeResolution)
+FN_LOCAL_BOOL(lp_fake_dir_create_times, bFakeDirCreateTimes)
+FN_LOCAL_BOOL(lp_blocking_locks, bBlockingLocks)
+FN_LOCAL_BOOL(lp_inherit_perms, bInheritPerms)
+FN_LOCAL_BOOL(lp_inherit_acls, bInheritACLS)
+FN_LOCAL_BOOL(lp_inherit_owner, bInheritOwner)
+FN_LOCAL_BOOL(lp_use_client_driver, bUseClientDriver)
+FN_LOCAL_BOOL(lp_default_devmode, bDefaultDevmode)
+FN_LOCAL_BOOL(lp_force_printername, bForcePrintername)
+FN_LOCAL_BOOL(lp_nt_acl_support, bNTAclSupport)
+FN_LOCAL_BOOL(lp_force_unknown_acl_user, bForceUnknownAclUser)
+FN_LOCAL_BOOL(lp_ea_support, bEASupport)
+FN_LOCAL_BOOL(_lp_use_sendfile, bUseSendfile)
+FN_LOCAL_BOOL(lp_profile_acls, bProfileAcls)
+FN_LOCAL_BOOL(lp_map_acl_inherit, bMap_acl_inherit)
+FN_LOCAL_BOOL(lp_afs_share, bAfs_Share)
+FN_LOCAL_BOOL(lp_acl_check_permissions, bAclCheckPermissions)
+FN_LOCAL_BOOL(lp_acl_group_control, bAclGroupControl)
+FN_LOCAL_BOOL(lp_acl_map_full_control, bAclMapFullControl)
+FN_LOCAL_INTEGER(lp_create_mask, iCreate_mask)
+FN_LOCAL_INTEGER(lp_force_create_mode, iCreate_force_mode)
+FN_LOCAL_INTEGER(lp_security_mask, iSecurity_mask)
+FN_LOCAL_INTEGER(lp_force_security_mode, iSecurity_force_mode)
+FN_LOCAL_INTEGER(lp_dir_mask, iDir_mask)
+FN_LOCAL_INTEGER(lp_force_dir_mode, iDir_force_mode)
+FN_LOCAL_INTEGER(lp_dir_security_mask, iDir_Security_mask)
+FN_LOCAL_INTEGER(lp_force_dir_security_mode, iDir_Security_force_mode)
+FN_LOCAL_INTEGER(lp_max_connections, iMaxConnections)
+FN_LOCAL_INTEGER(lp_defaultcase, iDefaultCase)
+FN_LOCAL_INTEGER(lp_minprintspace, iMinPrintSpace)
+FN_LOCAL_INTEGER(lp_printing, iPrinting)
+FN_LOCAL_INTEGER(lp_max_reported_jobs, iMaxReportedPrintJobs)
+FN_LOCAL_INTEGER(lp_oplock_contention_limit, iOplockContentionLimit)
+FN_LOCAL_INTEGER(lp_csc_policy, iCSCPolicy)
+FN_LOCAL_INTEGER(lp_write_cache_size, iWriteCacheSize)
+FN_LOCAL_INTEGER(lp_block_size, iBlock_size)
+FN_LOCAL_INTEGER(lp_dfree_cache_time, iDfreeCacheTime)
+FN_LOCAL_INTEGER(lp_allocation_roundup_size, iallocation_roundup_size)
+FN_LOCAL_INTEGER(lp_aio_read_size, iAioReadSize)
+FN_LOCAL_INTEGER(lp_aio_write_size, iAioWriteSize)
+FN_LOCAL_INTEGER(lp_map_readonly, iMap_readonly)
+FN_LOCAL_INTEGER(lp_directory_name_cache_size, iDirectoryNameCacheSize)
+FN_LOCAL_INTEGER(lp_smb_encrypt, ismb_encrypt)
+FN_LOCAL_CHAR(lp_magicchar, magic_char)
+FN_GLOBAL_INTEGER(lp_winbind_cache_time, &Globals.winbind_cache_time)
+FN_GLOBAL_INTEGER(lp_winbind_reconnect_delay, &Globals.winbind_reconnect_delay)
+FN_GLOBAL_LIST(lp_winbind_nss_info, &Globals.szWinbindNssInfo)
+FN_GLOBAL_INTEGER(lp_algorithmic_rid_base, &Globals.AlgorithmicRidBase)
+FN_GLOBAL_INTEGER(lp_name_cache_timeout, &Globals.name_cache_timeout)
+FN_GLOBAL_INTEGER(lp_client_signing, &Globals.client_signing)
+FN_GLOBAL_INTEGER(lp_server_signing, &Globals.server_signing)
+FN_GLOBAL_INTEGER(lp_client_ldap_sasl_wrapping, &Globals.client_ldap_sasl_wrapping)
+
+/* local prototypes */
+
+static int map_parameter(const char *pszParmName);
+static int map_parameter_canonical(const char *pszParmName, bool *inverse);
+static bool set_boolean(bool *pb, const char *pszParmValue);
+static const char *get_boolean(bool bool_value);
+static int getservicebyname(const char *pszServiceName,
+ struct service *pserviceDest);
+static void copy_service(struct service *pserviceDest,
+ struct service *pserviceSource,
+ struct bitmap *pcopymapDest);
+static bool do_parameter(const char *pszParmName, const char *pszParmValue,
+ void *userdata);
+static bool do_section(const char *pszSectionName, void *userdata);
+static void init_copymap(struct service *pservice);
+static bool hash_a_service(const char *name, int number);
+static void free_service_byindex(int iService);
+static char * canonicalize_servicename(const char *name);
+static void show_parameter(int parmIndex);
+static bool is_synonym_of(int parm1, int parm2, bool *inverse);
+
+/*
+ * This is a helper function for parametrical options support. It returns a
+ * pointer to parametrical option value if it exists or NULL otherwise. Actual
+ * parametrical functions are quite simple
+ */
+static struct param_opt_struct *get_parametrics(int snum, const char *type,
+ const char *option)
+{
+ bool global_section = False;
+ char* param_key;
+ struct param_opt_struct *data;
+
+ if (snum >= iNumServices) return NULL;
+
+ if (snum < 0) {
+ data = Globals.param_opt;
+ global_section = True;
+ } else {
+ data = ServicePtrs[snum]->param_opt;
+ }
+
+ if (asprintf(&param_key, "%s:%s", type, option) == -1) {
+ DEBUG(0,("asprintf failed!\n"));
+ return NULL;
+ }
+
+ while (data) {
+ if (strwicmp(data->key, param_key) == 0) {
+ string_free(&param_key);
+ return data;
+ }
+ data = data->next;
+ }
+
+ if (!global_section) {
+ /* Try to fetch the same option but from globals */
+ /* but only if we are not already working with Globals */
+ data = Globals.param_opt;
+ while (data) {
+ if (strwicmp(data->key, param_key) == 0) {
+ string_free(&param_key);
+ return data;
+ }
+ data = data->next;
+ }
+ }
+
+ string_free(&param_key);
+
+ return NULL;
+}
+
+
+#define MISSING_PARAMETER(name) \
+ DEBUG(0, ("%s(): value is NULL or empty!\n", #name))
+
+/*******************************************************************
+convenience routine to return int parameters.
+********************************************************************/
+static int lp_int(const char *s)
+{
+
+ if (!s || !*s) {
+ MISSING_PARAMETER(lp_int);
+ return (-1);
+ }
+
+ return (int)strtol(s, NULL, 0);
+}
+
+/*******************************************************************
+convenience routine to return unsigned long parameters.
+********************************************************************/
+static unsigned long lp_ulong(const char *s)
+{
+
+ if (!s || !*s) {
+ MISSING_PARAMETER(lp_ulong);
+ return (0);
+ }
+
+ return strtoul(s, NULL, 0);
+}
+
+/*******************************************************************
+convenience routine to return boolean parameters.
+********************************************************************/
+static bool lp_bool(const char *s)
+{
+ bool ret = False;
+
+ if (!s || !*s) {
+ MISSING_PARAMETER(lp_bool);
+ return False;
+ }
+
+ if (!set_boolean(&ret,s)) {
+ DEBUG(0,("lp_bool(%s): value is not boolean!\n",s));
+ return False;
+ }
+
+ return ret;
+}
+
+/*******************************************************************
+convenience routine to return enum parameters.
+********************************************************************/
+static int lp_enum(const char *s,const struct enum_list *_enum)
+{
+ int i;
+
+ if (!s || !*s || !_enum) {
+ MISSING_PARAMETER(lp_enum);
+ return (-1);
+ }
+
+ for (i=0; _enum[i].name; i++) {
+ if (strequal(_enum[i].name,s))
+ return _enum[i].value;
+ }
+
+ DEBUG(0,("lp_enum(%s,enum): value is not in enum_list!\n",s));
+ return (-1);
+}
+
+#undef MISSING_PARAMETER
+
+/* DO NOT USE lp_parm_string ANYMORE!!!!
+ * use lp_parm_const_string or lp_parm_talloc_string
+ *
+ * lp_parm_string is only used to let old modules find this symbol
+ */
+#undef lp_parm_string
+ char *lp_parm_string(const char *servicename, const char *type, const char *option);
+ char *lp_parm_string(const char *servicename, const char *type, const char *option)
+{
+ return lp_parm_talloc_string(lp_servicenumber(servicename), type, option, NULL);
+}
+
+/* Return parametric option from a given service. Type is a part of option before ':' */
+/* Parametric option has following syntax: 'Type: option = value' */
+/* the returned value is talloced on the talloc_tos() */
+char *lp_parm_talloc_string(int snum, const char *type, const char *option, const char *def)
+{
+ struct param_opt_struct *data = get_parametrics(snum, type, option);
+
+ if (data == NULL||data->value==NULL) {
+ if (def) {
+ return lp_string(def);
+ } else {
+ return NULL;
+ }
+ }
+
+ return lp_string(data->value);
+}
+
+/* Return parametric option from a given service. Type is a part of option before ':' */
+/* Parametric option has following syntax: 'Type: option = value' */
+const char *lp_parm_const_string(int snum, const char *type, const char *option, const char *def)
+{
+ struct param_opt_struct *data = get_parametrics(snum, type, option);
+
+ if (data == NULL||data->value==NULL)
+ return def;
+
+ return data->value;
+}
+
+/* Return parametric option from a given service. Type is a part of option before ':' */
+/* Parametric option has following syntax: 'Type: option = value' */
+
+const char **lp_parm_string_list(int snum, const char *type, const char *option, const char **def)
+{
+ struct param_opt_struct *data = get_parametrics(snum, type, option);
+
+ if (data == NULL||data->value==NULL)
+ return (const char **)def;
+
+ if (data->list==NULL) {
+ data->list = str_list_make(NULL, data->value, NULL);
+ }
+
+ return (const char **)data->list;
+}
+
+/* Return parametric option from a given service. Type is a part of option before ':' */
+/* Parametric option has following syntax: 'Type: option = value' */
+
+int lp_parm_int(int snum, const char *type, const char *option, int def)
+{
+ struct param_opt_struct *data = get_parametrics(snum, type, option);
+
+ if (data && data->value && *data->value)
+ return lp_int(data->value);
+
+ return def;
+}
+
+/* Return parametric option from a given service. Type is a part of option before ':' */
+/* Parametric option has following syntax: 'Type: option = value' */
+
+unsigned long lp_parm_ulong(int snum, const char *type, const char *option, unsigned long def)
+{
+ struct param_opt_struct *data = get_parametrics(snum, type, option);
+
+ if (data && data->value && *data->value)
+ return lp_ulong(data->value);
+
+ return def;
+}
+
+/* Return parametric option from a given service. Type is a part of option before ':' */
+/* Parametric option has following syntax: 'Type: option = value' */
+
+bool lp_parm_bool(int snum, const char *type, const char *option, bool def)
+{
+ struct param_opt_struct *data = get_parametrics(snum, type, option);
+
+ if (data && data->value && *data->value)
+ return lp_bool(data->value);
+
+ return def;
+}
+
+/* Return parametric option from a given service. Type is a part of option before ':' */
+/* Parametric option has following syntax: 'Type: option = value' */
+
+int lp_parm_enum(int snum, const char *type, const char *option,
+ const struct enum_list *_enum, int def)
+{
+ struct param_opt_struct *data = get_parametrics(snum, type, option);
+
+ if (data && data->value && *data->value && _enum)
+ return lp_enum(data->value, _enum);
+
+ return def;
+}
+
+
+/***************************************************************************
+ Initialise a service to the defaults.
+***************************************************************************/
+
+static void init_service(struct service *pservice)
+{
+ memset((char *)pservice, '\0', sizeof(struct service));
+ copy_service(pservice, &sDefault, NULL);
+}
+
+/***************************************************************************
+ Free the dynamically allocated parts of a service struct.
+***************************************************************************/
+
+static void free_service(struct service *pservice)
+{
+ int i;
+ struct param_opt_struct *data, *pdata;
+ if (!pservice)
+ return;
+
+ if (pservice->szService)
+ DEBUG(5, ("free_service: Freeing service %s\n",
+ pservice->szService));
+
+ string_free(&pservice->szService);
+ bitmap_free(pservice->copymap);
+
+ for (i = 0; parm_table[i].label; i++) {
+ if ((parm_table[i].type == P_STRING ||
+ parm_table[i].type == P_USTRING) &&
+ parm_table[i].p_class == P_LOCAL)
+ string_free((char **)
+ (((char *)pservice) +
+ PTR_DIFF(parm_table[i].ptr, &sDefault)));
+ else if (parm_table[i].type == P_LIST &&
+ parm_table[i].p_class == P_LOCAL)
+ TALLOC_FREE(*((char ***)
+ (((char *)pservice) +
+ PTR_DIFF(parm_table[i].ptr,
+ &sDefault))));
+ }
+
+ data = pservice->param_opt;
+ if (data)
+ DEBUG(5,("Freeing parametrics:\n"));
+ while (data) {
+ DEBUG(5,("[%s = %s]\n", data->key, data->value));
+ string_free(&data->key);
+ string_free(&data->value);
+ TALLOC_FREE(data->list);
+ pdata = data->next;
+ SAFE_FREE(data);
+ data = pdata;
+ }
+
+ ZERO_STRUCTP(pservice);
+}
+
+
+/***************************************************************************
+ remove a service indexed in the ServicePtrs array from the ServiceHash
+ and free the dynamically allocated parts
+***************************************************************************/
+
+static void free_service_byindex(int idx)
+{
+ if ( !LP_SNUM_OK(idx) )
+ return;
+
+ ServicePtrs[idx]->valid = False;
+ invalid_services[num_invalid_services++] = idx;
+
+ /* we have to cleanup the hash record */
+
+ if (ServicePtrs[idx]->szService) {
+ char *canon_name = canonicalize_servicename(
+ ServicePtrs[idx]->szService );
+
+ dbwrap_delete_bystring(ServiceHash, canon_name );
+ TALLOC_FREE(canon_name);
+ }
+
+ free_service(ServicePtrs[idx]);
+}
+
+/***************************************************************************
+ Add a new service to the services array initialising it with the given
+ service.
+***************************************************************************/
+
+static int add_a_service(const struct service *pservice, const char *name)
+{
+ int i;
+ struct service tservice;
+ int num_to_alloc = iNumServices + 1;
+ struct param_opt_struct *data, *pdata;
+
+ tservice = *pservice;
+
+ /* it might already exist */
+ if (name) {
+ i = getservicebyname(name, NULL);
+ if (i >= 0) {
+ /* Clean all parametric options for service */
+ /* They will be added during parsing again */
+ data = ServicePtrs[i]->param_opt;
+ while (data) {
+ string_free(&data->key);
+ string_free(&data->value);
+ TALLOC_FREE(data->list);
+ pdata = data->next;
+ SAFE_FREE(data);
+ data = pdata;
+ }
+ ServicePtrs[i]->param_opt = NULL;
+ return (i);
+ }
+ }
+
+ /* find an invalid one */
+ i = iNumServices;
+ if (num_invalid_services > 0) {
+ i = invalid_services[--num_invalid_services];
+ }
+
+ /* if not, then create one */
+ if (i == iNumServices) {
+ struct service **tsp;
+ int *tinvalid;
+
+ tsp = SMB_REALLOC_ARRAY_KEEP_OLD_ON_ERROR(ServicePtrs, struct service *, num_to_alloc);
+ if (tsp == NULL) {
+ DEBUG(0,("add_a_service: failed to enlarge ServicePtrs!\n"));
+ return (-1);
+ }
+ ServicePtrs = tsp;
+ ServicePtrs[iNumServices] = SMB_MALLOC_P(struct service);
+ if (!ServicePtrs[iNumServices]) {
+ DEBUG(0,("add_a_service: out of memory!\n"));
+ return (-1);
+ }
+ iNumServices++;
+
+ /* enlarge invalid_services here for now... */
+ tinvalid = SMB_REALLOC_ARRAY_KEEP_OLD_ON_ERROR(invalid_services, int,
+ num_to_alloc);
+ if (tinvalid == NULL) {
+ DEBUG(0,("add_a_service: failed to enlarge "
+ "invalid_services!\n"));
+ return (-1);
+ }
+ invalid_services = tinvalid;
+ } else {
+ free_service_byindex(i);
+ }
+
+ ServicePtrs[i]->valid = True;
+
+ init_service(ServicePtrs[i]);
+ copy_service(ServicePtrs[i], &tservice, NULL);
+ if (name)
+ string_set(&ServicePtrs[i]->szService, name);
+
+ DEBUG(8,("add_a_service: Creating snum = %d for %s\n",
+ i, ServicePtrs[i]->szService));
+
+ if (!hash_a_service(ServicePtrs[i]->szService, i)) {
+ return (-1);
+ }
+
+ return (i);
+}
+
+/***************************************************************************
+ Convert a string to uppercase and remove whitespaces.
+***************************************************************************/
+
+static char *canonicalize_servicename(const char *src)
+{
+ char *result;
+
+ if ( !src ) {
+ DEBUG(0,("canonicalize_servicename: NULL source name!\n"));
+ return NULL;
+ }
+
+ result = talloc_strdup(talloc_tos(), src);
+ SMB_ASSERT(result != NULL);
+
+ strlower_m(result);
+ return result;
+}
+
+/***************************************************************************
+ Add a name/index pair for the services array to the hash table.
+***************************************************************************/
+
+static bool hash_a_service(const char *name, int idx)
+{
+ char *canon_name;
+
+ if ( !ServiceHash ) {
+ DEBUG(10,("hash_a_service: creating servicehash\n"));
+ ServiceHash = db_open_rbt(NULL);
+ if ( !ServiceHash ) {
+ DEBUG(0,("hash_a_service: open tdb servicehash failed!\n"));
+ return False;
+ }
+ }
+
+ DEBUG(10,("hash_a_service: hashing index %d for service name %s\n",
+ idx, name));
+
+ canon_name = canonicalize_servicename( name );
+
+ dbwrap_store_bystring(ServiceHash, canon_name,
+ make_tdb_data((uint8 *)&idx, sizeof(idx)),
+ TDB_REPLACE);
+
+ TALLOC_FREE(canon_name);
+
+ return True;
+}
+
+/***************************************************************************
+ Add a new home service, with the specified home directory, defaults coming
+ from service ifrom.
+***************************************************************************/
+
+bool lp_add_home(const char *pszHomename, int iDefaultService,
+ const char *user, const char *pszHomedir)
+{
+ int i;
+
+ i = add_a_service(ServicePtrs[iDefaultService], pszHomename);
+
+ if (i < 0)
+ return (False);
+
+ if (!(*(ServicePtrs[iDefaultService]->szPath))
+ || strequal(ServicePtrs[iDefaultService]->szPath, lp_pathname(GLOBAL_SECTION_SNUM))) {
+ string_set(&ServicePtrs[i]->szPath, pszHomedir);
+ }
+
+ if (!(*(ServicePtrs[i]->comment))) {
+ char *comment = NULL;
+ if (asprintf(&comment, "Home directory of %s", user) < 0) {
+ return false;
+ }
+ string_set(&ServicePtrs[i]->comment, comment);
+ SAFE_FREE(comment);
+ }
+
+ /* set the browseable flag from the global default */
+
+ ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
+
+ ServicePtrs[i]->autoloaded = True;
+
+ DEBUG(3, ("adding home's share [%s] for user '%s' at '%s'\n", pszHomename,
+ user, ServicePtrs[i]->szPath ));
+
+ return (True);
+}
+
+/***************************************************************************
+ Add a new service, based on an old one.
+***************************************************************************/
+
+int lp_add_service(const char *pszService, int iDefaultService)
+{
+ if (iDefaultService < 0) {
+ return add_a_service(&sDefault, pszService);
+ }
+
+ return (add_a_service(ServicePtrs[iDefaultService], pszService));
+}
+
+/***************************************************************************
+ Add the IPC service.
+***************************************************************************/
+
+static bool lp_add_ipc(const char *ipc_name, bool guest_ok)
+{
+ char *comment = NULL;
+ int i = add_a_service(&sDefault, ipc_name);
+
+ if (i < 0)
+ return (False);
+
+ if (asprintf(&comment, "IPC Service (%s)",
+ Globals.szServerString) < 0) {
+ return (False);
+ }
+
+ string_set(&ServicePtrs[i]->szPath, tmpdir());
+ string_set(&ServicePtrs[i]->szUsername, "");
+ string_set(&ServicePtrs[i]->comment, comment);
+ string_set(&ServicePtrs[i]->fstype, "IPC");
+ ServicePtrs[i]->iMaxConnections = 0;
+ ServicePtrs[i]->bAvailable = True;
+ ServicePtrs[i]->bRead_only = True;
+ ServicePtrs[i]->bGuest_only = False;
+ ServicePtrs[i]->bAdministrative_share = True;
+ ServicePtrs[i]->bGuest_ok = guest_ok;
+ ServicePtrs[i]->bPrint_ok = False;
+ ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
+
+ DEBUG(3, ("adding IPC service\n"));
+
+ SAFE_FREE(comment);
+ return (True);
+}
+
+/***************************************************************************
+ Add a new printer service, with defaults coming from service iFrom.
+***************************************************************************/
+
+bool lp_add_printer(const char *pszPrintername, int iDefaultService)
+{
+ const char *comment = "From Printcap";
+ int i = add_a_service(ServicePtrs[iDefaultService], pszPrintername);
+
+ if (i < 0)
+ return (False);
+
+ /* note that we do NOT default the availability flag to True - */
+ /* we take it from the default service passed. This allows all */
+ /* dynamic printers to be disabled by disabling the [printers] */
+ /* entry (if/when the 'available' keyword is implemented!). */
+
+ /* the printer name is set to the service name. */
+ string_set(&ServicePtrs[i]->szPrintername, pszPrintername);
+ string_set(&ServicePtrs[i]->comment, comment);
+
+ /* set the browseable flag from the gloabl default */
+ ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
+
+ /* Printers cannot be read_only. */
+ ServicePtrs[i]->bRead_only = False;
+ /* No share modes on printer services. */
+ ServicePtrs[i]->bShareModes = False;
+ /* No oplocks on printer services. */
+ ServicePtrs[i]->bOpLocks = False;
+ /* Printer services must be printable. */
+ ServicePtrs[i]->bPrint_ok = True;
+
+ DEBUG(3, ("adding printer service %s\n", pszPrintername));
+
+ return (True);
+}
+
+
+/***************************************************************************
+ Check whether the given parameter name is valid.
+ Parametric options (names containing a colon) are considered valid.
+***************************************************************************/
+
+bool lp_parameter_is_valid(const char *pszParmName)
+{
+ return ((map_parameter(pszParmName) != -1) ||
+ (strchr(pszParmName, ':') != NULL));
+}
+
+/***************************************************************************
+ Check whether the given name is the name of a global parameter.
+ Returns True for strings belonging to parameters of class
+ P_GLOBAL, False for all other strings, also for parametric options
+ and strings not belonging to any option.
+***************************************************************************/
+
+bool lp_parameter_is_global(const char *pszParmName)
+{
+ int num = map_parameter(pszParmName);
+
+ if (num >= 0) {
+ return (parm_table[num].p_class == P_GLOBAL);
+ }
+
+ return False;
+}
+
+/**************************************************************************
+ Check whether the given name is the canonical name of a parameter.
+ Returns False if it is not a valid parameter Name.
+ For parametric options, True is returned.
+**************************************************************************/
+
+bool lp_parameter_is_canonical(const char *parm_name)
+{
+ if (!lp_parameter_is_valid(parm_name)) {
+ return False;
+ }
+
+ return (map_parameter(parm_name) ==
+ map_parameter_canonical(parm_name, NULL));
+}
+
+/**************************************************************************
+ Determine the canonical name for a parameter.
+ Indicate when it is an inverse (boolean) synonym instead of a
+ "usual" synonym.
+**************************************************************************/
+
+bool lp_canonicalize_parameter(const char *parm_name, const char **canon_parm,
+ bool *inverse)
+{
+ int num;
+
+ if (!lp_parameter_is_valid(parm_name)) {
+ *canon_parm = NULL;
+ return False;
+ }
+
+ num = map_parameter_canonical(parm_name, inverse);
+ if (num < 0) {
+ /* parametric option */
+ *canon_parm = parm_name;
+ } else {
+ *canon_parm = parm_table[num].label;
+ }
+
+ return True;
+
+}
+
+/**************************************************************************
+ Determine the canonical name for a parameter.
+ Turn the value given into the inverse boolean expression when
+ the synonym is an invers boolean synonym.
+
+ Return True if parm_name is a valid parameter name and
+ in case it is an invers boolean synonym, if the val string could
+ successfully be converted to the reverse bool.
+ Return false in all other cases.
+**************************************************************************/
+
+bool lp_canonicalize_parameter_with_value(const char *parm_name,
+ const char *val,
+ const char **canon_parm,
+ const char **canon_val)
+{
+ int num;
+ bool inverse;
+
+ if (!lp_parameter_is_valid(parm_name)) {
+ *canon_parm = NULL;
+ *canon_val = NULL;
+ return False;
+ }
+
+ num = map_parameter_canonical(parm_name, &inverse);
+ if (num < 0) {
+ /* parametric option */
+ *canon_parm = parm_name;
+ *canon_val = val;
+ } else {
+ *canon_parm = parm_table[num].label;
+ if (inverse) {
+ if (!lp_invert_boolean(val, canon_val)) {
+ *canon_val = NULL;
+ return False;
+ }
+ } else {
+ *canon_val = val;
+ }
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ Map a parameter's string representation to something we can use.
+ Returns False if the parameter string is not recognised, else TRUE.
+***************************************************************************/
+
+static int map_parameter(const char *pszParmName)
+{
+ int iIndex;
+
+ if (*pszParmName == '-' && !strequal(pszParmName, "-valid"))
+ return (-1);
+
+ for (iIndex = 0; parm_table[iIndex].label; iIndex++)
+ if (strwicmp(parm_table[iIndex].label, pszParmName) == 0)
+ return (iIndex);
+
+ /* Warn only if it isn't parametric option */
+ if (strchr(pszParmName, ':') == NULL)
+ DEBUG(1, ("Unknown parameter encountered: \"%s\"\n", pszParmName));
+ /* We do return 'fail' for parametric options as well because they are
+ stored in different storage
+ */
+ return (-1);
+}
+
+/***************************************************************************
+ Map a parameter's string representation to the index of the canonical
+ form of the parameter (it might be a synonym).
+ Returns -1 if the parameter string is not recognised.
+***************************************************************************/
+
+static int map_parameter_canonical(const char *pszParmName, bool *inverse)
+{
+ int parm_num, canon_num;
+ bool loc_inverse = False;
+
+ parm_num = map_parameter(pszParmName);
+ if ((parm_num < 0) || !(parm_table[parm_num].flags & FLAG_HIDE)) {
+ /* invalid, parametric or no canidate for synonyms ... */
+ goto done;
+ }
+
+ for (canon_num = 0; parm_table[canon_num].label; canon_num++) {
+ if (is_synonym_of(parm_num, canon_num, &loc_inverse)) {
+ parm_num = canon_num;
+ goto done;
+ }
+ }
+
+done:
+ if (inverse != NULL) {
+ *inverse = loc_inverse;
+ }
+ return parm_num;
+}
+
+/***************************************************************************
+ return true if parameter number parm1 is a synonym of parameter
+ number parm2 (parm2 being the principal name).
+ set inverse to True if parm1 is P_BOOLREV and parm2 is P_BOOL,
+ False otherwise.
+***************************************************************************/
+
+static bool is_synonym_of(int parm1, int parm2, bool *inverse)
+{
+ if ((parm_table[parm1].ptr == parm_table[parm2].ptr) &&
+ (parm_table[parm1].flags & FLAG_HIDE) &&
+ !(parm_table[parm2].flags & FLAG_HIDE))
+ {
+ if (inverse != NULL) {
+ if ((parm_table[parm1].type == P_BOOLREV) &&
+ (parm_table[parm2].type == P_BOOL))
+ {
+ *inverse = True;
+ } else {
+ *inverse = False;
+ }
+ }
+ return True;
+ }
+ return False;
+}
+
+/***************************************************************************
+ Show one parameter's name, type, [values,] and flags.
+ (helper functions for show_parameter_list)
+***************************************************************************/
+
+static void show_parameter(int parmIndex)
+{
+ int enumIndex, flagIndex;
+ int parmIndex2;
+ bool hadFlag;
+ bool hadSyn;
+ bool inverse;
+ const char *type[] = { "P_BOOL", "P_BOOLREV", "P_CHAR", "P_INTEGER",
+ "P_OCTAL", "P_LIST", "P_STRING", "P_USTRING",
+ "P_ENUM", "P_SEP"};
+ unsigned flags[] = { FLAG_BASIC, FLAG_SHARE, FLAG_PRINT, FLAG_GLOBAL,
+ FLAG_WIZARD, FLAG_ADVANCED, FLAG_DEVELOPER, FLAG_DEPRECATED,
+ FLAG_HIDE, FLAG_DOS_STRING};
+ const char *flag_names[] = { "FLAG_BASIC", "FLAG_SHARE", "FLAG_PRINT",
+ "FLAG_GLOBAL", "FLAG_WIZARD", "FLAG_ADVANCED", "FLAG_DEVELOPER",
+ "FLAG_DEPRECATED", "FLAG_HIDE", "FLAG_DOS_STRING", NULL};
+
+ printf("%s=%s", parm_table[parmIndex].label,
+ type[parm_table[parmIndex].type]);
+ if (parm_table[parmIndex].type == P_ENUM) {
+ printf(",");
+ for (enumIndex=0;
+ parm_table[parmIndex].enum_list[enumIndex].name;
+ enumIndex++)
+ {
+ printf("%s%s",
+ enumIndex ? "|" : "",
+ parm_table[parmIndex].enum_list[enumIndex].name);
+ }
+ }
+ printf(",");
+ hadFlag = False;
+ for (flagIndex=0; flag_names[flagIndex]; flagIndex++) {
+ if (parm_table[parmIndex].flags & flags[flagIndex]) {
+ printf("%s%s",
+ hadFlag ? "|" : "",
+ flag_names[flagIndex]);
+ hadFlag = True;
+ }
+ }
+
+ /* output synonyms */
+ hadSyn = False;
+ for (parmIndex2=0; parm_table[parmIndex2].label; parmIndex2++) {
+ if (is_synonym_of(parmIndex, parmIndex2, &inverse)) {
+ printf(" (%ssynonym of %s)", inverse ? "inverse " : "",
+ parm_table[parmIndex2].label);
+ } else if (is_synonym_of(parmIndex2, parmIndex, &inverse)) {
+ if (!hadSyn) {
+ printf(" (synonyms: ");
+ hadSyn = True;
+ } else {
+ printf(", ");
+ }
+ printf("%s%s", parm_table[parmIndex2].label,
+ inverse ? "[i]" : "");
+ }
+ }
+ if (hadSyn) {
+ printf(")");
+ }
+
+ printf("\n");
+}
+
+/***************************************************************************
+ Show all parameter's name, type, [values,] and flags.
+***************************************************************************/
+
+void show_parameter_list(void)
+{
+ int classIndex, parmIndex;
+ const char *section_names[] = { "local", "global", NULL};
+
+ for (classIndex=0; section_names[classIndex]; classIndex++) {
+ printf("[%s]\n", section_names[classIndex]);
+ for (parmIndex = 0; parm_table[parmIndex].label; parmIndex++) {
+ if (parm_table[parmIndex].p_class == classIndex) {
+ show_parameter(parmIndex);
+ }
+ }
+ }
+}
+
+/***************************************************************************
+ Set a boolean variable from the text value stored in the passed string.
+ Returns True in success, False if the passed string does not correctly
+ represent a boolean.
+***************************************************************************/
+
+static bool set_boolean(bool *pb, const char *pszParmValue)
+{
+ bool bRetval;
+ bool value;
+
+ bRetval = True;
+ value = False;
+ if (strwicmp(pszParmValue, "yes") == 0 ||
+ strwicmp(pszParmValue, "true") == 0 ||
+ strwicmp(pszParmValue, "1") == 0)
+ value = True;
+ else if (strwicmp(pszParmValue, "no") == 0 ||
+ strwicmp(pszParmValue, "False") == 0 ||
+ strwicmp(pszParmValue, "0") == 0)
+ value = False;
+ else {
+ DEBUG(2,
+ ("ERROR: Badly formed boolean in configuration file: \"%s\".\n",
+ pszParmValue));
+ bRetval = False;
+ }
+
+ if ((pb != NULL) && (bRetval != False)) {
+ *pb = value;
+ }
+
+ return (bRetval);
+}
+
+
+/***************************************************************************
+ Check if a given string correctly represents a boolean value.
+***************************************************************************/
+
+bool lp_string_is_valid_boolean(const char *parm_value)
+{
+ return set_boolean(NULL, parm_value);
+}
+
+/***************************************************************************
+ Get the standard string representation of a boolean value ("yes" or "no")
+***************************************************************************/
+
+static const char *get_boolean(bool bool_value)
+{
+ static const char *yes_str = "yes";
+ static const char *no_str = "no";
+
+ return (bool_value ? yes_str : no_str);
+}
+
+/***************************************************************************
+ Provide the string of the negated boolean value associated to the boolean
+ given as a string. Returns False if the passed string does not correctly
+ represent a boolean.
+***************************************************************************/
+
+bool lp_invert_boolean(const char *str, const char **inverse_str)
+{
+ bool val;
+
+ if (!set_boolean(&val, str)) {
+ return False;
+ }
+
+ *inverse_str = get_boolean(!val);
+ return True;
+}
+
+/***************************************************************************
+ Provide the canonical string representation of a boolean value given
+ as a string. Return True on success, False if the string given does
+ not correctly represent a boolean.
+***************************************************************************/
+
+bool lp_canonicalize_boolean(const char *str, const char**canon_str)
+{
+ bool val;
+
+ if (!set_boolean(&val, str)) {
+ return False;
+ }
+
+ *canon_str = get_boolean(val);
+ return True;
+}
+
+/***************************************************************************
+Find a service by name. Otherwise works like get_service.
+***************************************************************************/
+
+static int getservicebyname(const char *pszServiceName, struct service *pserviceDest)
+{
+ int iService = -1;
+ char *canon_name;
+ TDB_DATA data;
+
+ if (ServiceHash == NULL) {
+ return -1;
+ }
+
+ canon_name = canonicalize_servicename(pszServiceName);
+
+ data = dbwrap_fetch_bystring(ServiceHash, canon_name, canon_name);
+
+ if ((data.dptr != NULL) && (data.dsize == sizeof(iService))) {
+ iService = *(int *)data.dptr;
+ }
+
+ TALLOC_FREE(canon_name);
+
+ if ((iService != -1) && (LP_SNUM_OK(iService))
+ && (pserviceDest != NULL)) {
+ copy_service(pserviceDest, ServicePtrs[iService], NULL);
+ }
+
+ return (iService);
+}
+
+/***************************************************************************
+ Copy a service structure to another.
+ If pcopymapDest is NULL then copy all fields
+***************************************************************************/
+
+static void copy_service(struct service *pserviceDest, struct service *pserviceSource,
+ struct bitmap *pcopymapDest)
+{
+ int i;
+ bool bcopyall = (pcopymapDest == NULL);
+ struct param_opt_struct *data, *pdata, *paramo;
+ bool not_added;
+
+ for (i = 0; parm_table[i].label; i++)
+ if (parm_table[i].ptr && parm_table[i].p_class == P_LOCAL &&
+ (bcopyall || bitmap_query(pcopymapDest,i))) {
+ void *def_ptr = parm_table[i].ptr;
+ void *src_ptr =
+ ((char *)pserviceSource) + PTR_DIFF(def_ptr,
+ &sDefault);
+ void *dest_ptr =
+ ((char *)pserviceDest) + PTR_DIFF(def_ptr,
+ &sDefault);
+
+ switch (parm_table[i].type) {
+ case P_BOOL:
+ case P_BOOLREV:
+ *(bool *)dest_ptr = *(bool *)src_ptr;
+ break;
+
+ case P_INTEGER:
+ case P_ENUM:
+ case P_OCTAL:
+ *(int *)dest_ptr = *(int *)src_ptr;
+ break;
+
+ case P_CHAR:
+ *(char *)dest_ptr = *(char *)src_ptr;
+ break;
+
+ case P_STRING:
+ string_set((char **)dest_ptr,
+ *(char **)src_ptr);
+ break;
+
+ case P_USTRING:
+ string_set((char **)dest_ptr,
+ *(char **)src_ptr);
+ strupper_m(*(char **)dest_ptr);
+ break;
+ case P_LIST:
+ TALLOC_FREE(*((char ***)dest_ptr));
+ str_list_copy(NULL, (char ***)dest_ptr,
+ *(const char ***)src_ptr);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (bcopyall) {
+ init_copymap(pserviceDest);
+ if (pserviceSource->copymap)
+ bitmap_copy(pserviceDest->copymap,
+ pserviceSource->copymap);
+ }
+
+ data = pserviceSource->param_opt;
+ while (data) {
+ not_added = True;
+ pdata = pserviceDest->param_opt;
+ /* Traverse destination */
+ while (pdata) {
+ /* If we already have same option, override it */
+ if (strwicmp(pdata->key, data->key) == 0) {
+ string_free(&pdata->value);
+ TALLOC_FREE(data->list);
+ pdata->value = SMB_STRDUP(data->value);
+ not_added = False;
+ break;
+ }
+ pdata = pdata->next;
+ }
+ if (not_added) {
+ paramo = SMB_XMALLOC_P(struct param_opt_struct);
+ paramo->key = SMB_STRDUP(data->key);
+ paramo->value = SMB_STRDUP(data->value);
+ paramo->list = NULL;
+ DLIST_ADD(pserviceDest->param_opt, paramo);
+ }
+ data = data->next;
+ }
+}
+
+/***************************************************************************
+Check a service for consistency. Return False if the service is in any way
+incomplete or faulty, else True.
+***************************************************************************/
+
+bool service_ok(int iService)
+{
+ bool bRetval;
+
+ bRetval = True;
+ if (ServicePtrs[iService]->szService[0] == '\0') {
+ DEBUG(0, ("The following message indicates an internal error:\n"));
+ DEBUG(0, ("No service name in service entry.\n"));
+ bRetval = False;
+ }
+
+ /* The [printers] entry MUST be printable. I'm all for flexibility, but */
+ /* I can't see why you'd want a non-printable printer service... */
+ if (strwicmp(ServicePtrs[iService]->szService, PRINTERS_NAME) == 0) {
+ if (!ServicePtrs[iService]->bPrint_ok) {
+ DEBUG(0, ("WARNING: [%s] service MUST be printable!\n",
+ ServicePtrs[iService]->szService));
+ ServicePtrs[iService]->bPrint_ok = True;
+ }
+ /* [printers] service must also be non-browsable. */
+ if (ServicePtrs[iService]->bBrowseable)
+ ServicePtrs[iService]->bBrowseable = False;
+ }
+
+ if (ServicePtrs[iService]->szPath[0] == '\0' &&
+ strwicmp(ServicePtrs[iService]->szService, HOMES_NAME) != 0 &&
+ ServicePtrs[iService]->szMSDfsProxy[0] == '\0'
+ ) {
+ DEBUG(0, ("WARNING: No path in service %s - making it unavailable!\n",
+ ServicePtrs[iService]->szService));
+ ServicePtrs[iService]->bAvailable = False;
+ }
+
+ /* If a service is flagged unavailable, log the fact at level 1. */
+ if (!ServicePtrs[iService]->bAvailable)
+ DEBUG(1, ("NOTE: Service %s is flagged unavailable.\n",
+ ServicePtrs[iService]->szService));
+
+ return (bRetval);
+}
+
+static struct smbconf_ctx *lp_smbconf_ctx(void)
+{
+ WERROR werr;
+ static struct smbconf_ctx *conf_ctx = NULL;
+
+ if (conf_ctx == NULL) {
+ werr = smbconf_init(NULL, &conf_ctx, "registry:");
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(1, ("error initializing registry configuration: "
+ "%s\n", dos_errstr(werr)));
+ conf_ctx = NULL;
+ }
+ }
+
+ return conf_ctx;
+}
+
+static bool process_registry_service(struct smbconf_service *service)
+{
+ uint32_t count;
+ bool ret;
+
+ if (service == NULL) {
+ return false;
+ }
+
+ ret = do_section(service->name, NULL);
+ if (ret != true) {
+ return false;
+ }
+ for (count = 0; count < service->num_params; count++) {
+ ret = do_parameter(service->param_names[count],
+ service->param_values[count],
+ NULL);
+ if (ret != true) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ * process_registry_globals
+ */
+static bool process_registry_globals(void)
+{
+ WERROR werr;
+ struct smbconf_service *service = NULL;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+ struct smbconf_ctx *conf_ctx = lp_smbconf_ctx();
+ bool ret = false;
+
+ if (conf_ctx == NULL) {
+ goto done;
+ }
+
+ ret = do_parameter("registry shares", "yes", NULL);
+ if (!ret) {
+ goto done;
+ }
+
+ if (!smbconf_share_exists(conf_ctx, GLOBAL_NAME)) {
+ /* nothing to read from the registry yet but make sure lp_load
+ * doesn't return false */
+ ret = true;
+ goto done;
+ }
+
+ werr = smbconf_get_share(conf_ctx, mem_ctx, GLOBAL_NAME, &service);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ ret = process_registry_service(service);
+ if (!ret) {
+ goto done;
+ }
+
+ /* store the csn */
+ smbconf_changed(conf_ctx, &conf_last_csn, NULL, NULL);
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static bool process_registry_shares(void)
+{
+ WERROR werr;
+ uint32_t count;
+ struct smbconf_service **service = NULL;
+ uint32_t num_shares = 0;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+ struct smbconf_ctx *conf_ctx = lp_smbconf_ctx();
+ bool ret = false;
+
+ if (conf_ctx == NULL) {
+ goto done;
+ }
+
+ werr = smbconf_get_config(conf_ctx, mem_ctx, &num_shares, &service);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ ret = true;
+
+ for (count = 0; count < num_shares; count++) {
+ if (strequal(service[count]->name, GLOBAL_NAME)) {
+ continue;
+ }
+ ret = process_registry_service(service[count]);
+ if (!ret) {
+ goto done;
+ }
+ }
+
+ /* store the csn */
+ smbconf_changed(conf_ctx, &conf_last_csn, NULL, NULL);
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static struct file_lists {
+ struct file_lists *next;
+ char *name;
+ char *subfname;
+ time_t modtime;
+} *file_lists = NULL;
+
+/*******************************************************************
+ Keep a linked list of all config files so we know when one has changed
+ it's date and needs to be reloaded.
+********************************************************************/
+
+static void add_to_file_list(const char *fname, const char *subfname)
+{
+ struct file_lists *f = file_lists;
+
+ while (f) {
+ if (f->name && !strcmp(f->name, fname))
+ break;
+ f = f->next;
+ }
+
+ if (!f) {
+ f = SMB_MALLOC_P(struct file_lists);
+ if (!f)
+ return;
+ f->next = file_lists;
+ f->name = SMB_STRDUP(fname);
+ if (!f->name) {
+ SAFE_FREE(f);
+ return;
+ }
+ f->subfname = SMB_STRDUP(subfname);
+ if (!f->subfname) {
+ SAFE_FREE(f);
+ return;
+ }
+ file_lists = f;
+ f->modtime = file_modtime(subfname);
+ } else {
+ time_t t = file_modtime(subfname);
+ if (t)
+ f->modtime = t;
+ }
+}
+
+/**
+ * Utility function for outsiders to check if we're running on registry.
+ */
+bool lp_config_backend_is_registry(void)
+{
+ return (lp_config_backend() == CONFIG_BACKEND_REGISTRY);
+}
+
+/**
+ * Utility function to check if the config backend is FILE.
+ */
+bool lp_config_backend_is_file(void)
+{
+ return (lp_config_backend() == CONFIG_BACKEND_FILE);
+}
+
+/*******************************************************************
+ Check if a config file has changed date.
+********************************************************************/
+
+bool lp_file_list_changed(void)
+{
+ struct file_lists *f = file_lists;
+
+ DEBUG(6, ("lp_file_list_changed()\n"));
+
+ if (lp_config_backend_is_registry()) {
+ struct smbconf_ctx *conf_ctx = lp_smbconf_ctx();
+
+ if (conf_ctx == NULL) {
+ return false;
+ }
+ if (smbconf_changed(conf_ctx, &conf_last_csn, NULL, NULL)) {
+ DEBUGADD(6, ("registry config changed\n"));
+ return true;
+ }
+ }
+
+ while (f) {
+ char *n2 = NULL;
+ time_t mod_time;
+
+ n2 = alloc_sub_basic(get_current_username(),
+ current_user_info.domain,
+ f->name);
+ if (!n2) {
+ return false;
+ }
+ DEBUGADD(6, ("file %s -> %s last mod_time: %s\n",
+ f->name, n2, ctime(&f->modtime)));
+
+ mod_time = file_modtime(n2);
+
+ if (mod_time && ((f->modtime != mod_time) || (f->subfname == NULL) || (strcmp(n2, f->subfname) != 0))) {
+ DEBUGADD(6,
+ ("file %s modified: %s\n", n2,
+ ctime(&mod_time)));
+ f->modtime = mod_time;
+ SAFE_FREE(f->subfname);
+ f->subfname = n2; /* Passing ownership of
+ return from alloc_sub_basic
+ above. */
+ return true;
+ }
+ SAFE_FREE(n2);
+ f = f->next;
+ }
+ return (False);
+}
+
+
+/***************************************************************************
+ Run standard_sub_basic on netbios name... needed because global_myname
+ is not accessed through any lp_ macro.
+ Note: We must *NOT* use string_set() here as ptr points to global_myname.
+***************************************************************************/
+
+static bool handle_netbios_name(int snum, const char *pszParmValue, char **ptr)
+{
+ bool ret;
+ char *netbios_name = alloc_sub_basic(get_current_username(),
+ current_user_info.domain,
+ pszParmValue);
+
+ ret = set_global_myname(netbios_name);
+ SAFE_FREE(netbios_name);
+ string_set(&Globals.szNetbiosName,global_myname());
+
+ DEBUG(4, ("handle_netbios_name: set global_myname to: %s\n",
+ global_myname()));
+
+ return ret;
+}
+
+static bool handle_charset(int snum, const char *pszParmValue, char **ptr)
+{
+ if (strcmp(*ptr, pszParmValue) != 0) {
+ string_set(ptr, pszParmValue);
+ init_iconv();
+ }
+ return True;
+}
+
+
+
+static bool handle_workgroup(int snum, const char *pszParmValue, char **ptr)
+{
+ bool ret;
+
+ ret = set_global_myworkgroup(pszParmValue);
+ string_set(&Globals.szWorkgroup,lp_workgroup());
+
+ return ret;
+}
+
+static bool handle_netbios_scope(int snum, const char *pszParmValue, char **ptr)
+{
+ bool ret;
+
+ ret = set_global_scope(pszParmValue);
+ string_set(&Globals.szNetbiosScope,global_scope());
+
+ return ret;
+}
+
+static bool handle_netbios_aliases(int snum, const char *pszParmValue, char **ptr)
+{
+ TALLOC_FREE(Globals.szNetbiosAliases);
+ Globals.szNetbiosAliases = str_list_make(NULL, pszParmValue, NULL);
+ return set_netbios_aliases((const char **)Globals.szNetbiosAliases);
+}
+
+/***************************************************************************
+ Handle the include operation.
+***************************************************************************/
+static bool bAllowIncludeRegistry = true;
+
+static bool handle_include(int snum, const char *pszParmValue, char **ptr)
+{
+ char *fname;
+
+ if (strequal(pszParmValue, INCLUDE_REGISTRY_NAME)) {
+ if (!bAllowIncludeRegistry) {
+ return true;
+ }
+ if (bInGlobalSection) {
+ return process_registry_globals();
+ } else {
+ DEBUG(1, ("\"include = registry\" only effective "
+ "in %s section\n", GLOBAL_NAME));
+ return false;
+ }
+ }
+
+ fname = alloc_sub_basic(get_current_username(),
+ current_user_info.domain,
+ pszParmValue);
+
+ add_to_file_list(pszParmValue, fname);
+
+ string_set(ptr, fname);
+
+ if (file_exist(fname, NULL)) {
+ bool ret = pm_process(fname, do_section, do_parameter, NULL);
+ SAFE_FREE(fname);
+ return ret;
+ }
+
+ DEBUG(2, ("Can't find include file %s\n", fname));
+ SAFE_FREE(fname);
+ return true;
+}
+
+/***************************************************************************
+ Handle the interpretation of the copy parameter.
+***************************************************************************/
+
+static bool handle_copy(int snum, const char *pszParmValue, char **ptr)
+{
+ bool bRetval;
+ int iTemp;
+ struct service serviceTemp;
+
+ string_set(ptr, pszParmValue);
+
+ init_service(&serviceTemp);
+
+ bRetval = False;
+
+ DEBUG(3, ("Copying service from service %s\n", pszParmValue));
+
+ if ((iTemp = getservicebyname(pszParmValue, &serviceTemp)) >= 0) {
+ if (iTemp == iServiceIndex) {
+ DEBUG(0, ("Can't copy service %s - unable to copy self!\n", pszParmValue));
+ } else {
+ copy_service(ServicePtrs[iServiceIndex],
+ &serviceTemp,
+ ServicePtrs[iServiceIndex]->copymap);
+ bRetval = True;
+ }
+ } else {
+ DEBUG(0, ("Unable to copy service - source not found: %s\n", pszParmValue));
+ bRetval = False;
+ }
+
+ free_service(&serviceTemp);
+ return (bRetval);
+}
+
+static bool handle_ldap_debug_level(int snum, const char *pszParmValue, char **ptr)
+{
+ Globals.ldap_debug_level = lp_int(pszParmValue);
+ init_ldap_debugging();
+ return true;
+}
+
+/***************************************************************************
+ Handle idmap/non unix account uid and gid allocation parameters. The format of these
+ parameters is:
+
+ [global]
+
+ idmap uid = 1000-1999
+ idmap gid = 700-899
+
+ We only do simple parsing checks here. The strings are parsed into useful
+ structures in the idmap daemon code.
+
+***************************************************************************/
+
+/* Some lp_ routines to return idmap [ug]id information */
+
+static uid_t idmap_uid_low, idmap_uid_high;
+static gid_t idmap_gid_low, idmap_gid_high;
+
+bool lp_idmap_uid(uid_t *low, uid_t *high)
+{
+ if (idmap_uid_low == 0 || idmap_uid_high == 0)
+ return False;
+
+ if (low)
+ *low = idmap_uid_low;
+
+ if (high)
+ *high = idmap_uid_high;
+
+ return True;
+}
+
+bool lp_idmap_gid(gid_t *low, gid_t *high)
+{
+ if (idmap_gid_low == 0 || idmap_gid_high == 0)
+ return False;
+
+ if (low)
+ *low = idmap_gid_low;
+
+ if (high)
+ *high = idmap_gid_high;
+
+ return True;
+}
+
+/* Do some simple checks on "idmap [ug]id" parameter values */
+
+static bool handle_idmap_uid(int snum, const char *pszParmValue, char **ptr)
+{
+ uint32 low, high;
+
+ if (sscanf(pszParmValue, "%u - %u", &low, &high) != 2 || high < low)
+ return False;
+
+ /* Parse OK */
+
+ string_set(ptr, pszParmValue);
+
+ idmap_uid_low = low;
+ idmap_uid_high = high;
+
+ return True;
+}
+
+static bool handle_idmap_gid(int snum, const char *pszParmValue, char **ptr)
+{
+ uint32 low, high;
+
+ if (sscanf(pszParmValue, "%u - %u", &low, &high) != 2 || high < low)
+ return False;
+
+ /* Parse OK */
+
+ string_set(ptr, pszParmValue);
+
+ idmap_gid_low = low;
+ idmap_gid_high = high;
+
+ return True;
+}
+
+/***************************************************************************
+ Handle the DEBUG level list.
+***************************************************************************/
+
+static bool handle_debug_list( int snum, const char *pszParmValueIn, char **ptr )
+{
+ string_set(ptr, pszParmValueIn);
+ return debug_parse_levels(pszParmValueIn);
+}
+
+/***************************************************************************
+ Handle ldap suffixes - default to ldapsuffix if sub-suffixes are not defined.
+***************************************************************************/
+
+static const char *append_ldap_suffix( const char *str )
+{
+ const char *suffix_string;
+
+
+ suffix_string = talloc_asprintf(talloc_tos(), "%s,%s", str,
+ Globals.szLdapSuffix );
+ if ( !suffix_string ) {
+ DEBUG(0,("append_ldap_suffix: talloc_asprintf() failed!\n"));
+ return "";
+ }
+
+ return suffix_string;
+}
+
+const char *lp_ldap_machine_suffix(void)
+{
+ if (Globals.szLdapMachineSuffix[0])
+ return append_ldap_suffix(Globals.szLdapMachineSuffix);
+
+ return lp_string(Globals.szLdapSuffix);
+}
+
+const char *lp_ldap_user_suffix(void)
+{
+ if (Globals.szLdapUserSuffix[0])
+ return append_ldap_suffix(Globals.szLdapUserSuffix);
+
+ return lp_string(Globals.szLdapSuffix);
+}
+
+const char *lp_ldap_group_suffix(void)
+{
+ if (Globals.szLdapGroupSuffix[0])
+ return append_ldap_suffix(Globals.szLdapGroupSuffix);
+
+ return lp_string(Globals.szLdapSuffix);
+}
+
+const char *lp_ldap_idmap_suffix(void)
+{
+ if (Globals.szLdapIdmapSuffix[0])
+ return append_ldap_suffix(Globals.szLdapIdmapSuffix);
+
+ return lp_string(Globals.szLdapSuffix);
+}
+
+/****************************************************************************
+ set the value for a P_ENUM
+ ***************************************************************************/
+
+static void lp_set_enum_parm( struct parm_struct *parm, const char *pszParmValue,
+ int *ptr )
+{
+ int i;
+
+ for (i = 0; parm->enum_list[i].name; i++) {
+ if ( strequal(pszParmValue, parm->enum_list[i].name)) {
+ *ptr = parm->enum_list[i].value;
+ return;
+ }
+ }
+ DEBUG(0, ("WARNING: Ignoring invalid value '%s' for parameter '%s'\n",
+ pszParmValue, parm->label));
+}
+
+/***************************************************************************
+***************************************************************************/
+
+static bool handle_printing(int snum, const char *pszParmValue, char **ptr)
+{
+ static int parm_num = -1;
+ struct service *s;
+
+ if ( parm_num == -1 )
+ parm_num = map_parameter( "printing" );
+
+ lp_set_enum_parm( &parm_table[parm_num], pszParmValue, (int*)ptr );
+
+ if ( snum < 0 )
+ s = &sDefault;
+ else
+ s = ServicePtrs[snum];
+
+ init_printer_values( s );
+
+ return True;
+}
+
+
+/***************************************************************************
+ Initialise a copymap.
+***************************************************************************/
+
+static void init_copymap(struct service *pservice)
+{
+ int i;
+ if (pservice->copymap) {
+ bitmap_free(pservice->copymap);
+ }
+ pservice->copymap = bitmap_allocate(NUMPARAMETERS);
+ if (!pservice->copymap)
+ DEBUG(0,
+ ("Couldn't allocate copymap!! (size %d)\n",
+ (int)NUMPARAMETERS));
+ else
+ for (i = 0; i < NUMPARAMETERS; i++)
+ bitmap_set(pservice->copymap, i);
+}
+
+/***************************************************************************
+ Return the local pointer to a parameter given the service number and the
+ pointer into the default structure.
+***************************************************************************/
+
+void *lp_local_ptr(int snum, void *ptr)
+{
+ return (void *)(((char *)ServicePtrs[snum]) + PTR_DIFF(ptr, &sDefault));
+}
+
+/***************************************************************************
+ Process a parameter for a particular service number. If snum < 0
+ then assume we are in the globals.
+***************************************************************************/
+
+bool lp_do_parameter(int snum, const char *pszParmName, const char *pszParmValue)
+{
+ int parmnum, i;
+ void *parm_ptr = NULL; /* where we are going to store the result */
+ void *def_ptr = NULL;
+ struct param_opt_struct *paramo, *data;
+ bool not_added;
+
+ parmnum = map_parameter(pszParmName);
+
+ if (parmnum < 0) {
+ TALLOC_CTX *frame;
+
+ if (strchr(pszParmName, ':') == NULL) {
+ DEBUG(0, ("Ignoring unknown parameter \"%s\"\n",
+ pszParmName));
+ return (True);
+ }
+
+ /*
+ * We've got a parametric option
+ */
+
+ frame = talloc_stackframe();
+
+ not_added = True;
+ data = (snum < 0)
+ ? Globals.param_opt : ServicePtrs[snum]->param_opt;
+ /* Traverse destination */
+ while (data) {
+ /* If we already have same option, override it */
+ if (strwicmp(data->key, pszParmName) == 0) {
+ string_free(&data->value);
+ TALLOC_FREE(data->list);
+ data->value = SMB_STRDUP(pszParmValue);
+ not_added = False;
+ break;
+ }
+ data = data->next;
+ }
+ if (not_added) {
+ paramo = SMB_XMALLOC_P(struct param_opt_struct);
+ paramo->key = SMB_STRDUP(pszParmName);
+ paramo->value = SMB_STRDUP(pszParmValue);
+ paramo->list = NULL;
+ if (snum < 0) {
+ DLIST_ADD(Globals.param_opt, paramo);
+ } else {
+ DLIST_ADD(ServicePtrs[snum]->param_opt,
+ paramo);
+ }
+ }
+
+ TALLOC_FREE(frame);
+ return (True);
+ }
+
+ if (parm_table[parmnum].flags & FLAG_DEPRECATED) {
+ DEBUG(1, ("WARNING: The \"%s\" option is deprecated\n",
+ pszParmName));
+ }
+
+ def_ptr = parm_table[parmnum].ptr;
+
+ /* we might point at a service, the default service or a global */
+ if (snum < 0) {
+ parm_ptr = def_ptr;
+ } else {
+ if (parm_table[parmnum].p_class == P_GLOBAL) {
+ DEBUG(0,
+ ("Global parameter %s found in service section!\n",
+ pszParmName));
+ return (True);
+ }
+ parm_ptr =
+ ((char *)ServicePtrs[snum]) + PTR_DIFF(def_ptr,
+ &sDefault);
+ }
+
+ if (snum >= 0) {
+ if (!ServicePtrs[snum]->copymap)
+ init_copymap(ServicePtrs[snum]);
+
+ /* this handles the aliases - set the copymap for other entries with
+ the same data pointer */
+ for (i = 0; parm_table[i].label; i++)
+ if (parm_table[i].ptr == parm_table[parmnum].ptr)
+ bitmap_clear(ServicePtrs[snum]->copymap, i);
+ }
+
+ /* if it is a special case then go ahead */
+ if (parm_table[parmnum].special) {
+ return parm_table[parmnum].special(snum, pszParmValue,
+ (char **)parm_ptr);
+ }
+
+ /* now switch on the type of variable it is */
+ switch (parm_table[parmnum].type)
+ {
+ case P_BOOL:
+ *(bool *)parm_ptr = lp_bool(pszParmValue);
+ break;
+
+ case P_BOOLREV:
+ *(bool *)parm_ptr = !lp_bool(pszParmValue);
+ break;
+
+ case P_INTEGER:
+ *(int *)parm_ptr = lp_int(pszParmValue);
+ break;
+
+ case P_CHAR:
+ *(char *)parm_ptr = *pszParmValue;
+ break;
+
+ case P_OCTAL:
+ i = sscanf(pszParmValue, "%o", (int *)parm_ptr);
+ if ( i != 1 ) {
+ DEBUG ( 0, ("Invalid octal number %s\n", pszParmName ));
+ }
+ break;
+
+ case P_LIST:
+ TALLOC_FREE(*((char ***)parm_ptr));
+ *(char ***)parm_ptr = str_list_make(
+ NULL, pszParmValue, NULL);
+ break;
+
+ case P_STRING:
+ string_set((char **)parm_ptr, pszParmValue);
+ break;
+
+ case P_USTRING:
+ string_set((char **)parm_ptr, pszParmValue);
+ strupper_m(*(char **)parm_ptr);
+ break;
+
+ case P_ENUM:
+ lp_set_enum_parm( &parm_table[parmnum], pszParmValue, (int*)parm_ptr );
+ break;
+ case P_SEP:
+ break;
+ }
+
+ return (True);
+}
+
+/***************************************************************************
+ Process a parameter.
+***************************************************************************/
+
+static bool do_parameter(const char *pszParmName, const char *pszParmValue,
+ void *userdata)
+{
+ if (!bInGlobalSection && bGlobalOnly)
+ return (True);
+
+ DEBUGADD(4, ("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(struct parm_struct *p, void *ptr, FILE * f)
+{
+ int i;
+ switch (p->type)
+ {
+ case P_ENUM:
+ for (i = 0; p->enum_list[i].name; i++) {
+ if (*(int *)ptr == p->enum_list[i].value) {
+ fprintf(f, "%s",
+ p->enum_list[i].name);
+ break;
+ }
+ }
+ break;
+
+ case P_BOOL:
+ fprintf(f, "%s", BOOLSTR(*(bool *)ptr));
+ break;
+
+ case P_BOOLREV:
+ fprintf(f, "%s", BOOLSTR(!*(bool *)ptr));
+ break;
+
+ case P_INTEGER:
+ fprintf(f, "%d", *(int *)ptr);
+ break;
+
+ case P_CHAR:
+ fprintf(f, "%c", *(char *)ptr);
+ break;
+
+ case P_OCTAL: {
+ char *o = octal_string(*(int *)ptr);
+ fprintf(f, "%s", o);
+ TALLOC_FREE(o);
+ break;
+ }
+
+ case P_LIST:
+ if ((char ***)ptr && *(char ***)ptr) {
+ char **list = *(char ***)ptr;
+ for (; *list; list++) {
+ /* surround strings with whitespace in double quotes */
+ if ( strchr_m( *list, ' ' ) )
+ fprintf(f, "\"%s\"%s", *list, ((*(list+1))?", ":""));
+ else
+ fprintf(f, "%s%s", *list, ((*(list+1))?", ":""));
+ }
+ }
+ break;
+
+ case P_STRING:
+ case P_USTRING:
+ if (*(char **)ptr) {
+ fprintf(f, "%s", *(char **)ptr);
+ }
+ break;
+ case P_SEP:
+ break;
+ }
+}
+
+/***************************************************************************
+ Check if two parameters are equal.
+***************************************************************************/
+
+static bool equal_parameter(parm_type type, void *ptr1, void *ptr2)
+{
+ switch (type) {
+ case P_BOOL:
+ case P_BOOLREV:
+ return (*((bool *)ptr1) == *((bool *)ptr2));
+
+ case P_INTEGER:
+ case P_ENUM:
+ case P_OCTAL:
+ return (*((int *)ptr1) == *((int *)ptr2));
+
+ case P_CHAR:
+ return (*((char *)ptr1) == *((char *)ptr2));
+
+ case P_LIST:
+ return str_list_compare(*(char ***)ptr1, *(char ***)ptr2);
+
+ case P_STRING:
+ case P_USTRING:
+ {
+ char *p1 = *(char **)ptr1, *p2 = *(char **)ptr2;
+ if (p1 && !*p1)
+ p1 = NULL;
+ if (p2 && !*p2)
+ p2 = NULL;
+ return (p1 == p2 || strequal(p1, p2));
+ }
+ case P_SEP:
+ break;
+ }
+ return (False);
+}
+
+/***************************************************************************
+ Initialize any local varients in the sDefault table.
+***************************************************************************/
+
+void init_locals(void)
+{
+ /* None as yet. */
+}
+
+/***************************************************************************
+ Process a new section (service). At this stage all sections are services.
+ Later we'll have special sections that permit server parameters to be set.
+ Returns True on success, False on failure.
+***************************************************************************/
+
+static bool do_section(const char *pszSectionName, void *userdata)
+{
+ bool bRetval;
+ bool isglobal = ((strwicmp(pszSectionName, GLOBAL_NAME) == 0) ||
+ (strwicmp(pszSectionName, GLOBAL_NAME2) == 0));
+ bRetval = False;
+
+ /* if we were in a global section then do the local inits */
+ if (bInGlobalSection && !isglobal)
+ init_locals();
+
+ /* if we've just struck a global section, note the fact. */
+ bInGlobalSection = isglobal;
+
+ /* check for multiple global sections */
+ if (bInGlobalSection) {
+ DEBUG(3, ("Processing section \"[%s]\"\n", pszSectionName));
+ return (True);
+ }
+
+ if (!bInGlobalSection && bGlobalOnly)
+ return (True);
+
+ /* if we have a current service, tidy it up before moving on */
+ bRetval = True;
+
+ if (iServiceIndex >= 0)
+ bRetval = service_ok(iServiceIndex);
+
+ /* if all is still well, move to the next record in the services array */
+ if (bRetval) {
+ /* We put this here to avoid an odd message order if messages are */
+ /* issued by the post-processing of a previous section. */
+ DEBUG(2, ("Processing section \"[%s]\"\n", pszSectionName));
+
+ if ((iServiceIndex = add_a_service(&sDefault, pszSectionName))
+ < 0) {
+ DEBUG(0, ("Failed to add a new service\n"));
+ return (False);
+ }
+ }
+
+ return (bRetval);
+}
+
+
+/***************************************************************************
+ Determine if a partcular base parameter is currentl set to the default value.
+***************************************************************************/
+
+static bool is_default(int i)
+{
+ if (!defaults_saved)
+ return False;
+ switch (parm_table[i].type) {
+ case P_LIST:
+ return str_list_compare (parm_table[i].def.lvalue,
+ *(char ***)parm_table[i].ptr);
+ case P_STRING:
+ case P_USTRING:
+ return strequal(parm_table[i].def.svalue,
+ *(char **)parm_table[i].ptr);
+ case P_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(FILE *f)
+{
+ int i;
+ struct param_opt_struct *data;
+
+ fprintf(f, "[global]\n");
+
+ for (i = 0; parm_table[i].label; i++)
+ if (parm_table[i].p_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");
+ }
+ if (Globals.param_opt != NULL) {
+ data = Globals.param_opt;
+ while(data) {
+ fprintf(f, "\t%s = %s\n", data->key, data->value);
+ data = data->next;
+ }
+ }
+
+}
+
+/***************************************************************************
+ 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 *)ServicePtrs[snum]) + pdiff,
+ ((char *)&sDefault) + pdiff);
+}
+
+/***************************************************************************
+ Display the contents of a single services record.
+***************************************************************************/
+
+static void dump_a_service(struct service *pService, FILE * f)
+{
+ int i;
+ struct param_opt_struct *data;
+
+ if (pService != &sDefault)
+ fprintf(f, "[%s]\n", pService->szService);
+
+ for (i = 0; parm_table[i].label; i++) {
+
+ if (parm_table[i].p_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");
+ }
+ }
+
+ if (pService->param_opt != NULL) {
+ data = pService->param_opt;
+ while(data) {
+ fprintf(f, "\t%s = %s\n", data->key, data->value);
+ data = data->next;
+ }
+ }
+}
+
+/***************************************************************************
+ Display the contents of a parameter of a single services record.
+***************************************************************************/
+
+bool dump_a_parameter(int snum, char *parm_name, FILE * f, bool isGlobal)
+{
+ int i;
+ bool result = False;
+ parm_class p_class;
+ unsigned flag = 0;
+ fstring local_parm_name;
+ char *parm_opt;
+ const char *parm_opt_value;
+
+ /* check for parametrical option */
+ fstrcpy( local_parm_name, parm_name);
+ parm_opt = strchr( local_parm_name, ':');
+
+ if (parm_opt) {
+ *parm_opt = '\0';
+ parm_opt++;
+ if (strlen(parm_opt)) {
+ parm_opt_value = lp_parm_const_string( snum,
+ local_parm_name, parm_opt, NULL);
+ if (parm_opt_value) {
+ printf( "%s\n", parm_opt_value);
+ result = True;
+ }
+ }
+ return result;
+ }
+
+ /* check for a key and print the value */
+ if (isGlobal) {
+ p_class = P_GLOBAL;
+ flag = FLAG_GLOBAL;
+ } else
+ p_class = P_LOCAL;
+
+ for (i = 0; parm_table[i].label; i++) {
+ if (strwicmp(parm_table[i].label, parm_name) == 0 &&
+ (parm_table[i].p_class == p_class || parm_table[i].flags & flag) &&
+ parm_table[i].ptr &&
+ (*parm_table[i].label != '-') &&
+ (i == 0 || (parm_table[i].ptr != parm_table[i - 1].ptr)))
+ {
+ void *ptr;
+
+ if (isGlobal) {
+ ptr = parm_table[i].ptr;
+ } else {
+ struct service *pService = ServicePtrs[snum];
+ ptr = ((char *)pService) +
+ PTR_DIFF(parm_table[i].ptr, &sDefault);
+ }
+
+ print_parameter(&parm_table[i],
+ ptr, f);
+ fprintf(f, "\n");
+ result = True;
+ break;
+ }
+ }
+
+ return result;
+}
+
+/***************************************************************************
+ Return info about the requested parameter (given as a string).
+ Return NULL when the string is not a valid parameter name.
+***************************************************************************/
+
+struct parm_struct *lp_get_parameter(const char *param_name)
+{
+ int num = map_parameter(param_name);
+
+ if (num < 0) {
+ return NULL;
+ }
+
+ return &parm_table[num];
+}
+
+/***************************************************************************
+ Return info about the next parameter in a service.
+ snum==GLOBAL_SECTION_SNUM gives the globals.
+ Return NULL when out of parameters.
+***************************************************************************/
+
+struct parm_struct *lp_next_parameter(int snum, int *i, int allparameters)
+{
+ if (snum < 0) {
+ /* do the globals */
+ for (; parm_table[*i].label; (*i)++) {
+ if (parm_table[*i].p_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;
+
+ if (is_default(*i) && !allparameters)
+ continue;
+
+ return &parm_table[(*i)++];
+ }
+ } else {
+ struct service *pService = ServicePtrs[snum];
+
+ for (; parm_table[*i].label; (*i)++) {
+ if (parm_table[*i].p_class == P_SEPARATOR)
+ return &parm_table[(*i)++];
+
+ if (parm_table[*i].p_class == P_LOCAL &&
+ parm_table[*i].ptr &&
+ (*parm_table[*i].label != '-') &&
+ ((*i) == 0 ||
+ (parm_table[*i].ptr !=
+ parm_table[(*i) - 1].ptr)))
+ {
+ int pdiff =
+ PTR_DIFF(parm_table[*i].ptr,
+ &sDefault);
+
+ if (allparameters ||
+ !equal_parameter(parm_table[*i].type,
+ ((char *)pService) +
+ pdiff,
+ ((char *)&sDefault) +
+ pdiff))
+ {
+ return &parm_table[(*i)++];
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+#if 0
+/***************************************************************************
+ Display the contents of a single copy structure.
+***************************************************************************/
+static void dump_copy_map(bool *pcopymap)
+{
+ int i;
+ if (!pcopymap)
+ return;
+
+ printf("\n\tNon-Copied parameters:\n");
+
+ for (i = 0; parm_table[i].label; i++)
+ if (parm_table[i].p_class == P_LOCAL &&
+ parm_table[i].ptr && !pcopymap[i] &&
+ (i == 0 || (parm_table[i].ptr != parm_table[i - 1].ptr)))
+ {
+ printf("\t\t%s\n", parm_table[i].label);
+ }
+}
+#endif
+
+/***************************************************************************
+ Return TRUE if the passed service number is within range.
+***************************************************************************/
+
+bool lp_snum_ok(int iService)
+{
+ return (LP_SNUM_OK(iService) && ServicePtrs[iService]->bAvailable);
+}
+
+/***************************************************************************
+ Auto-load some home services.
+***************************************************************************/
+
+static void lp_add_auto_services(char *str)
+{
+ char *s;
+ char *p;
+ int homes;
+ char *saveptr;
+
+ if (!str)
+ return;
+
+ s = SMB_STRDUP(str);
+ if (!s)
+ return;
+
+ homes = lp_servicenumber(HOMES_NAME);
+
+ for (p = strtok_r(s, LIST_SEP, &saveptr); p;
+ p = strtok_r(NULL, LIST_SEP, &saveptr)) {
+ char *home;
+
+ if (lp_servicenumber(p) >= 0)
+ continue;
+
+ home = get_user_home_dir(talloc_tos(), p);
+
+ if (home && homes >= 0)
+ lp_add_home(p, homes, p, home);
+
+ TALLOC_FREE(home);
+ }
+ SAFE_FREE(s);
+}
+
+/***************************************************************************
+ Auto-load one printer.
+***************************************************************************/
+
+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(&ServicePtrs[i]->comment, comment);
+ ServicePtrs[i]->autoloaded = True;
+ }
+ }
+}
+
+/***************************************************************************
+ Have we loaded a services file yet?
+***************************************************************************/
+
+bool lp_loaded(void)
+{
+ return (bLoaded);
+}
+
+/***************************************************************************
+ Unload unused services.
+***************************************************************************/
+
+void lp_killunused(bool (*snumused) (int))
+{
+ int i;
+ for (i = 0; i < iNumServices; i++) {
+ if (!VALID(i))
+ continue;
+
+ /* don't kill autoloaded or usershare services */
+ if ( ServicePtrs[i]->autoloaded ||
+ ServicePtrs[i]->usershare == USERSHARE_VALID) {
+ continue;
+ }
+
+ if (!snumused || !snumused(i)) {
+ free_service_byindex(i);
+ }
+ }
+}
+
+/**
+ * Kill all except autoloaded and usershare services - convenience wrapper
+ */
+void lp_kill_all_services(void)
+{
+ lp_killunused(NULL);
+}
+
+/***************************************************************************
+ Unload a service.
+***************************************************************************/
+
+void lp_killservice(int iServiceIn)
+{
+ if (VALID(iServiceIn)) {
+ free_service_byindex(iServiceIn);
+ }
+}
+
+/***************************************************************************
+ 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_LIST:
+ str_list_copy(
+ NULL, &(parm_table[i].def.lvalue),
+ *(const char ***)parm_table[i].ptr);
+ break;
+ case P_STRING:
+ case P_USTRING:
+ if (parm_table[i].ptr) {
+ parm_table[i].def.svalue = SMB_STRDUP(*(char **)parm_table[i].ptr);
+ } else {
+ parm_table[i].def.svalue = NULL;
+ }
+ break;
+ case P_BOOL:
+ case P_BOOLREV:
+ parm_table[i].def.bvalue =
+ *(bool *)parm_table[i].ptr;
+ break;
+ case P_CHAR:
+ parm_table[i].def.cvalue =
+ *(char *)parm_table[i].ptr;
+ break;
+ case P_INTEGER:
+ case P_OCTAL:
+ case P_ENUM:
+ parm_table[i].def.ivalue =
+ *(int *)parm_table[i].ptr;
+ break;
+ case P_SEP:
+ break;
+ }
+ }
+ defaults_saved = True;
+}
+
+/*******************************************************************
+ Set the server type we will announce as via nmbd.
+********************************************************************/
+
+static const struct srv_role_tab {
+ uint32 role;
+ const char *role_str;
+} srv_role_tab [] = {
+ { ROLE_STANDALONE, "ROLE_STANDALONE" },
+ { ROLE_DOMAIN_MEMBER, "ROLE_DOMAIN_MEMBER" },
+ { ROLE_DOMAIN_BDC, "ROLE_DOMAIN_BDC" },
+ { ROLE_DOMAIN_PDC, "ROLE_DOMAIN_PDC" },
+ { 0, NULL }
+};
+
+const char* server_role_str(uint32 role)
+{
+ int i = 0;
+ for (i=0; srv_role_tab[i].role_str; i++) {
+ if (role == srv_role_tab[i].role) {
+ return srv_role_tab[i].role_str;
+ }
+ }
+ return NULL;
+}
+
+static void set_server_role(void)
+{
+ server_role = ROLE_STANDALONE;
+
+ switch (lp_security()) {
+ case SEC_SHARE:
+ if (lp_domain_logons())
+ DEBUG(0, ("Server's Role (logon server) conflicts with share-level security\n"));
+ break;
+ case SEC_SERVER:
+ if (lp_domain_logons())
+ DEBUG(0, ("Server's Role (logon server) conflicts with server-level security\n"));
+ /* this used to be considered ROLE_DOMAIN_MEMBER but that's just wrong */
+ server_role = ROLE_STANDALONE;
+ break;
+ case SEC_DOMAIN:
+ if (lp_domain_logons()) {
+ DEBUG(1, ("Server's Role (logon server) NOT ADVISED with domain-level security\n"));
+ server_role = ROLE_DOMAIN_BDC;
+ break;
+ }
+ server_role = ROLE_DOMAIN_MEMBER;
+ break;
+ case SEC_ADS:
+ if (lp_domain_logons()) {
+ server_role = ROLE_DOMAIN_PDC;
+ break;
+ }
+ server_role = ROLE_DOMAIN_MEMBER;
+ break;
+ case SEC_USER:
+ if (lp_domain_logons()) {
+
+ if (Globals.iDomainMaster) /* auto or yes */
+ server_role = ROLE_DOMAIN_PDC;
+ else
+ server_role = ROLE_DOMAIN_BDC;
+ }
+ break;
+ default:
+ DEBUG(0, ("Server's Role undefined due to unknown security mode\n"));
+ break;
+ }
+
+ DEBUG(10, ("set_server_role: role = %s\n", server_role_str(server_role)));
+}
+
+/***********************************************************
+ If we should send plaintext/LANMAN passwords in the clinet
+************************************************************/
+
+static void set_allowed_client_auth(void)
+{
+ if (Globals.bClientNTLMv2Auth) {
+ Globals.bClientLanManAuth = False;
+ }
+ if (!Globals.bClientLanManAuth) {
+ Globals.bClientPlaintextAuth = False;
+ }
+}
+
+/***************************************************************************
+ JRA.
+ The following code allows smbd to read a user defined share file.
+ Yes, this is my intent. Yes, I'm comfortable with that...
+
+ THE FOLLOWING IS SECURITY CRITICAL CODE.
+
+ It washes your clothes, it cleans your house, it guards you while you sleep...
+ Do not f%^k with it....
+***************************************************************************/
+
+#define MAX_USERSHARE_FILE_SIZE (10*1024)
+
+/***************************************************************************
+ Check allowed stat state of a usershare file.
+ Ensure we print out who is dicking with us so the admin can
+ get their sorry ass fired.
+***************************************************************************/
+
+static bool check_usershare_stat(const char *fname, SMB_STRUCT_STAT *psbuf)
+{
+ if (!S_ISREG(psbuf->st_mode)) {
+ DEBUG(0,("check_usershare_stat: file %s owned by uid %u is "
+ "not a regular file\n",
+ fname, (unsigned int)psbuf->st_uid ));
+ return False;
+ }
+
+ /* Ensure this doesn't have the other write bit set. */
+ if (psbuf->st_mode & S_IWOTH) {
+ DEBUG(0,("check_usershare_stat: file %s owned by uid %u allows "
+ "public write. Refusing to allow as a usershare file.\n",
+ fname, (unsigned int)psbuf->st_uid ));
+ return False;
+ }
+
+ /* Should be 10k or less. */
+ if (psbuf->st_size > MAX_USERSHARE_FILE_SIZE) {
+ DEBUG(0,("check_usershare_stat: file %s owned by uid %u is "
+ "too large (%u) to be a user share file.\n",
+ fname, (unsigned int)psbuf->st_uid,
+ (unsigned int)psbuf->st_size ));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ Parse the contents of a usershare file.
+***************************************************************************/
+
+enum usershare_err parse_usershare_file(TALLOC_CTX *ctx,
+ SMB_STRUCT_STAT *psbuf,
+ const char *servicename,
+ int snum,
+ char **lines,
+ int numlines,
+ char **pp_sharepath,
+ char **pp_comment,
+ SEC_DESC **ppsd,
+ bool *pallow_guest)
+{
+ const char **prefixallowlist = lp_usershare_prefix_allow_list();
+ const char **prefixdenylist = lp_usershare_prefix_deny_list();
+ int us_vers;
+ SMB_STRUCT_DIR *dp;
+ SMB_STRUCT_STAT sbuf;
+ char *sharepath = NULL;
+ char *comment = NULL;
+
+ *pp_sharepath = NULL;
+ *pp_comment = NULL;
+
+ *pallow_guest = False;
+
+ if (numlines < 4) {
+ return USERSHARE_MALFORMED_FILE;
+ }
+
+ if (strcmp(lines[0], "#VERSION 1") == 0) {
+ us_vers = 1;
+ } else if (strcmp(lines[0], "#VERSION 2") == 0) {
+ us_vers = 2;
+ if (numlines < 5) {
+ return USERSHARE_MALFORMED_FILE;
+ }
+ } else {
+ return USERSHARE_BAD_VERSION;
+ }
+
+ if (strncmp(lines[1], "path=", 5) != 0) {
+ return USERSHARE_MALFORMED_PATH;
+ }
+
+ sharepath = talloc_strdup(ctx, &lines[1][5]);
+ if (!sharepath) {
+ return USERSHARE_POSIX_ERR;
+ }
+ trim_string(sharepath, " ", " ");
+
+ if (strncmp(lines[2], "comment=", 8) != 0) {
+ return USERSHARE_MALFORMED_COMMENT_DEF;
+ }
+
+ comment = talloc_strdup(ctx, &lines[2][8]);
+ if (!comment) {
+ return USERSHARE_POSIX_ERR;
+ }
+ trim_string(comment, " ", " ");
+ trim_char(comment, '"', '"');
+
+ if (strncmp(lines[3], "usershare_acl=", 14) != 0) {
+ return USERSHARE_MALFORMED_ACL_DEF;
+ }
+
+ if (!parse_usershare_acl(ctx, &lines[3][14], ppsd)) {
+ return USERSHARE_ACL_ERR;
+ }
+
+ if (us_vers == 2) {
+ if (strncmp(lines[4], "guest_ok=", 9) != 0) {
+ return USERSHARE_MALFORMED_ACL_DEF;
+ }
+ if (lines[4][9] == 'y') {
+ *pallow_guest = True;
+ }
+ }
+
+ if (snum != -1 && (strcmp(sharepath, ServicePtrs[snum]->szPath) == 0)) {
+ /* Path didn't change, no checks needed. */
+ *pp_sharepath = sharepath;
+ *pp_comment = comment;
+ return USERSHARE_OK;
+ }
+
+ /* The path *must* be absolute. */
+ if (sharepath[0] != '/') {
+ DEBUG(2,("parse_usershare_file: share %s: path %s is not an absolute path.\n",
+ servicename, sharepath));
+ return USERSHARE_PATH_NOT_ABSOLUTE;
+ }
+
+ /* If there is a usershare prefix deny list ensure one of these paths
+ doesn't match the start of the user given path. */
+ if (prefixdenylist) {
+ int i;
+ for ( i=0; prefixdenylist[i]; i++ ) {
+ DEBUG(10,("parse_usershare_file: share %s : checking prefixdenylist[%d]='%s' against %s\n",
+ servicename, i, prefixdenylist[i], sharepath ));
+ if (memcmp( sharepath, prefixdenylist[i], strlen(prefixdenylist[i])) == 0) {
+ DEBUG(2,("parse_usershare_file: share %s path %s starts with one of the "
+ "usershare prefix deny list entries.\n",
+ servicename, sharepath));
+ return USERSHARE_PATH_IS_DENIED;
+ }
+ }
+ }
+
+ /* If there is a usershare prefix allow list ensure one of these paths
+ does match the start of the user given path. */
+
+ if (prefixallowlist) {
+ int i;
+ for ( i=0; prefixallowlist[i]; i++ ) {
+ DEBUG(10,("parse_usershare_file: share %s checking prefixallowlist[%d]='%s' against %s\n",
+ servicename, i, prefixallowlist[i], sharepath ));
+ if (memcmp( sharepath, prefixallowlist[i], strlen(prefixallowlist[i])) == 0) {
+ break;
+ }
+ }
+ if (prefixallowlist[i] == NULL) {
+ DEBUG(2,("parse_usershare_file: share %s path %s doesn't start with one of the "
+ "usershare prefix allow list entries.\n",
+ servicename, sharepath));
+ return USERSHARE_PATH_NOT_ALLOWED;
+ }
+ }
+
+ /* Ensure this is pointing to a directory. */
+ dp = sys_opendir(sharepath);
+
+ if (!dp) {
+ DEBUG(2,("parse_usershare_file: share %s path %s is not a directory.\n",
+ servicename, sharepath));
+ return USERSHARE_PATH_NOT_DIRECTORY;
+ }
+
+ /* Ensure the owner of the usershare file has permission to share
+ this directory. */
+
+ if (sys_stat(sharepath, &sbuf) == -1) {
+ DEBUG(2,("parse_usershare_file: share %s : stat failed on path %s. %s\n",
+ servicename, sharepath, strerror(errno) ));
+ sys_closedir(dp);
+ return USERSHARE_POSIX_ERR;
+ }
+
+ sys_closedir(dp);
+
+ if (!S_ISDIR(sbuf.st_mode)) {
+ DEBUG(2,("parse_usershare_file: share %s path %s is not a directory.\n",
+ servicename, sharepath ));
+ return USERSHARE_PATH_NOT_DIRECTORY;
+ }
+
+ /* Check if sharing is restricted to owner-only. */
+ /* psbuf is the stat of the usershare definition file,
+ sbuf is the stat of the target directory to be shared. */
+
+ if (lp_usershare_owner_only()) {
+ /* root can share anything. */
+ if ((psbuf->st_uid != 0) && (sbuf.st_uid != psbuf->st_uid)) {
+ return USERSHARE_PATH_NOT_ALLOWED;
+ }
+ }
+
+ *pp_sharepath = sharepath;
+ *pp_comment = comment;
+ return USERSHARE_OK;
+}
+
+/***************************************************************************
+ Deal with a usershare file.
+ Returns:
+ >= 0 - snum
+ -1 - Bad name, invalid contents.
+ - service name already existed and not a usershare, problem
+ with permissions to share directory etc.
+***************************************************************************/
+
+static int process_usershare_file(const char *dir_name, const char *file_name, int snum_template)
+{
+ SMB_STRUCT_STAT sbuf;
+ SMB_STRUCT_STAT lsbuf;
+ char *fname = NULL;
+ char *sharepath = NULL;
+ char *comment = NULL;
+ fstring service_name;
+ char **lines = NULL;
+ int numlines = 0;
+ int fd = -1;
+ int iService = -1;
+ TALLOC_CTX *ctx = NULL;
+ SEC_DESC *psd = NULL;
+ bool guest_ok = False;
+
+ /* Ensure share name doesn't contain invalid characters. */
+ if (!validate_net_name(file_name, INVALID_SHARENAME_CHARS, strlen(file_name))) {
+ DEBUG(0,("process_usershare_file: share name %s contains "
+ "invalid characters (any of %s)\n",
+ file_name, INVALID_SHARENAME_CHARS ));
+ return -1;
+ }
+
+ fstrcpy(service_name, file_name);
+
+ if (asprintf(&fname, "%s/%s", dir_name, file_name) < 0) {
+ }
+
+ /* Minimize the race condition by doing an lstat before we
+ open and fstat. Ensure this isn't a symlink link. */
+
+ if (sys_lstat(fname, &lsbuf) != 0) {
+ DEBUG(0,("process_usershare_file: stat of %s failed. %s\n",
+ fname, strerror(errno) ));
+ SAFE_FREE(fname);
+ return -1;
+ }
+
+ /* This must be a regular file, not a symlink, directory or
+ other strange filetype. */
+ if (!check_usershare_stat(fname, &lsbuf)) {
+ SAFE_FREE(fname);
+ return -1;
+ }
+
+ {
+ char *canon_name = canonicalize_servicename(service_name);
+ TDB_DATA data = dbwrap_fetch_bystring(
+ ServiceHash, canon_name, canon_name);
+
+ iService = -1;
+
+ if ((data.dptr != NULL) && (data.dsize == sizeof(iService))) {
+ iService = *(int *)data.dptr;
+ }
+ TALLOC_FREE(canon_name);
+ }
+
+ if (iService != -1 && ServicePtrs[iService]->usershare_last_mod == lsbuf.st_mtime) {
+ /* Nothing changed - Mark valid and return. */
+ DEBUG(10,("process_usershare_file: service %s not changed.\n",
+ service_name ));
+ ServicePtrs[iService]->usershare = USERSHARE_VALID;
+ SAFE_FREE(fname);
+ return iService;
+ }
+
+ /* Try and open the file read only - no symlinks allowed. */
+#ifdef O_NOFOLLOW
+ fd = sys_open(fname, O_RDONLY|O_NOFOLLOW, 0);
+#else
+ fd = sys_open(fname, O_RDONLY, 0);
+#endif
+
+ if (fd == -1) {
+ DEBUG(0,("process_usershare_file: unable to open %s. %s\n",
+ fname, strerror(errno) ));
+ SAFE_FREE(fname);
+ return -1;
+ }
+
+ /* Now fstat to be *SURE* it's a regular file. */
+ if (sys_fstat(fd, &sbuf) != 0) {
+ close(fd);
+ DEBUG(0,("process_usershare_file: fstat of %s failed. %s\n",
+ fname, strerror(errno) ));
+ SAFE_FREE(fname);
+ return -1;
+ }
+
+ /* Is it the same dev/inode as was lstated ? */
+ if (lsbuf.st_dev != sbuf.st_dev || lsbuf.st_ino != sbuf.st_ino) {
+ close(fd);
+ DEBUG(0,("process_usershare_file: fstat of %s is a different file from lstat. "
+ "Symlink spoofing going on ?\n", fname ));
+ SAFE_FREE(fname);
+ return -1;
+ }
+
+ /* This must be a regular file, not a symlink, directory or
+ other strange filetype. */
+ if (!check_usershare_stat(fname, &sbuf)) {
+ SAFE_FREE(fname);
+ return -1;
+ }
+
+ lines = fd_lines_load(fd, &numlines, MAX_USERSHARE_FILE_SIZE);
+
+ close(fd);
+ if (lines == NULL) {
+ DEBUG(0,("process_usershare_file: loading file %s owned by %u failed.\n",
+ fname, (unsigned int)sbuf.st_uid ));
+ SAFE_FREE(fname);
+ return -1;
+ }
+
+ SAFE_FREE(fname);
+
+ /* Should we allow printers to be shared... ? */
+ ctx = talloc_init("usershare_sd_xctx");
+ if (!ctx) {
+ file_lines_free(lines);
+ return 1;
+ }
+
+ if (parse_usershare_file(ctx, &sbuf, service_name,
+ iService, lines, numlines, &sharepath,
+ &comment, &psd, &guest_ok) != USERSHARE_OK) {
+ talloc_destroy(ctx);
+ file_lines_free(lines);
+ return -1;
+ }
+
+ file_lines_free(lines);
+
+ /* Everything ok - add the service possibly using a template. */
+ if (iService < 0) {
+ const struct service *sp = &sDefault;
+ if (snum_template != -1) {
+ sp = ServicePtrs[snum_template];
+ }
+
+ if ((iService = add_a_service(sp, service_name)) < 0) {
+ DEBUG(0, ("process_usershare_file: Failed to add "
+ "new service %s\n", service_name));
+ talloc_destroy(ctx);
+ return -1;
+ }
+
+ /* Read only is controlled by usershare ACL below. */
+ ServicePtrs[iService]->bRead_only = False;
+ }
+
+ /* Write the ACL of the new/modified share. */
+ if (!set_share_security(service_name, psd)) {
+ DEBUG(0, ("process_usershare_file: Failed to set share "
+ "security for user share %s\n",
+ service_name ));
+ lp_remove_service(iService);
+ talloc_destroy(ctx);
+ return -1;
+ }
+
+ /* If from a template it may be marked invalid. */
+ ServicePtrs[iService]->valid = True;
+
+ /* Set the service as a valid usershare. */
+ ServicePtrs[iService]->usershare = USERSHARE_VALID;
+
+ /* Set guest access. */
+ if (lp_usershare_allow_guests()) {
+ ServicePtrs[iService]->bGuest_ok = guest_ok;
+ }
+
+ /* And note when it was loaded. */
+ ServicePtrs[iService]->usershare_last_mod = sbuf.st_mtime;
+ string_set(&ServicePtrs[iService]->szPath, sharepath);
+ string_set(&ServicePtrs[iService]->comment, comment);
+
+ talloc_destroy(ctx);
+
+ return iService;
+}
+
+/***************************************************************************
+ Checks if a usershare entry has been modified since last load.
+***************************************************************************/
+
+static bool usershare_exists(int iService, time_t *last_mod)
+{
+ SMB_STRUCT_STAT lsbuf;
+ const char *usersharepath = Globals.szUsersharePath;
+ char *fname;
+
+ if (asprintf(&fname, "%s/%s",
+ usersharepath,
+ ServicePtrs[iService]->szService) < 0) {
+ return false;
+ }
+
+ if (sys_lstat(fname, &lsbuf) != 0) {
+ SAFE_FREE(fname);
+ return false;
+ }
+
+ if (!S_ISREG(lsbuf.st_mode)) {
+ SAFE_FREE(fname);
+ return false;
+ }
+
+ SAFE_FREE(fname);
+ *last_mod = lsbuf.st_mtime;
+ return true;
+}
+
+/***************************************************************************
+ Load a usershare service by name. Returns a valid servicenumber or -1.
+***************************************************************************/
+
+int load_usershare_service(const char *servicename)
+{
+ SMB_STRUCT_STAT sbuf;
+ const char *usersharepath = Globals.szUsersharePath;
+ int max_user_shares = Globals.iUsershareMaxShares;
+ int snum_template = -1;
+
+ if (*usersharepath == 0 || max_user_shares == 0) {
+ return -1;
+ }
+
+ if (sys_stat(usersharepath, &sbuf) != 0) {
+ DEBUG(0,("load_usershare_service: stat of %s failed. %s\n",
+ usersharepath, strerror(errno) ));
+ return -1;
+ }
+
+ if (!S_ISDIR(sbuf.st_mode)) {
+ DEBUG(0,("load_usershare_service: %s is not a directory.\n",
+ usersharepath ));
+ return -1;
+ }
+
+ /*
+ * This directory must be owned by root, and have the 't' bit set.
+ * It also must not be writable by "other".
+ */
+
+#ifdef S_ISVTX
+ if (sbuf.st_uid != 0 || !(sbuf.st_mode & S_ISVTX) || (sbuf.st_mode & S_IWOTH)) {
+#else
+ if (sbuf.st_uid != 0 || (sbuf.st_mode & S_IWOTH)) {
+#endif
+ DEBUG(0,("load_usershare_service: directory %s is not owned by root "
+ "or does not have the sticky bit 't' set or is writable by anyone.\n",
+ usersharepath ));
+ return -1;
+ }
+
+ /* Ensure the template share exists if it's set. */
+ if (Globals.szUsershareTemplateShare[0]) {
+ /* We can't use lp_servicenumber here as we are recommending that
+ template shares have -valid=False set. */
+ for (snum_template = iNumServices - 1; snum_template >= 0; snum_template--) {
+ if (ServicePtrs[snum_template]->szService &&
+ strequal(ServicePtrs[snum_template]->szService,
+ Globals.szUsershareTemplateShare)) {
+ break;
+ }
+ }
+
+ if (snum_template == -1) {
+ DEBUG(0,("load_usershare_service: usershare template share %s "
+ "does not exist.\n",
+ Globals.szUsershareTemplateShare ));
+ return -1;
+ }
+ }
+
+ return process_usershare_file(usersharepath, servicename, snum_template);
+}
+
+/***************************************************************************
+ Load all user defined shares from the user share directory.
+ We only do this if we're enumerating the share list.
+ This is the function that can delete usershares that have
+ been removed.
+***************************************************************************/
+
+int load_usershare_shares(void)
+{
+ SMB_STRUCT_DIR *dp;
+ SMB_STRUCT_STAT sbuf;
+ SMB_STRUCT_DIRENT *de;
+ int num_usershares = 0;
+ int max_user_shares = Globals.iUsershareMaxShares;
+ unsigned int num_dir_entries, num_bad_dir_entries, num_tmp_dir_entries;
+ unsigned int allowed_bad_entries = ((2*max_user_shares)/10);
+ unsigned int allowed_tmp_entries = ((2*max_user_shares)/10);
+ int iService;
+ int snum_template = -1;
+ const char *usersharepath = Globals.szUsersharePath;
+ int ret = lp_numservices();
+
+ if (max_user_shares == 0 || *usersharepath == '\0') {
+ return lp_numservices();
+ }
+
+ if (sys_stat(usersharepath, &sbuf) != 0) {
+ DEBUG(0,("load_usershare_shares: stat of %s failed. %s\n",
+ usersharepath, strerror(errno) ));
+ return ret;
+ }
+
+ /*
+ * This directory must be owned by root, and have the 't' bit set.
+ * It also must not be writable by "other".
+ */
+
+#ifdef S_ISVTX
+ if (sbuf.st_uid != 0 || !(sbuf.st_mode & S_ISVTX) || (sbuf.st_mode & S_IWOTH)) {
+#else
+ if (sbuf.st_uid != 0 || (sbuf.st_mode & S_IWOTH)) {
+#endif
+ DEBUG(0,("load_usershare_shares: directory %s is not owned by root "
+ "or does not have the sticky bit 't' set or is writable by anyone.\n",
+ usersharepath ));
+ return ret;
+ }
+
+ /* Ensure the template share exists if it's set. */
+ if (Globals.szUsershareTemplateShare[0]) {
+ /* We can't use lp_servicenumber here as we are recommending that
+ template shares have -valid=False set. */
+ for (snum_template = iNumServices - 1; snum_template >= 0; snum_template--) {
+ if (ServicePtrs[snum_template]->szService &&
+ strequal(ServicePtrs[snum_template]->szService,
+ Globals.szUsershareTemplateShare)) {
+ break;
+ }
+ }
+
+ if (snum_template == -1) {
+ DEBUG(0,("load_usershare_shares: usershare template share %s "
+ "does not exist.\n",
+ Globals.szUsershareTemplateShare ));
+ return ret;
+ }
+ }
+
+ /* Mark all existing usershares as pending delete. */
+ for (iService = iNumServices - 1; iService >= 0; iService--) {
+ if (VALID(iService) && ServicePtrs[iService]->usershare) {
+ ServicePtrs[iService]->usershare = USERSHARE_PENDING_DELETE;
+ }
+ }
+
+ dp = sys_opendir(usersharepath);
+ if (!dp) {
+ DEBUG(0,("load_usershare_shares:: failed to open directory %s. %s\n",
+ usersharepath, strerror(errno) ));
+ return ret;
+ }
+
+ for (num_dir_entries = 0, num_bad_dir_entries = 0, num_tmp_dir_entries = 0;
+ (de = sys_readdir(dp));
+ num_dir_entries++ ) {
+ int r;
+ const char *n = de->d_name;
+
+ /* Ignore . and .. */
+ if (*n == '.') {
+ if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
+ continue;
+ }
+ }
+
+ if (n[0] == ':') {
+ /* Temporary file used when creating a share. */
+ num_tmp_dir_entries++;
+ }
+
+ /* Allow 20% tmp entries. */
+ if (num_tmp_dir_entries > allowed_tmp_entries) {
+ DEBUG(0,("load_usershare_shares: too many temp entries (%u) "
+ "in directory %s\n",
+ num_tmp_dir_entries, usersharepath));
+ break;
+ }
+
+ r = process_usershare_file(usersharepath, n, snum_template);
+ if (r == 0) {
+ /* Update the services count. */
+ num_usershares++;
+ if (num_usershares >= max_user_shares) {
+ DEBUG(0,("load_usershare_shares: max user shares reached "
+ "on file %s in directory %s\n",
+ n, usersharepath ));
+ break;
+ }
+ } else if (r == -1) {
+ num_bad_dir_entries++;
+ }
+
+ /* Allow 20% bad entries. */
+ if (num_bad_dir_entries > allowed_bad_entries) {
+ DEBUG(0,("load_usershare_shares: too many bad entries (%u) "
+ "in directory %s\n",
+ num_bad_dir_entries, usersharepath));
+ break;
+ }
+
+ /* Allow 20% bad entries. */
+ if (num_dir_entries > max_user_shares + allowed_bad_entries) {
+ DEBUG(0,("load_usershare_shares: too many total entries (%u) "
+ "in directory %s\n",
+ num_dir_entries, usersharepath));
+ break;
+ }
+ }
+
+ sys_closedir(dp);
+
+ /* Sweep through and delete any non-refreshed usershares that are
+ not currently in use. */
+ for (iService = iNumServices - 1; iService >= 0; iService--) {
+ if (VALID(iService) && (ServicePtrs[iService]->usershare == USERSHARE_PENDING_DELETE)) {
+ if (conn_snum_used(iService)) {
+ continue;
+ }
+ /* Remove from the share ACL db. */
+ DEBUG(10,("load_usershare_shares: Removing deleted usershare %s\n",
+ lp_servicename(iService) ));
+ delete_share_security(lp_servicename(iService));
+ free_service_byindex(iService);
+ }
+ }
+
+ return lp_numservices();
+}
+
+/********************************************************
+ Destroy global resources allocated in this file
+********************************************************/
+
+void gfree_loadparm(void)
+{
+ struct file_lists *f;
+ struct file_lists *next;
+ int i;
+
+ /* Free the file lists */
+
+ f = file_lists;
+ while( f ) {
+ next = f->next;
+ SAFE_FREE( f->name );
+ SAFE_FREE( f->subfname );
+ SAFE_FREE( f );
+ f = next;
+ }
+ file_lists = NULL;
+
+ /* Free resources allocated to services */
+
+ for ( i = 0; i < iNumServices; i++ ) {
+ if ( VALID(i) ) {
+ free_service_byindex(i);
+ }
+ }
+
+ SAFE_FREE( ServicePtrs );
+ iNumServices = 0;
+
+ /* Now release all resources allocated to global
+ parameters and the default service */
+
+ for (i = 0; parm_table[i].label; i++)
+ {
+ if ( parm_table[i].type == P_STRING
+ || parm_table[i].type == P_USTRING )
+ {
+ string_free( (char**)parm_table[i].ptr );
+ }
+ else if (parm_table[i].type == P_LIST) {
+ TALLOC_FREE( *((char***)parm_table[i].ptr) );
+ }
+ }
+}
+
+
+/***************************************************************************
+ Allow client apps to specify that they are a client
+***************************************************************************/
+void lp_set_in_client(bool b)
+{
+ in_client = b;
+}
+
+
+/***************************************************************************
+ Determine if we're running in a client app
+***************************************************************************/
+bool lp_is_in_client(void)
+{
+ return in_client;
+}
+
+
+
+
+/***************************************************************************
+ Load the services array from the services file. Return True on success,
+ False on failure.
+***************************************************************************/
+
+bool lp_load_ex(const char *pszFname,
+ bool global_only,
+ bool save_defaults,
+ bool add_ipc,
+ bool initialize_globals,
+ bool allow_include_registry,
+ bool allow_registry_shares)
+{
+ char *n2 = NULL;
+ bool bRetval;
+ struct param_opt_struct *data, *pdata;
+
+ bRetval = False;
+
+ DEBUG(3, ("lp_load_ex: refreshing parameters\n"));
+
+ bInGlobalSection = True;
+ bGlobalOnly = global_only;
+ bAllowIncludeRegistry = allow_include_registry;
+
+ init_globals(! initialize_globals);
+ debug_init();
+
+ if (save_defaults) {
+ init_locals();
+ lp_save_defaults();
+ }
+
+ /* We get sections first, so have to start 'behind' to make up */
+ iServiceIndex = -1;
+
+ if (Globals.param_opt != NULL) {
+ data = Globals.param_opt;
+ while (data) {
+ string_free(&data->key);
+ string_free(&data->value);
+ TALLOC_FREE(data->list);
+ pdata = data->next;
+ SAFE_FREE(data);
+ data = pdata;
+ }
+ Globals.param_opt = NULL;
+ }
+
+ if (lp_config_backend_is_file()) {
+ n2 = alloc_sub_basic(get_current_username(),
+ current_user_info.domain,
+ pszFname);
+ if (!n2) {
+ smb_panic("lp_load_ex: out of memory");
+ }
+
+ add_to_file_list(pszFname, n2);
+
+ bRetval = pm_process(n2, do_section, do_parameter, NULL);
+ SAFE_FREE(n2);
+
+ /* finish up the last section */
+ DEBUG(4, ("pm_process() returned %s\n", BOOLSTR(bRetval)));
+ if (bRetval) {
+ if (iServiceIndex >= 0) {
+ bRetval = service_ok(iServiceIndex);
+ }
+ }
+
+ if (lp_config_backend_is_registry()) {
+ /* config backend changed to registry in config file */
+ /*
+ * We need to use this extra global variable here to
+ * survive restart: init_globals uses this as a default
+ * for ConfigBackend. Otherwise, init_globals would
+ * send us into an endless loop here.
+ */
+ config_backend = CONFIG_BACKEND_REGISTRY;
+ /* start over */
+ DEBUG(1, ("lp_load_ex: changing to config backend "
+ "registry\n"));
+ init_globals(false);
+ lp_kill_all_services();
+ return lp_load_ex(pszFname, global_only, save_defaults,
+ add_ipc, initialize_globals,
+ allow_include_registry,
+ allow_registry_shares);
+ }
+ } else if (lp_config_backend_is_registry()) {
+ bRetval = process_registry_globals();
+ } else {
+ DEBUG(0, ("Illegal config backend given: %d\n",
+ lp_config_backend()));
+ bRetval = false;
+ }
+
+ if (bRetval && lp_registry_shares() && allow_registry_shares) {
+ bRetval = process_registry_shares();
+ }
+
+ lp_add_auto_services(lp_auto_services());
+
+ if (add_ipc) {
+ /* When 'restrict anonymous = 2' guest connections to ipc$
+ are denied */
+ lp_add_ipc("IPC$", (lp_restrict_anonymous() < 2));
+ if ( lp_enable_asu_support() ) {
+ lp_add_ipc("ADMIN$", false);
+ }
+ }
+
+ set_server_role();
+ set_default_server_announce_type();
+ set_allowed_client_auth();
+
+ bLoaded = True;
+
+ /* Now we check bWINSsupport and set szWINSserver to 127.0.0.1 */
+ /* if bWINSsupport is true and we are in the client */
+ if (lp_is_in_client() && Globals.bWINSsupport) {
+ lp_do_parameter(GLOBAL_SECTION_SNUM, "wins server", "127.0.0.1");
+ }
+
+ init_iconv();
+
+ bAllowIncludeRegistry = true;
+
+ return (bRetval);
+}
+
+bool lp_load(const char *pszFname,
+ bool global_only,
+ bool save_defaults,
+ bool add_ipc,
+ bool initialize_globals)
+{
+ return lp_load_ex(pszFname,
+ global_only,
+ save_defaults,
+ add_ipc,
+ initialize_globals,
+ true, false);
+}
+
+bool lp_load_initial_only(const char *pszFname)
+{
+ return lp_load_ex(pszFname,
+ true,
+ false,
+ false,
+ true,
+ false,
+ false);
+}
+
+bool lp_load_with_registry_shares(const char *pszFname,
+ bool global_only,
+ bool save_defaults,
+ bool add_ipc,
+ bool initialize_globals)
+{
+ return lp_load_ex(pszFname,
+ global_only,
+ save_defaults,
+ add_ipc,
+ initialize_globals,
+ true,
+ true);
+}
+
+/***************************************************************************
+ Return the max number of services.
+***************************************************************************/
+
+int lp_numservices(void)
+{
+ return (iNumServices);
+}
+
+/***************************************************************************
+Display the contents of the services array in human-readable form.
+***************************************************************************/
+
+void lp_dump(FILE *f, bool show_defaults, int maxtoprint)
+{
+ int iService;
+
+ if (show_defaults)
+ defaults_saved = False;
+
+ dump_globals(f);
+
+ dump_a_service(&sDefault, f);
+
+ for (iService = 0; iService < maxtoprint; iService++) {
+ fprintf(f,"\n");
+ lp_dump_one(f, show_defaults, iService);
+ }
+}
+
+/***************************************************************************
+Display the contents of one service in human-readable form.
+***************************************************************************/
+
+void lp_dump_one(FILE * f, bool show_defaults, int snum)
+{
+ if (VALID(snum)) {
+ if (ServicePtrs[snum]->szService[0] == '\0')
+ return;
+ dump_a_service(ServicePtrs[snum], f);
+ }
+}
+
+/***************************************************************************
+Return the number of the service with the given name, or -1 if it doesn't
+exist. Note that this is a DIFFERENT ANIMAL from the internal function
+getservicebyname()! This works ONLY if all services have been loaded, and
+does not copy the found service.
+***************************************************************************/
+
+int lp_servicenumber(const char *pszServiceName)
+{
+ int iService;
+ fstring serviceName;
+
+ if (!pszServiceName) {
+ return GLOBAL_SECTION_SNUM;
+ }
+
+ for (iService = iNumServices - 1; iService >= 0; iService--) {
+ if (VALID(iService) && ServicePtrs[iService]->szService) {
+ /*
+ * The substitution here is used to support %U is
+ * service names
+ */
+ fstrcpy(serviceName, ServicePtrs[iService]->szService);
+ standard_sub_basic(get_current_username(),
+ current_user_info.domain,
+ serviceName,sizeof(serviceName));
+ if (strequal(serviceName, pszServiceName)) {
+ break;
+ }
+ }
+ }
+
+ if (iService >= 0 && ServicePtrs[iService]->usershare == USERSHARE_VALID) {
+ time_t last_mod;
+
+ if (!usershare_exists(iService, &last_mod)) {
+ /* Remove the share security tdb entry for it. */
+ delete_share_security(lp_servicename(iService));
+ /* Remove it from the array. */
+ free_service_byindex(iService);
+ /* Doesn't exist anymore. */
+ return GLOBAL_SECTION_SNUM;
+ }
+
+ /* Has it been modified ? If so delete and reload. */
+ if (ServicePtrs[iService]->usershare_last_mod < last_mod) {
+ /* Remove it from the array. */
+ free_service_byindex(iService);
+ /* and now reload it. */
+ iService = load_usershare_service(pszServiceName);
+ }
+ }
+
+ if (iService < 0) {
+ DEBUG(7,("lp_servicenumber: couldn't find %s\n", pszServiceName));
+ return GLOBAL_SECTION_SNUM;
+ }
+
+ return (iService);
+}
+
+bool share_defined(const char *service_name)
+{
+ return (lp_servicenumber(service_name) != -1);
+}
+
+struct share_params *get_share_params(TALLOC_CTX *mem_ctx,
+ const char *sharename)
+{
+ struct share_params *result;
+ char *sname;
+ int snum;
+
+ if (!(sname = SMB_STRDUP(sharename))) {
+ return NULL;
+ }
+
+ snum = find_service(sname);
+ SAFE_FREE(sname);
+
+ if (snum < 0) {
+ return NULL;
+ }
+
+ if (!(result = TALLOC_P(mem_ctx, struct share_params))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ result->service = snum;
+ return result;
+}
+
+struct share_iterator *share_list_all(TALLOC_CTX *mem_ctx)
+{
+ struct share_iterator *result;
+
+ if (!(result = TALLOC_P(mem_ctx, struct share_iterator))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ result->next_id = 0;
+ return result;
+}
+
+struct share_params *next_share(struct share_iterator *list)
+{
+ struct share_params *result;
+
+ while (!lp_snum_ok(list->next_id) &&
+ (list->next_id < lp_numservices())) {
+ list->next_id += 1;
+ }
+
+ if (list->next_id >= lp_numservices()) {
+ return NULL;
+ }
+
+ if (!(result = TALLOC_P(list, struct share_params))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ result->service = list->next_id;
+ list->next_id += 1;
+ return result;
+}
+
+struct share_params *next_printer(struct share_iterator *list)
+{
+ struct share_params *result;
+
+ while ((result = next_share(list)) != NULL) {
+ if (lp_print_ok(result->service)) {
+ break;
+ }
+ }
+ return result;
+}
+
+/*
+ * This is a hack for a transition period until we transformed all code from
+ * service numbers to struct share_params.
+ */
+
+struct share_params *snum2params_static(int snum)
+{
+ static struct share_params result;
+ result.service = snum;
+ return &result;
+}
+
+/*******************************************************************
+ A useful volume label function.
+********************************************************************/
+
+const char *volume_label(int snum)
+{
+ char *ret;
+ const char *label = lp_volume(snum);
+ if (!*label) {
+ label = lp_servicename(snum);
+ }
+
+ /* This returns a 33 byte guarenteed null terminated string. */
+ ret = talloc_strndup(talloc_tos(), label, 32);
+ if (!ret) {
+ return "";
+ }
+ return ret;
+}
+
+/*******************************************************************
+ Set the server type we will announce as via nmbd.
+********************************************************************/
+
+static void set_default_server_announce_type(void)
+{
+ default_server_announce = 0;
+ default_server_announce |= SV_TYPE_WORKSTATION;
+ default_server_announce |= SV_TYPE_SERVER;
+ default_server_announce |= SV_TYPE_SERVER_UNIX;
+
+ /* note that the flag should be set only if we have a
+ printer service but nmbd doesn't actually load the
+ services so we can't tell --jerry */
+
+ default_server_announce |= SV_TYPE_PRINTQ_SERVER;
+
+ switch (lp_announce_as()) {
+ case ANNOUNCE_AS_NT_SERVER:
+ default_server_announce |= SV_TYPE_SERVER_NT;
+ /* fall through... */
+ case ANNOUNCE_AS_NT_WORKSTATION:
+ default_server_announce |= SV_TYPE_NT;
+ break;
+ case ANNOUNCE_AS_WIN95:
+ default_server_announce |= SV_TYPE_WIN95_PLUS;
+ break;
+ case ANNOUNCE_AS_WFW:
+ default_server_announce |= SV_TYPE_WFW;
+ break;
+ default:
+ break;
+ }
+
+ switch (lp_server_role()) {
+ case ROLE_DOMAIN_MEMBER:
+ default_server_announce |= SV_TYPE_DOMAIN_MEMBER;
+ break;
+ case ROLE_DOMAIN_PDC:
+ default_server_announce |= SV_TYPE_DOMAIN_CTRL;
+ break;
+ case ROLE_DOMAIN_BDC:
+ default_server_announce |= SV_TYPE_DOMAIN_BAKCTRL;
+ break;
+ case ROLE_STANDALONE:
+ default:
+ break;
+ }
+ if (lp_time_server())
+ default_server_announce |= SV_TYPE_TIME_SOURCE;
+
+ if (lp_host_msdfs())
+ default_server_announce |= SV_TYPE_DFS_SERVER;
+}
+
+/***********************************************************
+ returns role of Samba server
+************************************************************/
+
+int lp_server_role(void)
+{
+ return server_role;
+}
+
+/***********************************************************
+ If we are PDC then prefer us as DMB
+************************************************************/
+
+bool lp_domain_master(void)
+{
+ if (Globals.iDomainMaster == Auto)
+ return (lp_server_role() == ROLE_DOMAIN_PDC);
+
+ return (bool)Globals.iDomainMaster;
+}
+
+/***********************************************************
+ If we are DMB then prefer us as LMB
+************************************************************/
+
+bool lp_preferred_master(void)
+{
+ if (Globals.iPreferredMaster == Auto)
+ return (lp_local_master() && lp_domain_master());
+
+ return (bool)Globals.iPreferredMaster;
+}
+
+/*******************************************************************
+ Remove a service.
+********************************************************************/
+
+void lp_remove_service(int snum)
+{
+ ServicePtrs[snum]->valid = False;
+ invalid_services[num_invalid_services++] = snum;
+}
+
+/*******************************************************************
+ Copy a service.
+********************************************************************/
+
+void lp_copy_service(int snum, const char *new_name)
+{
+ do_section(new_name, NULL);
+ if (snum >= 0) {
+ snum = lp_servicenumber(new_name);
+ if (snum >= 0)
+ lp_do_parameter(snum, "copy", lp_servicename(snum));
+ }
+}
+
+
+/*******************************************************************
+ Get the default server type we will announce as via nmbd.
+********************************************************************/
+
+int lp_default_server_announce(void)
+{
+ return default_server_announce;
+}
+
+/*******************************************************************
+ Split the announce version into major and minor numbers.
+********************************************************************/
+
+int lp_major_announce_version(void)
+{
+ static bool got_major = False;
+ static int major_version = DEFAULT_MAJOR_VERSION;
+ char *vers;
+ char *p;
+
+ if (got_major)
+ return major_version;
+
+ got_major = True;
+ if ((vers = lp_announce_version()) == NULL)
+ return major_version;
+
+ if ((p = strchr_m(vers, '.')) == 0)
+ return major_version;
+
+ *p = '\0';
+ major_version = atoi(vers);
+ return major_version;
+}
+
+int lp_minor_announce_version(void)
+{
+ static bool got_minor = False;
+ static int minor_version = DEFAULT_MINOR_VERSION;
+ char *vers;
+ char *p;
+
+ if (got_minor)
+ return minor_version;
+
+ got_minor = True;
+ if ((vers = lp_announce_version()) == NULL)
+ return minor_version;
+
+ if ((p = strchr_m(vers, '.')) == 0)
+ return minor_version;
+
+ p++;
+ minor_version = atoi(p);
+ return minor_version;
+}
+
+/***********************************************************
+ Set the global name resolution order (used in smbclient).
+************************************************************/
+
+void lp_set_name_resolve_order(const char *new_order)
+{
+ string_set(&Globals.szNameResolveOrder, new_order);
+}
+
+const char *lp_printername(int snum)
+{
+ const char *ret = _lp_printername(snum);
+ if (ret == NULL || (ret != NULL && *ret == '\0'))
+ ret = lp_const_servicename(snum);
+
+ return ret;
+}
+
+
+/***********************************************************
+ Allow daemons such as winbindd to fix their logfile name.
+************************************************************/
+
+void lp_set_logfile(const char *name)
+{
+ string_set(&Globals.szLogFile, name);
+ debug_set_logfile(name);
+}
+
+/*******************************************************************
+ Return the max print jobs per queue.
+********************************************************************/
+
+int lp_maxprintjobs(int snum)
+{
+ int maxjobs = LP_SNUM_OK(snum) ? ServicePtrs[snum]->iMaxPrintJobs : sDefault.iMaxPrintJobs;
+ if (maxjobs <= 0 || maxjobs >= PRINT_MAX_JOBID)
+ maxjobs = PRINT_MAX_JOBID - 1;
+
+ return maxjobs;
+}
+
+const char *lp_printcapname(void)
+{
+ if ((Globals.szPrintcapname != NULL) &&
+ (Globals.szPrintcapname[0] != '\0'))
+ return Globals.szPrintcapname;
+
+ if (sDefault.iPrinting == PRINT_CUPS) {
+#ifdef HAVE_CUPS
+ return "cups";
+#else
+ return "lpstat";
+#endif
+ }
+
+ if (sDefault.iPrinting == PRINT_BSD)
+ return "/etc/printcap";
+
+ return PRINTCAP_NAME;
+}
+
+/*******************************************************************
+ Ensure we don't use sendfile if server smb signing is active.
+********************************************************************/
+
+static uint32 spoolss_state;
+
+bool lp_disable_spoolss( void )
+{
+ if ( spoolss_state == SVCCTL_STATE_UNKNOWN )
+ spoolss_state = _lp_disable_spoolss() ? SVCCTL_STOPPED : SVCCTL_RUNNING;
+
+ return spoolss_state == SVCCTL_STOPPED ? True : False;
+}
+
+void lp_set_spoolss_state( uint32 state )
+{
+ SMB_ASSERT( (state == SVCCTL_STOPPED) || (state == SVCCTL_RUNNING) );
+
+ spoolss_state = state;
+}
+
+uint32 lp_get_spoolss_state( void )
+{
+ return lp_disable_spoolss() ? SVCCTL_STOPPED : SVCCTL_RUNNING;
+}
+
+/*******************************************************************
+ Ensure we don't use sendfile if server smb signing is active.
+********************************************************************/
+
+bool lp_use_sendfile(int snum)
+{
+ /* Using sendfile blows the brains out of any DOS or Win9x TCP stack... JRA. */
+ if (Protocol < PROTOCOL_NT1) {
+ return False;
+ }
+ return (_lp_use_sendfile(snum) &&
+ (get_remote_arch() != RA_WIN95) &&
+ !srv_is_signing_active());
+}
+
+/*******************************************************************
+ Turn off sendfile if we find the underlying OS doesn't support it.
+********************************************************************/
+
+void set_use_sendfile(int snum, bool val)
+{
+ if (LP_SNUM_OK(snum))
+ ServicePtrs[snum]->bUseSendfile = val;
+ else
+ sDefault.bUseSendfile = val;
+}
+
+/*******************************************************************
+ Turn off storing DOS attributes if this share doesn't support it.
+********************************************************************/
+
+void set_store_dos_attributes(int snum, bool val)
+{
+ if (!LP_SNUM_OK(snum))
+ return;
+ ServicePtrs[(snum)]->bStoreDosAttributes = val;
+}
+
+void lp_set_mangling_method(const char *new_method)
+{
+ string_set(&Globals.szManglingMethod, new_method);
+}
+
+/*******************************************************************
+ Global state for POSIX pathname processing.
+********************************************************************/
+
+static bool posix_pathnames;
+
+bool lp_posix_pathnames(void)
+{
+ return posix_pathnames;
+}
+
+/*******************************************************************
+ Change everything needed to ensure POSIX pathname processing (currently
+ not much).
+********************************************************************/
+
+void lp_set_posix_pathnames(void)
+{
+ posix_pathnames = True;
+}
+
+/*******************************************************************
+ Global state for POSIX lock processing - CIFS unix extensions.
+********************************************************************/
+
+bool posix_default_lock_was_set;
+static enum brl_flavour posix_cifsx_locktype; /* By default 0 == WINDOWS_LOCK */
+
+enum brl_flavour lp_posix_cifsu_locktype(files_struct *fsp)
+{
+ if (posix_default_lock_was_set) {
+ return posix_cifsx_locktype;
+ } else {
+ return fsp->posix_open ? POSIX_LOCK : WINDOWS_LOCK;
+ }
+}
+
+/*******************************************************************
+********************************************************************/
+
+void lp_set_posix_default_cifsx_readwrite_locktype(enum brl_flavour val)
+{
+ posix_default_lock_was_set = True;
+ posix_cifsx_locktype = val;
+}
+
+int lp_min_receive_file_size(void)
+{
+ if (Globals.iminreceivefile < 0) {
+ return 0;
+ }
+ return MIN(Globals.iminreceivefile, BUFFER_SIZE);
+}
diff --git a/source3/param/params.c b/source3/param/params.c
new file mode 100644
index 0000000000..478376c9e9
--- /dev/null
+++ b/source3/param/params.c
@@ -0,0 +1,590 @@
+/* -------------------------------------------------------------------------- **
+ * 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, 1997.
+ * This module Copyright (C) 1997-1998 by Christopher R. Hertel
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * 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"
+
+/* -------------------------------------------------------------------------- **
+ * 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>.
+ */
+
+/* we can't use FILE* due to the 256 fd limit - use this cheap hack
+ instead */
+typedef struct {
+ char *buf;
+ char *p;
+ size_t size;
+ char *end_section_p;
+} myFILE;
+
+static int mygetc(myFILE *f)
+{
+ if (f->p >= f->buf+f->size)
+ return EOF;
+ /* be sure to return chars >127 as positive values */
+ return (int)( *(f->p++) & 0x00FF );
+}
+
+static void myfile_close(myFILE *f)
+{
+ if (!f)
+ return;
+ SAFE_FREE(f->buf);
+ SAFE_FREE(f);
+}
+
+/* Find the end of the section. We must use mb functions for this. */
+static int FindSectionEnd(myFILE *f)
+{
+ f->end_section_p = strchr_m(f->p, ']');
+ return f->end_section_p ? 1 : 0;
+}
+
+static int AtSectionEnd(myFILE *f)
+{
+ if (f->p == f->end_section_p + 1) {
+ f->end_section_p = NULL;
+ return 1;
+ }
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+ /* ------------------------------------------------------------------------ **
+ * 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.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+static int EatWhitespace( myFILE *InFile )
+{
+ int c;
+
+ for( c = mygetc( InFile ); isspace( c ) && ('\n' != c); c = mygetc( InFile ) )
+ ;
+ return( c );
+}
+
+ /* ------------------------------------------------------------------------ **
+ * 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.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+static int EatComment( myFILE *InFile )
+{
+ int c;
+
+ for( c = mygetc( InFile ); ('\n'!=c) && (EOF!=c) && (c>0); c = mygetc( InFile ) )
+ ;
+ return( c );
+}
+
+/*****************************************************************************
+ * Scan backards within a string to discover if the last non-whitespace
+ * character is a line-continuation character ('\\').
+ *
+ * Input: line - A pointer to a buffer containing the string to be
+ * scanned.
+ * pos - This is taken to be the offset of the end of the
+ * string. This position is *not* scanned.
+ *
+ * Output: The offset of the '\\' character if it was found, or -1 to
+ * indicate that it was not.
+ *
+ *****************************************************************************/
+
+static int Continuation(uint8_t *line, int pos )
+{
+ pos--;
+ while( (pos >= 0) && isspace((int)line[pos]))
+ pos--;
+
+ return (((pos >= 0) && ('\\' == line[pos])) ? pos : -1 );
+}
+
+/* ------------------------------------------------------------------------ **
+ * 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.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+static bool Section( DATA_BLOB *buf, myFILE *InFile, bool (*sfunc)(const char *, void *), void *userdata )
+{
+ int c;
+ int i;
+ int end;
+ const 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>. */
+
+
+ /* Find the end of the section. We must use mb functions for this. */
+ if (!FindSectionEnd(InFile)) {
+ DEBUG(0, ("%s No terminating ']' character in section.\n", func) );
+ return False;
+ }
+
+ 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 > (buf->length - 2) ) {
+ uint8_t *tb = (uint8_t *)SMB_REALLOC_KEEP_OLD_ON_ERROR(buf->data, buf->length+BUFR_INC );
+ if(!tb) {
+ DEBUG(0, ("%s Memory re-allocation failure.", func) );
+ return False;
+ }
+ buf->data = tb;
+ buf->length += BUFR_INC;
+ }
+
+ /* Handle a single character other than section end. */
+ switch( c ) {
+ case '\n': /* Got newline before closing ']'. */
+ i = Continuation( buf->data, i ); /* Check for line continuation. */
+ if( i < 0 ) {
+ buf->data[end] = '\0';
+ DEBUG(0, ("%s Badly formed line in configuration file: %s\n", func, buf->data ));
+ return False;
+ }
+ end = ( (i > 0) && (' ' == buf->data[i - 1]) ) ? (i - 1) : (i);
+ c = mygetc( InFile ); /* Continue with next line. */
+ break;
+
+ default: /* All else are a valid name chars. */
+ if(isspace( c )) {
+ /* One space per whitespace region. */
+ buf->data[end] = ' ';
+ i = end + 1;
+ c = EatWhitespace( InFile );
+ } else {
+ buf->data[i++] = c;
+ end = i;
+ c = mygetc( InFile );
+ }
+ }
+
+ if (AtSectionEnd(InFile)) {
+ /* Got to the closing bracket. */
+ buf->data[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((char *)buf->data, userdata) ) /* Got a valid name. Deal with it. */
+ return False;
+ EatComment( InFile ); /* Finish off the line. */
+ return True;
+ }
+
+ }
+
+ /* 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, buf->data ));
+ return False;
+}
+
+/* ------------------------------------------------------------------------ **
+ * 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.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+static bool Parameter( DATA_BLOB *buf, myFILE *InFile, bool (*pfunc)(const char *, const char *, void *), int c, void *userdata )
+{
+ 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. */
+ const char *func = "params.c:Parameter() -";
+
+ /* Read the parameter name. */
+ while( 0 == vstart ) {
+ /* Loop until we've found the start of the value. */
+ if( i > (buf->length - 2) ) {
+ /* Ensure there's space for next char. */
+ uint8_t *tb = (uint8_t *)SMB_REALLOC_KEEP_OLD_ON_ERROR( buf->data, buf->length + BUFR_INC );
+ if (!tb) {
+ DEBUG(0, ("%s Memory re-allocation failure.", func) );
+ return False;
+ }
+ buf->data = tb;
+ buf->length += BUFR_INC;
+ }
+
+ switch(c) {
+ case '=': /* Equal sign marks end of param name. */
+ if( 0 == end ) {
+ /* Don't allow an empty name. */
+ DEBUG(0, ("%s Invalid parameter name in config. file.\n", func ));
+ return False;
+ }
+ buf->data[end++] = '\0'; /* Mark end of string & advance. */
+ i = end; /* New string starts here. */
+ vstart = end; /* New string is parameter value. */
+ buf->data[i] = '\0'; /* New string is nul, for now. */
+ break;
+
+ case '\n': /* Find continuation char, else error. */
+ i = Continuation( buf->data, i );
+ if( i < 0 ) {
+ buf->data[end] = '\0';
+ DEBUG(1,("%s Ignoring badly formed line in configuration file: %s\n", func, buf->data ));
+ return True;
+ }
+ end = ( (i > 0) && (' ' == buf->data[i - 1]) ) ? (i - 1) : (i);
+ c = mygetc( InFile ); /* Read past eoln. */
+ break;
+
+ case '\0': /* Shouldn't have EOF within param name. */
+ case EOF:
+ buf->data[i] = '\0';
+ DEBUG(1,("%s Unexpected end-of-file at: %s\n", func, buf->data ));
+ return True;
+
+ default:
+ if(isspace( c )) {
+ /* One ' ' per whitespace region. */
+ buf->data[end] = ' ';
+ i = end + 1;
+ c = EatWhitespace( InFile );
+ } else {
+ buf->data[i++] = c;
+ end = i;
+ c = mygetc( InFile );
+ }
+ }
+ }
+
+ /* Now parse the value. */
+ c = EatWhitespace( InFile ); /* Again, trim leading whitespace. */
+ while( (EOF !=c) && (c > 0) ) {
+ if( i > (buf->length - 2) ) {
+ /* Make sure there's enough room. */
+ uint8_t *tb = (uint8_t *)SMB_REALLOC_KEEP_OLD_ON_ERROR( buf->data, buf->length + BUFR_INC );
+ if (!tb) {
+ DEBUG(0, ("%s Memory re-allocation failure.", func));
+ return False;
+ }
+ buf->data = tb;
+ buf->length += BUFR_INC;
+ }
+
+ switch(c) {
+ case '\r': /* Explicitly remove '\r' because the older */
+ c = mygetc( InFile ); /* version called fgets_slash() which also */
+ break; /* removes them. */
+
+ case '\n': /* Marks end of value unless there's a '\'. */
+ i = Continuation( buf->data, i );
+ if( i < 0 ) {
+ c = 0;
+ } else {
+ for( end = i; (end >= 0) && isspace((int)buf->data[end]); end-- )
+ ;
+ c = mygetc( InFile );
+ }
+ break;
+
+ default: /* All others verbatim. Note that spaces do not advance <end>. This allows trimming */
+ buf->data[i++] = c;
+ if( !isspace( c ) ) /* of whitespace at the end of the line. */
+ end = i;
+ c = mygetc( InFile );
+ break;
+ }
+ }
+ buf->data[end] = '\0'; /* End of value. */
+
+ return( pfunc( (char *)buf->data, (char *)&buf->data[vstart], userdata ) ); /* Pass name & value to pfunc(). */
+}
+
+/* ------------------------------------------------------------------------ **
+ * 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.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+static bool Parse( DATA_BLOB *buf, myFILE *InFile,
+ bool (*sfunc)(const char *, void *),
+ bool (*pfunc)(const char *, const char *, void *),
+ void *userdata)
+{
+ 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( buf, InFile, sfunc, userdata ) )
+ return False;
+ c = EatWhitespace( InFile );
+ break;
+
+ case '\\': /* Bogus backslash. */
+ c = EatWhitespace( InFile );
+ break;
+
+ default: /* Parameter line. */
+ if( !Parameter( buf, InFile, pfunc, c, userdata ) )
+ return False;
+ c = EatWhitespace( InFile );
+ break;
+ }
+ }
+ return True;
+}
+
+/* ------------------------------------------------------------------------ **
+ * Open a configuration file.
+ *
+ * Input: FileName - The pathname of the config file to be opened.
+ *
+ * Output: A pointer of type (char **) to the lines of the file
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+static myFILE *OpenConfFile( const char *FileName )
+{
+ const char *func = "params.c:OpenConfFile() -";
+ int lvl = lp_is_in_client() ? 1 : 0;
+ myFILE *ret;
+
+ ret = SMB_MALLOC_P(myFILE);
+ if (!ret)
+ return NULL;
+
+ ret->buf = file_load(FileName, &ret->size, 0);
+ if( NULL == ret->buf ) {
+ DEBUG( lvl, ("%s Unable to open configuration file \"%s\":\n\t%s\n",
+ func, FileName, strerror(errno)) );
+ SAFE_FREE(ret);
+ return NULL;
+ }
+
+ ret->p = ret->buf;
+ ret->end_section_p = NULL;
+ return( ret );
+}
+
+/* ------------------------------------------------------------------------ **
+ * 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.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+bool pm_process( const char *FileName,
+ bool (*sfunc)(const char *, void *),
+ bool (*pfunc)(const char *, const char *, void *),
+ void *userdata)
+{
+ int result;
+ myFILE *InFile;
+ const char *func = "params.c:pm_process() -";
+ DATA_BLOB buf;
+
+ InFile = OpenConfFile( FileName ); /* Open the config file. */
+ if( NULL == InFile )
+ return False;
+
+ DEBUG( 3, ("%s Processing configuration file \"%s\"\n", func, FileName) );
+
+ buf = data_blob(NULL, 256);
+
+ if (buf.data == NULL) {
+ DEBUG(0,("%s memory allocation failure.\n", func));
+ myfile_close(InFile);
+ return False;
+ }
+
+ result = Parse( &buf, InFile, sfunc, pfunc, userdata );
+ data_blob_free(&buf);
+
+ myfile_close(InFile);
+
+ if( !result ) {
+ DEBUG(0,("%s Failed. Error returned from params.c:parse().\n", func));
+ return False;
+ }
+
+ return True;
+}
diff --git a/source3/param/util.c b/source3/param/util.c
new file mode 100644
index 0000000000..f953484256
--- /dev/null
+++ b/source3/param/util.c
@@ -0,0 +1,50 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * param helper routines
+ * Copyright (C) Gerald Carter 2003
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/*********************************************************
+ utility function to parse an integer parameter from
+ "parameter = value"
+**********************************************************/
+uint32 get_int_param( const char* param )
+{
+ char *p;
+
+ p = strchr( param, '=' );
+ if ( !p )
+ return 0;
+
+ return atoi(p+1);
+}
+
+/*********************************************************
+ utility function to parse an integer parameter from
+ "parameter = value"
+**********************************************************/
+char* get_string_param( const char* param )
+{
+ char *p;
+
+ p = strchr( param, '=' );
+ if ( !p )
+ return NULL;
+
+ return (p+1);
+}
diff --git a/source3/passdb/login_cache.c b/source3/passdb/login_cache.c
new file mode 100644
index 0000000000..8222f77b95
--- /dev/null
+++ b/source3/passdb/login_cache.c
@@ -0,0 +1,188 @@
+/*
+ Unix SMB/CIFS implementation.
+ struct samu local cache for
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2004.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+#define LOGIN_CACHE_FILE "login_cache.tdb"
+
+#define SAM_CACHE_FORMAT "dwwd"
+
+static TDB_CONTEXT *cache;
+
+bool login_cache_init(void)
+{
+ char* cache_fname = NULL;
+
+ /* skip file open if it's already opened */
+ if (cache) return True;
+
+ asprintf(&cache_fname, "%s/%s", lp_lockdir(), LOGIN_CACHE_FILE);
+ if (cache_fname)
+ DEBUG(5, ("Opening cache file at %s\n", cache_fname));
+ else {
+ DEBUG(0, ("Filename allocation failed.\n"));
+ return False;
+ }
+
+ cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT,
+ O_RDWR|O_CREAT, 0644);
+
+ if (!cache)
+ DEBUG(5, ("Attempt to open %s failed.\n", cache_fname));
+
+ SAFE_FREE(cache_fname);
+
+ return (cache ? True : False);
+}
+
+bool login_cache_shutdown(void)
+{
+ /* tdb_close routine returns -1 on error */
+ if (!cache) return False;
+ DEBUG(5, ("Closing cache file\n"));
+ return tdb_close(cache) != -1;
+}
+
+/* if we can't read the cache, oh well, no need to return anything */
+LOGIN_CACHE * login_cache_read(struct samu *sampass)
+{
+ char *keystr;
+ TDB_DATA databuf;
+ LOGIN_CACHE *entry;
+
+ if (!login_cache_init())
+ return NULL;
+
+ if (pdb_get_nt_username(sampass) == NULL) {
+ return NULL;
+ }
+
+ keystr = SMB_STRDUP(pdb_get_nt_username(sampass));
+ if (!keystr || !keystr[0]) {
+ SAFE_FREE(keystr);
+ return NULL;
+ }
+
+ DEBUG(7, ("Looking up login cache for user %s\n",
+ keystr));
+ databuf = tdb_fetch_bystring(cache, keystr);
+ SAFE_FREE(keystr);
+
+ if (!(entry = SMB_MALLOC_P(LOGIN_CACHE))) {
+ DEBUG(1, ("Unable to allocate cache entry buffer!\n"));
+ SAFE_FREE(databuf.dptr);
+ return NULL;
+ }
+
+ if (tdb_unpack (databuf.dptr, databuf.dsize, SAM_CACHE_FORMAT,
+ &entry->entry_timestamp, &entry->acct_ctrl,
+ &entry->bad_password_count,
+ &entry->bad_password_time) == -1) {
+ DEBUG(7, ("No cache entry found\n"));
+ SAFE_FREE(entry);
+ SAFE_FREE(databuf.dptr);
+ return NULL;
+ }
+
+ SAFE_FREE(databuf.dptr);
+
+ DEBUG(5, ("Found login cache entry: timestamp %12u, flags 0x%x, count %d, time %12u\n",
+ (unsigned int)entry->entry_timestamp, entry->acct_ctrl,
+ entry->bad_password_count, (unsigned int)entry->bad_password_time));
+ return entry;
+}
+
+bool login_cache_write(const struct samu *sampass, LOGIN_CACHE entry)
+{
+ char *keystr;
+ TDB_DATA databuf;
+ bool ret;
+
+ if (!login_cache_init())
+ return False;
+
+ if (pdb_get_nt_username(sampass) == NULL) {
+ return False;
+ }
+
+ keystr = SMB_STRDUP(pdb_get_nt_username(sampass));
+ if (!keystr || !keystr[0]) {
+ SAFE_FREE(keystr);
+ return False;
+ }
+
+ entry.entry_timestamp = time(NULL);
+
+ databuf.dsize =
+ tdb_pack(NULL, 0, SAM_CACHE_FORMAT,
+ entry.entry_timestamp,
+ entry.acct_ctrl,
+ entry.bad_password_count,
+ entry.bad_password_time);
+ databuf.dptr = SMB_MALLOC_ARRAY(uint8, databuf.dsize);
+ if (!databuf.dptr) {
+ SAFE_FREE(keystr);
+ return False;
+ }
+
+ if (tdb_pack(databuf.dptr, databuf.dsize, SAM_CACHE_FORMAT,
+ entry.entry_timestamp,
+ entry.acct_ctrl,
+ entry.bad_password_count,
+ entry.bad_password_time)
+ != databuf.dsize) {
+ SAFE_FREE(keystr);
+ SAFE_FREE(databuf.dptr);
+ return False;
+ }
+
+ ret = tdb_store_bystring(cache, keystr, databuf, 0);
+ SAFE_FREE(keystr);
+ SAFE_FREE(databuf.dptr);
+ return ret == 0;
+}
+
+bool login_cache_delentry(const struct samu *sampass)
+{
+ int ret;
+ char *keystr;
+
+ if (!login_cache_init())
+ return False;
+
+ if (pdb_get_nt_username(sampass) == NULL) {
+ return False;
+ }
+
+ keystr = SMB_STRDUP(pdb_get_nt_username(sampass));
+ if (!keystr || !keystr[0]) {
+ SAFE_FREE(keystr);
+ return False;
+ }
+
+ DEBUG(9, ("About to delete entry for %s\n", keystr));
+ ret = tdb_delete_bystring(cache, keystr);
+ DEBUG(9, ("tdb_delete returned %d\n", ret));
+
+ SAFE_FREE(keystr);
+ return ret == 0;
+}
diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c
new file mode 100644
index 0000000000..3861c8e229
--- /dev/null
+++ b/source3/passdb/lookup_sid.c
@@ -0,0 +1,1501 @@
+/*
+ Unix SMB/CIFS implementation.
+ uid/user handling
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Gerald (Jerry) Carter 2003
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*****************************************************************
+ Dissect a user-provided name into domain, name, sid and type.
+
+ If an explicit domain name was given in the form domain\user, it
+ has to try that. If no explicit domain name was given, we have
+ to do guesswork.
+*****************************************************************/
+
+bool lookup_name(TALLOC_CTX *mem_ctx,
+ const char *full_name, int flags,
+ const char **ret_domain, const char **ret_name,
+ DOM_SID *ret_sid, enum lsa_SidType *ret_type)
+{
+ char *p;
+ const char *tmp;
+ const char *domain = NULL;
+ const char *name = NULL;
+ uint32 rid;
+ DOM_SID sid;
+ enum lsa_SidType type;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+
+ if (tmp_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return false;
+ }
+
+ p = strchr_m(full_name, '\\');
+
+ if (p != NULL) {
+ domain = talloc_strndup(tmp_ctx, full_name,
+ PTR_DIFF(p, full_name));
+ name = talloc_strdup(tmp_ctx, p+1);
+ } else {
+ domain = talloc_strdup(tmp_ctx, "");
+ name = talloc_strdup(tmp_ctx, full_name);
+ }
+
+ if ((domain == NULL) || (name == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ DEBUG(10,("lookup_name: %s => %s (domain), %s (name)\n",
+ full_name, domain, name));
+ DEBUG(10, ("lookup_name: flags = 0x0%x\n", flags));
+
+ if ((flags & LOOKUP_NAME_DOMAIN) &&
+ strequal(domain, get_global_sam_name()))
+ {
+
+ /* It's our own domain, lookup the name in passdb */
+ if (lookup_global_sam_name(name, flags, &rid, &type)) {
+ sid_copy(&sid, get_global_sam_sid());
+ sid_append_rid(&sid, rid);
+ goto ok;
+ }
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ if ((flags & LOOKUP_NAME_BUILTIN) &&
+ strequal(domain, builtin_domain_name()))
+ {
+ /* Explicit request for a name in BUILTIN */
+ if (lookup_builtin_name(name, &rid)) {
+ sid_copy(&sid, &global_sid_Builtin);
+ sid_append_rid(&sid, rid);
+ type = SID_NAME_ALIAS;
+ goto ok;
+ }
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ /* Try the explicit winbind lookup first, don't let it guess the
+ * domain yet at this point yet. This comes later. */
+
+ if ((domain[0] != '\0') &&
+ (flags & ~(LOOKUP_NAME_DOMAIN|LOOKUP_NAME_ISOLATED)) &&
+ (winbind_lookup_name(domain, name, &sid, &type))) {
+ goto ok;
+ }
+
+ if (!(flags & LOOKUP_NAME_EXPLICIT) && strequal(domain, unix_users_domain_name())) {
+ if (lookup_unix_user_name(name, &sid)) {
+ type = SID_NAME_USER;
+ goto ok;
+ }
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ if (!(flags & LOOKUP_NAME_EXPLICIT) && strequal(domain, unix_groups_domain_name())) {
+ if (lookup_unix_group_name(name, &sid)) {
+ type = SID_NAME_DOM_GRP;
+ goto ok;
+ }
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ if ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) {
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ /* Now the guesswork begins, we haven't been given an explicit
+ * domain. Try the sequence as documented on
+ * http://msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp
+ * November 27, 2005 */
+
+ /* 1. well-known names */
+
+ if ((flags & LOOKUP_NAME_WKN) &&
+ lookup_wellknown_name(tmp_ctx, name, &sid, &domain))
+ {
+ type = SID_NAME_WKN_GRP;
+ goto ok;
+ }
+
+ /* 2. Builtin domain as such */
+
+ if ((flags & (LOOKUP_NAME_BUILTIN|LOOKUP_NAME_REMOTE)) &&
+ strequal(name, builtin_domain_name()))
+ {
+ /* Swap domain and name */
+ tmp = name; name = domain; domain = tmp;
+ sid_copy(&sid, &global_sid_Builtin);
+ type = SID_NAME_DOMAIN;
+ goto ok;
+ }
+
+ /* 3. Account domain */
+
+ if ((flags & LOOKUP_NAME_DOMAIN) &&
+ strequal(name, get_global_sam_name()))
+ {
+ if (!secrets_fetch_domain_sid(name, &sid)) {
+ DEBUG(3, ("Could not fetch my SID\n"));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+ /* Swap domain and name */
+ tmp = name; name = domain; domain = tmp;
+ type = SID_NAME_DOMAIN;
+ goto ok;
+ }
+
+ /* 4. Primary domain */
+
+ if ((flags & LOOKUP_NAME_DOMAIN) && !IS_DC &&
+ strequal(name, lp_workgroup()))
+ {
+ if (!secrets_fetch_domain_sid(name, &sid)) {
+ DEBUG(3, ("Could not fetch the domain SID\n"));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+ /* Swap domain and name */
+ tmp = name; name = domain; domain = tmp;
+ type = SID_NAME_DOMAIN;
+ goto ok;
+ }
+
+ /* 5. Trusted domains as such, to me it looks as if members don't do
+ this, tested an XP workstation in a NT domain -- vl */
+
+ if ((flags & LOOKUP_NAME_REMOTE) && IS_DC &&
+ (pdb_get_trusteddom_pw(name, NULL, &sid, NULL)))
+ {
+ /* Swap domain and name */
+ tmp = name; name = domain; domain = tmp;
+ type = SID_NAME_DOMAIN;
+ goto ok;
+ }
+
+ /* 6. Builtin aliases */
+
+ if ((flags & LOOKUP_NAME_BUILTIN) &&
+ lookup_builtin_name(name, &rid))
+ {
+ domain = talloc_strdup(tmp_ctx, builtin_domain_name());
+ sid_copy(&sid, &global_sid_Builtin);
+ sid_append_rid(&sid, rid);
+ type = SID_NAME_ALIAS;
+ goto ok;
+ }
+
+ /* 7. Local systems' SAM (DCs don't have a local SAM) */
+ /* 8. Primary SAM (On members, this is the domain) */
+
+ /* Both cases are done by looking at our passdb */
+
+ if ((flags & LOOKUP_NAME_DOMAIN) &&
+ lookup_global_sam_name(name, flags, &rid, &type))
+ {
+ domain = talloc_strdup(tmp_ctx, get_global_sam_name());
+ sid_copy(&sid, get_global_sam_sid());
+ sid_append_rid(&sid, rid);
+ goto ok;
+ }
+
+ /* Now our local possibilities are exhausted. */
+
+ if (!(flags & LOOKUP_NAME_REMOTE)) {
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ /* If we are not a DC, we have to ask in our primary domain. Let
+ * winbind do that. */
+
+ if (!IS_DC &&
+ (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
+ domain = talloc_strdup(tmp_ctx, lp_workgroup());
+ goto ok;
+ }
+
+ /* 9. Trusted domains */
+
+ /* If we're a DC we have to ask all trusted DC's. Winbind does not do
+ * that (yet), but give it a chance. */
+
+ if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
+ DOM_SID dom_sid;
+ uint32 tmp_rid;
+ enum lsa_SidType domain_type;
+
+ if (type == SID_NAME_DOMAIN) {
+ /* Swap name and type */
+ tmp = name; name = domain; domain = tmp;
+ goto ok;
+ }
+
+ /* Here we have to cope with a little deficiency in the
+ * winbind API: We have to ask it again for the name of the
+ * domain it figured out itself. Maybe fix that later... */
+
+ sid_copy(&dom_sid, &sid);
+ sid_split_rid(&dom_sid, &tmp_rid);
+
+ if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
+ &domain_type) ||
+ (domain_type != SID_NAME_DOMAIN)) {
+ DEBUG(2, ("winbind could not find the domain's name "
+ "it just looked up for us\n"));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+ goto ok;
+ }
+
+ /* 10. Don't translate */
+
+ /* 11. Ok, windows would end here. Samba has two more options:
+ Unmapped users and unmapped groups */
+
+ if (!(flags & LOOKUP_NAME_EXPLICIT) && lookup_unix_user_name(name, &sid)) {
+ domain = talloc_strdup(tmp_ctx, unix_users_domain_name());
+ type = SID_NAME_USER;
+ goto ok;
+ }
+
+ if (!(flags & LOOKUP_NAME_EXPLICIT) && lookup_unix_group_name(name, &sid)) {
+ domain = talloc_strdup(tmp_ctx, unix_groups_domain_name());
+ type = SID_NAME_DOM_GRP;
+ goto ok;
+ }
+
+ /*
+ * Ok, all possibilities tried. Fail.
+ */
+
+ TALLOC_FREE(tmp_ctx);
+ return false;
+
+ ok:
+ if ((domain == NULL) || (name == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ /*
+ * Hand over the results to the talloc context we've been given.
+ */
+
+ if ((ret_name != NULL) &&
+ !(*ret_name = talloc_strdup(mem_ctx, name))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ if (ret_domain != NULL) {
+ char *tmp_dom;
+ if (!(tmp_dom = talloc_strdup(mem_ctx, domain))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+ strupper_m(tmp_dom);
+ *ret_domain = tmp_dom;
+ }
+
+ if (ret_sid != NULL) {
+ sid_copy(ret_sid, &sid);
+ }
+
+ if (ret_type != NULL) {
+ *ret_type = type;
+ }
+
+ TALLOC_FREE(tmp_ctx);
+ return true;
+}
+
+/************************************************************************
+ Names from smb.conf can be unqualified. eg. valid users = foo
+ These names should never map to a remote name. Try global_sam_name()\foo,
+ and then "Unix Users"\foo (or "Unix Groups"\foo).
+************************************************************************/
+
+bool lookup_name_smbconf(TALLOC_CTX *mem_ctx,
+ const char *full_name, int flags,
+ const char **ret_domain, const char **ret_name,
+ DOM_SID *ret_sid, enum lsa_SidType *ret_type)
+{
+ char *qualified_name;
+ const char *p;
+
+ /* NB. No winbindd_separator here as lookup_name needs \\' */
+ if ((p = strchr_m(full_name, *lp_winbind_separator())) != NULL) {
+
+ /* The name is already qualified with a domain. */
+
+ if (*lp_winbind_separator() != '\\') {
+ char *tmp;
+
+ /* lookup_name() needs '\\' as a separator */
+
+ tmp = talloc_strdup(mem_ctx, full_name);
+ if (!tmp) {
+ return false;
+ }
+ tmp[p - full_name] = '\\';
+ full_name = tmp;
+ }
+
+ return lookup_name(mem_ctx, full_name, flags,
+ ret_domain, ret_name,
+ ret_sid, ret_type);
+ }
+
+ /* Try with our own SAM name. */
+ qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
+ get_global_sam_name(),
+ full_name );
+ if (!qualified_name) {
+ return false;
+ }
+
+ if (lookup_name(mem_ctx, qualified_name, flags,
+ ret_domain, ret_name,
+ ret_sid, ret_type)) {
+ return true;
+ }
+
+ /* Finally try with "Unix Users" or "Unix Group" */
+ qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
+ flags & LOOKUP_NAME_GROUP ?
+ unix_groups_domain_name() :
+ unix_users_domain_name(),
+ full_name );
+ if (!qualified_name) {
+ return false;
+ }
+
+ return lookup_name(mem_ctx, qualified_name, flags,
+ ret_domain, ret_name,
+ ret_sid, ret_type);
+}
+
+static bool wb_lookup_rids(TALLOC_CTX *mem_ctx,
+ const DOM_SID *domain_sid,
+ int num_rids, uint32 *rids,
+ const char **domain_name,
+ const char **names, enum lsa_SidType *types)
+{
+ int i;
+ const char **my_names;
+ enum lsa_SidType *my_types;
+ TALLOC_CTX *tmp_ctx;
+
+ if (!(tmp_ctx = talloc_init("wb_lookup_rids"))) {
+ return false;
+ }
+
+ if (!winbind_lookup_rids(tmp_ctx, domain_sid, num_rids, rids,
+ domain_name, &my_names, &my_types)) {
+ *domain_name = "";
+ for (i=0; i<num_rids; i++) {
+ names[i] = "";
+ types[i] = SID_NAME_UNKNOWN;
+ }
+ TALLOC_FREE(tmp_ctx);
+ return true;
+ }
+
+ if (!(*domain_name = talloc_strdup(mem_ctx, *domain_name))) {
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ /*
+ * winbind_lookup_rids allocates its own array. We've been given the
+ * array, so copy it over
+ */
+
+ for (i=0; i<num_rids; i++) {
+ if (my_names[i] == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+ if (!(names[i] = talloc_strdup(names, my_names[i]))) {
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+ types[i] = my_types[i];
+ }
+ TALLOC_FREE(tmp_ctx);
+ return true;
+}
+
+static bool lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
+ int num_rids, uint32_t *rids,
+ const char **domain_name,
+ const char ***names, enum lsa_SidType **types)
+{
+ int i;
+
+ DEBUG(10, ("lookup_rids called for domain sid '%s'\n",
+ sid_string_dbg(domain_sid)));
+
+ if (num_rids) {
+ *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
+ *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
+
+ if ((*names == NULL) || (*types == NULL)) {
+ return false;
+ }
+ } else {
+ *names = NULL;
+ *types = NULL;
+ }
+
+ if (sid_check_is_domain(domain_sid)) {
+ NTSTATUS result;
+
+ if (*domain_name == NULL) {
+ *domain_name = talloc_strdup(
+ mem_ctx, get_global_sam_name());
+ }
+
+ if (*domain_name == NULL) {
+ return false;
+ }
+
+ become_root();
+ result = pdb_lookup_rids(domain_sid, num_rids, rids,
+ *names, *types);
+ unbecome_root();
+
+ return (NT_STATUS_IS_OK(result) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
+ NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
+ }
+
+ if (sid_check_is_builtin(domain_sid)) {
+
+ if (*domain_name == NULL) {
+ *domain_name = talloc_strdup(
+ mem_ctx, builtin_domain_name());
+ }
+
+ if (*domain_name == NULL) {
+ return false;
+ }
+
+ for (i=0; i<num_rids; i++) {
+ if (lookup_builtin_rid(*names, rids[i],
+ &(*names)[i])) {
+ if ((*names)[i] == NULL) {
+ return false;
+ }
+ (*types)[i] = SID_NAME_ALIAS;
+ } else {
+ (*types)[i] = SID_NAME_UNKNOWN;
+ }
+ }
+ return true;
+ }
+
+ if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
+ for (i=0; i<num_rids; i++) {
+ DOM_SID sid;
+ sid_copy(&sid, domain_sid);
+ sid_append_rid(&sid, rids[i]);
+ if (lookup_wellknown_sid(mem_ctx, &sid,
+ domain_name, &(*names)[i])) {
+ if ((*names)[i] == NULL) {
+ return false;
+ }
+ (*types)[i] = SID_NAME_WKN_GRP;
+ } else {
+ (*types)[i] = SID_NAME_UNKNOWN;
+ }
+ }
+ return true;
+ }
+
+ if (sid_check_is_unix_users(domain_sid)) {
+ if (*domain_name == NULL) {
+ *domain_name = talloc_strdup(
+ mem_ctx, unix_users_domain_name());
+ if (*domain_name == NULL) {
+ return false;
+ }
+ }
+ for (i=0; i<num_rids; i++) {
+ (*names)[i] = talloc_strdup(
+ (*names), uidtoname(rids[i]));
+ if ((*names)[i] == NULL) {
+ return false;
+ }
+ (*types)[i] = SID_NAME_USER;
+ }
+ return true;
+ }
+
+ if (sid_check_is_unix_groups(domain_sid)) {
+ if (*domain_name == NULL) {
+ *domain_name = talloc_strdup(
+ mem_ctx, unix_groups_domain_name());
+ if (*domain_name == NULL) {
+ return false;
+ }
+ }
+ for (i=0; i<num_rids; i++) {
+ (*names)[i] = talloc_strdup(
+ (*names), gidtoname(rids[i]));
+ if ((*names)[i] == NULL) {
+ return false;
+ }
+ (*types)[i] = SID_NAME_DOM_GRP;
+ }
+ return true;
+ }
+
+ return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
+ domain_name, *names, *types);
+}
+
+/*
+ * Is the SID a domain as such? If yes, lookup its name.
+ */
+
+static bool lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
+ const char **name)
+{
+ const char *tmp;
+ enum lsa_SidType type;
+
+ if (sid_check_is_domain(sid)) {
+ *name = talloc_strdup(mem_ctx, get_global_sam_name());
+ return true;
+ }
+
+ if (sid_check_is_builtin(sid)) {
+ *name = talloc_strdup(mem_ctx, builtin_domain_name());
+ return true;
+ }
+
+ if (sid_check_is_wellknown_domain(sid, &tmp)) {
+ *name = talloc_strdup(mem_ctx, tmp);
+ return true;
+ }
+
+ if (sid_check_is_unix_users(sid)) {
+ *name = talloc_strdup(mem_ctx, unix_users_domain_name());
+ return true;
+ }
+
+ if (sid_check_is_unix_groups(sid)) {
+ *name = talloc_strdup(mem_ctx, unix_groups_domain_name());
+ return true;
+ }
+
+ if (sid->num_auths != 4) {
+ /* This can't be a domain */
+ return false;
+ }
+
+ if (IS_DC) {
+ uint32 i, num_domains;
+ struct trustdom_info **domains;
+
+ /* This is relatively expensive, but it happens only on DCs
+ * and for SIDs that have 4 sub-authorities and thus look like
+ * domains */
+
+ if (!NT_STATUS_IS_OK(pdb_enum_trusteddoms(mem_ctx,
+ &num_domains,
+ &domains))) {
+ return false;
+ }
+
+ for (i=0; i<num_domains; i++) {
+ if (sid_equal(sid, &domains[i]->sid)) {
+ *name = talloc_strdup(mem_ctx,
+ domains[i]->name);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
+ (type == SID_NAME_DOMAIN)) {
+ *name = tmp;
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * This tries to implement the rather weird rules for the lsa_lookup level
+ * parameter.
+ *
+ * This is as close as we can get to what W2k3 does. With this we survive the
+ * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
+ * different, but I assume that's just being too liberal. For example, W2k3
+ * replies to everything else but the levels 1-6 with INVALID_PARAMETER
+ * whereas NT4 does the same as level 1 (I think). I did not fully test that
+ * with NT4, this is what w2k3 does.
+ *
+ * Level 1: Ask everywhere
+ * Level 2: Ask domain and trusted domains, no builtin and wkn
+ * Level 3: Only ask domain
+ * Level 4: W2k3ad: Only ask AD trusts
+ * Level 5: Only ask transitive forest trusts
+ * Level 6: Like 4
+ */
+
+static bool check_dom_sid_to_level(const DOM_SID *sid, int level)
+{
+ int ret = false;
+
+ switch(level) {
+ case 1:
+ ret = true;
+ break;
+ case 2:
+ ret = (!sid_check_is_builtin(sid) &&
+ !sid_check_is_wellknown_domain(sid, NULL));
+ break;
+ case 3:
+ case 4:
+ case 6:
+ ret = sid_check_is_domain(sid);
+ break;
+ case 5:
+ ret = false;
+ break;
+ }
+
+ DEBUG(10, ("%s SID %s in level %d\n",
+ ret ? "Accepting" : "Rejecting",
+ sid_string_dbg(sid), level));
+ return ret;
+}
+
+/*
+ * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
+ * references to domains, it is explicitly made for this.
+ *
+ * This attempts to be as efficient as possible: It collects all SIDs
+ * belonging to a domain and hands them in bulk to the appropriate lookup
+ * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
+ * *hugely* from this. Winbind is going to be extended with a lookup_rids
+ * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
+ * appropriate DC.
+ */
+
+NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
+ const DOM_SID **sids, int level,
+ struct lsa_dom_info **ret_domains,
+ struct lsa_name_info **ret_names)
+{
+ TALLOC_CTX *tmp_ctx;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct lsa_name_info *name_infos;
+ struct lsa_dom_info *dom_infos = NULL;
+
+ int i, j;
+
+ if (!(tmp_ctx = talloc_new(mem_ctx))) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (num_sids) {
+ name_infos = TALLOC_ARRAY(mem_ctx, struct lsa_name_info, num_sids);
+ if (name_infos == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ } else {
+ name_infos = NULL;
+ }
+
+ dom_infos = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_dom_info,
+ MAX_REF_DOMAINS);
+ if (dom_infos == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ /* First build up the data structures:
+ *
+ * dom_infos is a list of domains referenced in the list of
+ * SIDs. Later we will walk the list of domains and look up the RIDs
+ * in bulk.
+ *
+ * name_infos is a shadow-copy of the SIDs array to collect the real
+ * data.
+ *
+ * dom_info->idxs is an index into the name_infos array. The
+ * difficulty we have here is that we need to keep the SIDs the client
+ * asked for in the same order for the reply
+ */
+
+ for (i=0; i<num_sids; i++) {
+ DOM_SID sid;
+ uint32 rid;
+ const char *domain_name = NULL;
+
+ sid_copy(&sid, sids[i]);
+ name_infos[i].type = SID_NAME_USE_NONE;
+
+ if (lookup_as_domain(&sid, name_infos, &domain_name)) {
+ /* We can't push that through the normal lookup
+ * process, as this would reference illegal
+ * domains.
+ *
+ * For example S-1-5-32 would end up referencing
+ * domain S-1-5- with RID 32 which is clearly wrong.
+ */
+ if (domain_name == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ name_infos[i].rid = 0;
+ name_infos[i].type = SID_NAME_DOMAIN;
+ name_infos[i].name = NULL;
+
+ if (sid_check_is_builtin(&sid)) {
+ /* Yes, W2k3 returns "BUILTIN" both as domain
+ * and name here */
+ name_infos[i].name = talloc_strdup(
+ name_infos, builtin_domain_name());
+ if (name_infos[i].name == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ }
+ } else {
+ /* This is a normal SID with rid component */
+ if (!sid_split_rid(&sid, &rid)) {
+ result = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ }
+
+ if (!check_dom_sid_to_level(&sid, level)) {
+ name_infos[i].rid = 0;
+ name_infos[i].type = SID_NAME_UNKNOWN;
+ name_infos[i].name = NULL;
+ continue;
+ }
+
+ for (j=0; j<MAX_REF_DOMAINS; j++) {
+ if (!dom_infos[j].valid) {
+ break;
+ }
+ if (sid_equal(&sid, &dom_infos[j].sid)) {
+ break;
+ }
+ }
+
+ if (j == MAX_REF_DOMAINS) {
+ /* TODO: What's the right error message here? */
+ result = NT_STATUS_NONE_MAPPED;
+ goto fail;
+ }
+
+ if (!dom_infos[j].valid) {
+ /* We found a domain not yet referenced, create a new
+ * ref. */
+ dom_infos[j].valid = true;
+ sid_copy(&dom_infos[j].sid, &sid);
+
+ if (domain_name != NULL) {
+ /* This name was being found above in the case
+ * when we found a domain SID */
+ dom_infos[j].name =
+ talloc_strdup(dom_infos, domain_name);
+ if (dom_infos[j].name == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ } else {
+ /* lookup_rids will take care of this */
+ dom_infos[j].name = NULL;
+ }
+ }
+
+ name_infos[i].dom_idx = j;
+
+ if (name_infos[i].type == SID_NAME_USE_NONE) {
+ name_infos[i].rid = rid;
+
+ ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
+ &dom_infos[j].num_idxs);
+
+ if (dom_infos[j].idxs == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ }
+ }
+
+ /* Iterate over the domains found */
+
+ for (i=0; i<MAX_REF_DOMAINS; i++) {
+ uint32_t *rids;
+ const char *domain_name = NULL;
+ const char **names;
+ enum lsa_SidType *types;
+ struct lsa_dom_info *dom = &dom_infos[i];
+
+ if (!dom->valid) {
+ /* No domains left, we're done */
+ break;
+ }
+
+ if (dom->num_idxs) {
+ if (!(rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs))) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ } else {
+ rids = NULL;
+ }
+
+ for (j=0; j<dom->num_idxs; j++) {
+ rids[j] = name_infos[dom->idxs[j]].rid;
+ }
+
+ if (!lookup_rids(tmp_ctx, &dom->sid,
+ dom->num_idxs, rids, &domain_name,
+ &names, &types)) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ for (j=0; j<dom->num_idxs; j++) {
+ int idx = dom->idxs[j];
+ name_infos[idx].type = types[j];
+ if (types[j] != SID_NAME_UNKNOWN) {
+ name_infos[idx].name =
+ talloc_strdup(name_infos, names[j]);
+ if (name_infos[idx].name == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ } else {
+ name_infos[idx].name = NULL;
+ }
+ }
+ }
+
+ *ret_domains = dom_infos;
+ *ret_names = name_infos;
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_OK;
+
+ fail:
+ TALLOC_FREE(dom_infos);
+ TALLOC_FREE(name_infos);
+ TALLOC_FREE(tmp_ctx);
+ return result;
+}
+
+/*****************************************************************
+ *THE CANONICAL* convert SID to name function.
+*****************************************************************/
+
+bool lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ const char **ret_domain, const char **ret_name,
+ enum lsa_SidType *ret_type)
+{
+ struct lsa_dom_info *domain;
+ struct lsa_name_info *name;
+ TALLOC_CTX *tmp_ctx;
+ bool ret = false;
+
+ DEBUG(10, ("lookup_sid called for SID '%s'\n", sid_string_dbg(sid)));
+
+ if (!(tmp_ctx = talloc_new(mem_ctx))) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return false;
+ }
+
+ if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
+ &domain, &name))) {
+ goto done;
+ }
+
+ if (name->type == SID_NAME_UNKNOWN) {
+ goto done;
+ }
+
+ if ((ret_domain != NULL) &&
+ !(*ret_domain = talloc_strdup(mem_ctx, domain->name))) {
+ goto done;
+ }
+
+ if ((ret_name != NULL) &&
+ !(*ret_name = talloc_strdup(mem_ctx, name->name))) {
+ goto done;
+ }
+
+ if (ret_type != NULL) {
+ *ret_type = name->type;
+ }
+
+ ret = true;
+
+ done:
+ if (ret) {
+ DEBUG(10, ("Sid %s -> %s\\%s(%d)\n", sid_string_dbg(sid),
+ domain->name, name->name, name->type));
+ } else {
+ DEBUG(10, ("failed to lookup sid %s\n", sid_string_dbg(sid)));
+ }
+ TALLOC_FREE(tmp_ctx);
+ return ret;
+}
+
+/*****************************************************************
+ Id mapping cache. This is to avoid Winbind mappings already
+ seen by smbd to be queried too frequently, keeping winbindd
+ busy, and blocking smbd while winbindd is busy with other
+ stuff. Written by Michael Steffens <michael.steffens@hp.com>,
+ modified to use linked lists by jra.
+*****************************************************************/
+
+/*****************************************************************
+ Find a SID given a uid.
+*****************************************************************/
+
+static bool fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
+{
+ DATA_BLOB cache_value;
+
+ if (!memcache_lookup(NULL, UID_SID_CACHE,
+ data_blob_const(&uid, sizeof(uid)),
+ &cache_value)) {
+ return false;
+ }
+
+ memcpy(psid, cache_value.data, MIN(sizeof(*psid), cache_value.length));
+ SMB_ASSERT(cache_value.length >= offsetof(struct dom_sid, id_auth));
+ SMB_ASSERT(cache_value.length == ndr_size_dom_sid(psid, 0));
+
+ return true;
+}
+
+/*****************************************************************
+ Find a uid given a SID.
+*****************************************************************/
+
+static bool fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
+{
+ DATA_BLOB cache_value;
+
+ if (!memcache_lookup(NULL, SID_UID_CACHE,
+ data_blob_const(psid, ndr_size_dom_sid(psid, 0)),
+ &cache_value)) {
+ return false;
+ }
+
+ SMB_ASSERT(cache_value.length == sizeof(*puid));
+ memcpy(puid, cache_value.data, sizeof(*puid));
+
+ return true;
+}
+
+/*****************************************************************
+ Store uid to SID mapping in cache.
+*****************************************************************/
+
+void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
+{
+ memcache_add(NULL, SID_UID_CACHE,
+ data_blob_const(psid, ndr_size_dom_sid(psid, 0)),
+ data_blob_const(&uid, sizeof(uid)));
+ memcache_add(NULL, UID_SID_CACHE,
+ data_blob_const(&uid, sizeof(uid)),
+ data_blob_const(psid, ndr_size_dom_sid(psid, 0)));
+}
+
+/*****************************************************************
+ Find a SID given a gid.
+*****************************************************************/
+
+static bool fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
+{
+ DATA_BLOB cache_value;
+
+ if (!memcache_lookup(NULL, GID_SID_CACHE,
+ data_blob_const(&gid, sizeof(gid)),
+ &cache_value)) {
+ return false;
+ }
+
+ memcpy(psid, cache_value.data, MIN(sizeof(*psid), cache_value.length));
+ SMB_ASSERT(cache_value.length >= offsetof(struct dom_sid, id_auth));
+ SMB_ASSERT(cache_value.length == ndr_size_dom_sid(psid, 0));
+
+ return true;
+}
+
+/*****************************************************************
+ Find a gid given a SID.
+*****************************************************************/
+
+static bool fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
+{
+ DATA_BLOB cache_value;
+
+ if (!memcache_lookup(NULL, SID_UID_CACHE,
+ data_blob_const(psid, ndr_size_dom_sid(psid, 0)),
+ &cache_value)) {
+ return false;
+ }
+
+ SMB_ASSERT(cache_value.length == sizeof(*pgid));
+ memcpy(pgid, cache_value.data, sizeof(*pgid));
+
+ return true;
+}
+
+/*****************************************************************
+ Store gid to SID mapping in cache.
+*****************************************************************/
+
+void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
+{
+ memcache_add(NULL, SID_GID_CACHE,
+ data_blob_const(psid, ndr_size_dom_sid(psid, 0)),
+ data_blob_const(&gid, sizeof(gid)));
+ memcache_add(NULL, GID_SID_CACHE,
+ data_blob_const(&gid, sizeof(gid)),
+ data_blob_const(psid, ndr_size_dom_sid(psid, 0)));
+}
+
+/*****************************************************************
+ *THE LEGACY* convert uid_t to SID function.
+*****************************************************************/
+
+static void legacy_uid_to_sid(DOM_SID *psid, uid_t uid)
+{
+ uint32 rid;
+ bool ret;
+
+ ZERO_STRUCTP(psid);
+
+ become_root();
+ ret = pdb_uid_to_rid(uid, &rid);
+ unbecome_root();
+
+ if (ret) {
+ /* This is a mapped user */
+ sid_copy(psid, get_global_sam_sid());
+ sid_append_rid(psid, rid);
+ goto done;
+ }
+
+ /* This is an unmapped user */
+
+ uid_to_unix_users_sid(uid, psid);
+
+ done:
+ DEBUG(10,("LEGACY: uid %u -> sid %s\n", (unsigned int)uid,
+ sid_string_dbg(psid)));
+
+ store_uid_sid_cache(psid, uid);
+ return;
+}
+
+/*****************************************************************
+ *THE LEGACY* convert gid_t to SID function.
+*****************************************************************/
+
+static void legacy_gid_to_sid(DOM_SID *psid, gid_t gid)
+{
+ bool ret;
+
+ ZERO_STRUCTP(psid);
+
+ become_root();
+ ret = pdb_gid_to_sid(gid, psid);
+ unbecome_root();
+
+ if (ret) {
+ /* This is a mapped group */
+ goto done;
+ }
+
+ /* This is an unmapped group */
+
+ gid_to_unix_groups_sid(gid, psid);
+
+ done:
+ DEBUG(10,("LEGACY: gid %u -> sid %s\n", (unsigned int)gid,
+ sid_string_dbg(psid)));
+
+ store_gid_sid_cache(psid, gid);
+ return;
+}
+
+/*****************************************************************
+ *THE LEGACY* convert SID to uid function.
+*****************************************************************/
+
+static bool legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid)
+{
+ enum lsa_SidType type;
+ uint32 rid;
+
+ if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
+ union unid_t id;
+ bool ret;
+
+ become_root();
+ ret = pdb_sid_to_id(psid, &id, &type);
+ unbecome_root();
+
+ if (ret) {
+ if (type != SID_NAME_USER) {
+ DEBUG(5, ("sid %s is a %s, expected a user\n",
+ sid_string_dbg(psid),
+ sid_type_lookup(type)));
+ return false;
+ }
+ *puid = id.uid;
+ goto done;
+ }
+
+ /* This was ours, but it was not mapped. Fail */
+ }
+
+ DEBUG(10,("LEGACY: mapping failed for sid %s\n",
+ sid_string_dbg(psid)));
+ return false;
+
+done:
+ DEBUG(10,("LEGACY: sid %s -> uid %u\n", sid_string_dbg(psid),
+ (unsigned int)*puid ));
+
+ store_uid_sid_cache(psid, *puid);
+ return true;
+}
+
+/*****************************************************************
+ *THE LEGACY* convert SID to gid function.
+ Group mapping is used for gids that maps to Wellknown SIDs
+*****************************************************************/
+
+static bool legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid)
+{
+ uint32 rid;
+ GROUP_MAP map;
+ union unid_t id;
+ enum lsa_SidType type;
+
+ if ((sid_check_is_in_builtin(psid) ||
+ sid_check_is_in_wellknown_domain(psid))) {
+ bool ret;
+
+ become_root();
+ ret = pdb_getgrsid(&map, *psid);
+ unbecome_root();
+
+ if (ret) {
+ *pgid = map.gid;
+ goto done;
+ }
+ DEBUG(10,("LEGACY: mapping failed for sid %s\n",
+ sid_string_dbg(psid)));
+ return false;
+ }
+
+ if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
+ bool ret;
+
+ become_root();
+ ret = pdb_sid_to_id(psid, &id, &type);
+ unbecome_root();
+
+ if (ret) {
+ if ((type != SID_NAME_DOM_GRP) &&
+ (type != SID_NAME_ALIAS)) {
+ DEBUG(5, ("LEGACY: sid %s is a %s, expected "
+ "a group\n", sid_string_dbg(psid),
+ sid_type_lookup(type)));
+ return false;
+ }
+ *pgid = id.gid;
+ goto done;
+ }
+
+ /* This was ours, but it was not mapped. Fail */
+ }
+
+ DEBUG(10,("LEGACY: mapping failed for sid %s\n",
+ sid_string_dbg(psid)));
+ return false;
+
+ done:
+ DEBUG(10,("LEGACY: sid %s -> gid %u\n", sid_string_dbg(psid),
+ (unsigned int)*pgid ));
+
+ store_gid_sid_cache(psid, *pgid);
+
+ return true;
+}
+
+/*****************************************************************
+ *THE CANONICAL* convert uid_t to SID function.
+*****************************************************************/
+
+void uid_to_sid(DOM_SID *psid, uid_t uid)
+{
+ bool expired = true;
+ bool ret;
+ ZERO_STRUCTP(psid);
+
+ if (fetch_sid_from_uid_cache(psid, uid))
+ return;
+
+ /* Check the winbindd cache directly. */
+ ret = idmap_cache_find_uid2sid(uid, psid, &expired);
+
+ if (ret && !expired && is_null_sid(psid)) {
+ /*
+ * Negative cache entry, we already asked.
+ * do legacy.
+ */
+ legacy_uid_to_sid(psid, uid);
+ return;
+ }
+
+ if (!ret || expired) {
+ /* Not in cache. Ask winbindd. */
+ if (!winbind_uid_to_sid(psid, uid)) {
+ if (!winbind_ping()) {
+ legacy_uid_to_sid(psid, uid);
+ return;
+ }
+
+ DEBUG(5, ("uid_to_sid: winbind failed to find a sid for uid %u\n",
+ uid));
+ return;
+ }
+ }
+
+ DEBUG(10,("uid %u -> sid %s\n", (unsigned int)uid,
+ sid_string_dbg(psid)));
+
+ store_uid_sid_cache(psid, uid);
+ return;
+}
+
+/*****************************************************************
+ *THE CANONICAL* convert gid_t to SID function.
+*****************************************************************/
+
+void gid_to_sid(DOM_SID *psid, gid_t gid)
+{
+ bool expired = true;
+ bool ret;
+ ZERO_STRUCTP(psid);
+
+ if (fetch_sid_from_gid_cache(psid, gid))
+ return;
+
+ /* Check the winbindd cache directly. */
+ ret = idmap_cache_find_gid2sid(gid, psid, &expired);
+
+ if (ret && !expired && is_null_sid(psid)) {
+ /*
+ * Negative cache entry, we already asked.
+ * do legacy.
+ */
+ legacy_gid_to_sid(psid, gid);
+ return;
+ }
+
+ if (!ret || expired) {
+ /* Not in cache. Ask winbindd. */
+ if (!winbind_gid_to_sid(psid, gid)) {
+ if (!winbind_ping()) {
+ legacy_gid_to_sid(psid, gid);
+ return;
+ }
+
+ DEBUG(5, ("gid_to_sid: winbind failed to find a sid for gid %u\n",
+ gid));
+ return;
+ }
+ }
+
+ DEBUG(10,("gid %u -> sid %s\n", (unsigned int)gid,
+ sid_string_dbg(psid)));
+
+ store_gid_sid_cache(psid, gid);
+ return;
+}
+
+/*****************************************************************
+ *THE CANONICAL* convert SID to uid function.
+*****************************************************************/
+
+bool sid_to_uid(const DOM_SID *psid, uid_t *puid)
+{
+ bool expired = true;
+ bool ret;
+ uint32 rid;
+ gid_t gid;
+
+ if (fetch_uid_from_cache(puid, psid))
+ return true;
+
+ if (fetch_gid_from_cache(&gid, psid)) {
+ return false;
+ }
+
+ /* Optimize for the Unix Users Domain
+ * as the conversion is straightforward */
+ if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
+ uid_t uid = rid;
+ *puid = uid;
+
+ /* return here, don't cache */
+ DEBUG(10,("sid %s -> uid %u\n", sid_string_dbg(psid),
+ (unsigned int)*puid ));
+ return true;
+ }
+
+ /* Check the winbindd cache directly. */
+ ret = idmap_cache_find_sid2uid(psid, puid, &expired);
+
+ if (ret && !expired && (*puid == (uid_t)-1)) {
+ /*
+ * Negative cache entry, we already asked.
+ * do legacy.
+ */
+ return legacy_sid_to_uid(psid, puid);
+ }
+
+ if (!ret || expired) {
+ /* Not in cache. Ask winbindd. */
+ if (!winbind_sid_to_uid(puid, psid)) {
+ if (!winbind_ping()) {
+ return legacy_sid_to_uid(psid, puid);
+ }
+
+ DEBUG(5, ("winbind failed to find a uid for sid %s\n",
+ sid_string_dbg(psid)));
+ return false;
+ }
+ }
+
+ /* TODO: Here would be the place to allocate both a gid and a uid for
+ * the SID in question */
+
+ DEBUG(10,("sid %s -> uid %u\n", sid_string_dbg(psid),
+ (unsigned int)*puid ));
+
+ store_uid_sid_cache(psid, *puid);
+ return true;
+}
+
+/*****************************************************************
+ *THE CANONICAL* convert SID to gid function.
+ Group mapping is used for gids that maps to Wellknown SIDs
+*****************************************************************/
+
+bool sid_to_gid(const DOM_SID *psid, gid_t *pgid)
+{
+ bool expired = true;
+ bool ret;
+ uint32 rid;
+ uid_t uid;
+
+ if (fetch_gid_from_cache(pgid, psid))
+ return true;
+
+ if (fetch_uid_from_cache(&uid, psid))
+ return false;
+
+ /* Optimize for the Unix Groups Domain
+ * as the conversion is straightforward */
+ if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
+ gid_t gid = rid;
+ *pgid = gid;
+
+ /* return here, don't cache */
+ DEBUG(10,("sid %s -> gid %u\n", sid_string_dbg(psid),
+ (unsigned int)*pgid ));
+ return true;
+ }
+
+ /* Check the winbindd cache directly. */
+ ret = idmap_cache_find_sid2gid(psid, pgid, &expired);
+
+ if (ret && !expired && (*pgid == (gid_t)-1)) {
+ /*
+ * Negative cache entry, we already asked.
+ * do legacy.
+ */
+ return legacy_sid_to_gid(psid, pgid);
+ }
+
+ if (!ret || expired) {
+ /* Not in cache or negative. Ask winbindd. */
+ /* Ask winbindd if it can map this sid to a gid.
+ * (Idmap will check it is a valid SID and of the right type) */
+
+ if ( !winbind_sid_to_gid(pgid, psid) ) {
+ if (!winbind_ping()) {
+ return legacy_sid_to_gid(psid, pgid);
+ }
+
+ DEBUG(10,("winbind failed to find a gid for sid %s\n",
+ sid_string_dbg(psid)));
+ return false;
+ }
+ }
+
+ DEBUG(10,("sid %s -> gid %u\n", sid_string_dbg(psid),
+ (unsigned int)*pgid ));
+
+ store_gid_sid_cache(psid, *pgid);
+ return true;
+}
diff --git a/source3/passdb/machine_sid.c b/source3/passdb/machine_sid.c
new file mode 100644
index 0000000000..ff2c9bcb0d
--- /dev/null
+++ b/source3/passdb/machine_sid.c
@@ -0,0 +1,248 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Jeremy Allison 1996-2002
+ Copyright (C) Andrew Tridgell 2002
+ Copyright (C) Gerald (Jerry) Carter 2000
+ Copyright (C) Stefan (metze) Metzmacher 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* NOTE! the global_sam_sid is the SID of our local SAM. This is only
+ equal to the domain SID when we are a DC, otherwise its our
+ workstation SID */
+static DOM_SID *global_sam_sid=NULL;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+/****************************************************************************
+ Read a SID from a file. This is for compatibility with the old MACHINE.SID
+ style of SID storage
+****************************************************************************/
+
+static bool read_sid_from_file(const char *fname, DOM_SID *sid)
+{
+ char **lines;
+ int numlines;
+ bool ret;
+
+ lines = file_lines_load(fname, &numlines,0);
+
+ if (!lines || numlines < 1) {
+ if (lines) file_lines_free(lines);
+ return False;
+ }
+
+ ret = string_to_sid(sid, lines[0]);
+ file_lines_free(lines);
+ return ret;
+}
+
+/*
+ generate a random sid - used to build our own sid if we don't have one
+*/
+static void generate_random_sid(DOM_SID *sid)
+{
+ int i;
+ uchar raw_sid_data[12];
+
+ memset((char *)sid, '\0', sizeof(*sid));
+ sid->sid_rev_num = 1;
+ sid->id_auth[5] = 5;
+ sid->num_auths = 0;
+ sid->sub_auths[sid->num_auths++] = 21;
+
+ generate_random_buffer(raw_sid_data, 12);
+ for (i = 0; i < 3; i++)
+ sid->sub_auths[sid->num_auths++] = IVAL(raw_sid_data, i*4);
+}
+
+/****************************************************************************
+ Generate the global machine sid.
+****************************************************************************/
+
+static DOM_SID *pdb_generate_sam_sid(void)
+{
+ DOM_SID domain_sid;
+ char *fname = NULL;
+ DOM_SID *sam_sid;
+
+ if(!(sam_sid=SMB_MALLOC_P(DOM_SID)))
+ return NULL;
+
+ if ( IS_DC ) {
+ if (secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
+ sid_copy(sam_sid, &domain_sid);
+ return sam_sid;
+ }
+ }
+
+ if (secrets_fetch_domain_sid(global_myname(), sam_sid)) {
+
+ /* We got our sid. If not a pdc/bdc, we're done. */
+ if ( !IS_DC )
+ return sam_sid;
+
+ if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
+
+ /* No domain sid and we're a pdc/bdc. Store it */
+
+ if (!secrets_store_domain_sid(lp_workgroup(), sam_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Can't store domain SID as a pdc/bdc.\n"));
+ SAFE_FREE(sam_sid);
+ return NULL;
+ }
+ return sam_sid;
+ }
+
+ if (!sid_equal(&domain_sid, sam_sid)) {
+
+ /* Domain name sid doesn't match global sam sid. Re-store domain sid as 'local' sid. */
+
+ DEBUG(0,("pdb_generate_sam_sid: Mismatched SIDs as a pdc/bdc.\n"));
+ if (!secrets_store_domain_sid(global_myname(), &domain_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Can't re-store domain SID for local sid as PDC/BDC.\n"));
+ SAFE_FREE(sam_sid);
+ return NULL;
+ }
+ return sam_sid;
+ }
+
+ return sam_sid;
+
+ }
+
+ /* check for an old MACHINE.SID file for backwards compatibility */
+ if (asprintf(&fname, "%s/MACHINE.SID", lp_private_dir()) == -1) {
+ SAFE_FREE(sam_sid);
+ return NULL;
+ }
+
+ if (read_sid_from_file(fname, sam_sid)) {
+ /* remember it for future reference and unlink the old MACHINE.SID */
+ if (!secrets_store_domain_sid(global_myname(), sam_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Failed to store SID from file.\n"));
+ SAFE_FREE(fname);
+ SAFE_FREE(sam_sid);
+ return NULL;
+ }
+ unlink(fname);
+ if ( !IS_DC ) {
+ if (!secrets_store_domain_sid(lp_workgroup(), sam_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Failed to store domain SID from file.\n"));
+ SAFE_FREE(fname);
+ SAFE_FREE(sam_sid);
+ return NULL;
+ }
+ }
+
+ /* Stored the old sid from MACHINE.SID successfully.*/
+ SAFE_FREE(fname);
+ return sam_sid;
+ }
+
+ SAFE_FREE(fname);
+
+ /* we don't have the SID in secrets.tdb, we will need to
+ generate one and save it */
+ generate_random_sid(sam_sid);
+
+ if (!secrets_store_domain_sid(global_myname(), sam_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Failed to store generated machine SID.\n"));
+ SAFE_FREE(sam_sid);
+ return NULL;
+ }
+ if ( IS_DC ) {
+ if (!secrets_store_domain_sid(lp_workgroup(), sam_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Failed to store generated domain SID.\n"));
+ SAFE_FREE(sam_sid);
+ return NULL;
+ }
+ }
+
+ return sam_sid;
+}
+
+/* return our global_sam_sid */
+DOM_SID *get_global_sam_sid(void)
+{
+ struct db_context *db;
+
+ if (global_sam_sid != NULL)
+ return global_sam_sid;
+
+ /*
+ * memory for global_sam_sid is allocated in
+ * pdb_generate_sam_sid() as needed
+ *
+ * Note: this is garded by a transaction
+ * to prevent races on startup which
+ * can happen with some dbwrap backends
+ */
+
+ db = secrets_db_ctx();
+ if (!db) {
+ smb_panic("could not open secrets db");
+ }
+
+ if (db->transaction_start(db) != 0) {
+ smb_panic("could not start transaction on secrets db");
+ }
+
+ if (!(global_sam_sid = pdb_generate_sam_sid())) {
+ db->transaction_cancel(db);
+ smb_panic("could not generate a machine SID");
+ }
+
+ if (db->transaction_commit(db) != 0) {
+ smb_panic("could not start commit secrets db");
+ }
+
+ return global_sam_sid;
+}
+
+/**
+ * Force get_global_sam_sid to requery the backends
+ */
+void reset_global_sam_sid(void)
+{
+ SAFE_FREE(global_sam_sid);
+}
+
+/*****************************************************************
+ Check if the SID is our domain SID (S-1-5-21-x-y-z).
+*****************************************************************/
+
+bool sid_check_is_domain(const DOM_SID *sid)
+{
+ return sid_equal(sid, get_global_sam_sid());
+}
+
+/*****************************************************************
+ Check if the SID is our domain SID (S-1-5-21-x-y-z).
+*****************************************************************/
+
+bool sid_check_is_in_our_domain(const DOM_SID *sid)
+{
+ DOM_SID dom_sid;
+ uint32 rid;
+
+ sid_copy(&dom_sid, sid);
+ sid_split_rid(&dom_sid, &rid);
+ return sid_check_is_domain(&dom_sid);
+}
diff --git a/source3/passdb/passdb.c b/source3/passdb/passdb.c
new file mode 100644
index 0000000000..a670b46d69
--- /dev/null
+++ b/source3/passdb/passdb.c
@@ -0,0 +1,1657 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Jeremy Allison 1996-2001
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Gerald (Jerry) Carter 2000-2006
+ Copyright (C) Andrew Bartlett 2001-2002
+ Copyright (C) Simo Sorce 2003
+ Copyright (C) Volker Lendecke 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+/******************************************************************
+ get the default domain/netbios name to be used when
+ testing authentication. For example, if you connect
+ to a Windows member server using a bogus domain name, the
+ Windows box will map the BOGUS\user to DOMAIN\user. A
+ standalone box will map to WKS\user.
+******************************************************************/
+
+const char *my_sam_name(void)
+{
+ /* standalone servers can only use the local netbios name */
+ if ( lp_server_role() == ROLE_STANDALONE )
+ return global_myname();
+
+ /* Windows domain members default to the DOMAIN
+ name when not specified */
+ return lp_workgroup();
+}
+
+/**********************************************************************
+***********************************************************************/
+
+static int samu_destroy(struct samu *user)
+{
+ data_blob_clear_free( &user->lm_pw );
+ data_blob_clear_free( &user->nt_pw );
+
+ if ( user->plaintext_pw )
+ memset( user->plaintext_pw, 0x0, strlen(user->plaintext_pw) );
+
+ return 0;
+}
+
+/**********************************************************************
+ generate a new struct samuser
+***********************************************************************/
+
+struct samu *samu_new( TALLOC_CTX *ctx )
+{
+ struct samu *user;
+
+ if ( !(user = TALLOC_ZERO_P( ctx, struct samu )) ) {
+ DEBUG(0,("samuser_new: Talloc failed!\n"));
+ return NULL;
+ }
+
+ talloc_set_destructor( user, samu_destroy );
+
+ /* no initial methods */
+
+ user->methods = NULL;
+
+ /* Don't change these timestamp settings without a good reason.
+ They are important for NT member server compatibility. */
+
+ user->logon_time = (time_t)0;
+ user->pass_last_set_time = (time_t)0;
+ user->pass_can_change_time = (time_t)0;
+ user->logoff_time = get_time_t_max();
+ user->kickoff_time = get_time_t_max();
+ user->pass_must_change_time = get_time_t_max();
+ user->fields_present = 0x00ffffff;
+ 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->bad_password_count = 0;
+ user->logon_count = 0;
+ user->unknown_6 = 0x000004ec; /* don't know */
+
+ /* Some parts of samba strlen their pdb_get...() returns,
+ so this keeps the interface unchanged for now. */
+
+ user->username = "";
+ user->domain = "";
+ user->nt_username = "";
+ user->full_name = "";
+ user->home_dir = "";
+ user->logon_script = "";
+ user->profile_path = "";
+ user->acct_desc = "";
+ user->workstations = "";
+ user->comment = "";
+ user->munged_dial = "";
+
+ user->plaintext_pw = NULL;
+
+ /* Unless we know otherwise have a Account Control Bit
+ value of 'normal user'. This helps User Manager, which
+ asks for a filtered list of users. */
+
+ user->acct_ctrl = ACB_NORMAL;
+
+
+ return user;
+}
+
+/*********************************************************************
+ Initialize a struct samu from a struct passwd including the user
+ and group SIDs. The *user structure is filled out with the Unix
+ attributes and a user SID.
+*********************************************************************/
+
+static NTSTATUS samu_set_unix_internal(struct samu *user, const struct passwd *pwd, bool create)
+{
+ const char *guest_account = lp_guestaccount();
+ const char *domain = global_myname();
+ uint32 urid;
+
+ if ( !pwd ) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* Basic properties based upon the Unix account information */
+
+ pdb_set_username(user, pwd->pw_name, PDB_SET);
+ pdb_set_fullname(user, pwd->pw_gecos, PDB_SET);
+ pdb_set_domain (user, get_global_sam_name(), PDB_DEFAULT);
+#if 0
+ /* This can lead to a primary group of S-1-22-2-XX which
+ will be rejected by other parts of the Samba code.
+ Rely on pdb_get_group_sid() to "Do The Right Thing" (TM)
+ --jerry */
+
+ gid_to_sid(&group_sid, pwd->pw_gid);
+ pdb_set_group_sid(user, &group_sid, PDB_SET);
+#endif
+
+ /* save the password structure for later use */
+
+ user->unix_pw = tcopy_passwd( user, pwd );
+
+ /* Special case for the guest account which must have a RID of 501 */
+
+ if ( strequal( pwd->pw_name, guest_account ) ) {
+ if ( !pdb_set_user_sid_from_rid(user, DOMAIN_USER_RID_GUEST, PDB_DEFAULT)) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+ return NT_STATUS_OK;
+ }
+
+ /* Non-guest accounts...Check for a workstation or user account */
+
+ if (pwd->pw_name[strlen(pwd->pw_name)-1] == '$') {
+ /* workstation */
+
+ if (!pdb_set_acct_ctrl(user, ACB_WSTRUST, PDB_DEFAULT)) {
+ DEBUG(1, ("Failed to set 'workstation account' flags for user %s.\n",
+ pwd->pw_name));
+ return NT_STATUS_INVALID_COMPUTER_NAME;
+ }
+ }
+ else {
+ /* user */
+
+ if (!pdb_set_acct_ctrl(user, ACB_NORMAL, PDB_DEFAULT)) {
+ DEBUG(1, ("Failed to set 'normal account' flags for user %s.\n",
+ pwd->pw_name));
+ return NT_STATUS_INVALID_ACCOUNT_NAME;
+ }
+
+ /* set some basic attributes */
+
+ pdb_set_profile_path(user, talloc_sub_specified(user,
+ lp_logon_path(), pwd->pw_name, domain, pwd->pw_uid, pwd->pw_gid),
+ PDB_DEFAULT);
+ pdb_set_homedir(user, talloc_sub_specified(user,
+ lp_logon_home(), pwd->pw_name, domain, pwd->pw_uid, pwd->pw_gid),
+ PDB_DEFAULT);
+ pdb_set_dir_drive(user, talloc_sub_specified(user,
+ lp_logon_drive(), pwd->pw_name, domain, pwd->pw_uid, pwd->pw_gid),
+ PDB_DEFAULT);
+ pdb_set_logon_script(user, talloc_sub_specified(user,
+ lp_logon_script(), pwd->pw_name, domain, pwd->pw_uid, pwd->pw_gid),
+ PDB_DEFAULT);
+ }
+
+ /* Now deal with the user SID. If we have a backend that can generate
+ RIDs, then do so. But sometimes the caller just wanted a structure
+ initialized and will fill in these fields later (such as from a
+ netr_SamInfo3 structure) */
+
+ if ( create && !pdb_rid_algorithm() ) {
+ uint32 user_rid;
+ DOM_SID user_sid;
+
+ if ( !pdb_new_rid( &user_rid ) ) {
+ DEBUG(3, ("Could not allocate a new RID\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ sid_copy( &user_sid, get_global_sam_sid() );
+ sid_append_rid( &user_sid, user_rid );
+
+ if ( !pdb_set_user_sid(user, &user_sid, PDB_SET) ) {
+ DEBUG(3, ("pdb_set_user_sid failed\n"));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ return NT_STATUS_OK;
+ }
+
+ /* generate a SID for the user with the RID algorithm */
+
+ urid = algorithmic_pdb_uid_to_user_rid( user->unix_pw->pw_uid );
+
+ if ( !pdb_set_user_sid_from_rid( user, urid, PDB_SET) ) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+ Set the Unix user attributes
+********************************************************************/
+
+NTSTATUS samu_set_unix(struct samu *user, const struct passwd *pwd)
+{
+ return samu_set_unix_internal( user, pwd, False );
+}
+
+NTSTATUS samu_alloc_rid_unix(struct samu *user, const struct passwd *pwd)
+{
+ return samu_set_unix_internal( user, pwd, True );
+}
+
+/**********************************************************
+ Encode the account control bits into a string.
+ length = length of string to encode into (including terminating
+ null). length *MUST BE MORE THAN 2* !
+ **********************************************************/
+
+char *pdb_encode_acct_ctrl(uint32 acct_ctrl, size_t length)
+{
+ fstring acct_str;
+ char *result;
+
+ size_t i = 0;
+
+ SMB_ASSERT(length <= sizeof(acct_str));
+
+ 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';
+
+ result = talloc_strdup(talloc_tos(), acct_str);
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+/**********************************************************
+ Decode the account control bits from a string.
+ **********************************************************/
+
+uint32 pdb_decode_acct_ctrl(const char *p)
+{
+ uint32 acct_ctrl = 0;
+ bool finished = False;
+
+ /*
+ * Check if the account type bits have been encoded after the
+ * NT password (in the form [NDHTUWSLXI]).
+ */
+
+ if (*p != '[')
+ return 0;
+
+ for (p++; *p && !finished; p++) {
+ switch (*p) {
+ case 'N': { acct_ctrl |= ACB_PWNOTREQ ; break; /* 'N'o password. */ }
+ case 'D': { acct_ctrl |= ACB_DISABLED ; break; /* 'D'isabled. */ }
+ case 'H': { acct_ctrl |= ACB_HOMDIRREQ; break; /* 'H'omedir required. */ }
+ case 'T': { acct_ctrl |= ACB_TEMPDUP ; break; /* 'T'emp account. */ }
+ case 'U': { acct_ctrl |= ACB_NORMAL ; break; /* 'U'ser account (normal). */ }
+ case 'M': { acct_ctrl |= ACB_MNS ; break; /* 'M'NS logon user account. What is this ? */ }
+ case 'W': { acct_ctrl |= ACB_WSTRUST ; break; /* 'W'orkstation account. */ }
+ case 'S': { acct_ctrl |= ACB_SVRTRUST ; break; /* 'S'erver account. */ }
+ case 'L': { acct_ctrl |= ACB_AUTOLOCK ; break; /* 'L'ocked account. */ }
+ case 'X': { acct_ctrl |= ACB_PWNOEXP ; break; /* No 'X'piry on password */ }
+ case 'I': { acct_ctrl |= ACB_DOMTRUST ; break; /* 'I'nterdomain trust account. */ }
+ case ' ': { break; }
+ case ':':
+ case '\n':
+ case '\0':
+ case ']':
+ default: { finished = True; }
+ }
+ }
+
+ return acct_ctrl;
+}
+
+/*************************************************************
+ Routine to set 32 hex password characters from a 16 byte array.
+**************************************************************/
+
+void pdb_sethexpwd(char p[33], const unsigned char *pwd, uint32 acct_ctrl)
+{
+ if (pwd != NULL) {
+ int i;
+ for (i = 0; i < 16; i++)
+ slprintf(&p[i*2], 3, "%02X", pwd[i]);
+ } else {
+ if (acct_ctrl & ACB_PWNOTREQ)
+ safe_strcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 32);
+ else
+ safe_strcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 32);
+ }
+}
+
+/*************************************************************
+ Routine to get the 32 hex characters and turn them
+ into a 16 byte array.
+**************************************************************/
+
+bool pdb_gethexpwd(const char *p, unsigned char *pwd)
+{
+ int i;
+ unsigned char lonybble, hinybble;
+ const char *hexchars = "0123456789ABCDEF";
+ char *p1, *p2;
+
+ if (!p)
+ return (False);
+
+ for (i = 0; i < 32; i += 2) {
+ hinybble = toupper_ascii(p[i]);
+ lonybble = toupper_ascii(p[i + 1]);
+
+ p1 = strchr(hexchars, hinybble);
+ p2 = strchr(hexchars, lonybble);
+
+ if (!p1 || !p2)
+ return (False);
+
+ hinybble = PTR_DIFF(p1, hexchars);
+ lonybble = PTR_DIFF(p2, hexchars);
+
+ pwd[i / 2] = (hinybble << 4) | lonybble;
+ }
+ return (True);
+}
+
+/*************************************************************
+ Routine to set 42 hex hours characters from a 21 byte array.
+**************************************************************/
+
+void pdb_sethexhours(char *p, const unsigned char *hours)
+{
+ if (hours != NULL) {
+ int i;
+ for (i = 0; i < 21; i++) {
+ slprintf(&p[i*2], 3, "%02X", hours[i]);
+ }
+ } else {
+ safe_strcpy(p, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 43);
+ }
+}
+
+/*************************************************************
+ Routine to get the 42 hex characters and turn them
+ into a 21 byte array.
+**************************************************************/
+
+bool pdb_gethexhours(const char *p, unsigned char *hours)
+{
+ int i;
+ unsigned char lonybble, hinybble;
+ const char *hexchars = "0123456789ABCDEF";
+ char *p1, *p2;
+
+ if (!p) {
+ return (False);
+ }
+
+ for (i = 0; i < 42; i += 2) {
+ hinybble = toupper_ascii(p[i]);
+ lonybble = toupper_ascii(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);
+
+ hours[i / 2] = (hinybble << 4) | lonybble;
+ }
+ return (True);
+}
+
+/********************************************************************
+********************************************************************/
+
+int algorithmic_rid_base(void)
+{
+ int rid_offset;
+
+ rid_offset = lp_algorithmic_rid_base();
+
+ if (rid_offset < BASE_RID) {
+ /* Try to prevent admin foot-shooting, we can't put algorithmic
+ rids below 1000, that's the 'well known RIDs' on NT */
+ DEBUG(0, ("'algorithmic rid base' must be equal to or above %ld\n", BASE_RID));
+ rid_offset = BASE_RID;
+ }
+ if (rid_offset & 1) {
+ DEBUG(0, ("algorithmic rid base must be even\n"));
+ rid_offset += 1;
+ }
+ return rid_offset;
+}
+
+/*******************************************************************
+ Converts NT user RID to a UNIX uid.
+ ********************************************************************/
+
+uid_t algorithmic_pdb_user_rid_to_uid(uint32 user_rid)
+{
+ int rid_offset = algorithmic_rid_base();
+ return (uid_t)(((user_rid & (~USER_RID_TYPE)) - rid_offset)/RID_MULTIPLIER);
+}
+
+uid_t max_algorithmic_uid(void)
+{
+ return algorithmic_pdb_user_rid_to_uid(0xfffffffe);
+}
+
+/*******************************************************************
+ converts UNIX uid to an NT User RID.
+ ********************************************************************/
+
+uint32 algorithmic_pdb_uid_to_user_rid(uid_t uid)
+{
+ int rid_offset = algorithmic_rid_base();
+ return (((((uint32)uid)*RID_MULTIPLIER) + rid_offset) | USER_RID_TYPE);
+}
+
+/*******************************************************************
+ Converts NT group RID to a UNIX gid.
+ ********************************************************************/
+
+gid_t pdb_group_rid_to_gid(uint32 group_rid)
+{
+ int rid_offset = algorithmic_rid_base();
+ return (gid_t)(((group_rid & (~GROUP_RID_TYPE))- rid_offset)/RID_MULTIPLIER);
+}
+
+gid_t max_algorithmic_gid(void)
+{
+ return pdb_group_rid_to_gid(0xffffffff);
+}
+
+/*******************************************************************
+ converts NT Group RID to a UNIX uid.
+
+ warning: you must not call that function only
+ you must do a call to the group mapping first.
+ there is not anymore a direct link between the gid and the rid.
+ ********************************************************************/
+
+uint32 algorithmic_pdb_gid_to_group_rid(gid_t gid)
+{
+ int rid_offset = algorithmic_rid_base();
+ return (((((uint32)gid)*RID_MULTIPLIER) + rid_offset) | GROUP_RID_TYPE);
+}
+
+/*******************************************************************
+ Decides if a RID is a well known RID.
+ ********************************************************************/
+
+static bool rid_is_well_known(uint32 rid)
+{
+ /* Not using rid_offset here, because this is the actual
+ NT fixed value (1000) */
+
+ return (rid < BASE_RID);
+}
+
+/*******************************************************************
+ Decides if a RID is a user or group RID.
+ ********************************************************************/
+
+bool algorithmic_pdb_rid_is_user(uint32 rid)
+{
+ if ( rid_is_well_known(rid) ) {
+ /*
+ * The only well known user RIDs are DOMAIN_USER_RID_ADMIN
+ * and DOMAIN_USER_RID_GUEST.
+ */
+ if(rid == DOMAIN_USER_RID_ADMIN || rid == DOMAIN_USER_RID_GUEST)
+ return True;
+ } else if((rid & RID_TYPE_MASK) == USER_RID_TYPE) {
+ return True;
+ }
+ return False;
+}
+
+/*******************************************************************
+ Convert a name into a SID. Used in the lookup name rpc.
+ ********************************************************************/
+
+bool lookup_global_sam_name(const char *name, int flags, uint32_t *rid,
+ enum lsa_SidType *type)
+{
+ GROUP_MAP map;
+ bool ret;
+
+ /* Windows treats "MACHINE\None" as a special name for
+ rid 513 on non-DCs. You cannot create a user or group
+ name "None" on Windows. You will get an error that
+ the group already exists. */
+
+ if ( strequal( name, "None" ) ) {
+ *rid = DOMAIN_GROUP_RID_USERS;
+ *type = SID_NAME_DOM_GRP;
+
+ return True;
+ }
+
+ /* LOOKUP_NAME_GROUP is a hack to allow valid users = @foo to work
+ * correctly in the case where foo also exists as a user. If the flag
+ * is set, don't look for users at all. */
+
+ if ((flags & LOOKUP_NAME_GROUP) == 0) {
+ struct samu *sam_account = NULL;
+ DOM_SID user_sid;
+
+ if ( !(sam_account = samu_new( NULL )) ) {
+ return False;
+ }
+
+ become_root();
+ ret = pdb_getsampwnam(sam_account, name);
+ unbecome_root();
+
+ if (ret) {
+ sid_copy(&user_sid, pdb_get_user_sid(sam_account));
+ }
+
+ TALLOC_FREE(sam_account);
+
+ if (ret) {
+ if (!sid_check_is_in_our_domain(&user_sid)) {
+ DEBUG(0, ("User %s with invalid SID %s in passdb\n",
+ name, sid_string_dbg(&user_sid)));
+ return False;
+ }
+
+ sid_peek_rid(&user_sid, rid);
+ *type = SID_NAME_USER;
+ return True;
+ }
+ }
+
+ /*
+ * Maybe it is a group ?
+ */
+
+ become_root();
+ ret = pdb_getgrnam(&map, name);
+ unbecome_root();
+
+ if (!ret) {
+ return False;
+ }
+
+ /* BUILTIN groups are looked up elsewhere */
+ if (!sid_check_is_in_our_domain(&map.sid)) {
+ DEBUG(10, ("Found group %s (%s) not in our domain -- "
+ "ignoring.", name, sid_string_dbg(&map.sid)));
+ return False;
+ }
+
+ /* yes it's a mapped group */
+ sid_peek_rid(&map.sid, rid);
+ *type = map.sid_name_use;
+ return True;
+}
+
+/*************************************************************
+ Change a password entry in the local smbpasswd file.
+ *************************************************************/
+
+NTSTATUS local_password_change(const char *user_name,
+ int local_flags,
+ const char *new_passwd,
+ char **pp_err_str,
+ char **pp_msg_str)
+{
+ struct samu *sam_pass=NULL;
+ uint32 other_acb;
+ NTSTATUS result;
+
+ *pp_err_str = NULL;
+ *pp_msg_str = NULL;
+
+ /* Get the smb passwd entry for this user */
+
+ if ( !(sam_pass = samu_new( NULL )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+ if(!pdb_getsampwnam(sam_pass, user_name)) {
+ unbecome_root();
+ TALLOC_FREE(sam_pass);
+
+ if ((local_flags & LOCAL_ADD_USER) || (local_flags & LOCAL_DELETE_USER)) {
+ int tmp_debug = DEBUGLEVEL;
+ struct passwd *pwd;
+
+ /* Might not exist in /etc/passwd. */
+
+ if (tmp_debug < 1) {
+ DEBUGLEVEL = 1;
+ }
+
+ if ( !(pwd = getpwnam_alloc( NULL, user_name)) ) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* create the struct samu and initialize the basic Unix properties */
+
+ if ( !(sam_pass = samu_new( NULL )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result = samu_set_unix( sam_pass, pwd );
+
+ DEBUGLEVEL = tmp_debug;
+
+ TALLOC_FREE( pwd );
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PRIMARY_GROUP)) {
+ return result;
+ }
+
+ if (!NT_STATUS_IS_OK(result)) {
+ asprintf(pp_err_str, "Failed to " "initialize account for user %s: %s\n",
+ user_name, nt_errstr(result));
+ return result;
+ }
+ } else {
+ asprintf(pp_err_str, "Failed to find entry for user %s.\n", user_name);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+ } else {
+ unbecome_root();
+ /* the entry already existed */
+ local_flags &= ~LOCAL_ADD_USER;
+ }
+
+ /* the 'other' acb bits not being changed here */
+ other_acb = (pdb_get_acct_ctrl(sam_pass) & (~(ACB_WSTRUST|ACB_DOMTRUST|ACB_SVRTRUST|ACB_NORMAL)));
+ if (local_flags & LOCAL_TRUST_ACCOUNT) {
+ if (!pdb_set_acct_ctrl(sam_pass, ACB_WSTRUST | other_acb, PDB_CHANGED) ) {
+ asprintf(pp_err_str, "Failed to set 'trusted workstation account' flags for user %s.\n", user_name);
+ TALLOC_FREE(sam_pass);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ } else if (local_flags & LOCAL_INTERDOM_ACCOUNT) {
+ if (!pdb_set_acct_ctrl(sam_pass, ACB_DOMTRUST | other_acb, PDB_CHANGED)) {
+ asprintf(pp_err_str, "Failed to set 'domain trust account' flags for user %s.\n", user_name);
+ TALLOC_FREE(sam_pass);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ } else {
+ if (!pdb_set_acct_ctrl(sam_pass, ACB_NORMAL | other_acb, PDB_CHANGED)) {
+ asprintf(pp_err_str, "Failed to set 'normal account' flags for user %s.\n", user_name);
+ TALLOC_FREE(sam_pass);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ /*
+ * We are root - just write the new password
+ * and the valid last change time.
+ */
+
+ if (local_flags & LOCAL_DISABLE_USER) {
+ if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)|ACB_DISABLED, PDB_CHANGED)) {
+ asprintf(pp_err_str, "Failed to set 'disabled' flag for user %s.\n", user_name);
+ TALLOC_FREE(sam_pass);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ } else if (local_flags & LOCAL_ENABLE_USER) {
+ if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_DISABLED), PDB_CHANGED)) {
+ asprintf(pp_err_str, "Failed to unset 'disabled' flag for user %s.\n", user_name);
+ TALLOC_FREE(sam_pass);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ if (local_flags & LOCAL_SET_NO_PASSWORD) {
+ if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)|ACB_PWNOTREQ, PDB_CHANGED)) {
+ asprintf(pp_err_str, "Failed to set 'no password required' flag for user %s.\n", user_name);
+ TALLOC_FREE(sam_pass);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ } else if (local_flags & LOCAL_SET_PASSWORD) {
+ /*
+ * If we're dealing with setting a completely empty user account
+ * ie. One with a password of 'XXXX', but not set disabled (like
+ * an account created from scratch) then if the old password was
+ * 'XX's then getsmbpwent will have set the ACB_DISABLED flag.
+ * We remove that as we're giving this user their first password
+ * and the decision hasn't really been made to disable them (ie.
+ * don't create them disabled). JRA.
+ */
+ if ((pdb_get_lanman_passwd(sam_pass)==NULL) && (pdb_get_acct_ctrl(sam_pass)&ACB_DISABLED)) {
+ if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_DISABLED), PDB_CHANGED)) {
+ asprintf(pp_err_str, "Failed to unset 'disabled' flag for user %s.\n", user_name);
+ TALLOC_FREE(sam_pass);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+ if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_PWNOTREQ), PDB_CHANGED)) {
+ asprintf(pp_err_str, "Failed to unset 'no password required' flag for user %s.\n", user_name);
+ TALLOC_FREE(sam_pass);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!pdb_set_plaintext_passwd (sam_pass, new_passwd)) {
+ asprintf(pp_err_str, "Failed to set password for user %s.\n", user_name);
+ TALLOC_FREE(sam_pass);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ if (local_flags & LOCAL_ADD_USER) {
+ if (NT_STATUS_IS_OK(pdb_add_sam_account(sam_pass))) {
+ asprintf(pp_msg_str, "Added user %s.\n", user_name);
+ TALLOC_FREE(sam_pass);
+ return NT_STATUS_OK;
+ } else {
+ asprintf(pp_err_str, "Failed to add entry for user %s.\n", user_name);
+ TALLOC_FREE(sam_pass);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ } else if (local_flags & LOCAL_DELETE_USER) {
+ if (!NT_STATUS_IS_OK(pdb_delete_sam_account(sam_pass))) {
+ asprintf(pp_err_str, "Failed to delete entry for user %s.\n", user_name);
+ TALLOC_FREE(sam_pass);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ asprintf(pp_msg_str, "Deleted user %s.\n", user_name);
+ } else {
+ result = pdb_update_sam_account(sam_pass);
+ if(!NT_STATUS_IS_OK(result)) {
+ asprintf(pp_err_str, "Failed to modify entry for user %s.\n", user_name);
+ TALLOC_FREE(sam_pass);
+ return result;
+ }
+ if(local_flags & LOCAL_DISABLE_USER)
+ asprintf(pp_msg_str, "Disabled user %s.\n", user_name);
+ else if (local_flags & LOCAL_ENABLE_USER)
+ asprintf(pp_msg_str, "Enabled user %s.\n", user_name);
+ else if (local_flags & LOCAL_SET_NO_PASSWORD)
+ asprintf(pp_msg_str, "User %s password set to none.\n", user_name);
+ }
+
+ TALLOC_FREE(sam_pass);
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Marshall/unmarshall struct samu structs.
+ *********************************************************************/
+
+#define TDB_FORMAT_STRING_V3 "dddddddBBBBBBBBBBBBddBBBdwdBwwd"
+
+/*********************************************************************
+*********************************************************************/
+
+bool init_sam_from_buffer_v3(struct samu *sampass, uint8 *buf, uint32 buflen)
+{
+
+ /* times are stored as 32bit integer
+ take care on system with 64bit wide time_t
+ --SSS */
+ uint32 logon_time,
+ logoff_time,
+ kickoff_time,
+ bad_password_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+ char *username = NULL;
+ char *domain = NULL;
+ char *nt_username = NULL;
+ char *dir_drive = NULL;
+ char *unknown_str = NULL;
+ char *munged_dial = NULL;
+ char *fullname = NULL;
+ char *homedir = NULL;
+ char *logon_script = NULL;
+ char *profile_path = NULL;
+ char *acct_desc = NULL;
+ char *workstations = NULL;
+ uint32 username_len, domain_len, nt_username_len,
+ dir_drive_len, unknown_str_len, munged_dial_len,
+ fullname_len, homedir_len, logon_script_len,
+ profile_path_len, acct_desc_len, workstations_len;
+
+ uint32 user_rid, group_rid, hours_len, unknown_6, acct_ctrl;
+ uint16 logon_divs;
+ uint16 bad_password_count, logon_count;
+ uint8 *hours = NULL;
+ uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL, *nt_pw_hist_ptr = NULL;
+ uint32 len = 0;
+ uint32 lm_pw_len, nt_pw_len, nt_pw_hist_len, hourslen;
+ uint32 pwHistLen = 0;
+ bool ret = True;
+ fstring tmp_string;
+ bool expand_explicit = lp_passdb_expand_explicit();
+
+ if(sampass == NULL || buf == NULL) {
+ DEBUG(0, ("init_sam_from_buffer_v3: NULL parameters found!\n"));
+ return False;
+ }
+
+/* TDB_FORMAT_STRING_V3 "dddddddBBBBBBBBBBBBddBBBdwdBwwd" */
+
+ /* unpack the buffer into variables */
+ len = tdb_unpack (buf, buflen, TDB_FORMAT_STRING_V3,
+ &logon_time, /* d */
+ &logoff_time, /* d */
+ &kickoff_time, /* d */
+ &bad_password_time, /* d */
+ &pass_last_set_time, /* d */
+ &pass_can_change_time, /* d */
+ &pass_must_change_time, /* d */
+ &username_len, &username, /* B */
+ &domain_len, &domain, /* B */
+ &nt_username_len, &nt_username, /* B */
+ &fullname_len, &fullname, /* B */
+ &homedir_len, &homedir, /* B */
+ &dir_drive_len, &dir_drive, /* B */
+ &logon_script_len, &logon_script, /* B */
+ &profile_path_len, &profile_path, /* B */
+ &acct_desc_len, &acct_desc, /* B */
+ &workstations_len, &workstations, /* B */
+ &unknown_str_len, &unknown_str, /* B */
+ &munged_dial_len, &munged_dial, /* B */
+ &user_rid, /* d */
+ &group_rid, /* d */
+ &lm_pw_len, &lm_pw_ptr, /* B */
+ &nt_pw_len, &nt_pw_ptr, /* B */
+ /* Change from V1 is addition of password history field. */
+ &nt_pw_hist_len, &nt_pw_hist_ptr, /* B */
+ /* Change from V2 is the uint32 acb_mask */
+ &acct_ctrl, /* d */
+ /* Also "remove_me" field was removed. */
+ &logon_divs, /* w */
+ &hours_len, /* d */
+ &hourslen, &hours, /* B */
+ &bad_password_count, /* w */
+ &logon_count, /* w */
+ &unknown_6); /* d */
+
+ if (len == (uint32) -1) {
+ ret = False;
+ goto done;
+ }
+
+ pdb_set_logon_time(sampass, convert_uint32_to_time_t(logon_time), PDB_SET);
+ pdb_set_logoff_time(sampass, convert_uint32_to_time_t(logoff_time), PDB_SET);
+ pdb_set_kickoff_time(sampass, convert_uint32_to_time_t(kickoff_time), PDB_SET);
+ pdb_set_bad_password_time(sampass, convert_uint32_to_time_t(bad_password_time), PDB_SET);
+ pdb_set_pass_can_change_time(sampass, convert_uint32_to_time_t(pass_can_change_time), PDB_SET);
+ pdb_set_pass_must_change_time(sampass, convert_uint32_to_time_t(pass_must_change_time), PDB_SET);
+ pdb_set_pass_last_set_time(sampass, convert_uint32_to_time_t(pass_last_set_time), PDB_SET);
+
+ pdb_set_username(sampass, username, PDB_SET);
+ pdb_set_domain(sampass, domain, PDB_SET);
+ pdb_set_nt_username(sampass, nt_username, PDB_SET);
+ pdb_set_fullname(sampass, fullname, PDB_SET);
+
+ if (homedir) {
+ fstrcpy( tmp_string, homedir );
+ if (expand_explicit) {
+ standard_sub_basic( username, domain, tmp_string,
+ sizeof(tmp_string) );
+ }
+ pdb_set_homedir(sampass, tmp_string, PDB_SET);
+ }
+ else {
+ pdb_set_homedir(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_home()),
+ PDB_DEFAULT);
+ }
+
+ if (dir_drive)
+ pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
+ else
+ pdb_set_dir_drive(sampass, lp_logon_drive(), PDB_DEFAULT );
+
+ if (logon_script) {
+ fstrcpy( tmp_string, logon_script );
+ if (expand_explicit) {
+ standard_sub_basic( username, domain, tmp_string,
+ sizeof(tmp_string) );
+ }
+ pdb_set_logon_script(sampass, tmp_string, PDB_SET);
+ }
+ else {
+ pdb_set_logon_script(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_script()),
+ PDB_DEFAULT);
+ }
+
+ if (profile_path) {
+ fstrcpy( tmp_string, profile_path );
+ if (expand_explicit) {
+ standard_sub_basic( username, domain, tmp_string,
+ sizeof(tmp_string) );
+ }
+ pdb_set_profile_path(sampass, tmp_string, PDB_SET);
+ }
+ else {
+ pdb_set_profile_path(sampass,
+ talloc_sub_basic(sampass, username, domain, lp_logon_path()),
+ PDB_DEFAULT);
+ }
+
+ pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
+ pdb_set_workstations(sampass, workstations, PDB_SET);
+ pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
+
+ if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
+ if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
+ if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen);
+ if (pwHistLen) {
+ uint8 *pw_hist = (uint8 *)SMB_MALLOC(pwHistLen * PW_HISTORY_ENTRY_LEN);
+ if (!pw_hist) {
+ ret = False;
+ goto done;
+ }
+ memset(pw_hist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN);
+ if (nt_pw_hist_ptr && nt_pw_hist_len) {
+ int i;
+ SMB_ASSERT((nt_pw_hist_len % PW_HISTORY_ENTRY_LEN) == 0);
+ nt_pw_hist_len /= PW_HISTORY_ENTRY_LEN;
+ for (i = 0; (i < pwHistLen) && (i < nt_pw_hist_len); i++) {
+ memcpy(&pw_hist[i*PW_HISTORY_ENTRY_LEN],
+ &nt_pw_hist_ptr[i*PW_HISTORY_ENTRY_LEN],
+ PW_HISTORY_ENTRY_LEN);
+ }
+ }
+ if (!pdb_set_pw_history(sampass, pw_hist, pwHistLen, PDB_SET)) {
+ SAFE_FREE(pw_hist);
+ ret = False;
+ goto done;
+ }
+ SAFE_FREE(pw_hist);
+ } else {
+ pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
+ }
+
+ pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
+ pdb_set_hours_len(sampass, hours_len, PDB_SET);
+ pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
+ pdb_set_logon_count(sampass, logon_count, PDB_SET);
+ pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
+ /* Change from V2 is the uint32 acct_ctrl */
+ pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
+ pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
+ pdb_set_hours(sampass, hours, PDB_SET);
+
+done:
+
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ SAFE_FREE(nt_username);
+ SAFE_FREE(fullname);
+ SAFE_FREE(homedir);
+ SAFE_FREE(dir_drive);
+ SAFE_FREE(logon_script);
+ SAFE_FREE(profile_path);
+ SAFE_FREE(acct_desc);
+ SAFE_FREE(workstations);
+ SAFE_FREE(munged_dial);
+ SAFE_FREE(unknown_str);
+ SAFE_FREE(lm_pw_ptr);
+ SAFE_FREE(nt_pw_ptr);
+ SAFE_FREE(nt_pw_hist_ptr);
+ SAFE_FREE(hours);
+
+ return ret;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+uint32 init_buffer_from_sam_v3 (uint8 **buf, struct samu *sampass, bool size_only)
+{
+ size_t len, buflen;
+
+ /* times are stored as 32bit integer
+ take care on system with 64bit wide time_t
+ --SSS */
+ uint32 logon_time,
+ logoff_time,
+ kickoff_time,
+ bad_password_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+
+ uint32 user_rid, group_rid;
+
+ const char *username;
+ const char *domain;
+ const char *nt_username;
+ const char *dir_drive;
+ const char *unknown_str;
+ const char *munged_dial;
+ const char *fullname;
+ const char *homedir;
+ const char *logon_script;
+ const char *profile_path;
+ const char *acct_desc;
+ const char *workstations;
+ uint32 username_len, domain_len, nt_username_len,
+ dir_drive_len, unknown_str_len, munged_dial_len,
+ fullname_len, homedir_len, logon_script_len,
+ profile_path_len, acct_desc_len, workstations_len;
+
+ const uint8 *lm_pw;
+ const uint8 *nt_pw;
+ const uint8 *nt_pw_hist;
+ uint32 lm_pw_len = 16;
+ uint32 nt_pw_len = 16;
+ uint32 nt_pw_hist_len;
+ uint32 pwHistLen = 0;
+
+ *buf = NULL;
+ buflen = 0;
+
+ logon_time = convert_time_t_to_uint32(pdb_get_logon_time(sampass));
+ logoff_time = convert_time_t_to_uint32(pdb_get_logoff_time(sampass));
+ kickoff_time = convert_time_t_to_uint32(pdb_get_kickoff_time(sampass));
+ bad_password_time = convert_time_t_to_uint32(pdb_get_bad_password_time(sampass));
+ pass_can_change_time = convert_time_t_to_uint32(pdb_get_pass_can_change_time_noncalc(sampass));
+ pass_must_change_time = convert_time_t_to_uint32(pdb_get_pass_must_change_time(sampass));
+ pass_last_set_time = convert_time_t_to_uint32(pdb_get_pass_last_set_time(sampass));
+
+ user_rid = pdb_get_user_rid(sampass);
+ group_rid = pdb_get_group_rid(sampass);
+
+ username = pdb_get_username(sampass);
+ if (username) {
+ username_len = strlen(username) +1;
+ } else {
+ username_len = 0;
+ }
+
+ domain = pdb_get_domain(sampass);
+ if (domain) {
+ domain_len = strlen(domain) +1;
+ } else {
+ domain_len = 0;
+ }
+
+ nt_username = pdb_get_nt_username(sampass);
+ if (nt_username) {
+ nt_username_len = strlen(nt_username) +1;
+ } else {
+ nt_username_len = 0;
+ }
+
+ fullname = pdb_get_fullname(sampass);
+ if (fullname) {
+ fullname_len = strlen(fullname) +1;
+ } else {
+ fullname_len = 0;
+ }
+
+ /*
+ * Only updates fields which have been set (not defaults from smb.conf)
+ */
+
+ if (!IS_SAM_DEFAULT(sampass, PDB_DRIVE)) {
+ dir_drive = pdb_get_dir_drive(sampass);
+ } else {
+ dir_drive = NULL;
+ }
+ if (dir_drive) {
+ dir_drive_len = strlen(dir_drive) +1;
+ } else {
+ dir_drive_len = 0;
+ }
+
+ if (!IS_SAM_DEFAULT(sampass, PDB_SMBHOME)) {
+ homedir = pdb_get_homedir(sampass);
+ } else {
+ homedir = NULL;
+ }
+ if (homedir) {
+ homedir_len = strlen(homedir) +1;
+ } else {
+ homedir_len = 0;
+ }
+
+ if (!IS_SAM_DEFAULT(sampass, PDB_LOGONSCRIPT)) {
+ logon_script = pdb_get_logon_script(sampass);
+ } else {
+ logon_script = NULL;
+ }
+ if (logon_script) {
+ logon_script_len = strlen(logon_script) +1;
+ } else {
+ logon_script_len = 0;
+ }
+
+ if (!IS_SAM_DEFAULT(sampass, PDB_PROFILE)) {
+ profile_path = pdb_get_profile_path(sampass);
+ } else {
+ profile_path = NULL;
+ }
+ if (profile_path) {
+ profile_path_len = strlen(profile_path) +1;
+ } else {
+ profile_path_len = 0;
+ }
+
+ lm_pw = pdb_get_lanman_passwd(sampass);
+ if (!lm_pw) {
+ lm_pw_len = 0;
+ }
+
+ nt_pw = pdb_get_nt_passwd(sampass);
+ if (!nt_pw) {
+ nt_pw_len = 0;
+ }
+
+ pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen);
+ nt_pw_hist = pdb_get_pw_history(sampass, &nt_pw_hist_len);
+ if (pwHistLen && nt_pw_hist && nt_pw_hist_len) {
+ nt_pw_hist_len *= PW_HISTORY_ENTRY_LEN;
+ } else {
+ nt_pw_hist_len = 0;
+ }
+
+ acct_desc = pdb_get_acct_desc(sampass);
+ if (acct_desc) {
+ acct_desc_len = strlen(acct_desc) +1;
+ } else {
+ acct_desc_len = 0;
+ }
+
+ workstations = pdb_get_workstations(sampass);
+ if (workstations) {
+ workstations_len = strlen(workstations) +1;
+ } else {
+ workstations_len = 0;
+ }
+
+ unknown_str = NULL;
+ unknown_str_len = 0;
+
+ munged_dial = pdb_get_munged_dial(sampass);
+ if (munged_dial) {
+ munged_dial_len = strlen(munged_dial) +1;
+ } else {
+ munged_dial_len = 0;
+ }
+
+/* TDB_FORMAT_STRING_V3 "dddddddBBBBBBBBBBBBddBBBdwdBwwd" */
+
+ /* one time to get the size needed */
+ len = tdb_pack(NULL, 0, TDB_FORMAT_STRING_V3,
+ logon_time, /* d */
+ logoff_time, /* d */
+ kickoff_time, /* d */
+ bad_password_time, /* d */
+ pass_last_set_time, /* d */
+ pass_can_change_time, /* d */
+ pass_must_change_time, /* d */
+ username_len, username, /* B */
+ domain_len, domain, /* B */
+ nt_username_len, nt_username, /* B */
+ fullname_len, fullname, /* B */
+ homedir_len, homedir, /* B */
+ dir_drive_len, dir_drive, /* B */
+ logon_script_len, logon_script, /* B */
+ profile_path_len, profile_path, /* B */
+ acct_desc_len, acct_desc, /* B */
+ workstations_len, workstations, /* B */
+ unknown_str_len, unknown_str, /* B */
+ munged_dial_len, munged_dial, /* B */
+ user_rid, /* d */
+ group_rid, /* d */
+ lm_pw_len, lm_pw, /* B */
+ nt_pw_len, nt_pw, /* B */
+ nt_pw_hist_len, nt_pw_hist, /* B */
+ pdb_get_acct_ctrl(sampass), /* d */
+ pdb_get_logon_divs(sampass), /* w */
+ pdb_get_hours_len(sampass), /* d */
+ MAX_HOURS_LEN, pdb_get_hours(sampass), /* B */
+ pdb_get_bad_password_count(sampass), /* w */
+ pdb_get_logon_count(sampass), /* w */
+ pdb_get_unknown_6(sampass)); /* d */
+
+ if (size_only) {
+ return buflen;
+ }
+
+ /* malloc the space needed */
+ if ( (*buf=(uint8*)SMB_MALLOC(len)) == NULL) {
+ DEBUG(0,("init_buffer_from_sam_v3: Unable to malloc() memory for buffer!\n"));
+ return (-1);
+ }
+
+ /* now for the real call to tdb_pack() */
+ buflen = tdb_pack(*buf, len, TDB_FORMAT_STRING_V3,
+ logon_time, /* d */
+ logoff_time, /* d */
+ kickoff_time, /* d */
+ bad_password_time, /* d */
+ pass_last_set_time, /* d */
+ pass_can_change_time, /* d */
+ pass_must_change_time, /* d */
+ username_len, username, /* B */
+ domain_len, domain, /* B */
+ nt_username_len, nt_username, /* B */
+ fullname_len, fullname, /* B */
+ homedir_len, homedir, /* B */
+ dir_drive_len, dir_drive, /* B */
+ logon_script_len, logon_script, /* B */
+ profile_path_len, profile_path, /* B */
+ acct_desc_len, acct_desc, /* B */
+ workstations_len, workstations, /* B */
+ unknown_str_len, unknown_str, /* B */
+ munged_dial_len, munged_dial, /* B */
+ user_rid, /* d */
+ group_rid, /* d */
+ lm_pw_len, lm_pw, /* B */
+ nt_pw_len, nt_pw, /* B */
+ nt_pw_hist_len, nt_pw_hist, /* B */
+ pdb_get_acct_ctrl(sampass), /* d */
+ pdb_get_logon_divs(sampass), /* w */
+ pdb_get_hours_len(sampass), /* d */
+ MAX_HOURS_LEN, pdb_get_hours(sampass), /* B */
+ pdb_get_bad_password_count(sampass), /* w */
+ pdb_get_logon_count(sampass), /* w */
+ pdb_get_unknown_6(sampass)); /* d */
+
+ /* check to make sure we got it correct */
+ if (buflen != len) {
+ DEBUG(0, ("init_buffer_from_sam_v3: somthing odd is going on here: bufflen (%lu) != len (%lu) in tdb_pack operations!\n",
+ (unsigned long)buflen, (unsigned long)len));
+ /* error */
+ SAFE_FREE (*buf);
+ return (-1);
+ }
+
+ return (buflen);
+}
+
+
+/*********************************************************************
+*********************************************************************/
+
+bool pdb_copy_sam_account(struct samu *dst, struct samu *src )
+{
+ uint8 *buf = NULL;
+ int len;
+
+ len = init_buffer_from_sam_v3(&buf, src, False);
+ if (len == -1 || !buf) {
+ SAFE_FREE(buf);
+ return False;
+ }
+
+ if (!init_sam_from_buffer_v3( dst, buf, len )) {
+ free(buf);
+ return False;
+ }
+
+ dst->methods = src->methods;
+
+ if ( src->unix_pw ) {
+ dst->unix_pw = tcopy_passwd( dst, src->unix_pw );
+ if (!dst->unix_pw) {
+ free(buf);
+ return False;
+ }
+ }
+
+ free(buf);
+ return True;
+}
+
+/*********************************************************************
+ Update the bad password count checking the AP_RESET_COUNT_TIME
+*********************************************************************/
+
+bool pdb_update_bad_password_count(struct samu *sampass, bool *updated)
+{
+ time_t LastBadPassword;
+ uint16 BadPasswordCount;
+ uint32 resettime;
+ bool res;
+
+ BadPasswordCount = pdb_get_bad_password_count(sampass);
+ if (!BadPasswordCount) {
+ DEBUG(9, ("No bad password attempts.\n"));
+ return True;
+ }
+
+ become_root();
+ res = pdb_get_account_policy(AP_RESET_COUNT_TIME, &resettime);
+ unbecome_root();
+
+ if (!res) {
+ DEBUG(0, ("pdb_update_bad_password_count: pdb_get_account_policy failed.\n"));
+ return False;
+ }
+
+ /* First, check if there is a reset time to compare */
+ if ((resettime == (uint32) -1) || (resettime == 0)) {
+ DEBUG(9, ("No reset time, can't reset bad pw count\n"));
+ return True;
+ }
+
+ LastBadPassword = pdb_get_bad_password_time(sampass);
+ DEBUG(7, ("LastBadPassword=%d, resettime=%d, current time=%d.\n",
+ (uint32) LastBadPassword, resettime, (uint32)time(NULL)));
+ if (time(NULL) > (LastBadPassword + convert_uint32_to_time_t(resettime)*60)){
+ pdb_set_bad_password_count(sampass, 0, PDB_CHANGED);
+ pdb_set_bad_password_time(sampass, 0, PDB_CHANGED);
+ if (updated) {
+ *updated = True;
+ }
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Update the ACB_AUTOLOCK flag checking the AP_LOCK_ACCOUNT_DURATION
+*********************************************************************/
+
+bool pdb_update_autolock_flag(struct samu *sampass, bool *updated)
+{
+ uint32 duration;
+ time_t LastBadPassword;
+ bool res;
+
+ if (!(pdb_get_acct_ctrl(sampass) & ACB_AUTOLOCK)) {
+ DEBUG(9, ("pdb_update_autolock_flag: Account %s not autolocked, no check needed\n",
+ pdb_get_username(sampass)));
+ return True;
+ }
+
+ become_root();
+ res = pdb_get_account_policy(AP_LOCK_ACCOUNT_DURATION, &duration);
+ unbecome_root();
+
+ if (!res) {
+ DEBUG(0, ("pdb_update_autolock_flag: pdb_get_account_policy failed.\n"));
+ return False;
+ }
+
+ /* First, check if there is a duration to compare */
+ if ((duration == (uint32) -1) || (duration == 0)) {
+ DEBUG(9, ("pdb_update_autolock_flag: No reset duration, can't reset autolock\n"));
+ return True;
+ }
+
+ LastBadPassword = pdb_get_bad_password_time(sampass);
+ DEBUG(7, ("pdb_update_autolock_flag: Account %s, LastBadPassword=%d, duration=%d, current time =%d.\n",
+ pdb_get_username(sampass), (uint32)LastBadPassword, duration*60, (uint32)time(NULL)));
+
+ if (LastBadPassword == (time_t)0) {
+ DEBUG(1,("pdb_update_autolock_flag: Account %s "
+ "administratively locked out with no bad password "
+ "time. Leaving locked out.\n",
+ pdb_get_username(sampass) ));
+ return True;
+ }
+
+ if ((time(NULL) > (LastBadPassword + convert_uint32_to_time_t(duration) * 60))) {
+ pdb_set_acct_ctrl(sampass,
+ pdb_get_acct_ctrl(sampass) & ~ACB_AUTOLOCK,
+ PDB_CHANGED);
+ pdb_set_bad_password_count(sampass, 0, PDB_CHANGED);
+ pdb_set_bad_password_time(sampass, 0, PDB_CHANGED);
+ if (updated) {
+ *updated = True;
+ }
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Increment the bad_password_count
+*********************************************************************/
+
+bool pdb_increment_bad_password_count(struct samu *sampass)
+{
+ uint32 account_policy_lockout;
+ bool autolock_updated = False, badpw_updated = False;
+ bool ret;
+
+ /* Retrieve the account lockout policy */
+ become_root();
+ ret = pdb_get_account_policy(AP_BAD_ATTEMPT_LOCKOUT, &account_policy_lockout);
+ unbecome_root();
+ if ( !ret ) {
+ DEBUG(0, ("pdb_increment_bad_password_count: pdb_get_account_policy failed.\n"));
+ return False;
+ }
+
+ /* If there is no policy, we don't need to continue checking */
+ if (!account_policy_lockout) {
+ DEBUG(9, ("No lockout policy, don't track bad passwords\n"));
+ return True;
+ }
+
+ /* Check if the autolock needs to be cleared */
+ if (!pdb_update_autolock_flag(sampass, &autolock_updated))
+ return False;
+
+ /* Check if the badpw count needs to be reset */
+ if (!pdb_update_bad_password_count(sampass, &badpw_updated))
+ return False;
+
+ /*
+ Ok, now we can assume that any resetting that needs to be
+ done has been done, and just get on with incrementing
+ and autolocking if necessary
+ */
+
+ pdb_set_bad_password_count(sampass,
+ pdb_get_bad_password_count(sampass)+1,
+ PDB_CHANGED);
+ pdb_set_bad_password_time(sampass, time(NULL), PDB_CHANGED);
+
+
+ if (pdb_get_bad_password_count(sampass) < account_policy_lockout)
+ return True;
+
+ if (!pdb_set_acct_ctrl(sampass,
+ pdb_get_acct_ctrl(sampass) | ACB_AUTOLOCK,
+ PDB_CHANGED)) {
+ DEBUG(1, ("pdb_increment_bad_password_count:failed to set 'autolock' flag. \n"));
+ return False;
+ }
+
+ return True;
+}
+
+bool is_dc_trusted_domain_situation(const char *domain_name)
+{
+ return IS_DC && !strequal(domain_name, lp_workgroup());
+}
+
+/*******************************************************************
+ Wrapper around retrieving the clear text trust account password.
+ appropriate account name is stored in account_name.
+ Caller must free password, but not account_name.
+*******************************************************************/
+
+bool get_trust_pw_clear(const char *domain, char **ret_pwd,
+ const char **account_name, uint32 *channel)
+{
+ char *pwd;
+ time_t last_set_time;
+
+ /* if we are a DC and this is not our domain, then lookup an account
+ * for the domain trust */
+
+ if (is_dc_trusted_domain_situation(domain)) {
+ if (!lp_allow_trusted_domains()) {
+ return false;
+ }
+
+ if (!pdb_get_trusteddom_pw(domain, ret_pwd, NULL,
+ &last_set_time))
+ {
+ DEBUG(0, ("get_trust_pw: could not fetch trust "
+ "account password for trusted domain %s\n",
+ domain));
+ return false;
+ }
+
+ if (channel != NULL) {
+ *channel = SEC_CHAN_DOMAIN;
+ }
+
+ if (account_name != NULL) {
+ *account_name = lp_workgroup();
+ }
+
+ return true;
+ }
+
+ /*
+ * Since we can only be member of one single domain, we are now
+ * in a member situation:
+ *
+ * - Either we are a DC (selfjoined) and the domain is our
+ * own domain.
+ * - Or we are on a member and the domain is our own or some
+ * other (potentially trusted) domain.
+ *
+ * In both cases, we can only get the machine account password
+ * for our own domain to connect to our own dc. (For a member,
+ * request to trusted domains are performed through our dc.)
+ *
+ * So we simply use our own domain name to retrieve the
+ * machine account passowrd and ignore the request domain here.
+ */
+
+ pwd = secrets_fetch_machine_password(lp_workgroup(), &last_set_time, channel);
+
+ if (pwd != NULL) {
+ *ret_pwd = pwd;
+ if (account_name != NULL) {
+ *account_name = global_myname();
+ }
+
+ return true;
+ }
+
+ DEBUG(5, ("get_trust_pw_clear: could not fetch clear text trust "
+ "account password for domain %s\n", domain));
+ return false;
+}
+
+/*******************************************************************
+ Wrapper around retrieving the trust account password.
+ appropriate account name is stored in account_name.
+*******************************************************************/
+
+bool get_trust_pw_hash(const char *domain, uint8 ret_pwd[16],
+ const char **account_name, uint32 *channel)
+{
+ char *pwd = NULL;
+ time_t last_set_time;
+
+ if (get_trust_pw_clear(domain, &pwd, account_name, channel)) {
+ E_md4hash(pwd, ret_pwd);
+ SAFE_FREE(pwd);
+ return true;
+ } else if (is_dc_trusted_domain_situation(domain)) {
+ return false;
+ }
+
+ /* as a fallback, try to get the hashed pwd directly from the tdb... */
+
+ if (secrets_fetch_trust_account_password_legacy(domain, ret_pwd,
+ &last_set_time,
+ channel))
+ {
+ if (account_name != NULL) {
+ *account_name = global_myname();
+ }
+
+ return true;
+ }
+
+ DEBUG(5, ("get_trust_pw_hash: could not fetch trust account "
+ "password for domain %s\n", domain));
+ return False;
+}
+
+struct samr_LogonHours get_logon_hours_from_pdb(TALLOC_CTX *mem_ctx,
+ struct samu *pw)
+{
+ struct samr_LogonHours hours;
+ const int units_per_week = 168;
+
+ ZERO_STRUCT(hours);
+ hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
+ if (!hours.bits) {
+ return hours;
+ }
+
+ hours.units_per_week = units_per_week;
+ memset(hours.bits, 0xFF, units_per_week);
+
+ if (pdb_get_hours(pw)) {
+ memcpy(hours.bits, pdb_get_hours(pw),
+ MIN(pdb_get_hours_len(pw), units_per_week));
+ }
+
+ return hours;
+}
+
diff --git a/source3/passdb/pdb_compat.c b/source3/passdb/pdb_compat.c
new file mode 100644
index 0000000000..9967eb53ad
--- /dev/null
+++ b/source3/passdb/pdb_compat.c
@@ -0,0 +1,103 @@
+/*
+ Unix SMB/CIFS implementation.
+ struct samu access routines
+ Copyright (C) Jeremy Allison 1996-2001
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Gerald (Jerry) Carter 2000-2001
+ Copyright (C) Andrew Bartlett 2001-2002
+ Copyright (C) Stefan (metze) Metzmacher 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+uint32 pdb_get_user_rid (const struct samu *sampass)
+{
+ uint32 u_rid;
+
+ if (sampass)
+ if (sid_peek_check_rid(get_global_sam_sid(), pdb_get_user_sid(sampass),&u_rid))
+ return u_rid;
+
+ return (0);
+}
+
+uint32 pdb_get_group_rid (struct samu *sampass)
+{
+ uint32 g_rid;
+
+ if (sampass)
+ if (sid_peek_check_rid(get_global_sam_sid(), pdb_get_group_sid(sampass),&g_rid))
+ return g_rid;
+ return (0);
+}
+
+bool pdb_set_user_sid_from_rid (struct samu *sampass, uint32 rid, enum pdb_value_state flag)
+{
+ DOM_SID u_sid;
+ const DOM_SID *global_sam_sid;
+
+ if (!sampass)
+ return False;
+
+ if (!(global_sam_sid = get_global_sam_sid())) {
+ DEBUG(1, ("pdb_set_user_sid_from_rid: Could not read global sam sid!\n"));
+ return False;
+ }
+
+ sid_copy(&u_sid, global_sam_sid);
+
+ if (!sid_append_rid(&u_sid, rid))
+ return False;
+
+ if (!pdb_set_user_sid(sampass, &u_sid, flag))
+ return False;
+
+ DEBUG(10, ("pdb_set_user_sid_from_rid:\n\tsetting user sid %s from rid %d\n",
+ sid_string_dbg(&u_sid),rid));
+
+ return True;
+}
+
+bool pdb_set_group_sid_from_rid (struct samu *sampass, uint32 grid, enum pdb_value_state flag)
+{
+ DOM_SID g_sid;
+ const DOM_SID *global_sam_sid;
+
+ if (!sampass)
+ return False;
+
+ if (!(global_sam_sid = get_global_sam_sid())) {
+ DEBUG(1, ("pdb_set_user_sid_from_rid: Could not read global sam sid!\n"));
+ return False;
+ }
+
+ sid_copy(&g_sid, global_sam_sid);
+
+ if (!sid_append_rid(&g_sid, grid))
+ return False;
+
+ if (!pdb_set_group_sid(sampass, &g_sid, flag))
+ return False;
+
+ DEBUG(10, ("pdb_set_group_sid_from_rid:\n\tsetting group sid %s from rid %d\n",
+ sid_string_dbg(&g_sid), grid));
+
+ return True;
+}
+
diff --git a/source3/passdb/pdb_get_set.c b/source3/passdb/pdb_get_set.c
new file mode 100644
index 0000000000..7a8086c63e
--- /dev/null
+++ b/source3/passdb/pdb_get_set.c
@@ -0,0 +1,1081 @@
+/*
+ Unix SMB/CIFS implementation.
+ struct samu access routines
+ Copyright (C) Jeremy Allison 1996-2001
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Gerald (Jerry) Carter 2000-2006
+ Copyright (C) Andrew Bartlett 2001-2002
+ Copyright (C) Stefan (metze) Metzmacher 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+/**
+ * @todo Redefine this to NULL, but this changes the API because
+ * much of samba assumes that the pdb_get...() funtions
+ * return strings. (ie not null-pointers).
+ * See also pdb_fill_default_sam().
+ */
+
+#define PDB_NOT_QUITE_NULL ""
+
+/*********************************************************************
+ Collection of get...() functions for struct samu.
+ ********************************************************************/
+
+uint32 pdb_get_acct_ctrl(const struct samu *sampass)
+{
+ return sampass->acct_ctrl;
+}
+
+time_t pdb_get_logon_time(const struct samu *sampass)
+{
+ return sampass->logon_time;
+}
+
+time_t pdb_get_logoff_time(const struct samu *sampass)
+{
+ return sampass->logoff_time;
+}
+
+time_t pdb_get_kickoff_time(const struct samu *sampass)
+{
+ return sampass->kickoff_time;
+}
+
+time_t pdb_get_bad_password_time(const struct samu *sampass)
+{
+ return sampass->bad_password_time;
+}
+
+time_t pdb_get_pass_last_set_time(const struct samu *sampass)
+{
+ return sampass->pass_last_set_time;
+}
+
+time_t pdb_get_pass_can_change_time(const struct samu *sampass)
+{
+ uint32 allow;
+
+ /* if the last set time is zero, it means the user cannot
+ change their password, and this time must be zero. jmcd
+ */
+ if (sampass->pass_last_set_time == 0)
+ return (time_t) 0;
+
+ /* if the time is max, and the field has been changed,
+ we're trying to update this real value from the sampass
+ to indicate that the user cannot change their password. jmcd
+ */
+ if (sampass->pass_can_change_time == get_time_t_max() &&
+ pdb_get_init_flags(sampass, PDB_CANCHANGETIME) == PDB_CHANGED)
+ return sampass->pass_can_change_time;
+
+ if (!pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &allow))
+ allow = 0;
+
+ /* in normal cases, just calculate it from policy */
+ return sampass->pass_last_set_time + allow;
+}
+
+/* we need this for loading from the backend, so that we don't overwrite
+ non-changed max times, otherwise the pass_can_change checking won't work */
+time_t pdb_get_pass_can_change_time_noncalc(const struct samu *sampass)
+{
+ return sampass->pass_can_change_time;
+}
+
+time_t pdb_get_pass_must_change_time(const struct samu *sampass)
+{
+ uint32 expire;
+
+ if (sampass->pass_last_set_time == 0)
+ return (time_t) 0;
+
+ if (sampass->acct_ctrl & ACB_PWNOEXP)
+ return get_time_t_max();
+
+ if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &expire)
+ || expire == (uint32)-1 || expire == 0)
+ return get_time_t_max();
+
+ return sampass->pass_last_set_time + expire;
+}
+
+bool pdb_get_pass_can_change(const struct samu *sampass)
+{
+ if (sampass->pass_can_change_time == get_time_t_max() &&
+ sampass->pass_last_set_time != 0)
+ return False;
+ return True;
+}
+
+uint16 pdb_get_logon_divs(const struct samu *sampass)
+{
+ return sampass->logon_divs;
+}
+
+uint32 pdb_get_hours_len(const struct samu *sampass)
+{
+ return sampass->hours_len;
+}
+
+const uint8 *pdb_get_hours(const struct samu *sampass)
+{
+ return (sampass->hours);
+}
+
+const uint8 *pdb_get_nt_passwd(const struct samu *sampass)
+{
+ SMB_ASSERT((!sampass->nt_pw.data)
+ || sampass->nt_pw.length == NT_HASH_LEN);
+ return (uint8 *)sampass->nt_pw.data;
+}
+
+const uint8 *pdb_get_lanman_passwd(const struct samu *sampass)
+{
+ SMB_ASSERT((!sampass->lm_pw.data)
+ || sampass->lm_pw.length == LM_HASH_LEN);
+ return (uint8 *)sampass->lm_pw.data;
+}
+
+const uint8 *pdb_get_pw_history(const struct samu *sampass, uint32 *current_hist_len)
+{
+ SMB_ASSERT((!sampass->nt_pw_his.data)
+ || ((sampass->nt_pw_his.length % PW_HISTORY_ENTRY_LEN) == 0));
+ *current_hist_len = sampass->nt_pw_his.length / PW_HISTORY_ENTRY_LEN;
+ return (uint8 *)sampass->nt_pw_his.data;
+}
+
+/* Return the plaintext password if known. Most of the time
+ it isn't, so don't assume anything magic about this function.
+
+ Used to pass the plaintext to passdb backends that might
+ want to store more than just the NTLM hashes.
+*/
+const char *pdb_get_plaintext_passwd(const struct samu *sampass)
+{
+ return sampass->plaintext_pw;
+}
+
+const DOM_SID *pdb_get_user_sid(const struct samu *sampass)
+{
+ return &sampass->user_sid;
+}
+
+const DOM_SID *pdb_get_group_sid(struct samu *sampass)
+{
+ DOM_SID *gsid;
+ struct passwd *pwd;
+
+ /* Return the cached group SID if we have that */
+ if ( sampass->group_sid ) {
+ return sampass->group_sid;
+ }
+
+ /* generate the group SID from the user's primary Unix group */
+
+ if ( !(gsid = TALLOC_P( sampass, DOM_SID )) ) {
+ return NULL;
+ }
+
+ /* No algorithmic mapping, meaning that we have to figure out the
+ primary group SID according to group mapping and the user SID must
+ be a newly allocated one. We rely on the user's Unix primary gid.
+ We have no choice but to fail if we can't find it. */
+
+ if ( sampass->unix_pw ) {
+ pwd = sampass->unix_pw;
+ } else {
+ pwd = Get_Pwnam_alloc( sampass, pdb_get_username(sampass) );
+ }
+
+ if ( !pwd ) {
+ DEBUG(0,("pdb_get_group_sid: Failed to find Unix account for %s\n", pdb_get_username(sampass) ));
+ return NULL;
+ }
+
+ if ( pdb_gid_to_sid(pwd->pw_gid, gsid) ) {
+ enum lsa_SidType type = SID_NAME_UNKNOWN;
+ TALLOC_CTX *mem_ctx = talloc_init("pdb_get_group_sid");
+ bool lookup_ret;
+
+ if (!mem_ctx) {
+ return NULL;
+ }
+
+ /* Now check that it's actually a domain group and not something else */
+
+ lookup_ret = lookup_sid(mem_ctx, gsid, NULL, NULL, &type);
+
+ TALLOC_FREE( mem_ctx );
+
+ if ( lookup_ret && (type == SID_NAME_DOM_GRP) ) {
+ sampass->group_sid = gsid;
+ return sampass->group_sid;
+ }
+
+ DEBUG(3, ("Primary group for user %s is a %s and not a domain group\n",
+ pwd->pw_name, sid_type_lookup(type)));
+ }
+
+ /* Just set it to the 'Domain Users' RID of 512 which will
+ always resolve to a name */
+
+ sid_copy( gsid, get_global_sam_sid() );
+ sid_append_rid( gsid, DOMAIN_GROUP_RID_USERS );
+
+ sampass->group_sid = gsid;
+
+ return sampass->group_sid;
+}
+
+/**
+ * Get flags showing what is initalised in the struct samu
+ * @param sampass the struct samu in question
+ * @return the flags indicating the members initialised in the struct.
+ **/
+
+enum pdb_value_state pdb_get_init_flags(const struct samu *sampass, enum pdb_elements element)
+{
+ enum pdb_value_state ret = PDB_DEFAULT;
+
+ if (!sampass->change_flags || !sampass->set_flags)
+ return ret;
+
+ if (bitmap_query(sampass->set_flags, element)) {
+ DEBUG(11, ("element %d: SET\n", element));
+ ret = PDB_SET;
+ }
+
+ if (bitmap_query(sampass->change_flags, element)) {
+ DEBUG(11, ("element %d: CHANGED\n", element));
+ ret = PDB_CHANGED;
+ }
+
+ if (ret == PDB_DEFAULT) {
+ DEBUG(11, ("element %d: DEFAULT\n", element));
+ }
+
+ return ret;
+}
+
+const char *pdb_get_username(const struct samu *sampass)
+{
+ return sampass->username;
+}
+
+const char *pdb_get_domain(const struct samu *sampass)
+{
+ return sampass->domain;
+}
+
+const char *pdb_get_nt_username(const struct samu *sampass)
+{
+ return sampass->nt_username;
+}
+
+const char *pdb_get_fullname(const struct samu *sampass)
+{
+ return sampass->full_name;
+}
+
+const char *pdb_get_homedir(const struct samu *sampass)
+{
+ return sampass->home_dir;
+}
+
+const char *pdb_get_dir_drive(const struct samu *sampass)
+{
+ return sampass->dir_drive;
+}
+
+const char *pdb_get_logon_script(const struct samu *sampass)
+{
+ return sampass->logon_script;
+}
+
+const char *pdb_get_profile_path(const struct samu *sampass)
+{
+ return sampass->profile_path;
+}
+
+const char *pdb_get_acct_desc(const struct samu *sampass)
+{
+ return sampass->acct_desc;
+}
+
+const char *pdb_get_workstations(const struct samu *sampass)
+{
+ return sampass->workstations;
+}
+
+const char *pdb_get_comment(const struct samu *sampass)
+{
+ return sampass->comment;
+}
+
+const char *pdb_get_munged_dial(const struct samu *sampass)
+{
+ return sampass->munged_dial;
+}
+
+uint16 pdb_get_bad_password_count(const struct samu *sampass)
+{
+ return sampass->bad_password_count;
+}
+
+uint16 pdb_get_logon_count(const struct samu *sampass)
+{
+ return sampass->logon_count;
+}
+
+uint32 pdb_get_unknown_6(const struct samu *sampass)
+{
+ return sampass->unknown_6;
+}
+
+void *pdb_get_backend_private_data(const struct samu *sampass, const struct pdb_methods *my_methods)
+{
+ if (my_methods == sampass->backend_private_methods) {
+ return sampass->backend_private_data;
+ } else {
+ return NULL;
+ }
+}
+
+/*********************************************************************
+ Collection of set...() functions for struct samu.
+ ********************************************************************/
+
+bool pdb_set_acct_ctrl(struct samu *sampass, uint32 acct_ctrl, enum pdb_value_state flag)
+{
+ sampass->acct_ctrl = acct_ctrl;
+ return pdb_set_init_flags(sampass, PDB_ACCTCTRL, flag);
+}
+
+bool pdb_set_logon_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag)
+{
+ sampass->logon_time = mytime;
+ return pdb_set_init_flags(sampass, PDB_LOGONTIME, flag);
+}
+
+bool pdb_set_logoff_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag)
+{
+ sampass->logoff_time = mytime;
+ return pdb_set_init_flags(sampass, PDB_LOGOFFTIME, flag);
+}
+
+bool pdb_set_kickoff_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag)
+{
+ sampass->kickoff_time = mytime;
+ return pdb_set_init_flags(sampass, PDB_KICKOFFTIME, flag);
+}
+
+bool pdb_set_bad_password_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag)
+{
+ sampass->bad_password_time = mytime;
+ return pdb_set_init_flags(sampass, PDB_BAD_PASSWORD_TIME, flag);
+}
+
+bool pdb_set_pass_can_change_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag)
+{
+ sampass->pass_can_change_time = mytime;
+ return pdb_set_init_flags(sampass, PDB_CANCHANGETIME, flag);
+}
+
+bool pdb_set_pass_must_change_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag)
+{
+ sampass->pass_must_change_time = mytime;
+ return pdb_set_init_flags(sampass, PDB_MUSTCHANGETIME, flag);
+}
+
+bool pdb_set_pass_last_set_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag)
+{
+ sampass->pass_last_set_time = mytime;
+ return pdb_set_init_flags(sampass, PDB_PASSLASTSET, flag);
+}
+
+bool pdb_set_hours_len(struct samu *sampass, uint32 len, enum pdb_value_state flag)
+{
+ sampass->hours_len = len;
+ return pdb_set_init_flags(sampass, PDB_HOURSLEN, flag);
+}
+
+bool pdb_set_logon_divs(struct samu *sampass, uint16 hours, enum pdb_value_state flag)
+{
+ sampass->logon_divs = hours;
+ return pdb_set_init_flags(sampass, PDB_LOGONDIVS, flag);
+}
+
+/**
+ * Set flags showing what is initalised in the struct samu
+ * @param sampass the struct samu in question
+ * @param flag The *new* flag to be set. Old flags preserved
+ * this flag is only added.
+ **/
+
+bool pdb_set_init_flags(struct samu *sampass, enum pdb_elements element, enum pdb_value_state value_flag)
+{
+ if (!sampass->set_flags) {
+ if ((sampass->set_flags =
+ bitmap_talloc(sampass,
+ PDB_COUNT))==NULL) {
+ DEBUG(0,("bitmap_talloc failed\n"));
+ return False;
+ }
+ }
+ if (!sampass->change_flags) {
+ if ((sampass->change_flags =
+ bitmap_talloc(sampass,
+ PDB_COUNT))==NULL) {
+ DEBUG(0,("bitmap_talloc failed\n"));
+ return False;
+ }
+ }
+
+ switch(value_flag) {
+ case PDB_CHANGED:
+ if (!bitmap_set(sampass->change_flags, element)) {
+ DEBUG(0,("Can't set flag: %d in change_flags.\n",element));
+ return False;
+ }
+ if (!bitmap_set(sampass->set_flags, element)) {
+ DEBUG(0,("Can't set flag: %d in set_flags.\n",element));
+ return False;
+ }
+ DEBUG(11, ("element %d -> now CHANGED\n", element));
+ break;
+ case PDB_SET:
+ if (!bitmap_clear(sampass->change_flags, element)) {
+ DEBUG(0,("Can't set flag: %d in change_flags.\n",element));
+ return False;
+ }
+ if (!bitmap_set(sampass->set_flags, element)) {
+ DEBUG(0,("Can't set flag: %d in set_flags.\n",element));
+ return False;
+ }
+ DEBUG(11, ("element %d -> now SET\n", element));
+ break;
+ case PDB_DEFAULT:
+ default:
+ if (!bitmap_clear(sampass->change_flags, element)) {
+ DEBUG(0,("Can't set flag: %d in change_flags.\n",element));
+ return False;
+ }
+ if (!bitmap_clear(sampass->set_flags, element)) {
+ DEBUG(0,("Can't set flag: %d in set_flags.\n",element));
+ return False;
+ }
+ DEBUG(11, ("element %d -> now DEFAULT\n", element));
+ break;
+ }
+
+ return True;
+}
+
+bool pdb_set_user_sid(struct samu *sampass, const DOM_SID *u_sid, enum pdb_value_state flag)
+{
+ if (!u_sid)
+ return False;
+
+ sid_copy(&sampass->user_sid, u_sid);
+
+ DEBUG(10, ("pdb_set_user_sid: setting user sid %s\n",
+ sid_string_dbg(&sampass->user_sid)));
+
+ return pdb_set_init_flags(sampass, PDB_USERSID, flag);
+}
+
+bool pdb_set_user_sid_from_string(struct samu *sampass, fstring u_sid, enum pdb_value_state flag)
+{
+ DOM_SID new_sid;
+
+ if (!u_sid)
+ return False;
+
+ DEBUG(10, ("pdb_set_user_sid_from_string: setting user sid %s\n",
+ u_sid));
+
+ if (!string_to_sid(&new_sid, u_sid)) {
+ DEBUG(1, ("pdb_set_user_sid_from_string: %s isn't a valid SID!\n", u_sid));
+ return False;
+ }
+
+ if (!pdb_set_user_sid(sampass, &new_sid, flag)) {
+ DEBUG(1, ("pdb_set_user_sid_from_string: could not set sid %s on struct samu!\n", u_sid));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ We never fill this in from a passdb backend but rather set is
+ based on the user's primary group membership. However, the
+ struct samu* is overloaded and reused in domain memship code
+ as well and built from the netr_SamInfo3 or PAC so we
+ have to allow the explicitly setting of a group SID here.
+********************************************************************/
+
+bool pdb_set_group_sid(struct samu *sampass, const DOM_SID *g_sid, enum pdb_value_state flag)
+{
+ gid_t gid;
+
+ if (!g_sid)
+ return False;
+
+ if ( !(sampass->group_sid = TALLOC_P( sampass, DOM_SID )) ) {
+ return False;
+ }
+
+ /* if we cannot resolve the SID to gid, then just ignore it and
+ store DOMAIN_USERS as the primary groupSID */
+
+ if ( sid_to_gid( g_sid, &gid ) ) {
+ sid_copy(sampass->group_sid, g_sid);
+ } else {
+ sid_copy( sampass->group_sid, get_global_sam_sid() );
+ sid_append_rid( sampass->group_sid, DOMAIN_GROUP_RID_USERS );
+ }
+
+ DEBUG(10, ("pdb_set_group_sid: setting group sid %s\n",
+ sid_string_dbg(sampass->group_sid)));
+
+ return pdb_set_init_flags(sampass, PDB_GROUPSID, flag);
+}
+
+/*********************************************************************
+ Set the user's UNIX name.
+ ********************************************************************/
+
+bool pdb_set_username(struct samu *sampass, const char *username, enum pdb_value_state flag)
+{
+ if (username) {
+ DEBUG(10, ("pdb_set_username: setting username %s, was %s\n", username,
+ (sampass->username)?(sampass->username):"NULL"));
+
+ sampass->username = talloc_strdup(sampass, username);
+
+ if (!sampass->username) {
+ DEBUG(0, ("pdb_set_username: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->username = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_USERNAME, flag);
+}
+
+/*********************************************************************
+ Set the domain name.
+ ********************************************************************/
+
+bool pdb_set_domain(struct samu *sampass, const char *domain, enum pdb_value_state flag)
+{
+ if (domain) {
+ DEBUG(10, ("pdb_set_domain: setting domain %s, was %s\n", domain,
+ (sampass->domain)?(sampass->domain):"NULL"));
+
+ sampass->domain = talloc_strdup(sampass, domain);
+
+ if (!sampass->domain) {
+ DEBUG(0, ("pdb_set_domain: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->domain = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_DOMAIN, flag);
+}
+
+/*********************************************************************
+ Set the user's NT name.
+ ********************************************************************/
+
+bool pdb_set_nt_username(struct samu *sampass, const char *nt_username, enum pdb_value_state flag)
+{
+ if (nt_username) {
+ DEBUG(10, ("pdb_set_nt_username: setting nt username %s, was %s\n", nt_username,
+ (sampass->nt_username)?(sampass->nt_username):"NULL"));
+
+ sampass->nt_username = talloc_strdup(sampass, nt_username);
+
+ if (!sampass->nt_username) {
+ DEBUG(0, ("pdb_set_nt_username: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->nt_username = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_NTUSERNAME, flag);
+}
+
+/*********************************************************************
+ Set the user's full name.
+ ********************************************************************/
+
+bool pdb_set_fullname(struct samu *sampass, const char *full_name, enum pdb_value_state flag)
+{
+ if (full_name) {
+ DEBUG(10, ("pdb_set_full_name: setting full name %s, was %s\n", full_name,
+ (sampass->full_name)?(sampass->full_name):"NULL"));
+
+ sampass->full_name = talloc_strdup(sampass, full_name);
+
+ if (!sampass->full_name) {
+ DEBUG(0, ("pdb_set_fullname: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->full_name = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_FULLNAME, flag);
+}
+
+/*********************************************************************
+ Set the user's logon script.
+ ********************************************************************/
+
+bool pdb_set_logon_script(struct samu *sampass, const char *logon_script, enum pdb_value_state flag)
+{
+ if (logon_script) {
+ DEBUG(10, ("pdb_set_logon_script: setting logon script %s, was %s\n", logon_script,
+ (sampass->logon_script)?(sampass->logon_script):"NULL"));
+
+ sampass->logon_script = talloc_strdup(sampass, logon_script);
+
+ if (!sampass->logon_script) {
+ DEBUG(0, ("pdb_set_logon_script: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->logon_script = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_LOGONSCRIPT, flag);
+}
+
+/*********************************************************************
+ Set the user's profile path.
+ ********************************************************************/
+
+bool pdb_set_profile_path(struct samu *sampass, const char *profile_path, enum pdb_value_state flag)
+{
+ if (profile_path) {
+ DEBUG(10, ("pdb_set_profile_path: setting profile path %s, was %s\n", profile_path,
+ (sampass->profile_path)?(sampass->profile_path):"NULL"));
+
+ sampass->profile_path = talloc_strdup(sampass, profile_path);
+
+ if (!sampass->profile_path) {
+ DEBUG(0, ("pdb_set_profile_path: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->profile_path = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_PROFILE, flag);
+}
+
+/*********************************************************************
+ Set the user's directory drive.
+ ********************************************************************/
+
+bool pdb_set_dir_drive(struct samu *sampass, const char *dir_drive, enum pdb_value_state flag)
+{
+ if (dir_drive) {
+ DEBUG(10, ("pdb_set_dir_drive: setting dir drive %s, was %s\n", dir_drive,
+ (sampass->dir_drive)?(sampass->dir_drive):"NULL"));
+
+ sampass->dir_drive = talloc_strdup(sampass, dir_drive);
+
+ if (!sampass->dir_drive) {
+ DEBUG(0, ("pdb_set_dir_drive: talloc_strdup() failed!\n"));
+ return False;
+ }
+
+ } else {
+ sampass->dir_drive = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_DRIVE, flag);
+}
+
+/*********************************************************************
+ Set the user's home directory.
+ ********************************************************************/
+
+bool pdb_set_homedir(struct samu *sampass, const char *home_dir, enum pdb_value_state flag)
+{
+ if (home_dir) {
+ DEBUG(10, ("pdb_set_homedir: setting home dir %s, was %s\n", home_dir,
+ (sampass->home_dir)?(sampass->home_dir):"NULL"));
+
+ sampass->home_dir = talloc_strdup(sampass, home_dir);
+
+ if (!sampass->home_dir) {
+ DEBUG(0, ("pdb_set_home_dir: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->home_dir = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_SMBHOME, flag);
+}
+
+/*********************************************************************
+ Set the user's account description.
+ ********************************************************************/
+
+bool pdb_set_acct_desc(struct samu *sampass, const char *acct_desc, enum pdb_value_state flag)
+{
+ if (acct_desc) {
+ sampass->acct_desc = talloc_strdup(sampass, acct_desc);
+
+ if (!sampass->acct_desc) {
+ DEBUG(0, ("pdb_set_acct_desc: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->acct_desc = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_ACCTDESC, flag);
+}
+
+/*********************************************************************
+ Set the user's workstation allowed list.
+ ********************************************************************/
+
+bool pdb_set_workstations(struct samu *sampass, const char *workstations, enum pdb_value_state flag)
+{
+ if (workstations) {
+ DEBUG(10, ("pdb_set_workstations: setting workstations %s, was %s\n", workstations,
+ (sampass->workstations)?(sampass->workstations):"NULL"));
+
+ sampass->workstations = talloc_strdup(sampass, workstations);
+
+ if (!sampass->workstations) {
+ DEBUG(0, ("pdb_set_workstations: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->workstations = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_WORKSTATIONS, flag);
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+bool pdb_set_comment(struct samu *sampass, const char *comment, enum pdb_value_state flag)
+{
+ if (comment) {
+ sampass->comment = talloc_strdup(sampass, comment);
+
+ if (!sampass->comment) {
+ DEBUG(0, ("pdb_set_comment: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->comment = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_COMMENT, flag);
+}
+
+/*********************************************************************
+ Set the user's dial string.
+ ********************************************************************/
+
+bool pdb_set_munged_dial(struct samu *sampass, const char *munged_dial, enum pdb_value_state flag)
+{
+ if (munged_dial) {
+ sampass->munged_dial = talloc_strdup(sampass, munged_dial);
+
+ if (!sampass->munged_dial) {
+ DEBUG(0, ("pdb_set_munged_dial: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->munged_dial = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_MUNGEDDIAL, flag);
+}
+
+/*********************************************************************
+ Set the user's NT hash.
+ ********************************************************************/
+
+bool pdb_set_nt_passwd(struct samu *sampass, const uint8 pwd[NT_HASH_LEN], enum pdb_value_state flag)
+{
+ data_blob_clear_free(&sampass->nt_pw);
+
+ if (pwd) {
+ sampass->nt_pw =
+ data_blob_talloc(sampass, pwd, NT_HASH_LEN);
+ } else {
+ sampass->nt_pw = data_blob_null;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_NTPASSWD, flag);
+}
+
+/*********************************************************************
+ Set the user's LM hash.
+ ********************************************************************/
+
+bool pdb_set_lanman_passwd(struct samu *sampass, const uint8 pwd[LM_HASH_LEN], enum pdb_value_state flag)
+{
+ data_blob_clear_free(&sampass->lm_pw);
+
+ /* on keep the password if we are allowing LANMAN authentication */
+
+ if (pwd && lp_lanman_auth() ) {
+ sampass->lm_pw = data_blob_talloc(sampass, pwd, LM_HASH_LEN);
+ } else {
+ sampass->lm_pw = data_blob_null;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_LMPASSWD, flag);
+}
+
+/*********************************************************************
+ Set the user's password history hash. historyLen is the number of
+ PW_HISTORY_SALT_LEN+SALTED_MD5_HASH_LEN length
+ entries to store in the history - this must match the size of the uint8 array
+ in pwd.
+********************************************************************/
+
+bool pdb_set_pw_history(struct samu *sampass, const uint8 *pwd, uint32 historyLen, enum pdb_value_state flag)
+{
+ if (historyLen && pwd){
+ sampass->nt_pw_his = data_blob_talloc(sampass,
+ pwd, historyLen*PW_HISTORY_ENTRY_LEN);
+ if (!sampass->nt_pw_his.length) {
+ DEBUG(0, ("pdb_set_pw_history: data_blob_talloc() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->nt_pw_his = data_blob_talloc(sampass, NULL, 0);
+ }
+
+ return pdb_set_init_flags(sampass, PDB_PWHISTORY, flag);
+}
+
+/*********************************************************************
+ Set the user's plaintext password only (base procedure, see helper
+ below)
+ ********************************************************************/
+
+bool pdb_set_plaintext_pw_only(struct samu *sampass, const char *password, enum pdb_value_state flag)
+{
+ if (password) {
+ if (sampass->plaintext_pw!=NULL)
+ memset(sampass->plaintext_pw,'\0',strlen(sampass->plaintext_pw)+1);
+
+ sampass->plaintext_pw = talloc_strdup(sampass, password);
+
+ if (!sampass->plaintext_pw) {
+ DEBUG(0, ("pdb_set_unknown_str: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->plaintext_pw = NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_PLAINTEXT_PW, flag);
+}
+
+bool pdb_set_bad_password_count(struct samu *sampass, uint16 bad_password_count, enum pdb_value_state flag)
+{
+ sampass->bad_password_count = bad_password_count;
+ return pdb_set_init_flags(sampass, PDB_BAD_PASSWORD_COUNT, flag);
+}
+
+bool pdb_set_logon_count(struct samu *sampass, uint16 logon_count, enum pdb_value_state flag)
+{
+ sampass->logon_count = logon_count;
+ return pdb_set_init_flags(sampass, PDB_LOGON_COUNT, flag);
+}
+
+bool pdb_set_unknown_6(struct samu *sampass, uint32 unkn, enum pdb_value_state flag)
+{
+ sampass->unknown_6 = unkn;
+ return pdb_set_init_flags(sampass, PDB_UNKNOWN6, flag);
+}
+
+bool pdb_set_hours(struct samu *sampass, const uint8 *hours, enum pdb_value_state flag)
+{
+ if (!hours) {
+ memset ((char *)sampass->hours, 0, MAX_HOURS_LEN);
+ } else {
+ memcpy (sampass->hours, hours, MAX_HOURS_LEN);
+ }
+
+ return pdb_set_init_flags(sampass, PDB_HOURS, flag);
+}
+
+bool pdb_set_backend_private_data(struct samu *sampass, void *private_data,
+ void (*free_fn)(void **),
+ const struct pdb_methods *my_methods,
+ enum pdb_value_state flag)
+{
+ if (sampass->backend_private_data &&
+ sampass->backend_private_data_free_fn) {
+ sampass->backend_private_data_free_fn(
+ &sampass->backend_private_data);
+ }
+
+ sampass->backend_private_data = private_data;
+ sampass->backend_private_data_free_fn = free_fn;
+ sampass->backend_private_methods = my_methods;
+
+ return pdb_set_init_flags(sampass, PDB_BACKEND_PRIVATE_DATA, flag);
+}
+
+
+/* Helpful interfaces to the above */
+
+bool pdb_set_pass_can_change(struct samu *sampass, bool canchange)
+{
+ return pdb_set_pass_can_change_time(sampass,
+ canchange ? 0 : get_time_t_max(),
+ PDB_CHANGED);
+}
+
+
+/*********************************************************************
+ Set the user's PLAINTEXT password. Used as an interface to the above.
+ Also sets the last change time to NOW.
+ ********************************************************************/
+
+bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext)
+{
+ uchar new_lanman_p16[LM_HASH_LEN];
+ uchar new_nt_p16[NT_HASH_LEN];
+
+ if (!plaintext)
+ return False;
+
+ /* Calculate the MD4 hash (NT compatible) of the password */
+ E_md4hash(plaintext, new_nt_p16);
+
+ if (!pdb_set_nt_passwd (sampass, new_nt_p16, PDB_CHANGED))
+ return False;
+
+ if (!E_deshash(plaintext, new_lanman_p16)) {
+ /* E_deshash returns false for 'long' passwords (> 14
+ DOS chars). This allows us to match Win2k, which
+ does not store a LM hash for these passwords (which
+ would reduce the effective password length to 14 */
+
+ if (!pdb_set_lanman_passwd (sampass, NULL, PDB_CHANGED))
+ return False;
+ } else {
+ if (!pdb_set_lanman_passwd (sampass, new_lanman_p16, PDB_CHANGED))
+ return False;
+ }
+
+ if (!pdb_set_plaintext_pw_only (sampass, plaintext, PDB_CHANGED))
+ return False;
+
+ if (!pdb_set_pass_last_set_time (sampass, time(NULL), PDB_CHANGED))
+ return False;
+
+ /* Store the password history. */
+ if (pdb_get_acct_ctrl(sampass) & ACB_NORMAL) {
+ uchar *pwhistory;
+ uint32 pwHistLen;
+ pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen);
+ if (pwHistLen != 0){
+ uint32 current_history_len;
+ /* We need to make sure we don't have a race condition here - the
+ account policy history length can change between when the pw_history
+ was first loaded into the struct samu struct and now.... JRA. */
+ pwhistory = (uchar *)pdb_get_pw_history(sampass, &current_history_len);
+
+ if (current_history_len != pwHistLen) {
+ /* After closing and reopening struct samu the history
+ values will sync up. We can't do this here. */
+
+ /* current_history_len > pwHistLen is not a problem - we
+ have more history than we need. */
+
+ if (current_history_len < pwHistLen) {
+ /* Ensure we have space for the needed history. */
+ uchar *new_history = (uchar *)TALLOC(sampass,
+ pwHistLen*PW_HISTORY_ENTRY_LEN);
+ if (!new_history) {
+ return False;
+ }
+
+ /* And copy it into the new buffer. */
+ if (current_history_len) {
+ memcpy(new_history, pwhistory,
+ current_history_len*PW_HISTORY_ENTRY_LEN);
+ }
+ /* Clearing out any extra space. */
+ memset(&new_history[current_history_len*PW_HISTORY_ENTRY_LEN],
+ '\0', (pwHistLen-current_history_len)*PW_HISTORY_ENTRY_LEN);
+ /* Finally replace it. */
+ pwhistory = new_history;
+ }
+ }
+ if (pwhistory && pwHistLen){
+ /* Make room for the new password in the history list. */
+ if (pwHistLen > 1) {
+ memmove(&pwhistory[PW_HISTORY_ENTRY_LEN],
+ pwhistory, (pwHistLen -1)*PW_HISTORY_ENTRY_LEN );
+ }
+ /* Create the new salt as the first part of the history entry. */
+ generate_random_buffer(pwhistory, PW_HISTORY_SALT_LEN);
+
+ /* Generate the md5 hash of the salt+new password as the second
+ part of the history entry. */
+
+ E_md5hash(pwhistory, new_nt_p16, &pwhistory[PW_HISTORY_SALT_LEN]);
+ pdb_set_pw_history(sampass, pwhistory, pwHistLen, PDB_CHANGED);
+ } else {
+ DEBUG (10,("pdb_get_set.c: pdb_set_plaintext_passwd: pwhistory was NULL!\n"));
+ }
+ } else {
+ /* Set the history length to zero. */
+ pdb_set_pw_history(sampass, NULL, 0, PDB_CHANGED);
+ }
+ }
+
+ return True;
+}
+
+/* check for any PDB_SET/CHANGED field and fill the appropriate mask bit */
+uint32 pdb_build_fields_present(struct samu *sampass)
+{
+ /* value set to all for testing */
+ return 0x00ffffff;
+}
diff --git a/source3/passdb/pdb_interface.c b/source3/passdb/pdb_interface.c
new file mode 100644
index 0000000000..2a1024cc56
--- /dev/null
+++ b/source3/passdb/pdb_interface.c
@@ -0,0 +1,2071 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Jelmer Vernooij 2002
+ Copyright (C) Simo Sorce 2003
+ Copyright (C) Volker Lendecke 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+static_decl_pdb;
+
+static struct pdb_init_function_entry *backends = NULL;
+
+static void lazy_initialize_passdb(void)
+{
+ static bool initialized = False;
+ if(initialized) {
+ return;
+ }
+ static_init_pdb;
+ initialized = True;
+}
+
+static bool lookup_global_sam_rid(TALLOC_CTX *mem_ctx, uint32 rid,
+ const char **name,
+ enum lsa_SidType *psid_name_use,
+ union unid_t *unix_id);
+
+NTSTATUS smb_register_passdb(int version, const char *name, pdb_init_function init)
+{
+ struct pdb_init_function_entry *entry = backends;
+
+ if(version != PASSDB_INTERFACE_VERSION) {
+ DEBUG(0,("Can't register passdb backend!\n"
+ "You tried to register a passdb module with PASSDB_INTERFACE_VERSION %d, "
+ "while this version of samba uses version %d\n",
+ version,PASSDB_INTERFACE_VERSION));
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ if (!name || !init) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ DEBUG(5,("Attempting to register passdb backend %s\n", name));
+
+ /* Check for duplicates */
+ if (pdb_find_backend_entry(name)) {
+ DEBUG(0,("There already is a passdb backend registered with the name %s!\n", name));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ entry = SMB_XMALLOC_P(struct pdb_init_function_entry);
+ entry->name = smb_xstrdup(name);
+ entry->init = init;
+
+ DLIST_ADD(backends, entry);
+ DEBUG(5,("Successfully added passdb backend '%s'\n", name));
+ return NT_STATUS_OK;
+}
+
+struct pdb_init_function_entry *pdb_find_backend_entry(const char *name)
+{
+ struct pdb_init_function_entry *entry = backends;
+
+ while(entry) {
+ if (strcmp(entry->name, name)==0) return entry;
+ entry = entry->next;
+ }
+
+ return NULL;
+}
+
+/*
+ * The event context for the passdb backend. I know this is a bad hack and yet
+ * another static variable, but our pdb API is a global thing per
+ * definition. The first use for this is the LDAP idle function, more might be
+ * added later.
+ *
+ * I don't feel too bad about this static variable, it replaces the
+ * smb_idle_event_list that used to exist in lib/module.c. -- VL
+ */
+
+static struct event_context *pdb_event_ctx;
+
+struct event_context *pdb_get_event_context(void)
+{
+ return pdb_event_ctx;
+}
+
+/******************************************************************
+ Make a pdb_methods from scratch
+ *******************************************************************/
+
+NTSTATUS make_pdb_method_name(struct pdb_methods **methods, const char *selected)
+{
+ char *module_name = smb_xstrdup(selected);
+ char *module_location = NULL, *p;
+ struct pdb_init_function_entry *entry;
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+
+ lazy_initialize_passdb();
+
+ p = strchr(module_name, ':');
+
+ if (p) {
+ *p = 0;
+ module_location = p+1;
+ trim_char(module_location, ' ', ' ');
+ }
+
+ trim_char(module_name, ' ', ' ');
+
+
+ DEBUG(5,("Attempting to find a passdb backend to match %s (%s)\n", selected, module_name));
+
+ entry = pdb_find_backend_entry(module_name);
+
+ /* Try to find a module that contains this module */
+ if (!entry) {
+ DEBUG(2,("No builtin backend found, trying to load plugin\n"));
+ if(NT_STATUS_IS_OK(smb_probe_module("pdb", module_name)) && !(entry = pdb_find_backend_entry(module_name))) {
+ DEBUG(0,("Plugin is available, but doesn't register passdb backend %s\n", module_name));
+ SAFE_FREE(module_name);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ /* No such backend found */
+ if(!entry) {
+ DEBUG(0,("No builtin nor plugin backend for %s found\n", module_name));
+ SAFE_FREE(module_name);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ DEBUG(5,("Found pdb backend %s\n", module_name));
+
+ if ( !NT_STATUS_IS_OK( nt_status = entry->init(methods, module_location) ) ) {
+ DEBUG(0,("pdb backend %s did not correctly init (error was %s)\n",
+ selected, nt_errstr(nt_status)));
+ SAFE_FREE(module_name);
+ return nt_status;
+ }
+
+ SAFE_FREE(module_name);
+
+ DEBUG(5,("pdb backend %s has a valid init\n", selected));
+
+ return nt_status;
+}
+
+/******************************************************************
+ Return an already initialized pdb_methods structure
+*******************************************************************/
+
+static struct pdb_methods *pdb_get_methods_reload( bool reload )
+{
+ static struct pdb_methods *pdb = NULL;
+
+ if ( pdb && reload ) {
+ pdb->free_private_data( &(pdb->private_data) );
+ if ( !NT_STATUS_IS_OK( make_pdb_method_name( &pdb, lp_passdb_backend() ) ) ) {
+ char *msg = NULL;
+ asprintf(&msg, "pdb_get_methods_reload: "
+ "failed to get pdb methods for backend %s\n",
+ lp_passdb_backend());
+ smb_panic(msg);
+ }
+ }
+
+ if ( !pdb ) {
+ if ( !NT_STATUS_IS_OK( make_pdb_method_name( &pdb, lp_passdb_backend() ) ) ) {
+ char *msg = NULL;
+ asprintf(&msg, "pdb_get_methods_reload: "
+ "failed to get pdb methods for backend %s\n",
+ lp_passdb_backend());
+ smb_panic(msg);
+ }
+ }
+
+ return pdb;
+}
+
+static struct pdb_methods *pdb_get_methods(void)
+{
+ return pdb_get_methods_reload(False);
+}
+
+bool pdb_getsampwnam(struct samu *sam_acct, const char *username)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ struct samu *cache_copy;
+ const struct dom_sid *user_sid;
+
+ if (!NT_STATUS_IS_OK(pdb->getsampwnam(pdb, sam_acct, username))) {
+ return False;
+ }
+
+ cache_copy = samu_new(NULL);
+ if (cache_copy == NULL) {
+ return False;
+ }
+
+ if (!pdb_copy_sam_account(cache_copy, sam_acct)) {
+ TALLOC_FREE(cache_copy);
+ return False;
+ }
+
+ user_sid = pdb_get_user_sid(cache_copy);
+
+ memcache_add_talloc(NULL, PDB_GETPWSID_CACHE,
+ data_blob_const(user_sid, sizeof(*user_sid)),
+ cache_copy);
+
+ return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+bool guest_user_info( struct samu *user )
+{
+ struct passwd *pwd;
+ NTSTATUS result;
+ const char *guestname = lp_guestaccount();
+
+ if ( !(pwd = getpwnam_alloc( NULL, guestname ) ) ) {
+ DEBUG(0,("guest_user_info: Unable to locate guest account [%s]!\n",
+ guestname));
+ return False;
+ }
+
+ result = samu_set_unix(user, pwd );
+
+ TALLOC_FREE( pwd );
+
+ return NT_STATUS_IS_OK( result );
+}
+
+/**********************************************************************
+**********************************************************************/
+
+bool pdb_getsampwsid(struct samu *sam_acct, const DOM_SID *sid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ uint32 rid;
+ void *cache_data;
+
+ /* hard code the Guest RID of 501 */
+
+ if ( !sid_peek_check_rid( get_global_sam_sid(), sid, &rid ) )
+ return False;
+
+ if ( rid == DOMAIN_USER_RID_GUEST ) {
+ DEBUG(6,("pdb_getsampwsid: Building guest account\n"));
+ return guest_user_info( sam_acct );
+ }
+
+ /* check the cache first */
+
+ cache_data = memcache_lookup_talloc(
+ NULL, PDB_GETPWSID_CACHE, data_blob_const(sid, sizeof(*sid)));
+
+ if (cache_data != NULL) {
+ struct samu *cache_copy = talloc_get_type_abort(
+ cache_data, struct samu);
+
+ return pdb_copy_sam_account(sam_acct, cache_copy);
+ }
+
+ return NT_STATUS_IS_OK(pdb->getsampwsid(pdb, sam_acct, sid));
+}
+
+static NTSTATUS pdb_default_create_user(struct pdb_methods *methods,
+ TALLOC_CTX *tmp_ctx, const char *name,
+ uint32 acb_info, uint32 *rid)
+{
+ struct samu *sam_pass;
+ NTSTATUS status;
+ struct passwd *pwd;
+
+ if ((sam_pass = samu_new(tmp_ctx)) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( !(pwd = Get_Pwnam_alloc(tmp_ctx, name)) ) {
+ char *add_script = NULL;
+ int add_ret;
+ fstring name2;
+
+ if ((acb_info & ACB_NORMAL) && name[strlen(name)-1] != '$') {
+ add_script = talloc_strdup(tmp_ctx,
+ lp_adduser_script());
+ } else {
+ add_script = talloc_strdup(tmp_ctx,
+ lp_addmachine_script());
+ }
+
+ if (!add_script || add_script[0] == '\0') {
+ DEBUG(3, ("Could not find user %s and no add script "
+ "defined\n", name));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* lowercase the username before creating the Unix account for
+ compatibility with previous Samba releases */
+ fstrcpy( name2, name );
+ strlower_m( name2 );
+ add_script = talloc_all_string_sub(tmp_ctx,
+ add_script,
+ "%u",
+ name2);
+ if (!add_script) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ add_ret = smbrun(add_script,NULL);
+ DEBUG(add_ret ? 0 : 3, ("_samr_create_user: Running the command `%s' gave %d\n",
+ add_script, add_ret));
+ if (add_ret == 0) {
+ smb_nscd_flush_user_cache();
+ }
+
+ flush_pwnam_cache();
+
+ pwd = Get_Pwnam_alloc(tmp_ctx, name);
+ }
+
+ /* we have a valid SID coming out of this call */
+
+ status = samu_alloc_rid_unix( sam_pass, pwd );
+
+ TALLOC_FREE( pwd );
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("pdb_default_create_user: failed to create a new user structure: %s\n", nt_errstr(status)));
+ return status;
+ }
+
+ if (!sid_peek_check_rid(get_global_sam_sid(),
+ pdb_get_user_sid(sam_pass), rid)) {
+ DEBUG(0, ("Could not get RID of fresh user\n"));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /* Use the username case specified in the original request */
+
+ pdb_set_username( sam_pass, name, PDB_SET );
+
+ /* Disable the account on creation, it does not have a reasonable password yet. */
+
+ acb_info |= ACB_DISABLED;
+
+ pdb_set_acct_ctrl(sam_pass, acb_info, PDB_CHANGED);
+
+ status = pdb_add_sam_account(sam_pass);
+
+ TALLOC_FREE(sam_pass);
+
+ return status;
+}
+
+NTSTATUS pdb_create_user(TALLOC_CTX *mem_ctx, const char *name, uint32 flags,
+ uint32 *rid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->create_user(pdb, mem_ctx, name, flags, rid);
+}
+
+/****************************************************************************
+ Delete a UNIX user on demand.
+****************************************************************************/
+
+static int smb_delete_user(const char *unix_user)
+{
+ char *del_script = NULL;
+ int ret;
+
+ /* safety check */
+
+ if ( strequal( unix_user, "root" ) ) {
+ DEBUG(0,("smb_delete_user: Refusing to delete local system root account!\n"));
+ return -1;
+ }
+
+ del_script = talloc_strdup(talloc_tos(), lp_deluser_script());
+ if (!del_script || !*del_script) {
+ return -1;
+ }
+ del_script = talloc_all_string_sub(talloc_tos(),
+ del_script,
+ "%u",
+ unix_user);
+ if (!del_script) {
+ return -1;
+ }
+ ret = smbrun(del_script,NULL);
+ flush_pwnam_cache();
+ if (ret == 0) {
+ smb_nscd_flush_user_cache();
+ }
+ DEBUG(ret ? 0 : 3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret));
+
+ return ret;
+}
+
+static NTSTATUS pdb_default_delete_user(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ struct samu *sam_acct)
+{
+ NTSTATUS status;
+ fstring username;
+
+ status = pdb_delete_sam_account(sam_acct);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * Now delete the unix side ....
+ * note: we don't check if the delete really happened as the script is
+ * not necessary present and maybe the sysadmin doesn't want to delete
+ * the unix side
+ */
+
+ /* always lower case the username before handing it off to
+ external scripts */
+
+ fstrcpy( username, pdb_get_username(sam_acct) );
+ strlower_m( username );
+
+ smb_delete_user( username );
+
+ return status;
+}
+
+NTSTATUS pdb_delete_user(TALLOC_CTX *mem_ctx, struct samu *sam_acct)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ uid_t uid = -1;
+
+ /* sanity check to make sure we don't delete root */
+
+ if ( !sid_to_uid( pdb_get_user_sid(sam_acct), &uid ) ) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if ( uid == 0 ) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return pdb->delete_user(pdb, mem_ctx, sam_acct);
+}
+
+NTSTATUS pdb_add_sam_account(struct samu *sam_acct)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->add_sam_account(pdb, sam_acct);
+}
+
+NTSTATUS pdb_update_sam_account(struct samu *sam_acct)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+
+ memcache_flush(NULL, PDB_GETPWSID_CACHE);
+
+ return pdb->update_sam_account(pdb, sam_acct);
+}
+
+NTSTATUS pdb_delete_sam_account(struct samu *sam_acct)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+
+ memcache_flush(NULL, PDB_GETPWSID_CACHE);
+
+ return pdb->delete_sam_account(pdb, sam_acct);
+}
+
+NTSTATUS pdb_rename_sam_account(struct samu *oldname, const char *newname)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ uid_t uid;
+ NTSTATUS status;
+
+ memcache_flush(NULL, PDB_GETPWSID_CACHE);
+
+ /* sanity check to make sure we don't rename root */
+
+ if ( !sid_to_uid( pdb_get_user_sid(oldname), &uid ) ) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if ( uid == 0 ) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = pdb->rename_sam_account(pdb, oldname, newname);
+
+ /* always flush the cache here just to be safe */
+ flush_pwnam_cache();
+
+ return status;
+}
+
+NTSTATUS pdb_update_login_attempts(struct samu *sam_acct, bool success)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->update_login_attempts(pdb, sam_acct, success);
+}
+
+bool pdb_getgrsid(GROUP_MAP *map, DOM_SID sid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return NT_STATUS_IS_OK(pdb->getgrsid(pdb, map, sid));
+}
+
+bool pdb_getgrgid(GROUP_MAP *map, gid_t gid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return NT_STATUS_IS_OK(pdb->getgrgid(pdb, map, gid));
+}
+
+bool pdb_getgrnam(GROUP_MAP *map, const char *name)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return NT_STATUS_IS_OK(pdb->getgrnam(pdb, map, name));
+}
+
+static NTSTATUS pdb_default_create_dom_group(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const char *name,
+ uint32 *rid)
+{
+ DOM_SID group_sid;
+ struct group *grp;
+ fstring tmp;
+
+ grp = getgrnam(name);
+
+ if (grp == NULL) {
+ gid_t gid;
+
+ if (smb_create_group(name, &gid) != 0) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ grp = getgrgid(gid);
+ }
+
+ if (grp == NULL) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (pdb_rid_algorithm()) {
+ *rid = algorithmic_pdb_gid_to_group_rid( grp->gr_gid );
+ } else {
+ if (!pdb_new_rid(rid)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ sid_compose(&group_sid, get_global_sam_sid(), *rid);
+
+ return add_initial_entry(grp->gr_gid, sid_to_fstring(tmp, &group_sid),
+ SID_NAME_DOM_GRP, name, NULL);
+}
+
+NTSTATUS pdb_create_dom_group(TALLOC_CTX *mem_ctx, const char *name,
+ uint32 *rid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->create_dom_group(pdb, mem_ctx, name, rid);
+}
+
+static NTSTATUS pdb_default_delete_dom_group(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ uint32 rid)
+{
+ DOM_SID group_sid;
+ GROUP_MAP map;
+ NTSTATUS status;
+ struct group *grp;
+ const char *grp_name;
+
+ sid_compose(&group_sid, get_global_sam_sid(), rid);
+
+ if (!get_domain_group_from_sid(group_sid, &map)) {
+ DEBUG(10, ("Could not find group for rid %d\n", rid));
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ /* We need the group name for the smb_delete_group later on */
+
+ if (map.gid == (gid_t)-1) {
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ grp = getgrgid(map.gid);
+ if (grp == NULL) {
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ /* Copy the name, no idea what pdb_delete_group_mapping_entry does.. */
+
+ grp_name = talloc_strdup(mem_ctx, grp->gr_name);
+ if (grp_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = pdb_delete_group_mapping_entry(group_sid);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Don't check the result of smb_delete_group */
+
+ smb_delete_group(grp_name);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_delete_dom_group(TALLOC_CTX *mem_ctx, uint32 rid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->delete_dom_group(pdb, mem_ctx, rid);
+}
+
+NTSTATUS pdb_add_group_mapping_entry(GROUP_MAP *map)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->add_group_mapping_entry(pdb, map);
+}
+
+NTSTATUS pdb_update_group_mapping_entry(GROUP_MAP *map)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->update_group_mapping_entry(pdb, map);
+}
+
+NTSTATUS pdb_delete_group_mapping_entry(DOM_SID sid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->delete_group_mapping_entry(pdb, sid);
+}
+
+bool pdb_enum_group_mapping(const DOM_SID *sid, enum lsa_SidType sid_name_use, GROUP_MAP **pp_rmap,
+ size_t *p_num_entries, bool unix_only)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return NT_STATUS_IS_OK(pdb-> enum_group_mapping(pdb, sid, sid_name_use,
+ pp_rmap, p_num_entries, unix_only));
+}
+
+NTSTATUS pdb_enum_group_members(TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ uint32 **pp_member_rids,
+ size_t *p_num_members)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ NTSTATUS result;
+
+ result = pdb->enum_group_members(pdb, mem_ctx,
+ sid, pp_member_rids, p_num_members);
+
+ /* special check for rid 513 */
+
+ if ( !NT_STATUS_IS_OK( result ) ) {
+ uint32 rid;
+
+ sid_peek_rid( sid, &rid );
+
+ if ( rid == DOMAIN_GROUP_RID_USERS ) {
+ *p_num_members = 0;
+ *pp_member_rids = NULL;
+
+ return NT_STATUS_OK;
+ }
+ }
+
+ return result;
+}
+
+NTSTATUS pdb_enum_group_memberships(TALLOC_CTX *mem_ctx, struct samu *user,
+ DOM_SID **pp_sids, gid_t **pp_gids,
+ size_t *p_num_groups)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->enum_group_memberships(
+ pdb, mem_ctx, user,
+ pp_sids, pp_gids, p_num_groups);
+}
+
+static NTSTATUS pdb_default_set_unix_primary_group(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ struct samu *sampass)
+{
+ struct group *grp;
+ gid_t gid;
+
+ if (!sid_to_gid(pdb_get_group_sid(sampass), &gid) ||
+ (grp = getgrgid(gid)) == NULL) {
+ return NT_STATUS_INVALID_PRIMARY_GROUP;
+ }
+
+ if (smb_set_primary_group(grp->gr_name,
+ pdb_get_username(sampass)) != 0) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_set_unix_primary_group(TALLOC_CTX *mem_ctx, struct samu *user)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->set_unix_primary_group(pdb, mem_ctx, user);
+}
+
+/*
+ * Helper function to see whether a user is in a group. We can't use
+ * user_in_group_sid here because this creates dependencies only smbd can
+ * fulfil.
+ */
+
+static bool pdb_user_in_group(TALLOC_CTX *mem_ctx, struct samu *account,
+ const DOM_SID *group_sid)
+{
+ DOM_SID *sids;
+ gid_t *gids;
+ size_t i, num_groups;
+
+ if (!NT_STATUS_IS_OK(pdb_enum_group_memberships(mem_ctx, account,
+ &sids, &gids,
+ &num_groups))) {
+ return False;
+ }
+
+ for (i=0; i<num_groups; i++) {
+ if (sid_equal(group_sid, &sids[i])) {
+ return True;
+ }
+ }
+ return False;
+}
+
+static NTSTATUS pdb_default_add_groupmem(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ uint32 group_rid,
+ uint32 member_rid)
+{
+ DOM_SID group_sid, member_sid;
+ struct samu *account = NULL;
+ GROUP_MAP map;
+ struct group *grp;
+ struct passwd *pwd;
+ const char *group_name;
+ uid_t uid;
+
+ sid_compose(&group_sid, get_global_sam_sid(), group_rid);
+ sid_compose(&member_sid, get_global_sam_sid(), member_rid);
+
+ if (!get_domain_group_from_sid(group_sid, &map) ||
+ (map.gid == (gid_t)-1) ||
+ ((grp = getgrgid(map.gid)) == NULL)) {
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ group_name = talloc_strdup(mem_ctx, grp->gr_name);
+ if (group_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( !(account = samu_new( NULL )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_getsampwsid(account, &member_sid) ||
+ !sid_to_uid(&member_sid, &uid) ||
+ ((pwd = getpwuid_alloc(mem_ctx, uid)) == NULL)) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (pdb_user_in_group(mem_ctx, account, &group_sid)) {
+ return NT_STATUS_MEMBER_IN_GROUP;
+ }
+
+ /*
+ * ok, the group exist, the user exist, the user is not in the group,
+ * we can (finally) add it to the group !
+ */
+
+ smb_add_user_group(group_name, pwd->pw_name);
+
+ if (!pdb_user_in_group(mem_ctx, account, &group_sid)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_add_groupmem(TALLOC_CTX *mem_ctx, uint32 group_rid,
+ uint32 member_rid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->add_groupmem(pdb, mem_ctx, group_rid, member_rid);
+}
+
+static NTSTATUS pdb_default_del_groupmem(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ uint32 group_rid,
+ uint32 member_rid)
+{
+ DOM_SID group_sid, member_sid;
+ struct samu *account = NULL;
+ GROUP_MAP map;
+ struct group *grp;
+ struct passwd *pwd;
+ const char *group_name;
+ uid_t uid;
+
+ sid_compose(&group_sid, get_global_sam_sid(), group_rid);
+ sid_compose(&member_sid, get_global_sam_sid(), member_rid);
+
+ if (!get_domain_group_from_sid(group_sid, &map) ||
+ (map.gid == (gid_t)-1) ||
+ ((grp = getgrgid(map.gid)) == NULL)) {
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ group_name = talloc_strdup(mem_ctx, grp->gr_name);
+ if (group_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( !(account = samu_new( NULL )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_getsampwsid(account, &member_sid) ||
+ !sid_to_uid(&member_sid, &uid) ||
+ ((pwd = getpwuid_alloc(mem_ctx, uid)) == NULL)) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (!pdb_user_in_group(mem_ctx, account, &group_sid)) {
+ return NT_STATUS_MEMBER_NOT_IN_GROUP;
+ }
+
+ /*
+ * ok, the group exist, the user exist, the user is in the group,
+ * we can (finally) delete it from the group!
+ */
+
+ smb_delete_user_group(group_name, pwd->pw_name);
+
+ if (pdb_user_in_group(mem_ctx, account, &group_sid)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_del_groupmem(TALLOC_CTX *mem_ctx, uint32 group_rid,
+ uint32 member_rid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->del_groupmem(pdb, mem_ctx, group_rid, member_rid);
+}
+
+NTSTATUS pdb_create_alias(const char *name, uint32 *rid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->create_alias(pdb, name, rid);
+}
+
+NTSTATUS pdb_delete_alias(const DOM_SID *sid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->delete_alias(pdb, sid);
+}
+
+NTSTATUS pdb_get_aliasinfo(const DOM_SID *sid, struct acct_info *info)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->get_aliasinfo(pdb, sid, info);
+}
+
+NTSTATUS pdb_set_aliasinfo(const DOM_SID *sid, struct acct_info *info)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->set_aliasinfo(pdb, sid, info);
+}
+
+NTSTATUS pdb_add_aliasmem(const DOM_SID *alias, const DOM_SID *member)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->add_aliasmem(pdb, alias, member);
+}
+
+NTSTATUS pdb_del_aliasmem(const DOM_SID *alias, const DOM_SID *member)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->del_aliasmem(pdb, alias, member);
+}
+
+NTSTATUS pdb_enum_aliasmem(const DOM_SID *alias,
+ DOM_SID **pp_members, size_t *p_num_members)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->enum_aliasmem(pdb, alias, pp_members, p_num_members);
+}
+
+NTSTATUS pdb_enum_alias_memberships(TALLOC_CTX *mem_ctx,
+ const DOM_SID *domain_sid,
+ const DOM_SID *members, size_t num_members,
+ uint32 **pp_alias_rids,
+ size_t *p_num_alias_rids)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->enum_alias_memberships(pdb, mem_ctx,
+ domain_sid,
+ members, num_members,
+ pp_alias_rids,
+ p_num_alias_rids);
+}
+
+NTSTATUS pdb_lookup_rids(const DOM_SID *domain_sid,
+ int num_rids,
+ uint32 *rids,
+ const char **names,
+ enum lsa_SidType *attrs)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->lookup_rids(pdb, domain_sid, num_rids, rids, names, attrs);
+}
+
+/*
+ * NOTE: pdb_lookup_names is currently (2007-01-12) not used anywhere
+ * in the samba code.
+ * Unlike _lsa_lookup_sids and _samr_lookup_rids, which eventually
+ * also ask pdb_lookup_rids, thus looking up a bunch of rids at a time,
+ * the pdb_ calls _lsa_lookup_names and _samr_lookup_names come
+ * down to are pdb_getsampwnam and pdb_getgrnam instead of
+ * pdb_lookup_names.
+ * But in principle, it the call belongs to the API and might get
+ * used in this context some day.
+ */
+#if 0
+NTSTATUS pdb_lookup_names(const DOM_SID *domain_sid,
+ int num_names,
+ const char **names,
+ uint32 *rids,
+ enum lsa_SidType *attrs)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->lookup_names(pdb, domain_sid, num_names, names, rids, attrs);
+}
+#endif
+
+bool pdb_get_account_policy(int policy_index, uint32 *value)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ NTSTATUS status;
+
+ become_root();
+ status = pdb->get_account_policy(pdb, policy_index, value);
+ unbecome_root();
+
+ return NT_STATUS_IS_OK(status);
+}
+
+bool pdb_set_account_policy(int policy_index, uint32 value)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ NTSTATUS status;
+
+ become_root();
+ status = pdb->set_account_policy(pdb, policy_index, value);
+ unbecome_root();
+
+ return NT_STATUS_IS_OK(status);
+}
+
+bool pdb_get_seq_num(time_t *seq_num)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return NT_STATUS_IS_OK(pdb->get_seq_num(pdb, seq_num));
+}
+
+bool pdb_uid_to_rid(uid_t uid, uint32 *rid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->uid_to_rid(pdb, uid, rid);
+}
+
+bool pdb_uid_to_sid(uid_t uid, DOM_SID *sid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->uid_to_sid(pdb, uid, sid);
+}
+
+bool pdb_gid_to_sid(gid_t gid, DOM_SID *sid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->gid_to_sid(pdb, gid, sid);
+}
+
+bool pdb_sid_to_id(const DOM_SID *sid, union unid_t *id,
+ enum lsa_SidType *type)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->sid_to_id(pdb, sid, id, type);
+}
+
+bool pdb_rid_algorithm(void)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->rid_algorithm(pdb);
+}
+
+/********************************************************************
+ Allocate a new RID from the passdb backend. Verify that it is free
+ by calling lookup_global_sam_rid() to verify that the RID is not
+ in use. This handles servers that have existing users or groups
+ with add RIDs (assigned from previous algorithmic mappings)
+********************************************************************/
+
+bool pdb_new_rid(uint32 *rid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ const char *name = NULL;
+ enum lsa_SidType type;
+ uint32 allocated_rid = 0;
+ int i;
+ TALLOC_CTX *ctx;
+
+ if (pdb_rid_algorithm()) {
+ DEBUG(0, ("Trying to allocate a RID when algorithmic RIDs "
+ "are active\n"));
+ return False;
+ }
+
+ if (algorithmic_rid_base() != BASE_RID) {
+ DEBUG(0, ("'algorithmic rid base' is set but a passdb backend "
+ "without algorithmic RIDs is chosen.\n"));
+ DEBUGADD(0, ("Please map all used groups using 'net groupmap "
+ "add', set the maximum used RID using\n"));
+ DEBUGADD(0, ("'net setmaxrid' and remove the parameter\n"));
+ return False;
+ }
+
+ if ( (ctx = talloc_init("pdb_new_rid")) == NULL ) {
+ DEBUG(0,("pdb_new_rid: Talloc initialization failure\n"));
+ return False;
+ }
+
+ /* Attempt to get an unused RID (max tires is 250...yes that it is
+ and arbitrary number I pulkled out of my head). -- jerry */
+
+ for ( i=0; allocated_rid==0 && i<250; i++ ) {
+ /* get a new RID */
+
+ if ( !pdb->new_rid(pdb, &allocated_rid) ) {
+ return False;
+ }
+
+ /* validate that the RID is not in use */
+
+ if ( lookup_global_sam_rid( ctx, allocated_rid, &name, &type, NULL ) ) {
+ allocated_rid = 0;
+ }
+ }
+
+ TALLOC_FREE( ctx );
+
+ if ( allocated_rid == 0 ) {
+ DEBUG(0,("pdb_new_rid: Failed to find unused RID\n"));
+ return False;
+ }
+
+ *rid = allocated_rid;
+
+ return True;
+}
+
+/***************************************************************
+ Initialize the static context (at smbd startup etc).
+
+ If uninitialised, context will auto-init on first use.
+ ***************************************************************/
+
+bool initialize_password_db(bool reload, struct event_context *event_ctx)
+{
+ pdb_event_ctx = event_ctx;
+ return (pdb_get_methods_reload(reload) != NULL);
+}
+
+
+/***************************************************************************
+ Default implementations of some functions.
+ ****************************************************************************/
+
+static NTSTATUS pdb_default_getsampwnam (struct pdb_methods *methods, struct samu *user, const char *sname)
+{
+ return NT_STATUS_NO_SUCH_USER;
+}
+
+static NTSTATUS pdb_default_getsampwsid(struct pdb_methods *my_methods, struct samu * user, const DOM_SID *sid)
+{
+ return NT_STATUS_NO_SUCH_USER;
+}
+
+static NTSTATUS pdb_default_add_sam_account (struct pdb_methods *methods, struct samu *newpwd)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_default_update_sam_account (struct pdb_methods *methods, struct samu *newpwd)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_default_delete_sam_account (struct pdb_methods *methods, struct samu *pwd)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_default_rename_sam_account (struct pdb_methods *methods, struct samu *pwd, const char *newname)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_default_update_login_attempts (struct pdb_methods *methods, struct samu *newpwd, bool success)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_default_get_account_policy(struct pdb_methods *methods, int policy_index, uint32 *value)
+{
+ return account_policy_get(policy_index, value) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+static NTSTATUS pdb_default_set_account_policy(struct pdb_methods *methods, int policy_index, uint32 value)
+{
+ return account_policy_set(policy_index, value) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+static NTSTATUS pdb_default_get_seq_num(struct pdb_methods *methods, time_t *seq_num)
+{
+ *seq_num = time(NULL);
+ return NT_STATUS_OK;
+}
+
+static bool pdb_default_uid_to_sid(struct pdb_methods *methods, uid_t uid,
+ DOM_SID *sid)
+{
+ struct samu *sampw = NULL;
+ struct passwd *unix_pw;
+ bool ret;
+
+ unix_pw = sys_getpwuid( uid );
+
+ if ( !unix_pw ) {
+ DEBUG(4,("pdb_default_uid_to_rid: host has no idea of uid "
+ "%lu\n", (unsigned long)uid));
+ return False;
+ }
+
+ if ( !(sampw = samu_new( NULL )) ) {
+ DEBUG(0,("pdb_default_uid_to_rid: samu_new() failed!\n"));
+ return False;
+ }
+
+ become_root();
+ ret = NT_STATUS_IS_OK(
+ methods->getsampwnam(methods, sampw, unix_pw->pw_name ));
+ unbecome_root();
+
+ if (!ret) {
+ DEBUG(5, ("pdb_default_uid_to_rid: Did not find user "
+ "%s (%d)\n", unix_pw->pw_name, uid));
+ TALLOC_FREE(sampw);
+ return False;
+ }
+
+ sid_copy(sid, pdb_get_user_sid(sampw));
+
+ TALLOC_FREE(sampw);
+
+ return True;
+}
+
+static bool pdb_default_uid_to_rid(struct pdb_methods *methods, uid_t uid,
+ uint32 *rid)
+{
+ DOM_SID sid;
+ bool ret;
+
+ ret = pdb_default_uid_to_sid(methods, uid, &sid);
+ if (!ret) {
+ return ret;
+ }
+
+ ret = sid_peek_check_rid(get_global_sam_sid(), &sid, rid);
+
+ if (!ret) {
+ DEBUG(1, ("Could not peek rid out of sid %s\n",
+ sid_string_dbg(&sid)));
+ }
+
+ return ret;
+}
+
+static bool pdb_default_gid_to_sid(struct pdb_methods *methods, gid_t gid,
+ DOM_SID *sid)
+{
+ GROUP_MAP map;
+
+ if (!NT_STATUS_IS_OK(methods->getgrgid(methods, &map, gid))) {
+ return False;
+ }
+
+ sid_copy(sid, &map.sid);
+ return True;
+}
+
+static bool pdb_default_sid_to_id(struct pdb_methods *methods,
+ const DOM_SID *sid,
+ union unid_t *id, enum lsa_SidType *type)
+{
+ TALLOC_CTX *mem_ctx;
+ bool ret = False;
+ const char *name;
+ uint32 rid;
+
+ mem_ctx = talloc_new(NULL);
+
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return False;
+ }
+
+ if (sid_peek_check_rid(get_global_sam_sid(), sid, &rid)) {
+ /* Here we might have users as well as groups and aliases */
+ ret = lookup_global_sam_rid(mem_ctx, rid, &name, type, id);
+ goto done;
+ }
+
+ /* check for "Unix User" */
+
+ if ( sid_peek_check_rid(&global_sid_Unix_Users, sid, &rid) ) {
+ id->uid = rid;
+ *type = SID_NAME_USER;
+ ret = True;
+ goto done;
+ }
+
+ /* check for "Unix Group" */
+
+ if ( sid_peek_check_rid(&global_sid_Unix_Groups, sid, &rid) ) {
+ id->gid = rid;
+ *type = SID_NAME_ALIAS;
+ ret = True;
+ goto done;
+ }
+
+ /* BUILTIN */
+
+ if (sid_check_is_in_builtin(sid) ||
+ sid_check_is_in_wellknown_domain(sid)) {
+ /* Here we only have aliases */
+ GROUP_MAP map;
+ if (!NT_STATUS_IS_OK(methods->getgrsid(methods, &map, *sid))) {
+ DEBUG(10, ("Could not find map for sid %s\n",
+ sid_string_dbg(sid)));
+ goto done;
+ }
+ if ((map.sid_name_use != SID_NAME_ALIAS) &&
+ (map.sid_name_use != SID_NAME_WKN_GRP)) {
+ DEBUG(10, ("Map for sid %s is a %s, expected an "
+ "alias\n", sid_string_dbg(sid),
+ sid_type_lookup(map.sid_name_use)));
+ goto done;
+ }
+
+ id->gid = map.gid;
+ *type = SID_NAME_ALIAS;
+ ret = True;
+ goto done;
+ }
+
+ DEBUG(5, ("Sid %s is neither ours, a Unix SID, nor builtin\n",
+ sid_string_dbg(sid)));
+
+ done:
+
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static bool add_uid_to_array_unique(TALLOC_CTX *mem_ctx,
+ uid_t uid, uid_t **pp_uids, size_t *p_num)
+{
+ size_t i;
+
+ for (i=0; i<*p_num; i++) {
+ if ((*pp_uids)[i] == uid)
+ return True;
+ }
+
+ *pp_uids = TALLOC_REALLOC_ARRAY(mem_ctx, *pp_uids, uid_t, *p_num+1);
+
+ if (*pp_uids == NULL)
+ return False;
+
+ (*pp_uids)[*p_num] = uid;
+ *p_num += 1;
+ return True;
+}
+
+static bool get_memberuids(TALLOC_CTX *mem_ctx, gid_t gid, uid_t **pp_uids, size_t *p_num)
+{
+ struct group *grp;
+ char **gr;
+ struct passwd *pwd;
+ bool winbind_env;
+ bool ret = False;
+
+ *pp_uids = NULL;
+ *p_num = 0;
+
+ /* We only look at our own sam, so don't care about imported stuff */
+ winbind_env = winbind_env_set();
+ (void)winbind_off();
+
+ if ((grp = getgrgid(gid)) == NULL) {
+ /* allow winbindd lookups, but only if they weren't already disabled */
+ goto done;
+ }
+
+ /* Primary group members */
+ setpwent();
+ while ((pwd = getpwent()) != NULL) {
+ if (pwd->pw_gid == gid) {
+ if (!add_uid_to_array_unique(mem_ctx, pwd->pw_uid,
+ pp_uids, p_num)) {
+ goto done;
+ }
+ }
+ }
+ endpwent();
+
+ /* Secondary group members */
+ for (gr = grp->gr_mem; (*gr != NULL) && ((*gr)[0] != '\0'); gr += 1) {
+ struct passwd *pw = getpwnam(*gr);
+
+ if (pw == NULL)
+ continue;
+ if (!add_uid_to_array_unique(mem_ctx, pw->pw_uid, pp_uids, p_num)) {
+ goto done;
+ }
+ }
+
+ ret = True;
+
+ done:
+
+ /* allow winbindd lookups, but only if they weren't already disabled */
+ if (!winbind_env) {
+ (void)winbind_on();
+ }
+
+ return ret;
+}
+
+static NTSTATUS pdb_default_enum_group_members(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group,
+ uint32 **pp_member_rids,
+ size_t *p_num_members)
+{
+ gid_t gid;
+ uid_t *uids;
+ size_t i, num_uids;
+
+ *pp_member_rids = NULL;
+ *p_num_members = 0;
+
+ if (!sid_to_gid(group, &gid))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ if(!get_memberuids(mem_ctx, gid, &uids, &num_uids))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ if (num_uids == 0)
+ return NT_STATUS_OK;
+
+ *pp_member_rids = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_uids);
+
+ for (i=0; i<num_uids; i++) {
+ DOM_SID sid;
+
+ uid_to_sid(&sid, uids[i]);
+
+ if (!sid_check_is_in_our_domain(&sid)) {
+ DEBUG(5, ("Inconsistent SAM -- group member uid not "
+ "in our domain\n"));
+ continue;
+ }
+
+ sid_peek_rid(&sid, &(*pp_member_rids)[*p_num_members]);
+ *p_num_members += 1;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_default_enum_group_memberships(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ struct samu *user,
+ DOM_SID **pp_sids,
+ gid_t **pp_gids,
+ size_t *p_num_groups)
+{
+ size_t i;
+ gid_t gid;
+ struct passwd *pw;
+ const char *username = pdb_get_username(user);
+
+
+ /* Ignore the primary group SID. Honor the real Unix primary group.
+ The primary group SID is only of real use to Windows clients */
+
+ if ( !(pw = getpwnam_alloc(mem_ctx, username)) ) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ gid = pw->pw_gid;
+
+ TALLOC_FREE( pw );
+
+ if (!getgroups_unix_user(mem_ctx, username, gid, pp_gids, p_num_groups)) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (*p_num_groups == 0) {
+ smb_panic("primary group missing");
+ }
+
+ *pp_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *p_num_groups);
+
+ if (*pp_sids == NULL) {
+ TALLOC_FREE(*pp_gids);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<*p_num_groups; i++) {
+ gid_to_sid(&(*pp_sids)[i], (*pp_gids)[i]);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Look up a rid in the SAM we're responsible for (i.e. passdb)
+ ********************************************************************/
+
+static bool lookup_global_sam_rid(TALLOC_CTX *mem_ctx, uint32 rid,
+ const char **name,
+ enum lsa_SidType *psid_name_use,
+ union unid_t *unix_id)
+{
+ struct samu *sam_account = NULL;
+ GROUP_MAP map;
+ bool ret;
+ DOM_SID sid;
+
+ *psid_name_use = SID_NAME_UNKNOWN;
+
+ DEBUG(5,("lookup_global_sam_rid: looking up RID %u.\n",
+ (unsigned int)rid));
+
+ sid_copy(&sid, get_global_sam_sid());
+ sid_append_rid(&sid, rid);
+
+ /* see if the passdb can help us with the name of the user */
+
+ if ( !(sam_account = samu_new( NULL )) ) {
+ return False;
+ }
+
+ /* BEING ROOT BLLOCK */
+ become_root();
+ if (pdb_getsampwsid(sam_account, &sid)) {
+ struct passwd *pw;
+
+ unbecome_root(); /* -----> EXIT BECOME_ROOT() */
+ *name = talloc_strdup(mem_ctx, pdb_get_username(sam_account));
+ if (!*name) {
+ TALLOC_FREE(sam_account);
+ return False;
+ }
+
+ *psid_name_use = SID_NAME_USER;
+
+ TALLOC_FREE(sam_account);
+
+ if (unix_id == NULL) {
+ return True;
+ }
+
+ pw = Get_Pwnam_alloc(talloc_tos(), *name);
+ if (pw == NULL) {
+ return False;
+ }
+ unix_id->uid = pw->pw_uid;
+ TALLOC_FREE(pw);
+ return True;
+ }
+ TALLOC_FREE(sam_account);
+
+ ret = pdb_getgrsid(&map, sid);
+ unbecome_root();
+ /* END BECOME_ROOT BLOCK */
+
+ /* do not resolve SIDs to a name unless there is a valid
+ gid associated with it */
+
+ if ( ret && (map.gid != (gid_t)-1) ) {
+ *name = talloc_strdup(mem_ctx, map.nt_name);
+ *psid_name_use = map.sid_name_use;
+
+ if ( unix_id ) {
+ unix_id->gid = map.gid;
+ }
+
+ return True;
+ }
+
+ /* Windows will always map RID 513 to something. On a non-domain
+ controller, this gets mapped to SERVER\None. */
+
+ if ( unix_id ) {
+ DEBUG(5, ("Can't find a unix id for an unmapped group\n"));
+ return False;
+ }
+
+ if ( rid == DOMAIN_GROUP_RID_USERS ) {
+ *name = talloc_strdup(mem_ctx, "None" );
+ *psid_name_use = SID_NAME_DOM_GRP;
+
+ return True;
+ }
+
+ return False;
+}
+
+static NTSTATUS pdb_default_lookup_rids(struct pdb_methods *methods,
+ const DOM_SID *domain_sid,
+ int num_rids,
+ uint32 *rids,
+ const char **names,
+ enum lsa_SidType *attrs)
+{
+ int i;
+ NTSTATUS result;
+ bool have_mapped = False;
+ bool have_unmapped = False;
+
+ if (sid_check_is_builtin(domain_sid)) {
+
+ for (i=0; i<num_rids; i++) {
+ const char *name;
+
+ if (lookup_builtin_rid(names, rids[i], &name)) {
+ attrs[i] = SID_NAME_ALIAS;
+ names[i] = name;
+ DEBUG(5,("lookup_rids: %s:%d\n",
+ names[i], attrs[i]));
+ have_mapped = True;
+ } else {
+ have_unmapped = True;
+ attrs[i] = SID_NAME_UNKNOWN;
+ }
+ }
+ goto done;
+ }
+
+ /* Should not happen, but better check once too many */
+ if (!sid_check_is_domain(domain_sid)) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ for (i = 0; i < num_rids; i++) {
+ const char *name;
+
+ if (lookup_global_sam_rid(names, rids[i], &name, &attrs[i],
+ NULL)) {
+ if (name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ names[i] = name;
+ DEBUG(5,("lookup_rids: %s:%d\n", names[i], attrs[i]));
+ have_mapped = True;
+ } else {
+ have_unmapped = True;
+ attrs[i] = SID_NAME_UNKNOWN;
+ }
+ }
+
+ done:
+
+ result = NT_STATUS_NONE_MAPPED;
+
+ if (have_mapped)
+ result = have_unmapped ? STATUS_SOME_UNMAPPED : NT_STATUS_OK;
+
+ return result;
+}
+
+#if 0
+static NTSTATUS pdb_default_lookup_names(struct pdb_methods *methods,
+ const DOM_SID *domain_sid,
+ int num_names,
+ const char **names,
+ uint32 *rids,
+ enum lsa_SidType *attrs)
+{
+ int i;
+ NTSTATUS result;
+ bool have_mapped = False;
+ bool have_unmapped = False;
+
+ if (sid_check_is_builtin(domain_sid)) {
+
+ for (i=0; i<num_names; i++) {
+ uint32 rid;
+
+ if (lookup_builtin_name(names[i], &rid)) {
+ attrs[i] = SID_NAME_ALIAS;
+ rids[i] = rid;
+ DEBUG(5,("lookup_rids: %s:%d\n",
+ names[i], attrs[i]));
+ have_mapped = True;
+ } else {
+ have_unmapped = True;
+ attrs[i] = SID_NAME_UNKNOWN;
+ }
+ }
+ goto done;
+ }
+
+ /* Should not happen, but better check once too many */
+ if (!sid_check_is_domain(domain_sid)) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ for (i = 0; i < num_names; i++) {
+ if (lookup_global_sam_name(names[i], 0, &rids[i], &attrs[i])) {
+ DEBUG(5,("lookup_names: %s-> %d:%d\n", names[i],
+ rids[i], attrs[i]));
+ have_mapped = True;
+ } else {
+ have_unmapped = True;
+ attrs[i] = SID_NAME_UNKNOWN;
+ }
+ }
+
+ done:
+
+ result = NT_STATUS_NONE_MAPPED;
+
+ if (have_mapped)
+ result = have_unmapped ? STATUS_SOME_UNMAPPED : NT_STATUS_OK;
+
+ return result;
+}
+#endif
+
+struct pdb_search *pdb_search_init(enum pdb_search_type type)
+{
+ TALLOC_CTX *mem_ctx;
+ struct pdb_search *result;
+
+ mem_ctx = talloc_init("pdb_search");
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_init failed\n"));
+ return NULL;
+ }
+
+ result = TALLOC_P(mem_ctx, struct pdb_search);
+ if (result == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ result->mem_ctx = mem_ctx;
+ result->type = type;
+ result->cache = NULL;
+ result->num_entries = 0;
+ result->cache_size = 0;
+ result->search_ended = False;
+
+ /* Segfault appropriately if not initialized */
+ result->next_entry = NULL;
+ result->search_end = NULL;
+
+ return result;
+}
+
+static void fill_displayentry(TALLOC_CTX *mem_ctx, uint32 rid,
+ uint16 acct_flags,
+ const char *account_name,
+ const char *fullname,
+ const char *description,
+ struct samr_displayentry *entry)
+{
+ entry->rid = rid;
+ entry->acct_flags = acct_flags;
+
+ if (account_name != NULL)
+ entry->account_name = talloc_strdup(mem_ctx, account_name);
+ else
+ entry->account_name = "";
+
+ if (fullname != NULL)
+ entry->fullname = talloc_strdup(mem_ctx, fullname);
+ else
+ entry->fullname = "";
+
+ if (description != NULL)
+ entry->description = talloc_strdup(mem_ctx, description);
+ else
+ entry->description = "";
+}
+
+struct group_search {
+ GROUP_MAP *groups;
+ size_t num_groups, current_group;
+};
+
+static bool next_entry_groups(struct pdb_search *s,
+ struct samr_displayentry *entry)
+{
+ struct group_search *state = (struct group_search *)s->private_data;
+ uint32 rid;
+ GROUP_MAP *map = &state->groups[state->current_group];
+
+ if (state->current_group == state->num_groups)
+ return False;
+
+ sid_peek_rid(&map->sid, &rid);
+
+ fill_displayentry(s->mem_ctx, rid, 0, map->nt_name, NULL, map->comment,
+ entry);
+
+ state->current_group += 1;
+ return True;
+}
+
+static void search_end_groups(struct pdb_search *search)
+{
+ struct group_search *state =
+ (struct group_search *)search->private_data;
+ SAFE_FREE(state->groups);
+}
+
+static bool pdb_search_grouptype(struct pdb_search *search,
+ const DOM_SID *sid, enum lsa_SidType type)
+{
+ struct group_search *state;
+
+ state = TALLOC_P(search->mem_ctx, struct group_search);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return False;
+ }
+
+ if (!pdb_enum_group_mapping(sid, type, &state->groups, &state->num_groups,
+ True)) {
+ DEBUG(0, ("Could not enum groups\n"));
+ return False;
+ }
+
+ state->current_group = 0;
+ search->private_data = state;
+ search->next_entry = next_entry_groups;
+ search->search_end = search_end_groups;
+ return True;
+}
+
+static bool pdb_default_search_groups(struct pdb_methods *methods,
+ struct pdb_search *search)
+{
+ return pdb_search_grouptype(search, get_global_sam_sid(), SID_NAME_DOM_GRP);
+}
+
+static bool pdb_default_search_aliases(struct pdb_methods *methods,
+ struct pdb_search *search,
+ const DOM_SID *sid)
+{
+
+ return pdb_search_grouptype(search, sid, SID_NAME_ALIAS);
+}
+
+static struct samr_displayentry *pdb_search_getentry(struct pdb_search *search,
+ uint32 idx)
+{
+ if (idx < search->num_entries)
+ return &search->cache[idx];
+
+ if (search->search_ended)
+ return NULL;
+
+ while (idx >= search->num_entries) {
+ struct samr_displayentry entry;
+
+ if (!search->next_entry(search, &entry)) {
+ search->search_end(search);
+ search->search_ended = True;
+ break;
+ }
+
+ ADD_TO_LARGE_ARRAY(search->mem_ctx, struct samr_displayentry,
+ entry, &search->cache, &search->num_entries,
+ &search->cache_size);
+ }
+
+ return (search->num_entries > idx) ? &search->cache[idx] : NULL;
+}
+
+struct pdb_search *pdb_search_users(uint32 acct_flags)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ struct pdb_search *result;
+
+ result = pdb_search_init(PDB_USER_SEARCH);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ if (!pdb->search_users(pdb, result, acct_flags)) {
+ talloc_destroy(result->mem_ctx);
+ return NULL;
+ }
+ return result;
+}
+
+struct pdb_search *pdb_search_groups(void)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ struct pdb_search *result;
+
+ result = pdb_search_init(PDB_GROUP_SEARCH);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ if (!pdb->search_groups(pdb, result)) {
+ talloc_destroy(result->mem_ctx);
+ return NULL;
+ }
+ return result;
+}
+
+struct pdb_search *pdb_search_aliases(const DOM_SID *sid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ struct pdb_search *result;
+
+ if (pdb == NULL) return NULL;
+
+ result = pdb_search_init(PDB_ALIAS_SEARCH);
+ if (result == NULL) return NULL;
+
+ if (!pdb->search_aliases(pdb, result, sid)) {
+ talloc_destroy(result->mem_ctx);
+ return NULL;
+ }
+ return result;
+}
+
+uint32 pdb_search_entries(struct pdb_search *search,
+ uint32 start_idx, uint32 max_entries,
+ struct samr_displayentry **result)
+{
+ struct samr_displayentry *end_entry;
+ uint32 end_idx = start_idx+max_entries-1;
+
+ /* The first entry needs to be searched after the last. Otherwise the
+ * first entry might have moved due to a realloc during the search for
+ * the last entry. */
+
+ end_entry = pdb_search_getentry(search, end_idx);
+ *result = pdb_search_getentry(search, start_idx);
+
+ if (end_entry != NULL)
+ return max_entries;
+
+ if (start_idx >= search->num_entries)
+ return 0;
+
+ return search->num_entries - start_idx;
+}
+
+void pdb_search_destroy(struct pdb_search *search)
+{
+ if (search == NULL)
+ return;
+
+ if (!search->search_ended)
+ search->search_end(search);
+
+ talloc_destroy(search->mem_ctx);
+}
+
+/*******************************************************************
+ trustodm methods
+ *******************************************************************/
+
+bool pdb_get_trusteddom_pw(const char *domain, char** pwd, DOM_SID *sid,
+ time_t *pass_last_set_time)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->get_trusteddom_pw(pdb, domain, pwd, sid,
+ pass_last_set_time);
+}
+
+bool pdb_set_trusteddom_pw(const char* domain, const char* pwd,
+ const DOM_SID *sid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->set_trusteddom_pw(pdb, domain, pwd, sid);
+}
+
+bool pdb_del_trusteddom_pw(const char *domain)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->del_trusteddom_pw(pdb, domain);
+}
+
+NTSTATUS pdb_enum_trusteddoms(TALLOC_CTX *mem_ctx, uint32 *num_domains,
+ struct trustdom_info ***domains)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->enum_trusteddoms(pdb, mem_ctx, num_domains, domains);
+}
+
+/*******************************************************************
+ the defaults for trustdom methods:
+ these simply call the original passdb/secrets.c actions,
+ to be replaced by pdb_ldap.
+ *******************************************************************/
+
+static bool pdb_default_get_trusteddom_pw(struct pdb_methods *methods,
+ const char *domain,
+ char** pwd,
+ DOM_SID *sid,
+ time_t *pass_last_set_time)
+{
+ return secrets_fetch_trusted_domain_password(domain, pwd,
+ sid, pass_last_set_time);
+
+}
+
+static bool pdb_default_set_trusteddom_pw(struct pdb_methods *methods,
+ const char* domain,
+ const char* pwd,
+ const DOM_SID *sid)
+{
+ return secrets_store_trusted_domain_password(domain, pwd, sid);
+}
+
+static bool pdb_default_del_trusteddom_pw(struct pdb_methods *methods,
+ const char *domain)
+{
+ return trusted_domain_password_delete(domain);
+}
+
+static NTSTATUS pdb_default_enum_trusteddoms(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_domains,
+ struct trustdom_info ***domains)
+{
+ return secrets_trusted_domains(mem_ctx, num_domains, domains);
+}
+
+/*******************************************************************
+ Create a pdb_methods structure and initialize it with the default
+ operations. In this way a passdb module can simply implement
+ the functionality it cares about. However, normally this is done
+ in groups of related functions.
+*******************************************************************/
+
+NTSTATUS make_pdb_method( struct pdb_methods **methods )
+{
+ /* allocate memory for the structure as its own talloc CTX */
+
+ if ( !(*methods = TALLOC_ZERO_P(NULL, struct pdb_methods) ) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*methods)->getsampwnam = pdb_default_getsampwnam;
+ (*methods)->getsampwsid = pdb_default_getsampwsid;
+ (*methods)->create_user = pdb_default_create_user;
+ (*methods)->delete_user = pdb_default_delete_user;
+ (*methods)->add_sam_account = pdb_default_add_sam_account;
+ (*methods)->update_sam_account = pdb_default_update_sam_account;
+ (*methods)->delete_sam_account = pdb_default_delete_sam_account;
+ (*methods)->rename_sam_account = pdb_default_rename_sam_account;
+ (*methods)->update_login_attempts = pdb_default_update_login_attempts;
+
+ (*methods)->getgrsid = pdb_default_getgrsid;
+ (*methods)->getgrgid = pdb_default_getgrgid;
+ (*methods)->getgrnam = pdb_default_getgrnam;
+ (*methods)->create_dom_group = pdb_default_create_dom_group;
+ (*methods)->delete_dom_group = pdb_default_delete_dom_group;
+ (*methods)->add_group_mapping_entry = pdb_default_add_group_mapping_entry;
+ (*methods)->update_group_mapping_entry = pdb_default_update_group_mapping_entry;
+ (*methods)->delete_group_mapping_entry = pdb_default_delete_group_mapping_entry;
+ (*methods)->enum_group_mapping = pdb_default_enum_group_mapping;
+ (*methods)->enum_group_members = pdb_default_enum_group_members;
+ (*methods)->enum_group_memberships = pdb_default_enum_group_memberships;
+ (*methods)->set_unix_primary_group = pdb_default_set_unix_primary_group;
+ (*methods)->add_groupmem = pdb_default_add_groupmem;
+ (*methods)->del_groupmem = pdb_default_del_groupmem;
+ (*methods)->create_alias = pdb_default_create_alias;
+ (*methods)->delete_alias = pdb_default_delete_alias;
+ (*methods)->get_aliasinfo = pdb_default_get_aliasinfo;
+ (*methods)->set_aliasinfo = pdb_default_set_aliasinfo;
+ (*methods)->add_aliasmem = pdb_default_add_aliasmem;
+ (*methods)->del_aliasmem = pdb_default_del_aliasmem;
+ (*methods)->enum_aliasmem = pdb_default_enum_aliasmem;
+ (*methods)->enum_alias_memberships = pdb_default_alias_memberships;
+ (*methods)->lookup_rids = pdb_default_lookup_rids;
+ (*methods)->get_account_policy = pdb_default_get_account_policy;
+ (*methods)->set_account_policy = pdb_default_set_account_policy;
+ (*methods)->get_seq_num = pdb_default_get_seq_num;
+ (*methods)->uid_to_rid = pdb_default_uid_to_rid;
+ (*methods)->uid_to_sid = pdb_default_uid_to_sid;
+ (*methods)->gid_to_sid = pdb_default_gid_to_sid;
+ (*methods)->sid_to_id = pdb_default_sid_to_id;
+
+ (*methods)->search_groups = pdb_default_search_groups;
+ (*methods)->search_aliases = pdb_default_search_aliases;
+
+ (*methods)->get_trusteddom_pw = pdb_default_get_trusteddom_pw;
+ (*methods)->set_trusteddom_pw = pdb_default_set_trusteddom_pw;
+ (*methods)->del_trusteddom_pw = pdb_default_del_trusteddom_pw;
+ (*methods)->enum_trusteddoms = pdb_default_enum_trusteddoms;
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c
new file mode 100644
index 0000000000..ddbb53a9b9
--- /dev/null
+++ b/source3/passdb/pdb_ldap.c
@@ -0,0 +1,6389 @@
+/*
+ Unix SMB/CIFS implementation.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Jean François Micouleau 1998
+ Copyright (C) Gerald Carter 2001-2003
+ Copyright (C) Shahms King 2001
+ Copyright (C) Andrew Bartlett 2002-2003
+ Copyright (C) Stefan (metze) Metzmacher 2002-2003
+ Copyright (C) Simo Sorce 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/* TODO:
+* persistent connections: if using NSS LDAP, many connections are made
+* however, using only one within Samba would be nice
+*
+* Clean up SSL stuff, compile on OpenLDAP 1.x, 2.x, and Netscape SDK
+*
+* Other LDAP based login attributes: accountExpires, etc.
+* (should be the domain of Samba proper, but the sam_password/struct samu
+* structures don't have fields for some of these attributes)
+*
+* SSL is done, but can't get the certificate based authentication to work
+* against on my test platform (Linux 2.4, OpenLDAP 2.x)
+*/
+
+/* NOTE: this will NOT work against an Active Directory server
+* due to the fact that the two password fields cannot be retrieved
+* from a server; recommend using security = domain in this situation
+* and/or winbind
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+#include <lber.h>
+#include <ldap.h>
+
+/*
+ * Work around versions of the LDAP client libs that don't have the OIDs
+ * defined, or have them defined under the old name.
+ * This functionality is really a factor of the server, not the client
+ *
+ */
+
+#if defined(LDAP_EXOP_X_MODIFY_PASSWD) && !defined(LDAP_EXOP_MODIFY_PASSWD)
+#define LDAP_EXOP_MODIFY_PASSWD LDAP_EXOP_X_MODIFY_PASSWD
+#elif !defined(LDAP_EXOP_MODIFY_PASSWD)
+#define LDAP_EXOP_MODIFY_PASSWD "1.3.6.1.4.1.4203.1.11.1"
+#endif
+
+#if defined(LDAP_EXOP_X_MODIFY_PASSWD_ID) && !defined(LDAP_EXOP_MODIFY_PASSWD_ID)
+#define LDAP_TAG_EXOP_MODIFY_PASSWD_ID LDAP_EXOP_X_MODIFY_PASSWD_ID
+#elif !defined(LDAP_EXOP_MODIFY_PASSWD_ID)
+#define LDAP_TAG_EXOP_MODIFY_PASSWD_ID ((ber_tag_t) 0x80U)
+#endif
+
+#if defined(LDAP_EXOP_X_MODIFY_PASSWD_NEW) && !defined(LDAP_EXOP_MODIFY_PASSWD_NEW)
+#define LDAP_TAG_EXOP_MODIFY_PASSWD_NEW LDAP_EXOP_X_MODIFY_PASSWD_NEW
+#elif !defined(LDAP_EXOP_MODIFY_PASSWD_NEW)
+#define LDAP_TAG_EXOP_MODIFY_PASSWD_NEW ((ber_tag_t) 0x82U)
+#endif
+
+
+#include "smbldap.h"
+
+/**********************************************************************
+ Simple helper function to make stuff better readable
+ **********************************************************************/
+
+static LDAP *priv2ld(struct ldapsam_privates *priv)
+{
+ return priv->smbldap_state->ldap_struct;
+}
+
+/**********************************************************************
+ Get the attribute name given a user schame version.
+ **********************************************************************/
+
+static const char* get_userattr_key2string( int schema_ver, int key )
+{
+ switch ( schema_ver ) {
+ case SCHEMAVER_SAMBAACCOUNT:
+ return get_attr_key2string( attrib_map_v22, key );
+
+ case SCHEMAVER_SAMBASAMACCOUNT:
+ return get_attr_key2string( attrib_map_v30, key );
+
+ default:
+ DEBUG(0,("get_userattr_key2string: unknown schema version specified\n"));
+ break;
+ }
+ return NULL;
+}
+
+/**********************************************************************
+ Return the list of attribute names given a user schema version.
+**********************************************************************/
+
+const char** get_userattr_list( TALLOC_CTX *mem_ctx, int schema_ver )
+{
+ switch ( schema_ver ) {
+ case SCHEMAVER_SAMBAACCOUNT:
+ return get_attr_list( mem_ctx, attrib_map_v22 );
+
+ case SCHEMAVER_SAMBASAMACCOUNT:
+ return get_attr_list( mem_ctx, attrib_map_v30 );
+ default:
+ DEBUG(0,("get_userattr_list: unknown schema version specified!\n"));
+ break;
+ }
+
+ return NULL;
+}
+
+/**************************************************************************
+ Return the list of attribute names to delete given a user schema version.
+**************************************************************************/
+
+static const char** get_userattr_delete_list( TALLOC_CTX *mem_ctx,
+ int schema_ver )
+{
+ switch ( schema_ver ) {
+ case SCHEMAVER_SAMBAACCOUNT:
+ return get_attr_list( mem_ctx,
+ attrib_map_to_delete_v22 );
+
+ case SCHEMAVER_SAMBASAMACCOUNT:
+ return get_attr_list( mem_ctx,
+ attrib_map_to_delete_v30 );
+ default:
+ DEBUG(0,("get_userattr_delete_list: unknown schema version specified!\n"));
+ break;
+ }
+
+ return NULL;
+}
+
+
+/*******************************************************************
+ Generate the LDAP search filter for the objectclass based on the
+ version of the schema we are using.
+******************************************************************/
+
+static const char* get_objclass_filter( int schema_ver )
+{
+ fstring objclass_filter;
+ char *result;
+
+ switch( schema_ver ) {
+ case SCHEMAVER_SAMBAACCOUNT:
+ fstr_sprintf( objclass_filter, "(objectclass=%s)", LDAP_OBJ_SAMBAACCOUNT );
+ break;
+ case SCHEMAVER_SAMBASAMACCOUNT:
+ fstr_sprintf( objclass_filter, "(objectclass=%s)", LDAP_OBJ_SAMBASAMACCOUNT );
+ break;
+ default:
+ DEBUG(0,("get_objclass_filter: Invalid schema version specified!\n"));
+ objclass_filter[0] = '\0';
+ break;
+ }
+
+ result = talloc_strdup(talloc_tos(), objclass_filter);
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+/*****************************************************************
+ Scan a sequence number off OpenLDAP's syncrepl contextCSN
+******************************************************************/
+
+static NTSTATUS ldapsam_get_seq_num(struct pdb_methods *my_methods, time_t *seq_num)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL;
+ LDAPMessage *msg = NULL;
+ LDAPMessage *entry = NULL;
+ TALLOC_CTX *mem_ctx;
+ char **values = NULL;
+ int rc, num_result, num_values, rid;
+ char *suffix = NULL;
+ char *tok;
+ const char *p;
+ const char **attrs;
+
+ /* Unfortunatly there is no proper way to detect syncrepl-support in
+ * smbldap_connect_system(). The syncrepl OIDs are submitted for publication
+ * but do not show up in the root-DSE yet. Neither we can query the
+ * subschema-context for the syncProviderSubentry or syncConsumerSubentry
+ * objectclass. Currently we require lp_ldap_suffix() to show up as
+ * namingContext. - Guenther
+ */
+
+ if (!lp_parm_bool(-1, "ldapsam", "syncrepl_seqnum", False)) {
+ return ntstatus;
+ }
+
+ if (!seq_num) {
+ DEBUG(3,("ldapsam_get_seq_num: no sequence_number\n"));
+ return ntstatus;
+ }
+
+ if (!smbldap_has_naming_context(ldap_state->smbldap_state->ldap_struct, lp_ldap_suffix())) {
+ DEBUG(3,("ldapsam_get_seq_num: DIT not configured to hold %s "
+ "as top-level namingContext\n", lp_ldap_suffix()));
+ return ntstatus;
+ }
+
+ mem_ctx = talloc_init("ldapsam_get_seq_num");
+
+ if (mem_ctx == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if ((attrs = TALLOC_ARRAY(mem_ctx, const char *, 2)) == NULL) {
+ ntstatus = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ /* if we got a syncrepl-rid (up to three digits long) we speak with a consumer */
+ rid = lp_parm_int(-1, "ldapsam", "syncrepl_rid", -1);
+ if (rid > 0) {
+
+ /* consumer syncreplCookie: */
+ /* csn=20050126161620Z#0000001#00#00000 */
+ attrs[0] = talloc_strdup(mem_ctx, "syncreplCookie");
+ attrs[1] = NULL;
+ suffix = talloc_asprintf(mem_ctx,
+ "cn=syncrepl%d,%s", rid, lp_ldap_suffix());
+ if (!suffix) {
+ ntstatus = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ } else {
+
+ /* provider contextCSN */
+ /* 20050126161620Z#000009#00#000000 */
+ attrs[0] = talloc_strdup(mem_ctx, "contextCSN");
+ attrs[1] = NULL;
+ suffix = talloc_asprintf(mem_ctx,
+ "cn=ldapsync,%s", lp_ldap_suffix());
+
+ if (!suffix) {
+ ntstatus = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ }
+
+ rc = smbldap_search(ldap_state->smbldap_state, suffix,
+ LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0, &msg);
+
+ if (rc != LDAP_SUCCESS) {
+ goto done;
+ }
+
+ num_result = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, msg);
+ if (num_result != 1) {
+ DEBUG(3,("ldapsam_get_seq_num: Expected one entry, got %d\n", num_result));
+ goto done;
+ }
+
+ entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, msg);
+ if (entry == NULL) {
+ DEBUG(3,("ldapsam_get_seq_num: Could not retrieve entry\n"));
+ goto done;
+ }
+
+ values = ldap_get_values(ldap_state->smbldap_state->ldap_struct, entry, attrs[0]);
+ if (values == NULL) {
+ DEBUG(3,("ldapsam_get_seq_num: no values\n"));
+ goto done;
+ }
+
+ num_values = ldap_count_values(values);
+ if (num_values == 0) {
+ DEBUG(3,("ldapsam_get_seq_num: not a single value\n"));
+ goto done;
+ }
+
+ p = values[0];
+ if (!next_token_talloc(mem_ctx, &p, &tok, "#")) {
+ DEBUG(0,("ldapsam_get_seq_num: failed to parse sequence number\n"));
+ goto done;
+ }
+
+ p = tok;
+ if (!strncmp(p, "csn=", strlen("csn=")))
+ p += strlen("csn=");
+
+ DEBUG(10,("ldapsam_get_seq_num: got %s: %s\n", attrs[0], p));
+
+ *seq_num = generalized_to_unix_time(p);
+
+ /* very basic sanity check */
+ if (*seq_num <= 0) {
+ DEBUG(3,("ldapsam_get_seq_num: invalid sequence number: %d\n",
+ (int)*seq_num));
+ goto done;
+ }
+
+ ntstatus = NT_STATUS_OK;
+
+ done:
+ if (values != NULL)
+ ldap_value_free(values);
+ if (msg != NULL)
+ ldap_msgfree(msg);
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return ntstatus;
+}
+
+/*******************************************************************
+ Run the search by name.
+******************************************************************/
+
+int ldapsam_search_suffix_by_name(struct ldapsam_privates *ldap_state,
+ const char *user,
+ LDAPMessage ** result,
+ const char **attr)
+{
+ char *filter = NULL;
+ char *escape_user = escape_ldap_string_alloc(user);
+ int ret = -1;
+
+ if (!escape_user) {
+ return LDAP_NO_MEMORY;
+ }
+
+ /*
+ * in the filter expression, replace %u with the real name
+ * so in ldap filter, %u MUST exist :-)
+ */
+ filter = talloc_asprintf(talloc_tos(), "(&%s%s)", "(uid=%u)",
+ get_objclass_filter(ldap_state->schema_ver));
+ if (!filter) {
+ SAFE_FREE(escape_user);
+ return LDAP_NO_MEMORY;
+ }
+ /*
+ * have to use this here because $ is filtered out
+ * in string_sub
+ */
+
+ filter = talloc_all_string_sub(talloc_tos(),
+ filter, "%u", escape_user);
+ SAFE_FREE(escape_user);
+ if (!filter) {
+ return LDAP_NO_MEMORY;
+ }
+
+ ret = smbldap_search_suffix(ldap_state->smbldap_state,
+ filter, attr, result);
+ TALLOC_FREE(filter);
+ return ret;
+}
+
+/*******************************************************************
+ Run the search by rid.
+******************************************************************/
+
+static int ldapsam_search_suffix_by_rid (struct ldapsam_privates *ldap_state,
+ uint32 rid, LDAPMessage ** result,
+ const char **attr)
+{
+ char *filter = NULL;
+ int rc;
+
+ filter = talloc_asprintf(talloc_tos(), "(&(rid=%i)%s)", rid,
+ get_objclass_filter(ldap_state->schema_ver));
+ if (!filter) {
+ return LDAP_NO_MEMORY;
+ }
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state,
+ filter, attr, result);
+ TALLOC_FREE(filter);
+ return rc;
+}
+
+/*******************************************************************
+ Run the search by SID.
+******************************************************************/
+
+static int ldapsam_search_suffix_by_sid (struct ldapsam_privates *ldap_state,
+ const DOM_SID *sid, LDAPMessage ** result,
+ const char **attr)
+{
+ char *filter = NULL;
+ int rc;
+ fstring sid_string;
+
+ filter = talloc_asprintf(talloc_tos(), "(&(%s=%s)%s)",
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_USER_SID),
+ sid_to_fstring(sid_string, sid),
+ get_objclass_filter(ldap_state->schema_ver));
+ if (!filter) {
+ return LDAP_NO_MEMORY;
+ }
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state,
+ filter, attr, result);
+
+ TALLOC_FREE(filter);
+ return rc;
+}
+
+/*******************************************************************
+ Delete complete object or objectclass and attrs from
+ object found in search_result depending on lp_ldap_delete_dn
+******************************************************************/
+
+static int ldapsam_delete_entry(struct ldapsam_privates *priv,
+ TALLOC_CTX *mem_ctx,
+ LDAPMessage *entry,
+ const char *objectclass,
+ const char **attrs)
+{
+ LDAPMod **mods = NULL;
+ char *name;
+ const char *dn;
+ BerElement *ptr = NULL;
+
+ dn = smbldap_talloc_dn(mem_ctx, priv2ld(priv), entry);
+ if (dn == NULL) {
+ return LDAP_NO_MEMORY;
+ }
+
+ if (lp_ldap_delete_dn()) {
+ return smbldap_delete(priv->smbldap_state, dn);
+ }
+
+ /* Ok, delete only the SAM attributes */
+
+ for (name = ldap_first_attribute(priv2ld(priv), entry, &ptr);
+ name != NULL;
+ name = ldap_next_attribute(priv2ld(priv), entry, ptr)) {
+ const char **attrib;
+
+ /* We are only allowed to delete the attributes that
+ really exist. */
+
+ for (attrib = attrs; *attrib != NULL; attrib++) {
+ if (strequal(*attrib, name)) {
+ DEBUG(10, ("ldapsam_delete_entry: deleting "
+ "attribute %s\n", name));
+ smbldap_set_mod(&mods, LDAP_MOD_DELETE, name,
+ NULL);
+ }
+ }
+ ldap_memfree(name);
+ }
+
+ if (ptr != NULL) {
+ ber_free(ptr, 0);
+ }
+
+ smbldap_set_mod(&mods, LDAP_MOD_DELETE, "objectClass", objectclass);
+ talloc_autofree_ldapmod(mem_ctx, mods);
+
+ return smbldap_modify(priv->smbldap_state, dn, mods);
+}
+
+static time_t ldapsam_get_entry_timestamp( struct ldapsam_privates *ldap_state, LDAPMessage * entry)
+{
+ char *temp;
+ struct tm tm;
+
+ temp = smbldap_talloc_single_attribute(ldap_state->smbldap_state->ldap_struct, entry,
+ get_userattr_key2string(ldap_state->schema_ver,LDAP_ATTR_MOD_TIMESTAMP),
+ talloc_tos());
+ if (!temp) {
+ return (time_t) 0;
+ }
+
+ if ( !strptime(temp, "%Y%m%d%H%M%SZ", &tm)) {
+ DEBUG(2,("ldapsam_get_entry_timestamp: strptime failed on: %s\n",
+ (char*)temp));
+ TALLOC_FREE(temp);
+ return (time_t) 0;
+ }
+ TALLOC_FREE(temp);
+ tzset();
+ return timegm(&tm);
+}
+
+/**********************************************************************
+ Initialize struct samu from an LDAP query.
+ (Based on init_sam_from_buffer in pdb_tdb.c)
+*********************************************************************/
+
+static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
+ struct samu * sampass,
+ LDAPMessage * entry)
+{
+ time_t logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time,
+ ldap_entry_time,
+ bad_password_time;
+ char *username = NULL,
+ *domain = NULL,
+ *nt_username = NULL,
+ *fullname = NULL,
+ *homedir = NULL,
+ *dir_drive = NULL,
+ *logon_script = NULL,
+ *profile_path = NULL,
+ *acct_desc = NULL,
+ *workstations = NULL,
+ *munged_dial = NULL;
+ uint32 user_rid;
+ uint8 smblmpwd[LM_HASH_LEN],
+ smbntpwd[NT_HASH_LEN];
+ bool use_samba_attrs = True;
+ uint32 acct_ctrl = 0;
+ uint16 logon_divs;
+ uint16 bad_password_count = 0,
+ logon_count = 0;
+ uint32 hours_len;
+ uint8 hours[MAX_HOURS_LEN];
+ char *temp = NULL;
+ LOGIN_CACHE *cache_entry = NULL;
+ uint32 pwHistLen;
+ bool expand_explicit = lp_passdb_expand_explicit();
+ bool ret = false;
+ TALLOC_CTX *ctx = talloc_init("init_sam_from_ldap");
+
+ if (!ctx) {
+ return false;
+ }
+ if (sampass == NULL || ldap_state == NULL || entry == NULL) {
+ DEBUG(0, ("init_sam_from_ldap: NULL parameters found!\n"));
+ goto fn_exit;
+ }
+
+ if (priv2ld(ldap_state) == NULL) {
+ DEBUG(0, ("init_sam_from_ldap: ldap_state->smbldap_state->"
+ "ldap_struct is NULL!\n"));
+ goto fn_exit;
+ }
+
+ if (!(username = smbldap_talloc_single_attribute(priv2ld(ldap_state),
+ entry,
+ "uid",
+ ctx))) {
+ DEBUG(1, ("init_sam_from_ldap: No uid attribute found for "
+ "this user!\n"));
+ goto fn_exit;
+ }
+
+ DEBUG(2, ("init_sam_from_ldap: Entry found for user: %s\n", username));
+
+ nt_username = talloc_strdup(ctx, username);
+ if (!nt_username) {
+ goto fn_exit;
+ }
+
+ domain = talloc_strdup(ctx, ldap_state->domain_name);
+ if (!domain) {
+ goto fn_exit;
+ }
+
+ pdb_set_username(sampass, username, PDB_SET);
+
+ pdb_set_domain(sampass, domain, PDB_DEFAULT);
+ pdb_set_nt_username(sampass, nt_username, PDB_SET);
+
+ /* deal with different attributes between the schema first */
+
+ if ( ldap_state->schema_ver == SCHEMAVER_SAMBASAMACCOUNT ) {
+ if ((temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_USER_SID),
+ ctx))!=NULL) {
+ pdb_set_user_sid_from_string(sampass, temp, PDB_SET);
+ }
+ } else {
+ if ((temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_USER_RID),
+ ctx))!=NULL) {
+ user_rid = (uint32)atol(temp);
+ pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
+ }
+ }
+
+ if (pdb_get_init_flags(sampass,PDB_USERSID) == PDB_DEFAULT) {
+ DEBUG(1, ("init_sam_from_ldap: no %s or %s attribute found for this user %s\n",
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_USER_SID),
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_USER_RID),
+ username));
+ return False;
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_PWD_LAST_SET),
+ ctx);
+ if (temp) {
+ pass_last_set_time = (time_t) atol(temp);
+ pdb_set_pass_last_set_time(sampass,
+ pass_last_set_time, PDB_SET);
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_LOGON_TIME),
+ ctx);
+ if (temp) {
+ logon_time = (time_t) atol(temp);
+ pdb_set_logon_time(sampass, logon_time, PDB_SET);
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_LOGOFF_TIME),
+ ctx);
+ if (temp) {
+ logoff_time = (time_t) atol(temp);
+ pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_KICKOFF_TIME),
+ ctx);
+ if (temp) {
+ kickoff_time = (time_t) atol(temp);
+ pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_PWD_CAN_CHANGE),
+ ctx);
+ if (temp) {
+ pass_can_change_time = (time_t) atol(temp);
+ pdb_set_pass_can_change_time(sampass,
+ pass_can_change_time, PDB_SET);
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_PWD_MUST_CHANGE),
+ ctx);
+ if (temp) {
+ pass_must_change_time = (time_t) atol(temp);
+ pdb_set_pass_must_change_time(sampass,
+ pass_must_change_time, PDB_SET);
+ }
+
+ /* recommend that 'gecos' and 'displayName' should refer to the same
+ * attribute OID. userFullName depreciated, only used by Samba
+ * primary rules of LDAP: don't make a new attribute when one is already defined
+ * that fits your needs; using cn then displayName rather than 'userFullName'
+ */
+
+ fullname = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_DISPLAY_NAME),
+ ctx);
+ if (fullname) {
+ pdb_set_fullname(sampass, fullname, PDB_SET);
+ } else {
+ fullname = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_CN),
+ ctx);
+ if (fullname) {
+ pdb_set_fullname(sampass, fullname, PDB_SET);
+ }
+ }
+
+ dir_drive = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_HOME_DRIVE),
+ ctx);
+ if (dir_drive) {
+ pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
+ } else {
+ pdb_set_dir_drive( sampass, lp_logon_drive(), PDB_DEFAULT );
+ }
+
+ homedir = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_HOME_PATH),
+ ctx);
+ if (homedir) {
+ if (expand_explicit) {
+ homedir = talloc_sub_basic(ctx,
+ username,
+ domain,
+ homedir);
+ if (!homedir) {
+ goto fn_exit;
+ }
+ }
+ pdb_set_homedir(sampass, homedir, PDB_SET);
+ } else {
+ pdb_set_homedir(sampass,
+ talloc_sub_basic(ctx, username, domain,
+ lp_logon_home()),
+ PDB_DEFAULT);
+ }
+
+ logon_script = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_LOGON_SCRIPT),
+ ctx);
+ if (logon_script) {
+ if (expand_explicit) {
+ logon_script = talloc_sub_basic(ctx,
+ username,
+ domain,
+ logon_script);
+ if (!logon_script) {
+ goto fn_exit;
+ }
+ }
+ pdb_set_logon_script(sampass, logon_script, PDB_SET);
+ } else {
+ pdb_set_logon_script(sampass,
+ talloc_sub_basic(ctx, username, domain,
+ lp_logon_script()),
+ PDB_DEFAULT );
+ }
+
+ profile_path = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_PROFILE_PATH),
+ ctx);
+ if (profile_path) {
+ if (expand_explicit) {
+ profile_path = talloc_sub_basic(ctx,
+ username,
+ domain,
+ profile_path);
+ if (!profile_path) {
+ goto fn_exit;
+ }
+ }
+ pdb_set_profile_path(sampass, profile_path, PDB_SET);
+ } else {
+ pdb_set_profile_path(sampass,
+ talloc_sub_basic(ctx, username, domain,
+ lp_logon_path()),
+ PDB_DEFAULT );
+ }
+
+ acct_desc = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_DESC),
+ ctx);
+ if (acct_desc) {
+ pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
+ }
+
+ workstations = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_USER_WKS),
+ ctx);
+ if (workstations) {
+ pdb_set_workstations(sampass, workstations, PDB_SET);
+ }
+
+ munged_dial = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_MUNGED_DIAL),
+ ctx);
+ if (munged_dial) {
+ pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
+ }
+
+ /* FIXME: hours stuff should be cleaner */
+
+ logon_divs = 168;
+ hours_len = 21;
+ memset(hours, 0xff, hours_len);
+
+ if (ldap_state->is_nds_ldap) {
+ char *user_dn;
+ size_t pwd_len;
+ char clear_text_pw[512];
+
+ /* Make call to Novell eDirectory ldap extension to get clear text password.
+ NOTE: This will only work if we have an SSL connection to eDirectory. */
+ user_dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry);
+ if (user_dn != NULL) {
+ DEBUG(3, ("init_sam_from_ldap: smbldap_get_dn(%s) returned '%s'\n", username, user_dn));
+
+ pwd_len = sizeof(clear_text_pw);
+ if (pdb_nds_get_password(ldap_state->smbldap_state, user_dn, &pwd_len, clear_text_pw) == LDAP_SUCCESS) {
+ nt_lm_owf_gen(clear_text_pw, smbntpwd, smblmpwd);
+ if (!pdb_set_lanman_passwd(sampass, smblmpwd, PDB_SET)) {
+ SAFE_FREE(user_dn);
+ return False;
+ }
+ ZERO_STRUCT(smblmpwd);
+ if (!pdb_set_nt_passwd(sampass, smbntpwd, PDB_SET)) {
+ SAFE_FREE(user_dn);
+ return False;
+ }
+ ZERO_STRUCT(smbntpwd);
+ use_samba_attrs = False;
+ }
+
+ SAFE_FREE(user_dn);
+
+ } else {
+ DEBUG(0, ("init_sam_from_ldap: failed to get user_dn for '%s'\n", username));
+ }
+ }
+
+ if (use_samba_attrs) {
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_LMPW),
+ ctx);
+ if (temp) {
+ pdb_gethexpwd(temp, smblmpwd);
+ memset((char *)temp, '\0', strlen(temp)+1);
+ if (!pdb_set_lanman_passwd(sampass, smblmpwd, PDB_SET)) {
+ goto fn_exit;
+ }
+ ZERO_STRUCT(smblmpwd);
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_NTPW),
+ ctx);
+ if (temp) {
+ pdb_gethexpwd(temp, smbntpwd);
+ memset((char *)temp, '\0', strlen(temp)+1);
+ if (!pdb_set_nt_passwd(sampass, smbntpwd, PDB_SET)) {
+ goto fn_exit;
+ }
+ ZERO_STRUCT(smbntpwd);
+ }
+ }
+
+ pwHistLen = 0;
+
+ pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen);
+ if (pwHistLen > 0){
+ uint8 *pwhist = NULL;
+ int i;
+ char *history_string = TALLOC_ARRAY(ctx, char,
+ MAX_PW_HISTORY_LEN*64);
+
+ if (!history_string) {
+ goto fn_exit;
+ }
+
+ pwHistLen = MIN(pwHistLen, MAX_PW_HISTORY_LEN);
+
+ if ((pwhist = TALLOC_ARRAY(ctx, uint8,
+ pwHistLen * PW_HISTORY_ENTRY_LEN)) ==
+ NULL){
+ DEBUG(0, ("init_sam_from_ldap: talloc failed!\n"));
+ goto fn_exit;
+ }
+ memset(pwhist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN);
+
+ if (smbldap_get_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_PWD_HISTORY),
+ history_string,
+ MAX_PW_HISTORY_LEN*64)) {
+ bool hex_failed = false;
+ for (i = 0; i < pwHistLen; i++){
+ /* Get the 16 byte salt. */
+ if (!pdb_gethexpwd(&history_string[i*64],
+ &pwhist[i*PW_HISTORY_ENTRY_LEN])) {
+ hex_failed = true;
+ break;
+ }
+ /* Get the 16 byte MD5 hash of salt+passwd. */
+ if (!pdb_gethexpwd(&history_string[(i*64)+32],
+ &pwhist[(i*PW_HISTORY_ENTRY_LEN)+
+ PW_HISTORY_SALT_LEN])) {
+ hex_failed = True;
+ break;
+ }
+ }
+ if (hex_failed) {
+ DEBUG(2,("init_sam_from_ldap: Failed to get password history for user %s\n",
+ username));
+ memset(pwhist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN);
+ }
+ }
+ if (!pdb_set_pw_history(sampass, pwhist, pwHistLen, PDB_SET)){
+ goto fn_exit;
+ }
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_ACB_INFO),
+ ctx);
+ if (temp) {
+ acct_ctrl = pdb_decode_acct_ctrl(temp);
+
+ if (acct_ctrl == 0) {
+ acct_ctrl |= ACB_NORMAL;
+ }
+
+ pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
+ } else {
+ acct_ctrl |= ACB_NORMAL;
+ }
+
+ pdb_set_hours_len(sampass, hours_len, PDB_SET);
+ pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
+
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_BAD_PASSWORD_COUNT),
+ ctx);
+ if (temp) {
+ bad_password_count = (uint32) atol(temp);
+ pdb_set_bad_password_count(sampass,
+ bad_password_count, PDB_SET);
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_BAD_PASSWORD_TIME),
+ ctx);
+ if (temp) {
+ bad_password_time = (time_t) atol(temp);
+ pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
+ }
+
+
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_LOGON_COUNT),
+ ctx);
+ if (temp) {
+ logon_count = (uint32) atol(temp);
+ pdb_set_logon_count(sampass, logon_count, PDB_SET);
+ }
+
+ /* pdb_set_unknown_6(sampass, unknown6, PDB_SET); */
+
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_LOGON_HOURS),
+ ctx);
+ if (temp) {
+ pdb_gethexhours(temp, hours);
+ memset((char *)temp, '\0', strlen(temp) +1);
+ pdb_set_hours(sampass, hours, PDB_SET);
+ ZERO_STRUCT(hours);
+ }
+
+ if (lp_parm_bool(-1, "ldapsam", "trusted", False)) {
+ temp = smbldap_talloc_single_attribute(
+ priv2ld(ldap_state),
+ entry,
+ "uidNumber",
+ ctx);
+ if (temp) {
+ /* We've got a uid, feed the cache */
+ uid_t uid = strtoul(temp, NULL, 10);
+ store_uid_sid_cache(pdb_get_user_sid(sampass), uid);
+ }
+ }
+
+ /* check the timestamp of the cache vs ldap entry */
+ if (!(ldap_entry_time = ldapsam_get_entry_timestamp(ldap_state,
+ entry))) {
+ ret = true;
+ goto fn_exit;
+ }
+
+ /* see if we have newer updates */
+ if (!(cache_entry = login_cache_read(sampass))) {
+ DEBUG (9, ("No cache entry, bad count = %u, bad time = %u\n",
+ (unsigned int)pdb_get_bad_password_count(sampass),
+ (unsigned int)pdb_get_bad_password_time(sampass)));
+ ret = true;
+ goto fn_exit;
+ }
+
+ DEBUG(7, ("ldap time is %u, cache time is %u, bad time = %u\n",
+ (unsigned int)ldap_entry_time,
+ (unsigned int)cache_entry->entry_timestamp,
+ (unsigned int)cache_entry->bad_password_time));
+
+ if (ldap_entry_time > cache_entry->entry_timestamp) {
+ /* cache is older than directory , so
+ we need to delete the entry but allow the
+ fields to be written out */
+ login_cache_delentry(sampass);
+ } else {
+ /* read cache in */
+ pdb_set_acct_ctrl(sampass,
+ pdb_get_acct_ctrl(sampass) |
+ (cache_entry->acct_ctrl & ACB_AUTOLOCK),
+ PDB_SET);
+ pdb_set_bad_password_count(sampass,
+ cache_entry->bad_password_count,
+ PDB_SET);
+ pdb_set_bad_password_time(sampass,
+ cache_entry->bad_password_time,
+ PDB_SET);
+ }
+
+ ret = true;
+
+ fn_exit:
+
+ TALLOC_FREE(ctx);
+ SAFE_FREE(cache_entry);
+ return ret;
+}
+
+/**********************************************************************
+ Initialize the ldap db from a struct samu. Called on update.
+ (Based on init_buffer_from_sam in pdb_tdb.c)
+*********************************************************************/
+
+static bool init_ldap_from_sam (struct ldapsam_privates *ldap_state,
+ LDAPMessage *existing,
+ LDAPMod *** mods, struct samu * sampass,
+ bool (*need_update)(const struct samu *,
+ enum pdb_elements))
+{
+ char *temp = NULL;
+ uint32 rid;
+
+ if (mods == NULL || sampass == NULL) {
+ DEBUG(0, ("init_ldap_from_sam: NULL parameters found!\n"));
+ return False;
+ }
+
+ *mods = NULL;
+
+ /*
+ * took out adding "objectclass: sambaAccount"
+ * do this on a per-mod basis
+ */
+ if (need_update(sampass, PDB_USERNAME)) {
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ "uid", pdb_get_username(sampass));
+ if (ldap_state->is_nds_ldap) {
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ "cn", pdb_get_username(sampass));
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ "sn", pdb_get_username(sampass));
+ }
+ }
+
+ DEBUG(2, ("init_ldap_from_sam: Setting entry for user: %s\n", pdb_get_username(sampass)));
+
+ /* only update the RID if we actually need to */
+ if (need_update(sampass, PDB_USERSID)) {
+ fstring sid_string;
+ const DOM_SID *user_sid = pdb_get_user_sid(sampass);
+
+ switch ( ldap_state->schema_ver ) {
+ case SCHEMAVER_SAMBAACCOUNT:
+ if (!sid_peek_check_rid(&ldap_state->domain_sid, user_sid, &rid)) {
+ DEBUG(1, ("init_ldap_from_sam: User's SID (%s) is not for this domain (%s), cannot add to LDAP!\n",
+ sid_string_dbg(user_sid),
+ sid_string_dbg(
+ &ldap_state->domain_sid)));
+ return False;
+ }
+ if (asprintf(&temp, "%i", rid) < 0) {
+ return false;
+ }
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_RID),
+ temp);
+ SAFE_FREE(temp);
+ break;
+
+ case SCHEMAVER_SAMBASAMACCOUNT:
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID),
+ sid_to_fstring(sid_string, user_sid));
+ break;
+
+ default:
+ DEBUG(0,("init_ldap_from_sam: unknown schema version specified\n"));
+ break;
+ }
+ }
+
+ /* we don't need to store the primary group RID - so leaving it
+ 'free' to hang off the unix primary group makes life easier */
+
+ if (need_update(sampass, PDB_GROUPSID)) {
+ fstring sid_string;
+ const DOM_SID *group_sid = pdb_get_group_sid(sampass);
+
+ switch ( ldap_state->schema_ver ) {
+ case SCHEMAVER_SAMBAACCOUNT:
+ if (!sid_peek_check_rid(&ldap_state->domain_sid, group_sid, &rid)) {
+ DEBUG(1, ("init_ldap_from_sam: User's Primary Group SID (%s) is not for this domain (%s), cannot add to LDAP!\n",
+ sid_string_dbg(group_sid),
+ sid_string_dbg(
+ &ldap_state->domain_sid)));
+ return False;
+ }
+
+ if (asprintf(&temp, "%i", rid) < 0) {
+ return false;
+ }
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_PRIMARY_GROUP_RID), temp);
+ SAFE_FREE(temp);
+ break;
+
+ case SCHEMAVER_SAMBASAMACCOUNT:
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_PRIMARY_GROUP_SID), sid_to_fstring(sid_string, group_sid));
+ break;
+
+ default:
+ DEBUG(0,("init_ldap_from_sam: unknown schema version specified\n"));
+ break;
+ }
+
+ }
+
+ /* displayName, cn, and gecos should all be the same
+ * most easily accomplished by giving them the same OID
+ * gecos isn't set here b/c it should be handled by the
+ * add-user script
+ * We change displayName only and fall back to cn if
+ * it does not exist.
+ */
+
+ if (need_update(sampass, PDB_FULLNAME))
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_DISPLAY_NAME),
+ pdb_get_fullname(sampass));
+
+ if (need_update(sampass, PDB_ACCTDESC))
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_DESC),
+ pdb_get_acct_desc(sampass));
+
+ if (need_update(sampass, PDB_WORKSTATIONS))
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_WKS),
+ pdb_get_workstations(sampass));
+
+ if (need_update(sampass, PDB_MUNGEDDIAL))
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_MUNGED_DIAL),
+ pdb_get_munged_dial(sampass));
+
+ if (need_update(sampass, PDB_SMBHOME))
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_PATH),
+ pdb_get_homedir(sampass));
+
+ if (need_update(sampass, PDB_DRIVE))
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_DRIVE),
+ pdb_get_dir_drive(sampass));
+
+ if (need_update(sampass, PDB_LOGONSCRIPT))
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_SCRIPT),
+ pdb_get_logon_script(sampass));
+
+ if (need_update(sampass, PDB_PROFILE))
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PROFILE_PATH),
+ pdb_get_profile_path(sampass));
+
+ if (asprintf(&temp, "%li", pdb_get_logon_time(sampass)) < 0) {
+ return false;
+ }
+ if (need_update(sampass, PDB_LOGONTIME))
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_TIME), temp);
+ SAFE_FREE(temp);
+
+ if (asprintf(&temp, "%li", pdb_get_logoff_time(sampass)) < 0) {
+ return false;
+ }
+ if (need_update(sampass, PDB_LOGOFFTIME))
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGOFF_TIME), temp);
+ SAFE_FREE(temp);
+
+ if (asprintf(&temp, "%li", pdb_get_kickoff_time(sampass)) < 0) {
+ return false;
+ }
+ if (need_update(sampass, PDB_KICKOFFTIME))
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_KICKOFF_TIME), temp);
+ SAFE_FREE(temp);
+
+ if (asprintf(&temp, "%li", pdb_get_pass_can_change_time_noncalc(sampass)) < 0) {
+ return false;
+ }
+ if (need_update(sampass, PDB_CANCHANGETIME))
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_CAN_CHANGE), temp);
+ SAFE_FREE(temp);
+
+ if (asprintf(&temp, "%li", pdb_get_pass_must_change_time(sampass)) < 0) {
+ return false;
+ }
+ if (need_update(sampass, PDB_MUSTCHANGETIME))
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_MUST_CHANGE), temp);
+ SAFE_FREE(temp);
+
+ if ((pdb_get_acct_ctrl(sampass)&(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST))
+ || (lp_ldap_passwd_sync()!=LDAP_PASSWD_SYNC_ONLY)) {
+
+ if (need_update(sampass, PDB_LMPASSWD)) {
+ const uchar *lm_pw = pdb_get_lanman_passwd(sampass);
+ if (lm_pw) {
+ char pwstr[34];
+ pdb_sethexpwd(pwstr, lm_pw,
+ pdb_get_acct_ctrl(sampass));
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LMPW),
+ pwstr);
+ } else {
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LMPW),
+ NULL);
+ }
+ }
+ if (need_update(sampass, PDB_NTPASSWD)) {
+ const uchar *nt_pw = pdb_get_nt_passwd(sampass);
+ if (nt_pw) {
+ char pwstr[34];
+ pdb_sethexpwd(pwstr, nt_pw,
+ pdb_get_acct_ctrl(sampass));
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_NTPW),
+ pwstr);
+ } else {
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_NTPW),
+ NULL);
+ }
+ }
+
+ if (need_update(sampass, PDB_PWHISTORY)) {
+ char *pwstr = NULL;
+ uint32 pwHistLen = 0;
+ pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen);
+
+ pwstr = SMB_MALLOC_ARRAY(char, 1024);
+ if (!pwstr) {
+ return false;
+ }
+ if (pwHistLen == 0) {
+ /* Remove any password history from the LDAP store. */
+ memset(pwstr, '0', 64); /* NOTE !!!! '0' *NOT '\0' */
+ pwstr[64] = '\0';
+ } else {
+ int i;
+ uint32 currHistLen = 0;
+ const uint8 *pwhist = pdb_get_pw_history(sampass, &currHistLen);
+ if (pwhist != NULL) {
+ /* We can only store (1024-1/64 password history entries. */
+ pwHistLen = MIN(pwHistLen, ((1024-1)/64));
+ for (i=0; i< pwHistLen && i < currHistLen; i++) {
+ /* Store the salt. */
+ pdb_sethexpwd(&pwstr[i*64], &pwhist[i*PW_HISTORY_ENTRY_LEN], 0);
+ /* Followed by the md5 hash of salt + md4 hash */
+ pdb_sethexpwd(&pwstr[(i*64)+32],
+ &pwhist[(i*PW_HISTORY_ENTRY_LEN)+PW_HISTORY_SALT_LEN], 0);
+ DEBUG(100, ("pwstr=%s\n", pwstr));
+ }
+ }
+ }
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_HISTORY),
+ pwstr);
+ SAFE_FREE(pwstr);
+ }
+
+ if (need_update(sampass, PDB_PASSLASTSET)) {
+ if (asprintf(&temp, "%li",
+ pdb_get_pass_last_set_time(sampass)) < 0) {
+ return false;
+ }
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_LAST_SET),
+ temp);
+ SAFE_FREE(temp);
+ }
+ }
+
+ if (need_update(sampass, PDB_HOURS)) {
+ const uint8 *hours = pdb_get_hours(sampass);
+ if (hours) {
+ char hourstr[44];
+ pdb_sethexhours(hourstr, hours);
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct,
+ existing,
+ mods,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_LOGON_HOURS),
+ hourstr);
+ }
+ }
+
+ if (need_update(sampass, PDB_ACCTCTRL))
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_ACB_INFO),
+ pdb_encode_acct_ctrl (pdb_get_acct_ctrl(sampass), NEW_PW_FORMAT_SPACE_PADDED_LEN));
+
+ /* password lockout cache:
+ - If we are now autolocking or clearing, we write to ldap
+ - If we are clearing, we delete the cache entry
+ - If the count is > 0, we update the cache
+
+ This even means when autolocking, we cache, just in case the
+ update doesn't work, and we have to cache the autolock flag */
+
+ if (need_update(sampass, PDB_BAD_PASSWORD_COUNT)) /* &&
+ need_update(sampass, PDB_BAD_PASSWORD_TIME)) */ {
+ uint16 badcount = pdb_get_bad_password_count(sampass);
+ time_t badtime = pdb_get_bad_password_time(sampass);
+ uint32 pol;
+ pdb_get_account_policy(AP_BAD_ATTEMPT_LOCKOUT, &pol);
+
+ DEBUG(3, ("updating bad password fields, policy=%u, count=%u, time=%u\n",
+ (unsigned int)pol, (unsigned int)badcount, (unsigned int)badtime));
+
+ if ((badcount >= pol) || (badcount == 0)) {
+ DEBUG(7, ("making mods to update ldap, count=%u, time=%u\n",
+ (unsigned int)badcount, (unsigned int)badtime));
+ if (asprintf(&temp, "%li", (long)badcount) < 0) {
+ return false;
+ }
+ smbldap_make_mod(
+ ldap_state->smbldap_state->ldap_struct,
+ existing, mods,
+ get_userattr_key2string(
+ ldap_state->schema_ver,
+ LDAP_ATTR_BAD_PASSWORD_COUNT),
+ temp);
+ SAFE_FREE(temp);
+
+ if (asprintf(&temp, "%li", badtime) < 0) {
+ return false;
+ }
+ smbldap_make_mod(
+ ldap_state->smbldap_state->ldap_struct,
+ existing, mods,
+ get_userattr_key2string(
+ ldap_state->schema_ver,
+ LDAP_ATTR_BAD_PASSWORD_TIME),
+ temp);
+ SAFE_FREE(temp);
+ }
+ if (badcount == 0) {
+ DEBUG(7, ("bad password count is reset, deleting login cache entry for %s\n", pdb_get_nt_username(sampass)));
+ login_cache_delentry(sampass);
+ } else {
+ LOGIN_CACHE cache_entry;
+
+ cache_entry.entry_timestamp = time(NULL);
+ cache_entry.acct_ctrl = pdb_get_acct_ctrl(sampass);
+ cache_entry.bad_password_count = badcount;
+ cache_entry.bad_password_time = badtime;
+
+ DEBUG(7, ("Updating bad password count and time in login cache\n"));
+ login_cache_write(sampass, cache_entry);
+ }
+ }
+
+ return True;
+}
+
+/**********************************************************************
+ End enumeration of the LDAP password list.
+*********************************************************************/
+
+static void ldapsam_endsampwent(struct pdb_methods *my_methods)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ if (ldap_state->result) {
+ ldap_msgfree(ldap_state->result);
+ ldap_state->result = NULL;
+ }
+}
+
+static void append_attr(TALLOC_CTX *mem_ctx, const char ***attr_list,
+ const char *new_attr)
+{
+ int i;
+
+ if (new_attr == NULL) {
+ return;
+ }
+
+ for (i=0; (*attr_list)[i] != NULL; i++) {
+ ;
+ }
+
+ (*attr_list) = TALLOC_REALLOC_ARRAY(mem_ctx, (*attr_list),
+ const char *, i+2);
+ SMB_ASSERT((*attr_list) != NULL);
+ (*attr_list)[i] = talloc_strdup((*attr_list), new_attr);
+ (*attr_list)[i+1] = NULL;
+}
+
+/**********************************************************************
+Get struct samu entry from LDAP by username.
+*********************************************************************/
+
+static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, struct samu *user, const char *sname)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int count;
+ const char ** attr_list;
+ int rc;
+
+ attr_list = get_userattr_list( user, ldap_state->schema_ver );
+ append_attr(user, &attr_list,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_MOD_TIMESTAMP));
+ append_attr(user, &attr_list, "uidNumber");
+ rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result,
+ attr_list);
+ TALLOC_FREE( attr_list );
+
+ if ( rc != LDAP_SUCCESS )
+ return NT_STATUS_NO_SUCH_USER;
+
+ count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result);
+
+ if (count < 1) {
+ DEBUG(4, ("ldapsam_getsampwnam: Unable to locate user [%s] count=%d\n", sname, count));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_USER;
+ } else if (count > 1) {
+ DEBUG(1, ("ldapsam_getsampwnam: Duplicate entries for this user [%s] Failing. count=%d\n", sname, count));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result);
+ if (entry) {
+ if (!init_sam_from_ldap(ldap_state, user, entry)) {
+ DEBUG(1,("ldapsam_getsampwnam: init_sam_from_ldap failed for user '%s'!\n", sname));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+ pdb_set_backend_private_data(user, result, NULL,
+ my_methods, PDB_CHANGED);
+ talloc_autofree_ldapmsg(user, result);
+ ret = NT_STATUS_OK;
+ } else {
+ ldap_msgfree(result);
+ }
+ return ret;
+}
+
+static int ldapsam_get_ldap_user_by_sid(struct ldapsam_privates *ldap_state,
+ const DOM_SID *sid, LDAPMessage **result)
+{
+ int rc = -1;
+ const char ** attr_list;
+ uint32 rid;
+
+ switch ( ldap_state->schema_ver ) {
+ case SCHEMAVER_SAMBASAMACCOUNT: {
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return LDAP_NO_MEMORY;
+ }
+
+ attr_list = get_userattr_list(tmp_ctx,
+ ldap_state->schema_ver);
+ append_attr(tmp_ctx, &attr_list,
+ get_userattr_key2string(
+ ldap_state->schema_ver,
+ LDAP_ATTR_MOD_TIMESTAMP));
+ append_attr(tmp_ctx, &attr_list, "uidNumber");
+ rc = ldapsam_search_suffix_by_sid(ldap_state, sid,
+ result, attr_list);
+ TALLOC_FREE(tmp_ctx);
+
+ if ( rc != LDAP_SUCCESS )
+ return rc;
+ break;
+ }
+
+ case SCHEMAVER_SAMBAACCOUNT:
+ if (!sid_peek_check_rid(&ldap_state->domain_sid, sid, &rid)) {
+ return rc;
+ }
+
+ attr_list = get_userattr_list(NULL,
+ ldap_state->schema_ver);
+ rc = ldapsam_search_suffix_by_rid(ldap_state, rid, result, attr_list );
+ TALLOC_FREE( attr_list );
+
+ if ( rc != LDAP_SUCCESS )
+ return rc;
+ break;
+ }
+ return rc;
+}
+
+/**********************************************************************
+ Get struct samu entry from LDAP by SID.
+*********************************************************************/
+
+static NTSTATUS ldapsam_getsampwsid(struct pdb_methods *my_methods, struct samu * user, const DOM_SID *sid)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int count;
+ int rc;
+
+ rc = ldapsam_get_ldap_user_by_sid(ldap_state,
+ sid, &result);
+ if (rc != LDAP_SUCCESS)
+ return NT_STATUS_NO_SUCH_USER;
+
+ count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result);
+
+ if (count < 1) {
+ DEBUG(4, ("ldapsam_getsampwsid: Unable to locate SID [%s] "
+ "count=%d\n", sid_string_dbg(sid), count));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_USER;
+ } else if (count > 1) {
+ DEBUG(1, ("ldapsam_getsampwsid: More than one user with SID "
+ "[%s]. Failing. count=%d\n", sid_string_dbg(sid),
+ count));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result);
+ if (!entry) {
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (!init_sam_from_ldap(ldap_state, user, entry)) {
+ DEBUG(1,("ldapsam_getsampwsid: init_sam_from_ldap failed!\n"));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ pdb_set_backend_private_data(user, result, NULL,
+ my_methods, PDB_CHANGED);
+ talloc_autofree_ldapmsg(user, result);
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+ Do the actual modification - also change a plaintext passord if
+ it it set.
+**********************************************************************/
+
+static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods,
+ struct samu *newpwd, char *dn,
+ LDAPMod **mods, int ldap_op,
+ bool (*need_update)(const struct samu *, enum pdb_elements))
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ int rc;
+
+ if (!newpwd || !dn) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!mods) {
+ DEBUG(5,("ldapsam_modify_entry: mods is empty: nothing to modify\n"));
+ /* may be password change below however */
+ } else {
+ switch(ldap_op) {
+ case LDAP_MOD_ADD:
+ if (ldap_state->is_nds_ldap) {
+ smbldap_set_mod(&mods, LDAP_MOD_ADD,
+ "objectclass",
+ "inetOrgPerson");
+ } else {
+ smbldap_set_mod(&mods, LDAP_MOD_ADD,
+ "objectclass",
+ LDAP_OBJ_ACCOUNT);
+ }
+ rc = smbldap_add(ldap_state->smbldap_state,
+ dn, mods);
+ break;
+ case LDAP_MOD_REPLACE:
+ rc = smbldap_modify(ldap_state->smbldap_state,
+ dn ,mods);
+ break;
+ default:
+ DEBUG(0,("ldapsam_modify_entry: Wrong LDAP operation type: %d!\n",
+ ldap_op));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (rc!=LDAP_SUCCESS) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ if (!(pdb_get_acct_ctrl(newpwd)&(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST)) &&
+ (lp_ldap_passwd_sync() != LDAP_PASSWD_SYNC_OFF) &&
+ need_update(newpwd, PDB_PLAINTEXT_PW) &&
+ (pdb_get_plaintext_passwd(newpwd)!=NULL)) {
+ BerElement *ber;
+ struct berval *bv;
+ char *retoid = NULL;
+ struct berval *retdata = NULL;
+ char *utf8_password;
+ char *utf8_dn;
+ size_t converted_size;
+
+ if (!ldap_state->is_nds_ldap) {
+
+ if (!smbldap_has_extension(ldap_state->smbldap_state->ldap_struct,
+ LDAP_EXOP_MODIFY_PASSWD)) {
+ DEBUG(2, ("ldap password change requested, but LDAP "
+ "server does not support it -- ignoring\n"));
+ return NT_STATUS_OK;
+ }
+ }
+
+ if (!push_utf8_allocate(&utf8_password,
+ pdb_get_plaintext_passwd(newpwd),
+ &converted_size))
+ {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!push_utf8_allocate(&utf8_dn, dn, &converted_size)) {
+ SAFE_FREE(utf8_password);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ((ber = ber_alloc_t(LBER_USE_DER))==NULL) {
+ DEBUG(0,("ber_alloc_t returns NULL\n"));
+ SAFE_FREE(utf8_password);
+ SAFE_FREE(utf8_dn);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if ((ber_printf (ber, "{") < 0) ||
+ (ber_printf (ber, "ts", LDAP_TAG_EXOP_MODIFY_PASSWD_ID, utf8_dn) < 0) ||
+ (ber_printf (ber, "ts", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, utf8_password) < 0) ||
+ (ber_printf (ber, "n}") < 0)) {
+ DEBUG(0,("ldapsam_modify_entry: ber_printf returns a value <0\n"));
+ ber_free(ber,1);
+ SAFE_FREE(utf8_dn);
+ SAFE_FREE(utf8_password);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if ((rc = ber_flatten (ber, &bv))<0) {
+ DEBUG(0,("ldapsam_modify_entry: ber_flatten returns a value <0\n"));
+ ber_free(ber,1);
+ SAFE_FREE(utf8_dn);
+ SAFE_FREE(utf8_password);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ SAFE_FREE(utf8_dn);
+ SAFE_FREE(utf8_password);
+ ber_free(ber, 1);
+
+ if (!ldap_state->is_nds_ldap) {
+ rc = smbldap_extended_operation(ldap_state->smbldap_state,
+ LDAP_EXOP_MODIFY_PASSWD,
+ bv, NULL, NULL, &retoid,
+ &retdata);
+ } else {
+ rc = pdb_nds_set_password(ldap_state->smbldap_state, dn,
+ pdb_get_plaintext_passwd(newpwd));
+ }
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error = NULL;
+
+ if (rc == LDAP_OBJECT_CLASS_VIOLATION) {
+ DEBUG(3, ("Could not set userPassword "
+ "attribute due to an objectClass "
+ "violation -- ignoring\n"));
+ ber_bvfree(bv);
+ return NT_STATUS_OK;
+ }
+
+ ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
+ &ld_error);
+ DEBUG(0,("ldapsam_modify_entry: LDAP Password could not be changed for user %s: %s\n\t%s\n",
+ pdb_get_username(newpwd), ldap_err2string(rc), ld_error?ld_error:"unknown"));
+ SAFE_FREE(ld_error);
+ ber_bvfree(bv);
+#if defined(LDAP_CONSTRAINT_VIOLATION)
+ if (rc == LDAP_CONSTRAINT_VIOLATION)
+ return NT_STATUS_PASSWORD_RESTRICTION;
+#endif
+ return NT_STATUS_UNSUCCESSFUL;
+ } else {
+ DEBUG(3,("ldapsam_modify_entry: LDAP Password changed for user %s\n",pdb_get_username(newpwd)));
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("ldapsam_modify_entry: LDAP Password changed to %s\n",pdb_get_plaintext_passwd(newpwd)));
+#endif
+ if (retdata)
+ ber_bvfree(retdata);
+ if (retoid)
+ ldap_memfree(retoid);
+ }
+ ber_bvfree(bv);
+ }
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Delete entry from LDAP for username.
+*********************************************************************/
+
+static NTSTATUS ldapsam_delete_sam_account(struct pdb_methods *my_methods,
+ struct samu * sam_acct)
+{
+ struct ldapsam_privates *priv =
+ (struct ldapsam_privates *)my_methods->private_data;
+ const char *sname;
+ int rc;
+ LDAPMessage *msg, *entry;
+ NTSTATUS result = NT_STATUS_NO_MEMORY;
+ const char **attr_list;
+ TALLOC_CTX *mem_ctx;
+
+ if (!sam_acct) {
+ DEBUG(0, ("ldapsam_delete_sam_account: sam_acct was NULL!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ sname = pdb_get_username(sam_acct);
+
+ DEBUG(3, ("ldapsam_delete_sam_account: Deleting user %s from "
+ "LDAP.\n", sname));
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ goto done;
+ }
+
+ attr_list = get_userattr_delete_list(mem_ctx, priv->schema_ver );
+ if (attr_list == NULL) {
+ goto done;
+ }
+
+ rc = ldapsam_search_suffix_by_name(priv, sname, &msg, attr_list);
+
+ if ((rc != LDAP_SUCCESS) ||
+ (ldap_count_entries(priv2ld(priv), msg) != 1) ||
+ ((entry = ldap_first_entry(priv2ld(priv), msg)) == NULL)) {
+ DEBUG(5, ("Could not find user %s\n", sname));
+ result = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ }
+
+ rc = ldapsam_delete_entry(
+ priv, mem_ctx, entry,
+ priv->schema_ver == SCHEMAVER_SAMBASAMACCOUNT ?
+ LDAP_OBJ_SAMBASAMACCOUNT : LDAP_OBJ_SAMBAACCOUNT,
+ attr_list);
+
+ result = (rc == LDAP_SUCCESS) ?
+ NT_STATUS_OK : NT_STATUS_ACCESS_DENIED;
+
+ done:
+ TALLOC_FREE(mem_ctx);
+ return result;
+}
+
+/**********************************************************************
+ Helper function to determine for update_sam_account whether
+ we need LDAP modification.
+*********************************************************************/
+
+static bool element_is_changed(const struct samu *sampass,
+ enum pdb_elements element)
+{
+ return IS_SAM_CHANGED(sampass, element);
+}
+
+/**********************************************************************
+ Update struct samu.
+*********************************************************************/
+
+static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, struct samu * newpwd)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ int rc = 0;
+ char *dn;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ LDAPMod **mods = NULL;
+ const char **attr_list;
+
+ result = (LDAPMessage *)pdb_get_backend_private_data(newpwd, my_methods);
+ if (!result) {
+ attr_list = get_userattr_list(NULL, ldap_state->schema_ver);
+ if (pdb_get_username(newpwd) == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ rc = ldapsam_search_suffix_by_name(ldap_state, pdb_get_username(newpwd), &result, attr_list );
+ TALLOC_FREE( attr_list );
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ pdb_set_backend_private_data(newpwd, result, NULL,
+ my_methods, PDB_CHANGED);
+ talloc_autofree_ldapmsg(newpwd, result);
+ }
+
+ if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) == 0) {
+ DEBUG(0, ("ldapsam_update_sam_account: No user to modify!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result);
+ dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry);
+ if (!dn) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(4, ("ldapsam_update_sam_account: user %s to be modified has dn: %s\n", pdb_get_username(newpwd), dn));
+
+ if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd,
+ element_is_changed)) {
+ DEBUG(0, ("ldapsam_update_sam_account: init_ldap_from_sam failed!\n"));
+ SAFE_FREE(dn);
+ if (mods != NULL)
+ ldap_mods_free(mods,True);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if ((lp_ldap_passwd_sync() != LDAP_PASSWD_SYNC_ONLY)
+ && (mods == NULL)) {
+ DEBUG(4,("ldapsam_update_sam_account: mods is empty: nothing to update for user: %s\n",
+ pdb_get_username(newpwd)));
+ SAFE_FREE(dn);
+ return NT_STATUS_OK;
+ }
+
+ ret = ldapsam_modify_entry(my_methods,newpwd,dn,mods,LDAP_MOD_REPLACE, element_is_changed);
+
+ if (mods != NULL) {
+ ldap_mods_free(mods,True);
+ }
+
+ SAFE_FREE(dn);
+
+ /*
+ * We need to set the backend private data to NULL here. For example
+ * setuserinfo level 25 does a pdb_update_sam_account twice on the
+ * same one, and with the explicit delete / add logic for attribute
+ * values the second time we would use the wrong "old" value which
+ * does not exist in LDAP anymore. Thus the LDAP server would refuse
+ * the update.
+ * The existing LDAPMessage is still being auto-freed by the
+ * destructor.
+ */
+ pdb_set_backend_private_data(newpwd, NULL, NULL, my_methods,
+ PDB_CHANGED);
+
+ if (!NT_STATUS_IS_OK(ret)) {
+ return ret;
+ }
+
+ DEBUG(2, ("ldapsam_update_sam_account: successfully modified uid = %s in the LDAP database\n",
+ pdb_get_username(newpwd)));
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ Renames a struct samu
+ - The "rename user script" has full responsibility for changing everything
+***************************************************************************/
+
+static NTSTATUS ldapsam_rename_sam_account(struct pdb_methods *my_methods,
+ struct samu *old_acct,
+ const char *newname)
+{
+ const char *oldname;
+ int rc;
+ char *rename_script = NULL;
+ fstring oldname_lower, newname_lower;
+
+ if (!old_acct) {
+ DEBUG(0, ("ldapsam_rename_sam_account: old_acct was NULL!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ if (!newname) {
+ DEBUG(0, ("ldapsam_rename_sam_account: newname was NULL!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ oldname = pdb_get_username(old_acct);
+
+ /* rename the posix user */
+ rename_script = SMB_STRDUP(lp_renameuser_script());
+ if (rename_script == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!(*rename_script)) {
+ SAFE_FREE(rename_script);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ DEBUG (3, ("ldapsam_rename_sam_account: Renaming user %s to %s.\n",
+ oldname, newname));
+
+ /* We have to allow the account name to end with a '$'.
+ Also, follow the semantics in _samr_create_user() and lower case the
+ posix name but preserve the case in passdb */
+
+ fstrcpy( oldname_lower, oldname );
+ strlower_m( oldname_lower );
+ fstrcpy( newname_lower, newname );
+ strlower_m( newname_lower );
+ rename_script = realloc_string_sub2(rename_script,
+ "%unew",
+ newname_lower,
+ true,
+ true);
+ if (rename_script) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ rename_script = realloc_string_sub2(rename_script,
+ "%uold",
+ oldname_lower,
+ true,
+ true);
+ rc = smbrun(rename_script, NULL);
+
+ DEBUG(rc ? 0 : 3,("Running the command `%s' gave %d\n",
+ rename_script, rc));
+
+ SAFE_FREE(rename_script);
+
+ if (rc == 0) {
+ smb_nscd_flush_user_cache();
+ }
+
+ if (rc)
+ return NT_STATUS_UNSUCCESSFUL;
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Helper function to determine for update_sam_account whether
+ we need LDAP modification.
+ *********************************************************************/
+
+static bool element_is_set_or_changed(const struct samu *sampass,
+ enum pdb_elements element)
+{
+ return (IS_SAM_SET(sampass, element) ||
+ IS_SAM_CHANGED(sampass, element));
+}
+
+/**********************************************************************
+ Add struct samu to LDAP.
+*********************************************************************/
+
+static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, struct samu * newpwd)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ int rc;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ LDAPMod **mods = NULL;
+ int ldap_op = LDAP_MOD_REPLACE;
+ uint32 num_result;
+ const char **attr_list;
+ char *escape_user = NULL;
+ const char *username = pdb_get_username(newpwd);
+ const DOM_SID *sid = pdb_get_user_sid(newpwd);
+ char *filter = NULL;
+ char *dn = NULL;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ TALLOC_CTX *ctx = talloc_init("ldapsam_add_sam_account");
+
+ if (!ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!username || !*username) {
+ DEBUG(0, ("ldapsam_add_sam_account: Cannot add user without a username!\n"));
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fn_exit;
+ }
+
+ /* free this list after the second search or in case we exit on failure */
+ attr_list = get_userattr_list(ctx, ldap_state->schema_ver);
+
+ rc = ldapsam_search_suffix_by_name (ldap_state, username, &result, attr_list);
+
+ if (rc != LDAP_SUCCESS) {
+ goto fn_exit;
+ }
+
+ if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) != 0) {
+ DEBUG(0,("ldapsam_add_sam_account: User '%s' already in the base, with samba attributes\n",
+ username));
+ goto fn_exit;
+ }
+ ldap_msgfree(result);
+ result = NULL;
+
+ if (element_is_set_or_changed(newpwd, PDB_USERSID)) {
+ rc = ldapsam_get_ldap_user_by_sid(ldap_state,
+ sid, &result);
+ if (rc == LDAP_SUCCESS) {
+ if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) != 0) {
+ DEBUG(0,("ldapsam_add_sam_account: SID '%s' "
+ "already in the base, with samba "
+ "attributes\n", sid_string_dbg(sid)));
+ goto fn_exit;
+ }
+ ldap_msgfree(result);
+ result = NULL;
+ }
+ }
+
+ /* does the entry already exist but without a samba attributes?
+ we need to return the samba attributes here */
+
+ escape_user = escape_ldap_string_alloc( username );
+ filter = talloc_strdup(attr_list, "(uid=%u)");
+ if (!filter) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fn_exit;
+ }
+ filter = talloc_all_string_sub(attr_list, filter, "%u", escape_user);
+ if (!filter) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fn_exit;
+ }
+ SAFE_FREE(escape_user);
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state,
+ filter, attr_list, &result);
+ if ( rc != LDAP_SUCCESS ) {
+ goto fn_exit;
+ }
+
+ num_result = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result);
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_add_sam_account: More than one user with that uid exists: bailing out!\n"));
+ goto fn_exit;
+ }
+
+ /* Check if we need to update an existing entry */
+ if (num_result == 1) {
+ char *tmp;
+
+ DEBUG(3,("ldapsam_add_sam_account: User exists without samba attributes: adding them\n"));
+ ldap_op = LDAP_MOD_REPLACE;
+ entry = ldap_first_entry (ldap_state->smbldap_state->ldap_struct, result);
+ tmp = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry);
+ if (!tmp) {
+ goto fn_exit;
+ }
+ dn = talloc_asprintf(ctx, "%s", tmp);
+ SAFE_FREE(tmp);
+ if (!dn) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fn_exit;
+ }
+
+ } else if (ldap_state->schema_ver == SCHEMAVER_SAMBASAMACCOUNT) {
+
+ /* There might be a SID for this account already - say an idmap entry */
+
+ filter = talloc_asprintf(ctx,
+ "(&(%s=%s)(|(objectClass=%s)(objectClass=%s)))",
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_USER_SID),
+ sid_string_talloc(ctx, sid),
+ LDAP_OBJ_IDMAP_ENTRY,
+ LDAP_OBJ_SID_ENTRY);
+ if (!filter) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fn_exit;
+ }
+
+ /* free old result before doing a new search */
+ if (result != NULL) {
+ ldap_msgfree(result);
+ result = NULL;
+ }
+ rc = smbldap_search_suffix(ldap_state->smbldap_state,
+ filter, attr_list, &result);
+
+ if ( rc != LDAP_SUCCESS ) {
+ goto fn_exit;
+ }
+
+ num_result = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result);
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_add_sam_account: More than one user with specified Sid exists: bailing out!\n"));
+ goto fn_exit;
+ }
+
+ /* Check if we need to update an existing entry */
+ if (num_result == 1) {
+ char *tmp;
+
+ DEBUG(3,("ldapsam_add_sam_account: User exists without samba attributes: adding them\n"));
+ ldap_op = LDAP_MOD_REPLACE;
+ entry = ldap_first_entry (ldap_state->smbldap_state->ldap_struct, result);
+ tmp = smbldap_get_dn (ldap_state->smbldap_state->ldap_struct, entry);
+ if (!tmp) {
+ goto fn_exit;
+ }
+ dn = talloc_asprintf(ctx, "%s", tmp);
+ SAFE_FREE(tmp);
+ if (!dn) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fn_exit;
+ }
+ }
+ }
+
+ if (num_result == 0) {
+ char *escape_username;
+ /* Check if we need to add an entry */
+ DEBUG(3,("ldapsam_add_sam_account: Adding new user\n"));
+ ldap_op = LDAP_MOD_ADD;
+
+ escape_username = escape_rdn_val_string_alloc(username);
+ if (!escape_username) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fn_exit;
+ }
+
+ if (username[strlen(username)-1] == '$') {
+ dn = talloc_asprintf(ctx,
+ "uid=%s,%s",
+ escape_username,
+ lp_ldap_machine_suffix());
+ } else {
+ dn = talloc_asprintf(ctx,
+ "uid=%s,%s",
+ escape_username,
+ lp_ldap_user_suffix());
+ }
+
+ SAFE_FREE(escape_username);
+ if (!dn) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fn_exit;
+ }
+ }
+
+ if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd,
+ element_is_set_or_changed)) {
+ DEBUG(0, ("ldapsam_add_sam_account: init_ldap_from_sam failed!\n"));
+ if (mods != NULL) {
+ ldap_mods_free(mods, true);
+ }
+ goto fn_exit;
+ }
+
+ if (mods == NULL) {
+ DEBUG(0,("ldapsam_add_sam_account: mods is empty: nothing to add for user: %s\n",pdb_get_username(newpwd)));
+ goto fn_exit;
+ }
+ switch ( ldap_state->schema_ver ) {
+ case SCHEMAVER_SAMBAACCOUNT:
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_SAMBAACCOUNT);
+ break;
+ case SCHEMAVER_SAMBASAMACCOUNT:
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_SAMBASAMACCOUNT);
+ break;
+ default:
+ DEBUG(0,("ldapsam_add_sam_account: invalid schema version specified\n"));
+ break;
+ }
+
+ ret = ldapsam_modify_entry(my_methods,newpwd,dn,mods,ldap_op, element_is_set_or_changed);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(0,("ldapsam_add_sam_account: failed to modify/add user with uid = %s (dn = %s)\n",
+ pdb_get_username(newpwd),dn));
+ ldap_mods_free(mods, true);
+ goto fn_exit;
+ }
+
+ DEBUG(2,("ldapsam_add_sam_account: added: uid == %s in the LDAP database\n", pdb_get_username(newpwd)));
+ ldap_mods_free(mods, true);
+
+ status = NT_STATUS_OK;
+
+ fn_exit:
+
+ TALLOC_FREE(ctx);
+ SAFE_FREE(escape_user);
+ if (result) {
+ ldap_msgfree(result);
+ }
+ return status;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static int ldapsam_search_one_group (struct ldapsam_privates *ldap_state,
+ const char *filter,
+ LDAPMessage ** result)
+{
+ int scope = LDAP_SCOPE_SUBTREE;
+ int rc;
+ const char **attr_list;
+
+ attr_list = get_attr_list(NULL, groupmap_attr_list);
+ rc = smbldap_search(ldap_state->smbldap_state,
+ lp_ldap_group_suffix (), scope,
+ filter, attr_list, 0, result);
+ TALLOC_FREE(attr_list);
+
+ return rc;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static bool init_group_from_ldap(struct ldapsam_privates *ldap_state,
+ GROUP_MAP *map, LDAPMessage *entry)
+{
+ char *temp = NULL;
+ TALLOC_CTX *ctx = talloc_init("init_group_from_ldap");
+
+ if (ldap_state == NULL || map == NULL || entry == NULL ||
+ ldap_state->smbldap_state->ldap_struct == NULL) {
+ DEBUG(0, ("init_group_from_ldap: NULL parameters found!\n"));
+ TALLOC_FREE(ctx);
+ return false;
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_GIDNUMBER),
+ ctx);
+ if (!temp) {
+ DEBUG(0, ("init_group_from_ldap: Mandatory attribute %s not found\n",
+ get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GIDNUMBER)));
+ TALLOC_FREE(ctx);
+ return false;
+ }
+ DEBUG(2, ("init_group_from_ldap: Entry found for group: %s\n", temp));
+
+ map->gid = (gid_t)atol(temp);
+
+ TALLOC_FREE(temp);
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_GROUP_SID),
+ ctx);
+ if (!temp) {
+ DEBUG(0, ("init_group_from_ldap: Mandatory attribute %s not found\n",
+ get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GROUP_SID)));
+ TALLOC_FREE(ctx);
+ return false;
+ }
+
+ if (!string_to_sid(&map->sid, temp)) {
+ DEBUG(1, ("SID string [%s] could not be read as a valid SID\n", temp));
+ TALLOC_FREE(ctx);
+ return false;
+ }
+
+ TALLOC_FREE(temp);
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_GROUP_TYPE),
+ ctx);
+ if (!temp) {
+ DEBUG(0, ("init_group_from_ldap: Mandatory attribute %s not found\n",
+ get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GROUP_TYPE)));
+ TALLOC_FREE(ctx);
+ return false;
+ }
+ map->sid_name_use = (enum lsa_SidType)atol(temp);
+
+ if ((map->sid_name_use < SID_NAME_USER) ||
+ (map->sid_name_use > SID_NAME_UNKNOWN)) {
+ DEBUG(0, ("init_group_from_ldap: Unknown Group type: %d\n", map->sid_name_use));
+ TALLOC_FREE(ctx);
+ return false;
+ }
+
+ TALLOC_FREE(temp);
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_DISPLAY_NAME),
+ ctx);
+ if (!temp) {
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_CN),
+ ctx);
+ if (!temp) {
+ DEBUG(0, ("init_group_from_ldap: Attributes cn not found either \
+for gidNumber(%lu)\n",(unsigned long)map->gid));
+ TALLOC_FREE(ctx);
+ return false;
+ }
+ }
+ fstrcpy(map->nt_name, temp);
+
+ TALLOC_FREE(temp);
+ temp = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_DESC),
+ ctx);
+ if (!temp) {
+ temp = talloc_strdup(ctx, "");
+ if (!temp) {
+ TALLOC_FREE(ctx);
+ return false;
+ }
+ }
+ fstrcpy(map->comment, temp);
+
+ if (lp_parm_bool(-1, "ldapsam", "trusted", false)) {
+ store_gid_sid_cache(&map->sid, map->gid);
+ }
+
+ TALLOC_FREE(ctx);
+ return true;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ldapsam_getgroup(struct pdb_methods *methods,
+ const char *filter,
+ GROUP_MAP *map)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int count;
+
+ if (ldapsam_search_one_group(ldap_state, filter, &result)
+ != LDAP_SUCCESS) {
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ count = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (count < 1) {
+ DEBUG(4, ("ldapsam_getgroup: Did not find group, filter was "
+ "%s\n", filter));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ if (count > 1) {
+ DEBUG(1, ("ldapsam_getgroup: Duplicate entries for filter %s: "
+ "count=%d\n", filter, count));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+
+ if (!entry) {
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!init_group_from_ldap(ldap_state, map, entry)) {
+ DEBUG(1, ("ldapsam_getgroup: init_group_from_ldap failed for "
+ "group filter %s\n", filter));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ ldap_msgfree(result);
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ldapsam_getgrsid(struct pdb_methods *methods, GROUP_MAP *map,
+ DOM_SID sid)
+{
+ char *filter = NULL;
+ NTSTATUS status;
+ fstring tmp;
+
+ if (asprintf(&filter, "(&(objectClass=%s)(%s=%s))",
+ LDAP_OBJ_GROUPMAP,
+ get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GROUP_SID),
+ sid_to_fstring(tmp, &sid)) < 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = ldapsam_getgroup(methods, filter, map);
+ SAFE_FREE(filter);
+ return status;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ldapsam_getgrgid(struct pdb_methods *methods, GROUP_MAP *map,
+ gid_t gid)
+{
+ char *filter = NULL;
+ NTSTATUS status;
+
+ if (asprintf(&filter, "(&(objectClass=%s)(%s=%lu))",
+ LDAP_OBJ_GROUPMAP,
+ get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GIDNUMBER),
+ (unsigned long)gid) < 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = ldapsam_getgroup(methods, filter, map);
+ SAFE_FREE(filter);
+ return status;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ldapsam_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
+ const char *name)
+{
+ char *filter = NULL;
+ char *escape_name = escape_ldap_string_alloc(name);
+ NTSTATUS status;
+
+ if (!escape_name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (asprintf(&filter, "(&(objectClass=%s)(|(%s=%s)(%s=%s)))",
+ LDAP_OBJ_GROUPMAP,
+ get_attr_key2string(groupmap_attr_list, LDAP_ATTR_DISPLAY_NAME), escape_name,
+ get_attr_key2string(groupmap_attr_list, LDAP_ATTR_CN),
+ escape_name) < 0) {
+ SAFE_FREE(escape_name);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SAFE_FREE(escape_name);
+ status = ldapsam_getgroup(methods, filter, map);
+ SAFE_FREE(filter);
+ return status;
+}
+
+static bool ldapsam_extract_rid_from_entry(LDAP *ldap_struct,
+ LDAPMessage *entry,
+ const DOM_SID *domain_sid,
+ uint32 *rid)
+{
+ fstring str;
+ DOM_SID sid;
+
+ if (!smbldap_get_single_attribute(ldap_struct, entry, "sambaSID",
+ str, sizeof(str)-1)) {
+ DEBUG(10, ("Could not find sambaSID attribute\n"));
+ return False;
+ }
+
+ if (!string_to_sid(&sid, str)) {
+ DEBUG(10, ("Could not convert string %s to sid\n", str));
+ return False;
+ }
+
+ if (sid_compare_domain(&sid, domain_sid) != 0) {
+ DEBUG(10, ("SID %s is not in expected domain %s\n",
+ str, sid_string_dbg(domain_sid)));
+ return False;
+ }
+
+ if (!sid_peek_rid(&sid, rid)) {
+ DEBUG(10, ("Could not peek into RID\n"));
+ return False;
+ }
+
+ return True;
+}
+
+static NTSTATUS ldapsam_enum_group_members(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group,
+ uint32 **pp_member_rids,
+ size_t *p_num_members)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ struct smbldap_state *conn = ldap_state->smbldap_state;
+ const char *id_attrs[] = { "memberUid", "gidNumber", NULL };
+ const char *sid_attrs[] = { "sambaSID", NULL };
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry;
+ char *filter;
+ char **values = NULL;
+ char **memberuid;
+ char *gidstr;
+ int rc, count;
+
+ *pp_member_rids = NULL;
+ *p_num_members = 0;
+
+ filter = talloc_asprintf(mem_ctx,
+ "(&(objectClass=%s)"
+ "(objectClass=%s)"
+ "(sambaSID=%s))",
+ LDAP_OBJ_POSIXGROUP,
+ LDAP_OBJ_GROUPMAP,
+ sid_string_talloc(mem_ctx, group));
+ if (filter == NULL) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rc = smbldap_search(conn, lp_ldap_group_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, id_attrs, 0,
+ &result);
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ talloc_autofree_ldapmsg(mem_ctx, result);
+
+ count = ldap_count_entries(conn->ldap_struct, result);
+
+ if (count > 1) {
+ DEBUG(1, ("Found more than one groupmap entry for %s\n",
+ sid_string_dbg(group)));
+ ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+
+ if (count == 0) {
+ ret = NT_STATUS_NO_SUCH_GROUP;
+ goto done;
+ }
+
+ entry = ldap_first_entry(conn->ldap_struct, result);
+ if (entry == NULL)
+ goto done;
+
+ gidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", mem_ctx);
+ if (!gidstr) {
+ DEBUG (0, ("ldapsam_enum_group_members: Unable to find the group's gid!\n"));
+ ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+
+ values = ldap_get_values(conn->ldap_struct, entry, "memberUid");
+
+ if (values) {
+
+ filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(|", LDAP_OBJ_SAMBASAMACCOUNT);
+ if (filter == NULL) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (memberuid = values; *memberuid != NULL; memberuid += 1) {
+ char *escape_memberuid;
+
+ escape_memberuid = escape_ldap_string_alloc(*memberuid);
+ if (escape_memberuid == NULL) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ filter = talloc_asprintf_append_buffer(filter, "(uid=%s)", escape_memberuid);
+ if (filter == NULL) {
+ SAFE_FREE(escape_memberuid);
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ SAFE_FREE(escape_memberuid);
+ }
+
+ filter = talloc_asprintf_append_buffer(filter, "))");
+ if (filter == NULL) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rc = smbldap_search(conn, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, sid_attrs, 0,
+ &result);
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ count = ldap_count_entries(conn->ldap_struct, result);
+ DEBUG(10,("ldapsam_enum_group_members: found %d accounts\n", count));
+
+ talloc_autofree_ldapmsg(mem_ctx, result);
+
+ for (entry = ldap_first_entry(conn->ldap_struct, result);
+ entry != NULL;
+ entry = ldap_next_entry(conn->ldap_struct, entry))
+ {
+ char *sidstr;
+ DOM_SID sid;
+ uint32 rid;
+
+ sidstr = smbldap_talloc_single_attribute(conn->ldap_struct,
+ entry, "sambaSID",
+ mem_ctx);
+ if (!sidstr) {
+ DEBUG(0, ("Severe DB error, %s can't miss the sambaSID"
+ "attribute\n", LDAP_OBJ_SAMBASAMACCOUNT));
+ ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+
+ if (!string_to_sid(&sid, sidstr))
+ goto done;
+
+ if (!sid_check_is_in_our_domain(&sid)) {
+ DEBUG(0, ("Inconsistent SAM -- group member uid not "
+ "in our domain\n"));
+ ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+
+ sid_peek_rid(&sid, &rid);
+
+ if (!add_rid_to_array_unique(mem_ctx, rid, pp_member_rids,
+ p_num_members)) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ }
+ }
+
+ filter = talloc_asprintf(mem_ctx,
+ "(&(objectClass=%s)"
+ "(gidNumber=%s))",
+ LDAP_OBJ_SAMBASAMACCOUNT,
+ gidstr);
+
+ rc = smbldap_search(conn, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, sid_attrs, 0,
+ &result);
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ talloc_autofree_ldapmsg(mem_ctx, result);
+
+ for (entry = ldap_first_entry(conn->ldap_struct, result);
+ entry != NULL;
+ entry = ldap_next_entry(conn->ldap_struct, entry))
+ {
+ uint32 rid;
+
+ if (!ldapsam_extract_rid_from_entry(conn->ldap_struct,
+ entry,
+ get_global_sam_sid(),
+ &rid)) {
+ DEBUG(0, ("Severe DB error, %s can't miss the samba SID" "attribute\n", LDAP_OBJ_SAMBASAMACCOUNT));
+ ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+
+ if (!add_rid_to_array_unique(mem_ctx, rid, pp_member_rids,
+ p_num_members)) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ }
+
+ ret = NT_STATUS_OK;
+
+ done:
+
+ if (values)
+ ldap_value_free(values);
+
+ return ret;
+}
+
+static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ struct samu *user,
+ DOM_SID **pp_sids,
+ gid_t **pp_gids,
+ size_t *p_num_groups)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ struct smbldap_state *conn = ldap_state->smbldap_state;
+ char *filter;
+ const char *attrs[] = { "gidNumber", "sambaSID", NULL };
+ char *escape_name;
+ int rc, count;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry;
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ size_t num_sids, num_gids;
+ char *gidstr;
+ gid_t primary_gid = -1;
+
+ *pp_sids = NULL;
+ num_sids = 0;
+
+ if (pdb_get_username(user) == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ escape_name = escape_ldap_string_alloc(pdb_get_username(user));
+ if (escape_name == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ /* retrieve the users primary gid */
+ filter = talloc_asprintf(mem_ctx,
+ "(&(objectClass=%s)(uid=%s))",
+ LDAP_OBJ_SAMBASAMACCOUNT,
+ escape_name);
+ if (filter == NULL) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rc = smbldap_search(conn, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result);
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ talloc_autofree_ldapmsg(mem_ctx, result);
+
+ count = ldap_count_entries(priv2ld(ldap_state), result);
+
+ switch (count) {
+ case 0:
+ DEBUG(1, ("User account [%s] not found!\n", pdb_get_username(user)));
+ ret = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ case 1:
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+
+ gidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", mem_ctx);
+ if (!gidstr) {
+ DEBUG (1, ("Unable to find the member's gid!\n"));
+ ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+ primary_gid = strtoul(gidstr, NULL, 10);
+ break;
+ default:
+ DEBUG(1, ("found more than one account with the same user name ?!\n"));
+ ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+
+ filter = talloc_asprintf(mem_ctx,
+ "(&(objectClass=%s)(|(memberUid=%s)(gidNumber=%d)))",
+ LDAP_OBJ_POSIXGROUP, escape_name, primary_gid);
+ if (filter == NULL) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rc = smbldap_search(conn, lp_ldap_group_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result);
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ talloc_autofree_ldapmsg(mem_ctx, result);
+
+ num_gids = 0;
+ *pp_gids = NULL;
+
+ num_sids = 0;
+ *pp_sids = NULL;
+
+ /* We need to add the primary group as the first gid/sid */
+
+ if (!add_gid_to_array_unique(mem_ctx, primary_gid, pp_gids, &num_gids)) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ /* This sid will be replaced later */
+
+ ret = add_sid_to_array_unique(mem_ctx, &global_sid_NULL, pp_sids,
+ &num_sids);
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto done;
+ }
+
+ for (entry = ldap_first_entry(conn->ldap_struct, result);
+ entry != NULL;
+ entry = ldap_next_entry(conn->ldap_struct, entry))
+ {
+ fstring str;
+ DOM_SID sid;
+ gid_t gid;
+ char *end;
+
+ if (!smbldap_get_single_attribute(conn->ldap_struct,
+ entry, "sambaSID",
+ str, sizeof(str)-1))
+ continue;
+
+ if (!string_to_sid(&sid, str))
+ goto done;
+
+ if (!smbldap_get_single_attribute(conn->ldap_struct,
+ entry, "gidNumber",
+ str, sizeof(str)-1))
+ continue;
+
+ gid = strtoul(str, &end, 10);
+
+ if (PTR_DIFF(end, str) != strlen(str))
+ goto done;
+
+ if (gid == primary_gid) {
+ sid_copy(&(*pp_sids)[0], &sid);
+ } else {
+ if (!add_gid_to_array_unique(mem_ctx, gid, pp_gids,
+ &num_gids)) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ ret = add_sid_to_array_unique(mem_ctx, &sid, pp_sids,
+ &num_sids);
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto done;
+ }
+ }
+ }
+
+ if (sid_compare(&global_sid_NULL, &(*pp_sids)[0]) == 0) {
+ DEBUG(3, ("primary group of [%s] not found\n",
+ pdb_get_username(user)));
+ goto done;
+ }
+
+ *p_num_groups = num_sids;
+
+ ret = NT_STATUS_OK;
+
+ done:
+
+ SAFE_FREE(escape_name);
+ return ret;
+}
+
+/**********************************************************************
+ * Augment a posixGroup object with a sambaGroupMapping domgroup
+ *********************************************************************/
+
+static NTSTATUS ldapsam_map_posixgroup(TALLOC_CTX *mem_ctx,
+ struct ldapsam_privates *ldap_state,
+ GROUP_MAP *map)
+{
+ const char *filter, *dn;
+ LDAPMessage *msg, *entry;
+ LDAPMod **mods;
+ int rc;
+
+ filter = talloc_asprintf(mem_ctx,
+ "(&(objectClass=%s)(gidNumber=%u))",
+ LDAP_OBJ_POSIXGROUP, map->gid);
+ if (filter == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter,
+ get_attr_list(mem_ctx, groupmap_attr_list),
+ &msg);
+ talloc_autofree_ldapmsg(mem_ctx, msg);
+
+ if ((rc != LDAP_SUCCESS) ||
+ (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, msg) != 1) ||
+ ((entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, msg)) == NULL)) {
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ dn = smbldap_talloc_dn(mem_ctx, ldap_state->smbldap_state->ldap_struct, entry);
+ if (dn == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ mods = NULL;
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass",
+ LDAP_OBJ_GROUPMAP);
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "sambaSid",
+ sid_string_talloc(mem_ctx, &map->sid));
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "sambaGroupType",
+ talloc_asprintf(mem_ctx, "%d", map->sid_name_use));
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "displayName",
+ map->nt_name);
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "description",
+ map->comment);
+ talloc_autofree_ldapmod(mem_ctx, mods);
+
+ rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_add_group_mapping_entry(struct pdb_methods *methods,
+ GROUP_MAP *map)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *msg = NULL;
+ LDAPMod **mods = NULL;
+ const char *attrs[] = { NULL };
+ char *filter;
+
+ char *dn;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS result;
+
+ DOM_SID sid;
+
+ int rc;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ filter = talloc_asprintf(mem_ctx, "(sambaSid=%s)",
+ sid_string_talloc(mem_ctx, &map->sid));
+ if (filter == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, attrs, True, &msg);
+ talloc_autofree_ldapmsg(mem_ctx, msg);
+
+ if ((rc == LDAP_SUCCESS) &&
+ (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, msg) > 0)) {
+
+ DEBUG(3, ("SID %s already present in LDAP, refusing to add "
+ "group mapping entry\n", sid_string_dbg(&map->sid)));
+ result = NT_STATUS_GROUP_EXISTS;
+ goto done;
+ }
+
+ switch (map->sid_name_use) {
+
+ case SID_NAME_DOM_GRP:
+ /* To map a domain group we need to have a posix group
+ to attach to. */
+ result = ldapsam_map_posixgroup(mem_ctx, ldap_state, map);
+ goto done;
+ break;
+
+ case SID_NAME_ALIAS:
+ if (!sid_check_is_in_our_domain(&map->sid)
+ && !sid_check_is_in_builtin(&map->sid) )
+ {
+ DEBUG(3, ("Refusing to map sid %s as an alias, not in our domain\n",
+ sid_string_dbg(&map->sid)));
+ result = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+ break;
+
+ default:
+ DEBUG(3, ("Got invalid use '%s' for mapping\n",
+ sid_type_lookup(map->sid_name_use)));
+ result = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ /* Domain groups have been mapped in a separate routine, we have to
+ * create an alias now */
+
+ if (map->gid == -1) {
+ DEBUG(10, ("Refusing to map gid==-1\n"));
+ result = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if (pdb_gid_to_sid(map->gid, &sid)) {
+ DEBUG(3, ("Gid %d is already mapped to SID %s, refusing to "
+ "add\n", map->gid, sid_string_dbg(&sid)));
+ result = NT_STATUS_GROUP_EXISTS;
+ goto done;
+ }
+
+ /* Ok, enough checks done. It's still racy to go ahead now, but that's
+ * the best we can get out of LDAP. */
+
+ dn = talloc_asprintf(mem_ctx, "sambaSid=%s,%s",
+ sid_string_talloc(mem_ctx, &map->sid),
+ lp_ldap_group_suffix());
+ if (dn == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ mods = NULL;
+
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "objectClass",
+ LDAP_OBJ_SID_ENTRY);
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "objectClass",
+ LDAP_OBJ_GROUPMAP);
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "sambaSid",
+ sid_string_talloc(mem_ctx, &map->sid));
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "sambaGroupType",
+ talloc_asprintf(mem_ctx, "%d", map->sid_name_use));
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "displayName",
+ map->nt_name);
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "description",
+ map->comment);
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "gidNumber",
+ talloc_asprintf(mem_ctx, "%u", map->gid));
+ talloc_autofree_ldapmod(mem_ctx, mods);
+
+ rc = smbldap_add(ldap_state->smbldap_state, dn, mods);
+
+ result = (rc == LDAP_SUCCESS) ?
+ NT_STATUS_OK : NT_STATUS_ACCESS_DENIED;
+
+ done:
+ TALLOC_FREE(mem_ctx);
+ return result;
+}
+
+/**********************************************************************
+ * Update a group mapping entry. We're quite strict about what can be changed:
+ * Only the description and displayname may be changed. It simply does not
+ * make any sense to change the SID, gid or the type in a mapping.
+ *********************************************************************/
+
+static NTSTATUS ldapsam_update_group_mapping_entry(struct pdb_methods *methods,
+ GROUP_MAP *map)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ int rc;
+ const char *filter, *dn;
+ LDAPMessage *msg = NULL;
+ LDAPMessage *entry = NULL;
+ LDAPMod **mods = NULL;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS result;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Make 100% sure that sid, gid and type are not changed by looking up
+ * exactly the values we're given in LDAP. */
+
+ filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)"
+ "(sambaSid=%s)(gidNumber=%u)"
+ "(sambaGroupType=%d))",
+ LDAP_OBJ_GROUPMAP,
+ sid_string_talloc(mem_ctx, &map->sid),
+ map->gid, map->sid_name_use);
+ if (filter == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter,
+ get_attr_list(mem_ctx, groupmap_attr_list),
+ &msg);
+ talloc_autofree_ldapmsg(mem_ctx, msg);
+
+ if ((rc != LDAP_SUCCESS) ||
+ (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, msg) != 1) ||
+ ((entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, msg)) == NULL)) {
+ result = NT_STATUS_NO_SUCH_GROUP;
+ goto done;
+ }
+
+ dn = smbldap_talloc_dn(mem_ctx, ldap_state->smbldap_state->ldap_struct, entry);
+
+ if (dn == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ mods = NULL;
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "displayName",
+ map->nt_name);
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "description",
+ map->comment);
+ talloc_autofree_ldapmod(mem_ctx, mods);
+
+ if (mods == NULL) {
+ DEBUG(4, ("ldapsam_update_group_mapping_entry: mods is empty: "
+ "nothing to do\n"));
+ result = NT_STATUS_OK;
+ goto done;
+ }
+
+ rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
+
+ if (rc != LDAP_SUCCESS) {
+ result = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+
+ DEBUG(2, ("ldapsam_update_group_mapping_entry: successfully modified "
+ "group %lu in LDAP\n", (unsigned long)map->gid));
+
+ result = NT_STATUS_OK;
+
+ done:
+ TALLOC_FREE(mem_ctx);
+ return result;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ldapsam_delete_group_mapping_entry(struct pdb_methods *methods,
+ DOM_SID sid)
+{
+ struct ldapsam_privates *priv =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *msg, *entry;
+ int rc;
+ NTSTATUS result;
+ TALLOC_CTX *mem_ctx;
+ char *filter;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=%s))",
+ LDAP_OBJ_GROUPMAP, LDAP_ATTRIBUTE_SID,
+ sid_string_talloc(mem_ctx, &sid));
+ if (filter == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ rc = smbldap_search_suffix(priv->smbldap_state, filter,
+ get_attr_list(mem_ctx, groupmap_attr_list),
+ &msg);
+ talloc_autofree_ldapmsg(mem_ctx, msg);
+
+ if ((rc != LDAP_SUCCESS) ||
+ (ldap_count_entries(priv2ld(priv), msg) != 1) ||
+ ((entry = ldap_first_entry(priv2ld(priv), msg)) == NULL)) {
+ result = NT_STATUS_NO_SUCH_GROUP;
+ goto done;
+ }
+
+ rc = ldapsam_delete_entry(priv, mem_ctx, entry, LDAP_OBJ_GROUPMAP,
+ get_attr_list(mem_ctx,
+ groupmap_attr_list_to_delete));
+
+ if ((rc == LDAP_NAMING_VIOLATION) ||
+ (rc == LDAP_OBJECT_CLASS_VIOLATION)) {
+ const char *attrs[] = { "sambaGroupType", "description",
+ "displayName", "sambaSIDList",
+ NULL };
+
+ /* Second try. Don't delete the sambaSID attribute, this is
+ for "old" entries that are tacked on a winbind
+ sambaIdmapEntry. */
+
+ rc = ldapsam_delete_entry(priv, mem_ctx, entry,
+ LDAP_OBJ_GROUPMAP, attrs);
+ }
+
+ if ((rc == LDAP_NAMING_VIOLATION) ||
+ (rc == LDAP_OBJECT_CLASS_VIOLATION)) {
+ const char *attrs[] = { "sambaGroupType", "description",
+ "displayName", "sambaSIDList",
+ "gidNumber", NULL };
+
+ /* Third try. This is a post-3.0.21 alias (containing only
+ * sambaSidEntry and sambaGroupMapping classes), we also have
+ * to delete the gidNumber attribute, only the sambaSidEntry
+ * remains */
+
+ rc = ldapsam_delete_entry(priv, mem_ctx, entry,
+ LDAP_OBJ_GROUPMAP, attrs);
+ }
+
+ result = (rc == LDAP_SUCCESS) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+
+ done:
+ TALLOC_FREE(mem_ctx);
+ return result;
+ }
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ldapsam_setsamgrent(struct pdb_methods *my_methods,
+ bool update)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)my_methods->private_data;
+ char *filter = NULL;
+ int rc;
+ const char **attr_list;
+
+ filter = talloc_asprintf(NULL, "(objectclass=%s)", LDAP_OBJ_GROUPMAP);
+ if (!filter) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ attr_list = get_attr_list( NULL, groupmap_attr_list );
+ rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_group_suffix(),
+ LDAP_SCOPE_SUBTREE, filter,
+ attr_list, 0, &ldap_state->result);
+ TALLOC_FREE(attr_list);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0, ("ldapsam_setsamgrent: LDAP search failed: %s\n",
+ ldap_err2string(rc)));
+ DEBUG(3, ("ldapsam_setsamgrent: Query was: %s, %s\n",
+ lp_ldap_group_suffix(), filter));
+ ldap_msgfree(ldap_state->result);
+ ldap_state->result = NULL;
+ TALLOC_FREE(filter);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ TALLOC_FREE(filter);
+
+ DEBUG(2, ("ldapsam_setsamgrent: %d entries in the base!\n",
+ ldap_count_entries(ldap_state->smbldap_state->ldap_struct,
+ ldap_state->result)));
+
+ ldap_state->entry =
+ ldap_first_entry(ldap_state->smbldap_state->ldap_struct,
+ ldap_state->result);
+ ldap_state->index = 0;
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static void ldapsam_endsamgrent(struct pdb_methods *my_methods)
+{
+ ldapsam_endsampwent(my_methods);
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ldapsam_getsamgrent(struct pdb_methods *my_methods,
+ GROUP_MAP *map)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)my_methods->private_data;
+ bool bret = False;
+
+ while (!bret) {
+ if (!ldap_state->entry)
+ return ret;
+
+ ldap_state->index++;
+ bret = init_group_from_ldap(ldap_state, map,
+ ldap_state->entry);
+
+ ldap_state->entry =
+ ldap_next_entry(ldap_state->smbldap_state->ldap_struct,
+ ldap_state->entry);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ldapsam_enum_group_mapping(struct pdb_methods *methods,
+ const DOM_SID *domsid, enum lsa_SidType sid_name_use,
+ GROUP_MAP **pp_rmap,
+ size_t *p_num_entries,
+ bool unix_only)
+{
+ GROUP_MAP map;
+ size_t entries = 0;
+
+ *p_num_entries = 0;
+ *pp_rmap = NULL;
+
+ if (!NT_STATUS_IS_OK(ldapsam_setsamgrent(methods, False))) {
+ DEBUG(0, ("ldapsam_enum_group_mapping: Unable to open "
+ "passdb\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ while (NT_STATUS_IS_OK(ldapsam_getsamgrent(methods, &map))) {
+ if (sid_name_use != SID_NAME_UNKNOWN &&
+ sid_name_use != map.sid_name_use) {
+ DEBUG(11,("ldapsam_enum_group_mapping: group %s is "
+ "not of the requested type\n", map.nt_name));
+ continue;
+ }
+ if (unix_only==ENUM_ONLY_MAPPED && map.gid==-1) {
+ DEBUG(11,("ldapsam_enum_group_mapping: group %s is "
+ "non mapped\n", map.nt_name));
+ continue;
+ }
+
+ (*pp_rmap)=SMB_REALLOC_ARRAY((*pp_rmap), GROUP_MAP, entries+1);
+ if (!(*pp_rmap)) {
+ DEBUG(0,("ldapsam_enum_group_mapping: Unable to "
+ "enlarge group map!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ (*pp_rmap)[entries] = map;
+
+ entries += 1;
+
+ }
+ ldapsam_endsamgrent(methods);
+
+ *p_num_entries = entries;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_modify_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias,
+ const DOM_SID *member,
+ int modop)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ char *dn = NULL;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int count;
+ LDAPMod **mods = NULL;
+ int rc;
+ enum lsa_SidType type = SID_NAME_USE_NONE;
+ fstring tmp;
+
+ char *filter = NULL;
+
+ if (sid_check_is_in_builtin(alias)) {
+ type = SID_NAME_ALIAS;
+ }
+
+ if (sid_check_is_in_our_domain(alias)) {
+ type = SID_NAME_ALIAS;
+ }
+
+ if (type == SID_NAME_USE_NONE) {
+ DEBUG(5, ("SID %s is neither in builtin nor in our domain!\n",
+ sid_string_dbg(alias)));
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ if (asprintf(&filter,
+ "(&(objectClass=%s)(sambaSid=%s)(sambaGroupType=%d))",
+ LDAP_OBJ_GROUPMAP, sid_to_fstring(tmp, alias),
+ type) < 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (ldapsam_search_one_group(ldap_state, filter,
+ &result) != LDAP_SUCCESS) {
+ SAFE_FREE(filter);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct,
+ result);
+
+ if (count < 1) {
+ DEBUG(4, ("ldapsam_modify_aliasmem: Did not find alias\n"));
+ ldap_msgfree(result);
+ SAFE_FREE(filter);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ if (count > 1) {
+ DEBUG(1, ("ldapsam_modify_aliasmem: Duplicate entries for "
+ "filter %s: count=%d\n", filter, count));
+ ldap_msgfree(result);
+ SAFE_FREE(filter);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ SAFE_FREE(filter);
+
+ entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct,
+ result);
+
+ if (!entry) {
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry);
+ if (!dn) {
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ smbldap_set_mod(&mods, modop,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_SID_LIST),
+ sid_to_fstring(tmp, member));
+
+ rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
+
+ ldap_mods_free(mods, True);
+ ldap_msgfree(result);
+ SAFE_FREE(dn);
+
+ if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
+ return NT_STATUS_MEMBER_IN_ALIAS;
+ }
+
+ if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
+ return NT_STATUS_MEMBER_NOT_IN_ALIAS;
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_add_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias,
+ const DOM_SID *member)
+{
+ return ldapsam_modify_aliasmem(methods, alias, member, LDAP_MOD_ADD);
+}
+
+static NTSTATUS ldapsam_del_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias,
+ const DOM_SID *member)
+{
+ return ldapsam_modify_aliasmem(methods, alias, member,
+ LDAP_MOD_DELETE);
+}
+
+static NTSTATUS ldapsam_enum_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias,
+ DOM_SID **pp_members,
+ size_t *p_num_members)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int count;
+ char **values = NULL;
+ int i;
+ char *filter = NULL;
+ size_t num_members = 0;
+ enum lsa_SidType type = SID_NAME_USE_NONE;
+ fstring tmp;
+
+ *pp_members = NULL;
+ *p_num_members = 0;
+
+ if (sid_check_is_in_builtin(alias)) {
+ type = SID_NAME_ALIAS;
+ }
+
+ if (sid_check_is_in_our_domain(alias)) {
+ type = SID_NAME_ALIAS;
+ }
+
+ if (type == SID_NAME_USE_NONE) {
+ DEBUG(5, ("SID %s is neither in builtin nor in our domain!\n",
+ sid_string_dbg(alias)));
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ if (asprintf(&filter,
+ "(&(objectClass=%s)(sambaSid=%s)(sambaGroupType=%d))",
+ LDAP_OBJ_GROUPMAP, sid_to_fstring(tmp, alias),
+ type) < 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (ldapsam_search_one_group(ldap_state, filter,
+ &result) != LDAP_SUCCESS) {
+ SAFE_FREE(filter);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct,
+ result);
+
+ if (count < 1) {
+ DEBUG(4, ("ldapsam_enum_aliasmem: Did not find alias\n"));
+ ldap_msgfree(result);
+ SAFE_FREE(filter);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ if (count > 1) {
+ DEBUG(1, ("ldapsam_enum_aliasmem: Duplicate entries for "
+ "filter %s: count=%d\n", filter, count));
+ ldap_msgfree(result);
+ SAFE_FREE(filter);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ SAFE_FREE(filter);
+
+ entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct,
+ result);
+
+ if (!entry) {
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ values = ldap_get_values(ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_SID_LIST));
+
+ if (values == NULL) {
+ ldap_msgfree(result);
+ return NT_STATUS_OK;
+ }
+
+ count = ldap_count_values(values);
+
+ for (i=0; i<count; i++) {
+ DOM_SID member;
+ NTSTATUS status;
+
+ if (!string_to_sid(&member, values[i]))
+ continue;
+
+ status = add_sid_to_array(NULL, &member, pp_members,
+ &num_members);
+ if (!NT_STATUS_IS_OK(status)) {
+ ldap_value_free(values);
+ ldap_msgfree(result);
+ return status;
+ }
+ }
+
+ *p_num_members = num_members;
+ ldap_value_free(values);
+ ldap_msgfree(result);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_alias_memberships(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *domain_sid,
+ const DOM_SID *members,
+ size_t num_members,
+ uint32 **pp_alias_rids,
+ size_t *p_num_alias_rids)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAP *ldap_struct;
+
+ const char *attrs[] = { LDAP_ATTRIBUTE_SID, NULL };
+
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int i;
+ int rc;
+ char *filter;
+ enum lsa_SidType type = SID_NAME_USE_NONE;
+
+ if (sid_check_is_builtin(domain_sid)) {
+ type = SID_NAME_ALIAS;
+ }
+
+ if (sid_check_is_domain(domain_sid)) {
+ type = SID_NAME_ALIAS;
+ }
+
+ if (type == SID_NAME_USE_NONE) {
+ DEBUG(5, ("SID %s is neither builtin nor domain!\n",
+ sid_string_dbg(domain_sid)));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ filter = talloc_asprintf(mem_ctx,
+ "(&(|(objectclass=%s)(sambaGroupType=%d))(|",
+ LDAP_OBJ_GROUPMAP, type);
+
+ for (i=0; i<num_members; i++)
+ filter = talloc_asprintf(mem_ctx, "%s(sambaSIDList=%s)",
+ filter,
+ sid_string_talloc(mem_ctx,
+ &members[i]));
+
+ filter = talloc_asprintf(mem_ctx, "%s))", filter);
+
+ if (filter == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_group_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result);
+
+ if (rc != LDAP_SUCCESS)
+ return NT_STATUS_UNSUCCESSFUL;
+
+ ldap_struct = ldap_state->smbldap_state->ldap_struct;
+
+ for (entry = ldap_first_entry(ldap_struct, result);
+ entry != NULL;
+ entry = ldap_next_entry(ldap_struct, entry))
+ {
+ fstring sid_str;
+ DOM_SID sid;
+ uint32 rid;
+
+ if (!smbldap_get_single_attribute(ldap_struct, entry,
+ LDAP_ATTRIBUTE_SID,
+ sid_str,
+ sizeof(sid_str)-1))
+ continue;
+
+ if (!string_to_sid(&sid, sid_str))
+ continue;
+
+ if (!sid_peek_check_rid(domain_sid, &sid, &rid))
+ continue;
+
+ if (!add_rid_to_array_unique(mem_ctx, rid, pp_alias_rids,
+ p_num_alias_rids)) {
+ ldap_msgfree(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ ldap_msgfree(result);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_set_account_policy_in_ldap(struct pdb_methods *methods,
+ int policy_index,
+ uint32 value)
+{
+ NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL;
+ int rc;
+ LDAPMod **mods = NULL;
+ fstring value_string;
+ const char *policy_attr = NULL;
+
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+
+ DEBUG(10,("ldapsam_set_account_policy_in_ldap\n"));
+
+ if (!ldap_state->domain_dn) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ policy_attr = get_account_policy_attr(policy_index);
+ if (policy_attr == NULL) {
+ DEBUG(0,("ldapsam_set_account_policy_in_ldap: invalid "
+ "policy\n"));
+ return ntstatus;
+ }
+
+ slprintf(value_string, sizeof(value_string) - 1, "%i", value);
+
+ smbldap_set_mod(&mods, LDAP_MOD_REPLACE, policy_attr, value_string);
+
+ rc = smbldap_modify(ldap_state->smbldap_state, ldap_state->domain_dn,
+ mods);
+
+ ldap_mods_free(mods, True);
+
+ if (rc != LDAP_SUCCESS) {
+ return ntstatus;
+ }
+
+ if (!cache_account_policy_set(policy_index, value)) {
+ DEBUG(0,("ldapsam_set_account_policy_in_ldap: failed to "
+ "update local tdb cache\n"));
+ return ntstatus;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_set_account_policy(struct pdb_methods *methods,
+ int policy_index, uint32 value)
+{
+ return ldapsam_set_account_policy_in_ldap(methods, policy_index,
+ value);
+}
+
+static NTSTATUS ldapsam_get_account_policy_from_ldap(struct pdb_methods *methods,
+ int policy_index,
+ uint32 *value)
+{
+ NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int count;
+ int rc;
+ char **vals = NULL;
+ const char *policy_attr = NULL;
+
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+
+ const char *attrs[2];
+
+ DEBUG(10,("ldapsam_get_account_policy_from_ldap\n"));
+
+ if (!ldap_state->domain_dn) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ policy_attr = get_account_policy_attr(policy_index);
+ if (!policy_attr) {
+ DEBUG(0,("ldapsam_get_account_policy_from_ldap: invalid "
+ "policy index: %d\n", policy_index));
+ return ntstatus;
+ }
+
+ attrs[0] = policy_attr;
+ attrs[1] = NULL;
+
+ rc = smbldap_search(ldap_state->smbldap_state, ldap_state->domain_dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0,
+ &result);
+
+ if (rc != LDAP_SUCCESS) {
+ return ntstatus;
+ }
+
+ count = ldap_count_entries(priv2ld(ldap_state), result);
+ if (count < 1) {
+ goto out;
+ }
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+ if (entry == NULL) {
+ goto out;
+ }
+
+ vals = ldap_get_values(priv2ld(ldap_state), entry, policy_attr);
+ if (vals == NULL) {
+ goto out;
+ }
+
+ *value = (uint32)atol(vals[0]);
+
+ ntstatus = NT_STATUS_OK;
+
+out:
+ if (vals)
+ ldap_value_free(vals);
+ ldap_msgfree(result);
+
+ return ntstatus;
+}
+
+/* wrapper around ldapsam_get_account_policy_from_ldap(), handles tdb as cache
+
+ - if user hasn't decided to use account policies inside LDAP just reuse the
+ old tdb values
+
+ - if there is a valid cache entry, return that
+ - if there is an LDAP entry, update cache and return
+ - otherwise set to default, update cache and return
+
+ Guenther
+*/
+static NTSTATUS ldapsam_get_account_policy(struct pdb_methods *methods,
+ int policy_index, uint32 *value)
+{
+ NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL;
+
+ if (cache_account_policy_get(policy_index, value)) {
+ DEBUG(11,("ldapsam_get_account_policy: got valid value from "
+ "cache\n"));
+ return NT_STATUS_OK;
+ }
+
+ ntstatus = ldapsam_get_account_policy_from_ldap(methods, policy_index,
+ value);
+ if (NT_STATUS_IS_OK(ntstatus)) {
+ goto update_cache;
+ }
+
+ DEBUG(10,("ldapsam_get_account_policy: failed to retrieve from "
+ "ldap\n"));
+
+#if 0
+ /* should we automagically migrate old tdb value here ? */
+ if (account_policy_get(policy_index, value))
+ goto update_ldap;
+
+ DEBUG(10,("ldapsam_get_account_policy: no tdb for %d, trying "
+ "default\n", policy_index));
+#endif
+
+ if (!account_policy_get_default(policy_index, value)) {
+ return ntstatus;
+ }
+
+/* update_ldap: */
+
+ ntstatus = ldapsam_set_account_policy(methods, policy_index, *value);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ return ntstatus;
+ }
+
+ update_cache:
+
+ if (!cache_account_policy_set(policy_index, *value)) {
+ DEBUG(0,("ldapsam_get_account_policy: failed to update local "
+ "tdb as a cache\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods,
+ const DOM_SID *domain_sid,
+ int num_rids,
+ uint32 *rids,
+ const char **names,
+ enum lsa_SidType *attrs)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *msg = NULL;
+ LDAPMessage *entry;
+ char *allsids = NULL;
+ int i, rc, num_mapped;
+ NTSTATUS result = NT_STATUS_NO_MEMORY;
+ TALLOC_CTX *mem_ctx;
+ LDAP *ld;
+ bool is_builtin;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ goto done;
+ }
+
+ if (!sid_check_is_builtin(domain_sid) &&
+ !sid_check_is_domain(domain_sid)) {
+ result = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ for (i=0; i<num_rids; i++)
+ attrs[i] = SID_NAME_UNKNOWN;
+
+ allsids = talloc_strdup(mem_ctx, "");
+ if (allsids == NULL) {
+ goto done;
+ }
+
+ for (i=0; i<num_rids; i++) {
+ DOM_SID sid;
+ sid_compose(&sid, domain_sid, rids[i]);
+ allsids = talloc_asprintf_append_buffer(
+ allsids, "(sambaSid=%s)",
+ sid_string_talloc(mem_ctx, &sid));
+ if (allsids == NULL) {
+ goto done;
+ }
+ }
+
+ /* First look for users */
+
+ {
+ char *filter;
+ const char *ldap_attrs[] = { "uid", "sambaSid", NULL };
+
+ filter = talloc_asprintf(
+ mem_ctx, ("(&(objectClass=%s)(|%s))"),
+ LDAP_OBJ_SAMBASAMACCOUNT, allsids);
+
+ if (filter == NULL) {
+ goto done;
+ }
+
+ rc = smbldap_search(ldap_state->smbldap_state,
+ lp_ldap_user_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, ldap_attrs, 0,
+ &msg);
+ talloc_autofree_ldapmsg(mem_ctx, msg);
+ }
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ ld = ldap_state->smbldap_state->ldap_struct;
+ num_mapped = 0;
+
+ for (entry = ldap_first_entry(ld, msg);
+ entry != NULL;
+ entry = ldap_next_entry(ld, entry)) {
+ uint32 rid;
+ int rid_index;
+ const char *name;
+
+ if (!ldapsam_extract_rid_from_entry(ld, entry, domain_sid,
+ &rid)) {
+ DEBUG(2, ("Could not find sid from ldap entry\n"));
+ continue;
+ }
+
+ name = smbldap_talloc_single_attribute(ld, entry, "uid",
+ names);
+ if (name == NULL) {
+ DEBUG(2, ("Could not retrieve uid attribute\n"));
+ continue;
+ }
+
+ for (rid_index = 0; rid_index < num_rids; rid_index++) {
+ if (rid == rids[rid_index])
+ break;
+ }
+
+ if (rid_index == num_rids) {
+ DEBUG(2, ("Got a RID not asked for: %d\n", rid));
+ continue;
+ }
+
+ attrs[rid_index] = SID_NAME_USER;
+ names[rid_index] = name;
+ num_mapped += 1;
+ }
+
+ if (num_mapped == num_rids) {
+ /* No need to look for groups anymore -- we're done */
+ result = NT_STATUS_OK;
+ goto done;
+ }
+
+ /* Same game for groups */
+
+ {
+ char *filter;
+ const char *ldap_attrs[] = { "cn", "displayName", "sambaSid",
+ "sambaGroupType", NULL };
+
+ filter = talloc_asprintf(
+ mem_ctx, "(&(objectClass=%s)(|%s))",
+ LDAP_OBJ_GROUPMAP, allsids);
+ if (filter == NULL) {
+ goto done;
+ }
+
+ rc = smbldap_search(ldap_state->smbldap_state,
+ lp_ldap_group_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, ldap_attrs, 0,
+ &msg);
+ talloc_autofree_ldapmsg(mem_ctx, msg);
+ }
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ /* ldap_struct might have changed due to a reconnect */
+
+ ld = ldap_state->smbldap_state->ldap_struct;
+
+ /* For consistency checks, we already checked we're only domain or builtin */
+
+ is_builtin = sid_check_is_builtin(domain_sid);
+
+ for (entry = ldap_first_entry(ld, msg);
+ entry != NULL;
+ entry = ldap_next_entry(ld, entry))
+ {
+ uint32 rid;
+ int rid_index;
+ const char *attr;
+ enum lsa_SidType type;
+ const char *dn = smbldap_talloc_dn(mem_ctx, ld, entry);
+
+ attr = smbldap_talloc_single_attribute(ld, entry, "sambaGroupType",
+ mem_ctx);
+ if (attr == NULL) {
+ DEBUG(2, ("Could not extract type from ldap entry %s\n",
+ dn));
+ continue;
+ }
+
+ type = (enum lsa_SidType)atol(attr);
+
+ /* Consistency checks */
+ if ((is_builtin && (type != SID_NAME_ALIAS)) ||
+ (!is_builtin && ((type != SID_NAME_ALIAS) &&
+ (type != SID_NAME_DOM_GRP)))) {
+ DEBUG(2, ("Rejecting invalid group mapping entry %s\n", dn));
+ }
+
+ if (!ldapsam_extract_rid_from_entry(ld, entry, domain_sid,
+ &rid)) {
+ DEBUG(2, ("Could not find sid from ldap entry %s\n", dn));
+ continue;
+ }
+
+ attr = smbldap_talloc_single_attribute(ld, entry, "displayName", names);
+
+ if (attr == NULL) {
+ DEBUG(10, ("Could not retrieve 'displayName' attribute from %s\n",
+ dn));
+ attr = smbldap_talloc_single_attribute(ld, entry, "cn", names);
+ }
+
+ if (attr == NULL) {
+ DEBUG(2, ("Could not retrieve naming attribute from %s\n",
+ dn));
+ continue;
+ }
+
+ for (rid_index = 0; rid_index < num_rids; rid_index++) {
+ if (rid == rids[rid_index])
+ break;
+ }
+
+ if (rid_index == num_rids) {
+ DEBUG(2, ("Got a RID not asked for: %d\n", rid));
+ continue;
+ }
+
+ attrs[rid_index] = type;
+ names[rid_index] = attr;
+ num_mapped += 1;
+ }
+
+ result = NT_STATUS_NONE_MAPPED;
+
+ if (num_mapped > 0)
+ result = (num_mapped == num_rids) ?
+ NT_STATUS_OK : STATUS_SOME_UNMAPPED;
+ done:
+ TALLOC_FREE(mem_ctx);
+ return result;
+}
+
+static char *get_ldap_filter(TALLOC_CTX *mem_ctx, const char *username)
+{
+ char *filter = NULL;
+ char *escaped = NULL;
+ char *result = NULL;
+
+ asprintf(&filter, "(&%s(objectclass=%s))",
+ "(uid=%u)", LDAP_OBJ_SAMBASAMACCOUNT);
+ if (filter == NULL) goto done;
+
+ escaped = escape_ldap_string_alloc(username);
+ if (escaped == NULL) goto done;
+
+ result = talloc_string_sub(mem_ctx, filter, "%u", username);
+
+ done:
+ SAFE_FREE(filter);
+ SAFE_FREE(escaped);
+
+ return result;
+}
+
+const char **talloc_attrs(TALLOC_CTX *mem_ctx, ...)
+{
+ int i, num = 0;
+ va_list ap;
+ const char **result;
+
+ va_start(ap, mem_ctx);
+ while (va_arg(ap, const char *) != NULL)
+ num += 1;
+ va_end(ap);
+
+ if ((result = TALLOC_ARRAY(mem_ctx, const char *, num+1)) == NULL) {
+ return NULL;
+ }
+
+ va_start(ap, mem_ctx);
+ for (i=0; i<num; i++) {
+ result[i] = talloc_strdup(result, va_arg(ap, const char*));
+ if (result[i] == NULL) {
+ talloc_free(result);
+ return NULL;
+ }
+ }
+ va_end(ap);
+
+ result[num] = NULL;
+ return result;
+}
+
+struct ldap_search_state {
+ struct smbldap_state *connection;
+
+ uint32 acct_flags;
+ uint16 group_type;
+
+ const char *base;
+ int scope;
+ const char *filter;
+ const char **attrs;
+ int attrsonly;
+ void *pagedresults_cookie;
+
+ LDAPMessage *entries, *current_entry;
+ bool (*ldap2displayentry)(struct ldap_search_state *state,
+ TALLOC_CTX *mem_ctx,
+ LDAP *ld, LDAPMessage *entry,
+ struct samr_displayentry *result);
+};
+
+static bool ldapsam_search_firstpage(struct pdb_search *search)
+{
+ struct ldap_search_state *state =
+ (struct ldap_search_state *)search->private_data;
+ LDAP *ld;
+ int rc = LDAP_OPERATIONS_ERROR;
+
+ state->entries = NULL;
+
+ if (state->connection->paged_results) {
+ rc = smbldap_search_paged(state->connection, state->base,
+ state->scope, state->filter,
+ state->attrs, state->attrsonly,
+ lp_ldap_page_size(), &state->entries,
+ &state->pagedresults_cookie);
+ }
+
+ if ((rc != LDAP_SUCCESS) || (state->entries == NULL)) {
+
+ if (state->entries != NULL) {
+ /* Left over from unsuccessful paged attempt */
+ ldap_msgfree(state->entries);
+ state->entries = NULL;
+ }
+
+ rc = smbldap_search(state->connection, state->base,
+ state->scope, state->filter, state->attrs,
+ state->attrsonly, &state->entries);
+
+ if ((rc != LDAP_SUCCESS) || (state->entries == NULL))
+ return False;
+
+ /* Ok, the server was lying. It told us it could do paged
+ * searches when it could not. */
+ state->connection->paged_results = False;
+ }
+
+ ld = state->connection->ldap_struct;
+ if ( ld == NULL) {
+ DEBUG(5, ("Don't have an LDAP connection right after a "
+ "search\n"));
+ return False;
+ }
+ state->current_entry = ldap_first_entry(ld, state->entries);
+
+ if (state->current_entry == NULL) {
+ ldap_msgfree(state->entries);
+ state->entries = NULL;
+ }
+
+ return True;
+}
+
+static bool ldapsam_search_nextpage(struct pdb_search *search)
+{
+ struct ldap_search_state *state =
+ (struct ldap_search_state *)search->private_data;
+ int rc;
+
+ if (!state->connection->paged_results) {
+ /* There is no next page when there are no paged results */
+ return False;
+ }
+
+ rc = smbldap_search_paged(state->connection, state->base,
+ state->scope, state->filter, state->attrs,
+ state->attrsonly, lp_ldap_page_size(),
+ &state->entries,
+ &state->pagedresults_cookie);
+
+ if ((rc != LDAP_SUCCESS) || (state->entries == NULL))
+ return False;
+
+ state->current_entry = ldap_first_entry(state->connection->ldap_struct, state->entries);
+
+ if (state->current_entry == NULL) {
+ ldap_msgfree(state->entries);
+ state->entries = NULL;
+ }
+
+ return True;
+}
+
+static bool ldapsam_search_next_entry(struct pdb_search *search,
+ struct samr_displayentry *entry)
+{
+ struct ldap_search_state *state =
+ (struct ldap_search_state *)search->private_data;
+ bool result;
+
+ retry:
+ if ((state->entries == NULL) && (state->pagedresults_cookie == NULL))
+ return False;
+
+ if ((state->entries == NULL) &&
+ !ldapsam_search_nextpage(search))
+ return False;
+
+ result = state->ldap2displayentry(state, search->mem_ctx, state->connection->ldap_struct,
+ state->current_entry, entry);
+
+ if (!result) {
+ char *dn;
+ dn = ldap_get_dn(state->connection->ldap_struct, state->current_entry);
+ DEBUG(5, ("Skipping entry %s\n", dn != NULL ? dn : "<NULL>"));
+ if (dn != NULL) ldap_memfree(dn);
+ }
+
+ state->current_entry = ldap_next_entry(state->connection->ldap_struct, state->current_entry);
+
+ if (state->current_entry == NULL) {
+ ldap_msgfree(state->entries);
+ state->entries = NULL;
+ }
+
+ if (!result) goto retry;
+
+ return True;
+}
+
+static void ldapsam_search_end(struct pdb_search *search)
+{
+ struct ldap_search_state *state =
+ (struct ldap_search_state *)search->private_data;
+ int rc;
+
+ if (state->pagedresults_cookie == NULL)
+ return;
+
+ if (state->entries != NULL)
+ ldap_msgfree(state->entries);
+
+ state->entries = NULL;
+ state->current_entry = NULL;
+
+ if (!state->connection->paged_results)
+ return;
+
+ /* Tell the LDAP server we're not interested in the rest anymore. */
+
+ rc = smbldap_search_paged(state->connection, state->base, state->scope,
+ state->filter, state->attrs,
+ state->attrsonly, 0, &state->entries,
+ &state->pagedresults_cookie);
+
+ if (rc != LDAP_SUCCESS)
+ DEBUG(5, ("Could not end search properly\n"));
+
+ return;
+}
+
+static bool ldapuser2displayentry(struct ldap_search_state *state,
+ TALLOC_CTX *mem_ctx,
+ LDAP *ld, LDAPMessage *entry,
+ struct samr_displayentry *result)
+{
+ char **vals;
+ size_t converted_size;
+ DOM_SID sid;
+ uint32 acct_flags;
+
+ vals = ldap_get_values(ld, entry, "sambaAcctFlags");
+ if ((vals == NULL) || (vals[0] == NULL)) {
+ DEBUG(5, ("\"sambaAcctFlags\" not found\n"));
+ return False;
+ }
+ acct_flags = pdb_decode_acct_ctrl(vals[0]);
+ ldap_value_free(vals);
+
+ if ((state->acct_flags != 0) &&
+ ((state->acct_flags & acct_flags) == 0))
+ return False;
+
+ result->acct_flags = acct_flags;
+ result->account_name = "";
+ result->fullname = "";
+ result->description = "";
+
+ vals = ldap_get_values(ld, entry, "uid");
+ if ((vals == NULL) || (vals[0] == NULL)) {
+ DEBUG(5, ("\"uid\" not found\n"));
+ return False;
+ }
+ if (!pull_utf8_talloc(mem_ctx,
+ CONST_DISCARD(char **, &result->account_name),
+ vals[0], &converted_size))
+ {
+ DEBUG(0,("ldapuser2displayentry: pull_utf8_talloc failed: %s",
+ strerror(errno)));
+ }
+
+ ldap_value_free(vals);
+
+ vals = ldap_get_values(ld, entry, "displayName");
+ if ((vals == NULL) || (vals[0] == NULL))
+ DEBUG(8, ("\"displayName\" not found\n"));
+ else if (!pull_utf8_talloc(mem_ctx,
+ CONST_DISCARD(char **, &result->fullname),
+ vals[0], &converted_size))
+ {
+ DEBUG(0,("ldapuser2displayentry: pull_utf8_talloc failed: %s",
+ strerror(errno)));
+ }
+
+ ldap_value_free(vals);
+
+ vals = ldap_get_values(ld, entry, "description");
+ if ((vals == NULL) || (vals[0] == NULL))
+ DEBUG(8, ("\"description\" not found\n"));
+ else if (!pull_utf8_talloc(mem_ctx,
+ CONST_DISCARD(char **, &result->description),
+ vals[0], &converted_size))
+ {
+ DEBUG(0,("ldapuser2displayentry: pull_utf8_talloc failed: %s",
+ strerror(errno)));
+ }
+
+ ldap_value_free(vals);
+
+ if ((result->account_name == NULL) ||
+ (result->fullname == NULL) ||
+ (result->description == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ return False;
+ }
+
+ vals = ldap_get_values(ld, entry, "sambaSid");
+ if ((vals == NULL) || (vals[0] == NULL)) {
+ DEBUG(0, ("\"objectSid\" not found\n"));
+ return False;
+ }
+
+ if (!string_to_sid(&sid, vals[0])) {
+ DEBUG(0, ("Could not convert %s to SID\n", vals[0]));
+ ldap_value_free(vals);
+ return False;
+ }
+ ldap_value_free(vals);
+
+ if (!sid_peek_check_rid(get_global_sam_sid(), &sid, &result->rid)) {
+ DEBUG(0, ("sid %s does not belong to our domain\n",
+ sid_string_dbg(&sid)));
+ return False;
+ }
+
+ return True;
+}
+
+
+static bool ldapsam_search_users(struct pdb_methods *methods,
+ struct pdb_search *search,
+ uint32 acct_flags)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ struct ldap_search_state *state;
+
+ state = TALLOC_P(search->mem_ctx, struct ldap_search_state);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return False;
+ }
+
+ state->connection = ldap_state->smbldap_state;
+
+ if ((acct_flags != 0) && ((acct_flags & ACB_NORMAL) != 0))
+ state->base = lp_ldap_user_suffix();
+ else if ((acct_flags != 0) &&
+ ((acct_flags & (ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST)) != 0))
+ state->base = lp_ldap_machine_suffix();
+ else
+ state->base = lp_ldap_suffix();
+
+ state->acct_flags = acct_flags;
+ state->base = talloc_strdup(search->mem_ctx, state->base);
+ state->scope = LDAP_SCOPE_SUBTREE;
+ state->filter = get_ldap_filter(search->mem_ctx, "*");
+ state->attrs = talloc_attrs(search->mem_ctx, "uid", "sambaSid",
+ "displayName", "description",
+ "sambaAcctFlags", NULL);
+ state->attrsonly = 0;
+ state->pagedresults_cookie = NULL;
+ state->entries = NULL;
+ state->ldap2displayentry = ldapuser2displayentry;
+
+ if ((state->filter == NULL) || (state->attrs == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ return False;
+ }
+
+ search->private_data = state;
+ search->next_entry = ldapsam_search_next_entry;
+ search->search_end = ldapsam_search_end;
+
+ return ldapsam_search_firstpage(search);
+}
+
+static bool ldapgroup2displayentry(struct ldap_search_state *state,
+ TALLOC_CTX *mem_ctx,
+ LDAP *ld, LDAPMessage *entry,
+ struct samr_displayentry *result)
+{
+ char **vals;
+ size_t converted_size;
+ DOM_SID sid;
+ uint16 group_type;
+
+ result->account_name = "";
+ result->fullname = "";
+ result->description = "";
+
+
+ vals = ldap_get_values(ld, entry, "sambaGroupType");
+ if ((vals == NULL) || (vals[0] == NULL)) {
+ DEBUG(5, ("\"sambaGroupType\" not found\n"));
+ if (vals != NULL) {
+ ldap_value_free(vals);
+ }
+ return False;
+ }
+
+ group_type = atoi(vals[0]);
+
+ if ((state->group_type != 0) &&
+ ((state->group_type != group_type))) {
+ ldap_value_free(vals);
+ return False;
+ }
+
+ ldap_value_free(vals);
+
+ /* display name is the NT group name */
+
+ vals = ldap_get_values(ld, entry, "displayName");
+ if ((vals == NULL) || (vals[0] == NULL)) {
+ DEBUG(8, ("\"displayName\" not found\n"));
+
+ /* fallback to the 'cn' attribute */
+ vals = ldap_get_values(ld, entry, "cn");
+ if ((vals == NULL) || (vals[0] == NULL)) {
+ DEBUG(5, ("\"cn\" not found\n"));
+ return False;
+ }
+ if (!pull_utf8_talloc(mem_ctx,
+ CONST_DISCARD(char **,
+ &result->account_name),
+ vals[0], &converted_size))
+ {
+ DEBUG(0,("ldapgroup2displayentry: pull_utf8_talloc "
+ "failed: %s", strerror(errno)));
+ }
+ }
+ else if (!pull_utf8_talloc(mem_ctx,
+ CONST_DISCARD(char **,
+ &result->account_name),
+ vals[0], &converted_size))
+ {
+ DEBUG(0,("ldapgroup2displayentry: pull_utf8_talloc failed: %s",
+ strerror(errno)));
+ }
+
+ ldap_value_free(vals);
+
+ vals = ldap_get_values(ld, entry, "description");
+ if ((vals == NULL) || (vals[0] == NULL))
+ DEBUG(8, ("\"description\" not found\n"));
+ else if (!pull_utf8_talloc(mem_ctx,
+ CONST_DISCARD(char **, &result->description),
+ vals[0], &converted_size))
+ {
+ DEBUG(0,("ldapgroup2displayentry: pull_utf8_talloc failed: %s",
+ strerror(errno)));
+ }
+ ldap_value_free(vals);
+
+ if ((result->account_name == NULL) ||
+ (result->fullname == NULL) ||
+ (result->description == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ return False;
+ }
+
+ vals = ldap_get_values(ld, entry, "sambaSid");
+ if ((vals == NULL) || (vals[0] == NULL)) {
+ DEBUG(0, ("\"objectSid\" not found\n"));
+ if (vals != NULL) {
+ ldap_value_free(vals);
+ }
+ return False;
+ }
+
+ if (!string_to_sid(&sid, vals[0])) {
+ DEBUG(0, ("Could not convert %s to SID\n", vals[0]));
+ return False;
+ }
+
+ ldap_value_free(vals);
+
+ switch (group_type) {
+ case SID_NAME_DOM_GRP:
+ case SID_NAME_ALIAS:
+
+ if (!sid_peek_check_rid(get_global_sam_sid(), &sid, &result->rid)
+ && !sid_peek_check_rid(&global_sid_Builtin, &sid, &result->rid))
+ {
+ DEBUG(0, ("%s is not in our domain\n",
+ sid_string_dbg(&sid)));
+ return False;
+ }
+ break;
+
+ default:
+ DEBUG(0,("unkown group type: %d\n", group_type));
+ return False;
+ }
+
+ result->acct_flags = 0;
+
+ return True;
+}
+
+static bool ldapsam_search_grouptype(struct pdb_methods *methods,
+ struct pdb_search *search,
+ const DOM_SID *sid,
+ enum lsa_SidType type)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ struct ldap_search_state *state;
+ fstring tmp;
+
+ state = TALLOC_P(search->mem_ctx, struct ldap_search_state);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return False;
+ }
+
+ state->connection = ldap_state->smbldap_state;
+
+ state->base = talloc_strdup(search->mem_ctx, lp_ldap_group_suffix());
+ state->connection = ldap_state->smbldap_state;
+ state->scope = LDAP_SCOPE_SUBTREE;
+ state->filter = talloc_asprintf(search->mem_ctx,
+ "(&(objectclass=%s)"
+ "(sambaGroupType=%d)(sambaSID=%s*))",
+ LDAP_OBJ_GROUPMAP,
+ type, sid_to_fstring(tmp, sid));
+ state->attrs = talloc_attrs(search->mem_ctx, "cn", "sambaSid",
+ "displayName", "description",
+ "sambaGroupType", NULL);
+ state->attrsonly = 0;
+ state->pagedresults_cookie = NULL;
+ state->entries = NULL;
+ state->group_type = type;
+ state->ldap2displayentry = ldapgroup2displayentry;
+
+ if ((state->filter == NULL) || (state->attrs == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ return False;
+ }
+
+ search->private_data = state;
+ search->next_entry = ldapsam_search_next_entry;
+ search->search_end = ldapsam_search_end;
+
+ return ldapsam_search_firstpage(search);
+}
+
+static bool ldapsam_search_groups(struct pdb_methods *methods,
+ struct pdb_search *search)
+{
+ return ldapsam_search_grouptype(methods, search, get_global_sam_sid(), SID_NAME_DOM_GRP);
+}
+
+static bool ldapsam_search_aliases(struct pdb_methods *methods,
+ struct pdb_search *search,
+ const DOM_SID *sid)
+{
+ return ldapsam_search_grouptype(methods, search, sid, SID_NAME_ALIAS);
+}
+
+static bool ldapsam_rid_algorithm(struct pdb_methods *methods)
+{
+ return False;
+}
+
+static NTSTATUS ldapsam_get_new_rid(struct ldapsam_privates *priv,
+ uint32 *rid)
+{
+ struct smbldap_state *smbldap_state = priv->smbldap_state;
+
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ LDAPMod **mods = NULL;
+ NTSTATUS status;
+ char *value;
+ int rc;
+ uint32 nextRid = 0;
+ const char *dn;
+
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = smbldap_search_domain_info(smbldap_state, &result,
+ get_global_sam_name(), False);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Could not get domain info: %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ talloc_autofree_ldapmsg(mem_ctx, result);
+
+ entry = ldap_first_entry(priv2ld(priv), result);
+ if (entry == NULL) {
+ DEBUG(0, ("Could not get domain info entry\n"));
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+
+ /* Find the largest of the three attributes "sambaNextRid",
+ "sambaNextGroupRid" and "sambaNextUserRid". I gave up on the
+ concept of differentiating between user and group rids, and will
+ use only "sambaNextRid" in the future. But for compatibility
+ reasons I look if others have chosen different strategies -- VL */
+
+ value = smbldap_talloc_single_attribute(priv2ld(priv), entry,
+ "sambaNextRid", mem_ctx);
+ if (value != NULL) {
+ uint32 tmp = (uint32)strtoul(value, NULL, 10);
+ nextRid = MAX(nextRid, tmp);
+ }
+
+ value = smbldap_talloc_single_attribute(priv2ld(priv), entry,
+ "sambaNextUserRid", mem_ctx);
+ if (value != NULL) {
+ uint32 tmp = (uint32)strtoul(value, NULL, 10);
+ nextRid = MAX(nextRid, tmp);
+ }
+
+ value = smbldap_talloc_single_attribute(priv2ld(priv), entry,
+ "sambaNextGroupRid", mem_ctx);
+ if (value != NULL) {
+ uint32 tmp = (uint32)strtoul(value, NULL, 10);
+ nextRid = MAX(nextRid, tmp);
+ }
+
+ if (nextRid == 0) {
+ nextRid = BASE_RID-1;
+ }
+
+ nextRid += 1;
+
+ smbldap_make_mod(priv2ld(priv), entry, &mods, "sambaNextRid",
+ talloc_asprintf(mem_ctx, "%d", nextRid));
+ talloc_autofree_ldapmod(mem_ctx, mods);
+
+ if ((dn = smbldap_talloc_dn(mem_ctx, priv2ld(priv), entry)) == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rc = smbldap_modify(smbldap_state, dn, mods);
+
+ /* ACCESS_DENIED is used as a placeholder for "the modify failed,
+ * please retry" */
+
+ status = (rc == LDAP_SUCCESS) ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED;
+
+ done:
+ if (NT_STATUS_IS_OK(status)) {
+ *rid = nextRid;
+ }
+
+ TALLOC_FREE(mem_ctx);
+ return status;
+}
+
+static NTSTATUS ldapsam_new_rid_internal(struct pdb_methods *methods, uint32 *rid)
+{
+ int i;
+
+ for (i=0; i<10; i++) {
+ NTSTATUS result = ldapsam_get_new_rid(
+ (struct ldapsam_privates *)methods->private_data, rid);
+ if (NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ if (!NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
+ return result;
+ }
+
+ /* The ldap update failed (maybe a race condition), retry */
+ }
+
+ /* Tried 10 times, fail. */
+ return NT_STATUS_ACCESS_DENIED;
+}
+
+static bool ldapsam_new_rid(struct pdb_methods *methods, uint32 *rid)
+{
+ NTSTATUS result = ldapsam_new_rid_internal(methods, rid);
+ return NT_STATUS_IS_OK(result) ? True : False;
+}
+
+static bool ldapsam_sid_to_id(struct pdb_methods *methods,
+ const DOM_SID *sid,
+ union unid_t *id, enum lsa_SidType *type)
+{
+ struct ldapsam_privates *priv =
+ (struct ldapsam_privates *)methods->private_data;
+ char *filter;
+ const char *attrs[] = { "sambaGroupType", "gidNumber", "uidNumber",
+ NULL };
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ bool ret = False;
+ char *value;
+ int rc;
+
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return False;
+ }
+
+ filter = talloc_asprintf(mem_ctx,
+ "(&(sambaSid=%s)"
+ "(|(objectClass=%s)(objectClass=%s)))",
+ sid_string_talloc(mem_ctx, sid),
+ LDAP_OBJ_GROUPMAP, LDAP_OBJ_SAMBASAMACCOUNT);
+ if (filter == NULL) {
+ DEBUG(5, ("talloc_asprintf failed\n"));
+ goto done;
+ }
+
+ rc = smbldap_search_suffix(priv->smbldap_state, filter,
+ attrs, &result);
+ if (rc != LDAP_SUCCESS) {
+ goto done;
+ }
+ talloc_autofree_ldapmsg(mem_ctx, result);
+
+ if (ldap_count_entries(priv2ld(priv), result) != 1) {
+ DEBUG(10, ("Got %d entries, expected one\n",
+ ldap_count_entries(priv2ld(priv), result)));
+ goto done;
+ }
+
+ entry = ldap_first_entry(priv2ld(priv), result);
+
+ value = smbldap_talloc_single_attribute(priv2ld(priv), entry,
+ "sambaGroupType", mem_ctx);
+
+ if (value != NULL) {
+ const char *gid_str;
+ /* It's a group */
+
+ gid_str = smbldap_talloc_single_attribute(
+ priv2ld(priv), entry, "gidNumber", mem_ctx);
+ if (gid_str == NULL) {
+ DEBUG(1, ("%s has sambaGroupType but no gidNumber\n",
+ smbldap_talloc_dn(mem_ctx, priv2ld(priv),
+ entry)));
+ goto done;
+ }
+
+ id->gid = strtoul(gid_str, NULL, 10);
+ *type = (enum lsa_SidType)strtoul(value, NULL, 10);
+ ret = True;
+ goto done;
+ }
+
+ /* It must be a user */
+
+ value = smbldap_talloc_single_attribute(priv2ld(priv), entry,
+ "uidNumber", mem_ctx);
+ if (value == NULL) {
+ DEBUG(1, ("Could not find uidNumber in %s\n",
+ smbldap_talloc_dn(mem_ctx, priv2ld(priv), entry)));
+ goto done;
+ }
+
+ id->uid = strtoul(value, NULL, 10);
+ *type = SID_NAME_USER;
+
+ ret = True;
+ done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+/*
+ * The following functions is called only if
+ * ldapsam:trusted and ldapsam:editposix are
+ * set to true
+ */
+
+/*
+ * ldapsam_create_user creates a new
+ * posixAccount and sambaSamAccount object
+ * in the ldap users subtree
+ *
+ * The uid is allocated by winbindd.
+ */
+
+static NTSTATUS ldapsam_create_user(struct pdb_methods *my_methods,
+ TALLOC_CTX *tmp_ctx, const char *name,
+ uint32 acb_info, uint32 *rid)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ LDAPMessage *entry = NULL;
+ LDAPMessage *result = NULL;
+ uint32 num_result;
+ bool is_machine = False;
+ bool add_posix = False;
+ LDAPMod **mods = NULL;
+ struct samu *user;
+ char *filter;
+ char *username;
+ char *homedir;
+ char *gidstr;
+ char *uidstr;
+ char *shell;
+ const char *dn = NULL;
+ DOM_SID group_sid;
+ DOM_SID user_sid;
+ gid_t gid = -1;
+ uid_t uid = -1;
+ NTSTATUS ret;
+ int rc;
+
+ if (((acb_info & ACB_NORMAL) && name[strlen(name)-1] == '$') ||
+ acb_info & ACB_WSTRUST ||
+ acb_info & ACB_SVRTRUST ||
+ acb_info & ACB_DOMTRUST) {
+ is_machine = True;
+ }
+
+ username = escape_ldap_string_alloc(name);
+ filter = talloc_asprintf(tmp_ctx, "(&(uid=%s)(objectClass=%s))",
+ username, LDAP_OBJ_POSIXACCOUNT);
+ SAFE_FREE(username);
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldapsam_create_user: ldap search failed!\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ talloc_autofree_ldapmsg(tmp_ctx, result);
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_create_user: More than one user with name [%s] ?!\n", name));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ if (num_result == 1) {
+ char *tmp;
+ /* check if it is just a posix account.
+ * or if there is a sid attached to this entry
+ */
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+ if (!entry) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ tmp = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "sambaSID", tmp_ctx);
+ if (tmp) {
+ DEBUG (1, ("ldapsam_create_user: The user [%s] already exist!\n", name));
+ return NT_STATUS_USER_EXISTS;
+ }
+
+ /* it is just a posix account, retrieve the dn for later use */
+ dn = smbldap_talloc_dn(tmp_ctx, priv2ld(ldap_state), entry);
+ if (!dn) {
+ DEBUG(0,("ldapsam_create_user: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (num_result == 0) {
+ add_posix = True;
+ }
+
+ /* Create the basic samu structure and generate the mods for the ldap commit */
+ if (!NT_STATUS_IS_OK((ret = ldapsam_new_rid_internal(my_methods, rid)))) {
+ DEBUG(1, ("ldapsam_create_user: Could not allocate a new RID\n"));
+ return ret;
+ }
+
+ sid_compose(&user_sid, get_global_sam_sid(), *rid);
+
+ user = samu_new(tmp_ctx);
+ if (!user) {
+ DEBUG(1,("ldapsam_create_user: Unable to allocate user struct\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_username(user, name, PDB_SET)) {
+ DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ if (!pdb_set_domain(user, get_global_sam_name(), PDB_SET)) {
+ DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ if (is_machine) {
+ if (acb_info & ACB_NORMAL) {
+ if (!pdb_set_acct_ctrl(user, ACB_WSTRUST, PDB_SET)) {
+ DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ } else {
+ if (!pdb_set_acct_ctrl(user, acb_info, PDB_SET)) {
+ DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+ } else {
+ if (!pdb_set_acct_ctrl(user, ACB_NORMAL | ACB_DISABLED, PDB_SET)) {
+ DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ if (!pdb_set_user_sid(user, &user_sid, PDB_SET)) {
+ DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!init_ldap_from_sam(ldap_state, NULL, &mods, user, element_is_set_or_changed)) {
+ DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (ldap_state->schema_ver != SCHEMAVER_SAMBASAMACCOUNT) {
+ DEBUG(1,("ldapsam_create_user: Unsupported schema version\n"));
+ }
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SAMBASAMACCOUNT);
+
+ if (add_posix) {
+ char *escape_name;
+
+ DEBUG(3,("ldapsam_create_user: Creating new posix user\n"));
+
+ /* retrieve the Domain Users group gid */
+ if (!sid_compose(&group_sid, get_global_sam_sid(), DOMAIN_GROUP_RID_USERS) ||
+ !sid_to_gid(&group_sid, &gid)) {
+ DEBUG (0, ("ldapsam_create_user: Unable to get the Domain Users gid: bailing out!\n"));
+ return NT_STATUS_INVALID_PRIMARY_GROUP;
+ }
+
+ /* lets allocate a new userid for this user */
+ if (!winbind_allocate_uid(&uid)) {
+ DEBUG (0, ("ldapsam_create_user: Unable to allocate a new user id: bailing out!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+
+ if (is_machine) {
+ /* TODO: choose a more appropriate default for machines */
+ homedir = talloc_sub_specified(tmp_ctx, lp_template_homedir(), "SMB_workstations_home", ldap_state->domain_name, uid, gid);
+ shell = talloc_strdup(tmp_ctx, "/bin/false");
+ } else {
+ homedir = talloc_sub_specified(tmp_ctx, lp_template_homedir(), name, ldap_state->domain_name, uid, gid);
+ shell = talloc_sub_specified(tmp_ctx, lp_template_shell(), name, ldap_state->domain_name, uid, gid);
+ }
+ uidstr = talloc_asprintf(tmp_ctx, "%d", uid);
+ gidstr = talloc_asprintf(tmp_ctx, "%d", gid);
+
+ escape_name = escape_rdn_val_string_alloc(name);
+ if (!escape_name) {
+ DEBUG (0, ("ldapsam_create_user: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (is_machine) {
+ dn = talloc_asprintf(tmp_ctx, "uid=%s,%s", escape_name, lp_ldap_machine_suffix ());
+ } else {
+ dn = talloc_asprintf(tmp_ctx, "uid=%s,%s", escape_name, lp_ldap_user_suffix ());
+ }
+
+ SAFE_FREE(escape_name);
+
+ if (!homedir || !shell || !uidstr || !gidstr || !dn) {
+ DEBUG (0, ("ldapsam_create_user: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_ACCOUNT);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_POSIXACCOUNT);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "cn", name);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "uidNumber", uidstr);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "gidNumber", gidstr);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "homeDirectory", homedir);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "loginShell", shell);
+ }
+
+ talloc_autofree_ldapmod(tmp_ctx, mods);
+
+ if (add_posix) {
+ rc = smbldap_add(ldap_state->smbldap_state, dn, mods);
+ } else {
+ rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldapsam_create_user: failed to create a new user [%s] (dn = %s)\n", name ,dn));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(2,("ldapsam_create_user: added account [%s] in the LDAP database\n", name));
+
+ flush_pwnam_cache();
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_delete_user(struct pdb_methods *my_methods, TALLOC_CTX *tmp_ctx, struct samu *sam_acct)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int num_result;
+ const char *dn;
+ char *filter;
+ int rc;
+
+ DEBUG(0,("ldapsam_delete_user: Attempt to delete user [%s]\n", pdb_get_username(sam_acct)));
+
+ filter = talloc_asprintf(tmp_ctx,
+ "(&(uid=%s)"
+ "(objectClass=%s)"
+ "(objectClass=%s))",
+ pdb_get_username(sam_acct),
+ LDAP_OBJ_POSIXACCOUNT,
+ LDAP_OBJ_SAMBASAMACCOUNT);
+ if (filter == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldapsam_delete_user: user search failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ talloc_autofree_ldapmsg(tmp_ctx, result);
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result == 0) {
+ DEBUG(0,("ldapsam_delete_user: user not found!\n"));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_delete_user: More than one user with name [%s] ?!\n", pdb_get_username(sam_acct)));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+ if (!entry) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* it is just a posix account, retrieve the dn for later use */
+ dn = smbldap_talloc_dn(tmp_ctx, priv2ld(ldap_state), entry);
+ if (!dn) {
+ DEBUG(0,("ldapsam_delete_user: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rc = smbldap_delete(ldap_state->smbldap_state, dn);
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ flush_pwnam_cache();
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * ldapsam_create_group creates a new
+ * posixGroup and sambaGroupMapping object
+ * in the ldap groups subtree
+ *
+ * The gid is allocated by winbindd.
+ */
+
+static NTSTATUS ldapsam_create_dom_group(struct pdb_methods *my_methods,
+ TALLOC_CTX *tmp_ctx,
+ const char *name,
+ uint32 *rid)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ NTSTATUS ret;
+ LDAPMessage *entry = NULL;
+ LDAPMessage *result = NULL;
+ uint32 num_result;
+ bool is_new_entry = False;
+ LDAPMod **mods = NULL;
+ char *filter;
+ char *groupsidstr;
+ char *groupname;
+ char *grouptype;
+ char *gidstr;
+ const char *dn = NULL;
+ DOM_SID group_sid;
+ gid_t gid = -1;
+ int rc;
+
+ groupname = escape_ldap_string_alloc(name);
+ filter = talloc_asprintf(tmp_ctx, "(&(cn=%s)(objectClass=%s))",
+ groupname, LDAP_OBJ_POSIXGROUP);
+ SAFE_FREE(groupname);
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldapsam_create_group: ldap search failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ talloc_autofree_ldapmsg(tmp_ctx, result);
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_create_group: There exists more than one group with name [%s]: bailing out!\n", name));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ if (num_result == 1) {
+ char *tmp;
+ /* check if it is just a posix group.
+ * or if there is a sid attached to this entry
+ */
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+ if (!entry) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ tmp = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "sambaSID", tmp_ctx);
+ if (tmp) {
+ DEBUG (1, ("ldapsam_create_group: The group [%s] already exist!\n", name));
+ return NT_STATUS_GROUP_EXISTS;
+ }
+
+ /* it is just a posix group, retrieve the gid and the dn for later use */
+ tmp = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", tmp_ctx);
+ if (!tmp) {
+ DEBUG (1, ("ldapsam_create_group: Couldn't retrieve the gidNumber for [%s]?!?!\n", name));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ gid = strtoul(tmp, NULL, 10);
+
+ dn = smbldap_talloc_dn(tmp_ctx, priv2ld(ldap_state), entry);
+ if (!dn) {
+ DEBUG(0,("ldapsam_create_group: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (num_result == 0) {
+ char *escape_name;
+
+ DEBUG(3,("ldapsam_create_user: Creating new posix group\n"));
+
+ is_new_entry = True;
+
+ /* lets allocate a new groupid for this group */
+ if (!winbind_allocate_gid(&gid)) {
+ DEBUG (0, ("ldapsam_create_group: Unable to allocate a new group id: bailing out!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ gidstr = talloc_asprintf(tmp_ctx, "%d", gid);
+
+ escape_name = escape_rdn_val_string_alloc(name);
+ if (!escape_name) {
+ DEBUG (0, ("ldapsam_create_group: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ dn = talloc_asprintf(tmp_ctx, "cn=%s,%s", escape_name, lp_ldap_group_suffix());
+
+ SAFE_FREE(escape_name);
+
+ if (!gidstr || !dn) {
+ DEBUG (0, ("ldapsam_create_group: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_POSIXGROUP);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "cn", name);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "gidNumber", gidstr);
+ }
+
+ if (!NT_STATUS_IS_OK((ret = ldapsam_new_rid_internal(my_methods, rid)))) {
+ DEBUG(1, ("ldapsam_create_group: Could not allocate a new RID\n"));
+ return ret;
+ }
+
+ sid_compose(&group_sid, get_global_sam_sid(), *rid);
+
+ groupsidstr = talloc_strdup(tmp_ctx, sid_string_talloc(tmp_ctx,
+ &group_sid));
+ grouptype = talloc_asprintf(tmp_ctx, "%d", SID_NAME_DOM_GRP);
+
+ if (!groupsidstr || !grouptype) {
+ DEBUG(0,("ldapsam_create_group: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_GROUPMAP);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaSid", groupsidstr);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaGroupType", grouptype);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "displayName", name);
+ talloc_autofree_ldapmod(tmp_ctx, mods);
+
+ if (is_new_entry) {
+ rc = smbldap_add(ldap_state->smbldap_state, dn, mods);
+#if 0
+ if (rc == LDAP_OBJECT_CLASS_VIOLATION) {
+ /* This call may fail with rfc2307bis schema */
+ /* Retry adding a structural class */
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", "????");
+ rc = smbldap_add(ldap_state->smbldap_state, dn, mods);
+ }
+#endif
+ } else {
+ rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldapsam_create_group: failed to create a new group [%s] (dn = %s)\n", name ,dn));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(2,("ldapsam_create_group: added group [%s] in the LDAP database\n", name));
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_delete_dom_group(struct pdb_methods *my_methods, TALLOC_CTX *tmp_ctx, uint32 rid)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int num_result;
+ const char *dn;
+ char *gidstr;
+ char *filter;
+ DOM_SID group_sid;
+ int rc;
+
+ /* get the group sid */
+ sid_compose(&group_sid, get_global_sam_sid(), rid);
+
+ filter = talloc_asprintf(tmp_ctx,
+ "(&(sambaSID=%s)"
+ "(objectClass=%s)"
+ "(objectClass=%s))",
+ sid_string_talloc(tmp_ctx, &group_sid),
+ LDAP_OBJ_POSIXGROUP,
+ LDAP_OBJ_GROUPMAP);
+ if (filter == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(1,("ldapsam_delete_dom_group: group search failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ talloc_autofree_ldapmsg(tmp_ctx, result);
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result == 0) {
+ DEBUG(1,("ldapsam_delete_dom_group: group not found!\n"));
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_delete_dom_group: More than one group with the same SID ?!\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+ if (!entry) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* here it is, retrieve the dn for later use */
+ dn = smbldap_talloc_dn(tmp_ctx, priv2ld(ldap_state), entry);
+ if (!dn) {
+ DEBUG(0,("ldapsam_delete_dom_group: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ gidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", tmp_ctx);
+ if (!gidstr) {
+ DEBUG (0, ("ldapsam_delete_dom_group: Unable to find the group's gid!\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ /* check no user have this group marked as primary group */
+ filter = talloc_asprintf(tmp_ctx,
+ "(&(gidNumber=%s)"
+ "(objectClass=%s)"
+ "(objectClass=%s))",
+ gidstr,
+ LDAP_OBJ_POSIXACCOUNT,
+ LDAP_OBJ_SAMBASAMACCOUNT);
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(1,("ldapsam_delete_dom_group: accounts search failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ talloc_autofree_ldapmsg(tmp_ctx, result);
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result != 0) {
+ DEBUG(3,("ldapsam_delete_dom_group: Can't delete group, it is a primary group for %d users\n", num_result));
+ return NT_STATUS_MEMBERS_PRIMARY_GROUP;
+ }
+
+ rc = smbldap_delete(ldap_state->smbldap_state, dn);
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_change_groupmem(struct pdb_methods *my_methods,
+ TALLOC_CTX *tmp_ctx,
+ uint32 group_rid,
+ uint32 member_rid,
+ int modop)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ LDAPMessage *entry = NULL;
+ LDAPMessage *result = NULL;
+ uint32 num_result;
+ LDAPMod **mods = NULL;
+ char *filter;
+ char *uidstr;
+ const char *dn = NULL;
+ DOM_SID group_sid;
+ DOM_SID member_sid;
+ int rc;
+
+ switch (modop) {
+ case LDAP_MOD_ADD:
+ DEBUG(1,("ldapsam_change_groupmem: add new member(rid=%d) to a domain group(rid=%d)", member_rid, group_rid));
+ break;
+ case LDAP_MOD_DELETE:
+ DEBUG(1,("ldapsam_change_groupmem: delete member(rid=%d) from a domain group(rid=%d)", member_rid, group_rid));
+ break;
+ default:
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* get member sid */
+ sid_compose(&member_sid, get_global_sam_sid(), member_rid);
+
+ /* get the group sid */
+ sid_compose(&group_sid, get_global_sam_sid(), group_rid);
+
+ filter = talloc_asprintf(tmp_ctx,
+ "(&(sambaSID=%s)"
+ "(objectClass=%s)"
+ "(objectClass=%s))",
+ sid_string_talloc(tmp_ctx, &member_sid),
+ LDAP_OBJ_POSIXACCOUNT,
+ LDAP_OBJ_SAMBASAMACCOUNT);
+ if (filter == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* get the member uid */
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(1,("ldapsam_change_groupmem: member search failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ talloc_autofree_ldapmsg(tmp_ctx, result);
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result == 0) {
+ DEBUG(1,("ldapsam_change_groupmem: member not found!\n"));
+ return NT_STATUS_NO_SUCH_MEMBER;
+ }
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_change_groupmem: More than one account with the same SID ?!\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+ if (!entry) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (modop == LDAP_MOD_DELETE) {
+ /* check if we are trying to remove the member from his primary group */
+ char *gidstr;
+ gid_t user_gid, group_gid;
+
+ gidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", tmp_ctx);
+ if (!gidstr) {
+ DEBUG (0, ("ldapsam_change_groupmem: Unable to find the member's gid!\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ user_gid = strtoul(gidstr, NULL, 10);
+
+ if (!sid_to_gid(&group_sid, &group_gid)) {
+ DEBUG (0, ("ldapsam_change_groupmem: Unable to get group gid from SID!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (user_gid == group_gid) {
+ DEBUG (3, ("ldapsam_change_groupmem: can't remove user from its own primary group!\n"));
+ return NT_STATUS_MEMBERS_PRIMARY_GROUP;
+ }
+ }
+
+ /* here it is, retrieve the uid for later use */
+ uidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "uid", tmp_ctx);
+ if (!uidstr) {
+ DEBUG (0, ("ldapsam_change_groupmem: Unable to find the member's name!\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ filter = talloc_asprintf(tmp_ctx,
+ "(&(sambaSID=%s)"
+ "(objectClass=%s)"
+ "(objectClass=%s))",
+ sid_string_talloc(tmp_ctx, &group_sid),
+ LDAP_OBJ_POSIXGROUP,
+ LDAP_OBJ_GROUPMAP);
+
+ /* get the group */
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(1,("ldapsam_change_groupmem: group search failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ talloc_autofree_ldapmsg(tmp_ctx, result);
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result == 0) {
+ DEBUG(1,("ldapsam_change_groupmem: group not found!\n"));
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_change_groupmem: More than one group with the same SID ?!\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+ if (!entry) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* here it is, retrieve the dn for later use */
+ dn = smbldap_talloc_dn(tmp_ctx, priv2ld(ldap_state), entry);
+ if (!dn) {
+ DEBUG(0,("ldapsam_change_groupmem: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ smbldap_set_mod(&mods, modop, "memberUid", uidstr);
+
+ talloc_autofree_ldapmod(tmp_ctx, mods);
+
+ rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
+ if (rc != LDAP_SUCCESS) {
+ if (rc == LDAP_TYPE_OR_VALUE_EXISTS && modop == LDAP_MOD_ADD) {
+ DEBUG(1,("ldapsam_change_groupmem: member is already in group, add failed!\n"));
+ return NT_STATUS_MEMBER_IN_GROUP;
+ }
+ if (rc == LDAP_NO_SUCH_ATTRIBUTE && modop == LDAP_MOD_DELETE) {
+ DEBUG(1,("ldapsam_change_groupmem: member is not in group, delete failed!\n"));
+ return NT_STATUS_MEMBER_NOT_IN_GROUP;
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_add_groupmem(struct pdb_methods *my_methods,
+ TALLOC_CTX *tmp_ctx,
+ uint32 group_rid,
+ uint32 member_rid)
+{
+ return ldapsam_change_groupmem(my_methods, tmp_ctx, group_rid, member_rid, LDAP_MOD_ADD);
+}
+static NTSTATUS ldapsam_del_groupmem(struct pdb_methods *my_methods,
+ TALLOC_CTX *tmp_ctx,
+ uint32 group_rid,
+ uint32 member_rid)
+{
+ return ldapsam_change_groupmem(my_methods, tmp_ctx, group_rid, member_rid, LDAP_MOD_DELETE);
+}
+
+static NTSTATUS ldapsam_set_primary_group(struct pdb_methods *my_methods,
+ TALLOC_CTX *mem_ctx,
+ struct samu *sampass)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ LDAPMessage *entry = NULL;
+ LDAPMessage *result = NULL;
+ uint32 num_result;
+ LDAPMod **mods = NULL;
+ char *filter;
+ char *escape_username;
+ char *gidstr;
+ const char *dn = NULL;
+ gid_t gid;
+ int rc;
+
+ DEBUG(0,("ldapsam_set_primary_group: Attempt to set primary group for user [%s]\n", pdb_get_username(sampass)));
+
+ if (!sid_to_gid(pdb_get_group_sid(sampass), &gid)) {
+ DEBUG(0,("ldapsam_set_primary_group: failed to retrieve gid from user's group SID!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ gidstr = talloc_asprintf(mem_ctx, "%d", gid);
+ if (!gidstr) {
+ DEBUG(0,("ldapsam_set_primary_group: Out of Memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ escape_username = escape_ldap_string_alloc(pdb_get_username(sampass));
+ if (escape_username== NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ filter = talloc_asprintf(mem_ctx,
+ "(&(uid=%s)"
+ "(objectClass=%s)"
+ "(objectClass=%s))",
+ escape_username,
+ LDAP_OBJ_POSIXACCOUNT,
+ LDAP_OBJ_SAMBASAMACCOUNT);
+
+ SAFE_FREE(escape_username);
+
+ if (filter == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldapsam_set_primary_group: user search failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ talloc_autofree_ldapmsg(mem_ctx, result);
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result == 0) {
+ DEBUG(0,("ldapsam_set_primary_group: user not found!\n"));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_set_primary_group: More than one user with name [%s] ?!\n", pdb_get_username(sampass)));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+ if (!entry) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* retrieve the dn for later use */
+ dn = smbldap_talloc_dn(mem_ctx, priv2ld(ldap_state), entry);
+ if (!dn) {
+ DEBUG(0,("ldapsam_set_primary_group: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* remove the old one, and add the new one, this way we do not risk races */
+ smbldap_make_mod(priv2ld(ldap_state), entry, &mods, "gidNumber", gidstr);
+
+ if (mods == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldapsam_set_primary_group: failed to modify [%s] primary group to [%s]\n",
+ pdb_get_username(sampass), gidstr));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ flush_pwnam_cache();
+
+ return NT_STATUS_OK;
+}
+
+
+/**********************************************************************
+ trusted domains functions
+ *********************************************************************/
+
+static char *trusteddom_dn(struct ldapsam_privates *ldap_state,
+ const char *domain)
+{
+ return talloc_asprintf(talloc_tos(), "sambaDomainName=%s,%s", domain,
+ ldap_state->domain_dn);
+}
+
+static bool get_trusteddom_pw_int(struct ldapsam_privates *ldap_state,
+ TALLOC_CTX *mem_ctx,
+ const char *domain, LDAPMessage **entry)
+{
+ int rc;
+ char *filter;
+ int scope = LDAP_SCOPE_SUBTREE;
+ const char **attrs = NULL; /* NULL: get all attrs */
+ int attrsonly = 0; /* 0: return values too */
+ LDAPMessage *result = NULL;
+ char *trusted_dn;
+ uint32 num_result;
+
+ filter = talloc_asprintf(talloc_tos(),
+ "(&(objectClass=%s)(sambaDomainName=%s))",
+ LDAP_OBJ_TRUSTDOM_PASSWORD, domain);
+
+ trusted_dn = trusteddom_dn(ldap_state, domain);
+ if (trusted_dn == NULL) {
+ return False;
+ }
+ rc = smbldap_search(ldap_state->smbldap_state, trusted_dn, scope,
+ filter, attrs, attrsonly, &result);
+
+ if (result != NULL) {
+ talloc_autofree_ldapmsg(mem_ctx, result);
+ }
+
+ if (rc == LDAP_NO_SUCH_OBJECT) {
+ *entry = NULL;
+ return True;
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ return False;
+ }
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result > 1) {
+ DEBUG(1, ("ldapsam_get_trusteddom_pw: more than one "
+ "%s object for domain '%s'?!\n",
+ LDAP_OBJ_TRUSTDOM_PASSWORD, domain));
+ return False;
+ }
+
+ if (num_result == 0) {
+ DEBUG(1, ("ldapsam_get_trusteddom_pw: no "
+ "%s object for domain %s.\n",
+ LDAP_OBJ_TRUSTDOM_PASSWORD, domain));
+ *entry = NULL;
+ } else {
+ *entry = ldap_first_entry(priv2ld(ldap_state), result);
+ }
+
+ return True;
+}
+
+static bool ldapsam_get_trusteddom_pw(struct pdb_methods *methods,
+ const char *domain,
+ char** pwd,
+ DOM_SID *sid,
+ time_t *pass_last_set_time)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *entry = NULL;
+
+ DEBUG(10, ("ldapsam_get_trusteddom_pw called for domain %s\n", domain));
+
+ if (!get_trusteddom_pw_int(ldap_state, talloc_tos(), domain, &entry) ||
+ (entry == NULL))
+ {
+ return False;
+ }
+
+ /* password */
+ if (pwd != NULL) {
+ char *pwd_str;
+ pwd_str = smbldap_talloc_single_attribute(priv2ld(ldap_state),
+ entry, "sambaClearTextPassword", talloc_tos());
+ if (pwd_str == NULL) {
+ return False;
+ }
+ /* trusteddom_pw routines do not use talloc yet... */
+ *pwd = SMB_STRDUP(pwd_str);
+ if (*pwd == NULL) {
+ return False;
+ }
+ }
+
+ /* last change time */
+ if (pass_last_set_time != NULL) {
+ char *time_str;
+ time_str = smbldap_talloc_single_attribute(priv2ld(ldap_state),
+ entry, "sambaPwdLastSet", talloc_tos());
+ if (time_str == NULL) {
+ return False;
+ }
+ *pass_last_set_time = (time_t)atol(time_str);
+ }
+
+ /* domain sid */
+ if (sid != NULL) {
+ char *sid_str;
+ DOM_SID *dom_sid;
+ sid_str = smbldap_talloc_single_attribute(priv2ld(ldap_state),
+ entry, "sambaSID",
+ talloc_tos());
+ if (sid_str == NULL) {
+ return False;
+ }
+ dom_sid = string_sid_talloc(talloc_tos(), sid_str);
+ if (dom_sid == NULL) {
+ return False;
+ }
+ sid_copy(sid, dom_sid);
+ }
+
+ return True;
+}
+
+static bool ldapsam_set_trusteddom_pw(struct pdb_methods *methods,
+ const char* domain,
+ const char* pwd,
+ const DOM_SID *sid)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *entry = NULL;
+ LDAPMod **mods = NULL;
+ char *prev_pwd = NULL;
+ char *trusted_dn = NULL;
+ int rc;
+
+ DEBUG(10, ("ldapsam_set_trusteddom_pw called for domain %s\n", domain));
+
+ /*
+ * get the current entry (if there is one) in order to put the
+ * current password into the previous password attribute
+ */
+ if (!get_trusteddom_pw_int(ldap_state, talloc_tos(), domain, &entry)) {
+ return False;
+ }
+
+ mods = NULL;
+ smbldap_make_mod(priv2ld(ldap_state), entry, &mods, "objectClass",
+ LDAP_OBJ_TRUSTDOM_PASSWORD);
+ smbldap_make_mod(priv2ld(ldap_state), entry, &mods, "sambaDomainName",
+ domain);
+ smbldap_make_mod(priv2ld(ldap_state), entry, &mods, "sambaSID",
+ sid_string_tos(sid));
+ smbldap_make_mod(priv2ld(ldap_state), entry, &mods, "sambaPwdLastSet",
+ talloc_asprintf(talloc_tos(), "%li", time(NULL)));
+ smbldap_make_mod(priv2ld(ldap_state), entry, &mods,
+ "sambaClearTextPassword", pwd);
+
+ talloc_autofree_ldapmod(talloc_tos(), mods);
+
+ if (entry != NULL) {
+ prev_pwd = smbldap_talloc_single_attribute(priv2ld(ldap_state),
+ entry, "sambaClearTextPassword", talloc_tos());
+ if (prev_pwd != NULL) {
+ smbldap_make_mod(priv2ld(ldap_state), entry, &mods,
+ "sambaPreviousClearTextPassword",
+ prev_pwd);
+ }
+ }
+
+ trusted_dn = trusteddom_dn(ldap_state, domain);
+ if (trusted_dn == NULL) {
+ return False;
+ }
+ if (entry == NULL) {
+ rc = smbldap_add(ldap_state->smbldap_state, trusted_dn, mods);
+ } else {
+ rc = smbldap_modify(ldap_state->smbldap_state, trusted_dn, mods);
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(1, ("error writing trusted domain password!\n"));
+ return False;
+ }
+
+ return True;
+}
+
+static bool ldapsam_del_trusteddom_pw(struct pdb_methods *methods,
+ const char *domain)
+{
+ int rc;
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *entry = NULL;
+ const char *trusted_dn;
+
+ if (!get_trusteddom_pw_int(ldap_state, talloc_tos(), domain, &entry)) {
+ return False;
+ }
+
+ if (entry == NULL) {
+ DEBUG(5, ("ldapsam_del_trusteddom_pw: no such trusted domain: "
+ "%s\n", domain));
+ return True;
+ }
+
+ trusted_dn = smbldap_talloc_dn(talloc_tos(), priv2ld(ldap_state),
+ entry);
+ if (trusted_dn == NULL) {
+ DEBUG(0,("ldapsam_del_trusteddom_pw: Out of memory!\n"));
+ return False;
+ }
+
+ rc = smbldap_delete(ldap_state->smbldap_state, trusted_dn);
+ if (rc != LDAP_SUCCESS) {
+ return False;
+ }
+
+ return True;
+}
+
+static NTSTATUS ldapsam_enum_trusteddoms(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_domains,
+ struct trustdom_info ***domains)
+{
+ int rc;
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ char *filter;
+ int scope = LDAP_SCOPE_SUBTREE;
+ const char *attrs[] = { "sambaDomainName", "sambaSID", NULL };
+ int attrsonly = 0; /* 0: return values too */
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+
+ filter = talloc_asprintf(talloc_tos(), "(objectClass=%s)",
+ LDAP_OBJ_TRUSTDOM_PASSWORD);
+
+ rc = smbldap_search(ldap_state->smbldap_state,
+ ldap_state->domain_dn,
+ scope,
+ filter,
+ attrs,
+ attrsonly,
+ &result);
+
+ if (result != NULL) {
+ talloc_autofree_ldapmsg(mem_ctx, result);
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ *num_domains = 0;
+ if (!(*domains = TALLOC_ARRAY(mem_ctx, struct trustdom_info *, 1))) {
+ DEBUG(1, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (entry = ldap_first_entry(priv2ld(ldap_state), result);
+ entry != NULL;
+ entry = ldap_next_entry(priv2ld(ldap_state), entry))
+ {
+ char *dom_name, *dom_sid_str;
+ struct trustdom_info *dom_info;
+
+ dom_info = TALLOC_P(*domains, struct trustdom_info);
+ if (dom_info == NULL) {
+ DEBUG(1, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ dom_name = smbldap_talloc_single_attribute(priv2ld(ldap_state),
+ entry,
+ "sambaDomainName",
+ talloc_tos());
+ if (dom_name == NULL) {
+ DEBUG(1, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ dom_info->name = dom_name;
+
+ dom_sid_str = smbldap_talloc_single_attribute(
+ priv2ld(ldap_state), entry, "sambaSID",
+ talloc_tos());
+ if (dom_sid_str == NULL) {
+ DEBUG(1, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (!string_to_sid(&dom_info->sid, dom_sid_str)) {
+ DEBUG(1, ("Error calling string_to_sid on SID %s\n",
+ dom_sid_str));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ADD_TO_ARRAY(*domains, struct trustdom_info *, dom_info,
+ domains, num_domains);
+
+ if (*domains == NULL) {
+ DEBUG(1, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ DEBUG(5, ("ldapsam_enum_trusteddoms: got %d domains\n", *num_domains));
+ return NT_STATUS_OK;
+}
+
+
+/**********************************************************************
+ Housekeeping
+ *********************************************************************/
+
+static void free_private_data(void **vp)
+{
+ struct ldapsam_privates **ldap_state = (struct ldapsam_privates **)vp;
+
+ smbldap_free_struct(&(*ldap_state)->smbldap_state);
+
+ if ((*ldap_state)->result != NULL) {
+ ldap_msgfree((*ldap_state)->result);
+ (*ldap_state)->result = NULL;
+ }
+ if ((*ldap_state)->domain_dn != NULL) {
+ SAFE_FREE((*ldap_state)->domain_dn);
+ }
+
+ *ldap_state = NULL;
+
+ /* No need to free any further, as it is talloc()ed */
+}
+
+/*********************************************************************
+ Intitalise the parts of the pdb_methods structure that are common to
+ all pdb_ldap modes
+*********************************************************************/
+
+static NTSTATUS pdb_init_ldapsam_common(struct pdb_methods **pdb_method, const char *location)
+{
+ NTSTATUS nt_status;
+ struct ldapsam_privates *ldap_state;
+
+ if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
+ return nt_status;
+ }
+
+ (*pdb_method)->name = "ldapsam";
+
+ (*pdb_method)->getsampwnam = ldapsam_getsampwnam;
+ (*pdb_method)->getsampwsid = ldapsam_getsampwsid;
+ (*pdb_method)->add_sam_account = ldapsam_add_sam_account;
+ (*pdb_method)->update_sam_account = ldapsam_update_sam_account;
+ (*pdb_method)->delete_sam_account = ldapsam_delete_sam_account;
+ (*pdb_method)->rename_sam_account = ldapsam_rename_sam_account;
+
+ (*pdb_method)->getgrsid = ldapsam_getgrsid;
+ (*pdb_method)->getgrgid = ldapsam_getgrgid;
+ (*pdb_method)->getgrnam = ldapsam_getgrnam;
+ (*pdb_method)->add_group_mapping_entry = ldapsam_add_group_mapping_entry;
+ (*pdb_method)->update_group_mapping_entry = ldapsam_update_group_mapping_entry;
+ (*pdb_method)->delete_group_mapping_entry = ldapsam_delete_group_mapping_entry;
+ (*pdb_method)->enum_group_mapping = ldapsam_enum_group_mapping;
+
+ (*pdb_method)->get_account_policy = ldapsam_get_account_policy;
+ (*pdb_method)->set_account_policy = ldapsam_set_account_policy;
+
+ (*pdb_method)->get_seq_num = ldapsam_get_seq_num;
+
+ (*pdb_method)->rid_algorithm = ldapsam_rid_algorithm;
+ (*pdb_method)->new_rid = ldapsam_new_rid;
+
+ (*pdb_method)->get_trusteddom_pw = ldapsam_get_trusteddom_pw;
+ (*pdb_method)->set_trusteddom_pw = ldapsam_set_trusteddom_pw;
+ (*pdb_method)->del_trusteddom_pw = ldapsam_del_trusteddom_pw;
+ (*pdb_method)->enum_trusteddoms = ldapsam_enum_trusteddoms;
+
+ /* TODO: Setup private data and free */
+
+ if ( !(ldap_state = TALLOC_ZERO_P(*pdb_method, struct ldapsam_privates)) ) {
+ DEBUG(0, ("pdb_init_ldapsam_common: talloc() failed for ldapsam private_data!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ nt_status = smbldap_init(*pdb_method, pdb_get_event_context(),
+ location, &ldap_state->smbldap_state);
+
+ if ( !NT_STATUS_IS_OK(nt_status) ) {
+ return nt_status;
+ }
+
+ if ( !(ldap_state->domain_name = talloc_strdup(*pdb_method, get_global_sam_name()) ) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*pdb_method)->private_data = ldap_state;
+
+ (*pdb_method)->free_private_data = free_private_data;
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Initialise the 'compat' mode for pdb_ldap
+ *********************************************************************/
+
+NTSTATUS pdb_init_ldapsam_compat(struct pdb_methods **pdb_method, const char *location)
+{
+ NTSTATUS nt_status;
+ struct ldapsam_privates *ldap_state;
+ char *uri = talloc_strdup( NULL, location );
+
+ trim_char( uri, '\"', '\"' );
+ nt_status = pdb_init_ldapsam_common( pdb_method, uri );
+ if ( uri )
+ TALLOC_FREE( uri );
+
+ if ( !NT_STATUS_IS_OK(nt_status) ) {
+ return nt_status;
+ }
+
+ (*pdb_method)->name = "ldapsam_compat";
+
+ ldap_state = (struct ldapsam_privates *)((*pdb_method)->private_data);
+ ldap_state->schema_ver = SCHEMAVER_SAMBAACCOUNT;
+
+ sid_copy(&ldap_state->domain_sid, get_global_sam_sid());
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Initialise the normal mode for pdb_ldap
+ *********************************************************************/
+
+NTSTATUS pdb_init_ldapsam(struct pdb_methods **pdb_method, const char *location)
+{
+ NTSTATUS nt_status;
+ struct ldapsam_privates *ldap_state = NULL;
+ uint32 alg_rid_base;
+ char *alg_rid_base_string = NULL;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ DOM_SID ldap_domain_sid;
+ DOM_SID secrets_domain_sid;
+ char *domain_sid_string = NULL;
+ char *dn = NULL;
+ char *uri = talloc_strdup( NULL, location );
+
+ trim_char( uri, '\"', '\"' );
+ nt_status = pdb_init_ldapsam_common(pdb_method, uri);
+ if (uri) {
+ TALLOC_FREE(uri);
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ (*pdb_method)->name = "ldapsam";
+
+ (*pdb_method)->add_aliasmem = ldapsam_add_aliasmem;
+ (*pdb_method)->del_aliasmem = ldapsam_del_aliasmem;
+ (*pdb_method)->enum_aliasmem = ldapsam_enum_aliasmem;
+ (*pdb_method)->enum_alias_memberships = ldapsam_alias_memberships;
+ (*pdb_method)->search_users = ldapsam_search_users;
+ (*pdb_method)->search_groups = ldapsam_search_groups;
+ (*pdb_method)->search_aliases = ldapsam_search_aliases;
+
+ if (lp_parm_bool(-1, "ldapsam", "trusted", False)) {
+ (*pdb_method)->enum_group_members = ldapsam_enum_group_members;
+ (*pdb_method)->enum_group_memberships =
+ ldapsam_enum_group_memberships;
+ (*pdb_method)->lookup_rids = ldapsam_lookup_rids;
+ (*pdb_method)->sid_to_id = ldapsam_sid_to_id;
+
+ if (lp_parm_bool(-1, "ldapsam", "editposix", False)) {
+ (*pdb_method)->create_user = ldapsam_create_user;
+ (*pdb_method)->delete_user = ldapsam_delete_user;
+ (*pdb_method)->create_dom_group = ldapsam_create_dom_group;
+ (*pdb_method)->delete_dom_group = ldapsam_delete_dom_group;
+ (*pdb_method)->add_groupmem = ldapsam_add_groupmem;
+ (*pdb_method)->del_groupmem = ldapsam_del_groupmem;
+ (*pdb_method)->set_unix_primary_group = ldapsam_set_primary_group;
+ }
+ }
+
+ ldap_state = (struct ldapsam_privates *)((*pdb_method)->private_data);
+ ldap_state->schema_ver = SCHEMAVER_SAMBASAMACCOUNT;
+
+ /* Try to setup the Domain Name, Domain SID, algorithmic rid base */
+
+ nt_status = smbldap_search_domain_info(ldap_state->smbldap_state,
+ &result,
+ ldap_state->domain_name, True);
+
+ if ( !NT_STATUS_IS_OK(nt_status) ) {
+ DEBUG(2, ("pdb_init_ldapsam: WARNING: Could not get domain "
+ "info, nor add one to the domain\n"));
+ DEBUGADD(2, ("pdb_init_ldapsam: Continuing on regardless, "
+ "will be unable to allocate new users/groups, "
+ "and will risk BDCs having inconsistant SIDs\n"));
+ sid_copy(&ldap_state->domain_sid, get_global_sam_sid());
+ return NT_STATUS_OK;
+ }
+
+ /* Given that the above might fail, everything below this must be
+ * optional */
+
+ entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct,
+ result);
+ if (!entry) {
+ DEBUG(0, ("pdb_init_ldapsam: Could not get domain info "
+ "entry\n"));
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry);
+ if (!dn) {
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ldap_state->domain_dn = smb_xstrdup(dn);
+ ldap_memfree(dn);
+
+ domain_sid_string = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_USER_SID),
+ talloc_tos());
+
+ if (domain_sid_string) {
+ bool found_sid;
+ if (!string_to_sid(&ldap_domain_sid, domain_sid_string)) {
+ DEBUG(1, ("pdb_init_ldapsam: SID [%s] could not be "
+ "read as a valid SID\n", domain_sid_string));
+ ldap_msgfree(result);
+ TALLOC_FREE(domain_sid_string);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ found_sid = secrets_fetch_domain_sid(ldap_state->domain_name,
+ &secrets_domain_sid);
+ if (!found_sid || !sid_equal(&secrets_domain_sid,
+ &ldap_domain_sid)) {
+ DEBUG(1, ("pdb_init_ldapsam: Resetting SID for domain "
+ "%s based on pdb_ldap results %s -> %s\n",
+ ldap_state->domain_name,
+ sid_string_dbg(&secrets_domain_sid),
+ sid_string_dbg(&ldap_domain_sid)));
+
+ /* reset secrets.tdb sid */
+ secrets_store_domain_sid(ldap_state->domain_name,
+ &ldap_domain_sid);
+ DEBUG(1, ("New global sam SID: %s\n",
+ sid_string_dbg(get_global_sam_sid())));
+ }
+ sid_copy(&ldap_state->domain_sid, &ldap_domain_sid);
+ TALLOC_FREE(domain_sid_string);
+ }
+
+ alg_rid_base_string = smbldap_talloc_single_attribute(
+ ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_attr_key2string( dominfo_attr_list,
+ LDAP_ATTR_ALGORITHMIC_RID_BASE ),
+ talloc_tos());
+ if (alg_rid_base_string) {
+ alg_rid_base = (uint32)atol(alg_rid_base_string);
+ if (alg_rid_base != algorithmic_rid_base()) {
+ DEBUG(0, ("The value of 'algorithmic RID base' has "
+ "changed since the LDAP\n"
+ "database was initialised. Aborting. \n"));
+ ldap_msgfree(result);
+ TALLOC_FREE(alg_rid_base_string);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ TALLOC_FREE(alg_rid_base_string);
+ }
+ ldap_msgfree(result);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_ldap_init(void)
+{
+ NTSTATUS nt_status;
+ if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "ldapsam", pdb_init_ldapsam)))
+ return nt_status;
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "ldapsam_compat", pdb_init_ldapsam_compat)))
+ return nt_status;
+
+ /* Let pdb_nds register backends */
+ pdb_nds_init();
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/passdb/pdb_nds.c b/source3/passdb/pdb_nds.c
new file mode 100644
index 0000000000..1edd665d54
--- /dev/null
+++ b/source3/passdb/pdb_nds.c
@@ -0,0 +1,913 @@
+/*
+ Unix SMB/CIFS mplementation.
+ NDS LDAP helper functions for SAMBA
+ Copyright (C) Vince Brimhall 2004-2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+#include <lber.h>
+#include <ldap.h>
+#include <wchar.h>
+
+#include "smbldap.h"
+
+#define NMASLDAP_GET_LOGIN_CONFIG_REQUEST "2.16.840.1.113719.1.39.42.100.3"
+#define NMASLDAP_GET_LOGIN_CONFIG_RESPONSE "2.16.840.1.113719.1.39.42.100.4"
+#define NMASLDAP_SET_PASSWORD_REQUEST "2.16.840.1.113719.1.39.42.100.11"
+#define NMASLDAP_SET_PASSWORD_RESPONSE "2.16.840.1.113719.1.39.42.100.12"
+#define NMASLDAP_GET_PASSWORD_REQUEST "2.16.840.1.113719.1.39.42.100.13"
+#define NMASLDAP_GET_PASSWORD_RESPONSE "2.16.840.1.113719.1.39.42.100.14"
+
+#define NMAS_LDAP_EXT_VERSION 1
+
+/**********************************************************************
+ Take the request BER value and input data items and BER encodes the
+ data into the BER value
+**********************************************************************/
+
+static int berEncodePasswordData(
+ struct berval **requestBV,
+ const char *objectDN,
+ const char *password,
+ const char *password2)
+{
+ int err = 0, rc=0;
+ BerElement *requestBer = NULL;
+
+ const char * utf8ObjPtr = NULL;
+ int utf8ObjSize = 0;
+ const char * utf8PwdPtr = NULL;
+ int utf8PwdSize = 0;
+ const char * utf8Pwd2Ptr = NULL;
+ int utf8Pwd2Size = 0;
+
+
+ /* Convert objectDN and tag strings from Unicode to UTF-8 */
+ utf8ObjSize = strlen(objectDN)+1;
+ utf8ObjPtr = objectDN;
+
+ if (password != NULL)
+ {
+ utf8PwdSize = strlen(password)+1;
+ utf8PwdPtr = password;
+ }
+
+ if (password2 != NULL)
+ {
+ utf8Pwd2Size = strlen(password2)+1;
+ utf8Pwd2Ptr = password2;
+ }
+
+ /* Allocate a BerElement for the request parameters. */
+ if((requestBer = ber_alloc()) == NULL)
+ {
+ err = LDAP_ENCODING_ERROR;
+ goto Cleanup;
+ }
+
+ if (password != NULL && password2 != NULL)
+ {
+ /* BER encode the NMAS Version, the objectDN, and the password */
+ rc = ber_printf(requestBer, "{iooo}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize, utf8PwdPtr, utf8PwdSize, utf8Pwd2Ptr, utf8Pwd2Size);
+ }
+ else if (password != NULL)
+ {
+ /* BER encode the NMAS Version, the objectDN, and the password */
+ rc = ber_printf(requestBer, "{ioo}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize, utf8PwdPtr, utf8PwdSize);
+ }
+ else
+ {
+ /* BER encode the NMAS Version and the objectDN */
+ rc = ber_printf(requestBer, "{io}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize);
+ }
+
+ if (rc < 0)
+ {
+ err = LDAP_ENCODING_ERROR;
+ goto Cleanup;
+ }
+ else
+ {
+ err = 0;
+ }
+
+ /* Convert the BER we just built to a berval that we'll send with the extended request. */
+ if(ber_flatten(requestBer, requestBV) == LBER_ERROR)
+ {
+ err = LDAP_ENCODING_ERROR;
+ goto Cleanup;
+ }
+
+Cleanup:
+
+ if(requestBer)
+ {
+ ber_free(requestBer, 1);
+ }
+
+ return err;
+}
+
+/**********************************************************************
+ Take the request BER value and input data items and BER encodes the
+ data into the BER value
+**********************************************************************/
+
+static int berEncodeLoginData(
+ struct berval **requestBV,
+ char *objectDN,
+ unsigned int methodIDLen,
+ unsigned int *methodID,
+ char *tag,
+ size_t putDataLen,
+ void *putData)
+{
+ int err = 0;
+ BerElement *requestBer = NULL;
+
+ unsigned int i;
+ unsigned int elemCnt = methodIDLen / sizeof(unsigned int);
+
+ char *utf8ObjPtr=NULL;
+ int utf8ObjSize = 0;
+
+ char *utf8TagPtr = NULL;
+ int utf8TagSize = 0;
+
+ utf8ObjPtr = objectDN;
+ utf8ObjSize = strlen(utf8ObjPtr)+1;
+
+ utf8TagPtr = tag;
+ utf8TagSize = strlen(utf8TagPtr)+1;
+
+ /* Allocate a BerElement for the request parameters. */
+ if((requestBer = ber_alloc()) == NULL)
+ {
+ err = LDAP_ENCODING_ERROR;
+ goto Cleanup;
+ }
+
+ /* BER encode the NMAS Version and the objectDN */
+ err = (ber_printf(requestBer, "{io", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize) < 0) ? LDAP_ENCODING_ERROR : 0;
+
+ /* BER encode the MethodID Length and value */
+ if (!err)
+ {
+ err = (ber_printf(requestBer, "{i{", methodIDLen) < 0) ? LDAP_ENCODING_ERROR : 0;
+ }
+
+ for (i = 0; !err && i < elemCnt; i++)
+ {
+ err = (ber_printf(requestBer, "i", methodID[i]) < 0) ? LDAP_ENCODING_ERROR : 0;
+ }
+
+ if (!err)
+ {
+ err = (ber_printf(requestBer, "}}", 0) < 0) ? LDAP_ENCODING_ERROR : 0;
+ }
+
+ if(putData)
+ {
+ /* BER Encode the the tag and data */
+ err = (ber_printf(requestBer, "oio}", utf8TagPtr, utf8TagSize, putDataLen, putData, putDataLen) < 0) ? LDAP_ENCODING_ERROR : 0;
+ }
+ else
+ {
+ /* BER Encode the the tag */
+ err = (ber_printf(requestBer, "o}", utf8TagPtr, utf8TagSize) < 0) ? LDAP_ENCODING_ERROR : 0;
+ }
+
+ if (err)
+ {
+ goto Cleanup;
+ }
+
+ /* Convert the BER we just built to a berval that we'll send with the extended request. */
+ if(ber_flatten(requestBer, requestBV) == LBER_ERROR)
+ {
+ err = LDAP_ENCODING_ERROR;
+ goto Cleanup;
+ }
+
+Cleanup:
+
+ if(requestBer)
+ {
+ ber_free(requestBer, 1);
+ }
+
+ return err;
+}
+
+/**********************************************************************
+ Takes the reply BER Value and decodes the NMAS server version and
+ return code and if a non null retData buffer was supplied, tries to
+ decode the the return data and length
+**********************************************************************/
+
+static int berDecodeLoginData(
+ struct berval *replyBV,
+ int *serverVersion,
+ size_t *retDataLen,
+ void *retData )
+{
+ int err = 0;
+ BerElement *replyBer = NULL;
+ char *retOctStr = NULL;
+ size_t retOctStrLen = 0;
+
+ if((replyBer = ber_init(replyBV)) == NULL)
+ {
+ err = LDAP_OPERATIONS_ERROR;
+ goto Cleanup;
+ }
+
+ if(retData)
+ {
+ retOctStrLen = *retDataLen + 1;
+ retOctStr = SMB_MALLOC_ARRAY(char, retOctStrLen);
+ if(!retOctStr)
+ {
+ err = LDAP_OPERATIONS_ERROR;
+ goto Cleanup;
+ }
+
+ if(ber_scanf(replyBer, "{iis}", serverVersion, &err, retOctStr, &retOctStrLen) != -1)
+ {
+ if (*retDataLen >= retOctStrLen)
+ {
+ memcpy(retData, retOctStr, retOctStrLen);
+ }
+ else if (!err)
+ {
+ err = LDAP_NO_MEMORY;
+ }
+
+ *retDataLen = retOctStrLen;
+ }
+ else if (!err)
+ {
+ err = LDAP_DECODING_ERROR;
+ }
+ }
+ else
+ {
+ if(ber_scanf(replyBer, "{ii}", serverVersion, &err) == -1)
+ {
+ if (!err)
+ {
+ err = LDAP_DECODING_ERROR;
+ }
+ }
+ }
+
+Cleanup:
+
+ if(replyBer)
+ {
+ ber_free(replyBer, 1);
+ }
+
+ if (retOctStr != NULL)
+ {
+ memset(retOctStr, 0, retOctStrLen);
+ free(retOctStr);
+ }
+
+ return err;
+}
+
+/**********************************************************************
+ Retrieves data in the login configuration of the specified object
+ that is tagged with the specified methodID and tag.
+**********************************************************************/
+
+static int getLoginConfig(
+ LDAP *ld,
+ char *objectDN,
+ unsigned int methodIDLen,
+ unsigned int *methodID,
+ char *tag,
+ size_t *dataLen,
+ void *data )
+{
+ int err = 0;
+ struct berval *requestBV = NULL;
+ char *replyOID = NULL;
+ struct berval *replyBV = NULL;
+ int serverVersion = 0;
+
+ /* Validate unicode parameters. */
+ if((strlen(objectDN) == 0) || ld == NULL)
+ {
+ return LDAP_NO_SUCH_ATTRIBUTE;
+ }
+
+ err = berEncodeLoginData(&requestBV, objectDN, methodIDLen, methodID, tag, 0, NULL);
+ if(err)
+ {
+ goto Cleanup;
+ }
+
+ /* Call the ldap_extended_operation (synchronously) */
+ if((err = ldap_extended_operation_s(ld, NMASLDAP_GET_LOGIN_CONFIG_REQUEST,
+ requestBV, NULL, NULL, &replyOID, &replyBV)))
+ {
+ goto Cleanup;
+ }
+
+ /* Make sure there is a return OID */
+ if(!replyOID)
+ {
+ err = LDAP_NOT_SUPPORTED;
+ goto Cleanup;
+ }
+
+ /* Is this what we were expecting to get back. */
+ if(strcmp(replyOID, NMASLDAP_GET_LOGIN_CONFIG_RESPONSE))
+ {
+ err = LDAP_NOT_SUPPORTED;
+ goto Cleanup;
+ }
+
+ /* Do we have a good returned berval? */
+ if(!replyBV)
+ {
+ /* No; returned berval means we experienced a rather drastic error. */
+ /* Return operations error. */
+ err = LDAP_OPERATIONS_ERROR;
+ goto Cleanup;
+ }
+
+ err = berDecodeLoginData(replyBV, &serverVersion, dataLen, data);
+
+ if(serverVersion != NMAS_LDAP_EXT_VERSION)
+ {
+ err = LDAP_OPERATIONS_ERROR;
+ goto Cleanup;
+ }
+
+Cleanup:
+
+ if(replyBV)
+ {
+ ber_bvfree(replyBV);
+ }
+
+ /* Free the return OID string if one was returned. */
+ if(replyOID)
+ {
+ ldap_memfree(replyOID);
+ }
+
+ /* Free memory allocated while building the request ber and berval. */
+ if(requestBV)
+ {
+ ber_bvfree(requestBV);
+ }
+
+ /* Return the appropriate error/success code. */
+ return err;
+}
+
+/**********************************************************************
+ Attempts to get the Simple Password
+**********************************************************************/
+
+static int nmasldap_get_simple_pwd(
+ LDAP *ld,
+ char *objectDN,
+ size_t pwdLen,
+ char *pwd )
+{
+ int err = 0;
+ unsigned int methodID = 0;
+ unsigned int methodIDLen = sizeof(methodID);
+ char tag[] = {'P','A','S','S','W','O','R','D',' ','H','A','S','H',0};
+ char *pwdBuf=NULL;
+ size_t pwdBufLen, bufferLen;
+
+ bufferLen = pwdBufLen = pwdLen+2;
+ pwdBuf = SMB_MALLOC_ARRAY(char, pwdBufLen); /* digest and null */
+ if(pwdBuf == NULL)
+ {
+ return LDAP_NO_MEMORY;
+ }
+
+ err = getLoginConfig(ld, objectDN, methodIDLen, &methodID, tag, &pwdBufLen, pwdBuf);
+ if (err == 0)
+ {
+ if (pwdBufLen !=0)
+ {
+ pwdBuf[pwdBufLen] = 0; /* null terminate */
+
+ switch (pwdBuf[0])
+ {
+ case 1: /* cleartext password */
+ break;
+ case 2: /* SHA1 HASH */
+ case 3: /* MD5_ID */
+ case 4: /* UNIXCrypt_ID */
+ case 8: /* SSHA_ID */
+ default: /* Unknown digest */
+ err = LDAP_INAPPROPRIATE_AUTH; /* only return clear text */
+ break;
+ }
+
+ if (!err)
+ {
+ if (pwdLen >= pwdBufLen-1)
+ {
+ memcpy(pwd, &pwdBuf[1], pwdBufLen-1); /* skip digest tag and include null */
+ }
+ else
+ {
+ err = LDAP_NO_MEMORY;
+ }
+ }
+ }
+ }
+
+ if (pwdBuf != NULL)
+ {
+ memset(pwdBuf, 0, bufferLen);
+ free(pwdBuf);
+ }
+
+ return err;
+}
+
+
+/**********************************************************************
+ Attempts to set the Universal Password
+**********************************************************************/
+
+static int nmasldap_set_password(
+ LDAP *ld,
+ const char *objectDN,
+ const char *pwd )
+{
+ int err = 0;
+
+ struct berval *requestBV = NULL;
+ char *replyOID = NULL;
+ struct berval *replyBV = NULL;
+ int serverVersion;
+
+ /* Validate char parameters. */
+ if(objectDN == NULL || (strlen(objectDN) == 0) || pwd == NULL || ld == NULL)
+ {
+ return LDAP_NO_SUCH_ATTRIBUTE;
+ }
+
+ err = berEncodePasswordData(&requestBV, objectDN, pwd, NULL);
+ if(err)
+ {
+ goto Cleanup;
+ }
+
+ /* Call the ldap_extended_operation (synchronously) */
+ if((err = ldap_extended_operation_s(ld, NMASLDAP_SET_PASSWORD_REQUEST, requestBV, NULL, NULL, &replyOID, &replyBV)))
+ {
+ goto Cleanup;
+ }
+
+ /* Make sure there is a return OID */
+ if(!replyOID)
+ {
+ err = LDAP_NOT_SUPPORTED;
+ goto Cleanup;
+ }
+
+ /* Is this what we were expecting to get back. */
+ if(strcmp(replyOID, NMASLDAP_SET_PASSWORD_RESPONSE))
+ {
+ err = LDAP_NOT_SUPPORTED;
+ goto Cleanup;
+ }
+
+ /* Do we have a good returned berval? */
+ if(!replyBV)
+ {
+ /* No; returned berval means we experienced a rather drastic error. */
+ /* Return operations error. */
+ err = LDAP_OPERATIONS_ERROR;
+ goto Cleanup;
+ }
+
+ err = berDecodeLoginData(replyBV, &serverVersion, NULL, NULL);
+
+ if(serverVersion != NMAS_LDAP_EXT_VERSION)
+ {
+ err = LDAP_OPERATIONS_ERROR;
+ goto Cleanup;
+ }
+
+Cleanup:
+
+ if(replyBV)
+ {
+ ber_bvfree(replyBV);
+ }
+
+ /* Free the return OID string if one was returned. */
+ if(replyOID)
+ {
+ ldap_memfree(replyOID);
+ }
+
+ /* Free memory allocated while building the request ber and berval. */
+ if(requestBV)
+ {
+ ber_bvfree(requestBV);
+ }
+
+ /* Return the appropriate error/success code. */
+ return err;
+}
+
+/**********************************************************************
+ Attempts to get the Universal Password
+**********************************************************************/
+
+static int nmasldap_get_password(
+ LDAP *ld,
+ char *objectDN,
+ size_t *pwdSize, /* in bytes */
+ unsigned char *pwd )
+{
+ int err = 0;
+
+ struct berval *requestBV = NULL;
+ char *replyOID = NULL;
+ struct berval *replyBV = NULL;
+ int serverVersion;
+ char *pwdBuf;
+ size_t pwdBufLen, bufferLen;
+
+ /* Validate char parameters. */
+ if(objectDN == NULL || (strlen(objectDN) == 0) || pwdSize == NULL || ld == NULL)
+ {
+ return LDAP_NO_SUCH_ATTRIBUTE;
+ }
+
+ bufferLen = pwdBufLen = *pwdSize;
+ pwdBuf = SMB_MALLOC_ARRAY(char, pwdBufLen+2);
+ if(pwdBuf == NULL)
+ {
+ return LDAP_NO_MEMORY;
+ }
+
+ err = berEncodePasswordData(&requestBV, objectDN, NULL, NULL);
+ if(err)
+ {
+ goto Cleanup;
+ }
+
+ /* Call the ldap_extended_operation (synchronously) */
+ if((err = ldap_extended_operation_s(ld, NMASLDAP_GET_PASSWORD_REQUEST, requestBV, NULL, NULL, &replyOID, &replyBV)))
+ {
+ goto Cleanup;
+ }
+
+ /* Make sure there is a return OID */
+ if(!replyOID)
+ {
+ err = LDAP_NOT_SUPPORTED;
+ goto Cleanup;
+ }
+
+ /* Is this what we were expecting to get back. */
+ if(strcmp(replyOID, NMASLDAP_GET_PASSWORD_RESPONSE))
+ {
+ err = LDAP_NOT_SUPPORTED;
+ goto Cleanup;
+ }
+
+ /* Do we have a good returned berval? */
+ if(!replyBV)
+ {
+ /* No; returned berval means we experienced a rather drastic error. */
+ /* Return operations error. */
+ err = LDAP_OPERATIONS_ERROR;
+ goto Cleanup;
+ }
+
+ err = berDecodeLoginData(replyBV, &serverVersion, &pwdBufLen, pwdBuf);
+
+ if(serverVersion != NMAS_LDAP_EXT_VERSION)
+ {
+ err = LDAP_OPERATIONS_ERROR;
+ goto Cleanup;
+ }
+
+ if (!err && pwdBufLen != 0)
+ {
+ if (*pwdSize >= pwdBufLen+1 && pwd != NULL)
+ {
+ memcpy(pwd, pwdBuf, pwdBufLen);
+ pwd[pwdBufLen] = 0; /* add null termination */
+ }
+ *pwdSize = pwdBufLen; /* does not include null termination */
+ }
+
+Cleanup:
+
+ if(replyBV)
+ {
+ ber_bvfree(replyBV);
+ }
+
+ /* Free the return OID string if one was returned. */
+ if(replyOID)
+ {
+ ldap_memfree(replyOID);
+ }
+
+ /* Free memory allocated while building the request ber and berval. */
+ if(requestBV)
+ {
+ ber_bvfree(requestBV);
+ }
+
+ if (pwdBuf != NULL)
+ {
+ memset(pwdBuf, 0, bufferLen);
+ free(pwdBuf);
+ }
+
+ /* Return the appropriate error/success code. */
+ return err;
+}
+
+/**********************************************************************
+ Get the user's password from NDS.
+ *********************************************************************/
+
+int pdb_nds_get_password(
+ struct smbldap_state *ldap_state,
+ char *object_dn,
+ size_t *pwd_len,
+ char *pwd )
+{
+ LDAP *ld = ldap_state->ldap_struct;
+ int rc = -1;
+
+ rc = nmasldap_get_password(ld, object_dn, pwd_len, (unsigned char *)pwd);
+ if (rc == LDAP_SUCCESS) {
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nmasldap_get_password returned %s for %s\n", pwd, object_dn));
+#endif
+ DEBUG(5, ("NDS Universal Password retrieved for %s\n", object_dn));
+ } else {
+ DEBUG(3, ("NDS Universal Password NOT retrieved for %s\n", object_dn));
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ rc = nmasldap_get_simple_pwd(ld, object_dn, *pwd_len, pwd);
+ if (rc == LDAP_SUCCESS) {
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nmasldap_get_simple_pwd returned %s for %s\n", pwd, object_dn));
+#endif
+ DEBUG(5, ("NDS Simple Password retrieved for %s\n", object_dn));
+ } else {
+ /* We couldn't get the password */
+ DEBUG(3, ("NDS Simple Password NOT retrieved for %s\n", object_dn));
+ return LDAP_INVALID_CREDENTIALS;
+ }
+ }
+
+ /* We got the password */
+ return LDAP_SUCCESS;
+}
+
+/**********************************************************************
+ Set the users NDS, Universal and Simple passwords.
+ ********************************************************************/
+
+int pdb_nds_set_password(
+ struct smbldap_state *ldap_state,
+ char *object_dn,
+ const char *pwd )
+{
+ LDAP *ld = ldap_state->ldap_struct;
+ int rc = -1;
+ LDAPMod **tmpmods = NULL;
+
+ rc = nmasldap_set_password(ld, object_dn, pwd);
+ if (rc == LDAP_SUCCESS) {
+ DEBUG(5,("NDS Universal Password changed for user %s\n", object_dn));
+ } else {
+ char *ld_error = NULL;
+ ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &ld_error);
+
+ /* This will fail if Universal Password is not enabled for the user's context */
+ DEBUG(3,("NDS Universal Password could not be changed for user %s: %s (%s)\n",
+ object_dn, ldap_err2string(rc), ld_error?ld_error:"unknown"));
+ SAFE_FREE(ld_error);
+ }
+
+ /* Set eDirectory Password */
+ smbldap_set_mod(&tmpmods, LDAP_MOD_REPLACE, "userPassword", pwd);
+ rc = smbldap_modify(ldap_state, object_dn, tmpmods);
+
+ return rc;
+}
+
+/**********************************************************************
+ Allow ldap server to update internal login attempt counters by
+ performing a simple bind. If the samba authentication failed attempt
+ the bind with a bogus, randomly generated password to count the
+ failed attempt. If the bind fails even though samba authentication
+ succeeded, this would indicate that the user's account is disabled,
+ time restrictions are in place or some other password policy
+ violation.
+*********************************************************************/
+
+static NTSTATUS pdb_nds_update_login_attempts(struct pdb_methods *methods,
+ struct samu *sam_acct, bool success)
+{
+ struct ldapsam_privates *ldap_state;
+
+ if ((!methods) || (!sam_acct)) {
+ DEBUG(3,("pdb_nds_update_login_attempts: invalid parameter.\n"));
+ return NT_STATUS_MEMORY_NOT_ALLOCATED;
+ }
+
+ ldap_state = (struct ldapsam_privates *)methods->private_data;
+
+ if (ldap_state) {
+ /* Attempt simple bind with user credentials to update eDirectory
+ password policy */
+ int rc = 0;
+ char *dn;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ const char **attr_list;
+ size_t pwd_len;
+ char clear_text_pw[512];
+ LDAP *ld = NULL;
+ const char *username = pdb_get_username(sam_acct);
+ bool got_clear_text_pw = False;
+
+ DEBUG(5,("pdb_nds_update_login_attempts: %s login for %s\n",
+ success ? "Successful" : "Failed", username));
+
+ result = (LDAPMessage *)pdb_get_backend_private_data(sam_acct, methods);
+ if (!result) {
+ attr_list = get_userattr_list(NULL,
+ ldap_state->schema_ver);
+ rc = ldapsam_search_suffix_by_name(ldap_state, username, &result, attr_list );
+ TALLOC_FREE( attr_list );
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ pdb_set_backend_private_data(sam_acct, result, NULL,
+ methods, PDB_CHANGED);
+ talloc_autofree_ldapmsg(sam_acct, result);
+ }
+
+ if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) == 0) {
+ DEBUG(0, ("pdb_nds_update_login_attempts: No user to modify!\n"));
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result);
+ dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry);
+ if (!dn) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ DEBUG(3, ("pdb_nds_update_login_attempts: username %s found dn '%s'\n", username, dn));
+
+ pwd_len = sizeof(clear_text_pw);
+ if (success == True) {
+ if (pdb_nds_get_password(ldap_state->smbldap_state, dn, &pwd_len, clear_text_pw) == LDAP_SUCCESS) {
+ /* Got clear text password. Use simple ldap bind */
+ got_clear_text_pw = True;
+ }
+ } else {
+ generate_random_buffer((unsigned char *)clear_text_pw, 24);
+ clear_text_pw[24] = '\0';
+ DEBUG(5,("pdb_nds_update_login_attempts: using random password %s\n", clear_text_pw));
+ }
+
+ if((success != True) || (got_clear_text_pw == True)) {
+
+ rc = smb_ldap_setup_full_conn(&ld, ldap_state->location);
+ if (rc) {
+ return NT_STATUS_INVALID_CONNECTION;
+ }
+
+ /* Attempt simple bind with real or bogus password */
+ rc = ldap_simple_bind_s(ld, dn, clear_text_pw);
+ ldap_unbind(ld);
+ if (rc == LDAP_SUCCESS) {
+ DEBUG(5,("pdb_nds_update_login_attempts: ldap_simple_bind_s Successful for %s\n", username));
+ } else {
+ NTSTATUS nt_status = NT_STATUS_ACCOUNT_RESTRICTION;
+ DEBUG(5,("pdb_nds_update_login_attempts: ldap_simple_bind_s Failed for %s\n", username));
+ switch(rc) {
+ case LDAP_INVALID_CREDENTIALS:
+ nt_status = NT_STATUS_WRONG_PASSWORD;
+ break;
+ case LDAP_UNWILLING_TO_PERFORM:
+ /* eDir returns this if the account was disabled. */
+ /* The problem is we don't know if the given
+ password was correct for this account or
+ not. We have to return more info than we
+ should and tell the client NT_STATUS_ACCOUNT_DISABLED
+ so they don't think the password was bad. JRA. */
+ nt_status = NT_STATUS_ACCOUNT_DISABLED;
+ break;
+ default:
+ break;
+ }
+ return nt_status;
+ }
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Intitalise the parts of the pdb_methods structuire that are common
+ to NDS_ldapsam modes
+ *********************************************************************/
+
+static NTSTATUS pdb_init_NDS_ldapsam_common(struct pdb_methods **pdb_method, const char *location)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)((*pdb_method)->private_data);
+
+ /* Mark this as eDirectory ldap */
+ ldap_state->is_nds_ldap = True;
+
+ /* Add pdb_nds specific method for updating login attempts. */
+ (*pdb_method)->update_login_attempts = pdb_nds_update_login_attempts;
+
+ /* Save location for use in pdb_nds_update_login_attempts */
+ ldap_state->location = SMB_STRDUP(location);
+
+ return NT_STATUS_OK;
+}
+
+
+/**********************************************************************
+ Initialise the 'nds compat' mode for pdb_ldap
+ *********************************************************************/
+
+static NTSTATUS pdb_init_NDS_ldapsam_compat(struct pdb_methods **pdb_method, const char *location)
+{
+ NTSTATUS nt_status = pdb_init_ldapsam_compat(pdb_method, location);
+
+ (*pdb_method)->name = "NDS_ldapsam_compat";
+
+ pdb_init_NDS_ldapsam_common(pdb_method, location);
+
+ return nt_status;
+}
+
+
+/**********************************************************************
+ Initialise the 'nds' normal mode for pdb_ldap
+ *********************************************************************/
+
+static NTSTATUS pdb_init_NDS_ldapsam(struct pdb_methods **pdb_method, const char *location)
+{
+ NTSTATUS nt_status = pdb_init_ldapsam(pdb_method, location);
+
+ (*pdb_method)->name = "NDS_ldapsam";
+
+ pdb_init_NDS_ldapsam_common(pdb_method, location);
+
+ return nt_status;
+}
+
+NTSTATUS pdb_nds_init(void)
+{
+ NTSTATUS nt_status;
+ if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "NDS_ldapsam", pdb_init_NDS_ldapsam)))
+ return nt_status;
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "NDS_ldapsam_compat", pdb_init_NDS_ldapsam_compat)))
+ return nt_status;
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/passdb/pdb_smbpasswd.c b/source3/passdb/pdb_smbpasswd.c
new file mode 100644
index 0000000000..f72638bed5
--- /dev/null
+++ b/source3/passdb/pdb_smbpasswd.c
@@ -0,0 +1,1718 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Modified by Jeremy Allison 1995.
+ * Modified by Gerald (Jerry) Carter 2000-2001,2003
+ * Modified by Andrew Bartlett 2002.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+/*
+ smb_passwd is analogous to sam_passwd used everywhere
+ else. However, smb_passwd is limited to the information
+ stored by an smbpasswd entry
+ */
+
+struct smb_passwd
+{
+ uint32 smb_userid; /* this is actually the unix uid_t */
+ const char *smb_name; /* username string */
+
+ const unsigned char *smb_passwd; /* Null if no password */
+ const unsigned char *smb_nt_passwd; /* Null if no password */
+
+ uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */
+ time_t pass_last_set_time; /* password last set time */
+};
+
+struct smbpasswd_privates
+{
+ /* used for maintain locks on the smbpasswd file */
+ int pw_file_lock_depth;
+
+ /* Global File pointer */
+ FILE *pw_file;
+
+ /* formerly static variables */
+ struct smb_passwd pw_buf;
+ fstring user_name;
+ unsigned char smbpwd[16];
+ unsigned char smbntpwd[16];
+
+ /* retrive-once info */
+ const char *smbpasswd_file;
+};
+
+enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE };
+
+static SIG_ATOMIC_T gotalarm;
+
+/***************************************************************
+ Signal function to tell us we timed out.
+****************************************************************/
+
+static void gotalarm_sig(void)
+{
+ gotalarm = 1;
+}
+
+/***************************************************************
+ Lock or unlock a fd for a known lock type. Abandon after waitsecs
+ seconds.
+****************************************************************/
+
+static bool do_file_lock(int fd, int waitsecs, int type)
+{
+ SMB_STRUCT_FLOCK lock;
+ int ret;
+ void (*oldsig_handler)(int);
+
+ gotalarm = 0;
+ oldsig_handler = CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+
+ lock.l_type = type;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 1;
+ lock.l_pid = 0;
+
+ alarm(waitsecs);
+ /* Note we must *NOT* use sys_fcntl here ! JRA */
+ ret = fcntl(fd, SMB_F_SETLKW, &lock);
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST oldsig_handler);
+
+ 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.
+****************************************************************/
+
+static bool pw_file_lock(int fd, int type, int secs, int *plock_depth)
+{
+ if (fd < 0) {
+ return False;
+ }
+
+ if(*plock_depth == 0) {
+ if (!do_file_lock(fd, secs, type)) {
+ DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n",
+ strerror(errno)));
+ return False;
+ }
+ }
+
+ (*plock_depth)++;
+
+ return True;
+}
+
+/***************************************************************
+ Unlock an fd. Abandon after waitsecs seconds.
+****************************************************************/
+
+static bool pw_file_unlock(int fd, int *plock_depth)
+{
+ bool ret=True;
+
+ if (fd == 0 || *plock_depth == 0) {
+ return True;
+ }
+
+ if(*plock_depth == 1) {
+ ret = do_file_lock(fd, 5, F_UNLCK);
+ }
+
+ if (*plock_depth > 0) {
+ (*plock_depth)--;
+ }
+
+ if(!ret) {
+ DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n",
+ strerror(errno)));
+ }
+ return ret;
+}
+
+/**************************************************************
+ Intialize a smb_passwd struct
+ *************************************************************/
+
+static void pdb_init_smb(struct smb_passwd *user)
+{
+ if (user == NULL)
+ return;
+ ZERO_STRUCTP (user);
+
+ user->pass_last_set_time = (time_t)0;
+}
+
+/***************************************************************
+ Internal fn to enumerate the smbpasswd list. Returns a void pointer
+ to ensure no modification outside this module. Checks for atomic
+ rename of smbpasswd file on update or create once the lock has
+ been granted to prevent race conditions. JRA.
+****************************************************************/
+
+static FILE *startsmbfilepwent(const char *pfile, enum pwf_access_type type, int *lock_depth)
+{
+ FILE *fp = NULL;
+ const char *open_mode = NULL;
+ int race_loop = 0;
+ int lock_type = F_RDLCK;
+
+ if (!*pfile) {
+ DEBUG(0, ("startsmbfilepwent: No SMB password file set\n"));
+ return (NULL);
+ }
+
+ switch(type) {
+ case PWF_READ:
+ open_mode = "rb";
+ lock_type = F_RDLCK;
+ break;
+ case PWF_UPDATE:
+ open_mode = "r+b";
+ lock_type = F_WRLCK;
+ break;
+ case PWF_CREATE:
+ /*
+ * Ensure atomic file creation.
+ */
+ {
+ int i, fd = -1;
+
+ for(i = 0; i < 5; i++) {
+ if((fd = sys_open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1) {
+ break;
+ }
+ sys_usleep(200); /* Spin, spin... */
+ }
+ if(fd == -1) {
+ DEBUG(0,("startsmbfilepwent_internal: too many race conditions \
+creating file %s\n", pfile));
+ return NULL;
+ }
+ close(fd);
+ open_mode = "r+b";
+ lock_type = F_WRLCK;
+ break;
+ }
+ }
+
+ for(race_loop = 0; race_loop < 5; race_loop++) {
+ DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile));
+
+ if((fp = sys_fopen(pfile, open_mode)) == NULL) {
+
+ /*
+ * If smbpasswd file doesn't exist, then create new one. This helps to avoid
+ * confusing error msg when adding user account first time.
+ */
+ if (errno == ENOENT) {
+ if ((fp = sys_fopen(pfile, "a+")) != NULL) {
+ DEBUG(0, ("startsmbfilepwent_internal: file %s did not \
+exist. File successfully created.\n", pfile));
+ } else {
+ DEBUG(0, ("startsmbfilepwent_internal: file %s did not \
+exist. Couldn't create new one. Error was: %s",
+ pfile, strerror(errno)));
+ return NULL;
+ }
+ } else {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to open file %s. \
+Error was: %s\n", pfile, strerror(errno)));
+ return NULL;
+ }
+ }
+
+ if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. \
+Error was %s\n", pfile, strerror(errno) ));
+ fclose(fp);
+ return NULL;
+ }
+
+ /*
+ * Only check for replacement races on update or create.
+ * For read we don't mind if the data is one record out of date.
+ */
+
+ if(type == PWF_READ) {
+ break;
+ } else {
+ SMB_STRUCT_STAT sbuf1, sbuf2;
+
+ /*
+ * Avoid the potential race condition between the open and the lock
+ * by doing a stat on the filename and an fstat on the fd. If the
+ * two inodes differ then someone did a rename between the open and
+ * the lock. Back off and try the open again. Only do this 5 times to
+ * prevent infinate loops. JRA.
+ */
+
+ if (sys_stat(pfile,&sbuf1) != 0) {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. \
+Error was %s\n", pfile, strerror(errno)));
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ return NULL;
+ }
+
+ if (sys_fstat(fileno(fp),&sbuf2) != 0) {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. \
+Error was %s\n", pfile, strerror(errno)));
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ return NULL;
+ }
+
+ if( sbuf1.st_ino == sbuf2.st_ino) {
+ /* No race. */
+ break;
+ }
+
+ /*
+ * Race occurred - back off and try again...
+ */
+
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ }
+ }
+
+ if(race_loop == 5) {
+ DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile));
+ return NULL;
+ }
+
+ /* Set a buffer to do more efficient reads */
+ setvbuf(fp, (char *)NULL, _IOFBF, 1024);
+
+ /* Make sure it is only rw by the owner */
+#ifdef HAVE_FCHMOD
+ if(fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) {
+#else
+ if(chmod(pfile, S_IRUSR|S_IWUSR) == -1) {
+#endif
+ DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \
+Error was %s\n.", pfile, strerror(errno) ));
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ return NULL;
+ }
+
+ /* We have a lock on the file. */
+ return fp;
+}
+
+/***************************************************************
+ End enumeration of the smbpasswd list.
+****************************************************************/
+
+static void endsmbfilepwent(FILE *fp, int *lock_depth)
+{
+ if (!fp) {
+ return;
+ }
+
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ DEBUG(7, ("endsmbfilepwent_internal: closed password file.\n"));
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smbpasswd list.
+ *************************************************************************/
+
+static struct smb_passwd *getsmbfilepwent(struct smbpasswd_privates *smbpasswd_state, FILE *fp)
+{
+ /* Static buffers we will return. */
+ struct smb_passwd *pw_buf = &smbpasswd_state->pw_buf;
+ char *user_name = smbpasswd_state->user_name;
+ unsigned char *smbpwd = smbpasswd_state->smbpwd;
+ unsigned char *smbntpwd = smbpasswd_state->smbntpwd;
+ char linebuf[256];
+ int c;
+ unsigned char *p;
+ long uidval;
+ size_t linebuf_len;
+ char *status;
+
+ 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.
+ */
+ status = linebuf;
+ while (status && !feof(fp)) {
+ linebuf[0] = '\0';
+
+ status = fgets(linebuf, 256, fp);
+ if (status == NULL && ferror(fp)) {
+ return NULL;
+ }
+
+ /*
+ * Check if the string is terminated with a newline - if not
+ * then we must keep reading and discard until we get one.
+ */
+ if ((linebuf_len = strlen(linebuf)) == 0) {
+ continue;
+ }
+
+ if (linebuf[linebuf_len - 1] != '\n') {
+ c = '\0';
+ while (!ferror(fp) && !feof(fp)) {
+ c = fgetc(fp);
+ if (c == '\n') {
+ break;
+ }
+ }
+ } else {
+ linebuf[linebuf_len - 1] = '\0';
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf));
+#endif
+ if ((linebuf[0] == 0) && feof(fp)) {
+ DEBUG(4, ("getsmbfilepwent: end of file reached\n"));
+ break;
+ }
+
+ /*
+ * The line we have should be of the form :-
+ *
+ * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
+ * ignored....
+ *
+ * or,
+ *
+ * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
+ *
+ * if Windows NT compatible passwords are also present.
+ * [Account type] is an ascii encoding of the type of account.
+ * LCT-(8 hex digits) is the time_t value of the last change time.
+ */
+
+ if (linebuf[0] == '#' || linebuf[0] == '\0') {
+ DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n"));
+ continue;
+ }
+ p = (unsigned char *) strchr_m(linebuf, ':');
+ if (p == NULL) {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n"));
+ continue;
+ }
+
+ strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
+ user_name[PTR_DIFF(p, linebuf)] = '\0';
+
+ /* Get smb uid. */
+
+ p++; /* Go past ':' */
+
+ if(*p == '-') {
+ DEBUG(0, ("getsmbfilepwent: user name %s has a negative uid.\n", user_name));
+ continue;
+ }
+
+ if (!isdigit(*p)) {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (uid not number)\n",
+ user_name));
+ continue;
+ }
+
+ uidval = atoi((char *) p);
+
+ while (*p && isdigit(*p)) {
+ p++;
+ }
+
+ if (*p != ':') {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (no : after uid)\n",
+ user_name));
+ 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 (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (passwd too short)\n",
+ user_name ));
+ continue;
+ }
+
+ if (p[32] != ':') {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (no terminating :)\n",
+ user_name));
+ continue;
+ }
+
+ if (strnequal((char *) p, "NO PASSWORD", 11)) {
+ pw_buf->smb_passwd = NULL;
+ pw_buf->acct_ctrl |= ACB_PWNOTREQ;
+ } else {
+ if (*p == '*' || *p == 'X') {
+ /* NULL LM password */
+ pw_buf->smb_passwd = NULL;
+ DEBUG(10, ("getsmbfilepwent: LM password for user %s invalidated\n", user_name));
+ } else if (pdb_gethexpwd((char *)p, smbpwd)) {
+ pw_buf->smb_passwd = smbpwd;
+ } else {
+ pw_buf->smb_passwd = NULL;
+ DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry for user %s \
+(non hex chars)\n", user_name));
+ }
+ }
+
+ /*
+ * Now check if the NT compatible password is
+ * available.
+ */
+ pw_buf->smb_nt_passwd = NULL;
+ p += 33; /* Move to the first character of the line after the lanman password. */
+ if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
+ if (*p != '*' && *p != 'X') {
+ if(pdb_gethexpwd((char *)p,smbntpwd)) {
+ pw_buf->smb_nt_passwd = smbntpwd;
+ }
+ }
+ p += 33; /* Move to the first character of the line after the NT password. */
+ }
+
+ DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n",
+ user_name, uidval));
+
+ if (*p == '[') {
+ unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']');
+ pw_buf->acct_ctrl = pdb_decode_acct_ctrl((char*)p);
+
+ /* Must have some account type set. */
+ if(pw_buf->acct_ctrl == 0) {
+ pw_buf->acct_ctrl = ACB_NORMAL;
+ }
+
+ /* Now try and get the last change time. */
+ if(end_p) {
+ p = end_p + 1;
+ }
+ if(*p == ':') {
+ p++;
+ if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) {
+ int i;
+ p += 4;
+ for(i = 0; i < 8; i++) {
+ if(p[i] == '\0' || !isxdigit(p[i])) {
+ break;
+ }
+ }
+ if(i == 8) {
+ /*
+ * p points at 8 characters of hex digits -
+ * read into a time_t as the seconds since
+ * 1970 that the password was last changed.
+ */
+ pw_buf->pass_last_set_time = (time_t)strtol((char *)p, NULL, 16);
+ }
+ }
+ }
+ } else {
+ /* 'Old' style file. Fake up based on user name. */
+ /*
+ * Currently trust accounts are kept in the same
+ * password file as 'normal accounts'. If this changes
+ * we will have to fix this code. JRA.
+ */
+ if(pw_buf->smb_name[strlen(pw_buf->smb_name) - 1] == '$') {
+ pw_buf->acct_ctrl &= ~ACB_NORMAL;
+ pw_buf->acct_ctrl |= ACB_WSTRUST;
+ }
+ }
+
+ return pw_buf;
+ }
+
+ DEBUG(5,("getsmbfilepwent: end of file reached.\n"));
+ return NULL;
+}
+
+/************************************************************************
+ Create a new smbpasswd entry - malloced space returned.
+*************************************************************************/
+
+static char *format_new_smbpasswd_entry(const struct smb_passwd *newpwd)
+{
+ int new_entry_length;
+ char *new_entry;
+ char *p;
+
+ 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 *)SMB_MALLOC( new_entry_length )) == NULL) {
+ DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n",
+ newpwd->smb_name ));
+ return NULL;
+ }
+
+ slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid);
+
+ p = new_entry+strlen(new_entry);
+ pdb_sethexpwd(p, newpwd->smb_passwd, newpwd->acct_ctrl);
+ p+=strlen(p);
+ *p = ':';
+ p++;
+
+ pdb_sethexpwd(p, newpwd->smb_nt_passwd, newpwd->acct_ctrl);
+ p+=strlen(p);
+ *p = ':';
+ p++;
+
+ /* Add the account encoding and the last change time. */
+ slprintf((char *)p, new_entry_length - 1 - (p - new_entry), "%s:LCT-%08X:\n",
+ pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN),
+ (uint32)newpwd->pass_last_set_time);
+
+ return new_entry;
+}
+
+/************************************************************************
+ Routine to add an entry to the smbpasswd file.
+*************************************************************************/
+
+static NTSTATUS add_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state,
+ struct smb_passwd *newpwd)
+{
+ const char *pfile = smbpasswd_state->smbpasswd_file;
+ struct smb_passwd *pwd = NULL;
+ FILE *fp = NULL;
+ int wr_len;
+ int fd;
+ size_t new_entry_length;
+ char *new_entry;
+ SMB_OFF_T offpos;
+
+ /* Open the smbpassword file - for update. */
+ fp = startsmbfilepwent(pfile, PWF_UPDATE, &smbpasswd_state->pw_file_lock_depth);
+
+ if (fp == NULL && errno == ENOENT) {
+ /* Try again - create. */
+ fp = startsmbfilepwent(pfile, PWF_CREATE, &smbpasswd_state->pw_file_lock_depth);
+ }
+
+ if (fp == NULL) {
+ DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n"));
+ return map_nt_error_from_unix(errno);
+ }
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+
+ while ((pwd = getsmbfilepwent(smbpasswd_state, 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, &smbpasswd_state->pw_file_lock_depth);
+ return NT_STATUS_USER_EXISTS;
+ }
+ }
+
+ /* 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) {
+ NTSTATUS result = map_nt_error_from_unix(errno);
+ 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, &smbpasswd_state->pw_file_lock_depth);
+ return result;
+ }
+
+ if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL) {
+ DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \
+Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ new_entry_length = strlen(new_entry);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|",
+ fd, (int)new_entry_length, new_entry));
+#endif
+
+ if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length) {
+ NTSTATUS result = map_nt_error_from_unix(errno);
+ 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, &smbpasswd_state->pw_file_lock_depth);
+ free(new_entry);
+ return result;
+ }
+
+ free(new_entry);
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ return NT_STATUS_OK;
+}
+
+/************************************************************************
+ 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 smbpasswd_privates *smbpasswd_state, const struct smb_passwd* pwd)
+{
+ /* Static buffers we will return. */
+ fstring user_name;
+
+ char *status;
+ char linebuf[256];
+ char readbuf[1024];
+ int c;
+ fstring ascii_p16;
+ fstring encode_bits;
+ unsigned char *p = NULL;
+ size_t linebuf_len = 0;
+ FILE *fp;
+ int lockfd;
+ const char *pfile = smbpasswd_state->smbpasswd_file;
+ bool found_entry = False;
+ bool got_pass_last_set_time = False;
+
+ SMB_OFF_T pwd_seekpos = 0;
+
+ int i;
+ int wr_len;
+ int fd;
+
+ if (!*pfile) {
+ DEBUG(0, ("No SMB password file set\n"));
+ return False;
+ }
+ DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile));
+
+ fp = sys_fopen(pfile, "r+");
+
+ if (fp == NULL) {
+ DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile));
+ return False;
+ }
+ /* Set a buffer to do more efficient reads */
+ setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
+
+ lockfd = fileno(fp);
+
+ if (!pw_file_lock(lockfd, F_WRLCK, 5, &smbpasswd_state->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.
+ */
+ status = linebuf;
+ while (status && !feof(fp)) {
+ pwd_seekpos = sys_ftell(fp);
+
+ linebuf[0] = '\0';
+
+ status = fgets(linebuf, sizeof(linebuf), fp);
+ if (status == NULL && ferror(fp)) {
+ pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /*
+ * Check if the string is terminated with a newline - if not
+ * then we must keep reading and discard until we get one.
+ */
+ linebuf_len = strlen(linebuf);
+ if (linebuf[linebuf_len - 1] != '\n') {
+ c = '\0';
+ while (!ferror(fp) && !feof(fp)) {
+ c = fgetc(fp);
+ if (c == '\n') {
+ break;
+ }
+ }
+ } else {
+ linebuf[linebuf_len - 1] = '\0';
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf));
+#endif
+
+ if ((linebuf[0] == 0) && feof(fp)) {
+ DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n"));
+ break;
+ }
+
+ /*
+ * The line we have should be of the form :-
+ *
+ * username:uid:[32hex bytes]:....other flags presently
+ * ignored....
+ *
+ * or,
+ *
+ * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored.
+ *
+ * if Windows NT compatible passwords are also present.
+ */
+
+ if (linebuf[0] == '#' || linebuf[0] == '\0') {
+ DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n"));
+ continue;
+ }
+
+ p = (unsigned char *) strchr_m(linebuf, ':');
+
+ if (p == NULL) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n"));
+ continue;
+ }
+
+ 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, &smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+
+ DEBUG(2, ("Cannot update entry for user %s, as they don't exist in the smbpasswd file!\n",
+ pwd->smb_name));
+ return False;
+ }
+
+ DEBUG(6, ("mod_smbfilepwd_entry: entry exists for user %s\n", pwd->smb_name));
+
+ /* User name matches - get uid and password */
+ p++; /* Go past ':' */
+
+ if (!isdigit(*p)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (uid not number)\n",
+ pwd->smb_name));
+ pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ while (*p && isdigit(*p)) {
+ p++;
+ }
+ if (*p != ':') {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no : after uid)\n",
+ pwd->smb_name));
+ pw_file_unlock(lockfd, &smbpasswd_state->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 (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (passwd too short)\n",
+ pwd->smb_name));
+ pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return (False);
+ }
+
+ if (p[32] != ':') {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no terminating :)\n",
+ pwd->smb_name));
+ pw_file_unlock(lockfd,&smbpasswd_state->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 for user %s (passwd too short)\n",
+ pwd->smb_name));
+ pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return (False);
+ }
+
+ if (p[32] != ':') {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no terminating :)\n",
+ pwd->smb_name));
+ pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /*
+ * Now check if the account info and the password last
+ * change time is available.
+ */
+ p += 33; /* Move to the first character of the line after the NT password. */
+
+ if (*p == '[') {
+ i = 0;
+ encode_bits[i++] = *p++;
+ while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']')) {
+ encode_bits[i++] = *p++;
+ }
+
+ encode_bits[i++] = ']';
+ encode_bits[i++] = '\0';
+
+ if(i == NEW_PW_FORMAT_SPACE_PADDED_LEN) {
+ /*
+ * We are using a new format, space padded
+ * acct ctrl field. Encode the given acct ctrl
+ * bits into it.
+ */
+ fstrcpy(encode_bits, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN));
+ } else {
+ DEBUG(0,("mod_smbfilepwd_entry: Using old smbpasswd format for user %s. \
+This is no longer supported.!\n", pwd->smb_name));
+ DEBUG(0,("mod_smbfilepwd_entry: No changes made, failing.!\n"));
+ pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /* Go past the ']' */
+ if(linebuf_len > PTR_DIFF(p, linebuf)) {
+ p++;
+ }
+
+ if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) {
+ p++;
+
+ /* We should be pointing at the LCT entry. */
+ if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && (StrnCaseCmp((char *)p, "LCT-", 4) == 0)) {
+ p += 4;
+ for(i = 0; i < 8; i++) {
+ if(p[i] == '\0' || !isxdigit(p[i])) {
+ break;
+ }
+ }
+ if(i == 8) {
+ /*
+ * p points at 8 characters of hex digits -
+ * read into a time_t as the seconds since
+ * 1970 that the password was last changed.
+ */
+ got_pass_last_set_time = True;
+ } /* i == 8 */
+ } /* *p && StrnCaseCmp() */
+ } /* p == ':' */
+ } /* p == '[' */
+
+ /* Entry is correctly formed. */
+
+ /* Create the 32 byte representation of the new p16 */
+ pdb_sethexpwd(ascii_p16, pwd->smb_passwd, pwd->acct_ctrl);
+
+ /* Add on the NT md4 hash */
+ ascii_p16[32] = ':';
+ wr_len = 66;
+ pdb_sethexpwd(ascii_p16+33, pwd->smb_nt_passwd, pwd->acct_ctrl);
+ ascii_p16[65] = ':';
+ ascii_p16[66] = '\0'; /* null-terminate the string so that strlen works */
+
+ /* Add on the account info bits and the time of last password change. */
+ if(got_pass_last_set_time) {
+ slprintf(&ascii_p16[strlen(ascii_p16)],
+ sizeof(ascii_p16)-(strlen(ascii_p16)+1),
+ "%s:LCT-%08X:",
+ encode_bits, (uint32)pwd->pass_last_set_time );
+ wr_len = strlen(ascii_p16);
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("mod_smbfilepwd_entry: "));
+ dump_data(100, (uint8 *)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,&smbpasswd_state->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,&smbpasswd_state->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,&smbpasswd_state->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,&smbpasswd_state->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,&smbpasswd_state->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,&smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return True;
+}
+
+/************************************************************************
+ Routine to delete an entry in the smbpasswd file by name.
+*************************************************************************/
+
+static bool del_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const char *name)
+{
+ const char *pfile = smbpasswd_state->smbpasswd_file;
+ char *pfile2 = NULL;
+ struct smb_passwd *pwd = NULL;
+ FILE *fp = NULL;
+ FILE *fp_write = NULL;
+ int pfile2_lockdepth = 0;
+
+ pfile2 = talloc_asprintf(talloc_tos(),
+ "%s.%u",
+ pfile, (unsigned)sys_getpid());
+ if (!pfile2) {
+ return false;
+ }
+
+ /*
+ * Open the smbpassword file - for update. It needs to be update
+ * as we need any other processes to wait until we have replaced
+ * it.
+ */
+
+ if((fp = startsmbfilepwent(pfile, PWF_UPDATE, &smbpasswd_state->pw_file_lock_depth)) == NULL) {
+ DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
+ return False;
+ }
+
+ /*
+ * Create the replacement password file.
+ */
+ if((fp_write = startsmbfilepwent(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) {
+ DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ return False;
+ }
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+
+ while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
+ char *new_entry;
+ size_t new_entry_length;
+
+ if (strequal(name, pwd->smb_name)) {
+ DEBUG(10, ("del_smbfilepwd_entry: found entry with "
+ "name %s - deleting it.\n", name));
+ continue;
+ }
+
+ /*
+ * We need to copy the entry out into the second file.
+ */
+
+ if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL) {
+ DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \
+Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
+ unlink(pfile2);
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ endsmbfilepwent(fp_write, &pfile2_lockdepth);
+ return False;
+ }
+
+ new_entry_length = strlen(new_entry);
+
+ if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length) {
+ DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \
+Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
+ unlink(pfile2);
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ endsmbfilepwent(fp_write, &pfile2_lockdepth);
+ free(new_entry);
+ return False;
+ }
+
+ free(new_entry);
+ }
+
+ /*
+ * Ensure pfile2 is flushed before rename.
+ */
+
+ if(fflush(fp_write) != 0) {
+ DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno)));
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ endsmbfilepwent(fp_write,&pfile2_lockdepth);
+ return False;
+ }
+
+ /*
+ * Do an atomic rename - then release the locks.
+ */
+
+ if(rename(pfile2,pfile) != 0) {
+ unlink(pfile2);
+ }
+
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ endsmbfilepwent(fp_write,&pfile2_lockdepth);
+ return True;
+}
+
+/*********************************************************************
+ Create a smb_passwd struct from a struct samu.
+ We will not allocate any new memory. The smb_passwd struct
+ should only stay around as long as the struct samu does.
+ ********************************************************************/
+
+static bool build_smb_pass (struct smb_passwd *smb_pw, const struct samu *sampass)
+{
+ uint32 rid;
+
+ if (sampass == NULL)
+ return False;
+ ZERO_STRUCTP(smb_pw);
+
+ if (!IS_SAM_DEFAULT(sampass, PDB_USERSID)) {
+ rid = pdb_get_user_rid(sampass);
+
+ /* If the user specified a RID, make sure its able to be both stored and retreived */
+ if (rid == DOMAIN_USER_RID_GUEST) {
+ struct passwd *passwd = getpwnam_alloc(NULL, lp_guestaccount());
+ if (!passwd) {
+ DEBUG(0, ("Could not find guest account via getpwnam()! (%s)\n", lp_guestaccount()));
+ return False;
+ }
+ smb_pw->smb_userid=passwd->pw_uid;
+ TALLOC_FREE(passwd);
+ } else if (algorithmic_pdb_rid_is_user(rid)) {
+ smb_pw->smb_userid=algorithmic_pdb_user_rid_to_uid(rid);
+ } else {
+ DEBUG(0,("build_sam_pass: Failing attempt to store user with non-uid based user RID. \n"));
+ return False;
+ }
+ }
+
+ smb_pw->smb_name=(const char*)pdb_get_username(sampass);
+
+ smb_pw->smb_passwd=pdb_get_lanman_passwd(sampass);
+ smb_pw->smb_nt_passwd=pdb_get_nt_passwd(sampass);
+
+ smb_pw->acct_ctrl=pdb_get_acct_ctrl(sampass);
+ smb_pw->pass_last_set_time=pdb_get_pass_last_set_time(sampass);
+
+ return True;
+}
+
+/*********************************************************************
+ Create a struct samu from a smb_passwd struct
+ ********************************************************************/
+
+static bool build_sam_account(struct smbpasswd_privates *smbpasswd_state,
+ struct samu *sam_pass, const struct smb_passwd *pw_buf)
+{
+ struct passwd *pwfile;
+
+ if ( !sam_pass ) {
+ DEBUG(5,("build_sam_account: struct samu is NULL\n"));
+ return False;
+ }
+
+ /* verify the user account exists */
+
+ if ( !(pwfile = Get_Pwnam_alloc(NULL, pw_buf->smb_name )) ) {
+ DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s with uid "
+ "%u is not in unix passwd database!\n", pw_buf->smb_name, pw_buf->smb_userid));
+ return False;
+ }
+
+ if ( !NT_STATUS_IS_OK( samu_set_unix(sam_pass, pwfile )) )
+ return False;
+
+ TALLOC_FREE(pwfile);
+
+ /* set remaining fields */
+
+ if (!pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd, PDB_SET))
+ return False;
+ if (!pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd, PDB_SET))
+ return False;
+ pdb_set_acct_ctrl (sam_pass, pw_buf->acct_ctrl, PDB_SET);
+ pdb_set_pass_last_set_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET);
+ pdb_set_pass_can_change_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET);
+
+ return True;
+}
+
+/*****************************************************************
+ Functions to be implemented by the new passdb API
+ ****************************************************************/
+
+/****************************************************************
+ Search smbpasswd file by iterating over the entries. Do not
+ call getpwnam() for unix account information until we have found
+ the correct entry
+ ***************************************************************/
+
+static NTSTATUS smbpasswd_getsampwnam(struct pdb_methods *my_methods,
+ struct samu *sam_acct, const char *username)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
+ struct smb_passwd *smb_pw;
+ FILE *fp = NULL;
+
+ DEBUG(10, ("getsampwnam (smbpasswd): search by name: %s\n", username));
+
+ /* startsmbfilepwent() is used here as we don't want to lookup
+ the UNIX account in the local system password file until
+ we have a match. */
+ fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ, &(smbpasswd_state->pw_file_lock_depth));
+
+ if (fp == NULL) {
+ DEBUG(0, ("Unable to open passdb database.\n"));
+ return nt_status;
+ }
+
+ while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL)&& (!strequal(smb_pw->smb_name, username)) )
+ /* do nothing....another loop */ ;
+
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+
+
+ /* did we locate the username in smbpasswd */
+ if (smb_pw == NULL)
+ return nt_status;
+
+ DEBUG(10, ("getsampwnam (smbpasswd): found by name: %s\n", smb_pw->smb_name));
+
+ if (!sam_acct) {
+ DEBUG(10,("getsampwnam (smbpasswd): struct samu is NULL\n"));
+ return nt_status;
+ }
+
+ /* now build the struct samu */
+ if (!build_sam_account(smbpasswd_state, sam_acct, smb_pw))
+ return nt_status;
+
+ /* success */
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS smbpasswd_getsampwsid(struct pdb_methods *my_methods, struct samu *sam_acct, const DOM_SID *sid)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
+ struct smb_passwd *smb_pw;
+ FILE *fp = NULL;
+ uint32 rid;
+
+ DEBUG(10, ("smbpasswd_getsampwrid: search by sid: %s\n",
+ sid_string_dbg(sid)));
+
+ if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ /* More special case 'guest account' hacks... */
+ if (rid == DOMAIN_USER_RID_GUEST) {
+ const char *guest_account = lp_guestaccount();
+ if (!(guest_account && *guest_account)) {
+ DEBUG(1, ("Guest account not specfied!\n"));
+ return nt_status;
+ }
+ return smbpasswd_getsampwnam(my_methods, sam_acct, guest_account);
+ }
+
+ /* Open the sam password file - not for update. */
+ fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ, &(smbpasswd_state->pw_file_lock_depth));
+
+ if (fp == NULL) {
+ DEBUG(0, ("Unable to open passdb database.\n"));
+ return nt_status;
+ }
+
+ while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL) && (algorithmic_pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) )
+ /* do nothing */ ;
+
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+
+
+ /* did we locate the username in smbpasswd */
+ if (smb_pw == NULL)
+ return nt_status;
+
+ DEBUG(10, ("getsampwrid (smbpasswd): found by name: %s\n", smb_pw->smb_name));
+
+ if (!sam_acct) {
+ DEBUG(10,("getsampwrid: (smbpasswd) struct samu is NULL\n"));
+ return nt_status;
+ }
+
+ /* now build the struct samu */
+ if (!build_sam_account (smbpasswd_state, sam_acct, smb_pw))
+ return nt_status;
+
+ /* build_sam_account might change the SID on us, if the name was for the guest account */
+ if (NT_STATUS_IS_OK(nt_status) && !sid_equal(pdb_get_user_sid(sam_acct), sid)) {
+ DEBUG(1, ("looking for user with sid %s instead returned %s "
+ "for account %s!?!\n", sid_string_dbg(sid),
+ sid_string_dbg(pdb_get_user_sid(sam_acct)),
+ pdb_get_username(sam_acct)));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* success */
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS smbpasswd_add_sam_account(struct pdb_methods *my_methods, struct samu *sampass)
+{
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
+ struct smb_passwd smb_pw;
+
+ /* convert the struct samu */
+ if (!build_smb_pass(&smb_pw, sampass)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* add the entry */
+ return add_smbfilepwd_entry(smbpasswd_state, &smb_pw);
+}
+
+static NTSTATUS smbpasswd_update_sam_account(struct pdb_methods *my_methods, struct samu *sampass)
+{
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
+ struct smb_passwd smb_pw;
+
+ /* convert the struct samu */
+ if (!build_smb_pass(&smb_pw, sampass)) {
+ DEBUG(0, ("smbpasswd_update_sam_account: build_smb_pass failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* update the entry */
+ if(!mod_smbfilepwd_entry(smbpasswd_state, &smb_pw)) {
+ DEBUG(0, ("smbpasswd_update_sam_account: mod_smbfilepwd_entry failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS smbpasswd_delete_sam_account (struct pdb_methods *my_methods, struct samu *sampass)
+{
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
+
+ const char *username = pdb_get_username(sampass);
+
+ if (del_smbfilepwd_entry(smbpasswd_state, username))
+ return NT_STATUS_OK;
+
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+static NTSTATUS smbpasswd_rename_sam_account (struct pdb_methods *my_methods,
+ struct samu *old_acct,
+ const char *newname)
+{
+ char *rename_script = NULL;
+ struct samu *new_acct = NULL;
+ bool interim_account = False;
+ TALLOC_CTX *ctx = talloc_tos();
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ if (!*(lp_renameuser_script()))
+ goto done;
+
+ if ( !(new_acct = samu_new( NULL )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( !pdb_copy_sam_account( new_acct, old_acct )
+ || !pdb_set_username(new_acct, newname, PDB_CHANGED))
+ {
+ goto done;
+ }
+
+ ret = smbpasswd_add_sam_account(my_methods, new_acct);
+ if (!NT_STATUS_IS_OK(ret))
+ goto done;
+
+ interim_account = True;
+
+ /* rename the posix user */
+ rename_script = talloc_strdup(ctx,
+ lp_renameuser_script());
+ if (!rename_script) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if (*rename_script) {
+ int rename_ret;
+
+ rename_script = talloc_string_sub2(ctx,
+ rename_script,
+ "%unew",
+ newname,
+ true,
+ false,
+ true);
+ if (!rename_script) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ rename_script = talloc_string_sub2(ctx,
+ rename_script,
+ "%uold",
+ pdb_get_username(old_acct),
+ true,
+ false,
+ true);
+ if (!rename_script) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rename_ret = smbrun(rename_script, NULL);
+
+ DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret));
+
+ if (rename_ret == 0) {
+ smb_nscd_flush_user_cache();
+ }
+
+ if (rename_ret)
+ goto done;
+ } else {
+ goto done;
+ }
+
+ smbpasswd_delete_sam_account(my_methods, old_acct);
+ interim_account = False;
+
+done:
+ /* cleanup */
+ if (interim_account)
+ smbpasswd_delete_sam_account(my_methods, new_acct);
+
+ if (new_acct)
+ TALLOC_FREE(new_acct);
+
+ return (ret);
+}
+
+static bool smbpasswd_rid_algorithm(struct pdb_methods *methods)
+{
+ return True;
+}
+
+static void free_private_data(void **vp)
+{
+ struct smbpasswd_privates **privates = (struct smbpasswd_privates**)vp;
+
+ endsmbfilepwent((*privates)->pw_file, &((*privates)->pw_file_lock_depth));
+
+ *privates = NULL;
+ /* No need to free any further, as it is talloc()ed */
+}
+
+struct smbpasswd_search_state {
+ uint32_t acct_flags;
+
+ struct samr_displayentry *entries;
+ uint32_t num_entries;
+ ssize_t array_size;
+ uint32_t current;
+};
+
+static void smbpasswd_search_end(struct pdb_search *search)
+{
+ struct smbpasswd_search_state *state = talloc_get_type_abort(
+ search->private_data, struct smbpasswd_search_state);
+ TALLOC_FREE(state);
+}
+
+static bool smbpasswd_search_next_entry(struct pdb_search *search,
+ struct samr_displayentry *entry)
+{
+ struct smbpasswd_search_state *state = talloc_get_type_abort(
+ search->private_data, struct smbpasswd_search_state);
+
+ if (state->current == state->num_entries) {
+ return false;
+ }
+
+ entry->idx = state->entries[state->current].idx;
+ entry->rid = state->entries[state->current].rid;
+ entry->acct_flags = state->entries[state->current].acct_flags;
+
+ entry->account_name = talloc_strdup(
+ search->mem_ctx, state->entries[state->current].account_name);
+ entry->fullname = talloc_strdup(
+ search->mem_ctx, state->entries[state->current].fullname);
+ entry->description = talloc_strdup(
+ search->mem_ctx, state->entries[state->current].description);
+
+ if ((entry->account_name == NULL) || (entry->fullname == NULL)
+ || (entry->description == NULL)) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ return false;
+ }
+
+ state->current += 1;
+ return true;
+}
+
+static bool smbpasswd_search_users(struct pdb_methods *methods,
+ struct pdb_search *search,
+ uint32_t acct_flags)
+{
+ struct smbpasswd_privates *smbpasswd_state =
+ (struct smbpasswd_privates*)methods->private_data;
+
+ struct smbpasswd_search_state *search_state;
+ struct smb_passwd *pwd;
+ FILE *fp;
+
+ search_state = TALLOC_ZERO_P(search->mem_ctx,
+ struct smbpasswd_search_state);
+ if (search_state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return false;
+ }
+ search_state->acct_flags = acct_flags;
+
+ fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ,
+ &smbpasswd_state->pw_file_lock_depth);
+
+ if (fp == NULL) {
+ DEBUG(10, ("Unable to open smbpasswd file.\n"));
+ TALLOC_FREE(search_state);
+ return false;
+ }
+
+ while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
+ struct samr_displayentry entry;
+ struct samu *user;
+
+ if ((acct_flags != 0)
+ && ((acct_flags & pwd->acct_ctrl) == 0)) {
+ continue;
+ }
+
+ user = samu_new(talloc_tos());
+ if (user == NULL) {
+ DEBUG(0, ("samu_new failed\n"));
+ break;
+ }
+
+ if (!build_sam_account(smbpasswd_state, user, pwd)) {
+ /* Already got debug msgs... */
+ break;
+ }
+
+ ZERO_STRUCT(entry);
+
+ entry.acct_flags = pdb_get_acct_ctrl(user);
+ sid_peek_rid(pdb_get_user_sid(user), &entry.rid);
+ entry.account_name = talloc_strdup(
+ search_state, pdb_get_username(user));
+ entry.fullname = talloc_strdup(
+ search_state, pdb_get_fullname(user));
+ entry.description = talloc_strdup(
+ search_state, pdb_get_acct_desc(user));
+
+ TALLOC_FREE(user);
+
+ if ((entry.account_name == NULL) || (entry.fullname == NULL)
+ || (entry.description == NULL)) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ break;
+ }
+
+ ADD_TO_LARGE_ARRAY(search_state, struct samr_displayentry,
+ entry, &search_state->entries,
+ &search_state->num_entries,
+ &search_state->array_size);
+ }
+
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+
+ search->private_data = search_state;
+ search->next_entry = smbpasswd_search_next_entry;
+ search->search_end = smbpasswd_search_end;
+
+ return true;
+}
+
+static NTSTATUS pdb_init_smbpasswd( struct pdb_methods **pdb_method, const char *location )
+{
+ NTSTATUS nt_status;
+ struct smbpasswd_privates *privates;
+
+ if ( !NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method )) ) {
+ return nt_status;
+ }
+
+ (*pdb_method)->name = "smbpasswd";
+
+ (*pdb_method)->getsampwnam = smbpasswd_getsampwnam;
+ (*pdb_method)->getsampwsid = smbpasswd_getsampwsid;
+ (*pdb_method)->add_sam_account = smbpasswd_add_sam_account;
+ (*pdb_method)->update_sam_account = smbpasswd_update_sam_account;
+ (*pdb_method)->delete_sam_account = smbpasswd_delete_sam_account;
+ (*pdb_method)->rename_sam_account = smbpasswd_rename_sam_account;
+ (*pdb_method)->search_users = smbpasswd_search_users;
+
+ (*pdb_method)->rid_algorithm = smbpasswd_rid_algorithm;
+
+ /* Setup private data and free function */
+
+ if ( !(privates = TALLOC_ZERO_P( *pdb_method, struct smbpasswd_privates )) ) {
+ DEBUG(0, ("talloc() failed for smbpasswd private_data!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Store some config details */
+
+ if (location) {
+ privates->smbpasswd_file = talloc_strdup(*pdb_method, location);
+ } else {
+ privates->smbpasswd_file = talloc_strdup(*pdb_method, lp_smb_passwd_file());
+ }
+
+ if (!privates->smbpasswd_file) {
+ DEBUG(0, ("talloc_strdp() failed for storing smbpasswd location!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*pdb_method)->private_data = privates;
+
+ (*pdb_method)->free_private_data = free_private_data;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_smbpasswd_init(void)
+{
+ return smb_register_passdb(PASSDB_INTERFACE_VERSION, "smbpasswd", pdb_init_smbpasswd);
+}
diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c
new file mode 100644
index 0000000000..e40f4bbab8
--- /dev/null
+++ b/source3/passdb/pdb_tdb.c
@@ -0,0 +1,1639 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Simo Sorce 2000-2003
+ * Copyright (C) Gerald Carter 2000-2006
+ * Copyright (C) Jeremy Allison 2001
+ * Copyright (C) Andrew Bartlett 2002
+ * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#if 0 /* when made a module use this */
+
+static int tdbsam_debug_level = DBGC_ALL;
+#undef DBGC_CLASS
+#define DBGC_CLASS tdbsam_debug_level
+
+#else
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+#endif
+
+#define TDBSAM_VERSION 3 /* Most recent TDBSAM version */
+#define TDBSAM_VERSION_STRING "INFO/version"
+#define PASSDB_FILE_NAME "passdb.tdb"
+#define USERPREFIX "USER_"
+#define USERPREFIX_LEN 5
+#define RIDPREFIX "RID_"
+#define PRIVPREFIX "PRIV_"
+
+/* GLOBAL TDB SAM CONTEXT */
+
+static struct db_context *db_sam;
+static char *tdbsam_filename;
+
+/**********************************************************************
+ Marshall/unmarshall struct samu structs.
+ *********************************************************************/
+
+#define TDB_FORMAT_STRING_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd"
+#define TDB_FORMAT_STRING_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd"
+#define TDB_FORMAT_STRING_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd"
+
+/*********************************************************************
+*********************************************************************/
+
+static bool init_sam_from_buffer_v0(struct samu *sampass, uint8 *buf, uint32 buflen)
+{
+
+ /* times are stored as 32bit integer
+ take care on system with 64bit wide time_t
+ --SSS */
+ uint32 logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+ char *username = NULL;
+ char *domain = NULL;
+ char *nt_username = NULL;
+ char *dir_drive = NULL;
+ char *unknown_str = NULL;
+ char *munged_dial = NULL;
+ char *fullname = NULL;
+ char *homedir = NULL;
+ char *logon_script = NULL;
+ char *profile_path = NULL;
+ char *acct_desc = NULL;
+ char *workstations = NULL;
+ uint32 username_len, domain_len, nt_username_len,
+ dir_drive_len, unknown_str_len, munged_dial_len,
+ fullname_len, homedir_len, logon_script_len,
+ profile_path_len, acct_desc_len, workstations_len;
+
+ uint32 user_rid, group_rid, remove_me, hours_len, unknown_6;
+ uint16 acct_ctrl, logon_divs;
+ uint16 bad_password_count, logon_count;
+ uint8 *hours = NULL;
+ uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL;
+ uint32 len = 0;
+ uint32 lm_pw_len, nt_pw_len, hourslen;
+ bool ret = True;
+
+ if(sampass == NULL || buf == NULL) {
+ DEBUG(0, ("init_sam_from_buffer_v0: NULL parameters found!\n"));
+ return False;
+ }
+
+/* TDB_FORMAT_STRING_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd" */
+
+ /* unpack the buffer into variables */
+ len = tdb_unpack (buf, buflen, TDB_FORMAT_STRING_V0,
+ &logon_time, /* d */
+ &logoff_time, /* d */
+ &kickoff_time, /* d */
+ &pass_last_set_time, /* d */
+ &pass_can_change_time, /* d */
+ &pass_must_change_time, /* d */
+ &username_len, &username, /* B */
+ &domain_len, &domain, /* B */
+ &nt_username_len, &nt_username, /* B */
+ &fullname_len, &fullname, /* B */
+ &homedir_len, &homedir, /* B */
+ &dir_drive_len, &dir_drive, /* B */
+ &logon_script_len, &logon_script, /* B */
+ &profile_path_len, &profile_path, /* B */
+ &acct_desc_len, &acct_desc, /* B */
+ &workstations_len, &workstations, /* B */
+ &unknown_str_len, &unknown_str, /* B */
+ &munged_dial_len, &munged_dial, /* B */
+ &user_rid, /* d */
+ &group_rid, /* d */
+ &lm_pw_len, &lm_pw_ptr, /* B */
+ &nt_pw_len, &nt_pw_ptr, /* B */
+ &acct_ctrl, /* w */
+ &remove_me, /* remove on the next TDB_FORMAT upgarde */ /* d */
+ &logon_divs, /* w */
+ &hours_len, /* d */
+ &hourslen, &hours, /* B */
+ &bad_password_count, /* w */
+ &logon_count, /* w */
+ &unknown_6); /* d */
+
+ if (len == (uint32) -1) {
+ ret = False;
+ goto done;
+ }
+
+ pdb_set_logon_time(sampass, logon_time, PDB_SET);
+ pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
+ pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
+ pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
+ pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
+ pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
+
+ pdb_set_username(sampass, username, PDB_SET);
+ pdb_set_domain(sampass, domain, PDB_SET);
+ pdb_set_nt_username(sampass, nt_username, PDB_SET);
+ pdb_set_fullname(sampass, fullname, PDB_SET);
+
+ if (homedir) {
+ pdb_set_homedir(sampass, homedir, PDB_SET);
+ }
+ else {
+ pdb_set_homedir(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_home()),
+ PDB_DEFAULT);
+ }
+
+ if (dir_drive)
+ pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
+ else {
+ pdb_set_dir_drive(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_drive()),
+ PDB_DEFAULT);
+ }
+
+ if (logon_script)
+ pdb_set_logon_script(sampass, logon_script, PDB_SET);
+ else {
+ pdb_set_logon_script(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_script()),
+ PDB_DEFAULT);
+ }
+
+ if (profile_path) {
+ pdb_set_profile_path(sampass, profile_path, PDB_SET);
+ } else {
+ pdb_set_profile_path(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_path()),
+ PDB_DEFAULT);
+ }
+
+ pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
+ pdb_set_workstations(sampass, workstations, PDB_SET);
+ pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
+
+ if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
+ if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
+ if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
+ pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
+ pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
+ pdb_set_hours_len(sampass, hours_len, PDB_SET);
+ pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
+ pdb_set_logon_count(sampass, logon_count, PDB_SET);
+ pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
+ pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
+ pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
+ pdb_set_hours(sampass, hours, PDB_SET);
+
+done:
+
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ SAFE_FREE(nt_username);
+ SAFE_FREE(fullname);
+ SAFE_FREE(homedir);
+ SAFE_FREE(dir_drive);
+ SAFE_FREE(logon_script);
+ SAFE_FREE(profile_path);
+ SAFE_FREE(acct_desc);
+ SAFE_FREE(workstations);
+ SAFE_FREE(munged_dial);
+ SAFE_FREE(unknown_str);
+ SAFE_FREE(lm_pw_ptr);
+ SAFE_FREE(nt_pw_ptr);
+ SAFE_FREE(hours);
+
+ return ret;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool init_sam_from_buffer_v1(struct samu *sampass, uint8 *buf, uint32 buflen)
+{
+
+ /* times are stored as 32bit integer
+ take care on system with 64bit wide time_t
+ --SSS */
+ uint32 logon_time,
+ logoff_time,
+ kickoff_time,
+ bad_password_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+ char *username = NULL;
+ char *domain = NULL;
+ char *nt_username = NULL;
+ char *dir_drive = NULL;
+ char *unknown_str = NULL;
+ char *munged_dial = NULL;
+ char *fullname = NULL;
+ char *homedir = NULL;
+ char *logon_script = NULL;
+ char *profile_path = NULL;
+ char *acct_desc = NULL;
+ char *workstations = NULL;
+ uint32 username_len, domain_len, nt_username_len,
+ dir_drive_len, unknown_str_len, munged_dial_len,
+ fullname_len, homedir_len, logon_script_len,
+ profile_path_len, acct_desc_len, workstations_len;
+
+ uint32 user_rid, group_rid, remove_me, hours_len, unknown_6;
+ uint16 acct_ctrl, logon_divs;
+ uint16 bad_password_count, logon_count;
+ uint8 *hours = NULL;
+ uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL;
+ uint32 len = 0;
+ uint32 lm_pw_len, nt_pw_len, hourslen;
+ bool ret = True;
+
+ if(sampass == NULL || buf == NULL) {
+ DEBUG(0, ("init_sam_from_buffer_v1: NULL parameters found!\n"));
+ return False;
+ }
+
+/* TDB_FORMAT_STRING_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd" */
+
+ /* unpack the buffer into variables */
+ len = tdb_unpack (buf, buflen, TDB_FORMAT_STRING_V1,
+ &logon_time, /* d */
+ &logoff_time, /* d */
+ &kickoff_time, /* d */
+ /* Change from V0 is addition of bad_password_time field. */
+ &bad_password_time, /* d */
+ &pass_last_set_time, /* d */
+ &pass_can_change_time, /* d */
+ &pass_must_change_time, /* d */
+ &username_len, &username, /* B */
+ &domain_len, &domain, /* B */
+ &nt_username_len, &nt_username, /* B */
+ &fullname_len, &fullname, /* B */
+ &homedir_len, &homedir, /* B */
+ &dir_drive_len, &dir_drive, /* B */
+ &logon_script_len, &logon_script, /* B */
+ &profile_path_len, &profile_path, /* B */
+ &acct_desc_len, &acct_desc, /* B */
+ &workstations_len, &workstations, /* B */
+ &unknown_str_len, &unknown_str, /* B */
+ &munged_dial_len, &munged_dial, /* B */
+ &user_rid, /* d */
+ &group_rid, /* d */
+ &lm_pw_len, &lm_pw_ptr, /* B */
+ &nt_pw_len, &nt_pw_ptr, /* B */
+ &acct_ctrl, /* w */
+ &remove_me, /* d */
+ &logon_divs, /* w */
+ &hours_len, /* d */
+ &hourslen, &hours, /* B */
+ &bad_password_count, /* w */
+ &logon_count, /* w */
+ &unknown_6); /* d */
+
+ if (len == (uint32) -1) {
+ ret = False;
+ goto done;
+ }
+
+ pdb_set_logon_time(sampass, logon_time, PDB_SET);
+ pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
+ pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
+
+ /* Change from V0 is addition of bad_password_time field. */
+ pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
+ pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
+ pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
+ pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
+
+ pdb_set_username(sampass, username, PDB_SET);
+ pdb_set_domain(sampass, domain, PDB_SET);
+ pdb_set_nt_username(sampass, nt_username, PDB_SET);
+ pdb_set_fullname(sampass, fullname, PDB_SET);
+
+ if (homedir) {
+ pdb_set_homedir(sampass, homedir, PDB_SET);
+ }
+ else {
+ pdb_set_homedir(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_home()),
+ PDB_DEFAULT);
+ }
+
+ if (dir_drive)
+ pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
+ else {
+ pdb_set_dir_drive(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_drive()),
+ PDB_DEFAULT);
+ }
+
+ if (logon_script)
+ pdb_set_logon_script(sampass, logon_script, PDB_SET);
+ else {
+ pdb_set_logon_script(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_script()),
+ PDB_DEFAULT);
+ }
+
+ if (profile_path) {
+ pdb_set_profile_path(sampass, profile_path, PDB_SET);
+ } else {
+ pdb_set_profile_path(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_path()),
+ PDB_DEFAULT);
+ }
+
+ pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
+ pdb_set_workstations(sampass, workstations, PDB_SET);
+ pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
+
+ if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
+ if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
+ if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
+
+ pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
+ pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
+ pdb_set_hours_len(sampass, hours_len, PDB_SET);
+ pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
+ pdb_set_logon_count(sampass, logon_count, PDB_SET);
+ pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
+ pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
+ pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
+ pdb_set_hours(sampass, hours, PDB_SET);
+
+done:
+
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ SAFE_FREE(nt_username);
+ SAFE_FREE(fullname);
+ SAFE_FREE(homedir);
+ SAFE_FREE(dir_drive);
+ SAFE_FREE(logon_script);
+ SAFE_FREE(profile_path);
+ SAFE_FREE(acct_desc);
+ SAFE_FREE(workstations);
+ SAFE_FREE(munged_dial);
+ SAFE_FREE(unknown_str);
+ SAFE_FREE(lm_pw_ptr);
+ SAFE_FREE(nt_pw_ptr);
+ SAFE_FREE(hours);
+
+ return ret;
+}
+
+bool init_sam_from_buffer_v2(struct samu *sampass, uint8 *buf, uint32 buflen)
+{
+
+ /* times are stored as 32bit integer
+ take care on system with 64bit wide time_t
+ --SSS */
+ uint32 logon_time,
+ logoff_time,
+ kickoff_time,
+ bad_password_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+ char *username = NULL;
+ char *domain = NULL;
+ char *nt_username = NULL;
+ char *dir_drive = NULL;
+ char *unknown_str = NULL;
+ char *munged_dial = NULL;
+ char *fullname = NULL;
+ char *homedir = NULL;
+ char *logon_script = NULL;
+ char *profile_path = NULL;
+ char *acct_desc = NULL;
+ char *workstations = NULL;
+ uint32 username_len, domain_len, nt_username_len,
+ dir_drive_len, unknown_str_len, munged_dial_len,
+ fullname_len, homedir_len, logon_script_len,
+ profile_path_len, acct_desc_len, workstations_len;
+
+ uint32 user_rid, group_rid, hours_len, unknown_6;
+ uint16 acct_ctrl, logon_divs;
+ uint16 bad_password_count, logon_count;
+ uint8 *hours = NULL;
+ uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL, *nt_pw_hist_ptr = NULL;
+ uint32 len = 0;
+ uint32 lm_pw_len, nt_pw_len, nt_pw_hist_len, hourslen;
+ uint32 pwHistLen = 0;
+ bool ret = True;
+ fstring tmp_string;
+ bool expand_explicit = lp_passdb_expand_explicit();
+
+ if(sampass == NULL || buf == NULL) {
+ DEBUG(0, ("init_sam_from_buffer_v2: NULL parameters found!\n"));
+ return False;
+ }
+
+/* TDB_FORMAT_STRING_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" */
+
+ /* unpack the buffer into variables */
+ len = tdb_unpack (buf, buflen, TDB_FORMAT_STRING_V2,
+ &logon_time, /* d */
+ &logoff_time, /* d */
+ &kickoff_time, /* d */
+ &bad_password_time, /* d */
+ &pass_last_set_time, /* d */
+ &pass_can_change_time, /* d */
+ &pass_must_change_time, /* d */
+ &username_len, &username, /* B */
+ &domain_len, &domain, /* B */
+ &nt_username_len, &nt_username, /* B */
+ &fullname_len, &fullname, /* B */
+ &homedir_len, &homedir, /* B */
+ &dir_drive_len, &dir_drive, /* B */
+ &logon_script_len, &logon_script, /* B */
+ &profile_path_len, &profile_path, /* B */
+ &acct_desc_len, &acct_desc, /* B */
+ &workstations_len, &workstations, /* B */
+ &unknown_str_len, &unknown_str, /* B */
+ &munged_dial_len, &munged_dial, /* B */
+ &user_rid, /* d */
+ &group_rid, /* d */
+ &lm_pw_len, &lm_pw_ptr, /* B */
+ &nt_pw_len, &nt_pw_ptr, /* B */
+ /* Change from V1 is addition of password history field. */
+ &nt_pw_hist_len, &nt_pw_hist_ptr, /* B */
+ &acct_ctrl, /* w */
+ /* Also "remove_me" field was removed. */
+ &logon_divs, /* w */
+ &hours_len, /* d */
+ &hourslen, &hours, /* B */
+ &bad_password_count, /* w */
+ &logon_count, /* w */
+ &unknown_6); /* d */
+
+ if (len == (uint32) -1) {
+ ret = False;
+ goto done;
+ }
+
+ pdb_set_logon_time(sampass, logon_time, PDB_SET);
+ pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
+ pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
+ pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
+ pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
+ pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
+ pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
+
+ pdb_set_username(sampass, username, PDB_SET);
+ pdb_set_domain(sampass, domain, PDB_SET);
+ pdb_set_nt_username(sampass, nt_username, PDB_SET);
+ pdb_set_fullname(sampass, fullname, PDB_SET);
+
+ if (homedir) {
+ fstrcpy( tmp_string, homedir );
+ if (expand_explicit) {
+ standard_sub_basic( username, domain, tmp_string,
+ sizeof(tmp_string) );
+ }
+ pdb_set_homedir(sampass, tmp_string, PDB_SET);
+ }
+ else {
+ pdb_set_homedir(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_home()),
+ PDB_DEFAULT);
+ }
+
+ if (dir_drive)
+ pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
+ else
+ pdb_set_dir_drive(sampass, lp_logon_drive(), PDB_DEFAULT );
+
+ if (logon_script) {
+ fstrcpy( tmp_string, logon_script );
+ if (expand_explicit) {
+ standard_sub_basic( username, domain, tmp_string,
+ sizeof(tmp_string) );
+ }
+ pdb_set_logon_script(sampass, tmp_string, PDB_SET);
+ }
+ else {
+ pdb_set_logon_script(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_script()),
+ PDB_DEFAULT);
+ }
+
+ if (profile_path) {
+ fstrcpy( tmp_string, profile_path );
+ if (expand_explicit) {
+ standard_sub_basic( username, domain, tmp_string,
+ sizeof(tmp_string) );
+ }
+ pdb_set_profile_path(sampass, tmp_string, PDB_SET);
+ }
+ else {
+ pdb_set_profile_path(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_path()),
+ PDB_DEFAULT);
+ }
+
+ pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
+ pdb_set_workstations(sampass, workstations, PDB_SET);
+ pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
+
+ if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
+ if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
+ if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ /* Change from V1 is addition of password history field. */
+ pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen);
+ if (pwHistLen) {
+ uint8 *pw_hist = SMB_MALLOC_ARRAY(uint8, pwHistLen * PW_HISTORY_ENTRY_LEN);
+ if (!pw_hist) {
+ ret = False;
+ goto done;
+ }
+ memset(pw_hist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN);
+ if (nt_pw_hist_ptr && nt_pw_hist_len) {
+ int i;
+ SMB_ASSERT((nt_pw_hist_len % PW_HISTORY_ENTRY_LEN) == 0);
+ nt_pw_hist_len /= PW_HISTORY_ENTRY_LEN;
+ for (i = 0; (i < pwHistLen) && (i < nt_pw_hist_len); i++) {
+ memcpy(&pw_hist[i*PW_HISTORY_ENTRY_LEN],
+ &nt_pw_hist_ptr[i*PW_HISTORY_ENTRY_LEN],
+ PW_HISTORY_ENTRY_LEN);
+ }
+ }
+ if (!pdb_set_pw_history(sampass, pw_hist, pwHistLen, PDB_SET)) {
+ SAFE_FREE(pw_hist);
+ ret = False;
+ goto done;
+ }
+ SAFE_FREE(pw_hist);
+ } else {
+ pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
+ }
+
+ pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
+ pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
+ pdb_set_hours_len(sampass, hours_len, PDB_SET);
+ pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
+ pdb_set_logon_count(sampass, logon_count, PDB_SET);
+ pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
+ pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
+ pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
+ pdb_set_hours(sampass, hours, PDB_SET);
+
+done:
+
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ SAFE_FREE(nt_username);
+ SAFE_FREE(fullname);
+ SAFE_FREE(homedir);
+ SAFE_FREE(dir_drive);
+ SAFE_FREE(logon_script);
+ SAFE_FREE(profile_path);
+ SAFE_FREE(acct_desc);
+ SAFE_FREE(workstations);
+ SAFE_FREE(munged_dial);
+ SAFE_FREE(unknown_str);
+ SAFE_FREE(lm_pw_ptr);
+ SAFE_FREE(nt_pw_ptr);
+ SAFE_FREE(nt_pw_hist_ptr);
+ SAFE_FREE(hours);
+
+ return ret;
+}
+
+
+/**********************************************************************
+ Intialize a struct samu struct from a BYTE buffer of size len
+ *********************************************************************/
+
+static bool init_sam_from_buffer(struct samu *sampass, uint8 *buf, uint32 buflen)
+{
+ return init_sam_from_buffer_v3(sampass, buf, buflen);
+}
+
+/**********************************************************************
+ Intialize a BYTE buffer from a struct samu struct
+ *********************************************************************/
+
+static uint32 init_buffer_from_sam (uint8 **buf, struct samu *sampass, bool size_only)
+{
+ return init_buffer_from_sam_v3(buf, sampass, size_only);
+}
+
+/**********************************************************************
+ Intialize a BYTE buffer from a struct samu struct
+ *********************************************************************/
+
+struct tdbsam_convert_state {
+ int32_t from;
+ bool success;
+};
+
+static int tdbsam_convert_one(struct db_record *rec, void *priv)
+{
+ struct tdbsam_convert_state *state =
+ (struct tdbsam_convert_state *)priv;
+ struct samu *user;
+ TDB_DATA data;
+ NTSTATUS status;
+ bool ret;
+
+ if (rec->key.dsize < USERPREFIX_LEN) {
+ return 0;
+ }
+ if (strncmp((char *)rec->key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
+ return 0;
+ }
+
+ user = samu_new(talloc_tos());
+ if (user == NULL) {
+ DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
+ state->success = false;
+ return -1;
+ }
+
+ DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
+ "(version:%d)\n", rec->key.dptr, state->from));
+
+ switch (state->from) {
+ case 0:
+ ret = init_sam_from_buffer_v0(user, (uint8 *)rec->value.dptr,
+ rec->value.dsize);
+ break;
+ case 1:
+ ret = init_sam_from_buffer_v1(user, (uint8 *)rec->value.dptr,
+ rec->value.dsize);
+ break;
+ case 2:
+ ret = init_sam_from_buffer_v2(user, (uint8 *)rec->value.dptr,
+ rec->value.dsize);
+ break;
+ case 3:
+ ret = init_sam_from_buffer_v3(user, (uint8 *)rec->value.dptr,
+ rec->value.dsize);
+ break;
+ default:
+ /* unknown tdbsam version */
+ ret = False;
+ }
+ if (!ret) {
+ DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
+ "from TDB (key:%s) (version:%d)\n", rec->key.dptr,
+ state->from));
+ TALLOC_FREE(user);
+ state->success = false;
+ return -1;
+ }
+
+ data.dsize = init_buffer_from_sam(&data.dptr, user, false);
+ TALLOC_FREE(user);
+
+ if (data.dsize == -1) {
+ DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
+ "the new format\n"));
+ state->success = false;
+ return -1;
+ }
+
+ status = rec->store(rec, data, TDB_MODIFY);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Could not store the new record: %s\n",
+ nt_errstr(status)));
+ state->success = false;
+ return -1;
+ }
+
+ return 0;
+}
+
+static bool tdbsam_convert(struct db_context *db, int32 from)
+{
+ struct tdbsam_convert_state state;
+ int ret;
+
+ state.from = from;
+ state.success = true;
+
+ if (db->transaction_start(db) != 0) {
+ DEBUG(0, ("Could not start transaction\n"));
+ return false;
+ }
+
+ ret = db->traverse(db, tdbsam_convert_one, &state);
+ if (ret < 0) {
+ DEBUG(0, ("traverse failed\n"));
+ goto cancel;
+ }
+
+ if (!state.success) {
+ DEBUG(0, ("Converting records failed\n"));
+ goto cancel;
+ }
+
+ if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
+ TDBSAM_VERSION) != 0) {
+ DEBUG(0, ("Could not store tdbsam version\n"));
+ goto cancel;
+ }
+
+ if (db->transaction_commit(db) != 0) {
+ DEBUG(0, ("Could not commit transaction\n"));
+ return false;
+ }
+
+ return true;
+
+ cancel:
+ if (db->transaction_cancel(db) != 0) {
+ smb_panic("transaction_cancel failed");
+ }
+
+ return false;
+}
+
+/*********************************************************************
+ Open the tdbsam file based on the absolute path specified.
+ Uses a reference count to allow multiple open calls.
+*********************************************************************/
+
+static bool tdbsam_open( const char *name )
+{
+ int32 version;
+
+ /* check if we are already open */
+
+ if ( db_sam ) {
+ return true;
+ }
+
+ /* Try to open tdb passwd. Create a new one if necessary */
+
+ db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
+ if (db_sam == NULL) {
+ DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
+ "[%s]\n", name));
+ return false;
+ }
+
+ /* Check the version */
+ version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
+ if (version == -1) {
+ version = 0; /* Version not found, assume version 0 */
+ }
+
+ /* Compare the version */
+ if (version > TDBSAM_VERSION) {
+ /* Version more recent than the latest known */
+ DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
+ TALLOC_FREE(db_sam);
+ return false;
+ }
+
+ if ( version < TDBSAM_VERSION ) {
+ DEBUG(1, ("tdbsam_open: Converting version %d database to "
+ "version %d.\n", version, TDBSAM_VERSION));
+
+ if ( !tdbsam_convert(db_sam, version) ) {
+ DEBUG(0, ("tdbsam_open: Error when trying to convert "
+ "tdbsam [%s]\n",name));
+ TALLOC_FREE(db_sam);
+ return false;
+ }
+
+ DEBUG(3, ("TDBSAM converted successfully.\n"));
+ }
+
+ DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
+
+ return true;
+}
+
+/******************************************************************
+ Lookup a name in the SAM TDB
+******************************************************************/
+
+static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
+ struct samu *user, const char *sname)
+{
+ TDB_DATA data;
+ fstring keystr;
+ fstring name;
+
+ if ( !user ) {
+ DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Data is stored in all lower-case */
+ fstrcpy(name, sname);
+ strlower_m(name);
+
+ /* set search key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+
+ /* open the database */
+
+ if ( !tdbsam_open( tdbsam_filename ) ) {
+ DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* get the record */
+
+ data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
+ if (!data.dptr) {
+ DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
+ DEBUGADD(5, (" Key: %s\n", keystr));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* unpack the buffer */
+
+ if (!init_sam_from_buffer(user, data.dptr, data.dsize)) {
+ DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
+ SAFE_FREE(data.dptr);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* success */
+
+ TALLOC_FREE(data.dptr);
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ Search by rid
+ **************************************************************************/
+
+static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
+ struct samu *user, uint32 rid)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ TDB_DATA data;
+ fstring keystr;
+ fstring name;
+
+ if ( !user ) {
+ DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
+ return nt_status;
+ }
+
+ /* set search key */
+
+ slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
+
+ /* open the database */
+
+ if ( !tdbsam_open( tdbsam_filename ) ) {
+ DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* get the record */
+
+ data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
+ if (!data.dptr) {
+ DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ fstrcpy(name, (const char *)data.dptr);
+ TALLOC_FREE(data.dptr);
+
+ return tdbsam_getsampwnam (my_methods, user, name);
+}
+
+static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
+ struct samu * user, const DOM_SID *sid)
+{
+ uint32 rid;
+
+ if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
+ return NT_STATUS_UNSUCCESSFUL;
+
+ return tdbsam_getsampwrid(my_methods, user, rid);
+}
+
+static bool tdb_delete_samacct_only( struct samu *sam_pass )
+{
+ fstring keystr;
+ fstring name;
+ NTSTATUS status;
+
+ fstrcpy(name, pdb_get_username(sam_pass));
+ strlower_m(name);
+
+ /* set the search key */
+
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+
+ /* it's outaa here! 8^) */
+
+ status = dbwrap_delete_bystring(db_sam, keystr);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("Error deleting entry from tdb passwd "
+ "database: %s!\n", nt_errstr(status)));
+ return false;
+ }
+
+ return true;
+}
+
+/***************************************************************************
+ Delete a struct samu records for the username and RID key
+****************************************************************************/
+
+static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
+ struct samu *sam_pass)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ fstring keystr;
+ uint32 rid;
+ fstring name;
+
+ /* open the database */
+
+ if ( !tdbsam_open( tdbsam_filename ) ) {
+ DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
+ tdbsam_filename));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ fstrcpy(name, pdb_get_username(sam_pass));
+ strlower_m(name);
+
+ /* set the search key */
+
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+
+ rid = pdb_get_user_rid(sam_pass);
+
+ /* it's outaa here! 8^) */
+
+ if (db_sam->transaction_start(db_sam) != 0) {
+ DEBUG(0, ("Could not start transaction\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ nt_status = dbwrap_delete_bystring(db_sam, keystr);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(5, ("Error deleting entry from tdb passwd "
+ "database: %s!\n", nt_errstr(nt_status)));
+ goto cancel;
+ }
+
+ /* set the search key */
+
+ slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
+
+ /* it's outaa here! 8^) */
+
+ nt_status = dbwrap_delete_bystring(db_sam, keystr);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(5, ("Error deleting entry from tdb rid "
+ "database: %s!\n", nt_errstr(nt_status)));
+ goto cancel;
+ }
+
+ if (db_sam->transaction_commit(db_sam) != 0) {
+ DEBUG(0, ("Could not commit transaction\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ return NT_STATUS_OK;
+
+ cancel:
+ if (db_sam->transaction_cancel(db_sam) != 0) {
+ smb_panic("transaction_cancel failed");
+ }
+
+ return nt_status;
+}
+
+
+/***************************************************************************
+ Update the TDB SAM account record only
+ Assumes that the tdbsam is already open
+****************************************************************************/
+static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
+{
+ TDB_DATA data;
+ uint8 *buf = NULL;
+ fstring keystr;
+ fstring name;
+ bool ret = false;
+ NTSTATUS status;
+
+ /* copy the struct samu struct into a BYTE buffer for storage */
+
+ if ( (data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1 ) {
+ DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
+ goto done;
+ }
+ data.dptr = buf;
+
+ fstrcpy(name, pdb_get_username(newpwd));
+ strlower_m(name);
+
+ DEBUG(5, ("Storing %saccount %s with RID %d\n",
+ flag == TDB_INSERT ? "(new) " : "", name,
+ pdb_get_user_rid(newpwd)));
+
+ /* setup the USER index key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+
+ /* add the account */
+
+ status = dbwrap_store_bystring(db_sam, keystr, data, flag);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Unable to modify passwd TDB: %s!",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ ret = true;
+
+done:
+ /* cleanup */
+ SAFE_FREE(buf);
+ return ret;
+}
+
+/***************************************************************************
+ Update the TDB SAM RID record only
+ Assumes that the tdbsam is already open
+****************************************************************************/
+static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
+{
+ TDB_DATA data;
+ fstring keystr;
+ fstring name;
+ NTSTATUS status;
+
+ fstrcpy(name, pdb_get_username(newpwd));
+ strlower_m(name);
+
+ /* setup RID data */
+ data = string_term_tdb_data(name);
+
+ /* setup the RID index key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
+ pdb_get_user_rid(newpwd));
+
+ /* add the reference */
+ status = dbwrap_store_bystring(db_sam, keystr, data, flag);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
+ nt_errstr(status)));
+ return false;
+ }
+
+ return true;
+
+}
+
+/***************************************************************************
+ Update the TDB SAM
+****************************************************************************/
+
+static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
+ int flag)
+{
+ if (!pdb_get_user_rid(newpwd)) {
+ DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
+ pdb_get_username(newpwd)));
+ return False;
+ }
+
+ /* open the database */
+
+ if ( !tdbsam_open( tdbsam_filename ) ) {
+ DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
+ return False;
+ }
+
+ if (db_sam->transaction_start(db_sam) != 0) {
+ DEBUG(0, ("Could not start transaction\n"));
+ return false;
+ }
+
+ if (!tdb_update_samacct_only(newpwd, flag)
+ || !tdb_update_ridrec_only(newpwd, flag)) {
+ goto cancel;
+ }
+
+ if (db_sam->transaction_commit(db_sam) != 0) {
+ DEBUG(0, ("Could not commit transaction\n"));
+ return false;
+ }
+
+ return true;
+
+ cancel:
+ if (db_sam->transaction_cancel(db_sam) != 0) {
+ smb_panic("transaction_cancel failed");
+ }
+ return false;
+}
+
+/***************************************************************************
+ Modifies an existing struct samu
+****************************************************************************/
+
+static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
+{
+ if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
+ return NT_STATUS_UNSUCCESSFUL;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ Adds an existing struct samu
+****************************************************************************/
+
+static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
+{
+ if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
+ return NT_STATUS_UNSUCCESSFUL;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ Renames a struct samu
+ - check for the posix user/rename user script
+ - Add and lock the new user record
+ - rename the posix user
+ - rewrite the rid->username record
+ - delete the old user
+ - unlock the new user record
+***************************************************************************/
+static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
+ struct samu *old_acct,
+ const char *newname)
+{
+ struct samu *new_acct = NULL;
+ char *rename_script = NULL;
+ int rename_ret;
+ fstring oldname_lower;
+ fstring newname_lower;
+
+ /* can't do anything without an external script */
+
+ if ( !(new_acct = samu_new( talloc_tos() )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rename_script = talloc_strdup(new_acct, lp_renameuser_script());
+ if (!rename_script) {
+ TALLOC_FREE(new_acct);
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (!*rename_script) {
+ TALLOC_FREE(new_acct);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if ( !pdb_copy_sam_account(new_acct, old_acct)
+ || !pdb_set_username(new_acct, newname, PDB_CHANGED))
+ {
+ TALLOC_FREE(new_acct);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* open the database */
+ if ( !tdbsam_open( tdbsam_filename ) ) {
+ DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
+ tdbsam_filename));
+ TALLOC_FREE(new_acct);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (db_sam->transaction_start(db_sam) != 0) {
+ DEBUG(0, ("Could not start transaction\n"));
+ TALLOC_FREE(new_acct);
+ return NT_STATUS_ACCESS_DENIED;
+
+ }
+
+ /* add the new account and lock it */
+ if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
+ goto cancel;
+ }
+
+ /* Rename the posix user. Follow the semantics of _samr_create_user()
+ so that we lower case the posix name but preserve the case in passdb */
+
+ fstrcpy( oldname_lower, pdb_get_username(old_acct) );
+ strlower_m( oldname_lower );
+
+ fstrcpy( newname_lower, newname );
+ strlower_m( newname_lower );
+
+ rename_script = talloc_string_sub2(new_acct,
+ rename_script,
+ "%unew",
+ newname_lower,
+ true,
+ false,
+ true);
+ if (!rename_script) {
+ goto cancel;
+ }
+ rename_script = talloc_string_sub2(new_acct,
+ rename_script,
+ "%uold",
+ oldname_lower,
+ true,
+ false,
+ true);
+ if (!rename_script) {
+ goto cancel;
+ }
+ rename_ret = smbrun(rename_script, NULL);
+
+ DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
+ rename_script, rename_ret));
+
+ if (rename_ret != 0) {
+ goto cancel;
+ }
+
+ smb_nscd_flush_user_cache();
+
+ /* rewrite the rid->username record */
+
+ if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
+ goto cancel;
+ }
+
+ tdb_delete_samacct_only( old_acct );
+
+ if (db_sam->transaction_commit(db_sam) != 0) {
+ /*
+ * Ok, we're screwed. We've changed the posix account, but
+ * could not adapt passdb.tdb. Shall we change the posix
+ * account back?
+ */
+ DEBUG(0, ("transaction_commit failed\n"));
+ TALLOC_FREE(new_acct);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ TALLOC_FREE(new_acct );
+ return NT_STATUS_OK;
+
+ cancel:
+ if (db_sam->transaction_cancel(db_sam) != 0) {
+ smb_panic("transaction_cancel failed");
+ }
+
+ TALLOC_FREE(new_acct);
+
+ return NT_STATUS_ACCESS_DENIED;
+}
+
+static bool tdbsam_rid_algorithm(struct pdb_methods *methods)
+{
+ return False;
+}
+
+/*
+ * Historically, winbind was responsible for allocating RIDs, so the next RID
+ * value was stored in winbindd_idmap.tdb. It has been moved to passdb now,
+ * but for compatibility reasons we still keep the the next RID counter in
+ * winbindd_idmap.tdb.
+ */
+
+/*****************************************************************************
+ Initialise idmap database. For now (Dec 2005) this is a copy of the code in
+ sam/idmap_tdb.c. Maybe at a later stage we can remove that capability from
+ winbind completely and store the RID counter in passdb.tdb.
+
+ Dont' fully initialize with the HWM values, if it's new, we're only
+ interested in the RID counter.
+*****************************************************************************/
+
+static bool init_idmap_tdb(TDB_CONTEXT *tdb)
+{
+ int32 version;
+
+ if (tdb_lock_bystring(tdb, "IDMAP_VERSION") != 0) {
+ DEBUG(0, ("Could not lock IDMAP_VERSION\n"));
+ return False;
+ }
+
+ version = tdb_fetch_int32(tdb, "IDMAP_VERSION");
+
+ if (version == -1) {
+ /* No key found, must be a new db */
+ if (tdb_store_int32(tdb, "IDMAP_VERSION",
+ IDMAP_VERSION) != 0) {
+ DEBUG(0, ("Could not store IDMAP_VERSION\n"));
+ tdb_unlock_bystring(tdb, "IDMAP_VERSION");
+ return False;
+ }
+ version = IDMAP_VERSION;
+ }
+
+ if (version != IDMAP_VERSION) {
+ DEBUG(0, ("Expected IDMAP_VERSION=%d, found %d. Please "
+ "start winbind once\n", IDMAP_VERSION, version));
+ tdb_unlock_bystring(tdb, "IDMAP_VERSION");
+ return False;
+ }
+
+ tdb_unlock_bystring(tdb, "IDMAP_VERSION");
+ return True;
+}
+
+static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
+{
+ TDB_CONTEXT *tdb;
+ uint32 rid;
+ bool ret = False;
+
+ tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
+ TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
+
+ if (tdb == NULL) {
+ DEBUG(1, ("Could not open idmap: %s\n", strerror(errno)));
+ goto done;
+ }
+
+ if (!init_idmap_tdb(tdb)) {
+ DEBUG(1, ("Could not init idmap\n"));
+ goto done;
+ }
+
+ rid = BASE_RID; /* Default if not set */
+
+ if (!tdb_change_uint32_atomic(tdb, "RID_COUNTER", &rid, 1)) {
+ DEBUG(3, ("tdbsam_new_rid: Failed to increase RID_COUNTER\n"));
+ goto done;
+ }
+
+ *prid = rid;
+ ret = True;
+
+ done:
+ if ((tdb != NULL) && (tdb_close(tdb) != 0)) {
+ smb_panic("tdb_close(idmap_tdb) failed");
+ }
+
+ return ret;
+}
+
+struct tdbsam_search_state {
+ struct pdb_methods *methods;
+ uint32_t acct_flags;
+
+ uint32_t *rids;
+ uint32_t num_rids;
+ ssize_t array_size;
+ uint32_t current;
+};
+
+static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
+{
+ struct tdbsam_search_state *state = talloc_get_type_abort(
+ private_data, struct tdbsam_search_state);
+ size_t prefixlen = strlen(RIDPREFIX);
+ uint32 rid;
+
+ if ((rec->key.dsize < prefixlen)
+ || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
+ return 0;
+ }
+
+ rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
+
+ ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
+ &state->array_size);
+
+ return 0;
+}
+
+static void tdbsam_search_end(struct pdb_search *search)
+{
+ struct tdbsam_search_state *state = talloc_get_type_abort(
+ search->private_data, struct tdbsam_search_state);
+ TALLOC_FREE(state);
+}
+
+static bool tdbsam_search_next_entry(struct pdb_search *search,
+ struct samr_displayentry *entry)
+{
+ struct tdbsam_search_state *state = talloc_get_type_abort(
+ search->private_data, struct tdbsam_search_state);
+ struct samu *user = NULL;
+ NTSTATUS status;
+ uint32_t rid;
+
+ again:
+ TALLOC_FREE(user);
+ user = samu_new(talloc_tos());
+ if (user == NULL) {
+ DEBUG(0, ("samu_new failed\n"));
+ return false;
+ }
+
+ if (state->current == state->num_rids) {
+ return false;
+ }
+
+ rid = state->rids[state->current++];
+
+ status = tdbsam_getsampwrid(state->methods, user, rid);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
+ /*
+ * Someone has deleted that user since we listed the RIDs
+ */
+ goto again;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(user);
+ return false;
+ }
+
+ if ((state->acct_flags != 0) &&
+ ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
+ goto again;
+ }
+
+ entry->acct_flags = pdb_get_acct_ctrl(user);
+ entry->rid = rid;
+ entry->account_name = talloc_strdup(
+ search->mem_ctx, pdb_get_username(user));
+ entry->fullname = talloc_strdup(
+ search->mem_ctx, pdb_get_fullname(user));
+ entry->description = talloc_strdup(
+ search->mem_ctx, pdb_get_acct_desc(user));
+
+ TALLOC_FREE(user);
+
+ if ((entry->account_name == NULL) || (entry->fullname == NULL)
+ || (entry->description == NULL)) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ return false;
+ }
+
+ return true;
+}
+
+static bool tdbsam_search_users(struct pdb_methods *methods,
+ struct pdb_search *search,
+ uint32 acct_flags)
+{
+ struct tdbsam_search_state *state;
+
+ if (!tdbsam_open(tdbsam_filename)) {
+ DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
+ tdbsam_filename));
+ return false;
+ }
+
+ state = TALLOC_ZERO_P(search->mem_ctx, struct tdbsam_search_state);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return false;
+ }
+ state->acct_flags = acct_flags;
+ state->methods = methods;
+
+ db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
+
+ search->private_data = state;
+ search->next_entry = tdbsam_search_next_entry;
+ search->search_end = tdbsam_search_end;
+
+ return true;
+}
+
+/*********************************************************************
+ Initialize the tdb sam backend. Setup the dispath table of methods,
+ open the tdb, etc...
+*********************************************************************/
+
+static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
+{
+ NTSTATUS nt_status;
+ char *tdbfile = NULL;
+ const char *pfile = location;
+
+ if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
+ return nt_status;
+ }
+
+ (*pdb_method)->name = "tdbsam";
+
+ (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
+ (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
+ (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
+ (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
+ (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
+ (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
+ (*pdb_method)->search_users = tdbsam_search_users;
+
+ (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
+ (*pdb_method)->new_rid = tdbsam_new_rid;
+
+ /* save the path for later */
+
+ if (!location) {
+ if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
+ PASSDB_FILE_NAME) < 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ pfile = tdbfile;
+ }
+ tdbsam_filename = SMB_STRDUP(pfile);
+ if (!tdbsam_filename) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ SAFE_FREE(tdbfile);
+
+ /* no private data */
+
+ (*pdb_method)->private_data = NULL;
+ (*pdb_method)->free_private_data = NULL;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_tdbsam_init(void)
+{
+ return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
+}
diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c
new file mode 100644
index 0000000000..4527ae7127
--- /dev/null
+++ b/source3/passdb/secrets.c
@@ -0,0 +1,1366 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Rafal Szczesniak 2002
+ Copyright (C) Tim Potter 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* the Samba secrets database stores any generated, private information
+ such as the local SID and machine trust password */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+static struct db_context *db_ctx;
+
+/* Urrrg. global.... */
+bool global_machine_password_needs_changing;
+
+/**
+ * Use a TDB to store an incrementing random seed.
+ *
+ * Initialised to the current pid, the very first time Samba starts,
+ * and incremented by one each time it is needed.
+ *
+ * @note Not called by systems with a working /dev/urandom.
+ */
+static void get_rand_seed(int *new_seed)
+{
+ *new_seed = sys_getpid();
+ if (db_ctx) {
+ dbwrap_change_int32_atomic(db_ctx, "INFO/random_seed",
+ new_seed, 1);
+ }
+}
+
+/* open up the secrets database */
+bool secrets_init(void)
+{
+ char *fname = NULL;
+ unsigned char dummy;
+
+ if (db_ctx != NULL)
+ return True;
+
+ fname = talloc_asprintf(talloc_tos(), "%s/secrets.tdb",
+ lp_private_dir());
+ if (fname == NULL) {
+ return false;
+ }
+
+ db_ctx = db_open(NULL, fname, 0,
+ TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+
+ if (db_ctx == NULL) {
+ DEBUG(0,("Failed to open %s\n", fname));
+ TALLOC_FREE(fname);
+ return False;
+ }
+
+ TALLOC_FREE(fname);
+
+ /**
+ * Set a reseed function for the crypto random generator
+ *
+ * This avoids a problem where systems without /dev/urandom
+ * could send the same challenge to multiple clients
+ */
+ set_rand_reseed_callback(get_rand_seed);
+
+ /* Ensure that the reseed is done now, while we are root, etc */
+ generate_random_buffer(&dummy, sizeof(dummy));
+
+ return True;
+}
+
+struct db_context *secrets_db_ctx(void)
+{
+ if (!secrets_init()) {
+ return NULL;
+ }
+
+ return db_ctx;
+}
+
+/*
+ * close secrets.tdb
+ */
+void secrets_shutdown(void)
+{
+ TALLOC_FREE(db_ctx);
+}
+
+/* read a entry from the secrets database - the caller must free the result
+ if size is non-null then the size of the entry is put in there
+ */
+void *secrets_fetch(const char *key, size_t *size)
+{
+ TDB_DATA dbuf;
+ void *result;
+
+ if (!secrets_init()) {
+ return NULL;
+ }
+
+ if (db_ctx->fetch(db_ctx, talloc_tos(), string_tdb_data(key),
+ &dbuf) != 0) {
+ return NULL;
+ }
+
+ result = memdup(dbuf.dptr, dbuf.dsize);
+ if (result == NULL) {
+ return NULL;
+ }
+ TALLOC_FREE(dbuf.dptr);
+
+ if (size) {
+ *size = dbuf.dsize;
+ }
+
+ return result;
+}
+
+/* store a secrets entry
+ */
+bool secrets_store(const char *key, const void *data, size_t size)
+{
+ NTSTATUS status;
+
+ if (!secrets_init()) {
+ return false;
+ }
+
+ status = dbwrap_trans_store(db_ctx, string_tdb_data(key),
+ make_tdb_data((const uint8 *)data, size),
+ TDB_REPLACE);
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/* delete a secets database entry
+ */
+bool secrets_delete(const char *key)
+{
+ NTSTATUS status;
+ if (!secrets_init()) {
+ return false;
+ }
+
+ status = dbwrap_trans_delete(db_ctx, string_tdb_data(key));
+
+ return NT_STATUS_IS_OK(status);
+}
+
+/**
+ * Form a key for fetching the domain sid
+ *
+ * @param domain domain name
+ *
+ * @return keystring
+ **/
+static const char *domain_sid_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_DOMAIN_SID, domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+bool secrets_store_domain_sid(const char *domain, const DOM_SID *sid)
+{
+ bool ret;
+
+ ret = secrets_store(domain_sid_keystr(domain), sid, sizeof(DOM_SID));
+
+ /* Force a re-query, in case we modified our domain */
+ if (ret)
+ reset_global_sam_sid();
+ return ret;
+}
+
+bool secrets_fetch_domain_sid(const char *domain, DOM_SID *sid)
+{
+ DOM_SID *dyn_sid;
+ size_t size = 0;
+
+ dyn_sid = (DOM_SID *)secrets_fetch(domain_sid_keystr(domain), &size);
+
+ if (dyn_sid == NULL)
+ return False;
+
+ if (size != sizeof(DOM_SID)) {
+ SAFE_FREE(dyn_sid);
+ return False;
+ }
+
+ *sid = *dyn_sid;
+ SAFE_FREE(dyn_sid);
+ return True;
+}
+
+bool secrets_store_domain_guid(const char *domain, struct GUID *guid)
+{
+ fstring key;
+
+ slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_DOMAIN_GUID, domain);
+ strupper_m(key);
+ return secrets_store(key, guid, sizeof(struct GUID));
+}
+
+bool secrets_fetch_domain_guid(const char *domain, struct GUID *guid)
+{
+ struct GUID *dyn_guid;
+ fstring key;
+ size_t size = 0;
+ struct GUID new_guid;
+
+ slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_DOMAIN_GUID, domain);
+ strupper_m(key);
+ dyn_guid = (struct GUID *)secrets_fetch(key, &size);
+
+ if (!dyn_guid) {
+ if (lp_server_role() == ROLE_DOMAIN_PDC) {
+ smb_uuid_generate_random(&new_guid);
+ if (!secrets_store_domain_guid(domain, &new_guid))
+ return False;
+ dyn_guid = (struct GUID *)secrets_fetch(key, &size);
+ }
+ if (dyn_guid == NULL) {
+ return False;
+ }
+ }
+
+ if (size != sizeof(struct GUID)) {
+ DEBUG(1,("UUID size %d is wrong!\n", (int)size));
+ SAFE_FREE(dyn_guid);
+ return False;
+ }
+
+ *guid = *dyn_guid;
+ SAFE_FREE(dyn_guid);
+ return True;
+}
+
+/**
+ * Form a key for fetching the machine trust account sec channel type
+ *
+ * @param domain domain name
+ *
+ * @return keystring
+ **/
+static const char *machine_sec_channel_type_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_MACHINE_SEC_CHANNEL_TYPE,
+ domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+/**
+ * Form a key for fetching the machine trust account last change time
+ *
+ * @param domain domain name
+ *
+ * @return keystring
+ **/
+static const char *machine_last_change_time_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_MACHINE_LAST_CHANGE_TIME,
+ domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+
+/**
+ * Form a key for fetching the machine trust account password
+ *
+ * @param domain domain name
+ *
+ * @return keystring
+ **/
+static const char *machine_password_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_MACHINE_PASSWORD, domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+/**
+ * Form a key for fetching the machine trust account password
+ *
+ * @param domain domain name
+ *
+ * @return stored password's key
+ **/
+static const char *trust_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_MACHINE_ACCT_PASS, domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+/**
+ * Form a key for fetching a trusted domain password
+ *
+ * @param domain trusted domain name
+ *
+ * @return stored password's key
+ **/
+static char *trustdom_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_DOMTRUST_ACCT_PASS,
+ domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+/************************************************************************
+ Lock the trust password entry.
+************************************************************************/
+
+void *secrets_get_trust_account_lock(TALLOC_CTX *mem_ctx, const char *domain)
+{
+ if (!secrets_init()) {
+ return NULL;
+ }
+
+ return db_ctx->fetch_locked(
+ db_ctx, mem_ctx, string_term_tdb_data(trust_keystr(domain)));
+}
+
+/************************************************************************
+ Routine to get the default secure channel type for trust accounts
+************************************************************************/
+
+uint32 get_default_sec_channel(void)
+{
+ if (lp_server_role() == ROLE_DOMAIN_BDC ||
+ lp_server_role() == ROLE_DOMAIN_PDC) {
+ return SEC_CHAN_BDC;
+ } else {
+ return SEC_CHAN_WKSTA;
+ }
+}
+
+/************************************************************************
+ Routine to get the trust account password for a domain.
+ This only tries to get the legacy hashed version of the password.
+ The user of this function must have locked the trust password file using
+ the above secrets_lock_trust_account_password().
+************************************************************************/
+
+bool secrets_fetch_trust_account_password_legacy(const char *domain,
+ uint8 ret_pwd[16],
+ time_t *pass_last_set_time,
+ uint32 *channel)
+{
+ struct machine_acct_pass *pass;
+ size_t size = 0;
+
+ if (!(pass = (struct machine_acct_pass *)secrets_fetch(
+ trust_keystr(domain), &size))) {
+ DEBUG(5, ("secrets_fetch failed!\n"));
+ return False;
+ }
+
+ if (size != sizeof(*pass)) {
+ DEBUG(0, ("secrets were of incorrect size!\n"));
+ SAFE_FREE(pass);
+ return False;
+ }
+
+ if (pass_last_set_time) {
+ *pass_last_set_time = pass->mod_time;
+ }
+ memcpy(ret_pwd, pass->hash, 16);
+
+ if (channel) {
+ *channel = get_default_sec_channel();
+ }
+
+ /* Test if machine password has expired and needs to be changed */
+ if (lp_machine_password_timeout()) {
+ if (pass->mod_time > 0 && time(NULL) > (pass->mod_time +
+ (time_t)lp_machine_password_timeout())) {
+ global_machine_password_needs_changing = True;
+ }
+ }
+
+ SAFE_FREE(pass);
+ return True;
+}
+
+/************************************************************************
+ Routine to get the trust account password for a domain.
+ The user of this function must have locked the trust password file using
+ the above secrets_lock_trust_account_password().
+************************************************************************/
+
+bool secrets_fetch_trust_account_password(const char *domain, uint8 ret_pwd[16],
+ time_t *pass_last_set_time,
+ uint32 *channel)
+{
+ char *plaintext;
+
+ plaintext = secrets_fetch_machine_password(domain, pass_last_set_time,
+ channel);
+ if (plaintext) {
+ DEBUG(4,("Using cleartext machine password\n"));
+ E_md4hash(plaintext, ret_pwd);
+ SAFE_FREE(plaintext);
+ return True;
+ }
+
+ return secrets_fetch_trust_account_password_legacy(domain, ret_pwd,
+ pass_last_set_time,
+ channel);
+}
+
+/**
+ * Pack SID passed by pointer
+ *
+ * @param pack_buf pointer to buffer which is to be filled with packed data
+ * @param bufsize size of packing buffer
+ * @param sid pointer to sid to be packed
+ *
+ * @return length of the packed representation of the whole structure
+ **/
+static size_t tdb_sid_pack(uint8 *pack_buf, int bufsize, DOM_SID* sid)
+{
+ int idx;
+ size_t len = 0;
+ uint8 *p = pack_buf;
+ int remaining_space = pack_buf ? bufsize : 0;
+
+ if (!sid) {
+ return -1;
+ }
+
+ len += tdb_pack(p, remaining_space, "bb", sid->sid_rev_num,
+ sid->num_auths);
+ if (pack_buf) {
+ p = pack_buf + len;
+ remaining_space = bufsize - len;
+ }
+
+ for (idx = 0; idx < 6; idx++) {
+ len += tdb_pack(p, remaining_space, "b",
+ sid->id_auth[idx]);
+ if (pack_buf) {
+ p = pack_buf + len;
+ remaining_space = bufsize - len;
+ }
+ }
+
+ for (idx = 0; idx < MAXSUBAUTHS; idx++) {
+ len += tdb_pack(p, remaining_space, "d",
+ sid->sub_auths[idx]);
+ if (pack_buf) {
+ p = pack_buf + len;
+ remaining_space = bufsize - len;
+ }
+ }
+
+ return len;
+}
+
+/**
+ * Unpack SID into a pointer
+ *
+ * @param pack_buf pointer to buffer with packed representation
+ * @param bufsize size of the buffer
+ * @param sid pointer to sid structure to be filled with unpacked data
+ *
+ * @return size of structure unpacked from buffer
+ **/
+static size_t tdb_sid_unpack(uint8 *pack_buf, int bufsize, DOM_SID* sid)
+{
+ int idx, len = 0;
+
+ if (!sid || !pack_buf) return -1;
+
+ len += tdb_unpack(pack_buf + len, bufsize - len, "bb",
+ &sid->sid_rev_num, &sid->num_auths);
+
+ for (idx = 0; idx < 6; idx++) {
+ len += tdb_unpack(pack_buf + len, bufsize - len, "b",
+ &sid->id_auth[idx]);
+ }
+
+ for (idx = 0; idx < MAXSUBAUTHS; idx++) {
+ len += tdb_unpack(pack_buf + len, bufsize - len, "d",
+ &sid->sub_auths[idx]);
+ }
+
+ return len;
+}
+
+/**
+ * Pack TRUSTED_DOM_PASS passed by pointer
+ *
+ * @param pack_buf pointer to buffer which is to be filled with packed data
+ * @param bufsize size of the buffer
+ * @param pass pointer to trusted domain password to be packed
+ *
+ * @return length of the packed representation of the whole structure
+ **/
+static size_t tdb_trusted_dom_pass_pack(uint8 *pack_buf, int bufsize,
+ TRUSTED_DOM_PASS* pass)
+{
+ int idx, len = 0;
+ uint8 *p = pack_buf;
+ int remaining_space = pack_buf ? bufsize : 0;
+
+ if (!pass) {
+ return -1;
+ }
+
+ /* packing unicode domain name and password */
+ len += tdb_pack(p, remaining_space, "d",
+ pass->uni_name_len);
+ if (pack_buf) {
+ p = pack_buf + len;
+ remaining_space = bufsize - len;
+ }
+
+ for (idx = 0; idx < 32; idx++) {
+ len += tdb_pack(p, remaining_space, "w",
+ pass->uni_name[idx]);
+ if (pack_buf) {
+ p = pack_buf + len;
+ remaining_space = bufsize - len;
+ }
+ }
+
+ len += tdb_pack(p, remaining_space, "dPd", pass->pass_len,
+ pass->pass, pass->mod_time);
+ if (pack_buf) {
+ p = pack_buf + len;
+ remaining_space = bufsize - len;
+ }
+
+ /* packing SID structure */
+ len += tdb_sid_pack(p, remaining_space, &pass->domain_sid);
+ if (pack_buf) {
+ p = pack_buf + len;
+ remaining_space = bufsize - len;
+ }
+
+ return len;
+}
+
+
+/**
+ * Unpack TRUSTED_DOM_PASS passed by pointer
+ *
+ * @param pack_buf pointer to buffer with packed representation
+ * @param bufsize size of the buffer
+ * @param pass pointer to trusted domain password to be filled with unpacked data
+ *
+ * @return size of structure unpacked from buffer
+ **/
+static size_t tdb_trusted_dom_pass_unpack(uint8 *pack_buf, int bufsize,
+ TRUSTED_DOM_PASS* pass)
+{
+ int idx, len = 0;
+ char *passp = NULL;
+
+ if (!pack_buf || !pass) return -1;
+
+ /* unpack unicode domain name and plaintext password */
+ len += tdb_unpack(pack_buf, bufsize - len, "d", &pass->uni_name_len);
+
+ for (idx = 0; idx < 32; idx++)
+ len += tdb_unpack(pack_buf + len, bufsize - len, "w",
+ &pass->uni_name[idx]);
+
+ len += tdb_unpack(pack_buf + len, bufsize - len, "dPd",
+ &pass->pass_len, &passp, &pass->mod_time);
+ if (passp) {
+ fstrcpy(pass->pass, passp);
+ }
+ SAFE_FREE(passp);
+
+ /* unpack domain sid */
+ len += tdb_sid_unpack(pack_buf + len, bufsize - len,
+ &pass->domain_sid);
+
+ return len;
+}
+
+/************************************************************************
+ Routine to get account password to trusted domain
+************************************************************************/
+
+bool secrets_fetch_trusted_domain_password(const char *domain, char** pwd,
+ DOM_SID *sid, time_t *pass_last_set_time)
+{
+ struct trusted_dom_pass pass;
+ size_t size = 0;
+
+ /* unpacking structures */
+ uint8 *pass_buf;
+ int pass_len = 0;
+
+ ZERO_STRUCT(pass);
+
+ /* fetching trusted domain password structure */
+ if (!(pass_buf = (uint8 *)secrets_fetch(trustdom_keystr(domain),
+ &size))) {
+ DEBUG(5, ("secrets_fetch failed!\n"));
+ return False;
+ }
+
+ /* unpack trusted domain password */
+ pass_len = tdb_trusted_dom_pass_unpack(pass_buf, size, &pass);
+ SAFE_FREE(pass_buf);
+
+ if (pass_len != size) {
+ DEBUG(5, ("Invalid secrets size. Unpacked data doesn't match trusted_dom_pass structure.\n"));
+ return False;
+ }
+
+ /* the trust's password */
+ if (pwd) {
+ *pwd = SMB_STRDUP(pass.pass);
+ if (!*pwd) {
+ return False;
+ }
+ }
+
+ /* last change time */
+ if (pass_last_set_time) *pass_last_set_time = pass.mod_time;
+
+ /* domain sid */
+ if (sid != NULL) sid_copy(sid, &pass.domain_sid);
+
+ return True;
+}
+
+/**
+ * Routine to store the password for trusted domain
+ *
+ * @param domain remote domain name
+ * @param pwd plain text password of trust relationship
+ * @param sid remote domain sid
+ *
+ * @return true if succeeded
+ **/
+
+bool secrets_store_trusted_domain_password(const char* domain, const char* pwd,
+ const DOM_SID *sid)
+{
+ smb_ucs2_t *uni_dom_name;
+ bool ret;
+ size_t converted_size;
+
+ /* packing structures */
+ uint8 *pass_buf = NULL;
+ int pass_len = 0;
+
+ struct trusted_dom_pass pass;
+ ZERO_STRUCT(pass);
+
+ if (!push_ucs2_allocate(&uni_dom_name, domain, &converted_size)) {
+ DEBUG(0, ("Could not convert domain name %s to unicode\n",
+ domain));
+ return False;
+ }
+
+ strncpy_w(pass.uni_name, uni_dom_name, sizeof(pass.uni_name) - 1);
+ pass.uni_name_len = strlen_w(uni_dom_name)+1;
+ SAFE_FREE(uni_dom_name);
+
+ /* last change time */
+ pass.mod_time = time(NULL);
+
+ /* password of the trust */
+ pass.pass_len = strlen(pwd);
+ fstrcpy(pass.pass, pwd);
+
+ /* domain sid */
+ sid_copy(&pass.domain_sid, sid);
+
+ /* Calculate the length. */
+ pass_len = tdb_trusted_dom_pass_pack(NULL, 0, &pass);
+ pass_buf = SMB_MALLOC_ARRAY(uint8, pass_len);
+ if (!pass_buf) {
+ return false;
+ }
+ pass_len = tdb_trusted_dom_pass_pack(pass_buf, pass_len, &pass);
+ ret = secrets_store(trustdom_keystr(domain), (void *)pass_buf,
+ pass_len);
+ SAFE_FREE(pass_buf);
+ return ret;
+}
+
+/************************************************************************
+ Routine to delete the plaintext machine account password
+************************************************************************/
+
+bool secrets_delete_machine_password(const char *domain)
+{
+ return secrets_delete(machine_password_keystr(domain));
+}
+
+/************************************************************************
+ Routine to delete the plaintext machine account password, sec channel type and
+ last change time from secrets database
+************************************************************************/
+
+bool secrets_delete_machine_password_ex(const char *domain)
+{
+ if (!secrets_delete(machine_password_keystr(domain))) {
+ return false;
+ }
+ if (!secrets_delete(machine_sec_channel_type_keystr(domain))) {
+ return false;
+ }
+ return secrets_delete(machine_last_change_time_keystr(domain));
+}
+
+/************************************************************************
+ Routine to delete the domain sid
+************************************************************************/
+
+bool secrets_delete_domain_sid(const char *domain)
+{
+ return secrets_delete(domain_sid_keystr(domain));
+}
+
+/************************************************************************
+ Routine to set the plaintext machine account password for a realm
+the password is assumed to be a null terminated ascii string
+************************************************************************/
+
+bool secrets_store_machine_password(const char *pass, const char *domain, uint32 sec_channel)
+{
+ bool ret;
+ uint32 last_change_time;
+ uint32 sec_channel_type;
+
+ ret = secrets_store(machine_password_keystr(domain), pass, strlen(pass)+1);
+ if (!ret)
+ return ret;
+
+ SIVAL(&last_change_time, 0, time(NULL));
+ ret = secrets_store(machine_last_change_time_keystr(domain), &last_change_time, sizeof(last_change_time));
+
+ SIVAL(&sec_channel_type, 0, sec_channel);
+ ret = secrets_store(machine_sec_channel_type_keystr(domain), &sec_channel_type, sizeof(sec_channel_type));
+
+ return ret;
+}
+
+/************************************************************************
+ Routine to fetch the plaintext machine account password for a realm
+ the password is assumed to be a null terminated ascii string.
+************************************************************************/
+
+char *secrets_fetch_machine_password(const char *domain,
+ time_t *pass_last_set_time,
+ uint32 *channel)
+{
+ char *ret;
+ ret = (char *)secrets_fetch(machine_password_keystr(domain), NULL);
+
+ if (pass_last_set_time) {
+ size_t size;
+ uint32 *last_set_time;
+ last_set_time = (unsigned int *)secrets_fetch(machine_last_change_time_keystr(domain), &size);
+ if (last_set_time) {
+ *pass_last_set_time = IVAL(last_set_time,0);
+ SAFE_FREE(last_set_time);
+ } else {
+ *pass_last_set_time = 0;
+ }
+ }
+
+ if (channel) {
+ size_t size;
+ uint32 *channel_type;
+ channel_type = (unsigned int *)secrets_fetch(machine_sec_channel_type_keystr(domain), &size);
+ if (channel_type) {
+ *channel = IVAL(channel_type,0);
+ SAFE_FREE(channel_type);
+ } else {
+ *channel = get_default_sec_channel();
+ }
+ }
+
+ return ret;
+}
+
+/************************************************************************
+ Routine to delete the password for trusted domain
+************************************************************************/
+
+bool trusted_domain_password_delete(const char *domain)
+{
+ return secrets_delete(trustdom_keystr(domain));
+}
+
+bool secrets_store_ldap_pw(const char* dn, char* pw)
+{
+ char *key = NULL;
+ bool ret;
+
+ if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, dn) < 0) {
+ DEBUG(0, ("secrets_store_ldap_pw: asprintf failed!\n"));
+ return False;
+ }
+
+ ret = secrets_store(key, pw, strlen(pw)+1);
+
+ SAFE_FREE(key);
+ return ret;
+}
+
+/*******************************************************************
+ Find the ldap password.
+******************************************************************/
+
+bool fetch_ldap_pw(char **dn, char** pw)
+{
+ char *key = NULL;
+ size_t size = 0;
+
+ *dn = smb_xstrdup(lp_ldap_admin_dn());
+
+ if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, *dn) < 0) {
+ SAFE_FREE(*dn);
+ DEBUG(0, ("fetch_ldap_pw: asprintf failed!\n"));
+ }
+
+ *pw=(char *)secrets_fetch(key, &size);
+ SAFE_FREE(key);
+
+ if (!size) {
+ /* Upgrade 2.2 style entry */
+ char *p;
+ char* old_style_key = SMB_STRDUP(*dn);
+ char *data;
+ fstring old_style_pw;
+
+ if (!old_style_key) {
+ DEBUG(0, ("fetch_ldap_pw: strdup failed!\n"));
+ return False;
+ }
+
+ for (p=old_style_key; *p; p++)
+ if (*p == ',') *p = '/';
+
+ data=(char *)secrets_fetch(old_style_key, &size);
+ if ((data == NULL) || (size < sizeof(old_style_pw))) {
+ DEBUG(0,("fetch_ldap_pw: neither ldap secret retrieved!\n"));
+ SAFE_FREE(old_style_key);
+ SAFE_FREE(*dn);
+ SAFE_FREE(data);
+ return False;
+ }
+
+ size = MIN(size, sizeof(fstring)-1);
+ strncpy(old_style_pw, data, size);
+ old_style_pw[size] = 0;
+
+ SAFE_FREE(data);
+
+ if (!secrets_store_ldap_pw(*dn, old_style_pw)) {
+ DEBUG(0,("fetch_ldap_pw: ldap secret could not be upgraded!\n"));
+ SAFE_FREE(old_style_key);
+ SAFE_FREE(*dn);
+ return False;
+ }
+ if (!secrets_delete(old_style_key)) {
+ DEBUG(0,("fetch_ldap_pw: old ldap secret could not be deleted!\n"));
+ }
+
+ SAFE_FREE(old_style_key);
+
+ *pw = smb_xstrdup(old_style_pw);
+ }
+
+ return True;
+}
+
+/**
+ * Get trusted domains info from secrets.tdb.
+ **/
+
+struct list_trusted_domains_state {
+ uint32 num_domains;
+ struct trustdom_info **domains;
+};
+
+static int list_trusted_domain(struct db_record *rec, void *private_data)
+{
+ const size_t prefix_len = strlen(SECRETS_DOMTRUST_ACCT_PASS);
+ size_t converted_size, packed_size = 0;
+ struct trusted_dom_pass pass;
+ struct trustdom_info *dom_info;
+
+ struct list_trusted_domains_state *state =
+ (struct list_trusted_domains_state *)private_data;
+
+ if ((rec->key.dsize < prefix_len)
+ || (strncmp((char *)rec->key.dptr, SECRETS_DOMTRUST_ACCT_PASS,
+ prefix_len) != 0)) {
+ return 0;
+ }
+
+ packed_size = tdb_trusted_dom_pass_unpack(
+ rec->value.dptr, rec->value.dsize, &pass);
+
+ if (rec->value.dsize != packed_size) {
+ DEBUG(2, ("Secrets record is invalid!\n"));
+ return 0;
+ }
+
+ if (pass.domain_sid.num_auths != 4) {
+ DEBUG(0, ("SID %s is not a domain sid, has %d "
+ "auths instead of 4\n",
+ sid_string_dbg(&pass.domain_sid),
+ pass.domain_sid.num_auths));
+ return 0;
+ }
+
+ if (!(dom_info = TALLOC_P(state->domains, struct trustdom_info))) {
+ DEBUG(0, ("talloc failed\n"));
+ return 0;
+ }
+
+ if (!pull_ucs2_talloc(dom_info, &dom_info->name, pass.uni_name,
+ &converted_size)) {
+ DEBUG(2, ("pull_ucs2_talloc failed\n"));
+ TALLOC_FREE(dom_info);
+ return 0;
+ }
+
+ sid_copy(&dom_info->sid, &pass.domain_sid);
+
+ ADD_TO_ARRAY(state->domains, struct trustdom_info *, dom_info,
+ &state->domains, &state->num_domains);
+
+ if (state->domains == NULL) {
+ state->num_domains = 0;
+ return -1;
+ }
+ return 0;
+}
+
+NTSTATUS secrets_trusted_domains(TALLOC_CTX *mem_ctx, uint32 *num_domains,
+ struct trustdom_info ***domains)
+{
+ struct list_trusted_domains_state state;
+
+ secrets_init();
+
+ if (db_ctx == NULL) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ state.num_domains = 0;
+
+ /*
+ * Make sure that a talloc context for the trustdom_info structs
+ * exists
+ */
+
+ if (!(state.domains = TALLOC_ARRAY(
+ mem_ctx, struct trustdom_info *, 1))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ db_ctx->traverse_read(db_ctx, list_trusted_domain, (void *)&state);
+
+ *num_domains = state.num_domains;
+ *domains = state.domains;
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************************
+ Store a complete AFS keyfile into secrets.tdb.
+*******************************************************************************/
+
+bool secrets_store_afs_keyfile(const char *cell, const struct afs_keyfile *keyfile)
+{
+ fstring key;
+
+ if ((cell == NULL) || (keyfile == NULL))
+ return False;
+
+ if (ntohl(keyfile->nkeys) > SECRETS_AFS_MAXKEYS)
+ return False;
+
+ slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_AFS_KEYFILE, cell);
+ return secrets_store(key, keyfile, sizeof(struct afs_keyfile));
+}
+
+/*******************************************************************************
+ Fetch the current (highest) AFS key from secrets.tdb
+*******************************************************************************/
+bool secrets_fetch_afs_key(const char *cell, struct afs_key *result)
+{
+ fstring key;
+ struct afs_keyfile *keyfile;
+ size_t size = 0;
+ uint32 i;
+
+ slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_AFS_KEYFILE, cell);
+
+ keyfile = (struct afs_keyfile *)secrets_fetch(key, &size);
+
+ if (keyfile == NULL)
+ return False;
+
+ if (size != sizeof(struct afs_keyfile)) {
+ SAFE_FREE(keyfile);
+ return False;
+ }
+
+ i = ntohl(keyfile->nkeys);
+
+ if (i > SECRETS_AFS_MAXKEYS) {
+ SAFE_FREE(keyfile);
+ return False;
+ }
+
+ *result = keyfile->entry[i-1];
+
+ result->kvno = ntohl(result->kvno);
+
+ SAFE_FREE(keyfile);
+
+ return True;
+}
+
+/******************************************************************************
+ When kerberos is not available, choose between anonymous or
+ authenticated connections.
+
+ We need to use an authenticated connection if DCs have the
+ RestrictAnonymous registry entry set > 0, or the "Additional
+ restrictions for anonymous connections" set in the win2k Local
+ Security Policy.
+
+ Caller to free() result in domain, username, password
+*******************************************************************************/
+void secrets_fetch_ipc_userpass(char **username, char **domain, char **password)
+{
+ *username = (char *)secrets_fetch(SECRETS_AUTH_USER, NULL);
+ *domain = (char *)secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
+ *password = (char *)secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
+
+ if (*username && **username) {
+
+ if (!*domain || !**domain)
+ *domain = smb_xstrdup(lp_workgroup());
+
+ if (!*password || !**password)
+ *password = smb_xstrdup("");
+
+ DEBUG(3, ("IPC$ connections done by user %s\\%s\n",
+ *domain, *username));
+
+ } else {
+ DEBUG(3, ("IPC$ connections done anonymously\n"));
+ *username = smb_xstrdup("");
+ *domain = smb_xstrdup("");
+ *password = smb_xstrdup("");
+ }
+}
+
+/******************************************************************************
+ Open or create the schannel session store tdb.
+*******************************************************************************/
+
+static TDB_CONTEXT *open_schannel_session_store(TALLOC_CTX *mem_ctx)
+{
+ TDB_DATA vers;
+ uint32 ver;
+ TDB_CONTEXT *tdb_sc = NULL;
+ char *fname = talloc_asprintf(mem_ctx, "%s/schannel_store.tdb", lp_private_dir());
+
+ if (!fname) {
+ return NULL;
+ }
+
+ tdb_sc = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+
+ if (!tdb_sc) {
+ DEBUG(0,("open_schannel_session_store: Failed to open %s\n", fname));
+ TALLOC_FREE(fname);
+ return NULL;
+ }
+
+ vers = tdb_fetch_bystring(tdb_sc, "SCHANNEL_STORE_VERSION");
+ if (vers.dptr == NULL) {
+ /* First opener, no version. */
+ SIVAL(&ver,0,1);
+ vers.dptr = (uint8 *)&ver;
+ vers.dsize = 4;
+ tdb_store_bystring(tdb_sc, "SCHANNEL_STORE_VERSION", vers, TDB_REPLACE);
+ vers.dptr = NULL;
+ } else if (vers.dsize == 4) {
+ ver = IVAL(vers.dptr,0);
+ if (ver != 1) {
+ tdb_close(tdb_sc);
+ tdb_sc = NULL;
+ DEBUG(0,("open_schannel_session_store: wrong version number %d in %s\n",
+ (int)ver, fname ));
+ }
+ } else {
+ tdb_close(tdb_sc);
+ tdb_sc = NULL;
+ DEBUG(0,("open_schannel_session_store: wrong version number size %d in %s\n",
+ (int)vers.dsize, fname ));
+ }
+
+ SAFE_FREE(vers.dptr);
+ TALLOC_FREE(fname);
+
+ return tdb_sc;
+}
+
+/******************************************************************************
+ Store the schannel state after an AUTH2 call.
+ Note we must be root here.
+*******************************************************************************/
+
+bool secrets_store_schannel_session_info(TALLOC_CTX *mem_ctx,
+ const char *remote_machine,
+ const struct dcinfo *pdc)
+{
+ TDB_CONTEXT *tdb_sc = NULL;
+ TDB_DATA value;
+ bool ret;
+ char *keystr = talloc_asprintf_strupper_m(mem_ctx, "%s/%s",
+ SECRETS_SCHANNEL_STATE,
+ remote_machine);
+ if (!keystr) {
+ return False;
+ }
+
+ /* Work out how large the record is. */
+ value.dsize = tdb_pack(NULL, 0, "dBBBBBfff",
+ pdc->sequence,
+ 8, pdc->seed_chal.data,
+ 8, pdc->clnt_chal.data,
+ 8, pdc->srv_chal.data,
+ 16, pdc->sess_key,
+ 16, pdc->mach_pw,
+ pdc->mach_acct,
+ pdc->remote_machine,
+ pdc->domain);
+
+ value.dptr = TALLOC_ARRAY(mem_ctx, uint8, value.dsize);
+ if (!value.dptr) {
+ TALLOC_FREE(keystr);
+ return False;
+ }
+
+ value.dsize = tdb_pack(value.dptr, value.dsize, "dBBBBBfff",
+ pdc->sequence,
+ 8, pdc->seed_chal.data,
+ 8, pdc->clnt_chal.data,
+ 8, pdc->srv_chal.data,
+ 16, pdc->sess_key,
+ 16, pdc->mach_pw,
+ pdc->mach_acct,
+ pdc->remote_machine,
+ pdc->domain);
+
+ tdb_sc = open_schannel_session_store(mem_ctx);
+ if (!tdb_sc) {
+ TALLOC_FREE(keystr);
+ TALLOC_FREE(value.dptr);
+ return False;
+ }
+
+ ret = (tdb_store_bystring(tdb_sc, keystr, value, TDB_REPLACE) == 0 ? True : False);
+
+ DEBUG(3,("secrets_store_schannel_session_info: stored schannel info with key %s\n",
+ keystr ));
+
+ tdb_close(tdb_sc);
+ TALLOC_FREE(keystr);
+ TALLOC_FREE(value.dptr);
+ return ret;
+}
+
+/******************************************************************************
+ Restore the schannel state on a client reconnect.
+ Note we must be root here.
+*******************************************************************************/
+
+bool secrets_restore_schannel_session_info(TALLOC_CTX *mem_ctx,
+ const char *remote_machine,
+ struct dcinfo **ppdc)
+{
+ TDB_CONTEXT *tdb_sc = NULL;
+ TDB_DATA value;
+ unsigned char *pseed_chal = NULL;
+ unsigned char *pclnt_chal = NULL;
+ unsigned char *psrv_chal = NULL;
+ unsigned char *psess_key = NULL;
+ unsigned char *pmach_pw = NULL;
+ uint32 l1, l2, l3, l4, l5;
+ int ret;
+ struct dcinfo *pdc = NULL;
+ char *keystr = talloc_asprintf_strupper_m(mem_ctx, "%s/%s",
+ SECRETS_SCHANNEL_STATE,
+ remote_machine);
+
+ *ppdc = NULL;
+
+ if (!keystr) {
+ return False;
+ }
+
+ tdb_sc = open_schannel_session_store(mem_ctx);
+ if (!tdb_sc) {
+ TALLOC_FREE(keystr);
+ return False;
+ }
+
+ value = tdb_fetch_bystring(tdb_sc, keystr);
+ if (!value.dptr) {
+ DEBUG(0,("secrets_restore_schannel_session_info: Failed to find entry with key %s\n",
+ keystr ));
+ tdb_close(tdb_sc);
+ return False;
+ }
+
+ pdc = TALLOC_ZERO_P(mem_ctx, struct dcinfo);
+
+ /* Retrieve the record. */
+ ret = tdb_unpack(value.dptr, value.dsize, "dBBBBBfff",
+ &pdc->sequence,
+ &l1, &pseed_chal,
+ &l2, &pclnt_chal,
+ &l3, &psrv_chal,
+ &l4, &psess_key,
+ &l5, &pmach_pw,
+ &pdc->mach_acct,
+ &pdc->remote_machine,
+ &pdc->domain);
+
+ if (ret == -1 || l1 != 8 || l2 != 8 || l3 != 8 || l4 != 16 || l5 != 16) {
+ /* Bad record - delete it. */
+ tdb_delete_bystring(tdb_sc, keystr);
+ tdb_close(tdb_sc);
+ TALLOC_FREE(keystr);
+ TALLOC_FREE(pdc);
+ SAFE_FREE(pseed_chal);
+ SAFE_FREE(pclnt_chal);
+ SAFE_FREE(psrv_chal);
+ SAFE_FREE(psess_key);
+ SAFE_FREE(pmach_pw);
+ SAFE_FREE(value.dptr);
+ return False;
+ }
+
+ tdb_close(tdb_sc);
+
+ memcpy(pdc->seed_chal.data, pseed_chal, 8);
+ memcpy(pdc->clnt_chal.data, pclnt_chal, 8);
+ memcpy(pdc->srv_chal.data, psrv_chal, 8);
+ memcpy(pdc->sess_key, psess_key, 16);
+ memcpy(pdc->mach_pw, pmach_pw, 16);
+
+ /* We know these are true so didn't bother to store them. */
+ pdc->challenge_sent = True;
+ pdc->authenticated = True;
+
+ DEBUG(3,("secrets_restore_schannel_session_info: restored schannel info key %s\n",
+ keystr ));
+
+ SAFE_FREE(pseed_chal);
+ SAFE_FREE(pclnt_chal);
+ SAFE_FREE(psrv_chal);
+ SAFE_FREE(psess_key);
+ SAFE_FREE(pmach_pw);
+
+ TALLOC_FREE(keystr);
+ SAFE_FREE(value.dptr);
+
+ *ppdc = pdc;
+
+ return True;
+}
+
+bool secrets_store_generic(const char *owner, const char *key, const char *secret)
+{
+ char *tdbkey = NULL;
+ bool ret;
+
+ if (asprintf(&tdbkey, "SECRETS/GENERIC/%s/%s", owner, key) < 0) {
+ DEBUG(0, ("asprintf failed!\n"));
+ return False;
+ }
+
+ ret = secrets_store(tdbkey, secret, strlen(secret)+1);
+
+ SAFE_FREE(tdbkey);
+ return ret;
+}
+
+/*******************************************************************
+ Find the ldap password.
+******************************************************************/
+
+char *secrets_fetch_generic(const char *owner, const char *key)
+{
+ char *secret = NULL;
+ char *tdbkey = NULL;
+
+ if (( ! owner) || ( ! key)) {
+ DEBUG(1, ("Invalid Paramters"));
+ return NULL;
+ }
+
+ if (asprintf(&tdbkey, "SECRETS/GENERIC/%s/%s", owner, key) < 0) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NULL;
+ }
+
+ secret = (char *)secrets_fetch(tdbkey, NULL);
+ SAFE_FREE(tdbkey);
+
+ return secret;
+}
+
diff --git a/source3/passdb/util_builtin.c b/source3/passdb/util_builtin.c
new file mode 100644
index 0000000000..dbddddd25d
--- /dev/null
+++ b/source3/passdb/util_builtin.c
@@ -0,0 +1,109 @@
+/*
+ Unix SMB/CIFS implementation.
+ Translate BUILTIN names to SIDs and vice versa
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+struct rid_name_map {
+ uint32 rid;
+ const char *name;
+};
+
+static const struct rid_name_map builtin_aliases[] = {
+ { 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, "Server Operators" },
+ { BUILTIN_ALIAS_RID_PRINT_OPS, "Print Operators" },
+ { BUILTIN_ALIAS_RID_BACKUP_OPS, "Backup Operators" },
+ { BUILTIN_ALIAS_RID_REPLICATOR, "Replicator" },
+ { BUILTIN_ALIAS_RID_RAS_SERVERS, "RAS Servers" },
+ { BUILTIN_ALIAS_RID_PRE_2K_ACCESS, "Pre-Windows 2000 Compatible Access" },
+ { 0, NULL}};
+
+/*******************************************************************
+ Look up a rid in the BUILTIN domain
+ ********************************************************************/
+bool lookup_builtin_rid(TALLOC_CTX *mem_ctx, uint32 rid, const char **name)
+{
+ const struct rid_name_map *aliases = builtin_aliases;
+
+ while (aliases->name != NULL) {
+ if (rid == aliases->rid) {
+ *name = talloc_strdup(mem_ctx, aliases->name);
+ return True;
+ }
+ aliases++;
+ }
+
+ return False;
+}
+
+/*******************************************************************
+ Look up a name in the BUILTIN domain
+ ********************************************************************/
+bool lookup_builtin_name(const char *name, uint32 *rid)
+{
+ const struct rid_name_map *aliases = builtin_aliases;
+
+ while (aliases->name != NULL) {
+ if (strequal(name, aliases->name)) {
+ *rid = aliases->rid;
+ return True;
+ }
+ aliases++;
+ }
+
+ return False;
+}
+
+/*****************************************************************
+ Return the name of the BUILTIN domain
+*****************************************************************/
+
+const char *builtin_domain_name(void)
+{
+ return "BUILTIN";
+}
+
+/*****************************************************************
+ Check if the SID is the builtin SID (S-1-5-32).
+*****************************************************************/
+
+bool sid_check_is_builtin(const DOM_SID *sid)
+{
+ return sid_equal(sid, &global_sid_Builtin);
+}
+
+/*****************************************************************
+ Check if the SID is one of the builtin SIDs (S-1-5-32-a).
+*****************************************************************/
+
+bool sid_check_is_in_builtin(const DOM_SID *sid)
+{
+ DOM_SID dom_sid;
+ uint32 rid;
+
+ sid_copy(&dom_sid, sid);
+ sid_split_rid(&dom_sid, &rid);
+
+ return sid_check_is_builtin(&dom_sid);
+}
+
diff --git a/source3/passdb/util_unixsids.c b/source3/passdb/util_unixsids.c
new file mode 100644
index 0000000000..1b674d02a2
--- /dev/null
+++ b/source3/passdb/util_unixsids.c
@@ -0,0 +1,105 @@
+/*
+ Unix SMB/CIFS implementation.
+ Translate unix-defined names to SIDs and vice versa
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+bool sid_check_is_unix_users(const DOM_SID *sid)
+{
+ return sid_equal(sid, &global_sid_Unix_Users);
+}
+
+bool sid_check_is_in_unix_users(const DOM_SID *sid)
+{
+ DOM_SID dom_sid;
+ uint32 rid;
+
+ sid_copy(&dom_sid, sid);
+ sid_split_rid(&dom_sid, &rid);
+
+ return sid_check_is_unix_users(&dom_sid);
+}
+
+bool uid_to_unix_users_sid(uid_t uid, DOM_SID *sid)
+{
+ sid_copy(sid, &global_sid_Unix_Users);
+ return sid_append_rid(sid, (uint32_t)uid);
+}
+
+bool gid_to_unix_groups_sid(gid_t gid, DOM_SID *sid)
+{
+ sid_copy(sid, &global_sid_Unix_Groups);
+ return sid_append_rid(sid, (uint32_t)gid);
+}
+
+const char *unix_users_domain_name(void)
+{
+ return "Unix User";
+}
+
+bool lookup_unix_user_name(const char *name, DOM_SID *sid)
+{
+ struct passwd *pwd;
+
+ pwd = getpwnam_alloc(NULL, name);
+ if (pwd == NULL) {
+ return False;
+ }
+
+ sid_copy(sid, &global_sid_Unix_Users);
+ sid_append_rid(sid, (uint32_t)pwd->pw_uid); /* For 64-bit uid's we have enough
+ * space ... */
+ TALLOC_FREE(pwd);
+ return True;
+}
+
+bool sid_check_is_unix_groups(const DOM_SID *sid)
+{
+ return sid_equal(sid, &global_sid_Unix_Groups);
+}
+
+bool sid_check_is_in_unix_groups(const DOM_SID *sid)
+{
+ DOM_SID dom_sid;
+ uint32 rid;
+
+ sid_copy(&dom_sid, sid);
+ sid_split_rid(&dom_sid, &rid);
+
+ return sid_check_is_unix_groups(&dom_sid);
+}
+
+const char *unix_groups_domain_name(void)
+{
+ return "Unix Group";
+}
+
+bool lookup_unix_group_name(const char *name, DOM_SID *sid)
+{
+ struct group *grp;
+
+ grp = sys_getgrnam(name);
+ if (grp == NULL) {
+ return False;
+ }
+
+ sid_copy(sid, &global_sid_Unix_Groups);
+ sid_append_rid(sid, (uint32_t)grp->gr_gid); /* For 64-bit uid's we have enough
+ * space ... */
+ return True;
+}
diff --git a/source3/passdb/util_wellknown.c b/source3/passdb/util_wellknown.c
new file mode 100644
index 0000000000..3a30ab0a65
--- /dev/null
+++ b/source3/passdb/util_wellknown.c
@@ -0,0 +1,172 @@
+/*
+ Unix SMB/CIFS implementation.
+ Lookup routines for well-known SIDs
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Luke Kenneth Caseson Leighton 1998-1999
+ Copyright (C) Jeremy Allison 1999
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+struct rid_name_map {
+ uint32 rid;
+ const char *name;
+};
+
+struct sid_name_map_info
+{
+ const DOM_SID *sid;
+ const char *name;
+ const struct rid_name_map *known_users;
+};
+
+static const struct rid_name_map everyone_users[] = {
+ { 0, "Everyone" },
+ { 0, NULL}};
+
+static const struct rid_name_map creator_owner_users[] = {
+ { 0, "Creator Owner" },
+ { 1, "Creator Group" },
+ { 0, NULL}};
+
+static const struct rid_name_map nt_authority_users[] = {
+ { 1, "Dialup" },
+ { 2, "Network"},
+ { 3, "Batch"},
+ { 4, "Interactive"},
+ { 6, "Service"},
+ { 7, "AnonymousLogon"},
+ { 8, "Proxy"},
+ { 9, "ServerLogon"},
+ { 10, "Self"},
+ { 11, "Authenticated Users"},
+ { 12, "Restricted"},
+ { 13, "Terminal Server User"},
+ { 14, "Remote Interactive Logon"},
+ { 15, "This Organization"},
+ { 18, "SYSTEM"},
+ { 19, "Local Service"},
+ { 20, "Network Service"},
+ { 0, NULL}};
+
+static struct sid_name_map_info special_domains[] = {
+ { &global_sid_World_Domain, "", everyone_users },
+ { &global_sid_Creator_Owner_Domain, "", creator_owner_users },
+ { &global_sid_NT_Authority, "NT Authority", nt_authority_users },
+ { NULL, NULL, NULL }};
+
+bool sid_check_is_wellknown_domain(const DOM_SID *sid, const char **name)
+{
+ int i;
+
+ for (i=0; special_domains[i].sid != NULL; i++) {
+ if (sid_equal(sid, special_domains[i].sid)) {
+ if (name != NULL) {
+ *name = special_domains[i].name;
+ }
+ return True;
+ }
+ }
+ return False;
+}
+
+bool sid_check_is_in_wellknown_domain(const DOM_SID *sid)
+{
+ DOM_SID dom_sid;
+ uint32 rid;
+
+ sid_copy(&dom_sid, sid);
+ sid_split_rid(&dom_sid, &rid);
+
+ return sid_check_is_wellknown_domain(&dom_sid, NULL);
+}
+
+/**************************************************************************
+ Looks up a known username from one of the known domains.
+***************************************************************************/
+
+bool lookup_wellknown_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ const char **domain, const char **name)
+{
+ int i;
+ DOM_SID dom_sid;
+ uint32 rid;
+ const struct rid_name_map *users = NULL;
+
+ sid_copy(&dom_sid, sid);
+ if (!sid_split_rid(&dom_sid, &rid)) {
+ DEBUG(2, ("Could not split rid from SID\n"));
+ return False;
+ }
+
+ for (i=0; special_domains[i].sid != NULL; i++) {
+ if (sid_equal(&dom_sid, special_domains[i].sid)) {
+ *domain = talloc_strdup(mem_ctx,
+ special_domains[i].name);
+ users = special_domains[i].known_users;
+ break;
+ }
+ }
+
+ if (users == NULL) {
+ DEBUG(10, ("SID %s is no special sid\n", sid_string_dbg(sid)));
+ return False;
+ }
+
+ for (i=0; users[i].name != NULL; i++) {
+ if (rid == users[i].rid) {
+ *name = talloc_strdup(mem_ctx, users[i].name);
+ return True;
+ }
+ }
+
+ DEBUG(10, ("RID of special SID %s not found\n", sid_string_dbg(sid)));
+
+ return False;
+}
+
+/**************************************************************************
+ Try and map a name to one of the well known SIDs.
+***************************************************************************/
+
+bool lookup_wellknown_name(TALLOC_CTX *mem_ctx, const char *name,
+ DOM_SID *sid, const char **domain)
+{
+ int i, j;
+
+ DEBUG(10,("map_name_to_wellknown_sid: looking up %s\n", name));
+
+ for (i=0; special_domains[i].sid != NULL; i++) {
+ const struct rid_name_map *users =
+ special_domains[i].known_users;
+
+ if (users == NULL)
+ continue;
+
+ for (j=0; users[j].name != NULL; j++) {
+ if ( strequal(users[j].name, name) ) {
+ sid_copy(sid, special_domains[i].sid);
+ sid_append_rid(sid, users[j].rid);
+ *domain = talloc_strdup(
+ mem_ctx, special_domains[i].name);
+ return True;
+ }
+ }
+ }
+
+ return False;
+}
diff --git a/source3/pkgconfig/netapi.pc.in b/source3/pkgconfig/netapi.pc.in
new file mode 100644
index 0000000000..b1f60b240e
--- /dev/null
+++ b/source3/pkgconfig/netapi.pc.in
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Samba libnetapi
+Description: A library to control CIFS servers
+Version: 0
+URL: http://www.samba.org/
+#Libs: -L@libdir@ -lnetapi
+Libs: -lnetapi
+Libs.private: -lnetapi @KRB5_LIBS@ @LDAP_LIBS@ @LIBS@
+Cflags: -I@includedir@
+
diff --git a/source3/pkgconfig/smbclient.pc.in b/source3/pkgconfig/smbclient.pc.in
new file mode 100644
index 0000000000..969abbe1ff
--- /dev/null
+++ b/source3/pkgconfig/smbclient.pc.in
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Samba libsmbclient
+Description: A library to access CIFS servers
+Version: 0
+URL: http://www.samba.org/
+#Libs: -L@libdir@ -lsmbclient
+Libs: -lsmbclient
+Libs.private: -lsmbclient @KRB5_LIBS@ @LDAP_LIBS@ @LIBS@
+Cflags: -I@includedir@
+
diff --git a/source3/pkgconfig/smbsharemodes.pc.in b/source3/pkgconfig/smbsharemodes.pc.in
new file mode 100644
index 0000000000..dcb0d2eeda
--- /dev/null
+++ b/source3/pkgconfig/smbsharemodes.pc.in
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Samba libsmbsharemodes
+Description: A library
+Version: 0
+URL: http://www.samba.org/
+#Libs: -L@libdir@ -lsmbsharemodes
+Libs: -lsmbsharemodes
+Libs.private: -lsmbsharemodes @KRB5_LIBS@ @LDAP_LIBS@ @LIBS@
+Cflags: -I@includedir@
+
diff --git a/source3/pkgconfig/wbclient.pc.in b/source3/pkgconfig/wbclient.pc.in
new file mode 100644
index 0000000000..158fa923d6
--- /dev/null
+++ b/source3/pkgconfig/wbclient.pc.in
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Samba libwbclient
+Description: A library to access winbindd
+Version: 0
+URL: http://www.samba.org/
+#Libs: -L@libdir@ -lwbclient
+Libs: -lwbclient
+Libs.private: -lwbclient
+Cflags: -I@includedir@
diff --git a/source3/po/de.msg b/source3/po/de.msg
new file mode 100644
index 0000000000..08116834b8
--- /dev/null
+++ b/source3/po/de.msg
@@ -0,0 +1,592 @@
+# German messages for international release of SWAT.
+# Copyright (C) 2001 Andreas Moroder
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: i18n_swat\n"
+"POT-Creation-Date: 2003-10-06 05:30+0900\n"
+"PO-Revision-Date: 2000-02-08 14:45+0100\n"
+"Last-Translator: Andreas Moroder\n"
+"Language-Team: (Samba Team) <samba-technical@samba.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../web/swat.c:117
+#, c-format
+msgid "ERROR: Can't open %s"
+msgstr "ERROR: Kann %s nicht öffnen"
+
+#: ../web/swat.c:200
+msgid "Help"
+msgstr "Hilfe"
+
+#: ../web/swat.c:206 ../web/swat.c:220 ../web/swat.c:235 ../web/swat.c:243 ../web/swat.c:252 ../web/swat.c:261 ../web/swat.c:267 ../web/swat.c:273 ../web/swat.c:286
+msgid "Set Default"
+msgstr "Standardwert"
+
+#: ../web/swat.c:408
+#, c-format
+msgid "failed to open %s for writing"
+msgstr "konnte %s nicht schreiben"
+
+#: ../web/swat.c:431
+#, c-format
+msgid "Can't reload %s"
+msgstr ""
+
+#: ../web/swat.c:501
+#, c-format
+msgid "Logged in as <b>%s</b>"
+msgstr "Verbunden als <b>%s</b>"
+
+#: ../web/swat.c:505
+msgid "Home"
+msgstr "Home"
+
+#: ../web/swat.c:507
+msgid "Globals"
+msgstr "Globals"
+
+#: ../web/swat.c:508
+msgid "Shares"
+msgstr "Freigaben"
+
+#: ../web/swat.c:509
+msgid "Printers"
+msgstr "Drucker"
+
+#: ../web/swat.c:510
+msgid "Wizard"
+msgstr "Assistent"
+
+#: ../web/swat.c:513
+msgid "Status"
+msgstr "Status"
+
+#: ../web/swat.c:514
+msgid "View Config"
+msgstr "Zeige Konfiguration"
+
+#: ../web/swat.c:516
+msgid "Password Management"
+msgstr "Passwortverwaltung"
+
+#: ../web/swat.c:526
+msgid "Current View Is"
+msgstr "Aktuelle Konfiguration"
+
+#: ../web/swat.c:527 ../web/swat.c:530
+msgid "Basic"
+msgstr "Einfache Ansicht"
+
+#: ../web/swat.c:528 ../web/swat.c:531
+msgid "Advanced"
+msgstr "Erweiterte Ansicht"
+
+#: ../web/swat.c:529
+msgid "Change View To"
+msgstr "Ansicht anpassen"
+
+#: ../web/swat.c:554
+msgid "Current Config"
+msgstr "Aktuelle Konfiguration"
+
+#: ../web/swat.c:558
+msgid "Normal View"
+msgstr "Normale Ansicht"
+
+#: ../web/swat.c:560
+msgid "Full View"
+msgstr "Komplette Ansicht"
+
+#. Here we first set and commit all the parameters that were selected
+#. in the previous screen.
+#: ../web/swat.c:579
+msgid "Wizard Parameter Edit Page"
+msgstr ""
+
+#: ../web/swat.c:608
+msgid "Note: smb.conf file has been read and rewritten"
+msgstr "Hinweis: smb.conf wurde gelesen und überschrieben"
+
+#. Here we go ...
+#: ../web/swat.c:716
+msgid "Samba Configuration Wizard"
+msgstr "Samba Konfigurations-Assistent"
+
+#: ../web/swat.c:720
+msgid "The \"Rewrite smb.conf file\" button will clear the smb.conf file of all default values and of comments."
+msgstr "Der Button \"Passe smb.conf an\" wird alle Kommentare und Standardwerte aus der smb.conf löschen."
+
+#: ../web/swat.c:721
+msgid "The same will happen if you press the commit button."
+msgstr "Das gleiche passiert bei \"übernehmen\"."
+
+#: ../web/swat.c:724
+msgid "Rewrite smb.conf file"
+msgstr "Schreibe smb.conf neu"
+
+#: ../web/swat.c:725
+msgid "Commit"
+msgstr "übernehmen"
+
+#: ../web/swat.c:726
+msgid "Edit Parameter Values"
+msgstr "Bearbeite Parameter"
+
+#: ../web/swat.c:732
+msgid "Server Type"
+msgstr "Server-Typ"
+
+#: ../web/swat.c:733
+msgid "Stand Alone"
+msgstr "Einzelserver"
+
+#: ../web/swat.c:734
+msgid "Domain Member"
+msgstr "Domänen-Mitglied"
+
+#: ../web/swat.c:735
+msgid "Domain Controller"
+msgstr "Domänen-Controller"
+
+#: ../web/swat.c:738
+msgid "Unusual Type in smb.conf - Please Select New Mode"
+msgstr ""
+
+#: ../web/swat.c:740
+msgid "Configure WINS As"
+msgstr "Konfiguriere WINS"
+
+#: ../web/swat.c:741
+msgid "Not Used"
+msgstr "nicht benutzt"
+
+#: ../web/swat.c:742
+msgid "Server for client use"
+msgstr "WINS-Server"
+
+#: ../web/swat.c:743
+msgid "Client of another WINS server"
+msgstr "WINS-Client an anderem Server"
+
+#: ../web/swat.c:745
+msgid "Remote WINS Server"
+msgstr "Zuständiger WINS-Server:"
+
+#: ../web/swat.c:756
+msgid "Error: WINS Server Mode and WINS Support both set in smb.conf"
+msgstr "Fehler: WINS-Server und WINS-Client zugleich in smb.conf gesetzt"
+
+#: ../web/swat.c:757
+msgid "Please Select desired WINS mode above."
+msgstr "Bitte wählen Sie den WINS-Modus."
+
+#: ../web/swat.c:759
+msgid "Expose Home Directories"
+msgstr "Home-Verzeichnisse freigeben"
+
+#: ../web/swat.c:774
+msgid "The above configuration options will set multiple parameters and will generally assist with rapid Samba deployment."
+msgstr "Diese Konfigurationsoptionen bearbeiten mehrere Parameter und dienen als Hilfe zur schnellen Samba-Einrichtung."
+
+#: ../web/swat.c:787
+msgid "Global Parameters"
+msgstr "Globale Parameter"
+
+#: ../web/swat.c:815 ../web/swat.c:916 ../web/swat.c:1265
+msgid "Commit Changes"
+msgstr "Änderungen speichern"
+
+#: ../web/swat.c:819 ../web/swat.c:919 ../web/swat.c:1267
+msgid "Reset Values"
+msgstr "Werte zurücksetzen"
+
+#: ../web/swat.c:844
+msgid "Share Parameters"
+msgstr "Parameter der Freigabe"
+
+#: ../web/swat.c:887
+msgid "Choose Share"
+msgstr "Wähle Freigabe"
+
+#: ../web/swat.c:901
+msgid "Delete Share"
+msgstr "Lösche Freigabe"
+
+#: ../web/swat.c:908
+msgid "Create Share"
+msgstr "Erstelle Freigabe"
+
+#: ../web/swat.c:944
+msgid "password change in demo mode rejected"
+msgstr "Änderung des Passworts im Demo modus nicht aktiv"
+
+#: ../web/swat.c:957
+msgid "Can't setup password database vectors."
+msgstr ""
+
+#: ../web/swat.c:983
+msgid " Must specify \"User Name\" "
+msgstr " \"Benutzername\" muss angegeben werden "
+
+#: ../web/swat.c:999
+msgid " Must specify \"Old Password\" "
+msgstr " \"Altes Passwort\" muss angegeben werden "
+
+#: ../web/swat.c:1005
+msgid " Must specify \"Remote Machine\" "
+msgstr " \"Remote-Server\" muss angegeben werden "
+
+#: ../web/swat.c:1012
+msgid " Must specify \"New, and Re-typed Passwords\" "
+msgstr " \"Neues/wiederholtes Passwort\" müssen angegeben werden "
+
+#: ../web/swat.c:1018
+msgid " Re-typed password didn't match new password "
+msgstr " Das wiederholte Passwort stimmt nicht mit dem neuen Passwort überein"
+
+#: ../web/swat.c:1048
+#, c-format
+msgid " The passwd for '%s' has been changed."
+msgstr " Das Passwort für '%s' wurde geändert."
+
+#: ../web/swat.c:1051
+#, c-format
+msgid " The passwd for '%s' has NOT been changed."
+msgstr " Das Passwort für '%s' wurde NICHT geändert."
+
+#: ../web/swat.c:1076
+msgid "Server Password Management"
+msgstr "Verwaltung des Server Passwortes"
+
+#.
+#. * Create all the dialog boxes for data collection
+#.
+#: ../web/swat.c:1085 ../web/swat.c:1132
+msgid "User Name"
+msgstr "Benutzername"
+
+#: ../web/swat.c:1088 ../web/swat.c:1134
+msgid "Old Password"
+msgstr "Altes Passwort"
+
+#: ../web/swat.c:1091 ../web/swat.c:1136
+msgid "New Password"
+msgstr "Neues Passwort"
+
+#: ../web/swat.c:1093 ../web/swat.c:1138
+msgid "Re-type New Password"
+msgstr "Wiederhole neues Passwort"
+
+#: ../web/swat.c:1101 ../web/swat.c:1149
+msgid "Change Password"
+msgstr "Ändere Passwort"
+
+#: ../web/swat.c:1104
+msgid "Add New User"
+msgstr "Füge Benutzer hinzu"
+
+#: ../web/swat.c:1106
+msgid "Delete User"
+msgstr "Lösche Benutzer"
+
+#: ../web/swat.c:1108
+msgid "Disable User"
+msgstr "Deaktiviere Benutzer"
+
+#: ../web/swat.c:1110
+msgid "Enable User"
+msgstr "Aktiviere Benutzer"
+
+#: ../web/swat.c:1123
+msgid "Client/Server Password Management"
+msgstr "Client/Server Passwort Verwaltung"
+
+#: ../web/swat.c:1140
+msgid "Remote Machine"
+msgstr "Remote-Server"
+
+#: ../web/swat.c:1179
+msgid "Printer Parameters"
+msgstr "Drucker Parameter"
+
+#: ../web/swat.c:1181
+msgid "Important Note:"
+msgstr "Wichtiger Hinweis:"
+
+#: ../web/swat.c:1182
+msgid "Printer names marked with [*] in the Choose Printer drop-down box "
+msgstr "Mit [*] gekennzeichnete Drucker in der Druckerauswahlliste"
+
+#: ../web/swat.c:1183
+msgid "are autoloaded printers from "
+msgstr "wurden automatisch geladen von :"
+
+#: ../web/swat.c:1184
+msgid "Printcap Name"
+msgstr "Printcap Name"
+
+#: ../web/swat.c:1185
+msgid "Attempting to delete these printers from SWAT will have no effect."
+msgstr "Der Versuch diese Drucker von SWAT aus zu löschen wird keine Auswirkung haben."
+
+#: ../web/swat.c:1231
+msgid "Choose Printer"
+msgstr "Wähle Drucker"
+
+#: ../web/swat.c:1250
+msgid "Delete Printer"
+msgstr "Lösche Drucker"
+
+#: ../web/swat.c:1257
+msgid "Create Printer"
+msgstr "Ersteller Drucker"
+
+#: ../web/statuspage.c:123
+msgid "RDONLY "
+msgstr ""
+
+#: ../web/statuspage.c:124
+msgid "WRONLY "
+msgstr ""
+
+#: ../web/statuspage.c:125
+msgid "RDWR "
+msgstr ""
+
+#: ../web/statuspage.c:309
+msgid "Server Status"
+msgstr "Server-Status"
+
+#: ../web/statuspage.c:314
+msgid "Auto Refresh"
+msgstr "Automatische Aktualisierung"
+
+#: ../web/statuspage.c:315 ../web/statuspage.c:320
+msgid "Refresh Interval: "
+msgstr "Aktualisierungsintervall: "
+
+#: ../web/statuspage.c:319
+msgid "Stop Refreshing"
+msgstr "Stoppe Aktualisierung"
+
+#: ../web/statuspage.c:334
+msgid "version:"
+msgstr "Version:"
+
+#: ../web/statuspage.c:337
+msgid "smbd:"
+msgstr ""
+
+#: ../web/statuspage.c:337 ../web/statuspage.c:350 ../web/statuspage.c:364
+msgid "running"
+msgstr "aktiv"
+
+#: ../web/statuspage.c:337 ../web/statuspage.c:350 ../web/statuspage.c:364
+msgid "not running"
+msgstr "inaktiv"
+
+#: ../web/statuspage.c:341
+msgid "Stop smbd"
+msgstr "Stoppe smbd"
+
+#: ../web/statuspage.c:343
+msgid "Start smbd"
+msgstr "Starte smbd"
+
+#: ../web/statuspage.c:345
+msgid "Restart smbd"
+msgstr "Neustart smbd"
+
+#: ../web/statuspage.c:350
+msgid "nmbd:"
+msgstr ""
+
+#: ../web/statuspage.c:354
+msgid "Stop nmbd"
+msgstr "Stoppe nmbd"
+
+#: ../web/statuspage.c:356
+msgid "Start nmbd"
+msgstr "Starte nmbd"
+
+#: ../web/statuspage.c:358
+msgid "Restart nmbd"
+msgstr "Neustart nmbd"
+
+#: ../web/statuspage.c:364
+msgid "winbindd:"
+msgstr ""
+
+#: ../web/statuspage.c:368
+msgid "Stop winbindd"
+msgstr "Stoppe winbindd"
+
+#: ../web/statuspage.c:370
+msgid "Start winbindd"
+msgstr "Starte winbindd"
+
+#: ../web/statuspage.c:372
+msgid "Restart winbindd"
+msgstr "Neustart winbindd"
+
+#. stop, restart all
+#: ../web/statuspage.c:381
+msgid "Stop All"
+msgstr "Alle Stoppen"
+
+#: ../web/statuspage.c:382
+msgid "Restart All"
+msgstr "Alle neu starten"
+
+#. start all
+#: ../web/statuspage.c:386
+msgid "Start All"
+msgstr "Alle Starten"
+
+#: ../web/statuspage.c:393
+msgid "Active Connections"
+msgstr "Aktive Verbindungen"
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408 ../web/statuspage.c:416
+msgid "PID"
+msgstr ""
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408
+msgid "Client"
+msgstr ""
+
+#: ../web/statuspage.c:395
+msgid "IP address"
+msgstr "IP-Adresse"
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408 ../web/statuspage.c:416
+msgid "Date"
+msgstr "Datum"
+
+#: ../web/statuspage.c:397
+msgid "Kill"
+msgstr "Killen"
+
+#: ../web/statuspage.c:405
+msgid "Active Shares"
+msgstr "Aktive Freigaben"
+
+#: ../web/statuspage.c:408
+msgid "Share"
+msgstr "Freigabe"
+
+#: ../web/statuspage.c:408
+msgid "User"
+msgstr "Benutzer"
+
+#: ../web/statuspage.c:408
+msgid "Group"
+msgstr "Gruppe"
+
+#: ../web/statuspage.c:414
+msgid "Open Files"
+msgstr "Offene Dateien"
+
+#: ../web/statuspage.c:416
+msgid "Sharing"
+msgstr ""
+
+#: ../web/statuspage.c:416
+msgid "R/W"
+msgstr ""
+
+#: ../web/statuspage.c:416
+msgid "Oplock"
+msgstr ""
+
+#: ../web/statuspage.c:416
+msgid "File"
+msgstr "Datei"
+
+#: ../web/statuspage.c:425
+msgid "Show Client in col 1"
+msgstr ""
+
+#: ../web/statuspage.c:426
+msgid "Show PID in col 1"
+msgstr ""
+
+#: ../param/loadparm.c:755
+msgid "Base Options"
+msgstr "Basisoptionen"
+
+#: ../param/loadparm.c:775
+msgid "Security Options"
+msgstr "Sicherheitsoptionen"
+
+#: ../param/loadparm.c:859
+msgid "Logging Options"
+msgstr "Log Optionen"
+
+#: ../param/loadparm.c:874
+msgid "Protocol Options"
+msgstr "Protokoll Optionen"
+
+#: ../param/loadparm.c:911
+msgid "Tuning Options"
+msgstr "Optimierungsoptionen"
+
+#: ../param/loadparm.c:940
+msgid "Printing Options"
+msgstr "Druckoptionen"
+
+#: ../param/loadparm.c:970
+msgid "Filename Handling"
+msgstr "Verwaltung Dateinamen"
+
+#: ../param/loadparm.c:996
+msgid "Domain Options"
+msgstr "Domänen Optionen"
+
+#: ../param/loadparm.c:1000
+msgid "Logon Options"
+msgstr "Login optionen"
+
+#: ../param/loadparm.c:1019
+msgid "Browse Options"
+msgstr "Browsing Optionen"
+
+#: ../param/loadparm.c:1033
+msgid "WINS Options"
+msgstr "WINS Optionen"
+
+#: ../param/loadparm.c:1043
+msgid "Locking Options"
+msgstr "Locking Optionen"
+
+#: ../param/loadparm.c:1061
+msgid "Ldap Options"
+msgstr "LDAP Optionen"
+
+#: ../param/loadparm.c:1078
+msgid "Miscellaneous Options"
+msgstr "Verschiedene Optionen"
+
+#: ../param/loadparm.c:1138
+msgid "VFS module options"
+msgstr "VFS Optionen"
+
+#: ../param/loadparm.c:1148
+msgid "Winbind options"
+msgstr "Winbind Optionen"
diff --git a/source3/po/en.msg b/source3/po/en.msg
new file mode 100644
index 0000000000..01e6b6943b
--- /dev/null
+++ b/source3/po/en.msg
@@ -0,0 +1,592 @@
+# English messages for international release of SWAT.
+# Copyright (C) 2003 TAKAHASHI Motonobu <monyo@samba.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: i18n_swat \n"
+"POT-Creation-Date: 2003-10-06 05:30+0900\n"
+"PO-Revision-Date: 2000-02-08 12:48+09:00\n"
+"Last-Translator: TAKAHASHI Motonobu <monyo@samba.org>\n"
+"Language-Team: (Samba Team) <samba-technical@samba.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: \n"
+
+#: ../web/swat.c:117
+#, c-format
+msgid "ERROR: Can't open %s"
+msgstr ""
+
+#: ../web/swat.c:200
+msgid "Help"
+msgstr ""
+
+#: ../web/swat.c:206 ../web/swat.c:220 ../web/swat.c:235 ../web/swat.c:243 ../web/swat.c:252 ../web/swat.c:261 ../web/swat.c:267 ../web/swat.c:273 ../web/swat.c:286
+msgid "Set Default"
+msgstr ""
+
+#: ../web/swat.c:408
+#, c-format
+msgid "failed to open %s for writing"
+msgstr ""
+
+#: ../web/swat.c:431
+#, c-format
+msgid "Can't reload %s"
+msgstr ""
+
+#: ../web/swat.c:501
+#, c-format
+msgid "Logged in as <b>%s</b>"
+msgstr ""
+
+#: ../web/swat.c:505
+msgid "Home"
+msgstr ""
+
+#: ../web/swat.c:507
+msgid "Globals"
+msgstr ""
+
+#: ../web/swat.c:508
+msgid "Shares"
+msgstr ""
+
+#: ../web/swat.c:509
+msgid "Printers"
+msgstr ""
+
+#: ../web/swat.c:510
+msgid "Wizard"
+msgstr ""
+
+#: ../web/swat.c:513
+msgid "Status"
+msgstr ""
+
+#: ../web/swat.c:514
+msgid "View Config"
+msgstr ""
+
+#: ../web/swat.c:516
+msgid "Password Management"
+msgstr ""
+
+#: ../web/swat.c:526
+msgid "Current View Is"
+msgstr ""
+
+#: ../web/swat.c:527 ../web/swat.c:530
+msgid "Basic"
+msgstr ""
+
+#: ../web/swat.c:528 ../web/swat.c:531
+msgid "Advanced"
+msgstr ""
+
+#: ../web/swat.c:529
+msgid "Change View To"
+msgstr ""
+
+#: ../web/swat.c:554
+msgid "Current Config"
+msgstr ""
+
+#: ../web/swat.c:558
+msgid "Normal View"
+msgstr ""
+
+#: ../web/swat.c:560
+msgid "Full View"
+msgstr ""
+
+#. Here we first set and commit all the parameters that were selected
+#. in the previous screen.
+#: ../web/swat.c:579
+msgid "Wizard Parameter Edit Page"
+msgstr ""
+
+#: ../web/swat.c:608
+msgid "Note: smb.conf file has been read and rewritten"
+msgstr ""
+
+#. Here we go ...
+#: ../web/swat.c:716
+msgid "Samba Configuration Wizard"
+msgstr ""
+
+#: ../web/swat.c:720
+msgid "The \"Rewrite smb.conf file\" button will clear the smb.conf file of all default values and of comments."
+msgstr ""
+
+#: ../web/swat.c:721
+msgid "The same will happen if you press the commit button."
+msgstr ""
+
+#: ../web/swat.c:724
+msgid "Rewrite smb.conf file"
+msgstr ""
+
+#: ../web/swat.c:725
+msgid "Commit"
+msgstr ""
+
+#: ../web/swat.c:726
+msgid "Edit Parameter Values"
+msgstr ""
+
+#: ../web/swat.c:732
+msgid "Server Type"
+msgstr ""
+
+#: ../web/swat.c:733
+msgid "Stand Alone"
+msgstr ""
+
+#: ../web/swat.c:734
+msgid "Domain Member"
+msgstr ""
+
+#: ../web/swat.c:735
+msgid "Domain Controller"
+msgstr ""
+
+#: ../web/swat.c:738
+msgid "Unusual Type in smb.conf - Please Select New Mode"
+msgstr ""
+
+#: ../web/swat.c:740
+msgid "Configure WINS As"
+msgstr ""
+
+#: ../web/swat.c:741
+msgid "Not Used"
+msgstr ""
+
+#: ../web/swat.c:742
+msgid "Server for client use"
+msgstr ""
+
+#: ../web/swat.c:743
+msgid "Client of another WINS server"
+msgstr ""
+
+#: ../web/swat.c:745
+msgid "Remote WINS Server"
+msgstr ""
+
+#: ../web/swat.c:756
+msgid "Error: WINS Server Mode and WINS Support both set in smb.conf"
+msgstr ""
+
+#: ../web/swat.c:757
+msgid "Please Select desired WINS mode above."
+msgstr ""
+
+#: ../web/swat.c:759
+msgid "Expose Home Directories"
+msgstr ""
+
+#: ../web/swat.c:774
+msgid "The above configuration options will set multiple parameters and will generally assist with rapid Samba deployment."
+msgstr ""
+
+#: ../web/swat.c:787
+msgid "Global Parameters"
+msgstr ""
+
+#: ../web/swat.c:815 ../web/swat.c:916 ../web/swat.c:1265
+msgid "Commit Changes"
+msgstr ""
+
+#: ../web/swat.c:819 ../web/swat.c:919 ../web/swat.c:1267
+msgid "Reset Values"
+msgstr ""
+
+#: ../web/swat.c:844
+msgid "Share Parameters"
+msgstr ""
+
+#: ../web/swat.c:887
+msgid "Choose Share"
+msgstr ""
+
+#: ../web/swat.c:901
+msgid "Delete Share"
+msgstr ""
+
+#: ../web/swat.c:908
+msgid "Create Share"
+msgstr ""
+
+#: ../web/swat.c:944
+msgid "password change in demo mode rejected"
+msgstr ""
+
+#: ../web/swat.c:957
+msgid "Can't setup password database vectors."
+msgstr ""
+
+#: ../web/swat.c:983
+msgid " Must specify \"User Name\" "
+msgstr ""
+
+#: ../web/swat.c:999
+msgid " Must specify \"Old Password\" "
+msgstr ""
+
+#: ../web/swat.c:1005
+msgid " Must specify \"Remote Machine\" "
+msgstr ""
+
+#: ../web/swat.c:1012
+msgid " Must specify \"New, and Re-typed Passwords\" "
+msgstr ""
+
+#: ../web/swat.c:1018
+msgid " Re-typed password didn't match new password "
+msgstr ""
+
+#: ../web/swat.c:1048
+#, c-format
+msgid " The passwd for '%s' has been changed."
+msgstr ""
+
+#: ../web/swat.c:1051
+#, c-format
+msgid " The passwd for '%s' has NOT been changed."
+msgstr ""
+
+#: ../web/swat.c:1076
+msgid "Server Password Management"
+msgstr ""
+
+#.
+#. * Create all the dialog boxes for data collection
+#.
+#: ../web/swat.c:1085 ../web/swat.c:1132
+msgid "User Name"
+msgstr ""
+
+#: ../web/swat.c:1088 ../web/swat.c:1134
+msgid "Old Password"
+msgstr ""
+
+#: ../web/swat.c:1091 ../web/swat.c:1136
+msgid "New Password"
+msgstr ""
+
+#: ../web/swat.c:1093 ../web/swat.c:1138
+msgid "Re-type New Password"
+msgstr ""
+
+#: ../web/swat.c:1101 ../web/swat.c:1149
+msgid "Change Password"
+msgstr ""
+
+#: ../web/swat.c:1104
+msgid "Add New User"
+msgstr ""
+
+#: ../web/swat.c:1106
+msgid "Delete User"
+msgstr ""
+
+#: ../web/swat.c:1108
+msgid "Disable User"
+msgstr ""
+
+#: ../web/swat.c:1110
+msgid "Enable User"
+msgstr ""
+
+#: ../web/swat.c:1123
+msgid "Client/Server Password Management"
+msgstr ""
+
+#: ../web/swat.c:1140
+msgid "Remote Machine"
+msgstr ""
+
+#: ../web/swat.c:1179
+msgid "Printer Parameters"
+msgstr ""
+
+#: ../web/swat.c:1181
+msgid "Important Note:"
+msgstr ""
+
+#: ../web/swat.c:1182
+msgid "Printer names marked with [*] in the Choose Printer drop-down box "
+msgstr ""
+
+#: ../web/swat.c:1183
+msgid "are autoloaded printers from "
+msgstr ""
+
+#: ../web/swat.c:1184
+msgid "Printcap Name"
+msgstr ""
+
+#: ../web/swat.c:1185
+msgid "Attempting to delete these printers from SWAT will have no effect."
+msgstr ""
+
+#: ../web/swat.c:1231
+msgid "Choose Printer"
+msgstr ""
+
+#: ../web/swat.c:1250
+msgid "Delete Printer"
+msgstr ""
+
+#: ../web/swat.c:1257
+msgid "Create Printer"
+msgstr ""
+
+#: ../web/statuspage.c:123
+msgid "RDONLY "
+msgstr ""
+
+#: ../web/statuspage.c:124
+msgid "WRONLY "
+msgstr ""
+
+#: ../web/statuspage.c:125
+msgid "RDWR "
+msgstr ""
+
+#: ../web/statuspage.c:309
+msgid "Server Status"
+msgstr ""
+
+#: ../web/statuspage.c:314
+msgid "Auto Refresh"
+msgstr ""
+
+#: ../web/statuspage.c:315 ../web/statuspage.c:320
+msgid "Refresh Interval: "
+msgstr ""
+
+#: ../web/statuspage.c:319
+msgid "Stop Refreshing"
+msgstr ""
+
+#: ../web/statuspage.c:334
+msgid "version:"
+msgstr ""
+
+#: ../web/statuspage.c:337
+msgid "smbd:"
+msgstr ""
+
+#: ../web/statuspage.c:337 ../web/statuspage.c:350 ../web/statuspage.c:364
+msgid "running"
+msgstr ""
+
+#: ../web/statuspage.c:337 ../web/statuspage.c:350 ../web/statuspage.c:364
+msgid "not running"
+msgstr ""
+
+#: ../web/statuspage.c:341
+msgid "Stop smbd"
+msgstr ""
+
+#: ../web/statuspage.c:343
+msgid "Start smbd"
+msgstr ""
+
+#: ../web/statuspage.c:345
+msgid "Restart smbd"
+msgstr ""
+
+#: ../web/statuspage.c:350
+msgid "nmbd:"
+msgstr ""
+
+#: ../web/statuspage.c:354
+msgid "Stop nmbd"
+msgstr ""
+
+#: ../web/statuspage.c:356
+msgid "Start nmbd"
+msgstr ""
+
+#: ../web/statuspage.c:358
+msgid "Restart nmbd"
+msgstr ""
+
+#: ../web/statuspage.c:364
+msgid "winbindd:"
+msgstr ""
+
+#: ../web/statuspage.c:368
+msgid "Stop winbindd"
+msgstr ""
+
+#: ../web/statuspage.c:370
+msgid "Start winbindd"
+msgstr ""
+
+#: ../web/statuspage.c:372
+msgid "Restart winbindd"
+msgstr ""
+
+#. stop, restart all
+#: ../web/statuspage.c:381
+msgid "Stop All"
+msgstr ""
+
+#: ../web/statuspage.c:382
+msgid "Restart All"
+msgstr ""
+
+#. start all
+#: ../web/statuspage.c:386
+msgid "Start All"
+msgstr ""
+
+#: ../web/statuspage.c:393
+msgid "Active Connections"
+msgstr ""
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408 ../web/statuspage.c:416
+msgid "PID"
+msgstr ""
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408
+msgid "Client"
+msgstr ""
+
+#: ../web/statuspage.c:395
+msgid "IP address"
+msgstr ""
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408 ../web/statuspage.c:416
+msgid "Date"
+msgstr ""
+
+#: ../web/statuspage.c:397
+msgid "Kill"
+msgstr ""
+
+#: ../web/statuspage.c:405
+msgid "Active Shares"
+msgstr ""
+
+#: ../web/statuspage.c:408
+msgid "Share"
+msgstr ""
+
+#: ../web/statuspage.c:408
+msgid "User"
+msgstr ""
+
+#: ../web/statuspage.c:408
+msgid "Group"
+msgstr ""
+
+#: ../web/statuspage.c:414
+msgid "Open Files"
+msgstr ""
+
+#: ../web/statuspage.c:416
+msgid "Sharing"
+msgstr ""
+
+#: ../web/statuspage.c:416
+msgid "R/W"
+msgstr ""
+
+#: ../web/statuspage.c:416
+msgid "Oplock"
+msgstr ""
+
+#: ../web/statuspage.c:416
+msgid "File"
+msgstr ""
+
+#: ../web/statuspage.c:425
+msgid "Show Client in col 1"
+msgstr ""
+
+#: ../web/statuspage.c:426
+msgid "Show PID in col 1"
+msgstr ""
+
+#: ../param/loadparm.c:755
+msgid "Base Options"
+msgstr ""
+
+#: ../param/loadparm.c:775
+msgid "Security Options"
+msgstr ""
+
+#: ../param/loadparm.c:859
+msgid "Logging Options"
+msgstr ""
+
+#: ../param/loadparm.c:874
+msgid "Protocol Options"
+msgstr ""
+
+#: ../param/loadparm.c:911
+msgid "Tuning Options"
+msgstr ""
+
+#: ../param/loadparm.c:940
+msgid "Printing Options"
+msgstr ""
+
+#: ../param/loadparm.c:970
+msgid "Filename Handling"
+msgstr ""
+
+#: ../param/loadparm.c:996
+msgid "Domain Options"
+msgstr ""
+
+#: ../param/loadparm.c:1000
+msgid "Logon Options"
+msgstr ""
+
+#: ../param/loadparm.c:1019
+msgid "Browse Options"
+msgstr ""
+
+#: ../param/loadparm.c:1033
+msgid "WINS Options"
+msgstr ""
+
+#: ../param/loadparm.c:1043
+msgid "Locking Options"
+msgstr ""
+
+#: ../param/loadparm.c:1061
+msgid "Ldap Options"
+msgstr ""
+
+#: ../param/loadparm.c:1078
+msgid "Miscellaneous Options"
+msgstr ""
+
+#: ../param/loadparm.c:1138
+msgid "VFS module options"
+msgstr ""
+
+#: ../param/loadparm.c:1148
+msgid "Winbind options"
+msgstr ""
diff --git a/source3/po/fi.msg b/source3/po/fi.msg
new file mode 100644
index 0000000000..e039311aa8
--- /dev/null
+++ b/source3/po/fi.msg
@@ -0,0 +1,610 @@
+# Finnish messages for international release of SWAT.
+# Copyright (C) 2007 Lauri Nurmi <lanurmi@iki.fi>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: i18n_swat \n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-01-02 01:56+0200\n"
+"PO-Revision-Date: 2007-01-12 18:56+0200\n"
+"Last-Translator: Lauri Nurmi <lanurmi@iki.fi>\n"
+"Language-Team: Finnish <laatu@lokalisointi.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: \n"
+
+#: ../web/swat.c:139
+#, c-format
+msgid "ERROR: Can't open %s"
+msgstr "VIRHE: Avaaminen ei onnistu — %s"
+
+#: ../web/swat.c:223
+msgid "Help"
+msgstr "Ohje"
+
+#: ../web/swat.c:229 ../web/swat.c:254 ../web/swat.c:275 ../web/swat.c:285 ../web/swat.c:294 ../web/swat.c:303 ../web/swat.c:309 ../web/swat.c:315 ../web/swat.c:328
+msgid "Set Default"
+msgstr "Oletusarvo"
+
+#: ../web/swat.c:450
+#, c-format
+msgid "failed to open %s for writing"
+msgstr "avaaminen kirjoitustilassa ei onnistu — %s"
+
+#: ../web/swat.c:473
+#, c-format
+msgid "Can't reload %s"
+msgstr "Uudelleen lataaminen ei onnistu — %s"
+
+#: ../web/swat.c:543
+#, c-format
+msgid "Logged in as <b>%s</b>"
+msgstr "Sisäänkirjautuminen käyttäjänä <b>%s</b>"
+
+#: ../web/swat.c:547
+msgid "Home"
+msgstr "Koti"
+
+#: ../web/swat.c:549
+msgid "Globals"
+msgstr "Yleiset"
+
+#: ../web/swat.c:550
+msgid "Shares"
+msgstr "Jaot"
+
+#: ../web/swat.c:551
+msgid "Printers"
+msgstr "Tulostimet"
+
+#: ../web/swat.c:552
+msgid "Wizard"
+msgstr "Ohjatut asetukset"
+
+#: ../web/swat.c:556
+msgid "Status"
+msgstr "Tila"
+
+#: ../web/swat.c:557
+msgid "View Config"
+msgstr "Näytä asetukset"
+
+#: ../web/swat.c:559
+msgid "Password Management"
+msgstr "Salasanojen hallinta"
+
+#: ../web/swat.c:569
+msgid "Current View Is"
+msgstr "Näkymä nyt"
+
+#: ../web/swat.c:570 ../web/swat.c:573
+msgid "Basic"
+msgstr "Tavallinen"
+
+#: ../web/swat.c:571 ../web/swat.c:574
+msgid "Advanced"
+msgstr "Laajennettu"
+
+#: ../web/swat.c:572
+msgid "Change View To"
+msgstr "Vaihda näkymäksi"
+
+#: ../web/swat.c:601
+msgid "Current Config"
+msgstr "Nykyiset asetukset"
+
+#: ../web/swat.c:605
+msgid "Normal View"
+msgstr "Normaali näkymä"
+
+#: ../web/swat.c:607
+msgid "Full View"
+msgstr "Täysi näkymä"
+
+#. Here we first set and commit all the parameters that were selected
+#. in the previous screen.
+#: ../web/swat.c:626
+msgid "Wizard Parameter Edit Page"
+msgstr "Ohjattujen asetusten muokkaussivu"
+
+#: ../web/swat.c:655
+msgid "Note: smb.conf file has been read and rewritten"
+msgstr "Huom: smb.conf-tiedosto on luettu ja kirjoitettu uudelleen"
+
+#. Here we go ...
+#: ../web/swat.c:763
+msgid "Samba Configuration Wizard"
+msgstr "Samban ohjatut asetukset"
+
+#: ../web/swat.c:767
+msgid "The \"Rewrite smb.conf file\" button will clear the smb.conf file of all default values and of comments."
+msgstr "â€Kirjoita uudelleen smb.conf-tiedostoâ€-painike tyhjentää oletusarvot ja kommentit smb.conf-tiedostosta."
+
+#: ../web/swat.c:768
+msgid "The same will happen if you press the commit button."
+msgstr "Samoin tapahtuu â€Tallennaâ€-painiketta painettaessa."
+
+#: ../web/swat.c:771
+msgid "Rewrite smb.conf file"
+msgstr "Kirjoita uudelleen smb.conf-tiedosto"
+
+#: ../web/swat.c:772
+msgid "Commit"
+msgstr "Tallenna"
+
+#: ../web/swat.c:773
+msgid "Edit Parameter Values"
+msgstr "Muokkaa asetusten arvoja"
+
+#: ../web/swat.c:779
+msgid "Server Type"
+msgstr "Palvelimen tyyppi"
+
+#: ../web/swat.c:780
+msgid "Stand Alone"
+msgstr "Itsenäinen"
+
+# lähde: Microsoftin käännökset
+#: ../web/swat.c:781
+msgid "Domain Member"
+msgstr "Toimialuejäsen"
+
+# lähde: Microsoftin käännökset
+#: ../web/swat.c:782
+msgid "Domain Controller"
+msgstr "Toimialueen ohjauskone"
+
+#: ../web/swat.c:785
+msgid "Unusual Type in smb.conf - Please Select New Mode"
+msgstr "Epätavallinen tyyppi smb.confissa — Valitse uusi tila"
+
+#: ../web/swat.c:787
+msgid "Configure WINS As"
+msgstr "WINS"
+
+#: ../web/swat.c:788
+msgid "Not Used"
+msgstr "Ei käytössä"
+
+#: ../web/swat.c:789
+msgid "Server for client use"
+msgstr "Palvelimena"
+
+#: ../web/swat.c:790
+msgid "Client of another WINS server"
+msgstr "Käyttää WINS-etäpalvelinta"
+
+#: ../web/swat.c:792
+msgid "Remote WINS Server"
+msgstr "WINS-etäpalvelin"
+
+#: ../web/swat.c:803
+msgid "Error: WINS Server Mode and WINS Support both set in smb.conf"
+msgstr "Virhe: Sekä WINS-palvelintila että WINS-tuki asetettu smb.confissa"
+
+#: ../web/swat.c:804
+msgid "Please Select desired WINS mode above."
+msgstr "Valitse haluttu WINSin tila yltä."
+
+#: ../web/swat.c:806
+msgid "Expose Home Directories"
+msgstr "Jaa kotihakemistot"
+
+#: ../web/swat.c:821
+msgid "The above configuration options will set multiple parameters and will generally assist with rapid Samba deployment."
+msgstr "Yllä olevat valinnat asettavat useita asetuksia, ja auttavat Samban nopeassa käyttöönotossa."
+
+#: ../web/swat.c:834
+msgid "Global Parameters"
+msgstr "Yleisasetukset"
+
+#: ../web/swat.c:862 ../web/swat.c:966 ../web/swat.c:1318
+msgid "Commit Changes"
+msgstr "Tallenna muutokset"
+
+#: ../web/swat.c:866 ../web/swat.c:969 ../web/swat.c:1320
+msgid "Reset Values"
+msgstr "Kumoa muutokset"
+
+#: ../web/swat.c:891
+msgid "Share Parameters"
+msgstr "Jakoasetukset"
+
+#: ../web/swat.c:934
+msgid "Choose Share"
+msgstr "Valitse jako"
+
+#: ../web/swat.c:951
+msgid "Delete Share"
+msgstr "Poista jako"
+
+#: ../web/swat.c:958
+msgid "Create Share"
+msgstr "Luo jako"
+
+#: ../web/swat.c:994
+msgid "password change in demo mode rejected"
+msgstr "salasanan muutos estetty esittelytilassa"
+
+#: ../web/swat.c:1007
+msgid "Can't setup password database vectors."
+msgstr "Salasanatietokannan alustus epäonnistui."
+
+#: ../web/swat.c:1033
+msgid " Must specify \"User Name\" "
+msgstr " Käyttäjätunnus on annettava "
+
+#: ../web/swat.c:1049
+msgid " Must specify \"Old Password\" "
+msgstr " Vanha salasana on annettava "
+
+#: ../web/swat.c:1055
+msgid " Must specify \"Remote Machine\" "
+msgstr " Etäkone on annettava "
+
+#: ../web/swat.c:1062
+msgid " Must specify \"New, and Re-typed Passwords\" "
+msgstr " Uusi salasana on kirjoitettava kahdesti "
+
+#: ../web/swat.c:1068
+msgid " Re-typed password didn't match new password "
+msgstr " Salasanat eivät täsmää "
+
+#: ../web/swat.c:1101
+#, c-format
+msgid " The passwd for '%s' has been changed."
+msgstr " Käyttäjän â€%s†salasana vaihdettu."
+
+#: ../web/swat.c:1104
+#, c-format
+msgid " The passwd for '%s' has NOT been changed."
+msgstr " Käyttäjän â€%s†salasanaa EI vaihdettu."
+
+#: ../web/swat.c:1129
+msgid "Server Password Management"
+msgstr "Palvelimen salasanojen hallinta"
+
+#.
+#. * Create all the dialog boxes for data collection
+#.
+#: ../web/swat.c:1138 ../web/swat.c:1185
+msgid "User Name"
+msgstr "Käyttäjätunnus"
+
+#: ../web/swat.c:1141 ../web/swat.c:1187
+msgid "Old Password"
+msgstr "Vanha salasana"
+
+#: ../web/swat.c:1144 ../web/swat.c:1189
+msgid "New Password"
+msgstr "Uusi salasana"
+
+#: ../web/swat.c:1146 ../web/swat.c:1191
+msgid "Re-type New Password"
+msgstr "Uusi salasana uudelleen"
+
+#: ../web/swat.c:1154 ../web/swat.c:1202
+msgid "Change Password"
+msgstr "Vaihda salasana"
+
+#: ../web/swat.c:1157
+msgid "Add New User"
+msgstr "Lisää uusi käyttäjä"
+
+#: ../web/swat.c:1159
+msgid "Delete User"
+msgstr "Poista käyttäjä"
+
+# Joku suomenkielisempi olisi ehkä parempi.
+#: ../web/swat.c:1161
+msgid "Disable User"
+msgstr "Passivoi käyttäjä"
+
+# Joku suomenkielisempi olisi ehkä parempi.
+#: ../web/swat.c:1163
+msgid "Enable User"
+msgstr "Aktivoi käyttäjä"
+
+# hmm...
+#: ../web/swat.c:1176
+msgid "Client/Server Password Management"
+msgstr "Asiakas-palvelin-salasanojen hallinta"
+
+#: ../web/swat.c:1193
+msgid "Remote Machine"
+msgstr "Etäkone"
+
+#: ../web/swat.c:1232
+msgid "Printer Parameters"
+msgstr "Tulostinasetukset"
+
+#: ../web/swat.c:1234
+msgid "Important Note:"
+msgstr "Tärkeä huomautus:"
+
+#: ../web/swat.c:1235
+#, c-format
+msgid "Printer names marked with [*] in the Choose Printer drop-down box "
+msgstr "Tähdellä [*] merkityt tulostimien nimet pudotusvalikossa ovat "
+
+#: ../web/swat.c:1236
+#, c-format
+msgid "are autoloaded printers from "
+msgstr "automaattisesti ladattuja tulostimia "
+
+#: ../web/swat.c:1237
+msgid "Printcap Name"
+msgstr "Printcap Name -asetuksen osoittamasta paikasta"
+
+#: ../web/swat.c:1238
+msgid "Attempting to delete these printers from SWAT will have no effect."
+msgstr "Näiden tulostimien poistaminen ei onnistu SWATin kautta."
+
+#: ../web/swat.c:1284
+msgid "Choose Printer"
+msgstr "Valitse tulostin"
+
+#: ../web/swat.c:1303
+msgid "Delete Printer"
+msgstr "Poista tulostin"
+
+#: ../web/swat.c:1310
+msgid "Create Printer"
+msgstr "Luo tulostin"
+
+#: ../web/statuspage.c:139
+msgid "RDWR "
+msgstr "Luku+kirj. "
+
+#: ../web/statuspage.c:141
+msgid "WRONLY "
+msgstr "Vain kirj. "
+
+#: ../web/statuspage.c:143
+msgid "RDONLY "
+msgstr "Vain luku "
+
+#: ../web/statuspage.c:330
+msgid "Server Status"
+msgstr "Palvelimen tila"
+
+#: ../web/statuspage.c:335
+msgid "Auto Refresh"
+msgstr "Automaattinen päivitys"
+
+#: ../web/statuspage.c:336 ../web/statuspage.c:341
+msgid "Refresh Interval: "
+msgstr "Päivitysväli: "
+
+#: ../web/statuspage.c:340
+msgid "Stop Refreshing"
+msgstr "Lopeta päivitys"
+
+#: ../web/statuspage.c:355
+msgid "version:"
+msgstr "versio:"
+
+#: ../web/statuspage.c:358
+msgid "smbd:"
+msgstr "smbd:"
+
+#: ../web/statuspage.c:358 ../web/statuspage.c:371 ../web/statuspage.c:385
+msgid "running"
+msgstr "käynnissä"
+
+#: ../web/statuspage.c:358 ../web/statuspage.c:371 ../web/statuspage.c:385
+msgid "not running"
+msgstr "pysäytetty"
+
+#: ../web/statuspage.c:362
+msgid "Stop smbd"
+msgstr "Pysäytä smbd"
+
+#: ../web/statuspage.c:364
+msgid "Start smbd"
+msgstr "Käynnistä smbd"
+
+#: ../web/statuspage.c:366
+msgid "Restart smbd"
+msgstr "Käynnistä smbd uudelleen"
+
+#: ../web/statuspage.c:371
+msgid "nmbd:"
+msgstr "nmbd:"
+
+#: ../web/statuspage.c:375
+msgid "Stop nmbd"
+msgstr "Pysäytä nmbd"
+
+#: ../web/statuspage.c:377
+msgid "Start nmbd"
+msgstr "Käynnistä nmbd"
+
+#: ../web/statuspage.c:379
+msgid "Restart nmbd"
+msgstr "Käynnistä nmbd uudelleen"
+
+#: ../web/statuspage.c:385
+msgid "winbindd:"
+msgstr "winbindd:"
+
+#: ../web/statuspage.c:389
+msgid "Stop winbindd"
+msgstr "Pysäytä winbindd"
+
+#: ../web/statuspage.c:391
+msgid "Start winbindd"
+msgstr "Käynnistä winbindd"
+
+#: ../web/statuspage.c:393
+msgid "Restart winbindd"
+msgstr "Käynnistä winbindd uudelleen"
+
+#. stop, restart all
+#: ../web/statuspage.c:402
+msgid "Stop All"
+msgstr "Pysäytä kaikki"
+
+#: ../web/statuspage.c:403
+msgid "Restart All"
+msgstr "Käynnistä kaikki uudelleen"
+
+#. start all
+#: ../web/statuspage.c:407
+msgid "Start All"
+msgstr "Käynnistä kaikki"
+
+#: ../web/statuspage.c:414
+msgid "Active Connections"
+msgstr "Aktiiviset yhteydet"
+
+#: ../web/statuspage.c:416 ../web/statuspage.c:429 ../web/statuspage.c:437
+msgid "PID"
+msgstr "PID"
+
+#: ../web/statuspage.c:416 ../web/statuspage.c:429
+msgid "Client"
+msgstr "Asiakas"
+
+#: ../web/statuspage.c:416
+msgid "IP address"
+msgstr "IP-osoite"
+
+#: ../web/statuspage.c:416 ../web/statuspage.c:429 ../web/statuspage.c:437
+msgid "Date"
+msgstr "Aika"
+
+#: ../web/statuspage.c:418
+msgid "Kill"
+msgstr "Sulje"
+
+#: ../web/statuspage.c:426
+msgid "Active Shares"
+msgstr "Aktiiviset jaot"
+
+#: ../web/statuspage.c:429
+msgid "Share"
+msgstr "Jako"
+
+#: ../web/statuspage.c:429
+msgid "User"
+msgstr "Käyttäjä"
+
+#: ../web/statuspage.c:429
+msgid "Group"
+msgstr "Ryhmä"
+
+#: ../web/statuspage.c:435
+msgid "Open Files"
+msgstr "Avoimet tiedostot"
+
+# Tämä on ilmeisesti palvelimen puolella vallitseva UID.
+#: ../web/statuspage.c:437
+msgid "Sharing"
+msgstr "Jakaja"
+
+#: ../web/statuspage.c:437
+msgid "R/W"
+msgstr "Luku/kirj."
+
+# Selitys:
+# "Oplocks is a unique Windows file locking feature. It is not really file
+# locking, but is included in most discussions of Windows file locking, so
+# is considered a de facto locking feature."
+# Suomennos: ???
+#: ../web/statuspage.c:437
+msgid "Oplock"
+msgstr "Oplock"
+
+#: ../web/statuspage.c:437
+msgid "File"
+msgstr "Tiedosto"
+
+#: ../web/statuspage.c:446
+msgid "Show Client in col 1"
+msgstr "Näytä asiakas 1. sarakkeessa"
+
+#: ../web/statuspage.c:447
+msgid "Show PID in col 1"
+msgstr "Näytä PID 1. sarakkeessa"
+
+#: ../param/loadparm.c:834
+msgid "Base Options"
+msgstr "Perusasetukset"
+
+#: ../param/loadparm.c:853
+msgid "Security Options"
+msgstr "Turvallisuusasetukset"
+
+#: ../param/loadparm.c:943
+msgid "Logging Options"
+msgstr "Lokiasetukset"
+
+#: ../param/loadparm.c:959
+msgid "Protocol Options"
+msgstr "Protokolla-asetukset"
+
+#: ../param/loadparm.c:1005
+msgid "Tuning Options"
+msgstr "Hienosäätöasetukset"
+
+#: ../param/loadparm.c:1035
+msgid "Printing Options"
+msgstr "Tulostusasetukset"
+
+#: ../param/loadparm.c:1072
+msgid "Filename Handling"
+msgstr "Tiedostonimien käsittely"
+
+#: ../param/loadparm.c:1102
+msgid "Domain Options"
+msgstr "Toimialueasetukset"
+
+#: ../param/loadparm.c:1106
+msgid "Logon Options"
+msgstr "Kirjautumisasetukset"
+
+#: ../param/loadparm.c:1127
+msgid "Browse Options"
+msgstr "Selausasetukset"
+
+#: ../param/loadparm.c:1141
+msgid "WINS Options"
+msgstr "WINS-asetukset"
+
+#: ../param/loadparm.c:1150
+msgid "Locking Options"
+msgstr "Lukitusasetukset"
+
+#: ../param/loadparm.c:1168
+msgid "Ldap Options"
+msgstr "LDAP-asetukset"
+
+#: ../param/loadparm.c:1184
+msgid "Miscellaneous Options"
+msgstr "Sekalaiset asetukset"
+
+#: ../param/loadparm.c:1189
+msgid "EventLog Options"
+msgstr "Tapahtumalokiasetukset"
+
+#: ../param/loadparm.c:1257
+msgid "VFS module options"
+msgstr "VFS-moduulin asetukset"
+
+#: ../param/loadparm.c:1267
+msgid "Winbind options"
+msgstr "Winbind-asetukset"
diff --git a/source3/po/fr.msg b/source3/po/fr.msg
new file mode 100644
index 0000000000..aac900223e
--- /dev/null
+++ b/source3/po/fr.msg
@@ -0,0 +1,592 @@
+# French messages for international release of SWAT.
+# Copyright (C) 2001 François Le Lay <fanch@tuxfamily.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: i18n_swat \n"
+"POT-Creation-Date: 2003-10-06 05:30+0900\n"
+"PO-Revision-Date: 2000-02-08 14:45+0100\n"
+"Last-Translator: François Le Lay <fanch@tuxfamily.org>\n"
+"Language-Team: (Samba Team) <samba-technical@samba.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: \n"
+
+#: ../web/swat.c:117
+#, c-format
+msgid "ERROR: Can't open %s"
+msgstr ""
+
+#: ../web/swat.c:200
+msgid "Help"
+msgstr "Aide"
+
+#: ../web/swat.c:206 ../web/swat.c:220 ../web/swat.c:235 ../web/swat.c:243 ../web/swat.c:252 ../web/swat.c:261 ../web/swat.c:267 ../web/swat.c:273 ../web/swat.c:286
+msgid "Set Default"
+msgstr "Définir par défaut"
+
+#: ../web/swat.c:408
+#, c-format
+msgid "failed to open %s for writing"
+msgstr ""
+
+#: ../web/swat.c:431
+#, c-format
+msgid "Can't reload %s"
+msgstr ""
+
+#: ../web/swat.c:501
+#, c-format
+msgid "Logged in as <b>%s</b>"
+msgstr "Connecté en tant que <b>%s</b>"
+
+#: ../web/swat.c:505
+msgid "Home"
+msgstr "Home"
+
+#: ../web/swat.c:507
+msgid "Globals"
+msgstr "Paramètres Généraux"
+
+#: ../web/swat.c:508
+msgid "Shares"
+msgstr "Partages"
+
+#: ../web/swat.c:509
+msgid "Printers"
+msgstr "Imprimantes"
+
+#: ../web/swat.c:510
+msgid "Wizard"
+msgstr ""
+
+#: ../web/swat.c:513
+msgid "Status"
+msgstr "Statut"
+
+#: ../web/swat.c:514
+msgid "View Config"
+msgstr "Voir Configuration"
+
+#: ../web/swat.c:516
+msgid "Password Management"
+msgstr "Gestion des mots de passe"
+
+#: ../web/swat.c:526
+msgid "Current View Is"
+msgstr "Configuration Actuelle"
+
+#: ../web/swat.c:527 ../web/swat.c:530
+msgid "Basic"
+msgstr "Vue Basique"
+
+#: ../web/swat.c:528 ../web/swat.c:531
+msgid "Advanced"
+msgstr "Vue Détaillée"
+
+#: ../web/swat.c:529
+msgid "Change View To"
+msgstr "Modifier le mot de passe"
+
+#: ../web/swat.c:554
+msgid "Current Config"
+msgstr "Configuration Actuelle"
+
+#: ../web/swat.c:558
+msgid "Normal View"
+msgstr "Vue Normale"
+
+#: ../web/swat.c:560
+msgid "Full View"
+msgstr "Vue Complète"
+
+#. Here we first set and commit all the parameters that were selected
+#. in the previous screen.
+#: ../web/swat.c:579
+msgid "Wizard Parameter Edit Page"
+msgstr ""
+
+#: ../web/swat.c:608
+msgid "Note: smb.conf file has been read and rewritten"
+msgstr ""
+
+#. Here we go ...
+#: ../web/swat.c:716
+msgid "Samba Configuration Wizard"
+msgstr ""
+
+#: ../web/swat.c:720
+msgid "The \"Rewrite smb.conf file\" button will clear the smb.conf file of all default values and of comments."
+msgstr ""
+
+#: ../web/swat.c:721
+msgid "The same will happen if you press the commit button."
+msgstr ""
+
+#: ../web/swat.c:724
+msgid "Rewrite smb.conf file"
+msgstr ""
+
+#: ../web/swat.c:725
+msgid "Commit"
+msgstr "commentaire"
+
+#: ../web/swat.c:726
+msgid "Edit Parameter Values"
+msgstr "Paramètres Imprimantes"
+
+#: ../web/swat.c:732
+msgid "Server Type"
+msgstr ""
+
+#: ../web/swat.c:733
+msgid "Stand Alone"
+msgstr ""
+
+#: ../web/swat.c:734
+msgid "Domain Member"
+msgstr "master de domaine"
+
+#: ../web/swat.c:735
+msgid "Domain Controller"
+msgstr "master de domaine"
+
+#: ../web/swat.c:738
+msgid "Unusual Type in smb.conf - Please Select New Mode"
+msgstr ""
+
+#: ../web/swat.c:740
+msgid "Configure WINS As"
+msgstr ""
+
+#: ../web/swat.c:741
+msgid "Not Used"
+msgstr "ne pas descendre"
+
+#: ../web/swat.c:742
+msgid "Server for client use"
+msgstr ""
+
+#: ../web/swat.c:743
+msgid "Client of another WINS server"
+msgstr ""
+
+#: ../web/swat.c:745
+msgid "Remote WINS Server"
+msgstr ""
+
+#: ../web/swat.c:756
+msgid "Error: WINS Server Mode and WINS Support both set in smb.conf"
+msgstr ""
+
+#: ../web/swat.c:757
+msgid "Please Select desired WINS mode above."
+msgstr ""
+
+#: ../web/swat.c:759
+msgid "Expose Home Directories"
+msgstr ""
+
+#: ../web/swat.c:774
+msgid "The above configuration options will set multiple parameters and will generally assist with rapid Samba deployment."
+msgstr ""
+
+#: ../web/swat.c:787
+msgid "Global Parameters"
+msgstr "Variables Globales"
+
+#: ../web/swat.c:815 ../web/swat.c:916 ../web/swat.c:1265
+msgid "Commit Changes"
+msgstr "Sauver les modifications"
+
+#: ../web/swat.c:819 ../web/swat.c:919 ../web/swat.c:1267
+msgid "Reset Values"
+msgstr "Réinitialiser Valeurs"
+
+#: ../web/swat.c:844
+msgid "Share Parameters"
+msgstr "Paramètres de partage"
+
+#: ../web/swat.c:887
+msgid "Choose Share"
+msgstr "Choisir un partage"
+
+#: ../web/swat.c:901
+msgid "Delete Share"
+msgstr "Supprimer un partage"
+
+#: ../web/swat.c:908
+msgid "Create Share"
+msgstr "Créer un partage"
+
+#: ../web/swat.c:944
+msgid "password change in demo mode rejected"
+msgstr "changement de mot de passe en mode démo rejeté"
+
+#: ../web/swat.c:957
+msgid "Can't setup password database vectors."
+msgstr ""
+
+#: ../web/swat.c:983
+msgid " Must specify \"User Name\" "
+msgstr " Le champ \"Nom d'utilisateur\" doit être spécifié"
+
+#: ../web/swat.c:999
+msgid " Must specify \"Old Password\" "
+msgstr " Le champ \"Ancien mot de passe\" doît être spécifié"
+
+#: ../web/swat.c:1005
+msgid " Must specify \"Remote Machine\" "
+msgstr " Le champ \"Machine Distante\" doît être spécifié"
+
+#: ../web/swat.c:1012
+msgid " Must specify \"New, and Re-typed Passwords\" "
+msgstr "Les champs \"Nouveau mot de passe\" et \"Confirmation du nouveau mot de passe\" doivent être spécifiés \n"
+
+#: ../web/swat.c:1018
+msgid " Re-typed password didn't match new password "
+msgstr " Echec de la confirmation du nouveau mot de passe"
+
+#: ../web/swat.c:1048
+#, c-format
+msgid " The passwd for '%s' has been changed."
+msgstr " Le mot de passe de '%s' a été modifié. "
+
+#: ../web/swat.c:1051
+#, c-format
+msgid " The passwd for '%s' has NOT been changed."
+msgstr " Le mot de passe de '%s' n'a PAS été modifié. \n"
+
+#: ../web/swat.c:1076
+msgid "Server Password Management"
+msgstr "Gestion des mots de passe serveur"
+
+#.
+#. * Create all the dialog boxes for data collection
+#.
+#: ../web/swat.c:1085 ../web/swat.c:1132
+msgid "User Name"
+msgstr " Nom d'utilisateur : "
+
+#: ../web/swat.c:1088 ../web/swat.c:1134
+msgid "Old Password"
+msgstr " Ancien mot de passe : "
+
+#: ../web/swat.c:1091 ../web/swat.c:1136
+msgid "New Password"
+msgstr " Nouveau mot de passe : "
+
+#: ../web/swat.c:1093 ../web/swat.c:1138
+msgid "Re-type New Password"
+msgstr " Confirmation du nouveau mot de passe : "
+
+#: ../web/swat.c:1101 ../web/swat.c:1149
+msgid "Change Password"
+msgstr "Modifier le mot de passe"
+
+#: ../web/swat.c:1104
+msgid "Add New User"
+msgstr "Nouvel Utilisateur"
+
+#: ../web/swat.c:1106
+msgid "Delete User"
+msgstr "Supprimer Utilisateur"
+
+#: ../web/swat.c:1108
+msgid "Disable User"
+msgstr "Désactiver Utilisateur"
+
+#: ../web/swat.c:1110
+msgid "Enable User"
+msgstr "Activer Utilisateur"
+
+#: ../web/swat.c:1123
+msgid "Client/Server Password Management"
+msgstr "Gestion des mots de passe Client/Serveur"
+
+#: ../web/swat.c:1140
+msgid "Remote Machine"
+msgstr " Machine distante : "
+
+#: ../web/swat.c:1179
+msgid "Printer Parameters"
+msgstr "Paramètres Imprimantes"
+
+#: ../web/swat.c:1181
+msgid "Important Note:"
+msgstr "Note Importante:"
+
+#: ../web/swat.c:1182
+msgid "Printer names marked with [*] in the Choose Printer drop-down box "
+msgstr "Les Noms d'imprimantes marqués du signe [*] dans le menu déroulant Choisir Imprimante"
+
+#: ../web/swat.c:1183
+msgid "are autoloaded printers from "
+msgstr "désignent des imprimantes automatiquement chargées depuis le "
+
+#: ../web/swat.c:1184
+msgid "Printcap Name"
+msgstr "Nom Printcap"
+
+#: ../web/swat.c:1185
+msgid "Attempting to delete these printers from SWAT will have no effect."
+msgstr "Essayer de supprimer ces imprimantes depuis SWAT n'aura aucun effet."
+
+#: ../web/swat.c:1231
+msgid "Choose Printer"
+msgstr "Choisir Imprimante"
+
+#: ../web/swat.c:1250
+msgid "Delete Printer"
+msgstr "Supprimer Imprimante"
+
+#: ../web/swat.c:1257
+msgid "Create Printer"
+msgstr "Créer Imprimante"
+
+#: ../web/statuspage.c:123
+msgid "RDONLY "
+msgstr ""
+
+#: ../web/statuspage.c:124
+msgid "WRONLY "
+msgstr ""
+
+#: ../web/statuspage.c:125
+msgid "RDWR "
+msgstr ""
+
+#: ../web/statuspage.c:309
+msgid "Server Status"
+msgstr "Statut du Serveur"
+
+#: ../web/statuspage.c:314
+msgid "Auto Refresh"
+msgstr "Rafraîchissement Automatique"
+
+#: ../web/statuspage.c:315 ../web/statuspage.c:320
+msgid "Refresh Interval: "
+msgstr "Intervalle de rafraîchissement: "
+
+#: ../web/statuspage.c:319
+msgid "Stop Refreshing"
+msgstr "Stopper Rafraîchissement"
+
+#: ../web/statuspage.c:334
+msgid "version:"
+msgstr "version:"
+
+#: ../web/statuspage.c:337
+msgid "smbd:"
+msgstr ""
+
+#: ../web/statuspage.c:337 ../web/statuspage.c:350 ../web/statuspage.c:364
+msgid "running"
+msgstr "actif"
+
+#: ../web/statuspage.c:337 ../web/statuspage.c:350 ../web/statuspage.c:364
+msgid "not running"
+msgstr "non actif"
+
+#: ../web/statuspage.c:341
+msgid "Stop smbd"
+msgstr "Stopper smbd"
+
+#: ../web/statuspage.c:343
+msgid "Start smbd"
+msgstr "Lancer smbd"
+
+#: ../web/statuspage.c:345
+msgid "Restart smbd"
+msgstr "Relancer smbd"
+
+#: ../web/statuspage.c:350
+msgid "nmbd:"
+msgstr ""
+
+#: ../web/statuspage.c:354
+msgid "Stop nmbd"
+msgstr "Stopper nmbd"
+
+#: ../web/statuspage.c:356
+msgid "Start nmbd"
+msgstr "Lancer nmbd"
+
+#: ../web/statuspage.c:358
+msgid "Restart nmbd"
+msgstr "Relancer nmbd"
+
+#: ../web/statuspage.c:364
+msgid "winbindd:"
+msgstr ""
+
+#: ../web/statuspage.c:368
+msgid "Stop winbindd"
+msgstr "Stopper nmbd"
+
+#: ../web/statuspage.c:370
+msgid "Start winbindd"
+msgstr "Lancer nmbd"
+
+#: ../web/statuspage.c:372
+msgid "Restart winbindd"
+msgstr "Relancer nmbd"
+
+#. stop, restart all
+#: ../web/statuspage.c:381
+msgid "Stop All"
+msgstr ""
+
+#: ../web/statuspage.c:382
+msgid "Restart All"
+msgstr "Relancer nmbd"
+
+#. start all
+#: ../web/statuspage.c:386
+msgid "Start All"
+msgstr "Lancer nmbd"
+
+#: ../web/statuspage.c:393
+msgid "Active Connections"
+msgstr "Connections Actives"
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408 ../web/statuspage.c:416
+msgid "PID"
+msgstr ""
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408
+msgid "Client"
+msgstr ""
+
+#: ../web/statuspage.c:395
+msgid "IP address"
+msgstr "adresse IP"
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408 ../web/statuspage.c:416
+msgid "Date"
+msgstr "Date"
+
+#: ../web/statuspage.c:397
+msgid "Kill"
+msgstr "Terminer"
+
+#: ../web/statuspage.c:405
+msgid "Active Shares"
+msgstr "Partages Actifs"
+
+#: ../web/statuspage.c:408
+msgid "Share"
+msgstr "Partager"
+
+#: ../web/statuspage.c:408
+msgid "User"
+msgstr "Utilisateur"
+
+#: ../web/statuspage.c:408
+msgid "Group"
+msgstr "Groupe"
+
+#: ../web/statuspage.c:414
+msgid "Open Files"
+msgstr "Fichiers Ouverts"
+
+#: ../web/statuspage.c:416
+msgid "Sharing"
+msgstr ""
+
+#: ../web/statuspage.c:416
+msgid "R/W"
+msgstr ""
+
+#: ../web/statuspage.c:416
+msgid "Oplock"
+msgstr ""
+
+#: ../web/statuspage.c:416
+msgid "File"
+msgstr "Fichier"
+
+#: ../web/statuspage.c:425
+msgid "Show Client in col 1"
+msgstr ""
+
+#: ../web/statuspage.c:426
+msgid "Show PID in col 1"
+msgstr ""
+
+#: ../param/loadparm.c:755
+msgid "Base Options"
+msgstr "Options de base"
+
+#: ../param/loadparm.c:775
+msgid "Security Options"
+msgstr "Options de Sécurité"
+
+#: ../param/loadparm.c:859
+msgid "Logging Options"
+msgstr "Options de Logging"
+
+#: ../param/loadparm.c:874
+msgid "Protocol Options"
+msgstr "Options de Protocole"
+
+#: ../param/loadparm.c:911
+msgid "Tuning Options"
+msgstr "Options de réglage"
+
+#: ../param/loadparm.c:940
+msgid "Printing Options"
+msgstr "Options d'impression"
+
+#: ../param/loadparm.c:970
+msgid "Filename Handling"
+msgstr "Gestion des noms de fichier"
+
+#: ../param/loadparm.c:996
+msgid "Domain Options"
+msgstr "Options de Domaine"
+
+#: ../param/loadparm.c:1000
+msgid "Logon Options"
+msgstr "Options de Logon"
+
+#: ../param/loadparm.c:1019
+msgid "Browse Options"
+msgstr "Options de Navigation"
+
+#: ../param/loadparm.c:1033
+msgid "WINS Options"
+msgstr "Options WINS"
+
+#: ../param/loadparm.c:1043
+msgid "Locking Options"
+msgstr "Options de Verrouillage"
+
+#: ../param/loadparm.c:1061
+msgid "Ldap Options"
+msgstr "Options Ldap"
+
+#: ../param/loadparm.c:1078
+msgid "Miscellaneous Options"
+msgstr "Options Diverses"
+
+#: ../param/loadparm.c:1138
+msgid "VFS module options"
+msgstr "Options VFS"
+
+#: ../param/loadparm.c:1148
+msgid "Winbind options"
+msgstr "Options Winbind"
diff --git a/source3/po/genmsg b/source3/po/genmsg
new file mode 100755
index 0000000000..543200a40f
--- /dev/null
+++ b/source3/po/genmsg
@@ -0,0 +1,39 @@
+#!/bin/sh
+# Copyright (C) 2003 TAKAHASHI Motonobu <monyo@samba.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+
+FILES='../web/swat.c ../web/statuspage.c ../param/loadparm.c'
+LANGS='en ja tr pl fr de it'
+
+XGETTEXT=xgettext
+MSGMERGE=msgmerge
+
+WIDTH=256
+
+$XGETTEXT --default-domain="i18n_swat" \
+ --add-comments \
+ --keyword=_ --keyword=N_ \
+ --width=${WIDTH} \
+ $FILES
+
+for lang in $LANGS; do
+ printf "%s" "$lang"
+ mv ${lang}.msg ${lang}.msg.old
+ $MSGMERGE --width=${WIDTH} ${lang}.msg.old i18n_swat.po -o ${lang}.msg
+done
+
+rm i18n_swat.po
+
diff --git a/source3/po/it.msg b/source3/po/it.msg
new file mode 100644
index 0000000000..90c3ed5672
--- /dev/null
+++ b/source3/po/it.msg
@@ -0,0 +1,592 @@
+# Italian messages for international release of SWAT.
+# Copyright (C) 2001 Simo Sorce <idra@samba.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: i18n_swat \n"
+"POT-Creation-Date: 2003-10-06 05:30+0900\n"
+"PO-Revision-Date: 2000-02-08 14:45+0100\n"
+"Last-Translator: Simo Sorce <idra@samba.org>\n"
+"Language-Team: (Samba Team) <samba-technical@samba.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: \n"
+
+#: ../web/swat.c:117
+#, c-format
+msgid "ERROR: Can't open %s"
+msgstr ""
+
+#: ../web/swat.c:200
+msgid "Help"
+msgstr "Aiuto"
+
+#: ../web/swat.c:206 ../web/swat.c:220 ../web/swat.c:235 ../web/swat.c:243 ../web/swat.c:252 ../web/swat.c:261 ../web/swat.c:267 ../web/swat.c:273 ../web/swat.c:286
+msgid "Set Default"
+msgstr "Imposta Default"
+
+#: ../web/swat.c:408
+#, c-format
+msgid "failed to open %s for writing"
+msgstr ""
+
+#: ../web/swat.c:431
+#, c-format
+msgid "Can't reload %s"
+msgstr ""
+
+#: ../web/swat.c:501
+#, c-format
+msgid "Logged in as <b>%s</b>"
+msgstr "Connesso come <b>%s</b><p>\n"
+
+#: ../web/swat.c:505
+msgid "Home"
+msgstr "Home"
+
+#: ../web/swat.c:507
+msgid "Globals"
+msgstr "Globali"
+
+#: ../web/swat.c:508
+msgid "Shares"
+msgstr "Condivisioni"
+
+#: ../web/swat.c:509
+msgid "Printers"
+msgstr "Stampanti"
+
+#: ../web/swat.c:510
+msgid "Wizard"
+msgstr ""
+
+#: ../web/swat.c:513
+msgid "Status"
+msgstr "Stato"
+
+#: ../web/swat.c:514
+msgid "View Config"
+msgstr "Visualizza Configurazione"
+
+#: ../web/swat.c:516
+msgid "Password Management"
+msgstr "Gestione Password"
+
+#: ../web/swat.c:526
+msgid "Current View Is"
+msgstr "Configurazione Attuale"
+
+#: ../web/swat.c:527 ../web/swat.c:530
+msgid "Basic"
+msgstr "Vista Semplice"
+
+#: ../web/swat.c:528 ../web/swat.c:531
+msgid "Advanced"
+msgstr "Vista Avanzata"
+
+#: ../web/swat.c:529
+msgid "Change View To"
+msgstr "Cambia Password"
+
+#: ../web/swat.c:554
+msgid "Current Config"
+msgstr "Configurazione Attuale"
+
+#: ../web/swat.c:558
+msgid "Normal View"
+msgstr "Vista Normale"
+
+#: ../web/swat.c:560
+msgid "Full View"
+msgstr "Vista Completa"
+
+#. Here we first set and commit all the parameters that were selected
+#. in the previous screen.
+#: ../web/swat.c:579
+msgid "Wizard Parameter Edit Page"
+msgstr ""
+
+#: ../web/swat.c:608
+msgid "Note: smb.conf file has been read and rewritten"
+msgstr ""
+
+#. Here we go ...
+#: ../web/swat.c:716
+msgid "Samba Configuration Wizard"
+msgstr ""
+
+#: ../web/swat.c:720
+msgid "The \"Rewrite smb.conf file\" button will clear the smb.conf file of all default values and of comments."
+msgstr ""
+
+#: ../web/swat.c:721
+msgid "The same will happen if you press the commit button."
+msgstr ""
+
+#: ../web/swat.c:724
+msgid "Rewrite smb.conf file"
+msgstr ""
+
+#: ../web/swat.c:725
+msgid "Commit"
+msgstr "commento"
+
+#: ../web/swat.c:726
+msgid "Edit Parameter Values"
+msgstr "Parametri Stampante"
+
+#: ../web/swat.c:732
+msgid "Server Type"
+msgstr ""
+
+#: ../web/swat.c:733
+msgid "Stand Alone"
+msgstr ""
+
+#: ../web/swat.c:734
+msgid "Domain Member"
+msgstr "master dominio"
+
+#: ../web/swat.c:735
+msgid "Domain Controller"
+msgstr "master dominio"
+
+#: ../web/swat.c:738
+msgid "Unusual Type in smb.conf - Please Select New Mode"
+msgstr ""
+
+#: ../web/swat.c:740
+msgid "Configure WINS As"
+msgstr ""
+
+#: ../web/swat.c:741
+msgid "Not Used"
+msgstr "non discendere"
+
+#: ../web/swat.c:742
+msgid "Server for client use"
+msgstr ""
+
+#: ../web/swat.c:743
+msgid "Client of another WINS server"
+msgstr ""
+
+#: ../web/swat.c:745
+msgid "Remote WINS Server"
+msgstr ""
+
+#: ../web/swat.c:756
+msgid "Error: WINS Server Mode and WINS Support both set in smb.conf"
+msgstr ""
+
+#: ../web/swat.c:757
+msgid "Please Select desired WINS mode above."
+msgstr ""
+
+#: ../web/swat.c:759
+msgid "Expose Home Directories"
+msgstr ""
+
+#: ../web/swat.c:774
+msgid "The above configuration options will set multiple parameters and will generally assist with rapid Samba deployment."
+msgstr ""
+
+#: ../web/swat.c:787
+msgid "Global Parameters"
+msgstr "Variabili Globali"
+
+#: ../web/swat.c:815 ../web/swat.c:916 ../web/swat.c:1265
+msgid "Commit Changes"
+msgstr "Salva Modifiche"
+
+#: ../web/swat.c:819 ../web/swat.c:919 ../web/swat.c:1267
+msgid "Reset Values"
+msgstr "Resetta Valori"
+
+#: ../web/swat.c:844
+msgid "Share Parameters"
+msgstr "Parametri Condivisioni"
+
+#: ../web/swat.c:887
+msgid "Choose Share"
+msgstr "Scegli Condivisione"
+
+#: ../web/swat.c:901
+msgid "Delete Share"
+msgstr "Cancella Condivisione"
+
+#: ../web/swat.c:908
+msgid "Create Share"
+msgstr "Crea Condivisione"
+
+#: ../web/swat.c:944
+msgid "password change in demo mode rejected"
+msgstr "cambio password in modalita' demo rigettata"
+
+#: ../web/swat.c:957
+msgid "Can't setup password database vectors."
+msgstr ""
+
+#: ../web/swat.c:983
+msgid " Must specify \"User Name\" "
+msgstr " \"Nome Utente\" deve essere specificato "
+
+#: ../web/swat.c:999
+msgid " Must specify \"Old Password\" "
+msgstr " \"Vecchia Password\" deve essere specificato "
+
+#: ../web/swat.c:1005
+msgid " Must specify \"Remote Machine\" "
+msgstr " \"Macchina Remota\" deve essere specificato "
+
+#: ../web/swat.c:1012
+msgid " Must specify \"New, and Re-typed Passwords\" "
+msgstr " \"Nuova/Conferma Password\" devono essere specificati "
+
+#: ../web/swat.c:1018
+msgid " Re-typed password didn't match new password "
+msgstr " la password di conferma non e' uguale alla nuova password "
+
+#: ../web/swat.c:1048
+#, c-format
+msgid " The passwd for '%s' has been changed."
+msgstr " La password per '%s' e' stata cambiata."
+
+#: ../web/swat.c:1051
+#, c-format
+msgid " The passwd for '%s' has NOT been changed."
+msgstr " La password per '%s' non e' stata cambianta."
+
+#: ../web/swat.c:1076
+msgid "Server Password Management"
+msgstr "Gestione Password del Server"
+
+#.
+#. * Create all the dialog boxes for data collection
+#.
+#: ../web/swat.c:1085 ../web/swat.c:1132
+msgid "User Name"
+msgstr " Nome Utente"
+
+#: ../web/swat.c:1088 ../web/swat.c:1134
+msgid "Old Password"
+msgstr " Vecchia Password"
+
+#: ../web/swat.c:1091 ../web/swat.c:1136
+msgid "New Password"
+msgstr " Nuova Password"
+
+#: ../web/swat.c:1093 ../web/swat.c:1138
+msgid "Re-type New Password"
+msgstr " Conferma nuova Password"
+
+#: ../web/swat.c:1101 ../web/swat.c:1149
+msgid "Change Password"
+msgstr "Cambia Password"
+
+#: ../web/swat.c:1104
+msgid "Add New User"
+msgstr "Aggiungi Nuovo Utente"
+
+#: ../web/swat.c:1106
+msgid "Delete User"
+msgstr "Cancella Utente"
+
+#: ../web/swat.c:1108
+msgid "Disable User"
+msgstr "Disabilita Utente"
+
+#: ../web/swat.c:1110
+msgid "Enable User"
+msgstr "Abilita Utente"
+
+#: ../web/swat.c:1123
+msgid "Client/Server Password Management"
+msgstr "Gestione Password Client/Server"
+
+#: ../web/swat.c:1140
+msgid "Remote Machine"
+msgstr " Macchina Remota"
+
+#: ../web/swat.c:1179
+msgid "Printer Parameters"
+msgstr "Parametri Stampante"
+
+#: ../web/swat.c:1181
+msgid "Important Note:"
+msgstr "Nota Importante:"
+
+#: ../web/swat.c:1182
+msgid "Printer names marked with [*] in the Choose Printer drop-down box "
+msgstr "nomi di stampante marcati con [*] nel riquadro a scomparsa Scegli Stampante"
+
+#: ../web/swat.c:1183
+msgid "are autoloaded printers from "
+msgstr "sono stampanti caricate automaticamente da "
+
+#: ../web/swat.c:1184
+msgid "Printcap Name"
+msgstr "Nome Printcap"
+
+#: ../web/swat.c:1185
+msgid "Attempting to delete these printers from SWAT will have no effect."
+msgstr "Il tentativo di cancellare queste stampanti da sWAT non avara' effetto.\n"
+
+#: ../web/swat.c:1231
+msgid "Choose Printer"
+msgstr "Scegli Stampante"
+
+#: ../web/swat.c:1250
+msgid "Delete Printer"
+msgstr "Cancella Stampante"
+
+#: ../web/swat.c:1257
+msgid "Create Printer"
+msgstr "Crea Stampante"
+
+#: ../web/statuspage.c:123
+msgid "RDONLY "
+msgstr ""
+
+#: ../web/statuspage.c:124
+msgid "WRONLY "
+msgstr ""
+
+#: ../web/statuspage.c:125
+msgid "RDWR "
+msgstr ""
+
+#: ../web/statuspage.c:309
+msgid "Server Status"
+msgstr "Stato del Server"
+
+#: ../web/statuspage.c:314
+msgid "Auto Refresh"
+msgstr "Rinfresco Automatico"
+
+#: ../web/statuspage.c:315 ../web/statuspage.c:320
+msgid "Refresh Interval: "
+msgstr "Intervallo Rinfresco: "
+
+#: ../web/statuspage.c:319
+msgid "Stop Refreshing"
+msgstr "Ferma Rinfresco"
+
+#: ../web/statuspage.c:334
+msgid "version:"
+msgstr "versione:"
+
+#: ../web/statuspage.c:337
+msgid "smbd:"
+msgstr ""
+
+#: ../web/statuspage.c:337 ../web/statuspage.c:350 ../web/statuspage.c:364
+msgid "running"
+msgstr "attivo"
+
+#: ../web/statuspage.c:337 ../web/statuspage.c:350 ../web/statuspage.c:364
+msgid "not running"
+msgstr "non attivo"
+
+#: ../web/statuspage.c:341
+msgid "Stop smbd"
+msgstr "Ferma smbd"
+
+#: ../web/statuspage.c:343
+msgid "Start smbd"
+msgstr "Lancia smbd"
+
+#: ../web/statuspage.c:345
+msgid "Restart smbd"
+msgstr "Rilancia smbd"
+
+#: ../web/statuspage.c:350
+msgid "nmbd:"
+msgstr ""
+
+#: ../web/statuspage.c:354
+msgid "Stop nmbd"
+msgstr "Ferma nmbd"
+
+#: ../web/statuspage.c:356
+msgid "Start nmbd"
+msgstr "Lancia nmbd"
+
+#: ../web/statuspage.c:358
+msgid "Restart nmbd"
+msgstr "Rilancia nmbd"
+
+#: ../web/statuspage.c:364
+msgid "winbindd:"
+msgstr ""
+
+#: ../web/statuspage.c:368
+msgid "Stop winbindd"
+msgstr "Ferma nmbd"
+
+#: ../web/statuspage.c:370
+msgid "Start winbindd"
+msgstr "Lancia nmbd"
+
+#: ../web/statuspage.c:372
+msgid "Restart winbindd"
+msgstr "Rilancia nmbd"
+
+#. stop, restart all
+#: ../web/statuspage.c:381
+msgid "Stop All"
+msgstr ""
+
+#: ../web/statuspage.c:382
+msgid "Restart All"
+msgstr "Rilancia nmbd"
+
+#. start all
+#: ../web/statuspage.c:386
+msgid "Start All"
+msgstr "Lancia nmbd"
+
+#: ../web/statuspage.c:393
+msgid "Active Connections"
+msgstr "Connessioni Attive"
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408 ../web/statuspage.c:416
+msgid "PID"
+msgstr ""
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408
+msgid "Client"
+msgstr ""
+
+#: ../web/statuspage.c:395
+msgid "IP address"
+msgstr "indirizzo IP"
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408 ../web/statuspage.c:416
+msgid "Date"
+msgstr "Data"
+
+#: ../web/statuspage.c:397
+msgid "Kill"
+msgstr "Termina"
+
+#: ../web/statuspage.c:405
+msgid "Active Shares"
+msgstr "Condivisioni Attive"
+
+#: ../web/statuspage.c:408
+msgid "Share"
+msgstr "Condivisione"
+
+#: ../web/statuspage.c:408
+msgid "User"
+msgstr "Utente"
+
+#: ../web/statuspage.c:408
+msgid "Group"
+msgstr "Gruppo"
+
+#: ../web/statuspage.c:414
+msgid "Open Files"
+msgstr "File Aperti"
+
+#: ../web/statuspage.c:416
+msgid "Sharing"
+msgstr ""
+
+#: ../web/statuspage.c:416
+msgid "R/W"
+msgstr ""
+
+#: ../web/statuspage.c:416
+msgid "Oplock"
+msgstr ""
+
+#: ../web/statuspage.c:416
+msgid "File"
+msgstr ""
+
+#: ../web/statuspage.c:425
+msgid "Show Client in col 1"
+msgstr ""
+
+#: ../web/statuspage.c:426
+msgid "Show PID in col 1"
+msgstr ""
+
+#: ../param/loadparm.c:755
+msgid "Base Options"
+msgstr "Opzioni Basilari"
+
+#: ../param/loadparm.c:775
+msgid "Security Options"
+msgstr "Opzioni di Sicurezza"
+
+#: ../param/loadparm.c:859
+msgid "Logging Options"
+msgstr "Opzioni di Log"
+
+#: ../param/loadparm.c:874
+msgid "Protocol Options"
+msgstr "Opzioni Protocollo"
+
+#: ../param/loadparm.c:911
+msgid "Tuning Options"
+msgstr "Opzioni Tuning"
+
+#: ../param/loadparm.c:940
+msgid "Printing Options"
+msgstr "Opzioni di Stampa"
+
+#: ../param/loadparm.c:970
+msgid "Filename Handling"
+msgstr "Gestione Nomi File"
+
+#: ../param/loadparm.c:996
+msgid "Domain Options"
+msgstr "Opzioni Dominio"
+
+#: ../param/loadparm.c:1000
+msgid "Logon Options"
+msgstr "Opzioni di Logon"
+
+#: ../param/loadparm.c:1019
+msgid "Browse Options"
+msgstr "Opzioni Browsing"
+
+#: ../param/loadparm.c:1033
+msgid "WINS Options"
+msgstr "opzioni WINS"
+
+#: ../param/loadparm.c:1043
+msgid "Locking Options"
+msgstr "Opzioni Locking"
+
+#: ../param/loadparm.c:1061
+msgid "Ldap Options"
+msgstr "Opzioni Ldap"
+
+#: ../param/loadparm.c:1078
+msgid "Miscellaneous Options"
+msgstr "Opzioni Generiche"
+
+#: ../param/loadparm.c:1138
+msgid "VFS module options"
+msgstr "Opzioni VFS"
+
+#: ../param/loadparm.c:1148
+msgid "Winbind options"
+msgstr "Opzioni Winbind"
diff --git a/source3/po/ja.msg b/source3/po/ja.msg
new file mode 100644
index 0000000000..52ec57105f
--- /dev/null
+++ b/source3/po/ja.msg
@@ -0,0 +1,594 @@
+# Japanese messages for international release of SWAT.
+# Copyright (C) 2003 TAKAHASHI Motonobu <monyo@samba.org>
+# Copyright (C) 2000 Ryo Kawahara <rkawa@lbe.co.jp>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: i18n-swat\n"
+"POT-Creation-Date: 2003-10-06 05:30+0900\n"
+"PO-Revision-Date: 2003-09-23 04:38+900\n"
+"Last-Translator: TAKAHASHI Motonobu <monyo@samba.org>\n"
+"Language-Team: Samba Users Group Japan <sugj-tech@samba.gr.jp>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../web/swat.c:117
+#, c-format
+msgid "ERROR: Can't open %s"
+msgstr "%s をオープンã§ãã¾ã›ã‚“"
+
+#: ../web/swat.c:200
+msgid "Help"
+msgstr "ヘルプ"
+
+#: ../web/swat.c:206 ../web/swat.c:220 ../web/swat.c:235 ../web/swat.c:243 ../web/swat.c:252 ../web/swat.c:261 ../web/swat.c:267 ../web/swat.c:273 ../web/swat.c:286
+msgid "Set Default"
+msgstr "デフォルト値"
+
+#: ../web/swat.c:408
+#, c-format
+msgid "failed to open %s for writing"
+msgstr "%s を書ãè¾¼ã¿ç”¨ã«ã‚ªãƒ¼ãƒ—ンã§ãã¾ã›ã‚“"
+
+#: ../web/swat.c:431
+#, c-format
+msgid "Can't reload %s"
+msgstr "%s ã‚’å†èª­ã¿è¾¼ã¿ã§ãã¾ã›ã‚“\n"
+
+# msgid "Logged in as <b>%s</b><p>\n"
+#: ../web/swat.c:501
+#, c-format
+msgid "Logged in as <b>%s</b>"
+msgstr "<b>%s</b>ã¨ã—ã¦ãƒ­ã‚°ã‚¤ãƒ³"
+
+#: ../web/swat.c:505
+msgid "Home"
+msgstr "ホーム"
+
+#: ../web/swat.c:507
+msgid "Globals"
+msgstr "グローãƒãƒ«"
+
+#: ../web/swat.c:508
+msgid "Shares"
+msgstr "ファイル共有"
+
+#: ../web/swat.c:509
+msgid "Printers"
+msgstr "å°åˆ·å…±æœ‰"
+
+#: ../web/swat.c:510
+msgid "Wizard"
+msgstr "ウィザード"
+
+#: ../web/swat.c:513
+msgid "Status"
+msgstr "サーãƒã®çŠ¶æ…‹"
+
+#: ../web/swat.c:514
+msgid "View Config"
+msgstr "ç¾åœ¨ã®è¨­å®š"
+
+#: ../web/swat.c:516
+msgid "Password Management"
+msgstr "パスワード管ç†"
+
+#: ../web/swat.c:526
+msgid "Current View Is"
+msgstr "ç¾åœ¨ã®è¡¨ç¤ºãƒ¢ãƒ¼ãƒ‰"
+
+#: ../web/swat.c:527 ../web/swat.c:530
+msgid "Basic"
+msgstr "標準表示"
+
+#: ../web/swat.c:528 ../web/swat.c:531
+msgid "Advanced"
+msgstr "詳細表示"
+
+#: ../web/swat.c:529
+msgid "Change View To"
+msgstr "表示モードã®å¤‰æ›´"
+
+#: ../web/swat.c:554
+msgid "Current Config"
+msgstr "ç¾åœ¨ã®è¨­å®š"
+
+#: ../web/swat.c:558
+msgid "Normal View"
+msgstr "標準表示"
+
+#: ../web/swat.c:560
+msgid "Full View"
+msgstr "完全表示"
+
+#. Here we first set and commit all the parameters that were selected
+#. in the previous screen.
+#: ../web/swat.c:579
+msgid "Wizard Parameter Edit Page"
+msgstr "ウィザードã«ã‚ˆã‚‹ãƒ‘ラメータ編集ページ"
+
+#: ../web/swat.c:608
+msgid "Note: smb.conf file has been read and rewritten"
+msgstr "smb.conf ファイルãŒæ›¸ãæ›ãˆã‚‰ã‚Œã¾ã—ãŸã€‚"
+
+#. Here we go ...
+#: ../web/swat.c:716
+msgid "Samba Configuration Wizard"
+msgstr "Samba 設定ウィザード"
+
+#: ../web/swat.c:720
+msgid "The \"Rewrite smb.conf file\" button will clear the smb.conf file of all default values and of comments."
+msgstr "「smb.conf ã®æ›¸æ›ã€ãƒœã‚¿ãƒ³ã‚’押ã™ã¨ smb.conf ファイル中ã®ã™ã¹ã¦ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ã‚„コメントã¯å‰Šé™¤ã•ã‚Œã¾ã™ã€‚"
+
+#: ../web/swat.c:721
+msgid "The same will happen if you press the commit button."
+msgstr "「commitã€ãƒœã‚¿ãƒ³ã‚’押ã—ãŸå ´åˆã«ã‚‚åŒæ§˜ã®å¤‰æ›´ãŒè¡Œãªã‚ã‚Œã¾ã™ã€‚"
+
+#: ../web/swat.c:724
+msgid "Rewrite smb.conf file"
+msgstr "smb.conf ã®æ›¸æ›"
+
+#: ../web/swat.c:725
+msgid "Commit"
+msgstr "設定をå映"
+
+#: ../web/swat.c:726
+msgid "Edit Parameter Values"
+msgstr "å„パラメータã®ç·¨é›†"
+
+#: ../web/swat.c:732
+msgid "Server Type"
+msgstr "サーãƒã‚¿ã‚¤ãƒ—"
+
+#: ../web/swat.c:733
+msgid "Stand Alone"
+msgstr "スタンドアロン"
+
+#: ../web/swat.c:734
+msgid "Domain Member"
+msgstr "ドメインメンãƒ"
+
+#: ../web/swat.c:735
+msgid "Domain Controller"
+msgstr "ドメインコントローラ"
+
+#: ../web/swat.c:738
+msgid "Unusual Type in smb.conf - Please Select New Mode"
+msgstr "通常ã®å½¢å¼ã§ã¯ãªã„ - æ–°ã—ã„モードをé¸æŠžã®ã“ã¨"
+
+#: ../web/swat.c:740
+msgid "Configure WINS As"
+msgstr "WINS"
+
+#: ../web/swat.c:741
+msgid "Not Used"
+msgstr "使ã‚ãªã„"
+
+#: ../web/swat.c:742
+msgid "Server for client use"
+msgstr "サーãƒã¨ã—ã¦æ§‹æˆ"
+
+#: ../web/swat.c:743
+msgid "Client of another WINS server"
+msgstr "別㮠WINS サーãƒã®ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã¨ã—ã¦æ§‹æˆ"
+
+#: ../web/swat.c:745
+msgid "Remote WINS Server"
+msgstr "別㮠WINS サーãƒ"
+
+#: ../web/swat.c:756
+msgid "Error: WINS Server Mode and WINS Support both set in smb.conf"
+msgstr "エラー: wins server 㨠wins support ã®ä¸¡ãƒ‘ラメータ㌠smb.conf ã§æŒ‡å®šã•ã‚Œã¦ã„ã¾ã™"
+
+#: ../web/swat.c:757
+msgid "Please Select desired WINS mode above."
+msgstr "ã„ãšã‚Œã‹ã® WINS モードをé¸æŠžã—ã¦ãã ã•ã„。"
+
+#: ../web/swat.c:759
+msgid "Expose Home Directories"
+msgstr "ホームディレクトリã®å…¬é–‹"
+
+#: ../web/swat.c:774
+msgid "The above configuration options will set multiple parameters and will generally assist with rapid Samba deployment."
+msgstr "上記ã®è¨­å®šã‚ªãƒ—ションã«ã‚ˆã‚Šã€è¤‡æ•°ã®ãƒ‘ラメータãŒåŒæœŸã—ã¦è¨­å®šã•ã‚Œã‚‹ãŸã‚〠Samba ã®é‹ç”¨ã‚’迅速ã«é–‹å§‹ã™ã‚‹ä¸Šã§ã®åŠ©ã‘ã¨ãªã‚‹ã§ã—ょã†ã€‚"
+
+#: ../web/swat.c:787
+msgid "Global Parameters"
+msgstr "Global パラメータ"
+
+#: ../web/swat.c:815 ../web/swat.c:916 ../web/swat.c:1265
+msgid "Commit Changes"
+msgstr "変更をå映"
+
+#: ../web/swat.c:819 ../web/swat.c:919 ../web/swat.c:1267
+msgid "Reset Values"
+msgstr "変更をå–消"
+
+#: ../web/swat.c:844
+msgid "Share Parameters"
+msgstr "ファイル共有 パラメータ"
+
+#: ../web/swat.c:887
+msgid "Choose Share"
+msgstr "ファイル共有ã®é¸æŠž"
+
+#: ../web/swat.c:901
+msgid "Delete Share"
+msgstr "ファイル共有ã®å‰Šé™¤"
+
+#: ../web/swat.c:908
+msgid "Create Share"
+msgstr "ファイル共有ã®ä½œæˆ"
+
+#: ../web/swat.c:944
+msgid "password change in demo mode rejected"
+msgstr "デモ・モードã§ã®ãƒ‘スワード変更ã¯ã§ãã¾ã›ã‚“"
+
+#: ../web/swat.c:957
+msgid "Can't setup password database vectors."
+msgstr "パスワード・データベースãŒè¦‹ã¤ã‘られã¾ã›ã‚“"
+
+#: ../web/swat.c:983
+msgid " Must specify \"User Name\" "
+msgstr "「ユーザåã€æ¬„ã«å…¥åŠ›ã—ã¦ãã ã•ã„"
+
+#: ../web/swat.c:999
+msgid " Must specify \"Old Password\" "
+msgstr "「旧パスワードã€æ¬„ã«å…¥åŠ›ã—ã¦ãã ã•ã„"
+
+#: ../web/swat.c:1005
+msgid " Must specify \"Remote Machine\" "
+msgstr "「リモートマシンã€æ¬„ã«å…¥åŠ›ã—ã¦ãã ã•ã„"
+
+#: ../web/swat.c:1012
+msgid " Must specify \"New, and Re-typed Passwords\" "
+msgstr "「新パスワードã€æ¬„ã¨ã€Œæ–°ãƒ‘スワードã®å†å…¥åŠ›ã€æ¬„ã«å…¥åŠ›ã—ã¦ãã ã•ã„"
+
+#: ../web/swat.c:1018
+msgid " Re-typed password didn't match new password "
+msgstr "「新パスワードã®å†å…¥åŠ›ã€æ¬„ã®å…¥åŠ›å†…容ãŒã€Œæ–°ãƒ‘スワードã€æ¬„ã®å…¥åŠ›ã¨ä¸€è‡´ã—ã¦ã„ã¾ã›ã‚“。"
+
+#: ../web/swat.c:1048
+#, c-format
+msgid " The passwd for '%s' has been changed."
+msgstr " %s ã®ãƒ‘スワードã¯å¤‰æ›´ã•ã‚Œã¾ã—ãŸã€‚"
+
+#: ../web/swat.c:1051
+#, c-format
+msgid " The passwd for '%s' has NOT been changed."
+msgstr " '%s' ã®ãƒ‘スワードã¯å¤‰æ›´ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸã€‚"
+
+#: ../web/swat.c:1076
+msgid "Server Password Management"
+msgstr "ローカルマシンã®ãƒ‘スワード管ç†"
+
+#.
+#. * Create all the dialog boxes for data collection
+#.
+#: ../web/swat.c:1085 ../web/swat.c:1132
+msgid "User Name"
+msgstr "ユーザå"
+
+#: ../web/swat.c:1088 ../web/swat.c:1134
+msgid "Old Password"
+msgstr "旧パスワード"
+
+#: ../web/swat.c:1091 ../web/swat.c:1136
+msgid "New Password"
+msgstr "新パスワード"
+
+#: ../web/swat.c:1093 ../web/swat.c:1138
+msgid "Re-type New Password"
+msgstr "新パスワードã®å†å…¥åŠ›"
+
+#: ../web/swat.c:1101 ../web/swat.c:1149
+msgid "Change Password"
+msgstr "パスワード変更"
+
+#: ../web/swat.c:1104
+msgid "Add New User"
+msgstr "æ–°è¦ãƒ¦ãƒ¼ã‚¶è¿½åŠ "
+
+#: ../web/swat.c:1106
+msgid "Delete User"
+msgstr "ユーザã®å‰Šé™¤"
+
+#: ../web/swat.c:1108
+msgid "Disable User"
+msgstr "ユーザã®ç„¡åŠ¹åŒ–"
+
+#: ../web/swat.c:1110
+msgid "Enable User"
+msgstr "ユーザã®æœ‰åŠ¹åŒ–"
+
+#: ../web/swat.c:1123
+msgid "Client/Server Password Management"
+msgstr "リモートマシンã®ãƒ‘スワード管ç†"
+
+#: ../web/swat.c:1140
+msgid "Remote Machine"
+msgstr "リモートマシン"
+
+#: ../web/swat.c:1179
+msgid "Printer Parameters"
+msgstr "å°åˆ·å…±æœ‰ パラメータ"
+
+#: ../web/swat.c:1181
+msgid "Important Note:"
+msgstr "*注"
+
+#: ../web/swat.c:1182
+msgid "Printer names marked with [*] in the Choose Printer drop-down box "
+msgstr "åå‰ã®å…ˆé ­ã« [*] ãŒã¤ã„ãŸãƒ—リンタ"
+
+#: ../web/swat.c:1183
+msgid "are autoloaded printers from "
+msgstr "ã¯"
+
+#: ../web/swat.c:1184
+msgid "Printcap Name"
+msgstr "printcap name パラメータ"
+
+#: ../web/swat.c:1185
+msgid "Attempting to delete these printers from SWAT will have no effect."
+msgstr "ã‹ã‚‰è‡ªå‹•è¨­å®šã•ã‚ŒãŸã‚‚ã®ã§ã™ã‹ã‚‰ã€å‰Šé™¤ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。"
+
+#: ../web/swat.c:1231
+msgid "Choose Printer"
+msgstr "å°åˆ·å…±æœ‰ã®é¸æŠž"
+
+#: ../web/swat.c:1250
+msgid "Delete Printer"
+msgstr "å°åˆ·å…±æœ‰ã®å‰Šé™¤"
+
+#: ../web/swat.c:1257
+msgid "Create Printer"
+msgstr "å°åˆ·å…±æœ‰ã®ä½œæˆ"
+
+#: ../web/statuspage.c:123
+msgid "RDONLY "
+msgstr "å‚ç…§ã®ã¿ "
+
+#: ../web/statuspage.c:124
+msgid "WRONLY "
+msgstr "æ›´æ–°ã®ã¿ "
+
+#: ../web/statuspage.c:125
+msgid "RDWR "
+msgstr "å‚ç…§/æ›´æ–° "
+
+#: ../web/statuspage.c:309
+msgid "Server Status"
+msgstr "サーãƒã®çŠ¶æ…‹"
+
+#: ../web/statuspage.c:314
+msgid "Auto Refresh"
+msgstr "自動更新ã®é–‹å§‹"
+
+#: ../web/statuspage.c:315 ../web/statuspage.c:320
+msgid "Refresh Interval: "
+msgstr "æ›´æ–°é–“éš”: "
+
+#: ../web/statuspage.c:319
+msgid "Stop Refreshing"
+msgstr "自動更新ã®åœæ­¢"
+
+#: ../web/statuspage.c:334
+msgid "version:"
+msgstr "ãƒãƒ¼ã‚¸ãƒ§ãƒ³"
+
+#: ../web/statuspage.c:337
+msgid "smbd:"
+msgstr ""
+
+#: ../web/statuspage.c:337 ../web/statuspage.c:350 ../web/statuspage.c:364
+msgid "running"
+msgstr "実行中"
+
+#: ../web/statuspage.c:337 ../web/statuspage.c:350 ../web/statuspage.c:364
+msgid "not running"
+msgstr "åœæ­¢ä¸­"
+
+#: ../web/statuspage.c:341
+msgid "Stop smbd"
+msgstr "smbd ã®åœæ­¢"
+
+#: ../web/statuspage.c:343
+msgid "Start smbd"
+msgstr "smbd ã®èµ·å‹•"
+
+#: ../web/statuspage.c:345
+msgid "Restart smbd"
+msgstr "smbd ã®å†èµ·å‹•"
+
+#: ../web/statuspage.c:350
+msgid "nmbd:"
+msgstr ""
+
+#: ../web/statuspage.c:354
+msgid "Stop nmbd"
+msgstr "nmbd ã®åœæ­¢"
+
+#: ../web/statuspage.c:356
+msgid "Start nmbd"
+msgstr "nmbd ã®èµ·å‹•"
+
+#: ../web/statuspage.c:358
+msgid "Restart nmbd"
+msgstr "nmbd ã®å†èµ·å‹•"
+
+#: ../web/statuspage.c:364
+msgid "winbindd:"
+msgstr ""
+
+#: ../web/statuspage.c:368
+msgid "Stop winbindd"
+msgstr "winbindd ã®åœæ­¢"
+
+#: ../web/statuspage.c:370
+msgid "Start winbindd"
+msgstr "winbindd ã®èµ·å‹•"
+
+#: ../web/statuspage.c:372
+msgid "Restart winbindd"
+msgstr "winbindd ã®å†èµ·å‹•"
+
+#. stop, restart all
+#: ../web/statuspage.c:381
+msgid "Stop All"
+msgstr "ã™ã¹ã¦åœæ­¢"
+
+#: ../web/statuspage.c:382
+msgid "Restart All"
+msgstr "ã™ã¹ã¦å†èµ·å‹•"
+
+#. start all
+#: ../web/statuspage.c:386
+msgid "Start All"
+msgstr "ã™ã¹ã¦èµ·å‹•"
+
+#: ../web/statuspage.c:393
+msgid "Active Connections"
+msgstr "接続中ã®ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆ"
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408 ../web/statuspage.c:416
+msgid "PID"
+msgstr ""
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408
+msgid "Client"
+msgstr "クライアント"
+
+#: ../web/statuspage.c:395
+msgid "IP address"
+msgstr "IPアドレス"
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408 ../web/statuspage.c:416
+msgid "Date"
+msgstr "日付"
+
+#: ../web/statuspage.c:397
+msgid "Kill"
+msgstr "切断"
+
+#: ../web/statuspage.c:405
+msgid "Active Shares"
+msgstr "接続中ã®å…±æœ‰"
+
+#: ../web/statuspage.c:408
+msgid "Share"
+msgstr "共有å"
+
+#: ../web/statuspage.c:408
+msgid "User"
+msgstr "ユーザ"
+
+#: ../web/statuspage.c:408
+msgid "Group"
+msgstr "グループ"
+
+#: ../web/statuspage.c:414
+msgid "Open Files"
+msgstr "使用中ã®ãƒ•ã‚¡ã‚¤ãƒ«"
+
+#: ../web/statuspage.c:416
+msgid "Sharing"
+msgstr "排他モード"
+
+#: ../web/statuspage.c:416
+msgid "R/W"
+msgstr "å‚ç…§/æ›´æ–°"
+
+#: ../web/statuspage.c:416
+msgid "Oplock"
+msgstr ""
+
+#: ../web/statuspage.c:416
+msgid "File"
+msgstr "ファイルå"
+
+#: ../web/statuspage.c:425
+msgid "Show Client in col 1"
+msgstr "クライアントåを先頭ã«è¡¨ç¤º"
+
+#: ../web/statuspage.c:426
+msgid "Show PID in col 1"
+msgstr "PIDを先頭ã«è¡¨ç¤º"
+
+#: ../param/loadparm.c:755
+msgid "Base Options"
+msgstr "基本 オプション"
+
+#: ../param/loadparm.c:775
+msgid "Security Options"
+msgstr "セキュリティ オプション"
+
+#: ../param/loadparm.c:859
+msgid "Logging Options"
+msgstr "ロギング オプション"
+
+#: ../param/loadparm.c:874
+msgid "Protocol Options"
+msgstr "プロトコル オプション"
+
+#: ../param/loadparm.c:911
+msgid "Tuning Options"
+msgstr "ãƒãƒ¥ãƒ¼ãƒ‹ãƒ³ã‚° オプション"
+
+#: ../param/loadparm.c:940
+msgid "Printing Options"
+msgstr "å°åˆ· オプション"
+
+#: ../param/loadparm.c:970
+msgid "Filename Handling"
+msgstr "ファイルåã®å–扱"
+
+#: ../param/loadparm.c:996
+msgid "Domain Options"
+msgstr "ドメイン オプション"
+
+#: ../param/loadparm.c:1000
+msgid "Logon Options"
+msgstr "ログオン オプション"
+
+#: ../param/loadparm.c:1019
+msgid "Browse Options"
+msgstr "ブラウジング オプション"
+
+#: ../param/loadparm.c:1033
+msgid "WINS Options"
+msgstr "WINS オプション"
+
+#: ../param/loadparm.c:1043
+msgid "Locking Options"
+msgstr "ロッキング オプション"
+
+#: ../param/loadparm.c:1061
+msgid "Ldap Options"
+msgstr "LDAP オプション"
+
+#: ../param/loadparm.c:1078
+msgid "Miscellaneous Options"
+msgstr "ãã®ä»–ã®ã‚ªãƒ—ション"
+
+#: ../param/loadparm.c:1138
+msgid "VFS module options"
+msgstr "VFS オプション"
+
+#: ../param/loadparm.c:1148
+msgid "Winbind options"
+msgstr "Winbind オプション"
diff --git a/source3/po/nl.msg b/source3/po/nl.msg
new file mode 100644
index 0000000000..c0aae12617
--- /dev/null
+++ b/source3/po/nl.msg
@@ -0,0 +1,592 @@
+# Dutch messages for international release of SWAT.
+# Copyright (C) 2003 Jelmer Vernooij <jelmer@samba.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: i18n_swat \n"
+"POT-Creation-Date: 2003-10-06 05:30+0900\n"
+"PO-Revision-Date: 2000-02-08 12:48+09:00\n"
+"Last-Translator: Jelmer Vernooij <jelmer@samba.org>\n"
+"Language-Team: (Samba Team) <samba-technical@samba.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+
+#: ../web/swat.c:117
+#, c-format
+msgid "ERROR: Can't open %s"
+msgstr "FOUT: Kan %s niet openen"
+
+#: ../web/swat.c:200
+msgid "Help"
+msgstr "Help"
+
+#: ../web/swat.c:206 ../web/swat.c:220 ../web/swat.c:235 ../web/swat.c:243 ../web/swat.c:252 ../web/swat.c:261 ../web/swat.c:267 ../web/swat.c:273 ../web/swat.c:286
+msgid "Set Default"
+msgstr "Stel Standaard In"
+
+#: ../web/swat.c:408
+#, c-format
+msgid "failed to open %s for writing"
+msgstr "kon %s niet openen voor schrijven"
+
+#: ../web/swat.c:431
+#, c-format
+msgid "Can't reload %s"
+msgstr "Kan %s niet herladen"
+
+#: ../web/swat.c:501
+#, c-format
+msgid "Logged in as <b>%s</b>"
+msgstr "Ingelogd als <b>%s</b>"
+
+#: ../web/swat.c:505
+msgid "Home"
+msgstr "Home"
+
+#: ../web/swat.c:507
+msgid "Globals"
+msgstr "Algemene Instellingen"
+
+#: ../web/swat.c:508
+msgid "Shares"
+msgstr "Gedeelde Bronnen"
+
+#: ../web/swat.c:509
+msgid "Printers"
+msgstr "Printers"
+
+#: ../web/swat.c:510
+msgid "Wizard"
+msgstr "Wizard"
+
+#: ../web/swat.c:513
+msgid "Status"
+msgstr "Status"
+
+#: ../web/swat.c:514
+msgid "View Config"
+msgstr "Bekijk Configuratie"
+
+#: ../web/swat.c:516
+msgid "Password Management"
+msgstr "Wachtwoord Beheer"
+
+#: ../web/swat.c:526
+msgid "Current View Is"
+msgstr "Huidige weergave is"
+
+#: ../web/swat.c:527 ../web/swat.c:530
+msgid "Basic"
+msgstr "Basis"
+
+#: ../web/swat.c:528 ../web/swat.c:531
+msgid "Advanced"
+msgstr "Geadvanceerd"
+
+#: ../web/swat.c:529
+msgid "Change View To"
+msgstr "Verander Weergave In"
+
+#: ../web/swat.c:554
+msgid "Current Config"
+msgstr "Huidige Configuratie"
+
+#: ../web/swat.c:558
+msgid "Normal View"
+msgstr "Normale Weergave"
+
+#: ../web/swat.c:560
+msgid "Full View"
+msgstr "Volledige Weergave"
+
+#. Here we first set and commit all the parameters that were selected
+#. in the previous screen.
+#: ../web/swat.c:579
+msgid "Wizard Parameter Edit Page"
+msgstr "Wizard Instellingen Veranderen Pagina"
+
+#: ../web/swat.c:608
+msgid "Note: smb.conf file has been read and rewritten"
+msgstr "N.B.: het smb.conf bestand is gelezen en herschreven"
+
+#. Here we go ...
+#: ../web/swat.c:716
+msgid "Samba Configuration Wizard"
+msgstr "Samba Configuratie Wizard"
+
+#: ../web/swat.c:720
+msgid "The \"Rewrite smb.conf file\" button will clear the smb.conf file of all default values and of comments."
+msgstr "De \"Herschrijf smb.conf bestand\" knop zal alle standaardwaardes en alle commentaar verwijderen."
+
+#: ../web/swat.c:721
+msgid "The same will happen if you press the commit button."
+msgstr "Hetzelfde zal gebeuren als u de \"toepassen\" knop gebruikt."
+
+#: ../web/swat.c:724
+msgid "Rewrite smb.conf file"
+msgstr "Herschrijf smb.conf bestand"
+
+#: ../web/swat.c:725
+msgid "Commit"
+msgstr "Toepassen"
+
+#: ../web/swat.c:726
+msgid "Edit Parameter Values"
+msgstr "Bewerk Configuratie Waardes"
+
+#: ../web/swat.c:732
+msgid "Server Type"
+msgstr "Server Type"
+
+#: ../web/swat.c:733
+msgid "Stand Alone"
+msgstr "Stand Alone"
+
+#: ../web/swat.c:734
+msgid "Domain Member"
+msgstr "Domein Lid"
+
+#: ../web/swat.c:735
+msgid "Domain Controller"
+msgstr "Domein Controller"
+
+#: ../web/swat.c:738
+msgid "Unusual Type in smb.conf - Please Select New Mode"
+msgstr "Ongebruikelijk Type in smb.conf - Selecteer een nieuwe modus"
+
+#: ../web/swat.c:740
+msgid "Configure WINS As"
+msgstr "Configureer WINS Als"
+
+#: ../web/swat.c:741
+msgid "Not Used"
+msgstr "Niet gebruikt"
+
+#: ../web/swat.c:742
+msgid "Server for client use"
+msgstr "Server voor client gebruik"
+
+#: ../web/swat.c:743
+msgid "Client of another WINS server"
+msgstr "Client van een andere WINS server"
+
+#: ../web/swat.c:745
+msgid "Remote WINS Server"
+msgstr "Naam of IP-adres WINS Server"
+
+#: ../web/swat.c:756
+msgid "Error: WINS Server Mode and WINS Support both set in smb.conf"
+msgstr "Fout: WINS Server Modus en WINS Ondersteuning beiden ingesteld in smb.conf"
+
+#: ../web/swat.c:757
+msgid "Please Select desired WINS mode above."
+msgstr "Selecteer hierboven de gewenste WINS modus."
+
+#: ../web/swat.c:759
+msgid "Expose Home Directories"
+msgstr "Stel Home Directories Open"
+
+#: ../web/swat.c:774
+msgid "The above configuration options will set multiple parameters and will generally assist with rapid Samba deployment."
+msgstr "The configuratie hierboven zal meerdere variabelen veranderen en zal over het algemeen zorgen voor snelle installatie van Samba."
+
+#: ../web/swat.c:787
+msgid "Global Parameters"
+msgstr "Algemene Instellingen"
+
+#: ../web/swat.c:815 ../web/swat.c:916 ../web/swat.c:1265
+msgid "Commit Changes"
+msgstr "Pas Veranderingen Toe"
+
+#: ../web/swat.c:819 ../web/swat.c:919 ../web/swat.c:1267
+msgid "Reset Values"
+msgstr "Beginwaarden"
+
+#: ../web/swat.c:844
+msgid "Share Parameters"
+msgstr "Instellingen Gedeelde Bronnen"
+
+#: ../web/swat.c:887
+msgid "Choose Share"
+msgstr "Kies Bron"
+
+#: ../web/swat.c:901
+msgid "Delete Share"
+msgstr "Verwijder Bron"
+
+#: ../web/swat.c:908
+msgid "Create Share"
+msgstr "Maak Bron"
+
+#: ../web/swat.c:944
+msgid "password change in demo mode rejected"
+msgstr "wachtwoord veranderen in demo modus geweigerd"
+
+#: ../web/swat.c:957
+msgid "Can't setup password database vectors."
+msgstr "Kan wachtwoord database vectors niet opzetten."
+
+#: ../web/swat.c:983
+msgid " Must specify \"User Name\" "
+msgstr " \"Gebruikersnaam\" moet opgegeven worden "
+
+#: ../web/swat.c:999
+msgid " Must specify \"Old Password\" "
+msgstr " \"Oude wachtwoord\" moet opgegeven worden "
+
+#: ../web/swat.c:1005
+msgid " Must specify \"Remote Machine\" "
+msgstr " \"Server Naam of IP\" moet opgegeven worden "
+
+#: ../web/swat.c:1012
+msgid " Must specify \"New, and Re-typed Passwords\" "
+msgstr " \"Nieuw, en bevestiging Wachtwoorden\" moeten opgegeven worden "
+
+#: ../web/swat.c:1018
+msgid " Re-typed password didn't match new password "
+msgstr " Bevestigingswachtwoord was anders dan nieuwe wachtwoord "
+
+#: ../web/swat.c:1048
+#, c-format
+msgid " The passwd for '%s' has been changed."
+msgstr " Het wachtwoord voor '%s' is veranderd."
+
+#: ../web/swat.c:1051
+#, c-format
+msgid " The passwd for '%s' has NOT been changed."
+msgstr " Het wachtwoord voor '%s' is niet veranderd."
+
+#: ../web/swat.c:1076
+msgid "Server Password Management"
+msgstr "Server Wachtwoord Beheer"
+
+#.
+#. * Create all the dialog boxes for data collection
+#.
+#: ../web/swat.c:1085 ../web/swat.c:1132
+msgid "User Name"
+msgstr "Gebuikersnaam"
+
+#: ../web/swat.c:1088 ../web/swat.c:1134
+msgid "Old Password"
+msgstr "Oud Wachtwoord"
+
+#: ../web/swat.c:1091 ../web/swat.c:1136
+msgid "New Password"
+msgstr "Nieuw Wachtwoord"
+
+#: ../web/swat.c:1093 ../web/swat.c:1138
+msgid "Re-type New Password"
+msgstr "Bevestiging Nieuw Wachtwoord"
+
+#: ../web/swat.c:1101 ../web/swat.c:1149
+msgid "Change Password"
+msgstr "Verander Wachtwoord"
+
+#: ../web/swat.c:1104
+msgid "Add New User"
+msgstr "Voeg Gebruiker Toe"
+
+#: ../web/swat.c:1106
+msgid "Delete User"
+msgstr "Verwijder Gebruiker"
+
+#: ../web/swat.c:1108
+msgid "Disable User"
+msgstr "Maak gebruiker inactief"
+
+#: ../web/swat.c:1110
+msgid "Enable User"
+msgstr "Maak gebruiker actief"
+
+#: ../web/swat.c:1123
+msgid "Client/Server Password Management"
+msgstr "Client/Server Wachtwoord Beheer"
+
+#: ../web/swat.c:1140
+msgid "Remote Machine"
+msgstr "Naam of IP Server"
+
+#: ../web/swat.c:1179
+msgid "Printer Parameters"
+msgstr "Printer Instellingen"
+
+#: ../web/swat.c:1181
+msgid "Important Note:"
+msgstr "Belangrijk:"
+
+#: ../web/swat.c:1182
+msgid "Printer names marked with [*] in the Choose Printer drop-down box "
+msgstr "Printer namen gemarkeerd met [*] in het Kies Printer veld "
+
+#: ../web/swat.c:1183
+msgid "are autoloaded printers from "
+msgstr "zijn automatisch geladen uit "
+
+#: ../web/swat.c:1184
+msgid "Printcap Name"
+msgstr "Printcap Naam"
+
+#: ../web/swat.c:1185
+msgid "Attempting to delete these printers from SWAT will have no effect."
+msgstr "Proberen deze printers te verwijderen vanuit SWAT zal geen effect hebben."
+
+#: ../web/swat.c:1231
+msgid "Choose Printer"
+msgstr "Kies Printer"
+
+#: ../web/swat.c:1250
+msgid "Delete Printer"
+msgstr "Verwijder Printer"
+
+#: ../web/swat.c:1257
+msgid "Create Printer"
+msgstr "Maak Printer"
+
+#: ../web/statuspage.c:123
+msgid "RDONLY "
+msgstr "RDONLY"
+
+#: ../web/statuspage.c:124
+msgid "WRONLY "
+msgstr "WRONLY"
+
+#: ../web/statuspage.c:125
+msgid "RDWR "
+msgstr "RDWR"
+
+#: ../web/statuspage.c:309
+msgid "Server Status"
+msgstr "Server Status"
+
+#: ../web/statuspage.c:314
+msgid "Auto Refresh"
+msgstr "Automatisch Verversen"
+
+#: ../web/statuspage.c:315 ../web/statuspage.c:320
+msgid "Refresh Interval: "
+msgstr "Ververs Interval:"
+
+#: ../web/statuspage.c:319
+msgid "Stop Refreshing"
+msgstr "Stop met Verversen"
+
+#: ../web/statuspage.c:334
+msgid "version:"
+msgstr "versie:"
+
+#: ../web/statuspage.c:337
+msgid "smbd:"
+msgstr "smbd:"
+
+#: ../web/statuspage.c:337 ../web/statuspage.c:350 ../web/statuspage.c:364
+msgid "running"
+msgstr "draaiend"
+
+#: ../web/statuspage.c:337 ../web/statuspage.c:350 ../web/statuspage.c:364
+msgid "not running"
+msgstr "niet draaiend"
+
+#: ../web/statuspage.c:341
+msgid "Stop smbd"
+msgstr "Stop smbd"
+
+#: ../web/statuspage.c:343
+msgid "Start smbd"
+msgstr "Start smbd"
+
+#: ../web/statuspage.c:345
+msgid "Restart smbd"
+msgstr "Herstart smbd"
+
+#: ../web/statuspage.c:350
+msgid "nmbd:"
+msgstr "nmbd:"
+
+#: ../web/statuspage.c:354
+msgid "Stop nmbd"
+msgstr "Stop nmbd"
+
+#: ../web/statuspage.c:356
+msgid "Start nmbd"
+msgstr "Start nmbd"
+
+#: ../web/statuspage.c:358
+msgid "Restart nmbd"
+msgstr "Herstart nmbd"
+
+#: ../web/statuspage.c:364
+msgid "winbindd:"
+msgstr "winbindd:"
+
+#: ../web/statuspage.c:368
+msgid "Stop winbindd"
+msgstr "Stop winbindd"
+
+#: ../web/statuspage.c:370
+msgid "Start winbindd"
+msgstr "Start winbindd"
+
+#: ../web/statuspage.c:372
+msgid "Restart winbindd"
+msgstr "Herstart winbindd"
+
+#. stop, restart all
+#: ../web/statuspage.c:381
+msgid "Stop All"
+msgstr "Stop Alles"
+
+#: ../web/statuspage.c:382
+msgid "Restart All"
+msgstr "Herstart Alles"
+
+#. start all
+#: ../web/statuspage.c:386
+msgid "Start All"
+msgstr "Start Alles"
+
+#: ../web/statuspage.c:393
+msgid "Active Connections"
+msgstr "Actieve Verbindingen"
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408 ../web/statuspage.c:416
+msgid "PID"
+msgstr "PID"
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408
+msgid "Client"
+msgstr "Client"
+
+#: ../web/statuspage.c:395
+msgid "IP address"
+msgstr "IP adres"
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408 ../web/statuspage.c:416
+msgid "Date"
+msgstr "Datum"
+
+#: ../web/statuspage.c:397
+msgid "Kill"
+msgstr "Kill"
+
+#: ../web/statuspage.c:405
+msgid "Active Shares"
+msgstr "Actieve Bronnen"
+
+#: ../web/statuspage.c:408
+msgid "Share"
+msgstr "Bron"
+
+#: ../web/statuspage.c:408
+msgid "User"
+msgstr "Gebruiker"
+
+#: ../web/statuspage.c:408
+msgid "Group"
+msgstr "Groep"
+
+#: ../web/statuspage.c:414
+msgid "Open Files"
+msgstr "Geopende Bestanden"
+
+#: ../web/statuspage.c:416
+msgid "Sharing"
+msgstr "Gedeeld"
+
+#: ../web/statuspage.c:416
+msgid "R/W"
+msgstr "Lees/Schrijf"
+
+#: ../web/statuspage.c:416
+msgid "Oplock"
+msgstr "Oplock"
+
+#: ../web/statuspage.c:416
+msgid "File"
+msgstr "Bestand"
+
+#: ../web/statuspage.c:425
+msgid "Show Client in col 1"
+msgstr "Toon Client in kolom 1"
+
+#: ../web/statuspage.c:426
+msgid "Show PID in col 1"
+msgstr "Toon PID in kolom 1"
+
+#: ../param/loadparm.c:755
+msgid "Base Options"
+msgstr "Basis Opties"
+
+#: ../param/loadparm.c:775
+msgid "Security Options"
+msgstr "Veiligheidsopties"
+
+#: ../param/loadparm.c:859
+msgid "Logging Options"
+msgstr "Log Opties"
+
+#: ../param/loadparm.c:874
+msgid "Protocol Options"
+msgstr "Protocol Opties"
+
+#: ../param/loadparm.c:911
+msgid "Tuning Options"
+msgstr "Fijntune Opties"
+
+#: ../param/loadparm.c:940
+msgid "Printing Options"
+msgstr "Printer Opties"
+
+#: ../param/loadparm.c:970
+msgid "Filename Handling"
+msgstr "Bestandsnaam Afhandeling"
+
+#: ../param/loadparm.c:996
+msgid "Domain Options"
+msgstr "Domein Opties"
+
+#: ../param/loadparm.c:1000
+msgid "Logon Options"
+msgstr "Logon Opties"
+
+#: ../param/loadparm.c:1019
+msgid "Browse Options"
+msgstr "Verken Opties"
+
+#: ../param/loadparm.c:1033
+msgid "WINS Options"
+msgstr "WINS Opties"
+
+#: ../param/loadparm.c:1043
+msgid "Locking Options"
+msgstr "Locking Opties"
+
+#: ../param/loadparm.c:1061
+msgid "Ldap Options"
+msgstr "LDAP Opties"
+
+#: ../param/loadparm.c:1078
+msgid "Miscellaneous Options"
+msgstr "Verscheidene Opties"
+
+#: ../param/loadparm.c:1138
+msgid "VFS module options"
+msgstr "VFS module opties"
+
+#: ../param/loadparm.c:1148
+msgid "Winbind options"
+msgstr "Winbind opties"
diff --git a/source3/po/pl.msg b/source3/po/pl.msg
new file mode 100644
index 0000000000..aca5de6eb3
--- /dev/null
+++ b/source3/po/pl.msg
@@ -0,0 +1,592 @@
+# Polish messages for international release of SWAT.
+# Copyright (C) 2001 Rafal Szczesniak <mimir@spin.ict.pwr.wroc.pl>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: i18n_swat \n"
+"POT-Creation-Date: 2003-10-06 05:30+0900\n"
+"PO-Revision-Date: 2001-08-15 22:45+02:00\n"
+"Last-Translator: Rafal Szczesniak <mimir@spin.ict.pwr.wroc.pl>\n"
+"Language-Team: pl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+
+#: ../web/swat.c:117
+#, c-format
+msgid "ERROR: Can't open %s"
+msgstr ""
+
+#: ../web/swat.c:200
+msgid "Help"
+msgstr "Pomoc"
+
+#: ../web/swat.c:206 ../web/swat.c:220 ../web/swat.c:235 ../web/swat.c:243 ../web/swat.c:252 ../web/swat.c:261 ../web/swat.c:267 ../web/swat.c:273 ../web/swat.c:286
+msgid "Set Default"
+msgstr "Ustaw domyślnie"
+
+#: ../web/swat.c:408
+#, c-format
+msgid "failed to open %s for writing"
+msgstr ""
+
+#: ../web/swat.c:431
+#, c-format
+msgid "Can't reload %s"
+msgstr ""
+
+#: ../web/swat.c:501
+#, c-format
+msgid "Logged in as <b>%s</b>"
+msgstr "Zalogowany jako <b>%s</b><p>\n"
+
+#: ../web/swat.c:505
+msgid "Home"
+msgstr "Strona domowa"
+
+#: ../web/swat.c:507
+msgid "Globals"
+msgstr "Ustawienia globalne"
+
+#: ../web/swat.c:508
+msgid "Shares"
+msgstr "Współudziały"
+
+#: ../web/swat.c:509
+msgid "Printers"
+msgstr "Drukarki"
+
+#: ../web/swat.c:510
+msgid "Wizard"
+msgstr ""
+
+#: ../web/swat.c:513
+msgid "Status"
+msgstr "Status"
+
+#: ../web/swat.c:514
+msgid "View Config"
+msgstr "Przejrzyj KonfiguracjÄ™"
+
+#: ../web/swat.c:516
+msgid "Password Management"
+msgstr "Zarządzanie Hasłami"
+
+#: ../web/swat.c:526
+msgid "Current View Is"
+msgstr "Bieżąca Konfiguracja"
+
+#: ../web/swat.c:527 ../web/swat.c:530
+msgid "Basic"
+msgstr "Widok Podstawowy"
+
+#: ../web/swat.c:528 ../web/swat.c:531
+msgid "Advanced"
+msgstr "Widok Zaawansowany"
+
+#: ../web/swat.c:529
+msgid "Change View To"
+msgstr "Zmień Hasło"
+
+#: ../web/swat.c:554
+msgid "Current Config"
+msgstr "Bieżąca Konfiguracja"
+
+#: ../web/swat.c:558
+msgid "Normal View"
+msgstr "Normalny Widok"
+
+#: ../web/swat.c:560
+msgid "Full View"
+msgstr "Pełny Widok"
+
+#. Here we first set and commit all the parameters that were selected
+#. in the previous screen.
+#: ../web/swat.c:579
+msgid "Wizard Parameter Edit Page"
+msgstr ""
+
+#: ../web/swat.c:608
+msgid "Note: smb.conf file has been read and rewritten"
+msgstr ""
+
+#. Here we go ...
+#: ../web/swat.c:716
+msgid "Samba Configuration Wizard"
+msgstr ""
+
+#: ../web/swat.c:720
+msgid "The \"Rewrite smb.conf file\" button will clear the smb.conf file of all default values and of comments."
+msgstr ""
+
+#: ../web/swat.c:721
+msgid "The same will happen if you press the commit button."
+msgstr ""
+
+#: ../web/swat.c:724
+msgid "Rewrite smb.conf file"
+msgstr ""
+
+#: ../web/swat.c:725
+msgid "Commit"
+msgstr "Potwierdź Zmiany"
+
+#: ../web/swat.c:726
+msgid "Edit Parameter Values"
+msgstr "Parametry Drukarki"
+
+#: ../web/swat.c:732
+msgid "Server Type"
+msgstr ""
+
+#: ../web/swat.c:733
+msgid "Stand Alone"
+msgstr "Uruchom nmbd"
+
+#: ../web/swat.c:734
+msgid "Domain Member"
+msgstr ""
+
+#: ../web/swat.c:735
+msgid "Domain Controller"
+msgstr ""
+
+#: ../web/swat.c:738
+msgid "Unusual Type in smb.conf - Please Select New Mode"
+msgstr ""
+
+#: ../web/swat.c:740
+msgid "Configure WINS As"
+msgstr ""
+
+#: ../web/swat.c:741
+msgid "Not Used"
+msgstr ""
+
+#: ../web/swat.c:742
+msgid "Server for client use"
+msgstr ""
+
+#: ../web/swat.c:743
+msgid "Client of another WINS server"
+msgstr ""
+
+#: ../web/swat.c:745
+msgid "Remote WINS Server"
+msgstr ""
+
+#: ../web/swat.c:756
+msgid "Error: WINS Server Mode and WINS Support both set in smb.conf"
+msgstr ""
+
+#: ../web/swat.c:757
+msgid "Please Select desired WINS mode above."
+msgstr ""
+
+#: ../web/swat.c:759
+msgid "Expose Home Directories"
+msgstr ""
+
+#: ../web/swat.c:774
+msgid "The above configuration options will set multiple parameters and will generally assist with rapid Samba deployment."
+msgstr ""
+
+#: ../web/swat.c:787
+msgid "Global Parameters"
+msgstr "Zmienne Globalne"
+
+#: ../web/swat.c:815 ../web/swat.c:916 ../web/swat.c:1265
+msgid "Commit Changes"
+msgstr "Potwierdź Zmiany"
+
+#: ../web/swat.c:819 ../web/swat.c:919 ../web/swat.c:1267
+msgid "Reset Values"
+msgstr "Zresetuj Wartości"
+
+#: ../web/swat.c:844
+msgid "Share Parameters"
+msgstr "Parametry Współudziału"
+
+#: ../web/swat.c:887
+msgid "Choose Share"
+msgstr "Wybierz Współudział"
+
+#: ../web/swat.c:901
+msgid "Delete Share"
+msgstr "Usuń Współudział"
+
+#: ../web/swat.c:908
+msgid "Create Share"
+msgstr "Utwórz Współudział"
+
+#: ../web/swat.c:944
+msgid "password change in demo mode rejected"
+msgstr "zmiana hasła w trybie demo odrzucona\n"
+
+#: ../web/swat.c:957
+msgid "Can't setup password database vectors."
+msgstr ""
+
+#: ../web/swat.c:983
+msgid " Must specify \"User Name\" "
+msgstr " Musisz podać \"Nazwę Użytkownika\" \n"
+
+#: ../web/swat.c:999
+msgid " Must specify \"Old Password\" "
+msgstr " Musisz podać \"Stare Hasło\" \n"
+
+#: ../web/swat.c:1005
+msgid " Must specify \"Remote Machine\" "
+msgstr " Musisz podać \"Zdalną Maszynę\" \n"
+
+#: ../web/swat.c:1012
+msgid " Must specify \"New, and Re-typed Passwords\" "
+msgstr " Musisz podać \"Nowe Hasło, i ponownie wpisane Nowe Hasło\" \n"
+
+#: ../web/swat.c:1018
+msgid " Re-typed password didn't match new password "
+msgstr " Ponownie wpisane hasło nie pasuje do nowego hasła\n"
+
+#: ../web/swat.c:1048
+#, c-format
+msgid " The passwd for '%s' has been changed."
+msgstr " Hasło dla '%s' zostało zmienione. \n"
+
+#: ../web/swat.c:1051
+#, c-format
+msgid " The passwd for '%s' has NOT been changed."
+msgstr " Hasło dla '%s' NIE zostało zmienione. \n"
+
+#: ../web/swat.c:1076
+msgid "Server Password Management"
+msgstr "Zarządzanie Hasłami na Serwerze"
+
+#.
+#. * Create all the dialog boxes for data collection
+#.
+#: ../web/swat.c:1085 ../web/swat.c:1132
+msgid "User Name"
+msgstr " Nazwa Użytkownika"
+
+#: ../web/swat.c:1088 ../web/swat.c:1134
+msgid "Old Password"
+msgstr " Stare Hasło"
+
+#: ../web/swat.c:1091 ../web/swat.c:1136
+msgid "New Password"
+msgstr " Nowe Hasło"
+
+#: ../web/swat.c:1093 ../web/swat.c:1138
+msgid "Re-type New Password"
+msgstr " Ponownie wpisz Nowe Hasło"
+
+#: ../web/swat.c:1101 ../web/swat.c:1149
+msgid "Change Password"
+msgstr "Zmień Hasło"
+
+#: ../web/swat.c:1104
+msgid "Add New User"
+msgstr "Dodaj Nowego Użytkownika"
+
+#: ../web/swat.c:1106
+msgid "Delete User"
+msgstr "Usuń Użytkownika"
+
+#: ../web/swat.c:1108
+msgid "Disable User"
+msgstr "Zablokuj Użytkownika"
+
+#: ../web/swat.c:1110
+msgid "Enable User"
+msgstr "Odblokuj Użytkownika"
+
+#: ../web/swat.c:1123
+msgid "Client/Server Password Management"
+msgstr "Zarządzanie Hasłami Klient/Serwer"
+
+#: ../web/swat.c:1140
+msgid "Remote Machine"
+msgstr " Zdalna Maszyna"
+
+#: ../web/swat.c:1179
+msgid "Printer Parameters"
+msgstr "Parametry Drukarki"
+
+#: ../web/swat.c:1181
+msgid "Important Note:"
+msgstr "Ważna Informacja:"
+
+#: ../web/swat.c:1182
+msgid "Printer names marked with [*] in the Choose Printer drop-down box "
+msgstr "Nazwy Drukarek zaznaczone [*] w rozwijanym polu Wybierz DrukarkÄ™ "
+
+#: ../web/swat.c:1183
+msgid "are autoloaded printers from "
+msgstr "sÄ… drukarkami automatycznie Å‚adowanymi z "
+
+#: ../web/swat.c:1184
+msgid "Printcap Name"
+msgstr "Nazwa Printcap"
+
+#: ../web/swat.c:1185
+msgid "Attempting to delete these printers from SWAT will have no effect."
+msgstr "Próby usunięcia tych drukarek ze SWAT nie przyniosą efektu.\n"
+
+#: ../web/swat.c:1231
+msgid "Choose Printer"
+msgstr "Wybierz DrukarkÄ™"
+
+#: ../web/swat.c:1250
+msgid "Delete Printer"
+msgstr "Usuń Drukarkę"
+
+#: ../web/swat.c:1257
+msgid "Create Printer"
+msgstr "Utwórz Drukarkę"
+
+#: ../web/statuspage.c:123
+msgid "RDONLY "
+msgstr ""
+
+#: ../web/statuspage.c:124
+msgid "WRONLY "
+msgstr ""
+
+#: ../web/statuspage.c:125
+msgid "RDWR "
+msgstr ""
+
+#: ../web/statuspage.c:309
+msgid "Server Status"
+msgstr "Status Serwera"
+
+#: ../web/statuspage.c:314
+msgid "Auto Refresh"
+msgstr "Automatyczne Odświeżanie"
+
+#: ../web/statuspage.c:315 ../web/statuspage.c:320
+msgid "Refresh Interval: "
+msgstr "Interwał Odświeżania: "
+
+#: ../web/statuspage.c:319
+msgid "Stop Refreshing"
+msgstr "Zatrzymaj Odświeżanie"
+
+#: ../web/statuspage.c:334
+msgid "version:"
+msgstr "wersja:"
+
+#: ../web/statuspage.c:337
+msgid "smbd:"
+msgstr ""
+
+#: ../web/statuspage.c:337 ../web/statuspage.c:350 ../web/statuspage.c:364
+msgid "running"
+msgstr "działa"
+
+#: ../web/statuspage.c:337 ../web/statuspage.c:350 ../web/statuspage.c:364
+msgid "not running"
+msgstr "nie działa"
+
+#: ../web/statuspage.c:341
+msgid "Stop smbd"
+msgstr "Zatrzymaj smbd"
+
+#: ../web/statuspage.c:343
+msgid "Start smbd"
+msgstr "Uruchom smbd"
+
+#: ../web/statuspage.c:345
+msgid "Restart smbd"
+msgstr "Zrestartuj smbd"
+
+#: ../web/statuspage.c:350
+msgid "nmbd:"
+msgstr ""
+
+#: ../web/statuspage.c:354
+msgid "Stop nmbd"
+msgstr "Zatrzymaj nmbd"
+
+#: ../web/statuspage.c:356
+msgid "Start nmbd"
+msgstr "Uruchom nmbd"
+
+#: ../web/statuspage.c:358
+msgid "Restart nmbd"
+msgstr "Zrestartuj nmbd"
+
+#: ../web/statuspage.c:364
+msgid "winbindd:"
+msgstr ""
+
+#: ../web/statuspage.c:368
+msgid "Stop winbindd"
+msgstr "Zatrzymaj nmbd"
+
+#: ../web/statuspage.c:370
+msgid "Start winbindd"
+msgstr "Uruchom nmbd"
+
+#: ../web/statuspage.c:372
+msgid "Restart winbindd"
+msgstr "Zrestartuj nmbd"
+
+#. stop, restart all
+#: ../web/statuspage.c:381
+msgid "Stop All"
+msgstr ""
+
+#: ../web/statuspage.c:382
+msgid "Restart All"
+msgstr "Zrestartuj nmbd"
+
+#. start all
+#: ../web/statuspage.c:386
+msgid "Start All"
+msgstr "Uruchom nmbd"
+
+#: ../web/statuspage.c:393
+msgid "Active Connections"
+msgstr "Aktywne Połączenia"
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408 ../web/statuspage.c:416
+msgid "PID"
+msgstr ""
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408
+msgid "Client"
+msgstr "Klient"
+
+#: ../web/statuspage.c:395
+msgid "IP address"
+msgstr "adres IP"
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408 ../web/statuspage.c:416
+msgid "Date"
+msgstr "Data"
+
+#: ../web/statuspage.c:397
+msgid "Kill"
+msgstr "Zatrzymaj"
+
+#: ../web/statuspage.c:405
+msgid "Active Shares"
+msgstr "Aktywne Współudziały"
+
+#: ../web/statuspage.c:408
+msgid "Share"
+msgstr "Współudział"
+
+#: ../web/statuspage.c:408
+msgid "User"
+msgstr "Użytkownik"
+
+#: ../web/statuspage.c:408
+msgid "Group"
+msgstr "Grupa"
+
+#: ../web/statuspage.c:414
+msgid "Open Files"
+msgstr "Otwarte Pliki"
+
+#: ../web/statuspage.c:416
+msgid "Sharing"
+msgstr "Współdzielenie"
+
+#: ../web/statuspage.c:416
+msgid "R/W"
+msgstr ""
+
+#: ../web/statuspage.c:416
+msgid "Oplock"
+msgstr ""
+
+#: ../web/statuspage.c:416
+msgid "File"
+msgstr "Plik"
+
+#: ../web/statuspage.c:425
+msgid "Show Client in col 1"
+msgstr ""
+
+#: ../web/statuspage.c:426
+msgid "Show PID in col 1"
+msgstr ""
+
+#: ../param/loadparm.c:755
+msgid "Base Options"
+msgstr "Bazowe Opcje"
+
+#: ../param/loadparm.c:775
+msgid "Security Options"
+msgstr "Opcje Zabezpieczeń"
+
+#: ../param/loadparm.c:859
+msgid "Logging Options"
+msgstr "Opcje Blokowania"
+
+#: ../param/loadparm.c:874
+msgid "Protocol Options"
+msgstr "Opcje Protokołu"
+
+#: ../param/loadparm.c:911
+msgid "Tuning Options"
+msgstr "Opcje DostrajajÄ…ce"
+
+#: ../param/loadparm.c:940
+msgid "Printing Options"
+msgstr "Opcje Drukowania"
+
+#: ../param/loadparm.c:970
+msgid "Filename Handling"
+msgstr "Obsługa Nazw Plików"
+
+#: ../param/loadparm.c:996
+msgid "Domain Options"
+msgstr "Opcje Domeny"
+
+#: ../param/loadparm.c:1000
+msgid "Logon Options"
+msgstr "Opcje Logowania"
+
+#: ../param/loadparm.c:1019
+msgid "Browse Options"
+msgstr "Opcje PrzeglÄ…dania"
+
+#: ../param/loadparm.c:1033
+msgid "WINS Options"
+msgstr "Opcje WINS"
+
+#: ../param/loadparm.c:1043
+msgid "Locking Options"
+msgstr "Opcje Blokowania"
+
+#: ../param/loadparm.c:1061
+msgid "Ldap Options"
+msgstr "Opcje Ldap"
+
+#: ../param/loadparm.c:1078
+msgid "Miscellaneous Options"
+msgstr "Pozostałe Opcje"
+
+#: ../param/loadparm.c:1138
+msgid "VFS module options"
+msgstr "Opcje WINS"
+
+#: ../param/loadparm.c:1148
+msgid "Winbind options"
+msgstr "Opcje Drukowania"
diff --git a/source3/po/tr.msg b/source3/po/tr.msg
new file mode 100644
index 0000000000..03b489d033
--- /dev/null
+++ b/source3/po/tr.msg
@@ -0,0 +1,593 @@
+# Turkish messages for international release of SWAT.
+# Copyright (C) 2001 Deniz Akkus Kanca <deniz@arayan.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: i18n_swat \n"
+"POT-Creation-Date: 2003-10-06 05:30+0900\n"
+"PO-Revision-Date: 2001-09-20 22:51EEST\n"
+"Last-Translator: Deniz Akkus Kanca <deniz@arayan.com>\n"
+"Language-Team: Turkish <gnu-tr-u12a@lists.sourceforge.net>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 0.9.1\n"
+
+#: ../web/swat.c:117
+#, c-format
+msgid "ERROR: Can't open %s"
+msgstr ""
+
+#: ../web/swat.c:200
+msgid "Help"
+msgstr "Yardım"
+
+#: ../web/swat.c:206 ../web/swat.c:220 ../web/swat.c:235 ../web/swat.c:243 ../web/swat.c:252 ../web/swat.c:261 ../web/swat.c:267 ../web/swat.c:273 ../web/swat.c:286
+msgid "Set Default"
+msgstr "Öntanımlıya Ayarla"
+
+#: ../web/swat.c:408
+#, c-format
+msgid "failed to open %s for writing"
+msgstr ""
+
+#: ../web/swat.c:431
+#, c-format
+msgid "Can't reload %s"
+msgstr ""
+
+#: ../web/swat.c:501
+#, c-format
+msgid "Logged in as <b>%s</b>"
+msgstr "<b>%s</b> kimliği ile oturum açılmış"
+
+#: ../web/swat.c:505
+msgid "Home"
+msgstr "Ev"
+
+#: ../web/swat.c:507
+msgid "Globals"
+msgstr "Evrenseller"
+
+#: ../web/swat.c:508
+msgid "Shares"
+msgstr "Paylaşımlar"
+
+#: ../web/swat.c:509
+msgid "Printers"
+msgstr "Yazıcılar"
+
+#: ../web/swat.c:510
+msgid "Wizard"
+msgstr ""
+
+#: ../web/swat.c:513
+msgid "Status"
+msgstr "Durum"
+
+#: ../web/swat.c:514
+msgid "View Config"
+msgstr "Ayarlara Gözat"
+
+#: ../web/swat.c:516
+msgid "Password Management"
+msgstr "Şifre Yönetimi"
+
+#: ../web/swat.c:526
+msgid "Current View Is"
+msgstr "Åžimdiki Ayarlar"
+
+#: ../web/swat.c:527 ../web/swat.c:530
+msgid "Basic"
+msgstr "Temel Görünüm"
+
+#: ../web/swat.c:528 ../web/swat.c:531
+msgid "Advanced"
+msgstr "Gelişmiş Görünüm"
+
+#: ../web/swat.c:529
+msgid "Change View To"
+msgstr "Åžifre DeÄŸiÅŸtir"
+
+#: ../web/swat.c:554
+msgid "Current Config"
+msgstr "Åžimdiki Ayarlar"
+
+#: ../web/swat.c:558
+msgid "Normal View"
+msgstr "Normal Görünüm"
+
+#: ../web/swat.c:560
+msgid "Full View"
+msgstr "Tam Görünüm"
+
+#. Here we first set and commit all the parameters that were selected
+#. in the previous screen.
+#: ../web/swat.c:579
+msgid "Wizard Parameter Edit Page"
+msgstr ""
+
+#: ../web/swat.c:608
+msgid "Note: smb.conf file has been read and rewritten"
+msgstr ""
+
+#. Here we go ...
+#: ../web/swat.c:716
+msgid "Samba Configuration Wizard"
+msgstr ""
+
+#: ../web/swat.c:720
+msgid "The \"Rewrite smb.conf file\" button will clear the smb.conf file of all default values and of comments."
+msgstr ""
+
+#: ../web/swat.c:721
+msgid "The same will happen if you press the commit button."
+msgstr ""
+
+#: ../web/swat.c:724
+msgid "Rewrite smb.conf file"
+msgstr ""
+
+#: ../web/swat.c:725
+msgid "Commit"
+msgstr "açıklama"
+
+#: ../web/swat.c:726
+msgid "Edit Parameter Values"
+msgstr "Yazıcı Bilgileri"
+
+#: ../web/swat.c:732
+msgid "Server Type"
+msgstr ""
+
+#: ../web/swat.c:733
+msgid "Stand Alone"
+msgstr "Nmbd'yi çalıştır"
+
+#: ../web/swat.c:734
+msgid "Domain Member"
+msgstr "alan sunucusu"
+
+#: ../web/swat.c:735
+msgid "Domain Controller"
+msgstr "alan sunucusu"
+
+#: ../web/swat.c:738
+msgid "Unusual Type in smb.conf - Please Select New Mode"
+msgstr ""
+
+#: ../web/swat.c:740
+msgid "Configure WINS As"
+msgstr ""
+
+#: ../web/swat.c:741
+msgid "Not Used"
+msgstr "dont descend"
+
+#: ../web/swat.c:742
+msgid "Server for client use"
+msgstr ""
+
+#: ../web/swat.c:743
+msgid "Client of another WINS server"
+msgstr ""
+
+#: ../web/swat.c:745
+msgid "Remote WINS Server"
+msgstr ""
+
+#: ../web/swat.c:756
+msgid "Error: WINS Server Mode and WINS Support both set in smb.conf"
+msgstr ""
+
+#: ../web/swat.c:757
+msgid "Please Select desired WINS mode above."
+msgstr ""
+
+#: ../web/swat.c:759
+msgid "Expose Home Directories"
+msgstr ""
+
+#: ../web/swat.c:774
+msgid "The above configuration options will set multiple parameters and will generally assist with rapid Samba deployment."
+msgstr ""
+
+#: ../web/swat.c:787
+msgid "Global Parameters"
+msgstr "Genel DeÄŸiÅŸkenler"
+
+#: ../web/swat.c:815 ../web/swat.c:916 ../web/swat.c:1265
+msgid "Commit Changes"
+msgstr "DeÄŸiÅŸiklikleri Kaydet"
+
+#: ../web/swat.c:819 ../web/swat.c:919 ../web/swat.c:1267
+msgid "Reset Values"
+msgstr "DeÄŸerleri Ä°lk Haline Getir"
+
+#: ../web/swat.c:844
+msgid "Share Parameters"
+msgstr "Paylaşım Parametreleri"
+
+#: ../web/swat.c:887
+msgid "Choose Share"
+msgstr "Paylaşım Seçin"
+
+#: ../web/swat.c:901
+msgid "Delete Share"
+msgstr "Paylaşım Kaldır"
+
+#: ../web/swat.c:908
+msgid "Create Share"
+msgstr "Paylaşım Oluştur"
+
+#: ../web/swat.c:944
+msgid "password change in demo mode rejected"
+msgstr "demo kipinde ÅŸifre deÄŸiÅŸikliÄŸi kabul edilmedi\n"
+
+#: ../web/swat.c:957
+msgid "Can't setup password database vectors."
+msgstr ""
+
+#: ../web/swat.c:983
+msgid " Must specify \"User Name\" "
+msgstr " \"Kullanıcı Adı\" belirtilmeli \n"
+
+#: ../web/swat.c:999
+msgid " Must specify \"Old Password\" "
+msgstr " \"Eski Åžifre\" belirtilmeli \n"
+
+#: ../web/swat.c:1005
+msgid " Must specify \"Remote Machine\" "
+msgstr " \"Uzak Makina\" belirtilmeli \n"
+
+#: ../web/swat.c:1012
+msgid " Must specify \"New, and Re-typed Passwords\" "
+msgstr " \"Yeni ve Tekrar GirilmiÅŸ Åžifreler\" belirtilmeli \n"
+
+#: ../web/swat.c:1018
+msgid " Re-typed password didn't match new password "
+msgstr " Tekrar girilen ÅŸifre yeni ÅŸifre ile eÅŸleÅŸmedi\n"
+
+#: ../web/swat.c:1048
+#, c-format
+msgid " The passwd for '%s' has been changed."
+msgstr " '%s' için şifre değiştirildi."
+
+#: ../web/swat.c:1051
+#, c-format
+msgid " The passwd for '%s' has NOT been changed."
+msgstr " '%s' için şifre DEĞİŞTİRİLMEDİ."
+
+#: ../web/swat.c:1076
+msgid "Server Password Management"
+msgstr "Sunucu Şifre Yönetimi"
+
+#.
+#. * Create all the dialog boxes for data collection
+#.
+#: ../web/swat.c:1085 ../web/swat.c:1132
+msgid "User Name"
+msgstr " Kullanıcı Adı"
+
+#: ../web/swat.c:1088 ../web/swat.c:1134
+msgid "Old Password"
+msgstr " Eski Åžifre"
+
+#: ../web/swat.c:1091 ../web/swat.c:1136
+msgid "New Password"
+msgstr " Yeni Åžifre"
+
+#: ../web/swat.c:1093 ../web/swat.c:1138
+msgid "Re-type New Password"
+msgstr " Yeni Şifre Tekrarı"
+
+#: ../web/swat.c:1101 ../web/swat.c:1149
+msgid "Change Password"
+msgstr "Åžifre DeÄŸiÅŸtir"
+
+#: ../web/swat.c:1104
+msgid "Add New User"
+msgstr "Kull. Ekle"
+
+#: ../web/swat.c:1106
+msgid "Delete User"
+msgstr "Kull. Sil"
+
+#: ../web/swat.c:1108
+msgid "Disable User"
+msgstr "Kull. EtkisizleÅŸtir"
+
+#: ../web/swat.c:1110
+msgid "Enable User"
+msgstr "Kull. EtkinleÅŸtir"
+
+#: ../web/swat.c:1123
+msgid "Client/Server Password Management"
+msgstr "İstemci/Sunucu Şifre Yönetimi"
+
+#: ../web/swat.c:1140
+msgid "Remote Machine"
+msgstr " Uzak Makina"
+
+#: ../web/swat.c:1179
+msgid "Printer Parameters"
+msgstr "Yazıcı Bilgileri"
+
+#: ../web/swat.c:1181
+msgid "Important Note:"
+msgstr "Önemli Not:"
+
+#: ../web/swat.c:1182
+msgid "Printer names marked with [*] in the Choose Printer drop-down box "
+msgstr "Yazıcı Seç kutusunda [*] ile işaretlenmiş yazıcı isimleri "
+
+#: ../web/swat.c:1183
+msgid "are autoloaded printers from "
+msgstr "otomatik yüklenen yazıcılar "
+
+#: ../web/swat.c:1184
+msgid "Printcap Name"
+msgstr "Printcap Adı"
+
+#: ../web/swat.c:1185
+msgid "Attempting to delete these printers from SWAT will have no effect."
+msgstr "Bu yazıcıları SWAT'dan silmek etkisiz olacaktır.\n"
+
+#: ../web/swat.c:1231
+msgid "Choose Printer"
+msgstr "Yazıcı Seç"
+
+#: ../web/swat.c:1250
+msgid "Delete Printer"
+msgstr "Yazıcı Sil"
+
+#: ../web/swat.c:1257
+msgid "Create Printer"
+msgstr "Yazıcı Oluştur"
+
+#: ../web/statuspage.c:123
+msgid "RDONLY "
+msgstr "SALTOKUNUR "
+
+#: ../web/statuspage.c:124
+msgid "WRONLY "
+msgstr "SALTYAZILIR "
+
+#: ../web/statuspage.c:125
+msgid "RDWR "
+msgstr "O/Y "
+
+#: ../web/statuspage.c:309
+msgid "Server Status"
+msgstr "Sunucu Durumu"
+
+#: ../web/statuspage.c:314
+msgid "Auto Refresh"
+msgstr "Oto Tazele"
+
+#: ../web/statuspage.c:315 ../web/statuspage.c:320
+msgid "Refresh Interval: "
+msgstr "Tazeleme Aralığı: "
+
+#: ../web/statuspage.c:319
+msgid "Stop Refreshing"
+msgstr "Tazelemeyi Durdur"
+
+#: ../web/statuspage.c:334
+msgid "version:"
+msgstr "sürüm:"
+
+#: ../web/statuspage.c:337
+msgid "smbd:"
+msgstr "smbd:"
+
+#: ../web/statuspage.c:337 ../web/statuspage.c:350 ../web/statuspage.c:364
+msgid "running"
+msgstr "çalışıyor"
+
+#: ../web/statuspage.c:337 ../web/statuspage.c:350 ../web/statuspage.c:364
+msgid "not running"
+msgstr "çalışmıyor"
+
+#: ../web/statuspage.c:341
+msgid "Stop smbd"
+msgstr "Smbd'yi durdur"
+
+#: ../web/statuspage.c:343
+msgid "Start smbd"
+msgstr "Smbd'yi çalıştır"
+
+#: ../web/statuspage.c:345
+msgid "Restart smbd"
+msgstr "Smbd'yi yeniden çalıştır"
+
+#: ../web/statuspage.c:350
+msgid "nmbd:"
+msgstr "nmbd:"
+
+#: ../web/statuspage.c:354
+msgid "Stop nmbd"
+msgstr "Nmbd'yi durdur"
+
+#: ../web/statuspage.c:356
+msgid "Start nmbd"
+msgstr "Nmbd'yi çalıştır"
+
+#: ../web/statuspage.c:358
+msgid "Restart nmbd"
+msgstr "Nmbd'yi yeniden çalıştır"
+
+#: ../web/statuspage.c:364
+msgid "winbindd:"
+msgstr "winbind uid"
+
+#: ../web/statuspage.c:368
+msgid "Stop winbindd"
+msgstr "Nmbd'yi durdur"
+
+#: ../web/statuspage.c:370
+msgid "Start winbindd"
+msgstr "Nmbd'yi çalıştır"
+
+#: ../web/statuspage.c:372
+msgid "Restart winbindd"
+msgstr "Nmbd'yi yeniden çalıştır"
+
+#. stop, restart all
+#: ../web/statuspage.c:381
+msgid "Stop All"
+msgstr ""
+
+#: ../web/statuspage.c:382
+msgid "Restart All"
+msgstr "Nmbd'yi yeniden çalıştır"
+
+#. start all
+#: ../web/statuspage.c:386
+msgid "Start All"
+msgstr "Nmbd'yi çalıştır"
+
+#: ../web/statuspage.c:393
+msgid "Active Connections"
+msgstr "Aktif Bağlantılar"
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408 ../web/statuspage.c:416
+msgid "PID"
+msgstr "PID"
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408
+msgid "Client"
+msgstr "Ä°stemci"
+
+#: ../web/statuspage.c:395
+msgid "IP address"
+msgstr "IP numarası"
+
+#: ../web/statuspage.c:395 ../web/statuspage.c:408 ../web/statuspage.c:416
+msgid "Date"
+msgstr "Tarih"
+
+#: ../web/statuspage.c:397
+msgid "Kill"
+msgstr "Kapat"
+
+#: ../web/statuspage.c:405
+msgid "Active Shares"
+msgstr "Aktif Paylaşımlar"
+
+#: ../web/statuspage.c:408
+msgid "Share"
+msgstr "Paylaşım"
+
+#: ../web/statuspage.c:408
+msgid "User"
+msgstr "Kullanıcı"
+
+#: ../web/statuspage.c:408
+msgid "Group"
+msgstr "Grup"
+
+#: ../web/statuspage.c:414
+msgid "Open Files"
+msgstr "Açık Dosyalar"
+
+#: ../web/statuspage.c:416
+msgid "Sharing"
+msgstr "Paylaşılıyor"
+
+#: ../web/statuspage.c:416
+msgid "R/W"
+msgstr "O/Y"
+
+#: ../web/statuspage.c:416
+msgid "Oplock"
+msgstr "Oplock"
+
+#: ../web/statuspage.c:416
+msgid "File"
+msgstr "Dosya"
+
+#: ../web/statuspage.c:425
+msgid "Show Client in col 1"
+msgstr ""
+
+#: ../web/statuspage.c:426
+msgid "Show PID in col 1"
+msgstr ""
+
+#: ../param/loadparm.c:755
+msgid "Base Options"
+msgstr "Temel Seçenekler"
+
+#: ../param/loadparm.c:775
+msgid "Security Options"
+msgstr "Güvenlik Seçenekleri"
+
+#: ../param/loadparm.c:859
+msgid "Logging Options"
+msgstr "Günlük Kaydı Seçenekleri"
+
+#: ../param/loadparm.c:874
+msgid "Protocol Options"
+msgstr "Protokol Seçenekleri"
+
+#: ../param/loadparm.c:911
+msgid "Tuning Options"
+msgstr "Ayar Seçenekleri"
+
+#: ../param/loadparm.c:940
+msgid "Printing Options"
+msgstr "Yazdırma Seçenekleri"
+
+#: ../param/loadparm.c:970
+msgid "Filename Handling"
+msgstr "Dosyaadı İşlenmesi"
+
+#: ../param/loadparm.c:996
+msgid "Domain Options"
+msgstr "Alan Seçenekleri"
+
+#: ../param/loadparm.c:1000
+msgid "Logon Options"
+msgstr "Sistem Giriş Seçenekleri"
+
+#: ../param/loadparm.c:1019
+msgid "Browse Options"
+msgstr "Gözatma Seçenekleri"
+
+#: ../param/loadparm.c:1033
+msgid "WINS Options"
+msgstr "WINS Seçenekleri"
+
+#: ../param/loadparm.c:1043
+msgid "Locking Options"
+msgstr "Kilitleme Seçenekleri"
+
+#: ../param/loadparm.c:1061
+msgid "Ldap Options"
+msgstr "Ldap Seçenekleri"
+
+#: ../param/loadparm.c:1078
+msgid "Miscellaneous Options"
+msgstr "Diğer Seçenekler"
+
+#: ../param/loadparm.c:1138
+msgid "VFS module options"
+msgstr "VFS Seçenekleri"
+
+#: ../param/loadparm.c:1148
+msgid "Winbind options"
+msgstr "Winbind seçenekleri"
diff --git a/source3/popt/CHANGES b/source3/popt/CHANGES
new file mode 100644
index 0000000000..db16a5fdd0
--- /dev/null
+++ b/source3/popt/CHANGES
@@ -0,0 +1,46 @@
+1.5 -> 1.6
+ - add ability to perform callbacks for every, not just first, match.
+
+1.3 -> 1.5
+ - heavy dose of const's
+ - poptParseArgvString() now NULL terminates the list
+
+1.2.3 -> 1.3
+ - added support for single -
+ - misc bug fixes
+ - portability improvements
+
+1.2.2 -> 1.2.3
+ - fixed memset() in help message generation (Dale Hawkins)
+ - added extern "C" stuff to popt.h for C++ compilers (Dale Hawkins)
+ - const'ified poptParseArgvString (Jeff Garzik)
+
+1.2.1 -> 1.2.2
+ - fixed bug in chaind alias happens which seems to have only
+ affected --triggers in rpm
+ - added POPT_ARG_VAL
+ - popt.3 installed by default
+
+1.2 -> 1.2.1
+ - added POPT_ARG_INTL_DOMAIN (Elliot Lee)
+ - updated Makefile's to be more GNUish (Elliot Lee)
+
+1.1 -> 1.2
+ - added popt.3 man page (Robert Lynch)
+ - don't use mmap anymore (its lack of portability isn't worth the
+ trouble)
+ - added test script
+ - added support for exec
+ - removed support for *_POPT_ALIASES env variable -- it was a bad
+ idea
+ - reorganized into multiple source files
+ - added automatic help generation, POPT_AUTOHELP
+ - added table callbacks
+ - added table inclusion
+ - updated man page for new features
+ - added test scripts
+
+1.0 -> 1.1
+ - moved to autoconf (Fred Fish)
+ - added STRERROR replacement (Norbert Warmuth)
+ - added const keywords (Bruce Perens)
diff --git a/source3/popt/COPYING b/source3/popt/COPYING
new file mode 100644
index 0000000000..b4c7ca876c
--- /dev/null
+++ b/source3/popt/COPYING
@@ -0,0 +1,22 @@
+Copyright (c) 1998 Red Hat Software
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
diff --git a/source3/popt/README b/source3/popt/README
new file mode 100644
index 0000000000..0b5205bfdd
--- /dev/null
+++ b/source3/popt/README
@@ -0,0 +1,18 @@
+This is the popt command line option parsing library. While it is similiar
+to getopt(3), it contains a number of enhancements, including:
+
+ 1) popt is fully reentrant
+ 2) popt can parse arbitrary argv[] style arrays while
+ getopt(2) makes this quite difficult
+ 3) popt allows users to alias command line arguments
+ 4) popt provides convience functions for parsing strings
+ into argv[] style arrays
+
+popt is used by rpm, the Red Hat install program, and many other Red Hat
+utilities, all of which provide excellent examples of how to use popt.
+Complete documentation on popt is available in popt.ps (included in this
+tarball), which is excerpted with permission from the book "Linux
+Application Development" by Michael K. Johnson and Erik Troan (availble
+from Addison Wesley in May, 1998).
+
+Comments on popt should be addressed to ewt@redhat.com.
diff --git a/source3/popt/dummy.in b/source3/popt/dummy.in
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/source3/popt/dummy.in
diff --git a/source3/popt/findme.c b/source3/popt/findme.c
new file mode 100644
index 0000000000..b28981ba1f
--- /dev/null
+++ b/source3/popt/findme.c
@@ -0,0 +1,50 @@
+/** \ingroup popt
+ * \file popt/findme.c
+ */
+
+/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
+ file accompanying popt source distributions, available from
+ ftp://ftp.rpm.org/pub/rpm/dist. */
+
+#include "system.h"
+#include "findme.h"
+
+const char * findProgramPath(const char * argv0) {
+ char * path = getenv("PATH");
+ char * pathbuf;
+ char * start, * chptr;
+ char * buf;
+
+ if (argv0 == NULL) return NULL; /* XXX can't happen */
+ /* If there is a / in the argv[0], it has to be an absolute path */
+ if (strchr(argv0, '/'))
+ return xstrdup(argv0);
+
+ if (path == NULL) return NULL;
+
+ start = pathbuf = (char *)alloca(strlen(path) + 1);
+ buf = (char *)malloc(strlen(path) + strlen(argv0) + sizeof("/"));
+ if (buf == NULL) return NULL; /* XXX can't happen */
+ strcpy(pathbuf, path);
+
+ chptr = NULL;
+ /*@-branchstate@*/
+ do {
+ if ((chptr = strchr(start, ':')))
+ *chptr = '\0';
+ sprintf(buf, "%s/%s", start, argv0);
+
+ if (!access(buf, X_OK))
+ return buf;
+
+ if (chptr)
+ start = chptr + 1;
+ else
+ start = NULL;
+ } while (start && *start);
+ /*@=branchstate@*/
+
+ free(buf);
+
+ return NULL;
+}
diff --git a/source3/popt/findme.h b/source3/popt/findme.h
new file mode 100644
index 0000000000..a016b867ea
--- /dev/null
+++ b/source3/popt/findme.h
@@ -0,0 +1,20 @@
+/** \ingroup popt
+ * \file popt/findme.h
+ */
+
+/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
+ file accompanying popt source distributions, available from
+ ftp://ftp.rpm.org/pub/rpm/dist. */
+
+#ifndef H_FINDME
+#define H_FINDME
+
+/**
+ * Return absolute path to executable by searching PATH.
+ * @param argv0 name of executable
+ * @return (malloc'd) absolute path to executable (or NULL)
+ */
+/*@null@*/ const char * findProgramPath(/*@null@*/ const char * argv0)
+ /*@*/;
+
+#endif
diff --git a/source3/popt/popt.c b/source3/popt/popt.c
new file mode 100644
index 0000000000..d9e8411b9f
--- /dev/null
+++ b/source3/popt/popt.c
@@ -0,0 +1,1249 @@
+/** \ingroup popt
+ * \file popt/popt.c
+ */
+
+/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
+ file accompanying popt source distributions, available from
+ ftp://ftp.rpm.org/pub/rpm/dist */
+
+#undef MYDEBUG
+
+#include "system.h"
+
+#if HAVE_FLOAT_H
+#include <float.h>
+#endif
+#include <math.h>
+
+#include "findme.h"
+#include "poptint.h"
+
+#ifdef MYDEBUG
+/*@unchecked@*/
+int _popt_debug = 0;
+#endif
+
+#ifndef HAVE_STRERROR
+static char * strerror(int errno) {
+ extern int sys_nerr;
+ extern char * sys_errlist[];
+
+ if ((0 <= errno) && (errno < sys_nerr))
+ return sys_errlist[errno];
+ else
+ return POPT_("unknown errno");
+}
+#endif
+
+#ifdef MYDEBUG
+/*@unused@*/ static void prtcon(const char *msg, poptContext con)
+{
+ if (msg) fprintf(stderr, "%s", msg);
+ fprintf(stderr, "\tcon %p os %p nextCharArg \"%s\" nextArg \"%s\" argv[%d] \"%s\"\n",
+ con, con->os,
+ (con->os->nextCharArg ? con->os->nextCharArg : ""),
+ (con->os->nextArg ? con->os->nextArg : ""),
+ con->os->next,
+ (con->os->argv && con->os->argv[con->os->next]
+ ? con->os->argv[con->os->next] : ""));
+}
+#endif
+
+void poptSetExecPath(poptContext con, const char * path, int allowAbsolute)
+{
+ con->execPath = (const char *)_free(con->execPath);
+ con->execPath = xstrdup(path);
+ con->execAbsolute = allowAbsolute;
+ /*@-nullstate@*/ /* LCL: con->execPath can be NULL? */
+ return;
+ /*@=nullstate@*/
+}
+
+static void invokeCallbacksPRE(poptContext con, const struct poptOption * opt)
+ /*@globals internalState@*/
+ /*@modifies internalState@*/
+{
+ if (opt != NULL)
+ for (; opt->longName || opt->shortName || opt->arg; opt++) {
+ if (opt->arg == NULL) continue; /* XXX program error. */
+ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
+ /* Recurse on included sub-tables. */
+ invokeCallbacksPRE(con, (const struct poptOption *)opt->arg);
+ } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK &&
+ (opt->argInfo & POPT_CBFLAG_PRE))
+ { /*@-castfcnptr@*/
+ poptCallbackType cb = (poptCallbackType)opt->arg;
+ /*@=castfcnptr@*/
+ /* Perform callback. */
+ /*@-moduncon -noeffectuncon @*/
+ cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip);
+ /*@=moduncon =noeffectuncon @*/
+ }
+ }
+}
+
+static void invokeCallbacksPOST(poptContext con, const struct poptOption * opt)
+ /*@globals internalState@*/
+ /*@modifies internalState@*/
+{
+ if (opt != NULL)
+ for (; opt->longName || opt->shortName || opt->arg; opt++) {
+ if (opt->arg == NULL) continue; /* XXX program error. */
+ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
+ /* Recurse on included sub-tables. */
+ invokeCallbacksPOST(con, (const struct poptOption *)opt->arg);
+ } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK &&
+ (opt->argInfo & POPT_CBFLAG_POST))
+ { /*@-castfcnptr@*/
+ poptCallbackType cb = (poptCallbackType)opt->arg;
+ /*@=castfcnptr@*/
+ /* Perform callback. */
+ /*@-moduncon -noeffectuncon @*/
+ cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip);
+ /*@=moduncon =noeffectuncon @*/
+ }
+ }
+}
+
+static void invokeCallbacksOPTION(poptContext con,
+ const struct poptOption * opt,
+ const struct poptOption * myOpt,
+ /*@null@*/ const void * myData, int shorty)
+ /*@globals internalState@*/
+ /*@modifies internalState@*/
+{
+ const struct poptOption * cbopt = NULL;
+
+ if (opt != NULL)
+ for (; opt->longName || opt->shortName || opt->arg; opt++) {
+ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
+ /* Recurse on included sub-tables. */
+ if (opt->arg != NULL) /* XXX program error */
+ invokeCallbacksOPTION(con, (const struct poptOption *)opt->arg,
+ myOpt, myData, shorty);
+ } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK &&
+ !(opt->argInfo & POPT_CBFLAG_SKIPOPTION)) {
+ /* Save callback info. */
+ cbopt = opt;
+ } else if (cbopt != NULL &&
+ ((myOpt->shortName && opt->shortName && shorty &&
+ myOpt->shortName == opt->shortName) ||
+ (myOpt->longName && opt->longName &&
+ /*@-nullpass@*/ /* LCL: opt->longName != NULL */
+ !strcmp(myOpt->longName, opt->longName)))
+ /*@=nullpass@*/
+ )
+ { /*@-castfcnptr@*/
+ poptCallbackType cb = (poptCallbackType)cbopt->arg;
+ /*@=castfcnptr@*/
+ const void * cbData = (cbopt->descrip ? cbopt->descrip : myData);
+ /* Perform callback. */
+ if (cb != NULL) { /* XXX program error */
+ /*@-moduncon -noeffectuncon @*/
+ cb(con, POPT_CALLBACK_REASON_OPTION, myOpt,
+ con->os->nextArg, cbData);
+ /*@=moduncon =noeffectuncon @*/
+ }
+ /* Terminate (unless explcitly continuing). */
+ if (!(cbopt->argInfo & POPT_CBFLAG_CONTINUE))
+ return;
+ }
+ }
+}
+
+poptContext poptGetContext(const char * name, int argc, const char ** argv,
+ const struct poptOption * options, int flags)
+{
+ poptContext con = (poptContext)malloc(sizeof(*con));
+
+ if (con == NULL) return NULL; /* XXX can't happen */
+ memset(con, 0, sizeof(*con));
+
+ con->os = con->optionStack;
+ con->os->argc = argc;
+ /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */
+ con->os->argv = argv;
+ /*@=dependenttrans =assignexpose@*/
+ con->os->argb = NULL;
+
+ if (!(flags & POPT_CONTEXT_KEEP_FIRST))
+ con->os->next = 1; /* skip argv[0] */
+
+ con->leftovers = (const char **)calloc( (argc + 1),
+ sizeof(*con->leftovers) );
+ /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */
+ con->options = options;
+ /*@=dependenttrans =assignexpose@*/
+ con->aliases = NULL;
+ con->numAliases = 0;
+ con->flags = flags;
+ con->execs = NULL;
+ con->numExecs = 0;
+ con->finalArgvAlloced = argc * 2;
+ con->finalArgv = (const char **)calloc( con->finalArgvAlloced,
+ sizeof(*con->finalArgv) );
+ con->execAbsolute = 1;
+ con->arg_strip = NULL;
+
+ if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
+ con->flags |= POPT_CONTEXT_POSIXMEHARDER;
+
+ if (name) {
+ char * t = (char *)malloc(strlen(name) + 1);
+ if (t) con->appName = strcpy(t, name);
+ }
+
+ /*@-internalglobs@*/
+ invokeCallbacksPRE(con, con->options);
+ /*@=internalglobs@*/
+
+ return con;
+}
+
+static void cleanOSE(/*@special@*/ struct optionStackEntry *os)
+ /*@uses os @*/
+ /*@releases os->nextArg, os->argv, os->argb @*/
+ /*@modifies os @*/
+{
+ os->nextArg = (const char *)_free(os->nextArg);
+ os->argv = (const char **)_free(os->argv);
+ os->argb = (pbm_set *)PBM_FREE(os->argb);
+}
+
+/*@-boundswrite@*/
+void poptResetContext(poptContext con)
+{
+ int i;
+
+ if (con == NULL) return;
+ while (con->os > con->optionStack) {
+ cleanOSE(con->os--);
+ }
+ con->os->argb = (pbm_set *)PBM_FREE(con->os->argb);
+ con->os->currAlias = NULL;
+ con->os->nextCharArg = NULL;
+ con->os->nextArg = NULL;
+ con->os->next = 1; /* skip argv[0] */
+
+ con->numLeftovers = 0;
+ con->nextLeftover = 0;
+ con->restLeftover = 0;
+ con->doExec = NULL;
+
+ if (con->finalArgv != NULL)
+ for (i = 0; i < con->finalArgvCount; i++) {
+ /*@-unqualifiedtrans@*/ /* FIX: typedef double indirection. */
+ con->finalArgv[i] = (const char *)_free(con->finalArgv[i]);
+ /*@=unqualifiedtrans@*/
+ }
+
+ con->finalArgvCount = 0;
+ con->arg_strip = ( pbm_set *)PBM_FREE(con->arg_strip);
+ /*@-nullstate@*/ /* FIX: con->finalArgv != NULL */
+ return;
+ /*@=nullstate@*/
+}
+/*@=boundswrite@*/
+
+/* Only one of longName, shortName should be set, not both. */
+/*@-boundswrite@*/
+static int handleExec(/*@special@*/ poptContext con,
+ /*@null@*/ const char * longName, char shortName)
+ /*@uses con->execs, con->numExecs, con->flags, con->doExec,
+ con->finalArgv, con->finalArgvAlloced, con->finalArgvCount @*/
+ /*@modifies con @*/
+{
+ poptItem item;
+ int i;
+
+ if (con->execs == NULL || con->numExecs <= 0) /* XXX can't happen */
+ return 0;
+
+ for (i = con->numExecs - 1; i >= 0; i--) {
+ item = con->execs + i;
+ if (longName && !(item->option.longName &&
+ !strcmp(longName, item->option.longName)))
+ continue;
+ else if (shortName != item->option.shortName)
+ continue;
+ break;
+ }
+ if (i < 0) return 0;
+
+
+ if (con->flags & POPT_CONTEXT_NO_EXEC)
+ return 1;
+
+ if (con->doExec == NULL) {
+ con->doExec = con->execs + i;
+ return 1;
+ }
+
+ /* We already have an exec to do; remember this option for next
+ time 'round */
+ if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) {
+ con->finalArgvAlloced += 10;
+ con->finalArgv = (const char **)realloc(con->finalArgv,
+ sizeof(*con->finalArgv) * con->finalArgvAlloced);
+ }
+
+ i = con->finalArgvCount++;
+ if (con->finalArgv != NULL) /* XXX can't happen */
+ { char *s = (char *)malloc((longName ? strlen(longName) : 0) + 3);
+ if (s != NULL) { /* XXX can't happen */
+ if (longName)
+ sprintf(s, "--%s", longName);
+ else
+ sprintf(s, "-%c", shortName);
+ con->finalArgv[i] = s;
+ } else
+ con->finalArgv[i] = NULL;
+ }
+
+ /*@-nullstate@*/ /* FIX: con->finalArgv[] == NULL */
+ return 1;
+ /*@=nullstate@*/
+}
+/*@=boundswrite@*/
+
+/* Only one of longName, shortName may be set at a time */
+static int handleAlias(/*@special@*/ poptContext con,
+ /*@null@*/ const char * longName, char shortName,
+ /*@exposed@*/ /*@null@*/ const char * nextCharArg)
+ /*@uses con->aliases, con->numAliases, con->optionStack, con->os,
+ con->os->currAlias, con->os->currAlias->option.longName @*/
+ /*@modifies con @*/
+{
+ poptItem item = con->os->currAlias;
+ int rc;
+ int i;
+
+ if (item) {
+ if (longName && (item->option.longName &&
+ !strcmp(longName, item->option.longName)))
+ return 0;
+ if (shortName && shortName == item->option.shortName)
+ return 0;
+ }
+
+ if (con->aliases == NULL || con->numAliases <= 0) /* XXX can't happen */
+ return 0;
+
+ for (i = con->numAliases - 1; i >= 0; i--) {
+ item = con->aliases + i;
+ if (longName && !(item->option.longName &&
+ !strcmp(longName, item->option.longName)))
+ continue;
+ else if (shortName != item->option.shortName)
+ continue;
+ break;
+ }
+ if (i < 0) return 0;
+
+ if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH)
+ return POPT_ERROR_OPTSTOODEEP;
+
+/*@-boundsread@*/
+ if (nextCharArg && *nextCharArg)
+ con->os->nextCharArg = nextCharArg;
+/*@=boundsread@*/
+
+ con->os++;
+ con->os->next = 0;
+ con->os->stuffed = 0;
+ con->os->nextArg = NULL;
+ con->os->nextCharArg = NULL;
+ con->os->currAlias = con->aliases + i;
+ rc = poptDupArgv(con->os->currAlias->argc, con->os->currAlias->argv,
+ &con->os->argc, &con->os->argv);
+ con->os->argb = NULL;
+
+ return (rc ? rc : 1);
+}
+
+/*@-bounds -boundswrite @*/
+static int execCommand(poptContext con)
+ /*@globals internalState @*/
+ /*@modifies internalState @*/
+{
+ poptItem item = con->doExec;
+ const char ** argv;
+ int argc = 0;
+ int rc;
+
+ if (item == NULL) /*XXX can't happen*/
+ return POPT_ERROR_NOARG;
+
+ if (item->argv == NULL || item->argc < 1 ||
+ (!con->execAbsolute && strchr(item->argv[0], '/')))
+ return POPT_ERROR_NOARG;
+
+ argv = (const char **)malloc(
+ sizeof(*argv) * (6 + item->argc + con->numLeftovers + con->finalArgvCount));
+ if (argv == NULL) return POPT_ERROR_MALLOC; /* XXX can't happen */
+
+ if (!strchr(item->argv[0], '/') && con->execPath) {
+ char *s = (char *)alloca(
+ strlen(con->execPath) + strlen(item->argv[0]) + sizeof("/"));
+ sprintf(s, "%s/%s", con->execPath, item->argv[0]);
+ argv[argc] = s;
+ } else {
+ argv[argc] = findProgramPath(item->argv[0]);
+ }
+ if (argv[argc++] == NULL) return POPT_ERROR_NOARG;
+
+ if (item->argc > 1) {
+ memcpy(argv + argc, item->argv + 1, sizeof(*argv) * (item->argc - 1));
+ argc += (item->argc - 1);
+ }
+
+ if (con->finalArgv != NULL && con->finalArgvCount > 0) {
+ memcpy(argv + argc, con->finalArgv,
+ sizeof(*argv) * con->finalArgvCount);
+ argc += con->finalArgvCount;
+ }
+
+ if (con->leftovers != NULL && con->numLeftovers > 0) {
+#if 0
+ argv[argc++] = "--";
+#endif
+ memcpy(argv + argc, con->leftovers, sizeof(*argv) * con->numLeftovers);
+ argc += con->numLeftovers;
+ }
+
+ argv[argc] = NULL;
+
+#ifdef __hpux
+ rc = setresuid(getuid(), getuid(),-1);
+ if (rc) return POPT_ERROR_ERRNO;
+#else
+/*
+ * XXX " ... on BSD systems setuid() should be preferred over setreuid()"
+ * XXX sez' Timur Bakeyev <mc@bat.ru>
+ * XXX from Norbert Warmuth <nwarmuth@privat.circular.de>
+ */
+#if defined(HAVE_SETUID)
+ rc = setuid(getuid());
+ if (rc) return POPT_ERROR_ERRNO;
+#elif defined (HAVE_SETREUID)
+ rc = setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */
+ if (rc) return POPT_ERROR_ERRNO;
+#else
+ ; /* Can't drop privileges */
+#endif
+#endif
+
+ if (argv[0] == NULL)
+ return POPT_ERROR_NOARG;
+
+#ifdef MYDEBUG
+if (_popt_debug)
+ { const char ** avp;
+ fprintf(stderr, "==> execvp(%s) argv[%d]:", argv[0], argc);
+ for (avp = argv; *avp; avp++)
+ fprintf(stderr, " '%s'", *avp);
+ fprintf(stderr, "\n");
+ }
+#endif
+
+ rc = execvp(argv[0], (char *const *)argv);
+ /* notreached */
+ if (rc) {
+ return POPT_ERROR_ERRNO;
+ }
+
+ return 0;
+}
+/*@=bounds =boundswrite @*/
+
+/*@-boundswrite@*/
+/*@observer@*/ /*@null@*/ static const struct poptOption *
+findOption(const struct poptOption * opt, /*@null@*/ const char * longName,
+ char shortName,
+ /*@null@*/ /*@out@*/ poptCallbackType * callback,
+ /*@null@*/ /*@out@*/ const void ** callbackData,
+ int singleDash)
+ /*@modifies *callback, *callbackData */
+{
+ const struct poptOption * cb = NULL;
+
+ /* This happens when a single - is given */
+ if (singleDash && !shortName && (longName && *longName == '\0'))
+ shortName = '-';
+
+ for (; opt->longName || opt->shortName || opt->arg; opt++) {
+
+ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
+ const struct poptOption * opt2;
+
+ /* Recurse on included sub-tables. */
+ if (opt->arg == NULL) continue; /* XXX program error */
+ opt2 = findOption((const struct poptOption *)opt->arg, longName,
+ shortName, callback,
+ callbackData, singleDash);
+ if (opt2 == NULL) continue;
+ /* Sub-table data will be inheirited if no data yet. */
+ if (!(callback && *callback)) return opt2;
+ if (!(callbackData && *callbackData == NULL)) return opt2;
+ /*@-observertrans -dependenttrans @*/
+ *callbackData = opt->descrip;
+ /*@=observertrans =dependenttrans @*/
+ return opt2;
+ } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) {
+ cb = opt;
+ } else if (longName && opt->longName &&
+ (!singleDash || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) &&
+ /*@-nullpass@*/ /* LCL: opt->longName != NULL */
+ !strcmp(longName, opt->longName))
+ /*@=nullpass@*/
+ {
+ break;
+ } else if (shortName && shortName == opt->shortName) {
+ break;
+ }
+ }
+
+ if (!opt->longName && !opt->shortName)
+ return NULL;
+ /*@-modobserver -mods @*/
+ if (callback) *callback = NULL;
+ if (callbackData) *callbackData = NULL;
+ if (cb) {
+ if (callback)
+ /*@-castfcnptr@*/
+ *callback = (poptCallbackType)cb->arg;
+ /*@=castfcnptr@*/
+ if (!(cb->argInfo & POPT_CBFLAG_INC_DATA)) {
+ if (callbackData)
+ /*@-observertrans@*/ /* FIX: typedef double indirection. */
+ *callbackData = cb->descrip;
+ /*@=observertrans@*/
+ }
+ }
+ /*@=modobserver =mods @*/
+
+ return opt;
+}
+/*@=boundswrite@*/
+
+static const char * findNextArg(/*@special@*/ poptContext con,
+ unsigned argx, int delete_arg)
+ /*@uses con->optionStack, con->os,
+ con->os->next, con->os->argb, con->os->argc, con->os->argv @*/
+ /*@modifies con @*/
+{
+ struct optionStackEntry * os = con->os;
+ const char * arg;
+
+ do {
+ int i;
+ arg = NULL;
+ while (os->next == os->argc && os > con->optionStack) os--;
+ if (os->next == os->argc && os == con->optionStack) break;
+ if (os->argv != NULL)
+ for (i = os->next; i < os->argc; i++) {
+ /*@-sizeoftype@*/
+ if (os->argb && PBM_ISSET(i, os->argb))
+ /*@innercontinue@*/ continue;
+ if (*os->argv[i] == '-')
+ /*@innercontinue@*/ continue;
+ if (--argx > 0)
+ /*@innercontinue@*/ continue;
+ arg = os->argv[i];
+ if (delete_arg) {
+ if (os->argb == NULL) os->argb = (pbm_set *)PBM_ALLOC(os->argc);
+ if (os->argb != NULL) /* XXX can't happen */
+ PBM_SET(i, os->argb);
+ }
+ /*@innerbreak@*/ break;
+ /*@=sizeoftype@*/
+ }
+ if (os > con->optionStack) os--;
+ } while (arg == NULL);
+ return arg;
+}
+
+/*@-boundswrite@*/
+static /*@only@*/ /*@null@*/ const char *
+expandNextArg(/*@special@*/ poptContext con, const char * s)
+ /*@uses con->optionStack, con->os,
+ con->os->next, con->os->argb, con->os->argc, con->os->argv @*/
+ /*@modifies con @*/
+{
+ const char * a = NULL;
+ size_t alen;
+ char *t, *te;
+ size_t tn = strlen(s) + 1;
+ char c;
+
+ te = t = (char *)malloc(tn);;
+ if (t == NULL) return NULL; /* XXX can't happen */
+ while ((c = *s++) != '\0') {
+ switch (c) {
+#if 0 /* XXX can't do this */
+ case '\\': /* escape */
+ c = *s++;
+ /*@switchbreak@*/ break;
+#endif
+ case '!':
+ if (!(s[0] == '#' && s[1] == ':' && s[2] == '+'))
+ /*@switchbreak@*/ break;
+ /* XXX Make sure that findNextArg deletes only next arg. */
+ if (a == NULL) {
+ if ((a = findNextArg(con, 1, 1)) == NULL)
+ /*@switchbreak@*/ break;
+ }
+ s += 3;
+
+ alen = strlen(a);
+ tn += alen;
+ *te = '\0';
+ t = (char *)realloc(t, tn);
+ te = t + strlen(t);
+ strncpy(te, a, alen); te += alen;
+ continue;
+ /*@notreached@*/ /*@switchbreak@*/ break;
+ default:
+ /*@switchbreak@*/ break;
+ }
+ *te++ = c;
+ }
+ *te = '\0';
+ t = (char *)realloc(t, strlen(t) + 1); /* XXX memory leak, hard to plug */
+ return t;
+}
+/*@=boundswrite@*/
+
+static void poptStripArg(/*@special@*/ poptContext con, int which)
+ /*@uses con->arg_strip, con->optionStack @*/
+ /*@defines con->arg_strip @*/
+ /*@modifies con @*/
+{
+ /*@-sizeoftype@*/
+ if (con->arg_strip == NULL)
+ con->arg_strip = (pbm_set *)PBM_ALLOC(con->optionStack[0].argc);
+ if (con->arg_strip != NULL) /* XXX can't happen */
+ PBM_SET(which, con->arg_strip);
+ /*@=sizeoftype@*/
+ /*@-compdef@*/ /* LCL: con->arg_strip udefined? */
+ return;
+ /*@=compdef@*/
+}
+
+int poptSaveLong(long * arg, int argInfo, long aLong)
+{
+ /* XXX Check alignment, may fail on funky platforms. */
+ if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1)))
+ return POPT_ERROR_NULLARG;
+
+ if (argInfo & POPT_ARGFLAG_NOT)
+ aLong = ~aLong;
+ switch (argInfo & POPT_ARGFLAG_LOGICALOPS) {
+ case 0:
+ *arg = aLong;
+ break;
+ case POPT_ARGFLAG_OR:
+ *arg |= aLong;
+ break;
+ case POPT_ARGFLAG_AND:
+ *arg &= aLong;
+ break;
+ case POPT_ARGFLAG_XOR:
+ *arg ^= aLong;
+ break;
+ default:
+ return POPT_ERROR_BADOPERATION;
+ /*@notreached@*/ break;
+ }
+ return 0;
+}
+
+int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong)
+{
+ /* XXX Check alignment, may fail on funky platforms. */
+ if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1)))
+ return POPT_ERROR_NULLARG;
+
+ if (argInfo & POPT_ARGFLAG_NOT)
+ aLong = ~aLong;
+ switch (argInfo & POPT_ARGFLAG_LOGICALOPS) {
+ case 0:
+ *arg = aLong;
+ break;
+ case POPT_ARGFLAG_OR:
+ *arg |= aLong;
+ break;
+ case POPT_ARGFLAG_AND:
+ *arg &= aLong;
+ break;
+ case POPT_ARGFLAG_XOR:
+ *arg ^= aLong;
+ break;
+ default:
+ return POPT_ERROR_BADOPERATION;
+ /*@notreached@*/ break;
+ }
+ return 0;
+}
+
+/*@-boundswrite@*/
+/* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
+int poptGetNextOpt(poptContext con)
+{
+ const struct poptOption * opt = NULL;
+ int done = 0;
+
+ if (con == NULL)
+ return -1;
+ while (!done) {
+ const char * origOptString = NULL;
+ poptCallbackType cb = NULL;
+ const void * cbData = NULL;
+ const char * longArg = NULL;
+ int canstrip = 0;
+ int shorty = 0;
+
+ while (!con->os->nextCharArg && con->os->next == con->os->argc
+ && con->os > con->optionStack) {
+ cleanOSE(con->os--);
+ }
+ if (!con->os->nextCharArg && con->os->next == con->os->argc) {
+ /*@-internalglobs@*/
+ invokeCallbacksPOST(con, con->options);
+ /*@=internalglobs@*/
+ if (con->doExec) return execCommand(con);
+ return -1;
+ }
+
+ /* Process next long option */
+ if (!con->os->nextCharArg) {
+ char * localOptString, * optString;
+ int thisopt;
+
+ /*@-sizeoftype@*/
+ if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) {
+ con->os->next++;
+ continue;
+ }
+ /*@=sizeoftype@*/
+ thisopt = con->os->next;
+ if (con->os->argv != NULL) /* XXX can't happen */
+ origOptString = con->os->argv[con->os->next++];
+
+ if (origOptString == NULL) /* XXX can't happen */
+ return POPT_ERROR_BADOPT;
+
+ if (con->restLeftover || *origOptString != '-') {
+ if (con->flags & POPT_CONTEXT_POSIXMEHARDER)
+ con->restLeftover = 1;
+ if (con->flags & POPT_CONTEXT_ARG_OPTS) {
+ con->os->nextArg = xstrdup(origOptString);
+ return 0;
+ }
+ if (con->leftovers != NULL) /* XXX can't happen */
+ con->leftovers[con->numLeftovers++] = origOptString;
+ continue;
+ }
+
+ /* Make a copy we can hack at */
+ localOptString = optString =
+ strcpy((char *)alloca(strlen(origOptString) + 1),
+ origOptString);
+
+ if (optString[0] == '\0')
+ return POPT_ERROR_BADOPT;
+
+ if (optString[1] == '-' && !optString[2]) {
+ con->restLeftover = 1;
+ continue;
+ } else {
+ char *oe;
+ int singleDash;
+
+ optString++;
+ if (*optString == '-')
+ singleDash = 0, optString++;
+ else
+ singleDash = 1;
+
+ /* XXX aliases with arg substitution need "--alias=arg" */
+ if (handleAlias(con, optString, '\0', NULL))
+ continue;
+
+ if (handleExec(con, optString, '\0'))
+ continue;
+
+ /* Check for "--long=arg" option. */
+ for (oe = optString; *oe && *oe != '='; oe++)
+ {};
+ if (*oe == '=') {
+ *oe++ = '\0';
+ /* XXX longArg is mapped back to persistent storage. */
+ longArg = origOptString + (oe - localOptString);
+ }
+
+ opt = findOption(con->options, optString, '\0', &cb, &cbData,
+ singleDash);
+ if (!opt && !singleDash)
+ return POPT_ERROR_BADOPT;
+ }
+
+ if (!opt) {
+ con->os->nextCharArg = origOptString + 1;
+ } else {
+ if (con->os == con->optionStack &&
+ opt->argInfo & POPT_ARGFLAG_STRIP)
+ {
+ canstrip = 1;
+ poptStripArg(con, thisopt);
+ }
+ shorty = 0;
+ }
+ }
+
+ /* Process next short option */
+ /*@-branchstate@*/ /* FIX: W2DO? */
+ if (con->os->nextCharArg) {
+ origOptString = con->os->nextCharArg;
+
+ con->os->nextCharArg = NULL;
+
+ if (handleAlias(con, NULL, *origOptString, origOptString + 1))
+ continue;
+
+ if (handleExec(con, NULL, *origOptString)) {
+ /* Restore rest of short options for further processing */
+ origOptString++;
+ if (*origOptString != '\0')
+ con->os->nextCharArg = origOptString;
+ continue;
+ }
+
+ opt = findOption(con->options, NULL, *origOptString, &cb,
+ &cbData, 0);
+ if (!opt)
+ return POPT_ERROR_BADOPT;
+ shorty = 1;
+
+ origOptString++;
+ if (*origOptString != '\0')
+ con->os->nextCharArg = origOptString;
+ }
+ /*@=branchstate@*/
+
+ if (opt == NULL) return POPT_ERROR_BADOPT; /* XXX can't happen */
+ if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) {
+ if (poptSaveInt((int *)opt->arg, opt->argInfo, 1L))
+ return POPT_ERROR_BADOPERATION;
+ } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) {
+ if (opt->arg) {
+ if (poptSaveInt((int *)opt->arg, opt->argInfo, (long)opt->val))
+ return POPT_ERROR_BADOPERATION;
+ }
+ } else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
+ con->os->nextArg = (const char *)_free(con->os->nextArg);
+ /*@-usedef@*/ /* FIX: W2DO? */
+ if (longArg) {
+ /*@=usedef@*/
+ longArg = expandNextArg(con, longArg);
+ con->os->nextArg = longArg;
+ } else if (con->os->nextCharArg) {
+ longArg = expandNextArg(con, con->os->nextCharArg);
+ con->os->nextArg = longArg;
+ con->os->nextCharArg = NULL;
+ } else {
+ while (con->os->next == con->os->argc &&
+ con->os > con->optionStack) {
+ cleanOSE(con->os--);
+ }
+ if (con->os->next == con->os->argc) {
+ if (!(opt->argInfo & POPT_ARGFLAG_OPTIONAL))
+ /*@-compdef@*/ /* FIX: con->os->argv not defined */
+ return POPT_ERROR_NOARG;
+ /*@=compdef@*/
+ con->os->nextArg = NULL;
+ } else {
+
+ /*
+ * Make sure this isn't part of a short arg or the
+ * result of an alias expansion.
+ */
+ if (con->os == con->optionStack &&
+ (opt->argInfo & POPT_ARGFLAG_STRIP) &&
+ canstrip) {
+ poptStripArg(con, con->os->next);
+ }
+
+ if (con->os->argv != NULL) { /* XXX can't happen */
+ /* XXX watchout: subtle side-effects live here. */
+ longArg = con->os->argv[con->os->next++];
+ longArg = expandNextArg(con, longArg);
+ con->os->nextArg = longArg;
+ }
+ }
+ }
+ longArg = NULL;
+
+ if (opt->arg) {
+ switch (opt->argInfo & POPT_ARG_MASK) {
+ case POPT_ARG_STRING:
+ /* XXX memory leak, hard to plug */
+ *((const char **) opt->arg) = (con->os->nextArg)
+ ? xstrdup(con->os->nextArg) : NULL;
+ /*@switchbreak@*/ break;
+
+ case POPT_ARG_INT:
+ case POPT_ARG_LONG:
+ { long aLong = 0;
+ char *end;
+
+ if (con->os->nextArg) {
+ aLong = strtol(con->os->nextArg, &end, 0);
+ if (!(end && *end == '\0'))
+ return POPT_ERROR_BADNUMBER;
+ }
+
+ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) {
+ if (aLong == LONG_MIN || aLong == LONG_MAX)
+ return POPT_ERROR_OVERFLOW;
+ if (poptSaveLong((long *)opt->arg, opt->argInfo, aLong))
+ return POPT_ERROR_BADOPERATION;
+ } else {
+ if (aLong > INT_MAX || aLong < INT_MIN)
+ return POPT_ERROR_OVERFLOW;
+ if (poptSaveInt((int *)opt->arg, opt->argInfo, aLong))
+ return POPT_ERROR_BADOPERATION;
+ }
+ } /*@switchbreak@*/ break;
+
+ case POPT_ARG_FLOAT:
+ case POPT_ARG_DOUBLE:
+ { double aDouble = 0.0;
+ char *end;
+
+ if (con->os->nextArg) {
+ /*@-mods@*/
+ int saveerrno = errno;
+ errno = 0;
+ aDouble = strtod(con->os->nextArg, &end);
+ if (errno == ERANGE)
+ return POPT_ERROR_OVERFLOW;
+ errno = saveerrno;
+ /*@=mods@*/
+ if (*end != '\0')
+ return POPT_ERROR_BADNUMBER;
+ }
+
+ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_DOUBLE) {
+ *((double *) opt->arg) = aDouble;
+ } else {
+#ifndef _ABS
+#define _ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a))
+#endif
+ if ((_ABS(aDouble) - FLT_MAX) > DBL_EPSILON)
+ return POPT_ERROR_OVERFLOW;
+ if ((FLT_MIN - _ABS(aDouble)) > DBL_EPSILON)
+ return POPT_ERROR_OVERFLOW;
+ *((float *) opt->arg) = aDouble;
+ }
+ } /*@switchbreak@*/ break;
+ default:
+ fprintf(stdout,
+ POPT_("option type (%d) not implemented in popt\n"),
+ (opt->argInfo & POPT_ARG_MASK));
+ exit(EXIT_FAILURE);
+ /*@notreached@*/ /*@switchbreak@*/ break;
+ }
+ }
+ }
+
+ if (cb) {
+ /*@-internalglobs@*/
+ invokeCallbacksOPTION(con, con->options, opt, cbData, shorty);
+ /*@=internalglobs@*/
+ } else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL))
+ done = 1;
+
+ if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) {
+ con->finalArgvAlloced += 10;
+ con->finalArgv = (const char **)realloc(con->finalArgv,
+ sizeof(*con->finalArgv) * con->finalArgvAlloced);
+ }
+
+ if (con->finalArgv != NULL)
+ { char *s = (char *)malloc(
+ (opt->longName ? strlen(opt->longName) : 0) + 3);
+ if (s != NULL) { /* XXX can't happen */
+ if (opt->longName)
+ sprintf(s, "%s%s",
+ ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
+ opt->longName);
+ else
+ sprintf(s, "-%c", opt->shortName);
+ con->finalArgv[con->finalArgvCount++] = s;
+ } else
+ con->finalArgv[con->finalArgvCount++] = NULL;
+ }
+
+ if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE)
+ /*@-ifempty@*/ ; /*@=ifempty@*/
+ else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL)
+ /*@-ifempty@*/ ; /*@=ifempty@*/
+ else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
+ if (con->finalArgv != NULL && con->os->nextArg)
+ con->finalArgv[con->finalArgvCount++] =
+ /*@-nullpass@*/ /* LCL: con->os->nextArg != NULL */
+ xstrdup(con->os->nextArg);
+ /*@=nullpass@*/
+ }
+ }
+
+ return (opt ? opt->val : -1); /* XXX can't happen */
+}
+/*@=boundswrite@*/
+
+const char * poptGetOptArg(poptContext con)
+{
+ const char * ret = NULL;
+ /*@-branchstate@*/
+ if (con) {
+ ret = con->os->nextArg;
+ con->os->nextArg = NULL;
+ }
+ /*@=branchstate@*/
+ return ret;
+}
+
+const char * poptGetArg(poptContext con)
+{
+ const char * ret = NULL;
+ if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers)
+ ret = con->leftovers[con->nextLeftover++];
+ return ret;
+}
+
+const char * poptPeekArg(poptContext con)
+{
+ const char * ret = NULL;
+ if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers)
+ ret = con->leftovers[con->nextLeftover];
+ return ret;
+}
+
+/*@-boundswrite@*/
+const char ** poptGetArgs(poptContext con)
+{
+ if (con == NULL ||
+ con->leftovers == NULL || con->numLeftovers == con->nextLeftover)
+ return NULL;
+
+ /* some apps like [like RPM ;-) ] need this NULL terminated */
+ con->leftovers[con->numLeftovers] = NULL;
+
+ /*@-nullret -nullstate @*/ /* FIX: typedef double indirection. */
+ return (con->leftovers + con->nextLeftover);
+ /*@=nullret =nullstate @*/
+}
+/*@=boundswrite@*/
+
+poptContext poptFreeContext(poptContext con)
+{
+ poptItem item;
+ int i;
+
+ if (con == NULL) return con;
+ poptResetContext(con);
+ con->os->argb = (pbm_set *)_free(con->os->argb);
+
+ if (con->aliases != NULL)
+ for (i = 0; i < con->numAliases; i++) {
+ item = con->aliases + i;
+ /*@-modobserver -observertrans -dependenttrans@*/
+ item->option.longName = (const char *)_free(item->option.longName);
+ item->option.descrip = (const char *)_free(item->option.descrip);
+ item->option.argDescrip = (const char *)_free(item->option.argDescrip);
+ /*@=modobserver =observertrans =dependenttrans@*/
+ item->argv = (const char **)_free(item->argv);
+ }
+ con->aliases = (poptItem)_free(con->aliases);
+
+ if (con->execs != NULL)
+ for (i = 0; i < con->numExecs; i++) {
+ item = con->execs + i;
+ /*@-modobserver -observertrans -dependenttrans@*/
+ item->option.longName = (const char *)_free(item->option.longName);
+ item->option.descrip = (const char *)_free(item->option.descrip);
+ item->option.argDescrip = (const char *)_free(item->option.argDescrip);
+ /*@=modobserver =observertrans =dependenttrans@*/
+ item->argv = (const char **)_free(item->argv);
+ }
+ con->execs = (poptItem)_free(con->execs);
+
+ con->leftovers = (const char **)_free(con->leftovers);
+ con->finalArgv = (const char **)_free(con->finalArgv);
+ con->appName = (const char *)_free(con->appName);
+ con->otherHelp = (const char *)_free(con->otherHelp);
+ con->execPath = (const char *)_free(con->execPath);
+ con->arg_strip = (pbm_set *)PBM_FREE(con->arg_strip);
+
+ con = (poptContext)_free(con);
+ return con;
+}
+
+int poptAddAlias(poptContext con, struct poptAlias alias,
+ /*@unused@*/ int flags)
+{
+ poptItem item = (poptItem)alloca(sizeof(*item));
+ memset(item, 0, sizeof(*item));
+ item->option.longName = alias.longName;
+ item->option.shortName = alias.shortName;
+ item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN;
+ item->option.arg = 0;
+ item->option.val = 0;
+ item->option.descrip = NULL;
+ item->option.argDescrip = NULL;
+ item->argc = alias.argc;
+ item->argv = alias.argv;
+ return poptAddItem(con, item, 0);
+}
+
+/*@-boundswrite@*/
+/*@-mustmod@*/ /* LCL: con not modified? */
+int poptAddItem(poptContext con, poptItem newItem, int flags)
+{
+ poptItem * items, item;
+ int * nitems;
+
+ switch (flags) {
+ case 1:
+ items = &con->execs;
+ nitems = &con->numExecs;
+ break;
+ case 0:
+ items = &con->aliases;
+ nitems = &con->numAliases;
+ break;
+ default:
+ return 1;
+ /*@notreached@*/ break;
+ }
+
+ *items = (poptItem)realloc((*items), ((*nitems) + 1) * sizeof(**items));
+ if ((*items) == NULL)
+ return 1;
+
+ item = (*items) + (*nitems);
+
+ item->option.longName =
+ (newItem->option.longName ? xstrdup(newItem->option.longName) : NULL);
+ item->option.shortName = newItem->option.shortName;
+ item->option.argInfo = newItem->option.argInfo;
+ item->option.arg = newItem->option.arg;
+ item->option.val = newItem->option.val;
+ item->option.descrip =
+ (newItem->option.descrip ? xstrdup(newItem->option.descrip) : NULL);
+ item->option.argDescrip =
+ (newItem->option.argDescrip ? xstrdup(newItem->option.argDescrip) : NULL);
+ item->argc = newItem->argc;
+ item->argv = newItem->argv;
+
+ (*nitems)++;
+
+ return 0;
+}
+/*@=mustmod@*/
+/*@=boundswrite@*/
+
+const char * poptBadOption(poptContext con, int flags)
+{
+ struct optionStackEntry * os = NULL;
+
+ if (con != NULL)
+ os = (flags & POPT_BADOPTION_NOALIAS) ? con->optionStack : con->os;
+
+ /*@-nullderef@*/ /* LCL: os->argv != NULL */
+ return (os && os->argv ? os->argv[os->next - 1] : NULL);
+ /*@=nullderef@*/
+}
+
+const char *poptStrerror(const int error)
+{
+ switch (error) {
+ case POPT_ERROR_NOARG:
+ return POPT_("missing argument");
+ case POPT_ERROR_BADOPT:
+ return POPT_("unknown option");
+ case POPT_ERROR_BADOPERATION:
+ return POPT_("mutually exclusive logical operations requested");
+ case POPT_ERROR_NULLARG:
+ return POPT_("opt->arg should not be NULL");
+ case POPT_ERROR_OPTSTOODEEP:
+ return POPT_("aliases nested too deeply");
+ case POPT_ERROR_BADQUOTE:
+ return POPT_("error in parameter quoting");
+ case POPT_ERROR_BADNUMBER:
+ return POPT_("invalid numeric value");
+ case POPT_ERROR_OVERFLOW:
+ return POPT_("number too large or too small");
+ case POPT_ERROR_MALLOC:
+ return POPT_("memory allocation failed");
+ case POPT_ERROR_ERRNO:
+ return strerror(errno);
+ default:
+ return POPT_("unknown error");
+ }
+}
+
+int poptStuffArgs(poptContext con, const char ** argv)
+{
+ int argc;
+ int rc;
+
+ if ((con->os - con->optionStack) == POPT_OPTION_DEPTH)
+ return POPT_ERROR_OPTSTOODEEP;
+
+ for (argc = 0; argv[argc]; argc++)
+ {};
+
+ con->os++;
+ con->os->next = 0;
+ con->os->nextArg = NULL;
+ con->os->nextCharArg = NULL;
+ con->os->currAlias = NULL;
+ rc = poptDupArgv(argc, argv, &con->os->argc, &con->os->argv);
+ con->os->argb = NULL;
+ con->os->stuffed = 1;
+
+ return rc;
+}
+
+const char * poptGetInvocationName(poptContext con)
+{
+ return (con->os->argv ? con->os->argv[0] : "");
+}
+
+/*@-boundswrite@*/
+int poptStrippedArgv(poptContext con, int argc, char ** argv)
+{
+ int numargs = argc;
+ int j = 1;
+ int i;
+
+ /*@-sizeoftype@*/
+ if (con->arg_strip)
+ for (i = 1; i < argc; i++) {
+ if (PBM_ISSET(i, con->arg_strip))
+ numargs--;
+ }
+
+ for (i = 1; i < argc; i++) {
+ if (con->arg_strip && PBM_ISSET(i, con->arg_strip))
+ continue;
+ argv[j] = (j < numargs) ? argv[i] : NULL;
+ j++;
+ }
+ /*@=sizeoftype@*/
+
+ return numargs;
+}
+/*@=boundswrite@*/
diff --git a/source3/popt/popt.h b/source3/popt/popt.h
new file mode 100644
index 0000000000..08701d73b5
--- /dev/null
+++ b/source3/popt/popt.h
@@ -0,0 +1,545 @@
+/** \file popt/popt.h
+ * \ingroup popt
+ */
+
+/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
+ file accompanying popt source distributions, available from
+ ftp://ftp.rpm.org/pub/rpm/dist. */
+
+#ifndef H_POPT
+#define H_POPT
+
+#include <stdio.h> /* for FILE * */
+
+#define POPT_OPTION_DEPTH 10
+
+/** \ingroup popt
+ * \name Arg type identifiers
+ */
+/*@{*/
+#define POPT_ARG_NONE 0 /*!< no arg */
+#define POPT_ARG_STRING 1 /*!< arg will be saved as string */
+#define POPT_ARG_INT 2 /*!< arg will be converted to int */
+#define POPT_ARG_LONG 3 /*!< arg will be converted to long */
+#define POPT_ARG_INCLUDE_TABLE 4 /*!< arg points to table */
+#define POPT_ARG_CALLBACK 5 /*!< table-wide callback... must be
+ set first in table; arg points
+ to callback, descrip points to
+ callback data to pass */
+#define POPT_ARG_INTL_DOMAIN 6 /*!< set the translation domain
+ for this table and any
+ included tables; arg points
+ to the domain string */
+#define POPT_ARG_VAL 7 /*!< arg should take value val */
+#define POPT_ARG_FLOAT 8 /*!< arg will be converted to float */
+#define POPT_ARG_DOUBLE 9 /*!< arg will be converted to double */
+
+#define POPT_ARG_MASK 0x0000FFFF
+/*@}*/
+
+/** \ingroup popt
+ * \name Arg modifiers
+ */
+/*@{*/
+#define POPT_ARGFLAG_ONEDASH 0x80000000 /*!< allow -longoption */
+#define POPT_ARGFLAG_DOC_HIDDEN 0x40000000 /*!< don't show in help/usage */
+#define POPT_ARGFLAG_STRIP 0x20000000 /*!< strip this arg from argv(only applies to long args) */
+#define POPT_ARGFLAG_OPTIONAL 0x10000000 /*!< arg may be missing */
+
+#define POPT_ARGFLAG_OR 0x08000000 /*!< arg will be or'ed */
+#define POPT_ARGFLAG_NOR 0x09000000 /*!< arg will be nor'ed */
+#define POPT_ARGFLAG_AND 0x04000000 /*!< arg will be and'ed */
+#define POPT_ARGFLAG_NAND 0x05000000 /*!< arg will be nand'ed */
+#define POPT_ARGFLAG_XOR 0x02000000 /*!< arg will be xor'ed */
+#define POPT_ARGFLAG_NOT 0x01000000 /*!< arg will be negated */
+#define POPT_ARGFLAG_LOGICALOPS \
+ (POPT_ARGFLAG_OR|POPT_ARGFLAG_AND|POPT_ARGFLAG_XOR)
+
+#define POPT_BIT_SET (POPT_ARG_VAL|POPT_ARGFLAG_OR)
+ /*!< set arg bit(s) */
+#define POPT_BIT_CLR (POPT_ARG_VAL|POPT_ARGFLAG_NAND)
+ /*!< clear arg bit(s) */
+
+#define POPT_ARGFLAG_SHOW_DEFAULT 0x00800000 /*!< show default value in --help */
+
+/*@}*/
+
+/** \ingroup popt
+ * \name Callback modifiers
+ */
+/*@{*/
+#define POPT_CBFLAG_PRE 0x80000000 /*!< call the callback before parse */
+#define POPT_CBFLAG_POST 0x40000000 /*!< call the callback after parse */
+#define POPT_CBFLAG_INC_DATA 0x20000000 /*!< use data from the include line,
+ not the subtable */
+#define POPT_CBFLAG_SKIPOPTION 0x10000000 /*!< don't callback with option */
+#define POPT_CBFLAG_CONTINUE 0x08000000 /*!< continue callbacks with option */
+/*@}*/
+
+/** \ingroup popt
+ * \name Error return values
+ */
+/*@{*/
+#define POPT_ERROR_NOARG -10 /*!< missing argument */
+#define POPT_ERROR_BADOPT -11 /*!< unknown option */
+#define POPT_ERROR_OPTSTOODEEP -13 /*!< aliases nested too deeply */
+#define POPT_ERROR_BADQUOTE -15 /*!< error in paramter quoting */
+#define POPT_ERROR_ERRNO -16 /*!< errno set, use strerror(errno) */
+#define POPT_ERROR_BADNUMBER -17 /*!< invalid numeric value */
+#define POPT_ERROR_OVERFLOW -18 /*!< number too large or too small */
+#define POPT_ERROR_BADOPERATION -19 /*!< mutually exclusive logical operations requested */
+#define POPT_ERROR_NULLARG -20 /*!< opt->arg should not be NULL */
+#define POPT_ERROR_MALLOC -21 /*!< memory allocation failed */
+/*@}*/
+
+/** \ingroup popt
+ * \name poptBadOption() flags
+ */
+/*@{*/
+#define POPT_BADOPTION_NOALIAS (1 << 0) /*!< don't go into an alias */
+/*@}*/
+
+/** \ingroup popt
+ * \name poptGetContext() flags
+ */
+/*@{*/
+#define POPT_CONTEXT_NO_EXEC (1 << 0) /*!< ignore exec expansions */
+#define POPT_CONTEXT_KEEP_FIRST (1 << 1) /*!< pay attention to argv[0] */
+#define POPT_CONTEXT_POSIXMEHARDER (1 << 2) /*!< options can't follow args */
+#define POPT_CONTEXT_ARG_OPTS (1 << 4) /*!< return args as options with value 0 */
+/*@}*/
+
+/** \ingroup popt
+ */
+struct poptOption {
+/*@observer@*/ /*@null@*/
+ const char * longName; /*!< may be NULL */
+ char shortName; /*!< may be '\0' */
+ int argInfo;
+/*@shared@*/ /*@null@*/
+ void * arg; /*!< depends on argInfo */
+ int val; /*!< 0 means don't return, just update flag */
+/*@observer@*/ /*@null@*/
+ const char * descrip; /*!< description for autohelp -- may be NULL */
+/*@observer@*/ /*@null@*/
+ const char * argDescrip; /*!< argument description for autohelp */
+};
+
+/** \ingroup popt
+ * A popt alias argument for poptAddAlias().
+ */
+struct poptAlias {
+/*@owned@*/ /*@null@*/
+ const char * longName; /*!< may be NULL */
+ char shortName; /*!< may be '\0' */
+ int argc;
+/*@owned@*/
+ const char ** argv; /*!< must be free()able */
+};
+
+/** \ingroup popt
+ * A popt alias or exec argument for poptAddItem().
+ */
+/*@-exporttype@*/
+typedef struct poptItem_s {
+ struct poptOption option; /*!< alias/exec name(s) and description. */
+ int argc; /*!< (alias) no. of args. */
+/*@owned@*/
+ const char ** argv; /*!< (alias) args, must be free()able. */
+} * poptItem;
+/*@=exporttype@*/
+
+/** \ingroup popt
+ * \name Auto-generated help/usage
+ */
+/*@{*/
+
+/**
+ * Empty table marker to enable displaying popt alias/exec options.
+ */
+/*@-exportvar@*/
+/*@unchecked@*/ /*@observer@*/
+extern struct poptOption poptAliasOptions[];
+/*@=exportvar@*/
+#define POPT_AUTOALIAS { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptAliasOptions, \
+ 0, "Options implemented via popt alias/exec:", NULL },
+
+/**
+ * Auto help table options.
+ */
+/*@-exportvar@*/
+/*@unchecked@*/ /*@observer@*/
+extern struct poptOption poptHelpOptions[];
+/*@=exportvar@*/
+#define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \
+ 0, "Help options:", NULL },
+
+#define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
+/*@}*/
+
+/** \ingroup popt
+ */
+/*@-exporttype@*/
+typedef /*@abstract@*/ struct poptContext_s * poptContext;
+/*@=exporttype@*/
+
+/** \ingroup popt
+ */
+#ifndef __cplusplus
+/*@-exporttype -typeuse@*/
+typedef struct poptOption * poptOption;
+/*@=exporttype =typeuse@*/
+#endif
+
+/*@-exportconst@*/
+enum poptCallbackReason {
+ POPT_CALLBACK_REASON_PRE = 0,
+ POPT_CALLBACK_REASON_POST = 1,
+ POPT_CALLBACK_REASON_OPTION = 2
+};
+/*@=exportconst@*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*@-type@*/
+
+/** \ingroup popt
+ * Table callback prototype.
+ * @param con context
+ * @param reason reason for callback
+ * @param opt option that triggered callback
+ * @param arg @todo Document.
+ * @param data @todo Document.
+ */
+typedef void (*poptCallbackType) (poptContext con,
+ enum poptCallbackReason reason,
+ /*@null@*/ const struct poptOption * opt,
+ /*@null@*/ const char * arg,
+ /*@null@*/ const void * data)
+ /*@*/;
+
+/** \ingroup popt
+ * Initialize popt context.
+ * @param name context name (usually argv[0] program name)
+ * @param argc no. of arguments
+ * @param argv argument array
+ * @param options address of popt option table
+ * @param flags or'd POPT_CONTEXT_* bits
+ * @return initialized popt context
+ */
+/*@only@*/ /*@null@*/ poptContext poptGetContext(
+ /*@dependent@*/ /*@keep@*/ const char * name,
+ int argc, /*@dependent@*/ /*@keep@*/ const char ** argv,
+ /*@dependent@*/ /*@keep@*/ const struct poptOption * options,
+ int flags)
+ /*@*/;
+
+/** \ingroup popt
+ * Reinitialize popt context.
+ * @param con context
+ */
+/*@unused@*/
+void poptResetContext(/*@null@*/poptContext con)
+ /*@modifies con @*/;
+
+/** \ingroup popt
+ * Return value of next option found.
+ * @param con context
+ * @return next option val, -1 on last item, POPT_ERROR_* on error
+ */
+int poptGetNextOpt(/*@null@*/poptContext con)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies con, fileSystem, internalState @*/;
+
+/** \ingroup popt
+ * Return next option argument (if any).
+ * @param con context
+ * @return option argument, NULL if no argument is available
+ */
+/*@observer@*/ /*@null@*/ const char * poptGetOptArg(/*@null@*/poptContext con)
+ /*@modifies con @*/;
+
+/** \ingroup popt
+ * Return next argument.
+ * @param con context
+ * @return next argument, NULL if no argument is available
+ */
+/*@observer@*/ /*@null@*/ const char * poptGetArg(/*@null@*/poptContext con)
+ /*@modifies con @*/;
+
+/** \ingroup popt
+ * Peek at current argument.
+ * @param con context
+ * @return current argument, NULL if no argument is available
+ */
+/*@observer@*/ /*@null@*/ const char * poptPeekArg(/*@null@*/poptContext con)
+ /*@*/;
+
+/** \ingroup popt
+ * Return remaining arguments.
+ * @param con context
+ * @return argument array, NULL terminated
+ */
+/*@observer@*/ /*@null@*/ const char ** poptGetArgs(/*@null@*/poptContext con)
+ /*@modifies con @*/;
+
+/** \ingroup popt
+ * Return the option which caused the most recent error.
+ * @param con context
+ * @param flags
+ * @return offending option
+ */
+/*@observer@*/ const char * poptBadOption(/*@null@*/poptContext con, int flags)
+ /*@*/;
+
+/** \ingroup popt
+ * Destroy context.
+ * @param con context
+ * @return NULL always
+ */
+/*@null@*/ poptContext poptFreeContext( /*@only@*/ /*@null@*/ poptContext con)
+ /*@modifies con @*/;
+
+/** \ingroup popt
+ * Add arguments to context.
+ * @param con context
+ * @param argv argument array, NULL terminated
+ * @return 0 on success, POPT_ERROR_OPTSTOODEEP on failure
+ */
+int poptStuffArgs(poptContext con, /*@keep@*/ const char ** argv)
+ /*@modifies con @*/;
+
+/** \ingroup popt
+ * Add alias to context.
+ * @todo Pass alias by reference, not value.
+ * @deprecated Use poptAddItem instead.
+ * @param con context
+ * @param alias alias to add
+ * @param flags (unused)
+ * @return 0 on success
+ */
+/*@unused@*/
+int poptAddAlias(poptContext con, struct poptAlias alias, int flags)
+ /*@modifies con @*/;
+
+/** \ingroup popt
+ * Add alias/exec item to context.
+ * @param con context
+ * @param newItem alias/exec item to add
+ * @param flags 0 for alias, 1 for exec
+ * @return 0 on success
+ */
+int poptAddItem(poptContext con, poptItem newItem, int flags)
+ /*@modifies con @*/;
+
+/** \ingroup popt
+ * Read configuration file.
+ * @param con context
+ * @param fn file name to read
+ * @return 0 on success, POPT_ERROR_ERRNO on failure
+ */
+int poptReadConfigFile(poptContext con, const char * fn)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies con->execs, con->numExecs,
+ fileSystem, internalState @*/;
+
+/** \ingroup popt
+ * Read default configuration from /etc/popt and $HOME/.popt.
+ * @param con context
+ * @param useEnv (unused)
+ * @return 0 on success, POPT_ERROR_ERRNO on failure
+ */
+int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies con->execs, con->numExecs,
+ fileSystem, internalState @*/;
+
+/** \ingroup popt
+ * Duplicate an argument array.
+ * @note: The argument array is malloc'd as a single area, so only argv must
+ * be free'd.
+ *
+ * @param argc no. of arguments
+ * @param argv argument array
+ * @retval argcPtr address of returned no. of arguments
+ * @retval argvPtr address of returned argument array
+ * @return 0 on success, POPT_ERROR_NOARG on failure
+ */
+int poptDupArgv(int argc, /*@null@*/ const char **argv,
+ /*@null@*/ /*@out@*/ int * argcPtr,
+ /*@null@*/ /*@out@*/ const char *** argvPtr)
+ /*@modifies *argcPtr, *argvPtr @*/;
+
+/** \ingroup popt
+ * Parse a string into an argument array.
+ * The parse allows ', ", and \ quoting, but ' is treated the same as " and
+ * both may include \ quotes.
+ * @note: The argument array is malloc'd as a single area, so only argv must
+ * be free'd.
+ *
+ * @param s string to parse
+ * @retval argcPtr address of returned no. of arguments
+ * @retval argvPtr address of returned argument array
+ */
+int poptParseArgvString(const char * s,
+ /*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr)
+ /*@modifies *argcPtr, *argvPtr @*/;
+
+/** \ingroup popt
+ * Parses an input configuration file and returns an string that is a
+ * command line. For use with popt. You must free the return value when done.
+ *
+ * Given the file:
+\verbatim
+# this line is ignored
+ # this one too
+aaa
+ bbb
+ ccc
+bla=bla
+
+this_is = fdsafdas
+ bad_line=
+ reall bad line
+ reall bad line = again
+5555= 55555
+ test = with lots of spaces
+\endverbatim
+*
+* The result is:
+\verbatim
+--aaa --bbb --ccc --bla="bla" --this_is="fdsafdas" --5555="55555" --test="with lots of spaces"
+\endverbatim
+*
+* Passing this to poptParseArgvString() yields an argv of:
+\verbatim
+'--aaa'
+'--bbb'
+'--ccc'
+'--bla=bla'
+'--this_is=fdsafdas'
+'--5555=55555'
+'--test=with lots of spaces'
+\endverbatim
+ *
+ * @bug NULL is returned if file line is too long.
+ * @bug Silently ignores invalid lines.
+ *
+ * @param fp file handle to read
+ * @param *argstrp return string of options (malloc'd)
+ * @param flags unused
+ * @return 0 on success
+ * @see poptParseArgvString
+ */
+/*@-fcnuse@*/
+int poptConfigFileToString(FILE *fp, /*@out@*/ char ** argstrp, int flags)
+ /*@globals fileSystem @*/
+ /*@modifies *fp, *argstrp, fileSystem @*/;
+/*@=fcnuse@*/
+
+/** \ingroup popt
+ * Return formatted error string for popt failure.
+ * @param error popt error
+ * @return error string
+ */
+/*@observer@*/ const char* poptStrerror(const int error)
+ /*@*/;
+
+/** \ingroup popt
+ * Limit search for executables.
+ * @param con context
+ * @param path single path to search for executables
+ * @param allowAbsolute absolute paths only?
+ */
+void poptSetExecPath(poptContext con, const char * path, int allowAbsolute)
+ /*@modifies con @*/;
+
+/** \ingroup popt
+ * Print detailed description of options.
+ * @param con context
+ * @param fp ouput file handle
+ * @param flags (unused)
+ */
+void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags)
+ /*@globals fileSystem @*/
+ /*@modifies *fp, fileSystem @*/;
+
+/** \ingroup popt
+ * Print terse description of options.
+ * @param con context
+ * @param fp ouput file handle
+ * @param flags (unused)
+ */
+void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags)
+ /*@globals fileSystem @*/
+ /*@modifies *fp, fileSystem @*/;
+
+/** \ingroup popt
+ * Provide text to replace default "[OPTION...]" in help/usage output.
+ * @param con context
+ * @param text replacement text
+ */
+/*@-fcnuse@*/
+void poptSetOtherOptionHelp(poptContext con, const char * text)
+ /*@modifies con @*/;
+/*@=fcnuse@*/
+
+/** \ingroup popt
+ * Return argv[0] from context.
+ * @param con context
+ * @return argv[0]
+ */
+/*@-fcnuse@*/
+/*@observer@*/ const char * poptGetInvocationName(poptContext con)
+ /*@*/;
+/*@=fcnuse@*/
+
+/** \ingroup popt
+ * Shuffle argv pointers to remove stripped args, returns new argc.
+ * @param con context
+ * @param argc no. of args
+ * @param argv arg vector
+ * @return new argc
+ */
+/*@-fcnuse@*/
+int poptStrippedArgv(poptContext con, int argc, char ** argv)
+ /*@modifies *argv @*/;
+/*@=fcnuse@*/
+
+/**
+ * Save a long, performing logical operation with value.
+ * @warning Alignment check may be too strict on certain platorms.
+ * @param arg integer pointer, aligned on int boundary.
+ * @param argInfo logical operation (see POPT_ARGFLAG_*)
+ * @param aLong value to use
+ * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION
+ */
+/*@-incondefs@*/
+/*@unused@*/
+int poptSaveLong(/*@null@*/ long * arg, int argInfo, long aLong)
+ /*@modifies *arg @*/
+ /*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/;
+/*@=incondefs@*/
+
+/**
+ * Save an integer, performing logical operation with value.
+ * @warning Alignment check may be too strict on certain platorms.
+ * @param arg integer pointer, aligned on int boundary.
+ * @param argInfo logical operation (see POPT_ARGFLAG_*)
+ * @param aLong value to use
+ * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION
+ */
+/*@-incondefs@*/
+/*@unused@*/
+int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong)
+ /*@modifies *arg @*/
+ /*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/;
+/*@=incondefs@*/
+
+/*@=type@*/
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source3/popt/poptconfig.c b/source3/popt/poptconfig.c
new file mode 100644
index 0000000000..837828ccf9
--- /dev/null
+++ b/source3/popt/poptconfig.c
@@ -0,0 +1,190 @@
+/** \ingroup popt
+ * \file popt/poptconfig.c
+ */
+
+/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
+ file accompanying popt source distributions, available from
+ ftp://ftp.rpm.org/pub/rpm/dist. */
+
+#include "system.h"
+#include "poptint.h"
+
+/*@-compmempass@*/ /* FIX: item->option.longName kept, not dependent. */
+static void configLine(poptContext con, char * line)
+ /*@modifies con @*/
+{
+ /*@-type@*/
+ int nameLength = strlen(con->appName);
+ /*@=type@*/
+ const char * entryType;
+ const char * opt;
+ poptItem item = (poptItem)alloca(sizeof(*item));
+ int i, j;
+
+/*@-boundswrite@*/
+ memset(item, 0, sizeof(*item));
+
+ /*@-type@*/
+ if (strncmp(line, con->appName, nameLength)) return;
+ /*@=type@*/
+
+ line += nameLength;
+ if (*line == '\0' || !isspace(*line)) return;
+
+ while (*line != '\0' && isspace(*line)) line++;
+ entryType = line;
+ while (*line == '\0' || !isspace(*line)) line++;
+ *line++ = '\0';
+
+ while (*line != '\0' && isspace(*line)) line++;
+ if (*line == '\0') return;
+ opt = line;
+ while (*line == '\0' || !isspace(*line)) line++;
+ *line++ = '\0';
+
+ while (*line != '\0' && isspace(*line)) line++;
+ if (*line == '\0') return;
+
+ /*@-temptrans@*/ /* FIX: line alias is saved */
+ if (opt[0] == '-' && opt[1] == '-')
+ item->option.longName = opt + 2;
+ else if (opt[0] == '-' && opt[2] == '\0')
+ item->option.shortName = opt[1];
+ /*@=temptrans@*/
+
+ if (poptParseArgvString(line, &item->argc, &item->argv)) return;
+
+ /*@-modobserver@*/
+ item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN;
+ for (i = 0, j = 0; i < item->argc; i++, j++) {
+ const char * f;
+ if (!strncmp(item->argv[i], "--POPTdesc=", sizeof("--POPTdesc=")-1)) {
+ f = item->argv[i] + sizeof("--POPTdesc=");
+ if (f[0] == '$' && f[1] == '"') f++;
+ item->option.descrip = f;
+ item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
+ j--;
+ } else
+ if (!strncmp(item->argv[i], "--POPTargs=", sizeof("--POPTargs=")-1)) {
+ f = item->argv[i] + sizeof("--POPTargs=");
+ if (f[0] == '$' && f[1] == '"') f++;
+ item->option.argDescrip = f;
+ item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
+ item->option.argInfo |= POPT_ARG_STRING;
+ j--;
+ } else
+ if (j != i)
+ item->argv[j] = item->argv[i];
+ }
+ if (j != i) {
+ item->argv[j] = NULL;
+ item->argc = j;
+ }
+ /*@=modobserver@*/
+/*@=boundswrite@*/
+
+ /*@-nullstate@*/ /* FIX: item->argv[] may be NULL */
+ if (!strcmp(entryType, "alias"))
+ (void) poptAddItem(con, item, 0);
+ else if (!strcmp(entryType, "exec"))
+ (void) poptAddItem(con, item, 1);
+ /*@=nullstate@*/
+}
+/*@=compmempass@*/
+
+int poptReadConfigFile(poptContext con, const char * fn)
+{
+ const char * file, * chptr, * end;
+ char * buf;
+/*@dependent@*/ char * dst;
+ int fd, rc;
+ off_t fileLength;
+
+ fd = open(fn, O_RDONLY);
+ if (fd < 0)
+ return (errno == ENOENT ? 0 : POPT_ERROR_ERRNO);
+
+ fileLength = lseek(fd, 0, SEEK_END);
+ if (fileLength == -1 || lseek(fd, 0, 0) == -1) {
+ rc = errno;
+ (void) close(fd);
+ /*@-mods@*/
+ errno = rc;
+ /*@=mods@*/
+ return POPT_ERROR_ERRNO;
+ }
+
+ file = (const char *)alloca(fileLength + 1);
+ if (read(fd, (char *)file, fileLength) != fileLength) {
+ rc = errno;
+ (void) close(fd);
+ /*@-mods@*/
+ errno = rc;
+ /*@=mods@*/
+ return POPT_ERROR_ERRNO;
+ }
+ if (close(fd) == -1)
+ return POPT_ERROR_ERRNO;
+
+/*@-boundswrite@*/
+ dst = buf = (char *)alloca(fileLength + 1);
+
+ chptr = file;
+ end = (file + fileLength);
+ /*@-infloops@*/ /* LCL: can't detect chptr++ */
+ while (chptr < end) {
+ switch (*chptr) {
+ case '\n':
+ *dst = '\0';
+ dst = buf;
+ while (*dst && isspace(*dst)) dst++;
+ if (*dst && *dst != '#')
+ configLine(con, dst);
+ chptr++;
+ /*@switchbreak@*/ break;
+ case '\\':
+ *dst++ = *chptr++;
+ if (chptr < end) {
+ if (*chptr == '\n')
+ dst--, chptr++;
+ /* \ at the end of a line does not insert a \n */
+ else
+ *dst++ = *chptr++;
+ }
+ /*@switchbreak@*/ break;
+ default:
+ *dst++ = *chptr++;
+ /*@switchbreak@*/ break;
+ }
+ }
+ /*@=infloops@*/
+/*@=boundswrite@*/
+
+ return 0;
+}
+
+int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv)
+{
+ char * fn, * home;
+ int rc;
+
+ /*@-type@*/
+ if (!con->appName) return 0;
+ /*@=type@*/
+
+ rc = poptReadConfigFile(con, "/etc/popt");
+ if (rc) return rc;
+#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
+ if (getuid() != geteuid()) return 0;
+#endif
+
+ if ((home = getenv("HOME"))) {
+ fn = (char *)alloca(strlen(home) + 20);
+ strcpy(fn, home);
+ strcat(fn, "/.popt");
+ rc = poptReadConfigFile(con, fn);
+ if (rc) return rc;
+ }
+
+ return 0;
+}
diff --git a/source3/popt/popthelp.c b/source3/popt/popthelp.c
new file mode 100644
index 0000000000..e965ff6168
--- /dev/null
+++ b/source3/popt/popthelp.c
@@ -0,0 +1,740 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/*@-type@*/
+/** \ingroup popt
+ * \file popt/popthelp.c
+ */
+
+/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
+ file accompanying popt source distributions, available from
+ ftp://ftp.rpm.org/pub/rpm/dist. */
+
+#include "system.h"
+#include "poptint.h"
+
+/**
+ * Display arguments.
+ * @param con context
+ * @param foo (unused)
+ * @param key option(s)
+ * @param arg (unused)
+ * @param data (unused)
+ */
+static void displayArgs(poptContext con,
+ /*@unused@*/ enum poptCallbackReason foo,
+ struct poptOption * key,
+ /*@unused@*/ const char * arg, /*@unused@*/ void * data)
+ /*@globals fileSystem@*/
+ /*@modifies fileSystem@*/
+{
+ if (key->shortName == '?')
+ poptPrintHelp(con, stdout, 0);
+ else
+ poptPrintUsage(con, stdout, 0);
+ exit(0);
+}
+
+#ifdef NOTYET
+/*@unchecked@*/
+static int show_option_defaults = 0;
+#endif
+
+/**
+ * Empty table marker to enable displaying popt alias/exec options.
+ */
+/*@observer@*/ /*@unchecked@*/
+struct poptOption poptAliasOptions[] = {
+ POPT_TABLEEND
+};
+
+/**
+ * Auto help table options.
+ */
+/*@-castfcnptr@*/
+/*@observer@*/ /*@unchecked@*/
+struct poptOption poptHelpOptions[] = {
+ { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
+ { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
+ { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
+#ifdef NOTYET
+ { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0,
+ N_("Display option defaults in message"), NULL },
+#endif
+ POPT_TABLEEND
+} ;
+/*@=castfcnptr@*/
+
+/**
+ * @param table option(s)
+ */
+/*@observer@*/ /*@null@*/ static const char *
+getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
+ /*@*/
+{
+ const struct poptOption *opt;
+
+ if (table != NULL)
+ for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
+ if (opt->argInfo == POPT_ARG_INTL_DOMAIN)
+ return (char *)opt->arg;
+ }
+ return NULL;
+}
+
+/**
+ * @param opt option(s)
+ * @param translation_domain translation domain
+ */
+/*@observer@*/ /*@null@*/ static const char *
+getArgDescrip(const struct poptOption * opt,
+ /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
+ /*@null@*/ const char * translation_domain)
+ /*@=paramuse@*/
+ /*@*/
+{
+ if (!(opt->argInfo & POPT_ARG_MASK)) return NULL;
+
+ if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2))
+ if (opt->argDescrip) return POPT_(opt->argDescrip);
+
+ if (opt->argDescrip) return D_(translation_domain, opt->argDescrip);
+
+ switch (opt->argInfo & POPT_ARG_MASK) {
+ case POPT_ARG_NONE: return POPT_("NONE");
+#ifdef DYING
+ case POPT_ARG_VAL: return POPT_("VAL");
+#else
+ case POPT_ARG_VAL: return NULL;
+#endif
+ case POPT_ARG_INT: return POPT_("INT");
+ case POPT_ARG_LONG: return POPT_("LONG");
+ case POPT_ARG_STRING: return POPT_("STRING");
+ case POPT_ARG_FLOAT: return POPT_("FLOAT");
+ case POPT_ARG_DOUBLE: return POPT_("DOUBLE");
+ default: return POPT_("ARG");
+ }
+}
+
+/**
+ * Display default value for an option.
+ * @param lineLength
+ * @param opt option(s)
+ * @param translation_domain translation domain
+ * @return
+ */
+static /*@only@*/ /*@null@*/ char *
+singleOptionDefaultValue(int lineLength,
+ const struct poptOption * opt,
+ /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
+ /*@null@*/ const char * translation_domain)
+ /*@=paramuse@*/
+ /*@*/
+{
+ const char * defstr = D_(translation_domain, "default");
+ char * le = (char *)malloc(4*lineLength + 1);
+ char * l = le;
+
+ if (le == NULL) return NULL; /* XXX can't happen */
+/*@-boundswrite@*/
+ *le = '\0';
+ *le++ = '(';
+ strcpy(le, defstr); le += strlen(le);
+ *le++ = ':';
+ *le++ = ' ';
+ if (opt->arg) /* XXX programmer error */
+ switch (opt->argInfo & POPT_ARG_MASK) {
+ case POPT_ARG_VAL:
+ case POPT_ARG_INT:
+ { long aLong = *((int *)opt->arg);
+ le += sprintf(le, "%ld", aLong);
+ } break;
+ case POPT_ARG_LONG:
+ { long aLong = *((long *)opt->arg);
+ le += sprintf(le, "%ld", aLong);
+ } break;
+ case POPT_ARG_FLOAT:
+ { double aDouble = *((float *)opt->arg);
+ le += sprintf(le, "%g", aDouble);
+ } break;
+ case POPT_ARG_DOUBLE:
+ { double aDouble = *((double *)opt->arg);
+ le += sprintf(le, "%g", aDouble);
+ } break;
+ case POPT_ARG_STRING:
+ { const char * s = *(const char **)opt->arg;
+ if (s == NULL) {
+ strcpy(le, "null"); le += strlen(le);
+ } else {
+ size_t slen = 4*lineLength - (le - l) - sizeof("\"...\")");
+ *le++ = '"';
+ strncpy(le, s, slen); le[slen] = '\0'; le += strlen(le);
+ if (slen < strlen(s)) {
+ strcpy(le, "..."); le += strlen(le);
+ }
+ *le++ = '"';
+ }
+ } break;
+ case POPT_ARG_NONE:
+ default:
+ l = (char *)_free(l);
+ return NULL;
+ /*@notreached@*/ break;
+ }
+ *le++ = ')';
+ *le = '\0';
+/*@=boundswrite@*/
+
+ return l;
+}
+
+/**
+ * Display help text for an option.
+ * @param fp output file handle
+ * @param maxLeftCol
+ * @param opt option(s)
+ * @param translation_domain translation domain
+ */
+static void singleOptionHelp(FILE * fp, int maxLeftCol,
+ const struct poptOption * opt,
+ /*@null@*/ const char * translation_domain)
+ /*@globals fileSystem @*/
+ /*@modifies *fp, fileSystem @*/
+{
+ int indentLength = maxLeftCol + 5;
+ int lineLength = 79 - indentLength;
+ const char * help = D_(translation_domain, opt->descrip);
+ const char * argDescrip = getArgDescrip(opt, translation_domain);
+ int helpLength;
+ char * defs = NULL;
+ char * left;
+ int nb = maxLeftCol + 1;
+
+ /* Make sure there's more than enough room in target buffer. */
+ if (opt->longName) nb += strlen(opt->longName);
+ if (argDescrip) nb += strlen(argDescrip);
+
+/*@-boundswrite@*/
+ left = (char *)malloc(nb);
+ if (left == NULL) return; /* XXX can't happen */
+ left[0] = '\0';
+ left[maxLeftCol] = '\0';
+
+ if (opt->longName && opt->shortName)
+ sprintf(left, "-%c, %s%s", opt->shortName,
+ ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
+ opt->longName);
+ else if (opt->shortName != '\0')
+ sprintf(left, "-%c", opt->shortName);
+ else if (opt->longName)
+ sprintf(left, "%s%s",
+ ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
+ opt->longName);
+ if (!*left) goto out;
+
+ if (argDescrip) {
+ char * le = left + strlen(left);
+
+ if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
+ *le++ = '[';
+
+ /* Choose type of output */
+ /*@-branchstate@*/
+ if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) {
+ defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
+ if (defs) {
+ char * t = (char *)malloc((help ? strlen(help) : 0) +
+ strlen(defs) + sizeof(" "));
+ if (t) {
+ char * te = t;
+ *te = '\0';
+ if (help) {
+ strcpy(te, help); te += strlen(te);
+ }
+ *te++ = ' ';
+ strcpy(te, defs);
+ defs = (char *)_free(defs);
+ }
+ defs = t;
+ }
+ }
+ /*@=branchstate@*/
+
+ if (opt->argDescrip == NULL) {
+ switch (opt->argInfo & POPT_ARG_MASK) {
+ case POPT_ARG_NONE:
+ break;
+ case POPT_ARG_VAL:
+#ifdef NOTNOW /* XXX pug ugly nerdy output */
+ { long aLong = opt->val;
+ int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS);
+ int negate = (opt->argInfo & POPT_ARGFLAG_NOT);
+
+ /* Don't bother displaying typical values */
+ if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L))
+ break;
+ *le++ = '[';
+ switch (ops) {
+ case POPT_ARGFLAG_OR:
+ *le++ = '|';
+ /*@innerbreak@*/ break;
+ case POPT_ARGFLAG_AND:
+ *le++ = '&';
+ /*@innerbreak@*/ break;
+ case POPT_ARGFLAG_XOR:
+ *le++ = '^';
+ /*@innerbreak@*/ break;
+ default:
+ /*@innerbreak@*/ break;
+ }
+ *le++ = '=';
+ if (negate) *le++ = '~';
+ /*@-formatconst@*/
+ le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong);
+ /*@=formatconst@*/
+ *le++ = ']';
+ }
+#endif
+ break;
+ case POPT_ARG_INT:
+ case POPT_ARG_LONG:
+ case POPT_ARG_FLOAT:
+ case POPT_ARG_DOUBLE:
+ case POPT_ARG_STRING:
+ *le++ = '=';
+ strcpy(le, argDescrip); le += strlen(le);
+ break;
+ default:
+ break;
+ }
+ } else {
+ *le++ = '=';
+ strcpy(le, argDescrip); le += strlen(le);
+ }
+ if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
+ *le++ = ']';
+ *le = '\0';
+ }
+/*@=boundswrite@*/
+
+ if (help)
+ fprintf(fp," %-*s ", maxLeftCol, left);
+ else {
+ fprintf(fp," %s\n", left);
+ goto out;
+ }
+
+ left = (char *)_free(left);
+ if (defs) {
+ help = defs; defs = NULL;
+ }
+
+ helpLength = strlen(help);
+/*@-boundsread@*/
+ while (helpLength > lineLength) {
+ const char * ch;
+ char format[16];
+
+ ch = help + lineLength - 1;
+ while (ch > help && !isspace(*ch)) ch--;
+ if (ch == help) break; /* give up */
+ while (ch > (help + 1) && isspace(*ch)) ch--;
+ ch++;
+
+ sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), indentLength);
+ /*@-formatconst@*/
+ fprintf(fp, format, help, " ");
+ /*@=formatconst@*/
+ help = ch;
+ while (isspace(*help) && *help) help++;
+ helpLength = strlen(help);
+ }
+/*@=boundsread@*/
+
+ if (helpLength) fprintf(fp, "%s\n", help);
+
+out:
+ /*@-dependenttrans@*/
+ defs = (char *)_free(defs);
+ /*@=dependenttrans@*/
+ left = (char *)_free(left);
+}
+
+/**
+ * @param opt option(s)
+ * @param translation_domain translation domain
+ */
+static int maxArgWidth(const struct poptOption * opt,
+ /*@null@*/ const char * translation_domain)
+ /*@*/
+{
+ int max = 0;
+ int len = 0;
+ const char * s;
+
+ if (opt != NULL)
+ while (opt->longName || opt->shortName || opt->arg) {
+ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
+ if (opt->arg) /* XXX program error */
+ len = maxArgWidth((const struct poptOption *)opt->arg, translation_domain);
+ if (len > max) max = len;
+ } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
+ len = sizeof(" ")-1;
+ if (opt->shortName != '\0') len += sizeof("-X")-1;
+ if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1;
+ if (opt->longName) {
+ len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH)
+ ? sizeof("-")-1 : sizeof("--")-1);
+ len += strlen(opt->longName);
+ }
+
+ s = getArgDescrip(opt, translation_domain);
+ if (s)
+ len += sizeof("=")-1 + strlen(s);
+ if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1;
+ if (len > max) max = len;
+ }
+
+ opt++;
+ }
+
+ return max;
+}
+
+/**
+ * Display popt alias and exec help.
+ * @param fp output file handle
+ * @param items alias/exec array
+ * @param nitems no. of alias/exec entries
+ * @param left
+ * @param translation_domain translation domain
+ */
+static void itemHelp(FILE * fp,
+ /*@null@*/ poptItem items, int nitems, int left,
+ /*@null@*/ const char * translation_domain)
+ /*@globals fileSystem @*/
+ /*@modifies *fp, fileSystem @*/
+{
+ poptItem item;
+ int i;
+
+ if (items != NULL)
+ for (i = 0, item = items; i < nitems; i++, item++) {
+ const struct poptOption * opt;
+ opt = &item->option;
+ if ((opt->longName || opt->shortName) &&
+ !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
+ singleOptionHelp(fp, left, opt, translation_domain);
+ }
+}
+
+/**
+ * Display help text for a table of options.
+ * @param con context
+ * @param fp output file handle
+ * @param table option(s)
+ * @param left
+ * @param translation_domain translation domain
+ */
+static void singleTableHelp(poptContext con, FILE * fp,
+ /*@null@*/ const struct poptOption * table, int left,
+ /*@null@*/ const char * translation_domain)
+ /*@globals fileSystem @*/
+ /*@modifies *fp, fileSystem @*/
+{
+ const struct poptOption * opt;
+ const char *sub_transdom;
+
+ if (table == poptAliasOptions) {
+ itemHelp(fp, con->aliases, con->numAliases, left, NULL);
+ itemHelp(fp, con->execs, con->numExecs, left, NULL);
+ return;
+ }
+
+ if (table != NULL)
+ for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
+ if ((opt->longName || opt->shortName) &&
+ !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
+ singleOptionHelp(fp, left, opt, translation_domain);
+ }
+
+ if (table != NULL)
+ for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
+ if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE)
+ continue;
+ sub_transdom = getTableTranslationDomain(
+ (const struct poptOption *)opt->arg);
+ if (sub_transdom == NULL)
+ sub_transdom = translation_domain;
+
+ if (opt->descrip)
+ fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
+
+ singleTableHelp(con, fp, (const struct poptOption *)opt->arg, left, sub_transdom);
+ }
+}
+
+/**
+ * @param con context
+ * @param fp output file handle
+ */
+static int showHelpIntro(poptContext con, FILE * fp)
+ /*@globals fileSystem @*/
+ /*@modifies *fp, fileSystem @*/
+{
+ int len = 6;
+ const char * fn;
+
+ fprintf(fp, POPT_("Usage:"));
+ if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
+/*@-boundsread@*/
+ /*@-nullderef@*/ /* LCL: wazzup? */
+ fn = con->optionStack->argv[0];
+ /*@=nullderef@*/
+/*@=boundsread@*/
+ if (fn == NULL) return len;
+ if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1;
+ fprintf(fp, " %s", fn);
+ len += strlen(fn) + 1;
+ }
+
+ return len;
+}
+
+void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags)
+{
+ int leftColWidth;
+
+ (void) showHelpIntro(con, fp);
+ if (con->otherHelp)
+ fprintf(fp, " %s\n", con->otherHelp);
+ else
+ fprintf(fp, " %s\n", POPT_("[OPTION...]"));
+
+ leftColWidth = maxArgWidth(con->options, NULL);
+ singleTableHelp(con, fp, con->options, leftColWidth, NULL);
+}
+
+/**
+ * @param fp output file handle
+ * @param cursor
+ * @param opt option(s)
+ * @param translation_domain translation domain
+ */
+static int singleOptionUsage(FILE * fp, int cursor,
+ const struct poptOption * opt,
+ /*@null@*/ const char *translation_domain)
+ /*@globals fileSystem @*/
+ /*@modifies *fp, fileSystem @*/
+{
+ int len = 4;
+ char shortStr[2] = { '\0', '\0' };
+ const char * item = shortStr;
+ const char * argDescrip = getArgDescrip(opt, translation_domain);
+
+ if (opt->shortName != '\0' && opt->longName != NULL) {
+ len += 2;
+ if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
+ len += strlen(opt->longName);
+ } else if (opt->shortName != '\0') {
+ len++;
+ shortStr[0] = opt->shortName;
+ shortStr[1] = '\0';
+ } else if (opt->longName) {
+ len += strlen(opt->longName);
+ if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
+ item = opt->longName;
+ }
+
+ if (len == 4) return cursor;
+
+ if (argDescrip)
+ len += strlen(argDescrip) + 1;
+
+ if ((cursor + len) > 79) {
+ fprintf(fp, "\n ");
+ cursor = 7;
+ }
+
+ if (opt->longName && opt->shortName) {
+ fprintf(fp, " [-%c|-%s%s%s%s]",
+ opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"),
+ opt->longName,
+ (argDescrip ? " " : ""),
+ (argDescrip ? argDescrip : ""));
+ } else {
+ fprintf(fp, " [-%s%s%s%s]",
+ ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"),
+ item,
+ (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""),
+ (argDescrip ? argDescrip : ""));
+ }
+
+ return cursor + len + 1;
+}
+
+/**
+ * Display popt alias and exec usage.
+ * @param fp output file handle
+ * @param cursor
+ * @param item alias/exec array
+ * @param nitems no. of ara/exec entries
+ * @param translation_domain translation domain
+ */
+static int itemUsage(FILE * fp, int cursor, poptItem item, int nitems,
+ /*@null@*/ const char * translation_domain)
+ /*@globals fileSystem @*/
+ /*@modifies *fp, fileSystem @*/
+{
+ int i;
+
+ /*@-branchstate@*/ /* FIX: W2DO? */
+ if (item != NULL)
+ for (i = 0; i < nitems; i++, item++) {
+ const struct poptOption * opt;
+ opt = &item->option;
+ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
+ translation_domain = (const char *)opt->arg;
+ } else if ((opt->longName || opt->shortName) &&
+ !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
+ cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
+ }
+ }
+ /*@=branchstate@*/
+
+ return cursor;
+}
+
+/**
+ * Keep track of option tables already processed.
+ */
+typedef struct poptDone_s {
+ int nopts;
+ int maxopts;
+ const void ** opts;
+} * poptDone;
+
+/**
+ * Display usage text for a table of options.
+ * @param con context
+ * @param fp output file handle
+ * @param cursor
+ * @param opt option(s)
+ * @param translation_domain translation domain
+ * @param done tables already processed
+ * @return
+ */
+static int singleTableUsage(poptContext con, FILE * fp, int cursor,
+ /*@null@*/ const struct poptOption * opt,
+ /*@null@*/ const char * translation_domain,
+ /*@null@*/ poptDone done)
+ /*@globals fileSystem @*/
+ /*@modifies *fp, done, fileSystem @*/
+{
+ /*@-branchstate@*/ /* FIX: W2DO? */
+ if (opt != NULL)
+ for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
+ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
+ translation_domain = (const char *)opt->arg;
+ } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
+ if (done) {
+ int i = 0;
+ for (i = 0; i < done->nopts; i++) {
+/*@-boundsread@*/
+ const void * that = done->opts[i];
+/*@=boundsread@*/
+ if (that == NULL || that != opt->arg)
+ /*@innercontinue@*/ continue;
+ /*@innerbreak@*/ break;
+ }
+ /* Skip if this table has already been processed. */
+ if (opt->arg == NULL || i < done->nopts)
+ continue;
+/*@-boundswrite@*/
+ if (done->nopts < done->maxopts)
+ done->opts[done->nopts++] = (const void *) opt->arg;
+/*@=boundswrite@*/
+ }
+ cursor = singleTableUsage(con, fp, cursor, (const struct poptOption *)opt->arg,
+ translation_domain, done);
+ } else if ((opt->longName || opt->shortName) &&
+ !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
+ cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
+ }
+ }
+ /*@=branchstate@*/
+
+ return cursor;
+}
+
+/**
+ * Return concatenated short options for display.
+ * @todo Sub-tables should be recursed.
+ * @param opt option(s)
+ * @param fp output file handle
+ * @retval str concatenation of short options
+ * @return length of display string
+ */
+static int showShortOptions(const struct poptOption * opt, FILE * fp,
+ /*@null@*/ char * str)
+ /*@globals fileSystem @*/
+ /*@modifies *str, *fp, fileSystem @*/
+ /*@requires maxRead(str) >= 0 @*/
+{
+ /* bufsize larger then the ascii set, lazy alloca on top level call. */
+ char * s = (str != NULL ? str : (char *)memset(alloca(300), 0, 300));
+ int len = 0;
+
+/*@-boundswrite@*/
+ if (opt != NULL)
+ for (; (opt->longName || opt->shortName || opt->arg); opt++) {
+ if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
+ s[strlen(s)] = opt->shortName;
+ else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
+ if (opt->arg) /* XXX program error */
+ len = showShortOptions(
+ (const struct poptOption *)opt->arg, fp, s);
+ }
+/*@=boundswrite@*/
+
+ /* On return to top level, print the short options, return print length. */
+ if (s == str && *s != '\0') {
+ fprintf(fp, " [-%s]", s);
+ len = strlen(s) + sizeof(" [-]")-1;
+ }
+ return len;
+}
+
+void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags)
+{
+ poptDone done = (poptDone)memset(alloca(sizeof(*done)), 0, sizeof(*done));
+ int cursor;
+
+ done->nopts = 0;
+ done->maxopts = 64;
+ cursor = done->maxopts * sizeof(*done->opts);
+/*@-boundswrite@*/
+ done->opts = (const void **)memset(alloca(cursor), 0, cursor);
+ done->opts[done->nopts++] = (const void *) con->options;
+/*@=boundswrite@*/
+
+ cursor = showHelpIntro(con, fp);
+ cursor += showShortOptions(con->options, fp, NULL);
+ cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done);
+ cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL);
+ cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL);
+
+ if (con->otherHelp) {
+ cursor += strlen(con->otherHelp) + 1;
+ if (cursor > 79) fprintf(fp, "\n ");
+ fprintf(fp, " %s", con->otherHelp);
+ }
+
+ fprintf(fp, "\n");
+}
+
+void poptSetOtherOptionHelp(poptContext con, const char * text)
+{
+ con->otherHelp = (const char *)_free(con->otherHelp);
+ con->otherHelp = xstrdup(text);
+}
+/*@=type@*/
diff --git a/source3/popt/poptint.h b/source3/popt/poptint.h
new file mode 100644
index 0000000000..5d308efe96
--- /dev/null
+++ b/source3/popt/poptint.h
@@ -0,0 +1,116 @@
+/** \ingroup popt
+ * \file popt/poptint.h
+ */
+
+/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
+ file accompanying popt source distributions, available from
+ ftp://ftp.rpm.org/pub/rpm/dist. */
+
+#ifndef H_POPTINT
+#define H_POPTINT
+
+/**
+ * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
+ * @param p memory to free
+ * @retval NULL always
+ */
+/*@unused@*/ static inline /*@null@*/ void *
+_free(/*@only@*/ /*@null@*/ const void * p)
+ /*@modifies p @*/
+{
+ if (p != NULL) free((void *)p);
+ return NULL;
+}
+
+/* Bit mask macros. */
+/*@-exporttype -redef @*/
+typedef unsigned int __pbm_bits;
+/*@=exporttype =redef @*/
+#define __PBM_NBITS (8 * sizeof (__pbm_bits))
+#define __PBM_IX(d) ((d) / __PBM_NBITS)
+#define __PBM_MASK(d) ((__pbm_bits) 1 << (((unsigned)(d)) % __PBM_NBITS))
+/*@-exporttype -redef @*/
+typedef struct {
+ __pbm_bits bits[1];
+} pbm_set;
+/*@=exporttype =redef @*/
+#define __PBM_BITS(set) ((set)->bits)
+
+#define PBM_ALLOC(d) calloc(__PBM_IX (d) + 1, sizeof(__pbm_bits))
+#define PBM_FREE(s) _free(s);
+#define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d))
+#define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d))
+#define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0)
+
+struct optionStackEntry {
+ int argc;
+/*@only@*/ /*@null@*/
+ const char ** argv;
+/*@only@*/ /*@null@*/
+ pbm_set * argb;
+ int next;
+/*@only@*/ /*@null@*/
+ const char * nextArg;
+/*@observer@*/ /*@null@*/
+ const char * nextCharArg;
+/*@dependent@*/ /*@null@*/
+ poptItem currAlias;
+ int stuffed;
+};
+
+struct poptContext_s {
+ struct optionStackEntry optionStack[POPT_OPTION_DEPTH];
+/*@dependent@*/
+ struct optionStackEntry * os;
+/*@owned@*/ /*@null@*/
+ const char ** leftovers;
+ int numLeftovers;
+ int nextLeftover;
+/*@keep@*/
+ const struct poptOption * options;
+ int restLeftover;
+/*@only@*/ /*@null@*/
+ const char * appName;
+/*@only@*/ /*@null@*/
+ poptItem aliases;
+ int numAliases;
+ int flags;
+/*@owned@*/ /*@null@*/
+ poptItem execs;
+ int numExecs;
+/*@only@*/ /*@null@*/
+ const char ** finalArgv;
+ int finalArgvCount;
+ int finalArgvAlloced;
+/*@dependent@*/ /*@null@*/
+ poptItem doExec;
+/*@only@*/
+ const char * execPath;
+ int execAbsolute;
+/*@only@*/
+ const char * otherHelp;
+/*@null@*/
+ pbm_set * arg_strip;
+};
+
+#ifdef HAVE_LIBINTL_H
+#include <libintl.h>
+#endif
+
+#if defined(HAVE_GETTEXT) && !defined(__LCLINT__)
+#define _(foo) gettext(foo)
+#else
+#define _(foo) foo
+#endif
+
+#if defined(HAVE_DCGETTEXT) && !defined(__LCLINT__)
+#define D_(dom, str) dgettext(dom, str)
+#define POPT_(foo) D_("popt", foo)
+#else
+#define D_(dom, str) str
+#define POPT_(foo) foo
+#endif
+
+#define N_(foo) foo
+
+#endif
diff --git a/source3/popt/poptparse.c b/source3/popt/poptparse.c
new file mode 100644
index 0000000000..b03deef085
--- /dev/null
+++ b/source3/popt/poptparse.c
@@ -0,0 +1,227 @@
+/** \ingroup popt
+ * \file popt/poptparse.c
+ */
+
+/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
+ file accompanying popt source distributions, available from
+ ftp://ftp.rpm.org/pub/rpm/dist. */
+
+#include "system.h"
+
+#define POPT_ARGV_ARRAY_GROW_DELTA 5
+
+/*@-boundswrite@*/
+int poptDupArgv(int argc, const char **argv,
+ int * argcPtr, const char *** argvPtr)
+{
+ size_t nb = (argc + 1) * sizeof(*argv);
+ const char ** argv2;
+ char * dst;
+ int i;
+
+ if (argc <= 0 || argv == NULL) /* XXX can't happen */
+ return POPT_ERROR_NOARG;
+ for (i = 0; i < argc; i++) {
+ if (argv[i] == NULL)
+ return POPT_ERROR_NOARG;
+ nb += strlen(argv[i]) + 1;
+ }
+
+ dst = (char *)malloc(nb);
+ if (dst == NULL) /* XXX can't happen */
+ return POPT_ERROR_MALLOC;
+ argv2 = (const char **) dst;
+ dst += (argc + 1) * sizeof(*argv);
+
+ /*@-branchstate@*/
+ for (i = 0; i < argc; i++) {
+ argv2[i] = dst;
+ dst += strlen(strcpy(dst, argv[i])) + 1;
+ }
+ /*@=branchstate@*/
+ argv2[argc] = NULL;
+
+ if (argvPtr) {
+ *argvPtr = argv2;
+ } else {
+ free(argv2);
+ argv2 = NULL;
+ }
+ if (argcPtr)
+ *argcPtr = argc;
+ return 0;
+}
+/*@=boundswrite@*/
+
+/*@-bounds@*/
+int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
+{
+ const char * src;
+ char quote = '\0';
+ int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
+ const char ** argv = (const char **)malloc(sizeof(*argv) * argvAlloced);
+ int argc = 0;
+ int buflen = strlen(s) + 1;
+ char * buf = (char*)memset(alloca(buflen), 0, buflen);
+ int rc = POPT_ERROR_MALLOC;
+
+ if (argv == NULL) return rc;
+ argv[argc] = buf;
+
+ for (src = s; *src != '\0'; src++) {
+ if (quote == *src) {
+ quote = '\0';
+ } else if (quote != '\0') {
+ if (*src == '\\') {
+ src++;
+ if (!*src) {
+ rc = POPT_ERROR_BADQUOTE;
+ goto exit;
+ }
+ if (*src != quote) *buf++ = '\\';
+ }
+ *buf++ = *src;
+ } else if (isspace(*src)) {
+ if (*argv[argc] != '\0') {
+ buf++, argc++;
+ if (argc == argvAlloced) {
+ argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
+ argv = (const char **)realloc(argv, sizeof(*argv) * argvAlloced);
+ if (argv == NULL) goto exit;
+ }
+ argv[argc] = buf;
+ }
+ } else switch (*src) {
+ case '"':
+ case '\'':
+ quote = *src;
+ /*@switchbreak@*/ break;
+ case '\\':
+ src++;
+ if (!*src) {
+ rc = POPT_ERROR_BADQUOTE;
+ goto exit;
+ }
+ /*@fallthrough@*/
+ default:
+ *buf++ = *src;
+ /*@switchbreak@*/ break;
+ }
+ }
+
+ if (strlen(argv[argc])) {
+ argc++, buf++;
+ }
+
+ rc = poptDupArgv(argc, argv, argcPtr, argvPtr);
+
+exit:
+ if (argv) free(argv);
+ return rc;
+}
+/*@=bounds@*/
+
+/* still in the dev stage.
+ * return values, perhaps 1== file erro
+ * 2== line to long
+ * 3== umm.... more?
+ */
+int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ int flags)
+{
+ char line[999];
+ char * argstr;
+ char * p;
+ char * q;
+ char * x;
+ int t;
+ int argvlen = 0;
+ size_t maxlinelen = sizeof(line);
+ size_t linelen;
+ int maxargvlen = 480;
+ int linenum = 0;
+
+ *argstrp = NULL;
+
+ /* | this_is = our_line
+ * p q x
+ */
+
+ if (fp == NULL)
+ return POPT_ERROR_NULLARG;
+
+ argstr = (char *)calloc(maxargvlen, sizeof(*argstr));
+ if (argstr == NULL) return POPT_ERROR_MALLOC;
+
+ while (fgets(line, (int)maxlinelen, fp) != NULL) {
+ linenum++;
+ p = line;
+
+ /* loop until first non-space char or EOL */
+ while( *p != '\0' && isspace(*p) )
+ p++;
+
+ linelen = strlen(p);
+ if (linelen >= maxlinelen-1)
+ return POPT_ERROR_OVERFLOW; /* XXX line too long */
+
+ if (*p == '\0' || *p == '\n') continue; /* line is empty */
+ if (*p == '#') continue; /* comment line */
+
+ q = p;
+
+ while (*q != '\0' && (!isspace(*q)) && *q != '=')
+ q++;
+
+ if (isspace(*q)) {
+ /* a space after the name, find next non space */
+ *q++='\0';
+ while( *q != '\0' && isspace((int)*q) ) q++;
+ }
+ if (*q == '\0') {
+ /* single command line option (ie, no name=val, just name) */
+ q[-1] = '\0'; /* kill off newline from fgets() call */
+ argvlen += (t = q - p) + (sizeof(" --")-1);
+ if (argvlen >= maxargvlen) {
+ maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2;
+ argstr = (char *)realloc(argstr, maxargvlen);
+ if (argstr == NULL) return POPT_ERROR_MALLOC;
+ }
+ strcat(argstr, " --");
+ strcat(argstr, p);
+ continue;
+ }
+ if (*q != '=')
+ continue; /* XXX for now, silently ignore bogus line */
+
+ /* *q is an equal sign. */
+ *q++ = '\0';
+
+ /* find next non-space letter of value */
+ while (*q != '\0' && isspace(*q))
+ q++;
+ if (*q == '\0')
+ continue; /* XXX silently ignore missing value */
+
+ /* now, loop and strip all ending whitespace */
+ x = p + linelen;
+ while (isspace(*--x))
+ *x = 0; /* null out last char if space (including fgets() NL) */
+
+ /* rest of line accept */
+ t = x - p;
+ argvlen += t + (sizeof("' --='")-1);
+ if (argvlen >= maxargvlen) {
+ maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2;
+ argstr = (char *)realloc(argstr, maxargvlen);
+ if (argstr == NULL) return POPT_ERROR_MALLOC;
+ }
+ strcat(argstr, " --");
+ strcat(argstr, p);
+ strcat(argstr, "=\"");
+ strcat(argstr, q);
+ strcat(argstr, "\"");
+ }
+
+ *argstrp = argstr;
+ return 0;
+}
diff --git a/source3/popt/system.h b/source3/popt/system.h
new file mode 100644
index 0000000000..1d1b9dae88
--- /dev/null
+++ b/source3/popt/system.h
@@ -0,0 +1,76 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined (__GLIBC__) && defined(__LCLINT__)
+/*@-declundef@*/
+/*@unchecked@*/
+extern __const __int32_t *__ctype_tolower;
+/*@unchecked@*/
+extern __const __int32_t *__ctype_toupper;
+/*@=declundef@*/
+#endif
+
+#include <ctype.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+
+#if HAVE_MCHECK_H
+#include <mcheck.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef __NeXT
+/* access macros are not declared in non posix mode in unistd.h -
+ don't try to use posix on NeXTstep 3.3 ! */
+#include <libc.h>
+#endif
+
+#if defined(__LCLINT__)
+/*@-declundef -incondefs -redecl@*/ /* LCL: missing annotation */
+/*@only@*/ void * alloca (size_t __size)
+ /*@ensures MaxSet(result) == (__size - 1) @*/
+ /*@*/;
+/*@=declundef =incondefs =redecl@*/
+#endif
+
+/* AIX requires this to be the first thing in the file. */
+#ifndef __GNUC__
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef _AIX
+#pragma alloca
+# else
+# ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+# endif
+# endif
+# endif
+#elif defined(__GNUC__) && defined(__STRICT_ANSI__)
+#define alloca __builtin_alloca
+#endif
+
+/*@-redecl -redef@*/
+/*@mayexit@*/ /*@only@*/ char * xstrdup (const char *str)
+ /*@*/;
+/*@=redecl =redef@*/
+
+#if HAVE_MCHECK_H && defined(__GNUC__)
+#define vmefail() (fprintf(stderr, "virtual memory exhausted.\n"), exit(EXIT_FAILURE), NULL)
+#define xstrdup(_str) (strcpy((malloc(strlen(_str)+1) ? : vmefail()), (_str)))
+#else
+#define xstrdup(_str) strdup(_str)
+#endif /* HAVE_MCHECK_H && defined(__GNUC__) */
+
+
+#include "popt.h"
diff --git a/source3/printing/load.c b/source3/printing/load.c
new file mode 100644
index 0000000000..23144d5a95
--- /dev/null
+++ b/source3/printing/load.c
@@ -0,0 +1,64 @@
+/*
+ Unix SMB/CIFS implementation.
+ load printer lists
+ Copyright (C) Andrew Tridgell 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+
+/***************************************************************************
+auto-load some homes and printer services
+***************************************************************************/
+static void add_auto_printers(void)
+{
+ const char *p;
+ int pnum = lp_servicenumber(PRINTERS_NAME);
+ char *str;
+ char *saveptr;
+
+ if (pnum < 0)
+ return;
+
+ if ((str = SMB_STRDUP(lp_auto_services())) == NULL)
+ return;
+
+ for (p = strtok_r(str, LIST_SEP, &saveptr); p;
+ p = strtok_r(NULL, LIST_SEP, &saveptr)) {
+ if (lp_servicenumber(p) >= 0)
+ continue;
+
+ if (pcap_printername_ok(p))
+ lp_add_printer(p, pnum);
+ }
+
+ SAFE_FREE(str);
+}
+
+/***************************************************************************
+load automatic printer services
+***************************************************************************/
+void load_printers(void)
+{
+ if (!pcap_cache_loaded())
+ pcap_cache_reload();
+
+ add_auto_printers();
+
+ /* load all printcap printers */
+ if (lp_load_printers() && lp_servicenumber(PRINTERS_NAME) >= 0)
+ pcap_printer_fn(lp_add_one_printer);
+}
diff --git a/source3/printing/lpq_parse.c b/source3/printing/lpq_parse.c
new file mode 100644
index 0000000000..addf2d14aa
--- /dev/null
+++ b/source3/printing/lpq_parse.c
@@ -0,0 +1,1152 @@
+/*
+ Unix SMB/CIFS implementation.
+ lpq parsing routines
+ Copyright (C) Andrew Tridgell 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static const char *Months[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Err"};
+
+
+/*******************************************************************
+ Process time fields
+********************************************************************/
+
+static time_t EntryTime(char *tok[], int ptr, int count, int minimum)
+{
+ time_t jobtime,jobtime1;
+
+ jobtime = time(NULL); /* default case: take current time */
+ if (count >= minimum) {
+ struct tm *t;
+ int i, day, hour, min, sec;
+
+ for (i=0; i<13; i++) {
+ if (!strncmp(tok[ptr], Months[i],3)) {
+ break; /* Find month */
+ }
+ }
+
+ if (i<12) {
+ fstring c;
+ t = localtime(&jobtime);
+ if (!t) {
+ return (time_t)-1;
+ }
+ day = atoi(tok[ptr+1]);
+ fstrcpy(c,tok[ptr+2]);
+ *(c+2)=0;
+ hour = atoi(c);
+ *(c+5)=0;
+ min = atoi(c+3);
+ if(*(c+6) != 0) {
+ sec = atoi(c+6);
+ } else {
+ sec=0;
+ }
+
+ if ((t->tm_mon < i)|| ((t->tm_mon == i)&&
+ ((t->tm_mday < day)||
+ ((t->tm_mday == day)&&
+ (t->tm_hour*60+t->tm_min < hour*60+min))))) {
+ t->tm_year--; /* last year's print job */
+ }
+
+ t->tm_mon = i;
+ t->tm_mday = day;
+ t->tm_hour = hour;
+ t->tm_min = min;
+ t->tm_sec = sec;
+ jobtime1 = mktime(t);
+ if (jobtime1 != (time_t)-1) {
+ jobtime = jobtime1;
+ }
+ }
+ }
+ return jobtime;
+}
+
+/****************************************************************************
+parse a lpq line
+
+here is an example of lpq output under bsd
+
+Warning: no daemon present
+Rank Owner Job Files Total Size
+1st tridge 148 README 8096 bytes
+
+here is an example of lpq output under osf/1
+
+Warning: no daemon present
+Rank Pri Owner Job Files Total Size
+1st 0 tridge 148 README 8096 bytes
+
+
+<allan@umich.edu> June 30, 1998.
+Modified to handle file names with spaces, like the parse_lpq_lprng code
+further below.
+****************************************************************************/
+
+static bool parse_lpq_bsd(char *line,print_queue_struct *buf,bool first)
+{
+#ifdef OSF1
+#define RANKTOK 0
+#define PRIOTOK 1
+#define USERTOK 2
+#define JOBTOK 3
+#define FILETOK 4
+#define TOTALTOK (count - 2)
+#define NTOK 6
+#define MAXTOK 128
+#else /* OSF1 */
+#define RANKTOK 0
+#define USERTOK 1
+#define JOBTOK 2
+#define FILETOK 3
+#define TOTALTOK (count - 2)
+#define NTOK 5
+#define MAXTOK 128
+#endif /* OSF1 */
+
+ char *tok[MAXTOK];
+ int count = 0;
+ TALLOC_CTX *ctx = talloc_tos();
+ char *line2 = NULL;
+ char *saveptr;
+
+ line2 = talloc_strdup(ctx, line);
+ if (!line2) {
+ return false;
+ }
+
+#ifdef OSF1
+ {
+ size_t length;
+ length = strlen(line2);
+ if (line2[length-3] == ':') {
+ return False;
+ }
+ }
+#endif /* OSF1 */
+
+ /* FIXME: Use next_token_talloc rather than strtok! */
+ tok[0] = strtok_r(line2," \t", &saveptr);
+ count++;
+
+ while ((count < MAXTOK)
+ && ((tok[count] = strtok_r(NULL, " \t", &saveptr)) != NULL)) {
+ count++;
+ }
+
+ /* we must get at least NTOK tokens */
+ if (count < NTOK) {
+ return False;
+ }
+
+ /* the Job and Total columns must be integer */
+ if (!isdigit((int)*tok[JOBTOK]) || !isdigit((int)*tok[TOTALTOK])) {
+ return False;
+ }
+
+ buf->job = atoi(tok[JOBTOK]);
+ buf->size = atoi(tok[TOTALTOK]);
+ buf->status = strequal(tok[RANKTOK],"active")?LPQ_PRINTING:LPQ_QUEUED;
+ buf->time = time(NULL);
+ fstrcpy(buf->fs_user,tok[USERTOK]);
+ fstrcpy(buf->fs_file,tok[FILETOK]);
+
+ if ((FILETOK + 1) != TOTALTOK) {
+ int i;
+
+ for (i = (FILETOK + 1); i < TOTALTOK; i++) {
+ /* FIXME: Using fstrcat rather than other means is a bit
+ * inefficient; this might be a problem for enormous queues with
+ * many fields. */
+ fstrcat(buf->fs_file, " ");
+ fstrcat(buf->fs_file, tok[i]);
+ }
+ /* Ensure null termination. */
+ buf->fs_file[sizeof(buf->fs_file)-1] = '\0';
+ }
+
+#ifdef PRIOTOK
+ buf->priority = atoi(tok[PRIOTOK]);
+#else
+ buf->priority = 1;
+#endif
+ return True;
+}
+
+/*
+<magnus@hum.auc.dk>
+LPRng_time modifies the current date by inserting the hour and minute from
+the lpq output. The lpq time looks like "23:15:07"
+
+<allan@umich.edu> June 30, 1998.
+Modified to work with the re-written parse_lpq_lprng routine.
+
+<J.P.M.v.Itegem@tue.nl> Dec 17,1999
+Modified to work with lprng 3.16
+With lprng 3.16 The lpq time looks like
+ "23:15:07"
+ "23:15:07.100"
+ "1999-12-16-23:15:07"
+ "1999-12-16-23:15:07.100"
+
+*/
+static time_t LPRng_time(char *time_string)
+{
+ time_t jobtime;
+ struct tm *t;
+
+ jobtime = time(NULL); /* default case: take current time */
+ t = localtime(&jobtime);
+ if (!t) {
+ return (time_t)-1;
+ }
+
+ if ( atoi(time_string) < 24 ){
+ t->tm_hour = atoi(time_string);
+ t->tm_min = atoi(time_string+3);
+ t->tm_sec = atoi(time_string+6);
+ } else {
+ t->tm_year = atoi(time_string)-1900;
+ t->tm_mon = atoi(time_string+5)-1;
+ t->tm_mday = atoi(time_string+8);
+ t->tm_hour = atoi(time_string+11);
+ t->tm_min = atoi(time_string+14);
+ t->tm_sec = atoi(time_string+17);
+ }
+ jobtime = mktime(t);
+
+ return jobtime;
+}
+
+/****************************************************************************
+ parse a lprng lpq line
+ <allan@umich.edu> June 30, 1998.
+ Re-wrote this to handle file names with spaces, multiple file names on one
+ lpq line, etc;
+
+****************************************************************************/
+
+static bool parse_lpq_lprng(char *line,print_queue_struct *buf,bool first)
+{
+#define LPRNG_RANKTOK 0
+#define LPRNG_USERTOK 1
+#define LPRNG_PRIOTOK 2
+#define LPRNG_JOBTOK 3
+#define LPRNG_FILETOK 4
+#define LPRNG_TOTALTOK (num_tok - 2)
+#define LPRNG_TIMETOK (num_tok - 1)
+#define LPRNG_NTOK 7
+#define LPRNG_MAXTOK 128 /* PFMA just to keep us from running away. */
+
+ char *tokarr[LPRNG_MAXTOK];
+ const char *cptr;
+ char *ptr;
+ int num_tok = 0;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ cptr = line;
+ while((num_tok < LPRNG_MAXTOK) && next_token_talloc(frame, &cptr,
+ &tokarr[num_tok], " \t")) {
+ num_tok++;
+ }
+
+ /* We must get at least LPRNG_NTOK tokens. */
+ if (num_tok < LPRNG_NTOK) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ if (!isdigit((int)*tokarr[LPRNG_JOBTOK]) || !isdigit((int)*tokarr[LPRNG_TOTALTOK])) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ buf->job = atoi(tokarr[LPRNG_JOBTOK]);
+ buf->size = atoi(tokarr[LPRNG_TOTALTOK]);
+
+ if (strequal(tokarr[LPRNG_RANKTOK],"active")) {
+ buf->status = LPQ_PRINTING;
+ } else if (strequal(tokarr[LPRNG_RANKTOK],"done")) {
+ buf->status = LPQ_PRINTED;
+ } else if (isdigit((int)*tokarr[LPRNG_RANKTOK])) {
+ buf->status = LPQ_QUEUED;
+ } else {
+ buf->status = LPQ_PAUSED;
+ }
+
+ buf->priority = *tokarr[LPRNG_PRIOTOK] -'A';
+
+ buf->time = LPRng_time(tokarr[LPRNG_TIMETOK]);
+
+ fstrcpy(buf->fs_user,tokarr[LPRNG_USERTOK]);
+
+ /* The '@hostname' prevents windows from displaying the printing icon
+ * for the current user on the taskbar. Plop in a null.
+ */
+
+ if ((ptr = strchr_m(buf->fs_user,'@')) != NULL) {
+ *ptr = '\0';
+ }
+
+ fstrcpy(buf->fs_file,tokarr[LPRNG_FILETOK]);
+
+ if ((LPRNG_FILETOK + 1) != LPRNG_TOTALTOK) {
+ int i;
+
+ for (i = (LPRNG_FILETOK + 1); i < LPRNG_TOTALTOK; i++) {
+ /* FIXME: Using fstrcat rather than other means is a bit
+ * inefficient; this might be a problem for enormous queues with
+ * many fields. */
+ fstrcat(buf->fs_file, " ");
+ fstrcat(buf->fs_file, tokarr[i]);
+ }
+ /* Ensure null termination. */
+ buf->fs_file[sizeof(buf->fs_file)-1] = '\0';
+ }
+
+ TALLOC_FREE(frame);
+ return True;
+}
+
+/*******************************************************************
+parse lpq on an aix system
+
+Queue Dev Status Job Files User PP % Blks Cp Rnk
+------- ----- --------- --- ------------------ ---------- ---- -- ----- --- ---
+lazer lazer READY
+lazer lazer RUNNING 537 6297doc.A kvintus@IE 0 10 2445 1 1
+ QUEUED 538 C.ps root@IEDVB 124 1 2
+ QUEUED 539 E.ps root@IEDVB 28 1 3
+ QUEUED 540 L.ps root@IEDVB 172 1 4
+ QUEUED 541 P.ps root@IEDVB 22 1 5
+********************************************************************/
+
+static bool parse_lpq_aix(char *line,print_queue_struct *buf,bool first)
+{
+ char *tok[11];
+ int count=0;
+ const char *cline = line;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ /* handle the case of "(standard input)" as a filename */
+ string_sub(line,"standard input","STDIN",0);
+ all_string_sub(line,"(","\"",0);
+ all_string_sub(line,")","\"",0);
+
+ for (count=0; count<10 &&
+ next_token_talloc(frame,&cline,&tok[count],NULL); count++) {
+ ;
+ }
+
+ /* we must get 6 tokens */
+ if (count < 10) {
+ if ((count == 7) && ((strcmp(tok[0],"QUEUED") == 0) || (strcmp(tok[0],"HELD") == 0))) {
+ /* the 2nd and 5th columns must be integer */
+ if (!isdigit((int)*tok[1]) || !isdigit((int)*tok[4])) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+ buf->size = atoi(tok[4]) * 1024;
+ /* if the fname contains a space then use STDIN */
+ if (strchr_m(tok[2],' ')) {
+ tok[2] = talloc_strdup(frame,"STDIN");
+ if (!tok[2]) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+ }
+
+ /* only take the last part of the filename */
+ {
+ char *p = strrchr_m(tok[2],'/');
+ if (p) {
+ tok[2] = p+1;
+ }
+ }
+
+ buf->job = atoi(tok[1]);
+ buf->status = strequal(tok[0],"HELD")?LPQ_PAUSED:LPQ_QUEUED;
+ buf->priority = 0;
+ buf->time = time(NULL);
+ fstrcpy(buf->fs_user,tok[3]);
+ fstrcpy(buf->fs_file,tok[2]);
+ } else {
+ DEBUG(6,("parse_lpq_aix count=%d\n", count));
+ TALLOC_FREE(frame);
+ return False;
+ }
+ } else {
+ /* the 4th and 9th columns must be integer */
+ if (!isdigit((int)*tok[3]) || !isdigit((int)*tok[8])) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ buf->size = atoi(tok[8]) * 1024;
+ /* if the fname contains a space then use STDIN */
+ if (strchr_m(tok[4],' ')) {
+ tok[4] = talloc_strdup(frame,"STDIN");
+ if (!tok[4]) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+ }
+
+ /* only take the last part of the filename */
+ {
+ char *p = strrchr_m(tok[4],'/');
+ if (p) {
+ tok[4] = p+1;
+ }
+ }
+
+ buf->job = atoi(tok[3]);
+ buf->status = strequal(tok[2],"RUNNING")?LPQ_PRINTING:LPQ_QUEUED;
+ buf->priority = 0;
+ buf->time = time(NULL);
+ fstrcpy(buf->fs_user,tok[5]);
+ fstrcpy(buf->fs_file,tok[4]);
+ }
+
+ TALLOC_FREE(frame);
+ return True;
+}
+
+/****************************************************************************
+parse a lpq line
+here is an example of lpq output under hpux; note there's no space after -o !
+$> lpstat -oljplus
+ljplus-2153 user priority 0 Jan 19 08:14 on ljplus
+ util.c 125697 bytes
+ server.c 110712 bytes
+ljplus-2154 user priority 0 Jan 19 08:14 from client
+ (standard input) 7551 bytes
+****************************************************************************/
+
+static bool parse_lpq_hpux(char *line, print_queue_struct *buf, bool first)
+{
+ /* must read two lines to process, therefore keep some values static */
+ static bool header_line_ok=False, base_prio_reset=False;
+ static char *jobuser;
+ static int jobid;
+ static int jobprio;
+ static time_t jobtime;
+ static int jobstat=LPQ_QUEUED;
+ /* to store minimum priority to print, lpstat command should be invoked
+ with -p option first, to work */
+ static int base_prio;
+ int count;
+ char htab = '\011';
+ const char *cline = line;
+ char *tok[12];
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ /* If a line begins with a horizontal TAB, it is a subline type */
+
+ if (line[0] == htab) { /* subline */
+ /* check if it contains the base priority */
+ if (!strncmp(line,"\tfence priority : ",18)) {
+ base_prio=atoi(&line[18]);
+ DEBUG(4, ("fence priority set at %d\n", base_prio));
+ }
+
+ if (!header_line_ok) {
+ TALLOC_FREE(frame);
+ return False; /* incorrect header line */
+ }
+
+ /* handle the case of "(standard input)" as a filename */
+ string_sub(line,"standard input","STDIN",0);
+ all_string_sub(line,"(","\"",0);
+ all_string_sub(line,")","\"",0);
+
+ for (count=0; count<2 &&
+ next_token_talloc(frame, &cline, &tok[count],NULL);
+ count++) {
+ ;
+ }
+ /* we must get 2 tokens */
+ if (count < 2) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ /* the 2nd column must be integer */
+ if (!isdigit((int)*tok[1])) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ /* if the fname contains a space then use STDIN */
+ if (strchr_m(tok[0],' ')) {
+ tok[0] = talloc_strdup(frame, "STDIN");
+ if (!tok[0]) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+ }
+
+ buf->size = atoi(tok[1]);
+ fstrcpy(buf->fs_file,tok[0]);
+
+ /* fill things from header line */
+ buf->time = jobtime;
+ buf->job = jobid;
+ buf->status = jobstat;
+ buf->priority = jobprio;
+ if (jobuser) {
+ fstrcpy(buf->fs_user,jobuser);
+ } else {
+ buf->fs_user[0] = '\0';
+ }
+
+ TALLOC_FREE(frame);
+ return True;
+ } else { /* header line */
+ header_line_ok=False; /* reset it */
+ if (first) {
+ if (!base_prio_reset) {
+ base_prio=0; /* reset it */
+ base_prio_reset=True;
+ }
+ } else if (base_prio) {
+ base_prio_reset=False;
+ }
+
+ /* handle the dash in the job id */
+ string_sub(line,"-"," ",0);
+
+ for (count=0; count<12 &&
+ next_token_talloc(frame, &cline, &tok[count],NULL);
+ count++) {
+ ;
+ }
+
+ /* we must get 8 tokens */
+ if (count < 8) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ /* first token must be printer name (cannot check ?) */
+ /* the 2nd, 5th & 7th column must be integer */
+ if (!isdigit((int)*tok[1]) || !isdigit((int)*tok[4]) || !isdigit((int)*tok[6])) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+ jobid = atoi(tok[1]);
+ SAFE_FREE(jobuser);
+ jobuser = SMB_STRDUP(tok[2]);
+ jobprio = atoi(tok[4]);
+
+ /* process time */
+ jobtime=EntryTime(tok, 5, count, 8);
+ if (jobprio < base_prio) {
+ jobstat = LPQ_PAUSED;
+ DEBUG (4, ("job %d is paused: prio %d < %d; jobstat=%d\n",
+ jobid, jobprio, base_prio, jobstat));
+ } else {
+ jobstat = LPQ_QUEUED;
+ if ((count >8) && (((strequal(tok[8],"on")) ||
+ ((strequal(tok[8],"from")) &&
+ ((count > 10)&&(strequal(tok[10],"on"))))))) {
+ jobstat = LPQ_PRINTING;
+ }
+ }
+
+ header_line_ok=True; /* information is correct */
+ TALLOC_FREE(frame);
+ return False; /* need subline info to include into queuelist */
+ }
+}
+
+/****************************************************************************
+parse a lpstat line
+
+here is an example of "lpstat -o dcslw" output under sysv
+
+dcslw-896 tridge 4712 Dec 20 10:30:30 on dcslw
+dcslw-897 tridge 4712 Dec 20 10:30:30 being held
+
+****************************************************************************/
+
+static bool parse_lpq_sysv(char *line,print_queue_struct *buf,bool first)
+{
+ char *tok[9];
+ int count=0;
+ char *p;
+ const char *cline = line;
+ TALLOC_CTX *frame = NULL;
+
+ /*
+ * Handle the dash in the job id, but make sure that we skip over
+ * the printer name in case we have a dash in that.
+ * Patch from Dom.Mitchell@palmerharvey.co.uk.
+ */
+
+ /*
+ * Move to the first space.
+ */
+ for (p = line ; !isspace(*p) && *p; p++) {
+ ;
+ }
+
+ /*
+ * Back up until the last '-' character or
+ * start of line.
+ */
+ for (; (p >= line) && (*p != '-'); p--) {
+ ;
+ }
+
+ if((p >= line) && (*p == '-')) {
+ *p = ' ';
+ }
+
+ frame = talloc_stackframe();
+ for (count=0; count<9 &&
+ next_token_talloc(frame, &cline, &tok[count],NULL);
+ count++) {
+ ;
+ }
+
+ /* we must get 7 tokens */
+ if (count < 7) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ /* the 2nd and 4th, 6th columns must be integer */
+ if (!isdigit((int)*tok[1]) || !isdigit((int)*tok[3])) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+ if (!isdigit((int)*tok[5])) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ /* if the user contains a ! then trim the first part of it */
+ if ((p=strchr_m(tok[2],'!'))) {
+ tok[2] = p+1;
+ }
+
+ buf->job = atoi(tok[1]);
+ buf->size = atoi(tok[3]);
+ if (count > 7 && strequal(tok[7],"on")) {
+ buf->status = LPQ_PRINTING;
+ } else if (count > 8 && strequal(tok[7],"being") && strequal(tok[8],"held")) {
+ buf->status = LPQ_PAUSED;
+ } else {
+ buf->status = LPQ_QUEUED;
+ }
+ buf->priority = 0;
+ buf->time = EntryTime(tok, 4, count, 7);
+ fstrcpy(buf->fs_user,tok[2]);
+ fstrcpy(buf->fs_file,tok[2]);
+ TALLOC_FREE(frame);
+ return True;
+}
+
+/****************************************************************************
+parse a lpq line
+
+here is an example of lpq output under qnx
+Spooler: /qnx/spooler, on node 1
+Printer: txt (ready)
+0000: root [job #1 ] active 1146 bytes /etc/profile
+0001: root [job #2 ] ready 2378 bytes /etc/install
+0002: root [job #3 ] ready 1146 bytes -- standard input --
+****************************************************************************/
+
+static bool parse_lpq_qnx(char *line,print_queue_struct *buf,bool first)
+{
+ char *tok[7];
+ int count=0;
+ const char *cline = line;
+ TALLOC_CTX *frame = NULL;
+
+ DEBUG(4,("antes [%s]\n", line));
+
+ /* handle the case of "-- standard input --" as a filename */
+ string_sub(line,"standard input","STDIN",0);
+ DEBUG(4,("despues [%s]\n", line));
+ all_string_sub(line,"-- ","\"",0);
+ all_string_sub(line," --","\"",0);
+ DEBUG(4,("despues 1 [%s]\n", line));
+
+ string_sub(line,"[job #","",0);
+ string_sub(line,"]","",0);
+ DEBUG(4,("despues 2 [%s]\n", line));
+
+ frame = talloc_stackframe();
+ for (count=0; count<7 &&
+ next_token_talloc(frame,&cline,&tok[count],NULL);
+ count++) {
+ ;
+ }
+
+ /* we must get 7 tokens */
+ if (count < 7) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ /* the 3rd and 5th columns must be integer */
+ if (!isdigit((int)*tok[2]) || !isdigit((int)*tok[4])) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ /* only take the last part of the filename */
+ {
+ char *p = strrchr_m(tok[6],'/');
+ if (p) {
+ tok[6] = p+1;
+ }
+ }
+
+ buf->job = atoi(tok[2]);
+ buf->size = atoi(tok[4]);
+ buf->status = strequal(tok[3],"active")?LPQ_PRINTING:LPQ_QUEUED;
+ buf->priority = 0;
+ buf->time = time(NULL);
+ fstrcpy(buf->fs_user,tok[1]);
+ fstrcpy(buf->fs_file,tok[6]);
+ TALLOC_FREE(frame);
+ return True;
+}
+
+/****************************************************************************
+ parse a lpq line for the plp printing system
+ Bertrand Wallrich <Bertrand.Wallrich@loria.fr>
+
+redone by tridge. Here is a sample queue:
+
+Local Printer 'lp2' (fjall):
+ Printing (started at Jun 15 13:33:58, attempt 1).
+ Rank Owner Pr Opt Job Host Files Size Date
+ active tridge X - 6 fjall /etc/hosts 739 Jun 15 13:33
+ 3rd tridge X - 7 fjall /etc/hosts 739 Jun 15 13:33
+
+****************************************************************************/
+
+static bool parse_lpq_plp(char *line,print_queue_struct *buf,bool first)
+{
+ char *tok[11];
+ int count=0;
+ const char *cline = line;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ /* handle the case of "(standard input)" as a filename */
+ string_sub(line,"stdin","STDIN",0);
+ all_string_sub(line,"(","\"",0);
+ all_string_sub(line,")","\"",0);
+
+ for (count=0; count<11 &&
+ next_token_talloc(frame,&cline,&tok[count],NULL);
+ count++) {
+ ;
+ }
+
+ /* we must get 11 tokens */
+ if (count < 11) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ /* the first must be "active" or begin with an integer */
+ if (strcmp(tok[0],"active") && !isdigit((int)tok[0][0])) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ /* the 5th and 8th must be integer */
+ if (!isdigit((int)*tok[4]) || !isdigit((int)*tok[7])) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ /* if the fname contains a space then use STDIN */
+ if (strchr_m(tok[6],' ')) {
+ tok[6] = talloc_strdup(frame, "STDIN");
+ if (!tok[6]) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+ }
+
+ /* only take the last part of the filename */
+ {
+ fstring tmp;
+ char *p = strrchr_m(tok[6],'/');
+ if (p) {
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[6],tmp);
+ }
+ }
+
+ buf->job = atoi(tok[4]);
+
+ buf->size = atoi(tok[7]);
+ if (strchr_m(tok[7],'K')) {
+ buf->size *= 1024;
+ }
+ if (strchr_m(tok[7],'M')) {
+ buf->size *= 1024*1024;
+ }
+
+ buf->status = strequal(tok[0],"active")?LPQ_PRINTING:LPQ_QUEUED;
+ buf->priority = 0;
+ buf->time = time(NULL);
+ fstrcpy(buf->fs_user,tok[1]);
+ fstrcpy(buf->fs_file,tok[6]);
+ TALLOC_FREE(frame);
+ return True;
+}
+
+/*******************************************************************
+parse lpq on an NT system
+
+ Windows 2000 LPD Server
+ Printer \\10.0.0.2\NP17PCL (Paused)
+
+Owner Status Jobname Job-Id Size Pages Priority
+----------------------------------------------------------------------------
+root (9.99. Printing /usr/lib/rhs/rhs-pr 3 625 0 1
+root (9.99. Paused /usr/lib/rhs/rhs-pr 4 625 0 1
+jmcd Waiting Re: Samba Open Sour 26 32476 1 1
+
+********************************************************************/
+
+static bool parse_lpq_nt(char *line,print_queue_struct *buf,bool first)
+{
+#define LPRNT_OWNSIZ 11
+#define LPRNT_STATSIZ 9
+#define LPRNT_JOBSIZ 19
+#define LPRNT_IDSIZ 6
+#define LPRNT_SIZSIZ 9
+ typedef struct {
+ char owner[LPRNT_OWNSIZ];
+ char space1;
+ char status[LPRNT_STATSIZ];
+ char space2;
+ char jobname[LPRNT_JOBSIZ];
+ char space3;
+ char jobid[LPRNT_IDSIZ];
+ char space4;
+ char size[LPRNT_SIZSIZ];
+ char terminator;
+ } nt_lpq_line;
+
+ char parse_line_char[sizeof(nt_lpq_line)];
+ nt_lpq_line *parse_line = (nt_lpq_line *)parse_line_char;
+#define LPRNT_PRINTING "Printing"
+#define LPRNT_WAITING "Waiting"
+#define LPRNT_PAUSED "Paused"
+
+ memset(parse_line_char, '\0', sizeof(parse_line_char));
+ strncpy(parse_line_char, line, sizeof(parse_line_char) -1);
+
+ if (strlen(parse_line_char) != sizeof(parse_line_char) - 1) {
+ return False;
+ }
+
+ /* Just want the first word in the owner field - the username */
+ if (strchr_m(parse_line->owner, ' ')) {
+ *(strchr_m(parse_line->owner, ' ')) = '\0';
+ } else {
+ parse_line->space1 = '\0';
+ }
+
+ /* Make sure we have an owner */
+ if (!strlen(parse_line->owner)) {
+ return False;
+ }
+
+ /* Make sure the status is valid */
+ parse_line->space2 = '\0';
+ trim_char(parse_line->status, '\0', ' ');
+ if (!strequal(parse_line->status, LPRNT_PRINTING) &&
+ !strequal(parse_line->status, LPRNT_PAUSED) &&
+ !strequal(parse_line->status, LPRNT_WAITING)) {
+ return False;
+ }
+
+ parse_line->space3 = '\0';
+ trim_char(parse_line->jobname, '\0', ' ');
+
+ buf->job = atoi(parse_line->jobid);
+ buf->priority = 0;
+ buf->size = atoi(parse_line->size);
+ buf->time = time(NULL);
+ fstrcpy(buf->fs_user, parse_line->owner);
+ fstrcpy(buf->fs_file, parse_line->jobname);
+ if (strequal(parse_line->status, LPRNT_PRINTING)) {
+ buf->status = LPQ_PRINTING;
+ } else if (strequal(parse_line->status, LPRNT_PAUSED)) {
+ buf->status = LPQ_PAUSED;
+ } else {
+ buf->status = LPQ_QUEUED;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+parse lpq on an OS2 system
+
+JobID File Name Rank Size Status Comment
+----- --------------- ------ -------- ------------ ------------
+ 3 Control 1 68 Queued root@psflinu
+ 4 /etc/motd 2 11666 Queued root@psflinu
+
+********************************************************************/
+
+static bool parse_lpq_os2(char *line,print_queue_struct *buf,bool first)
+{
+#define LPROS2_IDSIZ 5
+#define LPROS2_JOBSIZ 15
+#define LPROS2_SIZSIZ 8
+#define LPROS2_STATSIZ 12
+#define LPROS2_OWNSIZ 12
+ typedef struct {
+ char jobid[LPROS2_IDSIZ];
+ char space1[2];
+ char jobname[LPROS2_JOBSIZ];
+ char space2[14];
+ char size[LPROS2_SIZSIZ];
+ char space3[4];
+ char status[LPROS2_STATSIZ];
+ char space4[4];
+ char owner[LPROS2_OWNSIZ];
+ char terminator;
+ } os2_lpq_line;
+
+ char parse_line_char[sizeof(os2_lpq_line)];
+ os2_lpq_line *parse_line = (os2_lpq_line *)parse_line_char;
+#define LPROS2_PRINTING "Printing"
+#define LPROS2_WAITING "Queued"
+#define LPROS2_PAUSED "Paused"
+
+ memset(parse_line_char, '\0', sizeof(parse_line_char));
+ strncpy(parse_line_char, line, sizeof(parse_line_char) -1);
+
+ if (strlen(parse_line_char) != sizeof(parse_line_char) - 1) {
+ return False;
+ }
+
+ /* Get the jobid */
+ buf->job = atoi(parse_line->jobid);
+
+ /* Get the job name */
+ parse_line->space2[0] = '\0';
+ trim_char(parse_line->jobname, '\0', ' ');
+ fstrcpy(buf->fs_file, parse_line->jobname);
+
+ buf->priority = 0;
+ buf->size = atoi(parse_line->size);
+ buf->time = time(NULL);
+
+ /* Make sure we have an owner */
+ if (!strlen(parse_line->owner)) {
+ return False;
+ }
+
+ /* Make sure we have a valid status */
+ parse_line->space4[0] = '\0';
+ trim_char(parse_line->status, '\0', ' ');
+ if (!strequal(parse_line->status, LPROS2_PRINTING) &&
+ !strequal(parse_line->status, LPROS2_PAUSED) &&
+ !strequal(parse_line->status, LPROS2_WAITING)) {
+ return False;
+ }
+
+ fstrcpy(buf->fs_user, parse_line->owner);
+ if (strequal(parse_line->status, LPROS2_PRINTING)) {
+ buf->status = LPQ_PRINTING;
+ } else if (strequal(parse_line->status, LPROS2_PAUSED)) {
+ buf->status = LPQ_PAUSED;
+ } else {
+ buf->status = LPQ_QUEUED;
+ }
+
+ return True;
+}
+
+static const char *stat0_strings[] = { "enabled", "online", "idle", "no entries", "free", "ready", NULL };
+static const char *stat1_strings[] = { "offline", "disabled", "down", "off", "waiting", "no daemon", NULL };
+static const char *stat2_strings[] = { "jam", "paper", "error", "responding", "not accepting", "not running", "turned off", NULL };
+
+#ifdef DEVELOPER
+
+/****************************************************************************
+parse a vlp line
+****************************************************************************/
+
+static bool parse_lpq_vlp(char *line,print_queue_struct *buf,bool first)
+{
+ int toknum = 0;
+ char *tok;
+ TALLOC_CTX *frame = talloc_stackframe();
+ const char *cline = line;
+
+ /* First line is printer status */
+
+ if (!isdigit(line[0])) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ /* Parse a print job entry */
+
+ while(next_token_talloc(frame, &cline, &tok, NULL)) {
+ switch (toknum) {
+ case 0:
+ buf->job = atoi(tok);
+ break;
+ case 1:
+ buf->size = atoi(tok);
+ break;
+ case 2:
+ buf->status = atoi(tok);
+ break;
+ case 3:
+ buf->time = atoi(tok);
+ break;
+ case 4:
+ fstrcpy(buf->fs_user, tok);
+ break;
+ case 5:
+ fstrcpy(buf->fs_file, tok);
+ break;
+ }
+ toknum++;
+ }
+
+ TALLOC_FREE(frame);
+ return True;
+}
+
+#endif /* DEVELOPER */
+
+/****************************************************************************
+parse a lpq line. Choose printing style
+****************************************************************************/
+
+bool parse_lpq_entry(enum printing_types printing_type,char *line,
+ print_queue_struct *buf,
+ print_status_struct *status,bool first)
+{
+ bool ret;
+
+ switch (printing_type) {
+ case PRINT_SYSV:
+ ret = parse_lpq_sysv(line,buf,first);
+ break;
+ case PRINT_AIX:
+ ret = parse_lpq_aix(line,buf,first);
+ break;
+ case PRINT_HPUX:
+ ret = parse_lpq_hpux(line,buf,first);
+ break;
+ case PRINT_QNX:
+ ret = parse_lpq_qnx(line,buf,first);
+ break;
+ case PRINT_LPRNG:
+ ret = parse_lpq_lprng(line,buf,first);
+ break;
+ case PRINT_PLP:
+ ret = parse_lpq_plp(line,buf,first);
+ break;
+ case PRINT_LPRNT:
+ ret = parse_lpq_nt(line,buf,first);
+ break;
+ case PRINT_LPROS2:
+ ret = parse_lpq_os2(line,buf,first);
+ break;
+#ifdef DEVELOPER
+ case PRINT_VLP:
+ case PRINT_TEST:
+ ret = parse_lpq_vlp(line,buf,first);
+ break;
+#endif /* DEVELOPER */
+ default:
+ ret = parse_lpq_bsd(line,buf,first);
+ break;
+ }
+
+ /* We don't want the newline in the status message. */
+ {
+ char *p = strchr_m(line,'\n');
+ if (p) {
+ *p = 0;
+ }
+ }
+
+ /* in the LPRNG case, we skip lines starting by a space.*/
+ if (!ret && (printing_type==PRINT_LPRNG) ) {
+ if (line[0]==' ') {
+ return ret;
+ }
+ }
+
+ if (status && !ret) {
+ /* a few simple checks to see if the line might be a
+ printer status line:
+ handle them so that most severe condition is shown */
+ int i;
+ strlower_m(line);
+
+ switch (status->status) {
+ case LPSTAT_OK:
+ for (i=0; stat0_strings[i]; i++) {
+ if (strstr_m(line,stat0_strings[i])) {
+ fstrcpy(status->message,line);
+ status->status=LPSTAT_OK;
+ return ret;
+ }
+ }
+ /* fallthrough */
+ case LPSTAT_STOPPED:
+ for (i=0; stat1_strings[i]; i++) {
+ if (strstr_m(line,stat1_strings[i])) {
+ fstrcpy(status->message,line);
+ status->status=LPSTAT_STOPPED;
+ return ret;
+ }
+ }
+ /* fallthrough */
+ case LPSTAT_ERROR:
+ for (i=0; stat2_strings[i]; i++) {
+ if (strstr_m(line,stat2_strings[i])) {
+ fstrcpy(status->message,line);
+ status->status=LPSTAT_ERROR;
+ return ret;
+ }
+ }
+ break;
+ }
+ }
+
+ return ret;
+}
diff --git a/source3/printing/notify.c b/source3/printing/notify.c
new file mode 100644
index 0000000000..23df17c389
--- /dev/null
+++ b/source3/printing/notify.c
@@ -0,0 +1,571 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ printing backend routines
+ Copyright (C) Tim Potter, 2002
+ Copyright (C) Gerald Carter, 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "printing.h"
+
+static TALLOC_CTX *send_ctx;
+
+static unsigned int num_messages;
+
+static struct notify_queue {
+ struct notify_queue *next, *prev;
+ struct spoolss_notify_msg *msg;
+ struct timeval tv;
+ uint8 *buf;
+ size_t buflen;
+} *notify_queue_head = NULL;
+
+
+static bool create_send_ctx(void)
+{
+ if (!send_ctx)
+ send_ctx = talloc_init("print notify queue");
+
+ if (!send_ctx)
+ return False;
+
+ return True;
+}
+
+/****************************************************************************
+ Turn a queue name into a snum.
+****************************************************************************/
+
+int print_queue_snum(const char *qname)
+{
+ int snum = lp_servicenumber(qname);
+ if (snum == -1 || !lp_print_ok(snum))
+ return -1;
+ return snum;
+}
+
+/*******************************************************************
+ Used to decide if we need a short select timeout.
+*******************************************************************/
+
+bool print_notify_messages_pending(void)
+{
+ return (notify_queue_head != NULL);
+}
+
+/*******************************************************************
+ Flatten data into a message.
+*******************************************************************/
+
+static bool flatten_message(struct notify_queue *q)
+{
+ struct spoolss_notify_msg *msg = q->msg;
+ uint8 *buf = NULL;
+ size_t buflen = 0, len;
+
+again:
+ len = 0;
+
+ /* Pack header */
+
+ len += tdb_pack(buf + len, buflen - len, "f", msg->printer);
+
+ len += tdb_pack(buf + len, buflen - len, "ddddddd",
+ (uint32)q->tv.tv_sec, (uint32)q->tv.tv_usec,
+ msg->type, msg->field, msg->id, msg->len, msg->flags);
+
+ /* Pack data */
+
+ if (msg->len == 0)
+ len += tdb_pack(buf + len, buflen - len, "dd",
+ msg->notify.value[0], msg->notify.value[1]);
+ else
+ len += tdb_pack(buf + len, buflen - len, "B",
+ msg->len, msg->notify.data);
+
+ if (buflen != len) {
+ buf = (uint8 *)TALLOC_REALLOC(send_ctx, buf, len);
+ if (!buf)
+ return False;
+ buflen = len;
+ goto again;
+ }
+
+ q->buf = buf;
+ q->buflen = buflen;
+
+ return True;
+}
+
+/*******************************************************************
+ Send the batched messages - on a per-printer basis.
+*******************************************************************/
+
+static void print_notify_send_messages_to_printer(struct messaging_context *msg_ctx,
+ const char *printer,
+ unsigned int timeout)
+{
+ char *buf;
+ struct notify_queue *pq, *pq_next;
+ size_t msg_count = 0, offset = 0;
+ size_t num_pids = 0;
+ size_t i;
+ pid_t *pid_list = NULL;
+ struct timeval end_time = timeval_zero();
+
+ /* Count the space needed to send the messages. */
+ for (pq = notify_queue_head; pq; pq = pq->next) {
+ if (strequal(printer, pq->msg->printer)) {
+ if (!flatten_message(pq)) {
+ DEBUG(0,("print_notify_send_messages: Out of memory\n"));
+ talloc_free_children(send_ctx);
+ num_messages = 0;
+ return;
+ }
+ offset += (pq->buflen + 4);
+ msg_count++;
+ }
+ }
+ offset += 4; /* For count. */
+
+ buf = (char *)TALLOC(send_ctx, offset);
+ if (!buf) {
+ DEBUG(0,("print_notify_send_messages: Out of memory\n"));
+ talloc_free_children(send_ctx);
+ num_messages = 0;
+ return;
+ }
+
+ offset = 0;
+ SIVAL(buf,offset,msg_count);
+ offset += 4;
+ for (pq = notify_queue_head; pq; pq = pq_next) {
+ pq_next = pq->next;
+
+ if (strequal(printer, pq->msg->printer)) {
+ SIVAL(buf,offset,pq->buflen);
+ offset += 4;
+ memcpy(buf + offset, pq->buf, pq->buflen);
+ offset += pq->buflen;
+
+ /* Remove from list. */
+ DLIST_REMOVE(notify_queue_head, pq);
+ }
+ }
+
+ DEBUG(5, ("print_notify_send_messages_to_printer: sending %lu print notify message%s to printer %s\n",
+ (unsigned long)msg_count, msg_count != 1 ? "s" : "", printer));
+
+ /*
+ * Get the list of PID's to send to.
+ */
+
+ if (!print_notify_pid_list(printer, send_ctx, &num_pids, &pid_list))
+ return;
+
+ if (timeout != 0) {
+ end_time = timeval_current_ofs(timeout, 0);
+ }
+
+ for (i = 0; i < num_pids; i++) {
+ messaging_send_buf(msg_ctx,
+ pid_to_procid(pid_list[i]),
+ MSG_PRINTER_NOTIFY2 | MSG_FLAG_LOWPRIORITY,
+ (uint8 *)buf, offset);
+
+ if ((timeout != 0) && timeval_expired(&end_time)) {
+ break;
+ }
+ }
+}
+
+/*******************************************************************
+ Actually send the batched messages.
+*******************************************************************/
+
+void print_notify_send_messages(struct messaging_context *msg_ctx,
+ unsigned int timeout)
+{
+ if (!print_notify_messages_pending())
+ return;
+
+ if (!create_send_ctx())
+ return;
+
+ while (print_notify_messages_pending())
+ print_notify_send_messages_to_printer(
+ msg_ctx, notify_queue_head->msg->printer, timeout);
+
+ talloc_free_children(send_ctx);
+ num_messages = 0;
+}
+
+/**********************************************************************
+ deep copy a SPOOLSS_NOTIFY_MSG structure using a TALLOC_CTX
+ *********************************************************************/
+
+static bool copy_notify2_msg( SPOOLSS_NOTIFY_MSG *to, SPOOLSS_NOTIFY_MSG *from )
+{
+
+ if ( !to || !from )
+ return False;
+
+ memcpy( to, from, sizeof(SPOOLSS_NOTIFY_MSG) );
+
+ if ( from->len ) {
+ to->notify.data = (char *)TALLOC_MEMDUP(send_ctx, from->notify.data, from->len );
+ if ( !to->notify.data ) {
+ DEBUG(0,("copy_notify2_msg: TALLOC_MEMDUP() of size [%d] failed!\n", from->len ));
+ return False;
+ }
+ }
+
+
+ return True;
+}
+
+/*******************************************************************
+ Batch up print notify messages.
+*******************************************************************/
+
+static void send_spoolss_notify2_msg(SPOOLSS_NOTIFY_MSG *msg)
+{
+ struct notify_queue *pnqueue, *tmp_ptr;
+
+ /*
+ * Ensure we only have one job total_bytes and job total_pages for
+ * each job. There is no point in sending multiple messages that match
+ * as they will just cause flickering updates in the client.
+ */
+
+ if ((num_messages < 100) && (msg->type == JOB_NOTIFY_TYPE)
+ && (msg->field == JOB_NOTIFY_TOTAL_BYTES
+ || msg->field == JOB_NOTIFY_TOTAL_PAGES ))
+ {
+
+ for (tmp_ptr = notify_queue_head; tmp_ptr; tmp_ptr = tmp_ptr->next)
+ {
+ if (tmp_ptr->msg->type == msg->type &&
+ tmp_ptr->msg->field == msg->field &&
+ tmp_ptr->msg->id == msg->id &&
+ tmp_ptr->msg->flags == msg->flags &&
+ strequal(tmp_ptr->msg->printer, msg->printer)) {
+
+ DEBUG(5,("send_spoolss_notify2_msg: replacing message 0x%02x/0x%02x for "
+ "printer %s in notify_queue\n", msg->type, msg->field, msg->printer));
+
+ tmp_ptr->msg = msg;
+ return;
+ }
+ }
+ }
+
+ /* Store the message on the pending queue. */
+
+ pnqueue = TALLOC_P(send_ctx, struct notify_queue);
+ if (!pnqueue) {
+ DEBUG(0,("send_spoolss_notify2_msg: Out of memory.\n"));
+ return;
+ }
+
+ /* allocate a new msg structure and copy the fields */
+
+ if ( !(pnqueue->msg = TALLOC_P(send_ctx, SPOOLSS_NOTIFY_MSG)) ) {
+ DEBUG(0,("send_spoolss_notify2_msg: talloc() of size [%lu] failed!\n",
+ (unsigned long)sizeof(SPOOLSS_NOTIFY_MSG)));
+ return;
+ }
+ copy_notify2_msg(pnqueue->msg, msg);
+ GetTimeOfDay(&pnqueue->tv);
+ pnqueue->buf = NULL;
+ pnqueue->buflen = 0;
+
+ DEBUG(5, ("send_spoolss_notify2_msg: appending message 0x%02x/0x%02x for printer %s \
+to notify_queue_head\n", msg->type, msg->field, msg->printer));
+
+ /*
+ * Note we add to the end of the list to ensure
+ * the messages are sent in the order they were received. JRA.
+ */
+
+ DLIST_ADD_END(notify_queue_head, pnqueue, struct notify_queue *);
+ num_messages++;
+}
+
+static void send_notify_field_values(const char *sharename, uint32 type,
+ uint32 field, uint32 id, uint32 value1,
+ uint32 value2, uint32 flags)
+{
+ struct spoolss_notify_msg *msg;
+
+ if (lp_disable_spoolss())
+ return;
+
+ if (!create_send_ctx())
+ return;
+
+ msg = TALLOC_P(send_ctx, struct spoolss_notify_msg);
+ if (!msg)
+ return;
+
+ ZERO_STRUCTP(msg);
+
+ fstrcpy(msg->printer, sharename);
+ msg->type = type;
+ msg->field = field;
+ msg->id = id;
+ msg->notify.value[0] = value1;
+ msg->notify.value[1] = value2;
+ msg->flags = flags;
+
+ send_spoolss_notify2_msg(msg);
+}
+
+static void send_notify_field_buffer(const char *sharename, uint32 type,
+ uint32 field, uint32 id, uint32 len,
+ const char *buffer)
+{
+ struct spoolss_notify_msg *msg;
+
+ if (lp_disable_spoolss())
+ return;
+
+ if (!create_send_ctx())
+ return;
+
+ msg = TALLOC_P(send_ctx, struct spoolss_notify_msg);
+ if (!msg)
+ return;
+
+ ZERO_STRUCTP(msg);
+
+ fstrcpy(msg->printer, sharename);
+ msg->type = type;
+ msg->field = field;
+ msg->id = id;
+ msg->len = len;
+ msg->notify.data = CONST_DISCARD(char *,buffer);
+
+ send_spoolss_notify2_msg(msg);
+}
+
+/* Send a message that the printer status has changed */
+
+void notify_printer_status_byname(const char *sharename, uint32 status)
+{
+ /* Printer status stored in value1 */
+
+ send_notify_field_values(sharename, PRINTER_NOTIFY_TYPE,
+ PRINTER_NOTIFY_STATUS, 0,
+ status, 0, 0);
+}
+
+void notify_printer_status(int snum, uint32 status)
+{
+ const char *sharename = SERVICE(snum);
+
+ if (sharename)
+ notify_printer_status_byname(sharename, status);
+}
+
+void notify_job_status_byname(const char *sharename, uint32 jobid, uint32 status,
+ uint32 flags)
+{
+ /* Job id stored in id field, status in value1 */
+
+ send_notify_field_values(sharename, JOB_NOTIFY_TYPE,
+ JOB_NOTIFY_STATUS, jobid,
+ status, 0, flags);
+}
+
+void notify_job_status(const char *sharename, uint32 jobid, uint32 status)
+{
+ notify_job_status_byname(sharename, jobid, status, 0);
+}
+
+void notify_job_total_bytes(const char *sharename, uint32 jobid,
+ uint32 size)
+{
+ /* Job id stored in id field, status in value1 */
+
+ send_notify_field_values(sharename, JOB_NOTIFY_TYPE,
+ JOB_NOTIFY_TOTAL_BYTES, jobid,
+ size, 0, 0);
+}
+
+void notify_job_total_pages(const char *sharename, uint32 jobid,
+ uint32 pages)
+{
+ /* Job id stored in id field, status in value1 */
+
+ send_notify_field_values(sharename, JOB_NOTIFY_TYPE,
+ JOB_NOTIFY_TOTAL_PAGES, jobid,
+ pages, 0, 0);
+}
+
+void notify_job_username(const char *sharename, uint32 jobid, char *name)
+{
+ send_notify_field_buffer(
+ sharename, JOB_NOTIFY_TYPE, JOB_NOTIFY_USER_NAME,
+ jobid, strlen(name) + 1, name);
+}
+
+void notify_job_name(const char *sharename, uint32 jobid, char *name)
+{
+ send_notify_field_buffer(
+ sharename, JOB_NOTIFY_TYPE, JOB_NOTIFY_DOCUMENT,
+ jobid, strlen(name) + 1, name);
+}
+
+void notify_job_submitted(const char *sharename, uint32 jobid,
+ time_t submitted)
+{
+ send_notify_field_buffer(
+ sharename, JOB_NOTIFY_TYPE, JOB_NOTIFY_SUBMITTED,
+ jobid, sizeof(submitted), (char *)&submitted);
+}
+
+void notify_printer_driver(int snum, char *driver_name)
+{
+ const char *sharename = SERVICE(snum);
+
+ send_notify_field_buffer(
+ sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DRIVER_NAME,
+ snum, strlen(driver_name) + 1, driver_name);
+}
+
+void notify_printer_comment(int snum, char *comment)
+{
+ const char *sharename = SERVICE(snum);
+
+ send_notify_field_buffer(
+ sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_COMMENT,
+ snum, strlen(comment) + 1, comment);
+}
+
+void notify_printer_sharename(int snum, char *share_name)
+{
+ const char *sharename = SERVICE(snum);
+
+ send_notify_field_buffer(
+ sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SHARE_NAME,
+ snum, strlen(share_name) + 1, share_name);
+}
+
+void notify_printer_printername(int snum, char *printername)
+{
+ const char *sharename = SERVICE(snum);
+
+ send_notify_field_buffer(
+ sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINTER_NAME,
+ snum, strlen(printername) + 1, printername);
+}
+
+void notify_printer_port(int snum, char *port_name)
+{
+ const char *sharename = SERVICE(snum);
+
+ send_notify_field_buffer(
+ sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PORT_NAME,
+ snum, strlen(port_name) + 1, port_name);
+}
+
+void notify_printer_location(int snum, char *location)
+{
+ const char *sharename = SERVICE(snum);
+
+ send_notify_field_buffer(
+ sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_LOCATION,
+ snum, strlen(location) + 1, location);
+}
+
+void notify_printer_byname( const char *printername, uint32 change, const char *value )
+{
+ int snum = print_queue_snum(printername);
+ int type = PRINTER_NOTIFY_TYPE;
+
+ if ( snum == -1 )
+ return;
+
+ send_notify_field_buffer( printername, type, change, snum, strlen(value)+1, value );
+}
+
+
+/****************************************************************************
+ Return a malloced list of pid_t's that are interested in getting update
+ messages on this print queue. Used in printing/notify to send the messages.
+****************************************************************************/
+
+bool print_notify_pid_list(const char *printername, TALLOC_CTX *mem_ctx, size_t *p_num_pids, pid_t **pp_pid_list)
+{
+ struct tdb_print_db *pdb = NULL;
+ TDB_CONTEXT *tdb = NULL;
+ TDB_DATA data;
+ bool ret = True;
+ size_t i, num_pids, offset;
+ pid_t *pid_list;
+
+ *p_num_pids = 0;
+ *pp_pid_list = NULL;
+
+ pdb = get_print_db_byname(printername);
+ if (!pdb)
+ return False;
+ tdb = pdb->tdb;
+
+ if (tdb_read_lock_bystring_with_timeout(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) {
+ DEBUG(0,("print_notify_pid_list: Failed to lock printer %s database\n",
+ printername));
+ if (pdb)
+ release_print_db(pdb);
+ return False;
+ }
+
+ data = get_printer_notify_pid_list( tdb, printername, True );
+
+ if (!data.dptr) {
+ ret = True;
+ goto done;
+ }
+
+ num_pids = data.dsize / 8;
+
+ if (num_pids) {
+ if ((pid_list = TALLOC_ARRAY(mem_ctx, pid_t, num_pids)) == NULL) {
+ ret = False;
+ goto done;
+ }
+ } else {
+ pid_list = NULL;
+ }
+
+ for( i = 0, offset = 0; i < num_pids; offset += 8, i++)
+ pid_list[i] = (pid_t)IVAL(data.dptr, offset);
+
+ *pp_pid_list = pid_list;
+ *p_num_pids = num_pids;
+
+ ret = True;
+
+ done:
+
+ tdb_read_unlock_bystring(tdb, NOTIFY_PID_LIST_KEY);
+ if (pdb)
+ release_print_db(pdb);
+ SAFE_FREE(data.dptr);
+ return ret;
+}
diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c
new file mode 100644
index 0000000000..ded985c260
--- /dev/null
+++ b/source3/printing/nt_printing.c
@@ -0,0 +1,5892 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Jean François Micouleau 1998-2000.
+ * Copyright (C) Gerald Carter 2002-2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+static TDB_CONTEXT *tdb_forms; /* used for forms files */
+static TDB_CONTEXT *tdb_drivers; /* used for driver files */
+static TDB_CONTEXT *tdb_printers; /* used for printers files */
+
+#define FORMS_PREFIX "FORMS/"
+#define DRIVERS_PREFIX "DRIVERS/"
+#define DRIVER_INIT_PREFIX "DRIVER_INIT/"
+#define PRINTERS_PREFIX "PRINTERS/"
+#define SECDESC_PREFIX "SECDESC/"
+#define GLOBAL_C_SETPRINTER "GLOBALS/c_setprinter"
+
+#define NTDRIVERS_DATABASE_VERSION_1 1
+#define NTDRIVERS_DATABASE_VERSION_2 2
+#define NTDRIVERS_DATABASE_VERSION_3 3 /* little endian version of v2 */
+#define NTDRIVERS_DATABASE_VERSION_4 4 /* fix generic bits in security descriptors */
+#define NTDRIVERS_DATABASE_VERSION_5 5 /* normalize keys in ntprinters.tdb */
+
+/* Map generic permissions to printer object specific permissions */
+
+const struct generic_mapping printer_generic_mapping = {
+ PRINTER_READ,
+ PRINTER_WRITE,
+ PRINTER_EXECUTE,
+ PRINTER_ALL_ACCESS
+};
+
+const struct standard_mapping printer_std_mapping = {
+ PRINTER_READ,
+ PRINTER_WRITE,
+ PRINTER_EXECUTE,
+ PRINTER_ALL_ACCESS
+};
+
+/* Map generic permissions to print server object specific permissions */
+
+const struct generic_mapping printserver_generic_mapping = {
+ SERVER_READ,
+ SERVER_WRITE,
+ SERVER_EXECUTE,
+ SERVER_ALL_ACCESS
+};
+
+const struct generic_mapping printserver_std_mapping = {
+ SERVER_READ,
+ SERVER_WRITE,
+ SERVER_EXECUTE,
+ SERVER_ALL_ACCESS
+};
+
+/* Map generic permissions to job object specific permissions */
+
+const struct generic_mapping job_generic_mapping = {
+ JOB_READ,
+ JOB_WRITE,
+ JOB_EXECUTE,
+ JOB_ALL_ACCESS
+};
+
+/* We need one default form to support our default printer. Msoft adds the
+forms it wants and in the ORDER it wants them (note: DEVMODE papersize is an
+array index). Letter is always first, so (for the current code) additions
+always put things in the correct order. */
+static const nt_forms_struct default_forms[] = {
+ {"Letter",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
+ {"Letter Small",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
+ {"Tabloid",0x1,0x44368,0x696b8,0x0,0x0,0x44368,0x696b8},
+ {"Ledger",0x1,0x696b8,0x44368,0x0,0x0,0x696b8,0x44368},
+ {"Legal",0x1,0x34b5c,0x56d10,0x0,0x0,0x34b5c,0x56d10},
+ {"Statement",0x1,0x221b4,0x34b5c,0x0,0x0,0x221b4,0x34b5c},
+ {"Executive",0x1,0x2cf56,0x411cc,0x0,0x0,0x2cf56,0x411cc},
+ {"A3",0x1,0x48828,0x668a0,0x0,0x0,0x48828,0x668a0},
+ {"A4",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
+ {"A4 Small",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
+ {"A5",0x1,0x24220,0x33450,0x0,0x0,0x24220,0x33450},
+ {"B4 (JIS)",0x1,0x3ebe8,0x58de0,0x0,0x0,0x3ebe8,0x58de0},
+ {"B5 (JIS)",0x1,0x2c6f0,0x3ebe8,0x0,0x0,0x2c6f0,0x3ebe8},
+ {"Folio",0x1,0x34b5c,0x509d8,0x0,0x0,0x34b5c,0x509d8},
+ {"Quarto",0x1,0x347d8,0x43238,0x0,0x0,0x347d8,0x43238},
+ {"10x14",0x1,0x3e030,0x56d10,0x0,0x0,0x3e030,0x56d10},
+ {"11x17",0x1,0x44368,0x696b8,0x0,0x0,0x44368,0x696b8},
+ {"Note",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
+ {"Envelope #9",0x1,0x18079,0x37091,0x0,0x0,0x18079,0x37091},
+ {"Envelope #10",0x1,0x19947,0x3ae94,0x0,0x0,0x19947,0x3ae94},
+ {"Envelope #11",0x1,0x1be7c,0x40565,0x0,0x0,0x1be7c,0x40565},
+ {"Envelope #12",0x1,0x1d74a,0x44368,0x0,0x0,0x1d74a,0x44368},
+ {"Envelope #14",0x1,0x1f018,0x47504,0x0,0x0,0x1f018,0x47504},
+ {"C size sheet",0x1,0x696b8,0x886d0,0x0,0x0,0x696b8,0x886d0},
+ {"D size sheet",0x1,0x886d0,0xd2d70,0x0,0x0,0x886d0,0xd2d70},
+ {"E size sheet",0x1,0xd2d70,0x110da0,0x0,0x0,0xd2d70,0x110da0},
+ {"Envelope DL",0x1,0x1adb0,0x35b60,0x0,0x0,0x1adb0,0x35b60},
+ {"Envelope C5",0x1,0x278d0,0x37e88,0x0,0x0,0x278d0,0x37e88},
+ {"Envelope C3",0x1,0x4f1a0,0x6fd10,0x0,0x0,0x4f1a0,0x6fd10},
+ {"Envelope C4",0x1,0x37e88,0x4f1a0,0x0,0x0,0x37e88,0x4f1a0},
+ {"Envelope C6",0x1,0x1bd50,0x278d0,0x0,0x0,0x1bd50,0x278d0},
+ {"Envelope C65",0x1,0x1bd50,0x37e88,0x0,0x0,0x1bd50,0x37e88},
+ {"Envelope B4",0x1,0x3d090,0x562e8,0x0,0x0,0x3d090,0x562e8},
+ {"Envelope B5",0x1,0x2af80,0x3d090,0x0,0x0,0x2af80,0x3d090},
+ {"Envelope B6",0x1,0x2af80,0x1e848,0x0,0x0,0x2af80,0x1e848},
+ {"Envelope",0x1,0x1adb0,0x38270,0x0,0x0,0x1adb0,0x38270},
+ {"Envelope Monarch",0x1,0x18079,0x2e824,0x0,0x0,0x18079,0x2e824},
+ {"6 3/4 Envelope",0x1,0x167ab,0x284ec,0x0,0x0,0x167ab,0x284ec},
+ {"US Std Fanfold",0x1,0x5c3e1,0x44368,0x0,0x0,0x5c3e1,0x44368},
+ {"German Std Fanfold",0x1,0x34b5c,0x4a6a0,0x0,0x0,0x34b5c,0x4a6a0},
+ {"German Legal Fanfold",0x1,0x34b5c,0x509d8,0x0,0x0,0x34b5c,0x509d8},
+ {"B4 (ISO)",0x1,0x3d090,0x562e8,0x0,0x0,0x3d090,0x562e8},
+ {"Japanese Postcard",0x1,0x186a0,0x24220,0x0,0x0,0x186a0,0x24220},
+ {"9x11",0x1,0x37cf8,0x44368,0x0,0x0,0x37cf8,0x44368},
+ {"10x11",0x1,0x3e030,0x44368,0x0,0x0,0x3e030,0x44368},
+ {"15x11",0x1,0x5d048,0x44368,0x0,0x0,0x5d048,0x44368},
+ {"Envelope Invite",0x1,0x35b60,0x35b60,0x0,0x0,0x35b60,0x35b60},
+ {"Reserved48",0x1,0x1,0x1,0x0,0x0,0x1,0x1},
+ {"Reserved49",0x1,0x1,0x1,0x0,0x0,0x1,0x1},
+ {"Letter Extra",0x1,0x3ae94,0x4a6a0,0x0,0x0,0x3ae94,0x4a6a0},
+ {"Legal Extra",0x1,0x3ae94,0x5d048,0x0,0x0,0x3ae94,0x5d048},
+ {"Tabloid Extra",0x1,0x4a6a0,0x6f9f0,0x0,0x0,0x4a6a0,0x6f9f0},
+ {"A4 Extra",0x1,0x397c2,0x4eb16,0x0,0x0,0x397c2,0x4eb16},
+ {"Letter Transverse",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
+ {"A4 Transverse",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
+ {"Letter Extra Transverse",0x1,0x3ae94,0x4a6a0,0x0,0x0,0x3ae94,0x4a6a0},
+ {"Super A",0x1,0x376b8,0x56ea0,0x0,0x0,0x376b8,0x56ea0},
+ {"Super B",0x1,0x4a768,0x76e58,0x0,0x0,0x4a768,0x76e58},
+ {"Letter Plus",0x1,0x34b5c,0x4eb16,0x0,0x0,0x34b5c,0x4eb16},
+ {"A4 Plus",0x1,0x33450,0x50910,0x0,0x0,0x33450,0x50910},
+ {"A5 Transverse",0x1,0x24220,0x33450,0x0,0x0,0x24220,0x33450},
+ {"B5 (JIS) Transverse",0x1,0x2c6f0,0x3ebe8,0x0,0x0,0x2c6f0,0x3ebe8},
+ {"A3 Extra",0x1,0x4e9d0,0x6ca48,0x0,0x0,0x4e9d0,0x6ca48},
+ {"A5 Extra",0x1,0x2a7b0,0x395f8,0x0,0x0,0x2a7b0,0x395f8},
+ {"B5 (ISO) Extra",0x1,0x31128,0x43620,0x0,0x0,0x31128,0x43620},
+ {"A2",0x1,0x668a0,0x91050,0x0,0x0,0x668a0,0x91050},
+ {"A3 Transverse",0x1,0x48828,0x668a0,0x0,0x0,0x48828,0x668a0},
+ {"A3 Extra Transverse",0x1,0x4e9d0,0x6ca48,0x0,0x0,0x4e9d0,0x6ca48},
+ {"Japanese Double Postcard",0x1,0x30d40,0x24220,0x0,0x0,0x30d40,0x24220},
+ {"A6",0x1,0x19a28,0x24220,0x0,0x0,0x19a28,0x24220},
+ {"Japanese Envelope Kaku #2",0x1,0x3a980,0x510e0,0x0,0x0,0x3a980,0x510e0},
+ {"Japanese Envelope Kaku #3",0x1,0x34bc0,0x43a08,0x0,0x0,0x34bc0,0x43a08},
+ {"Japanese Envelope Chou #3",0x1,0x1d4c0,0x395f8,0x0,0x0,0x1d4c0,0x395f8},
+ {"Japanese Envelope Chou #4",0x1,0x15f90,0x320c8,0x0,0x0,0x15f90,0x320c8},
+ {"Letter Rotated",0x1,0x44368,0x34b5c,0x0,0x0,0x44368,0x34b5c},
+ {"A3 Rotated",0x1,0x668a0,0x48828,0x0,0x0,0x668a0,0x48828},
+ {"A4 Rotated",0x1,0x48828,0x33450,0x0,0x0,0x48828,0x33450},
+ {"A5 Rotated",0x1,0x33450,0x24220,0x0,0x0,0x33450,0x24220},
+ {"B4 (JIS) Rotated",0x1,0x58de0,0x3ebe8,0x0,0x0,0x58de0,0x3ebe8},
+ {"B5 (JIS) Rotated",0x1,0x3ebe8,0x2c6f0,0x0,0x0,0x3ebe8,0x2c6f0},
+ {"Japanese Postcard Rotated",0x1,0x24220,0x186a0,0x0,0x0,0x24220,0x186a0},
+ {"Double Japan Postcard Rotated",0x1,0x24220,0x30d40,0x0,0x0,0x24220,0x30d40},
+ {"A6 Rotated",0x1,0x24220,0x19a28,0x0,0x0,0x24220,0x19a28},
+ {"Japan Envelope Kaku #2 Rotated",0x1,0x510e0,0x3a980,0x0,0x0,0x510e0,0x3a980},
+ {"Japan Envelope Kaku #3 Rotated",0x1,0x43a08,0x34bc0,0x0,0x0,0x43a08, 0x34bc0},
+ {"Japan Envelope Chou #3 Rotated",0x1,0x395f8,0x1d4c0,0x0,0x0,0x395f8,0x1d4c0},
+ {"Japan Envelope Chou #4 Rotated",0x1,0x320c8,0x15f90,0x0,0x0,0x320c8,0x15f90},
+ {"B6 (JIS)",0x1,0x1f400,0x2c6f0,0x0,0x0,0x1f400,0x2c6f0},
+ {"B6 (JIS) Rotated",0x1,0x2c6f0,0x1f400,0x0,0x0,0x2c6f0,0x1f400},
+ {"12x11",0x1,0x4a724,0x443e1,0x0,0x0,0x4a724,0x443e1},
+ {"Japan Envelope You #4",0x1,0x19a28,0x395f8,0x0,0x0,0x19a28,0x395f8},
+ {"Japan Envelope You #4 Rotated",0x1,0x395f8,0x19a28,0x0,0x0,0x395f8,0x19a28},
+ {"PRC 16K",0x1,0x2de60,0x3f7a0,0x0,0x0,0x2de60,0x3f7a0},
+ {"PRC 32K",0x1,0x1fbd0,0x2cec0,0x0,0x0,0x1fbd0,0x2cec0},
+ {"PRC 32K(Big)",0x1,0x222e0,0x318f8,0x0,0x0,0x222e0,0x318f8},
+ {"PRC Envelope #1",0x1,0x18e70,0x28488,0x0,0x0,0x18e70,0x28488},
+ {"PRC Envelope #2",0x1,0x18e70,0x2af80,0x0,0x0,0x18e70,0x2af80},
+ {"PRC Envelope #3",0x1,0x1e848,0x2af80,0x0,0x0,0x1e848,0x2af80},
+ {"PRC Envelope #4",0x1,0x1adb0,0x32c80,0x0,0x0,0x1adb0,0x32c80},
+ {"PRC Envelope #5",0x1,0x1adb0,0x35b60,0x0,0x0,0x1adb0,0x35b60},
+ {"PRC Envelope #6",0x1,0x1d4c0,0x38270,0x0,0x0,0x1d4c0,0x38270},
+ {"PRC Envelope #7",0x1,0x27100,0x38270,0x0,0x0,0x27100,0x38270},
+ {"PRC Envelope #8",0x1,0x1d4c0,0x4b708,0x0,0x0,0x1d4c0,0x4b708},
+ {"PRC Envelope #9",0x1,0x37e88,0x4f1a0,0x0,0x0,0x37e88,0x4f1a0},
+ {"PRC Envelope #10",0x1,0x4f1a0,0x6fd10,0x0,0x0,0x4f1a0,0x6fd10},
+ {"PRC 16K Rotated",0x1,0x3f7a0,0x2de60,0x0,0x0,0x3f7a0,0x2de60},
+ {"PRC 32K Rotated",0x1,0x2cec0,0x1fbd0,0x0,0x0,0x2cec0,0x1fbd0},
+ {"PRC 32K(Big) Rotated",0x1,0x318f8,0x222e0,0x0,0x0,0x318f8,0x222e0},
+ {"PRC Envelope #1 Rotated",0x1,0x28488,0x18e70,0x0,0x0,0x28488,0x18e70},
+ {"PRC Envelope #2 Rotated",0x1,0x2af80,0x18e70,0x0,0x0,0x2af80,0x18e70},
+ {"PRC Envelope #3 Rotated",0x1,0x2af80,0x1e848,0x0,0x0,0x2af80,0x1e848},
+ {"PRC Envelope #4 Rotated",0x1,0x32c80,0x1adb0,0x0,0x0,0x32c80,0x1adb0},
+ {"PRC Envelope #5 Rotated",0x1,0x35b60,0x1adb0,0x0,0x0,0x35b60,0x1adb0},
+ {"PRC Envelope #6 Rotated",0x1,0x38270,0x1d4c0,0x0,0x0,0x38270,0x1d4c0},
+ {"PRC Envelope #7 Rotated",0x1,0x38270,0x27100,0x0,0x0,0x38270,0x27100},
+ {"PRC Envelope #8 Rotated",0x1,0x4b708,0x1d4c0,0x0,0x0,0x4b708,0x1d4c0},
+ {"PRC Envelope #9 Rotated",0x1,0x4f1a0,0x37e88,0x0,0x0,0x4f1a0,0x37e88},
+ {"PRC Envelope #10 Rotated",0x1,0x6fd10,0x4f1a0,0x0,0x0,0x6fd10,0x4f1a0}
+};
+
+struct table_node {
+ const char *long_archi;
+ const char *short_archi;
+ int version;
+};
+
+#define SPL_ARCH_WIN40 "WIN40"
+#define SPL_ARCH_W32X86 "W32X86"
+#define SPL_ARCH_W32MIPS "W32MIPS"
+#define SPL_ARCH_W32ALPHA "W32ALPHA"
+#define SPL_ARCH_W32PPC "W32PPC"
+#define SPL_ARCH_IA64 "IA64"
+#define SPL_ARCH_X64 "x64"
+
+static const struct table_node archi_table[]= {
+
+ {"Windows 4.0", SPL_ARCH_WIN40, 0 },
+ {"Windows NT x86", SPL_ARCH_W32X86, 2 },
+ {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
+ {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
+ {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
+ {"Windows IA64", SPL_ARCH_IA64, 3 },
+ {"Windows x64", SPL_ARCH_X64, 3 },
+ {NULL, "", -1 }
+};
+
+
+/****************************************************************************
+ generate a new TDB_DATA key for storing a printer
+****************************************************************************/
+
+static TDB_DATA make_printer_tdbkey(TALLOC_CTX *ctx, const char *sharename )
+{
+ fstring share;
+ char *keystr = NULL;
+ TDB_DATA key;
+
+ fstrcpy(share, sharename);
+ strlower_m(share);
+
+ keystr = talloc_asprintf(ctx, "%s%s", PRINTERS_PREFIX, share);
+ key = string_term_tdb_data(keystr ? keystr : "");
+
+ return key;
+}
+
+/****************************************************************************
+ generate a new TDB_DATA key for storing a printer security descriptor
+****************************************************************************/
+
+static TDB_DATA make_printers_secdesc_tdbkey(TALLOC_CTX *ctx,
+ const char* sharename )
+{
+ fstring share;
+ char *keystr = NULL;
+ TDB_DATA key;
+
+ fstrcpy(share, sharename );
+ strlower_m(share);
+
+ keystr = talloc_asprintf(ctx, "%s%s", SECDESC_PREFIX, share);
+ key = string_term_tdb_data(keystr ? keystr : "");
+
+ return key;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool upgrade_to_version_3(void)
+{
+ TDB_DATA kbuf, newkey, dbuf;
+
+ DEBUG(0,("upgrade_to_version_3: upgrading print tdb's to version 3\n"));
+
+ for (kbuf = tdb_firstkey(tdb_drivers); kbuf.dptr;
+ newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
+
+ dbuf = tdb_fetch(tdb_drivers, kbuf);
+
+ if (strncmp((const char *)kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
+ DEBUG(0,("upgrade_to_version_3:moving form\n"));
+ if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) {
+ SAFE_FREE(dbuf.dptr);
+ DEBUG(0,("upgrade_to_version_3: failed to move form. Error (%s).\n", tdb_errorstr(tdb_forms)));
+ return False;
+ }
+ if (tdb_delete(tdb_drivers, kbuf) != 0) {
+ SAFE_FREE(dbuf.dptr);
+ DEBUG(0,("upgrade_to_version_3: failed to delete form. Error (%s)\n", tdb_errorstr(tdb_drivers)));
+ return False;
+ }
+ }
+
+ if (strncmp((const char *)kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
+ DEBUG(0,("upgrade_to_version_3:moving printer\n"));
+ if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
+ SAFE_FREE(dbuf.dptr);
+ DEBUG(0,("upgrade_to_version_3: failed to move printer. Error (%s)\n", tdb_errorstr(tdb_printers)));
+ return False;
+ }
+ if (tdb_delete(tdb_drivers, kbuf) != 0) {
+ SAFE_FREE(dbuf.dptr);
+ DEBUG(0,("upgrade_to_version_3: failed to delete printer. Error (%s)\n", tdb_errorstr(tdb_drivers)));
+ return False;
+ }
+ }
+
+ if (strncmp((const char *)kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
+ DEBUG(0,("upgrade_to_version_3:moving secdesc\n"));
+ if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
+ SAFE_FREE(dbuf.dptr);
+ DEBUG(0,("upgrade_to_version_3: failed to move secdesc. Error (%s)\n", tdb_errorstr(tdb_printers)));
+ return False;
+ }
+ if (tdb_delete(tdb_drivers, kbuf) != 0) {
+ SAFE_FREE(dbuf.dptr);
+ DEBUG(0,("upgrade_to_version_3: failed to delete secdesc. Error (%s)\n", tdb_errorstr(tdb_drivers)));
+ return False;
+ }
+ }
+
+ SAFE_FREE(dbuf.dptr);
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Fix an issue with security descriptors. Printer sec_desc must
+ use more than the generic bits that were previously used
+ in <= 3.0.14a. They must also have a owner and group SID assigned.
+ Otherwise, any printers than have been migrated to a Windows
+ host using printmig.exe will not be accessible.
+*******************************************************************/
+
+static int sec_desc_upg_fn( TDB_CONTEXT *the_tdb, TDB_DATA key,
+ TDB_DATA data, void *state )
+{
+ prs_struct ps;
+ SEC_DESC_BUF *sd_orig = NULL;
+ SEC_DESC_BUF *sd_new, *sd_store;
+ SEC_DESC *sec, *new_sec;
+ TALLOC_CTX *ctx = state;
+ int result, i;
+ uint32 sd_size;
+ size_t size_new_sec;
+
+ if (!data.dptr || data.dsize == 0) {
+ return 0;
+ }
+
+ if ( strncmp((const char *) key.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX) ) != 0 ) {
+ return 0;
+ }
+
+ /* upgrade the security descriptor */
+
+ ZERO_STRUCT( ps );
+
+ prs_init_empty( &ps, ctx, UNMARSHALL );
+ prs_give_memory( &ps, (char *)data.dptr, data.dsize, False );
+
+ if ( !sec_io_desc_buf( "sec_desc_upg_fn", &sd_orig, &ps, 1 ) ) {
+ /* delete bad entries */
+ DEBUG(0,("sec_desc_upg_fn: Failed to parse original sec_desc for %si. Deleting....\n",
+ (const char *)key.dptr ));
+ tdb_delete( tdb_printers, key );
+ prs_mem_free( &ps );
+ return 0;
+ }
+
+ if (!sd_orig) {
+ prs_mem_free( &ps );
+ return 0;
+ }
+ sec = sd_orig->sd;
+
+ /* is this even valid? */
+
+ if ( !sec->dacl ) {
+ prs_mem_free( &ps );
+ return 0;
+ }
+
+ /* update access masks */
+
+ for ( i=0; i<sec->dacl->num_aces; i++ ) {
+ switch ( sec->dacl->aces[i].access_mask ) {
+ case (GENERIC_READ_ACCESS | GENERIC_WRITE_ACCESS | GENERIC_EXECUTE_ACCESS):
+ sec->dacl->aces[i].access_mask = PRINTER_ACE_PRINT;
+ break;
+
+ case GENERIC_ALL_ACCESS:
+ sec->dacl->aces[i].access_mask = PRINTER_ACE_FULL_CONTROL;
+ break;
+
+ case READ_CONTROL_ACCESS:
+ sec->dacl->aces[i].access_mask = PRINTER_ACE_MANAGE_DOCUMENTS;
+
+ default: /* no change */
+ break;
+ }
+ }
+
+ /* create a new SEC_DESC with the appropriate owner and group SIDs */
+
+ new_sec = make_sec_desc( ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
+ &global_sid_Builtin_Administrators,
+ &global_sid_Builtin_Administrators,
+ NULL, NULL, &size_new_sec );
+ if (!new_sec) {
+ prs_mem_free( &ps );
+ return 0;
+ }
+ sd_new = make_sec_desc_buf( ctx, size_new_sec, new_sec );
+ if (!sd_new) {
+ prs_mem_free( &ps );
+ return 0;
+ }
+
+ if ( !(sd_store = sec_desc_merge( ctx, sd_new, sd_orig )) ) {
+ DEBUG(0,("sec_desc_upg_fn: Failed to update sec_desc for %s\n", key.dptr ));
+ prs_mem_free( &ps );
+ return 0;
+ }
+
+ prs_mem_free( &ps );
+
+ /* store it back */
+
+ sd_size = ndr_size_security_descriptor(sd_store->sd, 0)
+ + sizeof(SEC_DESC_BUF);
+ if ( !prs_init(&ps, sd_size, ctx, MARSHALL) ) {
+ DEBUG(0,("sec_desc_upg_fn: Failed to allocate prs memory for %s\n", key.dptr ));
+ return 0;
+ }
+
+ if ( !sec_io_desc_buf( "sec_desc_upg_fn", &sd_store, &ps, 1 ) ) {
+ DEBUG(0,("sec_desc_upg_fn: Failed to parse new sec_desc for %s\n", key.dptr ));
+ prs_mem_free( &ps );
+ return 0;
+ }
+
+ data.dptr = (uint8 *)prs_data_p( &ps );
+ data.dsize = sd_size;
+
+ result = tdb_store( tdb_printers, key, data, TDB_REPLACE );
+
+ prs_mem_free( &ps );
+
+ /* 0 to continue and non-zero to stop traversal */
+
+ return (result == -1);
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool upgrade_to_version_4(void)
+{
+ TALLOC_CTX *ctx;
+ int result;
+
+ DEBUG(0,("upgrade_to_version_4: upgrading printer security descriptors\n"));
+
+ if ( !(ctx = talloc_init( "upgrade_to_version_4" )) )
+ return False;
+
+ result = tdb_traverse( tdb_printers, sec_desc_upg_fn, ctx );
+
+ talloc_destroy( ctx );
+
+ return ( result != -1 );
+}
+
+/*******************************************************************
+ Fix an issue with security descriptors. Printer sec_desc must
+ use more than the generic bits that were previously used
+ in <= 3.0.14a. They must also have a owner and group SID assigned.
+ Otherwise, any printers than have been migrated to a Windows
+ host using printmig.exe will not be accessible.
+*******************************************************************/
+
+static int normalize_printers_fn( TDB_CONTEXT *the_tdb, TDB_DATA key,
+ TDB_DATA data, void *state )
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ TDB_DATA new_key;
+
+ if (!data.dptr || data.dsize == 0)
+ return 0;
+
+ /* upgrade printer records and security descriptors */
+
+ if ( strncmp((const char *) key.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX) ) == 0 ) {
+ new_key = make_printer_tdbkey(ctx, (const char *)key.dptr+strlen(PRINTERS_PREFIX) );
+ }
+ else if ( strncmp((const char *) key.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX) ) == 0 ) {
+ new_key = make_printers_secdesc_tdbkey(ctx, (const char *)key.dptr+strlen(SECDESC_PREFIX) );
+ }
+ else {
+ /* ignore this record */
+ return 0;
+ }
+
+ /* delete the original record and store under the normalized key */
+
+ if ( tdb_delete( the_tdb, key ) != 0 ) {
+ DEBUG(0,("normalize_printers_fn: tdb_delete for [%s] failed!\n",
+ key.dptr));
+ return 1;
+ }
+
+ if ( tdb_store( the_tdb, new_key, data, TDB_REPLACE) != 0 ) {
+ DEBUG(0,("normalize_printers_fn: failed to store new record for [%s]!\n",
+ key.dptr));
+ return 1;
+ }
+
+ return 0;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool upgrade_to_version_5(void)
+{
+ TALLOC_CTX *ctx;
+ int result;
+
+ DEBUG(0,("upgrade_to_version_5: normalizing printer keys\n"));
+
+ if ( !(ctx = talloc_init( "upgrade_to_version_5" )) )
+ return False;
+
+ result = tdb_traverse( tdb_printers, normalize_printers_fn, NULL );
+
+ talloc_destroy( ctx );
+
+ return ( result != -1 );
+}
+
+/****************************************************************************
+ Open the NT printing tdbs. Done once before fork().
+****************************************************************************/
+
+bool nt_printing_init(struct messaging_context *msg_ctx)
+{
+ const char *vstring = "INFO/version";
+ WERROR win_rc;
+ int32 vers_id;
+
+ if ( tdb_drivers && tdb_printers && tdb_forms )
+ return True;
+
+ if (tdb_drivers)
+ tdb_close(tdb_drivers);
+ tdb_drivers = tdb_open_log(state_path("ntdrivers.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if (!tdb_drivers) {
+ DEBUG(0,("nt_printing_init: Failed to open nt drivers database %s (%s)\n",
+ state_path("ntdrivers.tdb"), strerror(errno) ));
+ return False;
+ }
+
+ if (tdb_printers)
+ tdb_close(tdb_printers);
+ tdb_printers = tdb_open_log(state_path("ntprinters.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if (!tdb_printers) {
+ DEBUG(0,("nt_printing_init: Failed to open nt printers database %s (%s)\n",
+ state_path("ntprinters.tdb"), strerror(errno) ));
+ return False;
+ }
+
+ if (tdb_forms)
+ tdb_close(tdb_forms);
+ tdb_forms = tdb_open_log(state_path("ntforms.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if (!tdb_forms) {
+ DEBUG(0,("nt_printing_init: Failed to open nt forms database %s (%s)\n",
+ state_path("ntforms.tdb"), strerror(errno) ));
+ return False;
+ }
+
+ /* handle a Samba upgrade */
+
+ vers_id = tdb_fetch_int32(tdb_drivers, vstring);
+ if (vers_id == -1) {
+ DEBUG(10, ("Fresh database\n"));
+ tdb_store_int32( tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_5 );
+ vers_id = NTDRIVERS_DATABASE_VERSION_5;
+ }
+
+ if ( vers_id != NTDRIVERS_DATABASE_VERSION_5 ) {
+
+ if ((vers_id == NTDRIVERS_DATABASE_VERSION_1) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_1)) {
+ if (!upgrade_to_version_3())
+ return False;
+ tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_3);
+ vers_id = NTDRIVERS_DATABASE_VERSION_3;
+ }
+
+ if ((vers_id == NTDRIVERS_DATABASE_VERSION_2) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_2)) {
+ /* Written on a bigendian machine with old fetch_int code. Save as le. */
+ /* The only upgrade between V2 and V3 is to save the version in little-endian. */
+ tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_3);
+ vers_id = NTDRIVERS_DATABASE_VERSION_3;
+ }
+
+ if (vers_id == NTDRIVERS_DATABASE_VERSION_3 ) {
+ if ( !upgrade_to_version_4() )
+ return False;
+ tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_4);
+ vers_id = NTDRIVERS_DATABASE_VERSION_4;
+ }
+
+ if (vers_id == NTDRIVERS_DATABASE_VERSION_4 ) {
+ if ( !upgrade_to_version_5() )
+ return False;
+ tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_5);
+ vers_id = NTDRIVERS_DATABASE_VERSION_5;
+ }
+
+
+ if ( vers_id != NTDRIVERS_DATABASE_VERSION_5 ) {
+ DEBUG(0,("nt_printing_init: Unknown printer database version [%d]\n", vers_id));
+ return False;
+ }
+ }
+
+ update_c_setprinter(True);
+
+ /*
+ * register callback to handle updating printers as new
+ * drivers are installed
+ */
+
+ messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
+ do_drv_upgrade_printer);
+
+ /*
+ * register callback to handle updating printer data
+ * when a driver is initialized
+ */
+
+ messaging_register(msg_ctx, NULL, MSG_PRINTERDATA_INIT_RESET,
+ reset_all_printerdata);
+
+ /* of course, none of the message callbacks matter if you don't
+ tell messages.c that you interested in receiving PRINT_GENERAL
+ msgs. This is done in claim_connection() */
+
+
+ if ( lp_security() == SEC_ADS ) {
+ win_rc = check_published_printers();
+ if (!W_ERROR_IS_OK(win_rc))
+ DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", dos_errstr(win_rc)));
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Function to allow filename parsing "the old way".
+********************************************************************/
+
+static char *driver_unix_convert(connection_struct *conn,
+ const char *old_name,
+ SMB_STRUCT_STAT *pst)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *name = talloc_strdup(ctx, old_name);
+ char *new_name = NULL;
+
+ if (!name) {
+ return NULL;
+ }
+ unix_format(name);
+ name = unix_clean_name(ctx, name);
+ if (!name) {
+ return NULL;
+ }
+ trim_string(name,"/","/");
+ unix_convert(ctx,conn, name, false, &new_name, NULL, pst);
+ return new_name;
+}
+
+/*******************************************************************
+ tdb traversal function for counting printers.
+********************************************************************/
+
+static int traverse_counting_printers(TDB_CONTEXT *t, TDB_DATA key,
+ TDB_DATA data, void *context)
+{
+ int *printer_count = (int*)context;
+
+ if (memcmp(PRINTERS_PREFIX, key.dptr, sizeof(PRINTERS_PREFIX)-1) == 0) {
+ (*printer_count)++;
+ DEBUG(10,("traverse_counting_printers: printer = [%s] printer_count = %d\n", key.dptr, *printer_count));
+ }
+
+ return 0;
+}
+
+/*******************************************************************
+ Update the spooler global c_setprinter. This variable is initialized
+ when the parent smbd starts with the number of existing printers. It
+ is monotonically increased by the current number of printers *after*
+ each add or delete printer RPC. Only Microsoft knows why... JRR020119
+********************************************************************/
+
+uint32 update_c_setprinter(bool initialize)
+{
+ int32 c_setprinter;
+ int32 printer_count = 0;
+
+ tdb_lock_bystring(tdb_printers, GLOBAL_C_SETPRINTER);
+
+ /* Traverse the tdb, counting the printers */
+ tdb_traverse(tdb_printers, traverse_counting_printers, (void *)&printer_count);
+
+ /* If initializing, set c_setprinter to current printers count
+ * otherwise, bump it by the current printer count
+ */
+ if (!initialize)
+ c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER) + printer_count;
+ else
+ c_setprinter = printer_count;
+
+ DEBUG(10,("update_c_setprinter: c_setprinter = %u\n", (unsigned int)c_setprinter));
+ tdb_store_int32(tdb_printers, GLOBAL_C_SETPRINTER, c_setprinter);
+
+ tdb_unlock_bystring(tdb_printers, GLOBAL_C_SETPRINTER);
+
+ return (uint32)c_setprinter;
+}
+
+/*******************************************************************
+ Get the spooler global c_setprinter, accounting for initialization.
+********************************************************************/
+
+uint32 get_c_setprinter(void)
+{
+ int32 c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER);
+
+ if (c_setprinter == (int32)-1)
+ c_setprinter = update_c_setprinter(True);
+
+ DEBUG(10,("get_c_setprinter: c_setprinter = %d\n", c_setprinter));
+
+ return (uint32)c_setprinter;
+}
+
+/****************************************************************************
+ Get builtin form struct list.
+****************************************************************************/
+
+int get_builtin_ntforms(nt_forms_struct **list)
+{
+ *list = (nt_forms_struct *)memdup(&default_forms[0], sizeof(default_forms));
+ if (!*list) {
+ return 0;
+ }
+ return sizeof(default_forms) / sizeof(default_forms[0]);
+}
+
+/****************************************************************************
+ get a builtin form struct
+****************************************************************************/
+
+bool get_a_builtin_ntform(UNISTR2 *uni_formname,nt_forms_struct *form)
+{
+ int i,count;
+ fstring form_name;
+ unistr2_to_ascii(form_name, uni_formname, sizeof(form_name));
+ DEBUGADD(6,("Looking for builtin form %s \n", form_name));
+ count = sizeof(default_forms) / sizeof(default_forms[0]);
+ for (i=0;i<count;i++) {
+ if (strequal(form_name,default_forms[i].name)) {
+ DEBUGADD(6,("Found builtin form %s \n", form_name));
+ memcpy(form,&default_forms[i],sizeof(*form));
+ break;
+ }
+ }
+
+ return (i !=count);
+}
+
+/****************************************************************************
+ get a form struct list.
+****************************************************************************/
+
+int get_ntforms(nt_forms_struct **list)
+{
+ TDB_DATA kbuf, newkey, dbuf;
+ nt_forms_struct form;
+ int ret;
+ int i;
+ int n = 0;
+
+ *list = NULL;
+
+ for (kbuf = tdb_firstkey(tdb_forms);
+ kbuf.dptr;
+ newkey = tdb_nextkey(tdb_forms, kbuf), safe_free(kbuf.dptr), kbuf=newkey)
+ {
+ if (strncmp((const char *)kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) != 0)
+ continue;
+
+ dbuf = tdb_fetch(tdb_forms, kbuf);
+ if (!dbuf.dptr)
+ continue;
+
+ fstrcpy(form.name, (const char *)kbuf.dptr+strlen(FORMS_PREFIX));
+ ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddddddd",
+ &i, &form.flag, &form.width, &form.length, &form.left,
+ &form.top, &form.right, &form.bottom);
+ SAFE_FREE(dbuf.dptr);
+ if (ret != dbuf.dsize)
+ continue;
+
+ *list = SMB_REALLOC_ARRAY(*list, nt_forms_struct, n+1);
+ if (!*list) {
+ DEBUG(0,("get_ntforms: Realloc fail.\n"));
+ return 0;
+ }
+ (*list)[n] = form;
+ n++;
+ }
+
+
+ return n;
+}
+
+/****************************************************************************
+write a form struct list
+****************************************************************************/
+
+int write_ntforms(nt_forms_struct **list, int number)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *buf = NULL;
+ char *key = NULL;
+ int len;
+ TDB_DATA dbuf;
+ int i;
+
+ for (i=0;i<number;i++) {
+ /* save index, so list is rebuilt in correct order */
+ len = tdb_pack(NULL, 0, "dddddddd",
+ i, (*list)[i].flag, (*list)[i].width, (*list)[i].length,
+ (*list)[i].left, (*list)[i].top, (*list)[i].right,
+ (*list)[i].bottom);
+ if (!len) {
+ continue;
+ }
+ buf = TALLOC_ARRAY(ctx, char, len);
+ if (!buf) {
+ return 0;
+ }
+ len = tdb_pack((uint8 *)buf, len, "dddddddd",
+ i, (*list)[i].flag, (*list)[i].width, (*list)[i].length,
+ (*list)[i].left, (*list)[i].top, (*list)[i].right,
+ (*list)[i].bottom);
+ key = talloc_asprintf(ctx, "%s%s", FORMS_PREFIX, (*list)[i].name);
+ if (!key) {
+ return 0;
+ }
+ dbuf.dsize = len;
+ dbuf.dptr = (uint8 *)buf;
+ if (tdb_store_bystring(tdb_forms, key, dbuf, TDB_REPLACE) != 0) {
+ TALLOC_FREE(key);
+ TALLOC_FREE(buf);
+ break;
+ }
+ TALLOC_FREE(key);
+ TALLOC_FREE(buf);
+ }
+
+ return i;
+}
+
+/****************************************************************************
+add a form struct at the end of the list
+****************************************************************************/
+bool add_a_form(nt_forms_struct **list, const FORM *form, int *count)
+{
+ int n=0;
+ bool update;
+ fstring form_name;
+
+ /*
+ * NT tries to add forms even when
+ * they are already in the base
+ * only update the values if already present
+ */
+
+ update=False;
+
+ unistr2_to_ascii(form_name, &form->name, sizeof(form_name));
+ for (n=0; n<*count; n++) {
+ if ( strequal((*list)[n].name, form_name) ) {
+ update=True;
+ break;
+ }
+ }
+
+ if (update==False) {
+ if((*list=SMB_REALLOC_ARRAY(*list, nt_forms_struct, n+1)) == NULL) {
+ DEBUG(0,("add_a_form: failed to enlarge forms list!\n"));
+ return False;
+ }
+ unistr2_to_ascii((*list)[n].name, &form->name, sizeof((*list)[n].name));
+ (*count)++;
+ }
+
+ (*list)[n].flag=form->flags;
+ (*list)[n].width=form->size_x;
+ (*list)[n].length=form->size_y;
+ (*list)[n].left=form->left;
+ (*list)[n].top=form->top;
+ (*list)[n].right=form->right;
+ (*list)[n].bottom=form->bottom;
+
+ DEBUG(6,("add_a_form: Successfully %s form [%s]\n",
+ update ? "updated" : "added", form_name));
+
+ return True;
+}
+
+/****************************************************************************
+ Delete a named form struct.
+****************************************************************************/
+
+bool delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, WERROR *ret)
+{
+ char *key = NULL;
+ int n=0;
+ fstring form_name;
+
+ *ret = WERR_OK;
+
+ unistr2_to_ascii(form_name, del_name, sizeof(form_name));
+
+ for (n=0; n<*count; n++) {
+ if (!strncmp((*list)[n].name, form_name, strlen(form_name))) {
+ DEBUG(103, ("delete_a_form, [%s] in list\n", form_name));
+ break;
+ }
+ }
+
+ if (n == *count) {
+ DEBUG(10,("delete_a_form, [%s] not found\n", form_name));
+ *ret = WERR_INVALID_PARAM;
+ return False;
+ }
+
+ if (asprintf(&key, "%s%s", FORMS_PREFIX, (*list)[n].name) < 0) {
+ *ret = WERR_NOMEM;
+ return false;
+ }
+ if (tdb_delete_bystring(tdb_forms, key) != 0) {
+ SAFE_FREE(key);
+ *ret = WERR_NOMEM;
+ return False;
+ }
+ SAFE_FREE(key);
+ return true;
+}
+
+/****************************************************************************
+ Update a form struct.
+****************************************************************************/
+
+void update_a_form(nt_forms_struct **list, const FORM *form, int count)
+{
+ int n=0;
+ fstring form_name;
+ unistr2_to_ascii(form_name, &(form->name), sizeof(form_name));
+
+ DEBUG(106, ("[%s]\n", form_name));
+ for (n=0; n<count; n++) {
+ DEBUGADD(106, ("n [%d]:[%s]\n", n, (*list)[n].name));
+ if (!strncmp((*list)[n].name, form_name, strlen(form_name)))
+ break;
+ }
+
+ if (n==count) return;
+
+ (*list)[n].flag=form->flags;
+ (*list)[n].width=form->size_x;
+ (*list)[n].length=form->size_y;
+ (*list)[n].left=form->left;
+ (*list)[n].top=form->top;
+ (*list)[n].right=form->right;
+ (*list)[n].bottom=form->bottom;
+}
+
+/****************************************************************************
+ Get the nt drivers list.
+ Traverse the database and look-up the matching names.
+****************************************************************************/
+int get_ntdrivers(fstring **list, const char *architecture, uint32 version)
+{
+ int total=0;
+ const char *short_archi;
+ char *key = NULL;
+ TDB_DATA kbuf, newkey;
+
+ short_archi = get_short_archi(architecture);
+ if (!short_archi) {
+ return 0;
+ }
+
+ if (asprintf(&key, "%s%s/%d/", DRIVERS_PREFIX,
+ short_archi, version) < 0) {
+ return 0;
+ }
+
+ for (kbuf = tdb_firstkey(tdb_drivers);
+ kbuf.dptr;
+ newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
+
+ if (strncmp((const char *)kbuf.dptr, key, strlen(key)) != 0)
+ continue;
+
+ if((*list = SMB_REALLOC_ARRAY(*list, fstring, total+1)) == NULL) {
+ DEBUG(0,("get_ntdrivers: failed to enlarge list!\n"));
+ SAFE_FREE(key);
+ return -1;
+ }
+
+ fstrcpy((*list)[total], (const char *)kbuf.dptr+strlen(key));
+ total++;
+ }
+
+ SAFE_FREE(key);
+ return(total);
+}
+
+/****************************************************************************
+ Function to do the mapping between the long architecture name and
+ the short one.
+****************************************************************************/
+
+const char *get_short_archi(const char *long_archi)
+{
+ int i=-1;
+
+ DEBUG(107,("Getting architecture dependant directory\n"));
+ do {
+ i++;
+ } while ( (archi_table[i].long_archi!=NULL ) &&
+ StrCaseCmp(long_archi, archi_table[i].long_archi) );
+
+ if (archi_table[i].long_archi==NULL) {
+ DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
+ return NULL;
+ }
+
+ /* this might be client code - but shouldn't this be an fstrcpy etc? */
+
+ DEBUGADD(108,("index: [%d]\n", i));
+ DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
+ DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
+
+ return archi_table[i].short_archi;
+}
+
+/****************************************************************************
+ Version information in Microsoft files is held in a VS_VERSION_INFO structure.
+ There are two case to be covered here: PE (Portable Executable) and NE (New
+ Executable) files. Both files support the same INFO structure, but PE files
+ store the signature in unicode, and NE files store it as !unicode.
+ returns -1 on error, 1 on version info found, and 0 on no version info found.
+****************************************************************************/
+
+static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
+{
+ int i;
+ char *buf = NULL;
+ ssize_t byte_count;
+
+ if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
+ DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
+ fname, DOS_HEADER_SIZE));
+ goto error_exit;
+ }
+
+ if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
+ DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
+ fname, (unsigned long)byte_count));
+ goto no_version_info;
+ }
+
+ /* Is this really a DOS header? */
+ if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
+ DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
+ fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
+ goto no_version_info;
+ }
+
+ /* Skip OEM header (if any) and the DOS stub to start of Windows header */
+ if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
+ DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
+ fname, errno));
+ /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
+ goto no_version_info;
+ }
+
+ /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
+ if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
+ DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
+ fname, (unsigned long)byte_count));
+ /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
+ goto no_version_info;
+ }
+
+ /* The header may be a PE (Portable Executable) or an NE (New Executable) */
+ if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
+ unsigned int num_sections;
+ unsigned int section_table_bytes;
+
+ /* Just skip over optional header to get to section table */
+ if (SMB_VFS_LSEEK(fsp,
+ SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
+ SEEK_CUR) == (SMB_OFF_T)-1) {
+ DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
+ fname, errno));
+ goto error_exit;
+ }
+
+ /* get the section table */
+ num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
+ section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
+ if (section_table_bytes == 0)
+ goto error_exit;
+
+ SAFE_FREE(buf);
+ if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
+ DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
+ fname, section_table_bytes));
+ goto error_exit;
+ }
+
+ if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
+ DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
+ fname, (unsigned long)byte_count));
+ goto error_exit;
+ }
+
+ /* Iterate the section table looking for the resource section ".rsrc" */
+ for (i = 0; i < num_sections; i++) {
+ int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
+
+ if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
+ unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
+ unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
+
+ if (section_bytes == 0)
+ goto error_exit;
+
+ SAFE_FREE(buf);
+ if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
+ DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
+ fname, section_bytes));
+ goto error_exit;
+ }
+
+ /* Seek to the start of the .rsrc section info */
+ if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
+ DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
+ fname, errno));
+ goto error_exit;
+ }
+
+ if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
+ DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
+ fname, (unsigned long)byte_count));
+ goto error_exit;
+ }
+
+ if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
+ goto error_exit;
+
+ for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
+ /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
+ if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
+ /* Align to next long address */
+ int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
+
+ if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
+ *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
+ *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
+
+ DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
+ fname, *major, *minor,
+ (*major>>16)&0xffff, *major&0xffff,
+ (*minor>>16)&0xffff, *minor&0xffff));
+ SAFE_FREE(buf);
+ return 1;
+ }
+ }
+ }
+ }
+ }
+
+ /* Version info not found, fall back to origin date/time */
+ DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
+ SAFE_FREE(buf);
+ return 0;
+
+ } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
+ if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
+ DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
+ fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
+ /* At this point, we assume the file is in error. It still could be somthing
+ * else besides a NE file, but it unlikely at this point. */
+ goto error_exit;
+ }
+
+ /* Allocate a bit more space to speed up things */
+ SAFE_FREE(buf);
+ if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
+ DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
+ fname, PE_HEADER_SIZE));
+ goto error_exit;
+ }
+
+ /* This is a HACK! I got tired of trying to sort through the messy
+ * 'NE' file format. If anyone wants to clean this up please have at
+ * it, but this works. 'NE' files will eventually fade away. JRR */
+ while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
+ /* Cover case that should not occur in a well formed 'NE' .dll file */
+ if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
+
+ for(i=0; i<byte_count; i++) {
+ /* Fast skip past data that can't possibly match */
+ if (buf[i] != 'V') continue;
+
+ /* Potential match data crosses buf boundry, move it to beginning
+ * of buf, and fill the buf with as much as it will hold. */
+ if (i>byte_count-VS_VERSION_INFO_SIZE) {
+ int bc;
+
+ memcpy(buf, &buf[i], byte_count-i);
+ if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
+ (byte_count-i))) < 0) {
+
+ DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
+ fname, errno));
+ goto error_exit;
+ }
+
+ byte_count = bc + (byte_count - i);
+ if (byte_count<VS_VERSION_INFO_SIZE) break;
+
+ i = 0;
+ }
+
+ /* Check that the full signature string and the magic number that
+ * follows exist (not a perfect solution, but the chances that this
+ * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
+ * twice, as it is simpler to read the code. */
+ if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
+ /* Compute skip alignment to next long address */
+ int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
+ sizeof(VS_SIGNATURE)) & 3;
+ if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
+
+ *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
+ *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
+ DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
+ fname, *major, *minor,
+ (*major>>16)&0xffff, *major&0xffff,
+ (*minor>>16)&0xffff, *minor&0xffff));
+ SAFE_FREE(buf);
+ return 1;
+ }
+ }
+ }
+
+ /* Version info not found, fall back to origin date/time */
+ DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
+ SAFE_FREE(buf);
+ return 0;
+
+ } else
+ /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
+ DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
+ fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
+
+ no_version_info:
+ SAFE_FREE(buf);
+ return 0;
+
+ error_exit:
+ SAFE_FREE(buf);
+ return -1;
+}
+
+/****************************************************************************
+Drivers for Microsoft systems contain multiple files. Often, multiple drivers
+share one or more files. During the MS installation process files are checked
+to insure that only a newer version of a shared file is installed over an
+older version. There are several possibilities for this comparison. If there
+is no previous version, the new one is newer (obviously). If either file is
+missing the version info structure, compare the creation date (on Unix use
+the modification date). Otherwise chose the numerically larger version number.
+****************************************************************************/
+
+static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
+{
+ bool use_version = true;
+ char *filepath = NULL;
+
+ uint32 new_major;
+ uint32 new_minor;
+ time_t new_create_time;
+
+ uint32 old_major;
+ uint32 old_minor;
+ time_t old_create_time;
+
+ files_struct *fsp = NULL;
+ SMB_STRUCT_STAT st;
+ SMB_STRUCT_STAT stat_buf;
+
+ NTSTATUS status;
+
+ SET_STAT_INVALID(st);
+ SET_STAT_INVALID(stat_buf);
+ new_create_time = (time_t)0;
+ old_create_time = (time_t)0;
+
+ /* Get file version info (if available) for previous file (if it exists) */
+ filepath = driver_unix_convert(conn,old_file,&stat_buf);
+ if (!filepath) {
+ goto error_exit;
+ }
+
+ status = open_file_ntcreate(conn, NULL, filepath, &stat_buf,
+ FILE_GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN,
+ 0,
+ FILE_ATTRIBUTE_NORMAL,
+ INTERNAL_OPEN_ONLY,
+ NULL, &fsp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ /* Old file not found, so by definition new file is in fact newer */
+ DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n",
+ filepath, errno));
+ return 1;
+
+ } else {
+ int ret = get_file_version(fsp, old_file, &old_major, &old_minor);
+ if (ret == -1) {
+ goto error_exit;
+ }
+
+ if (!ret) {
+ DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
+ old_file));
+ use_version = false;
+ if (SMB_VFS_FSTAT(fsp, &st) == -1) {
+ goto error_exit;
+ }
+ old_create_time = st.st_mtime;
+ DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", old_create_time));
+ }
+ }
+ close_file(fsp, NORMAL_CLOSE);
+
+ /* Get file version info (if available) for new file */
+ filepath = driver_unix_convert(conn,new_file,&stat_buf);
+ if (!filepath) {
+ goto error_exit;
+ }
+
+ status = open_file_ntcreate(conn, NULL, filepath, &stat_buf,
+ FILE_GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN,
+ 0,
+ FILE_ATTRIBUTE_NORMAL,
+ INTERNAL_OPEN_ONLY,
+ NULL, &fsp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ /* New file not found, this shouldn't occur if the caller did its job */
+ DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n",
+ filepath, errno));
+ goto error_exit;
+
+ } else {
+ int ret = get_file_version(fsp, new_file, &new_major, &new_minor);
+ if (ret == -1) {
+ goto error_exit;
+ }
+
+ if (!ret) {
+ DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
+ new_file));
+ use_version = false;
+ if (SMB_VFS_FSTAT(fsp, &st) == -1) {
+ goto error_exit;
+ }
+ new_create_time = st.st_mtime;
+ DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", new_create_time));
+ }
+ }
+ close_file(fsp, NORMAL_CLOSE);
+
+ if (use_version && (new_major != old_major || new_minor != old_minor)) {
+ /* Compare versions and choose the larger version number */
+ if (new_major > old_major ||
+ (new_major == old_major && new_minor > old_minor)) {
+
+ DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
+ return 1;
+ }
+ else {
+ DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
+ return 0;
+ }
+
+ } else {
+ /* Compare modification time/dates and choose the newest time/date */
+ if (new_create_time > old_create_time) {
+ DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
+ return 1;
+ }
+ else {
+ DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
+ return 0;
+ }
+ }
+
+ error_exit:
+ if(fsp)
+ close_file(fsp, NORMAL_CLOSE);
+ return -1;
+}
+
+/****************************************************************************
+Determine the correct cVersion associated with an architecture and driver
+****************************************************************************/
+static uint32 get_correct_cversion(const char *architecture, fstring driverpath_in,
+ struct current_user *user, WERROR *perr)
+{
+ int cversion;
+ NTSTATUS nt_status;
+ char *driverpath = NULL;
+ DATA_BLOB null_pw;
+ fstring res_type;
+ files_struct *fsp = NULL;
+ SMB_STRUCT_STAT st;
+ connection_struct *conn;
+ NTSTATUS status;
+
+ SET_STAT_INVALID(st);
+
+ *perr = WERR_INVALID_PARAM;
+
+ /* If architecture is Windows 95/98/ME, the version is always 0. */
+ if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
+ DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
+ *perr = WERR_OK;
+ return 0;
+ }
+
+ /* If architecture is Windows x64, the version is always 3. */
+ if (strcmp(architecture, SPL_ARCH_X64) == 0) {
+ DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
+ *perr = WERR_OK;
+ return 3;
+ }
+
+ /*
+ * Connect to the print$ share under the same account as the user connected
+ * to the rpc pipe. Note we must still be root to do this.
+ */
+
+ /* Null password is ok - we are already an authenticated user... */
+ null_pw = data_blob_null;
+ fstrcpy(res_type, "A:");
+ become_root();
+ conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
+ unbecome_root();
+
+ if (conn == NULL) {
+ DEBUG(0,("get_correct_cversion: Unable to connect\n"));
+ *perr = ntstatus_to_werror(nt_status);
+ return -1;
+ }
+
+ /* We are temporarily becoming the connection user. */
+ if (!become_user(conn, user->vuid)) {
+ DEBUG(0,("get_correct_cversion: Can't become user!\n"));
+ *perr = WERR_ACCESS_DENIED;
+ return -1;
+ }
+
+ /* Open the driver file (Portable Executable format) and determine the
+ * deriver the cversion. */
+ driverpath = talloc_asprintf(talloc_tos(),
+ "%s/%s",
+ architecture,
+ driverpath_in);
+ if (!driverpath) {
+ *perr = WERR_NOMEM;
+ goto error_exit;
+ }
+
+ driverpath = driver_unix_convert(conn,driverpath,&st);
+ if (!driverpath) {
+ *perr = WERR_NOMEM;
+ goto error_exit;
+ }
+
+ if (!vfs_file_exist(conn, driverpath, &st)) {
+ *perr = WERR_BADFILE;
+ goto error_exit;
+ }
+
+ status = open_file_ntcreate(conn, NULL, driverpath, &st,
+ FILE_GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN,
+ 0,
+ FILE_ATTRIBUTE_NORMAL,
+ INTERNAL_OPEN_ONLY,
+ NULL, &fsp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
+ driverpath, errno));
+ *perr = WERR_ACCESS_DENIED;
+ goto error_exit;
+ } else {
+ uint32 major;
+ uint32 minor;
+ int ret = get_file_version(fsp, driverpath, &major, &minor);
+ if (ret == -1) goto error_exit;
+
+ if (!ret) {
+ DEBUG(6,("get_correct_cversion: Version info not found [%s]\n", driverpath));
+ goto error_exit;
+ }
+
+ /*
+ * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
+ * for more details. Version in this case is not just the version of the
+ * file, but the version in the sense of kernal mode (2) vs. user mode
+ * (3) drivers. Other bits of the version fields are the version info.
+ * JRR 010716
+ */
+ cversion = major & 0x0000ffff;
+ switch (cversion) {
+ case 2: /* WinNT drivers */
+ case 3: /* Win2K drivers */
+ break;
+
+ default:
+ DEBUG(6,("get_correct_cversion: cversion invalid [%s] cversion = %d\n",
+ driverpath, cversion));
+ goto error_exit;
+ }
+
+ DEBUG(10,("get_correct_cversion: Version info found [%s] major = 0x%x minor = 0x%x\n",
+ driverpath, major, minor));
+ }
+
+ DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
+ driverpath, cversion));
+
+ close_file(fsp, NORMAL_CLOSE);
+ close_cnum(conn, user->vuid);
+ unbecome_user();
+ *perr = WERR_OK;
+ return cversion;
+
+
+ error_exit:
+
+ if(fsp)
+ close_file(fsp, NORMAL_CLOSE);
+
+ close_cnum(conn, user->vuid);
+ unbecome_user();
+ return -1;
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver,
+ struct current_user *user)
+{
+ const char *architecture;
+ fstring new_name;
+ char *p;
+ int i;
+ WERROR err;
+
+ /* clean up the driver name.
+ * we can get .\driver.dll
+ * or worse c:\windows\system\driver.dll !
+ */
+ /* using an intermediate string to not have overlaping memcpy()'s */
+ if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->driverpath, new_name);
+ }
+
+ if ((p = strrchr(driver->datafile,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->datafile, new_name);
+ }
+
+ if ((p = strrchr(driver->configfile,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->configfile, new_name);
+ }
+
+ if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->helpfile, new_name);
+ }
+
+ if (driver->dependentfiles) {
+ for (i=0; *driver->dependentfiles[i]; i++) {
+ if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->dependentfiles[i], new_name);
+ }
+ }
+ }
+
+ architecture = get_short_archi(driver->environment);
+ if (!architecture) {
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+
+ /* jfm:7/16/2000 the client always sends the cversion=0.
+ * The server should check which version the driver is by reading
+ * the PE header of driver->driverpath.
+ *
+ * For Windows 95/98 the version is 0 (so the value sent is correct)
+ * For Windows NT (the architecture doesn't matter)
+ * NT 3.1: cversion=0
+ * NT 3.5/3.51: cversion=1
+ * NT 4: cversion=2
+ * NT2K: cversion=3
+ */
+ if ((driver->cversion = get_correct_cversion( architecture, driver->driverpath, user, &err)) == -1)
+ return err;
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver, struct current_user *user)
+{
+ const char *architecture;
+ fstring new_name;
+ char *p;
+ int i;
+ WERROR err;
+
+ /* clean up the driver name.
+ * we can get .\driver.dll
+ * or worse c:\windows\system\driver.dll !
+ */
+ /* using an intermediate string to not have overlaping memcpy()'s */
+ if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->driverpath, new_name);
+ }
+
+ if ((p = strrchr(driver->datafile,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->datafile, new_name);
+ }
+
+ if ((p = strrchr(driver->configfile,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->configfile, new_name);
+ }
+
+ if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->helpfile, new_name);
+ }
+
+ if (driver->dependentfiles) {
+ for (i=0; *driver->dependentfiles[i]; i++) {
+ if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->dependentfiles[i], new_name);
+ }
+ }
+ }
+
+ architecture = get_short_archi(driver->environment);
+ if (!architecture) {
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+
+ /* jfm:7/16/2000 the client always sends the cversion=0.
+ * The server should check which version the driver is by reading
+ * the PE header of driver->driverpath.
+ *
+ * For Windows 95/98 the version is 0 (so the value sent is correct)
+ * For Windows NT (the architecture doesn't matter)
+ * NT 3.1: cversion=0
+ * NT 3.5/3.51: cversion=1
+ * NT 4: cversion=2
+ * NT2K: cversion=3
+ */
+
+ if ((driver->version = get_correct_cversion(architecture, driver->driverpath, user, &err)) == -1)
+ return err;
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+WERROR clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
+ uint32 level, struct current_user *user)
+{
+ switch (level) {
+ case 3:
+ {
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
+ driver=driver_abstract.info_3;
+ return clean_up_driver_struct_level_3(driver, user);
+ }
+ case 6:
+ {
+ NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver;
+ driver=driver_abstract.info_6;
+ return clean_up_driver_struct_level_6(driver, user);
+ }
+ default:
+ return WERR_INVALID_PARAM;
+ }
+}
+
+/****************************************************************************
+ This function sucks and should be replaced. JRA.
+****************************************************************************/
+
+static void convert_level_6_to_level3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dst, NT_PRINTER_DRIVER_INFO_LEVEL_6 *src)
+{
+ dst->cversion = src->version;
+
+ fstrcpy( dst->name, src->name);
+ fstrcpy( dst->environment, src->environment);
+ fstrcpy( dst->driverpath, src->driverpath);
+ fstrcpy( dst->datafile, src->datafile);
+ fstrcpy( dst->configfile, src->configfile);
+ fstrcpy( dst->helpfile, src->helpfile);
+ fstrcpy( dst->monitorname, src->monitorname);
+ fstrcpy( dst->defaultdatatype, src->defaultdatatype);
+ dst->dependentfiles = src->dependentfiles;
+}
+
+#if 0 /* Debugging function */
+
+static char* ffmt(unsigned char *c){
+ int i;
+ static char ffmt_str[17];
+
+ for (i=0; i<16; i++) {
+ if ((c[i] < ' ') || (c[i] > '~'))
+ ffmt_str[i]='.';
+ else
+ ffmt_str[i]=c[i];
+ }
+ ffmt_str[16]='\0';
+ return ffmt_str;
+}
+
+#endif
+
+/****************************************************************************
+****************************************************************************/
+WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level,
+ struct current_user *user, WERROR *perr)
+{
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 converted_driver;
+ const char *architecture;
+ char *new_dir = NULL;
+ char *old_name = NULL;
+ char *new_name = NULL;
+ DATA_BLOB null_pw;
+ connection_struct *conn;
+ NTSTATUS nt_status;
+ fstring res_type;
+ SMB_STRUCT_STAT st;
+ int i;
+ TALLOC_CTX *ctx = talloc_tos();
+ int ver = 0;
+
+ *perr = WERR_OK;
+
+ if (level==3)
+ driver=driver_abstract.info_3;
+ else if (level==6) {
+ convert_level_6_to_level3(&converted_driver, driver_abstract.info_6);
+ driver = &converted_driver;
+ } else {
+ DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)level ));
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ architecture = get_short_archi(driver->environment);
+ if (!architecture) {
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+
+ /*
+ * Connect to the print$ share under the same account as the user connected to the rpc pipe.
+ * Note we must be root to do this.
+ */
+
+ null_pw = data_blob_null;
+ fstrcpy(res_type, "A:");
+ become_root();
+ conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
+ unbecome_root();
+
+ if (conn == NULL) {
+ DEBUG(0,("move_driver_to_download_area: Unable to connect\n"));
+ *perr = ntstatus_to_werror(nt_status);
+ return WERR_NO_SUCH_SHARE;
+ }
+
+ /*
+ * Save who we are - we are temporarily becoming the connection user.
+ */
+
+ if (!become_user(conn, conn->vuid)) {
+ DEBUG(0,("move_driver_to_download_area: Can't become user!\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ /* WE ARE NOW RUNNING AS USER conn->vuid !!!!! */
+
+ /*
+ * make the directories version and version\driver_name
+ * under the architecture directory.
+ */
+ DEBUG(5,("Creating first directory\n"));
+ new_dir = talloc_asprintf(ctx,
+ "%s/%d",
+ architecture,
+ driver->cversion);
+ if (!new_dir) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+ new_dir = driver_unix_convert(conn,new_dir,&st);
+ if (!new_dir) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+
+ create_directory(conn, NULL, new_dir);
+
+ /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
+ * listed for this driver which has already been moved, skip it (note:
+ * drivers may list the same file name several times. Then check if the
+ * file already exists in archi\cversion\, if so, check that the version
+ * info (or time stamps if version info is unavailable) is newer (or the
+ * date is later). If it is, move it to archi\cversion\filexxx.yyy.
+ * Otherwise, delete the file.
+ *
+ * If a file is not moved to archi\cversion\ because of an error, all the
+ * rest of the 'unmoved' driver files are removed from archi\. If one or
+ * more of the driver's files was already moved to archi\cversion\, it
+ * potentially leaves the driver in a partially updated state. Version
+ * trauma will most likely occur if an client attempts to use any printer
+ * bound to the driver. Perhaps a rewrite to make sure the moves can be
+ * done is appropriate... later JRR
+ */
+
+ DEBUG(5,("Moving files now !\n"));
+
+ if (driver->driverpath && strlen(driver->driverpath)) {
+ new_name = talloc_asprintf(ctx,
+ "%s/%s",
+ architecture,
+ driver->driverpath);
+ if (!new_name) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+ old_name = talloc_asprintf(ctx,
+ "%s/%s",
+ new_dir,
+ driver->driverpath);
+ if (!old_name) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+
+ if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
+ new_name = driver_unix_convert(conn,new_name,&st);
+ if (!new_name) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+ if ( !NT_STATUS_IS_OK(copy_file(ctx,conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE|
+ OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
+ DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
+ new_name, old_name));
+ *perr = WERR_ACCESS_DENIED;
+ ver = -1;
+ }
+ }
+ }
+
+ if (driver->datafile && strlen(driver->datafile)) {
+ if (!strequal(driver->datafile, driver->driverpath)) {
+ new_name = talloc_asprintf(ctx,
+ "%s/%s",
+ architecture,
+ driver->datafile);
+ if (!new_name) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+ old_name = talloc_asprintf(ctx,
+ "%s/%s",
+ new_dir,
+ driver->datafile);
+ if (!old_name) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+ if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
+ new_name = driver_unix_convert(conn,new_name,&st);
+ if (!new_name) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+ if ( !NT_STATUS_IS_OK(copy_file(ctx,conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE|
+ OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
+ DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
+ new_name, old_name));
+ *perr = WERR_ACCESS_DENIED;
+ ver = -1;
+ }
+ }
+ }
+ }
+
+ if (driver->configfile && strlen(driver->configfile)) {
+ if (!strequal(driver->configfile, driver->driverpath) &&
+ !strequal(driver->configfile, driver->datafile)) {
+ new_name = talloc_asprintf(ctx,
+ "%s/%s",
+ architecture,
+ driver->configfile);
+ if (!new_name) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+ old_name = talloc_asprintf(ctx,
+ "%s/%s",
+ new_dir,
+ driver->configfile);
+ if (!old_name) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+ if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
+ new_name = driver_unix_convert(conn,new_name,&st);
+ if (!new_name) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+ if ( !NT_STATUS_IS_OK(copy_file(ctx,conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE|
+ OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
+ DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
+ new_name, old_name));
+ *perr = WERR_ACCESS_DENIED;
+ ver = -1;
+ }
+ }
+ }
+ }
+
+ if (driver->helpfile && strlen(driver->helpfile)) {
+ if (!strequal(driver->helpfile, driver->driverpath) &&
+ !strequal(driver->helpfile, driver->datafile) &&
+ !strequal(driver->helpfile, driver->configfile)) {
+ new_name = talloc_asprintf(ctx,
+ "%s/%s",
+ architecture,
+ driver->helpfile);
+ if (!new_name) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+ old_name = talloc_asprintf(ctx,
+ "%s/%s",
+ new_dir,
+ driver->helpfile);
+ if (!old_name) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+ if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
+ new_name = driver_unix_convert(conn,new_name,&st);
+ if (!new_name) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+ if ( !NT_STATUS_IS_OK(copy_file(ctx,conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE|
+ OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
+ DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
+ new_name, old_name));
+ *perr = WERR_ACCESS_DENIED;
+ ver = -1;
+ }
+ }
+ }
+ }
+
+ if (driver->dependentfiles) {
+ for (i=0; *driver->dependentfiles[i]; i++) {
+ if (!strequal(driver->dependentfiles[i], driver->driverpath) &&
+ !strequal(driver->dependentfiles[i], driver->datafile) &&
+ !strequal(driver->dependentfiles[i], driver->configfile) &&
+ !strequal(driver->dependentfiles[i], driver->helpfile)) {
+ int j;
+ for (j=0; j < i; j++) {
+ if (strequal(driver->dependentfiles[i], driver->dependentfiles[j])) {
+ goto NextDriver;
+ }
+ }
+
+ new_name = talloc_asprintf(ctx,
+ "%s/%s",
+ architecture,
+ driver->dependentfiles[i]);
+ if (!new_name) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+ old_name = talloc_asprintf(ctx,
+ "%s/%s",
+ new_dir,
+ driver->dependentfiles[i]);
+ if (!old_name) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+ if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
+ new_name = driver_unix_convert(conn,new_name,&st);
+ if (!new_name) {
+ *perr = WERR_NOMEM;
+ goto err_exit;
+ }
+ if ( !NT_STATUS_IS_OK(copy_file(ctx,conn, new_name, old_name,
+ OPENX_FILE_EXISTS_TRUNCATE|
+ OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
+ DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
+ new_name, old_name));
+ *perr = WERR_ACCESS_DENIED;
+ ver = -1;
+ }
+ }
+ }
+ NextDriver: ;
+ }
+ }
+
+ err_exit:
+
+ close_cnum(conn, user->vuid);
+ unbecome_user();
+
+ if (W_ERROR_EQUAL(*perr, WERR_OK)) {
+ return WERR_OK;
+ }
+ if (ver == -1) {
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+ return (*perr);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ int len, buflen;
+ const char *architecture;
+ char *directory = NULL;
+ fstring temp_name;
+ char *key = NULL;
+ uint8 *buf;
+ int i, ret;
+ TDB_DATA dbuf;
+
+ architecture = get_short_archi(driver->environment);
+ if (!architecture) {
+ return (uint32)-1;
+ }
+
+ /* The names are relative. We store them in the form: \print$\arch\version\driver.xxx
+ * \\server is added in the rpc server layer.
+ * It does make sense to NOT store the server's name in the printer TDB.
+ */
+
+ directory = talloc_asprintf(ctx, "\\print$\\%s\\%d\\",
+ architecture, driver->cversion);
+ if (!directory) {
+ return (uint32)-1;
+ }
+
+ /* .inf files do not always list a file for each of the four standard files.
+ * Don't prepend a path to a null filename, or client claims:
+ * "The server on which the printer resides does not have a suitable
+ * <printer driver name> printer driver installed. Click OK if you
+ * wish to install the driver on your local machine."
+ */
+ if (strlen(driver->driverpath)) {
+ fstrcpy(temp_name, driver->driverpath);
+ slprintf(driver->driverpath, sizeof(driver->driverpath)-1, "%s%s", directory, temp_name);
+ }
+
+ if (strlen(driver->datafile)) {
+ fstrcpy(temp_name, driver->datafile);
+ slprintf(driver->datafile, sizeof(driver->datafile)-1, "%s%s", directory, temp_name);
+ }
+
+ if (strlen(driver->configfile)) {
+ fstrcpy(temp_name, driver->configfile);
+ slprintf(driver->configfile, sizeof(driver->configfile)-1, "%s%s", directory, temp_name);
+ }
+
+ if (strlen(driver->helpfile)) {
+ fstrcpy(temp_name, driver->helpfile);
+ slprintf(driver->helpfile, sizeof(driver->helpfile)-1, "%s%s", directory, temp_name);
+ }
+
+ if (driver->dependentfiles) {
+ for (i=0; *driver->dependentfiles[i]; i++) {
+ fstrcpy(temp_name, driver->dependentfiles[i]);
+ slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i])-1, "%s%s", directory, temp_name);
+ }
+ }
+
+ key = talloc_asprintf(ctx, "%s%s/%d/%s", DRIVERS_PREFIX,
+ architecture, driver->cversion, driver->name);
+ if (!key) {
+ return (uint32)-1;
+ }
+
+ DEBUG(5,("add_a_printer_driver_3: Adding driver with key %s\n", key ));
+
+ buf = NULL;
+ len = buflen = 0;
+
+ again:
+ len = 0;
+ len += tdb_pack(buf+len, buflen-len, "dffffffff",
+ driver->cversion,
+ driver->name,
+ driver->environment,
+ driver->driverpath,
+ driver->datafile,
+ driver->configfile,
+ driver->helpfile,
+ driver->monitorname,
+ driver->defaultdatatype);
+
+ if (driver->dependentfiles) {
+ for (i=0; *driver->dependentfiles[i]; i++) {
+ len += tdb_pack(buf+len, buflen-len, "f",
+ driver->dependentfiles[i]);
+ }
+ }
+
+ if (len != buflen) {
+ buf = (uint8 *)SMB_REALLOC(buf, len);
+ if (!buf) {
+ DEBUG(0,("add_a_printer_driver_3: failed to enlarge buffer\n!"));
+ ret = -1;
+ goto done;
+ }
+ buflen = len;
+ goto again;
+ }
+
+ dbuf.dptr = buf;
+ dbuf.dsize = len;
+
+ ret = tdb_store_bystring(tdb_drivers, key, dbuf, TDB_REPLACE);
+
+done:
+ if (ret)
+ DEBUG(0,("add_a_printer_driver_3: Adding driver with key %s failed.\n", key ));
+
+ SAFE_FREE(buf);
+ return ret;
+}
+
+/****************************************************************************
+****************************************************************************/
+static uint32 add_a_printer_driver_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
+{
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 info3;
+
+ ZERO_STRUCT(info3);
+ info3.cversion = driver->version;
+ fstrcpy(info3.name,driver->name);
+ fstrcpy(info3.environment,driver->environment);
+ fstrcpy(info3.driverpath,driver->driverpath);
+ fstrcpy(info3.datafile,driver->datafile);
+ fstrcpy(info3.configfile,driver->configfile);
+ fstrcpy(info3.helpfile,driver->helpfile);
+ fstrcpy(info3.monitorname,driver->monitorname);
+ fstrcpy(info3.defaultdatatype,driver->defaultdatatype);
+ info3.dependentfiles = driver->dependentfiles;
+
+ return add_a_printer_driver_3(&info3);
+}
+
+
+/****************************************************************************
+****************************************************************************/
+static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, const char *driver, const char *arch)
+{
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 info;
+
+ ZERO_STRUCT(info);
+
+ fstrcpy(info.name, driver);
+ fstrcpy(info.defaultdatatype, "RAW");
+
+ fstrcpy(info.driverpath, "");
+ fstrcpy(info.datafile, "");
+ fstrcpy(info.configfile, "");
+ fstrcpy(info.helpfile, "");
+
+ if ((info.dependentfiles= SMB_MALLOC_ARRAY(fstring, 2)) == NULL)
+ return WERR_NOMEM;
+
+ memset(info.dependentfiles, '\0', 2*sizeof(fstring));
+ fstrcpy(info.dependentfiles[0], "");
+
+ *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&info, sizeof(info));
+ if (!*info_ptr) {
+ SAFE_FREE(info.dependentfiles);
+ return WERR_NOMEM;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring drivername, const char *arch, uint32 version)
+{
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 driver;
+ TDB_DATA dbuf;
+ const char *architecture;
+ int len = 0;
+ int i;
+ char *key = NULL;
+
+ ZERO_STRUCT(driver);
+
+ architecture = get_short_archi(arch);
+ if ( !architecture ) {
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+
+ /* Windows 4.0 (i.e. win9x) should always use a version of 0 */
+
+ if ( strcmp( architecture, SPL_ARCH_WIN40 ) == 0 )
+ version = 0;
+
+ DEBUG(8,("get_a_printer_driver_3: [%s%s/%d/%s]\n", DRIVERS_PREFIX, architecture, version, drivername));
+
+ if (asprintf(&key, "%s%s/%d/%s", DRIVERS_PREFIX,
+ architecture, version, drivername) < 0) {
+ return WERR_NOMEM;
+ }
+
+ dbuf = tdb_fetch_bystring(tdb_drivers, key);
+ if (!dbuf.dptr) {
+ SAFE_FREE(key);
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+
+ len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff",
+ &driver.cversion,
+ driver.name,
+ driver.environment,
+ driver.driverpath,
+ driver.datafile,
+ driver.configfile,
+ driver.helpfile,
+ driver.monitorname,
+ driver.defaultdatatype);
+
+ i=0;
+ while (len < dbuf.dsize) {
+ driver.dependentfiles = SMB_REALLOC_ARRAY(driver.dependentfiles, fstring, i+2);
+ if ( !driver.dependentfiles ) {
+ DEBUG(0,("get_a_printer_driver_3: failed to enlarge buffer!\n"));
+ break;
+ }
+
+ len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f",
+ &driver.dependentfiles[i]);
+ i++;
+ }
+
+ if ( driver.dependentfiles )
+ fstrcpy( driver.dependentfiles[i], "" );
+
+ SAFE_FREE(dbuf.dptr);
+ SAFE_FREE(key);
+
+ if (len != dbuf.dsize) {
+ SAFE_FREE(driver.dependentfiles);
+
+ return get_a_printer_driver_3_default(info_ptr, drivername, arch);
+ }
+
+ *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&driver, sizeof(driver));
+ if (!*info_ptr) {
+ SAFE_FREE(driver.dependentfiles);
+ return WERR_NOMEM;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ Debugging function, dump at level 6 the struct in the logs.
+****************************************************************************/
+
+static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
+{
+ uint32 result;
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
+ int i;
+
+ DEBUG(20,("Dumping printer driver at level [%d]\n", level));
+
+ switch (level)
+ {
+ case 3:
+ {
+ if (driver.info_3 == NULL)
+ result=5;
+ else {
+ info3=driver.info_3;
+
+ DEBUGADD(20,("version:[%d]\n", info3->cversion));
+ DEBUGADD(20,("name:[%s]\n", info3->name));
+ DEBUGADD(20,("environment:[%s]\n", info3->environment));
+ DEBUGADD(20,("driverpath:[%s]\n", info3->driverpath));
+ DEBUGADD(20,("datafile:[%s]\n", info3->datafile));
+ DEBUGADD(20,("configfile:[%s]\n", info3->configfile));
+ DEBUGADD(20,("helpfile:[%s]\n", info3->helpfile));
+ DEBUGADD(20,("monitorname:[%s]\n", info3->monitorname));
+ DEBUGADD(20,("defaultdatatype:[%s]\n", info3->defaultdatatype));
+
+ for (i=0; info3->dependentfiles &&
+ *info3->dependentfiles[i]; i++) {
+ DEBUGADD(20,("dependentfile:[%s]\n",
+ info3->dependentfiles[i]));
+ }
+ result=0;
+ }
+ break;
+ }
+ default:
+ DEBUGADD(20,("dump_a_printer_driver: Level %u not implemented\n", (unsigned int)level));
+ result=1;
+ break;
+ }
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+int pack_devicemode(NT_DEVICEMODE *nt_devmode, uint8 *buf, int buflen)
+{
+ int len = 0;
+
+ len += tdb_pack(buf+len, buflen-len, "p", nt_devmode);
+
+ if (!nt_devmode)
+ return len;
+
+ len += tdb_pack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
+ nt_devmode->devicename,
+ nt_devmode->formname,
+
+ nt_devmode->specversion,
+ nt_devmode->driverversion,
+ nt_devmode->size,
+ nt_devmode->driverextra,
+ nt_devmode->orientation,
+ nt_devmode->papersize,
+ nt_devmode->paperlength,
+ nt_devmode->paperwidth,
+ nt_devmode->scale,
+ nt_devmode->copies,
+ nt_devmode->defaultsource,
+ nt_devmode->printquality,
+ nt_devmode->color,
+ nt_devmode->duplex,
+ nt_devmode->yresolution,
+ nt_devmode->ttoption,
+ nt_devmode->collate,
+ nt_devmode->logpixels,
+
+ nt_devmode->fields,
+ nt_devmode->bitsperpel,
+ nt_devmode->pelswidth,
+ nt_devmode->pelsheight,
+ nt_devmode->displayflags,
+ nt_devmode->displayfrequency,
+ nt_devmode->icmmethod,
+ nt_devmode->icmintent,
+ nt_devmode->mediatype,
+ nt_devmode->dithertype,
+ nt_devmode->reserved1,
+ nt_devmode->reserved2,
+ nt_devmode->panningwidth,
+ nt_devmode->panningheight,
+ nt_devmode->nt_dev_private);
+
+ if (nt_devmode->nt_dev_private) {
+ len += tdb_pack(buf+len, buflen-len, "B",
+ nt_devmode->driverextra,
+ nt_devmode->nt_dev_private);
+ }
+
+ DEBUG(8,("Packed devicemode [%s]\n", nt_devmode->formname));
+
+ return len;
+}
+
+/****************************************************************************
+ Pack all values in all printer keys
+ ***************************************************************************/
+
+static int pack_values(NT_PRINTER_DATA *data, uint8 *buf, int buflen)
+{
+ int len = 0;
+ int i, j;
+ REGISTRY_VALUE *val;
+ REGVAL_CTR *val_ctr;
+ char *path = NULL;
+ int num_values;
+
+ if ( !data )
+ return 0;
+
+ /* loop over all keys */
+
+ for ( i=0; i<data->num_keys; i++ ) {
+ val_ctr = data->keys[i].values;
+ num_values = regval_ctr_numvals( val_ctr );
+
+ /* pack the keyname followed by a empty value */
+
+ len += tdb_pack(buf+len, buflen-len, "pPdB",
+ &data->keys[i].name,
+ data->keys[i].name,
+ REG_NONE,
+ 0,
+ NULL);
+
+ /* now loop over all values */
+
+ for ( j=0; j<num_values; j++ ) {
+ /* pathname should be stored as <key>\<value> */
+
+ val = regval_ctr_specific_value( val_ctr, j );
+ if (asprintf(&path, "%s\\%s",
+ data->keys[i].name,
+ regval_name(val)) < 0) {
+ return -1;
+ }
+
+ len += tdb_pack(buf+len, buflen-len, "pPdB",
+ val,
+ path,
+ regval_type(val),
+ regval_size(val),
+ regval_data_p(val) );
+
+ DEBUG(8,("specific: [%s], len: %d\n", regval_name(val), regval_size(val)));
+ SAFE_FREE(path);
+ }
+
+ }
+
+ /* terminator */
+
+ len += tdb_pack(buf+len, buflen-len, "p", NULL);
+
+ return len;
+}
+
+
+/****************************************************************************
+ Delete a printer - this just deletes the printer info file, any open
+ handles are not affected.
+****************************************************************************/
+
+uint32 del_a_printer(const char *sharename)
+{
+ TDB_DATA kbuf;
+ char *printdb_path = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ kbuf = make_printer_tdbkey(ctx, sharename);
+ tdb_delete(tdb_printers, kbuf);
+
+ kbuf= make_printers_secdesc_tdbkey(ctx, sharename);
+ tdb_delete(tdb_printers, kbuf);
+
+ close_all_print_db();
+
+ if (geteuid() == 0) {
+ if (asprintf(&printdb_path, "%s%s.tdb",
+ lock_path("printing/"),
+ sharename) < 0) {
+ return (uint32)-1;
+ }
+ unlink(printdb_path);
+ SAFE_FREE(printdb_path);
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
+{
+ uint8 *buf;
+ int buflen, len;
+ int retlen;
+ WERROR ret;
+ TDB_DATA kbuf, dbuf;
+
+ /*
+ * in addprinter: no servername and the printer is the name
+ * in setprinter: servername is \\server
+ * and printer is \\server\\printer
+ *
+ * Samba manages only local printers.
+ * we currently don't support things like i
+ * path=\\other_server\printer
+ *
+ * We only store the printername, not \\server\printername
+ */
+
+ if ( info->servername[0] != '\0' ) {
+ trim_string(info->printername, info->servername, NULL);
+ trim_char(info->printername, '\\', '\0');
+ info->servername[0]='\0';
+ }
+
+ /*
+ * JFM: one day I'll forget.
+ * below that's info->portname because that's the SAMBA sharename
+ * and I made NT 'thinks' it's the portname
+ * the info->sharename is the thing you can name when you add a printer
+ * that's the short-name when you create shared printer for 95/98
+ * So I've made a limitation in SAMBA: you can only have 1 printer model
+ * behind a SAMBA share.
+ */
+
+ buf = NULL;
+ buflen = 0;
+
+ again:
+ len = 0;
+ len += tdb_pack(buf+len, buflen-len, "dddddddddddfffffPfffff",
+ info->attributes,
+ info->priority,
+ info->default_priority,
+ info->starttime,
+ info->untiltime,
+ info->status,
+ info->cjobs,
+ info->averageppm,
+ info->changeid,
+ info->c_setprinter,
+ info->setuptime,
+ info->servername,
+ info->printername,
+ info->sharename,
+ info->portname,
+ info->drivername,
+ info->comment,
+ info->location,
+ info->sepfile,
+ info->printprocessor,
+ info->datatype,
+ info->parameters);
+
+ len += pack_devicemode(info->devmode, buf+len, buflen-len);
+ retlen = pack_values( info->data, buf+len, buflen-len );
+ if (retlen == -1) {
+ ret = WERR_NOMEM;
+ goto done;
+ }
+ len += retlen;
+
+ if (buflen != len) {
+ buf = (uint8 *)SMB_REALLOC(buf, len);
+ if (!buf) {
+ DEBUG(0,("update_a_printer_2: failed to enlarge buffer!\n"));
+ ret = WERR_NOMEM;
+ goto done;
+ }
+ buflen = len;
+ goto again;
+ }
+
+ kbuf = make_printer_tdbkey(talloc_tos(), info->sharename );
+
+ dbuf.dptr = buf;
+ dbuf.dsize = len;
+
+ ret = (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) == 0? WERR_OK : WERR_NOMEM);
+
+done:
+ if (!W_ERROR_IS_OK(ret))
+ DEBUG(8, ("error updating printer to tdb on disk\n"));
+
+ SAFE_FREE(buf);
+
+ DEBUG(8,("packed printer [%s] with driver [%s] portname=[%s] len=%d\n",
+ info->sharename, info->drivername, info->portname, len));
+
+ return ret;
+}
+
+
+/****************************************************************************
+ Malloc and return an NT devicemode.
+****************************************************************************/
+
+NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
+{
+
+ char adevice[MAXDEVICENAME];
+ NT_DEVICEMODE *nt_devmode = SMB_MALLOC_P(NT_DEVICEMODE);
+
+ if (nt_devmode == NULL) {
+ DEBUG(0,("construct_nt_devicemode: malloc fail.\n"));
+ return NULL;
+ }
+
+ ZERO_STRUCTP(nt_devmode);
+
+ slprintf(adevice, sizeof(adevice), "%s", default_devicename);
+ fstrcpy(nt_devmode->devicename, adevice);
+
+ fstrcpy(nt_devmode->formname, "Letter");
+
+ nt_devmode->specversion = 0x0401;
+ nt_devmode->driverversion = 0x0400;
+ nt_devmode->size = 0x00DC;
+ nt_devmode->driverextra = 0x0000;
+ nt_devmode->fields = FORMNAME | TTOPTION | PRINTQUALITY |
+ DEFAULTSOURCE | COPIES | SCALE |
+ PAPERSIZE | ORIENTATION;
+ nt_devmode->orientation = 1;
+ nt_devmode->papersize = PAPER_LETTER;
+ nt_devmode->paperlength = 0;
+ nt_devmode->paperwidth = 0;
+ nt_devmode->scale = 0x64;
+ nt_devmode->copies = 1;
+ nt_devmode->defaultsource = BIN_FORMSOURCE;
+ nt_devmode->printquality = RES_HIGH; /* 0x0258 */
+ nt_devmode->color = COLOR_MONOCHROME;
+ nt_devmode->duplex = DUP_SIMPLEX;
+ nt_devmode->yresolution = 0;
+ nt_devmode->ttoption = TT_SUBDEV;
+ nt_devmode->collate = COLLATE_FALSE;
+ nt_devmode->icmmethod = 0;
+ nt_devmode->icmintent = 0;
+ nt_devmode->mediatype = 0;
+ nt_devmode->dithertype = 0;
+
+ /* non utilisés par un driver d'imprimante */
+ nt_devmode->logpixels = 0;
+ nt_devmode->bitsperpel = 0;
+ nt_devmode->pelswidth = 0;
+ nt_devmode->pelsheight = 0;
+ nt_devmode->displayflags = 0;
+ nt_devmode->displayfrequency = 0;
+ nt_devmode->reserved1 = 0;
+ nt_devmode->reserved2 = 0;
+ nt_devmode->panningwidth = 0;
+ nt_devmode->panningheight = 0;
+
+ nt_devmode->nt_dev_private = NULL;
+ return nt_devmode;
+}
+
+/****************************************************************************
+ Deepcopy an NT devicemode.
+****************************************************************************/
+
+NT_DEVICEMODE *dup_nt_devicemode(NT_DEVICEMODE *nt_devicemode)
+{
+ NT_DEVICEMODE *new_nt_devicemode = NULL;
+
+ if ( !nt_devicemode )
+ return NULL;
+
+ if ((new_nt_devicemode = (NT_DEVICEMODE *)memdup(nt_devicemode, sizeof(NT_DEVICEMODE))) == NULL) {
+ DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
+ return NULL;
+ }
+
+ new_nt_devicemode->nt_dev_private = NULL;
+ if (nt_devicemode->nt_dev_private != NULL) {
+ if ((new_nt_devicemode->nt_dev_private = (uint8 *)memdup(nt_devicemode->nt_dev_private, nt_devicemode->driverextra)) == NULL) {
+ SAFE_FREE(new_nt_devicemode);
+ DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
+ return NULL;
+ }
+ }
+
+ return new_nt_devicemode;
+}
+
+/****************************************************************************
+ Clean up and deallocate a (maybe partially) allocated NT_DEVICEMODE.
+****************************************************************************/
+
+void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr)
+{
+ NT_DEVICEMODE *nt_devmode = *devmode_ptr;
+
+ if(nt_devmode == NULL)
+ return;
+
+ DEBUG(106,("free_nt_devicemode: deleting DEVMODE\n"));
+
+ SAFE_FREE(nt_devmode->nt_dev_private);
+ SAFE_FREE(*devmode_ptr);
+}
+
+/****************************************************************************
+ Clean up and deallocate a (maybe partially) allocated NT_PRINTER_INFO_LEVEL_2.
+****************************************************************************/
+
+static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
+{
+ NT_PRINTER_INFO_LEVEL_2 *info = *info_ptr;
+
+ if ( !info )
+ return;
+
+ free_nt_devicemode(&info->devmode);
+
+ TALLOC_FREE( *info_ptr );
+}
+
+
+/****************************************************************************
+****************************************************************************/
+int unpack_devicemode(NT_DEVICEMODE **nt_devmode, const uint8 *buf, int buflen)
+{
+ int len = 0;
+ int extra_len = 0;
+ NT_DEVICEMODE devmode;
+
+ ZERO_STRUCT(devmode);
+
+ len += tdb_unpack(buf+len, buflen-len, "p", nt_devmode);
+
+ if (!*nt_devmode) return len;
+
+ len += tdb_unpack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
+ devmode.devicename,
+ devmode.formname,
+
+ &devmode.specversion,
+ &devmode.driverversion,
+ &devmode.size,
+ &devmode.driverextra,
+ &devmode.orientation,
+ &devmode.papersize,
+ &devmode.paperlength,
+ &devmode.paperwidth,
+ &devmode.scale,
+ &devmode.copies,
+ &devmode.defaultsource,
+ &devmode.printquality,
+ &devmode.color,
+ &devmode.duplex,
+ &devmode.yresolution,
+ &devmode.ttoption,
+ &devmode.collate,
+ &devmode.logpixels,
+
+ &devmode.fields,
+ &devmode.bitsperpel,
+ &devmode.pelswidth,
+ &devmode.pelsheight,
+ &devmode.displayflags,
+ &devmode.displayfrequency,
+ &devmode.icmmethod,
+ &devmode.icmintent,
+ &devmode.mediatype,
+ &devmode.dithertype,
+ &devmode.reserved1,
+ &devmode.reserved2,
+ &devmode.panningwidth,
+ &devmode.panningheight,
+ &devmode.nt_dev_private);
+
+ if (devmode.nt_dev_private) {
+ /* the len in tdb_unpack is an int value and
+ * devmode.driverextra is only a short
+ */
+ len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.nt_dev_private);
+ devmode.driverextra=(uint16)extra_len;
+
+ /* check to catch an invalid TDB entry so we don't segfault */
+ if (devmode.driverextra == 0) {
+ devmode.nt_dev_private = NULL;
+ }
+ }
+
+ *nt_devmode = (NT_DEVICEMODE *)memdup(&devmode, sizeof(devmode));
+ if (!*nt_devmode) {
+ SAFE_FREE(devmode.nt_dev_private);
+ return -1;
+ }
+
+ DEBUG(8,("Unpacked devicemode [%s](%s)\n", devmode.devicename, devmode.formname));
+ if (devmode.nt_dev_private)
+ DEBUG(8,("with a private section of %d bytes\n", devmode.driverextra));
+
+ return len;
+}
+
+/****************************************************************************
+ Allocate and initialize a new slot.
+***************************************************************************/
+
+int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
+{
+ NT_PRINTER_KEY *d;
+ int key_index;
+
+ if ( !name || !data )
+ return -1;
+
+ /* allocate another slot in the NT_PRINTER_KEY array */
+
+ if ( !(d = TALLOC_REALLOC_ARRAY( data, data->keys, NT_PRINTER_KEY, data->num_keys+1)) ) {
+ DEBUG(0,("add_new_printer_key: Realloc() failed!\n"));
+ return -1;
+ }
+
+ data->keys = d;
+
+ key_index = data->num_keys;
+
+ /* initialze new key */
+
+ data->keys[key_index].name = talloc_strdup( data, name );
+
+ if ( !(data->keys[key_index].values = TALLOC_ZERO_P( data, REGVAL_CTR )) )
+ return -1;
+
+ data->num_keys++;
+
+ DEBUG(10,("add_new_printer_key: Inserted new data key [%s]\n", name ));
+
+ return key_index;
+}
+
+/****************************************************************************
+ search for a registry key name in the existing printer data
+ ***************************************************************************/
+
+int delete_printer_key( NT_PRINTER_DATA *data, const char *name )
+{
+ int i;
+
+ for ( i=0; i<data->num_keys; i++ ) {
+ if ( strequal( data->keys[i].name, name ) ) {
+
+ /* cleanup memory */
+
+ TALLOC_FREE( data->keys[i].name );
+ TALLOC_FREE( data->keys[i].values );
+
+ /* if not the end of the array, move remaining elements down one slot */
+
+ data->num_keys--;
+ if ( data->num_keys && (i < data->num_keys) )
+ memmove( &data->keys[i], &data->keys[i+1], sizeof(NT_PRINTER_KEY)*(data->num_keys-i) );
+
+ break;
+ }
+ }
+
+
+ return data->num_keys;
+}
+
+/****************************************************************************
+ search for a registry key name in the existing printer data
+ ***************************************************************************/
+
+int lookup_printerkey( NT_PRINTER_DATA *data, const char *name )
+{
+ int key_index = -1;
+ int i;
+
+ if ( !data || !name )
+ return -1;
+
+ DEBUG(12,("lookup_printerkey: Looking for [%s]\n", name));
+
+ /* loop over all existing keys */
+
+ for ( i=0; i<data->num_keys; i++ ) {
+ if ( strequal(data->keys[i].name, name) ) {
+ DEBUG(12,("lookup_printerkey: Found [%s]!\n", name));
+ key_index = i;
+ break;
+
+ }
+ }
+
+ return key_index;
+}
+
+/****************************************************************************
+ ***************************************************************************/
+
+int get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **subkeys )
+{
+ int i, j;
+ int key_len;
+ int num_subkeys = 0;
+ char *p;
+ fstring *subkeys_ptr = NULL;
+ fstring subkeyname;
+
+ *subkeys = NULL;
+
+ if ( !data )
+ return 0;
+
+ if ( !key )
+ return -1;
+
+ /* special case of asking for the top level printer data registry key names */
+
+ if ( strlen(key) == 0 ) {
+ for ( i=0; i<data->num_keys; i++ ) {
+
+ /* found a match, so allocate space and copy the name */
+
+ if ( !(subkeys_ptr = SMB_REALLOC_ARRAY( subkeys_ptr, fstring, num_subkeys+2)) ) {
+ DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n",
+ num_subkeys+1));
+ return -1;
+ }
+
+ fstrcpy( subkeys_ptr[num_subkeys], data->keys[i].name );
+ num_subkeys++;
+ }
+
+ goto done;
+ }
+
+ /* asking for the subkeys of some key */
+ /* subkey paths are stored in the key name using '\' as the delimiter */
+
+ for ( i=0; i<data->num_keys; i++ ) {
+ if ( StrnCaseCmp(data->keys[i].name, key, strlen(key)) == 0 ) {
+
+ /* if we found the exact key, then break */
+ key_len = strlen( key );
+ if ( strlen(data->keys[i].name) == key_len )
+ break;
+
+ /* get subkey path */
+
+ p = data->keys[i].name + key_len;
+ if ( *p == '\\' )
+ p++;
+ fstrcpy( subkeyname, p );
+ if ( (p = strchr( subkeyname, '\\' )) )
+ *p = '\0';
+
+ /* don't add a key more than once */
+
+ for ( j=0; j<num_subkeys; j++ ) {
+ if ( strequal( subkeys_ptr[j], subkeyname ) )
+ break;
+ }
+
+ if ( j != num_subkeys )
+ continue;
+
+ /* found a match, so allocate space and copy the name */
+
+ if ( !(subkeys_ptr = SMB_REALLOC_ARRAY( subkeys_ptr, fstring, num_subkeys+2)) ) {
+ DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n",
+ num_subkeys+1));
+ return 0;
+ }
+
+ fstrcpy( subkeys_ptr[num_subkeys], subkeyname );
+ num_subkeys++;
+ }
+
+ }
+
+ /* return error if the key was not found */
+
+ if ( i == data->num_keys ) {
+ SAFE_FREE(subkeys_ptr);
+ return -1;
+ }
+
+done:
+ /* tag off the end */
+
+ if (num_subkeys)
+ fstrcpy(subkeys_ptr[num_subkeys], "" );
+
+ *subkeys = subkeys_ptr;
+
+ return num_subkeys;
+}
+
+#ifdef HAVE_ADS
+static void map_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
+ const char *sz)
+{
+ smb_ucs2_t conv_str[1024];
+ size_t str_size;
+
+ regval_ctr_delvalue(ctr, val_name);
+ str_size = push_ucs2(NULL, conv_str, sz, sizeof(conv_str),
+ STR_TERMINATE | STR_NOALIGN);
+ regval_ctr_addvalue(ctr, val_name, REG_SZ,
+ (char *) conv_str, str_size);
+}
+
+static void map_dword_into_ctr(REGVAL_CTR *ctr, const char *val_name,
+ uint32 dword)
+{
+ regval_ctr_delvalue(ctr, val_name);
+ regval_ctr_addvalue(ctr, val_name, REG_DWORD,
+ (char *) &dword, sizeof(dword));
+}
+
+static void map_bool_into_ctr(REGVAL_CTR *ctr, const char *val_name,
+ bool b)
+{
+ uint8 bin_bool = (b ? 1 : 0);
+ regval_ctr_delvalue(ctr, val_name);
+ regval_ctr_addvalue(ctr, val_name, REG_BINARY,
+ (char *) &bin_bool, sizeof(bin_bool));
+}
+
+static void map_single_multi_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
+ const char *multi_sz)
+{
+ smb_ucs2_t *conv_strs = NULL;
+ size_t str_size;
+
+ /* a multi-sz has to have a null string terminator, i.e., the last
+ string must be followed by two nulls */
+ str_size = strlen(multi_sz) + 2;
+ conv_strs = SMB_CALLOC_ARRAY(smb_ucs2_t, str_size);
+ if (!conv_strs) {
+ return;
+ }
+
+ /* Change to byte units. */
+ str_size *= sizeof(smb_ucs2_t);
+ push_ucs2(NULL, conv_strs, multi_sz, str_size,
+ STR_TERMINATE | STR_NOALIGN);
+
+ regval_ctr_delvalue(ctr, val_name);
+ regval_ctr_addvalue(ctr, val_name, REG_MULTI_SZ,
+ (char *) conv_strs, str_size);
+ safe_free(conv_strs);
+
+}
+
+/****************************************************************************
+ * Map the NT_PRINTER_INFO_LEVEL_2 data into DsSpooler keys for publishing.
+ *
+ * @param info2 NT_PRINTER_INFO_LEVEL_2 describing printer - gets modified
+ * @return bool indicating success or failure
+ ***************************************************************************/
+
+static bool map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2)
+{
+ REGVAL_CTR *ctr = NULL;
+ fstring longname;
+ const char *dnssuffix;
+ char *allocated_string = NULL;
+ const char *ascii_str;
+ int i;
+
+ if ((i = lookup_printerkey(info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
+ i = add_new_printer_key(info2->data, SPOOL_DSSPOOLER_KEY);
+ ctr = info2->data->keys[i].values;
+
+ map_sz_into_ctr(ctr, SPOOL_REG_PRINTERNAME, info2->sharename);
+ map_sz_into_ctr(ctr, SPOOL_REG_SHORTSERVERNAME, global_myname());
+
+ /* we make the assumption that the netbios name is the same
+ as the DNS name sinc ethe former will be what we used to
+ join the domain */
+
+ dnssuffix = get_mydnsdomname(talloc_tos());
+ if (dnssuffix && *dnssuffix) {
+ fstr_sprintf( longname, "%s.%s", global_myname(), dnssuffix );
+ } else {
+ fstrcpy( longname, global_myname() );
+ }
+
+ map_sz_into_ctr(ctr, SPOOL_REG_SERVERNAME, longname);
+
+ asprintf(&allocated_string, "\\\\%s\\%s", longname, info2->sharename);
+ map_sz_into_ctr(ctr, SPOOL_REG_UNCNAME, allocated_string);
+ SAFE_FREE(allocated_string);
+
+ map_dword_into_ctr(ctr, SPOOL_REG_VERSIONNUMBER, 4);
+ map_sz_into_ctr(ctr, SPOOL_REG_DRIVERNAME, info2->drivername);
+ map_sz_into_ctr(ctr, SPOOL_REG_LOCATION, info2->location);
+ map_sz_into_ctr(ctr, SPOOL_REG_DESCRIPTION, info2->comment);
+ map_single_multi_sz_into_ctr(ctr, SPOOL_REG_PORTNAME, info2->portname);
+ map_sz_into_ctr(ctr, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
+ map_dword_into_ctr(ctr, SPOOL_REG_PRINTSTARTTIME, info2->starttime);
+ map_dword_into_ctr(ctr, SPOOL_REG_PRINTENDTIME, info2->untiltime);
+ map_dword_into_ctr(ctr, SPOOL_REG_PRIORITY, info2->priority);
+
+ map_bool_into_ctr(ctr, SPOOL_REG_PRINTKEEPPRINTEDJOBS,
+ (info2->attributes &
+ PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS));
+
+ switch (info2->attributes & 0x3) {
+ case 0:
+ ascii_str = SPOOL_REGVAL_PRINTWHILESPOOLING;
+ break;
+ case 1:
+ ascii_str = SPOOL_REGVAL_PRINTAFTERSPOOLED;
+ break;
+ case 2:
+ ascii_str = SPOOL_REGVAL_PRINTDIRECT;
+ break;
+ default:
+ ascii_str = "unknown";
+ }
+ map_sz_into_ctr(ctr, SPOOL_REG_PRINTSPOOLING, ascii_str);
+
+ return True;
+}
+
+/*****************************************************************
+ ****************************************************************/
+
+static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2,
+ struct GUID guid)
+{
+ int i;
+ REGVAL_CTR *ctr=NULL;
+ UNISTR2 unistr_guid;
+
+ /* find the DsSpooler key */
+ if ((i = lookup_printerkey(info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
+ i = add_new_printer_key(info2->data, SPOOL_DSSPOOLER_KEY);
+ ctr = info2->data->keys[i].values;
+
+ regval_ctr_delvalue(ctr, "objectGUID");
+
+ /* We used to store this as a REG_BINARY but that causes
+ Vista to whine */
+
+ ZERO_STRUCT( unistr_guid );
+
+ init_unistr2( &unistr_guid, smb_uuid_string(talloc_tos(), guid),
+ UNI_STR_TERMINATE );
+
+ regval_ctr_addvalue(ctr, "objectGUID", REG_SZ,
+ (char *)unistr_guid.buffer,
+ unistr_guid.uni_max_len*2);
+
+}
+
+static WERROR nt_printer_publish_ads(ADS_STRUCT *ads,
+ NT_PRINTER_INFO_LEVEL *printer)
+{
+ ADS_STATUS ads_rc;
+ LDAPMessage *res;
+ char *prt_dn = NULL, *srv_dn, *srv_cn_0, *srv_cn_escaped, *sharename_escaped;
+ char *srv_dn_utf8, **srv_cn_utf8;
+ TALLOC_CTX *ctx;
+ ADS_MODLIST mods;
+ const char *attrs[] = {"objectGUID", NULL};
+ struct GUID guid;
+ WERROR win_rc = WERR_OK;
+ size_t converted_size;
+
+ DEBUG(5, ("publishing printer %s\n", printer->info_2->printername));
+
+ /* figure out where to publish */
+ ads_find_machine_acct(ads, &res, global_myname());
+
+ /* We use ldap_get_dn here as we need the answer
+ * in utf8 to call ldap_explode_dn(). JRA. */
+
+ srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
+ if (!srv_dn_utf8) {
+ ads_destroy(&ads);
+ return WERR_SERVER_UNAVAILABLE;
+ }
+ ads_msgfree(ads, res);
+ srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
+ if (!srv_cn_utf8) {
+ ldap_memfree(srv_dn_utf8);
+ ads_destroy(&ads);
+ return WERR_SERVER_UNAVAILABLE;
+ }
+ /* Now convert to CH_UNIX. */
+ if (!pull_utf8_allocate(&srv_dn, srv_dn_utf8, &converted_size)) {
+ ldap_memfree(srv_dn_utf8);
+ ldap_memfree(srv_cn_utf8);
+ ads_destroy(&ads);
+ return WERR_SERVER_UNAVAILABLE;
+ }
+ if (!pull_utf8_allocate(&srv_cn_0, srv_cn_utf8[0], &converted_size)) {
+ ldap_memfree(srv_dn_utf8);
+ ldap_memfree(srv_cn_utf8);
+ ads_destroy(&ads);
+ SAFE_FREE(srv_dn);
+ return WERR_SERVER_UNAVAILABLE;
+ }
+
+ ldap_memfree(srv_dn_utf8);
+ ldap_memfree(srv_cn_utf8);
+
+ srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
+ if (!srv_cn_escaped) {
+ SAFE_FREE(srv_cn_0);
+ ldap_memfree(srv_dn_utf8);
+ ads_destroy(&ads);
+ return WERR_SERVER_UNAVAILABLE;
+ }
+ sharename_escaped = escape_rdn_val_string_alloc(printer->info_2->sharename);
+ if (!sharename_escaped) {
+ SAFE_FREE(srv_cn_escaped);
+ SAFE_FREE(srv_cn_0);
+ ldap_memfree(srv_dn_utf8);
+ ads_destroy(&ads);
+ return WERR_SERVER_UNAVAILABLE;
+ }
+
+
+ asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn);
+
+ SAFE_FREE(srv_dn);
+ SAFE_FREE(srv_cn_0);
+ SAFE_FREE(srv_cn_escaped);
+ SAFE_FREE(sharename_escaped);
+
+ /* build the ads mods */
+ ctx = talloc_init("nt_printer_publish_ads");
+ if (ctx == NULL) {
+ SAFE_FREE(prt_dn);
+ return WERR_NOMEM;
+ }
+
+ mods = ads_init_mods(ctx);
+
+ if (mods == NULL) {
+ SAFE_FREE(prt_dn);
+ talloc_destroy(ctx);
+ return WERR_NOMEM;
+ }
+
+ get_local_printer_publishing_data(ctx, &mods, printer->info_2->data);
+ ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME,
+ printer->info_2->sharename);
+
+ /* publish it */
+ ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
+ if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) {
+ int i;
+ for (i=0; mods[i] != 0; i++)
+ ;
+ mods[i] = (LDAPMod *)-1;
+ ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
+ }
+
+ if (!ADS_ERR_OK(ads_rc))
+ DEBUG(3, ("error publishing %s: %s\n", printer->info_2->sharename, ads_errstr(ads_rc)));
+
+ talloc_destroy(ctx);
+
+ /* retreive the guid and store it locally */
+ if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
+ ZERO_STRUCT(guid);
+ ads_pull_guid(ads, res, &guid);
+ ads_msgfree(ads, res);
+ store_printer_guid(printer->info_2, guid);
+ win_rc = mod_a_printer(printer, 2);
+ }
+
+ SAFE_FREE(prt_dn);
+ return win_rc;
+}
+
+static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
+ NT_PRINTER_INFO_LEVEL *printer)
+{
+ ADS_STATUS ads_rc;
+ LDAPMessage *res;
+ char *prt_dn = NULL;
+
+ DEBUG(5, ("unpublishing printer %s\n", printer->info_2->printername));
+
+ /* remove the printer from the directory */
+ ads_rc = ads_find_printer_on_server(ads, &res,
+ printer->info_2->sharename, global_myname());
+
+ if (ADS_ERR_OK(ads_rc) && ads_count_replies(ads, res)) {
+ prt_dn = ads_get_dn(ads, res);
+ if (!prt_dn) {
+ ads_msgfree(ads, res);
+ return WERR_NOMEM;
+ }
+ ads_rc = ads_del_dn(ads, prt_dn);
+ ads_memfree(ads, prt_dn);
+ }
+
+ ads_msgfree(ads, res);
+ return WERR_OK;
+}
+
+/****************************************************************************
+ * Publish a printer in the directory
+ *
+ * @param snum describing printer service
+ * @return WERROR indicating status of publishing
+ ***************************************************************************/
+
+WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
+{
+ ADS_STATUS ads_rc;
+ ADS_STRUCT *ads = NULL;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ WERROR win_rc;
+
+ win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
+ if (!W_ERROR_IS_OK(win_rc))
+ goto done;
+
+ switch (action) {
+ case SPOOL_DS_PUBLISH:
+ case SPOOL_DS_UPDATE:
+ /* set the DsSpooler info and attributes */
+ if (!(map_nt_printer_info2_to_dsspooler(printer->info_2))) {
+ win_rc = WERR_NOMEM;
+ goto done;
+ }
+
+ printer->info_2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
+ break;
+ case SPOOL_DS_UNPUBLISH:
+ printer->info_2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
+ break;
+ default:
+ win_rc = WERR_NOT_SUPPORTED;
+ goto done;
+ }
+
+ win_rc = mod_a_printer(printer, 2);
+ if (!W_ERROR_IS_OK(win_rc)) {
+ DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc)));
+ goto done;
+ }
+
+ ads = ads_init(lp_realm(), lp_workgroup(), NULL);
+ if (!ads) {
+ DEBUG(3, ("ads_init() failed\n"));
+ win_rc = WERR_SERVER_UNAVAILABLE;
+ goto done;
+ }
+ setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
+ SAFE_FREE(ads->auth.password);
+ ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
+ NULL, NULL);
+
+ /* ads_connect() will find the DC for us */
+ ads_rc = ads_connect(ads);
+ if (!ADS_ERR_OK(ads_rc)) {
+ DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
+ win_rc = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ switch (action) {
+ case SPOOL_DS_PUBLISH:
+ case SPOOL_DS_UPDATE:
+ win_rc = nt_printer_publish_ads(ads, printer);
+ break;
+ case SPOOL_DS_UNPUBLISH:
+ win_rc = nt_printer_unpublish_ads(ads, printer);
+ break;
+ }
+
+done:
+ free_a_printer(&printer, 2);
+ ads_destroy(&ads);
+ return win_rc;
+}
+
+WERROR check_published_printers(void)
+{
+ ADS_STATUS ads_rc;
+ ADS_STRUCT *ads = NULL;
+ int snum;
+ int n_services = lp_numservices();
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+ ads = ads_init(lp_realm(), lp_workgroup(), NULL);
+ if (!ads) {
+ DEBUG(3, ("ads_init() failed\n"));
+ return WERR_SERVER_UNAVAILABLE;
+ }
+ setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
+ SAFE_FREE(ads->auth.password);
+ ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
+ NULL, NULL);
+
+ /* ads_connect() will find the DC for us */
+ ads_rc = ads_connect(ads);
+ if (!ADS_ERR_OK(ads_rc)) {
+ DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
+ ads_destroy(&ads);
+ ads_kdestroy("MEMORY:prtpub_cache");
+ return WERR_ACCESS_DENIED;
+ }
+
+ for (snum = 0; snum < n_services; snum++) {
+ if (!(lp_snum_ok(snum) && lp_print_ok(snum)))
+ continue;
+
+ if (W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2,
+ lp_servicename(snum))) &&
+ (printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED))
+ nt_printer_publish_ads(ads, printer);
+
+ free_a_printer(&printer, 2);
+ }
+
+ ads_destroy(&ads);
+ ads_kdestroy("MEMORY:prtpub_cache");
+ return WERR_OK;
+}
+
+bool is_printer_published(Printer_entry *print_hnd, int snum,
+ struct GUID *guid)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ REGVAL_CTR *ctr;
+ REGISTRY_VALUE *guid_val;
+ WERROR win_rc;
+ int i;
+ bool ret = False;
+
+ win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
+
+ if (!W_ERROR_IS_OK(win_rc) ||
+ !(printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) ||
+ ((i = lookup_printerkey(printer->info_2->data, SPOOL_DSSPOOLER_KEY)) < 0) ||
+ !(ctr = printer->info_2->data->keys[i].values) ||
+ !(guid_val = regval_ctr_getvalue(ctr, "objectGUID")))
+ {
+ free_a_printer(&printer, 2);
+ return False;
+ }
+
+ /* fetching printer guids really ought to be a separate function. */
+
+ if ( guid ) {
+ fstring guid_str;
+
+ /* We used to store the guid as REG_BINARY, then swapped
+ to REG_SZ for Vista compatibility so check for both */
+
+ switch ( regval_type(guid_val) ){
+ case REG_SZ:
+ rpcstr_pull( guid_str, regval_data_p(guid_val),
+ sizeof(guid_str)-1, -1, STR_TERMINATE );
+ ret = smb_string_to_uuid( guid_str, guid );
+ break;
+ case REG_BINARY:
+ if ( regval_size(guid_val) != sizeof(struct GUID) ) {
+ ret = False;
+ break;
+ }
+ memcpy(guid, regval_data_p(guid_val), sizeof(struct GUID));
+ break;
+ default:
+ DEBUG(0,("is_printer_published: GUID value stored as "
+ "invaluid type (%d)\n", regval_type(guid_val) ));
+ break;
+ }
+ }
+
+ free_a_printer(&printer, 2);
+ return ret;
+}
+#else
+WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
+{
+ return WERR_OK;
+}
+
+WERROR check_published_printers(void)
+{
+ return WERR_OK;
+}
+
+bool is_printer_published(Printer_entry *print_hnd, int snum,
+ struct GUID *guid)
+{
+ return False;
+}
+#endif /* HAVE_ADS */
+
+/****************************************************************************
+ ***************************************************************************/
+
+WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key )
+{
+ NT_PRINTER_DATA *data;
+ int i;
+ int removed_keys = 0;
+ int empty_slot;
+
+ data = p2->data;
+ empty_slot = data->num_keys;
+
+ if ( !key )
+ return WERR_INVALID_PARAM;
+
+ /* remove all keys */
+
+ if ( !strlen(key) ) {
+
+ TALLOC_FREE( data );
+
+ p2->data = NULL;
+
+ DEBUG(8,("delete_all_printer_data: Removed all Printer Data from printer [%s]\n",
+ p2->printername ));
+
+ return WERR_OK;
+ }
+
+ /* remove a specific key (and all subkeys) */
+
+ for ( i=0; i<data->num_keys; i++ ) {
+ if ( StrnCaseCmp( data->keys[i].name, key, strlen(key)) == 0 ) {
+ DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
+ data->keys[i].name));
+
+ TALLOC_FREE( data->keys[i].name );
+ TALLOC_FREE( data->keys[i].values );
+
+ /* mark the slot as empty */
+
+ ZERO_STRUCTP( &data->keys[i] );
+ }
+ }
+
+ /* find the first empty slot */
+
+ for ( i=0; i<data->num_keys; i++ ) {
+ if ( !data->keys[i].name ) {
+ empty_slot = i;
+ removed_keys++;
+ break;
+ }
+ }
+
+ if ( i == data->num_keys )
+ /* nothing was removed */
+ return WERR_INVALID_PARAM;
+
+ /* move everything down */
+
+ for ( i=empty_slot+1; i<data->num_keys; i++ ) {
+ if ( data->keys[i].name ) {
+ memcpy( &data->keys[empty_slot], &data->keys[i], sizeof(NT_PRINTER_KEY) );
+ ZERO_STRUCTP( &data->keys[i] );
+ empty_slot++;
+ removed_keys++;
+ }
+ }
+
+ /* update count */
+
+ data->num_keys -= removed_keys;
+
+ /* sanity check to see if anything is left */
+
+ if ( !data->num_keys ) {
+ DEBUG(8,("delete_all_printer_data: No keys left for printer [%s]\n", p2->printername ));
+
+ SAFE_FREE( data->keys );
+ ZERO_STRUCTP( data );
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ ***************************************************************************/
+
+WERROR delete_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
+{
+ WERROR result = WERR_OK;
+ int key_index;
+
+ /* we must have names on non-zero length */
+
+ if ( !key || !*key|| !value || !*value )
+ return WERR_INVALID_NAME;
+
+ /* find the printer key first */
+
+ key_index = lookup_printerkey( p2->data, key );
+ if ( key_index == -1 )
+ return WERR_OK;
+
+ /* make sure the value exists so we can return the correct error code */
+
+ if ( !regval_ctr_getvalue( p2->data->keys[key_index].values, value ) )
+ return WERR_BADFILE;
+
+ regval_ctr_delvalue( p2->data->keys[key_index].values, value );
+
+ DEBUG(8,("delete_printer_data: Removed key => [%s], value => [%s]\n",
+ key, value ));
+
+ return result;
+}
+
+/****************************************************************************
+ ***************************************************************************/
+
+WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value,
+ uint32 type, uint8 *data, int real_len )
+{
+ WERROR result = WERR_OK;
+ int key_index;
+
+ /* we must have names on non-zero length */
+
+ if ( !key || !*key|| !value || !*value )
+ return WERR_INVALID_NAME;
+
+ /* find the printer key first */
+
+ key_index = lookup_printerkey( p2->data, key );
+ if ( key_index == -1 )
+ key_index = add_new_printer_key( p2->data, key );
+
+ if ( key_index == -1 )
+ return WERR_NOMEM;
+
+ regval_ctr_addvalue( p2->data->keys[key_index].values, value,
+ type, (const char *)data, real_len );
+
+ DEBUG(8,("add_printer_data: Added key => [%s], value => [%s], type=> [%d], size => [%d]\n",
+ key, value, type, real_len ));
+
+ return result;
+}
+
+/****************************************************************************
+ ***************************************************************************/
+
+REGISTRY_VALUE* get_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
+{
+ int key_index;
+
+ if ( (key_index = lookup_printerkey( p2->data, key )) == -1 )
+ return NULL;
+
+ DEBUG(8,("get_printer_data: Attempting to lookup key => [%s], value => [%s]\n",
+ key, value ));
+
+ return regval_ctr_getvalue( p2->data->keys[key_index].values, value );
+}
+
+/****************************************************************************
+ Unpack a list of registry values frem the TDB
+ ***************************************************************************/
+
+static int unpack_values(NT_PRINTER_DATA *printer_data, const uint8 *buf, int buflen)
+{
+ int len = 0;
+ uint32 type;
+ fstring string;
+ const char *valuename = NULL;
+ const char *keyname = NULL;
+ char *str;
+ int size;
+ uint8 *data_p;
+ REGISTRY_VALUE *regval_p;
+ int key_index;
+
+ /* add the "PrinterDriverData" key first for performance reasons */
+
+ add_new_printer_key( printer_data, SPOOL_PRINTERDATA_KEY );
+
+ /* loop and unpack the rest of the registry values */
+
+ while ( True ) {
+
+ /* check to see if there are any more registry values */
+
+ regval_p = NULL;
+ len += tdb_unpack(buf+len, buflen-len, "p", &regval_p);
+ if ( !regval_p )
+ break;
+
+ /* unpack the next regval */
+
+ len += tdb_unpack(buf+len, buflen-len, "fdB",
+ string,
+ &type,
+ &size,
+ &data_p);
+
+ /* lookup for subkey names which have a type of REG_NONE */
+ /* there's no data with this entry */
+
+ if ( type == REG_NONE ) {
+ if ( (key_index=lookup_printerkey( printer_data, string)) == -1 )
+ add_new_printer_key( printer_data, string );
+ continue;
+ }
+
+ /*
+ * break of the keyname from the value name.
+ * Valuenames can have embedded '\'s so be careful.
+ * only support one level of keys. See the
+ * "Konica Fiery S300 50C-K v1.1. enu" 2k driver.
+ * -- jerry
+ */
+
+ str = strchr_m( string, '\\');
+
+ /* Put in "PrinterDriverData" is no key specified */
+
+ if ( !str ) {
+ keyname = SPOOL_PRINTERDATA_KEY;
+ valuename = string;
+ }
+ else {
+ *str = '\0';
+ keyname = string;
+ valuename = str+1;
+ }
+
+ /* see if we need a new key */
+
+ if ( (key_index=lookup_printerkey( printer_data, keyname )) == -1 )
+ key_index = add_new_printer_key( printer_data, keyname );
+
+ if ( key_index == -1 ) {
+ DEBUG(0,("unpack_values: Failed to allocate a new key [%s]!\n",
+ keyname));
+ break;
+ }
+
+ DEBUG(8,("specific: [%s:%s], len: %d\n", keyname, valuename, size));
+
+ /* Vista doesn't like unknown REG_BINARY values in DsSpooler.
+ Thanks to Martin Zielinski for the hint. */
+
+ if ( type == REG_BINARY &&
+ strequal( keyname, SPOOL_DSSPOOLER_KEY ) &&
+ strequal( valuename, "objectGUID" ) )
+ {
+ struct GUID guid;
+ UNISTR2 unistr_guid;
+
+ ZERO_STRUCT( unistr_guid );
+
+ /* convert the GUID to a UNICODE string */
+
+ memcpy( &guid, data_p, sizeof(struct GUID) );
+
+ init_unistr2( &unistr_guid,
+ smb_uuid_string(talloc_tos(), guid),
+ UNI_STR_TERMINATE );
+
+ regval_ctr_addvalue( printer_data->keys[key_index].values,
+ valuename, REG_SZ,
+ (const char *)unistr_guid.buffer,
+ unistr_guid.uni_str_len*2 );
+
+ } else {
+ /* add the value */
+
+ regval_ctr_addvalue( printer_data->keys[key_index].values,
+ valuename, type, (const char *)data_p,
+ size );
+ }
+
+ SAFE_FREE(data_p); /* 'B' option to tdbpack does a malloc() */
+
+ }
+
+ return len;
+}
+
+/****************************************************************************
+ ***************************************************************************/
+
+static char *last_from;
+static char *last_to;
+
+static const char *get_last_from(void)
+{
+ if (!last_from) {
+ return "";
+ }
+ return last_from;
+}
+
+static const char *get_last_to(void)
+{
+ if (!last_to) {
+ return "";
+ }
+ return last_to;
+}
+
+static bool set_last_from_to(const char *from, const char *to)
+{
+ char *orig_from = last_from;
+ char *orig_to = last_to;
+
+ last_from = SMB_STRDUP(from);
+ last_to = SMB_STRDUP(to);
+
+ SAFE_FREE(orig_from);
+ SAFE_FREE(orig_to);
+
+ if (!last_from || !last_to) {
+ SAFE_FREE(last_from);
+ SAFE_FREE(last_to);
+ return false;
+ }
+ return true;
+}
+
+static void map_to_os2_driver(fstring drivername)
+{
+ char *mapfile = lp_os2_driver_map();
+ char **lines = NULL;
+ int numlines = 0;
+ int i;
+
+ if (!strlen(drivername))
+ return;
+
+ if (!*mapfile)
+ return;
+
+ if (strequal(drivername,get_last_from())) {
+ DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",
+ drivername,get_last_to()));
+ fstrcpy(drivername,get_last_to());
+ return;
+ }
+
+ lines = file_lines_load(mapfile, &numlines,0);
+ if (numlines == 0 || lines == NULL) {
+ DEBUG(0,("No entries in OS/2 driver map %s\n",mapfile));
+ SAFE_FREE(lines);
+ return;
+ }
+
+ DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
+
+ for( i = 0; i < numlines; i++) {
+ char *nt_name = lines[i];
+ char *os2_name = strchr(nt_name,'=');
+
+ if (!os2_name)
+ continue;
+
+ *os2_name++ = 0;
+
+ while (isspace(*nt_name))
+ nt_name++;
+
+ if (!*nt_name || strchr("#;",*nt_name))
+ continue;
+
+ {
+ int l = strlen(nt_name);
+ while (l && isspace(nt_name[l-1])) {
+ nt_name[l-1] = 0;
+ l--;
+ }
+ }
+
+ while (isspace(*os2_name))
+ os2_name++;
+
+ {
+ int l = strlen(os2_name);
+ while (l && isspace(os2_name[l-1])) {
+ os2_name[l-1] = 0;
+ l--;
+ }
+ }
+
+ if (strequal(nt_name,drivername)) {
+ DEBUG(3,("Mapped windows driver %s to os2 driver%s\n",drivername,os2_name));
+ set_last_from_to(drivername,os2_name);
+ fstrcpy(drivername,os2_name);
+ file_lines_free(lines);
+ return;
+ }
+ }
+
+ file_lines_free(lines);
+}
+
+/****************************************************************************
+ Get a default printer info 2 struct.
+****************************************************************************/
+
+static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 *info,
+ const char *servername,
+ const char* sharename,
+ bool get_loc_com)
+{
+ int snum = lp_servicenumber(sharename);
+
+ slprintf(info->servername, sizeof(info->servername)-1, "\\\\%s", servername);
+ slprintf(info->printername, sizeof(info->printername)-1, "\\\\%s\\%s",
+ servername, sharename);
+ fstrcpy(info->sharename, sharename);
+ fstrcpy(info->portname, SAMBA_PRINTER_PORT_NAME);
+
+ /* by setting the driver name to an empty string, a local NT admin
+ can now run the **local** APW to install a local printer driver
+ for a Samba shared printer in 2.2. Without this, drivers **must** be
+ installed on the Samba server for NT clients --jerry */
+#if 0 /* JERRY --do not uncomment-- */
+ if (!*info->drivername)
+ fstrcpy(info->drivername, "NO DRIVER AVAILABLE FOR THIS PRINTER");
+#endif
+
+
+ DEBUG(10,("get_a_printer_2_default: driver name set to [%s]\n", info->drivername));
+
+ strlcpy(info->comment, "", sizeof(info->comment));
+ fstrcpy(info->printprocessor, "winprint");
+ fstrcpy(info->datatype, "RAW");
+
+#ifdef HAVE_CUPS
+ if (get_loc_com && (enum printing_types)lp_printing(snum) == PRINT_CUPS ) {
+ /* Pull the location and comment strings from cups if we don't
+ already have one */
+ if ( !strlen(info->location) || !strlen(info->comment) )
+ cups_pull_comment_location( info );
+ }
+#endif
+
+ info->attributes = PRINTER_ATTRIBUTE_SAMBA;
+
+ info->starttime = 0; /* Minutes since 12:00am GMT */
+ info->untiltime = 0; /* Minutes since 12:00am GMT */
+ info->priority = 1;
+ info->default_priority = 1;
+ info->setuptime = (uint32)time(NULL);
+
+ /*
+ * I changed this as I think it is better to have a generic
+ * DEVMODE than to crash Win2k explorer.exe --jerry
+ * See the HP Deskjet 990c Win2k drivers for an example.
+ *
+ * However the default devmode appears to cause problems
+ * with the HP CLJ 8500 PCL driver. Hence the addition of
+ * the "default devmode" parameter --jerry 22/01/2002
+ */
+
+ if (lp_default_devmode(snum)) {
+ if ((info->devmode = construct_nt_devicemode(info->printername)) == NULL) {
+ goto fail;
+ }
+ } else {
+ info->devmode = NULL;
+ }
+
+ if (!nt_printing_getsec(info, sharename, &info->secdesc_buf)) {
+ goto fail;
+ }
+
+ return WERR_OK;
+
+fail:
+ if (info->devmode)
+ free_nt_devicemode(&info->devmode);
+
+ return WERR_ACCESS_DENIED;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info,
+ const char *servername,
+ const char *sharename,
+ bool get_loc_com)
+{
+ int len = 0;
+ int snum = lp_servicenumber(sharename);
+ TDB_DATA kbuf, dbuf;
+ fstring printername;
+ char adevice[MAXDEVICENAME];
+ char *comment = NULL;
+
+ kbuf = make_printer_tdbkey(talloc_tos(), sharename);
+
+ dbuf = tdb_fetch(tdb_printers, kbuf);
+ if (!dbuf.dptr) {
+ return get_a_printer_2_default(info, servername,
+ sharename, get_loc_com);
+ }
+
+ len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "dddddddddddfffffPfffff",
+ &info->attributes,
+ &info->priority,
+ &info->default_priority,
+ &info->starttime,
+ &info->untiltime,
+ &info->status,
+ &info->cjobs,
+ &info->averageppm,
+ &info->changeid,
+ &info->c_setprinter,
+ &info->setuptime,
+ info->servername,
+ info->printername,
+ info->sharename,
+ info->portname,
+ info->drivername,
+ &comment,
+ info->location,
+ info->sepfile,
+ info->printprocessor,
+ info->datatype,
+ info->parameters);
+
+ if (comment) {
+ strlcpy(info->comment, comment, sizeof(info->comment));
+ SAFE_FREE(comment);
+ }
+
+ /* Samba has to have shared raw drivers. */
+ info->attributes |= PRINTER_ATTRIBUTE_SAMBA;
+ info->attributes &= ~PRINTER_ATTRIBUTE_NOT_SAMBA;
+
+ /* Restore the stripped strings. */
+ slprintf(info->servername, sizeof(info->servername)-1, "\\\\%s", servername);
+
+ if ( lp_force_printername(snum) ) {
+ slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, sharename );
+ } else {
+ slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, info->printername);
+ }
+
+ fstrcpy(info->printername, printername);
+
+#ifdef HAVE_CUPS
+ if (get_loc_com && (enum printing_types)lp_printing(snum) == PRINT_CUPS ) {
+ /* Pull the location and comment strings from cups if we don't
+ already have one */
+ if ( !strlen(info->location) || !strlen(info->comment) )
+ cups_pull_comment_location( info );
+ }
+#endif
+
+ len += unpack_devicemode(&info->devmode,dbuf.dptr+len, dbuf.dsize-len);
+
+ /*
+ * Some client drivers freak out if there is a NULL devmode
+ * (probably the driver is not checking before accessing
+ * the devmode pointer) --jerry
+ *
+ * See comments in get_a_printer_2_default()
+ */
+
+ if (lp_default_devmode(snum) && !info->devmode) {
+ DEBUG(8,("get_a_printer_2: Constructing a default device mode for [%s]\n",
+ printername));
+ info->devmode = construct_nt_devicemode(printername);
+ }
+
+ slprintf( adevice, sizeof(adevice), "%s", info->printername );
+ if (info->devmode) {
+ fstrcpy(info->devmode->devicename, adevice);
+ }
+
+ if ( !(info->data = TALLOC_ZERO_P( info, NT_PRINTER_DATA )) ) {
+ DEBUG(0,("unpack_values: talloc() failed!\n"));
+ SAFE_FREE(dbuf.dptr);
+ return WERR_NOMEM;
+ }
+ len += unpack_values( info->data, dbuf.dptr+len, dbuf.dsize-len );
+
+ /* This will get the current RPC talloc context, but we should be
+ passing this as a parameter... fixme... JRA ! */
+
+ if (!nt_printing_getsec(info, sharename, &info->secdesc_buf)) {
+ SAFE_FREE(dbuf.dptr);
+ return WERR_NOMEM;
+ }
+
+ /* Fix for OS/2 drivers. */
+
+ if (get_remote_arch() == RA_OS2) {
+ map_to_os2_driver(info->drivername);
+ }
+
+ SAFE_FREE(dbuf.dptr);
+
+ DEBUG(9,("Unpacked printer [%s] name [%s] running driver [%s]\n",
+ sharename, info->printername, info->drivername));
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ Debugging function, dump at level 6 the struct in the logs.
+****************************************************************************/
+static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
+{
+ uint32 result;
+ NT_PRINTER_INFO_LEVEL_2 *info2;
+
+ DEBUG(106,("Dumping printer at level [%d]\n", level));
+
+ switch (level) {
+ case 2:
+ {
+ if (printer->info_2 == NULL)
+ result=5;
+ else
+ {
+ info2=printer->info_2;
+
+ DEBUGADD(106,("attributes:[%d]\n", info2->attributes));
+ DEBUGADD(106,("priority:[%d]\n", info2->priority));
+ DEBUGADD(106,("default_priority:[%d]\n", info2->default_priority));
+ DEBUGADD(106,("starttime:[%d]\n", info2->starttime));
+ DEBUGADD(106,("untiltime:[%d]\n", info2->untiltime));
+ DEBUGADD(106,("status:[%d]\n", info2->status));
+ DEBUGADD(106,("cjobs:[%d]\n", info2->cjobs));
+ DEBUGADD(106,("averageppm:[%d]\n", info2->averageppm));
+ DEBUGADD(106,("changeid:[%d]\n", info2->changeid));
+ DEBUGADD(106,("c_setprinter:[%d]\n", info2->c_setprinter));
+ DEBUGADD(106,("setuptime:[%d]\n", info2->setuptime));
+
+ DEBUGADD(106,("servername:[%s]\n", info2->servername));
+ DEBUGADD(106,("printername:[%s]\n", info2->printername));
+ DEBUGADD(106,("sharename:[%s]\n", info2->sharename));
+ DEBUGADD(106,("portname:[%s]\n", info2->portname));
+ DEBUGADD(106,("drivername:[%s]\n", info2->drivername));
+ DEBUGADD(106,("comment:[%s]\n", info2->comment));
+ DEBUGADD(106,("location:[%s]\n", info2->location));
+ DEBUGADD(106,("sepfile:[%s]\n", info2->sepfile));
+ DEBUGADD(106,("printprocessor:[%s]\n", info2->printprocessor));
+ DEBUGADD(106,("datatype:[%s]\n", info2->datatype));
+ DEBUGADD(106,("parameters:[%s]\n", info2->parameters));
+ result=0;
+ }
+ break;
+ }
+ default:
+ DEBUGADD(106,("dump_a_printer: Level %u not implemented\n", (unsigned int)level ));
+ result=1;
+ break;
+ }
+
+ return result;
+}
+
+/****************************************************************************
+ Update the changeid time.
+ This is SO NASTY as some drivers need this to change, others need it
+ static. This value will change every second, and I must hope that this
+ is enough..... DON'T CHANGE THIS CODE WITHOUT A TEST MATRIX THE SIZE OF
+ UTAH ! JRA.
+****************************************************************************/
+
+static uint32 rev_changeid(void)
+{
+ struct timeval tv;
+
+ get_process_uptime(&tv);
+
+#if 1 /* JERRY */
+ /* Return changeid as msec since spooler restart */
+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+#else
+ /*
+ * This setting seems to work well but is too untested
+ * to replace the above calculation. Left in for experiementation
+ * of the reader --jerry (Tue Mar 12 09:15:05 CST 2002)
+ */
+ return tv.tv_sec * 10 + tv.tv_usec / 100000;
+#endif
+}
+
+
+/*
+ * The function below are the high level ones.
+ * only those ones must be called from the spoolss code.
+ * JFM.
+ */
+
+/****************************************************************************
+ Modify a printer. This is called from SETPRINTERDATA/DELETEPRINTERDATA.
+****************************************************************************/
+
+WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
+{
+ WERROR result;
+
+ dump_a_printer(printer, level);
+
+ switch (level) {
+ case 2:
+ {
+ /*
+ * Update the changestamp. Emperical tests show that the
+ * ChangeID is always updated,but c_setprinter is
+ * global spooler variable (not per printer).
+ */
+
+ /* ChangeID **must** be increasing over the lifetime
+ of client's spoolss service in order for the
+ client's cache to show updates */
+
+ printer->info_2->changeid = rev_changeid();
+
+ /*
+ * Because one day someone will ask:
+ * NT->NT An admin connection to a remote
+ * printer show changes imeediately in
+ * the properities dialog
+ *
+ * A non-admin connection will only show the
+ * changes after viewing the properites page
+ * 2 times. Seems to be related to a
+ * race condition in the client between the spooler
+ * updating the local cache and the Explorer.exe GUI
+ * actually displaying the properties.
+ *
+ * This is fixed in Win2k. admin/non-admin
+ * connections both display changes immediately.
+ *
+ * 14/12/01 --jerry
+ */
+
+ result=update_a_printer_2(printer->info_2);
+ break;
+ }
+ default:
+ result=WERR_UNKNOWN_LEVEL;
+ break;
+ }
+
+ return result;
+}
+
+/****************************************************************************
+ Initialize printer devmode & data with previously saved driver init values.
+****************************************************************************/
+
+static bool set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr )
+{
+ int len = 0;
+ char *key = NULL;
+ TDB_DATA dbuf;
+ NT_PRINTER_INFO_LEVEL_2 info;
+
+
+ ZERO_STRUCT(info);
+
+ /*
+ * Delete any printer data 'values' already set. When called for driver
+ * replace, there will generally be some, but during an add printer, there
+ * should not be any (if there are delete them).
+ */
+
+ if ( info_ptr->data )
+ delete_all_printer_data( info_ptr, "" );
+
+ if (asprintf(&key, "%s%s", DRIVER_INIT_PREFIX,
+ info_ptr->drivername) < 0) {
+ return false;
+ }
+
+ dbuf = tdb_fetch_bystring(tdb_drivers, key);
+ if (!dbuf.dptr) {
+ /*
+ * When changing to a driver that has no init info in the tdb, remove
+ * the previous drivers init info and leave the new on blank.
+ */
+ free_nt_devicemode(&info_ptr->devmode);
+ SAFE_FREE(key);
+ return false;
+ }
+
+ SAFE_FREE(key);
+ /*
+ * Get the saved DEVMODE..
+ */
+
+ len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
+
+ /*
+ * The saved DEVMODE contains the devicename from the printer used during
+ * the initialization save. Change it to reflect the new printer.
+ */
+
+ if ( info.devmode ) {
+ ZERO_STRUCT(info.devmode->devicename);
+ fstrcpy(info.devmode->devicename, info_ptr->printername);
+ }
+
+ /*
+ * NT/2k does not change out the entire DeviceMode of a printer
+ * when changing the driver. Only the driverextra, private, &
+ * driverversion fields. --jerry (Thu Mar 14 08:58:43 CST 2002)
+ *
+ * Later examination revealed that Windows NT/2k does reset the
+ * the printer's device mode, bit **only** when you change a
+ * property of the device mode such as the page orientation.
+ * --jerry
+ */
+
+
+ /* Bind the saved DEVMODE to the new the printer */
+
+ free_nt_devicemode(&info_ptr->devmode);
+ info_ptr->devmode = info.devmode;
+
+ DEBUG(10,("set_driver_init_2: Set printer [%s] init %s DEVMODE for driver [%s]\n",
+ info_ptr->printername, info_ptr->devmode?"VALID":"NULL", info_ptr->drivername));
+
+ /* Add the printer data 'values' to the new printer */
+
+ if ( !(info_ptr->data = TALLOC_ZERO_P( info_ptr, NT_PRINTER_DATA )) ) {
+ DEBUG(0,("set_driver_init_2: talloc() failed!\n"));
+ return False;
+ }
+
+ len += unpack_values( info_ptr->data, dbuf.dptr+len, dbuf.dsize-len );
+
+ SAFE_FREE(dbuf.dptr);
+
+ return true;
+}
+
+/****************************************************************************
+ Initialize printer devmode & data with previously saved driver init values.
+ When a printer is created using AddPrinter, the drivername bound to the
+ printer is used to lookup previously saved driver initialization info, which
+ is bound to the new printer.
+****************************************************************************/
+
+bool set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
+{
+ bool result = False;
+
+ switch (level) {
+ case 2:
+ result = set_driver_init_2(printer->info_2);
+ break;
+
+ default:
+ DEBUG(0,("set_driver_init: Programmer's error! Unknown driver_init level [%d]\n",
+ level));
+ break;
+ }
+
+ return result;
+}
+
+/****************************************************************************
+ Delete driver init data stored for a specified driver
+****************************************************************************/
+
+bool del_driver_init(char *drivername)
+{
+ char *key;
+ bool ret;
+
+ if (!drivername || !*drivername) {
+ DEBUG(3,("del_driver_init: No drivername specified!\n"));
+ return false;
+ }
+
+ if (asprintf(&key, "%s%s", DRIVER_INIT_PREFIX, drivername) < 0) {
+ return false;
+ }
+
+ DEBUG(6,("del_driver_init: Removing driver init data for [%s]\n",
+ drivername));
+
+ ret = (tdb_delete_bystring(tdb_drivers, key) == 0);
+ SAFE_FREE(key);
+ return ret;
+}
+
+/****************************************************************************
+ Pack up the DEVMODE and values for a printer into a 'driver init' entry
+ in the tdb. Note: this is different from the driver entry and the printer
+ entry. There should be a single driver init entry for each driver regardless
+ of whether it was installed from NT or 2K. Technically, they should be
+ different, but they work out to the same struct.
+****************************************************************************/
+
+static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
+{
+ char *key = NULL;
+ uint8 *buf;
+ int buflen, len, ret;
+ int retlen;
+ TDB_DATA dbuf;
+
+ buf = NULL;
+ buflen = 0;
+
+ again:
+ len = 0;
+ len += pack_devicemode(info->devmode, buf+len, buflen-len);
+
+ retlen = pack_values( info->data, buf+len, buflen-len );
+ if (retlen == -1) {
+ ret = -1;
+ goto done;
+ }
+ len += retlen;
+
+ if (buflen < len) {
+ buf = (uint8 *)SMB_REALLOC(buf, len);
+ if (!buf) {
+ DEBUG(0, ("update_driver_init_2: failed to enlarge buffer!\n"));
+ ret = -1;
+ goto done;
+ }
+ buflen = len;
+ goto again;
+ }
+
+ SAFE_FREE(key);
+ if (asprintf(&key, "%s%s", DRIVER_INIT_PREFIX, info->drivername) < 0) {
+ ret = (uint32)-1;
+ goto done;
+ }
+
+ dbuf.dptr = buf;
+ dbuf.dsize = len;
+
+ ret = tdb_store_bystring(tdb_drivers, key, dbuf, TDB_REPLACE);
+
+done:
+ if (ret == -1)
+ DEBUG(8, ("update_driver_init_2: error updating printer init to tdb on disk\n"));
+
+ SAFE_FREE(buf);
+
+ DEBUG(10,("update_driver_init_2: Saved printer [%s] init DEVMODE & values for driver [%s]\n",
+ info->sharename, info->drivername));
+
+ return ret;
+}
+
+/****************************************************************************
+ Update (i.e. save) the driver init info (DEVMODE and values) for a printer
+****************************************************************************/
+
+static uint32 update_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
+{
+ uint32 result;
+
+ dump_a_printer(printer, level);
+
+ switch (level) {
+ case 2:
+ result = update_driver_init_2(printer->info_2);
+ break;
+ default:
+ result = 1;
+ break;
+ }
+
+ return result;
+}
+
+/****************************************************************************
+ Convert the printer data value, a REG_BINARY array, into an initialization
+ DEVMODE. Note: the array must be parsed as if it was a DEVMODE in an rpc...
+ got to keep the endians happy :).
+****************************************************************************/
+
+static bool convert_driver_init( TALLOC_CTX *ctx, NT_DEVICEMODE *nt_devmode, uint8 *data, uint32 data_len )
+{
+ bool result = False;
+ prs_struct ps;
+ DEVICEMODE devmode;
+
+ ZERO_STRUCT(devmode);
+
+ prs_init_empty(&ps, ctx, UNMARSHALL);
+ ps.data_p = (char *)data;
+ ps.buffer_size = data_len;
+
+ if (spoolss_io_devmode("phantom DEVMODE", &ps, 0, &devmode))
+ result = convert_devicemode("", &devmode, &nt_devmode);
+ else
+ DEBUG(10,("convert_driver_init: error parsing DEVMODE\n"));
+
+ return result;
+}
+
+/****************************************************************************
+ Set the DRIVER_INIT info in the tdb. Requires Win32 client code that:
+
+ 1. Use the driver's config DLL to this UNC printername and:
+ a. Call DrvPrintEvent with PRINTER_EVENT_INITIALIZE
+ b. Call DrvConvertDevMode with CDM_DRIVER_DEFAULT to get default DEVMODE
+ 2. Call SetPrinterData with the 'magic' key and the DEVMODE as data.
+
+ The last step triggers saving the "driver initialization" information for
+ this printer into the tdb. Later, new printers that use this driver will
+ have this initialization information bound to them. This simulates the
+ driver initialization, as if it had run on the Samba server (as it would
+ have done on NT).
+
+ The Win32 client side code requirement sucks! But until we can run arbitrary
+ Win32 printer driver code on any Unix that Samba runs on, we are stuck with it.
+
+ It would have been easier to use SetPrinter because all the UNMARSHALLING of
+ the DEVMODE is done there, but 2K/XP clients do not set the DEVMODE... think
+ about it and you will realize why. JRR 010720
+****************************************************************************/
+
+static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, uint32 data_len )
+{
+ WERROR status = WERR_OK;
+ TALLOC_CTX *ctx = NULL;
+ NT_DEVICEMODE *nt_devmode = NULL;
+ NT_DEVICEMODE *tmp_devmode = printer->info_2->devmode;
+
+ /*
+ * When the DEVMODE is already set on the printer, don't try to unpack it.
+ */
+ DEBUG(8,("save_driver_init_2: Enter...\n"));
+
+ if ( !printer->info_2->devmode && data_len ) {
+ /*
+ * Set devmode on printer info, so entire printer initialization can be
+ * saved to tdb.
+ */
+
+ if ((ctx = talloc_init("save_driver_init_2")) == NULL)
+ return WERR_NOMEM;
+
+ if ((nt_devmode = SMB_MALLOC_P(NT_DEVICEMODE)) == NULL) {
+ status = WERR_NOMEM;
+ goto done;
+ }
+
+ ZERO_STRUCTP(nt_devmode);
+
+ /*
+ * The DEVMODE is held in the 'data' component of the param in raw binary.
+ * Convert it to to a devmode structure
+ */
+ if ( !convert_driver_init( ctx, nt_devmode, data, data_len )) {
+ DEBUG(10,("save_driver_init_2: error converting DEVMODE\n"));
+ status = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ printer->info_2->devmode = nt_devmode;
+ }
+
+ /*
+ * Pack up and add (or update) the DEVMODE and any current printer data to
+ * a 'driver init' element in the tdb
+ *
+ */
+
+ if ( update_driver_init(printer, 2) != 0 ) {
+ DEBUG(10,("save_driver_init_2: error updating DEVMODE\n"));
+ status = WERR_NOMEM;
+ goto done;
+ }
+
+ /*
+ * If driver initialization info was successfully saved, set the current
+ * printer to match it. This allows initialization of the current printer
+ * as well as the driver.
+ */
+ status = mod_a_printer(printer, 2);
+ if (!W_ERROR_IS_OK(status)) {
+ DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n",
+ printer->info_2->printername));
+ }
+
+ done:
+ talloc_destroy(ctx);
+ free_nt_devicemode( &nt_devmode );
+
+ printer->info_2->devmode = tmp_devmode;
+
+ return status;
+}
+
+/****************************************************************************
+ Update the driver init info (DEVMODE and specifics) for a printer
+****************************************************************************/
+
+WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, uint8 *data, uint32 data_len)
+{
+ WERROR status = WERR_OK;
+
+ switch (level) {
+ case 2:
+ status = save_driver_init_2( printer, data, data_len );
+ break;
+ default:
+ status = WERR_UNKNOWN_LEVEL;
+ break;
+ }
+
+ return status;
+}
+
+/****************************************************************************
+ Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory.
+
+ Previously the code had a memory allocation problem because it always
+ used the TALLOC_CTX from the Printer_entry*. This context lasts
+ as a long as the original handle is open. So if the client made a lot
+ of getprinter[data]() calls, the memory usage would climb. Now we use
+ a short lived TALLOC_CTX for printer_info_2 objects returned. We
+ still use the Printer_entry->ctx for maintaining the cache copy though
+ since that object must live as long as the handle by definition.
+ --jerry
+
+****************************************************************************/
+
+static WERROR get_a_printer_internal( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level,
+ const char *sharename, bool get_loc_com)
+{
+ WERROR result;
+ fstring servername;
+
+ DEBUG(10,("get_a_printer: [%s] level %u\n", sharename, (unsigned int)level));
+
+ if ( !(*pp_printer = TALLOC_ZERO_P(NULL, NT_PRINTER_INFO_LEVEL)) ) {
+ DEBUG(0,("get_a_printer: talloc() fail.\n"));
+ return WERR_NOMEM;
+ }
+
+ switch (level) {
+ case 2:
+ if ( !((*pp_printer)->info_2 = TALLOC_ZERO_P(*pp_printer, NT_PRINTER_INFO_LEVEL_2)) ) {
+ DEBUG(0,("get_a_printer: talloc() fail.\n"));
+ TALLOC_FREE( *pp_printer );
+ return WERR_NOMEM;
+ }
+
+ if ( print_hnd )
+ fstrcpy( servername, print_hnd->servername );
+ else {
+ fstrcpy( servername, "%L" );
+ standard_sub_basic( "", "", servername,
+ sizeof(servername)-1 );
+ }
+
+ result = get_a_printer_2( (*pp_printer)->info_2,
+ servername, sharename, get_loc_com);
+
+ /* we have a new printer now. Save it with this handle */
+
+ if ( !W_ERROR_IS_OK(result) ) {
+ TALLOC_FREE( *pp_printer );
+ DEBUG(10,("get_a_printer: [%s] level %u returning %s\n",
+ sharename, (unsigned int)level, dos_errstr(result)));
+ return result;
+ }
+
+ dump_a_printer( *pp_printer, level);
+
+ break;
+
+ default:
+ TALLOC_FREE( *pp_printer );
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return WERR_OK;
+}
+
+WERROR get_a_printer( Printer_entry *print_hnd,
+ NT_PRINTER_INFO_LEVEL **pp_printer,
+ uint32 level,
+ const char *sharename)
+{
+ return get_a_printer_internal(print_hnd, pp_printer, level,
+ sharename, true);
+}
+
+WERROR get_a_printer_search( Printer_entry *print_hnd,
+ NT_PRINTER_INFO_LEVEL **pp_printer,
+ uint32 level,
+ const char *sharename)
+{
+ return get_a_printer_internal(print_hnd, pp_printer, level,
+ sharename, false);
+}
+
+/****************************************************************************
+ Deletes a NT_PRINTER_INFO_LEVEL struct.
+****************************************************************************/
+
+uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level)
+{
+ NT_PRINTER_INFO_LEVEL *printer = *pp_printer;
+
+ if ( !printer )
+ return 0;
+
+ switch (level) {
+ case 2:
+ if ( printer->info_2 )
+ free_nt_printer_info_level_2(&printer->info_2);
+ break;
+
+ default:
+ DEBUG(0,("free_a_printer: unknown level! [%d]\n", level ));
+ return 1;
+ }
+
+ TALLOC_FREE(*pp_printer);
+
+ return 0;
+}
+
+/****************************************************************************
+****************************************************************************/
+uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
+{
+ uint32 result;
+ DEBUG(104,("adding a printer at level [%d]\n", level));
+ dump_a_printer_driver(driver, level);
+
+ switch (level) {
+ case 3:
+ result=add_a_printer_driver_3(driver.info_3);
+ break;
+
+ case 6:
+ result=add_a_printer_driver_6(driver.info_6);
+ break;
+
+ default:
+ result=1;
+ break;
+ }
+
+ return result;
+}
+/****************************************************************************
+****************************************************************************/
+
+WERROR get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
+ fstring drivername, const char *architecture, uint32 version)
+{
+ WERROR result;
+
+ switch (level) {
+ case 3:
+ /* Sometime we just want any version of the driver */
+
+ if ( version == DRIVER_ANY_VERSION ) {
+ /* look for Win2k first and then for NT4 */
+ result = get_a_printer_driver_3(&driver->info_3, drivername,
+ architecture, 3);
+
+ if ( !W_ERROR_IS_OK(result) ) {
+ result = get_a_printer_driver_3( &driver->info_3,
+ drivername, architecture, 2 );
+ }
+ } else {
+ result = get_a_printer_driver_3(&driver->info_3, drivername,
+ architecture, version);
+ }
+ break;
+
+ default:
+ result=W_ERROR(1);
+ break;
+ }
+
+ if (W_ERROR_IS_OK(result))
+ dump_a_printer_driver(*driver, level);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
+{
+ uint32 result;
+
+ switch (level) {
+ case 3:
+ {
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
+ if (driver.info_3 != NULL)
+ {
+ info3=driver.info_3;
+ SAFE_FREE(info3->dependentfiles);
+ ZERO_STRUCTP(info3);
+ SAFE_FREE(info3);
+ result=0;
+ } else {
+ result=4;
+ }
+ break;
+ }
+ case 6:
+ {
+ NT_PRINTER_DRIVER_INFO_LEVEL_6 *info6;
+ if (driver.info_6 != NULL) {
+ info6=driver.info_6;
+ SAFE_FREE(info6->dependentfiles);
+ SAFE_FREE(info6->previousnames);
+ ZERO_STRUCTP(info6);
+ SAFE_FREE(info6);
+ result=0;
+ } else {
+ result=4;
+ }
+ break;
+ }
+ default:
+ result=1;
+ break;
+ }
+ return result;
+}
+
+
+/****************************************************************************
+ Determine whether or not a particular driver is currently assigned
+ to a printer
+****************************************************************************/
+
+bool printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
+{
+ int snum;
+ int n_services = lp_numservices();
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ bool in_use = False;
+
+ if ( !info_3 )
+ return False;
+
+ DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
+
+ /* loop through the printers.tdb and check for the drivername */
+
+ for (snum=0; snum<n_services && !in_use; snum++) {
+ if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
+ continue;
+
+ if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))) )
+ continue;
+
+ if ( strequal(info_3->name, printer->info_2->drivername) )
+ in_use = True;
+
+ free_a_printer( &printer, 2 );
+ }
+
+ DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
+
+ if ( in_use ) {
+ NT_PRINTER_DRIVER_INFO_LEVEL d;
+ WERROR werr;
+
+ DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", info_3->name));
+
+ /* we can still remove the driver if there is one of
+ "Windows NT x86" version 2 or 3 left */
+
+ if ( !strequal( "Windows NT x86", info_3->environment ) ) {
+ werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", DRIVER_ANY_VERSION );
+ }
+ else {
+ switch ( info_3->cversion ) {
+ case 2:
+ werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", 3 );
+ break;
+ case 3:
+ werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", 2 );
+ break;
+ default:
+ DEBUG(0,("printer_driver_in_use: ERROR! unknown driver version (%d)\n",
+ info_3->cversion));
+ werr = WERR_UNKNOWN_PRINTER_DRIVER;
+ break;
+ }
+ }
+
+ /* now check the error code */
+
+ if ( W_ERROR_IS_OK(werr) ) {
+ /* it's ok to remove the driver, we have other architctures left */
+ in_use = False;
+ free_a_printer_driver( d, 3 );
+ }
+ }
+
+ /* report that the driver is not in use by default */
+
+ return in_use;
+}
+
+
+/**********************************************************************
+ Check to see if a ogiven file is in use by *info
+ *********************************************************************/
+
+static bool drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
+{
+ int i = 0;
+
+ if ( !info )
+ return False;
+
+ /* mz: skip files that are in the list but already deleted */
+ if (!file || !file[0]) {
+ return false;
+ }
+
+ if ( strequal(file, info->driverpath) )
+ return True;
+
+ if ( strequal(file, info->datafile) )
+ return True;
+
+ if ( strequal(file, info->configfile) )
+ return True;
+
+ if ( strequal(file, info->helpfile) )
+ return True;
+
+ /* see of there are any dependent files to examine */
+
+ if ( !info->dependentfiles )
+ return False;
+
+ while ( *info->dependentfiles[i] ) {
+ if ( strequal(file, info->dependentfiles[i]) )
+ return True;
+ i++;
+ }
+
+ return False;
+
+}
+
+/**********************************************************************
+ Utility function to remove the dependent file pointed to by the
+ input parameter from the list
+ *********************************************************************/
+
+static void trim_dependent_file( fstring files[], int idx )
+{
+
+ /* bump everything down a slot */
+
+ while( *files[idx+1] ) {
+ fstrcpy( files[idx], files[idx+1] );
+ idx++;
+ }
+
+ *files[idx] = '\0';
+
+ return;
+}
+
+/**********************************************************************
+ Check if any of the files used by src are also used by drv
+ *********************************************************************/
+
+static bool trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src,
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 *drv )
+{
+ bool in_use = False;
+ int i = 0;
+
+ if ( !src || !drv )
+ return False;
+
+ /* check each file. Remove it from the src structure if it overlaps */
+
+ if ( drv_file_in_use(src->driverpath, drv) ) {
+ in_use = True;
+ DEBUG(10,("Removing driverfile [%s] from list\n", src->driverpath));
+ fstrcpy( src->driverpath, "" );
+ }
+
+ if ( drv_file_in_use(src->datafile, drv) ) {
+ in_use = True;
+ DEBUG(10,("Removing datafile [%s] from list\n", src->datafile));
+ fstrcpy( src->datafile, "" );
+ }
+
+ if ( drv_file_in_use(src->configfile, drv) ) {
+ in_use = True;
+ DEBUG(10,("Removing configfile [%s] from list\n", src->configfile));
+ fstrcpy( src->configfile, "" );
+ }
+
+ if ( drv_file_in_use(src->helpfile, drv) ) {
+ in_use = True;
+ DEBUG(10,("Removing helpfile [%s] from list\n", src->helpfile));
+ fstrcpy( src->helpfile, "" );
+ }
+
+ /* are there any dependentfiles to examine? */
+
+ if ( !src->dependentfiles )
+ return in_use;
+
+ while ( *src->dependentfiles[i] ) {
+ if ( drv_file_in_use(src->dependentfiles[i], drv) ) {
+ in_use = True;
+ DEBUG(10,("Removing [%s] from dependent file list\n", src->dependentfiles[i]));
+ trim_dependent_file( src->dependentfiles, i );
+ } else
+ i++;
+ }
+
+ return in_use;
+}
+
+/****************************************************************************
+ Determine whether or not a particular driver files are currently being
+ used by any other driver.
+
+ Return value is True if any files were in use by other drivers
+ and False otherwise.
+
+ Upon return, *info has been modified to only contain the driver files
+ which are not in use
+
+ Fix from mz:
+
+ This needs to check all drivers to ensure that all files in use
+ have been removed from *info, not just the ones in the first
+ match.
+****************************************************************************/
+
+bool printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
+{
+ int i;
+ int ndrivers;
+ uint32 version;
+ fstring *list = NULL;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ bool in_use = false;
+
+ if ( !info )
+ return False;
+
+ version = info->cversion;
+
+ /* loop over all driver versions */
+
+ DEBUG(5,("printer_driver_files_in_use: Beginning search through ntdrivers.tdb...\n"));
+
+ /* get the list of drivers */
+
+ list = NULL;
+ ndrivers = get_ntdrivers(&list, info->environment, version);
+
+ DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n",
+ ndrivers, info->environment, version));
+
+ /* check each driver for overlap in files */
+
+ for (i=0; i<ndrivers; i++) {
+ DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
+
+ ZERO_STRUCT(driver);
+
+ if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, list[i], info->environment, version)) ) {
+ SAFE_FREE(list);
+ return True;
+ }
+
+ /* check if d2 uses any files from d1 */
+ /* only if this is a different driver than the one being deleted */
+
+ if ( !strequal(info->name, driver.info_3->name) ) {
+ if ( trim_overlap_drv_files(info, driver.info_3) ) {
+ /* mz: Do not instantly return -
+ * we need to ensure this file isn't
+ * also in use by other drivers. */
+ in_use = true;
+ }
+ }
+
+ free_a_printer_driver(driver, 3);
+ }
+
+ SAFE_FREE(list);
+
+ DEBUG(5,("printer_driver_files_in_use: Completed search through ntdrivers.tdb...\n"));
+
+ driver.info_3 = info;
+
+ if ( DEBUGLEVEL >= 20 )
+ dump_a_printer_driver( driver, 3 );
+
+ return in_use;
+}
+
+/****************************************************************************
+ Actually delete the driver files. Make sure that
+ printer_driver_files_in_use() return False before calling
+ this.
+****************************************************************************/
+
+static bool delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user )
+{
+ int i = 0;
+ char *s;
+ const char *file;
+ connection_struct *conn;
+ DATA_BLOB null_pw;
+ NTSTATUS nt_status;
+ fstring res_type;
+ SMB_STRUCT_STAT st;
+
+ if ( !info_3 )
+ return False;
+
+ DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n", info_3->name, info_3->cversion));
+
+ /*
+ * Connect to the print$ share under the same account as the
+ * user connected to the rpc pipe. Note we must be root to
+ * do this.
+ */
+
+ null_pw = data_blob_null;
+ fstrcpy(res_type, "A:");
+ become_root();
+ conn = make_connection_with_chdir( "print$", null_pw, res_type, user->vuid, &nt_status );
+ unbecome_root();
+
+ if ( !conn ) {
+ DEBUG(0,("delete_driver_files: Unable to connect\n"));
+ return False;
+ }
+
+ if ( !CAN_WRITE(conn) ) {
+ DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
+ return False;
+ }
+
+ /* Save who we are - we are temporarily becoming the connection user. */
+
+ if ( !become_user(conn, conn->vuid) ) {
+ DEBUG(0,("delete_driver_files: Can't become user!\n"));
+ return False;
+ }
+
+ /* now delete the files; must strip the '\print$' string from
+ fron of path */
+
+ if ( *info_3->driverpath ) {
+ if ( (s = strchr( &info_3->driverpath[1], '\\' )) != NULL ) {
+ file = s;
+ driver_unix_convert(conn,file,&st);
+ DEBUG(10,("deleting driverfile [%s]\n", s));
+ unlink_internals(conn, NULL, 0, file, False);
+ }
+ }
+
+ if ( *info_3->configfile ) {
+ if ( (s = strchr( &info_3->configfile[1], '\\' )) != NULL ) {
+ file = s;
+ driver_unix_convert(conn,file,&st);
+ DEBUG(10,("deleting configfile [%s]\n", s));
+ unlink_internals(conn, NULL, 0, file, False);
+ }
+ }
+
+ if ( *info_3->datafile ) {
+ if ( (s = strchr( &info_3->datafile[1], '\\' )) != NULL ) {
+ file = s;
+ driver_unix_convert(conn,file,&st);
+ DEBUG(10,("deleting datafile [%s]\n", s));
+ unlink_internals(conn, NULL, 0, file, False);
+ }
+ }
+
+ if ( *info_3->helpfile ) {
+ if ( (s = strchr( &info_3->helpfile[1], '\\' )) != NULL ) {
+ file = s;
+ driver_unix_convert(conn,file,&st);
+ DEBUG(10,("deleting helpfile [%s]\n", s));
+ unlink_internals(conn, NULL, 0, file, False);
+ }
+ }
+
+ /* check if we are done removing files */
+
+ if ( info_3->dependentfiles ) {
+ while ( info_3->dependentfiles[i][0] ) {
+ char *p;
+
+ /* bypass the "\print$" portion of the path */
+
+ if ( (p = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL ) {
+ file = p;
+ driver_unix_convert(conn,file,&st);
+ DEBUG(10,("deleting dependent file [%s]\n", file));
+ unlink_internals(conn, NULL, 0, file, False);
+ }
+
+ i++;
+ }
+ }
+
+ unbecome_user();
+
+ return true;
+}
+
+/****************************************************************************
+ Remove a printer driver from the TDB. This assumes that the the driver was
+ previously looked up.
+ ***************************************************************************/
+
+WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user,
+ uint32 version, bool delete_files )
+{
+ char *key = NULL;
+ const char *arch;
+ TDB_DATA dbuf;
+ NT_PRINTER_DRIVER_INFO_LEVEL ctr;
+
+ /* delete the tdb data first */
+
+ arch = get_short_archi(info_3->environment);
+ if (!arch) {
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+ if (asprintf(&key, "%s%s/%d/%s", DRIVERS_PREFIX,
+ arch, version, info_3->name) < 0) {
+ return WERR_NOMEM;
+ }
+
+ DEBUG(5,("delete_printer_driver: key = [%s] delete_files = %s\n",
+ key, delete_files ? "TRUE" : "FALSE" ));
+
+ ctr.info_3 = info_3;
+ dump_a_printer_driver( ctr, 3 );
+
+ /* check if the driver actually exists for this environment */
+
+ dbuf = tdb_fetch_bystring( tdb_drivers, key );
+ if ( !dbuf.dptr ) {
+ DEBUG(8,("delete_printer_driver: Driver unknown [%s]\n", key));
+ SAFE_FREE(key);
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+
+ SAFE_FREE( dbuf.dptr );
+
+ /* ok... the driver exists so the delete should return success */
+
+ if (tdb_delete_bystring(tdb_drivers, key) == -1) {
+ DEBUG (0,("delete_printer_driver: fail to delete %s!\n", key));
+ SAFE_FREE(key);
+ return WERR_ACCESS_DENIED;
+ }
+
+ /*
+ * now delete any associated files if delete_files == True
+ * even if this part failes, we return succes because the
+ * driver doesn not exist any more
+ */
+
+ if ( delete_files )
+ delete_driver_files( info_3, user );
+
+ DEBUG(5,("delete_printer_driver: driver delete successful [%s]\n", key));
+ SAFE_FREE(key);
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ Store a security desc for a printer.
+****************************************************************************/
+
+WERROR nt_printing_setsec(const char *sharename, SEC_DESC_BUF *secdesc_ctr)
+{
+ SEC_DESC_BUF *new_secdesc_ctr = NULL;
+ SEC_DESC_BUF *old_secdesc_ctr = NULL;
+ prs_struct ps;
+ bool prs_init_done = false;
+ TALLOC_CTX *mem_ctx = NULL;
+ TDB_DATA kbuf;
+ WERROR status;
+
+ mem_ctx = talloc_init("nt_printing_setsec");
+ if (mem_ctx == NULL)
+ return WERR_NOMEM;
+
+ /* The old owner and group sids of the security descriptor are not
+ present when new ACEs are added or removed by changing printer
+ permissions through NT. If they are NULL in the new security
+ descriptor then copy them over from the old one. */
+
+ if (!secdesc_ctr->sd->owner_sid || !secdesc_ctr->sd->group_sid) {
+ DOM_SID *owner_sid, *group_sid;
+ SEC_ACL *dacl, *sacl;
+ SEC_DESC *psd = NULL;
+ size_t size;
+
+ if (!nt_printing_getsec(mem_ctx, sharename, &old_secdesc_ctr)) {
+ status = WERR_NOMEM;
+ goto out;
+ }
+
+ /* Pick out correct owner and group sids */
+
+ owner_sid = secdesc_ctr->sd->owner_sid ?
+ secdesc_ctr->sd->owner_sid :
+ old_secdesc_ctr->sd->owner_sid;
+
+ group_sid = secdesc_ctr->sd->group_sid ?
+ secdesc_ctr->sd->group_sid :
+ old_secdesc_ctr->sd->group_sid;
+
+ dacl = secdesc_ctr->sd->dacl ?
+ secdesc_ctr->sd->dacl :
+ old_secdesc_ctr->sd->dacl;
+
+ sacl = secdesc_ctr->sd->sacl ?
+ secdesc_ctr->sd->sacl :
+ old_secdesc_ctr->sd->sacl;
+
+ /* Make a deep copy of the security descriptor */
+
+ psd = make_sec_desc(mem_ctx, secdesc_ctr->sd->revision, secdesc_ctr->sd->type,
+ owner_sid, group_sid,
+ sacl,
+ dacl,
+ &size);
+
+ if (!psd) {
+ status = WERR_NOMEM;
+ goto out;
+ }
+
+ new_secdesc_ctr = make_sec_desc_buf(mem_ctx, size, psd);
+ }
+
+ if (!new_secdesc_ctr) {
+ new_secdesc_ctr = secdesc_ctr;
+ }
+
+ /* Store the security descriptor in a tdb */
+
+ if (!prs_init(&ps,
+ (uint32)ndr_size_security_descriptor(new_secdesc_ctr->sd, 0)
+ + sizeof(SEC_DESC_BUF), mem_ctx, MARSHALL) ) {
+ status = WERR_NOMEM;
+ goto out;
+ }
+
+
+ prs_init_done = true;
+
+ if (!sec_io_desc_buf("nt_printing_setsec", &new_secdesc_ctr,
+ &ps, 1)) {
+ status = WERR_BADFUNC;
+ goto out;
+ }
+
+ kbuf = make_printers_secdesc_tdbkey(mem_ctx, sharename );
+
+ if (tdb_prs_store(tdb_printers, kbuf, &ps)==0) {
+ status = WERR_OK;
+ } else {
+ DEBUG(1,("Failed to store secdesc for %s\n", sharename));
+ status = WERR_BADFUNC;
+ }
+
+ /* Free malloc'ed memory */
+
+ out:
+
+ if (prs_init_done) {
+ prs_mem_free(&ps);
+ }
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ return status;
+}
+
+/****************************************************************************
+ Construct a default security descriptor buffer for a printer.
+****************************************************************************/
+
+static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
+{
+ SEC_ACE ace[5]; /* max number of ace entries */
+ int i = 0;
+ SEC_ACCESS sa;
+ SEC_ACL *psa = NULL;
+ SEC_DESC_BUF *sdb = NULL;
+ SEC_DESC *psd = NULL;
+ DOM_SID adm_sid;
+ size_t sd_size;
+
+ /* Create an ACE where Everyone is allowed to print */
+
+ init_sec_access(&sa, PRINTER_ACE_PRINT);
+ init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
+ sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
+
+ /* Add the domain admins group if we are a DC */
+
+ if ( IS_DC ) {
+ DOM_SID domadmins_sid;
+
+ sid_copy(&domadmins_sid, get_global_sam_sid());
+ sid_append_rid(&domadmins_sid, DOMAIN_GROUP_RID_ADMINS);
+
+ init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
+ init_sec_ace(&ace[i++], &domadmins_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
+ SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
+ init_sec_ace(&ace[i++], &domadmins_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
+ sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
+ }
+ else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) {
+ sid_append_rid(&adm_sid, DOMAIN_USER_RID_ADMIN);
+
+ init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
+ init_sec_ace(&ace[i++], &adm_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
+ SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
+ init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
+ sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
+ }
+
+ /* add BUILTIN\Administrators as FULL CONTROL */
+
+ init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
+ init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
+ SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
+ SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
+ init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
+
+ /* Make the security descriptor owned by the BUILTIN\Administrators */
+
+ /* The ACL revision number in rpc_secdesc.h differs from the one
+ created by NT when setting ACE entries in printer
+ descriptors. NT4 complains about the property being edited by a
+ NT5 machine. */
+
+ if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) != NULL) {
+ psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
+ &global_sid_Builtin_Administrators,
+ &global_sid_Builtin_Administrators,
+ NULL, psa, &sd_size);
+ }
+
+ if (!psd) {
+ DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
+ return NULL;
+ }
+
+ sdb = make_sec_desc_buf(ctx, sd_size, psd);
+
+ DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
+ (unsigned int)sd_size));
+
+ return sdb;
+}
+
+/****************************************************************************
+ Get a security desc for a printer.
+****************************************************************************/
+
+bool nt_printing_getsec(TALLOC_CTX *ctx, const char *sharename, SEC_DESC_BUF **secdesc_ctr)
+{
+ prs_struct ps;
+ TDB_DATA kbuf;
+ char *temp;
+
+ if (strlen(sharename) > 2 && (temp = strchr(sharename + 2, '\\'))) {
+ sharename = temp + 1;
+ }
+
+ ZERO_STRUCT(ps);
+
+ /* Fetch security descriptor from tdb */
+
+ kbuf = make_printers_secdesc_tdbkey(ctx, sharename );
+
+ if (tdb_prs_fetch(tdb_printers, kbuf, &ps, ctx)!=0 ||
+ !sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) {
+
+ prs_mem_free(&ps);
+
+ DEBUG(4,("using default secdesc for %s\n", sharename));
+
+ if (!(*secdesc_ctr = construct_default_printer_sdb(ctx))) {
+ return False;
+ }
+
+ /* Save default security descriptor for later */
+
+ if (!prs_init(&ps, (uint32)ndr_size_security_descriptor((*secdesc_ctr)->sd, 0) +
+ sizeof(SEC_DESC_BUF), ctx, MARSHALL))
+ return False;
+
+ if (sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) {
+ tdb_prs_store(tdb_printers, kbuf, &ps);
+ }
+
+ prs_mem_free(&ps);
+
+ return True;
+ }
+
+ prs_mem_free(&ps);
+
+ /* If security descriptor is owned by S-1-1-0 and winbindd is up,
+ this security descriptor has been created when winbindd was
+ down. Take ownership of security descriptor. */
+
+ if (sid_equal((*secdesc_ctr)->sd->owner_sid, &global_sid_World)) {
+ DOM_SID owner_sid;
+
+ /* Change sd owner to workgroup administrator */
+
+ if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
+ SEC_DESC_BUF *new_secdesc_ctr = NULL;
+ SEC_DESC *psd = NULL;
+ size_t size;
+
+ /* Create new sd */
+
+ sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
+
+ psd = make_sec_desc(ctx, (*secdesc_ctr)->sd->revision, (*secdesc_ctr)->sd->type,
+ &owner_sid,
+ (*secdesc_ctr)->sd->group_sid,
+ (*secdesc_ctr)->sd->sacl,
+ (*secdesc_ctr)->sd->dacl,
+ &size);
+
+ if (!psd) {
+ return False;
+ }
+
+ new_secdesc_ctr = make_sec_desc_buf(ctx, size, psd);
+ if (!new_secdesc_ctr) {
+ return False;
+ }
+
+ /* Swap with other one */
+
+ *secdesc_ctr = new_secdesc_ctr;
+
+ /* Set it */
+
+ nt_printing_setsec(sharename, *secdesc_ctr);
+ }
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ SEC_ACL *the_acl = (*secdesc_ctr)->sd->dacl;
+ int i;
+
+ DEBUG(10, ("secdesc_ctr for %s has %d aces:\n",
+ sharename, the_acl->num_aces));
+
+ for (i = 0; i < the_acl->num_aces; i++) {
+ DEBUG(10, ("%s %d %d 0x%08x\n",
+ sid_string_dbg(&the_acl->aces[i].trustee),
+ the_acl->aces[i].type, the_acl->aces[i].flags,
+ the_acl->aces[i].access_mask));
+ }
+ }
+
+ return True;
+}
+
+/* error code:
+ 0: everything OK
+ 1: level not implemented
+ 2: file doesn't exist
+ 3: can't allocate memory
+ 4: can't free memory
+ 5: non existant struct
+*/
+
+/*
+ A printer and a printer driver are 2 different things.
+ NT manages them separatelly, Samba does the same.
+ Why ? Simply because it's easier and it makes sense !
+
+ Now explanation: You have 3 printers behind your samba server,
+ 2 of them are the same make and model (laser A and B). But laser B
+ has an 3000 sheet feeder and laser A doesn't such an option.
+ Your third printer is an old dot-matrix model for the accounting :-).
+
+ If the /usr/local/samba/lib directory (default dir), you will have
+ 5 files to describe all of this.
+
+ 3 files for the printers (1 by printer):
+ NTprinter_laser A
+ NTprinter_laser B
+ NTprinter_accounting
+ 2 files for the drivers (1 for the laser and 1 for the dot matrix)
+ NTdriver_printer model X
+ NTdriver_printer model Y
+
+jfm: I should use this comment for the text file to explain
+ same thing for the forms BTW.
+ Je devrais mettre mes commentaires en francais, ca serait mieux :-)
+
+*/
+
+/* Convert generic access rights to printer object specific access rights.
+ It turns out that NT4 security descriptors use generic access rights and
+ NT5 the object specific ones. */
+
+void map_printer_permissions(SEC_DESC *sd)
+{
+ int i;
+
+ for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
+ se_map_generic(&sd->dacl->aces[i].access_mask,
+ &printer_generic_mapping);
+ }
+}
+
+void map_job_permissions(SEC_DESC *sd)
+{
+ int i;
+
+ for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
+ se_map_generic(&sd->dacl->aces[i].access_mask,
+ &job_generic_mapping);
+ }
+}
+
+
+/****************************************************************************
+ Check a user has permissions to perform the given operation. We use the
+ permission constants defined in include/rpc_spoolss.h to check the various
+ actions we perform when checking printer access.
+
+ PRINTER_ACCESS_ADMINISTER:
+ print_queue_pause, print_queue_resume, update_printer_sec,
+ update_printer, spoolss_addprinterex_level_2,
+ _spoolss_setprinterdata
+
+ PRINTER_ACCESS_USE:
+ print_job_start
+
+ JOB_ACCESS_ADMINISTER:
+ print_job_delete, print_job_pause, print_job_resume,
+ print_queue_purge
+
+ Try access control in the following order (for performance reasons):
+ 1) root ans SE_PRINT_OPERATOR can do anything (easy check)
+ 2) check security descriptor (bit comparisons in memory)
+ 3) "printer admins" (may result in numerous calls to winbind)
+
+ ****************************************************************************/
+bool print_access_check(struct auth_serversupplied_info *server_info, int snum,
+ int access_type)
+{
+ SEC_DESC_BUF *secdesc = NULL;
+ uint32 access_granted;
+ NTSTATUS status;
+ bool result;
+ const char *pname;
+ TALLOC_CTX *mem_ctx = NULL;
+ SE_PRIV se_printop = SE_PRINT_OPERATOR;
+
+ /* If user is NULL then use the current_user structure */
+
+ /* Always allow root or SE_PRINT_OPERATROR to do anything */
+
+ if (server_info->utok.uid == 0
+ || user_has_privileges(server_info->ptok, &se_printop ) ) {
+ return True;
+ }
+
+ /* Get printer name */
+
+ pname = PRINTERNAME(snum);
+
+ if (!pname || !*pname) {
+ errno = EACCES;
+ return False;
+ }
+
+ /* Get printer security descriptor */
+
+ if(!(mem_ctx = talloc_init("print_access_check"))) {
+ errno = ENOMEM;
+ return False;
+ }
+
+ if (!nt_printing_getsec(mem_ctx, pname, &secdesc)) {
+ talloc_destroy(mem_ctx);
+ errno = ENOMEM;
+ return False;
+ }
+
+ if (access_type == JOB_ACCESS_ADMINISTER) {
+ SEC_DESC_BUF *parent_secdesc = secdesc;
+
+ /* Create a child security descriptor to check permissions
+ against. This is because print jobs are child objects
+ objects of a printer. */
+
+ secdesc = se_create_child_secdesc(mem_ctx, parent_secdesc->sd, False);
+
+ if (!secdesc) {
+ talloc_destroy(mem_ctx);
+ errno = ENOMEM;
+ return False;
+ }
+
+ map_job_permissions(secdesc->sd);
+ } else {
+ map_printer_permissions(secdesc->sd);
+ }
+
+ /* Check access */
+ result = se_access_check(secdesc->sd, server_info->ptok, access_type,
+ &access_granted, &status);
+
+ DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE"));
+
+ /* see if we need to try the printer admin list */
+
+ if ((access_granted == 0) &&
+ (token_contains_name_in_list(uidtoname(server_info->utok.uid),
+ NULL, NULL, server_info->ptok,
+ lp_printer_admin(snum)))) {
+ talloc_destroy(mem_ctx);
+ return True;
+ }
+
+ talloc_destroy(mem_ctx);
+
+ if (!result) {
+ errno = EACCES;
+ }
+
+ return result;
+}
+
+/****************************************************************************
+ Check the time parameters allow a print operation.
+*****************************************************************************/
+
+bool print_time_access_check(const char *servicename)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ bool ok = False;
+ time_t now = time(NULL);
+ struct tm *t;
+ uint32 mins;
+
+ if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, servicename)))
+ return False;
+
+ if (printer->info_2->starttime == 0 && printer->info_2->untiltime == 0)
+ ok = True;
+
+ t = gmtime(&now);
+ mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
+
+ if (mins >= printer->info_2->starttime && mins <= printer->info_2->untiltime)
+ ok = True;
+
+ free_a_printer(&printer, 2);
+
+ if (!ok)
+ errno = EACCES;
+
+ return ok;
+}
+
+/****************************************************************************
+ Fill in the servername sent in the _spoolss_open_printer_ex() call
+****************************************************************************/
+
+char* get_server_name( Printer_entry *printer )
+{
+ return printer->servername;
+}
+
+
diff --git a/source3/printing/pcap.c b/source3/printing/pcap.c
new file mode 100644
index 0000000000..30cb254a29
--- /dev/null
+++ b/source3/printing/pcap.c
@@ -0,0 +1,263 @@
+/*
+ Unix SMB/CIFS implementation.
+ printcap parsing
+ Copyright (C) Karl Auer 1993-1998
+
+ Re-working by Martin Kiff, 1994
+
+ Re-written again by Andrew Tridgell
+
+ Modified for SVID support by Norm Jacobs, 1997
+
+ Modified for CUPS support by Michael Sweet, 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * This module contains code to parse and cache printcap data, possibly
+ * in concert with the CUPS/SYSV/AIX-specific code found elsewhere.
+ *
+ * The way this module looks at the printcap file is very simplistic.
+ * Only the local printcap file is inspected (no searching of NIS
+ * databases etc).
+ *
+ * There are assumed to be one or more printer names per record, held
+ * as a set of sub-fields separated by vertical bar symbols ('|') in the
+ * first field of the record. The field separator is assumed to be a colon
+ * ':' and the record separator a newline.
+ *
+ * Lines ending with a backspace '\' are assumed to flag that the following
+ * line is a continuation line so that a set of lines can be read as one
+ * printcap entry.
+ *
+ * A line stating with a hash '#' is assumed to be a comment and is ignored
+ * Comments are discarded before the record is strung together from the
+ * set of continuation lines.
+ *
+ * Opening a pipe for "lpc status" and reading that would probably
+ * be pretty effective. Code to do this already exists in the freely
+ * distributable PCNFS server code.
+ *
+ * Modified to call SVID/XPG4 support if printcap name is set to "lpstat"
+ * in smb.conf under Solaris.
+ *
+ * Modified to call CUPS support if printcap name is set to "cups"
+ * in smb.conf.
+ *
+ * Modified to call iPrint support if printcap name is set to "iprint"
+ * in smb.conf.
+ */
+
+#include "includes.h"
+
+
+typedef struct pcap_cache {
+ char *name;
+ char *comment;
+ struct pcap_cache *next;
+} pcap_cache_t;
+
+static pcap_cache_t *pcap_cache = NULL;
+
+bool pcap_cache_add(const char *name, const char *comment)
+{
+ pcap_cache_t *p;
+
+ if (name == NULL || ((p = SMB_MALLOC_P(pcap_cache_t)) == NULL))
+ return False;
+
+ p->name = SMB_STRDUP(name);
+ p->comment = (comment && *comment) ? SMB_STRDUP(comment) : NULL;
+
+ p->next = pcap_cache;
+ pcap_cache = p;
+
+ return True;
+}
+
+static void pcap_cache_destroy(pcap_cache_t *cache)
+{
+ pcap_cache_t *p, *next;
+
+ for (p = cache; p != NULL; p = next) {
+ next = p->next;
+
+ SAFE_FREE(p->name);
+ SAFE_FREE(p->comment);
+ SAFE_FREE(p);
+ }
+}
+
+bool pcap_cache_loaded(void)
+{
+ return (pcap_cache != NULL);
+}
+
+void pcap_cache_reload(void)
+{
+ const char *pcap_name = lp_printcapname();
+ bool pcap_reloaded = False;
+ pcap_cache_t *tmp_cache = NULL;
+ XFILE *pcap_file;
+ char *pcap_line;
+
+ DEBUG(3, ("reloading printcap cache\n"));
+
+ /* only go looking if no printcap name supplied */
+ if (pcap_name == NULL || *pcap_name == 0) {
+ DEBUG(0, ("No printcap file name configured!\n"));
+ return;
+ }
+
+ tmp_cache = pcap_cache;
+ pcap_cache = NULL;
+
+#ifdef HAVE_CUPS
+ if (strequal(pcap_name, "cups")) {
+ pcap_reloaded = cups_cache_reload();
+ goto done;
+ }
+#endif
+
+#ifdef HAVE_IPRINT
+ if (strequal(pcap_name, "iprint")) {
+ pcap_reloaded = iprint_cache_reload();
+ goto done;
+ }
+#endif
+
+#if defined(SYSV) || defined(HPUX)
+ if (strequal(pcap_name, "lpstat")) {
+ pcap_reloaded = sysv_cache_reload();
+ goto done;
+ }
+#endif
+
+#ifdef AIX
+ if (strstr_m(pcap_name, "/qconfig") != NULL) {
+ pcap_reloaded = aix_cache_reload();
+ goto done;
+ }
+#endif
+
+ /* handle standard printcap - moved from pcap_printer_fn() */
+
+ if ((pcap_file = x_fopen(pcap_name, O_RDONLY, 0)) == NULL) {
+ DEBUG(0, ("Unable to open printcap file %s for read!\n", pcap_name));
+ goto done;
+ }
+
+ for (; (pcap_line = fgets_slash(NULL, 1024, pcap_file)) != NULL; safe_free(pcap_line)) {
+ char name[MAXPRINTERLEN+1];
+ char comment[62];
+ char *p, *q;
+
+ if (*pcap_line == '#' || *pcap_line == 0)
+ continue;
+
+ /* now we have a real printer line - cut at the first : */
+ if ((p = strchr_m(pcap_line, ':')) != NULL)
+ *p = 0;
+
+ /*
+ * now find the most likely printer name and comment
+ * this is pure guesswork, but it's better than nothing
+ */
+ for (*name = *comment = 0, p = pcap_line; p != NULL; p = q) {
+ bool has_punctuation;
+
+ if ((q = strchr_m(p, '|')) != NULL)
+ *q++ = 0;
+
+ has_punctuation = (strchr_m(p, ' ') ||
+ strchr_m(p, '\t') ||
+ strchr_m(p, '(') ||
+ strchr_m(p, ')'));
+
+ if (strlen(p) > strlen(comment) && has_punctuation) {
+ strlcpy(comment, p, sizeof(comment));
+ continue;
+ }
+
+ if (strlen(p) <= MAXPRINTERLEN &&
+ strlen(p) > strlen(name) && !has_punctuation) {
+ if (!*comment) {
+ strlcpy(comment, name, sizeof(comment));
+ }
+ strlcpy(name, p, sizeof(name));
+ continue;
+ }
+
+ if (!strchr_m(comment, ' ') &&
+ strlen(p) > strlen(comment)) {
+ strlcpy(comment, p, sizeof(comment));
+ continue;
+ }
+ }
+
+ comment[60] = 0;
+ name[MAXPRINTERLEN] = 0;
+
+ if (*name && !pcap_cache_add(name, comment)) {
+ x_fclose(pcap_file);
+ goto done;
+ }
+ }
+
+ x_fclose(pcap_file);
+ pcap_reloaded = True;
+
+done:
+ DEBUG(3, ("reload status: %s\n", (pcap_reloaded) ? "ok" : "error"));
+
+ if (pcap_reloaded)
+ pcap_cache_destroy(tmp_cache);
+ else {
+ pcap_cache_destroy(pcap_cache);
+ pcap_cache = tmp_cache;
+ }
+
+ return;
+}
+
+
+bool pcap_printername_ok(const char *printername)
+{
+ pcap_cache_t *p;
+
+ for (p = pcap_cache; p != NULL; p = p->next)
+ if (strequal(p->name, printername))
+ return True;
+
+ return False;
+}
+
+/***************************************************************************
+run a function on each printer name in the printcap file. The function is
+passed the primary name and the comment (if possible). Note the fn() takes
+strings in DOS codepage. This means the xxx_printer_fn() calls must be fixed
+to return DOS codepage. FIXME !! JRA.
+
+XXX: I'm not sure if this comment still applies.. Anyone? -Rob
+***************************************************************************/
+void pcap_printer_fn(void (*fn)(char *, char *))
+{
+ pcap_cache_t *p;
+
+ for (p = pcap_cache; p != NULL; p = p->next)
+ fn(p->name, p->comment);
+
+ return;
+}
diff --git a/source3/printing/print_aix.c b/source3/printing/print_aix.c
new file mode 100644
index 0000000000..57590cc39e
--- /dev/null
+++ b/source3/printing/print_aix.c
@@ -0,0 +1,123 @@
+/*
+ AIX-specific printcap loading
+ Copyright (C) Jean-Pierre.Boulard@univ-rennes1.fr 1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * This module implements AIX-specific printcap loading. Most of the code
+ * here was originally provided by Jean-Pierre.Boulard@univ-rennes1.fr in
+ * the Samba 1.9.14 release, and was formerly contained in pcap.c. It has
+ * been moved here and condensed as part of a larger effort to clean up and
+ * simplify the printcap code. -- Rob Foehl, 2004/12/06
+ */
+
+#include "includes.h"
+
+#ifdef AIX
+bool aix_cache_reload(void)
+{
+ int iEtat;
+ XFILE *pfile;
+ char *line = NULL, *p;
+ char *name = NULL;
+ TALLOC_CTX *ctx = talloc_init("aix_cache_reload");
+
+ if (!ctx) {
+ return false;
+ }
+
+ DEBUG(5, ("reloading aix printcap cache\n"));
+
+ if ((pfile = x_fopen(lp_printcapname(), O_RDONLY, 0)) == NULL) {
+ DEBUG(0,( "Unable to open qconfig file %s for read!\n", lp_printcapname()));
+ TALLOC_FREE(ctx);
+ return false;
+ }
+
+ iEtat = 0;
+ /* scan qconfig file for searching <printername>: */
+ for (;(line = fgets_slash(NULL, 1024, pfile)); safe_free(line)) {
+ if (*line == '*' || *line == 0)
+ continue;
+
+ switch (iEtat) {
+ case 0: /* locate an entry */
+ if (*line == '\t' || *line == ' ')
+ continue;
+
+ if ((p = strchr_m(line, ':'))) {
+ char *saveptr;
+ *p = '\0';
+ p = strtok_r(line, ":", &saveptr);
+ if (strcmp(p, "bsh") != 0) {
+ name = talloc_strdup(ctx, p);
+ if (!name) {
+ safe_free(line);
+ x_fclose(pfile);
+ TALLOC_FREE(ctx);
+ return false;
+ }
+ iEtat = 1;
+ continue;
+ }
+ }
+ break;
+
+ case 1: /* scanning device stanza */
+ if (*line == '*' || *line == 0)
+ continue;
+
+ if (*line != '\t' && *line != ' ') {
+ /* name is found without stanza device */
+ /* probably a good printer ??? */
+ iEtat = 0;
+ if (!pcap_cache_add(name, NULL)) {
+ safe_free(line);
+ x_fclose(pfile);
+ TALLOC_FREE(ctx);
+ return false;
+ }
+ continue;
+ }
+
+ if (strstr_m(line, "backend")) {
+ /* it's a device, not a virtual printer */
+ iEtat = 0;
+ } else if (strstr_m(line, "device")) {
+ /* it's a good virtual printer */
+ iEtat = 0;
+ if (!pcap_cache_add(name, NULL)) {
+ safe_free(line);
+ x_fclose(pfile);
+ TALLOC_FREE(ctx);
+ return false;
+ }
+ continue;
+ }
+ break;
+ }
+ }
+
+ x_fclose(pfile);
+ TALLOC_FREE(ctx);
+ return true;
+}
+
+#else
+/* this keeps fussy compilers happy */
+ void print_aix_dummy(void);
+ void print_aix_dummy(void) {}
+#endif /* AIX */
diff --git a/source3/printing/print_cups.c b/source3/printing/print_cups.c
new file mode 100644
index 0000000000..593c5c7a1f
--- /dev/null
+++ b/source3/printing/print_cups.c
@@ -0,0 +1,1347 @@
+/*
+ * Support code for the Common UNIX Printing System ("CUPS")
+ *
+ * Copyright 1999-2003 by Michael R Sweet.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "printing.h"
+
+#ifdef HAVE_CUPS
+#include <cups/cups.h>
+#include <cups/language.h>
+
+extern userdom_struct current_user_info;
+
+/*
+ * 'cups_passwd_cb()' - The CUPS password callback...
+ */
+
+static const char * /* O - Password or NULL */
+cups_passwd_cb(const char *prompt) /* I - Prompt */
+{
+ /*
+ * Always return NULL to indicate that no password is available...
+ */
+
+ return (NULL);
+}
+
+static http_t *cups_connect(void)
+{
+ http_t *http;
+ char *server, *p;
+ int port;
+
+ if (lp_cups_server() != NULL && strlen(lp_cups_server()) > 0) {
+ server = smb_xstrdup(lp_cups_server());
+ } else {
+ server = smb_xstrdup(cupsServer());
+ }
+
+ p = strchr(server, ':');
+ if (p) {
+ port = atoi(p+1);
+ *p = '\0';
+ } else {
+ port = ippPort();
+ }
+
+ DEBUG(10, ("connecting to cups server %s:%d\n",
+ server, port));
+
+ if ((http = httpConnect(server, port)) == NULL) {
+ DEBUG(0,("Unable to connect to CUPS server %s:%d - %s\n",
+ server, port, strerror(errno)));
+ SAFE_FREE(server);
+ return NULL;
+ }
+
+ SAFE_FREE(server);
+ return http;
+}
+
+bool cups_cache_reload(void)
+{
+ http_t *http = NULL; /* HTTP connection to server */
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language = NULL; /* Default language */
+ char *name, /* printer-name attribute */
+ *info; /* printer-info attribute */
+ static const char *requested[] =/* Requested attributes */
+ {
+ "printer-name",
+ "printer-info"
+ };
+ bool ret = False;
+
+ DEBUG(5, ("reloading cups printcap cache\n"));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = cups_connect()) == NULL) {
+ goto out;
+ }
+
+ /*
+ * Build a CUPS_GET_PRINTERS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_GET_PRINTERS;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requested-attributes",
+ (sizeof(requested) / sizeof(requested[0])),
+ NULL, requested);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) == NULL) {
+ DEBUG(0,("Unable to get printer list - %s\n",
+ ippErrorString(cupsLastError())));
+ goto out;
+ }
+
+ for (attr = response->attrs; attr != NULL;) {
+ /*
+ * Skip leading attributes until we hit a printer...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Pull the needed attributes from this printer...
+ */
+
+ name = NULL;
+ info = NULL;
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
+ if (strcmp(attr->name, "printer-name") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ name = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "printer-info") == 0 &&
+ attr->value_tag == IPP_TAG_TEXT)
+ info = attr->values[0].string.text;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (name == NULL)
+ break;
+
+ if (!pcap_cache_add(name, info)) {
+ goto out;
+ }
+ }
+
+ ippDelete(response);
+ response = NULL;
+
+ /*
+ * Build a CUPS_GET_CLASSES request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_GET_CLASSES;
+ request->request.op.request_id = 1;
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requested-attributes",
+ (sizeof(requested) / sizeof(requested[0])),
+ NULL, requested);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) == NULL) {
+ DEBUG(0,("Unable to get printer list - %s\n",
+ ippErrorString(cupsLastError())));
+ goto out;
+ }
+
+ for (attr = response->attrs; attr != NULL;) {
+ /*
+ * Skip leading attributes until we hit a printer...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Pull the needed attributes from this printer...
+ */
+
+ name = NULL;
+ info = NULL;
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
+ if (strcmp(attr->name, "printer-name") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ name = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "printer-info") == 0 &&
+ attr->value_tag == IPP_TAG_TEXT)
+ info = attr->values[0].string.text;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (name == NULL)
+ break;
+
+ if (!pcap_cache_add(name, info)) {
+ goto out;
+ }
+ }
+
+ ret = True;
+
+ out:
+ if (response)
+ ippDelete(response);
+
+ if (language)
+ cupsLangFree(language);
+
+ if (http)
+ httpClose(http);
+
+ return ret;
+}
+
+
+/*
+ * 'cups_job_delete()' - Delete a job.
+ */
+
+static int cups_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob)
+{
+ int ret = 1; /* Return value */
+ http_t *http = NULL; /* HTTP connection to server */
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ cups_lang_t *language = NULL; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+
+
+ DEBUG(5,("cups_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = cups_connect()) == NULL) {
+ goto out;
+ }
+
+ /*
+ * Build an IPP_CANCEL_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * job-uri
+ * requesting-user-name
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_CANCEL_JOB;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, pjob->user);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
+ if (response->request.status.status_code >= IPP_OK_CONFLICT) {
+ DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+ } else {
+ ret = 0;
+ }
+ } else {
+ DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+ }
+
+ out:
+ if (response)
+ ippDelete(response);
+
+ if (language)
+ cupsLangFree(language);
+
+ if (http)
+ httpClose(http);
+
+ return ret;
+}
+
+
+/*
+ * 'cups_job_pause()' - Pause a job.
+ */
+
+static int cups_job_pause(int snum, struct printjob *pjob)
+{
+ int ret = 1; /* Return value */
+ http_t *http = NULL; /* HTTP connection to server */
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ cups_lang_t *language = NULL; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+
+
+ DEBUG(5,("cups_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = cups_connect()) == NULL) {
+ goto out;
+ }
+
+ /*
+ * Build an IPP_HOLD_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * job-uri
+ * requesting-user-name
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_HOLD_JOB;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, pjob->user);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
+ if (response->request.status.status_code >= IPP_OK_CONFLICT) {
+ DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+ } else {
+ ret = 0;
+ }
+ } else {
+ DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+ }
+
+ out:
+ if (response)
+ ippDelete(response);
+
+ if (language)
+ cupsLangFree(language);
+
+ if (http)
+ httpClose(http);
+
+ return ret;
+}
+
+
+/*
+ * 'cups_job_resume()' - Resume a paused job.
+ */
+
+static int cups_job_resume(int snum, struct printjob *pjob)
+{
+ int ret = 1; /* Return value */
+ http_t *http = NULL; /* HTTP connection to server */
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ cups_lang_t *language = NULL; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+
+
+ DEBUG(5,("cups_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = cups_connect()) == NULL) {
+ goto out;
+ }
+
+ /*
+ * Build an IPP_RELEASE_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * job-uri
+ * requesting-user-name
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_RELEASE_JOB;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, pjob->user);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
+ if (response->request.status.status_code >= IPP_OK_CONFLICT) {
+ DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+ } else {
+ ret = 0;
+ }
+ } else {
+ DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+ }
+
+ out:
+ if (response)
+ ippDelete(response);
+
+ if (language)
+ cupsLangFree(language);
+
+ if (http)
+ httpClose(http);
+
+ return ret;
+}
+
+
+/*
+ * 'cups_job_submit()' - Submit a job for printing.
+ */
+
+static int cups_job_submit(int snum, struct printjob *pjob)
+{
+ int ret = 1; /* Return value */
+ http_t *http = NULL; /* HTTP connection to server */
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ cups_lang_t *language = NULL; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+ const char *clientname = NULL; /* hostname of client for job-originating-host attribute */
+ char *new_jobname = NULL;
+ int num_options = 0;
+ cups_option_t *options = NULL;
+ char addr[INET6_ADDRSTRLEN];
+
+ DEBUG(5,("cups_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = cups_connect()) == NULL) {
+ goto out;
+ }
+
+ /*
+ * Build an IPP_PRINT_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ * [document-data]
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_PRINT_JOB;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
+ PRINTERNAME(snum));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, pjob->user);
+
+ clientname = client_name(get_client_fd());
+ if (strcmp(clientname, "UNKNOWN") == 0) {
+ clientname = client_addr(get_client_fd(),addr,sizeof(addr));
+ }
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "job-originating-host-name", NULL,
+ clientname);
+
+ if (asprintf(&new_jobname,"%s%.8u %s", PRINT_SPOOL_PREFIX,
+ (unsigned int)pjob->smbjob, pjob->jobname) < 0) {
+ goto out;
+ }
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
+ new_jobname);
+
+ /*
+ * add any options defined in smb.conf
+ */
+
+ num_options = 0;
+ options = NULL;
+ num_options = cupsParseOptions(lp_cups_options(snum), num_options, &options);
+
+ if ( num_options )
+ cupsEncodeOptions(request, num_options, options);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ slprintf(uri, sizeof(uri) - 1, "/printers/%s", PRINTERNAME(snum));
+
+ if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
+ if (response->request.status.status_code >= IPP_OK_CONFLICT) {
+ DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum),
+ ippErrorString(cupsLastError())));
+ } else {
+ ret = 0;
+ }
+ } else {
+ DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum),
+ ippErrorString(cupsLastError())));
+ }
+
+ if ( ret == 0 )
+ unlink(pjob->filename);
+ /* else print_job_end will do it for us */
+
+ out:
+ if (response)
+ ippDelete(response);
+
+ if (language)
+ cupsLangFree(language);
+
+ if (http)
+ httpClose(http);
+
+ SAFE_FREE(new_jobname);
+
+ return ret;
+}
+
+/*
+ * 'cups_queue_get()' - Get all the jobs in the print queue.
+ */
+
+static int cups_queue_get(const char *sharename,
+ enum printing_types printing_type,
+ char *lpq_command,
+ print_queue_struct **q,
+ print_status_struct *status)
+{
+ fstring printername;
+ http_t *http = NULL; /* HTTP connection to server */
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ ipp_attribute_t *attr = NULL; /* Current attribute */
+ cups_lang_t *language = NULL; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+ int qcount = 0, /* Number of active queue entries */
+ qalloc = 0; /* Number of queue entries allocated */
+ print_queue_struct *queue = NULL, /* Queue entries */
+ *temp; /* Temporary pointer for queue */
+ const char *user_name, /* job-originating-user-name attribute */
+ *job_name; /* job-name attribute */
+ int job_id; /* job-id attribute */
+ int job_k_octets; /* job-k-octets attribute */
+ time_t job_time; /* time-at-creation attribute */
+ ipp_jstate_t job_status; /* job-status attribute */
+ int job_priority; /* job-priority attribute */
+ static const char *jattrs[] = /* Requested job attributes */
+ {
+ "job-id",
+ "job-k-octets",
+ "job-name",
+ "job-originating-user-name",
+ "job-priority",
+ "job-state",
+ "time-at-creation",
+ };
+ static const char *pattrs[] = /* Requested printer attributes */
+ {
+ "printer-state",
+ "printer-state-message"
+ };
+
+ *q = NULL;
+
+ /* HACK ALERT!!! The problem with support the 'printer name'
+ option is that we key the tdb off the sharename. So we will
+ overload the lpq_command string to pass in the printername
+ (which is basically what we do for non-cups printers ... using
+ the lpq_command to get the queue listing). */
+
+ fstrcpy( printername, lpq_command );
+
+ DEBUG(5,("cups_queue_get(%s, %p, %p)\n", printername, q, status));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = cups_connect()) == NULL) {
+ goto out;
+ }
+
+ /*
+ * Generate the printer URI...
+ */
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", printername);
+
+ /*
+ * Build an IPP_GET_JOBS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ * printer-uri
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_GET_JOBS;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requested-attributes",
+ (sizeof(jattrs) / sizeof(jattrs[0])),
+ NULL, jattrs);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) == NULL) {
+ DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
+ ippErrorString(cupsLastError())));
+ goto out;
+ }
+
+ if (response->request.status.status_code >= IPP_OK_CONFLICT) {
+ DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
+ ippErrorString(response->request.status.status_code)));
+ goto out;
+ }
+
+ /*
+ * Process the jobs...
+ */
+
+ qcount = 0;
+ qalloc = 0;
+ queue = NULL;
+
+ for (attr = response->attrs; attr != NULL; attr = attr->next) {
+ /*
+ * Skip leading attributes until we hit a job...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Allocate memory as needed...
+ */
+ if (qcount >= qalloc) {
+ qalloc += 16;
+
+ queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
+
+ if (queue == NULL) {
+ DEBUG(0,("cups_queue_get: Not enough memory!"));
+ qcount = 0;
+ goto out;
+ }
+ }
+
+ temp = queue + qcount;
+ memset(temp, 0, sizeof(print_queue_struct));
+
+ /*
+ * Pull the needed attributes from this job...
+ */
+
+ job_id = 0;
+ job_priority = 50;
+ job_status = IPP_JOB_PENDING;
+ job_time = 0;
+ job_k_octets = 0;
+ user_name = NULL;
+ job_name = NULL;
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_JOB) {
+ if (attr->name == NULL) {
+ attr = attr->next;
+ break;
+ }
+
+ if (strcmp(attr->name, "job-id") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ job_id = attr->values[0].integer;
+
+ if (strcmp(attr->name, "job-k-octets") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ job_k_octets = attr->values[0].integer;
+
+ if (strcmp(attr->name, "job-priority") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ job_priority = attr->values[0].integer;
+
+ if (strcmp(attr->name, "job-state") == 0 &&
+ attr->value_tag == IPP_TAG_ENUM)
+ job_status = (ipp_jstate_t)(attr->values[0].integer);
+
+ if (strcmp(attr->name, "time-at-creation") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ job_time = attr->values[0].integer;
+
+ if (strcmp(attr->name, "job-name") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ job_name = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "job-originating-user-name") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ user_name = attr->values[0].string.text;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (user_name == NULL || job_name == NULL || job_id == 0) {
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ temp->job = job_id;
+ temp->size = job_k_octets * 1024;
+ temp->status = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
+ job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
+ job_status == IPP_JOB_HELD ? LPQ_PAUSED :
+ LPQ_PRINTING;
+ temp->priority = job_priority;
+ temp->time = job_time;
+ strncpy(temp->fs_user, user_name, sizeof(temp->fs_user) - 1);
+ strncpy(temp->fs_file, job_name, sizeof(temp->fs_file) - 1);
+
+ qcount ++;
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ response = NULL;
+
+ /*
+ * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
+ * following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ * printer-uri
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
+ request->request.op.request_id = 1;
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requested-attributes",
+ (sizeof(pattrs) / sizeof(pattrs[0])),
+ NULL, pattrs);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) == NULL) {
+ DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
+ ippErrorString(cupsLastError())));
+ *q = queue;
+ goto out;
+ }
+
+ if (response->request.status.status_code >= IPP_OK_CONFLICT) {
+ DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
+ ippErrorString(response->request.status.status_code)));
+ *q = queue;
+ goto out;
+ }
+
+ /*
+ * Get the current printer status and convert it to the SAMBA values.
+ */
+
+ if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
+ if (attr->values[0].integer == IPP_PRINTER_STOPPED)
+ status->status = LPSTAT_STOPPED;
+ else
+ status->status = LPSTAT_OK;
+ }
+
+ if ((attr = ippFindAttribute(response, "printer-state-message",
+ IPP_TAG_TEXT)) != NULL)
+ fstrcpy(status->message, attr->values[0].string.text);
+
+ /*
+ * Return the job queue...
+ */
+
+ *q = queue;
+
+ out:
+ if (response)
+ ippDelete(response);
+
+ if (language)
+ cupsLangFree(language);
+
+ if (http)
+ httpClose(http);
+
+ return qcount;
+}
+
+
+/*
+ * 'cups_queue_pause()' - Pause a print queue.
+ */
+
+static int cups_queue_pause(int snum)
+{
+ int ret = 1; /* Return value */
+ http_t *http = NULL; /* HTTP connection to server */
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ cups_lang_t *language = NULL; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+
+
+ DEBUG(5,("cups_queue_pause(%d)\n", snum));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = cups_connect()) == NULL) {
+ goto out;
+ }
+
+ /*
+ * Build an IPP_PAUSE_PRINTER request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_PAUSE_PRINTER;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
+ PRINTERNAME(snum));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, current_user_info.unix_name);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
+ if (response->request.status.status_code >= IPP_OK_CONFLICT) {
+ DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
+ ippErrorString(cupsLastError())));
+ } else {
+ ret = 0;
+ }
+ } else {
+ DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
+ ippErrorString(cupsLastError())));
+ }
+
+ out:
+ if (response)
+ ippDelete(response);
+
+ if (language)
+ cupsLangFree(language);
+
+ if (http)
+ httpClose(http);
+
+ return ret;
+}
+
+
+/*
+ * 'cups_queue_resume()' - Restart a print queue.
+ */
+
+static int cups_queue_resume(int snum)
+{
+ int ret = 1; /* Return value */
+ http_t *http = NULL; /* HTTP connection to server */
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ cups_lang_t *language = NULL; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+
+
+ DEBUG(5,("cups_queue_resume(%d)\n", snum));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = cups_connect()) == NULL) {
+ goto out;
+ }
+
+ /*
+ * Build an IPP_RESUME_PRINTER request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_RESUME_PRINTER;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
+ PRINTERNAME(snum));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, current_user_info.unix_name);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
+ if (response->request.status.status_code >= IPP_OK_CONFLICT) {
+ DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
+ ippErrorString(cupsLastError())));
+ } else {
+ ret = 0;
+ }
+ } else {
+ DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
+ ippErrorString(cupsLastError())));
+ }
+
+ out:
+ if (response)
+ ippDelete(response);
+
+ if (language)
+ cupsLangFree(language);
+
+ if (http)
+ httpClose(http);
+
+ return ret;
+}
+
+/*******************************************************************
+ * CUPS printing interface definitions...
+ ******************************************************************/
+
+struct printif cups_printif =
+{
+ PRINT_CUPS,
+ cups_queue_get,
+ cups_queue_pause,
+ cups_queue_resume,
+ cups_job_delete,
+ cups_job_pause,
+ cups_job_resume,
+ cups_job_submit,
+};
+
+bool cups_pull_comment_location(NT_PRINTER_INFO_LEVEL_2 *printer)
+{
+ http_t *http = NULL; /* HTTP connection to server */
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language = NULL; /* Default language */
+ char *name, /* printer-name attribute */
+ *info, /* printer-info attribute */
+ *location; /* printer-location attribute */
+ char uri[HTTP_MAX_URI];
+ static const char *requested[] =/* Requested attributes */
+ {
+ "printer-name",
+ "printer-info",
+ "printer-location"
+ };
+ bool ret = False;
+
+ DEBUG(5, ("pulling %s location\n", printer->sharename));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = cups_connect()) == NULL) {
+ goto out;
+ }
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://%s/printers/%s",
+ lp_cups_server(), printer->sharename);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requested-attributes",
+ (sizeof(requested) / sizeof(requested[0])),
+ NULL, requested);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) == NULL) {
+ DEBUG(0,("Unable to get printer attributes - %s\n",
+ ippErrorString(cupsLastError())));
+ goto out;
+ }
+
+ for (attr = response->attrs; attr != NULL;) {
+ /*
+ * Skip leading attributes until we hit a printer...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Pull the needed attributes from this printer...
+ */
+
+ name = NULL;
+ info = NULL;
+ location = NULL;
+
+ while ( attr && (attr->group_tag == IPP_TAG_PRINTER) ) {
+ /* Grab the comment if we don't have one */
+ if ( (strcmp(attr->name, "printer-info") == 0)
+ && (attr->value_tag == IPP_TAG_TEXT)
+ && !strlen(printer->comment) )
+ {
+ DEBUG(5,("cups_pull_comment_location: Using cups comment: %s\n",
+ attr->values[0].string.text));
+ strlcpy(printer->comment,
+ attr->values[0].string.text,
+ sizeof(printer->comment));
+ }
+
+ /* Grab the location if we don't have one */
+ if ( (strcmp(attr->name, "printer-location") == 0)
+ && (attr->value_tag == IPP_TAG_TEXT)
+ && !strlen(printer->location) )
+ {
+ DEBUG(5,("cups_pull_comment_location: Using cups location: %s\n",
+ attr->values[0].string.text));
+ fstrcpy(printer->location,attr->values[0].string.text);
+ }
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (name == NULL)
+ break;
+
+ }
+
+ ret = True;
+
+ out:
+ if (response)
+ ippDelete(response);
+
+ if (language)
+ cupsLangFree(language);
+
+ if (http)
+ httpClose(http);
+
+ return ret;
+}
+
+#else
+ /* this keeps fussy compilers happy */
+ void print_cups_dummy(void);
+ void print_cups_dummy(void) {}
+#endif /* HAVE_CUPS */
diff --git a/source3/printing/print_generic.c b/source3/printing/print_generic.c
new file mode 100644
index 0000000000..2a324fdd5c
--- /dev/null
+++ b/source3/printing/print_generic.c
@@ -0,0 +1,301 @@
+/*
+ Unix SMB/CIFS implementation.
+ printing command routines
+ Copyright (C) Andrew Tridgell 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "printing.h"
+
+extern struct current_user current_user;
+extern userdom_struct current_user_info;
+
+/****************************************************************************
+ Run a given print command
+ a null terminated list of value/substitute pairs is provided
+ for local substitution strings
+****************************************************************************/
+static int print_run_command(int snum, const char* printername, bool do_sub,
+ const char *command, int *outfd, ...)
+{
+ char *syscmd;
+ char *arg;
+ int ret;
+ TALLOC_CTX *ctx = talloc_tos();
+ va_list ap;
+ va_start(ap, outfd);
+
+ /* check for a valid system printername and valid command to run */
+
+ if ( !printername || !*printername ) {
+ va_end(ap);
+ return -1;
+ }
+
+ if (!command || !*command) {
+ va_end(ap);
+ return -1;
+ }
+
+ syscmd = talloc_strdup(ctx, command);
+ if (!syscmd) {
+ va_end(ap);
+ return -1;
+ }
+
+ while ((arg = va_arg(ap, char *))) {
+ char *value = va_arg(ap,char *);
+ syscmd = talloc_string_sub(ctx, syscmd, arg, value);
+ if (!syscmd) {
+ va_end(ap);
+ return -1;
+ }
+ }
+ va_end(ap);
+
+ syscmd = talloc_string_sub(ctx, syscmd, "%p", printername);
+ if (!syscmd) {
+ return -1;
+ }
+
+ if (do_sub && snum != -1) {
+ syscmd = talloc_sub_advanced(ctx,
+ lp_servicename(snum),
+ current_user_info.unix_name,
+ "",
+ current_user.ut.gid,
+ get_current_username(),
+ current_user_info.domain,
+ syscmd);
+ if (!syscmd) {
+ return -1;
+ }
+ }
+
+ ret = smbrun_no_sanitize(syscmd,outfd);
+
+ DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
+
+ return ret;
+}
+
+
+/****************************************************************************
+delete a print job
+****************************************************************************/
+static int generic_job_delete( const char *sharename, const char *lprm_command, struct printjob *pjob)
+{
+ fstring jobstr;
+
+ /* need to delete the spooled entry */
+ slprintf(jobstr, sizeof(jobstr)-1, "%d", pjob->sysjob);
+ return print_run_command( -1, sharename, False, lprm_command, NULL,
+ "%j", jobstr,
+ "%T", http_timestring(pjob->starttime),
+ NULL);
+}
+
+/****************************************************************************
+pause a job
+****************************************************************************/
+static int generic_job_pause(int snum, struct printjob *pjob)
+{
+ fstring jobstr;
+
+ /* need to pause the spooled entry */
+ slprintf(jobstr, sizeof(jobstr)-1, "%d", pjob->sysjob);
+ return print_run_command(snum, PRINTERNAME(snum), True,
+ lp_lppausecommand(snum), NULL,
+ "%j", jobstr,
+ NULL);
+}
+
+/****************************************************************************
+resume a job
+****************************************************************************/
+static int generic_job_resume(int snum, struct printjob *pjob)
+{
+ fstring jobstr;
+
+ /* need to pause the spooled entry */
+ slprintf(jobstr, sizeof(jobstr)-1, "%d", pjob->sysjob);
+ return print_run_command(snum, PRINTERNAME(snum), True,
+ lp_lpresumecommand(snum), NULL,
+ "%j", jobstr,
+ NULL);
+}
+
+/****************************************************************************
+ Submit a file for printing - called from print_job_end()
+****************************************************************************/
+
+static int generic_job_submit(int snum, struct printjob *pjob)
+{
+ int ret = -1;
+ char *current_directory = NULL;
+ char *print_directory = NULL;
+ char *wd = NULL;
+ char *p = NULL;
+ char *jobname = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+ fstring job_page_count, job_size;
+
+ /* we print from the directory path to give the best chance of
+ parsing the lpq output */
+ current_directory = TALLOC_ARRAY(ctx,
+ char,
+ PATH_MAX+1);
+ if (!current_directory) {
+ return -1;
+ }
+ wd = sys_getwd(current_directory);
+ if (!wd) {
+ return -1;
+ }
+
+ print_directory = talloc_strdup(ctx, pjob->filename);
+ if (!print_directory) {
+ return -1;
+ }
+ p = strrchr_m(print_directory,'/');
+ if (!p) {
+ return -1;
+ }
+ *p++ = 0;
+
+ if (chdir(print_directory) != 0) {
+ return -1;
+ }
+
+ jobname = talloc_strdup(ctx, pjob->jobname);
+ if (!jobname) {
+ ret = -1;
+ goto out;
+ }
+ jobname = talloc_string_sub(ctx, jobname, "'", "_");
+ if (!jobname) {
+ ret = -1;
+ goto out;
+ }
+ slprintf(job_page_count, sizeof(job_page_count)-1, "%d", pjob->page_count);
+ slprintf(job_size, sizeof(job_size)-1, "%lu", (unsigned long)pjob->size);
+
+ /* send it to the system spooler */
+ ret = print_run_command(snum, PRINTERNAME(snum), True,
+ lp_printcommand(snum), NULL,
+ "%s", p,
+ "%J", jobname,
+ "%f", p,
+ "%z", job_size,
+ "%c", job_page_count,
+ NULL);
+
+ out:
+
+ chdir(wd);
+ TALLOC_FREE(current_directory);
+ return ret;
+}
+
+
+/****************************************************************************
+get the current list of queued jobs
+****************************************************************************/
+static int generic_queue_get(const char *printer_name,
+ enum printing_types printing_type,
+ char *lpq_command,
+ print_queue_struct **q,
+ print_status_struct *status)
+{
+ char **qlines;
+ int fd;
+ int numlines, i, qcount;
+ print_queue_struct *queue = NULL;
+
+ /* never do substitution when running the 'lpq command' since we can't
+ get it rigt when using the background update daemon. Make the caller
+ do it before passing off the command string to us here. */
+
+ print_run_command(-1, printer_name, False, lpq_command, &fd, NULL);
+
+ if (fd == -1) {
+ DEBUG(5,("generic_queue_get: Can't read print queue status for printer %s\n",
+ printer_name ));
+ return 0;
+ }
+
+ numlines = 0;
+ qlines = fd_lines_load(fd, &numlines,0);
+ close(fd);
+
+ /* turn the lpq output into a series of job structures */
+ qcount = 0;
+ ZERO_STRUCTP(status);
+ if (numlines && qlines) {
+ queue = SMB_MALLOC_ARRAY(print_queue_struct, numlines+1);
+ if (!queue) {
+ file_lines_free(qlines);
+ *q = NULL;
+ return 0;
+ }
+ memset(queue, '\0', sizeof(print_queue_struct)*(numlines+1));
+
+ for (i=0; i<numlines; i++) {
+ /* parse the line */
+ if (parse_lpq_entry(printing_type,qlines[i],
+ &queue[qcount],status,qcount==0)) {
+ qcount++;
+ }
+ }
+ }
+
+ file_lines_free(qlines);
+ *q = queue;
+ return qcount;
+}
+
+/****************************************************************************
+ pause a queue
+****************************************************************************/
+static int generic_queue_pause(int snum)
+{
+ return print_run_command(snum, PRINTERNAME(snum), True, lp_queuepausecommand(snum), NULL, NULL);
+}
+
+/****************************************************************************
+ resume a queue
+****************************************************************************/
+static int generic_queue_resume(int snum)
+{
+ return print_run_command(snum, PRINTERNAME(snum), True, lp_queueresumecommand(snum), NULL, NULL);
+}
+
+/****************************************************************************
+ * Generic printing interface definitions...
+ ***************************************************************************/
+
+struct printif generic_printif =
+{
+ DEFAULT_PRINTING,
+ generic_queue_get,
+ generic_queue_pause,
+ generic_queue_resume,
+ generic_job_delete,
+ generic_job_pause,
+ generic_job_resume,
+ generic_job_submit,
+};
+
diff --git a/source3/printing/print_iprint.c b/source3/printing/print_iprint.c
new file mode 100644
index 0000000000..b038f8d1fe
--- /dev/null
+++ b/source3/printing/print_iprint.c
@@ -0,0 +1,1240 @@
+/*
+ * Support code for Novell iPrint using the Common UNIX Printing
+ * System ("CUPS") libraries
+ *
+ * Copyright 1999-2003 by Michael R Sweet.
+ * Portions Copyright 2005 by Joel J. Smith.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "printing.h"
+
+#ifdef HAVE_IPRINT
+#include <cups/cups.h>
+#include <cups/language.h>
+
+#define OPERATION_NOVELL_LIST_PRINTERS 0x401A
+#define OPERATION_NOVELL_MGMT 0x401C
+#define NOVELL_SERVER_SYSNAME "sysname="
+#define NOVELL_SERVER_SYSNAME_NETWARE "NetWare IA32"
+#define NOVELL_SERVER_VERSION_STRING "iprintserverversion="
+#define NOVELL_SERVER_VERSION_OES_SP1 33554432
+
+/*
+ * 'iprint_passwd_cb()' - The iPrint password callback...
+ */
+
+static const char * /* O - Password or NULL */
+iprint_passwd_cb(const char *prompt) /* I - Prompt */
+{
+ /*
+ * Always return NULL to indicate that no password is available...
+ */
+
+ return (NULL);
+}
+
+static const char *iprint_server(void)
+{
+ if ((lp_iprint_server() != NULL) && (strlen(lp_iprint_server()) > 0)) {
+ DEBUG(10, ("iprint server explicitly set to %s\n",
+ lp_iprint_server()));
+ return lp_iprint_server();
+ }
+
+ DEBUG(10, ("iprint server left to default %s\n", cupsServer()));
+ return cupsServer();
+}
+
+/*
+ * Pass in an already connected http_t*
+ * Returns the server version if one can be found, multiplied by
+ * -1 for all NetWare versions. Returns 0 if a server version
+ * cannot be determined
+ */
+
+static int iprint_get_server_version(http_t *http, char* serviceUri)
+{
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language = NULL; /* Default language */
+ char *ver; /* server version pointer */
+ char *vertmp; /* server version tmp pointer */
+ int serverVersion = 0; /* server version */
+ char *os; /* server os */
+ int osFlag = 0; /* 0 for NetWare, 1 for anything else */
+ char *temp; /* pointer for string manipulation */
+
+ /*
+ * Build an OPERATION_NOVELL_MGMT("get-server-version") request,
+ * which requires the following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * operation-name
+ * service-uri
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = (ipp_op_t)OPERATION_NOVELL_MGMT;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, "utf-8");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "service-uri", NULL, serviceUri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "operation-name", NULL, "get-server-version");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if (((response = cupsDoRequest(http, request, "/ipp/")) == NULL) ||
+ (response->request.status.status_code >= IPP_OK_CONFLICT))
+ goto out;
+
+ if (((attr = ippFindAttribute(response, "server-version",
+ IPP_TAG_STRING)) != NULL)) {
+ if ((ver = strstr(attr->values[0].string.text,
+ NOVELL_SERVER_VERSION_STRING)) != NULL) {
+ ver += strlen(NOVELL_SERVER_VERSION_STRING);
+ /*
+ * Strangely, libcups stores a IPP_TAG_STRING (octet
+ * string) as a null-terminated string with no length
+ * even though it could be binary data with nulls in
+ * it. Luckily, in this case the value is not binary.
+ */
+ serverVersion = strtol(ver, &vertmp, 10);
+
+ /* Check for not found, overflow or negative version */
+ if ((ver == vertmp) || (serverVersion < 0))
+ serverVersion = 0;
+ }
+
+ if ((os = strstr(attr->values[0].string.text,
+ NOVELL_SERVER_SYSNAME)) != NULL) {
+ os += strlen(NOVELL_SERVER_SYSNAME);
+ if ((temp = strchr(os,'<')) != NULL)
+ *temp = '\0';
+ if (strcmp(os,NOVELL_SERVER_SYSNAME_NETWARE))
+ osFlag = 1; /* 1 for non-NetWare systems */
+ }
+ }
+
+ out:
+ if (response)
+ ippDelete(response);
+
+ if (language)
+ cupsLangFree(language);
+
+ if (osFlag == 0)
+ serverVersion *= -1;
+
+ return serverVersion;
+}
+
+
+static int iprint_cache_add_printer(http_t *http,
+ int reqId,
+ char* url)
+{
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language = NULL; /* Default language */
+ char *name, /* printer-name attribute */
+ *info, /* printer-info attribute */
+ smb_enabled, /* smb-enabled attribute */
+ secure; /* security-enabled attrib. */
+
+ char *httpPath; /* path portion of the printer-uri */
+
+ static const char *pattrs[] = /* Requested printer attributes */
+ {
+ "printer-name",
+ "security-enabled",
+ "printer-info",
+ "smb-enabled"
+ };
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
+ request->request.op.request_id = reqId;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, "utf-8");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, url);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ (sizeof(pattrs) / sizeof(pattrs[0])),
+ NULL, pattrs);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((httpPath = strstr(url,"://")) == NULL ||
+ (httpPath = strchr(httpPath+3,'/')) == NULL)
+ {
+ ippDelete(request);
+ request = NULL;
+ goto out;
+ }
+
+ if ((response = cupsDoRequest(http, request, httpPath)) == NULL) {
+ ipp_status_t lastErr = cupsLastError();
+
+ /*
+ * Ignore printers that cannot be queried without credentials
+ */
+ if (lastErr == IPP_FORBIDDEN ||
+ lastErr == IPP_NOT_AUTHENTICATED ||
+ lastErr == IPP_NOT_AUTHORIZED)
+ goto out;
+
+ DEBUG(0,("Unable to get printer list - %s\n",
+ ippErrorString(lastErr)));
+ goto out;
+ }
+
+ for (attr = response->attrs; attr != NULL;) {
+ /*
+ * Skip leading attributes until we hit a printer...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Pull the needed attributes from this printer...
+ */
+
+ name = NULL;
+ info = NULL;
+ smb_enabled= 1;
+ secure = 0;
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
+ if (strcmp(attr->name, "printer-name") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ name = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "printer-info") == 0 &&
+ (attr->value_tag == IPP_TAG_TEXT ||
+ attr->value_tag == IPP_TAG_TEXTLANG))
+ info = attr->values[0].string.text;
+
+ /*
+ * If the smb-enabled attribute is present and the
+ * value is set to 0, don't show the printer.
+ * If the attribute is not present, assume that the
+ * printer should show up
+ */
+ if (!strcmp(attr->name, "smb-enabled") &&
+ ((attr->value_tag == IPP_TAG_INTEGER &&
+ !attr->values[0].integer) ||
+ (attr->value_tag == IPP_TAG_BOOLEAN &&
+ !attr->values[0].boolean)))
+ smb_enabled = 0;
+
+ /*
+ * If the security-enabled attribute is present and the
+ * value is set to 1, don't show the printer.
+ * If the attribute is not present, assume that the
+ * printer should show up
+ */
+ if (!strcmp(attr->name, "security-enabled") &&
+ ((attr->value_tag == IPP_TAG_INTEGER &&
+ attr->values[0].integer) ||
+ (attr->value_tag == IPP_TAG_BOOLEAN &&
+ attr->values[0].boolean)))
+ secure = 1;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ * Make sure the printer is not a secure printer
+ * and make sure smb printing hasn't been explicitly
+ * disabled for the printer
+ */
+
+ if (name != NULL && !secure && smb_enabled)
+ pcap_cache_add(name, info);
+ }
+
+ out:
+ if (response)
+ ippDelete(response);
+ return(0);
+}
+
+bool iprint_cache_reload(void)
+{
+ http_t *http = NULL; /* HTTP connection to server */
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language = NULL; /* Default language */
+ int i;
+ bool ret = False;
+
+ DEBUG(5, ("reloading iprint printcap cache\n"));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(iprint_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
+ DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
+ iprint_server(), strerror(errno)));
+ goto out;
+ }
+
+ /*
+ * Build a OPERATION_NOVELL_LIST_PRINTERS request, which requires the following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id =
+ (ipp_op_t)OPERATION_NOVELL_LIST_PRINTERS;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, "utf-8");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "ipp-server", NULL, "ippSrvr");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/ipp")) == NULL) {
+ DEBUG(0,("Unable to get printer list - %s\n",
+ ippErrorString(cupsLastError())));
+ goto out;
+ }
+
+ for (attr = response->attrs; attr != NULL;) {
+ /*
+ * Skip leading attributes until we hit a printer...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Pull the needed attributes from this printer...
+ */
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
+ {
+ if (strcmp(attr->name, "printer-name") == 0 &&
+ (attr->value_tag == IPP_TAG_URI ||
+ attr->value_tag == IPP_TAG_NAME ||
+ attr->value_tag == IPP_TAG_TEXT ||
+ attr->value_tag == IPP_TAG_NAMELANG ||
+ attr->value_tag == IPP_TAG_TEXTLANG))
+ {
+ for (i = 0; i<attr->num_values; i++)
+ {
+ char *url = attr->values[i].string.text;
+ if (!url || !strlen(url))
+ continue;
+ iprint_cache_add_printer(http, i+2, url);
+ }
+ }
+ attr = attr->next;
+ }
+ }
+
+ ret = True;
+
+ out:
+ if (response)
+ ippDelete(response);
+
+ if (language)
+ cupsLangFree(language);
+
+ if (http)
+ httpClose(http);
+
+ return ret;
+}
+
+
+/*
+ * 'iprint_job_delete()' - Delete a job.
+ */
+
+static int iprint_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob)
+{
+ int ret = 1; /* Return value */
+ http_t *http = NULL; /* HTTP connection to server */
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ cups_lang_t *language = NULL; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+ char httpPath[HTTP_MAX_URI]; /* path portion of the printer-uri */
+
+
+ DEBUG(5,("iprint_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(iprint_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
+ DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
+ iprint_server(), strerror(errno)));
+ goto out;
+ }
+
+ /*
+ * Build an IPP_CANCEL_JOB request, which uses the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * job-id
+ * requesting-user-name
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_CANCEL_JOB;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, "utf-8");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), sharename);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
+
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, pjob->user);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", sharename);
+
+ if ((response = cupsDoRequest(http, request, httpPath)) != NULL) {
+ if (response->request.status.status_code >= IPP_OK_CONFLICT) {
+ DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+ } else {
+ ret = 0;
+ }
+ } else {
+ DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+ }
+
+ out:
+ if (response)
+ ippDelete(response);
+
+ if (language)
+ cupsLangFree(language);
+
+ if (http)
+ httpClose(http);
+
+ return ret;
+}
+
+
+/*
+ * 'iprint_job_pause()' - Pause a job.
+ */
+
+static int iprint_job_pause(int snum, struct printjob *pjob)
+{
+ int ret = 1; /* Return value */
+ http_t *http = NULL; /* HTTP connection to server */
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ cups_lang_t *language = NULL; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+ char httpPath[HTTP_MAX_URI]; /* path portion of the printer-uri */
+
+
+ DEBUG(5,("iprint_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(iprint_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
+ DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
+ iprint_server(), strerror(errno)));
+ goto out;
+ }
+
+ /*
+ * Build an IPP_HOLD_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * job-id
+ * requesting-user-name
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_HOLD_JOB;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, "utf-8");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), PRINTERNAME(snum));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
+
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, pjob->user);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", PRINTERNAME(snum));
+
+ if ((response = cupsDoRequest(http, request, httpPath)) != NULL) {
+ if (response->request.status.status_code >= IPP_OK_CONFLICT) {
+ DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+ } else {
+ ret = 0;
+ }
+ } else {
+ DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+ }
+
+ out:
+ if (response)
+ ippDelete(response);
+
+ if (language)
+ cupsLangFree(language);
+
+ if (http)
+ httpClose(http);
+
+ return ret;
+}
+
+
+/*
+ * 'iprint_job_resume()' - Resume a paused job.
+ */
+
+static int iprint_job_resume(int snum, struct printjob *pjob)
+{
+ int ret = 1; /* Return value */
+ http_t *http = NULL; /* HTTP connection to server */
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ cups_lang_t *language = NULL; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+ char httpPath[HTTP_MAX_URI]; /* path portion of the printer-uri */
+
+
+ DEBUG(5,("iprint_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(iprint_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
+ DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
+ iprint_server(), strerror(errno)));
+ goto out;
+ }
+
+ /*
+ * Build an IPP_RELEASE_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * job-id
+ * requesting-user-name
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_RELEASE_JOB;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, "utf-8");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), PRINTERNAME(snum));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
+
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, pjob->user);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", PRINTERNAME(snum));
+
+ if ((response = cupsDoRequest(http, request, httpPath)) != NULL) {
+ if (response->request.status.status_code >= IPP_OK_CONFLICT) {
+ DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+ } else {
+ ret = 0;
+ }
+ } else {
+ DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+ }
+
+ out:
+ if (response)
+ ippDelete(response);
+
+ if (language)
+ cupsLangFree(language);
+
+ if (http)
+ httpClose(http);
+
+ return ret;
+}
+
+
+/*
+ * 'iprint_job_submit()' - Submit a job for printing.
+ */
+
+static int iprint_job_submit(int snum, struct printjob *pjob)
+{
+ int ret = 1; /* Return value */
+ http_t *http = NULL; /* HTTP connection to server */
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language = NULL; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+ const char *clientname = NULL; /* hostname of client for job-originating-host attribute */
+ char addr[INET6_ADDRSTRLEN];
+
+ DEBUG(5,("iprint_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(iprint_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
+ DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
+ iprint_server(), strerror(errno)));
+ goto out;
+ }
+
+ /*
+ * Build an IPP_PRINT_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ * [document-data]
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_PRINT_JOB;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, "utf-8");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), PRINTERNAME(snum));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, pjob->user);
+
+ clientname = client_name(get_client_fd());
+ if (strcmp(clientname, "UNKNOWN") == 0) {
+ clientname = client_addr(get_client_fd(),addr,sizeof(addr));
+ }
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "job-originating-host-name", NULL,
+ clientname);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
+ pjob->jobname);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ slprintf(uri, sizeof(uri) - 1, "/ipp/%s", PRINTERNAME(snum));
+
+ if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
+ if (response->request.status.status_code >= IPP_OK_CONFLICT) {
+ DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum),
+ ippErrorString(cupsLastError())));
+ } else {
+ ret = 0;
+ }
+ } else {
+ DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum),
+ ippErrorString(cupsLastError())));
+ }
+
+ if ( ret == 0 )
+ unlink(pjob->filename);
+ /* else print_job_end will do it for us */
+
+ if ( ret == 0 ) {
+
+ attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER);
+ if (attr != NULL && attr->group_tag == IPP_TAG_JOB)
+ {
+ pjob->sysjob = attr->values[0].integer;
+ }
+ }
+
+ out:
+ if (response)
+ ippDelete(response);
+
+ if (language)
+ cupsLangFree(language);
+
+ if (http)
+ httpClose(http);
+
+ return ret;
+}
+
+/*
+ * 'iprint_queue_get()' - Get all the jobs in the print queue.
+ */
+
+static int iprint_queue_get(const char *sharename,
+ enum printing_types printing_type,
+ char *lpq_command,
+ print_queue_struct **q,
+ print_status_struct *status)
+{
+ fstring printername;
+ http_t *http = NULL; /* HTTP connection to server */
+ ipp_t *request = NULL, /* IPP Request */
+ *response = NULL; /* IPP Response */
+ ipp_attribute_t *attr = NULL; /* Current attribute */
+ cups_lang_t *language = NULL; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+ char serviceUri[HTTP_MAX_URI]; /* service-uri attribute */
+ char httpPath[HTTP_MAX_URI]; /* path portion of the uri */
+ int jobUseUnixTime = 0; /* Whether job times should
+ * be assumed to be Unix time */
+ int qcount = 0, /* Number of active queue entries */
+ qalloc = 0; /* Number of queue entries allocated */
+ print_queue_struct *queue = NULL, /* Queue entries */
+ *temp; /* Temporary pointer for queue */
+ const char *user_name, /* job-originating-user-name attribute */
+ *job_name; /* job-name attribute */
+ int job_id; /* job-id attribute */
+ int job_k_octets; /* job-k-octets attribute */
+ time_t job_time; /* time-at-creation attribute */
+ time_t printer_current_time = 0; /* printer's current time */
+ time_t printer_up_time = 0; /* printer's uptime */
+ ipp_jstate_t job_status; /* job-status attribute */
+ int job_priority; /* job-priority attribute */
+ static const char *jattrs[] = /* Requested job attributes */
+ {
+ "job-id",
+ "job-k-octets",
+ "job-name",
+ "job-originating-user-name",
+ "job-priority",
+ "job-state",
+ "time-at-creation",
+ };
+ static const char *pattrs[] = /* Requested printer attributes */
+ {
+ "printer-state",
+ "printer-state-message",
+ "printer-current-time",
+ "printer-up-time"
+ };
+
+ *q = NULL;
+
+ /* HACK ALERT!!! The porblem with support the 'printer name'
+ option is that we key the tdb off the sharename. So we will
+ overload the lpq_command string to pass in the printername
+ (which is basically what we do for non-cups printers ... using
+ the lpq_command to get the queue listing). */
+
+ fstrcpy( printername, lpq_command );
+
+ DEBUG(5,("iprint_queue_get(%s, %p, %p)\n", printername, q, status));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(iprint_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
+ DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
+ iprint_server(), strerror(errno)));
+ goto out;
+ }
+
+ /*
+ * Generate the printer URI and the service URI that goes with it...
+ */
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), printername);
+ slprintf(serviceUri, sizeof(serviceUri) - 1, "ipp://%s/ipp/", iprint_server());
+
+ /*
+ * For Linux iPrint servers from OES SP1 on, the iPrint server
+ * uses Unix time for job start times unless it detects the iPrint
+ * client in an http User-Agent header. (This was done to accomodate
+ * CUPS broken behavior. According to RFC 2911, section 4.3.14, job
+ * start times are supposed to be relative to how long the printer has
+ * been up.) Since libcups doesn't allow us to set that header before
+ * the request is sent, this ugly hack allows us to detect the server
+ * version and decide how to interpret the job time.
+ */
+ if (iprint_get_server_version(http, serviceUri) >=
+ NOVELL_SERVER_VERSION_OES_SP1)
+ jobUseUnixTime = 1;
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
+ request->request.op.request_id = 2;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, "utf-8");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ (sizeof(pattrs) / sizeof(pattrs[0])),
+ NULL, pattrs);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", printername);
+
+ if ((response = cupsDoRequest(http, request, httpPath)) == NULL) {
+ DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
+ ippErrorString(cupsLastError())));
+ *q = queue;
+ goto out;
+ }
+
+ if (response->request.status.status_code >= IPP_OK_CONFLICT) {
+ DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
+ ippErrorString(response->request.status.status_code)));
+ *q = queue;
+ goto out;
+ }
+
+ /*
+ * Get the current printer status and convert it to the SAMBA values.
+ */
+
+ if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
+ if (attr->values[0].integer == IPP_PRINTER_STOPPED)
+ status->status = LPSTAT_STOPPED;
+ else
+ status->status = LPSTAT_OK;
+ }
+
+ if ((attr = ippFindAttribute(response, "printer-state-message",
+ IPP_TAG_TEXT)) != NULL)
+ fstrcpy(status->message, attr->values[0].string.text);
+
+ if ((attr = ippFindAttribute(response, "printer-current-time",
+ IPP_TAG_DATE)) != NULL)
+ printer_current_time = ippDateToTime(attr->values[0].date);
+
+ if ((attr = ippFindAttribute(response, "printer-up-time",
+ IPP_TAG_INTEGER)) != NULL)
+ printer_up_time = attr->values[0].integer;
+
+ ippDelete(response);
+ response = NULL;
+
+ /*
+ * Build an IPP_GET_JOBS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ * printer-uri
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_GET_JOBS;
+ request->request.op.request_id = 3;
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, "utf-8");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ (sizeof(jattrs) / sizeof(jattrs[0])),
+ NULL, jattrs);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", printername);
+
+ if ((response = cupsDoRequest(http, request, httpPath)) == NULL) {
+ DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
+ ippErrorString(cupsLastError())));
+ goto out;
+ }
+
+ if (response->request.status.status_code >= IPP_OK_CONFLICT) {
+ DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
+ ippErrorString(response->request.status.status_code)));
+ goto out;
+ }
+
+ /*
+ * Process the jobs...
+ */
+
+ qcount = 0;
+ qalloc = 0;
+ queue = NULL;
+
+ for (attr = response->attrs; attr != NULL; attr = attr->next) {
+ /*
+ * Skip leading attributes until we hit a job...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Allocate memory as needed...
+ */
+ if (qcount >= qalloc) {
+ qalloc += 16;
+
+ queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
+
+ if (queue == NULL) {
+ DEBUG(0,("iprint_queue_get: Not enough memory!"));
+ qcount = 0;
+ goto out;
+ }
+ }
+
+ temp = queue + qcount;
+ memset(temp, 0, sizeof(print_queue_struct));
+
+ /*
+ * Pull the needed attributes from this job...
+ */
+
+ job_id = 0;
+ job_priority = 50;
+ job_status = IPP_JOB_PENDING;
+ job_time = 0;
+ job_k_octets = 0;
+ user_name = NULL;
+ job_name = NULL;
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_JOB) {
+ if (attr->name == NULL) {
+ attr = attr->next;
+ break;
+ }
+
+ if (strcmp(attr->name, "job-id") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ job_id = attr->values[0].integer;
+
+ if (strcmp(attr->name, "job-k-octets") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ job_k_octets = attr->values[0].integer;
+
+ if (strcmp(attr->name, "job-priority") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ job_priority = attr->values[0].integer;
+
+ if (strcmp(attr->name, "job-state") == 0 &&
+ attr->value_tag == IPP_TAG_ENUM)
+ job_status = (ipp_jstate_t)(attr->values[0].integer);
+
+ if (strcmp(attr->name, "time-at-creation") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ {
+ /*
+ * If jobs times are in Unix time, the accuracy of the job
+ * start time depends upon the iPrint server's time being
+ * set correctly. Otherwise, the accuracy depends upon
+ * the Samba server's time being set correctly
+ */
+
+ if (jobUseUnixTime)
+ job_time = attr->values[0].integer;
+ else
+ job_time = time(NULL) - printer_up_time + attr->values[0].integer;
+ }
+
+ if (strcmp(attr->name, "job-name") == 0 &&
+ (attr->value_tag == IPP_TAG_NAMELANG ||
+ attr->value_tag == IPP_TAG_NAME))
+ job_name = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "job-originating-user-name") == 0 &&
+ (attr->value_tag == IPP_TAG_NAMELANG ||
+ attr->value_tag == IPP_TAG_NAME))
+ user_name = attr->values[0].string.text;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (user_name == NULL || job_name == NULL || job_id == 0) {
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ temp->job = job_id;
+ temp->size = job_k_octets * 1024;
+ temp->status = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
+ job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
+ job_status == IPP_JOB_HELD ? LPQ_PAUSED :
+ LPQ_PRINTING;
+ temp->priority = job_priority;
+ temp->time = job_time;
+ strncpy(temp->fs_user, user_name, sizeof(temp->fs_user) - 1);
+ strncpy(temp->fs_file, job_name, sizeof(temp->fs_file) - 1);
+
+ qcount ++;
+
+ if (attr == NULL)
+ break;
+ }
+
+ /*
+ * Return the job queue...
+ */
+
+ *q = queue;
+
+ out:
+ if (response)
+ ippDelete(response);
+
+ if (language)
+ cupsLangFree(language);
+
+ if (http)
+ httpClose(http);
+
+ return qcount;
+}
+
+
+/*
+ * 'iprint_queue_pause()' - Pause a print queue.
+ */
+
+static int iprint_queue_pause(int snum)
+{
+ return(-1); /* Not supported without credentials */
+}
+
+
+/*
+ * 'iprint_queue_resume()' - Restart a print queue.
+ */
+
+static int iprint_queue_resume(int snum)
+{
+ return(-1); /* Not supported without credentials */
+}
+
+/*******************************************************************
+ * iPrint printing interface definitions...
+ ******************************************************************/
+
+struct printif iprint_printif =
+{
+ PRINT_IPRINT,
+ iprint_queue_get,
+ iprint_queue_pause,
+ iprint_queue_resume,
+ iprint_job_delete,
+ iprint_job_pause,
+ iprint_job_resume,
+ iprint_job_submit,
+};
+
+#else
+ /* this keeps fussy compilers happy */
+ void print_iprint_dummy(void);
+ void print_iprint_dummy(void) {}
+#endif /* HAVE_IPRINT */
diff --git a/source3/printing/print_svid.c b/source3/printing/print_svid.c
new file mode 100644
index 0000000000..7e91d3a677
--- /dev/null
+++ b/source3/printing/print_svid.c
@@ -0,0 +1,127 @@
+/*
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * 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"
+
+#if defined(SYSV) || defined(HPUX)
+bool sysv_cache_reload(void)
+{
+ char **lines;
+ int i;
+
+#if defined(HPUX)
+ DEBUG(5, ("reloading hpux printcap cache\n"));
+#else
+ DEBUG(5, ("reloading sysv printcap cache\n"));
+#endif
+
+ if ((lines = file_lines_pload("/usr/bin/lpstat -v", NULL)) == NULL)
+ {
+#if defined(HPUX)
+
+ /*
+ * if "lpstat -v" is NULL then we check if schedular is running if it is
+ * that means no printers are added on the HP-UX system, if schedular is not
+ * running we display reload error.
+ */
+
+ char **scheduler;
+ scheduler = file_lines_pload("/usr/bin/lpstat -r", NULL);
+ if(!strcmp(*scheduler,"scheduler is running")){
+ DEBUG(3,("No Printers found!!!\n"));
+ file_lines_free(scheduler);
+ return True;
+ }
+ else{
+ DEBUG(3,("Scheduler is not running!!!\n"));
+ file_lines_free(scheduler);
+ return False;
+ }
+#else
+ DEBUG(3,("No Printers found!!!\n"));
+ return False;
+#endif
+ }
+
+ for (i = 0; lines[i]; i++) {
+ char *name, *tmp;
+ char *buf = lines[i];
+
+ /* eat "system/device for " */
+ if (((tmp = strchr_m(buf, ' ')) == NULL) ||
+ ((tmp = strchr_m(++tmp, ' ')) == NULL))
+ continue;
+
+ /*
+ * In case we're only at the "for ".
+ */
+
+ if(!strncmp("for ", ++tmp, 4)) {
+ tmp=strchr_m(tmp, ' ');
+ tmp++;
+ }
+
+ /* Eat whitespace. */
+
+ while(*tmp == ' ')
+ ++tmp;
+
+ /*
+ * On HPUX there is an extra line that can be ignored.
+ * d.thibadeau 2001/08/09
+ */
+ if(!strncmp("remote to", tmp, 9))
+ continue;
+
+ name = tmp;
+
+ /* truncate the ": ..." */
+ if ((tmp = strchr_m(name, ':')) != NULL)
+ *tmp = '\0';
+
+ /* add it to the cache */
+ if (!pcap_cache_add(name, NULL)) {
+ file_lines_free(lines);
+ return False;
+ }
+ }
+
+ file_lines_free(lines);
+ return True;
+}
+
+#else
+/* this keeps fussy compilers happy */
+ void print_svid_dummy(void);
+ void print_svid_dummy(void) {}
+#endif
diff --git a/source3/printing/printfsp.c b/source3/printing/printfsp.c
new file mode 100644
index 0000000000..c6749226fd
--- /dev/null
+++ b/source3/printing/printfsp.c
@@ -0,0 +1,122 @@
+/*
+ Unix SMB/CIFS implementation.
+ printing backend routines for smbd - using files_struct rather
+ than only snum
+ Copyright (C) Andrew Tridgell 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/***************************************************************************
+open a print file and setup a fsp for it. This is a wrapper around
+print_job_start().
+***************************************************************************/
+
+NTSTATUS print_fsp_open(connection_struct *conn, const char *fname,
+ uint16_t current_vuid, files_struct **result)
+{
+ int jobid;
+ SMB_STRUCT_STAT sbuf;
+ files_struct *fsp;
+ fstring name;
+ NTSTATUS status;
+
+ status = file_new(conn, &fsp);
+ if(!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ fstrcpy( name, "Remote Downlevel Document");
+ if (fname) {
+ const char *p = strrchr(fname, '/');
+ fstrcat(name, " ");
+ if (!p) {
+ p = fname;
+ }
+ fstrcat(name, p);
+ }
+
+ jobid = print_job_start(conn->server_info, SNUM(conn), name, NULL);
+ if (jobid == -1) {
+ status = map_nt_error_from_unix(errno);
+ file_free(fsp);
+ return status;
+ }
+
+ /* Convert to RAP id. */
+ fsp->rap_print_jobid = pjobid_to_rap(lp_const_servicename(SNUM(conn)), jobid);
+ if (fsp->rap_print_jobid == 0) {
+ /* We need to delete the entry in the tdb. */
+ pjob_delete(lp_const_servicename(SNUM(conn)), jobid);
+ file_free(fsp);
+ return NT_STATUS_ACCESS_DENIED; /* No errno around here */
+ }
+
+ /* setup a full fsp */
+ fsp->fh->fd = print_job_fd(lp_const_servicename(SNUM(conn)),jobid);
+ GetTimeOfDay(&fsp->open_time);
+ fsp->vuid = current_vuid;
+ fsp->fh->pos = -1;
+ fsp->can_lock = True;
+ fsp->can_read = False;
+ fsp->access_mask = FILE_GENERIC_WRITE;
+ fsp->can_write = True;
+ fsp->print_file = True;
+ fsp->modified = False;
+ fsp->oplock_type = NO_OPLOCK;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+ fsp->is_directory = False;
+ string_set(&fsp->fsp_name,print_job_fname(lp_const_servicename(SNUM(conn)),jobid));
+ fsp->wcp = NULL;
+ SMB_VFS_FSTAT(fsp, &sbuf);
+ fsp->mode = sbuf.st_mode;
+ fsp->file_id = vfs_file_id_from_sbuf(conn, &sbuf);
+
+ conn->num_files_open++;
+
+ *result = fsp;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Print a file - called on closing the file.
+****************************************************************************/
+
+void print_fsp_end(files_struct *fsp, enum file_close_type close_type)
+{
+ uint32 jobid;
+ fstring sharename;
+
+ if (fsp->fh->private_options & FILE_DELETE_ON_CLOSE) {
+ /*
+ * Truncate the job. print_job_end will take
+ * care of deleting it for us. JRA.
+ */
+ sys_ftruncate(fsp->fh->fd, 0);
+ }
+
+ if (fsp->fsp_name) {
+ string_free(&fsp->fsp_name);
+ }
+
+ if (!rap_to_pjobid(fsp->rap_print_jobid, sharename, &jobid)) {
+ DEBUG(3,("print_fsp_end: Unable to convert RAP jobid %u to print jobid.\n",
+ (unsigned int)fsp->rap_print_jobid ));
+ return;
+ }
+
+ print_job_end(SNUM(fsp->conn),jobid, close_type);
+}
diff --git a/source3/printing/printing.c b/source3/printing/printing.c
new file mode 100644
index 0000000000..1016e6183d
--- /dev/null
+++ b/source3/printing/printing.c
@@ -0,0 +1,2888 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ printing backend routines
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Jeremy Allison 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "printing.h"
+
+extern SIG_ATOMIC_T got_sig_term;
+extern SIG_ATOMIC_T reload_after_sighup;
+extern struct current_user current_user;
+extern userdom_struct current_user_info;
+
+/* Current printer interface */
+static bool remove_from_jobs_changed(const char* sharename, uint32 jobid);
+
+/*
+ the printing backend revolves around a tdb database that stores the
+ SMB view of the print queue
+
+ The key for this database is a jobid - a internally generated number that
+ uniquely identifies a print job
+
+ reading the print queue involves two steps:
+ - possibly running lpq and updating the internal database from that
+ - reading entries from the database
+
+ jobids are assigned when a job starts spooling.
+*/
+
+static TDB_CONTEXT *rap_tdb;
+static uint16 next_rap_jobid;
+struct rap_jobid_key {
+ fstring sharename;
+ uint32 jobid;
+};
+
+/***************************************************************************
+ Nightmare. LANMAN jobid's are 16 bit numbers..... We must map them to 32
+ bit RPC jobids.... JRA.
+***************************************************************************/
+
+uint16 pjobid_to_rap(const char* sharename, uint32 jobid)
+{
+ uint16 rap_jobid;
+ TDB_DATA data, key;
+ struct rap_jobid_key jinfo;
+ uint8 buf[2];
+
+ DEBUG(10,("pjobid_to_rap: called.\n"));
+
+ if (!rap_tdb) {
+ /* Create the in-memory tdb. */
+ rap_tdb = tdb_open_log(NULL, 0, TDB_INTERNAL, (O_RDWR|O_CREAT), 0644);
+ if (!rap_tdb)
+ return 0;
+ }
+
+ ZERO_STRUCT( jinfo );
+ fstrcpy( jinfo.sharename, sharename );
+ jinfo.jobid = jobid;
+ key.dptr = (uint8 *)&jinfo;
+ key.dsize = sizeof(jinfo);
+
+ data = tdb_fetch(rap_tdb, key);
+ if (data.dptr && data.dsize == sizeof(uint16)) {
+ rap_jobid = SVAL(data.dptr, 0);
+ SAFE_FREE(data.dptr);
+ DEBUG(10,("pjobid_to_rap: jobid %u maps to RAP jobid %u\n",
+ (unsigned int)jobid, (unsigned int)rap_jobid));
+ return rap_jobid;
+ }
+ SAFE_FREE(data.dptr);
+ /* Not found - create and store mapping. */
+ rap_jobid = ++next_rap_jobid;
+ if (rap_jobid == 0)
+ rap_jobid = ++next_rap_jobid;
+ SSVAL(buf,0,rap_jobid);
+ data.dptr = buf;
+ data.dsize = sizeof(rap_jobid);
+ tdb_store(rap_tdb, key, data, TDB_REPLACE);
+ tdb_store(rap_tdb, data, key, TDB_REPLACE);
+
+ DEBUG(10,("pjobid_to_rap: created jobid %u maps to RAP jobid %u\n",
+ (unsigned int)jobid, (unsigned int)rap_jobid));
+ return rap_jobid;
+}
+
+bool rap_to_pjobid(uint16 rap_jobid, fstring sharename, uint32 *pjobid)
+{
+ TDB_DATA data, key;
+ uint8 buf[2];
+
+ DEBUG(10,("rap_to_pjobid called.\n"));
+
+ if (!rap_tdb)
+ return False;
+
+ SSVAL(buf,0,rap_jobid);
+ key.dptr = buf;
+ key.dsize = sizeof(rap_jobid);
+ data = tdb_fetch(rap_tdb, key);
+ if ( data.dptr && data.dsize == sizeof(struct rap_jobid_key) )
+ {
+ struct rap_jobid_key *jinfo = (struct rap_jobid_key*)data.dptr;
+ fstrcpy( sharename, jinfo->sharename );
+ *pjobid = jinfo->jobid;
+ DEBUG(10,("rap_to_pjobid: jobid %u maps to RAP jobid %u\n",
+ (unsigned int)*pjobid, (unsigned int)rap_jobid));
+ SAFE_FREE(data.dptr);
+ return True;
+ }
+
+ DEBUG(10,("rap_to_pjobid: Failed to lookup RAP jobid %u\n",
+ (unsigned int)rap_jobid));
+ SAFE_FREE(data.dptr);
+ return False;
+}
+
+static void rap_jobid_delete(const char* sharename, uint32 jobid)
+{
+ TDB_DATA key, data;
+ uint16 rap_jobid;
+ struct rap_jobid_key jinfo;
+ uint8 buf[2];
+
+ DEBUG(10,("rap_jobid_delete: called.\n"));
+
+ if (!rap_tdb)
+ return;
+
+ ZERO_STRUCT( jinfo );
+ fstrcpy( jinfo.sharename, sharename );
+ jinfo.jobid = jobid;
+ key.dptr = (uint8 *)&jinfo;
+ key.dsize = sizeof(jinfo);
+
+ data = tdb_fetch(rap_tdb, key);
+ if (!data.dptr || (data.dsize != sizeof(uint16))) {
+ DEBUG(10,("rap_jobid_delete: cannot find jobid %u\n",
+ (unsigned int)jobid ));
+ SAFE_FREE(data.dptr);
+ return;
+ }
+
+ DEBUG(10,("rap_jobid_delete: deleting jobid %u\n",
+ (unsigned int)jobid ));
+
+ rap_jobid = SVAL(data.dptr, 0);
+ SAFE_FREE(data.dptr);
+ SSVAL(buf,0,rap_jobid);
+ data.dptr = buf;
+ data.dsize = sizeof(rap_jobid);
+ tdb_delete(rap_tdb, key);
+ tdb_delete(rap_tdb, data);
+}
+
+static int get_queue_status(const char* sharename, print_status_struct *);
+
+/****************************************************************************
+ Initialise the printing backend. Called once at startup before the fork().
+****************************************************************************/
+
+bool print_backend_init(struct messaging_context *msg_ctx)
+{
+ const char *sversion = "INFO/version";
+ int services = lp_numservices();
+ int snum;
+
+ unlink(lock_path("printing.tdb"));
+ mkdir(lock_path("printing"),0755);
+
+ /* handle a Samba upgrade */
+
+ for (snum = 0; snum < services; snum++) {
+ struct tdb_print_db *pdb;
+ if (!lp_print_ok(snum))
+ continue;
+
+ pdb = get_print_db_byname(lp_const_servicename(snum));
+ if (!pdb)
+ continue;
+ if (tdb_lock_bystring(pdb->tdb, sversion) == -1) {
+ DEBUG(0,("print_backend_init: Failed to open printer %s database\n", lp_const_servicename(snum) ));
+ release_print_db(pdb);
+ return False;
+ }
+ if (tdb_fetch_int32(pdb->tdb, sversion) != PRINT_DATABASE_VERSION) {
+ tdb_wipe_all(pdb->tdb);
+ tdb_store_int32(pdb->tdb, sversion, PRINT_DATABASE_VERSION);
+ }
+ tdb_unlock_bystring(pdb->tdb, sversion);
+ release_print_db(pdb);
+ }
+
+ close_all_print_db(); /* Don't leave any open. */
+
+ /* do NT print initialization... */
+ return nt_printing_init(msg_ctx);
+}
+
+/****************************************************************************
+ Shut down printing backend. Called once at shutdown to close the tdb.
+****************************************************************************/
+
+void printing_end(void)
+{
+ close_all_print_db(); /* Don't leave any open. */
+}
+
+/****************************************************************************
+ Retrieve the set of printing functions for a given service. This allows
+ us to set the printer function table based on the value of the 'printing'
+ service parameter.
+
+ Use the generic interface as the default and only use cups interface only
+ when asked for (and only when supported)
+****************************************************************************/
+
+static struct printif *get_printer_fns_from_type( enum printing_types type )
+{
+ struct printif *printer_fns = &generic_printif;
+
+#ifdef HAVE_CUPS
+ if ( type == PRINT_CUPS ) {
+ printer_fns = &cups_printif;
+ }
+#endif /* HAVE_CUPS */
+
+#ifdef HAVE_IPRINT
+ if ( type == PRINT_IPRINT ) {
+ printer_fns = &iprint_printif;
+ }
+#endif /* HAVE_IPRINT */
+
+ printer_fns->type = type;
+
+ return printer_fns;
+}
+
+static struct printif *get_printer_fns( int snum )
+{
+ return get_printer_fns_from_type( (enum printing_types)lp_printing(snum) );
+}
+
+
+/****************************************************************************
+ Useful function to generate a tdb key.
+****************************************************************************/
+
+static TDB_DATA print_key(uint32 jobid, uint32 *tmp)
+{
+ TDB_DATA ret;
+
+ SIVAL(tmp, 0, jobid);
+ ret.dptr = (uint8 *)tmp;
+ ret.dsize = sizeof(*tmp);
+ return ret;
+}
+
+/***********************************************************************
+ unpack a pjob from a tdb buffer
+***********************************************************************/
+
+int unpack_pjob( uint8 *buf, int buflen, struct printjob *pjob )
+{
+ int len = 0;
+ int used;
+ uint32 pjpid, pjsysjob, pjfd, pjstarttime, pjstatus;
+ uint32 pjsize, pjpage_count, pjspooled, pjsmbjob;
+
+ if ( !buf || !pjob )
+ return -1;
+
+ len += tdb_unpack(buf+len, buflen-len, "dddddddddffff",
+ &pjpid,
+ &pjsysjob,
+ &pjfd,
+ &pjstarttime,
+ &pjstatus,
+ &pjsize,
+ &pjpage_count,
+ &pjspooled,
+ &pjsmbjob,
+ pjob->filename,
+ pjob->jobname,
+ pjob->user,
+ pjob->queuename);
+
+ if ( len == -1 )
+ return -1;
+
+ if ( (used = unpack_devicemode(&pjob->nt_devmode, buf+len, buflen-len)) == -1 )
+ return -1;
+
+ len += used;
+
+ pjob->pid = pjpid;
+ pjob->sysjob = pjsysjob;
+ pjob->fd = pjfd;
+ pjob->starttime = pjstarttime;
+ pjob->status = pjstatus;
+ pjob->size = pjsize;
+ pjob->page_count = pjpage_count;
+ pjob->spooled = pjspooled;
+ pjob->smbjob = pjsmbjob;
+
+ return len;
+
+}
+
+/****************************************************************************
+ Useful function to find a print job in the database.
+****************************************************************************/
+
+static struct printjob *print_job_find(const char *sharename, uint32 jobid)
+{
+ static struct printjob pjob;
+ uint32_t tmp;
+ TDB_DATA ret;
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+
+ DEBUG(10,("print_job_find: looking up job %u for share %s\n",
+ (unsigned int)jobid, sharename ));
+
+ if (!pdb) {
+ return NULL;
+ }
+
+ ret = tdb_fetch(pdb->tdb, print_key(jobid, &tmp));
+ release_print_db(pdb);
+
+ if (!ret.dptr) {
+ DEBUG(10,("print_job_find: failed to find jobid %u.\n", (unsigned int)jobid ));
+ return NULL;
+ }
+
+ if ( pjob.nt_devmode ) {
+ free_nt_devicemode( &pjob.nt_devmode );
+ }
+
+ ZERO_STRUCT( pjob );
+
+ if ( unpack_pjob( ret.dptr, ret.dsize, &pjob ) == -1 ) {
+ DEBUG(10,("print_job_find: failed to unpack jobid %u.\n", (unsigned int)jobid ));
+ SAFE_FREE(ret.dptr);
+ return NULL;
+ }
+
+ SAFE_FREE(ret.dptr);
+
+ DEBUG(10,("print_job_find: returning system job %d for jobid %u.\n",
+ (int)pjob.sysjob, (unsigned int)jobid ));
+
+ return &pjob;
+}
+
+/* Convert a unix jobid to a smb jobid */
+
+struct unixjob_traverse_state {
+ int sysjob;
+ uint32 sysjob_to_jobid_value;
+};
+
+static int unixjob_traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA key,
+ TDB_DATA data, void *private_data)
+{
+ struct printjob *pjob;
+ struct unixjob_traverse_state *state =
+ (struct unixjob_traverse_state *)private_data;
+
+ if (!data.dptr || data.dsize == 0)
+ return 0;
+
+ pjob = (struct printjob *)data.dptr;
+ if (key.dsize != sizeof(uint32))
+ return 0;
+
+ if (state->sysjob == pjob->sysjob) {
+ uint32 jobid = IVAL(key.dptr,0);
+
+ state->sysjob_to_jobid_value = jobid;
+ return 1;
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ This is a *horribly expensive call as we have to iterate through all the
+ current printer tdb's. Don't do this often ! JRA.
+****************************************************************************/
+
+uint32 sysjob_to_jobid(int unix_jobid)
+{
+ int services = lp_numservices();
+ int snum;
+ struct unixjob_traverse_state state;
+
+ state.sysjob = unix_jobid;
+ state.sysjob_to_jobid_value = (uint32)-1;
+
+ for (snum = 0; snum < services; snum++) {
+ struct tdb_print_db *pdb;
+ if (!lp_print_ok(snum))
+ continue;
+ pdb = get_print_db_byname(lp_const_servicename(snum));
+ if (!pdb) {
+ continue;
+ }
+ tdb_traverse(pdb->tdb, unixjob_traverse_fn, &state);
+ release_print_db(pdb);
+ if (state.sysjob_to_jobid_value != (uint32)-1)
+ return state.sysjob_to_jobid_value;
+ }
+ return (uint32)-1;
+}
+
+/****************************************************************************
+ Send notifications based on what has changed after a pjob_store.
+****************************************************************************/
+
+static const struct {
+ uint32 lpq_status;
+ uint32 spoolss_status;
+} lpq_to_spoolss_status_map[] = {
+ { LPQ_QUEUED, JOB_STATUS_QUEUED },
+ { LPQ_PAUSED, JOB_STATUS_PAUSED },
+ { LPQ_SPOOLING, JOB_STATUS_SPOOLING },
+ { LPQ_PRINTING, JOB_STATUS_PRINTING },
+ { LPQ_DELETING, JOB_STATUS_DELETING },
+ { LPQ_OFFLINE, JOB_STATUS_OFFLINE },
+ { LPQ_PAPEROUT, JOB_STATUS_PAPEROUT },
+ { LPQ_PRINTED, JOB_STATUS_PRINTED },
+ { LPQ_DELETED, JOB_STATUS_DELETED },
+ { LPQ_BLOCKED, JOB_STATUS_BLOCKED },
+ { LPQ_USER_INTERVENTION, JOB_STATUS_USER_INTERVENTION },
+ { -1, 0 }
+};
+
+/* Convert a lpq status value stored in printing.tdb into the
+ appropriate win32 API constant. */
+
+static uint32 map_to_spoolss_status(uint32 lpq_status)
+{
+ int i = 0;
+
+ while (lpq_to_spoolss_status_map[i].lpq_status != -1) {
+ if (lpq_to_spoolss_status_map[i].lpq_status == lpq_status)
+ return lpq_to_spoolss_status_map[i].spoolss_status;
+ i++;
+ }
+
+ return 0;
+}
+
+static void pjob_store_notify(const char* sharename, uint32 jobid, struct printjob *old_data,
+ struct printjob *new_data)
+{
+ bool new_job = False;
+
+ if (!old_data)
+ new_job = True;
+
+ /* Job attributes that can't be changed. We only send
+ notification for these on a new job. */
+
+ /* ACHTUNG! Due to a bug in Samba's spoolss parsing of the
+ NOTIFY_INFO_DATA buffer, we *have* to send the job submission
+ time first or else we'll end up with potential alignment
+ errors. I don't think the systemtime should be spooled as
+ a string, but this gets us around that error.
+ --jerry (i'll feel dirty for this) */
+
+ if (new_job) {
+ notify_job_submitted(sharename, jobid, new_data->starttime);
+ notify_job_username(sharename, jobid, new_data->user);
+ }
+
+ if (new_job || !strequal(old_data->jobname, new_data->jobname))
+ notify_job_name(sharename, jobid, new_data->jobname);
+
+ /* Job attributes of a new job or attributes that can be
+ modified. */
+
+ if (new_job || !strequal(old_data->jobname, new_data->jobname))
+ notify_job_name(sharename, jobid, new_data->jobname);
+
+ if (new_job || old_data->status != new_data->status)
+ notify_job_status(sharename, jobid, map_to_spoolss_status(new_data->status));
+
+ if (new_job || old_data->size != new_data->size)
+ notify_job_total_bytes(sharename, jobid, new_data->size);
+
+ if (new_job || old_data->page_count != new_data->page_count)
+ notify_job_total_pages(sharename, jobid, new_data->page_count);
+}
+
+/****************************************************************************
+ Store a job structure back to the database.
+****************************************************************************/
+
+static bool pjob_store(const char* sharename, uint32 jobid, struct printjob *pjob)
+{
+ uint32_t tmp;
+ TDB_DATA old_data, new_data;
+ bool ret = False;
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+ uint8 *buf = NULL;
+ int len, newlen, buflen;
+
+
+ if (!pdb)
+ return False;
+
+ /* Get old data */
+
+ old_data = tdb_fetch(pdb->tdb, print_key(jobid, &tmp));
+
+ /* Doh! Now we have to pack/unpack data since the NT_DEVICEMODE was added */
+
+ newlen = 0;
+
+ do {
+ len = 0;
+ buflen = newlen;
+ len += tdb_pack(buf+len, buflen-len, "dddddddddffff",
+ (uint32)pjob->pid,
+ (uint32)pjob->sysjob,
+ (uint32)pjob->fd,
+ (uint32)pjob->starttime,
+ (uint32)pjob->status,
+ (uint32)pjob->size,
+ (uint32)pjob->page_count,
+ (uint32)pjob->spooled,
+ (uint32)pjob->smbjob,
+ pjob->filename,
+ pjob->jobname,
+ pjob->user,
+ pjob->queuename);
+
+ len += pack_devicemode(pjob->nt_devmode, buf+len, buflen-len);
+
+ if (buflen != len) {
+ buf = (uint8 *)SMB_REALLOC(buf, len);
+ if (!buf) {
+ DEBUG(0,("pjob_store: failed to enlarge buffer!\n"));
+ goto done;
+ }
+ newlen = len;
+ }
+ } while ( buflen != len );
+
+
+ /* Store new data */
+
+ new_data.dptr = buf;
+ new_data.dsize = len;
+ ret = (tdb_store(pdb->tdb, print_key(jobid, &tmp), new_data,
+ TDB_REPLACE) == 0);
+
+ release_print_db(pdb);
+
+ /* Send notify updates for what has changed */
+
+ if ( ret ) {
+ struct printjob old_pjob;
+
+ if ( old_data.dsize )
+ {
+ if ( unpack_pjob( old_data.dptr, old_data.dsize, &old_pjob ) != -1 )
+ {
+ pjob_store_notify( sharename, jobid, &old_pjob , pjob );
+ free_nt_devicemode( &old_pjob.nt_devmode );
+ }
+ }
+ else {
+ /* new job */
+ pjob_store_notify( sharename, jobid, NULL, pjob );
+ }
+ }
+
+done:
+ SAFE_FREE( old_data.dptr );
+ SAFE_FREE( buf );
+
+ return ret;
+}
+
+/****************************************************************************
+ Remove a job structure from the database.
+****************************************************************************/
+
+void pjob_delete(const char* sharename, uint32 jobid)
+{
+ uint32_t tmp;
+ struct printjob *pjob;
+ uint32 job_status = 0;
+ struct tdb_print_db *pdb;
+
+ pdb = get_print_db_byname( sharename );
+
+ if (!pdb)
+ return;
+
+ pjob = print_job_find( sharename, jobid );
+
+ if (!pjob) {
+ DEBUG(5, ("pjob_delete: we were asked to delete nonexistent job %u\n",
+ (unsigned int)jobid));
+ release_print_db(pdb);
+ return;
+ }
+
+ /* We must cycle through JOB_STATUS_DELETING and
+ JOB_STATUS_DELETED for the port monitor to delete the job
+ properly. */
+
+ job_status = JOB_STATUS_DELETING|JOB_STATUS_DELETED;
+ notify_job_status(sharename, jobid, job_status);
+
+ /* Remove from printing.tdb */
+
+ tdb_delete(pdb->tdb, print_key(jobid, &tmp));
+ remove_from_jobs_changed(sharename, jobid);
+ release_print_db( pdb );
+ rap_jobid_delete(sharename, jobid);
+}
+
+/****************************************************************************
+ Parse a file name from the system spooler to generate a jobid.
+****************************************************************************/
+
+static uint32 print_parse_jobid(char *fname)
+{
+ int jobid;
+
+ if (strncmp(fname,PRINT_SPOOL_PREFIX,strlen(PRINT_SPOOL_PREFIX)) != 0)
+ return (uint32)-1;
+ fname += strlen(PRINT_SPOOL_PREFIX);
+
+ jobid = atoi(fname);
+ if (jobid <= 0)
+ return (uint32)-1;
+
+ return (uint32)jobid;
+}
+
+/****************************************************************************
+ List a unix job in the print database.
+****************************************************************************/
+
+static void print_unix_job(const char *sharename, print_queue_struct *q, uint32 jobid)
+{
+ struct printjob pj, *old_pj;
+
+ if (jobid == (uint32)-1)
+ jobid = q->job + UNIX_JOB_START;
+
+ /* Preserve the timestamp on an existing unix print job */
+
+ old_pj = print_job_find(sharename, jobid);
+
+ ZERO_STRUCT(pj);
+
+ pj.pid = (pid_t)-1;
+ pj.sysjob = q->job;
+ pj.fd = -1;
+ pj.starttime = old_pj ? old_pj->starttime : q->time;
+ pj.status = q->status;
+ pj.size = q->size;
+ pj.spooled = True;
+ fstrcpy(pj.filename, old_pj ? old_pj->filename : "");
+ if (jobid < UNIX_JOB_START) {
+ pj.smbjob = True;
+ fstrcpy(pj.jobname, old_pj ? old_pj->jobname : "Remote Downlevel Document");
+ } else {
+ pj.smbjob = False;
+ fstrcpy(pj.jobname, old_pj ? old_pj->jobname : q->fs_file);
+ }
+ fstrcpy(pj.user, old_pj ? old_pj->user : q->fs_user);
+ fstrcpy(pj.queuename, old_pj ? old_pj->queuename : sharename );
+
+ pjob_store(sharename, jobid, &pj);
+}
+
+
+struct traverse_struct {
+ print_queue_struct *queue;
+ int qcount, snum, maxcount, total_jobs;
+ const char *sharename;
+ time_t lpq_time;
+ const char *lprm_command;
+ struct printif *print_if;
+};
+
+/****************************************************************************
+ Utility fn to delete any jobs that are no longer active.
+****************************************************************************/
+
+static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
+{
+ struct traverse_struct *ts = (struct traverse_struct *)state;
+ struct printjob pjob;
+ uint32 jobid;
+ int i = 0;
+
+ if ( key.dsize != sizeof(jobid) )
+ return 0;
+
+ jobid = IVAL(key.dptr, 0);
+ if ( unpack_pjob( data.dptr, data.dsize, &pjob ) == -1 )
+ return 0;
+ free_nt_devicemode( &pjob.nt_devmode );
+
+
+ if (!pjob.smbjob) {
+ /* remove a unix job if it isn't in the system queue any more */
+
+ for (i=0;i<ts->qcount;i++) {
+ uint32 u_jobid = (ts->queue[i].job + UNIX_JOB_START);
+ if (jobid == u_jobid)
+ break;
+ }
+ if (i == ts->qcount) {
+ DEBUG(10,("traverse_fn_delete: pjob %u deleted due to !smbjob\n",
+ (unsigned int)jobid ));
+ pjob_delete(ts->sharename, jobid);
+ return 0;
+ }
+
+ /* need to continue the the bottom of the function to
+ save the correct attributes */
+ }
+
+ /* maybe it hasn't been spooled yet */
+ if (!pjob.spooled) {
+ /* if a job is not spooled and the process doesn't
+ exist then kill it. This cleans up after smbd
+ deaths */
+ if (!process_exists_by_pid(pjob.pid)) {
+ DEBUG(10,("traverse_fn_delete: pjob %u deleted due to !process_exists (%u)\n",
+ (unsigned int)jobid, (unsigned int)pjob.pid ));
+ pjob_delete(ts->sharename, jobid);
+ } else
+ ts->total_jobs++;
+ return 0;
+ }
+
+ /* this check only makes sense for jobs submitted from Windows clients */
+
+ if ( pjob.smbjob ) {
+ for (i=0;i<ts->qcount;i++) {
+ uint32 curr_jobid;
+
+ if ( pjob.status == LPQ_DELETED )
+ continue;
+
+ curr_jobid = print_parse_jobid(ts->queue[i].fs_file);
+
+ if (jobid == curr_jobid) {
+
+ /* try to clean up any jobs that need to be deleted */
+
+ if ( pjob.status == LPQ_DELETING ) {
+ int result;
+
+ result = (*(ts->print_if->job_delete))(
+ ts->sharename, ts->lprm_command, &pjob );
+
+ if ( result != 0 ) {
+ /* if we can't delete, then reset the job status */
+ pjob.status = LPQ_QUEUED;
+ pjob_store(ts->sharename, jobid, &pjob);
+ }
+ else {
+ /* if we deleted the job, the remove the tdb record */
+ pjob_delete(ts->sharename, jobid);
+ pjob.status = LPQ_DELETED;
+ }
+
+ }
+
+ break;
+ }
+ }
+ }
+
+ /* The job isn't in the system queue - we have to assume it has
+ completed, so delete the database entry. */
+
+ if (i == ts->qcount) {
+
+ /* A race can occur between the time a job is spooled and
+ when it appears in the lpq output. This happens when
+ the job is added to printing.tdb when another smbd
+ running print_queue_update() has completed a lpq and
+ is currently traversing the printing tdb and deleting jobs.
+ Don't delete the job if it was submitted after the lpq_time. */
+
+ if (pjob.starttime < ts->lpq_time) {
+ DEBUG(10,("traverse_fn_delete: pjob %u deleted due to pjob.starttime (%u) < ts->lpq_time (%u)\n",
+ (unsigned int)jobid,
+ (unsigned int)pjob.starttime,
+ (unsigned int)ts->lpq_time ));
+ pjob_delete(ts->sharename, jobid);
+ } else
+ ts->total_jobs++;
+ return 0;
+ }
+
+ /* Save the pjob attributes we will store.
+ FIXME!!! This is the only place where queue->job
+ represents the SMB jobid --jerry */
+
+ ts->queue[i].job = jobid;
+ ts->queue[i].size = pjob.size;
+ ts->queue[i].page_count = pjob.page_count;
+ ts->queue[i].status = pjob.status;
+ ts->queue[i].priority = 1;
+ ts->queue[i].time = pjob.starttime;
+ fstrcpy(ts->queue[i].fs_user, pjob.user);
+ fstrcpy(ts->queue[i].fs_file, pjob.jobname);
+
+ ts->total_jobs++;
+
+ return 0;
+}
+
+/****************************************************************************
+ Check if the print queue has been updated recently enough.
+****************************************************************************/
+
+static void print_cache_flush(const char *sharename)
+{
+ fstring key;
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+
+ if (!pdb)
+ return;
+ slprintf(key, sizeof(key)-1, "CACHE/%s", sharename);
+ tdb_store_int32(pdb->tdb, key, -1);
+ release_print_db(pdb);
+}
+
+/****************************************************************************
+ Check if someone already thinks they are doing the update.
+****************************************************************************/
+
+static pid_t get_updating_pid(const char *sharename)
+{
+ fstring keystr;
+ TDB_DATA data, key;
+ pid_t updating_pid;
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+
+ if (!pdb)
+ return (pid_t)-1;
+ slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", sharename);
+ key = string_tdb_data(keystr);
+
+ data = tdb_fetch(pdb->tdb, key);
+ release_print_db(pdb);
+ if (!data.dptr || data.dsize != sizeof(pid_t)) {
+ SAFE_FREE(data.dptr);
+ return (pid_t)-1;
+ }
+
+ updating_pid = IVAL(data.dptr, 0);
+ SAFE_FREE(data.dptr);
+
+ if (process_exists_by_pid(updating_pid))
+ return updating_pid;
+
+ return (pid_t)-1;
+}
+
+/****************************************************************************
+ Set the fact that we're doing the update, or have finished doing the update
+ in the tdb.
+****************************************************************************/
+
+static void set_updating_pid(const fstring sharename, bool updating)
+{
+ fstring keystr;
+ TDB_DATA key;
+ TDB_DATA data;
+ pid_t updating_pid = sys_getpid();
+ uint8 buffer[4];
+
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+
+ if (!pdb)
+ return;
+
+ slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", sharename);
+ key = string_tdb_data(keystr);
+
+ DEBUG(5, ("set_updating_pid: %s updating lpq cache for print share %s\n",
+ updating ? "" : "not ",
+ sharename ));
+
+ if ( !updating ) {
+ tdb_delete(pdb->tdb, key);
+ release_print_db(pdb);
+ return;
+ }
+
+ SIVAL( buffer, 0, updating_pid);
+ data.dptr = buffer;
+ data.dsize = 4; /* we always assume this is a 4 byte value */
+
+ tdb_store(pdb->tdb, key, data, TDB_REPLACE);
+ release_print_db(pdb);
+}
+
+/****************************************************************************
+ Sort print jobs by submittal time.
+****************************************************************************/
+
+static int printjob_comp(print_queue_struct *j1, print_queue_struct *j2)
+{
+ /* Silly cases */
+
+ if (!j1 && !j2)
+ return 0;
+ if (!j1)
+ return -1;
+ if (!j2)
+ return 1;
+
+ /* Sort on job start time */
+
+ if (j1->time == j2->time)
+ return 0;
+ return (j1->time > j2->time) ? 1 : -1;
+}
+
+/****************************************************************************
+ Store the sorted queue representation for later portmon retrieval.
+ Skip deleted jobs
+****************************************************************************/
+
+static void store_queue_struct(struct tdb_print_db *pdb, struct traverse_struct *pts)
+{
+ TDB_DATA data;
+ int max_reported_jobs = lp_max_reported_jobs(pts->snum);
+ print_queue_struct *queue = pts->queue;
+ size_t len;
+ size_t i;
+ unsigned int qcount;
+
+ if (max_reported_jobs && (max_reported_jobs < pts->qcount))
+ pts->qcount = max_reported_jobs;
+ qcount = 0;
+
+ /* Work out the size. */
+ data.dsize = 0;
+ data.dsize += tdb_pack(NULL, 0, "d", qcount);
+
+ for (i = 0; i < pts->qcount; i++) {
+ if ( queue[i].status == LPQ_DELETED )
+ continue;
+
+ qcount++;
+ data.dsize += tdb_pack(NULL, 0, "ddddddff",
+ (uint32)queue[i].job,
+ (uint32)queue[i].size,
+ (uint32)queue[i].page_count,
+ (uint32)queue[i].status,
+ (uint32)queue[i].priority,
+ (uint32)queue[i].time,
+ queue[i].fs_user,
+ queue[i].fs_file);
+ }
+
+ if ((data.dptr = (uint8 *)SMB_MALLOC(data.dsize)) == NULL)
+ return;
+
+ len = 0;
+ len += tdb_pack(data.dptr + len, data.dsize - len, "d", qcount);
+ for (i = 0; i < pts->qcount; i++) {
+ if ( queue[i].status == LPQ_DELETED )
+ continue;
+
+ len += tdb_pack(data.dptr + len, data.dsize - len, "ddddddff",
+ (uint32)queue[i].job,
+ (uint32)queue[i].size,
+ (uint32)queue[i].page_count,
+ (uint32)queue[i].status,
+ (uint32)queue[i].priority,
+ (uint32)queue[i].time,
+ queue[i].fs_user,
+ queue[i].fs_file);
+ }
+
+ tdb_store(pdb->tdb, string_tdb_data("INFO/linear_queue_array"), data,
+ TDB_REPLACE);
+ SAFE_FREE(data.dptr);
+ return;
+}
+
+static TDB_DATA get_jobs_changed_data(struct tdb_print_db *pdb)
+{
+ TDB_DATA data;
+
+ ZERO_STRUCT(data);
+
+ data = tdb_fetch(pdb->tdb, string_tdb_data("INFO/jobs_changed"));
+ if (data.dptr == NULL || data.dsize == 0 || (data.dsize % 4 != 0)) {
+ SAFE_FREE(data.dptr);
+ ZERO_STRUCT(data);
+ }
+
+ return data;
+}
+
+static void check_job_changed(const char *sharename, TDB_DATA data, uint32 jobid)
+{
+ unsigned int i;
+ unsigned int job_count = data.dsize / 4;
+
+ for (i = 0; i < job_count; i++) {
+ uint32 ch_jobid;
+
+ ch_jobid = IVAL(data.dptr, i*4);
+ if (ch_jobid == jobid)
+ remove_from_jobs_changed(sharename, jobid);
+ }
+}
+
+/****************************************************************************
+ Check if the print queue has been updated recently enough.
+****************************************************************************/
+
+static bool print_cache_expired(const char *sharename, bool check_pending)
+{
+ fstring key;
+ time_t last_qscan_time, time_now = time(NULL);
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+ bool result = False;
+
+ if (!pdb)
+ return False;
+
+ snprintf(key, sizeof(key), "CACHE/%s", sharename);
+ last_qscan_time = (time_t)tdb_fetch_int32(pdb->tdb, key);
+
+ /*
+ * Invalidate the queue for 3 reasons.
+ * (1). last queue scan time == -1.
+ * (2). Current time - last queue scan time > allowed cache time.
+ * (3). last queue scan time > current time + MAX_CACHE_VALID_TIME (1 hour by default).
+ * This last test picks up machines for which the clock has been moved
+ * forward, an lpq scan done and then the clock moved back. Otherwise
+ * that last lpq scan would stay around for a loooong loooong time... :-). JRA.
+ */
+
+ if (last_qscan_time == ((time_t)-1)
+ || (time_now - last_qscan_time) >= lp_lpqcachetime()
+ || last_qscan_time > (time_now + MAX_CACHE_VALID_TIME))
+ {
+ uint32 u;
+ time_t msg_pending_time;
+
+ DEBUG(4, ("print_cache_expired: cache expired for queue %s "
+ "(last_qscan_time = %d, time now = %d, qcachetime = %d)\n",
+ sharename, (int)last_qscan_time, (int)time_now,
+ (int)lp_lpqcachetime() ));
+
+ /* check if another smbd has already sent a message to update the
+ queue. Give the pending message one minute to clear and
+ then send another message anyways. Make sure to check for
+ clocks that have been run forward and then back again. */
+
+ snprintf(key, sizeof(key), "MSG_PENDING/%s", sharename);
+
+ if ( check_pending
+ && tdb_fetch_uint32( pdb->tdb, key, &u )
+ && (msg_pending_time=u) > 0
+ && msg_pending_time <= time_now
+ && (time_now - msg_pending_time) < 60 )
+ {
+ DEBUG(4,("print_cache_expired: message already pending for %s. Accepting cache\n",
+ sharename));
+ goto done;
+ }
+
+ result = True;
+ }
+
+done:
+ release_print_db(pdb);
+ return result;
+}
+
+/****************************************************************************
+ main work for updating the lpq cahe for a printer queue
+****************************************************************************/
+
+static void print_queue_update_internal( const char *sharename,
+ struct printif *current_printif,
+ char *lpq_command, char *lprm_command )
+{
+ int i, qcount;
+ print_queue_struct *queue = NULL;
+ print_status_struct status;
+ print_status_struct old_status;
+ struct printjob *pjob;
+ struct traverse_struct tstruct;
+ TDB_DATA data, key;
+ TDB_DATA jcdata;
+ fstring keystr, cachestr;
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+
+ if (!pdb) {
+ return;
+ }
+
+ DEBUG(5,("print_queue_update_internal: printer = %s, type = %d, lpq command = [%s]\n",
+ sharename, current_printif->type, lpq_command));
+
+ /*
+ * Update the cache time FIRST ! Stops others even
+ * attempting to get the lock and doing this
+ * if the lpq takes a long time.
+ */
+
+ slprintf(cachestr, sizeof(cachestr)-1, "CACHE/%s", sharename);
+ tdb_store_int32(pdb->tdb, cachestr, (int)time(NULL));
+
+ /* get the current queue using the appropriate interface */
+ ZERO_STRUCT(status);
+
+ qcount = (*(current_printif->queue_get))(sharename,
+ current_printif->type,
+ lpq_command, &queue, &status);
+
+ DEBUG(3, ("print_queue_update_internal: %d job%s in queue for %s\n",
+ qcount, (qcount != 1) ? "s" : "", sharename));
+
+ /* Sort the queue by submission time otherwise they are displayed
+ in hash order. */
+
+ qsort(queue, qcount, sizeof(print_queue_struct),
+ QSORT_CAST(printjob_comp));
+
+ /*
+ any job in the internal database that is marked as spooled
+ and doesn't exist in the system queue is considered finished
+ and removed from the database
+
+ any job in the system database but not in the internal database
+ is added as a unix job
+
+ fill in any system job numbers as we go
+ */
+
+ jcdata = get_jobs_changed_data(pdb);
+
+ for (i=0; i<qcount; i++) {
+ uint32 jobid = print_parse_jobid(queue[i].fs_file);
+
+ if (jobid == (uint32)-1) {
+ /* assume its a unix print job */
+ print_unix_job(sharename, &queue[i], jobid);
+ continue;
+ }
+
+ /* we have an active SMB print job - update its status */
+ pjob = print_job_find(sharename, jobid);
+ if (!pjob) {
+ /* err, somethings wrong. Probably smbd was restarted
+ with jobs in the queue. All we can do is treat them
+ like unix jobs. Pity. */
+ print_unix_job(sharename, &queue[i], jobid);
+ continue;
+ }
+
+ pjob->sysjob = queue[i].job;
+
+ /* don't reset the status on jobs to be deleted */
+
+ if ( pjob->status != LPQ_DELETING )
+ pjob->status = queue[i].status;
+
+ pjob_store(sharename, jobid, pjob);
+
+ check_job_changed(sharename, jcdata, jobid);
+ }
+
+ SAFE_FREE(jcdata.dptr);
+
+ /* now delete any queued entries that don't appear in the
+ system queue */
+ tstruct.queue = queue;
+ tstruct.qcount = qcount;
+ tstruct.snum = -1;
+ tstruct.total_jobs = 0;
+ tstruct.lpq_time = time(NULL);
+ tstruct.sharename = sharename;
+ tstruct.lprm_command = lprm_command;
+ tstruct.print_if = current_printif;
+
+ tdb_traverse(pdb->tdb, traverse_fn_delete, (void *)&tstruct);
+
+ /* Store the linearised queue, max jobs only. */
+ store_queue_struct(pdb, &tstruct);
+
+ SAFE_FREE(tstruct.queue);
+
+ DEBUG(10,("print_queue_update_internal: printer %s INFO/total_jobs = %d\n",
+ sharename, tstruct.total_jobs ));
+
+ tdb_store_int32(pdb->tdb, "INFO/total_jobs", tstruct.total_jobs);
+
+ get_queue_status(sharename, &old_status);
+ if (old_status.qcount != qcount)
+ DEBUG(10,("print_queue_update_internal: queue status change %d jobs -> %d jobs for printer %s\n",
+ old_status.qcount, qcount, sharename));
+
+ /* store the new queue status structure */
+ slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", sharename);
+ key = string_tdb_data(keystr);
+
+ status.qcount = qcount;
+ data.dptr = (uint8 *)&status;
+ data.dsize = sizeof(status);
+ tdb_store(pdb->tdb, key, data, TDB_REPLACE);
+
+ /*
+ * Update the cache time again. We want to do this call
+ * as little as possible...
+ */
+
+ slprintf(keystr, sizeof(keystr)-1, "CACHE/%s", sharename);
+ tdb_store_int32(pdb->tdb, keystr, (int32)time(NULL));
+
+ /* clear the msg pending record for this queue */
+
+ snprintf(keystr, sizeof(keystr), "MSG_PENDING/%s", sharename);
+
+ if ( !tdb_store_uint32( pdb->tdb, keystr, 0 ) ) {
+ /* log a message but continue on */
+
+ DEBUG(0,("print_queue_update: failed to store MSG_PENDING flag for [%s]!\n",
+ sharename));
+ }
+
+ release_print_db( pdb );
+
+ return;
+}
+
+/****************************************************************************
+ Update the internal database from the system print queue for a queue.
+ obtain a lock on the print queue before proceeding (needed when mutiple
+ smbd processes maytry to update the lpq cache concurrently).
+****************************************************************************/
+
+static void print_queue_update_with_lock( const char *sharename,
+ struct printif *current_printif,
+ char *lpq_command, char *lprm_command )
+{
+ fstring keystr;
+ struct tdb_print_db *pdb;
+
+ DEBUG(5,("print_queue_update_with_lock: printer share = %s\n", sharename));
+ pdb = get_print_db_byname(sharename);
+ if (!pdb)
+ return;
+
+ if ( !print_cache_expired(sharename, False) ) {
+ DEBUG(5,("print_queue_update_with_lock: print cache for %s is still ok\n", sharename));
+ release_print_db(pdb);
+ return;
+ }
+
+ /*
+ * Check to see if someone else is doing this update.
+ * This is essentially a mutex on the update.
+ */
+
+ if (get_updating_pid(sharename) != -1) {
+ release_print_db(pdb);
+ return;
+ }
+
+ /* Lock the queue for the database update */
+
+ slprintf(keystr, sizeof(keystr) - 1, "LOCK/%s", sharename);
+ /* Only wait 10 seconds for this. */
+ if (tdb_lock_bystring_with_timeout(pdb->tdb, keystr, 10) == -1) {
+ DEBUG(0,("print_queue_update_with_lock: Failed to lock printer %s database\n", sharename));
+ release_print_db(pdb);
+ return;
+ }
+
+ /*
+ * Ensure that no one else got in here.
+ * If the updating pid is still -1 then we are
+ * the winner.
+ */
+
+ if (get_updating_pid(sharename) != -1) {
+ /*
+ * Someone else is doing the update, exit.
+ */
+ tdb_unlock_bystring(pdb->tdb, keystr);
+ release_print_db(pdb);
+ return;
+ }
+
+ /*
+ * We're going to do the update ourselves.
+ */
+
+ /* Tell others we're doing the update. */
+ set_updating_pid(sharename, True);
+
+ /*
+ * Allow others to enter and notice we're doing
+ * the update.
+ */
+
+ tdb_unlock_bystring(pdb->tdb, keystr);
+
+ /* do the main work now */
+
+ print_queue_update_internal( sharename, current_printif,
+ lpq_command, lprm_command );
+
+ /* Delete our pid from the db. */
+ set_updating_pid(sharename, False);
+ release_print_db(pdb);
+}
+
+/****************************************************************************
+this is the receive function of the background lpq updater
+****************************************************************************/
+static void print_queue_receive(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ fstring sharename;
+ char *lpqcommand = NULL, *lprmcommand = NULL;
+ int printing_type;
+ size_t len;
+
+ len = tdb_unpack( (uint8 *)data->data, data->length, "fdPP",
+ sharename,
+ &printing_type,
+ &lpqcommand,
+ &lprmcommand );
+
+ if ( len == -1 ) {
+ SAFE_FREE(lpqcommand);
+ SAFE_FREE(lprmcommand);
+ DEBUG(0,("print_queue_receive: Got invalid print queue update message\n"));
+ return;
+ }
+
+ print_queue_update_with_lock(sharename,
+ get_printer_fns_from_type((enum printing_types)printing_type),
+ lpqcommand, lprmcommand );
+
+ SAFE_FREE(lpqcommand);
+ SAFE_FREE(lprmcommand);
+ return;
+}
+
+static pid_t background_lpq_updater_pid = -1;
+
+/****************************************************************************
+main thread of the background lpq updater
+****************************************************************************/
+void start_background_queue(void)
+{
+ DEBUG(3,("start_background_queue: Starting background LPQ thread\n"));
+ background_lpq_updater_pid = sys_fork();
+
+ if (background_lpq_updater_pid == -1) {
+ DEBUG(5,("start_background_queue: background LPQ thread failed to start. %s\n", strerror(errno) ));
+ exit(1);
+ }
+
+ if(background_lpq_updater_pid == 0) {
+ /* Child. */
+ DEBUG(5,("start_background_queue: background LPQ thread started\n"));
+
+ if (!reinit_after_fork(smbd_messaging_context(), true)) {
+ DEBUG(0,("reinit_after_fork() failed\n"));
+ smb_panic("reinit_after_fork() failed");
+ }
+
+ claim_connection( NULL, "smbd lpq backend",
+ FLAG_MSG_GENERAL|FLAG_MSG_SMBD|FLAG_MSG_PRINT_GENERAL);
+
+ if (!locking_init()) {
+ exit(1);
+ }
+
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_PRINTER_UPDATE, print_queue_receive);
+
+ DEBUG(5,("start_background_queue: background LPQ thread waiting for messages\n"));
+ while (1) {
+ pause();
+
+ /* check for some essential signals first */
+
+ if (got_sig_term) {
+ exit_server_cleanly(NULL);
+ }
+
+ if (reload_after_sighup) {
+ change_to_root_user();
+ DEBUG(1,("Reloading services after SIGHUP\n"));
+ reload_services(False);
+ reload_after_sighup = 0;
+ }
+
+ /* now check for messages */
+
+ DEBUG(10,("start_background_queue: background LPQ thread got a message\n"));
+ message_dispatch(smbd_messaging_context());
+
+ /* process any pending print change notify messages */
+
+ print_notify_send_messages(smbd_messaging_context(),
+ 0);
+ }
+ }
+}
+
+/****************************************************************************
+update the internal database from the system print queue for a queue
+****************************************************************************/
+
+static void print_queue_update(int snum, bool force)
+{
+ fstring key;
+ fstring sharename;
+ char *lpqcommand = NULL;
+ char *lprmcommand = NULL;
+ uint8 *buffer = NULL;
+ size_t len = 0;
+ size_t newlen;
+ struct tdb_print_db *pdb;
+ int type;
+ struct printif *current_printif;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ fstrcpy( sharename, lp_const_servicename(snum));
+
+ /* don't strip out characters like '$' from the printername */
+
+ lpqcommand = talloc_string_sub2(ctx,
+ lp_lpqcommand(snum),
+ "%p",
+ PRINTERNAME(snum),
+ false, false, false);
+ if (!lpqcommand) {
+ return;
+ }
+ lpqcommand = talloc_sub_advanced(ctx,
+ lp_servicename(snum),
+ current_user_info.unix_name,
+ "",
+ current_user.ut.gid,
+ get_current_username(),
+ current_user_info.domain,
+ lpqcommand);
+ if (!lpqcommand) {
+ return;
+ }
+
+ lprmcommand = talloc_string_sub2(ctx,
+ lp_lprmcommand(snum),
+ "%p",
+ PRINTERNAME(snum),
+ false, false, false);
+ if (!lprmcommand) {
+ return;
+ }
+ lprmcommand = talloc_sub_advanced(ctx,
+ lp_servicename(snum),
+ current_user_info.unix_name,
+ "",
+ current_user.ut.gid,
+ get_current_username(),
+ current_user_info.domain,
+ lprmcommand);
+ if (!lprmcommand) {
+ return;
+ }
+
+ /*
+ * Make sure that the background queue process exists.
+ * Otherwise just do the update ourselves
+ */
+
+ if ( force || background_lpq_updater_pid == -1 ) {
+ DEBUG(4,("print_queue_update: updating queue [%s] myself\n", sharename));
+ current_printif = get_printer_fns( snum );
+ print_queue_update_with_lock( sharename, current_printif, lpqcommand, lprmcommand );
+
+ return;
+ }
+
+ type = lp_printing(snum);
+
+ /* get the length */
+
+ len = tdb_pack( NULL, 0, "fdPP",
+ sharename,
+ type,
+ lpqcommand,
+ lprmcommand );
+
+ buffer = SMB_XMALLOC_ARRAY( uint8, len );
+
+ /* now pack the buffer */
+ newlen = tdb_pack( buffer, len, "fdPP",
+ sharename,
+ type,
+ lpqcommand,
+ lprmcommand );
+
+ SMB_ASSERT( newlen == len );
+
+ DEBUG(10,("print_queue_update: Sending message -> printer = %s, "
+ "type = %d, lpq command = [%s] lprm command = [%s]\n",
+ sharename, type, lpqcommand, lprmcommand ));
+
+ /* here we set a msg pending record for other smbd processes
+ to throttle the number of duplicate print_queue_update msgs
+ sent. */
+
+ pdb = get_print_db_byname(sharename);
+ if (!pdb) {
+ SAFE_FREE(buffer);
+ return;
+ }
+
+ snprintf(key, sizeof(key), "MSG_PENDING/%s", sharename);
+
+ if ( !tdb_store_uint32( pdb->tdb, key, time(NULL) ) ) {
+ /* log a message but continue on */
+
+ DEBUG(0,("print_queue_update: failed to store MSG_PENDING flag for [%s]!\n",
+ sharename));
+ }
+
+ release_print_db( pdb );
+
+ /* finally send the message */
+
+ messaging_send_buf(smbd_messaging_context(),
+ pid_to_procid(background_lpq_updater_pid),
+ MSG_PRINTER_UPDATE, (uint8 *)buffer, len);
+
+ SAFE_FREE( buffer );
+
+ return;
+}
+
+/****************************************************************************
+ Create/Update an entry in the print tdb that will allow us to send notify
+ updates only to interested smbd's.
+****************************************************************************/
+
+bool print_notify_register_pid(int snum)
+{
+ TDB_DATA data;
+ struct tdb_print_db *pdb = NULL;
+ TDB_CONTEXT *tdb = NULL;
+ const char *printername;
+ uint32 mypid = (uint32)sys_getpid();
+ bool ret = False;
+ size_t i;
+
+ /* if (snum == -1), then the change notify request was
+ on a print server handle and we need to register on
+ all print queus */
+
+ if (snum == -1)
+ {
+ int num_services = lp_numservices();
+ int idx;
+
+ for ( idx=0; idx<num_services; idx++ ) {
+ if (lp_snum_ok(idx) && lp_print_ok(idx) )
+ print_notify_register_pid(idx);
+ }
+
+ return True;
+ }
+ else /* register for a specific printer */
+ {
+ printername = lp_const_servicename(snum);
+ pdb = get_print_db_byname(printername);
+ if (!pdb)
+ return False;
+ tdb = pdb->tdb;
+ }
+
+ if (tdb_lock_bystring_with_timeout(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) {
+ DEBUG(0,("print_notify_register_pid: Failed to lock printer %s\n",
+ printername));
+ if (pdb)
+ release_print_db(pdb);
+ return False;
+ }
+
+ data = get_printer_notify_pid_list( tdb, printername, True );
+
+ /* Add ourselves and increase the refcount. */
+
+ for (i = 0; i < data.dsize; i += 8) {
+ if (IVAL(data.dptr,i) == mypid) {
+ uint32 new_refcount = IVAL(data.dptr, i+4) + 1;
+ SIVAL(data.dptr, i+4, new_refcount);
+ break;
+ }
+ }
+
+ if (i == data.dsize) {
+ /* We weren't in the list. Realloc. */
+ data.dptr = (uint8 *)SMB_REALLOC(data.dptr, data.dsize + 8);
+ if (!data.dptr) {
+ DEBUG(0,("print_notify_register_pid: Relloc fail for printer %s\n",
+ printername));
+ goto done;
+ }
+ data.dsize += 8;
+ SIVAL(data.dptr,data.dsize - 8,mypid);
+ SIVAL(data.dptr,data.dsize - 4,1); /* Refcount. */
+ }
+
+ /* Store back the record. */
+ if (tdb_store_bystring(tdb, NOTIFY_PID_LIST_KEY, data, TDB_REPLACE) == -1) {
+ DEBUG(0,("print_notify_register_pid: Failed to update pid \
+list for printer %s\n", printername));
+ goto done;
+ }
+
+ ret = True;
+
+ done:
+
+ tdb_unlock_bystring(tdb, NOTIFY_PID_LIST_KEY);
+ if (pdb)
+ release_print_db(pdb);
+ SAFE_FREE(data.dptr);
+ return ret;
+}
+
+/****************************************************************************
+ Update an entry in the print tdb that will allow us to send notify
+ updates only to interested smbd's.
+****************************************************************************/
+
+bool print_notify_deregister_pid(int snum)
+{
+ TDB_DATA data;
+ struct tdb_print_db *pdb = NULL;
+ TDB_CONTEXT *tdb = NULL;
+ const char *printername;
+ uint32 mypid = (uint32)sys_getpid();
+ size_t i;
+ bool ret = False;
+
+ /* if ( snum == -1 ), we are deregister a print server handle
+ which means to deregister on all print queues */
+
+ if (snum == -1)
+ {
+ int num_services = lp_numservices();
+ int idx;
+
+ for ( idx=0; idx<num_services; idx++ ) {
+ if ( lp_snum_ok(idx) && lp_print_ok(idx) )
+ print_notify_deregister_pid(idx);
+ }
+
+ return True;
+ }
+ else /* deregister a specific printer */
+ {
+ printername = lp_const_servicename(snum);
+ pdb = get_print_db_byname(printername);
+ if (!pdb)
+ return False;
+ tdb = pdb->tdb;
+ }
+
+ if (tdb_lock_bystring_with_timeout(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) {
+ DEBUG(0,("print_notify_register_pid: Failed to lock \
+printer %s database\n", printername));
+ if (pdb)
+ release_print_db(pdb);
+ return False;
+ }
+
+ data = get_printer_notify_pid_list( tdb, printername, True );
+
+ /* Reduce refcount. Remove ourselves if zero. */
+
+ for (i = 0; i < data.dsize; ) {
+ if (IVAL(data.dptr,i) == mypid) {
+ uint32 refcount = IVAL(data.dptr, i+4);
+
+ refcount--;
+
+ if (refcount == 0) {
+ if (data.dsize - i > 8)
+ memmove( &data.dptr[i], &data.dptr[i+8], data.dsize - i - 8);
+ data.dsize -= 8;
+ continue;
+ }
+ SIVAL(data.dptr, i+4, refcount);
+ }
+
+ i += 8;
+ }
+
+ if (data.dsize == 0)
+ SAFE_FREE(data.dptr);
+
+ /* Store back the record. */
+ if (tdb_store_bystring(tdb, NOTIFY_PID_LIST_KEY, data, TDB_REPLACE) == -1) {
+ DEBUG(0,("print_notify_register_pid: Failed to update pid \
+list for printer %s\n", printername));
+ goto done;
+ }
+
+ ret = True;
+
+ done:
+
+ tdb_unlock_bystring(tdb, NOTIFY_PID_LIST_KEY);
+ if (pdb)
+ release_print_db(pdb);
+ SAFE_FREE(data.dptr);
+ return ret;
+}
+
+/****************************************************************************
+ Check if a jobid is valid. It is valid if it exists in the database.
+****************************************************************************/
+
+bool print_job_exists(const char* sharename, uint32 jobid)
+{
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+ bool ret;
+ uint32_t tmp;
+
+ if (!pdb)
+ return False;
+ ret = tdb_exists(pdb->tdb, print_key(jobid, &tmp));
+ release_print_db(pdb);
+ return ret;
+}
+
+/****************************************************************************
+ Give the fd used for a jobid.
+****************************************************************************/
+
+int print_job_fd(const char* sharename, uint32 jobid)
+{
+ struct printjob *pjob = print_job_find(sharename, jobid);
+ if (!pjob)
+ return -1;
+ /* don't allow another process to get this info - it is meaningless */
+ if (pjob->pid != sys_getpid())
+ return -1;
+ return pjob->fd;
+}
+
+/****************************************************************************
+ Give the filename used for a jobid.
+ Only valid for the process doing the spooling and when the job
+ has not been spooled.
+****************************************************************************/
+
+char *print_job_fname(const char* sharename, uint32 jobid)
+{
+ struct printjob *pjob = print_job_find(sharename, jobid);
+ if (!pjob || pjob->spooled || pjob->pid != sys_getpid())
+ return NULL;
+ return pjob->filename;
+}
+
+
+/****************************************************************************
+ Give the filename used for a jobid.
+ Only valid for the process doing the spooling and when the job
+ has not been spooled.
+****************************************************************************/
+
+NT_DEVICEMODE *print_job_devmode(const char* sharename, uint32 jobid)
+{
+ struct printjob *pjob = print_job_find(sharename, jobid);
+
+ if ( !pjob )
+ return NULL;
+
+ return pjob->nt_devmode;
+}
+
+/****************************************************************************
+ Set the place in the queue for a job.
+****************************************************************************/
+
+bool print_job_set_place(const char *sharename, uint32 jobid, int place)
+{
+ DEBUG(2,("print_job_set_place not implemented yet\n"));
+ return False;
+}
+
+/****************************************************************************
+ Set the name of a job. Only possible for owner.
+****************************************************************************/
+
+bool print_job_set_name(const char *sharename, uint32 jobid, char *name)
+{
+ struct printjob *pjob;
+
+ pjob = print_job_find(sharename, jobid);
+ if (!pjob || pjob->pid != sys_getpid())
+ return False;
+
+ fstrcpy(pjob->jobname, name);
+ return pjob_store(sharename, jobid, pjob);
+}
+
+/***************************************************************************
+ Remove a jobid from the 'jobs changed' list.
+***************************************************************************/
+
+static bool remove_from_jobs_changed(const char* sharename, uint32 jobid)
+{
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+ TDB_DATA data, key;
+ size_t job_count, i;
+ bool ret = False;
+ bool gotlock = False;
+
+ if (!pdb) {
+ return False;
+ }
+
+ ZERO_STRUCT(data);
+
+ key = string_tdb_data("INFO/jobs_changed");
+
+ if (tdb_chainlock_with_timeout(pdb->tdb, key, 5) == -1)
+ goto out;
+
+ gotlock = True;
+
+ data = tdb_fetch(pdb->tdb, key);
+
+ if (data.dptr == NULL || data.dsize == 0 || (data.dsize % 4 != 0))
+ goto out;
+
+ job_count = data.dsize / 4;
+ for (i = 0; i < job_count; i++) {
+ uint32 ch_jobid;
+
+ ch_jobid = IVAL(data.dptr, i*4);
+ if (ch_jobid == jobid) {
+ if (i < job_count -1 )
+ memmove(data.dptr + (i*4), data.dptr + (i*4) + 4, (job_count - i - 1)*4 );
+ data.dsize -= 4;
+ if (tdb_store(pdb->tdb, key, data, TDB_REPLACE) == -1)
+ goto out;
+ break;
+ }
+ }
+
+ ret = True;
+ out:
+
+ if (gotlock)
+ tdb_chainunlock(pdb->tdb, key);
+ SAFE_FREE(data.dptr);
+ release_print_db(pdb);
+ if (ret)
+ DEBUG(10,("remove_from_jobs_changed: removed jobid %u\n", (unsigned int)jobid ));
+ else
+ DEBUG(10,("remove_from_jobs_changed: Failed to remove jobid %u\n", (unsigned int)jobid ));
+ return ret;
+}
+
+/****************************************************************************
+ Delete a print job - don't update queue.
+****************************************************************************/
+
+static bool print_job_delete1(int snum, uint32 jobid)
+{
+ const char* sharename = lp_const_servicename(snum);
+ struct printjob *pjob = print_job_find(sharename, jobid);
+ int result = 0;
+ struct printif *current_printif = get_printer_fns( snum );
+
+ if (!pjob)
+ return False;
+
+ /*
+ * If already deleting just return.
+ */
+
+ if (pjob->status == LPQ_DELETING)
+ return True;
+
+ /* Hrm - we need to be able to cope with deleting a job before it
+ has reached the spooler. Just mark it as LPQ_DELETING and
+ let the print_queue_update() code rmeove the record */
+
+
+ if (pjob->sysjob == -1) {
+ DEBUG(5, ("attempt to delete job %u not seen by lpr\n", (unsigned int)jobid));
+ }
+
+ /* Set the tdb entry to be deleting. */
+
+ pjob->status = LPQ_DELETING;
+ pjob_store(sharename, jobid, pjob);
+
+ if (pjob->spooled && pjob->sysjob != -1)
+ {
+ result = (*(current_printif->job_delete))(
+ PRINTERNAME(snum),
+ lp_lprmcommand(snum),
+ pjob);
+
+ /* Delete the tdb entry if the delete succeeded or the job hasn't
+ been spooled. */
+
+ if (result == 0) {
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+ int njobs = 1;
+
+ if (!pdb)
+ return False;
+ pjob_delete(sharename, jobid);
+ /* Ensure we keep a rough count of the number of total jobs... */
+ tdb_change_int32_atomic(pdb->tdb, "INFO/total_jobs", &njobs, -1);
+ release_print_db(pdb);
+ }
+ }
+
+ remove_from_jobs_changed( sharename, jobid );
+
+ return (result == 0);
+}
+
+/****************************************************************************
+ Return true if the current user owns the print job.
+****************************************************************************/
+
+static bool is_owner(struct auth_serversupplied_info *server_info,
+ const char *servicename,
+ uint32 jobid)
+{
+ struct printjob *pjob = print_job_find(servicename, jobid);
+
+ if (!pjob || !server_info)
+ return False;
+
+ return strequal(pjob->user, server_info->sanitized_username);
+}
+
+/****************************************************************************
+ Delete a print job.
+****************************************************************************/
+
+bool print_job_delete(struct auth_serversupplied_info *server_info, int snum,
+ uint32 jobid, WERROR *errcode)
+{
+ const char* sharename = lp_const_servicename( snum );
+ struct printjob *pjob;
+ bool owner;
+ char *fname;
+
+ *errcode = WERR_OK;
+
+ owner = is_owner(server_info, lp_const_servicename(snum), jobid);
+
+ /* Check access against security descriptor or whether the user
+ owns their job. */
+
+ if (!owner &&
+ !print_access_check(server_info, snum, JOB_ACCESS_ADMINISTER)) {
+ DEBUG(3, ("delete denied by security descriptor\n"));
+ *errcode = WERR_ACCESS_DENIED;
+
+ /* BEGIN_ADMIN_LOG */
+ sys_adminlog( LOG_ERR,
+ "Permission denied-- user not allowed to delete, \
+pause, or resume print job. User name: %s. Printer name: %s.",
+ uidtoname(server_info->utok.uid),
+ PRINTERNAME(snum) );
+ /* END_ADMIN_LOG */
+
+ return False;
+ }
+
+ /*
+ * get the spooled filename of the print job
+ * if this works, then the file has not been spooled
+ * to the underlying print system. Just delete the
+ * spool file & return.
+ */
+
+ if ( (fname = print_job_fname( sharename, jobid )) != NULL )
+ {
+ /* remove the spool file */
+ DEBUG(10,("print_job_delete: Removing spool file [%s]\n", fname ));
+ if ( unlink( fname ) == -1 ) {
+ *errcode = map_werror_from_unix(errno);
+ return False;
+ }
+ }
+
+ if (!print_job_delete1(snum, jobid)) {
+ *errcode = WERR_ACCESS_DENIED;
+ return False;
+ }
+
+ /* force update the database and say the delete failed if the
+ job still exists */
+
+ print_queue_update(snum, True);
+
+ pjob = print_job_find(sharename, jobid);
+ if ( pjob && (pjob->status != LPQ_DELETING) )
+ *errcode = WERR_ACCESS_DENIED;
+
+ return (pjob == NULL );
+}
+
+/****************************************************************************
+ Pause a job.
+****************************************************************************/
+
+bool print_job_pause(struct auth_serversupplied_info *server_info, int snum,
+ uint32 jobid, WERROR *errcode)
+{
+ const char* sharename = lp_const_servicename(snum);
+ struct printjob *pjob;
+ int ret = -1;
+ struct printif *current_printif = get_printer_fns( snum );
+
+ pjob = print_job_find(sharename, jobid);
+
+ if (!pjob || !server_info) {
+ DEBUG(10, ("print_job_pause: no pjob or user for jobid %u\n",
+ (unsigned int)jobid ));
+ return False;
+ }
+
+ if (!pjob->spooled || pjob->sysjob == -1) {
+ DEBUG(10, ("print_job_pause: not spooled or bad sysjob = %d for jobid %u\n",
+ (int)pjob->sysjob, (unsigned int)jobid ));
+ return False;
+ }
+
+ if (!is_owner(server_info, lp_const_servicename(snum), jobid) &&
+ !print_access_check(server_info, snum, JOB_ACCESS_ADMINISTER)) {
+ DEBUG(3, ("pause denied by security descriptor\n"));
+
+ /* BEGIN_ADMIN_LOG */
+ sys_adminlog( LOG_ERR,
+ "Permission denied-- user not allowed to delete, \
+pause, or resume print job. User name: %s. Printer name: %s.",
+ uidtoname(server_info->utok.uid),
+ PRINTERNAME(snum) );
+ /* END_ADMIN_LOG */
+
+ *errcode = WERR_ACCESS_DENIED;
+ return False;
+ }
+
+ /* need to pause the spooled entry */
+ ret = (*(current_printif->job_pause))(snum, pjob);
+
+ if (ret != 0) {
+ *errcode = WERR_INVALID_PARAM;
+ return False;
+ }
+
+ /* force update the database */
+ print_cache_flush(lp_const_servicename(snum));
+
+ /* Send a printer notify message */
+
+ notify_job_status(sharename, jobid, JOB_STATUS_PAUSED);
+
+ /* how do we tell if this succeeded? */
+
+ return True;
+}
+
+/****************************************************************************
+ Resume a job.
+****************************************************************************/
+
+bool print_job_resume(struct auth_serversupplied_info *server_info, int snum,
+ uint32 jobid, WERROR *errcode)
+{
+ const char *sharename = lp_const_servicename(snum);
+ struct printjob *pjob;
+ int ret;
+ struct printif *current_printif = get_printer_fns( snum );
+
+ pjob = print_job_find(sharename, jobid);
+
+ if (!pjob || !server_info) {
+ DEBUG(10, ("print_job_resume: no pjob or user for jobid %u\n",
+ (unsigned int)jobid ));
+ return False;
+ }
+
+ if (!pjob->spooled || pjob->sysjob == -1) {
+ DEBUG(10, ("print_job_resume: not spooled or bad sysjob = %d for jobid %u\n",
+ (int)pjob->sysjob, (unsigned int)jobid ));
+ return False;
+ }
+
+ if (!is_owner(server_info, lp_const_servicename(snum), jobid) &&
+ !print_access_check(server_info, snum, JOB_ACCESS_ADMINISTER)) {
+ DEBUG(3, ("resume denied by security descriptor\n"));
+ *errcode = WERR_ACCESS_DENIED;
+
+ /* BEGIN_ADMIN_LOG */
+ sys_adminlog( LOG_ERR,
+ "Permission denied-- user not allowed to delete, \
+pause, or resume print job. User name: %s. Printer name: %s.",
+ uidtoname(server_info->utok.uid),
+ PRINTERNAME(snum) );
+ /* END_ADMIN_LOG */
+ return False;
+ }
+
+ ret = (*(current_printif->job_resume))(snum, pjob);
+
+ if (ret != 0) {
+ *errcode = WERR_INVALID_PARAM;
+ return False;
+ }
+
+ /* force update the database */
+ print_cache_flush(lp_const_servicename(snum));
+
+ /* Send a printer notify message */
+
+ notify_job_status(sharename, jobid, JOB_STATUS_QUEUED);
+
+ return True;
+}
+
+/****************************************************************************
+ Write to a print file.
+****************************************************************************/
+
+ssize_t print_job_write(int snum, uint32 jobid, const char *buf, SMB_OFF_T pos, size_t size)
+{
+ const char* sharename = lp_const_servicename(snum);
+ int return_code;
+ struct printjob *pjob;
+
+ pjob = print_job_find(sharename, jobid);
+
+ if (!pjob)
+ return -1;
+ /* don't allow another process to get this info - it is meaningless */
+ if (pjob->pid != sys_getpid())
+ return -1;
+
+ return_code = write_data_at_offset(pjob->fd, buf, size, pos);
+
+ if (return_code>0) {
+ pjob->size += size;
+ pjob_store(sharename, jobid, pjob);
+ }
+ return return_code;
+}
+
+/****************************************************************************
+ Get the queue status - do not update if db is out of date.
+****************************************************************************/
+
+static int get_queue_status(const char* sharename, print_status_struct *status)
+{
+ fstring keystr;
+ TDB_DATA data;
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+ int len;
+
+ if (status) {
+ ZERO_STRUCTP(status);
+ }
+
+ if (!pdb)
+ return 0;
+
+ if (status) {
+ fstr_sprintf(keystr, "STATUS/%s", sharename);
+ data = tdb_fetch(pdb->tdb, string_tdb_data(keystr));
+ if (data.dptr) {
+ if (data.dsize == sizeof(print_status_struct))
+ /* this memcpy is ok since the status struct was
+ not packed before storing it in the tdb */
+ memcpy(status, data.dptr, sizeof(print_status_struct));
+ SAFE_FREE(data.dptr);
+ }
+ }
+ len = tdb_fetch_int32(pdb->tdb, "INFO/total_jobs");
+ release_print_db(pdb);
+ return (len == -1 ? 0 : len);
+}
+
+/****************************************************************************
+ Determine the number of jobs in a queue.
+****************************************************************************/
+
+int print_queue_length(int snum, print_status_struct *pstatus)
+{
+ const char* sharename = lp_const_servicename( snum );
+ print_status_struct status;
+ int len;
+
+ ZERO_STRUCT( status );
+
+ /* make sure the database is up to date */
+ if (print_cache_expired(lp_const_servicename(snum), True))
+ print_queue_update(snum, False);
+
+ /* also fetch the queue status */
+ memset(&status, 0, sizeof(status));
+ len = get_queue_status(sharename, &status);
+
+ if (pstatus)
+ *pstatus = status;
+
+ return len;
+}
+
+/***************************************************************************
+ Allocate a jobid. Hold the lock for as short a time as possible.
+***************************************************************************/
+
+static bool allocate_print_jobid(struct tdb_print_db *pdb, int snum, const char *sharename, uint32 *pjobid)
+{
+ int i;
+ uint32 jobid;
+
+ *pjobid = (uint32)-1;
+
+ for (i = 0; i < 3; i++) {
+ /* Lock the database - only wait 20 seconds. */
+ if (tdb_lock_bystring_with_timeout(pdb->tdb, "INFO/nextjob", 20) == -1) {
+ DEBUG(0,("allocate_print_jobid: failed to lock printing database %s\n", sharename));
+ return False;
+ }
+
+ if (!tdb_fetch_uint32(pdb->tdb, "INFO/nextjob", &jobid)) {
+ if (tdb_error(pdb->tdb) != TDB_ERR_NOEXIST) {
+ DEBUG(0, ("allocate_print_jobid: failed to fetch INFO/nextjob for print queue %s\n",
+ sharename));
+ return False;
+ }
+ jobid = 0;
+ }
+
+ jobid = NEXT_JOBID(jobid);
+
+ if (tdb_store_int32(pdb->tdb, "INFO/nextjob", jobid)==-1) {
+ DEBUG(3, ("allocate_print_jobid: failed to store INFO/nextjob.\n"));
+ tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
+ return False;
+ }
+
+ /* We've finished with the INFO/nextjob lock. */
+ tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
+
+ if (!print_job_exists(sharename, jobid))
+ break;
+ }
+
+ if (i > 2) {
+ DEBUG(0, ("allocate_print_jobid: failed to allocate a print job for queue %s\n",
+ sharename));
+ /* Probably full... */
+ errno = ENOSPC;
+ return False;
+ }
+
+ /* Store a dummy placeholder. */
+ {
+ uint32_t tmp;
+ TDB_DATA dum;
+ dum.dptr = NULL;
+ dum.dsize = 0;
+ if (tdb_store(pdb->tdb, print_key(jobid, &tmp), dum,
+ TDB_INSERT) == -1) {
+ DEBUG(3, ("allocate_print_jobid: jobid (%d) failed to store placeholder.\n",
+ jobid ));
+ return False;
+ }
+ }
+
+ *pjobid = jobid;
+ return True;
+}
+
+/***************************************************************************
+ Append a jobid to the 'jobs changed' list.
+***************************************************************************/
+
+static bool add_to_jobs_changed(struct tdb_print_db *pdb, uint32 jobid)
+{
+ TDB_DATA data;
+ uint32 store_jobid;
+
+ SIVAL(&store_jobid, 0, jobid);
+ data.dptr = (uint8 *)&store_jobid;
+ data.dsize = 4;
+
+ DEBUG(10,("add_to_jobs_changed: Added jobid %u\n", (unsigned int)jobid ));
+
+ return (tdb_append(pdb->tdb, string_tdb_data("INFO/jobs_changed"),
+ data) == 0);
+}
+
+/***************************************************************************
+ Start spooling a job - return the jobid.
+***************************************************************************/
+
+uint32 print_job_start(struct auth_serversupplied_info *server_info, int snum,
+ char *jobname, NT_DEVICEMODE *nt_devmode )
+{
+ uint32 jobid;
+ char *path;
+ struct printjob pjob;
+ const char *sharename = lp_const_servicename(snum);
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+ int njobs;
+
+ errno = 0;
+
+ if (!pdb)
+ return (uint32)-1;
+
+ if (!print_access_check(server_info, snum, PRINTER_ACCESS_USE)) {
+ DEBUG(3, ("print_job_start: job start denied by security descriptor\n"));
+ release_print_db(pdb);
+ return (uint32)-1;
+ }
+
+ if (!print_time_access_check(lp_servicename(snum))) {
+ DEBUG(3, ("print_job_start: job start denied by time check\n"));
+ release_print_db(pdb);
+ return (uint32)-1;
+ }
+
+ path = lp_pathname(snum);
+
+ /* see if we have sufficient disk space */
+ if (lp_minprintspace(snum)) {
+ SMB_BIG_UINT dspace, dsize;
+ if (sys_fsusage(path, &dspace, &dsize) == 0 &&
+ dspace < 2*(SMB_BIG_UINT)lp_minprintspace(snum)) {
+ DEBUG(3, ("print_job_start: disk space check failed.\n"));
+ release_print_db(pdb);
+ errno = ENOSPC;
+ return (uint32)-1;
+ }
+ }
+
+ /* for autoloaded printers, check that the printcap entry still exists */
+ if (lp_autoloaded(snum) && !pcap_printername_ok(lp_const_servicename(snum))) {
+ DEBUG(3, ("print_job_start: printer name %s check failed.\n", lp_const_servicename(snum) ));
+ release_print_db(pdb);
+ errno = ENOENT;
+ return (uint32)-1;
+ }
+
+ /* Insure the maximum queue size is not violated */
+ if ((njobs = print_queue_length(snum,NULL)) > lp_maxprintjobs(snum)) {
+ DEBUG(3, ("print_job_start: Queue %s number of jobs (%d) larger than max printjobs per queue (%d).\n",
+ sharename, njobs, lp_maxprintjobs(snum) ));
+ release_print_db(pdb);
+ errno = ENOSPC;
+ return (uint32)-1;
+ }
+
+ DEBUG(10,("print_job_start: Queue %s number of jobs (%d), max printjobs = %d\n",
+ sharename, njobs, lp_maxprintjobs(snum) ));
+
+ if (!allocate_print_jobid(pdb, snum, sharename, &jobid))
+ goto fail;
+
+ /* create the database entry */
+
+ ZERO_STRUCT(pjob);
+
+ pjob.pid = sys_getpid();
+ pjob.sysjob = -1;
+ pjob.fd = -1;
+ pjob.starttime = time(NULL);
+ pjob.status = LPQ_SPOOLING;
+ pjob.size = 0;
+ pjob.spooled = False;
+ pjob.smbjob = True;
+ pjob.nt_devmode = nt_devmode;
+
+ fstrcpy(pjob.jobname, jobname);
+
+ fstrcpy(pjob.user, lp_printjob_username(snum));
+ standard_sub_advanced(sharename, server_info->sanitized_username,
+ path, server_info->utok.gid,
+ server_info->sanitized_username,
+ pdb_get_domain(server_info->sam_account),
+ pjob.user, sizeof(pjob.user)-1);
+ /* ensure NULL termination */
+ pjob.user[sizeof(pjob.user)-1] = '\0';
+
+ fstrcpy(pjob.queuename, lp_const_servicename(snum));
+
+ /* we have a job entry - now create the spool file */
+ slprintf(pjob.filename, sizeof(pjob.filename)-1, "%s/%s%.8u.XXXXXX",
+ path, PRINT_SPOOL_PREFIX, (unsigned int)jobid);
+ pjob.fd = smb_mkstemp(pjob.filename);
+
+ if (pjob.fd == -1) {
+ if (errno == EACCES) {
+ /* Common setup error, force a report. */
+ DEBUG(0, ("print_job_start: insufficient permissions \
+to open spool file %s.\n", pjob.filename));
+ } else {
+ /* Normal case, report at level 3 and above. */
+ DEBUG(3, ("print_job_start: can't open spool file %s,\n", pjob.filename));
+ DEBUGADD(3, ("errno = %d (%s).\n", errno, strerror(errno)));
+ }
+ goto fail;
+ }
+
+ pjob_store(sharename, jobid, &pjob);
+
+ /* Update the 'jobs changed' entry used by print_queue_status. */
+ add_to_jobs_changed(pdb, jobid);
+
+ /* Ensure we keep a rough count of the number of total jobs... */
+ tdb_change_int32_atomic(pdb->tdb, "INFO/total_jobs", &njobs, 1);
+
+ release_print_db(pdb);
+
+ return jobid;
+
+ fail:
+ if (jobid != -1)
+ pjob_delete(sharename, jobid);
+
+ release_print_db(pdb);
+
+ DEBUG(3, ("print_job_start: returning fail. Error = %s\n", strerror(errno) ));
+ return (uint32)-1;
+}
+
+/****************************************************************************
+ Update the number of pages spooled to jobid
+****************************************************************************/
+
+void print_job_endpage(int snum, uint32 jobid)
+{
+ const char* sharename = lp_const_servicename(snum);
+ struct printjob *pjob;
+
+ pjob = print_job_find(sharename, jobid);
+ if (!pjob)
+ return;
+ /* don't allow another process to get this info - it is meaningless */
+ if (pjob->pid != sys_getpid())
+ return;
+
+ pjob->page_count++;
+ pjob_store(sharename, jobid, pjob);
+}
+
+/****************************************************************************
+ Print a file - called on closing the file. This spools the job.
+ If normal close is false then we're tearing down the jobs - treat as an
+ error.
+****************************************************************************/
+
+bool print_job_end(int snum, uint32 jobid, enum file_close_type close_type)
+{
+ const char* sharename = lp_const_servicename(snum);
+ struct printjob *pjob;
+ int ret;
+ SMB_STRUCT_STAT sbuf;
+ struct printif *current_printif = get_printer_fns( snum );
+
+ pjob = print_job_find(sharename, jobid);
+
+ if (!pjob)
+ return False;
+
+ if (pjob->spooled || pjob->pid != sys_getpid())
+ return False;
+
+ if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
+ (sys_fstat(pjob->fd, &sbuf) == 0)) {
+ pjob->size = sbuf.st_size;
+ close(pjob->fd);
+ pjob->fd = -1;
+ } else {
+
+ /*
+ * Not a normal close or we couldn't stat the job file,
+ * so something has gone wrong. Cleanup.
+ */
+ close(pjob->fd);
+ pjob->fd = -1;
+ DEBUG(3,("print_job_end: failed to stat file for jobid %d\n", jobid ));
+ goto fail;
+ }
+
+ /* Technically, this is not quite right. If the printer has a separator
+ * page turned on, the NT spooler prints the separator page even if the
+ * print job is 0 bytes. 010215 JRR */
+ if (pjob->size == 0 || pjob->status == LPQ_DELETING) {
+ /* don't bother spooling empty files or something being deleted. */
+ DEBUG(5,("print_job_end: canceling spool of %s (%s)\n",
+ pjob->filename, pjob->size ? "deleted" : "zero length" ));
+ unlink(pjob->filename);
+ pjob_delete(sharename, jobid);
+ return True;
+ }
+
+ pjob->smbjob = jobid;
+
+ ret = (*(current_printif->job_submit))(snum, pjob);
+
+ if (ret)
+ goto fail;
+
+ /* The print job has been successfully handed over to the back-end */
+
+ pjob->spooled = True;
+ pjob->status = LPQ_QUEUED;
+ pjob_store(sharename, jobid, pjob);
+
+ /* make sure the database is up to date */
+ if (print_cache_expired(lp_const_servicename(snum), True))
+ print_queue_update(snum, False);
+
+ return True;
+
+fail:
+
+ /* The print job was not successfully started. Cleanup */
+ /* Still need to add proper error return propagation! 010122:JRR */
+ unlink(pjob->filename);
+ pjob_delete(sharename, jobid);
+ return False;
+}
+
+/****************************************************************************
+ Get a snapshot of jobs in the system without traversing.
+****************************************************************************/
+
+static bool get_stored_queue_info(struct tdb_print_db *pdb, int snum, int *pcount, print_queue_struct **ppqueue)
+{
+ TDB_DATA data, cgdata;
+ print_queue_struct *queue = NULL;
+ uint32 qcount = 0;
+ uint32 extra_count = 0;
+ int total_count = 0;
+ size_t len = 0;
+ uint32 i;
+ int max_reported_jobs = lp_max_reported_jobs(snum);
+ bool ret = False;
+ const char* sharename = lp_servicename(snum);
+
+ /* make sure the database is up to date */
+ if (print_cache_expired(lp_const_servicename(snum), True))
+ print_queue_update(snum, False);
+
+ *pcount = 0;
+ *ppqueue = NULL;
+
+ ZERO_STRUCT(data);
+ ZERO_STRUCT(cgdata);
+
+ /* Get the stored queue data. */
+ data = tdb_fetch(pdb->tdb, string_tdb_data("INFO/linear_queue_array"));
+
+ if (data.dptr && data.dsize >= sizeof(qcount))
+ len += tdb_unpack(data.dptr + len, data.dsize - len, "d", &qcount);
+
+ /* Get the changed jobs list. */
+ cgdata = tdb_fetch(pdb->tdb, string_tdb_data("INFO/jobs_changed"));
+ if (cgdata.dptr != NULL && (cgdata.dsize % 4 == 0))
+ extra_count = cgdata.dsize/4;
+
+ DEBUG(5,("get_stored_queue_info: qcount = %u, extra_count = %u\n", (unsigned int)qcount, (unsigned int)extra_count));
+
+ /* Allocate the queue size. */
+ if (qcount == 0 && extra_count == 0)
+ goto out;
+
+ if ((queue = SMB_MALLOC_ARRAY(print_queue_struct, qcount + extra_count)) == NULL)
+ goto out;
+
+ /* Retrieve the linearised queue data. */
+
+ for( i = 0; i < qcount; i++) {
+ uint32 qjob, qsize, qpage_count, qstatus, qpriority, qtime;
+ len += tdb_unpack(data.dptr + len, data.dsize - len, "ddddddff",
+ &qjob,
+ &qsize,
+ &qpage_count,
+ &qstatus,
+ &qpriority,
+ &qtime,
+ queue[i].fs_user,
+ queue[i].fs_file);
+ queue[i].job = qjob;
+ queue[i].size = qsize;
+ queue[i].page_count = qpage_count;
+ queue[i].status = qstatus;
+ queue[i].priority = qpriority;
+ queue[i].time = qtime;
+ }
+
+ total_count = qcount;
+
+ /* Add in the changed jobids. */
+ for( i = 0; i < extra_count; i++) {
+ uint32 jobid;
+ struct printjob *pjob;
+
+ jobid = IVAL(cgdata.dptr, i*4);
+ DEBUG(5,("get_stored_queue_info: changed job = %u\n", (unsigned int)jobid));
+ pjob = print_job_find(lp_const_servicename(snum), jobid);
+ if (!pjob) {
+ DEBUG(5,("get_stored_queue_info: failed to find changed job = %u\n", (unsigned int)jobid));
+ remove_from_jobs_changed(sharename, jobid);
+ continue;
+ }
+
+ queue[total_count].job = jobid;
+ queue[total_count].size = pjob->size;
+ queue[total_count].page_count = pjob->page_count;
+ queue[total_count].status = pjob->status;
+ queue[total_count].priority = 1;
+ queue[total_count].time = pjob->starttime;
+ fstrcpy(queue[total_count].fs_user, pjob->user);
+ fstrcpy(queue[total_count].fs_file, pjob->jobname);
+ total_count++;
+ }
+
+ /* Sort the queue by submission time otherwise they are displayed
+ in hash order. */
+
+ qsort(queue, total_count, sizeof(print_queue_struct), QSORT_CAST(printjob_comp));
+
+ DEBUG(5,("get_stored_queue_info: total_count = %u\n", (unsigned int)total_count));
+
+ if (max_reported_jobs && total_count > max_reported_jobs)
+ total_count = max_reported_jobs;
+
+ *ppqueue = queue;
+ *pcount = total_count;
+
+ ret = True;
+
+ out:
+
+ SAFE_FREE(data.dptr);
+ SAFE_FREE(cgdata.dptr);
+ return ret;
+}
+
+/****************************************************************************
+ Get a printer queue listing.
+ set queue = NULL and status = NULL if you just want to update the cache
+****************************************************************************/
+
+int print_queue_status(int snum,
+ print_queue_struct **ppqueue,
+ print_status_struct *status)
+{
+ fstring keystr;
+ TDB_DATA data, key;
+ const char *sharename;
+ struct tdb_print_db *pdb;
+ int count = 0;
+
+ /* make sure the database is up to date */
+
+ if (print_cache_expired(lp_const_servicename(snum), True))
+ print_queue_update(snum, False);
+
+ /* return if we are done */
+ if ( !ppqueue || !status )
+ return 0;
+
+ *ppqueue = NULL;
+ sharename = lp_const_servicename(snum);
+ pdb = get_print_db_byname(sharename);
+
+ if (!pdb)
+ return 0;
+
+ /*
+ * Fetch the queue status. We must do this first, as there may
+ * be no jobs in the queue.
+ */
+
+ ZERO_STRUCTP(status);
+ slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", sharename);
+ key = string_tdb_data(keystr);
+
+ data = tdb_fetch(pdb->tdb, key);
+ if (data.dptr) {
+ if (data.dsize == sizeof(*status)) {
+ /* this memcpy is ok since the status struct was
+ not packed before storing it in the tdb */
+ memcpy(status, data.dptr, sizeof(*status));
+ }
+ SAFE_FREE(data.dptr);
+ }
+
+ /*
+ * Now, fetch the print queue information. We first count the number
+ * of entries, and then only retrieve the queue if necessary.
+ */
+
+ if (!get_stored_queue_info(pdb, snum, &count, ppqueue)) {
+ release_print_db(pdb);
+ return 0;
+ }
+
+ release_print_db(pdb);
+ return count;
+}
+
+/****************************************************************************
+ Pause a queue.
+****************************************************************************/
+
+bool print_queue_pause(struct auth_serversupplied_info *server_info, int snum,
+ WERROR *errcode)
+{
+ int ret;
+ struct printif *current_printif = get_printer_fns( snum );
+
+ if (!print_access_check(server_info, snum,
+ PRINTER_ACCESS_ADMINISTER)) {
+ *errcode = WERR_ACCESS_DENIED;
+ return False;
+ }
+
+
+ become_root();
+
+ ret = (*(current_printif->queue_pause))(snum);
+
+ unbecome_root();
+
+ if (ret != 0) {
+ *errcode = WERR_INVALID_PARAM;
+ return False;
+ }
+
+ /* force update the database */
+ print_cache_flush(lp_const_servicename(snum));
+
+ /* Send a printer notify message */
+
+ notify_printer_status(snum, PRINTER_STATUS_PAUSED);
+
+ return True;
+}
+
+/****************************************************************************
+ Resume a queue.
+****************************************************************************/
+
+bool print_queue_resume(struct auth_serversupplied_info *server_info, int snum,
+ WERROR *errcode)
+{
+ int ret;
+ struct printif *current_printif = get_printer_fns( snum );
+
+ if (!print_access_check(server_info, snum,
+ PRINTER_ACCESS_ADMINISTER)) {
+ *errcode = WERR_ACCESS_DENIED;
+ return False;
+ }
+
+ become_root();
+
+ ret = (*(current_printif->queue_resume))(snum);
+
+ unbecome_root();
+
+ if (ret != 0) {
+ *errcode = WERR_INVALID_PARAM;
+ return False;
+ }
+
+ /* make sure the database is up to date */
+ if (print_cache_expired(lp_const_servicename(snum), True))
+ print_queue_update(snum, True);
+
+ /* Send a printer notify message */
+
+ notify_printer_status(snum, PRINTER_STATUS_OK);
+
+ return True;
+}
+
+/****************************************************************************
+ Purge a queue - implemented by deleting all jobs that we can delete.
+****************************************************************************/
+
+bool print_queue_purge(struct auth_serversupplied_info *server_info, int snum,
+ WERROR *errcode)
+{
+ print_queue_struct *queue;
+ print_status_struct status;
+ int njobs, i;
+ bool can_job_admin;
+
+ /* Force and update so the count is accurate (i.e. not a cached count) */
+ print_queue_update(snum, True);
+
+ can_job_admin = print_access_check(server_info, snum,
+ JOB_ACCESS_ADMINISTER);
+ njobs = print_queue_status(snum, &queue, &status);
+
+ if ( can_job_admin )
+ become_root();
+
+ for (i=0;i<njobs;i++) {
+ bool owner = is_owner(server_info, lp_const_servicename(snum),
+ queue[i].job);
+
+ if (owner || can_job_admin) {
+ print_job_delete1(snum, queue[i].job);
+ }
+ }
+
+ if ( can_job_admin )
+ unbecome_root();
+
+ /* update the cache */
+ print_queue_update( snum, True );
+
+ SAFE_FREE(queue);
+
+ return True;
+}
diff --git a/source3/printing/printing_db.c b/source3/printing/printing_db.c
new file mode 100644
index 0000000000..94319f96d0
--- /dev/null
+++ b/source3/printing/printing_db.c
@@ -0,0 +1,215 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ printing backend routines
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Jeremy Allison 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "printing.h"
+
+static struct tdb_print_db *print_db_head;
+
+/****************************************************************************
+ Function to find or create the printer specific job tdb given a printername.
+ Limits the number of tdb's open to MAX_PRINT_DBS_OPEN.
+****************************************************************************/
+
+struct tdb_print_db *get_print_db_byname(const char *printername)
+{
+ struct tdb_print_db *p = NULL, *last_entry = NULL;
+ int num_open = 0;
+ char *printdb_path = NULL;
+ bool done_become_root = False;
+
+ SMB_ASSERT(printername != NULL);
+
+ for (p = print_db_head, last_entry = print_db_head; p; p = p->next) {
+ /* Ensure the list terminates... JRA. */
+ SMB_ASSERT(p->next != print_db_head);
+
+ if (p->tdb && strequal(p->printer_name, printername)) {
+ DLIST_PROMOTE(print_db_head, p);
+ p->ref_count++;
+ return p;
+ }
+ num_open++;
+ last_entry = p;
+ }
+
+ /* Not found. */
+ if (num_open >= MAX_PRINT_DBS_OPEN) {
+ /* Try and recycle the last entry. */
+ if (print_db_head && last_entry) {
+ DLIST_PROMOTE(print_db_head, last_entry);
+ }
+
+ for (p = print_db_head; p; p = p->next) {
+ if (p->ref_count)
+ continue;
+ if (p->tdb) {
+ if (tdb_close(print_db_head->tdb)) {
+ DEBUG(0,("get_print_db: Failed to close tdb for printer %s\n",
+ print_db_head->printer_name ));
+ return NULL;
+ }
+ }
+ p->tdb = NULL;
+ p->ref_count = 0;
+ memset(p->printer_name, '\0', sizeof(p->printer_name));
+ break;
+ }
+ if (p && print_db_head) {
+ DLIST_PROMOTE(print_db_head, p);
+ p = print_db_head;
+ }
+ }
+
+ if (!p) {
+ /* Create one. */
+ p = SMB_MALLOC_P(struct tdb_print_db);
+ if (!p) {
+ DEBUG(0,("get_print_db: malloc fail !\n"));
+ return NULL;
+ }
+ ZERO_STRUCTP(p);
+ DLIST_ADD(print_db_head, p);
+ }
+
+ if (asprintf(&printdb_path, "%s%s.tdb",
+ lock_path("printing/"),
+ printername) < 0) {
+ DLIST_REMOVE(print_db_head, p);
+ SAFE_FREE(p);
+ return NULL;
+ }
+
+ if (geteuid() != 0) {
+ become_root();
+ done_become_root = True;
+ }
+
+ p->tdb = tdb_open_log(printdb_path, 5000, TDB_DEFAULT, O_RDWR|O_CREAT,
+ 0600);
+
+ if (done_become_root)
+ unbecome_root();
+
+ if (!p->tdb) {
+ DEBUG(0,("get_print_db: Failed to open printer backend database %s.\n",
+ printdb_path ));
+ DLIST_REMOVE(print_db_head, p);
+ SAFE_FREE(printdb_path);
+ SAFE_FREE(p);
+ return NULL;
+ }
+ SAFE_FREE(printdb_path);
+ fstrcpy(p->printer_name, printername);
+ p->ref_count++;
+ return p;
+}
+
+/***************************************************************************
+ Remove a reference count.
+****************************************************************************/
+
+void release_print_db( struct tdb_print_db *pdb)
+{
+ pdb->ref_count--;
+ SMB_ASSERT(pdb->ref_count >= 0);
+}
+
+/***************************************************************************
+ Close all open print db entries.
+****************************************************************************/
+
+void close_all_print_db(void)
+{
+ struct tdb_print_db *p = NULL, *next_p = NULL;
+
+ for (p = print_db_head; p; p = next_p) {
+ next_p = p->next;
+
+ if (p->tdb)
+ tdb_close(p->tdb);
+ DLIST_REMOVE(print_db_head, p);
+ ZERO_STRUCTP(p);
+ SAFE_FREE(p);
+ }
+}
+
+
+/****************************************************************************
+ Fetch and clean the pid_t record list for all pids interested in notify
+ messages. data needs freeing on exit.
+****************************************************************************/
+
+TDB_DATA get_printer_notify_pid_list(TDB_CONTEXT *tdb, const char *printer_name, bool cleanlist)
+{
+ TDB_DATA data;
+ size_t i;
+
+ ZERO_STRUCT(data);
+
+ data = tdb_fetch_bystring( tdb, NOTIFY_PID_LIST_KEY );
+
+ if (!data.dptr) {
+ ZERO_STRUCT(data);
+ return data;
+ }
+
+ if (data.dsize % 8) {
+ DEBUG(0,("get_printer_notify_pid_list: Size of record for printer %s not a multiple of 8 !\n", printer_name ));
+ tdb_delete_bystring(tdb, NOTIFY_PID_LIST_KEY );
+ SAFE_FREE(data.dptr);
+ ZERO_STRUCT(data);
+ return data;
+ }
+
+ if (!cleanlist)
+ return data;
+
+ /*
+ * Weed out all dead entries.
+ */
+
+ for( i = 0; i < data.dsize; i += 8) {
+ pid_t pid = (pid_t)IVAL(data.dptr, i);
+
+ if (pid == sys_getpid())
+ continue;
+
+ /* Entry is dead if process doesn't exist or refcount is zero. */
+
+ while ((i < data.dsize) && ((IVAL(data.dptr, i + 4) == 0) || !process_exists_by_pid(pid))) {
+
+ /* Refcount == zero is a logic error and should never happen. */
+ if (IVAL(data.dptr, i + 4) == 0) {
+ DEBUG(0,("get_printer_notify_pid_list: Refcount == 0 for pid = %u printer %s !\n",
+ (unsigned int)pid, printer_name ));
+ }
+
+ if (data.dsize - i > 8)
+ memmove( &data.dptr[i], &data.dptr[i+8], data.dsize - i - 8);
+ data.dsize -= 8;
+ }
+ }
+
+ return data;
+}
+
+
diff --git a/source3/profile/profile.c b/source3/profile/profile.c
new file mode 100644
index 0000000000..bdbd805718
--- /dev/null
+++ b/source3/profile/profile.c
@@ -0,0 +1,458 @@
+/*
+ Unix SMB/CIFS implementation.
+ store smbd profiling information in shared memory
+ Copyright (C) Andrew Tridgell 1999
+ Copyright (C) James Peach 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+#ifdef WITH_PROFILE
+#define IPC_PERMS ((S_IRUSR | S_IWUSR) | S_IRGRP | S_IROTH)
+#endif /* WITH_PROFILE */
+
+#ifdef WITH_PROFILE
+static int shm_id;
+static bool read_only;
+#if defined(HAVE_CLOCK_GETTIME)
+clockid_t __profile_clock;
+bool have_profiling_clock = False;
+#endif
+#endif
+
+struct profile_header *profile_h;
+struct profile_stats *profile_p;
+
+bool do_profile_flag = False;
+bool do_profile_times = False;
+
+/****************************************************************************
+Set a profiling level.
+****************************************************************************/
+void set_profile_level(int level, struct server_id src)
+{
+#ifdef WITH_PROFILE
+ switch (level) {
+ case 0: /* turn off profiling */
+ do_profile_flag = False;
+ do_profile_times = False;
+ DEBUG(1,("INFO: Profiling turned OFF from pid %d\n",
+ (int)procid_to_pid(&src)));
+ break;
+ case 1: /* turn on counter profiling only */
+ do_profile_flag = True;
+ do_profile_times = False;
+ DEBUG(1,("INFO: Profiling counts turned ON from pid %d\n",
+ (int)procid_to_pid(&src)));
+ break;
+ case 2: /* turn on complete profiling */
+
+#if defined(HAVE_CLOCK_GETTIME)
+ if (!have_profiling_clock) {
+ do_profile_flag = True;
+ do_profile_times = False;
+ DEBUG(1,("INFO: Profiling counts turned ON from "
+ "pid %d\n", (int)procid_to_pid(&src)));
+ DEBUGADD(1,("INFO: Profiling times disabled "
+ "due to lack of a suitable clock\n"));
+ break;
+ }
+#endif
+
+ do_profile_flag = True;
+ do_profile_times = True;
+ DEBUG(1,("INFO: Full profiling turned ON from pid %d\n",
+ (int)procid_to_pid(&src)));
+ break;
+ case 3: /* reset profile values */
+ memset((char *)profile_p, 0, sizeof(*profile_p));
+ DEBUG(1,("INFO: Profiling values cleared from pid %d\n",
+ (int)procid_to_pid(&src)));
+ break;
+ }
+#else /* WITH_PROFILE */
+ DEBUG(1,("INFO: Profiling support unavailable in this build.\n"));
+#endif /* WITH_PROFILE */
+}
+
+#ifdef WITH_PROFILE
+
+/****************************************************************************
+receive a set profile level message
+****************************************************************************/
+static void profile_message(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ DATA_BLOB *data)
+{
+ int level;
+
+ if (data->length != sizeof(level)) {
+ DEBUG(0, ("got invalid profile message\n"));
+ return;
+ }
+
+ memcpy(&level, data->data, sizeof(level));
+ set_profile_level(level, src);
+}
+
+/****************************************************************************
+receive a request profile level message
+****************************************************************************/
+static void reqprofile_message(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ DATA_BLOB *data)
+{
+ int level;
+
+#ifdef WITH_PROFILE
+ level = 1 + (do_profile_flag?2:0) + (do_profile_times?4:0);
+#else
+ level = 0;
+#endif
+ DEBUG(1,("INFO: Received REQ_PROFILELEVEL message from PID %u\n",
+ (unsigned int)procid_to_pid(&src)));
+ messaging_send_buf(msg_ctx, src, MSG_PROFILELEVEL,
+ (uint8 *)&level, sizeof(level));
+}
+
+/*******************************************************************
+ open the profiling shared memory area
+ ******************************************************************/
+
+#ifdef HAVE_CLOCK_GETTIME
+
+/* Find a clock. Just because the definition for a particular clock ID is
+ * present doesn't mean the system actually supports it.
+ */
+static void init_clock_gettime(void)
+{
+ struct timespec ts;
+
+ have_profiling_clock = False;
+
+#ifdef HAVE_CLOCK_PROCESS_CPUTIME_ID
+ /* CLOCK_PROCESS_CPUTIME_ID is sufficiently fast that the
+ * always profiling times is plausible. Unfortunately on Linux
+ * it is only accurate if we can guarantee we will not be scheduled
+ * scheduled onto a different CPU between samples. Until there is
+ * some way to set processor affinity, we can only use this on
+ * uniprocessors.
+ */
+ if (!this_is_smp()) {
+ if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == 0) {
+ DEBUG(10, ("Using CLOCK_PROCESS_CPUTIME_ID "
+ "for profile_clock\n"));
+ __profile_clock = CLOCK_PROCESS_CPUTIME_ID;
+ have_profiling_clock = True;
+ }
+ }
+#endif
+
+#ifdef HAVE_CLOCK_MONOTONIC
+ if (!have_profiling_clock &&
+ clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ DEBUG(10, ("Using CLOCK_MONOTONIC for profile_clock\n"));
+ __profile_clock = CLOCK_MONOTONIC;
+ have_profiling_clock = True;
+ }
+#endif
+
+#ifdef HAVE_CLOCK_REALTIME
+ /* POSIX says that CLOCK_REALTIME should be defined everywhere
+ * where we have clock_gettime...
+ */
+ if (!have_profiling_clock &&
+ clock_gettime(CLOCK_REALTIME, &ts) == 0) {
+ __profile_clock = CLOCK_REALTIME;
+ have_profiling_clock = True;
+
+ SMB_WARN(__profile_clock != CLOCK_REALTIME,
+ ("forced to use a slow profiling clock"));
+ }
+
+#endif
+
+ SMB_WARN(have_profiling_clock == True,
+ ("could not find a working clock for profiling"));
+ return;
+}
+#endif
+
+bool profile_setup(struct messaging_context *msg_ctx, bool rdonly)
+{
+ struct shmid_ds shm_ds;
+
+ read_only = rdonly;
+
+#ifdef HAVE_CLOCK_GETTIME
+ init_clock_gettime();
+#endif
+
+ again:
+ /* try to use an existing key */
+ shm_id = shmget(PROF_SHMEM_KEY, 0, 0);
+
+ /* if that failed then create one. There is a race condition here
+ if we are running from inetd. Bad luck. */
+ if (shm_id == -1) {
+ if (read_only) return False;
+ shm_id = shmget(PROF_SHMEM_KEY, sizeof(*profile_h),
+ IPC_CREAT | IPC_EXCL | IPC_PERMS);
+ }
+
+ if (shm_id == -1) {
+ DEBUG(0,("Can't create or use IPC area. Error was %s\n",
+ strerror(errno)));
+ return False;
+ }
+
+
+ profile_h = (struct profile_header *)shmat(shm_id, 0,
+ read_only?SHM_RDONLY:0);
+ if ((long)profile_p == -1) {
+ DEBUG(0,("Can't attach to IPC area. Error was %s\n",
+ strerror(errno)));
+ return False;
+ }
+
+ /* find out who created this memory area */
+ if (shmctl(shm_id, IPC_STAT, &shm_ds) != 0) {
+ DEBUG(0,("ERROR shmctl : can't IPC_STAT. Error was %s\n",
+ strerror(errno)));
+ return False;
+ }
+
+ if (shm_ds.shm_perm.cuid != sec_initial_uid() ||
+ shm_ds.shm_perm.cgid != sec_initial_gid()) {
+ DEBUG(0,("ERROR: we did not create the shmem "
+ "(owned by another user, uid %u, gid %u)\n",
+ shm_ds.shm_perm.cuid,
+ shm_ds.shm_perm.cgid));
+ return False;
+ }
+
+ if (shm_ds.shm_segsz != sizeof(*profile_h)) {
+ DEBUG(0,("WARNING: profile size is %d (expected %d). Deleting\n",
+ (int)shm_ds.shm_segsz, (int)sizeof(*profile_h)));
+ if (shmctl(shm_id, IPC_RMID, &shm_ds) == 0) {
+ goto again;
+ } else {
+ return False;
+ }
+ }
+
+ if (!read_only && (shm_ds.shm_nattch == 1)) {
+ memset((char *)profile_h, 0, sizeof(*profile_h));
+ profile_h->prof_shm_magic = PROF_SHM_MAGIC;
+ profile_h->prof_shm_version = PROF_SHM_VERSION;
+ DEBUG(3,("Initialised profile area\n"));
+ }
+
+ profile_p = &profile_h->stats;
+ if (msg_ctx != NULL) {
+ messaging_register(msg_ctx, NULL, MSG_PROFILE,
+ profile_message);
+ messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
+ reqprofile_message);
+ }
+ return True;
+}
+
+ const char * profile_value_name(enum profile_stats_values val)
+{
+ static const char * valnames[PR_VALUE_MAX + 1] =
+ {
+ "smbd_idle", /* PR_VALUE_SMBD_IDLE */
+ "syscall_opendir", /* PR_VALUE_SYSCALL_OPENDIR */
+ "syscall_readdir", /* PR_VALUE_SYSCALL_READDIR */
+ "syscall_seekdir", /* PR_VALUE_SYSCALL_SEEKDIR */
+ "syscall_telldir", /* PR_VALUE_SYSCALL_TELLDIR */
+ "syscall_rewinddir", /* PR_VALUE_SYSCALL_REWINDDIR */
+ "syscall_mkdir", /* PR_VALUE_SYSCALL_MKDIR */
+ "syscall_rmdir", /* PR_VALUE_SYSCALL_RMDIR */
+ "syscall_closedir", /* PR_VALUE_SYSCALL_CLOSEDIR */
+ "syscall_open", /* PR_VALUE_SYSCALL_OPEN */
+ "syscall_close", /* PR_VALUE_SYSCALL_CLOSE */
+ "syscall_read", /* PR_VALUE_SYSCALL_READ */
+ "syscall_pread", /* PR_VALUE_SYSCALL_PREAD */
+ "syscall_write", /* PR_VALUE_SYSCALL_WRITE */
+ "syscall_pwrite", /* PR_VALUE_SYSCALL_PWRITE */
+ "syscall_lseek", /* PR_VALUE_SYSCALL_LSEEK */
+ "syscall_sendfile", /* PR_VALUE_SYSCALL_SENDFILE */
+ "syscall_recvfile", /* PR_VALUE_SYSCALL_RECVFILE */
+ "syscall_rename", /* PR_VALUE_SYSCALL_RENAME */
+ "syscall_fsync", /* PR_VALUE_SYSCALL_FSYNC */
+ "syscall_stat", /* PR_VALUE_SYSCALL_STAT */
+ "syscall_fstat", /* PR_VALUE_SYSCALL_FSTAT */
+ "syscall_lstat", /* PR_VALUE_SYSCALL_LSTAT */
+ "syscall_unlink", /* PR_VALUE_SYSCALL_UNLINK */
+ "syscall_chmod", /* PR_VALUE_SYSCALL_CHMOD */
+ "syscall_fchmod", /* PR_VALUE_SYSCALL_FCHMOD */
+ "syscall_chown", /* PR_VALUE_SYSCALL_CHOWN */
+ "syscall_fchown", /* PR_VALUE_SYSCALL_FCHOWN */
+ "syscall_chdir", /* PR_VALUE_SYSCALL_CHDIR */
+ "syscall_getwd", /* PR_VALUE_SYSCALL_GETWD */
+ "syscall_ntimes", /* PR_VALUE_SYSCALL_NTIMES */
+ "syscall_ftruncate", /* PR_VALUE_SYSCALL_FTRUNCATE */
+ "syscall_fcntl_lock", /* PR_VALUE_SYSCALL_FCNTL_LOCK */
+ "syscall_kernel_flock", /* PR_VALUE_SYSCALL_KERNEL_FLOCK */
+ "syscall_linux_setlease", /* PR_VALUE_SYSCALL_LINUX_SETLEASE */
+ "syscall_fcntl_getlock", /* PR_VALUE_SYSCALL_FCNTL_GETLOCK */
+ "syscall_readlink", /* PR_VALUE_SYSCALL_READLINK */
+ "syscall_symlink", /* PR_VALUE_SYSCALL_SYMLINK */
+ "syscall_link", /* PR_VALUE_SYSCALL_LINK */
+ "syscall_mknod", /* PR_VALUE_SYSCALL_MKNOD */
+ "syscall_realpath", /* PR_VALUE_SYSCALL_REALPATH */
+ "syscall_get_quota", /* PR_VALUE_SYSCALL_GET_QUOTA */
+ "syscall_set_quota", /* PR_VALUE_SYSCALL_SET_QUOTA */
+ "SMBmkdir", /* PR_VALUE_SMBMKDIR */
+ "SMBrmdir", /* PR_VALUE_SMBRMDIR */
+ "SMBopen", /* PR_VALUE_SMBOPEN */
+ "SMBcreate", /* PR_VALUE_SMBCREATE */
+ "SMBclose", /* PR_VALUE_SMBCLOSE */
+ "SMBflush", /* PR_VALUE_SMBFLUSH */
+ "SMBunlink", /* PR_VALUE_SMBUNLINK */
+ "SMBmv", /* PR_VALUE_SMBMV */
+ "SMBgetatr", /* PR_VALUE_SMBGETATR */
+ "SMBsetatr", /* PR_VALUE_SMBSETATR */
+ "SMBread", /* PR_VALUE_SMBREAD */
+ "SMBwrite", /* PR_VALUE_SMBWRITE */
+ "SMBlock", /* PR_VALUE_SMBLOCK */
+ "SMBunlock", /* PR_VALUE_SMBUNLOCK */
+ "SMBctemp", /* PR_VALUE_SMBCTEMP */
+ "SMBmknew", /* PR_VALUE_SMBMKNEW */
+ "SMBcheckpath", /* PR_VALUE_SMBCHECKPATH */
+ "SMBexit", /* PR_VALUE_SMBEXIT */
+ "SMBlseek", /* PR_VALUE_SMBLSEEK */
+ "SMBlockread", /* PR_VALUE_SMBLOCKREAD */
+ "SMBwriteunlock", /* PR_VALUE_SMBWRITEUNLOCK */
+ "SMBreadbraw", /* PR_VALUE_SMBREADBRAW */
+ "SMBreadBmpx", /* PR_VALUE_SMBREADBMPX */
+ "SMBreadBs", /* PR_VALUE_SMBREADBS */
+ "SMBwritebraw", /* PR_VALUE_SMBWRITEBRAW */
+ "SMBwriteBmpx", /* PR_VALUE_SMBWRITEBMPX */
+ "SMBwriteBs", /* PR_VALUE_SMBWRITEBS */
+ "SMBwritec", /* PR_VALUE_SMBWRITEC */
+ "SMBsetattrE", /* PR_VALUE_SMBSETATTRE */
+ "SMBgetattrE", /* PR_VALUE_SMBGETATTRE */
+ "SMBlockingX", /* PR_VALUE_SMBLOCKINGX */
+ "SMBtrans", /* PR_VALUE_SMBTRANS */
+ "SMBtranss", /* PR_VALUE_SMBTRANSS */
+ "SMBioctl", /* PR_VALUE_SMBIOCTL */
+ "SMBioctls", /* PR_VALUE_SMBIOCTLS */
+ "SMBcopy", /* PR_VALUE_SMBCOPY */
+ "SMBmove", /* PR_VALUE_SMBMOVE */
+ "SMBecho", /* PR_VALUE_SMBECHO */
+ "SMBwriteclose", /* PR_VALUE_SMBWRITECLOSE */
+ "SMBopenX", /* PR_VALUE_SMBOPENX */
+ "SMBreadX", /* PR_VALUE_SMBREADX */
+ "SMBwriteX", /* PR_VALUE_SMBWRITEX */
+ "SMBtrans2", /* PR_VALUE_SMBTRANS2 */
+ "SMBtranss2", /* PR_VALUE_SMBTRANSS2 */
+ "SMBfindclose", /* PR_VALUE_SMBFINDCLOSE */
+ "SMBfindnclose", /* PR_VALUE_SMBFINDNCLOSE */
+ "SMBtcon", /* PR_VALUE_SMBTCON */
+ "SMBtdis", /* PR_VALUE_SMBTDIS */
+ "SMBnegprot", /* PR_VALUE_SMBNEGPROT */
+ "SMBsesssetupX", /* PR_VALUE_SMBSESSSETUPX */
+ "SMBulogoffX", /* PR_VALUE_SMBULOGOFFX */
+ "SMBtconX", /* PR_VALUE_SMBTCONX */
+ "SMBdskattr", /* PR_VALUE_SMBDSKATTR */
+ "SMBsearch", /* PR_VALUE_SMBSEARCH */
+ "SMBffirst", /* PR_VALUE_SMBFFIRST */
+ "SMBfunique", /* PR_VALUE_SMBFUNIQUE */
+ "SMBfclose", /* PR_VALUE_SMBFCLOSE */
+ "SMBnttrans", /* PR_VALUE_SMBNTTRANS */
+ "SMBnttranss", /* PR_VALUE_SMBNTTRANSS */
+ "SMBntcreateX", /* PR_VALUE_SMBNTCREATEX */
+ "SMBntcancel", /* PR_VALUE_SMBNTCANCEL */
+ "SMBntrename", /* PR_VALUE_SMBNTRENAME */
+ "SMBsplopen", /* PR_VALUE_SMBSPLOPEN */
+ "SMBsplwr", /* PR_VALUE_SMBSPLWR */
+ "SMBsplclose", /* PR_VALUE_SMBSPLCLOSE */
+ "SMBsplretq", /* PR_VALUE_SMBSPLRETQ */
+ "SMBsends", /* PR_VALUE_SMBSENDS */
+ "SMBsendb", /* PR_VALUE_SMBSENDB */
+ "SMBfwdname", /* PR_VALUE_SMBFWDNAME */
+ "SMBcancelf", /* PR_VALUE_SMBCANCELF */
+ "SMBgetmac", /* PR_VALUE_SMBGETMAC */
+ "SMBsendstrt", /* PR_VALUE_SMBSENDSTRT */
+ "SMBsendend", /* PR_VALUE_SMBSENDEND */
+ "SMBsendtxt", /* PR_VALUE_SMBSENDTXT */
+ "SMBinvalid", /* PR_VALUE_SMBINVALID */
+ "pathworks_setdir", /* PR_VALUE_PATHWORKS_SETDIR */
+ "Trans2_open", /* PR_VALUE_TRANS2_OPEN */
+ "Trans2_findfirst", /* PR_VALUE_TRANS2_FINDFIRST */
+ "Trans2_findnext", /* PR_VALUE_TRANS2_FINDNEXT */
+ "Trans2_qfsinfo", /* PR_VALUE_TRANS2_QFSINFO */
+ "Trans2_setfsinfo", /* PR_VALUE_TRANS2_SETFSINFO */
+ "Trans2_qpathinfo", /* PR_VALUE_TRANS2_QPATHINFO */
+ "Trans2_setpathinfo", /* PR_VALUE_TRANS2_SETPATHINFO */
+ "Trans2_qfileinfo", /* PR_VALUE_TRANS2_QFILEINFO */
+ "Trans2_setfileinfo", /* PR_VALUE_TRANS2_SETFILEINFO */
+ "Trans2_fsctl", /* PR_VALUE_TRANS2_FSCTL */
+ "Trans2_ioctl", /* PR_VALUE_TRANS2_IOCTL */
+ "Trans2_findnotifyfirst", /* PR_VALUE_TRANS2_FINDNOTIFYFIRST */
+ "Trans2_findnotifynext", /* PR_VALUE_TRANS2_FINDNOTIFYNEXT */
+ "Trans2_mkdir", /* PR_VALUE_TRANS2_MKDIR */
+ "Trans2_session_setup", /* PR_VALUE_TRANS2_SESSION_SETUP */
+ "Trans2_get_dfs_referral", /* PR_VALUE_TRANS2_GET_DFS_REFERRAL */
+ "Trans2_report_dfs_inconsistancy", /* PR_VALUE_TRANS2_REPORT_DFS_INCONSISTANCY */
+ "NT_transact_create", /* PR_VALUE_NT_TRANSACT_CREATE */
+ "NT_transact_ioctl", /* PR_VALUE_NT_TRANSACT_IOCTL */
+ "NT_transact_set_security_desc", /* PR_VALUE_NT_TRANSACT_SET_SECURITY_DESC */
+ "NT_transact_notify_change",/* PR_VALUE_NT_TRANSACT_NOTIFY_CHANGE */
+ "NT_transact_rename", /* PR_VALUE_NT_TRANSACT_RENAME */
+ "NT_transact_query_security_desc", /* PR_VALUE_NT_TRANSACT_QUERY_SECURITY_DESC */
+ "NT_transact_get_user_quota",/* PR_VALUE_NT_TRANSACT_GET_USER_QUOTA */
+ "NT_transact_set_user_quota",/* PR_VALUE_NT_TRANSACT_SET_USER_QUOTA */
+ "get_nt_acl", /* PR_VALUE_GET_NT_ACL */
+ "fget_nt_acl", /* PR_VALUE_FGET_NT_ACL */
+ "fset_nt_acl", /* PR_VALUE_FSET_NT_ACL */
+ "chmod_acl", /* PR_VALUE_CHMOD_ACL */
+ "fchmod_acl", /* PR_VALUE_FCHMOD_ACL */
+ "name_release", /* PR_VALUE_NAME_RELEASE */
+ "name_refresh", /* PR_VALUE_NAME_REFRESH */
+ "name_registration", /* PR_VALUE_NAME_REGISTRATION */
+ "node_status", /* PR_VALUE_NODE_STATUS */
+ "name_query", /* PR_VALUE_NAME_QUERY */
+ "host_announce", /* PR_VALUE_HOST_ANNOUNCE */
+ "workgroup_announce", /* PR_VALUE_WORKGROUP_ANNOUNCE */
+ "local_master_announce", /* PR_VALUE_LOCAL_MASTER_ANNOUNCE */
+ "master_browser_announce", /* PR_VALUE_MASTER_BROWSER_ANNOUNCE */
+ "lm_host_announce", /* PR_VALUE_LM_HOST_ANNOUNCE */
+ "get_backup_list", /* PR_VALUE_GET_BACKUP_LIST */
+ "reset_browser", /* PR_VALUE_RESET_BROWSER */
+ "announce_request", /* PR_VALUE_ANNOUNCE_REQUEST */
+ "lm_announce_request", /* PR_VALUE_LM_ANNOUNCE_REQUEST */
+ "domain_logon", /* PR_VALUE_DOMAIN_LOGON */
+ "sync_browse_lists", /* PR_VALUE_SYNC_BROWSE_LISTS */
+ "run_elections", /* PR_VALUE_RUN_ELECTIONS */
+ "election", /* PR_VALUE_ELECTION */
+ "" /* PR_VALUE_MAX */
+ };
+
+ SMB_ASSERT(val >= 0);
+ SMB_ASSERT(val < PR_VALUE_MAX);
+ return valnames[val];
+}
+
+#endif /* WITH_PROFILE */
diff --git a/source3/registry/reg_api.c b/source3/registry/reg_api.c
new file mode 100644
index 0000000000..e9a7145255
--- /dev/null
+++ b/source3/registry/reg_api.c
@@ -0,0 +1,1247 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Volker Lendecke 2006
+ * Copyright (C) Michael Adam 2007-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Attempt to wrap the existing API in a more winreg.idl-like way */
+
+/*
+ * Here is a list of winreg.idl functions and corresponding implementations
+ * provided here:
+ *
+ * 0x00 winreg_OpenHKCR
+ * 0x01 winreg_OpenHKCU
+ * 0x02 winreg_OpenHKLM
+ * 0x03 winreg_OpenHKPD
+ * 0x04 winreg_OpenHKU
+ * 0x05 winreg_CloseKey
+ * 0x06 winreg_CreateKey reg_createkey
+ * 0x07 winreg_DeleteKey reg_deletekey
+ * 0x08 winreg_DeleteValue reg_deletevalue
+ * 0x09 winreg_EnumKey reg_enumkey
+ * 0x0a winreg_EnumValue reg_enumvalue
+ * 0x0b winreg_FlushKey
+ * 0x0c winreg_GetKeySecurity reg_getkeysecurity
+ * 0x0d winreg_LoadKey
+ * 0x0e winreg_NotifyChangeKeyValue
+ * 0x0f winreg_OpenKey reg_openkey
+ * 0x10 winreg_QueryInfoKey reg_queryinfokey
+ * 0x11 winreg_QueryValue reg_queryvalue
+ * 0x12 winreg_ReplaceKey
+ * 0x13 winreg_RestoreKey reg_restorekey
+ * 0x14 winreg_SaveKey reg_savekey
+ * 0x15 winreg_SetKeySecurity reg_setkeysecurity
+ * 0x16 winreg_SetValue reg_setvalue
+ * 0x17 winreg_UnLoadKey
+ * 0x18 winreg_InitiateSystemShutdown
+ * 0x19 winreg_AbortSystemShutdown
+ * 0x1a winreg_GetVersion reg_getversion
+ * 0x1b winreg_OpenHKCC
+ * 0x1c winreg_OpenHKDD
+ * 0x1d winreg_QueryMultipleValues
+ * 0x1e winreg_InitiateSystemShutdownEx
+ * 0x1f winreg_SaveKeyEx
+ * 0x20 winreg_OpenHKPT
+ * 0x21 winreg_OpenHKPN
+ * 0x22 winreg_QueryMultipleValues2
+ *
+ */
+
+#include "includes.h"
+#include "regfio.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+
+/**********************************************************************
+ * Helper functions
+ **********************************************************************/
+
+static WERROR fill_value_cache(struct registry_key *key)
+{
+ if (key->values != NULL) {
+ if (!reg_values_need_update(key->key, key->values)) {
+ return WERR_OK;
+ }
+ }
+
+ if (!(key->values = TALLOC_ZERO_P(key, REGVAL_CTR))) {
+ return WERR_NOMEM;
+ }
+ if (fetch_reg_values(key->key, key->values) == -1) {
+ TALLOC_FREE(key->values);
+ return WERR_BADFILE;
+ }
+
+ return WERR_OK;
+}
+
+static WERROR fill_subkey_cache(struct registry_key *key)
+{
+ if (key->subkeys != NULL) {
+ if (!reg_subkeys_need_update(key->key, key->subkeys)) {
+ return WERR_OK;
+ }
+ }
+
+ if (!(key->subkeys = TALLOC_ZERO_P(key, REGSUBKEY_CTR))) {
+ return WERR_NOMEM;
+ }
+
+ if (fetch_reg_keys(key->key, key->subkeys) == -1) {
+ TALLOC_FREE(key->subkeys);
+ return WERR_NO_MORE_ITEMS;
+ }
+
+ return WERR_OK;
+}
+
+static int regkey_destructor(REGISTRY_KEY *key)
+{
+ return regdb_close();
+}
+
+static WERROR regkey_open_onelevel(TALLOC_CTX *mem_ctx,
+ struct registry_key *parent,
+ const char *name,
+ const struct nt_user_token *token,
+ uint32 access_desired,
+ struct registry_key **pregkey)
+{
+ WERROR result = WERR_OK;
+ struct registry_key *regkey;
+ REGISTRY_KEY *key;
+ REGSUBKEY_CTR *subkeys = NULL;
+
+ DEBUG(7,("regkey_open_onelevel: name = [%s]\n", name));
+
+ SMB_ASSERT(strchr(name, '\\') == NULL);
+
+ if (!(regkey = TALLOC_ZERO_P(mem_ctx, struct registry_key)) ||
+ !(regkey->token = dup_nt_token(regkey, token)) ||
+ !(regkey->key = TALLOC_ZERO_P(regkey, REGISTRY_KEY))) {
+ result = WERR_NOMEM;
+ goto done;
+ }
+
+ if ( !(W_ERROR_IS_OK(result = regdb_open())) ) {
+ goto done;
+ }
+
+ key = regkey->key;
+ talloc_set_destructor(key, regkey_destructor);
+
+ /* initialization */
+
+ key->type = REG_KEY_GENERIC;
+
+ if (name[0] == '\0') {
+ /*
+ * Open a copy of the parent key
+ */
+ if (!parent) {
+ result = WERR_BADFILE;
+ goto done;
+ }
+ key->name = talloc_strdup(key, parent->key->name);
+ }
+ else {
+ /*
+ * Normal subkey open
+ */
+ key->name = talloc_asprintf(key, "%s%s%s",
+ parent ? parent->key->name : "",
+ parent ? "\\": "",
+ name);
+ }
+
+ if (key->name == NULL) {
+ result = WERR_NOMEM;
+ goto done;
+ }
+
+ /* Tag this as a Performance Counter Key */
+
+ if( StrnCaseCmp(key->name, KEY_HKPD, strlen(KEY_HKPD)) == 0 )
+ key->type = REG_KEY_HKPD;
+
+ /* Look up the table of registry I/O operations */
+
+ if ( !(key->ops = reghook_cache_find( key->name )) ) {
+ DEBUG(0,("reg_open_onelevel: Failed to assign "
+ "REGISTRY_OPS to [%s]\n", key->name ));
+ result = WERR_BADFILE;
+ goto done;
+ }
+
+ /* check if the path really exists; failed is indicated by -1 */
+ /* if the subkey count failed, bail out */
+
+ if ( !(subkeys = TALLOC_ZERO_P( key, REGSUBKEY_CTR )) ) {
+ result = WERR_NOMEM;
+ goto done;
+ }
+
+ if ( fetch_reg_keys( key, subkeys ) == -1 ) {
+ result = WERR_BADFILE;
+ goto done;
+ }
+
+ TALLOC_FREE( subkeys );
+
+ if ( !regkey_access_check( key, access_desired, &key->access_granted,
+ token ) ) {
+ result = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ *pregkey = regkey;
+ result = WERR_OK;
+
+done:
+ if ( !W_ERROR_IS_OK(result) ) {
+ TALLOC_FREE(regkey);
+ }
+
+ return result;
+}
+
+WERROR reg_openhive(TALLOC_CTX *mem_ctx, const char *hive,
+ uint32 desired_access,
+ const struct nt_user_token *token,
+ struct registry_key **pkey)
+{
+ SMB_ASSERT(hive != NULL);
+ SMB_ASSERT(hive[0] != '\0');
+ SMB_ASSERT(strchr(hive, '\\') == NULL);
+
+ return regkey_open_onelevel(mem_ctx, NULL, hive, token, desired_access,
+ pkey);
+}
+
+
+/**********************************************************************
+ * The API functions
+ **********************************************************************/
+
+WERROR reg_openkey(TALLOC_CTX *mem_ctx, struct registry_key *parent,
+ const char *name, uint32 desired_access,
+ struct registry_key **pkey)
+{
+ struct registry_key *direct_parent = parent;
+ WERROR err;
+ char *p, *path, *to_free;
+ size_t len;
+
+ if (!(path = SMB_STRDUP(name))) {
+ return WERR_NOMEM;
+ }
+ to_free = path;
+
+ len = strlen(path);
+
+ if ((len > 0) && (path[len-1] == '\\')) {
+ path[len-1] = '\0';
+ }
+
+ while ((p = strchr(path, '\\')) != NULL) {
+ char *name_component;
+ struct registry_key *tmp;
+
+ if (!(name_component = SMB_STRNDUP(path, (p - path)))) {
+ err = WERR_NOMEM;
+ goto error;
+ }
+
+ err = regkey_open_onelevel(mem_ctx, direct_parent,
+ name_component, parent->token,
+ SEC_RIGHTS_ENUM_SUBKEYS, &tmp);
+ SAFE_FREE(name_component);
+
+ if (!W_ERROR_IS_OK(err)) {
+ goto error;
+ }
+ if (direct_parent != parent) {
+ TALLOC_FREE(direct_parent);
+ }
+
+ direct_parent = tmp;
+ path = p+1;
+ }
+
+ err = regkey_open_onelevel(mem_ctx, direct_parent, path, parent->token,
+ desired_access, pkey);
+ error:
+ if (direct_parent != parent) {
+ TALLOC_FREE(direct_parent);
+ }
+ SAFE_FREE(to_free);
+ return err;
+}
+
+WERROR reg_enumkey(TALLOC_CTX *mem_ctx, struct registry_key *key,
+ uint32 idx, char **name, NTTIME *last_write_time)
+{
+ WERROR err;
+
+ if (!(key->key->access_granted & SEC_RIGHTS_ENUM_SUBKEYS)) {
+ return WERR_ACCESS_DENIED;
+ }
+
+ if (!W_ERROR_IS_OK(err = fill_subkey_cache(key))) {
+ return err;
+ }
+
+ if (idx >= key->subkeys->num_subkeys) {
+ return WERR_NO_MORE_ITEMS;
+ }
+
+ if (!(*name = talloc_strdup(mem_ctx, key->subkeys->subkeys[idx]))) {
+ return WERR_NOMEM;
+ }
+
+ if (last_write_time) {
+ *last_write_time = 0;
+ }
+
+ return WERR_OK;
+}
+
+WERROR reg_enumvalue(TALLOC_CTX *mem_ctx, struct registry_key *key,
+ uint32 idx, char **pname, struct registry_value **pval)
+{
+ struct registry_value *val;
+ WERROR err;
+
+ if (!(key->key->access_granted & SEC_RIGHTS_QUERY_VALUE)) {
+ return WERR_ACCESS_DENIED;
+ }
+
+ if (!(W_ERROR_IS_OK(err = fill_value_cache(key)))) {
+ return err;
+ }
+
+ if (idx >= key->values->num_values) {
+ return WERR_NO_MORE_ITEMS;
+ }
+
+ err = registry_pull_value(mem_ctx, &val,
+ key->values->values[idx]->type,
+ key->values->values[idx]->data_p,
+ key->values->values[idx]->size,
+ key->values->values[idx]->size);
+ if (!W_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ if (pname
+ && !(*pname = talloc_strdup(
+ mem_ctx, key->values->values[idx]->valuename))) {
+ SAFE_FREE(val);
+ return WERR_NOMEM;
+ }
+
+ *pval = val;
+ return WERR_OK;
+}
+
+WERROR reg_queryvalue(TALLOC_CTX *mem_ctx, struct registry_key *key,
+ const char *name, struct registry_value **pval)
+{
+ WERROR err;
+ uint32 i;
+
+ if (!(key->key->access_granted & SEC_RIGHTS_QUERY_VALUE)) {
+ return WERR_ACCESS_DENIED;
+ }
+
+ if (!(W_ERROR_IS_OK(err = fill_value_cache(key)))) {
+ return err;
+ }
+
+ for (i=0; i<key->values->num_values; i++) {
+ if (strequal(key->values->values[i]->valuename, name)) {
+ return reg_enumvalue(mem_ctx, key, i, NULL, pval);
+ }
+ }
+
+ return WERR_BADFILE;
+}
+
+WERROR reg_queryinfokey(struct registry_key *key, uint32_t *num_subkeys,
+ uint32_t *max_subkeylen, uint32_t *max_subkeysize,
+ uint32_t *num_values, uint32_t *max_valnamelen,
+ uint32_t *max_valbufsize, uint32_t *secdescsize,
+ NTTIME *last_changed_time)
+{
+ uint32 i, max_size;
+ size_t max_len;
+ TALLOC_CTX *mem_ctx;
+ WERROR err;
+ struct security_descriptor *secdesc;
+
+ if (!(key->key->access_granted & SEC_RIGHTS_QUERY_VALUE)) {
+ return WERR_ACCESS_DENIED;
+ }
+
+ if (!W_ERROR_IS_OK(fill_subkey_cache(key)) ||
+ !W_ERROR_IS_OK(fill_value_cache(key))) {
+ return WERR_BADFILE;
+ }
+
+ max_len = 0;
+ for (i=0; i<key->subkeys->num_subkeys; i++) {
+ max_len = MAX(max_len, strlen(key->subkeys->subkeys[i]));
+ }
+
+ *num_subkeys = key->subkeys->num_subkeys;
+ *max_subkeylen = max_len;
+ *max_subkeysize = 0; /* Class length? */
+
+ max_len = 0;
+ max_size = 0;
+ for (i=0; i<key->values->num_values; i++) {
+ max_len = MAX(max_len,
+ strlen(key->values->values[i]->valuename));
+ max_size = MAX(max_size, key->values->values[i]->size);
+ }
+
+ *num_values = key->values->num_values;
+ *max_valnamelen = max_len;
+ *max_valbufsize = max_size;
+
+ if (!(mem_ctx = talloc_new(key))) {
+ return WERR_NOMEM;
+ }
+
+ err = regkey_get_secdesc(mem_ctx, key->key, &secdesc);
+ if (!W_ERROR_IS_OK(err)) {
+ TALLOC_FREE(mem_ctx);
+ return err;
+ }
+
+ *secdescsize = ndr_size_security_descriptor(secdesc, 0);
+ TALLOC_FREE(mem_ctx);
+
+ *last_changed_time = 0;
+
+ return WERR_OK;
+}
+
+WERROR reg_createkey(TALLOC_CTX *ctx, struct registry_key *parent,
+ const char *subkeypath, uint32 desired_access,
+ struct registry_key **pkey,
+ enum winreg_CreateAction *paction)
+{
+ struct registry_key *key = parent;
+ struct registry_key *create_parent;
+ TALLOC_CTX *mem_ctx;
+ char *path, *end;
+ WERROR err;
+
+ if (!(mem_ctx = talloc_new(ctx))) return WERR_NOMEM;
+
+ if (!(path = talloc_strdup(mem_ctx, subkeypath))) {
+ err = WERR_NOMEM;
+ goto done;
+ }
+
+ while ((end = strchr(path, '\\')) != NULL) {
+ struct registry_key *tmp;
+ enum winreg_CreateAction action;
+
+ *end = '\0';
+
+ err = reg_createkey(mem_ctx, key, path,
+ SEC_RIGHTS_ENUM_SUBKEYS, &tmp, &action);
+ if (!W_ERROR_IS_OK(err)) {
+ goto done;
+ }
+
+ if (key != parent) {
+ TALLOC_FREE(key);
+ }
+
+ key = tmp;
+ path = end+1;
+ }
+
+ /*
+ * At this point, "path" contains the one-element subkey of "key". We
+ * can try to open it.
+ */
+
+ err = reg_openkey(ctx, key, path, desired_access, pkey);
+ if (W_ERROR_IS_OK(err)) {
+ if (paction != NULL) {
+ *paction = REG_OPENED_EXISTING_KEY;
+ }
+ goto done;
+ }
+
+ if (!W_ERROR_EQUAL(err, WERR_BADFILE)) {
+ /*
+ * Something but "notfound" has happened, so bail out
+ */
+ goto done;
+ }
+
+ /*
+ * We have to make a copy of the current key, as we opened it only
+ * with ENUM_SUBKEY access.
+ */
+
+ err = reg_openkey(mem_ctx, key, "", SEC_RIGHTS_CREATE_SUBKEY,
+ &create_parent);
+ if (!W_ERROR_IS_OK(err)) {
+ goto done;
+ }
+
+ /*
+ * Actually create the subkey
+ */
+
+ err = fill_subkey_cache(create_parent);
+ if (!W_ERROR_IS_OK(err)) goto done;
+
+ err = regsubkey_ctr_addkey(create_parent->subkeys, path);
+ if (!W_ERROR_IS_OK(err)) goto done;
+
+ if (!store_reg_keys(create_parent->key, create_parent->subkeys)) {
+ TALLOC_FREE(create_parent->subkeys);
+ err = WERR_REG_IO_FAILURE;
+ goto done;
+ }
+
+ /*
+ * Now open the newly created key
+ */
+
+ err = reg_openkey(ctx, create_parent, path, desired_access, pkey);
+ if (W_ERROR_IS_OK(err) && (paction != NULL)) {
+ *paction = REG_CREATED_NEW_KEY;
+ }
+
+ done:
+ TALLOC_FREE(mem_ctx);
+ return err;
+}
+
+WERROR reg_deletekey(struct registry_key *parent, const char *path)
+{
+ WERROR err;
+ TALLOC_CTX *mem_ctx;
+ char *name, *end;
+ int num_subkeys;
+ struct registry_key *tmp_key, *key;
+
+ if (!(mem_ctx = talloc_init("reg_createkey"))) return WERR_NOMEM;
+
+ if (!(name = talloc_strdup(mem_ctx, path))) {
+ err = WERR_NOMEM;
+ goto error;
+ }
+
+ /* check if the key has subkeys */
+ err = reg_openkey(mem_ctx, parent, name, REG_KEY_READ, &key);
+ if (!W_ERROR_IS_OK(err)) {
+ goto error;
+ }
+ if (!W_ERROR_IS_OK(err = fill_subkey_cache(key))) {
+ goto error;
+ }
+ if (key->subkeys->num_subkeys > 0) {
+ err = WERR_ACCESS_DENIED;
+ goto error;
+ }
+
+ /* no subkeys - proceed with delete */
+ if ((end = strrchr(name, '\\')) != NULL) {
+ *end = '\0';
+
+ err = reg_openkey(mem_ctx, parent, name,
+ SEC_RIGHTS_CREATE_SUBKEY, &tmp_key);
+ if (!W_ERROR_IS_OK(err)) {
+ goto error;
+ }
+
+ parent = tmp_key;
+ name = end+1;
+ }
+
+ if (name[0] == '\0') {
+ err = WERR_INVALID_PARAM;
+ goto error;
+ }
+
+ if (!W_ERROR_IS_OK(err = fill_subkey_cache(parent))) {
+ goto error;
+ }
+
+ num_subkeys = parent->subkeys->num_subkeys;
+
+ if (regsubkey_ctr_delkey(parent->subkeys, name) == num_subkeys) {
+ err = WERR_BADFILE;
+ goto error;
+ }
+
+ if (!store_reg_keys(parent->key, parent->subkeys)) {
+ TALLOC_FREE(parent->subkeys);
+ err = WERR_REG_IO_FAILURE;
+ goto error;
+ }
+
+ regkey_set_secdesc(key->key, NULL);
+
+ err = WERR_OK;
+
+ error:
+ TALLOC_FREE(mem_ctx);
+ return err;
+}
+
+WERROR reg_setvalue(struct registry_key *key, const char *name,
+ const struct registry_value *val)
+{
+ WERROR err;
+ DATA_BLOB value_data;
+ int res;
+
+ if (!(key->key->access_granted & SEC_RIGHTS_SET_VALUE)) {
+ return WERR_ACCESS_DENIED;
+ }
+
+ if (!W_ERROR_IS_OK(err = fill_value_cache(key))) {
+ return err;
+ }
+
+ err = registry_push_value(key, val, &value_data);
+ if (!W_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ res = regval_ctr_addvalue(key->values, name, val->type,
+ (char *)value_data.data, value_data.length);
+ TALLOC_FREE(value_data.data);
+
+ if (res == 0) {
+ TALLOC_FREE(key->values);
+ return WERR_NOMEM;
+ }
+
+ if (!store_reg_values(key->key, key->values)) {
+ TALLOC_FREE(key->values);
+ return WERR_REG_IO_FAILURE;
+ }
+
+ return WERR_OK;
+}
+
+static WERROR reg_value_exists(struct registry_key *key, const char *name)
+{
+ int i;
+
+ for (i=0; i<key->values->num_values; i++) {
+ if (strequal(key->values->values[i]->valuename, name)) {
+ return WERR_OK;
+ }
+ }
+
+ return WERR_BADFILE;
+}
+
+WERROR reg_deletevalue(struct registry_key *key, const char *name)
+{
+ WERROR err;
+
+ if (!(key->key->access_granted & SEC_RIGHTS_SET_VALUE)) {
+ return WERR_ACCESS_DENIED;
+ }
+
+ if (!W_ERROR_IS_OK(err = fill_value_cache(key))) {
+ return err;
+ }
+
+ err = reg_value_exists(key, name);
+ if (!W_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ regval_ctr_delvalue(key->values, name);
+
+ if (!store_reg_values(key->key, key->values)) {
+ TALLOC_FREE(key->values);
+ return WERR_REG_IO_FAILURE;
+ }
+
+ return WERR_OK;
+}
+
+WERROR reg_getkeysecurity(TALLOC_CTX *mem_ctx, struct registry_key *key,
+ struct security_descriptor **psecdesc)
+{
+ return regkey_get_secdesc(mem_ctx, key->key, psecdesc);
+}
+
+WERROR reg_setkeysecurity(struct registry_key *key,
+ struct security_descriptor *psecdesc)
+{
+ return regkey_set_secdesc(key->key, psecdesc);
+}
+
+WERROR reg_getversion(uint32_t *version)
+{
+ if (version == NULL) {
+ return WERR_INVALID_PARAM;
+ }
+
+ *version = 0x00000005; /* Windows 2000 registry API version */
+ return WERR_OK;
+}
+
+/*******************************************************************
+ Note: topkeypat is the *full* path that this *key will be
+ loaded into (including the name of the key)
+ ********************************************************************/
+
+static WERROR reg_load_tree(REGF_FILE *regfile, const char *topkeypath,
+ REGF_NK_REC *key)
+{
+ REGF_NK_REC *subkey;
+ REGISTRY_KEY registry_key;
+ REGVAL_CTR *values;
+ REGSUBKEY_CTR *subkeys;
+ int i;
+ char *path = NULL;
+ WERROR result = WERR_OK;
+
+ /* initialize the REGISTRY_KEY structure */
+
+ registry_key.ops = reghook_cache_find(topkeypath);
+ if (!registry_key.ops) {
+ DEBUG(0, ("reg_load_tree: Failed to assign REGISTRY_OPS "
+ "to [%s]\n", topkeypath));
+ return WERR_BADFILE;
+ }
+
+ registry_key.name = talloc_strdup(regfile->mem_ctx, topkeypath);
+ if (!registry_key.name) {
+ DEBUG(0, ("reg_load_tree: Talloc failed for reg_key.name!\n"));
+ return WERR_NOMEM;
+ }
+
+ /* now start parsing the values and subkeys */
+
+ subkeys = TALLOC_ZERO_P(regfile->mem_ctx, REGSUBKEY_CTR);
+ if (subkeys == NULL) {
+ return WERR_NOMEM;
+ }
+
+ values = TALLOC_ZERO_P(subkeys, REGVAL_CTR);
+ if (values == NULL) {
+ return WERR_NOMEM;
+ }
+
+ /* copy values into the REGVAL_CTR */
+
+ for (i=0; i<key->num_values; i++) {
+ regval_ctr_addvalue(values, key->values[i].valuename,
+ key->values[i].type,
+ (char*)key->values[i].data,
+ (key->values[i].data_size & ~VK_DATA_IN_OFFSET));
+ }
+
+ /* copy subkeys into the REGSUBKEY_CTR */
+
+ key->subkey_index = 0;
+ while ((subkey = regfio_fetch_subkey( regfile, key ))) {
+ result = regsubkey_ctr_addkey(subkeys, subkey->keyname);
+ if (!W_ERROR_IS_OK(result)) {
+ TALLOC_FREE(subkeys);
+ return result;
+ }
+ }
+
+ /* write this key and values out */
+
+ if (!store_reg_values(&registry_key, values)
+ || !store_reg_keys(&registry_key, subkeys))
+ {
+ DEBUG(0,("reg_load_tree: Failed to load %s!\n", topkeypath));
+ result = WERR_REG_IO_FAILURE;
+ }
+
+ TALLOC_FREE(subkeys);
+
+ if (!W_ERROR_IS_OK(result)) {
+ return result;
+ }
+
+ /* now continue to load each subkey registry tree */
+
+ key->subkey_index = 0;
+ while ((subkey = regfio_fetch_subkey(regfile, key))) {
+ path = talloc_asprintf(regfile->mem_ctx,
+ "%s\\%s",
+ topkeypath,
+ subkey->keyname);
+ if (path == NULL) {
+ return WERR_NOMEM;
+ }
+ result = reg_load_tree(regfile, path, subkey);
+ if (!W_ERROR_IS_OK(result)) {
+ break;
+ }
+ }
+
+ return result;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static WERROR restore_registry_key(REGISTRY_KEY *krecord, const char *fname)
+{
+ REGF_FILE *regfile;
+ REGF_NK_REC *rootkey;
+ WERROR result;
+
+ /* open the registry file....fail if the file already exists */
+
+ regfile = regfio_open(fname, (O_RDONLY), 0);
+ if (regfile == NULL) {
+ DEBUG(0, ("restore_registry_key: failed to open \"%s\" (%s)\n",
+ fname, strerror(errno)));
+ return ntstatus_to_werror(map_nt_error_from_unix(errno));
+ }
+
+ /* get the rootkey from the regf file and then load the tree
+ via recursive calls */
+
+ if (!(rootkey = regfio_rootkey(regfile))) {
+ regfio_close(regfile);
+ return WERR_REG_FILE_INVALID;
+ }
+
+ result = reg_load_tree(regfile, krecord->name, rootkey);
+
+ /* cleanup */
+
+ regfio_close(regfile);
+
+ return result;
+}
+
+WERROR reg_restorekey(struct registry_key *key, const char *fname)
+{
+ return restore_registry_key(key->key, fname);
+}
+
+/********************************************************************
+********************************************************************/
+
+static WERROR reg_write_tree(REGF_FILE *regfile, const char *keypath,
+ REGF_NK_REC *parent)
+{
+ REGF_NK_REC *key;
+ REGVAL_CTR *values;
+ REGSUBKEY_CTR *subkeys;
+ int i, num_subkeys;
+ char *key_tmp = NULL;
+ char *keyname, *parentpath;
+ char *subkeypath = NULL;
+ char *subkeyname;
+ REGISTRY_KEY registry_key;
+ WERROR result = WERR_OK;
+ SEC_DESC *sec_desc = NULL;
+
+ if (!regfile) {
+ return WERR_GENERAL_FAILURE;
+ }
+
+ if (!keypath) {
+ return WERR_OBJECT_PATH_INVALID;
+ }
+
+ /* split up the registry key path */
+
+ key_tmp = talloc_strdup(regfile->mem_ctx, keypath);
+ if (!key_tmp) {
+ return WERR_NOMEM;
+ }
+ if (!reg_split_key(key_tmp, &parentpath, &keyname)) {
+ return WERR_OBJECT_PATH_INVALID;
+ }
+
+ if (!keyname) {
+ keyname = parentpath;
+ }
+
+ /* we need a REGISTRY_KEY object here to enumerate subkeys and values */
+
+ ZERO_STRUCT(registry_key);
+
+ registry_key.name = talloc_strdup(regfile->mem_ctx, keypath);
+ if (registry_key.name == NULL) {
+ return WERR_NOMEM;
+ }
+
+ registry_key.ops = reghook_cache_find(registry_key.name);
+ if (registry_key.ops == NULL) {
+ return WERR_BADFILE;
+ }
+
+ /* lookup the values and subkeys */
+
+ subkeys = TALLOC_ZERO_P(regfile->mem_ctx, REGSUBKEY_CTR);
+ if (subkeys == NULL) {
+ return WERR_NOMEM;
+ }
+
+ values = TALLOC_ZERO_P(subkeys, REGVAL_CTR);
+ if (values == NULL) {
+ return WERR_NOMEM;
+ }
+
+ fetch_reg_keys(&registry_key, subkeys);
+ fetch_reg_values(&registry_key, values);
+
+ result = regkey_get_secdesc(regfile->mem_ctx, &registry_key, &sec_desc);
+ if (!W_ERROR_IS_OK(result)) {
+ goto done;
+ }
+
+ /* write out this key */
+
+ key = regfio_write_key(regfile, keyname, values, subkeys, sec_desc,
+ parent);
+ if (key == NULL) {
+ result = WERR_CAN_NOT_COMPLETE;
+ goto done;
+ }
+
+ /* write each one of the subkeys out */
+
+ num_subkeys = regsubkey_ctr_numkeys(subkeys);
+ for (i=0; i<num_subkeys; i++) {
+ subkeyname = regsubkey_ctr_specific_key(subkeys, i);
+ subkeypath = talloc_asprintf(regfile->mem_ctx, "%s\\%s",
+ keypath, subkeyname);
+ if (subkeypath == NULL) {
+ result = WERR_NOMEM;
+ goto done;
+ }
+ result = reg_write_tree(regfile, subkeypath, key);
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+ }
+
+ DEBUG(6, ("reg_write_tree: wrote key [%s]\n", keypath));
+
+done:
+ TALLOC_FREE(subkeys);
+ TALLOC_FREE(registry_key.name);
+
+ return result;
+}
+
+static WERROR backup_registry_key(REGISTRY_KEY *krecord, const char *fname)
+{
+ REGF_FILE *regfile;
+ WERROR result;
+
+ /* open the registry file....fail if the file already exists */
+
+ regfile = regfio_open(fname, (O_RDWR|O_CREAT|O_EXCL),
+ (S_IREAD|S_IWRITE));
+ if (regfile == NULL) {
+ DEBUG(0,("backup_registry_key: failed to open \"%s\" (%s)\n",
+ fname, strerror(errno) ));
+ return ntstatus_to_werror(map_nt_error_from_unix(errno));
+ }
+
+ /* write the registry tree to the file */
+
+ result = reg_write_tree(regfile, krecord->name, NULL);
+
+ /* cleanup */
+
+ regfio_close(regfile);
+
+ return result;
+}
+
+WERROR reg_savekey(struct registry_key *key, const char *fname)
+{
+ return backup_registry_key(key->key, fname);
+}
+
+/**********************************************************************
+ * Higher level utility functions
+ **********************************************************************/
+
+WERROR reg_deleteallvalues(struct registry_key *key)
+{
+ WERROR err;
+ int i;
+
+ if (!(key->key->access_granted & SEC_RIGHTS_SET_VALUE)) {
+ return WERR_ACCESS_DENIED;
+ }
+
+ if (!W_ERROR_IS_OK(err = fill_value_cache(key))) {
+ return err;
+ }
+
+ for (i=0; i<key->values->num_values; i++) {
+ regval_ctr_delvalue(key->values, key->values->values[i]->valuename);
+ }
+
+ if (!store_reg_values(key->key, key->values)) {
+ TALLOC_FREE(key->values);
+ return WERR_REG_IO_FAILURE;
+ }
+
+ return WERR_OK;
+}
+
+/*
+ * Utility function to open a complete registry path including the hive prefix.
+ */
+
+WERROR reg_open_path(TALLOC_CTX *mem_ctx, const char *orig_path,
+ uint32 desired_access, const struct nt_user_token *token,
+ struct registry_key **pkey)
+{
+ struct registry_key *hive, *key;
+ char *path, *p;
+ WERROR err;
+
+ if (!(path = SMB_STRDUP(orig_path))) {
+ return WERR_NOMEM;
+ }
+
+ p = strchr(path, '\\');
+
+ if ((p == NULL) || (p[1] == '\0')) {
+ /*
+ * No key behind the hive, just return the hive
+ */
+
+ err = reg_openhive(mem_ctx, path, desired_access, token,
+ &hive);
+ if (!W_ERROR_IS_OK(err)) {
+ SAFE_FREE(path);
+ return err;
+ }
+ SAFE_FREE(path);
+ *pkey = hive;
+ return WERR_OK;
+ }
+
+ *p = '\0';
+
+ err = reg_openhive(mem_ctx, path, SEC_RIGHTS_ENUM_SUBKEYS, token,
+ &hive);
+ if (!W_ERROR_IS_OK(err)) {
+ SAFE_FREE(path);
+ return err;
+ }
+
+ err = reg_openkey(mem_ctx, hive, p+1, desired_access, &key);
+
+ TALLOC_FREE(hive);
+ SAFE_FREE(path);
+
+ if (!W_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ *pkey = key;
+ return WERR_OK;
+}
+
+/*
+ * Utility function to delete a registry key with all its subkeys.
+ * Note that reg_deletekey returns ACCESS_DENIED when called on a
+ * key that has subkeys.
+ */
+static WERROR reg_deletekey_recursive_internal(TALLOC_CTX *ctx,
+ struct registry_key *parent,
+ const char *path,
+ bool del_key)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ WERROR werr = WERR_OK;
+ struct registry_key *key;
+ char *subkey_name = NULL;
+
+ mem_ctx = talloc_new(ctx);
+ if (mem_ctx == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ /* recurse through subkeys first */
+ werr = reg_openkey(mem_ctx, parent, path, REG_KEY_ALL, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ while (W_ERROR_IS_OK(werr = reg_enumkey(mem_ctx, key, 0,
+ &subkey_name, NULL)))
+ {
+ werr = reg_deletekey_recursive_internal(mem_ctx, key,
+ subkey_name,
+ true);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ }
+ if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
+ DEBUG(1, ("reg_deletekey_recursive_internal: "
+ "Error enumerating subkeys: %s\n",
+ dos_errstr(werr)));
+ goto done;
+ }
+
+ werr = WERR_OK;
+
+ if (del_key) {
+ /* now delete the actual key */
+ werr = reg_deletekey(parent, path);
+ }
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return werr;
+}
+
+WERROR reg_deletekey_recursive(TALLOC_CTX *ctx,
+ struct registry_key *parent,
+ const char *path)
+{
+ return reg_deletekey_recursive_internal(ctx, parent, path, true);
+}
+
+WERROR reg_deletesubkeys_recursive(TALLOC_CTX *ctx,
+ struct registry_key *parent,
+ const char *path)
+{
+ return reg_deletekey_recursive_internal(ctx, parent, path, false);
+}
+
+#if 0
+/* these two functions are unused. */
+
+/**
+ * Utility function to create a registry key without opening the hive
+ * before. Assumes the hive already exists.
+ */
+
+WERROR reg_create_path(TALLOC_CTX *mem_ctx, const char *orig_path,
+ uint32 desired_access,
+ const struct nt_user_token *token,
+ enum winreg_CreateAction *paction,
+ struct registry_key **pkey)
+{
+ struct registry_key *hive;
+ char *path, *p;
+ WERROR err;
+
+ if (!(path = SMB_STRDUP(orig_path))) {
+ return WERR_NOMEM;
+ }
+
+ p = strchr(path, '\\');
+
+ if ((p == NULL) || (p[1] == '\0')) {
+ /*
+ * No key behind the hive, just return the hive
+ */
+
+ err = reg_openhive(mem_ctx, path, desired_access, token,
+ &hive);
+ if (!W_ERROR_IS_OK(err)) {
+ SAFE_FREE(path);
+ return err;
+ }
+ SAFE_FREE(path);
+ *pkey = hive;
+ *paction = REG_OPENED_EXISTING_KEY;
+ return WERR_OK;
+ }
+
+ *p = '\0';
+
+ err = reg_openhive(mem_ctx, path,
+ (strchr(p+1, '\\') != NULL) ?
+ SEC_RIGHTS_ENUM_SUBKEYS : SEC_RIGHTS_CREATE_SUBKEY,
+ token, &hive);
+ if (!W_ERROR_IS_OK(err)) {
+ SAFE_FREE(path);
+ return err;
+ }
+
+ err = reg_createkey(mem_ctx, hive, p+1, desired_access, pkey, paction);
+ SAFE_FREE(path);
+ TALLOC_FREE(hive);
+ return err;
+}
+
+/*
+ * Utility function to create a registry key without opening the hive
+ * before. Will not delete a hive.
+ */
+
+WERROR reg_delete_path(const struct nt_user_token *token,
+ const char *orig_path)
+{
+ struct registry_key *hive;
+ char *path, *p;
+ WERROR err;
+
+ if (!(path = SMB_STRDUP(orig_path))) {
+ return WERR_NOMEM;
+ }
+
+ p = strchr(path, '\\');
+
+ if ((p == NULL) || (p[1] == '\0')) {
+ SAFE_FREE(path);
+ return WERR_INVALID_PARAM;
+ }
+
+ *p = '\0';
+
+ err = reg_openhive(NULL, path,
+ (strchr(p+1, '\\') != NULL) ?
+ SEC_RIGHTS_ENUM_SUBKEYS : SEC_RIGHTS_CREATE_SUBKEY,
+ token, &hive);
+ if (!W_ERROR_IS_OK(err)) {
+ SAFE_FREE(path);
+ return err;
+ }
+
+ err = reg_deletekey(hive, p+1);
+ SAFE_FREE(path);
+ TALLOC_FREE(hive);
+ return err;
+}
+#endif /* #if 0 */
diff --git a/source3/registry/reg_backend_current_version.c b/source3/registry/reg_backend_current_version.c
new file mode 100644
index 0000000000..04cc0ebfa7
--- /dev/null
+++ b/source3/registry/reg_backend_current_version.c
@@ -0,0 +1,81 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * CurrentVersion registry backend.
+ *
+ * This is a virtual overlay, dynamically presenting version information.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+extern REGISTRY_OPS regdb_ops;
+
+#define KEY_CURRENT_VERSION_NORM "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION"
+
+static int current_version_fetch_values(const char *key, REGVAL_CTR *values)
+{
+ const char *sysroot_string = "c:\\Windows";
+ fstring sysversion;
+ fstring value;
+ uint32 value_length;
+ char *path = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ path = talloc_strdup(ctx, key);
+ if (path == NULL) {
+ return -1;
+ }
+ path = normalize_reg_path(ctx, path);
+ if (path == NULL) {
+ return -1;
+ }
+
+ if (strncmp(path, KEY_CURRENT_VERSION_NORM, strlen(path)) != 0) {
+ return regdb_ops.fetch_values(key, values);
+ }
+
+ value_length = push_ucs2(value, value, sysroot_string, sizeof(value),
+ STR_TERMINATE|STR_NOALIGN );
+ regval_ctr_addvalue(values, "SystemRoot", REG_SZ, value, value_length);
+
+ fstr_sprintf(sysversion, "%d.%d", lp_major_announce_version(),
+ lp_minor_announce_version());
+ value_length = push_ucs2(value, value, sysversion, sizeof(value),
+ STR_TERMINATE|STR_NOALIGN);
+ regval_ctr_addvalue(values, "CurrentVersion", REG_SZ, value,
+ value_length);
+
+ return regval_ctr_numvals(values);
+}
+
+static int current_version_fetch_subkeys(const char *key,
+ REGSUBKEY_CTR *subkey_ctr)
+{
+ return regdb_ops.fetch_subkeys(key, subkey_ctr);
+}
+
+REGISTRY_OPS current_version_reg_ops = {
+ .fetch_values = current_version_fetch_values,
+ .fetch_subkeys = current_version_fetch_subkeys,
+};
diff --git a/source3/registry/reg_backend_db.c b/source3/registry/reg_backend_db.c
new file mode 100644
index 0000000000..6f4c614b9a
--- /dev/null
+++ b/source3/registry/reg_backend_db.c
@@ -0,0 +1,1271 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Implementation of internal registry database functions. */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+static struct db_context *regdb = NULL;
+static int regdb_refcount;
+
+static bool regdb_key_exists(const char *key);
+static bool regdb_key_is_base_key(const char *key);
+
+/* List the deepest path into the registry. All part components will be created.*/
+
+/* If you want to have a part of the path controlled by the tdb and part by
+ a virtual registry db (e.g. printing), then you have to list the deepest path.
+ For example,"HKLM/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Print"
+ allows the reg_db backend to handle everything up to
+ "HKLM/SOFTWARE/Microsoft/Windows NT/CurrentVersion" and then we'll hook
+ the reg_printing backend onto the last component of the path (see
+ KEY_PRINTING_2K in include/rpc_reg.h) --jerry */
+
+static const char *builtin_registry_paths[] = {
+ KEY_PRINTING_2K,
+ KEY_PRINTING_PORTS,
+ KEY_PRINTING,
+ KEY_SHARES,
+ KEY_EVENTLOG,
+ KEY_SMBCONF,
+ KEY_PERFLIB,
+ KEY_PERFLIB_009,
+ KEY_GROUP_POLICY,
+ KEY_SAMBA_GROUP_POLICY,
+ KEY_GP_MACHINE_POLICY,
+ KEY_GP_MACHINE_WIN_POLICY,
+ KEY_HKCU,
+ KEY_GP_USER_POLICY,
+ KEY_GP_USER_WIN_POLICY,
+ KEY_WINLOGON_GPEXT_PATH,
+ "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors",
+ KEY_PROD_OPTIONS,
+ "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\DefaultUserConfiguration",
+ KEY_TCPIP_PARAMS,
+ KEY_NETLOGON_PARAMS,
+ KEY_HKU,
+ KEY_HKCR,
+ KEY_HKPD,
+ KEY_HKPT,
+ NULL };
+
+struct builtin_regkey_value {
+ const char *path;
+ const char *valuename;
+ uint32 type;
+ union {
+ const char *string;
+ uint32 dw_value;
+ } data;
+};
+
+static struct builtin_regkey_value builtin_registry_values[] = {
+ { KEY_PRINTING_PORTS,
+ SAMBA_PRINTER_PORT_NAME, REG_SZ, { "" } },
+ { KEY_PRINTING_2K,
+ "DefaultSpoolDirectory", REG_SZ, { "C:\\Windows\\System32\\Spool\\Printers" } },
+ { KEY_EVENTLOG,
+ "DisplayName", REG_SZ, { "Event Log" } },
+ { KEY_EVENTLOG,
+ "ErrorControl", REG_DWORD, { (char*)0x00000001 } },
+ { NULL, NULL, 0, { NULL } }
+};
+
+/**
+ * Initialize a key in the registry:
+ * create each component key of the specified path.
+ */
+static WERROR init_registry_key_internal(const char *add_path)
+{
+ WERROR werr;
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *path = NULL;
+ char *base = NULL;
+ char *remaining = NULL;
+ char *keyname;
+ char *subkeyname;
+ REGSUBKEY_CTR *subkeys;
+ const char *p, *p2;
+
+ DEBUG(6, ("init_registry_key: Adding [%s]\n", add_path));
+
+ path = talloc_strdup(frame, add_path);
+ base = talloc_strdup(frame, "");
+ if (!path || !base) {
+ werr = WERR_NOMEM;
+ goto fail;
+ }
+ p = path;
+
+ while (next_token_talloc(frame, &p, &keyname, "\\")) {
+
+ /* build up the registry path from the components */
+
+ if (*base) {
+ base = talloc_asprintf(frame, "%s\\", base);
+ if (!base) {
+ werr = WERR_NOMEM;
+ goto fail;
+ }
+ }
+ base = talloc_asprintf_append(base, "%s", keyname);
+ if (!base) {
+ werr = WERR_NOMEM;
+ goto fail;
+ }
+
+ /* get the immediate subkeyname (if we have one ) */
+
+ subkeyname = talloc_strdup(frame, "");
+ if (!subkeyname) {
+ werr = WERR_NOMEM;
+ goto fail;
+ }
+ if (*p) {
+ remaining = talloc_strdup(frame, p);
+ if (!remaining) {
+ werr = WERR_NOMEM;
+ goto fail;
+ }
+ p2 = remaining;
+
+ if (!next_token_talloc(frame, &p2,
+ &subkeyname, "\\"))
+ {
+ subkeyname = talloc_strdup(frame,p2);
+ if (!subkeyname) {
+ werr = WERR_NOMEM;
+ goto fail;
+ }
+ }
+ }
+
+ DEBUG(10,("init_registry_key: Storing key [%s] with "
+ "subkey [%s]\n", base,
+ *subkeyname ? subkeyname : "NULL"));
+
+ /* we don't really care if the lookup succeeds or not
+ * since we are about to update the record.
+ * We just want any subkeys already present */
+
+ if (!(subkeys = TALLOC_ZERO_P(frame, REGSUBKEY_CTR))) {
+ DEBUG(0,("talloc() failure!\n"));
+ werr = WERR_NOMEM;
+ goto fail;
+ }
+
+ regdb_fetch_keys(base, subkeys);
+ if (*subkeyname) {
+ werr = regsubkey_ctr_addkey(subkeys, subkeyname);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto fail;
+ }
+ }
+ if (!regdb_store_keys( base, subkeys)) {
+ werr = WERR_CAN_NOT_COMPLETE;
+ goto fail;
+ }
+ }
+
+ werr = WERR_OK;
+
+fail:
+ TALLOC_FREE(frame);
+ return werr;
+}
+
+/**
+ * Initialize a key in the registry:
+ * create each component key of the specified path,
+ * wrapped in one db transaction.
+ */
+WERROR init_registry_key(const char *add_path)
+{
+ WERROR werr;
+
+ if (regdb_key_exists(add_path)) {
+ return WERR_OK;
+ }
+
+ if (regdb->transaction_start(regdb) != 0) {
+ DEBUG(0, ("init_registry_key: transaction_start failed\n"));
+ return WERR_REG_IO_FAILURE;
+ }
+
+ werr = init_registry_key_internal(add_path);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto fail;
+ }
+
+ if (regdb->transaction_commit(regdb) != 0) {
+ DEBUG(0, ("init_registry_key: Could not commit transaction\n"));
+ return WERR_REG_IO_FAILURE;
+ }
+
+ return WERR_OK;
+
+fail:
+ if (regdb->transaction_cancel(regdb) != 0) {
+ smb_panic("init_registry_key: transaction_cancel failed\n");
+ }
+
+ return werr;
+}
+
+/***********************************************************************
+ Open the registry data in the tdb
+ ***********************************************************************/
+
+WERROR init_registry_data(void)
+{
+ WERROR werr;
+ TALLOC_CTX *frame = talloc_stackframe();
+ REGVAL_CTR *values;
+ int i;
+ UNISTR2 data;
+
+ /*
+ * First, check for the existence of the needed keys and values.
+ * If all do already exist, we can save the writes.
+ */
+ for (i=0; builtin_registry_paths[i] != NULL; i++) {
+ if (!regdb_key_exists(builtin_registry_paths[i])) {
+ goto do_init;
+ }
+ }
+
+ for (i=0; builtin_registry_values[i].path != NULL; i++) {
+ values = TALLOC_ZERO_P(frame, REGVAL_CTR);
+ if (values == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ regdb_fetch_values(builtin_registry_values[i].path, values);
+ if (!regval_ctr_key_exists(values,
+ builtin_registry_values[i].valuename))
+ {
+ TALLOC_FREE(values);
+ goto do_init;
+ }
+
+ TALLOC_FREE(values);
+ }
+
+ werr = WERR_OK;
+ goto done;
+
+do_init:
+
+ /*
+ * There are potentially quite a few store operations which are all
+ * indiviually wrapped in tdb transactions. Wrapping them in a single
+ * transaction gives just a single transaction_commit() to actually do
+ * its fsync()s. See tdb/common/transaction.c for info about nested
+ * transaction behaviour.
+ */
+
+ if (regdb->transaction_start(regdb) != 0) {
+ DEBUG(0, ("init_registry_data: tdb_transaction_start "
+ "failed\n"));
+ werr = WERR_REG_IO_FAILURE;
+ goto done;
+ }
+
+ /* loop over all of the predefined paths and add each component */
+
+ for (i=0; builtin_registry_paths[i] != NULL; i++) {
+ if (regdb_key_exists(builtin_registry_paths[i])) {
+ continue;
+ }
+ werr = init_registry_key_internal(builtin_registry_paths[i]);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto fail;
+ }
+ }
+
+ /* loop over all of the predefined values and add each component */
+
+ for (i=0; builtin_registry_values[i].path != NULL; i++) {
+
+ values = TALLOC_ZERO_P(frame, REGVAL_CTR);
+ if (values == NULL) {
+ werr = WERR_NOMEM;
+ goto fail;
+ }
+
+ regdb_fetch_values(builtin_registry_values[i].path, values);
+
+ /* preserve existing values across restarts. Only add new ones */
+
+ if (!regval_ctr_key_exists(values,
+ builtin_registry_values[i].valuename))
+ {
+ switch(builtin_registry_values[i].type) {
+ case REG_DWORD:
+ regval_ctr_addvalue(values,
+ builtin_registry_values[i].valuename,
+ REG_DWORD,
+ (char*)&builtin_registry_values[i].data.dw_value,
+ sizeof(uint32));
+ break;
+
+ case REG_SZ:
+ init_unistr2(&data,
+ builtin_registry_values[i].data.string,
+ UNI_STR_TERMINATE);
+ regval_ctr_addvalue(values,
+ builtin_registry_values[i].valuename,
+ REG_SZ,
+ (char*)data.buffer,
+ data.uni_str_len*sizeof(uint16));
+ break;
+
+ default:
+ DEBUG(0, ("init_registry_data: invalid value "
+ "type in builtin_registry_values "
+ "[%d]\n",
+ builtin_registry_values[i].type));
+ }
+ regdb_store_values(builtin_registry_values[i].path,
+ values);
+ }
+ TALLOC_FREE(values);
+ }
+
+ if (regdb->transaction_commit(regdb) != 0) {
+ DEBUG(0, ("init_registry_data: Could not commit "
+ "transaction\n"));
+ werr = WERR_REG_IO_FAILURE;
+ } else {
+ werr = WERR_OK;
+ }
+
+ goto done;
+
+fail:
+ if (regdb->transaction_cancel(regdb) != 0) {
+ smb_panic("init_registry_data: tdb_transaction_cancel "
+ "failed\n");
+ }
+
+done:
+ TALLOC_FREE(frame);
+ return werr;
+}
+
+/***********************************************************************
+ Open the registry database
+ ***********************************************************************/
+
+WERROR regdb_init(void)
+{
+ const char *vstring = "INFO/version";
+ uint32 vers_id;
+ WERROR werr;
+
+ if (regdb) {
+ DEBUG(10, ("regdb_init: incrementing refcount (%d)\n",
+ regdb_refcount));
+ regdb_refcount++;
+ return WERR_OK;
+ }
+
+ regdb = db_open(NULL, state_path("registry.tdb"), 0,
+ REG_TDB_FLAGS, O_RDWR, 0600);
+ if (!regdb) {
+ regdb = db_open(NULL, state_path("registry.tdb"), 0,
+ REG_TDB_FLAGS, O_RDWR|O_CREAT, 0600);
+ if (!regdb) {
+ werr = ntstatus_to_werror(map_nt_error_from_unix(errno));
+ DEBUG(1,("regdb_init: Failed to open registry %s (%s)\n",
+ state_path("registry.tdb"), strerror(errno) ));
+ return werr;
+ }
+
+ DEBUG(10,("regdb_init: Successfully created registry tdb\n"));
+ }
+
+ regdb_refcount = 1;
+
+ vers_id = dbwrap_fetch_int32(regdb, vstring);
+
+ if ( vers_id != REGVER_V1 ) {
+ NTSTATUS status;
+ /* any upgrade code here if needed */
+ DEBUG(10, ("regdb_init: got %s = %d != %d\n", vstring,
+ vers_id, REGVER_V1));
+ status = dbwrap_trans_store_int32(regdb, vstring, REGVER_V1);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("regdb_init: error storing %s = %d: %s\n",
+ vstring, REGVER_V1, nt_errstr(status)));
+ return ntstatus_to_werror(status);
+ } else {
+ DEBUG(10, ("regdb_init: stored %s = %d\n",
+ vstring, REGVER_V1));
+ }
+ }
+
+ return WERR_OK;
+}
+
+/***********************************************************************
+ Open the registry. Must already have been initialized by regdb_init()
+ ***********************************************************************/
+
+WERROR regdb_open( void )
+{
+ WERROR result = WERR_OK;
+
+ if ( regdb ) {
+ DEBUG(10,("regdb_open: incrementing refcount (%d)\n", regdb_refcount));
+ regdb_refcount++;
+ return WERR_OK;
+ }
+
+ become_root();
+
+ regdb = db_open(NULL, state_path("registry.tdb"), 0,
+ REG_TDB_FLAGS, O_RDWR, 0600);
+ if ( !regdb ) {
+ result = ntstatus_to_werror( map_nt_error_from_unix( errno ) );
+ DEBUG(0,("regdb_open: Failed to open %s! (%s)\n",
+ state_path("registry.tdb"), strerror(errno) ));
+ }
+
+ unbecome_root();
+
+ regdb_refcount = 1;
+ DEBUG(10,("regdb_open: refcount reset (%d)\n", regdb_refcount));
+
+ return result;
+}
+
+/***********************************************************************
+ ***********************************************************************/
+
+int regdb_close( void )
+{
+ if (regdb_refcount == 0) {
+ return 0;
+ }
+
+ regdb_refcount--;
+
+ DEBUG(10,("regdb_close: decrementing refcount (%d)\n", regdb_refcount));
+
+ if ( regdb_refcount > 0 )
+ return 0;
+
+ SMB_ASSERT( regdb_refcount >= 0 );
+
+ TALLOC_FREE(regdb);
+ return 0;
+}
+
+/***********************************************************************
+ return the tdb sequence number of the registry tdb.
+ this is an indicator for the content of the registry
+ having changed. it will change upon regdb_init, too, though.
+ ***********************************************************************/
+int regdb_get_seqnum(void)
+{
+ return regdb->get_seqnum(regdb);
+}
+
+/***********************************************************************
+ Add subkey strings to the registry tdb under a defined key
+ fmt is the same format as tdb_pack except this function only supports
+ fstrings
+ ***********************************************************************/
+
+static bool regdb_store_keys_internal(const char *key, REGSUBKEY_CTR *ctr)
+{
+ TDB_DATA dbuf;
+ uint8 *buffer = NULL;
+ int i = 0;
+ uint32 len, buflen;
+ bool ret = true;
+ uint32 num_subkeys = regsubkey_ctr_numkeys(ctr);
+ char *keyname = NULL;
+ TALLOC_CTX *ctx = talloc_stackframe();
+ NTSTATUS status;
+
+ if (!key) {
+ return false;
+ }
+
+ keyname = talloc_strdup(ctx, key);
+ if (!keyname) {
+ return false;
+ }
+ keyname = normalize_reg_path(ctx, keyname);
+
+ /* allocate some initial memory */
+
+ buffer = (uint8 *)SMB_MALLOC(1024);
+ if (buffer == NULL) {
+ return false;
+ }
+ buflen = 1024;
+ len = 0;
+
+ /* store the number of subkeys */
+
+ len += tdb_pack(buffer+len, buflen-len, "d", num_subkeys);
+
+ /* pack all the strings */
+
+ for (i=0; i<num_subkeys; i++) {
+ len += tdb_pack(buffer+len, buflen-len, "f",
+ regsubkey_ctr_specific_key(ctr, i));
+ if (len > buflen) {
+ /* allocate some extra space */
+ buffer = (uint8 *)SMB_REALLOC(buffer, len*2);
+ if(buffer == NULL) {
+ DEBUG(0, ("regdb_store_keys: Failed to realloc "
+ "memory of size [%d]\n", len*2));
+ ret = false;
+ goto done;
+ }
+ buflen = len*2;
+ len = tdb_pack(buffer+len, buflen-len, "f",
+ regsubkey_ctr_specific_key(ctr, i));
+ }
+ }
+
+ /* finally write out the data */
+
+ dbuf.dptr = buffer;
+ dbuf.dsize = len;
+ status = dbwrap_store_bystring(regdb, keyname, dbuf, TDB_REPLACE);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ TALLOC_FREE(ctx);
+ SAFE_FREE(buffer);
+ return ret;
+}
+
+/***********************************************************************
+ Store the new subkey record and create any child key records that
+ do not currently exist
+ ***********************************************************************/
+
+bool regdb_store_keys(const char *key, REGSUBKEY_CTR *ctr)
+{
+ int num_subkeys, i;
+ char *path = NULL;
+ REGSUBKEY_CTR *subkeys = NULL, *old_subkeys = NULL;
+ char *oldkeyname = NULL;
+ TALLOC_CTX *ctx = talloc_stackframe();
+ NTSTATUS status;
+
+ if (!regdb_key_is_base_key(key) && !regdb_key_exists(key)) {
+ goto fail;
+ }
+
+ /*
+ * fetch a list of the old subkeys so we can determine if anything has
+ * changed
+ */
+
+ if (!(old_subkeys = TALLOC_ZERO_P(ctx, REGSUBKEY_CTR))) {
+ DEBUG(0,("regdb_store_keys: talloc() failure!\n"));
+ return false;
+ }
+
+ regdb_fetch_keys(key, old_subkeys);
+
+ if ((ctr->num_subkeys && old_subkeys->num_subkeys) &&
+ (ctr->num_subkeys == old_subkeys->num_subkeys)) {
+
+ for (i = 0; i<ctr->num_subkeys; i++) {
+ if (strcmp(ctr->subkeys[i],
+ old_subkeys->subkeys[i]) != 0) {
+ break;
+ }
+ }
+ if (i == ctr->num_subkeys) {
+ /*
+ * Nothing changed, no point to even start a tdb
+ * transaction
+ */
+ TALLOC_FREE(old_subkeys);
+ return true;
+ }
+ }
+
+ TALLOC_FREE(old_subkeys);
+
+ if (regdb->transaction_start(regdb) != 0) {
+ DEBUG(0, ("regdb_store_keys: transaction_start failed\n"));
+ goto fail;
+ }
+
+ /*
+ * Re-fetch the old keys inside the transaction
+ */
+
+ if (!(old_subkeys = TALLOC_ZERO_P(ctx, REGSUBKEY_CTR))) {
+ DEBUG(0,("regdb_store_keys: talloc() failure!\n"));
+ goto cancel;
+ }
+
+ regdb_fetch_keys(key, old_subkeys);
+
+ /*
+ * Make the store operation as safe as possible without transactions:
+ *
+ * (1) For each subkey removed from ctr compared with old_subkeys:
+ *
+ * (a) First delete the value db entry.
+ *
+ * (b) Next delete the secdesc db record.
+ *
+ * (c) Then delete the subkey list entry.
+ *
+ * (2) Now write the list of subkeys of the parent key,
+ * deleting removed entries and adding new ones.
+ *
+ * (3) Finally create the subkey list entries for the added keys.
+ *
+ * This way if we crash half-way in between deleting the subkeys
+ * and storing the parent's list of subkeys, no old data can pop up
+ * out of the blue when re-adding keys later on.
+ */
+
+ /* (1) delete removed keys' lists (values/secdesc/subkeys) */
+
+ num_subkeys = regsubkey_ctr_numkeys(old_subkeys);
+ for (i=0; i<num_subkeys; i++) {
+ oldkeyname = regsubkey_ctr_specific_key(old_subkeys, i);
+
+ if (regsubkey_ctr_key_exists(ctr, oldkeyname)) {
+ /*
+ * It's still around, don't delete
+ */
+
+ continue;
+ }
+
+ /* (a) Delete the value list for this key */
+
+ path = talloc_asprintf(ctx, "%s/%s/%s",
+ REG_VALUE_PREFIX,
+ key,
+ oldkeyname );
+ if (!path) {
+ goto cancel;
+ }
+ path = normalize_reg_path(ctx, path);
+ if (!path) {
+ goto cancel;
+ }
+ /* Ignore errors here, we might have no values around */
+ dbwrap_delete_bystring(regdb, path);
+ TALLOC_FREE(path);
+
+ /* (b) Delete the secdesc for this key */
+
+ path = talloc_asprintf(ctx, "%s/%s/%s",
+ REG_SECDESC_PREFIX,
+ key,
+ oldkeyname );
+ if (!path) {
+ goto cancel;
+ }
+ path = normalize_reg_path(ctx, path);
+ if (!path) {
+ goto cancel;
+ }
+ status = dbwrap_delete_bystring(regdb, path);
+ /* Don't fail if there are no values around. */
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND))
+ {
+ DEBUG(1, ("Deleting %s failed: %s\n", path,
+ nt_errstr(status)));
+ goto cancel;
+ }
+ TALLOC_FREE(path);
+
+ /* (c) Delete the list of subkeys of this key */
+
+ path = talloc_asprintf(ctx, "%s/%s", key, oldkeyname);
+ if (!path) {
+ goto cancel;
+ }
+ path = normalize_reg_path(ctx, path);
+ if (!path) {
+ goto cancel;
+ }
+ status = dbwrap_delete_bystring(regdb, path);
+ /* Don't fail if the subkey record was not found. */
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND))
+ {
+ DEBUG(1, ("Deleting %s failed: %s\n", path,
+ nt_errstr(status)));
+ goto cancel;
+ }
+ TALLOC_FREE(path);
+ }
+
+ TALLOC_FREE(old_subkeys);
+
+ /* (2) store the subkey list for the parent */
+
+ if (!regdb_store_keys_internal(key, ctr) ) {
+ DEBUG(0,("regdb_store_keys: Failed to store new subkey list "
+ "for parent [%s]\n", key));
+ goto cancel;
+ }
+
+ /* (3) now create records for any subkeys that don't already exist */
+
+ num_subkeys = regsubkey_ctr_numkeys(ctr);
+
+ if (num_subkeys == 0) {
+ if (!(subkeys = TALLOC_ZERO_P(ctx, REGSUBKEY_CTR)) ) {
+ DEBUG(0,("regdb_store_keys: talloc() failure!\n"));
+ goto cancel;
+ }
+
+ if (!regdb_store_keys_internal(key, subkeys)) {
+ DEBUG(0,("regdb_store_keys: Failed to store "
+ "new record for key [%s]\n", key));
+ goto cancel;
+ }
+ TALLOC_FREE(subkeys);
+
+ }
+
+ for (i=0; i<num_subkeys; i++) {
+ path = talloc_asprintf(ctx, "%s/%s",
+ key,
+ regsubkey_ctr_specific_key(ctr, i));
+ if (!path) {
+ goto cancel;
+ }
+ if (!(subkeys = TALLOC_ZERO_P(ctx, REGSUBKEY_CTR)) ) {
+ DEBUG(0,("regdb_store_keys: talloc() failure!\n"));
+ goto cancel;
+ }
+
+ if (regdb_fetch_keys( path, subkeys ) == -1) {
+ /* create a record with 0 subkeys */
+ if (!regdb_store_keys_internal(path, subkeys)) {
+ DEBUG(0,("regdb_store_keys: Failed to store "
+ "new record for key [%s]\n", path));
+ goto cancel;
+ }
+ }
+
+ TALLOC_FREE(subkeys);
+ TALLOC_FREE(path);
+ }
+
+ if (regdb->transaction_commit(regdb) != 0) {
+ DEBUG(0, ("regdb_store_keys: Could not commit transaction\n"));
+ goto fail;
+ }
+
+ TALLOC_FREE(ctx);
+ return true;
+
+cancel:
+ if (regdb->transaction_cancel(regdb) != 0) {
+ smb_panic("regdb_store_keys: transaction_cancel failed\n");
+ }
+
+fail:
+ TALLOC_FREE(ctx);
+
+ return false;
+}
+
+
+static TDB_DATA regdb_fetch_key_internal(TALLOC_CTX *mem_ctx, const char *key)
+{
+ char *path = NULL;
+ TDB_DATA data;
+
+ path = normalize_reg_path(mem_ctx, key);
+ if (!path) {
+ return make_tdb_data(NULL, 0);
+ }
+
+ data = dbwrap_fetch_bystring(regdb, mem_ctx, path);
+
+ TALLOC_FREE(path);
+ return data;
+}
+
+
+/**
+ * check whether a given key name represents a base key,
+ * i.e one without a subkey separator ('/' or '\').
+ */
+static bool regdb_key_is_base_key(const char *key)
+{
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+ bool ret = false;
+ char *path;
+
+ if (key == NULL) {
+ goto done;
+ }
+
+ path = normalize_reg_path(mem_ctx, key);
+ if (path == NULL) {
+ DEBUG(0, ("out of memory! (talloc failed)\n"));
+ goto done;
+ }
+
+ if (*path == '\0') {
+ goto done;
+ }
+
+ ret = (strrchr(path, '/') == NULL);
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+
+/**
+ * Check for the existence of a key.
+ *
+ * Existence of a key is authoritatively defined by its
+ * existence in the list of subkeys of its parent key.
+ * The exeption of this are keys without a parent key,
+ * i.e. the "base" keys (HKLM, HKCU, ...).
+ */
+static bool regdb_key_exists(const char *key)
+{
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+ TDB_DATA value;
+ bool ret = false;
+ char *path, *p;
+
+ if (key == NULL) {
+ goto done;
+ }
+
+ path = normalize_reg_path(mem_ctx, key);
+ if (path == NULL) {
+ DEBUG(0, ("out of memory! (talloc failed)\n"));
+ goto done;
+ }
+
+ if (*path == '\0') {
+ goto done;
+ }
+
+ p = strrchr(path, '/');
+ if (p == NULL) {
+ /* this is a base key */
+ value = regdb_fetch_key_internal(mem_ctx, path);
+ ret = (value.dptr != NULL);
+ } else {
+ /* get the list of subkeys of the parent key */
+ uint32 num_items, len, i;
+ fstring subkeyname;
+
+ *p = '\0';
+ p++;
+ value = regdb_fetch_key_internal(mem_ctx, path);
+ if (value.dptr == NULL) {
+ goto done;
+ }
+
+ len = tdb_unpack(value.dptr, value.dsize, "d", &num_items);
+ for (i = 0; i < num_items; i++) {
+ len += tdb_unpack(value.dptr +len, value.dsize -len,
+ "f", &subkeyname);
+ if (strequal(subkeyname, p)) {
+ ret = true;
+ goto done;
+ }
+ }
+ }
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+
+/***********************************************************************
+ Retrieve an array of strings containing subkeys. Memory should be
+ released by the caller.
+ ***********************************************************************/
+
+int regdb_fetch_keys(const char *key, REGSUBKEY_CTR *ctr)
+{
+ WERROR werr;
+ uint32 num_items;
+ uint8 *buf;
+ uint32 buflen, len;
+ int i;
+ fstring subkeyname;
+ int ret = -1;
+ TALLOC_CTX *frame = talloc_stackframe();
+ TDB_DATA value;
+
+ DEBUG(11,("regdb_fetch_keys: Enter key => [%s]\n", key ? key : "NULL"));
+
+ if (!regdb_key_exists(key)) {
+ goto done;
+ }
+
+ ctr->seqnum = regdb_get_seqnum();
+
+ value = regdb_fetch_key_internal(frame, key);
+
+ if (value.dptr == NULL) {
+ DEBUG(10, ("regdb_fetch_keys: no subkeys found for key [%s]\n",
+ key));
+ ret = 0;
+ goto done;
+ }
+
+ buf = value.dptr;
+ buflen = value.dsize;
+ len = tdb_unpack( buf, buflen, "d", &num_items);
+
+ for (i=0; i<num_items; i++) {
+ len += tdb_unpack(buf+len, buflen-len, "f", subkeyname);
+ werr = regsubkey_ctr_addkey(ctr, subkeyname);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(5, ("regdb_fetch_keys: regsubkey_ctr_addkey "
+ "failed: %s\n", dos_errstr(werr)));
+ goto done;
+ }
+ }
+
+ DEBUG(11,("regdb_fetch_keys: Exit [%d] items\n", num_items));
+
+ ret = num_items;
+done:
+ TALLOC_FREE(frame);
+ return ret;
+}
+
+/****************************************************************************
+ Unpack a list of registry values frem the TDB
+ ***************************************************************************/
+
+static int regdb_unpack_values(REGVAL_CTR *values, uint8 *buf, int buflen)
+{
+ int len = 0;
+ uint32 type;
+ fstring valuename;
+ uint32 size;
+ uint8 *data_p;
+ uint32 num_values = 0;
+ int i;
+
+ /* loop and unpack the rest of the registry values */
+
+ len += tdb_unpack(buf+len, buflen-len, "d", &num_values);
+
+ for ( i=0; i<num_values; i++ ) {
+ /* unpack the next regval */
+
+ type = REG_NONE;
+ size = 0;
+ data_p = NULL;
+ valuename[0] = '\0';
+ len += tdb_unpack(buf+len, buflen-len, "fdB",
+ valuename,
+ &type,
+ &size,
+ &data_p);
+
+ /* add the new value. Paranoid protective code -- make sure data_p is valid */
+
+ if (*valuename && size && data_p) {
+ regval_ctr_addvalue(values, valuename, type,
+ (const char *)data_p, size);
+ }
+ SAFE_FREE(data_p); /* 'B' option to tdb_unpack does a malloc() */
+
+ DEBUG(8,("specific: [%s], len: %d\n", valuename, size));
+ }
+
+ return len;
+}
+
+/****************************************************************************
+ Pack all values in all printer keys
+ ***************************************************************************/
+
+static int regdb_pack_values(REGVAL_CTR *values, uint8 *buf, int buflen)
+{
+ int len = 0;
+ int i;
+ REGISTRY_VALUE *val;
+ int num_values;
+
+ if ( !values )
+ return 0;
+
+ num_values = regval_ctr_numvals( values );
+
+ /* pack the number of values first */
+
+ len += tdb_pack( buf+len, buflen-len, "d", num_values );
+
+ /* loop over all values */
+
+ for ( i=0; i<num_values; i++ ) {
+ val = regval_ctr_specific_value( values, i );
+ len += tdb_pack(buf+len, buflen-len, "fdB",
+ regval_name(val),
+ regval_type(val),
+ regval_size(val),
+ regval_data_p(val) );
+ }
+
+ return len;
+}
+
+/***********************************************************************
+ Retrieve an array of strings containing subkeys. Memory should be
+ released by the caller.
+ ***********************************************************************/
+
+int regdb_fetch_values( const char* key, REGVAL_CTR *values )
+{
+ char *keystr = NULL;
+ TALLOC_CTX *ctx = talloc_stackframe();
+ int ret = 0;
+ TDB_DATA value;
+
+ DEBUG(10,("regdb_fetch_values: Looking for value of key [%s] \n", key));
+
+ if (!regdb_key_exists(key)) {
+ goto done;
+ }
+
+ keystr = talloc_asprintf(ctx, "%s/%s", REG_VALUE_PREFIX, key);
+ if (!keystr) {
+ goto done;
+ }
+
+ values->seqnum = regdb_get_seqnum();
+
+ value = regdb_fetch_key_internal(ctx, keystr);
+
+ if (!value.dptr) {
+ /* all keys have zero values by default */
+ goto done;
+ }
+
+ regdb_unpack_values(values, value.dptr, value.dsize);
+ ret = regval_ctr_numvals(values);
+
+done:
+ TALLOC_FREE(ctx);
+ return ret;
+}
+
+bool regdb_store_values( const char *key, REGVAL_CTR *values )
+{
+ TDB_DATA old_data, data;
+ char *keystr = NULL;
+ TALLOC_CTX *ctx = talloc_stackframe();
+ int len;
+ NTSTATUS status;
+ bool result = false;
+
+ DEBUG(10,("regdb_store_values: Looking for value of key [%s] \n", key));
+
+ if (!regdb_key_exists(key)) {
+ goto done;
+ }
+
+ ZERO_STRUCT(data);
+
+ len = regdb_pack_values(values, data.dptr, data.dsize);
+ if (len <= 0) {
+ DEBUG(0,("regdb_store_values: unable to pack values. len <= 0\n"));
+ goto done;
+ }
+
+ data.dptr = TALLOC_ARRAY(ctx, uint8, len);
+ data.dsize = len;
+
+ len = regdb_pack_values(values, data.dptr, data.dsize);
+
+ SMB_ASSERT( len == data.dsize );
+
+ keystr = talloc_asprintf(ctx, "%s/%s", REG_VALUE_PREFIX, key );
+ if (!keystr) {
+ goto done;
+ }
+ keystr = normalize_reg_path(ctx, keystr);
+ if (!keystr) {
+ goto done;
+ }
+
+ old_data = dbwrap_fetch_bystring(regdb, ctx, keystr);
+
+ if ((old_data.dptr != NULL)
+ && (old_data.dsize == data.dsize)
+ && (memcmp(old_data.dptr, data.dptr, data.dsize) == 0))
+ {
+ result = true;
+ goto done;
+ }
+
+ status = dbwrap_trans_store_bystring(regdb, keystr, data, TDB_REPLACE);
+
+ result = NT_STATUS_IS_OK(status);
+
+done:
+ TALLOC_FREE(ctx);
+ return result;
+}
+
+static WERROR regdb_get_secdesc(TALLOC_CTX *mem_ctx, const char *key,
+ struct security_descriptor **psecdesc)
+{
+ char *tdbkey;
+ TDB_DATA data;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ WERROR err = WERR_OK;
+
+ DEBUG(10, ("regdb_get_secdesc: Getting secdesc of key [%s]\n", key));
+
+ if (!regdb_key_exists(key)) {
+ err = WERR_BADFILE;
+ goto done;
+ }
+
+ tdbkey = talloc_asprintf(tmp_ctx, "%s/%s", REG_SECDESC_PREFIX, key);
+ if (tdbkey == NULL) {
+ err = WERR_NOMEM;
+ goto done;
+ }
+ normalize_dbkey(tdbkey);
+
+ data = dbwrap_fetch_bystring(regdb, tmp_ctx, tdbkey);
+ if (data.dptr == NULL) {
+ err = WERR_BADFILE;
+ goto done;
+ }
+
+ status = unmarshall_sec_desc(mem_ctx, (uint8 *)data.dptr, data.dsize,
+ psecdesc);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
+ err = WERR_NOMEM;
+ } else if (!NT_STATUS_IS_OK(status)) {
+ err = WERR_REG_CORRUPT;
+ }
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return err;
+}
+
+static WERROR regdb_set_secdesc(const char *key,
+ struct security_descriptor *secdesc)
+{
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+ char *tdbkey;
+ NTSTATUS status;
+ WERROR err = WERR_NOMEM;
+ TDB_DATA tdbdata;
+
+ if (!regdb_key_exists(key)) {
+ err = WERR_BADFILE;
+ goto done;
+ }
+
+ tdbkey = talloc_asprintf(mem_ctx, "%s/%s", REG_SECDESC_PREFIX, key);
+ if (tdbkey == NULL) {
+ goto done;
+ }
+ normalize_dbkey(tdbkey);
+
+ if (secdesc == NULL) {
+ /* assuming a delete */
+ status = dbwrap_trans_delete_bystring(regdb, tdbkey);
+ if (NT_STATUS_IS_OK(status)) {
+ err = WERR_OK;
+ } else {
+ err = ntstatus_to_werror(status);
+ }
+ goto done;
+ }
+
+ err = ntstatus_to_werror(marshall_sec_desc(mem_ctx, secdesc,
+ &tdbdata.dptr,
+ &tdbdata.dsize));
+ if (!W_ERROR_IS_OK(err)) {
+ goto done;
+ }
+
+ status = dbwrap_trans_store_bystring(regdb, tdbkey, tdbdata, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ err = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ done:
+ TALLOC_FREE(mem_ctx);
+ return err;
+}
+
+bool regdb_subkeys_need_update(REGSUBKEY_CTR *subkeys)
+{
+ return (regdb_get_seqnum() != subkeys->seqnum);
+}
+
+bool regdb_values_need_update(REGVAL_CTR *values)
+{
+ return (regdb_get_seqnum() != values->seqnum);
+}
+
+/*
+ * Table of function pointers for default access
+ */
+
+REGISTRY_OPS regdb_ops = {
+ .fetch_subkeys = regdb_fetch_keys,
+ .fetch_values = regdb_fetch_values,
+ .store_subkeys = regdb_store_keys,
+ .store_values = regdb_store_values,
+ .get_secdesc = regdb_get_secdesc,
+ .set_secdesc = regdb_set_secdesc,
+ .subkeys_need_update = regdb_subkeys_need_update,
+ .values_need_update = regdb_values_need_update
+};
diff --git a/source3/registry/reg_backend_hkpt_params.c b/source3/registry/reg_backend_hkpt_params.c
new file mode 100644
index 0000000000..2ed5e78e1c
--- /dev/null
+++ b/source3/registry/reg_backend_hkpt_params.c
@@ -0,0 +1,70 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * HKPT parameters registry backend.
+ *
+ * This replaces the former dynamic hkpt parameters overlay.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+extern REGISTRY_OPS regdb_ops;
+
+static int hkpt_params_fetch_values(const char *key, REGVAL_CTR *regvals)
+{
+ uint32 base_index;
+ uint32 buffer_size;
+ char *buffer = NULL;
+
+ /* This is ALMOST the same as perflib_009_params, but HKPT has
+ a "Counters" entry instead of a "Counter" key. <Grrrr> */
+
+ base_index = reg_perfcount_get_base_index();
+ buffer_size = reg_perfcount_get_counter_names(base_index, &buffer);
+ regval_ctr_addvalue(regvals, "Counters", REG_MULTI_SZ, buffer,
+ buffer_size);
+
+ if(buffer_size > 0) {
+ SAFE_FREE(buffer);
+ }
+
+ buffer_size = reg_perfcount_get_counter_help(base_index, &buffer);
+ regval_ctr_addvalue(regvals, "Help", REG_MULTI_SZ, buffer, buffer_size);
+ if(buffer_size > 0) {
+ SAFE_FREE(buffer);
+ }
+
+ return regval_ctr_numvals( regvals );
+}
+
+static int hkpt_params_fetch_subkeys(const char *key,
+ REGSUBKEY_CTR *subkey_ctr)
+{
+ return regdb_ops.fetch_subkeys(key, subkey_ctr);
+}
+
+REGISTRY_OPS hkpt_params_reg_ops = {
+ .fetch_values = hkpt_params_fetch_values,
+ .fetch_subkeys = hkpt_params_fetch_subkeys,
+};
diff --git a/source3/registry/reg_backend_netlogon_params.c b/source3/registry/reg_backend_netlogon_params.c
new file mode 100644
index 0000000000..71f88144c8
--- /dev/null
+++ b/source3/registry/reg_backend_netlogon_params.c
@@ -0,0 +1,57 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Netlogon parameters registry backend.
+ *
+ * This replaces the former dynamic netlogon parameters overlay.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+extern REGISTRY_OPS regdb_ops;
+
+static int netlogon_params_fetch_values(const char *key, REGVAL_CTR *regvals)
+{
+ uint32 dwValue;
+
+ if (!pdb_get_account_policy(AP_REFUSE_MACHINE_PW_CHANGE, &dwValue)) {
+ dwValue = 0;
+ }
+
+ regval_ctr_addvalue(regvals, "RefusePasswordChange", REG_DWORD,
+ (char*)&dwValue, sizeof(dwValue));
+
+ return regval_ctr_numvals(regvals);
+}
+
+static int netlogon_params_fetch_subkeys(const char *key,
+ REGSUBKEY_CTR *subkey_ctr)
+{
+ return regdb_ops.fetch_subkeys(key, subkey_ctr);
+}
+
+REGISTRY_OPS netlogon_params_reg_ops = {
+ .fetch_values = netlogon_params_fetch_values,
+ .fetch_subkeys = netlogon_params_fetch_subkeys,
+};
diff --git a/source3/registry/reg_backend_perflib.c b/source3/registry/reg_backend_perflib.c
new file mode 100644
index 0000000000..999bca2682
--- /dev/null
+++ b/source3/registry/reg_backend_perflib.c
@@ -0,0 +1,106 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * perflib registry backend.
+ *
+ * This is a virtual overlay, dynamically presenting perflib values.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+extern REGISTRY_OPS regdb_ops;
+
+#define KEY_PERFLIB_NORM "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PERFLIB"
+#define KEY_PERFLIB_009_NORM "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PERFLIB/009"
+
+static int perflib_params( REGVAL_CTR *regvals )
+{
+ int base_index = -1;
+ int last_counter = -1;
+ int last_help = -1;
+ int version = 0x00010001;
+
+ base_index = reg_perfcount_get_base_index();
+ regval_ctr_addvalue(regvals, "Base Index", REG_DWORD, (char *)&base_index, sizeof(base_index));
+ last_counter = reg_perfcount_get_last_counter(base_index);
+ regval_ctr_addvalue(regvals, "Last Counter", REG_DWORD, (char *)&last_counter, sizeof(last_counter));
+ last_help = reg_perfcount_get_last_help(last_counter);
+ regval_ctr_addvalue(regvals, "Last Help", REG_DWORD, (char *)&last_help, sizeof(last_help));
+ regval_ctr_addvalue(regvals, "Version", REG_DWORD, (char *)&version, sizeof(version));
+
+ return regval_ctr_numvals( regvals );
+}
+
+static int perflib_009_params( REGVAL_CTR *regvals )
+{
+ int base_index;
+ int buffer_size;
+ char *buffer = NULL;
+
+ base_index = reg_perfcount_get_base_index();
+ buffer_size = reg_perfcount_get_counter_names(base_index, &buffer);
+ regval_ctr_addvalue(regvals, "Counter", REG_MULTI_SZ, buffer, buffer_size);
+ if(buffer_size > 0)
+ SAFE_FREE(buffer);
+ buffer_size = reg_perfcount_get_counter_help(base_index, &buffer);
+ regval_ctr_addvalue(regvals, "Help", REG_MULTI_SZ, buffer, buffer_size);
+ if(buffer_size > 0)
+ SAFE_FREE(buffer);
+
+ return regval_ctr_numvals( regvals );
+}
+
+static int perflib_fetch_values(const char *key, REGVAL_CTR *regvals)
+{
+ char *path = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ path = talloc_strdup(ctx, key);
+ if (path == NULL) {
+ return -1;
+ }
+ path = normalize_reg_path(ctx, path);
+ if (path == NULL) {
+ return -1;
+ }
+
+ if (strncmp(path, KEY_PERFLIB_NORM, strlen(path)) == 0) {
+ return perflib_params(regvals);
+ } else if (strncmp(path, KEY_PERFLIB_009_NORM, strlen(path)) == 0) {
+ return perflib_009_params(regvals);
+ } else {
+ return 0;
+ }
+}
+
+static int perflib_fetch_subkeys(const char *key,
+ REGSUBKEY_CTR *subkey_ctr)
+{
+ return regdb_ops.fetch_subkeys(key, subkey_ctr);
+}
+
+REGISTRY_OPS perflib_reg_ops = {
+ .fetch_values = perflib_fetch_values,
+ .fetch_subkeys = perflib_fetch_subkeys,
+};
diff --git a/source3/registry/reg_backend_printing.c b/source3/registry/reg_backend_printing.c
new file mode 100644
index 0000000000..5c1e6eb543
--- /dev/null
+++ b/source3/registry/reg_backend_printing.c
@@ -0,0 +1,1268 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Implementation of registry virtual views for printing information */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+/* registrt paths used in the print_registry[] */
+
+#define KEY_MONITORS "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/MONITORS"
+#define KEY_FORMS "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/FORMS"
+#define KEY_CONTROL_PRINTERS "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/PRINTERS"
+#define KEY_ENVIRONMENTS "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/ENVIRONMENTS"
+#define KEY_CONTROL_PRINT "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT"
+#define KEY_WINNT_PRINTERS "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PRINT/PRINTERS"
+#define KEY_WINNT_PRINT "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PRINT"
+#define KEY_PORTS "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PORTS"
+
+/* callback table for various registry paths below the ones we service in this module */
+
+struct reg_dyn_tree {
+ /* full key path in normalized form */
+ const char *path;
+
+ /* callbscks for fetch/store operations */
+ int ( *fetch_subkeys) ( const char *path, REGSUBKEY_CTR *subkeys );
+ bool (*store_subkeys) ( const char *path, REGSUBKEY_CTR *subkeys );
+ int (*fetch_values) ( const char *path, REGVAL_CTR *values );
+ bool (*store_values) ( const char *path, REGVAL_CTR *values );
+};
+
+/*********************************************************************
+ *********************************************************************
+ ** Utility Functions
+ *********************************************************************
+ *********************************************************************/
+
+/***********************************************************************
+ simple function to prune a pathname down to the basename of a file
+ **********************************************************************/
+
+static const char *dos_basename(const char *path)
+{
+ const char *p;
+
+ if (!(p = strrchr( path, '\\'))) {
+ p = path;
+ } else {
+ p++;
+ }
+
+ return p;
+}
+
+/*********************************************************************
+ *********************************************************************
+ ** "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/FORMS"
+ *********************************************************************
+ *********************************************************************/
+
+static int key_forms_fetch_keys(const char *key, REGSUBKEY_CTR *subkeys)
+{
+ char *p = reg_remaining_path(talloc_tos(), key + strlen(KEY_FORMS));
+
+ /* no keys below Forms */
+
+ if (p) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static int key_forms_fetch_values( const char *key, REGVAL_CTR *values )
+{
+ uint32 data[8];
+ int i, num_values, form_index = 1;
+ nt_forms_struct *forms_list = NULL;
+ nt_forms_struct *form;
+
+ DEBUG(10,("print_values_forms: key=>[%s]\n", key ? key : "NULL" ));
+
+ num_values = get_ntforms( &forms_list );
+
+ DEBUG(10,("hive_forms_fetch_values: [%d] user defined forms returned\n",
+ num_values));
+
+ /* handle user defined forms */
+
+ for ( i=0; i<num_values; i++ ) {
+ form = &forms_list[i];
+
+ data[0] = form->width;
+ data[1] = form->length;
+ data[2] = form->left;
+ data[3] = form->top;
+ data[4] = form->right;
+ data[5] = form->bottom;
+ data[6] = form_index++;
+ data[7] = form->flag;
+
+ regval_ctr_addvalue( values, form->name, REG_BINARY, (char*)data, sizeof(data) );
+ }
+
+ SAFE_FREE( forms_list );
+ forms_list = NULL;
+
+ /* handle built-on forms */
+
+ num_values = get_builtin_ntforms( &forms_list );
+
+ DEBUG(10,("print_subpath_values_forms: [%d] built-in forms returned\n",
+ num_values));
+
+ for ( i=0; i<num_values; i++ ) {
+ form = &forms_list[i];
+
+ data[0] = form->width;
+ data[1] = form->length;
+ data[2] = form->left;
+ data[3] = form->top;
+ data[4] = form->right;
+ data[5] = form->bottom;
+ data[6] = form_index++;
+ data[7] = form->flag;
+
+ regval_ctr_addvalue(values, form->name, REG_BINARY, (char*)data, sizeof(data) );
+ }
+
+ SAFE_FREE(forms_list);
+
+ return regval_ctr_numvals(values);
+}
+
+/*********************************************************************
+ *********************************************************************
+ ** "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/PRINTERS"
+ ** "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PRINT/PRINTERS"
+ *********************************************************************
+ *********************************************************************/
+
+/*********************************************************************
+ strip off prefix for printers key. DOes return a pointer to static
+ memory.
+ *********************************************************************/
+
+static char *strip_printers_prefix(const char *key)
+{
+ char *subkeypath = NULL;
+ char *path = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ path = talloc_strdup(ctx, key);
+ if (!path) {
+ return NULL;
+ }
+ path = normalize_reg_path(ctx, path);
+ if (!path) {
+ return NULL;
+ }
+
+ /* normalizing the path does not change length, just key delimiters and case */
+
+ if (strncmp(path, KEY_WINNT_PRINTERS, strlen(KEY_WINNT_PRINTERS)) == 0) {
+ subkeypath = reg_remaining_path(ctx, key + strlen(KEY_WINNT_PRINTERS));
+ } else {
+ subkeypath = reg_remaining_path(ctx, key + strlen(KEY_CONTROL_PRINTERS));
+ }
+
+ TALLOC_FREE(path);
+ return subkeypath;
+}
+
+/*********************************************************************
+ *********************************************************************/
+
+static int key_printers_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
+{
+ int n_services = lp_numservices();
+ int snum;
+ fstring sname;
+ int i;
+ int num_subkeys = 0;
+ char *printers_key;
+ char *printername, *printerdatakey;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ fstring *subkey_names = NULL;
+
+ DEBUG(10,("key_printers_fetch_keys: key=>[%s]\n", key ? key : "NULL" ));
+
+ printers_key = strip_printers_prefix( key );
+
+ if ( !printers_key ) {
+ /* enumerate all printers */
+
+ for (snum=0; snum<n_services; snum++) {
+ if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
+ continue;
+
+ /* don't report the [printers] share */
+
+ if ( strequal( lp_servicename(snum), PRINTERS_NAME ) )
+ continue;
+
+ fstrcpy( sname, lp_servicename(snum) );
+
+ regsubkey_ctr_addkey( subkeys, sname );
+ }
+
+ num_subkeys = regsubkey_ctr_numkeys( subkeys );
+ goto done;
+ }
+
+ /* get information for a specific printer */
+
+ if (!reg_split_path( printers_key, &printername, &printerdatakey )) {
+ return -1;
+ }
+
+ /* validate the printer name */
+
+ for (snum=0; snum<n_services; snum++) {
+ if ( !lp_snum_ok(snum) || !lp_print_ok(snum) )
+ continue;
+ if (strequal( lp_servicename(snum), printername ) )
+ break;
+ }
+
+ if ( snum>=n_services
+ || !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) )
+ {
+ return -1;
+ }
+
+ num_subkeys = get_printer_subkeys( printer->info_2->data, printerdatakey?printerdatakey:"", &subkey_names );
+
+ for ( i=0; i<num_subkeys; i++ )
+ regsubkey_ctr_addkey( subkeys, subkey_names[i] );
+
+ free_a_printer( &printer, 2 );
+
+ /* no other subkeys below here */
+
+done:
+ SAFE_FREE( subkey_names );
+
+ return num_subkeys;
+}
+
+/**********************************************************************
+ Take a list of names and call add_printer_hook() if necessary
+ Note that we do this a little differently from Windows since the
+ keyname is the sharename and not the printer name.
+ *********************************************************************/
+
+static bool add_printers_by_registry( REGSUBKEY_CTR *subkeys )
+{
+ int i, num_keys, snum;
+ char *printername;
+ NT_PRINTER_INFO_LEVEL_2 info2;
+ NT_PRINTER_INFO_LEVEL printer;
+
+ ZERO_STRUCT( info2 );
+ printer.info_2 = &info2;
+
+ num_keys = regsubkey_ctr_numkeys( subkeys );
+
+ become_root();
+ for ( i=0; i<num_keys; i++ ) {
+ printername = regsubkey_ctr_specific_key( subkeys, i );
+ snum = find_service( printername );
+
+ /* just verify a valied snum for now */
+ if ( snum == -1 ) {
+ fstrcpy( info2.printername, printername );
+ fstrcpy( info2.sharename, printername );
+ if ( !add_printer_hook(talloc_tos(), NULL, &printer ) ) {
+ DEBUG(0,("add_printers_by_registry: Failed to add printer [%s]\n",
+ printername));
+ }
+ }
+ }
+ unbecome_root();
+
+ return True;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static bool key_printers_store_keys( const char *key, REGSUBKEY_CTR *subkeys )
+{
+ char *printers_key;
+ char *printername, *printerdatakey;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ int i, num_subkeys, num_existing_keys;
+ char *subkeyname;
+ fstring *existing_subkeys = NULL;
+
+ printers_key = strip_printers_prefix( key );
+
+ if ( !printers_key ) {
+ /* have to deal with some new or deleted printer */
+ return add_printers_by_registry( subkeys );
+ }
+
+ if (!reg_split_path( printers_key, &printername, &printerdatakey )) {
+ return False;
+ }
+
+ /* lookup the printer */
+
+ if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, printername)) ) {
+ DEBUG(0,("key_printers_store_keys: Tried to store subkey for bad printername %s\n",
+ printername));
+ return False;
+ }
+
+ /* get the top level printer keys */
+
+ num_existing_keys = get_printer_subkeys( printer->info_2->data, "", &existing_subkeys );
+
+ for ( i=0; i<num_existing_keys; i++ ) {
+
+ /* remove the key if it has been deleted */
+
+ if ( !regsubkey_ctr_key_exists( subkeys, existing_subkeys[i] ) ) {
+ DEBUG(5,("key_printers_store_keys: deleting key %s\n",
+ existing_subkeys[i]));
+ delete_printer_key( printer->info_2->data, existing_subkeys[i] );
+ }
+ }
+
+ num_subkeys = regsubkey_ctr_numkeys( subkeys );
+ for ( i=0; i<num_subkeys; i++ ) {
+ subkeyname = regsubkey_ctr_specific_key(subkeys, i);
+ /* add any missing printer keys */
+ if ( lookup_printerkey(printer->info_2->data, subkeyname) == -1 ) {
+ DEBUG(5,("key_printers_store_keys: adding key %s\n",
+ existing_subkeys[i]));
+ if ( add_new_printer_key( printer->info_2->data, subkeyname ) == -1 ) {
+ SAFE_FREE( existing_subkeys );
+ return False;
+ }
+ }
+ }
+
+ /* write back to disk */
+
+ mod_a_printer( printer, 2 );
+
+ /* cleanup */
+
+ free_a_printer( &printer, 2 );
+
+ SAFE_FREE( existing_subkeys );
+
+ return True;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static void fill_in_printer_values( NT_PRINTER_INFO_LEVEL_2 *info2, REGVAL_CTR *values )
+{
+ DEVICEMODE *devmode;
+ prs_struct prs;
+ uint32 offset;
+ UNISTR2 data;
+ char *p;
+ uint32 printer_status = PRINTER_STATUS_OK;
+
+ regval_ctr_addvalue( values, "Attributes", REG_DWORD, (char*)&info2->attributes, sizeof(info2->attributes) );
+ regval_ctr_addvalue( values, "Priority", REG_DWORD, (char*)&info2->priority, sizeof(info2->attributes) );
+ regval_ctr_addvalue( values, "ChangeID", REG_DWORD, (char*)&info2->changeid, sizeof(info2->changeid) );
+ regval_ctr_addvalue( values, "Default Priority", REG_DWORD, (char*)&info2->default_priority, sizeof(info2->default_priority) );
+
+ /* lie and say everything is ok since we don't want to call print_queue_length() to get the real status */
+ regval_ctr_addvalue( values, "Status", REG_DWORD, (char*)&printer_status, sizeof(info2->status) );
+
+ regval_ctr_addvalue( values, "StartTime", REG_DWORD, (char*)&info2->starttime, sizeof(info2->starttime) );
+ regval_ctr_addvalue( values, "UntilTime", REG_DWORD, (char*)&info2->untiltime, sizeof(info2->untiltime) );
+
+ /* strip the \\server\ from this string */
+ if ( !(p = strrchr( info2->printername, '\\' ) ) )
+ p = info2->printername;
+ else
+ p++;
+ init_unistr2( &data, p, UNI_STR_TERMINATE);
+ regval_ctr_addvalue( values, "Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+
+ init_unistr2( &data, info2->location, UNI_STR_TERMINATE);
+ regval_ctr_addvalue( values, "Location", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+
+ init_unistr2( &data, info2->comment, UNI_STR_TERMINATE);
+ regval_ctr_addvalue( values, "Description", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+
+ init_unistr2( &data, info2->parameters, UNI_STR_TERMINATE);
+ regval_ctr_addvalue( values, "Parameters", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+
+ init_unistr2( &data, info2->portname, UNI_STR_TERMINATE);
+ regval_ctr_addvalue( values, "Port", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+
+ init_unistr2( &data, info2->sharename, UNI_STR_TERMINATE);
+ regval_ctr_addvalue( values, "Share Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+
+ init_unistr2( &data, info2->drivername, UNI_STR_TERMINATE);
+ regval_ctr_addvalue( values, "Printer Driver", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+
+ init_unistr2( &data, info2->sepfile, UNI_STR_TERMINATE);
+ regval_ctr_addvalue( values, "Separator File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+
+ init_unistr2( &data, "WinPrint", UNI_STR_TERMINATE);
+ regval_ctr_addvalue( values, "Print Processor", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+
+ init_unistr2( &data, "RAW", UNI_STR_TERMINATE);
+ regval_ctr_addvalue( values, "Datatype", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+
+
+ /* use a prs_struct for converting the devmode and security
+ descriptor to REG_BINARY */
+
+ if (!prs_init( &prs, RPC_MAX_PDU_FRAG_LEN, values, MARSHALL))
+ return;
+
+ /* stream the device mode */
+
+ if ( (devmode = construct_dev_mode( info2->sharename )) != NULL ) {
+ if ( spoolss_io_devmode( "devmode", &prs, 0, devmode ) ) {
+ offset = prs_offset( &prs );
+ regval_ctr_addvalue( values, "Default Devmode", REG_BINARY, prs_data_p(&prs), offset );
+ }
+ }
+
+ prs_mem_clear( &prs );
+ prs_set_offset( &prs, 0 );
+
+ /* stream the printer security descriptor */
+
+ if ( info2->secdesc_buf &&
+ info2->secdesc_buf->sd &&
+ info2->secdesc_buf->sd_size )
+ {
+ if ( sec_io_desc("sec_desc", &info2->secdesc_buf->sd, &prs, 0 ) ) {
+ offset = prs_offset( &prs );
+ regval_ctr_addvalue( values, "Security", REG_BINARY, prs_data_p(&prs), offset );
+ }
+ }
+
+ prs_mem_free( &prs );
+
+ return;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static int key_printers_fetch_values( const char *key, REGVAL_CTR *values )
+{
+ int num_values;
+ char *printers_key;
+ char *printername, *printerdatakey;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ NT_PRINTER_DATA *p_data;
+ int i, key_index;
+
+ printers_key = strip_printers_prefix( key );
+
+ /* top level key values stored in the registry has no values */
+
+ if ( !printers_key ) {
+ /* normalize to the 'HKLM\SOFTWARE\...\Print\Printers' key */
+ return regdb_fetch_values( KEY_WINNT_PRINTERS, values );
+ }
+
+ /* lookup the printer object */
+
+ if (!reg_split_path( printers_key, &printername, &printerdatakey )) {
+ return -1;
+ }
+
+ if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) )
+ goto done;
+
+ if ( !printerdatakey ) {
+ fill_in_printer_values( printer->info_2, values );
+ goto done;
+ }
+
+ /* iterate over all printer data keys and fill the regval container */
+
+ p_data = printer->info_2->data;
+ if ( (key_index = lookup_printerkey( p_data, printerdatakey )) == -1 ) {
+ /* failure....should never happen if the client has a valid open handle first */
+ DEBUG(10,("key_printers_fetch_values: Unknown keyname [%s]\n", printerdatakey));
+ free_a_printer( &printer, 2 );
+ return -1;
+ }
+
+ num_values = regval_ctr_numvals( p_data->keys[key_index].values );
+ for ( i=0; i<num_values; i++ )
+ regval_ctr_copyvalue( values, regval_ctr_specific_value(p_data->keys[key_index].values, i) );
+
+
+done:
+ if ( printer )
+ free_a_printer( &printer, 2 );
+
+ return regval_ctr_numvals( values );
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+#define REG_IDX_ATTRIBUTES 1
+#define REG_IDX_PRIORITY 2
+#define REG_IDX_DEFAULT_PRIORITY 3
+#define REG_IDX_CHANGEID 4
+#define REG_IDX_STATUS 5
+#define REG_IDX_STARTTIME 6
+#define REG_IDX_NAME 7
+#define REG_IDX_LOCATION 8
+#define REG_IDX_DESCRIPTION 9
+#define REG_IDX_PARAMETERS 10
+#define REG_IDX_PORT 12
+#define REG_IDX_SHARENAME 13
+#define REG_IDX_DRIVER 14
+#define REG_IDX_SEP_FILE 15
+#define REG_IDX_PRINTPROC 16
+#define REG_IDX_DATATYPE 17
+#define REG_IDX_DEVMODE 18
+#define REG_IDX_SECDESC 19
+#define REG_IDX_UNTILTIME 20
+
+struct {
+ const char *name;
+ int index;
+} printer_values_map[] = {
+ { "Attributes", REG_IDX_ATTRIBUTES },
+ { "Priority", REG_IDX_PRIORITY },
+ { "Default Priority", REG_IDX_DEFAULT_PRIORITY },
+ { "ChangeID", REG_IDX_CHANGEID },
+ { "Status", REG_IDX_STATUS },
+ { "StartTime", REG_IDX_STARTTIME },
+ { "UntilTime", REG_IDX_UNTILTIME },
+ { "Name", REG_IDX_NAME },
+ { "Location", REG_IDX_LOCATION },
+ { "Description", REG_IDX_DESCRIPTION },
+ { "Parameters", REG_IDX_PARAMETERS },
+ { "Port", REG_IDX_PORT },
+ { "Share Name", REG_IDX_SHARENAME },
+ { "Printer Driver", REG_IDX_DRIVER },
+ { "Separator File", REG_IDX_SEP_FILE },
+ { "Print Processor", REG_IDX_PRINTPROC },
+ { "Datatype", REG_IDX_DATATYPE },
+ { "Default Devmode", REG_IDX_DEVMODE },
+ { "Security", REG_IDX_SECDESC },
+ { NULL, -1 }
+};
+
+
+static int find_valuename_index( const char *valuename )
+{
+ int i;
+
+ for ( i=0; printer_values_map[i].name; i++ ) {
+ if ( strequal( valuename, printer_values_map[i].name ) )
+ return printer_values_map[i].index;
+ }
+
+ return -1;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static void convert_values_to_printer_info_2( NT_PRINTER_INFO_LEVEL_2 *printer2, REGVAL_CTR *values )
+{
+ int num_values = regval_ctr_numvals( values );
+ uint32 value_index;
+ REGISTRY_VALUE *val;
+ int i;
+
+ for ( i=0; i<num_values; i++ ) {
+ val = regval_ctr_specific_value( values, i );
+ value_index = find_valuename_index( regval_name( val ) );
+
+ switch( value_index ) {
+ case REG_IDX_ATTRIBUTES:
+ printer2->attributes = (uint32)(*regval_data_p(val));
+ break;
+ case REG_IDX_PRIORITY:
+ printer2->priority = (uint32)(*regval_data_p(val));
+ break;
+ case REG_IDX_DEFAULT_PRIORITY:
+ printer2->default_priority = (uint32)(*regval_data_p(val));
+ break;
+ case REG_IDX_CHANGEID:
+ printer2->changeid = (uint32)(*regval_data_p(val));
+ break;
+ case REG_IDX_STARTTIME:
+ printer2->starttime = (uint32)(*regval_data_p(val));
+ break;
+ case REG_IDX_UNTILTIME:
+ printer2->untiltime = (uint32)(*regval_data_p(val));
+ break;
+ case REG_IDX_NAME:
+ rpcstr_pull( printer2->printername, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
+ break;
+ case REG_IDX_LOCATION:
+ rpcstr_pull( printer2->location, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
+ break;
+ case REG_IDX_DESCRIPTION:
+ rpcstr_pull( printer2->comment, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
+ break;
+ case REG_IDX_PARAMETERS:
+ rpcstr_pull( printer2->parameters, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
+ break;
+ case REG_IDX_PORT:
+ rpcstr_pull( printer2->portname, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
+ break;
+ case REG_IDX_SHARENAME:
+ rpcstr_pull( printer2->sharename, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
+ break;
+ case REG_IDX_DRIVER:
+ rpcstr_pull( printer2->drivername, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
+ break;
+ case REG_IDX_SEP_FILE:
+ rpcstr_pull( printer2->sepfile, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
+ break;
+ case REG_IDX_PRINTPROC:
+ rpcstr_pull( printer2->printprocessor, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
+ break;
+ case REG_IDX_DATATYPE:
+ rpcstr_pull( printer2->datatype, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
+ break;
+ case REG_IDX_DEVMODE:
+ break;
+ case REG_IDX_SECDESC:
+ break;
+ default:
+ /* unsupported value...throw away */
+ DEBUG(8,("convert_values_to_printer_info_2: Unsupported registry value [%s]\n",
+ regval_name( val ) ));
+ }
+ }
+
+ return;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static bool key_printers_store_values( const char *key, REGVAL_CTR *values )
+{
+ char *printers_key;
+ char *printername, *keyname;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ WERROR result;
+
+ printers_key = strip_printers_prefix( key );
+
+ /* values in the top level key get stored in the registry */
+
+ if ( !printers_key ) {
+ /* normalize on the 'HKLM\SOFTWARE\....\Print\Printers' key */
+ return regdb_store_values( KEY_WINNT_PRINTERS, values );
+ }
+
+ if (!reg_split_path( printers_key, &printername, &keyname )) {
+ return False;
+ }
+
+ if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, printername) ) )
+ return False;
+
+ /* deal with setting values directly under the printername */
+
+ if ( !keyname ) {
+ convert_values_to_printer_info_2( printer->info_2, values );
+ }
+ else {
+ int num_values = regval_ctr_numvals( values );
+ int i;
+ REGISTRY_VALUE *val;
+
+ delete_printer_key( printer->info_2->data, keyname );
+
+ /* deal with any subkeys */
+ for ( i=0; i<num_values; i++ ) {
+ val = regval_ctr_specific_value( values, i );
+ result = set_printer_dataex( printer, keyname,
+ regval_name( val ),
+ regval_type( val ),
+ regval_data_p( val ),
+ regval_size( val ) );
+ if ( !W_ERROR_IS_OK(result) ) {
+ DEBUG(0,("key_printers_store_values: failed to set printer data [%s]!\n",
+ keyname));
+ free_a_printer( &printer, 2 );
+ return False;
+ }
+ }
+ }
+
+ result = mod_a_printer( printer, 2 );
+
+ free_a_printer( &printer, 2 );
+
+ return W_ERROR_IS_OK(result);
+}
+
+/*********************************************************************
+ *********************************************************************
+ ** "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/ENVIRONMENTS"
+ *********************************************************************
+ *********************************************************************/
+
+static int key_driver_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
+{
+ const char *environments[] = {
+ "Windows 4.0",
+ "Windows NT x86",
+ "Windows NT R4000",
+ "Windows NT Alpha_AXP",
+ "Windows NT PowerPC",
+ "Windows IA64",
+ "Windows x64",
+ NULL };
+ fstring *drivers = NULL;
+ int i, env_index, num_drivers;
+ char *keystr, *base, *subkeypath;
+ char *key2 = NULL;
+ int num_subkeys = -1;
+ int version;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ DEBUG(10,("key_driver_fetch_keys key=>[%s]\n", key ? key : "NULL" ));
+
+ keystr = reg_remaining_path(ctx, key + strlen(KEY_ENVIRONMENTS) );
+
+ /* list all possible architectures */
+
+ if ( !keystr ) {
+ for ( num_subkeys=0; environments[num_subkeys]; num_subkeys++ )
+ regsubkey_ctr_addkey( subkeys, environments[num_subkeys] );
+
+ return num_subkeys;
+ }
+
+ /* we are dealing with a subkey of "Environments */
+ key2 = talloc_strdup(ctx, keystr);
+ if (!key2) {
+ return -1;
+ }
+ keystr = key2;
+ if (!reg_split_path(keystr, &base, &subkeypath )) {
+ return -1;
+ }
+
+ /* sanity check */
+
+ for ( env_index=0; environments[env_index]; env_index++ ) {
+ if ( strequal( environments[env_index], base ) )
+ break;
+ }
+ if ( !environments[env_index] )
+ return -1;
+
+ /* ...\Print\Environements\...\ */
+
+ if ( !subkeypath ) {
+ regsubkey_ctr_addkey( subkeys, "Drivers" );
+ regsubkey_ctr_addkey( subkeys, "Print Processors" );
+
+ return 2;
+ }
+
+ /* more of the key path to process */
+
+ keystr = subkeypath;
+ if (!reg_split_path( keystr, &base, &subkeypath )) {
+ return -1;
+ }
+
+ /* ...\Print\Environements\...\Drivers\ */
+
+ if ( !subkeypath ) {
+ if ( strequal(base, "Drivers") ) {
+ switch ( env_index ) {
+ case 0: /* Win9x */
+ regsubkey_ctr_addkey( subkeys, "Version-0" );
+ break;
+ default: /* Windows NT based systems */
+ regsubkey_ctr_addkey( subkeys, "Version-2" );
+ regsubkey_ctr_addkey( subkeys, "Version-3" );
+ break;
+ }
+
+ return regsubkey_ctr_numkeys( subkeys );
+ } else if ( strequal(base, "Print Processors") ) {
+ if ( env_index == 1 || env_index == 5 || env_index == 6 )
+
+
+ return regsubkey_ctr_numkeys( subkeys );
+ } else
+ return -1; /* bad path */
+ }
+
+ /* we finally get to enumerate the drivers */
+
+ /* only one possible subkey below PrintProc key */
+
+ if ( strequal(base, "Print Processors") ) {
+ keystr = subkeypath;
+ if (!reg_split_path( keystr, &base, &subkeypath )) {
+ return -1;
+ }
+
+ /* no subkeys below this point */
+
+ if ( subkeypath )
+ return -1;
+
+ /* only allow one keyname here -- 'winprint' */
+
+ return strequal( base, "winprint" ) ? 0 : -1;
+ }
+
+ /* only dealing with drivers from here on out */
+
+ keystr = subkeypath;
+ if (!reg_split_path( keystr, &base, &subkeypath )) {
+ return -1;
+ }
+
+ version = atoi(&base[strlen(base)-1]);
+
+ switch (env_index) {
+ case 0:
+ if ( version != 0 )
+ return -1;
+ break;
+ default:
+ if ( version != 2 && version != 3 )
+ return -1;
+ break;
+ }
+
+
+ if ( !subkeypath ) {
+ num_drivers = get_ntdrivers( &drivers, environments[env_index], version );
+ for ( i=0; i<num_drivers; i++ )
+ regsubkey_ctr_addkey( subkeys, drivers[i] );
+
+ return regsubkey_ctr_numkeys( subkeys );
+ }
+
+ /* if anything else left, just say if has no subkeys */
+
+ DEBUG(1,("key_driver_fetch_keys unhandled key [%s] (subkey == %s\n",
+ key, subkeypath ));
+
+ return 0;
+}
+
+
+/**********************************************************************
+ *********************************************************************/
+
+static void fill_in_driver_values( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3, REGVAL_CTR *values )
+{
+ char *buffer = NULL;
+ int buffer_size = 0;
+ int i, length;
+ const char *filename;
+ UNISTR2 data;
+
+ filename = dos_basename( info3->driverpath );
+ init_unistr2( &data, filename, UNI_STR_TERMINATE);
+ regval_ctr_addvalue( values, "Driver", REG_SZ, (char*)data.buffer,
+ data.uni_str_len*sizeof(uint16) );
+
+ filename = dos_basename( info3->configfile );
+ init_unistr2( &data, filename, UNI_STR_TERMINATE);
+ regval_ctr_addvalue( values, "Configuration File", REG_SZ, (char*)data.buffer,
+ data.uni_str_len*sizeof(uint16) );
+
+ filename = dos_basename( info3->datafile );
+ init_unistr2( &data, filename, UNI_STR_TERMINATE);
+ regval_ctr_addvalue( values, "Data File", REG_SZ, (char*)data.buffer,
+ data.uni_str_len*sizeof(uint16) );
+
+ filename = dos_basename( info3->helpfile );
+ init_unistr2( &data, filename, UNI_STR_TERMINATE);
+ regval_ctr_addvalue( values, "Help File", REG_SZ, (char*)data.buffer,
+ data.uni_str_len*sizeof(uint16) );
+
+ init_unistr2( &data, info3->defaultdatatype, UNI_STR_TERMINATE);
+ regval_ctr_addvalue( values, "Data Type", REG_SZ, (char*)data.buffer,
+ data.uni_str_len*sizeof(uint16) );
+
+ regval_ctr_addvalue( values, "Version", REG_DWORD, (char*)&info3->cversion,
+ sizeof(info3->cversion) );
+
+ if ( info3->dependentfiles ) {
+ /* place the list of dependent files in a single
+ character buffer, separating each file name by
+ a NULL */
+
+ for ( i=0; strcmp(info3->dependentfiles[i], ""); i++ ) {
+ /* strip the path to only the file's base name */
+
+ filename = dos_basename( info3->dependentfiles[i] );
+
+ length = strlen(filename);
+
+ buffer = (char *)SMB_REALLOC( buffer, buffer_size + (length + 1)*sizeof(uint16) );
+ if ( !buffer ) {
+ break;
+ }
+
+ init_unistr2( &data, filename, UNI_STR_TERMINATE);
+ memcpy( buffer+buffer_size, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+
+ buffer_size += (length + 1)*sizeof(uint16);
+ }
+
+ /* terminated by double NULL. Add the final one here */
+
+ buffer = (char *)SMB_REALLOC( buffer, buffer_size + 2 );
+ if ( !buffer ) {
+ buffer_size = 0;
+ } else {
+ buffer[buffer_size++] = '\0';
+ buffer[buffer_size++] = '\0';
+ }
+ }
+
+ regval_ctr_addvalue( values, "Dependent Files", REG_MULTI_SZ, buffer, buffer_size );
+
+ SAFE_FREE( buffer );
+
+ return;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static int driver_arch_fetch_values( char *key, REGVAL_CTR *values )
+{
+ char *keystr, *base, *subkeypath;
+ fstring arch_environment;
+ fstring driver;
+ int version;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver_ctr;
+ WERROR w_result;
+
+ if (!reg_split_path( key, &base, &subkeypath )) {
+ return -1;
+ }
+
+ /* no values in 'Environments\Drivers\Windows NT x86' */
+
+ if ( !subkeypath )
+ return 0;
+
+ /* We have the Architecture string and some subkey name:
+ Currently we only support
+ * Drivers
+ * Print Processors
+ Anything else is an error.
+ */
+
+ fstrcpy( arch_environment, base );
+
+ keystr = subkeypath;
+ if (!reg_split_path( keystr, &base, &subkeypath )) {
+ return -1;
+ }
+
+ if ( strequal(base, "Print Processors") )
+ return 0;
+
+ /* only Drivers key can be left */
+
+ if ( !strequal(base, "Drivers") )
+ return -1;
+
+ if ( !subkeypath )
+ return 0;
+
+ /* We know that we have Architechure\Drivers with some subkey name
+ The subkey name has to be Version-XX */
+
+ keystr = subkeypath;
+ if (!reg_split_path( keystr, &base, &subkeypath )) {
+ return -1;
+ }
+
+ if ( !subkeypath )
+ return 0;
+
+ version = atoi(&base[strlen(base)-1]);
+
+ /* BEGIN PRINTER DRIVER NAME BLOCK */
+
+ keystr = subkeypath;
+ if (!reg_split_path( keystr, &base, &subkeypath )) {
+ return -1;
+ }
+
+ /* don't go any deeper for now */
+
+ fstrcpy( driver, base );
+
+ w_result = get_a_printer_driver( &driver_ctr, 3, driver, arch_environment, version );
+
+ if ( !W_ERROR_IS_OK(w_result) )
+ return -1;
+
+ fill_in_driver_values( driver_ctr.info_3, values );
+
+ free_a_printer_driver( driver_ctr, 3 );
+
+ /* END PRINTER DRIVER NAME BLOCK */
+
+
+ DEBUG(8,("key_driver_fetch_values: Exit\n"));
+
+ return regval_ctr_numvals( values );
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static int key_driver_fetch_values( const char *key, REGVAL_CTR *values )
+{
+ char *keystr = NULL;
+ char *subkey = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ DEBUG(8,("key_driver_fetch_values: Enter key => [%s]\n", key ? key : "NULL"));
+
+ /* no values in the Environments key */
+
+ if (!(keystr = reg_remaining_path(ctx, key + strlen(KEY_ENVIRONMENTS))))
+ return 0;
+
+ subkey = talloc_strdup(ctx, keystr);
+ if (!subkey) {
+ return 0;
+ }
+
+ /* pass off to handle subkeys */
+
+ return driver_arch_fetch_values( subkey, values );
+}
+
+/*********************************************************************
+ *********************************************************************
+ ** "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT"
+ *********************************************************************
+ *********************************************************************/
+
+static int key_print_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
+{
+ int key_len = strlen(key);
+
+ /* no keys below 'Print' handled here */
+
+ if ( (key_len != strlen(KEY_CONTROL_PRINT)) && (key_len != strlen(KEY_WINNT_PRINT)) )
+ return -1;
+
+ regsubkey_ctr_addkey( subkeys, "Environments" );
+ regsubkey_ctr_addkey( subkeys, "Monitors" );
+ regsubkey_ctr_addkey( subkeys, "Forms" );
+ regsubkey_ctr_addkey( subkeys, "Printers" );
+
+ return regsubkey_ctr_numkeys( subkeys );
+}
+
+/**********************************************************************
+ *********************************************************************
+ ** Structure to hold dispatch table of ops for various printer keys.
+ ** Make sure to always store deeper keys along the same path first so
+ ** we ge a more specific match.
+ *********************************************************************
+ *********************************************************************/
+
+static struct reg_dyn_tree print_registry[] = {
+/* just pass the monitor onto the registry tdb */
+{ KEY_MONITORS,
+ &regdb_fetch_keys,
+ &regdb_store_keys,
+ &regdb_fetch_values,
+ &regdb_store_values },
+{ KEY_FORMS,
+ &key_forms_fetch_keys,
+ NULL,
+ &key_forms_fetch_values,
+ NULL },
+{ KEY_CONTROL_PRINTERS,
+ &key_printers_fetch_keys,
+ &key_printers_store_keys,
+ &key_printers_fetch_values,
+ &key_printers_store_values },
+{ KEY_ENVIRONMENTS,
+ &key_driver_fetch_keys,
+ NULL,
+ &key_driver_fetch_values,
+ NULL },
+{ KEY_CONTROL_PRINT,
+ &key_print_fetch_keys,
+ NULL,
+ NULL,
+ NULL },
+{ KEY_WINNT_PRINTERS,
+ &key_printers_fetch_keys,
+ &key_printers_store_keys,
+ &key_printers_fetch_values,
+ &key_printers_store_values },
+{ KEY_PORTS,
+ &regdb_fetch_keys,
+ &regdb_store_keys,
+ &regdb_fetch_values,
+ &regdb_store_values },
+
+{ NULL, NULL, NULL, NULL, NULL }
+};
+
+
+/**********************************************************************
+ *********************************************************************
+ ** Main reg_printing interface functions
+ *********************************************************************
+ *********************************************************************/
+
+/***********************************************************************
+ Lookup a key in the print_registry table, returning its index.
+ -1 on failure
+ **********************************************************************/
+
+static int match_registry_path(const char *key)
+{
+ int i;
+ char *path = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if ( !key )
+ return -1;
+
+ path = talloc_strdup(ctx, key);
+ if (!path) {
+ return -1;
+ }
+ path = normalize_reg_path(ctx, path);
+ if (!path) {
+ return -1;
+ }
+
+ for ( i=0; print_registry[i].path; i++ ) {
+ if (strncmp( path, print_registry[i].path, strlen(print_registry[i].path) ) == 0 )
+ return i;
+ }
+
+ return -1;
+}
+
+/***********************************************************************
+ **********************************************************************/
+
+static int regprint_fetch_reg_keys( const char *key, REGSUBKEY_CTR *subkeys )
+{
+ int i = match_registry_path( key );
+
+ if ( i == -1 )
+ return -1;
+
+ if ( !print_registry[i].fetch_subkeys )
+ return -1;
+
+ return print_registry[i].fetch_subkeys( key, subkeys );
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static bool regprint_store_reg_keys( const char *key, REGSUBKEY_CTR *subkeys )
+{
+ int i = match_registry_path( key );
+
+ if ( i == -1 )
+ return False;
+
+ if ( !print_registry[i].store_subkeys )
+ return False;
+
+ return print_registry[i].store_subkeys( key, subkeys );
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static int regprint_fetch_reg_values( const char *key, REGVAL_CTR *values )
+{
+ int i = match_registry_path( key );
+
+ if ( i == -1 )
+ return -1;
+
+ /* return 0 values by default since we know the key had
+ to exist because the client opened a handle */
+
+ if ( !print_registry[i].fetch_values )
+ return 0;
+
+ return print_registry[i].fetch_values( key, values );
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static bool regprint_store_reg_values( const char *key, REGVAL_CTR *values )
+{
+ int i = match_registry_path( key );
+
+ if ( i == -1 )
+ return False;
+
+ if ( !print_registry[i].store_values )
+ return False;
+
+ return print_registry[i].store_values( key, values );
+}
+
+/*
+ * Table of function pointers for accessing printing data
+ */
+
+REGISTRY_OPS printing_ops = {
+ .fetch_subkeys = regprint_fetch_reg_keys,
+ .fetch_values = regprint_fetch_reg_values,
+ .store_subkeys = regprint_store_reg_keys,
+ .store_values = regprint_store_reg_values,
+};
diff --git a/source3/registry/reg_backend_prod_options.c b/source3/registry/reg_backend_prod_options.c
new file mode 100644
index 0000000000..7ac5c5b4b9
--- /dev/null
+++ b/source3/registry/reg_backend_prod_options.c
@@ -0,0 +1,70 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Product options registry backend.
+ *
+ * This replaces the former dynamic product options overlay.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+extern REGISTRY_OPS regdb_ops;
+
+static int prod_options_fetch_values(const char *key, REGVAL_CTR *regvals)
+{
+ const char *value_ascii = "";
+ fstring value;
+ int value_length;
+
+ switch (lp_server_role()) {
+ case ROLE_DOMAIN_PDC:
+ case ROLE_DOMAIN_BDC:
+ value_ascii = "LanmanNT";
+ break;
+ case ROLE_STANDALONE:
+ value_ascii = "ServerNT";
+ break;
+ case ROLE_DOMAIN_MEMBER:
+ value_ascii = "WinNT";
+ break;
+ }
+
+ value_length = push_ucs2(value, value, value_ascii, sizeof(value),
+ STR_TERMINATE|STR_NOALIGN );
+ regval_ctr_addvalue(regvals, "ProductType", REG_SZ, value,
+ value_length);
+
+ return regval_ctr_numvals( regvals );
+}
+
+static int prod_options_fetch_subkeys(const char *key,
+ REGSUBKEY_CTR *subkey_ctr)
+{
+ return regdb_ops.fetch_subkeys(key, subkey_ctr);
+}
+
+REGISTRY_OPS prod_options_reg_ops = {
+ .fetch_values = prod_options_fetch_values,
+ .fetch_subkeys = prod_options_fetch_subkeys,
+};
diff --git a/source3/registry/reg_backend_shares.c b/source3/registry/reg_backend_shares.c
new file mode 100644
index 0000000000..ee9e5dc5a1
--- /dev/null
+++ b/source3/registry/reg_backend_shares.c
@@ -0,0 +1,164 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Implementation of registry virtual views for printing information */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+/**********************************************************************
+ It is safe to assume that every registry path passed into on of
+ the exported functions here begins with KEY_PRINTING else
+ these functions would have never been called. This is a small utility
+ function to strip the beginning of the path and make a copy that the
+ caller can modify. Note that the caller is responsible for releasing
+ the memory allocated here.
+ **********************************************************************/
+
+static char* trim_reg_path( const char *path )
+{
+ const char *p;
+ uint16 key_len = strlen(KEY_SHARES);
+
+ /*
+ * sanity check...this really should never be True.
+ * It is only here to prevent us from accessing outside
+ * the path buffer in the extreme case.
+ */
+
+ if ( strlen(path) < key_len ) {
+ DEBUG(0,("trim_reg_path: Registry path too short! [%s]\n", path));
+ return NULL;
+ }
+
+
+ p = path + strlen( KEY_SHARES );
+
+ if ( *p == '\\' )
+ p++;
+
+ if ( *p )
+ return SMB_STRDUP(p);
+ else
+ return NULL;
+}
+
+/**********************************************************************
+ Enumerate registry subkey names given a registry path.
+ Caller is responsible for freeing memory to **subkeys
+ *********************************************************************/
+
+static int shares_subkey_info( const char *key, REGSUBKEY_CTR *subkey_ctr )
+{
+ char *path;
+ bool top_level = False;
+ int num_subkeys = 0;
+
+ DEBUG(10,("printing_subkey_info: key=>[%s]\n", key));
+
+ path = trim_reg_path( key );
+
+ /* check to see if we are dealing with the top level key */
+
+ if ( !path )
+ top_level = True;
+
+ if ( top_level ) {
+ num_subkeys = 1;
+ regsubkey_ctr_addkey( subkey_ctr, "Security" );
+ }
+#if 0
+ else
+ num_subkeys = handle_share_subpath( path, subkey_ctr, NULL );
+#endif
+
+ SAFE_FREE( path );
+
+ return num_subkeys;
+}
+
+/**********************************************************************
+ Enumerate registry values given a registry path.
+ Caller is responsible for freeing memory
+ *********************************************************************/
+
+static int shares_value_info( const char *key, REGVAL_CTR *val )
+{
+ char *path;
+ bool top_level = False;
+ int num_values = 0;
+
+ DEBUG(10,("printing_value_info: key=>[%s]\n", key));
+
+ path = trim_reg_path( key );
+
+ /* check to see if we are dealing with the top level key */
+
+ if ( !path )
+ top_level = True;
+
+ /* fill in values from the getprinterdata_printer_server() */
+ if ( top_level )
+ num_values = 0;
+#if 0
+ else
+ num_values = handle_printing_subpath( path, NULL, val );
+#endif
+
+ SAFE_FREE(path);
+
+ return num_values;
+}
+
+/**********************************************************************
+ Stub function which always returns failure since we don't want
+ people storing printing information directly via regostry calls
+ (for now at least)
+ *********************************************************************/
+
+static bool shares_store_subkey( const char *key, REGSUBKEY_CTR *subkeys )
+{
+ return False;
+}
+
+/**********************************************************************
+ Stub function which always returns failure since we don't want
+ people storing printing information directly via regostry calls
+ (for now at least)
+ *********************************************************************/
+
+static bool shares_store_value( const char *key, REGVAL_CTR *val )
+{
+ return False;
+}
+
+/*
+ * Table of function pointers for accessing printing data
+ */
+
+REGISTRY_OPS shares_reg_ops = {
+ .fetch_subkeys = shares_subkey_info,
+ .fetch_values = shares_value_info,
+ .store_subkeys = shares_store_subkey,
+ .store_values = shares_store_value,
+};
+
+
diff --git a/source3/registry/reg_backend_smbconf.c b/source3/registry/reg_backend_smbconf.c
new file mode 100644
index 0000000000..2e4a5f1c1d
--- /dev/null
+++ b/source3/registry/reg_backend_smbconf.c
@@ -0,0 +1,85 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Volker Lendecke 2006
+ * Copyright (C) Michael Adam 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+extern REGISTRY_OPS regdb_ops; /* these are the default */
+
+static int smbconf_fetch_keys( const char *key, REGSUBKEY_CTR *subkey_ctr )
+{
+ return regdb_ops.fetch_subkeys(key, subkey_ctr);
+}
+
+static bool smbconf_store_keys( const char *key, REGSUBKEY_CTR *subkeys )
+{
+ return regdb_ops.store_subkeys(key, subkeys);
+}
+
+static int smbconf_fetch_values( const char *key, REGVAL_CTR *val )
+{
+ return regdb_ops.fetch_values(key, val);
+}
+
+static bool smbconf_store_values( const char *key, REGVAL_CTR *val )
+{
+ return regdb_ops.store_values(key, val);
+}
+
+static bool smbconf_reg_access_check(const char *keyname, uint32 requested,
+ uint32 *granted,
+ const struct nt_user_token *token)
+{
+ if (!(user_has_privileges(token, &se_disk_operators))) {
+ return False;
+ }
+
+ *granted = REG_KEY_ALL;
+ return True;
+}
+
+static WERROR smbconf_get_secdesc(TALLOC_CTX *mem_ctx, const char *key,
+ struct security_descriptor **psecdesc)
+{
+ return regdb_ops.get_secdesc(mem_ctx, key, psecdesc);
+}
+
+static WERROR smbconf_set_secdesc(const char *key,
+ struct security_descriptor *secdesc)
+{
+ return regdb_ops.set_secdesc(key, secdesc);
+}
+
+
+/*
+ * Table of function pointers for accessing smb.conf data
+ */
+
+REGISTRY_OPS smbconf_reg_ops = {
+ .fetch_subkeys = smbconf_fetch_keys,
+ .fetch_values = smbconf_fetch_values,
+ .store_subkeys = smbconf_store_keys,
+ .store_values = smbconf_store_values,
+ .reg_access_check = smbconf_reg_access_check,
+ .get_secdesc = smbconf_get_secdesc,
+ .set_secdesc = smbconf_set_secdesc,
+};
diff --git a/source3/registry/reg_backend_tcpip_params.c b/source3/registry/reg_backend_tcpip_params.c
new file mode 100644
index 0000000000..db7df5dd8f
--- /dev/null
+++ b/source3/registry/reg_backend_tcpip_params.c
@@ -0,0 +1,67 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * TCP/IP parameters registry backend.
+ *
+ * This replaces the former dynamic tcpip parameters overlay.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+extern REGISTRY_OPS regdb_ops;
+
+static int tcpip_params_fetch_values(const char *key, REGVAL_CTR *regvals)
+{
+ fstring value;
+ int value_length;
+ char *hname;
+ char *mydomainname = NULL;
+
+ hname = myhostname();
+ value_length = push_ucs2(value, value, hname, sizeof(value),
+ STR_TERMINATE|STR_NOALIGN);
+ regval_ctr_addvalue(regvals, "Hostname",REG_SZ, value, value_length);
+
+ mydomainname = get_mydnsdomname(talloc_tos());
+ if (!mydomainname) {
+ return -1;
+ }
+
+ value_length = push_ucs2(value, value, mydomainname, sizeof(value),
+ STR_TERMINATE|STR_NOALIGN);
+ regval_ctr_addvalue(regvals, "Domain", REG_SZ, value, value_length);
+
+ return regval_ctr_numvals(regvals);
+}
+
+static int tcpip_params_fetch_subkeys(const char *key,
+ REGSUBKEY_CTR *subkey_ctr)
+{
+ return regdb_ops.fetch_subkeys(key, subkey_ctr);
+}
+
+REGISTRY_OPS tcpip_params_reg_ops = {
+ .fetch_values = tcpip_params_fetch_values,
+ .fetch_subkeys = tcpip_params_fetch_subkeys,
+};
diff --git a/source3/registry/reg_cachehook.c b/source3/registry/reg_cachehook.c
new file mode 100644
index 0000000000..6697a69356
--- /dev/null
+++ b/source3/registry/reg_cachehook.c
@@ -0,0 +1,147 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Implementation of registry hook cache tree */
+
+#include "includes.h"
+#include "adt_tree.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+static SORTED_TREE *cache_tree = NULL;
+extern REGISTRY_OPS regdb_ops; /* these are the default */
+
+static WERROR keyname_to_path(TALLOC_CTX *mem_ctx, const char *keyname,
+ char **path)
+{
+ char *tmp_path = NULL;
+
+ if ((keyname == NULL) || (path == NULL)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ tmp_path = talloc_asprintf(mem_ctx, "\\%s", keyname);
+ if (tmp_path == NULL) {
+ DEBUG(0, ("talloc_asprintf failed!\n"));
+ return WERR_NOMEM;
+ }
+
+ tmp_path = talloc_string_sub(mem_ctx, tmp_path, "\\", "/");
+ if (tmp_path == NULL) {
+ DEBUG(0, ("talloc_string_sub_failed!\n"));
+ return WERR_NOMEM;
+ }
+
+ *path = tmp_path;
+
+ return WERR_OK;
+}
+
+/**********************************************************************
+ Initialize the cache tree if it has not been initialized yet.
+ *********************************************************************/
+
+WERROR reghook_cache_init(void)
+{
+ if (cache_tree != NULL) {
+ return WERR_OK;
+ }
+
+ cache_tree = pathtree_init(&regdb_ops, NULL);
+ if (cache_tree == NULL) {
+ return WERR_NOMEM;
+ }
+ DEBUG(10, ("reghook_cache_init: new tree with default "
+ "ops %p for key [%s]\n", (void *)&regdb_ops,
+ KEY_TREE_ROOT));
+ return WERR_OK;
+}
+
+/**********************************************************************
+ Add a new registry hook to the cache. Note that the keyname
+ is not in the exact format that a SORTED_TREE expects.
+ *********************************************************************/
+
+WERROR reghook_cache_add(const char *keyname, REGISTRY_OPS *ops)
+{
+ WERROR werr;
+ char *key = NULL;
+
+ if ((keyname == NULL) || (ops == NULL)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ werr = keyname_to_path(talloc_tos(), keyname, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ DEBUG(10, ("reghook_cache_add: Adding ops %p for key [%s]\n",
+ (void *)ops, key));
+
+ werr = pathtree_add(cache_tree, key, ops);
+
+done:
+ TALLOC_FREE(key);
+ return werr;
+}
+
+/**********************************************************************
+ Find a key in the cache.
+ *********************************************************************/
+
+REGISTRY_OPS *reghook_cache_find(const char *keyname)
+{
+ WERROR werr;
+ char *key = NULL;
+ REGISTRY_OPS *ops = NULL;
+
+ if (keyname == NULL) {
+ return NULL;
+ }
+
+ werr = keyname_to_path(talloc_tos(), keyname, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ DEBUG(10,("reghook_cache_find: Searching for keyname [%s]\n", key));
+
+ ops = (REGISTRY_OPS *)pathtree_find(cache_tree, key);
+
+ DEBUG(10, ("reghook_cache_find: found ops %p for key [%s]\n",
+ ops ? (void *)ops : 0, key));
+
+done:
+ TALLOC_FREE(key);
+
+ return ops;
+}
+
+/**********************************************************************
+ Print out the cache tree structure for debugging.
+ *********************************************************************/
+
+void reghook_dump_cache( int debuglevel )
+{
+ DEBUG(debuglevel,("reghook_dump_cache: Starting cache dump now...\n"));
+
+ pathtree_print_keys( cache_tree, debuglevel );
+}
diff --git a/source3/registry/reg_dispatcher.c b/source3/registry/reg_dispatcher.c
new file mode 100644
index 0000000000..c68ecdedeb
--- /dev/null
+++ b/source3/registry/reg_dispatcher.c
@@ -0,0 +1,245 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ * Copyright (C) Michael Adam 2006-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Implementation of registry frontend view functions.
+ * Functions moved from reg_frontend.c to minimize linker deps.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+static const struct generic_mapping reg_generic_map =
+ { REG_KEY_READ, REG_KEY_WRITE, REG_KEY_EXECUTE, REG_KEY_ALL };
+
+/********************************************************************
+********************************************************************/
+
+static WERROR construct_registry_sd(TALLOC_CTX *ctx, SEC_DESC **psd)
+{
+ SEC_ACE ace[3];
+ SEC_ACCESS mask;
+ size_t i = 0;
+ SEC_DESC *sd;
+ SEC_ACL *acl;
+ size_t sd_size;
+
+ /* basic access for Everyone */
+
+ init_sec_access(&mask, REG_KEY_READ);
+ init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
+ mask, 0);
+
+ /* Full Access 'BUILTIN\Administrators' */
+
+ init_sec_access(&mask, REG_KEY_ALL);
+ init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
+ SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ /* Full Access 'NT Authority\System' */
+
+ init_sec_access(&mask, REG_KEY_ALL );
+ init_sec_ace(&ace[i++], &global_sid_System, SEC_ACE_TYPE_ACCESS_ALLOWED,
+ mask, 0);
+
+ /* create the security descriptor */
+
+ acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace);
+ if (acl == NULL) {
+ return WERR_NOMEM;
+ }
+
+ sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
+ &global_sid_Builtin_Administrators,
+ &global_sid_System, NULL, acl,
+ &sd_size);
+ if (sd == NULL) {
+ return WERR_NOMEM;
+ }
+
+ *psd = sd;
+ return WERR_OK;
+}
+
+/***********************************************************************
+ High level wrapper function for storing registry subkeys
+ ***********************************************************************/
+
+bool store_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkeys )
+{
+ if (key->ops && key->ops->store_subkeys)
+ return key->ops->store_subkeys(key->name, subkeys);
+
+ return false;
+}
+
+/***********************************************************************
+ High level wrapper function for storing registry values
+ ***********************************************************************/
+
+bool store_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val )
+{
+ if (key->ops && key->ops->store_values)
+ return key->ops->store_values(key->name, val);
+
+ return false;
+}
+
+/***********************************************************************
+ High level wrapper function for enumerating registry subkeys
+ Initialize the TALLOC_CTX if necessary
+ ***********************************************************************/
+
+int fetch_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkey_ctr )
+{
+ int result = -1;
+
+ if (key->ops && key->ops->fetch_subkeys)
+ result = key->ops->fetch_subkeys(key->name, subkey_ctr);
+
+ return result;
+}
+
+/***********************************************************************
+ High level wrapper function for enumerating registry values
+ ***********************************************************************/
+
+int fetch_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val )
+{
+ int result = -1;
+
+ DEBUG(10, ("fetch_reg_values called for key '%s' (ops %p)\n", key->name,
+ (key->ops) ? (void *)key->ops : NULL));
+
+ if (key->ops && key->ops->fetch_values)
+ result = key->ops->fetch_values(key->name, val);
+
+ return result;
+}
+
+/***********************************************************************
+ High level access check for passing the required access mask to the
+ underlying registry backend
+ ***********************************************************************/
+
+bool regkey_access_check( REGISTRY_KEY *key, uint32 requested, uint32 *granted,
+ const struct nt_user_token *token )
+{
+ SEC_DESC *sec_desc;
+ NTSTATUS status;
+ WERROR err;
+ TALLOC_CTX *mem_ctx;
+
+ /* use the default security check if the backend has not defined its
+ * own */
+
+ if (key->ops && key->ops->reg_access_check) {
+ return key->ops->reg_access_check(key->name, requested,
+ granted, token);
+ }
+
+ /*
+ * The secdesc routines can't yet cope with a NULL talloc ctx sanely.
+ */
+
+ if (!(mem_ctx = talloc_init("regkey_access_check"))) {
+ return false;
+ }
+
+ err = regkey_get_secdesc(mem_ctx, key, &sec_desc);
+
+ if (!W_ERROR_IS_OK(err)) {
+ TALLOC_FREE(mem_ctx);
+ return false;
+ }
+
+ se_map_generic( &requested, &reg_generic_map );
+
+ if (!se_access_check(sec_desc, token, requested, granted, &status)) {
+ TALLOC_FREE(mem_ctx);
+ return false;
+ }
+
+ TALLOC_FREE(mem_ctx);
+ return NT_STATUS_IS_OK(status);
+}
+
+WERROR regkey_get_secdesc(TALLOC_CTX *mem_ctx, REGISTRY_KEY *key,
+ struct security_descriptor **psecdesc)
+{
+ struct security_descriptor *secdesc;
+ WERROR werr;
+
+ if (key->ops && key->ops->get_secdesc) {
+ werr = key->ops->get_secdesc(mem_ctx, key->name, psecdesc);
+ if (W_ERROR_IS_OK(werr)) {
+ return WERR_OK;
+ }
+ }
+
+ werr = construct_registry_sd(mem_ctx, &secdesc);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ *psecdesc = secdesc;
+ return WERR_OK;
+}
+
+WERROR regkey_set_secdesc(REGISTRY_KEY *key,
+ struct security_descriptor *psecdesc)
+{
+ if (key->ops && key->ops->set_secdesc) {
+ return key->ops->set_secdesc(key->name, psecdesc);
+ }
+
+ return WERR_ACCESS_DENIED;
+}
+
+/**
+ * Check whether the in-memory version of the subkyes of a
+ * registry key needs update from disk.
+ */
+bool reg_subkeys_need_update(REGISTRY_KEY *key, REGSUBKEY_CTR *subkeys)
+{
+ if (key->ops && key->ops->subkeys_need_update)
+ {
+ return key->ops->subkeys_need_update(subkeys);
+ }
+
+ return false;
+}
+
+/**
+ * Check whether the in-memory version of the values of a
+ * registry key needs update from disk.
+ */
+bool reg_values_need_update(REGISTRY_KEY *key, REGVAL_CTR *values)
+{
+ if (key->ops && key->ops->values_need_update)
+ {
+ return key->ops->values_need_update(values);
+ }
+
+ return false;
+}
+
diff --git a/source3/registry/reg_eventlog.c b/source3/registry/reg_eventlog.c
new file mode 100644
index 0000000000..8994acf107
--- /dev/null
+++ b/source3/registry/reg_eventlog.c
@@ -0,0 +1,380 @@
+
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Marcin Krzysztof Porwit 2005,
+ * Copyright (C) Brian Moran 2005.
+ * Copyright (C) Gerald (Jerry) Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+/**********************************************************************
+ for an eventlog, add in the default values
+*********************************************************************/
+
+bool eventlog_init_keys(void)
+{
+ /* Find all of the eventlogs, add keys for each of them */
+ const char **elogs = lp_eventlog_list();
+ char *evtlogpath = NULL;
+ char *evtfilepath = NULL;
+ REGSUBKEY_CTR *subkeys;
+ REGVAL_CTR *values;
+ uint32 uiMaxSize;
+ uint32 uiRetention;
+ uint32 uiCategoryCount;
+ UNISTR2 data;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ while (elogs && *elogs) {
+ if (!(subkeys = TALLOC_ZERO_P(ctx, REGSUBKEY_CTR ) ) ) {
+ DEBUG( 0, ( "talloc() failure!\n" ) );
+ return False;
+ }
+ regdb_fetch_keys(KEY_EVENTLOG, subkeys);
+ regsubkey_ctr_addkey( subkeys, *elogs );
+ if ( !regdb_store_keys( KEY_EVENTLOG, subkeys ) ) {
+ TALLOC_FREE(subkeys);
+ return False;
+ }
+ TALLOC_FREE(subkeys);
+
+ /* add in the key of form KEY_EVENTLOG/Application */
+ DEBUG( 5,
+ ( "Adding key of [%s] to path of [%s]\n", *elogs,
+ KEY_EVENTLOG ) );
+
+ evtlogpath = talloc_asprintf(ctx, "%s\\%s",
+ KEY_EVENTLOG, *elogs);
+ if (!evtlogpath) {
+ return false;
+ }
+ /* add in the key of form KEY_EVENTLOG/Application/Application */
+ DEBUG( 5,
+ ( "Adding key of [%s] to path of [%s]\n", *elogs,
+ evtlogpath ) );
+ if (!(subkeys = TALLOC_ZERO_P(ctx, REGSUBKEY_CTR))) {
+ DEBUG( 0, ( "talloc() failure!\n" ) );
+ return False;
+ }
+ regdb_fetch_keys( evtlogpath, subkeys );
+ regsubkey_ctr_addkey( subkeys, *elogs );
+
+ if ( !regdb_store_keys( evtlogpath, subkeys ) ) {
+ TALLOC_FREE(subkeys);
+ return False;
+ }
+ TALLOC_FREE( subkeys );
+
+ /* now add the values to the KEY_EVENTLOG/Application form key */
+ if (!(values = TALLOC_ZERO_P(ctx, REGVAL_CTR))) {
+ DEBUG( 0, ( "talloc() failure!\n" ) );
+ return False;
+ }
+ DEBUG( 5,
+ ( "Storing values to eventlog path of [%s]\n",
+ evtlogpath ) );
+ regdb_fetch_values( evtlogpath, values );
+
+
+ if (!regval_ctr_key_exists(values, "MaxSize")) {
+
+ /* assume we have none, add them all */
+
+ /* hard code some initial values */
+
+ /* uiDisplayNameId = 0x00000100; */
+ uiMaxSize = 0x00080000;
+ uiRetention = 0x93A80;
+
+ regval_ctr_addvalue(values, "MaxSize", REG_DWORD,
+ (char *)&uiMaxSize,
+ sizeof(uint32));
+
+ regval_ctr_addvalue(values, "Retention", REG_DWORD,
+ (char *)&uiRetention,
+ sizeof(uint32));
+ init_unistr2(&data, *elogs, UNI_STR_TERMINATE);
+
+ regval_ctr_addvalue(values, "PrimaryModule", REG_SZ,
+ (char *)data.buffer,
+ data.uni_str_len *
+ sizeof(uint16));
+ init_unistr2(&data, *elogs, UNI_STR_TERMINATE);
+
+ regval_ctr_addvalue(values, "Sources", REG_MULTI_SZ,
+ (char *)data.buffer,
+ data.uni_str_len *
+ sizeof(uint16));
+
+ evtfilepath = talloc_asprintf(ctx,
+ "%%SystemRoot%%\\system32\\config\\%s.tdb",
+ *elogs);
+ if (!evtfilepath) {
+ TALLOC_FREE(values);
+ }
+ init_unistr2(&data, evtfilepath, UNI_STR_TERMINATE);
+ regval_ctr_addvalue(values, "File", REG_EXPAND_SZ, (char *)data.buffer,
+ data.uni_str_len * sizeof(uint16));
+ regdb_store_values(evtlogpath, values);
+
+ }
+
+ TALLOC_FREE(values);
+
+ /* now do the values under KEY_EVENTLOG/Application/Application */
+ TALLOC_FREE(evtlogpath);
+ evtlogpath = talloc_asprintf(ctx, "%s\\%s\\%s",
+ KEY_EVENTLOG, *elogs, *elogs);
+ if (!evtlogpath) {
+ return false;
+ }
+ if (!(values = TALLOC_ZERO_P(ctx, REGVAL_CTR))) {
+ DEBUG( 0, ( "talloc() failure!\n" ) );
+ return False;
+ }
+ DEBUG( 5,
+ ( "Storing values to eventlog path of [%s]\n",
+ evtlogpath));
+ regdb_fetch_values(evtlogpath, values);
+ if (!regval_ctr_key_exists( values, "CategoryCount")) {
+
+ /* hard code some initial values */
+
+ uiCategoryCount = 0x00000007;
+ regval_ctr_addvalue( values, "CategoryCount",
+ REG_DWORD,
+ ( char * ) &uiCategoryCount,
+ sizeof( uint32 ) );
+ init_unistr2( &data,
+ "%SystemRoot%\\system32\\eventlog.dll",
+ UNI_STR_TERMINATE );
+
+ regval_ctr_addvalue( values, "CategoryMessageFile",
+ REG_EXPAND_SZ,
+ ( char * ) data.buffer,
+ data.uni_str_len *
+ sizeof( uint16 ) );
+ regdb_store_values( evtlogpath, values );
+ }
+ TALLOC_FREE(values);
+ elogs++;
+ }
+
+ return true;
+}
+
+/*********************************************************************
+ for an eventlog, add in a source name. If the eventlog doesn't
+ exist (not in the list) do nothing. If a source for the log
+ already exists, change the information (remove, replace)
+*********************************************************************/
+
+bool eventlog_add_source( const char *eventlog, const char *sourcename,
+ const char *messagefile )
+{
+ /* Find all of the eventlogs, add keys for each of them */
+ /* need to add to the value KEY_EVENTLOG/<eventlog>/Sources string (Creating if necessary)
+ need to add KEY of source to KEY_EVENTLOG/<eventlog>/<source> */
+
+ const char **elogs = lp_eventlog_list( );
+ char **wrklist, **wp;
+ char *evtlogpath = NULL;
+ REGSUBKEY_CTR *subkeys;
+ REGVAL_CTR *values;
+ REGISTRY_VALUE *rval;
+ UNISTR2 data;
+ uint16 *msz_wp;
+ int mbytes, ii;
+ bool already_in;
+ int i;
+ int numsources;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if (!elogs) {
+ return False;
+ }
+
+ for ( i = 0; elogs[i]; i++ ) {
+ if ( strequal( elogs[i], eventlog ) )
+ break;
+ }
+
+ if ( !elogs[i] ) {
+ DEBUG( 0,
+ ( "Eventlog [%s] not found in list of valid event logs\n",
+ eventlog ) );
+ return false; /* invalid named passed in */
+ }
+
+ /* have to assume that the evenlog key itself exists at this point */
+ /* add in a key of [sourcename] under the eventlog key */
+
+ /* todo add to Sources */
+
+ if (!( values = TALLOC_ZERO_P(ctx, REGVAL_CTR))) {
+ DEBUG( 0, ( "talloc() failure!\n" ));
+ return false;
+ }
+
+ evtlogpath = talloc_asprintf(ctx, "%s\\%s", KEY_EVENTLOG, eventlog);
+ if (!evtlogpath) {
+ TALLOC_FREE(values);
+ return false;
+ }
+
+ regdb_fetch_values( evtlogpath, values );
+
+
+ if ( !( rval = regval_ctr_getvalue( values, "Sources" ) ) ) {
+ DEBUG( 0, ( "No Sources value for [%s]!\n", eventlog ) );
+ return False;
+ }
+ /* perhaps this adding a new string to a multi_sz should be a fn? */
+ /* check to see if it's there already */
+
+ if ( rval->type != REG_MULTI_SZ ) {
+ DEBUG( 0,
+ ( "Wrong type for Sources, should be REG_MULTI_SZ\n" ) );
+ return False;
+ }
+ /* convert to a 'regulah' chars to do some comparisons */
+
+ already_in = False;
+ wrklist = NULL;
+ dump_data( 1, rval->data_p, rval->size );
+ if ( ( numsources =
+ regval_convert_multi_sz( ( uint16 * ) rval->data_p, rval->size,
+ &wrklist ) ) > 0 ) {
+
+ ii = numsources;
+ /* see if it's in there already */
+ wp = wrklist;
+
+ while ( ii && wp && *wp ) {
+ if ( strequal( *wp, sourcename ) ) {
+ DEBUG( 5,
+ ( "Source name [%s] already in list for [%s] \n",
+ sourcename, eventlog ) );
+ already_in = True;
+ break;
+ }
+ wp++;
+ ii--;
+ }
+ } else {
+ if ( numsources < 0 ) {
+ DEBUG( 3, ( "problem in getting the sources\n" ) );
+ return False;
+ }
+ DEBUG( 3,
+ ( "Nothing in the sources list, this might be a problem\n" ) );
+ }
+
+ wp = wrklist;
+
+ if ( !already_in ) {
+ /* make a new list with an additional entry; copy values, add another */
+ wp = TALLOC_ARRAY(ctx, char *, numsources + 2 );
+
+ if ( !wp ) {
+ DEBUG( 0, ( "talloc() failed \n" ) );
+ return False;
+ }
+ memcpy( wp, wrklist, sizeof( char * ) * numsources );
+ *( wp + numsources ) = ( char * ) sourcename;
+ *( wp + numsources + 1 ) = NULL;
+ mbytes = regval_build_multi_sz( wp, &msz_wp );
+ dump_data( 1, ( uint8 * ) msz_wp, mbytes );
+ regval_ctr_addvalue( values, "Sources", REG_MULTI_SZ,
+ ( char * ) msz_wp, mbytes );
+ regdb_store_values( evtlogpath, values );
+ TALLOC_FREE(msz_wp);
+ } else {
+ DEBUG( 3,
+ ( "Source name [%s] found in existing list of sources\n",
+ sourcename ) );
+ }
+ TALLOC_FREE(values);
+ TALLOC_FREE(wrklist); /* */
+
+ if ( !( subkeys = TALLOC_ZERO_P(ctx, REGSUBKEY_CTR ) ) ) {
+ DEBUG( 0, ( "talloc() failure!\n" ) );
+ return False;
+ }
+ TALLOC_FREE(evtlogpath);
+ evtlogpath = talloc_asprintf(ctx, "%s\\%s", KEY_EVENTLOG, eventlog );
+ if (!evtlogpath) {
+ TALLOC_FREE(subkeys);
+ return false;
+ }
+
+ regdb_fetch_keys( evtlogpath, subkeys );
+
+ if ( !regsubkey_ctr_key_exists( subkeys, sourcename ) ) {
+ DEBUG( 5,
+ ( " Source name [%s] for eventlog [%s] didn't exist, adding \n",
+ sourcename, eventlog ) );
+ regsubkey_ctr_addkey( subkeys, sourcename );
+ if ( !regdb_store_keys( evtlogpath, subkeys ) )
+ return False;
+ }
+ TALLOC_FREE(subkeys);
+
+ /* at this point KEY_EVENTLOG/<eventlog>/<sourcename> key is in there. Now need to add EventMessageFile */
+
+ /* now allocate room for the source's subkeys */
+
+ if ( !( subkeys = TALLOC_ZERO_P(ctx, REGSUBKEY_CTR ) ) ) {
+ DEBUG( 0, ( "talloc() failure!\n" ) );
+ return False;
+ }
+ TALLOC_FREE(evtlogpath);
+ evtlogpath = talloc_asprintf(ctx, "%s\\%s\\%s",
+ KEY_EVENTLOG, eventlog, sourcename);
+ if (!evtlogpath) {
+ TALLOC_FREE(subkeys);
+ return false;
+ }
+
+ regdb_fetch_keys( evtlogpath, subkeys );
+
+ /* now add the values to the KEY_EVENTLOG/Application form key */
+ if ( !( values = TALLOC_ZERO_P(ctx, REGVAL_CTR ) ) ) {
+ DEBUG( 0, ( "talloc() failure!\n" ) );
+ return False;
+ }
+ DEBUG( 5,
+ ( "Storing EventMessageFile [%s] to eventlog path of [%s]\n",
+ messagefile, evtlogpath ) );
+
+ regdb_fetch_values( evtlogpath, values );
+
+ init_unistr2( &data, messagefile, UNI_STR_TERMINATE );
+
+ regval_ctr_addvalue( values, "EventMessageFile", REG_SZ,
+ ( char * ) data.buffer,
+ data.uni_str_len * sizeof( uint16 ) );
+ regdb_store_values( evtlogpath, values );
+
+ TALLOC_FREE(values);
+
+ return True;
+}
diff --git a/source3/registry/reg_init_basic.c b/source3/registry/reg_init_basic.c
new file mode 100644
index 0000000000..c5e2c346b0
--- /dev/null
+++ b/source3/registry/reg_init_basic.c
@@ -0,0 +1,55 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Registry helper routines
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+WERROR registry_init_common(void)
+{
+ WERROR werr;
+
+ werr = regdb_init();
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0, ("Failed to initialize the registry: %s\n",
+ dos_errstr(werr)));
+ goto done;
+ }
+
+ werr = reghook_cache_init();
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0, ("Failed to initialize the reghook cache: %s\n",
+ dos_errstr(werr)));
+ }
+
+done:
+ return werr;
+}
+
+WERROR registry_init_basic(void)
+{
+ WERROR werr;
+
+ DEBUG(10, ("registry_init_basic called\n"));
+
+ werr = registry_init_common();
+ regdb_close();
+ return werr;
+}
diff --git a/source3/registry/reg_init_full.c b/source3/registry/reg_init_full.c
new file mode 100644
index 0000000000..91e55d76b2
--- /dev/null
+++ b/source3/registry/reg_init_full.c
@@ -0,0 +1,105 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Initialize the registry with all available backends. */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+extern REGISTRY_OPS printing_ops;
+extern REGISTRY_OPS eventlog_ops;
+extern REGISTRY_OPS shares_reg_ops;
+extern REGISTRY_OPS smbconf_reg_ops;
+extern REGISTRY_OPS netlogon_params_reg_ops;
+extern REGISTRY_OPS prod_options_reg_ops;
+extern REGISTRY_OPS tcpip_params_reg_ops;
+extern REGISTRY_OPS hkpt_params_reg_ops;
+extern REGISTRY_OPS current_version_reg_ops;
+extern REGISTRY_OPS perflib_reg_ops;
+extern REGISTRY_OPS regdb_ops; /* these are the default */
+
+/* array of REGISTRY_HOOK's which are read into a tree for easy access */
+/* #define REG_TDB_ONLY 1 */
+
+REGISTRY_HOOK reg_hooks[] = {
+#ifndef REG_TDB_ONLY
+ { KEY_PRINTING, &printing_ops },
+ { KEY_PRINTING_2K, &printing_ops },
+ { KEY_PRINTING_PORTS, &printing_ops },
+ { KEY_SHARES, &shares_reg_ops },
+ { KEY_SMBCONF, &smbconf_reg_ops },
+ { KEY_NETLOGON_PARAMS, &netlogon_params_reg_ops },
+ { KEY_PROD_OPTIONS, &prod_options_reg_ops },
+ { KEY_TCPIP_PARAMS, &tcpip_params_reg_ops },
+ { KEY_HKPT, &hkpt_params_reg_ops },
+ { KEY_CURRENT_VERSION, &current_version_reg_ops },
+ { KEY_PERFLIB, &perflib_reg_ops },
+#endif
+ { NULL, NULL }
+};
+
+/***********************************************************************
+ Open the registry database and initialize the REGISTRY_HOOK cache
+ with all available backens.
+ ***********************************************************************/
+
+WERROR registry_init_full(void)
+{
+ int i;
+ WERROR werr;
+
+ werr = registry_init_common();
+ if (!W_ERROR_IS_OK(werr)) {
+ goto fail;
+ }
+
+ /* setup the necessary keys and values */
+
+ werr = init_registry_data();
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0, ("Failed to initialize data in registry!\n"));
+ goto fail;
+ }
+
+ /* build the cache tree of registry hooks */
+
+ for ( i=0; reg_hooks[i].keyname; i++ ) {
+ werr = reghook_cache_add(reg_hooks[i].keyname, reg_hooks[i].ops);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto fail;
+ }
+ }
+
+ if ( DEBUGLEVEL >= 20 )
+ reghook_dump_cache(20);
+
+ /* add any keys for other services */
+
+ svcctl_init_keys();
+ eventlog_init_keys();
+ perfcount_init_keys();
+
+fail:
+ /* close and let each smbd open up as necessary */
+ regdb_close();
+ return werr;
+}
diff --git a/source3/registry/reg_init_smbconf.c b/source3/registry/reg_init_smbconf.c
new file mode 100644
index 0000000000..43a5be025d
--- /dev/null
+++ b/source3/registry/reg_init_smbconf.c
@@ -0,0 +1,104 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Registry helper routines
+ * Copyright (C) Michael Adam 2007
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+extern REGISTRY_OPS smbconf_reg_ops;
+
+/*
+ * create a fake token just with enough rights to
+ * locally access the registry:
+ *
+ * - builtin administrators sid
+ * - disk operators privilege
+ */
+NTSTATUS registry_create_admin_token(TALLOC_CTX *mem_ctx,
+ NT_USER_TOKEN **ptoken)
+{
+ NTSTATUS status;
+ NT_USER_TOKEN *token = NULL;
+
+ if (ptoken == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ token = TALLOC_ZERO_P(mem_ctx, NT_USER_TOKEN);
+ if (token == NULL) {
+ DEBUG(1, ("talloc failed\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ token->privileges = se_disk_operators;
+ status = add_sid_to_array(token, &global_sid_Builtin_Administrators,
+ &token->user_sids, &token->num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Error adding builtin administrators sid "
+ "to fake token.\n"));
+ goto done;
+ }
+
+ *ptoken = token;
+
+done:
+ return status;
+}
+
+/*
+ * init the smbconf portion of the registry.
+ * for use in places where not the whole registry is needed,
+ * e.g. utils/net_conf.c and loadparm.c
+ */
+WERROR registry_init_smbconf(const char *keyname)
+{
+ WERROR werr;
+
+ DEBUG(10, ("registry_init_smbconf called\n"));
+
+ if (keyname == NULL) {
+ DEBUG(10, ("registry_init_smbconf: defaulting to key '%s'\n",
+ KEY_SMBCONF));
+ keyname = KEY_SMBCONF;
+ }
+
+ werr = registry_init_common();
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = init_registry_key(keyname);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(1, ("Failed to initialize registry key '%s': %s\n",
+ keyname, dos_errstr(werr)));
+ goto done;
+ }
+
+ werr = reghook_cache_add(keyname, &smbconf_reg_ops);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(1, ("Failed to add smbconf reghooks to reghook cache: "
+ "%s\n", dos_errstr(werr)));
+ goto done;
+ }
+
+done:
+ regdb_close();
+ return werr;
+}
diff --git a/source3/registry/reg_objects.c b/source3/registry/reg_objects.c
new file mode 100644
index 0000000000..47122ccad2
--- /dev/null
+++ b/source3/registry/reg_objects.c
@@ -0,0 +1,431 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Implementation of registry frontend view functions. */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+/**********************************************************************
+
+ Note that the REGSUB_CTR and REGVAL_CTR objects *must* be talloc()'d
+ since the methods use the object pointer as the talloc context for
+ internal private data.
+
+ There is no longer a regXXX_ctr_intit() and regXXX_ctr_destroy()
+ pair of functions. Simply TALLOC_ZERO_P() and TALLOC_FREE() the
+ object.
+
+ **********************************************************************/
+
+/***********************************************************************
+ Add a new key to the array
+ **********************************************************************/
+
+WERROR regsubkey_ctr_addkey( REGSUBKEY_CTR *ctr, const char *keyname )
+{
+ char **newkeys;
+
+ if ( !keyname ) {
+ return WERR_OK;
+ }
+
+ /* make sure the keyname is not already there */
+
+ if ( regsubkey_ctr_key_exists( ctr, keyname ) ) {
+ return WERR_OK;
+ }
+
+ if (!(newkeys = TALLOC_REALLOC_ARRAY(ctr, ctr->subkeys, char *,
+ ctr->num_subkeys+1))) {
+ return WERR_NOMEM;
+ }
+
+ ctr->subkeys = newkeys;
+
+ if (!(ctr->subkeys[ctr->num_subkeys] = talloc_strdup(ctr->subkeys,
+ keyname ))) {
+ /*
+ * Don't shrink the new array again, this wastes a pointer
+ */
+ return WERR_NOMEM;
+ }
+ ctr->num_subkeys++;
+
+ return WERR_OK;
+}
+
+ /***********************************************************************
+ Delete a key from the array
+ **********************************************************************/
+
+int regsubkey_ctr_delkey( REGSUBKEY_CTR *ctr, const char *keyname )
+{
+ int i;
+
+ if ( !keyname )
+ return ctr->num_subkeys;
+
+ /* make sure the keyname is actually already there */
+
+ for ( i=0; i<ctr->num_subkeys; i++ ) {
+ if ( strequal( ctr->subkeys[i], keyname ) )
+ break;
+ }
+
+ if ( i == ctr->num_subkeys )
+ return ctr->num_subkeys;
+
+ /* update if we have any keys left */
+ ctr->num_subkeys--;
+ if ( i < ctr->num_subkeys )
+ memmove(&ctr->subkeys[i], &ctr->subkeys[i+1],
+ sizeof(char*) * (ctr->num_subkeys-i));
+
+ return ctr->num_subkeys;
+}
+
+/***********************************************************************
+ Check for the existance of a key
+ **********************************************************************/
+
+bool regsubkey_ctr_key_exists( REGSUBKEY_CTR *ctr, const char *keyname )
+{
+ int i;
+
+ if (!ctr->subkeys) {
+ return False;
+ }
+
+ for ( i=0; i<ctr->num_subkeys; i++ ) {
+ if ( strequal( ctr->subkeys[i],keyname ) )
+ return True;
+ }
+
+ return False;
+}
+
+/***********************************************************************
+ How many keys does the container hold ?
+ **********************************************************************/
+
+int regsubkey_ctr_numkeys( REGSUBKEY_CTR *ctr )
+{
+ return ctr->num_subkeys;
+}
+
+/***********************************************************************
+ Retreive a specific key string
+ **********************************************************************/
+
+char* regsubkey_ctr_specific_key( REGSUBKEY_CTR *ctr, uint32 key_index )
+{
+ if ( ! (key_index < ctr->num_subkeys) )
+ return NULL;
+
+ return ctr->subkeys[key_index];
+}
+
+/*
+ * Utility functions for REGVAL_CTR
+ */
+
+/***********************************************************************
+ How many keys does the container hold ?
+ **********************************************************************/
+
+int regval_ctr_numvals( REGVAL_CTR *ctr )
+{
+ return ctr->num_values;
+}
+
+/***********************************************************************
+ allocate memory for and duplicate a REGISTRY_VALUE.
+ This is malloc'd memory so the caller should free it when done
+ **********************************************************************/
+
+REGISTRY_VALUE* dup_registry_value( REGISTRY_VALUE *val )
+{
+ REGISTRY_VALUE *copy = NULL;
+
+ if ( !val )
+ return NULL;
+
+ if ( !(copy = SMB_MALLOC_P( REGISTRY_VALUE)) ) {
+ DEBUG(0,("dup_registry_value: malloc() failed!\n"));
+ return NULL;
+ }
+
+ /* copy all the non-pointer initial data */
+
+ memcpy( copy, val, sizeof(REGISTRY_VALUE) );
+
+ copy->size = 0;
+ copy->data_p = NULL;
+
+ if ( val->data_p && val->size )
+ {
+ if ( !(copy->data_p = (uint8 *)memdup( val->data_p,
+ val->size )) ) {
+ DEBUG(0,("dup_registry_value: memdup() failed for [%d] "
+ "bytes!\n", val->size));
+ SAFE_FREE( copy );
+ return NULL;
+ }
+ copy->size = val->size;
+ }
+
+ return copy;
+}
+
+/**********************************************************************
+ free the memory allocated to a REGISTRY_VALUE
+ *********************************************************************/
+
+void free_registry_value( REGISTRY_VALUE *val )
+{
+ if ( !val )
+ return;
+
+ SAFE_FREE( val->data_p );
+ SAFE_FREE( val );
+
+ return;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+uint8* regval_data_p( REGISTRY_VALUE *val )
+{
+ return val->data_p;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+uint32 regval_size( REGISTRY_VALUE *val )
+{
+ return val->size;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+char* regval_name( REGISTRY_VALUE *val )
+{
+ return val->valuename;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+uint32 regval_type( REGISTRY_VALUE *val )
+{
+ return val->type;
+}
+
+/***********************************************************************
+ Retreive a pointer to a specific value. Caller shoud dup the structure
+ since this memory will go away when the ctr is free()'d
+ **********************************************************************/
+
+REGISTRY_VALUE* regval_ctr_specific_value( REGVAL_CTR *ctr, uint32 idx )
+{
+ if ( !(idx < ctr->num_values) )
+ return NULL;
+
+ return ctr->values[idx];
+}
+
+/***********************************************************************
+ Check for the existance of a value
+ **********************************************************************/
+
+bool regval_ctr_key_exists( REGVAL_CTR *ctr, const char *value )
+{
+ int i;
+
+ for ( i=0; i<ctr->num_values; i++ ) {
+ if ( strequal( ctr->values[i]->valuename, value) )
+ return True;
+ }
+
+ return False;
+}
+
+/***********************************************************************
+ * compose a REGISTRY_VALUE from input data
+ **********************************************************************/
+
+REGISTRY_VALUE *regval_compose(TALLOC_CTX *ctx, const char *name, uint16 type,
+ const char *data_p, size_t size)
+{
+ REGISTRY_VALUE *regval = TALLOC_P(ctx, REGISTRY_VALUE);
+
+ if (regval == NULL) {
+ return NULL;
+ }
+
+ fstrcpy(regval->valuename, name);
+ regval->type = type;
+ if (size) {
+ regval->data_p = (uint8 *)TALLOC_MEMDUP(regval, data_p, size);
+ if (!regval->data_p) {
+ TALLOC_FREE(regval);
+ return NULL;
+ }
+ } else {
+ regval->data_p = NULL;
+ }
+ regval->size = size;
+
+ return regval;
+}
+
+/***********************************************************************
+ Add a new registry value to the array
+ **********************************************************************/
+
+int regval_ctr_addvalue( REGVAL_CTR *ctr, const char *name, uint16 type,
+ const char *data_p, size_t size )
+{
+ if ( !name )
+ return ctr->num_values;
+
+ /* Delete the current value (if it exists) and add the new one */
+
+ regval_ctr_delvalue( ctr, name );
+
+ /* allocate a slot in the array of pointers */
+
+ if ( ctr->num_values == 0 ) {
+ ctr->values = TALLOC_P( ctr, REGISTRY_VALUE *);
+ } else {
+ ctr->values = TALLOC_REALLOC_ARRAY(ctr, ctr->values,
+ REGISTRY_VALUE *,
+ ctr->num_values+1);
+ }
+
+ if (!ctr->values) {
+ ctr->num_values = 0;
+ return 0;
+ }
+
+ /* allocate a new value and store the pointer in the arrya */
+
+ ctr->values[ctr->num_values] = regval_compose(ctr, name, type, data_p,
+ size);
+ if (ctr->values[ctr->num_values] == NULL) {
+ ctr->num_values = 0;
+ return 0;
+ }
+ ctr->num_values++;
+
+ return ctr->num_values;
+}
+
+/***********************************************************************
+ Add a new registry value to the array
+ **********************************************************************/
+
+int regval_ctr_copyvalue( REGVAL_CTR *ctr, REGISTRY_VALUE *val )
+{
+ if ( val ) {
+ regval_ctr_addvalue(ctr, val->valuename, val->type,
+ (char *)val->data_p, val->size);
+ }
+
+ return ctr->num_values;
+}
+
+/***********************************************************************
+ Delete a single value from the registry container.
+ No need to free memory since it is talloc'd.
+ **********************************************************************/
+
+int regval_ctr_delvalue( REGVAL_CTR *ctr, const char *name )
+{
+ int i;
+
+ for ( i=0; i<ctr->num_values; i++ ) {
+ if ( strequal( ctr->values[i]->valuename, name ) )
+ break;
+ }
+
+ /* just return if we don't find it */
+
+ if ( i == ctr->num_values )
+ return ctr->num_values;
+
+ /* If 'i' was not the last element, just shift everything down one */
+ ctr->num_values--;
+ if ( i < ctr->num_values )
+ memmove(&ctr->values[i], &ctr->values[i+1],
+ sizeof(REGISTRY_VALUE*)*(ctr->num_values-i));
+
+ return ctr->num_values;
+}
+
+/***********************************************************************
+ Retrieve single value from the registry container.
+ No need to free memory since it is talloc'd.
+ **********************************************************************/
+
+REGISTRY_VALUE* regval_ctr_getvalue( REGVAL_CTR *ctr, const char *name )
+{
+ int i;
+
+ /* search for the value */
+
+ for ( i=0; i<ctr->num_values; i++ ) {
+ if ( strequal( ctr->values[i]->valuename, name ) )
+ return ctr->values[i];
+ }
+
+ return NULL;
+}
+
+/***********************************************************************
+ return the data_p as a uint32
+ **********************************************************************/
+
+uint32 regval_dword( REGISTRY_VALUE *val )
+{
+ uint32 data;
+
+ data = IVAL( regval_data_p(val), 0 );
+
+ return data;
+}
+
+/***********************************************************************
+ return the data_p as a character string
+ **********************************************************************/
+
+char *regval_sz(REGISTRY_VALUE *val)
+{
+ char *data = NULL;
+
+ rpcstr_pull_talloc(talloc_tos(), &data,
+ regval_data_p(val), regval_size(val),0);
+ return data;
+}
diff --git a/source3/registry/reg_perfcount.c b/source3/registry/reg_perfcount.c
new file mode 100644
index 0000000000..e608847048
--- /dev/null
+++ b/source3/registry/reg_perfcount.c
@@ -0,0 +1,1372 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005,
+ * Copyright (C) Gerald (Jerry) Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+#define PERFCOUNT_MAX_LEN 256
+
+#define PERFCOUNTDIR "perfmon"
+#define NAMES_DB "names.tdb"
+#define DATA_DB "data.tdb"
+
+PERF_OBJECT_TYPE *_reg_perfcount_find_obj(PERF_DATA_BLOCK *block, int objind);
+
+/*********************************************************************
+*********************************************************************/
+
+static char *counters_directory(const char *dbname)
+{
+ char *path = NULL;
+ char *ret = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if (!dbname)
+ return NULL;
+
+ path = talloc_asprintf(ctx, "%s/%s", PERFCOUNTDIR, dbname);
+ if (!path) {
+ return NULL;
+ }
+
+ ret = talloc_strdup(ctx, state_path(path));
+ TALLOC_FREE(path);
+ return ret;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+void perfcount_init_keys( void )
+{
+ char *p = state_path(PERFCOUNTDIR);
+
+ /* no registry keys; just create the perfmon directory */
+
+ if ( !directory_exist( p, NULL ) )
+ mkdir( p, 0755 );
+
+ return;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+uint32 reg_perfcount_get_base_index(void)
+{
+ const char *fname = counters_directory( NAMES_DB );
+ TDB_CONTEXT *names;
+ TDB_DATA kbuf, dbuf;
+ char key[] = "1";
+ uint32 retval = 0;
+ char buf[PERFCOUNT_MAX_LEN];
+
+ names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
+
+ if ( !names ) {
+ DEBUG(1, ("reg_perfcount_get_base_index: unable to open [%s].\n", fname));
+ return 0;
+ }
+ /* needs to read the value of key "1" from the counter_names.tdb file, as that is
+ where the total number of counters is stored. We're assuming no holes in the
+ enumeration.
+ The format for the counter_names.tdb file is:
+ key value
+ 1 num_counters
+ 2 perf_counter1
+ 3 perf_counter1_help
+ 4 perf_counter2
+ 5 perf_counter2_help
+ even_num perf_counter<even_num>
+ even_num+1 perf_counter<even_num>_help
+ and so on.
+ So last_counter becomes num_counters*2, and last_help will be last_counter+1 */
+ kbuf = string_tdb_data(key);
+ dbuf = tdb_fetch(names, kbuf);
+ if(dbuf.dptr == NULL)
+ {
+ DEBUG(1, ("reg_perfcount_get_base_index: failed to find key \'1\' in [%s].\n", fname));
+ tdb_close(names);
+ return 0;
+ }
+ else
+ {
+ tdb_close(names);
+ memset(buf, 0, PERFCOUNT_MAX_LEN);
+ memcpy(buf, dbuf.dptr, dbuf.dsize);
+ retval = (uint32)atoi(buf);
+ SAFE_FREE(dbuf.dptr);
+ return retval;
+ }
+ return 0;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+uint32 reg_perfcount_get_last_counter(uint32 base_index)
+{
+ uint32 retval;
+
+ if(base_index == 0)
+ retval = 0;
+ else
+ retval = base_index * 2;
+
+ return retval;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+uint32 reg_perfcount_get_last_help(uint32 last_counter)
+{
+ uint32 retval;
+
+ if(last_counter == 0)
+ retval = 0;
+ else
+ retval = last_counter + 1;
+
+ return retval;
+}
+
+
+/*********************************************************************
+*********************************************************************/
+
+static uint32 _reg_perfcount_multi_sz_from_tdb(TDB_CONTEXT *tdb,
+ int keyval,
+ char **retbuf,
+ uint32 buffer_size)
+{
+ TDB_DATA kbuf, dbuf;
+ char temp[256];
+ char *buf1 = *retbuf;
+ uint32 working_size = 0;
+ UNISTR2 name_index, name;
+
+ memset(temp, 0, sizeof(temp));
+ snprintf(temp, sizeof(temp), "%d", keyval);
+ kbuf = string_tdb_data(temp);
+ dbuf = tdb_fetch(tdb, kbuf);
+ if(dbuf.dptr == NULL)
+ {
+ /* If a key isn't there, just bypass it -- this really shouldn't
+ happen unless someone's mucking around with the tdb */
+ DEBUG(3, ("_reg_perfcount_multi_sz_from_tdb: failed to find key [%s] in [%s].\n",
+ temp, tdb_name(tdb)));
+ return buffer_size;
+ }
+ /* First encode the name_index */
+ working_size = (kbuf.dsize + 1)*sizeof(uint16);
+ buf1 = (char *)SMB_REALLOC(buf1, buffer_size + working_size);
+ if(!buf1) {
+ buffer_size = 0;
+ return buffer_size;
+ }
+ init_unistr2(&name_index, (const char *)kbuf.dptr, UNI_STR_TERMINATE);
+ memcpy(buf1+buffer_size, (char *)name_index.buffer, working_size);
+ buffer_size += working_size;
+ /* Now encode the actual name */
+ working_size = (dbuf.dsize + 1)*sizeof(uint16);
+ buf1 = (char *)SMB_REALLOC(buf1, buffer_size + working_size);
+ if(!buf1) {
+ buffer_size = 0;
+ return buffer_size;
+ }
+ memset(temp, 0, sizeof(temp));
+ memcpy(temp, dbuf.dptr, dbuf.dsize);
+ SAFE_FREE(dbuf.dptr);
+ init_unistr2(&name, temp, UNI_STR_TERMINATE);
+ memcpy(buf1+buffer_size, (char *)name.buffer, working_size);
+ buffer_size += working_size;
+
+ *retbuf = buf1;
+
+ return buffer_size;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+uint32 reg_perfcount_get_counter_help(uint32 base_index, char **retbuf)
+{
+ char *buf1 = NULL;
+ uint32 buffer_size = 0;
+ TDB_CONTEXT *names;
+ const char *fname = counters_directory( NAMES_DB );
+ int i;
+
+ if(base_index == 0)
+ return 0;
+
+ names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
+
+ if(names == NULL)
+ {
+ DEBUG(1, ("reg_perfcount_get_counter_help: unable to open [%s].\n", fname));
+ return 0;
+ }
+
+ for(i = 1; i <= base_index; i++)
+ {
+ buffer_size = _reg_perfcount_multi_sz_from_tdb(names, (i*2)+1, retbuf, buffer_size);
+ }
+ tdb_close(names);
+
+ /* Now terminate the MULTI_SZ with a double unicode NULL */
+ buf1 = *retbuf;
+ buf1 = (char *)SMB_REALLOC(buf1, buffer_size + 2);
+ if(!buf1) {
+ buffer_size = 0;
+ } else {
+ buf1[buffer_size++] = '\0';
+ buf1[buffer_size++] = '\0';
+ }
+
+ *retbuf = buf1;
+
+ return buffer_size;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+uint32 reg_perfcount_get_counter_names(uint32 base_index, char **retbuf)
+{
+ char *buf1 = NULL;
+ uint32 buffer_size = 0;
+ TDB_CONTEXT *names;
+ const char *fname = counters_directory( NAMES_DB );
+ int i;
+
+ if(base_index == 0)
+ return 0;
+
+ names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
+
+ if(names == NULL)
+ {
+ DEBUG(1, ("reg_perfcount_get_counter_names: unable to open [%s].\n", fname));
+ return 0;
+ }
+
+ buffer_size = _reg_perfcount_multi_sz_from_tdb(names, 1, retbuf, buffer_size);
+
+ for(i = 1; i <= base_index; i++)
+ {
+ buffer_size = _reg_perfcount_multi_sz_from_tdb(names, i*2, retbuf, buffer_size);
+ }
+ tdb_close(names);
+
+ /* Now terminate the MULTI_SZ with a double unicode NULL */
+ buf1 = *retbuf;
+ buf1 = (char *)SMB_REALLOC(buf1, buffer_size + 2);
+ if(!buf1) {
+ buffer_size = 0;
+ } else {
+ buf1[buffer_size++] = '\0';
+ buf1[buffer_size++] = '\0';
+ }
+
+ *retbuf=buf1;
+
+ return buffer_size;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static void _reg_perfcount_make_key(TDB_DATA *key,
+ char *buf,
+ int buflen,
+ int key_part1,
+ const char *key_part2)
+{
+ memset(buf, 0, buflen);
+ if(key_part2 != NULL)
+ snprintf(buf, buflen,"%d%s", key_part1, key_part2);
+ else
+ snprintf(buf, buflen, "%d", key_part1);
+
+ *key = string_tdb_data(buf);
+
+ return;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool _reg_perfcount_isparent(TDB_DATA data)
+{
+ if(data.dsize > 0)
+ {
+ if(data.dptr[0] == 'p')
+ return True;
+ else
+ return False;
+ }
+ return False;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool _reg_perfcount_ischild(TDB_DATA data)
+{
+ if(data.dsize > 0)
+ {
+ if(data.dptr[0] == 'c')
+ return True;
+ else
+ return False;
+ }
+ return False;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static uint32 _reg_perfcount_get_numinst(int objInd, TDB_CONTEXT *names)
+{
+ TDB_DATA key, data;
+ char buf[PERFCOUNT_MAX_LEN];
+
+ _reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, objInd, "inst");
+ data = tdb_fetch(names, key);
+
+ if(data.dptr == NULL)
+ return (uint32)PERF_NO_INSTANCES;
+
+ memset(buf, 0, PERFCOUNT_MAX_LEN);
+ memcpy(buf, data.dptr, data.dsize);
+ SAFE_FREE(data.dptr);
+ return (uint32)atoi(buf);
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool _reg_perfcount_add_object(PERF_DATA_BLOCK *block,
+ prs_struct *ps,
+ int num,
+ TDB_DATA data,
+ TDB_CONTEXT *names)
+{
+ int i;
+ bool success = True;
+ PERF_OBJECT_TYPE *obj;
+
+ block->objects = (PERF_OBJECT_TYPE *)TALLOC_REALLOC_ARRAY(ps->mem_ctx,
+ block->objects,
+ PERF_OBJECT_TYPE,
+ block->NumObjectTypes+1);
+ if(block->objects == NULL)
+ return False;
+ obj = &(block->objects[block->NumObjectTypes]);
+ memset((void *)&(block->objects[block->NumObjectTypes]), 0, sizeof(PERF_OBJECT_TYPE));
+ block->objects[block->NumObjectTypes].ObjectNameTitleIndex = num;
+ block->objects[block->NumObjectTypes].ObjectNameTitlePointer = 0;
+ block->objects[block->NumObjectTypes].ObjectHelpTitleIndex = num+1;
+ block->objects[block->NumObjectTypes].ObjectHelpTitlePointer = 0;
+ block->objects[block->NumObjectTypes].NumCounters = 0;
+ block->objects[block->NumObjectTypes].DefaultCounter = 0;
+ block->objects[block->NumObjectTypes].NumInstances = _reg_perfcount_get_numinst(num, names);
+ block->objects[block->NumObjectTypes].counters = NULL;
+ block->objects[block->NumObjectTypes].instances = NULL;
+ block->objects[block->NumObjectTypes].counter_data.ByteLength = sizeof(uint32);
+ block->objects[block->NumObjectTypes].counter_data.data = NULL;
+ block->objects[block->NumObjectTypes].DetailLevel = PERF_DETAIL_NOVICE;
+ block->NumObjectTypes+=1;
+
+ for(i = 0; i < (int)obj->NumInstances; i++) {
+ success = _reg_perfcount_add_instance(obj, ps, i, names);
+ }
+
+ return success;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+bool _reg_perfcount_get_counter_data(TDB_DATA key, TDB_DATA *data)
+{
+ TDB_CONTEXT *counters;
+ const char *fname = counters_directory( DATA_DB );
+
+ counters = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
+
+ if(counters == NULL)
+ {
+ DEBUG(1, ("reg_perfcount_get_counter_data: unable to open [%s].\n", fname));
+ return False;
+ }
+
+ *data = tdb_fetch(counters, key);
+
+ tdb_close(counters);
+
+ return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static uint32 _reg_perfcount_get_size_field(uint32 CounterType)
+{
+ uint32 retval;
+
+ retval = CounterType;
+
+ /* First mask out reserved lower 8 bits */
+ retval = retval & 0xFFFFFF00;
+ retval = retval << 22;
+ retval = retval >> 22;
+
+ return retval;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static uint32 _reg_perfcount_compute_scale(SMB_BIG_INT data)
+{
+ int scale = 0;
+ if(data == 0)
+ return scale;
+ while(data > 100)
+ {
+ data /= 10;
+ scale--;
+ }
+ while(data < 10)
+ {
+ data *= 10;
+ scale++;
+ }
+
+ return (uint32)scale;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool _reg_perfcount_get_counter_info(PERF_DATA_BLOCK *block,
+ prs_struct *ps,
+ int CounterIndex,
+ PERF_OBJECT_TYPE *obj,
+ TDB_CONTEXT *names)
+{
+ TDB_DATA key, data;
+ char buf[PERFCOUNT_MAX_LEN];
+ size_t dsize, padding;
+ long int data32, dbuf[2];
+ SMB_BIG_INT data64;
+ uint32 counter_size;
+
+ obj->counters[obj->NumCounters].DefaultScale = 0;
+ dbuf[0] = dbuf[1] = 0;
+ padding = 0;
+
+ _reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, CounterIndex, "type");
+ data = tdb_fetch(names, key);
+ if(data.dptr == NULL)
+ {
+ DEBUG(3, ("_reg_perfcount_get_counter_info: No type data for counter [%d].\n", CounterIndex));
+ return False;
+ }
+ memset(buf, 0, PERFCOUNT_MAX_LEN);
+ memcpy(buf, data.dptr, data.dsize);
+ obj->counters[obj->NumCounters].CounterType = atoi(buf);
+ DEBUG(10, ("_reg_perfcount_get_counter_info: Got type [%d] for counter [%d].\n",
+ obj->counters[obj->NumCounters].CounterType, CounterIndex));
+ SAFE_FREE(data.dptr);
+
+ /* Fetch the actual data */
+ _reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, CounterIndex, "");
+ _reg_perfcount_get_counter_data(key, &data);
+ if(data.dptr == NULL)
+ {
+ DEBUG(3, ("_reg_perfcount_get_counter_info: No counter data for counter [%d].\n", CounterIndex));
+ return False;
+ }
+
+ counter_size = _reg_perfcount_get_size_field(obj->counters[obj->NumCounters].CounterType);
+
+ if(counter_size == PERF_SIZE_DWORD)
+ {
+ dsize = sizeof(data32);
+ memset(buf, 0, PERFCOUNT_MAX_LEN);
+ memcpy(buf, data.dptr, data.dsize);
+ data32 = strtol(buf, NULL, 0);
+ if((obj->counters[obj->NumCounters].CounterType & 0x00000F00) == PERF_TYPE_NUMBER)
+ obj->counters[obj->NumCounters].DefaultScale = _reg_perfcount_compute_scale((SMB_BIG_INT)data32);
+ else
+ obj->counters[obj->NumCounters].DefaultScale = 0;
+ dbuf[0] = data32;
+ padding = (dsize - (obj->counter_data.ByteLength%dsize)) % dsize;
+ }
+ else if(counter_size == PERF_SIZE_LARGE)
+ {
+ dsize = sizeof(data64);
+ memset(buf, 0, PERFCOUNT_MAX_LEN);
+ memcpy(buf, data.dptr, data.dsize);
+ data64 = atof(buf);
+ if((obj->counters[obj->NumCounters].CounterType & 0x00000F00) == PERF_TYPE_NUMBER)
+ obj->counters[obj->NumCounters].DefaultScale = _reg_perfcount_compute_scale(data64);
+ else
+ obj->counters[obj->NumCounters].DefaultScale = 0;
+ memcpy((void *)dbuf, (const void *)&data64, dsize);
+ padding = (dsize - (obj->counter_data.ByteLength%dsize)) % dsize;
+ }
+ else /* PERF_SIZE_VARIABLE_LEN */
+ {
+ dsize = data.dsize;
+ memset(buf, 0, PERFCOUNT_MAX_LEN);
+ memcpy(buf, data.dptr, data.dsize);
+ }
+ SAFE_FREE(data.dptr);
+
+ obj->counter_data.ByteLength += dsize + padding;
+ obj->counter_data.data = TALLOC_REALLOC_ARRAY(ps->mem_ctx,
+ obj->counter_data.data,
+ uint8,
+ obj->counter_data.ByteLength - sizeof(uint32));
+ if(obj->counter_data.data == NULL)
+ return False;
+ if(dbuf[0] != 0 || dbuf[1] != 0)
+ {
+ memcpy((void *)(obj->counter_data.data +
+ (obj->counter_data.ByteLength - (sizeof(uint32) + dsize))),
+ (const void *)dbuf, dsize);
+ }
+ else
+ {
+ /* Handling PERF_SIZE_VARIABLE_LEN */
+ memcpy((void *)(obj->counter_data.data +
+ (obj->counter_data.ByteLength - (sizeof(uint32) + dsize))),
+ (const void *)buf, dsize);
+ }
+ obj->counters[obj->NumCounters].CounterOffset = obj->counter_data.ByteLength - dsize;
+ if(obj->counters[obj->NumCounters].CounterOffset % dsize != 0)
+ {
+ DEBUG(3,("Improperly aligned counter [%d]\n", obj->NumCounters));
+ }
+ obj->counters[obj->NumCounters].CounterSize = dsize;
+
+ return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+PERF_OBJECT_TYPE *_reg_perfcount_find_obj(PERF_DATA_BLOCK *block, int objind)
+{
+ int i;
+
+ PERF_OBJECT_TYPE *obj = NULL;
+
+ for(i = 0; i < block->NumObjectTypes; i++)
+ {
+ if(block->objects[i].ObjectNameTitleIndex == objind)
+ {
+ obj = &(block->objects[i]);
+ }
+ }
+
+ return obj;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool _reg_perfcount_add_counter(PERF_DATA_BLOCK *block,
+ prs_struct *ps,
+ int num,
+ TDB_DATA data,
+ TDB_CONTEXT *names)
+{
+ char *begin, *end, *start, *stop;
+ int parent;
+ PERF_OBJECT_TYPE *obj;
+ bool success = True;
+ char buf[PERFCOUNT_MAX_LEN];
+
+ obj = NULL;
+ memset(buf, 0, PERFCOUNT_MAX_LEN);
+ memcpy(buf, data.dptr, data.dsize);
+ begin = index(buf, '[');
+ end = index(buf, ']');
+ if(begin == NULL || end == NULL)
+ return False;
+ start = begin+1;
+
+ while(start < end) {
+ stop = index(start, ',');
+ if(stop == NULL)
+ stop = end;
+ *stop = '\0';
+ parent = atoi(start);
+
+ obj = _reg_perfcount_find_obj(block, parent);
+ if(obj == NULL) {
+ /* At this point we require that the parent object exist.
+ This can probably be handled better at some later time */
+ DEBUG(3, ("_reg_perfcount_add_counter: Could not find parent object [%d] for counter [%d].\n",
+ parent, num));
+ return False;
+ }
+ obj->counters = (PERF_COUNTER_DEFINITION *)TALLOC_REALLOC_ARRAY(ps->mem_ctx,
+ obj->counters,
+ PERF_COUNTER_DEFINITION,
+ obj->NumCounters+1);
+ if(obj->counters == NULL)
+ return False;
+ memset((void *)&(obj->counters[obj->NumCounters]), 0, sizeof(PERF_COUNTER_DEFINITION));
+ obj->counters[obj->NumCounters].CounterNameTitleIndex=num;
+ obj->counters[obj->NumCounters].CounterHelpTitleIndex=num+1;
+ obj->counters[obj->NumCounters].DetailLevel = PERF_DETAIL_NOVICE;
+ obj->counters[obj->NumCounters].ByteLength = sizeof(PERF_COUNTER_DEFINITION);
+ success = _reg_perfcount_get_counter_info(block, ps, num, obj, names);
+ obj->NumCounters += 1;
+ start = stop + 1;
+ }
+
+ /* Handle case of Objects/Counters without any counter data, which would suggest
+ that the required instances are not there yet, so change NumInstances from
+ PERF_NO_INSTANCES to 0 */
+
+ return success;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+bool _reg_perfcount_get_instance_info(PERF_INSTANCE_DEFINITION *inst,
+ prs_struct *ps,
+ int instId,
+ PERF_OBJECT_TYPE *obj,
+ TDB_CONTEXT *names)
+{
+ TDB_DATA key, data;
+ char buf[PERFCOUNT_MAX_LEN], temp[PERFCOUNT_MAX_LEN];
+ smb_ucs2_t *name = NULL;
+ int pad;
+
+ /* First grab the instance data from the data file */
+ memset(temp, 0, PERFCOUNT_MAX_LEN);
+ snprintf(temp, PERFCOUNT_MAX_LEN, "i%d", instId);
+ _reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, obj->ObjectNameTitleIndex, temp);
+ if (!_reg_perfcount_get_counter_data(key, &data)) {
+ DEBUG(3, ("_reg_perfcount_get_counter_data failed\n"));
+ return false;
+ }
+ if(data.dptr == NULL)
+ {
+ DEBUG(3, ("_reg_perfcount_get_instance_info: No instance data for instance [%s].\n",
+ buf));
+ return False;
+ }
+ inst->counter_data.ByteLength = data.dsize + sizeof(inst->counter_data.ByteLength);
+ inst->counter_data.data = TALLOC_REALLOC_ARRAY(ps->mem_ctx,
+ inst->counter_data.data,
+ uint8,
+ data.dsize);
+ if(inst->counter_data.data == NULL)
+ return False;
+ memset(inst->counter_data.data, 0, data.dsize);
+ memcpy(inst->counter_data.data, data.dptr, data.dsize);
+ SAFE_FREE(data.dptr);
+
+ /* Fetch instance name */
+ memset(temp, 0, PERFCOUNT_MAX_LEN);
+ snprintf(temp, PERFCOUNT_MAX_LEN, "i%dname", instId);
+ _reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, obj->ObjectNameTitleIndex, temp);
+ data = tdb_fetch(names, key);
+ if(data.dptr == NULL)
+ {
+ /* Not actually an error, but possibly unintended? -- just logging FYI */
+ DEBUG(3, ("_reg_perfcount_get_instance_info: No instance name for instance [%s].\n",
+ buf));
+ inst->NameLength = 0;
+ }
+ else
+ {
+ memset(buf, 0, PERFCOUNT_MAX_LEN);
+ memcpy(buf, data.dptr, MIN(PERFCOUNT_MAX_LEN-1,data.dsize));
+ buf[PERFCOUNT_MAX_LEN-1] = '\0';
+ inst->NameLength = rpcstr_push_talloc(ps->mem_ctx, &name, buf);
+ if (inst->NameLength == (uint32_t)-1 || !name) {
+ SAFE_FREE(data.dptr);
+ return False;
+ }
+ inst->data = TALLOC_REALLOC_ARRAY(ps->mem_ctx,
+ inst->data,
+ uint8,
+ inst->NameLength);
+ if (inst->data == NULL) {
+ SAFE_FREE(data.dptr);
+ return False;
+ }
+ memcpy(inst->data, name, inst->NameLength);
+ SAFE_FREE(data.dptr);
+ }
+
+ inst->ParentObjectTitleIndex = 0;
+ inst->ParentObjectTitlePointer = 0;
+ inst->UniqueID = PERF_NO_UNIQUE_ID;
+ inst->NameOffset = 6 * sizeof(uint32);
+
+ inst->ByteLength = inst->NameOffset + inst->NameLength;
+ /* Need to be aligned on a 64-bit boundary here for counter_data */
+ if((pad = (inst->ByteLength % 8)))
+ {
+ pad = 8 - pad;
+ inst->data = TALLOC_REALLOC_ARRAY(ps->mem_ctx,
+ inst->data,
+ uint8,
+ inst->NameLength + pad);
+ memset(inst->data + inst->NameLength, 0, pad);
+ inst->ByteLength += pad;
+ }
+
+ return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+bool _reg_perfcount_add_instance(PERF_OBJECT_TYPE *obj,
+ prs_struct *ps,
+ int instInd,
+ TDB_CONTEXT *names)
+{
+ PERF_INSTANCE_DEFINITION *inst;
+
+ if(obj->instances == NULL) {
+ obj->instances = TALLOC_REALLOC_ARRAY(ps->mem_ctx,
+ obj->instances,
+ PERF_INSTANCE_DEFINITION,
+ obj->NumInstances);
+ }
+ if(obj->instances == NULL)
+ return False;
+
+ memset(&(obj->instances[instInd]), 0, sizeof(PERF_INSTANCE_DEFINITION));
+ inst = &(obj->instances[instInd]);
+ return _reg_perfcount_get_instance_info(inst, ps, instInd, obj, names);
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static int _reg_perfcount_assemble_global(PERF_DATA_BLOCK *block,
+ prs_struct *ps,
+ int base_index,
+ TDB_CONTEXT *names)
+{
+ bool success;
+ int i, j, retval = 0;
+ char keybuf[PERFCOUNT_MAX_LEN];
+ TDB_DATA key, data;
+
+ for(i = 1; i <= base_index; i++)
+ {
+ j = i*2;
+ _reg_perfcount_make_key(&key, keybuf, PERFCOUNT_MAX_LEN, j, "rel");
+ data = tdb_fetch(names, key);
+ if(data.dptr != NULL)
+ {
+ if(_reg_perfcount_isparent(data))
+ success = _reg_perfcount_add_object(block, ps, j, data, names);
+ else if(_reg_perfcount_ischild(data))
+ success = _reg_perfcount_add_counter(block, ps, j, data, names);
+ else
+ {
+ DEBUG(3, ("Bogus relationship [%s] for counter [%d].\n", data.dptr, j));
+ success = False;
+ }
+ if(success == False)
+ {
+ DEBUG(3, ("_reg_perfcount_assemble_global: Failed to add new relationship for counter [%d].\n", j));
+ retval = -1;
+ }
+ SAFE_FREE(data.dptr);
+ }
+ else
+ DEBUG(3, ("NULL relationship for counter [%d] using key [%s].\n", j, keybuf));
+ }
+ return retval;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool _reg_perfcount_get_64(SMB_BIG_UINT *retval,
+ TDB_CONTEXT *tdb,
+ int key_part1,
+ const char *key_part2)
+{
+ TDB_DATA key, data;
+ char buf[PERFCOUNT_MAX_LEN];
+
+ _reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, key_part1, key_part2);
+
+ data = tdb_fetch(tdb, key);
+ if(data.dptr == NULL)
+ {
+ DEBUG(3,("_reg_perfcount_get_64: No data found for key [%s].\n", key.dptr));
+ return False;
+ }
+
+ memset(buf, 0, PERFCOUNT_MAX_LEN);
+ memcpy(buf, data.dptr, data.dsize);
+ SAFE_FREE(data.dptr);
+
+ *retval = atof(buf);
+
+ return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool _reg_perfcount_init_data_block_perf(PERF_DATA_BLOCK *block,
+ TDB_CONTEXT *names)
+{
+ SMB_BIG_UINT PerfFreq, PerfTime, PerfTime100nSec;
+ TDB_CONTEXT *counters;
+ bool status = False;
+ const char *fname = counters_directory( DATA_DB );
+
+ counters = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
+
+ if(counters == NULL)
+ {
+ DEBUG(1, ("reg_perfcount_init_data_block_perf: unable to open [%s].\n", fname));
+ return False;
+ }
+
+ status = _reg_perfcount_get_64(&PerfFreq, names, 0, "PerfFreq");
+ if(status == False)
+ {
+ tdb_close(counters);
+ return status;
+ }
+ memcpy((void *)&(block->PerfFreq), (const void *)&PerfFreq, sizeof(PerfFreq));
+
+ status = _reg_perfcount_get_64(&PerfTime, counters, 0, "PerfTime");
+ if(status == False)
+ {
+ tdb_close(counters);
+ return status;
+ }
+ memcpy((void *)&(block->PerfTime), (const void *)&PerfTime, sizeof(PerfTime));
+
+ status = _reg_perfcount_get_64(&PerfTime100nSec, counters, 0, "PerfTime100nSec");
+ if(status == False)
+ {
+ tdb_close(counters);
+ return status;
+ }
+ memcpy((void *)&(block->PerfTime100nSec), (const void *)&PerfTime100nSec, sizeof(PerfTime100nSec));
+
+ tdb_close(counters);
+ return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool _reg_perfcount_init_data_block(PERF_DATA_BLOCK *block,
+ prs_struct *ps, TDB_CONTEXT *names)
+{
+ smb_ucs2_t *temp = NULL;
+ time_t tm;
+
+ if (rpcstr_push_talloc(ps->mem_ctx, &temp, "PERF")==(size_t)-1) {
+ return false;
+ }
+ if (!temp) {
+ return false;
+ }
+ memcpy(block->Signature, temp, strlen_w(temp) *2);
+
+ if(ps->bigendian_data == RPC_BIG_ENDIAN)
+ block->LittleEndian = 0;
+ else
+ block->LittleEndian = 1;
+ block->Version = 1;
+ block->Revision = 1;
+ block->TotalByteLength = 0;
+ block->NumObjectTypes = 0;
+ block->DefaultObject = -1;
+ block->objects = NULL;
+ tm = time(NULL);
+ make_systemtime(&(block->SystemTime), gmtime(&tm));
+ _reg_perfcount_init_data_block_perf(block, names);
+ memset(temp, 0, sizeof(temp));
+ rpcstr_push((void *)temp, global_myname(), sizeof(temp), STR_TERMINATE);
+ block->SystemNameLength = (strlen_w(temp) * 2) + 2;
+ block->data = TALLOC_ZERO_ARRAY(ps->mem_ctx, uint8, block->SystemNameLength + (8 - (block->SystemNameLength % 8)));
+ if (block->data == NULL) {
+ return False;
+ }
+ memcpy(block->data, temp, block->SystemNameLength);
+ block->SystemNameOffset = sizeof(PERF_DATA_BLOCK) - sizeof(block->objects) - sizeof(block->data);
+ block->HeaderLength = block->SystemNameOffset + block->SystemNameLength;
+ /* Make sure to adjust for 64-bit alignment for when we finish writing the system name,
+ so that the PERF_OBJECT_TYPE struct comes out 64-bit aligned */
+ block->HeaderLength += 8 - (block->HeaderLength % 8);
+
+ return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static uint32 _reg_perfcount_perf_data_block_fixup(PERF_DATA_BLOCK *block, prs_struct *ps)
+{
+ int obj, cnt, inst, pad, i;
+ PERF_OBJECT_TYPE *object;
+ PERF_INSTANCE_DEFINITION *instance;
+ PERF_COUNTER_DEFINITION *counter;
+ PERF_COUNTER_BLOCK *counter_data;
+ char *temp = NULL, *src_addr, *dst_addr;
+
+ block->TotalByteLength = 0;
+ object = block->objects;
+ for(obj = 0; obj < block->NumObjectTypes; obj++)
+ {
+ object[obj].TotalByteLength = 0;
+ object[obj].DefinitionLength = 0;
+ instance = object[obj].instances;
+ counter = object[obj].counters;
+ for(cnt = 0; cnt < object[obj].NumCounters; cnt++)
+ {
+ object[obj].TotalByteLength += counter[cnt].ByteLength;
+ object[obj].DefinitionLength += counter[cnt].ByteLength;
+ }
+ if(object[obj].NumInstances != PERF_NO_INSTANCES)
+ {
+ for(inst = 0; inst < object[obj].NumInstances; inst++)
+ {
+ instance = &(object[obj].instances[inst]);
+ object[obj].TotalByteLength += instance->ByteLength;
+ counter_data = &(instance->counter_data);
+ counter = &(object[obj].counters[object[obj].NumCounters - 1]);
+ counter_data->ByteLength = counter->CounterOffset + counter->CounterSize + sizeof(counter_data->ByteLength);
+ temp = TALLOC_REALLOC_ARRAY(ps->mem_ctx,
+ temp,
+ char,
+ counter_data->ByteLength- sizeof(counter_data->ByteLength));
+ if (temp == NULL) {
+ return 0;
+ }
+ memset(temp, 0, counter_data->ByteLength - sizeof(counter_data->ByteLength));
+ src_addr = (char *)counter_data->data;
+ for(i = 0; i < object[obj].NumCounters; i++)
+ {
+ counter = &(object[obj].counters[i]);
+ dst_addr = temp + counter->CounterOffset - sizeof(counter_data->ByteLength);
+ memcpy(dst_addr, src_addr, counter->CounterSize);
+ src_addr += counter->CounterSize;
+ }
+ /* Make sure to be 64-bit aligned */
+ if((pad = (counter_data->ByteLength % 8)))
+ {
+ pad = 8 - pad;
+ }
+ counter_data->data = TALLOC_REALLOC_ARRAY(ps->mem_ctx,
+ counter_data->data,
+ uint8,
+ counter_data->ByteLength - sizeof(counter_data->ByteLength) + pad);
+ if (counter_data->data == NULL) {
+ return 0;
+ }
+ memset(counter_data->data, 0, counter_data->ByteLength - sizeof(counter_data->ByteLength) + pad);
+ memcpy(counter_data->data, temp, counter_data->ByteLength - sizeof(counter_data->ByteLength));
+ counter_data->ByteLength += pad;
+ object[obj].TotalByteLength += counter_data->ByteLength;
+ }
+ }
+ else
+ {
+ /* Need to be 64-bit aligned at the end of the counter_data block, so pad counter_data to a 64-bit boundary,
+ so that the next PERF_OBJECT_TYPE can start on a 64-bit alignment */
+ if((pad = (object[obj].counter_data.ByteLength % 8)))
+ {
+ pad = 8 - pad;
+ object[obj].counter_data.data = TALLOC_REALLOC_ARRAY(ps->mem_ctx,
+ object[obj].counter_data.data,
+ uint8,
+ object[obj].counter_data.ByteLength + pad);
+ memset((void *)(object[obj].counter_data.data + object[obj].counter_data.ByteLength), 0, pad);
+ object[obj].counter_data.ByteLength += pad;
+ }
+ object[obj].TotalByteLength += object[obj].counter_data.ByteLength;
+ }
+ object[obj].HeaderLength = sizeof(*object) - (sizeof(counter) + sizeof(instance) + sizeof(PERF_COUNTER_BLOCK));
+ object[obj].TotalByteLength += object[obj].HeaderLength;
+ object[obj].DefinitionLength += object[obj].HeaderLength;
+
+ block->TotalByteLength += object[obj].TotalByteLength;
+ }
+
+ return block->TotalByteLength;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+uint32 reg_perfcount_get_perf_data_block(uint32 base_index,
+ prs_struct *ps,
+ PERF_DATA_BLOCK *block,
+ const char *object_ids)
+{
+ uint32 buffer_size = 0;
+ const char *fname = counters_directory( NAMES_DB );
+ TDB_CONTEXT *names;
+ int retval = 0;
+
+ names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
+
+ if(names == NULL)
+ {
+ DEBUG(1, ("reg_perfcount_get_perf_data_block: unable to open [%s].\n", fname));
+ return 0;
+ }
+
+ if (!_reg_perfcount_init_data_block(block, ps, names)) {
+ DEBUG(0, ("_reg_perfcount_init_data_block failed\n"));
+ tdb_close(names);
+ return 0;
+ }
+
+ reg_perfcount_get_last_counter(base_index);
+
+ if(object_ids == NULL)
+ {
+ /* we're getting a request for "Global" here */
+ retval = _reg_perfcount_assemble_global(block, ps, base_index, names);
+ }
+ else
+ {
+ /* we're getting a request for a specific set of PERF_OBJECT_TYPES */
+ retval = _reg_perfcount_assemble_global(block, ps, base_index, names);
+ }
+ buffer_size = _reg_perfcount_perf_data_block_fixup(block, ps);
+
+ tdb_close(names);
+
+ if (retval == -1) {
+ return 0;
+ }
+
+ return buffer_size + block->HeaderLength;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool _reg_perfcount_marshall_perf_data_block(prs_struct *ps, PERF_DATA_BLOCK block, int depth)
+{
+ int i;
+ prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_data_block");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ for(i = 0; i < 4; i++)
+ {
+ if(!prs_uint16("Signature", ps, depth, &block.Signature[i]))
+ return False;
+ }
+ if(!prs_uint32("Little Endian", ps, depth, &block.LittleEndian))
+ return False;
+ if(!prs_uint32("Version", ps, depth, &block.Version))
+ return False;
+ if(!prs_uint32("Revision", ps, depth, &block.Revision))
+ return False;
+ if(!prs_uint32("TotalByteLength", ps, depth, &block.TotalByteLength))
+ return False;
+ if(!prs_uint32("HeaderLength", ps, depth, &block.HeaderLength))
+ return False;
+ if(!prs_uint32("NumObjectTypes", ps, depth, &block.NumObjectTypes))
+ return False;
+ if(!prs_uint32("DefaultObject", ps, depth, &block.DefaultObject))
+ return False;
+ if(!spoolss_io_system_time("SystemTime", ps, depth, &block.SystemTime))
+ return False;
+ if(!prs_uint32("Padding", ps, depth, &block.Padding))
+ return False;
+ if(!prs_align_uint64(ps))
+ return False;
+ if(!prs_uint64("PerfTime", ps, depth, &block.PerfTime))
+ return False;
+ if(!prs_uint64("PerfFreq", ps, depth, &block.PerfFreq))
+ return False;
+ if(!prs_uint64("PerfTime100nSec", ps, depth, &block.PerfTime100nSec))
+ return False;
+ if(!prs_uint32("SystemNameLength", ps, depth, &block.SystemNameLength))
+ return False;
+ if(!prs_uint32("SystemNameOffset", ps, depth, &block.SystemNameOffset))
+ return False;
+ /* hack to make sure we're 64-bit aligned at the end of this whole mess */
+ if(!prs_uint8s(False, "SystemName", ps, depth, block.data,
+ block.HeaderLength - block.SystemNameOffset))
+ return False;
+
+ return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool _reg_perfcount_marshall_perf_counters(prs_struct *ps,
+ PERF_OBJECT_TYPE object,
+ int depth)
+{
+ int cnt;
+ PERF_COUNTER_DEFINITION counter;
+
+ prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_counters");
+ depth++;
+
+ for(cnt = 0; cnt < object.NumCounters; cnt++)
+ {
+ counter = object.counters[cnt];
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("ByteLength", ps, depth, &counter.ByteLength))
+ return False;
+ if(!prs_uint32("CounterNameTitleIndex", ps, depth, &counter.CounterNameTitleIndex))
+ return False;
+ if(!prs_uint32("CounterNameTitlePointer", ps, depth, &counter.CounterNameTitlePointer))
+ return False;
+ if(!prs_uint32("CounterHelpTitleIndex", ps, depth, &counter.CounterHelpTitleIndex))
+ return False;
+ if(!prs_uint32("CounterHelpTitlePointer", ps, depth, &counter.CounterHelpTitlePointer))
+ return False;
+ if(!prs_uint32("DefaultScale", ps, depth, &counter.DefaultScale))
+ return False;
+ if(!prs_uint32("DetailLevel", ps, depth, &counter.DetailLevel))
+ return False;
+ if(!prs_uint32("CounterType", ps, depth, &counter.CounterType))
+ return False;
+ if(!prs_uint32("CounterSize", ps, depth, &counter.CounterSize))
+ return False;
+ if(!prs_uint32("CounterOffset", ps, depth, &counter.CounterOffset))
+ return False;
+ }
+
+ return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool _reg_perfcount_marshall_perf_counter_data(prs_struct *ps,
+ PERF_COUNTER_BLOCK counter_data,
+ int depth)
+{
+ prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_counter_data");
+ depth++;
+
+ if(!prs_align_uint64(ps))
+ return False;
+
+ if(!prs_uint32("ByteLength", ps, depth, &counter_data.ByteLength))
+ return False;
+ if(!prs_uint8s(False, "CounterData", ps, depth, counter_data.data, counter_data.ByteLength - sizeof(uint32)))
+ return False;
+ if(!prs_align_uint64(ps))
+ return False;
+
+ return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool _reg_perfcount_marshall_perf_instances(prs_struct *ps,
+ PERF_OBJECT_TYPE object,
+ int depth)
+{
+ PERF_INSTANCE_DEFINITION instance;
+ int inst;
+
+ prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_instances");
+ depth++;
+
+ for(inst = 0; inst < object.NumInstances; inst++)
+ {
+ instance = object.instances[inst];
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("ByteLength", ps, depth, &instance.ByteLength))
+ return False;
+ if(!prs_uint32("ParentObjectTitleIndex", ps, depth, &instance.ParentObjectTitleIndex))
+ return False;
+ if(!prs_uint32("ParentObjectTitlePointer", ps, depth, &instance.ParentObjectTitlePointer))
+ return False;
+ if(!prs_uint32("UniqueID", ps, depth, &instance.UniqueID))
+ return False;
+ if(!prs_uint32("NameOffset", ps, depth, &instance.NameOffset))
+ return False;
+ if(!prs_uint32("NameLength", ps, depth, &instance.NameLength))
+ return False;
+ if(!prs_uint8s(False, "InstanceName", ps, depth, instance.data,
+ instance.ByteLength - instance.NameOffset))
+ return False;
+ if(_reg_perfcount_marshall_perf_counter_data(ps, instance.counter_data, depth) == False)
+ return False;
+ }
+
+ return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool _reg_perfcount_marshall_perf_objects(prs_struct *ps, PERF_DATA_BLOCK block, int depth)
+{
+ int obj;
+
+ PERF_OBJECT_TYPE object;
+
+ prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_objects");
+ depth++;
+
+ for(obj = 0; obj < block.NumObjectTypes; obj++)
+ {
+ object = block.objects[obj];
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("TotalByteLength", ps, depth, &object.TotalByteLength))
+ return False;
+ if(!prs_uint32("DefinitionLength", ps, depth, &object.DefinitionLength))
+ return False;
+ if(!prs_uint32("HeaderLength", ps, depth, &object.HeaderLength))
+ return False;
+ if(!prs_uint32("ObjectNameTitleIndex", ps, depth, &object.ObjectNameTitleIndex))
+ return False;
+ if(!prs_uint32("ObjectNameTitlePointer", ps, depth, &object.ObjectNameTitlePointer))
+ return False;
+ if(!prs_uint32("ObjectHelpTitleIndex", ps, depth, &object.ObjectHelpTitleIndex))
+ return False;
+ if(!prs_uint32("ObjectHelpTitlePointer", ps, depth, &object.ObjectHelpTitlePointer))
+ return False;
+ if(!prs_uint32("DetailLevel", ps, depth, &object.DetailLevel))
+ return False;
+ if(!prs_uint32("NumCounters", ps, depth, &object.NumCounters))
+ return False;
+ if(!prs_uint32("DefaultCounter", ps, depth, &object.DefaultCounter))
+ return False;
+ if(!prs_uint32("NumInstances", ps, depth, &object.NumInstances))
+ return False;
+ if(!prs_uint32("CodePage", ps, depth, &object.CodePage))
+ return False;
+ if(!prs_align_uint64(ps))
+ return False;
+ if(!prs_uint64("PerfTime", ps, depth, &object.PerfTime))
+ return False;
+ if(!prs_uint64("PerfFreq", ps, depth, &object.PerfFreq))
+ return False;
+
+ /* Now do the counters */
+ /* If no instances, encode counter_data */
+ /* If instances, encode instace plus counter data for each instance */
+ if(_reg_perfcount_marshall_perf_counters(ps, object, depth) == False)
+ return False;
+ if(object.NumInstances == PERF_NO_INSTANCES)
+ {
+ if(_reg_perfcount_marshall_perf_counter_data(ps, object.counter_data, depth) == False)
+ return False;
+ }
+ else
+ {
+ if(_reg_perfcount_marshall_perf_instances(ps, object, depth) == False)
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool _reg_perfcount_marshall_hkpd(prs_struct *ps, PERF_DATA_BLOCK block)
+{
+ int depth = 0;
+ if(_reg_perfcount_marshall_perf_data_block(ps, block, depth) == True)
+ {
+ if(_reg_perfcount_marshall_perf_objects(ps, block, depth) == True)
+ return True;
+ }
+ return False;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+WERROR reg_perfcount_get_hkpd(prs_struct *ps, uint32 max_buf_size, uint32 *outbuf_len, const char *object_ids)
+{
+ /*
+ * For a detailed description of the layout of this structure,
+ * see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/perfmon/base/performance_data_format.asp
+ *
+ * By 2006-11-23 this link did not work anymore, I found something
+ * promising under
+ * http://msdn2.microsoft.com/en-us/library/aa373105.aspx -- vl
+ */
+ PERF_DATA_BLOCK block;
+ uint32 buffer_size, base_index;
+
+ buffer_size = 0;
+ base_index = reg_perfcount_get_base_index();
+ ZERO_STRUCT(block);
+
+ buffer_size = reg_perfcount_get_perf_data_block(base_index, ps, &block, object_ids);
+
+ if(buffer_size < max_buf_size)
+ {
+ *outbuf_len = buffer_size;
+ if(_reg_perfcount_marshall_hkpd(ps, block) == True)
+ return WERR_OK;
+ else
+ return WERR_NOMEM;
+ }
+ else
+ {
+ *outbuf_len = max_buf_size;
+ _reg_perfcount_marshall_perf_data_block(ps, block, 0);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+}
diff --git a/source3/registry/reg_util.c b/source3/registry/reg_util.c
new file mode 100644
index 0000000000..714a39f307
--- /dev/null
+++ b/source3/registry/reg_util.c
@@ -0,0 +1,267 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer (utility functions)
+ * Copyright (C) Gerald Carter 2002-2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Implementation of registry frontend view functions. */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+/***********************************************************************
+ Utility function for splitting the base path of a registry path off
+ by setting base and new_path to the apprapriate offsets withing the
+ path.
+
+ WARNING!! Does modify the original string!
+ ***********************************************************************/
+
+bool reg_split_path(char *path, char **base, char **new_path)
+{
+ char *p;
+
+ *new_path = *base = NULL;
+
+ if (!path) {
+ return false;
+ }
+ *base = path;
+
+ p = strchr(path, '\\');
+
+ if ( p ) {
+ *p = '\0';
+ *new_path = p+1;
+ }
+
+ return true;
+}
+
+/***********************************************************************
+ Utility function for splitting the base path of a registry path off
+ by setting base and new_path to the appropriate offsets withing the
+ path.
+
+ WARNING!! Does modify the original string!
+ ***********************************************************************/
+
+bool reg_split_key(char *path, char **base, char **key)
+{
+ char *p;
+
+ *key = *base = NULL;
+
+ if (!path) {
+ return false;
+ }
+
+ *base = path;
+
+ p = strrchr(path, '\\');
+
+ if (p) {
+ *p = '\0';
+ *key = p+1;
+ }
+
+ return true;
+}
+
+/**
+ * The full path to the registry key is used as database key
+ * after the \'s are converted to /'s.
+ * Leading and trailing '/' and '\' characters are stripped.
+ * Key string is also normalized to UPPER case.
+ */
+
+char *normalize_reg_path(TALLOC_CTX *ctx, const char *keyname )
+{
+ char *p;
+ char *nkeyname;
+
+ /* skip leading '/' and '\' chars */
+ p = (char *)keyname;
+ while ((*p == '/') || (*p == '\\')) {
+ p++;
+ }
+
+ nkeyname = talloc_string_sub(ctx, p, "\\", "/");
+ if (nkeyname == NULL) {
+ return NULL;
+ }
+
+ /* strip trailing '/' chars */
+ p = strrchr(nkeyname, '/');
+ while ((p != NULL) && (p[1] == '\0')) {
+ *p = '\0';
+ p = strrchr(nkeyname, '/');
+ }
+
+ strupper_m(nkeyname);
+
+ return nkeyname;
+}
+
+/**
+ * normalize ther registry path in place.
+ */
+void normalize_dbkey(char *key)
+{
+ size_t len = strlen(key);
+ string_sub(key, "\\", "/", len+1);
+ strupper_m(key);
+}
+
+/**********************************************************************
+ move to next non-delimter character
+*********************************************************************/
+
+char *reg_remaining_path(TALLOC_CTX *ctx, const char *key)
+{
+ char *new_path = NULL;
+ char *p = NULL;
+
+ if (!key || !*key) {
+ return NULL;
+ }
+
+ new_path = talloc_strdup(ctx, key);
+ if (!new_path) {
+ return NULL;
+ }
+ /* normalize_reg_path( new_path ); */
+ if (!(p = strchr(new_path, '\\')) ) {
+ if (!(p = strchr( new_path, '/'))) {
+ p = new_path;
+ } else {
+ p++;
+ }
+ } else {
+ p++;
+ }
+
+ return p;
+}
+
+/**********************************************************************
+*********************************************************************/
+
+int regval_convert_multi_sz( uint16 *multi_string, size_t byte_len, char ***values )
+{
+ char **sz;
+ int i;
+ int num_strings = 0;
+ fstring buffer;
+ uint16 *wp;
+ size_t multi_len = byte_len / 2;
+
+ if ( !multi_string || !values )
+ return 0;
+
+ *values = NULL;
+
+ /* just count the NULLs */
+
+ for ( i=0; (i<multi_len-1) && !(multi_string[i]==0x0 && multi_string[i+1]==0x0); i++ ) {
+ /* peek ahead */
+ if ( multi_string[i+1] == 0x0 )
+ num_strings++;
+ }
+
+ if ( num_strings == 0 )
+ return 0;
+
+ if ( !(sz = TALLOC_ARRAY( NULL, char*, num_strings+1 )) ) {
+ DEBUG(0,("reg_convert_multi_sz: talloc() failed!\n"));
+ return -1;
+ }
+
+ wp = multi_string;
+
+ for ( i=0; i<num_strings; i++ ) {
+ rpcstr_pull( buffer, wp, sizeof(buffer), -1, STR_TERMINATE );
+ sz[i] = talloc_strdup( sz, buffer );
+
+ /* skip to the next string NULL and then one more */
+ while ( *wp )
+ wp++;
+ wp++;
+ }
+
+ /* tag the array off with an empty string */
+ sz[i] = '\0';
+
+ *values = sz;
+
+ return num_strings;
+}
+
+/**********************************************************************
+ Returns number of bytes, not number of unicode characters
+*********************************************************************/
+
+size_t regval_build_multi_sz( char **values, uint16 **buffer )
+{
+ int i;
+ size_t buf_size = 0;
+ uint16 *buf, *b;
+ UNISTR2 sz;
+
+ if ( !values || !buffer )
+ return 0;
+
+ /* go ahead and alloc some space */
+
+ if ( !(buf = TALLOC_ARRAY( NULL, uint16, 2 )) ) {
+ DEBUG(0,("regval_build_multi_sz: talloc() failed!\n"));
+ return 0;
+ }
+
+ for ( i=0; values[i]; i++ ) {
+ ZERO_STRUCT( sz );
+ /* DEBUG(0,("regval_build_multi_sz: building [%s]\n",values[i])); */
+ init_unistr2( &sz, values[i], UNI_STR_TERMINATE );
+
+ /* Alloc some more memory. Always add one one to account for the
+ double NULL termination */
+
+ b = TALLOC_REALLOC_ARRAY( NULL, buf, uint16, buf_size+sz.uni_str_len+1 );
+ if ( !b ) {
+ DEBUG(0,("regval_build_multi_sz: talloc() reallocation error!\n"));
+ TALLOC_FREE( buffer );
+ return 0;
+ }
+ buf = b;
+
+ /* copy the unistring2 buffer and increment the size */
+ /* dump_data(1,sz.buffer,sz.uni_str_len*2); */
+ memcpy( buf+buf_size, sz.buffer, sz.uni_str_len*2 );
+ buf_size += sz.uni_str_len;
+
+ /* cleanup rather than leaving memory hanging around */
+ TALLOC_FREE( sz.buffer );
+ }
+
+ buf[buf_size++] = 0x0;
+
+ *buffer = buf;
+
+ /* return number of bytes */
+ return buf_size*2;
+}
diff --git a/source3/registry/reg_util_legacy.c b/source3/registry/reg_util_legacy.c
new file mode 100644
index 0000000000..3e68025ae9
--- /dev/null
+++ b/source3/registry/reg_util_legacy.c
@@ -0,0 +1,47 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Implementation of registry frontend view functions. */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+/**
+ * legacy open key function that should be replaced by uses of
+ * reg_open_path
+ */
+WERROR regkey_open_internal( TALLOC_CTX *ctx, REGISTRY_KEY **regkey,
+ const char *path,
+ const struct nt_user_token *token,
+ uint32 access_desired )
+{
+ struct registry_key *key;
+ WERROR err;
+
+ err = reg_open_path(NULL, path, access_desired, token, &key);
+ if (!W_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ *regkey = talloc_move(ctx, &key->key);
+ TALLOC_FREE(key);
+ return WERR_OK;
+}
diff --git a/source3/registry/regfio.c b/source3/registry/regfio.c
new file mode 100644
index 0000000000..b6e822955c
--- /dev/null
+++ b/source3/registry/regfio.c
@@ -0,0 +1,1915 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Windows NT registry I/O library
+ * Copyright (c) Gerald (Jerry) Carter 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "regfio.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+/*******************************************************************
+ *
+ * TODO : Right now this code basically ignores classnames.
+ *
+ ******************************************************************/
+
+
+/*******************************************************************
+*******************************************************************/
+
+static int write_block( REGF_FILE *file, prs_struct *ps, uint32 offset )
+{
+ int bytes_written, returned;
+ char *buffer = prs_data_p( ps );
+ uint32 buffer_size = prs_data_size( ps );
+ SMB_STRUCT_STAT sbuf;
+
+ if ( file->fd == -1 )
+ return -1;
+
+ /* check for end of file */
+
+ if ( sys_fstat( file->fd, &sbuf ) ) {
+ DEBUG(0,("write_block: stat() failed! (%s)\n", strerror(errno)));
+ return -1;
+ }
+
+ if ( lseek( file->fd, offset, SEEK_SET ) == -1 ) {
+ DEBUG(0,("write_block: lseek() failed! (%s)\n", strerror(errno) ));
+ return -1;
+ }
+
+ bytes_written = returned = 0;
+ while ( bytes_written < buffer_size ) {
+ if ( (returned = write( file->fd, buffer+bytes_written, buffer_size-bytes_written )) == -1 ) {
+ DEBUG(0,("write_block: write() failed! (%s)\n", strerror(errno) ));
+ return False;
+ }
+
+ bytes_written += returned;
+ }
+
+ return bytes_written;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset, uint32 block_size )
+{
+ int bytes_read, returned;
+ char *buffer;
+ SMB_STRUCT_STAT sbuf;
+
+ /* check for end of file */
+
+ if ( sys_fstat( file->fd, &sbuf ) ) {
+ DEBUG(0,("read_block: stat() failed! (%s)\n", strerror(errno)));
+ return -1;
+ }
+
+ if ( (size_t)file_offset >= sbuf.st_size )
+ return -1;
+
+ /* if block_size == 0, we are parsing HBIN records and need
+ to read some of the header to get the block_size from there */
+
+ if ( block_size == 0 ) {
+ char hdr[0x20];
+
+ if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) {
+ DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) ));
+ return -1;
+ }
+
+ returned = read( file->fd, hdr, 0x20 );
+ if ( (returned == -1) || (returned < 0x20) ) {
+ DEBUG(0,("read_block: failed to read in HBIN header. Is the file corrupt?\n"));
+ return -1;
+ }
+
+ /* make sure this is an hbin header */
+
+ if ( strncmp( hdr, "hbin", HBIN_HDR_SIZE ) != 0 ) {
+ DEBUG(0,("read_block: invalid block header!\n"));
+ return -1;
+ }
+
+ block_size = IVAL( hdr, 0x08 );
+ }
+
+ DEBUG(10,("read_block: block_size == 0x%x\n", block_size ));
+
+ /* set the offset, initialize the buffer, and read the block from disk */
+
+ if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) {
+ DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) ));
+ return -1;
+ }
+
+ if (!prs_init( ps, block_size, file->mem_ctx, UNMARSHALL )) {
+ DEBUG(0,("read_block: prs_init() failed! (%s)\n", strerror(errno) ));
+ return -1;
+ }
+ buffer = prs_data_p( ps );
+ bytes_read = returned = 0;
+
+ while ( bytes_read < block_size ) {
+ if ( (returned = read( file->fd, buffer+bytes_read, block_size-bytes_read )) == -1 ) {
+ DEBUG(0,("read_block: read() failed (%s)\n", strerror(errno) ));
+ return False;
+ }
+ if ( (returned == 0) && (bytes_read < block_size) ) {
+ DEBUG(0,("read_block: not a vald registry file ?\n" ));
+ return False;
+ }
+
+ bytes_read += returned;
+ }
+
+ return bytes_read;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool write_hbin_block( REGF_FILE *file, REGF_HBIN *hbin )
+{
+ if ( !hbin->dirty )
+ return True;
+
+ /* write free space record if any is available */
+
+ if ( hbin->free_off != REGF_OFFSET_NONE ) {
+ uint32 header = 0xffffffff;
+
+ if ( !prs_set_offset( &hbin->ps, hbin->free_off-sizeof(uint32) ) )
+ return False;
+ if ( !prs_uint32( "free_size", &hbin->ps, 0, &hbin->free_size ) )
+ return False;
+ if ( !prs_uint32( "free_header", &hbin->ps, 0, &header ) )
+ return False;
+ }
+
+ hbin->dirty = (write_block( file, &hbin->ps, hbin->file_off ) != -1);
+
+ return hbin->dirty;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool hbin_block_close( REGF_FILE *file, REGF_HBIN *hbin )
+{
+ REGF_HBIN *p;
+
+ /* remove the block from the open list and flush it to disk */
+
+ for ( p=file->block_list; p && p!=hbin; p=p->next )
+ ;;
+
+ if ( p == hbin ) {
+ DLIST_REMOVE( file->block_list, hbin );
+ }
+ else
+ DEBUG(0,("hbin_block_close: block not in open list!\n"));
+
+ if ( !write_hbin_block( file, hbin ) )
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool prs_regf_block( const char *desc, prs_struct *ps, int depth, REGF_FILE *file )
+{
+ prs_debug(ps, depth, desc, "prs_regf_block");
+ depth++;
+
+ if ( !prs_uint8s( True, "header", ps, depth, (uint8*)file->header, sizeof( file->header )) )
+ return False;
+
+ /* yes, these values are always identical so store them only once */
+
+ if ( !prs_uint32( "unknown1", ps, depth, &file->unknown1 ))
+ return False;
+ if ( !prs_uint32( "unknown1 (again)", ps, depth, &file->unknown1 ))
+ return False;
+
+ /* get the modtime */
+
+ if ( !prs_set_offset( ps, 0x0c ) )
+ return False;
+ if ( !smb_io_time( "modtime", &file->mtime, ps, depth ) )
+ return False;
+
+ /* constants */
+
+ if ( !prs_uint32( "unknown2", ps, depth, &file->unknown2 ))
+ return False;
+ if ( !prs_uint32( "unknown3", ps, depth, &file->unknown3 ))
+ return False;
+ if ( !prs_uint32( "unknown4", ps, depth, &file->unknown4 ))
+ return False;
+ if ( !prs_uint32( "unknown5", ps, depth, &file->unknown5 ))
+ return False;
+
+ /* get file offsets */
+
+ if ( !prs_set_offset( ps, 0x24 ) )
+ return False;
+ if ( !prs_uint32( "data_offset", ps, depth, &file->data_offset ))
+ return False;
+ if ( !prs_uint32( "last_block", ps, depth, &file->last_block ))
+ return False;
+
+ /* one more constant */
+
+ if ( !prs_uint32( "unknown6", ps, depth, &file->unknown6 ))
+ return False;
+
+ /* get the checksum */
+
+ if ( !prs_set_offset( ps, 0x01fc ) )
+ return False;
+ if ( !prs_uint32( "checksum", ps, depth, &file->checksum ))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool prs_hbin_block( const char *desc, prs_struct *ps, int depth, REGF_HBIN *hbin )
+{
+ uint32 block_size2;
+
+ prs_debug(ps, depth, desc, "prs_regf_block");
+ depth++;
+
+ if ( !prs_uint8s( True, "header", ps, depth, (uint8*)hbin->header, sizeof( hbin->header )) )
+ return False;
+
+ if ( !prs_uint32( "first_hbin_off", ps, depth, &hbin->first_hbin_off ))
+ return False;
+
+ /* The dosreg.cpp comments say that the block size is at 0x1c.
+ According to a WINXP NTUSER.dat file, this is wrong. The block_size
+ is at 0x08 */
+
+ if ( !prs_uint32( "block_size", ps, depth, &hbin->block_size ))
+ return False;
+
+ block_size2 = hbin->block_size;
+ prs_set_offset( ps, 0x1c );
+ if ( !prs_uint32( "block_size2", ps, depth, &block_size2 ))
+ return False;
+
+ if ( MARSHALLING(ps) )
+ hbin->dirty = True;
+
+
+ return True;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool prs_nk_rec( const char *desc, prs_struct *ps, int depth, REGF_NK_REC *nk )
+{
+ uint16 class_length, name_length;
+ uint32 start;
+ uint32 data_size, start_off, end_off;
+ uint32 unknown_off = REGF_OFFSET_NONE;
+
+ nk->hbin_off = prs_offset( ps );
+ start = nk->hbin_off;
+
+ prs_debug(ps, depth, desc, "prs_nk_rec");
+ depth++;
+
+ /* back up and get the data_size */
+
+ if ( !prs_set_offset( ps, prs_offset(ps)-sizeof(uint32)) )
+ return False;
+ start_off = prs_offset( ps );
+ if ( !prs_uint32( "rec_size", ps, depth, &nk->rec_size ))
+ return False;
+
+ if ( !prs_uint8s( True, "header", ps, depth, (uint8*)nk->header, sizeof( nk->header )) )
+ return False;
+
+ if ( !prs_uint16( "key_type", ps, depth, &nk->key_type ))
+ return False;
+ if ( !smb_io_time( "mtime", &nk->mtime, ps, depth ))
+ return False;
+
+ if ( !prs_set_offset( ps, start+0x0010 ) )
+ return False;
+ if ( !prs_uint32( "parent_off", ps, depth, &nk->parent_off ))
+ return False;
+ if ( !prs_uint32( "num_subkeys", ps, depth, &nk->num_subkeys ))
+ return False;
+
+ if ( !prs_set_offset( ps, start+0x001c ) )
+ return False;
+ if ( !prs_uint32( "subkeys_off", ps, depth, &nk->subkeys_off ))
+ return False;
+ if ( !prs_uint32( "unknown_off", ps, depth, &unknown_off) )
+ return False;
+
+ if ( !prs_set_offset( ps, start+0x0024 ) )
+ return False;
+ if ( !prs_uint32( "num_values", ps, depth, &nk->num_values ))
+ return False;
+ if ( !prs_uint32( "values_off", ps, depth, &nk->values_off ))
+ return False;
+ if ( !prs_uint32( "sk_off", ps, depth, &nk->sk_off ))
+ return False;
+ if ( !prs_uint32( "classname_off", ps, depth, &nk->classname_off ))
+ return False;
+
+ if ( !prs_uint32( "max_bytes_subkeyname", ps, depth, &nk->max_bytes_subkeyname))
+ return False;
+ if ( !prs_uint32( "max_bytes_subkeyclassname", ps, depth, &nk->max_bytes_subkeyclassname))
+ return False;
+ if ( !prs_uint32( "max_bytes_valuename", ps, depth, &nk->max_bytes_valuename))
+ return False;
+ if ( !prs_uint32( "max_bytes_value", ps, depth, &nk->max_bytes_value))
+ return False;
+ if ( !prs_uint32( "unknown index", ps, depth, &nk->unk_index))
+ return False;
+
+ name_length = nk->keyname ? strlen(nk->keyname) : 0 ;
+ class_length = nk->classname ? strlen(nk->classname) : 0 ;
+ if ( !prs_uint16( "name_length", ps, depth, &name_length ))
+ return False;
+ if ( !prs_uint16( "class_length", ps, depth, &class_length ))
+ return False;
+
+ if ( class_length ) {
+ ;;
+ }
+
+ if ( name_length ) {
+ if ( UNMARSHALLING(ps) ) {
+ if ( !(nk->keyname = PRS_ALLOC_MEM( ps, char, name_length+1 )) )
+ return False;
+ }
+
+ if ( !prs_uint8s( True, "name", ps, depth, (uint8*)nk->keyname, name_length) )
+ return False;
+
+ if ( UNMARSHALLING(ps) )
+ nk->keyname[name_length] = '\0';
+ }
+
+ end_off = prs_offset( ps );
+
+ /* data_size must be divisible by 8 and large enough to hold the original record */
+
+ data_size = ((start_off - end_off) & 0xfffffff8 );
+ if ( data_size > nk->rec_size )
+ DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, nk->rec_size));
+
+ if ( MARSHALLING(ps) )
+ nk->hbin->dirty = True;
+
+ return True;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static uint32 regf_block_checksum( prs_struct *ps )
+{
+ char *buffer = prs_data_p( ps );
+ uint32 checksum, x;
+ int i;
+
+ /* XOR of all bytes 0x0000 - 0x01FB */
+
+ checksum = x = 0;
+
+ for ( i=0; i<0x01FB; i+=4 ) {
+ x = IVAL(buffer, i );
+ checksum ^= x;
+ }
+
+ return checksum;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool read_regf_block( REGF_FILE *file )
+{
+ prs_struct ps;
+ uint32 checksum;
+
+ /* grab the first block from the file */
+
+ if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) == -1 )
+ return False;
+
+ /* parse the block and verify the checksum */
+
+ if ( !prs_regf_block( "regf_header", &ps, 0, file ) )
+ return False;
+
+ checksum = regf_block_checksum( &ps );
+
+ prs_mem_free( &ps );
+
+ if ( file->checksum != checksum ) {
+ DEBUG(0,("read_regf_block: invalid checksum\n" ));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset )
+{
+ REGF_HBIN *hbin;
+ uint32 record_size, curr_off, block_size, header;
+
+ if ( !(hbin = TALLOC_ZERO_P(file->mem_ctx, REGF_HBIN)) )
+ return NULL;
+ hbin->file_off = offset;
+ hbin->free_off = -1;
+
+ if ( read_block( file, &hbin->ps, offset, 0 ) == -1 )
+ return NULL;
+
+ if ( !prs_hbin_block( "hbin", &hbin->ps, 0, hbin ) )
+ return NULL;
+
+ /* this should be the same thing as hbin->block_size but just in case */
+
+ block_size = prs_data_size( &hbin->ps );
+
+ /* Find the available free space offset. Always at the end,
+ so walk the record list and stop when you get to the end.
+ The end is defined by a record header of 0xffffffff. The
+ previous 4 bytes contains the amount of free space remaining
+ in the hbin block. */
+
+ /* remember that the record_size is in the 4 bytes preceeding the record itself */
+
+ if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE-sizeof(uint32) ) )
+ return False;
+
+ record_size = 0;
+ header = 0;
+ curr_off = prs_offset( &hbin->ps );
+ while ( header != 0xffffffff ) {
+ /* not done yet so reset the current offset to the
+ next record_size field */
+
+ curr_off = curr_off+record_size;
+
+ /* for some reason the record_size of the last record in
+ an hbin block can extend past the end of the block
+ even though the record fits within the remaining
+ space....aaarrrgggghhhhhh */
+
+ if ( curr_off >= block_size ) {
+ record_size = -1;
+ curr_off = -1;
+ break;
+ }
+
+ if ( !prs_set_offset( &hbin->ps, curr_off) )
+ return False;
+
+ if ( !prs_uint32( "rec_size", &hbin->ps, 0, &record_size ) )
+ return False;
+ if ( !prs_uint32( "header", &hbin->ps, 0, &header ) )
+ return False;
+
+ SMB_ASSERT( record_size != 0 );
+
+ if ( record_size & 0x80000000 ) {
+ /* absolute_value(record_size) */
+ record_size = (record_size ^ 0xffffffff) + 1;
+ }
+ }
+
+ /* save the free space offset */
+
+ if ( header == 0xffffffff ) {
+
+ /* account for the fact that the curr_off is 4 bytes behind the actual
+ record header */
+
+ hbin->free_off = curr_off + sizeof(uint32);
+ hbin->free_size = record_size;
+ }
+
+ DEBUG(10,("read_hbin_block: free space offset == 0x%x\n", hbin->free_off));
+
+ if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE ) )
+ return False;
+
+ return hbin;
+}
+
+/*******************************************************************
+ Input a random offset and receive the corresponding HBIN
+ block for it
+*******************************************************************/
+
+static bool hbin_contains_offset( REGF_HBIN *hbin, uint32 offset )
+{
+ if ( !hbin )
+ return False;
+
+ if ( (offset > hbin->first_hbin_off) && (offset < (hbin->first_hbin_off+hbin->block_size)) )
+ return True;
+
+ return False;
+}
+
+/*******************************************************************
+ Input a random offset and receive the corresponding HBIN
+ block for it
+*******************************************************************/
+
+static REGF_HBIN* lookup_hbin_block( REGF_FILE *file, uint32 offset )
+{
+ REGF_HBIN *hbin = NULL;
+ uint32 block_off;
+
+ /* start with the open list */
+
+ for ( hbin=file->block_list; hbin; hbin=hbin->next ) {
+ DEBUG(10,("lookup_hbin_block: address = 0x%x [0x%lx]\n", hbin->file_off, (unsigned long)hbin ));
+ if ( hbin_contains_offset( hbin, offset ) )
+ return hbin;
+ }
+
+ if ( !hbin ) {
+ /* start at the beginning */
+
+ block_off = REGF_BLOCKSIZE;
+ do {
+ /* cleanup before the next round */
+ if ( hbin )
+ prs_mem_free( &hbin->ps );
+
+ hbin = read_hbin_block( file, block_off );
+
+ if ( hbin )
+ block_off = hbin->file_off + hbin->block_size;
+
+ } while ( hbin && !hbin_contains_offset( hbin, offset ) );
+ }
+
+ if ( hbin )
+ DLIST_ADD( file->block_list, hbin );
+
+ return hbin;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH_REC *hash )
+{
+ prs_debug(ps, depth, desc, "prs_hash_rec");
+ depth++;
+
+ if ( !prs_uint32( "nk_off", ps, depth, &hash->nk_off ))
+ return False;
+ if ( !prs_uint8s( True, "keycheck", ps, depth, hash->keycheck, sizeof( hash->keycheck )) )
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool hbin_prs_lf_records( const char *desc, REGF_HBIN *hbin, int depth, REGF_NK_REC *nk )
+{
+ int i;
+ REGF_LF_REC *lf = &nk->subkeys;
+ uint32 data_size, start_off, end_off;
+
+ prs_debug(&hbin->ps, depth, desc, "prs_lf_records");
+ depth++;
+
+ /* check if we have anything to do first */
+
+ if ( nk->num_subkeys == 0 )
+ return True;
+
+ /* move to the LF record */
+
+ if ( !prs_set_offset( &hbin->ps, nk->subkeys_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
+ return False;
+
+ /* backup and get the data_size */
+
+ if ( !prs_set_offset( &hbin->ps, prs_offset(&hbin->ps)-sizeof(uint32)) )
+ return False;
+ start_off = prs_offset( &hbin->ps );
+ if ( !prs_uint32( "rec_size", &hbin->ps, depth, &lf->rec_size ))
+ return False;
+
+ if ( !prs_uint8s( True, "header", &hbin->ps, depth, (uint8*)lf->header, sizeof( lf->header )) )
+ return False;
+
+ if ( !prs_uint16( "num_keys", &hbin->ps, depth, &lf->num_keys))
+ return False;
+
+ if ( UNMARSHALLING(&hbin->ps) ) {
+ if (lf->num_keys) {
+ if ( !(lf->hashes = PRS_ALLOC_MEM( &hbin->ps, REGF_HASH_REC, lf->num_keys )) )
+ return False;
+ } else {
+ lf->hashes = NULL;
+ }
+ }
+
+ for ( i=0; i<lf->num_keys; i++ ) {
+ if ( !prs_hash_rec( "hash_rec", &hbin->ps, depth, &lf->hashes[i] ) )
+ return False;
+ }
+
+ end_off = prs_offset( &hbin->ps );
+
+ /* data_size must be divisible by 8 and large enough to hold the original record */
+
+ data_size = ((start_off - end_off) & 0xfffffff8 );
+ if ( data_size > lf->rec_size )
+ DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, lf->rec_size));
+
+ if ( MARSHALLING(&hbin->ps) )
+ hbin->dirty = True;
+
+ return True;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk )
+{
+ prs_struct *ps = &hbin->ps;
+ uint16 tag = 0xFFFF;
+ uint32 data_size, start_off, end_off;
+
+
+ prs_debug(ps, depth, desc, "hbin_prs_sk_rec");
+ depth++;
+
+ if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
+ return False;
+
+ /* backup and get the data_size */
+
+ if ( !prs_set_offset( &hbin->ps, prs_offset(&hbin->ps)-sizeof(uint32)) )
+ return False;
+ start_off = prs_offset( &hbin->ps );
+ if ( !prs_uint32( "rec_size", &hbin->ps, depth, &sk->rec_size ))
+ return False;
+
+ if ( !prs_uint8s( True, "header", ps, depth, (uint8*)sk->header, sizeof( sk->header )) )
+ return False;
+ if ( !prs_uint16( "tag", ps, depth, &tag))
+ return False;
+
+ if ( !prs_uint32( "prev_sk_off", ps, depth, &sk->prev_sk_off))
+ return False;
+ if ( !prs_uint32( "next_sk_off", ps, depth, &sk->next_sk_off))
+ return False;
+ if ( !prs_uint32( "ref_count", ps, depth, &sk->ref_count))
+ return False;
+ if ( !prs_uint32( "size", ps, depth, &sk->size))
+ return False;
+
+ if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth ))
+ return False;
+
+ end_off = prs_offset( &hbin->ps );
+
+ /* data_size must be divisible by 8 and large enough to hold the original record */
+
+ data_size = ((start_off - end_off) & 0xfffffff8 );
+ if ( data_size > sk->rec_size )
+ DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->rec_size));
+
+ if ( MARSHALLING(&hbin->ps) )
+ hbin->dirty = True;
+
+ return True;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_VK_REC *vk, REGF_FILE *file )
+{
+ uint32 offset;
+ uint16 name_length;
+ prs_struct *ps = &hbin->ps;
+ uint32 data_size, start_off, end_off;
+
+ prs_debug(ps, depth, desc, "prs_vk_rec");
+ depth++;
+
+ /* backup and get the data_size */
+
+ if ( !prs_set_offset( &hbin->ps, prs_offset(&hbin->ps)-sizeof(uint32)) )
+ return False;
+ start_off = prs_offset( &hbin->ps );
+ if ( !prs_uint32( "rec_size", &hbin->ps, depth, &vk->rec_size ))
+ return False;
+
+ if ( !prs_uint8s( True, "header", ps, depth, (uint8*)vk->header, sizeof( vk->header )) )
+ return False;
+
+ if ( MARSHALLING(&hbin->ps) )
+ name_length = strlen(vk->valuename);
+
+ if ( !prs_uint16( "name_length", ps, depth, &name_length ))
+ return False;
+ if ( !prs_uint32( "data_size", ps, depth, &vk->data_size ))
+ return False;
+ if ( !prs_uint32( "data_off", ps, depth, &vk->data_off ))
+ return False;
+ if ( !prs_uint32( "type", ps, depth, &vk->type))
+ return False;
+ if ( !prs_uint16( "flag", ps, depth, &vk->flag))
+ return False;
+
+ offset = prs_offset( ps );
+ offset += 2; /* skip 2 bytes */
+ prs_set_offset( ps, offset );
+
+ /* get the name */
+
+ if ( vk->flag&VK_FLAG_NAME_PRESENT ) {
+
+ if ( UNMARSHALLING(&hbin->ps) ) {
+ if ( !(vk->valuename = PRS_ALLOC_MEM( ps, char, name_length+1 )))
+ return False;
+ }
+ if ( !prs_uint8s( True, "name", ps, depth, (uint8*)vk->valuename, name_length ) )
+ return False;
+ }
+
+ end_off = prs_offset( &hbin->ps );
+
+ /* get the data if necessary */
+
+ if ( vk->data_size != 0 ) {
+ bool charmode = False;
+
+ if ( (vk->type == REG_SZ) || (vk->type == REG_MULTI_SZ) )
+ charmode = True;
+
+ /* the data is stored in the offset if the size <= 4 */
+
+ if ( !(vk->data_size & VK_DATA_IN_OFFSET) ) {
+ REGF_HBIN *hblock = hbin;
+ uint32 data_rec_size;
+
+ if ( UNMARSHALLING(&hbin->ps) ) {
+ if ( !(vk->data = PRS_ALLOC_MEM( ps, uint8, vk->data_size) ) )
+ return False;
+ }
+
+ /* this data can be in another hbin */
+ if ( !hbin_contains_offset( hbin, vk->data_off ) ) {
+ if ( !(hblock = lookup_hbin_block( file, vk->data_off )) )
+ return False;
+ }
+ if ( !(prs_set_offset( &hblock->ps, (vk->data_off+HBIN_HDR_SIZE-hblock->first_hbin_off)-sizeof(uint32) )) )
+ return False;
+
+ if ( MARSHALLING(&hblock->ps) ) {
+ data_rec_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8;
+ data_rec_size = ( data_rec_size - 1 ) ^ 0xFFFFFFFF;
+ }
+ if ( !prs_uint32( "data_rec_size", &hblock->ps, depth, &data_rec_size ))
+ return False;
+ if ( !prs_uint8s( charmode, "data", &hblock->ps, depth, vk->data, vk->data_size) )
+ return False;
+
+ if ( MARSHALLING(&hblock->ps) )
+ hblock->dirty = True;
+ }
+ else {
+ if ( !(vk->data = PRS_ALLOC_MEM( ps, uint8, 4 ) ) )
+ return False;
+ SIVAL( vk->data, 0, vk->data_off );
+ }
+
+ }
+
+ /* data_size must be divisible by 8 and large enough to hold the original record */
+
+ data_size = ((start_off - end_off ) & 0xfffffff8 );
+ if ( data_size != vk->rec_size )
+ DEBUG(10,("prs_vk_rec: data_size check failed (0x%x < 0x%x)\n", data_size, vk->rec_size));
+
+ if ( MARSHALLING(&hbin->ps) )
+ hbin->dirty = True;
+
+ return True;
+}
+
+/*******************************************************************
+ read a VK record which is contained in the HBIN block stored
+ in the prs_struct *ps.
+*******************************************************************/
+
+static bool hbin_prs_vk_records( const char *desc, REGF_HBIN *hbin, int depth, REGF_NK_REC *nk, REGF_FILE *file )
+{
+ int i;
+ uint32 record_size;
+
+ prs_debug(&hbin->ps, depth, desc, "prs_vk_records");
+ depth++;
+
+ /* check if we have anything to do first */
+
+ if ( nk->num_values == 0 )
+ return True;
+
+ if ( UNMARSHALLING(&hbin->ps) ) {
+ if ( !(nk->values = PRS_ALLOC_MEM( &hbin->ps, REGF_VK_REC, nk->num_values ) ) )
+ return False;
+ }
+
+ /* convert the offset to something relative to this HBIN block */
+
+ if ( !prs_set_offset( &hbin->ps, nk->values_off+HBIN_HDR_SIZE-hbin->first_hbin_off-sizeof(uint32)) )
+ return False;
+
+ if ( MARSHALLING( &hbin->ps) ) {
+ record_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
+ record_size = (record_size - 1) ^ 0xFFFFFFFF;
+ }
+
+ if ( !prs_uint32( "record_size", &hbin->ps, depth, &record_size ) )
+ return False;
+
+ for ( i=0; i<nk->num_values; i++ ) {
+ if ( !prs_uint32( "vk_off", &hbin->ps, depth, &nk->values[i].rec_off ) )
+ return False;
+ }
+
+ for ( i=0; i<nk->num_values; i++ ) {
+ REGF_HBIN *sub_hbin = hbin;
+ uint32 new_offset;
+
+ if ( !hbin_contains_offset( hbin, nk->values[i].rec_off ) ) {
+ sub_hbin = lookup_hbin_block( file, nk->values[i].rec_off );
+ if ( !sub_hbin ) {
+ DEBUG(0,("hbin_prs_vk_records: Failed to find HBIN block containing offset [0x%x]\n",
+ nk->values[i].hbin_off));
+ return False;
+ }
+ }
+
+ new_offset = nk->values[i].rec_off + HBIN_HDR_SIZE - sub_hbin->first_hbin_off;
+ if ( !prs_set_offset( &sub_hbin->ps, new_offset ) )
+ return False;
+ if ( !hbin_prs_vk_rec( "vk_rec", sub_hbin, depth, &nk->values[i], file ) )
+ return False;
+ }
+
+ if ( MARSHALLING(&hbin->ps) )
+ hbin->dirty = True;
+
+
+ return True;
+}
+
+
+/*******************************************************************
+*******************************************************************/
+
+static REGF_SK_REC* find_sk_record_by_offset( REGF_FILE *file, uint32 offset )
+{
+ REGF_SK_REC *p_sk;
+
+ for ( p_sk=file->sec_desc_list; p_sk; p_sk=p_sk->next ) {
+ if ( p_sk->sk_off == offset )
+ return p_sk;
+ }
+
+ return NULL;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd )
+{
+ REGF_SK_REC *p;
+
+ for ( p=file->sec_desc_list; p; p=p->next ) {
+ if ( sec_desc_equal( p->sec_desc, sd ) )
+ return p;
+ }
+
+ /* failure */
+
+ return NULL;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
+{
+ int depth = 0;
+ REGF_HBIN *sub_hbin;
+
+ prs_debug(&hbin->ps, depth, "", "fetch_key");
+ depth++;
+
+ /* get the initial nk record */
+
+ if ( !prs_nk_rec( "nk_rec", &hbin->ps, depth, nk ))
+ return False;
+
+ /* fill in values */
+
+ if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) ) {
+ sub_hbin = hbin;
+ if ( !hbin_contains_offset( hbin, nk->values_off ) ) {
+ sub_hbin = lookup_hbin_block( file, nk->values_off );
+ if ( !sub_hbin ) {
+ DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing value_list_offset [0x%x]\n",
+ nk->values_off));
+ return False;
+ }
+ }
+
+ if ( !hbin_prs_vk_records( "vk_rec", sub_hbin, depth, nk, file ))
+ return False;
+ }
+
+ /* now get subkeys */
+
+ if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) ) {
+ sub_hbin = hbin;
+ if ( !hbin_contains_offset( hbin, nk->subkeys_off ) ) {
+ sub_hbin = lookup_hbin_block( file, nk->subkeys_off );
+ if ( !sub_hbin ) {
+ DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing subkey_offset [0x%x]\n",
+ nk->subkeys_off));
+ return False;
+ }
+ }
+
+ if ( !hbin_prs_lf_records( "lf_rec", sub_hbin, depth, nk ))
+ return False;
+ }
+
+ /* get the to the security descriptor. First look if we have already parsed it */
+
+ if ( (nk->sk_off!=REGF_OFFSET_NONE) && !( nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )) ) {
+
+ sub_hbin = hbin;
+ if ( !hbin_contains_offset( hbin, nk->sk_off ) ) {
+ sub_hbin = lookup_hbin_block( file, nk->sk_off );
+ if ( !sub_hbin ) {
+ DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing sk_offset [0x%x]\n",
+ nk->subkeys_off));
+ return False;
+ }
+ }
+
+ if ( !(nk->sec_desc = TALLOC_ZERO_P( file->mem_ctx, REGF_SK_REC )) )
+ return False;
+ nk->sec_desc->sk_off = nk->sk_off;
+ if ( !hbin_prs_sk_rec( "sk_rec", sub_hbin, depth, nk->sec_desc ))
+ return False;
+
+ /* add to the list of security descriptors (ref_count has been read from the files) */
+
+ nk->sec_desc->sk_off = nk->sk_off;
+ DLIST_ADD( file->sec_desc_list, nk->sec_desc );
+ }
+
+ return True;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool next_record( REGF_HBIN *hbin, const char *hdr, bool *eob )
+{
+ uint8 header[REC_HDR_SIZE];
+ uint32 record_size;
+ uint32 curr_off, block_size;
+ bool found = False;
+ prs_struct *ps = &hbin->ps;
+
+ curr_off = prs_offset( ps );
+ if ( curr_off == 0 )
+ prs_set_offset( ps, HBIN_HEADER_REC_SIZE );
+
+ /* assume that the current offset is at the record header
+ and we need to backup to read the record size */
+
+ curr_off -= sizeof(uint32);
+
+ block_size = prs_data_size( ps );
+ record_size = 0;
+ memset( header, 0x0, sizeof(uint8)*REC_HDR_SIZE );
+ while ( !found ) {
+
+ curr_off = curr_off+record_size;
+ if ( curr_off >= block_size )
+ break;
+
+ if ( !prs_set_offset( &hbin->ps, curr_off) )
+ return False;
+
+ if ( !prs_uint32( "record_size", ps, 0, &record_size ) )
+ return False;
+ if ( !prs_uint8s( True, "header", ps, 0, header, REC_HDR_SIZE ) )
+ return False;
+
+ if ( record_size & 0x80000000 ) {
+ /* absolute_value(record_size) */
+ record_size = (record_size ^ 0xffffffff) + 1;
+ }
+
+ if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) {
+ found = True;
+ curr_off += sizeof(uint32);
+ }
+ }
+
+ /* mark prs_struct as done ( at end ) if no more SK records */
+ /* mark end-of-block as True */
+
+ if ( !found ) {
+ prs_set_offset( &hbin->ps, prs_data_size(&hbin->ps) );
+ *eob = True;
+ return False;
+ }
+
+ if ( !prs_set_offset( ps, curr_off ) )
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool next_nk_record( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk, bool *eob )
+{
+ if ( next_record( hbin, "nk", eob ) && hbin_prs_key( file, hbin, nk ) )
+ return True;
+
+ return False;
+}
+
+/*******************************************************************
+ Intialize the newly created REGF_BLOCK in *file and write the
+ block header to disk
+*******************************************************************/
+
+static bool init_regf_block( REGF_FILE *file )
+{
+ prs_struct ps;
+ bool result = True;
+
+ if ( !prs_init( &ps, REGF_BLOCKSIZE, file->mem_ctx, MARSHALL ) )
+ return False;
+
+ memcpy( file->header, "regf", REGF_HDR_SIZE );
+ file->data_offset = 0x20;
+ file->last_block = 0x1000;
+
+ /* set mod time */
+
+ unix_to_nt_time( &file->mtime, time(NULL) );
+
+ /* hard coded values...no diea what these are ... maybe in time */
+
+ file->unknown1 = 0x2;
+ file->unknown2 = 0x1;
+ file->unknown3 = 0x3;
+ file->unknown4 = 0x0;
+ file->unknown5 = 0x1;
+ file->unknown6 = 0x1;
+
+ /* write header to the buffer */
+
+ if ( !prs_regf_block( "regf_header", &ps, 0, file ) ) {
+ result = False;
+ goto out;
+ }
+
+ /* calculate the checksum, re-marshall data (to include the checksum)
+ and write to disk */
+
+ file->checksum = regf_block_checksum( &ps );
+ prs_set_offset( &ps, 0 );
+ if ( !prs_regf_block( "regf_header", &ps, 0, file ) ) {
+ result = False;
+ goto out;
+ }
+
+ if ( write_block( file, &ps, 0 ) == -1 ) {
+ DEBUG(0,("init_regf_block: Failed to initialize registry header block!\n"));
+ result = False;
+ goto out;
+ }
+
+out:
+ prs_mem_free( &ps );
+
+ return result;
+}
+/*******************************************************************
+ Open the registry file and then read in the REGF block to get the
+ first hbin offset.
+*******************************************************************/
+
+ REGF_FILE* regfio_open( const char *filename, int flags, int mode )
+{
+ REGF_FILE *rb;
+
+ if ( !(rb = SMB_MALLOC_P(REGF_FILE)) ) {
+ DEBUG(0,("ERROR allocating memory\n"));
+ return NULL;
+ }
+ ZERO_STRUCTP( rb );
+ rb->fd = -1;
+
+ if ( !(rb->mem_ctx = talloc_init( "read_regf_block" )) ) {
+ regfio_close( rb );
+ return NULL;
+ }
+
+ rb->open_flags = flags;
+
+ /* open and existing file */
+
+ if ( (rb->fd = open(filename, flags, mode)) == -1 ) {
+ DEBUG(0,("regfio_open: failure to open %s (%s)\n", filename, strerror(errno)));
+ regfio_close( rb );
+ return NULL;
+ }
+
+ /* check if we are creating a new file or overwriting an existing one */
+
+ if ( flags & (O_CREAT|O_TRUNC) ) {
+ if ( !init_regf_block( rb ) ) {
+ DEBUG(0,("regfio_open: Failed to read initial REGF block\n"));
+ regfio_close( rb );
+ return NULL;
+ }
+
+ /* success */
+ return rb;
+ }
+
+ /* read in an existing file */
+
+ if ( !read_regf_block( rb ) ) {
+ DEBUG(0,("regfio_open: Failed to read initial REGF block\n"));
+ regfio_close( rb );
+ return NULL;
+ }
+
+ /* success */
+
+ return rb;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static void regfio_mem_free( REGF_FILE *file )
+{
+ /* free any talloc()'d memory */
+
+ if ( file && file->mem_ctx )
+ talloc_destroy( file->mem_ctx );
+}
+
+/*******************************************************************
+*******************************************************************/
+
+ int regfio_close( REGF_FILE *file )
+{
+ int fd;
+
+ /* cleanup for a file opened for write */
+
+ if ((file->fd != -1) && (file->open_flags & (O_WRONLY|O_RDWR))) {
+ prs_struct ps;
+ REGF_SK_REC *sk;
+
+ /* write of sd list */
+
+ for ( sk=file->sec_desc_list; sk; sk=sk->next ) {
+ hbin_prs_sk_rec( "sk_rec", sk->hbin, 0, sk );
+ }
+
+ /* flush any dirty blocks */
+
+ while ( file->block_list ) {
+ hbin_block_close( file, file->block_list );
+ }
+
+ ZERO_STRUCT( ps );
+
+ unix_to_nt_time( &file->mtime, time(NULL) );
+
+ if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) != -1 ) {
+ /* now use for writing */
+ prs_switch_type( &ps, MARSHALL );
+
+ /* stream the block once, generate the checksum,
+ and stream it again */
+ prs_set_offset( &ps, 0 );
+ prs_regf_block( "regf_blocK", &ps, 0, file );
+ file->checksum = regf_block_checksum( &ps );
+ prs_set_offset( &ps, 0 );
+ prs_regf_block( "regf_blocK", &ps, 0, file );
+
+ /* now we are ready to write it to disk */
+ if ( write_block( file, &ps, 0 ) == -1 )
+ DEBUG(0,("regfio_close: failed to update the regf header block!\n"));
+ }
+
+ prs_mem_free( &ps );
+ }
+
+ regfio_mem_free( file );
+
+ /* nothing tdo do if there is no open file */
+
+ if (file->fd == -1)
+ return 0;
+
+ fd = file->fd;
+ file->fd = -1;
+ SAFE_FREE( file );
+
+ return close( fd );
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static void regfio_flush( REGF_FILE *file )
+{
+ REGF_HBIN *hbin;
+
+ for ( hbin=file->block_list; hbin; hbin=hbin->next ) {
+ write_hbin_block( file, hbin );
+ }
+}
+
+/*******************************************************************
+ There should be only *one* root key in the registry file based
+ on my experience. --jerry
+*******************************************************************/
+
+REGF_NK_REC* regfio_rootkey( REGF_FILE *file )
+{
+ REGF_NK_REC *nk;
+ REGF_HBIN *hbin;
+ uint32 offset = REGF_BLOCKSIZE;
+ bool found = False;
+ bool eob;
+
+ if ( !file )
+ return NULL;
+
+ if ( !(nk = TALLOC_ZERO_P( file->mem_ctx, REGF_NK_REC )) ) {
+ DEBUG(0,("regfio_rootkey: talloc() failed!\n"));
+ return NULL;
+ }
+
+ /* scan through the file on HBIN block at a time looking
+ for an NK record with a type == 0x002c.
+ Normally this is the first nk record in the first hbin
+ block (but I'm not assuming that for now) */
+
+ while ( (hbin = read_hbin_block( file, offset )) ) {
+ eob = False;
+
+ while ( !eob) {
+ if ( next_nk_record( file, hbin, nk, &eob ) ) {
+ if ( nk->key_type == NK_TYPE_ROOTKEY ) {
+ found = True;
+ break;
+ }
+ }
+ prs_mem_free( &hbin->ps );
+ }
+
+ if ( found )
+ break;
+
+ offset += hbin->block_size;
+ }
+
+ if ( !found ) {
+ DEBUG(0,("regfio_rootkey: corrupt registry file ? No root key record located\n"));
+ return NULL;
+ }
+
+ DLIST_ADD( file->block_list, hbin );
+
+ return nk;
+}
+
+/*******************************************************************
+ This acts as an interator over the subkeys defined for a given
+ NK record. Remember that offsets are from the *first* HBIN block.
+*******************************************************************/
+
+ REGF_NK_REC* regfio_fetch_subkey( REGF_FILE *file, REGF_NK_REC *nk )
+{
+ REGF_NK_REC *subkey;
+ REGF_HBIN *hbin;
+ uint32 nk_offset;
+
+ /* see if there is anything left to report */
+
+ if ( !nk || (nk->subkeys_off==REGF_OFFSET_NONE) || (nk->subkey_index >= nk->num_subkeys) )
+ return NULL;
+
+ /* find the HBIN block which should contain the nk record */
+
+ if ( !(hbin = lookup_hbin_block( file, nk->subkeys.hashes[nk->subkey_index].nk_off )) ) {
+ DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing offset [0x%x]\n",
+ nk->subkeys.hashes[nk->subkey_index].nk_off));
+ return NULL;
+ }
+
+ nk_offset = nk->subkeys.hashes[nk->subkey_index].nk_off;
+ if ( !prs_set_offset( &hbin->ps, (HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off) ) )
+ return NULL;
+
+ nk->subkey_index++;
+ if ( !(subkey = TALLOC_ZERO_P( file->mem_ctx, REGF_NK_REC )) )
+ return NULL;
+
+ if ( !hbin_prs_key( file, hbin, subkey ) )
+ return NULL;
+
+ return subkey;
+}
+
+
+/*******************************************************************
+*******************************************************************/
+
+static REGF_HBIN* regf_hbin_allocate( REGF_FILE *file, uint32 block_size )
+{
+ REGF_HBIN *hbin;
+ SMB_STRUCT_STAT sbuf;
+
+ if ( !(hbin = TALLOC_ZERO_P( file->mem_ctx, REGF_HBIN )) )
+ return NULL;
+
+ memcpy( hbin->header, "hbin", sizeof(HBIN_HDR_SIZE) );
+
+
+ if ( sys_fstat( file->fd, &sbuf ) ) {
+ DEBUG(0,("regf_hbin_allocate: stat() failed! (%s)\n", strerror(errno)));
+ return NULL;
+ }
+
+ hbin->file_off = sbuf.st_size;
+
+ hbin->free_off = HBIN_HEADER_REC_SIZE;
+ hbin->free_size = block_size - hbin->free_off + sizeof(uint32);;
+
+ hbin->block_size = block_size;
+ hbin->first_hbin_off = hbin->file_off - REGF_BLOCKSIZE;
+
+ if ( !prs_init( &hbin->ps, block_size, file->mem_ctx, MARSHALL ) )
+ return NULL;
+
+ if ( !prs_hbin_block( "new_hbin", &hbin->ps, 0, hbin ) )
+ return NULL;
+
+ if ( !write_hbin_block( file, hbin ) )
+ return NULL;
+
+ file->last_block = hbin->file_off;
+
+ return hbin;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static void update_free_space( REGF_HBIN *hbin, uint32 size_used )
+{
+ hbin->free_off += size_used;
+ hbin->free_size -= size_used;
+
+ if ( hbin->free_off >= hbin->block_size ) {
+ hbin->free_off = REGF_OFFSET_NONE;
+ }
+
+ return;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static REGF_HBIN* find_free_space( REGF_FILE *file, uint32 size )
+{
+ REGF_HBIN *hbin, *p_hbin;
+ uint32 block_off;
+ bool cached;
+
+ /* check open block list */
+
+ for ( hbin=file->block_list; hbin!=NULL; hbin=hbin->next ) {
+ /* only check blocks that actually have available space */
+
+ if ( hbin->free_off == REGF_OFFSET_NONE )
+ continue;
+
+ /* check for a large enough available chunk */
+
+ if ( (hbin->block_size - hbin->free_off) >= size ) {
+ DLIST_PROMOTE( file->block_list, hbin );
+ goto done;
+ }
+ }
+
+ /* parse the file until we find a block with
+ enough free space; save the last non-filled hbin */
+
+ block_off = REGF_BLOCKSIZE;
+ do {
+ /* cleanup before the next round */
+ cached = False;
+ if ( hbin )
+ prs_mem_free( &hbin->ps );
+
+ hbin = read_hbin_block( file, block_off );
+
+ if ( hbin ) {
+
+ /* make sure that we don't already have this block in memory */
+
+ for ( p_hbin=file->block_list; p_hbin!=NULL; p_hbin=p_hbin->next ) {
+ if ( p_hbin->file_off == hbin->file_off ) {
+ cached = True;
+ break;
+ }
+ }
+
+ block_off = hbin->file_off + hbin->block_size;
+
+ if ( cached ) {
+ prs_mem_free( &hbin->ps );
+ hbin = NULL;
+ continue;
+ }
+ }
+ /* if (cached block or (new block and not enough free space)) then continue looping */
+ } while ( cached || (hbin && (hbin->free_size < size)) );
+
+ /* no free space; allocate a new one */
+
+ if ( !hbin ) {
+ uint32 alloc_size;
+
+ /* allocate in multiples of REGF_ALLOC_BLOCK; make sure (size + hbin_header) fits */
+
+ alloc_size = (((size+HBIN_HEADER_REC_SIZE) / REGF_ALLOC_BLOCK ) + 1 ) * REGF_ALLOC_BLOCK;
+
+ if ( !(hbin = regf_hbin_allocate( file, alloc_size )) ) {
+ DEBUG(0,("find_free_space: regf_hbin_allocate() failed!\n"));
+ return NULL;
+ }
+ DLIST_ADD( file->block_list, hbin );
+ }
+
+done:
+ /* set the offset to be ready to write */
+
+ if ( !prs_set_offset( &hbin->ps, hbin->free_off-sizeof(uint32) ) )
+ return NULL;
+
+ /* write the record size as a placeholder for now, it should be
+ probably updated by the caller once it all of the data necessary
+ for the record */
+
+ if ( !prs_uint32("allocated_size", &hbin->ps, 0, &size) )
+ return False;
+
+ update_free_space( hbin, size );
+
+ return hbin;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static uint32 sk_record_data_size( SEC_DESC * sd )
+{
+ uint32 size, size_mod8;
+
+ size_mod8 = 0;
+
+ /* the record size is sizeof(hdr) + name + static members + data_size_field */
+
+ size = sizeof(uint32)*5 + ndr_size_security_descriptor(sd, 0) + sizeof(uint32);
+
+ /* multiple of 8 */
+ size_mod8 = size & 0xfffffff8;
+ if ( size_mod8 < size )
+ size_mod8 += 8;
+
+ return size_mod8;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static uint32 vk_record_data_size( REGF_VK_REC *vk )
+{
+ uint32 size, size_mod8;
+
+ size_mod8 = 0;
+
+ /* the record size is sizeof(hdr) + name + static members + data_size_field */
+
+ size = REC_HDR_SIZE + (sizeof(uint16)*3) + (sizeof(uint32)*3) + sizeof(uint32);
+
+ if ( vk->valuename )
+ size += strlen(vk->valuename);
+
+ /* multiple of 8 */
+ size_mod8 = size & 0xfffffff8;
+ if ( size_mod8 < size )
+ size_mod8 += 8;
+
+ return size_mod8;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static uint32 lf_record_data_size( uint32 num_keys )
+{
+ uint32 size, size_mod8;
+
+ size_mod8 = 0;
+
+ /* the record size is sizeof(hdr) + num_keys + sizeof of hash_array + data_size_uint32 */
+
+ size = REC_HDR_SIZE + sizeof(uint16) + (sizeof(REGF_HASH_REC) * num_keys) + sizeof(uint32);
+
+ /* multiple of 8 */
+ size_mod8 = size & 0xfffffff8;
+ if ( size_mod8 < size )
+ size_mod8 += 8;
+
+ return size_mod8;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static uint32 nk_record_data_size( REGF_NK_REC *nk )
+{
+ uint32 size, size_mod8;
+
+ size_mod8 = 0;
+
+ /* the record size is static + length_of_keyname + length_of_classname + data_size_uint32 */
+
+ size = 0x4c + strlen(nk->keyname) + sizeof(uint32);
+
+ if ( nk->classname )
+ size += strlen( nk->classname );
+
+ /* multiple of 8 */
+ size_mod8 = size & 0xfffffff8;
+ if ( size_mod8 < size )
+ size_mod8 += 8;
+
+ return size_mod8;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static bool create_vk_record( REGF_FILE *file, REGF_VK_REC *vk, REGISTRY_VALUE *value )
+{
+ char *name = regval_name(value);
+ REGF_HBIN *data_hbin;
+
+ ZERO_STRUCTP( vk );
+
+ memcpy( vk->header, "vk", REC_HDR_SIZE );
+
+ if ( name ) {
+ vk->valuename = talloc_strdup( file->mem_ctx, regval_name(value) );
+ vk->flag = VK_FLAG_NAME_PRESENT;
+ }
+
+ vk->data_size = regval_size( value );
+ vk->type = regval_type( value );
+
+ if ( vk->data_size > sizeof(uint32) ) {
+ uint32 data_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8;
+
+ vk->data = (uint8 *)TALLOC_MEMDUP( file->mem_ctx,
+ regval_data_p(value),
+ vk->data_size );
+ if (vk->data == NULL) {
+ return False;
+ }
+
+ /* go ahead and store the offset....we'll pick this hbin block back up when
+ we stream the data */
+
+ if ((data_hbin = find_free_space(file, data_size )) == NULL) {
+ return False;
+ }
+ vk->data_off = prs_offset( &data_hbin->ps ) + data_hbin->first_hbin_off - HBIN_HDR_SIZE;
+ }
+ else {
+ /* make sure we don't try to copy from a NULL value pointer */
+
+ if ( vk->data_size != 0 )
+ memcpy( &vk->data_off, regval_data_p(value), sizeof(uint32) );
+ vk->data_size |= VK_DATA_IN_OFFSET;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static int hashrec_cmp( REGF_HASH_REC *h1, REGF_HASH_REC *h2 )
+{
+ return StrCaseCmp( h1->fullname, h2->fullname );
+}
+
+/*******************************************************************
+*******************************************************************/
+
+ REGF_NK_REC* regfio_write_key( REGF_FILE *file, const char *name,
+ REGVAL_CTR *values, REGSUBKEY_CTR *subkeys,
+ SEC_DESC *sec_desc, REGF_NK_REC *parent )
+{
+ REGF_NK_REC *nk;
+ REGF_HBIN *vlist_hbin = NULL;
+ uint32 size;
+
+ if ( !(nk = TALLOC_ZERO_P( file->mem_ctx, REGF_NK_REC )) )
+ return NULL;
+
+ memcpy( nk->header, "nk", REC_HDR_SIZE );
+
+ if ( !parent )
+ nk->key_type = NK_TYPE_ROOTKEY;
+ else
+ nk->key_type = NK_TYPE_NORMALKEY;
+
+ /* store the parent offset (or -1 if a the root key */
+
+ nk->parent_off = parent ? (parent->hbin_off + parent->hbin->file_off - REGF_BLOCKSIZE - HBIN_HDR_SIZE ) : REGF_OFFSET_NONE;
+
+ /* no classname currently */
+
+ nk->classname_off = REGF_OFFSET_NONE;
+ nk->classname = NULL;
+ nk->keyname = talloc_strdup( file->mem_ctx, name );
+
+ /* current modification time */
+
+ unix_to_nt_time( &nk->mtime, time(NULL) );
+
+ /* allocate the record on disk */
+
+ size = nk_record_data_size( nk );
+ nk->rec_size = ( size - 1 ) ^ 0XFFFFFFFF;
+ if ((nk->hbin = find_free_space( file, size )) == NULL) {
+ return NULL;
+ }
+ nk->hbin_off = prs_offset( &nk->hbin->ps );
+
+ /* Update the hash record in the parent */
+
+ if ( parent ) {
+ REGF_HASH_REC *hash = &parent->subkeys.hashes[parent->subkey_index];
+
+ hash->nk_off = prs_offset( &nk->hbin->ps ) + nk->hbin->first_hbin_off - HBIN_HDR_SIZE;
+ memcpy( hash->keycheck, name, sizeof(uint32) );
+ hash->fullname = talloc_strdup( file->mem_ctx, name );
+ parent->subkey_index++;
+
+ /* sort the list by keyname */
+
+ qsort( parent->subkeys.hashes, parent->subkey_index, sizeof(REGF_HASH_REC), QSORT_CAST hashrec_cmp );
+
+ if ( !hbin_prs_lf_records( "lf_rec", parent->subkeys.hbin, 0, parent ) )
+ return False;
+ }
+
+ /* write the security descriptor */
+
+ nk->sk_off = REGF_OFFSET_NONE;
+ if ( sec_desc ) {
+ uint32 sk_size = sk_record_data_size( sec_desc );
+ REGF_HBIN *sk_hbin;
+
+ /* search for it in the existing list of sd's */
+
+ if ( (nk->sec_desc = find_sk_record_by_sec_desc( file, sec_desc )) == NULL ) {
+ /* not found so add it to the list */
+
+ if (!(sk_hbin = find_free_space( file, sk_size ))) {
+ return NULL;
+ }
+
+ if ( !(nk->sec_desc = TALLOC_ZERO_P( file->mem_ctx, REGF_SK_REC )) )
+ return NULL;
+
+ /* now we have to store the security descriptor in the list and
+ update the offsets */
+
+ memcpy( nk->sec_desc->header, "sk", REC_HDR_SIZE );
+ nk->sec_desc->hbin = sk_hbin;
+ nk->sec_desc->hbin_off = prs_offset( &sk_hbin->ps );
+ nk->sec_desc->sk_off = prs_offset( &sk_hbin->ps ) + sk_hbin->first_hbin_off - HBIN_HDR_SIZE;
+ nk->sec_desc->rec_size = (sk_size-1) ^ 0xFFFFFFFF;
+
+ nk->sec_desc->sec_desc = sec_desc;
+ nk->sec_desc->ref_count = 0;
+
+ /* size value must be self-inclusive */
+ nk->sec_desc->size = ndr_size_security_descriptor(sec_desc, 0)
+ + sizeof(uint32);
+
+ DLIST_ADD_END( file->sec_desc_list, nk->sec_desc, REGF_SK_REC *);
+
+ /* update the offsets for us and the previous sd in the list.
+ if this is the first record, then just set the next and prev
+ offsets to ourself. */
+
+ if ( nk->sec_desc->prev ) {
+ REGF_SK_REC *prev = nk->sec_desc->prev;
+
+ nk->sec_desc->prev_sk_off = prev->hbin_off + prev->hbin->first_hbin_off - HBIN_HDR_SIZE;
+ prev->next_sk_off = nk->sec_desc->sk_off;
+
+ /* the end must loop around to the front */
+ nk->sec_desc->next_sk_off = file->sec_desc_list->sk_off;
+
+ /* and first must loop around to the tail */
+ file->sec_desc_list->prev_sk_off = nk->sec_desc->sk_off;
+ } else {
+ nk->sec_desc->prev_sk_off = nk->sec_desc->sk_off;
+ nk->sec_desc->next_sk_off = nk->sec_desc->sk_off;
+ }
+ }
+
+ /* bump the reference count +1 */
+
+ nk->sk_off = nk->sec_desc->sk_off;
+ nk->sec_desc->ref_count++;
+ }
+
+ /* write the subkeys */
+
+ nk->subkeys_off = REGF_OFFSET_NONE;
+ if ( (nk->num_subkeys = regsubkey_ctr_numkeys( subkeys )) != 0 ) {
+ uint32 lf_size = lf_record_data_size( nk->num_subkeys );
+ uint32 namelen;
+ int i;
+
+ if (!(nk->subkeys.hbin = find_free_space( file, lf_size ))) {
+ return NULL;
+ }
+ nk->subkeys.hbin_off = prs_offset( &nk->subkeys.hbin->ps );
+ nk->subkeys.rec_size = (lf_size-1) ^ 0xFFFFFFFF;
+ nk->subkeys_off = prs_offset( &nk->subkeys.hbin->ps ) + nk->subkeys.hbin->first_hbin_off - HBIN_HDR_SIZE;
+
+ memcpy( nk->subkeys.header, "lf", REC_HDR_SIZE );
+
+ nk->subkeys.num_keys = nk->num_subkeys;
+ if (nk->subkeys.num_keys) {
+ if ( !(nk->subkeys.hashes = TALLOC_ZERO_ARRAY( file->mem_ctx, REGF_HASH_REC, nk->subkeys.num_keys )) )
+ return NULL;
+ } else {
+ nk->subkeys.hashes = NULL;
+ }
+ nk->subkey_index = 0;
+
+ /* update the max_bytes_subkey{name,classname} fields */
+ for ( i=0; i<nk->num_subkeys; i++ ) {
+ namelen = strlen( regsubkey_ctr_specific_key(subkeys, i) );
+ if ( namelen*2 > nk->max_bytes_subkeyname )
+ nk->max_bytes_subkeyname = namelen * 2;
+ }
+ }
+
+ /* write the values */
+
+ nk->values_off = REGF_OFFSET_NONE;
+ if ( (nk->num_values = regval_ctr_numvals( values )) != 0 ) {
+ uint32 vlist_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
+ int i;
+
+ if (!(vlist_hbin = find_free_space( file, vlist_size ))) {
+ return NULL;
+ }
+ nk->values_off = prs_offset( &vlist_hbin->ps ) + vlist_hbin->first_hbin_off - HBIN_HDR_SIZE;
+
+ if (nk->num_values) {
+ if ( !(nk->values = TALLOC_ARRAY( file->mem_ctx, REGF_VK_REC, nk->num_values )) )
+ return NULL;
+ } else {
+ nk->values = NULL;
+ }
+
+ /* create the vk records */
+
+ for ( i=0; i<nk->num_values; i++ ) {
+ uint32 vk_size, namelen, datalen;
+ REGISTRY_VALUE *r;
+
+ r = regval_ctr_specific_value( values, i );
+ create_vk_record( file, &nk->values[i], r );
+ vk_size = vk_record_data_size( &nk->values[i] );
+ nk->values[i].hbin = find_free_space( file, vk_size );
+ nk->values[i].hbin_off = prs_offset( &nk->values[i].hbin->ps );
+ nk->values[i].rec_size = ( vk_size - 1 ) ^ 0xFFFFFFFF;
+ nk->values[i].rec_off = prs_offset( &nk->values[i].hbin->ps )
+ + nk->values[i].hbin->first_hbin_off
+ - HBIN_HDR_SIZE;
+
+ /* update the max bytes fields if necessary */
+
+ namelen = strlen( regval_name(r) );
+ if ( namelen*2 > nk->max_bytes_valuename )
+ nk->max_bytes_valuename = namelen * 2;
+
+ datalen = regval_size( r );
+ if ( datalen > nk->max_bytes_value )
+ nk->max_bytes_value = datalen;
+ }
+ }
+
+ /* stream the records */
+
+ prs_set_offset( &nk->hbin->ps, nk->hbin_off );
+ if ( !prs_nk_rec( "nk_rec", &nk->hbin->ps, 0, nk ) )
+ return False;
+
+ if ( nk->num_values ) {
+ if ( !hbin_prs_vk_records( "vk_records", vlist_hbin, 0, nk, file ) )
+ return False;
+ }
+
+
+ regfio_flush( file );
+
+ return nk;
+}
+
diff --git a/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c
new file mode 100644
index 0000000000..577df64fbb
--- /dev/null
+++ b/source3/rpc_client/cli_lsarpc.c
@@ -0,0 +1,469 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+ Copyright (C) Tim Potter 2000-2001,
+ Copyright (C) Andrew Tridgell 1992-1997,2000,
+ Copyright (C) Rafal Szczesniak 2002
+ Copyright (C) Jeremy Allison 2005.
+ Copyright (C) Michael Adam 2007.
+ Copyright (C) Guenther Deschner 2008.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/** @defgroup lsa LSA - Local Security Architecture
+ * @ingroup rpc_client
+ *
+ * @{
+ **/
+
+/**
+ * @file cli_lsarpc.c
+ *
+ * RPC client routines for the LSA RPC pipe. LSA means "local
+ * security authority", which is half of a password database.
+ **/
+
+/** Open a LSA policy handle
+ *
+ * @param cli Handle on an initialised SMB connection */
+
+NTSTATUS rpccli_lsa_open_policy(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ bool sec_qos, uint32 des_access,
+ POLICY_HND *pol)
+{
+ struct lsa_ObjectAttribute attr;
+ struct lsa_QosInfo qos;
+ uint16_t system_name = '\\';
+
+ if (sec_qos) {
+ init_lsa_sec_qos(&qos, 0xc, 2, 1, 0);
+ init_lsa_obj_attr(&attr,
+ 0x18,
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ &qos);
+ } else {
+ init_lsa_obj_attr(&attr,
+ 0x18,
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ }
+
+ return rpccli_lsa_OpenPolicy(cli, mem_ctx,
+ &system_name,
+ &attr,
+ des_access,
+ pol);
+}
+
+/** Open a LSA policy handle
+ *
+ * @param cli Handle on an initialised SMB connection
+ */
+
+NTSTATUS rpccli_lsa_open_policy2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, bool sec_qos,
+ uint32 des_access, POLICY_HND *pol)
+{
+ struct lsa_ObjectAttribute attr;
+ struct lsa_QosInfo qos;
+
+ if (sec_qos) {
+ init_lsa_sec_qos(&qos, 0xc, 2, 1, 0);
+ init_lsa_obj_attr(&attr,
+ 0x18,
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ &qos);
+ } else {
+ init_lsa_obj_attr(&attr,
+ 0x18,
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ }
+
+ return rpccli_lsa_OpenPolicy2(cli, mem_ctx,
+ cli->srv_name_slash,
+ &attr,
+ des_access,
+ pol);
+}
+
+/* Lookup a list of sids
+ *
+ * internal version withOUT memory allocation of the target arrays.
+ * this assumes suffciently sized arrays to store domains, names and types. */
+
+static NTSTATUS rpccli_lsa_lookup_sids_noalloc(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol,
+ int num_sids,
+ const DOM_SID *sids,
+ char **domains,
+ char **names,
+ enum lsa_SidType *types)
+{
+ NTSTATUS result = NT_STATUS_OK;
+ TALLOC_CTX *tmp_ctx = NULL;
+ int i;
+ struct lsa_SidArray sid_array;
+ struct lsa_RefDomainList *ref_domains = NULL;
+ struct lsa_TransNameArray lsa_names;
+ uint32_t count = 0;
+ uint16_t level = 1;
+
+ ZERO_STRUCT(lsa_names);
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (!tmp_ctx) {
+ DEBUG(0, ("rpccli_lsa_lookup_sids_noalloc: out of memory!\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ sid_array.num_sids = num_sids;
+ sid_array.sids = TALLOC_ARRAY(mem_ctx, struct lsa_SidPtr, num_sids);
+ if (!sid_array.sids) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i<num_sids; i++) {
+ sid_array.sids[i].sid = sid_dup_talloc(mem_ctx, &sids[i]);
+ if (!sid_array.sids[i].sid) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ result = rpccli_lsa_LookupSids(cli, mem_ctx,
+ pol,
+ &sid_array,
+ &ref_domains,
+ &lsa_names,
+ level,
+ &count);
+
+ DEBUG(10, ("LSA_LOOKUPSIDS returned '%s', mapped count = %d'\n",
+ nt_errstr(result), count));
+
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) &&
+ !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED))
+ {
+ /* An actual error occured */
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
+ (count == 0))
+ {
+ for (i = 0; i < num_sids; i++) {
+ (names)[i] = NULL;
+ (domains)[i] = NULL;
+ (types)[i] = SID_NAME_UNKNOWN;
+ }
+ result = NT_STATUS_NONE_MAPPED;
+ goto done;
+ }
+
+ for (i = 0; i < num_sids; i++) {
+ const char *name, *dom_name;
+ uint32_t dom_idx = lsa_names.names[i].sid_index;
+
+ /* Translate optimised name through domain index array */
+
+ if (dom_idx != 0xffffffff) {
+
+ dom_name = ref_domains->domains[dom_idx].name.string;
+ name = lsa_names.names[i].name.string;
+
+ if (name) {
+ (names)[i] = talloc_strdup(mem_ctx, name);
+ if ((names)[i] == NULL) {
+ DEBUG(0, ("cli_lsa_lookup_sids_noalloc(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ } else {
+ (names)[i] = NULL;
+ }
+ (domains)[i] = talloc_strdup(mem_ctx, dom_name);
+ (types)[i] = lsa_names.names[i].sid_type;
+ if (((domains)[i] == NULL)) {
+ DEBUG(0, ("cli_lsa_lookup_sids_noalloc(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ } else {
+ (names)[i] = NULL;
+ (domains)[i] = NULL;
+ (types)[i] = SID_NAME_UNKNOWN;
+ }
+ }
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return result;
+}
+
+/* Lookup a list of sids
+ *
+ * do it the right way: there is a limit (of 20480 for w2k3) entries
+ * returned by this call. when the sids list contains more entries,
+ * empty lists are returned. This version of lsa_lookup_sids passes
+ * the list of sids in hunks of LOOKUP_SIDS_HUNK_SIZE to the lsa call. */
+
+/* This constant defines the limit of how many sids to look up
+ * in one call (maximum). the limit from the server side is
+ * at 20480 for win2k3, but we keep it at a save 1000 for now. */
+#define LOOKUP_SIDS_HUNK_SIZE 1000
+
+NTSTATUS rpccli_lsa_lookup_sids(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol,
+ int num_sids,
+ const DOM_SID *sids,
+ char ***pdomains,
+ char ***pnames,
+ enum lsa_SidType **ptypes)
+{
+ NTSTATUS result = NT_STATUS_OK;
+ int sids_left = 0;
+ int sids_processed = 0;
+ const DOM_SID *hunk_sids = sids;
+ char **hunk_domains;
+ char **hunk_names;
+ enum lsa_SidType *hunk_types;
+ char **domains = NULL;
+ char **names = NULL;
+ enum lsa_SidType *types = NULL;
+
+ if (num_sids) {
+ if (!(domains = TALLOC_ARRAY(mem_ctx, char *, num_sids))) {
+ DEBUG(0, ("rpccli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ if (!(names = TALLOC_ARRAY(mem_ctx, char *, num_sids))) {
+ DEBUG(0, ("rpccli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ if (!(types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_sids))) {
+ DEBUG(0, ("rpccli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ }
+
+ sids_left = num_sids;
+ hunk_domains = domains;
+ hunk_names = names;
+ hunk_types = types;
+
+ while (sids_left > 0) {
+ int hunk_num_sids;
+ NTSTATUS hunk_result = NT_STATUS_OK;
+
+ hunk_num_sids = ((sids_left > LOOKUP_SIDS_HUNK_SIZE)
+ ? LOOKUP_SIDS_HUNK_SIZE
+ : sids_left);
+
+ DEBUG(10, ("rpccli_lsa_lookup_sids: processing items "
+ "%d -- %d of %d.\n",
+ sids_processed,
+ sids_processed + hunk_num_sids - 1,
+ num_sids));
+
+ hunk_result = rpccli_lsa_lookup_sids_noalloc(cli,
+ mem_ctx,
+ pol,
+ hunk_num_sids,
+ hunk_sids,
+ hunk_domains,
+ hunk_names,
+ hunk_types);
+
+ if (!NT_STATUS_IS_OK(hunk_result) &&
+ !NT_STATUS_EQUAL(hunk_result, STATUS_SOME_UNMAPPED) &&
+ !NT_STATUS_EQUAL(hunk_result, NT_STATUS_NONE_MAPPED))
+ {
+ /* An actual error occured */
+ result = hunk_result;
+ goto fail;
+ }
+
+ /* adapt overall result */
+ if (( NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_IS_OK(hunk_result))
+ ||
+ ( NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) &&
+ !NT_STATUS_EQUAL(hunk_result, NT_STATUS_NONE_MAPPED)))
+ {
+ result = STATUS_SOME_UNMAPPED;
+ }
+
+ sids_left -= hunk_num_sids;
+ sids_processed += hunk_num_sids; /* only used in DEBUG */
+ hunk_sids += hunk_num_sids;
+ hunk_domains += hunk_num_sids;
+ hunk_names += hunk_num_sids;
+ hunk_types += hunk_num_sids;
+ }
+
+ *pdomains = domains;
+ *pnames = names;
+ *ptypes = types;
+ return result;
+
+fail:
+ TALLOC_FREE(domains);
+ TALLOC_FREE(names);
+ TALLOC_FREE(types);
+ return result;
+}
+
+/** Lookup a list of names */
+
+NTSTATUS rpccli_lsa_lookup_names(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, int num_names,
+ const char **names,
+ const char ***dom_names,
+ int level,
+ DOM_SID **sids,
+ enum lsa_SidType **types)
+{
+ NTSTATUS result;
+ int i;
+ struct lsa_String *lsa_names = NULL;
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_TransSidArray sid_array;
+ uint32_t count = 0;
+
+ ZERO_STRUCT(sid_array);
+
+ lsa_names = TALLOC_ARRAY(mem_ctx, struct lsa_String, num_names);
+ if (!lsa_names) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<num_names; i++) {
+ init_lsa_String(&lsa_names[i], names[i]);
+ }
+
+ result = rpccli_lsa_LookupNames(cli, mem_ctx,
+ pol,
+ num_names,
+ lsa_names,
+ &domains,
+ &sid_array,
+ level,
+ &count);
+
+ if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) !=
+ NT_STATUS_V(STATUS_SOME_UNMAPPED)) {
+
+ /* An actual error occured */
+
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (count == 0) {
+ result = NT_STATUS_NONE_MAPPED;
+ goto done;
+ }
+
+ if (num_names) {
+ if (!((*sids = TALLOC_ARRAY(mem_ctx, DOM_SID, num_names)))) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if (!((*types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_names)))) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if (dom_names != NULL) {
+ *dom_names = TALLOC_ARRAY(mem_ctx, const char *, num_names);
+ if (*dom_names == NULL) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ }
+ } else {
+ *sids = NULL;
+ *types = NULL;
+ if (dom_names != NULL) {
+ *dom_names = NULL;
+ }
+ }
+
+ for (i = 0; i < num_names; i++) {
+ uint32_t dom_idx = sid_array.sids[i].sid_index;
+ uint32_t dom_rid = sid_array.sids[i].rid;
+ DOM_SID *sid = &(*sids)[i];
+
+ /* Translate optimised sid through domain index array */
+
+ if (dom_idx == 0xffffffff) {
+ /* Nothing to do, this is unknown */
+ ZERO_STRUCTP(sid);
+ (*types)[i] = SID_NAME_UNKNOWN;
+ continue;
+ }
+
+ sid_copy(sid, domains->domains[dom_idx].sid);
+
+ if (dom_rid != 0xffffffff) {
+ sid_append_rid(sid, dom_rid);
+ }
+
+ (*types)[i] = sid_array.sids[i].sid_type;
+
+ if (dom_names == NULL) {
+ continue;
+ }
+
+ (*dom_names)[i] = domains->domains[dom_idx].name.string;
+ }
+
+ done:
+
+ return result;
+}
diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c
new file mode 100644
index 0000000000..df87ed13d1
--- /dev/null
+++ b/source3/rpc_client/cli_netlogon.c
@@ -0,0 +1,540 @@
+/*
+ Unix SMB/CIFS implementation.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Jeremy Allison 1998.
+ Largely re-written by Jeremy Allison (C) 2005.
+ Copyright (C) Guenther Deschner 2008.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
+ credentials chain. Stores the credentials in the struct dcinfo in the
+ netlogon pipe struct.
+****************************************************************************/
+
+NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
+ const char *server_name,
+ const char *domain,
+ const char *clnt_name,
+ const char *machine_account,
+ const unsigned char machine_pwd[16],
+ enum netr_SchannelType sec_chan_type,
+ uint32_t *neg_flags_inout)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct netr_Credential clnt_chal_send;
+ struct netr_Credential srv_chal_recv;
+ struct dcinfo *dc;
+ bool retried = false;
+
+ SMB_ASSERT(ndr_syntax_id_equal(&cli->abstract_syntax,
+ &ndr_table_netlogon.syntax_id));
+
+ TALLOC_FREE(cli->dc);
+ cli->dc = talloc_zero(cli, struct dcinfo);
+ if (cli->dc == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ dc = cli->dc;
+
+ /* Store the machine account password we're going to use. */
+ memcpy(dc->mach_pw, machine_pwd, 16);
+
+ fstrcpy(dc->remote_machine, "\\\\");
+ fstrcat(dc->remote_machine, server_name);
+
+ fstrcpy(dc->domain, domain);
+
+ fstr_sprintf( dc->mach_acct, "%s$", machine_account);
+
+ again:
+ /* Create the client challenge. */
+ generate_random_buffer(clnt_chal_send.data, 8);
+
+ /* Get the server challenge. */
+ result = rpccli_netr_ServerReqChallenge(cli, talloc_tos(),
+ dc->remote_machine,
+ clnt_name,
+ &clnt_chal_send,
+ &srv_chal_recv);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ /* Calculate the session key and client credentials */
+ creds_client_init(*neg_flags_inout,
+ dc,
+ &clnt_chal_send,
+ &srv_chal_recv,
+ machine_pwd,
+ &clnt_chal_send);
+
+ /*
+ * Send client auth-2 challenge and receive server repy.
+ */
+
+ result = rpccli_netr_ServerAuthenticate2(cli, talloc_tos(),
+ dc->remote_machine,
+ dc->mach_acct,
+ sec_chan_type,
+ clnt_name,
+ &clnt_chal_send, /* input. */
+ &srv_chal_recv, /* output. */
+ neg_flags_inout);
+
+ /* we might be talking to NT4, so let's downgrade in that case and retry
+ * with the returned neg_flags - gd */
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
+ retried = true;
+ goto again;
+ }
+
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ /*
+ * Check the returned value using the initial
+ * server received challenge.
+ */
+
+ if (!netlogon_creds_client_check(dc, &srv_chal_recv)) {
+ /*
+ * Server replied with bad credential. Fail.
+ */
+ DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
+ "replied with bad credential\n",
+ cli->desthost ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
+ "chain established.\n",
+ cli->desthost ));
+
+ return NT_STATUS_OK;
+}
+
+/* Logon domain user */
+
+NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 logon_parameters,
+ const char *domain,
+ const char *username,
+ const char *password,
+ const char *workstation,
+ int logon_type)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct netr_Authenticator clnt_creds;
+ struct netr_Authenticator ret_creds;
+ union netr_LogonInfo *logon;
+ union netr_Validation validation;
+ uint8_t authoritative;
+ int validation_level = 3;
+ fstring clnt_name_slash;
+ uint8 zeros[16];
+
+ ZERO_STRUCT(ret_creds);
+ ZERO_STRUCT(zeros);
+
+ logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
+ if (!logon) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (workstation) {
+ fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
+ } else {
+ fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
+ }
+
+ /* Initialise input parameters */
+
+ netlogon_creds_client_step(cli->dc, &clnt_creds);
+
+ switch (logon_type) {
+ case INTERACTIVE_LOGON_TYPE: {
+
+ struct netr_PasswordInfo *password_info;
+
+ struct samr_Password lmpassword;
+ struct samr_Password ntpassword;
+
+ unsigned char lm_owf_user_pwd[16], nt_owf_user_pwd[16];
+
+ unsigned char lm_owf[16];
+ unsigned char nt_owf[16];
+ unsigned char key[16];
+
+ password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
+ if (!password_info) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("lm cypher:"));
+ dump_data(100, lm_owf_user_pwd, 16);
+
+ DEBUG(100,("nt cypher:"));
+ dump_data(100, nt_owf_user_pwd, 16);
+#endif
+ memset(key, 0, 16);
+ memcpy(key, cli->dc->sess_key, 8);
+
+ memcpy(lm_owf, lm_owf_user_pwd, 16);
+ SamOEMhash(lm_owf, key, 16);
+ memcpy(nt_owf, nt_owf_user_pwd, 16);
+ SamOEMhash(nt_owf, key, 16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("encrypt of lm owf password:"));
+ dump_data(100, lm_owf, 16);
+
+ DEBUG(100,("encrypt of nt owf password:"));
+ dump_data(100, nt_owf, 16);
+#endif
+ memcpy(lmpassword.hash, lm_owf, 16);
+ memcpy(ntpassword.hash, nt_owf, 16);
+
+ init_netr_PasswordInfo(password_info,
+ domain,
+ logon_parameters,
+ 0xdead,
+ 0xbeef,
+ username,
+ clnt_name_slash,
+ lmpassword,
+ ntpassword);
+
+ logon->password = password_info;
+
+ break;
+ }
+ case NET_LOGON_TYPE: {
+ struct netr_NetworkInfo *network_info;
+ uint8 chal[8];
+ unsigned char local_lm_response[24];
+ unsigned char local_nt_response[24];
+ struct netr_ChallengeResponse lm;
+ struct netr_ChallengeResponse nt;
+
+ ZERO_STRUCT(lm);
+ ZERO_STRUCT(nt);
+
+ network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
+ if (!network_info) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ generate_random_buffer(chal, 8);
+
+ SMBencrypt(password, chal, local_lm_response);
+ SMBNTencrypt(password, chal, local_nt_response);
+
+ lm.length = 24;
+ lm.data = local_lm_response;
+
+ nt.length = 24;
+ nt.data = local_nt_response;
+
+ init_netr_NetworkInfo(network_info,
+ domain,
+ logon_parameters,
+ 0xdead,
+ 0xbeef,
+ username,
+ clnt_name_slash,
+ chal,
+ nt,
+ lm);
+
+ logon->network = network_info;
+
+ break;
+ }
+ default:
+ DEBUG(0, ("switch value %d not supported\n",
+ logon_type));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
+ cli->dc->remote_machine,
+ global_myname(),
+ &clnt_creds,
+ &ret_creds,
+ logon_type,
+ logon,
+ validation_level,
+ &validation,
+ &authoritative);
+
+ if (memcmp(zeros, &ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
+ /* Check returned credentials if present. */
+ if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
+ DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ return result;
+}
+
+
+/**
+ * Logon domain user with an 'network' SAM logon
+ *
+ * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
+ **/
+
+NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 logon_parameters,
+ const char *server,
+ const char *username,
+ const char *domain,
+ const char *workstation,
+ const uint8 chal[8],
+ DATA_BLOB lm_response,
+ DATA_BLOB nt_response,
+ struct netr_SamInfo3 **info3)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ int validation_level = 3;
+ const char *workstation_name_slash;
+ const char *server_name_slash;
+ uint8 zeros[16];
+ struct netr_Authenticator clnt_creds;
+ struct netr_Authenticator ret_creds;
+ union netr_LogonInfo *logon = NULL;
+ struct netr_NetworkInfo *network_info;
+ uint8_t authoritative;
+ union netr_Validation validation;
+ struct netr_ChallengeResponse lm;
+ struct netr_ChallengeResponse nt;
+
+ *info3 = NULL;
+
+ ZERO_STRUCT(zeros);
+ ZERO_STRUCT(ret_creds);
+
+ ZERO_STRUCT(lm);
+ ZERO_STRUCT(nt);
+
+ logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
+ if (!logon) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
+ if (!network_info) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ netlogon_creds_client_step(cli->dc, &clnt_creds);
+
+ if (server[0] != '\\' && server[1] != '\\') {
+ server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
+ } else {
+ server_name_slash = server;
+ }
+
+ if (workstation[0] != '\\' && workstation[1] != '\\') {
+ workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
+ } else {
+ workstation_name_slash = workstation;
+ }
+
+ if (!workstation_name_slash || !server_name_slash) {
+ DEBUG(0, ("talloc_asprintf failed!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Initialise input parameters */
+
+ lm.data = lm_response.data;
+ lm.length = lm_response.length;
+ nt.data = nt_response.data;
+ nt.length = nt_response.length;
+
+ init_netr_NetworkInfo(network_info,
+ domain,
+ logon_parameters,
+ 0xdead,
+ 0xbeef,
+ username,
+ workstation_name_slash,
+ (uint8_t *) chal,
+ nt,
+ lm);
+
+ logon->network = network_info;
+
+ /* Marshall data and send request */
+
+ result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
+ server_name_slash,
+ global_myname(),
+ &clnt_creds,
+ &ret_creds,
+ NET_LOGON_TYPE,
+ logon,
+ validation_level,
+ &validation,
+ &authoritative);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ if (memcmp(zeros, validation.sam3->base.key.key, 16) != 0) {
+ SamOEMhash(validation.sam3->base.key.key,
+ cli->dc->sess_key, 16);
+ }
+
+ if (memcmp(zeros, validation.sam3->base.LMSessKey.key, 8) != 0) {
+ SamOEMhash(validation.sam3->base.LMSessKey.key,
+ cli->dc->sess_key, 8);
+ }
+
+ if (memcmp(zeros, ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
+ /* Check returned credentials if present. */
+ if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
+ DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ *info3 = validation.sam3;
+
+ return result;
+}
+
+NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 logon_parameters,
+ const char *server,
+ const char *username,
+ const char *domain,
+ const char *workstation,
+ const uint8 chal[8],
+ DATA_BLOB lm_response,
+ DATA_BLOB nt_response,
+ struct netr_SamInfo3 **info3)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ int validation_level = 3;
+ const char *workstation_name_slash;
+ const char *server_name_slash;
+ uint8 zeros[16];
+ union netr_LogonInfo *logon = NULL;
+ struct netr_NetworkInfo *network_info;
+ uint8_t authoritative;
+ union netr_Validation validation;
+ struct netr_ChallengeResponse lm;
+ struct netr_ChallengeResponse nt;
+ uint32_t flags = 0;
+
+ *info3 = NULL;
+
+ ZERO_STRUCT(zeros);
+
+ ZERO_STRUCT(lm);
+ ZERO_STRUCT(nt);
+
+ logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
+ if (!logon) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
+ if (!network_info) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (server[0] != '\\' && server[1] != '\\') {
+ server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
+ } else {
+ server_name_slash = server;
+ }
+
+ if (workstation[0] != '\\' && workstation[1] != '\\') {
+ workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
+ } else {
+ workstation_name_slash = workstation;
+ }
+
+ if (!workstation_name_slash || !server_name_slash) {
+ DEBUG(0, ("talloc_asprintf failed!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Initialise input parameters */
+
+ lm.data = lm_response.data;
+ lm.length = lm_response.length;
+ nt.data = nt_response.data;
+ nt.length = nt_response.length;
+
+ init_netr_NetworkInfo(network_info,
+ domain,
+ logon_parameters,
+ 0xdead,
+ 0xbeef,
+ username,
+ workstation_name_slash,
+ (uint8_t *) chal,
+ nt,
+ lm);
+
+ logon->network = network_info;
+
+ /* Marshall data and send request */
+
+ result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
+ server_name_slash,
+ global_myname(),
+ NET_LOGON_TYPE,
+ logon,
+ validation_level,
+ &validation,
+ &authoritative,
+ &flags);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ if (memcmp(zeros, validation.sam3->base.key.key, 16) != 0) {
+ SamOEMhash(validation.sam3->base.key.key,
+ cli->dc->sess_key, 16);
+ }
+
+ if (memcmp(zeros, validation.sam3->base.LMSessKey.key, 8) != 0) {
+ SamOEMhash(validation.sam3->base.LMSessKey.key,
+ cli->dc->sess_key, 8);
+ }
+
+ *info3 = validation.sam3;
+
+ return result;
+}
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
new file mode 100644
index 0000000000..f32a33fdb6
--- /dev/null
+++ b/source3/rpc_client/cli_pipe.c
@@ -0,0 +1,3451 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Largely rewritten by Jeremy Allison 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/cli_epmapper.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_CLI
+
+/*******************************************************************
+interface/version dce/rpc pipe identification
+********************************************************************/
+
+#define PIPE_SRVSVC "\\PIPE\\srvsvc"
+#define PIPE_SAMR "\\PIPE\\samr"
+#define PIPE_WINREG "\\PIPE\\winreg"
+#define PIPE_WKSSVC "\\PIPE\\wkssvc"
+#define PIPE_NETLOGON "\\PIPE\\NETLOGON"
+#define PIPE_NTLSA "\\PIPE\\ntlsa"
+#define PIPE_NTSVCS "\\PIPE\\ntsvcs"
+#define PIPE_LSASS "\\PIPE\\lsass"
+#define PIPE_LSARPC "\\PIPE\\lsarpc"
+#define PIPE_SPOOLSS "\\PIPE\\spoolss"
+#define PIPE_NETDFS "\\PIPE\\netdfs"
+#define PIPE_ECHO "\\PIPE\\rpcecho"
+#define PIPE_SHUTDOWN "\\PIPE\\initshutdown"
+#define PIPE_EPM "\\PIPE\\epmapper"
+#define PIPE_SVCCTL "\\PIPE\\svcctl"
+#define PIPE_EVENTLOG "\\PIPE\\eventlog"
+#define PIPE_EPMAPPER "\\PIPE\\epmapper"
+#define PIPE_DRSUAPI "\\PIPE\\drsuapi"
+
+/*
+ * IMPORTANT!! If you update this structure, make sure to
+ * update the index #defines in smb.h.
+ */
+
+static const struct pipe_id_info {
+ /* the names appear not to matter: the syntaxes _do_ matter */
+
+ const char *client_pipe;
+ const RPC_IFACE *abstr_syntax; /* this one is the abstract syntax id */
+} pipe_names [] =
+{
+ { PIPE_LSARPC, &ndr_table_lsarpc.syntax_id },
+ { PIPE_LSARPC, &ndr_table_dssetup.syntax_id },
+ { PIPE_SAMR, &ndr_table_samr.syntax_id },
+ { PIPE_NETLOGON, &ndr_table_netlogon.syntax_id },
+ { PIPE_SRVSVC, &ndr_table_srvsvc.syntax_id },
+ { PIPE_WKSSVC, &ndr_table_wkssvc.syntax_id },
+ { PIPE_WINREG, &ndr_table_winreg.syntax_id },
+ { PIPE_SPOOLSS, &syntax_spoolss },
+ { PIPE_NETDFS, &ndr_table_netdfs.syntax_id },
+ { PIPE_ECHO, &ndr_table_rpcecho.syntax_id },
+ { PIPE_SHUTDOWN, &ndr_table_initshutdown.syntax_id },
+ { PIPE_SVCCTL, &ndr_table_svcctl.syntax_id },
+ { PIPE_EVENTLOG, &ndr_table_eventlog.syntax_id },
+ { PIPE_NTSVCS, &ndr_table_ntsvcs.syntax_id },
+ { PIPE_EPMAPPER, &ndr_table_epmapper.syntax_id },
+ { PIPE_DRSUAPI, &ndr_table_drsuapi.syntax_id },
+ { NULL, NULL }
+};
+
+/****************************************************************************
+ Return the pipe name from the interface.
+ ****************************************************************************/
+
+const char *cli_get_pipe_name_from_iface(TALLOC_CTX *mem_ctx,
+ struct cli_state *cli,
+ const struct ndr_syntax_id *interface)
+{
+ int i;
+ for (i = 0; pipe_names[i].client_pipe; i++) {
+ if (ndr_syntax_id_equal(pipe_names[i].abstr_syntax,
+ interface)) {
+ return &pipe_names[i].client_pipe[5];
+ }
+ }
+
+ /*
+ * Here we should ask \\epmapper, but for now our code is only
+ * interested in the known pipes mentioned in pipe_names[]
+ */
+
+ return NULL;
+}
+
+/********************************************************************
+ Map internal value to wire value.
+ ********************************************************************/
+
+static int map_pipe_auth_type_to_rpc_auth_type(enum pipe_auth_type auth_type)
+{
+ switch (auth_type) {
+
+ case PIPE_AUTH_TYPE_NONE:
+ return RPC_ANONYMOUS_AUTH_TYPE;
+
+ case PIPE_AUTH_TYPE_NTLMSSP:
+ return RPC_NTLMSSP_AUTH_TYPE;
+
+ case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP:
+ case PIPE_AUTH_TYPE_SPNEGO_KRB5:
+ return RPC_SPNEGO_AUTH_TYPE;
+
+ case PIPE_AUTH_TYPE_SCHANNEL:
+ return RPC_SCHANNEL_AUTH_TYPE;
+
+ case PIPE_AUTH_TYPE_KRB5:
+ return RPC_KRB5_AUTH_TYPE;
+
+ default:
+ DEBUG(0,("map_pipe_auth_type_to_rpc_type: unknown pipe "
+ "auth type %u\n",
+ (unsigned int)auth_type ));
+ break;
+ }
+ return -1;
+}
+
+/********************************************************************
+ Pipe description for a DEBUG
+ ********************************************************************/
+static char *rpccli_pipe_txt(TALLOC_CTX *mem_ctx, struct rpc_pipe_client *cli)
+{
+ char *result;
+
+ switch (cli->transport_type) {
+ case NCACN_NP:
+ result = talloc_asprintf(mem_ctx, "host %s, pipe %s, "
+ "fnum 0x%x",
+ cli->desthost,
+ cli->trans.np.pipe_name,
+ (unsigned int)(cli->trans.np.fnum));
+ break;
+ case NCACN_IP_TCP:
+ case NCACN_UNIX_STREAM:
+ result = talloc_asprintf(mem_ctx, "host %s, fd %d",
+ cli->desthost, cli->trans.sock.fd);
+ break;
+ default:
+ result = talloc_asprintf(mem_ctx, "host %s", cli->desthost);
+ break;
+ }
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+/********************************************************************
+ Rpc pipe call id.
+ ********************************************************************/
+
+static uint32 get_rpc_call_id(void)
+{
+ static uint32 call_id = 0;
+ return ++call_id;
+}
+
+/*******************************************************************
+ Read from a RPC named pipe
+ ********************************************************************/
+static NTSTATUS rpc_read_np(struct cli_state *cli, const char *pipe_name,
+ int fnum, char *buf, off_t offset, size_t size,
+ ssize_t *pnum_read)
+{
+ ssize_t num_read;
+
+ num_read = cli_read(cli, fnum, buf, offset, size);
+
+ DEBUG(5,("rpc_read_np: num_read = %d, read offset: %u, to read: %u\n",
+ (int)num_read, (unsigned int)offset, (unsigned int)size));
+
+ /*
+ * A dos error of ERRDOS/ERRmoredata is not an error.
+ */
+ if (cli_is_dos_error(cli)) {
+ uint32 ecode;
+ uint8 eclass;
+ cli_dos_error(cli, &eclass, &ecode);
+ if (eclass != ERRDOS && ecode != ERRmoredata) {
+ DEBUG(0,("rpc_read: DOS Error %d/%u (%s) in cli_read "
+ "on fnum 0x%x\n", eclass, (unsigned int)ecode,
+ cli_errstr(cli), fnum));
+ return dos_to_ntstatus(eclass, ecode);
+ }
+ }
+
+ /*
+ * Likewise for NT_STATUS_BUFFER_TOO_SMALL
+ */
+ if (cli_is_nt_error(cli)) {
+ if (!NT_STATUS_EQUAL(cli_nt_error(cli),
+ NT_STATUS_BUFFER_TOO_SMALL)) {
+ DEBUG(0,("rpc_read: Error (%s) in cli_read on fnum "
+ "0x%x\n", nt_errstr(cli_nt_error(cli)), fnum));
+ return cli_nt_error(cli);
+ }
+ }
+
+ if (num_read == -1) {
+ DEBUG(0,("rpc_read: Error - cli_read on fnum 0x%x returned "
+ "-1\n", fnum));
+ return cli_get_nt_error(cli);
+ }
+
+ *pnum_read = num_read;
+ return NT_STATUS_OK;
+}
+
+
+/*******************************************************************
+ Use SMBreadX to get rest of one fragment's worth of rpc data.
+ Will expand the current_pdu struct to the correct size.
+ ********************************************************************/
+
+static NTSTATUS rpc_read(struct rpc_pipe_client *cli,
+ prs_struct *current_pdu,
+ uint32 data_to_read,
+ uint32 *current_pdu_offset)
+{
+ size_t size = (size_t)cli->max_recv_frag;
+ uint32 stream_offset = 0;
+ ssize_t num_read = 0;
+ char *pdata;
+ ssize_t extra_data_size = ((ssize_t)*current_pdu_offset) + ((ssize_t)data_to_read) - (ssize_t)prs_data_size(current_pdu);
+
+ DEBUG(5,("rpc_read: data_to_read: %u current_pdu offset: %u extra_data_size: %d\n",
+ (unsigned int)data_to_read, (unsigned int)*current_pdu_offset, (int)extra_data_size ));
+
+ /*
+ * Grow the buffer if needed to accommodate the data to be read.
+ */
+
+ if (extra_data_size > 0) {
+ if(!prs_force_grow(current_pdu, (uint32)extra_data_size)) {
+ DEBUG(0,("rpc_read: Failed to grow parse struct by %d bytes.\n", (int)extra_data_size ));
+ return NT_STATUS_NO_MEMORY;
+ }
+ DEBUG(5,("rpc_read: grew buffer by %d bytes to %u\n", (int)extra_data_size, prs_data_size(current_pdu) ));
+ }
+
+ pdata = prs_data_p(current_pdu) + *current_pdu_offset;
+
+ do {
+ NTSTATUS status;
+
+ /* read data using SMBreadX */
+ if (size > (size_t)data_to_read) {
+ size = (size_t)data_to_read;
+ }
+
+ switch (cli->transport_type) {
+ case NCACN_NP:
+ status = rpc_read_np(cli->trans.np.cli,
+ cli->trans.np.pipe_name,
+ cli->trans.np.fnum, pdata,
+ (off_t)stream_offset, size,
+ &num_read);
+ break;
+ case NCACN_IP_TCP:
+ case NCACN_UNIX_STREAM:
+ status = NT_STATUS_OK;
+ num_read = sys_read(cli->trans.sock.fd, pdata, size);
+ if (num_read == -1) {
+ status = map_nt_error_from_unix(errno);
+ }
+ if (num_read == 0) {
+ status = NT_STATUS_END_OF_FILE;
+ }
+ break;
+ default:
+ DEBUG(0, ("unknown transport type %d\n",
+ cli->transport_type));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ data_to_read -= num_read;
+ stream_offset += num_read;
+ pdata += num_read;
+
+ } while (num_read > 0 && data_to_read > 0);
+ /* && err == (0x80000000 | STATUS_BUFFER_OVERFLOW)); */
+
+ /*
+ * Update the current offset into current_pdu by the amount read.
+ */
+ *current_pdu_offset += stream_offset;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Try and get a PDU's worth of data from current_pdu. If not, then read more
+ from the wire.
+ ****************************************************************************/
+
+static NTSTATUS cli_pipe_get_current_pdu(struct rpc_pipe_client *cli, RPC_HDR *prhdr, prs_struct *current_pdu)
+{
+ NTSTATUS ret = NT_STATUS_OK;
+ uint32 current_pdu_len = prs_data_size(current_pdu);
+
+ /* Ensure we have at least RPC_HEADER_LEN worth of data to parse. */
+ if (current_pdu_len < RPC_HEADER_LEN) {
+ /* rpc_read expands the current_pdu struct as neccessary. */
+ ret = rpc_read(cli, current_pdu, RPC_HEADER_LEN - current_pdu_len, &current_pdu_len);
+ if (!NT_STATUS_IS_OK(ret)) {
+ return ret;
+ }
+ }
+
+ /* This next call sets the endian bit correctly in current_pdu. */
+ /* We will propagate this to rbuf later. */
+ if(!smb_io_rpc_hdr("rpc_hdr ", prhdr, current_pdu, 0)) {
+ DEBUG(0,("cli_pipe_get_current_pdu: Failed to unmarshall RPC_HDR.\n"));
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /* Ensure we have frag_len bytes of data. */
+ if (current_pdu_len < prhdr->frag_len) {
+ /* rpc_read expands the current_pdu struct as neccessary. */
+ ret = rpc_read(cli, current_pdu, (uint32)prhdr->frag_len - current_pdu_len, &current_pdu_len);
+ if (!NT_STATUS_IS_OK(ret)) {
+ return ret;
+ }
+ }
+
+ if (current_pdu_len < prhdr->frag_len) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ NTLMSSP specific sign/seal.
+ Virtually identical to rpc_server/srv_pipe.c:api_pipe_ntlmssp_auth_process.
+ In fact I should probably abstract these into identical pieces of code... JRA.
+ ****************************************************************************/
+
+static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, RPC_HDR *prhdr,
+ prs_struct *current_pdu,
+ uint8 *p_ss_padding_len)
+{
+ RPC_HDR_AUTH auth_info;
+ uint32 save_offset = prs_offset(current_pdu);
+ uint32 auth_len = prhdr->auth_len;
+ NTLMSSP_STATE *ntlmssp_state = cli->auth->a_u.ntlmssp_state;
+ unsigned char *data = NULL;
+ size_t data_len;
+ unsigned char *full_packet_data = NULL;
+ size_t full_packet_data_len;
+ DATA_BLOB auth_blob;
+ NTSTATUS status;
+
+ if (cli->auth->auth_level == PIPE_AUTH_LEVEL_NONE
+ || cli->auth->auth_level == PIPE_AUTH_LEVEL_CONNECT) {
+ return NT_STATUS_OK;
+ }
+
+ if (!ntlmssp_state) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Ensure there's enough data for an authenticated response. */
+ if ((auth_len > RPC_MAX_SIGN_SIZE) ||
+ (RPC_HEADER_LEN + RPC_HDR_RESP_LEN + RPC_HDR_AUTH_LEN + auth_len > prhdr->frag_len)) {
+ DEBUG(0,("cli_pipe_verify_ntlmssp: auth_len %u is too large.\n",
+ (unsigned int)auth_len ));
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /*
+ * We need the full packet data + length (minus auth stuff) as well as the packet data + length
+ * after the RPC header.
+ * We need to pass in the full packet (minus auth len) to the NTLMSSP sign and check seal
+ * functions as NTLMv2 checks the rpc headers also.
+ */
+
+ data = (unsigned char *)(prs_data_p(current_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN);
+ data_len = (size_t)(prhdr->frag_len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN - auth_len);
+
+ full_packet_data = (unsigned char *)prs_data_p(current_pdu);
+ full_packet_data_len = prhdr->frag_len - auth_len;
+
+ /* Pull the auth header and the following data into a blob. */
+ if(!prs_set_offset(current_pdu, RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len)) {
+ DEBUG(0,("cli_pipe_verify_ntlmssp: cannot move offset to %u.\n",
+ (unsigned int)RPC_HEADER_LEN + (unsigned int)RPC_HDR_RESP_LEN + (unsigned int)data_len ));
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, current_pdu, 0)) {
+ DEBUG(0,("cli_pipe_verify_ntlmssp: failed to unmarshall RPC_HDR_AUTH.\n"));
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ auth_blob.data = (unsigned char *)prs_data_p(current_pdu) + prs_offset(current_pdu);
+ auth_blob.length = auth_len;
+
+ switch (cli->auth->auth_level) {
+ case PIPE_AUTH_LEVEL_PRIVACY:
+ /* Data is encrypted. */
+ status = ntlmssp_unseal_packet(ntlmssp_state,
+ data, data_len,
+ full_packet_data,
+ full_packet_data_len,
+ &auth_blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("cli_pipe_verify_ntlmssp: failed to unseal "
+ "packet from %s. Error was %s.\n",
+ rpccli_pipe_txt(debug_ctx(), cli),
+ nt_errstr(status) ));
+ return status;
+ }
+ break;
+ case PIPE_AUTH_LEVEL_INTEGRITY:
+ /* Data is signed. */
+ status = ntlmssp_check_packet(ntlmssp_state,
+ data, data_len,
+ full_packet_data,
+ full_packet_data_len,
+ &auth_blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("cli_pipe_verify_ntlmssp: check signing failed on "
+ "packet from %s. Error was %s.\n",
+ rpccli_pipe_txt(debug_ctx(), cli),
+ nt_errstr(status) ));
+ return status;
+ }
+ break;
+ default:
+ DEBUG(0, ("cli_pipe_verify_ntlmssp: unknown internal "
+ "auth level %d\n", cli->auth->auth_level));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ /*
+ * Return the current pointer to the data offset.
+ */
+
+ if(!prs_set_offset(current_pdu, save_offset)) {
+ DEBUG(0,("api_pipe_auth_process: failed to set offset back to %u\n",
+ (unsigned int)save_offset ));
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /*
+ * Remember the padding length. We must remove it from the real data
+ * stream once the sign/seal is done.
+ */
+
+ *p_ss_padding_len = auth_info.auth_pad_len;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ schannel specific sign/seal.
+ ****************************************************************************/
+
+static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *prhdr,
+ prs_struct *current_pdu,
+ uint8 *p_ss_padding_len)
+{
+ RPC_HDR_AUTH auth_info;
+ RPC_AUTH_SCHANNEL_CHK schannel_chk;
+ uint32 auth_len = prhdr->auth_len;
+ uint32 save_offset = prs_offset(current_pdu);
+ struct schannel_auth_struct *schannel_auth =
+ cli->auth->a_u.schannel_auth;
+ uint32 data_len;
+
+ if (cli->auth->auth_level == PIPE_AUTH_LEVEL_NONE
+ || cli->auth->auth_level == PIPE_AUTH_LEVEL_CONNECT) {
+ return NT_STATUS_OK;
+ }
+
+ if (auth_len != RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN) {
+ DEBUG(0,("cli_pipe_verify_schannel: auth_len %u.\n", (unsigned int)auth_len ));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!schannel_auth) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Ensure there's enough data for an authenticated response. */
+ if ((auth_len > RPC_MAX_SIGN_SIZE) ||
+ (RPC_HEADER_LEN + RPC_HDR_RESP_LEN + RPC_HDR_AUTH_LEN + auth_len > prhdr->frag_len)) {
+ DEBUG(0,("cli_pipe_verify_schannel: auth_len %u is too large.\n",
+ (unsigned int)auth_len ));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ data_len = prhdr->frag_len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN - auth_len;
+
+ if(!prs_set_offset(current_pdu, RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len)) {
+ DEBUG(0,("cli_pipe_verify_schannel: cannot move offset to %u.\n",
+ (unsigned int)RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len ));
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, current_pdu, 0)) {
+ DEBUG(0,("cli_pipe_verify_schannel: failed to unmarshall RPC_HDR_AUTH.\n"));
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if (auth_info.auth_type != RPC_SCHANNEL_AUTH_TYPE) {
+ DEBUG(0,("cli_pipe_verify_schannel: Invalid auth info %d on schannel\n",
+ auth_info.auth_type));
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if(!smb_io_rpc_auth_schannel_chk("", RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN,
+ &schannel_chk, current_pdu, 0)) {
+ DEBUG(0,("cli_pipe_verify_schannel: failed to unmarshal RPC_AUTH_SCHANNEL_CHK.\n"));
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if (!schannel_decode(schannel_auth,
+ cli->auth->auth_level,
+ SENDER_IS_ACCEPTOR,
+ &schannel_chk,
+ prs_data_p(current_pdu)+RPC_HEADER_LEN+RPC_HDR_RESP_LEN,
+ data_len)) {
+ DEBUG(3,("cli_pipe_verify_schannel: failed to decode PDU "
+ "Connection to %s.\n",
+ rpccli_pipe_txt(debug_ctx(), cli)));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* The sequence number gets incremented on both send and receive. */
+ schannel_auth->seq_num++;
+
+ /*
+ * Return the current pointer to the data offset.
+ */
+
+ if(!prs_set_offset(current_pdu, save_offset)) {
+ DEBUG(0,("api_pipe_auth_process: failed to set offset back to %u\n",
+ (unsigned int)save_offset ));
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /*
+ * Remember the padding length. We must remove it from the real data
+ * stream once the sign/seal is done.
+ */
+
+ *p_ss_padding_len = auth_info.auth_pad_len;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Do the authentication checks on an incoming pdu. Check sign and unseal etc.
+ ****************************************************************************/
+
+static NTSTATUS cli_pipe_validate_rpc_response(struct rpc_pipe_client *cli, RPC_HDR *prhdr,
+ prs_struct *current_pdu,
+ uint8 *p_ss_padding_len)
+{
+ NTSTATUS ret = NT_STATUS_OK;
+
+ /* Paranioa checks for auth_len. */
+ if (prhdr->auth_len) {
+ if (prhdr->auth_len > prhdr->frag_len) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (prhdr->auth_len + (unsigned int)RPC_HDR_AUTH_LEN < prhdr->auth_len ||
+ prhdr->auth_len + (unsigned int)RPC_HDR_AUTH_LEN < (unsigned int)RPC_HDR_AUTH_LEN) {
+ /* Integer wrap attempt. */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ /*
+ * Now we have a complete RPC request PDU fragment, try and verify any auth data.
+ */
+
+ switch(cli->auth->auth_type) {
+ case PIPE_AUTH_TYPE_NONE:
+ if (prhdr->auth_len) {
+ DEBUG(3, ("cli_pipe_validate_rpc_response: "
+ "Connection to %s - got non-zero "
+ "auth len %u.\n",
+ rpccli_pipe_txt(debug_ctx(), cli),
+ (unsigned int)prhdr->auth_len ));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ break;
+
+ case PIPE_AUTH_TYPE_NTLMSSP:
+ case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP:
+ ret = cli_pipe_verify_ntlmssp(cli, prhdr, current_pdu, p_ss_padding_len);
+ if (!NT_STATUS_IS_OK(ret)) {
+ return ret;
+ }
+ break;
+
+ case PIPE_AUTH_TYPE_SCHANNEL:
+ ret = cli_pipe_verify_schannel(cli, prhdr, current_pdu, p_ss_padding_len);
+ if (!NT_STATUS_IS_OK(ret)) {
+ return ret;
+ }
+ break;
+
+ case PIPE_AUTH_TYPE_KRB5:
+ case PIPE_AUTH_TYPE_SPNEGO_KRB5:
+ default:
+ DEBUG(3, ("cli_pipe_validate_rpc_response: Connection "
+ "to %s - unknown internal auth type %u.\n",
+ rpccli_pipe_txt(debug_ctx(), cli),
+ cli->auth->auth_type ));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Do basic authentication checks on an incoming pdu.
+ ****************************************************************************/
+
+static NTSTATUS cli_pipe_validate_current_pdu(struct rpc_pipe_client *cli, RPC_HDR *prhdr,
+ prs_struct *current_pdu,
+ uint8 expected_pkt_type,
+ char **ppdata,
+ uint32 *pdata_len,
+ prs_struct *return_data)
+{
+
+ NTSTATUS ret = NT_STATUS_OK;
+ uint32 current_pdu_len = prs_data_size(current_pdu);
+
+ if (current_pdu_len != prhdr->frag_len) {
+ DEBUG(5,("cli_pipe_validate_current_pdu: incorrect pdu length %u, expected %u\n",
+ (unsigned int)current_pdu_len, (unsigned int)prhdr->frag_len ));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /*
+ * Point the return values at the real data including the RPC
+ * header. Just in case the caller wants it.
+ */
+ *ppdata = prs_data_p(current_pdu);
+ *pdata_len = current_pdu_len;
+
+ /* Ensure we have the correct type. */
+ switch (prhdr->pkt_type) {
+ case RPC_ALTCONTRESP:
+ case RPC_BINDACK:
+
+ /* Alter context and bind ack share the same packet definitions. */
+ break;
+
+
+ case RPC_RESPONSE:
+ {
+ RPC_HDR_RESP rhdr_resp;
+ uint8 ss_padding_len = 0;
+
+ if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, current_pdu, 0)) {
+ DEBUG(5,("cli_pipe_validate_current_pdu: failed to unmarshal RPC_HDR_RESP.\n"));
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /* Here's where we deal with incoming sign/seal. */
+ ret = cli_pipe_validate_rpc_response(cli, prhdr,
+ current_pdu, &ss_padding_len);
+ if (!NT_STATUS_IS_OK(ret)) {
+ return ret;
+ }
+
+ /* Point the return values at the NDR data. Remember to remove any ss padding. */
+ *ppdata = prs_data_p(current_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN;
+
+ if (current_pdu_len < RPC_HEADER_LEN + RPC_HDR_RESP_LEN + ss_padding_len) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ *pdata_len = current_pdu_len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN - ss_padding_len;
+
+ /* Remember to remove the auth footer. */
+ if (prhdr->auth_len) {
+ /* We've already done integer wrap tests on auth_len in
+ cli_pipe_validate_rpc_response(). */
+ if (*pdata_len < RPC_HDR_AUTH_LEN + prhdr->auth_len) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+ *pdata_len -= (RPC_HDR_AUTH_LEN + prhdr->auth_len);
+ }
+
+ DEBUG(10,("cli_pipe_validate_current_pdu: got pdu len %u, data_len %u, ss_len %u\n",
+ current_pdu_len, *pdata_len, ss_padding_len ));
+
+ /*
+ * If this is the first reply, and the allocation hint is reasonably, try and
+ * set up the return_data parse_struct to the correct size.
+ */
+
+ if ((prs_data_size(return_data) == 0) && rhdr_resp.alloc_hint && (rhdr_resp.alloc_hint < 15*1024*1024)) {
+ if (!prs_set_buffer_size(return_data, rhdr_resp.alloc_hint)) {
+ DEBUG(0,("cli_pipe_validate_current_pdu: reply alloc hint %u "
+ "too large to allocate\n",
+ (unsigned int)rhdr_resp.alloc_hint ));
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ break;
+ }
+
+ case RPC_BINDNACK:
+ DEBUG(1, ("cli_pipe_validate_current_pdu: Bind NACK "
+ "received from %s!\n",
+ rpccli_pipe_txt(debug_ctx(), cli)));
+ /* Use this for now... */
+ return NT_STATUS_NETWORK_ACCESS_DENIED;
+
+ case RPC_FAULT:
+ {
+ RPC_HDR_RESP rhdr_resp;
+ RPC_HDR_FAULT fault_resp;
+
+ if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, current_pdu, 0)) {
+ DEBUG(5,("cli_pipe_validate_current_pdu: failed to unmarshal RPC_HDR_RESP.\n"));
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if(!smb_io_rpc_hdr_fault("fault", &fault_resp, current_pdu, 0)) {
+ DEBUG(5,("cli_pipe_validate_current_pdu: failed to unmarshal RPC_HDR_FAULT.\n"));
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ DEBUG(1, ("cli_pipe_validate_current_pdu: RPC fault "
+ "code %s received from %s!\n",
+ dcerpc_errstr(NT_STATUS_V(fault_resp.status)),
+ rpccli_pipe_txt(debug_ctx(), cli)));
+ if (NT_STATUS_IS_OK(fault_resp.status)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ } else {
+ return fault_resp.status;
+ }
+ }
+
+ default:
+ DEBUG(0, ("cli_pipe_validate_current_pdu: unknown packet type %u received "
+ "from %s!\n",
+ (unsigned int)prhdr->pkt_type,
+ rpccli_pipe_txt(debug_ctx(), cli)));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ if (prhdr->pkt_type != expected_pkt_type) {
+ DEBUG(3, ("cli_pipe_validate_current_pdu: Connection to %s "
+ "got an unexpected RPC packet type - %u, not %u\n",
+ rpccli_pipe_txt(debug_ctx(), cli),
+ prhdr->pkt_type,
+ expected_pkt_type));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ /* Do this just before return - we don't want to modify any rpc header
+ data before now as we may have needed to do cryptographic actions on
+ it before. */
+
+ if ((prhdr->pkt_type == RPC_BINDACK) && !(prhdr->flags & RPC_FLG_LAST)) {
+ DEBUG(5,("cli_pipe_validate_current_pdu: bug in server (AS/U?), "
+ "setting fragment first/last ON.\n"));
+ prhdr->flags |= RPC_FLG_FIRST|RPC_FLG_LAST;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Ensure we eat the just processed pdu from the current_pdu prs_struct.
+ Normally the frag_len and buffer size will match, but on the first trans
+ reply there is a theoretical chance that buffer size > frag_len, so we must
+ deal with that.
+ ****************************************************************************/
+
+static NTSTATUS cli_pipe_reset_current_pdu(struct rpc_pipe_client *cli, RPC_HDR *prhdr, prs_struct *current_pdu)
+{
+ uint32 current_pdu_len = prs_data_size(current_pdu);
+
+ if (current_pdu_len < prhdr->frag_len) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /* Common case. */
+ if (current_pdu_len == (uint32)prhdr->frag_len) {
+ prs_mem_free(current_pdu);
+ prs_init_empty(current_pdu, prs_get_mem_context(current_pdu), UNMARSHALL);
+ /* Make current_pdu dynamic with no memory. */
+ prs_give_memory(current_pdu, 0, 0, True);
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * Oh no ! More data in buffer than we processed in current pdu.
+ * Cheat. Move the data down and shrink the buffer.
+ */
+
+ memcpy(prs_data_p(current_pdu), prs_data_p(current_pdu) + prhdr->frag_len,
+ current_pdu_len - prhdr->frag_len);
+
+ /* Remember to set the read offset back to zero. */
+ prs_set_offset(current_pdu, 0);
+
+ /* Shrink the buffer. */
+ if (!prs_set_buffer_size(current_pdu, current_pdu_len - prhdr->frag_len)) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Send data on an rpc pipe via trans. The prs_struct data must be the last
+ pdu fragment of an NDR data stream.
+
+ Receive response data from an rpc pipe, which may be large...
+
+ Read the first fragment: unfortunately have to use SMBtrans for the first
+ bit, then SMBreadX for subsequent bits.
+
+ If first fragment received also wasn't the last fragment, continue
+ getting fragments until we _do_ receive the last fragment.
+
+ Request/Response PDU's look like the following...
+
+ |<------------------PDU len----------------------------------------------->|
+ |<-HDR_LEN-->|<--REQ LEN------>|.............|<-AUTH_HDRLEN->|<-AUTH_LEN-->|
+
+ +------------+-----------------+-------------+---------------+-------------+
+ | RPC HEADER | REQ/RESP HEADER | DATA ...... | AUTH_HDR | AUTH DATA |
+ +------------+-----------------+-------------+---------------+-------------+
+
+ Where the presence of the AUTH_HDR and AUTH DATA are dependent on the
+ signing & sealing being negotiated.
+
+ ****************************************************************************/
+
+static NTSTATUS rpc_api_pipe(struct rpc_pipe_client *cli,
+ prs_struct *data, /* Outgoing pdu fragment, already formatted for send. */
+ prs_struct *rbuf, /* Incoming reply - return as an NDR stream. */
+ uint8 expected_pkt_type)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ char *rparam = NULL;
+ uint32 rparam_len = 0;
+ char *pdata = prs_data_p(data);
+ uint32 data_len = prs_offset(data);
+ char *prdata = NULL;
+ uint32 rdata_len = 0;
+ uint32 max_data = cli->max_xmit_frag ? cli->max_xmit_frag : RPC_MAX_PDU_FRAG_LEN;
+ uint32 current_rbuf_offset = 0;
+ prs_struct current_pdu;
+
+#ifdef DEVELOPER
+ /* Ensure we're not sending too much. */
+ SMB_ASSERT(data_len <= max_data);
+#endif
+
+ /* Set up the current pdu parse struct. */
+ prs_init_empty(&current_pdu, prs_get_mem_context(rbuf), UNMARSHALL);
+
+ DEBUG(5,("rpc_api_pipe: %s\n", rpccli_pipe_txt(debug_ctx(), cli)));
+
+ switch (cli->transport_type) {
+ case NCACN_NP: {
+ uint16 setup[2];
+ /* Create setup parameters - must be in native byte order. */
+ setup[0] = TRANSACT_DCERPCCMD;
+ setup[1] = cli->trans.np.fnum; /* Pipe file handle. */
+
+ /*
+ * Send the last (or only) fragment of an RPC request. For
+ * small amounts of data (about 1024 bytes or so) the RPC
+ * request and response appears in a SMBtrans request and
+ * response.
+ */
+
+ if (!cli_api_pipe(cli->trans.np.cli, "\\PIPE\\",
+ setup, 2, 0, /* Setup, length, max */
+ NULL, 0, 0, /* Params, length, max */
+ pdata, data_len, max_data, /* data, length,
+ * max */
+ &rparam, &rparam_len, /* return params,
+ * len */
+ &prdata, &rdata_len)) /* return data, len */
+ {
+ DEBUG(0, ("rpc_api_pipe: %s returned critical error. "
+ "Error was %s\n",
+ rpccli_pipe_txt(debug_ctx(), cli),
+ cli_errstr(cli->trans.np.cli)));
+ ret = cli_get_nt_error(cli->trans.np.cli);
+ SAFE_FREE(rparam);
+ SAFE_FREE(prdata);
+ goto err;
+ }
+ break;
+ }
+ case NCACN_IP_TCP:
+ case NCACN_UNIX_STREAM:
+ {
+ ssize_t nwritten, nread;
+ nwritten = write_data(cli->trans.sock.fd, pdata, data_len);
+ if (nwritten == -1) {
+ ret = map_nt_error_from_unix(errno);
+ DEBUG(0, ("rpc_api_pipe: write_data returned %s\n",
+ strerror(errno)));
+ goto err;
+ }
+ rparam = NULL;
+ prdata = SMB_MALLOC_ARRAY(char, 1);
+ if (prdata == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ nread = sys_read(cli->trans.sock.fd, prdata, 1);
+ if (nread == 0) {
+ SAFE_FREE(prdata);
+ }
+ if (nread == -1) {
+ ret = NT_STATUS_END_OF_FILE;
+ goto err;
+ }
+ rdata_len = nread;
+ break;
+ }
+ default:
+ DEBUG(0, ("unknown transport type %d\n",
+ cli->transport_type));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /* Throw away returned params - we know we won't use them. */
+
+ SAFE_FREE(rparam);
+
+ if (prdata == NULL) {
+ DEBUG(3,("rpc_api_pipe: %s failed to return data.\n",
+ rpccli_pipe_txt(debug_ctx(), cli)));
+ /* Yes - some calls can truely return no data... */
+ prs_mem_free(&current_pdu);
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * Give this memory as dynamic to the current pdu.
+ */
+
+ prs_give_memory(&current_pdu, prdata, rdata_len, True);
+
+ /* Ensure we can mess with the return prs_struct. */
+ SMB_ASSERT(UNMARSHALLING(rbuf));
+ SMB_ASSERT(prs_data_size(rbuf) == 0);
+
+ /* Make rbuf dynamic with no memory. */
+ prs_give_memory(rbuf, 0, 0, True);
+
+ while(1) {
+ RPC_HDR rhdr;
+ char *ret_data = NULL;
+ uint32 ret_data_len = 0;
+
+ /* Ensure we have enough data for a pdu. */
+ ret = cli_pipe_get_current_pdu(cli, &rhdr, &current_pdu);
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto err;
+ }
+
+ /* We pass in rbuf here so if the alloc hint is set correctly
+ we can set the output size and avoid reallocs. */
+
+ ret = cli_pipe_validate_current_pdu(cli, &rhdr, &current_pdu, expected_pkt_type,
+ &ret_data, &ret_data_len, rbuf);
+
+ DEBUG(10,("rpc_api_pipe: got PDU len of %u at offset %u\n",
+ prs_data_size(&current_pdu), current_rbuf_offset ));
+
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto err;
+ }
+
+ if ((rhdr.flags & RPC_FLG_FIRST)) {
+ if (rhdr.pack_type[0] == 0) {
+ /* Set the data type correctly for big-endian data on the first packet. */
+ DEBUG(10,("rpc_api_pipe: On %s "
+ "PDU data format is big-endian.\n",
+ rpccli_pipe_txt(debug_ctx(), cli)));
+
+ prs_set_endian_data(rbuf, RPC_BIG_ENDIAN);
+ } else {
+ /* Check endianness on subsequent packets. */
+ if (current_pdu.bigendian_data != rbuf->bigendian_data) {
+ DEBUG(0,("rpc_api_pipe: Error : Endianness changed from %s to %s\n",
+ rbuf->bigendian_data ? "big" : "little",
+ current_pdu.bigendian_data ? "big" : "little" ));
+ ret = NT_STATUS_INVALID_PARAMETER;
+ goto err;
+ }
+ }
+ }
+
+ /* Now copy the data portion out of the pdu into rbuf. */
+ if (!prs_force_grow(rbuf, ret_data_len)) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto err;
+ }
+ memcpy(prs_data_p(rbuf)+current_rbuf_offset, ret_data, (size_t)ret_data_len);
+ current_rbuf_offset += ret_data_len;
+
+ /* See if we've finished with all the data in current_pdu yet ? */
+ ret = cli_pipe_reset_current_pdu(cli, &rhdr, &current_pdu);
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto err;
+ }
+
+ if (rhdr.flags & RPC_FLG_LAST) {
+ break; /* We're done. */
+ }
+ }
+
+ DEBUG(10,("rpc_api_pipe: %s returned %u bytes.\n",
+ rpccli_pipe_txt(debug_ctx(), cli),
+ (unsigned int)prs_data_size(rbuf) ));
+
+ prs_mem_free(&current_pdu);
+ return NT_STATUS_OK;
+
+ err:
+
+ prs_mem_free(&current_pdu);
+ prs_mem_free(rbuf);
+ return ret;
+}
+
+/*******************************************************************
+ Creates krb5 auth bind.
+ ********************************************************************/
+
+static NTSTATUS create_krb5_auth_bind_req( struct rpc_pipe_client *cli,
+ enum pipe_auth_level auth_level,
+ RPC_HDR_AUTH *pauth_out,
+ prs_struct *auth_data)
+{
+#ifdef HAVE_KRB5
+ int ret;
+ struct kerberos_auth_struct *a = cli->auth->a_u.kerberos_auth;
+ DATA_BLOB tkt = data_blob_null;
+ DATA_BLOB tkt_wrapped = data_blob_null;
+
+ /* We may change the pad length before marshalling. */
+ init_rpc_hdr_auth(pauth_out, RPC_KRB5_AUTH_TYPE, (int)auth_level, 0, 1);
+
+ DEBUG(5, ("create_krb5_auth_bind_req: creating a service ticket for principal %s\n",
+ a->service_principal ));
+
+ /* Create the ticket for the service principal and return it in a gss-api wrapped blob. */
+
+ ret = cli_krb5_get_ticket(a->service_principal, 0, &tkt,
+ &a->session_key, (uint32)AP_OPTS_MUTUAL_REQUIRED, NULL, NULL);
+
+ if (ret) {
+ DEBUG(1,("create_krb5_auth_bind_req: cli_krb5_get_ticket for principal %s "
+ "failed with %s\n",
+ a->service_principal,
+ error_message(ret) ));
+
+ data_blob_free(&tkt);
+ prs_mem_free(auth_data);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* wrap that up in a nice GSS-API wrapping */
+ tkt_wrapped = spnego_gen_krb5_wrap(tkt, TOK_ID_KRB_AP_REQ);
+
+ data_blob_free(&tkt);
+
+ /* Auth len in the rpc header doesn't include auth_header. */
+ if (!prs_copy_data_in(auth_data, (char *)tkt_wrapped.data, tkt_wrapped.length)) {
+ data_blob_free(&tkt_wrapped);
+ prs_mem_free(auth_data);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(5, ("create_krb5_auth_bind_req: Created krb5 GSS blob :\n"));
+ dump_data(5, tkt_wrapped.data, tkt_wrapped.length);
+
+ data_blob_free(&tkt_wrapped);
+ return NT_STATUS_OK;
+#else
+ return NT_STATUS_INVALID_PARAMETER;
+#endif
+}
+
+/*******************************************************************
+ Creates SPNEGO NTLMSSP auth bind.
+ ********************************************************************/
+
+static NTSTATUS create_spnego_ntlmssp_auth_rpc_bind_req( struct rpc_pipe_client *cli,
+ enum pipe_auth_level auth_level,
+ RPC_HDR_AUTH *pauth_out,
+ prs_struct *auth_data)
+{
+ NTSTATUS nt_status;
+ DATA_BLOB null_blob = data_blob_null;
+ DATA_BLOB request = data_blob_null;
+ DATA_BLOB spnego_msg = data_blob_null;
+
+ /* We may change the pad length before marshalling. */
+ init_rpc_hdr_auth(pauth_out, RPC_SPNEGO_AUTH_TYPE, (int)auth_level, 0, 1);
+
+ DEBUG(5, ("create_spnego_ntlmssp_auth_rpc_bind_req: Processing NTLMSSP Negotiate\n"));
+ nt_status = ntlmssp_update(cli->auth->a_u.ntlmssp_state,
+ null_blob,
+ &request);
+
+ if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ data_blob_free(&request);
+ prs_mem_free(auth_data);
+ return nt_status;
+ }
+
+ /* Wrap this in SPNEGO. */
+ spnego_msg = gen_negTokenInit(OID_NTLMSSP, request);
+
+ data_blob_free(&request);
+
+ /* Auth len in the rpc header doesn't include auth_header. */
+ if (!prs_copy_data_in(auth_data, (char *)spnego_msg.data, spnego_msg.length)) {
+ data_blob_free(&spnego_msg);
+ prs_mem_free(auth_data);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(5, ("create_spnego_ntlmssp_auth_rpc_bind_req: NTLMSSP Negotiate:\n"));
+ dump_data(5, spnego_msg.data, spnego_msg.length);
+
+ data_blob_free(&spnego_msg);
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Creates NTLMSSP auth bind.
+ ********************************************************************/
+
+static NTSTATUS create_ntlmssp_auth_rpc_bind_req( struct rpc_pipe_client *cli,
+ enum pipe_auth_level auth_level,
+ RPC_HDR_AUTH *pauth_out,
+ prs_struct *auth_data)
+{
+ NTSTATUS nt_status;
+ DATA_BLOB null_blob = data_blob_null;
+ DATA_BLOB request = data_blob_null;
+
+ /* We may change the pad length before marshalling. */
+ init_rpc_hdr_auth(pauth_out, RPC_NTLMSSP_AUTH_TYPE, (int)auth_level, 0, 1);
+
+ DEBUG(5, ("create_ntlmssp_auth_rpc_bind_req: Processing NTLMSSP Negotiate\n"));
+ nt_status = ntlmssp_update(cli->auth->a_u.ntlmssp_state,
+ null_blob,
+ &request);
+
+ if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ data_blob_free(&request);
+ prs_mem_free(auth_data);
+ return nt_status;
+ }
+
+ /* Auth len in the rpc header doesn't include auth_header. */
+ if (!prs_copy_data_in(auth_data, (char *)request.data, request.length)) {
+ data_blob_free(&request);
+ prs_mem_free(auth_data);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(5, ("create_ntlmssp_auth_rpc_bind_req: NTLMSSP Negotiate:\n"));
+ dump_data(5, request.data, request.length);
+
+ data_blob_free(&request);
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Creates schannel auth bind.
+ ********************************************************************/
+
+static NTSTATUS create_schannel_auth_rpc_bind_req( struct rpc_pipe_client *cli,
+ enum pipe_auth_level auth_level,
+ RPC_HDR_AUTH *pauth_out,
+ prs_struct *auth_data)
+{
+ RPC_AUTH_SCHANNEL_NEG schannel_neg;
+
+ /* We may change the pad length before marshalling. */
+ init_rpc_hdr_auth(pauth_out, RPC_SCHANNEL_AUTH_TYPE, (int)auth_level, 0, 1);
+
+ /* Use lp_workgroup() if domain not specified */
+
+ if (!cli->auth->domain || !cli->auth->domain[0]) {
+ cli->auth->domain = talloc_strdup(cli, lp_workgroup());
+ if (cli->auth->domain == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ init_rpc_auth_schannel_neg(&schannel_neg, cli->auth->domain,
+ global_myname());
+
+ /*
+ * Now marshall the data into the auth parse_struct.
+ */
+
+ if(!smb_io_rpc_auth_schannel_neg("schannel_neg",
+ &schannel_neg, auth_data, 0)) {
+ DEBUG(0,("Failed to marshall RPC_AUTH_SCHANNEL_NEG.\n"));
+ prs_mem_free(auth_data);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Creates the internals of a DCE/RPC bind request or alter context PDU.
+ ********************************************************************/
+
+static NTSTATUS create_bind_or_alt_ctx_internal(enum RPC_PKT_TYPE pkt_type,
+ prs_struct *rpc_out,
+ uint32 rpc_call_id,
+ const RPC_IFACE *abstract,
+ const RPC_IFACE *transfer,
+ RPC_HDR_AUTH *phdr_auth,
+ prs_struct *pauth_info)
+{
+ RPC_HDR hdr;
+ RPC_HDR_RB hdr_rb;
+ RPC_CONTEXT rpc_ctx;
+ uint16 auth_len = prs_offset(pauth_info);
+ uint8 ss_padding_len = 0;
+ uint16 frag_len = 0;
+
+ /* create the RPC context. */
+ init_rpc_context(&rpc_ctx, 0 /* context id */, abstract, transfer);
+
+ /* create the bind request RPC_HDR_RB */
+ init_rpc_hdr_rb(&hdr_rb, RPC_MAX_PDU_FRAG_LEN, RPC_MAX_PDU_FRAG_LEN, 0x0, &rpc_ctx);
+
+ /* Start building the frag length. */
+ frag_len = RPC_HEADER_LEN + RPC_HDR_RB_LEN(&hdr_rb);
+
+ /* Do we need to pad ? */
+ if (auth_len) {
+ uint16 data_len = RPC_HEADER_LEN + RPC_HDR_RB_LEN(&hdr_rb);
+ if (data_len % 8) {
+ ss_padding_len = 8 - (data_len % 8);
+ phdr_auth->auth_pad_len = ss_padding_len;
+ }
+ frag_len += RPC_HDR_AUTH_LEN + auth_len + ss_padding_len;
+ }
+
+ /* Create the request RPC_HDR */
+ init_rpc_hdr(&hdr, pkt_type, RPC_FLG_FIRST|RPC_FLG_LAST, rpc_call_id, frag_len, auth_len);
+
+ /* Marshall the RPC header */
+ if(!smb_io_rpc_hdr("hdr" , &hdr, rpc_out, 0)) {
+ DEBUG(0,("create_bind_or_alt_ctx_internal: failed to marshall RPC_HDR.\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Marshall the bind request data */
+ if(!smb_io_rpc_hdr_rb("", &hdr_rb, rpc_out, 0)) {
+ DEBUG(0,("create_bind_or_alt_ctx_internal: failed to marshall RPC_HDR_RB.\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * Grow the outgoing buffer to store any auth info.
+ */
+
+ if(auth_len != 0) {
+ if (ss_padding_len) {
+ char pad[8];
+ memset(pad, '\0', 8);
+ if (!prs_copy_data_in(rpc_out, pad, ss_padding_len)) {
+ DEBUG(0,("create_bind_or_alt_ctx_internal: failed to marshall padding.\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", phdr_auth, rpc_out, 0)) {
+ DEBUG(0,("create_bind_or_alt_ctx_internal: failed to marshall RPC_HDR_AUTH.\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+
+ if(!prs_append_prs_data( rpc_out, pauth_info)) {
+ DEBUG(0,("create_bind_or_alt_ctx_internal: failed to grow parse struct to add auth.\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Creates a DCE/RPC bind request.
+ ********************************************************************/
+
+static NTSTATUS create_rpc_bind_req(struct rpc_pipe_client *cli,
+ prs_struct *rpc_out,
+ uint32 rpc_call_id,
+ const RPC_IFACE *abstract,
+ const RPC_IFACE *transfer,
+ enum pipe_auth_type auth_type,
+ enum pipe_auth_level auth_level)
+{
+ RPC_HDR_AUTH hdr_auth;
+ prs_struct auth_info;
+ NTSTATUS ret = NT_STATUS_OK;
+
+ ZERO_STRUCT(hdr_auth);
+ if (!prs_init(&auth_info, RPC_HDR_AUTH_LEN, prs_get_mem_context(rpc_out), MARSHALL))
+ return NT_STATUS_NO_MEMORY;
+
+ switch (auth_type) {
+ case PIPE_AUTH_TYPE_SCHANNEL:
+ ret = create_schannel_auth_rpc_bind_req(cli, auth_level, &hdr_auth, &auth_info);
+ if (!NT_STATUS_IS_OK(ret)) {
+ prs_mem_free(&auth_info);
+ return ret;
+ }
+ break;
+
+ case PIPE_AUTH_TYPE_NTLMSSP:
+ ret = create_ntlmssp_auth_rpc_bind_req(cli, auth_level, &hdr_auth, &auth_info);
+ if (!NT_STATUS_IS_OK(ret)) {
+ prs_mem_free(&auth_info);
+ return ret;
+ }
+ break;
+
+ case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP:
+ ret = create_spnego_ntlmssp_auth_rpc_bind_req(cli, auth_level, &hdr_auth, &auth_info);
+ if (!NT_STATUS_IS_OK(ret)) {
+ prs_mem_free(&auth_info);
+ return ret;
+ }
+ break;
+
+ case PIPE_AUTH_TYPE_KRB5:
+ ret = create_krb5_auth_bind_req(cli, auth_level, &hdr_auth, &auth_info);
+ if (!NT_STATUS_IS_OK(ret)) {
+ prs_mem_free(&auth_info);
+ return ret;
+ }
+ break;
+
+ case PIPE_AUTH_TYPE_NONE:
+ break;
+
+ default:
+ /* "Can't" happen. */
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ ret = create_bind_or_alt_ctx_internal(RPC_BIND,
+ rpc_out,
+ rpc_call_id,
+ abstract,
+ transfer,
+ &hdr_auth,
+ &auth_info);
+
+ prs_mem_free(&auth_info);
+ return ret;
+}
+
+/*******************************************************************
+ Create and add the NTLMSSP sign/seal auth header and data.
+ ********************************************************************/
+
+static NTSTATUS add_ntlmssp_auth_footer(struct rpc_pipe_client *cli,
+ RPC_HDR *phdr,
+ uint32 ss_padding_len,
+ prs_struct *outgoing_pdu)
+{
+ RPC_HDR_AUTH auth_info;
+ NTSTATUS status;
+ DATA_BLOB auth_blob = data_blob_null;
+ uint16 data_and_pad_len = prs_offset(outgoing_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN;
+
+ if (!cli->auth->a_u.ntlmssp_state) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Init and marshall the auth header. */
+ init_rpc_hdr_auth(&auth_info,
+ map_pipe_auth_type_to_rpc_auth_type(
+ cli->auth->auth_type),
+ cli->auth->auth_level,
+ ss_padding_len,
+ 1 /* context id. */);
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, outgoing_pdu, 0)) {
+ DEBUG(0,("add_ntlmssp_auth_footer: failed to marshall RPC_HDR_AUTH.\n"));
+ data_blob_free(&auth_blob);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ switch (cli->auth->auth_level) {
+ case PIPE_AUTH_LEVEL_PRIVACY:
+ /* Data portion is encrypted. */
+ status = ntlmssp_seal_packet(cli->auth->a_u.ntlmssp_state,
+ (unsigned char *)prs_data_p(outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN,
+ data_and_pad_len,
+ (unsigned char *)prs_data_p(outgoing_pdu),
+ (size_t)prs_offset(outgoing_pdu),
+ &auth_blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ data_blob_free(&auth_blob);
+ return status;
+ }
+ break;
+
+ case PIPE_AUTH_LEVEL_INTEGRITY:
+ /* Data is signed. */
+ status = ntlmssp_sign_packet(cli->auth->a_u.ntlmssp_state,
+ (unsigned char *)prs_data_p(outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN,
+ data_and_pad_len,
+ (unsigned char *)prs_data_p(outgoing_pdu),
+ (size_t)prs_offset(outgoing_pdu),
+ &auth_blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ data_blob_free(&auth_blob);
+ return status;
+ }
+ break;
+
+ default:
+ /* Can't happen. */
+ smb_panic("bad auth level");
+ /* Notreached. */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Finally marshall the blob. */
+
+ if (!prs_copy_data_in(outgoing_pdu, (const char *)auth_blob.data, NTLMSSP_SIG_SIZE)) {
+ DEBUG(0,("add_ntlmssp_auth_footer: failed to add %u bytes auth blob.\n",
+ (unsigned int)NTLMSSP_SIG_SIZE));
+ data_blob_free(&auth_blob);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ data_blob_free(&auth_blob);
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Create and add the schannel sign/seal auth header and data.
+ ********************************************************************/
+
+static NTSTATUS add_schannel_auth_footer(struct rpc_pipe_client *cli,
+ RPC_HDR *phdr,
+ uint32 ss_padding_len,
+ prs_struct *outgoing_pdu)
+{
+ RPC_HDR_AUTH auth_info;
+ RPC_AUTH_SCHANNEL_CHK verf;
+ struct schannel_auth_struct *sas = cli->auth->a_u.schannel_auth;
+ char *data_p = prs_data_p(outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN;
+ size_t data_and_pad_len = prs_offset(outgoing_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN;
+
+ if (!sas) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Init and marshall the auth header. */
+ init_rpc_hdr_auth(&auth_info,
+ map_pipe_auth_type_to_rpc_auth_type(cli->auth->auth_type),
+ cli->auth->auth_level,
+ ss_padding_len,
+ 1 /* context id. */);
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, outgoing_pdu, 0)) {
+ DEBUG(0,("add_schannel_auth_footer: failed to marshall RPC_HDR_AUTH.\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ switch (cli->auth->auth_level) {
+ case PIPE_AUTH_LEVEL_PRIVACY:
+ case PIPE_AUTH_LEVEL_INTEGRITY:
+ DEBUG(10,("add_schannel_auth_footer: SCHANNEL seq_num=%d\n",
+ sas->seq_num));
+
+ schannel_encode(sas,
+ cli->auth->auth_level,
+ SENDER_IS_INITIATOR,
+ &verf,
+ data_p,
+ data_and_pad_len);
+
+ sas->seq_num++;
+ break;
+
+ default:
+ /* Can't happen. */
+ smb_panic("bad auth level");
+ /* Notreached. */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Finally marshall the blob. */
+ smb_io_rpc_auth_schannel_chk("",
+ RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN,
+ &verf,
+ outgoing_pdu,
+ 0);
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Calculate how much data we're going to send in this packet, also
+ work out any sign/seal padding length.
+ ********************************************************************/
+
+static uint32 calculate_data_len_tosend(struct rpc_pipe_client *cli,
+ uint32 data_left,
+ uint16 *p_frag_len,
+ uint16 *p_auth_len,
+ uint32 *p_ss_padding)
+{
+ uint32 data_space, data_len;
+
+ switch (cli->auth->auth_level) {
+ case PIPE_AUTH_LEVEL_NONE:
+ case PIPE_AUTH_LEVEL_CONNECT:
+ data_space = cli->max_xmit_frag - RPC_HEADER_LEN - RPC_HDR_REQ_LEN;
+ data_len = MIN(data_space, data_left);
+ *p_ss_padding = 0;
+ *p_auth_len = 0;
+ *p_frag_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + data_len;
+ return data_len;
+
+ case PIPE_AUTH_LEVEL_INTEGRITY:
+ case PIPE_AUTH_LEVEL_PRIVACY:
+ /* Treat the same for all authenticated rpc requests. */
+ switch(cli->auth->auth_type) {
+ case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP:
+ case PIPE_AUTH_TYPE_NTLMSSP:
+ *p_auth_len = NTLMSSP_SIG_SIZE;
+ break;
+ case PIPE_AUTH_TYPE_SCHANNEL:
+ *p_auth_len = RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN;
+ break;
+ default:
+ smb_panic("bad auth type");
+ break;
+ }
+
+ data_space = cli->max_xmit_frag - RPC_HEADER_LEN - RPC_HDR_REQ_LEN -
+ RPC_HDR_AUTH_LEN - *p_auth_len;
+
+ data_len = MIN(data_space, data_left);
+ if (data_len % 8) {
+ *p_ss_padding = 8 - (data_len % 8);
+ }
+ *p_frag_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + /* Normal headers. */
+ data_len + *p_ss_padding + /* data plus padding. */
+ RPC_HDR_AUTH_LEN + *p_auth_len; /* Auth header and auth data. */
+ return data_len;
+
+ default:
+ smb_panic("bad auth level");
+ /* Notreached. */
+ return 0;
+ }
+}
+
+/*******************************************************************
+ External interface.
+ Does an rpc request on a pipe. Incoming data is NDR encoded in in_data.
+ Reply is NDR encoded in out_data. Splits the data stream into RPC PDU's
+ and deals with signing/sealing details.
+ ********************************************************************/
+
+NTSTATUS rpc_api_pipe_req(struct rpc_pipe_client *cli,
+ uint8 op_num,
+ prs_struct *in_data,
+ prs_struct *out_data)
+{
+ NTSTATUS ret;
+ uint32 data_left = prs_offset(in_data);
+ uint32 alloc_hint = prs_offset(in_data);
+ uint32 data_sent_thistime = 0;
+ uint32 current_data_offset = 0;
+ uint32 call_id = get_rpc_call_id();
+ char pad[8];
+ prs_struct outgoing_pdu;
+
+ memset(pad, '\0', 8);
+
+ if (cli->max_xmit_frag < RPC_HEADER_LEN + RPC_HDR_REQ_LEN + RPC_MAX_SIGN_SIZE) {
+ /* Server is screwed up ! */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!prs_init(&outgoing_pdu, cli->max_xmit_frag, prs_get_mem_context(in_data), MARSHALL))
+ return NT_STATUS_NO_MEMORY;
+
+ while (1) {
+ RPC_HDR hdr;
+ RPC_HDR_REQ hdr_req;
+ uint16 auth_len = 0;
+ uint16 frag_len = 0;
+ uint8 flags = 0;
+ uint32 ss_padding = 0;
+ ssize_t num_written;
+
+ data_sent_thistime = calculate_data_len_tosend(cli, data_left,
+ &frag_len, &auth_len, &ss_padding);
+
+ if (current_data_offset == 0) {
+ flags = RPC_FLG_FIRST;
+ }
+
+ if (data_sent_thistime == data_left) {
+ flags |= RPC_FLG_LAST;
+ }
+
+ /* Create and marshall the header and request header. */
+ init_rpc_hdr(&hdr, RPC_REQUEST, flags, call_id, frag_len, auth_len);
+
+ if(!smb_io_rpc_hdr("hdr ", &hdr, &outgoing_pdu, 0)) {
+ prs_mem_free(&outgoing_pdu);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Create the rpc request RPC_HDR_REQ */
+ init_rpc_hdr_req(&hdr_req, alloc_hint, op_num);
+
+ if(!smb_io_rpc_hdr_req("hdr_req", &hdr_req, &outgoing_pdu, 0)) {
+ prs_mem_free(&outgoing_pdu);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Copy in the data, plus any ss padding. */
+ if (!prs_append_some_prs_data(&outgoing_pdu, in_data, current_data_offset, data_sent_thistime)) {
+ prs_mem_free(&outgoing_pdu);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Copy the sign/seal padding data. */
+ if (ss_padding) {
+ if (!prs_copy_data_in(&outgoing_pdu, pad, ss_padding)) {
+ prs_mem_free(&outgoing_pdu);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ /* Generate any auth sign/seal and add the auth footer. */
+ if (auth_len) {
+ switch (cli->auth->auth_type) {
+ case PIPE_AUTH_TYPE_NONE:
+ break;
+ case PIPE_AUTH_TYPE_NTLMSSP:
+ case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP:
+ ret = add_ntlmssp_auth_footer(cli, &hdr, ss_padding, &outgoing_pdu);
+ if (!NT_STATUS_IS_OK(ret)) {
+ prs_mem_free(&outgoing_pdu);
+ return ret;
+ }
+ break;
+ case PIPE_AUTH_TYPE_SCHANNEL:
+ ret = add_schannel_auth_footer(cli, &hdr, ss_padding, &outgoing_pdu);
+ if (!NT_STATUS_IS_OK(ret)) {
+ prs_mem_free(&outgoing_pdu);
+ return ret;
+ }
+ break;
+ default:
+ smb_panic("bad auth type");
+ break; /* notreached */
+ }
+ }
+
+ /* Actually send the packet. */
+ if (flags & RPC_FLG_LAST) {
+ /* Last packet - send the data, get the reply and return. */
+ ret = rpc_api_pipe(cli, &outgoing_pdu, out_data, RPC_RESPONSE);
+ prs_mem_free(&outgoing_pdu);
+
+ if ((DEBUGLEVEL >= 50)
+ && (cli->transport_type == NCACN_NP)) {
+ char *dump_name = NULL;
+ /* Also capture received data */
+ if (asprintf(&dump_name, "%s/reply_%s_%d",
+ get_dyn_LOGFILEBASE(),
+ cli->trans.np.pipe_name, op_num) > 0) {
+ prs_dump(dump_name, op_num, out_data);
+ SAFE_FREE(dump_name);
+ }
+ }
+
+ return ret;
+ }
+
+ switch (cli->transport_type) {
+ case NCACN_NP:
+ num_written = cli_write(cli->trans.np.cli,
+ cli->trans.np.fnum,
+ 8, /* 8 means message mode. */
+ prs_data_p(&outgoing_pdu),
+ (off_t)0,
+ (size_t)hdr.frag_len);
+
+ if (num_written != hdr.frag_len) {
+ prs_mem_free(&outgoing_pdu);
+ return cli_get_nt_error(cli->trans.np.cli);
+ }
+ break;
+ case NCACN_IP_TCP:
+ case NCACN_UNIX_STREAM:
+ num_written = write_data(
+ cli->trans.sock.fd,
+ prs_data_p(&outgoing_pdu),
+ (size_t)hdr.frag_len);
+ if (num_written != hdr.frag_len) {
+ NTSTATUS status;
+ status = map_nt_error_from_unix(errno);
+ prs_mem_free(&outgoing_pdu);
+ return status;
+ }
+ break;
+ default:
+ DEBUG(0, ("unknown transport type %d\n",
+ cli->transport_type));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ current_data_offset += data_sent_thistime;
+ data_left -= data_sent_thistime;
+
+ /* Reset the marshalling position back to zero. */
+ if (!prs_set_offset(&outgoing_pdu, 0)) {
+ prs_mem_free(&outgoing_pdu);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+}
+#if 0
+/****************************************************************************
+ Set the handle state.
+****************************************************************************/
+
+static bool rpc_pipe_set_hnd_state(struct rpc_pipe_client *cli,
+ const char *pipe_name, uint16 device_state)
+{
+ bool state_set = False;
+ char param[2];
+ uint16 setup[2]; /* only need 2 uint16 setup parameters */
+ char *rparam = NULL;
+ char *rdata = NULL;
+ uint32 rparam_len, rdata_len;
+
+ if (pipe_name == NULL)
+ return False;
+
+ DEBUG(5,("Set Handle state Pipe[%x]: %s - device state:%x\n",
+ cli->fnum, pipe_name, device_state));
+
+ /* create parameters: device state */
+ SSVAL(param, 0, device_state);
+
+ /* create setup parameters. */
+ setup[0] = 0x0001;
+ setup[1] = cli->fnum; /* pipe file handle. got this from an SMBOpenX. */
+
+ /* send the data on \PIPE\ */
+ if (cli_api_pipe(cli->cli, "\\PIPE\\",
+ setup, 2, 0, /* setup, length, max */
+ param, 2, 0, /* param, length, max */
+ NULL, 0, 1024, /* data, length, max */
+ &rparam, &rparam_len, /* return param, length */
+ &rdata, &rdata_len)) /* return data, length */
+ {
+ DEBUG(5, ("Set Handle state: return OK\n"));
+ state_set = True;
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return state_set;
+}
+#endif
+
+/****************************************************************************
+ Check the rpc bind acknowledge response.
+****************************************************************************/
+
+static bool check_bind_response(RPC_HDR_BA *hdr_ba, const RPC_IFACE *transfer)
+{
+ if ( hdr_ba->addr.len == 0) {
+ DEBUG(4,("Ignoring length check -- ASU bug (server didn't fill in the pipe name correctly)"));
+ }
+
+ /* check the transfer syntax */
+ if ((hdr_ba->transfer.if_version != transfer->if_version) ||
+ (memcmp(&hdr_ba->transfer.uuid, &transfer->uuid, sizeof(transfer->uuid)) !=0)) {
+ DEBUG(2,("bind_rpc_pipe: transfer syntax differs\n"));
+ return False;
+ }
+
+ 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,("check_bind_response: accepted!\n"));
+ return True;
+}
+
+/*******************************************************************
+ Creates a DCE/RPC bind authentication response.
+ This is the packet that is sent back to the server once we
+ have received a BIND-ACK, to finish the third leg of
+ the authentication handshake.
+ ********************************************************************/
+
+static NTSTATUS create_rpc_bind_auth3(struct rpc_pipe_client *cli,
+ uint32 rpc_call_id,
+ enum pipe_auth_type auth_type,
+ enum pipe_auth_level auth_level,
+ DATA_BLOB *pauth_blob,
+ prs_struct *rpc_out)
+{
+ RPC_HDR hdr;
+ RPC_HDR_AUTH hdr_auth;
+ uint32 pad = 0;
+
+ /* Create the request RPC_HDR */
+ init_rpc_hdr(&hdr, RPC_AUTH3, RPC_FLG_FIRST|RPC_FLG_LAST, rpc_call_id,
+ RPC_HEADER_LEN + 4 /* pad */ + RPC_HDR_AUTH_LEN + pauth_blob->length,
+ pauth_blob->length );
+
+ /* Marshall it. */
+ if(!smb_io_rpc_hdr("hdr", &hdr, rpc_out, 0)) {
+ DEBUG(0,("create_rpc_bind_auth3: failed to marshall RPC_HDR.\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ I'm puzzled about this - seems to violate the DCE RPC auth rules,
+ about padding - shouldn't this pad to length 8 ? JRA.
+ */
+
+ /* 4 bytes padding. */
+ if (!prs_uint32("pad", rpc_out, 0, &pad)) {
+ DEBUG(0,("create_rpc_bind_auth3: failed to marshall 4 byte pad.\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Create the request RPC_HDR_AUTHA */
+ init_rpc_hdr_auth(&hdr_auth,
+ map_pipe_auth_type_to_rpc_auth_type(auth_type),
+ auth_level, 0, 1);
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, rpc_out, 0)) {
+ DEBUG(0,("create_rpc_bind_auth3: failed to marshall RPC_HDR_AUTHA.\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * Append the auth data to the outgoing buffer.
+ */
+
+ if(!prs_copy_data_in(rpc_out, (char *)pauth_blob->data, pauth_blob->length)) {
+ DEBUG(0,("create_rpc_bind_auth3: failed to marshall auth blob.\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Create and send the third packet in an RPC auth.
+****************************************************************************/
+
+static NTSTATUS rpc_finish_auth3_bind(struct rpc_pipe_client *cli,
+ RPC_HDR *phdr,
+ prs_struct *rbuf,
+ uint32 rpc_call_id,
+ enum pipe_auth_type auth_type,
+ enum pipe_auth_level auth_level)
+{
+ DATA_BLOB server_response = data_blob_null;
+ DATA_BLOB client_reply = data_blob_null;
+ RPC_HDR_AUTH hdr_auth;
+ NTSTATUS nt_status;
+ prs_struct rpc_out;
+ ssize_t ret;
+
+ if (!phdr->auth_len || (phdr->frag_len < phdr->auth_len + RPC_HDR_AUTH_LEN)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Process the returned NTLMSSP blob first. */
+ if (!prs_set_offset(rbuf, phdr->frag_len - phdr->auth_len - RPC_HDR_AUTH_LEN)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, rbuf, 0)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* TODO - check auth_type/auth_level match. */
+
+ server_response = data_blob(NULL, phdr->auth_len);
+ prs_copy_data_out((char *)server_response.data, rbuf, phdr->auth_len);
+
+ nt_status = ntlmssp_update(cli->auth->a_u.ntlmssp_state,
+ server_response,
+ &client_reply);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0,("rpc_finish_auth3_bind: NTLMSSP update using server blob failed.\n"));
+ data_blob_free(&server_response);
+ return nt_status;
+ }
+
+ prs_init_empty(&rpc_out, prs_get_mem_context(rbuf), MARSHALL);
+
+ nt_status = create_rpc_bind_auth3(cli, rpc_call_id,
+ auth_type, auth_level,
+ &client_reply, &rpc_out);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ prs_mem_free(&rpc_out);
+ data_blob_free(&client_reply);
+ data_blob_free(&server_response);
+ return nt_status;
+ }
+
+ switch (cli->transport_type) {
+ case NCACN_NP:
+ /* 8 here is named pipe message mode. */
+ ret = cli_write(cli->trans.np.cli, cli->trans.np.fnum,
+ 0x8, prs_data_p(&rpc_out), 0,
+ (size_t)prs_offset(&rpc_out));
+ break;
+
+ if (ret != (ssize_t)prs_offset(&rpc_out)) {
+ nt_status = cli_get_nt_error(cli->trans.np.cli);
+ }
+ case NCACN_IP_TCP:
+ case NCACN_UNIX_STREAM:
+ ret = write_data(cli->trans.sock.fd, prs_data_p(&rpc_out),
+ (size_t)prs_offset(&rpc_out));
+ if (ret != (ssize_t)prs_offset(&rpc_out)) {
+ nt_status = map_nt_error_from_unix(errno);
+ }
+ break;
+ default:
+ DEBUG(0, ("unknown transport type %d\n", cli->transport_type));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (ret != (ssize_t)prs_offset(&rpc_out)) {
+ DEBUG(0,("rpc_send_auth_auth3: write failed. Return was %s\n",
+ nt_errstr(nt_status)));
+ prs_mem_free(&rpc_out);
+ data_blob_free(&client_reply);
+ data_blob_free(&server_response);
+ return nt_status;
+ }
+
+ DEBUG(5,("rpc_send_auth_auth3: %s sent auth3 response ok.\n",
+ rpccli_pipe_txt(debug_ctx(), cli)));
+
+ prs_mem_free(&rpc_out);
+ data_blob_free(&client_reply);
+ data_blob_free(&server_response);
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Creates a DCE/RPC bind alter context authentication request which
+ may contain a spnego auth blobl
+ ********************************************************************/
+
+static NTSTATUS create_rpc_alter_context(uint32 rpc_call_id,
+ const RPC_IFACE *abstract,
+ const RPC_IFACE *transfer,
+ enum pipe_auth_level auth_level,
+ const DATA_BLOB *pauth_blob, /* spnego auth blob already created. */
+ prs_struct *rpc_out)
+{
+ RPC_HDR_AUTH hdr_auth;
+ prs_struct auth_info;
+ NTSTATUS ret = NT_STATUS_OK;
+
+ ZERO_STRUCT(hdr_auth);
+ if (!prs_init(&auth_info, RPC_HDR_AUTH_LEN, prs_get_mem_context(rpc_out), MARSHALL))
+ return NT_STATUS_NO_MEMORY;
+
+ /* We may change the pad length before marshalling. */
+ init_rpc_hdr_auth(&hdr_auth, RPC_SPNEGO_AUTH_TYPE, (int)auth_level, 0, 1);
+
+ if (pauth_blob->length) {
+ if (!prs_copy_data_in(&auth_info, (const char *)pauth_blob->data, pauth_blob->length)) {
+ prs_mem_free(&auth_info);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ ret = create_bind_or_alt_ctx_internal(RPC_ALTCONT,
+ rpc_out,
+ rpc_call_id,
+ abstract,
+ transfer,
+ &hdr_auth,
+ &auth_info);
+ prs_mem_free(&auth_info);
+ return ret;
+}
+
+/*******************************************************************
+ Third leg of the SPNEGO bind mechanism - sends alter context PDU
+ and gets a response.
+ ********************************************************************/
+
+static NTSTATUS rpc_finish_spnego_ntlmssp_bind(struct rpc_pipe_client *cli,
+ RPC_HDR *phdr,
+ prs_struct *rbuf,
+ uint32 rpc_call_id,
+ const RPC_IFACE *abstract,
+ const RPC_IFACE *transfer,
+ enum pipe_auth_type auth_type,
+ enum pipe_auth_level auth_level)
+{
+ DATA_BLOB server_spnego_response = data_blob_null;
+ DATA_BLOB server_ntlm_response = data_blob_null;
+ DATA_BLOB client_reply = data_blob_null;
+ DATA_BLOB tmp_blob = data_blob_null;
+ RPC_HDR_AUTH hdr_auth;
+ NTSTATUS nt_status;
+ prs_struct rpc_out;
+
+ if (!phdr->auth_len || (phdr->frag_len < phdr->auth_len + RPC_HDR_AUTH_LEN)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Process the returned NTLMSSP blob first. */
+ if (!prs_set_offset(rbuf, phdr->frag_len - phdr->auth_len - RPC_HDR_AUTH_LEN)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, rbuf, 0)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ server_spnego_response = data_blob(NULL, phdr->auth_len);
+ prs_copy_data_out((char *)server_spnego_response.data, rbuf, phdr->auth_len);
+
+ /* The server might give us back two challenges - tmp_blob is for the second. */
+ if (!spnego_parse_challenge(server_spnego_response, &server_ntlm_response, &tmp_blob)) {
+ data_blob_free(&server_spnego_response);
+ data_blob_free(&server_ntlm_response);
+ data_blob_free(&tmp_blob);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* We're finished with the server spnego response and the tmp_blob. */
+ data_blob_free(&server_spnego_response);
+ data_blob_free(&tmp_blob);
+
+ nt_status = ntlmssp_update(cli->auth->a_u.ntlmssp_state,
+ server_ntlm_response,
+ &client_reply);
+
+ /* Finished with the server_ntlm response */
+ data_blob_free(&server_ntlm_response);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0,("rpc_finish_spnego_ntlmssp_bind: NTLMSSP update using server blob failed.\n"));
+ data_blob_free(&client_reply);
+ return nt_status;
+ }
+
+ /* SPNEGO wrap the client reply. */
+ tmp_blob = spnego_gen_auth(client_reply);
+ data_blob_free(&client_reply);
+ client_reply = tmp_blob;
+ tmp_blob = data_blob_null; /* Ensure it's safe to free this just in case. */
+
+ /* Now prepare the alter context pdu. */
+ prs_init_empty(&rpc_out, prs_get_mem_context(rbuf), MARSHALL);
+
+ nt_status = create_rpc_alter_context(rpc_call_id,
+ abstract,
+ transfer,
+ auth_level,
+ &client_reply,
+ &rpc_out);
+
+ data_blob_free(&client_reply);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ prs_mem_free(&rpc_out);
+ return nt_status;
+ }
+
+ /* Initialize the returning data struct. */
+ prs_mem_free(rbuf);
+ prs_init_empty(rbuf, talloc_tos(), UNMARSHALL);
+
+ nt_status = rpc_api_pipe(cli, &rpc_out, rbuf, RPC_ALTCONTRESP);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ prs_mem_free(&rpc_out);
+ return nt_status;
+ }
+
+ prs_mem_free(&rpc_out);
+
+ /* Get the auth blob from the reply. */
+ if(!smb_io_rpc_hdr("rpc_hdr ", phdr, rbuf, 0)) {
+ DEBUG(0,("rpc_finish_spnego_ntlmssp_bind: Failed to unmarshall RPC_HDR.\n"));
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if (!prs_set_offset(rbuf, phdr->frag_len - phdr->auth_len - RPC_HDR_AUTH_LEN)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, rbuf, 0)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ server_spnego_response = data_blob(NULL, phdr->auth_len);
+ prs_copy_data_out((char *)server_spnego_response.data, rbuf, phdr->auth_len);
+
+ /* Check we got a valid auth response. */
+ if (!spnego_parse_auth_response(server_spnego_response, NT_STATUS_OK, OID_NTLMSSP, &tmp_blob)) {
+ data_blob_free(&server_spnego_response);
+ data_blob_free(&tmp_blob);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ data_blob_free(&server_spnego_response);
+ data_blob_free(&tmp_blob);
+
+ DEBUG(5,("rpc_finish_spnego_ntlmssp_bind: alter context request to "
+ "%s.\n", rpccli_pipe_txt(debug_ctx(), cli)));
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Do an rpc bind.
+****************************************************************************/
+
+NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
+ struct cli_pipe_auth_data *auth)
+{
+ RPC_HDR hdr;
+ RPC_HDR_BA hdr_ba;
+ prs_struct rpc_out;
+ prs_struct rbuf;
+ uint32 rpc_call_id;
+ NTSTATUS status;
+
+ DEBUG(5,("Bind RPC Pipe: %s auth_type %u, auth_level %u\n",
+ rpccli_pipe_txt(debug_ctx(), cli),
+ (unsigned int)auth->auth_type,
+ (unsigned int)auth->auth_level ));
+
+ cli->auth = talloc_move(cli, &auth);
+
+ prs_init_empty(&rpc_out, talloc_tos(), MARSHALL);
+
+ rpc_call_id = get_rpc_call_id();
+
+ /* Marshall the outgoing data. */
+ status = create_rpc_bind_req(cli, &rpc_out, rpc_call_id,
+ &cli->abstract_syntax,
+ &cli->transfer_syntax,
+ cli->auth->auth_type,
+ cli->auth->auth_level);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ prs_mem_free(&rpc_out);
+ return status;
+ }
+
+ /* Initialize the incoming data struct. */
+ prs_init_empty(&rbuf, talloc_tos(), UNMARSHALL);
+
+ /* send data on \PIPE\. receive a response */
+ status = rpc_api_pipe(cli, &rpc_out, &rbuf, RPC_BINDACK);
+ if (!NT_STATUS_IS_OK(status)) {
+ prs_mem_free(&rpc_out);
+ return status;
+ }
+
+ prs_mem_free(&rpc_out);
+
+ DEBUG(3,("rpc_pipe_bind: %s bind request returned ok.\n",
+ rpccli_pipe_txt(debug_ctx(), cli)));
+
+ /* Unmarshall the RPC header */
+ if(!smb_io_rpc_hdr("hdr" , &hdr, &rbuf, 0)) {
+ DEBUG(0,("rpc_pipe_bind: failed to unmarshall RPC_HDR.\n"));
+ prs_mem_free(&rbuf);
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if(!smb_io_rpc_hdr_ba("", &hdr_ba, &rbuf, 0)) {
+ DEBUG(0,("rpc_pipe_bind: Failed to unmarshall RPC_HDR_BA.\n"));
+ prs_mem_free(&rbuf);
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if(!check_bind_response(&hdr_ba, &cli->transfer_syntax)) {
+ DEBUG(2,("rpc_pipe_bind: check_bind_response failed.\n"));
+ prs_mem_free(&rbuf);
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ cli->max_xmit_frag = hdr_ba.bba.max_tsize;
+ cli->max_recv_frag = hdr_ba.bba.max_rsize;
+
+ /* For authenticated binds we may need to do 3 or 4 leg binds. */
+ switch(cli->auth->auth_type) {
+
+ case PIPE_AUTH_TYPE_NONE:
+ case PIPE_AUTH_TYPE_SCHANNEL:
+ /* Bind complete. */
+ break;
+
+ case PIPE_AUTH_TYPE_NTLMSSP:
+ /* Need to send AUTH3 packet - no reply. */
+ status = rpc_finish_auth3_bind(
+ cli, &hdr, &rbuf, rpc_call_id,
+ cli->auth->auth_type,
+ cli->auth->auth_level);
+ if (!NT_STATUS_IS_OK(status)) {
+ prs_mem_free(&rbuf);
+ return status;
+ }
+ break;
+
+ case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP:
+ /* Need to send alter context request and reply. */
+ status = rpc_finish_spnego_ntlmssp_bind(
+ cli, &hdr, &rbuf, rpc_call_id,
+ &cli->abstract_syntax, &cli->transfer_syntax,
+ cli->auth->auth_type, cli->auth->auth_level);
+ if (!NT_STATUS_IS_OK(status)) {
+ prs_mem_free(&rbuf);
+ return status;
+ }
+ break;
+
+ case PIPE_AUTH_TYPE_KRB5:
+ /* */
+
+ default:
+ DEBUG(0,("cli_finish_bind_auth: unknown auth type "
+ "%u\n", (unsigned int)cli->auth->auth_type));
+ prs_mem_free(&rbuf);
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ /* For NTLMSSP ensure the server gave us the auth_level we wanted. */
+ if (cli->auth->auth_type == PIPE_AUTH_TYPE_NTLMSSP
+ || cli->auth->auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) {
+ if (cli->auth->auth_level == PIPE_AUTH_LEVEL_INTEGRITY) {
+ if (!(cli->auth->a_u.ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN)) {
+ DEBUG(0,("cli_finish_bind_auth: requested NTLMSSSP signing and server refused.\n"));
+ prs_mem_free(&rbuf);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+ if (cli->auth->auth_level == PIPE_AUTH_LEVEL_INTEGRITY) {
+ if (!(cli->auth->a_u.ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL)) {
+ DEBUG(0,("cli_finish_bind_auth: requested NTLMSSSP sealing and server refused.\n"));
+ prs_mem_free(&rbuf);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ return NT_STATUS_OK;
+}
+
+unsigned int rpccli_set_timeout(struct rpc_pipe_client *cli,
+ unsigned int timeout)
+{
+ return cli_set_timeout(cli->trans.np.cli, timeout);
+}
+
+bool rpccli_get_pwd_hash(struct rpc_pipe_client *cli, uint8_t nt_hash[16])
+{
+ if ((cli->auth->auth_type == PIPE_AUTH_TYPE_NTLMSSP)
+ || (cli->auth->auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP)) {
+ memcpy(nt_hash, cli->auth->a_u.ntlmssp_state->nt_hash, 16);
+ return true;
+ }
+
+ if (cli->transport_type == NCACN_NP) {
+ E_md4hash(cli->trans.np.cli->pwd.password, nt_hash);
+ return true;
+ }
+
+ return false;
+}
+
+struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p)
+{
+ if (p->transport_type == NCACN_NP) {
+ return p->trans.np.cli;
+ }
+ return NULL;
+}
+
+static int rpc_pipe_destructor(struct rpc_pipe_client *p)
+{
+ if (p->transport_type == NCACN_NP) {
+ bool ret;
+ ret = cli_close(p->trans.np.cli, p->trans.np.fnum);
+ if (!ret) {
+ DEBUG(1, ("rpc_pipe_destructor: cli_close failed on "
+ "pipe %s. Error was %s\n",
+ rpccli_pipe_txt(debug_ctx(), p),
+ cli_errstr(p->trans.np.cli)));
+ }
+
+ DEBUG(10, ("rpc_pipe_destructor: closed %s\n",
+ rpccli_pipe_txt(debug_ctx(), p)));
+
+ DLIST_REMOVE(p->trans.np.cli->pipe_list, p);
+ return ret ? -1 : 0;
+ }
+
+ return -1;
+}
+
+NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx,
+ struct cli_pipe_auth_data **presult)
+{
+ struct cli_pipe_auth_data *result;
+
+ result = talloc(mem_ctx, struct cli_pipe_auth_data);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result->auth_type = PIPE_AUTH_TYPE_NONE;
+ result->auth_level = PIPE_AUTH_LEVEL_NONE;
+
+ result->user_name = talloc_strdup(result, "");
+ result->domain = talloc_strdup(result, "");
+ if ((result->user_name == NULL) || (result->domain == NULL)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *presult = result;
+ return NT_STATUS_OK;
+}
+
+static int cli_auth_ntlmssp_data_destructor(struct cli_pipe_auth_data *auth)
+{
+ ntlmssp_end(&auth->a_u.ntlmssp_state);
+ return 0;
+}
+
+NTSTATUS rpccli_ntlmssp_bind_data(TALLOC_CTX *mem_ctx,
+ enum pipe_auth_type auth_type,
+ enum pipe_auth_level auth_level,
+ const char *domain,
+ const char *username,
+ const char *password,
+ struct cli_pipe_auth_data **presult)
+{
+ struct cli_pipe_auth_data *result;
+ NTSTATUS status;
+
+ result = talloc(mem_ctx, struct cli_pipe_auth_data);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result->auth_type = auth_type;
+ result->auth_level = auth_level;
+
+ result->user_name = talloc_strdup(result, username);
+ result->domain = talloc_strdup(result, domain);
+ if ((result->user_name == NULL) || (result->domain == NULL)) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ status = ntlmssp_client_start(&result->a_u.ntlmssp_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ talloc_set_destructor(result, cli_auth_ntlmssp_data_destructor);
+
+ status = ntlmssp_set_username(result->a_u.ntlmssp_state, username);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ status = ntlmssp_set_domain(result->a_u.ntlmssp_state, domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ status = ntlmssp_set_password(result->a_u.ntlmssp_state, password);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ /*
+ * Turn off sign+seal to allow selected auth level to turn it back on.
+ */
+ result->a_u.ntlmssp_state->neg_flags &=
+ ~(NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL);
+
+ if (auth_level == PIPE_AUTH_LEVEL_INTEGRITY) {
+ result->a_u.ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ } else if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
+ result->a_u.ntlmssp_state->neg_flags
+ |= NTLMSSP_NEGOTIATE_SEAL | NTLMSSP_NEGOTIATE_SIGN;
+ }
+
+ *presult = result;
+ return NT_STATUS_OK;
+
+ fail:
+ TALLOC_FREE(result);
+ return status;
+}
+
+NTSTATUS rpccli_schannel_bind_data(TALLOC_CTX *mem_ctx, const char *domain,
+ enum pipe_auth_level auth_level,
+ const uint8_t sess_key[16],
+ struct cli_pipe_auth_data **presult)
+{
+ struct cli_pipe_auth_data *result;
+
+ result = talloc(mem_ctx, struct cli_pipe_auth_data);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result->auth_type = PIPE_AUTH_TYPE_SCHANNEL;
+ result->auth_level = auth_level;
+
+ result->user_name = talloc_strdup(result, "");
+ result->domain = talloc_strdup(result, domain);
+ if ((result->user_name == NULL) || (result->domain == NULL)) {
+ goto fail;
+ }
+
+ result->a_u.schannel_auth = talloc(result,
+ struct schannel_auth_struct);
+ if (result->a_u.schannel_auth == NULL) {
+ goto fail;
+ }
+
+ memcpy(result->a_u.schannel_auth->sess_key, sess_key,
+ sizeof(result->a_u.schannel_auth->sess_key));
+ result->a_u.schannel_auth->seq_num = 0;
+
+ *presult = result;
+ return NT_STATUS_OK;
+
+ fail:
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+}
+
+#ifdef HAVE_KRB5
+static int cli_auth_kerberos_data_destructor(struct kerberos_auth_struct *auth)
+{
+ data_blob_free(&auth->session_key);
+ return 0;
+}
+#endif
+
+NTSTATUS rpccli_kerberos_bind_data(TALLOC_CTX *mem_ctx,
+ enum pipe_auth_level auth_level,
+ const char *service_princ,
+ const char *username,
+ const char *password,
+ struct cli_pipe_auth_data **presult)
+{
+#ifdef HAVE_KRB5
+ struct cli_pipe_auth_data *result;
+
+ if ((username != NULL) && (password != NULL)) {
+ int ret = kerberos_kinit_password(username, password, 0, NULL);
+ if (ret != 0) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ result = talloc(mem_ctx, struct cli_pipe_auth_data);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result->auth_type = PIPE_AUTH_TYPE_KRB5;
+ result->auth_level = auth_level;
+
+ /*
+ * Username / domain need fixing!
+ */
+ result->user_name = talloc_strdup(result, "");
+ result->domain = talloc_strdup(result, "");
+ if ((result->user_name == NULL) || (result->domain == NULL)) {
+ goto fail;
+ }
+
+ result->a_u.kerberos_auth = TALLOC_ZERO_P(
+ result, struct kerberos_auth_struct);
+ if (result->a_u.kerberos_auth == NULL) {
+ goto fail;
+ }
+ talloc_set_destructor(result->a_u.kerberos_auth,
+ cli_auth_kerberos_data_destructor);
+
+ result->a_u.kerberos_auth->service_principal = talloc_strdup(
+ result, service_princ);
+ if (result->a_u.kerberos_auth->service_principal == NULL) {
+ goto fail;
+ }
+
+ *presult = result;
+ return NT_STATUS_OK;
+
+ fail:
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+#else
+ return NT_STATUS_NOT_SUPPORTED;
+#endif
+}
+
+static int rpc_pipe_sock_destructor(struct rpc_pipe_client *p)
+{
+ close(p->trans.sock.fd);
+ return 0;
+}
+
+/**
+ * Create an rpc pipe client struct, connecting to a tcp port.
+ */
+static NTSTATUS rpc_pipe_open_tcp_port(TALLOC_CTX *mem_ctx, const char *host,
+ uint16_t port,
+ const struct ndr_syntax_id *abstract_syntax,
+ struct rpc_pipe_client **presult)
+{
+ struct rpc_pipe_client *result;
+ struct sockaddr_storage addr;
+ NTSTATUS status;
+
+ result = TALLOC_ZERO_P(mem_ctx, struct rpc_pipe_client);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result->transport_type = NCACN_IP_TCP;
+
+ result->abstract_syntax = *abstract_syntax;
+ result->transfer_syntax = ndr_transfer_syntax;
+
+ result->desthost = talloc_strdup(result, host);
+ result->srv_name_slash = talloc_asprintf_strupper_m(
+ result, "\\\\%s", result->desthost);
+ if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
+ result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
+
+ if (!resolve_name(host, &addr, 0)) {
+ status = NT_STATUS_NOT_FOUND;
+ goto fail;
+ }
+
+ result->trans.sock.fd = open_socket_out(SOCK_STREAM, &addr, port, 60);
+ if (result->trans.sock.fd == -1) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
+ }
+
+ talloc_set_destructor(result, rpc_pipe_sock_destructor);
+
+ *presult = result;
+ return NT_STATUS_OK;
+
+ fail:
+ TALLOC_FREE(result);
+ return status;
+}
+
+/**
+ * Determine the tcp port on which a dcerpc interface is listening
+ * for the ncacn_ip_tcp transport via the endpoint mapper of the
+ * target host.
+ */
+static NTSTATUS rpc_pipe_get_tcp_port(const char *host,
+ const struct ndr_syntax_id *abstract_syntax,
+ uint16_t *pport)
+{
+ NTSTATUS status;
+ struct rpc_pipe_client *epm_pipe = NULL;
+ struct cli_pipe_auth_data *auth = NULL;
+ struct dcerpc_binding *map_binding = NULL;
+ struct dcerpc_binding *res_binding = NULL;
+ struct epm_twr_t *map_tower = NULL;
+ struct epm_twr_t *res_towers = NULL;
+ struct policy_handle *entry_handle = NULL;
+ uint32_t num_towers = 0;
+ uint32_t max_towers = 1;
+ struct epm_twr_p_t towers;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ if (pport == NULL) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ /* open the connection to the endpoint mapper */
+ status = rpc_pipe_open_tcp_port(tmp_ctx, host, 135,
+ &ndr_table_epmapper.syntax_id,
+ &epm_pipe);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = rpccli_anon_bind_data(tmp_ctx, &auth);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = rpc_pipe_bind(epm_pipe, auth);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ /* create tower for asking the epmapper */
+
+ map_binding = TALLOC_ZERO_P(tmp_ctx, struct dcerpc_binding);
+ if (map_binding == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ map_binding->transport = NCACN_IP_TCP;
+ map_binding->object = *abstract_syntax;
+ map_binding->host = host; /* needed? */
+ map_binding->endpoint = "0"; /* correct? needed? */
+
+ map_tower = TALLOC_ZERO_P(tmp_ctx, struct epm_twr_t);
+ if (map_tower == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ status = dcerpc_binding_build_tower(tmp_ctx, map_binding,
+ &(map_tower->tower));
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ /* allocate further parameters for the epm_Map call */
+
+ res_towers = TALLOC_ARRAY(tmp_ctx, struct epm_twr_t, max_towers);
+ if (res_towers == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ towers.twr = res_towers;
+
+ entry_handle = TALLOC_ZERO_P(tmp_ctx, struct policy_handle);
+ if (entry_handle == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ /* ask the endpoint mapper for the port */
+
+ status = rpccli_epm_Map(epm_pipe,
+ tmp_ctx,
+ CONST_DISCARD(struct GUID *,
+ &(abstract_syntax->uuid)),
+ map_tower,
+ entry_handle,
+ max_towers,
+ &num_towers,
+ &towers);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (num_towers != 1) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* extract the port from the answer */
+
+ status = dcerpc_binding_from_tower(tmp_ctx,
+ &(towers.twr->tower),
+ &res_binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ /* are further checks here necessary? */
+ if (res_binding->transport != NCACN_IP_TCP) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ *pport = (uint16_t)atoi(res_binding->endpoint);
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return status;
+}
+
+/**
+ * Create a rpc pipe client struct, connecting to a host via tcp.
+ * The port is determined by asking the endpoint mapper on the given
+ * host.
+ */
+NTSTATUS rpc_pipe_open_tcp(TALLOC_CTX *mem_ctx, const char *host,
+ const struct ndr_syntax_id *abstract_syntax,
+ struct rpc_pipe_client **presult)
+{
+ NTSTATUS status;
+ uint16_t port = 0;
+
+ *presult = NULL;
+
+ status = rpc_pipe_get_tcp_port(host, abstract_syntax, &port);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = rpc_pipe_open_tcp_port(mem_ctx, host, port,
+ abstract_syntax, presult);
+
+done:
+ return status;
+}
+
+/********************************************************************
+ Create a rpc pipe client struct, connecting to a unix domain socket
+ ********************************************************************/
+NTSTATUS rpc_pipe_open_ncalrpc(TALLOC_CTX *mem_ctx, const char *socket_path,
+ const struct ndr_syntax_id *abstract_syntax,
+ struct rpc_pipe_client **presult)
+{
+ struct rpc_pipe_client *result;
+ struct sockaddr_un addr;
+ NTSTATUS status;
+
+ result = talloc_zero(mem_ctx, struct rpc_pipe_client);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result->transport_type = NCACN_UNIX_STREAM;
+
+ result->abstract_syntax = *abstract_syntax;
+ result->transfer_syntax = ndr_transfer_syntax;
+
+ result->desthost = get_myname(result);
+ result->srv_name_slash = talloc_asprintf_strupper_m(
+ result, "\\\\%s", result->desthost);
+ if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
+ result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
+
+ result->trans.sock.fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (result->trans.sock.fd == -1) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
+ }
+
+ talloc_set_destructor(result, rpc_pipe_sock_destructor);
+
+ ZERO_STRUCT(addr);
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
+
+ if (sys_connect(result->trans.sock.fd,
+ (struct sockaddr *)&addr) == -1) {
+ DEBUG(0, ("connect(%s) failed: %s\n", socket_path,
+ strerror(errno)));
+ close(result->trans.sock.fd);
+ return map_nt_error_from_unix(errno);
+ }
+
+ *presult = result;
+ return NT_STATUS_OK;
+
+ fail:
+ TALLOC_FREE(result);
+ return status;
+}
+
+
+/****************************************************************************
+ Open a named pipe over SMB to a remote server.
+ *
+ * CAVEAT CALLER OF THIS FUNCTION:
+ * The returned rpc_pipe_client saves a copy of the cli_state cli pointer,
+ * so be sure that this function is called AFTER any structure (vs pointer)
+ * assignment of the cli. In particular, libsmbclient does structure
+ * assignments of cli, which invalidates the data in the returned
+ * rpc_pipe_client if this function is called before the structure assignment
+ * of cli.
+ *
+ ****************************************************************************/
+
+static NTSTATUS rpc_pipe_open_np(struct cli_state *cli,
+ const struct ndr_syntax_id *abstract_syntax,
+ struct rpc_pipe_client **presult)
+{
+ struct rpc_pipe_client *result;
+ int fnum;
+
+ /* sanity check to protect against crashes */
+
+ if ( !cli ) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ result = TALLOC_ZERO_P(NULL, struct rpc_pipe_client);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result->transport_type = NCACN_NP;
+
+ result->trans.np.pipe_name = cli_get_pipe_name_from_iface(
+ result, cli, abstract_syntax);
+ if (result->trans.np.pipe_name == NULL) {
+ DEBUG(1, ("Could not find pipe for interface\n"));
+ TALLOC_FREE(result);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ result->trans.np.cli = cli;
+ result->abstract_syntax = *abstract_syntax;
+ result->transfer_syntax = ndr_transfer_syntax;
+ result->desthost = talloc_strdup(result, cli->desthost);
+ result->srv_name_slash = talloc_asprintf_strupper_m(
+ result, "\\\\%s", result->desthost);
+
+ if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ fnum = cli_nt_create(cli, result->trans.np.pipe_name,
+ DESIRED_ACCESS_PIPE);
+ if (fnum == -1) {
+ DEBUG(1,("rpc_pipe_open_np: cli_nt_create failed on pipe %s "
+ "to machine %s. Error was %s\n",
+ result->trans.np.pipe_name, cli->desthost,
+ cli_errstr(cli)));
+ TALLOC_FREE(result);
+ return cli_get_nt_error(cli);
+ }
+
+ result->trans.np.fnum = fnum;
+
+ DLIST_ADD(cli->pipe_list, result);
+ talloc_set_destructor(result, rpc_pipe_destructor);
+
+ *presult = result;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Open a pipe to a remote server.
+ ****************************************************************************/
+
+static NTSTATUS cli_rpc_pipe_open(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ struct rpc_pipe_client **presult)
+{
+ if (ndr_syntax_id_equal(interface, &ndr_table_drsuapi.syntax_id)) {
+ /*
+ * We should have a better way to figure out this drsuapi
+ * speciality...
+ */
+ return rpc_pipe_open_tcp(NULL, cli->desthost, interface,
+ presult);
+ }
+
+ return rpc_pipe_open_np(cli, interface, presult);
+}
+
+/****************************************************************************
+ Open a named pipe to an SMB server and bind anonymously.
+ ****************************************************************************/
+
+NTSTATUS cli_rpc_pipe_open_noauth(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ struct rpc_pipe_client **presult)
+{
+ struct rpc_pipe_client *result;
+ struct cli_pipe_auth_data *auth;
+ NTSTATUS status;
+
+ status = cli_rpc_pipe_open(cli, interface, &result);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = rpccli_anon_bind_data(result, &auth);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("rpccli_anon_bind_data returned %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(result);
+ return status;
+ }
+
+ /*
+ * This is a bit of an abstraction violation due to the fact that an
+ * anonymous bind on an authenticated SMB inherits the user/domain
+ * from the enclosing SMB creds
+ */
+
+ TALLOC_FREE(auth->user_name);
+ TALLOC_FREE(auth->domain);
+
+ auth->user_name = talloc_strdup(auth, cli->user_name);
+ auth->domain = talloc_strdup(auth, cli->domain);
+
+ if ((auth->user_name == NULL) || (auth->domain == NULL)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = rpc_pipe_bind(result, auth);
+ if (!NT_STATUS_IS_OK(status)) {
+ int lvl = 0;
+ if (ndr_syntax_id_equal(interface,
+ &ndr_table_dssetup.syntax_id)) {
+ /* non AD domains just don't have this pipe, avoid
+ * level 0 statement in that case - gd */
+ lvl = 3;
+ }
+ DEBUG(lvl, ("cli_rpc_pipe_open_noauth: rpc_pipe_bind for pipe "
+ "%s failed with error %s\n",
+ cli_get_pipe_name_from_iface(debug_ctx(), cli,
+ interface),
+ nt_errstr(status) ));
+ TALLOC_FREE(result);
+ return status;
+ }
+
+ DEBUG(10,("cli_rpc_pipe_open_noauth: opened pipe %s to machine "
+ "%s and bound anonymously.\n", result->trans.np.pipe_name,
+ cli->desthost ));
+
+ *presult = result;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Open a named pipe to an SMB server and bind using NTLMSSP or SPNEGO NTLMSSP
+ ****************************************************************************/
+
+static NTSTATUS cli_rpc_pipe_open_ntlmssp_internal(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ enum pipe_auth_type auth_type,
+ enum pipe_auth_level auth_level,
+ const char *domain,
+ const char *username,
+ const char *password,
+ struct rpc_pipe_client **presult)
+{
+ struct rpc_pipe_client *result;
+ struct cli_pipe_auth_data *auth;
+ NTSTATUS status;
+
+ status = cli_rpc_pipe_open(cli, interface, &result);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = rpccli_ntlmssp_bind_data(
+ result, auth_type, auth_level, domain, username,
+ cli->pwd.null_pwd ? NULL : password, &auth);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("rpccli_ntlmssp_bind_data returned %s\n",
+ nt_errstr(status)));
+ goto err;
+ }
+
+ status = rpc_pipe_bind(result, auth);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("cli_rpc_pipe_open_ntlmssp_internal: cli_rpc_pipe_bind failed with error %s\n",
+ nt_errstr(status) ));
+ goto err;
+ }
+
+ DEBUG(10,("cli_rpc_pipe_open_ntlmssp_internal: opened pipe %s to "
+ "machine %s and bound NTLMSSP as user %s\\%s.\n",
+ result->trans.np.pipe_name, cli->desthost,
+ domain, username ));
+
+ *presult = result;
+ return NT_STATUS_OK;
+
+ err:
+
+ TALLOC_FREE(result);
+ return status;
+}
+
+/****************************************************************************
+ External interface.
+ Open a named pipe to an SMB server and bind using NTLMSSP (bind type 10)
+ ****************************************************************************/
+
+NTSTATUS cli_rpc_pipe_open_ntlmssp(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ enum pipe_auth_level auth_level,
+ const char *domain,
+ const char *username,
+ const char *password,
+ struct rpc_pipe_client **presult)
+{
+ return cli_rpc_pipe_open_ntlmssp_internal(cli,
+ interface,
+ PIPE_AUTH_TYPE_NTLMSSP,
+ auth_level,
+ domain,
+ username,
+ password,
+ presult);
+}
+
+/****************************************************************************
+ External interface.
+ Open a named pipe to an SMB server and bind using spnego NTLMSSP (bind type 9)
+ ****************************************************************************/
+
+NTSTATUS cli_rpc_pipe_open_spnego_ntlmssp(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ enum pipe_auth_level auth_level,
+ const char *domain,
+ const char *username,
+ const char *password,
+ struct rpc_pipe_client **presult)
+{
+ return cli_rpc_pipe_open_ntlmssp_internal(cli,
+ interface,
+ PIPE_AUTH_TYPE_SPNEGO_NTLMSSP,
+ auth_level,
+ domain,
+ username,
+ password,
+ presult);
+}
+
+/****************************************************************************
+ Get a the schannel session key out of an already opened netlogon pipe.
+ ****************************************************************************/
+static NTSTATUS get_schannel_session_key_common(struct rpc_pipe_client *netlogon_pipe,
+ struct cli_state *cli,
+ const char *domain,
+ uint32 *pneg_flags)
+{
+ uint32 sec_chan_type = 0;
+ unsigned char machine_pwd[16];
+ const char *machine_account;
+ NTSTATUS status;
+
+ /* Get the machine account credentials from secrets.tdb. */
+ if (!get_trust_pw_hash(domain, machine_pwd, &machine_account,
+ &sec_chan_type))
+ {
+ DEBUG(0, ("get_schannel_session_key: could not fetch "
+ "trust account password for domain '%s'\n",
+ domain));
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ status = rpccli_netlogon_setup_creds(netlogon_pipe,
+ cli->desthost, /* server name */
+ domain, /* domain */
+ global_myname(), /* client name */
+ machine_account, /* machine account name */
+ machine_pwd,
+ sec_chan_type,
+ pneg_flags);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("get_schannel_session_key_common: "
+ "rpccli_netlogon_setup_creds failed with result %s "
+ "to server %s, domain %s, machine account %s.\n",
+ nt_errstr(status), cli->desthost, domain,
+ machine_account ));
+ return status;
+ }
+
+ if (((*pneg_flags) & NETLOGON_NEG_SCHANNEL) == 0) {
+ DEBUG(3, ("get_schannel_session_key: Server %s did not offer schannel\n",
+ cli->desthost));
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ return NT_STATUS_OK;;
+}
+
+/****************************************************************************
+ Open a netlogon pipe and get the schannel session key.
+ Now exposed to external callers.
+ ****************************************************************************/
+
+
+NTSTATUS get_schannel_session_key(struct cli_state *cli,
+ const char *domain,
+ uint32 *pneg_flags,
+ struct rpc_pipe_client **presult)
+{
+ struct rpc_pipe_client *netlogon_pipe = NULL;
+ NTSTATUS status;
+
+ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id,
+ &netlogon_pipe);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = get_schannel_session_key_common(netlogon_pipe, cli, domain,
+ pneg_flags);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(netlogon_pipe);
+ return status;
+ }
+
+ *presult = netlogon_pipe;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ External interface.
+ Open a named pipe to an SMB server and bind using schannel (bind type 68)
+ using session_key. sign and seal.
+ ****************************************************************************/
+
+NTSTATUS cli_rpc_pipe_open_schannel_with_key(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ enum pipe_auth_level auth_level,
+ const char *domain,
+ const struct dcinfo *pdc,
+ struct rpc_pipe_client **presult)
+{
+ struct rpc_pipe_client *result;
+ struct cli_pipe_auth_data *auth;
+ NTSTATUS status;
+
+ status = cli_rpc_pipe_open(cli, interface, &result);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = rpccli_schannel_bind_data(result, domain, auth_level,
+ pdc->sess_key, &auth);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("rpccli_schannel_bind_data returned %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(result);
+ return status;
+ }
+
+ status = rpc_pipe_bind(result, auth);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("cli_rpc_pipe_open_schannel_with_key: "
+ "cli_rpc_pipe_bind failed with error %s\n",
+ nt_errstr(status) ));
+ TALLOC_FREE(result);
+ return status;
+ }
+
+ /*
+ * The credentials on a new netlogon pipe are the ones we are passed
+ * in - copy them over.
+ */
+ result->dc = (struct dcinfo *)talloc_memdup(result, pdc, sizeof(*pdc));
+ if (result->dc == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(10,("cli_rpc_pipe_open_schannel_with_key: opened pipe %s to machine %s "
+ "for domain %s "
+ "and bound using schannel.\n",
+ result->trans.np.pipe_name, cli->desthost, domain ));
+
+ *presult = result;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Open a named pipe to an SMB server and bind using schannel (bind type 68).
+ Fetch the session key ourselves using a temporary netlogon pipe. This
+ version uses an ntlmssp auth bound netlogon pipe to get the key.
+ ****************************************************************************/
+
+static NTSTATUS get_schannel_session_key_auth_ntlmssp(struct cli_state *cli,
+ const char *domain,
+ const char *username,
+ const char *password,
+ uint32 *pneg_flags,
+ struct rpc_pipe_client **presult)
+{
+ struct rpc_pipe_client *netlogon_pipe = NULL;
+ NTSTATUS status;
+
+ status = cli_rpc_pipe_open_spnego_ntlmssp(
+ cli, &ndr_table_netlogon.syntax_id, PIPE_AUTH_LEVEL_PRIVACY,
+ domain, username, password, &netlogon_pipe);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = get_schannel_session_key_common(netlogon_pipe, cli, domain,
+ pneg_flags);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(netlogon_pipe);
+ return status;
+ }
+
+ *presult = netlogon_pipe;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Open a named pipe to an SMB server and bind using schannel (bind type 68).
+ Fetch the session key ourselves using a temporary netlogon pipe. This version
+ uses an ntlmssp bind to get the session key.
+ ****************************************************************************/
+
+NTSTATUS cli_rpc_pipe_open_ntlmssp_auth_schannel(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ enum pipe_auth_level auth_level,
+ const char *domain,
+ const char *username,
+ const char *password,
+ struct rpc_pipe_client **presult)
+{
+ uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+ struct rpc_pipe_client *netlogon_pipe = NULL;
+ struct rpc_pipe_client *result = NULL;
+ NTSTATUS status;
+
+ status = get_schannel_session_key_auth_ntlmssp(
+ cli, domain, username, password, &neg_flags, &netlogon_pipe);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("cli_rpc_pipe_open_ntlmssp_auth_schannel: failed to get schannel session "
+ "key from server %s for domain %s.\n",
+ cli->desthost, domain ));
+ return status;
+ }
+
+ status = cli_rpc_pipe_open_schannel_with_key(
+ cli, interface, auth_level, domain, netlogon_pipe->dc,
+ &result);
+
+ /* Now we've bound using the session key we can close the netlog pipe. */
+ TALLOC_FREE(netlogon_pipe);
+
+ if (NT_STATUS_IS_OK(status)) {
+ *presult = result;
+ }
+ return status;
+}
+
+/****************************************************************************
+ Open a named pipe to an SMB server and bind using schannel (bind type 68).
+ Fetch the session key ourselves using a temporary netlogon pipe.
+ ****************************************************************************/
+
+NTSTATUS cli_rpc_pipe_open_schannel(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ enum pipe_auth_level auth_level,
+ const char *domain,
+ struct rpc_pipe_client **presult)
+{
+ uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+ struct rpc_pipe_client *netlogon_pipe = NULL;
+ struct rpc_pipe_client *result = NULL;
+ NTSTATUS status;
+
+ status = get_schannel_session_key(cli, domain, &neg_flags,
+ &netlogon_pipe);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("cli_rpc_pipe_open_schannel: failed to get schannel session "
+ "key from server %s for domain %s.\n",
+ cli->desthost, domain ));
+ return status;
+ }
+
+ status = cli_rpc_pipe_open_schannel_with_key(
+ cli, interface, auth_level, domain, netlogon_pipe->dc,
+ &result);
+
+ /* Now we've bound using the session key we can close the netlog pipe. */
+ TALLOC_FREE(netlogon_pipe);
+
+ if (NT_STATUS_IS_OK(status)) {
+ *presult = result;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Open a named pipe to an SMB server and bind using krb5 (bind type 16).
+ The idea is this can be called with service_princ, username and password all
+ NULL so long as the caller has a TGT.
+ ****************************************************************************/
+
+NTSTATUS cli_rpc_pipe_open_krb5(struct cli_state *cli,
+ const struct ndr_syntax_id *interface,
+ enum pipe_auth_level auth_level,
+ const char *service_princ,
+ const char *username,
+ const char *password,
+ struct rpc_pipe_client **presult)
+{
+#ifdef HAVE_KRB5
+ struct rpc_pipe_client *result;
+ struct cli_pipe_auth_data *auth;
+ NTSTATUS status;
+
+ status = cli_rpc_pipe_open(cli, interface, &result);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = rpccli_kerberos_bind_data(result, auth_level, service_princ,
+ username, password, &auth);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("rpccli_kerberos_bind_data returned %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(result);
+ return status;
+ }
+
+ status = rpc_pipe_bind(result, auth);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("cli_rpc_pipe_open_krb5: cli_rpc_pipe_bind failed "
+ "with error %s\n", nt_errstr(status)));
+ TALLOC_FREE(result);
+ return status;
+ }
+
+ *presult = result;
+ return NT_STATUS_OK;
+#else
+ DEBUG(0,("cli_rpc_pipe_open_krb5: kerberos not found at compile time.\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+#endif
+}
+
+NTSTATUS cli_get_session_key(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *cli,
+ DATA_BLOB *session_key)
+{
+ if (!session_key || !cli) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!cli->auth) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ switch (cli->auth->auth_type) {
+ case PIPE_AUTH_TYPE_SCHANNEL:
+ *session_key = data_blob_talloc(mem_ctx,
+ cli->auth->a_u.schannel_auth->sess_key, 16);
+ break;
+ case PIPE_AUTH_TYPE_NTLMSSP:
+ case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP:
+ *session_key = data_blob_talloc(mem_ctx,
+ cli->auth->a_u.ntlmssp_state->session_key.data,
+ cli->auth->a_u.ntlmssp_state->session_key.length);
+ break;
+ case PIPE_AUTH_TYPE_KRB5:
+ case PIPE_AUTH_TYPE_SPNEGO_KRB5:
+ *session_key = data_blob_talloc(mem_ctx,
+ cli->auth->a_u.kerberos_auth->session_key.data,
+ cli->auth->a_u.kerberos_auth->session_key.length);
+ break;
+ case PIPE_AUTH_TYPE_NONE:
+ default:
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/rpc_client/cli_reg.c b/source3/rpc_client/cli_reg.c
new file mode 100644
index 0000000000..ba98e25d63
--- /dev/null
+++ b/source3/rpc_client/cli_reg.c
@@ -0,0 +1,79 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC Pipe client
+
+ Copyright (C) Gerald (Jerry) Carter 2005-2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpc_client.h"
+
+/*******************************************************************
+ connect to a registry hive root (open a registry policy)
+*******************************************************************/
+
+NTSTATUS rpccli_winreg_Connect(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ uint32 reg_type, uint32 access_mask,
+ POLICY_HND *reg_hnd)
+{
+ ZERO_STRUCTP(reg_hnd);
+
+ switch (reg_type)
+ {
+ case HKEY_CLASSES_ROOT:
+ return rpccli_winreg_OpenHKCR( cli, mem_ctx, NULL,
+ access_mask, reg_hnd, NULL);
+
+ case HKEY_LOCAL_MACHINE:
+ return rpccli_winreg_OpenHKLM( cli, mem_ctx, NULL,
+ access_mask, reg_hnd, NULL);
+
+ case HKEY_USERS:
+ return rpccli_winreg_OpenHKU( cli, mem_ctx, NULL,
+ access_mask, reg_hnd, NULL);
+
+ case HKEY_CURRENT_USER:
+ return rpccli_winreg_OpenHKCU( cli, mem_ctx, NULL,
+ access_mask, reg_hnd, NULL);
+
+ case HKEY_PERFORMANCE_DATA:
+ return rpccli_winreg_OpenHKPD( cli, mem_ctx, NULL,
+ access_mask, reg_hnd, NULL);
+
+ default:
+ /* fall through to end of function */
+ break;
+ }
+
+ return NT_STATUS_INVALID_PARAMETER;
+}
+
+/*******************************************************************
+ Fill in a REGVAL_BUFFER for the data given a REGISTRY_VALUE
+ *******************************************************************/
+
+uint32 reg_init_regval_buffer( REGVAL_BUFFER *buf2, REGISTRY_VALUE *val )
+{
+ uint32 real_size = 0;
+
+ if ( !buf2 || !val )
+ return 0;
+
+ real_size = regval_size(val);
+ init_regval_buffer( buf2, (unsigned char*)regval_data_p(val), real_size );
+
+ return real_size;
+}
diff --git a/source3/rpc_client/cli_samr.c b/source3/rpc_client/cli_samr.c
new file mode 100644
index 0000000000..ed42d56a02
--- /dev/null
+++ b/source3/rpc_client/cli_samr.c
@@ -0,0 +1,324 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+ Copyright (C) Tim Potter 2000-2001,
+ Copyright (C) Andrew Tridgell 1992-1997,2000,
+ Copyright (C) Rafal Szczesniak 2002.
+ Copyright (C) Jeremy Allison 2005.
+ Copyright (C) Guenther Deschner 2008.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* User change password */
+
+NTSTATUS rpccli_samr_chgpasswd_user(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *user_handle,
+ const char *newpassword,
+ const char *oldpassword)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6;
+
+ uchar old_nt_hash[16];
+ uchar old_lm_hash[16];
+ uchar new_nt_hash[16];
+ uchar new_lm_hash[16];
+
+ ZERO_STRUCT(old_nt_hash);
+ ZERO_STRUCT(old_lm_hash);
+ ZERO_STRUCT(new_nt_hash);
+ ZERO_STRUCT(new_lm_hash);
+
+ DEBUG(10,("rpccli_samr_chgpasswd_user\n"));
+
+ E_md4hash(oldpassword, old_nt_hash);
+ E_md4hash(newpassword, new_nt_hash);
+
+ E_deshash(oldpassword, old_lm_hash);
+ E_deshash(newpassword, new_lm_hash);
+
+ E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
+ E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
+ E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
+ E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
+ E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
+ E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
+
+ result = rpccli_samr_ChangePasswordUser(cli, mem_ctx,
+ user_handle,
+ true,
+ &hash1,
+ &hash2,
+ true,
+ &hash3,
+ &hash4,
+ true,
+ &hash5,
+ true,
+ &hash6);
+
+ return result;
+}
+
+
+/* User change password */
+
+NTSTATUS rpccli_samr_chgpasswd_user2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *username,
+ const char *newpassword,
+ const char *oldpassword)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct samr_CryptPassword new_nt_password;
+ struct samr_CryptPassword new_lm_password;
+ struct samr_Password old_nt_hash_enc;
+ struct samr_Password old_lanman_hash_enc;
+
+ uchar old_nt_hash[16];
+ uchar old_lanman_hash[16];
+ uchar new_nt_hash[16];
+ uchar new_lanman_hash[16];
+ struct lsa_String server, account;
+
+ DEBUG(10,("rpccli_samr_chgpasswd_user2\n"));
+
+ init_lsa_String(&server, cli->srv_name_slash);
+ init_lsa_String(&account, username);
+
+ /* Calculate the MD4 hash (NT compatible) of the password */
+ E_md4hash(oldpassword, old_nt_hash);
+ E_md4hash(newpassword, new_nt_hash);
+
+ if (lp_client_lanman_auth() &&
+ E_deshash(newpassword, new_lanman_hash) &&
+ E_deshash(oldpassword, old_lanman_hash)) {
+ /* E_deshash returns false for 'long' passwords (> 14
+ DOS chars). This allows us to match Win2k, which
+ does not store a LM hash for these passwords (which
+ would reduce the effective password length to 14) */
+
+ encode_pw_buffer(new_lm_password.data, newpassword, STR_UNICODE);
+
+ SamOEMhash(new_lm_password.data, old_nt_hash, 516);
+ E_old_pw_hash(new_nt_hash, old_lanman_hash, old_lanman_hash_enc.hash);
+ } else {
+ ZERO_STRUCT(new_lm_password);
+ ZERO_STRUCT(old_lanman_hash_enc);
+ }
+
+ encode_pw_buffer(new_nt_password.data, newpassword, STR_UNICODE);
+
+ SamOEMhash(new_nt_password.data, old_nt_hash, 516);
+ E_old_pw_hash(new_nt_hash, old_nt_hash, old_nt_hash_enc.hash);
+
+ result = rpccli_samr_ChangePasswordUser2(cli, mem_ctx,
+ &server,
+ &account,
+ &new_nt_password,
+ &old_nt_hash_enc,
+ true,
+ &new_lm_password,
+ &old_lanman_hash_enc);
+
+ return result;
+}
+
+/* User change password given blobs */
+
+NTSTATUS rpccli_samr_chng_pswd_auth_crap(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *username,
+ DATA_BLOB new_nt_password_blob,
+ DATA_BLOB old_nt_hash_enc_blob,
+ DATA_BLOB new_lm_password_blob,
+ DATA_BLOB old_lm_hash_enc_blob)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct samr_CryptPassword new_nt_password;
+ struct samr_CryptPassword new_lm_password;
+ struct samr_Password old_nt_hash_enc;
+ struct samr_Password old_lm_hash_enc;
+ struct lsa_String server, account;
+
+ DEBUG(10,("rpccli_samr_chng_pswd_auth_crap\n"));
+
+ init_lsa_String(&server, cli->srv_name_slash);
+ init_lsa_String(&account, username);
+
+ memcpy(&new_nt_password.data, new_nt_password_blob.data, 516);
+ memcpy(&new_lm_password.data, new_lm_password_blob.data, 516);
+ memcpy(&old_nt_hash_enc.hash, old_nt_hash_enc_blob.data, 16);
+ memcpy(&old_lm_hash_enc.hash, old_lm_hash_enc_blob.data, 16);
+
+ result = rpccli_samr_ChangePasswordUser2(cli, mem_ctx,
+ &server,
+ &account,
+ &new_nt_password,
+ &old_nt_hash_enc,
+ true,
+ &new_lm_password,
+ &old_lm_hash_enc);
+ return result;
+}
+
+
+/* change password 3 */
+
+NTSTATUS rpccli_samr_chgpasswd_user3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *username,
+ const char *newpassword,
+ const char *oldpassword,
+ struct samr_DomInfo1 **dominfo1,
+ struct samr_ChangeReject **reject)
+{
+ NTSTATUS status;
+
+ struct samr_CryptPassword new_nt_password;
+ struct samr_CryptPassword new_lm_password;
+ struct samr_Password old_nt_hash_enc;
+ struct samr_Password old_lanman_hash_enc;
+
+ uchar old_nt_hash[16];
+ uchar old_lanman_hash[16];
+ uchar new_nt_hash[16];
+ uchar new_lanman_hash[16];
+
+ struct lsa_String server, account;
+
+ DEBUG(10,("rpccli_samr_chgpasswd_user3\n"));
+
+ init_lsa_String(&server, cli->srv_name_slash);
+ init_lsa_String(&account, username);
+
+ /* Calculate the MD4 hash (NT compatible) of the password */
+ E_md4hash(oldpassword, old_nt_hash);
+ E_md4hash(newpassword, new_nt_hash);
+
+ if (lp_client_lanman_auth() &&
+ E_deshash(newpassword, new_lanman_hash) &&
+ E_deshash(oldpassword, old_lanman_hash)) {
+ /* E_deshash returns false for 'long' passwords (> 14
+ DOS chars). This allows us to match Win2k, which
+ does not store a LM hash for these passwords (which
+ would reduce the effective password length to 14) */
+
+ encode_pw_buffer(new_lm_password.data, newpassword, STR_UNICODE);
+
+ SamOEMhash(new_lm_password.data, old_nt_hash, 516);
+ E_old_pw_hash(new_nt_hash, old_lanman_hash, old_lanman_hash_enc.hash);
+ } else {
+ ZERO_STRUCT(new_lm_password);
+ ZERO_STRUCT(old_lanman_hash_enc);
+ }
+
+ encode_pw_buffer(new_nt_password.data, newpassword, STR_UNICODE);
+
+ SamOEMhash(new_nt_password.data, old_nt_hash, 516);
+ E_old_pw_hash(new_nt_hash, old_nt_hash, old_nt_hash_enc.hash);
+
+ status = rpccli_samr_ChangePasswordUser3(cli, mem_ctx,
+ &server,
+ &account,
+ &new_nt_password,
+ &old_nt_hash_enc,
+ true,
+ &new_lm_password,
+ &old_lanman_hash_enc,
+ NULL,
+ dominfo1,
+ reject);
+ return status;
+}
+
+/* This function returns the bizzare set of (max_entries, max_size) required
+ for the QueryDisplayInfo RPC to actually work against a domain controller
+ with large (10k and higher) numbers of users. These values were
+ obtained by inspection using ethereal and NT4 running User Manager. */
+
+void get_query_dispinfo_params(int loop_count, uint32 *max_entries,
+ uint32 *max_size)
+{
+ switch(loop_count) {
+ case 0:
+ *max_entries = 512;
+ *max_size = 16383;
+ break;
+ case 1:
+ *max_entries = 1024;
+ *max_size = 32766;
+ break;
+ case 2:
+ *max_entries = 2048;
+ *max_size = 65532;
+ break;
+ case 3:
+ *max_entries = 4096;
+ *max_size = 131064;
+ break;
+ default: /* loop_count >= 4 */
+ *max_entries = 4096;
+ *max_size = 131071;
+ break;
+ }
+}
+
+NTSTATUS rpccli_try_samr_connects(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32_t access_mask,
+ POLICY_HND *connect_pol)
+{
+ NTSTATUS status;
+ union samr_ConnectInfo info_in, info_out;
+ struct samr_ConnectInfo1 info1;
+ uint32_t lvl_out = 0;
+
+ ZERO_STRUCT(info1);
+
+ info1.client_version = SAMR_CONNECT_W2K;
+ info_in.info1 = info1;
+
+ status = rpccli_samr_Connect5(cli, mem_ctx,
+ cli->srv_name_slash,
+ access_mask,
+ 1,
+ &info_in,
+ &lvl_out,
+ &info_out,
+ connect_pol);
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = rpccli_samr_Connect4(cli, mem_ctx,
+ cli->srv_name_slash,
+ SAMR_CONNECT_W2K,
+ access_mask,
+ connect_pol);
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = rpccli_samr_Connect2(cli, mem_ctx,
+ cli->srv_name_slash,
+ access_mask,
+ connect_pol);
+ return status;
+}
+
diff --git a/source3/rpc_client/cli_spoolss.c b/source3/rpc_client/cli_spoolss.c
new file mode 100644
index 0000000000..69cee6c8e8
--- /dev/null
+++ b/source3/rpc_client/cli_spoolss.c
@@ -0,0 +1,2052 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Gerald Carter 2001-2005,
+ Copyright (C) Tim Potter 2000-2002,
+ Copyright (C) Andrew Tridgell 1994-2000,
+ Copyright (C) Jean-Francois Micouleau 1999-2000.
+ Copyright (C) Jeremy Allison 2005.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpc_client.h"
+
+/*********************************************************************
+ Decode various spoolss rpc's and info levels
+ ********************************************************************/
+
+/**********************************************************************
+**********************************************************************/
+
+static bool decode_printer_info_0(TALLOC_CTX *mem_ctx, RPC_BUFFER *buffer,
+ uint32 returned, PRINTER_INFO_0 **info)
+{
+ uint32 i;
+ PRINTER_INFO_0 *inf;
+
+ if (returned) {
+ inf=TALLOC_ARRAY(mem_ctx, PRINTER_INFO_0, returned);
+ if (!inf) {
+ return False;
+ }
+ memset(inf, 0, returned*sizeof(PRINTER_INFO_0));
+ } else {
+ inf = NULL;
+ }
+
+ prs_set_offset(&buffer->prs,0);
+
+ for (i=0; i<returned; i++) {
+ if (!smb_io_printer_info_0("", buffer, &inf[i], 0)) {
+ return False;
+ }
+ }
+
+ *info=inf;
+ return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static bool decode_printer_info_1(TALLOC_CTX *mem_ctx, RPC_BUFFER *buffer,
+ uint32 returned, PRINTER_INFO_1 **info)
+{
+ uint32 i;
+ PRINTER_INFO_1 *inf;
+
+ if (returned) {
+ inf=TALLOC_ARRAY(mem_ctx, PRINTER_INFO_1, returned);
+ if (!inf) {
+ return False;
+ }
+ memset(inf, 0, returned*sizeof(PRINTER_INFO_1));
+ } else {
+ inf = NULL;
+ }
+
+ prs_set_offset(&buffer->prs,0);
+
+ for (i=0; i<returned; i++) {
+ if (!smb_io_printer_info_1("", buffer, &inf[i], 0)) {
+ return False;
+ }
+ }
+
+ *info=inf;
+ return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static bool decode_printer_info_2(TALLOC_CTX *mem_ctx, RPC_BUFFER *buffer,
+ uint32 returned, PRINTER_INFO_2 **info)
+{
+ uint32 i;
+ PRINTER_INFO_2 *inf;
+
+ if (returned) {
+ inf=TALLOC_ARRAY(mem_ctx, PRINTER_INFO_2, returned);
+ if (!inf) {
+ return False;
+ }
+ memset(inf, 0, returned*sizeof(PRINTER_INFO_2));
+ } else {
+ inf = NULL;
+ }
+
+ prs_set_offset(&buffer->prs,0);
+
+ for (i=0; i<returned; i++) {
+ /* a little initialization as we go */
+ inf[i].secdesc = NULL;
+ if (!smb_io_printer_info_2("", buffer, &inf[i], 0)) {
+ return False;
+ }
+ }
+
+ *info=inf;
+ return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static bool decode_printer_info_3(TALLOC_CTX *mem_ctx, RPC_BUFFER *buffer,
+ uint32 returned, PRINTER_INFO_3 **info)
+{
+ uint32 i;
+ PRINTER_INFO_3 *inf;
+
+ if (returned) {
+ inf=TALLOC_ARRAY(mem_ctx, PRINTER_INFO_3, returned);
+ if (!inf) {
+ return False;
+ }
+ memset(inf, 0, returned*sizeof(PRINTER_INFO_3));
+ } else {
+ inf = NULL;
+ }
+
+ prs_set_offset(&buffer->prs,0);
+
+ for (i=0; i<returned; i++) {
+ inf[i].secdesc = NULL;
+ if (!smb_io_printer_info_3("", buffer, &inf[i], 0)) {
+ return False;
+ }
+ }
+
+ *info=inf;
+ return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static bool decode_printer_info_7(TALLOC_CTX *mem_ctx, RPC_BUFFER *buffer,
+ uint32 returned, PRINTER_INFO_7 **info)
+{
+ uint32 i;
+ PRINTER_INFO_7 *inf;
+
+ if (returned) {
+ inf=TALLOC_ARRAY(mem_ctx, PRINTER_INFO_7, returned);
+ if (!inf) {
+ return False;
+ }
+ memset(inf, 0, returned*sizeof(PRINTER_INFO_7));
+ } else {
+ inf = NULL;
+ }
+
+ prs_set_offset(&buffer->prs,0);
+
+ for (i=0; i<returned; i++) {
+ if (!smb_io_printer_info_7("", buffer, &inf[i], 0)) {
+ return False;
+ }
+ }
+
+ *info=inf;
+ return True;
+}
+
+
+/**********************************************************************
+**********************************************************************/
+
+static bool decode_port_info_1(TALLOC_CTX *mem_ctx, RPC_BUFFER *buffer,
+ uint32 returned, PORT_INFO_1 **info)
+{
+ uint32 i;
+ PORT_INFO_1 *inf;
+
+ if (returned) {
+ inf=TALLOC_ARRAY(mem_ctx, PORT_INFO_1, returned);
+ if (!inf) {
+ return False;
+ }
+ memset(inf, 0, returned*sizeof(PORT_INFO_1));
+ } else {
+ inf = NULL;
+ }
+
+ prs_set_offset(&buffer->prs, 0);
+
+ for (i=0; i<returned; i++) {
+ if (!smb_io_port_info_1("", buffer, &(inf[i]), 0)) {
+ return False;
+ }
+ }
+
+ *info=inf;
+ return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static bool decode_port_info_2(TALLOC_CTX *mem_ctx, RPC_BUFFER *buffer,
+ uint32 returned, PORT_INFO_2 **info)
+{
+ uint32 i;
+ PORT_INFO_2 *inf;
+
+ if (returned) {
+ inf=TALLOC_ARRAY(mem_ctx, PORT_INFO_2, returned);
+ if (!inf) {
+ return False;
+ }
+ memset(inf, 0, returned*sizeof(PORT_INFO_2));
+ } else {
+ inf = NULL;
+ }
+
+ prs_set_offset(&buffer->prs, 0);
+
+ for (i=0; i<returned; i++) {
+ if (!smb_io_port_info_2("", buffer, &(inf[i]), 0)) {
+ return False;
+ }
+ }
+
+ *info=inf;
+ return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static bool decode_printer_driver_1(TALLOC_CTX *mem_ctx, RPC_BUFFER *buffer,
+ uint32 returned, DRIVER_INFO_1 **info)
+{
+ uint32 i;
+ DRIVER_INFO_1 *inf;
+
+ if (returned) {
+ inf=TALLOC_ARRAY(mem_ctx, DRIVER_INFO_1, returned);
+ if (!inf) {
+ return False;
+ }
+ memset(inf, 0, returned*sizeof(DRIVER_INFO_1));
+ } else {
+ inf = NULL;
+ }
+
+ prs_set_offset(&buffer->prs,0);
+
+ for (i=0; i<returned; i++) {
+ if (!smb_io_printer_driver_info_1("", buffer, &(inf[i]), 0)) {
+ return False;
+ }
+ }
+
+ *info=inf;
+ return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static bool decode_printer_driver_2(TALLOC_CTX *mem_ctx, RPC_BUFFER *buffer,
+ uint32 returned, DRIVER_INFO_2 **info)
+{
+ uint32 i;
+ DRIVER_INFO_2 *inf;
+
+ if (returned) {
+ inf=TALLOC_ARRAY(mem_ctx, DRIVER_INFO_2, returned);
+ if (!inf) {
+ return False;
+ }
+ memset(inf, 0, returned*sizeof(DRIVER_INFO_2));
+ } else {
+ inf = NULL;
+ }
+
+ prs_set_offset(&buffer->prs,0);
+
+ for (i=0; i<returned; i++) {
+ if (!smb_io_printer_driver_info_2("", buffer, &(inf[i]), 0)) {
+ return False;
+ }
+ }
+
+ *info=inf;
+ return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static bool decode_printer_driver_3(TALLOC_CTX *mem_ctx, RPC_BUFFER *buffer,
+ uint32 returned, DRIVER_INFO_3 **info)
+{
+ uint32 i;
+ DRIVER_INFO_3 *inf;
+
+ if (returned) {
+ inf=TALLOC_ARRAY(mem_ctx, DRIVER_INFO_3, returned);
+ if (!inf) {
+ return False;
+ }
+ memset(inf, 0, returned*sizeof(DRIVER_INFO_3));
+ } else {
+ inf = NULL;
+ }
+
+ prs_set_offset(&buffer->prs,0);
+
+ for (i=0; i<returned; i++) {
+ if (!smb_io_printer_driver_info_3("", buffer, &(inf[i]), 0)) {
+ return False;
+ }
+ }
+
+ *info=inf;
+ return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static bool decode_printerdriverdir_1 (TALLOC_CTX *mem_ctx, RPC_BUFFER *buffer,
+ uint32 returned, DRIVER_DIRECTORY_1 **info
+)
+{
+ DRIVER_DIRECTORY_1 *inf;
+
+ inf=TALLOC_P(mem_ctx, DRIVER_DIRECTORY_1);
+ if (!inf) {
+ return False;
+ }
+ memset(inf, 0, sizeof(DRIVER_DIRECTORY_1));
+
+ prs_set_offset(&buffer->prs, 0);
+
+ if (!smb_io_driverdir_1("", buffer, inf, 0)) {
+ return False;
+ }
+
+ *info=inf;
+ return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static bool decode_jobs_1(TALLOC_CTX *mem_ctx, RPC_BUFFER *buffer,
+ uint32 num_jobs, JOB_INFO_1 **jobs)
+{
+ uint32 i;
+
+ if (num_jobs) {
+ *jobs = TALLOC_ARRAY(mem_ctx, JOB_INFO_1, num_jobs);
+ if (*jobs == NULL) {
+ return False;
+ }
+ } else {
+ *jobs = NULL;
+ }
+ prs_set_offset(&buffer->prs,0);
+
+ for (i = 0; i < num_jobs; i++) {
+ if (!smb_io_job_info_1("", buffer, &((*jobs)[i]), 0)) {
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static bool decode_jobs_2(TALLOC_CTX *mem_ctx, RPC_BUFFER *buffer,
+ uint32 num_jobs, JOB_INFO_2 **jobs)
+{
+ uint32 i;
+
+ if (num_jobs) {
+ *jobs = TALLOC_ARRAY(mem_ctx, JOB_INFO_2, num_jobs);
+ if (*jobs == NULL) {
+ return False;
+ }
+ } else {
+ *jobs = NULL;
+ }
+ prs_set_offset(&buffer->prs,0);
+
+ for (i = 0; i < num_jobs; i++) {
+ if (!smb_io_job_info_2("", buffer, &((*jobs)[i]), 0)) {
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static bool decode_forms_1(TALLOC_CTX *mem_ctx, RPC_BUFFER *buffer,
+ uint32 num_forms, FORM_1 **forms)
+{
+ int i;
+
+ if (num_forms) {
+ *forms = TALLOC_ARRAY(mem_ctx, FORM_1, num_forms);
+ if (*forms == NULL) {
+ return False;
+ }
+ } else {
+ *forms = NULL;
+ }
+
+ prs_set_offset(&buffer->prs,0);
+
+ for (i = 0; i < num_forms; i++) {
+ if (!smb_io_form_1("", buffer, &((*forms)[i]), 0)) {
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_open_printer_ex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ const char *printername, const char *datatype, uint32 access_required,
+ const char *station, const char *username, POLICY_HND *pol)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_OPEN_PRINTER_EX in;
+ SPOOL_R_OPEN_PRINTER_EX out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_open_printer_ex( &in, printername, datatype,
+ access_required, station, username );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_OPENPRINTEREX,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_open_printer_ex,
+ spoolss_io_r_open_printer_ex,
+ WERR_GENERAL_FAILURE );
+
+ memcpy( pol, &out.handle, sizeof(POLICY_HND) );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_close_printer(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_CLOSEPRINTER in;
+ SPOOL_R_CLOSEPRINTER out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_closeprinter( &in, pol );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_CLOSEPRINTER,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_closeprinter,
+ spoolss_io_r_closeprinter,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_enum_printers(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ char *name, uint32 flags, uint32 level,
+ uint32 *num_printers, PRINTER_INFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENUMPRINTERS in;
+ SPOOL_R_ENUMPRINTERS out;
+ RPC_BUFFER buffer;
+ uint32 offered;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ offered = 0;
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_enumprinters( &in, flags, name, level, &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENUMPRINTERS,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_enumprinters,
+ spoolss_io_r_enumprinters,
+ WERR_GENERAL_FAILURE );
+
+ if ( W_ERROR_EQUAL( out.status, WERR_INSUFFICIENT_BUFFER ) ) {
+ offered = out.needed;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_enumprinters( &in, flags, name, level, &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENUMPRINTERS,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_enumprinters,
+ spoolss_io_r_enumprinters,
+ WERR_GENERAL_FAILURE );
+ }
+
+ if ( !W_ERROR_IS_OK(out.status) )
+ return out.status;
+
+ switch (level) {
+ case 0:
+ if (!decode_printer_info_0(mem_ctx, out.buffer, out.returned, &ctr->printers_0)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ case 1:
+ if (!decode_printer_info_1(mem_ctx, out.buffer, out.returned, &ctr->printers_1)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ case 2:
+ if (!decode_printer_info_2(mem_ctx, out.buffer, out.returned, &ctr->printers_2)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ case 3:
+ if (!decode_printer_info_3(mem_ctx, out.buffer, out.returned, &ctr->printers_3)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ *num_printers = out.returned;
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_enum_ports(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ uint32 level, uint32 *num_ports, PORT_INFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENUMPORTS in;
+ SPOOL_R_ENUMPORTS out;
+ RPC_BUFFER buffer;
+ fstring server;
+ uint32 offered;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper_m(server);
+
+ offered = 0;
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_enumports( &in, server, level, &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENUMPORTS,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_enumports,
+ spoolss_io_r_enumports,
+ WERR_GENERAL_FAILURE );
+
+ if ( W_ERROR_EQUAL( out.status, WERR_INSUFFICIENT_BUFFER ) ) {
+ offered = out.needed;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_enumports( &in, server, level, &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENUMPORTS,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_enumports,
+ spoolss_io_r_enumports,
+ WERR_GENERAL_FAILURE );
+ }
+
+ if ( !W_ERROR_IS_OK(out.status) )
+ return out.status;
+
+ switch (level) {
+ case 1:
+ if (!decode_port_info_1(mem_ctx, out.buffer, out.returned, &ctr->port.info_1)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ case 2:
+ if (!decode_port_info_2(mem_ctx, out.buffer, out.returned, &ctr->port.info_2)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ *num_ports = out.returned;
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_getprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 level,
+ PRINTER_INFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETPRINTER in;
+ SPOOL_R_GETPRINTER out;
+ RPC_BUFFER buffer;
+ uint32 offered;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ /* Initialise input parameters */
+
+ offered = 0;
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_getprinter( mem_ctx, &in, pol, level, &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_GETPRINTER,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_getprinter,
+ spoolss_io_r_getprinter,
+ WERR_GENERAL_FAILURE );
+
+ if ( W_ERROR_EQUAL( out.status, WERR_INSUFFICIENT_BUFFER ) ) {
+ offered = out.needed;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_getprinter( mem_ctx, &in, pol, level, &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_GETPRINTER,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_getprinter,
+ spoolss_io_r_getprinter,
+ WERR_GENERAL_FAILURE );
+ }
+
+ if ( !W_ERROR_IS_OK(out.status) )
+ return out.status;
+
+ switch (level) {
+ case 0:
+ if (!decode_printer_info_0(mem_ctx, out.buffer, 1, &ctr->printers_0)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ case 1:
+ if (!decode_printer_info_1(mem_ctx, out.buffer, 1, &ctr->printers_1)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ case 2:
+ if (!decode_printer_info_2(mem_ctx, out.buffer, 1, &ctr->printers_2)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ case 3:
+ if (!decode_printer_info_3(mem_ctx, out.buffer, 1, &ctr->printers_3)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ case 7:
+ if (!decode_printer_info_7(mem_ctx, out.buffer, 1, &ctr->printers_7)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_setprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 level,
+ PRINTER_INFO_CTR *ctr, uint32 command)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_SETPRINTER in;
+ SPOOL_R_SETPRINTER out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_setprinter( mem_ctx, &in, pol, level, ctr, command );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_SETPRINTER,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_setprinter,
+ spoolss_io_r_setprinter,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_getprinterdriver(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 level,
+ const char *env, int version, PRINTER_DRIVER_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETPRINTERDRIVER2 in;
+ SPOOL_R_GETPRINTERDRIVER2 out;
+ RPC_BUFFER buffer;
+ fstring server;
+ uint32 offered;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ fstrcpy(server, cli->desthost);
+ strupper_m(server);
+
+ offered = 0;
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_getprinterdriver2( &in, pol, env, level,
+ version, 2, &buffer, offered);
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_GETPRINTERDRIVER2,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_getprinterdriver2,
+ spoolss_io_r_getprinterdriver2,
+ WERR_GENERAL_FAILURE );
+
+ if ( W_ERROR_EQUAL( out.status, WERR_INSUFFICIENT_BUFFER ) ) {
+ offered = out.needed;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_getprinterdriver2( &in, pol, env, level,
+ version, 2, &buffer, offered);
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_GETPRINTERDRIVER2,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_getprinterdriver2,
+ spoolss_io_r_getprinterdriver2,
+ WERR_GENERAL_FAILURE );
+ }
+
+ if ( !W_ERROR_IS_OK(out.status) )
+ return out.status;
+
+ switch (level) {
+ case 1:
+ if (!decode_printer_driver_1(mem_ctx, out.buffer, 1, &ctr->info1)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ case 2:
+ if (!decode_printer_driver_2(mem_ctx, out.buffer, 1, &ctr->info2)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ case 3:
+ if (!decode_printer_driver_3(mem_ctx, out.buffer, 1, &ctr->info3)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_enumprinterdrivers (struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 level, const char *env,
+ uint32 *num_drivers,
+ PRINTER_DRIVER_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENUMPRINTERDRIVERS in;
+ SPOOL_R_ENUMPRINTERDRIVERS out;
+ RPC_BUFFER buffer;
+ fstring server;
+ uint32 offered;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper_m(server);
+
+ offered = 0;
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_enumprinterdrivers( &in, server, env, level,
+ &buffer, offered);
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENUMPRINTERDRIVERS,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_enumprinterdrivers,
+ spoolss_io_r_enumprinterdrivers,
+ WERR_GENERAL_FAILURE );
+
+ if ( W_ERROR_EQUAL( out.status, WERR_INSUFFICIENT_BUFFER ) ) {
+ offered = out.needed;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_enumprinterdrivers( &in, server, env, level,
+ &buffer, offered);
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENUMPRINTERDRIVERS,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_enumprinterdrivers,
+ spoolss_io_r_enumprinterdrivers,
+ WERR_GENERAL_FAILURE );
+ }
+
+ *num_drivers = out.returned;
+
+ if ( !W_ERROR_IS_OK(out.status) )
+ return out.status;
+
+ if ( out.returned ) {
+
+ switch (level) {
+ case 1:
+ if (!decode_printer_driver_1(mem_ctx, out.buffer, out.returned, &ctr->info1)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ case 2:
+ if (!decode_printer_driver_2(mem_ctx, out.buffer, out.returned, &ctr->info2)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ case 3:
+ if (!decode_printer_driver_3(mem_ctx, out.buffer, out.returned, &ctr->info3)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+ }
+
+ return out.status;
+}
+
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_getprinterdriverdir (struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 level, char *env,
+ DRIVER_DIRECTORY_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETPRINTERDRIVERDIR in;
+ SPOOL_R_GETPRINTERDRIVERDIR out;
+ RPC_BUFFER buffer;
+ fstring server;
+ uint32 offered;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper_m(server);
+
+ offered = 0;
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_getprinterdriverdir( &in, server, env, level,
+ &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_GETPRINTERDRIVERDIRECTORY,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_getprinterdriverdir,
+ spoolss_io_r_getprinterdriverdir,
+ WERR_GENERAL_FAILURE );
+
+ if ( W_ERROR_EQUAL( out.status, WERR_INSUFFICIENT_BUFFER ) ) {
+ offered = out.needed;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_getprinterdriverdir( &in, server, env, level,
+ &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_GETPRINTERDRIVERDIRECTORY,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_getprinterdriverdir,
+ spoolss_io_r_getprinterdriverdir,
+ WERR_GENERAL_FAILURE );
+ }
+
+ if (!W_ERROR_IS_OK(out.status))
+ return out.status;
+
+ if (!decode_printerdriverdir_1(mem_ctx, out.buffer, 1, &ctr->info1)) {
+ return WERR_GENERAL_FAILURE;
+ }
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_addprinterdriver (struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, uint32 level,
+ PRINTER_DRIVER_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ADDPRINTERDRIVER in;
+ SPOOL_R_ADDPRINTERDRIVER out;
+ fstring server;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper_m(server);
+
+ make_spoolss_q_addprinterdriver( mem_ctx, &in, server, level, ctr );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ADDPRINTERDRIVER,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_addprinterdriver,
+ spoolss_io_r_addprinterdriver,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_addprinterex (struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ uint32 level, PRINTER_INFO_CTR*ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ADDPRINTEREX in;
+ SPOOL_R_ADDPRINTEREX out;
+ fstring server, client, user;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ slprintf(client, sizeof(fstring)-1, "\\\\%s", global_myname());
+ slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+
+ strupper_m(client);
+ strupper_m(server);
+
+ fstrcpy (user, cli->auth->user_name);
+
+ make_spoolss_q_addprinterex( mem_ctx, &in, server, client,
+ user, level, ctr);
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ADDPRINTEREX,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_addprinterex,
+ spoolss_io_r_addprinterex,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_deleteprinterdriverex(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, const char *arch,
+ const char *driver, int version)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_DELETEPRINTERDRIVEREX in;
+ SPOOL_R_DELETEPRINTERDRIVEREX out;
+ fstring server;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper_m(server);
+
+ make_spoolss_q_deleteprinterdriverex( mem_ctx, &in, server, arch, driver, version );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_DELETEPRINTERDRIVEREX,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_deleteprinterdriverex,
+ spoolss_io_r_deleteprinterdriverex,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_deleteprinterdriver (struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, const char *arch,
+ const char *driver)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_DELETEPRINTERDRIVER in;
+ SPOOL_R_DELETEPRINTERDRIVER out;
+ fstring server;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper_m(server);
+
+ make_spoolss_q_deleteprinterdriver( mem_ctx, &in, server, arch, driver );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_DELETEPRINTERDRIVER,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_deleteprinterdriver,
+ spoolss_io_r_deleteprinterdriver,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_getprintprocessordirectory(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ char *name, char *environment,
+ fstring procdir)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETPRINTPROCESSORDIRECTORY in;
+ SPOOL_R_GETPRINTPROCESSORDIRECTORY out;
+ int level = 1;
+ RPC_BUFFER buffer;
+ uint32 offered;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ offered = 0;
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_getprintprocessordirectory( &in, name,
+ environment, level, &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_GETPRINTPROCESSORDIRECTORY,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_getprintprocessordirectory,
+ spoolss_io_r_getprintprocessordirectory,
+ WERR_GENERAL_FAILURE );
+
+ if ( W_ERROR_EQUAL( out.status, WERR_INSUFFICIENT_BUFFER ) ) {
+ offered = out.needed;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_getprintprocessordirectory( &in, name,
+ environment, level, &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_GETPRINTPROCESSORDIRECTORY,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_getprintprocessordirectory,
+ spoolss_io_r_getprintprocessordirectory,
+ WERR_GENERAL_FAILURE );
+ }
+
+ if ( !W_ERROR_IS_OK(out.status) )
+ return out.status;
+
+ fstrcpy(procdir, "Not implemented!");
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *handle, uint32 level, FORM *form)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ADDFORM in;
+ SPOOL_R_ADDFORM out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_addform( &in, handle, level, form );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ADDFORM,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_addform,
+ spoolss_io_r_addform,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *handle, uint32 level,
+ const char *form_name, FORM *form)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_SETFORM in;
+ SPOOL_R_SETFORM out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_setform( &in, handle, level, form_name, form );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_SETFORM,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_setform,
+ spoolss_io_r_setform,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *handle, const char *formname,
+ uint32 level, FORM_1 *form)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETFORM in;
+ SPOOL_R_GETFORM out;
+ RPC_BUFFER buffer;
+ uint32 offered;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ offered = 0;
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_getform( &in, handle, formname, level, &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_GETFORM,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_getform,
+ spoolss_io_r_getform,
+ WERR_GENERAL_FAILURE );
+
+ if ( W_ERROR_EQUAL( out.status, WERR_INSUFFICIENT_BUFFER ) ) {
+ offered = out.needed;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_getform( &in, handle, formname, level, &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_GETFORM,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_getform,
+ spoolss_io_r_getform,
+ WERR_GENERAL_FAILURE );
+ }
+
+ if (!W_ERROR_IS_OK(out.status))
+ return out.status;
+
+ if (!smb_io_form_1("", out.buffer, form, 0)) {
+ return WERR_GENERAL_FAILURE;
+ }
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_deleteform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *handle, const char *form_name)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_DELETEFORM in;
+ SPOOL_R_DELETEFORM out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_deleteform( &in, handle, form_name );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_DELETEFORM,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_deleteform,
+ spoolss_io_r_deleteform,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_enumforms(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *handle, int level, uint32 *num_forms,
+ FORM_1 **forms)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENUMFORMS in;
+ SPOOL_R_ENUMFORMS out;
+ RPC_BUFFER buffer;
+ uint32 offered;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ offered = 0;
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_enumforms( &in, handle, level, &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENUMFORMS,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_enumforms,
+ spoolss_io_r_enumforms,
+ WERR_GENERAL_FAILURE );
+
+ if ( W_ERROR_EQUAL( out.status, WERR_INSUFFICIENT_BUFFER ) ) {
+ offered = out.needed;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_enumforms( &in, handle, level, &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENUMFORMS,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_enumforms,
+ spoolss_io_r_enumforms,
+ WERR_GENERAL_FAILURE );
+ }
+
+ if (!W_ERROR_IS_OK(out.status))
+ return out.status;
+
+ *num_forms = out.numofforms;
+
+ if (!decode_forms_1(mem_ctx, out.buffer, *num_forms, forms)) {
+ return WERR_GENERAL_FAILURE;
+ }
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_enumjobs(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, uint32 level, uint32 firstjob,
+ uint32 num_jobs, uint32 *returned, JOB_INFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENUMJOBS in;
+ SPOOL_R_ENUMJOBS out;
+ RPC_BUFFER buffer;
+ uint32 offered;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ offered = 0;
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_enumjobs( &in, hnd, firstjob, num_jobs, level,
+ &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENUMJOBS,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_enumjobs,
+ spoolss_io_r_enumjobs,
+ WERR_GENERAL_FAILURE );
+
+ if ( W_ERROR_EQUAL( out.status, WERR_INSUFFICIENT_BUFFER ) ) {
+ offered = out.needed;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_enumjobs( &in, hnd, firstjob, num_jobs, level,
+ &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENUMJOBS,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_enumjobs,
+ spoolss_io_r_enumjobs,
+ WERR_GENERAL_FAILURE );
+ }
+
+ if (!W_ERROR_IS_OK(out.status))
+ return out.status;
+
+ switch(level) {
+ case 1:
+ if (!decode_jobs_1(mem_ctx, out.buffer, out.returned, &ctr->job.job_info_1)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ case 2:
+ if (!decode_jobs_2(mem_ctx, out.buffer, out.returned, &ctr->job.job_info_2)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ default:
+ DEBUG(3, ("unsupported info level %d", level));
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ *returned = out.returned;
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_setjob(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, uint32 jobid, uint32 level,
+ uint32 command)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_SETJOB in;
+ SPOOL_R_SETJOB out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_setjob( &in, hnd, jobid, level, command );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_SETJOB,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_setjob,
+ spoolss_io_r_setjob,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_getjob(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, uint32 jobid, uint32 level,
+ JOB_INFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETJOB in;
+ SPOOL_R_GETJOB out;
+ RPC_BUFFER buffer;
+ uint32 offered;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ offered = 0;
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_getjob( &in, hnd, jobid, level, &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_GETJOB,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_getjob,
+ spoolss_io_r_getjob,
+ WERR_GENERAL_FAILURE );
+
+ if ( W_ERROR_EQUAL( out.status, WERR_MORE_DATA ) ) {
+ offered = out.needed;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ rpcbuf_init(&buffer, offered, mem_ctx);
+ make_spoolss_q_getjob( &in, hnd, jobid, level, &buffer, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_GETJOB,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_getjob,
+ spoolss_io_r_getjob,
+ WERR_GENERAL_FAILURE );
+ }
+
+ if (!W_ERROR_IS_OK(out.status))
+ return out.status;
+
+ switch(level) {
+ case 1:
+ if (!decode_jobs_1(mem_ctx, out.buffer, 1, &ctr->job.job_info_1)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ case 2:
+ if (!decode_jobs_2(mem_ctx, out.buffer, 1, &ctr->job.job_info_2)) {
+ return WERR_GENERAL_FAILURE;
+ }
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_startpageprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_STARTPAGEPRINTER in;
+ SPOOL_R_STARTPAGEPRINTER out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_startpageprinter( &in, hnd );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_STARTPAGEPRINTER,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_startpageprinter,
+ spoolss_io_r_startpageprinter,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_endpageprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENDPAGEPRINTER in;
+ SPOOL_R_ENDPAGEPRINTER out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_endpageprinter( &in, hnd );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENDPAGEPRINTER,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_endpageprinter,
+ spoolss_io_r_endpageprinter,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_startdocprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, char *docname,
+ char *outputfile, char *datatype,
+ uint32 *jobid)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_STARTDOCPRINTER in;
+ SPOOL_R_STARTDOCPRINTER out;
+ uint32 level = 1;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_startdocprinter( &in, hnd, level, docname,
+ outputfile, datatype );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_STARTDOCPRINTER,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_startdocprinter,
+ spoolss_io_r_startdocprinter,
+ WERR_GENERAL_FAILURE );
+
+ *jobid = out.jobid;
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_enddocprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENDDOCPRINTER in;
+ SPOOL_R_ENDDOCPRINTER out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_enddocprinter( &in, hnd );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENDDOCPRINTER,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_enddocprinter,
+ spoolss_io_r_enddocprinter,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_getprinterdata(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, const char *valuename,
+ REGISTRY_VALUE *value)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETPRINTERDATA in;
+ SPOOL_R_GETPRINTERDATA out;
+ uint32 offered;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ offered = 0;
+ make_spoolss_q_getprinterdata( &in, hnd, valuename, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_GETPRINTERDATA,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_getprinterdata,
+ spoolss_io_r_getprinterdata,
+ WERR_GENERAL_FAILURE );
+
+ if ( W_ERROR_EQUAL( out.status, WERR_MORE_DATA ) ) {
+ offered = out.needed;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_getprinterdata( &in, hnd, valuename, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_GETPRINTERDATA,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_getprinterdata,
+ spoolss_io_r_getprinterdata,
+ WERR_GENERAL_FAILURE );
+ }
+
+ if (!W_ERROR_IS_OK(out.status))
+ return out.status;
+
+ /* Return output parameters */
+
+ if (out.needed) {
+ value->data_p = (uint8 *)TALLOC_MEMDUP(mem_ctx, out.data, out.needed);
+ } else {
+ value->data_p = NULL;
+ }
+ value->type = out.type;
+ value->size = out.size;
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_getprinterdataex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, const char *keyname,
+ const char *valuename,
+ REGISTRY_VALUE *value)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETPRINTERDATAEX in;
+ SPOOL_R_GETPRINTERDATAEX out;
+ uint32 offered = 0;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_getprinterdataex( &in, hnd, keyname, valuename, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_GETPRINTERDATAEX,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_getprinterdataex,
+ spoolss_io_r_getprinterdataex,
+ WERR_GENERAL_FAILURE );
+
+ if ( W_ERROR_EQUAL( out.status, WERR_MORE_DATA ) ) {
+ offered = out.needed;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_getprinterdataex( &in, hnd, keyname, valuename, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_GETPRINTERDATAEX,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_getprinterdataex,
+ spoolss_io_r_getprinterdataex,
+ WERR_GENERAL_FAILURE );
+ }
+
+ if (!W_ERROR_IS_OK(out.status))
+ return out.status;
+
+ /* Return output parameters */
+
+ if (out.needed) {
+ value->data_p = (uint8 *)TALLOC_MEMDUP(mem_ctx, out.data, out.needed);
+ } else {
+ value->data_p = NULL;
+ }
+ value->type = out.type;
+ value->size = out.needed;
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_setprinterdata(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, REGISTRY_VALUE *value)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_SETPRINTERDATA in;
+ SPOOL_R_SETPRINTERDATA out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_setprinterdata( &in, hnd, value->valuename,
+ value->type, (char *)value->data_p, value->size);
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_SETPRINTERDATA,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_setprinterdata,
+ spoolss_io_r_setprinterdata,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_setprinterdataex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, char *keyname,
+ REGISTRY_VALUE *value)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_SETPRINTERDATAEX in;
+ SPOOL_R_SETPRINTERDATAEX out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_setprinterdataex( &in, hnd, keyname, value->valuename,
+ value->type, (char *)value->data_p, value->size);
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_SETPRINTERDATAEX,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_setprinterdataex,
+ spoolss_io_r_setprinterdataex,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_enumprinterdata(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, uint32 ndx,
+ uint32 value_offered, uint32 data_offered,
+ uint32 *value_needed, uint32 *data_needed,
+ REGISTRY_VALUE *value)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENUMPRINTERDATA in;
+ SPOOL_R_ENUMPRINTERDATA out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_enumprinterdata( &in, hnd, ndx, value_offered, data_offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENUMPRINTERDATA,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_enumprinterdata,
+ spoolss_io_r_enumprinterdata,
+ WERR_GENERAL_FAILURE );
+
+ if ( value_needed )
+ *value_needed = out.realvaluesize;
+ if ( data_needed )
+ *data_needed = out.realdatasize;
+
+ if (!W_ERROR_IS_OK(out.status))
+ return out.status;
+
+ if (value) {
+ rpcstr_pull(value->valuename, out.value, sizeof(value->valuename), -1,
+ STR_TERMINATE);
+ if (out.realdatasize) {
+ value->data_p = (uint8 *)TALLOC_MEMDUP(mem_ctx, out.data,
+ out.realdatasize);
+ } else {
+ value->data_p = NULL;
+ }
+ value->type = out.type;
+ value->size = out.realdatasize;
+ }
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_enumprinterdataex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, const char *keyname,
+ REGVAL_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENUMPRINTERDATAEX in;
+ SPOOL_R_ENUMPRINTERDATAEX out;
+ int i;
+ uint32 offered;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ offered = 0;
+ make_spoolss_q_enumprinterdataex( &in, hnd, keyname, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENUMPRINTERDATAEX,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_enumprinterdataex,
+ spoolss_io_r_enumprinterdataex,
+ WERR_GENERAL_FAILURE );
+
+ if ( W_ERROR_EQUAL( out.status, WERR_MORE_DATA ) ) {
+ offered = out.needed;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_enumprinterdataex( &in, hnd, keyname, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENUMPRINTERDATAEX,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_enumprinterdataex,
+ spoolss_io_r_enumprinterdataex,
+ WERR_GENERAL_FAILURE );
+ }
+
+ if (!W_ERROR_IS_OK(out.status))
+ return out.status;
+
+ for (i = 0; i < out.returned; i++) {
+ PRINTER_ENUM_VALUES *v = &out.ctr.values[i];
+ fstring name;
+
+ rpcstr_pull(name, v->valuename.buffer, sizeof(name), -1,
+ STR_TERMINATE);
+ regval_ctr_addvalue(ctr, name, v->type, (const char *)v->data, v->data_len);
+ }
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_writeprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, uint32 data_size, char *data,
+ uint32 *num_written)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_WRITEPRINTER in;
+ SPOOL_R_WRITEPRINTER out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_writeprinter( &in, hnd, data_size, data );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_WRITEPRINTER,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_writeprinter,
+ spoolss_io_r_writeprinter,
+ WERR_GENERAL_FAILURE );
+
+ if (num_written)
+ *num_written = out.buffer_written;
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_deleteprinterdata(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, char *valuename)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_DELETEPRINTERDATA in;
+ SPOOL_R_DELETEPRINTERDATA out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_deleteprinterdata( &in, hnd, valuename );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_DELETEPRINTERDATA,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_deleteprinterdata,
+ spoolss_io_r_deleteprinterdata,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_deleteprinterdataex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, char *keyname,
+ char *valuename)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_DELETEPRINTERDATAEX in;
+ SPOOL_R_DELETEPRINTERDATAEX out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_deleteprinterdataex( &in, hnd, keyname, valuename );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_DELETEPRINTERDATAEX,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_deleteprinterdataex,
+ spoolss_io_r_deleteprinterdataex,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_enumprinterkey(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, const char *keyname,
+ uint16 **keylist, uint32 *len)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENUMPRINTERKEY in;
+ SPOOL_R_ENUMPRINTERKEY out;
+ uint32 offered = 0;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_enumprinterkey( &in, hnd, keyname, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENUMPRINTERKEY,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_enumprinterkey,
+ spoolss_io_r_enumprinterkey,
+ WERR_GENERAL_FAILURE );
+
+ if ( W_ERROR_EQUAL( out.status, WERR_MORE_DATA ) ) {
+ offered = out.needed;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_enumprinterkey( &in, hnd, keyname, offered );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ENUMPRINTERKEY,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_enumprinterkey,
+ spoolss_io_r_enumprinterkey,
+ WERR_GENERAL_FAILURE );
+ }
+
+ if ( !W_ERROR_IS_OK(out.status) )
+ return out.status;
+
+ if (keylist) {
+ *keylist = SMB_MALLOC_ARRAY(uint16, out.keys.buf_len);
+ if (!*keylist) {
+ return WERR_NOMEM;
+ }
+ memcpy(*keylist, out.keys.buffer, out.keys.buf_len * 2);
+ if (len)
+ *len = out.keys.buf_len * 2;
+ }
+
+ return out.status;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WERROR rpccli_spoolss_deleteprinterkey(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, char *keyname)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_DELETEPRINTERKEY in;
+ SPOOL_R_DELETEPRINTERKEY out;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ make_spoolss_q_deleteprinterkey( &in, hnd, keyname );
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_DELETEPRINTERKEY,
+ in, out,
+ qbuf, rbuf,
+ spoolss_io_q_deleteprinterkey,
+ spoolss_io_r_deleteprinterkey,
+ WERR_GENERAL_FAILURE );
+
+ return out.status;
+}
+
+/** @} **/
diff --git a/source3/rpc_client/cli_spoolss_notify.c b/source3/rpc_client/cli_spoolss_notify.c
new file mode 100644
index 0000000000..5440f76248
--- /dev/null
+++ b/source3/rpc_client/cli_spoolss_notify.c
@@ -0,0 +1,218 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Gerald Carter 2001-2002,
+ Copyright (C) Tim Potter 2000-2002,
+ Copyright (C) Andrew Tridgell 1994-2000,
+ Copyright (C) Jean-Francois Micouleau 1999-2000.
+ Copyright (C) Jeremy Allison 2005.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*
+ * SPOOLSS Client RPC's used by servers as the notification
+ * back channel.
+ */
+
+/* Send a ReplyOpenPrinter request. This rpc is made by the printer
+ server to the printer client in response to a rffpcnex request.
+ The rrfpcnex request names a printer and a handle (the printerlocal
+ value) and this rpc establishes a back-channel over which printer
+ notifications are performed. */
+
+WERROR rpccli_spoolss_reply_open_printer(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ const char *printer, uint32 printerlocal, uint32 type,
+ POLICY_HND *handle)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_REPLYOPENPRINTER q;
+ SPOOL_R_REPLYOPENPRINTER r;
+ WERROR result = W_ERROR(ERRgeneral);
+
+ /* Initialise input parameters */
+
+ make_spoolss_q_replyopenprinter(&q, printer, printerlocal, type);
+
+ /* Marshall data and send request */
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_REPLYOPENPRINTER,
+ q, r,
+ qbuf, rbuf,
+ spoolss_io_q_replyopenprinter,
+ spoolss_io_r_replyopenprinter,
+ WERR_GENERAL_FAILURE );
+
+ /* Return result */
+
+ memcpy(handle, &r.handle, sizeof(r.handle));
+ result = r.status;
+
+ return result;
+}
+
+/* Close a back-channel notification connection */
+
+WERROR rpccli_spoolss_reply_close_printer(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *handle)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_REPLYCLOSEPRINTER q;
+ SPOOL_R_REPLYCLOSEPRINTER r;
+ WERROR result = W_ERROR(ERRgeneral);
+
+ /* Initialise input parameters */
+
+ make_spoolss_q_reply_closeprinter(&q, handle);
+
+ /* Marshall data and send request */
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_REPLYCLOSEPRINTER,
+ q, r,
+ qbuf, rbuf,
+ spoolss_io_q_replycloseprinter,
+ spoolss_io_r_replycloseprinter,
+ WERR_GENERAL_FAILURE );
+
+ /* Return result */
+
+ result = r.status;
+ return result;
+}
+
+/*********************************************************************
+ This SPOOLSS_ROUTERREPLYPRINTER function is used to send a change
+ notification event when the registration **did not** use
+ SPOOL_NOTIFY_OPTION_TYPE structure to specify the events to monitor.
+ Also see cli_spolss_reply_rrpcn()
+ *********************************************************************/
+
+WERROR rpccli_spoolss_routerreplyprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 condition, uint32 change_id)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ROUTERREPLYPRINTER q;
+ SPOOL_R_ROUTERREPLYPRINTER r;
+ WERROR result = W_ERROR(ERRgeneral);
+
+ /* Initialise input parameters */
+
+ make_spoolss_q_routerreplyprinter(&q, pol, condition, change_id);
+
+ /* Marshall data and send request */
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_ROUTERREPLYPRINTER,
+ q, r,
+ qbuf, rbuf,
+ spoolss_io_q_routerreplyprinter,
+ spoolss_io_r_routerreplyprinter,
+ WERR_GENERAL_FAILURE );
+
+ /* Return output parameters */
+
+ result = r.status;
+ return result;
+}
+
+/*********************************************************************
+ This SPOOLSS_REPLY_RRPCN function is used to send a change
+ notification event when the registration **did** use
+ SPOOL_NOTIFY_OPTION_TYPE structure to specify the events to monitor
+ Also see cli_spoolss_routereplyprinter()
+ *********************************************************************/
+
+WERROR rpccli_spoolss_rrpcn(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 notify_data_len,
+ SPOOL_NOTIFY_INFO_DATA *notify_data,
+ uint32 change_low, uint32 change_high)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_REPLY_RRPCN q;
+ SPOOL_R_REPLY_RRPCN r;
+ WERROR result = W_ERROR(ERRgeneral);
+ SPOOL_NOTIFY_INFO notify_info;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ ZERO_STRUCT(notify_info);
+
+ /* Initialise input parameters */
+
+ notify_info.version = 0x2;
+ notify_info.flags = 0x00020000; /* ?? */
+ notify_info.count = notify_data_len;
+ notify_info.data = notify_data;
+
+ /* create and send a MSRPC command with api */
+ /* store the parameters */
+
+ make_spoolss_q_reply_rrpcn(&q, pol, change_low, change_high,
+ &notify_info);
+
+ /* Marshall data and send request */
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_RRPCN,
+ q, r,
+ qbuf, rbuf,
+ spoolss_io_q_reply_rrpcn,
+ spoolss_io_r_reply_rrpcn,
+ WERR_GENERAL_FAILURE );
+
+ if (r.unknown0 == 0x00080000)
+ DEBUG(8,("cli_spoolss_reply_rrpcn: I think the spooler resonded that the notification was ignored.\n"));
+ else if ( r.unknown0 != 0x0 )
+ DEBUG(8,("cli_spoolss_reply_rrpcn: unknown0 is non-zero [0x%x]\n", r.unknown0));
+
+ result = r.status;
+ return result;
+}
+
+/*********************************************************************
+ *********************************************************************/
+
+WERROR rpccli_spoolss_rffpcnex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 flags, uint32 options,
+ const char *localmachine, uint32 printerlocal,
+ SPOOL_NOTIFY_OPTION *option)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_RFFPCNEX q;
+ SPOOL_R_RFFPCNEX r;
+ WERROR result = W_ERROR(ERRgeneral);
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise input parameters */
+
+ make_spoolss_q_rffpcnex(
+ &q, pol, flags, options, localmachine, printerlocal,
+ option);
+
+ /* Marshall data and send request */
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &syntax_spoolss, SPOOLSS_RFFPCNEX,
+ q, r,
+ qbuf, rbuf,
+ spoolss_io_q_rffpcnex,
+ spoolss_io_r_rffpcnex,
+ WERR_GENERAL_FAILURE );
+
+ result = r.status;
+ return result;
+}
diff --git a/source3/rpc_client/cli_svcctl.c b/source3/rpc_client/cli_svcctl.c
new file mode 100644
index 0000000000..3c29dcdee8
--- /dev/null
+++ b/source3/rpc_client/cli_svcctl.c
@@ -0,0 +1,168 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Gerald Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "includes.h"
+#include "rpc_client.h"
+
+/*******************************************************************
+*******************************************************************/
+
+WERROR rpccli_svcctl_enumerate_services( struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hSCM, uint32 type, uint32 state,
+ uint32 *returned, ENUM_SERVICES_STATUS **service_array )
+{
+ SVCCTL_Q_ENUM_SERVICES_STATUS in;
+ SVCCTL_R_ENUM_SERVICES_STATUS out;
+ prs_struct qbuf, rbuf;
+ uint32 resume = 0;
+ ENUM_SERVICES_STATUS *services;
+ int i;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ /* setup the request */
+
+ memcpy( &in.handle, hSCM, sizeof(POLICY_HND) );
+
+ in.type = type;
+ in.state = state;
+ in.resume = &resume;
+
+ /* first time is to get the buffer size */
+ in.buffer_size = 0;
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &ndr_table_svcctl.syntax_id, SVCCTL_ENUM_SERVICES_STATUS_W,
+ in, out,
+ qbuf, rbuf,
+ svcctl_io_q_enum_services_status,
+ svcctl_io_r_enum_services_status,
+ WERR_GENERAL_FAILURE );
+
+ /* second time with correct buffer size...should be ok */
+
+ if ( W_ERROR_EQUAL( out.status, WERR_MORE_DATA ) ) {
+ in.buffer_size = out.needed;
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &ndr_table_svcctl.syntax_id,
+ SVCCTL_ENUM_SERVICES_STATUS_W,
+ in, out,
+ qbuf, rbuf,
+ svcctl_io_q_enum_services_status,
+ svcctl_io_r_enum_services_status,
+ WERR_GENERAL_FAILURE );
+ }
+
+ if ( !W_ERROR_IS_OK(out.status) )
+ return out.status;
+
+ /* pull out the data */
+ if (out.returned) {
+ if ( !(services = TALLOC_ARRAY( mem_ctx, ENUM_SERVICES_STATUS, out.returned )) )
+ return WERR_NOMEM;
+ } else {
+ services = NULL;
+ }
+
+ for ( i=0; i<out.returned; i++ ) {
+ svcctl_io_enum_services_status( "", &services[i], &out.buffer, 0 );
+ }
+
+ *service_array = services;
+ *returned = out.returned;
+
+ return out.status;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+WERROR rpccli_svcctl_query_config(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *hService, SERVICE_CONFIG *config )
+{
+ SVCCTL_Q_QUERY_SERVICE_CONFIG in;
+ SVCCTL_R_QUERY_SERVICE_CONFIG out;
+ prs_struct qbuf, rbuf;
+
+ ZERO_STRUCT(in);
+ ZERO_STRUCT(out);
+
+ memcpy( &in.handle, hService, sizeof(POLICY_HND) );
+ in.buffer_size = 0;
+
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &ndr_table_svcctl.syntax_id,
+ SVCCTL_QUERY_SERVICE_CONFIG_W,
+ in, out,
+ qbuf, rbuf,
+ svcctl_io_q_query_service_config,
+ svcctl_io_r_query_service_config,
+ WERR_GENERAL_FAILURE );
+
+ if ( W_ERROR_EQUAL( out.status, WERR_INSUFFICIENT_BUFFER ) ) {
+ in.buffer_size = out.needed;
+
+ CLI_DO_RPC_WERR( cli, mem_ctx, &ndr_table_svcctl.syntax_id,
+ SVCCTL_QUERY_SERVICE_CONFIG_W,
+ in, out,
+ qbuf, rbuf,
+ svcctl_io_q_query_service_config,
+ svcctl_io_r_query_service_config,
+ WERR_GENERAL_FAILURE );
+ }
+
+ if ( !W_ERROR_IS_OK( out.status ) )
+ return out.status;
+
+ memcpy( config, &out.config, sizeof(SERVICE_CONFIG) );
+
+ config->executablepath = TALLOC_ZERO_P( mem_ctx, UNISTR2 );
+ config->loadordergroup = TALLOC_ZERO_P( mem_ctx, UNISTR2 );
+ config->dependencies = TALLOC_ZERO_P( mem_ctx, UNISTR2 );
+ config->startname = TALLOC_ZERO_P( mem_ctx, UNISTR2 );
+ config->displayname = TALLOC_ZERO_P( mem_ctx, UNISTR2 );
+
+ if ( out.config.executablepath ) {
+ config->executablepath = TALLOC_ZERO_P( mem_ctx, UNISTR2 );
+ copy_unistr2( config->executablepath, out.config.executablepath );
+ }
+
+ if ( out.config.loadordergroup ) {
+ config->loadordergroup = TALLOC_ZERO_P( mem_ctx, UNISTR2 );
+ copy_unistr2( config->loadordergroup, out.config.loadordergroup );
+ }
+
+ if ( out.config.dependencies ) {
+ config->dependencies = TALLOC_ZERO_P( mem_ctx, UNISTR2 );
+ copy_unistr2( config->dependencies, out.config.dependencies );
+ }
+
+ if ( out.config.startname ) {
+ config->startname = TALLOC_ZERO_P( mem_ctx, UNISTR2 );
+ copy_unistr2( config->startname, out.config.startname );
+ }
+
+ if ( out.config.displayname ) {
+ config->displayname = TALLOC_ZERO_P( mem_ctx, UNISTR2 );
+ copy_unistr2( config->displayname, out.config.displayname );
+ }
+
+ return out.status;
+}
diff --git a/source3/rpc_client/init_lsa.c b/source3/rpc_client/init_lsa.c
new file mode 100644
index 0000000000..9777f27629
--- /dev/null
+++ b/source3/rpc_client/init_lsa.c
@@ -0,0 +1,128 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Guenther Deschner 2008.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_lsa_String(struct lsa_String *name, const char *s)
+{
+ name->string = s;
+ name->size = 2 * strlen_m(s);
+ name->length = name->size;
+}
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_lsa_StringLarge(struct lsa_StringLarge *name, const char *s)
+{
+ name->string = s;
+}
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_lsa_AsciiString(struct lsa_AsciiString *name, const char *s)
+{
+ name->string = s;
+}
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_lsa_AsciiStringLarge(struct lsa_AsciiStringLarge *name, const char *s)
+{
+ name->string = s;
+}
+
+/*******************************************************************
+ Inits an lsa_QosInfo structure.
+********************************************************************/
+
+void init_lsa_sec_qos(struct lsa_QosInfo *r,
+ uint32_t len,
+ uint16_t impersonation_level,
+ uint8_t context_mode,
+ uint8_t effective_only)
+{
+ DEBUG(5, ("init_lsa_sec_qos\n"));
+
+ r->len = len;
+ r->impersonation_level = impersonation_level;
+ r->context_mode = context_mode;
+ r->effective_only = effective_only;
+}
+
+/*******************************************************************
+ Inits an lsa_ObjectAttribute structure.
+********************************************************************/
+
+void init_lsa_obj_attr(struct lsa_ObjectAttribute *r,
+ uint32_t len,
+ uint8_t *root_dir,
+ const char *object_name,
+ uint32_t attributes,
+ struct security_descriptor *sec_desc,
+ struct lsa_QosInfo *sec_qos)
+{
+ DEBUG(5,("init_lsa_obj_attr\n"));
+
+ r->len = len;
+ r->root_dir = root_dir;
+ r->object_name = object_name;
+ r->attributes = attributes;
+ r->sec_desc = sec_desc;
+ r->sec_qos = sec_qos;
+}
+
+/*******************************************************************
+ Inits a lsa_TranslatedSid structure.
+********************************************************************/
+
+void init_lsa_translated_sid(struct lsa_TranslatedSid *r,
+ enum lsa_SidType sid_type,
+ uint32_t rid,
+ uint32_t sid_index)
+{
+ r->sid_type = sid_type;
+ r->rid = rid;
+ r->sid_index = sid_index;
+}
+
+/*******************************************************************
+ Inits a lsa_TranslatedName2 structure.
+********************************************************************/
+
+void init_lsa_translated_name2(struct lsa_TranslatedName2 *r,
+ enum lsa_SidType sid_type,
+ const char *name,
+ uint32_t sid_index,
+ uint32_t unknown)
+{
+ r->sid_type = sid_type;
+ init_lsa_String(&r->name, name);
+ r->sid_index = sid_index;
+ r->unknown = unknown;
+}
diff --git a/source3/rpc_client/init_netlogon.c b/source3/rpc_client/init_netlogon.c
new file mode 100644
index 0000000000..61841953fc
--- /dev/null
+++ b/source3/rpc_client/init_netlogon.c
@@ -0,0 +1,393 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Guenther Deschner 2008.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_netr_SamBaseInfo(struct netr_SamBaseInfo *r,
+ NTTIME last_logon,
+ NTTIME last_logoff,
+ NTTIME acct_expiry,
+ NTTIME last_password_change,
+ NTTIME allow_password_change,
+ NTTIME force_password_change,
+ const char *account_name,
+ const char *full_name,
+ const char *logon_script,
+ const char *profile_path,
+ const char *home_directory,
+ const char *home_drive,
+ uint16_t logon_count,
+ uint16_t bad_password_count,
+ uint32_t rid,
+ uint32_t primary_gid,
+ struct samr_RidWithAttributeArray groups,
+ uint32_t user_flags,
+ struct netr_UserSessionKey key,
+ const char *logon_server,
+ const char *domain,
+ struct dom_sid2 *domain_sid,
+ struct netr_LMSessionKey LMSessKey,
+ uint32_t acct_flags)
+{
+ r->last_logon = last_logon;
+ r->last_logoff = last_logoff;
+ r->acct_expiry = acct_expiry;
+ r->last_password_change = last_password_change;
+ r->allow_password_change = allow_password_change;
+ r->force_password_change = force_password_change;
+ init_lsa_String(&r->account_name, account_name);
+ init_lsa_String(&r->full_name, full_name);
+ init_lsa_String(&r->logon_script, logon_script);
+ init_lsa_String(&r->profile_path, profile_path);
+ init_lsa_String(&r->home_directory, home_directory);
+ init_lsa_String(&r->home_drive, home_drive);
+ r->logon_count = logon_count;
+ r->bad_password_count = bad_password_count;
+ r->rid = rid;
+ r->primary_gid = primary_gid;
+ r->groups = groups;
+ r->user_flags = user_flags;
+ r->key = key;
+ init_lsa_StringLarge(&r->logon_server, logon_server);
+ init_lsa_StringLarge(&r->domain, domain);
+ r->domain_sid = domain_sid;
+ r->LMSessKey = LMSessKey;
+ r->acct_flags = acct_flags;
+}
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_netr_SamInfo3(struct netr_SamInfo3 *r,
+ NTTIME last_logon,
+ NTTIME last_logoff,
+ NTTIME acct_expiry,
+ NTTIME last_password_change,
+ NTTIME allow_password_change,
+ NTTIME force_password_change,
+ const char *account_name,
+ const char *full_name,
+ const char *logon_script,
+ const char *profile_path,
+ const char *home_directory,
+ const char *home_drive,
+ uint16_t logon_count,
+ uint16_t bad_password_count,
+ uint32_t rid,
+ uint32_t primary_gid,
+ struct samr_RidWithAttributeArray groups,
+ uint32_t user_flags,
+ struct netr_UserSessionKey key,
+ const char *logon_server,
+ const char *domain,
+ struct dom_sid2 *domain_sid,
+ struct netr_LMSessionKey LMSessKey,
+ uint32_t acct_flags,
+ uint32_t sidcount,
+ struct netr_SidAttr *sids)
+{
+ init_netr_SamBaseInfo(&r->base,
+ last_logon,
+ last_logoff,
+ acct_expiry,
+ last_password_change,
+ allow_password_change,
+ force_password_change,
+ account_name,
+ full_name,
+ logon_script,
+ profile_path,
+ home_directory,
+ home_drive,
+ logon_count,
+ bad_password_count,
+ rid,
+ primary_gid,
+ groups,
+ user_flags,
+ key,
+ logon_server,
+ domain,
+ domain_sid,
+ LMSessKey,
+ acct_flags);
+ r->sidcount = sidcount;
+ r->sids = sids;
+}
+
+/*******************************************************************
+ gets a domain user's groups from their already-calculated NT_USER_TOKEN
+ ********************************************************************/
+
+static NTSTATUS nt_token_to_group_list(TALLOC_CTX *mem_ctx,
+ const DOM_SID *domain_sid,
+ size_t num_sids,
+ const DOM_SID *sids,
+ int *numgroups, DOM_GID **pgids)
+{
+ int i;
+
+ *numgroups=0;
+ *pgids = NULL;
+
+ for (i=0; i<num_sids; i++) {
+ DOM_GID gid;
+ if (!sid_peek_check_rid(domain_sid, &sids[i], &gid.g_rid)) {
+ continue;
+ }
+ gid.attr = (SE_GROUP_MANDATORY|SE_GROUP_ENABLED_BY_DEFAULT|
+ SE_GROUP_ENABLED);
+ ADD_TO_ARRAY(mem_ctx, DOM_GID, gid, pgids, numgroups);
+ if (*pgids == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ inits a netr_SamInfo3 structure from an auth_serversupplied_info. sam3 must
+ already be initialized and is used as the talloc parent for its members.
+*****************************************************************************/
+
+NTSTATUS serverinfo_to_SamInfo3(struct auth_serversupplied_info *server_info,
+ uint8_t pipe_session_key[16],
+ struct netr_SamInfo3 *sam3)
+{
+ struct samu *sampw;
+ DOM_GID *gids = NULL;
+ const DOM_SID *user_sid = NULL;
+ const DOM_SID *group_sid = NULL;
+ DOM_SID domain_sid;
+ uint32 user_rid, group_rid;
+ NTSTATUS status;
+
+ int num_gids = 0;
+ const char *my_name;
+
+ struct netr_UserSessionKey user_session_key;
+ struct netr_LMSessionKey lm_session_key;
+
+ NTTIME last_logon, last_logoff, acct_expiry, last_password_change;
+ NTTIME allow_password_change, force_password_change;
+ struct samr_RidWithAttributeArray groups;
+ int i;
+ struct dom_sid2 *sid = NULL;
+
+ ZERO_STRUCT(user_session_key);
+ ZERO_STRUCT(lm_session_key);
+
+ sampw = server_info->sam_account;
+
+ user_sid = pdb_get_user_sid(sampw);
+ group_sid = pdb_get_group_sid(sampw);
+
+ if ((user_sid == NULL) || (group_sid == NULL)) {
+ DEBUG(1, ("_netr_LogonSamLogon: User without group or user SID\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ sid_copy(&domain_sid, user_sid);
+ sid_split_rid(&domain_sid, &user_rid);
+
+ sid = sid_dup_talloc(sam3, &domain_sid);
+ if (!sid) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!sid_peek_check_rid(&domain_sid, group_sid, &group_rid)) {
+ DEBUG(1, ("_netr_LogonSamLogon: user %s\\%s has user sid "
+ "%s\n but group sid %s.\n"
+ "The conflicting domain portions are not "
+ "supported for NETLOGON calls\n",
+ pdb_get_domain(sampw),
+ pdb_get_username(sampw),
+ sid_string_dbg(user_sid),
+ sid_string_dbg(group_sid)));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if(server_info->login_server) {
+ my_name = server_info->login_server;
+ } else {
+ my_name = global_myname();
+ }
+
+ status = nt_token_to_group_list(sam3, &domain_sid,
+ server_info->num_sids,
+ server_info->sids,
+ &num_gids, &gids);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (server_info->user_session_key.length) {
+ memcpy(user_session_key.key,
+ server_info->user_session_key.data,
+ MIN(sizeof(user_session_key.key),
+ server_info->user_session_key.length));
+ SamOEMhash(user_session_key.key, pipe_session_key, 16);
+ }
+ if (server_info->lm_session_key.length) {
+ memcpy(lm_session_key.key,
+ server_info->lm_session_key.data,
+ MIN(sizeof(lm_session_key.key),
+ server_info->lm_session_key.length));
+ SamOEMhash(lm_session_key.key, pipe_session_key, 8);
+ }
+
+ groups.count = num_gids;
+ groups.rids = TALLOC_ARRAY(sam3, struct samr_RidWithAttribute, groups.count);
+ if (!groups.rids) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i < groups.count; i++) {
+ groups.rids[i].rid = gids[i].g_rid;
+ groups.rids[i].attributes = gids[i].attr;
+ }
+
+ unix_to_nt_time(&last_logon, pdb_get_logon_time(sampw));
+ unix_to_nt_time(&last_logoff, get_time_t_max());
+ unix_to_nt_time(&acct_expiry, get_time_t_max());
+ unix_to_nt_time(&last_password_change, pdb_get_pass_last_set_time(sampw));
+ unix_to_nt_time(&allow_password_change, pdb_get_pass_can_change_time(sampw));
+ unix_to_nt_time(&force_password_change, pdb_get_pass_must_change_time(sampw));
+
+ init_netr_SamInfo3(sam3,
+ last_logon,
+ last_logoff,
+ acct_expiry,
+ last_password_change,
+ allow_password_change,
+ force_password_change,
+ talloc_strdup(sam3, pdb_get_username(sampw)),
+ talloc_strdup(sam3, pdb_get_fullname(sampw)),
+ talloc_strdup(sam3, pdb_get_logon_script(sampw)),
+ talloc_strdup(sam3, pdb_get_profile_path(sampw)),
+ talloc_strdup(sam3, pdb_get_homedir(sampw)),
+ talloc_strdup(sam3, pdb_get_dir_drive(sampw)),
+ 0, /* logon_count */
+ 0, /* bad_password_count */
+ user_rid,
+ group_rid,
+ groups,
+ NETLOGON_EXTRA_SIDS,
+ user_session_key,
+ my_name,
+ talloc_strdup(sam3, pdb_get_domain(sampw)),
+ sid,
+ lm_session_key,
+ pdb_get_acct_ctrl(sampw),
+ 0, /* sidcount */
+ NULL); /* struct netr_SidAttr *sids */
+ ZERO_STRUCT(user_session_key);
+ ZERO_STRUCT(lm_session_key);
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_netr_IdentityInfo(struct netr_IdentityInfo *r,
+ const char *domain_name,
+ uint32_t parameter_control,
+ uint32_t logon_id_low,
+ uint32_t logon_id_high,
+ const char *account_name,
+ const char *workstation)
+{
+ init_lsa_String(&r->domain_name, domain_name);
+ r->parameter_control = parameter_control;
+ r->logon_id_low = logon_id_low;
+ r->logon_id_high = logon_id_high;
+ init_lsa_String(&r->account_name, account_name);
+ init_lsa_String(&r->workstation, workstation);
+}
+
+/*******************************************************************
+ inits a structure.
+ This is a network logon packet. The log_id parameters
+ are what an NT server would generate for LUID once the
+ user is logged on. I don't think we care about them.
+
+ Note that this has no access to the NT and LM hashed passwords,
+ so it forwards the challenge, and the NT and LM responses (24
+ bytes each) over the secure channel to the Domain controller
+ for it to say yea or nay. This is the preferred method of
+ checking for a logon as it doesn't export the password
+ hashes to anyone who has compromised the secure channel. JRA.
+
+********************************************************************/
+
+void init_netr_NetworkInfo(struct netr_NetworkInfo *r,
+ const char *domain_name,
+ uint32_t parameter_control,
+ uint32_t logon_id_low,
+ uint32_t logon_id_high,
+ const char *account_name,
+ const char *workstation,
+ uint8_t challenge[8],
+ struct netr_ChallengeResponse nt,
+ struct netr_ChallengeResponse lm)
+{
+ init_netr_IdentityInfo(&r->identity_info,
+ domain_name,
+ parameter_control,
+ logon_id_low,
+ logon_id_high,
+ account_name,
+ workstation);
+ memcpy(r->challenge, challenge, 8);
+ r->nt = nt;
+ r->lm = lm;
+}
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_netr_PasswordInfo(struct netr_PasswordInfo *r,
+ const char *domain_name,
+ uint32_t parameter_control,
+ uint32_t logon_id_low,
+ uint32_t logon_id_high,
+ const char *account_name,
+ const char *workstation,
+ struct samr_Password lmpassword,
+ struct samr_Password ntpassword)
+{
+ init_netr_IdentityInfo(&r->identity_info,
+ domain_name,
+ parameter_control,
+ logon_id_low,
+ logon_id_high,
+ account_name,
+ workstation);
+ r->lmpassword = lmpassword;
+ r->ntpassword = ntpassword;
+}
diff --git a/source3/rpc_client/init_samr.c b/source3/rpc_client/init_samr.c
new file mode 100644
index 0000000000..2e757531ce
--- /dev/null
+++ b/source3/rpc_client/init_samr.c
@@ -0,0 +1,508 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Guenther Deschner 2008.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_samr_DomInfo1(struct samr_DomInfo1 *r,
+ uint16_t min_password_length,
+ uint16_t password_history_length,
+ uint32_t password_properties,
+ int64_t max_password_age,
+ int64_t min_password_age)
+{
+ r->min_password_length = min_password_length;
+ r->password_history_length = password_history_length;
+ r->password_properties = password_properties;
+ r->max_password_age = max_password_age;
+ r->min_password_age = min_password_age;
+}
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_samr_DomInfo2(struct samr_DomInfo2 *r,
+ NTTIME force_logoff_time,
+ const char *comment,
+ const char *domain_name,
+ const char *primary,
+ uint64_t sequence_num,
+ uint32_t unknown2,
+ enum samr_Role role,
+ uint32_t unknown3,
+ uint32_t num_users,
+ uint32_t num_groups,
+ uint32_t num_aliases)
+{
+ r->force_logoff_time = force_logoff_time;
+ init_lsa_String(&r->comment, comment);
+ init_lsa_String(&r->domain_name, domain_name);
+ init_lsa_String(&r->primary, primary);
+ r->sequence_num = sequence_num;
+ r->unknown2 = unknown2;
+ r->role = role;
+ r->unknown3 = unknown3;
+ r->num_users = num_users;
+ r->num_groups = num_groups;
+ r->num_aliases = num_aliases;
+}
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_samr_DomInfo3(struct samr_DomInfo3 *r,
+ NTTIME force_logoff_time)
+{
+ r->force_logoff_time = force_logoff_time;
+}
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_samr_DomInfo4(struct samr_DomInfo4 *r,
+ const char *comment)
+{
+ init_lsa_String(&r->comment, comment);
+}
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_samr_DomInfo5(struct samr_DomInfo5 *r,
+ const char *domain_name)
+{
+ init_lsa_String(&r->domain_name, domain_name);
+}
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_samr_DomInfo6(struct samr_DomInfo6 *r,
+ const char *primary)
+{
+ init_lsa_String(&r->primary, primary);
+}
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_samr_DomInfo7(struct samr_DomInfo7 *r,
+ enum samr_Role role)
+{
+ r->role = role;
+}
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_samr_DomInfo8(struct samr_DomInfo8 *r,
+ uint64_t sequence_num,
+ NTTIME domain_create_time)
+{
+ r->sequence_num = sequence_num;
+ r->domain_create_time = domain_create_time;
+}
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_samr_DomInfo9(struct samr_DomInfo9 *r,
+ uint32_t unknown)
+{
+ r->unknown = unknown;
+}
+
+/*******************************************************************
+ inits a structure.
+********************************************************************/
+
+void init_samr_DomInfo12(struct samr_DomInfo12 *r,
+ uint64_t lockout_duration,
+ uint64_t lockout_window,
+ uint16_t lockout_threshold)
+{
+ r->lockout_duration = lockout_duration;
+ r->lockout_window = lockout_window;
+ r->lockout_threshold = lockout_threshold;
+}
+
+/*******************************************************************
+ inits a samr_GroupInfoAll structure.
+********************************************************************/
+
+void init_samr_group_info1(struct samr_GroupInfoAll *r,
+ const char *name,
+ uint32_t attributes,
+ uint32_t num_members,
+ const char *description)
+{
+ DEBUG(5, ("init_samr_group_info1\n"));
+
+ init_lsa_String(&r->name, name);
+ r->attributes = attributes;
+ r->num_members = num_members;
+ init_lsa_String(&r->description, description);
+}
+
+/*******************************************************************
+ inits a lsa_String structure
+********************************************************************/
+
+void init_samr_group_info2(struct lsa_String *r, const char *group_name)
+{
+ DEBUG(5, ("init_samr_group_info2\n"));
+
+ init_lsa_String(r, group_name);
+}
+
+/*******************************************************************
+ inits a samr_GroupInfoAttributes structure.
+********************************************************************/
+
+void init_samr_group_info3(struct samr_GroupInfoAttributes *r,
+ uint32_t attributes)
+{
+ DEBUG(5, ("init_samr_group_info3\n"));
+
+ r->attributes = attributes;
+}
+
+/*******************************************************************
+ inits a lsa_String structure
+********************************************************************/
+
+void init_samr_group_info4(struct lsa_String *r, const char *description)
+{
+ DEBUG(5, ("init_samr_group_info4\n"));
+
+ init_lsa_String(r, description);
+}
+
+/*******************************************************************
+ inits a samr_GroupInfoAll structure.
+********************************************************************/
+
+void init_samr_group_info5(struct samr_GroupInfoAll *r,
+ const char *name,
+ uint32_t attributes,
+ uint32_t num_members,
+ const char *description)
+{
+ DEBUG(5, ("init_samr_group_info5\n"));
+
+ init_lsa_String(&r->name, name);
+ r->attributes = attributes;
+ r->num_members = num_members;
+ init_lsa_String(&r->description, description);
+}
+
+/*******************************************************************
+ inits a samr_AliasInfoAll structure.
+********************************************************************/
+
+void init_samr_alias_info1(struct samr_AliasInfoAll *r,
+ const char *name,
+ uint32_t num_members,
+ const char *description)
+{
+ DEBUG(5, ("init_samr_alias_info1\n"));
+
+ init_lsa_String(&r->name, name);
+ r->num_members = num_members;
+ init_lsa_String(&r->description, description);
+}
+
+/*******************************************************************
+inits a lsa_String structure.
+********************************************************************/
+
+void init_samr_alias_info3(struct lsa_String *r,
+ const char *description)
+{
+ DEBUG(5, ("init_samr_alias_info3\n"));
+
+ init_lsa_String(r, description);
+}
+
+/*******************************************************************
+ inits a samr_UserInfo7 structure.
+********************************************************************/
+
+void init_samr_user_info7(struct samr_UserInfo7 *r,
+ const char *account_name)
+{
+ DEBUG(5, ("init_samr_user_info7\n"));
+
+ init_lsa_String(&r->account_name, account_name);
+}
+
+/*******************************************************************
+ inits a samr_UserInfo9 structure.
+********************************************************************/
+
+void init_samr_user_info9(struct samr_UserInfo9 *r,
+ uint32_t primary_gid)
+{
+ DEBUG(5, ("init_samr_user_info9\n"));
+
+ r->primary_gid = primary_gid;
+}
+
+/*******************************************************************
+ inits a SAM_USER_INFO_16 structure.
+********************************************************************/
+
+void init_samr_user_info16(struct samr_UserInfo16 *r,
+ uint32_t acct_flags)
+{
+ DEBUG(5, ("init_samr_user_info16\n"));
+
+ r->acct_flags = acct_flags;
+}
+
+/*******************************************************************
+ inits a samr_UserInfo18 structure.
+********************************************************************/
+
+void init_samr_user_info18(struct samr_UserInfo18 *r,
+ const uint8 lm_pwd[16],
+ const uint8 nt_pwd[16])
+{
+ DEBUG(5, ("init_samr_user_info18\n"));
+
+ r->lm_pwd_active =
+ memcpy(r->lm_pwd.hash, lm_pwd, sizeof(r->lm_pwd.hash)) ? true : false;
+ r->nt_pwd_active =
+ memcpy(r->nt_pwd.hash, nt_pwd, sizeof(r->nt_pwd.hash)) ? true : false;
+}
+
+/*******************************************************************
+ inits a samr_UserInfo20 structure.
+********************************************************************/
+
+void init_samr_user_info20(struct samr_UserInfo20 *r,
+ struct lsa_BinaryString *parameters)
+{
+ r->parameters = *parameters;
+}
+
+/*************************************************************************
+ inits a samr_UserInfo21 structure
+ *************************************************************************/
+
+void init_samr_user_info21(struct samr_UserInfo21 *r,
+ NTTIME last_logon,
+ NTTIME last_logoff,
+ NTTIME last_password_change,
+ NTTIME acct_expiry,
+ NTTIME allow_password_change,
+ NTTIME force_password_change,
+ const char *account_name,
+ const char *full_name,
+ const char *home_directory,
+ const char *home_drive,
+ const char *logon_script,
+ const char *profile_path,
+ const char *description,
+ const char *workstations,
+ const char *comment,
+ struct lsa_BinaryString *parameters,
+ uint32_t rid,
+ uint32_t primary_gid,
+ uint32_t acct_flags,
+ uint32_t fields_present,
+ struct samr_LogonHours logon_hours,
+ uint16_t bad_password_count,
+ uint16_t logon_count,
+ uint16_t country_code,
+ uint16_t code_page,
+ uint8_t nt_password_set,
+ uint8_t lm_password_set,
+ uint8_t password_expired)
+{
+ r->last_logon = last_logon;
+ r->last_logoff = last_logoff;
+ r->last_password_change = last_password_change;
+ r->acct_expiry = acct_expiry;
+ r->allow_password_change = allow_password_change;
+ r->force_password_change = force_password_change;
+ init_lsa_String(&r->account_name, account_name);
+ init_lsa_String(&r->full_name, full_name);
+ init_lsa_String(&r->home_directory, home_directory);
+ init_lsa_String(&r->home_drive, home_drive);
+ init_lsa_String(&r->logon_script, logon_script);
+ init_lsa_String(&r->profile_path, profile_path);
+ init_lsa_String(&r->description, description);
+ init_lsa_String(&r->workstations, workstations);
+ init_lsa_String(&r->comment, comment);
+ r->parameters = *parameters;
+ r->rid = rid;
+ r->primary_gid = primary_gid;
+ r->acct_flags = acct_flags;
+ r->fields_present = fields_present;
+ r->logon_hours = logon_hours;
+ r->bad_password_count = bad_password_count;
+ r->logon_count = logon_count;
+ r->country_code = country_code;
+ r->code_page = code_page;
+ r->nt_password_set = nt_password_set;
+ r->lm_password_set = lm_password_set;
+ r->password_expired = password_expired;
+}
+
+/*************************************************************************
+ init_samr_user_info23
+ *************************************************************************/
+
+void init_samr_user_info23(struct samr_UserInfo23 *r,
+ NTTIME last_logon,
+ NTTIME last_logoff,
+ NTTIME last_password_change,
+ NTTIME acct_expiry,
+ NTTIME allow_password_change,
+ NTTIME force_password_change,
+ const char *account_name,
+ const char *full_name,
+ const char *home_directory,
+ const char *home_drive,
+ const char *logon_script,
+ const char *profile_path,
+ const char *description,
+ const char *workstations,
+ const char *comment,
+ struct lsa_BinaryString *parameters,
+ uint32_t rid,
+ uint32_t primary_gid,
+ uint32_t acct_flags,
+ uint32_t fields_present,
+ struct samr_LogonHours logon_hours,
+ uint16_t bad_password_count,
+ uint16_t logon_count,
+ uint16_t country_code,
+ uint16_t code_page,
+ uint8_t nt_password_set,
+ uint8_t lm_password_set,
+ uint8_t password_expired,
+ uint8_t data[516],
+ uint8_t pw_len)
+{
+ memset(r, '\0', sizeof(*r));
+ init_samr_user_info21(&r->info,
+ last_logon,
+ last_logoff,
+ last_password_change,
+ acct_expiry,
+ allow_password_change,
+ force_password_change,
+ account_name,
+ full_name,
+ home_directory,
+ home_drive,
+ logon_script,
+ profile_path,
+ description,
+ workstations,
+ comment,
+ parameters,
+ rid,
+ primary_gid,
+ acct_flags,
+ fields_present,
+ logon_hours,
+ bad_password_count,
+ logon_count,
+ country_code,
+ code_page,
+ nt_password_set,
+ lm_password_set,
+ password_expired);
+
+ memcpy(r->password.data, data, sizeof(r->password.data));
+}
+
+/*************************************************************************
+ init_samr_user_info24
+ *************************************************************************/
+
+void init_samr_user_info24(struct samr_UserInfo24 *r,
+ uint8_t data[516],
+ uint8_t pw_len)
+{
+ DEBUG(10, ("init_samr_user_info24:\n"));
+
+ memcpy(r->password.data, data, sizeof(r->password.data));
+ r->pw_len = pw_len;
+}
+
+/*************************************************************************
+ inits a samr_CryptPasswordEx structure
+ *************************************************************************/
+
+void init_samr_CryptPasswordEx(const char *pwd,
+ DATA_BLOB *session_key,
+ struct samr_CryptPasswordEx *pwd_buf)
+{
+ /* samr_CryptPasswordEx */
+
+ uchar pwbuf[532];
+ struct MD5Context md5_ctx;
+ uint8_t confounder[16];
+ DATA_BLOB confounded_session_key = data_blob(NULL, 16);
+
+ encode_pw_buffer(pwbuf, pwd, STR_UNICODE);
+
+ generate_random_buffer((uint8_t *)confounder, 16);
+
+ MD5Init(&md5_ctx);
+ MD5Update(&md5_ctx, confounder, 16);
+ MD5Update(&md5_ctx, session_key->data,
+ session_key->length);
+ MD5Final(confounded_session_key.data, &md5_ctx);
+
+ SamOEMhashBlob(pwbuf, 516, &confounded_session_key);
+ memcpy(&pwbuf[516], confounder, 16);
+
+ memcpy(pwd_buf->data, pwbuf, sizeof(pwbuf));
+ data_blob_free(&confounded_session_key);
+}
+
+/*************************************************************************
+ inits a samr_CryptPassword structure
+ *************************************************************************/
+
+void init_samr_CryptPassword(const char *pwd,
+ DATA_BLOB *session_key,
+ struct samr_CryptPassword *pwd_buf)
+{
+ /* samr_CryptPassword */
+
+ encode_pw_buffer(pwd_buf->data, pwd, STR_UNICODE);
+ SamOEMhashBlob(pwd_buf->data, 516, session_key);
+}
diff --git a/source3/rpc_client/init_srvsvc.c b/source3/rpc_client/init_srvsvc.c
new file mode 100644
index 0000000000..24beb1ace2
--- /dev/null
+++ b/source3/rpc_client/init_srvsvc.c
@@ -0,0 +1,402 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Guenther Deschner 2008.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/*******************************************************************
+ inits a srvsvc_NetSrvInfo102 structure
+********************************************************************/
+
+void init_srvsvc_NetSrvInfo102(struct srvsvc_NetSrvInfo102 *r,
+ enum srvsvc_PlatformId platform_id,
+ const char *server_name,
+ uint32_t version_major,
+ uint32_t version_minor,
+ uint32_t server_type,
+ const char *comment,
+ uint32_t users,
+ uint32_t disc,
+ uint32_t hidden,
+ uint32_t announce,
+ uint32_t anndelta,
+ uint32_t licenses,
+ const char *userpath)
+{
+ r->platform_id = platform_id;
+ r->server_name = server_name;
+ r->version_major = version_major;
+ r->version_minor = version_minor;
+ r->server_type = server_type;
+ r->comment = comment;
+ r->users = users;
+ r->disc = disc;
+ r->hidden = hidden;
+ r->announce = announce;
+ r->anndelta = anndelta;
+ r->licenses = licenses;
+ r->userpath = userpath;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetSrvInfo101 structure
+********************************************************************/
+
+void init_srvsvc_NetSrvInfo101(struct srvsvc_NetSrvInfo101 *r,
+ enum srvsvc_PlatformId platform_id,
+ const char *server_name,
+ uint32_t version_major,
+ uint32_t version_minor,
+ uint32_t server_type,
+ const char *comment)
+{
+ r->platform_id = platform_id;
+ r->server_name = server_name;
+ r->version_major = version_major;
+ r->version_minor = version_minor;
+ r->server_type = server_type;
+ r->comment = comment;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetSrvInfo100 structure
+********************************************************************/
+
+void init_srvsvc_NetSrvInfo100(struct srvsvc_NetSrvInfo100 *r,
+ enum srvsvc_PlatformId platform_id,
+ const char *server_name)
+{
+ r->platform_id = platform_id;
+ r->server_name = server_name;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetShareInfo0 structure
+********************************************************************/
+
+void init_srvsvc_NetShareInfo0(struct srvsvc_NetShareInfo0 *r,
+ const char *name)
+{
+ r->name = name;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetShareInfo1 structure
+********************************************************************/
+
+void init_srvsvc_NetShareInfo1(struct srvsvc_NetShareInfo1 *r,
+ const char *name,
+ enum srvsvc_ShareType type,
+ const char *comment)
+{
+ r->name = name;
+ r->type = type;
+ r->comment = comment;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetShareInfo2 structure
+********************************************************************/
+
+void init_srvsvc_NetShareInfo2(struct srvsvc_NetShareInfo2 *r,
+ const char *name,
+ enum srvsvc_ShareType type,
+ const char *comment,
+ uint32_t permissions,
+ uint32_t max_users,
+ uint32_t current_users,
+ const char *path,
+ const char *password)
+{
+ r->name = name;
+ r->type = type;
+ r->comment = comment;
+ r->permissions = permissions;
+ r->max_users = max_users;
+ r->current_users = current_users;
+ r->path = path;
+ r->password = password;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetShareInfo501 structure
+********************************************************************/
+
+void init_srvsvc_NetShareInfo501(struct srvsvc_NetShareInfo501 *r,
+ const char *name,
+ enum srvsvc_ShareType type,
+ const char *comment,
+ uint32_t csc_policy)
+{
+ r->name = name;
+ r->type = type;
+ r->comment = comment;
+ r->csc_policy = csc_policy;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetShareInfo502 structure
+********************************************************************/
+
+void init_srvsvc_NetShareInfo502(struct srvsvc_NetShareInfo502 *r,
+ const char *name,
+ enum srvsvc_ShareType type,
+ const char *comment,
+ uint32_t permissions,
+ uint32_t max_users,
+ uint32_t current_users,
+ const char *path,
+ const char *password,
+ struct sec_desc_buf *sd_buf)
+{
+ r->name = name;
+ r->type = type;
+ r->comment = comment;
+ r->permissions = permissions;
+ r->max_users = max_users;
+ r->current_users = current_users;
+ r->path = path;
+ r->password = password;
+ r->sd_buf = *sd_buf;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetShareInfo1004 structure
+********************************************************************/
+
+void init_srvsvc_NetShareInfo1004(struct srvsvc_NetShareInfo1004 *r,
+ const char *comment)
+{
+ r->comment = comment;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetShareInfo1005 structure
+********************************************************************/
+
+void init_srvsvc_NetShareInfo1005(struct srvsvc_NetShareInfo1005 *r,
+ uint32_t dfs_flags)
+{
+ r->dfs_flags = dfs_flags;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetShareInfo1006 structure
+********************************************************************/
+
+void init_srvsvc_NetShareInfo1006(struct srvsvc_NetShareInfo1006 *r,
+ uint32_t max_users)
+{
+ r->max_users = max_users;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetShareInfo1007 structure
+********************************************************************/
+
+void init_srvsvc_NetShareInfo1007(struct srvsvc_NetShareInfo1007 *r,
+ uint32_t flags,
+ const char *alternate_directory_name)
+{
+ r->flags = flags;
+ r->alternate_directory_name = alternate_directory_name;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetRemoteTODInfo structure
+ ********************************************************************/
+
+void init_srvsvc_NetRemoteTODInfo(struct srvsvc_NetRemoteTODInfo *r,
+ uint32_t elapsed,
+ uint32_t msecs,
+ uint32_t hours,
+ uint32_t mins,
+ uint32_t secs,
+ uint32_t hunds,
+ int32_t ttimezone,
+ uint32_t tinterval,
+ uint32_t day,
+ uint32_t month,
+ uint32_t year,
+ uint32_t weekday)
+{
+ r->elapsed = elapsed;
+ r->msecs = msecs;
+ r->hours = hours;
+ r->mins = mins;
+ r->secs = secs;
+ r->hunds = hunds;
+ r->timezone = ttimezone;
+ r->tinterval = tinterval;
+ r->day = day;
+ r->month = month;
+ r->year = year;
+ r->weekday = weekday;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetSessInfo0 structure
+ ********************************************************************/
+
+void init_srvsvc_NetSessInfo0(struct srvsvc_NetSessInfo0 *r,
+ const char *client)
+{
+ r->client = client;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetSessInfo1 structure
+ ********************************************************************/
+
+void init_srvsvc_NetSessInfo1(struct srvsvc_NetSessInfo1 *r,
+ const char *client,
+ const char *user,
+ uint32_t num_open,
+ uint32_t _time,
+ uint32_t idle_time,
+ uint32_t user_flags)
+{
+ r->client = client;
+ r->user = user;
+ r->num_open = num_open;
+ r->time = _time;
+ r->idle_time = idle_time;
+ r->user_flags = user_flags;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetSessInfo2 structure
+ ********************************************************************/
+
+void init_srvsvc_NetSessInfo2(struct srvsvc_NetSessInfo2 *r,
+ const char *client,
+ const char *user,
+ uint32_t num_open,
+ uint32_t _time,
+ uint32_t idle_time,
+ uint32_t user_flags,
+ const char *client_type)
+{
+ r->client = client;
+ r->user = user;
+ r->num_open = num_open;
+ r->time = _time;
+ r->idle_time = idle_time;
+ r->user_flags = user_flags;
+ r->client_type = client_type;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetSessInfo10 structure
+ ********************************************************************/
+
+void init_srvsvc_NetSessInfo10(struct srvsvc_NetSessInfo10 *r,
+ const char *client,
+ const char *user,
+ uint32_t _time,
+ uint32_t idle_time)
+{
+ r->client = client;
+ r->user = user;
+ r->time = _time;
+ r->idle_time = idle_time;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetSessInfo502 structure
+ ********************************************************************/
+
+void init_srvsvc_NetSessInfo502(struct srvsvc_NetSessInfo502 *r,
+ const char *client,
+ const char *user,
+ uint32_t num_open,
+ uint32_t _time,
+ uint32_t idle_time,
+ uint32_t user_flags,
+ const char *client_type,
+ const char *transport)
+{
+ r->client = client;
+ r->user = user;
+ r->num_open = num_open;
+ r->time = _time;
+ r->idle_time = idle_time;
+ r->user_flags = user_flags;
+ r->client_type = client_type;
+ r->transport = transport;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetFileInfo2 structure
+ ********************************************************************/
+
+void init_srvsvc_NetFileInfo2(struct srvsvc_NetFileInfo2 *r,
+ uint32_t fid)
+{
+ r->fid = fid;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetFileInfo3 structure
+ ********************************************************************/
+
+void init_srvsvc_NetFileInfo3(struct srvsvc_NetFileInfo3 *r,
+ uint32_t fid,
+ uint32_t permissions,
+ uint32_t num_locks,
+ const char *path,
+ const char *user)
+{
+ r->fid = fid;
+ r->permissions = permissions;
+ r->num_locks = num_locks;
+ r->path = path;
+ r->user = user;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetConnInfo0 structure
+ ********************************************************************/
+
+void init_srvsvc_NetConnInfo0(struct srvsvc_NetConnInfo0 *r,
+ uint32_t conn_id)
+{
+ r->conn_id = conn_id;
+}
+
+/*******************************************************************
+ inits a srvsvc_NetConnInfo1 structure
+ ********************************************************************/
+
+void init_srvsvc_NetConnInfo1(struct srvsvc_NetConnInfo1 *r,
+ uint32_t conn_id,
+ uint32_t conn_type,
+ uint32_t num_open,
+ uint32_t num_users,
+ uint32_t conn_time,
+ const char *user,
+ const char *share)
+{
+ r->conn_id = conn_id;
+ r->conn_type = conn_type;
+ r->num_open = num_open;
+ r->num_users = num_users;
+ r->conn_time = conn_time;
+ r->user = user;
+ r->share = share;
+}
diff --git a/source3/rpc_client/ndr.c b/source3/rpc_client/ndr.c
new file mode 100644
index 0000000000..72a33137a6
--- /dev/null
+++ b/source3/rpc_client/ndr.c
@@ -0,0 +1,95 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ libndr interface
+
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+
+NTSTATUS cli_do_rpc_ndr(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ const struct ndr_interface_table *table,
+ uint32 opnum, void *r)
+{
+ prs_struct q_ps, r_ps;
+ const struct ndr_interface_call *call;
+ struct ndr_pull *pull;
+ DATA_BLOB blob;
+ struct ndr_push *push;
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+
+ SMB_ASSERT(ndr_syntax_id_equal(&table->syntax_id,
+ &cli->abstract_syntax));
+ SMB_ASSERT(table->num_calls > opnum);
+
+ call = &table->calls[opnum];
+
+ push = ndr_push_init_ctx(mem_ctx);
+ if (!push) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ndr_err = call->ndr_push(push, NDR_IN, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ blob = ndr_push_blob(push);
+
+ if (!prs_init_data_blob(&q_ps, &blob, mem_ctx)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ talloc_free(push);
+
+ prs_init_empty( &r_ps, mem_ctx, UNMARSHALL );
+
+ status = rpc_api_pipe_req(cli, opnum, &q_ps, &r_ps);
+
+ prs_mem_free( &q_ps );
+
+ if (!NT_STATUS_IS_OK(status)) {
+ prs_mem_free( &r_ps );
+ return status;
+ }
+
+ if (!prs_data_blob(&r_ps, &blob, mem_ctx)) {
+ prs_mem_free( &r_ps );
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ prs_mem_free( &r_ps );
+
+ pull = ndr_pull_init_blob(&blob, mem_ctx);
+ if (pull == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* have the ndr parser alloc memory for us */
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_err = call->ndr_pull(pull, NDR_OUT, r);
+ talloc_free(pull);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/rpc_parse/parse_buffer.c b/source3/rpc_parse/parse_buffer.c
new file mode 100644
index 0000000000..63a73c4b7c
--- /dev/null
+++ b/source3/rpc_parse/parse_buffer.c
@@ -0,0 +1,508 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ *
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ * Copyright (C) Jean François Micouleau 1998-2000,
+ * Copyright (C) Gerald Carter 2000-2005,
+ * Copyright (C) Tim Potter 2001-2002.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_PARSE
+
+/**********************************************************************
+ Initialize a new spoolss buff for use by a client rpc
+**********************************************************************/
+void rpcbuf_init(RPC_BUFFER *buffer, uint32 size, TALLOC_CTX *ctx)
+{
+ buffer->size = size;
+ buffer->string_at_end = size;
+ if (prs_init(&buffer->prs, size, ctx, MARSHALL))
+ buffer->struct_start = prs_offset(&buffer->prs);
+ else
+ buffer->struct_start = 0;
+}
+
+/*******************************************************************
+ Read/write a RPC_BUFFER struct.
+********************************************************************/
+
+bool prs_rpcbuffer(const char *desc, prs_struct *ps, int depth, RPC_BUFFER *buffer)
+{
+ prs_debug(ps, depth, desc, "prs_rpcbuffer");
+ depth++;
+
+ /* reading */
+ if (UNMARSHALLING(ps)) {
+ buffer->size=0;
+ buffer->string_at_end=0;
+
+ if (!prs_uint32("size", ps, depth, &buffer->size))
+ return False;
+
+ /*
+ * JRA. I'm not sure if the data in here is in big-endian format if
+ * the client is big-endian. Leave as default (little endian) for now.
+ */
+
+ if (!prs_init(&buffer->prs, buffer->size, prs_get_mem_context(ps), UNMARSHALL))
+ return False;
+
+ if (!prs_append_some_prs_data(&buffer->prs, ps, prs_offset(ps), buffer->size))
+ return False;
+
+ if (!prs_set_offset(&buffer->prs, 0))
+ return False;
+
+ if (!prs_set_offset(ps, buffer->size+prs_offset(ps)))
+ return False;
+
+ buffer->string_at_end=buffer->size;
+
+ return True;
+ }
+ else {
+ bool ret = False;
+
+ if (!prs_uint32("size", ps, depth, &buffer->size))
+ goto out;
+
+ if (!prs_append_some_prs_data(ps, &buffer->prs, 0, buffer->size))
+ goto out;
+
+ ret = True;
+ out:
+
+ /* We have finished with the data in buffer->prs - free it. */
+ prs_mem_free(&buffer->prs);
+
+ return ret;
+ }
+}
+
+/*******************************************************************
+ Read/write an RPC_BUFFER* struct.(allocate memory if unmarshalling)
+********************************************************************/
+
+bool prs_rpcbuffer_p(const char *desc, prs_struct *ps, int depth, RPC_BUFFER **buffer)
+{
+ uint32 data_p;
+
+ /* caputure the pointer value to stream */
+
+ data_p = *buffer ? 0xf000baaa : 0;
+
+ if ( !prs_uint32("ptr", ps, depth, &data_p ))
+ return False;
+
+ /* we're done if there is no data */
+
+ if ( !data_p )
+ return True;
+
+ if ( UNMARSHALLING(ps) ) {
+ if ( !(*buffer = PRS_ALLOC_MEM(ps, RPC_BUFFER, 1)) )
+ return False;
+ } else {
+ /* Marshalling case. - coverity paranoia - should already be ok if data_p != 0 */
+ if (!*buffer) {
+ return True;
+ }
+ }
+
+ return prs_rpcbuffer( desc, ps, depth, *buffer);
+}
+
+/****************************************************************************
+ Allocate more memory for a RPC_BUFFER.
+****************************************************************************/
+
+bool rpcbuf_alloc_size(RPC_BUFFER *buffer, uint32 buffer_size)
+{
+ prs_struct *ps;
+ uint32 extra_space;
+ uint32 old_offset;
+
+ /* if we don't need anything. don't do anything */
+
+ if ( buffer_size == 0x0 )
+ return True;
+
+ if (!buffer) {
+ return False;
+ }
+
+ ps= &buffer->prs;
+
+ /* damn, I'm doing the reverse operation of prs_grow() :) */
+ if (buffer_size < prs_data_size(ps))
+ extra_space=0;
+ else
+ extra_space = buffer_size - prs_data_size(ps);
+
+ /*
+ * save the offset and move to the end of the buffer
+ * prs_grow() checks the extra_space against the offset
+ */
+ old_offset=prs_offset(ps);
+ prs_set_offset(ps, prs_data_size(ps));
+
+ if (!prs_grow(ps, extra_space))
+ return False;
+
+ prs_set_offset(ps, old_offset);
+
+ buffer->string_at_end=prs_data_size(ps);
+
+ return True;
+}
+
+/*******************************************************************
+ move a BUFFER from the query to the reply.
+ As the data pointers in RPC_BUFFER are malloc'ed, not talloc'ed,
+ this is ok. This is an OPTIMIZATION and is not strictly neccessary.
+ Clears the memory to zero also.
+********************************************************************/
+
+void rpcbuf_move(RPC_BUFFER *src, RPC_BUFFER **dest)
+{
+ if ( !src ) {
+ *dest = NULL;
+ return;
+ }
+
+ prs_switch_type( &src->prs, MARSHALL );
+
+ if ( !prs_set_offset(&src->prs, 0) )
+ return;
+
+ prs_force_dynamic( &src->prs );
+ prs_mem_clear( &src->prs );
+
+ *dest = src;
+}
+
+/*******************************************************************
+ Get the size of a BUFFER struct.
+********************************************************************/
+
+uint32 rpcbuf_get_size(RPC_BUFFER *buffer)
+{
+ return (buffer->size);
+}
+
+
+/*******************************************************************
+ * write a UNICODE string and its relative pointer.
+ * used by all the RPC structs passing a buffer
+ *
+ * As I'm a nice guy, I'm forcing myself to explain this code.
+ * MS did a good job in the overall spoolss code except in some
+ * functions where they are passing the API buffer directly in the
+ * RPC request/reply. That's to maintain compatiility at the API level.
+ * They could have done it the good way the first time.
+ *
+ * So what happen is: the strings are written at the buffer's end,
+ * in the reverse order of the original structure. Some pointers to
+ * the strings are also in the buffer. Those are relative to the
+ * buffer's start.
+ *
+ * If you don't understand or want to change that function,
+ * first get in touch with me: jfm@samba.org
+ *
+ ********************************************************************/
+
+bool smb_io_relstr(const char *desc, RPC_BUFFER *buffer, int depth, UNISTR *string)
+{
+ prs_struct *ps=&buffer->prs;
+
+ if (MARSHALLING(ps)) {
+ uint32 struct_offset = prs_offset(ps);
+ uint32 relative_offset;
+
+ buffer->string_at_end -= (size_of_relative_string(string) - 4);
+ if(!prs_set_offset(ps, buffer->string_at_end))
+ return False;
+#if 0 /* JERRY */
+ /*
+ * Win2k does not align strings in a buffer
+ * Tested against WinNT 4.0 SP 6a & 2k SP2 --jerry
+ */
+ if (!prs_align(ps))
+ return False;
+#endif
+ buffer->string_at_end = prs_offset(ps);
+
+ /* write the string */
+ if (!smb_io_unistr(desc, string, ps, depth))
+ return False;
+
+ if(!prs_set_offset(ps, struct_offset))
+ return False;
+
+ relative_offset=buffer->string_at_end - buffer->struct_start;
+ /* write its offset */
+ if (!prs_uint32("offset", ps, depth, &relative_offset))
+ return False;
+ }
+ else {
+ uint32 old_offset;
+
+ /* read the offset */
+ if (!prs_uint32("offset", ps, depth, &(buffer->string_at_end)))
+ return False;
+
+ if (buffer->string_at_end == 0)
+ return True;
+
+ old_offset = prs_offset(ps);
+ if(!prs_set_offset(ps, buffer->string_at_end+buffer->struct_start))
+ return False;
+
+ /* read the string */
+ if (!smb_io_unistr(desc, string, ps, depth))
+ return False;
+
+ if(!prs_set_offset(ps, old_offset))
+ return False;
+ }
+ return True;
+}
+
+/*******************************************************************
+ * write a array of UNICODE strings and its relative pointer.
+ * used by 2 RPC structs
+ ********************************************************************/
+
+bool smb_io_relarraystr(const char *desc, RPC_BUFFER *buffer, int depth, uint16 **string)
+{
+ UNISTR chaine;
+
+ prs_struct *ps=&buffer->prs;
+
+ if (MARSHALLING(ps)) {
+ uint32 struct_offset = prs_offset(ps);
+ uint32 relative_offset;
+ uint16 *p;
+ uint16 *q;
+ uint16 zero=0;
+ p=*string;
+ q=*string;
+
+ /* first write the last 0 */
+ buffer->string_at_end -= 2;
+ if(!prs_set_offset(ps, buffer->string_at_end))
+ return False;
+
+ if(!prs_uint16("leading zero", ps, depth, &zero))
+ return False;
+
+ while (p && (*p!=0)) {
+ while (*q!=0)
+ q++;
+
+ /* Yes this should be malloc not talloc. Don't change. */
+
+ chaine.buffer = (uint16 *)
+ SMB_MALLOC((q-p+1)*sizeof(uint16));
+ if (chaine.buffer == NULL)
+ return False;
+
+ memcpy(chaine.buffer, p, (q-p+1)*sizeof(uint16));
+
+ buffer->string_at_end -= (q-p+1)*sizeof(uint16);
+
+ if(!prs_set_offset(ps, buffer->string_at_end)) {
+ SAFE_FREE(chaine.buffer);
+ return False;
+ }
+
+ /* write the string */
+ if (!smb_io_unistr(desc, &chaine, ps, depth)) {
+ SAFE_FREE(chaine.buffer);
+ return False;
+ }
+ q++;
+ p=q;
+
+ SAFE_FREE(chaine.buffer);
+ }
+
+ if(!prs_set_offset(ps, struct_offset))
+ return False;
+
+ relative_offset=buffer->string_at_end - buffer->struct_start;
+ /* write its offset */
+ if (!prs_uint32("offset", ps, depth, &relative_offset))
+ return False;
+
+ } else {
+
+ /* UNMARSHALLING */
+
+ uint32 old_offset;
+ uint16 *chaine2=NULL;
+ int l_chaine=0;
+ int l_chaine2=0;
+ size_t realloc_size = 0;
+
+ *string=NULL;
+
+ /* read the offset */
+ if (!prs_uint32("offset", ps, depth, &buffer->string_at_end))
+ return False;
+
+ old_offset = prs_offset(ps);
+ if(!prs_set_offset(ps, buffer->string_at_end + buffer->struct_start))
+ return False;
+
+ do {
+ if (!smb_io_unistr(desc, &chaine, ps, depth)) {
+ SAFE_FREE(chaine2);
+ return False;
+ }
+
+ l_chaine=str_len_uni(&chaine);
+
+ /* we're going to add two more bytes here in case this
+ is the last string in the array and we need to add
+ an extra NULL for termination */
+ if (l_chaine > 0) {
+ realloc_size = (l_chaine2+l_chaine+2)*sizeof(uint16);
+
+ /* Yes this should be realloc - it's freed below. JRA */
+
+ if((chaine2=(uint16 *)SMB_REALLOC(chaine2, realloc_size)) == NULL) {
+ return False;
+ }
+ memcpy(chaine2+l_chaine2, chaine.buffer, (l_chaine+1)*sizeof(uint16));
+ l_chaine2+=l_chaine+1;
+ }
+
+ } while(l_chaine!=0);
+
+ /* the end should be bould NULL terminated so add
+ the second one here */
+ if (chaine2)
+ {
+ chaine2[l_chaine2] = '\0';
+ *string=(uint16 *)TALLOC_MEMDUP(prs_get_mem_context(ps),chaine2,realloc_size);
+ SAFE_FREE(chaine2);
+ if (!*string) {
+ return False;
+ }
+ }
+
+ if(!prs_set_offset(ps, old_offset))
+ return False;
+ }
+ return True;
+}
+
+/*******************************************************************
+ Parse a DEVMODE structure and its relative pointer.
+********************************************************************/
+
+bool smb_io_relsecdesc(const char *desc, RPC_BUFFER *buffer, int depth, SEC_DESC **secdesc)
+{
+ prs_struct *ps= &buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_relsecdesc");
+ depth++;
+
+ if (MARSHALLING(ps)) {
+ uint32 struct_offset = prs_offset(ps);
+ uint32 relative_offset;
+
+ if (! *secdesc) {
+ relative_offset = 0;
+ if (!prs_uint32("offset", ps, depth, &relative_offset))
+ return False;
+ return True;
+ }
+
+ if (*secdesc != NULL) {
+ buffer->string_at_end -= ndr_size_security_descriptor(*secdesc, 0);
+
+ if(!prs_set_offset(ps, buffer->string_at_end))
+ return False;
+ /* write the secdesc */
+ if (!sec_io_desc(desc, secdesc, ps, depth))
+ return False;
+
+ if(!prs_set_offset(ps, struct_offset))
+ return False;
+ }
+
+ relative_offset=buffer->string_at_end - buffer->struct_start;
+ /* write its offset */
+
+ if (!prs_uint32("offset", ps, depth, &relative_offset))
+ return False;
+ } else {
+ uint32 old_offset;
+
+ /* read the offset */
+ if (!prs_uint32("offset", ps, depth, &buffer->string_at_end))
+ return False;
+
+ old_offset = prs_offset(ps);
+ if(!prs_set_offset(ps, buffer->string_at_end + buffer->struct_start))
+ return False;
+
+ /* read the sd */
+ if (!sec_io_desc(desc, secdesc, ps, depth))
+ return False;
+
+ if(!prs_set_offset(ps, old_offset))
+ return False;
+ }
+ return True;
+}
+
+
+
+/*******************************************************************
+ * return the length of a UNICODE string in number of char, includes:
+ * - the leading zero
+ * - the relative pointer size
+ ********************************************************************/
+
+uint32 size_of_relative_string(UNISTR *string)
+{
+ uint32 size=0;
+
+ size=str_len_uni(string); /* the string length */
+ size=size+1; /* add the trailing zero */
+ size=size*2; /* convert in char */
+ size=size+4; /* add the size of the ptr */
+
+#if 0 /* JERRY */
+ /*
+ * Do not include alignment as Win2k does not align relative
+ * strings within a buffer --jerry
+ */
+ /* Ensure size is 4 byte multiple (prs_align is being called...). */
+ /* size += ((4 - (size & 3)) & 3); */
+#endif
+
+ return size;
+}
+
diff --git a/source3/rpc_parse/parse_eventlog.c b/source3/rpc_parse/parse_eventlog.c
new file mode 100644
index 0000000000..2ff217eb9e
--- /dev/null
+++ b/source3/rpc_parse/parse_eventlog.c
@@ -0,0 +1,193 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Marcin Krzysztof Porwit 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_PARSE
+
+/********************************************************************
+********************************************************************/
+
+bool eventlog_io_q_read_eventlog(const char *desc, EVENTLOG_Q_READ_EVENTLOG *q_u,
+ prs_struct *ps, int depth)
+{
+ if(q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "eventlog_io_q_read_eventlog");
+ depth++;
+
+ if(!(prs_align(ps)))
+ return False;
+
+ if(!(smb_io_pol_hnd("log handle", &(q_u->handle), ps, depth)))
+ return False;
+
+ if(!(prs_uint32("read flags", ps, depth, &(q_u->flags))))
+ return False;
+
+ if(!(prs_uint32("read offset", ps, depth, &(q_u->offset))))
+ return False;
+
+ if(!(prs_uint32("read buf size", ps, depth, &(q_u->max_read_size))))
+ return False;
+
+ return True;
+}
+/** Structure of response seems to be:
+ DWORD num_bytes_in_resp -- MUST be the same as q_u->max_read_size
+ for i=0..n
+ EVENTLOGRECORD record
+ DWORD sent_size -- sum of EVENTLOGRECORD lengths if records returned, 0 otherwise
+ DWORD real_size -- 0 if records returned, otherwise length of next record to be returned
+ WERROR status */
+bool eventlog_io_r_read_eventlog(const char *desc,
+ EVENTLOG_Q_READ_EVENTLOG *q_u,
+ EVENTLOG_R_READ_EVENTLOG *r_u,
+ prs_struct *ps,
+ int depth)
+{
+ Eventlog_entry *entry;
+ uint32 record_written = 0;
+ uint32 record_total = 0;
+
+ if(r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "eventlog_io_r_read_eventlog");
+ depth++;
+
+ /* First, see if we've read more logs than we can output */
+
+ if(r_u->num_bytes_in_resp > q_u->max_read_size) {
+ entry = r_u->entry;
+
+ /* remove the size of the last entry from the list */
+
+ while(entry->next != NULL)
+ entry = entry->next;
+
+ r_u->num_bytes_in_resp -= entry->record.length;
+
+ /* do not output the last log entry */
+
+ r_u->num_records--;
+ }
+
+ entry = r_u->entry;
+ record_total = r_u->num_records;
+
+ if(r_u->num_bytes_in_resp != 0)
+ r_u->sent_size = r_u->num_bytes_in_resp;
+ else
+ r_u->real_size = r_u->bytes_in_next_record;
+
+ if(!(prs_align(ps)))
+ return False;
+ if(!(prs_uint32("bytes in resp", ps, depth, &(q_u->max_read_size))))
+ return False;
+
+ while(entry != NULL && record_written < record_total)
+ {
+ DEBUG(11, ("eventlog_io_r_read_eventlog: writing record [%d] out of [%d].\n", record_written, record_total));
+
+ /* Encode the actual eventlog record record */
+
+ if(!(prs_uint32("length", ps, depth, &(entry->record.length))))
+ return False;
+ if(!(prs_uint32("reserved", ps, depth, &(entry->record.reserved1))))
+ return False;
+ if(!(prs_uint32("record number", ps, depth, &(entry->record.record_number))))
+ return False;
+ if(!(prs_uint32("time generated", ps, depth, &(entry->record.time_generated))))
+ return False;
+ if(!(prs_uint32("time written", ps, depth, &(entry->record.time_written))))
+ return False;
+ if(!(prs_uint32("event id", ps, depth, &(entry->record.event_id))))
+ return False;
+ if(!(prs_uint16("event type", ps, depth, &(entry->record.event_type))))
+ return False;
+ if(!(prs_uint16("num strings", ps, depth, &(entry->record.num_strings))))
+ return False;
+ if(!(prs_uint16("event category", ps, depth, &(entry->record.event_category))))
+ return False;
+ if(!(prs_uint16("reserved2", ps, depth, &(entry->record.reserved2))))
+ return False;
+ if(!(prs_uint32("closing record", ps, depth, &(entry->record.closing_record_number))))
+ return False;
+ if(!(prs_uint32("string offset", ps, depth, &(entry->record.string_offset))))
+ return False;
+ if(!(prs_uint32("user sid length", ps, depth, &(entry->record.user_sid_length))))
+ return False;
+ if(!(prs_uint32("user sid offset", ps, depth, &(entry->record.user_sid_offset))))
+ return False;
+ if(!(prs_uint32("data length", ps, depth, &(entry->record.data_length))))
+ return False;
+ if(!(prs_uint32("data offset", ps, depth, &(entry->record.data_offset))))
+ return False;
+ if(!(prs_align(ps)))
+ return False;
+
+ /* Now encoding data */
+
+ if(!(prs_uint8s(False, "buffer", ps, depth, entry->data,
+ entry->record.length - sizeof(Eventlog_record) - sizeof(entry->record.length))))
+ {
+ return False;
+ }
+
+ if(!(prs_align(ps)))
+ return False;
+ if(!(prs_uint32("length 2", ps, depth, &(entry->record.length))))
+ return False;
+
+ entry = entry->next;
+ record_written++;
+
+ } /* end of encoding EVENTLOGRECORD */
+
+ /* Now pad with whitespace until the end of the response buffer */
+
+ if (q_u->max_read_size - r_u->num_bytes_in_resp) {
+ if (!r_u->end_of_entries_padding) {
+ return False;
+ }
+
+ if(!(prs_uint8s(False, "end of entries padding", ps,
+ depth, r_u->end_of_entries_padding,
+ (q_u->max_read_size - r_u->num_bytes_in_resp)))) {
+ free(r_u->end_of_entries_padding);
+ return False;
+ }
+
+ free(r_u->end_of_entries_padding);
+ }
+
+ /* We had better be DWORD aligned here */
+
+ if(!(prs_uint32("sent size", ps, depth, &(r_u->sent_size))))
+ return False;
+ if(!(prs_uint32("real size", ps, depth, &(r_u->real_size))))
+ return False;
+ if(!(prs_ntstatus("status code", ps, depth, &r_u->status)))
+ return False;
+
+ return True;
+}
diff --git a/source3/rpc_parse/parse_misc.c b/source3/rpc_parse/parse_misc.c
new file mode 100644
index 0000000000..cf989c8b5e
--- /dev/null
+++ b/source3/rpc_parse/parse_misc.c
@@ -0,0 +1,1834 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * 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) Gerald (Jerry) Carter 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_PARSE
+
+/*******************************************************************
+ Reads or writes a UTIME type.
+********************************************************************/
+
+static bool smb_io_utime(const char *desc, UTIME *t, prs_struct *ps, int depth)
+{
+ if (t == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_utime");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32 ("time", ps, depth, &t->time))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an NTTIME structure.
+********************************************************************/
+
+bool smb_io_time(const char *desc, NTTIME *nttime, prs_struct *ps, int depth)
+{
+ uint32 low, high;
+ if (nttime == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_time");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (MARSHALLING(ps)) {
+ low = *nttime & 0xFFFFFFFF;
+ high = *nttime >> 32;
+ }
+
+ if(!prs_uint32("low ", ps, depth, &low)) /* low part */
+ return False;
+ if(!prs_uint32("high", ps, depth, &high)) /* high part */
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ *nttime = (((uint64_t)high << 32) + low);
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an NTTIME structure.
+********************************************************************/
+
+bool smb_io_nttime(const char *desc, prs_struct *ps, int depth, NTTIME *nttime)
+{
+ return smb_io_time( desc, nttime, ps, depth );
+}
+
+/*******************************************************************
+ Gets an enumeration handle from an ENUM_HND structure.
+********************************************************************/
+
+uint32 get_enum_hnd(ENUM_HND *enh)
+{
+ return (enh && enh->ptr_hnd != 0) ? enh->handle : 0;
+}
+
+/*******************************************************************
+ Inits an ENUM_HND structure.
+********************************************************************/
+
+void init_enum_hnd(ENUM_HND *enh, uint32 hnd)
+{
+ DEBUG(5,("smb_io_enum_hnd\n"));
+
+ enh->ptr_hnd = (hnd != 0) ? 1 : 0;
+ enh->handle = hnd;
+}
+
+/*******************************************************************
+ Reads or writes an ENUM_HND structure.
+********************************************************************/
+
+bool smb_io_enum_hnd(const char *desc, ENUM_HND *hnd, prs_struct *ps, int depth)
+{
+ if (hnd == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_enum_hnd");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_hnd", ps, depth, &hnd->ptr_hnd)) /* pointer */
+ return False;
+
+ if (hnd->ptr_hnd != 0) {
+ if(!prs_uint32("handle ", ps, depth, &hnd->handle )) /* enum handle */
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_SID structure.
+********************************************************************/
+
+bool smb_io_dom_sid(const char *desc, DOM_SID *sid, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (sid == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_dom_sid");
+ depth++;
+
+ if(!prs_uint8 ("sid_rev_num", ps, depth, &sid->sid_rev_num))
+ return False;
+
+ if(!prs_uint8 ("num_auths ", ps, depth, &sid->num_auths))
+ return False;
+
+ for (i = 0; i < 6; i++)
+ {
+ fstring tmp;
+ slprintf(tmp, sizeof(tmp) - 1, "id_auth[%d] ", i);
+ if(!prs_uint8 (tmp, ps, depth, &sid->id_auth[i]))
+ return False;
+ }
+
+ /* oops! XXXX should really issue a warning here... */
+ if (sid->num_auths > MAXSUBAUTHS)
+ sid->num_auths = MAXSUBAUTHS;
+
+ if(!prs_uint32s(False, "sub_auths ", ps, depth, sid->sub_auths, sid->num_auths))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a DOM_SID2 structure.
+********************************************************************/
+
+void init_dom_sid2(DOM_SID2 *sid2, const DOM_SID *sid)
+{
+ sid2->sid = *sid;
+ sid2->num_auths = sid2->sid.num_auths;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_SID2 structure.
+********************************************************************/
+
+bool smb_io_dom_sid2_p(const char *desc, prs_struct *ps, int depth, DOM_SID2 **sid2)
+{
+ uint32 data_p;
+
+ /* caputure the pointer value to stream */
+
+ data_p = *sid2 ? 0xf000baaa : 0;
+
+ if ( !prs_uint32("dom_sid2_p", ps, depth, &data_p ))
+ return False;
+
+ /* we're done if there is no data */
+
+ if ( !data_p )
+ return True;
+
+ if (UNMARSHALLING(ps)) {
+ if ( !(*sid2 = PRS_ALLOC_MEM(ps, DOM_SID2, 1)) )
+ return False;
+ }
+
+ return True;
+}
+/*******************************************************************
+ Reads or writes a DOM_SID2 structure.
+********************************************************************/
+
+bool smb_io_dom_sid2(const char *desc, DOM_SID2 *sid, prs_struct *ps, int depth)
+{
+ if (sid == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_dom_sid2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_auths", ps, depth, &sid->num_auths))
+ return False;
+
+ if(!smb_io_dom_sid("sid", &sid->sid, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a struct GUID
+********************************************************************/
+
+bool smb_io_uuid(const char *desc, struct GUID *uuid,
+ prs_struct *ps, int depth)
+{
+ if (uuid == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_uuid");
+ depth++;
+
+ if(!prs_uint32 ("data ", ps, depth, &uuid->time_low))
+ return False;
+ if(!prs_uint16 ("data ", ps, depth, &uuid->time_mid))
+ return False;
+ if(!prs_uint16 ("data ", ps, depth, &uuid->time_hi_and_version))
+ return False;
+
+ if(!prs_uint8s (False, "data ", ps, depth, uuid->clock_seq, sizeof(uuid->clock_seq)))
+ return False;
+ if(!prs_uint8s (False, "data ", ps, depth, uuid->node, sizeof(uuid->node)))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+creates a STRHDR structure.
+********************************************************************/
+
+void init_str_hdr(STRHDR *hdr, int max_len, int len, uint32 buffer)
+{
+ hdr->str_max_len = max_len;
+ hdr->str_str_len = len;
+ hdr->buffer = buffer;
+}
+
+/*******************************************************************
+ Reads or writes a STRHDR structure.
+********************************************************************/
+
+bool smb_io_strhdr(const char *desc, STRHDR *hdr, prs_struct *ps, int depth)
+{
+ if (hdr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_strhdr");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16("str_str_len", ps, depth, &hdr->str_str_len))
+ return False;
+ if(!prs_uint16("str_max_len", ps, depth, &hdr->str_max_len))
+ return False;
+ if(!prs_uint32("buffer ", ps, depth, &hdr->buffer))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a UNIHDR structure.
+********************************************************************/
+
+void init_uni_hdr(UNIHDR *hdr, UNISTR2 *str2)
+{
+ hdr->uni_str_len = 2 * (str2->uni_str_len);
+ hdr->uni_max_len = 2 * (str2->uni_max_len);
+ hdr->buffer = (str2->uni_str_len != 0) ? 1 : 0;
+}
+
+/*******************************************************************
+ Reads or writes a UNIHDR structure.
+********************************************************************/
+
+bool smb_io_unihdr(const char *desc, UNIHDR *hdr, prs_struct *ps, int depth)
+{
+ if (hdr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_unihdr");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16("uni_str_len", ps, depth, &hdr->uni_str_len))
+ return False;
+ if(!prs_uint16("uni_max_len", ps, depth, &hdr->uni_max_len))
+ return False;
+ if(!prs_uint32("buffer ", ps, depth, &hdr->buffer))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a BUFHDR structure.
+********************************************************************/
+
+void init_buf_hdr(BUFHDR *hdr, int max_len, int len)
+{
+ hdr->buf_max_len = max_len;
+ hdr->buf_len = len;
+}
+
+/*******************************************************************
+ prs_uint16 wrapper. Call this and it sets up a pointer to where the
+ uint16 should be stored, or gets the size if reading.
+ ********************************************************************/
+
+bool smb_io_hdrbuf_pre(const char *desc, BUFHDR *hdr, prs_struct *ps, int depth, uint32 *offset)
+{
+ (*offset) = prs_offset(ps);
+ if (ps->io) {
+
+ /* reading. */
+
+ if(!smb_io_hdrbuf(desc, hdr, ps, depth))
+ return False;
+
+ } else {
+
+ /* writing. */
+
+ if(!prs_set_offset(ps, prs_offset(ps) + (sizeof(uint32) * 2)))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ smb_io_hdrbuf wrapper. Call this and it retrospectively stores the size.
+ Does nothing on reading, as that is already handled by ...._pre()
+ ********************************************************************/
+
+bool smb_io_hdrbuf_post(const char *desc, BUFHDR *hdr, prs_struct *ps, int depth,
+ uint32 ptr_hdrbuf, uint32 max_len, uint32 len)
+{
+ if (!ps->io) {
+ /* writing: go back and do a retrospective job. i hate this */
+
+ uint32 old_offset = prs_offset(ps);
+
+ init_buf_hdr(hdr, max_len, len);
+ if(!prs_set_offset(ps, ptr_hdrbuf))
+ return False;
+ if(!smb_io_hdrbuf(desc, hdr, ps, depth))
+ return False;
+
+ if(!prs_set_offset(ps, old_offset))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a BUFHDR structure.
+********************************************************************/
+
+bool smb_io_hdrbuf(const char *desc, BUFHDR *hdr, prs_struct *ps, int depth)
+{
+ if (hdr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_hdrbuf");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("buf_max_len", ps, depth, &hdr->buf_max_len))
+ return False;
+ if(!prs_uint32("buf_len ", ps, depth, &hdr->buf_len))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a UNISTR structure.
+********************************************************************/
+
+void init_unistr(UNISTR *str, const char *buf)
+{
+ size_t len;
+
+ if (buf == NULL) {
+ str->buffer = NULL;
+ return;
+ }
+
+ len = rpcstr_push_talloc(talloc_tos(), &str->buffer, buf);
+ if (len == (size_t)-1) {
+ str->buffer = NULL;
+ }
+}
+
+/*******************************************************************
+reads or writes a UNISTR structure.
+XXXX NOTE: UNISTR structures NEED to be null-terminated.
+********************************************************************/
+
+bool smb_io_unistr(const char *desc, UNISTR *uni, prs_struct *ps, int depth)
+{
+ if (uni == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_unistr");
+ depth++;
+
+ if(!prs_unistr("unistr", ps, depth, uni))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Allocate the RPC_DATA_BLOB memory.
+********************************************************************/
+
+static void create_rpc_blob(RPC_DATA_BLOB *str, size_t len)
+{
+ if (len) {
+ str->buffer = (uint8 *)TALLOC_ZERO(talloc_tos(), len);
+ if (str->buffer == NULL)
+ smb_panic("create_rpc_blob: talloc fail");
+ str->buf_len = len;
+ } else {
+ str->buffer = NULL;
+ str->buf_len = 0;
+ }
+}
+
+/*******************************************************************
+ Inits a RPC_DATA_BLOB structure from a uint32
+********************************************************************/
+
+void init_rpc_blob_uint32(RPC_DATA_BLOB *str, uint32 val)
+{
+ ZERO_STRUCTP(str);
+
+ /* set up string lengths. */
+ create_rpc_blob(str, sizeof(uint32));
+ SIVAL(str->buffer, 0, val);
+}
+
+/*******************************************************************
+ Inits a RPC_DATA_BLOB structure.
+********************************************************************/
+
+void init_rpc_blob_str(RPC_DATA_BLOB *str, const char *buf, int len)
+{
+ ZERO_STRUCTP(str);
+
+ /* set up string lengths. */
+ if (len) {
+ create_rpc_blob(str, len*2);
+ rpcstr_push(str->buffer, buf, (size_t)str->buf_len, STR_TERMINATE);
+ }
+}
+
+/*******************************************************************
+ Inits a RPC_DATA_BLOB structure from a hex string.
+********************************************************************/
+
+void init_rpc_blob_hex(RPC_DATA_BLOB *str, const char *buf)
+{
+ ZERO_STRUCTP(str);
+ if (buf && *buf) {
+ size_t len = strlen(buf);
+ create_rpc_blob(str, len);
+ str->buf_len = strhex_to_str((char *)str->buffer, str->buf_len,
+ buf, len);
+ }
+}
+
+/*******************************************************************
+ Inits a RPC_DATA_BLOB structure.
+********************************************************************/
+
+void init_rpc_blob_bytes(RPC_DATA_BLOB *str, uint8 *buf, size_t len)
+{
+ ZERO_STRUCTP(str);
+
+ /* max buffer size (allocated size) */
+ if (buf != NULL && len) {
+ create_rpc_blob(str, len);
+ memcpy(str->buffer, buf, len);
+ }
+ str->buf_len = len;
+}
+
+/*******************************************************************
+reads or writes a BUFFER5 structure.
+the buf_len member tells you how large the buffer is.
+********************************************************************/
+bool smb_io_buffer5(const char *desc, BUFFER5 *buf5, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "smb_io_buffer5");
+ depth++;
+
+ if (buf5 == NULL) return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("buf_len", ps, depth, &buf5->buf_len))
+ return False;
+
+ if(buf5->buf_len) {
+ if(!prs_buffer5(True, "buffer" , ps, depth, buf5))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a REGVAL_BUFFER structure.
+********************************************************************/
+
+void init_regval_buffer(REGVAL_BUFFER *str, const uint8 *buf, size_t len)
+{
+ ZERO_STRUCTP(str);
+
+ /* max buffer size (allocated size) */
+ str->buf_max_len = len;
+ str->offset = 0;
+ str->buf_len = buf != NULL ? len : 0;
+
+ if (buf != NULL) {
+ SMB_ASSERT(str->buf_max_len >= str->buf_len);
+ str->buffer = (uint16 *)TALLOC_ZERO(talloc_tos(),
+ str->buf_max_len);
+ if (str->buffer == NULL)
+ smb_panic("init_regval_buffer: talloc fail");
+ memcpy(str->buffer, buf, str->buf_len);
+ }
+}
+
+/*******************************************************************
+ Reads or writes a REGVAL_BUFFER structure.
+ the uni_max_len member tells you how large the buffer is.
+ the uni_str_len member tells you how much of the buffer is really used.
+********************************************************************/
+
+bool smb_io_regval_buffer(const char *desc, prs_struct *ps, int depth, REGVAL_BUFFER *buf2)
+{
+
+ prs_debug(ps, depth, desc, "smb_io_regval_buffer");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("buf_max_len", ps, depth, &buf2->buf_max_len))
+ return False;
+ if(!prs_uint32("offset ", ps, depth, &buf2->offset))
+ return False;
+ if(!prs_uint32("buf_len ", ps, depth, &buf2->buf_len))
+ return False;
+
+ /* buffer advanced by indicated length of string
+ NOT by searching for null-termination */
+
+ if(!prs_regval_buffer(True, "buffer ", ps, depth, buf2))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+creates a UNISTR2 structure: sets up the buffer, too
+********************************************************************/
+
+void init_buf_unistr2(UNISTR2 *str, uint32 *ptr, const char *buf)
+{
+ if (buf != NULL) {
+ *ptr = 1;
+ init_unistr2(str, buf, UNI_STR_TERMINATE);
+ } else {
+ *ptr = 0;
+ init_unistr2(str, NULL, UNI_FLAGS_NONE);
+
+ }
+}
+
+/*******************************************************************
+ Copies a UNISTR2 structure.
+********************************************************************/
+
+void copy_unistr2(UNISTR2 *str, const UNISTR2 *from)
+{
+ if (from->buffer == NULL) {
+ ZERO_STRUCTP(str);
+ return;
+ }
+
+ SMB_ASSERT(from->uni_max_len >= from->uni_str_len);
+
+ str->uni_max_len = from->uni_max_len;
+ str->offset = from->offset;
+ str->uni_str_len = from->uni_str_len;
+
+ /* the string buffer is allocated to the maximum size
+ (the the length of the source string) to prevent
+ reallocation of memory. */
+ if (str->buffer == NULL) {
+ if (str->uni_max_len) {
+ str->buffer = (uint16 *)TALLOC_ZERO_ARRAY(talloc_tos(), uint16, str->uni_max_len);
+ if ((str->buffer == NULL)) {
+ smb_panic("copy_unistr2: talloc fail");
+ return;
+ }
+ /* copy the string */
+ memcpy(str->buffer, from->buffer, str->uni_max_len*sizeof(uint16));
+ } else {
+ str->buffer = NULL;
+ }
+ }
+}
+
+/*******************************************************************
+ Creates a STRING2 structure.
+********************************************************************/
+
+void init_string2(STRING2 *str, const char *buf, size_t max_len, size_t str_len)
+{
+ /* set up string lengths. */
+ SMB_ASSERT(max_len >= str_len);
+
+ /* Ensure buf is valid if str_len was set. Coverity check. */
+ if (str_len && !buf) {
+ return;
+ }
+
+ str->str_max_len = max_len;
+ str->offset = 0;
+ str->str_str_len = str_len;
+
+ /* store the string */
+ if(str_len != 0) {
+ str->buffer = (uint8 *)TALLOC_ZERO(talloc_tos(),
+ str->str_max_len);
+ if (str->buffer == NULL)
+ smb_panic("init_string2: malloc fail");
+ memcpy(str->buffer, buf, str_len);
+ }
+}
+
+/*******************************************************************
+ Reads or writes a STRING2 structure.
+ XXXX NOTE: STRING2 structures need NOT be null-terminated.
+ the str_str_len member tells you how long the string is;
+ the str_max_len member tells you how large the buffer is.
+********************************************************************/
+
+bool smb_io_string2(const char *desc, STRING2 *str2, uint32 buffer, prs_struct *ps, int depth)
+{
+ if (str2 == NULL)
+ return False;
+
+ if (buffer) {
+
+ prs_debug(ps, depth, desc, "smb_io_string2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("str_max_len", ps, depth, &str2->str_max_len))
+ return False;
+ if(!prs_uint32("offset ", ps, depth, &str2->offset))
+ return False;
+ if(!prs_uint32("str_str_len", ps, depth, &str2->str_str_len))
+ return False;
+
+ /* buffer advanced by indicated length of string
+ NOT by searching for null-termination */
+ if(!prs_string2(True, "buffer ", ps, depth, str2))
+ return False;
+
+ } else {
+
+ prs_debug(ps, depth, desc, "smb_io_string2 - NULL");
+ depth++;
+ memset((char *)str2, '\0', sizeof(*str2));
+
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a UNISTR2 structure.
+********************************************************************/
+
+void init_unistr2(UNISTR2 *str, const char *buf, enum unistr2_term_codes flags)
+{
+ size_t len = 0;
+ uint32 num_chars = 0;
+
+ if (buf) {
+ /* We always null terminate the copy. */
+ len = strlen(buf) + 1;
+ if ( flags == UNI_STR_DBLTERMINATE )
+ len++;
+ }
+
+ if (buf == NULL || len == 0) {
+ /* no buffer -- nothing to do */
+ str->uni_max_len = 0;
+ str->offset = 0;
+ str->uni_str_len = 0;
+
+ return;
+ }
+
+
+ str->buffer = TALLOC_ZERO_ARRAY(talloc_tos(), uint16, len);
+ if (str->buffer == NULL) {
+ smb_panic("init_unistr2: malloc fail");
+ return;
+ }
+
+ /* Ensure len is the length in *bytes* */
+ len *= sizeof(uint16);
+
+ /*
+ * The UNISTR2 must be initialized !!!
+ * jfm, 7/7/2001.
+ */
+ if (buf) {
+ rpcstr_push((char *)str->buffer, buf, len, STR_TERMINATE);
+ num_chars = strlen_w(str->buffer);
+ if (flags == UNI_STR_TERMINATE || flags == UNI_MAXLEN_TERMINATE) {
+ num_chars++;
+ }
+ if ( flags == UNI_STR_DBLTERMINATE )
+ num_chars += 2;
+ }
+
+ str->uni_max_len = num_chars;
+ str->offset = 0;
+ str->uni_str_len = num_chars;
+ if ( num_chars && ((flags == UNI_MAXLEN_TERMINATE) || (flags == UNI_BROKEN_NON_NULL)) )
+ str->uni_max_len++;
+}
+
+/*******************************************************************
+ Inits a UNISTR4 structure.
+********************************************************************/
+
+void init_unistr4(UNISTR4 *uni4, const char *buf, enum unistr2_term_codes flags)
+{
+ uni4->string = TALLOC_P( talloc_tos(), UNISTR2 );
+ if (!uni4->string) {
+ smb_panic("init_unistr4: talloc fail");
+ return;
+ }
+ init_unistr2( uni4->string, buf, flags );
+
+ uni4->length = 2 * (uni4->string->uni_str_len);
+ uni4->size = 2 * (uni4->string->uni_max_len);
+}
+
+void init_unistr4_w( TALLOC_CTX *ctx, UNISTR4 *uni4, const smb_ucs2_t *buf )
+{
+ uni4->string = TALLOC_P( ctx, UNISTR2 );
+ if (!uni4->string) {
+ smb_panic("init_unistr4_w: talloc fail");
+ return;
+ }
+ init_unistr2_w( ctx, uni4->string, buf );
+
+ uni4->length = 2 * (uni4->string->uni_str_len);
+ uni4->size = 2 * (uni4->string->uni_max_len);
+}
+
+/**
+ * Inits a UNISTR2 structure.
+ * @param ctx talloc context to allocate string on
+ * @param str pointer to string to create
+ * @param buf UCS2 null-terminated buffer to init from
+*/
+
+void init_unistr2_w(TALLOC_CTX *ctx, UNISTR2 *str, const smb_ucs2_t *buf)
+{
+ uint32 len = buf ? strlen_w(buf) : 0;
+
+ ZERO_STRUCTP(str);
+
+ /* set up string lengths. */
+ str->uni_max_len = len;
+ str->offset = 0;
+ str->uni_str_len = len;
+
+ if (len + 1) {
+ str->buffer = TALLOC_ZERO_ARRAY(ctx, uint16, len + 1);
+ if (str->buffer == NULL) {
+ smb_panic("init_unistr2_w: talloc fail");
+ return;
+ }
+ } else {
+ str->buffer = NULL;
+ }
+
+ /*
+ * don't move this test above ! The UNISTR2 must be initialized !!!
+ * jfm, 7/7/2001.
+ */
+ if (buf==NULL)
+ return;
+
+ /* Yes, this is a strncpy( foo, bar, strlen(bar)) - but as
+ long as the buffer above is talloc()ed correctly then this
+ is the correct thing to do */
+ if (len+1) {
+ strncpy_w(str->buffer, buf, len + 1);
+ }
+}
+
+/*******************************************************************
+ Inits a UNISTR2 structure from a UNISTR
+********************************************************************/
+
+void init_unistr2_from_unistr(TALLOC_CTX *ctx, UNISTR2 *to, const UNISTR *from)
+{
+ uint32 i;
+
+ /* the destination UNISTR2 should never be NULL.
+ if it is it is a programming error */
+
+ /* if the source UNISTR is NULL, then zero out
+ the destination string and return */
+ ZERO_STRUCTP (to);
+ if ((from == NULL) || (from->buffer == NULL))
+ return;
+
+ /* get the length; UNISTR must be NULL terminated */
+ i = 0;
+ while ((from->buffer)[i]!='\0')
+ i++;
+ i++; /* one more to catch the terminating NULL */
+ /* is this necessary -- jerry? I need to think */
+
+ /* set up string lengths; uni_max_len is set to i+1
+ because we need to account for the final NULL termination */
+ to->uni_max_len = i;
+ to->offset = 0;
+ to->uni_str_len = i;
+
+ /* allocate the space and copy the string buffer */
+ if (i) {
+ to->buffer = TALLOC_ZERO_ARRAY(ctx, uint16, i);
+ if (to->buffer == NULL)
+ smb_panic("init_unistr2_from_unistr: talloc fail");
+ memcpy(to->buffer, from->buffer, i*sizeof(uint16));
+ } else {
+ to->buffer = NULL;
+ }
+ return;
+}
+
+/*******************************************************************
+ Inits a UNISTR2 structure from a DATA_BLOB.
+ The length of the data_blob must count the bytes of the buffer.
+ Copies the blob data.
+********************************************************************/
+
+void init_unistr2_from_datablob(UNISTR2 *str, DATA_BLOB *blob)
+{
+ /* Allocs the unistring */
+ init_unistr2(str, NULL, UNI_FLAGS_NONE);
+
+ /* Sets the values */
+ str->uni_str_len = blob->length / sizeof(uint16);
+ str->uni_max_len = str->uni_str_len;
+ str->offset = 0;
+ if (blob->length) {
+ str->buffer = (uint16 *) memdup(blob->data, blob->length);
+ } else {
+ str->buffer = NULL;
+ }
+ if ((str->buffer == NULL) && (blob->length > 0)) {
+ smb_panic("init_unistr2_from_datablob: malloc fail");
+ }
+}
+
+/*******************************************************************
+ UNISTR2* are a little different in that the pointer and the UNISTR2
+ are not necessarily read/written back to back. So we break it up
+ into 2 separate functions.
+ See SPOOL_USER_1 in include/rpc_spoolss.h for an example.
+********************************************************************/
+
+bool prs_io_unistr2_p(const char *desc, prs_struct *ps, int depth, UNISTR2 **uni2)
+{
+ uint32 data_p;
+
+ /* caputure the pointer value to stream */
+
+ data_p = *uni2 ? 0xf000baaa : 0;
+
+ if ( !prs_uint32("ptr", ps, depth, &data_p ))
+ return False;
+
+ /* we're done if there is no data */
+
+ if ( !data_p )
+ return True;
+
+ if (UNMARSHALLING(ps)) {
+ if ( !(*uni2 = PRS_ALLOC_MEM(ps, UNISTR2, 1)) )
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ now read/write the actual UNISTR2. Memory for the UNISTR2 (but
+ not UNISTR2.buffer) has been allocated previously by prs_unistr2_p()
+********************************************************************/
+
+bool prs_io_unistr2(const char *desc, prs_struct *ps, int depth, UNISTR2 *uni2 )
+{
+ /* just return true if there is no pointer to deal with.
+ the memory must have been previously allocated on unmarshalling
+ by prs_unistr2_p() */
+
+ if ( !uni2 )
+ return True;
+
+ /* just pass off to smb_io_unstr2() passing the uni2 address as
+ the pointer (like you would expect) */
+
+ return smb_io_unistr2( desc, uni2, uni2 ? 1 : 0, ps, depth );
+}
+
+/*******************************************************************
+ Reads or writes a UNISTR2 structure.
+ XXXX NOTE: UNISTR2 structures need NOT be null-terminated.
+ the uni_str_len member tells you how long the string is;
+ the uni_max_len member tells you how large the buffer is.
+********************************************************************/
+
+bool smb_io_unistr2(const char *desc, UNISTR2 *uni2, uint32 buffer, prs_struct *ps, int depth)
+{
+ if (uni2 == NULL)
+ return False;
+
+ if (buffer) {
+
+ prs_debug(ps, depth, desc, "smb_io_unistr2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("uni_max_len", ps, depth, &uni2->uni_max_len))
+ return False;
+ if(!prs_uint32("offset ", ps, depth, &uni2->offset))
+ return False;
+ if(!prs_uint32("uni_str_len", ps, depth, &uni2->uni_str_len))
+ return False;
+
+ /* buffer advanced by indicated length of string
+ NOT by searching for null-termination */
+ if(!prs_unistr2(True, "buffer ", ps, depth, uni2))
+ return False;
+
+ } else {
+
+ prs_debug(ps, depth, desc, "smb_io_unistr2 - NULL");
+ depth++;
+ memset((char *)uni2, '\0', sizeof(*uni2));
+
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ now read/write UNISTR4
+********************************************************************/
+
+bool prs_unistr4(const char *desc, prs_struct *ps, int depth, UNISTR4 *uni4)
+{
+ void *ptr;
+ prs_debug(ps, depth, desc, "prs_unistr4");
+ depth++;
+
+ if ( !prs_uint16("length", ps, depth, &uni4->length ))
+ return False;
+ if ( !prs_uint16("size", ps, depth, &uni4->size ))
+ return False;
+
+ ptr = uni4->string;
+
+ if ( !prs_pointer( desc, ps, depth, &ptr, sizeof(UNISTR2), (PRS_POINTER_CAST)prs_io_unistr2 ) )
+ return False;
+
+ uni4->string = (UNISTR2 *)ptr;
+
+ return True;
+}
+
+/*******************************************************************
+ now read/write UNISTR4 header
+********************************************************************/
+
+bool prs_unistr4_hdr(const char *desc, prs_struct *ps, int depth, UNISTR4 *uni4)
+{
+ prs_debug(ps, depth, desc, "prs_unistr4_hdr");
+ depth++;
+
+ if ( !prs_uint16("length", ps, depth, &uni4->length) )
+ return False;
+ if ( !prs_uint16("size", ps, depth, &uni4->size) )
+ return False;
+ if ( !prs_io_unistr2_p(desc, ps, depth, &uni4->string) )
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ now read/write UNISTR4 string
+********************************************************************/
+
+bool prs_unistr4_str(const char *desc, prs_struct *ps, int depth, UNISTR4 *uni4)
+{
+ prs_debug(ps, depth, desc, "prs_unistr4_str");
+ depth++;
+
+ if ( !prs_io_unistr2(desc, ps, depth, uni4->string) )
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a UNISTR4_ARRAY structure.
+********************************************************************/
+
+bool prs_unistr4_array(const char *desc, prs_struct *ps, int depth, UNISTR4_ARRAY *array )
+{
+ unsigned int i;
+
+ prs_debug(ps, depth, desc, "prs_unistr4_array");
+ depth++;
+
+ if(!prs_uint32("count", ps, depth, &array->count))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (array->count) {
+ if ( !(array->strings = TALLOC_ZERO_ARRAY( talloc_tos(), UNISTR4, array->count)) )
+ return False;
+ } else {
+ array->strings = NULL;
+ }
+ }
+
+ /* write the headers and then the actual string buffer */
+
+ for ( i=0; i<array->count; i++ ) {
+ if ( !prs_unistr4_hdr( "string", ps, depth, &array->strings[i]) )
+ return False;
+ }
+
+ for (i=0;i<array->count;i++) {
+ if ( !prs_unistr4_str("string", ps, depth, &array->strings[i]) )
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ initialise a UNISTR_ARRAY from a char**
+********************************************************************/
+
+bool init_unistr4_array( UNISTR4_ARRAY *array, uint32 count, const char **strings )
+{
+ unsigned int i;
+
+ array->count = count;
+
+ /* allocate memory for the array of UNISTR4 objects */
+
+ if (array->count) {
+ if ( !(array->strings = TALLOC_ZERO_ARRAY(talloc_tos(), UNISTR4, count )) )
+ return False;
+ } else {
+ array->strings = NULL;
+ }
+
+ for ( i=0; i<count; i++ )
+ init_unistr4( &array->strings[i], strings[i], UNI_STR_TERMINATE );
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a DOM_RID structure.
+********************************************************************/
+
+void init_dom_rid(DOM_RID *prid, uint32 rid, uint16 type, uint32 idx)
+{
+ prid->type = type;
+ prid->rid = rid;
+ prid->rid_idx = idx;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_RID structure.
+********************************************************************/
+
+bool smb_io_dom_rid(const char *desc, DOM_RID *rid, prs_struct *ps, int depth)
+{
+ if (rid == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_dom_rid");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16("type ", ps, depth, &rid->type))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("rid ", ps, depth, &rid->rid))
+ return False;
+ if(!prs_uint32("rid_idx", ps, depth, &rid->rid_idx))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_RID2 structure.
+********************************************************************/
+
+bool smb_io_dom_rid2(const char *desc, DOM_RID2 *rid, prs_struct *ps, int depth)
+{
+ if (rid == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_dom_rid2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16("type ", ps, depth, &rid->type))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("rid ", ps, depth, &rid->rid))
+ return False;
+ if(!prs_uint32("rid_idx", ps, depth, &rid->rid_idx))
+ return False;
+ if(!prs_uint32("unknown", ps, depth, &rid->unknown))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+creates a DOM_RID3 structure.
+********************************************************************/
+
+void init_dom_rid3(DOM_RID3 *rid3, uint32 rid, uint8 type)
+{
+ rid3->rid = rid;
+ rid3->type1 = type;
+ rid3->ptr_type = 0x1; /* non-zero, basically. */
+ rid3->type2 = 0x1;
+ rid3->unk = type;
+}
+
+/*******************************************************************
+reads or writes a DOM_RID3 structure.
+********************************************************************/
+
+bool smb_io_dom_rid3(const char *desc, DOM_RID3 *rid3, prs_struct *ps, int depth)
+{
+ if (rid3 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_dom_rid3");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("rid ", ps, depth, &rid3->rid))
+ return False;
+ if(!prs_uint32("type1 ", ps, depth, &rid3->type1))
+ return False;
+ if(!prs_uint32("ptr_type", ps, depth, &rid3->ptr_type))
+ return False;
+ if(!prs_uint32("type2 ", ps, depth, &rid3->type2))
+ return False;
+ if(!prs_uint32("unk ", ps, depth, &rid3->unk))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a DOM_RID4 structure.
+********************************************************************/
+
+void init_dom_rid4(DOM_RID4 *rid4, uint16 unknown, uint16 attr, uint32 rid)
+{
+ rid4->unknown = unknown;
+ rid4->attr = attr;
+ rid4->rid = rid;
+}
+
+/*******************************************************************
+ Inits a DOM_CLNT_SRV structure.
+********************************************************************/
+
+void init_clnt_srv(DOM_CLNT_SRV *logcln, const char *logon_srv,
+ const char *comp_name)
+{
+ DEBUG(5,("init_clnt_srv: %d\n", __LINE__));
+
+ if (logon_srv != NULL) {
+ logcln->undoc_buffer = 1;
+ init_unistr2(&logcln->uni_logon_srv, logon_srv, UNI_STR_TERMINATE);
+ } else {
+ logcln->undoc_buffer = 0;
+ }
+
+ if (comp_name != NULL) {
+ logcln->undoc_buffer2 = 1;
+ init_unistr2(&logcln->uni_comp_name, comp_name, UNI_STR_TERMINATE);
+ } else {
+ logcln->undoc_buffer2 = 0;
+ }
+}
+
+/*******************************************************************
+ Inits or writes a DOM_CLNT_SRV structure.
+********************************************************************/
+
+bool smb_io_clnt_srv(const char *desc, DOM_CLNT_SRV *logcln, prs_struct *ps, int depth)
+{
+ if (logcln == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_clnt_srv");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("undoc_buffer ", ps, depth, &logcln->undoc_buffer))
+ return False;
+
+ if (logcln->undoc_buffer != 0) {
+ if(!smb_io_unistr2("unistr2", &logcln->uni_logon_srv, logcln->undoc_buffer, ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("undoc_buffer2", ps, depth, &logcln->undoc_buffer2))
+ return False;
+
+ if (logcln->undoc_buffer2 != 0) {
+ if(!smb_io_unistr2("unistr2", &logcln->uni_comp_name, logcln->undoc_buffer2, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a DOM_LOG_INFO structure.
+********************************************************************/
+
+void init_log_info(DOM_LOG_INFO *loginfo, const char *logon_srv, const char *acct_name,
+ uint16 sec_chan, const char *comp_name)
+{
+ DEBUG(5,("make_log_info %d\n", __LINE__));
+
+ loginfo->undoc_buffer = 1;
+
+ init_unistr2(&loginfo->uni_logon_srv, logon_srv, UNI_STR_TERMINATE);
+ init_unistr2(&loginfo->uni_acct_name, acct_name, UNI_STR_TERMINATE);
+
+ loginfo->sec_chan = sec_chan;
+
+ init_unistr2(&loginfo->uni_comp_name, comp_name, UNI_STR_TERMINATE);
+}
+
+/*******************************************************************
+ Reads or writes a DOM_LOG_INFO structure.
+********************************************************************/
+
+bool smb_io_log_info(const char *desc, DOM_LOG_INFO *loginfo, prs_struct *ps, int depth)
+{
+ if (loginfo == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_log_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("undoc_buffer", ps, depth, &loginfo->undoc_buffer))
+ return False;
+
+ if(!smb_io_unistr2("unistr2", &loginfo->uni_logon_srv, True, ps, depth))
+ return False;
+ if(!smb_io_unistr2("unistr2", &loginfo->uni_acct_name, True, ps, depth))
+ return False;
+
+ if(!prs_uint16("sec_chan", ps, depth, &loginfo->sec_chan))
+ return False;
+
+ if(!smb_io_unistr2("unistr2", &loginfo->uni_comp_name, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_CHAL structure.
+********************************************************************/
+
+bool smb_io_chal(const char *desc, DOM_CHAL *chal, prs_struct *ps, int depth)
+{
+ if (chal == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_chal");
+ depth++;
+
+ if(!prs_uint8s (False, "data", ps, depth, chal->data, 8))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_CRED structure.
+********************************************************************/
+
+bool smb_io_cred(const char *desc, DOM_CRED *cred, prs_struct *ps, int depth)
+{
+ if (cred == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_cred");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_chal ("", &cred->challenge, ps, depth))
+ return False;
+
+ if(!smb_io_utime("", &cred->timestamp, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a DOM_CLNT_INFO2 structure.
+********************************************************************/
+
+void init_clnt_info2(DOM_CLNT_INFO2 *clnt,
+ const char *logon_srv, const char *comp_name,
+ const DOM_CRED *clnt_cred)
+{
+ DEBUG(5,("make_clnt_info: %d\n", __LINE__));
+
+ init_clnt_srv(&clnt->login, logon_srv, comp_name);
+
+ if (clnt_cred != NULL) {
+ clnt->ptr_cred = 1;
+ memcpy(&clnt->cred, clnt_cred, sizeof(clnt->cred));
+ } else {
+ clnt->ptr_cred = 0;
+ }
+}
+
+/*******************************************************************
+ Reads or writes a DOM_CLNT_INFO2 structure.
+********************************************************************/
+
+bool smb_io_clnt_info2(const char *desc, DOM_CLNT_INFO2 *clnt, prs_struct *ps, int depth)
+{
+ if (clnt == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_clnt_info2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_clnt_srv("", &clnt->login, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_cred", ps, depth, &clnt->ptr_cred))
+ return False;
+ if(!smb_io_cred("", &clnt->cred, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a DOM_CLNT_INFO structure.
+********************************************************************/
+
+void init_clnt_info(DOM_CLNT_INFO *clnt,
+ const char *logon_srv, const char *acct_name,
+ uint16 sec_chan, const char *comp_name,
+ const DOM_CRED *cred)
+{
+ DEBUG(5,("make_clnt_info\n"));
+
+ init_log_info(&clnt->login, logon_srv, acct_name, sec_chan, comp_name);
+ memcpy(&clnt->cred, cred, sizeof(clnt->cred));
+}
+
+/*******************************************************************
+ Reads or writes a DOM_CLNT_INFO structure.
+********************************************************************/
+
+bool smb_io_clnt_info(const char *desc, DOM_CLNT_INFO *clnt, prs_struct *ps, int depth)
+{
+ if (clnt == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_clnt_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_log_info("", &clnt->login, ps, depth))
+ return False;
+ if(!smb_io_cred("", &clnt->cred, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a DOM_LOGON_ID structure.
+********************************************************************/
+
+void init_logon_id(DOM_LOGON_ID *logonid, uint32 log_id_low, uint32 log_id_high)
+{
+ DEBUG(5,("make_logon_id: %d\n", __LINE__));
+
+ logonid->low = log_id_low;
+ logonid->high = log_id_high;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_LOGON_ID structure.
+********************************************************************/
+
+bool smb_io_logon_id(const char *desc, DOM_LOGON_ID *logonid, prs_struct *ps, int depth)
+{
+ if (logonid == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_logon_id");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("low ", ps, depth, &logonid->low ))
+ return False;
+ if(!prs_uint32("high", ps, depth, &logonid->high))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an OWF_INFO structure.
+********************************************************************/
+
+void init_owf_info(OWF_INFO *hash, const uint8 data[16])
+{
+ DEBUG(5,("init_owf_info: %d\n", __LINE__));
+
+ if (data != NULL)
+ memcpy(hash->data, data, sizeof(hash->data));
+ else
+ memset((char *)hash->data, '\0', sizeof(hash->data));
+}
+
+/*******************************************************************
+ Reads or writes an OWF_INFO structure.
+********************************************************************/
+
+bool smb_io_owf_info(const char *desc, OWF_INFO *hash, prs_struct *ps, int depth)
+{
+ if (hash == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_owf_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint8s (False, "data", ps, depth, hash->data, 16))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_GID structure.
+********************************************************************/
+
+bool smb_io_gid(const char *desc, DOM_GID *gid, prs_struct *ps, int depth)
+{
+ if (gid == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_gid");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("g_rid", ps, depth, &gid->g_rid))
+ return False;
+ if(!prs_uint32("attr ", ps, depth, &gid->attr))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an POLICY_HND structure.
+********************************************************************/
+
+bool smb_io_pol_hnd(const char *desc, POLICY_HND *pol, prs_struct *ps, int depth)
+{
+ if (pol == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_pol_hnd");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(UNMARSHALLING(ps))
+ ZERO_STRUCTP(pol);
+
+ if (!prs_uint32("handle_type", ps, depth, &pol->handle_type))
+ return False;
+ if (!smb_io_uuid("uuid", (struct GUID*)&pol->uuid, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Create a UNISTR3.
+********************************************************************/
+
+void init_unistr3(UNISTR3 *str, const char *buf)
+{
+ if (buf == NULL) {
+ str->uni_str_len=0;
+ str->str.buffer = NULL;
+ return;
+ }
+
+ str->uni_str_len = strlen(buf) + 1;
+
+ if (str->uni_str_len) {
+ str->str.buffer = TALLOC_ZERO_ARRAY(talloc_tos(), uint16, str->uni_str_len);
+ if (str->str.buffer == NULL)
+ smb_panic("init_unistr3: malloc fail");
+
+ rpcstr_push((char *)str->str.buffer, buf, str->uni_str_len * sizeof(uint16), STR_TERMINATE);
+ } else {
+ str->str.buffer = NULL;
+ }
+}
+
+/*******************************************************************
+ Reads or writes a UNISTR3 structure.
+********************************************************************/
+
+bool smb_io_unistr3(const char *desc, UNISTR3 *name, prs_struct *ps, int depth)
+{
+ if (name == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_unistr3");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("uni_str_len", ps, depth, &name->uni_str_len))
+ return False;
+
+ /* we're done if there is no string */
+
+ if ( name->uni_str_len == 0 )
+ return True;
+
+ /* don't know if len is specified by uni_str_len member... */
+ /* assume unicode string is unicode-null-terminated, instead */
+
+ if(!prs_unistr3(True, "unistr", name, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Stream a uint64_struct
+ ********************************************************************/
+bool prs_uint64(const char *name, prs_struct *ps, int depth, uint64 *data64)
+{
+ if (UNMARSHALLING(ps)) {
+ uint32 high, low;
+
+ if (!prs_uint32(name, ps, depth+1, &low))
+ return False;
+
+ if (!prs_uint32(name, ps, depth+1, &high))
+ return False;
+
+ *data64 = ((uint64_t)high << 32) + low;
+
+ return True;
+ } else {
+ uint32 high = (*data64) >> 32, low = (*data64) & 0xFFFFFFFF;
+ return prs_uint32(name, ps, depth+1, &low) &&
+ prs_uint32(name, ps, depth+1, &high);
+ }
+}
+
+/*******************************************************************
+reads or writes a BUFHDR2 structure.
+********************************************************************/
+bool smb_io_bufhdr2(const char *desc, BUFHDR2 *hdr, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "smb_io_bufhdr2");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("info_level", ps, depth, &(hdr->info_level)))
+ return False;
+ if (!prs_uint32("length ", ps, depth, &(hdr->length )))
+ return False;
+ if (!prs_uint32("buffer ", ps, depth, &(hdr->buffer )))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a BUFHDR4 structure.
+********************************************************************/
+bool smb_io_bufhdr4(const char *desc, BUFHDR4 *hdr, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "smb_io_bufhdr4");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("size", ps, depth, &hdr->size))
+ return False;
+ if (!prs_uint32("buffer", ps, depth, &hdr->buffer))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a RPC_DATA_BLOB structure.
+********************************************************************/
+
+bool smb_io_rpc_blob(const char *desc, RPC_DATA_BLOB *blob, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "smb_io_rpc_blob");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if ( !prs_uint32("buf_len", ps, depth, &blob->buf_len) )
+ return False;
+
+ if ( blob->buf_len == 0 )
+ return True;
+
+ if (UNMARSHALLING(ps)) {
+ blob->buffer = PRS_ALLOC_MEM(ps, uint8, blob->buf_len);
+ if (!blob->buffer) {
+ return False;
+ }
+ }
+
+ if ( !prs_uint8s(True, "buffer", ps, depth, blob->buffer, blob->buf_len) )
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+creates a UNIHDR structure.
+********************************************************************/
+
+bool make_uni_hdr(UNIHDR *hdr, int len)
+{
+ if (hdr == NULL)
+ {
+ return False;
+ }
+ hdr->uni_str_len = 2 * len;
+ hdr->uni_max_len = 2 * len;
+ hdr->buffer = len != 0 ? 1 : 0;
+
+ return True;
+}
+
+/*******************************************************************
+creates a BUFHDR2 structure.
+********************************************************************/
+bool make_bufhdr2(BUFHDR2 *hdr, uint32 info_level, uint32 length, uint32 buffer)
+{
+ hdr->info_level = info_level;
+ hdr->length = length;
+ hdr->buffer = buffer;
+
+ return True;
+}
+
+/*******************************************************************
+return the length of a UNISTR string.
+********************************************************************/
+
+uint32 str_len_uni(UNISTR *source)
+{
+ uint32 i=0;
+
+ if (!source->buffer)
+ return 0;
+
+ while (source->buffer[i])
+ i++;
+
+ return i;
+}
+
+/*******************************************************************
+ Verifies policy handle
+********************************************************************/
+
+bool policy_handle_is_valid(const POLICY_HND *hnd)
+{
+ POLICY_HND zero_pol;
+
+ ZERO_STRUCT(zero_pol);
+ return ((memcmp(&zero_pol, hnd, sizeof(POLICY_HND)) == 0) ? false : true );
+}
diff --git a/source3/rpc_parse/parse_ntsvcs.c b/source3/rpc_parse/parse_ntsvcs.c
new file mode 100644
index 0000000000..2b15a45506
--- /dev/null
+++ b/source3/rpc_parse/parse_ntsvcs.c
@@ -0,0 +1,147 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Gerald (Jerry) Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_PARSE
+
+/*******************************************************************
+********************************************************************/
+
+bool ntsvcs_io_q_get_device_list(const char *desc, NTSVCS_Q_GET_DEVICE_LIST *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "ntsvcs_io_q_get_device_list");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if ( !prs_pointer("devicename", ps, depth, (void*)&q_u->devicename, sizeof(UNISTR2), (PRS_POINTER_CAST)prs_io_unistr2) )
+ return False;
+ if( !prs_align(ps) )
+ return False;
+
+ if ( !prs_uint32("buffer_size", ps, depth, &q_u->buffer_size) )
+ return False;
+ if ( !prs_uint32("flags", ps, depth, &q_u->flags) )
+ return False;
+
+ return True;
+
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool ntsvcs_io_r_get_device_list(const char *desc, NTSVCS_R_GET_DEVICE_LIST *r_u, prs_struct *ps, int depth)
+{
+ if ( !r_u )
+ return False;
+
+ prs_debug(ps, depth, desc, "ntsvcs_io_r_get_device_list_size");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if ( !prs_io_unistr2("devicepath", ps, depth, &r_u->devicepath) )
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool ntsvcs_io_q_get_device_reg_property(const char *desc, NTSVCS_Q_GET_DEVICE_REG_PROPERTY *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "ntsvcs_io_q_get_device_reg_property");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if ( !prs_io_unistr2("devicepath", ps, depth, &q_u->devicepath) )
+ return False;
+ if( !prs_align(ps) )
+ return False;
+
+ if ( !prs_uint32("property", ps, depth, &q_u->property) )
+ return False;
+ if ( !prs_uint32("unknown2", ps, depth, &q_u->unknown2) )
+ return False;
+ if ( !prs_uint32("buffer_size1", ps, depth, &q_u->buffer_size1) )
+ return False;
+ if ( !prs_uint32("buffer_size2", ps, depth, &q_u->buffer_size2) )
+ return False;
+ if ( !prs_uint32("unknown5", ps, depth, &q_u->unknown5) )
+ return False;
+
+ return True;
+
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool ntsvcs_io_r_get_device_reg_property(const char *desc, NTSVCS_R_GET_DEVICE_REG_PROPERTY *r_u, prs_struct *ps, int depth)
+{
+ if ( !r_u )
+ return False;
+
+ prs_debug(ps, depth, desc, "ntsvcs_io_r_get_device_reg_property");
+ depth++;
+
+ if ( !prs_align(ps) )
+ return False;
+
+ if ( !prs_uint32("unknown1", ps, depth, &r_u->unknown1) )
+ return False;
+
+ if ( !smb_io_regval_buffer("value", ps, depth, &r_u->value) )
+ return False;
+ if ( !prs_align(ps) )
+ return False;
+
+ if ( !prs_uint32("size", ps, depth, &r_u->size) )
+ return False;
+
+ if ( !prs_uint32("needed", ps, depth, &r_u->needed) )
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
diff --git a/source3/rpc_parse/parse_prs.c b/source3/rpc_parse/parse_prs.c
new file mode 100644
index 0000000000..5eb6c31ee6
--- /dev/null
+++ b/source3/rpc_parse/parse_prs.c
@@ -0,0 +1,1868 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba memory buffer functions
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Jeremy Allison 1999
+ Copyright (C) Andrew Bartlett 2003.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_PARSE
+
+/**
+ * Dump a prs to a file: from the current location through to the end.
+ **/
+void prs_dump(const char *name, int v, prs_struct *ps)
+{
+ prs_dump_region(name, v, ps, ps->data_offset, ps->buffer_size);
+}
+
+/**
+ * Dump from the start of the prs to the current location.
+ **/
+void prs_dump_before(const char *name, int v, prs_struct *ps)
+{
+ prs_dump_region(name, v, ps, 0, ps->data_offset);
+}
+
+/**
+ * Dump everything from the start of the prs up to the current location.
+ **/
+void prs_dump_region(const char *name, int v, prs_struct *ps,
+ int from_off, int to_off)
+{
+ int fd, i;
+ char *fname = NULL;
+ ssize_t sz;
+ if (DEBUGLEVEL < 50) return;
+ for (i=1;i<100;i++) {
+ if (v != -1) {
+ if (asprintf(&fname,"/tmp/%s_%d.%d.prs", name, v, i) < 0) {
+ return;
+ }
+ } else {
+ if (asprintf(&fname,"/tmp/%s.%d.prs", name, i) < 0) {
+ return;
+ }
+ }
+ fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
+ if (fd != -1 || errno != EEXIST) break;
+ }
+ if (fd != -1) {
+ sz = write(fd, ps->data_p + from_off, to_off - from_off);
+ i = close(fd);
+ if ( (sz != to_off-from_off) || (i != 0) ) {
+ DEBUG(0,("Error writing/closing %s: %ld!=%ld %d\n", fname, (unsigned long)sz, (unsigned long)to_off-from_off, i ));
+ } else {
+ DEBUG(0,("created %s\n", fname));
+ }
+ }
+ SAFE_FREE(fname);
+}
+
+/*******************************************************************
+ Debug output for parsing info
+
+ XXXX side-effect of this function is to increase the debug depth XXXX.
+
+********************************************************************/
+
+void prs_debug(prs_struct *ps, int depth, const char *desc, const char *fn_name)
+{
+ DEBUG(5+depth, ("%s%06x %s %s\n", tab_depth(5+depth,depth), ps->data_offset, fn_name, desc));
+}
+
+/**
+ * Initialise an expandable parse structure.
+ *
+ * @param size Initial buffer size. If >0, a new buffer will be
+ * created with malloc().
+ *
+ * @return False if allocation fails, otherwise True.
+ **/
+
+bool prs_init(prs_struct *ps, uint32 size, TALLOC_CTX *ctx, bool io)
+{
+ ZERO_STRUCTP(ps);
+ ps->io = io;
+ ps->bigendian_data = RPC_LITTLE_ENDIAN;
+ ps->align = RPC_PARSE_ALIGN;
+ ps->is_dynamic = False;
+ ps->data_offset = 0;
+ ps->buffer_size = 0;
+ ps->data_p = NULL;
+ ps->mem_ctx = ctx;
+
+ if (size != 0) {
+ ps->buffer_size = size;
+ if((ps->data_p = (char *)SMB_MALLOC((size_t)size)) == NULL) {
+ DEBUG(0,("prs_init: malloc fail for %u bytes.\n", (unsigned int)size));
+ return False;
+ }
+ memset(ps->data_p, '\0', (size_t)size);
+ ps->is_dynamic = True; /* We own this memory. */
+ } else if (MARSHALLING(ps)) {
+ /* If size is zero and we're marshalling we should allocate memory on demand. */
+ ps->is_dynamic = True;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Delete the memory in a parse structure - if we own it.
+
+ NOTE: Contrary to the somewhat confusing naming, this function is not
+ intended for freeing memory allocated by prs_alloc_mem(). That memory
+ is attached to the talloc context given by ps->mem_ctx.
+ ********************************************************************/
+
+void prs_mem_free(prs_struct *ps)
+{
+ if(ps->is_dynamic)
+ SAFE_FREE(ps->data_p);
+ ps->is_dynamic = False;
+ ps->buffer_size = 0;
+ ps->data_offset = 0;
+}
+
+/*******************************************************************
+ Clear the memory in a parse structure.
+ ********************************************************************/
+
+void prs_mem_clear(prs_struct *ps)
+{
+ if (ps->buffer_size)
+ memset(ps->data_p, '\0', (size_t)ps->buffer_size);
+}
+
+/*******************************************************************
+ Allocate memory when unmarshalling... Always zero clears.
+ ********************************************************************/
+
+#if defined(PARANOID_MALLOC_CHECKER)
+char *prs_alloc_mem_(prs_struct *ps, size_t size, unsigned int count)
+#else
+char *prs_alloc_mem(prs_struct *ps, size_t size, unsigned int count)
+#endif
+{
+ char *ret = NULL;
+
+ if (size && count) {
+ /* We can't call the type-safe version here. */
+ ret = (char *)_talloc_zero_array(ps->mem_ctx, size, count,
+ "parse_prs");
+ }
+ return ret;
+}
+
+/*******************************************************************
+ Return the current talloc context we're using.
+ ********************************************************************/
+
+TALLOC_CTX *prs_get_mem_context(prs_struct *ps)
+{
+ return ps->mem_ctx;
+}
+
+/*******************************************************************
+ Hand some already allocated memory to a prs_struct.
+ ********************************************************************/
+
+void prs_give_memory(prs_struct *ps, char *buf, uint32 size, bool is_dynamic)
+{
+ ps->is_dynamic = is_dynamic;
+ ps->data_p = buf;
+ ps->buffer_size = size;
+}
+
+/*******************************************************************
+ Take some memory back from a prs_struct.
+ ********************************************************************/
+
+char *prs_take_memory(prs_struct *ps, uint32 *psize)
+{
+ char *ret = ps->data_p;
+ if(psize)
+ *psize = ps->buffer_size;
+ ps->is_dynamic = False;
+ prs_mem_free(ps);
+ return ret;
+}
+
+/*******************************************************************
+ Set a prs_struct to exactly a given size. Will grow or tuncate if neccessary.
+ ********************************************************************/
+
+bool prs_set_buffer_size(prs_struct *ps, uint32 newsize)
+{
+ if (newsize > ps->buffer_size)
+ return prs_force_grow(ps, newsize - ps->buffer_size);
+
+ if (newsize < ps->buffer_size) {
+ ps->buffer_size = newsize;
+
+ /* newsize == 0 acts as a free and set pointer to NULL */
+ if (newsize == 0) {
+ SAFE_FREE(ps->data_p);
+ } else {
+ ps->data_p = (char *)SMB_REALLOC(ps->data_p, newsize);
+
+ if (ps->data_p == NULL) {
+ DEBUG(0,("prs_set_buffer_size: Realloc failure for size %u.\n",
+ (unsigned int)newsize));
+ DEBUG(0,("prs_set_buffer_size: Reason %s\n",strerror(errno)));
+ return False;
+ }
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Attempt, if needed, to grow a data buffer.
+ Also depends on the data stream mode (io).
+ ********************************************************************/
+
+bool prs_grow(prs_struct *ps, uint32 extra_space)
+{
+ uint32 new_size;
+
+ ps->grow_size = MAX(ps->grow_size, ps->data_offset + extra_space);
+
+ if(ps->data_offset + extra_space <= ps->buffer_size)
+ return True;
+
+ /*
+ * We cannot grow the buffer if we're not reading
+ * into the prs_struct, or if we don't own the memory.
+ */
+
+ if(UNMARSHALLING(ps) || !ps->is_dynamic) {
+ DEBUG(0,("prs_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
+ (unsigned int)extra_space));
+ return False;
+ }
+
+ /*
+ * Decide how much extra space we really need.
+ */
+
+ extra_space -= (ps->buffer_size - ps->data_offset);
+ if(ps->buffer_size == 0) {
+ /*
+ * Ensure we have at least a PDU's length, or extra_space, whichever
+ * is greater.
+ */
+
+ new_size = MAX(RPC_MAX_PDU_FRAG_LEN,extra_space);
+
+ if((ps->data_p = (char *)SMB_MALLOC(new_size)) == NULL) {
+ DEBUG(0,("prs_grow: Malloc failure for size %u.\n", (unsigned int)new_size));
+ return False;
+ }
+ memset(ps->data_p, '\0', (size_t)new_size );
+ } else {
+ /*
+ * If the current buffer size is bigger than the space needed, just
+ * double it, else add extra_space.
+ */
+ new_size = MAX(ps->buffer_size*2, ps->buffer_size + extra_space);
+
+ if ((ps->data_p = (char *)SMB_REALLOC(ps->data_p, new_size)) == NULL) {
+ DEBUG(0,("prs_grow: Realloc failure for size %u.\n",
+ (unsigned int)new_size));
+ return False;
+ }
+
+ memset(&ps->data_p[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
+ }
+ ps->buffer_size = new_size;
+
+ return True;
+}
+
+/*******************************************************************
+ Attempt to force a data buffer to grow by len bytes.
+ This is only used when appending more data onto a prs_struct
+ when reading an rpc reply, before unmarshalling it.
+ ********************************************************************/
+
+bool prs_force_grow(prs_struct *ps, uint32 extra_space)
+{
+ uint32 new_size = ps->buffer_size + extra_space;
+
+ if(!UNMARSHALLING(ps) || !ps->is_dynamic) {
+ DEBUG(0,("prs_force_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
+ (unsigned int)extra_space));
+ return False;
+ }
+
+ if((ps->data_p = (char *)SMB_REALLOC(ps->data_p, new_size)) == NULL) {
+ DEBUG(0,("prs_force_grow: Realloc failure for size %u.\n",
+ (unsigned int)new_size));
+ return False;
+ }
+
+ memset(&ps->data_p[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
+
+ ps->buffer_size = new_size;
+
+ return True;
+}
+
+/*******************************************************************
+ Get the data pointer (external interface).
+********************************************************************/
+
+char *prs_data_p(prs_struct *ps)
+{
+ return ps->data_p;
+}
+
+/*******************************************************************
+ Get the current data size (external interface).
+ ********************************************************************/
+
+uint32 prs_data_size(prs_struct *ps)
+{
+ return ps->buffer_size;
+}
+
+/*******************************************************************
+ Fetch the current offset (external interface).
+ ********************************************************************/
+
+uint32 prs_offset(prs_struct *ps)
+{
+ return ps->data_offset;
+}
+
+/*******************************************************************
+ Set the current offset (external interface).
+ ********************************************************************/
+
+bool prs_set_offset(prs_struct *ps, uint32 offset)
+{
+ if(offset <= ps->data_offset) {
+ ps->data_offset = offset;
+ return True;
+ }
+
+ if(!prs_grow(ps, offset - ps->data_offset))
+ return False;
+
+ ps->data_offset = offset;
+ return True;
+}
+
+/*******************************************************************
+ Append the data from one parse_struct into another.
+ ********************************************************************/
+
+bool prs_append_prs_data(prs_struct *dst, prs_struct *src)
+{
+ if (prs_offset(src) == 0)
+ return True;
+
+ if(!prs_grow(dst, prs_offset(src)))
+ return False;
+
+ memcpy(&dst->data_p[dst->data_offset], src->data_p, (size_t)prs_offset(src));
+ dst->data_offset += prs_offset(src);
+
+ return True;
+}
+
+/*******************************************************************
+ Append some data from one parse_struct into another.
+ ********************************************************************/
+
+bool prs_append_some_data(prs_struct *dst, void *src_base, uint32_t start,
+ uint32_t len)
+{
+ if (len == 0) {
+ return true;
+ }
+
+ if(!prs_grow(dst, len)) {
+ return false;
+ }
+
+ memcpy(&dst->data_p[dst->data_offset], ((char *)src_base) + start, (size_t)len);
+ dst->data_offset += len;
+ return true;
+}
+
+bool prs_append_some_prs_data(prs_struct *dst, prs_struct *src, int32 start,
+ uint32 len)
+{
+ return prs_append_some_data(dst, src->data_p, start, len);
+}
+
+/*******************************************************************
+ Append the data from a buffer into a parse_struct.
+ ********************************************************************/
+
+bool prs_copy_data_in(prs_struct *dst, const char *src, uint32 len)
+{
+ if (len == 0)
+ return True;
+
+ if(!prs_grow(dst, len))
+ return False;
+
+ memcpy(&dst->data_p[dst->data_offset], src, (size_t)len);
+ dst->data_offset += len;
+
+ return True;
+}
+
+/*******************************************************************
+ Copy some data from a parse_struct into a buffer.
+ ********************************************************************/
+
+bool prs_copy_data_out(char *dst, prs_struct *src, uint32 len)
+{
+ if (len == 0)
+ return True;
+
+ if(!prs_mem_get(src, len))
+ return False;
+
+ memcpy(dst, &src->data_p[src->data_offset], (size_t)len);
+ src->data_offset += len;
+
+ return True;
+}
+
+/*******************************************************************
+ Copy all the data from a parse_struct into a buffer.
+ ********************************************************************/
+
+bool prs_copy_all_data_out(char *dst, prs_struct *src)
+{
+ uint32 len = prs_offset(src);
+
+ if (!len)
+ return True;
+
+ prs_set_offset(src, 0);
+ return prs_copy_data_out(dst, src, len);
+}
+
+/*******************************************************************
+ Set the data as X-endian (external interface).
+ ********************************************************************/
+
+void prs_set_endian_data(prs_struct *ps, bool endian)
+{
+ ps->bigendian_data = endian;
+}
+
+/*******************************************************************
+ Align a the data_len to a multiple of align bytes - filling with
+ zeros.
+ ********************************************************************/
+
+bool prs_align(prs_struct *ps)
+{
+ uint32 mod = ps->data_offset & (ps->align-1);
+
+ if (ps->align != 0 && mod != 0) {
+ uint32 extra_space = (ps->align - mod);
+ if(!prs_grow(ps, extra_space))
+ return False;
+ memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space);
+ ps->data_offset += extra_space;
+ }
+
+ return True;
+}
+
+/******************************************************************
+ Align on a 2 byte boundary
+ *****************************************************************/
+
+bool prs_align_uint16(prs_struct *ps)
+{
+ bool ret;
+ uint8 old_align = ps->align;
+
+ ps->align = 2;
+ ret = prs_align(ps);
+ ps->align = old_align;
+
+ return ret;
+}
+
+/******************************************************************
+ Align on a 8 byte boundary
+ *****************************************************************/
+
+bool prs_align_uint64(prs_struct *ps)
+{
+ bool ret;
+ uint8 old_align = ps->align;
+
+ ps->align = 8;
+ ret = prs_align(ps);
+ ps->align = old_align;
+
+ return ret;
+}
+
+/******************************************************************
+ Align on a specific byte boundary
+ *****************************************************************/
+
+bool prs_align_custom(prs_struct *ps, uint8 boundary)
+{
+ bool ret;
+ uint8 old_align = ps->align;
+
+ ps->align = boundary;
+ ret = prs_align(ps);
+ ps->align = old_align;
+
+ return ret;
+}
+
+
+
+/*******************************************************************
+ Align only if required (for the unistr2 string mainly)
+ ********************************************************************/
+
+bool prs_align_needed(prs_struct *ps, uint32 needed)
+{
+ if (needed==0)
+ return True;
+ else
+ return prs_align(ps);
+}
+
+/*******************************************************************
+ Ensure we can read/write to a given offset.
+ ********************************************************************/
+
+char *prs_mem_get(prs_struct *ps, uint32 extra_size)
+{
+ if(UNMARSHALLING(ps)) {
+ /*
+ * If reading, ensure that we can read the requested size item.
+ */
+ if (ps->data_offset + extra_size > ps->buffer_size) {
+ DEBUG(0,("prs_mem_get: reading data of size %u would overrun "
+ "buffer by %u bytes.\n",
+ (unsigned int)extra_size,
+ (unsigned int)(ps->data_offset + extra_size - ps->buffer_size) ));
+ return NULL;
+ }
+ } else {
+ /*
+ * Writing - grow the buffer if needed.
+ */
+ if(!prs_grow(ps, extra_size))
+ return NULL;
+ }
+ return &ps->data_p[ps->data_offset];
+}
+
+/*******************************************************************
+ Change the struct type.
+ ********************************************************************/
+
+void prs_switch_type(prs_struct *ps, bool io)
+{
+ if ((ps->io ^ io) == True)
+ ps->io=io;
+}
+
+/*******************************************************************
+ Force a prs_struct to be dynamic even when it's size is 0.
+ ********************************************************************/
+
+void prs_force_dynamic(prs_struct *ps)
+{
+ ps->is_dynamic=True;
+}
+
+/*******************************************************************
+ Associate a session key with a parse struct.
+ ********************************************************************/
+
+void prs_set_session_key(prs_struct *ps, const char sess_key[16])
+{
+ ps->sess_key = sess_key;
+}
+
+/*******************************************************************
+ Stream a uint8.
+ ********************************************************************/
+
+bool prs_uint8(const char *name, prs_struct *ps, int depth, uint8 *data8)
+{
+ char *q = prs_mem_get(ps, 1);
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps))
+ *data8 = CVAL(q,0);
+ else
+ SCVAL(q,0,*data8);
+
+ DEBUG(5,("%s%04x %s: %02x\n", tab_depth(5,depth), ps->data_offset, name, *data8));
+
+ ps->data_offset += 1;
+
+ return True;
+}
+
+/*******************************************************************
+ Stream a uint16* (allocate memory if unmarshalling)
+ ********************************************************************/
+
+bool prs_pointer( const char *name, prs_struct *ps, int depth,
+ void *dta, size_t data_size,
+ bool (*prs_fn)(const char*, prs_struct*, int, void*) )
+{
+ void ** data = (void **)dta;
+ uint32 data_p;
+
+ /* output f000baaa to stream if the pointer is non-zero. */
+
+ data_p = *data ? 0xf000baaa : 0;
+
+ if ( !prs_uint32("ptr", ps, depth, &data_p ))
+ return False;
+
+ /* we're done if there is no data */
+
+ if ( !data_p )
+ return True;
+
+ if (UNMARSHALLING(ps)) {
+ if (data_size) {
+ if ( !(*data = PRS_ALLOC_MEM(ps, char, data_size)) )
+ return False;
+ } else {
+ *data = NULL;
+ }
+ }
+
+ return prs_fn(name, ps, depth, *data);
+}
+
+
+/*******************************************************************
+ Stream a uint16.
+ ********************************************************************/
+
+bool prs_uint16(const char *name, prs_struct *ps, int depth, uint16 *data16)
+{
+ char *q = prs_mem_get(ps, sizeof(uint16));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data)
+ *data16 = RSVAL(q,0);
+ else
+ *data16 = SVAL(q,0);
+ } else {
+ if (ps->bigendian_data)
+ RSSVAL(q,0,*data16);
+ else
+ SSVAL(q,0,*data16);
+ }
+
+ DEBUG(5,("%s%04x %s: %04x\n", tab_depth(5,depth), ps->data_offset, name, *data16));
+
+ ps->data_offset += sizeof(uint16);
+
+ return True;
+}
+
+/*******************************************************************
+ Stream a uint32.
+ ********************************************************************/
+
+bool prs_uint32(const char *name, prs_struct *ps, int depth, uint32 *data32)
+{
+ char *q = prs_mem_get(ps, sizeof(uint32));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data)
+ *data32 = RIVAL(q,0);
+ else
+ *data32 = IVAL(q,0);
+ } else {
+ if (ps->bigendian_data)
+ RSIVAL(q,0,*data32);
+ else
+ SIVAL(q,0,*data32);
+ }
+
+ DEBUG(5,("%s%04x %s: %08x\n", tab_depth(5,depth), ps->data_offset, name, *data32));
+
+ ps->data_offset += sizeof(uint32);
+
+ return True;
+}
+
+/*******************************************************************
+ Stream an int32.
+ ********************************************************************/
+
+bool prs_int32(const char *name, prs_struct *ps, int depth, int32 *data32)
+{
+ char *q = prs_mem_get(ps, sizeof(int32));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data)
+ *data32 = RIVALS(q,0);
+ else
+ *data32 = IVALS(q,0);
+ } else {
+ if (ps->bigendian_data)
+ RSIVALS(q,0,*data32);
+ else
+ SIVALS(q,0,*data32);
+ }
+
+ DEBUG(5,("%s%04x %s: %08x\n", tab_depth(5,depth), ps->data_offset, name, *data32));
+
+ ps->data_offset += sizeof(int32);
+
+ return True;
+}
+
+/*******************************************************************
+ Stream a NTSTATUS
+ ********************************************************************/
+
+bool prs_ntstatus(const char *name, prs_struct *ps, int depth, NTSTATUS *status)
+{
+ char *q = prs_mem_get(ps, sizeof(uint32));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data)
+ *status = NT_STATUS(RIVAL(q,0));
+ else
+ *status = NT_STATUS(IVAL(q,0));
+ } else {
+ if (ps->bigendian_data)
+ RSIVAL(q,0,NT_STATUS_V(*status));
+ else
+ SIVAL(q,0,NT_STATUS_V(*status));
+ }
+
+ DEBUG(5,("%s%04x %s: %s\n", tab_depth(5,depth), ps->data_offset, name,
+ nt_errstr(*status)));
+
+ ps->data_offset += sizeof(uint32);
+
+ return True;
+}
+
+/*******************************************************************
+ Stream a DCE error code
+ ********************************************************************/
+
+bool prs_dcerpc_status(const char *name, prs_struct *ps, int depth, NTSTATUS *status)
+{
+ char *q = prs_mem_get(ps, sizeof(uint32));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data)
+ *status = NT_STATUS(RIVAL(q,0));
+ else
+ *status = NT_STATUS(IVAL(q,0));
+ } else {
+ if (ps->bigendian_data)
+ RSIVAL(q,0,NT_STATUS_V(*status));
+ else
+ SIVAL(q,0,NT_STATUS_V(*status));
+ }
+
+ DEBUG(5,("%s%04x %s: %s\n", tab_depth(5,depth), ps->data_offset, name,
+ dcerpc_errstr(NT_STATUS_V(*status))));
+
+ ps->data_offset += sizeof(uint32);
+
+ return True;
+}
+
+
+/*******************************************************************
+ Stream a WERROR
+ ********************************************************************/
+
+bool prs_werror(const char *name, prs_struct *ps, int depth, WERROR *status)
+{
+ char *q = prs_mem_get(ps, sizeof(uint32));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data)
+ *status = W_ERROR(RIVAL(q,0));
+ else
+ *status = W_ERROR(IVAL(q,0));
+ } else {
+ if (ps->bigendian_data)
+ RSIVAL(q,0,W_ERROR_V(*status));
+ else
+ SIVAL(q,0,W_ERROR_V(*status));
+ }
+
+ DEBUG(5,("%s%04x %s: %s\n", tab_depth(5,depth), ps->data_offset, name,
+ dos_errstr(*status)));
+
+ ps->data_offset += sizeof(uint32);
+
+ return True;
+}
+
+
+/******************************************************************
+ Stream an array of uint8s. Length is number of uint8s.
+ ********************************************************************/
+
+bool prs_uint8s(bool charmode, const char *name, prs_struct *ps, int depth, uint8 *data8s, int len)
+{
+ int i;
+ char *q = prs_mem_get(ps, len);
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ for (i = 0; i < len; i++)
+ data8s[i] = CVAL(q,i);
+ } else {
+ for (i = 0; i < len; i++)
+ SCVAL(q, i, data8s[i]);
+ }
+
+ DEBUG(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset ,name));
+ if (charmode)
+ print_asc(5, (unsigned char*)data8s, len);
+ else {
+ for (i = 0; i < len; i++)
+ DEBUG(5,("%02x ", data8s[i]));
+ }
+ DEBUG(5,("\n"));
+
+ ps->data_offset += len;
+
+ return True;
+}
+
+/******************************************************************
+ Stream an array of uint16s. Length is number of uint16s.
+ ********************************************************************/
+
+bool prs_uint16s(bool charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
+{
+ int i;
+ char *q = prs_mem_get(ps, len * sizeof(uint16));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data) {
+ for (i = 0; i < len; i++)
+ data16s[i] = RSVAL(q, 2*i);
+ } else {
+ for (i = 0; i < len; i++)
+ data16s[i] = SVAL(q, 2*i);
+ }
+ } else {
+ if (ps->bigendian_data) {
+ for (i = 0; i < len; i++)
+ RSSVAL(q, 2*i, data16s[i]);
+ } else {
+ for (i = 0; i < len; i++)
+ SSVAL(q, 2*i, data16s[i]);
+ }
+ }
+
+ DEBUG(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
+ if (charmode)
+ print_asc(5, (unsigned char*)data16s, 2*len);
+ else {
+ for (i = 0; i < len; i++)
+ DEBUG(5,("%04x ", data16s[i]));
+ }
+ DEBUG(5,("\n"));
+
+ ps->data_offset += (len * sizeof(uint16));
+
+ return True;
+}
+
+/******************************************************************
+ Start using a function for streaming unicode chars. If unmarshalling,
+ output must be little-endian, if marshalling, input must be little-endian.
+ ********************************************************************/
+
+static void dbg_rw_punival(bool charmode, const char *name, int depth, prs_struct *ps,
+ char *in_buf, char *out_buf, int len)
+{
+ int i;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data) {
+ for (i = 0; i < len; i++)
+ SSVAL(out_buf,2*i,RSVAL(in_buf, 2*i));
+ } else {
+ for (i = 0; i < len; i++)
+ SSVAL(out_buf, 2*i, SVAL(in_buf, 2*i));
+ }
+ } else {
+ if (ps->bigendian_data) {
+ for (i = 0; i < len; i++)
+ RSSVAL(in_buf, 2*i, SVAL(out_buf,2*i));
+ } else {
+ for (i = 0; i < len; i++)
+ SSVAL(in_buf, 2*i, SVAL(out_buf,2*i));
+ }
+ }
+
+ DEBUG(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
+ if (charmode)
+ print_asc(5, (unsigned char*)out_buf, 2*len);
+ else {
+ for (i = 0; i < len; i++)
+ DEBUG(5,("%04x ", out_buf[i]));
+ }
+ DEBUG(5,("\n"));
+}
+
+/******************************************************************
+ Stream a unistr. Always little endian.
+ ********************************************************************/
+
+bool prs_uint16uni(bool charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
+{
+ char *q = prs_mem_get(ps, len * sizeof(uint16));
+ if (q == NULL)
+ return False;
+
+ dbg_rw_punival(charmode, name, depth, ps, q, (char *)data16s, len);
+ ps->data_offset += (len * sizeof(uint16));
+
+ return True;
+}
+
+/******************************************************************
+ Stream an array of uint32s. Length is number of uint32s.
+ ********************************************************************/
+
+bool prs_uint32s(bool charmode, const char *name, prs_struct *ps, int depth, uint32 *data32s, int len)
+{
+ int i;
+ char *q = prs_mem_get(ps, len * sizeof(uint32));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data) {
+ for (i = 0; i < len; i++)
+ data32s[i] = RIVAL(q, 4*i);
+ } else {
+ for (i = 0; i < len; i++)
+ data32s[i] = IVAL(q, 4*i);
+ }
+ } else {
+ if (ps->bigendian_data) {
+ for (i = 0; i < len; i++)
+ RSIVAL(q, 4*i, data32s[i]);
+ } else {
+ for (i = 0; i < len; i++)
+ SIVAL(q, 4*i, data32s[i]);
+ }
+ }
+
+ DEBUG(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
+ if (charmode)
+ print_asc(5, (unsigned char*)data32s, 4*len);
+ else {
+ for (i = 0; i < len; i++)
+ DEBUG(5,("%08x ", data32s[i]));
+ }
+ DEBUG(5,("\n"));
+
+ ps->data_offset += (len * sizeof(uint32));
+
+ return True;
+}
+
+/******************************************************************
+ Stream an array of unicode string, length/buffer specified separately,
+ in uint16 chars. The unicode string is already in little-endian format.
+ ********************************************************************/
+
+bool prs_buffer5(bool charmode, const char *name, prs_struct *ps, int depth, BUFFER5 *str)
+{
+ char *p;
+ char *q = prs_mem_get(ps, str->buf_len * sizeof(uint16));
+ if (q == NULL)
+ return False;
+
+ /* If the string is empty, we don't have anything to stream */
+ if (str->buf_len==0)
+ return True;
+
+ if (UNMARSHALLING(ps)) {
+ str->buffer = PRS_ALLOC_MEM(ps,uint16,str->buf_len);
+ if (str->buffer == NULL)
+ return False;
+ }
+
+ p = (char *)str->buffer;
+
+ dbg_rw_punival(charmode, name, depth, ps, q, p, str->buf_len);
+
+ ps->data_offset += (str->buf_len * sizeof(uint16));
+
+ return True;
+}
+
+/******************************************************************
+ Stream a "not" unicode string, length/buffer specified separately,
+ in byte chars. String is in little-endian format.
+ ********************************************************************/
+
+bool prs_regval_buffer(bool charmode, const char *name, prs_struct *ps, int depth, REGVAL_BUFFER *buf)
+{
+ char *p;
+ char *q = prs_mem_get(ps, buf->buf_len);
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (buf->buf_len > buf->buf_max_len) {
+ return False;
+ }
+ if ( buf->buf_max_len ) {
+ buf->buffer = PRS_ALLOC_MEM(ps, uint16, buf->buf_max_len);
+ if ( buf->buffer == NULL )
+ return False;
+ } else {
+ buf->buffer = NULL;
+ }
+ }
+
+ p = (char *)buf->buffer;
+
+ dbg_rw_punival(charmode, name, depth, ps, q, p, buf->buf_len/2);
+ ps->data_offset += buf->buf_len;
+
+ return True;
+}
+
+/******************************************************************
+ Stream a string, length/buffer specified separately,
+ in uint8 chars.
+ ********************************************************************/
+
+bool prs_string2(bool charmode, const char *name, prs_struct *ps, int depth, STRING2 *str)
+{
+ unsigned int i;
+ char *q = prs_mem_get(ps, str->str_str_len);
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (str->str_str_len > str->str_max_len) {
+ return False;
+ }
+ if (str->str_max_len) {
+ str->buffer = PRS_ALLOC_MEM(ps,unsigned char, str->str_max_len);
+ if (str->buffer == NULL)
+ return False;
+ } else {
+ str->buffer = NULL;
+ /* Return early to ensure Coverity isn't confused. */
+ DEBUG(5,("%s%04x %s: \n", tab_depth(5,depth), ps->data_offset, name));
+ return True;
+ }
+ }
+
+ if (UNMARSHALLING(ps)) {
+ for (i = 0; i < str->str_str_len; i++)
+ str->buffer[i] = CVAL(q,i);
+ } else {
+ for (i = 0; i < str->str_str_len; i++)
+ SCVAL(q, i, str->buffer[i]);
+ }
+
+ DEBUG(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
+ if (charmode)
+ print_asc(5, (unsigned char*)str->buffer, str->str_str_len);
+ else {
+ for (i = 0; i < str->str_str_len; i++)
+ DEBUG(5,("%02x ", str->buffer[i]));
+ }
+ DEBUG(5,("\n"));
+
+ ps->data_offset += str->str_str_len;
+
+ return True;
+}
+
+/******************************************************************
+ Stream a unicode string, length/buffer specified separately,
+ in uint16 chars. The unicode string is already in little-endian format.
+ ********************************************************************/
+
+bool prs_unistr2(bool charmode, const char *name, prs_struct *ps, int depth, UNISTR2 *str)
+{
+ char *p;
+ char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
+ if (q == NULL)
+ return False;
+
+ /* If the string is empty, we don't have anything to stream */
+ if (str->uni_str_len==0)
+ return True;
+
+ if (UNMARSHALLING(ps)) {
+ if (str->uni_str_len > str->uni_max_len) {
+ return False;
+ }
+ if (str->uni_max_len) {
+ str->buffer = PRS_ALLOC_MEM(ps,uint16,str->uni_max_len);
+ if (str->buffer == NULL)
+ return False;
+ } else {
+ str->buffer = NULL;
+ }
+ }
+
+ p = (char *)str->buffer;
+
+ dbg_rw_punival(charmode, name, depth, ps, q, p, str->uni_str_len);
+
+ ps->data_offset += (str->uni_str_len * sizeof(uint16));
+
+ return True;
+}
+
+/******************************************************************
+ Stream a unicode string, length/buffer specified separately,
+ in uint16 chars. The unicode string is already in little-endian format.
+ ********************************************************************/
+
+bool prs_unistr3(bool charmode, const char *name, UNISTR3 *str, prs_struct *ps, int depth)
+{
+ char *p;
+ char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (str->uni_str_len) {
+ str->str.buffer = PRS_ALLOC_MEM(ps,uint16,str->uni_str_len);
+ if (str->str.buffer == NULL)
+ return False;
+ } else {
+ str->str.buffer = NULL;
+ }
+ }
+
+ p = (char *)str->str.buffer;
+
+ dbg_rw_punival(charmode, name, depth, ps, q, p, str->uni_str_len);
+ ps->data_offset += (str->uni_str_len * sizeof(uint16));
+
+ return True;
+}
+
+/*******************************************************************
+ Stream a unicode null-terminated string. As the string is already
+ in little-endian format then do it as a stream of bytes.
+ ********************************************************************/
+
+bool prs_unistr(const char *name, prs_struct *ps, int depth, UNISTR *str)
+{
+ unsigned int len = 0;
+ unsigned char *p = (unsigned char *)str->buffer;
+ uint8 *start;
+ char *q;
+ uint32 max_len;
+ uint16* ptr;
+
+ if (MARSHALLING(ps)) {
+
+ for(len = 0; str->buffer[len] != 0; len++)
+ ;
+
+ q = prs_mem_get(ps, (len+1)*2);
+ if (q == NULL)
+ return False;
+
+ start = (uint8*)q;
+
+ for(len = 0; str->buffer[len] != 0; len++) {
+ if(ps->bigendian_data) {
+ /* swap bytes - p is little endian, q is big endian. */
+ q[0] = (char)p[1];
+ q[1] = (char)p[0];
+ p += 2;
+ q += 2;
+ }
+ else
+ {
+ q[0] = (char)p[0];
+ q[1] = (char)p[1];
+ p += 2;
+ q += 2;
+ }
+ }
+
+ /*
+ * even if the string is 'empty' (only an \0 char)
+ * at this point the leading \0 hasn't been parsed.
+ * so parse it now
+ */
+
+ q[0] = 0;
+ q[1] = 0;
+ q += 2;
+
+ len++;
+
+ DEBUG(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
+ print_asc(5, (unsigned char*)start, 2*len);
+ DEBUG(5, ("\n"));
+ }
+ else { /* unmarshalling */
+
+ uint32 alloc_len = 0;
+ q = ps->data_p + prs_offset(ps);
+
+ /*
+ * Work out how much space we need and talloc it.
+ */
+ max_len = (ps->buffer_size - ps->data_offset)/sizeof(uint16);
+
+ /* the test of the value of *ptr helps to catch the circumstance
+ where we have an emtpty (non-existent) string in the buffer */
+ for ( ptr = (uint16 *)q; *ptr++ && (alloc_len <= max_len); alloc_len++)
+ /* do nothing */
+ ;
+
+ if (alloc_len < max_len)
+ alloc_len += 1;
+
+ /* should we allocate anything at all? */
+ str->buffer = PRS_ALLOC_MEM(ps,uint16,alloc_len);
+ if ((str->buffer == NULL) && (alloc_len > 0))
+ return False;
+
+ p = (unsigned char *)str->buffer;
+
+ len = 0;
+ /* the (len < alloc_len) test is to prevent us from overwriting
+ memory that is not ours...if we get that far, we have a non-null
+ terminated string in the buffer and have messed up somewhere */
+ while ((len < alloc_len) && (*(uint16 *)q != 0)) {
+ if(ps->bigendian_data)
+ {
+ /* swap bytes - q is big endian, p is little endian. */
+ p[0] = (unsigned char)q[1];
+ p[1] = (unsigned char)q[0];
+ p += 2;
+ q += 2;
+ } else {
+
+ p[0] = (unsigned char)q[0];
+ p[1] = (unsigned char)q[1];
+ p += 2;
+ q += 2;
+ }
+
+ len++;
+ }
+ if (len < alloc_len) {
+ /* NULL terminate the UNISTR */
+ str->buffer[len++] = '\0';
+ }
+
+ DEBUG(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
+ print_asc(5, (unsigned char*)str->buffer, 2*len);
+ DEBUG(5, ("\n"));
+ }
+
+ /* set the offset in the prs_struct; 'len' points to the
+ terminiating NULL in the UNISTR so we need to go one more
+ uint16 */
+ ps->data_offset += (len)*2;
+
+ return True;
+}
+
+
+/*******************************************************************
+ Stream a null-terminated string. len is strlen, and therefore does
+ not include the null-termination character.
+ ********************************************************************/
+
+bool prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_buf_size)
+{
+ char *q;
+ int i;
+ int len;
+
+ if (UNMARSHALLING(ps))
+ len = strlen(&ps->data_p[ps->data_offset]);
+ else
+ len = strlen(str);
+
+ len = MIN(len, (max_buf_size-1));
+
+ q = prs_mem_get(ps, len+1);
+ if (q == NULL)
+ return False;
+
+ for(i = 0; i < len; i++) {
+ if (UNMARSHALLING(ps))
+ str[i] = q[i];
+ else
+ q[i] = str[i];
+ }
+
+ /* The terminating null. */
+ str[i] = '\0';
+
+ if (MARSHALLING(ps)) {
+ q[i] = '\0';
+ }
+
+ ps->data_offset += len+1;
+
+ dump_data(5+depth, (uint8 *)q, len);
+
+ return True;
+}
+
+bool prs_string_alloc(const char *name, prs_struct *ps, int depth, const char **str)
+{
+ size_t len;
+ char *tmp_str;
+
+ if (UNMARSHALLING(ps)) {
+ len = strlen(&ps->data_p[ps->data_offset]);
+ } else {
+ len = strlen(*str);
+ }
+
+ tmp_str = PRS_ALLOC_MEM(ps, char, len+1);
+
+ if (tmp_str == NULL) {
+ return False;
+ }
+
+ if (MARSHALLING(ps)) {
+ strncpy(tmp_str, *str, len);
+ }
+
+ if (!prs_string(name, ps, depth, tmp_str, len+1)) {
+ return False;
+ }
+
+ *str = tmp_str;
+ return True;
+}
+
+/*******************************************************************
+ prs_uint16 wrapper. Call this and it sets up a pointer to where the
+ uint16 should be stored, or gets the size if reading.
+ ********************************************************************/
+
+bool prs_uint16_pre(const char *name, prs_struct *ps, int depth, uint16 *data16, uint32 *offset)
+{
+ *offset = ps->data_offset;
+ if (UNMARSHALLING(ps)) {
+ /* reading. */
+ return prs_uint16(name, ps, depth, data16);
+ } else {
+ char *q = prs_mem_get(ps, sizeof(uint16));
+ if(q ==NULL)
+ return False;
+ ps->data_offset += sizeof(uint16);
+ }
+ return True;
+}
+
+/*******************************************************************
+ prs_uint16 wrapper. call this and it retrospectively stores the size.
+ does nothing on reading, as that is already handled by ...._pre()
+ ********************************************************************/
+
+bool prs_uint16_post(const char *name, prs_struct *ps, int depth, uint16 *data16,
+ uint32 ptr_uint16, uint32 start_offset)
+{
+ if (MARSHALLING(ps)) {
+ /*
+ * Writing - temporarily move the offset pointer.
+ */
+ uint16 data_size = ps->data_offset - start_offset;
+ uint32 old_offset = ps->data_offset;
+
+ ps->data_offset = ptr_uint16;
+ if(!prs_uint16(name, ps, depth, &data_size)) {
+ ps->data_offset = old_offset;
+ return False;
+ }
+ ps->data_offset = old_offset;
+ } else {
+ ps->data_offset = start_offset + (uint32)(*data16);
+ }
+ return True;
+}
+
+/*******************************************************************
+ prs_uint32 wrapper. Call this and it sets up a pointer to where the
+ uint32 should be stored, or gets the size if reading.
+ ********************************************************************/
+
+bool prs_uint32_pre(const char *name, prs_struct *ps, int depth, uint32 *data32, uint32 *offset)
+{
+ *offset = ps->data_offset;
+ if (UNMARSHALLING(ps) && (data32 != NULL)) {
+ /* reading. */
+ return prs_uint32(name, ps, depth, data32);
+ } else {
+ ps->data_offset += sizeof(uint32);
+ }
+ return True;
+}
+
+/*******************************************************************
+ prs_uint32 wrapper. call this and it retrospectively stores the size.
+ does nothing on reading, as that is already handled by ...._pre()
+ ********************************************************************/
+
+bool prs_uint32_post(const char *name, prs_struct *ps, int depth, uint32 *data32,
+ uint32 ptr_uint32, uint32 data_size)
+{
+ if (MARSHALLING(ps)) {
+ /*
+ * Writing - temporarily move the offset pointer.
+ */
+ uint32 old_offset = ps->data_offset;
+ ps->data_offset = ptr_uint32;
+ if(!prs_uint32(name, ps, depth, &data_size)) {
+ ps->data_offset = old_offset;
+ return False;
+ }
+ ps->data_offset = old_offset;
+ }
+ return True;
+}
+
+/* useful function to store a structure in rpc wire format */
+int tdb_prs_store(TDB_CONTEXT *tdb, TDB_DATA kbuf, prs_struct *ps)
+{
+ TDB_DATA dbuf;
+ dbuf.dptr = (uint8 *)ps->data_p;
+ dbuf.dsize = prs_offset(ps);
+ return tdb_trans_store(tdb, kbuf, dbuf, TDB_REPLACE);
+}
+
+/* useful function to fetch a structure into rpc wire format */
+int tdb_prs_fetch(TDB_CONTEXT *tdb, TDB_DATA kbuf, prs_struct *ps, TALLOC_CTX *mem_ctx)
+{
+ TDB_DATA dbuf;
+
+ prs_init_empty(ps, mem_ctx, UNMARSHALL);
+
+ dbuf = tdb_fetch(tdb, kbuf);
+ if (!dbuf.dptr)
+ return -1;
+
+ prs_give_memory(ps, (char *)dbuf.dptr, dbuf.dsize, True);
+
+ return 0;
+}
+
+/*******************************************************************
+ hash a stream.
+ ********************************************************************/
+
+bool prs_hash1(prs_struct *ps, uint32 offset, int len)
+{
+ char *q;
+
+ q = ps->data_p;
+ q = &q[offset];
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("prs_hash1\n"));
+ dump_data(100, (uint8 *)ps->sess_key, 16);
+ dump_data(100, (uint8 *)q, len);
+#endif
+ SamOEMhash((uchar *) q, (const unsigned char *)ps->sess_key, len);
+
+#ifdef DEBUG_PASSWORD
+ dump_data(100, (uint8 *)q, len);
+#endif
+
+ return True;
+}
+
+/*******************************************************************
+ Create a digest over the entire packet (including the data), and
+ MD5 it with the session key.
+ ********************************************************************/
+
+static void schannel_digest(struct schannel_auth_struct *a,
+ enum pipe_auth_level auth_level,
+ RPC_AUTH_SCHANNEL_CHK * verf,
+ char *data, size_t data_len,
+ uchar digest_final[16])
+{
+ uchar whole_packet_digest[16];
+ uchar zeros[4];
+ struct MD5Context ctx3;
+
+ ZERO_STRUCT(zeros);
+
+ /* verfiy the signature on the packet by MD5 over various bits */
+ MD5Init(&ctx3);
+ /* use our sequence number, which ensures the packet is not
+ out of order */
+ MD5Update(&ctx3, zeros, sizeof(zeros));
+ MD5Update(&ctx3, verf->sig, sizeof(verf->sig));
+ if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
+ MD5Update(&ctx3, verf->confounder, sizeof(verf->confounder));
+ }
+ MD5Update(&ctx3, (const unsigned char *)data, data_len);
+ MD5Final(whole_packet_digest, &ctx3);
+ dump_data_pw("whole_packet_digest:\n", whole_packet_digest, sizeof(whole_packet_digest));
+
+ /* MD5 this result and the session key, to prove that
+ only a valid client could had produced this */
+ hmac_md5(a->sess_key, whole_packet_digest, sizeof(whole_packet_digest), digest_final);
+}
+
+/*******************************************************************
+ Calculate the key with which to encode the data payload
+ ********************************************************************/
+
+static void schannel_get_sealing_key(struct schannel_auth_struct *a,
+ RPC_AUTH_SCHANNEL_CHK *verf,
+ uchar sealing_key[16])
+{
+ uchar zeros[4];
+ uchar digest2[16];
+ uchar sess_kf0[16];
+ int i;
+
+ ZERO_STRUCT(zeros);
+
+ for (i = 0; i < sizeof(sess_kf0); i++) {
+ sess_kf0[i] = a->sess_key[i] ^ 0xf0;
+ }
+
+ dump_data_pw("sess_kf0:\n", sess_kf0, sizeof(sess_kf0));
+
+ /* MD5 of sess_kf0 and 4 zero bytes */
+ hmac_md5(sess_kf0, zeros, 0x4, digest2);
+ dump_data_pw("digest2:\n", digest2, sizeof(digest2));
+
+ /* MD5 of the above result, plus 8 bytes of sequence number */
+ hmac_md5(digest2, verf->seq_num, sizeof(verf->seq_num), sealing_key);
+ dump_data_pw("sealing_key:\n", sealing_key, 16);
+}
+
+/*******************************************************************
+ Encode or Decode the sequence number (which is symmetric)
+ ********************************************************************/
+
+static void schannel_deal_with_seq_num(struct schannel_auth_struct *a,
+ RPC_AUTH_SCHANNEL_CHK *verf)
+{
+ uchar zeros[4];
+ uchar sequence_key[16];
+ uchar digest1[16];
+
+ ZERO_STRUCT(zeros);
+
+ hmac_md5(a->sess_key, zeros, sizeof(zeros), digest1);
+ dump_data_pw("(sequence key) digest1:\n", digest1, sizeof(digest1));
+
+ hmac_md5(digest1, verf->packet_digest, 8, sequence_key);
+
+ dump_data_pw("sequence_key:\n", sequence_key, sizeof(sequence_key));
+
+ dump_data_pw("seq_num (before):\n", verf->seq_num, sizeof(verf->seq_num));
+ SamOEMhash(verf->seq_num, sequence_key, 8);
+ dump_data_pw("seq_num (after):\n", verf->seq_num, sizeof(verf->seq_num));
+}
+
+/*******************************************************************
+creates an RPC_AUTH_SCHANNEL_CHK structure.
+********************************************************************/
+
+static bool init_rpc_auth_schannel_chk(RPC_AUTH_SCHANNEL_CHK * chk,
+ const uchar sig[8],
+ const uchar packet_digest[8],
+ const uchar seq_num[8], const uchar confounder[8])
+{
+ if (chk == NULL)
+ return False;
+
+ memcpy(chk->sig, sig, sizeof(chk->sig));
+ memcpy(chk->packet_digest, packet_digest, sizeof(chk->packet_digest));
+ memcpy(chk->seq_num, seq_num, sizeof(chk->seq_num));
+ memcpy(chk->confounder, confounder, sizeof(chk->confounder));
+
+ return True;
+}
+
+/*******************************************************************
+ Encode a blob of data using the schannel alogrithm, also produceing
+ a checksum over the original data. We currently only support
+ signing and sealing togeather - the signing-only code is close, but not
+ quite compatible with what MS does.
+ ********************************************************************/
+
+void schannel_encode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level,
+ enum schannel_direction direction,
+ RPC_AUTH_SCHANNEL_CHK * verf,
+ char *data, size_t data_len)
+{
+ uchar digest_final[16];
+ uchar confounder[8];
+ uchar seq_num[8];
+ static const uchar nullbytes[8] = { 0, };
+
+ static const uchar schannel_seal_sig[8] = SCHANNEL_SEAL_SIGNATURE;
+ static const uchar schannel_sign_sig[8] = SCHANNEL_SIGN_SIGNATURE;
+ const uchar *schannel_sig = NULL;
+
+ DEBUG(10,("SCHANNEL: schannel_encode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
+
+ if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
+ schannel_sig = schannel_seal_sig;
+ } else {
+ schannel_sig = schannel_sign_sig;
+ }
+
+ /* fill the 'confounder' with random data */
+ generate_random_buffer(confounder, sizeof(confounder));
+
+ dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
+
+ RSIVAL(seq_num, 0, a->seq_num);
+
+ switch (direction) {
+ case SENDER_IS_INITIATOR:
+ SIVAL(seq_num, 4, 0x80);
+ break;
+ case SENDER_IS_ACCEPTOR:
+ SIVAL(seq_num, 4, 0x0);
+ break;
+ }
+
+ dump_data_pw("verf->seq_num:\n", seq_num, sizeof(verf->seq_num));
+
+ init_rpc_auth_schannel_chk(verf, schannel_sig, nullbytes,
+ seq_num, confounder);
+
+ /* produce a digest of the packet to prove it's legit (before we seal it) */
+ schannel_digest(a, auth_level, verf, data, data_len, digest_final);
+ memcpy(verf->packet_digest, digest_final, sizeof(verf->packet_digest));
+
+ if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
+ uchar sealing_key[16];
+
+ /* get the key to encode the data with */
+ schannel_get_sealing_key(a, verf, sealing_key);
+
+ /* encode the verification data */
+ dump_data_pw("verf->confounder:\n", verf->confounder, sizeof(verf->confounder));
+ SamOEMhash(verf->confounder, sealing_key, 8);
+
+ dump_data_pw("verf->confounder_enc:\n", verf->confounder, sizeof(verf->confounder));
+
+ /* encode the packet payload */
+ dump_data_pw("data:\n", (const unsigned char *)data, data_len);
+ SamOEMhash((unsigned char *)data, sealing_key, data_len);
+ dump_data_pw("data_enc:\n", (const unsigned char *)data, data_len);
+ }
+
+ /* encode the sequence number (key based on packet digest) */
+ /* needs to be done after the sealing, as the original version
+ is used in the sealing stuff... */
+ schannel_deal_with_seq_num(a, verf);
+
+ return;
+}
+
+/*******************************************************************
+ Decode a blob of data using the schannel alogrithm, also verifiying
+ a checksum over the original data. We currently can verify signed messages,
+ as well as decode sealed messages
+ ********************************************************************/
+
+bool schannel_decode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level,
+ enum schannel_direction direction,
+ RPC_AUTH_SCHANNEL_CHK * verf, char *data, size_t data_len)
+{
+ uchar digest_final[16];
+
+ static const uchar schannel_seal_sig[8] = SCHANNEL_SEAL_SIGNATURE;
+ static const uchar schannel_sign_sig[8] = SCHANNEL_SIGN_SIGNATURE;
+ const uchar *schannel_sig = NULL;
+
+ uchar seq_num[8];
+
+ DEBUG(10,("SCHANNEL: schannel_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
+
+ if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
+ schannel_sig = schannel_seal_sig;
+ } else {
+ schannel_sig = schannel_sign_sig;
+ }
+
+ /* Create the expected sequence number for comparison */
+ RSIVAL(seq_num, 0, a->seq_num);
+
+ switch (direction) {
+ case SENDER_IS_INITIATOR:
+ SIVAL(seq_num, 4, 0x80);
+ break;
+ case SENDER_IS_ACCEPTOR:
+ SIVAL(seq_num, 4, 0x0);
+ break;
+ }
+
+ DEBUG(10,("SCHANNEL: schannel_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
+ dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
+
+ dump_data_pw("seq_num:\n", seq_num, sizeof(seq_num));
+
+ /* extract the sequence number (key based on supplied packet digest) */
+ /* needs to be done before the sealing, as the original version
+ is used in the sealing stuff... */
+ schannel_deal_with_seq_num(a, verf);
+
+ if (memcmp(verf->seq_num, seq_num, sizeof(seq_num))) {
+ /* don't even bother with the below if the sequence number is out */
+ /* The sequence number is MD5'ed with a key based on the whole-packet
+ digest, as supplied by the client. We check that it's a valid
+ checksum after the decode, below
+ */
+ DEBUG(2, ("schannel_decode: FAILED: packet sequence number:\n"));
+ dump_data(2, verf->seq_num, sizeof(verf->seq_num));
+ DEBUG(2, ("should be:\n"));
+ dump_data(2, seq_num, sizeof(seq_num));
+
+ return False;
+ }
+
+ if (memcmp(verf->sig, schannel_sig, sizeof(verf->sig))) {
+ /* Validate that the other end sent the expected header */
+ DEBUG(2, ("schannel_decode: FAILED: packet header:\n"));
+ dump_data(2, verf->sig, sizeof(verf->sig));
+ DEBUG(2, ("should be:\n"));
+ dump_data(2, schannel_sig, sizeof(schannel_sig));
+ return False;
+ }
+
+ if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
+ uchar sealing_key[16];
+
+ /* get the key to extract the data with */
+ schannel_get_sealing_key(a, verf, sealing_key);
+
+ /* extract the verification data */
+ dump_data_pw("verf->confounder:\n", verf->confounder,
+ sizeof(verf->confounder));
+ SamOEMhash(verf->confounder, sealing_key, 8);
+
+ dump_data_pw("verf->confounder_dec:\n", verf->confounder,
+ sizeof(verf->confounder));
+
+ /* extract the packet payload */
+ dump_data_pw("data :\n", (const unsigned char *)data, data_len);
+ SamOEMhash((unsigned char *)data, sealing_key, data_len);
+ dump_data_pw("datadec:\n", (const unsigned char *)data, data_len);
+ }
+
+ /* digest includes 'data' after unsealing */
+ schannel_digest(a, auth_level, verf, data, data_len, digest_final);
+
+ dump_data_pw("Calculated digest:\n", digest_final,
+ sizeof(digest_final));
+ dump_data_pw("verf->packet_digest:\n", verf->packet_digest,
+ sizeof(verf->packet_digest));
+
+ /* compare - if the client got the same result as us, then
+ it must know the session key */
+ return (memcmp(digest_final, verf->packet_digest,
+ sizeof(verf->packet_digest)) == 0);
+}
+
+/*******************************************************************
+creates a new prs_struct containing a DATA_BLOB
+********************************************************************/
+bool prs_init_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
+{
+ if (!prs_init( prs, RPC_MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL ))
+ return False;
+
+
+ if (!prs_copy_data_in(prs, (char *)blob->data, blob->length))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+return the contents of a prs_struct in a DATA_BLOB
+********************************************************************/
+bool prs_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
+{
+ blob->length = prs_data_size(prs);
+ blob->data = (uint8 *)TALLOC_ZERO_SIZE(mem_ctx, blob->length);
+
+ /* set the pointer at the end of the buffer */
+ prs_set_offset( prs, prs_data_size(prs) );
+
+ if (!prs_copy_all_data_out((char *)blob->data, prs))
+ return False;
+
+ return True;
+}
diff --git a/source3/rpc_parse/parse_rpc.c b/source3/rpc_parse/parse_rpc.c
new file mode 100644
index 0000000000..1477a4c81e
--- /dev/null
+++ b/source3/rpc_parse/parse_rpc.c
@@ -0,0 +1,651 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 1999.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_PARSE
+
+/*******************************************************************
+ Inits an RPC_HDR structure.
+********************************************************************/
+
+void init_rpc_hdr(RPC_HDR *hdr, enum RPC_PKT_TYPE pkt_type, uint8 flags,
+ uint32 call_id, int data_len, int auth_len)
+{
+ hdr->major = 5; /* RPC version 5 */
+ hdr->minor = 0; /* minor version 0 */
+ hdr->pkt_type = pkt_type; /* RPC packet type */
+ hdr->flags = flags; /* dce/rpc flags */
+ hdr->pack_type[0] = 0x10; /* little-endian data representation */
+ hdr->pack_type[1] = 0; /* packed data representation */
+ hdr->pack_type[2] = 0; /* packed data representation */
+ hdr->pack_type[3] = 0; /* packed data representation */
+ hdr->frag_len = data_len; /* fragment length, fill in later */
+ hdr->auth_len = auth_len; /* authentication length */
+ hdr->call_id = call_id; /* call identifier - match incoming RPC */
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR structure.
+********************************************************************/
+
+bool smb_io_rpc_hdr(const char *desc, RPC_HDR *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr");
+ depth++;
+
+ if(!prs_uint8 ("major ", ps, depth, &rpc->major))
+ return False;
+
+ if(!prs_uint8 ("minor ", ps, depth, &rpc->minor))
+ return False;
+ if(!prs_uint8 ("pkt_type ", ps, depth, &rpc->pkt_type))
+ return False;
+ if(!prs_uint8 ("flags ", ps, depth, &rpc->flags))
+ return False;
+
+ /* We always marshall in little endian format. */
+ if (MARSHALLING(ps))
+ rpc->pack_type[0] = 0x10;
+
+ if(!prs_uint8("pack_type0", ps, depth, &rpc->pack_type[0]))
+ return False;
+ if(!prs_uint8("pack_type1", ps, depth, &rpc->pack_type[1]))
+ return False;
+ if(!prs_uint8("pack_type2", ps, depth, &rpc->pack_type[2]))
+ return False;
+ if(!prs_uint8("pack_type3", ps, depth, &rpc->pack_type[3]))
+ return False;
+
+ /*
+ * If reading and pack_type[0] == 0 then the data is in big-endian
+ * format. Set the flag in the prs_struct to specify reverse-endainness.
+ */
+
+ if (UNMARSHALLING(ps) && rpc->pack_type[0] == 0) {
+ DEBUG(10,("smb_io_rpc_hdr: PDU data format is big-endian. Setting flag.\n"));
+ prs_set_endian_data(ps, RPC_BIG_ENDIAN);
+ }
+
+ if(!prs_uint16("frag_len ", ps, depth, &rpc->frag_len))
+ return False;
+ if(!prs_uint16("auth_len ", ps, depth, &rpc->auth_len))
+ return False;
+ if(!prs_uint32("call_id ", ps, depth, &rpc->call_id))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an RPC_IFACE structure.
+********************************************************************/
+
+static bool smb_io_rpc_iface(const char *desc, RPC_IFACE *ifc, prs_struct *ps, int depth)
+{
+ if (ifc == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_iface");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_uuid( "uuid", &ifc->uuid, ps, depth))
+ return False;
+
+ if(!prs_uint32 ("version", ps, depth, &ifc->if_version))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an RPC_ADDR_STR structure.
+********************************************************************/
+
+static void init_rpc_addr_str(RPC_ADDR_STR *str, const char *name)
+{
+ str->len = strlen(name) + 1;
+ fstrcpy(str->str, name);
+}
+
+/*******************************************************************
+ Reads or writes an RPC_ADDR_STR structure.
+********************************************************************/
+
+static bool smb_io_rpc_addr_str(const char *desc, RPC_ADDR_STR *str, prs_struct *ps, int depth)
+{
+ if (str == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_addr_str");
+ depth++;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16 ( "len", ps, depth, &str->len))
+ return False;
+ if(!prs_uint8s (True, "str", ps, depth, (uchar*)str->str, MIN(str->len, sizeof(str->str)) ))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Inits an RPC_HDR_BBA structure.
+********************************************************************/
+
+static void init_rpc_hdr_bba(RPC_HDR_BBA *bba, uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid)
+{
+ bba->max_tsize = max_tsize; /* maximum transmission fragment size (0x1630) */
+ bba->max_rsize = max_rsize; /* max receive fragment size (0x1630) */
+ bba->assoc_gid = assoc_gid; /* associated group id (0x0) */
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR_BBA structure.
+********************************************************************/
+
+static bool smb_io_rpc_hdr_bba(const char *desc, RPC_HDR_BBA *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_bba");
+ depth++;
+
+ if(!prs_uint16("max_tsize", ps, depth, &rpc->max_tsize))
+ return False;
+ if(!prs_uint16("max_rsize", ps, depth, &rpc->max_rsize))
+ return False;
+ if(!prs_uint32("assoc_gid", ps, depth, &rpc->assoc_gid))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Inits an RPC_CONTEXT structure.
+ Note the transfer pointer must remain valid until this is marshalled.
+********************************************************************/
+
+void init_rpc_context(RPC_CONTEXT *rpc_ctx, uint16 context_id,
+ const RPC_IFACE *abstract, const RPC_IFACE *transfer)
+{
+ rpc_ctx->context_id = context_id ; /* presentation context identifier (0x0) */
+ rpc_ctx->num_transfer_syntaxes = 1 ; /* the number of syntaxes (has always been 1?)(0x1) */
+
+ /* num and vers. of interface client is using */
+ rpc_ctx->abstract = *abstract;
+
+ /* vers. of interface to use for replies */
+ rpc_ctx->transfer = CONST_DISCARD(RPC_IFACE *, transfer);
+}
+
+/*******************************************************************
+ Inits an RPC_HDR_RB structure.
+ Note the context pointer must remain valid until this is marshalled.
+********************************************************************/
+
+void init_rpc_hdr_rb(RPC_HDR_RB *rpc,
+ uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid,
+ RPC_CONTEXT *context)
+{
+ init_rpc_hdr_bba(&rpc->bba, max_tsize, max_rsize, assoc_gid);
+
+ rpc->num_contexts = 1;
+ rpc->rpc_context = context;
+}
+
+/*******************************************************************
+ Reads or writes an RPC_CONTEXT structure.
+********************************************************************/
+
+bool smb_io_rpc_context(const char *desc, RPC_CONTEXT *rpc_ctx, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (rpc_ctx == NULL)
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint16("context_id ", ps, depth, &rpc_ctx->context_id ))
+ return False;
+ if(!prs_uint8 ("num_transfer_syntaxes", ps, depth, &rpc_ctx->num_transfer_syntaxes))
+ return False;
+
+ /* num_transfer_syntaxes must not be zero. */
+ if (rpc_ctx->num_transfer_syntaxes == 0)
+ return False;
+
+ if(!smb_io_rpc_iface("", &rpc_ctx->abstract, ps, depth))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (!(rpc_ctx->transfer = PRS_ALLOC_MEM(ps, RPC_IFACE, rpc_ctx->num_transfer_syntaxes))) {
+ return False;
+ }
+ }
+
+ for (i = 0; i < rpc_ctx->num_transfer_syntaxes; i++ ) {
+ if (!smb_io_rpc_iface("", &rpc_ctx->transfer[i], ps, depth))
+ return False;
+ }
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR_RB structure.
+********************************************************************/
+
+bool smb_io_rpc_hdr_rb(const char *desc, RPC_HDR_RB *rpc, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (rpc == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_rb");
+ depth++;
+
+ if(!smb_io_rpc_hdr_bba("", &rpc->bba, ps, depth))
+ return False;
+
+ if(!prs_uint8("num_contexts", ps, depth, &rpc->num_contexts))
+ return False;
+
+ /* 3 pad bytes following - will be mopped up by the prs_align in smb_io_rpc_context(). */
+
+ /* num_contexts must not be zero. */
+ if (rpc->num_contexts == 0)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (!(rpc->rpc_context = PRS_ALLOC_MEM(ps, RPC_CONTEXT, rpc->num_contexts))) {
+ return False;
+ }
+ }
+
+ for (i = 0; i < rpc->num_contexts; i++ ) {
+ if (!smb_io_rpc_context("", &rpc->rpc_context[i], ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an RPC_RESULTS structure.
+
+ lkclXXXX only one reason at the moment!
+********************************************************************/
+
+static void init_rpc_results(RPC_RESULTS *res,
+ uint8 num_results, uint16 result, uint16 reason)
+{
+ res->num_results = num_results; /* the number of results (0x01) */
+ res->result = result ; /* result (0x00 = accept) */
+ res->reason = reason ; /* reason (0x00 = no reason specified) */
+}
+
+/*******************************************************************
+ Reads or writes an RPC_RESULTS structure.
+
+ lkclXXXX only one reason at the moment!
+********************************************************************/
+
+static bool smb_io_rpc_results(const char *desc, RPC_RESULTS *res, prs_struct *ps, int depth)
+{
+ if (res == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_results");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint8 ("num_results", ps, depth, &res->num_results))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16("result ", ps, depth, &res->result))
+ return False;
+ if(!prs_uint16("reason ", ps, depth, &res->reason))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Init an RPC_HDR_BA structure.
+
+ lkclXXXX only one reason at the moment!
+
+********************************************************************/
+
+void init_rpc_hdr_ba(RPC_HDR_BA *rpc,
+ uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid,
+ const char *pipe_addr,
+ uint8 num_results, uint16 result, uint16 reason,
+ RPC_IFACE *transfer)
+{
+ init_rpc_hdr_bba (&rpc->bba, max_tsize, max_rsize, assoc_gid);
+ init_rpc_addr_str(&rpc->addr, pipe_addr);
+ init_rpc_results (&rpc->res, num_results, result, reason);
+
+ /* the transfer syntax from the request */
+ memcpy(&rpc->transfer, transfer, sizeof(rpc->transfer));
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR_BA structure.
+********************************************************************/
+
+bool smb_io_rpc_hdr_ba(const char *desc, RPC_HDR_BA *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_ba");
+ depth++;
+
+ if(!smb_io_rpc_hdr_bba("", &rpc->bba, ps, depth))
+ return False;
+ if(!smb_io_rpc_addr_str("", &rpc->addr, ps, depth))
+ return False;
+ if(!smb_io_rpc_results("", &rpc->res, ps, depth))
+ return False;
+ if(!smb_io_rpc_iface("", &rpc->transfer, ps, depth))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Init an RPC_HDR_REQ structure.
+********************************************************************/
+
+void init_rpc_hdr_req(RPC_HDR_REQ *hdr, uint32 alloc_hint, uint16 opnum)
+{
+ hdr->alloc_hint = alloc_hint; /* allocation hint */
+ hdr->context_id = 0; /* presentation context identifier */
+ hdr->opnum = opnum; /* opnum */
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR_REQ structure.
+********************************************************************/
+
+bool smb_io_rpc_hdr_req(const char *desc, RPC_HDR_REQ *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_req");
+ depth++;
+
+ if(!prs_uint32("alloc_hint", ps, depth, &rpc->alloc_hint))
+ return False;
+ if(!prs_uint16("context_id", ps, depth, &rpc->context_id))
+ return False;
+ if(!prs_uint16("opnum ", ps, depth, &rpc->opnum))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR_RESP structure.
+********************************************************************/
+
+bool smb_io_rpc_hdr_resp(const char *desc, RPC_HDR_RESP *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_resp");
+ depth++;
+
+ if(!prs_uint32("alloc_hint", ps, depth, &rpc->alloc_hint))
+ return False;
+ if(!prs_uint16("context_id", ps, depth, &rpc->context_id))
+ return False;
+ if(!prs_uint8 ("cancel_ct ", ps, depth, &rpc->cancel_count))
+ return False;
+ if(!prs_uint8 ("reserved ", ps, depth, &rpc->reserved))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR_FAULT structure.
+********************************************************************/
+
+bool smb_io_rpc_hdr_fault(const char *desc, RPC_HDR_FAULT *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_fault");
+ depth++;
+
+ if(!prs_dcerpc_status("status ", ps, depth, &rpc->status))
+ return False;
+ if(!prs_uint32("reserved", ps, depth, &rpc->reserved))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an RPC_HDR_AUTH structure.
+********************************************************************/
+
+void init_rpc_hdr_auth(RPC_HDR_AUTH *rai,
+ uint8 auth_type, uint8 auth_level,
+ uint8 auth_pad_len,
+ uint32 auth_context_id)
+{
+ rai->auth_type = auth_type;
+ rai->auth_level = auth_level;
+ rai->auth_pad_len = auth_pad_len;
+ rai->auth_reserved = 0;
+ rai->auth_context_id = auth_context_id;
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR_AUTH structure.
+********************************************************************/
+
+bool smb_io_rpc_hdr_auth(const char *desc, RPC_HDR_AUTH *rai, prs_struct *ps, int depth)
+{
+ if (rai == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_auth");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint8 ("auth_type ", ps, depth, &rai->auth_type))
+ return False;
+ if(!prs_uint8 ("auth_level ", ps, depth, &rai->auth_level))
+ return False;
+ if(!prs_uint8 ("auth_pad_len ", ps, depth, &rai->auth_pad_len))
+ return False;
+ if(!prs_uint8 ("auth_reserved", ps, depth, &rai->auth_reserved))
+ return False;
+ if(!prs_uint32("auth_context_id", ps, depth, &rai->auth_context_id))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Checks an RPC_AUTH_VERIFIER structure.
+********************************************************************/
+
+bool rpc_auth_verifier_chk(RPC_AUTH_VERIFIER *rav,
+ const char *signature, uint32 msg_type)
+{
+ return (strequal(rav->signature, signature) && rav->msg_type == msg_type);
+}
+
+/*******************************************************************
+ Inits an RPC_AUTH_VERIFIER structure.
+********************************************************************/
+
+void init_rpc_auth_verifier(RPC_AUTH_VERIFIER *rav,
+ const char *signature, uint32 msg_type)
+{
+ fstrcpy(rav->signature, signature); /* "NTLMSSP" */
+ rav->msg_type = msg_type; /* NTLMSSP_MESSAGE_TYPE */
+}
+
+/*******************************************************************
+ Reads or writes an RPC_AUTH_VERIFIER structure.
+********************************************************************/
+
+bool smb_io_rpc_auth_verifier(const char *desc, RPC_AUTH_VERIFIER *rav, prs_struct *ps, int depth)
+{
+ if (rav == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_auth_verifier");
+ depth++;
+
+ /* "NTLMSSP" */
+ if(!prs_string("signature", ps, depth, rav->signature,
+ sizeof(rav->signature)))
+ return False;
+ if(!prs_uint32("msg_type ", ps, depth, &rav->msg_type)) /* NTLMSSP_MESSAGE_TYPE */
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ This parses an RPC_AUTH_VERIFIER for schannel. I think
+********************************************************************/
+
+bool smb_io_rpc_schannel_verifier(const char *desc, RPC_AUTH_VERIFIER *rav, prs_struct *ps, int depth)
+{
+ if (rav == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_schannel_verifier");
+ depth++;
+
+ if(!prs_string("signature", ps, depth, rav->signature, sizeof(rav->signature)))
+ return False;
+ if(!prs_uint32("msg_type ", ps, depth, &rav->msg_type))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+creates an RPC_AUTH_SCHANNEL_NEG structure.
+********************************************************************/
+
+void init_rpc_auth_schannel_neg(RPC_AUTH_SCHANNEL_NEG *neg,
+ const char *domain, const char *myname)
+{
+ neg->type1 = 0;
+ neg->type2 = 0x3;
+ fstrcpy(neg->domain, domain);
+ fstrcpy(neg->myname, myname);
+}
+
+/*******************************************************************
+ Reads or writes an RPC_AUTH_SCHANNEL_NEG structure.
+********************************************************************/
+
+bool smb_io_rpc_auth_schannel_neg(const char *desc, RPC_AUTH_SCHANNEL_NEG *neg,
+ prs_struct *ps, int depth)
+{
+ if (neg == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_auth_schannel_neg");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("type1", ps, depth, &neg->type1))
+ return False;
+ if(!prs_uint32("type2", ps, depth, &neg->type2))
+ return False;
+ if(!prs_string("domain ", ps, depth, neg->domain, sizeof(neg->domain)))
+ return False;
+ if(!prs_string("myname ", ps, depth, neg->myname, sizeof(neg->myname)))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an RPC_AUTH_SCHANNEL_CHK structure.
+********************************************************************/
+
+bool smb_io_rpc_auth_schannel_chk(const char *desc, int auth_len,
+ RPC_AUTH_SCHANNEL_CHK * chk,
+ prs_struct *ps, int depth)
+{
+ if (chk == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_auth_schannel_chk");
+ depth++;
+
+ if ( !prs_uint8s(False, "sig ", ps, depth, chk->sig, sizeof(chk->sig)) )
+ return False;
+
+ if ( !prs_uint8s(False, "seq_num", ps, depth, chk->seq_num, sizeof(chk->seq_num)) )
+ return False;
+
+ if ( !prs_uint8s(False, "packet_digest", ps, depth, chk->packet_digest, sizeof(chk->packet_digest)) )
+ return False;
+
+ if ( auth_len == RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN ) {
+ if ( !prs_uint8s(False, "confounder", ps, depth, chk->confounder, sizeof(chk->confounder)) )
+ return False;
+ }
+
+ return True;
+}
+
+const struct ndr_syntax_id syntax_spoolss = {
+ {
+ 0x12345678, 0x1234, 0xabcd,
+ { 0xef, 0x00 },
+ { 0x01, 0x23,
+ 0x45, 0x67, 0x89, 0xab }
+ }, 0x01
+};
+
diff --git a/source3/rpc_parse/parse_sec.c b/source3/rpc_parse/parse_sec.c
new file mode 100644
index 0000000000..c71b31086a
--- /dev/null
+++ b/source3/rpc_parse/parse_sec.c
@@ -0,0 +1,436 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Jeremy R. Allison 1995-2005.
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_PARSE
+
+/*******************************************************************
+ Reads or writes a SEC_ACE structure.
+********************************************************************/
+
+static bool sec_io_ace(const char *desc, SEC_ACE *psa, prs_struct *ps,
+ int depth)
+{
+ uint32 old_offset;
+ uint32 offset_ace_size;
+ uint8 type;
+
+ if (psa == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sec_io_ace");
+ depth++;
+
+ old_offset = prs_offset(ps);
+
+ if (MARSHALLING(ps)) {
+ type = (uint8)psa->type;
+ }
+
+ if(!prs_uint8("type ", ps, depth, &type))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ psa->type = (enum security_ace_type)type;
+ }
+
+ if(!prs_uint8("flags", ps, depth, &psa->flags))
+ return False;
+
+ if(!prs_uint16_pre("size ", ps, depth, &psa->size, &offset_ace_size))
+ return False;
+
+ if(!prs_uint32("access_mask", ps, depth, &psa->access_mask))
+ return False;
+
+ /* check whether object access is present */
+ if (!sec_ace_object(psa->type)) {
+ if (!smb_io_dom_sid("trustee ", &psa->trustee , ps, depth))
+ return False;
+ } else {
+ if (!prs_uint32("obj_flags", ps, depth, &psa->object.object.flags))
+ return False;
+
+ if (psa->object.object.flags & SEC_ACE_OBJECT_PRESENT)
+ if (!smb_io_uuid("obj_guid", &psa->object.object.type.type, ps,depth))
+ return False;
+
+ if (psa->object.object.flags & SEC_ACE_OBJECT_INHERITED_PRESENT)
+ if (!smb_io_uuid("inh_guid", &psa->object.object.inherited_type.inherited_type, ps,depth))
+ return False;
+
+ if(!smb_io_dom_sid("trustee ", &psa->trustee , ps, depth))
+ return False;
+ }
+
+ /* Theorectically an ACE can have a size greater than the
+ sum of its components. When marshalling, pad with extra null bytes up to the
+ correct size. */
+
+ if (MARSHALLING(ps) && (psa->size > prs_offset(ps) - old_offset)) {
+ uint32 extra_len = psa->size - (prs_offset(ps) - old_offset);
+ uint32 i;
+ uint8 c = 0;
+
+ for (i = 0; i < extra_len; i++) {
+ if (!prs_uint8("ace extra space", ps, depth, &c))
+ return False;
+ }
+ }
+
+ if(!prs_uint16_post("size ", ps, depth, &psa->size, offset_ace_size, old_offset))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a SEC_ACL structure.
+
+ First of the xx_io_xx functions that allocates its data structures
+ for you as it reads them.
+********************************************************************/
+
+static bool sec_io_acl(const char *desc, SEC_ACL **ppsa, prs_struct *ps,
+ int depth)
+{
+ unsigned int i;
+ uint32 old_offset;
+ uint32 offset_acl_size;
+ SEC_ACL *psa;
+ uint16 revision;
+
+ /*
+ * Note that the size is always a multiple of 4 bytes due to the
+ * nature of the data structure. Therefore the prs_align() calls
+ * have been removed as they through us off when doing two-layer
+ * marshalling such as in the printing code (RPC_BUFFER). --jerry
+ */
+
+ if (ppsa == NULL)
+ return False;
+
+ psa = *ppsa;
+
+ if(UNMARSHALLING(ps) && psa == NULL) {
+ /*
+ * This is a read and we must allocate the stuct to read into.
+ */
+ if((psa = PRS_ALLOC_MEM(ps, SEC_ACL, 1)) == NULL)
+ return False;
+ *ppsa = psa;
+ }
+
+ prs_debug(ps, depth, desc, "sec_io_acl");
+ depth++;
+
+ old_offset = prs_offset(ps);
+
+ if (MARSHALLING(ps)) {
+ revision = (uint16)psa->revision;
+ }
+
+ if(!prs_uint16("revision", ps, depth, &revision))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ psa->revision = (enum security_acl_revision)revision;
+ }
+
+ if(!prs_uint16_pre("size ", ps, depth, &psa->size, &offset_acl_size))
+ return False;
+
+ if(!prs_uint32("num_aces ", ps, depth, &psa->num_aces))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (psa->num_aces) {
+ if((psa->aces = PRS_ALLOC_MEM(ps, SEC_ACE, psa->num_aces)) == NULL)
+ return False;
+ } else {
+ psa->aces = NULL;
+ }
+ }
+
+ for (i = 0; i < psa->num_aces; i++) {
+ fstring tmp;
+ slprintf(tmp, sizeof(tmp)-1, "ace_list[%02d]: ", i);
+ if(!sec_io_ace(tmp, &psa->aces[i], ps, depth))
+ return False;
+ }
+
+ /* Theorectically an ACL can have a size greater than the
+ sum of its components. When marshalling, pad with extra null bytes up to the
+ correct size. */
+
+ if (MARSHALLING(ps) && (psa->size > prs_offset(ps) - old_offset)) {
+ uint32 extra_len = psa->size - (prs_offset(ps) - old_offset);
+ uint8 c = 0;
+
+ for (i = 0; i < extra_len; i++) {
+ if (!prs_uint8("acl extra space", ps, depth, &c))
+ return False;
+ }
+ }
+
+ if(!prs_uint16_post("size ", ps, depth, &psa->size, offset_acl_size, old_offset))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a SEC_DESC structure.
+ If reading and the *ppsd = NULL, allocates the structure.
+********************************************************************/
+
+bool sec_io_desc(const char *desc, SEC_DESC **ppsd, prs_struct *ps, int depth)
+{
+ uint32 old_offset;
+ uint32 max_offset = 0; /* after we're done, move offset to end */
+ uint32 tmp_offset = 0;
+ uint32 off_sacl, off_dacl, off_owner_sid, off_grp_sid;
+ uint16 revision;
+
+ SEC_DESC *psd;
+
+ if (ppsd == NULL)
+ return False;
+
+ psd = *ppsd;
+
+ if (psd == NULL) {
+ if(UNMARSHALLING(ps)) {
+ if((psd = PRS_ALLOC_MEM(ps,SEC_DESC,1)) == NULL)
+ return False;
+ *ppsd = psd;
+ } else {
+ /* Marshalling - just ignore. */
+ return True;
+ }
+ }
+
+ prs_debug(ps, depth, desc, "sec_io_desc");
+ depth++;
+
+ /* start of security descriptor stored for back-calc offset purposes */
+ old_offset = prs_offset(ps);
+
+ if (MARSHALLING(ps)) {
+ revision = (uint16)psd->revision;
+ }
+
+ if(!prs_uint16("revision", ps, depth, &revision))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ psd->revision = (enum security_descriptor_revision)revision;
+ }
+
+ if(!prs_uint16("type ", ps, depth, &psd->type))
+ return False;
+
+ if (MARSHALLING(ps)) {
+ uint32 offset = SEC_DESC_HEADER_SIZE;
+
+ /*
+ * Work out the offsets here, as we write it out.
+ */
+
+ if (psd->sacl != NULL) {
+ off_sacl = offset;
+ offset += psd->sacl->size;
+ } else {
+ off_sacl = 0;
+ }
+
+ if (psd->dacl != NULL) {
+ off_dacl = offset;
+ offset += psd->dacl->size;
+ } else {
+ off_dacl = 0;
+ }
+
+ if (psd->owner_sid != NULL) {
+ off_owner_sid = offset;
+ offset += ndr_size_dom_sid(psd->owner_sid, 0);
+ } else {
+ off_owner_sid = 0;
+ }
+
+ if (psd->group_sid != NULL) {
+ off_grp_sid = offset;
+ offset += ndr_size_dom_sid(psd->group_sid, 0);
+ } else {
+ off_grp_sid = 0;
+ }
+ }
+
+ if(!prs_uint32("off_owner_sid", ps, depth, &off_owner_sid))
+ return False;
+
+ if(!prs_uint32("off_grp_sid ", ps, depth, &off_grp_sid))
+ return False;
+
+ if(!prs_uint32("off_sacl ", ps, depth, &off_sacl))
+ return False;
+
+ if(!prs_uint32("off_dacl ", ps, depth, &off_dacl))
+ return False;
+
+ max_offset = MAX(max_offset, prs_offset(ps));
+
+ if (off_owner_sid != 0) {
+
+ tmp_offset = prs_offset(ps);
+ if(!prs_set_offset(ps, old_offset + off_owner_sid))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ /* reading */
+ if((psd->owner_sid = PRS_ALLOC_MEM(ps,DOM_SID,1)) == NULL)
+ return False;
+ }
+
+ if(!smb_io_dom_sid("owner_sid ", psd->owner_sid , ps, depth))
+ return False;
+
+ max_offset = MAX(max_offset, prs_offset(ps));
+
+ if (!prs_set_offset(ps,tmp_offset))
+ return False;
+ }
+
+ if (psd->group_sid != 0) {
+
+ tmp_offset = prs_offset(ps);
+ if(!prs_set_offset(ps, old_offset + off_grp_sid))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ /* reading */
+ if((psd->group_sid = PRS_ALLOC_MEM(ps,DOM_SID,1)) == NULL)
+ return False;
+ }
+
+ if(!smb_io_dom_sid("grp_sid", psd->group_sid, ps, depth))
+ return False;
+
+ max_offset = MAX(max_offset, prs_offset(ps));
+
+ if (!prs_set_offset(ps,tmp_offset))
+ return False;
+ }
+
+ if ((psd->type & SEC_DESC_SACL_PRESENT) && off_sacl) {
+ tmp_offset = prs_offset(ps);
+ if(!prs_set_offset(ps, old_offset + off_sacl))
+ return False;
+ if(!sec_io_acl("sacl", &psd->sacl, ps, depth))
+ return False;
+ max_offset = MAX(max_offset, prs_offset(ps));
+ if (!prs_set_offset(ps,tmp_offset))
+ return False;
+ }
+
+ if ((psd->type & SEC_DESC_DACL_PRESENT) && off_dacl != 0) {
+ tmp_offset = prs_offset(ps);
+ if(!prs_set_offset(ps, old_offset + off_dacl))
+ return False;
+ if(!sec_io_acl("dacl", &psd->dacl, ps, depth))
+ return False;
+ max_offset = MAX(max_offset, prs_offset(ps));
+ if (!prs_set_offset(ps,tmp_offset))
+ return False;
+ }
+
+ if(!prs_set_offset(ps, max_offset))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a SEC_DESC_BUF structure.
+********************************************************************/
+
+bool sec_io_desc_buf(const char *desc, SEC_DESC_BUF **ppsdb, prs_struct *ps, int depth)
+{
+ uint32 off_len;
+ uint32 off_max_len;
+ uint32 old_offset;
+ uint32 size;
+ uint32 len;
+ SEC_DESC_BUF *psdb;
+ uint32 ptr;
+
+ if (ppsdb == NULL)
+ return False;
+
+ psdb = *ppsdb;
+
+ if (UNMARSHALLING(ps) && psdb == NULL) {
+ if((psdb = PRS_ALLOC_MEM(ps,SEC_DESC_BUF,1)) == NULL)
+ return False;
+ *ppsdb = psdb;
+ }
+
+ prs_debug(ps, depth, desc, "sec_io_desc_buf");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32_pre("max_len", ps, depth, &psdb->sd_size, &off_max_len))
+ return False;
+
+ ptr = 1;
+ if(!prs_uint32 ("ptr ", ps, depth, &ptr))
+ return False;
+
+ len = ndr_size_security_descriptor(psdb->sd, 0);
+ if(!prs_uint32_pre("len ", ps, depth, &len, &off_len))
+ return False;
+
+ old_offset = prs_offset(ps);
+
+ /* reading, length is non-zero; writing, descriptor is non-NULL */
+ if ((UNMARSHALLING(ps) && psdb->sd_size != 0) || (MARSHALLING(ps) && psdb->sd != NULL)) {
+ if(!sec_io_desc("sec ", &psdb->sd, ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ size = prs_offset(ps) - old_offset;
+ if(!prs_uint32_post("max_len", ps, depth, &psdb->sd_size, off_max_len, size == 0 ? psdb->sd_size : size))
+ return False;
+
+ if(!prs_uint32_post("len ", ps, depth, &len, off_len, size))
+ return False;
+
+ return True;
+}
diff --git a/source3/rpc_parse/parse_spoolss.c b/source3/rpc_parse/parse_spoolss.c
new file mode 100644
index 0000000000..78a80a019b
--- /dev/null
+++ b/source3/rpc_parse/parse_spoolss.c
@@ -0,0 +1,7726 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ * Copyright (C) Jean François Micouleau 1998-2000,
+ * Copyright (C) Gerald Carter 2000-2002,
+ * Copyright (C) Tim Potter 2001-2002.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_PARSE
+
+
+/*******************************************************************
+This should be moved in a more generic lib.
+********************************************************************/
+
+bool spoolss_io_system_time(const char *desc, prs_struct *ps, int depth, SYSTEMTIME *systime)
+{
+ if(!prs_uint16("year", ps, depth, &systime->year))
+ return False;
+ if(!prs_uint16("month", ps, depth, &systime->month))
+ return False;
+ if(!prs_uint16("dayofweek", ps, depth, &systime->dayofweek))
+ return False;
+ if(!prs_uint16("day", ps, depth, &systime->day))
+ return False;
+ if(!prs_uint16("hour", ps, depth, &systime->hour))
+ return False;
+ if(!prs_uint16("minute", ps, depth, &systime->minute))
+ return False;
+ if(!prs_uint16("second", ps, depth, &systime->second))
+ return False;
+ if(!prs_uint16("milliseconds", ps, depth, &systime->milliseconds))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool make_systemtime(SYSTEMTIME *systime, struct tm *unixtime)
+{
+ systime->year=unixtime->tm_year+1900;
+ systime->month=unixtime->tm_mon+1;
+ systime->dayofweek=unixtime->tm_wday;
+ systime->day=unixtime->tm_mday;
+ systime->hour=unixtime->tm_hour;
+ systime->minute=unixtime->tm_min;
+ systime->second=unixtime->tm_sec;
+ systime->milliseconds=0;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an DOC_INFO structure.
+********************************************************************/
+
+static bool smb_io_doc_info_1(const char *desc, DOC_INFO_1 *info_1, prs_struct *ps, int depth)
+{
+ if (info_1 == NULL) return False;
+
+ prs_debug(ps, depth, desc, "smb_io_doc_info_1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("p_docname", ps, depth, &info_1->p_docname))
+ return False;
+ if(!prs_uint32("p_outputfile", ps, depth, &info_1->p_outputfile))
+ return False;
+ if(!prs_uint32("p_datatype", ps, depth, &info_1->p_datatype))
+ return False;
+
+ if(!smb_io_unistr2("", &info_1->docname, info_1->p_docname, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &info_1->outputfile, info_1->p_outputfile, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &info_1->datatype, info_1->p_datatype, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an DOC_INFO structure.
+********************************************************************/
+
+static bool smb_io_doc_info(const char *desc, DOC_INFO *info, prs_struct *ps, int depth)
+{
+ uint32 useless_ptr=0;
+
+ if (info == NULL) return False;
+
+ prs_debug(ps, depth, desc, "smb_io_doc_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("switch_value", ps, depth, &info->switch_value))
+ return False;
+
+ if(!prs_uint32("doc_info_X ptr", ps, depth, &useless_ptr))
+ return False;
+
+ switch (info->switch_value)
+ {
+ case 1:
+ if(!smb_io_doc_info_1("",&info->doc_info_1, ps, depth))
+ return False;
+ break;
+ case 2:
+ /*
+ this is just a placeholder
+
+ MSDN July 1998 says doc_info_2 is only on
+ Windows 95, and as Win95 doesn't do RPC to print
+ this case is nearly impossible
+
+ Maybe one day with Windows for dishwasher 2037 ...
+
+ */
+ /* smb_io_doc_info_2("",&info->doc_info_2, ps, depth); */
+ break;
+ default:
+ DEBUG(0,("Something is obviously wrong somewhere !\n"));
+ break;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an DOC_INFO_CONTAINER structure.
+********************************************************************/
+
+static bool smb_io_doc_info_container(const char *desc, DOC_INFO_CONTAINER *cont, prs_struct *ps, int depth)
+{
+ if (cont == NULL) return False;
+
+ prs_debug(ps, depth, desc, "smb_io_doc_info_container");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("level", ps, depth, &cont->level))
+ return False;
+
+ if(!smb_io_doc_info("",&cont->docinfo, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an NOTIFY OPTION TYPE structure.
+********************************************************************/
+
+/* NOTIFY_OPTION_TYPE and NOTIFY_OPTION_TYPE_DATA are really one
+ structure. The _TYPE structure is really the deferred referrants (i.e
+ the notify fields array) of the _TYPE structure. -tpot */
+
+static bool smb_io_notify_option_type(const char *desc, SPOOL_NOTIFY_OPTION_TYPE *type, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "smb_io_notify_option_type");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!prs_uint16("type", ps, depth, &type->type))
+ return False;
+ if(!prs_uint16("reserved0", ps, depth, &type->reserved0))
+ return False;
+ if(!prs_uint32("reserved1", ps, depth, &type->reserved1))
+ return False;
+ if(!prs_uint32("reserved2", ps, depth, &type->reserved2))
+ return False;
+ if(!prs_uint32("count", ps, depth, &type->count))
+ return False;
+ if(!prs_uint32("fields_ptr", ps, depth, &type->fields_ptr))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an NOTIFY OPTION TYPE DATA.
+********************************************************************/
+
+static bool smb_io_notify_option_type_data(const char *desc, SPOOL_NOTIFY_OPTION_TYPE *type, prs_struct *ps, int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "smb_io_notify_option_type_data");
+ depth++;
+
+ /* if there are no fields just return */
+ if (type->fields_ptr==0)
+ return True;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("count2", ps, depth, &type->count2))
+ return False;
+
+ if (type->count2 != type->count)
+ DEBUG(4,("What a mess, count was %x now is %x !\n", type->count, type->count2));
+
+ if (type->count2 > MAX_NOTIFY_TYPE_FOR_NOW) {
+ return False;
+ }
+
+ /* parse the option type data */
+ for(i=0;i<type->count2;i++)
+ if(!prs_uint16("fields",ps,depth,&type->fields[i]))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+reads or writes an NOTIFY OPTION structure.
+********************************************************************/
+
+static bool smb_io_notify_option_type_ctr(const char *desc, SPOOL_NOTIFY_OPTION_TYPE_CTR *ctr , prs_struct *ps, int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "smb_io_notify_option_type_ctr");
+ depth++;
+
+ if(!prs_uint32("count", ps, depth, &ctr->count))
+ return False;
+
+ /* reading */
+ if (UNMARSHALLING(ps) && ctr->count)
+ if((ctr->type=PRS_ALLOC_MEM(ps,SPOOL_NOTIFY_OPTION_TYPE,ctr->count)) == NULL)
+ return False;
+
+ /* the option type struct */
+ for(i=0;i<ctr->count;i++)
+ if(!smb_io_notify_option_type("", &ctr->type[i] , ps, depth))
+ return False;
+
+ /* the type associated with the option type struct */
+ for(i=0;i<ctr->count;i++)
+ if(!smb_io_notify_option_type_data("", &ctr->type[i] , ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an NOTIFY OPTION structure.
+********************************************************************/
+
+static bool smb_io_notify_option(const char *desc, SPOOL_NOTIFY_OPTION *option, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "smb_io_notify_option");
+ depth++;
+
+ if(!prs_uint32("version", ps, depth, &option->version))
+ return False;
+ if(!prs_uint32("flags", ps, depth, &option->flags))
+ return False;
+ if(!prs_uint32("count", ps, depth, &option->count))
+ return False;
+ if(!prs_uint32("option_type_ptr", ps, depth, &option->option_type_ptr))
+ return False;
+
+ /* marshalling or unmarshalling, that would work */
+ if (option->option_type_ptr!=0) {
+ if(!smb_io_notify_option_type_ctr("", &option->ctr ,ps, depth))
+ return False;
+ }
+ else {
+ option->ctr.type=NULL;
+ option->ctr.count=0;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an NOTIFY INFO DATA structure.
+********************************************************************/
+
+static bool smb_io_notify_info_data(const char *desc,SPOOL_NOTIFY_INFO_DATA *data, prs_struct *ps, int depth)
+{
+ uint32 useless_ptr=0x0FF0ADDE;
+
+ prs_debug(ps, depth, desc, "smb_io_notify_info_data");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint16("type", ps, depth, &data->type))
+ return False;
+ if(!prs_uint16("field", ps, depth, &data->field))
+ return False;
+
+ if(!prs_uint32("how many words", ps, depth, &data->size))
+ return False;
+ if(!prs_uint32("id", ps, depth, &data->id))
+ return False;
+ if(!prs_uint32("how many words", ps, depth, &data->size))
+ return False;
+
+ switch (data->enc_type) {
+
+ /* One and two value data has two uint32 values */
+
+ case NOTIFY_ONE_VALUE:
+ case NOTIFY_TWO_VALUE:
+
+ if(!prs_uint32("value[0]", ps, depth, &data->notify_data.value[0]))
+ return False;
+ if(!prs_uint32("value[1]", ps, depth, &data->notify_data.value[1]))
+ return False;
+ break;
+
+ /* Pointers and strings have a string length and a
+ pointer. For a string the length is expressed as
+ the number of uint16 characters plus a trailing
+ \0\0. */
+
+ case NOTIFY_POINTER:
+
+ if(!prs_uint32("string length", ps, depth, &data->notify_data.data.length ))
+ return False;
+ if(!prs_uint32("pointer", ps, depth, &useless_ptr))
+ return False;
+
+ break;
+
+ case NOTIFY_STRING:
+
+ if(!prs_uint32("string length", ps, depth, &data->notify_data.data.length))
+ return False;
+
+ if(!prs_uint32("pointer", ps, depth, &useless_ptr))
+ return False;
+
+ break;
+
+ case NOTIFY_SECDESC:
+ if( !prs_uint32( "sd size", ps, depth, &data->notify_data.sd.size ) )
+ return False;
+ if( !prs_uint32( "pointer", ps, depth, &useless_ptr ) )
+ return False;
+
+ break;
+
+ default:
+ DEBUG(3, ("invalid enc_type %d for smb_io_notify_info_data\n",
+ data->enc_type));
+ break;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an NOTIFY INFO DATA structure.
+********************************************************************/
+
+bool smb_io_notify_info_data_strings(const char *desc,SPOOL_NOTIFY_INFO_DATA *data,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "smb_io_notify_info_data_strings");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ switch(data->enc_type) {
+
+ /* No data for values */
+
+ case NOTIFY_ONE_VALUE:
+ case NOTIFY_TWO_VALUE:
+
+ break;
+
+ /* Strings start with a length in uint16s */
+
+ case NOTIFY_STRING:
+
+ if (MARSHALLING(ps))
+ data->notify_data.data.length /= 2;
+
+ if(!prs_uint32("string length", ps, depth, &data->notify_data.data.length))
+ return False;
+
+ if (UNMARSHALLING(ps) && data->notify_data.data.length) {
+ data->notify_data.data.string = PRS_ALLOC_MEM(ps, uint16,
+ data->notify_data.data.length);
+
+ if (!data->notify_data.data.string)
+ return False;
+ }
+
+ if (!prs_uint16uni(True, "string", ps, depth, data->notify_data.data.string,
+ data->notify_data.data.length))
+ return False;
+
+ if (MARSHALLING(ps))
+ data->notify_data.data.length *= 2;
+
+ break;
+
+ case NOTIFY_POINTER:
+
+ if (UNMARSHALLING(ps) && data->notify_data.data.length) {
+ data->notify_data.data.string = PRS_ALLOC_MEM(ps, uint16,
+ data->notify_data.data.length);
+
+ if (!data->notify_data.data.string)
+ return False;
+ }
+
+ if(!prs_uint8s(True,"buffer",ps,depth,(uint8*)data->notify_data.data.string,data->notify_data.data.length))
+ return False;
+
+ break;
+
+ case NOTIFY_SECDESC:
+ if( !prs_uint32("secdesc size ", ps, depth, &data->notify_data.sd.size ) )
+ return False;
+ if ( !sec_io_desc( "sec_desc", &data->notify_data.sd.desc, ps, depth ) )
+ return False;
+ break;
+
+ default:
+ DEBUG(3, ("invalid enc_type %d for smb_io_notify_info_data_strings\n",
+ data->enc_type));
+ break;
+ }
+
+#if 0
+ if (isvalue==False) {
+
+ /* length of string in unicode include \0 */
+ x=data->notify_data.data.length+1;
+
+ if (data->field != 16)
+ if(!prs_uint32("string length", ps, depth, &x ))
+ return False;
+
+ if (MARSHALLING(ps)) {
+ /* These are already in little endian format. Don't byte swap. */
+ if (x == 1) {
+
+ /* No memory allocated for this string
+ therefore following the data.string
+ pointer is a bad idea. Use a pointer to
+ the uint32 length union member to
+ provide a source for a unicode NULL */
+
+ if(!prs_uint8s(True,"string",ps,depth, (uint8 *)&data->notify_data.data.length,x*2))
+ return False;
+ } else {
+
+ if (data->field == 16)
+ x /= 2;
+
+ if(!prs_uint16uni(True,"string",ps,depth,data->notify_data.data.string,x))
+ return False;
+ }
+ } else {
+
+ /* Tallocate memory for string */
+
+ if (x) {
+ data->notify_data.data.string = PRS_ALLOC_MEM(ps, uint16, x * 2);
+ if (!data->notify_data.data.string)
+ return False;
+ } else {
+ data->notify_data.data.string = NULL;
+ }
+
+ if(!prs_uint16uni(True,"string",ps,depth,data->notify_data.data.string,x))
+ return False;
+ }
+ }
+
+#endif
+
+#if 0 /* JERRY */
+ /* Win2k does not seem to put this parse align here */
+ if(!prs_align(ps))
+ return False;
+#endif
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an NOTIFY INFO structure.
+********************************************************************/
+
+static bool smb_io_notify_info(const char *desc, SPOOL_NOTIFY_INFO *info, prs_struct *ps, int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "smb_io_notify_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("count", ps, depth, &info->count))
+ return False;
+ if(!prs_uint32("version", ps, depth, &info->version))
+ return False;
+ if(!prs_uint32("flags", ps, depth, &info->flags))
+ return False;
+ if(!prs_uint32("count", ps, depth, &info->count))
+ return False;
+
+ for (i=0;i<info->count;i++) {
+ if(!smb_io_notify_info_data(desc, &info->data[i], ps, depth))
+ return False;
+ }
+
+ /* now do the strings at the end of the stream */
+ for (i=0;i<info->count;i++) {
+ if(!smb_io_notify_info_data_strings(desc, &info->data[i], ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spool_io_user_level_1( const char *desc, prs_struct *ps, int depth, SPOOL_USER_1 *q_u )
+{
+ prs_debug(ps, depth, desc, "");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("size", ps, depth, &q_u->size))
+ return False;
+
+ if (!prs_io_unistr2_p("", ps, depth, &q_u->client_name))
+ return False;
+ if (!prs_io_unistr2_p("", ps, depth, &q_u->user_name))
+ return False;
+
+ if (!prs_uint32("build", ps, depth, &q_u->build))
+ return False;
+ if (!prs_uint32("major", ps, depth, &q_u->major))
+ return False;
+ if (!prs_uint32("minor", ps, depth, &q_u->minor))
+ return False;
+ if (!prs_uint32("processor", ps, depth, &q_u->processor))
+ return False;
+
+ if (!prs_io_unistr2("", ps, depth, q_u->client_name))
+ return False;
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_io_unistr2("", ps, depth, q_u->user_name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static bool spool_io_user_level(const char *desc, SPOOL_USER_CTR *q_u, prs_struct *ps, int depth)
+{
+ if (q_u==NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spool_io_user_level");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ switch ( q_u->level )
+ {
+ case 1:
+ if ( !prs_pointer( "" , ps, depth, (void*)&q_u->user.user1,
+ sizeof(SPOOL_USER_1), (PRS_POINTER_CAST)spool_io_user_level_1 ))
+ {
+ return False;
+ }
+ break;
+ default:
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ * read or write a DEVICEMODE struct.
+ * on reading allocate memory for the private member
+ ********************************************************************/
+
+#define DM_NUM_OPTIONAL_FIELDS 8
+
+bool spoolss_io_devmode(const char *desc, prs_struct *ps, int depth, DEVICEMODE *devmode)
+{
+ int available_space; /* size of the device mode left to parse */
+ /* only important on unmarshalling */
+ int i = 0;
+ uint16 *unistr_buffer;
+ int j;
+
+ struct optional_fields {
+ fstring name;
+ uint32* field;
+ } opt_fields[DM_NUM_OPTIONAL_FIELDS] = {
+ { "icmmethod", NULL },
+ { "icmintent", NULL },
+ { "mediatype", NULL },
+ { "dithertype", NULL },
+ { "reserved1", NULL },
+ { "reserved2", NULL },
+ { "panningwidth", NULL },
+ { "panningheight", NULL }
+ };
+
+ /* assign at run time to keep non-gcc compilers happy */
+
+ opt_fields[0].field = &devmode->icmmethod;
+ opt_fields[1].field = &devmode->icmintent;
+ opt_fields[2].field = &devmode->mediatype;
+ opt_fields[3].field = &devmode->dithertype;
+ opt_fields[4].field = &devmode->reserved1;
+ opt_fields[5].field = &devmode->reserved2;
+ opt_fields[6].field = &devmode->panningwidth;
+ opt_fields[7].field = &devmode->panningheight;
+
+
+ prs_debug(ps, depth, desc, "spoolss_io_devmode");
+ depth++;
+
+ if (UNMARSHALLING(ps)) {
+ devmode->devicename.buffer = PRS_ALLOC_MEM(ps, uint16, MAXDEVICENAME);
+ if (devmode->devicename.buffer == NULL)
+ return False;
+ unistr_buffer = devmode->devicename.buffer;
+ }
+ else {
+ /* devicename is a static sized string but the buffer we set is not */
+ unistr_buffer = PRS_ALLOC_MEM(ps, uint16, MAXDEVICENAME);
+ memset( unistr_buffer, 0x0, MAXDEVICENAME );
+ for ( j=0; devmode->devicename.buffer[j]; j++ )
+ unistr_buffer[j] = devmode->devicename.buffer[j];
+ }
+
+ if (!prs_uint16uni(True,"devicename", ps, depth, unistr_buffer, MAXDEVICENAME))
+ return False;
+
+ if (!prs_uint16("specversion", ps, depth, &devmode->specversion))
+ return False;
+
+ if (!prs_uint16("driverversion", ps, depth, &devmode->driverversion))
+ return False;
+ if (!prs_uint16("size", ps, depth, &devmode->size))
+ return False;
+ if (!prs_uint16("driverextra", ps, depth, &devmode->driverextra))
+ return False;
+ if (!prs_uint32("fields", ps, depth, &devmode->fields))
+ return False;
+ if (!prs_uint16("orientation", ps, depth, &devmode->orientation))
+ return False;
+ if (!prs_uint16("papersize", ps, depth, &devmode->papersize))
+ return False;
+ if (!prs_uint16("paperlength", ps, depth, &devmode->paperlength))
+ return False;
+ if (!prs_uint16("paperwidth", ps, depth, &devmode->paperwidth))
+ return False;
+ if (!prs_uint16("scale", ps, depth, &devmode->scale))
+ return False;
+ if (!prs_uint16("copies", ps, depth, &devmode->copies))
+ return False;
+ if (!prs_uint16("defaultsource", ps, depth, &devmode->defaultsource))
+ return False;
+ if (!prs_uint16("printquality", ps, depth, &devmode->printquality))
+ return False;
+ if (!prs_uint16("color", ps, depth, &devmode->color))
+ return False;
+ if (!prs_uint16("duplex", ps, depth, &devmode->duplex))
+ return False;
+ if (!prs_uint16("yresolution", ps, depth, &devmode->yresolution))
+ return False;
+ if (!prs_uint16("ttoption", ps, depth, &devmode->ttoption))
+ return False;
+ if (!prs_uint16("collate", ps, depth, &devmode->collate))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ devmode->formname.buffer = PRS_ALLOC_MEM(ps, uint16, MAXDEVICENAME);
+ if (devmode->formname.buffer == NULL)
+ return False;
+ unistr_buffer = devmode->formname.buffer;
+ }
+ else {
+ /* devicename is a static sized string but the buffer we set is not */
+ unistr_buffer = PRS_ALLOC_MEM(ps, uint16, MAXDEVICENAME);
+ memset( unistr_buffer, 0x0, MAXDEVICENAME );
+ for ( j=0; devmode->formname.buffer[j]; j++ )
+ unistr_buffer[j] = devmode->formname.buffer[j];
+ }
+
+ if (!prs_uint16uni(True, "formname", ps, depth, unistr_buffer, MAXDEVICENAME))
+ return False;
+ if (!prs_uint16("logpixels", ps, depth, &devmode->logpixels))
+ return False;
+ if (!prs_uint32("bitsperpel", ps, depth, &devmode->bitsperpel))
+ return False;
+ if (!prs_uint32("pelswidth", ps, depth, &devmode->pelswidth))
+ return False;
+ if (!prs_uint32("pelsheight", ps, depth, &devmode->pelsheight))
+ return False;
+ if (!prs_uint32("displayflags", ps, depth, &devmode->displayflags))
+ return False;
+ if (!prs_uint32("displayfrequency", ps, depth, &devmode->displayfrequency))
+ return False;
+ /*
+ * every device mode I've ever seen on the wire at least has up
+ * to the displayfrequency field. --jerry (05-09-2002)
+ */
+
+ /* add uint32's + uint16's + two UNICODE strings */
+
+ available_space = devmode->size - (sizeof(uint32)*6 + sizeof(uint16)*18 + sizeof(uint16)*64);
+
+ /* Sanity check - we only have uint32's left tp parse */
+
+ if ( available_space && ((available_space % sizeof(uint32)) != 0) ) {
+ DEBUG(0,("spoolss_io_devmode: available_space [%d] no in multiple of 4 bytes (size = %d)!\n",
+ available_space, devmode->size));
+ DEBUG(0,("spoolss_io_devmode: please report to samba-technical@samba.org!\n"));
+ return False;
+ }
+
+ /*
+ * Conditional parsing. Assume that the DeviceMode has been
+ * zero'd by the caller.
+ */
+
+ while ((available_space > 0) && (i < DM_NUM_OPTIONAL_FIELDS))
+ {
+ DEBUG(11, ("spoolss_io_devmode: [%d] bytes left to parse in devmode\n", available_space));
+ if (!prs_uint32(opt_fields[i].name, ps, depth, opt_fields[i].field))
+ return False;
+ available_space -= sizeof(uint32);
+ i++;
+ }
+
+ /* Sanity Check - we should no available space at this point unless
+ MS changes the device mode structure */
+
+ if (available_space) {
+ DEBUG(0,("spoolss_io_devmode: I've parsed all I know and there is still stuff left|\n"));
+ DEBUG(0,("spoolss_io_devmode: available_space = [%d], devmode_size = [%d]!\n",
+ available_space, devmode->size));
+ DEBUG(0,("spoolss_io_devmode: please report to samba-technical@samba.org!\n"));
+ return False;
+ }
+
+
+ if (devmode->driverextra!=0) {
+ if (UNMARSHALLING(ps)) {
+ devmode->dev_private=PRS_ALLOC_MEM(ps, uint8, devmode->driverextra);
+ if(devmode->dev_private == NULL)
+ return False;
+ DEBUG(7,("spoolss_io_devmode: allocated memory [%d] for dev_private\n",devmode->driverextra));
+ }
+
+ DEBUG(7,("spoolss_io_devmode: parsing [%d] bytes of dev_private\n",devmode->driverextra));
+ if (!prs_uint8s(False, "dev_private", ps, depth,
+ devmode->dev_private, devmode->driverextra))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Read or write a DEVICEMODE container
+********************************************************************/
+
+static bool spoolss_io_devmode_cont(const char *desc, DEVMODE_CTR *dm_c, prs_struct *ps, int depth)
+{
+ if (dm_c==NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_devmode_cont");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("size", ps, depth, &dm_c->size))
+ return False;
+
+ if (!prs_uint32("devmode_ptr", ps, depth, &dm_c->devmode_ptr))
+ return False;
+
+ if (dm_c->size==0 || dm_c->devmode_ptr==0) {
+ if (UNMARSHALLING(ps))
+ /* if while reading there is no DEVMODE ... */
+ dm_c->devmode=NULL;
+ return True;
+ }
+
+ /* so we have a DEVICEMODE to follow */
+ if (UNMARSHALLING(ps)) {
+ DEBUG(9,("Allocating memory for spoolss_io_devmode\n"));
+ dm_c->devmode=PRS_ALLOC_MEM(ps,DEVICEMODE,1);
+ if(dm_c->devmode == NULL)
+ return False;
+ }
+
+ /* this is bad code, shouldn't be there */
+ if (!prs_uint32("size", ps, depth, &dm_c->size))
+ return False;
+
+ if (!spoolss_io_devmode(desc, ps, depth, dm_c->devmode))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static bool spoolss_io_printer_default(const char *desc, PRINTER_DEFAULT *pd, prs_struct *ps, int depth)
+{
+ if (pd==NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_printer_default");
+ depth++;
+
+ if (!prs_uint32("datatype_ptr", ps, depth, &pd->datatype_ptr))
+ return False;
+
+ if (!smb_io_unistr2("datatype", &pd->datatype, pd->datatype_ptr, ps,depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_devmode_cont("", &pd->devmode_cont, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("access_required", ps, depth, &pd->access_required))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_open_printer_ex(SPOOL_Q_OPEN_PRINTER_EX *q_u,
+ const fstring printername,
+ const fstring datatype,
+ uint32 access_required,
+ const fstring clientname,
+ const fstring user_name)
+{
+ DEBUG(5,("make_spoolss_q_open_printer_ex\n"));
+
+ q_u->printername = TALLOC_P( talloc_tos(), UNISTR2 );
+ if (!q_u->printername) {
+ return False;
+ }
+ init_unistr2(q_u->printername, printername, UNI_STR_TERMINATE);
+
+ q_u->printer_default.datatype_ptr = 0;
+
+ q_u->printer_default.devmode_cont.size=0;
+ q_u->printer_default.devmode_cont.devmode_ptr=0;
+ q_u->printer_default.devmode_cont.devmode=NULL;
+ q_u->printer_default.access_required=access_required;
+
+ q_u->user_switch = 1;
+
+ q_u->user_ctr.level = 1;
+ q_u->user_ctr.user.user1 = TALLOC_P( talloc_tos(), SPOOL_USER_1 );
+ if (!q_u->user_ctr.user.user1) {
+ return False;
+ }
+ q_u->user_ctr.user.user1->size = strlen(clientname) + strlen(user_name) + 10;
+ q_u->user_ctr.user.user1->build = 1381;
+ q_u->user_ctr.user.user1->major = 2;
+ q_u->user_ctr.user.user1->minor = 0;
+ q_u->user_ctr.user.user1->processor = 0;
+
+ q_u->user_ctr.user.user1->client_name = TALLOC_P( talloc_tos(), UNISTR2 );
+ if (!q_u->user_ctr.user.user1->client_name) {
+ return False;
+ }
+ q_u->user_ctr.user.user1->user_name = TALLOC_P( talloc_tos(), UNISTR2 );
+ if (!q_u->user_ctr.user.user1->user_name) {
+ return False;
+ }
+
+ init_unistr2(q_u->user_ctr.user.user1->client_name, clientname, UNI_STR_TERMINATE);
+ init_unistr2(q_u->user_ctr.user.user1->user_name, user_name, UNI_STR_TERMINATE);
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_addprinterex( TALLOC_CTX *mem_ctx, SPOOL_Q_ADDPRINTEREX *q_u,
+ const char *srv_name, const char* clientname, const char* user_name,
+ uint32 level, PRINTER_INFO_CTR *ctr)
+{
+ DEBUG(5,("make_spoolss_q_addprinterex\n"));
+
+ if (!ctr || !ctr->printers_2)
+ return False;
+
+ ZERO_STRUCTP(q_u);
+
+ q_u->server_name = TALLOC_P( mem_ctx, UNISTR2 );
+ if (!q_u->server_name) {
+ return False;
+ }
+ init_unistr2(q_u->server_name, srv_name, UNI_FLAGS_NONE);
+
+ q_u->level = level;
+
+ q_u->info.level = level;
+ q_u->info.info_ptr = (ctr->printers_2!=NULL)?1:0;
+ switch (level) {
+ case 2:
+ /* init q_u->info.info2 from *info */
+ if (!make_spoolss_printer_info_2(mem_ctx, &q_u->info.info_2, ctr->printers_2)) {
+ DEBUG(0,("make_spoolss_q_addprinterex: Unable to fill SPOOL_Q_ADDPRINTEREX struct!\n"));
+ return False;
+ }
+ break;
+ default :
+ break;
+ }
+
+ q_u->user_switch=1;
+
+ q_u->user_ctr.level = 1;
+ q_u->user_ctr.user.user1 = TALLOC_P( talloc_tos(), SPOOL_USER_1 );
+ if (!q_u->user_ctr.user.user1) {
+ return False;
+ }
+ q_u->user_ctr.user.user1->build = 1381;
+ q_u->user_ctr.user.user1->major = 2;
+ q_u->user_ctr.user.user1->minor = 0;
+ q_u->user_ctr.user.user1->processor = 0;
+
+ q_u->user_ctr.user.user1->client_name = TALLOC_P( mem_ctx, UNISTR2 );
+ if (!q_u->user_ctr.user.user1->client_name) {
+ return False;
+ }
+ q_u->user_ctr.user.user1->user_name = TALLOC_P( mem_ctx, UNISTR2 );
+ if (!q_u->user_ctr.user.user1->user_name) {
+ return False;
+ }
+ init_unistr2(q_u->user_ctr.user.user1->client_name, clientname, UNI_STR_TERMINATE);
+ init_unistr2(q_u->user_ctr.user.user1->user_name, user_name, UNI_STR_TERMINATE);
+
+ q_u->user_ctr.user.user1->size = q_u->user_ctr.user.user1->user_name->uni_str_len +
+ q_u->user_ctr.user.user1->client_name->uni_str_len + 2;
+
+ return True;
+}
+
+/*******************************************************************
+create a SPOOL_PRINTER_INFO_2 stuct from a PRINTER_INFO_2 struct
+*******************************************************************/
+
+bool make_spoolss_printer_info_2(TALLOC_CTX *ctx, SPOOL_PRINTER_INFO_LEVEL_2 **spool_info2,
+ PRINTER_INFO_2 *info)
+{
+
+ SPOOL_PRINTER_INFO_LEVEL_2 *inf;
+
+ /* allocate the necessary memory */
+ if (!(inf=TALLOC_P(ctx, SPOOL_PRINTER_INFO_LEVEL_2))) {
+ DEBUG(0,("make_spoolss_printer_info_2: Unable to allocate SPOOL_PRINTER_INFO_LEVEL_2 sruct!\n"));
+ return False;
+ }
+
+ inf->servername_ptr = (info->servername.buffer!=NULL)?1:0;
+ inf->printername_ptr = (info->printername.buffer!=NULL)?1:0;
+ inf->sharename_ptr = (info->sharename.buffer!=NULL)?1:0;
+ inf->portname_ptr = (info->portname.buffer!=NULL)?1:0;
+ inf->drivername_ptr = (info->drivername.buffer!=NULL)?1:0;
+ inf->comment_ptr = (info->comment.buffer!=NULL)?1:0;
+ inf->location_ptr = (info->location.buffer!=NULL)?1:0;
+ inf->devmode_ptr = (info->devmode!=NULL)?1:0;
+ inf->sepfile_ptr = (info->sepfile.buffer!=NULL)?1:0;
+ inf->printprocessor_ptr = (info->printprocessor.buffer!=NULL)?1:0;
+ inf->datatype_ptr = (info->datatype.buffer!=NULL)?1:0;
+ inf->parameters_ptr = (info->parameters.buffer!=NULL)?1:0;
+ inf->secdesc_ptr = (info->secdesc!=NULL)?1:0;
+ inf->attributes = info->attributes;
+ inf->priority = info->priority;
+ inf->default_priority = info->defaultpriority;
+ inf->starttime = info->starttime;
+ inf->untiltime = info->untiltime;
+ inf->cjobs = info->cjobs;
+ inf->averageppm = info->averageppm;
+ init_unistr2_from_unistr(inf, &inf->servername, &info->servername);
+ init_unistr2_from_unistr(inf, &inf->printername, &info->printername);
+ init_unistr2_from_unistr(inf, &inf->sharename, &info->sharename);
+ init_unistr2_from_unistr(inf, &inf->portname, &info->portname);
+ init_unistr2_from_unistr(inf, &inf->drivername, &info->drivername);
+ init_unistr2_from_unistr(inf, &inf->comment, &info->comment);
+ init_unistr2_from_unistr(inf, &inf->location, &info->location);
+ init_unistr2_from_unistr(inf, &inf->sepfile, &info->sepfile);
+ init_unistr2_from_unistr(inf, &inf->printprocessor, &info->printprocessor);
+ init_unistr2_from_unistr(inf, &inf->datatype, &info->datatype);
+ init_unistr2_from_unistr(inf, &inf->parameters, &info->parameters);
+ init_unistr2_from_unistr(inf, &inf->datatype, &info->datatype);
+
+ *spool_info2 = inf;
+
+ return True;
+}
+
+/*******************************************************************
+create a SPOOL_PRINTER_INFO_3 struct from a PRINTER_INFO_3 struct
+*******************************************************************/
+
+bool make_spoolss_printer_info_3(TALLOC_CTX *mem_ctx, SPOOL_PRINTER_INFO_LEVEL_3 **spool_info3,
+ PRINTER_INFO_3 *info)
+{
+
+ SPOOL_PRINTER_INFO_LEVEL_3 *inf;
+
+ /* allocate the necessary memory */
+ if (!(inf=TALLOC_P(mem_ctx, SPOOL_PRINTER_INFO_LEVEL_3))) {
+ DEBUG(0,("make_spoolss_printer_info_3: Unable to allocate SPOOL_PRINTER_INFO_LEVEL_3 sruct!\n"));
+ return False;
+ }
+
+ inf->secdesc_ptr = (info->secdesc!=NULL)?1:0;
+
+ *spool_info3 = inf;
+
+ return True;
+}
+
+/*******************************************************************
+create a SPOOL_PRINTER_INFO_7 struct from a PRINTER_INFO_7 struct
+*******************************************************************/
+
+bool make_spoolss_printer_info_7(TALLOC_CTX *mem_ctx, SPOOL_PRINTER_INFO_LEVEL_7 **spool_info7,
+ PRINTER_INFO_7 *info)
+{
+
+ SPOOL_PRINTER_INFO_LEVEL_7 *inf;
+
+ /* allocate the necessary memory */
+ if (!(inf=TALLOC_P(mem_ctx, SPOOL_PRINTER_INFO_LEVEL_7))) {
+ DEBUG(0,("make_spoolss_printer_info_7: Unable to allocate SPOOL_PRINTER_INFO_LEVEL_7 struct!\n"));
+ return False;
+ }
+
+ inf->guid_ptr = (info->guid.buffer!=NULL)?1:0;
+ inf->action = info->action;
+ init_unistr2_from_unistr(inf, &inf->guid, &info->guid);
+
+ *spool_info7 = inf;
+
+ return True;
+}
+
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_open_printer_ex (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_open_printer(const char *desc, SPOOL_Q_OPEN_PRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_open_printer");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_io_unistr2_p("ptr", ps, depth, &q_u->printername))
+ return False;
+ if (!prs_io_unistr2("printername", ps, depth, q_u->printername))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_printer_default("", &q_u->printer_default, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from static spoolss_r_open_printer_ex (srv_spoolss.c)
+ * called from spoolss_open_printer_ex (cli_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_open_printer(const char *desc, SPOOL_R_OPEN_PRINTER *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_r_open_printer");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("printer handle",&(r_u->handle),ps,depth))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &(r_u->status)))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_open_printer_ex (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_open_printer_ex(const char *desc, SPOOL_Q_OPEN_PRINTER_EX *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_open_printer_ex");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_io_unistr2_p("ptr", ps, depth, &q_u->printername))
+ return False;
+ if (!prs_io_unistr2("printername", ps, depth, q_u->printername))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_printer_default("", &q_u->printer_default, ps, depth))
+ return False;
+
+ if (!prs_uint32("user_switch", ps, depth, &q_u->user_switch))
+ return False;
+ if (!spool_io_user_level("", &q_u->user_ctr, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from static spoolss_r_open_printer_ex (srv_spoolss.c)
+ * called from spoolss_open_printer_ex (cli_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_open_printer_ex(const char *desc, SPOOL_R_OPEN_PRINTER_EX *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_r_open_printer_ex");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("printer handle",&(r_u->handle),ps,depth))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &(r_u->status)))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+bool make_spoolss_q_deleteprinterdriverex( TALLOC_CTX *mem_ctx,
+ SPOOL_Q_DELETEPRINTERDRIVEREX *q_u,
+ const char *server,
+ const char* arch,
+ const char* driver,
+ int version)
+{
+ DEBUG(5,("make_spoolss_q_deleteprinterdriverex\n"));
+
+ q_u->server_ptr = (server!=NULL)?1:0;
+ q_u->delete_flags = DPD_DELETE_UNUSED_FILES;
+
+ /* these must be NULL terminated or else NT4 will
+ complain about invalid parameters --jerry */
+ init_unistr2(&q_u->server, server, UNI_STR_TERMINATE);
+ init_unistr2(&q_u->arch, arch, UNI_STR_TERMINATE);
+ init_unistr2(&q_u->driver, driver, UNI_STR_TERMINATE);
+
+ if (version >= 0) {
+ q_u->delete_flags |= DPD_DELETE_SPECIFIC_VERSION;
+ q_u->version = version;
+ }
+
+ return True;
+}
+
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+bool make_spoolss_q_deleteprinterdriver(
+ TALLOC_CTX *mem_ctx,
+ SPOOL_Q_DELETEPRINTERDRIVER *q_u,
+ const char *server,
+ const char* arch,
+ const char* driver
+)
+{
+ DEBUG(5,("make_spoolss_q_deleteprinterdriver\n"));
+
+ q_u->server_ptr = (server!=NULL)?1:0;
+
+ /* these must be NULL terminated or else NT4 will
+ complain about invalid parameters --jerry */
+ init_unistr2(&q_u->server, server, UNI_STR_TERMINATE);
+ init_unistr2(&q_u->arch, arch, UNI_STR_TERMINATE);
+ init_unistr2(&q_u->driver, driver, UNI_STR_TERMINATE);
+
+ return True;
+}
+
+/*******************************************************************
+ * make a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_getprinterdata(SPOOL_Q_GETPRINTERDATA *q_u,
+ const POLICY_HND *handle,
+ const char *valuename, uint32 size)
+{
+ if (q_u == NULL) return False;
+
+ DEBUG(5,("make_spoolss_q_getprinterdata\n"));
+
+ q_u->handle = *handle;
+ init_unistr2(&q_u->valuename, valuename, UNI_STR_TERMINATE);
+ q_u->size = size;
+
+ return True;
+}
+
+/*******************************************************************
+ * make a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_getprinterdataex(SPOOL_Q_GETPRINTERDATAEX *q_u,
+ const POLICY_HND *handle,
+ const char *keyname,
+ const char *valuename, uint32 size)
+{
+ if (q_u == NULL) return False;
+
+ DEBUG(5,("make_spoolss_q_getprinterdataex\n"));
+
+ q_u->handle = *handle;
+ init_unistr2(&q_u->valuename, valuename, UNI_STR_TERMINATE);
+ init_unistr2(&q_u->keyname, keyname, UNI_STR_TERMINATE);
+ q_u->size = size;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_getprinterdata (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_getprinterdata(const char *desc, SPOOL_Q_GETPRINTERDATA *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_getprinterdata");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_unistr2("valuename", &q_u->valuename,True,ps,depth))
+ return False;
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("size", ps, depth, &q_u->size))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_deleteprinterdata (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_deleteprinterdata(const char *desc, SPOOL_Q_DELETEPRINTERDATA *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_deleteprinterdata");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_unistr2("valuename", &q_u->valuename,True,ps,depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_deleteprinterdata (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_deleteprinterdata(const char *desc, SPOOL_R_DELETEPRINTERDATA *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_deleteprinterdata");
+ depth++;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_deleteprinterdataex (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_deleteprinterdataex(const char *desc, SPOOL_Q_DELETEPRINTERDATAEX *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_deleteprinterdataex");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+
+ if (!smb_io_unistr2("keyname ", &q_u->keyname, True, ps, depth))
+ return False;
+ if (!smb_io_unistr2("valuename", &q_u->valuename, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_deleteprinterdataex (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_deleteprinterdataex(const char *desc, SPOOL_R_DELETEPRINTERDATAEX *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_deleteprinterdataex");
+ depth++;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_getprinterdata (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_getprinterdata(const char *desc, SPOOL_R_GETPRINTERDATA *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_r_getprinterdata");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("type", ps, depth, &r_u->type))
+ return False;
+ if (!prs_uint32("size", ps, depth, &r_u->size))
+ return False;
+
+ if (UNMARSHALLING(ps) && r_u->size) {
+ r_u->data = PRS_ALLOC_MEM(ps, unsigned char, r_u->size);
+ if(!r_u->data)
+ return False;
+ }
+
+ if (!prs_uint8s( False, "data", ps, depth, r_u->data, r_u->size ))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * make a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_closeprinter(SPOOL_Q_CLOSEPRINTER *q_u, POLICY_HND *hnd)
+{
+ if (q_u == NULL) return False;
+
+ DEBUG(5,("make_spoolss_q_closeprinter\n"));
+
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from static spoolss_q_abortprinter (srv_spoolss.c)
+ * called from spoolss_abortprinter (cli_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_abortprinter(const char *desc, SPOOL_Q_ABORTPRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_abortprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_abortprinter (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_abortprinter(const char *desc, SPOOL_R_ABORTPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_abortprinter");
+ depth++;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from static spoolss_q_deleteprinter (srv_spoolss.c)
+ * called from spoolss_deleteprinter (cli_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_deleteprinter(const char *desc, SPOOL_Q_DELETEPRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_deleteprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from static spoolss_r_deleteprinter (srv_spoolss.c)
+ * called from spoolss_deleteprinter (cli_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_deleteprinter(const char *desc, SPOOL_R_DELETEPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_deleteprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("printer handle",&r_u->handle,ps,depth))
+ return False;
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ * read a structure.
+ * called from api_spoolss_deleteprinterdriver (srv_spoolss.c)
+ * called from spoolss_deleteprinterdriver (cli_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_deleteprinterdriver(const char *desc, SPOOL_Q_DELETEPRINTERDRIVER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_deleteprinterdriver");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("server_ptr", ps, depth, &q_u->server_ptr))
+ return False;
+ if(!smb_io_unistr2("server", &q_u->server, q_u->server_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("arch", &q_u->arch, True, ps, depth))
+ return False;
+ if(!smb_io_unistr2("driver", &q_u->driver, True, ps, depth))
+ return False;
+
+
+ return True;
+}
+
+
+/*******************************************************************
+ * write a structure.
+ ********************************************************************/
+bool spoolss_io_r_deleteprinterdriver(const char *desc, SPOOL_R_DELETEPRINTERDRIVER *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_r_deleteprinterdriver");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ * read a structure.
+ * called from api_spoolss_deleteprinterdriver (srv_spoolss.c)
+ * called from spoolss_deleteprinterdriver (cli_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_deleteprinterdriverex(const char *desc, SPOOL_Q_DELETEPRINTERDRIVEREX *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_deleteprinterdriverex");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("server_ptr", ps, depth, &q_u->server_ptr))
+ return False;
+ if(!smb_io_unistr2("server", &q_u->server, q_u->server_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("arch", &q_u->arch, True, ps, depth))
+ return False;
+ if(!smb_io_unistr2("driver", &q_u->driver, True, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("delete_flags ", ps, depth, &q_u->delete_flags))
+ return False;
+ if(!prs_uint32("version ", ps, depth, &q_u->version))
+ return False;
+
+
+ return True;
+}
+
+
+/*******************************************************************
+ * write a structure.
+ ********************************************************************/
+bool spoolss_io_r_deleteprinterdriverex(const char *desc, SPOOL_R_DELETEPRINTERDRIVEREX *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_r_deleteprinterdriverex");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+
+
+/*******************************************************************
+ * read a structure.
+ * called from static spoolss_q_closeprinter (srv_spoolss.c)
+ * called from spoolss_closeprinter (cli_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_closeprinter(const char *desc, SPOOL_Q_CLOSEPRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_closeprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from static spoolss_r_closeprinter (srv_spoolss.c)
+ * called from spoolss_closeprinter (cli_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_closeprinter(const char *desc, SPOOL_R_CLOSEPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_closeprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("printer handle",&r_u->handle,ps,depth))
+ return False;
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_startdocprinter (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_startdocprinter(const char *desc, SPOOL_Q_STARTDOCPRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_startdocprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ if(!smb_io_doc_info_container("",&q_u->doc_info_container, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_startdocprinter (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_startdocprinter(const char *desc, SPOOL_R_STARTDOCPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_startdocprinter");
+ depth++;
+ if(!prs_uint32("jobid", ps, depth, &r_u->jobid))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_enddocprinter (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_enddocprinter(const char *desc, SPOOL_Q_ENDDOCPRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_enddocprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_enddocprinter (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_enddocprinter(const char *desc, SPOOL_R_ENDDOCPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enddocprinter");
+ depth++;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_startpageprinter (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_startpageprinter(const char *desc, SPOOL_Q_STARTPAGEPRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_startpageprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_startpageprinter (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_startpageprinter(const char *desc, SPOOL_R_STARTPAGEPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_startpageprinter");
+ depth++;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_endpageprinter (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_endpageprinter(const char *desc, SPOOL_Q_ENDPAGEPRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_endpageprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_endpageprinter (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_endpageprinter(const char *desc, SPOOL_R_ENDPAGEPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_endpageprinter");
+ depth++;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_writeprinter (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_writeprinter(const char *desc, SPOOL_Q_WRITEPRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_writeprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if(!prs_uint32("buffer_size", ps, depth, &q_u->buffer_size))
+ return False;
+
+ if (q_u->buffer_size!=0)
+ {
+ if (UNMARSHALLING(ps))
+ q_u->buffer=PRS_ALLOC_MEM(ps, uint8, q_u->buffer_size);
+ if(q_u->buffer == NULL)
+ return False;
+ if(!prs_uint8s(True, "buffer", ps, depth, q_u->buffer, q_u->buffer_size))
+ return False;
+ }
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("buffer_size2", ps, depth, &q_u->buffer_size2))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_writeprinter (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_writeprinter(const char *desc, SPOOL_R_WRITEPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_writeprinter");
+ depth++;
+ if(!prs_uint32("buffer_written", ps, depth, &r_u->buffer_written))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_rffpcnex (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_rffpcnex(const char *desc, SPOOL_Q_RFFPCNEX *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_rffpcnex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if(!prs_uint32("flags", ps, depth, &q_u->flags))
+ return False;
+ if(!prs_uint32("options", ps, depth, &q_u->options))
+ return False;
+ if(!prs_uint32("localmachine_ptr", ps, depth, &q_u->localmachine_ptr))
+ return False;
+ if(!smb_io_unistr2("localmachine", &q_u->localmachine, q_u->localmachine_ptr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("printerlocal", ps, depth, &q_u->printerlocal))
+ return False;
+
+ if(!prs_uint32("option_ptr", ps, depth, &q_u->option_ptr))
+ return False;
+
+ if (q_u->option_ptr!=0) {
+
+ if (UNMARSHALLING(ps))
+ if((q_u->option=PRS_ALLOC_MEM(ps,SPOOL_NOTIFY_OPTION,1)) == NULL)
+ return False;
+
+ if(!smb_io_notify_option("notify option", q_u->option, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_rffpcnex (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_rffpcnex(const char *desc, SPOOL_R_RFFPCNEX *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_rffpcnex");
+ depth++;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_rfnpcnex (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_rfnpcnex(const char *desc, SPOOL_Q_RFNPCNEX *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_rfnpcnex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ if(!prs_uint32("change", ps, depth, &q_u->change))
+ return False;
+
+ if(!prs_uint32("option_ptr", ps, depth, &q_u->option_ptr))
+ return False;
+
+ if (q_u->option_ptr!=0) {
+
+ if (UNMARSHALLING(ps))
+ if((q_u->option=PRS_ALLOC_MEM(ps,SPOOL_NOTIFY_OPTION,1)) == NULL)
+ return False;
+
+ if(!smb_io_notify_option("notify option", q_u->option, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_rfnpcnex (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_rfnpcnex(const char *desc, SPOOL_R_RFNPCNEX *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_rfnpcnex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("info_ptr", ps, depth, &r_u->info_ptr))
+ return False;
+
+ if(!smb_io_notify_info("notify info", &r_u->info ,ps,depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * return the length of a uint16 (obvious, but the code is clean)
+ ********************************************************************/
+
+static uint32 size_of_uint16(uint16 *value)
+{
+ return (sizeof(*value));
+}
+
+/*******************************************************************
+ * return the length of a uint32 (obvious, but the code is clean)
+ ********************************************************************/
+
+static uint32 size_of_uint32(uint32 *value)
+{
+ return (sizeof(*value));
+}
+
+/*******************************************************************
+ * return the length of a NTTIME (obvious, but the code is clean)
+ ********************************************************************/
+
+static uint32 size_of_nttime(NTTIME *value)
+{
+ return (sizeof(*value));
+}
+
+/*******************************************************************
+ * return the length of a uint32 (obvious, but the code is clean)
+ ********************************************************************/
+
+static uint32 size_of_device_mode(DEVICEMODE *devmode)
+{
+ if (devmode==NULL)
+ return (4);
+ else
+ return (4+devmode->size+devmode->driverextra);
+}
+
+/*******************************************************************
+ * return the length of a uint32 (obvious, but the code is clean)
+ ********************************************************************/
+
+static uint32 size_of_systemtime(SYSTEMTIME *systime)
+{
+ if (systime==NULL)
+ return (4);
+ else
+ return (sizeof(SYSTEMTIME) +4);
+}
+
+/*******************************************************************
+ Parse a DEVMODE structure and its relative pointer.
+********************************************************************/
+
+static bool smb_io_reldevmode(const char *desc, RPC_BUFFER *buffer, int depth, DEVICEMODE **devmode)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_reldevmode");
+ depth++;
+
+ if (MARSHALLING(ps)) {
+ uint32 struct_offset = prs_offset(ps);
+ uint32 relative_offset;
+
+ if (*devmode == NULL) {
+ relative_offset=0;
+ if (!prs_uint32("offset", ps, depth, &relative_offset))
+ return False;
+ DEBUG(8, ("boing, the devmode was NULL\n"));
+
+ return True;
+ }
+
+ buffer->string_at_end -= ((*devmode)->size + (*devmode)->driverextra);
+
+ /* mz: we have to align the device mode for VISTA */
+ if (buffer->string_at_end % 4) {
+ buffer->string_at_end += 4 - (buffer->string_at_end % 4);
+ }
+
+ if(!prs_set_offset(ps, buffer->string_at_end))
+ return False;
+
+ /* write the DEVMODE */
+ if (!spoolss_io_devmode(desc, ps, depth, *devmode))
+ return False;
+
+ if(!prs_set_offset(ps, struct_offset))
+ return False;
+
+ relative_offset=buffer->string_at_end - buffer->struct_start;
+ /* write its offset */
+ if (!prs_uint32("offset", ps, depth, &relative_offset))
+ return False;
+ }
+ else {
+ uint32 old_offset;
+
+ /* read the offset */
+ if (!prs_uint32("offset", ps, depth, &buffer->string_at_end))
+ return False;
+ if (buffer->string_at_end == 0) {
+ *devmode = NULL;
+ return True;
+ }
+
+ old_offset = prs_offset(ps);
+ if(!prs_set_offset(ps, buffer->string_at_end + buffer->struct_start))
+ return False;
+
+ /* read the string */
+ if((*devmode=PRS_ALLOC_MEM(ps,DEVICEMODE,1)) == NULL)
+ return False;
+ if (!spoolss_io_devmode(desc, ps, depth, *devmode))
+ return False;
+
+ if(!prs_set_offset(ps, old_offset))
+ return False;
+ }
+ return True;
+}
+
+/*******************************************************************
+ Parse a PRINTER_INFO_0 structure.
+********************************************************************/
+
+bool smb_io_printer_info_0(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_0 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_info_0");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("printername", buffer, depth, &info->printername))
+ return False;
+ if (!smb_io_relstr("servername", buffer, depth, &info->servername))
+ return False;
+
+ if(!prs_uint32("cjobs", ps, depth, &info->cjobs))
+ return False;
+ if(!prs_uint32("total_jobs", ps, depth, &info->total_jobs))
+ return False;
+ if(!prs_uint32("total_bytes", ps, depth, &info->total_bytes))
+ return False;
+
+ if(!prs_uint16("year", ps, depth, &info->year))
+ return False;
+ if(!prs_uint16("month", ps, depth, &info->month))
+ return False;
+ if(!prs_uint16("dayofweek", ps, depth, &info->dayofweek))
+ return False;
+ if(!prs_uint16("day", ps, depth, &info->day))
+ return False;
+ if(!prs_uint16("hour", ps, depth, &info->hour))
+ return False;
+ if(!prs_uint16("minute", ps, depth, &info->minute))
+ return False;
+ if(!prs_uint16("second", ps, depth, &info->second))
+ return False;
+ if(!prs_uint16("milliseconds", ps, depth, &info->milliseconds))
+ return False;
+
+ if(!prs_uint32("global_counter", ps, depth, &info->global_counter))
+ return False;
+ if(!prs_uint32("total_pages", ps, depth, &info->total_pages))
+ return False;
+
+ if(!prs_uint16("major_version", ps, depth, &info->major_version))
+ return False;
+ if(!prs_uint16("build_version", ps, depth, &info->build_version))
+ return False;
+ if(!prs_uint32("unknown7", ps, depth, &info->unknown7))
+ return False;
+ if(!prs_uint32("unknown8", ps, depth, &info->unknown8))
+ return False;
+ if(!prs_uint32("unknown9", ps, depth, &info->unknown9))
+ return False;
+ if(!prs_uint32("session_counter", ps, depth, &info->session_counter))
+ return False;
+ if(!prs_uint32("unknown11", ps, depth, &info->unknown11))
+ return False;
+ if(!prs_uint32("printer_errors", ps, depth, &info->printer_errors))
+ return False;
+ if(!prs_uint32("unknown13", ps, depth, &info->unknown13))
+ return False;
+ if(!prs_uint32("unknown14", ps, depth, &info->unknown14))
+ return False;
+ if(!prs_uint32("unknown15", ps, depth, &info->unknown15))
+ return False;
+ if(!prs_uint32("unknown16", ps, depth, &info->unknown16))
+ return False;
+ if(!prs_uint32("change_id", ps, depth, &info->change_id))
+ return False;
+ if(!prs_uint32("unknown18", ps, depth, &info->unknown18))
+ return False;
+ if(!prs_uint32("status" , ps, depth, &info->status))
+ return False;
+ if(!prs_uint32("unknown20", ps, depth, &info->unknown20))
+ return False;
+ if(!prs_uint32("c_setprinter", ps, depth, &info->c_setprinter))
+ return False;
+ if(!prs_uint16("unknown22", ps, depth, &info->unknown22))
+ return False;
+ if(!prs_uint16("unknown23", ps, depth, &info->unknown23))
+ return False;
+ if(!prs_uint16("unknown24", ps, depth, &info->unknown24))
+ return False;
+ if(!prs_uint16("unknown25", ps, depth, &info->unknown25))
+ return False;
+ if(!prs_uint16("unknown26", ps, depth, &info->unknown26))
+ return False;
+ if(!prs_uint16("unknown27", ps, depth, &info->unknown27))
+ return False;
+ if(!prs_uint16("unknown28", ps, depth, &info->unknown28))
+ return False;
+ if(!prs_uint16("unknown29", ps, depth, &info->unknown29))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a PRINTER_INFO_1 structure.
+********************************************************************/
+
+bool smb_io_printer_info_1(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_info_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!prs_uint32("flags", ps, depth, &info->flags))
+ return False;
+ if (!smb_io_relstr("description", buffer, depth, &info->description))
+ return False;
+ if (!smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+ if (!smb_io_relstr("comment", buffer, depth, &info->comment))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a PRINTER_INFO_2 structure.
+********************************************************************/
+
+bool smb_io_printer_info_2(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_2 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+ uint32 dm_offset, sd_offset, current_offset;
+ uint32 dummy_value = 0, has_secdesc = 0;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_info_2");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("servername", buffer, depth, &info->servername))
+ return False;
+ if (!smb_io_relstr("printername", buffer, depth, &info->printername))
+ return False;
+ if (!smb_io_relstr("sharename", buffer, depth, &info->sharename))
+ return False;
+ if (!smb_io_relstr("portname", buffer, depth, &info->portname))
+ return False;
+ if (!smb_io_relstr("drivername", buffer, depth, &info->drivername))
+ return False;
+ if (!smb_io_relstr("comment", buffer, depth, &info->comment))
+ return False;
+ if (!smb_io_relstr("location", buffer, depth, &info->location))
+ return False;
+
+ /* save current offset and wind forwared by a uint32 */
+ dm_offset = prs_offset(ps);
+ if (!prs_uint32("devmode", ps, depth, &dummy_value))
+ return False;
+
+ if (!smb_io_relstr("sepfile", buffer, depth, &info->sepfile))
+ return False;
+ if (!smb_io_relstr("printprocessor", buffer, depth, &info->printprocessor))
+ return False;
+ if (!smb_io_relstr("datatype", buffer, depth, &info->datatype))
+ return False;
+ if (!smb_io_relstr("parameters", buffer, depth, &info->parameters))
+ return False;
+
+ /* save current offset for the sec_desc */
+ sd_offset = prs_offset(ps);
+ if (!prs_uint32("sec_desc", ps, depth, &has_secdesc))
+ return False;
+
+
+ /* save current location so we can pick back up here */
+ current_offset = prs_offset(ps);
+
+ /* parse the devmode */
+ if (!prs_set_offset(ps, dm_offset))
+ return False;
+ if (!smb_io_reldevmode("devmode", buffer, depth, &info->devmode))
+ return False;
+
+ /* parse the sec_desc */
+ if (info->secdesc) {
+ if (!prs_set_offset(ps, sd_offset))
+ return False;
+ if (!smb_io_relsecdesc("secdesc", buffer, depth, &info->secdesc))
+ return False;
+ }
+
+ /* pick up where we left off */
+ if (!prs_set_offset(ps, current_offset))
+ return False;
+
+ if (!prs_uint32("attributes", ps, depth, &info->attributes))
+ return False;
+ if (!prs_uint32("priority", ps, depth, &info->priority))
+ return False;
+ if (!prs_uint32("defpriority", ps, depth, &info->defaultpriority))
+ return False;
+ if (!prs_uint32("starttime", ps, depth, &info->starttime))
+ return False;
+ if (!prs_uint32("untiltime", ps, depth, &info->untiltime))
+ return False;
+ if (!prs_uint32("status", ps, depth, &info->status))
+ return False;
+ if (!prs_uint32("jobs", ps, depth, &info->cjobs))
+ return False;
+ if (!prs_uint32("averageppm", ps, depth, &info->averageppm))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a PRINTER_INFO_3 structure.
+********************************************************************/
+
+bool smb_io_printer_info_3(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_3 *info, int depth)
+{
+ uint32 offset = 0;
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_info_3");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (MARSHALLING(ps)) {
+ /* Ensure the SD is 8 byte aligned in the buffer. */
+ uint32 start = prs_offset(ps); /* Remember the start position. */
+ uint32 off_val = 0;
+
+ /* Write a dummy value. */
+ if (!prs_uint32("offset", ps, depth, &off_val))
+ return False;
+
+ /* 8 byte align. */
+ if (!prs_align_uint64(ps))
+ return False;
+
+ /* Remember where we must seek back to write the SD. */
+ offset = prs_offset(ps);
+
+ /* Calculate the real offset for the SD. */
+
+ off_val = offset - start;
+
+ /* Seek back to where we store the SD offset & store. */
+ prs_set_offset(ps, start);
+ if (!prs_uint32("offset", ps, depth, &off_val))
+ return False;
+
+ /* Return to after the 8 byte align. */
+ prs_set_offset(ps, offset);
+
+ } else {
+ if (!prs_uint32("offset", ps, depth, &offset))
+ return False;
+ /* Seek within the buffer. */
+ if (!prs_set_offset(ps, offset))
+ return False;
+ }
+ if (!sec_io_desc("sec_desc", &info->secdesc, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a PRINTER_INFO_4 structure.
+********************************************************************/
+
+bool smb_io_printer_info_4(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_4 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_info_4");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("printername", buffer, depth, &info->printername))
+ return False;
+ if (!smb_io_relstr("servername", buffer, depth, &info->servername))
+ return False;
+ if (!prs_uint32("attributes", ps, depth, &info->attributes))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Parse a PRINTER_INFO_5 structure.
+********************************************************************/
+
+bool smb_io_printer_info_5(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_5 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_info_5");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("printername", buffer, depth, &info->printername))
+ return False;
+ if (!smb_io_relstr("portname", buffer, depth, &info->portname))
+ return False;
+ if (!prs_uint32("attributes", ps, depth, &info->attributes))
+ return False;
+ if (!prs_uint32("device_not_selected_timeout", ps, depth, &info->device_not_selected_timeout))
+ return False;
+ if (!prs_uint32("transmission_retry_timeout", ps, depth, &info->transmission_retry_timeout))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Parse a PRINTER_INFO_6 structure.
+********************************************************************/
+
+bool smb_io_printer_info_6(const char *desc, RPC_BUFFER *buffer,
+ PRINTER_INFO_6 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_info_6");
+ depth++;
+
+ if (!prs_uint32("status", ps, depth, &info->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a PRINTER_INFO_7 structure.
+********************************************************************/
+
+bool smb_io_printer_info_7(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_7 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_info_7");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("guid", buffer, depth, &info->guid))
+ return False;
+ if (!prs_uint32("action", ps, depth, &info->action))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Parse a PORT_INFO_1 structure.
+********************************************************************/
+
+bool smb_io_port_info_1(const char *desc, RPC_BUFFER *buffer, PORT_INFO_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_port_info_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("port_name", buffer, depth, &info->port_name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a PORT_INFO_2 structure.
+********************************************************************/
+
+bool smb_io_port_info_2(const char *desc, RPC_BUFFER *buffer, PORT_INFO_2 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_port_info_2");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("port_name", buffer, depth, &info->port_name))
+ return False;
+ if (!smb_io_relstr("monitor_name", buffer, depth, &info->monitor_name))
+ return False;
+ if (!smb_io_relstr("description", buffer, depth, &info->description))
+ return False;
+ if (!prs_uint32("port_type", ps, depth, &info->port_type))
+ return False;
+ if (!prs_uint32("reserved", ps, depth, &info->reserved))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a DRIVER_INFO_1 structure.
+********************************************************************/
+
+bool smb_io_printer_driver_info_1(const char *desc, RPC_BUFFER *buffer, DRIVER_INFO_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_driver_info_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a DRIVER_INFO_2 structure.
+********************************************************************/
+
+bool smb_io_printer_driver_info_2(const char *desc, RPC_BUFFER *buffer, DRIVER_INFO_2 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_driver_info_2");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!prs_uint32("version", ps, depth, &info->version))
+ return False;
+ if (!smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+ if (!smb_io_relstr("architecture", buffer, depth, &info->architecture))
+ return False;
+ if (!smb_io_relstr("driverpath", buffer, depth, &info->driverpath))
+ return False;
+ if (!smb_io_relstr("datafile", buffer, depth, &info->datafile))
+ return False;
+ if (!smb_io_relstr("configfile", buffer, depth, &info->configfile))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a DRIVER_INFO_3 structure.
+********************************************************************/
+
+bool smb_io_printer_driver_info_3(const char *desc, RPC_BUFFER *buffer, DRIVER_INFO_3 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_driver_info_3");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!prs_uint32("version", ps, depth, &info->version))
+ return False;
+ if (!smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+ if (!smb_io_relstr("architecture", buffer, depth, &info->architecture))
+ return False;
+ if (!smb_io_relstr("driverpath", buffer, depth, &info->driverpath))
+ return False;
+ if (!smb_io_relstr("datafile", buffer, depth, &info->datafile))
+ return False;
+ if (!smb_io_relstr("configfile", buffer, depth, &info->configfile))
+ return False;
+ if (!smb_io_relstr("helpfile", buffer, depth, &info->helpfile))
+ return False;
+
+ if (!smb_io_relarraystr("dependentfiles", buffer, depth, &info->dependentfiles))
+ return False;
+
+ if (!smb_io_relstr("monitorname", buffer, depth, &info->monitorname))
+ return False;
+ if (!smb_io_relstr("defaultdatatype", buffer, depth, &info->defaultdatatype))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a DRIVER_INFO_6 structure.
+********************************************************************/
+
+bool smb_io_printer_driver_info_6(const char *desc, RPC_BUFFER *buffer, DRIVER_INFO_6 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_driver_info_6");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!prs_uint32("version", ps, depth, &info->version))
+ return False;
+ if (!smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+ if (!smb_io_relstr("architecture", buffer, depth, &info->architecture))
+ return False;
+ if (!smb_io_relstr("driverpath", buffer, depth, &info->driverpath))
+ return False;
+ if (!smb_io_relstr("datafile", buffer, depth, &info->datafile))
+ return False;
+ if (!smb_io_relstr("configfile", buffer, depth, &info->configfile))
+ return False;
+ if (!smb_io_relstr("helpfile", buffer, depth, &info->helpfile))
+ return False;
+
+ if (!smb_io_relarraystr("dependentfiles", buffer, depth, &info->dependentfiles))
+ return False;
+
+ if (!smb_io_relstr("monitorname", buffer, depth, &info->monitorname))
+ return False;
+ if (!smb_io_relstr("defaultdatatype", buffer, depth, &info->defaultdatatype))
+ return False;
+
+ if (!smb_io_relarraystr("previousdrivernames", buffer, depth, &info->previousdrivernames))
+ return False;
+
+ if (!prs_uint64("date", ps, depth, &info->driver_date))
+ return False;
+
+ if (!prs_uint32("padding", ps, depth, &info->padding))
+ return False;
+
+ if (!prs_uint32("driver_version_low", ps, depth, &info->driver_version_low))
+ return False;
+
+ if (!prs_uint32("driver_version_high", ps, depth, &info->driver_version_high))
+ return False;
+
+ if (!smb_io_relstr("mfgname", buffer, depth, &info->mfgname))
+ return False;
+ if (!smb_io_relstr("oem_url", buffer, depth, &info->oem_url))
+ return False;
+ if (!smb_io_relstr("hardware_id", buffer, depth, &info->hardware_id))
+ return False;
+ if (!smb_io_relstr("provider", buffer, depth, &info->provider))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a JOB_INFO_1 structure.
+********************************************************************/
+
+bool smb_io_job_info_1(const char *desc, RPC_BUFFER *buffer, JOB_INFO_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_job_info_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!prs_uint32("jobid", ps, depth, &info->jobid))
+ return False;
+ if (!smb_io_relstr("printername", buffer, depth, &info->printername))
+ return False;
+ if (!smb_io_relstr("machinename", buffer, depth, &info->machinename))
+ return False;
+ if (!smb_io_relstr("username", buffer, depth, &info->username))
+ return False;
+ if (!smb_io_relstr("document", buffer, depth, &info->document))
+ return False;
+ if (!smb_io_relstr("datatype", buffer, depth, &info->datatype))
+ return False;
+ if (!smb_io_relstr("text_status", buffer, depth, &info->text_status))
+ return False;
+ if (!prs_uint32("status", ps, depth, &info->status))
+ return False;
+ if (!prs_uint32("priority", ps, depth, &info->priority))
+ return False;
+ if (!prs_uint32("position", ps, depth, &info->position))
+ return False;
+ if (!prs_uint32("totalpages", ps, depth, &info->totalpages))
+ return False;
+ if (!prs_uint32("pagesprinted", ps, depth, &info->pagesprinted))
+ return False;
+ if (!spoolss_io_system_time("submitted", ps, depth, &info->submitted))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a JOB_INFO_2 structure.
+********************************************************************/
+
+bool smb_io_job_info_2(const char *desc, RPC_BUFFER *buffer, JOB_INFO_2 *info, int depth)
+{
+ uint32 pipo=0;
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_job_info_2");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!prs_uint32("jobid",ps, depth, &info->jobid))
+ return False;
+ if (!smb_io_relstr("printername", buffer, depth, &info->printername))
+ return False;
+ if (!smb_io_relstr("machinename", buffer, depth, &info->machinename))
+ return False;
+ if (!smb_io_relstr("username", buffer, depth, &info->username))
+ return False;
+ if (!smb_io_relstr("document", buffer, depth, &info->document))
+ return False;
+ if (!smb_io_relstr("notifyname", buffer, depth, &info->notifyname))
+ return False;
+ if (!smb_io_relstr("datatype", buffer, depth, &info->datatype))
+ return False;
+
+ if (!smb_io_relstr("printprocessor", buffer, depth, &info->printprocessor))
+ return False;
+ if (!smb_io_relstr("parameters", buffer, depth, &info->parameters))
+ return False;
+ if (!smb_io_relstr("drivername", buffer, depth, &info->drivername))
+ return False;
+ if (!smb_io_reldevmode("devmode", buffer, depth, &info->devmode))
+ return False;
+ if (!smb_io_relstr("text_status", buffer, depth, &info->text_status))
+ return False;
+
+/* SEC_DESC sec_desc;*/
+ if (!prs_uint32("Hack! sec desc", ps, depth, &pipo))
+ return False;
+
+ if (!prs_uint32("status",ps, depth, &info->status))
+ return False;
+ if (!prs_uint32("priority",ps, depth, &info->priority))
+ return False;
+ if (!prs_uint32("position",ps, depth, &info->position))
+ return False;
+ if (!prs_uint32("starttime",ps, depth, &info->starttime))
+ return False;
+ if (!prs_uint32("untiltime",ps, depth, &info->untiltime))
+ return False;
+ if (!prs_uint32("totalpages",ps, depth, &info->totalpages))
+ return False;
+ if (!prs_uint32("size",ps, depth, &info->size))
+ return False;
+ if (!spoolss_io_system_time("submitted", ps, depth, &info->submitted) )
+ return False;
+ if (!prs_uint32("timeelapsed",ps, depth, &info->timeelapsed))
+ return False;
+ if (!prs_uint32("pagesprinted",ps, depth, &info->pagesprinted))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool smb_io_form_1(const char *desc, RPC_BUFFER *buffer, FORM_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_form_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!prs_uint32("flag", ps, depth, &info->flag))
+ return False;
+
+ if (!smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+
+ if (!prs_uint32("width", ps, depth, &info->width))
+ return False;
+ if (!prs_uint32("length", ps, depth, &info->length))
+ return False;
+ if (!prs_uint32("left", ps, depth, &info->left))
+ return False;
+ if (!prs_uint32("top", ps, depth, &info->top))
+ return False;
+ if (!prs_uint32("right", ps, depth, &info->right))
+ return False;
+ if (!prs_uint32("bottom", ps, depth, &info->bottom))
+ return False;
+
+ return True;
+}
+
+
+
+/*******************************************************************
+ Parse a DRIVER_DIRECTORY_1 structure.
+********************************************************************/
+
+bool smb_io_driverdir_1(const char *desc, RPC_BUFFER *buffer, DRIVER_DIRECTORY_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_driverdir_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_unistr(desc, &info->name, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a PORT_INFO_1 structure.
+********************************************************************/
+
+bool smb_io_port_1(const char *desc, RPC_BUFFER *buffer, PORT_INFO_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_port_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if(!smb_io_relstr("port_name", buffer, depth, &info->port_name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a PORT_INFO_2 structure.
+********************************************************************/
+
+bool smb_io_port_2(const char *desc, RPC_BUFFER *buffer, PORT_INFO_2 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_port_2");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if(!smb_io_relstr("port_name", buffer, depth, &info->port_name))
+ return False;
+ if(!smb_io_relstr("monitor_name", buffer, depth, &info->monitor_name))
+ return False;
+ if(!smb_io_relstr("description", buffer, depth, &info->description))
+ return False;
+ if(!prs_uint32("port_type", ps, depth, &info->port_type))
+ return False;
+ if(!prs_uint32("reserved", ps, depth, &info->reserved))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool smb_io_printprocessor_info_1(const char *desc, RPC_BUFFER *buffer, PRINTPROCESSOR_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printprocessor_info_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool smb_io_printprocdatatype_info_1(const char *desc, RPC_BUFFER *buffer, PRINTPROCDATATYPE_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printprocdatatype_info_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool smb_io_printmonitor_info_1(const char *desc, RPC_BUFFER *buffer, PRINTMONITOR_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printmonitor_info_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool smb_io_printmonitor_info_2(const char *desc, RPC_BUFFER *buffer, PRINTMONITOR_2 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printmonitor_info_2");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+ if (!smb_io_relstr("environment", buffer, depth, &info->environment))
+ return False;
+ if (!smb_io_relstr("dll_name", buffer, depth, &info->dll_name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_info_0(PRINTER_INFO_0 *info)
+{
+ int size=0;
+
+ size+=size_of_relative_string( &info->printername );
+ size+=size_of_relative_string( &info->servername );
+
+ size+=size_of_uint32( &info->cjobs);
+ size+=size_of_uint32( &info->total_jobs);
+ size+=size_of_uint32( &info->total_bytes);
+
+ size+=size_of_uint16( &info->year);
+ size+=size_of_uint16( &info->month);
+ size+=size_of_uint16( &info->dayofweek);
+ size+=size_of_uint16( &info->day);
+ size+=size_of_uint16( &info->hour);
+ size+=size_of_uint16( &info->minute);
+ size+=size_of_uint16( &info->second);
+ size+=size_of_uint16( &info->milliseconds);
+
+ size+=size_of_uint32( &info->global_counter);
+ size+=size_of_uint32( &info->total_pages);
+
+ size+=size_of_uint16( &info->major_version);
+ size+=size_of_uint16( &info->build_version);
+
+ size+=size_of_uint32( &info->unknown7);
+ size+=size_of_uint32( &info->unknown8);
+ size+=size_of_uint32( &info->unknown9);
+ size+=size_of_uint32( &info->session_counter);
+ size+=size_of_uint32( &info->unknown11);
+ size+=size_of_uint32( &info->printer_errors);
+ size+=size_of_uint32( &info->unknown13);
+ size+=size_of_uint32( &info->unknown14);
+ size+=size_of_uint32( &info->unknown15);
+ size+=size_of_uint32( &info->unknown16);
+ size+=size_of_uint32( &info->change_id);
+ size+=size_of_uint32( &info->unknown18);
+ size+=size_of_uint32( &info->status);
+ size+=size_of_uint32( &info->unknown20);
+ size+=size_of_uint32( &info->c_setprinter);
+
+ size+=size_of_uint16( &info->unknown22);
+ size+=size_of_uint16( &info->unknown23);
+ size+=size_of_uint16( &info->unknown24);
+ size+=size_of_uint16( &info->unknown25);
+ size+=size_of_uint16( &info->unknown26);
+ size+=size_of_uint16( &info->unknown27);
+ size+=size_of_uint16( &info->unknown28);
+ size+=size_of_uint16( &info->unknown29);
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_info_1(PRINTER_INFO_1 *info)
+{
+ int size=0;
+
+ size+=size_of_uint32( &info->flags );
+ size+=size_of_relative_string( &info->description );
+ size+=size_of_relative_string( &info->name );
+ size+=size_of_relative_string( &info->comment );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_info_2(PRINTER_INFO_2 *info)
+{
+ uint32 size=0;
+
+ size += 4;
+
+ size += ndr_size_security_descriptor( info->secdesc, 0 );
+
+ size+=size_of_device_mode( info->devmode );
+
+ size+=size_of_relative_string( &info->servername );
+ size+=size_of_relative_string( &info->printername );
+ size+=size_of_relative_string( &info->sharename );
+ size+=size_of_relative_string( &info->portname );
+ size+=size_of_relative_string( &info->drivername );
+ size+=size_of_relative_string( &info->comment );
+ size+=size_of_relative_string( &info->location );
+
+ size+=size_of_relative_string( &info->sepfile );
+ size+=size_of_relative_string( &info->printprocessor );
+ size+=size_of_relative_string( &info->datatype );
+ size+=size_of_relative_string( &info->parameters );
+
+ size+=size_of_uint32( &info->attributes );
+ size+=size_of_uint32( &info->priority );
+ size+=size_of_uint32( &info->defaultpriority );
+ size+=size_of_uint32( &info->starttime );
+ size+=size_of_uint32( &info->untiltime );
+ size+=size_of_uint32( &info->status );
+ size+=size_of_uint32( &info->cjobs );
+ size+=size_of_uint32( &info->averageppm );
+
+ /*
+ * add any adjustments for alignment. This is
+ * not optimal since we could be calling this
+ * function from a loop (e.g. enumprinters), but
+ * it is easier to maintain the calculation here and
+ * not place the burden on the caller to remember. --jerry
+ */
+ if ((size % 4) != 0)
+ size += 4 - (size % 4);
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_info_4(PRINTER_INFO_4 *info)
+{
+ uint32 size=0;
+
+ size+=size_of_relative_string( &info->printername );
+ size+=size_of_relative_string( &info->servername );
+
+ size+=size_of_uint32( &info->attributes );
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_info_5(PRINTER_INFO_5 *info)
+{
+ uint32 size=0;
+
+ size+=size_of_relative_string( &info->printername );
+ size+=size_of_relative_string( &info->portname );
+
+ size+=size_of_uint32( &info->attributes );
+ size+=size_of_uint32( &info->device_not_selected_timeout );
+ size+=size_of_uint32( &info->transmission_retry_timeout );
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_info_6(PRINTER_INFO_6 *info)
+{
+ return sizeof(uint32);
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_info_3(PRINTER_INFO_3 *info)
+{
+ /* The 8 is for the self relative pointer - 8 byte aligned.. */
+ return 8 + (uint32)ndr_size_security_descriptor( info->secdesc, 0 );
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_info_7(PRINTER_INFO_7 *info)
+{
+ uint32 size=0;
+
+ size+=size_of_relative_string( &info->guid );
+ size+=size_of_uint32( &info->action );
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_driver_info_1(DRIVER_INFO_1 *info)
+{
+ int size=0;
+ size+=size_of_relative_string( &info->name );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_driver_info_2(DRIVER_INFO_2 *info)
+{
+ int size=0;
+ size+=size_of_uint32( &info->version );
+ size+=size_of_relative_string( &info->name );
+ size+=size_of_relative_string( &info->architecture );
+ size+=size_of_relative_string( &info->driverpath );
+ size+=size_of_relative_string( &info->datafile );
+ size+=size_of_relative_string( &info->configfile );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a string array.
+********************************************************************/
+
+uint32 spoolss_size_string_array(uint16 *string)
+{
+ uint32 i = 0;
+
+ if (string) {
+ for (i=0; (string[i]!=0x0000) || (string[i+1]!=0x0000); i++);
+ }
+ i=i+2; /* to count all chars including the leading zero */
+ i=2*i; /* because we need the value in bytes */
+ i=i+4; /* the offset pointer size */
+
+ return i;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_driver_info_3(DRIVER_INFO_3 *info)
+{
+ int size=0;
+
+ size+=size_of_uint32( &info->version );
+ size+=size_of_relative_string( &info->name );
+ size+=size_of_relative_string( &info->architecture );
+ size+=size_of_relative_string( &info->driverpath );
+ size+=size_of_relative_string( &info->datafile );
+ size+=size_of_relative_string( &info->configfile );
+ size+=size_of_relative_string( &info->helpfile );
+ size+=size_of_relative_string( &info->monitorname );
+ size+=size_of_relative_string( &info->defaultdatatype );
+
+ size+=spoolss_size_string_array(info->dependentfiles);
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_driver_info_6(DRIVER_INFO_6 *info)
+{
+ uint32 size=0;
+
+ size+=size_of_uint32( &info->version );
+ size+=size_of_relative_string( &info->name );
+ size+=size_of_relative_string( &info->architecture );
+ size+=size_of_relative_string( &info->driverpath );
+ size+=size_of_relative_string( &info->datafile );
+ size+=size_of_relative_string( &info->configfile );
+ size+=size_of_relative_string( &info->helpfile );
+
+ size+=spoolss_size_string_array(info->dependentfiles);
+
+ size+=size_of_relative_string( &info->monitorname );
+ size+=size_of_relative_string( &info->defaultdatatype );
+
+ size+=spoolss_size_string_array(info->previousdrivernames);
+
+ size+=size_of_nttime(&info->driver_date);
+ size+=size_of_uint32( &info->padding );
+ size+=size_of_uint32( &info->driver_version_low );
+ size+=size_of_uint32( &info->driver_version_high );
+ size+=size_of_relative_string( &info->mfgname );
+ size+=size_of_relative_string( &info->oem_url );
+ size+=size_of_relative_string( &info->hardware_id );
+ size+=size_of_relative_string( &info->provider );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_job_info_1(JOB_INFO_1 *info)
+{
+ int size=0;
+ size+=size_of_uint32( &info->jobid );
+ size+=size_of_relative_string( &info->printername );
+ size+=size_of_relative_string( &info->machinename );
+ size+=size_of_relative_string( &info->username );
+ size+=size_of_relative_string( &info->document );
+ size+=size_of_relative_string( &info->datatype );
+ size+=size_of_relative_string( &info->text_status );
+ size+=size_of_uint32( &info->status );
+ size+=size_of_uint32( &info->priority );
+ size+=size_of_uint32( &info->position );
+ size+=size_of_uint32( &info->totalpages );
+ size+=size_of_uint32( &info->pagesprinted );
+ size+=size_of_systemtime( &info->submitted );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_job_info_2(JOB_INFO_2 *info)
+{
+ int size=0;
+
+ size+=4; /* size of sec desc ptr */
+
+ size+=size_of_uint32( &info->jobid );
+ size+=size_of_relative_string( &info->printername );
+ size+=size_of_relative_string( &info->machinename );
+ size+=size_of_relative_string( &info->username );
+ size+=size_of_relative_string( &info->document );
+ size+=size_of_relative_string( &info->notifyname );
+ size+=size_of_relative_string( &info->datatype );
+ size+=size_of_relative_string( &info->printprocessor );
+ size+=size_of_relative_string( &info->parameters );
+ size+=size_of_relative_string( &info->drivername );
+ size+=size_of_device_mode( info->devmode );
+ size+=size_of_relative_string( &info->text_status );
+/* SEC_DESC sec_desc;*/
+ size+=size_of_uint32( &info->status );
+ size+=size_of_uint32( &info->priority );
+ size+=size_of_uint32( &info->position );
+ size+=size_of_uint32( &info->starttime );
+ size+=size_of_uint32( &info->untiltime );
+ size+=size_of_uint32( &info->totalpages );
+ size+=size_of_uint32( &info->size );
+ size+=size_of_systemtime( &info->submitted );
+ size+=size_of_uint32( &info->timeelapsed );
+ size+=size_of_uint32( &info->pagesprinted );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_form_1(FORM_1 *info)
+{
+ int size=0;
+
+ size+=size_of_uint32( &info->flag );
+ size+=size_of_relative_string( &info->name );
+ size+=size_of_uint32( &info->width );
+ size+=size_of_uint32( &info->length );
+ size+=size_of_uint32( &info->left );
+ size+=size_of_uint32( &info->top );
+ size+=size_of_uint32( &info->right );
+ size+=size_of_uint32( &info->bottom );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_port_info_1(PORT_INFO_1 *info)
+{
+ int size=0;
+
+ size+=size_of_relative_string( &info->port_name );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_driverdir_info_1(DRIVER_DIRECTORY_1 *info)
+{
+ int size=0;
+
+ size=str_len_uni(&info->name); /* the string length */
+ size=size+1; /* add the leading zero */
+ size=size*2; /* convert in char */
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printprocessordirectory_info_1(PRINTPROCESSOR_DIRECTORY_1 *info)
+{
+ int size=0;
+
+ size=str_len_uni(&info->name); /* the string length */
+ size=size+1; /* add the leading zero */
+ size=size*2; /* convert in char */
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_port_info_2(PORT_INFO_2 *info)
+{
+ int size=0;
+
+ size+=size_of_relative_string( &info->port_name );
+ size+=size_of_relative_string( &info->monitor_name );
+ size+=size_of_relative_string( &info->description );
+
+ size+=size_of_uint32( &info->port_type );
+ size+=size_of_uint32( &info->reserved );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printprocessor_info_1(PRINTPROCESSOR_1 *info)
+{
+ int size=0;
+ size+=size_of_relative_string( &info->name );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printprocdatatype_info_1(PRINTPROCDATATYPE_1 *info)
+{
+ int size=0;
+ size+=size_of_relative_string( &info->name );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+uint32 spoolss_size_printer_enum_values(PRINTER_ENUM_VALUES *p)
+{
+ uint32 size = 0;
+
+ if (!p)
+ return 0;
+
+ /* uint32(offset) + uint32(length) + length) */
+ size += (size_of_uint32(&p->value_len)*2) + p->value_len;
+ size += (size_of_uint32(&p->data_len)*2) + p->data_len + (p->data_len%2) ;
+
+ size += size_of_uint32(&p->type);
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printmonitor_info_1(PRINTMONITOR_1 *info)
+{
+ int size=0;
+ size+=size_of_relative_string( &info->name );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printmonitor_info_2(PRINTMONITOR_2 *info)
+{
+ int size=0;
+ size+=size_of_relative_string( &info->name);
+ size+=size_of_relative_string( &info->environment);
+ size+=size_of_relative_string( &info->dll_name);
+
+ return size;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_getprinterdriver2(SPOOL_Q_GETPRINTERDRIVER2 *q_u,
+ const POLICY_HND *hnd,
+ const fstring architecture,
+ uint32 level, uint32 clientmajor, uint32 clientminor,
+ RPC_BUFFER *buffer, uint32 offered)
+{
+ if (q_u == NULL)
+ return False;
+
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+
+ init_buf_unistr2(&q_u->architecture, &q_u->architecture_ptr, architecture);
+
+ q_u->level=level;
+ q_u->clientmajorversion=clientmajor;
+ q_u->clientminorversion=clientminor;
+
+ q_u->buffer=buffer;
+ q_u->offered=offered;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_getprinterdriver2 (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_getprinterdriver2(const char *desc, SPOOL_Q_GETPRINTERDRIVER2 *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_getprinterdriver2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if(!prs_uint32("architecture_ptr", ps, depth, &q_u->architecture_ptr))
+ return False;
+ if(!smb_io_unistr2("architecture", &q_u->architecture, q_u->architecture_ptr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!prs_rpcbuffer_p("", ps, depth, &q_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ if(!prs_uint32("clientmajorversion", ps, depth, &q_u->clientmajorversion))
+ return False;
+ if(!prs_uint32("clientminorversion", ps, depth, &q_u->clientminorversion))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_getprinterdriver2 (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_getprinterdriver2(const char *desc, SPOOL_R_GETPRINTERDRIVER2 *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_getprinterdriver2");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+ if (!prs_uint32("servermajorversion", ps, depth, &r_u->servermajorversion))
+ return False;
+ if (!prs_uint32("serverminorversion", ps, depth, &r_u->serverminorversion))
+ return False;
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_enumprinters(
+ SPOOL_Q_ENUMPRINTERS *q_u,
+ uint32 flags,
+ char *servername,
+ uint32 level,
+ RPC_BUFFER *buffer,
+ uint32 offered
+)
+{
+ q_u->flags=flags;
+
+ q_u->servername_ptr = (servername != NULL) ? 1 : 0;
+ init_buf_unistr2(&q_u->servername, &q_u->servername_ptr, servername);
+
+ q_u->level=level;
+ q_u->buffer=buffer;
+ q_u->offered=offered;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_enumports(SPOOL_Q_ENUMPORTS *q_u,
+ fstring servername, uint32 level,
+ RPC_BUFFER *buffer, uint32 offered)
+{
+ q_u->name_ptr = (servername != NULL) ? 1 : 0;
+ init_buf_unistr2(&q_u->name, &q_u->name_ptr, servername);
+
+ q_u->level=level;
+ q_u->buffer=buffer;
+ q_u->offered=offered;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_enumprinters (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_enumprinters(const char *desc, SPOOL_Q_ENUMPRINTERS *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumprinters");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("flags", ps, depth, &q_u->flags))
+ return False;
+ if (!prs_uint32("servername_ptr", ps, depth, &q_u->servername_ptr))
+ return False;
+
+ if (!smb_io_unistr2("", &q_u->servername, q_u->servername_ptr, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_ENUMPRINTERS structure.
+ ********************************************************************/
+
+bool spoolss_io_r_enumprinters(const char *desc, SPOOL_R_ENUMPRINTERS *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumprinters");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_enum_printers (srv_spoolss.c)
+ *
+ ********************************************************************/
+
+bool spoolss_io_r_getprinter(const char *desc, SPOOL_R_GETPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_getprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_getprinter (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_getprinter(const char *desc, SPOOL_Q_GETPRINTER *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_getprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_getprinter(
+ TALLOC_CTX *mem_ctx,
+ SPOOL_Q_GETPRINTER *q_u,
+ const POLICY_HND *hnd,
+ uint32 level,
+ RPC_BUFFER *buffer,
+ uint32 offered
+)
+{
+ if (q_u == NULL)
+ {
+ return False;
+ }
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+
+ q_u->level=level;
+ q_u->buffer=buffer;
+ q_u->offered=offered;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+bool make_spoolss_q_setprinter(TALLOC_CTX *mem_ctx, SPOOL_Q_SETPRINTER *q_u,
+ const POLICY_HND *hnd, uint32 level, PRINTER_INFO_CTR *info,
+ uint32 command)
+{
+ SEC_DESC *secdesc;
+ DEVICEMODE *devmode;
+
+ if (!q_u || !info)
+ return False;
+
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+
+ q_u->level = level;
+ q_u->info.level = level;
+ q_u->info.info_ptr = 1; /* Info is != NULL, see above */
+ switch (level) {
+
+ /* There's no such thing as a setprinter level 1 */
+
+ case 2:
+ secdesc = info->printers_2->secdesc;
+ devmode = info->printers_2->devmode;
+
+ make_spoolss_printer_info_2 (mem_ctx, &q_u->info.info_2, info->printers_2);
+#if 1 /* JERRY TEST */
+ q_u->secdesc_ctr = SMB_MALLOC_P(SEC_DESC_BUF);
+ if (!q_u->secdesc_ctr)
+ return False;
+ q_u->secdesc_ctr->sd = secdesc;
+ q_u->secdesc_ctr->sd_size = (secdesc) ? sizeof(SEC_DESC) + (2*sizeof(uint32)) : 0;
+
+ q_u->devmode_ctr.devmode_ptr = (devmode != NULL) ? 1 : 0;
+ q_u->devmode_ctr.size = (devmode != NULL) ? sizeof(DEVICEMODE) + (3*sizeof(uint32)) : 0;
+ q_u->devmode_ctr.devmode = devmode;
+#else
+ q_u->secdesc_ctr = NULL;
+
+ q_u->devmode_ctr.devmode_ptr = 0;
+ q_u->devmode_ctr.size = 0;
+ q_u->devmode_ctr.devmode = NULL;
+#endif
+ break;
+ case 3:
+ secdesc = info->printers_3->secdesc;
+
+ make_spoolss_printer_info_3 (mem_ctx, &q_u->info.info_3, info->printers_3);
+
+ q_u->secdesc_ctr = SMB_MALLOC_P(SEC_DESC_BUF);
+ if (!q_u->secdesc_ctr)
+ return False;
+ q_u->secdesc_ctr->sd_size = (secdesc) ? sizeof(SEC_DESC) + (2*sizeof(uint32)) : 0;
+ q_u->secdesc_ctr->sd = secdesc;
+
+ break;
+ case 7:
+ make_spoolss_printer_info_7 (mem_ctx, &q_u->info.info_7, info->printers_7);
+ break;
+
+ default:
+ DEBUG(0,("make_spoolss_q_setprinter: Unknown info level [%d]\n", level));
+ break;
+ }
+
+
+ q_u->command = command;
+
+ return True;
+}
+
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_setprinter(const char *desc, SPOOL_R_SETPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_setprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Marshall/unmarshall a SPOOL_Q_SETPRINTER struct.
+********************************************************************/
+
+bool spoolss_io_q_setprinter(const char *desc, SPOOL_Q_SETPRINTER *q_u, prs_struct *ps, int depth)
+{
+ uint32 ptr_sec_desc = 0;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_setprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle ,ps, depth))
+ return False;
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ /* check for supported levels and structures we know about */
+
+ switch ( q_u->level ) {
+ case 0:
+ case 2:
+ case 3:
+ case 7:
+ /* supported levels */
+ break;
+ default:
+ DEBUG(0,("spoolss_io_q_setprinter: unsupported printer info level [%d]\n",
+ q_u->level));
+ return True;
+ }
+
+
+ if(!spool_io_printer_info_level("", &q_u->info, ps, depth))
+ return False;
+
+ if (!spoolss_io_devmode_cont(desc, &q_u->devmode_ctr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ switch (q_u->level)
+ {
+ case 2:
+ {
+ ptr_sec_desc = q_u->info.info_2->secdesc_ptr;
+ break;
+ }
+ case 3:
+ {
+ /* FIXME ! Our parsing here is wrong I think,
+ * but for a level3 it makes no sense for
+ * ptr_sec_desc to be NULL. JRA. Based on
+ * a Vista sniff from Martin Zielinski <mz@seh.de>.
+ */
+ if (UNMARSHALLING(ps)) {
+ ptr_sec_desc = 1;
+ } else {
+ ptr_sec_desc = q_u->info.info_3->secdesc_ptr;
+ }
+ break;
+ }
+ }
+ if (ptr_sec_desc)
+ {
+ if (!sec_io_desc_buf(desc, &q_u->secdesc_ctr, ps, depth))
+ return False;
+ } else {
+ uint32 dummy = 0;
+
+ /* Parse a NULL security descriptor. This should really
+ happen inside the sec_io_desc_buf() function. */
+
+ prs_debug(ps, depth, "", "sec_io_desc_buf");
+ if (!prs_uint32("size", ps, depth + 1, &dummy))
+ return False;
+ if (!prs_uint32("ptr", ps, depth + 1, &dummy))
+ return False;
+ }
+
+ if(!prs_uint32("command", ps, depth, &q_u->command))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_fcpn(const char *desc, SPOOL_R_FCPN *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_fcpn");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_fcpn(const char *desc, SPOOL_Q_FCPN *q_u, prs_struct *ps, int depth)
+{
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_fcpn");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_addjob(const char *desc, SPOOL_R_ADDJOB *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_rpcbuffer_p("", ps, depth, &r_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_addjob(const char *desc, SPOOL_Q_ADDJOB *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!prs_rpcbuffer_p("", ps, depth, &q_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_enumjobs(const char *desc, SPOOL_R_ENUMJOBS *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumjobs");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool make_spoolss_q_enumjobs(SPOOL_Q_ENUMJOBS *q_u, const POLICY_HND *hnd,
+ uint32 firstjob,
+ uint32 numofjobs,
+ uint32 level,
+ RPC_BUFFER *buffer,
+ uint32 offered)
+{
+ if (q_u == NULL)
+ {
+ return False;
+ }
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+ q_u->firstjob = firstjob;
+ q_u->numofjobs = numofjobs;
+ q_u->level = level;
+ q_u->buffer= buffer;
+ q_u->offered = offered;
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_enumjobs(const char *desc, SPOOL_Q_ENUMJOBS *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumjobs");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle, ps, depth))
+ return False;
+
+ if (!prs_uint32("firstjob", ps, depth, &q_u->firstjob))
+ return False;
+ if (!prs_uint32("numofjobs", ps, depth, &q_u->numofjobs))
+ return False;
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &q_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_schedulejob(const char *desc, SPOOL_R_SCHEDULEJOB *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_schedulejob");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_schedulejob(const char *desc, SPOOL_Q_SCHEDULEJOB *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_schedulejob");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if(!prs_uint32("jobid", ps, depth, &q_u->jobid))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_setjob(const char *desc, SPOOL_R_SETJOB *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_setjob");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_setjob(const char *desc, SPOOL_Q_SETJOB *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_setjob");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if(!prs_uint32("jobid", ps, depth, &q_u->jobid))
+ return False;
+ /*
+ * level is usually 0. If (level!=0) then I'm in trouble !
+ * I will try to generate setjob command with level!=0, one day.
+ */
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+ if(!prs_uint32("command", ps, depth, &q_u->command))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_ENUMPRINTERDRIVERS structure.
+********************************************************************/
+
+bool spoolss_io_r_enumprinterdrivers(const char *desc, SPOOL_R_ENUMPRINTERDRIVERS *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumprinterdrivers");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_enumprinterdrivers(SPOOL_Q_ENUMPRINTERDRIVERS *q_u,
+ const char *name,
+ const char *environment,
+ uint32 level,
+ RPC_BUFFER *buffer, uint32 offered)
+{
+ init_buf_unistr2(&q_u->name, &q_u->name_ptr, name);
+ init_buf_unistr2(&q_u->environment, &q_u->environment_ptr, environment);
+
+ q_u->level=level;
+ q_u->buffer=buffer;
+ q_u->offered=offered;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_Q_ENUMPRINTERDRIVERS structure.
+********************************************************************/
+
+bool spoolss_io_q_enumprinterdrivers(const char *desc, SPOOL_Q_ENUMPRINTERDRIVERS *q_u, prs_struct *ps, int depth)
+{
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumprinterdrivers");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("name_ptr", ps, depth, &q_u->name_ptr))
+ return False;
+ if (!smb_io_unistr2("", &q_u->name, q_u->name_ptr,ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("environment_ptr", ps, depth, &q_u->environment_ptr))
+ return False;
+ if (!smb_io_unistr2("", &q_u->environment, q_u->environment_ptr, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_enumforms(const char *desc, SPOOL_Q_ENUMFORMS *q_u, prs_struct *ps, int depth)
+{
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumforms");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_enumforms(const char *desc, SPOOL_R_ENUMFORMS *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumforms");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("size of buffer needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_uint32("numofforms", ps, depth, &r_u->numofforms))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_getform(const char *desc, SPOOL_Q_GETFORM *q_u, prs_struct *ps, int depth)
+{
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_getform");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if (!smb_io_unistr2("", &q_u->formname,True,ps,depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_getform(const char *desc, SPOOL_R_GETFORM *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_getform");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("size of buffer needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_ENUMPORTS structure.
+********************************************************************/
+
+bool spoolss_io_r_enumports(const char *desc, SPOOL_R_ENUMPORTS *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumports");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_enumports(const char *desc, SPOOL_Q_ENUMPORTS *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("", ps, depth, &q_u->name_ptr))
+ return False;
+ if (!smb_io_unistr2("", &q_u->name,True,ps,depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_PRINTER_INFO_LEVEL_1 structure.
+********************************************************************/
+
+bool spool_io_printer_info_level_1(const char *desc, SPOOL_PRINTER_INFO_LEVEL_1 *il, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spool_io_printer_info_level_1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("flags", ps, depth, &il->flags))
+ return False;
+ if(!prs_uint32("description_ptr", ps, depth, &il->description_ptr))
+ return False;
+ if(!prs_uint32("name_ptr", ps, depth, &il->name_ptr))
+ return False;
+ if(!prs_uint32("comment_ptr", ps, depth, &il->comment_ptr))
+ return False;
+
+ if(!smb_io_unistr2("description", &il->description, il->description_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("name", &il->name, il->name_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("comment", &il->comment, il->comment_ptr, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_PRINTER_INFO_LEVEL_3 structure.
+********************************************************************/
+
+bool spool_io_printer_info_level_3(const char *desc, SPOOL_PRINTER_INFO_LEVEL_3 *il, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spool_io_printer_info_level_3");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("secdesc_ptr", ps, depth, &il->secdesc_ptr))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_PRINTER_INFO_LEVEL_2 structure.
+********************************************************************/
+
+bool spool_io_printer_info_level_2(const char *desc, SPOOL_PRINTER_INFO_LEVEL_2 *il, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spool_io_printer_info_level_2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("servername_ptr", ps, depth, &il->servername_ptr))
+ return False;
+ if(!prs_uint32("printername_ptr", ps, depth, &il->printername_ptr))
+ return False;
+ if(!prs_uint32("sharename_ptr", ps, depth, &il->sharename_ptr))
+ return False;
+ if(!prs_uint32("portname_ptr", ps, depth, &il->portname_ptr))
+ return False;
+
+ if(!prs_uint32("drivername_ptr", ps, depth, &il->drivername_ptr))
+ return False;
+ if(!prs_uint32("comment_ptr", ps, depth, &il->comment_ptr))
+ return False;
+ if(!prs_uint32("location_ptr", ps, depth, &il->location_ptr))
+ return False;
+ if(!prs_uint32("devmode_ptr", ps, depth, &il->devmode_ptr))
+ return False;
+ if(!prs_uint32("sepfile_ptr", ps, depth, &il->sepfile_ptr))
+ return False;
+ if(!prs_uint32("printprocessor_ptr", ps, depth, &il->printprocessor_ptr))
+ return False;
+ if(!prs_uint32("datatype_ptr", ps, depth, &il->datatype_ptr))
+ return False;
+ if(!prs_uint32("parameters_ptr", ps, depth, &il->parameters_ptr))
+ return False;
+ if(!prs_uint32("secdesc_ptr", ps, depth, &il->secdesc_ptr))
+ return False;
+
+ if(!prs_uint32("attributes", ps, depth, &il->attributes))
+ return False;
+ if(!prs_uint32("priority", ps, depth, &il->priority))
+ return False;
+ if(!prs_uint32("default_priority", ps, depth, &il->default_priority))
+ return False;
+ if(!prs_uint32("starttime", ps, depth, &il->starttime))
+ return False;
+ if(!prs_uint32("untiltime", ps, depth, &il->untiltime))
+ return False;
+ if(!prs_uint32("status", ps, depth, &il->status))
+ return False;
+ if(!prs_uint32("cjobs", ps, depth, &il->cjobs))
+ return False;
+ if(!prs_uint32("averageppm", ps, depth, &il->averageppm))
+ return False;
+
+ if(!smb_io_unistr2("servername", &il->servername, il->servername_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("printername", &il->printername, il->printername_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("sharename", &il->sharename, il->sharename_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("portname", &il->portname, il->portname_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("drivername", &il->drivername, il->drivername_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("comment", &il->comment, il->comment_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("location", &il->location, il->location_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("sepfile", &il->sepfile, il->sepfile_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("printprocessor", &il->printprocessor, il->printprocessor_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("datatype", &il->datatype, il->datatype_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("parameters", &il->parameters, il->parameters_ptr, ps, depth))
+ return False;
+
+ return True;
+}
+
+bool spool_io_printer_info_level_7(const char *desc, SPOOL_PRINTER_INFO_LEVEL_7 *il, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spool_io_printer_info_level_7");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("guid_ptr", ps, depth, &il->guid_ptr))
+ return False;
+ if(!prs_uint32("action", ps, depth, &il->action))
+ return False;
+
+ if(!smb_io_unistr2("servername", &il->guid, il->guid_ptr, ps, depth))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spool_io_printer_info_level(const char *desc, SPOOL_PRINTER_INFO_LEVEL *il, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spool_io_printer_info_level");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("level", ps, depth, &il->level))
+ return False;
+ if(!prs_uint32("info_ptr", ps, depth, &il->info_ptr))
+ return False;
+
+ /* if no struct inside just return */
+ if (il->info_ptr==0) {
+ if (UNMARSHALLING(ps)) {
+ il->info_1=NULL;
+ il->info_2=NULL;
+ }
+ return True;
+ }
+
+ switch (il->level) {
+ /*
+ * level 0 is used by setprinter when managing the queue
+ * (hold, stop, start a queue)
+ */
+ case 0:
+ break;
+ /* DOCUMENT ME!!! What is level 1 used for? */
+ case 1:
+ {
+ if (UNMARSHALLING(ps)) {
+ if ((il->info_1=PRS_ALLOC_MEM(ps,SPOOL_PRINTER_INFO_LEVEL_1,1)) == NULL)
+ return False;
+ }
+ if (!spool_io_printer_info_level_1("", il->info_1, ps, depth))
+ return False;
+ break;
+ }
+ /*
+ * level 2 is used by addprinter
+ * and by setprinter when updating printer's info
+ */
+ case 2:
+ if (UNMARSHALLING(ps)) {
+ if ((il->info_2=PRS_ALLOC_MEM(ps,SPOOL_PRINTER_INFO_LEVEL_2,1)) == NULL)
+ return False;
+ }
+ if (!spool_io_printer_info_level_2("", il->info_2, ps, depth))
+ return False;
+ break;
+ /* DOCUMENT ME!!! What is level 3 used for? */
+ case 3:
+ {
+ if (UNMARSHALLING(ps)) {
+ if ((il->info_3=PRS_ALLOC_MEM(ps,SPOOL_PRINTER_INFO_LEVEL_3,1)) == NULL)
+ return False;
+ }
+ if (!spool_io_printer_info_level_3("", il->info_3, ps, depth))
+ return False;
+ break;
+ }
+ case 7:
+ if (UNMARSHALLING(ps))
+ if ((il->info_7=PRS_ALLOC_MEM(ps,SPOOL_PRINTER_INFO_LEVEL_7,1)) == NULL)
+ return False;
+ if (!spool_io_printer_info_level_7("", il->info_7, ps, depth))
+ return False;
+ break;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_addprinterex(const char *desc, SPOOL_Q_ADDPRINTEREX *q_u, prs_struct *ps, int depth)
+{
+ uint32 ptr_sec_desc = 0;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_addprinterex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!prs_io_unistr2_p("ptr", ps, depth, &q_u->server_name))
+ return False;
+ if (!prs_io_unistr2("servername", ps, depth, q_u->server_name))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("info_level", ps, depth, &q_u->level))
+ return False;
+
+ if(!spool_io_printer_info_level("", &q_u->info, ps, depth))
+ return False;
+
+ if (!spoolss_io_devmode_cont(desc, &q_u->devmode_ctr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ switch (q_u->level) {
+ case 2:
+ ptr_sec_desc = q_u->info.info_2->secdesc_ptr;
+ break;
+ case 3:
+ ptr_sec_desc = q_u->info.info_3->secdesc_ptr;
+ break;
+ }
+ if (ptr_sec_desc) {
+ if (!sec_io_desc_buf(desc, &q_u->secdesc_ctr, ps, depth))
+ return False;
+ } else {
+ uint32 dummy = 0;
+
+ /* Parse a NULL security descriptor. This should really
+ happen inside the sec_io_desc_buf() function. */
+
+ prs_debug(ps, depth, "", "sec_io_desc_buf");
+ if (!prs_uint32("size", ps, depth + 1, &dummy))
+ return False;
+ if (!prs_uint32("ptr", ps, depth + 1, &dummy))
+ return False;
+ }
+
+ if(!prs_uint32("user_switch", ps, depth, &q_u->user_switch))
+ return False;
+ if(!spool_io_user_level("", &q_u->user_ctr, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_addprinterex(const char *desc, SPOOL_R_ADDPRINTEREX *r_u,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_addprinterex");
+ depth++;
+
+ if(!smb_io_pol_hnd("printer handle",&r_u->handle,ps,depth))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spool_io_printer_driver_info_level_3(const char *desc, SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 **q_u,
+ prs_struct *ps, int depth)
+{
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 *il;
+
+ prs_debug(ps, depth, desc, "spool_io_printer_driver_info_level_3");
+ depth++;
+
+ /* reading */
+ if (UNMARSHALLING(ps)) {
+ il=PRS_ALLOC_MEM(ps,SPOOL_PRINTER_DRIVER_INFO_LEVEL_3,1);
+ if(il == NULL)
+ return False;
+ *q_u=il;
+ }
+ else {
+ il=*q_u;
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("cversion", ps, depth, &il->cversion))
+ return False;
+ if(!prs_uint32("name", ps, depth, &il->name_ptr))
+ return False;
+ if(!prs_uint32("environment", ps, depth, &il->environment_ptr))
+ return False;
+ if(!prs_uint32("driverpath", ps, depth, &il->driverpath_ptr))
+ return False;
+ if(!prs_uint32("datafile", ps, depth, &il->datafile_ptr))
+ return False;
+ if(!prs_uint32("configfile", ps, depth, &il->configfile_ptr))
+ return False;
+ if(!prs_uint32("helpfile", ps, depth, &il->helpfile_ptr))
+ return False;
+ if(!prs_uint32("monitorname", ps, depth, &il->monitorname_ptr))
+ return False;
+ if(!prs_uint32("defaultdatatype", ps, depth, &il->defaultdatatype_ptr))
+ return False;
+ if(!prs_uint32("dependentfilessize", ps, depth, &il->dependentfilessize))
+ return False;
+ if(!prs_uint32("dependentfiles", ps, depth, &il->dependentfiles_ptr))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("name", &il->name, il->name_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("environment", &il->environment, il->environment_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("driverpath", &il->driverpath, il->driverpath_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("datafile", &il->datafile, il->datafile_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("configfile", &il->configfile, il->configfile_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("helpfile", &il->helpfile, il->helpfile_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("monitorname", &il->monitorname, il->monitorname_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("defaultdatatype", &il->defaultdatatype, il->defaultdatatype_ptr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (il->dependentfiles_ptr)
+ smb_io_buffer5("", &il->dependentfiles, ps, depth);
+
+ return True;
+}
+
+/*******************************************************************
+parse a SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 structure
+********************************************************************/
+
+bool spool_io_printer_driver_info_level_6(const char *desc, SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 **q_u,
+ prs_struct *ps, int depth)
+{
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 *il;
+
+ prs_debug(ps, depth, desc, "spool_io_printer_driver_info_level_6");
+ depth++;
+
+ /* reading */
+ if (UNMARSHALLING(ps)) {
+ il=PRS_ALLOC_MEM(ps,SPOOL_PRINTER_DRIVER_INFO_LEVEL_6,1);
+ if(il == NULL)
+ return False;
+ *q_u=il;
+ }
+ else {
+ il=*q_u;
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ /*
+ * I know this seems weird, but I have no other explanation.
+ * This is observed behavior on both NT4 and 2K servers.
+ * --jerry
+ */
+
+ if (!prs_align_uint64(ps))
+ return False;
+
+ /* parse the main elements the packet */
+
+ if(!prs_uint32("cversion ", ps, depth, &il->version))
+ return False;
+ if(!prs_uint32("name ", ps, depth, &il->name_ptr))
+ return False;
+ if(!prs_uint32("environment ", ps, depth, &il->environment_ptr))
+ return False;
+ if(!prs_uint32("driverpath ", ps, depth, &il->driverpath_ptr))
+ return False;
+ if(!prs_uint32("datafile ", ps, depth, &il->datafile_ptr))
+ return False;
+ if(!prs_uint32("configfile ", ps, depth, &il->configfile_ptr))
+ return False;
+ if(!prs_uint32("helpfile ", ps, depth, &il->helpfile_ptr))
+ return False;
+ if(!prs_uint32("monitorname ", ps, depth, &il->monitorname_ptr))
+ return False;
+ if(!prs_uint32("defaultdatatype", ps, depth, &il->defaultdatatype_ptr))
+ return False;
+ if(!prs_uint32("dependentfiles ", ps, depth, &il->dependentfiles_len))
+ return False;
+ if(!prs_uint32("dependentfiles ", ps, depth, &il->dependentfiles_ptr))
+ return False;
+ if(!prs_uint32("previousnames ", ps, depth, &il->previousnames_len))
+ return False;
+ if(!prs_uint32("previousnames ", ps, depth, &il->previousnames_ptr))
+ return False;
+ if(!smb_io_time("driverdate ", &il->driverdate, ps, depth))
+ return False;
+ if(!prs_uint32("dummy4 ", ps, depth, &il->dummy4))
+ return False;
+ if(!prs_uint64("driverversion ", ps, depth, &il->driverversion))
+ return False;
+ if(!prs_uint32("mfgname ", ps, depth, &il->mfgname_ptr))
+ return False;
+ if(!prs_uint32("oemurl ", ps, depth, &il->oemurl_ptr))
+ return False;
+ if(!prs_uint32("hardwareid ", ps, depth, &il->hardwareid_ptr))
+ return False;
+ if(!prs_uint32("provider ", ps, depth, &il->provider_ptr))
+ return False;
+
+ /* parse the structures in the packet */
+
+ if(!smb_io_unistr2("name", &il->name, il->name_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("environment", &il->environment, il->environment_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("driverpath", &il->driverpath, il->driverpath_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("datafile", &il->datafile, il->datafile_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("configfile", &il->configfile, il->configfile_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("helpfile", &il->helpfile, il->helpfile_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("monitorname", &il->monitorname, il->monitorname_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("defaultdatatype", &il->defaultdatatype, il->defaultdatatype_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if (il->dependentfiles_ptr) {
+ if(!smb_io_buffer5("dependentfiles", &il->dependentfiles, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+ if (il->previousnames_ptr) {
+ if(!smb_io_buffer5("previousnames", &il->previousnames, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+ if(!smb_io_unistr2("mfgname", &il->mfgname, il->mfgname_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("oemurl", &il->oemurl, il->oemurl_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("hardwareid", &il->hardwareid, il->hardwareid_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("provider", &il->provider, il->provider_ptr, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ convert a buffer of UNICODE strings null terminated
+ the buffer is terminated by a NULL
+
+ convert to an dos codepage array (null terminated)
+
+ dynamically allocate memory
+
+********************************************************************/
+
+static bool uniarray_2_dosarray(BUFFER5 *buf5, fstring **ar)
+{
+ fstring f;
+ int n = 0;
+ char *src;
+
+ if (buf5==NULL)
+ return False;
+
+ src = (char *)buf5->buffer;
+ *ar = SMB_MALLOC_ARRAY(fstring, 1);
+ if (!*ar) {
+ return False;
+ }
+
+ while (src < ((char *)buf5->buffer) + buf5->buf_len*2) {
+ rpcstr_pull(f, src, sizeof(f)-1, -1, STR_TERMINATE);
+ src = skip_unibuf(src, 2*buf5->buf_len - PTR_DIFF(src,buf5->buffer));
+ *ar = SMB_REALLOC_ARRAY(*ar, fstring, n+2);
+ if (!*ar) {
+ return False;
+ }
+ fstrcpy((*ar)[n], f);
+ n++;
+ }
+
+ fstrcpy((*ar)[n], "");
+
+ return True;
+}
+
+/*******************************************************************
+ read a UNICODE array with null terminated strings
+ and null terminated array
+ and size of array at beginning
+********************************************************************/
+
+bool smb_io_unibuffer(const char *desc, UNISTR2 *buffer, prs_struct *ps, int depth)
+{
+ if (buffer==NULL) return False;
+
+ buffer->offset=0;
+ buffer->uni_str_len=buffer->uni_max_len;
+
+ if(!prs_uint32("buffer_size", ps, depth, &buffer->uni_max_len))
+ return False;
+
+ if(!prs_unistr2(True, "buffer ", ps, depth, buffer))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spool_io_printer_driver_info_level(const char *desc, SPOOL_PRINTER_DRIVER_INFO_LEVEL *il, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spool_io_printer_driver_info_level");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("level", ps, depth, &il->level))
+ return False;
+ if(!prs_uint32("ptr", ps, depth, &il->ptr))
+ return False;
+
+ if (il->ptr==0)
+ return True;
+
+ switch (il->level) {
+ case 3:
+ if(!spool_io_printer_driver_info_level_3("", &il->info_3, ps, depth))
+ return False;
+ break;
+ case 6:
+ if(!spool_io_printer_driver_info_level_6("", &il->info_6, ps, depth))
+ return False;
+ break;
+ default:
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ init a SPOOL_Q_ADDPRINTERDRIVER struct
+ ******************************************************************/
+
+bool make_spoolss_q_addprinterdriver(TALLOC_CTX *mem_ctx,
+ SPOOL_Q_ADDPRINTERDRIVER *q_u, const char* srv_name,
+ uint32 level, PRINTER_DRIVER_CTR *info)
+{
+ DEBUG(5,("make_spoolss_q_addprinterdriver\n"));
+
+ if (!srv_name || !info) {
+ return False;
+ }
+
+ q_u->server_name_ptr = 1; /* srv_name is != NULL, see above */
+ init_unistr2(&q_u->server_name, srv_name, UNI_STR_TERMINATE);
+
+ q_u->level = level;
+
+ q_u->info.level = level;
+ q_u->info.ptr = 1; /* Info is != NULL, see above */
+ switch (level)
+ {
+ /* info level 3 is supported by Windows 95/98, WinNT and Win2k */
+ case 3 :
+ make_spoolss_driver_info_3(mem_ctx, &q_u->info.info_3, info->info3);
+ break;
+
+ default:
+ DEBUG(0,("make_spoolss_q_addprinterdriver: Unknown info level [%d]\n", level));
+ break;
+ }
+
+ return True;
+}
+
+bool make_spoolss_driver_info_3(TALLOC_CTX *mem_ctx,
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 **spool_drv_info,
+ DRIVER_INFO_3 *info3)
+{
+ uint32 len = 0;
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 *inf;
+
+ if (!(inf=TALLOC_ZERO_P(mem_ctx, SPOOL_PRINTER_DRIVER_INFO_LEVEL_3)))
+ return False;
+
+ inf->cversion = info3->version;
+ inf->name_ptr = (info3->name.buffer!=NULL)?1:0;
+ inf->environment_ptr = (info3->architecture.buffer!=NULL)?1:0;
+ inf->driverpath_ptr = (info3->driverpath.buffer!=NULL)?1:0;
+ inf->datafile_ptr = (info3->datafile.buffer!=NULL)?1:0;
+ inf->configfile_ptr = (info3->configfile.buffer!=NULL)?1:0;
+ inf->helpfile_ptr = (info3->helpfile.buffer!=NULL)?1:0;
+ inf->monitorname_ptr = (info3->monitorname.buffer!=NULL)?1:0;
+ inf->defaultdatatype_ptr = (info3->defaultdatatype.buffer!=NULL)?1:0;
+
+ init_unistr2_from_unistr(inf, &inf->name, &info3->name);
+ init_unistr2_from_unistr(inf, &inf->environment, &info3->architecture);
+ init_unistr2_from_unistr(inf, &inf->driverpath, &info3->driverpath);
+ init_unistr2_from_unistr(inf, &inf->datafile, &info3->datafile);
+ init_unistr2_from_unistr(inf, &inf->configfile, &info3->configfile);
+ init_unistr2_from_unistr(inf, &inf->helpfile, &info3->helpfile);
+ init_unistr2_from_unistr(inf, &inf->monitorname, &info3->monitorname);
+ init_unistr2_from_unistr(inf, &inf->defaultdatatype, &info3->defaultdatatype);
+
+ if (info3->dependentfiles) {
+ bool done = False;
+ bool null_char = False;
+ uint16 *ptr = info3->dependentfiles;
+
+ while (!done) {
+ switch (*ptr) {
+ case 0:
+ /* the null_char bool is used to help locate
+ two '\0's back to back */
+ if (null_char) {
+ done = True;
+ } else {
+ null_char = True;
+ }
+ break;
+
+ default:
+ null_char = False;
+ break;
+ }
+ len++;
+ ptr++;
+ }
+ }
+
+ inf->dependentfiles_ptr = (info3->dependentfiles != NULL) ? 1 : 0;
+ inf->dependentfilessize = (info3->dependentfiles != NULL) ? len : 0;
+ if(!make_spoolss_buffer5(mem_ctx, &inf->dependentfiles, len, info3->dependentfiles)) {
+ SAFE_FREE(inf);
+ return False;
+ }
+
+ *spool_drv_info = inf;
+
+ return True;
+}
+
+/*******************************************************************
+ make a BUFFER5 struct from a uint16*
+ ******************************************************************/
+
+bool make_spoolss_buffer5(TALLOC_CTX *mem_ctx, BUFFER5 *buf5, uint32 len, uint16 *src)
+{
+
+ buf5->buf_len = len;
+ if (src) {
+ if (len) {
+ if((buf5->buffer=(uint16*)TALLOC_MEMDUP(mem_ctx, src, sizeof(uint16)*len)) == NULL) {
+ DEBUG(0,("make_spoolss_buffer5: Unable to malloc memory for buffer!\n"));
+ return False;
+ }
+ } else {
+ buf5->buffer = NULL;
+ }
+ } else {
+ buf5->buffer=NULL;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ fill in the prs_struct for a ADDPRINTERDRIVER request PDU
+ ********************************************************************/
+
+bool spoolss_io_q_addprinterdriver(const char *desc, SPOOL_Q_ADDPRINTERDRIVER *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_addprinterdriver");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("server_name_ptr", ps, depth, &q_u->server_name_ptr))
+ return False;
+ if(!smb_io_unistr2("server_name", &q_u->server_name, q_u->server_name_ptr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("info_level", ps, depth, &q_u->level))
+ return False;
+
+ if(!spool_io_printer_driver_info_level("", &q_u->info, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_addprinterdriver(const char *desc, SPOOL_R_ADDPRINTERDRIVER *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_addprinterdriver");
+ depth++;
+
+ if(!prs_werror("status", ps, depth, &q_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ fill in the prs_struct for a ADDPRINTERDRIVER request PDU
+ ********************************************************************/
+
+bool spoolss_io_q_addprinterdriverex(const char *desc, SPOOL_Q_ADDPRINTERDRIVEREX *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_addprinterdriverex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("server_name_ptr", ps, depth, &q_u->server_name_ptr))
+ return False;
+ if(!smb_io_unistr2("server_name", &q_u->server_name, q_u->server_name_ptr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("info_level", ps, depth, &q_u->level))
+ return False;
+
+ if(!spool_io_printer_driver_info_level("", &q_u->info, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("copy flags", ps, depth, &q_u->copy_flags))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_addprinterdriverex(const char *desc, SPOOL_R_ADDPRINTERDRIVEREX *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_addprinterdriverex");
+ depth++;
+
+ if(!prs_werror("status", ps, depth, &q_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool uni_2_asc_printer_driver_3(SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 *uni,
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 **asc)
+{
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 *d;
+
+ DEBUG(7,("uni_2_asc_printer_driver_3: Converting from UNICODE to ASCII\n"));
+
+ if (*asc==NULL)
+ {
+ *asc=SMB_MALLOC_P(NT_PRINTER_DRIVER_INFO_LEVEL_3);
+ if(*asc == NULL)
+ return False;
+ ZERO_STRUCTP(*asc);
+ }
+
+ d=*asc;
+
+ d->cversion=uni->cversion;
+
+ unistr2_to_ascii(d->name, &uni->name, sizeof(d->name));
+ unistr2_to_ascii(d->environment, &uni->environment, sizeof(d->environment));
+ unistr2_to_ascii(d->driverpath, &uni->driverpath, sizeof(d->driverpath));
+ unistr2_to_ascii(d->datafile, &uni->datafile, sizeof(d->datafile));
+ unistr2_to_ascii(d->configfile, &uni->configfile, sizeof(d->configfile));
+ unistr2_to_ascii(d->helpfile, &uni->helpfile, sizeof(d->helpfile));
+ unistr2_to_ascii(d->monitorname, &uni->monitorname, sizeof(d->monitorname));
+ unistr2_to_ascii(d->defaultdatatype, &uni->defaultdatatype, sizeof(d->defaultdatatype));
+
+ DEBUGADD(8,( "version: %d\n", d->cversion));
+ DEBUGADD(8,( "name: %s\n", d->name));
+ DEBUGADD(8,( "environment: %s\n", d->environment));
+ DEBUGADD(8,( "driverpath: %s\n", d->driverpath));
+ DEBUGADD(8,( "datafile: %s\n", d->datafile));
+ DEBUGADD(8,( "configfile: %s\n", d->configfile));
+ DEBUGADD(8,( "helpfile: %s\n", d->helpfile));
+ DEBUGADD(8,( "monitorname: %s\n", d->monitorname));
+ DEBUGADD(8,( "defaultdatatype: %s\n", d->defaultdatatype));
+
+ if (uniarray_2_dosarray(&uni->dependentfiles, &d->dependentfiles ))
+ return True;
+
+ SAFE_FREE(*asc);
+ return False;
+}
+
+/*******************************************************************
+********************************************************************/
+bool uni_2_asc_printer_driver_6(SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 *uni,
+ NT_PRINTER_DRIVER_INFO_LEVEL_6 **asc)
+{
+ NT_PRINTER_DRIVER_INFO_LEVEL_6 *d;
+
+ DEBUG(7,("uni_2_asc_printer_driver_6: Converting from UNICODE to ASCII\n"));
+
+ if (*asc==NULL)
+ {
+ *asc=SMB_MALLOC_P(NT_PRINTER_DRIVER_INFO_LEVEL_6);
+ if(*asc == NULL)
+ return False;
+ ZERO_STRUCTP(*asc);
+ }
+
+ d=*asc;
+
+ d->version=uni->version;
+
+ unistr2_to_ascii(d->name, &uni->name, sizeof(d->name));
+ unistr2_to_ascii(d->environment, &uni->environment, sizeof(d->environment));
+ unistr2_to_ascii(d->driverpath, &uni->driverpath, sizeof(d->driverpath));
+ unistr2_to_ascii(d->datafile, &uni->datafile, sizeof(d->datafile));
+ unistr2_to_ascii(d->configfile, &uni->configfile, sizeof(d->configfile));
+ unistr2_to_ascii(d->helpfile, &uni->helpfile, sizeof(d->helpfile));
+ unistr2_to_ascii(d->monitorname, &uni->monitorname, sizeof(d->monitorname));
+ unistr2_to_ascii(d->defaultdatatype, &uni->defaultdatatype, sizeof(d->defaultdatatype));
+
+ DEBUGADD(8,( "version: %d\n", d->version));
+ DEBUGADD(8,( "name: %s\n", d->name));
+ DEBUGADD(8,( "environment: %s\n", d->environment));
+ DEBUGADD(8,( "driverpath: %s\n", d->driverpath));
+ DEBUGADD(8,( "datafile: %s\n", d->datafile));
+ DEBUGADD(8,( "configfile: %s\n", d->configfile));
+ DEBUGADD(8,( "helpfile: %s\n", d->helpfile));
+ DEBUGADD(8,( "monitorname: %s\n", d->monitorname));
+ DEBUGADD(8,( "defaultdatatype: %s\n", d->defaultdatatype));
+
+ if (!uniarray_2_dosarray(&uni->dependentfiles, &d->dependentfiles ))
+ goto error;
+ if (!uniarray_2_dosarray(&uni->previousnames, &d->previousnames ))
+ goto error;
+
+ return True;
+
+error:
+ SAFE_FREE(*asc);
+ return False;
+}
+
+bool uni_2_asc_printer_info_2(const SPOOL_PRINTER_INFO_LEVEL_2 *uni,
+ NT_PRINTER_INFO_LEVEL_2 *d)
+{
+ DEBUG(7,("Converting from UNICODE to ASCII\n"));
+
+ d->attributes=uni->attributes;
+ d->priority=uni->priority;
+ d->default_priority=uni->default_priority;
+ d->starttime=uni->starttime;
+ d->untiltime=uni->untiltime;
+ d->status=uni->status;
+ d->cjobs=uni->cjobs;
+
+ unistr2_to_ascii(d->servername, &uni->servername, sizeof(d->servername));
+ unistr2_to_ascii(d->printername, &uni->printername, sizeof(d->printername));
+ unistr2_to_ascii(d->sharename, &uni->sharename, sizeof(d->sharename));
+ unistr2_to_ascii(d->portname, &uni->portname, sizeof(d->portname));
+ unistr2_to_ascii(d->drivername, &uni->drivername, sizeof(d->drivername));
+ unistr2_to_ascii(d->comment, &uni->comment, sizeof(d->comment));
+ unistr2_to_ascii(d->location, &uni->location, sizeof(d->location));
+ unistr2_to_ascii(d->sepfile, &uni->sepfile, sizeof(d->sepfile));
+ unistr2_to_ascii(d->printprocessor, &uni->printprocessor, sizeof(d->printprocessor));
+ unistr2_to_ascii(d->datatype, &uni->datatype, sizeof(d->datatype));
+ unistr2_to_ascii(d->parameters, &uni->parameters, sizeof(d->parameters));
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_getprinterdriverdir(SPOOL_Q_GETPRINTERDRIVERDIR *q_u,
+ fstring servername, fstring env_name, uint32 level,
+ RPC_BUFFER *buffer, uint32 offered)
+{
+ init_buf_unistr2(&q_u->name, &q_u->name_ptr, servername);
+ init_buf_unistr2(&q_u->environment, &q_u->environment_ptr, env_name);
+
+ q_u->level=level;
+ q_u->buffer=buffer;
+ q_u->offered=offered;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_Q_GETPRINTERDRIVERDIR structure.
+********************************************************************/
+
+bool spoolss_io_q_getprinterdriverdir(const char *desc, SPOOL_Q_GETPRINTERDRIVERDIR *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_getprinterdriverdir");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("name_ptr", ps, depth, &q_u->name_ptr))
+ return False;
+ if(!smb_io_unistr2("", &q_u->name, q_u->name_ptr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("", ps, depth, &q_u->environment_ptr))
+ return False;
+ if(!smb_io_unistr2("", &q_u->environment, q_u->environment_ptr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!prs_rpcbuffer_p("", ps, depth, &q_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_GETPRINTERDRIVERDIR structure.
+********************************************************************/
+
+bool spoolss_io_r_getprinterdriverdir(const char *desc, SPOOL_R_GETPRINTERDRIVERDIR *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_getprinterdriverdir");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_enumprintprocessors(const char *desc, SPOOL_R_ENUMPRINTPROCESSORS *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumprintprocessors");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_enumprintprocessors(const char *desc, SPOOL_Q_ENUMPRINTPROCESSORS *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumprintprocessors");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("name_ptr", ps, depth, &q_u->name_ptr))
+ return False;
+ if (!smb_io_unistr2("name", &q_u->name, True, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("", ps, depth, &q_u->environment_ptr))
+ return False;
+ if (!smb_io_unistr2("", &q_u->environment, q_u->environment_ptr, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!prs_rpcbuffer_p("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_addprintprocessor(const char *desc, SPOOL_Q_ADDPRINTPROCESSOR *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_addprintprocessor");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("server_ptr", ps, depth, &q_u->server_ptr))
+ return False;
+ if (!smb_io_unistr2("server", &q_u->server, q_u->server_ptr, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_unistr2("environment", &q_u->environment, True, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_unistr2("path", &q_u->path, True, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_unistr2("name", &q_u->name, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_addprintprocessor(const char *desc, SPOOL_R_ADDPRINTPROCESSOR *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_addprintproicessor");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_enumprintprocdatatypes(const char *desc, SPOOL_R_ENUMPRINTPROCDATATYPES *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumprintprocdatatypes");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_enumprintprocdatatypes(const char *desc, SPOOL_Q_ENUMPRINTPROCDATATYPES *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumprintprocdatatypes");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("name_ptr", ps, depth, &q_u->name_ptr))
+ return False;
+ if (!smb_io_unistr2("name", &q_u->name, True, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("processor_ptr", ps, depth, &q_u->processor_ptr))
+ return False;
+ if (!smb_io_unistr2("processor", &q_u->processor, q_u->processor_ptr, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!prs_rpcbuffer_p("buffer", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_Q_ENUMPRINTMONITORS structure.
+********************************************************************/
+
+bool spoolss_io_q_enumprintmonitors(const char *desc, SPOOL_Q_ENUMPRINTMONITORS *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumprintmonitors");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("name_ptr", ps, depth, &q_u->name_ptr))
+ return False;
+ if (!smb_io_unistr2("name", &q_u->name, True, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!prs_rpcbuffer_p("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_enumprintmonitors(const char *desc, SPOOL_R_ENUMPRINTMONITORS *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumprintmonitors");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_enumprinterdata(const char *desc, SPOOL_R_ENUMPRINTERDATA *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumprinterdata");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("valuesize", ps, depth, &r_u->valuesize))
+ return False;
+
+ if (UNMARSHALLING(ps) && r_u->valuesize) {
+ r_u->value = PRS_ALLOC_MEM(ps, uint16, r_u->valuesize);
+ if (!r_u->value) {
+ DEBUG(0, ("spoolss_io_r_enumprinterdata: out of memory for printerdata value\n"));
+ return False;
+ }
+ }
+
+ if(!prs_uint16uni(False, "value", ps, depth, r_u->value, r_u->valuesize ))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("realvaluesize", ps, depth, &r_u->realvaluesize))
+ return False;
+
+ if(!prs_uint32("type", ps, depth, &r_u->type))
+ return False;
+
+ if(!prs_uint32("datasize", ps, depth, &r_u->datasize))
+ return False;
+
+ if (UNMARSHALLING(ps) && r_u->datasize) {
+ r_u->data = PRS_ALLOC_MEM(ps, uint8, r_u->datasize);
+ if (!r_u->data) {
+ DEBUG(0, ("spoolss_io_r_enumprinterdata: out of memory for printerdata data\n"));
+ return False;
+ }
+ }
+
+ if(!prs_uint8s(False, "data", ps, depth, r_u->data, r_u->datasize))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("realdatasize", ps, depth, &r_u->realdatasize))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_enumprinterdata(const char *desc, SPOOL_Q_ENUMPRINTERDATA *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumprinterdata");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if(!prs_uint32("index", ps, depth, &q_u->index))
+ return False;
+ if(!prs_uint32("valuesize", ps, depth, &q_u->valuesize))
+ return False;
+ if(!prs_uint32("datasize", ps, depth, &q_u->datasize))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool make_spoolss_q_enumprinterdata(SPOOL_Q_ENUMPRINTERDATA *q_u,
+ const POLICY_HND *hnd,
+ uint32 idx, uint32 valuelen, uint32 datalen)
+{
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+ q_u->index=idx;
+ q_u->valuesize=valuelen;
+ q_u->datasize=datalen;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool make_spoolss_q_enumprinterdataex(SPOOL_Q_ENUMPRINTERDATAEX *q_u,
+ const POLICY_HND *hnd, const char *key,
+ uint32 size)
+{
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+ init_unistr2(&q_u->key, key, UNI_STR_TERMINATE);
+ q_u->size = size;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+bool make_spoolss_q_setprinterdata(SPOOL_Q_SETPRINTERDATA *q_u, const POLICY_HND *hnd,
+ char* value, uint32 data_type, char* data, uint32 data_size)
+{
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+ q_u->type = data_type;
+ init_unistr2(&q_u->value, value, UNI_STR_TERMINATE);
+
+ q_u->max_len = q_u->real_len = data_size;
+ q_u->data = (unsigned char *)data;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+bool make_spoolss_q_setprinterdataex(SPOOL_Q_SETPRINTERDATAEX *q_u, const POLICY_HND *hnd,
+ char *key, char* value, uint32 data_type, char* data,
+ uint32 data_size)
+{
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+ q_u->type = data_type;
+ init_unistr2(&q_u->value, value, UNI_STR_TERMINATE);
+ init_unistr2(&q_u->key, key, UNI_STR_TERMINATE);
+
+ q_u->max_len = q_u->real_len = data_size;
+ q_u->data = (unsigned char *)data;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_setprinterdata(const char *desc, SPOOL_Q_SETPRINTERDATA *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_setprinterdata");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &q_u->value, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("type", ps, depth, &q_u->type))
+ return False;
+
+ if(!prs_uint32("max_len", ps, depth, &q_u->max_len))
+ return False;
+
+ switch (q_u->type)
+ {
+ case REG_SZ:
+ case REG_BINARY:
+ case REG_DWORD:
+ case REG_MULTI_SZ:
+ if (q_u->max_len) {
+ if (UNMARSHALLING(ps))
+ q_u->data=PRS_ALLOC_MEM(ps, uint8, q_u->max_len);
+ if(q_u->data == NULL)
+ return False;
+ if(!prs_uint8s(False,"data", ps, depth, q_u->data, q_u->max_len))
+ return False;
+ }
+ if(!prs_align(ps))
+ return False;
+ break;
+ }
+
+ if(!prs_uint32("real_len", ps, depth, &q_u->real_len))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_setprinterdata(const char *desc, SPOOL_R_SETPRINTERDATA *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_setprinterdata");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+bool spoolss_io_q_resetprinter(const char *desc, SPOOL_Q_RESETPRINTER *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_resetprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+
+ if (!prs_uint32("datatype_ptr", ps, depth, &q_u->datatype_ptr))
+ return False;
+
+ if (q_u->datatype_ptr) {
+ if (!smb_io_unistr2("datatype", &q_u->datatype, q_u->datatype_ptr?True:False, ps, depth))
+ return False;
+ }
+
+ if (!spoolss_io_devmode_cont(desc, &q_u->devmode_ctr, ps, depth))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+********************************************************************/
+bool spoolss_io_r_resetprinter(const char *desc, SPOOL_R_RESETPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_resetprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static bool spoolss_io_addform(const char *desc, FORM *f, uint32 ptr, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_addform");
+ depth++;
+ if(!prs_align(ps))
+ return False;
+
+ if (ptr!=0)
+ {
+ if(!prs_uint32("flags", ps, depth, &f->flags))
+ return False;
+ if(!prs_uint32("name_ptr", ps, depth, &f->name_ptr))
+ return False;
+ if(!prs_uint32("size_x", ps, depth, &f->size_x))
+ return False;
+ if(!prs_uint32("size_y", ps, depth, &f->size_y))
+ return False;
+ if(!prs_uint32("left", ps, depth, &f->left))
+ return False;
+ if(!prs_uint32("top", ps, depth, &f->top))
+ return False;
+ if(!prs_uint32("right", ps, depth, &f->right))
+ return False;
+ if(!prs_uint32("bottom", ps, depth, &f->bottom))
+ return False;
+
+ if(!smb_io_unistr2("", &f->name, f->name_ptr, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_deleteform(const char *desc, SPOOL_Q_DELETEFORM *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_deleteform");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if(!smb_io_unistr2("form name", &q_u->name, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_deleteform(const char *desc, SPOOL_R_DELETEFORM *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_deleteform");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_addform(const char *desc, SPOOL_Q_ADDFORM *q_u, prs_struct *ps, int depth)
+{
+ uint32 useless_ptr=1;
+ prs_debug(ps, depth, desc, "spoolss_io_q_addform");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+ if(!prs_uint32("level2", ps, depth, &q_u->level2))
+ return False;
+
+ if (q_u->level==1)
+ {
+ if(!prs_uint32("useless_ptr", ps, depth, &useless_ptr))
+ return False;
+ if(!spoolss_io_addform("", &q_u->form, useless_ptr, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_addform(const char *desc, SPOOL_R_ADDFORM *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_addform");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_q_setform(const char *desc, SPOOL_Q_SETFORM *q_u, prs_struct *ps, int depth)
+{
+ uint32 useless_ptr=1;
+ prs_debug(ps, depth, desc, "spoolss_io_q_setform");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &q_u->name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+ if(!prs_uint32("level2", ps, depth, &q_u->level2))
+ return False;
+
+ if (q_u->level==1)
+ {
+ if(!prs_uint32("useless_ptr", ps, depth, &useless_ptr))
+ return False;
+ if(!spoolss_io_addform("", &q_u->form, useless_ptr, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool spoolss_io_r_setform(const char *desc, SPOOL_R_SETFORM *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_setform");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_GETJOB structure.
+********************************************************************/
+
+bool spoolss_io_r_getjob(const char *desc, SPOOL_R_GETJOB *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_getjob");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_rpcbuffer_p("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_Q_GETJOB structure.
+********************************************************************/
+
+bool spoolss_io_q_getjob(const char *desc, SPOOL_Q_GETJOB *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if(!prs_uint32("jobid", ps, depth, &q_u->jobid))
+ return False;
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!prs_rpcbuffer_p("", ps, depth, &q_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+void free_devmode(DEVICEMODE *devmode)
+{
+ if (devmode!=NULL) {
+ SAFE_FREE(devmode->dev_private);
+ SAFE_FREE(devmode);
+ }
+}
+
+void free_printer_info_1(PRINTER_INFO_1 *printer)
+{
+ SAFE_FREE(printer);
+}
+
+void free_printer_info_2(PRINTER_INFO_2 *printer)
+{
+ if (printer!=NULL) {
+ free_devmode(printer->devmode);
+ printer->devmode = NULL;
+ SAFE_FREE(printer);
+ }
+}
+
+void free_printer_info_3(PRINTER_INFO_3 *printer)
+{
+ SAFE_FREE(printer);
+}
+
+void free_printer_info_4(PRINTER_INFO_4 *printer)
+{
+ SAFE_FREE(printer);
+}
+
+void free_printer_info_5(PRINTER_INFO_5 *printer)
+{
+ SAFE_FREE(printer);
+}
+
+void free_printer_info_6(PRINTER_INFO_6 *printer)
+{
+ SAFE_FREE(printer);
+}
+
+void free_printer_info_7(PRINTER_INFO_7 *printer)
+{
+ SAFE_FREE(printer);
+}
+
+void free_job_info_2(JOB_INFO_2 *job)
+{
+ if (job!=NULL)
+ free_devmode(job->devmode);
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_replyopenprinter(SPOOL_Q_REPLYOPENPRINTER *q_u,
+ const fstring string, uint32 printer, uint32 type)
+{
+ if (q_u == NULL)
+ return False;
+
+ init_unistr2(&q_u->string, string, UNI_STR_TERMINATE);
+
+ q_u->printer=printer;
+ q_u->type=type;
+
+ q_u->unknown0=0x0;
+ q_u->unknown1=0x0;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_Q_REPLYOPENPRINTER structure.
+********************************************************************/
+
+bool spoolss_io_q_replyopenprinter(const char *desc, SPOOL_Q_REPLYOPENPRINTER *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_replyopenprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("", &q_u->string, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("printer", ps, depth, &q_u->printer))
+ return False;
+ if(!prs_uint32("type", ps, depth, &q_u->type))
+ return False;
+
+ if(!prs_uint32("unknown0", ps, depth, &q_u->unknown0))
+ return False;
+ if(!prs_uint32("unknown1", ps, depth, &q_u->unknown1))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_REPLYOPENPRINTER structure.
+********************************************************************/
+
+bool spoolss_io_r_replyopenprinter(const char *desc, SPOOL_R_REPLYOPENPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_replyopenprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&r_u->handle,ps,depth))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+bool make_spoolss_q_routerreplyprinter(SPOOL_Q_ROUTERREPLYPRINTER *q_u, POLICY_HND *hnd,
+ uint32 condition, uint32 change_id)
+{
+
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+
+ q_u->condition = condition;
+ q_u->change_id = change_id;
+
+ /* magic values */
+ q_u->unknown1 = 0x1;
+ memset(q_u->unknown2, 0x0, 5);
+ q_u->unknown2[0] = 0x1;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_Q_ROUTERREPLYPRINTER structure.
+********************************************************************/
+bool spoolss_io_q_routerreplyprinter (const char *desc, SPOOL_Q_ROUTERREPLYPRINTER *q_u, prs_struct *ps, int depth)
+{
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_routerreplyprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ if (!prs_uint32("condition", ps, depth, &q_u->condition))
+ return False;
+
+ if (!prs_uint32("unknown1", ps, depth, &q_u->unknown1))
+ return False;
+
+ if (!prs_uint32("change_id", ps, depth, &q_u->change_id))
+ return False;
+
+ if (!prs_uint8s(False, "dev_private", ps, depth, q_u->unknown2, 5))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_ROUTERREPLYPRINTER structure.
+********************************************************************/
+bool spoolss_io_r_routerreplyprinter (const char *desc, SPOOL_R_ROUTERREPLYPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_routerreplyprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_reply_closeprinter(SPOOL_Q_REPLYCLOSEPRINTER *q_u, POLICY_HND *hnd)
+{
+ if (q_u == NULL)
+ return False;
+
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_Q_REPLYCLOSEPRINTER structure.
+********************************************************************/
+
+bool spoolss_io_q_replycloseprinter(const char *desc, SPOOL_Q_REPLYCLOSEPRINTER *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_replycloseprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_REPLYCLOSEPRINTER structure.
+********************************************************************/
+
+bool spoolss_io_r_replycloseprinter(const char *desc, SPOOL_R_REPLYCLOSEPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_replycloseprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&r_u->handle,ps,depth))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+#if 0 /* JERRY - not currently used but could be :-) */
+
+/*******************************************************************
+ Deep copy a SPOOL_NOTIFY_INFO_DATA structure
+ ******************************************************************/
+static bool copy_spool_notify_info_data(SPOOL_NOTIFY_INFO_DATA *dst,
+ SPOOL_NOTIFY_INFO_DATA *src, int n)
+{
+ int i;
+
+ memcpy(dst, src, sizeof(SPOOL_NOTIFY_INFO_DATA)*n);
+
+ for (i=0; i<n; i++) {
+ int len;
+ uint16 *s = NULL;
+
+ if (src->size != POINTER)
+ continue;
+ len = src->notify_data.data.length;
+ s = SMB_MALLOC_ARRAY(uint16, len);
+ if (s == NULL) {
+ DEBUG(0,("copy_spool_notify_info_data: malloc() failed!\n"));
+ return False;
+ }
+
+ memcpy(s, src->notify_data.data.string, len*2);
+ dst->notify_data.data.string = s;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Deep copy a SPOOL_NOTIFY_INFO structure
+ ******************************************************************/
+static bool copy_spool_notify_info(SPOOL_NOTIFY_INFO *dst, SPOOL_NOTIFY_INFO *src)
+{
+ if (!dst) {
+ DEBUG(0,("copy_spool_notify_info: NULL destination pointer!\n"));
+ return False;
+ }
+
+ dst->version = src->version;
+ dst->flags = src->flags;
+ dst->count = src->count;
+
+ if (dst->count)
+ {
+ dst->data = SMB_MALLOC_ARRAY(SPOOL_NOTIFY_INFO_DATA, dst->count);
+
+ DEBUG(10,("copy_spool_notify_info: allocating space for [%d] PRINTER_NOTIFY_INFO_DATA entries\n",
+ dst->count));
+
+ if (dst->data == NULL) {
+ DEBUG(0,("copy_spool_notify_info: malloc() failed for [%d] entries!\n",
+ dst->count));
+ return False;
+ }
+
+ return (copy_spool_notify_info_data(dst->data, src->data, src->count));
+ }
+
+ return True;
+}
+#endif /* JERRY */
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_reply_rrpcn(SPOOL_Q_REPLY_RRPCN *q_u, POLICY_HND *hnd,
+ uint32 change_low, uint32 change_high,
+ SPOOL_NOTIFY_INFO *info)
+{
+ if (q_u == NULL)
+ return False;
+
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+
+ q_u->change_low=change_low;
+ q_u->change_high=change_high;
+
+ q_u->unknown0=0x0;
+ q_u->unknown1=0x0;
+
+ q_u->info_ptr=0x0FF0ADDE;
+
+ q_u->info.version=2;
+
+ if (info->count) {
+ DEBUG(10,("make_spoolss_q_reply_rrpcn: [%d] PRINTER_NOTIFY_INFO_DATA\n",
+ info->count));
+ q_u->info.version = info->version;
+ q_u->info.flags = info->flags;
+ q_u->info.count = info->count;
+ /* pointer field - be careful! */
+ q_u->info.data = info->data;
+ }
+ else {
+ q_u->info.flags=PRINTER_NOTIFY_INFO_DISCARDED;
+ q_u->info.count=0;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_Q_REPLY_RRPCN structure.
+********************************************************************/
+
+bool spoolss_io_q_reply_rrpcn(const char *desc, SPOOL_Q_REPLY_RRPCN *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_reply_rrpcn");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ if (!prs_uint32("change_low", ps, depth, &q_u->change_low))
+ return False;
+
+ if (!prs_uint32("change_high", ps, depth, &q_u->change_high))
+ return False;
+
+ if (!prs_uint32("unknown0", ps, depth, &q_u->unknown0))
+ return False;
+
+ if (!prs_uint32("unknown1", ps, depth, &q_u->unknown1))
+ return False;
+
+ if (!prs_uint32("info_ptr", ps, depth, &q_u->info_ptr))
+ return False;
+
+ if(q_u->info_ptr!=0)
+ if(!smb_io_notify_info(desc, &q_u->info, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_REPLY_RRPCN structure.
+********************************************************************/
+
+bool spoolss_io_r_reply_rrpcn(const char *desc, SPOOL_R_REPLY_RRPCN *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_reply_rrpcn");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("unknown0", ps, depth, &r_u->unknown0))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_getprinterdataex (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_q_getprinterdataex(const char *desc, SPOOL_Q_GETPRINTERDATAEX *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_getprinterdataex");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_unistr2("keyname", &q_u->keyname,True,ps,depth))
+ return False;
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_unistr2("valuename", &q_u->valuename,True,ps,depth))
+ return False;
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("size", ps, depth, &q_u->size))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_getprinterdataex (srv_spoolss.c)
+ ********************************************************************/
+
+bool spoolss_io_r_getprinterdataex(const char *desc, SPOOL_R_GETPRINTERDATAEX *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_r_getprinterdataex");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("type", ps, depth, &r_u->type))
+ return False;
+ if (!prs_uint32("size", ps, depth, &r_u->size))
+ return False;
+
+ if (UNMARSHALLING(ps) && r_u->size) {
+ r_u->data = PRS_ALLOC_MEM(ps, unsigned char, r_u->size);
+ if(!r_u->data)
+ return False;
+ }
+
+ if (!prs_uint8s(False,"data", ps, depth, r_u->data, r_u->size))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ ********************************************************************/
+
+bool spoolss_io_q_setprinterdataex(const char *desc, SPOOL_Q_SETPRINTERDATAEX *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_setprinterdataex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &q_u->key, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("", &q_u->value, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("type", ps, depth, &q_u->type))
+ return False;
+
+ if(!prs_uint32("max_len", ps, depth, &q_u->max_len))
+ return False;
+
+ switch (q_u->type)
+ {
+ case 0x1:
+ case 0x3:
+ case 0x4:
+ case 0x7:
+ if (q_u->max_len) {
+ if (UNMARSHALLING(ps))
+ q_u->data=PRS_ALLOC_MEM(ps, uint8, q_u->max_len);
+ if(q_u->data == NULL)
+ return False;
+ if(!prs_uint8s(False,"data", ps, depth, q_u->data, q_u->max_len))
+ return False;
+ }
+ if(!prs_align(ps))
+ return False;
+ break;
+ }
+
+ if(!prs_uint32("real_len", ps, depth, &q_u->real_len))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ ********************************************************************/
+
+bool spoolss_io_r_setprinterdataex(const char *desc, SPOOL_R_SETPRINTERDATAEX *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_setprinterdataex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ ********************************************************************/
+bool make_spoolss_q_enumprinterkey(SPOOL_Q_ENUMPRINTERKEY *q_u,
+ POLICY_HND *hnd, const char *key,
+ uint32 size)
+{
+ DEBUG(5,("make_spoolss_q_enumprinterkey\n"));
+
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+ init_unistr2(&q_u->key, key, UNI_STR_TERMINATE);
+ q_u->size = size;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ ********************************************************************/
+
+bool spoolss_io_q_enumprinterkey(const char *desc, SPOOL_Q_ENUMPRINTERKEY *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumprinterkey");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+
+ if(!smb_io_unistr2("", &q_u->key, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("size", ps, depth, &q_u->size))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ ********************************************************************/
+
+bool spoolss_io_r_enumprinterkey(const char *desc, SPOOL_R_ENUMPRINTERKEY *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumprinterkey");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!smb_io_buffer5("", &r_u->keys, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_deleteprinterkey(SPOOL_Q_DELETEPRINTERKEY *q_u,
+ POLICY_HND *hnd, char *keyname)
+{
+ DEBUG(5,("make_spoolss_q_deleteprinterkey\n"));
+
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+ init_unistr2(&q_u->keyname, keyname, UNI_STR_TERMINATE);
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ ********************************************************************/
+
+bool spoolss_io_q_deleteprinterkey(const char *desc, SPOOL_Q_DELETEPRINTERKEY *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_deleteprinterkey");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+
+ if(!smb_io_unistr2("", &q_u->keyname, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ ********************************************************************/
+
+bool spoolss_io_r_deleteprinterkey(const char *desc, SPOOL_R_DELETEPRINTERKEY *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_deleteprinterkey");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ * read a structure.
+ ********************************************************************/
+
+bool spoolss_io_q_enumprinterdataex(const char *desc, SPOOL_Q_ENUMPRINTERDATAEX *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumprinterdataex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+
+ if(!smb_io_unistr2("", &q_u->key, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("size", ps, depth, &q_u->size))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static bool spoolss_io_printer_enum_values_ctr(const char *desc, prs_struct *ps,
+ PRINTER_ENUM_VALUES_CTR *ctr, int depth)
+{
+ int i;
+ uint32 valuename_offset,
+ data_offset,
+ current_offset;
+ const uint32 basic_unit = 20; /* size of static portion of enum_values */
+
+ prs_debug(ps, depth, desc, "spoolss_io_printer_enum_values_ctr");
+ depth++;
+
+ /*
+ * offset data begins at 20 bytes per structure * size_of_array.
+ * Don't forget the uint32 at the beginning
+ * */
+
+ current_offset = basic_unit * ctr->size_of_array;
+
+ /* first loop to write basic enum_value information */
+
+ if (UNMARSHALLING(ps) && ctr->size_of_array) {
+ ctr->values = PRS_ALLOC_MEM(ps, PRINTER_ENUM_VALUES, ctr->size_of_array);
+ if (!ctr->values)
+ return False;
+ }
+
+ for (i=0; i<ctr->size_of_array; i++) {
+ uint32 base_offset, return_offset;
+
+ base_offset = prs_offset(ps);
+
+ valuename_offset = current_offset;
+ if (!prs_uint32("valuename_offset", ps, depth, &valuename_offset))
+ return False;
+
+ /* Read or write the value. */
+
+ return_offset = prs_offset(ps);
+
+ if (!prs_set_offset(ps, base_offset + valuename_offset)) {
+ return False;
+ }
+
+ if (!prs_unistr("valuename", ps, depth, &ctr->values[i].valuename))
+ return False;
+
+ /* And go back. */
+ if (!prs_set_offset(ps, return_offset))
+ return False;
+
+ if (!prs_uint32("value_len", ps, depth, &ctr->values[i].value_len))
+ return False;
+
+ if (!prs_uint32("type", ps, depth, &ctr->values[i].type))
+ return False;
+
+ data_offset = ctr->values[i].value_len + valuename_offset;
+
+ if (!prs_uint32("data_offset", ps, depth, &data_offset))
+ return False;
+
+ if (!prs_uint32("data_len", ps, depth, &ctr->values[i].data_len))
+ return False;
+
+ /* Read or write the data. */
+
+ return_offset = prs_offset(ps);
+
+ if (!prs_set_offset(ps, base_offset + data_offset)) {
+ return False;
+ }
+
+ if ( ctr->values[i].data_len ) {
+ if ( UNMARSHALLING(ps) ) {
+ ctr->values[i].data = PRS_ALLOC_MEM(ps, uint8, ctr->values[i].data_len);
+ if (!ctr->values[i].data)
+ return False;
+ }
+ if (!prs_uint8s(False, "data", ps, depth, ctr->values[i].data, ctr->values[i].data_len))
+ return False;
+ }
+
+ current_offset = data_offset + ctr->values[i].data_len - basic_unit;
+ /* account for 2 byte alignment */
+ current_offset += (current_offset % 2);
+
+ /* Remember how far we got. */
+ data_offset = prs_offset(ps);
+
+ /* And go back. */
+ if (!prs_set_offset(ps, return_offset))
+ return False;
+
+ }
+
+ /* Go to the last data offset we got to. */
+
+ if (!prs_set_offset(ps, data_offset))
+ return False;
+
+ /* And ensure we're 2 byte aligned. */
+
+ if ( !prs_align_uint16(ps) )
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ ********************************************************************/
+
+bool spoolss_io_r_enumprinterdataex(const char *desc, SPOOL_R_ENUMPRINTERDATAEX *r_u, prs_struct *ps, int depth)
+{
+ uint32 data_offset, end_offset;
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumprinterdataex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("size", ps, depth, &r_u->ctr.size))
+ return False;
+
+ data_offset = prs_offset(ps);
+
+ if (!prs_set_offset(ps, data_offset + r_u->ctr.size))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if(!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ r_u->ctr.size_of_array = r_u->returned;
+
+ end_offset = prs_offset(ps);
+
+ if (!prs_set_offset(ps, data_offset))
+ return False;
+
+ if (r_u->ctr.size)
+ if (!spoolss_io_printer_enum_values_ctr("", ps, &r_u->ctr, depth ))
+ return False;
+
+ if (!prs_set_offset(ps, end_offset))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ ********************************************************************/
+
+/*
+ uint32 GetPrintProcessorDirectory(
+ [in] unistr2 *name,
+ [in] unistr2 *environment,
+ [in] uint32 level,
+ [in,out] RPC_BUFFER buffer,
+ [in] uint32 offered,
+ [out] uint32 needed,
+ [out] uint32 returned
+ );
+
+*/
+
+bool make_spoolss_q_getprintprocessordirectory(SPOOL_Q_GETPRINTPROCESSORDIRECTORY *q_u, const char *name, char *environment, int level, RPC_BUFFER *buffer, uint32 offered)
+{
+ DEBUG(5,("make_spoolss_q_getprintprocessordirectory\n"));
+
+ init_unistr2(&q_u->name, name, UNI_STR_TERMINATE);
+ init_unistr2(&q_u->environment, environment, UNI_STR_TERMINATE);
+
+ q_u->level = level;
+
+ q_u->buffer = buffer;
+ q_u->offered = offered;
+
+ return True;
+}
+
+bool spoolss_io_q_getprintprocessordirectory(const char *desc, SPOOL_Q_GETPRINTPROCESSORDIRECTORY *q_u, prs_struct *ps, int depth)
+{
+ uint32 ptr = 0;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_getprintprocessordirectory");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("ptr", ps, depth, &ptr))
+ return False;
+
+ if (ptr) {
+ if(!smb_io_unistr2("name", &q_u->name, True, ps, depth))
+ return False;
+ }
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("ptr", ps, depth, &ptr))
+ return False;
+
+ if (ptr) {
+ if(!smb_io_unistr2("environment", &q_u->environment, True,
+ ps, depth))
+ return False;
+ }
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!prs_rpcbuffer_p("", ps, depth, &q_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ ********************************************************************/
+
+bool spoolss_io_r_getprintprocessordirectory(const char *desc, SPOOL_R_GETPRINTPROCESSORDIRECTORY *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_getprintprocessordirectory");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_rpcbuffer_p("", ps, depth, &r_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+bool smb_io_printprocessordirectory_1(const char *desc, RPC_BUFFER *buffer, PRINTPROCESSOR_DIRECTORY_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printprocessordirectory_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_unistr(desc, &info->name, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_addform(SPOOL_Q_ADDFORM *q_u, POLICY_HND *handle,
+ int level, FORM *form)
+{
+ memcpy(&q_u->handle, handle, sizeof(POLICY_HND));
+ q_u->level = level;
+ q_u->level2 = level;
+ memcpy(&q_u->form, form, sizeof(FORM));
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_setform(SPOOL_Q_SETFORM *q_u, POLICY_HND *handle,
+ int level, const char *form_name, FORM *form)
+{
+ memcpy(&q_u->handle, handle, sizeof(POLICY_HND));
+ q_u->level = level;
+ q_u->level2 = level;
+ memcpy(&q_u->form, form, sizeof(FORM));
+ init_unistr2(&q_u->name, form_name, UNI_STR_TERMINATE);
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_deleteform(SPOOL_Q_DELETEFORM *q_u, POLICY_HND *handle,
+ const char *form)
+{
+ memcpy(&q_u->handle, handle, sizeof(POLICY_HND));
+ init_unistr2(&q_u->name, form, UNI_STR_TERMINATE);
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_getform(SPOOL_Q_GETFORM *q_u, POLICY_HND *handle,
+ const char *formname, uint32 level,
+ RPC_BUFFER *buffer, uint32 offered)
+{
+ memcpy(&q_u->handle, handle, sizeof(POLICY_HND));
+ q_u->level = level;
+ init_unistr2(&q_u->formname, formname, UNI_STR_TERMINATE);
+ q_u->buffer=buffer;
+ q_u->offered=offered;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_enumforms(SPOOL_Q_ENUMFORMS *q_u, POLICY_HND *handle,
+ uint32 level, RPC_BUFFER *buffer,
+ uint32 offered)
+{
+ memcpy(&q_u->handle, handle, sizeof(POLICY_HND));
+ q_u->level = level;
+ q_u->buffer=buffer;
+ q_u->offered=offered;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_setjob(SPOOL_Q_SETJOB *q_u, POLICY_HND *handle,
+ uint32 jobid, uint32 level, uint32 command)
+{
+ memcpy(&q_u->handle, handle, sizeof(POLICY_HND));
+ q_u->jobid = jobid;
+ q_u->level = level;
+
+ /* Hmm - the SPOOL_Q_SETJOB structure has a JOB_INFO ctr in it but
+ the server side code has it marked as unused. */
+
+ q_u->command = command;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_getjob(SPOOL_Q_GETJOB *q_u, POLICY_HND *handle,
+ uint32 jobid, uint32 level, RPC_BUFFER *buffer,
+ uint32 offered)
+{
+ memcpy(&q_u->handle, handle, sizeof(POLICY_HND));
+ q_u->jobid = jobid;
+ q_u->level = level;
+ q_u->buffer = buffer;
+ q_u->offered = offered;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_startpageprinter(SPOOL_Q_STARTPAGEPRINTER *q_u,
+ POLICY_HND *handle)
+{
+ memcpy(&q_u->handle, handle, sizeof(POLICY_HND));
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_endpageprinter(SPOOL_Q_ENDPAGEPRINTER *q_u,
+ POLICY_HND *handle)
+{
+ memcpy(&q_u->handle, handle, sizeof(POLICY_HND));
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_startdocprinter(SPOOL_Q_STARTDOCPRINTER *q_u,
+ POLICY_HND *handle, uint32 level,
+ char *docname, char *outputfile,
+ char *datatype)
+{
+ DOC_INFO_CONTAINER *ctr = &q_u->doc_info_container;
+
+ memcpy(&q_u->handle, handle, sizeof(POLICY_HND));
+
+ ctr->level = level;
+
+ switch (level) {
+ case 1:
+ ctr->docinfo.switch_value = level;
+
+ ctr->docinfo.doc_info_1.p_docname = docname ? 1 : 0;
+ ctr->docinfo.doc_info_1.p_outputfile = outputfile ? 1 : 0;
+ ctr->docinfo.doc_info_1.p_datatype = datatype ? 1 : 0;
+
+ init_unistr2(&ctr->docinfo.doc_info_1.docname, docname, UNI_STR_TERMINATE);
+ init_unistr2(&ctr->docinfo.doc_info_1.outputfile, outputfile, UNI_STR_TERMINATE);
+ init_unistr2(&ctr->docinfo.doc_info_1.datatype, datatype, UNI_STR_TERMINATE);
+
+ break;
+ case 2:
+ /* DOC_INFO_2 is only used by Windows 9x and since it
+ doesn't do printing over RPC we don't have to worry
+ about it. */
+ default:
+ DEBUG(3, ("unsupported info level %d\n", level));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_enddocprinter(SPOOL_Q_ENDDOCPRINTER *q_u,
+ POLICY_HND *handle)
+{
+ memcpy(&q_u->handle, handle, sizeof(POLICY_HND));
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_writeprinter(SPOOL_Q_WRITEPRINTER *q_u,
+ POLICY_HND *handle, uint32 data_size,
+ char *data)
+{
+ memcpy(&q_u->handle, handle, sizeof(POLICY_HND));
+ q_u->buffer_size = q_u->buffer_size2 = data_size;
+ q_u->buffer = (unsigned char *)data;
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_deleteprinterdata(SPOOL_Q_DELETEPRINTERDATA *q_u,
+ POLICY_HND *handle, char *valuename)
+{
+ memcpy(&q_u->handle, handle, sizeof(POLICY_HND));
+ init_unistr2(&q_u->valuename, valuename, UNI_STR_TERMINATE);
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_deleteprinterdataex(SPOOL_Q_DELETEPRINTERDATAEX *q_u,
+ POLICY_HND *handle, char *key,
+ char *value)
+{
+ memcpy(&q_u->handle, handle, sizeof(POLICY_HND));
+ init_unistr2(&q_u->valuename, value, UNI_STR_TERMINATE);
+ init_unistr2(&q_u->keyname, key, UNI_STR_TERMINATE);
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+bool make_spoolss_q_rffpcnex(SPOOL_Q_RFFPCNEX *q_u, POLICY_HND *handle,
+ uint32 flags, uint32 options, const char *localmachine,
+ uint32 printerlocal, SPOOL_NOTIFY_OPTION *option)
+{
+ memcpy(&q_u->handle, handle, sizeof(POLICY_HND));
+
+ q_u->flags = flags;
+ q_u->options = options;
+
+ q_u->localmachine_ptr = 1;
+
+ init_unistr2(&q_u->localmachine, localmachine, UNI_STR_TERMINATE);
+
+ q_u->printerlocal = printerlocal;
+
+ if (option)
+ q_u->option_ptr = 1;
+
+ q_u->option = option;
+
+ return True;
+}
+
+
+/*******************************************************************
+ ********************************************************************/
+
+bool spoolss_io_q_xcvdataport(const char *desc, SPOOL_Q_XCVDATAPORT *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_xcvdataport");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+
+ if(!smb_io_unistr2("", &q_u->dataname, True, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!prs_rpcbuffer("", ps, depth, &q_u->indata))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("indata_len", ps, depth, &q_u->indata_len))
+ return False;
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+ if (!prs_uint32("unknown", ps, depth, &q_u->unknown))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+bool spoolss_io_r_xcvdataport(const char *desc, SPOOL_R_XCVDATAPORT *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_xcvdataport");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_rpcbuffer("", ps, depth, &r_u->outdata))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+ if (!prs_uint32("unknown", ps, depth, &r_u->unknown))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+bool make_monitorui_buf( RPC_BUFFER *buf, const char *dllname )
+{
+ UNISTR string;
+
+ if ( !buf )
+ return False;
+
+ init_unistr( &string, dllname );
+
+ if ( !prs_unistr( "ui_dll", &buf->prs, 0, &string ) )
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+#define PORT_DATA_1_PAD 540
+
+static bool smb_io_port_data_1( const char *desc, RPC_BUFFER *buf, int depth, SPOOL_PORT_DATA_1 *p1 )
+{
+ prs_struct *ps = &buf->prs;
+ uint8 padding[PORT_DATA_1_PAD];
+
+ prs_debug(ps, depth, desc, "smb_io_port_data_1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if( !prs_uint16s(True, "portname", ps, depth, p1->portname, MAX_PORTNAME))
+ return False;
+
+ if (!prs_uint32("version", ps, depth, &p1->version))
+ return False;
+ if (!prs_uint32("protocol", ps, depth, &p1->protocol))
+ return False;
+ if (!prs_uint32("size", ps, depth, &p1->size))
+ return False;
+ if (!prs_uint32("reserved", ps, depth, &p1->reserved))
+ return False;
+
+ if( !prs_uint16s(True, "hostaddress", ps, depth, p1->hostaddress, MAX_NETWORK_NAME))
+ return False;
+ if( !prs_uint16s(True, "snmpcommunity", ps, depth, p1->snmpcommunity, MAX_SNMP_COMM_NAME))
+ return False;
+
+ if (!prs_uint32("dblspool", ps, depth, &p1->dblspool))
+ return False;
+
+ if( !prs_uint16s(True, "queue", ps, depth, p1->queue, MAX_QUEUE_NAME))
+ return False;
+ if( !prs_uint16s(True, "ipaddress", ps, depth, p1->ipaddress, MAX_IPADDR_STRING))
+ return False;
+
+ if( !prs_uint8s(False, "", ps, depth, padding, PORT_DATA_1_PAD))
+ return False;
+
+ if (!prs_uint32("port", ps, depth, &p1->port))
+ return False;
+ if (!prs_uint32("snmpenabled", ps, depth, &p1->snmpenabled))
+ return False;
+ if (!prs_uint32("snmpdevindex", ps, depth, &p1->snmpdevindex))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+bool convert_port_data_1( NT_PORT_DATA_1 *port1, RPC_BUFFER *buf )
+{
+ SPOOL_PORT_DATA_1 spdata_1;
+
+ ZERO_STRUCT( spdata_1 );
+
+ if ( !smb_io_port_data_1( "port_data_1", buf, 0, &spdata_1 ) )
+ return False;
+
+ rpcstr_pull(port1->name, spdata_1.portname, sizeof(port1->name), -1, 0);
+ rpcstr_pull(port1->queue, spdata_1.queue, sizeof(port1->queue), -1, 0);
+ rpcstr_pull(port1->hostaddr, spdata_1.hostaddress, sizeof(port1->hostaddr), -1, 0);
+
+ port1->port = spdata_1.port;
+
+ switch ( spdata_1.protocol ) {
+ case 1:
+ port1->protocol = PORT_PROTOCOL_DIRECT;
+ break;
+ case 2:
+ port1->protocol = PORT_PROTOCOL_LPR;
+ break;
+ default:
+ DEBUG(3,("convert_port_data_1: unknown protocol [%d]!\n",
+ spdata_1.protocol));
+ return False;
+ }
+
+ return True;
+}
diff --git a/source3/rpc_parse/parse_svcctl.c b/source3/rpc_parse/parse_svcctl.c
new file mode 100644
index 0000000000..c5d93864ba
--- /dev/null
+++ b/source3/rpc_parse/parse_svcctl.c
@@ -0,0 +1,535 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Gerald (Jerry) Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_PARSE
+
+/*******************************************************************
+********************************************************************/
+
+static bool svcctl_io_service_status( const char *desc, SERVICE_STATUS *status, prs_struct *ps, int depth )
+{
+
+ prs_debug(ps, depth, desc, "svcctl_io_service_status");
+ depth++;
+
+ if(!prs_uint32("type", ps, depth, &status->type))
+ return False;
+
+ if(!prs_uint32("state", ps, depth, &status->state))
+ return False;
+
+ if(!prs_uint32("controls_accepted", ps, depth, &status->controls_accepted))
+ return False;
+
+ if(!prs_werror("win32_exit_code", ps, depth, &status->win32_exit_code))
+ return False;
+
+ if(!prs_uint32("service_exit_code", ps, depth, &status->service_exit_code))
+ return False;
+
+ if(!prs_uint32("check_point", ps, depth, &status->check_point))
+ return False;
+
+ if(!prs_uint32("wait_hint", ps, depth, &status->wait_hint))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static bool svcctl_io_service_config( const char *desc, SERVICE_CONFIG *config, prs_struct *ps, int depth )
+{
+
+ prs_debug(ps, depth, desc, "svcctl_io_service_config");
+ depth++;
+
+ if(!prs_uint32("service_type", ps, depth, &config->service_type))
+ return False;
+ if(!prs_uint32("start_type", ps, depth, &config->start_type))
+ return False;
+ if(!prs_uint32("error_control", ps, depth, &config->error_control))
+ return False;
+
+ if (!prs_io_unistr2_p("", ps, depth, &config->executablepath))
+ return False;
+ if (!prs_io_unistr2_p("", ps, depth, &config->loadordergroup))
+ return False;
+
+ if(!prs_uint32("tag_id", ps, depth, &config->tag_id))
+ return False;
+
+ if (!prs_io_unistr2_p("", ps, depth, &config->dependencies))
+ return False;
+ if (!prs_io_unistr2_p("", ps, depth, &config->startname))
+ return False;
+ if (!prs_io_unistr2_p("", ps, depth, &config->displayname))
+ return False;
+
+ if (!prs_io_unistr2("", ps, depth, config->executablepath))
+ return False;
+ if (!prs_io_unistr2("", ps, depth, config->loadordergroup))
+ return False;
+ if (!prs_io_unistr2("", ps, depth, config->dependencies))
+ return False;
+ if (!prs_io_unistr2("", ps, depth, config->startname))
+ return False;
+ if (!prs_io_unistr2("", ps, depth, config->displayname))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool svcctl_io_enum_services_status( const char *desc, ENUM_SERVICES_STATUS *enum_status, RPC_BUFFER *buffer, int depth )
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "svcctl_io_enum_services_status");
+ depth++;
+
+ if ( !smb_io_relstr("servicename", buffer, depth, &enum_status->servicename) )
+ return False;
+ if ( !smb_io_relstr("displayname", buffer, depth, &enum_status->displayname) )
+ return False;
+
+ if ( !svcctl_io_service_status("svc_status", &enum_status->status, ps, depth) )
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool svcctl_io_service_status_process( const char *desc, SERVICE_STATUS_PROCESS *status, RPC_BUFFER *buffer, int depth )
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "svcctl_io_service_status_process");
+ depth++;
+
+ if ( !svcctl_io_service_status("status", &status->status, ps, depth) )
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("process_id", ps, depth, &status->process_id))
+ return False;
+ if(!prs_uint32("service_flags", ps, depth, &status->service_flags))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+uint32 svcctl_sizeof_enum_services_status( ENUM_SERVICES_STATUS *status )
+{
+ uint32 size = 0;
+
+ size += size_of_relative_string( &status->servicename );
+ size += size_of_relative_string( &status->displayname );
+ size += sizeof(SERVICE_STATUS);
+
+ return size;
+}
+
+/********************************************************************
+********************************************************************/
+
+static uint32 sizeof_unistr2( UNISTR2 *string )
+{
+ uint32 size = 0;
+
+ if ( !string )
+ return 0;
+
+ size = sizeof(uint32) * 3; /* length fields */
+ size += 2 * string->uni_max_len; /* string data */
+ size += size % 4; /* alignment */
+
+ return size;
+}
+
+/********************************************************************
+********************************************************************/
+
+uint32 svcctl_sizeof_service_config( SERVICE_CONFIG *config )
+{
+ uint32 size = 0;
+
+ size = sizeof(uint32) * 4; /* static uint32 fields */
+
+ /* now add the UNISTR2 + pointer sizes */
+
+ size += sizeof(uint32) * sizeof_unistr2(config->executablepath);
+ size += sizeof(uint32) * sizeof_unistr2(config->loadordergroup);
+ size += sizeof(uint32) * sizeof_unistr2(config->dependencies);
+ size += sizeof(uint32) * sizeof_unistr2(config->startname);
+ size += sizeof(uint32) * sizeof_unistr2(config->displayname);
+
+ return size;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool svcctl_io_q_enum_services_status(const char *desc, SVCCTL_Q_ENUM_SERVICES_STATUS *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "svcctl_io_q_enum_services_status");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("scm_pol", &q_u->handle, ps, depth))
+ return False;
+
+ if(!prs_uint32("type", ps, depth, &q_u->type))
+ return False;
+ if(!prs_uint32("state", ps, depth, &q_u->state))
+ return False;
+ if(!prs_uint32("buffer_size", ps, depth, &q_u->buffer_size))
+ return False;
+
+ if(!prs_pointer("resume", ps, depth, (void*)&q_u->resume, sizeof(uint32), (PRS_POINTER_CAST)prs_uint32))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool svcctl_io_r_enum_services_status(const char *desc, SVCCTL_R_ENUM_SERVICES_STATUS *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "svcctl_io_r_enum_services_status");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!prs_rpcbuffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+ if(!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if(!prs_pointer("resume", ps, depth, (void*)&r_u->resume, sizeof(uint32), (PRS_POINTER_CAST)prs_uint32))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool svcctl_io_q_query_service_config(const char *desc, SVCCTL_Q_QUERY_SERVICE_CONFIG *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "svcctl_io_q_query_service_config");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("service_pol", &q_u->handle, ps, depth))
+ return False;
+
+ if(!prs_uint32("buffer_size", ps, depth, &q_u->buffer_size))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool svcctl_io_r_query_service_config(const char *desc, SVCCTL_R_QUERY_SERVICE_CONFIG *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "svcctl_io_r_query_service_config");
+ depth++;
+
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!svcctl_io_service_config("config", &r_u->config, ps, depth))
+ return False;
+
+ if(!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool svcctl_io_q_query_service_config2(const char *desc, SVCCTL_Q_QUERY_SERVICE_CONFIG2 *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "svcctl_io_q_query_service_config2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("service_pol", &q_u->handle, ps, depth))
+ return False;
+
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!prs_uint32("buffer_size", ps, depth, &q_u->buffer_size))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+********************************************************************/
+
+void init_service_description_buffer(SERVICE_DESCRIPTION *desc, const char *service_desc )
+{
+ desc->unknown = 0x04; /* always 0x0000 0004 (no idea what this is) */
+ init_unistr( &desc->description, service_desc );
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool svcctl_io_service_description( const char *desc, SERVICE_DESCRIPTION *description, RPC_BUFFER *buffer, int depth )
+{
+ prs_struct *ps = &buffer->prs;
+
+ prs_debug(ps, depth, desc, "svcctl_io_service_description");
+ depth++;
+
+ if ( !prs_uint32("unknown", ps, depth, &description->unknown) )
+ return False;
+ if ( !prs_unistr("description", ps, depth, &description->description) )
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+uint32 svcctl_sizeof_service_description( SERVICE_DESCRIPTION *desc )
+{
+ if ( !desc )
+ return 0;
+
+ /* make sure to include the terminating NULL */
+ return ( sizeof(uint32) + (2*(str_len_uni(&desc->description)+1)) );
+}
+
+/*******************************************************************
+********************************************************************/
+
+static bool svcctl_io_action( const char *desc, SC_ACTION *action, prs_struct *ps, int depth )
+{
+
+ prs_debug(ps, depth, desc, "svcctl_io_action");
+ depth++;
+
+ if ( !prs_uint32("type", ps, depth, &action->type) )
+ return False;
+ if ( !prs_uint32("delay", ps, depth, &action->delay) )
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool svcctl_io_service_fa( const char *desc, SERVICE_FAILURE_ACTIONS *fa, RPC_BUFFER *buffer, int depth )
+{
+ prs_struct *ps = &buffer->prs;
+ int i;
+
+ prs_debug(ps, depth, desc, "svcctl_io_service_description");
+ depth++;
+
+ if ( !prs_uint32("reset_period", ps, depth, &fa->reset_period) )
+ return False;
+
+ if ( !prs_pointer( desc, ps, depth, (void*)&fa->rebootmsg, sizeof(UNISTR2), (PRS_POINTER_CAST)prs_io_unistr2 ) )
+ return False;
+ if ( !prs_pointer( desc, ps, depth, (void*)&fa->command, sizeof(UNISTR2), (PRS_POINTER_CAST)prs_io_unistr2 ) )
+ return False;
+
+ if ( !prs_uint32("num_actions", ps, depth, &fa->num_actions) )
+ return False;
+
+ if ( UNMARSHALLING(ps)) {
+ if (fa->num_actions) {
+ if ( !(fa->actions = TALLOC_ARRAY( talloc_tos(), SC_ACTION, fa->num_actions )) ) {
+ DEBUG(0,("svcctl_io_service_fa: talloc() failure!\n"));
+ return False;
+ }
+ } else {
+ fa->actions = NULL;
+ }
+ }
+
+ for ( i=0; i<fa->num_actions; i++ ) {
+ if ( !svcctl_io_action( "actions", &fa->actions[i], ps, depth ) )
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+uint32 svcctl_sizeof_service_fa( SERVICE_FAILURE_ACTIONS *fa)
+{
+ uint32 size = 0;
+
+ if ( !fa )
+ return 0;
+
+ size = sizeof(uint32) * 2;
+ size += sizeof_unistr2( fa->rebootmsg );
+ size += sizeof_unistr2( fa->command );
+ size += sizeof(SC_ACTION) * fa->num_actions;
+
+ return size;
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool svcctl_io_r_query_service_config2(const char *desc, SVCCTL_R_QUERY_SERVICE_CONFIG2 *r_u, prs_struct *ps, int depth)
+{
+ if ( !r_u )
+ return False;
+
+ prs_debug(ps, depth, desc, "svcctl_io_r_query_service_config2");
+ depth++;
+
+ if ( !prs_align(ps) )
+ return False;
+
+ if (!prs_rpcbuffer("", ps, depth, &r_u->buffer))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+********************************************************************/
+
+bool svcctl_io_q_query_service_status_ex(const char *desc, SVCCTL_Q_QUERY_SERVICE_STATUSEX *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "svcctl_io_q_query_service_status_ex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("service_pol", &q_u->handle, ps, depth))
+ return False;
+
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!prs_uint32("buffer_size", ps, depth, &q_u->buffer_size))
+ return False;
+
+ return True;
+
+}
+
+/*******************************************************************
+********************************************************************/
+
+bool svcctl_io_r_query_service_status_ex(const char *desc, SVCCTL_R_QUERY_SERVICE_STATUSEX *r_u, prs_struct *ps, int depth)
+{
+ if ( !r_u )
+ return False;
+
+ prs_debug(ps, depth, desc, "svcctl_io_r_query_service_status_ex");
+ depth++;
+
+ if (!prs_rpcbuffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
diff --git a/source3/rpc_server/srv_dfs_nt.c b/source3/rpc_server/srv_dfs_nt.c
new file mode 100644
index 0000000000..661d262dc4
--- /dev/null
+++ b/source3/rpc_server/srv_dfs_nt.c
@@ -0,0 +1,530 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines for Dfs
+ * Copyright (C) Shirish Kalele 2000.
+ * Copyright (C) Jeremy Allison 2001-2007.
+ * Copyright (C) Jelmer Vernooij 2005-2006.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This is the implementation of the dfs pipe. */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_MSDFS
+
+/* This function does not return a WERROR or NTSTATUS code but rather 1 if
+ dfs exists, or 0 otherwise. */
+
+void _dfs_GetManagerVersion(pipes_struct *p, struct dfs_GetManagerVersion *r)
+{
+ if (lp_host_msdfs()) {
+ *r->out.version = DFS_MANAGER_VERSION_NT4;
+ } else {
+ *r->out.version = (enum dfs_ManagerVersion)0;
+ }
+}
+
+WERROR _dfs_Add(pipes_struct *p, struct dfs_Add *r)
+{
+ struct junction_map *jn = NULL;
+ struct referral *old_referral_list = NULL;
+ bool self_ref = False;
+ int consumedcnt = 0;
+ char *altpath = NULL;
+ NTSTATUS status;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if (p->pipe_user.ut.uid != sec_initial_uid()) {
+ DEBUG(10,("_dfs_add: uid != 0. Access denied.\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ jn = TALLOC_ZERO_P(ctx, struct junction_map);
+ if (!jn) {
+ return WERR_NOMEM;
+ }
+
+ DEBUG(5,("init_reply_dfs_add: Request to add %s -> %s\\%s.\n",
+ r->in.path, r->in.server, r->in.share));
+
+ altpath = talloc_asprintf(ctx, "%s\\%s",
+ r->in.server,
+ r->in.share);
+ if (!altpath) {
+ return WERR_NOMEM;
+ }
+
+ /* The following call can change the cwd. */
+ status = get_referred_path(ctx, r->in.path, jn,
+ &consumedcnt, &self_ref);
+ if(!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ jn->referral_count += 1;
+ old_referral_list = jn->referral_list;
+
+ if (jn->referral_count < 1) {
+ return WERR_NOMEM;
+ }
+
+ jn->referral_list = TALLOC_ARRAY(ctx, struct referral, jn->referral_count);
+ if(jn->referral_list == NULL) {
+ DEBUG(0,("init_reply_dfs_add: talloc failed for referral list!\n"));
+ return WERR_DFS_INTERNAL_ERROR;
+ }
+
+ if(old_referral_list && jn->referral_list) {
+ memcpy(jn->referral_list, old_referral_list,
+ sizeof(struct referral)*jn->referral_count-1);
+ }
+
+ jn->referral_list[jn->referral_count-1].proximity = 0;
+ jn->referral_list[jn->referral_count-1].ttl = REFERRAL_TTL;
+ jn->referral_list[jn->referral_count-1].alternate_path = altpath;
+
+ if(!create_msdfs_link(jn)) {
+ return WERR_DFS_CANT_CREATE_JUNCT;
+ }
+
+ return WERR_OK;
+}
+
+WERROR _dfs_Remove(pipes_struct *p, struct dfs_Remove *r)
+{
+ struct junction_map *jn = NULL;
+ bool self_ref = False;
+ int consumedcnt = 0;
+ bool found = False;
+ TALLOC_CTX *ctx = talloc_tos();
+ char *altpath = NULL;
+
+ if (p->pipe_user.ut.uid != sec_initial_uid()) {
+ DEBUG(10,("_dfs_remove: uid != 0. Access denied.\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ jn = TALLOC_ZERO_P(ctx, struct junction_map);
+ if (!jn) {
+ return WERR_NOMEM;
+ }
+
+ if (r->in.servername && r->in.sharename) {
+ altpath = talloc_asprintf(ctx, "%s\\%s",
+ r->in.servername,
+ r->in.sharename);
+ if (!altpath) {
+ return WERR_NOMEM;
+ }
+ strlower_m(altpath);
+ DEBUG(5,("init_reply_dfs_remove: Request to remove %s -> %s\\%s.\n",
+ r->in.dfs_entry_path, r->in.servername, r->in.sharename));
+ }
+
+ if(!NT_STATUS_IS_OK(get_referred_path(ctx, r->in.dfs_entry_path, jn,
+ &consumedcnt, &self_ref))) {
+ return WERR_DFS_NO_SUCH_VOL;
+ }
+
+ /* if no server-share pair given, remove the msdfs link completely */
+ if(!r->in.servername && !r->in.sharename) {
+ if(!remove_msdfs_link(jn)) {
+ return WERR_DFS_NO_SUCH_VOL;
+ }
+ } else {
+ int i=0;
+ /* compare each referral in the list with the one to remove */
+ DEBUG(10,("altpath: .%s. refcnt: %d\n", altpath, jn->referral_count));
+ for(i=0;i<jn->referral_count;i++) {
+ char *refpath = talloc_strdup(ctx,
+ jn->referral_list[i].alternate_path);
+ if (!refpath) {
+ return WERR_NOMEM;
+ }
+ trim_char(refpath, '\\', '\\');
+ DEBUG(10,("_dfs_remove: refpath: .%s.\n", refpath));
+ if(strequal(refpath, altpath)) {
+ *(jn->referral_list[i].alternate_path)='\0';
+ DEBUG(10,("_dfs_remove: Removal request matches referral %s\n",
+ refpath));
+ found = True;
+ }
+ }
+
+ if(!found) {
+ return WERR_DFS_NO_SUCH_SHARE;
+ }
+
+ /* Only one referral, remove it */
+ if(jn->referral_count == 1) {
+ if(!remove_msdfs_link(jn)) {
+ return WERR_DFS_NO_SUCH_VOL;
+ }
+ } else {
+ if(!create_msdfs_link(jn)) {
+ return WERR_DFS_CANT_CREATE_JUNCT;
+ }
+ }
+ }
+
+ return WERR_OK;
+}
+
+static bool init_reply_dfs_info_1(TALLOC_CTX *mem_ctx, struct junction_map* j,struct dfs_Info1* dfs1)
+{
+ dfs1->path = talloc_asprintf(mem_ctx,
+ "\\\\%s\\%s\\%s", global_myname(),
+ j->service_name, j->volume_name);
+ if (dfs1->path == NULL)
+ return False;
+
+ DEBUG(5,("init_reply_dfs_info_1: initing entrypath: %s\n",dfs1->path));
+ return True;
+}
+
+static bool init_reply_dfs_info_2(TALLOC_CTX *mem_ctx, struct junction_map* j, struct dfs_Info2* dfs2)
+{
+ dfs2->path = talloc_asprintf(mem_ctx,
+ "\\\\%s\\%s\\%s", global_myname(), j->service_name, j->volume_name);
+ if (dfs2->path == NULL)
+ return False;
+ dfs2->comment = talloc_strdup(mem_ctx, j->comment);
+ dfs2->state = 1; /* set up state of dfs junction as OK */
+ dfs2->num_stores = j->referral_count;
+ return True;
+}
+
+static bool init_reply_dfs_info_3(TALLOC_CTX *mem_ctx, struct junction_map* j, struct dfs_Info3* dfs3)
+{
+ int ii;
+ if (j->volume_name[0] == '\0')
+ dfs3->path = talloc_asprintf(mem_ctx, "\\\\%s\\%s",
+ global_myname(), j->service_name);
+ else
+ dfs3->path = talloc_asprintf(mem_ctx, "\\\\%s\\%s\\%s", global_myname(),
+ j->service_name, j->volume_name);
+
+ if (dfs3->path == NULL)
+ return False;
+
+ dfs3->comment = talloc_strdup(mem_ctx, j->comment);
+ dfs3->state = 1;
+ dfs3->num_stores = j->referral_count;
+
+ /* also enumerate the stores */
+ if (j->referral_count) {
+ dfs3->stores = TALLOC_ARRAY(mem_ctx, struct dfs_StorageInfo, j->referral_count);
+ if (!dfs3->stores)
+ return False;
+ memset(dfs3->stores, '\0', j->referral_count * sizeof(struct dfs_StorageInfo));
+ } else {
+ dfs3->stores = NULL;
+ }
+
+ for(ii=0;ii<j->referral_count;ii++) {
+ char* p;
+ char *path = NULL;
+ struct dfs_StorageInfo* stor = &(dfs3->stores[ii]);
+ struct referral* ref = &(j->referral_list[ii]);
+
+ path = talloc_strdup(mem_ctx, ref->alternate_path);
+ if (!path) {
+ return False;
+ }
+ trim_char(path,'\\','\0');
+ p = strrchr_m(path,'\\');
+ if(p==NULL) {
+ DEBUG(4,("init_reply_dfs_info_3: invalid path: no \\ found in %s\n",path));
+ continue;
+ }
+ *p = '\0';
+ DEBUG(5,("storage %d: %s.%s\n",ii,path,p+1));
+ stor->state = 2; /* set all stores as ONLINE */
+ stor->server = talloc_strdup(mem_ctx, path);
+ stor->share = talloc_strdup(mem_ctx, p+1);
+ }
+ return True;
+}
+
+static bool init_reply_dfs_info_100(TALLOC_CTX *mem_ctx, struct junction_map* j, struct dfs_Info100* dfs100)
+{
+ dfs100->comment = talloc_strdup(mem_ctx, j->comment);
+ return True;
+}
+
+WERROR _dfs_Enum(pipes_struct *p, struct dfs_Enum *r)
+{
+ struct junction_map *jn = NULL;
+ size_t num_jn = 0;
+ size_t i;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ jn = enum_msdfs_links(ctx, &num_jn);
+ if (!jn || num_jn == 0) {
+ num_jn = 0;
+ jn = NULL;
+ }
+
+ DEBUG(5,("_dfs_Enum: %u junctions found in Dfs, doing level %d\n",
+ (unsigned int)num_jn, r->in.level));
+
+ *r->out.total = num_jn;
+
+ /* Create the return array */
+ switch (r->in.level) {
+ case 1:
+ if (num_jn) {
+ if ((r->out.info->e.info1->s = TALLOC_ARRAY(ctx, struct dfs_Info1, num_jn)) == NULL) {
+ return WERR_NOMEM;
+ }
+ } else {
+ r->out.info->e.info1->s = NULL;
+ }
+ r->out.info->e.info1->count = num_jn;
+ break;
+ case 2:
+ if (num_jn) {
+ if ((r->out.info->e.info2->s = TALLOC_ARRAY(ctx, struct dfs_Info2, num_jn)) == NULL) {
+ return WERR_NOMEM;
+ }
+ } else {
+ r->out.info->e.info2->s = NULL;
+ }
+ r->out.info->e.info2->count = num_jn;
+ break;
+ case 3:
+ if (num_jn) {
+ if ((r->out.info->e.info3->s = TALLOC_ARRAY(ctx, struct dfs_Info3, num_jn)) == NULL) {
+ return WERR_NOMEM;
+ }
+ } else {
+ r->out.info->e.info3->s = NULL;
+ }
+ r->out.info->e.info3->count = num_jn;
+ break;
+ default:
+ return WERR_INVALID_PARAM;
+ }
+
+ for (i = 0; i < num_jn; i++) {
+ switch (r->in.level) {
+ case 1:
+ init_reply_dfs_info_1(ctx, &jn[i], &r->out.info->e.info1->s[i]);
+ break;
+ case 2:
+ init_reply_dfs_info_2(ctx, &jn[i], &r->out.info->e.info2->s[i]);
+ break;
+ case 3:
+ init_reply_dfs_info_3(ctx, &jn[i], &r->out.info->e.info3->s[i]);
+ break;
+ default:
+ return WERR_INVALID_PARAM;
+ }
+ }
+
+ return WERR_OK;
+}
+
+WERROR _dfs_GetInfo(pipes_struct *p, struct dfs_GetInfo *r)
+{
+ int consumedcnt = strlen(r->in.dfs_entry_path);
+ struct junction_map *jn = NULL;
+ bool self_ref = False;
+ TALLOC_CTX *ctx = talloc_tos();
+ bool ret;
+
+ jn = TALLOC_ZERO_P(ctx, struct junction_map);
+ if (!jn) {
+ return WERR_NOMEM;
+ }
+
+ if(!create_junction(ctx, r->in.dfs_entry_path, jn)) {
+ return WERR_DFS_NO_SUCH_SERVER;
+ }
+
+ /* The following call can change the cwd. */
+ if(!NT_STATUS_IS_OK(get_referred_path(ctx, r->in.dfs_entry_path,
+ jn, &consumedcnt, &self_ref)) ||
+ consumedcnt < strlen(r->in.dfs_entry_path)) {
+ return WERR_DFS_NO_SUCH_VOL;
+ }
+
+ switch (r->in.level) {
+ case 1:
+ r->out.info->info1 = TALLOC_ZERO_P(ctx,struct dfs_Info1);
+ if (!r->out.info->info1) {
+ return WERR_NOMEM;
+ }
+ ret = init_reply_dfs_info_1(ctx, jn, r->out.info->info1);
+ break;
+ case 2:
+ r->out.info->info2 = TALLOC_ZERO_P(ctx,struct dfs_Info2);
+ if (!r->out.info->info2) {
+ return WERR_NOMEM;
+ }
+ ret = init_reply_dfs_info_2(ctx, jn, r->out.info->info2);
+ break;
+ case 3:
+ r->out.info->info3 = TALLOC_ZERO_P(ctx,struct dfs_Info3);
+ if (!r->out.info->info3) {
+ return WERR_NOMEM;
+ }
+ ret = init_reply_dfs_info_3(ctx, jn, r->out.info->info3);
+ break;
+ case 100:
+ r->out.info->info100 = TALLOC_ZERO_P(ctx,struct dfs_Info100);
+ if (!r->out.info->info100) {
+ return WERR_NOMEM;
+ }
+ ret = init_reply_dfs_info_100(ctx, jn, r->out.info->info100);
+ break;
+ default:
+ r->out.info->info1 = NULL;
+ return WERR_INVALID_PARAM;
+ }
+
+ if (!ret)
+ return WERR_INVALID_PARAM;
+
+ return WERR_OK;
+}
+
+WERROR _dfs_SetInfo(pipes_struct *p, struct dfs_SetInfo *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_Rename(pipes_struct *p, struct dfs_Rename *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_Move(pipes_struct *p, struct dfs_Move *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_ManagerGetConfigInfo(pipes_struct *p, struct dfs_ManagerGetConfigInfo *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_ManagerSendSiteInfo(pipes_struct *p, struct dfs_ManagerSendSiteInfo *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_AddFtRoot(pipes_struct *p, struct dfs_AddFtRoot *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_RemoveFtRoot(pipes_struct *p, struct dfs_RemoveFtRoot *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_AddStdRoot(pipes_struct *p, struct dfs_AddStdRoot *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_RemoveStdRoot(pipes_struct *p, struct dfs_RemoveStdRoot *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_ManagerInitialize(pipes_struct *p, struct dfs_ManagerInitialize *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_AddStdRootForced(pipes_struct *p, struct dfs_AddStdRootForced *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_GetDcAddress(pipes_struct *p, struct dfs_GetDcAddress *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_SetDcAddress(pipes_struct *p, struct dfs_SetDcAddress *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_FlushFtTable(pipes_struct *p, struct dfs_FlushFtTable *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_Add2(pipes_struct *p, struct dfs_Add2 *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_Remove2(pipes_struct *p, struct dfs_Remove2 *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_EnumEx(pipes_struct *p, struct dfs_EnumEx *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _dfs_SetInfo2(pipes_struct *p, struct dfs_SetInfo2 *r)
+{
+ /* FIXME: Implement your code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
diff --git a/source3/rpc_server/srv_dssetup_nt.c b/source3/rpc_server/srv_dssetup_nt.c
new file mode 100644
index 0000000000..2b18e6b2ae
--- /dev/null
+++ b/source3/rpc_server/srv_dssetup_nt.c
@@ -0,0 +1,223 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997.
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997.
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 2001.
+ * Copyright (C) Gerald Carter 2002.
+ * Copyright (C) Guenther Deschner 2008.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+/********************************************************************
+ Fill in a dssetup_DsRolePrimaryDomInfoBasic structure
+ ********************************************************************/
+
+static WERROR fill_dsrole_dominfo_basic(TALLOC_CTX *ctx,
+ struct dssetup_DsRolePrimaryDomInfoBasic **info)
+{
+ struct dssetup_DsRolePrimaryDomInfoBasic *basic = NULL;
+ char *dnsdomain = NULL;
+
+ DEBUG(10,("fill_dsrole_dominfo_basic: enter\n"));
+
+ basic = TALLOC_ZERO_P(ctx, struct dssetup_DsRolePrimaryDomInfoBasic);
+ if (!basic) {
+ DEBUG(0,("fill_dsrole_dominfo_basic: out of memory\n"));
+ return WERR_NOMEM;
+ }
+
+ switch (lp_server_role()) {
+ case ROLE_STANDALONE:
+ basic->role = DS_ROLE_STANDALONE_SERVER;
+ basic->domain = get_global_sam_name();
+ break;
+ case ROLE_DOMAIN_MEMBER:
+ basic->role = DS_ROLE_MEMBER_SERVER;
+ basic->domain = lp_workgroup();
+ break;
+ case ROLE_DOMAIN_BDC:
+ basic->role = DS_ROLE_BACKUP_DC;
+ basic->domain = get_global_sam_name();
+ break;
+ case ROLE_DOMAIN_PDC:
+ basic->role = DS_ROLE_PRIMARY_DC;
+ basic->domain = get_global_sam_name();
+ break;
+ }
+
+ if (secrets_fetch_domain_guid(lp_workgroup(), &basic->domain_guid)) {
+ basic->flags |= DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT;
+ }
+
+ /* fill in some additional fields if we are a member of an AD domain */
+
+ if (lp_security() == SEC_ADS) {
+ dnsdomain = talloc_strdup(ctx, lp_realm());
+ if (!dnsdomain) {
+ return WERR_NOMEM;
+ }
+ strlower_m(dnsdomain);
+ basic->dns_domain = dnsdomain;
+
+ /* FIXME!! We really should fill in the correct forest
+ name. Should get this information from winbindd. */
+ basic->forest = dnsdomain;
+ } else {
+ /* security = domain should not fill in the dns or
+ forest name */
+ basic->dns_domain = NULL;
+ basic->forest = NULL;
+ }
+
+ *info = basic;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ Implement the _dssetup_DsRoleGetPrimaryDomainInformation() call
+ ********************************************************************/
+
+WERROR _dssetup_DsRoleGetPrimaryDomainInformation(pipes_struct *p,
+ struct dssetup_DsRoleGetPrimaryDomainInformation *r)
+{
+ WERROR werr = WERR_OK;
+
+ switch (r->in.level) {
+
+ case DS_ROLE_BASIC_INFORMATION: {
+ struct dssetup_DsRolePrimaryDomInfoBasic *basic = NULL;
+ werr = fill_dsrole_dominfo_basic(p->mem_ctx, &basic);
+ if (W_ERROR_IS_OK(werr)) {
+ r->out.info->basic = *basic;
+ }
+ break;
+ }
+ default:
+ DEBUG(0,("_dssetup_DsRoleGetPrimaryDomainInformation: "
+ "Unknown info level [%d]!\n", r->in.level));
+ werr = WERR_UNKNOWN_LEVEL;
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _dssetup_DsRoleDnsNameToFlatName(pipes_struct *p,
+ struct dssetup_DsRoleDnsNameToFlatName *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _dssetup_DsRoleDcAsDc(pipes_struct *p,
+ struct dssetup_DsRoleDcAsDc *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _dssetup_DsRoleDcAsReplica(pipes_struct *p,
+ struct dssetup_DsRoleDcAsReplica *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _dssetup_DsRoleDemoteDc(pipes_struct *p,
+ struct dssetup_DsRoleDemoteDc *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _dssetup_DsRoleGetDcOperationProgress(pipes_struct *p,
+ struct dssetup_DsRoleGetDcOperationProgress *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _dssetup_DsRoleGetDcOperationResults(pipes_struct *p,
+ struct dssetup_DsRoleGetDcOperationResults *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _dssetup_DsRoleCancel(pipes_struct *p,
+ struct dssetup_DsRoleCancel *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _dssetup_DsRoleServerSaveStateForUpgrade(pipes_struct *p,
+ struct dssetup_DsRoleServerSaveStateForUpgrade *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _dssetup_DsRoleUpgradeDownlevelServer(pipes_struct *p,
+ struct dssetup_DsRoleUpgradeDownlevelServer *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _dssetup_DsRoleAbortDownlevelServerUpgrade(pipes_struct *p,
+ struct dssetup_DsRoleAbortDownlevelServerUpgrade *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
diff --git a/source3/rpc_server/srv_echo_nt.c b/source3/rpc_server/srv_echo_nt.c
new file mode 100644
index 0000000000..1179a162b0
--- /dev/null
+++ b/source3/rpc_server/srv_echo_nt.c
@@ -0,0 +1,125 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines for rpcecho
+ * Copyright (C) Tim Potter 2003
+ * Copyright (C) Jelmer Vernooij 2006
+ * Copyright (C) Gerald (Jerry) Carter 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This is the interface to the rpcecho pipe. */
+
+#include "includes.h"
+#include "nterr.h"
+
+#ifdef DEVELOPER
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+/* Add one to the input and return it */
+
+void _echo_AddOne(pipes_struct *p, struct echo_AddOne *r )
+{
+ DEBUG(10, ("_echo_AddOne\n"));
+
+ *r->out.out_data = r->in.in_data + 1;
+}
+
+/* Echo back an array of data */
+
+void _echo_EchoData(pipes_struct *p, struct echo_EchoData *r)
+{
+ DEBUG(10, ("_echo_EchoData\n"));
+
+ if ( r->in.len == 0 ) {
+ r->out.out_data = NULL;
+ return;
+ }
+
+ r->out.out_data = TALLOC_ARRAY(p->mem_ctx, uint8, r->in.len);
+ memcpy( r->out.out_data, r->in.in_data, r->in.len );
+ return;
+}
+
+/* Sink an array of data */
+
+void _echo_SinkData(pipes_struct *p, struct echo_SinkData *r)
+{
+ DEBUG(10, ("_echo_SinkData\n"));
+
+ /* My that was some yummy data! */
+ return;
+}
+
+/* Source an array of data */
+
+void _echo_SourceData(pipes_struct *p, struct echo_SourceData *r)
+{
+ uint32 i;
+
+ DEBUG(10, ("_echo_SourceData\n"));
+
+ if ( r->in.len == 0 ) {
+ r->out.data = NULL;
+ return;
+ }
+
+ r->out.data = TALLOC_ARRAY(p->mem_ctx, uint8, r->in.len );
+
+ for (i = 0; i < r->in.len; i++ ) {
+ r->out.data[i] = i & 0xff;
+ }
+
+ return;
+}
+
+void _echo_TestCall(pipes_struct *p, struct echo_TestCall *r)
+{
+ p->rng_fault_state = True;
+ return;
+}
+
+NTSTATUS _echo_TestCall2(pipes_struct *p, struct echo_TestCall2 *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_OK;
+}
+
+uint32 _echo_TestSleep(pipes_struct *p, struct echo_TestSleep *r)
+{
+ p->rng_fault_state = True;
+ return 0;
+}
+
+void _echo_TestEnum(pipes_struct *p, struct echo_TestEnum *r)
+{
+ p->rng_fault_state = True;
+ return;
+}
+
+void _echo_TestSurrounding(pipes_struct *p, struct echo_TestSurrounding *r)
+{
+ p->rng_fault_state = True;
+ return;
+}
+
+uint16 _echo_TestDoublePointer(pipes_struct *p, struct echo_TestDoublePointer *r)
+{
+ p->rng_fault_state = True;
+ return 0;
+}
+
+#endif /* DEVELOPER */
diff --git a/source3/rpc_server/srv_eventlog.c b/source3/rpc_server/srv_eventlog.c
new file mode 100644
index 0000000000..da761c905e
--- /dev/null
+++ b/source3/rpc_server/srv_eventlog.c
@@ -0,0 +1,118 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Marcin Krzysztof Porwit 2005.
+ * Copyright (C) Gerald Carter 2005 - 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+static bool proxy_eventlog_call(pipes_struct *p, uint8 opnum)
+{
+ struct api_struct *fns;
+ int n_fns;
+
+ eventlog_get_pipe_fns(&fns, &n_fns);
+
+ if (opnum >= n_fns)
+ return False;
+
+ if (fns[opnum].opnum != opnum) {
+ smb_panic("EVENTLOG function table not sorted\n");
+ }
+
+ return fns[opnum].fn(p);
+}
+
+static bool api_eventlog_open_eventlog(pipes_struct *p)
+{
+ return proxy_eventlog_call(p, NDR_EVENTLOG_OPENEVENTLOGW);
+}
+
+static bool api_eventlog_close_eventlog(pipes_struct *p)
+{
+ return proxy_eventlog_call( p, NDR_EVENTLOG_CLOSEEVENTLOG );
+}
+
+static bool api_eventlog_get_num_records(pipes_struct *p)
+{
+ return proxy_eventlog_call(p, NDR_EVENTLOG_GETNUMRECORDS);
+}
+
+static bool api_eventlog_get_oldest_entry(pipes_struct *p)
+{
+ return proxy_eventlog_call(p, NDR_EVENTLOG_GETOLDESTRECORD);
+}
+
+static bool api_eventlog_read_eventlog(pipes_struct *p)
+{
+ EVENTLOG_Q_READ_EVENTLOG q_u;
+ EVENTLOG_R_READ_EVENTLOG r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!(eventlog_io_q_read_eventlog("", &q_u, data, 0))) {
+ DEBUG(0, ("eventlog_io_q_read_eventlog: unable to unmarshall EVENTLOG_Q_READ_EVENTLOG.\n"));
+ return False;
+ }
+
+ r_u.status = _eventlog_read_eventlog(p, &q_u, &r_u);
+
+ if (!(eventlog_io_r_read_eventlog("", &q_u, &r_u, rdata, 0))) {
+ DEBUG(0, ("eventlog_io_r_read_eventlog: unable to marshall EVENTLOG_R_READ_EVENTLOG.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+static bool api_eventlog_clear_eventlog(pipes_struct *p)
+{
+ return proxy_eventlog_call(p, NDR_EVENTLOG_CLEAREVENTLOGW);
+}
+
+/*
+ \pipe\eventlog commands
+*/
+struct api_struct api_eventlog_cmds[] =
+{
+ {"EVENTLOG_OPENEVENTLOG", EVENTLOG_OPENEVENTLOG, api_eventlog_open_eventlog },
+ {"EVENTLOG_CLOSEEVENTLOG", EVENTLOG_CLOSEEVENTLOG, api_eventlog_close_eventlog },
+ {"EVENTLOG_GETNUMRECORDS", EVENTLOG_GETNUMRECORDS, api_eventlog_get_num_records },
+ {"EVENTLOG_GETOLDESTENTRY", EVENTLOG_GETOLDESTENTRY, api_eventlog_get_oldest_entry },
+ {"EVENTLOG_READEVENTLOG", EVENTLOG_READEVENTLOG, api_eventlog_read_eventlog },
+ {"EVENTLOG_CLEAREVENTLOG", EVENTLOG_CLEAREVENTLOG, api_eventlog_clear_eventlog }
+};
+
+NTSTATUS rpc_eventlog2_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION,
+ "eventlog", "eventlog", &ndr_table_eventlog.syntax_id,
+ api_eventlog_cmds,
+ sizeof(api_eventlog_cmds)/sizeof(struct api_struct));
+}
+
+void eventlog2_get_pipe_fns(struct api_struct **fns, int *n_fns)
+{
+ *fns = api_eventlog_cmds;
+ *n_fns = sizeof(api_eventlog_cmds) / sizeof(struct api_struct);
+}
diff --git a/source3/rpc_server/srv_eventlog_lib.c b/source3/rpc_server/srv_eventlog_lib.c
new file mode 100644
index 0000000000..e232a30078
--- /dev/null
+++ b/source3/rpc_server/srv_eventlog_lib.c
@@ -0,0 +1,742 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Eventlog utility routines
+ * Copyright (C) Marcin Krzysztof Porwit 2005,
+ * Copyright (C) Brian Moran 2005.
+ * Copyright (C) Gerald (Jerry) Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/* maintain a list of open eventlog tdbs with reference counts */
+
+static ELOG_TDB *open_elog_list;
+
+/********************************************************************
+ Init an Eventlog TDB, and return it. If null, something bad
+ happened.
+********************************************************************/
+
+TDB_CONTEXT *elog_init_tdb( char *tdbfilename )
+{
+ TDB_CONTEXT *tdb;
+
+ DEBUG(10,("elog_init_tdb: Initializing eventlog tdb (%s)\n",
+ tdbfilename));
+
+ tdb = tdb_open_log( tdbfilename, 0, TDB_DEFAULT,
+ O_RDWR|O_CREAT|O_TRUNC, 0660 );
+
+ if ( !tdb ) {
+ DEBUG( 0, ( "Can't open tdb for [%s]\n", tdbfilename ) );
+ return NULL;
+ }
+
+ /* initialize with defaults, copy real values in here from registry */
+
+ tdb_store_int32( tdb, EVT_OLDEST_ENTRY, 1 );
+ tdb_store_int32( tdb, EVT_NEXT_RECORD, 1 );
+ tdb_store_int32( tdb, EVT_MAXSIZE, 0x80000 );
+ tdb_store_int32( tdb, EVT_RETENTION, 0x93A80 );
+
+ tdb_store_int32( tdb, EVT_VERSION, EVENTLOG_DATABASE_VERSION_V1 );
+
+ return tdb;
+}
+
+/********************************************************************
+ make the tdb file name for an event log, given destination buffer
+ and size. Caller must free memory.
+********************************************************************/
+
+char *elog_tdbname(TALLOC_CTX *ctx, const char *name )
+{
+ char *path = talloc_asprintf(ctx, "%s/%s.tdb",
+ state_path("eventlog"),
+ name);
+ if (!path) {
+ return NULL;
+ }
+ strlower_m(path);
+ return path;
+}
+
+
+/********************************************************************
+ this function is used to count up the number of bytes in a
+ particular TDB
+********************************************************************/
+
+struct trav_size_struct {
+ int size;
+ int rec_count;
+};
+
+static int eventlog_tdb_size_fn( TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data,
+ void *state )
+{
+ struct trav_size_struct *tsize = (struct trav_size_struct *)state;
+
+ tsize->size += data.dsize;
+ tsize->rec_count++;
+
+ return 0;
+}
+
+/********************************************************************
+ returns the size of the eventlog, and if MaxSize is a non-null
+ ptr, puts the MaxSize there. This is purely a way not to have yet
+ another function that solely reads the maxsize of the eventlog.
+ Yeah, that's it.
+********************************************************************/
+
+int elog_tdb_size( TDB_CONTEXT * tdb, int *MaxSize, int *Retention )
+{
+ struct trav_size_struct tsize;
+
+ if ( !tdb )
+ return 0;
+
+ ZERO_STRUCT( tsize );
+
+ tdb_traverse( tdb, eventlog_tdb_size_fn, &tsize );
+
+ if ( MaxSize != NULL ) {
+ *MaxSize = tdb_fetch_int32( tdb, EVT_MAXSIZE );
+ }
+
+ if ( Retention != NULL ) {
+ *Retention = tdb_fetch_int32( tdb, EVT_RETENTION );
+ }
+
+ DEBUG( 1,
+ ( "eventlog size: [%d] for [%d] records\n", tsize.size,
+ tsize.rec_count ) );
+ return tsize.size;
+}
+
+/********************************************************************
+ Discard early event logs until we have enough for 'needed' bytes...
+ NO checking done beforehand to see that we actually need to do
+ this, and it's going to pluck records one-by-one. So, it's best
+ to determine that this needs to be done before doing it.
+
+ Setting whack_by_date to True indicates that eventlogs falling
+ outside of the retention range need to go...
+
+ return True if we made enough room to accommodate needed bytes
+********************************************************************/
+
+static bool make_way_for_eventlogs( TDB_CONTEXT * the_tdb, int32 needed,
+ bool whack_by_date )
+{
+ int start_record, i, new_start;
+ int end_record;
+ int nbytes, reclen, len, Retention, MaxSize;
+ int tresv1, trecnum, timegen, timewr;
+ TDB_DATA key, ret;
+ time_t current_time, exp_time;
+
+ /* discard some eventlogs */
+
+ /* read eventlogs from oldest_entry -- there can't be any discontinuity in recnos,
+ although records not necessarily guaranteed to have successive times */
+ /* */
+
+ /* lock */
+ tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
+ /* read */
+ end_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
+ start_record = tdb_fetch_int32( the_tdb, EVT_OLDEST_ENTRY );
+ Retention = tdb_fetch_int32( the_tdb, EVT_RETENTION );
+ MaxSize = tdb_fetch_int32( the_tdb, EVT_MAXSIZE );
+
+ time( &current_time );
+
+ /* calculate ... */
+ exp_time = current_time - Retention; /* discard older than exp_time */
+
+ /* todo - check for sanity in next_record */
+ nbytes = 0;
+
+ DEBUG( 3,
+ ( "MaxSize [%d] Retention [%d] Current Time [%d] exp_time [%d]\n",
+ MaxSize, Retention, (uint32)current_time, (uint32)exp_time ) );
+ DEBUG( 3,
+ ( "Start Record [%d] End Record [%d]\n", start_record,
+ end_record ) );
+
+ for ( i = start_record; i < end_record; i++ ) {
+ /* read a record, add the amt to nbytes */
+ key.dsize = sizeof( int32 );
+ key.dptr = ( uint8 * ) ( int32 * ) & i;
+ ret = tdb_fetch( the_tdb, key );
+ if ( ret.dsize == 0 ) {
+ DEBUG( 8,
+ ( "Can't find a record for the key, record [%d]\n",
+ i ) );
+ tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
+ return False;
+ }
+ nbytes += ret.dsize; /* note this includes overhead */
+
+ len = tdb_unpack( ret.dptr, ret.dsize, "ddddd", &reclen,
+ &tresv1, &trecnum, &timegen, &timewr );
+ if (len == -1) {
+ DEBUG( 10,("make_way_for_eventlogs: tdb_unpack failed.\n"));
+ tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
+ return False;
+ }
+
+ DEBUG( 8,
+ ( "read record %d, record size is [%d], total so far [%d]\n",
+ i, reclen, nbytes ) );
+
+ SAFE_FREE( ret.dptr );
+
+ /* note that other servers may just stop writing records when the size limit
+ is reached, and there are no records older than 'retention'. This doesn't
+ like a very useful thing to do, so instead we whack (as in sleeps with the
+ fishes) just enough records to fit the what we need. This behavior could
+ be changed to 'match', if the need arises. */
+
+ if ( !whack_by_date && ( nbytes >= needed ) )
+ break; /* done */
+ if ( whack_by_date && ( timegen >= exp_time ) )
+ break; /* done */
+ }
+
+ DEBUG( 3,
+ ( "nbytes [%d] needed [%d] start_record is [%d], should be set to [%d]\n",
+ nbytes, needed, start_record, i ) );
+ /* todo - remove eventlog entries here and set starting record to start_record... */
+ new_start = i;
+ if ( start_record != new_start ) {
+ for ( i = start_record; i < new_start; i++ ) {
+ key.dsize = sizeof( int32 );
+ key.dptr = ( uint8 * ) ( int32 * ) & i;
+ tdb_delete( the_tdb, key );
+ }
+
+ tdb_store_int32( the_tdb, EVT_OLDEST_ENTRY, new_start );
+ }
+ tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
+ return True;
+}
+
+/********************************************************************
+ some hygiene for an eventlog - see how big it is, and then
+ calculate how many bytes we need to remove
+********************************************************************/
+
+bool prune_eventlog( TDB_CONTEXT * tdb )
+{
+ int MaxSize, Retention, CalcdSize;
+
+ if ( !tdb ) {
+ DEBUG( 4, ( "No eventlog tdb handle\n" ) );
+ return False;
+ }
+
+ CalcdSize = elog_tdb_size( tdb, &MaxSize, &Retention );
+ DEBUG( 3,
+ ( "Calculated size [%d] MaxSize [%d]\n", CalcdSize,
+ MaxSize ) );
+
+ if ( CalcdSize > MaxSize ) {
+ return make_way_for_eventlogs( tdb, CalcdSize - MaxSize,
+ False );
+ }
+
+ return make_way_for_eventlogs( tdb, 0, True );
+}
+
+/********************************************************************
+********************************************************************/
+
+bool can_write_to_eventlog( TDB_CONTEXT * tdb, int32 needed )
+{
+ int calcd_size;
+ int MaxSize, Retention;
+
+ /* see if we can write to the eventlog -- do a policy enforcement */
+ if ( !tdb )
+ return False; /* tdb is null, so we can't write to it */
+
+
+ if ( needed < 0 )
+ return False;
+ MaxSize = 0;
+ Retention = 0;
+
+ calcd_size = elog_tdb_size( tdb, &MaxSize, &Retention );
+
+ if ( calcd_size <= MaxSize )
+ return True; /* you betcha */
+ if ( calcd_size + needed < MaxSize )
+ return True;
+
+ if ( Retention == 0xffffffff ) {
+ return False; /* see msdn - we can't write no room, discard */
+ }
+ /*
+ note don't have to test, but always good to show intent, in case changes needed
+ later
+ */
+
+ if ( Retention == 0x00000000 ) {
+ /* discard record(s) */
+ /* todo - decide when to remove a bunch vs. just what we need... */
+ return make_way_for_eventlogs( tdb, calcd_size - MaxSize,
+ True );
+ }
+
+ return make_way_for_eventlogs( tdb, calcd_size - MaxSize, False );
+}
+
+/*******************************************************************
+*******************************************************************/
+
+ELOG_TDB *elog_open_tdb( char *logname, bool force_clear )
+{
+ TDB_CONTEXT *tdb = NULL;
+ uint32 vers_id;
+ ELOG_TDB *ptr;
+ char *tdbpath = NULL;
+ ELOG_TDB *tdb_node = NULL;
+ char *eventlogdir;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ /* first see if we have an open context */
+
+ for ( ptr=open_elog_list; ptr; ptr=ptr->next ) {
+ if ( strequal( ptr->name, logname ) ) {
+ ptr->ref_count++;
+
+ /* trick to alow clearing of the eventlog tdb.
+ The force_clear flag should imply that someone
+ has done a force close. So make sure the tdb
+ is NULL. If this is a normal open, then just
+ return the existing reference */
+
+ if ( force_clear ) {
+ SMB_ASSERT( ptr->tdb == NULL );
+ break;
+ }
+ else
+ return ptr;
+ }
+ }
+
+ /* make sure that the eventlog dir exists */
+
+ eventlogdir = state_path( "eventlog" );
+ if ( !directory_exist( eventlogdir, NULL ) )
+ mkdir( eventlogdir, 0755 );
+
+ /* get the path on disk */
+
+ tdbpath = elog_tdbname(ctx, logname);
+ if (!tdbpath) {
+ return NULL;
+ }
+
+ DEBUG(7,("elog_open_tdb: Opening %s...(force_clear == %s)\n",
+ tdbpath, force_clear?"True":"False" ));
+
+ /* the tdb wasn't already open or this is a forced clear open */
+
+ if ( !force_clear ) {
+
+ tdb = tdb_open_log( tdbpath, 0, TDB_DEFAULT, O_RDWR , 0 );
+ if ( tdb ) {
+ vers_id = tdb_fetch_int32( tdb, EVT_VERSION );
+
+ if ( vers_id != EVENTLOG_DATABASE_VERSION_V1 ) {
+ DEBUG(1,("elog_open_tdb: Invalid version [%d] on file [%s].\n",
+ vers_id, tdbpath));
+ tdb_close( tdb );
+ tdb = elog_init_tdb( tdbpath );
+ }
+ }
+ }
+
+ if ( !tdb )
+ tdb = elog_init_tdb( tdbpath );
+
+ /* if we got a valid context, then add it to the list */
+
+ if ( tdb ) {
+ /* on a forced clear, just reset the tdb context if we already
+ have an open entry in the list */
+
+ if ( ptr ) {
+ ptr->tdb = tdb;
+ return ptr;
+ }
+
+ if ( !(tdb_node = TALLOC_ZERO_P( NULL, ELOG_TDB)) ) {
+ DEBUG(0,("elog_open_tdb: talloc() failure!\n"));
+ tdb_close( tdb );
+ return NULL;
+ }
+
+ tdb_node->name = talloc_strdup( tdb_node, logname );
+ tdb_node->tdb = tdb;
+ tdb_node->ref_count = 1;
+
+ DLIST_ADD( open_elog_list, tdb_node );
+ }
+
+ return tdb_node;
+}
+
+/*******************************************************************
+ Wrapper to handle reference counts to the tdb
+*******************************************************************/
+
+int elog_close_tdb( ELOG_TDB *etdb, bool force_close )
+{
+ TDB_CONTEXT *tdb;
+
+ if ( !etdb )
+ return 0;
+
+ etdb->ref_count--;
+
+ SMB_ASSERT( etdb->ref_count >= 0 );
+
+ if ( etdb->ref_count == 0 ) {
+ tdb = etdb->tdb;
+ DLIST_REMOVE( open_elog_list, etdb );
+ TALLOC_FREE( etdb );
+ return tdb_close( tdb );
+ }
+
+ if ( force_close ) {
+ tdb = etdb->tdb;
+ etdb->tdb = NULL;
+ return tdb_close( tdb );
+ }
+
+ return 0;
+}
+
+
+/*******************************************************************
+ write an eventlog entry. Note that we have to lock, read next
+ eventlog, increment, write, write the record, unlock
+
+ coming into this, ee has the eventlog record, and the auxilliary date
+ (computer name, etc.) filled into the other structure. Before packing
+ into a record, this routine will calc the appropriate padding, etc.,
+ and then blast out the record in a form that can be read back in
+*******************************************************************/
+
+#define MARGIN 512
+
+int write_eventlog_tdb( TDB_CONTEXT * the_tdb, Eventlog_entry * ee )
+{
+ int32 next_record;
+ uint8 *packed_ee;
+ TALLOC_CTX *mem_ctx = NULL;
+ TDB_DATA kbuf, ebuf;
+ uint32 n_packed;
+
+ if ( !ee )
+ return 0;
+
+ mem_ctx = talloc_init( "write_eventlog_tdb" );
+
+ if ( mem_ctx == NULL )
+ return 0;
+
+ /* discard any entries that have bogus time, which usually indicates a bogus entry as well. */
+ if ( ee->record.time_generated == 0 )
+ return 0;
+
+ /* todo - check for sanity in next_record */
+
+ fixup_eventlog_entry( ee );
+
+ if ( !can_write_to_eventlog( the_tdb, ee->record.length ) ) {
+ DEBUG( 3, ( "Can't write to Eventlog, no room \n" ) );
+ talloc_destroy( mem_ctx );
+ return 0;
+ }
+
+ /* alloc mem for the packed version */
+ packed_ee = (uint8 *)TALLOC( mem_ctx, ee->record.length + MARGIN );
+ if ( !packed_ee ) {
+ talloc_destroy( mem_ctx );
+ return 0;
+ }
+
+ /* need to read the record number and insert it into the entry here */
+
+ /* lock */
+ tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
+ /* read */
+ next_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
+
+ n_packed =
+ tdb_pack( (uint8 *)packed_ee, ee->record.length + MARGIN,
+ "ddddddwwwwddddddBBdBBBd", ee->record.length,
+ ee->record.reserved1, next_record,
+ ee->record.time_generated, ee->record.time_written,
+ ee->record.event_id, ee->record.event_type,
+ ee->record.num_strings, ee->record.event_category,
+ ee->record.reserved2,
+ ee->record.closing_record_number,
+ ee->record.string_offset,
+ ee->record.user_sid_length,
+ ee->record.user_sid_offset, ee->record.data_length,
+ ee->record.data_offset,
+ ee->data_record.source_name_len,
+ ee->data_record.source_name,
+ ee->data_record.computer_name_len,
+ ee->data_record.computer_name,
+ ee->data_record.sid_padding,
+ ee->record.user_sid_length, ee->data_record.sid,
+ ee->data_record.strings_len,
+ ee->data_record.strings,
+ ee->data_record.user_data_len,
+ ee->data_record.user_data,
+ ee->data_record.data_padding );
+
+ /*DEBUG(3,("write_eventlog_tdb: packed into %d\n",n_packed)); */
+
+ /* increment the record count */
+
+ kbuf.dsize = sizeof( int32 );
+ kbuf.dptr = (uint8 * ) & next_record;
+
+ ebuf.dsize = n_packed;
+ ebuf.dptr = (uint8 *)packed_ee;
+
+ if ( tdb_store( the_tdb, kbuf, ebuf, 0 ) ) {
+ /* DEBUG(1,("write_eventlog_tdb: Can't write record %d to eventlog\n",next_record)); */
+ tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
+ talloc_destroy( mem_ctx );
+ return 0;
+ }
+ next_record++;
+ tdb_store_int32( the_tdb, EVT_NEXT_RECORD, next_record );
+ tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
+ talloc_destroy( mem_ctx );
+ return ( next_record - 1 );
+}
+
+/*******************************************************************
+ calculate the correct fields etc for an eventlog entry
+*******************************************************************/
+
+void fixup_eventlog_entry( Eventlog_entry * ee )
+{
+ /* fix up the eventlog entry structure as necessary */
+
+ ee->data_record.sid_padding =
+ ( ( 4 -
+ ( ( ee->data_record.source_name_len +
+ ee->data_record.computer_name_len ) % 4 ) ) % 4 );
+ ee->data_record.data_padding =
+ ( 4 -
+ ( ( ee->data_record.strings_len +
+ ee->data_record.user_data_len ) % 4 ) ) % 4;
+ ee->record.length = sizeof( Eventlog_record );
+ ee->record.length += ee->data_record.source_name_len;
+ ee->record.length += ee->data_record.computer_name_len;
+ if ( ee->record.user_sid_length == 0 ) {
+ /* Should not pad to a DWORD boundary for writing out the sid if there is
+ no SID, so just propagate the padding to pad the data */
+ ee->data_record.data_padding += ee->data_record.sid_padding;
+ ee->data_record.sid_padding = 0;
+ }
+ /* DEBUG(10, ("sid_padding is [%d].\n", ee->data_record.sid_padding)); */
+ /* DEBUG(10, ("data_padding is [%d].\n", ee->data_record.data_padding)); */
+
+ ee->record.length += ee->data_record.sid_padding;
+ ee->record.length += ee->record.user_sid_length;
+ ee->record.length += ee->data_record.strings_len;
+ ee->record.length += ee->data_record.user_data_len;
+ ee->record.length += ee->data_record.data_padding;
+ /* need another copy of length at the end of the data */
+ ee->record.length += sizeof( ee->record.length );
+}
+
+/********************************************************************
+ Note that it's a pretty good idea to initialize the Eventlog_entry
+ structure to zero's before calling parse_logentry on an batch of
+ lines that may resolve to a record. ALSO, it's a good idea to
+ remove any linefeeds (that's EOL to you and me) on the lines
+ going in.
+********************************************************************/
+
+bool parse_logentry( char *line, Eventlog_entry * entry, bool * eor )
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *start = NULL, *stop = NULL;
+
+ start = line;
+
+ /* empty line signyfiying record delimeter, or we're at the end of the buffer */
+ if ( start == NULL || strlen( start ) == 0 ) {
+ DEBUG( 6,
+ ( "parse_logentry: found end-of-record indicator.\n" ) );
+ *eor = True;
+ return True;
+ }
+ if ( !( stop = strchr( line, ':' ) ) ) {
+ return False;
+ }
+
+ DEBUG( 6, ( "parse_logentry: trying to parse [%s].\n", line ) );
+
+ if ( 0 == strncmp( start, "LEN", stop - start ) ) {
+ /* This will get recomputed later anyway -- probably not necessary */
+ entry->record.length = atoi( stop + 1 );
+ } else if ( 0 == strncmp( start, "RS1", stop - start ) ) {
+ /* For now all these reserved entries seem to have the same value,
+ which can be hardcoded to int(1699505740) for now */
+ entry->record.reserved1 = atoi( stop + 1 );
+ } else if ( 0 == strncmp( start, "RCN", stop - start ) ) {
+ entry->record.record_number = atoi( stop + 1 );
+ } else if ( 0 == strncmp( start, "TMG", stop - start ) ) {
+ entry->record.time_generated = atoi( stop + 1 );
+ } else if ( 0 == strncmp( start, "TMW", stop - start ) ) {
+ entry->record.time_written = atoi( stop + 1 );
+ } else if ( 0 == strncmp( start, "EID", stop - start ) ) {
+ entry->record.event_id = atoi( stop + 1 );
+ } else if ( 0 == strncmp( start, "ETP", stop - start ) ) {
+ if ( strstr( start, "ERROR" ) ) {
+ entry->record.event_type = EVENTLOG_ERROR_TYPE;
+ } else if ( strstr( start, "WARNING" ) ) {
+ entry->record.event_type = EVENTLOG_WARNING_TYPE;
+ } else if ( strstr( start, "INFO" ) ) {
+ entry->record.event_type = EVENTLOG_INFORMATION_TYPE;
+ } else if ( strstr( start, "AUDIT_SUCCESS" ) ) {
+ entry->record.event_type = EVENTLOG_AUDIT_SUCCESS;
+ } else if ( strstr( start, "AUDIT_FAILURE" ) ) {
+ entry->record.event_type = EVENTLOG_AUDIT_FAILURE;
+ } else if ( strstr( start, "SUCCESS" ) ) {
+ entry->record.event_type = EVENTLOG_SUCCESS;
+ } else {
+ /* some other eventlog type -- currently not defined in MSDN docs, so error out */
+ return False;
+ }
+ }
+
+/*
+ else if(0 == strncmp(start, "NST", stop - start))
+ {
+ entry->record.num_strings = atoi(stop + 1);
+ }
+*/
+ else if ( 0 == strncmp( start, "ECT", stop - start ) ) {
+ entry->record.event_category = atoi( stop + 1 );
+ } else if ( 0 == strncmp( start, "RS2", stop - start ) ) {
+ entry->record.reserved2 = atoi( stop + 1 );
+ } else if ( 0 == strncmp( start, "CRN", stop - start ) ) {
+ entry->record.closing_record_number = atoi( stop + 1 );
+ } else if ( 0 == strncmp( start, "USL", stop - start ) ) {
+ entry->record.user_sid_length = atoi( stop + 1 );
+ } else if ( 0 == strncmp( start, "SRC", stop - start ) ) {
+ stop++;
+ while ( isspace( stop[0] ) ) {
+ stop++;
+ }
+ entry->data_record.source_name_len = rpcstr_push_talloc(ctx,
+ &entry->data_record.source_name,
+ stop);
+ if (entry->data_record.source_name_len == (uint32_t)-1 ||
+ entry->data_record.source_name == NULL) {
+ return false;
+ }
+ } else if ( 0 == strncmp( start, "SRN", stop - start ) ) {
+ stop++;
+ while ( isspace( stop[0] ) ) {
+ stop++;
+ }
+ entry->data_record.computer_name_len = rpcstr_push_talloc(ctx,
+ &entry->data_record.computer_name,
+ stop);
+ if (entry->data_record.computer_name_len == (uint32_t)-1 ||
+ entry->data_record.computer_name == NULL) {
+ return false;
+ }
+ } else if ( 0 == strncmp( start, "SID", stop - start ) ) {
+ stop++;
+ while ( isspace( stop[0] ) ) {
+ stop++;
+ }
+ entry->record.user_sid_length = rpcstr_push_talloc(ctx,
+ &entry->data_record.sid,
+ stop);
+ if (entry->record.user_sid_length == (uint32_t)-1 ||
+ entry->data_record.sid == NULL) {
+ return false;
+ }
+ } else if ( 0 == strncmp( start, "STR", stop - start ) ) {
+ smb_ucs2_t *temp = NULL;
+ size_t tmp_len;
+ uint32_t old_len;
+ /* skip past initial ":" */
+ stop++;
+ /* now skip any other leading whitespace */
+ while ( isspace(stop[0])) {
+ stop++;
+ }
+ tmp_len = rpcstr_push_talloc(ctx,
+ &temp,
+ stop);
+ if (tmp_len == (size_t)-1 || !temp) {
+ return false;
+ }
+ old_len = entry->data_record.strings_len;
+ entry->data_record.strings = (smb_ucs2_t *)TALLOC_REALLOC_ARRAY(ctx,
+ entry->data_record.strings,
+ char,
+ old_len + tmp_len);
+ if (!entry->data_record.strings) {
+ return false;
+ }
+ memcpy(entry->data_record.strings + old_len,
+ temp,
+ tmp_len);
+ entry->data_record.strings_len += tmp_len;
+ entry->record.num_strings++;
+ } else if ( 0 == strncmp( start, "DAT", stop - start ) ) {
+ /* skip past initial ":" */
+ stop++;
+ /* now skip any other leading whitespace */
+ while ( isspace( stop[0] ) ) {
+ stop++;
+ }
+ entry->data_record.user_data_len = strlen(stop);
+ entry->data_record.user_data = talloc_strdup(ctx,
+ stop);
+ if (!entry->data_record.user_data) {
+ return false;
+ }
+ } else {
+ /* some other eventlog entry -- not implemented, so dropping on the floor */
+ DEBUG( 10, ( "Unknown entry [%s]. Ignoring.\n", line ) );
+ /* For now return true so that we can keep on parsing this mess. Eventually
+ we will return False here. */
+ return true;
+ }
+ return true;
+}
diff --git a/source3/rpc_server/srv_eventlog_nt.c b/source3/rpc_server/srv_eventlog_nt.c
new file mode 100644
index 0000000000..0e2bcf4126
--- /dev/null
+++ b/source3/rpc_server/srv_eventlog_nt.c
@@ -0,0 +1,968 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Marcin Krzysztof Porwit 2005,
+ * Copyright (C) Brian Moran 2005,
+ * Copyright (C) Gerald (Jerry) Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+typedef struct {
+ char *logname;
+ ELOG_TDB *etdb;
+ uint32 current_record;
+ uint32 num_records;
+ uint32 oldest_entry;
+ uint32 flags;
+ uint32 access_granted;
+} EVENTLOG_INFO;
+
+/********************************************************************
+ ********************************************************************/
+
+static void free_eventlog_info( void *ptr )
+{
+ EVENTLOG_INFO *elog = (EVENTLOG_INFO *)ptr;
+
+ if ( elog->etdb )
+ elog_close_tdb( elog->etdb, False );
+
+ TALLOC_FREE( elog );
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static EVENTLOG_INFO *find_eventlog_info_by_hnd( pipes_struct * p,
+ POLICY_HND * handle )
+{
+ EVENTLOG_INFO *info;
+
+ if ( !find_policy_by_hnd( p, handle, (void **)(void *)&info ) ) {
+ DEBUG( 2,
+ ( "find_eventlog_info_by_hnd: eventlog not found.\n" ) );
+ return NULL;
+ }
+
+ return info;
+}
+
+/********************************************************************
+********************************************************************/
+
+static bool elog_check_access( EVENTLOG_INFO *info, NT_USER_TOKEN *token )
+{
+ char *tdbname = elog_tdbname(talloc_tos(), info->logname );
+ SEC_DESC *sec_desc;
+ bool ret;
+ NTSTATUS ntstatus;
+
+ if ( !tdbname )
+ return False;
+
+ /* get the security descriptor for the file */
+
+ sec_desc = get_nt_acl_no_snum( info, tdbname );
+ SAFE_FREE( tdbname );
+
+ if ( !sec_desc ) {
+ DEBUG(5,("elog_check_access: Unable to get NT ACL for %s\n",
+ tdbname));
+ return False;
+ }
+
+ /* root free pass */
+
+ if ( geteuid() == sec_initial_uid() ) {
+ DEBUG(5,("elog_check_access: using root's token\n"));
+ token = get_root_nt_token();
+ }
+
+ /* run the check, try for the max allowed */
+
+ ret = se_access_check( sec_desc, token, MAXIMUM_ALLOWED_ACCESS,
+ &info->access_granted, &ntstatus );
+
+ if ( sec_desc )
+ TALLOC_FREE( sec_desc );
+
+ if ( !ret ) {
+ DEBUG(8,("elog_check_access: se_access_check() return %s\n",
+ nt_errstr( ntstatus)));
+ return False;
+ }
+
+ /* we have to have READ permission for a successful open */
+
+ return ( info->access_granted & SA_RIGHT_FILE_READ_DATA );
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static bool elog_validate_logname( const char *name )
+{
+ int i;
+ const char **elogs = lp_eventlog_list();
+
+ if (!elogs) {
+ return False;
+ }
+
+ for ( i=0; elogs[i]; i++ ) {
+ if ( strequal( name, elogs[i] ) )
+ return True;
+ }
+
+ return False;
+}
+
+/********************************************************************
+********************************************************************/
+
+static bool get_num_records_hook( EVENTLOG_INFO * info )
+{
+ int next_record;
+ int oldest_record;
+
+ if ( !info->etdb ) {
+ DEBUG( 10, ( "No open tdb for %s\n", info->logname ) );
+ return False;
+ }
+
+ /* lock the tdb since we have to get 2 records */
+
+ tdb_lock_bystring_with_timeout( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD, 1 );
+ next_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
+ oldest_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_OLDEST_ENTRY);
+ tdb_unlock_bystring( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
+
+ DEBUG( 8,
+ ( "Oldest Record %d; Next Record %d\n", oldest_record,
+ next_record ) );
+
+ info->num_records = ( next_record - oldest_record );
+ info->oldest_entry = oldest_record;
+
+ return True;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static bool get_oldest_entry_hook( EVENTLOG_INFO * info )
+{
+ /* it's the same thing */
+ return get_num_records_hook( info );
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static NTSTATUS elog_open( pipes_struct * p, const char *logname, POLICY_HND *hnd )
+{
+ EVENTLOG_INFO *elog;
+
+ /* first thing is to validate the eventlog name */
+
+ if ( !elog_validate_logname( logname ) )
+ return NT_STATUS_OBJECT_PATH_INVALID;
+
+ if ( !(elog = TALLOC_ZERO_P( NULL, EVENTLOG_INFO )) )
+ return NT_STATUS_NO_MEMORY;
+
+ elog->logname = talloc_strdup( elog, logname );
+
+ /* Open the tdb first (so that we can create any new tdbs if necessary).
+ We have to do this as root and then use an internal access check
+ on the file permissions since you can only have a tdb open once
+ in a single process */
+
+ become_root();
+ elog->etdb = elog_open_tdb( elog->logname, False );
+ unbecome_root();
+
+ if ( !elog->etdb ) {
+ /* according to MSDN, if the logfile cannot be found, we should
+ default to the "Application" log */
+
+ if ( !strequal( logname, ELOG_APPL ) ) {
+
+ TALLOC_FREE( elog->logname );
+
+ elog->logname = talloc_strdup( elog, ELOG_APPL );
+
+ /* do the access check */
+ if ( !elog_check_access( elog, p->pipe_user.nt_user_token ) ) {
+ TALLOC_FREE( elog );
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ become_root();
+ elog->etdb = elog_open_tdb( elog->logname, False );
+ unbecome_root();
+ }
+
+ if ( !elog->etdb ) {
+ TALLOC_FREE( elog );
+ return NT_STATUS_ACCESS_DENIED; /* ??? */
+ }
+ }
+
+ /* now do the access check. Close the tdb if we fail here */
+
+ if ( !elog_check_access( elog, p->pipe_user.nt_user_token ) ) {
+ elog_close_tdb( elog->etdb, False );
+ TALLOC_FREE( elog );
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* create the policy handle */
+
+ if ( !create_policy_hnd
+ ( p, hnd, free_eventlog_info, ( void * ) elog ) ) {
+ free_eventlog_info( elog );
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* set the initial current_record pointer */
+
+ if ( !get_oldest_entry_hook( elog ) ) {
+ DEBUG(3,("elog_open: Successfully opened eventlog but can't "
+ "get any information on internal records!\n"));
+ }
+
+ elog->current_record = elog->oldest_entry;
+
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static NTSTATUS elog_close( pipes_struct *p, POLICY_HND *hnd )
+{
+ if ( !( close_policy_hnd( p, hnd ) ) ) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ *******************************************************************/
+
+static int elog_size( EVENTLOG_INFO *info )
+{
+ if ( !info || !info->etdb ) {
+ DEBUG(0,("elog_size: Invalid info* structure!\n"));
+ return 0;
+ }
+
+ return elog_tdb_size( ELOG_TDB_CTX(info->etdb), NULL, NULL );
+}
+
+/********************************************************************
+ For the given tdb, get the next eventlog record into the passed
+ Eventlog_entry. returns NULL if it can't get the record for some reason.
+ ********************************************************************/
+
+static Eventlog_entry *get_eventlog_record(prs_struct *ps,
+ TDB_CONTEXT *tdb,
+ int recno)
+{
+ Eventlog_entry *ee = NULL;
+ TDB_DATA ret, key;
+
+ int srecno;
+ int reclen;
+ int len;
+
+ char *wpsource = NULL;
+ char *wpcomputer = NULL;
+ char *wpsid = NULL;
+ char *wpstrs = NULL;
+ char *puserdata = NULL;
+
+ key.dsize = sizeof(int32);
+
+ srecno = recno;
+ key.dptr = ( uint8 * ) &srecno;
+
+ ret = tdb_fetch( tdb, key );
+
+ if ( ret.dsize == 0 ) {
+ DEBUG( 8,
+ ( "Can't find a record for the key, record %d\n",
+ recno ) );
+ return NULL;
+ }
+
+ len = tdb_unpack( ret.dptr, ret.dsize, "d", &reclen );
+
+ DEBUG( 10, ( "Unpacking record %d, size is %d\n", srecno, len ) );
+
+ if ( !len )
+ return NULL;
+
+ ee = TALLOC_ARRAY(ps->mem_ctx, Eventlog_entry, 1);
+ if (!ee) {
+ return NULL;
+ }
+ ZERO_STRUCTP(ee);
+
+ len = tdb_unpack( ret.dptr, ret.dsize, "ddddddwwwwddddddBBdBBBd",
+ &ee->record.length, &ee->record.reserved1,
+ &ee->record.record_number,
+ &ee->record.time_generated,
+ &ee->record.time_written, &ee->record.event_id,
+ &ee->record.event_type, &ee->record.num_strings,
+ &ee->record.event_category, &ee->record.reserved2,
+ &ee->record.closing_record_number,
+ &ee->record.string_offset,
+ &ee->record.user_sid_length,
+ &ee->record.user_sid_offset,
+ &ee->record.data_length, &ee->record.data_offset,
+ &ee->data_record.source_name_len, &wpsource,
+ &ee->data_record.computer_name_len, &wpcomputer,
+ &ee->data_record.sid_padding,
+ &ee->record.user_sid_length, &wpsid,
+ &ee->data_record.strings_len, &wpstrs,
+ &ee->data_record.user_data_len, &puserdata,
+ &ee->data_record.data_padding );
+ DEBUG( 10,
+ ( "Read record %d, len in tdb was %d\n",
+ ee->record.record_number, len ) );
+
+ /* have to do the following because the tdb_unpack allocs a buff, stuffs a pointer to the buff
+ into it's 2nd argment for 'B' */
+
+ if (wpcomputer) {
+ ee->data_record.computer_name = (smb_ucs2_t *)TALLOC_MEMDUP(
+ ee, wpcomputer, ee->data_record.computer_name_len);
+ if (!ee->data_record.computer_name) {
+ TALLOC_FREE(ee);
+ goto out;
+ }
+ }
+ if (wpsource) {
+ ee->data_record.source_name = (smb_ucs2_t *)TALLOC_MEMDUP(
+ ee, wpsource, ee->data_record.source_name_len);
+ if (!ee->data_record.source_name) {
+ TALLOC_FREE(ee);
+ goto out;
+ }
+ }
+
+ if (wpsid) {
+ ee->data_record.sid = (smb_ucs2_t *)TALLOC_MEMDUP(
+ ee, wpsid, ee->record.user_sid_length);
+ if (!ee->data_record.sid) {
+ TALLOC_FREE(ee);
+ goto out;
+ }
+ }
+ if (wpstrs) {
+ ee->data_record.strings = (smb_ucs2_t *)TALLOC_MEMDUP(
+ ee, wpstrs, ee->data_record.strings_len);
+ if (!ee->data_record.strings) {
+ TALLOC_FREE(ee);
+ goto out;
+ }
+ }
+
+ if (puserdata) {
+ ee->data_record.user_data = (char *)TALLOC_MEMDUP(
+ ee, puserdata, ee->data_record.user_data_len);
+ if (!ee->data_record.user_data) {
+ TALLOC_FREE(ee);
+ goto out;
+ }
+ }
+
+ out:
+
+ SAFE_FREE(wpcomputer);
+ SAFE_FREE(wpsource);
+ SAFE_FREE(wpsid);
+ SAFE_FREE(wpstrs);
+ SAFE_FREE(puserdata);
+
+ DEBUG( 10, ( "get_eventlog_record: read back %d\n", len ) );
+ DEBUG( 10,
+ ( "get_eventlog_record: computer_name %d is ",
+ ee->data_record.computer_name_len ) );
+ SAFE_FREE(ret.dptr);
+ return ee;
+}
+
+/********************************************************************
+ note that this can only be called AFTER the table is constructed,
+ since it uses the table to find the tdb handle
+ ********************************************************************/
+
+static bool sync_eventlog_params( EVENTLOG_INFO *info )
+{
+ char *path = NULL;
+ uint32 uiMaxSize;
+ uint32 uiRetention;
+ struct registry_key *key;
+ struct registry_value *value;
+ WERROR wresult;
+ char *elogname = info->logname;
+ TALLOC_CTX *ctx = talloc_tos();
+ bool ret = false;
+
+ DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) );
+
+ if ( !info->etdb ) {
+ DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) );
+ return False;
+ }
+ /* set resonable defaults. 512Kb on size and 1 week on time */
+
+ uiMaxSize = 0x80000;
+ uiRetention = 604800;
+
+ /* the general idea is to internally open the registry
+ key and retrieve the values. That way we can continue
+ to use the same fetch/store api that we use in
+ srv_reg_nt.c */
+
+ path = talloc_asprintf(ctx, "%s/%s", KEY_EVENTLOG, elogname );
+ if (!path) {
+ return false;
+ }
+
+ wresult = reg_open_path(ctx, path, REG_KEY_READ, get_root_nt_token(),
+ &key);
+
+ if ( !W_ERROR_IS_OK( wresult ) ) {
+ DEBUG( 4,
+ ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
+ path, dos_errstr( wresult ) ) );
+ return false;
+ }
+
+ wresult = reg_queryvalue(key, key, "Retention", &value);
+ if (!W_ERROR_IS_OK(wresult)) {
+ DEBUG(4, ("Failed to query value \"Retention\": %s\n",
+ dos_errstr(wresult)));
+ ret = false;
+ goto done;
+ }
+ uiRetention = value->v.dword;
+
+ wresult = reg_queryvalue(key, key, "MaxSize", &value);
+ if (!W_ERROR_IS_OK(wresult)) {
+ DEBUG(4, ("Failed to query value \"MaxSize\": %s\n",
+ dos_errstr(wresult)));
+ ret = false;
+ goto done;
+ }
+ uiMaxSize = value->v.dword;
+
+ tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
+ tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
+
+ ret = true;
+
+done:
+ TALLOC_FREE(ctx);
+ return ret;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static Eventlog_entry *read_package_entry( prs_struct * ps,
+ Eventlog_entry * entry )
+{
+ uint8 *offset;
+ Eventlog_entry *ee_new = NULL;
+
+ ee_new = PRS_ALLOC_MEM( ps, Eventlog_entry, 1 );
+ if ( ee_new == NULL ) {
+ return NULL;
+ }
+
+ entry->data_record.sid_padding =
+ ( ( 4 -
+ ( ( entry->data_record.source_name_len +
+ entry->data_record.computer_name_len ) % 4 ) ) % 4 );
+ entry->data_record.data_padding =
+ ( 4 -
+ ( ( entry->data_record.strings_len +
+ entry->data_record.user_data_len ) % 4 ) ) % 4;
+ entry->record.length = sizeof( Eventlog_record );
+ entry->record.length += entry->data_record.source_name_len;
+ entry->record.length += entry->data_record.computer_name_len;
+ if ( entry->record.user_sid_length == 0 ) {
+ /* Should not pad to a DWORD boundary for writing out the sid if there is
+ no SID, so just propagate the padding to pad the data */
+ entry->data_record.data_padding +=
+ entry->data_record.sid_padding;
+ entry->data_record.sid_padding = 0;
+ }
+ DEBUG( 10,
+ ( "sid_padding is [%d].\n", entry->data_record.sid_padding ) );
+ DEBUG( 10,
+ ( "data_padding is [%d].\n",
+ entry->data_record.data_padding ) );
+
+ entry->record.length += entry->data_record.sid_padding;
+ entry->record.length += entry->record.user_sid_length;
+ entry->record.length += entry->data_record.strings_len;
+ entry->record.length += entry->data_record.user_data_len;
+ entry->record.length += entry->data_record.data_padding;
+ /* need another copy of length at the end of the data */
+ entry->record.length += sizeof( entry->record.length );
+ DEBUG( 10,
+ ( "entry->record.length is [%d].\n", entry->record.length ) );
+ entry->data =
+ PRS_ALLOC_MEM( ps, uint8,
+ entry->record.length -
+ sizeof( Eventlog_record ) -
+ sizeof( entry->record.length ) );
+ if ( entry->data == NULL ) {
+ return NULL;
+ }
+ offset = entry->data;
+ memcpy( offset, &( entry->data_record.source_name ),
+ entry->data_record.source_name_len );
+ offset += entry->data_record.source_name_len;
+ memcpy( offset, &( entry->data_record.computer_name ),
+ entry->data_record.computer_name_len );
+ offset += entry->data_record.computer_name_len;
+ /* SID needs to be DWORD-aligned */
+ offset += entry->data_record.sid_padding;
+ entry->record.user_sid_offset =
+ sizeof( Eventlog_record ) + ( offset - entry->data );
+ memcpy( offset, &( entry->data_record.sid ),
+ entry->record.user_sid_length );
+ offset += entry->record.user_sid_length;
+ /* Now do the strings */
+ entry->record.string_offset =
+ sizeof( Eventlog_record ) + ( offset - entry->data );
+ memcpy( offset, &( entry->data_record.strings ),
+ entry->data_record.strings_len );
+ offset += entry->data_record.strings_len;
+ /* Now do the data */
+ entry->record.data_length = entry->data_record.user_data_len;
+ entry->record.data_offset =
+ sizeof( Eventlog_record ) + ( offset - entry->data );
+ memcpy( offset, &( entry->data_record.user_data ),
+ entry->data_record.user_data_len );
+ offset += entry->data_record.user_data_len;
+
+ memcpy( &( ee_new->record ), &entry->record,
+ sizeof( Eventlog_record ) );
+ memcpy( &( ee_new->data_record ), &entry->data_record,
+ sizeof( Eventlog_data_record ) );
+ ee_new->data = entry->data;
+
+ return ee_new;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static bool add_record_to_resp( EVENTLOG_R_READ_EVENTLOG * r_u,
+ Eventlog_entry * ee_new )
+{
+ Eventlog_entry *insert_point;
+
+ insert_point = r_u->entry;
+
+ if ( NULL == insert_point ) {
+ r_u->entry = ee_new;
+ ee_new->next = NULL;
+ } else {
+ while ( ( NULL != insert_point->next ) ) {
+ insert_point = insert_point->next;
+ }
+ ee_new->next = NULL;
+ insert_point->next = ee_new;
+ }
+ r_u->num_records++;
+ r_u->num_bytes_in_resp += ee_new->record.length;
+
+ return True;
+}
+
+/********************************************************************
+ _eventlog_OpenEventLogW
+ ********************************************************************/
+
+NTSTATUS _eventlog_OpenEventLogW(pipes_struct *p,
+ struct eventlog_OpenEventLogW *r)
+{
+ const char *servername = "";
+ const char *logname = "";
+ EVENTLOG_INFO *info;
+ NTSTATUS result;
+
+ if (r->in.servername->string) {
+ servername = r->in.servername->string;
+ }
+
+ if (r->in.logname->string) {
+ logname = r->in.logname->string;
+ }
+
+ DEBUG( 10,("_eventlog_open_eventlog: Server [%s], Log [%s]\n",
+ servername, logname ));
+
+ /* according to MSDN, if the logfile cannot be found, we should
+ default to the "Application" log */
+
+ if ( !NT_STATUS_IS_OK( result = elog_open( p, logname, r->out.handle )) )
+ return result;
+
+ if ( !(info = find_eventlog_info_by_hnd( p, r->out.handle )) ) {
+ DEBUG(0,("_eventlog_open_eventlog: eventlog (%s) opened but unable to find handle!\n",
+ logname ));
+ elog_close( p, r->out.handle );
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info )));
+
+ sync_eventlog_params( info );
+ prune_eventlog( ELOG_TDB_CTX(info->etdb) );
+
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+ _eventlog_ClearEventLogW
+ This call still needs some work
+ ********************************************************************/
+/** The windows client seems to be doing something funny with the file name
+ A call like
+ ClearEventLog(handle, "backup_file")
+ on the client side will result in the backup file name looking like this on the
+ server side:
+ \??\${CWD of client}\backup_file
+ If an absolute path gets specified, such as
+ ClearEventLog(handle, "C:\\temp\\backup_file")
+ then it is still mangled by the client into this:
+ \??\C:\temp\backup_file
+ when it is on the wire.
+ I'm not sure where the \?? is coming from, or why the ${CWD} of the client process
+ would be added in given that the backup file gets written on the server side. */
+
+NTSTATUS _eventlog_ClearEventLogW(pipes_struct *p,
+ struct eventlog_ClearEventLogW *r)
+{
+ EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
+ const char *backup_file_name = NULL;
+
+ if ( !info )
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (r->in.backupfile && r->in.backupfile->string) {
+
+ backup_file_name = r->in.backupfile->string;
+
+ DEBUG(8,( "_eventlog_clear_eventlog: Using [%s] as the backup "
+ "file name for log [%s].",
+ backup_file_name, info->logname ) );
+ }
+
+ /* check for WRITE access to the file */
+
+ if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) )
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* Force a close and reopen */
+
+ elog_close_tdb( info->etdb, True );
+ become_root();
+ info->etdb = elog_open_tdb( info->logname, True );
+ unbecome_root();
+
+ if ( !info->etdb )
+ return NT_STATUS_ACCESS_DENIED;
+
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+NTSTATUS _eventlog_CloseEventLog( pipes_struct * p, struct eventlog_CloseEventLog *r )
+{
+ return elog_close( p, r->in.handle );
+}
+
+/********************************************************************
+ ********************************************************************/
+
+NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
+ EVENTLOG_Q_READ_EVENTLOG * q_u,
+ EVENTLOG_R_READ_EVENTLOG * r_u )
+{
+ EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
+ Eventlog_entry *entry = NULL, *ee_new = NULL;
+ uint32 num_records_read = 0;
+ prs_struct *ps;
+ int bytes_left, record_number;
+ uint32 elog_read_type, elog_read_dir;
+
+ if (info == NULL) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ info->flags = q_u->flags;
+ ps = &p->out_data.rdata;
+
+ bytes_left = q_u->max_read_size;
+
+ if ( !info->etdb )
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* check for valid flags. Can't use the sequential and seek flags together */
+
+ elog_read_type = q_u->flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
+ elog_read_dir = q_u->flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ);
+
+ if ( elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ)
+ || elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ) )
+ {
+ DEBUG(3,("_eventlog_read_eventlog: Invalid flags [0x%x] for ReadEventLog\n", q_u->flags));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* a sequential read should ignore the offset */
+
+ if ( elog_read_type & EVENTLOG_SEQUENTIAL_READ )
+ record_number = info->current_record;
+ else
+ record_number = q_u->offset;
+
+ while ( bytes_left > 0 ) {
+
+ /* assume that when the record fetch fails, that we are done */
+
+ entry = get_eventlog_record (ps, ELOG_TDB_CTX(info->etdb), record_number);
+ if (!entry) {
+ break;
+ }
+
+ DEBUG( 8, ( "Retrieved record %d\n", record_number ) );
+
+ /* Now see if there is enough room to add */
+
+ if ( !(ee_new = read_package_entry( ps, entry )) )
+ return NT_STATUS_NO_MEMORY;
+
+ if ( r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size ) {
+ r_u->bytes_in_next_record = ee_new->record.length;
+
+ /* response would be too big to fit in client-size buffer */
+
+ bytes_left = 0;
+ break;
+ }
+
+ add_record_to_resp( r_u, ee_new );
+ bytes_left -= ee_new->record.length;
+ TALLOC_FREE(entry);
+ num_records_read = r_u->num_records - num_records_read;
+
+ DEBUG( 10, ( "_eventlog_read_eventlog: read [%d] records for a total "
+ "of [%d] records using [%d] bytes out of a max of [%d].\n",
+ num_records_read, r_u->num_records,
+ r_u->num_bytes_in_resp,
+ q_u->max_read_size ) );
+
+ if ( info->flags & EVENTLOG_FORWARDS_READ )
+ record_number++;
+ else
+ record_number--;
+
+ /* update the eventlog record pointer */
+
+ info->current_record = record_number;
+ }
+
+ /* crazy by WinXP uses NT_STATUS_BUFFER_TOO_SMALL to
+ say when there are no more records */
+
+ return (num_records_read ? NT_STATUS_OK : NT_STATUS_BUFFER_TOO_SMALL);
+}
+
+/********************************************************************
+ _eventlog_GetOldestRecord
+ ********************************************************************/
+
+NTSTATUS _eventlog_GetOldestRecord(pipes_struct *p,
+ struct eventlog_GetOldestRecord *r)
+{
+ EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
+
+ if (info == NULL) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ if ( !( get_oldest_entry_hook( info ) ) )
+ return NT_STATUS_ACCESS_DENIED;
+
+ *r->out.oldest_entry = info->oldest_entry;
+
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+_eventlog_GetNumRecords
+ ********************************************************************/
+
+NTSTATUS _eventlog_GetNumRecords(pipes_struct *p,
+ struct eventlog_GetNumRecords *r)
+{
+ EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
+
+ if (info == NULL) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ if ( !( get_num_records_hook( info ) ) )
+ return NT_STATUS_ACCESS_DENIED;
+
+ *r->out.number = info->num_records;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS _eventlog_BackupEventLogW(pipes_struct *p, struct eventlog_BackupEventLogW *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_DeregisterEventSource(pipes_struct *p, struct eventlog_DeregisterEventSource *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_ChangeNotify(pipes_struct *p, struct eventlog_ChangeNotify *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_RegisterEventSourceW(pipes_struct *p, struct eventlog_RegisterEventSourceW *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_OpenBackupEventLogW(pipes_struct *p, struct eventlog_OpenBackupEventLogW *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_ReadEventLogW(pipes_struct *p, struct eventlog_ReadEventLogW *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_ReportEventW(pipes_struct *p, struct eventlog_ReportEventW *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_ClearEventLogA(pipes_struct *p, struct eventlog_ClearEventLogA *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_BackupEventLogA(pipes_struct *p, struct eventlog_BackupEventLogA *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_OpenEventLogA(pipes_struct *p, struct eventlog_OpenEventLogA *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_RegisterEventSourceA(pipes_struct *p, struct eventlog_RegisterEventSourceA *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_OpenBackupEventLogA(pipes_struct *p, struct eventlog_OpenBackupEventLogA *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_ReadEventLogA(pipes_struct *p, struct eventlog_ReadEventLogA *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_ReportEventA(pipes_struct *p, struct eventlog_ReportEventA *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_RegisterClusterSvc(pipes_struct *p, struct eventlog_RegisterClusterSvc *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_DeregisterClusterSvc(pipes_struct *p, struct eventlog_DeregisterClusterSvc *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_WriteClusterEvents(pipes_struct *p, struct eventlog_WriteClusterEvents *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_GetLogIntormation(pipes_struct *p, struct eventlog_GetLogIntormation *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _eventlog_FlushEventLog(pipes_struct *p, struct eventlog_FlushEventLog *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
diff --git a/source3/rpc_server/srv_initshutdown_nt.c b/source3/rpc_server/srv_initshutdown_nt.c
new file mode 100644
index 0000000000..8b3ef52293
--- /dev/null
+++ b/source3/rpc_server/srv_initshutdown_nt.c
@@ -0,0 +1,77 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997.
+ * Copyright (C) Gerald Carter 2006.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Implementation of registry functions. */
+
+#include "includes.h"
+#include "regfio.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+
+/*******************************************************************
+ ********************************************************************/
+WERROR _initshutdown_Init(pipes_struct *p, struct initshutdown_Init *r)
+{
+ struct winreg_InitiateSystemShutdownEx s;
+
+ s.in.hostname = r->in.hostname;
+ s.in.message = r->in.message;
+ s.in.timeout = r->in.timeout;
+ s.in.force_apps = r->in.force_apps;
+ s.in.do_reboot = r->in.do_reboot;
+ s.in.reason = 0;
+
+ /* thunk down to _winreg_InitiateSystemShutdownEx()
+ (just returns a status) */
+
+ return _winreg_InitiateSystemShutdownEx( p, &s );
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _initshutdown_InitEx(pipes_struct *p, struct initshutdown_InitEx *r)
+{
+ struct winreg_InitiateSystemShutdownEx s;
+ s.in.hostname = r->in.hostname;
+ s.in.message = r->in.message;
+ s.in.timeout = r->in.timeout;
+ s.in.force_apps = r->in.force_apps;
+ s.in.do_reboot = r->in.do_reboot;
+ s.in.reason = r->in.reason;
+
+ return _winreg_InitiateSystemShutdownEx( p, &s);
+}
+
+
+
+
+/*******************************************************************
+ reg_abort_shutdwon
+ ********************************************************************/
+
+WERROR _initshutdown_Abort(pipes_struct *p, struct initshutdown_Abort *r)
+{
+ struct winreg_AbortSystemShutdown s;
+ s.in.server = r->in.server;
+ return _winreg_AbortSystemShutdown( p, &s );
+}
diff --git a/source3/rpc_server/srv_lsa_hnd.c b/source3/rpc_server/srv_lsa_hnd.c
new file mode 100644
index 0000000000..377ed505b4
--- /dev/null
+++ b/source3/rpc_server/srv_lsa_hnd.c
@@ -0,0 +1,271 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Jeremy Allison 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+/* This is the max handles across all instances of a pipe name. */
+#ifndef MAX_OPEN_POLS
+#define MAX_OPEN_POLS 1024
+#endif
+
+/****************************************************************************
+ Hack as handles need to be persisant over lsa pipe closes so long as a samr
+ pipe is open. JRA.
+****************************************************************************/
+
+static bool is_samr_lsa_pipe(const char *pipe_name)
+{
+ return (strstr(pipe_name, "samr") || strstr(pipe_name, "lsa"));
+}
+
+/****************************************************************************
+ Initialise a policy handle list on a pipe. Handle list is shared between all
+ pipes of the same name.
+****************************************************************************/
+
+bool init_pipe_handle_list(pipes_struct *p, const char *pipe_name)
+{
+ pipes_struct *plist = get_first_internal_pipe();
+ struct handle_list *hl = NULL;
+
+ for (plist = get_first_internal_pipe(); plist; plist = get_next_internal_pipe(plist)) {
+ if (strequal( plist->name, pipe_name) ||
+ (is_samr_lsa_pipe(plist->name) && is_samr_lsa_pipe(pipe_name))) {
+ if (!plist->pipe_handles) {
+ char *msg;
+ asprintf(&msg, "init_pipe_handles: NULL "
+ "pipe_handle pointer in pipe %s",
+ pipe_name);
+ smb_panic(msg);
+ }
+ hl = plist->pipe_handles;
+ break;
+ }
+ }
+
+ if (!hl) {
+ /*
+ * No handle list for this pipe (first open of pipe).
+ * Create list.
+ */
+
+ if ((hl = SMB_MALLOC_P(struct handle_list)) == NULL)
+ return False;
+ ZERO_STRUCTP(hl);
+
+ DEBUG(10,("init_pipe_handles: created handle list for pipe %s\n", pipe_name ));
+ }
+
+ /*
+ * One more pipe is using this list.
+ */
+
+ hl->pipe_ref_count++;
+
+ /*
+ * Point this pipe at this list.
+ */
+
+ p->pipe_handles = hl;
+
+ DEBUG(10,("init_pipe_handles: pipe_handles ref count = %lu for pipe %s\n",
+ (unsigned long)p->pipe_handles->pipe_ref_count, pipe_name ));
+
+ return True;
+}
+
+/****************************************************************************
+ find first available policy slot. creates a policy handle for you.
+****************************************************************************/
+
+bool create_policy_hnd(pipes_struct *p, POLICY_HND *hnd, void (*free_fn)(void *), void *data_ptr)
+{
+ static uint32 pol_hnd_low = 0;
+ static uint32 pol_hnd_high = 0;
+ time_t t = time(NULL);
+
+ struct policy *pol;
+
+ if (p->pipe_handles->count > MAX_OPEN_POLS) {
+ DEBUG(0,("create_policy_hnd: ERROR: too many handles (%d) on this pipe.\n",
+ (int)p->pipe_handles->count));
+ return False;
+ }
+
+ pol = SMB_MALLOC_P(struct policy);
+ if (!pol) {
+ DEBUG(0,("create_policy_hnd: ERROR: out of memory!\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(pol);
+
+ pol->data_ptr = data_ptr;
+ pol->free_fn = free_fn;
+
+ pol_hnd_low++;
+ if (pol_hnd_low == 0)
+ (pol_hnd_high)++;
+
+ SIVAL(&pol->pol_hnd.handle_type, 0 , 0); /* first bit must be null */
+ SIVAL(&pol->pol_hnd.uuid.time_low, 0 , pol_hnd_low ); /* second bit is incrementing */
+ SSVAL(&pol->pol_hnd.uuid.time_mid, 0 , pol_hnd_high); /* second bit is incrementing */
+ SSVAL(&pol->pol_hnd.uuid.time_hi_and_version, 0 , (pol_hnd_high>>16)); /* second bit is incrementing */
+
+ /* split the current time into two 16 bit values */
+
+ SSVAL(pol->pol_hnd.uuid.clock_seq, 0, (t>>16)); /* something random */
+ SSVAL(pol->pol_hnd.uuid.node, 0, t); /* something random */
+
+ SIVAL(pol->pol_hnd.uuid.node, 2, sys_getpid()); /* something more random */
+
+ DLIST_ADD(p->pipe_handles->Policy, pol);
+ p->pipe_handles->count++;
+
+ *hnd = pol->pol_hnd;
+
+ DEBUG(4,("Opened policy hnd[%d] ", (int)p->pipe_handles->count));
+ dump_data(4, (uint8 *)hnd, sizeof(*hnd));
+
+ return True;
+}
+
+/****************************************************************************
+ find policy by handle - internal version.
+****************************************************************************/
+
+static struct policy *find_policy_by_hnd_internal(pipes_struct *p, POLICY_HND *hnd, void **data_p)
+{
+ struct policy *pol;
+ size_t i;
+
+ if (data_p)
+ *data_p = NULL;
+
+ for (i = 0, pol=p->pipe_handles->Policy;pol;pol=pol->next, i++) {
+ if (memcmp(&pol->pol_hnd, hnd, sizeof(*hnd)) == 0) {
+ DEBUG(4,("Found policy hnd[%d] ", (int)i));
+ dump_data(4, (uint8 *)hnd, sizeof(*hnd));
+ if (data_p)
+ *data_p = pol->data_ptr;
+ return pol;
+ }
+ }
+
+ DEBUG(4,("Policy not found: "));
+ dump_data(4, (uint8 *)hnd, sizeof(*hnd));
+
+ p->bad_handle_fault_state = True;
+
+ return NULL;
+}
+
+/****************************************************************************
+ find policy by handle
+****************************************************************************/
+
+bool find_policy_by_hnd(pipes_struct *p, POLICY_HND *hnd, void **data_p)
+{
+ return find_policy_by_hnd_internal(p, hnd, data_p) == NULL ? False : True;
+}
+
+/****************************************************************************
+ Close a policy.
+****************************************************************************/
+
+bool close_policy_hnd(pipes_struct *p, POLICY_HND *hnd)
+{
+ struct policy *pol = find_policy_by_hnd_internal(p, hnd, NULL);
+
+ if (!pol) {
+ DEBUG(3,("Error closing policy\n"));
+ return False;
+ }
+
+ DEBUG(3,("Closed policy\n"));
+
+ if (pol->free_fn && pol->data_ptr)
+ (*pol->free_fn)(pol->data_ptr);
+
+ p->pipe_handles->count--;
+
+ DLIST_REMOVE(p->pipe_handles->Policy, pol);
+
+ ZERO_STRUCTP(pol);
+
+ SAFE_FREE(pol);
+
+ return True;
+}
+
+/****************************************************************************
+ Close a pipe - free the handle list if it was the last pipe reference.
+****************************************************************************/
+
+void close_policy_by_pipe(pipes_struct *p)
+{
+ p->pipe_handles->pipe_ref_count--;
+
+ if (p->pipe_handles->pipe_ref_count == 0) {
+ /*
+ * Last pipe open on this list - free the list.
+ */
+ while (p->pipe_handles->Policy)
+ close_policy_hnd(p, &p->pipe_handles->Policy->pol_hnd);
+
+ p->pipe_handles->Policy = NULL;
+ p->pipe_handles->count = 0;
+
+ SAFE_FREE(p->pipe_handles);
+ DEBUG(10,("close_policy_by_pipe: deleted handle list for pipe %s\n", p->name ));
+ }
+}
+
+/*******************************************************************
+Shall we allow access to this rpc? Currently this function
+implements the 'restrict anonymous' setting by denying access to
+anonymous users if the restrict anonymous level is > 0. Further work
+will be checking a security descriptor to determine whether a user
+token has enough access to access the pipe.
+********************************************************************/
+
+bool pipe_access_check(pipes_struct *p)
+{
+ /* Don't let anonymous users access this RPC if restrict
+ anonymous > 0 */
+
+ if (lp_restrict_anonymous() > 0) {
+
+ /* schannel, so we must be ok */
+ if (p->pipe_bound && (p->auth.auth_type == PIPE_AUTH_TYPE_SCHANNEL)) {
+ return True;
+ }
+
+ if (p->server_info->guest) {
+ return False;
+ }
+ }
+
+ return True;
+}
diff --git a/source3/rpc_server/srv_lsa_nt.c b/source3/rpc_server/srv_lsa_nt.c
new file mode 100644
index 0000000000..94517f3478
--- /dev/null
+++ b/source3/rpc_server/srv_lsa_nt.c
@@ -0,0 +1,2426 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997,
+ * Copyright (C) Jeremy Allison 2001, 2006.
+ * Copyright (C) Rafal Szczesniak 2002,
+ * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002,
+ * Copyright (C) Simo Sorce 2003.
+ * Copyright (C) Gerald (Jerry) Carter 2005.
+ * Copyright (C) Volker Lendecke 2005.
+ * Copyright (C) Guenther Deschner 2008.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This is the implementation of the lsa server code. */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+extern PRIVS privs[];
+
+struct lsa_info {
+ DOM_SID sid;
+ uint32 access;
+};
+
+const struct generic_mapping lsa_generic_mapping = {
+ LSA_POLICY_READ,
+ LSA_POLICY_WRITE,
+ LSA_POLICY_EXECUTE,
+ LSA_POLICY_ALL_ACCESS
+};
+
+/***************************************************************************
+ init_lsa_ref_domain_list - adds a domain if it's not already in, returns the index.
+***************************************************************************/
+
+static int init_lsa_ref_domain_list(TALLOC_CTX *mem_ctx,
+ struct lsa_RefDomainList *ref,
+ const char *dom_name,
+ DOM_SID *dom_sid)
+{
+ int num = 0;
+
+ if (dom_name != NULL) {
+ for (num = 0; num < ref->count; num++) {
+ if (sid_equal(dom_sid, ref->domains[num].sid)) {
+ return num;
+ }
+ }
+ } else {
+ num = ref->count;
+ }
+
+ if (num >= MAX_REF_DOMAINS) {
+ /* index not found, already at maximum domain limit */
+ return -1;
+ }
+
+ ref->count = num + 1;
+ ref->max_size = MAX_REF_DOMAINS;
+
+ ref->domains = TALLOC_REALLOC_ARRAY(mem_ctx, ref->domains,
+ struct lsa_DomainInfo, ref->count);
+ if (!ref->domains) {
+ return -1;
+ }
+
+ ZERO_STRUCT(ref->domains[num]);
+
+ init_lsa_StringLarge(&ref->domains[num].name, dom_name);
+ ref->domains[num].sid = sid_dup_talloc(mem_ctx, dom_sid);
+ if (!ref->domains[num].sid) {
+ return -1;
+ }
+
+ return num;
+}
+
+
+/*******************************************************************
+ Function to free the per handle data.
+ ********************************************************************/
+
+static void free_lsa_info(void *ptr)
+{
+ struct lsa_info *lsa = (struct lsa_info *)ptr;
+
+ SAFE_FREE(lsa);
+}
+
+/***************************************************************************
+ initialize a lsa_DomainInfo structure.
+ ***************************************************************************/
+
+static void init_dom_query_3(struct lsa_DomainInfo *r,
+ const char *name,
+ DOM_SID *sid)
+{
+ init_lsa_StringLarge(&r->name, name);
+ r->sid = sid;
+}
+
+/***************************************************************************
+ initialize a lsa_DomainInfo structure.
+ ***************************************************************************/
+
+static void init_dom_query_5(struct lsa_DomainInfo *r,
+ const char *name,
+ DOM_SID *sid)
+{
+ init_lsa_StringLarge(&r->name, name);
+ r->sid = sid;
+}
+
+/***************************************************************************
+ lookup_lsa_rids. Must be called as root for lookup_name to work.
+ ***************************************************************************/
+
+static NTSTATUS lookup_lsa_rids(TALLOC_CTX *mem_ctx,
+ struct lsa_RefDomainList *ref,
+ struct lsa_TranslatedSid *prid,
+ uint32_t num_entries,
+ struct lsa_String *name,
+ int flags,
+ uint32_t *pmapped_count)
+{
+ uint32 mapped_count, i;
+
+ SMB_ASSERT(num_entries <= MAX_LOOKUP_SIDS);
+
+ mapped_count = 0;
+ *pmapped_count = 0;
+
+ for (i = 0; i < num_entries; i++) {
+ DOM_SID sid;
+ uint32 rid;
+ int dom_idx;
+ const char *full_name;
+ const char *domain;
+ enum lsa_SidType type = SID_NAME_UNKNOWN;
+
+ /* Split name into domain and user component */
+
+ full_name = name[i].string;
+ if (full_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(5, ("lookup_lsa_rids: looking up name %s\n", full_name));
+
+ /* We can ignore the result of lookup_name, it will not touch
+ "type" if it's not successful */
+
+ lookup_name(mem_ctx, full_name, flags, &domain, NULL,
+ &sid, &type);
+
+ switch (type) {
+ case SID_NAME_USER:
+ case SID_NAME_DOM_GRP:
+ case SID_NAME_DOMAIN:
+ case SID_NAME_ALIAS:
+ case SID_NAME_WKN_GRP:
+ DEBUG(5, ("init_lsa_rids: %s found\n", full_name));
+ /* Leave these unchanged */
+ break;
+ default:
+ /* Don't hand out anything but the list above */
+ DEBUG(5, ("init_lsa_rids: %s not found\n", full_name));
+ type = SID_NAME_UNKNOWN;
+ break;
+ }
+
+ rid = 0;
+ dom_idx = -1;
+
+ if (type != SID_NAME_UNKNOWN) {
+ sid_split_rid(&sid, &rid);
+ dom_idx = init_lsa_ref_domain_list(mem_ctx, ref, domain, &sid);
+ mapped_count++;
+ }
+
+ init_lsa_translated_sid(&prid[i], type, rid, dom_idx);
+ }
+
+ *pmapped_count = mapped_count;
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ lookup_lsa_sids. Must be called as root for lookup_name to work.
+ ***************************************************************************/
+
+static NTSTATUS lookup_lsa_sids(TALLOC_CTX *mem_ctx,
+ struct lsa_RefDomainList *ref,
+ struct lsa_TranslatedSid3 *trans_sids,
+ uint32_t num_entries,
+ struct lsa_String *name,
+ int flags,
+ uint32 *pmapped_count)
+{
+ uint32 mapped_count, i;
+
+ SMB_ASSERT(num_entries <= MAX_LOOKUP_SIDS);
+
+ mapped_count = 0;
+ *pmapped_count = 0;
+
+ for (i = 0; i < num_entries; i++) {
+ DOM_SID sid;
+ uint32 rid;
+ int dom_idx;
+ const char *full_name;
+ const char *domain;
+ enum lsa_SidType type = SID_NAME_UNKNOWN;
+
+ ZERO_STRUCT(sid);
+
+ /* Split name into domain and user component */
+
+ full_name = name[i].string;
+ if (full_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(5, ("init_lsa_sids: looking up name %s\n", full_name));
+
+ /* We can ignore the result of lookup_name, it will not touch
+ "type" if it's not successful */
+
+ lookup_name(mem_ctx, full_name, flags, &domain, NULL,
+ &sid, &type);
+
+ switch (type) {
+ case SID_NAME_USER:
+ case SID_NAME_DOM_GRP:
+ case SID_NAME_DOMAIN:
+ case SID_NAME_ALIAS:
+ case SID_NAME_WKN_GRP:
+ DEBUG(5, ("init_lsa_sids: %s found\n", full_name));
+ /* Leave these unchanged */
+ break;
+ default:
+ /* Don't hand out anything but the list above */
+ DEBUG(5, ("init_lsa_sids: %s not found\n", full_name));
+ type = SID_NAME_UNKNOWN;
+ break;
+ }
+
+ rid = 0;
+ dom_idx = -1;
+
+ if (type != SID_NAME_UNKNOWN) {
+ DOM_SID domain_sid;
+ sid_copy(&domain_sid, &sid);
+ sid_split_rid(&domain_sid, &rid);
+ dom_idx = init_lsa_ref_domain_list(mem_ctx, ref, domain, &domain_sid);
+ mapped_count++;
+ }
+
+ /* Initialize the lsa_TranslatedSid3 return. */
+ trans_sids[i].sid_type = type;
+ trans_sids[i].sid = sid_dup_talloc(mem_ctx, &sid);
+ trans_sids[i].sid_index = dom_idx;
+ }
+
+ *pmapped_count = mapped_count;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS lsa_get_generic_sd(TALLOC_CTX *mem_ctx, SEC_DESC **sd, size_t *sd_size)
+{
+ DOM_SID local_adm_sid;
+ DOM_SID adm_sid;
+
+ SEC_ACE ace[3];
+ SEC_ACCESS mask;
+
+ SEC_ACL *psa = NULL;
+
+ init_sec_access(&mask, LSA_POLICY_EXECUTE);
+ init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ sid_copy(&adm_sid, get_global_sam_sid());
+ sid_append_rid(&adm_sid, DOMAIN_GROUP_RID_ADMINS);
+ init_sec_access(&mask, LSA_POLICY_ALL_ACCESS);
+ init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ sid_copy(&local_adm_sid, &global_sid_Builtin);
+ sid_append_rid(&local_adm_sid, BUILTIN_ALIAS_RID_ADMINS);
+ init_sec_access(&mask, LSA_POLICY_ALL_ACCESS);
+ init_sec_ace(&ace[2], &local_adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ if((psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, 3, ace)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if((*sd = make_sec_desc(mem_ctx, SECURITY_DESCRIPTOR_REVISION_1,
+ SEC_DESC_SELF_RELATIVE, &adm_sid, NULL, NULL,
+ psa, sd_size)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ return NT_STATUS_OK;
+}
+
+#if 0 /* AD DC work in ongoing in Samba 4 */
+
+/***************************************************************************
+ Init_dns_dom_info.
+***************************************************************************/
+
+static void init_dns_dom_info(LSA_DNS_DOM_INFO *r_l, const char *nb_name,
+ const char *dns_name, const char *forest_name,
+ struct GUID *dom_guid, DOM_SID *dom_sid)
+{
+ if (nb_name && *nb_name) {
+ init_unistr2(&r_l->uni_nb_dom_name, nb_name, UNI_FLAGS_NONE);
+ init_uni_hdr(&r_l->hdr_nb_dom_name, &r_l->uni_nb_dom_name);
+ r_l->hdr_nb_dom_name.uni_max_len += 2;
+ r_l->uni_nb_dom_name.uni_max_len += 1;
+ }
+
+ if (dns_name && *dns_name) {
+ init_unistr2(&r_l->uni_dns_dom_name, dns_name, UNI_FLAGS_NONE);
+ init_uni_hdr(&r_l->hdr_dns_dom_name, &r_l->uni_dns_dom_name);
+ r_l->hdr_dns_dom_name.uni_max_len += 2;
+ r_l->uni_dns_dom_name.uni_max_len += 1;
+ }
+
+ if (forest_name && *forest_name) {
+ init_unistr2(&r_l->uni_forest_name, forest_name, UNI_FLAGS_NONE);
+ init_uni_hdr(&r_l->hdr_forest_name, &r_l->uni_forest_name);
+ r_l->hdr_forest_name.uni_max_len += 2;
+ r_l->uni_forest_name.uni_max_len += 1;
+ }
+
+ /* how do we init the guid ? probably should write an init fn */
+ if (dom_guid) {
+ memcpy(&r_l->dom_guid, dom_guid, sizeof(struct GUID));
+ }
+
+ if (dom_sid) {
+ r_l->ptr_dom_sid = 1;
+ init_dom_sid2(&r_l->dom_sid, dom_sid);
+ }
+}
+#endif /* AD DC work in ongoing in Samba 4 */
+
+
+/***************************************************************************
+ _lsa_OpenPolicy2
+ ***************************************************************************/
+
+NTSTATUS _lsa_OpenPolicy2(pipes_struct *p,
+ struct lsa_OpenPolicy2 *r)
+{
+ struct lsa_info *info;
+ SEC_DESC *psd = NULL;
+ size_t sd_size;
+ uint32 des_access = r->in.access_mask;
+ uint32 acc_granted;
+ NTSTATUS status;
+
+
+ /* map the generic bits to the lsa policy ones */
+ se_map_generic(&des_access, &lsa_generic_mapping);
+
+ /* get the generic lsa policy SD until we store it */
+ lsa_get_generic_sd(p->mem_ctx, &psd, &sd_size);
+
+ if(!se_access_check(psd, p->pipe_user.nt_user_token, des_access, &acc_granted, &status)) {
+ if (p->pipe_user.ut.uid != sec_initial_uid()) {
+ return status;
+ }
+ DEBUG(4,("ACCESS should be DENIED (granted: %#010x; required: %#010x)\n",
+ acc_granted, des_access));
+ DEBUGADD(4,("but overwritten by euid == 0\n"));
+ }
+
+ /* This is needed for lsa_open_account and rpcclient .... :-) */
+
+ if (p->pipe_user.ut.uid == sec_initial_uid())
+ acc_granted = LSA_POLICY_ALL_ACCESS;
+
+ /* associate the domain SID with the (unique) handle. */
+ if ((info = SMB_MALLOC_P(struct lsa_info)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(info);
+ sid_copy(&info->sid,get_global_sam_sid());
+ info->access = acc_granted;
+
+ /* set up the LSA QUERY INFO response */
+ if (!create_policy_hnd(p, r->out.handle, free_lsa_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ _lsa_OpenPolicy
+ ***************************************************************************/
+
+NTSTATUS _lsa_OpenPolicy(pipes_struct *p,
+ struct lsa_OpenPolicy *r)
+{
+ struct lsa_info *info;
+ SEC_DESC *psd = NULL;
+ size_t sd_size;
+ uint32 des_access= r->in.access_mask;
+ uint32 acc_granted;
+ NTSTATUS status;
+
+
+ /* map the generic bits to the lsa policy ones */
+ se_map_generic(&des_access, &lsa_generic_mapping);
+
+ /* get the generic lsa policy SD until we store it */
+ lsa_get_generic_sd(p->mem_ctx, &psd, &sd_size);
+
+ if(!se_access_check(psd, p->pipe_user.nt_user_token, des_access, &acc_granted, &status)) {
+ if (geteuid() != 0) {
+ return status;
+ }
+ DEBUG(4,("ACCESS should be DENIED (granted: %#010x; required: %#010x)\n",
+ acc_granted, des_access));
+ DEBUGADD(4,("but overwritten by euid == 0\n"));
+ acc_granted = des_access;
+ }
+
+ /* associate the domain SID with the (unique) handle. */
+ if ((info = SMB_MALLOC_P(struct lsa_info)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(info);
+ sid_copy(&info->sid,get_global_sam_sid());
+ info->access = acc_granted;
+
+ /* set up the LSA QUERY INFO response */
+ if (!create_policy_hnd(p, r->out.handle, free_lsa_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ _lsa_EnumTrustDom - this needs fixing to do more than return NULL ! JRA.
+ ufff, done :) mimir
+ ***************************************************************************/
+
+NTSTATUS _lsa_EnumTrustDom(pipes_struct *p,
+ struct lsa_EnumTrustDom *r)
+{
+ struct lsa_info *info;
+ uint32 next_idx;
+ struct trustdom_info **domains;
+ struct lsa_DomainInfo *lsa_domains = NULL;
+ int i;
+
+ /*
+ * preferred length is set to 5 as a "our" preferred length
+ * nt sets this parameter to 2
+ * update (20.08.2002): it's not preferred length, but preferred size!
+ * it needs further investigation how to optimally choose this value
+ */
+ uint32 max_num_domains =
+ r->in.max_size < 5 ? r->in.max_size : 10;
+ uint32 num_domains;
+ NTSTATUS nt_status;
+ uint32 num_thistime;
+
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check if the user has enough rights */
+ if (!(info->access & LSA_POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ become_root();
+ nt_status = pdb_enum_trusteddoms(p->mem_ctx, &num_domains, &domains);
+ unbecome_root();
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ if (*r->in.resume_handle < num_domains) {
+ num_thistime = MIN(num_domains, max_num_domains);
+
+ nt_status = STATUS_MORE_ENTRIES;
+
+ if (*r->in.resume_handle + num_thistime > num_domains) {
+ num_thistime = num_domains - *r->in.resume_handle;
+ nt_status = NT_STATUS_OK;
+ }
+
+ next_idx = *r->in.resume_handle + num_thistime;
+ } else {
+ num_thistime = 0;
+ next_idx = 0xffffffff;
+ nt_status = NT_STATUS_NO_MORE_ENTRIES;
+ }
+
+ /* set up the lsa_enum_trust_dom response */
+
+ lsa_domains = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_DomainInfo,
+ num_thistime);
+ if (!lsa_domains) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<num_thistime; i++) {
+ init_lsa_StringLarge(&lsa_domains[i].name, domains[i]->name);
+ lsa_domains[i].sid = &domains[i]->sid;
+ }
+
+ *r->out.resume_handle = next_idx;
+ r->out.domains->count = num_thistime;
+ r->out.domains->domains = lsa_domains;
+
+ return nt_status;
+}
+
+#define LSA_AUDIT_NUM_CATEGORIES_NT4 7
+#define LSA_AUDIT_NUM_CATEGORIES_WIN2K 9
+#define LSA_AUDIT_NUM_CATEGORIES LSA_AUDIT_NUM_CATEGORIES_NT4
+
+/***************************************************************************
+ _lsa_QueryInfoPolicy
+ ***************************************************************************/
+
+NTSTATUS _lsa_QueryInfoPolicy(pipes_struct *p,
+ struct lsa_QueryInfoPolicy *r)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ struct lsa_info *handle;
+ DOM_SID domain_sid;
+ const char *name;
+ DOM_SID *sid = NULL;
+ union lsa_PolicyInformation *info = NULL;
+
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle))
+ return NT_STATUS_INVALID_HANDLE;
+
+ info = TALLOC_ZERO_P(p->mem_ctx, union lsa_PolicyInformation);
+ if (!info) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ switch (r->in.level) {
+ case 0x02:
+ {
+
+ uint32 policy_def = LSA_AUDIT_POLICY_ALL;
+
+ /* check if the user has enough rights */
+ if (!(handle->access & LSA_POLICY_VIEW_AUDIT_INFORMATION)) {
+ DEBUG(10,("_lsa_QueryInfoPolicy: insufficient access rights\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* fake info: We audit everything. ;) */
+
+ info->audit_events.auditing_mode = true;
+ info->audit_events.count = LSA_AUDIT_NUM_CATEGORIES;
+ info->audit_events.settings = TALLOC_ZERO_ARRAY(p->mem_ctx,
+ enum lsa_PolicyAuditPolicy,
+ info->audit_events.count);
+ if (!info->audit_events.settings) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ info->audit_events.settings[LSA_AUDIT_CATEGORY_ACCOUNT_MANAGEMENT] = policy_def;
+ info->audit_events.settings[LSA_AUDIT_CATEGORY_FILE_AND_OBJECT_ACCESS] = policy_def;
+ info->audit_events.settings[LSA_AUDIT_CATEGORY_LOGON] = policy_def;
+ info->audit_events.settings[LSA_AUDIT_CATEGORY_PROCCESS_TRACKING] = policy_def;
+ info->audit_events.settings[LSA_AUDIT_CATEGORY_SECURITY_POLICY_CHANGES] = policy_def;
+ info->audit_events.settings[LSA_AUDIT_CATEGORY_SYSTEM] = policy_def;
+ info->audit_events.settings[LSA_AUDIT_CATEGORY_USE_OF_USER_RIGHTS] = policy_def;
+
+ break;
+ }
+ case 0x03:
+ /* check if the user has enough rights */
+ if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* Request PolicyPrimaryDomainInformation. */
+ switch (lp_server_role()) {
+ case ROLE_DOMAIN_PDC:
+ case ROLE_DOMAIN_BDC:
+ name = get_global_sam_name();
+ sid = sid_dup_talloc(p->mem_ctx, get_global_sam_sid());
+ if (!sid) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ break;
+ case ROLE_DOMAIN_MEMBER:
+ name = lp_workgroup();
+ /* We need to return the Domain SID here. */
+ if (secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
+ sid = sid_dup_talloc(p->mem_ctx, &domain_sid);
+ if (!sid) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+ break;
+ case ROLE_STANDALONE:
+ name = lp_workgroup();
+ sid = NULL;
+ break;
+ default:
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+ init_dom_query_3(&info->domain, name, sid);
+ break;
+ case 0x05:
+ /* check if the user has enough rights */
+ if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* Request PolicyAccountDomainInformation. */
+ name = get_global_sam_name();
+ sid = get_global_sam_sid();
+
+ init_dom_query_5(&info->account_domain, name, sid);
+ break;
+ case 0x06:
+ /* check if the user has enough rights */
+ if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ switch (lp_server_role()) {
+ case ROLE_DOMAIN_BDC:
+ /*
+ * only a BDC is a backup controller
+ * of the domain, it controls.
+ */
+ info->role.role = 2;
+ break;
+ default:
+ /*
+ * any other role is a primary
+ * of the domain, it controls.
+ */
+ info->role.role = 3;
+ break;
+ }
+ break;
+ default:
+ DEBUG(0,("_lsa_QueryInfoPolicy: unknown info level in Lsa Query: %d\n",
+ r->in.level));
+ status = NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
+ *r->out.info = info;
+
+ return status;
+}
+
+/***************************************************************************
+ _lsa_lookup_sids_internal
+ ***************************************************************************/
+
+static NTSTATUS _lsa_lookup_sids_internal(pipes_struct *p,
+ TALLOC_CTX *mem_ctx,
+ uint16_t level, /* input */
+ int num_sids, /* input */
+ struct lsa_SidPtr *sid, /* input */
+ struct lsa_RefDomainList **pp_ref, /* input/output */
+ struct lsa_TranslatedName2 **pp_names,/* input/output */
+ uint32_t *pp_mapped_count) /* input/output */
+{
+ NTSTATUS status;
+ int i;
+ const DOM_SID **sids = NULL;
+ struct lsa_RefDomainList *ref = NULL;
+ uint32 mapped_count = 0;
+ struct lsa_dom_info *dom_infos = NULL;
+ struct lsa_name_info *name_infos = NULL;
+ struct lsa_TranslatedName2 *names = NULL;
+
+ *pp_mapped_count = 0;
+ *pp_names = NULL;
+ *pp_ref = NULL;
+
+ if (num_sids == 0) {
+ return NT_STATUS_OK;
+ }
+
+ sids = TALLOC_ARRAY(p->mem_ctx, const DOM_SID *, num_sids);
+ ref = TALLOC_ZERO_P(p->mem_ctx, struct lsa_RefDomainList);
+
+ if (sids == NULL || ref == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<num_sids; i++) {
+ sids[i] = sid[i].sid;
+ }
+
+ status = lookup_sids(p->mem_ctx, num_sids, sids, level,
+ &dom_infos, &name_infos);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ names = TALLOC_ARRAY(p->mem_ctx, struct lsa_TranslatedName2, num_sids);
+ if (names == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<MAX_REF_DOMAINS; i++) {
+
+ if (!dom_infos[i].valid) {
+ break;
+ }
+
+ if (init_lsa_ref_domain_list(mem_ctx, ref,
+ dom_infos[i].name,
+ &dom_infos[i].sid) != i) {
+ DEBUG(0, ("Domain %s mentioned twice??\n",
+ dom_infos[i].name));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ }
+
+ for (i=0; i<num_sids; i++) {
+ struct lsa_name_info *name = &name_infos[i];
+
+ if (name->type == SID_NAME_UNKNOWN) {
+ fstring tmp;
+ name->dom_idx = -1;
+ /* Unknown sids should return the string
+ * representation of the SID. Windows 2003 behaves
+ * rather erratic here, in many cases it returns the
+ * RID as 8 bytes hex, in others it returns the full
+ * SID. We (Jerry/VL) could not figure out which the
+ * hard cases are, so leave it with the SID. */
+ name->name = talloc_asprintf(p->mem_ctx, "%s",
+ sid_to_fstring(tmp,
+ sids[i]));
+ if (name->name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ mapped_count += 1;
+ }
+
+ init_lsa_translated_name2(&names[i], name->type,
+ name->name, name->dom_idx, 0);
+ }
+
+ status = NT_STATUS_NONE_MAPPED;
+ if (mapped_count > 0) {
+ status = (mapped_count < num_sids) ?
+ STATUS_SOME_UNMAPPED : NT_STATUS_OK;
+ }
+
+ DEBUG(10, ("num_sids %d, mapped_count %d, status %s\n",
+ num_sids, mapped_count, nt_errstr(status)));
+
+ *pp_mapped_count = mapped_count;
+ *pp_names = names;
+ *pp_ref = ref;
+
+ return status;
+}
+
+/***************************************************************************
+ _lsa_LookupSids
+ ***************************************************************************/
+
+NTSTATUS _lsa_LookupSids(pipes_struct *p,
+ struct lsa_LookupSids *r)
+{
+ NTSTATUS status;
+ struct lsa_info *handle;
+ int num_sids = r->in.sids->num_sids;
+ uint32 mapped_count = 0;
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_TranslatedName *names_out = NULL;
+ struct lsa_TranslatedName2 *names = NULL;
+ int i;
+
+ if ((r->in.level < 1) || (r->in.level > 6)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ /* check if the user has enough rights */
+ if (!(handle->access & LSA_POLICY_LOOKUP_NAMES)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (num_sids > MAX_LOOKUP_SIDS) {
+ DEBUG(5,("_lsa_LookupSids: limit of %d exceeded, requested %d\n",
+ MAX_LOOKUP_SIDS, num_sids));
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ status = _lsa_lookup_sids_internal(p,
+ p->mem_ctx,
+ r->in.level,
+ num_sids,
+ r->in.sids->sids,
+ &domains,
+ &names,
+ &mapped_count);
+
+ /* Convert from lsa_TranslatedName2 to lsa_TranslatedName */
+ names_out = TALLOC_ARRAY(p->mem_ctx, struct lsa_TranslatedName,
+ num_sids);
+ if (!names_out) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<num_sids; i++) {
+ names_out[i].sid_type = names[i].sid_type;
+ names_out[i].name = names[i].name;
+ names_out[i].sid_index = names[i].sid_index;
+ }
+
+ *r->out.domains = domains;
+ r->out.names->count = num_sids;
+ r->out.names->names = names_out;
+ *r->out.count = mapped_count;
+
+ return status;
+}
+
+/***************************************************************************
+ _lsa_LookupSids2
+ ***************************************************************************/
+
+NTSTATUS _lsa_LookupSids2(pipes_struct *p,
+ struct lsa_LookupSids2 *r)
+{
+ NTSTATUS status;
+ struct lsa_info *handle;
+ int num_sids = r->in.sids->num_sids;
+ uint32 mapped_count = 0;
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_TranslatedName2 *names = NULL;
+ bool check_policy = true;
+
+ switch (p->hdr_req.opnum) {
+ case NDR_LSA_LOOKUPSIDS3:
+ check_policy = false;
+ break;
+ case NDR_LSA_LOOKUPSIDS2:
+ default:
+ check_policy = true;
+ }
+
+ if ((r->in.level < 1) || (r->in.level > 6)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (check_policy) {
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ /* check if the user has enough rights */
+ if (!(handle->access & LSA_POLICY_LOOKUP_NAMES)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ if (num_sids > MAX_LOOKUP_SIDS) {
+ DEBUG(5,("_lsa_LookupSids2: limit of %d exceeded, requested %d\n",
+ MAX_LOOKUP_SIDS, num_sids));
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ status = _lsa_lookup_sids_internal(p,
+ p->mem_ctx,
+ r->in.level,
+ num_sids,
+ r->in.sids->sids,
+ &domains,
+ &names,
+ &mapped_count);
+
+ *r->out.domains = domains;
+ r->out.names->count = num_sids;
+ r->out.names->names = names;
+ *r->out.count = mapped_count;
+
+ return status;
+}
+
+/***************************************************************************
+ _lsa_LookupSids3
+ ***************************************************************************/
+
+NTSTATUS _lsa_LookupSids3(pipes_struct *p,
+ struct lsa_LookupSids3 *r)
+{
+ struct lsa_LookupSids2 q;
+
+ /* No policy handle on this call. Restrict to crypto connections. */
+ if (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) {
+ DEBUG(0,("_lsa_LookupSids3: client %s not using schannel for netlogon\n",
+ get_remote_machine_name() ));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ q.in.handle = NULL;
+ q.in.sids = r->in.sids;
+ q.in.level = r->in.level;
+ q.in.unknown1 = r->in.unknown1;
+ q.in.unknown2 = r->in.unknown2;
+ q.in.names = r->in.names;
+ q.in.count = r->in.count;
+
+ q.out.domains = r->out.domains;
+ q.out.names = r->out.names;
+ q.out.count = r->out.count;
+
+ return _lsa_LookupSids2(p, &q);
+}
+
+/***************************************************************************
+ ***************************************************************************/
+
+static int lsa_lookup_level_to_flags(uint16 level)
+{
+ int flags;
+
+ switch (level) {
+ case 1:
+ flags = LOOKUP_NAME_ALL;
+ break;
+ case 2:
+ flags = LOOKUP_NAME_DOMAIN|LOOKUP_NAME_REMOTE|LOOKUP_NAME_ISOLATED;
+ break;
+ case 3:
+ flags = LOOKUP_NAME_DOMAIN|LOOKUP_NAME_ISOLATED;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ default:
+ flags = LOOKUP_NAME_NONE;
+ break;
+ }
+
+ return flags;
+}
+
+/***************************************************************************
+ _lsa_LookupNames
+ ***************************************************************************/
+
+NTSTATUS _lsa_LookupNames(pipes_struct *p,
+ struct lsa_LookupNames *r)
+{
+ NTSTATUS status = NT_STATUS_NONE_MAPPED;
+ struct lsa_info *handle;
+ struct lsa_String *names = r->in.names;
+ uint32 num_entries = r->in.num_names;
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_TranslatedSid *rids = NULL;
+ uint32 mapped_count = 0;
+ int flags = 0;
+
+ if (num_entries > MAX_LOOKUP_SIDS) {
+ num_entries = MAX_LOOKUP_SIDS;
+ DEBUG(5,("_lsa_LookupNames: truncating name lookup list to %d\n",
+ num_entries));
+ }
+
+ flags = lsa_lookup_level_to_flags(r->in.level);
+
+ domains = TALLOC_ZERO_P(p->mem_ctx, struct lsa_RefDomainList);
+ if (!domains) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (num_entries) {
+ rids = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_TranslatedSid,
+ num_entries);
+ if (!rids) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ rids = NULL;
+ }
+
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) {
+ status = NT_STATUS_INVALID_HANDLE;
+ goto done;
+ }
+
+ /* check if the user has enough rights */
+ if (!(handle->access & LSA_POLICY_LOOKUP_NAMES)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+
+ /* set up the LSA Lookup RIDs response */
+ become_root(); /* lookup_name can require root privs */
+ status = lookup_lsa_rids(p->mem_ctx, domains, rids, num_entries,
+ names, flags, &mapped_count);
+ unbecome_root();
+
+done:
+
+ if (NT_STATUS_IS_OK(status) && (num_entries != 0) ) {
+ if (mapped_count == 0) {
+ status = NT_STATUS_NONE_MAPPED;
+ } else if (mapped_count != num_entries) {
+ status = STATUS_SOME_UNMAPPED;
+ }
+ }
+
+ *r->out.count = mapped_count;
+ *r->out.domains = domains;
+ r->out.sids->sids = rids;
+ r->out.sids->count = num_entries;
+
+ return status;
+}
+
+/***************************************************************************
+ _lsa_LookupNames2
+ ***************************************************************************/
+
+NTSTATUS _lsa_LookupNames2(pipes_struct *p,
+ struct lsa_LookupNames2 *r)
+{
+ NTSTATUS status;
+ struct lsa_LookupNames q;
+ struct lsa_TransSidArray2 *sid_array2 = r->in.sids;
+ struct lsa_TransSidArray *sid_array = NULL;
+ uint32_t i;
+
+ sid_array = TALLOC_ZERO_P(p->mem_ctx, struct lsa_TransSidArray);
+ if (!sid_array) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ q.in.handle = r->in.handle;
+ q.in.num_names = r->in.num_names;
+ q.in.names = r->in.names;
+ q.in.level = r->in.level;
+ q.in.sids = sid_array;
+ q.in.count = r->in.count;
+ /* we do not know what this is for */
+ /* = r->in.unknown1; */
+ /* = r->in.unknown2; */
+
+ q.out.domains = r->out.domains;
+ q.out.sids = sid_array;
+ q.out.count = r->out.count;
+
+ status = _lsa_LookupNames(p, &q);
+
+ sid_array2->sids = TALLOC_ARRAY(p->mem_ctx, struct lsa_TranslatedSid2, sid_array->count);
+ if (!sid_array2->sids) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<sid_array->count; i++) {
+ sid_array2->sids[i].sid_type = sid_array->sids[i].sid_type;
+ sid_array2->sids[i].rid = sid_array->sids[i].rid;
+ sid_array2->sids[i].sid_index = sid_array->sids[i].sid_index;
+ sid_array2->sids[i].unknown = 0;
+ }
+
+ r->out.sids = sid_array2;
+
+ return status;
+}
+
+/***************************************************************************
+ _lsa_LookupNames3
+ ***************************************************************************/
+
+NTSTATUS _lsa_LookupNames3(pipes_struct *p,
+ struct lsa_LookupNames3 *r)
+{
+ NTSTATUS status;
+ struct lsa_info *handle;
+ struct lsa_String *names = r->in.names;
+ uint32 num_entries = r->in.num_names;
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_TranslatedSid3 *trans_sids = NULL;
+ uint32 mapped_count = 0;
+ int flags = 0;
+ bool check_policy = true;
+
+ switch (p->hdr_req.opnum) {
+ case NDR_LSA_LOOKUPNAMES4:
+ check_policy = false;
+ break;
+ case NDR_LSA_LOOKUPNAMES3:
+ default:
+ check_policy = true;
+ }
+
+ if (num_entries > MAX_LOOKUP_SIDS) {
+ num_entries = MAX_LOOKUP_SIDS;
+ DEBUG(5,("_lsa_LookupNames3: truncating name lookup list to %d\n", num_entries));
+ }
+
+ /* Probably the lookup_level is some sort of bitmask. */
+ if (r->in.level == 1) {
+ flags = LOOKUP_NAME_ALL;
+ }
+
+ domains = TALLOC_ZERO_P(p->mem_ctx, struct lsa_RefDomainList);
+ if (!domains) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (num_entries) {
+ trans_sids = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_TranslatedSid3,
+ num_entries);
+ if (!trans_sids) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ trans_sids = NULL;
+ }
+
+ if (check_policy) {
+
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) {
+ status = NT_STATUS_INVALID_HANDLE;
+ goto done;
+ }
+
+ /* check if the user has enough rights */
+ if (!(handle->access & LSA_POLICY_LOOKUP_NAMES)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+ }
+
+ /* set up the LSA Lookup SIDs response */
+ become_root(); /* lookup_name can require root privs */
+ status = lookup_lsa_sids(p->mem_ctx, domains, trans_sids, num_entries,
+ names, flags, &mapped_count);
+ unbecome_root();
+
+done:
+
+ if (NT_STATUS_IS_OK(status)) {
+ if (mapped_count == 0) {
+ status = NT_STATUS_NONE_MAPPED;
+ } else if (mapped_count != num_entries) {
+ status = STATUS_SOME_UNMAPPED;
+ }
+ }
+
+ *r->out.count = mapped_count;
+ *r->out.domains = domains;
+ r->out.sids->sids = trans_sids;
+ r->out.sids->count = num_entries;
+
+ return status;
+}
+
+/***************************************************************************
+ _lsa_LookupNames4
+ ***************************************************************************/
+
+NTSTATUS _lsa_LookupNames4(pipes_struct *p,
+ struct lsa_LookupNames4 *r)
+{
+ struct lsa_LookupNames3 q;
+
+ /* No policy handle on this call. Restrict to crypto connections. */
+ if (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) {
+ DEBUG(0,("_lsa_lookup_names4: client %s not using schannel for netlogon\n",
+ get_remote_machine_name() ));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ q.in.handle = NULL;
+ q.in.num_names = r->in.num_names;
+ q.in.names = r->in.names;
+ q.in.level = r->in.level;
+ q.in.unknown1 = r->in.unknown1;
+ q.in.unknown2 = r->in.unknown2;
+ q.in.sids = r->in.sids;
+ q.in.count = r->in.count;
+
+ q.out.domains = r->out.domains;
+ q.out.sids = r->out.sids;
+ q.out.count = r->out.count;
+
+ return _lsa_LookupNames3(p, &q);
+}
+
+/***************************************************************************
+ _lsa_close. Also weird - needs to check if lsa handle is correct. JRA.
+ ***************************************************************************/
+
+NTSTATUS _lsa_Close(pipes_struct *p, struct lsa_Close *r)
+{
+ if (!find_policy_by_hnd(p, r->in.handle, NULL)) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ close_policy_hnd(p, r->in.handle);
+ ZERO_STRUCTP(r->out.handle);
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ ***************************************************************************/
+
+NTSTATUS _lsa_OpenSecret(pipes_struct *p, struct lsa_OpenSecret *r)
+{
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+}
+
+/***************************************************************************
+ ***************************************************************************/
+
+NTSTATUS _lsa_OpenTrustedDomain(pipes_struct *p, struct lsa_OpenTrustedDomain *r)
+{
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+}
+
+/***************************************************************************
+ ***************************************************************************/
+
+NTSTATUS _lsa_CreateTrustedDomain(pipes_struct *p, struct lsa_CreateTrustedDomain *r)
+{
+ return NT_STATUS_ACCESS_DENIED;
+}
+
+/***************************************************************************
+ ***************************************************************************/
+
+NTSTATUS _lsa_CreateSecret(pipes_struct *p, struct lsa_CreateSecret *r)
+{
+ return NT_STATUS_ACCESS_DENIED;
+}
+
+/***************************************************************************
+ ***************************************************************************/
+
+NTSTATUS _lsa_SetSecret(pipes_struct *p, struct lsa_SetSecret *r)
+{
+ return NT_STATUS_ACCESS_DENIED;
+}
+
+/***************************************************************************
+ _lsa_DeleteObject
+ ***************************************************************************/
+
+NTSTATUS _lsa_DeleteObject(pipes_struct *p,
+ struct lsa_DeleteObject *r)
+{
+ return NT_STATUS_ACCESS_DENIED;
+}
+
+/***************************************************************************
+ _lsa_EnumPrivs
+ ***************************************************************************/
+
+NTSTATUS _lsa_EnumPrivs(pipes_struct *p,
+ struct lsa_EnumPrivs *r)
+{
+ struct lsa_info *handle;
+ uint32 i;
+ uint32 enum_context = *r->in.resume_handle;
+ int num_privs = count_all_privileges();
+ struct lsa_PrivEntry *entries = NULL;
+ LUID_ATTR luid;
+
+ /* remember that the enum_context starts at 0 and not 1 */
+
+ if ( enum_context >= num_privs )
+ return NT_STATUS_NO_MORE_ENTRIES;
+
+ DEBUG(10,("_lsa_EnumPrivs: enum_context:%d total entries:%d\n",
+ enum_context, num_privs));
+
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check if the user has enough rights
+ I don't know if it's the right one. not documented. */
+
+ if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ if (num_privs) {
+ entries = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_PrivEntry, num_privs);
+ if (!entries) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ entries = NULL;
+ }
+
+ for (i = 0; i < num_privs; i++) {
+ if( i < enum_context) {
+
+ init_lsa_StringLarge(&entries[i].name, NULL);
+
+ entries[i].luid.low = 0;
+ entries[i].luid.high = 0;
+ } else {
+
+ init_lsa_StringLarge(&entries[i].name, privs[i].name);
+
+ luid = get_privilege_luid( &privs[i].se_priv );
+
+ entries[i].luid.low = luid.luid.low;
+ entries[i].luid.high = luid.luid.high;
+ }
+ }
+
+ enum_context = num_privs;
+
+ *r->out.resume_handle = enum_context;
+ r->out.privs->count = num_privs;
+ r->out.privs->privs = entries;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ _lsa_LookupPrivDisplayName
+ ***************************************************************************/
+
+NTSTATUS _lsa_LookupPrivDisplayName(pipes_struct *p,
+ struct lsa_LookupPrivDisplayName *r)
+{
+ struct lsa_info *handle;
+ const char *description;
+ struct lsa_StringLarge *lsa_name;
+
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check if the user has enough rights */
+
+ /*
+ * I don't know if it's the right one. not documented.
+ */
+ if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ DEBUG(10,("_lsa_LookupPrivDisplayName: name = %s\n", r->in.name->string));
+
+ description = get_privilege_dispname(r->in.name->string);
+ if (!description) {
+ DEBUG(10,("_lsa_LookupPrivDisplayName: doesn't exist\n"));
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+
+ DEBUG(10,("_lsa_LookupPrivDisplayName: display name = %s\n", description));
+
+ lsa_name = TALLOC_ZERO_P(p->mem_ctx, struct lsa_StringLarge);
+ if (!lsa_name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ init_lsa_StringLarge(lsa_name, description);
+
+ *r->out.returned_language_id = r->in.language_id;
+ *r->out.disp_name = lsa_name;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ _lsa_EnumAccounts
+ ***************************************************************************/
+
+NTSTATUS _lsa_EnumAccounts(pipes_struct *p,
+ struct lsa_EnumAccounts *r)
+{
+ struct lsa_info *handle;
+ DOM_SID *sid_list;
+ int i, j, num_entries;
+ NTSTATUS status;
+ struct lsa_SidPtr *sids = NULL;
+
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ sid_list = NULL;
+ num_entries = 0;
+
+ /* The only way we can currently find out all the SIDs that have been
+ privileged is to scan all privileges */
+
+ status = privilege_enumerate_accounts(&sid_list, &num_entries);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (*r->in.resume_handle >= num_entries) {
+ return NT_STATUS_NO_MORE_ENTRIES;
+ }
+
+ if (num_entries - *r->in.resume_handle) {
+ sids = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_SidPtr,
+ num_entries - *r->in.resume_handle);
+ if (!sids) {
+ SAFE_FREE(sid_list);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = *r->in.resume_handle, j = 0; i < num_entries; i++, j++) {
+ sids[j].sid = sid_dup_talloc(p->mem_ctx, &sid_list[i]);
+ if (!sids[j].sid) {
+ SAFE_FREE(sid_list);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ }
+
+ talloc_free(sid_list);
+
+ *r->out.resume_handle = num_entries;
+ r->out.sids->num_sids = num_entries;
+ r->out.sids->sids = sids;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ _lsa_GetUserName
+ ***************************************************************************/
+
+NTSTATUS _lsa_GetUserName(pipes_struct *p,
+ struct lsa_GetUserName *r)
+{
+ const char *username, *domname;
+ struct lsa_String *account_name = NULL;
+ struct lsa_String *authority_name = NULL;
+
+ if (p->server_info->guest) {
+ /*
+ * I'm 99% sure this is not the right place to do this,
+ * global_sid_Anonymous should probably be put into the token
+ * instead of the guest id -- vl
+ */
+ if (!lookup_sid(p->mem_ctx, &global_sid_Anonymous,
+ &domname, &username, NULL)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ username = p->server_info->sanitized_username;
+ domname = pdb_get_domain(p->server_info->sam_account);
+ }
+
+ account_name = TALLOC_ZERO_P(p->mem_ctx, struct lsa_String);
+ if (!account_name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ authority_name = TALLOC_ZERO_P(p->mem_ctx, struct lsa_String);
+ if (!authority_name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ init_lsa_String(account_name, username);
+ init_lsa_String(authority_name, domname);
+
+ *r->out.account_name = account_name;
+ *r->out.authority_name = authority_name;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ _lsa_CreateAccount
+ ***************************************************************************/
+
+NTSTATUS _lsa_CreateAccount(pipes_struct *p,
+ struct lsa_CreateAccount *r)
+{
+ struct lsa_info *handle;
+ struct lsa_info *info;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check if the user has enough rights */
+
+ /*
+ * I don't know if it's the right one. not documented.
+ * but guessed with rpcclient.
+ */
+ if (!(handle->access & LSA_POLICY_GET_PRIVATE_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* check to see if the pipe_user is a Domain Admin since
+ account_pol.tdb was already opened as root, this is all we have */
+
+ if ( !nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ) )
+ return NT_STATUS_ACCESS_DENIED;
+
+ if ( is_privileged_sid( r->in.sid ) )
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+
+ /* associate the user/group SID with the (unique) handle. */
+
+ if ((info = SMB_MALLOC_P(struct lsa_info)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(info);
+ info->sid = *r->in.sid;
+ info->access = r->in.access_mask;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, r->out.acct_handle, free_lsa_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return privilege_create_account( &info->sid );
+}
+
+
+/***************************************************************************
+ _lsa_OpenAccount
+ ***************************************************************************/
+
+NTSTATUS _lsa_OpenAccount(pipes_struct *p,
+ struct lsa_OpenAccount *r)
+{
+ struct lsa_info *handle;
+ struct lsa_info *info;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check if the user has enough rights */
+
+ /*
+ * I don't know if it's the right one. not documented.
+ * but guessed with rpcclient.
+ */
+ if (!(handle->access & LSA_POLICY_GET_PRIVATE_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* TODO: Fis the parsing routine before reenabling this check! */
+ #if 0
+ if (!lookup_sid(&handle->sid, dom_name, name, &type))
+ return NT_STATUS_ACCESS_DENIED;
+ #endif
+ /* associate the user/group SID with the (unique) handle. */
+ if ((info = SMB_MALLOC_P(struct lsa_info)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(info);
+ info->sid = *r->in.sid;
+ info->access = r->in.access_mask;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, r->out.acct_handle, free_lsa_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ _lsa_EnumPrivsAccount
+ For a given SID, enumerate all the privilege this account has.
+ ***************************************************************************/
+
+NTSTATUS _lsa_EnumPrivsAccount(pipes_struct *p,
+ struct lsa_EnumPrivsAccount *r)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ struct lsa_info *info=NULL;
+ SE_PRIV mask;
+ PRIVILEGE_SET privileges;
+ struct lsa_PrivilegeSet *priv_set = NULL;
+ struct lsa_LUIDAttribute *luid_attrs = NULL;
+ int i;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if ( !get_privileges_for_sids( &mask, &info->sid, 1 ) )
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ privilege_set_init( &privileges );
+
+ if ( se_priv_to_privilege_set( &privileges, &mask ) ) {
+
+ DEBUG(10,("_lsa_EnumPrivsAccount: %s has %d privileges\n",
+ sid_string_dbg(&info->sid),
+ privileges.count));
+
+ priv_set = TALLOC_ZERO_P(p->mem_ctx, struct lsa_PrivilegeSet);
+ if (!priv_set) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ luid_attrs = TALLOC_ZERO_ARRAY(p->mem_ctx,
+ struct lsa_LUIDAttribute,
+ privileges.count);
+ if (!luid_attrs) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i=0; i<privileges.count; i++) {
+ luid_attrs[i].luid.low = privileges.set[i].luid.low;
+ luid_attrs[i].luid.high = privileges.set[i].luid.high;
+ luid_attrs[i].attribute = privileges.set[i].attr;
+ }
+
+ priv_set->count = privileges.count;
+ priv_set->unknown = 0;
+ priv_set->set = luid_attrs;
+
+ *r->out.privs = priv_set;
+ } else {
+ status = NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+
+ done:
+ privilege_set_free( &privileges );
+
+ return status;
+}
+
+/***************************************************************************
+ _lsa_GetSystemAccessAccount
+ ***************************************************************************/
+
+NTSTATUS _lsa_GetSystemAccessAccount(pipes_struct *p,
+ struct lsa_GetSystemAccessAccount *r)
+{
+ struct lsa_info *info=NULL;
+
+ /* find the connection policy handle. */
+
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!lookup_sid(p->mem_ctx, &info->sid, NULL, NULL, NULL))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /*
+ 0x01 -> Log on locally
+ 0x02 -> Access this computer from network
+ 0x04 -> Log on as a batch job
+ 0x10 -> Log on as a service
+
+ they can be ORed together
+ */
+
+ *r->out.access_mask = PR_LOG_ON_LOCALLY | PR_ACCESS_FROM_NETWORK;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ update the systemaccount information
+ ***************************************************************************/
+
+NTSTATUS _lsa_SetSystemAccessAccount(pipes_struct *p,
+ struct lsa_SetSystemAccessAccount *r)
+{
+ struct lsa_info *info=NULL;
+ GROUP_MAP map;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check to see if the pipe_user is a Domain Admin since
+ account_pol.tdb was already opened as root, this is all we have */
+
+ if ( !nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ) )
+ return NT_STATUS_ACCESS_DENIED;
+
+ if (!pdb_getgrsid(&map, info->sid))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ return pdb_update_group_mapping_entry(&map);
+}
+
+/***************************************************************************
+ _lsa_AddPrivilegesToAccount
+ For a given SID, add some privileges.
+ ***************************************************************************/
+
+NTSTATUS _lsa_AddPrivilegesToAccount(pipes_struct *p,
+ struct lsa_AddPrivilegesToAccount *r)
+{
+ struct lsa_info *info = NULL;
+ SE_PRIV mask;
+ struct lsa_PrivilegeSet *set = NULL;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check to see if the pipe_user is root or a Domain Admin since
+ account_pol.tdb was already opened as root, this is all we have */
+
+ if ( p->pipe_user.ut.uid != sec_initial_uid()
+ && !nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ) )
+ {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ set = r->in.privs;
+ if ( !privilege_set_to_se_priv( &mask, set ) )
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+
+ if ( !grant_privilege( &info->sid, &mask ) ) {
+ DEBUG(3,("_lsa_AddPrivilegesToAccount: grant_privilege(%s) failed!\n",
+ sid_string_dbg(&info->sid) ));
+ DEBUG(3,("Privilege mask:\n"));
+ dump_se_priv( DBGC_ALL, 3, &mask );
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ _lsa_RemovePrivilegesFromAccount
+ For a given SID, remove some privileges.
+ ***************************************************************************/
+
+NTSTATUS _lsa_RemovePrivilegesFromAccount(pipes_struct *p,
+ struct lsa_RemovePrivilegesFromAccount *r)
+{
+ struct lsa_info *info = NULL;
+ SE_PRIV mask;
+ struct lsa_PrivilegeSet *set = NULL;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check to see if the pipe_user is root or a Domain Admin since
+ account_pol.tdb was already opened as root, this is all we have */
+
+ if ( p->pipe_user.ut.uid != sec_initial_uid()
+ && !nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ) )
+ {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ set = r->in.privs;
+
+ if ( !privilege_set_to_se_priv( &mask, set ) )
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+
+ if ( !revoke_privilege( &info->sid, &mask ) ) {
+ DEBUG(3,("_lsa_RemovePrivilegesFromAccount: revoke_privilege(%s) failed!\n",
+ sid_string_dbg(&info->sid) ));
+ DEBUG(3,("Privilege mask:\n"));
+ dump_se_priv( DBGC_ALL, 3, &mask );
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ _lsa_QuerySecurity
+ ***************************************************************************/
+
+NTSTATUS _lsa_QuerySecurity(pipes_struct *p,
+ struct lsa_QuerySecurity *r)
+{
+ struct lsa_info *handle=NULL;
+ SEC_DESC *psd = NULL;
+ size_t sd_size;
+ NTSTATUS status;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check if the user has enough rights */
+ if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+
+ switch (r->in.sec_info) {
+ case 1:
+ /* SD contains only the owner */
+
+ status=lsa_get_generic_sd(p->mem_ctx, &psd, &sd_size);
+ if(!NT_STATUS_IS_OK(status))
+ return NT_STATUS_NO_MEMORY;
+
+
+ if((*r->out.sdbuf = make_sec_desc_buf(p->mem_ctx, sd_size, psd)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+ break;
+ case 4:
+ /* SD contains only the ACL */
+
+ status=lsa_get_generic_sd(p->mem_ctx, &psd, &sd_size);
+ if(!NT_STATUS_IS_OK(status))
+ return NT_STATUS_NO_MEMORY;
+
+ if((*r->out.sdbuf = make_sec_desc_buf(p->mem_ctx, sd_size, psd)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+ break;
+ default:
+ return NT_STATUS_INVALID_LEVEL;
+ }
+
+ return status;
+}
+
+#if 0 /* AD DC work in ongoing in Samba 4 */
+
+/***************************************************************************
+ ***************************************************************************/
+
+ NTSTATUS _lsa_query_info2(pipes_struct *p, LSA_Q_QUERY_INFO2 *q_u, LSA_R_QUERY_INFO2 *r_u)
+{
+ struct lsa_info *handle;
+ const char *nb_name;
+ char *dns_name = NULL;
+ char *forest_name = NULL;
+ DOM_SID *sid = NULL;
+ struct GUID guid;
+ fstring dnsdomname;
+
+ ZERO_STRUCT(guid);
+ r_u->status = NT_STATUS_OK;
+
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)(void *)&handle))
+ return NT_STATUS_INVALID_HANDLE;
+
+ switch (q_u->info_class) {
+ case 0x0c:
+ /* check if the user has enough rights */
+ if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* Request PolicyPrimaryDomainInformation. */
+ switch (lp_server_role()) {
+ case ROLE_DOMAIN_PDC:
+ case ROLE_DOMAIN_BDC:
+ nb_name = get_global_sam_name();
+ /* ugly temp hack for these next two */
+
+ /* This should be a 'netbios domain -> DNS domain' mapping */
+ dnsdomname = get_mydnsdomname(p->mem_ctx);
+ if (!dnsdomname || !*dnsdomname) {
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+ strlower_m(dnsdomname);
+
+ dns_name = dnsdomname;
+ forest_name = dnsdomname;
+
+ sid = get_global_sam_sid();
+ secrets_fetch_domain_guid(lp_workgroup(), &guid);
+ break;
+ default:
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+ init_dns_dom_info(&r_u->info.dns_dom_info, nb_name, dns_name,
+ forest_name,&guid,sid);
+ break;
+ default:
+ DEBUG(0,("_lsa_query_info2: unknown info level in Lsa Query: %d\n", q_u->info_class));
+ r_u->status = NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
+ if (NT_STATUS_IS_OK(r_u->status)) {
+ r_u->ptr = 0x1;
+ r_u->info_class = q_u->info_class;
+ }
+
+ return r_u->status;
+}
+#endif /* AD DC work in ongoing in Samba 4 */
+
+/***************************************************************************
+ _lsa_AddAccountRights
+ ***************************************************************************/
+
+NTSTATUS _lsa_AddAccountRights(pipes_struct *p,
+ struct lsa_AddAccountRights *r)
+{
+ struct lsa_info *info = NULL;
+ int i = 0;
+ DOM_SID sid;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check to see if the pipe_user is a Domain Admin since
+ account_pol.tdb was already opened as root, this is all we have */
+
+ if ( p->pipe_user.ut.uid != sec_initial_uid()
+ && !nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ) )
+ {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* according to an NT4 PDC, you can add privileges to SIDs even without
+ call_lsa_create_account() first. And you can use any arbitrary SID. */
+
+ sid_copy( &sid, r->in.sid );
+
+ for ( i=0; i < r->in.rights->count; i++ ) {
+
+ const char *privname = r->in.rights->names[i].string;
+
+ /* only try to add non-null strings */
+
+ if ( !privname )
+ continue;
+
+ if ( !grant_privilege_by_name( &sid, privname ) ) {
+ DEBUG(2,("_lsa_AddAccountRights: Failed to add privilege [%s]\n",
+ privname ));
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ _lsa_RemoveAccountRights
+ ***************************************************************************/
+
+NTSTATUS _lsa_RemoveAccountRights(pipes_struct *p,
+ struct lsa_RemoveAccountRights *r)
+{
+ struct lsa_info *info = NULL;
+ int i = 0;
+ DOM_SID sid;
+ const char *privname = NULL;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check to see if the pipe_user is a Domain Admin since
+ account_pol.tdb was already opened as root, this is all we have */
+
+ if ( p->pipe_user.ut.uid != sec_initial_uid()
+ && !nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ) )
+ {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ sid_copy( &sid, r->in.sid );
+
+ if ( r->in.remove_all ) {
+ if ( !revoke_all_privileges( &sid ) )
+ return NT_STATUS_ACCESS_DENIED;
+
+ return NT_STATUS_OK;
+ }
+
+ for ( i=0; i < r->in.rights->count; i++ ) {
+
+ privname = r->in.rights->names[i].string;
+
+ /* only try to add non-null strings */
+
+ if ( !privname )
+ continue;
+
+ if ( !revoke_privilege_by_name( &sid, privname ) ) {
+ DEBUG(2,("_lsa_RemoveAccountRights: Failed to revoke privilege [%s]\n",
+ privname ));
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static NTSTATUS init_lsa_right_set(TALLOC_CTX *mem_ctx,
+ struct lsa_RightSet *r,
+ PRIVILEGE_SET *privileges)
+{
+ uint32 i;
+ const char *privname;
+ const char **privname_array = NULL;
+ int num_priv = 0;
+
+ for (i=0; i<privileges->count; i++) {
+
+ privname = luid_to_privilege_name(&privileges->set[i].luid);
+ if (privname) {
+ if (!add_string_to_array(mem_ctx, privname,
+ &privname_array, &num_priv)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ }
+
+ if (num_priv) {
+
+ r->names = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_StringLarge,
+ num_priv);
+ if (!r->names) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<num_priv; i++) {
+ init_lsa_StringLarge(&r->names[i], privname_array[i]);
+ }
+
+ r->count = num_priv;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ _lsa_EnumAccountRights
+ ***************************************************************************/
+
+NTSTATUS _lsa_EnumAccountRights(pipes_struct *p,
+ struct lsa_EnumAccountRights *r)
+{
+ NTSTATUS status;
+ struct lsa_info *info = NULL;
+ DOM_SID sid;
+ PRIVILEGE_SET privileges;
+ SE_PRIV mask;
+
+ /* find the connection policy handle. */
+
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* according to an NT4 PDC, you can add privileges to SIDs even without
+ call_lsa_create_account() first. And you can use any arbitrary SID. */
+
+ sid_copy( &sid, r->in.sid );
+
+ if ( !get_privileges_for_sids( &mask, &sid, 1 ) )
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ privilege_set_init( &privileges );
+
+ if ( se_priv_to_privilege_set( &privileges, &mask ) ) {
+
+ DEBUG(10,("_lsa_EnumAccountRights: %s has %d privileges\n",
+ sid_string_dbg(&sid), privileges.count));
+
+ status = init_lsa_right_set(p->mem_ctx, r->out.rights, &privileges);
+ } else {
+ status = NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+
+ privilege_set_free( &privileges );
+
+ return status;
+}
+
+/***************************************************************************
+ _lsa_LookupPrivValue
+ ***************************************************************************/
+
+NTSTATUS _lsa_LookupPrivValue(pipes_struct *p,
+ struct lsa_LookupPrivValue *r)
+{
+ struct lsa_info *info = NULL;
+ const char *name = NULL;
+ LUID_ATTR priv_luid;
+ SE_PRIV mask;
+
+ /* find the connection policy handle. */
+
+ if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ name = r->in.name->string;
+
+ DEBUG(10,("_lsa_lookup_priv_value: name = %s\n", name));
+
+ if ( !se_priv_from_name( name, &mask ) )
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+
+ priv_luid = get_privilege_luid( &mask );
+
+ r->out.luid->low = priv_luid.luid.low;
+ r->out.luid->high = priv_luid.luid.high;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * From here on the server routines are just dummy ones to make smbd link with
+ * librpc/gen_ndr/srv_lsa.c. These routines are actually never called, we are
+ * pulling the server stubs across one by one.
+ */
+
+NTSTATUS _lsa_Delete(pipes_struct *p, struct lsa_Delete *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_SetSecObj(pipes_struct *p, struct lsa_SetSecObj *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_ChangePassword(pipes_struct *p, struct lsa_ChangePassword *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_SetInfoPolicy(pipes_struct *p, struct lsa_SetInfoPolicy *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_ClearAuditLog(pipes_struct *p, struct lsa_ClearAuditLog *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_GetQuotasForAccount(pipes_struct *p, struct lsa_GetQuotasForAccount *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_SetQuotasForAccount(pipes_struct *p, struct lsa_SetQuotasForAccount *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_QueryTrustedDomainInfo(pipes_struct *p, struct lsa_QueryTrustedDomainInfo *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_SetInformationTrustedDomain(pipes_struct *p, struct lsa_SetInformationTrustedDomain *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_QuerySecret(pipes_struct *p, struct lsa_QuerySecret *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_LookupPrivName(pipes_struct *p, struct lsa_LookupPrivName *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_EnumAccountsWithUserRight(pipes_struct *p, struct lsa_EnumAccountsWithUserRight *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_QueryTrustedDomainInfoBySid(pipes_struct *p, struct lsa_QueryTrustedDomainInfoBySid *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_SetTrustedDomainInfo(pipes_struct *p, struct lsa_SetTrustedDomainInfo *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_DeleteTrustedDomain(pipes_struct *p, struct lsa_DeleteTrustedDomain *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_StorePrivateData(pipes_struct *p, struct lsa_StorePrivateData *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_RetrievePrivateData(pipes_struct *p, struct lsa_RetrievePrivateData *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_QueryInfoPolicy2(pipes_struct *p, struct lsa_QueryInfoPolicy2 *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_SetInfoPolicy2(pipes_struct *p, struct lsa_SetInfoPolicy2 *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_QueryTrustedDomainInfoByName(pipes_struct *p, struct lsa_QueryTrustedDomainInfoByName *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_SetTrustedDomainInfoByName(pipes_struct *p, struct lsa_SetTrustedDomainInfoByName *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_EnumTrustedDomainsEx(pipes_struct *p, struct lsa_EnumTrustedDomainsEx *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_CreateTrustedDomainEx(pipes_struct *p, struct lsa_CreateTrustedDomainEx *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_CloseTrustedDomainEx(pipes_struct *p, struct lsa_CloseTrustedDomainEx *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_QueryDomainInformationPolicy(pipes_struct *p, struct lsa_QueryDomainInformationPolicy *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_SetDomainInformationPolicy(pipes_struct *p, struct lsa_SetDomainInformationPolicy *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_OpenTrustedDomainByName(pipes_struct *p, struct lsa_OpenTrustedDomainByName *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_TestCall(pipes_struct *p, struct lsa_TestCall *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_CreateTrustedDomainEx2(pipes_struct *p, struct lsa_CreateTrustedDomainEx2 *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_CREDRWRITE(pipes_struct *p, struct lsa_CREDRWRITE *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_CREDRREAD(pipes_struct *p, struct lsa_CREDRREAD *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_CREDRENUMERATE(pipes_struct *p, struct lsa_CREDRENUMERATE *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_CREDRWRITEDOMAINCREDENTIALS(pipes_struct *p, struct lsa_CREDRWRITEDOMAINCREDENTIALS *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_CREDRREADDOMAINCREDENTIALS(pipes_struct *p, struct lsa_CREDRREADDOMAINCREDENTIALS *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_CREDRDELETE(pipes_struct *p, struct lsa_CREDRDELETE *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_CREDRGETTARGETINFO(pipes_struct *p, struct lsa_CREDRGETTARGETINFO *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_CREDRPROFILELOADED(pipes_struct *p, struct lsa_CREDRPROFILELOADED *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_CREDRGETSESSIONTYPES(pipes_struct *p, struct lsa_CREDRGETSESSIONTYPES *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_LSARREGISTERAUDITEVENT(pipes_struct *p, struct lsa_LSARREGISTERAUDITEVENT *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_LSARGENAUDITEVENT(pipes_struct *p, struct lsa_LSARGENAUDITEVENT *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_LSARUNREGISTERAUDITEVENT(pipes_struct *p, struct lsa_LSARUNREGISTERAUDITEVENT *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_lsaRQueryForestTrustInformation(pipes_struct *p, struct lsa_lsaRQueryForestTrustInformation *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_LSARSETFORESTTRUSTINFORMATION(pipes_struct *p, struct lsa_LSARSETFORESTTRUSTINFORMATION *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_CREDRRENAME(pipes_struct *p, struct lsa_CREDRRENAME *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_LSAROPENPOLICYSCE(pipes_struct *p, struct lsa_LSAROPENPOLICYSCE *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_LSARADTREGISTERSECURITYEVENTSOURCE(pipes_struct *p, struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(pipes_struct *p, struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS _lsa_LSARADTREPORTSECURITYEVENT(pipes_struct *p, struct lsa_LSARADTREPORTSECURITYEVENT *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
diff --git a/source3/rpc_server/srv_netlog_nt.c b/source3/rpc_server/srv_netlog_nt.c
new file mode 100644
index 0000000000..4e211cfb81
--- /dev/null
+++ b/source3/rpc_server/srv_netlog_nt.c
@@ -0,0 +1,1414 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 1998-2001.
+ * Copyright (C) Andrew Bartlett 2001.
+ * Copyright (C) Guenther Deschner 2008.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This is the implementation of the netlogon pipe. */
+
+#include "includes.h"
+
+extern userdom_struct current_user_info;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+/*************************************************************************
+ init_net_r_req_chal:
+ *************************************************************************/
+
+static void init_net_r_req_chal(struct netr_Credential *r,
+ struct netr_Credential *srv_chal)
+{
+ DEBUG(6,("init_net_r_req_chal: %d\n", __LINE__));
+
+ memcpy(r->data, srv_chal->data, sizeof(r->data));
+}
+
+/*******************************************************************
+ Inits a netr_NETLOGON_INFO_1 structure.
+********************************************************************/
+
+static void init_netlogon_info1(struct netr_NETLOGON_INFO_1 *r,
+ uint32_t flags,
+ uint32_t pdc_connection_status)
+{
+ r->flags = flags;
+ r->pdc_connection_status = pdc_connection_status;
+}
+
+/*******************************************************************
+ Inits a netr_NETLOGON_INFO_2 structure.
+********************************************************************/
+
+static void init_netlogon_info2(struct netr_NETLOGON_INFO_2 *r,
+ uint32_t flags,
+ uint32_t pdc_connection_status,
+ const char *trusted_dc_name,
+ uint32_t tc_connection_status)
+{
+ r->flags = flags;
+ r->pdc_connection_status = pdc_connection_status;
+ r->trusted_dc_name = trusted_dc_name;
+ r->tc_connection_status = tc_connection_status;
+}
+
+/*******************************************************************
+ Inits a netr_NETLOGON_INFO_3 structure.
+********************************************************************/
+
+static void init_netlogon_info3(struct netr_NETLOGON_INFO_3 *r,
+ uint32_t flags,
+ uint32_t logon_attempts)
+{
+ r->flags = flags;
+ r->logon_attempts = logon_attempts;
+}
+
+/*************************************************************************
+ _netr_LogonControl
+ *************************************************************************/
+
+WERROR _netr_LogonControl(pipes_struct *p,
+ struct netr_LogonControl *r)
+{
+ struct netr_NETLOGON_INFO_1 *info1;
+ uint32_t flags = 0x0;
+ uint32_t pdc_connection_status = W_ERROR_V(WERR_OK);
+
+ /* Setup the Logon Control response */
+
+ switch (r->in.level) {
+ case 1:
+ info1 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_1);
+ if (!info1) {
+ return WERR_NOMEM;
+ }
+ init_netlogon_info1(info1,
+ flags,
+ pdc_connection_status);
+ r->out.info->info1 = info1;
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+Send a message to smbd to do a sam synchronisation
+**************************************************************************/
+
+static void send_sync_message(void)
+{
+ DEBUG(3, ("sending sam synchronisation message\n"));
+ message_send_all(smbd_messaging_context(), MSG_SMB_SAM_SYNC, NULL, 0,
+ NULL);
+}
+
+/*************************************************************************
+ _netr_LogonControl2
+ *************************************************************************/
+
+WERROR _netr_LogonControl2(pipes_struct *p,
+ struct netr_LogonControl2 *r)
+{
+ uint32 flags = 0x0;
+ uint32 pdc_connection_status = 0x0;
+ uint32 logon_attempts = 0x0;
+ uint32 tc_status;
+ fstring dc_name2;
+ const char *dc_name = NULL;
+ struct sockaddr_storage dc_ss;
+ const char *domain = NULL;
+ struct netr_NETLOGON_INFO_1 *info1;
+ struct netr_NETLOGON_INFO_2 *info2;
+ struct netr_NETLOGON_INFO_3 *info3;
+
+ tc_status = W_ERROR_V(WERR_NO_SUCH_DOMAIN);
+
+ switch (r->in.function_code) {
+ case NETLOGON_CONTROL_TC_QUERY:
+ domain = r->in.data->domain;
+
+ if ( !is_trusted_domain( domain ) )
+ break;
+
+ if ( !get_dc_name( domain, NULL, dc_name2, &dc_ss ) ) {
+ tc_status = W_ERROR_V(WERR_NO_LOGON_SERVERS);
+ break;
+ }
+
+ dc_name = talloc_asprintf(p->mem_ctx, "\\\\%s", dc_name2);
+ if (!dc_name) {
+ return WERR_NOMEM;
+ }
+
+ tc_status = W_ERROR_V(WERR_OK);
+
+ break;
+
+ case NETLOGON_CONTROL_REDISCOVER:
+ domain = r->in.data->domain;
+
+ if ( !is_trusted_domain( domain ) )
+ break;
+
+ if ( !get_dc_name( domain, NULL, dc_name2, &dc_ss ) ) {
+ tc_status = W_ERROR_V(WERR_NO_LOGON_SERVERS);
+ break;
+ }
+
+ dc_name = talloc_asprintf(p->mem_ctx, "\\\\%s", dc_name2);
+ if (!dc_name) {
+ return WERR_NOMEM;
+ }
+
+ tc_status = W_ERROR_V(WERR_OK);
+
+ break;
+
+ default:
+ /* no idea what this should be */
+ DEBUG(0,("_netr_LogonControl2: unimplemented function level [%d]\n",
+ r->in.function_code));
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ /* prepare the response */
+
+ switch (r->in.level) {
+ case 1:
+ info1 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_1);
+ W_ERROR_HAVE_NO_MEMORY(info1);
+
+ init_netlogon_info1(info1,
+ flags,
+ pdc_connection_status);
+ r->out.query->info1 = info1;
+ break;
+ case 2:
+ info2 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_2);
+ W_ERROR_HAVE_NO_MEMORY(info2);
+
+ init_netlogon_info2(info2,
+ flags,
+ pdc_connection_status,
+ dc_name,
+ tc_status);
+ r->out.query->info2 = info2;
+ break;
+ case 3:
+ info3 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_3);
+ W_ERROR_HAVE_NO_MEMORY(info3);
+
+ init_netlogon_info3(info3,
+ flags,
+ logon_attempts);
+ r->out.query->info3 = info3;
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ if (lp_server_role() == ROLE_DOMAIN_BDC) {
+ send_sync_message();
+ }
+
+ return WERR_OK;
+}
+
+/*************************************************************************
+ _netr_NetrEnumerateTrustedDomains
+ *************************************************************************/
+
+WERROR _netr_NetrEnumerateTrustedDomains(pipes_struct *p,
+ struct netr_NetrEnumerateTrustedDomains *r)
+{
+ struct netr_Blob trusted_domains_blob;
+ DATA_BLOB blob;
+
+ DEBUG(6,("_netr_NetrEnumerateTrustedDomains: %d\n", __LINE__));
+
+ /* set up the Trusted Domain List response */
+
+ blob = data_blob_talloc_zero(p->mem_ctx, 2);
+ trusted_domains_blob.data = blob.data;
+ trusted_domains_blob.length = blob.length;
+
+ DEBUG(6,("_netr_NetrEnumerateTrustedDomains: %d\n", __LINE__));
+
+ *r->out.trusted_domains_blob = trusted_domains_blob;
+
+ return WERR_OK;
+}
+
+/******************************************************************
+ gets a machine password entry. checks access rights of the host.
+ ******************************************************************/
+
+static NTSTATUS get_md4pw(char *md4pw, const char *mach_acct, uint16 sec_chan_type)
+{
+ struct samu *sampass = NULL;
+ const uint8 *pass;
+ bool ret;
+ uint32 acct_ctrl;
+
+#if 0
+ char addr[INET6_ADDRSTRLEN];
+
+ /*
+ * 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(get_client_fd()),
+ client_addr(get_client_fd(),addr,sizeof(addr)))) {
+ DEBUG(0,("get_md4pw: Workstation %s denied access to domain\n", mach_acct));
+ return False;
+ }
+#endif /* 0 */
+
+ if ( !(sampass = samu_new( NULL )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* JRA. This is ok as it is only used for generating the challenge. */
+ become_root();
+ ret = pdb_getsampwnam(sampass, mach_acct);
+ unbecome_root();
+
+ if (!ret) {
+ DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ acct_ctrl = pdb_get_acct_ctrl(sampass);
+ if (acct_ctrl & ACB_DISABLED) {
+ DEBUG(0,("get_md4pw: Workstation %s: account is disabled\n", mach_acct));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_ACCOUNT_DISABLED;
+ }
+
+ if (!(acct_ctrl & ACB_SVRTRUST) &&
+ !(acct_ctrl & ACB_WSTRUST) &&
+ !(acct_ctrl & ACB_DOMTRUST))
+ {
+ DEBUG(0,("get_md4pw: Workstation %s: account is not a trust account\n", mach_acct));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_NO_TRUST_SAM_ACCOUNT;
+ }
+
+ switch (sec_chan_type) {
+ case SEC_CHAN_BDC:
+ if (!(acct_ctrl & ACB_SVRTRUST)) {
+ DEBUG(0,("get_md4pw: Workstation %s: BDC secure channel requested "
+ "but not a server trust account\n", mach_acct));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_NO_TRUST_SAM_ACCOUNT;
+ }
+ break;
+ case SEC_CHAN_WKSTA:
+ if (!(acct_ctrl & ACB_WSTRUST)) {
+ DEBUG(0,("get_md4pw: Workstation %s: WORKSTATION secure channel requested "
+ "but not a workstation trust account\n", mach_acct));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_NO_TRUST_SAM_ACCOUNT;
+ }
+ break;
+ case SEC_CHAN_DOMAIN:
+ if (!(acct_ctrl & ACB_DOMTRUST)) {
+ DEBUG(0,("get_md4pw: Workstation %s: DOMAIN secure channel requested "
+ "but not a interdomain trust account\n", mach_acct));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_NO_TRUST_SAM_ACCOUNT;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if ((pass = pdb_get_nt_passwd(sampass)) == NULL) {
+ DEBUG(0,("get_md4pw: Workstation %s: account does not have a password\n", mach_acct));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ memcpy(md4pw, pass, 16);
+ dump_data(5, (uint8 *)md4pw, 16);
+
+ TALLOC_FREE(sampass);
+
+ return NT_STATUS_OK;
+
+
+}
+
+/*************************************************************************
+ _netr_ServerReqChallenge
+ *************************************************************************/
+
+NTSTATUS _netr_ServerReqChallenge(pipes_struct *p,
+ struct netr_ServerReqChallenge *r)
+{
+ if (!p->dc) {
+ p->dc = TALLOC_ZERO_P(p, struct dcinfo);
+ if (!p->dc) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ DEBUG(10,("_netr_ServerReqChallenge: new challenge requested. Clearing old state.\n"));
+ ZERO_STRUCTP(p->dc);
+ }
+
+ fstrcpy(p->dc->remote_machine, r->in.computer_name);
+
+ /* Save the client challenge to the server. */
+ memcpy(p->dc->clnt_chal.data, r->in.credentials->data,
+ sizeof(r->in.credentials->data));
+
+ /* Create a server challenge for the client */
+ /* Set this to a random value. */
+ generate_random_buffer(p->dc->srv_chal.data, 8);
+
+ /* set up the LSA REQUEST CHALLENGE response */
+ init_net_r_req_chal(r->out.return_credentials, &p->dc->srv_chal);
+
+ p->dc->challenge_sent = True;
+
+ return NT_STATUS_OK;
+}
+
+/*************************************************************************
+ _netr_ServerAuthenticate
+ Create the initial credentials.
+ *************************************************************************/
+
+NTSTATUS _netr_ServerAuthenticate(pipes_struct *p,
+ struct netr_ServerAuthenticate *r)
+{
+ NTSTATUS status;
+ struct netr_Credential srv_chal_out;
+
+ if (!p->dc || !p->dc->challenge_sent) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = get_md4pw((char *)p->dc->mach_pw,
+ r->in.account_name,
+ r->in.secure_channel_type);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("_netr_ServerAuthenticate: get_md4pw failed. Failed to "
+ "get password for machine account %s "
+ "from client %s: %s\n",
+ r->in.account_name,
+ r->in.computer_name,
+ nt_errstr(status) ));
+ /* always return NT_STATUS_ACCESS_DENIED */
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* From the client / server challenges and md4 password, generate sess key */
+ creds_server_init(0, /* No neg flags. */
+ p->dc,
+ &p->dc->clnt_chal, /* Stored client chal. */
+ &p->dc->srv_chal, /* Stored server chal. */
+ p->dc->mach_pw,
+ &srv_chal_out);
+
+ /* Check client credentials are valid. */
+ if (!netlogon_creds_server_check(p->dc, r->in.credentials)) {
+ DEBUG(0,("_netr_ServerAuthenticate: netlogon_creds_server_check failed. Rejecting auth "
+ "request from client %s machine account %s\n",
+ r->in.computer_name,
+ r->in.account_name));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ fstrcpy(p->dc->mach_acct, r->in.account_name);
+ fstrcpy(p->dc->remote_machine, r->in.computer_name);
+ p->dc->authenticated = True;
+
+ /* set up the LSA AUTH response */
+ /* Return the server credentials. */
+
+ memcpy(r->out.return_credentials->data, &srv_chal_out.data,
+ sizeof(r->out.return_credentials->data));
+
+ return NT_STATUS_OK;
+}
+
+/*************************************************************************
+ _netr_ServerAuthenticate2
+ *************************************************************************/
+
+NTSTATUS _netr_ServerAuthenticate2(pipes_struct *p,
+ struct netr_ServerAuthenticate2 *r)
+{
+ NTSTATUS status;
+ uint32_t srv_flgs;
+ struct netr_Credential srv_chal_out;
+
+ /* We use this as the key to store the creds: */
+ /* r->in.computer_name */
+
+ if (!p->dc || !p->dc->challenge_sent) {
+ DEBUG(0,("_netr_ServerAuthenticate2: no challenge sent to client %s\n",
+ r->in.computer_name));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if ( (lp_server_schannel() == true) &&
+ ((*r->in.negotiate_flags & NETLOGON_NEG_SCHANNEL) == 0) ) {
+
+ /* schannel must be used, but client did not offer it. */
+ DEBUG(0,("_netr_ServerAuthenticate2: schannel required but client failed "
+ "to offer it. Client was %s\n",
+ r->in.account_name));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = get_md4pw((char *)p->dc->mach_pw,
+ r->in.account_name,
+ r->in.secure_channel_type);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("_netr_ServerAuthenticate2: failed to get machine password for "
+ "account %s: %s\n",
+ r->in.account_name, nt_errstr(status) ));
+ /* always return NT_STATUS_ACCESS_DENIED */
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* From the client / server challenges and md4 password, generate sess key */
+ creds_server_init(*r->in.negotiate_flags,
+ p->dc,
+ &p->dc->clnt_chal, /* Stored client chal. */
+ &p->dc->srv_chal, /* Stored server chal. */
+ p->dc->mach_pw,
+ &srv_chal_out);
+
+ /* Check client credentials are valid. */
+ if (!netlogon_creds_server_check(p->dc, r->in.credentials)) {
+ DEBUG(0,("_netr_ServerAuthenticate2: netlogon_creds_server_check failed. Rejecting auth "
+ "request from client %s machine account %s\n",
+ r->in.computer_name,
+ r->in.account_name));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* 0x000001ff */
+ srv_flgs = NETLOGON_NEG_ACCOUNT_LOCKOUT |
+ NETLOGON_NEG_PERSISTENT_SAMREPL |
+ NETLOGON_NEG_ARCFOUR |
+ NETLOGON_NEG_PROMOTION_COUNT |
+ NETLOGON_NEG_CHANGELOG_BDC |
+ NETLOGON_NEG_FULL_SYNC_REPL |
+ NETLOGON_NEG_MULTIPLE_SIDS |
+ NETLOGON_NEG_REDO |
+ NETLOGON_NEG_PASSWORD_CHANGE_REFUSAL;
+
+ if (lp_server_schannel() != false) {
+ srv_flgs |= NETLOGON_NEG_SCHANNEL;
+ }
+
+ /* set up the LSA AUTH 2 response */
+ memcpy(r->out.return_credentials->data, &srv_chal_out.data,
+ sizeof(r->out.return_credentials->data));
+ *r->out.negotiate_flags = srv_flgs;
+
+ fstrcpy(p->dc->mach_acct, r->in.account_name);
+ fstrcpy(p->dc->remote_machine, r->in.computer_name);
+ fstrcpy(p->dc->domain, lp_workgroup() );
+
+ p->dc->authenticated = True;
+
+ /* Store off the state so we can continue after client disconnect. */
+ become_root();
+ secrets_store_schannel_session_info(p->mem_ctx,
+ r->in.computer_name,
+ p->dc);
+ unbecome_root();
+
+ return NT_STATUS_OK;
+}
+
+/*************************************************************************
+ _netr_ServerPasswordSet
+ *************************************************************************/
+
+NTSTATUS _netr_ServerPasswordSet(pipes_struct *p,
+ struct netr_ServerPasswordSet *r)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ fstring remote_machine;
+ struct samu *sampass=NULL;
+ bool ret = False;
+ unsigned char pwd[16];
+ int i;
+ uint32 acct_ctrl;
+ struct netr_Authenticator cred_out;
+ const uchar *old_pw;
+
+ DEBUG(5,("_netr_ServerPasswordSet: %d\n", __LINE__));
+
+ /* We need the remote machine name for the creds lookup. */
+ fstrcpy(remote_machine, r->in.computer_name);
+
+ if ( (lp_server_schannel() == True) && (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) ) {
+ /* 'server schannel = yes' should enforce use of
+ schannel, the client did offer it in auth2, but
+ obviously did not use it. */
+ DEBUG(0,("_netr_ServerPasswordSet: client %s not using schannel for netlogon\n",
+ remote_machine ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (!p->dc) {
+ /* Restore the saved state of the netlogon creds. */
+ become_root();
+ ret = secrets_restore_schannel_session_info(p, remote_machine,
+ &p->dc);
+ unbecome_root();
+ if (!ret) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+ }
+
+ if (!p->dc || !p->dc->authenticated) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ DEBUG(3,("_netr_ServerPasswordSet: Server Password Set by remote machine:[%s] on account [%s]\n",
+ remote_machine, p->dc->mach_acct));
+
+ /* Step the creds chain forward. */
+ if (!netlogon_creds_server_step(p->dc, r->in.credential, &cred_out)) {
+ DEBUG(2,("_netr_ServerPasswordSet: netlogon_creds_server_step failed. Rejecting auth "
+ "request from client %s machine account %s\n",
+ remote_machine, p->dc->mach_acct ));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* We must store the creds state after an update. */
+ sampass = samu_new( NULL );
+ if (!sampass) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+ secrets_store_schannel_session_info(p, remote_machine, p->dc);
+ ret = pdb_getsampwnam(sampass, p->dc->mach_acct);
+ unbecome_root();
+
+ if (!ret) {
+ TALLOC_FREE(sampass);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* Ensure the account exists and is a machine account. */
+
+ acct_ctrl = pdb_get_acct_ctrl(sampass);
+
+ if (!(acct_ctrl & ACB_WSTRUST ||
+ acct_ctrl & ACB_SVRTRUST ||
+ acct_ctrl & ACB_DOMTRUST)) {
+ TALLOC_FREE(sampass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (pdb_get_acct_ctrl(sampass) & ACB_DISABLED) {
+ TALLOC_FREE(sampass);
+ return NT_STATUS_ACCOUNT_DISABLED;
+ }
+
+ /* Woah - what does this to to the credential chain ? JRA */
+ cred_hash3(pwd, r->in.new_password->hash, p->dc->sess_key, 0);
+
+ DEBUG(100,("_netr_ServerPasswordSet: new given value was :\n"));
+ for(i = 0; i < sizeof(pwd); i++)
+ DEBUG(100,("%02X ", pwd[i]));
+ DEBUG(100,("\n"));
+
+ old_pw = pdb_get_nt_passwd(sampass);
+
+ if (old_pw && memcmp(pwd, old_pw, 16) == 0) {
+ /* Avoid backend modificiations and other fun if the
+ client changed the password to the *same thing* */
+
+ ret = True;
+ } else {
+
+ /* LM password should be NULL for machines */
+ if (!pdb_set_lanman_passwd(sampass, NULL, PDB_CHANGED)) {
+ TALLOC_FREE(sampass);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_nt_passwd(sampass, pwd, PDB_CHANGED)) {
+ TALLOC_FREE(sampass);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_pass_last_set_time(sampass, time(NULL), PDB_CHANGED)) {
+ TALLOC_FREE(sampass);
+ /* Not quite sure what this one qualifies as, but this will do */
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ become_root();
+ status = pdb_update_sam_account(sampass);
+ unbecome_root();
+ }
+
+ /* set up the LSA Server Password Set response */
+
+ memcpy(r->out.return_authenticator, &cred_out,
+ sizeof(r->out.return_authenticator));
+
+ TALLOC_FREE(sampass);
+ return status;
+}
+
+/*************************************************************************
+ _netr_LogonSamLogoff
+ *************************************************************************/
+
+NTSTATUS _netr_LogonSamLogoff(pipes_struct *p,
+ struct netr_LogonSamLogoff *r)
+{
+ if ( (lp_server_schannel() == True) && (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) ) {
+ /* 'server schannel = yes' should enforce use of
+ schannel, the client did offer it in auth2, but
+ obviously did not use it. */
+ DEBUG(0,("_netr_LogonSamLogoff: client %s not using schannel for netlogon\n",
+ get_remote_machine_name() ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+
+ /* Using the remote machine name for the creds store: */
+ /* r->in.computer_name */
+
+ if (!p->dc) {
+ /* Restore the saved state of the netlogon creds. */
+ bool ret;
+
+ become_root();
+ ret = secrets_restore_schannel_session_info(
+ p, r->in.computer_name, &p->dc);
+ unbecome_root();
+ if (!ret) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+ }
+
+ if (!p->dc || !p->dc->authenticated) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ /* checks and updates credentials. creates reply credentials */
+ if (!netlogon_creds_server_step(p->dc, r->in.credential, r->out.return_authenticator)) {
+ DEBUG(2,("_netr_LogonSamLogoff: netlogon_creds_server_step failed. Rejecting auth "
+ "request from client %s machine account %s\n",
+ r->in.computer_name, p->dc->mach_acct ));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* We must store the creds state after an update. */
+ become_root();
+ secrets_store_schannel_session_info(p, r->in.computer_name, p->dc);
+ unbecome_root();
+
+ return NT_STATUS_OK;
+}
+
+/*************************************************************************
+ _netr_LogonSamLogon
+ *************************************************************************/
+
+NTSTATUS _netr_LogonSamLogon(pipes_struct *p,
+ struct netr_LogonSamLogon *r)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ struct netr_SamInfo3 *sam3 = NULL;
+ union netr_LogonInfo *logon = r->in.logon;
+ fstring nt_username, nt_domain, nt_workstation;
+ auth_usersupplied_info *user_info = NULL;
+ auth_serversupplied_info *server_info = NULL;
+ struct auth_context *auth_context = NULL;
+ uint8_t pipe_session_key[16];
+ bool process_creds = true;
+
+ switch (p->hdr_req.opnum) {
+ case NDR_NETR_LOGONSAMLOGON:
+ process_creds = true;
+ break;
+ case NDR_NETR_LOGONSAMLOGONEX:
+ default:
+ process_creds = false;
+ }
+
+ if ( (lp_server_schannel() == True) && (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) ) {
+ /* 'server schannel = yes' should enforce use of
+ schannel, the client did offer it in auth2, but
+ obviously did not use it. */
+ DEBUG(0,("_netr_LogonSamLogon: client %s not using schannel for netlogon\n",
+ get_remote_machine_name() ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ sam3 = TALLOC_ZERO_P(p->mem_ctx, struct netr_SamInfo3);
+ if (!sam3) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* store the user information, if there is any. */
+ r->out.validation->sam3 = sam3;
+ *r->out.authoritative = true; /* authoritative response */
+ if (r->in.validation_level != 2 && r->in.validation_level != 3) {
+ DEBUG(0,("_netr_LogonSamLogon: bad validation_level value %d.\n",
+ (int)r->in.validation_level));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (process_creds) {
+ fstring remote_machine;
+
+ /* Get the remote machine name for the creds store. */
+ /* Note this is the remote machine this request is coming from (member server),
+ not neccessarily the workstation name the user is logging onto.
+ */
+
+ fstrcpy(remote_machine, r->in.computer_name);
+
+ if (!p->dc) {
+ /* Restore the saved state of the netlogon creds. */
+ bool ret;
+
+ become_root();
+ ret = secrets_restore_schannel_session_info(
+ p, remote_machine, &p->dc);
+ unbecome_root();
+ if (!ret) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+ }
+
+ if (!p->dc || !p->dc->authenticated) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ /* checks and updates credentials. creates reply credentials */
+ if (!netlogon_creds_server_step(p->dc, r->in.credential, r->out.return_authenticator)) {
+ DEBUG(2,("_netr_LogonSamLogon: creds_server_step failed. Rejecting auth "
+ "request from client %s machine account %s\n",
+ remote_machine, p->dc->mach_acct ));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* We must store the creds state after an update. */
+ become_root();
+ secrets_store_schannel_session_info(p, remote_machine, p->dc);
+ unbecome_root();
+ }
+
+ switch (r->in.logon_level) {
+ case INTERACTIVE_LOGON_TYPE:
+ fstrcpy(nt_username,
+ logon->password->identity_info.account_name.string);
+ fstrcpy(nt_domain,
+ logon->password->identity_info.domain_name.string);
+ fstrcpy(nt_workstation,
+ logon->password->identity_info.workstation.string);
+
+ DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ", lp_workgroup()));
+ break;
+ case NET_LOGON_TYPE:
+ fstrcpy(nt_username,
+ logon->network->identity_info.account_name.string);
+ fstrcpy(nt_domain,
+ logon->network->identity_info.domain_name.string);
+ fstrcpy(nt_workstation,
+ logon->network->identity_info.workstation.string);
+
+ DEBUG(3,("SAM Logon (Network). Domain:[%s]. ", lp_workgroup()));
+ break;
+ default:
+ DEBUG(2,("SAM Logon: unsupported switch value\n"));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ } /* end switch */
+
+ DEBUG(3,("User:[%s@%s] Requested Domain:[%s]\n", nt_username, nt_workstation, nt_domain));
+ fstrcpy(current_user_info.smb_name, nt_username);
+ sub_set_smb_name(nt_username);
+
+ DEBUG(5,("Attempting validation level %d for unmapped username %s.\n",
+ r->in.validation_level, nt_username));
+
+ status = NT_STATUS_OK;
+
+ switch (r->in.logon_level) {
+ case NET_LOGON_TYPE:
+ {
+ const char *wksname = nt_workstation;
+
+ status = make_auth_context_fixed(&auth_context,
+ logon->network->challenge);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* For a network logon, the workstation name comes in with two
+ * backslashes in the front. Strip them if they are there. */
+
+ if (*wksname == '\\') wksname++;
+ if (*wksname == '\\') wksname++;
+
+ /* Standard challenge/response authenticaion */
+ if (!make_user_info_netlogon_network(&user_info,
+ nt_username, nt_domain,
+ wksname,
+ logon->network->identity_info.parameter_control,
+ logon->network->lm.data,
+ logon->network->lm.length,
+ logon->network->nt.data,
+ logon->network->nt.length)) {
+ status = NT_STATUS_NO_MEMORY;
+ }
+ break;
+ }
+ case INTERACTIVE_LOGON_TYPE:
+ /* 'Interactive' authentication, supplies the password in its
+ MD4 form, encrypted with the session key. We will convert
+ this to challenge/response for the auth subsystem to chew
+ on */
+ {
+ const uint8 *chal;
+
+ if (!NT_STATUS_IS_OK(status = make_auth_context_subsystem(&auth_context))) {
+ return status;
+ }
+
+ chal = auth_context->get_ntlm_challenge(auth_context);
+
+ if (!make_user_info_netlogon_interactive(&user_info,
+ nt_username, nt_domain,
+ nt_workstation,
+ logon->password->identity_info.parameter_control,
+ chal,
+ logon->password->lmpassword.hash,
+ logon->password->ntpassword.hash,
+ p->dc->sess_key)) {
+ status = NT_STATUS_NO_MEMORY;
+ }
+ break;
+ }
+ default:
+ DEBUG(2,("SAM Logon: unsupported switch value\n"));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ } /* end switch */
+
+ if ( NT_STATUS_IS_OK(status) ) {
+ status = auth_context->check_ntlm_password(auth_context,
+ user_info, &server_info);
+ }
+
+ (auth_context->free)(&auth_context);
+ free_user_info(&user_info);
+
+ DEBUG(5,("_netr_LogonSamLogon: check_password returned status %s\n",
+ nt_errstr(status)));
+
+ /* Check account and password */
+
+ if (!NT_STATUS_IS_OK(status)) {
+ /* If we don't know what this domain is, we need to
+ indicate that we are not authoritative. This
+ allows the client to decide if it needs to try
+ a local user. Fix by jpjanosi@us.ibm.com, #2976 */
+ if ( NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
+ && !strequal(nt_domain, get_global_sam_name())
+ && !is_trusted_domain(nt_domain) )
+ *r->out.authoritative = false; /* We are not authoritative */
+
+ TALLOC_FREE(server_info);
+ return status;
+ }
+
+ if (server_info->guest) {
+ /* We don't like guest domain logons... */
+ DEBUG(5,("_netr_LogonSamLogon: Attempted domain logon as GUEST "
+ "denied.\n"));
+ TALLOC_FREE(server_info);
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ /* This is the point at which, if the login was successful, that
+ the SAM Local Security Authority should record that the user is
+ logged in to the domain. */
+
+ if (process_creds) {
+ /* Get the pipe session key from the creds. */
+ memcpy(pipe_session_key, p->dc->sess_key, 16);
+ } else {
+ /* Get the pipe session key from the schannel. */
+ if ((p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL)
+ || (p->auth.a_u.schannel_auth == NULL)) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+ memcpy(pipe_session_key, p->auth.a_u.schannel_auth->sess_key, 16);
+ }
+
+ status = serverinfo_to_SamInfo3(server_info, pipe_session_key, sam3);
+ TALLOC_FREE(server_info);
+ return status;
+}
+
+/*************************************************************************
+ _netr_LogonSamLogonEx
+ - no credential chaining. Map into net sam logon.
+ *************************************************************************/
+
+NTSTATUS _netr_LogonSamLogonEx(pipes_struct *p,
+ struct netr_LogonSamLogonEx *r)
+{
+ struct netr_LogonSamLogon q;
+
+ /* Only allow this if the pipe is protected. */
+ if (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) {
+ DEBUG(0,("_net_sam_logon_ex: client %s not using schannel for netlogon\n",
+ get_remote_machine_name() ));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ q.in.server_name = r->in.server_name;
+ q.in.computer_name = r->in.computer_name;
+ q.in.logon_level = r->in.logon_level;
+ q.in.logon = r->in.logon;
+ q.in.validation_level = r->in.validation_level;
+ /* we do not handle the flags */
+ /* = r->in.flags; */
+
+ q.out.validation = r->out.validation;
+ q.out.authoritative = r->out.authoritative;
+ /* we do not handle the flags */
+ /* = r->out.flags; */
+
+ return _netr_LogonSamLogon(p, &q);
+}
+
+/*************************************************************************
+ _ds_enum_dom_trusts
+ *************************************************************************/
+#if 0 /* JERRY -- not correct */
+ NTSTATUS _ds_enum_dom_trusts(pipes_struct *p, DS_Q_ENUM_DOM_TRUSTS *q_u,
+ DS_R_ENUM_DOM_TRUSTS *r_u)
+{
+ NTSTATUS status = NT_STATUS_OK;
+
+ /* TODO: According to MSDN, the can only be executed against a
+ DC or domain member running Windows 2000 or later. Need
+ to test against a standalone 2k server and see what it
+ does. A windows 2000 DC includes its own domain in the
+ list. --jerry */
+
+ return status;
+}
+#endif /* JERRY */
+
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_LogonUasLogon(pipes_struct *p,
+ struct netr_LogonUasLogon *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_LogonUasLogoff(pipes_struct *p,
+ struct netr_LogonUasLogoff *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _netr_DatabaseDeltas(pipes_struct *p,
+ struct netr_DatabaseDeltas *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _netr_DatabaseSync(pipes_struct *p,
+ struct netr_DatabaseSync *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _netr_AccountDeltas(pipes_struct *p,
+ struct netr_AccountDeltas *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _netr_AccountSync(pipes_struct *p,
+ struct netr_AccountSync *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_GetDcName(pipes_struct *p,
+ struct netr_GetDcName *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_GetAnyDCName(pipes_struct *p,
+ struct netr_GetAnyDCName *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _netr_DatabaseSync2(pipes_struct *p,
+ struct netr_DatabaseSync2 *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _netr_DatabaseRedo(pipes_struct *p,
+ struct netr_DatabaseRedo *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_LogonControl2Ex(pipes_struct *p,
+ struct netr_LogonControl2Ex *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_DsRGetDCName(pipes_struct *p,
+ struct netr_DsRGetDCName *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_NETRLOGONDUMMYROUTINE1(pipes_struct *p,
+ struct netr_NETRLOGONDUMMYROUTINE1 *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_NETRLOGONSETSERVICEBITS(pipes_struct *p,
+ struct netr_NETRLOGONSETSERVICEBITS *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_LogonGetTrustRid(pipes_struct *p,
+ struct netr_LogonGetTrustRid *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_NETRLOGONCOMPUTESERVERDIGEST(pipes_struct *p,
+ struct netr_NETRLOGONCOMPUTESERVERDIGEST *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_NETRLOGONCOMPUTECLIENTDIGEST(pipes_struct *p,
+ struct netr_NETRLOGONCOMPUTECLIENTDIGEST *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _netr_ServerAuthenticate3(pipes_struct *p,
+ struct netr_ServerAuthenticate3 *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_DsRGetDCNameEx(pipes_struct *p,
+ struct netr_DsRGetDCNameEx *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_DsRGetSiteName(pipes_struct *p,
+ struct netr_DsRGetSiteName *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _netr_LogonGetDomainInfo(pipes_struct *p,
+ struct netr_LogonGetDomainInfo *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _netr_ServerPasswordSet2(pipes_struct *p,
+ struct netr_ServerPasswordSet2 *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_ServerPasswordGet(pipes_struct *p,
+ struct netr_ServerPasswordGet *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_NETRLOGONSENDTOSAM(pipes_struct *p,
+ struct netr_NETRLOGONSENDTOSAM *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_DsRAddressToSitenamesW(pipes_struct *p,
+ struct netr_DsRAddressToSitenamesW *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_DsRGetDCNameEx2(pipes_struct *p,
+ struct netr_DsRGetDCNameEx2 *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(pipes_struct *p,
+ struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_NetrEnumerateTrustedDomainsEx(pipes_struct *p,
+ struct netr_NetrEnumerateTrustedDomainsEx *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_DsRAddressToSitenamesExW(pipes_struct *p,
+ struct netr_DsRAddressToSitenamesExW *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_DsrGetDcSiteCoverageW(pipes_struct *p,
+ struct netr_DsrGetDcSiteCoverageW *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_DsrEnumerateDomainTrusts(pipes_struct *p,
+ struct netr_DsrEnumerateDomainTrusts *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_DsrDeregisterDNSHostRecords(pipes_struct *p,
+ struct netr_DsrDeregisterDNSHostRecords *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _netr_ServerTrustPasswordsGet(pipes_struct *p,
+ struct netr_ServerTrustPasswordsGet *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_DsRGetForestTrustInformation(pipes_struct *p,
+ struct netr_DsRGetForestTrustInformation *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_GetForestTrustInformation(pipes_struct *p,
+ struct netr_GetForestTrustInformation *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _netr_LogonSamLogonWithFlags(pipes_struct *p,
+ struct netr_LogonSamLogonWithFlags *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_NETRSERVERGETTRUSTINFO(pipes_struct *p,
+ struct netr_NETRSERVERGETTRUSTINFO *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
diff --git a/source3/rpc_server/srv_ntsvcs.c b/source3/rpc_server/srv_ntsvcs.c
new file mode 100644
index 0000000000..100d577010
--- /dev/null
+++ b/source3/rpc_server/srv_ntsvcs.c
@@ -0,0 +1,163 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Gerald Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool proxy_ntsvcs_call(pipes_struct *p, uint8_t opnum)
+{
+ struct api_struct *fns;
+ int n_fns;
+
+ ntsvcs_get_pipe_fns(&fns, &n_fns);
+
+ if (opnum >= n_fns) {
+ return false;
+ }
+
+ if (fns[opnum].opnum != opnum) {
+ smb_panic("NTSVCS function table not sorted");
+ }
+
+ return fns[opnum].fn(p);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_ntsvcs_get_version(pipes_struct *p)
+{
+ return proxy_ntsvcs_call(p, NDR_PNP_GETVERSION);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_ntsvcs_get_device_list_size(pipes_struct *p)
+{
+ return proxy_ntsvcs_call(p, NDR_PNP_GETDEVICELISTSIZE);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_ntsvcs_get_device_list(pipes_struct *p)
+{
+ NTSVCS_Q_GET_DEVICE_LIST q_u;
+ NTSVCS_R_GET_DEVICE_LIST r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!ntsvcs_io_q_get_device_list("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _ntsvcs_get_device_list(p, &q_u, &r_u);
+
+ if(!ntsvcs_io_r_get_device_list("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_ntsvcs_validate_device_instance(pipes_struct *p)
+{
+ return proxy_ntsvcs_call(p, NDR_PNP_VALIDATEDEVICEINSTANCE);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_ntsvcs_get_device_reg_property(pipes_struct *p)
+{
+ NTSVCS_Q_GET_DEVICE_REG_PROPERTY q_u;
+ NTSVCS_R_GET_DEVICE_REG_PROPERTY r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!ntsvcs_io_q_get_device_reg_property("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _ntsvcs_get_device_reg_property(p, &q_u, &r_u);
+
+ if(!ntsvcs_io_r_get_device_reg_property("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_ntsvcs_get_hw_profile_info(pipes_struct *p)
+{
+ return proxy_ntsvcs_call(p, NDR_PNP_GETHWPROFINFO);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_ntsvcs_hw_profile_flags(pipes_struct *p)
+{
+ return proxy_ntsvcs_call(p, NDR_PNP_HWPROFFLAGS);
+}
+
+/*******************************************************************
+ \PIPE\svcctl commands
+ ********************************************************************/
+
+static struct api_struct api_ntsvcs_cmds[] =
+{
+ { "NTSVCS_GET_VERSION" , NTSVCS_GET_VERSION , api_ntsvcs_get_version },
+ { "NTSVCS_GET_DEVICE_LIST_SIZE" , NTSVCS_GET_DEVICE_LIST_SIZE , api_ntsvcs_get_device_list_size },
+ { "NTSVCS_GET_DEVICE_LIST" , NTSVCS_GET_DEVICE_LIST , api_ntsvcs_get_device_list },
+ { "NTSVCS_VALIDATE_DEVICE_INSTANCE" , NTSVCS_VALIDATE_DEVICE_INSTANCE , api_ntsvcs_validate_device_instance },
+ { "NTSVCS_GET_DEVICE_REG_PROPERTY" , NTSVCS_GET_DEVICE_REG_PROPERTY , api_ntsvcs_get_device_reg_property },
+ { "NTSVCS_GET_HW_PROFILE_INFO" , NTSVCS_GET_HW_PROFILE_INFO , api_ntsvcs_get_hw_profile_info },
+ { "NTSVCS_HW_PROFILE_FLAGS" , NTSVCS_HW_PROFILE_FLAGS , api_ntsvcs_hw_profile_flags }
+};
+
+
+void ntsvcs2_get_pipe_fns( struct api_struct **fns, int *n_fns )
+{
+ *fns = api_ntsvcs_cmds;
+ *n_fns = sizeof(api_ntsvcs_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_ntsvcs2_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION,
+ "ntsvcs", "ntsvcs",
+ &ndr_table_ntsvcs.syntax_id,
+ api_ntsvcs_cmds,
+ sizeof(api_ntsvcs_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/rpc_server/srv_ntsvcs_nt.c b/source3/rpc_server/srv_ntsvcs_nt.c
new file mode 100644
index 0000000000..268da52896
--- /dev/null
+++ b/source3/rpc_server/srv_ntsvcs_nt.c
@@ -0,0 +1,778 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ *
+ * Copyright (C) Gerald (Jerry) Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+/********************************************************************
+********************************************************************/
+
+static char* get_device_path(TALLOC_CTX *mem_ctx, const char *device )
+{
+ return talloc_asprintf(mem_ctx, "ROOT\\Legacy_%s\\0000", device);
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _PNP_GetVersion(pipes_struct *p,
+ struct PNP_GetVersion *r)
+{
+ *r->out.version = 0x0400; /* no idea what this means */
+
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _PNP_GetDeviceListSize(pipes_struct *p,
+ struct PNP_GetDeviceListSize *r)
+{
+ char *devicepath;
+
+ if (!r->in.devicename) {
+ return WERR_ACCESS_DENIED;
+ }
+
+ if (!(devicepath = get_device_path(p->mem_ctx, r->in.devicename))) {
+ return WERR_NOMEM;
+ }
+
+ *r->out.size = strlen(devicepath) + 2;
+
+ TALLOC_FREE(devicepath);
+
+ return WERR_OK;
+}
+
+
+/********************************************************************
+********************************************************************/
+
+WERROR _ntsvcs_get_device_list( pipes_struct *p, NTSVCS_Q_GET_DEVICE_LIST *q_u, NTSVCS_R_GET_DEVICE_LIST *r_u )
+{
+ fstring device;
+ char *devicepath;
+
+ if ( !q_u->devicename )
+ return WERR_ACCESS_DENIED;
+
+ rpcstr_pull(device, q_u->devicename->buffer, sizeof(device), q_u->devicename->uni_str_len*2, 0);
+
+ if (!(devicepath = get_device_path(p->mem_ctx, device))) {
+ return WERR_NOMEM;
+ }
+
+ /* This has to be DOUBLE NULL terminated */
+
+ init_unistr2( &r_u->devicepath, devicepath, UNI_STR_DBLTERMINATE );
+ TALLOC_FREE(devicepath);
+ r_u->needed = r_u->devicepath.uni_str_len;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _ntsvcs_get_device_reg_property( pipes_struct *p, NTSVCS_Q_GET_DEVICE_REG_PROPERTY *q_u, NTSVCS_R_GET_DEVICE_REG_PROPERTY *r_u )
+{
+ fstring devicepath;
+ char *ptr;
+ REGVAL_CTR *values;
+ REGISTRY_VALUE *val;
+
+ rpcstr_pull(devicepath, q_u->devicepath.buffer, sizeof(devicepath), q_u->devicepath.uni_str_len*2, 0);
+
+ switch( q_u->property ) {
+ case DEV_REGPROP_DESC:
+ /* just parse the service name from the device path and then
+ lookup the display name */
+ if ( !(ptr = strrchr_m( devicepath, '\\' )) )
+ return WERR_GENERAL_FAILURE;
+ *ptr = '\0';
+
+ if ( !(ptr = strrchr_m( devicepath, '_' )) )
+ return WERR_GENERAL_FAILURE;
+ ptr++;
+
+ if ( !(values = svcctl_fetch_regvalues( ptr, p->pipe_user.nt_user_token )) )
+ return WERR_GENERAL_FAILURE;
+
+ if ( !(val = regval_ctr_getvalue( values, "DisplayName" )) ) {
+ TALLOC_FREE( values );
+ return WERR_GENERAL_FAILURE;
+ }
+
+ r_u->unknown1 = 0x1; /* always 1...tested using a remove device manager connection */
+ r_u->size = reg_init_regval_buffer( &r_u->value, val );
+ r_u->needed = r_u->size;
+
+ TALLOC_FREE(values);
+
+ break;
+
+ default:
+ r_u->unknown1 = 0x00437c98;
+ return WERR_CM_NO_SUCH_VALUE;
+ }
+
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _PNP_ValidateDeviceInstance(pipes_struct *p,
+ struct PNP_ValidateDeviceInstance *r)
+{
+ /* whatever dude */
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _PNP_GetHwProfInfo(pipes_struct *p,
+ struct PNP_GetHwProfInfo *r)
+{
+ /* steal the incoming buffer */
+
+ r->out.info = r->in.info;
+
+ /* Take the 5th Ammentment */
+
+ return WERR_CM_NO_MORE_HW_PROFILES;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _PNP_HwProfFlags(pipes_struct *p,
+ struct PNP_HwProfFlags *r)
+{
+ /* just nod your head */
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_Disconnect(pipes_struct *p,
+ struct PNP_Disconnect *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_Connect(pipes_struct *p,
+ struct PNP_Connect *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetGlobalState(pipes_struct *p,
+ struct PNP_GetGlobalState *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_InitDetection(pipes_struct *p,
+ struct PNP_InitDetection *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_ReportLogOn(pipes_struct *p,
+ struct PNP_ReportLogOn *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetRootDeviceInstance(pipes_struct *p,
+ struct PNP_GetRootDeviceInstance *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetRelatedDeviceInstance(pipes_struct *p,
+ struct PNP_GetRelatedDeviceInstance *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_EnumerateSubKeys(pipes_struct *p,
+ struct PNP_EnumerateSubKeys *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetDeviceList(pipes_struct *p,
+ struct PNP_GetDeviceList *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetDepth(pipes_struct *p,
+ struct PNP_GetDepth *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetDeviceRegProp(pipes_struct *p,
+ struct PNP_GetDeviceRegProp *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_SetDeviceRegProp(pipes_struct *p,
+ struct PNP_SetDeviceRegProp *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetClassInstance(pipes_struct *p,
+ struct PNP_GetClassInstance *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_CreateKey(pipes_struct *p,
+ struct PNP_CreateKey *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_DeleteRegistryKey(pipes_struct *p,
+ struct PNP_DeleteRegistryKey *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetClassCount(pipes_struct *p,
+ struct PNP_GetClassCount *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetClassName(pipes_struct *p,
+ struct PNP_GetClassName *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_DeleteClassKey(pipes_struct *p,
+ struct PNP_DeleteClassKey *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetInterfaceDeviceAlias(pipes_struct *p,
+ struct PNP_GetInterfaceDeviceAlias *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetInterfaceDeviceList(pipes_struct *p,
+ struct PNP_GetInterfaceDeviceList *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetInterfaceDeviceListSize(pipes_struct *p,
+ struct PNP_GetInterfaceDeviceListSize *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_RegisterDeviceClassAssociation(pipes_struct *p,
+ struct PNP_RegisterDeviceClassAssociation *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_UnregisterDeviceClassAssociation(pipes_struct *p,
+ struct PNP_UnregisterDeviceClassAssociation *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetClassRegProp(pipes_struct *p,
+ struct PNP_GetClassRegProp *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_SetClassRegProp(pipes_struct *p,
+ struct PNP_SetClassRegProp *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_CreateDevInst(pipes_struct *p,
+ struct PNP_CreateDevInst *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_DeviceInstanceAction(pipes_struct *p,
+ struct PNP_DeviceInstanceAction *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetDeviceStatus(pipes_struct *p,
+ struct PNP_GetDeviceStatus *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_SetDeviceProblem(pipes_struct *p,
+ struct PNP_SetDeviceProblem *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_DisableDevInst(pipes_struct *p,
+ struct PNP_DisableDevInst *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_UninstallDevInst(pipes_struct *p,
+ struct PNP_UninstallDevInst *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_AddID(pipes_struct *p,
+ struct PNP_AddID *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_RegisterDriver(pipes_struct *p,
+ struct PNP_RegisterDriver *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_QueryRemove(pipes_struct *p,
+ struct PNP_QueryRemove *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_RequestDeviceEject(pipes_struct *p,
+ struct PNP_RequestDeviceEject *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_IsDockStationPresent(pipes_struct *p,
+ struct PNP_IsDockStationPresent *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_RequestEjectPC(pipes_struct *p,
+ struct PNP_RequestEjectPC *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_AddEmptyLogConf(pipes_struct *p,
+ struct PNP_AddEmptyLogConf *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_FreeLogConf(pipes_struct *p,
+ struct PNP_FreeLogConf *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetFirstLogConf(pipes_struct *p,
+ struct PNP_GetFirstLogConf *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetNextLogConf(pipes_struct *p,
+ struct PNP_GetNextLogConf *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetLogConfPriority(pipes_struct *p,
+ struct PNP_GetLogConfPriority *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_AddResDes(pipes_struct *p,
+ struct PNP_AddResDes *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_FreeResDes(pipes_struct *p,
+ struct PNP_FreeResDes *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetNextResDes(pipes_struct *p,
+ struct PNP_GetNextResDes *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetResDesData(pipes_struct *p,
+ struct PNP_GetResDesData *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetResDesDataSize(pipes_struct *p,
+ struct PNP_GetResDesDataSize *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_ModifyResDes(pipes_struct *p,
+ struct PNP_ModifyResDes *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_DetectResourceLimit(pipes_struct *p,
+ struct PNP_DetectResourceLimit *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_QueryResConfList(pipes_struct *p,
+ struct PNP_QueryResConfList *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_SetHwProf(pipes_struct *p,
+ struct PNP_SetHwProf *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_QueryArbitratorFreeData(pipes_struct *p,
+ struct PNP_QueryArbitratorFreeData *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_QueryArbitratorFreeSize(pipes_struct *p,
+ struct PNP_QueryArbitratorFreeSize *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_RunDetection(pipes_struct *p,
+ struct PNP_RunDetection *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_RegisterNotification(pipes_struct *p,
+ struct PNP_RegisterNotification *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_UnregisterNotification(pipes_struct *p,
+ struct PNP_UnregisterNotification *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetCustomDevProp(pipes_struct *p,
+ struct PNP_GetCustomDevProp *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetVersionInternal(pipes_struct *p,
+ struct PNP_GetVersionInternal *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetBlockedDriverInfo(pipes_struct *p,
+ struct PNP_GetBlockedDriverInfo *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR _PNP_GetServerSideDeviceInstallFlags(pipes_struct *p,
+ struct PNP_GetServerSideDeviceInstallFlags *r)
+{
+ p->rng_fault_state = true;
+ return WERR_NOT_SUPPORTED;
+}
+
diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c
new file mode 100644
index 0000000000..be7d3db444
--- /dev/null
+++ b/source3/rpc_server/srv_pipe.c
@@ -0,0 +1,2419 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Almost completely rewritten by (C) Jeremy Allison 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* 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.
+ *
+ */
+
+#include "includes.h"
+
+extern struct current_user current_user;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+static void free_pipe_ntlmssp_auth_data(struct pipe_auth_data *auth)
+{
+ AUTH_NTLMSSP_STATE *a = auth->a_u.auth_ntlmssp_state;
+
+ if (a) {
+ auth_ntlmssp_end(&a);
+ }
+ auth->a_u.auth_ntlmssp_state = NULL;
+}
+
+static DATA_BLOB generic_session_key(void)
+{
+ return data_blob("SystemLibraryDTC", 16);
+}
+
+/*******************************************************************
+ Generate the next PDU to be returned from the data in p->rdata.
+ Handle NTLMSSP.
+ ********************************************************************/
+
+static bool create_next_pdu_ntlmssp(pipes_struct *p)
+{
+ RPC_HDR_RESP hdr_resp;
+ uint32 ss_padding_len = 0;
+ uint32 data_space_available;
+ uint32 data_len_left;
+ uint32 data_len;
+ prs_struct outgoing_pdu;
+ NTSTATUS status;
+ DATA_BLOB auth_blob;
+ RPC_HDR_AUTH auth_info;
+ uint8 auth_type, auth_level;
+ AUTH_NTLMSSP_STATE *a = p->auth.a_u.auth_ntlmssp_state;
+
+ /*
+ * If we're in the fault state, keep returning fault PDU's until
+ * the pipe gets closed. JRA.
+ */
+
+ if(p->fault_state) {
+ setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR));
+ return True;
+ }
+
+ memset((char *)&hdr_resp, '\0', sizeof(hdr_resp));
+
+ /* Change the incoming request header to a response. */
+ p->hdr.pkt_type = RPC_RESPONSE;
+
+ /* Set up rpc header flags. */
+ if (p->out_data.data_sent_length == 0) {
+ p->hdr.flags = RPC_FLG_FIRST;
+ } else {
+ p->hdr.flags = 0;
+ }
+
+ /*
+ * Work out how much we can fit in a single PDU.
+ */
+
+ data_len_left = prs_offset(&p->out_data.rdata) - p->out_data.data_sent_length;
+
+ /*
+ * Ensure there really is data left to send.
+ */
+
+ if(!data_len_left) {
+ DEBUG(0,("create_next_pdu_ntlmssp: no data left to send !\n"));
+ return False;
+ }
+
+ data_space_available = sizeof(p->out_data.current_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN -
+ RPC_HDR_AUTH_LEN - NTLMSSP_SIG_SIZE;
+
+ /*
+ * The amount we send is the minimum of the available
+ * space and the amount left to send.
+ */
+
+ data_len = MIN(data_len_left, data_space_available);
+
+ /*
+ * Set up the alloc hint. This should be the data left to
+ * send.
+ */
+
+ hdr_resp.alloc_hint = data_len_left;
+
+ /*
+ * Work out if this PDU will be the last.
+ */
+
+ if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata)) {
+ p->hdr.flags |= RPC_FLG_LAST;
+ if (data_len_left % 8) {
+ ss_padding_len = 8 - (data_len_left % 8);
+ DEBUG(10,("create_next_pdu_ntlmssp: adding sign/seal padding of %u\n",
+ ss_padding_len ));
+ }
+ }
+
+ /*
+ * Set up the header lengths.
+ */
+
+ p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN +
+ data_len + ss_padding_len +
+ RPC_HDR_AUTH_LEN + NTLMSSP_SIG_SIZE;
+ p->hdr.auth_len = NTLMSSP_SIG_SIZE;
+
+
+ /*
+ * Init the parse struct to point at the outgoing
+ * data.
+ */
+
+ prs_init_empty( &outgoing_pdu, p->mem_ctx, MARSHALL);
+ prs_give_memory( &outgoing_pdu, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
+
+ /* Store the header in the data stream. */
+ if(!smb_io_rpc_hdr("hdr", &p->hdr, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu_ntlmssp: failed to marshall RPC_HDR.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu_ntlmssp: failed to marshall RPC_HDR_RESP.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ /* Copy the data into the PDU. */
+
+ if(!prs_append_some_prs_data(&outgoing_pdu, &p->out_data.rdata, p->out_data.data_sent_length, data_len)) {
+ DEBUG(0,("create_next_pdu_ntlmssp: failed to copy %u bytes of data.\n", (unsigned int)data_len));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ /* Copy the sign/seal padding data. */
+ if (ss_padding_len) {
+ char pad[8];
+
+ memset(pad, '\0', 8);
+ if (!prs_copy_data_in(&outgoing_pdu, pad, ss_padding_len)) {
+ DEBUG(0,("create_next_pdu_ntlmssp: failed to add %u bytes of pad data.\n",
+ (unsigned int)ss_padding_len));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+ }
+
+
+ /* Now write out the auth header and null blob. */
+ if (p->auth.auth_type == PIPE_AUTH_TYPE_NTLMSSP) {
+ auth_type = RPC_NTLMSSP_AUTH_TYPE;
+ } else {
+ auth_type = RPC_SPNEGO_AUTH_TYPE;
+ }
+ if (p->auth.auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
+ auth_level = RPC_AUTH_LEVEL_PRIVACY;
+ } else {
+ auth_level = RPC_AUTH_LEVEL_INTEGRITY;
+ }
+
+ init_rpc_hdr_auth(&auth_info, auth_type, auth_level, ss_padding_len, 1 /* context id. */);
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu_ntlmssp: failed to marshall RPC_HDR_AUTH.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ /* Generate the sign blob. */
+
+ switch (p->auth.auth_level) {
+ case PIPE_AUTH_LEVEL_PRIVACY:
+ /* Data portion is encrypted. */
+ status = ntlmssp_seal_packet(a->ntlmssp_state,
+ (unsigned char *)prs_data_p(&outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN,
+ data_len + ss_padding_len,
+ (unsigned char *)prs_data_p(&outgoing_pdu),
+ (size_t)prs_offset(&outgoing_pdu),
+ &auth_blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ data_blob_free(&auth_blob);
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+ break;
+ case PIPE_AUTH_LEVEL_INTEGRITY:
+ /* Data is signed. */
+ status = ntlmssp_sign_packet(a->ntlmssp_state,
+ (unsigned char *)prs_data_p(&outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN,
+ data_len + ss_padding_len,
+ (unsigned char *)prs_data_p(&outgoing_pdu),
+ (size_t)prs_offset(&outgoing_pdu),
+ &auth_blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ data_blob_free(&auth_blob);
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+ break;
+ default:
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ /* Append the auth blob. */
+ if (!prs_copy_data_in(&outgoing_pdu, (char *)auth_blob.data, NTLMSSP_SIG_SIZE)) {
+ DEBUG(0,("create_next_pdu_ntlmssp: failed to add %u bytes auth blob.\n",
+ (unsigned int)NTLMSSP_SIG_SIZE));
+ data_blob_free(&auth_blob);
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ data_blob_free(&auth_blob);
+
+ /*
+ * Setup the counts for this PDU.
+ */
+
+ p->out_data.data_sent_length += data_len;
+ p->out_data.current_pdu_len = p->hdr.frag_len;
+ p->out_data.current_pdu_sent = 0;
+
+ prs_mem_free(&outgoing_pdu);
+ return True;
+}
+
+/*******************************************************************
+ Generate the next PDU to be returned from the data in p->rdata.
+ Return an schannel authenticated fragment.
+ ********************************************************************/
+
+static bool create_next_pdu_schannel(pipes_struct *p)
+{
+ RPC_HDR_RESP hdr_resp;
+ uint32 ss_padding_len = 0;
+ uint32 data_len;
+ uint32 data_space_available;
+ uint32 data_len_left;
+ prs_struct outgoing_pdu;
+ uint32 data_pos;
+
+ /*
+ * If we're in the fault state, keep returning fault PDU's until
+ * the pipe gets closed. JRA.
+ */
+
+ if(p->fault_state) {
+ setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR));
+ return True;
+ }
+
+ memset((char *)&hdr_resp, '\0', sizeof(hdr_resp));
+
+ /* Change the incoming request header to a response. */
+ p->hdr.pkt_type = RPC_RESPONSE;
+
+ /* Set up rpc header flags. */
+ if (p->out_data.data_sent_length == 0) {
+ p->hdr.flags = RPC_FLG_FIRST;
+ } else {
+ p->hdr.flags = 0;
+ }
+
+ /*
+ * Work out how much we can fit in a single PDU.
+ */
+
+ data_len_left = prs_offset(&p->out_data.rdata) - p->out_data.data_sent_length;
+
+ /*
+ * Ensure there really is data left to send.
+ */
+
+ if(!data_len_left) {
+ DEBUG(0,("create_next_pdu_schannel: no data left to send !\n"));
+ return False;
+ }
+
+ data_space_available = sizeof(p->out_data.current_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN -
+ RPC_HDR_AUTH_LEN - RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN;
+
+ /*
+ * The amount we send is the minimum of the available
+ * space and the amount left to send.
+ */
+
+ data_len = MIN(data_len_left, data_space_available);
+
+ /*
+ * Set up the alloc hint. This should be the data left to
+ * send.
+ */
+
+ hdr_resp.alloc_hint = data_len_left;
+
+ /*
+ * Work out if this PDU will be the last.
+ */
+
+ if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata)) {
+ p->hdr.flags |= RPC_FLG_LAST;
+ if (data_len_left % 8) {
+ ss_padding_len = 8 - (data_len_left % 8);
+ DEBUG(10,("create_next_pdu_schannel: adding sign/seal padding of %u\n",
+ ss_padding_len ));
+ }
+ }
+
+ p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len + ss_padding_len +
+ RPC_HDR_AUTH_LEN + RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN;
+ p->hdr.auth_len = RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN;
+
+ /*
+ * Init the parse struct to point at the outgoing
+ * data.
+ */
+
+ prs_init_empty( &outgoing_pdu, p->mem_ctx, MARSHALL);
+ prs_give_memory( &outgoing_pdu, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
+
+ /* Store the header in the data stream. */
+ if(!smb_io_rpc_hdr("hdr", &p->hdr, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu_schannel: failed to marshall RPC_HDR.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu_schannel: failed to marshall RPC_HDR_RESP.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ /* Store the current offset. */
+ data_pos = prs_offset(&outgoing_pdu);
+
+ /* Copy the data into the PDU. */
+
+ if(!prs_append_some_prs_data(&outgoing_pdu, &p->out_data.rdata, p->out_data.data_sent_length, data_len)) {
+ DEBUG(0,("create_next_pdu_schannel: failed to copy %u bytes of data.\n", (unsigned int)data_len));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ /* Copy the sign/seal padding data. */
+ if (ss_padding_len) {
+ char pad[8];
+ memset(pad, '\0', 8);
+ if (!prs_copy_data_in(&outgoing_pdu, pad, ss_padding_len)) {
+ DEBUG(0,("create_next_pdu_schannel: failed to add %u bytes of pad data.\n", (unsigned int)ss_padding_len));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+ }
+
+ {
+ /*
+ * Schannel processing.
+ */
+ char *data;
+ RPC_HDR_AUTH auth_info;
+ RPC_AUTH_SCHANNEL_CHK verf;
+
+ data = prs_data_p(&outgoing_pdu) + data_pos;
+ /* Check it's the type of reply we were expecting to decode */
+
+ init_rpc_hdr_auth(&auth_info,
+ RPC_SCHANNEL_AUTH_TYPE,
+ p->auth.auth_level == PIPE_AUTH_LEVEL_PRIVACY ?
+ RPC_AUTH_LEVEL_PRIVACY : RPC_AUTH_LEVEL_INTEGRITY,
+ ss_padding_len, 1);
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu_schannel: failed to marshall RPC_HDR_AUTH.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ schannel_encode(p->auth.a_u.schannel_auth,
+ p->auth.auth_level,
+ SENDER_IS_ACCEPTOR,
+ &verf, data, data_len + ss_padding_len);
+
+ if (!smb_io_rpc_auth_schannel_chk("", RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN,
+ &verf, &outgoing_pdu, 0)) {
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ p->auth.a_u.schannel_auth->seq_num++;
+ }
+
+ /*
+ * Setup the counts for this PDU.
+ */
+
+ p->out_data.data_sent_length += data_len;
+ p->out_data.current_pdu_len = p->hdr.frag_len;
+ p->out_data.current_pdu_sent = 0;
+
+ prs_mem_free(&outgoing_pdu);
+ return True;
+}
+
+/*******************************************************************
+ Generate the next PDU to be returned from the data in p->rdata.
+ No authentication done.
+********************************************************************/
+
+static bool create_next_pdu_noauth(pipes_struct *p)
+{
+ RPC_HDR_RESP hdr_resp;
+ uint32 data_len;
+ uint32 data_space_available;
+ uint32 data_len_left;
+ prs_struct outgoing_pdu;
+
+ /*
+ * If we're in the fault state, keep returning fault PDU's until
+ * the pipe gets closed. JRA.
+ */
+
+ if(p->fault_state) {
+ setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR));
+ return True;
+ }
+
+ memset((char *)&hdr_resp, '\0', sizeof(hdr_resp));
+
+ /* Change the incoming request header to a response. */
+ p->hdr.pkt_type = RPC_RESPONSE;
+
+ /* Set up rpc header flags. */
+ if (p->out_data.data_sent_length == 0) {
+ p->hdr.flags = RPC_FLG_FIRST;
+ } else {
+ p->hdr.flags = 0;
+ }
+
+ /*
+ * Work out how much we can fit in a single PDU.
+ */
+
+ data_len_left = prs_offset(&p->out_data.rdata) - p->out_data.data_sent_length;
+
+ /*
+ * Ensure there really is data left to send.
+ */
+
+ if(!data_len_left) {
+ DEBUG(0,("create_next_pdu_noath: no data left to send !\n"));
+ return False;
+ }
+
+ data_space_available = sizeof(p->out_data.current_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN;
+
+ /*
+ * The amount we send is the minimum of the available
+ * space and the amount left to send.
+ */
+
+ data_len = MIN(data_len_left, data_space_available);
+
+ /*
+ * Set up the alloc hint. This should be the data left to
+ * send.
+ */
+
+ hdr_resp.alloc_hint = data_len_left;
+
+ /*
+ * Work out if this PDU will be the last.
+ */
+
+ if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata)) {
+ p->hdr.flags |= RPC_FLG_LAST;
+ }
+
+ /*
+ * Set up the header lengths.
+ */
+
+ p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len;
+ p->hdr.auth_len = 0;
+
+ /*
+ * Init the parse struct to point at the outgoing
+ * data.
+ */
+
+ prs_init_empty( &outgoing_pdu, p->mem_ctx, MARSHALL);
+ prs_give_memory( &outgoing_pdu, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
+
+ /* Store the header in the data stream. */
+ if(!smb_io_rpc_hdr("hdr", &p->hdr, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu_noath: failed to marshall RPC_HDR.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu_noath: failed to marshall RPC_HDR_RESP.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ /* Copy the data into the PDU. */
+
+ if(!prs_append_some_prs_data(&outgoing_pdu, &p->out_data.rdata, p->out_data.data_sent_length, data_len)) {
+ DEBUG(0,("create_next_pdu_noauth: failed to copy %u bytes of data.\n", (unsigned int)data_len));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ /*
+ * Setup the counts for this PDU.
+ */
+
+ p->out_data.data_sent_length += data_len;
+ p->out_data.current_pdu_len = p->hdr.frag_len;
+ p->out_data.current_pdu_sent = 0;
+
+ prs_mem_free(&outgoing_pdu);
+ return True;
+}
+
+/*******************************************************************
+ Generate the next PDU to be returned from the data in p->rdata.
+********************************************************************/
+
+bool create_next_pdu(pipes_struct *p)
+{
+ switch(p->auth.auth_level) {
+ case PIPE_AUTH_LEVEL_NONE:
+ case PIPE_AUTH_LEVEL_CONNECT:
+ /* This is incorrect for auth level connect. Fixme. JRA */
+ return create_next_pdu_noauth(p);
+
+ default:
+ switch(p->auth.auth_type) {
+ case PIPE_AUTH_TYPE_NTLMSSP:
+ case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP:
+ return create_next_pdu_ntlmssp(p);
+ case PIPE_AUTH_TYPE_SCHANNEL:
+ return create_next_pdu_schannel(p);
+ default:
+ break;
+ }
+ }
+
+ DEBUG(0,("create_next_pdu: invalid internal auth level %u / type %u",
+ (unsigned int)p->auth.auth_level,
+ (unsigned int)p->auth.auth_type));
+ return False;
+}
+
+/*******************************************************************
+ Process an NTLMSSP authentication response.
+ If this function succeeds, the user has been authenticated
+ and their domain, name and calling workstation stored in
+ the pipe struct.
+*******************************************************************/
+
+static bool pipe_ntlmssp_verify_final(pipes_struct *p, DATA_BLOB *p_resp_blob)
+{
+ DATA_BLOB session_key, reply;
+ NTSTATUS status;
+ AUTH_NTLMSSP_STATE *a = p->auth.a_u.auth_ntlmssp_state;
+ bool ret;
+
+ DEBUG(5,("pipe_ntlmssp_verify_final: pipe %s checking user details\n", p->name));
+
+ ZERO_STRUCT(reply);
+
+ /* Set up for non-authenticated user. */
+ TALLOC_FREE(p->pipe_user.nt_user_token);
+ p->pipe_user.ut.ngroups = 0;
+ SAFE_FREE( p->pipe_user.ut.groups);
+
+ /* this has to be done as root in order to verify the password */
+ become_root();
+ status = auth_ntlmssp_update(a, *p_resp_blob, &reply);
+ unbecome_root();
+
+ /* Don't generate a reply. */
+ data_blob_free(&reply);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ /* Finally - if the pipe negotiated integrity (sign) or privacy (seal)
+ ensure the underlying NTLMSSP flags are also set. If not we should
+ refuse the bind. */
+
+ if (p->auth.auth_level == PIPE_AUTH_LEVEL_INTEGRITY) {
+ if (!(a->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN)) {
+ DEBUG(0,("pipe_ntlmssp_verify_final: pipe %s : packet integrity requested "
+ "but client declined signing.\n",
+ p->name ));
+ return False;
+ }
+ }
+ if (p->auth.auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
+ if (!(a->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL)) {
+ DEBUG(0,("pipe_ntlmssp_verify_final: pipe %s : packet privacy requested "
+ "but client declined sealing.\n",
+ p->name ));
+ return False;
+ }
+ }
+
+ DEBUG(5, ("pipe_ntlmssp_verify_final: OK: user: %s domain: %s "
+ "workstation: %s\n", a->ntlmssp_state->user,
+ a->ntlmssp_state->domain, a->ntlmssp_state->workstation));
+
+ /*
+ * Store the UNIX credential data (uid/gid pair) in the pipe structure.
+ */
+
+ p->pipe_user.ut.uid = a->server_info->utok.uid;
+ p->pipe_user.ut.gid = a->server_info->utok.gid;
+
+ p->pipe_user.ut.ngroups = a->server_info->utok.ngroups;
+ if (p->pipe_user.ut.ngroups) {
+ if (!(p->pipe_user.ut.groups = (gid_t *)memdup(
+ a->server_info->utok.groups,
+ sizeof(gid_t) * p->pipe_user.ut.ngroups))) {
+ DEBUG(0,("failed to memdup group list to p->pipe_user.groups\n"));
+ return False;
+ }
+ }
+
+ if (a->server_info->ptok) {
+ p->pipe_user.nt_user_token =
+ dup_nt_token(NULL, a->server_info->ptok);
+ } else {
+ DEBUG(1,("Error: Authmodule failed to provide nt_user_token\n"));
+ p->pipe_user.nt_user_token = NULL;
+ return False;
+ }
+
+ TALLOC_FREE(p->server_info);
+
+ p->server_info = copy_serverinfo(p, a->server_info);
+ if (p->server_info == NULL) {
+ DEBUG(0, ("copy_serverinfo failed\n"));
+ return false;
+ }
+
+ /*
+ * We're an authenticated bind over smb, so the session key needs to
+ * be set to "SystemLibraryDTC". Weird, but this is what Windows
+ * does. See the RPC-SAMBA3SESSIONKEY.
+ */
+
+ session_key = generic_session_key();
+ if (session_key.data == NULL) {
+ return False;
+ }
+
+ ret = server_info_set_session_key(p->server_info, session_key);
+
+ data_blob_free(&session_key);
+
+ return True;
+}
+
+/*******************************************************************
+ The switch table for the pipe names and the functions to handle them.
+*******************************************************************/
+
+struct rpc_table {
+ struct {
+ const char *clnt;
+ const char *srv;
+ } pipe;
+ struct ndr_syntax_id rpc_interface;
+ const struct api_struct *cmds;
+ int n_cmds;
+};
+
+static struct rpc_table *rpc_lookup;
+static int rpc_lookup_size;
+
+/*******************************************************************
+ This is the "stage3" NTLMSSP response after a bind request and reply.
+*******************************************************************/
+
+bool api_pipe_bind_auth3(pipes_struct *p, prs_struct *rpc_in_p)
+{
+ RPC_HDR_AUTH auth_info;
+ uint32 pad;
+ DATA_BLOB blob;
+
+ ZERO_STRUCT(blob);
+
+ DEBUG(5,("api_pipe_bind_auth3: decode request. %d\n", __LINE__));
+
+ if (p->hdr.auth_len == 0) {
+ DEBUG(0,("api_pipe_bind_auth3: No auth field sent !\n"));
+ goto err;
+ }
+
+ /* 4 bytes padding. */
+ if (!prs_uint32("pad", rpc_in_p, 0, &pad)) {
+ DEBUG(0,("api_pipe_bind_auth3: unmarshall of 4 byte pad failed.\n"));
+ goto err;
+ }
+
+ /*
+ * Decode the authentication verifier response.
+ */
+
+ if(!smb_io_rpc_hdr_auth("", &auth_info, rpc_in_p, 0)) {
+ DEBUG(0,("api_pipe_bind_auth3: unmarshall of RPC_HDR_AUTH failed.\n"));
+ goto err;
+ }
+
+ if (auth_info.auth_type != RPC_NTLMSSP_AUTH_TYPE) {
+ DEBUG(0,("api_pipe_bind_auth3: incorrect auth type (%u).\n",
+ (unsigned int)auth_info.auth_type ));
+ return False;
+ }
+
+ blob = data_blob(NULL,p->hdr.auth_len);
+
+ if (!prs_copy_data_out((char *)blob.data, rpc_in_p, p->hdr.auth_len)) {
+ DEBUG(0,("api_pipe_bind_auth3: Failed to pull %u bytes - the response blob.\n",
+ (unsigned int)p->hdr.auth_len ));
+ goto err;
+ }
+
+ /*
+ * The following call actually checks the challenge/response data.
+ * for correctness against the given DOMAIN\user name.
+ */
+
+ if (!pipe_ntlmssp_verify_final(p, &blob)) {
+ goto err;
+ }
+
+ data_blob_free(&blob);
+
+ p->pipe_bound = True;
+
+ return True;
+
+ err:
+
+ data_blob_free(&blob);
+ free_pipe_ntlmssp_auth_data(&p->auth);
+ p->auth.a_u.auth_ntlmssp_state = NULL;
+
+ return False;
+}
+
+/*******************************************************************
+ Marshall a bind_nak pdu.
+*******************************************************************/
+
+static bool setup_bind_nak(pipes_struct *p)
+{
+ prs_struct outgoing_rpc;
+ RPC_HDR nak_hdr;
+ uint16 zero = 0;
+
+ /* Free any memory in the current return data buffer. */
+ prs_mem_free(&p->out_data.rdata);
+
+ /*
+ * Marshall directly into the outgoing PDU space. We
+ * must do this as we need to set to the bind response
+ * header and are never sending more than one PDU here.
+ */
+
+ prs_init_empty( &outgoing_rpc, p->mem_ctx, MARSHALL);
+ prs_give_memory( &outgoing_rpc, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
+
+ /*
+ * Initialize a bind_nak header.
+ */
+
+ init_rpc_hdr(&nak_hdr, RPC_BINDNACK, RPC_FLG_FIRST | RPC_FLG_LAST,
+ p->hdr.call_id, RPC_HEADER_LEN + sizeof(uint16), 0);
+
+ /*
+ * Marshall the header into the outgoing PDU.
+ */
+
+ if(!smb_io_rpc_hdr("", &nak_hdr, &outgoing_rpc, 0)) {
+ DEBUG(0,("setup_bind_nak: marshalling of RPC_HDR failed.\n"));
+ prs_mem_free(&outgoing_rpc);
+ return False;
+ }
+
+ /*
+ * Now add the reject reason.
+ */
+
+ if(!prs_uint16("reject code", &outgoing_rpc, 0, &zero)) {
+ prs_mem_free(&outgoing_rpc);
+ return False;
+ }
+
+ p->out_data.data_sent_length = 0;
+ p->out_data.current_pdu_len = prs_offset(&outgoing_rpc);
+ p->out_data.current_pdu_sent = 0;
+
+ if (p->auth.auth_data_free_func) {
+ (*p->auth.auth_data_free_func)(&p->auth);
+ }
+ p->auth.auth_level = PIPE_AUTH_LEVEL_NONE;
+ p->auth.auth_type = PIPE_AUTH_TYPE_NONE;
+ p->pipe_bound = False;
+
+ return True;
+}
+
+/*******************************************************************
+ Marshall a fault pdu.
+*******************************************************************/
+
+bool setup_fault_pdu(pipes_struct *p, NTSTATUS status)
+{
+ prs_struct outgoing_pdu;
+ RPC_HDR fault_hdr;
+ RPC_HDR_RESP hdr_resp;
+ RPC_HDR_FAULT fault_resp;
+
+ /* Free any memory in the current return data buffer. */
+ prs_mem_free(&p->out_data.rdata);
+
+ /*
+ * Marshall directly into the outgoing PDU space. We
+ * must do this as we need to set to the bind response
+ * header and are never sending more than one PDU here.
+ */
+
+ prs_init_empty( &outgoing_pdu, p->mem_ctx, MARSHALL);
+ prs_give_memory( &outgoing_pdu, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
+
+ /*
+ * Initialize a fault header.
+ */
+
+ init_rpc_hdr(&fault_hdr, RPC_FAULT, RPC_FLG_FIRST | RPC_FLG_LAST | RPC_FLG_NOCALL,
+ p->hdr.call_id, RPC_HEADER_LEN + RPC_HDR_RESP_LEN + RPC_HDR_FAULT_LEN, 0);
+
+ /*
+ * Initialize the HDR_RESP and FAULT parts of the PDU.
+ */
+
+ memset((char *)&hdr_resp, '\0', sizeof(hdr_resp));
+
+ fault_resp.status = status;
+ fault_resp.reserved = 0;
+
+ /*
+ * Marshall the header into the outgoing PDU.
+ */
+
+ if(!smb_io_rpc_hdr("", &fault_hdr, &outgoing_pdu, 0)) {
+ DEBUG(0,("setup_fault_pdu: marshalling of RPC_HDR failed.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &outgoing_pdu, 0)) {
+ DEBUG(0,("setup_fault_pdu: failed to marshall RPC_HDR_RESP.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ if(!smb_io_rpc_hdr_fault("fault", &fault_resp, &outgoing_pdu, 0)) {
+ DEBUG(0,("setup_fault_pdu: failed to marshall RPC_HDR_FAULT.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ p->out_data.data_sent_length = 0;
+ p->out_data.current_pdu_len = prs_offset(&outgoing_pdu);
+ p->out_data.current_pdu_sent = 0;
+
+ prs_mem_free(&outgoing_pdu);
+ return True;
+}
+
+#if 0
+/*******************************************************************
+ Marshall a cancel_ack pdu.
+ We should probably check the auth-verifier here.
+*******************************************************************/
+
+bool setup_cancel_ack_reply(pipes_struct *p, prs_struct *rpc_in_p)
+{
+ prs_struct outgoing_pdu;
+ RPC_HDR ack_reply_hdr;
+
+ /* Free any memory in the current return data buffer. */
+ prs_mem_free(&p->out_data.rdata);
+
+ /*
+ * Marshall directly into the outgoing PDU space. We
+ * must do this as we need to set to the bind response
+ * header and are never sending more than one PDU here.
+ */
+
+ prs_init_empty( &outgoing_pdu, p->mem_ctx, MARSHALL);
+ prs_give_memory( &outgoing_pdu, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
+
+ /*
+ * Initialize a cancel_ack header.
+ */
+
+ init_rpc_hdr(&ack_reply_hdr, RPC_CANCEL_ACK, RPC_FLG_FIRST | RPC_FLG_LAST,
+ p->hdr.call_id, RPC_HEADER_LEN, 0);
+
+ /*
+ * Marshall the header into the outgoing PDU.
+ */
+
+ if(!smb_io_rpc_hdr("", &ack_reply_hdr, &outgoing_pdu, 0)) {
+ DEBUG(0,("setup_cancel_ack_reply: marshalling of RPC_HDR failed.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ p->out_data.data_sent_length = 0;
+ p->out_data.current_pdu_len = prs_offset(&outgoing_pdu);
+ p->out_data.current_pdu_sent = 0;
+
+ prs_mem_free(&outgoing_pdu);
+ return True;
+}
+#endif
+
+/*******************************************************************
+ Ensure a bind request has the correct abstract & transfer interface.
+ Used to reject unknown binds from Win2k.
+*******************************************************************/
+
+bool check_bind_req(struct pipes_struct *p, RPC_IFACE* abstract,
+ RPC_IFACE* transfer, uint32 context_id)
+{
+ int i=0;
+ struct pipe_rpc_fns *context_fns;
+
+ DEBUG(3,("check_bind_req for %s\n", p->name));
+
+ /* we have to check all now since win2k introduced a new UUID on the lsaprpc pipe */
+
+ for (i=0; i<rpc_lookup_size; i++) {
+ DEBUGADD(10, ("checking %s\n", rpc_lookup[i].pipe.clnt));
+ if (strequal(rpc_lookup[i].pipe.clnt, p->name)
+ && ndr_syntax_id_equal(
+ abstract, &rpc_lookup[i].rpc_interface)
+ && ndr_syntax_id_equal(
+ transfer, &ndr_transfer_syntax)) {
+ break;
+ }
+ }
+
+ if (i == rpc_lookup_size) {
+ return false;
+ }
+
+ context_fns = SMB_MALLOC_P(struct pipe_rpc_fns);
+ if (context_fns == NULL) {
+ DEBUG(0,("check_bind_req: malloc() failed!\n"));
+ return False;
+ }
+
+ context_fns->cmds = rpc_lookup[i].cmds;
+ context_fns->n_cmds = rpc_lookup[i].n_cmds;
+ context_fns->context_id = context_id;
+
+ /* add to the list of open contexts */
+
+ DLIST_ADD( p->contexts, context_fns );
+
+ return True;
+}
+
+/*******************************************************************
+ Register commands to an RPC pipe
+*******************************************************************/
+
+NTSTATUS rpc_pipe_register_commands(int version, const char *clnt,
+ const char *srv,
+ const struct ndr_syntax_id *interface,
+ const struct api_struct *cmds, int size)
+{
+ struct rpc_table *rpc_entry;
+
+ if (!clnt || !srv || !cmds) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (version != SMB_RPC_INTERFACE_VERSION) {
+ DEBUG(0,("Can't register rpc commands!\n"
+ "You tried to register a rpc module with SMB_RPC_INTERFACE_VERSION %d"
+ ", while this version of samba uses version %d!\n",
+ version,SMB_RPC_INTERFACE_VERSION));
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ /* TODO:
+ *
+ * we still need to make sure that don't register the same commands twice!!!
+ *
+ * --metze
+ */
+
+ /* We use a temporary variable because this call can fail and
+ rpc_lookup will still be valid afterwards. It could then succeed if
+ called again later */
+ rpc_lookup_size++;
+ rpc_entry = SMB_REALLOC_ARRAY_KEEP_OLD_ON_ERROR(rpc_lookup, struct rpc_table, rpc_lookup_size);
+ if (NULL == rpc_entry) {
+ rpc_lookup_size--;
+ DEBUG(0, ("rpc_pipe_register_commands: memory allocation failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ } else {
+ rpc_lookup = rpc_entry;
+ }
+
+ rpc_entry = rpc_lookup + (rpc_lookup_size - 1);
+ ZERO_STRUCTP(rpc_entry);
+ rpc_entry->pipe.clnt = SMB_STRDUP(clnt);
+ rpc_entry->pipe.srv = SMB_STRDUP(srv);
+ rpc_entry->rpc_interface = *interface;
+ rpc_entry->cmds = cmds;
+ rpc_entry->n_cmds = size;
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Is a named pipe known?
+ * @param[in] cli_filename The pipe name requested by the client
+ * @result Do we want to serve this?
+ */
+bool is_known_pipename(const char *cli_filename)
+{
+ const char *pipename = cli_filename;
+ int i;
+
+ if (strnequal(pipename, "\\PIPE\\", 6)) {
+ pipename += 5;
+ }
+
+ if (*pipename == '\\') {
+ pipename += 1;
+ }
+
+ if (lp_disable_spoolss() && strequal(pipename, "spoolss")) {
+ DEBUG(10, ("refusing spoolss access\n"));
+ return false;
+ }
+
+ for (i=0; i<rpc_lookup_size; i++) {
+ if (strequal(pipename, rpc_lookup[i].pipe.clnt)) {
+ return true;
+ }
+ }
+
+ DEBUG(10, ("is_known_pipename: %s unknown\n", cli_filename));
+ return false;
+}
+
+/*******************************************************************
+ Handle a SPNEGO krb5 bind auth.
+*******************************************************************/
+
+static bool pipe_spnego_auth_bind_kerberos(pipes_struct *p, prs_struct *rpc_in_p, RPC_HDR_AUTH *pauth_info,
+ DATA_BLOB *psecblob, prs_struct *pout_auth)
+{
+ return False;
+}
+
+/*******************************************************************
+ Handle the first part of a SPNEGO bind auth.
+*******************************************************************/
+
+static bool pipe_spnego_auth_bind_negotiate(pipes_struct *p, prs_struct *rpc_in_p,
+ RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth)
+{
+ DATA_BLOB blob;
+ DATA_BLOB secblob;
+ DATA_BLOB response;
+ DATA_BLOB chal;
+ char *OIDs[ASN1_MAX_OIDS];
+ int i;
+ NTSTATUS status;
+ bool got_kerberos_mechanism = false;
+ AUTH_NTLMSSP_STATE *a = NULL;
+ RPC_HDR_AUTH auth_info;
+
+ ZERO_STRUCT(secblob);
+ ZERO_STRUCT(chal);
+ ZERO_STRUCT(response);
+
+ /* Grab the SPNEGO blob. */
+ blob = data_blob(NULL,p->hdr.auth_len);
+
+ if (!prs_copy_data_out((char *)blob.data, rpc_in_p, p->hdr.auth_len)) {
+ DEBUG(0,("pipe_spnego_auth_bind_negotiate: Failed to pull %u bytes - the SPNEGO auth header.\n",
+ (unsigned int)p->hdr.auth_len ));
+ goto err;
+ }
+
+ if (blob.data[0] != ASN1_APPLICATION(0)) {
+ goto err;
+ }
+
+ /* parse out the OIDs and the first sec blob */
+ if (!parse_negTokenTarg(blob, OIDs, &secblob)) {
+ DEBUG(0,("pipe_spnego_auth_bind_negotiate: Failed to parse the security blob.\n"));
+ goto err;
+ }
+
+ if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 || strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
+ got_kerberos_mechanism = true;
+ }
+
+ for (i=0;OIDs[i];i++) {
+ DEBUG(3,("pipe_spnego_auth_bind_negotiate: Got OID %s\n", OIDs[i]));
+ SAFE_FREE(OIDs[i]);
+ }
+ DEBUG(3,("pipe_spnego_auth_bind_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length));
+
+ if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
+ bool ret = pipe_spnego_auth_bind_kerberos(p, rpc_in_p, pauth_info, &secblob, pout_auth);
+ data_blob_free(&secblob);
+ data_blob_free(&blob);
+ return ret;
+ }
+
+ if (p->auth.auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP && p->auth.a_u.auth_ntlmssp_state) {
+ /* Free any previous auth type. */
+ free_pipe_ntlmssp_auth_data(&p->auth);
+ }
+
+ if (!got_kerberos_mechanism) {
+ /* Initialize the NTLM engine. */
+ status = auth_ntlmssp_start(&a);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto err;
+ }
+
+ /*
+ * Pass the first security blob of data to it.
+ * This can return an error or NT_STATUS_MORE_PROCESSING_REQUIRED
+ * which means we need another packet to complete the bind.
+ */
+
+ status = auth_ntlmssp_update(a, secblob, &chal);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DEBUG(3,("pipe_spnego_auth_bind_negotiate: auth_ntlmssp_update failed.\n"));
+ goto err;
+ }
+
+ /* Generate the response blob we need for step 2 of the bind. */
+ response = spnego_gen_auth_response(&chal, status, OID_NTLMSSP);
+ } else {
+ /*
+ * SPNEGO negotiate down to NTLMSSP. The subsequent
+ * code to process follow-up packets is not complete
+ * yet. JRA.
+ */
+ response = spnego_gen_auth_response(NULL,
+ NT_STATUS_MORE_PROCESSING_REQUIRED,
+ OID_NTLMSSP);
+ }
+
+ /* Copy the blob into the pout_auth parse struct */
+ init_rpc_hdr_auth(&auth_info, RPC_SPNEGO_AUTH_TYPE, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1);
+ if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) {
+ DEBUG(0,("pipe_spnego_auth_bind_negotiate: marshalling of RPC_HDR_AUTH failed.\n"));
+ goto err;
+ }
+
+ if (!prs_copy_data_in(pout_auth, (char *)response.data, response.length)) {
+ DEBUG(0,("pipe_spnego_auth_bind_negotiate: marshalling of data blob failed.\n"));
+ goto err;
+ }
+
+ p->auth.a_u.auth_ntlmssp_state = a;
+ p->auth.auth_data_free_func = &free_pipe_ntlmssp_auth_data;
+ p->auth.auth_type = PIPE_AUTH_TYPE_SPNEGO_NTLMSSP;
+
+ data_blob_free(&blob);
+ data_blob_free(&secblob);
+ data_blob_free(&chal);
+ data_blob_free(&response);
+
+ /* We can't set pipe_bound True yet - we need an RPC_ALTER_CONTEXT response packet... */
+ return True;
+
+ err:
+
+ data_blob_free(&blob);
+ data_blob_free(&secblob);
+ data_blob_free(&chal);
+ data_blob_free(&response);
+
+ p->auth.a_u.auth_ntlmssp_state = NULL;
+
+ return False;
+}
+
+/*******************************************************************
+ Handle the second part of a SPNEGO bind auth.
+*******************************************************************/
+
+static bool pipe_spnego_auth_bind_continue(pipes_struct *p, prs_struct *rpc_in_p,
+ RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth)
+{
+ RPC_HDR_AUTH auth_info;
+ DATA_BLOB spnego_blob;
+ DATA_BLOB auth_blob;
+ DATA_BLOB auth_reply;
+ DATA_BLOB response;
+ AUTH_NTLMSSP_STATE *a = p->auth.a_u.auth_ntlmssp_state;
+
+ ZERO_STRUCT(spnego_blob);
+ ZERO_STRUCT(auth_blob);
+ ZERO_STRUCT(auth_reply);
+ ZERO_STRUCT(response);
+
+ /*
+ * NB. If we've negotiated down from krb5 to NTLMSSP we'll currently
+ * fail here as 'a' == NULL.
+ */
+ if (p->auth.auth_type != PIPE_AUTH_TYPE_SPNEGO_NTLMSSP || !a) {
+ DEBUG(0,("pipe_spnego_auth_bind_continue: not in NTLMSSP auth state.\n"));
+ goto err;
+ }
+
+ /* Grab the SPNEGO blob. */
+ spnego_blob = data_blob(NULL,p->hdr.auth_len);
+
+ if (!prs_copy_data_out((char *)spnego_blob.data, rpc_in_p, p->hdr.auth_len)) {
+ DEBUG(0,("pipe_spnego_auth_bind_continue: Failed to pull %u bytes - the SPNEGO auth header.\n",
+ (unsigned int)p->hdr.auth_len ));
+ goto err;
+ }
+
+ if (spnego_blob.data[0] != ASN1_CONTEXT(1)) {
+ DEBUG(0,("pipe_spnego_auth_bind_continue: invalid SPNEGO blob type.\n"));
+ goto err;
+ }
+
+ if (!spnego_parse_auth(spnego_blob, &auth_blob)) {
+ DEBUG(0,("pipe_spnego_auth_bind_continue: invalid SPNEGO blob.\n"));
+ goto err;
+ }
+
+ /*
+ * The following call actually checks the challenge/response data.
+ * for correctness against the given DOMAIN\user name.
+ */
+
+ if (!pipe_ntlmssp_verify_final(p, &auth_blob)) {
+ goto err;
+ }
+
+ data_blob_free(&spnego_blob);
+ data_blob_free(&auth_blob);
+
+ /* Generate the spnego "accept completed" blob - no incoming data. */
+ response = spnego_gen_auth_response(&auth_reply, NT_STATUS_OK, OID_NTLMSSP);
+
+ /* Copy the blob into the pout_auth parse struct */
+ init_rpc_hdr_auth(&auth_info, RPC_SPNEGO_AUTH_TYPE, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1);
+ if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) {
+ DEBUG(0,("pipe_spnego_auth_bind_continue: marshalling of RPC_HDR_AUTH failed.\n"));
+ goto err;
+ }
+
+ if (!prs_copy_data_in(pout_auth, (char *)response.data, response.length)) {
+ DEBUG(0,("pipe_spnego_auth_bind_continue: marshalling of data blob failed.\n"));
+ goto err;
+ }
+
+ data_blob_free(&auth_reply);
+ data_blob_free(&response);
+
+ p->pipe_bound = True;
+
+ return True;
+
+ err:
+
+ data_blob_free(&spnego_blob);
+ data_blob_free(&auth_blob);
+ data_blob_free(&auth_reply);
+ data_blob_free(&response);
+
+ free_pipe_ntlmssp_auth_data(&p->auth);
+ p->auth.a_u.auth_ntlmssp_state = NULL;
+
+ return False;
+}
+
+/*******************************************************************
+ Handle an schannel bind auth.
+*******************************************************************/
+
+static bool pipe_schannel_auth_bind(pipes_struct *p, prs_struct *rpc_in_p,
+ RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth)
+{
+ RPC_HDR_AUTH auth_info;
+ RPC_AUTH_SCHANNEL_NEG neg;
+ RPC_AUTH_VERIFIER auth_verifier;
+ bool ret;
+ struct dcinfo *pdcinfo;
+ uint32 flags;
+ DATA_BLOB session_key;
+
+ if (!smb_io_rpc_auth_schannel_neg("", &neg, rpc_in_p, 0)) {
+ DEBUG(0,("pipe_schannel_auth_bind: Could not unmarshal SCHANNEL auth neg\n"));
+ return False;
+ }
+
+ /*
+ * The neg.myname key here must match the remote computer name
+ * given in the DOM_CLNT_SRV.uni_comp_name used on all netlogon pipe
+ * operations that use credentials.
+ */
+
+ become_root();
+ ret = secrets_restore_schannel_session_info(p->mem_ctx, neg.myname, &pdcinfo);
+ unbecome_root();
+
+ if (!ret) {
+ DEBUG(0, ("pipe_schannel_auth_bind: Attempt to bind using schannel without successful serverauth2\n"));
+ return False;
+ }
+
+ p->auth.a_u.schannel_auth = talloc(p, struct schannel_auth_struct);
+ if (!p->auth.a_u.schannel_auth) {
+ TALLOC_FREE(pdcinfo);
+ return False;
+ }
+
+ memset(p->auth.a_u.schannel_auth->sess_key, 0, sizeof(p->auth.a_u.schannel_auth->sess_key));
+ memcpy(p->auth.a_u.schannel_auth->sess_key, pdcinfo->sess_key,
+ sizeof(pdcinfo->sess_key));
+
+ TALLOC_FREE(pdcinfo);
+
+ p->auth.a_u.schannel_auth->seq_num = 0;
+
+ /*
+ * JRA. Should we also copy the schannel session key into the pipe session key p->session_key
+ * here ? We do that for NTLMSSP, but the session key is already set up from the vuser
+ * struct of the person who opened the pipe. I need to test this further. JRA.
+ *
+ * VL. As we are mapping this to guest set the generic key
+ * "SystemLibraryDTC" key here. It's a bit difficult to test against
+ * W2k3, as it does not allow schannel binds against SAMR and LSA
+ * anymore.
+ */
+
+ session_key = generic_session_key();
+ if (session_key.data == NULL) {
+ DEBUG(0, ("pipe_schannel_auth_bind: Could not alloc session"
+ " key\n"));
+ return false;
+ }
+
+ ret = server_info_set_session_key(p->server_info, session_key);
+
+ data_blob_free(&session_key);
+
+ if (!ret) {
+ DEBUG(0, ("server_info_set_session_key failed\n"));
+ return false;
+ }
+
+ init_rpc_hdr_auth(&auth_info, RPC_SCHANNEL_AUTH_TYPE, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1);
+ if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) {
+ DEBUG(0,("pipe_schannel_auth_bind: marshalling of RPC_HDR_AUTH failed.\n"));
+ return False;
+ }
+
+ /*** SCHANNEL verifier ***/
+
+ init_rpc_auth_verifier(&auth_verifier, "\001", 0x0);
+ if(!smb_io_rpc_schannel_verifier("", &auth_verifier, pout_auth, 0)) {
+ DEBUG(0,("pipe_schannel_auth_bind: marshalling of RPC_AUTH_VERIFIER failed.\n"));
+ return False;
+ }
+
+ prs_align(pout_auth);
+
+ flags = 5;
+ if(!prs_uint32("flags ", pout_auth, 0, &flags)) {
+ return False;
+ }
+
+ DEBUG(10,("pipe_schannel_auth_bind: schannel auth: domain [%s] myname [%s]\n",
+ neg.domain, neg.myname));
+
+ /* We're finished with this bind - no more packets. */
+ p->auth.auth_data_free_func = NULL;
+ p->auth.auth_type = PIPE_AUTH_TYPE_SCHANNEL;
+
+ p->pipe_bound = True;
+
+ return True;
+}
+
+/*******************************************************************
+ Handle an NTLMSSP bind auth.
+*******************************************************************/
+
+static bool pipe_ntlmssp_auth_bind(pipes_struct *p, prs_struct *rpc_in_p,
+ RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth)
+{
+ RPC_HDR_AUTH auth_info;
+ DATA_BLOB blob;
+ DATA_BLOB response;
+ NTSTATUS status;
+ AUTH_NTLMSSP_STATE *a = NULL;
+
+ ZERO_STRUCT(blob);
+ ZERO_STRUCT(response);
+
+ /* Grab the NTLMSSP blob. */
+ blob = data_blob(NULL,p->hdr.auth_len);
+
+ if (!prs_copy_data_out((char *)blob.data, rpc_in_p, p->hdr.auth_len)) {
+ DEBUG(0,("pipe_ntlmssp_auth_bind: Failed to pull %u bytes - the NTLM auth header.\n",
+ (unsigned int)p->hdr.auth_len ));
+ goto err;
+ }
+
+ if (strncmp((char *)blob.data, "NTLMSSP", 7) != 0) {
+ DEBUG(0,("pipe_ntlmssp_auth_bind: Failed to read NTLMSSP in blob\n"));
+ goto err;
+ }
+
+ /* We have an NTLMSSP blob. */
+ status = auth_ntlmssp_start(&a);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("pipe_ntlmssp_auth_bind: auth_ntlmssp_start failed: %s\n",
+ nt_errstr(status) ));
+ goto err;
+ }
+
+ status = auth_ntlmssp_update(a, blob, &response);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DEBUG(0,("pipe_ntlmssp_auth_bind: auth_ntlmssp_update failed: %s\n",
+ nt_errstr(status) ));
+ goto err;
+ }
+
+ data_blob_free(&blob);
+
+ /* Copy the blob into the pout_auth parse struct */
+ init_rpc_hdr_auth(&auth_info, RPC_NTLMSSP_AUTH_TYPE, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1);
+ if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) {
+ DEBUG(0,("pipe_ntlmssp_auth_bind: marshalling of RPC_HDR_AUTH failed.\n"));
+ goto err;
+ }
+
+ if (!prs_copy_data_in(pout_auth, (char *)response.data, response.length)) {
+ DEBUG(0,("pipe_ntlmssp_auth_bind: marshalling of data blob failed.\n"));
+ goto err;
+ }
+
+ p->auth.a_u.auth_ntlmssp_state = a;
+ p->auth.auth_data_free_func = &free_pipe_ntlmssp_auth_data;
+ p->auth.auth_type = PIPE_AUTH_TYPE_NTLMSSP;
+
+ data_blob_free(&blob);
+ data_blob_free(&response);
+
+ DEBUG(10,("pipe_ntlmssp_auth_bind: NTLMSSP auth started\n"));
+
+ /* We can't set pipe_bound True yet - we need an RPC_AUTH3 response packet... */
+ return True;
+
+ err:
+
+ data_blob_free(&blob);
+ data_blob_free(&response);
+
+ free_pipe_ntlmssp_auth_data(&p->auth);
+ p->auth.a_u.auth_ntlmssp_state = NULL;
+ return False;
+}
+
+/*******************************************************************
+ Respond to a pipe bind request.
+*******************************************************************/
+
+bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
+{
+ RPC_HDR_BA hdr_ba;
+ RPC_HDR_RB hdr_rb;
+ RPC_HDR_AUTH auth_info;
+ uint16 assoc_gid;
+ fstring ack_pipe_name;
+ prs_struct out_hdr_ba;
+ prs_struct out_auth;
+ prs_struct outgoing_rpc;
+ int i = 0;
+ int auth_len = 0;
+ unsigned int auth_type = RPC_ANONYMOUS_AUTH_TYPE;
+
+ /* No rebinds on a bound pipe - use alter context. */
+ if (p->pipe_bound) {
+ DEBUG(2,("api_pipe_bind_req: rejecting bind request on bound pipe %s.\n", p->pipe_srv_name));
+ return setup_bind_nak(p);
+ }
+
+ prs_init_empty( &outgoing_rpc, p->mem_ctx, MARSHALL);
+
+ /*
+ * Marshall directly into the outgoing PDU space. We
+ * must do this as we need to set to the bind response
+ * header and are never sending more than one PDU here.
+ */
+
+ prs_give_memory( &outgoing_rpc, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
+
+ /*
+ * Setup the memory to marshall the ba header, and the
+ * auth footers.
+ */
+
+ if(!prs_init(&out_hdr_ba, 1024, p->mem_ctx, MARSHALL)) {
+ DEBUG(0,("api_pipe_bind_req: malloc out_hdr_ba failed.\n"));
+ prs_mem_free(&outgoing_rpc);
+ return False;
+ }
+
+ if(!prs_init(&out_auth, 1024, p->mem_ctx, MARSHALL)) {
+ DEBUG(0,("api_pipe_bind_req: malloc out_auth failed.\n"));
+ prs_mem_free(&outgoing_rpc);
+ prs_mem_free(&out_hdr_ba);
+ return False;
+ }
+
+ DEBUG(5,("api_pipe_bind_req: decode request. %d\n", __LINE__));
+
+ ZERO_STRUCT(hdr_rb);
+
+ /* decode the bind request */
+
+ if(!smb_io_rpc_hdr_rb("", &hdr_rb, rpc_in_p, 0)) {
+ DEBUG(0,("api_pipe_bind_req: unable to unmarshall RPC_HDR_RB "
+ "struct.\n"));
+ goto err_exit;
+ }
+
+ if (hdr_rb.num_contexts == 0) {
+ DEBUG(0, ("api_pipe_bind_req: no rpc contexts around\n"));
+ goto err_exit;
+ }
+
+ /*
+ * Try and find the correct pipe name to ensure
+ * that this is a pipe name we support.
+ */
+
+ for (i = 0; i < rpc_lookup_size; i++) {
+ if (ndr_syntax_id_equal(&rpc_lookup[i].rpc_interface,
+ &hdr_rb.rpc_context[0].abstract)) {
+ DEBUG(3, ("api_pipe_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n",
+ rpc_lookup[i].pipe.clnt, rpc_lookup[i].pipe.srv));
+ fstrcpy(p->name, rpc_lookup[i].pipe.clnt);
+ fstrcpy(p->pipe_srv_name, rpc_lookup[i].pipe.srv);
+ break;
+ }
+ }
+
+ if (i == rpc_lookup_size) {
+ if (NT_STATUS_IS_ERR(smb_probe_module("rpc", p->name))) {
+ DEBUG(3,("api_pipe_bind_req: Unknown pipe name %s in bind request.\n",
+ p->name ));
+ prs_mem_free(&outgoing_rpc);
+ prs_mem_free(&out_hdr_ba);
+ prs_mem_free(&out_auth);
+
+ return setup_bind_nak(p);
+ }
+
+ for (i = 0; i < rpc_lookup_size; i++) {
+ if (strequal(rpc_lookup[i].pipe.clnt, p->name)) {
+ DEBUG(3, ("api_pipe_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n",
+ rpc_lookup[i].pipe.clnt, rpc_lookup[i].pipe.srv));
+ fstrcpy(p->pipe_srv_name, rpc_lookup[i].pipe.srv);
+ break;
+ }
+ }
+
+ if (i == rpc_lookup_size) {
+ DEBUG(0, ("module %s doesn't provide functions for pipe %s!\n", p->name, p->name));
+ goto err_exit;
+ }
+ }
+
+ /* 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__));
+
+ /*
+ * Check if this is an authenticated bind request.
+ */
+
+ if (p->hdr.auth_len) {
+ /*
+ * Decode the authentication verifier.
+ */
+
+ if(!smb_io_rpc_hdr_auth("", &auth_info, rpc_in_p, 0)) {
+ DEBUG(0,("api_pipe_bind_req: unable to unmarshall RPC_HDR_AUTH struct.\n"));
+ goto err_exit;
+ }
+
+ auth_type = auth_info.auth_type;
+
+ /* Work out if we have to sign or seal etc. */
+ switch (auth_info.auth_level) {
+ case RPC_AUTH_LEVEL_INTEGRITY:
+ p->auth.auth_level = PIPE_AUTH_LEVEL_INTEGRITY;
+ break;
+ case RPC_AUTH_LEVEL_PRIVACY:
+ p->auth.auth_level = PIPE_AUTH_LEVEL_PRIVACY;
+ break;
+ default:
+ DEBUG(0,("api_pipe_bind_req: unexpected auth level (%u).\n",
+ (unsigned int)auth_info.auth_level ));
+ goto err_exit;
+ }
+ } else {
+ ZERO_STRUCT(auth_info);
+ }
+
+ assoc_gid = hdr_rb.bba.assoc_gid ? hdr_rb.bba.assoc_gid : 0x53f0;
+
+ switch(auth_type) {
+ case RPC_NTLMSSP_AUTH_TYPE:
+ if (!pipe_ntlmssp_auth_bind(p, rpc_in_p, &auth_info, &out_auth)) {
+ goto err_exit;
+ }
+ assoc_gid = 0x7a77;
+ break;
+
+ case RPC_SCHANNEL_AUTH_TYPE:
+ if (!pipe_schannel_auth_bind(p, rpc_in_p, &auth_info, &out_auth)) {
+ goto err_exit;
+ }
+ break;
+
+ case RPC_SPNEGO_AUTH_TYPE:
+ if (!pipe_spnego_auth_bind_negotiate(p, rpc_in_p, &auth_info, &out_auth)) {
+ goto err_exit;
+ }
+ break;
+
+ case RPC_ANONYMOUS_AUTH_TYPE:
+ /* Unauthenticated bind request. */
+ /* Get the authenticated pipe user from current_user */
+ if (!copy_current_user(&p->pipe_user, &current_user)) {
+ DEBUG(10, ("Could not copy current user\n"));
+ goto err_exit;
+ }
+ /* We're finished - no more packets. */
+ p->auth.auth_type = PIPE_AUTH_TYPE_NONE;
+ /* We must set the pipe auth_level here also. */
+ p->auth.auth_level = PIPE_AUTH_LEVEL_NONE;
+ p->pipe_bound = True;
+ /* The session key was initialized from the SMB
+ * session in make_internal_rpc_pipe_p */
+ break;
+
+ default:
+ DEBUG(0,("api_pipe_bind_req: unknown auth type %x requested.\n", auth_type ));
+ goto err_exit;
+ }
+
+ /*
+ * Create the bind response struct.
+ */
+
+ /* If the requested abstract synt uuid doesn't match our client pipe,
+ reject the bind_ack & set the transfer interface synt to all 0's,
+ ver 0 (observed when NT5 attempts to bind to abstract interfaces
+ unknown to NT4)
+ Needed when adding entries to a DACL from NT5 - SK */
+
+ if(check_bind_req(p, &hdr_rb.rpc_context[0].abstract, &hdr_rb.rpc_context[0].transfer[0],
+ hdr_rb.rpc_context[0].context_id )) {
+ init_rpc_hdr_ba(&hdr_ba,
+ RPC_MAX_PDU_FRAG_LEN,
+ RPC_MAX_PDU_FRAG_LEN,
+ assoc_gid,
+ ack_pipe_name,
+ 0x1, 0x0, 0x0,
+ &hdr_rb.rpc_context[0].transfer[0]);
+ } else {
+ RPC_IFACE null_interface;
+ ZERO_STRUCT(null_interface);
+ /* Rejection reason: abstract syntax not supported */
+ init_rpc_hdr_ba(&hdr_ba, RPC_MAX_PDU_FRAG_LEN,
+ RPC_MAX_PDU_FRAG_LEN, assoc_gid,
+ ack_pipe_name, 0x1, 0x2, 0x1,
+ &null_interface);
+ p->pipe_bound = False;
+ }
+
+ /*
+ * and marshall it.
+ */
+
+ if(!smb_io_rpc_hdr_ba("", &hdr_ba, &out_hdr_ba, 0)) {
+ DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_BA failed.\n"));
+ goto err_exit;
+ }
+
+ /*
+ * Create the header, now we know the length.
+ */
+
+ if (prs_offset(&out_auth)) {
+ auth_len = prs_offset(&out_auth) - RPC_HDR_AUTH_LEN;
+ }
+
+ init_rpc_hdr(&p->hdr, RPC_BINDACK, RPC_FLG_FIRST | RPC_FLG_LAST,
+ p->hdr.call_id,
+ RPC_HEADER_LEN + prs_offset(&out_hdr_ba) + prs_offset(&out_auth),
+ auth_len);
+
+ /*
+ * Marshall the header into the outgoing PDU.
+ */
+
+ if(!smb_io_rpc_hdr("", &p->hdr, &outgoing_rpc, 0)) {
+ DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR failed.\n"));
+ goto err_exit;
+ }
+
+ /*
+ * Now add the RPC_HDR_BA and any auth needed.
+ */
+
+ if(!prs_append_prs_data( &outgoing_rpc, &out_hdr_ba)) {
+ DEBUG(0,("api_pipe_bind_req: append of RPC_HDR_BA failed.\n"));
+ goto err_exit;
+ }
+
+ if (auth_len && !prs_append_prs_data( &outgoing_rpc, &out_auth)) {
+ DEBUG(0,("api_pipe_bind_req: append of auth info failed.\n"));
+ goto err_exit;
+ }
+
+ /*
+ * Setup the lengths for the initial reply.
+ */
+
+ p->out_data.data_sent_length = 0;
+ p->out_data.current_pdu_len = prs_offset(&outgoing_rpc);
+ p->out_data.current_pdu_sent = 0;
+
+ prs_mem_free(&out_hdr_ba);
+ prs_mem_free(&out_auth);
+
+ return True;
+
+ err_exit:
+
+ prs_mem_free(&outgoing_rpc);
+ prs_mem_free(&out_hdr_ba);
+ prs_mem_free(&out_auth);
+ return setup_bind_nak(p);
+}
+
+/****************************************************************************
+ Deal with an alter context call. Can be third part of 3 leg auth request for
+ SPNEGO calls.
+****************************************************************************/
+
+bool api_pipe_alter_context(pipes_struct *p, prs_struct *rpc_in_p)
+{
+ RPC_HDR_BA hdr_ba;
+ RPC_HDR_RB hdr_rb;
+ RPC_HDR_AUTH auth_info;
+ uint16 assoc_gid;
+ fstring ack_pipe_name;
+ prs_struct out_hdr_ba;
+ prs_struct out_auth;
+ prs_struct outgoing_rpc;
+ int auth_len = 0;
+
+ prs_init_empty( &outgoing_rpc, p->mem_ctx, MARSHALL);
+
+ /*
+ * Marshall directly into the outgoing PDU space. We
+ * must do this as we need to set to the bind response
+ * header and are never sending more than one PDU here.
+ */
+
+ prs_give_memory( &outgoing_rpc, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
+
+ /*
+ * Setup the memory to marshall the ba header, and the
+ * auth footers.
+ */
+
+ if(!prs_init(&out_hdr_ba, 1024, p->mem_ctx, MARSHALL)) {
+ DEBUG(0,("api_pipe_alter_context: malloc out_hdr_ba failed.\n"));
+ prs_mem_free(&outgoing_rpc);
+ return False;
+ }
+
+ if(!prs_init(&out_auth, 1024, p->mem_ctx, MARSHALL)) {
+ DEBUG(0,("api_pipe_alter_context: malloc out_auth failed.\n"));
+ prs_mem_free(&outgoing_rpc);
+ prs_mem_free(&out_hdr_ba);
+ return False;
+ }
+
+ DEBUG(5,("api_pipe_alter_context: decode request. %d\n", __LINE__));
+
+ /* decode the alter context request */
+ if(!smb_io_rpc_hdr_rb("", &hdr_rb, rpc_in_p, 0)) {
+ DEBUG(0,("api_pipe_alter_context: unable to unmarshall RPC_HDR_RB struct.\n"));
+ goto err_exit;
+ }
+
+ /* secondary address CAN be NULL
+ * as the specs say it's ignored.
+ * It MUST be NULL to have the spoolss working.
+ */
+ fstrcpy(ack_pipe_name,"");
+
+ DEBUG(5,("api_pipe_alter_context: make response. %d\n", __LINE__));
+
+ /*
+ * Check if this is an authenticated alter context request.
+ */
+
+ if (p->hdr.auth_len != 0) {
+ /*
+ * Decode the authentication verifier.
+ */
+
+ if(!smb_io_rpc_hdr_auth("", &auth_info, rpc_in_p, 0)) {
+ DEBUG(0,("api_pipe_alter_context: unable to unmarshall RPC_HDR_AUTH struct.\n"));
+ goto err_exit;
+ }
+
+ /*
+ * Currently only the SPNEGO auth type uses the alter ctx
+ * response in place of the NTLMSSP auth3 type.
+ */
+
+ if (auth_info.auth_type == RPC_SPNEGO_AUTH_TYPE) {
+ /* We can only finish if the pipe is unbound. */
+ if (!p->pipe_bound) {
+ if (!pipe_spnego_auth_bind_continue(p, rpc_in_p, &auth_info, &out_auth)) {
+ goto err_exit;
+ }
+ } else {
+ goto err_exit;
+ }
+ }
+ } else {
+ ZERO_STRUCT(auth_info);
+ }
+
+ assoc_gid = hdr_rb.bba.assoc_gid ? hdr_rb.bba.assoc_gid : 0x53f0;
+
+ /*
+ * Create the bind response struct.
+ */
+
+ /* If the requested abstract synt uuid doesn't match our client pipe,
+ reject the bind_ack & set the transfer interface synt to all 0's,
+ ver 0 (observed when NT5 attempts to bind to abstract interfaces
+ unknown to NT4)
+ Needed when adding entries to a DACL from NT5 - SK */
+
+ if(check_bind_req(p, &hdr_rb.rpc_context[0].abstract, &hdr_rb.rpc_context[0].transfer[0],
+ hdr_rb.rpc_context[0].context_id )) {
+ init_rpc_hdr_ba(&hdr_ba,
+ RPC_MAX_PDU_FRAG_LEN,
+ RPC_MAX_PDU_FRAG_LEN,
+ assoc_gid,
+ ack_pipe_name,
+ 0x1, 0x0, 0x0,
+ &hdr_rb.rpc_context[0].transfer[0]);
+ } else {
+ RPC_IFACE null_interface;
+ ZERO_STRUCT(null_interface);
+ /* Rejection reason: abstract syntax not supported */
+ init_rpc_hdr_ba(&hdr_ba, RPC_MAX_PDU_FRAG_LEN,
+ RPC_MAX_PDU_FRAG_LEN, assoc_gid,
+ ack_pipe_name, 0x1, 0x2, 0x1,
+ &null_interface);
+ p->pipe_bound = False;
+ }
+
+ /*
+ * and marshall it.
+ */
+
+ if(!smb_io_rpc_hdr_ba("", &hdr_ba, &out_hdr_ba, 0)) {
+ DEBUG(0,("api_pipe_alter_context: marshalling of RPC_HDR_BA failed.\n"));
+ goto err_exit;
+ }
+
+ /*
+ * Create the header, now we know the length.
+ */
+
+ if (prs_offset(&out_auth)) {
+ auth_len = prs_offset(&out_auth) - RPC_HDR_AUTH_LEN;
+ }
+
+ init_rpc_hdr(&p->hdr, RPC_ALTCONTRESP, RPC_FLG_FIRST | RPC_FLG_LAST,
+ p->hdr.call_id,
+ RPC_HEADER_LEN + prs_offset(&out_hdr_ba) + prs_offset(&out_auth),
+ auth_len);
+
+ /*
+ * Marshall the header into the outgoing PDU.
+ */
+
+ if(!smb_io_rpc_hdr("", &p->hdr, &outgoing_rpc, 0)) {
+ DEBUG(0,("api_pipe_alter_context: marshalling of RPC_HDR failed.\n"));
+ goto err_exit;
+ }
+
+ /*
+ * Now add the RPC_HDR_BA and any auth needed.
+ */
+
+ if(!prs_append_prs_data( &outgoing_rpc, &out_hdr_ba)) {
+ DEBUG(0,("api_pipe_alter_context: append of RPC_HDR_BA failed.\n"));
+ goto err_exit;
+ }
+
+ if (auth_len && !prs_append_prs_data( &outgoing_rpc, &out_auth)) {
+ DEBUG(0,("api_pipe_alter_context: append of auth info failed.\n"));
+ goto err_exit;
+ }
+
+ /*
+ * Setup the lengths for the initial reply.
+ */
+
+ p->out_data.data_sent_length = 0;
+ p->out_data.current_pdu_len = prs_offset(&outgoing_rpc);
+ p->out_data.current_pdu_sent = 0;
+
+ prs_mem_free(&out_hdr_ba);
+ prs_mem_free(&out_auth);
+
+ return True;
+
+ err_exit:
+
+ prs_mem_free(&outgoing_rpc);
+ prs_mem_free(&out_hdr_ba);
+ prs_mem_free(&out_auth);
+ return setup_bind_nak(p);
+}
+
+/****************************************************************************
+ Deal with NTLMSSP sign & seal processing on an RPC request.
+****************************************************************************/
+
+bool api_pipe_ntlmssp_auth_process(pipes_struct *p, prs_struct *rpc_in,
+ uint32 *p_ss_padding_len, NTSTATUS *pstatus)
+{
+ RPC_HDR_AUTH auth_info;
+ uint32 auth_len = p->hdr.auth_len;
+ uint32 save_offset = prs_offset(rpc_in);
+ AUTH_NTLMSSP_STATE *a = p->auth.a_u.auth_ntlmssp_state;
+ unsigned char *data = NULL;
+ size_t data_len;
+ unsigned char *full_packet_data = NULL;
+ size_t full_packet_data_len;
+ DATA_BLOB auth_blob;
+
+ *pstatus = NT_STATUS_OK;
+
+ if (p->auth.auth_level == PIPE_AUTH_LEVEL_NONE || p->auth.auth_level == PIPE_AUTH_LEVEL_CONNECT) {
+ return True;
+ }
+
+ if (!a) {
+ *pstatus = NT_STATUS_INVALID_PARAMETER;
+ return False;
+ }
+
+ /* Ensure there's enough data for an authenticated request. */
+ if ((auth_len > RPC_MAX_SIGN_SIZE) ||
+ (RPC_HEADER_LEN + RPC_HDR_REQ_LEN + RPC_HDR_AUTH_LEN + auth_len > p->hdr.frag_len)) {
+ DEBUG(0,("api_pipe_ntlmssp_auth_process: auth_len %u is too large.\n",
+ (unsigned int)auth_len ));
+ *pstatus = NT_STATUS_INVALID_PARAMETER;
+ return False;
+ }
+
+ /*
+ * We need the full packet data + length (minus auth stuff) as well as the packet data + length
+ * after the RPC header.
+ * We need to pass in the full packet (minus auth len) to the NTLMSSP sign and check seal
+ * functions as NTLMv2 checks the rpc headers also.
+ */
+
+ data = (unsigned char *)(prs_data_p(rpc_in) + RPC_HDR_REQ_LEN);
+ data_len = (size_t)(p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN - RPC_HDR_AUTH_LEN - auth_len);
+
+ full_packet_data = p->in_data.current_in_pdu;
+ full_packet_data_len = p->hdr.frag_len - auth_len;
+
+ /* Pull the auth header and the following data into a blob. */
+ if(!prs_set_offset(rpc_in, RPC_HDR_REQ_LEN + data_len)) {
+ DEBUG(0,("api_pipe_ntlmssp_auth_process: cannot move offset to %u.\n",
+ (unsigned int)RPC_HDR_REQ_LEN + (unsigned int)data_len ));
+ *pstatus = NT_STATUS_INVALID_PARAMETER;
+ return False;
+ }
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, rpc_in, 0)) {
+ DEBUG(0,("api_pipe_ntlmssp_auth_process: failed to unmarshall RPC_HDR_AUTH.\n"));
+ *pstatus = NT_STATUS_INVALID_PARAMETER;
+ return False;
+ }
+
+ auth_blob.data = (unsigned char *)prs_data_p(rpc_in) + prs_offset(rpc_in);
+ auth_blob.length = auth_len;
+
+ switch (p->auth.auth_level) {
+ case PIPE_AUTH_LEVEL_PRIVACY:
+ /* Data is encrypted. */
+ *pstatus = ntlmssp_unseal_packet(a->ntlmssp_state,
+ data, data_len,
+ full_packet_data,
+ full_packet_data_len,
+ &auth_blob);
+ if (!NT_STATUS_IS_OK(*pstatus)) {
+ return False;
+ }
+ break;
+ case PIPE_AUTH_LEVEL_INTEGRITY:
+ /* Data is signed. */
+ *pstatus = ntlmssp_check_packet(a->ntlmssp_state,
+ data, data_len,
+ full_packet_data,
+ full_packet_data_len,
+ &auth_blob);
+ if (!NT_STATUS_IS_OK(*pstatus)) {
+ return False;
+ }
+ break;
+ default:
+ *pstatus = NT_STATUS_INVALID_PARAMETER;
+ return False;
+ }
+
+ /*
+ * Return the current pointer to the data offset.
+ */
+
+ if(!prs_set_offset(rpc_in, save_offset)) {
+ DEBUG(0,("api_pipe_auth_process: failed to set offset back to %u\n",
+ (unsigned int)save_offset ));
+ *pstatus = NT_STATUS_INVALID_PARAMETER;
+ return False;
+ }
+
+ /*
+ * Remember the padding length. We must remove it from the real data
+ * stream once the sign/seal is done.
+ */
+
+ *p_ss_padding_len = auth_info.auth_pad_len;
+
+ return True;
+}
+
+/****************************************************************************
+ Deal with schannel processing on an RPC request.
+****************************************************************************/
+
+bool api_pipe_schannel_process(pipes_struct *p, prs_struct *rpc_in, uint32 *p_ss_padding_len)
+{
+ uint32 data_len;
+ uint32 auth_len;
+ uint32 save_offset = prs_offset(rpc_in);
+ RPC_HDR_AUTH auth_info;
+ RPC_AUTH_SCHANNEL_CHK schannel_chk;
+
+ auth_len = p->hdr.auth_len;
+
+ if (auth_len != RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN) {
+ DEBUG(0,("Incorrect auth_len %u.\n", (unsigned int)auth_len ));
+ return False;
+ }
+
+ /*
+ * The following is that length of the data we must verify or unseal.
+ * This doesn't include the RPC headers or the auth_len or the RPC_HDR_AUTH_LEN
+ * preceeding the auth_data.
+ */
+
+ if (p->hdr.frag_len < RPC_HEADER_LEN + RPC_HDR_REQ_LEN + RPC_HDR_AUTH_LEN + auth_len) {
+ DEBUG(0,("Incorrect frag %u, auth %u.\n",
+ (unsigned int)p->hdr.frag_len,
+ (unsigned int)auth_len ));
+ return False;
+ }
+
+ data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN -
+ RPC_HDR_AUTH_LEN - auth_len;
+
+ DEBUG(5,("data %d auth %d\n", data_len, auth_len));
+
+ if(!prs_set_offset(rpc_in, RPC_HDR_REQ_LEN + data_len)) {
+ DEBUG(0,("cannot move offset to %u.\n",
+ (unsigned int)RPC_HDR_REQ_LEN + data_len ));
+ return False;
+ }
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, rpc_in, 0)) {
+ DEBUG(0,("failed to unmarshall RPC_HDR_AUTH.\n"));
+ return False;
+ }
+
+ if (auth_info.auth_type != RPC_SCHANNEL_AUTH_TYPE) {
+ DEBUG(0,("Invalid auth info %d on schannel\n",
+ auth_info.auth_type));
+ return False;
+ }
+
+ if(!smb_io_rpc_auth_schannel_chk("", RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN, &schannel_chk, rpc_in, 0)) {
+ DEBUG(0,("failed to unmarshal RPC_AUTH_SCHANNEL_CHK.\n"));
+ return False;
+ }
+
+ if (!schannel_decode(p->auth.a_u.schannel_auth,
+ p->auth.auth_level,
+ SENDER_IS_INITIATOR,
+ &schannel_chk,
+ prs_data_p(rpc_in)+RPC_HDR_REQ_LEN, data_len)) {
+ DEBUG(3,("failed to decode PDU\n"));
+ return False;
+ }
+
+ /*
+ * Return the current pointer to the data offset.
+ */
+
+ if(!prs_set_offset(rpc_in, save_offset)) {
+ DEBUG(0,("failed to set offset back to %u\n",
+ (unsigned int)save_offset ));
+ return False;
+ }
+
+ /* The sequence number gets incremented on both send and receive. */
+ p->auth.a_u.schannel_auth->seq_num++;
+
+ /*
+ * Remember the padding length. We must remove it from the real data
+ * stream once the sign/seal is done.
+ */
+
+ *p_ss_padding_len = auth_info.auth_pad_len;
+
+ return True;
+}
+
+/****************************************************************************
+ Return a user struct for a pipe user.
+****************************************************************************/
+
+struct current_user *get_current_user(struct current_user *user, pipes_struct *p)
+{
+ if (p->pipe_bound &&
+ (p->auth.auth_type == PIPE_AUTH_TYPE_NTLMSSP ||
+ (p->auth.auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP))) {
+ memcpy(user, &p->pipe_user, sizeof(struct current_user));
+ } else {
+ memcpy(user, &current_user, sizeof(struct current_user));
+ }
+
+ return user;
+}
+
+/****************************************************************************
+ Find the set of RPC functions associated with this context_id
+****************************************************************************/
+
+static PIPE_RPC_FNS* find_pipe_fns_by_context( PIPE_RPC_FNS *list, uint32 context_id )
+{
+ PIPE_RPC_FNS *fns = NULL;
+ PIPE_RPC_FNS *tmp = NULL;
+
+ if ( !list ) {
+ DEBUG(0,("find_pipe_fns_by_context: ERROR! No context list for pipe!\n"));
+ return NULL;
+ }
+
+ for (tmp=list; tmp; tmp=tmp->next ) {
+ if ( tmp->context_id == context_id )
+ break;
+ }
+
+ fns = tmp;
+
+ return fns;
+}
+
+/****************************************************************************
+ Memory cleanup.
+****************************************************************************/
+
+void free_pipe_rpc_context( PIPE_RPC_FNS *list )
+{
+ PIPE_RPC_FNS *tmp = list;
+ PIPE_RPC_FNS *tmp2;
+
+ while (tmp) {
+ tmp2 = tmp->next;
+ SAFE_FREE(tmp);
+ tmp = tmp2;
+ }
+
+ return;
+}
+
+static bool api_rpcTNP(pipes_struct *p, const char *rpc_name,
+ const struct api_struct *api_rpc_cmds, int n_cmds);
+
+/****************************************************************************
+ Find the correct RPC function to call for this request.
+ If the pipe is authenticated then become the correct UNIX user
+ before doing the call.
+****************************************************************************/
+
+bool api_pipe_request(pipes_struct *p)
+{
+ bool ret = False;
+ bool changed_user = False;
+ PIPE_RPC_FNS *pipe_fns;
+
+ if (p->pipe_bound &&
+ ((p->auth.auth_type == PIPE_AUTH_TYPE_NTLMSSP) ||
+ (p->auth.auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP))) {
+ if(!become_authenticated_pipe_user(p)) {
+ prs_mem_free(&p->out_data.rdata);
+ return False;
+ }
+ changed_user = True;
+ }
+
+ DEBUG(5, ("Requested \\PIPE\\%s\n", p->name));
+
+ /* get the set of RPC functions for this context */
+
+ pipe_fns = find_pipe_fns_by_context(p->contexts, p->hdr_req.context_id);
+
+ if ( pipe_fns ) {
+ TALLOC_CTX *frame = talloc_stackframe();
+ ret = api_rpcTNP(p, p->name, pipe_fns->cmds, pipe_fns->n_cmds);
+ TALLOC_FREE(frame);
+ }
+ else {
+ DEBUG(0,("api_pipe_request: No rpc function table associated with context [%d] on pipe [%s]\n",
+ p->hdr_req.context_id, p->name));
+ }
+
+ if (changed_user) {
+ unbecome_authenticated_pipe_user();
+ }
+
+ return ret;
+}
+
+/*******************************************************************
+ Calls the underlying RPC function for a named pipe.
+ ********************************************************************/
+
+static bool api_rpcTNP(pipes_struct *p, const char *rpc_name,
+ const struct api_struct *api_rpc_cmds, int n_cmds)
+{
+ int fn_num;
+ fstring name;
+ uint32 offset1, offset2;
+
+ /* interpret the command */
+ DEBUG(4,("api_rpcTNP: %s op 0x%x - ", rpc_name, p->hdr_req.opnum));
+
+ slprintf(name, sizeof(name)-1, "in_%s", rpc_name);
+ prs_dump(name, p->hdr_req.opnum, &p->in_data.data);
+
+ for (fn_num = 0; fn_num < n_cmds; fn_num++) {
+ if (api_rpc_cmds[fn_num].opnum == p->hdr_req.opnum && api_rpc_cmds[fn_num].fn != NULL) {
+ DEBUG(3,("api_rpcTNP: rpc command: %s\n", api_rpc_cmds[fn_num].name));
+ break;
+ }
+ }
+
+ if (fn_num == n_cmds) {
+ /*
+ * For an unknown RPC just return a fault PDU but
+ * return True to allow RPC's on the pipe to continue
+ * and not put the pipe into fault state. JRA.
+ */
+ DEBUG(4, ("unknown\n"));
+ setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR));
+ return True;
+ }
+
+ offset1 = prs_offset(&p->out_data.rdata);
+
+ DEBUG(6, ("api_rpc_cmds[%d].fn == %p\n",
+ fn_num, api_rpc_cmds[fn_num].fn));
+ /* do the actual command */
+ if(!api_rpc_cmds[fn_num].fn(p)) {
+ DEBUG(0,("api_rpcTNP: %s: %s failed.\n", rpc_name, api_rpc_cmds[fn_num].name));
+ prs_mem_free(&p->out_data.rdata);
+ return False;
+ }
+
+ if (p->bad_handle_fault_state) {
+ DEBUG(4,("api_rpcTNP: bad handle fault return.\n"));
+ p->bad_handle_fault_state = False;
+ setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_CONTEXT_MISMATCH));
+ return True;
+ }
+
+ if (p->rng_fault_state) {
+ DEBUG(4, ("api_rpcTNP: rng fault return\n"));
+ p->rng_fault_state = False;
+ setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR));
+ return True;
+ }
+
+ slprintf(name, sizeof(name)-1, "out_%s", rpc_name);
+ offset2 = prs_offset(&p->out_data.rdata);
+ prs_set_offset(&p->out_data.rdata, offset1);
+ prs_dump(name, p->hdr_req.opnum, &p->out_data.rdata);
+ prs_set_offset(&p->out_data.rdata, offset2);
+
+ DEBUG(5,("api_rpcTNP: called %s successfully\n", rpc_name));
+
+ /* Check for buffer underflow in rpc parsing */
+
+ if ((DEBUGLEVEL >= 10) &&
+ (prs_offset(&p->in_data.data) != prs_data_size(&p->in_data.data))) {
+ size_t data_len = prs_data_size(&p->in_data.data) - prs_offset(&p->in_data.data);
+ char *data = (char *)SMB_MALLOC(data_len);
+
+ DEBUG(10, ("api_rpcTNP: rpc input buffer underflow (parse error?)\n"));
+ if (data) {
+ prs_uint8s(False, "", &p->in_data.data, 0, (unsigned char *)data, (uint32)data_len);
+ SAFE_FREE(data);
+ }
+
+ }
+
+ return True;
+}
diff --git a/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c
new file mode 100644
index 0000000000..3968d41168
--- /dev/null
+++ b/source3/rpc_server/srv_pipe_hnd.c
@@ -0,0 +1,1249 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Largely re-written : 2005
+ * Copyright (C) Jeremy Allison 1998 - 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+#define PIPE "\\PIPE\\"
+#define PIPELEN strlen(PIPE)
+
+static smb_np_struct *chain_p;
+static int pipes_open;
+
+/*
+ * Sometimes I can't decide if I hate Windows printer driver
+ * writers more than I hate the Windows spooler service driver
+ * writers. This gets around a combination of bugs in the spooler
+ * and the HP 8500 PCL driver that causes a spooler spin. JRA.
+ *
+ * bumped up from 20 -> 64 after viewing traffic from WordPerfect
+ * 2002 running on NT 4.- SP6
+ * bumped up from 64 -> 256 after viewing traffic from con2prt
+ * for lots of printers on a WinNT 4.x SP6 box.
+ */
+
+#ifndef MAX_OPEN_SPOOLSS_PIPES
+#define MAX_OPEN_SPOOLSS_PIPES 256
+#endif
+static int current_spoolss_pipes_open;
+
+static smb_np_struct *Pipes;
+static pipes_struct *InternalPipes;
+static struct bitmap *bmap;
+
+/* TODO
+ * the following prototypes are declared here to avoid
+ * code being moved about too much for a patch to be
+ * disrupted / less obvious.
+ *
+ * these functions, and associated functions that they
+ * call, should be moved behind a .so module-loading
+ * system _anyway_. so that's the next step...
+ */
+
+static int close_internal_rpc_pipe_hnd(struct pipes_struct *p);
+
+/****************************************************************************
+ Internal Pipe iterator functions.
+****************************************************************************/
+
+pipes_struct *get_first_internal_pipe(void)
+{
+ return InternalPipes;
+}
+
+pipes_struct *get_next_internal_pipe(pipes_struct *p)
+{
+ return p->next;
+}
+
+/* this must be larger than the sum of the open files and directories */
+static int pipe_handle_offset;
+
+/****************************************************************************
+ Set the pipe_handle_offset. Called from smbd/files.c
+****************************************************************************/
+
+void set_pipe_handle_offset(int max_open_files)
+{
+ if(max_open_files < 0x7000) {
+ pipe_handle_offset = 0x7000;
+ } else {
+ pipe_handle_offset = max_open_files + 10; /* For safety. :-) */
+ }
+}
+
+/****************************************************************************
+ Reset pipe chain handle number.
+****************************************************************************/
+
+void reset_chain_p(void)
+{
+ chain_p = NULL;
+}
+
+/****************************************************************************
+ Initialise pipe handle states.
+****************************************************************************/
+
+void init_rpc_pipe_hnd(void)
+{
+ bmap = bitmap_allocate(MAX_OPEN_PIPES);
+ if (!bmap) {
+ exit_server("out of memory in init_rpc_pipe_hnd");
+ }
+}
+
+/****************************************************************************
+ Initialise an outgoing packet.
+****************************************************************************/
+
+static bool pipe_init_outgoing_data(pipes_struct *p)
+{
+ output_data *o_data = &p->out_data;
+
+ /* Reset the offset counters. */
+ o_data->data_sent_length = 0;
+ o_data->current_pdu_len = 0;
+ o_data->current_pdu_sent = 0;
+
+ memset(o_data->current_pdu, '\0', sizeof(o_data->current_pdu));
+
+ /* Free any memory in the current return data buffer. */
+ prs_mem_free(&o_data->rdata);
+
+ /*
+ * Initialize the outgoing RPC data buffer.
+ * we will use this as the raw data area for replying to rpc requests.
+ */
+ if(!prs_init(&o_data->rdata, RPC_MAX_PDU_FRAG_LEN, p->mem_ctx, MARSHALL)) {
+ DEBUG(0,("pipe_init_outgoing_data: malloc fail.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Find first available pipe slot.
+****************************************************************************/
+
+smb_np_struct *open_rpc_pipe_p(const char *pipe_name,
+ connection_struct *conn, uint16 vuid)
+{
+ int i;
+ smb_np_struct *p, *p_it;
+ static int next_pipe;
+ bool is_spoolss_pipe = False;
+
+ DEBUG(4,("Open pipe requested %s (pipes_open=%d)\n",
+ pipe_name, pipes_open));
+
+ if (strstr(pipe_name, "spoolss")) {
+ is_spoolss_pipe = True;
+ }
+
+ if (is_spoolss_pipe && current_spoolss_pipes_open >= MAX_OPEN_SPOOLSS_PIPES) {
+ DEBUG(10,("open_rpc_pipe_p: spooler bug workaround. Denying open on pipe %s\n",
+ pipe_name ));
+ return NULL;
+ }
+
+ /* not repeating pipe numbers makes it easier to track things in
+ log files and prevents client bugs where pipe numbers are reused
+ over connection restarts */
+
+ if (next_pipe == 0) {
+ next_pipe = (sys_getpid() ^ time(NULL)) % MAX_OPEN_PIPES;
+ }
+
+ i = bitmap_find(bmap, next_pipe);
+
+ if (i == -1) {
+ DEBUG(0,("ERROR! Out of pipe structures\n"));
+ return NULL;
+ }
+
+ next_pipe = (i+1) % MAX_OPEN_PIPES;
+
+ for (p = Pipes; p; p = p->next) {
+ DEBUG(5,("open_rpc_pipe_p: name %s pnum=%x\n", p->name, p->pnum));
+ }
+
+ p = talloc(NULL, smb_np_struct);
+ if (!p) {
+ DEBUG(0,("ERROR! no memory for smb_np_struct!\n"));
+ return NULL;
+ }
+
+ ZERO_STRUCTP(p);
+
+ p->name = talloc_strdup(p, pipe_name);
+ if (p->name == NULL) {
+ TALLOC_FREE(p);
+ DEBUG(0,("ERROR! no memory for pipe name!\n"));
+ return NULL;
+ }
+
+ /* add a dso mechanism instead of this, here */
+
+ p->namedpipe_create = make_internal_rpc_pipe_p;
+ p->namedpipe_read = read_from_internal_pipe;
+ p->namedpipe_write = write_to_internal_pipe;
+
+ p->np_state = p->namedpipe_create(pipe_name, conn->client_address,
+ conn->server_info, vuid);
+
+ if (p->np_state == NULL) {
+ DEBUG(0,("open_rpc_pipe_p: make_internal_rpc_pipe_p failed.\n"));
+ TALLOC_FREE(p);
+ return NULL;
+ }
+
+ DLIST_ADD(Pipes, p);
+
+ /*
+ * Initialize the incoming RPC data buffer with one PDU worth of memory.
+ * We cheat here and say we're marshalling, as we intend to add incoming
+ * data directly into the prs_struct and we want it to auto grow. We will
+ * change the type to UNMARSALLING before processing the stream.
+ */
+
+ bitmap_set(bmap, i);
+ i += pipe_handle_offset;
+
+ pipes_open++;
+
+ p->pnum = i;
+
+ p->open = True;
+ p->device_state = 0;
+ p->priority = 0;
+ p->conn = conn;
+ p->vuid = vuid;
+
+ p->max_trans_reply = 0;
+
+ DEBUG(4,("Opened pipe %s with handle %x (pipes_open=%d)\n",
+ pipe_name, i, pipes_open));
+
+ chain_p = p;
+
+ /* Iterate over p_it as a temp variable, to display all open pipes */
+ for (p_it = Pipes; p_it; p_it = p_it->next) {
+ DEBUG(5,("open pipes: name %s pnum=%x\n", p_it->name, p_it->pnum));
+ }
+
+ return chain_p;
+}
+
+/****************************************************************************
+ Make an internal namedpipes structure
+****************************************************************************/
+
+struct pipes_struct *make_internal_rpc_pipe_p(const char *pipe_name,
+ const char *client_address,
+ struct auth_serversupplied_info *server_info,
+ uint16_t vuid)
+{
+ pipes_struct *p;
+
+ DEBUG(4,("Create pipe requested %s\n", pipe_name));
+
+ p = TALLOC_ZERO_P(NULL, pipes_struct);
+
+ if (!p) {
+ DEBUG(0,("ERROR! no memory for pipes_struct!\n"));
+ return NULL;
+ }
+
+ if ((p->mem_ctx = talloc_init("pipe %s %p", pipe_name, p)) == NULL) {
+ DEBUG(0,("open_rpc_pipe_p: talloc_init failed.\n"));
+ TALLOC_FREE(p);
+ return NULL;
+ }
+
+ if (!init_pipe_handle_list(p, pipe_name)) {
+ DEBUG(0,("open_rpc_pipe_p: init_pipe_handles failed.\n"));
+ talloc_destroy(p->mem_ctx);
+ TALLOC_FREE(p);
+ return NULL;
+ }
+
+ /*
+ * Initialize the incoming RPC data buffer with one PDU worth of memory.
+ * We cheat here and say we're marshalling, as we intend to add incoming
+ * data directly into the prs_struct and we want it to auto grow. We will
+ * change the type to UNMARSALLING before processing the stream.
+ */
+
+ if(!prs_init(&p->in_data.data, RPC_MAX_PDU_FRAG_LEN, p->mem_ctx, MARSHALL)) {
+ DEBUG(0,("open_rpc_pipe_p: malloc fail for in_data struct.\n"));
+ talloc_destroy(p->mem_ctx);
+ close_policy_by_pipe(p);
+ TALLOC_FREE(p);
+ return NULL;
+ }
+
+ p->server_info = copy_serverinfo(p, server_info);
+ if (p->server_info == NULL) {
+ DEBUG(0, ("open_rpc_pipe_p: copy_serverinfo failed\n"));
+ talloc_destroy(p->mem_ctx);
+ close_policy_by_pipe(p);
+ TALLOC_FREE(p);
+ return NULL;
+ }
+
+ DLIST_ADD(InternalPipes, p);
+
+ memcpy(p->client_address, client_address, sizeof(p->client_address));
+
+ p->endian = RPC_LITTLE_ENDIAN;
+
+ ZERO_STRUCT(p->pipe_user);
+
+ p->pipe_user.vuid = vuid;
+ p->pipe_user.ut.uid = (uid_t)-1;
+ p->pipe_user.ut.gid = (gid_t)-1;
+ p->pipe_user.nt_user_token = dup_nt_token(NULL, server_info->ptok);
+
+ /*
+ * Initialize the outgoing RPC data buffer with no memory.
+ */
+ prs_init_empty(&p->out_data.rdata, p->mem_ctx, MARSHALL);
+
+ fstrcpy(p->name, pipe_name);
+
+ DEBUG(4,("Created internal pipe %s (pipes_open=%d)\n",
+ pipe_name, pipes_open));
+
+ talloc_set_destructor(p, close_internal_rpc_pipe_hnd);
+
+ return p;
+}
+
+/****************************************************************************
+ Sets the fault state on incoming packets.
+****************************************************************************/
+
+static void set_incoming_fault(pipes_struct *p)
+{
+ prs_mem_free(&p->in_data.data);
+ p->in_data.pdu_needed_len = 0;
+ p->in_data.pdu_received_len = 0;
+ p->fault_state = True;
+ DEBUG(10, ("set_incoming_fault: Setting fault state on pipe %s\n",
+ p->name));
+}
+
+/****************************************************************************
+ Ensures we have at least RPC_HEADER_LEN amount of data in the incoming buffer.
+****************************************************************************/
+
+static ssize_t fill_rpc_header(pipes_struct *p, char *data, size_t data_to_copy)
+{
+ size_t len_needed_to_complete_hdr = MIN(data_to_copy, RPC_HEADER_LEN - p->in_data.pdu_received_len);
+
+ DEBUG(10,("fill_rpc_header: data_to_copy = %u, len_needed_to_complete_hdr = %u, receive_len = %u\n",
+ (unsigned int)data_to_copy, (unsigned int)len_needed_to_complete_hdr,
+ (unsigned int)p->in_data.pdu_received_len ));
+
+ memcpy((char *)&p->in_data.current_in_pdu[p->in_data.pdu_received_len], data, len_needed_to_complete_hdr);
+ p->in_data.pdu_received_len += len_needed_to_complete_hdr;
+
+ return (ssize_t)len_needed_to_complete_hdr;
+}
+
+/****************************************************************************
+ Unmarshalls a new PDU header. Assumes the raw header data is in current_in_pdu.
+****************************************************************************/
+
+static ssize_t unmarshall_rpc_header(pipes_struct *p)
+{
+ /*
+ * Unmarshall the header to determine the needed length.
+ */
+
+ prs_struct rpc_in;
+
+ if(p->in_data.pdu_received_len != RPC_HEADER_LEN) {
+ DEBUG(0,("unmarshall_rpc_header: assert on rpc header length failed.\n"));
+ set_incoming_fault(p);
+ return -1;
+ }
+
+ prs_init_empty( &rpc_in, p->mem_ctx, UNMARSHALL);
+ prs_set_endian_data( &rpc_in, p->endian);
+
+ prs_give_memory( &rpc_in, (char *)&p->in_data.current_in_pdu[0],
+ p->in_data.pdu_received_len, False);
+
+ /*
+ * Unmarshall the header as this will tell us how much
+ * data we need to read to get the complete pdu.
+ * This also sets the endian flag in rpc_in.
+ */
+
+ if(!smb_io_rpc_hdr("", &p->hdr, &rpc_in, 0)) {
+ DEBUG(0,("unmarshall_rpc_header: failed to unmarshall RPC_HDR.\n"));
+ set_incoming_fault(p);
+ prs_mem_free(&rpc_in);
+ return -1;
+ }
+
+ /*
+ * Validate the RPC header.
+ */
+
+ if(p->hdr.major != 5 && p->hdr.minor != 0) {
+ DEBUG(0,("unmarshall_rpc_header: invalid major/minor numbers in RPC_HDR.\n"));
+ set_incoming_fault(p);
+ prs_mem_free(&rpc_in);
+ return -1;
+ }
+
+ /*
+ * If there's not data in the incoming buffer this should be the start of a new RPC.
+ */
+
+ if(prs_offset(&p->in_data.data) == 0) {
+
+ /*
+ * AS/U doesn't set FIRST flag in a BIND packet it seems.
+ */
+
+ if ((p->hdr.pkt_type == RPC_REQUEST) && !(p->hdr.flags & RPC_FLG_FIRST)) {
+ /*
+ * Ensure that the FIRST flag is set. If not then we have
+ * a stream missmatch.
+ */
+
+ DEBUG(0,("unmarshall_rpc_header: FIRST flag not set in first PDU !\n"));
+ set_incoming_fault(p);
+ prs_mem_free(&rpc_in);
+ return -1;
+ }
+
+ /*
+ * If this is the first PDU then set the endianness
+ * flag in the pipe. We will need this when parsing all
+ * data in this RPC.
+ */
+
+ p->endian = rpc_in.bigendian_data;
+
+ DEBUG(5,("unmarshall_rpc_header: using %sendian RPC\n",
+ p->endian == RPC_LITTLE_ENDIAN ? "little-" : "big-" ));
+
+ } else {
+
+ /*
+ * If this is *NOT* the first PDU then check the endianness
+ * flag in the pipe is the same as that in the PDU.
+ */
+
+ if (p->endian != rpc_in.bigendian_data) {
+ DEBUG(0,("unmarshall_rpc_header: FIRST endianness flag (%d) different in next PDU !\n", (int)p->endian));
+ set_incoming_fault(p);
+ prs_mem_free(&rpc_in);
+ return -1;
+ }
+ }
+
+ /*
+ * Ensure that the pdu length is sane.
+ */
+
+ if((p->hdr.frag_len < RPC_HEADER_LEN) || (p->hdr.frag_len > RPC_MAX_PDU_FRAG_LEN)) {
+ DEBUG(0,("unmarshall_rpc_header: assert on frag length failed.\n"));
+ set_incoming_fault(p);
+ prs_mem_free(&rpc_in);
+ return -1;
+ }
+
+ DEBUG(10,("unmarshall_rpc_header: type = %u, flags = %u\n", (unsigned int)p->hdr.pkt_type,
+ (unsigned int)p->hdr.flags ));
+
+ p->in_data.pdu_needed_len = (uint32)p->hdr.frag_len - RPC_HEADER_LEN;
+
+ prs_mem_free(&rpc_in);
+
+ return 0; /* No extra data processed. */
+}
+
+/****************************************************************************
+ Call this to free any talloc'ed memory. Do this before and after processing
+ a complete PDU.
+****************************************************************************/
+
+static void free_pipe_context(pipes_struct *p)
+{
+ if (p->mem_ctx) {
+ DEBUG(3,("free_pipe_context: destroying talloc pool of size "
+ "%lu\n", (unsigned long)talloc_total_size(p->mem_ctx) ));
+ talloc_free_children(p->mem_ctx);
+ } else {
+ p->mem_ctx = talloc_init("pipe %s %p", p->name, p);
+ if (p->mem_ctx == NULL) {
+ p->fault_state = True;
+ }
+ }
+}
+
+/****************************************************************************
+ Processes a request pdu. This will do auth processing if needed, and
+ appends the data into the complete stream if the LAST flag is not set.
+****************************************************************************/
+
+static bool process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p)
+{
+ uint32 ss_padding_len = 0;
+ size_t data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN -
+ (p->hdr.auth_len ? RPC_HDR_AUTH_LEN : 0) - p->hdr.auth_len;
+
+ if(!p->pipe_bound) {
+ DEBUG(0,("process_request_pdu: rpc request with no bind.\n"));
+ set_incoming_fault(p);
+ return False;
+ }
+
+ /*
+ * Check if we need to do authentication processing.
+ * This is only done on requests, not binds.
+ */
+
+ /*
+ * Read the RPC request header.
+ */
+
+ if(!smb_io_rpc_hdr_req("req", &p->hdr_req, rpc_in_p, 0)) {
+ DEBUG(0,("process_request_pdu: failed to unmarshall RPC_HDR_REQ.\n"));
+ set_incoming_fault(p);
+ return False;
+ }
+
+ switch(p->auth.auth_type) {
+ case PIPE_AUTH_TYPE_NONE:
+ break;
+
+ case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP:
+ case PIPE_AUTH_TYPE_NTLMSSP:
+ {
+ NTSTATUS status;
+ if(!api_pipe_ntlmssp_auth_process(p, rpc_in_p, &ss_padding_len, &status)) {
+ DEBUG(0,("process_request_pdu: failed to do auth processing.\n"));
+ DEBUG(0,("process_request_pdu: error was %s.\n", nt_errstr(status) ));
+ set_incoming_fault(p);
+ return False;
+ }
+ break;
+ }
+
+ case PIPE_AUTH_TYPE_SCHANNEL:
+ if (!api_pipe_schannel_process(p, rpc_in_p, &ss_padding_len)) {
+ DEBUG(3,("process_request_pdu: failed to do schannel processing.\n"));
+ set_incoming_fault(p);
+ return False;
+ }
+ break;
+
+ default:
+ DEBUG(0,("process_request_pdu: unknown auth type %u set.\n", (unsigned int)p->auth.auth_type ));
+ set_incoming_fault(p);
+ return False;
+ }
+
+ /* Now we've done the sign/seal we can remove any padding data. */
+ if (data_len > ss_padding_len) {
+ data_len -= ss_padding_len;
+ }
+
+ /*
+ * Check the data length doesn't go over the 15Mb limit.
+ * increased after observing a bug in the Windows NT 4.0 SP6a
+ * spoolsv.exe when the response to a GETPRINTERDRIVER2 RPC
+ * will not fit in the initial buffer of size 0x1068 --jerry 22/01/2002
+ */
+
+ if(prs_offset(&p->in_data.data) + data_len > 15*1024*1024) {
+ DEBUG(0,("process_request_pdu: rpc data buffer too large (%u) + (%u)\n",
+ (unsigned int)prs_data_size(&p->in_data.data), (unsigned int)data_len ));
+ set_incoming_fault(p);
+ return False;
+ }
+
+ /*
+ * Append the data portion into the buffer and return.
+ */
+
+ if(!prs_append_some_prs_data(&p->in_data.data, rpc_in_p, prs_offset(rpc_in_p), data_len)) {
+ DEBUG(0,("process_request_pdu: Unable to append data size %u to parse buffer of size %u.\n",
+ (unsigned int)data_len, (unsigned int)prs_data_size(&p->in_data.data) ));
+ set_incoming_fault(p);
+ return False;
+ }
+
+ if(p->hdr.flags & RPC_FLG_LAST) {
+ bool ret = False;
+ /*
+ * Ok - we finally have a complete RPC stream.
+ * Call the rpc command to process it.
+ */
+
+ /*
+ * Ensure the internal prs buffer size is *exactly* the same
+ * size as the current offset.
+ */
+
+ if(!prs_set_buffer_size(&p->in_data.data, prs_offset(&p->in_data.data))) {
+ DEBUG(0,("process_request_pdu: Call to prs_set_buffer_size failed!\n"));
+ set_incoming_fault(p);
+ return False;
+ }
+
+ /*
+ * Set the parse offset to the start of the data and set the
+ * prs_struct to UNMARSHALL.
+ */
+
+ prs_set_offset(&p->in_data.data, 0);
+ prs_switch_type(&p->in_data.data, UNMARSHALL);
+
+ /*
+ * Process the complete data stream here.
+ */
+
+ free_pipe_context(p);
+
+ if(pipe_init_outgoing_data(p)) {
+ ret = api_pipe_request(p);
+ }
+
+ free_pipe_context(p);
+
+ /*
+ * We have consumed the whole data stream. Set back to
+ * marshalling and set the offset back to the start of
+ * the buffer to re-use it (we could also do a prs_mem_free()
+ * and then re_init on the next start of PDU. Not sure which
+ * is best here.... JRA.
+ */
+
+ prs_switch_type(&p->in_data.data, MARSHALL);
+ prs_set_offset(&p->in_data.data, 0);
+ return ret;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Processes a finished PDU stored in current_in_pdu. The RPC_HEADER has
+ already been parsed and stored in p->hdr.
+****************************************************************************/
+
+static void process_complete_pdu(pipes_struct *p)
+{
+ prs_struct rpc_in;
+ size_t data_len = p->in_data.pdu_received_len - RPC_HEADER_LEN;
+ char *data_p = (char *)&p->in_data.current_in_pdu[RPC_HEADER_LEN];
+ bool reply = False;
+
+ if(p->fault_state) {
+ DEBUG(10,("process_complete_pdu: pipe %s in fault state.\n",
+ p->name ));
+ set_incoming_fault(p);
+ setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR));
+ return;
+ }
+
+ prs_init_empty( &rpc_in, p->mem_ctx, UNMARSHALL);
+
+ /*
+ * Ensure we're using the corrent endianness for both the
+ * RPC header flags and the raw data we will be reading from.
+ */
+
+ prs_set_endian_data( &rpc_in, p->endian);
+ prs_set_endian_data( &p->in_data.data, p->endian);
+
+ prs_give_memory( &rpc_in, data_p, (uint32)data_len, False);
+
+ DEBUG(10,("process_complete_pdu: processing packet type %u\n",
+ (unsigned int)p->hdr.pkt_type ));
+
+ switch (p->hdr.pkt_type) {
+ case RPC_REQUEST:
+ reply = process_request_pdu(p, &rpc_in);
+ break;
+
+ case RPC_PING: /* CL request - ignore... */
+ DEBUG(0,("process_complete_pdu: Error. Connectionless packet type %u received on pipe %s.\n",
+ (unsigned int)p->hdr.pkt_type, p->name));
+ break;
+
+ case RPC_RESPONSE: /* No responses here. */
+ DEBUG(0,("process_complete_pdu: Error. RPC_RESPONSE received from client on pipe %s.\n",
+ p->name ));
+ break;
+
+ case RPC_FAULT:
+ case RPC_WORKING: /* CL request - reply to a ping when a call in process. */
+ case RPC_NOCALL: /* CL - server reply to a ping call. */
+ case RPC_REJECT:
+ case RPC_ACK:
+ case RPC_CL_CANCEL:
+ case RPC_FACK:
+ case RPC_CANCEL_ACK:
+ DEBUG(0,("process_complete_pdu: Error. Connectionless packet type %u received on pipe %s.\n",
+ (unsigned int)p->hdr.pkt_type, p->name));
+ break;
+
+ case RPC_BIND:
+ /*
+ * We assume that a pipe bind is only in one pdu.
+ */
+ if(pipe_init_outgoing_data(p)) {
+ reply = api_pipe_bind_req(p, &rpc_in);
+ }
+ break;
+
+ case RPC_BINDACK:
+ case RPC_BINDNACK:
+ DEBUG(0,("process_complete_pdu: Error. RPC_BINDACK/RPC_BINDNACK packet type %u received on pipe %s.\n",
+ (unsigned int)p->hdr.pkt_type, p->name));
+ break;
+
+
+ case RPC_ALTCONT:
+ /*
+ * We assume that a pipe bind is only in one pdu.
+ */
+ if(pipe_init_outgoing_data(p)) {
+ reply = api_pipe_alter_context(p, &rpc_in);
+ }
+ break;
+
+ case RPC_ALTCONTRESP:
+ DEBUG(0,("process_complete_pdu: Error. RPC_ALTCONTRESP on pipe %s: Should only be server -> client.\n",
+ p->name));
+ break;
+
+ case RPC_AUTH3:
+ /*
+ * The third packet in an NTLMSSP auth exchange.
+ */
+ if(pipe_init_outgoing_data(p)) {
+ reply = api_pipe_bind_auth3(p, &rpc_in);
+ }
+ break;
+
+ case RPC_SHUTDOWN:
+ DEBUG(0,("process_complete_pdu: Error. RPC_SHUTDOWN on pipe %s: Should only be server -> client.\n",
+ p->name));
+ break;
+
+ case RPC_CO_CANCEL:
+ /* For now just free all client data and continue processing. */
+ DEBUG(3,("process_complete_pdu: RPC_ORPHANED. Abandoning rpc call.\n"));
+ /* As we never do asynchronous RPC serving, we can never cancel a
+ call (as far as I know). If we ever did we'd have to send a cancel_ack
+ reply. For now, just free all client data and continue processing. */
+ reply = True;
+ break;
+#if 0
+ /* Enable this if we're doing async rpc. */
+ /* We must check the call-id matches the outstanding callid. */
+ if(pipe_init_outgoing_data(p)) {
+ /* Send a cancel_ack PDU reply. */
+ /* We should probably check the auth-verifier here. */
+ reply = setup_cancel_ack_reply(p, &rpc_in);
+ }
+ break;
+#endif
+
+ case RPC_ORPHANED:
+ /* We should probably check the auth-verifier here.
+ For now just free all client data and continue processing. */
+ DEBUG(3,("process_complete_pdu: RPC_ORPHANED. Abandoning rpc call.\n"));
+ reply = True;
+ break;
+
+ default:
+ DEBUG(0,("process_complete_pdu: Unknown rpc type = %u received.\n", (unsigned int)p->hdr.pkt_type ));
+ break;
+ }
+
+ /* Reset to little endian. Probably don't need this but it won't hurt. */
+ prs_set_endian_data( &p->in_data.data, RPC_LITTLE_ENDIAN);
+
+ if (!reply) {
+ DEBUG(3,("process_complete_pdu: DCE/RPC fault sent on pipe %s\n", p->pipe_srv_name));
+ set_incoming_fault(p);
+ setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR));
+ prs_mem_free(&rpc_in);
+ } else {
+ /*
+ * Reset the lengths. We're ready for a new pdu.
+ */
+ p->in_data.pdu_needed_len = 0;
+ p->in_data.pdu_received_len = 0;
+ }
+
+ prs_mem_free(&rpc_in);
+}
+
+/****************************************************************************
+ Accepts incoming data on an rpc pipe. Processes the data in pdu sized units.
+****************************************************************************/
+
+static ssize_t process_incoming_data(pipes_struct *p, char *data, size_t n)
+{
+ size_t data_to_copy = MIN(n, RPC_MAX_PDU_FRAG_LEN - p->in_data.pdu_received_len);
+
+ DEBUG(10,("process_incoming_data: Start: pdu_received_len = %u, pdu_needed_len = %u, incoming data = %u\n",
+ (unsigned int)p->in_data.pdu_received_len, (unsigned int)p->in_data.pdu_needed_len,
+ (unsigned int)n ));
+
+ if(data_to_copy == 0) {
+ /*
+ * This is an error - data is being received and there is no
+ * space in the PDU. Free the received data and go into the fault state.
+ */
+ DEBUG(0,("process_incoming_data: No space in incoming pdu buffer. Current size = %u \
+incoming data size = %u\n", (unsigned int)p->in_data.pdu_received_len, (unsigned int)n ));
+ set_incoming_fault(p);
+ return -1;
+ }
+
+ /*
+ * If we have no data already, wait until we get at least a RPC_HEADER_LEN
+ * number of bytes before we can do anything.
+ */
+
+ if((p->in_data.pdu_needed_len == 0) && (p->in_data.pdu_received_len < RPC_HEADER_LEN)) {
+ /*
+ * Always return here. If we have more data then the RPC_HEADER
+ * will be processed the next time around the loop.
+ */
+ return fill_rpc_header(p, data, data_to_copy);
+ }
+
+ /*
+ * At this point we know we have at least an RPC_HEADER_LEN amount of data
+ * stored in current_in_pdu.
+ */
+
+ /*
+ * If pdu_needed_len is zero this is a new pdu.
+ * Unmarshall the header so we know how much more
+ * data we need, then loop again.
+ */
+
+ if(p->in_data.pdu_needed_len == 0) {
+ ssize_t rret = unmarshall_rpc_header(p);
+ if (rret == -1 || p->in_data.pdu_needed_len > 0) {
+ return rret;
+ }
+ /* If rret == 0 and pdu_needed_len == 0 here we have a PDU that consists
+ of an RPC_HEADER only. This is a RPC_SHUTDOWN, RPC_CO_CANCEL or RPC_ORPHANED
+ pdu type. Deal with this in process_complete_pdu(). */
+ }
+
+ /*
+ * Ok - at this point we have a valid RPC_HEADER in p->hdr.
+ * Keep reading until we have a full pdu.
+ */
+
+ data_to_copy = MIN(data_to_copy, p->in_data.pdu_needed_len);
+
+ /*
+ * Copy as much of the data as we need into the current_in_pdu buffer.
+ * pdu_needed_len becomes zero when we have a complete pdu.
+ */
+
+ memcpy( (char *)&p->in_data.current_in_pdu[p->in_data.pdu_received_len], data, data_to_copy);
+ p->in_data.pdu_received_len += data_to_copy;
+ p->in_data.pdu_needed_len -= data_to_copy;
+
+ /*
+ * Do we have a complete PDU ?
+ * (return the number of bytes handled in the call)
+ */
+
+ if(p->in_data.pdu_needed_len == 0) {
+ process_complete_pdu(p);
+ return data_to_copy;
+ }
+
+ DEBUG(10,("process_incoming_data: not a complete PDU yet. pdu_received_len = %u, pdu_needed_len = %u\n",
+ (unsigned int)p->in_data.pdu_received_len, (unsigned int)p->in_data.pdu_needed_len ));
+
+ return (ssize_t)data_to_copy;
+}
+
+/****************************************************************************
+ Accepts incoming data on an rpc pipe.
+****************************************************************************/
+
+ssize_t write_to_pipe(smb_np_struct *p, char *data, size_t n)
+{
+ DEBUG(6,("write_to_pipe: %x", p->pnum));
+
+ DEBUG(6,(" name: %s open: %s len: %d\n",
+ p->name, BOOLSTR(p->open), (int)n));
+
+ dump_data(50, (uint8 *)data, n);
+
+ return p->namedpipe_write(p->np_state, data, n);
+}
+
+/****************************************************************************
+ Accepts incoming data on an internal rpc pipe.
+****************************************************************************/
+
+ssize_t write_to_internal_pipe(struct pipes_struct *p, char *data, size_t n)
+{
+ size_t data_left = n;
+
+ while(data_left) {
+ ssize_t data_used;
+
+ DEBUG(10,("write_to_pipe: data_left = %u\n", (unsigned int)data_left ));
+
+ data_used = process_incoming_data(p, data, data_left);
+
+ DEBUG(10,("write_to_pipe: data_used = %d\n", (int)data_used ));
+
+ if(data_used < 0) {
+ return -1;
+ }
+
+ data_left -= data_used;
+ data += data_used;
+ }
+
+ return n;
+}
+
+/****************************************************************************
+ Replies to a request to read data from a pipe.
+
+ Headers are interspersed with the data at PDU intervals. By the time
+ this function is called, the start of the data could possibly have been
+ read by an SMBtrans (file_offset != 0).
+
+ Calling create_rpc_reply() here is a hack. The data should already
+ have been prepared into arrays of headers + data stream sections.
+****************************************************************************/
+
+ssize_t read_from_pipe(smb_np_struct *p, char *data, size_t n,
+ bool *is_data_outstanding)
+{
+ if (!p || !p->open) {
+ DEBUG(0,("read_from_pipe: pipe not open\n"));
+ return -1;
+ }
+
+ DEBUG(6,("read_from_pipe: %x", p->pnum));
+
+ return p->namedpipe_read(p->np_state, data, n, is_data_outstanding);
+}
+
+/****************************************************************************
+ Replies to a request to read data from a pipe.
+
+ Headers are interspersed with the data at PDU intervals. By the time
+ this function is called, the start of the data could possibly have been
+ read by an SMBtrans (file_offset != 0).
+
+ Calling create_rpc_reply() here is a hack. The data should already
+ have been prepared into arrays of headers + data stream sections.
+****************************************************************************/
+
+ssize_t read_from_internal_pipe(struct pipes_struct *p, char *data, size_t n,
+ bool *is_data_outstanding)
+{
+ uint32 pdu_remaining = 0;
+ ssize_t data_returned = 0;
+
+ if (!p) {
+ DEBUG(0,("read_from_pipe: pipe not open\n"));
+ return -1;
+ }
+
+ DEBUG(6,(" name: %s len: %u\n", p->name, (unsigned int)n));
+
+ /*
+ * We cannot return more than one PDU length per
+ * read request.
+ */
+
+ /*
+ * This condition should result in the connection being closed.
+ * Netapp filers seem to set it to 0xffff which results in domain
+ * authentications failing. Just ignore it so things work.
+ */
+
+ if(n > RPC_MAX_PDU_FRAG_LEN) {
+ DEBUG(5,("read_from_pipe: too large read (%u) requested on \
+pipe %s. We can only service %d sized reads.\n", (unsigned int)n, p->name, RPC_MAX_PDU_FRAG_LEN ));
+ n = RPC_MAX_PDU_FRAG_LEN;
+ }
+
+ /*
+ * Determine if there is still data to send in the
+ * pipe PDU buffer. Always send this first. Never
+ * send more than is left in the current PDU. The
+ * client should send a new read request for a new
+ * PDU.
+ */
+
+ if((pdu_remaining = p->out_data.current_pdu_len - p->out_data.current_pdu_sent) > 0) {
+ data_returned = (ssize_t)MIN(n, pdu_remaining);
+
+ DEBUG(10,("read_from_pipe: %s: current_pdu_len = %u, current_pdu_sent = %u \
+returning %d bytes.\n", p->name, (unsigned int)p->out_data.current_pdu_len,
+ (unsigned int)p->out_data.current_pdu_sent, (int)data_returned));
+
+ memcpy( data, &p->out_data.current_pdu[p->out_data.current_pdu_sent], (size_t)data_returned);
+ p->out_data.current_pdu_sent += (uint32)data_returned;
+ goto out;
+ }
+
+ /*
+ * At this point p->current_pdu_len == p->current_pdu_sent (which
+ * may of course be zero if this is the first return fragment.
+ */
+
+ DEBUG(10,("read_from_pipe: %s: fault_state = %d : data_sent_length \
+= %u, prs_offset(&p->out_data.rdata) = %u.\n",
+ p->name, (int)p->fault_state, (unsigned int)p->out_data.data_sent_length, (unsigned int)prs_offset(&p->out_data.rdata) ));
+
+ if(p->out_data.data_sent_length >= prs_offset(&p->out_data.rdata)) {
+ /*
+ * We have sent all possible data, return 0.
+ */
+ data_returned = 0;
+ goto out;
+ }
+
+ /*
+ * We need to create a new PDU from the data left in p->rdata.
+ * Create the header/data/footers. This also sets up the fields
+ * p->current_pdu_len, p->current_pdu_sent, p->data_sent_length
+ * and stores the outgoing PDU in p->current_pdu.
+ */
+
+ if(!create_next_pdu(p)) {
+ DEBUG(0,("read_from_pipe: %s: create_next_pdu failed.\n", p->name));
+ return -1;
+ }
+
+ data_returned = MIN(n, p->out_data.current_pdu_len);
+
+ memcpy( data, p->out_data.current_pdu, (size_t)data_returned);
+ p->out_data.current_pdu_sent += (uint32)data_returned;
+
+ out:
+
+ (*is_data_outstanding) = p->out_data.current_pdu_len > n;
+ return data_returned;
+}
+
+/****************************************************************************
+ Wait device state on a pipe. Exactly what this is for is unknown...
+****************************************************************************/
+
+bool wait_rpc_pipe_hnd_state(smb_np_struct *p, uint16 priority)
+{
+ if (p == NULL) {
+ return False;
+ }
+
+ if (p->open) {
+ DEBUG(3,("wait_rpc_pipe_hnd_state: Setting pipe wait state priority=%x on pipe (name=%s)\n",
+ priority, p->name));
+
+ p->priority = priority;
+
+ return True;
+ }
+
+ DEBUG(3,("wait_rpc_pipe_hnd_state: Error setting pipe wait state priority=%x (name=%s)\n",
+ priority, p->name));
+ return False;
+}
+
+
+/****************************************************************************
+ Set device state on a pipe. Exactly what this is for is unknown...
+****************************************************************************/
+
+bool set_rpc_pipe_hnd_state(smb_np_struct *p, uint16 device_state)
+{
+ if (p == NULL) {
+ return False;
+ }
+
+ if (p->open) {
+ DEBUG(3,("set_rpc_pipe_hnd_state: Setting pipe device state=%x on pipe (name=%s)\n",
+ device_state, p->name));
+
+ p->device_state = device_state;
+
+ return True;
+ }
+
+ DEBUG(3,("set_rpc_pipe_hnd_state: Error setting pipe device state=%x (name=%s)\n",
+ device_state, p->name));
+ return False;
+}
+
+
+/****************************************************************************
+ Close an rpc pipe.
+****************************************************************************/
+
+bool close_rpc_pipe_hnd(smb_np_struct *p)
+{
+ if (!p) {
+ DEBUG(0,("Invalid pipe in close_rpc_pipe_hnd\n"));
+ return False;
+ }
+
+ TALLOC_FREE(p->np_state);
+
+ 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);
+
+ /* TODO: Remove from pipe open db */
+
+ if ( !delete_pipe_opendb( p ) ) {
+ DEBUG(3,("close_rpc_pipe_hnd: failed to delete %s "
+ "pipe from open db.\n", p->name));
+ }
+
+ TALLOC_FREE(p);
+
+ return True;
+}
+
+/****************************************************************************
+ Close all pipes on a connection.
+****************************************************************************/
+
+void pipe_close_conn(connection_struct *conn)
+{
+ smb_np_struct *p, *next;
+
+ for (p=Pipes;p;p=next) {
+ next = p->next;
+ if (p->conn == conn) {
+ close_rpc_pipe_hnd(p);
+ }
+ }
+}
+
+/****************************************************************************
+ Close an rpc pipe.
+****************************************************************************/
+
+static int close_internal_rpc_pipe_hnd(struct pipes_struct *p)
+{
+ if (!p) {
+ DEBUG(0,("Invalid pipe in close_internal_rpc_pipe_hnd\n"));
+ return False;
+ }
+
+ prs_mem_free(&p->out_data.rdata);
+ prs_mem_free(&p->in_data.data);
+
+ if (p->auth.auth_data_free_func) {
+ (*p->auth.auth_data_free_func)(&p->auth);
+ }
+
+ if (p->mem_ctx) {
+ talloc_destroy(p->mem_ctx);
+ }
+
+ free_pipe_rpc_context( p->contexts );
+
+ /* Free the handles database. */
+ close_policy_by_pipe(p);
+
+ TALLOC_FREE(p->pipe_user.nt_user_token);
+ SAFE_FREE(p->pipe_user.ut.groups);
+
+ DLIST_REMOVE(InternalPipes, p);
+
+ ZERO_STRUCTP(p);
+
+ TALLOC_FREE(p);
+
+ return True;
+}
+
+/****************************************************************************
+ Find an rpc pipe given a pipe handle in a buffer and an offset.
+****************************************************************************/
+
+smb_np_struct *get_rpc_pipe_p(uint16 pnum)
+{
+ if (chain_p) {
+ return chain_p;
+ }
+
+ return get_rpc_pipe(pnum);
+}
+
+/****************************************************************************
+ Find an rpc pipe given a pipe handle.
+****************************************************************************/
+
+smb_np_struct *get_rpc_pipe(int pnum)
+{
+ smb_np_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/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c
new file mode 100644
index 0000000000..1b1e98c049
--- /dev/null
+++ b/source3/rpc_server/srv_samr_nt.c
@@ -0,0 +1,5956 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997,
+ * Copyright (C) Marc Jacobsen 1999,
+ * Copyright (C) Jeremy Allison 2001-2005,
+ * Copyright (C) Jean François Micouleau 1998-2001,
+ * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002,
+ * Copyright (C) Gerald (Jerry) Carter 2003-2004,
+ * Copyright (C) Simo Sorce 2003.
+ * Copyright (C) Volker Lendecke 2005.
+ * Copyright (C) Guenther Deschner 2008.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This is the implementation of the SAMR code.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+#define SAMR_USR_RIGHTS_WRITE_PW \
+ ( READ_CONTROL_ACCESS | \
+ SA_RIGHT_USER_CHANGE_PASSWORD | \
+ SA_RIGHT_USER_SET_LOC_COM )
+#define SAMR_USR_RIGHTS_CANT_WRITE_PW \
+ ( READ_CONTROL_ACCESS | SA_RIGHT_USER_SET_LOC_COM )
+
+#define DISP_INFO_CACHE_TIMEOUT 10
+
+typedef struct disp_info {
+ DOM_SID sid; /* identify which domain this is. */
+ bool builtin_domain; /* Quick flag to check if this is the builtin domain. */
+ struct pdb_search *users; /* querydispinfo 1 and 4 */
+ struct pdb_search *machines; /* querydispinfo 2 */
+ struct pdb_search *groups; /* querydispinfo 3 and 5, enumgroups */
+ struct pdb_search *aliases; /* enumaliases */
+
+ uint16 enum_acb_mask;
+ struct pdb_search *enum_users; /* enumusers with a mask */
+
+ struct timed_event *cache_timeout_event; /* cache idle timeout
+ * handler. */
+} DISP_INFO;
+
+/* We keep a static list of these by SID as modern clients close down
+ all resources between each request in a complete enumeration. */
+
+struct samr_info {
+ /* for use by the \PIPE\samr policy */
+ DOM_SID sid;
+ bool builtin_domain; /* Quick flag to check if this is the builtin domain. */
+ uint32 status; /* some sort of flag. best to record it. comes from opnum 0x39 */
+ uint32 acc_granted;
+ DISP_INFO *disp_info;
+ TALLOC_CTX *mem_ctx;
+};
+
+static const struct generic_mapping sam_generic_mapping = {
+ GENERIC_RIGHTS_SAM_READ,
+ GENERIC_RIGHTS_SAM_WRITE,
+ GENERIC_RIGHTS_SAM_EXECUTE,
+ GENERIC_RIGHTS_SAM_ALL_ACCESS};
+static const struct generic_mapping dom_generic_mapping = {
+ GENERIC_RIGHTS_DOMAIN_READ,
+ GENERIC_RIGHTS_DOMAIN_WRITE,
+ GENERIC_RIGHTS_DOMAIN_EXECUTE,
+ GENERIC_RIGHTS_DOMAIN_ALL_ACCESS};
+static const struct generic_mapping usr_generic_mapping = {
+ GENERIC_RIGHTS_USER_READ,
+ GENERIC_RIGHTS_USER_WRITE,
+ GENERIC_RIGHTS_USER_EXECUTE,
+ GENERIC_RIGHTS_USER_ALL_ACCESS};
+static const struct generic_mapping usr_nopwchange_generic_mapping = {
+ GENERIC_RIGHTS_USER_READ,
+ GENERIC_RIGHTS_USER_WRITE,
+ GENERIC_RIGHTS_USER_EXECUTE & ~SA_RIGHT_USER_CHANGE_PASSWORD,
+ GENERIC_RIGHTS_USER_ALL_ACCESS};
+static const struct generic_mapping grp_generic_mapping = {
+ GENERIC_RIGHTS_GROUP_READ,
+ GENERIC_RIGHTS_GROUP_WRITE,
+ GENERIC_RIGHTS_GROUP_EXECUTE,
+ GENERIC_RIGHTS_GROUP_ALL_ACCESS};
+static const struct generic_mapping ali_generic_mapping = {
+ GENERIC_RIGHTS_ALIAS_READ,
+ GENERIC_RIGHTS_ALIAS_WRITE,
+ GENERIC_RIGHTS_ALIAS_EXECUTE,
+ GENERIC_RIGHTS_ALIAS_ALL_ACCESS};
+
+/*******************************************************************
+*******************************************************************/
+
+static NTSTATUS make_samr_object_sd( TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd_size,
+ const struct generic_mapping *map,
+ DOM_SID *sid, uint32 sid_access )
+{
+ DOM_SID domadmin_sid;
+ SEC_ACE ace[5]; /* at most 5 entries */
+ SEC_ACCESS mask;
+ size_t i = 0;
+
+ SEC_ACL *psa = NULL;
+
+ /* basic access for Everyone */
+
+ init_sec_access(&mask, map->generic_execute | map->generic_read );
+ init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ /* add Full Access 'BUILTIN\Administrators' and 'BUILTIN\Account Operators */
+
+ init_sec_access(&mask, map->generic_all);
+
+ init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+ init_sec_ace(&ace[i++], &global_sid_Builtin_Account_Operators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ /* Add Full Access for Domain Admins if we are a DC */
+
+ if ( IS_DC ) {
+ sid_copy( &domadmin_sid, get_global_sam_sid() );
+ sid_append_rid( &domadmin_sid, DOMAIN_GROUP_RID_ADMINS );
+ init_sec_ace(&ace[i++], &domadmin_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+ }
+
+ /* if we have a sid, give it some special access */
+
+ if ( sid ) {
+ init_sec_access( &mask, sid_access );
+ init_sec_ace(&ace[i++], sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+ }
+
+ /* create the security descriptor */
+
+ if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if ((*psd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
+ SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL,
+ psa, sd_size)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Checks if access to an object should be granted, and returns that
+ level of access for further checks.
+********************************************************************/
+
+static NTSTATUS access_check_samr_object( SEC_DESC *psd, NT_USER_TOKEN *token,
+ SE_PRIV *rights, uint32 rights_mask,
+ uint32 des_access, uint32 *acc_granted,
+ const char *debug )
+{
+ NTSTATUS status = NT_STATUS_ACCESS_DENIED;
+ uint32 saved_mask = 0;
+
+ /* check privileges; certain SAM access bits should be overridden
+ by privileges (mostly having to do with creating/modifying/deleting
+ users and groups) */
+
+ if ( rights && user_has_any_privilege( token, rights ) ) {
+
+ saved_mask = (des_access & rights_mask);
+ des_access &= ~saved_mask;
+
+ DEBUG(4,("access_check_samr_object: user rights access mask [0x%x]\n",
+ rights_mask));
+ }
+
+
+ /* check the security descriptor first */
+
+ if ( se_access_check(psd, token, des_access, acc_granted, &status) )
+ goto done;
+
+ /* give root a free pass */
+
+ if ( geteuid() == sec_initial_uid() ) {
+
+ DEBUG(4,("%s: ACCESS should be DENIED (requested: %#010x)\n", debug, des_access));
+ DEBUGADD(4,("but overritten by euid == sec_initial_uid()\n"));
+
+ *acc_granted = des_access;
+
+ status = NT_STATUS_OK;
+ goto done;
+ }
+
+
+done:
+ /* add in any bits saved during the privilege check (only
+ matters is status is ok) */
+
+ *acc_granted |= rights_mask;
+
+ DEBUG(4,("%s: access %s (requested: 0x%08x, granted: 0x%08x)\n",
+ debug, NT_STATUS_IS_OK(status) ? "GRANTED" : "DENIED",
+ des_access, *acc_granted));
+
+ return status;
+}
+
+/*******************************************************************
+ Checks if access to a function can be granted
+********************************************************************/
+
+static NTSTATUS access_check_samr_function(uint32 acc_granted, uint32 acc_required, const char *debug)
+{
+ DEBUG(5,("%s: access check ((granted: %#010x; required: %#010x)\n",
+ debug, acc_granted, acc_required));
+
+ /* check the security descriptor first */
+
+ if ( (acc_granted&acc_required) == acc_required )
+ return NT_STATUS_OK;
+
+ /* give root a free pass */
+
+ if (geteuid() == sec_initial_uid()) {
+
+ DEBUG(4,("%s: ACCESS should be DENIED (granted: %#010x; required: %#010x)\n",
+ debug, acc_granted, acc_required));
+ DEBUGADD(4,("but overwritten by euid == 0\n"));
+
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(2,("%s: ACCESS DENIED (granted: %#010x; required: %#010x)\n",
+ debug, acc_granted, acc_required));
+
+ return NT_STATUS_ACCESS_DENIED;
+}
+
+/*******************************************************************
+ Fetch or create a dispinfo struct.
+********************************************************************/
+
+static DISP_INFO *get_samr_dispinfo_by_sid(DOM_SID *psid)
+{
+ /*
+ * We do a static cache for DISP_INFO's here. Explanation can be found
+ * in Jeremy's checkin message to r11793:
+ *
+ * Fix the SAMR cache so it works across completely insane
+ * client behaviour (ie.:
+ * open pipe/open SAMR handle/enumerate 0 - 1024
+ * close SAMR handle, close pipe.
+ * open pipe/open SAMR handle/enumerate 1024 - 2048...
+ * close SAMR handle, close pipe.
+ * And on ad-nausium. Amazing.... probably object-oriented
+ * client side programming in action yet again.
+ * This change should *massively* improve performance when
+ * enumerating users from an LDAP database.
+ * Jeremy.
+ *
+ * "Our" and the builtin domain are the only ones where we ever
+ * enumerate stuff, so just cache 2 entries.
+ */
+
+ static struct disp_info builtin_dispinfo;
+ static struct disp_info domain_dispinfo;
+
+ /* There are two cases to consider here:
+ 1) The SID is a domain SID and we look for an equality match, or
+ 2) This is an account SID and so we return the DISP_INFO* for our
+ domain */
+
+ if (psid == NULL) {
+ return NULL;
+ }
+
+ if (sid_check_is_builtin(psid) || sid_check_is_in_builtin(psid)) {
+ /*
+ * Necessary only once, but it does not really hurt.
+ */
+ sid_copy(&builtin_dispinfo.sid, &global_sid_Builtin);
+
+ return &builtin_dispinfo;
+ }
+
+ if (sid_check_is_domain(psid) || sid_check_is_in_our_domain(psid)) {
+ /*
+ * Necessary only once, but it does not really hurt.
+ */
+ sid_copy(&domain_dispinfo.sid, get_global_sam_sid());
+
+ return &domain_dispinfo;
+ }
+
+ return NULL;
+}
+
+/*******************************************************************
+ Create a samr_info struct.
+********************************************************************/
+
+static struct samr_info *get_samr_info_by_sid(DOM_SID *psid)
+{
+ struct samr_info *info;
+ fstring sid_str;
+ TALLOC_CTX *mem_ctx;
+
+ if (psid) {
+ sid_to_fstring(sid_str, psid);
+ } else {
+ fstrcpy(sid_str,"(NULL)");
+ }
+
+ mem_ctx = talloc_init("samr_info for domain sid %s", sid_str);
+
+ if ((info = TALLOC_ZERO_P(mem_ctx, struct samr_info)) == NULL)
+ return NULL;
+
+ DEBUG(10,("get_samr_info_by_sid: created new info for sid %s\n", sid_str));
+ if (psid) {
+ sid_copy( &info->sid, psid);
+ info->builtin_domain = sid_check_is_builtin(psid);
+ } else {
+ DEBUG(10,("get_samr_info_by_sid: created new info for NULL sid.\n"));
+ info->builtin_domain = False;
+ }
+ info->mem_ctx = mem_ctx;
+
+ info->disp_info = get_samr_dispinfo_by_sid(psid);
+
+ return info;
+}
+
+/*******************************************************************
+ Function to free the per SID data.
+ ********************************************************************/
+
+static void free_samr_cache(DISP_INFO *disp_info)
+{
+ DEBUG(10, ("free_samr_cache: deleting cache for SID %s\n",
+ sid_string_dbg(&disp_info->sid)));
+
+ /* We need to become root here because the paged search might have to
+ * tell the LDAP server we're not interested in the rest anymore. */
+
+ become_root();
+
+ if (disp_info->users) {
+ DEBUG(10,("free_samr_cache: deleting users cache\n"));
+ pdb_search_destroy(disp_info->users);
+ disp_info->users = NULL;
+ }
+ if (disp_info->machines) {
+ DEBUG(10,("free_samr_cache: deleting machines cache\n"));
+ pdb_search_destroy(disp_info->machines);
+ disp_info->machines = NULL;
+ }
+ if (disp_info->groups) {
+ DEBUG(10,("free_samr_cache: deleting groups cache\n"));
+ pdb_search_destroy(disp_info->groups);
+ disp_info->groups = NULL;
+ }
+ if (disp_info->aliases) {
+ DEBUG(10,("free_samr_cache: deleting aliases cache\n"));
+ pdb_search_destroy(disp_info->aliases);
+ disp_info->aliases = NULL;
+ }
+ if (disp_info->enum_users) {
+ DEBUG(10,("free_samr_cache: deleting enum_users cache\n"));
+ pdb_search_destroy(disp_info->enum_users);
+ disp_info->enum_users = NULL;
+ }
+ disp_info->enum_acb_mask = 0;
+
+ unbecome_root();
+}
+
+/*******************************************************************
+ Function to free the per handle data.
+ ********************************************************************/
+
+static void free_samr_info(void *ptr)
+{
+ struct samr_info *info=(struct samr_info *) ptr;
+
+ /* Only free the dispinfo cache if no one bothered to set up
+ a timeout. */
+
+ if (info->disp_info && info->disp_info->cache_timeout_event == NULL) {
+ free_samr_cache(info->disp_info);
+ }
+
+ talloc_destroy(info->mem_ctx);
+}
+
+/*******************************************************************
+ Idle event handler. Throw away the disp info cache.
+ ********************************************************************/
+
+static void disp_info_cache_idle_timeout_handler(struct event_context *ev_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ DISP_INFO *disp_info = (DISP_INFO *)private_data;
+
+ TALLOC_FREE(disp_info->cache_timeout_event);
+
+ DEBUG(10, ("disp_info_cache_idle_timeout_handler: caching timed "
+ "out\n"));
+ free_samr_cache(disp_info);
+}
+
+/*******************************************************************
+ Setup cache removal idle event handler.
+ ********************************************************************/
+
+static void set_disp_info_cache_timeout(DISP_INFO *disp_info, time_t secs_fromnow)
+{
+ /* Remove any pending timeout and update. */
+
+ TALLOC_FREE(disp_info->cache_timeout_event);
+
+ DEBUG(10,("set_disp_info_cache_timeout: caching enumeration for "
+ "SID %s for %u seconds\n", sid_string_dbg(&disp_info->sid),
+ (unsigned int)secs_fromnow ));
+
+ disp_info->cache_timeout_event = event_add_timed(
+ smbd_event_context(), NULL,
+ timeval_current_ofs(secs_fromnow, 0),
+ "disp_info_cache_idle_timeout_handler",
+ disp_info_cache_idle_timeout_handler, (void *)disp_info);
+}
+
+/*******************************************************************
+ Force flush any cache. We do this on any samr_set_xxx call.
+ We must also remove the timeout handler.
+ ********************************************************************/
+
+static void force_flush_samr_cache(DISP_INFO *disp_info)
+{
+ if ((disp_info == NULL) || (disp_info->cache_timeout_event == NULL)) {
+ return;
+ }
+
+ DEBUG(10,("force_flush_samr_cache: clearing idle event\n"));
+ TALLOC_FREE(disp_info->cache_timeout_event);
+ free_samr_cache(disp_info);
+}
+
+/*******************************************************************
+ Ensure password info is never given out. Paranioa... JRA.
+ ********************************************************************/
+
+static void samr_clear_sam_passwd(struct samu *sam_pass)
+{
+
+ if (!sam_pass)
+ return;
+
+ /* These now zero out the old password */
+
+ pdb_set_lanman_passwd(sam_pass, NULL, PDB_DEFAULT);
+ pdb_set_nt_passwd(sam_pass, NULL, PDB_DEFAULT);
+}
+
+static uint32 count_sam_users(struct disp_info *info, uint32 acct_flags)
+{
+ struct samr_displayentry *entry;
+
+ if (info->builtin_domain) {
+ /* No users in builtin. */
+ return 0;
+ }
+
+ if (info->users == NULL) {
+ info->users = pdb_search_users(acct_flags);
+ if (info->users == NULL) {
+ return 0;
+ }
+ }
+ /* Fetch the last possible entry, thus trigger an enumeration */
+ pdb_search_entries(info->users, 0xffffffff, 1, &entry);
+
+ /* Ensure we cache this enumeration. */
+ set_disp_info_cache_timeout(info, DISP_INFO_CACHE_TIMEOUT);
+
+ return info->users->num_entries;
+}
+
+static uint32 count_sam_groups(struct disp_info *info)
+{
+ struct samr_displayentry *entry;
+
+ if (info->builtin_domain) {
+ /* No groups in builtin. */
+ return 0;
+ }
+
+ if (info->groups == NULL) {
+ info->groups = pdb_search_groups();
+ if (info->groups == NULL) {
+ return 0;
+ }
+ }
+ /* Fetch the last possible entry, thus trigger an enumeration */
+ pdb_search_entries(info->groups, 0xffffffff, 1, &entry);
+
+ /* Ensure we cache this enumeration. */
+ set_disp_info_cache_timeout(info, DISP_INFO_CACHE_TIMEOUT);
+
+ return info->groups->num_entries;
+}
+
+static uint32 count_sam_aliases(struct disp_info *info)
+{
+ struct samr_displayentry *entry;
+
+ if (info->aliases == NULL) {
+ info->aliases = pdb_search_aliases(&info->sid);
+ if (info->aliases == NULL) {
+ return 0;
+ }
+ }
+ /* Fetch the last possible entry, thus trigger an enumeration */
+ pdb_search_entries(info->aliases, 0xffffffff, 1, &entry);
+
+ /* Ensure we cache this enumeration. */
+ set_disp_info_cache_timeout(info, DISP_INFO_CACHE_TIMEOUT);
+
+ return info->aliases->num_entries;
+}
+
+/*******************************************************************
+ _samr_Close
+ ********************************************************************/
+
+NTSTATUS _samr_Close(pipes_struct *p, struct samr_Close *r)
+{
+ if (!close_policy_hnd(p, r->in.handle)) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ ZERO_STRUCTP(r->out.handle);
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ _samr_OpenDomain
+ ********************************************************************/
+
+NTSTATUS _samr_OpenDomain(pipes_struct *p,
+ struct samr_OpenDomain *r)
+{
+ struct samr_info *info;
+ SEC_DESC *psd = NULL;
+ uint32 acc_granted;
+ uint32 des_access = r->in.access_mask;
+ NTSTATUS status;
+ size_t sd_size;
+ SE_PRIV se_rights;
+
+ /* find the connection policy handle. */
+
+ if ( !find_policy_by_hnd(p, r->in.connect_handle, (void**)(void *)&info) )
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(info->acc_granted,
+ SA_RIGHT_SAM_OPEN_DOMAIN,
+ "_samr_OpenDomain" );
+
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+ /*check if access can be granted as requested by client. */
+
+ make_samr_object_sd( p->mem_ctx, &psd, &sd_size, &dom_generic_mapping, NULL, 0 );
+ se_map_generic( &des_access, &dom_generic_mapping );
+
+ se_priv_copy( &se_rights, &se_machine_account );
+ se_priv_add( &se_rights, &se_add_users );
+
+ status = access_check_samr_object( psd, p->pipe_user.nt_user_token,
+ &se_rights, GENERIC_RIGHTS_DOMAIN_WRITE, des_access,
+ &acc_granted, "_samr_OpenDomain" );
+
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+ if (!sid_check_is_domain(r->in.sid) &&
+ !sid_check_is_builtin(r->in.sid)) {
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
+ /* associate the domain SID with the (unique) handle. */
+ if ((info = get_samr_info_by_sid(r->in.sid))==NULL)
+ return NT_STATUS_NO_MEMORY;
+ info->acc_granted = acc_granted;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, r->out.domain_handle, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ DEBUG(5,("_samr_OpenDomain: %d\n", __LINE__));
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ _samr_GetUserPwInfo
+ ********************************************************************/
+
+NTSTATUS _samr_GetUserPwInfo(pipes_struct *p,
+ struct samr_GetUserPwInfo *r)
+{
+ struct samr_info *info = NULL;
+ enum lsa_SidType sid_type;
+ uint32_t min_password_length = 0;
+ uint32_t password_properties = 0;
+ bool ret = false;
+ NTSTATUS status;
+
+ DEBUG(5,("_samr_GetUserPwInfo: %d\n", __LINE__));
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, r->in.user_handle, (void **)(void *)&info)) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ status = access_check_samr_function(info->acc_granted,
+ SAMR_USER_ACCESS_GET_ATTRIBUTES,
+ "_samr_GetUserPwInfo" );
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (!sid_check_is_in_our_domain(&info->sid)) {
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ become_root();
+ ret = lookup_sid(p->mem_ctx, &info->sid, NULL, NULL, &sid_type);
+ unbecome_root();
+ if (ret == false) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ switch (sid_type) {
+ case SID_NAME_USER:
+ become_root();
+ pdb_get_account_policy(AP_MIN_PASSWORD_LEN,
+ &min_password_length);
+ pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS,
+ &password_properties);
+ unbecome_root();
+
+ if (lp_check_password_script() && *lp_check_password_script()) {
+ password_properties |= DOMAIN_PASSWORD_COMPLEX;
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ r->out.info->min_password_length = min_password_length;
+ r->out.info->password_properties = password_properties;
+
+ DEBUG(5,("_samr_GetUserPwInfo: %d\n", __LINE__));
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static bool get_lsa_policy_samr_sid( pipes_struct *p, POLICY_HND *pol,
+ DOM_SID *sid, uint32 *acc_granted,
+ DISP_INFO **ppdisp_info)
+{
+ struct samr_info *info = NULL;
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, pol, (void **)(void *)&info))
+ return False;
+
+ if (!info)
+ return False;
+
+ *sid = info->sid;
+ *acc_granted = info->acc_granted;
+ if (ppdisp_info) {
+ *ppdisp_info = info->disp_info;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ _samr_SetSecurity
+ ********************************************************************/
+
+NTSTATUS _samr_SetSecurity(pipes_struct *p,
+ struct samr_SetSecurity *r)
+{
+ DOM_SID pol_sid;
+ uint32 acc_granted, i;
+ SEC_ACL *dacl;
+ bool ret;
+ struct samu *sampass=NULL;
+ NTSTATUS status;
+
+ if (!get_lsa_policy_samr_sid(p, r->in.handle, &pol_sid, &acc_granted, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!(sampass = samu_new( p->mem_ctx))) {
+ DEBUG(0,("No memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* get the user record */
+ become_root();
+ ret = pdb_getsampwsid(sampass, &pol_sid);
+ unbecome_root();
+
+ if (!ret) {
+ DEBUG(4, ("User %s not found\n", sid_string_dbg(&pol_sid)));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ dacl = r->in.sdbuf->sd->dacl;
+ for (i=0; i < dacl->num_aces; i++) {
+ if (sid_equal(&pol_sid, &dacl->aces[i].trustee)) {
+ ret = pdb_set_pass_can_change(sampass,
+ (dacl->aces[i].access_mask &
+ SA_RIGHT_USER_CHANGE_PASSWORD) ?
+ True: False);
+ break;
+ }
+ }
+
+ if (!ret) {
+ TALLOC_FREE(sampass);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = access_check_samr_function(acc_granted,
+ SA_RIGHT_USER_SET_ATTRIBUTES,
+ "_samr_SetSecurity");
+ if (NT_STATUS_IS_OK(status)) {
+ become_root();
+ status = pdb_update_sam_account(sampass);
+ unbecome_root();
+ }
+
+ TALLOC_FREE(sampass);
+
+ return status;
+}
+
+/*******************************************************************
+ build correct perms based on policies and password times for _samr_query_sec_obj
+*******************************************************************/
+static bool check_change_pw_access(TALLOC_CTX *mem_ctx, DOM_SID *user_sid)
+{
+ struct samu *sampass=NULL;
+ bool ret;
+
+ if ( !(sampass = samu_new( mem_ctx )) ) {
+ DEBUG(0,("No memory!\n"));
+ return False;
+ }
+
+ become_root();
+ ret = pdb_getsampwsid(sampass, user_sid);
+ unbecome_root();
+
+ if (ret == False) {
+ DEBUG(4,("User %s not found\n", sid_string_dbg(user_sid)));
+ TALLOC_FREE(sampass);
+ return False;
+ }
+
+ DEBUG(3,("User:[%s]\n", pdb_get_username(sampass) ));
+
+ if (pdb_get_pass_can_change(sampass)) {
+ TALLOC_FREE(sampass);
+ return True;
+ }
+ TALLOC_FREE(sampass);
+ return False;
+}
+
+
+/*******************************************************************
+ _samr_QuerySecurity
+ ********************************************************************/
+
+NTSTATUS _samr_QuerySecurity(pipes_struct *p,
+ struct samr_QuerySecurity *r)
+{
+ NTSTATUS status;
+ DOM_SID pol_sid;
+ SEC_DESC * psd = NULL;
+ uint32 acc_granted;
+ size_t sd_size;
+
+ /* Get the SID. */
+ if (!get_lsa_policy_samr_sid(p, r->in.handle, &pol_sid, &acc_granted, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ DEBUG(10,("_samr_QuerySecurity: querying security on SID: %s\n",
+ sid_string_dbg(&pol_sid)));
+
+ /* Check what typ of SID is beeing queried (e.g Domain SID, User SID, Group SID) */
+
+ /* To query the security of the SAM it self an invalid SID with S-0-0 is passed to this function */
+ if (pol_sid.sid_rev_num == 0) {
+ DEBUG(5,("_samr_QuerySecurity: querying security on SAM\n"));
+ status = make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &sam_generic_mapping, NULL, 0);
+ } else if (sid_equal(&pol_sid,get_global_sam_sid())) {
+ /* check if it is our domain SID */
+ DEBUG(5,("_samr_QuerySecurity: querying security on Domain "
+ "with SID: %s\n", sid_string_dbg(&pol_sid)));
+ status = make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &dom_generic_mapping, NULL, 0);
+ } else if (sid_equal(&pol_sid,&global_sid_Builtin)) {
+ /* check if it is the Builtin Domain */
+ /* TODO: Builtin probably needs a different SD with restricted write access*/
+ DEBUG(5,("_samr_QuerySecurity: querying security on Builtin "
+ "Domain with SID: %s\n", sid_string_dbg(&pol_sid)));
+ status = make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &dom_generic_mapping, NULL, 0);
+ } else if (sid_check_is_in_our_domain(&pol_sid) ||
+ sid_check_is_in_builtin(&pol_sid)) {
+ /* TODO: different SDs have to be generated for aliases groups and users.
+ Currently all three get a default user SD */
+ DEBUG(10,("_samr_QuerySecurity: querying security on Object "
+ "with SID: %s\n", sid_string_dbg(&pol_sid)));
+ if (check_change_pw_access(p->mem_ctx, &pol_sid)) {
+ status = make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &usr_generic_mapping,
+ &pol_sid, SAMR_USR_RIGHTS_WRITE_PW);
+ } else {
+ status = make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &usr_nopwchange_generic_mapping,
+ &pol_sid, SAMR_USR_RIGHTS_CANT_WRITE_PW);
+ }
+ } else {
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ if ((*r->out.sdbuf = make_sec_desc_buf(p->mem_ctx, sd_size, psd)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ return status;
+}
+
+/*******************************************************************
+makes a SAM_ENTRY / UNISTR2* structure from a user list.
+********************************************************************/
+
+static NTSTATUS make_user_sam_entry_list(TALLOC_CTX *ctx,
+ struct samr_SamEntry **sam_pp,
+ uint32_t num_entries,
+ uint32_t start_idx,
+ struct samr_displayentry *entries)
+{
+ uint32_t i;
+ struct samr_SamEntry *sam;
+
+ *sam_pp = NULL;
+
+ if (num_entries == 0) {
+ return NT_STATUS_OK;
+ }
+
+ sam = TALLOC_ZERO_ARRAY(ctx, struct samr_SamEntry, num_entries);
+ if (sam == NULL) {
+ DEBUG(0, ("make_user_sam_entry_list: TALLOC_ZERO failed!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+#if 0
+ /*
+ * usrmgr expects a non-NULL terminated string with
+ * trust relationships
+ */
+ if (entries[i].acct_flags & ACB_DOMTRUST) {
+ init_unistr2(&uni_temp_name, entries[i].account_name,
+ UNI_FLAGS_NONE);
+ } else {
+ init_unistr2(&uni_temp_name, entries[i].account_name,
+ UNI_STR_TERMINATE);
+ }
+#endif
+ init_lsa_String(&sam[i].name, entries[i].account_name);
+ sam[i].idx = entries[i].rid;
+ }
+
+ *sam_pp = sam;
+
+ return NT_STATUS_OK;
+}
+
+#define MAX_SAM_ENTRIES MAX_SAM_ENTRIES_W2K
+
+/*******************************************************************
+ _samr_EnumDomainUsers
+ ********************************************************************/
+
+NTSTATUS _samr_EnumDomainUsers(pipes_struct *p,
+ struct samr_EnumDomainUsers *r)
+{
+ NTSTATUS status;
+ struct samr_info *info = NULL;
+ int num_account;
+ uint32 enum_context = *r->in.resume_handle;
+ enum remote_arch_types ra_type = get_remote_arch();
+ int max_sam_entries = (ra_type == RA_WIN95) ? MAX_SAM_ENTRIES_W95 : MAX_SAM_ENTRIES_W2K;
+ uint32 max_entries = max_sam_entries;
+ struct samr_displayentry *entries = NULL;
+ struct samr_SamArray *samr_array = NULL;
+ struct samr_SamEntry *samr_entries = NULL;
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, r->in.domain_handle, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(info->acc_granted,
+ SA_RIGHT_DOMAIN_ENUM_ACCOUNTS,
+ "_samr_EnumDomainUsers");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(5,("_samr_EnumDomainUsers: %d\n", __LINE__));
+
+ if (info->builtin_domain) {
+ /* No users in builtin. */
+ *r->out.resume_handle = *r->in.resume_handle;
+ DEBUG(5,("_samr_EnumDomainUsers: No users in BUILTIN\n"));
+ return status;
+ }
+
+ samr_array = TALLOC_ZERO_P(p->mem_ctx, struct samr_SamArray);
+ if (!samr_array) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+
+ /* AS ROOT !!!! */
+
+ if ((info->disp_info->enum_users != NULL) &&
+ (info->disp_info->enum_acb_mask != r->in.acct_flags)) {
+ pdb_search_destroy(info->disp_info->enum_users);
+ info->disp_info->enum_users = NULL;
+ }
+
+ if (info->disp_info->enum_users == NULL) {
+ info->disp_info->enum_users = pdb_search_users(r->in.acct_flags);
+ info->disp_info->enum_acb_mask = r->in.acct_flags;
+ }
+
+ if (info->disp_info->enum_users == NULL) {
+ /* END AS ROOT !!!! */
+ unbecome_root();
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ num_account = pdb_search_entries(info->disp_info->enum_users,
+ enum_context, max_entries,
+ &entries);
+
+ /* END AS ROOT !!!! */
+
+ unbecome_root();
+
+ if (num_account == 0) {
+ DEBUG(5, ("_samr_EnumDomainUsers: enumeration handle over "
+ "total entries\n"));
+ *r->out.resume_handle = *r->in.resume_handle;
+ return NT_STATUS_OK;
+ }
+
+ status = make_user_sam_entry_list(p->mem_ctx, &samr_entries,
+ num_account, enum_context,
+ entries);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (max_entries <= num_account) {
+ status = STATUS_MORE_ENTRIES;
+ } else {
+ status = NT_STATUS_OK;
+ }
+
+ /* Ensure we cache this enumeration. */
+ set_disp_info_cache_timeout(info->disp_info, DISP_INFO_CACHE_TIMEOUT);
+
+ DEBUG(5, ("_samr_EnumDomainUsers: %d\n", __LINE__));
+
+ samr_array->count = num_account;
+ samr_array->entries = samr_entries;
+
+ *r->out.resume_handle = *r->in.resume_handle + num_account;
+ *r->out.sam = samr_array;
+ *r->out.num_entries = num_account;
+
+ DEBUG(5,("_samr_EnumDomainUsers: %d\n", __LINE__));
+
+ return status;
+}
+
+/*******************************************************************
+makes a SAM_ENTRY / UNISTR2* structure from a group list.
+********************************************************************/
+
+static void make_group_sam_entry_list(TALLOC_CTX *ctx,
+ struct samr_SamEntry **sam_pp,
+ uint32_t num_sam_entries,
+ struct samr_displayentry *entries)
+{
+ struct samr_SamEntry *sam;
+ uint32_t i;
+
+ *sam_pp = NULL;
+
+ if (num_sam_entries == 0) {
+ return;
+ }
+
+ sam = TALLOC_ZERO_ARRAY(ctx, struct samr_SamEntry, num_sam_entries);
+ if (sam == NULL) {
+ return;
+ }
+
+ for (i = 0; i < num_sam_entries; i++) {
+ /*
+ * JRA. I think this should include the null. TNG does not.
+ */
+ init_lsa_String(&sam[i].name, entries[i].account_name);
+ sam[i].idx = entries[i].rid;
+ }
+
+ *sam_pp = sam;
+}
+
+/*******************************************************************
+ _samr_EnumDomainGroups
+ ********************************************************************/
+
+NTSTATUS _samr_EnumDomainGroups(pipes_struct *p,
+ struct samr_EnumDomainGroups *r)
+{
+ NTSTATUS status;
+ struct samr_info *info = NULL;
+ struct samr_displayentry *groups;
+ uint32 num_groups;
+ struct samr_SamArray *samr_array = NULL;
+ struct samr_SamEntry *samr_entries = NULL;
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, r->in.domain_handle, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(info->acc_granted,
+ SA_RIGHT_DOMAIN_ENUM_ACCOUNTS,
+ "_samr_EnumDomainGroups");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(5,("_samr_EnumDomainGroups: %d\n", __LINE__));
+
+ if (info->builtin_domain) {
+ /* No groups in builtin. */
+ *r->out.resume_handle = *r->in.resume_handle;
+ DEBUG(5,("_samr_EnumDomainGroups: No groups in BUILTIN\n"));
+ return status;
+ }
+
+ samr_array = TALLOC_ZERO_P(p->mem_ctx, struct samr_SamArray);
+ if (!samr_array) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* the domain group array is being allocated in the function below */
+
+ become_root();
+
+ if (info->disp_info->groups == NULL) {
+ info->disp_info->groups = pdb_search_groups();
+
+ if (info->disp_info->groups == NULL) {
+ unbecome_root();
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ num_groups = pdb_search_entries(info->disp_info->groups,
+ *r->in.resume_handle,
+ MAX_SAM_ENTRIES, &groups);
+ unbecome_root();
+
+ /* Ensure we cache this enumeration. */
+ set_disp_info_cache_timeout(info->disp_info, DISP_INFO_CACHE_TIMEOUT);
+
+ make_group_sam_entry_list(p->mem_ctx, &samr_entries,
+ num_groups, groups);
+
+ samr_array->count = num_groups;
+ samr_array->entries = samr_entries;
+
+ *r->out.sam = samr_array;
+ *r->out.num_entries = num_groups;
+ /* this was missing, IMHO:
+ *r->out.resume_handle = num_groups + *r->in.resume_handle;
+ */
+
+ DEBUG(5,("_samr_EnumDomainGroups: %d\n", __LINE__));
+
+ return status;
+}
+
+/*******************************************************************
+ _samr_EnumDomainAliases
+ ********************************************************************/
+
+NTSTATUS _samr_EnumDomainAliases(pipes_struct *p,
+ struct samr_EnumDomainAliases *r)
+{
+ NTSTATUS status;
+ struct samr_info *info;
+ struct samr_displayentry *aliases;
+ uint32 num_aliases = 0;
+ struct samr_SamArray *samr_array = NULL;
+ struct samr_SamEntry *samr_entries = NULL;
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, r->in.domain_handle, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(info->acc_granted,
+ SA_RIGHT_DOMAIN_ENUM_ACCOUNTS,
+ "_samr_EnumDomainAliases");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(5,("_samr_EnumDomainAliases: sid %s\n",
+ sid_string_dbg(&info->sid)));
+
+ samr_array = TALLOC_ZERO_P(p->mem_ctx, struct samr_SamArray);
+ if (!samr_array) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+
+ if (info->disp_info->aliases == NULL) {
+ info->disp_info->aliases = pdb_search_aliases(&info->sid);
+ if (info->disp_info->aliases == NULL) {
+ unbecome_root();
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ num_aliases = pdb_search_entries(info->disp_info->aliases,
+ *r->in.resume_handle,
+ MAX_SAM_ENTRIES, &aliases);
+ unbecome_root();
+
+ /* Ensure we cache this enumeration. */
+ set_disp_info_cache_timeout(info->disp_info, DISP_INFO_CACHE_TIMEOUT);
+
+ make_group_sam_entry_list(p->mem_ctx, &samr_entries,
+ num_aliases, aliases);
+
+ DEBUG(5,("_samr_EnumDomainAliases: %d\n", __LINE__));
+
+ samr_array->count = num_aliases;
+ samr_array->entries = samr_entries;
+
+ *r->out.sam = samr_array;
+ *r->out.num_entries = num_aliases;
+ *r->out.resume_handle = num_aliases + *r->in.resume_handle;
+
+ return status;
+}
+
+/*******************************************************************
+ inits a samr_DispInfoGeneral structure.
+********************************************************************/
+
+static NTSTATUS init_samr_dispinfo_1(TALLOC_CTX *ctx,
+ struct samr_DispInfoGeneral *r,
+ uint32_t num_entries,
+ uint32_t start_idx,
+ struct samr_displayentry *entries)
+{
+ uint32 i;
+
+ DEBUG(10, ("init_samr_dispinfo_1: num_entries: %d\n", num_entries));
+
+ if (num_entries == 0) {
+ return NT_STATUS_OK;
+ }
+
+ r->count = num_entries;
+
+ r->entries = TALLOC_ZERO_ARRAY(ctx, struct samr_DispEntryGeneral, num_entries);
+ if (!r->entries) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < num_entries ; i++) {
+
+ init_lsa_String(&r->entries[i].account_name,
+ entries[i].account_name);
+
+ init_lsa_String(&r->entries[i].description,
+ entries[i].description);
+
+ init_lsa_String(&r->entries[i].full_name,
+ entries[i].fullname);
+
+ r->entries[i].rid = entries[i].rid;
+ r->entries[i].acct_flags = entries[i].acct_flags;
+ r->entries[i].idx = start_idx+i+1;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ inits a samr_DispInfoFull structure.
+********************************************************************/
+
+static NTSTATUS init_samr_dispinfo_2(TALLOC_CTX *ctx,
+ struct samr_DispInfoFull *r,
+ uint32_t num_entries,
+ uint32_t start_idx,
+ struct samr_displayentry *entries)
+{
+ uint32_t i;
+
+ DEBUG(10, ("init_samr_dispinfo_2: num_entries: %d\n", num_entries));
+
+ if (num_entries == 0) {
+ return NT_STATUS_OK;
+ }
+
+ r->count = num_entries;
+
+ r->entries = TALLOC_ZERO_ARRAY(ctx, struct samr_DispEntryFull, num_entries);
+ if (!r->entries) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < num_entries ; i++) {
+
+ init_lsa_String(&r->entries[i].account_name,
+ entries[i].account_name);
+
+ init_lsa_String(&r->entries[i].description,
+ entries[i].description);
+
+ r->entries[i].rid = entries[i].rid;
+ r->entries[i].acct_flags = entries[i].acct_flags;
+ r->entries[i].idx = start_idx+i+1;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ inits a samr_DispInfoFullGroups structure.
+********************************************************************/
+
+static NTSTATUS init_samr_dispinfo_3(TALLOC_CTX *ctx,
+ struct samr_DispInfoFullGroups *r,
+ uint32_t num_entries,
+ uint32_t start_idx,
+ struct samr_displayentry *entries)
+{
+ uint32_t i;
+
+ DEBUG(5, ("init_samr_dispinfo_3: num_entries: %d\n", num_entries));
+
+ if (num_entries == 0) {
+ return NT_STATUS_OK;
+ }
+
+ r->count = num_entries;
+
+ r->entries = TALLOC_ZERO_ARRAY(ctx, struct samr_DispEntryFullGroup, num_entries);
+ if (!r->entries) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < num_entries ; i++) {
+
+ init_lsa_String(&r->entries[i].account_name,
+ entries[i].account_name);
+
+ init_lsa_String(&r->entries[i].description,
+ entries[i].description);
+
+ r->entries[i].rid = entries[i].rid;
+ r->entries[i].acct_flags = entries[i].acct_flags;
+ r->entries[i].idx = start_idx+i+1;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ inits a samr_DispInfoAscii structure.
+********************************************************************/
+
+static NTSTATUS init_samr_dispinfo_4(TALLOC_CTX *ctx,
+ struct samr_DispInfoAscii *r,
+ uint32_t num_entries,
+ uint32_t start_idx,
+ struct samr_displayentry *entries)
+{
+ uint32_t i;
+
+ DEBUG(5, ("init_samr_dispinfo_4: num_entries: %d\n", num_entries));
+
+ if (num_entries == 0) {
+ return NT_STATUS_OK;
+ }
+
+ r->count = num_entries;
+
+ r->entries = TALLOC_ZERO_ARRAY(ctx, struct samr_DispEntryAscii, num_entries);
+ if (!r->entries) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < num_entries ; i++) {
+
+ init_lsa_AsciiStringLarge(&r->entries[i].account_name,
+ entries[i].account_name);
+
+ r->entries[i].idx = start_idx+i+1;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ inits a samr_DispInfoAscii structure.
+********************************************************************/
+
+static NTSTATUS init_samr_dispinfo_5(TALLOC_CTX *ctx,
+ struct samr_DispInfoAscii *r,
+ uint32_t num_entries,
+ uint32_t start_idx,
+ struct samr_displayentry *entries)
+{
+ uint32_t i;
+
+ DEBUG(5, ("init_samr_dispinfo_5: num_entries: %d\n", num_entries));
+
+ if (num_entries == 0) {
+ return NT_STATUS_OK;
+ }
+
+ r->count = num_entries;
+
+ r->entries = TALLOC_ZERO_ARRAY(ctx, struct samr_DispEntryAscii, num_entries);
+ if (!r->entries) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < num_entries ; i++) {
+
+ init_lsa_AsciiStringLarge(&r->entries[i].account_name,
+ entries[i].account_name);
+
+ r->entries[i].idx = start_idx+i+1;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ _samr_QueryDisplayInfo
+ ********************************************************************/
+
+NTSTATUS _samr_QueryDisplayInfo(pipes_struct *p,
+ struct samr_QueryDisplayInfo *r)
+{
+ NTSTATUS status;
+ struct samr_info *info = NULL;
+ uint32 struct_size=0x20; /* W2K always reply that, client doesn't care */
+
+ uint32 max_entries = r->in.max_entries;
+ uint32 enum_context = r->in.start_idx;
+ uint32 max_size = r->in.buf_size;
+
+ union samr_DispInfo *disp_info = r->out.info;
+
+ uint32 temp_size=0, total_data_size=0;
+ NTSTATUS disp_ret = NT_STATUS_UNSUCCESSFUL;
+ uint32 num_account = 0;
+ enum remote_arch_types ra_type = get_remote_arch();
+ int max_sam_entries = (ra_type == RA_WIN95) ? MAX_SAM_ENTRIES_W95 : MAX_SAM_ENTRIES_W2K;
+ struct samr_displayentry *entries = NULL;
+
+ DEBUG(5,("_samr_QueryDisplayInfo: %d\n", __LINE__));
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, r->in.domain_handle, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /*
+ * calculate how many entries we will return.
+ * based on
+ * - the number of entries the client asked
+ * - our limit on that
+ * - the starting point (enumeration context)
+ * - the buffer size the client will accept
+ */
+
+ /*
+ * We are a lot more like W2K. Instead of reading the SAM
+ * each time to find the records we need to send back,
+ * we read it once and link that copy to the sam handle.
+ * For large user list (over the MAX_SAM_ENTRIES)
+ * it's a definitive win.
+ * second point to notice: between enumerations
+ * our sam is now the same as it's a snapshoot.
+ * third point: got rid of the static SAM_USER_21 struct
+ * no more intermediate.
+ * con: it uses much more memory, as a full copy is stored
+ * in memory.
+ *
+ * If you want to change it, think twice and think
+ * of the second point , that's really important.
+ *
+ * JFM, 12/20/2001
+ */
+
+ if ((r->in.level < 1) || (r->in.level > 5)) {
+ DEBUG(0,("_samr_QueryDisplayInfo: Unknown info level (%u)\n",
+ (unsigned int)r->in.level ));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ /* first limit the number of entries we will return */
+ if(max_entries > max_sam_entries) {
+ DEBUG(5, ("_samr_QueryDisplayInfo: client requested %d "
+ "entries, limiting to %d\n", max_entries,
+ max_sam_entries));
+ max_entries = max_sam_entries;
+ }
+
+ /* calculate the size and limit on the number of entries we will
+ * return */
+
+ temp_size=max_entries*struct_size;
+
+ if (temp_size>max_size) {
+ max_entries=MIN((max_size/struct_size),max_entries);;
+ DEBUG(5, ("_samr_QueryDisplayInfo: buffer size limits to "
+ "only %d entries\n", max_entries));
+ }
+
+ become_root();
+
+ /* THe following done as ROOT. Don't return without unbecome_root(). */
+
+ switch (r->in.level) {
+ case 0x1:
+ case 0x4:
+ if (info->disp_info->users == NULL) {
+ info->disp_info->users = pdb_search_users(ACB_NORMAL);
+ if (info->disp_info->users == NULL) {
+ unbecome_root();
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ DEBUG(10,("_samr_QueryDisplayInfo: starting user enumeration at index %u\n",
+ (unsigned int)enum_context ));
+ } else {
+ DEBUG(10,("_samr_QueryDisplayInfo: using cached user enumeration at index %u\n",
+ (unsigned int)enum_context ));
+ }
+
+ num_account = pdb_search_entries(info->disp_info->users,
+ enum_context, max_entries,
+ &entries);
+ break;
+ case 0x2:
+ if (info->disp_info->machines == NULL) {
+ info->disp_info->machines =
+ pdb_search_users(ACB_WSTRUST|ACB_SVRTRUST);
+ if (info->disp_info->machines == NULL) {
+ unbecome_root();
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ DEBUG(10,("_samr_QueryDisplayInfo: starting machine enumeration at index %u\n",
+ (unsigned int)enum_context ));
+ } else {
+ DEBUG(10,("_samr_QueryDisplayInfo: using cached machine enumeration at index %u\n",
+ (unsigned int)enum_context ));
+ }
+
+ num_account = pdb_search_entries(info->disp_info->machines,
+ enum_context, max_entries,
+ &entries);
+ break;
+ case 0x3:
+ case 0x5:
+ if (info->disp_info->groups == NULL) {
+ info->disp_info->groups = pdb_search_groups();
+ if (info->disp_info->groups == NULL) {
+ unbecome_root();
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ DEBUG(10,("_samr_QueryDisplayInfo: starting group enumeration at index %u\n",
+ (unsigned int)enum_context ));
+ } else {
+ DEBUG(10,("_samr_QueryDisplayInfo: using cached group enumeration at index %u\n",
+ (unsigned int)enum_context ));
+ }
+
+ num_account = pdb_search_entries(info->disp_info->groups,
+ enum_context, max_entries,
+ &entries);
+ break;
+ default:
+ unbecome_root();
+ smb_panic("info class changed");
+ break;
+ }
+ unbecome_root();
+
+
+ /* Now create reply structure */
+ switch (r->in.level) {
+ case 0x1:
+ disp_ret = init_samr_dispinfo_1(p->mem_ctx, &disp_info->info1,
+ num_account, enum_context,
+ entries);
+ break;
+ case 0x2:
+ disp_ret = init_samr_dispinfo_2(p->mem_ctx, &disp_info->info2,
+ num_account, enum_context,
+ entries);
+ break;
+ case 0x3:
+ disp_ret = init_samr_dispinfo_3(p->mem_ctx, &disp_info->info3,
+ num_account, enum_context,
+ entries);
+ break;
+ case 0x4:
+ disp_ret = init_samr_dispinfo_4(p->mem_ctx, &disp_info->info4,
+ num_account, enum_context,
+ entries);
+ break;
+ case 0x5:
+ disp_ret = init_samr_dispinfo_5(p->mem_ctx, &disp_info->info5,
+ num_account, enum_context,
+ entries);
+ break;
+ default:
+ smb_panic("info class changed");
+ break;
+ }
+
+ if (!NT_STATUS_IS_OK(disp_ret))
+ return disp_ret;
+
+ /* calculate the total size */
+ total_data_size=num_account*struct_size;
+
+ if (num_account) {
+ status = STATUS_MORE_ENTRIES;
+ } else {
+ status = NT_STATUS_OK;
+ }
+
+ /* Ensure we cache this enumeration. */
+ set_disp_info_cache_timeout(info->disp_info, DISP_INFO_CACHE_TIMEOUT);
+
+ DEBUG(5, ("_samr_QueryDisplayInfo: %d\n", __LINE__));
+
+ *r->out.total_size = total_data_size;
+ *r->out.returned_size = temp_size;
+
+ return status;
+}
+
+/****************************************************************
+ _samr_QueryDisplayInfo2
+****************************************************************/
+
+NTSTATUS _samr_QueryDisplayInfo2(pipes_struct *p,
+ struct samr_QueryDisplayInfo2 *r)
+{
+ struct samr_QueryDisplayInfo q;
+
+ q.in.domain_handle = r->in.domain_handle;
+ q.in.level = r->in.level;
+ q.in.start_idx = r->in.start_idx;
+ q.in.max_entries = r->in.max_entries;
+ q.in.buf_size = r->in.buf_size;
+
+ q.out.total_size = r->out.total_size;
+ q.out.returned_size = r->out.returned_size;
+ q.out.info = r->out.info;
+
+ return _samr_QueryDisplayInfo(p, &q);
+}
+
+/****************************************************************
+ _samr_QueryDisplayInfo3
+****************************************************************/
+
+NTSTATUS _samr_QueryDisplayInfo3(pipes_struct *p,
+ struct samr_QueryDisplayInfo3 *r)
+{
+ struct samr_QueryDisplayInfo q;
+
+ q.in.domain_handle = r->in.domain_handle;
+ q.in.level = r->in.level;
+ q.in.start_idx = r->in.start_idx;
+ q.in.max_entries = r->in.max_entries;
+ q.in.buf_size = r->in.buf_size;
+
+ q.out.total_size = r->out.total_size;
+ q.out.returned_size = r->out.returned_size;
+ q.out.info = r->out.info;
+
+ return _samr_QueryDisplayInfo(p, &q);
+}
+
+/*******************************************************************
+ _samr_QueryAliasInfo
+ ********************************************************************/
+
+NTSTATUS _samr_QueryAliasInfo(pipes_struct *p,
+ struct samr_QueryAliasInfo *r)
+{
+ DOM_SID sid;
+ struct acct_info info;
+ uint32 acc_granted;
+ NTSTATUS status;
+ union samr_AliasInfo *alias_info = NULL;
+ const char *alias_name = NULL;
+ const char *alias_description = NULL;
+
+ DEBUG(5,("_samr_QueryAliasInfo: %d\n", __LINE__));
+
+ alias_info = TALLOC_ZERO_P(p->mem_ctx, union samr_AliasInfo);
+ if (!alias_info) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* find the policy handle. open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, r->in.alias_handle, &sid, &acc_granted, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(acc_granted,
+ SA_RIGHT_ALIAS_LOOKUP_INFO,
+ "_samr_QueryAliasInfo");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ become_root();
+ status = pdb_get_aliasinfo(&sid, &info);
+ unbecome_root();
+
+ if ( !NT_STATUS_IS_OK(status))
+ return status;
+
+ /* FIXME: info contains fstrings */
+ alias_name = talloc_strdup(r, info.acct_name);
+ alias_description = talloc_strdup(r, info.acct_desc);
+
+ switch (r->in.level) {
+ case ALIASINFOALL:
+ init_samr_alias_info1(&alias_info->all,
+ alias_name,
+ 1,
+ alias_description);
+ break;
+ case ALIASINFODESCRIPTION:
+ init_samr_alias_info3(&alias_info->description,
+ alias_description);
+ break;
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ *r->out.info = alias_info;
+
+ DEBUG(5,("_samr_QueryAliasInfo: %d\n", __LINE__));
+
+ return NT_STATUS_OK;
+}
+
+#if 0
+/*******************************************************************
+ samr_reply_lookup_ids
+ ********************************************************************/
+
+ uint32 _samr_lookup_ids(pipes_struct *p, SAMR_Q_LOOKUP_IDS *q_u, SAMR_R_LOOKUP_IDS *r_u)
+{
+ uint32 rid[MAX_SAM_ENTRIES];
+ int num_rids = q_u->num_sids1;
+
+ r_u->status = NT_STATUS_OK;
+
+ DEBUG(5,("_samr_lookup_ids: %d\n", __LINE__));
+
+ if (num_rids > MAX_SAM_ENTRIES) {
+ num_rids = MAX_SAM_ENTRIES;
+ DEBUG(5,("_samr_lookup_ids: truncating entries to %d\n", num_rids));
+ }
+
+#if 0
+ int i;
+ SMB_ASSERT_ARRAY(q_u->uni_user_name, num_rids);
+
+ for (i = 0; i < num_rids && status == 0; i++)
+ {
+ struct sam_passwd *sam_pass;
+ fstring user_name;
+
+
+ fstrcpy(user_name, unistrn2(q_u->uni_user_name[i].buffer,
+ q_u->uni_user_name[i].uni_str_len));
+
+ /* find the user account */
+ become_root();
+ sam_pass = get_smb21pwd_entry(user_name, 0);
+ unbecome_root();
+
+ if (sam_pass == NULL)
+ {
+ status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
+ rid[i] = 0;
+ }
+ else
+ {
+ rid[i] = sam_pass->user_rid;
+ }
+ }
+#endif
+
+ num_rids = 1;
+ rid[0] = BUILTIN_ALIAS_RID_USERS;
+
+ init_samr_r_lookup_ids(&r_u, num_rids, rid, NT_STATUS_OK);
+
+ DEBUG(5,("_samr_lookup_ids: %d\n", __LINE__));
+
+ return r_u->status;
+}
+#endif
+
+/*******************************************************************
+ _samr_LookupNames
+ ********************************************************************/
+
+NTSTATUS _samr_LookupNames(pipes_struct *p,
+ struct samr_LookupNames *r)
+{
+ NTSTATUS status;
+ uint32 *rid;
+ enum lsa_SidType *type;
+ int i;
+ int num_rids = r->in.num_names;
+ DOM_SID pol_sid;
+ uint32 acc_granted;
+ struct samr_Ids rids, types;
+
+ DEBUG(5,("_samr_LookupNames: %d\n", __LINE__));
+
+ if (!get_lsa_policy_samr_sid(p, r->in.domain_handle, &pol_sid, &acc_granted, NULL)) {
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ status = access_check_samr_function(acc_granted,
+ 0, /* Don't know the acc_bits yet */
+ "_samr_LookupNames");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (num_rids > MAX_SAM_ENTRIES) {
+ num_rids = MAX_SAM_ENTRIES;
+ DEBUG(5,("_samr_LookupNames: truncating entries to %d\n", num_rids));
+ }
+
+ rid = talloc_array(p->mem_ctx, uint32, num_rids);
+ NT_STATUS_HAVE_NO_MEMORY(rid);
+
+ type = talloc_array(p->mem_ctx, enum lsa_SidType, num_rids);
+ NT_STATUS_HAVE_NO_MEMORY(type);
+
+ DEBUG(5,("_samr_LookupNames: looking name on SID %s\n",
+ sid_string_dbg(&pol_sid)));
+
+ for (i = 0; i < num_rids; i++) {
+
+ status = NT_STATUS_NONE_MAPPED;
+ type[i] = SID_NAME_UNKNOWN;
+
+ rid[i] = 0xffffffff;
+
+ if (sid_check_is_builtin(&pol_sid)) {
+ if (lookup_builtin_name(r->in.names[i].string,
+ &rid[i]))
+ {
+ type[i] = SID_NAME_ALIAS;
+ }
+ } else {
+ lookup_global_sam_name(r->in.names[i].string, 0,
+ &rid[i], &type[i]);
+ }
+
+ if (type[i] != SID_NAME_UNKNOWN) {
+ status = NT_STATUS_OK;
+ }
+ }
+
+ rids.count = num_rids;
+ rids.ids = rid;
+
+ types.count = num_rids;
+ types.ids = type;
+
+ *r->out.rids = rids;
+ *r->out.types = types;
+
+ DEBUG(5,("_samr_LookupNames: %d\n", __LINE__));
+
+ return status;
+}
+
+/*******************************************************************
+ _samr_ChangePasswordUser2
+ ********************************************************************/
+
+NTSTATUS _samr_ChangePasswordUser2(pipes_struct *p,
+ struct samr_ChangePasswordUser2 *r)
+{
+ NTSTATUS status;
+ fstring user_name;
+ fstring wks;
+
+ DEBUG(5,("_samr_ChangePasswordUser2: %d\n", __LINE__));
+
+ fstrcpy(user_name, r->in.account->string);
+ fstrcpy(wks, r->in.server->string);
+
+ DEBUG(5,("_samr_ChangePasswordUser2: user: %s wks: %s\n", user_name, wks));
+
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user_name);
+
+ /*
+ * UNIX username case mangling not required, pass_oem_change
+ * is case insensitive.
+ */
+
+ status = pass_oem_change(user_name,
+ r->in.lm_password->data,
+ r->in.lm_verifier->hash,
+ r->in.nt_password->data,
+ r->in.nt_verifier->hash,
+ NULL);
+
+ DEBUG(5,("_samr_ChangePasswordUser2: %d\n", __LINE__));
+
+ return status;
+}
+
+/*******************************************************************
+ _samr_ChangePasswordUser3
+ ********************************************************************/
+
+NTSTATUS _samr_ChangePasswordUser3(pipes_struct *p,
+ struct samr_ChangePasswordUser3 *r)
+{
+ NTSTATUS status;
+ fstring user_name;
+ const char *wks = NULL;
+ uint32 reject_reason;
+ struct samr_DomInfo1 *dominfo = NULL;
+ struct samr_ChangeReject *reject = NULL;
+
+ DEBUG(5,("_samr_ChangePasswordUser3: %d\n", __LINE__));
+
+ fstrcpy(user_name, r->in.account->string);
+ if (r->in.server && r->in.server->string) {
+ wks = r->in.server->string;
+ }
+
+ DEBUG(5,("_samr_ChangePasswordUser3: user: %s wks: %s\n", user_name, wks));
+
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user_name);
+
+ /*
+ * UNIX username case mangling not required, pass_oem_change
+ * is case insensitive.
+ */
+
+ status = pass_oem_change(user_name,
+ r->in.lm_password->data,
+ r->in.lm_verifier->hash,
+ r->in.nt_password->data,
+ r->in.nt_verifier->hash,
+ &reject_reason);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_RESTRICTION)) {
+
+ uint32 min_pass_len,pass_hist,password_properties;
+ time_t u_expire, u_min_age;
+ NTTIME nt_expire, nt_min_age;
+ uint32 account_policy_temp;
+
+ dominfo = TALLOC_ZERO_P(p->mem_ctx, struct samr_DomInfo1);
+ if (!dominfo) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ reject = TALLOC_ZERO_P(p->mem_ctx, struct samr_ChangeReject);
+ if (!reject) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+
+ /* AS ROOT !!! */
+
+ pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &account_policy_temp);
+ min_pass_len = account_policy_temp;
+
+ pdb_get_account_policy(AP_PASSWORD_HISTORY, &account_policy_temp);
+ pass_hist = account_policy_temp;
+
+ pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp);
+ password_properties = account_policy_temp;
+
+ pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp);
+ u_expire = account_policy_temp;
+
+ pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &account_policy_temp);
+ u_min_age = account_policy_temp;
+
+ /* !AS ROOT */
+
+ unbecome_root();
+
+ unix_to_nt_time_abs(&nt_expire, u_expire);
+ unix_to_nt_time_abs(&nt_min_age, u_min_age);
+
+ if (lp_check_password_script() && *lp_check_password_script()) {
+ password_properties |= DOMAIN_PASSWORD_COMPLEX;
+ }
+
+ init_samr_DomInfo1(dominfo,
+ min_pass_len,
+ pass_hist,
+ password_properties,
+ u_expire,
+ u_min_age);
+
+ reject->reason = reject_reason;
+
+ *r->out.dominfo = dominfo;
+ *r->out.reject = reject;
+ }
+
+ DEBUG(5,("_samr_ChangePasswordUser3: %d\n", __LINE__));
+
+ return status;
+}
+
+/*******************************************************************
+makes a SAMR_R_LOOKUP_RIDS structure.
+********************************************************************/
+
+static bool make_samr_lookup_rids(TALLOC_CTX *ctx, uint32 num_names,
+ const char **names,
+ struct lsa_String **lsa_name_array_p)
+{
+ struct lsa_String *lsa_name_array = NULL;
+ uint32_t i;
+
+ *lsa_name_array_p = NULL;
+
+ if (num_names != 0) {
+ lsa_name_array = TALLOC_ZERO_ARRAY(ctx, struct lsa_String, num_names);
+ if (!lsa_name_array) {
+ return false;
+ }
+ }
+
+ for (i = 0; i < num_names; i++) {
+ DEBUG(10, ("names[%d]:%s\n", i, names[i] && *names[i] ? names[i] : ""));
+ init_lsa_String(&lsa_name_array[i], names[i]);
+ }
+
+ *lsa_name_array_p = lsa_name_array;
+
+ return true;
+}
+
+/*******************************************************************
+ _samr_LookupRids
+ ********************************************************************/
+
+NTSTATUS _samr_LookupRids(pipes_struct *p,
+ struct samr_LookupRids *r)
+{
+ NTSTATUS status;
+ const char **names;
+ enum lsa_SidType *attrs = NULL;
+ uint32 *wire_attrs = NULL;
+ DOM_SID pol_sid;
+ int num_rids = (int)r->in.num_rids;
+ uint32 acc_granted;
+ int i;
+ struct lsa_Strings names_array;
+ struct samr_Ids types_array;
+ struct lsa_String *lsa_names = NULL;
+
+ DEBUG(5,("_samr_LookupRids: %d\n", __LINE__));
+
+ /* find the policy handle. open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, r->in.domain_handle, &pol_sid, &acc_granted, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (num_rids > 1000) {
+ DEBUG(0, ("Got asked for %d rids (more than 1000) -- according "
+ "to samba4 idl this is not possible\n", num_rids));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (num_rids) {
+ names = TALLOC_ZERO_ARRAY(p->mem_ctx, const char *, num_rids);
+ attrs = TALLOC_ZERO_ARRAY(p->mem_ctx, enum lsa_SidType, num_rids);
+ wire_attrs = TALLOC_ZERO_ARRAY(p->mem_ctx, uint32, num_rids);
+
+ if ((names == NULL) || (attrs == NULL) || (wire_attrs==NULL))
+ return NT_STATUS_NO_MEMORY;
+ } else {
+ names = NULL;
+ attrs = NULL;
+ wire_attrs = NULL;
+ }
+
+ become_root(); /* lookup_sid can require root privs */
+ status = pdb_lookup_rids(&pol_sid, num_rids, r->in.rids,
+ names, attrs);
+ unbecome_root();
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) && (num_rids == 0)) {
+ status = NT_STATUS_OK;
+ }
+
+ if (!make_samr_lookup_rids(p->mem_ctx, num_rids, names,
+ &lsa_names)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Convert from enum lsa_SidType to uint32 for wire format. */
+ for (i = 0; i < num_rids; i++) {
+ wire_attrs[i] = (uint32)attrs[i];
+ }
+
+ names_array.count = num_rids;
+ names_array.names = lsa_names;
+
+ types_array.count = num_rids;
+ types_array.ids = wire_attrs;
+
+ *r->out.names = names_array;
+ *r->out.types = types_array;
+
+ DEBUG(5,("_samr_LookupRids: %d\n", __LINE__));
+
+ return status;
+}
+
+/*******************************************************************
+ _samr_OpenUser
+********************************************************************/
+
+NTSTATUS _samr_OpenUser(pipes_struct *p,
+ struct samr_OpenUser *r)
+{
+ struct samu *sampass=NULL;
+ DOM_SID sid;
+ POLICY_HND domain_pol = *r->in.domain_handle;
+ POLICY_HND *user_pol = r->out.user_handle;
+ struct samr_info *info = NULL;
+ SEC_DESC *psd = NULL;
+ uint32 acc_granted;
+ uint32 des_access = r->in.access_mask;
+ size_t sd_size;
+ bool ret;
+ NTSTATUS nt_status;
+ SE_PRIV se_rights;
+
+ /* find the domain policy handle and get domain SID / access bits in the domain policy. */
+
+ if ( !get_lsa_policy_samr_sid(p, &domain_pol, &sid, &acc_granted, NULL) )
+ return NT_STATUS_INVALID_HANDLE;
+
+ nt_status = access_check_samr_function(acc_granted,
+ SA_RIGHT_DOMAIN_OPEN_ACCOUNT,
+ "_samr_OpenUser" );
+
+ if ( !NT_STATUS_IS_OK(nt_status) )
+ return nt_status;
+
+ if ( !(sampass = samu_new( p->mem_ctx )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* append the user's RID to it */
+
+ if (!sid_append_rid(&sid, r->in.rid))
+ return NT_STATUS_NO_SUCH_USER;
+
+ /* check if access can be granted as requested by client. */
+
+ make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &usr_generic_mapping, &sid, SAMR_USR_RIGHTS_WRITE_PW);
+ se_map_generic(&des_access, &usr_generic_mapping);
+
+ se_priv_copy( &se_rights, &se_machine_account );
+ se_priv_add( &se_rights, &se_add_users );
+
+ nt_status = access_check_samr_object(psd, p->pipe_user.nt_user_token,
+ &se_rights, GENERIC_RIGHTS_USER_WRITE, des_access,
+ &acc_granted, "_samr_OpenUser");
+
+ if ( !NT_STATUS_IS_OK(nt_status) )
+ return nt_status;
+
+ become_root();
+ ret=pdb_getsampwsid(sampass, &sid);
+ unbecome_root();
+
+ /* check that the SID exists in our domain. */
+ if (ret == False) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ TALLOC_FREE(sampass);
+
+ /* associate the user's SID and access bits with the new handle. */
+ if ((info = get_samr_info_by_sid(&sid)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+ info->acc_granted = acc_granted;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, user_pol, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return NT_STATUS_OK;
+}
+
+/*************************************************************************
+ *************************************************************************/
+
+static NTSTATUS init_samr_parameters_string(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob,
+ struct lsa_BinaryString **_r)
+{
+ struct lsa_BinaryString *r;
+
+ if (!blob || !_r) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ r = TALLOC_ZERO_P(mem_ctx, struct lsa_BinaryString);
+ if (!r) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ r->array = TALLOC_ZERO_ARRAY(mem_ctx, uint16_t, blob->length/2);
+ if (!r->array) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ memcpy(r->array, blob->data, blob->length);
+ r->size = blob->length;
+ r->length = blob->length;
+
+ if (!r->array) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *_r = r;
+
+ return NT_STATUS_OK;
+}
+
+/*************************************************************************
+ get_user_info_7. Safe. Only gives out account_name.
+ *************************************************************************/
+
+static NTSTATUS get_user_info_7(TALLOC_CTX *mem_ctx,
+ struct samr_UserInfo7 *r,
+ DOM_SID *user_sid)
+{
+ struct samu *smbpass=NULL;
+ bool ret;
+ const char *account_name = NULL;
+
+ ZERO_STRUCTP(r);
+
+ if ( !(smbpass = samu_new( mem_ctx )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+ ret = pdb_getsampwsid(smbpass, user_sid);
+ unbecome_root();
+
+ if ( !ret ) {
+ DEBUG(4,("User %s not found\n", sid_string_dbg(user_sid)));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ account_name = talloc_strdup(mem_ctx, pdb_get_username(smbpass));
+ if (!account_name) {
+ TALLOC_FREE(smbpass);
+ return NT_STATUS_NO_MEMORY;
+ }
+ TALLOC_FREE(smbpass);
+
+ DEBUG(3,("User:[%s]\n", account_name));
+
+ init_samr_user_info7(r, account_name);
+
+ return NT_STATUS_OK;
+}
+
+/*************************************************************************
+ get_user_info_9. Only gives out primary group SID.
+ *************************************************************************/
+
+static NTSTATUS get_user_info_9(TALLOC_CTX *mem_ctx,
+ struct samr_UserInfo9 *r,
+ DOM_SID *user_sid)
+{
+ struct samu *smbpass=NULL;
+ bool ret;
+
+ ZERO_STRUCTP(r);
+
+ if ( !(smbpass = samu_new( mem_ctx )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+ ret = pdb_getsampwsid(smbpass, user_sid);
+ unbecome_root();
+
+ if (ret==False) {
+ DEBUG(4,("User %s not found\n", sid_string_dbg(user_sid)));
+ TALLOC_FREE(smbpass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ DEBUG(3,("User:[%s]\n", pdb_get_username(smbpass) ));
+
+ init_samr_user_info9(r, pdb_get_group_rid(smbpass));
+
+ TALLOC_FREE(smbpass);
+
+ return NT_STATUS_OK;
+}
+
+/*************************************************************************
+ get_user_info_16. Safe. Only gives out acb bits.
+ *************************************************************************/
+
+static NTSTATUS get_user_info_16(TALLOC_CTX *mem_ctx,
+ struct samr_UserInfo16 *r,
+ DOM_SID *user_sid)
+{
+ struct samu *smbpass=NULL;
+ bool ret;
+
+ ZERO_STRUCTP(r);
+
+ if ( !(smbpass = samu_new( mem_ctx )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+ ret = pdb_getsampwsid(smbpass, user_sid);
+ unbecome_root();
+
+ if (ret==False) {
+ DEBUG(4,("User %s not found\n", sid_string_dbg(user_sid)));
+ TALLOC_FREE(smbpass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ DEBUG(3,("User:[%s]\n", pdb_get_username(smbpass) ));
+
+ init_samr_user_info16(r, pdb_get_acct_ctrl(smbpass));
+
+ TALLOC_FREE(smbpass);
+
+ return NT_STATUS_OK;
+}
+
+/*************************************************************************
+ get_user_info_18. OK - this is the killer as it gives out password info.
+ Ensure that this is only allowed on an encrypted connection with a root
+ user. JRA.
+ *************************************************************************/
+
+static NTSTATUS get_user_info_18(pipes_struct *p,
+ TALLOC_CTX *mem_ctx,
+ struct samr_UserInfo18 *r,
+ DOM_SID *user_sid)
+{
+ struct samu *smbpass=NULL;
+ bool ret;
+
+ ZERO_STRUCTP(r);
+
+ if (p->auth.auth_type != PIPE_AUTH_TYPE_NTLMSSP || p->auth.auth_type != PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (p->auth.auth_level != PIPE_AUTH_LEVEL_PRIVACY) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /*
+ * Do *NOT* do become_root()/unbecome_root() here ! JRA.
+ */
+
+ if ( !(smbpass = samu_new( mem_ctx )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ret = pdb_getsampwsid(smbpass, user_sid);
+
+ if (ret == False) {
+ DEBUG(4, ("User %s not found\n", sid_string_dbg(user_sid)));
+ TALLOC_FREE(smbpass);
+ return (geteuid() == (uid_t)0) ? NT_STATUS_NO_SUCH_USER : NT_STATUS_ACCESS_DENIED;
+ }
+
+ DEBUG(3,("User:[%s] 0x%x\n", pdb_get_username(smbpass), pdb_get_acct_ctrl(smbpass) ));
+
+ if ( pdb_get_acct_ctrl(smbpass) & ACB_DISABLED) {
+ TALLOC_FREE(smbpass);
+ return NT_STATUS_ACCOUNT_DISABLED;
+ }
+
+ init_samr_user_info18(r, pdb_get_lanman_passwd(smbpass),
+ pdb_get_nt_passwd(smbpass));
+
+ TALLOC_FREE(smbpass);
+
+ return NT_STATUS_OK;
+}
+
+/*************************************************************************
+ get_user_info_20
+ *************************************************************************/
+
+static NTSTATUS get_user_info_20(TALLOC_CTX *mem_ctx,
+ struct samr_UserInfo20 *r,
+ DOM_SID *user_sid)
+{
+ struct samu *sampass=NULL;
+ bool ret;
+ const char *munged_dial = NULL;
+ DATA_BLOB blob;
+ NTSTATUS status;
+ struct lsa_BinaryString *parameters = NULL;
+
+ ZERO_STRUCTP(r);
+
+ if ( !(sampass = samu_new( mem_ctx )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+ ret = pdb_getsampwsid(sampass, user_sid);
+ unbecome_root();
+
+ if (ret == False) {
+ DEBUG(4,("User %s not found\n", sid_string_dbg(user_sid)));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ munged_dial = pdb_get_munged_dial(sampass);
+
+ samr_clear_sam_passwd(sampass);
+
+ DEBUG(3,("User:[%s] has [%s] (length: %d)\n", pdb_get_username(sampass),
+ munged_dial, (int)strlen(munged_dial)));
+
+ if (munged_dial) {
+ blob = base64_decode_data_blob(munged_dial);
+ } else {
+ blob = data_blob_string_const("");
+ }
+
+ status = init_samr_parameters_string(mem_ctx, &blob, &parameters);
+ data_blob_free(&blob);
+ TALLOC_FREE(sampass);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ init_samr_user_info20(r, parameters);
+
+ return NT_STATUS_OK;
+}
+
+
+/*************************************************************************
+ get_user_info_21
+ *************************************************************************/
+
+static NTSTATUS get_user_info_21(TALLOC_CTX *mem_ctx,
+ struct samr_UserInfo21 *r,
+ DOM_SID *user_sid,
+ DOM_SID *domain_sid)
+{
+ NTSTATUS status;
+ struct samu *pw = NULL;
+ bool ret;
+ const DOM_SID *sid_user, *sid_group;
+ uint32_t rid, primary_gid;
+ NTTIME last_logon, last_logoff, last_password_change,
+ acct_expiry, allow_password_change, force_password_change;
+ time_t must_change_time;
+ uint8_t password_expired;
+ const char *account_name, *full_name, *home_directory, *home_drive,
+ *logon_script, *profile_path, *description,
+ *workstations, *comment;
+ struct samr_LogonHours logon_hours;
+ struct lsa_BinaryString *parameters = NULL;
+ const char *munged_dial = NULL;
+ DATA_BLOB blob;
+
+ ZERO_STRUCTP(r);
+
+ if (!(pw = samu_new(mem_ctx))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+ ret = pdb_getsampwsid(pw, user_sid);
+ unbecome_root();
+
+ if (ret == False) {
+ DEBUG(4,("User %s not found\n", sid_string_dbg(user_sid)));
+ TALLOC_FREE(pw);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ samr_clear_sam_passwd(pw);
+
+ DEBUG(3,("User:[%s]\n", pdb_get_username(pw)));
+
+ sid_user = pdb_get_user_sid(pw);
+
+ if (!sid_peek_check_rid(domain_sid, sid_user, &rid)) {
+ DEBUG(0, ("get_user_info_21: User %s has SID %s, \nwhich conflicts with "
+ "the domain sid %s. Failing operation.\n",
+ pdb_get_username(pw), sid_string_dbg(sid_user),
+ sid_string_dbg(domain_sid)));
+ TALLOC_FREE(pw);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ become_root();
+ sid_group = pdb_get_group_sid(pw);
+ unbecome_root();
+
+ if (!sid_peek_check_rid(domain_sid, sid_group, &primary_gid)) {
+ DEBUG(0, ("get_user_info_21: User %s has Primary Group SID %s, \n"
+ "which conflicts with the domain sid %s. Failing operation.\n",
+ pdb_get_username(pw), sid_string_dbg(sid_group),
+ sid_string_dbg(domain_sid)));
+ TALLOC_FREE(pw);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ unix_to_nt_time(&last_logon, pdb_get_logon_time(pw));
+ unix_to_nt_time(&last_logoff, pdb_get_logoff_time(pw));
+ unix_to_nt_time(&acct_expiry, pdb_get_kickoff_time(pw));
+ unix_to_nt_time(&last_password_change, pdb_get_pass_last_set_time(pw));
+ unix_to_nt_time(&allow_password_change, pdb_get_pass_can_change_time(pw));
+
+ must_change_time = pdb_get_pass_must_change_time(pw);
+ if (must_change_time == get_time_t_max()) {
+ unix_to_nt_time_abs(&force_password_change, must_change_time);
+ } else {
+ unix_to_nt_time(&force_password_change, must_change_time);
+ }
+
+ if (pdb_get_pass_must_change_time(pw) == 0) {
+ password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
+ } else {
+ password_expired = 0;
+ }
+
+ munged_dial = pdb_get_munged_dial(pw);
+ if (munged_dial) {
+ blob = base64_decode_data_blob(munged_dial);
+ } else {
+ blob = data_blob_string_const("");
+ }
+
+ status = init_samr_parameters_string(mem_ctx, &blob, &parameters);
+ data_blob_free(&blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(pw);
+ return status;
+ }
+
+ account_name = talloc_strdup(mem_ctx, pdb_get_username(pw));
+ full_name = talloc_strdup(mem_ctx, pdb_get_fullname(pw));
+ home_directory = talloc_strdup(mem_ctx, pdb_get_homedir(pw));
+ home_drive = talloc_strdup(mem_ctx, pdb_get_dir_drive(pw));
+ logon_script = talloc_strdup(mem_ctx, pdb_get_logon_script(pw));
+ profile_path = talloc_strdup(mem_ctx, pdb_get_profile_path(pw));
+ description = talloc_strdup(mem_ctx, pdb_get_acct_desc(pw));
+ workstations = talloc_strdup(mem_ctx, pdb_get_workstations(pw));
+ comment = talloc_strdup(mem_ctx, pdb_get_comment(pw));
+
+ logon_hours = get_logon_hours_from_pdb(mem_ctx, pw);
+#if 0
+
+ /*
+ Look at a user on a real NT4 PDC with usrmgr, press
+ 'ok'. Then you will see that fields_present is set to
+ 0x08f827fa. Look at the user immediately after that again,
+ and you will see that 0x00fffff is returned. This solves
+ the problem that you get access denied after having looked
+ at the user.
+ -- Volker
+ */
+
+#endif
+
+ init_samr_user_info21(r,
+ last_logon,
+ last_logoff,
+ last_password_change,
+ acct_expiry,
+ allow_password_change,
+ force_password_change,
+ account_name,
+ full_name,
+ home_directory,
+ home_drive,
+ logon_script,
+ profile_path,
+ description,
+ workstations,
+ comment,
+ parameters,
+ rid,
+ primary_gid,
+ pdb_get_acct_ctrl(pw),
+ pdb_build_fields_present(pw),
+ logon_hours,
+ pdb_get_bad_password_count(pw),
+ pdb_get_logon_count(pw),
+ 0, /* country_code */
+ 0, /* code_page */
+ 0, /* nt_password_set */
+ 0, /* lm_password_set */
+ password_expired);
+ TALLOC_FREE(pw);
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ _samr_QueryUserInfo
+ ********************************************************************/
+
+NTSTATUS _samr_QueryUserInfo(pipes_struct *p,
+ struct samr_QueryUserInfo *r)
+{
+ NTSTATUS status;
+ union samr_UserInfo *user_info = NULL;
+ struct samr_info *info = NULL;
+ DOM_SID domain_sid;
+ uint32 rid;
+
+ /* search for the handle */
+ if (!find_policy_by_hnd(p, r->in.user_handle, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ domain_sid = info->sid;
+
+ sid_split_rid(&domain_sid, &rid);
+
+ if (!sid_check_is_in_our_domain(&info->sid))
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+
+ DEBUG(5,("_samr_QueryUserInfo: sid:%s\n",
+ sid_string_dbg(&info->sid)));
+
+ user_info = TALLOC_ZERO_P(p->mem_ctx, union samr_UserInfo);
+ if (!user_info) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(5,("_samr_QueryUserInfo: user info level: %d\n", r->in.level));
+
+ switch (r->in.level) {
+ case 7:
+ status = get_user_info_7(p->mem_ctx, &user_info->info7, &info->sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ break;
+ case 9:
+ status = get_user_info_9(p->mem_ctx, &user_info->info9, &info->sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ break;
+ case 16:
+ status = get_user_info_16(p->mem_ctx, &user_info->info16, &info->sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ break;
+
+ case 18:
+ status = get_user_info_18(p, p->mem_ctx, &user_info->info18, &info->sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ break;
+
+ case 20:
+ status = get_user_info_20(p->mem_ctx, &user_info->info20, &info->sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ break;
+
+ case 21:
+ status = get_user_info_21(p->mem_ctx, &user_info->info21,
+ &info->sid, &domain_sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ break;
+
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ *r->out.info = user_info;
+
+ DEBUG(5,("_samr_QueryUserInfo: %d\n", __LINE__));
+
+ return status;
+}
+
+/*******************************************************************
+ _samr_GetGroupsForUser
+ ********************************************************************/
+
+NTSTATUS _samr_GetGroupsForUser(pipes_struct *p,
+ struct samr_GetGroupsForUser *r)
+{
+ struct samu *sam_pass=NULL;
+ DOM_SID sid;
+ DOM_SID *sids;
+ struct samr_RidWithAttribute dom_gid;
+ struct samr_RidWithAttribute *gids = NULL;
+ uint32 primary_group_rid;
+ size_t num_groups = 0;
+ gid_t *unix_gids;
+ size_t i, num_gids;
+ uint32 acc_granted;
+ bool ret;
+ NTSTATUS result;
+ bool success = False;
+
+ struct samr_RidWithAttributeArray *rids = NULL;
+
+ /*
+ * from the SID in the request:
+ * we should send back the list of DOMAIN GROUPS
+ * the user is a member of
+ *
+ * and only the DOMAIN GROUPS
+ * no ALIASES !!! neither aliases of the domain
+ * nor aliases of the builtin SID
+ *
+ * JFM, 12/2/2001
+ */
+
+ DEBUG(5,("_samr_GetGroupsForUser: %d\n", __LINE__));
+
+ rids = TALLOC_ZERO_P(p->mem_ctx, struct samr_RidWithAttributeArray);
+ if (!rids) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* find the policy handle. open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, r->in.user_handle, &sid, &acc_granted, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ result = access_check_samr_function(acc_granted,
+ SA_RIGHT_USER_GET_GROUPS,
+ "_samr_GetGroupsForUser");
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ if (!sid_check_is_in_our_domain(&sid))
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+
+ if ( !(sam_pass = samu_new( p->mem_ctx )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+ ret = pdb_getsampwsid(sam_pass, &sid);
+ unbecome_root();
+
+ if (!ret) {
+ DEBUG(10, ("pdb_getsampwsid failed for %s\n",
+ sid_string_dbg(&sid)));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ sids = NULL;
+
+ /* make both calls inside the root block */
+ become_root();
+ result = pdb_enum_group_memberships(p->mem_ctx, sam_pass,
+ &sids, &unix_gids, &num_groups);
+ if ( NT_STATUS_IS_OK(result) ) {
+ success = sid_peek_check_rid(get_global_sam_sid(),
+ pdb_get_group_sid(sam_pass),
+ &primary_group_rid);
+ }
+ unbecome_root();
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
+ sid_string_dbg(&sid)));
+ return result;
+ }
+
+ if ( !success ) {
+ DEBUG(5, ("Group sid %s for user %s not in our domain\n",
+ sid_string_dbg(pdb_get_group_sid(sam_pass)),
+ pdb_get_username(sam_pass)));
+ TALLOC_FREE(sam_pass);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ gids = NULL;
+ num_gids = 0;
+
+ dom_gid.attributes = (SE_GROUP_MANDATORY|SE_GROUP_ENABLED_BY_DEFAULT|
+ SE_GROUP_ENABLED);
+ dom_gid.rid = primary_group_rid;
+ ADD_TO_ARRAY(p->mem_ctx, struct samr_RidWithAttribute, dom_gid, &gids, &num_gids);
+
+ for (i=0; i<num_groups; i++) {
+
+ if (!sid_peek_check_rid(get_global_sam_sid(),
+ &(sids[i]), &dom_gid.rid)) {
+ DEBUG(10, ("Found sid %s not in our domain\n",
+ sid_string_dbg(&sids[i])));
+ continue;
+ }
+
+ if (dom_gid.rid == primary_group_rid) {
+ /* We added the primary group directly from the
+ * sam_account. The other SIDs are unique from
+ * enum_group_memberships */
+ continue;
+ }
+
+ ADD_TO_ARRAY(p->mem_ctx, struct samr_RidWithAttribute, dom_gid, &gids, &num_gids);
+ }
+
+ rids->count = num_gids;
+ rids->rids = gids;
+
+ *r->out.rids = rids;
+
+ DEBUG(5,("_samr_GetGroupsForUser: %d\n", __LINE__));
+
+ return result;
+}
+
+/*******************************************************************
+ samr_QueryDomainInfo_internal
+ ********************************************************************/
+
+static NTSTATUS samr_QueryDomainInfo_internal(const char *fn_name,
+ pipes_struct *p,
+ struct policy_handle *handle,
+ uint32_t level,
+ union samr_DomainInfo **dom_info_ptr)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ struct samr_info *info = NULL;
+ union samr_DomainInfo *dom_info;
+ uint32 min_pass_len,pass_hist,password_properties;
+ time_t u_expire, u_min_age;
+ NTTIME nt_expire, nt_min_age;
+
+ time_t u_lock_duration, u_reset_time;
+ NTTIME nt_lock_duration, nt_reset_time;
+ uint32 lockout;
+ time_t u_logout;
+ NTTIME nt_logout;
+
+ uint32 account_policy_temp;
+
+ time_t seq_num;
+ uint32 server_role;
+
+ uint32 num_users=0, num_groups=0, num_aliases=0;
+
+ DEBUG(5,("%s: %d\n", fn_name, __LINE__));
+
+ dom_info = TALLOC_ZERO_P(p->mem_ctx, union samr_DomainInfo);
+ if (!dom_info) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *dom_info_ptr = dom_info;
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, handle, (void **)(void *)&info)) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ switch (level) {
+ case 0x01:
+
+ become_root();
+
+ /* AS ROOT !!! */
+
+ pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &account_policy_temp);
+ min_pass_len = account_policy_temp;
+
+ pdb_get_account_policy(AP_PASSWORD_HISTORY, &account_policy_temp);
+ pass_hist = account_policy_temp;
+
+ pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp);
+ password_properties = account_policy_temp;
+
+ pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp);
+ u_expire = account_policy_temp;
+
+ pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &account_policy_temp);
+ u_min_age = account_policy_temp;
+
+ /* !AS ROOT */
+
+ unbecome_root();
+
+ unix_to_nt_time_abs(&nt_expire, u_expire);
+ unix_to_nt_time_abs(&nt_min_age, u_min_age);
+
+ init_samr_DomInfo1(&dom_info->info1,
+ (uint16)min_pass_len,
+ (uint16)pass_hist,
+ password_properties,
+ nt_expire,
+ nt_min_age);
+ break;
+ case 0x02:
+
+ become_root();
+
+ /* AS ROOT !!! */
+
+ num_users = count_sam_users(info->disp_info, ACB_NORMAL);
+ num_groups = count_sam_groups(info->disp_info);
+ num_aliases = count_sam_aliases(info->disp_info);
+
+ pdb_get_account_policy(AP_TIME_TO_LOGOUT, &account_policy_temp);
+ u_logout = account_policy_temp;
+
+ unix_to_nt_time_abs(&nt_logout, u_logout);
+
+ if (!pdb_get_seq_num(&seq_num))
+ seq_num = time(NULL);
+
+ /* !AS ROOT */
+
+ unbecome_root();
+
+ server_role = ROLE_DOMAIN_PDC;
+ if (lp_server_role() == ROLE_DOMAIN_BDC)
+ server_role = ROLE_DOMAIN_BDC;
+
+ init_samr_DomInfo2(&dom_info->info2,
+ nt_logout,
+ lp_serverstring(),
+ lp_workgroup(),
+ global_myname(),
+ seq_num,
+ 1,
+ server_role,
+ 1,
+ num_users,
+ num_groups,
+ num_aliases);
+ break;
+ case 0x03:
+
+ become_root();
+
+ /* AS ROOT !!! */
+
+ {
+ uint32 ul;
+ pdb_get_account_policy(AP_TIME_TO_LOGOUT, &ul);
+ u_logout = (time_t)ul;
+ }
+
+ /* !AS ROOT */
+
+ unbecome_root();
+
+ unix_to_nt_time_abs(&nt_logout, u_logout);
+
+ init_samr_DomInfo3(&dom_info->info3,
+ nt_logout);
+
+ break;
+ case 0x04:
+ init_samr_DomInfo4(&dom_info->info4,
+ lp_serverstring());
+ break;
+ case 0x05:
+ init_samr_DomInfo5(&dom_info->info5,
+ get_global_sam_name());
+ break;
+ case 0x06:
+ /* NT returns its own name when a PDC. win2k and later
+ * only the name of the PDC if itself is a BDC (samba4
+ * idl) */
+ init_samr_DomInfo6(&dom_info->info6,
+ global_myname());
+ break;
+ case 0x07:
+ server_role = ROLE_DOMAIN_PDC;
+ if (lp_server_role() == ROLE_DOMAIN_BDC)
+ server_role = ROLE_DOMAIN_BDC;
+
+ init_samr_DomInfo7(&dom_info->info7,
+ server_role);
+ break;
+ case 0x08:
+
+ become_root();
+
+ /* AS ROOT !!! */
+
+ if (!pdb_get_seq_num(&seq_num)) {
+ seq_num = time(NULL);
+ }
+
+ /* !AS ROOT */
+
+ unbecome_root();
+
+ init_samr_DomInfo8(&dom_info->info8,
+ seq_num,
+ 0);
+ break;
+ case 0x0c:
+
+ become_root();
+
+ /* AS ROOT !!! */
+
+ pdb_get_account_policy(AP_LOCK_ACCOUNT_DURATION, &account_policy_temp);
+ u_lock_duration = account_policy_temp;
+ if (u_lock_duration != -1) {
+ u_lock_duration *= 60;
+ }
+
+ pdb_get_account_policy(AP_RESET_COUNT_TIME, &account_policy_temp);
+ u_reset_time = account_policy_temp * 60;
+
+ pdb_get_account_policy(AP_BAD_ATTEMPT_LOCKOUT, &account_policy_temp);
+ lockout = account_policy_temp;
+
+ /* !AS ROOT */
+
+ unbecome_root();
+
+ unix_to_nt_time_abs(&nt_lock_duration, u_lock_duration);
+ unix_to_nt_time_abs(&nt_reset_time, u_reset_time);
+
+ init_samr_DomInfo12(&dom_info->info12,
+ nt_lock_duration,
+ nt_reset_time,
+ (uint16)lockout);
+ break;
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ DEBUG(5,("%s: %d\n", fn_name, __LINE__));
+
+ return status;
+}
+
+/*******************************************************************
+ _samr_QueryDomainInfo
+ ********************************************************************/
+
+NTSTATUS _samr_QueryDomainInfo(pipes_struct *p,
+ struct samr_QueryDomainInfo *r)
+{
+ return samr_QueryDomainInfo_internal("_samr_QueryDomainInfo",
+ p,
+ r->in.domain_handle,
+ r->in.level,
+ r->out.info);
+}
+
+/* W2k3 seems to use the same check for all 3 objects that can be created via
+ * SAMR, if you try to create for example "Dialup" as an alias it says
+ * "NT_STATUS_USER_EXISTS". This is racy, but we can't really lock the user
+ * database. */
+
+static NTSTATUS can_create(TALLOC_CTX *mem_ctx, const char *new_name)
+{
+ enum lsa_SidType type;
+ bool result;
+
+ DEBUG(10, ("Checking whether [%s] can be created\n", new_name));
+
+ become_root();
+ /* Lookup in our local databases (LOOKUP_NAME_REMOTE not set)
+ * whether the name already exists */
+ result = lookup_name(mem_ctx, new_name, LOOKUP_NAME_LOCAL,
+ NULL, NULL, NULL, &type);
+ unbecome_root();
+
+ if (!result) {
+ DEBUG(10, ("%s does not exist, can create it\n", new_name));
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(5, ("trying to create %s, exists as %s\n",
+ new_name, sid_type_lookup(type)));
+
+ if (type == SID_NAME_DOM_GRP) {
+ return NT_STATUS_GROUP_EXISTS;
+ }
+ if (type == SID_NAME_ALIAS) {
+ return NT_STATUS_ALIAS_EXISTS;
+ }
+
+ /* Yes, the default is NT_STATUS_USER_EXISTS */
+ return NT_STATUS_USER_EXISTS;
+}
+
+/*******************************************************************
+ _samr_CreateUser2
+ ********************************************************************/
+
+NTSTATUS _samr_CreateUser2(pipes_struct *p,
+ struct samr_CreateUser2 *r)
+{
+ const char *account = NULL;
+ DOM_SID sid;
+ POLICY_HND dom_pol = *r->in.domain_handle;
+ uint32_t acb_info = r->in.acct_flags;
+ POLICY_HND *user_pol = r->out.user_handle;
+ struct samr_info *info = NULL;
+ NTSTATUS nt_status;
+ uint32 acc_granted;
+ SEC_DESC *psd;
+ size_t sd_size;
+ /* check this, when giving away 'add computer to domain' privs */
+ uint32 des_access = GENERIC_RIGHTS_USER_ALL_ACCESS;
+ bool can_add_account = False;
+ SE_PRIV se_rights;
+ DISP_INFO *disp_info = NULL;
+
+ /* Get the domain SID stored in the domain policy */
+ if (!get_lsa_policy_samr_sid(p, &dom_pol, &sid, &acc_granted,
+ &disp_info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ nt_status = access_check_samr_function(acc_granted,
+ SA_RIGHT_DOMAIN_CREATE_USER,
+ "_samr_CreateUser2");
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ if (!(acb_info == ACB_NORMAL || acb_info == ACB_DOMTRUST ||
+ acb_info == ACB_WSTRUST || acb_info == ACB_SVRTRUST)) {
+ /* Match Win2k, and return NT_STATUS_INVALID_PARAMETER if
+ this parameter is not an account type */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ account = r->in.account_name->string;
+ if (account == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ nt_status = can_create(p->mem_ctx, account);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ /* determine which user right we need to check based on the acb_info */
+
+ if ( acb_info & ACB_WSTRUST )
+ {
+ se_priv_copy( &se_rights, &se_machine_account );
+ can_add_account = user_has_privileges(
+ p->pipe_user.nt_user_token, &se_rights );
+ }
+ /* usrmgr.exe (and net rpc trustdom grant) creates a normal user
+ account for domain trusts and changes the ACB flags later */
+ else if ( acb_info & ACB_NORMAL &&
+ (account[strlen(account)-1] != '$') )
+ {
+ se_priv_copy( &se_rights, &se_add_users );
+ can_add_account = user_has_privileges(
+ p->pipe_user.nt_user_token, &se_rights );
+ }
+ else /* implicit assumption of a BDC or domain trust account here
+ * (we already check the flags earlier) */
+ {
+ if ( lp_enable_privileges() ) {
+ /* only Domain Admins can add a BDC or domain trust */
+ se_priv_copy( &se_rights, &se_priv_none );
+ can_add_account = nt_token_check_domain_rid(
+ p->pipe_user.nt_user_token,
+ DOMAIN_GROUP_RID_ADMINS );
+ }
+ }
+
+ DEBUG(5, ("_samr_CreateUser2: %s can add this account : %s\n",
+ uidtoname(p->pipe_user.ut.uid),
+ can_add_account ? "True":"False" ));
+
+ /********** BEGIN Admin BLOCK **********/
+
+ if ( can_add_account )
+ become_root();
+
+ nt_status = pdb_create_user(p->mem_ctx, account, acb_info,
+ r->out.rid);
+
+ if ( can_add_account )
+ unbecome_root();
+
+ /********** END Admin BLOCK **********/
+
+ /* now check for failure */
+
+ if ( !NT_STATUS_IS_OK(nt_status) )
+ return nt_status;
+
+ /* Get the user's SID */
+
+ sid_compose(&sid, get_global_sam_sid(), *r->out.rid);
+
+ make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &usr_generic_mapping,
+ &sid, SAMR_USR_RIGHTS_WRITE_PW);
+ se_map_generic(&des_access, &usr_generic_mapping);
+
+ nt_status = access_check_samr_object(psd, p->pipe_user.nt_user_token,
+ &se_rights, GENERIC_RIGHTS_USER_WRITE, des_access,
+ &acc_granted, "_samr_CreateUser2");
+
+ if ( !NT_STATUS_IS_OK(nt_status) ) {
+ return nt_status;
+ }
+
+ /* associate the user's SID with the new handle. */
+ if ((info = get_samr_info_by_sid(&sid)) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCTP(info);
+ info->sid = sid;
+ info->acc_granted = acc_granted;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, user_pol, free_samr_info, (void *)info)) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ /* After a "set" ensure we have no cached display info. */
+ force_flush_samr_cache(info->disp_info);
+
+ *r->out.access_granted = acc_granted;
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ _samr_Connect
+ ********************************************************************/
+
+NTSTATUS _samr_Connect(pipes_struct *p,
+ struct samr_Connect *r)
+{
+ struct samr_info *info = NULL;
+ uint32 des_access = r->in.access_mask;
+
+ /* Access check */
+
+ if (!pipe_access_check(p)) {
+ DEBUG(3, ("access denied to _samr_Connect\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* set up the SAMR connect_anon response */
+
+ /* associate the user's SID with the new handle. */
+ if ((info = get_samr_info_by_sid(NULL)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ /* don't give away the farm but this is probably ok. The SA_RIGHT_SAM_ENUM_DOMAINS
+ was observed from a win98 client trying to enumerate users (when configured
+ user level access control on shares) --jerry */
+
+ if (des_access == MAXIMUM_ALLOWED_ACCESS) {
+ /* Map to max possible knowing we're filtered below. */
+ des_access = GENERIC_ALL_ACCESS;
+ }
+
+ se_map_generic( &des_access, &sam_generic_mapping );
+ info->acc_granted = des_access & (SA_RIGHT_SAM_ENUM_DOMAINS|SA_RIGHT_SAM_OPEN_DOMAIN);
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, r->out.connect_handle, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ _samr_Connect2
+ ********************************************************************/
+
+NTSTATUS _samr_Connect2(pipes_struct *p,
+ struct samr_Connect2 *r)
+{
+ struct samr_info *info = NULL;
+ SEC_DESC *psd = NULL;
+ uint32 acc_granted;
+ uint32 des_access = r->in.access_mask;
+ NTSTATUS nt_status;
+ size_t sd_size;
+
+
+ DEBUG(5,("_samr_Connect2: %d\n", __LINE__));
+
+ /* Access check */
+
+ if (!pipe_access_check(p)) {
+ DEBUG(3, ("access denied to _samr_Connect2\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &sam_generic_mapping, NULL, 0);
+ se_map_generic(&des_access, &sam_generic_mapping);
+
+ nt_status = access_check_samr_object(psd, p->pipe_user.nt_user_token,
+ NULL, 0, des_access, &acc_granted, "_samr_Connect2");
+
+ if ( !NT_STATUS_IS_OK(nt_status) )
+ return nt_status;
+
+ /* associate the user's SID and access granted with the new handle. */
+ if ((info = get_samr_info_by_sid(NULL)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ info->acc_granted = acc_granted;
+ info->status = r->in.access_mask; /* this looks so wrong... - gd */
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, r->out.connect_handle, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ DEBUG(5,("_samr_Connect2: %d\n", __LINE__));
+
+ return nt_status;
+}
+
+/*******************************************************************
+ _samr_Connect4
+ ********************************************************************/
+
+NTSTATUS _samr_Connect4(pipes_struct *p,
+ struct samr_Connect4 *r)
+{
+ struct samr_info *info = NULL;
+ SEC_DESC *psd = NULL;
+ uint32 acc_granted;
+ uint32 des_access = r->in.access_mask;
+ NTSTATUS nt_status;
+ size_t sd_size;
+
+
+ DEBUG(5,("_samr_Connect4: %d\n", __LINE__));
+
+ /* Access check */
+
+ if (!pipe_access_check(p)) {
+ DEBUG(3, ("access denied to samr_Connect4\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &sam_generic_mapping, NULL, 0);
+ se_map_generic(&des_access, &sam_generic_mapping);
+
+ nt_status = access_check_samr_object(psd, p->pipe_user.nt_user_token,
+ NULL, 0, des_access, &acc_granted, "_samr_Connect4");
+
+ if ( !NT_STATUS_IS_OK(nt_status) )
+ return nt_status;
+
+ /* associate the user's SID and access granted with the new handle. */
+ if ((info = get_samr_info_by_sid(NULL)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ info->acc_granted = acc_granted;
+ info->status = r->in.access_mask; /* ??? */
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, r->out.connect_handle, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ DEBUG(5,("_samr_Connect4: %d\n", __LINE__));
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ _samr_Connect5
+ ********************************************************************/
+
+NTSTATUS _samr_Connect5(pipes_struct *p,
+ struct samr_Connect5 *r)
+{
+ struct samr_info *info = NULL;
+ SEC_DESC *psd = NULL;
+ uint32 acc_granted;
+ uint32 des_access = r->in.access_mask;
+ NTSTATUS nt_status;
+ size_t sd_size;
+ struct samr_ConnectInfo1 info1;
+
+ DEBUG(5,("_samr_Connect5: %d\n", __LINE__));
+
+ /* Access check */
+
+ if (!pipe_access_check(p)) {
+ DEBUG(3, ("access denied to samr_Connect5\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &sam_generic_mapping, NULL, 0);
+ se_map_generic(&des_access, &sam_generic_mapping);
+
+ nt_status = access_check_samr_object(psd, p->pipe_user.nt_user_token,
+ NULL, 0, des_access, &acc_granted, "_samr_Connect5");
+
+ if ( !NT_STATUS_IS_OK(nt_status) )
+ return nt_status;
+
+ /* associate the user's SID and access granted with the new handle. */
+ if ((info = get_samr_info_by_sid(NULL)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ info->acc_granted = acc_granted;
+ info->status = r->in.access_mask; /* ??? */
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, r->out.connect_handle, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ DEBUG(5,("_samr_Connect5: %d\n", __LINE__));
+
+ info1.client_version = SAMR_CONNECT_AFTER_W2K;
+ info1.unknown2 = 0;
+
+ *r->out.level_out = 1;
+ r->out.info_out->info1 = info1;
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ _samr_LookupDomain
+ **********************************************************************/
+
+NTSTATUS _samr_LookupDomain(pipes_struct *p,
+ struct samr_LookupDomain *r)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ struct samr_info *info;
+ const char *domain_name;
+ DOM_SID *sid = NULL;
+
+ if (!find_policy_by_hnd(p, r->in.connect_handle, (void**)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* win9x user manager likes to use SA_RIGHT_SAM_ENUM_DOMAINS here.
+ Reverted that change so we will work with RAS servers again */
+
+ status = access_check_samr_function(info->acc_granted,
+ SA_RIGHT_SAM_OPEN_DOMAIN,
+ "_samr_LookupDomain");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ domain_name = r->in.domain_name->string;
+
+ sid = TALLOC_ZERO_P(p->mem_ctx, struct dom_sid2);
+ if (!sid) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (strequal(domain_name, builtin_domain_name())) {
+ sid_copy(sid, &global_sid_Builtin);
+ } else {
+ if (!secrets_fetch_domain_sid(domain_name, sid)) {
+ status = NT_STATUS_NO_SUCH_DOMAIN;
+ }
+ }
+
+ DEBUG(2,("Returning domain sid for domain %s -> %s\n", domain_name,
+ sid_string_dbg(sid)));
+
+ *r->out.sid = sid;
+
+ return status;
+}
+
+/**********************************************************************
+ _samr_EnumDomains
+ **********************************************************************/
+
+NTSTATUS _samr_EnumDomains(pipes_struct *p,
+ struct samr_EnumDomains *r)
+{
+ NTSTATUS status;
+ struct samr_info *info;
+ uint32_t num_entries = 2;
+ struct samr_SamEntry *entry_array = NULL;
+ struct samr_SamArray *sam;
+
+ if (!find_policy_by_hnd(p, r->in.connect_handle, (void**)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(info->acc_granted,
+ SA_RIGHT_SAM_ENUM_DOMAINS,
+ "_samr_EnumDomains");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ sam = TALLOC_ZERO_P(p->mem_ctx, struct samr_SamArray);
+ if (!sam) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ entry_array = TALLOC_ZERO_ARRAY(p->mem_ctx,
+ struct samr_SamEntry,
+ num_entries);
+ if (!entry_array) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ entry_array[0].idx = 0;
+ init_lsa_String(&entry_array[0].name, get_global_sam_name());
+
+ entry_array[1].idx = 1;
+ init_lsa_String(&entry_array[1].name, "Builtin");
+
+ sam->count = num_entries;
+ sam->entries = entry_array;
+
+ *r->out.sam = sam;
+ *r->out.num_entries = num_entries;
+
+ return status;
+}
+
+/*******************************************************************
+ _samr_OpenAlias
+ ********************************************************************/
+
+NTSTATUS _samr_OpenAlias(pipes_struct *p,
+ struct samr_OpenAlias *r)
+{
+ DOM_SID sid;
+ POLICY_HND domain_pol = *r->in.domain_handle;
+ uint32 alias_rid = r->in.rid;
+ POLICY_HND *alias_pol = r->out.alias_handle;
+ struct samr_info *info = NULL;
+ SEC_DESC *psd = NULL;
+ uint32 acc_granted;
+ uint32 des_access = r->in.access_mask;
+ size_t sd_size;
+ NTSTATUS status;
+ SE_PRIV se_rights;
+
+ /* find the domain policy and get the SID / access bits stored in the domain policy */
+
+ if ( !get_lsa_policy_samr_sid(p, &domain_pol, &sid, &acc_granted, NULL) )
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(acc_granted,
+ SA_RIGHT_DOMAIN_OPEN_ACCOUNT,
+ "_samr_OpenAlias");
+
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+ /* append the alias' RID to it */
+
+ if (!sid_append_rid(&sid, alias_rid))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ /*check if access can be granted as requested by client. */
+
+ make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &ali_generic_mapping, NULL, 0);
+ se_map_generic(&des_access,&ali_generic_mapping);
+
+ se_priv_copy( &se_rights, &se_add_users );
+
+
+ status = access_check_samr_object(psd, p->pipe_user.nt_user_token,
+ &se_rights, GENERIC_RIGHTS_ALIAS_WRITE, des_access,
+ &acc_granted, "_samr_OpenAlias");
+
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+ {
+ /* Check we actually have the requested alias */
+ enum lsa_SidType type;
+ bool result;
+ gid_t gid;
+
+ become_root();
+ result = lookup_sid(NULL, &sid, NULL, NULL, &type);
+ unbecome_root();
+
+ if (!result || (type != SID_NAME_ALIAS)) {
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ /* make sure there is a mapping */
+
+ if ( !sid_to_gid( &sid, &gid ) ) {
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ }
+
+ /* associate the alias SID with the new handle. */
+ if ((info = get_samr_info_by_sid(&sid)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ info->acc_granted = acc_granted;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, alias_pol, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ set_user_info_7
+ ********************************************************************/
+
+static NTSTATUS set_user_info_7(TALLOC_CTX *mem_ctx,
+ struct samr_UserInfo7 *id7,
+ struct samu *pwd)
+{
+ NTSTATUS rc;
+
+ if (id7 == NULL) {
+ DEBUG(5, ("set_user_info_7: NULL id7\n"));
+ TALLOC_FREE(pwd);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (!id7->account_name.string) {
+ DEBUG(5, ("set_user_info_7: failed to get new username\n"));
+ TALLOC_FREE(pwd);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* check to see if the new username already exists. Note: we can't
+ reliably lock all backends, so there is potentially the
+ possibility that a user can be created in between this check and
+ the rename. The rename should fail, but may not get the
+ exact same failure status code. I think this is small enough
+ of a window for this type of operation and the results are
+ simply that the rename fails with a slightly different status
+ code (like UNSUCCESSFUL instead of ALREADY_EXISTS). */
+
+ rc = can_create(mem_ctx, id7->account_name.string);
+ if (!NT_STATUS_IS_OK(rc)) {
+ return rc;
+ }
+
+ rc = pdb_rename_sam_account(pwd, id7->account_name.string);
+
+ TALLOC_FREE(pwd);
+ return rc;
+}
+
+/*******************************************************************
+ set_user_info_16
+ ********************************************************************/
+
+static bool set_user_info_16(struct samr_UserInfo16 *id16,
+ struct samu *pwd)
+{
+ if (id16 == NULL) {
+ DEBUG(5, ("set_user_info_16: NULL id16\n"));
+ TALLOC_FREE(pwd);
+ return False;
+ }
+
+ /* FIX ME: check if the value is really changed --metze */
+ if (!pdb_set_acct_ctrl(pwd, id16->acct_flags, PDB_CHANGED)) {
+ TALLOC_FREE(pwd);
+ return False;
+ }
+
+ if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) {
+ TALLOC_FREE(pwd);
+ return False;
+ }
+
+ TALLOC_FREE(pwd);
+
+ return True;
+}
+
+/*******************************************************************
+ set_user_info_18
+ ********************************************************************/
+
+static bool set_user_info_18(struct samr_UserInfo18 *id18,
+ struct samu *pwd)
+{
+ if (id18 == NULL) {
+ DEBUG(2, ("set_user_info_18: id18 is NULL\n"));
+ TALLOC_FREE(pwd);
+ return False;
+ }
+
+ if (!pdb_set_lanman_passwd (pwd, id18->lm_pwd.hash, PDB_CHANGED)) {
+ TALLOC_FREE(pwd);
+ return False;
+ }
+ if (!pdb_set_nt_passwd (pwd, id18->nt_pwd.hash, PDB_CHANGED)) {
+ TALLOC_FREE(pwd);
+ return False;
+ }
+ if (!pdb_set_pass_last_set_time (pwd, time(NULL), PDB_CHANGED)) {
+ TALLOC_FREE(pwd);
+ return False;
+ }
+
+ if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) {
+ TALLOC_FREE(pwd);
+ return False;
+ }
+
+ TALLOC_FREE(pwd);
+ return True;
+}
+
+/*******************************************************************
+ set_user_info_20
+ ********************************************************************/
+
+static bool set_user_info_20(struct samr_UserInfo20 *id20,
+ struct samu *pwd)
+{
+ if (id20 == NULL) {
+ DEBUG(5, ("set_user_info_20: NULL id20\n"));
+ return False;
+ }
+
+ copy_id20_to_sam_passwd(pwd, id20);
+
+ /* write the change out */
+ if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) {
+ TALLOC_FREE(pwd);
+ return False;
+ }
+
+ TALLOC_FREE(pwd);
+
+ return True;
+}
+
+/*******************************************************************
+ set_user_info_21
+ ********************************************************************/
+
+static NTSTATUS set_user_info_21(TALLOC_CTX *mem_ctx,
+ struct samr_UserInfo21 *id21,
+ struct samu *pwd)
+{
+ NTSTATUS status;
+
+ if (id21 == NULL) {
+ DEBUG(5, ("set_user_info_21: NULL id21\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* we need to separately check for an account rename first */
+
+ if (id21->account_name.string &&
+ (!strequal(id21->account_name.string, pdb_get_username(pwd))))
+ {
+
+ /* check to see if the new username already exists. Note: we can't
+ reliably lock all backends, so there is potentially the
+ possibility that a user can be created in between this check and
+ the rename. The rename should fail, but may not get the
+ exact same failure status code. I think this is small enough
+ of a window for this type of operation and the results are
+ simply that the rename fails with a slightly different status
+ code (like UNSUCCESSFUL instead of ALREADY_EXISTS). */
+
+ status = can_create(mem_ctx, id21->account_name.string);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = pdb_rename_sam_account(pwd, id21->account_name.string);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("set_user_info_21: failed to rename account: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(pwd);
+ return status;
+ }
+
+ /* set the new username so that later
+ functions can work on the new account */
+ pdb_set_username(pwd, id21->account_name.string, PDB_SET);
+ }
+
+ copy_id21_to_sam_passwd("INFO_21", pwd, id21);
+
+ /*
+ * The funny part about the previous two calls is
+ * that pwd still has the password hashes from the
+ * passdb entry. These have not been updated from
+ * id21. I don't know if they need to be set. --jerry
+ */
+
+ if ( IS_SAM_CHANGED(pwd, PDB_GROUPSID) ) {
+ status = pdb_set_unix_primary_group(mem_ctx, pwd);
+ if ( !NT_STATUS_IS_OK(status) ) {
+ return status;
+ }
+ }
+
+ /* Don't worry about writing out the user account since the
+ primary group SID is generated solely from the user's Unix
+ primary group. */
+
+ /* write the change out */
+ if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) {
+ TALLOC_FREE(pwd);
+ return status;
+ }
+
+ TALLOC_FREE(pwd);
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ set_user_info_23
+ ********************************************************************/
+
+static NTSTATUS set_user_info_23(TALLOC_CTX *mem_ctx,
+ struct samr_UserInfo23 *id23,
+ struct samu *pwd)
+{
+ char *plaintext_buf = NULL;
+ uint32 len = 0;
+ uint16 acct_ctrl;
+ NTSTATUS status;
+
+ if (id23 == NULL) {
+ DEBUG(5, ("set_user_info_23: NULL id23\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ DEBUG(5, ("Attempting administrator password change (level 23) for user %s\n",
+ pdb_get_username(pwd)));
+
+ acct_ctrl = pdb_get_acct_ctrl(pwd);
+
+ if (!decode_pw_buffer(mem_ctx,
+ id23->password.data,
+ &plaintext_buf,
+ &len,
+ STR_UNICODE)) {
+ TALLOC_FREE(pwd);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!pdb_set_plaintext_passwd (pwd, plaintext_buf)) {
+ TALLOC_FREE(pwd);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ copy_id23_to_sam_passwd(pwd, id23);
+
+ /* if it's a trust account, don't update /etc/passwd */
+ if ( ( (acct_ctrl & ACB_DOMTRUST) == ACB_DOMTRUST ) ||
+ ( (acct_ctrl & ACB_WSTRUST) == ACB_WSTRUST) ||
+ ( (acct_ctrl & ACB_SVRTRUST) == ACB_SVRTRUST) ) {
+ DEBUG(5, ("Changing trust account. Not updating /etc/passwd\n"));
+ } else {
+ /* update the UNIX password */
+ if (lp_unix_password_sync() ) {
+ struct passwd *passwd;
+ if (pdb_get_username(pwd) == NULL) {
+ DEBUG(1, ("chgpasswd: User without name???\n"));
+ TALLOC_FREE(pwd);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ passwd = Get_Pwnam_alloc(pwd, pdb_get_username(pwd));
+ if (passwd == NULL) {
+ DEBUG(1, ("chgpasswd: Username does not exist in system !?!\n"));
+ }
+
+ if(!chgpasswd(pdb_get_username(pwd), passwd, "", plaintext_buf, True)) {
+ TALLOC_FREE(pwd);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ TALLOC_FREE(passwd);
+ }
+ }
+
+ memset(plaintext_buf, '\0', strlen(plaintext_buf));
+
+ if (IS_SAM_CHANGED(pwd, PDB_GROUPSID) &&
+ (!NT_STATUS_IS_OK(status = pdb_set_unix_primary_group(mem_ctx,
+ pwd)))) {
+ TALLOC_FREE(pwd);
+ return status;
+ }
+
+ if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) {
+ TALLOC_FREE(pwd);
+ return status;
+ }
+
+ TALLOC_FREE(pwd);
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ set_user_info_pw
+ ********************************************************************/
+
+static bool set_user_info_pw(uint8 *pass, struct samu *pwd,
+ int level)
+{
+ uint32 len = 0;
+ char *plaintext_buf = NULL;
+ uint32 acct_ctrl;
+ time_t last_set_time;
+ enum pdb_value_state last_set_state;
+
+ DEBUG(5, ("Attempting administrator password change for user %s\n",
+ pdb_get_username(pwd)));
+
+ acct_ctrl = pdb_get_acct_ctrl(pwd);
+ /* we need to know if it's expired, because this is an admin change, not a
+ user change, so it's still expired when we're done */
+ last_set_state = pdb_get_init_flags(pwd, PDB_PASSLASTSET);
+ last_set_time = pdb_get_pass_last_set_time(pwd);
+
+ if (!decode_pw_buffer(talloc_tos(),
+ pass,
+ &plaintext_buf,
+ &len,
+ STR_UNICODE)) {
+ TALLOC_FREE(pwd);
+ return False;
+ }
+
+ if (!pdb_set_plaintext_passwd (pwd, plaintext_buf)) {
+ TALLOC_FREE(pwd);
+ return False;
+ }
+
+ /* if it's a trust account, don't update /etc/passwd */
+ if ( ( (acct_ctrl & ACB_DOMTRUST) == ACB_DOMTRUST ) ||
+ ( (acct_ctrl & ACB_WSTRUST) == ACB_WSTRUST) ||
+ ( (acct_ctrl & ACB_SVRTRUST) == ACB_SVRTRUST) ) {
+ DEBUG(5, ("Changing trust account or non-unix-user password, not updating /etc/passwd\n"));
+ } else {
+ /* update the UNIX password */
+ if (lp_unix_password_sync()) {
+ struct passwd *passwd;
+
+ if (pdb_get_username(pwd) == NULL) {
+ DEBUG(1, ("chgpasswd: User without name???\n"));
+ TALLOC_FREE(pwd);
+ return False;
+ }
+
+ passwd = Get_Pwnam_alloc(pwd, pdb_get_username(pwd));
+ if (passwd == NULL) {
+ DEBUG(1, ("chgpasswd: Username does not exist in system !?!\n"));
+ }
+
+ if(!chgpasswd(pdb_get_username(pwd), passwd, "", plaintext_buf, True)) {
+ TALLOC_FREE(pwd);
+ return False;
+ }
+ TALLOC_FREE(passwd);
+ }
+ }
+
+ memset(plaintext_buf, '\0', strlen(plaintext_buf));
+
+ /*
+ * A level 25 change does reset the pwdlastset field, a level 24
+ * change does not. I know this is probably not the full story, but
+ * it is needed to make XP join LDAP correctly, without it the later
+ * auth2 check can fail with PWD_MUST_CHANGE.
+ */
+ if (level != 25) {
+ /*
+ * restore last set time as this is an admin change, not a
+ * user pw change
+ */
+ pdb_set_pass_last_set_time (pwd, last_set_time,
+ last_set_state);
+ }
+
+ DEBUG(5,("set_user_info_pw: pdb_update_pwd()\n"));
+
+ /* update the SAMBA password */
+ if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) {
+ TALLOC_FREE(pwd);
+ return False;
+ }
+
+ TALLOC_FREE(pwd);
+
+ return True;
+}
+
+/*******************************************************************
+ set_user_info_25
+ ********************************************************************/
+
+static NTSTATUS set_user_info_25(TALLOC_CTX *mem_ctx,
+ struct samr_UserInfo25 *id25,
+ struct samu *pwd)
+{
+ NTSTATUS status;
+
+ if (id25 == NULL) {
+ DEBUG(5, ("set_user_info_25: NULL id25\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ copy_id25_to_sam_passwd(pwd, id25);
+
+ /* write the change out */
+ if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) {
+ TALLOC_FREE(pwd);
+ return status;
+ }
+
+ /*
+ * We need to "pdb_update_sam_account" before the unix primary group
+ * is set, because the idealx scripts would also change the
+ * sambaPrimaryGroupSid using the ldap replace method. pdb_ldap uses
+ * the delete explicit / add explicit, which would then fail to find
+ * the previous primaryGroupSid value.
+ */
+
+ if ( IS_SAM_CHANGED(pwd, PDB_GROUPSID) ) {
+ status = pdb_set_unix_primary_group(mem_ctx, pwd);
+ if ( !NT_STATUS_IS_OK(status) ) {
+ return status;
+ }
+ }
+
+ /* WARNING: No TALLOC_FREE(pwd), we are about to set the password
+ * hereafter! */
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ samr_SetUserInfo_internal
+ ********************************************************************/
+
+static NTSTATUS samr_SetUserInfo_internal(const char *fn_name,
+ pipes_struct *p,
+ struct policy_handle *user_handle,
+ uint16_t level,
+ union samr_UserInfo *info)
+{
+ NTSTATUS status;
+ struct samu *pwd = NULL;
+ DOM_SID sid;
+ POLICY_HND *pol = user_handle;
+ uint16_t switch_value = level;
+ uint32_t acc_granted;
+ uint32_t acc_required;
+ bool ret;
+ bool has_enough_rights = False;
+ uint32_t acb_info;
+ DISP_INFO *disp_info = NULL;
+
+ DEBUG(5,("%s: %d\n", fn_name, __LINE__));
+
+ /* find the policy handle. open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, pol, &sid, &acc_granted, &disp_info)) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ /* This is tricky. A WinXP domain join sets
+ (SA_RIGHT_USER_SET_PASSWORD|SA_RIGHT_USER_SET_ATTRIBUTES|SA_RIGHT_USER_ACCT_FLAGS_EXPIRY)
+ The MMC lusrmgr plugin includes these perms and more in the SamrOpenUser(). But the
+ standard Win32 API calls just ask for SA_RIGHT_USER_SET_PASSWORD in the SamrOpenUser().
+ This should be enough for levels 18, 24, 25,& 26. Info level 23 can set more so
+ we'll use the set from the WinXP join as the basis. */
+
+ switch (switch_value) {
+ case 18:
+ case 24:
+ case 25:
+ case 26:
+ acc_required = SA_RIGHT_USER_SET_PASSWORD;
+ break;
+ default:
+ acc_required = SA_RIGHT_USER_SET_PASSWORD |
+ SA_RIGHT_USER_SET_ATTRIBUTES |
+ SA_RIGHT_USER_ACCT_FLAGS_EXPIRY;
+ break;
+ }
+
+ status = access_check_samr_function(acc_granted,
+ acc_required,
+ fn_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(5, ("%s: sid:%s, level:%d\n",
+ fn_name, sid_string_dbg(&sid), switch_value));
+
+ if (info == NULL) {
+ DEBUG(5, ("%s: NULL info level\n", fn_name));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ if (!(pwd = samu_new(NULL))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+ ret = pdb_getsampwsid(pwd, &sid);
+ unbecome_root();
+
+ if (!ret) {
+ TALLOC_FREE(pwd);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* deal with machine password changes differently from userinfo changes */
+ /* check to see if we have the sufficient rights */
+
+ acb_info = pdb_get_acct_ctrl(pwd);
+ if (acb_info & ACB_WSTRUST)
+ has_enough_rights = user_has_privileges(p->pipe_user.nt_user_token,
+ &se_machine_account);
+ else if (acb_info & ACB_NORMAL)
+ has_enough_rights = user_has_privileges(p->pipe_user.nt_user_token,
+ &se_add_users);
+ else if (acb_info & (ACB_SVRTRUST|ACB_DOMTRUST)) {
+ if (lp_enable_privileges()) {
+ has_enough_rights = nt_token_check_domain_rid(p->pipe_user.nt_user_token,
+ DOMAIN_GROUP_RID_ADMINS);
+ }
+ }
+
+ DEBUG(5, ("%s: %s does%s possess sufficient rights\n",
+ fn_name,
+ uidtoname(p->pipe_user.ut.uid),
+ has_enough_rights ? "" : " not"));
+
+ /* ================ BEGIN SeMachineAccountPrivilege BLOCK ================ */
+
+ if (has_enough_rights) {
+ become_root();
+ }
+
+ /* ok! user info levels (lots: see MSDEV help), off we go... */
+
+ switch (switch_value) {
+
+ case 7:
+ status = set_user_info_7(p->mem_ctx,
+ &info->info7, pwd);
+ break;
+
+ case 16:
+ if (!set_user_info_16(&info->info16, pwd)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ }
+ break;
+
+ case 18:
+ /* Used by AS/U JRA. */
+ if (!set_user_info_18(&info->info18, pwd)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ }
+ break;
+
+ case 20:
+ if (!set_user_info_20(&info->info20, pwd)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ }
+ break;
+
+ case 21:
+ status = set_user_info_21(p->mem_ctx,
+ &info->info21, pwd);
+ break;
+
+ case 23:
+ if (!p->server_info->user_session_key.length) {
+ status = NT_STATUS_NO_USER_SESSION_KEY;
+ }
+ SamOEMhashBlob(info->info23.password.data, 516,
+ &p->server_info->user_session_key);
+
+ dump_data(100, info->info23.password.data, 516);
+
+ status = set_user_info_23(p->mem_ctx,
+ &info->info23, pwd);
+ break;
+
+ case 24:
+ if (!p->server_info->user_session_key.length) {
+ status = NT_STATUS_NO_USER_SESSION_KEY;
+ }
+ SamOEMhashBlob(info->info24.password.data,
+ 516,
+ &p->server_info->user_session_key);
+
+ dump_data(100, info->info24.password.data, 516);
+
+ if (!set_user_info_pw(info->info24.password.data, pwd,
+ switch_value)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ }
+ break;
+
+ case 25:
+ if (!p->server_info->user_session_key.length) {
+ status = NT_STATUS_NO_USER_SESSION_KEY;
+ }
+ encode_or_decode_arc4_passwd_buffer(
+ info->info25.password.data,
+ &p->server_info->user_session_key);
+
+ dump_data(100, info->info25.password.data, 532);
+
+ status = set_user_info_25(p->mem_ctx,
+ &info->info25, pwd);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ if (!set_user_info_pw(info->info25.password.data, pwd,
+ switch_value)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ }
+ break;
+
+ case 26:
+ if (!p->server_info->user_session_key.length) {
+ status = NT_STATUS_NO_USER_SESSION_KEY;
+ }
+ encode_or_decode_arc4_passwd_buffer(
+ info->info26.password.data,
+ &p->server_info->user_session_key);
+
+ dump_data(100, info->info26.password.data, 516);
+
+ if (!set_user_info_pw(info->info26.password.data, pwd,
+ switch_value)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ }
+ break;
+
+ default:
+ status = NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ done:
+
+ if (has_enough_rights) {
+ unbecome_root();
+ }
+
+ /* ================ END SeMachineAccountPrivilege BLOCK ================ */
+
+ if (NT_STATUS_IS_OK(status)) {
+ force_flush_samr_cache(disp_info);
+ }
+
+ return status;
+}
+
+/*******************************************************************
+ _samr_SetUserInfo
+ ********************************************************************/
+
+NTSTATUS _samr_SetUserInfo(pipes_struct *p,
+ struct samr_SetUserInfo *r)
+{
+ return samr_SetUserInfo_internal("_samr_SetUserInfo",
+ p,
+ r->in.user_handle,
+ r->in.level,
+ r->in.info);
+}
+
+/*******************************************************************
+ _samr_SetUserInfo2
+ ********************************************************************/
+
+NTSTATUS _samr_SetUserInfo2(pipes_struct *p,
+ struct samr_SetUserInfo2 *r)
+{
+ return samr_SetUserInfo_internal("_samr_SetUserInfo2",
+ p,
+ r->in.user_handle,
+ r->in.level,
+ r->in.info);
+}
+
+/*********************************************************************
+ _samr_GetAliasMembership
+*********************************************************************/
+
+NTSTATUS _samr_GetAliasMembership(pipes_struct *p,
+ struct samr_GetAliasMembership *r)
+{
+ size_t num_alias_rids;
+ uint32 *alias_rids;
+ struct samr_info *info = NULL;
+ size_t i;
+
+ NTSTATUS ntstatus1;
+ NTSTATUS ntstatus2;
+
+ DOM_SID *members;
+
+ DEBUG(5,("_samr_GetAliasMembership: %d\n", __LINE__));
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, r->in.domain_handle, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ ntstatus1 = access_check_samr_function(info->acc_granted,
+ SA_RIGHT_DOMAIN_LOOKUP_ALIAS_BY_MEM,
+ "_samr_GetAliasMembership");
+ ntstatus2 = access_check_samr_function(info->acc_granted,
+ SA_RIGHT_DOMAIN_OPEN_ACCOUNT,
+ "_samr_GetAliasMembership");
+
+ if (!NT_STATUS_IS_OK(ntstatus1) || !NT_STATUS_IS_OK(ntstatus2)) {
+ if (!(NT_STATUS_EQUAL(ntstatus1,NT_STATUS_ACCESS_DENIED) && NT_STATUS_IS_OK(ntstatus2)) &&
+ !(NT_STATUS_EQUAL(ntstatus1,NT_STATUS_ACCESS_DENIED) && NT_STATUS_IS_OK(ntstatus1))) {
+ return (NT_STATUS_IS_OK(ntstatus1)) ? ntstatus2 : ntstatus1;
+ }
+ }
+
+ if (!sid_check_is_domain(&info->sid) &&
+ !sid_check_is_builtin(&info->sid))
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+
+ if (r->in.sids->num_sids) {
+ members = TALLOC_ARRAY(p->mem_ctx, DOM_SID, r->in.sids->num_sids);
+
+ if (members == NULL)
+ return NT_STATUS_NO_MEMORY;
+ } else {
+ members = NULL;
+ }
+
+ for (i=0; i<r->in.sids->num_sids; i++)
+ sid_copy(&members[i], r->in.sids->sids[i].sid);
+
+ alias_rids = NULL;
+ num_alias_rids = 0;
+
+ become_root();
+ ntstatus1 = pdb_enum_alias_memberships(p->mem_ctx, &info->sid, members,
+ r->in.sids->num_sids,
+ &alias_rids, &num_alias_rids);
+ unbecome_root();
+
+ if (!NT_STATUS_IS_OK(ntstatus1)) {
+ return ntstatus1;
+ }
+
+ r->out.rids->count = num_alias_rids;
+ r->out.rids->ids = alias_rids;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_GetMembersInAlias
+*********************************************************************/
+
+NTSTATUS _samr_GetMembersInAlias(pipes_struct *p,
+ struct samr_GetMembersInAlias *r)
+{
+ NTSTATUS status;
+ size_t i;
+ size_t num_sids = 0;
+ struct lsa_SidPtr *sids = NULL;
+ DOM_SID *pdb_sids = NULL;
+
+ DOM_SID alias_sid;
+
+ uint32 acc_granted;
+
+ /* find the policy handle. open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, r->in.alias_handle, &alias_sid, &acc_granted, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(acc_granted,
+ SA_RIGHT_ALIAS_GET_MEMBERS,
+ "_samr_GetMembersInAlias");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(10, ("sid is %s\n", sid_string_dbg(&alias_sid)));
+
+ become_root();
+ status = pdb_enum_aliasmem(&alias_sid, &pdb_sids, &num_sids);
+ unbecome_root();
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (num_sids) {
+ sids = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_SidPtr, num_sids);
+ if (sids == NULL) {
+ TALLOC_FREE(pdb_sids);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ for (i = 0; i < num_sids; i++) {
+ sids[i].sid = sid_dup_talloc(p->mem_ctx, &pdb_sids[i]);
+ if (!sids[i].sid) {
+ TALLOC_FREE(pdb_sids);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ r->out.sids->num_sids = num_sids;
+ r->out.sids->sids = sids;
+
+ TALLOC_FREE(pdb_sids);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_QueryGroupMember
+*********************************************************************/
+
+NTSTATUS _samr_QueryGroupMember(pipes_struct *p,
+ struct samr_QueryGroupMember *r)
+{
+ DOM_SID group_sid;
+ size_t i, num_members;
+
+ uint32 *rid=NULL;
+ uint32 *attr=NULL;
+
+ uint32 acc_granted;
+
+ NTSTATUS status;
+ struct samr_RidTypeArray *rids = NULL;
+
+ rids = TALLOC_ZERO_P(p->mem_ctx, struct samr_RidTypeArray);
+ if (!rids) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* find the policy handle. open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, r->in.group_handle, &group_sid, &acc_granted, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(acc_granted,
+ SA_RIGHT_GROUP_GET_MEMBERS,
+ "_samr_QueryGroupMember");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(10, ("sid is %s\n", sid_string_dbg(&group_sid)));
+
+ if (!sid_check_is_in_our_domain(&group_sid)) {
+ DEBUG(3, ("sid %s is not in our domain\n",
+ sid_string_dbg(&group_sid)));
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ DEBUG(10, ("lookup on Domain SID\n"));
+
+ become_root();
+ status = pdb_enum_group_members(p->mem_ctx, &group_sid,
+ &rid, &num_members);
+ unbecome_root();
+
+ if (!NT_STATUS_IS_OK(status))
+ return status;
+
+ if (num_members) {
+ attr=TALLOC_ZERO_ARRAY(p->mem_ctx, uint32, num_members);
+ if (attr == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ attr = NULL;
+ }
+
+ for (i=0; i<num_members; i++)
+ attr[i] = SID_NAME_USER;
+
+ rids->count = num_members;
+ rids->types = attr;
+ rids->rids = rid;
+
+ *r->out.rids = rids;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_AddAliasMember
+*********************************************************************/
+
+NTSTATUS _samr_AddAliasMember(pipes_struct *p,
+ struct samr_AddAliasMember *r)
+{
+ DOM_SID alias_sid;
+ uint32 acc_granted;
+ SE_PRIV se_rights;
+ bool can_add_accounts;
+ NTSTATUS status;
+ DISP_INFO *disp_info = NULL;
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, r->in.alias_handle, &alias_sid, &acc_granted, &disp_info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(acc_granted,
+ SA_RIGHT_ALIAS_ADD_MEMBER,
+ "_samr_AddAliasMember");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(10, ("sid is %s\n", sid_string_dbg(&alias_sid)));
+
+ se_priv_copy( &se_rights, &se_add_users );
+ can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights );
+
+ /******** BEGIN SeAddUsers BLOCK *********/
+
+ if ( can_add_accounts )
+ become_root();
+
+ status = pdb_add_aliasmem(&alias_sid, r->in.sid);
+
+ if ( can_add_accounts )
+ unbecome_root();
+
+ /******** END SeAddUsers BLOCK *********/
+
+ if (NT_STATUS_IS_OK(status)) {
+ force_flush_samr_cache(disp_info);
+ }
+
+ return status;
+}
+
+/*********************************************************************
+ _samr_DeleteAliasMember
+*********************************************************************/
+
+NTSTATUS _samr_DeleteAliasMember(pipes_struct *p,
+ struct samr_DeleteAliasMember *r)
+{
+ DOM_SID alias_sid;
+ uint32 acc_granted;
+ SE_PRIV se_rights;
+ bool can_add_accounts;
+ NTSTATUS status;
+ DISP_INFO *disp_info = NULL;
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, r->in.alias_handle, &alias_sid, &acc_granted, &disp_info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(acc_granted,
+ SA_RIGHT_ALIAS_REMOVE_MEMBER,
+ "_samr_DeleteAliasMember");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(10, ("_samr_del_aliasmem:sid is %s\n",
+ sid_string_dbg(&alias_sid)));
+
+ se_priv_copy( &se_rights, &se_add_users );
+ can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights );
+
+ /******** BEGIN SeAddUsers BLOCK *********/
+
+ if ( can_add_accounts )
+ become_root();
+
+ status = pdb_del_aliasmem(&alias_sid, r->in.sid);
+
+ if ( can_add_accounts )
+ unbecome_root();
+
+ /******** END SeAddUsers BLOCK *********/
+
+ if (NT_STATUS_IS_OK(status)) {
+ force_flush_samr_cache(disp_info);
+ }
+
+ return status;
+}
+
+/*********************************************************************
+ _samr_AddGroupMember
+*********************************************************************/
+
+NTSTATUS _samr_AddGroupMember(pipes_struct *p,
+ struct samr_AddGroupMember *r)
+{
+ NTSTATUS status;
+ DOM_SID group_sid;
+ uint32 group_rid;
+ uint32 acc_granted;
+ SE_PRIV se_rights;
+ bool can_add_accounts;
+ DISP_INFO *disp_info = NULL;
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, r->in.group_handle, &group_sid, &acc_granted, &disp_info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(acc_granted,
+ SA_RIGHT_GROUP_ADD_MEMBER,
+ "_samr_AddGroupMember");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(10, ("sid is %s\n", sid_string_dbg(&group_sid)));
+
+ if (!sid_peek_check_rid(get_global_sam_sid(), &group_sid,
+ &group_rid)) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ se_priv_copy( &se_rights, &se_add_users );
+ can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights );
+
+ /******** BEGIN SeAddUsers BLOCK *********/
+
+ if ( can_add_accounts )
+ become_root();
+
+ status = pdb_add_groupmem(p->mem_ctx, group_rid, r->in.rid);
+
+ if ( can_add_accounts )
+ unbecome_root();
+
+ /******** END SeAddUsers BLOCK *********/
+
+ force_flush_samr_cache(disp_info);
+
+ return status;
+}
+
+/*********************************************************************
+ _samr_DeleteGroupMember
+*********************************************************************/
+
+NTSTATUS _samr_DeleteGroupMember(pipes_struct *p,
+ struct samr_DeleteGroupMember *r)
+
+{
+ NTSTATUS status;
+ DOM_SID group_sid;
+ uint32 group_rid;
+ uint32 acc_granted;
+ SE_PRIV se_rights;
+ bool can_add_accounts;
+ DISP_INFO *disp_info = NULL;
+
+ /*
+ * delete the group member named r->in.rid
+ * who is a member of the sid associated with the handle
+ * the rid is a user's rid as the group is a domain group.
+ */
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, r->in.group_handle, &group_sid, &acc_granted, &disp_info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(acc_granted,
+ SA_RIGHT_GROUP_REMOVE_MEMBER,
+ "_samr_DeleteGroupMember");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (!sid_peek_check_rid(get_global_sam_sid(), &group_sid,
+ &group_rid)) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ se_priv_copy( &se_rights, &se_add_users );
+ can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights );
+
+ /******** BEGIN SeAddUsers BLOCK *********/
+
+ if ( can_add_accounts )
+ become_root();
+
+ status = pdb_del_groupmem(p->mem_ctx, group_rid, r->in.rid);
+
+ if ( can_add_accounts )
+ unbecome_root();
+
+ /******** END SeAddUsers BLOCK *********/
+
+ force_flush_samr_cache(disp_info);
+
+ return status;
+}
+
+/*********************************************************************
+ _samr_DeleteUser
+*********************************************************************/
+
+NTSTATUS _samr_DeleteUser(pipes_struct *p,
+ struct samr_DeleteUser *r)
+{
+ NTSTATUS status;
+ DOM_SID user_sid;
+ struct samu *sam_pass=NULL;
+ uint32 acc_granted;
+ bool can_add_accounts;
+ uint32 acb_info;
+ DISP_INFO *disp_info = NULL;
+ bool ret;
+
+ DEBUG(5, ("_samr_DeleteUser: %d\n", __LINE__));
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, r->in.user_handle, &user_sid, &acc_granted, &disp_info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(acc_granted,
+ STD_RIGHT_DELETE_ACCESS,
+ "_samr_DeleteUser");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (!sid_check_is_in_our_domain(&user_sid))
+ return NT_STATUS_CANNOT_DELETE;
+
+ /* check if the user exists before trying to delete */
+ if ( !(sam_pass = samu_new( NULL )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+ ret = pdb_getsampwsid(sam_pass, &user_sid);
+ unbecome_root();
+
+ if( !ret ) {
+ DEBUG(5,("_samr_DeleteUser: User %s doesn't exist.\n",
+ sid_string_dbg(&user_sid)));
+ TALLOC_FREE(sam_pass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ acb_info = pdb_get_acct_ctrl(sam_pass);
+
+ /* For machine accounts it's the SeMachineAccountPrivilege that counts. */
+ if ( acb_info & ACB_WSTRUST ) {
+ can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_machine_account );
+ } else {
+ can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_add_users );
+ }
+
+ /******** BEGIN SeAddUsers BLOCK *********/
+
+ if ( can_add_accounts )
+ become_root();
+
+ status = pdb_delete_user(p->mem_ctx, sam_pass);
+
+ if ( can_add_accounts )
+ unbecome_root();
+
+ /******** END SeAddUsers BLOCK *********/
+
+ if ( !NT_STATUS_IS_OK(status) ) {
+ DEBUG(5,("_samr_DeleteUser: Failed to delete entry for "
+ "user %s: %s.\n", pdb_get_username(sam_pass),
+ nt_errstr(status)));
+ TALLOC_FREE(sam_pass);
+ return status;
+ }
+
+
+ TALLOC_FREE(sam_pass);
+
+ if (!close_policy_hnd(p, r->in.user_handle))
+ return NT_STATUS_OBJECT_NAME_INVALID;
+
+ force_flush_samr_cache(disp_info);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_DeleteDomainGroup
+*********************************************************************/
+
+NTSTATUS _samr_DeleteDomainGroup(pipes_struct *p,
+ struct samr_DeleteDomainGroup *r)
+{
+ NTSTATUS status;
+ DOM_SID group_sid;
+ uint32 group_rid;
+ uint32 acc_granted;
+ SE_PRIV se_rights;
+ bool can_add_accounts;
+ DISP_INFO *disp_info = NULL;
+
+ DEBUG(5, ("samr_DeleteDomainGroup: %d\n", __LINE__));
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, r->in.group_handle, &group_sid, &acc_granted, &disp_info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(acc_granted,
+ STD_RIGHT_DELETE_ACCESS,
+ "_samr_DeleteDomainGroup");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(10, ("sid is %s\n", sid_string_dbg(&group_sid)));
+
+ if (!sid_peek_check_rid(get_global_sam_sid(), &group_sid,
+ &group_rid)) {
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ se_priv_copy( &se_rights, &se_add_users );
+ can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights );
+
+ /******** BEGIN SeAddUsers BLOCK *********/
+
+ if ( can_add_accounts )
+ become_root();
+
+ status = pdb_delete_dom_group(p->mem_ctx, group_rid);
+
+ if ( can_add_accounts )
+ unbecome_root();
+
+ /******** END SeAddUsers BLOCK *********/
+
+ if ( !NT_STATUS_IS_OK(status) ) {
+ DEBUG(5,("_samr_DeleteDomainGroup: Failed to delete mapping "
+ "entry for group %s: %s\n",
+ sid_string_dbg(&group_sid),
+ nt_errstr(status)));
+ return status;
+ }
+
+ if (!close_policy_hnd(p, r->in.group_handle))
+ return NT_STATUS_OBJECT_NAME_INVALID;
+
+ force_flush_samr_cache(disp_info);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_DeleteDomAlias
+*********************************************************************/
+
+NTSTATUS _samr_DeleteDomAlias(pipes_struct *p,
+ struct samr_DeleteDomAlias *r)
+{
+ DOM_SID alias_sid;
+ uint32 acc_granted;
+ SE_PRIV se_rights;
+ bool can_add_accounts;
+ NTSTATUS status;
+ DISP_INFO *disp_info = NULL;
+
+ DEBUG(5, ("_samr_DeleteDomAlias: %d\n", __LINE__));
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, r->in.alias_handle, &alias_sid, &acc_granted, &disp_info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* copy the handle to the outgoing reply */
+
+ memcpy(r->out.alias_handle, r->in.alias_handle, sizeof(r->out.alias_handle));
+
+ status = access_check_samr_function(acc_granted,
+ STD_RIGHT_DELETE_ACCESS,
+ "_samr_DeleteDomAlias");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(10, ("sid is %s\n", sid_string_dbg(&alias_sid)));
+
+ /* Don't let Windows delete builtin groups */
+
+ if ( sid_check_is_in_builtin( &alias_sid ) ) {
+ return NT_STATUS_SPECIAL_ACCOUNT;
+ }
+
+ if (!sid_check_is_in_our_domain(&alias_sid))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ DEBUG(10, ("lookup on Local SID\n"));
+
+ se_priv_copy( &se_rights, &se_add_users );
+ can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights );
+
+ /******** BEGIN SeAddUsers BLOCK *********/
+
+ if ( can_add_accounts )
+ become_root();
+
+ /* Have passdb delete the alias */
+ status = pdb_delete_alias(&alias_sid);
+
+ if ( can_add_accounts )
+ unbecome_root();
+
+ /******** END SeAddUsers BLOCK *********/
+
+ if ( !NT_STATUS_IS_OK(status))
+ return status;
+
+ if (!close_policy_hnd(p, r->in.alias_handle))
+ return NT_STATUS_OBJECT_NAME_INVALID;
+
+ force_flush_samr_cache(disp_info);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_CreateDomainGroup
+*********************************************************************/
+
+NTSTATUS _samr_CreateDomainGroup(pipes_struct *p,
+ struct samr_CreateDomainGroup *r)
+
+{
+ NTSTATUS status;
+ DOM_SID dom_sid;
+ DOM_SID info_sid;
+ const char *name;
+ struct samr_info *info;
+ uint32 acc_granted;
+ SE_PRIV se_rights;
+ bool can_add_accounts;
+ DISP_INFO *disp_info = NULL;
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, r->in.domain_handle, &dom_sid, &acc_granted, &disp_info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(acc_granted,
+ SA_RIGHT_DOMAIN_CREATE_GROUP,
+ "_samr_CreateDomainGroup");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (!sid_equal(&dom_sid, get_global_sam_sid()))
+ return NT_STATUS_ACCESS_DENIED;
+
+ name = r->in.name->string;
+ if (name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = can_create(p->mem_ctx, name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ se_priv_copy( &se_rights, &se_add_users );
+ can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights );
+
+ /******** BEGIN SeAddUsers BLOCK *********/
+
+ if ( can_add_accounts )
+ become_root();
+
+ /* check that we successfully create the UNIX group */
+
+ status = pdb_create_dom_group(p->mem_ctx, name, r->out.rid);
+
+ if ( can_add_accounts )
+ unbecome_root();
+
+ /******** END SeAddUsers BLOCK *********/
+
+ /* check if we should bail out here */
+
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+ sid_compose(&info_sid, get_global_sam_sid(), *r->out.rid);
+
+ if ((info = get_samr_info_by_sid(&info_sid)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ /* they created it; let the user do what he wants with it */
+
+ info->acc_granted = GENERIC_RIGHTS_GROUP_ALL_ACCESS;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, r->out.group_handle, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ force_flush_samr_cache(disp_info);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_CreateDomAlias
+*********************************************************************/
+
+NTSTATUS _samr_CreateDomAlias(pipes_struct *p,
+ struct samr_CreateDomAlias *r)
+{
+ DOM_SID dom_sid;
+ DOM_SID info_sid;
+ const char *name = NULL;
+ struct samr_info *info;
+ uint32 acc_granted;
+ gid_t gid;
+ NTSTATUS result;
+ SE_PRIV se_rights;
+ bool can_add_accounts;
+ DISP_INFO *disp_info = NULL;
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, r->in.domain_handle, &dom_sid, &acc_granted, &disp_info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ result = access_check_samr_function(acc_granted,
+ SA_RIGHT_DOMAIN_CREATE_ALIAS,
+ "_samr_CreateDomAlias");
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ if (!sid_equal(&dom_sid, get_global_sam_sid()))
+ return NT_STATUS_ACCESS_DENIED;
+
+ name = r->in.alias_name->string;
+
+ se_priv_copy( &se_rights, &se_add_users );
+ can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights );
+
+ result = can_create(p->mem_ctx, name);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ /******** BEGIN SeAddUsers BLOCK *********/
+
+ if ( can_add_accounts )
+ become_root();
+
+ /* Have passdb create the alias */
+ result = pdb_create_alias(name, r->out.rid);
+
+ if ( can_add_accounts )
+ unbecome_root();
+
+ /******** END SeAddUsers BLOCK *********/
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10, ("pdb_create_alias failed: %s\n",
+ nt_errstr(result)));
+ return result;
+ }
+
+ sid_copy(&info_sid, get_global_sam_sid());
+ sid_append_rid(&info_sid, *r->out.rid);
+
+ if (!sid_to_gid(&info_sid, &gid)) {
+ DEBUG(10, ("Could not find alias just created\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* check if the group has been successfully created */
+ if ( getgrgid(gid) == NULL ) {
+ DEBUG(10, ("getgrgid(%d) of just created alias failed\n",
+ gid));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if ((info = get_samr_info_by_sid(&info_sid)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ /* they created it; let the user do what he wants with it */
+
+ info->acc_granted = GENERIC_RIGHTS_ALIAS_ALL_ACCESS;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, r->out.alias_handle, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ force_flush_samr_cache(disp_info);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_QueryGroupInfo
+*********************************************************************/
+
+NTSTATUS _samr_QueryGroupInfo(pipes_struct *p,
+ struct samr_QueryGroupInfo *r)
+{
+ NTSTATUS status;
+ DOM_SID group_sid;
+ GROUP_MAP map;
+ union samr_GroupInfo *info = NULL;
+ uint32 acc_granted;
+ bool ret;
+ uint32_t attributes = SE_GROUP_MANDATORY |
+ SE_GROUP_ENABLED_BY_DEFAULT |
+ SE_GROUP_ENABLED;
+ const char *group_name = NULL;
+ const char *group_description = NULL;
+
+ if (!get_lsa_policy_samr_sid(p, r->in.group_handle, &group_sid, &acc_granted, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(acc_granted,
+ SA_RIGHT_GROUP_LOOKUP_INFO,
+ "_samr_QueryGroupInfo");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ become_root();
+ ret = get_domain_group_from_sid(group_sid, &map);
+ unbecome_root();
+ if (!ret)
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* FIXME: map contains fstrings */
+ group_name = talloc_strdup(r, map.nt_name);
+ group_description = talloc_strdup(r, map.comment);
+
+ info = TALLOC_ZERO_P(p->mem_ctx, union samr_GroupInfo);
+ if (!info) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ switch (r->in.level) {
+ case 1: {
+ uint32 *members;
+ size_t num_members;
+
+ become_root();
+ status = pdb_enum_group_members(
+ p->mem_ctx, &group_sid, &members, &num_members);
+ unbecome_root();
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ init_samr_group_info1(&info->all,
+ group_name,
+ attributes,
+ num_members,
+ group_description);
+ break;
+ }
+ case 2:
+ init_samr_group_info2(&info->name,
+ group_name);
+ break;
+ case 3:
+ init_samr_group_info3(&info->attributes,
+ attributes);
+ break;
+ case 4:
+ init_samr_group_info4(&info->description,
+ group_description);
+ break;
+ case 5: {
+ /*
+ uint32 *members;
+ size_t num_members;
+ */
+
+ /*
+ become_root();
+ status = pdb_enum_group_members(
+ p->mem_ctx, &group_sid, &members, &num_members);
+ unbecome_root();
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ */
+ init_samr_group_info5(&info->all2,
+ group_name,
+ attributes,
+ 0, /* num_members - in w2k3 this is always 0 */
+ group_description);
+
+ break;
+ }
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ *r->out.info = info;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_SetGroupInfo
+*********************************************************************/
+
+NTSTATUS _samr_SetGroupInfo(pipes_struct *p,
+ struct samr_SetGroupInfo *r)
+{
+ DOM_SID group_sid;
+ GROUP_MAP map;
+ uint32 acc_granted;
+ NTSTATUS status;
+ bool ret;
+ bool can_mod_accounts;
+ DISP_INFO *disp_info = NULL;
+
+ if (!get_lsa_policy_samr_sid(p, r->in.group_handle, &group_sid, &acc_granted, &disp_info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(acc_granted,
+ SA_RIGHT_GROUP_SET_INFO,
+ "_samr_SetGroupInfo");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ become_root();
+ ret = get_domain_group_from_sid(group_sid, &map);
+ unbecome_root();
+ if (!ret)
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ switch (r->in.level) {
+ case 1:
+ fstrcpy(map.comment, r->in.info->all.description.string);
+ break;
+ case 4:
+ fstrcpy(map.comment, r->in.info->description.string);
+ break;
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ can_mod_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_add_users );
+
+ /******** BEGIN SeAddUsers BLOCK *********/
+
+ if ( can_mod_accounts )
+ become_root();
+
+ status = pdb_update_group_mapping_entry(&map);
+
+ if ( can_mod_accounts )
+ unbecome_root();
+
+ /******** End SeAddUsers BLOCK *********/
+
+ if (NT_STATUS_IS_OK(status)) {
+ force_flush_samr_cache(disp_info);
+ }
+
+ return status;
+}
+
+/*********************************************************************
+ _samr_SetAliasInfo
+*********************************************************************/
+
+NTSTATUS _samr_SetAliasInfo(pipes_struct *p,
+ struct samr_SetAliasInfo *r)
+{
+ DOM_SID group_sid;
+ struct acct_info info;
+ uint32 acc_granted;
+ bool can_mod_accounts;
+ NTSTATUS status;
+ DISP_INFO *disp_info = NULL;
+
+ if (!get_lsa_policy_samr_sid(p, r->in.alias_handle, &group_sid, &acc_granted, &disp_info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(acc_granted,
+ SA_RIGHT_ALIAS_SET_INFO,
+ "_samr_SetAliasInfo");
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* get the current group information */
+
+ become_root();
+ status = pdb_get_aliasinfo( &group_sid, &info );
+ unbecome_root();
+
+ if ( !NT_STATUS_IS_OK(status))
+ return status;
+
+ switch (r->in.level) {
+ case ALIASINFONAME:
+ {
+ fstring group_name;
+
+ /* We currently do not support renaming groups in the
+ the BUILTIN domain. Refer to util_builtin.c to understand
+ why. The eventually needs to be fixed to be like Windows
+ where you can rename builtin groups, just not delete them */
+
+ if ( sid_check_is_in_builtin( &group_sid ) ) {
+ return NT_STATUS_SPECIAL_ACCOUNT;
+ }
+
+ /* There has to be a valid name (and it has to be different) */
+
+ if ( !r->in.info->name.string )
+ return NT_STATUS_INVALID_PARAMETER;
+
+ /* If the name is the same just reply "ok". Yes this
+ doesn't allow you to change the case of a group name. */
+
+ if ( strequal( r->in.info->name.string, info.acct_name ) )
+ return NT_STATUS_OK;
+
+ fstrcpy( info.acct_name, r->in.info->name.string);
+
+ /* make sure the name doesn't already exist as a user
+ or local group */
+
+ fstr_sprintf( group_name, "%s\\%s", global_myname(), info.acct_name );
+ status = can_create( p->mem_ctx, group_name );
+ if ( !NT_STATUS_IS_OK( status ) )
+ return status;
+ break;
+ }
+ case ALIASINFODESCRIPTION:
+ if (r->in.info->description.string) {
+ fstrcpy(info.acct_desc,
+ r->in.info->description.string);
+ } else {
+ fstrcpy( info.acct_desc, "" );
+ }
+ break;
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ can_mod_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_add_users );
+
+ /******** BEGIN SeAddUsers BLOCK *********/
+
+ if ( can_mod_accounts )
+ become_root();
+
+ status = pdb_set_aliasinfo( &group_sid, &info );
+
+ if ( can_mod_accounts )
+ unbecome_root();
+
+ /******** End SeAddUsers BLOCK *********/
+
+ if (NT_STATUS_IS_OK(status))
+ force_flush_samr_cache(disp_info);
+
+ return status;
+}
+
+/****************************************************************
+ _samr_GetDomPwInfo
+****************************************************************/
+
+NTSTATUS _samr_GetDomPwInfo(pipes_struct *p,
+ struct samr_GetDomPwInfo *r)
+{
+ uint32_t min_password_length = 0;
+ uint32_t password_properties = 0;
+
+ /* Perform access check. Since this rpc does not require a
+ policy handle it will not be caught by the access checks on
+ SAMR_CONNECT or SAMR_CONNECT_ANON. */
+
+ if (!pipe_access_check(p)) {
+ DEBUG(3, ("access denied to _samr_GetDomPwInfo\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ become_root();
+ pdb_get_account_policy(AP_MIN_PASSWORD_LEN,
+ &min_password_length);
+ pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS,
+ &password_properties);
+ unbecome_root();
+
+ if (lp_check_password_script() && *lp_check_password_script()) {
+ password_properties |= DOMAIN_PASSWORD_COMPLEX;
+ }
+
+ r->out.info->min_password_length = min_password_length;
+ r->out.info->password_properties = password_properties;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_OpenGroup
+*********************************************************************/
+
+NTSTATUS _samr_OpenGroup(pipes_struct *p,
+ struct samr_OpenGroup *r)
+
+{
+ DOM_SID sid;
+ DOM_SID info_sid;
+ GROUP_MAP map;
+ struct samr_info *info;
+ SEC_DESC *psd = NULL;
+ uint32 acc_granted;
+ uint32 des_access = r->in.access_mask;
+ size_t sd_size;
+ NTSTATUS status;
+ fstring sid_string;
+ bool ret;
+ SE_PRIV se_rights;
+
+ if (!get_lsa_policy_samr_sid(p, r->in.domain_handle, &sid, &acc_granted, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ status = access_check_samr_function(acc_granted,
+ SA_RIGHT_DOMAIN_OPEN_ACCOUNT,
+ "_samr_OpenGroup");
+
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+ /*check if access can be granted as requested by client. */
+ make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &grp_generic_mapping, NULL, 0);
+ se_map_generic(&des_access,&grp_generic_mapping);
+
+ se_priv_copy( &se_rights, &se_add_users );
+
+ status = access_check_samr_object(psd, p->pipe_user.nt_user_token,
+ &se_rights, GENERIC_RIGHTS_GROUP_WRITE, des_access,
+ &acc_granted, "_samr_OpenGroup");
+
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+ /* this should not be hard-coded like this */
+
+ if (!sid_equal(&sid, get_global_sam_sid()))
+ return NT_STATUS_ACCESS_DENIED;
+
+ sid_copy(&info_sid, get_global_sam_sid());
+ sid_append_rid(&info_sid, r->in.rid);
+ sid_to_fstring(sid_string, &info_sid);
+
+ if ((info = get_samr_info_by_sid(&info_sid)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ info->acc_granted = acc_granted;
+
+ DEBUG(10, ("_samr_OpenGroup:Opening SID: %s\n", sid_string));
+
+ /* check if that group really exists */
+ become_root();
+ ret = get_domain_group_from_sid(info->sid, &map);
+ unbecome_root();
+ if (!ret)
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, r->out.group_handle, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_RemoveMemberFromForeignDomain
+*********************************************************************/
+
+NTSTATUS _samr_RemoveMemberFromForeignDomain(pipes_struct *p,
+ struct samr_RemoveMemberFromForeignDomain *r)
+{
+ DOM_SID delete_sid, domain_sid;
+ uint32 acc_granted;
+ NTSTATUS result;
+ DISP_INFO *disp_info = NULL;
+
+ sid_copy( &delete_sid, r->in.sid );
+
+ DEBUG(5,("_samr_RemoveMemberFromForeignDomain: removing SID [%s]\n",
+ sid_string_dbg(&delete_sid)));
+
+ /* Find the policy handle. Open a policy on it. */
+
+ if (!get_lsa_policy_samr_sid(p, r->in.domain_handle, &domain_sid,
+ &acc_granted, &disp_info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ result = access_check_samr_function(acc_granted,
+ STD_RIGHT_DELETE_ACCESS,
+ "_samr_RemoveMemberFromForeignDomain");
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ DEBUG(8, ("_samr_RemoveMemberFromForeignDomain: sid is %s\n",
+ sid_string_dbg(&domain_sid)));
+
+ /* we can only delete a user from a group since we don't have
+ nested groups anyways. So in the latter case, just say OK */
+
+ /* TODO: The above comment nowadays is bogus. Since we have nested
+ * groups now, and aliases members are never reported out of the unix
+ * group membership, the "just say OK" makes this call a no-op. For
+ * us. This needs fixing however. */
+
+ /* I've only ever seen this in the wild when deleting a user from
+ * usrmgr.exe. domain_sid is the builtin domain, and the sid to delete
+ * is the user about to be deleted. I very much suspect this is the
+ * only application of this call. To verify this, let people report
+ * other cases. */
+
+ if (!sid_check_is_builtin(&domain_sid)) {
+ DEBUG(1,("_samr_RemoveMemberFromForeignDomain: domain_sid = %s, "
+ "global_sam_sid() = %s\n",
+ sid_string_dbg(&domain_sid),
+ sid_string_dbg(get_global_sam_sid())));
+ DEBUGADD(1,("please report to samba-technical@samba.org!\n"));
+ return NT_STATUS_OK;
+ }
+
+ force_flush_samr_cache(disp_info);
+
+ result = NT_STATUS_OK;
+
+ return result;
+}
+
+/*******************************************************************
+ _samr_QueryDomainInfo2
+ ********************************************************************/
+
+NTSTATUS _samr_QueryDomainInfo2(pipes_struct *p,
+ struct samr_QueryDomainInfo2 *r)
+{
+ return samr_QueryDomainInfo_internal("_samr_QueryDomainInfo2",
+ p,
+ r->in.domain_handle,
+ r->in.level,
+ r->out.info);
+}
+
+/*******************************************************************
+ _samr_SetDomainInfo
+ ********************************************************************/
+
+NTSTATUS _samr_SetDomainInfo(pipes_struct *p,
+ struct samr_SetDomainInfo *r)
+{
+ time_t u_expire, u_min_age;
+ time_t u_logout;
+ time_t u_lock_duration, u_reset_time;
+
+ DEBUG(5,("_samr_SetDomainInfo: %d\n", __LINE__));
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, r->in.domain_handle, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ DEBUG(5,("_samr_SetDomainInfo: level: %d\n", r->in.level));
+
+ switch (r->in.level) {
+ case 0x01:
+ u_expire=nt_time_to_unix_abs((NTTIME *)&r->in.info->info1.max_password_age);
+ u_min_age=nt_time_to_unix_abs((NTTIME *)&r->in.info->info1.min_password_age);
+ pdb_set_account_policy(AP_MIN_PASSWORD_LEN, (uint32)r->in.info->info1.min_password_length);
+ pdb_set_account_policy(AP_PASSWORD_HISTORY, (uint32)r->in.info->info1.password_history_length);
+ pdb_set_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, (uint32)r->in.info->info1.password_properties);
+ pdb_set_account_policy(AP_MAX_PASSWORD_AGE, (int)u_expire);
+ pdb_set_account_policy(AP_MIN_PASSWORD_AGE, (int)u_min_age);
+ break;
+ case 0x02:
+ break;
+ case 0x03:
+ u_logout=nt_time_to_unix_abs((NTTIME *)&r->in.info->info3.force_logoff_time);
+ pdb_set_account_policy(AP_TIME_TO_LOGOUT, (int)u_logout);
+ break;
+ case 0x05:
+ break;
+ case 0x06:
+ break;
+ case 0x07:
+ break;
+ case 0x0c:
+ u_lock_duration=nt_time_to_unix_abs((NTTIME *)&r->in.info->info12.lockout_duration);
+ if (u_lock_duration != -1)
+ u_lock_duration /= 60;
+
+ u_reset_time=nt_time_to_unix_abs((NTTIME *)&r->in.info->info12.lockout_window)/60;
+
+ pdb_set_account_policy(AP_LOCK_ACCOUNT_DURATION, (int)u_lock_duration);
+ pdb_set_account_policy(AP_RESET_COUNT_TIME, (int)u_reset_time);
+ pdb_set_account_policy(AP_BAD_ATTEMPT_LOCKOUT, (uint32)r->in.info->info12.lockout_threshold);
+ break;
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ DEBUG(5,("_samr_SetDomainInfo: %d\n", __LINE__));
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+ _samr_GetDisplayEnumerationIndex
+****************************************************************/
+
+NTSTATUS _samr_GetDisplayEnumerationIndex(pipes_struct *p,
+ struct samr_GetDisplayEnumerationIndex *r)
+{
+ struct samr_info *info = NULL;
+ uint32_t max_entries = (uint32_t) -1;
+ uint32_t enum_context = 0;
+ int i;
+ uint32_t num_account = 0;
+ struct samr_displayentry *entries = NULL;
+
+ DEBUG(5,("_samr_GetDisplayEnumerationIndex: %d\n", __LINE__));
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, r->in.domain_handle, (void **)(void *)&info)) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ if ((r->in.level < 1) || (r->in.level > 3)) {
+ DEBUG(0,("_samr_GetDisplayEnumerationIndex: "
+ "Unknown info level (%u)\n",
+ r->in.level));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ become_root();
+
+ /* The following done as ROOT. Don't return without unbecome_root(). */
+
+ switch (r->in.level) {
+ case 1:
+ if (info->disp_info->users == NULL) {
+ info->disp_info->users = pdb_search_users(ACB_NORMAL);
+ if (info->disp_info->users == NULL) {
+ unbecome_root();
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ DEBUG(10,("_samr_GetDisplayEnumerationIndex: "
+ "starting user enumeration at index %u\n",
+ (unsigned int)enum_context));
+ } else {
+ DEBUG(10,("_samr_GetDisplayEnumerationIndex: "
+ "using cached user enumeration at index %u\n",
+ (unsigned int)enum_context));
+ }
+ num_account = pdb_search_entries(info->disp_info->users,
+ enum_context, max_entries,
+ &entries);
+ break;
+ case 2:
+ if (info->disp_info->machines == NULL) {
+ info->disp_info->machines =
+ pdb_search_users(ACB_WSTRUST|ACB_SVRTRUST);
+ if (info->disp_info->machines == NULL) {
+ unbecome_root();
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ DEBUG(10,("_samr_GetDisplayEnumerationIndex: "
+ "starting machine enumeration at index %u\n",
+ (unsigned int)enum_context));
+ } else {
+ DEBUG(10,("_samr_GetDisplayEnumerationIndex: "
+ "using cached machine enumeration at index %u\n",
+ (unsigned int)enum_context));
+ }
+ num_account = pdb_search_entries(info->disp_info->machines,
+ enum_context, max_entries,
+ &entries);
+ break;
+ case 3:
+ if (info->disp_info->groups == NULL) {
+ info->disp_info->groups = pdb_search_groups();
+ if (info->disp_info->groups == NULL) {
+ unbecome_root();
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ DEBUG(10,("_samr_GetDisplayEnumerationIndex: "
+ "starting group enumeration at index %u\n",
+ (unsigned int)enum_context));
+ } else {
+ DEBUG(10,("_samr_GetDisplayEnumerationIndex: "
+ "using cached group enumeration at index %u\n",
+ (unsigned int)enum_context));
+ }
+ num_account = pdb_search_entries(info->disp_info->groups,
+ enum_context, max_entries,
+ &entries);
+ break;
+ default:
+ unbecome_root();
+ smb_panic("info class changed");
+ break;
+ }
+
+ unbecome_root();
+
+ /* Ensure we cache this enumeration. */
+ set_disp_info_cache_timeout(info->disp_info, DISP_INFO_CACHE_TIMEOUT);
+
+ DEBUG(10,("_samr_GetDisplayEnumerationIndex: looking for :%s\n",
+ r->in.name->string));
+
+ for (i=0; i<num_account; i++) {
+ if (strequal(entries[i].account_name, r->in.name->string)) {
+ DEBUG(10,("_samr_GetDisplayEnumerationIndex: "
+ "found %s at idx %d\n",
+ r->in.name->string, i));
+ *r->out.idx = i;
+ return NT_STATUS_OK;
+ }
+ }
+
+ /* assuming account_name lives at the very end */
+ *r->out.idx = num_account;
+
+ return NT_STATUS_NO_MORE_ENTRIES;
+}
+
+/****************************************************************
+ _samr_GetDisplayEnumerationIndex2
+****************************************************************/
+
+NTSTATUS _samr_GetDisplayEnumerationIndex2(pipes_struct *p,
+ struct samr_GetDisplayEnumerationIndex2 *r)
+{
+ struct samr_GetDisplayEnumerationIndex q;
+
+ q.in.domain_handle = r->in.domain_handle;
+ q.in.level = r->in.level;
+ q.in.name = r->in.name;
+
+ q.out.idx = r->out.idx;
+
+ return _samr_GetDisplayEnumerationIndex(p, &q);
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _samr_Shutdown(pipes_struct *p,
+ struct samr_Shutdown *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _samr_CreateUser(pipes_struct *p,
+ struct samr_CreateUser *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _samr_SetMemberAttributesOfGroup(pipes_struct *p,
+ struct samr_SetMemberAttributesOfGroup *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _samr_ChangePasswordUser(pipes_struct *p,
+ struct samr_ChangePasswordUser *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _samr_TestPrivateFunctionsDomain(pipes_struct *p,
+ struct samr_TestPrivateFunctionsDomain *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _samr_TestPrivateFunctionsUser(pipes_struct *p,
+ struct samr_TestPrivateFunctionsUser *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _samr_QueryUserInfo2(pipes_struct *p,
+ struct samr_QueryUserInfo2 *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _samr_AddMultipleMembersToAlias(pipes_struct *p,
+ struct samr_AddMultipleMembersToAlias *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _samr_RemoveMultipleMembersFromAlias(pipes_struct *p,
+ struct samr_RemoveMultipleMembersFromAlias *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _samr_OemChangePasswordUser2(pipes_struct *p,
+ struct samr_OemChangePasswordUser2 *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _samr_SetBootKeyInformation(pipes_struct *p,
+ struct samr_SetBootKeyInformation *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _samr_GetBootKeyInformation(pipes_struct *p,
+ struct samr_GetBootKeyInformation *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _samr_Connect3(pipes_struct *p,
+ struct samr_Connect3 *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _samr_RidToSid(pipes_struct *p,
+ struct samr_RidToSid *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _samr_SetDsrmPassword(pipes_struct *p,
+ struct samr_SetDsrmPassword *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS _samr_ValidatePassword(pipes_struct *p,
+ struct samr_ValidatePassword *r)
+{
+ p->rng_fault_state = true;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
diff --git a/source3/rpc_server/srv_samr_util.c b/source3/rpc_server/srv_samr_util.c
new file mode 100644
index 0000000000..ef588aed1a
--- /dev/null
+++ b/source3/rpc_server/srv_samr_util.c
@@ -0,0 +1,382 @@
+/*
+ Unix SMB/CIFS implementation.
+ SAMR Pipe utility functions.
+
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Gerald (Jerry) Carter 2000-2001
+ Copyright (C) Andrew Bartlett 2001-2002
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Guenther Deschner 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+#define STRING_CHANGED (old_string && !new_string) ||\
+ (!old_string && new_string) ||\
+ (old_string && new_string && (strcmp(old_string, new_string) != 0))
+
+#define STRING_CHANGED_NC(s1,s2) ((s1) && !(s2)) ||\
+ (!(s1) && (s2)) ||\
+ ((s1) && (s2) && (strcmp((s1), (s2)) != 0))
+
+/*************************************************************
+ Copies a struct samr_UserInfo20 to a struct samu
+**************************************************************/
+
+void copy_id20_to_sam_passwd(struct samu *to,
+ struct samr_UserInfo20 *from)
+{
+ const char *old_string;
+ char *new_string;
+ DATA_BLOB mung;
+
+ if (from == NULL || to == NULL) {
+ return;
+ }
+
+ if (from->parameters.array) {
+ old_string = pdb_get_munged_dial(to);
+ mung = data_blob_const(from->parameters.array,
+ from->parameters.length);
+ new_string = (mung.length == 0) ?
+ NULL : base64_encode_data_blob(talloc_tos(), mung);
+ DEBUG(10,("INFO_20 PARAMETERS: %s -> %s\n",
+ old_string, new_string));
+ if (STRING_CHANGED_NC(old_string,new_string)) {
+ pdb_set_munged_dial(to, new_string, PDB_CHANGED);
+ }
+
+ TALLOC_FREE(new_string);
+ }
+}
+
+/*************************************************************
+ Copies a struct samr_UserInfo21 to a struct samu
+**************************************************************/
+
+void copy_id21_to_sam_passwd(const char *log_prefix,
+ struct samu *to,
+ struct samr_UserInfo21 *from)
+{
+ time_t unix_time, stored_time;
+ const char *old_string, *new_string;
+ const char *l;
+
+ if (from == NULL || to == NULL) {
+ return;
+ }
+
+ if (log_prefix) {
+ l = log_prefix;
+ } else {
+ l = "INFO_21";
+ }
+
+ if (from->fields_present & SAMR_FIELD_LAST_LOGON) {
+ unix_time = nt_time_to_unix(from->last_logon);
+ stored_time = pdb_get_logon_time(to);
+ DEBUG(10,("%s SAMR_FIELD_LAST_LOGON: %lu -> %lu\n", l,
+ (long unsigned int)stored_time,
+ (long unsigned int)unix_time));
+ if (stored_time != unix_time) {
+ pdb_set_logon_time(to, unix_time, PDB_CHANGED);
+ }
+ }
+
+ if (from->fields_present & SAMR_FIELD_LAST_LOGOFF) {
+ unix_time = nt_time_to_unix(from->last_logoff);
+ stored_time = pdb_get_logoff_time(to);
+ DEBUG(10,("%s SAMR_FIELD_LAST_LOGOFF: %lu -> %lu\n", l,
+ (long unsigned int)stored_time,
+ (long unsigned int)unix_time));
+ if (stored_time != unix_time) {
+ pdb_set_logoff_time(to, unix_time, PDB_CHANGED);
+ }
+ }
+
+ if (from->fields_present & SAMR_FIELD_ACCT_EXPIRY) {
+ unix_time = nt_time_to_unix(from->acct_expiry);
+ stored_time = pdb_get_kickoff_time(to);
+ DEBUG(10,("%s SAMR_FIELD_ACCT_EXPIRY: %lu -> %lu\n", l,
+ (long unsigned int)stored_time,
+ (long unsigned int)unix_time));
+ if (stored_time != unix_time) {
+ pdb_set_kickoff_time(to, unix_time , PDB_CHANGED);
+ }
+ }
+
+ if (from->fields_present & SAMR_FIELD_LAST_PWD_CHANGE) {
+ unix_time = nt_time_to_unix(from->last_password_change);
+ stored_time = pdb_get_pass_last_set_time(to);
+ DEBUG(10,("%s SAMR_FIELD_LAST_PWD_CHANGE: %lu -> %lu\n", l,
+ (long unsigned int)stored_time,
+ (long unsigned int)unix_time));
+ if (stored_time != unix_time) {
+ pdb_set_pass_last_set_time(to, unix_time, PDB_CHANGED);
+ }
+ }
+
+ if ((from->fields_present & SAMR_FIELD_ACCOUNT_NAME) &&
+ (from->account_name.string)) {
+ old_string = pdb_get_username(to);
+ new_string = from->account_name.string;
+ DEBUG(10,("%s SAMR_FIELD_ACCOUNT_NAME: %s -> %s\n", l,
+ old_string, new_string));
+ if (STRING_CHANGED) {
+ pdb_set_username(to, new_string, PDB_CHANGED);
+ }
+ }
+
+ if ((from->fields_present & SAMR_FIELD_FULL_NAME) &&
+ (from->full_name.string)) {
+ old_string = pdb_get_fullname(to);
+ new_string = from->full_name.string;
+ DEBUG(10,("%s SAMR_FIELD_FULL_NAME: %s -> %s\n", l,
+ old_string, new_string));
+ if (STRING_CHANGED) {
+ pdb_set_fullname(to, new_string, PDB_CHANGED);
+ }
+ }
+
+ if ((from->fields_present & SAMR_FIELD_HOME_DIRECTORY) &&
+ (from->home_directory.string)) {
+ old_string = pdb_get_homedir(to);
+ new_string = from->home_directory.string;
+ DEBUG(10,("%s SAMR_FIELD_HOME_DIRECTORY: %s -> %s\n", l,
+ old_string, new_string));
+ if (STRING_CHANGED) {
+ pdb_set_homedir(to, new_string, PDB_CHANGED);
+ }
+ }
+
+ if ((from->fields_present & SAMR_FIELD_HOME_DRIVE) &&
+ (from->home_drive.string)) {
+ old_string = pdb_get_dir_drive(to);
+ new_string = from->home_drive.string;
+ DEBUG(10,("%s SAMR_FIELD_HOME_DRIVE: %s -> %s\n", l,
+ old_string, new_string));
+ if (STRING_CHANGED) {
+ pdb_set_dir_drive(to, new_string, PDB_CHANGED);
+ }
+ }
+
+ if ((from->fields_present & SAMR_FIELD_LOGON_SCRIPT) &&
+ (from->logon_script.string)) {
+ old_string = pdb_get_logon_script(to);
+ new_string = from->logon_script.string;
+ DEBUG(10,("%s SAMR_FIELD_LOGON_SCRIPT: %s -> %s\n", l,
+ old_string, new_string));
+ if (STRING_CHANGED) {
+ pdb_set_logon_script(to , new_string, PDB_CHANGED);
+ }
+ }
+
+ if ((from->fields_present & SAMR_FIELD_PROFILE_PATH) &&
+ (from->profile_path.string)) {
+ old_string = pdb_get_profile_path(to);
+ new_string = from->profile_path.string;
+ DEBUG(10,("%s SAMR_FIELD_PROFILE_PATH: %s -> %s\n", l,
+ old_string, new_string));
+ if (STRING_CHANGED) {
+ pdb_set_profile_path(to , new_string, PDB_CHANGED);
+ }
+ }
+
+ if ((from->fields_present & SAMR_FIELD_DESCRIPTION) &&
+ (from->description.string)) {
+ old_string = pdb_get_acct_desc(to);
+ new_string = from->description.string;
+ DEBUG(10,("%s SAMR_FIELD_DESCRIPTION: %s -> %s\n", l,
+ old_string, new_string));
+ if (STRING_CHANGED) {
+ pdb_set_acct_desc(to, new_string, PDB_CHANGED);
+ }
+ }
+
+ if ((from->fields_present & SAMR_FIELD_WORKSTATIONS) &&
+ (from->workstations.string)) {
+ old_string = pdb_get_workstations(to);
+ new_string = from->workstations.string;
+ DEBUG(10,("%s SAMR_FIELD_WORKSTATIONS: %s -> %s\n", l,
+ old_string, new_string));
+ if (STRING_CHANGED) {
+ pdb_set_workstations(to , new_string, PDB_CHANGED);
+ }
+ }
+
+ if ((from->fields_present & SAMR_FIELD_COMMENT) &&
+ (from->comment.string)) {
+ old_string = pdb_get_comment(to);
+ new_string = from->comment.string;
+ DEBUG(10,("%s SAMR_FIELD_COMMENT: %s -> %s\n", l,
+ old_string, new_string));
+ if (STRING_CHANGED) {
+ pdb_set_comment(to, new_string, PDB_CHANGED);
+ }
+ }
+
+ if ((from->fields_present & SAMR_FIELD_PARAMETERS) &&
+ (from->parameters.array)) {
+ char *newstr;
+ DATA_BLOB mung;
+ old_string = pdb_get_munged_dial(to);
+
+ mung = data_blob_const(from->parameters.array,
+ from->parameters.length);
+ newstr = (mung.length == 0) ?
+ NULL : base64_encode_data_blob(talloc_tos(), mung);
+ DEBUG(10,("%s SAMR_FIELD_PARAMETERS: %s -> %s\n", l,
+ old_string, newstr));
+ if (STRING_CHANGED_NC(old_string,newstr)) {
+ pdb_set_munged_dial(to, newstr, PDB_CHANGED);
+ }
+
+ TALLOC_FREE(newstr);
+ }
+
+ if (from->fields_present & SAMR_FIELD_RID) {
+ if (from->rid == 0) {
+ DEBUG(10,("%s: Asked to set User RID to 0 !? Skipping change!\n", l));
+ } else if (from->rid != pdb_get_user_rid(to)) {
+ DEBUG(10,("%s SAMR_FIELD_RID: %u -> %u NOT UPDATED!\n", l,
+ pdb_get_user_rid(to), from->rid));
+ }
+ }
+
+ if (from->fields_present & SAMR_FIELD_PRIMARY_GID) {
+ if (from->primary_gid == 0) {
+ DEBUG(10,("%s: Asked to set Group RID to 0 !? Skipping change!\n", l));
+ } else if (from->primary_gid != pdb_get_group_rid(to)) {
+ DEBUG(10,("%s SAMR_FIELD_PRIMARY_GID: %u -> %u\n", l,
+ pdb_get_group_rid(to), from->primary_gid));
+ pdb_set_group_sid_from_rid(to,
+ from->primary_gid, PDB_CHANGED);
+ }
+ }
+
+ if (from->fields_present & SAMR_FIELD_ACCT_FLAGS) {
+ DEBUG(10,("%s SAMR_FIELD_ACCT_FLAGS: %08X -> %08X\n", l,
+ pdb_get_acct_ctrl(to), from->acct_flags));
+ if (from->acct_flags != pdb_get_acct_ctrl(to)) {
+ if (!(from->acct_flags & ACB_AUTOLOCK) &&
+ (pdb_get_acct_ctrl(to) & ACB_AUTOLOCK)) {
+ /* We're unlocking a previously locked user. Reset bad password counts.
+ Patch from Jianliang Lu. <Jianliang.Lu@getronics.com> */
+ pdb_set_bad_password_count(to, 0, PDB_CHANGED);
+ pdb_set_bad_password_time(to, 0, PDB_CHANGED);
+ }
+ pdb_set_acct_ctrl(to, from->acct_flags, PDB_CHANGED);
+ }
+ }
+
+ if (from->fields_present & SAMR_FIELD_LOGON_HOURS) {
+ char oldstr[44]; /* hours strings are 42 bytes. */
+ char newstr[44];
+ DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (units_per_week): %08X -> %08X\n", l,
+ pdb_get_logon_divs(to), from->logon_hours.units_per_week));
+ if (from->logon_hours.units_per_week != pdb_get_logon_divs(to)) {
+ pdb_set_logon_divs(to,
+ from->logon_hours.units_per_week, PDB_CHANGED);
+ }
+
+ DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (units_per_week/8): %08X -> %08X\n", l,
+ pdb_get_hours_len(to),
+ from->logon_hours.units_per_week/8));
+ if (from->logon_hours.units_per_week/8 != pdb_get_hours_len(to)) {
+ pdb_set_hours_len(to,
+ from->logon_hours.units_per_week/8, PDB_CHANGED);
+ }
+
+ DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (bits): %s -> %s\n", l,
+ pdb_get_hours(to), from->logon_hours.bits));
+ pdb_sethexhours(oldstr, pdb_get_hours(to));
+ pdb_sethexhours(newstr, from->logon_hours.bits);
+ if (!strequal(oldstr, newstr)) {
+ pdb_set_hours(to, from->logon_hours.bits, PDB_CHANGED);
+ }
+ }
+
+ if (from->fields_present & SAMR_FIELD_BAD_PWD_COUNT) {
+ DEBUG(10,("%s SAMR_FIELD_BAD_PWD_COUNT: %08X -> %08X\n", l,
+ pdb_get_bad_password_count(to), from->bad_password_count));
+ if (from->bad_password_count != pdb_get_bad_password_count(to)) {
+ pdb_set_bad_password_count(to,
+ from->bad_password_count, PDB_CHANGED);
+ }
+ }
+
+ if (from->fields_present & SAMR_FIELD_NUM_LOGONS) {
+ DEBUG(10,("%s SAMR_FIELD_NUM_LOGONS: %08X -> %08X\n", l,
+ pdb_get_logon_count(to), from->logon_count));
+ if (from->logon_count != pdb_get_logon_count(to)) {
+ pdb_set_logon_count(to, from->logon_count, PDB_CHANGED);
+ }
+ }
+
+ /* If the must change flag is set, the last set time goes to zero.
+ the must change and can change fields also do, but they are
+ calculated from policy, not set from the wire */
+
+ if (from->fields_present & SAMR_FIELD_EXPIRED_FLAG) {
+ DEBUG(10,("%s SAMR_FIELD_EXPIRED_FLAG: %02X\n", l,
+ from->password_expired));
+ if (from->password_expired == PASS_MUST_CHANGE_AT_NEXT_LOGON) {
+ pdb_set_pass_last_set_time(to, 0, PDB_CHANGED);
+ } else {
+ /* A subtlety here: some windows commands will
+ clear the expired flag even though it's not
+ set, and we don't want to reset the time
+ in these caess. "net user /dom <user> /active:y"
+ for example, to clear an autolocked acct.
+ We must check to see if it's expired first. jmcd */
+ stored_time = pdb_get_pass_last_set_time(to);
+ if (stored_time == 0)
+ pdb_set_pass_last_set_time(to, time(NULL),PDB_CHANGED);
+ }
+ }
+}
+
+
+/*************************************************************
+ Copies a struct samr_UserInfo23 to a struct samu
+**************************************************************/
+
+void copy_id23_to_sam_passwd(struct samu *to,
+ struct samr_UserInfo23 *from)
+{
+ if (from == NULL || to == NULL) {
+ return;
+ }
+
+ copy_id21_to_sam_passwd("INFO 23", to, &from->info);
+}
+
+/*************************************************************
+ Copies a struct samr_UserInfo25 to a struct samu
+**************************************************************/
+
+void copy_id25_to_sam_passwd(struct samu *to,
+ struct samr_UserInfo25 *from)
+{
+ if (from == NULL || to == NULL) {
+ return;
+ }
+
+ copy_id21_to_sam_passwd("INFO_25", to, &from->info);
+}
diff --git a/source3/rpc_server/srv_spoolss.c b/source3/rpc_server/srv_spoolss.c
new file mode 100644
index 0000000000..22b3a7607e
--- /dev/null
+++ b/source3/rpc_server/srv_spoolss.c
@@ -0,0 +1,1639 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ * Copyright (C) Jean François Micouleau 1998-2000,
+ * Copyright (C) Jeremy Allison 2001,
+ * Copyright (C) Gerald Carter 2001-2002,
+ * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+/********************************************************************
+ * api_spoolss_open_printer_ex (rarely seen - older call)
+ ********************************************************************/
+
+static bool api_spoolss_open_printer(pipes_struct *p)
+{
+ SPOOL_Q_OPEN_PRINTER q_u;
+ SPOOL_R_OPEN_PRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_open_printer("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_open_printer: unable to unmarshall SPOOL_Q_OPEN_PRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_open_printer( p, &q_u, &r_u);
+
+ if (!spoolss_io_r_open_printer("",&r_u,rdata,0)){
+ DEBUG(0,("spoolss_io_r_open_printer: unable to marshall SPOOL_R_OPEN_PRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/********************************************************************
+ * api_spoolss_open_printer_ex
+ ********************************************************************/
+
+static bool api_spoolss_open_printer_ex(pipes_struct *p)
+{
+ SPOOL_Q_OPEN_PRINTER_EX q_u;
+ SPOOL_R_OPEN_PRINTER_EX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_open_printer_ex("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_open_printer_ex: unable to unmarshall SPOOL_Q_OPEN_PRINTER_EX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_open_printer_ex( p, &q_u, &r_u);
+
+ if (!spoolss_io_r_open_printer_ex("",&r_u,rdata,0)){
+ DEBUG(0,("spoolss_io_r_open_printer_ex: unable to marshall SPOOL_R_OPEN_PRINTER_EX.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_getprinterdata
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+static bool api_spoolss_getprinterdata(pipes_struct *p)
+{
+ SPOOL_Q_GETPRINTERDATA q_u;
+ SPOOL_R_GETPRINTERDATA r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* read the stream and fill the struct */
+ if (!spoolss_io_q_getprinterdata("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_getprinterdata: unable to unmarshall SPOOL_Q_GETPRINTERDATA.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_getprinterdata( p, &q_u, &r_u);
+
+ if (!spoolss_io_r_getprinterdata("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_getprinterdata: unable to marshall SPOOL_R_GETPRINTERDATA.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_deleteprinterdata
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+static bool api_spoolss_deleteprinterdata(pipes_struct *p)
+{
+ SPOOL_Q_DELETEPRINTERDATA q_u;
+ SPOOL_R_DELETEPRINTERDATA r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* read the stream and fill the struct */
+ if (!spoolss_io_q_deleteprinterdata("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_deleteprinterdata: unable to unmarshall SPOOL_Q_DELETEPRINTERDATA.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_deleteprinterdata( p, &q_u, &r_u );
+
+ if (!spoolss_io_r_deleteprinterdata("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_deleteprinterdata: unable to marshall SPOOL_R_DELETEPRINTERDATA.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_closeprinter
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+static bool api_spoolss_closeprinter(pipes_struct *p)
+{
+ SPOOL_Q_CLOSEPRINTER q_u;
+ SPOOL_R_CLOSEPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_closeprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_closeprinter: unable to unmarshall SPOOL_Q_CLOSEPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_closeprinter(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_closeprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_closeprinter: unable to marshall SPOOL_R_CLOSEPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_abortprinter
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+static bool api_spoolss_abortprinter(pipes_struct *p)
+{
+ SPOOL_Q_ABORTPRINTER q_u;
+ SPOOL_R_ABORTPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_abortprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_abortprinter: unable to unmarshall SPOOL_Q_ABORTPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_abortprinter(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_abortprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_abortprinter: unable to marshall SPOOL_R_ABORTPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_deleteprinter
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+static bool api_spoolss_deleteprinter(pipes_struct *p)
+{
+ SPOOL_Q_DELETEPRINTER q_u;
+ SPOOL_R_DELETEPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_deleteprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_deleteprinter: unable to unmarshall SPOOL_Q_DELETEPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_deleteprinter(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_deleteprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_deleteprinter: unable to marshall SPOOL_R_DELETEPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/********************************************************************
+ * api_spoolss_deleteprinterdriver
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+static bool api_spoolss_deleteprinterdriver(pipes_struct *p)
+{
+ SPOOL_Q_DELETEPRINTERDRIVER q_u;
+ SPOOL_R_DELETEPRINTERDRIVER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_deleteprinterdriver("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_deleteprinterdriver: unable to unmarshall SPOOL_Q_DELETEPRINTERDRIVER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_deleteprinterdriver(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_deleteprinterdriver("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_deleteprinter: unable to marshall SPOOL_R_DELETEPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/********************************************************************
+ * api_spoolss_rffpcnex
+ * ReplyFindFirstPrinterChangeNotifyEx
+ ********************************************************************/
+
+static bool api_spoolss_rffpcnex(pipes_struct *p)
+{
+ SPOOL_Q_RFFPCNEX q_u;
+ SPOOL_R_RFFPCNEX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_rffpcnex("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_rffpcnex: unable to unmarshall SPOOL_Q_RFFPCNEX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_rffpcnex(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_rffpcnex("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_rffpcnex: unable to marshall SPOOL_R_RFFPCNEX.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/********************************************************************
+ * api_spoolss_rfnpcnex
+ * ReplyFindNextPrinterChangeNotifyEx
+ * called from the spoolss dispatcher
+
+ * Note - this is the *ONLY* function that breaks the RPC call
+ * symmetry in all the other calls. We need to do this to fix
+ * the massive memory allocation problem with thousands of jobs...
+ * JRA.
+ ********************************************************************/
+
+static bool api_spoolss_rfnpcnex(pipes_struct *p)
+{
+ SPOOL_Q_RFNPCNEX q_u;
+ SPOOL_R_RFNPCNEX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_rfnpcnex("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_rfnpcnex: unable to unmarshall SPOOL_Q_RFNPCNEX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_rfnpcnex(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_rfnpcnex("", &r_u, rdata, 0)) {
+ SAFE_FREE(r_u.info.data);
+ DEBUG(0,("spoolss_io_r_rfnpcnex: unable to marshall SPOOL_R_RFNPCNEX.\n"));
+ return False;
+ }
+
+ SAFE_FREE(r_u.info.data);
+
+ return True;
+}
+
+
+/********************************************************************
+ * api_spoolss_enumprinters
+ * called from the spoolss dispatcher
+ *
+ ********************************************************************/
+
+static bool api_spoolss_enumprinters(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPRINTERS q_u;
+ SPOOL_R_ENUMPRINTERS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_enumprinters("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumprinters: unable to unmarshall SPOOL_Q_ENUMPRINTERS.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumprinters( p, &q_u, &r_u);
+
+ if (!spoolss_io_r_enumprinters("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_enumprinters: unable to marshall SPOOL_R_ENUMPRINTERS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_getprinter
+ * called from the spoolss dispatcher
+ *
+ ********************************************************************/
+
+static bool api_spoolss_getprinter(pipes_struct *p)
+{
+ SPOOL_Q_GETPRINTER q_u;
+ SPOOL_R_GETPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_getprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_getprinter: unable to unmarshall SPOOL_Q_GETPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_getprinter(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_getprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_getprinter: unable to marshall SPOOL_R_GETPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_getprinter
+ * called from the spoolss dispatcher
+ *
+ ********************************************************************/
+
+static bool api_spoolss_getprinterdriver2(pipes_struct *p)
+{
+ SPOOL_Q_GETPRINTERDRIVER2 q_u;
+ SPOOL_R_GETPRINTERDRIVER2 r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_getprinterdriver2("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_getprinterdriver2: unable to unmarshall SPOOL_Q_GETPRINTERDRIVER2.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_getprinterdriver2(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_getprinterdriver2("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_getprinterdriver2: unable to marshall SPOOL_R_GETPRINTERDRIVER2.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_getprinter
+ * called from the spoolss dispatcher
+ *
+ ********************************************************************/
+
+static bool api_spoolss_startpageprinter(pipes_struct *p)
+{
+ SPOOL_Q_STARTPAGEPRINTER q_u;
+ SPOOL_R_STARTPAGEPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_startpageprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_startpageprinter: unable to unmarshall SPOOL_Q_STARTPAGEPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_startpageprinter(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_startpageprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_startpageprinter: unable to marshall SPOOL_R_STARTPAGEPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_getprinter
+ * called from the spoolss dispatcher
+ *
+ ********************************************************************/
+
+static bool api_spoolss_endpageprinter(pipes_struct *p)
+{
+ SPOOL_Q_ENDPAGEPRINTER q_u;
+ SPOOL_R_ENDPAGEPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_endpageprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_endpageprinter: unable to unmarshall SPOOL_Q_ENDPAGEPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_endpageprinter(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_endpageprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_endpageprinter: unable to marshall SPOOL_R_ENDPAGEPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+********************************************************************/
+
+static bool api_spoolss_startdocprinter(pipes_struct *p)
+{
+ SPOOL_Q_STARTDOCPRINTER q_u;
+ SPOOL_R_STARTDOCPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_startdocprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_startdocprinter: unable to unmarshall SPOOL_Q_STARTDOCPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_startdocprinter(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_startdocprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_startdocprinter: unable to marshall SPOOL_R_STARTDOCPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+********************************************************************/
+
+static bool api_spoolss_enddocprinter(pipes_struct *p)
+{
+ SPOOL_Q_ENDDOCPRINTER q_u;
+ SPOOL_R_ENDDOCPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_enddocprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enddocprinter: unable to unmarshall SPOOL_Q_ENDDOCPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enddocprinter(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_enddocprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_enddocprinter: unable to marshall SPOOL_R_ENDDOCPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+********************************************************************/
+
+static bool api_spoolss_writeprinter(pipes_struct *p)
+{
+ SPOOL_Q_WRITEPRINTER q_u;
+ SPOOL_R_WRITEPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_writeprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_writeprinter: unable to unmarshall SPOOL_Q_WRITEPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_writeprinter(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_writeprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_writeprinter: unable to marshall SPOOL_R_WRITEPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+
+****************************************************************************/
+
+static bool api_spoolss_setprinter(pipes_struct *p)
+{
+ SPOOL_Q_SETPRINTER q_u;
+ SPOOL_R_SETPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_setprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_setprinter: unable to unmarshall SPOOL_Q_SETPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_setprinter(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_setprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_setprinter: unable to marshall SPOOL_R_SETPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_fcpn(pipes_struct *p)
+{
+ SPOOL_Q_FCPN q_u;
+ SPOOL_R_FCPN r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_fcpn("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_fcpn: unable to unmarshall SPOOL_Q_FCPN.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_fcpn(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_fcpn("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_fcpn: unable to marshall SPOOL_R_FCPN.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_addjob(pipes_struct *p)
+{
+ SPOOL_Q_ADDJOB q_u;
+ SPOOL_R_ADDJOB r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_addjob("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_addjob: unable to unmarshall SPOOL_Q_ADDJOB.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_addjob(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_addjob("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_addjob: unable to marshall SPOOL_R_ADDJOB.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_enumjobs(pipes_struct *p)
+{
+ SPOOL_Q_ENUMJOBS q_u;
+ SPOOL_R_ENUMJOBS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_enumjobs("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumjobs: unable to unmarshall SPOOL_Q_ENUMJOBS.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumjobs(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_enumjobs("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_enumjobs: unable to marshall SPOOL_R_ENUMJOBS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_schedulejob(pipes_struct *p)
+{
+ SPOOL_Q_SCHEDULEJOB q_u;
+ SPOOL_R_SCHEDULEJOB r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_schedulejob("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_schedulejob: unable to unmarshall SPOOL_Q_SCHEDULEJOB.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_schedulejob(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_schedulejob("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_schedulejob: unable to marshall SPOOL_R_SCHEDULEJOB.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_setjob(pipes_struct *p)
+{
+ SPOOL_Q_SETJOB q_u;
+ SPOOL_R_SETJOB r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_setjob("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_setjob: unable to unmarshall SPOOL_Q_SETJOB.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_setjob(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_setjob("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_setjob: unable to marshall SPOOL_R_SETJOB.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_enumprinterdrivers(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPRINTERDRIVERS q_u;
+ SPOOL_R_ENUMPRINTERDRIVERS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_enumprinterdrivers("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumprinterdrivers: unable to unmarshall SPOOL_Q_ENUMPRINTERDRIVERS.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumprinterdrivers(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_enumprinterdrivers("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_enumprinterdrivers: unable to marshall SPOOL_R_ENUMPRINTERDRIVERS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_getform(pipes_struct *p)
+{
+ SPOOL_Q_GETFORM q_u;
+ SPOOL_R_GETFORM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_getform("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_getform: unable to unmarshall SPOOL_Q_GETFORM.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_getform(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_getform("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_getform: unable to marshall SPOOL_R_GETFORM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_enumforms(pipes_struct *p)
+{
+ SPOOL_Q_ENUMFORMS q_u;
+ SPOOL_R_ENUMFORMS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_enumforms("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumforms: unable to unmarshall SPOOL_Q_ENUMFORMS.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumforms(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_enumforms("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_enumforms: unable to marshall SPOOL_R_ENUMFORMS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_enumports(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPORTS q_u;
+ SPOOL_R_ENUMPORTS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_enumports("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumports: unable to unmarshall SPOOL_Q_ENUMPORTS.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumports(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_enumports("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_enumports: unable to marshall SPOOL_R_ENUMPORTS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_addprinterex(pipes_struct *p)
+{
+ SPOOL_Q_ADDPRINTEREX q_u;
+ SPOOL_R_ADDPRINTEREX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_addprinterex("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_addprinterex: unable to unmarshall SPOOL_Q_ADDPRINTEREX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_addprinterex(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_addprinterex("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_addprinterex: unable to marshall SPOOL_R_ADDPRINTEREX.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_addprinterdriver(pipes_struct *p)
+{
+ SPOOL_Q_ADDPRINTERDRIVER q_u;
+ SPOOL_R_ADDPRINTERDRIVER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_addprinterdriver("", &q_u, data, 0)) {
+ if (q_u.level != 3 && q_u.level != 6) {
+ /* Clever hack from Martin Zielinski <mz@seh.de>
+ * to allow downgrade from level 8 (Vista).
+ */
+ DEBUG(3,("api_spoolss_addprinterdriver: unknown SPOOL_Q_ADDPRINTERDRIVER level %u.\n",
+ (unsigned int)q_u.level ));
+ setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_INVALID_TAG));
+ return True;
+ }
+ DEBUG(0,("spoolss_io_q_addprinterdriver: unable to unmarshall SPOOL_Q_ADDPRINTERDRIVER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_addprinterdriver(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_addprinterdriver("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_addprinterdriver: unable to marshall SPOOL_R_ADDPRINTERDRIVER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_getprinterdriverdirectory(pipes_struct *p)
+{
+ SPOOL_Q_GETPRINTERDRIVERDIR q_u;
+ SPOOL_R_GETPRINTERDRIVERDIR r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_getprinterdriverdir("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_getprinterdriverdir: unable to unmarshall SPOOL_Q_GETPRINTERDRIVERDIR.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_getprinterdriverdirectory(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_getprinterdriverdir("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_getprinterdriverdir: unable to marshall SPOOL_R_GETPRINTERDRIVERDIR.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_enumprinterdata(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPRINTERDATA q_u;
+ SPOOL_R_ENUMPRINTERDATA r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_enumprinterdata("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumprinterdata: unable to unmarshall SPOOL_Q_ENUMPRINTERDATA.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumprinterdata(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_enumprinterdata("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_enumprinterdata: unable to marshall SPOOL_R_ENUMPRINTERDATA.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_setprinterdata(pipes_struct *p)
+{
+ SPOOL_Q_SETPRINTERDATA q_u;
+ SPOOL_R_SETPRINTERDATA r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_setprinterdata("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_setprinterdata: unable to unmarshall SPOOL_Q_SETPRINTERDATA.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_setprinterdata(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_setprinterdata("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_setprinterdata: unable to marshall SPOOL_R_SETPRINTERDATA.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+static bool api_spoolss_reset_printer(pipes_struct *p)
+{
+ SPOOL_Q_RESETPRINTER q_u;
+ SPOOL_R_RESETPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_resetprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_setprinterdata: unable to unmarshall SPOOL_Q_SETPRINTERDATA.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_resetprinter(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_resetprinter("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_setprinterdata: unable to marshall SPOOL_R_RESETPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+static bool api_spoolss_addform(pipes_struct *p)
+{
+ SPOOL_Q_ADDFORM q_u;
+ SPOOL_R_ADDFORM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_addform("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_addform: unable to unmarshall SPOOL_Q_ADDFORM.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_addform(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_addform("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_addform: unable to marshall SPOOL_R_ADDFORM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_deleteform(pipes_struct *p)
+{
+ SPOOL_Q_DELETEFORM q_u;
+ SPOOL_R_DELETEFORM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_deleteform("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_deleteform: unable to unmarshall SPOOL_Q_DELETEFORM.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_deleteform(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_deleteform("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_deleteform: unable to marshall SPOOL_R_DELETEFORM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_setform(pipes_struct *p)
+{
+ SPOOL_Q_SETFORM q_u;
+ SPOOL_R_SETFORM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_setform("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_setform: unable to unmarshall SPOOL_Q_SETFORM.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_setform(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_setform("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_setform: unable to marshall SPOOL_R_SETFORM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_enumprintprocessors(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPRINTPROCESSORS q_u;
+ SPOOL_R_ENUMPRINTPROCESSORS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_enumprintprocessors("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumprintprocessors: unable to unmarshall SPOOL_Q_ENUMPRINTPROCESSORS.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumprintprocessors(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_enumprintprocessors("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_enumprintprocessors: unable to marshall SPOOL_R_ENUMPRINTPROCESSORS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_addprintprocessor(pipes_struct *p)
+{
+ SPOOL_Q_ADDPRINTPROCESSOR q_u;
+ SPOOL_R_ADDPRINTPROCESSOR r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_addprintprocessor("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_addprintprocessor: unable to unmarshall SPOOL_Q_ADDPRINTPROCESSOR.\n"));
+ return False;
+ }
+
+ /* for now, just indicate success and ignore the add. We'll
+ automatically set the winprint processor for printer
+ entries later. Used to debug the LexMark Optra S 1855 PCL
+ driver --jerry */
+ r_u.status = WERR_OK;
+
+ if(!spoolss_io_r_addprintprocessor("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_addprintprocessor: unable to marshall SPOOL_R_ADDPRINTPROCESSOR.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_enumprintprocdatatypes(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPRINTPROCDATATYPES q_u;
+ SPOOL_R_ENUMPRINTPROCDATATYPES r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_enumprintprocdatatypes("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumprintprocdatatypes: unable to unmarshall SPOOL_Q_ENUMPRINTPROCDATATYPES.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumprintprocdatatypes(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_enumprintprocdatatypes("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_enumprintprocdatatypes: unable to marshall SPOOL_R_ENUMPRINTPROCDATATYPES.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_enumprintmonitors(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPRINTMONITORS q_u;
+ SPOOL_R_ENUMPRINTMONITORS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_enumprintmonitors("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumprintmonitors: unable to unmarshall SPOOL_Q_ENUMPRINTMONITORS.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumprintmonitors(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_enumprintmonitors("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_enumprintmonitors: unable to marshall SPOOL_R_ENUMPRINTMONITORS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_getjob(pipes_struct *p)
+{
+ SPOOL_Q_GETJOB q_u;
+ SPOOL_R_GETJOB r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_getjob("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_getjob: unable to unmarshall SPOOL_Q_GETJOB.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_getjob(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_getjob("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_getjob: unable to marshall SPOOL_R_GETJOB.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_getprinterdataex
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+static bool api_spoolss_getprinterdataex(pipes_struct *p)
+{
+ SPOOL_Q_GETPRINTERDATAEX q_u;
+ SPOOL_R_GETPRINTERDATAEX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* read the stream and fill the struct */
+ if (!spoolss_io_q_getprinterdataex("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_getprinterdataex: unable to unmarshall SPOOL_Q_GETPRINTERDATAEX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_getprinterdataex( p, &q_u, &r_u);
+
+ if (!spoolss_io_r_getprinterdataex("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_getprinterdataex: unable to marshall SPOOL_R_GETPRINTERDATAEX.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_setprinterdataex(pipes_struct *p)
+{
+ SPOOL_Q_SETPRINTERDATAEX q_u;
+ SPOOL_R_SETPRINTERDATAEX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_setprinterdataex("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_setprinterdataex: unable to unmarshall SPOOL_Q_SETPRINTERDATAEX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_setprinterdataex(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_setprinterdataex("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_setprinterdataex: unable to marshall SPOOL_R_SETPRINTERDATAEX.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_enumprinterkey(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPRINTERKEY q_u;
+ SPOOL_R_ENUMPRINTERKEY r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_enumprinterkey("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_setprinterkey: unable to unmarshall SPOOL_Q_ENUMPRINTERKEY.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumprinterkey(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_enumprinterkey("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_enumprinterkey: unable to marshall SPOOL_R_ENUMPRINTERKEY.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_enumprinterdataex(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPRINTERDATAEX q_u;
+ SPOOL_R_ENUMPRINTERDATAEX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_enumprinterdataex("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumprinterdataex: unable to unmarshall SPOOL_Q_ENUMPRINTERDATAEX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumprinterdataex(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_enumprinterdataex("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_enumprinterdataex: unable to marshall SPOOL_R_ENUMPRINTERDATAEX.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_getprintprocessordirectory(pipes_struct *p)
+{
+ SPOOL_Q_GETPRINTPROCESSORDIRECTORY q_u;
+ SPOOL_R_GETPRINTPROCESSORDIRECTORY r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_getprintprocessordirectory("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_getprintprocessordirectory: unable to unmarshall SPOOL_Q_GETPRINTPROCESSORDIRECTORY.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_getprintprocessordirectory(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_getprintprocessordirectory("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_getprintprocessordirectory: unable to marshall SPOOL_R_GETPRINTPROCESSORDIRECTORY.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_deleteprinterdataex(pipes_struct *p)
+{
+ SPOOL_Q_DELETEPRINTERDATAEX q_u;
+ SPOOL_R_DELETEPRINTERDATAEX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_deleteprinterdataex("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_deleteprinterdataex: unable to unmarshall SPOOL_Q_DELETEPRINTERDATAEX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_deleteprinterdataex(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_deleteprinterdataex("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_deleteprinterdataex: unable to marshall SPOOL_R_DELETEPRINTERDATAEX.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_deleteprinterkey(pipes_struct *p)
+{
+ SPOOL_Q_DELETEPRINTERKEY q_u;
+ SPOOL_R_DELETEPRINTERKEY r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_deleteprinterkey("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_deleteprinterkey: unable to unmarshall SPOOL_Q_DELETEPRINTERKEY.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_deleteprinterkey(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_deleteprinterkey("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_deleteprinterkey: unable to marshall SPOOL_R_DELETEPRINTERKEY.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_addprinterdriverex(pipes_struct *p)
+{
+ SPOOL_Q_ADDPRINTERDRIVEREX q_u;
+ SPOOL_R_ADDPRINTERDRIVEREX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_addprinterdriverex("", &q_u, data, 0)) {
+ if (q_u.level != 3 && q_u.level != 6) {
+ /* Clever hack from Martin Zielinski <mz@seh.de>
+ * to allow downgrade from level 8 (Vista).
+ */
+ DEBUG(3,("api_spoolss_addprinterdriverex: unknown SPOOL_Q_ADDPRINTERDRIVEREX level %u.\n",
+ (unsigned int)q_u.level ));
+ setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_INVALID_TAG));
+ return True;
+ }
+ DEBUG(0,("spoolss_io_q_addprinterdriverex: unable to unmarshall SPOOL_Q_ADDPRINTERDRIVEREX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_addprinterdriverex(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_addprinterdriverex("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_addprinterdriverex: unable to marshall SPOOL_R_ADDPRINTERDRIVEREX.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_deleteprinterdriverex(pipes_struct *p)
+{
+ SPOOL_Q_DELETEPRINTERDRIVEREX q_u;
+ SPOOL_R_DELETEPRINTERDRIVEREX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_deleteprinterdriverex("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_deleteprinterdriverex: unable to unmarshall SPOOL_Q_DELETEPRINTERDRIVEREX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_deleteprinterdriverex(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_deleteprinterdriverex("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_deleteprinterdriverex: unable to marshall SPOOL_R_DELETEPRINTERDRIVEREX.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool api_spoolss_xcvdataport(pipes_struct *p)
+{
+ SPOOL_Q_XCVDATAPORT q_u;
+ SPOOL_R_XCVDATAPORT r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_xcvdataport("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_replyopenprinter: unable to unmarshall SPOOL_Q_XCVDATAPORT.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_xcvdataport(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_xcvdataport("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_replyopenprinter: unable to marshall SPOOL_R_XCVDATAPORT.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+\pipe\spoolss commands
+********************************************************************/
+
+ struct api_struct api_spoolss_cmds[] =
+ {
+ {"SPOOLSS_OPENPRINTER", SPOOLSS_OPENPRINTER, api_spoolss_open_printer },
+ {"SPOOLSS_OPENPRINTEREX", SPOOLSS_OPENPRINTEREX, api_spoolss_open_printer_ex },
+ {"SPOOLSS_GETPRINTERDATA", SPOOLSS_GETPRINTERDATA, api_spoolss_getprinterdata },
+ {"SPOOLSS_CLOSEPRINTER", SPOOLSS_CLOSEPRINTER, api_spoolss_closeprinter },
+ {"SPOOLSS_DELETEPRINTER", SPOOLSS_DELETEPRINTER, api_spoolss_deleteprinter },
+ {"SPOOLSS_ABORTPRINTER", SPOOLSS_ABORTPRINTER, api_spoolss_abortprinter },
+ {"SPOOLSS_RFFPCNEX", SPOOLSS_RFFPCNEX, api_spoolss_rffpcnex },
+ {"SPOOLSS_RFNPCNEX", SPOOLSS_RFNPCNEX, api_spoolss_rfnpcnex },
+ {"SPOOLSS_ENUMPRINTERS", SPOOLSS_ENUMPRINTERS, api_spoolss_enumprinters },
+ {"SPOOLSS_GETPRINTER", SPOOLSS_GETPRINTER, api_spoolss_getprinter },
+ {"SPOOLSS_GETPRINTERDRIVER2", SPOOLSS_GETPRINTERDRIVER2, api_spoolss_getprinterdriver2 },
+ {"SPOOLSS_STARTPAGEPRINTER", SPOOLSS_STARTPAGEPRINTER, api_spoolss_startpageprinter },
+ {"SPOOLSS_ENDPAGEPRINTER", SPOOLSS_ENDPAGEPRINTER, api_spoolss_endpageprinter },
+ {"SPOOLSS_STARTDOCPRINTER", SPOOLSS_STARTDOCPRINTER, api_spoolss_startdocprinter },
+ {"SPOOLSS_ENDDOCPRINTER", SPOOLSS_ENDDOCPRINTER, api_spoolss_enddocprinter },
+ {"SPOOLSS_WRITEPRINTER", SPOOLSS_WRITEPRINTER, api_spoolss_writeprinter },
+ {"SPOOLSS_SETPRINTER", SPOOLSS_SETPRINTER, api_spoolss_setprinter },
+ {"SPOOLSS_FCPN", SPOOLSS_FCPN, api_spoolss_fcpn },
+ {"SPOOLSS_ADDJOB", SPOOLSS_ADDJOB, api_spoolss_addjob },
+ {"SPOOLSS_ENUMJOBS", SPOOLSS_ENUMJOBS, api_spoolss_enumjobs },
+ {"SPOOLSS_SCHEDULEJOB", SPOOLSS_SCHEDULEJOB, api_spoolss_schedulejob },
+ {"SPOOLSS_SETJOB", SPOOLSS_SETJOB, api_spoolss_setjob },
+ {"SPOOLSS_ENUMFORMS", SPOOLSS_ENUMFORMS, api_spoolss_enumforms },
+ {"SPOOLSS_ENUMPORTS", SPOOLSS_ENUMPORTS, api_spoolss_enumports },
+ {"SPOOLSS_ENUMPRINTERDRIVERS", SPOOLSS_ENUMPRINTERDRIVERS, api_spoolss_enumprinterdrivers },
+ {"SPOOLSS_ADDPRINTEREX", SPOOLSS_ADDPRINTEREX, api_spoolss_addprinterex },
+ {"SPOOLSS_ADDPRINTERDRIVER", SPOOLSS_ADDPRINTERDRIVER, api_spoolss_addprinterdriver },
+ {"SPOOLSS_DELETEPRINTERDRIVER", SPOOLSS_DELETEPRINTERDRIVER, api_spoolss_deleteprinterdriver },
+ {"SPOOLSS_GETPRINTERDRIVERDIRECTORY", SPOOLSS_GETPRINTERDRIVERDIRECTORY, api_spoolss_getprinterdriverdirectory },
+ {"SPOOLSS_ENUMPRINTERDATA", SPOOLSS_ENUMPRINTERDATA, api_spoolss_enumprinterdata },
+ {"SPOOLSS_SETPRINTERDATA", SPOOLSS_SETPRINTERDATA, api_spoolss_setprinterdata },
+ {"SPOOLSS_RESETPRINTER", SPOOLSS_RESETPRINTER, api_spoolss_reset_printer },
+ {"SPOOLSS_DELETEPRINTERDATA", SPOOLSS_DELETEPRINTERDATA, api_spoolss_deleteprinterdata },
+ {"SPOOLSS_ADDFORM", SPOOLSS_ADDFORM, api_spoolss_addform },
+ {"SPOOLSS_DELETEFORM", SPOOLSS_DELETEFORM, api_spoolss_deleteform },
+ {"SPOOLSS_GETFORM", SPOOLSS_GETFORM, api_spoolss_getform },
+ {"SPOOLSS_SETFORM", SPOOLSS_SETFORM, api_spoolss_setform },
+ {"SPOOLSS_ADDPRINTPROCESSOR", SPOOLSS_ADDPRINTPROCESSOR, api_spoolss_addprintprocessor },
+ {"SPOOLSS_ENUMPRINTPROCESSORS", SPOOLSS_ENUMPRINTPROCESSORS, api_spoolss_enumprintprocessors },
+ {"SPOOLSS_ENUMMONITORS", SPOOLSS_ENUMMONITORS, api_spoolss_enumprintmonitors },
+ {"SPOOLSS_GETJOB", SPOOLSS_GETJOB, api_spoolss_getjob },
+ {"SPOOLSS_ENUMPRINTPROCDATATYPES", SPOOLSS_ENUMPRINTPROCDATATYPES, api_spoolss_enumprintprocdatatypes },
+ {"SPOOLSS_GETPRINTERDATAEX", SPOOLSS_GETPRINTERDATAEX, api_spoolss_getprinterdataex },
+ {"SPOOLSS_SETPRINTERDATAEX", SPOOLSS_SETPRINTERDATAEX, api_spoolss_setprinterdataex },
+ {"SPOOLSS_DELETEPRINTERDATAEX", SPOOLSS_DELETEPRINTERDATAEX, api_spoolss_deleteprinterdataex },
+ {"SPOOLSS_ENUMPRINTERDATAEX", SPOOLSS_ENUMPRINTERDATAEX, api_spoolss_enumprinterdataex },
+ {"SPOOLSS_ENUMPRINTERKEY", SPOOLSS_ENUMPRINTERKEY, api_spoolss_enumprinterkey },
+ {"SPOOLSS_DELETEPRINTERKEY", SPOOLSS_DELETEPRINTERKEY, api_spoolss_deleteprinterkey },
+ {"SPOOLSS_GETPRINTPROCESSORDIRECTORY",SPOOLSS_GETPRINTPROCESSORDIRECTORY,api_spoolss_getprintprocessordirectory},
+ {"SPOOLSS_ADDPRINTERDRIVEREX", SPOOLSS_ADDPRINTERDRIVEREX, api_spoolss_addprinterdriverex },
+ {"SPOOLSS_DELETEPRINTERDRIVEREX", SPOOLSS_DELETEPRINTERDRIVEREX, api_spoolss_deleteprinterdriverex },
+ {"SPOOLSS_XCVDATAPORT", SPOOLSS_XCVDATAPORT, api_spoolss_xcvdataport },
+};
+
+void spoolss_get_pipe_fns( struct api_struct **fns, int *n_fns )
+{
+ *fns = api_spoolss_cmds;
+ *n_fns = sizeof(api_spoolss_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_spoolss_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION,
+ "spoolss", "spoolss", &syntax_spoolss,
+ api_spoolss_cmds,
+ sizeof(api_spoolss_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c
new file mode 100644
index 0000000000..635898a9d5
--- /dev/null
+++ b/source3/rpc_server/srv_spoolss_nt.c
@@ -0,0 +1,9946 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ * Copyright (C) Jean François Micouleau 1998-2000,
+ * Copyright (C) Jeremy Allison 2001-2002,
+ * Copyright (C) Gerald Carter 2000-2004,
+ * Copyright (C) Tim Potter 2001-2002.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Since the SPOOLSS rpc routines are basically DOS 16-bit calls wrapped
+ up, all the errors returned are DOS errors, not NT status codes. */
+
+#include "includes.h"
+
+extern userdom_struct current_user_info;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+#ifndef MAX_OPEN_PRINTER_EXS
+#define MAX_OPEN_PRINTER_EXS 50
+#endif
+
+#define MAGIC_DISPLAY_FREQUENCY 0xfade2bad
+#define PHANTOM_DEVMODE_KEY "_p_f_a_n_t_0_m_"
+
+struct table_node {
+ const char *long_archi;
+ const char *short_archi;
+ int version;
+};
+
+static Printer_entry *printers_list;
+
+typedef struct _counter_printer_0 {
+ struct _counter_printer_0 *next;
+ struct _counter_printer_0 *prev;
+
+ int snum;
+ uint32 counter;
+} counter_printer_0;
+
+static counter_printer_0 *counter_list;
+
+static struct rpc_pipe_client *notify_cli_pipe; /* print notify back-channel pipe handle*/
+static uint32 smb_connections=0;
+
+
+/* in printing/nt_printing.c */
+
+extern struct standard_mapping printer_std_mapping, printserver_std_mapping;
+
+/* API table for Xcv Monitor functions */
+
+struct xcv_api_table {
+ const char *name;
+ WERROR(*fn) (NT_USER_TOKEN *token, RPC_BUFFER *in, RPC_BUFFER *out, uint32 *needed);
+};
+
+/********************************************************************
+ * Canonicalize servername.
+ ********************************************************************/
+
+static const char *canon_servername(const char *servername)
+{
+ const char *pservername = servername;
+ while (*pservername == '\\') {
+ pservername++;
+ }
+ return pservername;
+}
+
+/* translate between internal status numbers and NT status numbers */
+static int nt_printj_status(int v)
+{
+ switch (v) {
+ case LPQ_QUEUED:
+ return 0;
+ case LPQ_PAUSED:
+ return JOB_STATUS_PAUSED;
+ case LPQ_SPOOLING:
+ return JOB_STATUS_SPOOLING;
+ case LPQ_PRINTING:
+ return JOB_STATUS_PRINTING;
+ case LPQ_ERROR:
+ return JOB_STATUS_ERROR;
+ case LPQ_DELETING:
+ return JOB_STATUS_DELETING;
+ case LPQ_OFFLINE:
+ return JOB_STATUS_OFFLINE;
+ case LPQ_PAPEROUT:
+ return JOB_STATUS_PAPEROUT;
+ case LPQ_PRINTED:
+ return JOB_STATUS_PRINTED;
+ case LPQ_DELETED:
+ return JOB_STATUS_DELETED;
+ case LPQ_BLOCKED:
+ return JOB_STATUS_BLOCKED;
+ case LPQ_USER_INTERVENTION:
+ return JOB_STATUS_USER_INTERVENTION;
+ }
+ return 0;
+}
+
+static int nt_printq_status(int v)
+{
+ switch (v) {
+ case LPQ_PAUSED:
+ return PRINTER_STATUS_PAUSED;
+ case LPQ_QUEUED:
+ case LPQ_SPOOLING:
+ case LPQ_PRINTING:
+ return 0;
+ }
+ return 0;
+}
+
+/****************************************************************************
+ Functions to handle SPOOL_NOTIFY_OPTION struct stored in Printer_entry.
+****************************************************************************/
+
+static void free_spool_notify_option(SPOOL_NOTIFY_OPTION **pp)
+{
+ if (*pp == NULL)
+ return;
+
+ SAFE_FREE((*pp)->ctr.type);
+ SAFE_FREE(*pp);
+}
+
+/***************************************************************************
+ Disconnect from the client
+****************************************************************************/
+
+static void srv_spoolss_replycloseprinter(int snum, POLICY_HND *handle)
+{
+ WERROR result;
+
+ /*
+ * Tell the specific printing tdb we no longer want messages for this printer
+ * by deregistering our PID.
+ */
+
+ if (!print_notify_deregister_pid(snum))
+ DEBUG(0,("print_notify_register_pid: Failed to register our pid for printer %s\n", lp_const_servicename(snum) ));
+
+ /* weird if the test succeds !!! */
+ if (smb_connections==0) {
+ DEBUG(0,("srv_spoolss_replycloseprinter:Trying to close non-existant notify backchannel !\n"));
+ return;
+ }
+
+ result = rpccli_spoolss_reply_close_printer(notify_cli_pipe,
+ talloc_tos(),
+ handle);
+
+ if (!W_ERROR_IS_OK(result))
+ DEBUG(0,("srv_spoolss_replycloseprinter: reply_close_printer failed [%s].\n",
+ dos_errstr(result)));
+
+ /* if it's the last connection, deconnect the IPC$ share */
+ if (smb_connections==1) {
+
+ cli_shutdown( rpc_pipe_np_smb_conn(notify_cli_pipe) );
+ notify_cli_pipe = NULL; /* The above call shuts downn the pipe also. */
+
+ messaging_deregister(smbd_messaging_context(),
+ MSG_PRINTER_NOTIFY2, NULL);
+
+ /* Tell the connections db we're no longer interested in
+ * printer notify messages. */
+
+ register_message_flags( False, FLAG_MSG_PRINT_NOTIFY );
+ }
+
+ smb_connections--;
+}
+
+/****************************************************************************
+ Functions to free a printer entry datastruct.
+****************************************************************************/
+
+static void free_printer_entry(void *ptr)
+{
+ Printer_entry *Printer = (Printer_entry *)ptr;
+
+ if (Printer->notify.client_connected==True) {
+ int snum = -1;
+
+ if ( Printer->printer_type == SPLHND_SERVER) {
+ snum = -1;
+ srv_spoolss_replycloseprinter(snum, &Printer->notify.client_hnd);
+ } else if (Printer->printer_type == SPLHND_PRINTER) {
+ snum = print_queue_snum(Printer->sharename);
+ if (snum != -1)
+ srv_spoolss_replycloseprinter(snum,
+ &Printer->notify.client_hnd);
+ }
+ }
+
+ Printer->notify.flags=0;
+ Printer->notify.options=0;
+ Printer->notify.localmachine[0]='\0';
+ Printer->notify.printerlocal=0;
+ free_spool_notify_option(&Printer->notify.option);
+ Printer->notify.option=NULL;
+ Printer->notify.client_connected=False;
+
+ free_nt_devicemode( &Printer->nt_devmode );
+ free_a_printer( &Printer->printer_info, 2 );
+
+ talloc_destroy( Printer->ctx );
+
+ /* Remove from the internal list. */
+ DLIST_REMOVE(printers_list, Printer);
+
+ SAFE_FREE(Printer);
+}
+
+/****************************************************************************
+ Functions to duplicate a SPOOL_NOTIFY_OPTION struct stored in Printer_entry.
+****************************************************************************/
+
+static SPOOL_NOTIFY_OPTION *dup_spool_notify_option(SPOOL_NOTIFY_OPTION *sp)
+{
+ SPOOL_NOTIFY_OPTION *new_sp = NULL;
+
+ if (!sp)
+ return NULL;
+
+ new_sp = SMB_MALLOC_P(SPOOL_NOTIFY_OPTION);
+ if (!new_sp)
+ return NULL;
+
+ *new_sp = *sp;
+
+ if (sp->ctr.count) {
+ new_sp->ctr.type = (SPOOL_NOTIFY_OPTION_TYPE *)memdup(sp->ctr.type, sizeof(SPOOL_NOTIFY_OPTION_TYPE) * sp->ctr.count);
+
+ if (!new_sp->ctr.type) {
+ SAFE_FREE(new_sp);
+ return NULL;
+ }
+ }
+
+ return new_sp;
+}
+
+/****************************************************************************
+ find printer index by handle
+****************************************************************************/
+
+static Printer_entry *find_printer_index_by_hnd(pipes_struct *p, POLICY_HND *hnd)
+{
+ Printer_entry *find_printer = NULL;
+
+ if(!find_policy_by_hnd(p,hnd,(void **)(void *)&find_printer)) {
+ DEBUG(2,("find_printer_index_by_hnd: Printer handle not found: "));
+ return NULL;
+ }
+
+ return find_printer;
+}
+
+/****************************************************************************
+ Close printer index by handle.
+****************************************************************************/
+
+static bool close_printer_handle(pipes_struct *p, POLICY_HND *hnd)
+{
+ Printer_entry *Printer = find_printer_index_by_hnd(p, hnd);
+
+ if (!Printer) {
+ DEBUG(2,("close_printer_handle: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
+ return False;
+ }
+
+ close_policy_hnd(p, hnd);
+
+ return True;
+}
+
+/****************************************************************************
+ Delete a printer given a handle.
+****************************************************************************/
+
+WERROR delete_printer_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, const char *sharename )
+{
+ char *cmd = lp_deleteprinter_cmd();
+ char *command = NULL;
+ int ret;
+ SE_PRIV se_printop = SE_PRINT_OPERATOR;
+ bool is_print_op = False;
+
+ /* can't fail if we don't try */
+
+ if ( !*cmd )
+ return WERR_OK;
+
+ command = talloc_asprintf(ctx,
+ "%s \"%s\"",
+ cmd, sharename);
+ if (!command) {
+ return WERR_NOMEM;
+ }
+ if ( token )
+ is_print_op = user_has_privileges( token, &se_printop );
+
+ DEBUG(10,("Running [%s]\n", command));
+
+ /********** BEGIN SePrintOperatorPrivlege BLOCK **********/
+
+ if ( is_print_op )
+ become_root();
+
+ if ( (ret = smbrun(command, NULL)) == 0 ) {
+ /* Tell everyone we updated smb.conf. */
+ message_send_all(smbd_messaging_context(),
+ MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
+ }
+
+ if ( is_print_op )
+ unbecome_root();
+
+ /********** END SePrintOperatorPrivlege BLOCK **********/
+
+ DEBUGADD(10,("returned [%d]\n", ret));
+
+ TALLOC_FREE(command);
+
+ if (ret != 0)
+ return WERR_BADFID; /* What to return here? */
+
+ /* go ahead and re-read the services immediately */
+ reload_services( False );
+
+ if ( lp_servicenumber( sharename ) < 0 )
+ return WERR_ACCESS_DENIED;
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ Delete a printer given a handle.
+****************************************************************************/
+
+static WERROR delete_printer_handle(pipes_struct *p, POLICY_HND *hnd)
+{
+ Printer_entry *Printer = find_printer_index_by_hnd(p, hnd);
+
+ if (!Printer) {
+ DEBUG(2,("delete_printer_handle: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
+ return WERR_BADFID;
+ }
+
+ /*
+ * It turns out that Windows allows delete printer on a handle
+ * opened by an admin user, then used on a pipe handle created
+ * by an anonymous user..... but they're working on security.... riiight !
+ * JRA.
+ */
+
+ if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
+ DEBUG(3, ("delete_printer_handle: denied by handle\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ /* this does not need a become root since the access check has been
+ done on the handle already */
+
+ if (del_a_printer( Printer->sharename ) != 0) {
+ DEBUG(3,("Error deleting printer %s\n", Printer->sharename));
+ return WERR_BADFID;
+ }
+
+ return delete_printer_hook(p->mem_ctx, p->pipe_user.nt_user_token, Printer->sharename );
+}
+
+/****************************************************************************
+ Return the snum of a printer corresponding to an handle.
+****************************************************************************/
+
+static bool get_printer_snum(pipes_struct *p, POLICY_HND *hnd, int *number,
+ struct share_params **params)
+{
+ Printer_entry *Printer = find_printer_index_by_hnd(p, hnd);
+
+ if (!Printer) {
+ DEBUG(2,("get_printer_snum: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
+ return False;
+ }
+
+ switch (Printer->printer_type) {
+ case SPLHND_PRINTER:
+ DEBUG(4,("short name:%s\n", Printer->sharename));
+ *number = print_queue_snum(Printer->sharename);
+ return (*number != -1);
+ case SPLHND_SERVER:
+ return False;
+ default:
+ return False;
+ }
+}
+
+/****************************************************************************
+ Set printer handle type.
+ Check if it's \\server or \\server\printer
+****************************************************************************/
+
+static bool set_printer_hnd_printertype(Printer_entry *Printer, char *handlename)
+{
+ DEBUG(3,("Setting printer type=%s\n", handlename));
+
+ if ( strlen(handlename) < 3 ) {
+ DEBUGADD(4,("A print server must have at least 1 char ! %s\n", handlename));
+ return False;
+ }
+
+ /* it's a print server */
+ if (*handlename=='\\' && *(handlename+1)=='\\' && !strchr_m(handlename+2, '\\')) {
+ DEBUGADD(4,("Printer is a print server\n"));
+ Printer->printer_type = SPLHND_SERVER;
+ }
+ /* it's a printer (set_printer_hnd_name() will handle port monitors */
+ else {
+ DEBUGADD(4,("Printer is a printer\n"));
+ Printer->printer_type = SPLHND_PRINTER;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Set printer handle name.. Accept names like \\server, \\server\printer,
+ \\server\SHARE, & "\\server\,XcvMonitor Standard TCP/IP Port" See
+ the MSDN docs regarding OpenPrinter() for details on the XcvData() and
+ XcvDataPort() interface.
+****************************************************************************/
+
+static bool set_printer_hnd_name(Printer_entry *Printer, char *handlename)
+{
+ int snum;
+ int n_services=lp_numservices();
+ char *aprinter, *printername;
+ const char *servername;
+ fstring sname;
+ bool found=False;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ WERROR result;
+
+ DEBUG(4,("Setting printer name=%s (len=%lu)\n", handlename, (unsigned long)strlen(handlename)));
+
+ aprinter = handlename;
+ if ( *handlename == '\\' ) {
+ servername = canon_servername(handlename);
+ if ( (aprinter = strchr_m( servername, '\\' )) != NULL ) {
+ *aprinter = '\0';
+ aprinter++;
+ }
+ } else {
+ servername = "";
+ }
+
+ /* save the servername to fill in replies on this handle */
+
+ if ( !is_myname_or_ipaddr( servername ) )
+ return False;
+
+ fstrcpy( Printer->servername, servername );
+
+ if ( Printer->printer_type == SPLHND_SERVER )
+ return True;
+
+ if ( Printer->printer_type != SPLHND_PRINTER )
+ return False;
+
+ DEBUGADD(5, ("searching for [%s]\n", aprinter ));
+
+ /* check for the Port Monitor Interface */
+
+ if ( strequal( aprinter, SPL_XCV_MONITOR_TCPMON ) ) {
+ Printer->printer_type = SPLHND_PORTMON_TCP;
+ fstrcpy(sname, SPL_XCV_MONITOR_TCPMON);
+ found = True;
+ }
+ else if ( strequal( aprinter, SPL_XCV_MONITOR_LOCALMON ) ) {
+ Printer->printer_type = SPLHND_PORTMON_LOCAL;
+ fstrcpy(sname, SPL_XCV_MONITOR_LOCALMON);
+ found = True;
+ }
+
+ /* Search all sharenames first as this is easier than pulling
+ the printer_info_2 off of disk. Don't use find_service() since
+ that calls out to map_username() */
+
+ /* do another loop to look for printernames */
+
+ for (snum=0; !found && snum<n_services; snum++) {
+
+ /* no point going on if this is not a printer */
+
+ if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
+ continue;
+
+ fstrcpy(sname, lp_servicename(snum));
+ if ( strequal( aprinter, sname ) ) {
+ found = True;
+ break;
+ }
+
+ /* no point looking up the printer object if
+ we aren't allowing printername != sharename */
+
+ if ( lp_force_printername(snum) )
+ continue;
+
+ fstrcpy(sname, lp_servicename(snum));
+
+ printer = NULL;
+
+ /* This call doesn't fill in the location or comment from
+ * a CUPS server for efficiency with large numbers of printers.
+ * JRA.
+ */
+
+ result = get_a_printer_search( NULL, &printer, 2, sname );
+ if ( !W_ERROR_IS_OK(result) ) {
+ DEBUG(0,("set_printer_hnd_name: failed to lookup printer [%s] -- result [%s]\n",
+ sname, dos_errstr(result)));
+ continue;
+ }
+
+ /* printername is always returned as \\server\printername */
+ if ( !(printername = strchr_m(&printer->info_2->printername[2], '\\')) ) {
+ DEBUG(0,("set_printer_hnd_name: info2->printername in wrong format! [%s]\n",
+ printer->info_2->printername));
+ free_a_printer( &printer, 2);
+ continue;
+ }
+
+ printername++;
+
+ if ( strequal(printername, aprinter) ) {
+ free_a_printer( &printer, 2);
+ found = True;
+ break;
+ }
+
+ DEBUGADD(10, ("printername: %s\n", printername));
+
+ free_a_printer( &printer, 2);
+ }
+
+ free_a_printer( &printer, 2);
+
+ if ( !found ) {
+ DEBUGADD(4,("Printer not found\n"));
+ return False;
+ }
+
+ DEBUGADD(4,("set_printer_hnd_name: Printer found: %s -> %s\n", aprinter, sname));
+
+ fstrcpy(Printer->sharename, sname);
+
+ return True;
+}
+
+/****************************************************************************
+ Find first available printer slot. creates a printer handle for you.
+ ****************************************************************************/
+
+static bool open_printer_hnd(pipes_struct *p, POLICY_HND *hnd, char *name, uint32 access_granted)
+{
+ Printer_entry *new_printer;
+
+ DEBUG(10,("open_printer_hnd: name [%s]\n", name));
+
+ if((new_printer=SMB_MALLOC_P(Printer_entry)) == NULL)
+ return False;
+
+ ZERO_STRUCTP(new_printer);
+
+ if (!create_policy_hnd(p, hnd, free_printer_entry, new_printer)) {
+ SAFE_FREE(new_printer);
+ return False;
+ }
+
+ /* Add to the internal list. */
+ DLIST_ADD(printers_list, new_printer);
+
+ new_printer->notify.option=NULL;
+
+ if ( !(new_printer->ctx = talloc_init("Printer Entry [%p]", hnd)) ) {
+ DEBUG(0,("open_printer_hnd: talloc_init() failed!\n"));
+ close_printer_handle(p, hnd);
+ return False;
+ }
+
+ if (!set_printer_hnd_printertype(new_printer, name)) {
+ close_printer_handle(p, hnd);
+ return False;
+ }
+
+ if (!set_printer_hnd_name(new_printer, name)) {
+ close_printer_handle(p, hnd);
+ return False;
+ }
+
+ new_printer->access_granted = access_granted;
+
+ DEBUG(5, ("%d printer handles active\n", (int)p->pipe_handles->count ));
+
+ return True;
+}
+
+/***************************************************************************
+ check to see if the client motify handle is monitoring the notification
+ given by (notify_type, notify_field).
+ **************************************************************************/
+
+static bool is_monitoring_event_flags(uint32 flags, uint16 notify_type,
+ uint16 notify_field)
+{
+ return True;
+}
+
+static bool is_monitoring_event(Printer_entry *p, uint16 notify_type,
+ uint16 notify_field)
+{
+ SPOOL_NOTIFY_OPTION *option = p->notify.option;
+ uint32 i, j;
+
+ /*
+ * Flags should always be zero when the change notify
+ * is registered by the client's spooler. A user Win32 app
+ * might use the flags though instead of the NOTIFY_OPTION_INFO
+ * --jerry
+ */
+
+ if (!option) {
+ return False;
+ }
+
+ if (p->notify.flags)
+ return is_monitoring_event_flags(
+ p->notify.flags, notify_type, notify_field);
+
+ for (i = 0; i < option->count; i++) {
+
+ /* Check match for notify_type */
+
+ if (option->ctr.type[i].type != notify_type)
+ continue;
+
+ /* Check match for field */
+
+ for (j = 0; j < option->ctr.type[i].count; j++) {
+ if (option->ctr.type[i].fields[j] == notify_field) {
+ return True;
+ }
+ }
+ }
+
+ DEBUG(10, ("Open handle for \\\\%s\\%s is not monitoring 0x%02x/0x%02x\n",
+ p->servername, p->sharename, notify_type, notify_field));
+
+ return False;
+}
+
+/* Convert a notification message to a SPOOL_NOTIFY_INFO_DATA struct */
+
+static void notify_one_value(struct spoolss_notify_msg *msg,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0] = msg->notify.value[0];
+ data->notify_data.value[1] = 0;
+}
+
+static void notify_string(struct spoolss_notify_msg *msg,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ TALLOC_CTX *mem_ctx)
+{
+ UNISTR2 unistr;
+
+ /* The length of the message includes the trailing \0 */
+
+ init_unistr2(&unistr, msg->notify.data, UNI_STR_TERMINATE);
+
+ data->notify_data.data.length = msg->len * 2;
+ data->notify_data.data.string = TALLOC_ARRAY(mem_ctx, uint16, msg->len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ memcpy(data->notify_data.data.string, unistr.buffer, msg->len * 2);
+}
+
+static void notify_system_time(struct spoolss_notify_msg *msg,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ TALLOC_CTX *mem_ctx)
+{
+ SYSTEMTIME systime;
+ prs_struct ps;
+
+ if (msg->len != sizeof(time_t)) {
+ DEBUG(5, ("notify_system_time: received wrong sized message (%d)\n",
+ msg->len));
+ return;
+ }
+
+ if (!prs_init(&ps, RPC_MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL)) {
+ DEBUG(5, ("notify_system_time: prs_init() failed\n"));
+ return;
+ }
+
+ if (!make_systemtime(&systime, gmtime((time_t *)msg->notify.data))) {
+ DEBUG(5, ("notify_system_time: unable to make systemtime\n"));
+ prs_mem_free(&ps);
+ return;
+ }
+
+ if (!spoolss_io_system_time("", &ps, 0, &systime)) {
+ prs_mem_free(&ps);
+ return;
+ }
+
+ data->notify_data.data.length = prs_offset(&ps);
+ if (prs_offset(&ps)) {
+ data->notify_data.data.string = (uint16 *)
+ TALLOC(mem_ctx, prs_offset(&ps));
+ if (!data->notify_data.data.string) {
+ prs_mem_free(&ps);
+ return;
+ }
+ prs_copy_all_data_out((char *)data->notify_data.data.string, &ps);
+ } else {
+ data->notify_data.data.string = NULL;
+ }
+
+ prs_mem_free(&ps);
+}
+
+struct notify2_message_table {
+ const char *name;
+ void (*fn)(struct spoolss_notify_msg *msg,
+ SPOOL_NOTIFY_INFO_DATA *data, TALLOC_CTX *mem_ctx);
+};
+
+static struct notify2_message_table printer_notify_table[] = {
+ /* 0x00 */ { "PRINTER_NOTIFY_SERVER_NAME", notify_string },
+ /* 0x01 */ { "PRINTER_NOTIFY_PRINTER_NAME", notify_string },
+ /* 0x02 */ { "PRINTER_NOTIFY_SHARE_NAME", notify_string },
+ /* 0x03 */ { "PRINTER_NOTIFY_PORT_NAME", notify_string },
+ /* 0x04 */ { "PRINTER_NOTIFY_DRIVER_NAME", notify_string },
+ /* 0x05 */ { "PRINTER_NOTIFY_COMMENT", notify_string },
+ /* 0x06 */ { "PRINTER_NOTIFY_LOCATION", notify_string },
+ /* 0x07 */ { "PRINTER_NOTIFY_DEVMODE", NULL },
+ /* 0x08 */ { "PRINTER_NOTIFY_SEPFILE", notify_string },
+ /* 0x09 */ { "PRINTER_NOTIFY_PRINT_PROCESSOR", notify_string },
+ /* 0x0a */ { "PRINTER_NOTIFY_PARAMETERS", NULL },
+ /* 0x0b */ { "PRINTER_NOTIFY_DATATYPE", notify_string },
+ /* 0x0c */ { "PRINTER_NOTIFY_SECURITY_DESCRIPTOR", NULL },
+ /* 0x0d */ { "PRINTER_NOTIFY_ATTRIBUTES", notify_one_value },
+ /* 0x0e */ { "PRINTER_NOTIFY_PRIORITY", notify_one_value },
+ /* 0x0f */ { "PRINTER_NOTIFY_DEFAULT_PRIORITY", NULL },
+ /* 0x10 */ { "PRINTER_NOTIFY_START_TIME", NULL },
+ /* 0x11 */ { "PRINTER_NOTIFY_UNTIL_TIME", NULL },
+ /* 0x12 */ { "PRINTER_NOTIFY_STATUS", notify_one_value },
+};
+
+static struct notify2_message_table job_notify_table[] = {
+ /* 0x00 */ { "JOB_NOTIFY_PRINTER_NAME", NULL },
+ /* 0x01 */ { "JOB_NOTIFY_MACHINE_NAME", NULL },
+ /* 0x02 */ { "JOB_NOTIFY_PORT_NAME", NULL },
+ /* 0x03 */ { "JOB_NOTIFY_USER_NAME", notify_string },
+ /* 0x04 */ { "JOB_NOTIFY_NOTIFY_NAME", NULL },
+ /* 0x05 */ { "JOB_NOTIFY_DATATYPE", NULL },
+ /* 0x06 */ { "JOB_NOTIFY_PRINT_PROCESSOR", NULL },
+ /* 0x07 */ { "JOB_NOTIFY_PARAMETERS", NULL },
+ /* 0x08 */ { "JOB_NOTIFY_DRIVER_NAME", NULL },
+ /* 0x09 */ { "JOB_NOTIFY_DEVMODE", NULL },
+ /* 0x0a */ { "JOB_NOTIFY_STATUS", notify_one_value },
+ /* 0x0b */ { "JOB_NOTIFY_STATUS_STRING", NULL },
+ /* 0x0c */ { "JOB_NOTIFY_SECURITY_DESCRIPTOR", NULL },
+ /* 0x0d */ { "JOB_NOTIFY_DOCUMENT", notify_string },
+ /* 0x0e */ { "JOB_NOTIFY_PRIORITY", NULL },
+ /* 0x0f */ { "JOB_NOTIFY_POSITION", NULL },
+ /* 0x10 */ { "JOB_NOTIFY_SUBMITTED", notify_system_time },
+ /* 0x11 */ { "JOB_NOTIFY_START_TIME", NULL },
+ /* 0x12 */ { "JOB_NOTIFY_UNTIL_TIME", NULL },
+ /* 0x13 */ { "JOB_NOTIFY_TIME", NULL },
+ /* 0x14 */ { "JOB_NOTIFY_TOTAL_PAGES", notify_one_value },
+ /* 0x15 */ { "JOB_NOTIFY_PAGES_PRINTED", NULL },
+ /* 0x16 */ { "JOB_NOTIFY_TOTAL_BYTES", notify_one_value },
+ /* 0x17 */ { "JOB_NOTIFY_BYTES_PRINTED", NULL },
+};
+
+
+/***********************************************************************
+ Allocate talloc context for container object
+ **********************************************************************/
+
+static void notify_msg_ctr_init( SPOOLSS_NOTIFY_MSG_CTR *ctr )
+{
+ if ( !ctr )
+ return;
+
+ ctr->ctx = talloc_init("notify_msg_ctr_init %p", ctr);
+
+ return;
+}
+
+/***********************************************************************
+ release all allocated memory and zero out structure
+ **********************************************************************/
+
+static void notify_msg_ctr_destroy( SPOOLSS_NOTIFY_MSG_CTR *ctr )
+{
+ if ( !ctr )
+ return;
+
+ if ( ctr->ctx )
+ talloc_destroy(ctr->ctx);
+
+ ZERO_STRUCTP(ctr);
+
+ return;
+}
+
+/***********************************************************************
+ **********************************************************************/
+
+static TALLOC_CTX* notify_ctr_getctx( SPOOLSS_NOTIFY_MSG_CTR *ctr )
+{
+ if ( !ctr )
+ return NULL;
+
+ return ctr->ctx;
+}
+
+/***********************************************************************
+ **********************************************************************/
+
+static SPOOLSS_NOTIFY_MSG_GROUP* notify_ctr_getgroup( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx )
+{
+ if ( !ctr || !ctr->msg_groups )
+ return NULL;
+
+ if ( idx >= ctr->num_groups )
+ return NULL;
+
+ return &ctr->msg_groups[idx];
+
+}
+
+/***********************************************************************
+ How many groups of change messages do we have ?
+ **********************************************************************/
+
+static int notify_msg_ctr_numgroups( SPOOLSS_NOTIFY_MSG_CTR *ctr )
+{
+ if ( !ctr )
+ return 0;
+
+ return ctr->num_groups;
+}
+
+/***********************************************************************
+ Add a SPOOLSS_NOTIFY_MSG_CTR to the correct group
+ **********************************************************************/
+
+static int notify_msg_ctr_addmsg( SPOOLSS_NOTIFY_MSG_CTR *ctr, SPOOLSS_NOTIFY_MSG *msg )
+{
+ SPOOLSS_NOTIFY_MSG_GROUP *groups = NULL;
+ SPOOLSS_NOTIFY_MSG_GROUP *msg_grp = NULL;
+ SPOOLSS_NOTIFY_MSG *msg_list = NULL;
+ int i, new_slot;
+
+ if ( !ctr || !msg )
+ return 0;
+
+ /* loop over all groups looking for a matching printer name */
+
+ for ( i=0; i<ctr->num_groups; i++ ) {
+ if ( strcmp(ctr->msg_groups[i].printername, msg->printer) == 0 )
+ break;
+ }
+
+ /* add a new group? */
+
+ if ( i == ctr->num_groups ) {
+ ctr->num_groups++;
+
+ if ( !(groups = TALLOC_REALLOC_ARRAY( ctr->ctx, ctr->msg_groups, SPOOLSS_NOTIFY_MSG_GROUP, ctr->num_groups)) ) {
+ DEBUG(0,("notify_msg_ctr_addmsg: talloc_realloc() failed!\n"));
+ return 0;
+ }
+ ctr->msg_groups = groups;
+
+ /* clear the new entry and set the printer name */
+
+ ZERO_STRUCT( ctr->msg_groups[ctr->num_groups-1] );
+ fstrcpy( ctr->msg_groups[ctr->num_groups-1].printername, msg->printer );
+ }
+
+ /* add the change messages; 'i' is the correct index now regardless */
+
+ msg_grp = &ctr->msg_groups[i];
+
+ msg_grp->num_msgs++;
+
+ if ( !(msg_list = TALLOC_REALLOC_ARRAY( ctr->ctx, msg_grp->msgs, SPOOLSS_NOTIFY_MSG, msg_grp->num_msgs )) ) {
+ DEBUG(0,("notify_msg_ctr_addmsg: talloc_realloc() failed for new message [%d]!\n", msg_grp->num_msgs));
+ return 0;
+ }
+ msg_grp->msgs = msg_list;
+
+ new_slot = msg_grp->num_msgs-1;
+ memcpy( &msg_grp->msgs[new_slot], msg, sizeof(SPOOLSS_NOTIFY_MSG) );
+
+ /* need to allocate own copy of data */
+
+ if ( msg->len != 0 )
+ msg_grp->msgs[new_slot].notify.data = (char *)
+ TALLOC_MEMDUP( ctr->ctx, msg->notify.data, msg->len );
+
+ return ctr->num_groups;
+}
+
+/***********************************************************************
+ Send a change notication message on all handles which have a call
+ back registered
+ **********************************************************************/
+
+static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx )
+{
+ Printer_entry *p;
+ TALLOC_CTX *mem_ctx = notify_ctr_getctx( ctr );
+ SPOOLSS_NOTIFY_MSG_GROUP *msg_group = notify_ctr_getgroup( ctr, idx );
+ SPOOLSS_NOTIFY_MSG *messages;
+ int sending_msg_count;
+
+ if ( !msg_group ) {
+ DEBUG(5,("send_notify2_changes() called with no msg group!\n"));
+ return;
+ }
+
+ messages = msg_group->msgs;
+
+ if ( !messages ) {
+ DEBUG(5,("send_notify2_changes() called with no messages!\n"));
+ return;
+ }
+
+ DEBUG(8,("send_notify2_changes: Enter...[%s]\n", msg_group->printername));
+
+ /* loop over all printers */
+
+ for (p = printers_list; p; p = p->next) {
+ SPOOL_NOTIFY_INFO_DATA *data;
+ uint32 data_len = 0;
+ uint32 id;
+ int i;
+
+ /* Is there notification on this handle? */
+
+ if ( !p->notify.client_connected )
+ continue;
+
+ DEBUG(10,("Client connected! [\\\\%s\\%s]\n", p->servername, p->sharename));
+
+ /* For this printer? Print servers always receive
+ notifications. */
+
+ if ( ( p->printer_type == SPLHND_PRINTER ) &&
+ ( !strequal(msg_group->printername, p->sharename) ) )
+ continue;
+
+ DEBUG(10,("Our printer\n"));
+
+ /* allocate the max entries possible */
+
+ data = TALLOC_ARRAY( mem_ctx, SPOOL_NOTIFY_INFO_DATA, msg_group->num_msgs);
+ if (!data) {
+ return;
+ }
+
+ ZERO_STRUCTP(data);
+
+ /* build the array of change notifications */
+
+ sending_msg_count = 0;
+
+ for ( i=0; i<msg_group->num_msgs; i++ ) {
+ SPOOLSS_NOTIFY_MSG *msg = &messages[i];
+
+ /* Are we monitoring this event? */
+
+ if (!is_monitoring_event(p, msg->type, msg->field))
+ continue;
+
+ sending_msg_count++;
+
+
+ DEBUG(10,("process_notify2_message: Sending message type [0x%x] field [0x%2x] for printer [%s]\n",
+ msg->type, msg->field, p->sharename));
+
+ /*
+ * if the is a printer notification handle and not a job notification
+ * type, then set the id to 0. Other wise just use what was specified
+ * in the message.
+ *
+ * When registering change notification on a print server handle
+ * we always need to send back the id (snum) matching the printer
+ * for which the change took place. For change notify registered
+ * on a printer handle, this does not matter and the id should be 0.
+ *
+ * --jerry
+ */
+
+ if ( ( p->printer_type == SPLHND_PRINTER ) && ( msg->type == PRINTER_NOTIFY_TYPE ) )
+ id = 0;
+ else
+ id = msg->id;
+
+
+ /* Convert unix jobid to smb jobid */
+
+ if (msg->flags & SPOOLSS_NOTIFY_MSG_UNIX_JOBID) {
+ id = sysjob_to_jobid(msg->id);
+
+ if (id == -1) {
+ DEBUG(3, ("no such unix jobid %d\n", msg->id));
+ goto done;
+ }
+ }
+
+ construct_info_data( &data[data_len], msg->type, msg->field, id );
+
+ switch(msg->type) {
+ case PRINTER_NOTIFY_TYPE:
+ if ( printer_notify_table[msg->field].fn )
+ printer_notify_table[msg->field].fn(msg, &data[data_len], mem_ctx);
+ break;
+
+ case JOB_NOTIFY_TYPE:
+ if ( job_notify_table[msg->field].fn )
+ job_notify_table[msg->field].fn(msg, &data[data_len], mem_ctx);
+ break;
+
+ default:
+ DEBUG(5, ("Unknown notification type %d\n", msg->type));
+ goto done;
+ }
+
+ data_len++;
+ }
+
+ if ( sending_msg_count ) {
+ rpccli_spoolss_rrpcn( notify_cli_pipe, mem_ctx, &p->notify.client_hnd,
+ data_len, data, p->notify.change, 0 );
+ }
+ }
+
+done:
+ DEBUG(8,("send_notify2_changes: Exit...\n"));
+ return;
+}
+
+/***********************************************************************
+ **********************************************************************/
+
+static bool notify2_unpack_msg( SPOOLSS_NOTIFY_MSG *msg, struct timeval *tv, void *buf, size_t len )
+{
+
+ uint32 tv_sec, tv_usec;
+ size_t offset = 0;
+
+ /* Unpack message */
+
+ offset += tdb_unpack((uint8 *)buf + offset, len - offset, "f",
+ msg->printer);
+
+ offset += tdb_unpack((uint8 *)buf + offset, len - offset, "ddddddd",
+ &tv_sec, &tv_usec,
+ &msg->type, &msg->field, &msg->id, &msg->len, &msg->flags);
+
+ if (msg->len == 0)
+ tdb_unpack((uint8 *)buf + offset, len - offset, "dd",
+ &msg->notify.value[0], &msg->notify.value[1]);
+ else
+ tdb_unpack((uint8 *)buf + offset, len - offset, "B",
+ &msg->len, &msg->notify.data);
+
+ DEBUG(3, ("notify2_unpack_msg: got NOTIFY2 message for printer %s, jobid %u type %d, field 0x%02x, flags 0x%04x\n",
+ msg->printer, (unsigned int)msg->id, msg->type, msg->field, msg->flags));
+
+ tv->tv_sec = tv_sec;
+ tv->tv_usec = tv_usec;
+
+ if (msg->len == 0)
+ DEBUG(3, ("notify2_unpack_msg: value1 = %d, value2 = %d\n", msg->notify.value[0],
+ msg->notify.value[1]));
+ else
+ dump_data(3, (uint8 *)msg->notify.data, msg->len);
+
+ return True;
+}
+
+/********************************************************************
+ Receive a notify2 message list
+ ********************************************************************/
+
+static void receive_notify2_message_list(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ size_t msg_count, i;
+ char *buf = (char *)data->data;
+ char *msg_ptr;
+ size_t msg_len;
+ SPOOLSS_NOTIFY_MSG notify;
+ SPOOLSS_NOTIFY_MSG_CTR messages;
+ int num_groups;
+
+ if (data->length < 4) {
+ DEBUG(0,("receive_notify2_message_list: bad message format (len < 4)!\n"));
+ return;
+ }
+
+ msg_count = IVAL(buf, 0);
+ msg_ptr = buf + 4;
+
+ DEBUG(5, ("receive_notify2_message_list: got %lu messages in list\n", (unsigned long)msg_count));
+
+ if (msg_count == 0) {
+ DEBUG(0,("receive_notify2_message_list: bad message format (msg_count == 0) !\n"));
+ return;
+ }
+
+ /* initialize the container */
+
+ ZERO_STRUCT( messages );
+ notify_msg_ctr_init( &messages );
+
+ /*
+ * build message groups for each printer identified
+ * in a change_notify msg. Remember that a PCN message
+ * includes the handle returned for the srv_spoolss_replyopenprinter()
+ * call. Therefore messages are grouped according to printer handle.
+ */
+
+ for ( i=0; i<msg_count; i++ ) {
+ struct timeval msg_tv;
+
+ if (msg_ptr + 4 - buf > data->length) {
+ DEBUG(0,("receive_notify2_message_list: bad message format (len > buf_size) !\n"));
+ return;
+ }
+
+ msg_len = IVAL(msg_ptr,0);
+ msg_ptr += 4;
+
+ if (msg_ptr + msg_len - buf > data->length) {
+ DEBUG(0,("receive_notify2_message_list: bad message format (bad len) !\n"));
+ return;
+ }
+
+ /* unpack messages */
+
+ ZERO_STRUCT( notify );
+ notify2_unpack_msg( &notify, &msg_tv, msg_ptr, msg_len );
+ msg_ptr += msg_len;
+
+ /* add to correct list in container */
+
+ notify_msg_ctr_addmsg( &messages, &notify );
+
+ /* free memory that might have been allocated by notify2_unpack_msg() */
+
+ if ( notify.len != 0 )
+ SAFE_FREE( notify.notify.data );
+ }
+
+ /* process each group of messages */
+
+ num_groups = notify_msg_ctr_numgroups( &messages );
+ for ( i=0; i<num_groups; i++ )
+ send_notify2_changes( &messages, i );
+
+
+ /* cleanup */
+
+ DEBUG(10,("receive_notify2_message_list: processed %u messages\n", (uint32)msg_count ));
+
+ notify_msg_ctr_destroy( &messages );
+
+ return;
+}
+
+/********************************************************************
+ Send a message to ourself about new driver being installed
+ so we can upgrade the information for each printer bound to this
+ driver
+ ********************************************************************/
+
+static bool srv_spoolss_drv_upgrade_printer(char* drivername)
+{
+ int len = strlen(drivername);
+
+ if (!len)
+ return False;
+
+ DEBUG(10,("srv_spoolss_drv_upgrade_printer: Sending message about driver upgrade [%s]\n",
+ drivername));
+
+ messaging_send_buf(smbd_messaging_context(), procid_self(),
+ MSG_PRINTER_DRVUPGRADE,
+ (uint8 *)drivername, len+1);
+
+ return True;
+}
+
+/**********************************************************************
+ callback to receive a MSG_PRINTER_DRVUPGRADE message and interate
+ over all printers, upgrading ones as necessary
+ **********************************************************************/
+
+void do_drv_upgrade_printer(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ fstring drivername;
+ int snum;
+ int n_services = lp_numservices();
+ size_t len;
+
+ len = MIN(data->length,sizeof(drivername)-1);
+ strncpy(drivername, (const char *)data->data, len);
+
+ DEBUG(10,("do_drv_upgrade_printer: Got message for new driver [%s]\n", drivername ));
+
+ /* Iterate the printer list */
+
+ for (snum=0; snum<n_services; snum++)
+ {
+ if (lp_snum_ok(snum) && lp_print_ok(snum) )
+ {
+ WERROR result;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+ result = get_a_printer(NULL, &printer, 2, lp_const_servicename(snum));
+ if (!W_ERROR_IS_OK(result))
+ continue;
+
+ if (printer && printer->info_2 && !strcmp(drivername, printer->info_2->drivername))
+ {
+ DEBUG(6,("Updating printer [%s]\n", printer->info_2->printername));
+
+ /* all we care about currently is the change_id */
+
+ result = mod_a_printer(printer, 2);
+ if (!W_ERROR_IS_OK(result)) {
+ DEBUG(3,("do_drv_upgrade_printer: mod_a_printer() failed with status [%s]\n",
+ dos_errstr(result)));
+ }
+ }
+
+ free_a_printer(&printer, 2);
+ }
+ }
+
+ /* all done */
+}
+
+/********************************************************************
+ Update the cache for all printq's with a registered client
+ connection
+ ********************************************************************/
+
+void update_monitored_printq_cache( void )
+{
+ Printer_entry *printer = printers_list;
+ int snum;
+
+ /* loop through all printers and update the cache where
+ client_connected == True */
+ while ( printer )
+ {
+ if ( (printer->printer_type == SPLHND_PRINTER)
+ && printer->notify.client_connected )
+ {
+ snum = print_queue_snum(printer->sharename);
+ print_queue_status( snum, NULL, NULL );
+ }
+
+ printer = printer->next;
+ }
+
+ return;
+}
+/********************************************************************
+ Send a message to ourself about new driver being installed
+ so we can upgrade the information for each printer bound to this
+ driver
+ ********************************************************************/
+
+static bool srv_spoolss_reset_printerdata(char* drivername)
+{
+ int len = strlen(drivername);
+
+ if (!len)
+ return False;
+
+ DEBUG(10,("srv_spoolss_reset_printerdata: Sending message about resetting printerdata [%s]\n",
+ drivername));
+
+ messaging_send_buf(smbd_messaging_context(), procid_self(),
+ MSG_PRINTERDATA_INIT_RESET,
+ (uint8 *)drivername, len+1);
+
+ return True;
+}
+
+/**********************************************************************
+ callback to receive a MSG_PRINTERDATA_INIT_RESET message and interate
+ over all printers, resetting printer data as neessary
+ **********************************************************************/
+
+void reset_all_printerdata(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ fstring drivername;
+ int snum;
+ int n_services = lp_numservices();
+ size_t len;
+
+ len = MIN( data->length, sizeof(drivername)-1 );
+ strncpy( drivername, (const char *)data->data, len );
+
+ DEBUG(10,("reset_all_printerdata: Got message for new driver [%s]\n", drivername ));
+
+ /* Iterate the printer list */
+
+ for ( snum=0; snum<n_services; snum++ )
+ {
+ if ( lp_snum_ok(snum) && lp_print_ok(snum) )
+ {
+ WERROR result;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+ result = get_a_printer( NULL, &printer, 2, lp_const_servicename(snum) );
+ if ( !W_ERROR_IS_OK(result) )
+ continue;
+
+ /*
+ * if the printer is bound to the driver,
+ * then reset to the new driver initdata
+ */
+
+ if ( printer && printer->info_2 && !strcmp(drivername, printer->info_2->drivername) )
+ {
+ DEBUG(6,("reset_all_printerdata: Updating printer [%s]\n", printer->info_2->printername));
+
+ if ( !set_driver_init(printer, 2) ) {
+ DEBUG(5,("reset_all_printerdata: Error resetting printer data for printer [%s], driver [%s]!\n",
+ printer->info_2->printername, printer->info_2->drivername));
+ }
+
+ result = mod_a_printer( printer, 2 );
+ if ( !W_ERROR_IS_OK(result) ) {
+ DEBUG(3,("reset_all_printerdata: mod_a_printer() failed! (%s)\n",
+ get_dos_error_msg(result)));
+ }
+ }
+
+ free_a_printer( &printer, 2 );
+ }
+ }
+
+ /* all done */
+
+ return;
+}
+
+/********************************************************************
+ Copy routines used by convert_to_openprinterex()
+ *******************************************************************/
+
+static DEVICEMODE* dup_devicemode(TALLOC_CTX *ctx, DEVICEMODE *devmode)
+{
+ DEVICEMODE *d;
+ int len;
+
+ if (!devmode)
+ return NULL;
+
+ DEBUG (8,("dup_devmode\n"));
+
+ /* bulk copy first */
+
+ d = (DEVICEMODE *)TALLOC_MEMDUP(ctx, devmode, sizeof(DEVICEMODE));
+ if (!d)
+ return NULL;
+
+ /* dup the pointer members separately */
+
+ len = unistrlen(devmode->devicename.buffer);
+ if (len != -1) {
+ d->devicename.buffer = TALLOC_ARRAY(ctx, uint16, len);
+ if (!d->devicename.buffer) {
+ return NULL;
+ }
+ if (unistrcpy(d->devicename.buffer, devmode->devicename.buffer) != len)
+ return NULL;
+ }
+
+
+ len = unistrlen(devmode->formname.buffer);
+ if (len != -1) {
+ d->formname.buffer = TALLOC_ARRAY(ctx, uint16, len);
+ if (!d->formname.buffer) {
+ return NULL;
+ }
+ if (unistrcpy(d->formname.buffer, devmode->formname.buffer) != len)
+ return NULL;
+ }
+
+ if (devmode->driverextra) {
+ d->dev_private = (uint8 *)TALLOC_MEMDUP(ctx, devmode->dev_private,
+ devmode->driverextra);
+ if (!d->dev_private) {
+ return NULL;
+ }
+ } else {
+ d->dev_private = NULL;
+ }
+ return d;
+}
+
+static void copy_devmode_ctr(TALLOC_CTX *ctx, DEVMODE_CTR *new_ctr, DEVMODE_CTR *ctr)
+{
+ if (!new_ctr || !ctr)
+ return;
+
+ DEBUG(8,("copy_devmode_ctr\n"));
+
+ new_ctr->size = ctr->size;
+ new_ctr->devmode_ptr = ctr->devmode_ptr;
+
+ if(ctr->devmode_ptr)
+ new_ctr->devmode = dup_devicemode(ctx, ctr->devmode);
+}
+
+static void copy_printer_default(TALLOC_CTX *ctx, PRINTER_DEFAULT *new_def, PRINTER_DEFAULT *def)
+{
+ if (!new_def || !def)
+ return;
+
+ DEBUG(8,("copy_printer_defaults\n"));
+
+ new_def->datatype_ptr = def->datatype_ptr;
+
+ if (def->datatype_ptr)
+ copy_unistr2(&new_def->datatype, &def->datatype);
+
+ copy_devmode_ctr(ctx, &new_def->devmode_cont, &def->devmode_cont);
+
+ new_def->access_required = def->access_required;
+}
+
+/********************************************************************
+ * Convert a SPOOL_Q_OPEN_PRINTER structure to a
+ * SPOOL_Q_OPEN_PRINTER_EX structure
+ ********************************************************************/
+
+static WERROR convert_to_openprinterex(TALLOC_CTX *ctx, SPOOL_Q_OPEN_PRINTER_EX *q_u_ex, SPOOL_Q_OPEN_PRINTER *q_u)
+{
+ if (!q_u_ex || !q_u)
+ return WERR_OK;
+
+ DEBUG(8,("convert_to_openprinterex\n"));
+
+ if ( q_u->printername ) {
+ q_u_ex->printername = TALLOC_ZERO_P( ctx, UNISTR2 );
+ if (q_u_ex->printername == NULL)
+ return WERR_NOMEM;
+ copy_unistr2(q_u_ex->printername, q_u->printername);
+ }
+
+ copy_printer_default(ctx, &q_u_ex->printer_default, &q_u->printer_default);
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * spoolss_open_printer
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+WERROR _spoolss_open_printer(pipes_struct *p, SPOOL_Q_OPEN_PRINTER *q_u, SPOOL_R_OPEN_PRINTER *r_u)
+{
+ SPOOL_Q_OPEN_PRINTER_EX q_u_ex;
+ SPOOL_R_OPEN_PRINTER_EX r_u_ex;
+
+ if (!q_u || !r_u)
+ return WERR_NOMEM;
+
+ ZERO_STRUCT(q_u_ex);
+ ZERO_STRUCT(r_u_ex);
+
+ /* convert the OpenPrinter() call to OpenPrinterEx() */
+
+ r_u_ex.status = convert_to_openprinterex(p->mem_ctx, &q_u_ex, q_u);
+ if (!W_ERROR_IS_OK(r_u_ex.status))
+ return r_u_ex.status;
+
+ r_u_ex.status = _spoolss_open_printer_ex(p, &q_u_ex, &r_u_ex);
+
+ /* convert back to OpenPrinter() */
+
+ memcpy(r_u, &r_u_ex, sizeof(*r_u));
+
+ if (W_ERROR_EQUAL(r_u->status, WERR_INVALID_PARAM)) {
+ /* OpenPrinterEx returns this for a bad
+ * printer name. We must return WERR_INVALID_PRINTER_NAME
+ * instead.
+ */
+ r_u->status = WERR_INVALID_PRINTER_NAME;
+ }
+ return r_u->status;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _spoolss_open_printer_ex( pipes_struct *p, SPOOL_Q_OPEN_PRINTER_EX *q_u, SPOOL_R_OPEN_PRINTER_EX *r_u)
+{
+ PRINTER_DEFAULT *printer_default = &q_u->printer_default;
+ POLICY_HND *handle = &r_u->handle;
+
+ fstring name;
+ int snum;
+ Printer_entry *Printer=NULL;
+
+ if (!q_u->printername) {
+ return WERR_INVALID_PARAM;
+ }
+
+ /* some sanity check because you can open a printer or a print server */
+ /* aka: \\server\printer or \\server */
+
+ unistr2_to_ascii(name, q_u->printername, sizeof(name));
+
+ DEBUGADD(3,("checking name: %s\n",name));
+
+ if (!open_printer_hnd(p, handle, name, 0)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ Printer=find_printer_index_by_hnd(p, handle);
+ if ( !Printer ) {
+ DEBUG(0,(" _spoolss_open_printer_ex: logic error. Can't find printer "
+ "handle we created for printer %s\n", name ));
+ close_printer_handle(p,handle);
+ return WERR_INVALID_PARAM;
+ }
+
+ /*
+ * First case: the user is opening the print server:
+ *
+ * Disallow MS AddPrinterWizard if parameter disables it. A Win2k
+ * client 1st tries an OpenPrinterEx with access==0, MUST be allowed.
+ *
+ * Then both Win2k and WinNT clients try an OpenPrinterEx with
+ * SERVER_ALL_ACCESS, which we allow only if the user is root (uid=0)
+ * or if the user is listed in the smb.conf printer admin parameter.
+ *
+ * Then they try OpenPrinterEx with SERVER_READ which we allow. This lets the
+ * client view printer folder, but does not show the MSAPW.
+ *
+ * Note: this test needs code to check access rights here too. Jeremy
+ * could you look at this?
+ *
+ * Second case: the user is opening a printer:
+ * NT doesn't let us connect to a printer if the connecting user
+ * doesn't have print permission.
+ *
+ * Third case: user is opening a Port Monitor
+ * access checks same as opening a handle to the print server.
+ */
+
+ switch (Printer->printer_type )
+ {
+ case SPLHND_SERVER:
+ case SPLHND_PORTMON_TCP:
+ case SPLHND_PORTMON_LOCAL:
+ /* Printserver handles use global struct... */
+
+ snum = -1;
+
+ /* Map standard access rights to object specific access rights */
+
+ se_map_standard(&printer_default->access_required,
+ &printserver_std_mapping);
+
+ /* Deny any object specific bits that don't apply to print
+ servers (i.e printer and job specific bits) */
+
+ printer_default->access_required &= SPECIFIC_RIGHTS_MASK;
+
+ if (printer_default->access_required &
+ ~(SERVER_ACCESS_ADMINISTER | SERVER_ACCESS_ENUMERATE)) {
+ DEBUG(3, ("access DENIED for non-printserver bits\n"));
+ close_printer_handle(p, handle);
+ return WERR_ACCESS_DENIED;
+ }
+
+ /* Allow admin access */
+
+ if ( printer_default->access_required & SERVER_ACCESS_ADMINISTER )
+ {
+ SE_PRIV se_printop = SE_PRINT_OPERATOR;
+
+ if (!lp_ms_add_printer_wizard()) {
+ close_printer_handle(p, handle);
+ return WERR_ACCESS_DENIED;
+ }
+
+ /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege,
+ and not a printer admin, then fail */
+
+ if ((p->pipe_user.ut.uid != 0) &&
+ !user_has_privileges(p->pipe_user.nt_user_token,
+ &se_printop ) &&
+ !token_contains_name_in_list(
+ uidtoname(p->pipe_user.ut.uid),
+ NULL, NULL,
+ p->pipe_user.nt_user_token,
+ lp_printer_admin(snum))) {
+ close_printer_handle(p, handle);
+ return WERR_ACCESS_DENIED;
+ }
+
+ printer_default->access_required = SERVER_ACCESS_ADMINISTER;
+ }
+ else
+ {
+ printer_default->access_required = SERVER_ACCESS_ENUMERATE;
+ }
+
+ DEBUG(4,("Setting print server access = %s\n", (printer_default->access_required == SERVER_ACCESS_ADMINISTER)
+ ? "SERVER_ACCESS_ADMINISTER" : "SERVER_ACCESS_ENUMERATE" ));
+
+ /* We fall through to return WERR_OK */
+ break;
+
+ case SPLHND_PRINTER:
+ /* NT doesn't let us connect to a printer if the connecting user
+ doesn't have print permission. */
+
+ if (!get_printer_snum(p, handle, &snum, NULL)) {
+ close_printer_handle(p, handle);
+ return WERR_BADFID;
+ }
+
+ se_map_standard(&printer_default->access_required, &printer_std_mapping);
+
+ /* map an empty access mask to the minimum access mask */
+ if (printer_default->access_required == 0x0)
+ printer_default->access_required = PRINTER_ACCESS_USE;
+
+ /*
+ * If we are not serving the printer driver for this printer,
+ * map PRINTER_ACCESS_ADMINISTER to PRINTER_ACCESS_USE. This
+ * will keep NT clients happy --jerry
+ */
+
+ if (lp_use_client_driver(snum)
+ && (printer_default->access_required & PRINTER_ACCESS_ADMINISTER))
+ {
+ printer_default->access_required = PRINTER_ACCESS_USE;
+ }
+
+ /* check smb.conf parameters and the the sec_desc */
+
+ if ( !check_access(smbd_server_fd(), lp_hostsallow(snum), lp_hostsdeny(snum)) ) {
+ DEBUG(3, ("access DENIED (hosts allow/deny) for printer open\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ if (!user_ok_token(uidtoname(p->pipe_user.ut.uid), NULL,
+ p->pipe_user.nt_user_token, snum) ||
+ !print_access_check(p->server_info, snum,
+ printer_default->access_required)) {
+ DEBUG(3, ("access DENIED for printer open\n"));
+ close_printer_handle(p, handle);
+ return WERR_ACCESS_DENIED;
+ }
+
+ if ((printer_default->access_required & SPECIFIC_RIGHTS_MASK)& ~(PRINTER_ACCESS_ADMINISTER|PRINTER_ACCESS_USE)) {
+ DEBUG(3, ("access DENIED for printer open - unknown bits\n"));
+ close_printer_handle(p, handle);
+ return WERR_ACCESS_DENIED;
+ }
+
+ if (printer_default->access_required & PRINTER_ACCESS_ADMINISTER)
+ printer_default->access_required = PRINTER_ACCESS_ADMINISTER;
+ else
+ printer_default->access_required = PRINTER_ACCESS_USE;
+
+ DEBUG(4,("Setting printer access = %s\n", (printer_default->access_required == PRINTER_ACCESS_ADMINISTER)
+ ? "PRINTER_ACCESS_ADMINISTER" : "PRINTER_ACCESS_USE" ));
+
+ break;
+
+ default:
+ /* sanity check to prevent programmer error */
+ return WERR_BADFID;
+ }
+
+ Printer->access_granted = printer_default->access_required;
+
+ /*
+ * If the client sent a devmode in the OpenPrinter() call, then
+ * save it here in case we get a job submission on this handle
+ */
+
+ if ( (Printer->printer_type != SPLHND_SERVER)
+ && q_u->printer_default.devmode_cont.devmode_ptr )
+ {
+ convert_devicemode( Printer->sharename, q_u->printer_default.devmode_cont.devmode,
+ &Printer->nt_devmode );
+ }
+
+#if 0 /* JERRY -- I'm doubtful this is really effective */
+ /* HACK ALERT!!! Sleep for 1/3 of a second to try trigger a LAN/WAN
+ optimization in Windows 2000 clients --jerry */
+
+ if ( (printer_default->access_required == PRINTER_ACCESS_ADMINISTER)
+ && (RA_WIN2K == get_remote_arch()) )
+ {
+ DEBUG(10,("_spoolss_open_printer_ex: Enabling LAN/WAN hack for Win2k clients.\n"));
+ sys_usleep( 500000 );
+ }
+#endif
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool convert_printer_info(const SPOOL_PRINTER_INFO_LEVEL *uni,
+ NT_PRINTER_INFO_LEVEL *printer, uint32 level)
+{
+ bool ret;
+
+ switch (level) {
+ case 2:
+ /* allocate memory if needed. Messy because
+ convert_printer_info is used to update an existing
+ printer or build a new one */
+
+ if ( !printer->info_2 ) {
+ printer->info_2 = TALLOC_ZERO_P( printer, NT_PRINTER_INFO_LEVEL_2 );
+ if ( !printer->info_2 ) {
+ DEBUG(0,("convert_printer_info: talloc() failed!\n"));
+ return False;
+ }
+ }
+
+ ret = uni_2_asc_printer_info_2(uni->info_2, printer->info_2);
+ printer->info_2->setuptime = time(NULL);
+
+ return ret;
+ }
+
+ return False;
+}
+
+static bool convert_printer_driver_info(const SPOOL_PRINTER_DRIVER_INFO_LEVEL *uni,
+ NT_PRINTER_DRIVER_INFO_LEVEL *printer, uint32 level)
+{
+ bool result = True;
+
+ switch (level) {
+ case 3:
+ printer->info_3=NULL;
+ if (!uni_2_asc_printer_driver_3(uni->info_3, &printer->info_3))
+ result = False;
+ break;
+ case 6:
+ printer->info_6=NULL;
+ if (!uni_2_asc_printer_driver_6(uni->info_6, &printer->info_6))
+ result = False;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+bool convert_devicemode(const char *printername, const DEVICEMODE *devmode,
+ NT_DEVICEMODE **pp_nt_devmode)
+{
+ NT_DEVICEMODE *nt_devmode = *pp_nt_devmode;
+
+ /*
+ * Ensure nt_devmode is a valid pointer
+ * as we will be overwriting it.
+ */
+
+ if (nt_devmode == NULL) {
+ DEBUG(5, ("convert_devicemode: allocating a generic devmode\n"));
+ if ((nt_devmode = construct_nt_devicemode(printername)) == NULL)
+ return False;
+ }
+
+ rpcstr_pull(nt_devmode->devicename,devmode->devicename.buffer, 31, -1, 0);
+ rpcstr_pull(nt_devmode->formname,devmode->formname.buffer, 31, -1, 0);
+
+ nt_devmode->specversion=devmode->specversion;
+ nt_devmode->driverversion=devmode->driverversion;
+ nt_devmode->size=devmode->size;
+ nt_devmode->fields=devmode->fields;
+ nt_devmode->orientation=devmode->orientation;
+ nt_devmode->papersize=devmode->papersize;
+ nt_devmode->paperlength=devmode->paperlength;
+ nt_devmode->paperwidth=devmode->paperwidth;
+ nt_devmode->scale=devmode->scale;
+ nt_devmode->copies=devmode->copies;
+ nt_devmode->defaultsource=devmode->defaultsource;
+ nt_devmode->printquality=devmode->printquality;
+ nt_devmode->color=devmode->color;
+ nt_devmode->duplex=devmode->duplex;
+ nt_devmode->yresolution=devmode->yresolution;
+ nt_devmode->ttoption=devmode->ttoption;
+ nt_devmode->collate=devmode->collate;
+
+ nt_devmode->logpixels=devmode->logpixels;
+ nt_devmode->bitsperpel=devmode->bitsperpel;
+ nt_devmode->pelswidth=devmode->pelswidth;
+ nt_devmode->pelsheight=devmode->pelsheight;
+ nt_devmode->displayflags=devmode->displayflags;
+ nt_devmode->displayfrequency=devmode->displayfrequency;
+ nt_devmode->icmmethod=devmode->icmmethod;
+ nt_devmode->icmintent=devmode->icmintent;
+ nt_devmode->mediatype=devmode->mediatype;
+ nt_devmode->dithertype=devmode->dithertype;
+ nt_devmode->reserved1=devmode->reserved1;
+ nt_devmode->reserved2=devmode->reserved2;
+ nt_devmode->panningwidth=devmode->panningwidth;
+ nt_devmode->panningheight=devmode->panningheight;
+
+ /*
+ * Only change private and driverextra if the incoming devmode
+ * has a new one. JRA.
+ */
+
+ if ((devmode->driverextra != 0) && (devmode->dev_private != NULL)) {
+ SAFE_FREE(nt_devmode->nt_dev_private);
+ nt_devmode->driverextra=devmode->driverextra;
+ if((nt_devmode->nt_dev_private=SMB_MALLOC_ARRAY(uint8, nt_devmode->driverextra)) == NULL)
+ return False;
+ memcpy(nt_devmode->nt_dev_private, devmode->dev_private, nt_devmode->driverextra);
+ }
+
+ *pp_nt_devmode = nt_devmode;
+
+ return True;
+}
+
+/********************************************************************
+ * _spoolss_enddocprinter_internal.
+ ********************************************************************/
+
+static WERROR _spoolss_enddocprinter_internal(pipes_struct *p, POLICY_HND *handle)
+{
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+ int snum;
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_enddocprinter_internal: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if (!get_printer_snum(p, handle, &snum, NULL))
+ return WERR_BADFID;
+
+ Printer->document_started=False;
+ print_job_end(snum, Printer->jobid,NORMAL_CLOSE);
+ /* error codes unhandled so far ... */
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * api_spoolss_closeprinter
+ ********************************************************************/
+
+WERROR _spoolss_closeprinter(pipes_struct *p, SPOOL_Q_CLOSEPRINTER *q_u, SPOOL_R_CLOSEPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+
+ if (Printer && Printer->document_started)
+ _spoolss_enddocprinter_internal(p, handle); /* print job was not closed */
+
+ if (!close_printer_handle(p, handle))
+ return WERR_BADFID;
+
+ /* clear the returned printer handle. Observed behavior
+ from Win2k server. Don't think this really matters.
+ Previous code just copied the value of the closed
+ handle. --jerry */
+
+ memset(&r_u->handle, '\0', sizeof(r_u->handle));
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * api_spoolss_deleteprinter
+
+ ********************************************************************/
+
+WERROR _spoolss_deleteprinter(pipes_struct *p, SPOOL_Q_DELETEPRINTER *q_u, SPOOL_R_DELETEPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+ WERROR result;
+
+ if (Printer && Printer->document_started)
+ _spoolss_enddocprinter_internal(p, handle); /* print job was not closed */
+
+ memcpy(&r_u->handle, &q_u->handle, sizeof(r_u->handle));
+
+ result = delete_printer_handle(p, handle);
+
+ update_c_setprinter(False);
+
+ return result;
+}
+
+/*******************************************************************
+ * static function to lookup the version id corresponding to an
+ * long architecture string
+ ******************************************************************/
+
+static int get_version_id (char * arch)
+{
+ int i;
+ struct table_node archi_table[]= {
+
+ {"Windows 4.0", "WIN40", 0 },
+ {"Windows NT x86", "W32X86", 2 },
+ {"Windows NT R4000", "W32MIPS", 2 },
+ {"Windows NT Alpha_AXP", "W32ALPHA", 2 },
+ {"Windows NT PowerPC", "W32PPC", 2 },
+ {"Windows IA64", "IA64", 3 },
+ {"Windows x64", "x64", 3 },
+ {NULL, "", -1 }
+ };
+
+ for (i=0; archi_table[i].long_archi != NULL; i++)
+ {
+ if (strcmp(arch, archi_table[i].long_archi) == 0)
+ return (archi_table[i].version);
+ }
+
+ return -1;
+}
+
+/********************************************************************
+ * _spoolss_deleteprinterdriver
+ ********************************************************************/
+
+WERROR _spoolss_deleteprinterdriver(pipes_struct *p, SPOOL_Q_DELETEPRINTERDRIVER *q_u, SPOOL_R_DELETEPRINTERDRIVER *r_u)
+{
+ fstring driver;
+ fstring arch;
+ NT_PRINTER_DRIVER_INFO_LEVEL info;
+ NT_PRINTER_DRIVER_INFO_LEVEL info_win2k;
+ int version;
+ WERROR status;
+ WERROR status_win2k = WERR_ACCESS_DENIED;
+ SE_PRIV se_printop = SE_PRINT_OPERATOR;
+
+ /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege,
+ and not a printer admin, then fail */
+
+ if ( (p->pipe_user.ut.uid != 0)
+ && !user_has_privileges(p->pipe_user.nt_user_token, &se_printop )
+ && !token_contains_name_in_list(
+ uidtoname(p->pipe_user.ut.uid), NULL,
+ NULL, p->pipe_user.nt_user_token,
+ lp_printer_admin(-1)) )
+ {
+ return WERR_ACCESS_DENIED;
+ }
+
+ unistr2_to_ascii(driver, &q_u->driver, sizeof(driver));
+ unistr2_to_ascii(arch, &q_u->arch, sizeof(arch));
+
+ /* check that we have a valid driver name first */
+
+ if ((version=get_version_id(arch)) == -1)
+ return WERR_INVALID_ENVIRONMENT;
+
+ ZERO_STRUCT(info);
+ ZERO_STRUCT(info_win2k);
+
+ if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, driver, arch, version)))
+ {
+ /* try for Win2k driver if "Windows NT x86" */
+
+ if ( version == 2 ) {
+ version = 3;
+ if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, driver, arch, version))) {
+ status = WERR_UNKNOWN_PRINTER_DRIVER;
+ goto done;
+ }
+ }
+ /* otherwise it was a failure */
+ else {
+ status = WERR_UNKNOWN_PRINTER_DRIVER;
+ goto done;
+ }
+
+ }
+
+ if (printer_driver_in_use(info.info_3)) {
+ status = WERR_PRINTER_DRIVER_IN_USE;
+ goto done;
+ }
+
+ if ( version == 2 )
+ {
+ if (W_ERROR_IS_OK(get_a_printer_driver(&info_win2k, 3, driver, arch, 3)))
+ {
+ /* if we get to here, we now have 2 driver info structures to remove */
+ /* remove the Win2k driver first*/
+
+ status_win2k = delete_printer_driver(info_win2k.info_3, &p->pipe_user, 3, False );
+ free_a_printer_driver( info_win2k, 3 );
+
+ /* this should not have failed---if it did, report to client */
+ if ( !W_ERROR_IS_OK(status_win2k) )
+ {
+ status = status_win2k;
+ goto done;
+ }
+ }
+ }
+
+ status = delete_printer_driver(info.info_3, &p->pipe_user, version, False);
+
+ /* if at least one of the deletes succeeded return OK */
+
+ if ( W_ERROR_IS_OK(status) || W_ERROR_IS_OK(status_win2k) )
+ status = WERR_OK;
+
+done:
+ free_a_printer_driver( info, 3 );
+
+ return status;
+}
+
+/********************************************************************
+ * spoolss_deleteprinterdriverex
+ ********************************************************************/
+
+WERROR _spoolss_deleteprinterdriverex(pipes_struct *p, SPOOL_Q_DELETEPRINTERDRIVEREX *q_u, SPOOL_R_DELETEPRINTERDRIVEREX *r_u)
+{
+ fstring driver;
+ fstring arch;
+ NT_PRINTER_DRIVER_INFO_LEVEL info;
+ NT_PRINTER_DRIVER_INFO_LEVEL info_win2k;
+ int version;
+ uint32 flags = q_u->delete_flags;
+ bool delete_files;
+ WERROR status;
+ WERROR status_win2k = WERR_ACCESS_DENIED;
+ SE_PRIV se_printop = SE_PRINT_OPERATOR;
+
+ /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege,
+ and not a printer admin, then fail */
+
+ if ( (p->pipe_user.ut.uid != 0)
+ && !user_has_privileges(p->pipe_user.nt_user_token, &se_printop )
+ && !token_contains_name_in_list(
+ uidtoname(p->pipe_user.ut.uid), NULL, NULL,
+ p->pipe_user.nt_user_token, lp_printer_admin(-1)) )
+ {
+ return WERR_ACCESS_DENIED;
+ }
+
+ unistr2_to_ascii(driver, &q_u->driver, sizeof(driver));
+ unistr2_to_ascii(arch, &q_u->arch, sizeof(arch));
+
+ /* check that we have a valid driver name first */
+ if ((version=get_version_id(arch)) == -1) {
+ /* this is what NT returns */
+ return WERR_INVALID_ENVIRONMENT;
+ }
+
+ if ( flags & DPD_DELETE_SPECIFIC_VERSION )
+ version = q_u->version;
+
+ ZERO_STRUCT(info);
+ ZERO_STRUCT(info_win2k);
+
+ status = get_a_printer_driver(&info, 3, driver, arch, version);
+
+ if ( !W_ERROR_IS_OK(status) )
+ {
+ /*
+ * if the client asked for a specific version,
+ * or this is something other than Windows NT x86,
+ * then we've failed
+ */
+
+ if ( (flags&DPD_DELETE_SPECIFIC_VERSION) || (version !=2) )
+ goto done;
+
+ /* try for Win2k driver if "Windows NT x86" */
+
+ version = 3;
+ if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, driver, arch, version))) {
+ status = WERR_UNKNOWN_PRINTER_DRIVER;
+ goto done;
+ }
+ }
+
+ if ( printer_driver_in_use(info.info_3) ) {
+ status = WERR_PRINTER_DRIVER_IN_USE;
+ goto done;
+ }
+
+ /*
+ * we have a couple of cases to consider.
+ * (1) Are any files in use? If so and DPD_DELTE_ALL_FILE is set,
+ * then the delete should fail if **any** files overlap with
+ * other drivers
+ * (2) If DPD_DELTE_UNUSED_FILES is sert, then delete all
+ * non-overlapping files
+ * (3) If neither DPD_DELTE_ALL_FILE nor DPD_DELTE_ALL_FILES
+ * is set, the do not delete any files
+ * Refer to MSDN docs on DeletePrinterDriverEx() for details.
+ */
+
+ delete_files = flags & (DPD_DELETE_ALL_FILES|DPD_DELETE_UNUSED_FILES);
+
+ /* fail if any files are in use and DPD_DELETE_ALL_FILES is set */
+
+ if ( delete_files && printer_driver_files_in_use(info.info_3) & (flags&DPD_DELETE_ALL_FILES) ) {
+ /* no idea of the correct error here */
+ status = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+
+ /* also check for W32X86/3 if necessary; maybe we already have? */
+
+ if ( (version == 2) && ((flags&DPD_DELETE_SPECIFIC_VERSION) != DPD_DELETE_SPECIFIC_VERSION) ) {
+ if (W_ERROR_IS_OK(get_a_printer_driver(&info_win2k, 3, driver, arch, 3)))
+ {
+
+ if ( delete_files && printer_driver_files_in_use(info_win2k.info_3) & (flags&DPD_DELETE_ALL_FILES) ) {
+ /* no idea of the correct error here */
+ free_a_printer_driver( info_win2k, 3 );
+ status = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ /* if we get to here, we now have 2 driver info structures to remove */
+ /* remove the Win2k driver first*/
+
+ status_win2k = delete_printer_driver(info_win2k.info_3, &p->pipe_user, 3, delete_files);
+ free_a_printer_driver( info_win2k, 3 );
+
+ /* this should not have failed---if it did, report to client */
+
+ if ( !W_ERROR_IS_OK(status_win2k) )
+ goto done;
+ }
+ }
+
+ status = delete_printer_driver(info.info_3, &p->pipe_user, version, delete_files);
+
+ if ( W_ERROR_IS_OK(status) || W_ERROR_IS_OK(status_win2k) )
+ status = WERR_OK;
+done:
+ free_a_printer_driver( info, 3 );
+
+ return status;
+}
+
+
+/****************************************************************************
+ Internal routine for retreiving printerdata
+ ***************************************************************************/
+
+static WERROR get_printer_dataex( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL *printer,
+ const char *key, const char *value, uint32 *type, uint8 **data,
+ uint32 *needed, uint32 in_size )
+{
+ REGISTRY_VALUE *val;
+ uint32 size;
+ int data_len;
+
+ if ( !(val = get_printer_data( printer->info_2, key, value)) )
+ return WERR_BADFILE;
+
+ *type = regval_type( val );
+
+ DEBUG(5,("get_printer_dataex: allocating %d\n", in_size));
+
+ size = regval_size( val );
+
+ /* copy the min(in_size, len) */
+
+ if ( in_size ) {
+ data_len = (size > in_size) ? in_size : size*sizeof(uint8);
+
+ /* special case for 0 length values */
+ if ( data_len ) {
+ if ( (*data = (uint8 *)TALLOC_MEMDUP(ctx, regval_data_p(val), data_len)) == NULL )
+ return WERR_NOMEM;
+ }
+ else {
+ if ( (*data = (uint8 *)TALLOC_ZERO(ctx, in_size)) == NULL )
+ return WERR_NOMEM;
+ }
+ }
+ else
+ *data = NULL;
+
+ *needed = size;
+
+ DEBUG(5,("get_printer_dataex: copy done\n"));
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ Internal routine for removing printerdata
+ ***************************************************************************/
+
+static WERROR delete_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, const char *key, const char *value )
+{
+ return delete_printer_data( printer->info_2, key, value );
+}
+
+/****************************************************************************
+ Internal routine for storing printerdata
+ ***************************************************************************/
+
+WERROR set_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, const char *key, const char *value,
+ uint32 type, uint8 *data, int real_len )
+{
+ /* the registry objects enforce uniqueness based on value name */
+
+ return add_printer_data( printer->info_2, key, value, type, data, real_len );
+}
+
+/********************************************************************
+ GetPrinterData on a printer server Handle.
+********************************************************************/
+
+static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint32 *type, uint8 **data, uint32 *needed, uint32 in_size)
+{
+ int i;
+
+ DEBUG(8,("getprinterdata_printer_server:%s\n", value));
+
+ if (!StrCaseCmp(value, "W3SvcInstalled")) {
+ *type = REG_DWORD;
+ if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
+ return WERR_NOMEM;
+ SIVAL(*data, 0, 0x00);
+ *needed = 0x4;
+ return WERR_OK;
+ }
+
+ if (!StrCaseCmp(value, "BeepEnabled")) {
+ *type = REG_DWORD;
+ if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
+ return WERR_NOMEM;
+ SIVAL(*data, 0, 0x00);
+ *needed = 0x4;
+ return WERR_OK;
+ }
+
+ if (!StrCaseCmp(value, "EventLog")) {
+ *type = REG_DWORD;
+ if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
+ return WERR_NOMEM;
+ /* formally was 0x1b */
+ SIVAL(*data, 0, 0x0);
+ *needed = 0x4;
+ return WERR_OK;
+ }
+
+ if (!StrCaseCmp(value, "NetPopup")) {
+ *type = REG_DWORD;
+ if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
+ return WERR_NOMEM;
+ SIVAL(*data, 0, 0x00);
+ *needed = 0x4;
+ return WERR_OK;
+ }
+
+ if (!StrCaseCmp(value, "MajorVersion")) {
+ *type = REG_DWORD;
+ if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
+ return WERR_NOMEM;
+
+ /* Windows NT 4.0 seems to not allow uploading of drivers
+ to a server that reports 0x3 as the MajorVersion.
+ need to investigate more how Win2k gets around this .
+ -- jerry */
+
+ if ( RA_WINNT == get_remote_arch() )
+ SIVAL(*data, 0, 2);
+ else
+ SIVAL(*data, 0, 3);
+
+ *needed = 0x4;
+ return WERR_OK;
+ }
+
+ if (!StrCaseCmp(value, "MinorVersion")) {
+ *type = REG_DWORD;
+ if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
+ return WERR_NOMEM;
+ SIVAL(*data, 0, 0);
+ *needed = 0x4;
+ return WERR_OK;
+ }
+
+ /* REG_BINARY
+ * uint32 size = 0x114
+ * uint32 major = 5
+ * uint32 minor = [0|1]
+ * uint32 build = [2195|2600]
+ * extra unicode string = e.g. "Service Pack 3"
+ */
+ if (!StrCaseCmp(value, "OSVersion")) {
+ *type = REG_BINARY;
+ *needed = 0x114;
+
+ if ( !(*data = TALLOC_ZERO_ARRAY(ctx, uint8, (*needed > in_size) ? *needed:in_size )) )
+ return WERR_NOMEM;
+
+ SIVAL(*data, 0, *needed); /* size */
+ SIVAL(*data, 4, 5); /* Windows 2000 == 5.0 */
+ SIVAL(*data, 8, 0);
+ SIVAL(*data, 12, 2195); /* build */
+
+ /* leave extra string empty */
+
+ return WERR_OK;
+ }
+
+
+ if (!StrCaseCmp(value, "DefaultSpoolDirectory")) {
+ const char *string="C:\\PRINTERS";
+ *type = REG_SZ;
+ *needed = 2*(strlen(string)+1);
+ if((*data = (uint8 *)TALLOC(ctx, (*needed > in_size) ? *needed:in_size )) == NULL)
+ return WERR_NOMEM;
+ memset(*data, 0, (*needed > in_size) ? *needed:in_size);
+
+ /* it's done by hand ready to go on the wire */
+ for (i=0; i<strlen(string); i++) {
+ (*data)[2*i]=string[i];
+ (*data)[2*i+1]='\0';
+ }
+ return WERR_OK;
+ }
+
+ if (!StrCaseCmp(value, "Architecture")) {
+ const char *string="Windows NT x86";
+ *type = REG_SZ;
+ *needed = 2*(strlen(string)+1);
+ if((*data = (uint8 *)TALLOC(ctx, (*needed > in_size) ? *needed:in_size )) == NULL)
+ return WERR_NOMEM;
+ memset(*data, 0, (*needed > in_size) ? *needed:in_size);
+ for (i=0; i<strlen(string); i++) {
+ (*data)[2*i]=string[i];
+ (*data)[2*i+1]='\0';
+ }
+ return WERR_OK;
+ }
+
+ if (!StrCaseCmp(value, "DsPresent")) {
+ *type = REG_DWORD;
+ if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
+ return WERR_NOMEM;
+
+ /* only show the publish check box if we are a
+ memeber of a AD domain */
+
+ if ( lp_security() == SEC_ADS )
+ SIVAL(*data, 0, 0x01);
+ else
+ SIVAL(*data, 0, 0x00);
+
+ *needed = 0x4;
+ return WERR_OK;
+ }
+
+ if (!StrCaseCmp(value, "DNSMachineName")) {
+ const char *hostname = get_mydnsfullname();
+
+ if (!hostname)
+ return WERR_BADFILE;
+ *type = REG_SZ;
+ *needed = 2*(strlen(hostname)+1);
+ if((*data = (uint8 *)TALLOC(ctx, (*needed > in_size) ? *needed:in_size )) == NULL)
+ return WERR_NOMEM;
+ memset(*data, 0, (*needed > in_size) ? *needed:in_size);
+ for (i=0; i<strlen(hostname); i++) {
+ (*data)[2*i]=hostname[i];
+ (*data)[2*i+1]='\0';
+ }
+ return WERR_OK;
+ }
+
+
+ return WERR_BADFILE;
+}
+
+/********************************************************************
+ * spoolss_getprinterdata
+ ********************************************************************/
+
+WERROR _spoolss_getprinterdata(pipes_struct *p, SPOOL_Q_GETPRINTERDATA *q_u, SPOOL_R_GETPRINTERDATA *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ UNISTR2 *valuename = &q_u->valuename;
+ uint32 in_size = q_u->size;
+ uint32 *type = &r_u->type;
+ uint32 *out_size = &r_u->size;
+ uint8 **data = &r_u->data;
+ uint32 *needed = &r_u->needed;
+ WERROR status;
+ fstring value;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ int snum = 0;
+
+ /*
+ * Reminder: when it's a string, the length is in BYTES
+ * even if UNICODE is negociated.
+ *
+ * JFM, 4/19/1999
+ */
+
+ *out_size = in_size;
+
+ /* in case of problem, return some default values */
+
+ *needed = 0;
+ *type = 0;
+
+ DEBUG(4,("_spoolss_getprinterdata\n"));
+
+ if ( !Printer ) {
+ DEBUG(2,("_spoolss_getprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+ status = WERR_BADFID;
+ goto done;
+ }
+
+ unistr2_to_ascii(value, valuename, sizeof(value));
+
+ if ( Printer->printer_type == SPLHND_SERVER )
+ status = getprinterdata_printer_server( p->mem_ctx, value, type, data, needed, *out_size );
+ else
+ {
+ if ( !get_printer_snum(p,handle, &snum, NULL) ) {
+ status = WERR_BADFID;
+ goto done;
+ }
+
+ status = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
+ if ( !W_ERROR_IS_OK(status) )
+ goto done;
+
+ /* XP sends this and wants to change id value from the PRINTER_INFO_0 */
+
+ if ( strequal(value, "ChangeId") ) {
+ *type = REG_DWORD;
+ *needed = sizeof(uint32);
+ if ( (*data = (uint8*)TALLOC(p->mem_ctx, sizeof(uint32))) == NULL) {
+ status = WERR_NOMEM;
+ goto done;
+ }
+ SIVAL( *data, 0, printer->info_2->changeid );
+ status = WERR_OK;
+ }
+ else
+ status = get_printer_dataex( p->mem_ctx, printer, SPOOL_PRINTERDATA_KEY, value, type, data, needed, *out_size );
+ }
+
+ if (*needed > *out_size)
+ status = WERR_MORE_DATA;
+
+done:
+ if ( !W_ERROR_IS_OK(status) )
+ {
+ DEBUG(5, ("error %d: allocating %d\n", W_ERROR_V(status),*out_size));
+
+ /* reply this param doesn't exist */
+
+ if ( *out_size ) {
+ if((*data=(uint8 *)TALLOC_ZERO_ARRAY(p->mem_ctx, uint8, *out_size)) == NULL) {
+ if ( printer )
+ free_a_printer( &printer, 2 );
+ return WERR_NOMEM;
+ }
+ } else {
+ *data = NULL;
+ }
+ }
+
+ /* cleanup & exit */
+
+ if ( printer )
+ free_a_printer( &printer, 2 );
+
+ return status;
+}
+
+/*********************************************************
+ Connect to the client machine.
+**********************************************************/
+
+static bool spoolss_connect_to_client(struct rpc_pipe_client **pp_pipe,
+ struct sockaddr_storage *client_ss, const char *remote_machine)
+{
+ NTSTATUS ret;
+ struct cli_state *the_cli;
+ struct sockaddr_storage rm_addr;
+
+ if ( is_zero_addr(client_ss) ) {
+ if ( !resolve_name( remote_machine, &rm_addr, 0x20) ) {
+ DEBUG(2,("spoolss_connect_to_client: Can't resolve address for %s\n", remote_machine));
+ return False;
+ }
+
+ if (ismyaddr(&rm_addr)) {
+ DEBUG(0,("spoolss_connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n", remote_machine));
+ return False;
+ }
+ } else {
+ char addr[INET6_ADDRSTRLEN];
+ rm_addr = *client_ss;
+ print_sockaddr(addr, sizeof(addr), &rm_addr);
+ DEBUG(5,("spoolss_connect_to_client: Using address %s (no name resolution necessary)\n",
+ addr));
+ }
+
+ /* setup the connection */
+
+ ret = cli_full_connection( &the_cli, global_myname(), remote_machine,
+ &rm_addr, 0, "IPC$", "IPC",
+ "", /* username */
+ "", /* domain */
+ "", /* password */
+ 0, lp_client_signing(), NULL );
+
+ if ( !NT_STATUS_IS_OK( ret ) ) {
+ DEBUG(2,("spoolss_connect_to_client: connection to [%s] failed!\n",
+ remote_machine ));
+ return False;
+ }
+
+ if ( the_cli->protocol != PROTOCOL_NT1 ) {
+ DEBUG(0,("spoolss_connect_to_client: machine %s didn't negotiate NT protocol.\n", remote_machine));
+ cli_shutdown(the_cli);
+ return False;
+ }
+
+ /*
+ * Ok - we have an anonymous connection to the IPC$ share.
+ * Now start the NT Domain stuff :-).
+ */
+
+ ret = cli_rpc_pipe_open_noauth(the_cli, &syntax_spoolss, pp_pipe);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(2,("spoolss_connect_to_client: unable to open the spoolss pipe on machine %s. Error was : %s.\n",
+ remote_machine, nt_errstr(ret)));
+ cli_shutdown(the_cli);
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ Connect to the client.
+****************************************************************************/
+
+static bool srv_spoolss_replyopenprinter(int snum, const char *printer,
+ uint32 localprinter, uint32 type,
+ POLICY_HND *handle, struct sockaddr_storage *client_ss)
+{
+ WERROR result;
+
+ /*
+ * If it's the first connection, contact the client
+ * and connect to the IPC$ share anonymously
+ */
+ if (smb_connections==0) {
+ fstring unix_printer;
+
+ fstrcpy(unix_printer, printer+2); /* the +2 is to strip the leading 2 backslashs */
+
+ if ( !spoolss_connect_to_client( &notify_cli_pipe, client_ss, unix_printer ))
+ return False;
+
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_PRINTER_NOTIFY2,
+ receive_notify2_message_list);
+ /* Tell the connections db we're now interested in printer
+ * notify messages. */
+ register_message_flags( True, FLAG_MSG_PRINT_NOTIFY );
+ }
+
+ /*
+ * Tell the specific printing tdb we want messages for this printer
+ * by registering our PID.
+ */
+
+ if (!print_notify_register_pid(snum))
+ DEBUG(0,("print_notify_register_pid: Failed to register our pid for printer %s\n", printer ));
+
+ smb_connections++;
+
+ result = rpccli_spoolss_reply_open_printer(notify_cli_pipe,
+ talloc_tos(),
+ printer,
+ localprinter,
+ type,
+ handle);
+
+ if (!W_ERROR_IS_OK(result))
+ DEBUG(5,("srv_spoolss_reply_open_printer: Client RPC returned [%s]\n",
+ dos_errstr(result)));
+
+ return (W_ERROR_IS_OK(result));
+}
+
+/********************************************************************
+ * _spoolss_rffpcnex
+ * ReplyFindFirstPrinterChangeNotifyEx
+ *
+ * before replying OK: status=0 a rpc call is made to the workstation
+ * asking ReplyOpenPrinter
+ *
+ * in fact ReplyOpenPrinter is the changenotify equivalent on the spoolss pipe
+ * called from api_spoolss_rffpcnex
+ ********************************************************************/
+
+WERROR _spoolss_rffpcnex(pipes_struct *p, SPOOL_Q_RFFPCNEX *q_u, SPOOL_R_RFFPCNEX *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 flags = q_u->flags;
+ uint32 options = q_u->options;
+ UNISTR2 *localmachine = &q_u->localmachine;
+ uint32 printerlocal = q_u->printerlocal;
+ int snum = -1;
+ SPOOL_NOTIFY_OPTION *option = q_u->option;
+ struct sockaddr_storage client_ss;
+
+ /* store the notify value in the printer struct */
+
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_rffpcnex: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ Printer->notify.flags=flags;
+ Printer->notify.options=options;
+ Printer->notify.printerlocal=printerlocal;
+
+ if (Printer->notify.option)
+ free_spool_notify_option(&Printer->notify.option);
+
+ Printer->notify.option=dup_spool_notify_option(option);
+
+ unistr2_to_ascii(Printer->notify.localmachine, localmachine,
+ sizeof(Printer->notify.localmachine));
+
+ /* Connect to the client machine and send a ReplyOpenPrinter */
+
+ if ( Printer->printer_type == SPLHND_SERVER)
+ snum = -1;
+ else if ( (Printer->printer_type == SPLHND_PRINTER) &&
+ !get_printer_snum(p, handle, &snum, NULL) )
+ return WERR_BADFID;
+
+ if (!interpret_string_addr(&client_ss, p->client_address,
+ AI_NUMERICHOST)) {
+ return WERR_SERVER_UNAVAILABLE;
+ }
+
+ if(!srv_spoolss_replyopenprinter(snum, Printer->notify.localmachine,
+ Printer->notify.printerlocal, 1,
+ &Printer->notify.client_hnd, &client_ss))
+ return WERR_SERVER_UNAVAILABLE;
+
+ Printer->notify.client_connected=True;
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the servername
+ ********************************************************************/
+
+void spoolss_notify_server_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ smb_ucs2_t *temp = NULL;
+ uint32 len;
+
+ len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->servername);
+ if (len == (uint32)-1) {
+ len = 0;
+ }
+
+ data->notify_data.data.length = len;
+ if (len) {
+ data->notify_data.data.string = (uint16 *)temp;
+ } else {
+ data->notify_data.data.string = NULL;
+ }
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the printername (not including the servername).
+ ********************************************************************/
+
+void spoolss_notify_printer_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ smb_ucs2_t *temp = NULL;
+ uint32 len;
+
+ /* the notify name should not contain the \\server\ part */
+ char *p = strrchr(printer->info_2->printername, '\\');
+
+ if (!p) {
+ p = printer->info_2->printername;
+ } else {
+ p++;
+ }
+
+ len = rpcstr_push_talloc(mem_ctx, &temp, p);
+ if (len == (uint32)-1) {
+ len = 0;
+ }
+
+ data->notify_data.data.length = len;
+ if (len) {
+ data->notify_data.data.string = (uint16 *)temp;
+ } else {
+ data->notify_data.data.string = NULL;
+ }
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the servicename
+ ********************************************************************/
+
+void spoolss_notify_share_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ smb_ucs2_t *temp = NULL;
+ uint32 len;
+
+ len = rpcstr_push_talloc(mem_ctx, &temp, lp_servicename(snum));
+ if (len == (uint32)-1) {
+ len = 0;
+ }
+
+ data->notify_data.data.length = len;
+ if (len) {
+ data->notify_data.data.string = (uint16 *)temp;
+ } else {
+ data->notify_data.data.string = NULL;
+ }
+
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the port name
+ ********************************************************************/
+
+void spoolss_notify_port_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ smb_ucs2_t *temp = NULL;
+ uint32 len;
+
+ /* even if it's strange, that's consistant in all the code */
+
+ len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->portname);
+ if (len == (uint32)-1) {
+ len = 0;
+ }
+
+ data->notify_data.data.length = len;
+ if (len) {
+ data->notify_data.data.string = (uint16 *)temp;
+ } else {
+ data->notify_data.data.string = NULL;
+ }
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the printername
+ * but it doesn't exist, have to see what to do
+ ********************************************************************/
+
+void spoolss_notify_driver_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ smb_ucs2_t *temp = NULL;
+ uint32 len;
+
+ len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->drivername);
+ if (len == (uint32)-1) {
+ len = 0;
+ }
+
+ data->notify_data.data.length = len;
+ if (len) {
+ data->notify_data.data.string = (uint16 *)temp;
+ } else {
+ data->notify_data.data.string = NULL;
+ }
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the comment
+ ********************************************************************/
+
+void spoolss_notify_comment(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ smb_ucs2_t *temp = NULL;
+ uint32 len;
+
+ if (*printer->info_2->comment == '\0')
+ len = rpcstr_push_talloc(mem_ctx, &temp, lp_comment(snum));
+ else
+ len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->comment);
+
+ if (len == (uint32)-1) {
+ len = 0;
+ }
+ data->notify_data.data.length = len;
+ if (len) {
+ data->notify_data.data.string = (uint16 *)temp;
+ } else {
+ data->notify_data.data.string = NULL;
+ }
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the comment
+ * location = "Room 1, floor 2, building 3"
+ ********************************************************************/
+
+void spoolss_notify_location(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ smb_ucs2_t *temp = NULL;
+ uint32 len;
+
+ len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->location);
+ if (len == (uint32)-1) {
+ len = 0;
+ }
+
+ data->notify_data.data.length = len;
+ if (len) {
+ data->notify_data.data.string = (uint16 *)temp;
+ } else {
+ data->notify_data.data.string = NULL;
+ }
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the device mode
+ * jfm:xxxx don't to it for know but that's a real problem !!!
+ ********************************************************************/
+
+static void spoolss_notify_devmode(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ /* for a dummy implementation we have to zero the fields */
+ data->notify_data.data.length = 0;
+ data->notify_data.data.string = NULL;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the separator file name
+ ********************************************************************/
+
+void spoolss_notify_sepfile(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ smb_ucs2_t *temp = NULL;
+ uint32 len;
+
+ len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->sepfile);
+ if (len == (uint32)-1) {
+ len = 0;
+ }
+
+ data->notify_data.data.length = len;
+ if (len) {
+ data->notify_data.data.string = (uint16 *)temp;
+ } else {
+ data->notify_data.data.string = NULL;
+ }
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the print processor
+ * jfm:xxxx return always winprint to indicate we don't do anything to it
+ ********************************************************************/
+
+void spoolss_notify_print_processor(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ smb_ucs2_t *temp = NULL;
+ uint32 len;
+
+ len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->printprocessor);
+ if (len == (uint32)-1) {
+ len = 0;
+ }
+
+ data->notify_data.data.length = len;
+ if (len) {
+ data->notify_data.data.string = (uint16 *)temp;
+ } else {
+ data->notify_data.data.string = NULL;
+ }
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the print processor options
+ * jfm:xxxx send an empty string
+ ********************************************************************/
+
+void spoolss_notify_parameters(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ smb_ucs2_t *temp = NULL;
+ uint32 len;
+
+ len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->parameters);
+ if (len == (uint32)-1) {
+ len = 0;
+ }
+
+ data->notify_data.data.length = len;
+ if (len) {
+ data->notify_data.data.string = (uint16 *)temp;
+ } else {
+ data->notify_data.data.string = NULL;
+ }
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the data type
+ * jfm:xxxx always send RAW as data type
+ ********************************************************************/
+
+void spoolss_notify_datatype(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ smb_ucs2_t *temp = NULL;
+ uint32 len;
+
+ len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->datatype);
+ if (len == (uint32)-1) {
+ len = 0;
+ }
+
+ data->notify_data.data.length = len;
+ if (len) {
+ data->notify_data.data.string = (uint16 *)temp;
+ } else {
+ data->notify_data.data.string = NULL;
+ }
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the security descriptor
+ * jfm:xxxx send an null pointer to say no security desc
+ * have to implement security before !
+ ********************************************************************/
+
+static void spoolss_notify_security_desc(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.sd.size = printer->info_2->secdesc_buf->sd_size;
+ data->notify_data.sd.desc = dup_sec_desc( mem_ctx, printer->info_2->secdesc_buf->sd ) ;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the attributes
+ * jfm:xxxx a samba printer is always shared
+ ********************************************************************/
+
+void spoolss_notify_attributes(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0] = printer->info_2->attributes;
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the priority
+ ********************************************************************/
+
+static void spoolss_notify_priority(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0] = printer->info_2->priority;
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the default priority
+ ********************************************************************/
+
+static void spoolss_notify_default_priority(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0] = printer->info_2->default_priority;
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the start time
+ ********************************************************************/
+
+static void spoolss_notify_start_time(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0] = printer->info_2->starttime;
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the until time
+ ********************************************************************/
+
+static void spoolss_notify_until_time(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0] = printer->info_2->untiltime;
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the status
+ ********************************************************************/
+
+static void spoolss_notify_status(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ print_status_struct status;
+
+ print_queue_length(snum, &status);
+ data->notify_data.value[0]=(uint32) status.status;
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the number of jobs queued
+ ********************************************************************/
+
+void spoolss_notify_cjobs(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0] = print_queue_length(snum, NULL);
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the average ppm
+ ********************************************************************/
+
+static void spoolss_notify_average_ppm(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ /* always respond 8 pages per minutes */
+ /* a little hard ! */
+ data->notify_data.value[0] = printer->info_2->averageppm;
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with username
+ ********************************************************************/
+
+static void spoolss_notify_username(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ smb_ucs2_t *temp = NULL;
+ uint32 len;
+
+ len = rpcstr_push_talloc(mem_ctx, &temp, queue->fs_user);
+ if (len == (uint32)-1) {
+ len = 0;
+ }
+
+ data->notify_data.data.length = len;
+ if (len) {
+ data->notify_data.data.string = (uint16 *)temp;
+ } else {
+ data->notify_data.data.string = NULL;
+ }
+}
+
+/*******************************************************************
+ * fill a notify_info_data with job status
+ ********************************************************************/
+
+static void spoolss_notify_job_status(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0]=nt_printj_status(queue->status);
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with job name
+ ********************************************************************/
+
+static void spoolss_notify_job_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ smb_ucs2_t *temp = NULL;
+ uint32 len;
+
+ len = rpcstr_push_talloc(mem_ctx, &temp, queue->fs_file);
+ if (len == (uint32)-1) {
+ len = 0;
+ }
+
+ data->notify_data.data.length = len;
+ if (len) {
+ data->notify_data.data.string = (uint16 *)temp;
+ } else {
+ data->notify_data.data.string = NULL;
+ }
+}
+
+/*******************************************************************
+ * fill a notify_info_data with job status
+ ********************************************************************/
+
+static void spoolss_notify_job_status_string(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ /*
+ * Now we're returning job status codes we just return a "" here. JRA.
+ */
+
+ const char *p = "";
+ smb_ucs2_t *temp = NULL;
+ uint32 len;
+
+#if 0 /* NO LONGER NEEDED - JRA. 02/22/2001 */
+ p = "unknown";
+
+ switch (queue->status) {
+ case LPQ_QUEUED:
+ p = "Queued";
+ break;
+ case LPQ_PAUSED:
+ p = ""; /* NT provides the paused string */
+ break;
+ case LPQ_SPOOLING:
+ p = "Spooling";
+ break;
+ case LPQ_PRINTING:
+ p = "Printing";
+ break;
+ }
+#endif /* NO LONGER NEEDED. */
+
+ len = rpcstr_push_talloc(mem_ctx, &temp, p);
+ if (len == (uint32)-1) {
+ len = 0;
+ }
+
+ data->notify_data.data.length = len;
+ if (len) {
+ data->notify_data.data.string = (uint16 *)temp;
+ } else {
+ data->notify_data.data.string = NULL;
+ }
+}
+
+/*******************************************************************
+ * fill a notify_info_data with job time
+ ********************************************************************/
+
+static void spoolss_notify_job_time(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0]=0x0;
+ data->notify_data.value[1]=0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with job size
+ ********************************************************************/
+
+static void spoolss_notify_job_size(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0]=queue->size;
+ data->notify_data.value[1]=0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with page info
+ ********************************************************************/
+static void spoolss_notify_total_pages(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0]=queue->page_count;
+ data->notify_data.value[1]=0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with pages printed info.
+ ********************************************************************/
+static void spoolss_notify_pages_printed(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0]=0; /* Add code when back-end tracks this */
+ data->notify_data.value[1]=0;
+}
+
+/*******************************************************************
+ Fill a notify_info_data with job position.
+ ********************************************************************/
+
+static void spoolss_notify_job_position(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0]=queue->job;
+ data->notify_data.value[1]=0;
+}
+
+/*******************************************************************
+ Fill a notify_info_data with submitted time.
+ ********************************************************************/
+
+static void spoolss_notify_submitted_time(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ struct tm *t;
+ uint32 len;
+ SYSTEMTIME st;
+ char *p;
+
+ t=gmtime(&queue->time);
+
+ len = sizeof(SYSTEMTIME);
+
+ data->notify_data.data.length = len;
+ data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ make_systemtime(&st, t);
+
+ /*
+ * Systemtime must be linearized as a set of UINT16's.
+ * Fix from Benjamin (Bj) Kuit bj@it.uts.edu.au
+ */
+
+ p = (char *)data->notify_data.data.string;
+ SSVAL(p, 0, st.year);
+ SSVAL(p, 2, st.month);
+ SSVAL(p, 4, st.dayofweek);
+ SSVAL(p, 6, st.day);
+ SSVAL(p, 8, st.hour);
+ SSVAL(p, 10, st.minute);
+ SSVAL(p, 12, st.second);
+ SSVAL(p, 14, st.milliseconds);
+}
+
+struct s_notify_info_data_table
+{
+ uint16 type;
+ uint16 field;
+ const char *name;
+ uint32 size;
+ void (*fn) (int snum, SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer, TALLOC_CTX *mem_ctx);
+};
+
+/* A table describing the various print notification constants and
+ whether the notification data is a pointer to a variable sized
+ buffer, a one value uint32 or a two value uint32. */
+
+static const struct s_notify_info_data_table notify_info_data_table[] =
+{
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SERVER_NAME, "PRINTER_NOTIFY_SERVER_NAME", NOTIFY_STRING, spoolss_notify_server_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINTER_NAME, "PRINTER_NOTIFY_PRINTER_NAME", NOTIFY_STRING, spoolss_notify_printer_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SHARE_NAME, "PRINTER_NOTIFY_SHARE_NAME", NOTIFY_STRING, spoolss_notify_share_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PORT_NAME, "PRINTER_NOTIFY_PORT_NAME", NOTIFY_STRING, spoolss_notify_port_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DRIVER_NAME, "PRINTER_NOTIFY_DRIVER_NAME", NOTIFY_STRING, spoolss_notify_driver_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_COMMENT, "PRINTER_NOTIFY_COMMENT", NOTIFY_STRING, spoolss_notify_comment },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_LOCATION, "PRINTER_NOTIFY_LOCATION", NOTIFY_STRING, spoolss_notify_location },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DEVMODE, "PRINTER_NOTIFY_DEVMODE", NOTIFY_POINTER, spoolss_notify_devmode },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SEPFILE, "PRINTER_NOTIFY_SEPFILE", NOTIFY_STRING, spoolss_notify_sepfile },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINT_PROCESSOR, "PRINTER_NOTIFY_PRINT_PROCESSOR", NOTIFY_STRING, spoolss_notify_print_processor },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PARAMETERS, "PRINTER_NOTIFY_PARAMETERS", NOTIFY_STRING, spoolss_notify_parameters },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DATATYPE, "PRINTER_NOTIFY_DATATYPE", NOTIFY_STRING, spoolss_notify_datatype },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SECURITY_DESCRIPTOR, "PRINTER_NOTIFY_SECURITY_DESCRIPTOR", NOTIFY_SECDESC, spoolss_notify_security_desc },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_ATTRIBUTES, "PRINTER_NOTIFY_ATTRIBUTES", NOTIFY_ONE_VALUE, spoolss_notify_attributes },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRIORITY, "PRINTER_NOTIFY_PRIORITY", NOTIFY_ONE_VALUE, spoolss_notify_priority },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DEFAULT_PRIORITY, "PRINTER_NOTIFY_DEFAULT_PRIORITY", NOTIFY_ONE_VALUE, spoolss_notify_default_priority },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_START_TIME, "PRINTER_NOTIFY_START_TIME", NOTIFY_ONE_VALUE, spoolss_notify_start_time },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_UNTIL_TIME, "PRINTER_NOTIFY_UNTIL_TIME", NOTIFY_ONE_VALUE, spoolss_notify_until_time },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_STATUS, "PRINTER_NOTIFY_STATUS", NOTIFY_ONE_VALUE, spoolss_notify_status },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_STATUS_STRING, "PRINTER_NOTIFY_STATUS_STRING", NOTIFY_POINTER, NULL },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_CJOBS, "PRINTER_NOTIFY_CJOBS", NOTIFY_ONE_VALUE, spoolss_notify_cjobs },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_AVERAGE_PPM, "PRINTER_NOTIFY_AVERAGE_PPM", NOTIFY_ONE_VALUE, spoolss_notify_average_ppm },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_TOTAL_PAGES, "PRINTER_NOTIFY_TOTAL_PAGES", NOTIFY_POINTER, NULL },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PAGES_PRINTED, "PRINTER_NOTIFY_PAGES_PRINTED", NOTIFY_POINTER, NULL },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_TOTAL_BYTES, "PRINTER_NOTIFY_TOTAL_BYTES", NOTIFY_POINTER, NULL },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_BYTES_PRINTED, "PRINTER_NOTIFY_BYTES_PRINTED", NOTIFY_POINTER, NULL },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_PRINTER_NAME, "JOB_NOTIFY_PRINTER_NAME", NOTIFY_STRING, spoolss_notify_printer_name },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_MACHINE_NAME, "JOB_NOTIFY_MACHINE_NAME", NOTIFY_STRING, spoolss_notify_server_name },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_PORT_NAME, "JOB_NOTIFY_PORT_NAME", NOTIFY_STRING, spoolss_notify_port_name },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_USER_NAME, "JOB_NOTIFY_USER_NAME", NOTIFY_STRING, spoolss_notify_username },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_NOTIFY_NAME, "JOB_NOTIFY_NOTIFY_NAME", NOTIFY_STRING, spoolss_notify_username },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_DATATYPE, "JOB_NOTIFY_DATATYPE", NOTIFY_STRING, spoolss_notify_datatype },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_PRINT_PROCESSOR, "JOB_NOTIFY_PRINT_PROCESSOR", NOTIFY_STRING, spoolss_notify_print_processor },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_PARAMETERS, "JOB_NOTIFY_PARAMETERS", NOTIFY_STRING, spoolss_notify_parameters },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_DRIVER_NAME, "JOB_NOTIFY_DRIVER_NAME", NOTIFY_STRING, spoolss_notify_driver_name },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_DEVMODE, "JOB_NOTIFY_DEVMODE", NOTIFY_POINTER, spoolss_notify_devmode },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_STATUS, "JOB_NOTIFY_STATUS", NOTIFY_ONE_VALUE, spoolss_notify_job_status },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_STATUS_STRING, "JOB_NOTIFY_STATUS_STRING", NOTIFY_STRING, spoolss_notify_job_status_string },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_SECURITY_DESCRIPTOR, "JOB_NOTIFY_SECURITY_DESCRIPTOR", NOTIFY_POINTER, NULL },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_DOCUMENT, "JOB_NOTIFY_DOCUMENT", NOTIFY_STRING, spoolss_notify_job_name },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_PRIORITY, "JOB_NOTIFY_PRIORITY", NOTIFY_ONE_VALUE, spoolss_notify_priority },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_POSITION, "JOB_NOTIFY_POSITION", NOTIFY_ONE_VALUE, spoolss_notify_job_position },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_SUBMITTED, "JOB_NOTIFY_SUBMITTED", NOTIFY_POINTER, spoolss_notify_submitted_time },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_START_TIME, "JOB_NOTIFY_START_TIME", NOTIFY_ONE_VALUE, spoolss_notify_start_time },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_UNTIL_TIME, "JOB_NOTIFY_UNTIL_TIME", NOTIFY_ONE_VALUE, spoolss_notify_until_time },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_TIME, "JOB_NOTIFY_TIME", NOTIFY_ONE_VALUE, spoolss_notify_job_time },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_TOTAL_PAGES, "JOB_NOTIFY_TOTAL_PAGES", NOTIFY_ONE_VALUE, spoolss_notify_total_pages },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_PAGES_PRINTED, "JOB_NOTIFY_PAGES_PRINTED", NOTIFY_ONE_VALUE, spoolss_notify_pages_printed },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_TOTAL_BYTES, "JOB_NOTIFY_TOTAL_BYTES", NOTIFY_ONE_VALUE, spoolss_notify_job_size },
+{ PRINT_TABLE_END, 0x0, NULL, 0x0, NULL },
+};
+
+/*******************************************************************
+ Return the size of info_data structure.
+********************************************************************/
+
+static uint32 size_of_notify_info_data(uint16 type, uint16 field)
+{
+ int i=0;
+
+ for (i = 0; i < (sizeof(notify_info_data_table)/sizeof(struct s_notify_info_data_table)); i++) {
+ if ( (notify_info_data_table[i].type == type)
+ && (notify_info_data_table[i].field == field) ) {
+ switch(notify_info_data_table[i].size) {
+ case NOTIFY_ONE_VALUE:
+ case NOTIFY_TWO_VALUE:
+ return 1;
+ case NOTIFY_STRING:
+ return 2;
+
+ /* The only pointer notify data I have seen on
+ the wire is the submitted time and this has
+ the notify size set to 4. -tpot */
+
+ case NOTIFY_POINTER:
+ return 4;
+
+ case NOTIFY_SECDESC:
+ return 5;
+ }
+ }
+ }
+
+ DEBUG(5, ("invalid notify data type %d/%d\n", type, field));
+
+ return 0;
+}
+
+/*******************************************************************
+ Return the type of notify_info_data.
+********************************************************************/
+
+static uint32 type_of_notify_info_data(uint16 type, uint16 field)
+{
+ uint32 i=0;
+
+ for (i = 0; i < (sizeof(notify_info_data_table)/sizeof(struct s_notify_info_data_table)); i++) {
+ if (notify_info_data_table[i].type == type &&
+ notify_info_data_table[i].field == field)
+ return notify_info_data_table[i].size;
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool search_notify(uint16 type, uint16 field, int *value)
+{
+ int i;
+
+ for (i = 0; notify_info_data_table[i].type != PRINT_TABLE_END; i++) {
+ if (notify_info_data_table[i].type == type &&
+ notify_info_data_table[i].field == field &&
+ notify_info_data_table[i].fn != NULL) {
+ *value = i;
+ return True;
+ }
+ }
+
+ return False;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void construct_info_data(SPOOL_NOTIFY_INFO_DATA *info_data, uint16 type, uint16 field, int id)
+{
+ info_data->type = type;
+ info_data->field = field;
+ info_data->reserved = 0;
+
+ info_data->size = size_of_notify_info_data(type, field);
+ info_data->enc_type = type_of_notify_info_data(type, field);
+
+ info_data->id = id;
+}
+
+/*******************************************************************
+ *
+ * fill a notify_info struct with info asked
+ *
+ ********************************************************************/
+
+static bool construct_notify_printer_info(Printer_entry *print_hnd, SPOOL_NOTIFY_INFO *info, int
+ snum, SPOOL_NOTIFY_OPTION_TYPE
+ *option_type, uint32 id,
+ TALLOC_CTX *mem_ctx)
+{
+ int field_num,j;
+ uint16 type;
+ uint16 field;
+
+ SPOOL_NOTIFY_INFO_DATA *current_data;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ print_queue_struct *queue=NULL;
+
+ type=option_type->type;
+
+ DEBUG(4,("construct_notify_printer_info: Notify type: [%s], number of notify info: [%d] on printer: [%s]\n",
+ (option_type->type==PRINTER_NOTIFY_TYPE?"PRINTER_NOTIFY_TYPE":"JOB_NOTIFY_TYPE"),
+ option_type->count, lp_servicename(snum)));
+
+ if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &printer, 2, lp_const_servicename(snum))))
+ return False;
+
+ for(field_num=0; field_num<option_type->count; field_num++) {
+ field = option_type->fields[field_num];
+
+ DEBUG(4,("construct_notify_printer_info: notify [%d]: type [%x], field [%x]\n", field_num, type, field));
+
+ if (!search_notify(type, field, &j) )
+ continue;
+
+ if((info->data=SMB_REALLOC_ARRAY(info->data, SPOOL_NOTIFY_INFO_DATA, info->count+1)) == NULL) {
+ DEBUG(2,("construct_notify_printer_info: failed to enlarge buffer info->data!\n"));
+ free_a_printer(&printer, 2);
+ return False;
+ }
+
+ current_data = &info->data[info->count];
+
+ construct_info_data(current_data, type, field, id);
+
+ DEBUG(10,("construct_notify_printer_info: calling [%s] snum=%d printername=[%s])\n",
+ notify_info_data_table[j].name, snum, printer->info_2->printername ));
+
+ notify_info_data_table[j].fn(snum, current_data, queue,
+ printer, mem_ctx);
+
+ info->count++;
+ }
+
+ free_a_printer(&printer, 2);
+ return True;
+}
+
+/*******************************************************************
+ *
+ * fill a notify_info struct with info asked
+ *
+ ********************************************************************/
+
+static bool construct_notify_jobs_info(print_queue_struct *queue,
+ SPOOL_NOTIFY_INFO *info,
+ NT_PRINTER_INFO_LEVEL *printer,
+ int snum, SPOOL_NOTIFY_OPTION_TYPE
+ *option_type, uint32 id,
+ TALLOC_CTX *mem_ctx)
+{
+ int field_num,j;
+ uint16 type;
+ uint16 field;
+
+ SPOOL_NOTIFY_INFO_DATA *current_data;
+
+ DEBUG(4,("construct_notify_jobs_info\n"));
+
+ type = option_type->type;
+
+ DEBUGADD(4,("Notify type: [%s], number of notify info: [%d]\n",
+ (option_type->type==PRINTER_NOTIFY_TYPE?"PRINTER_NOTIFY_TYPE":"JOB_NOTIFY_TYPE"),
+ option_type->count));
+
+ for(field_num=0; field_num<option_type->count; field_num++) {
+ field = option_type->fields[field_num];
+
+ if (!search_notify(type, field, &j) )
+ continue;
+
+ if((info->data=SMB_REALLOC_ARRAY(info->data, SPOOL_NOTIFY_INFO_DATA, info->count+1)) == NULL) {
+ DEBUG(2,("construct_notify_jobs_info: failed to enlarg buffer info->data!\n"));
+ return False;
+ }
+
+ current_data=&(info->data[info->count]);
+
+ construct_info_data(current_data, type, field, id);
+ notify_info_data_table[j].fn(snum, current_data, queue,
+ printer, mem_ctx);
+ info->count++;
+ }
+
+ return True;
+}
+
+/*
+ * JFM: The enumeration is not that simple, it's even non obvious.
+ *
+ * let's take an example: I want to monitor the PRINTER SERVER for
+ * the printer's name and the number of jobs currently queued.
+ * So in the NOTIFY_OPTION, I have one NOTIFY_OPTION_TYPE structure.
+ * Its type is PRINTER_NOTIFY_TYPE and it has 2 fields NAME and CJOBS.
+ *
+ * I have 3 printers on the back of my server.
+ *
+ * Now the response is a NOTIFY_INFO structure, with 6 NOTIFY_INFO_DATA
+ * structures.
+ * Number Data Id
+ * 1 printer 1 name 1
+ * 2 printer 1 cjob 1
+ * 3 printer 2 name 2
+ * 4 printer 2 cjob 2
+ * 5 printer 3 name 3
+ * 6 printer 3 name 3
+ *
+ * that's the print server case, the printer case is even worse.
+ */
+
+/*******************************************************************
+ *
+ * enumerate all printers on the printserver
+ * fill a notify_info struct with info asked
+ *
+ ********************************************************************/
+
+static WERROR printserver_notify_info(pipes_struct *p, POLICY_HND *hnd,
+ SPOOL_NOTIFY_INFO *info,
+ TALLOC_CTX *mem_ctx)
+{
+ int snum;
+ Printer_entry *Printer=find_printer_index_by_hnd(p, hnd);
+ int n_services=lp_numservices();
+ int i;
+ SPOOL_NOTIFY_OPTION *option;
+ SPOOL_NOTIFY_OPTION_TYPE *option_type;
+
+ DEBUG(4,("printserver_notify_info\n"));
+
+ if (!Printer)
+ return WERR_BADFID;
+
+ option=Printer->notify.option;
+ info->version=2;
+ info->data=NULL;
+ info->count=0;
+
+ /* a bug in xp sp2 rc2 causes it to send a fnpcn request without
+ sending a ffpcn() request first */
+
+ if ( !option )
+ return WERR_BADFID;
+
+ for (i=0; i<option->count; i++) {
+ option_type=&(option->ctr.type[i]);
+
+ if (option_type->type!=PRINTER_NOTIFY_TYPE)
+ continue;
+
+ for (snum=0; snum<n_services; snum++)
+ {
+ if ( lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) )
+ construct_notify_printer_info ( Printer, info, snum, option_type, snum, mem_ctx );
+ }
+ }
+
+#if 0
+ /*
+ * Debugging information, don't delete.
+ */
+
+ DEBUG(1,("dumping the NOTIFY_INFO\n"));
+ DEBUGADD(1,("info->version:[%d], info->flags:[%d], info->count:[%d]\n", info->version, info->flags, info->count));
+ DEBUGADD(1,("num\ttype\tfield\tres\tid\tsize\tenc_type\n"));
+
+ for (i=0; i<info->count; i++) {
+ DEBUGADD(1,("[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\n",
+ i, info->data[i].type, info->data[i].field, info->data[i].reserved,
+ info->data[i].id, info->data[i].size, info->data[i].enc_type));
+ }
+#endif
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ *
+ * fill a notify_info struct with info asked
+ *
+ ********************************************************************/
+
+static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, SPOOL_NOTIFY_INFO *info,
+ TALLOC_CTX *mem_ctx)
+{
+ int snum;
+ Printer_entry *Printer=find_printer_index_by_hnd(p, hnd);
+ int i;
+ uint32 id;
+ SPOOL_NOTIFY_OPTION *option;
+ SPOOL_NOTIFY_OPTION_TYPE *option_type;
+ int count,j;
+ print_queue_struct *queue=NULL;
+ print_status_struct status;
+
+ DEBUG(4,("printer_notify_info\n"));
+
+ if (!Printer)
+ return WERR_BADFID;
+
+ option=Printer->notify.option;
+ id = 0x0;
+ info->version=2;
+ info->data=NULL;
+ info->count=0;
+
+ /* a bug in xp sp2 rc2 causes it to send a fnpcn request without
+ sending a ffpcn() request first */
+
+ if ( !option )
+ return WERR_BADFID;
+
+ get_printer_snum(p, hnd, &snum, NULL);
+
+ for (i=0; i<option->count; i++) {
+ option_type=&option->ctr.type[i];
+
+ switch ( option_type->type ) {
+ case PRINTER_NOTIFY_TYPE:
+ if(construct_notify_printer_info(Printer, info, snum,
+ option_type, id,
+ mem_ctx))
+ id--;
+ break;
+
+ case JOB_NOTIFY_TYPE: {
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+ count = print_queue_status(snum, &queue, &status);
+
+ if (!W_ERROR_IS_OK(get_a_printer(Printer, &printer, 2, lp_const_servicename(snum))))
+ goto done;
+
+ for (j=0; j<count; j++) {
+ construct_notify_jobs_info(&queue[j], info,
+ printer, snum,
+ option_type,
+ queue[j].job,
+ mem_ctx);
+ }
+
+ free_a_printer(&printer, 2);
+
+ done:
+ SAFE_FREE(queue);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Debugging information, don't delete.
+ */
+ /*
+ DEBUG(1,("dumping the NOTIFY_INFO\n"));
+ DEBUGADD(1,("info->version:[%d], info->flags:[%d], info->count:[%d]\n", info->version, info->flags, info->count));
+ DEBUGADD(1,("num\ttype\tfield\tres\tid\tsize\tenc_type\n"));
+
+ for (i=0; i<info->count; i++) {
+ DEBUGADD(1,("[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\n",
+ i, info->data[i].type, info->data[i].field, info->data[i].reserved,
+ info->data[i].id, info->data[i].size, info->data[i].enc_type));
+ }
+ */
+ return WERR_OK;
+}
+
+/********************************************************************
+ * spoolss_rfnpcnex
+ ********************************************************************/
+
+WERROR _spoolss_rfnpcnex( pipes_struct *p, SPOOL_Q_RFNPCNEX *q_u, SPOOL_R_RFNPCNEX *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ SPOOL_NOTIFY_INFO *info = &r_u->info;
+
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+ WERROR result = WERR_BADFID;
+
+ /* we always have a NOTIFY_INFO struct */
+ r_u->info_ptr=0x1;
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_rfnpcnex: Invalid handle (%s:%u:%u).\n",
+ OUR_HANDLE(handle)));
+ goto done;
+ }
+
+ DEBUG(4,("Printer type %x\n",Printer->printer_type));
+
+ /*
+ * We are now using the change value, and
+ * I should check for PRINTER_NOTIFY_OPTIONS_REFRESH but as
+ * I don't have a global notification system, I'm sending back all the
+ * informations even when _NOTHING_ has changed.
+ */
+
+ /* We need to keep track of the change value to send back in
+ RRPCN replies otherwise our updates are ignored. */
+
+ Printer->notify.fnpcn = True;
+
+ if (Printer->notify.client_connected) {
+ DEBUG(10,("_spoolss_rfnpcnex: Saving change value in request [%x]\n", q_u->change));
+ Printer->notify.change = q_u->change;
+ }
+
+ /* just ignore the SPOOL_NOTIFY_OPTION */
+
+ switch (Printer->printer_type) {
+ case SPLHND_SERVER:
+ result = printserver_notify_info(p, handle, info, p->mem_ctx);
+ break;
+
+ case SPLHND_PRINTER:
+ result = printer_notify_info(p, handle, info, p->mem_ctx);
+ break;
+ }
+
+ Printer->notify.fnpcn = False;
+
+done:
+ return result;
+}
+
+/********************************************************************
+ * construct_printer_info_0
+ * fill a printer_info_0 struct
+ ********************************************************************/
+
+static bool construct_printer_info_0(Printer_entry *print_hnd, PRINTER_INFO_0 *printer, int snum)
+{
+ char *chaine = NULL;
+ int count;
+ NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+ counter_printer_0 *session_counter;
+ uint32 global_counter;
+ struct tm *t;
+ time_t setuptime;
+ print_status_struct status;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
+ return False;
+
+ init_unistr(&printer->printername, ntprinter->info_2->printername);
+
+ chaine = talloc_asprintf(ctx, "\\\\%s", get_server_name(print_hnd));
+ if (!chaine) {
+ free_a_printer(&ntprinter,2);
+ return false;
+ }
+
+ count = print_queue_length(snum, &status);
+
+ /* check if we already have a counter for this printer */
+ for(session_counter = counter_list; session_counter; session_counter = session_counter->next) {
+ if (session_counter->snum == snum)
+ break;
+ }
+
+ init_unistr(&printer->servername, chaine);
+
+ /* it's the first time, add it to the list */
+ if (session_counter==NULL) {
+ if((session_counter=SMB_MALLOC_P(counter_printer_0)) == NULL) {
+ free_a_printer(&ntprinter, 2);
+ return False;
+ }
+ ZERO_STRUCTP(session_counter);
+ session_counter->snum=snum;
+ session_counter->counter=0;
+ DLIST_ADD(counter_list, session_counter);
+ }
+
+ /* increment it */
+ session_counter->counter++;
+
+ /* JFM:
+ * the global_counter should be stored in a TDB as it's common to all the clients
+ * and should be zeroed on samba startup
+ */
+ global_counter=session_counter->counter;
+ printer->cjobs = count;
+ printer->total_jobs = 0;
+ printer->total_bytes = 0;
+
+ setuptime = (time_t)ntprinter->info_2->setuptime;
+ t=gmtime(&setuptime);
+
+ printer->year = t->tm_year+1900;
+ printer->month = t->tm_mon+1;
+ printer->dayofweek = t->tm_wday;
+ printer->day = t->tm_mday;
+ printer->hour = t->tm_hour;
+ printer->minute = t->tm_min;
+ printer->second = t->tm_sec;
+ printer->milliseconds = 0;
+
+ printer->global_counter = global_counter;
+ printer->total_pages = 0;
+
+ /* in 2.2 we reported ourselves as 0x0004 and 0x0565 */
+ printer->major_version = 0x0005; /* NT 5 */
+ printer->build_version = 0x0893; /* build 2195 */
+
+ printer->unknown7 = 0x1;
+ printer->unknown8 = 0x0;
+ printer->unknown9 = 0x0;
+ printer->session_counter = session_counter->counter;
+ printer->unknown11 = 0x0;
+ printer->printer_errors = 0x0; /* number of print failure */
+ printer->unknown13 = 0x0;
+ printer->unknown14 = 0x1;
+ printer->unknown15 = 0x024a; /* 586 Pentium ? */
+ printer->unknown16 = 0x0;
+ printer->change_id = ntprinter->info_2->changeid; /* ChangeID in milliseconds*/
+ printer->unknown18 = 0x0;
+ printer->status = nt_printq_status(status.status);
+ printer->unknown20 = 0x0;
+ printer->c_setprinter = get_c_setprinter(); /* monotonically increasing sum of delta printer counts */
+ printer->unknown22 = 0x0;
+ printer->unknown23 = 0x6; /* 6 ???*/
+ printer->unknown24 = 0; /* unknown 24 to 26 are always 0 */
+ printer->unknown25 = 0;
+ printer->unknown26 = 0;
+ printer->unknown27 = 0;
+ printer->unknown28 = 0;
+ printer->unknown29 = 0;
+
+ free_a_printer(&ntprinter,2);
+ return (True);
+}
+
+/********************************************************************
+ * construct_printer_info_1
+ * fill a printer_info_1 struct
+ ********************************************************************/
+static bool construct_printer_info_1(Printer_entry *print_hnd, uint32 flags, PRINTER_INFO_1 *printer, int snum)
+{
+ char *chaine = NULL;
+ NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
+ return false;
+
+ printer->flags=flags;
+
+ if (*ntprinter->info_2->comment == '\0') {
+ init_unistr(&printer->comment, lp_comment(snum));
+ chaine = talloc_asprintf(ctx,
+ "%s,%s,%s", ntprinter->info_2->printername,
+ ntprinter->info_2->drivername, lp_comment(snum));
+ }
+ else {
+ init_unistr(&printer->comment, ntprinter->info_2->comment); /* saved comment. */
+ chaine = talloc_asprintf(ctx,
+ "%s,%s,%s", ntprinter->info_2->printername,
+ ntprinter->info_2->drivername, ntprinter->info_2->comment);
+ }
+
+ if (!chaine) {
+ free_a_printer(&ntprinter,2);
+ return false;
+ }
+
+ init_unistr(&printer->description, chaine);
+ init_unistr(&printer->name, ntprinter->info_2->printername);
+
+ free_a_printer(&ntprinter,2);
+
+ return True;
+}
+
+/****************************************************************************
+ Free a DEVMODE struct.
+****************************************************************************/
+
+static void free_dev_mode(DEVICEMODE *dev)
+{
+ if (dev == NULL)
+ return;
+
+ SAFE_FREE(dev->dev_private);
+ SAFE_FREE(dev);
+}
+
+
+/****************************************************************************
+ Convert an NT_DEVICEMODE to a DEVICEMODE structure. Both pointers
+ should be valid upon entry
+****************************************************************************/
+
+static bool convert_nt_devicemode( DEVICEMODE *devmode, NT_DEVICEMODE *ntdevmode )
+{
+ if ( !devmode || !ntdevmode )
+ return False;
+
+ init_unistr(&devmode->devicename, ntdevmode->devicename);
+
+ init_unistr(&devmode->formname, ntdevmode->formname);
+
+ devmode->specversion = ntdevmode->specversion;
+ devmode->driverversion = ntdevmode->driverversion;
+ devmode->size = ntdevmode->size;
+ devmode->driverextra = ntdevmode->driverextra;
+ devmode->fields = ntdevmode->fields;
+
+ devmode->orientation = ntdevmode->orientation;
+ devmode->papersize = ntdevmode->papersize;
+ devmode->paperlength = ntdevmode->paperlength;
+ devmode->paperwidth = ntdevmode->paperwidth;
+ devmode->scale = ntdevmode->scale;
+ devmode->copies = ntdevmode->copies;
+ devmode->defaultsource = ntdevmode->defaultsource;
+ devmode->printquality = ntdevmode->printquality;
+ devmode->color = ntdevmode->color;
+ devmode->duplex = ntdevmode->duplex;
+ devmode->yresolution = ntdevmode->yresolution;
+ devmode->ttoption = ntdevmode->ttoption;
+ devmode->collate = ntdevmode->collate;
+ devmode->icmmethod = ntdevmode->icmmethod;
+ devmode->icmintent = ntdevmode->icmintent;
+ devmode->mediatype = ntdevmode->mediatype;
+ devmode->dithertype = ntdevmode->dithertype;
+
+ if (ntdevmode->nt_dev_private != NULL) {
+ if ((devmode->dev_private=(uint8 *)memdup(ntdevmode->nt_dev_private, ntdevmode->driverextra)) == NULL)
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Create a DEVMODE struct. Returns malloced memory.
+****************************************************************************/
+
+DEVICEMODE *construct_dev_mode(const char *servicename)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ DEVICEMODE *devmode = NULL;
+
+ DEBUG(7,("construct_dev_mode\n"));
+
+ DEBUGADD(8,("getting printer characteristics\n"));
+
+ if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, servicename)))
+ return NULL;
+
+ if ( !printer->info_2->devmode ) {
+ DEBUG(5, ("BONG! There was no device mode!\n"));
+ goto done;
+ }
+
+ if ((devmode = SMB_MALLOC_P(DEVICEMODE)) == NULL) {
+ DEBUG(2,("construct_dev_mode: malloc fail.\n"));
+ goto done;
+ }
+
+ ZERO_STRUCTP(devmode);
+
+ DEBUGADD(8,("loading DEVICEMODE\n"));
+
+ if ( !convert_nt_devicemode( devmode, printer->info_2->devmode ) ) {
+ free_dev_mode( devmode );
+ devmode = NULL;
+ }
+
+done:
+ free_a_printer(&printer,2);
+
+ return devmode;
+}
+
+/********************************************************************
+ * construct_printer_info_2
+ * fill a printer_info_2 struct
+ ********************************************************************/
+
+static bool construct_printer_info_2(Printer_entry *print_hnd, PRINTER_INFO_2 *printer, int snum)
+{
+ int count;
+ NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+
+ print_status_struct status;
+
+ if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
+ return False;
+
+ count = print_queue_length(snum, &status);
+
+ init_unistr(&printer->servername, ntprinter->info_2->servername); /* servername*/
+ init_unistr(&printer->printername, ntprinter->info_2->printername); /* printername*/
+ init_unistr(&printer->sharename, lp_servicename(snum)); /* sharename */
+ init_unistr(&printer->portname, ntprinter->info_2->portname); /* port */
+ init_unistr(&printer->drivername, ntprinter->info_2->drivername); /* drivername */
+
+ if (*ntprinter->info_2->comment == '\0')
+ init_unistr(&printer->comment, lp_comment(snum)); /* comment */
+ else
+ init_unistr(&printer->comment, ntprinter->info_2->comment); /* saved comment. */
+
+ init_unistr(&printer->location, ntprinter->info_2->location); /* location */
+ init_unistr(&printer->sepfile, ntprinter->info_2->sepfile); /* separator file */
+ init_unistr(&printer->printprocessor, ntprinter->info_2->printprocessor);/* print processor */
+ init_unistr(&printer->datatype, ntprinter->info_2->datatype); /* datatype */
+ init_unistr(&printer->parameters, ntprinter->info_2->parameters); /* parameters (of print processor) */
+
+ printer->attributes = ntprinter->info_2->attributes;
+
+ printer->priority = ntprinter->info_2->priority; /* priority */
+ printer->defaultpriority = ntprinter->info_2->default_priority; /* default priority */
+ printer->starttime = ntprinter->info_2->starttime; /* starttime */
+ printer->untiltime = ntprinter->info_2->untiltime; /* untiltime */
+ printer->status = nt_printq_status(status.status); /* status */
+ printer->cjobs = count; /* jobs */
+ printer->averageppm = ntprinter->info_2->averageppm; /* average pages per minute */
+
+ if ( !(printer->devmode = construct_dev_mode(
+ lp_const_servicename(snum))) )
+ DEBUG(8, ("Returning NULL Devicemode!\n"));
+
+ printer->secdesc = NULL;
+
+ if ( ntprinter->info_2->secdesc_buf
+ && ntprinter->info_2->secdesc_buf->sd_size != 0 )
+ {
+ /* don't use talloc_steal() here unless you do a deep steal of all
+ the SEC_DESC members */
+
+ printer->secdesc = dup_sec_desc( talloc_tos(),
+ ntprinter->info_2->secdesc_buf->sd );
+ }
+
+ free_a_printer(&ntprinter, 2);
+
+ return True;
+}
+
+/********************************************************************
+ * construct_printer_info_3
+ * fill a printer_info_3 struct
+ ********************************************************************/
+
+static bool construct_printer_info_3(Printer_entry *print_hnd, PRINTER_INFO_3 **pp_printer, int snum)
+{
+ NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+ PRINTER_INFO_3 *printer = NULL;
+
+ if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
+ return False;
+
+ *pp_printer = NULL;
+ if ((printer = SMB_MALLOC_P(PRINTER_INFO_3)) == NULL) {
+ DEBUG(2,("construct_printer_info_3: malloc fail.\n"));
+ free_a_printer(&ntprinter, 2);
+ return False;
+ }
+
+ ZERO_STRUCTP(printer);
+
+ /* These are the components of the SD we are returning. */
+
+ if (ntprinter->info_2->secdesc_buf && ntprinter->info_2->secdesc_buf->sd_size != 0) {
+ /* don't use talloc_steal() here unless you do a deep steal of all
+ the SEC_DESC members */
+
+ printer->secdesc = dup_sec_desc( talloc_tos(),
+ ntprinter->info_2->secdesc_buf->sd );
+ }
+
+ free_a_printer(&ntprinter, 2);
+
+ *pp_printer = printer;
+ return True;
+}
+
+/********************************************************************
+ * construct_printer_info_4
+ * fill a printer_info_4 struct
+ ********************************************************************/
+
+static bool construct_printer_info_4(Printer_entry *print_hnd, PRINTER_INFO_4 *printer, int snum)
+{
+ NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+
+ if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
+ return False;
+
+ init_unistr(&printer->printername, ntprinter->info_2->printername); /* printername*/
+ init_unistr(&printer->servername, ntprinter->info_2->servername); /* servername*/
+ printer->attributes = ntprinter->info_2->attributes;
+
+ free_a_printer(&ntprinter, 2);
+ return True;
+}
+
+/********************************************************************
+ * construct_printer_info_5
+ * fill a printer_info_5 struct
+ ********************************************************************/
+
+static bool construct_printer_info_5(Printer_entry *print_hnd, PRINTER_INFO_5 *printer, int snum)
+{
+ NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+
+ if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
+ return False;
+
+ init_unistr(&printer->printername, ntprinter->info_2->printername);
+ init_unistr(&printer->portname, ntprinter->info_2->portname);
+ printer->attributes = ntprinter->info_2->attributes;
+
+ /* these two are not used by NT+ according to MSDN */
+
+ printer->device_not_selected_timeout = 0x0; /* have seen 0x3a98 */
+ printer->transmission_retry_timeout = 0x0; /* have seen 0xafc8 */
+
+ free_a_printer(&ntprinter, 2);
+
+ return True;
+}
+
+/********************************************************************
+ * construct_printer_info_6
+ * fill a printer_info_6 struct
+ ********************************************************************/
+
+static bool construct_printer_info_6(Printer_entry *print_hnd,
+ PRINTER_INFO_6 *printer,
+ int snum)
+{
+ NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+ int count;
+ print_status_struct status;
+
+ if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2,
+ lp_const_servicename(snum))))
+ return False;
+
+ count = print_queue_length(snum, &status);
+
+ printer->status = nt_printq_status(status.status);
+
+ free_a_printer(&ntprinter, 2);
+
+ return True;
+}
+
+/********************************************************************
+ * construct_printer_info_7
+ * fill a printer_info_7 struct
+ ********************************************************************/
+
+static bool construct_printer_info_7(Printer_entry *print_hnd, PRINTER_INFO_7 *printer, int snum)
+{
+ char *guid_str = NULL;
+ struct GUID guid;
+
+ if (is_printer_published(print_hnd, snum, &guid)) {
+ if (asprintf(&guid_str, "{%s}",
+ smb_uuid_string(talloc_tos(), guid)) == -1) {
+ return false;
+ }
+ strupper_m(guid_str);
+ init_unistr(&printer->guid, guid_str);
+ SAFE_FREE(guid_str);
+ printer->action = SPOOL_DS_PUBLISH;
+ } else {
+ init_unistr(&printer->guid, "");
+ printer->action = SPOOL_DS_UNPUBLISH;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ Spoolss_enumprinters.
+********************************************************************/
+
+static WERROR enum_all_printers_info_1(uint32 flags, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ int snum;
+ int i;
+ int n_services=lp_numservices();
+ PRINTER_INFO_1 *printers=NULL;
+ PRINTER_INFO_1 current_prt;
+ WERROR result = WERR_OK;
+
+ DEBUG(4,("enum_all_printers_info_1\n"));
+
+ for (snum=0; snum<n_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
+ DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
+
+ if (construct_printer_info_1(NULL, flags, &current_prt, snum)) {
+ if((printers=SMB_REALLOC_ARRAY(printers, PRINTER_INFO_1, *returned +1)) == NULL) {
+ DEBUG(2,("enum_all_printers_info_1: failed to enlarge printers buffer!\n"));
+ *returned=0;
+ return WERR_NOMEM;
+ }
+ DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_1\n", *returned));
+
+ memcpy(&printers[*returned], &current_prt, sizeof(PRINTER_INFO_1));
+ (*returned)++;
+ }
+ }
+ }
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++)
+ (*needed) += spoolss_size_printer_info_1(&printers[i]);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the structures */
+ for (i=0; i<*returned; i++)
+ smb_io_printer_info_1("", buffer, &printers[i], 0);
+
+out:
+ /* clear memory */
+
+ SAFE_FREE(printers);
+
+ if ( !W_ERROR_IS_OK(result) )
+ *returned = 0;
+
+ return result;
+}
+
+/********************************************************************
+ enum_all_printers_info_1_local.
+*********************************************************************/
+
+static WERROR enum_all_printers_info_1_local(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ DEBUG(4,("enum_all_printers_info_1_local\n"));
+
+ return enum_all_printers_info_1(PRINTER_ENUM_ICON8, buffer, offered, needed, returned);
+}
+
+/********************************************************************
+ enum_all_printers_info_1_name.
+*********************************************************************/
+
+static WERROR enum_all_printers_info_1_name(fstring name, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ char *s = name;
+
+ DEBUG(4,("enum_all_printers_info_1_name\n"));
+
+ if ((name[0] == '\\') && (name[1] == '\\'))
+ s = name + 2;
+
+ if (is_myname_or_ipaddr(s)) {
+ return enum_all_printers_info_1(PRINTER_ENUM_ICON8, buffer, offered, needed, returned);
+ }
+ else
+ return WERR_INVALID_NAME;
+}
+
+#if 0 /* JERRY -- disabled for now. Don't think this is used, tested, or correct */
+/********************************************************************
+ enum_all_printers_info_1_remote.
+*********************************************************************/
+
+static WERROR enum_all_printers_info_1_remote(fstring name, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ PRINTER_INFO_1 *printer;
+ fstring printername;
+ fstring desc;
+ fstring comment;
+ DEBUG(4,("enum_all_printers_info_1_remote\n"));
+ WERROR result = WERR_OK;
+
+ /* JFM: currently it's more a place holder than anything else.
+ * In the spooler world there is a notion of server registration.
+ * the print servers are registered on the PDC (in the same domain)
+ *
+ * We should have a TDB here. The registration is done thru an
+ * undocumented RPC call.
+ */
+
+ if((printer=SMB_MALLOC_P(PRINTER_INFO_1)) == NULL)
+ return WERR_NOMEM;
+
+ *returned=1;
+
+ slprintf(printername, sizeof(printername)-1,"Windows NT Remote Printers!!\\\\%s", name);
+ slprintf(desc, sizeof(desc)-1,"%s", name);
+ slprintf(comment, sizeof(comment)-1, "Logged on Domain");
+
+ init_unistr(&printer->description, desc);
+ init_unistr(&printer->name, printername);
+ init_unistr(&printer->comment, comment);
+ printer->flags=PRINTER_ENUM_ICON3|PRINTER_ENUM_CONTAINER;
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_info_1(printer);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_info_1("", buffer, printer, 0);
+
+out:
+ /* clear memory */
+ SAFE_FREE(printer);
+
+ if ( !W_ERROR_IS_OK(result) )
+ *returned = 0;
+
+ return result;
+}
+
+#endif
+
+/********************************************************************
+ enum_all_printers_info_1_network.
+*********************************************************************/
+
+static WERROR enum_all_printers_info_1_network(fstring name, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ char *s = name;
+
+ DEBUG(4,("enum_all_printers_info_1_network\n"));
+
+ /* If we respond to a enum_printers level 1 on our name with flags
+ set to PRINTER_ENUM_REMOTE with a list of printers then these
+ printers incorrectly appear in the APW browse list.
+ Specifically the printers for the server appear at the workgroup
+ level where all the other servers in the domain are
+ listed. Windows responds to this call with a
+ WERR_CAN_NOT_COMPLETE so we should do the same. */
+
+ if (name[0] == '\\' && name[1] == '\\')
+ s = name + 2;
+
+ if (is_myname_or_ipaddr(s))
+ return WERR_CAN_NOT_COMPLETE;
+
+ return enum_all_printers_info_1(PRINTER_ENUM_UNKNOWN_8, buffer, offered, needed, returned);
+}
+
+/********************************************************************
+ * api_spoolss_enumprinters
+ *
+ * called from api_spoolss_enumprinters (see this to understand)
+ ********************************************************************/
+
+static WERROR enum_all_printers_info_2(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ int snum;
+ int i;
+ int n_services=lp_numservices();
+ PRINTER_INFO_2 *printers=NULL;
+ PRINTER_INFO_2 current_prt;
+ WERROR result = WERR_OK;
+
+ *returned = 0;
+
+ for (snum=0; snum<n_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
+ DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
+
+ if (construct_printer_info_2(NULL, &current_prt, snum)) {
+ if ( !(printers=SMB_REALLOC_ARRAY(printers, PRINTER_INFO_2, *returned +1)) ) {
+ DEBUG(2,("enum_all_printers_info_2: failed to enlarge printers buffer!\n"));
+ *returned = 0;
+ return WERR_NOMEM;
+ }
+
+ DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_2\n", *returned + 1));
+
+ memcpy(&printers[*returned], &current_prt, sizeof(PRINTER_INFO_2));
+
+ (*returned)++;
+ }
+ }
+ }
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++)
+ (*needed) += spoolss_size_printer_info_2(&printers[i]);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the structures */
+ for (i=0; i<*returned; i++)
+ smb_io_printer_info_2("", buffer, &(printers[i]), 0);
+
+out:
+ /* clear memory */
+
+ for (i=0; i<*returned; i++)
+ free_devmode(printers[i].devmode);
+
+ SAFE_FREE(printers);
+
+ if ( !W_ERROR_IS_OK(result) )
+ *returned = 0;
+
+ return result;
+}
+
+/********************************************************************
+ * handle enumeration of printers at level 1
+ ********************************************************************/
+
+static WERROR enumprinters_level1( uint32 flags, fstring name,
+ RPC_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+ /* Not all the flags are equals */
+
+ if (flags & PRINTER_ENUM_LOCAL)
+ return enum_all_printers_info_1_local(buffer, offered, needed, returned);
+
+ if (flags & PRINTER_ENUM_NAME)
+ return enum_all_printers_info_1_name(name, buffer, offered, needed, returned);
+
+#if 0 /* JERRY - disabled for now */
+ if (flags & PRINTER_ENUM_REMOTE)
+ return enum_all_printers_info_1_remote(name, buffer, offered, needed, returned);
+#endif
+
+ if (flags & PRINTER_ENUM_NETWORK)
+ return enum_all_printers_info_1_network(name, buffer, offered, needed, returned);
+
+ return WERR_OK; /* NT4sp5 does that */
+}
+
+/********************************************************************
+ * handle enumeration of printers at level 2
+ ********************************************************************/
+
+static WERROR enumprinters_level2( uint32 flags, const char *servername,
+ RPC_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+ if (flags & PRINTER_ENUM_LOCAL) {
+ return enum_all_printers_info_2(buffer, offered, needed, returned);
+ }
+
+ if (flags & PRINTER_ENUM_NAME) {
+ if (is_myname_or_ipaddr(canon_servername(servername)))
+ return enum_all_printers_info_2(buffer, offered, needed, returned);
+ else
+ return WERR_INVALID_NAME;
+ }
+
+ if (flags & PRINTER_ENUM_REMOTE)
+ return WERR_UNKNOWN_LEVEL;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * handle enumeration of printers at level 5
+ ********************************************************************/
+
+static WERROR enumprinters_level5( uint32 flags, const char *servername,
+ RPC_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+/* return enum_all_printers_info_5(buffer, offered, needed, returned);*/
+ return WERR_OK;
+}
+
+/********************************************************************
+ * api_spoolss_enumprinters
+ *
+ * called from api_spoolss_enumprinters (see this to understand)
+ ********************************************************************/
+
+WERROR _spoolss_enumprinters( pipes_struct *p, SPOOL_Q_ENUMPRINTERS *q_u, SPOOL_R_ENUMPRINTERS *r_u)
+{
+ uint32 flags = q_u->flags;
+ UNISTR2 *servername = &q_u->servername;
+ uint32 level = q_u->level;
+ RPC_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *returned = &r_u->returned;
+
+ fstring name;
+
+ /* that's an [in out] buffer */
+
+ if (!q_u->buffer && (offered!=0)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ rpcbuf_move(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(4,("_spoolss_enumprinters\n"));
+
+ *needed=0;
+ *returned=0;
+
+ /*
+ * Level 1:
+ * flags==PRINTER_ENUM_NAME
+ * if name=="" then enumerates all printers
+ * if name!="" then enumerate the printer
+ * flags==PRINTER_ENUM_REMOTE
+ * name is NULL, enumerate printers
+ * Level 2: name!="" enumerates printers, name can't be NULL
+ * Level 3: doesn't exist
+ * Level 4: does a local registry lookup
+ * Level 5: same as Level 2
+ */
+
+ unistr2_to_ascii(name, servername, sizeof(name));
+ strupper_m(name);
+
+ switch (level) {
+ case 1:
+ return enumprinters_level1(flags, name, buffer, offered, needed, returned);
+ case 2:
+ return enumprinters_level2(flags, name, buffer, offered, needed, returned);
+ case 5:
+ return enumprinters_level5(flags, name, buffer, offered, needed, returned);
+ case 3:
+ case 4:
+ break;
+ }
+ return WERR_UNKNOWN_LEVEL;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR getprinter_level_0(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ PRINTER_INFO_0 *printer=NULL;
+ WERROR result = WERR_OK;
+
+ if((printer=SMB_MALLOC_P(PRINTER_INFO_0)) == NULL)
+ return WERR_NOMEM;
+
+ construct_printer_info_0(print_hnd, printer, snum);
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_info_0(printer);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_info_0("", buffer, printer, 0);
+
+out:
+ /* clear memory */
+
+ SAFE_FREE(printer);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR getprinter_level_1(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ PRINTER_INFO_1 *printer=NULL;
+ WERROR result = WERR_OK;
+
+ if((printer=SMB_MALLOC_P(PRINTER_INFO_1)) == NULL)
+ return WERR_NOMEM;
+
+ construct_printer_info_1(print_hnd, PRINTER_ENUM_ICON8, printer, snum);
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_info_1(printer);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_info_1("", buffer, printer, 0);
+
+out:
+ /* clear memory */
+ SAFE_FREE(printer);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR getprinter_level_2(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ PRINTER_INFO_2 *printer=NULL;
+ WERROR result = WERR_OK;
+
+ if((printer=SMB_MALLOC_P(PRINTER_INFO_2))==NULL)
+ return WERR_NOMEM;
+
+ construct_printer_info_2(print_hnd, printer, snum);
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_info_2(printer);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the structures */
+ if (!smb_io_printer_info_2("", buffer, printer, 0))
+ result = WERR_NOMEM;
+
+out:
+ /* clear memory */
+ free_printer_info_2(printer);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR getprinter_level_3(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ PRINTER_INFO_3 *printer=NULL;
+ WERROR result = WERR_OK;
+
+ if (!construct_printer_info_3(print_hnd, &printer, snum))
+ return WERR_NOMEM;
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_info_3(printer);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_info_3("", buffer, printer, 0);
+
+out:
+ /* clear memory */
+ free_printer_info_3(printer);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR getprinter_level_4(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ PRINTER_INFO_4 *printer=NULL;
+ WERROR result = WERR_OK;
+
+ if((printer=SMB_MALLOC_P(PRINTER_INFO_4))==NULL)
+ return WERR_NOMEM;
+
+ if (!construct_printer_info_4(print_hnd, printer, snum)) {
+ SAFE_FREE(printer);
+ return WERR_NOMEM;
+ }
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_info_4(printer);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_info_4("", buffer, printer, 0);
+
+out:
+ /* clear memory */
+ free_printer_info_4(printer);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR getprinter_level_5(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ PRINTER_INFO_5 *printer=NULL;
+ WERROR result = WERR_OK;
+
+ if((printer=SMB_MALLOC_P(PRINTER_INFO_5))==NULL)
+ return WERR_NOMEM;
+
+ if (!construct_printer_info_5(print_hnd, printer, snum)) {
+ free_printer_info_5(printer);
+ return WERR_NOMEM;
+ }
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_info_5(printer);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_info_5("", buffer, printer, 0);
+
+out:
+ /* clear memory */
+ free_printer_info_5(printer);
+
+ return result;
+}
+
+static WERROR getprinter_level_6(Printer_entry *print_hnd,
+ int snum,
+ RPC_BUFFER *buffer, uint32 offered,
+ uint32 *needed)
+{
+ PRINTER_INFO_6 *printer;
+ WERROR result = WERR_OK;
+
+ if ((printer = SMB_MALLOC_P(PRINTER_INFO_6)) == NULL) {
+ return WERR_NOMEM;
+ }
+
+ if (!construct_printer_info_6(print_hnd, printer, snum)) {
+ free_printer_info_6(printer);
+ return WERR_NOMEM;
+ }
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_info_6(printer);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_info_6("", buffer, printer, 0);
+
+out:
+ /* clear memory */
+ free_printer_info_6(printer);
+
+ return result;
+}
+
+static WERROR getprinter_level_7(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ PRINTER_INFO_7 *printer=NULL;
+ WERROR result = WERR_OK;
+
+ if((printer=SMB_MALLOC_P(PRINTER_INFO_7))==NULL)
+ return WERR_NOMEM;
+
+ if (!construct_printer_info_7(print_hnd, printer, snum)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_info_7(printer);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_info_7("", buffer, printer, 0);
+
+out:
+ /* clear memory */
+ free_printer_info_7(printer);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_getprinter(pipes_struct *p, SPOOL_Q_GETPRINTER *q_u, SPOOL_R_GETPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 level = q_u->level;
+ RPC_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+
+ int snum;
+
+ /* that's an [in out] buffer */
+
+ if (!q_u->buffer && (offered!=0)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ rpcbuf_move(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ *needed=0;
+
+ if (!get_printer_snum(p, handle, &snum, NULL))
+ return WERR_BADFID;
+
+ switch (level) {
+ case 0:
+ return getprinter_level_0(Printer, snum, buffer, offered, needed);
+ case 1:
+ return getprinter_level_1(Printer, snum, buffer, offered, needed);
+ case 2:
+ return getprinter_level_2(Printer, snum, buffer, offered, needed);
+ case 3:
+ return getprinter_level_3(Printer, snum, buffer, offered, needed);
+ case 4:
+ return getprinter_level_4(Printer, snum, buffer, offered, needed);
+ case 5:
+ return getprinter_level_5(Printer, snum, buffer, offered, needed);
+ case 6:
+ return getprinter_level_6(Printer, snum, buffer, offered, needed);
+ case 7:
+ return getprinter_level_7(Printer, snum, buffer, offered, needed);
+ }
+ return WERR_UNKNOWN_LEVEL;
+}
+
+/********************************************************************
+ * fill a DRIVER_INFO_1 struct
+ ********************************************************************/
+
+static void fill_printer_driver_info_1(DRIVER_INFO_1 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, const char *servername, fstring architecture)
+{
+ init_unistr( &info->name, driver.info_3->name);
+}
+
+/********************************************************************
+ * construct_printer_driver_info_1
+ ********************************************************************/
+
+static WERROR construct_printer_driver_info_1(DRIVER_INFO_1 *info, int snum, const char *servername, fstring architecture, uint32 version)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+
+ ZERO_STRUCT(driver);
+
+ if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
+ return WERR_INVALID_PRINTER_NAME;
+
+ if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version))) {
+ free_a_printer(&printer, 2);
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+
+ fill_printer_driver_info_1(info, driver, servername, architecture);
+
+ free_a_printer(&printer,2);
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * construct_printer_driver_info_2
+ * fill a printer_info_2 struct
+ ********************************************************************/
+
+static void fill_printer_driver_info_2(DRIVER_INFO_2 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, const char *servername)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *temp = NULL;
+ const char *cservername = canon_servername(servername);
+
+ info->version=driver.info_3->cversion;
+
+ init_unistr( &info->name, driver.info_3->name );
+ init_unistr( &info->architecture, driver.info_3->environment );
+
+ if (strlen(driver.info_3->driverpath)) {
+ temp = talloc_asprintf(ctx,
+ "\\\\%s%s",
+ cservername,
+ driver.info_3->driverpath);
+ init_unistr( &info->driverpath, temp );
+ } else {
+ init_unistr( &info->driverpath, "" );
+ }
+
+ TALLOC_FREE(temp);
+ if (strlen(driver.info_3->datafile)) {
+ temp = talloc_asprintf(ctx,
+ "\\\\%s%s",
+ cservername,
+ driver.info_3->datafile);
+ init_unistr( &info->datafile, temp );
+ } else
+ init_unistr( &info->datafile, "" );
+
+ TALLOC_FREE(temp);
+ if (strlen(driver.info_3->configfile)) {
+ temp = talloc_asprintf(ctx,
+ "\\\\%s%s",
+ cservername,
+ driver.info_3->configfile);
+ init_unistr( &info->configfile, temp );
+ } else
+ init_unistr( &info->configfile, "" );
+}
+
+/********************************************************************
+ * construct_printer_driver_info_2
+ * fill a printer_info_2 struct
+ ********************************************************************/
+
+static WERROR construct_printer_driver_info_2(DRIVER_INFO_2 *info, int snum, const char *servername, fstring architecture, uint32 version)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+
+ ZERO_STRUCT(printer);
+ ZERO_STRUCT(driver);
+
+ if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
+ return WERR_INVALID_PRINTER_NAME;
+
+ if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version))) {
+ free_a_printer(&printer, 2);
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+
+ fill_printer_driver_info_2(info, driver, servername);
+
+ free_a_printer(&printer,2);
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * copy a strings array and convert to UNICODE
+ *
+ * convert an array of ascii string to a UNICODE string
+ ********************************************************************/
+
+static uint32 init_unistr_array(uint16 **uni_array, fstring *char_array, const char *servername)
+{
+ int i=0;
+ int j=0;
+ const char *v;
+ char *line = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ DEBUG(6,("init_unistr_array\n"));
+ *uni_array=NULL;
+
+ while (true) {
+ if ( !char_array ) {
+ v = "";
+ } else {
+ v = char_array[i];
+ if (!v)
+ v = ""; /* hack to handle null lists */
+ }
+
+ /* hack to allow this to be used in places other than when generating
+ the list of dependent files */
+
+ TALLOC_FREE(line);
+ if ( servername ) {
+ line = talloc_asprintf(ctx,
+ "\\\\%s%s",
+ canon_servername(servername),
+ v);
+ } else {
+ line = talloc_strdup(ctx, v);
+ }
+
+ if (!line) {
+ SAFE_FREE(*uni_array);
+ return 0;
+ }
+ DEBUGADD(6,("%d:%s:%lu\n", i, line, (unsigned long)strlen(line)));
+
+ /* add one extra unit16 for the second terminating NULL */
+
+ if ( (*uni_array=SMB_REALLOC_ARRAY(*uni_array, uint16, j+1+strlen(line)+2)) == NULL ) {
+ DEBUG(2,("init_unistr_array: Realloc error\n" ));
+ return 0;
+ }
+
+ if ( !strlen(v) )
+ break;
+
+ j += (rpcstr_push((*uni_array+j), line, sizeof(uint16)*strlen(line)+2, STR_TERMINATE) / sizeof(uint16));
+ i++;
+ }
+
+ if (*uni_array) {
+ /* special case for ""; we need to add both NULL's here */
+ if (!j)
+ (*uni_array)[j++]=0x0000;
+ (*uni_array)[j]=0x0000;
+ }
+
+ DEBUGADD(6,("last one:done\n"));
+
+ /* return size of array in uint16's */
+
+ return j+1;
+}
+
+/********************************************************************
+ * construct_printer_info_3
+ * fill a printer_info_3 struct
+ ********************************************************************/
+
+static void fill_printer_driver_info_3(DRIVER_INFO_3 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, const char *servername)
+{
+ char *temp = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+ const char *cservername = canon_servername(servername);
+
+ ZERO_STRUCTP(info);
+
+ info->version=driver.info_3->cversion;
+
+ init_unistr( &info->name, driver.info_3->name );
+ init_unistr( &info->architecture, driver.info_3->environment );
+
+ if (strlen(driver.info_3->driverpath)) {
+ temp = talloc_asprintf(ctx,
+ "\\\\%s%s",
+ cservername,
+ driver.info_3->driverpath);
+ init_unistr( &info->driverpath, temp );
+ } else
+ init_unistr( &info->driverpath, "" );
+
+ TALLOC_FREE(temp);
+ if (strlen(driver.info_3->datafile)) {
+ temp = talloc_asprintf(ctx,
+ "\\\\%s%s",
+ cservername,
+ driver.info_3->datafile);
+ init_unistr( &info->datafile, temp );
+ } else
+ init_unistr( &info->datafile, "" );
+
+ TALLOC_FREE(temp);
+ if (strlen(driver.info_3->configfile)) {
+ temp = talloc_asprintf(ctx,
+ "\\\\%s%s",
+ cservername,
+ driver.info_3->configfile);
+ init_unistr( &info->configfile, temp );
+ } else
+ init_unistr( &info->configfile, "" );
+
+ TALLOC_FREE(temp);
+ if (strlen(driver.info_3->helpfile)) {
+ temp = talloc_asprintf(ctx,
+ "\\\\%s%s",
+ cservername,
+ driver.info_3->helpfile);
+ init_unistr( &info->helpfile, temp );
+ } else
+ init_unistr( &info->helpfile, "" );
+
+ TALLOC_FREE(temp);
+ init_unistr( &info->monitorname, driver.info_3->monitorname );
+ init_unistr( &info->defaultdatatype, driver.info_3->defaultdatatype );
+
+ info->dependentfiles=NULL;
+ init_unistr_array(&info->dependentfiles, driver.info_3->dependentfiles, cservername);
+}
+
+/********************************************************************
+ * construct_printer_info_3
+ * fill a printer_info_3 struct
+ ********************************************************************/
+
+static WERROR construct_printer_driver_info_3(DRIVER_INFO_3 *info, int snum, const char *servername, fstring architecture, uint32 version)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ WERROR status;
+ ZERO_STRUCT(driver);
+
+ status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
+ DEBUG(8,("construct_printer_driver_info_3: status: %s\n", dos_errstr(status)));
+ if (!W_ERROR_IS_OK(status))
+ return WERR_INVALID_PRINTER_NAME;
+
+ status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
+ DEBUG(8,("construct_printer_driver_info_3: status: %s\n", dos_errstr(status)));
+
+#if 0 /* JERRY */
+
+ /*
+ * I put this code in during testing. Helpful when commenting out the
+ * support for DRIVER_INFO_6 in regards to win2k. Not needed in general
+ * as win2k always queries the driver using an infor level of 6.
+ * I've left it in (but ifdef'd out) because I'll probably
+ * use it in experimentation again in the future. --jerry 22/01/2002
+ */
+
+ if (!W_ERROR_IS_OK(status)) {
+ /*
+ * Is this a W2k client ?
+ */
+ if (version == 3) {
+ /* Yes - try again with a WinNT driver. */
+ version = 2;
+ status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
+ DEBUG(8,("construct_printer_driver_info_3: status: %s\n", dos_errstr(status)));
+ }
+#endif
+
+ if (!W_ERROR_IS_OK(status)) {
+ free_a_printer(&printer,2);
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+
+#if 0 /* JERRY */
+ }
+#endif
+
+
+ fill_printer_driver_info_3(info, driver, servername);
+
+ free_a_printer(&printer,2);
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * construct_printer_info_6
+ * fill a printer_info_6 struct - we know that driver is really level 3. This sucks. JRA.
+ ********************************************************************/
+
+static void fill_printer_driver_info_6(DRIVER_INFO_6 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, const char *servername)
+{
+ char *temp = NULL;
+ fstring nullstr;
+ TALLOC_CTX *ctx = talloc_tos();
+ const char *cservername = canon_servername(servername);
+
+ ZERO_STRUCTP(info);
+ memset(&nullstr, '\0', sizeof(fstring));
+
+ info->version=driver.info_3->cversion;
+
+ init_unistr( &info->name, driver.info_3->name );
+ init_unistr( &info->architecture, driver.info_3->environment );
+
+ if (strlen(driver.info_3->driverpath)) {
+ temp = talloc_asprintf(ctx,
+ "\\\\%s%s",
+ cservername,
+ driver.info_3->driverpath);
+ init_unistr( &info->driverpath, temp );
+ } else
+ init_unistr( &info->driverpath, "" );
+
+ TALLOC_FREE(temp);
+ if (strlen(driver.info_3->datafile)) {
+ temp = talloc_asprintf(ctx,
+ "\\\\%s%s",
+ cservername,
+ driver.info_3->datafile);
+ init_unistr( &info->datafile, temp );
+ } else
+ init_unistr( &info->datafile, "" );
+
+ TALLOC_FREE(temp);
+ if (strlen(driver.info_3->configfile)) {
+ temp = talloc_asprintf(ctx,
+ "\\\\%s%s",
+ cservername,
+ driver.info_3->configfile);
+ init_unistr( &info->configfile, temp );
+ } else
+ init_unistr( &info->configfile, "" );
+
+ TALLOC_FREE(temp);
+ if (strlen(driver.info_3->helpfile)) {
+ temp = talloc_asprintf(ctx,
+ "\\\\%s%s",
+ cservername,
+ driver.info_3->helpfile);
+ init_unistr( &info->helpfile, temp );
+ } else
+ init_unistr( &info->helpfile, "" );
+
+ TALLOC_FREE(temp);
+ init_unistr( &info->monitorname, driver.info_3->monitorname );
+ init_unistr( &info->defaultdatatype, driver.info_3->defaultdatatype );
+
+ info->dependentfiles = NULL;
+ init_unistr_array( &info->dependentfiles, driver.info_3->dependentfiles, servername );
+
+ info->previousdrivernames=NULL;
+ init_unistr_array(&info->previousdrivernames, &nullstr, servername);
+
+ info->driver_date=0;
+
+ info->padding=0;
+ info->driver_version_low=0;
+ info->driver_version_high=0;
+
+ init_unistr( &info->mfgname, "");
+ init_unistr( &info->oem_url, "");
+ init_unistr( &info->hardware_id, "");
+ init_unistr( &info->provider, "");
+}
+
+/********************************************************************
+ * construct_printer_info_6
+ * fill a printer_info_6 struct
+ ********************************************************************/
+
+static WERROR construct_printer_driver_info_6(DRIVER_INFO_6 *info, int snum,
+ const char *servername, fstring architecture, uint32 version)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ WERROR status;
+
+ ZERO_STRUCT(driver);
+
+ status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
+
+ DEBUG(8,("construct_printer_driver_info_6: status: %s\n", dos_errstr(status)));
+
+ if (!W_ERROR_IS_OK(status))
+ return WERR_INVALID_PRINTER_NAME;
+
+ status = get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
+
+ DEBUG(8,("construct_printer_driver_info_6: status: %s\n", dos_errstr(status)));
+
+ if (!W_ERROR_IS_OK(status))
+ {
+ /*
+ * Is this a W2k client ?
+ */
+
+ if (version < 3) {
+ free_a_printer(&printer,2);
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+
+ /* Yes - try again with a WinNT driver. */
+ version = 2;
+ status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
+ DEBUG(8,("construct_printer_driver_info_6: status: %s\n", dos_errstr(status)));
+ if (!W_ERROR_IS_OK(status)) {
+ free_a_printer(&printer,2);
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+ }
+
+ fill_printer_driver_info_6(info, driver, servername);
+
+ free_a_printer(&printer,2);
+ free_a_printer_driver(driver, 3);
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void free_printer_driver_info_3(DRIVER_INFO_3 *info)
+{
+ SAFE_FREE(info->dependentfiles);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void free_printer_driver_info_6(DRIVER_INFO_6 *info)
+{
+ SAFE_FREE(info->dependentfiles);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR getprinterdriver2_level1(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ DRIVER_INFO_1 *info=NULL;
+ WERROR result;
+
+ if((info=SMB_MALLOC_P(DRIVER_INFO_1)) == NULL)
+ return WERR_NOMEM;
+
+ result = construct_printer_driver_info_1(info, snum, servername, architecture, version);
+ if (!W_ERROR_IS_OK(result))
+ goto out;
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_driver_info_1(info);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_driver_info_1("", buffer, info, 0);
+
+out:
+ /* clear memory */
+ SAFE_FREE(info);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR getprinterdriver2_level2(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ DRIVER_INFO_2 *info=NULL;
+ WERROR result;
+
+ if((info=SMB_MALLOC_P(DRIVER_INFO_2)) == NULL)
+ return WERR_NOMEM;
+
+ result = construct_printer_driver_info_2(info, snum, servername, architecture, version);
+ if (!W_ERROR_IS_OK(result))
+ goto out;
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_driver_info_2(info);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_driver_info_2("", buffer, info, 0);
+
+out:
+ /* clear memory */
+ SAFE_FREE(info);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR getprinterdriver2_level3(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ DRIVER_INFO_3 info;
+ WERROR result;
+
+ ZERO_STRUCT(info);
+
+ result = construct_printer_driver_info_3(&info, snum, servername, architecture, version);
+ if (!W_ERROR_IS_OK(result))
+ goto out;
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_driver_info_3(&info);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_driver_info_3("", buffer, &info, 0);
+
+out:
+ free_printer_driver_info_3(&info);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR getprinterdriver2_level6(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ DRIVER_INFO_6 info;
+ WERROR result;
+
+ ZERO_STRUCT(info);
+
+ result = construct_printer_driver_info_6(&info, snum, servername, architecture, version);
+ if (!W_ERROR_IS_OK(result))
+ goto out;
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_driver_info_6(&info);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_driver_info_6("", buffer, &info, 0);
+
+out:
+ free_printer_driver_info_6(&info);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_getprinterdriver2(pipes_struct *p, SPOOL_Q_GETPRINTERDRIVER2 *q_u, SPOOL_R_GETPRINTERDRIVER2 *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ UNISTR2 *uni_arch = &q_u->architecture;
+ uint32 level = q_u->level;
+ uint32 clientmajorversion = q_u->clientmajorversion;
+ RPC_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *servermajorversion = &r_u->servermajorversion;
+ uint32 *serverminorversion = &r_u->serverminorversion;
+ Printer_entry *printer;
+
+ fstring servername;
+ fstring architecture;
+ int snum;
+
+ /* that's an [in out] buffer */
+
+ if (!q_u->buffer && (offered!=0)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ rpcbuf_move(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(4,("_spoolss_getprinterdriver2\n"));
+
+ if ( !(printer = find_printer_index_by_hnd( p, handle )) ) {
+ DEBUG(0,("_spoolss_getprinterdriver2: invalid printer handle!\n"));
+ return WERR_INVALID_PRINTER_NAME;
+ }
+
+ *needed = 0;
+ *servermajorversion = 0;
+ *serverminorversion = 0;
+
+ fstrcpy(servername, get_server_name( printer ));
+ unistr2_to_ascii(architecture, uni_arch, sizeof(architecture));
+
+ if (!get_printer_snum(p, handle, &snum, NULL))
+ return WERR_BADFID;
+
+ switch (level) {
+ case 1:
+ return getprinterdriver2_level1(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
+ case 2:
+ return getprinterdriver2_level2(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
+ case 3:
+ return getprinterdriver2_level3(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
+ case 6:
+ return getprinterdriver2_level6(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
+#if 0 /* JERRY */
+ case 101:
+ /* apparently this call is the equivalent of
+ EnumPrinterDataEx() for the DsDriver key */
+ break;
+#endif
+ }
+
+ return WERR_UNKNOWN_LEVEL;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_startpageprinter(pipes_struct *p, SPOOL_Q_STARTPAGEPRINTER *q_u, SPOOL_R_STARTPAGEPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ if (!Printer) {
+ DEBUG(3,("Error in startpageprinter printer handle\n"));
+ return WERR_BADFID;
+ }
+
+ Printer->page_started=True;
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_endpageprinter(pipes_struct *p, SPOOL_Q_ENDPAGEPRINTER *q_u, SPOOL_R_ENDPAGEPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ int snum;
+
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_endpageprinter: Invalid handle (%s:%u:%u).\n",OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if (!get_printer_snum(p, handle, &snum, NULL))
+ return WERR_BADFID;
+
+ Printer->page_started=False;
+ print_job_endpage(snum, Printer->jobid);
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * api_spoolss_getprinter
+ * called from the spoolss dispatcher
+ *
+ ********************************************************************/
+
+WERROR _spoolss_startdocprinter(pipes_struct *p, SPOOL_Q_STARTDOCPRINTER *q_u, SPOOL_R_STARTDOCPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ DOC_INFO *docinfo = &q_u->doc_info_container.docinfo;
+ uint32 *jobid = &r_u->jobid;
+ TALLOC_CTX *ctx = p->mem_ctx;
+ DOC_INFO_1 *info_1 = &docinfo->doc_info_1;
+ int snum;
+ char *jobname = NULL;
+ fstring datatype;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_startdocprinter: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ /*
+ * a nice thing with NT is it doesn't listen to what you tell it.
+ * when asked to send _only_ RAW datas, it tries to send datas
+ * in EMF format.
+ *
+ * So I add checks like in NT Server ...
+ */
+
+ if (info_1->p_datatype != 0) {
+ unistr2_to_ascii(datatype, &info_1->datatype, sizeof(datatype));
+ if (strcmp(datatype, "RAW") != 0) {
+ (*jobid)=0;
+ return WERR_INVALID_DATATYPE;
+ }
+ }
+
+ /* get the share number of the printer */
+ if (!get_printer_snum(p, handle, &snum, NULL)) {
+ return WERR_BADFID;
+ }
+
+ jobname = unistr2_to_ascii_talloc(ctx, &info_1->docname);
+
+ Printer->jobid = print_job_start(p->server_info, snum, jobname,
+ Printer->nt_devmode);
+
+ /* An error occured in print_job_start() so return an appropriate
+ NT error code. */
+
+ if (Printer->jobid == -1) {
+ return map_werror_from_unix(errno);
+ }
+
+ Printer->document_started=True;
+ (*jobid) = Printer->jobid;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * api_spoolss_getprinter
+ * called from the spoolss dispatcher
+ *
+ ********************************************************************/
+
+WERROR _spoolss_enddocprinter(pipes_struct *p, SPOOL_Q_ENDDOCPRINTER *q_u, SPOOL_R_ENDDOCPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+
+ return _spoolss_enddocprinter_internal(p, handle);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_writeprinter(pipes_struct *p, SPOOL_Q_WRITEPRINTER *q_u, SPOOL_R_WRITEPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 buffer_size = q_u->buffer_size;
+ uint8 *buffer = q_u->buffer;
+ uint32 *buffer_written = &q_u->buffer_size2;
+ int snum;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_writeprinter: Invalid handle (%s:%u:%u)\n",OUR_HANDLE(handle)));
+ r_u->buffer_written = q_u->buffer_size2;
+ return WERR_BADFID;
+ }
+
+ if (!get_printer_snum(p, handle, &snum, NULL))
+ return WERR_BADFID;
+
+ (*buffer_written) = (uint32)print_job_write(snum, Printer->jobid, (const char *)buffer,
+ (SMB_OFF_T)-1, (size_t)buffer_size);
+ if (*buffer_written == (uint32)-1) {
+ r_u->buffer_written = 0;
+ if (errno == ENOSPC)
+ return WERR_NO_SPOOL_SPACE;
+ else
+ return WERR_ACCESS_DENIED;
+ }
+
+ r_u->buffer_written = q_u->buffer_size2;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * api_spoolss_getprinter
+ * called from the spoolss dispatcher
+ *
+ ********************************************************************/
+
+static WERROR control_printer(POLICY_HND *handle, uint32 command,
+ pipes_struct *p)
+{
+ int snum;
+ WERROR errcode = WERR_BADFUNC;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ if (!Printer) {
+ DEBUG(2,("control_printer: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if (!get_printer_snum(p, handle, &snum, NULL))
+ return WERR_BADFID;
+
+ switch (command) {
+ case PRINTER_CONTROL_PAUSE:
+ if (print_queue_pause(p->server_info, snum, &errcode)) {
+ errcode = WERR_OK;
+ }
+ break;
+ case PRINTER_CONTROL_RESUME:
+ case PRINTER_CONTROL_UNPAUSE:
+ if (print_queue_resume(p->server_info, snum, &errcode)) {
+ errcode = WERR_OK;
+ }
+ break;
+ case PRINTER_CONTROL_PURGE:
+ if (print_queue_purge(p->server_info, snum, &errcode)) {
+ errcode = WERR_OK;
+ }
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return errcode;
+}
+
+/********************************************************************
+ * api_spoolss_abortprinter
+ * From MSDN: "Deletes printer's spool file if printer is configured
+ * for spooling"
+ ********************************************************************/
+
+WERROR _spoolss_abortprinter(pipes_struct *p, SPOOL_Q_ABORTPRINTER *q_u, SPOOL_R_ABORTPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+ int snum;
+ WERROR errcode = WERR_OK;
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_abortprinter: Invalid handle (%s:%u:%u)\n",OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if (!get_printer_snum(p, handle, &snum, NULL))
+ return WERR_BADFID;
+
+ print_job_delete(p->server_info, snum, Printer->jobid, &errcode );
+
+ return errcode;
+}
+
+/********************************************************************
+ * called by spoolss_api_setprinter
+ * when updating a printer description
+ ********************************************************************/
+
+static WERROR update_printer_sec(POLICY_HND *handle, uint32 level,
+ const SPOOL_PRINTER_INFO_LEVEL *info,
+ pipes_struct *p, SEC_DESC_BUF *secdesc_ctr)
+{
+ SEC_DESC_BUF *new_secdesc_ctr = NULL, *old_secdesc_ctr = NULL;
+ WERROR result;
+ int snum;
+
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ if (!Printer || !get_printer_snum(p, handle, &snum, NULL)) {
+ DEBUG(2,("update_printer_sec: Invalid handle (%s:%u:%u)\n",
+ OUR_HANDLE(handle)));
+
+ result = WERR_BADFID;
+ goto done;
+ }
+
+ if (!secdesc_ctr) {
+ DEBUG(10,("update_printer_sec: secdesc_ctr is NULL !\n"));
+ result = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ /* Check the user has permissions to change the security
+ descriptor. By experimentation with two NT machines, the user
+ requires Full Access to the printer to change security
+ information. */
+
+ if ( Printer->access_granted != PRINTER_ACCESS_ADMINISTER ) {
+ DEBUG(4,("update_printer_sec: updated denied by printer permissions\n"));
+ result = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ /* NT seems to like setting the security descriptor even though
+ nothing may have actually changed. */
+
+ if ( !nt_printing_getsec(p->mem_ctx, Printer->sharename, &old_secdesc_ctr)) {
+ DEBUG(2,("update_printer_sec: nt_printing_getsec() failed\n"));
+ result = WERR_BADFID;
+ goto done;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ SEC_ACL *the_acl;
+ int i;
+
+ the_acl = old_secdesc_ctr->sd->dacl;
+ DEBUG(10, ("old_secdesc_ctr for %s has %d aces:\n",
+ PRINTERNAME(snum), the_acl->num_aces));
+
+ for (i = 0; i < the_acl->num_aces; i++) {
+ DEBUG(10, ("%s 0x%08x\n", sid_string_dbg(
+ &the_acl->aces[i].trustee),
+ the_acl->aces[i].access_mask));
+ }
+
+ the_acl = secdesc_ctr->sd->dacl;
+
+ if (the_acl) {
+ DEBUG(10, ("secdesc_ctr for %s has %d aces:\n",
+ PRINTERNAME(snum), the_acl->num_aces));
+
+ for (i = 0; i < the_acl->num_aces; i++) {
+ DEBUG(10, ("%s 0x%08x\n", sid_string_dbg(
+ &the_acl->aces[i].trustee),
+ the_acl->aces[i].access_mask));
+ }
+ } else {
+ DEBUG(10, ("dacl for secdesc_ctr is NULL\n"));
+ }
+ }
+
+ new_secdesc_ctr = sec_desc_merge(p->mem_ctx, secdesc_ctr, old_secdesc_ctr);
+ if (!new_secdesc_ctr) {
+ result = WERR_NOMEM;
+ goto done;
+ }
+
+ if (sec_desc_equal(new_secdesc_ctr->sd, old_secdesc_ctr->sd)) {
+ result = WERR_OK;
+ goto done;
+ }
+
+ result = nt_printing_setsec(Printer->sharename, new_secdesc_ctr);
+
+ done:
+
+ return result;
+}
+
+/********************************************************************
+ Canonicalize printer info from a client
+
+ ATTN: It does not matter what we set the servername to hear
+ since we do the necessary work in get_a_printer() to set it to
+ the correct value based on what the client sent in the
+ _spoolss_open_printer_ex().
+ ********************************************************************/
+
+static bool check_printer_ok(NT_PRINTER_INFO_LEVEL_2 *info, int snum)
+{
+ fstring printername;
+ const char *p;
+
+ DEBUG(5,("check_printer_ok: servername=%s printername=%s sharename=%s "
+ "portname=%s drivername=%s comment=%s location=%s\n",
+ info->servername, info->printername, info->sharename,
+ info->portname, info->drivername, info->comment, info->location));
+
+ /* we force some elements to "correct" values */
+ slprintf(info->servername, sizeof(info->servername)-1, "\\\\%s", global_myname());
+ fstrcpy(info->sharename, lp_servicename(snum));
+
+ /* check to see if we allow printername != sharename */
+
+ if ( lp_force_printername(snum) ) {
+ slprintf(info->printername, sizeof(info->printername)-1, "\\\\%s\\%s",
+ global_myname(), info->sharename );
+ } else {
+
+ /* make sure printername is in \\server\printername format */
+
+ fstrcpy( printername, info->printername );
+ p = printername;
+ if ( printername[0] == '\\' && printername[1] == '\\' ) {
+ if ( (p = strchr_m( &printername[2], '\\' )) != NULL )
+ p++;
+ }
+
+ slprintf(info->printername, sizeof(info->printername)-1, "\\\\%s\\%s",
+ global_myname(), p );
+ }
+
+ info->attributes |= PRINTER_ATTRIBUTE_SAMBA;
+ info->attributes &= ~PRINTER_ATTRIBUTE_NOT_SAMBA;
+
+
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR add_port_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, const char *portname, const char *uri )
+{
+ char *cmd = lp_addport_cmd();
+ char *command = NULL;
+ int ret;
+ SE_PRIV se_printop = SE_PRINT_OPERATOR;
+ bool is_print_op = False;
+
+ if ( !*cmd ) {
+ return WERR_ACCESS_DENIED;
+ }
+
+ command = talloc_asprintf(ctx,
+ "%s \"%s\" \"%s\"", cmd, portname, uri );
+ if (!command) {
+ return WERR_NOMEM;
+ }
+
+ if ( token )
+ is_print_op = user_has_privileges( token, &se_printop );
+
+ DEBUG(10,("Running [%s]\n", command));
+
+ /********* BEGIN SePrintOperatorPrivilege **********/
+
+ if ( is_print_op )
+ become_root();
+
+ ret = smbrun(command, NULL);
+
+ if ( is_print_op )
+ unbecome_root();
+
+ /********* END SePrintOperatorPrivilege **********/
+
+ DEBUGADD(10,("returned [%d]\n", ret));
+
+ TALLOC_FREE(command);
+
+ if ( ret != 0 ) {
+ return WERR_ACCESS_DENIED;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+bool add_printer_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, NT_PRINTER_INFO_LEVEL *printer)
+{
+ char *cmd = lp_addprinter_cmd();
+ char **qlines;
+ char *command = NULL;
+ int numlines;
+ int ret;
+ int fd;
+ SE_PRIV se_printop = SE_PRINT_OPERATOR;
+ bool is_print_op = False;
+ char *remote_machine = talloc_strdup(ctx, "%m");
+
+ if (!remote_machine) {
+ return false;
+ }
+ remote_machine = talloc_sub_basic(ctx,
+ current_user_info.smb_name,
+ current_user_info.domain,
+ remote_machine);
+ if (!remote_machine) {
+ return false;
+ }
+
+ command = talloc_asprintf(ctx,
+ "%s \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"",
+ cmd, printer->info_2->printername, printer->info_2->sharename,
+ printer->info_2->portname, printer->info_2->drivername,
+ printer->info_2->location, printer->info_2->comment, remote_machine);
+ if (!command) {
+ return false;
+ }
+
+ if ( token )
+ is_print_op = user_has_privileges( token, &se_printop );
+
+ DEBUG(10,("Running [%s]\n", command));
+
+ /********* BEGIN SePrintOperatorPrivilege **********/
+
+ if ( is_print_op )
+ become_root();
+
+ if ( (ret = smbrun(command, &fd)) == 0 ) {
+ /* Tell everyone we updated smb.conf. */
+ message_send_all(smbd_messaging_context(),
+ MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
+ }
+
+ if ( is_print_op )
+ unbecome_root();
+
+ /********* END SePrintOperatorPrivilege **********/
+
+ DEBUGADD(10,("returned [%d]\n", ret));
+
+ TALLOC_FREE(command);
+ TALLOC_FREE(remote_machine);
+
+ if ( ret != 0 ) {
+ if (fd != -1)
+ close(fd);
+ return False;
+ }
+
+ /* reload our services immediately */
+ reload_services( False );
+
+ numlines = 0;
+ /* Get lines and convert them back to dos-codepage */
+ qlines = fd_lines_load(fd, &numlines, 0);
+ DEBUGADD(10,("Lines returned = [%d]\n", numlines));
+ close(fd);
+
+ /* Set the portname to what the script says the portname should be. */
+ /* but don't require anything to be return from the script exit a good error code */
+
+ if (numlines) {
+ /* Set the portname to what the script says the portname should be. */
+ strncpy(printer->info_2->portname, qlines[0], sizeof(printer->info_2->portname));
+ DEBUGADD(6,("Line[0] = [%s]\n", qlines[0]));
+ }
+
+ file_lines_free(qlines);
+ return True;
+}
+
+
+/********************************************************************
+ * Called by spoolss_api_setprinter
+ * when updating a printer description.
+ ********************************************************************/
+
+static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
+ const SPOOL_PRINTER_INFO_LEVEL *info,
+ DEVICEMODE *devmode)
+{
+ int snum;
+ NT_PRINTER_INFO_LEVEL *printer = NULL, *old_printer = NULL;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+ WERROR result;
+ UNISTR2 buffer;
+ fstring asc_buffer;
+
+ DEBUG(8,("update_printer\n"));
+
+ result = WERR_OK;
+
+ if (!Printer) {
+ result = WERR_BADFID;
+ goto done;
+ }
+
+ if (!get_printer_snum(p, handle, &snum, NULL)) {
+ result = WERR_BADFID;
+ goto done;
+ }
+
+ if (!W_ERROR_IS_OK(get_a_printer(Printer, &printer, 2, lp_const_servicename(snum))) ||
+ (!W_ERROR_IS_OK(get_a_printer(Printer, &old_printer, 2, lp_const_servicename(snum))))) {
+ result = WERR_BADFID;
+ goto done;
+ }
+
+ DEBUGADD(8,("Converting info_2 struct\n"));
+
+ /*
+ * convert_printer_info converts the incoming
+ * info from the client and overwrites the info
+ * just read from the tdb in the pointer 'printer'.
+ */
+
+ if (!convert_printer_info(info, printer, level)) {
+ result = WERR_NOMEM;
+ goto done;
+ }
+
+ if (devmode) {
+ /* we have a valid devmode
+ convert it and link it*/
+
+ DEBUGADD(8,("update_printer: Converting the devicemode struct\n"));
+ if (!convert_devicemode(printer->info_2->printername, devmode,
+ &printer->info_2->devmode)) {
+ result = WERR_NOMEM;
+ goto done;
+ }
+ }
+
+ /* Do sanity check on the requested changes for Samba */
+
+ if (!check_printer_ok(printer->info_2, snum)) {
+ result = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ /* FIXME!!! If the driver has changed we really should verify that
+ it is installed before doing much else --jerry */
+
+ /* Check calling user has permission to update printer description */
+
+ if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
+ DEBUG(3, ("update_printer: printer property change denied by handle\n"));
+ result = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ /* Call addprinter hook */
+ /* Check changes to see if this is really needed */
+
+ if ( *lp_addprinter_cmd()
+ && (!strequal(printer->info_2->drivername, old_printer->info_2->drivername)
+ || !strequal(printer->info_2->comment, old_printer->info_2->comment)
+ || !strequal(printer->info_2->portname, old_printer->info_2->portname)
+ || !strequal(printer->info_2->location, old_printer->info_2->location)) )
+ {
+ /* add_printer_hook() will call reload_services() */
+
+ if ( !add_printer_hook(p->mem_ctx, p->pipe_user.nt_user_token, printer) ) {
+ result = WERR_ACCESS_DENIED;
+ goto done;
+ }
+ }
+
+ /*
+ * When a *new* driver is bound to a printer, the drivername is used to
+ * lookup previously saved driver initialization info, which is then
+ * bound to the printer, simulating what happens in the Windows arch.
+ */
+ if (!strequal(printer->info_2->drivername, old_printer->info_2->drivername))
+ {
+ if (!set_driver_init(printer, 2))
+ {
+ DEBUG(5,("update_printer: Error restoring driver initialization data for driver [%s]!\n",
+ printer->info_2->drivername));
+ }
+
+ DEBUG(10,("update_printer: changing driver [%s]! Sending event!\n",
+ printer->info_2->drivername));
+
+ notify_printer_driver(snum, printer->info_2->drivername);
+ }
+
+ /*
+ * flag which changes actually occured. This is a small subset of
+ * all the possible changes. We also have to update things in the
+ * DsSpooler key.
+ */
+
+ if (!strequal(printer->info_2->comment, old_printer->info_2->comment)) {
+ init_unistr2( &buffer, printer->info_2->comment, UNI_STR_TERMINATE);
+ set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "description",
+ REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
+
+ notify_printer_comment(snum, printer->info_2->comment);
+ }
+
+ if (!strequal(printer->info_2->sharename, old_printer->info_2->sharename)) {
+ init_unistr2( &buffer, printer->info_2->sharename, UNI_STR_TERMINATE);
+ set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "shareName",
+ REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
+
+ notify_printer_sharename(snum, printer->info_2->sharename);
+ }
+
+ if (!strequal(printer->info_2->printername, old_printer->info_2->printername)) {
+ char *pname;
+
+ if ( (pname = strchr_m( printer->info_2->printername+2, '\\' )) != NULL )
+ pname++;
+ else
+ pname = printer->info_2->printername;
+
+
+ init_unistr2( &buffer, pname, UNI_STR_TERMINATE);
+ set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "printerName",
+ REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
+
+ notify_printer_printername( snum, pname );
+ }
+
+ if (!strequal(printer->info_2->portname, old_printer->info_2->portname)) {
+ init_unistr2( &buffer, printer->info_2->portname, UNI_STR_TERMINATE);
+ set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "portName",
+ REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
+
+ notify_printer_port(snum, printer->info_2->portname);
+ }
+
+ if (!strequal(printer->info_2->location, old_printer->info_2->location)) {
+ init_unistr2( &buffer, printer->info_2->location, UNI_STR_TERMINATE);
+ set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "location",
+ REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
+
+ notify_printer_location(snum, printer->info_2->location);
+ }
+
+ /* here we need to update some more DsSpooler keys */
+ /* uNCName, serverName, shortServerName */
+
+ init_unistr2( &buffer, global_myname(), UNI_STR_TERMINATE);
+ set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "serverName",
+ REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
+ set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "shortServerName",
+ REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
+
+ slprintf( asc_buffer, sizeof(asc_buffer)-1, "\\\\%s\\%s",
+ global_myname(), printer->info_2->sharename );
+ init_unistr2( &buffer, asc_buffer, UNI_STR_TERMINATE);
+ set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "uNCName",
+ REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
+
+ /* Update printer info */
+ result = mod_a_printer(printer, 2);
+
+done:
+ free_a_printer(&printer, 2);
+ free_a_printer(&old_printer, 2);
+
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR publish_or_unpublish_printer(pipes_struct *p, POLICY_HND *handle,
+ const SPOOL_PRINTER_INFO_LEVEL *info)
+{
+#ifdef HAVE_ADS
+ SPOOL_PRINTER_INFO_LEVEL_7 *info7 = info->info_7;
+ int snum;
+ Printer_entry *Printer;
+
+ if ( lp_security() != SEC_ADS ) {
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ Printer = find_printer_index_by_hnd(p, handle);
+
+ DEBUG(5,("publish_or_unpublish_printer, action = %d\n",info7->action));
+
+ if (!Printer)
+ return WERR_BADFID;
+
+ if (!get_printer_snum(p, handle, &snum, NULL))
+ return WERR_BADFID;
+
+ nt_printer_publish(Printer, snum, info7->action);
+
+ return WERR_OK;
+#else
+ return WERR_UNKNOWN_LEVEL;
+#endif
+}
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_setprinter(pipes_struct *p, SPOOL_Q_SETPRINTER *q_u, SPOOL_R_SETPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 level = q_u->level;
+ SPOOL_PRINTER_INFO_LEVEL *info = &q_u->info;
+ DEVMODE_CTR devmode_ctr = q_u->devmode_ctr;
+ SEC_DESC_BUF *secdesc_ctr = q_u->secdesc_ctr;
+ uint32 command = q_u->command;
+ WERROR result;
+
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_setprinter: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ /* check the level */
+ switch (level) {
+ case 0:
+ return control_printer(handle, command, p);
+ case 2:
+ result = update_printer(p, handle, level, info, devmode_ctr.devmode);
+ if (!W_ERROR_IS_OK(result))
+ return result;
+ if (secdesc_ctr)
+ result = update_printer_sec(handle, level, info, p, secdesc_ctr);
+ return result;
+ case 3:
+ return update_printer_sec(handle, level, info, p,
+ secdesc_ctr);
+ case 7:
+ return publish_or_unpublish_printer(p, handle, info);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_fcpn(pipes_struct *p, SPOOL_Q_FCPN *q_u, SPOOL_R_FCPN *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ Printer_entry *Printer= find_printer_index_by_hnd(p, handle);
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_fcpn: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if (Printer->notify.client_connected==True) {
+ int snum = -1;
+
+ if ( Printer->printer_type == SPLHND_SERVER)
+ snum = -1;
+ else if ( (Printer->printer_type == SPLHND_PRINTER) &&
+ !get_printer_snum(p, handle, &snum, NULL) )
+ return WERR_BADFID;
+
+ srv_spoolss_replycloseprinter(snum, &Printer->notify.client_hnd);
+ }
+
+ Printer->notify.flags=0;
+ Printer->notify.options=0;
+ Printer->notify.localmachine[0]='\0';
+ Printer->notify.printerlocal=0;
+ if (Printer->notify.option)
+ free_spool_notify_option(&Printer->notify.option);
+ Printer->notify.client_connected=False;
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_addjob(pipes_struct *p, SPOOL_Q_ADDJOB *q_u, SPOOL_R_ADDJOB *r_u)
+{
+ /* that's an [in out] buffer */
+
+ if (!q_u->buffer && (q_u->offered!=0)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ rpcbuf_move(q_u->buffer, &r_u->buffer);
+
+ r_u->needed = 0;
+ return WERR_INVALID_PARAM; /* this is what a NT server
+ returns for AddJob. AddJob
+ must fail on non-local
+ printers */
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void fill_job_info_1(JOB_INFO_1 *job_info, const print_queue_struct *queue,
+ int position, int snum,
+ const NT_PRINTER_INFO_LEVEL *ntprinter)
+{
+ struct tm *t;
+
+ t=gmtime(&queue->time);
+
+ job_info->jobid=queue->job;
+ init_unistr(&job_info->printername, lp_servicename(snum));
+ init_unistr(&job_info->machinename, ntprinter->info_2->servername);
+ init_unistr(&job_info->username, queue->fs_user);
+ init_unistr(&job_info->document, queue->fs_file);
+ init_unistr(&job_info->datatype, "RAW");
+ init_unistr(&job_info->text_status, "");
+ job_info->status=nt_printj_status(queue->status);
+ job_info->priority=queue->priority;
+ job_info->position=position;
+ job_info->totalpages=queue->page_count;
+ job_info->pagesprinted=0;
+
+ make_systemtime(&job_info->submitted, t);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool fill_job_info_2(JOB_INFO_2 *job_info, const print_queue_struct *queue,
+ int position, int snum,
+ const NT_PRINTER_INFO_LEVEL *ntprinter,
+ DEVICEMODE *devmode)
+{
+ struct tm *t;
+
+ t=gmtime(&queue->time);
+
+ job_info->jobid=queue->job;
+
+ init_unistr(&job_info->printername, ntprinter->info_2->printername);
+
+ init_unistr(&job_info->machinename, ntprinter->info_2->servername);
+ init_unistr(&job_info->username, queue->fs_user);
+ init_unistr(&job_info->document, queue->fs_file);
+ init_unistr(&job_info->notifyname, queue->fs_user);
+ init_unistr(&job_info->datatype, "RAW");
+ init_unistr(&job_info->printprocessor, "winprint");
+ init_unistr(&job_info->parameters, "");
+ init_unistr(&job_info->drivername, ntprinter->info_2->drivername);
+ init_unistr(&job_info->text_status, "");
+
+/* and here the security descriptor */
+
+ job_info->status=nt_printj_status(queue->status);
+ job_info->priority=queue->priority;
+ job_info->position=position;
+ job_info->starttime=0;
+ job_info->untiltime=0;
+ job_info->totalpages=queue->page_count;
+ job_info->size=queue->size;
+ make_systemtime(&(job_info->submitted), t);
+ job_info->timeelapsed=0;
+ job_info->pagesprinted=0;
+
+ job_info->devmode = devmode;
+
+ return (True);
+}
+
+/****************************************************************************
+ Enumjobs at level 1.
+****************************************************************************/
+
+static WERROR enumjobs_level1(const print_queue_struct *queue, int snum,
+ const NT_PRINTER_INFO_LEVEL *ntprinter,
+ RPC_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+ JOB_INFO_1 *info;
+ int i;
+ WERROR result = WERR_OK;
+
+ info=SMB_MALLOC_ARRAY(JOB_INFO_1,*returned);
+ if (info==NULL) {
+ *returned=0;
+ return WERR_NOMEM;
+ }
+
+ for (i=0; i<*returned; i++)
+ fill_job_info_1( &info[i], &queue[i], i, snum, ntprinter );
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++)
+ (*needed) += spoolss_size_job_info_1(&info[i]);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the structures */
+ for (i=0; i<*returned; i++)
+ smb_io_job_info_1("", buffer, &info[i], 0);
+
+out:
+ /* clear memory */
+ SAFE_FREE(info);
+
+ if ( !W_ERROR_IS_OK(result) )
+ *returned = 0;
+
+ return result;
+}
+
+/****************************************************************************
+ Enumjobs at level 2.
+****************************************************************************/
+
+static WERROR enumjobs_level2(const print_queue_struct *queue, int snum,
+ const NT_PRINTER_INFO_LEVEL *ntprinter,
+ RPC_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+ JOB_INFO_2 *info = NULL;
+ int i;
+ WERROR result = WERR_OK;
+ DEVICEMODE *devmode = NULL;
+
+ if ( !(info = SMB_MALLOC_ARRAY(JOB_INFO_2,*returned)) ) {
+ *returned=0;
+ return WERR_NOMEM;
+ }
+
+ /* this should not be a failure condition if the devmode is NULL */
+
+ devmode = construct_dev_mode(lp_const_servicename(snum));
+
+ for (i=0; i<*returned; i++)
+ fill_job_info_2(&(info[i]), &queue[i], i, snum, ntprinter, devmode);
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++)
+ (*needed) += spoolss_size_job_info_2(&info[i]);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the structures */
+ for (i=0; i<*returned; i++)
+ smb_io_job_info_2("", buffer, &info[i], 0);
+
+out:
+ free_devmode(devmode);
+ SAFE_FREE(info);
+
+ if ( !W_ERROR_IS_OK(result) )
+ *returned = 0;
+
+ return result;
+
+}
+
+/****************************************************************************
+ Enumjobs.
+****************************************************************************/
+
+WERROR _spoolss_enumjobs( pipes_struct *p, SPOOL_Q_ENUMJOBS *q_u, SPOOL_R_ENUMJOBS *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 level = q_u->level;
+ RPC_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *returned = &r_u->returned;
+ WERROR wret;
+ NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+ int snum;
+ print_status_struct prt_status;
+ print_queue_struct *queue=NULL;
+
+ /* that's an [in out] buffer */
+
+ if (!q_u->buffer && (offered!=0)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ rpcbuf_move(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(4,("_spoolss_enumjobs\n"));
+
+ *needed=0;
+ *returned=0;
+
+ /* lookup the printer snum and tdb entry */
+
+ if (!get_printer_snum(p, handle, &snum, NULL))
+ return WERR_BADFID;
+
+ wret = get_a_printer(NULL, &ntprinter, 2, lp_servicename(snum));
+ if ( !W_ERROR_IS_OK(wret) )
+ return wret;
+
+ *returned = print_queue_status(snum, &queue, &prt_status);
+ DEBUGADD(4,("count:[%d], status:[%d], [%s]\n", *returned, prt_status.status, prt_status.message));
+
+ if (*returned == 0) {
+ SAFE_FREE(queue);
+ free_a_printer(&ntprinter, 2);
+ return WERR_OK;
+ }
+
+ switch (level) {
+ case 1:
+ wret = enumjobs_level1(queue, snum, ntprinter, buffer, offered, needed, returned);
+ break;
+ case 2:
+ wret = enumjobs_level2(queue, snum, ntprinter, buffer, offered, needed, returned);
+ break;
+ default:
+ *returned=0;
+ wret = WERR_UNKNOWN_LEVEL;
+ break;
+ }
+
+ SAFE_FREE(queue);
+ free_a_printer( &ntprinter, 2 );
+ return wret;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_schedulejob( pipes_struct *p, SPOOL_Q_SCHEDULEJOB *q_u, SPOOL_R_SCHEDULEJOB *r_u)
+{
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_setjob(pipes_struct *p, SPOOL_Q_SETJOB *q_u, SPOOL_R_SETJOB *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 jobid = q_u->jobid;
+ uint32 command = q_u->command;
+
+ int snum;
+ WERROR errcode = WERR_BADFUNC;
+
+ if (!get_printer_snum(p, handle, &snum, NULL)) {
+ return WERR_BADFID;
+ }
+
+ if (!print_job_exists(lp_const_servicename(snum), jobid)) {
+ return WERR_INVALID_PRINTER_NAME;
+ }
+
+ switch (command) {
+ case JOB_CONTROL_CANCEL:
+ case JOB_CONTROL_DELETE:
+ if (print_job_delete(p->server_info, snum, jobid, &errcode)) {
+ errcode = WERR_OK;
+ }
+ break;
+ case JOB_CONTROL_PAUSE:
+ if (print_job_pause(p->server_info, snum, jobid, &errcode)) {
+ errcode = WERR_OK;
+ }
+ break;
+ case JOB_CONTROL_RESTART:
+ case JOB_CONTROL_RESUME:
+ if (print_job_resume(p->server_info, snum, jobid, &errcode)) {
+ errcode = WERR_OK;
+ }
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return errcode;
+}
+
+/****************************************************************************
+ Enumerates all printer drivers at level 1.
+****************************************************************************/
+
+static WERROR enumprinterdrivers_level1(const char *servername, fstring architecture, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ int i;
+ int ndrivers;
+ uint32 version;
+ fstring *list = NULL;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ DRIVER_INFO_1 *driver_info_1=NULL;
+ WERROR result = WERR_OK;
+
+ *returned=0;
+
+ for (version=0; version<DRIVER_MAX_VERSION; version++) {
+ list=NULL;
+ ndrivers=get_ntdrivers(&list, architecture, version);
+ DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n", ndrivers, architecture, version));
+
+ if(ndrivers == -1) {
+ SAFE_FREE(driver_info_1);
+ return WERR_NOMEM;
+ }
+
+ if(ndrivers != 0) {
+ if((driver_info_1=SMB_REALLOC_ARRAY(driver_info_1, DRIVER_INFO_1, *returned+ndrivers )) == NULL) {
+ DEBUG(0,("enumprinterdrivers_level1: failed to enlarge driver info buffer!\n"));
+ SAFE_FREE(list);
+ return WERR_NOMEM;
+ }
+ }
+
+ for (i=0; i<ndrivers; i++) {
+ WERROR status;
+ DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
+ ZERO_STRUCT(driver);
+ status = get_a_printer_driver(&driver, 3, list[i],
+ architecture, version);
+ if (!W_ERROR_IS_OK(status)) {
+ SAFE_FREE(list);
+ SAFE_FREE(driver_info_1);
+ return status;
+ }
+ fill_printer_driver_info_1(&driver_info_1[*returned+i], driver, servername, architecture );
+ free_a_printer_driver(driver, 3);
+ }
+
+ *returned+=ndrivers;
+ SAFE_FREE(list);
+ }
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding driver [%d]'s size\n",i));
+ *needed += spoolss_size_printer_driver_info_1(&driver_info_1[i]);
+ }
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the driver structures */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding driver [%d] to buffer\n",i));
+ smb_io_printer_driver_info_1("", buffer, &driver_info_1[i], 0);
+ }
+
+out:
+ SAFE_FREE(driver_info_1);
+
+ if ( !W_ERROR_IS_OK(result) )
+ *returned = 0;
+
+ return result;
+}
+
+/****************************************************************************
+ Enumerates all printer drivers at level 2.
+****************************************************************************/
+
+static WERROR enumprinterdrivers_level2(const char *servername, fstring architecture, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ int i;
+ int ndrivers;
+ uint32 version;
+ fstring *list = NULL;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ DRIVER_INFO_2 *driver_info_2=NULL;
+ WERROR result = WERR_OK;
+
+ *returned=0;
+
+ for (version=0; version<DRIVER_MAX_VERSION; version++) {
+ list=NULL;
+ ndrivers=get_ntdrivers(&list, architecture, version);
+ DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n", ndrivers, architecture, version));
+
+ if(ndrivers == -1) {
+ SAFE_FREE(driver_info_2);
+ return WERR_NOMEM;
+ }
+
+ if(ndrivers != 0) {
+ if((driver_info_2=SMB_REALLOC_ARRAY(driver_info_2, DRIVER_INFO_2, *returned+ndrivers )) == NULL) {
+ DEBUG(0,("enumprinterdrivers_level2: failed to enlarge driver info buffer!\n"));
+ SAFE_FREE(list);
+ return WERR_NOMEM;
+ }
+ }
+
+ for (i=0; i<ndrivers; i++) {
+ WERROR status;
+
+ DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
+ ZERO_STRUCT(driver);
+ status = get_a_printer_driver(&driver, 3, list[i],
+ architecture, version);
+ if (!W_ERROR_IS_OK(status)) {
+ SAFE_FREE(list);
+ SAFE_FREE(driver_info_2);
+ return status;
+ }
+ fill_printer_driver_info_2(&driver_info_2[*returned+i], driver, servername);
+ free_a_printer_driver(driver, 3);
+ }
+
+ *returned+=ndrivers;
+ SAFE_FREE(list);
+ }
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding driver [%d]'s size\n",i));
+ *needed += spoolss_size_printer_driver_info_2(&(driver_info_2[i]));
+ }
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the form structures */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding driver [%d] to buffer\n",i));
+ smb_io_printer_driver_info_2("", buffer, &(driver_info_2[i]), 0);
+ }
+
+out:
+ SAFE_FREE(driver_info_2);
+
+ if ( !W_ERROR_IS_OK(result) )
+ *returned = 0;
+
+ return result;
+}
+
+/****************************************************************************
+ Enumerates all printer drivers at level 3.
+****************************************************************************/
+
+static WERROR enumprinterdrivers_level3(const char *servername, fstring architecture, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ int i;
+ int ndrivers;
+ uint32 version;
+ fstring *list = NULL;
+ DRIVER_INFO_3 *driver_info_3=NULL;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ WERROR result = WERR_OK;
+
+ *returned=0;
+
+ for (version=0; version<DRIVER_MAX_VERSION; version++) {
+ list=NULL;
+ ndrivers=get_ntdrivers(&list, architecture, version);
+ DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n", ndrivers, architecture, version));
+
+ if(ndrivers == -1) {
+ SAFE_FREE(driver_info_3);
+ return WERR_NOMEM;
+ }
+
+ if(ndrivers != 0) {
+ if((driver_info_3=SMB_REALLOC_ARRAY(driver_info_3, DRIVER_INFO_3, *returned+ndrivers )) == NULL) {
+ DEBUG(0,("enumprinterdrivers_level3: failed to enlarge driver info buffer!\n"));
+ SAFE_FREE(list);
+ return WERR_NOMEM;
+ }
+ }
+
+ for (i=0; i<ndrivers; i++) {
+ WERROR status;
+
+ DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
+ ZERO_STRUCT(driver);
+ status = get_a_printer_driver(&driver, 3, list[i],
+ architecture, version);
+ if (!W_ERROR_IS_OK(status)) {
+ SAFE_FREE(list);
+ SAFE_FREE(driver_info_3);
+ return status;
+ }
+ fill_printer_driver_info_3(&driver_info_3[*returned+i], driver, servername);
+ free_a_printer_driver(driver, 3);
+ }
+
+ *returned+=ndrivers;
+ SAFE_FREE(list);
+ }
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding driver [%d]'s size\n",i));
+ *needed += spoolss_size_printer_driver_info_3(&driver_info_3[i]);
+ }
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the driver structures */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding driver [%d] to buffer\n",i));
+ smb_io_printer_driver_info_3("", buffer, &driver_info_3[i], 0);
+ }
+
+out:
+ for (i=0; i<*returned; i++) {
+ SAFE_FREE(driver_info_3[i].dependentfiles);
+ }
+
+ SAFE_FREE(driver_info_3);
+
+ if ( !W_ERROR_IS_OK(result) )
+ *returned = 0;
+
+ return result;
+}
+
+/****************************************************************************
+ Enumerates all printer drivers.
+****************************************************************************/
+
+WERROR _spoolss_enumprinterdrivers( pipes_struct *p, SPOOL_Q_ENUMPRINTERDRIVERS *q_u, SPOOL_R_ENUMPRINTERDRIVERS *r_u)
+{
+ uint32 level = q_u->level;
+ RPC_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *returned = &r_u->returned;
+ const char *cservername;
+ fstring servername;
+ fstring architecture;
+
+ /* that's an [in out] buffer */
+
+ if (!q_u->buffer && (offered!=0)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ rpcbuf_move(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(4,("_spoolss_enumprinterdrivers\n"));
+
+ *needed = 0;
+ *returned = 0;
+
+ unistr2_to_ascii(architecture, &q_u->environment, sizeof(architecture));
+ unistr2_to_ascii(servername, &q_u->name, sizeof(servername));
+
+ cservername = canon_servername(servername);
+
+ if (!is_myname_or_ipaddr(cservername))
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+
+ switch (level) {
+ case 1:
+ return enumprinterdrivers_level1(cservername, architecture, buffer, offered, needed, returned);
+ case 2:
+ return enumprinterdrivers_level2(cservername, architecture, buffer, offered, needed, returned);
+ case 3:
+ return enumprinterdrivers_level3(cservername, architecture, buffer, offered, needed, returned);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void fill_form_1(FORM_1 *form, nt_forms_struct *list)
+{
+ form->flag=list->flag;
+ init_unistr(&form->name, list->name);
+ form->width=list->width;
+ form->length=list->length;
+ form->left=list->left;
+ form->top=list->top;
+ form->right=list->right;
+ form->bottom=list->bottom;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_enumforms(pipes_struct *p, SPOOL_Q_ENUMFORMS *q_u, SPOOL_R_ENUMFORMS *r_u)
+{
+ uint32 level = q_u->level;
+ RPC_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *numofforms = &r_u->numofforms;
+ uint32 numbuiltinforms;
+
+ nt_forms_struct *list=NULL;
+ nt_forms_struct *builtinlist=NULL;
+ FORM_1 *forms_1;
+ int buffer_size=0;
+ int i;
+
+ /* that's an [in out] buffer */
+
+ if (!q_u->buffer && (offered!=0) ) {
+ return WERR_INVALID_PARAM;
+ }
+
+ rpcbuf_move(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(4,("_spoolss_enumforms\n"));
+ DEBUGADD(5,("Offered buffer size [%d]\n", offered));
+ DEBUGADD(5,("Info level [%d]\n", level));
+
+ numbuiltinforms = get_builtin_ntforms(&builtinlist);
+ DEBUGADD(5,("Number of builtin forms [%d]\n", numbuiltinforms));
+ *numofforms = get_ntforms(&list);
+ DEBUGADD(5,("Number of user forms [%d]\n", *numofforms));
+ *numofforms += numbuiltinforms;
+
+ if (*numofforms == 0) {
+ SAFE_FREE(builtinlist);
+ SAFE_FREE(list);
+ return WERR_NO_MORE_ITEMS;
+ }
+
+ switch (level) {
+ case 1:
+ if ((forms_1=SMB_MALLOC_ARRAY(FORM_1, *numofforms)) == NULL) {
+ SAFE_FREE(builtinlist);
+ SAFE_FREE(list);
+ *numofforms=0;
+ return WERR_NOMEM;
+ }
+
+ /* construct the list of form structures */
+ for (i=0; i<numbuiltinforms; i++) {
+ DEBUGADD(6,("Filling form number [%d]\n",i));
+ fill_form_1(&forms_1[i], &builtinlist[i]);
+ }
+
+ SAFE_FREE(builtinlist);
+
+ for (; i<*numofforms; i++) {
+ DEBUGADD(6,("Filling form number [%d]\n",i));
+ fill_form_1(&forms_1[i], &list[i-numbuiltinforms]);
+ }
+
+ SAFE_FREE(list);
+
+ /* check the required size. */
+ for (i=0; i<numbuiltinforms; i++) {
+ DEBUGADD(6,("adding form [%d]'s size\n",i));
+ buffer_size += spoolss_size_form_1(&forms_1[i]);
+ }
+ for (; i<*numofforms; i++) {
+ DEBUGADD(6,("adding form [%d]'s size\n",i));
+ buffer_size += spoolss_size_form_1(&forms_1[i]);
+ }
+
+ *needed=buffer_size;
+
+ if (*needed > offered) {
+ SAFE_FREE(forms_1);
+ *numofforms=0;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, buffer_size)){
+ SAFE_FREE(forms_1);
+ *numofforms=0;
+ return WERR_NOMEM;
+ }
+
+ /* fill the buffer with the form structures */
+ for (i=0; i<numbuiltinforms; i++) {
+ DEBUGADD(6,("adding form [%d] to buffer\n",i));
+ smb_io_form_1("", buffer, &forms_1[i], 0);
+ }
+ for (; i<*numofforms; i++) {
+ DEBUGADD(6,("adding form [%d] to buffer\n",i));
+ smb_io_form_1("", buffer, &forms_1[i], 0);
+ }
+
+ SAFE_FREE(forms_1);
+
+ return WERR_OK;
+
+ default:
+ SAFE_FREE(list);
+ SAFE_FREE(builtinlist);
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_getform(pipes_struct *p, SPOOL_Q_GETFORM *q_u, SPOOL_R_GETFORM *r_u)
+{
+ uint32 level = q_u->level;
+ UNISTR2 *uni_formname = &q_u->formname;
+ RPC_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+
+ nt_forms_struct *list=NULL;
+ nt_forms_struct builtin_form;
+ bool foundBuiltin;
+ FORM_1 form_1;
+ fstring form_name;
+ int buffer_size=0;
+ int numofforms=0, i=0;
+
+ /* that's an [in out] buffer */
+
+ if (!q_u->buffer && (offered!=0)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ rpcbuf_move(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ unistr2_to_ascii(form_name, uni_formname, sizeof(form_name));
+
+ DEBUG(4,("_spoolss_getform\n"));
+ DEBUGADD(5,("Offered buffer size [%d]\n", offered));
+ DEBUGADD(5,("Info level [%d]\n", level));
+
+ foundBuiltin = get_a_builtin_ntform(uni_formname,&builtin_form);
+ if (!foundBuiltin) {
+ numofforms = get_ntforms(&list);
+ DEBUGADD(5,("Number of forms [%d]\n", numofforms));
+
+ if (numofforms == 0)
+ return WERR_BADFID;
+ }
+
+ switch (level) {
+ case 1:
+ if (foundBuiltin) {
+ fill_form_1(&form_1, &builtin_form);
+ } else {
+
+ /* Check if the requested name is in the list of form structures */
+ for (i=0; i<numofforms; i++) {
+
+ DEBUG(4,("_spoolss_getform: checking form %s (want %s)\n", list[i].name, form_name));
+
+ if (strequal(form_name, list[i].name)) {
+ DEBUGADD(6,("Found form %s number [%d]\n", form_name, i));
+ fill_form_1(&form_1, &list[i]);
+ break;
+ }
+ }
+
+ SAFE_FREE(list);
+ if (i == numofforms) {
+ return WERR_BADFID;
+ }
+ }
+ /* check the required size. */
+
+ *needed=spoolss_size_form_1(&form_1);
+
+ if (*needed > offered)
+ return WERR_INSUFFICIENT_BUFFER;
+
+ if (!rpcbuf_alloc_size(buffer, buffer_size))
+ return WERR_NOMEM;
+
+ /* fill the buffer with the form structures */
+ DEBUGADD(6,("adding form %s [%d] to buffer\n", form_name, i));
+ smb_io_form_1("", buffer, &form_1, 0);
+
+ return WERR_OK;
+
+ default:
+ SAFE_FREE(list);
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void fill_port_1(PORT_INFO_1 *port, const char *name)
+{
+ init_unistr(&port->port_name, name);
+}
+
+/****************************************************************************
+ TODO: This probably needs distinguish between TCP/IP and Local ports
+ somehow.
+****************************************************************************/
+
+static void fill_port_2(PORT_INFO_2 *port, const char *name)
+{
+ init_unistr(&port->port_name, name);
+ init_unistr(&port->monitor_name, "Local Monitor");
+ init_unistr(&port->description, SPL_LOCAL_PORT );
+ port->port_type=PORT_TYPE_WRITE;
+ port->reserved=0x0;
+}
+
+
+/****************************************************************************
+ wrapper around the enumer ports command
+****************************************************************************/
+
+WERROR enumports_hook(TALLOC_CTX *ctx, int *count, char ***lines )
+{
+ char *cmd = lp_enumports_cmd();
+ char **qlines = NULL;
+ char *command = NULL;
+ int numlines;
+ int ret;
+ int fd;
+
+ *count = 0;
+ *lines = NULL;
+
+ /* if no hook then just fill in the default port */
+
+ if ( !*cmd ) {
+ if (!(qlines = SMB_MALLOC_ARRAY( char*, 2 ))) {
+ return WERR_NOMEM;
+ }
+ if (!(qlines[0] = SMB_STRDUP( SAMBA_PRINTER_PORT_NAME ))) {
+ SAFE_FREE(qlines);
+ return WERR_NOMEM;
+ }
+ qlines[1] = NULL;
+ numlines = 1;
+ }
+ else {
+ /* we have a valid enumport command */
+
+ command = talloc_asprintf(ctx, "%s \"%d\"", cmd, 1);
+ if (!command) {
+ return WERR_NOMEM;
+ }
+
+ DEBUG(10,("Running [%s]\n", command));
+ ret = smbrun(command, &fd);
+ DEBUG(10,("Returned [%d]\n", ret));
+ TALLOC_FREE(command);
+ if (ret != 0) {
+ if (fd != -1) {
+ close(fd);
+ }
+ return WERR_ACCESS_DENIED;
+ }
+
+ numlines = 0;
+ qlines = fd_lines_load(fd, &numlines, 0);
+ DEBUGADD(10,("Lines returned = [%d]\n", numlines));
+ close(fd);
+ }
+
+ *count = numlines;
+ *lines = qlines;
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ enumports level 1.
+****************************************************************************/
+
+static WERROR enumports_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ PORT_INFO_1 *ports=NULL;
+ int i=0;
+ WERROR result = WERR_OK;
+ char **qlines = NULL;
+ int numlines = 0;
+
+ result = enumports_hook(talloc_tos(), &numlines, &qlines );
+ if (!W_ERROR_IS_OK(result)) {
+ file_lines_free(qlines);
+ return result;
+ }
+
+ if(numlines) {
+ if((ports=SMB_MALLOC_ARRAY( PORT_INFO_1, numlines )) == NULL) {
+ DEBUG(10,("Returning WERR_NOMEM [%s]\n",
+ dos_errstr(WERR_NOMEM)));
+ file_lines_free(qlines);
+ return WERR_NOMEM;
+ }
+
+ for (i=0; i<numlines; i++) {
+ DEBUG(6,("Filling port number [%d] with port [%s]\n", i, qlines[i]));
+ fill_port_1(&ports[i], qlines[i]);
+ }
+ }
+ file_lines_free(qlines);
+
+ *returned = numlines;
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding port [%d]'s size\n", i));
+ *needed += spoolss_size_port_info_1(&ports[i]);
+ }
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the ports structures */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding port [%d] to buffer\n", i));
+ smb_io_port_1("", buffer, &ports[i], 0);
+ }
+
+out:
+ SAFE_FREE(ports);
+
+ if ( !W_ERROR_IS_OK(result) )
+ *returned = 0;
+
+ return result;
+}
+
+/****************************************************************************
+ enumports level 2.
+****************************************************************************/
+
+static WERROR enumports_level_2(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ PORT_INFO_2 *ports=NULL;
+ int i=0;
+ WERROR result = WERR_OK;
+ char **qlines = NULL;
+ int numlines = 0;
+
+ result = enumports_hook(talloc_tos(), &numlines, &qlines );
+ if ( !W_ERROR_IS_OK(result)) {
+ file_lines_free(qlines);
+ return result;
+ }
+
+ if(numlines) {
+ if((ports=SMB_MALLOC_ARRAY( PORT_INFO_2, numlines)) == NULL) {
+ file_lines_free(qlines);
+ return WERR_NOMEM;
+ }
+
+ for (i=0; i<numlines; i++) {
+ DEBUG(6,("Filling port number [%d] with port [%s]\n", i, qlines[i]));
+ fill_port_2(&(ports[i]), qlines[i]);
+ }
+ }
+
+ file_lines_free(qlines);
+
+ *returned = numlines;
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding port [%d]'s size\n", i));
+ *needed += spoolss_size_port_info_2(&ports[i]);
+ }
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ /* fill the buffer with the ports structures */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding port [%d] to buffer\n", i));
+ smb_io_port_2("", buffer, &ports[i], 0);
+ }
+
+out:
+ SAFE_FREE(ports);
+
+ if ( !W_ERROR_IS_OK(result) )
+ *returned = 0;
+
+ return result;
+}
+
+/****************************************************************************
+ enumports.
+****************************************************************************/
+
+WERROR _spoolss_enumports( pipes_struct *p, SPOOL_Q_ENUMPORTS *q_u, SPOOL_R_ENUMPORTS *r_u)
+{
+ uint32 level = q_u->level;
+ RPC_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *returned = &r_u->returned;
+
+ /* that's an [in out] buffer */
+
+ if (!q_u->buffer && (offered!=0)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ rpcbuf_move(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(4,("_spoolss_enumports\n"));
+
+ *returned=0;
+ *needed=0;
+
+ switch (level) {
+ case 1:
+ return enumports_level_1(buffer, offered, needed, returned);
+ case 2:
+ return enumports_level_2(buffer, offered, needed, returned);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_srv_name,
+ const SPOOL_PRINTER_INFO_LEVEL *info,
+ DEVICEMODE *devmode, SEC_DESC_BUF *sec_desc_buf,
+ uint32 user_switch, const SPOOL_USER_CTR *user,
+ POLICY_HND *handle)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ fstring name;
+ int snum;
+ WERROR err = WERR_OK;
+
+ if ( !(printer = TALLOC_ZERO_P(NULL, NT_PRINTER_INFO_LEVEL)) ) {
+ DEBUG(0,("spoolss_addprinterex_level_2: malloc fail.\n"));
+ return WERR_NOMEM;
+ }
+
+ /* convert from UNICODE to ASCII - this allocates the info_2 struct inside *printer.*/
+ if (!convert_printer_info(info, printer, 2)) {
+ free_a_printer(&printer, 2);
+ return WERR_NOMEM;
+ }
+
+ /* check to see if the printer already exists */
+
+ if ((snum = print_queue_snum(printer->info_2->sharename)) != -1) {
+ DEBUG(5, ("spoolss_addprinterex_level_2: Attempted to add a printer named [%s] when one already existed!\n",
+ printer->info_2->sharename));
+ free_a_printer(&printer, 2);
+ return WERR_PRINTER_ALREADY_EXISTS;
+ }
+
+ /* FIXME!!! smbd should check to see if the driver is installed before
+ trying to add a printer like this --jerry */
+
+ if (*lp_addprinter_cmd() ) {
+ if ( !add_printer_hook(p->mem_ctx, p->pipe_user.nt_user_token, printer) ) {
+ free_a_printer(&printer,2);
+ return WERR_ACCESS_DENIED;
+ }
+ } else {
+ DEBUG(0,("spoolss_addprinterex_level_2: add printer for printer %s called and no"
+ "smb.conf parameter \"addprinter command\" is defined. This"
+ "parameter must exist for this call to succeed\n",
+ printer->info_2->sharename ));
+ }
+
+ /* use our primary netbios name since get_a_printer() will convert
+ it to what the client expects on a case by case basis */
+
+ slprintf(name, sizeof(name)-1, "\\\\%s\\%s", global_myname(),
+ printer->info_2->sharename);
+
+
+ if ((snum = print_queue_snum(printer->info_2->sharename)) == -1) {
+ free_a_printer(&printer,2);
+ return WERR_ACCESS_DENIED;
+ }
+
+ /* you must be a printer admin to add a new printer */
+ if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
+ free_a_printer(&printer,2);
+ return WERR_ACCESS_DENIED;
+ }
+
+ /*
+ * Do sanity check on the requested changes for Samba.
+ */
+
+ if (!check_printer_ok(printer->info_2, snum)) {
+ free_a_printer(&printer,2);
+ return WERR_INVALID_PARAM;
+ }
+
+ /*
+ * When a printer is created, the drivername bound to the printer is used
+ * to lookup previously saved driver initialization info, which is then
+ * bound to the new printer, simulating what happens in the Windows arch.
+ */
+
+ if (!devmode)
+ {
+ set_driver_init(printer, 2);
+ }
+ else
+ {
+ /* A valid devmode was included, convert and link it
+ */
+ DEBUGADD(10, ("spoolss_addprinterex_level_2: devmode included, converting\n"));
+
+ if (!convert_devicemode(printer->info_2->printername, devmode,
+ &printer->info_2->devmode))
+ return WERR_NOMEM;
+ }
+
+ /* write the ASCII on disk */
+ err = mod_a_printer(printer, 2);
+ if (!W_ERROR_IS_OK(err)) {
+ free_a_printer(&printer,2);
+ return err;
+ }
+
+ if (!open_printer_hnd(p, handle, name, PRINTER_ACCESS_ADMINISTER)) {
+ /* Handle open failed - remove addition. */
+ del_a_printer(printer->info_2->sharename);
+ free_a_printer(&printer,2);
+ return WERR_ACCESS_DENIED;
+ }
+
+ update_c_setprinter(False);
+ free_a_printer(&printer,2);
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_addprinterex( pipes_struct *p, SPOOL_Q_ADDPRINTEREX *q_u, SPOOL_R_ADDPRINTEREX *r_u)
+{
+ UNISTR2 *uni_srv_name = q_u->server_name;
+ uint32 level = q_u->level;
+ SPOOL_PRINTER_INFO_LEVEL *info = &q_u->info;
+ DEVICEMODE *devmode = q_u->devmode_ctr.devmode;
+ SEC_DESC_BUF *sdb = q_u->secdesc_ctr;
+ uint32 user_switch = q_u->user_switch;
+ SPOOL_USER_CTR *user = &q_u->user_ctr;
+ POLICY_HND *handle = &r_u->handle;
+
+ switch (level) {
+ case 1:
+ /* we don't handle yet */
+ /* but I know what to do ... */
+ return WERR_UNKNOWN_LEVEL;
+ case 2:
+ return spoolss_addprinterex_level_2(p, uni_srv_name, info,
+ devmode, sdb,
+ user_switch, user, handle);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_addprinterdriver(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVER *q_u, SPOOL_R_ADDPRINTERDRIVER *r_u)
+{
+ uint32 level = q_u->level;
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL *info = &q_u->info;
+ WERROR err = WERR_OK;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ fstring driver_name;
+ uint32 version;
+
+ ZERO_STRUCT(driver);
+
+ if (!convert_printer_driver_info(info, &driver, level)) {
+ err = WERR_NOMEM;
+ goto done;
+ }
+
+ DEBUG(5,("Cleaning driver's information\n"));
+ err = clean_up_driver_struct(driver, level, &p->pipe_user);
+ if (!W_ERROR_IS_OK(err))
+ goto done;
+
+ DEBUG(5,("Moving driver to final destination\n"));
+ if( !W_ERROR_IS_OK(err = move_driver_to_download_area(driver, level, &p->pipe_user, &err)) ) {
+ goto done;
+ }
+
+ if (add_a_printer_driver(driver, level)!=0) {
+ err = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ switch(level) {
+ case 3:
+ fstrcpy(driver_name,
+ driver.info_3->name ? driver.info_3->name : "");
+ break;
+ case 6:
+ fstrcpy(driver_name,
+ driver.info_6->name ? driver.info_6->name : "");
+ break;
+ }
+
+ /*
+ * I think this is where he DrvUpgradePrinter() hook would be
+ * be called in a driver's interface DLL on a Windows NT 4.0/2k
+ * server. Right now, we just need to send ourselves a message
+ * to update each printer bound to this driver. --jerry
+ */
+
+ if (!srv_spoolss_drv_upgrade_printer(driver_name)) {
+ DEBUG(0,("_spoolss_addprinterdriver: Failed to send message about upgrading driver [%s]!\n",
+ driver_name));
+ }
+
+ /*
+ * Based on the version (e.g. driver destination dir: 0=9x,2=Nt/2k,3=2k/Xp),
+ * decide if the driver init data should be deleted. The rules are:
+ * 1) never delete init data if it is a 9x driver, they don't use it anyway
+ * 2) delete init data only if there is no 2k/Xp driver
+ * 3) always delete init data
+ * The generalized rule is always use init data from the highest order driver.
+ * It is necessary to follow the driver install by an initialization step to
+ * finish off this process.
+ */
+ if (level == 3)
+ version = driver.info_3->cversion;
+ else if (level == 6)
+ version = driver.info_6->version;
+ else
+ version = -1;
+ switch (version) {
+ /*
+ * 9x printer driver - never delete init data
+ */
+ case 0:
+ DEBUG(10,("_spoolss_addprinterdriver: init data not deleted for 9x driver [%s]\n",
+ driver_name));
+ break;
+
+ /*
+ * Nt or 2k (compatiblity mode) printer driver - only delete init data if
+ * there is no 2k/Xp driver init data for this driver name.
+ */
+ case 2:
+ {
+ NT_PRINTER_DRIVER_INFO_LEVEL driver1;
+
+ if (!W_ERROR_IS_OK(get_a_printer_driver(&driver1, 3, driver_name, "Windows NT x86", 3))) {
+ /*
+ * No 2k/Xp driver found, delete init data (if any) for the new Nt driver.
+ */
+ if (!del_driver_init(driver_name))
+ DEBUG(6,("_spoolss_addprinterdriver: del_driver_init(%s) Nt failed!\n", driver_name));
+ } else {
+ /*
+ * a 2k/Xp driver was found, don't delete init data because Nt driver will use it.
+ */
+ free_a_printer_driver(driver1,3);
+ DEBUG(10,("_spoolss_addprinterdriver: init data not deleted for Nt driver [%s]\n",
+ driver_name));
+ }
+ }
+ break;
+
+ /*
+ * 2k or Xp printer driver - always delete init data
+ */
+ case 3:
+ if (!del_driver_init(driver_name))
+ DEBUG(6,("_spoolss_addprinterdriver: del_driver_init(%s) 2k/Xp failed!\n", driver_name));
+ break;
+
+ default:
+ DEBUG(0,("_spoolss_addprinterdriver: invalid level=%d\n", level));
+ break;
+ }
+
+
+done:
+ free_a_printer_driver(driver, level);
+ return err;
+}
+
+/********************************************************************
+ * spoolss_addprinterdriverex
+ ********************************************************************/
+
+WERROR _spoolss_addprinterdriverex(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVEREX *q_u, SPOOL_R_ADDPRINTERDRIVEREX *r_u)
+{
+ SPOOL_Q_ADDPRINTERDRIVER q_u_local;
+ SPOOL_R_ADDPRINTERDRIVER r_u_local;
+
+ /*
+ * we only support the semantics of AddPrinterDriver()
+ * i.e. only copy files that are newer than existing ones
+ */
+
+ if ( q_u->copy_flags != APD_COPY_NEW_FILES )
+ return WERR_ACCESS_DENIED;
+
+ ZERO_STRUCT(q_u_local);
+ ZERO_STRUCT(r_u_local);
+
+ /* just pass the information off to _spoolss_addprinterdriver() */
+ q_u_local.server_name_ptr = q_u->server_name_ptr;
+ copy_unistr2(&q_u_local.server_name, &q_u->server_name);
+ q_u_local.level = q_u->level;
+ memcpy( &q_u_local.info, &q_u->info, sizeof(SPOOL_PRINTER_DRIVER_INFO_LEVEL) );
+
+ return _spoolss_addprinterdriver( p, &q_u_local, &r_u_local );
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void fill_driverdir_1(DRIVER_DIRECTORY_1 *info, char *name)
+{
+ init_unistr(&info->name, name);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR getprinterdriverdir_level_1(UNISTR2 *name, UNISTR2 *uni_environment, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ char *path = NULL;
+ char *long_archi = NULL;
+ char *servername = NULL;
+ const char *pservername = NULL;
+ const char *short_archi;
+ DRIVER_DIRECTORY_1 *info=NULL;
+ WERROR result = WERR_OK;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ servername = unistr2_to_ascii_talloc(ctx, name);
+ if (!servername) {
+ return WERR_NOMEM;
+ }
+ long_archi = unistr2_to_ascii_talloc(ctx, uni_environment);
+ if (!long_archi) {
+ return WERR_NOMEM;
+ }
+
+ pservername = canon_servername(servername);
+
+ if ( !is_myname_or_ipaddr(pservername))
+ return WERR_INVALID_PARAM;
+
+ if (!(short_archi = get_short_archi(long_archi)))
+ return WERR_INVALID_ENVIRONMENT;
+
+ if((info=SMB_MALLOC_P(DRIVER_DIRECTORY_1)) == NULL)
+ return WERR_NOMEM;
+
+ path = talloc_asprintf(ctx,
+ "\\\\%s\\print$\\%s", pservername, short_archi);
+ if (!path) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ DEBUG(4,("printer driver directory: [%s]\n", path));
+
+ fill_driverdir_1(info, path);
+
+ *needed += spoolss_size_driverdir_info_1(info);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ smb_io_driverdir_1("", buffer, info, 0);
+
+out:
+ SAFE_FREE(info);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_getprinterdriverdirectory(pipes_struct *p, SPOOL_Q_GETPRINTERDRIVERDIR *q_u, SPOOL_R_GETPRINTERDRIVERDIR *r_u)
+{
+ UNISTR2 *name = &q_u->name;
+ UNISTR2 *uni_environment = &q_u->environment;
+ uint32 level = q_u->level;
+ RPC_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+
+ /* that's an [in out] buffer */
+
+ if (!q_u->buffer && (offered!=0)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ rpcbuf_move(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(4,("_spoolss_getprinterdriverdirectory\n"));
+
+ *needed=0;
+
+ switch(level) {
+ case 1:
+ return getprinterdriverdir_level_1(name, uni_environment, buffer, offered, needed);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, SPOOL_R_ENUMPRINTERDATA *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 idx = q_u->index;
+ uint32 in_value_len = q_u->valuesize;
+ uint32 in_data_len = q_u->datasize;
+ uint32 *out_max_value_len = &r_u->valuesize;
+ uint16 **out_value = &r_u->value;
+ uint32 *out_value_len = &r_u->realvaluesize;
+ uint32 *out_type = &r_u->type;
+ uint32 *out_max_data_len = &r_u->datasize;
+ uint8 **data_out = &r_u->data;
+ uint32 *out_data_len = &r_u->realdatasize;
+
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+ uint32 biggest_valuesize;
+ uint32 biggest_datasize;
+ uint32 data_len;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+ int snum;
+ WERROR result;
+ REGISTRY_VALUE *val = NULL;
+ NT_PRINTER_DATA *p_data;
+ int i, key_index, num_values;
+ int name_length;
+
+ *out_type = 0;
+
+ *out_max_data_len = 0;
+ *data_out = NULL;
+ *out_data_len = 0;
+
+ DEBUG(5,("spoolss_enumprinterdata\n"));
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_enumprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if (!get_printer_snum(p,handle, &snum, NULL))
+ return WERR_BADFID;
+
+ result = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
+ if (!W_ERROR_IS_OK(result))
+ return result;
+
+ p_data = printer->info_2->data;
+ key_index = lookup_printerkey( p_data, SPOOL_PRINTERDATA_KEY );
+
+ result = WERR_OK;
+
+ /*
+ * The NT machine wants to know the biggest size of value and data
+ *
+ * cf: MSDN EnumPrinterData remark section
+ */
+
+ if ( !in_value_len && !in_data_len && (key_index != -1) )
+ {
+ DEBUGADD(6,("Activating NT mega-hack to find sizes\n"));
+
+ biggest_valuesize = 0;
+ biggest_datasize = 0;
+
+ num_values = regval_ctr_numvals( p_data->keys[key_index].values );
+
+ for ( i=0; i<num_values; i++ )
+ {
+ val = regval_ctr_specific_value( p_data->keys[key_index].values, i );
+
+ name_length = strlen(val->valuename);
+ if ( strlen(val->valuename) > biggest_valuesize )
+ biggest_valuesize = name_length;
+
+ if ( val->size > biggest_datasize )
+ biggest_datasize = val->size;
+
+ DEBUG(6,("current values: [%d], [%d]\n", biggest_valuesize,
+ biggest_datasize));
+ }
+
+ /* the value is an UNICODE string but real_value_size is the length
+ in bytes including the trailing 0 */
+
+ *out_value_len = 2 * (1+biggest_valuesize);
+ *out_data_len = biggest_datasize;
+
+ DEBUG(6,("final values: [%d], [%d]\n", *out_value_len, *out_data_len));
+
+ goto done;
+ }
+
+ /*
+ * the value len is wrong in NT sp3
+ * that's the number of bytes not the number of unicode chars
+ */
+
+ if ( key_index != -1 )
+ val = regval_ctr_specific_value( p_data->keys[key_index].values, idx );
+
+ if ( !val )
+ {
+
+ /* out_value should default to "" or else NT4 has
+ problems unmarshalling the response */
+
+ *out_max_value_len=(in_value_len/sizeof(uint16));
+
+ if (in_value_len) {
+ if((*out_value=(uint16 *)TALLOC_ZERO(p->mem_ctx, in_value_len*sizeof(uint8))) == NULL)
+ {
+ result = WERR_NOMEM;
+ goto done;
+ }
+ *out_value_len = (uint32)rpcstr_push((char *)*out_value, "", in_value_len, 0);
+ } else {
+ *out_value=NULL;
+ *out_value_len = 0;
+ }
+
+ /* the data is counted in bytes */
+
+ *out_max_data_len = in_data_len;
+ *out_data_len = in_data_len;
+
+ /* only allocate when given a non-zero data_len */
+
+ if ( in_data_len && ((*data_out=(uint8 *)TALLOC_ZERO(p->mem_ctx, in_data_len*sizeof(uint8))) == NULL) )
+ {
+ result = WERR_NOMEM;
+ goto done;
+ }
+
+ result = WERR_NO_MORE_ITEMS;
+ }
+ else
+ {
+ /*
+ * the value is:
+ * - counted in bytes in the request
+ * - counted in UNICODE chars in the max reply
+ * - counted in bytes in the real size
+ *
+ * take a pause *before* coding not *during* coding
+ */
+
+ /* name */
+ *out_max_value_len=(in_value_len/sizeof(uint16));
+ if (in_value_len) {
+ if ( (*out_value = (uint16 *)TALLOC_ZERO(p->mem_ctx, in_value_len*sizeof(uint8))) == NULL )
+ {
+ result = WERR_NOMEM;
+ goto done;
+ }
+
+ *out_value_len = (uint32)rpcstr_push((char *)*out_value, regval_name(val), (size_t)in_value_len, 0);
+ } else {
+ *out_value = NULL;
+ *out_value_len = 0;
+ }
+
+ /* type */
+
+ *out_type = regval_type( val );
+
+ /* data - counted in bytes */
+
+ *out_max_data_len = in_data_len;
+ if ( in_data_len && (*data_out = (uint8 *)TALLOC_ZERO(p->mem_ctx, in_data_len*sizeof(uint8))) == NULL)
+ {
+ result = WERR_NOMEM;
+ goto done;
+ }
+ data_len = regval_size(val);
+ if ( *data_out && data_len )
+ memcpy( *data_out, regval_data_p(val), data_len );
+ *out_data_len = data_len;
+ }
+
+done:
+ free_a_printer(&printer, 2);
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SPOOL_R_SETPRINTERDATA *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ UNISTR2 *value = &q_u->value;
+ uint32 type = q_u->type;
+ uint8 *data = q_u->data;
+ uint32 real_len = q_u->real_len;
+
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ int snum=0;
+ WERROR status = WERR_OK;
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+ fstring valuename;
+
+ DEBUG(5,("spoolss_setprinterdata\n"));
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_setprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if ( Printer->printer_type == SPLHND_SERVER ) {
+ DEBUG(10,("_spoolss_setprinterdata: Not implemented for server handles yet\n"));
+ return WERR_INVALID_PARAM;
+ }
+
+ if (!get_printer_snum(p,handle, &snum, NULL))
+ return WERR_BADFID;
+
+ /*
+ * Access check : NT returns "access denied" if you make a
+ * SetPrinterData call without the necessary privildge.
+ * we were originally returning OK if nothing changed
+ * which made Win2k issue **a lot** of SetPrinterData
+ * when connecting to a printer --jerry
+ */
+
+ if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER)
+ {
+ DEBUG(3, ("_spoolss_setprinterdata: change denied by handle access permissions\n"));
+ status = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
+ if (!W_ERROR_IS_OK(status))
+ return status;
+
+ unistr2_to_ascii(valuename, value, sizeof(valuename));
+
+ /*
+ * When client side code sets a magic printer data key, detect it and save
+ * the current printer data and the magic key's data (its the DEVMODE) for
+ * future printer/driver initializations.
+ */
+ if ( (type == REG_BINARY) && strequal( valuename, PHANTOM_DEVMODE_KEY))
+ {
+ /* Set devmode and printer initialization info */
+ status = save_driver_init( printer, 2, data, real_len );
+
+ srv_spoolss_reset_printerdata( printer->info_2->drivername );
+ }
+ else
+ {
+ status = set_printer_dataex( printer, SPOOL_PRINTERDATA_KEY, valuename,
+ type, data, real_len );
+ if ( W_ERROR_IS_OK(status) )
+ status = mod_a_printer(printer, 2);
+ }
+
+done:
+ free_a_printer(&printer, 2);
+
+ return status;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_resetprinter(pipes_struct *p, SPOOL_Q_RESETPRINTER *q_u, SPOOL_R_RESETPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+ int snum;
+
+ DEBUG(5,("_spoolss_resetprinter\n"));
+
+ /*
+ * All we do is to check to see if the handle and queue is valid.
+ * This call really doesn't mean anything to us because we only
+ * support RAW printing. --jerry
+ */
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_resetprinter: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if (!get_printer_snum(p,handle, &snum, NULL))
+ return WERR_BADFID;
+
+
+ /* blindly return success */
+ return WERR_OK;
+}
+
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_deleteprinterdata(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATA *q_u, SPOOL_R_DELETEPRINTERDATA *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ UNISTR2 *value = &q_u->valuename;
+
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ int snum=0;
+ WERROR status = WERR_OK;
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+ char *valuename = NULL;
+ TALLOC_CTX *ctx = p->mem_ctx;
+
+ DEBUG(5,("spoolss_deleteprinterdata\n"));
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_deleteprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if (!get_printer_snum(p, handle, &snum, NULL))
+ return WERR_BADFID;
+
+ if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
+ DEBUG(3, ("_spoolss_deleteprinterdata: printer properties change denied by handle\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
+ if (!W_ERROR_IS_OK(status))
+ return status;
+
+ valuename = unistr2_to_ascii_talloc(ctx, value);
+ if (!valuename) {
+ free_a_printer(&printer, 2);
+ return WERR_NOMEM;
+ }
+
+ status = delete_printer_dataex( printer, SPOOL_PRINTERDATA_KEY, valuename );
+
+ if ( W_ERROR_IS_OK(status) )
+ mod_a_printer( printer, 2 );
+
+ free_a_printer(&printer, 2);
+ TALLOC_FREE(valuename);
+
+ return status;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_addform( pipes_struct *p, SPOOL_Q_ADDFORM *q_u, SPOOL_R_ADDFORM *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ FORM *form = &q_u->form;
+ nt_forms_struct tmpForm;
+ int snum;
+ WERROR status = WERR_OK;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+ int count=0;
+ nt_forms_struct *list=NULL;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ DEBUG(5,("spoolss_addform\n"));
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_addform: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+
+ /* forms can be added on printer of on the print server handle */
+
+ if ( Printer->printer_type == SPLHND_PRINTER )
+ {
+ if (!get_printer_snum(p,handle, &snum, NULL))
+ return WERR_BADFID;
+
+ status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
+ if (!W_ERROR_IS_OK(status))
+ goto done;
+ }
+
+ if ( !(Printer->access_granted & (PRINTER_ACCESS_ADMINISTER|SERVER_ACCESS_ADMINISTER)) ) {
+ DEBUG(2,("_spoolss_addform: denied by handle permissions.\n"));
+ status = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ /* can't add if builtin */
+
+ if (get_a_builtin_ntform(&form->name,&tmpForm)) {
+ status = WERR_ALREADY_EXISTS;
+ goto done;
+ }
+
+ count = get_ntforms(&list);
+
+ if(!add_a_form(&list, form, &count)) {
+ status = WERR_NOMEM;
+ goto done;
+ }
+
+ write_ntforms(&list, count);
+
+ /*
+ * ChangeID must always be set if this is a printer
+ */
+
+ if ( Printer->printer_type == SPLHND_PRINTER )
+ status = mod_a_printer(printer, 2);
+
+done:
+ if ( printer )
+ free_a_printer(&printer, 2);
+ SAFE_FREE(list);
+
+ return status;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_deleteform( pipes_struct *p, SPOOL_Q_DELETEFORM *q_u, SPOOL_R_DELETEFORM *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ UNISTR2 *form_name = &q_u->name;
+ nt_forms_struct tmpForm;
+ int count=0;
+ nt_forms_struct *list=NULL;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+ int snum;
+ WERROR status = WERR_OK;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+ DEBUG(5,("spoolss_deleteform\n"));
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_deleteform: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ /* forms can be deleted on printer of on the print server handle */
+
+ if ( Printer->printer_type == SPLHND_PRINTER )
+ {
+ if (!get_printer_snum(p,handle, &snum, NULL))
+ return WERR_BADFID;
+
+ status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
+ if (!W_ERROR_IS_OK(status))
+ goto done;
+ }
+
+ if ( !(Printer->access_granted & (PRINTER_ACCESS_ADMINISTER|SERVER_ACCESS_ADMINISTER)) ) {
+ DEBUG(2,("_spoolss_deleteform: denied by handle permissions.\n"));
+ status = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ /* can't delete if builtin */
+
+ if (get_a_builtin_ntform(form_name,&tmpForm)) {
+ status = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ count = get_ntforms(&list);
+
+ if ( !delete_a_form(&list, form_name, &count, &status ))
+ goto done;
+
+ /*
+ * ChangeID must always be set if this is a printer
+ */
+
+ if ( Printer->printer_type == SPLHND_PRINTER )
+ status = mod_a_printer(printer, 2);
+
+done:
+ if ( printer )
+ free_a_printer(&printer, 2);
+ SAFE_FREE(list);
+
+ return status;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_setform(pipes_struct *p, SPOOL_Q_SETFORM *q_u, SPOOL_R_SETFORM *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ FORM *form = &q_u->form;
+ nt_forms_struct tmpForm;
+ int snum;
+ WERROR status = WERR_OK;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+ int count=0;
+ nt_forms_struct *list=NULL;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ DEBUG(5,("spoolss_setform\n"));
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_setform: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ /* forms can be modified on printer of on the print server handle */
+
+ if ( Printer->printer_type == SPLHND_PRINTER )
+ {
+ if (!get_printer_snum(p,handle, &snum, NULL))
+ return WERR_BADFID;
+
+ status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
+ if (!W_ERROR_IS_OK(status))
+ goto done;
+ }
+
+ if ( !(Printer->access_granted & (PRINTER_ACCESS_ADMINISTER|SERVER_ACCESS_ADMINISTER)) ) {
+ DEBUG(2,("_spoolss_setform: denied by handle permissions\n"));
+ status = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ /* can't set if builtin */
+ if (get_a_builtin_ntform(&form->name,&tmpForm)) {
+ status = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ count = get_ntforms(&list);
+ update_a_form(&list, form, count);
+ write_ntforms(&list, count);
+
+ /*
+ * ChangeID must always be set if this is a printer
+ */
+
+ if ( Printer->printer_type == SPLHND_PRINTER )
+ status = mod_a_printer(printer, 2);
+
+
+done:
+ if ( printer )
+ free_a_printer(&printer, 2);
+ SAFE_FREE(list);
+
+ return status;
+}
+
+/****************************************************************************
+ enumprintprocessors level 1.
+****************************************************************************/
+
+static WERROR enumprintprocessors_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ PRINTPROCESSOR_1 *info_1=NULL;
+ WERROR result = WERR_OK;
+
+ if((info_1 = SMB_MALLOC_P(PRINTPROCESSOR_1)) == NULL)
+ return WERR_NOMEM;
+
+ (*returned) = 0x1;
+
+ init_unistr(&info_1->name, "winprint");
+
+ *needed += spoolss_size_printprocessor_info_1(info_1);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ smb_io_printprocessor_info_1("", buffer, info_1, 0);
+
+out:
+ SAFE_FREE(info_1);
+
+ if ( !W_ERROR_IS_OK(result) )
+ *returned = 0;
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_enumprintprocessors(pipes_struct *p, SPOOL_Q_ENUMPRINTPROCESSORS *q_u, SPOOL_R_ENUMPRINTPROCESSORS *r_u)
+{
+ uint32 level = q_u->level;
+ RPC_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *returned = &r_u->returned;
+
+ /* that's an [in out] buffer */
+
+ if (!q_u->buffer && (offered!=0)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ rpcbuf_move(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(5,("spoolss_enumprintprocessors\n"));
+
+ /*
+ * Enumerate the print processors ...
+ *
+ * Just reply with "winprint", to keep NT happy
+ * and I can use my nice printer checker.
+ */
+
+ *returned=0;
+ *needed=0;
+
+ switch (level) {
+ case 1:
+ return enumprintprocessors_level_1(buffer, offered, needed, returned);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+ enumprintprocdatatypes level 1.
+****************************************************************************/
+
+static WERROR enumprintprocdatatypes_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ PRINTPROCDATATYPE_1 *info_1=NULL;
+ WERROR result = WERR_OK;
+
+ if((info_1 = SMB_MALLOC_P(PRINTPROCDATATYPE_1)) == NULL)
+ return WERR_NOMEM;
+
+ (*returned) = 0x1;
+
+ init_unistr(&info_1->name, "RAW");
+
+ *needed += spoolss_size_printprocdatatype_info_1(info_1);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ smb_io_printprocdatatype_info_1("", buffer, info_1, 0);
+
+out:
+ SAFE_FREE(info_1);
+
+ if ( !W_ERROR_IS_OK(result) )
+ *returned = 0;
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_enumprintprocdatatypes(pipes_struct *p, SPOOL_Q_ENUMPRINTPROCDATATYPES *q_u, SPOOL_R_ENUMPRINTPROCDATATYPES *r_u)
+{
+ uint32 level = q_u->level;
+ RPC_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *returned = &r_u->returned;
+
+ /* that's an [in out] buffer */
+
+ if (!q_u->buffer && (offered!=0)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ rpcbuf_move(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(5,("_spoolss_enumprintprocdatatypes\n"));
+
+ *returned=0;
+ *needed=0;
+
+ switch (level) {
+ case 1:
+ return enumprintprocdatatypes_level_1(buffer, offered, needed, returned);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+ enumprintmonitors level 1.
+****************************************************************************/
+
+static WERROR enumprintmonitors_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ PRINTMONITOR_1 *info_1;
+ WERROR result = WERR_OK;
+ int i;
+
+ if((info_1 = SMB_MALLOC_ARRAY(PRINTMONITOR_1, 2)) == NULL)
+ return WERR_NOMEM;
+
+ *returned = 2;
+
+ init_unistr(&(info_1[0].name), SPL_LOCAL_PORT );
+ init_unistr(&(info_1[1].name), SPL_TCPIP_PORT );
+
+ for ( i=0; i<*returned; i++ ) {
+ *needed += spoolss_size_printmonitor_info_1(&info_1[i]);
+ }
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ for ( i=0; i<*returned; i++ ) {
+ smb_io_printmonitor_info_1("", buffer, &info_1[i], 0);
+ }
+
+out:
+ SAFE_FREE(info_1);
+
+ if ( !W_ERROR_IS_OK(result) )
+ *returned = 0;
+
+ return result;
+}
+
+/****************************************************************************
+ enumprintmonitors level 2.
+****************************************************************************/
+
+static WERROR enumprintmonitors_level_2(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ PRINTMONITOR_2 *info_2;
+ WERROR result = WERR_OK;
+ int i;
+
+ if((info_2 = SMB_MALLOC_ARRAY(PRINTMONITOR_2, 2)) == NULL)
+ return WERR_NOMEM;
+
+ *returned = 2;
+
+ init_unistr( &(info_2[0].name), SPL_LOCAL_PORT );
+ init_unistr( &(info_2[0].environment), "Windows NT X86" );
+ init_unistr( &(info_2[0].dll_name), "localmon.dll" );
+
+ init_unistr( &(info_2[1].name), SPL_TCPIP_PORT );
+ init_unistr( &(info_2[1].environment), "Windows NT X86" );
+ init_unistr( &(info_2[1].dll_name), "tcpmon.dll" );
+
+ for ( i=0; i<*returned; i++ ) {
+ *needed += spoolss_size_printmonitor_info_2(&info_2[i]);
+ }
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ for ( i=0; i<*returned; i++ ) {
+ smb_io_printmonitor_info_2("", buffer, &info_2[i], 0);
+ }
+
+out:
+ SAFE_FREE(info_2);
+
+ if ( !W_ERROR_IS_OK(result) )
+ *returned = 0;
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_enumprintmonitors(pipes_struct *p, SPOOL_Q_ENUMPRINTMONITORS *q_u, SPOOL_R_ENUMPRINTMONITORS *r_u)
+{
+ uint32 level = q_u->level;
+ RPC_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *returned = &r_u->returned;
+
+ /* that's an [in out] buffer */
+
+ if (!q_u->buffer && (offered!=0)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ rpcbuf_move(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(5,("spoolss_enumprintmonitors\n"));
+
+ /*
+ * Enumerate the print monitors ...
+ *
+ * Just reply with "Local Port", to keep NT happy
+ * and I can use my nice printer checker.
+ */
+
+ *returned=0;
+ *needed=0;
+
+ switch (level) {
+ case 1:
+ return enumprintmonitors_level_1(buffer, offered, needed, returned);
+ case 2:
+ return enumprintmonitors_level_2(buffer, offered, needed, returned);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR getjob_level_1(print_queue_struct **queue, int count, int snum,
+ NT_PRINTER_INFO_LEVEL *ntprinter,
+ uint32 jobid, RPC_BUFFER *buffer, uint32 offered,
+ uint32 *needed)
+{
+ int i=0;
+ bool found=False;
+ JOB_INFO_1 *info_1=NULL;
+ WERROR result = WERR_OK;
+
+ info_1=SMB_MALLOC_P(JOB_INFO_1);
+
+ if (info_1 == NULL) {
+ return WERR_NOMEM;
+ }
+
+ for (i=0; i<count && found==False; i++) {
+ if ((*queue)[i].job==(int)jobid)
+ found=True;
+ }
+
+ if (found==False) {
+ SAFE_FREE(info_1);
+ /* NT treats not found as bad param... yet another bad choice */
+ return WERR_INVALID_PARAM;
+ }
+
+ fill_job_info_1( info_1, &((*queue)[i-1]), i, snum, ntprinter );
+
+ *needed += spoolss_size_job_info_1(info_1);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto out;
+ }
+
+ smb_io_job_info_1("", buffer, info_1, 0);
+
+out:
+ SAFE_FREE(info_1);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR getjob_level_2(print_queue_struct **queue, int count, int snum,
+ NT_PRINTER_INFO_LEVEL *ntprinter,
+ uint32 jobid, RPC_BUFFER *buffer, uint32 offered,
+ uint32 *needed)
+{
+ int i = 0;
+ bool found = False;
+ JOB_INFO_2 *info_2;
+ WERROR result;
+ DEVICEMODE *devmode = NULL;
+ NT_DEVICEMODE *nt_devmode = NULL;
+
+ if ( !(info_2=SMB_MALLOC_P(JOB_INFO_2)) )
+ return WERR_NOMEM;
+
+ ZERO_STRUCTP(info_2);
+
+ for ( i=0; i<count && found==False; i++ )
+ {
+ if ((*queue)[i].job == (int)jobid)
+ found = True;
+ }
+
+ if ( !found ) {
+ /* NT treats not found as bad param... yet another bad
+ choice */
+ result = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ /*
+ * if the print job does not have a DEVMODE associated with it,
+ * just use the one for the printer. A NULL devicemode is not
+ * a failure condition
+ */
+
+ if ( !(nt_devmode=print_job_devmode( lp_const_servicename(snum), jobid )) )
+ devmode = construct_dev_mode(lp_const_servicename(snum));
+ else {
+ if ((devmode = SMB_MALLOC_P(DEVICEMODE)) != NULL) {
+ ZERO_STRUCTP( devmode );
+ convert_nt_devicemode( devmode, nt_devmode );
+ }
+ }
+
+ fill_job_info_2(info_2, &((*queue)[i-1]), i, snum, ntprinter, devmode);
+
+ *needed += spoolss_size_job_info_2(info_2);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto done;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_NOMEM;
+ goto done;
+ }
+
+ smb_io_job_info_2("", buffer, info_2, 0);
+
+ result = WERR_OK;
+
+ done:
+ /* Cleanup allocated memory */
+
+ free_job_info_2(info_2); /* Also frees devmode */
+ SAFE_FREE(info_2);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_getjob( pipes_struct *p, SPOOL_Q_GETJOB *q_u, SPOOL_R_GETJOB *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 jobid = q_u->jobid;
+ uint32 level = q_u->level;
+ RPC_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ WERROR wstatus = WERR_OK;
+ NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+ int snum;
+ int count;
+ print_queue_struct *queue = NULL;
+ print_status_struct prt_status;
+
+ /* that's an [in out] buffer */
+
+ if (!q_u->buffer && (offered!=0)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ rpcbuf_move(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(5,("spoolss_getjob\n"));
+
+ *needed = 0;
+
+ if (!get_printer_snum(p, handle, &snum, NULL))
+ return WERR_BADFID;
+
+ wstatus = get_a_printer(NULL, &ntprinter, 2, lp_servicename(snum));
+ if ( !W_ERROR_IS_OK(wstatus) )
+ return wstatus;
+
+ count = print_queue_status(snum, &queue, &prt_status);
+
+ DEBUGADD(4,("count:[%d], prt_status:[%d], [%s]\n",
+ count, prt_status.status, prt_status.message));
+
+ switch ( level ) {
+ case 1:
+ wstatus = getjob_level_1(&queue, count, snum, ntprinter, jobid,
+ buffer, offered, needed);
+ break;
+ case 2:
+ wstatus = getjob_level_2(&queue, count, snum, ntprinter, jobid,
+ buffer, offered, needed);
+ break;
+ default:
+ wstatus = WERR_UNKNOWN_LEVEL;
+ break;
+ }
+
+ SAFE_FREE(queue);
+ free_a_printer( &ntprinter, 2 );
+
+ return wstatus;
+}
+
+/********************************************************************
+ spoolss_getprinterdataex
+
+ From MSDN documentation of GetPrinterDataEx: pass request
+ to GetPrinterData if key is "PrinterDriverData".
+ ********************************************************************/
+
+WERROR _spoolss_getprinterdataex(pipes_struct *p, SPOOL_Q_GETPRINTERDATAEX *q_u, SPOOL_R_GETPRINTERDATAEX *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 in_size = q_u->size;
+ uint32 *type = &r_u->type;
+ uint32 *out_size = &r_u->size;
+ uint8 **data = &r_u->data;
+ uint32 *needed = &r_u->needed;
+ fstring keyname, valuename;
+
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ int snum = 0;
+ WERROR status = WERR_OK;
+
+ DEBUG(4,("_spoolss_getprinterdataex\n"));
+
+ unistr2_to_ascii(keyname, &q_u->keyname, sizeof(keyname));
+ unistr2_to_ascii(valuename, &q_u->valuename, sizeof(valuename));
+
+ DEBUG(10, ("_spoolss_getprinterdataex: key => [%s], value => [%s]\n",
+ keyname, valuename));
+
+ /* in case of problem, return some default values */
+
+ *needed = 0;
+ *type = 0;
+ *out_size = in_size;
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_getprinterdataex: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+ status = WERR_BADFID;
+ goto done;
+ }
+
+ /* Is the handle to a printer or to the server? */
+
+ if (Printer->printer_type == SPLHND_SERVER) {
+ DEBUG(10,("_spoolss_getprinterdataex: Not implemented for server handles yet\n"));
+ status = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ if ( !get_printer_snum(p,handle, &snum, NULL) )
+ return WERR_BADFID;
+
+ status = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
+ if ( !W_ERROR_IS_OK(status) )
+ goto done;
+
+ /* check to see if the keyname is valid */
+ if ( !strlen(keyname) ) {
+ status = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ if ( lookup_printerkey( printer->info_2->data, keyname ) == -1 ) {
+ DEBUG(4,("_spoolss_getprinterdataex: Invalid keyname [%s]\n", keyname ));
+ free_a_printer( &printer, 2 );
+ status = WERR_BADFILE;
+ goto done;
+ }
+
+ /* When given a new keyname, we should just create it */
+
+ status = get_printer_dataex( p->mem_ctx, printer, keyname, valuename, type, data, needed, in_size );
+
+ if (*needed > *out_size)
+ status = WERR_MORE_DATA;
+
+done:
+ if ( !W_ERROR_IS_OK(status) )
+ {
+ DEBUG(5, ("error: allocating %d\n", *out_size));
+
+ /* reply this param doesn't exist */
+
+ if ( *out_size )
+ {
+ if( (*data=(uint8 *)TALLOC_ZERO(p->mem_ctx, *out_size*sizeof(uint8))) == NULL ) {
+ status = WERR_NOMEM;
+ goto done;
+ }
+ } else {
+ *data = NULL;
+ }
+ }
+
+ if ( printer )
+ free_a_printer( &printer, 2 );
+
+ return status;
+}
+
+/********************************************************************
+ * spoolss_setprinterdataex
+ ********************************************************************/
+
+WERROR _spoolss_setprinterdataex(pipes_struct *p, SPOOL_Q_SETPRINTERDATAEX *q_u, SPOOL_R_SETPRINTERDATAEX *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 type = q_u->type;
+ uint8 *data = q_u->data;
+ uint32 real_len = q_u->real_len;
+
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ int snum = 0;
+ WERROR status = WERR_OK;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+ fstring valuename;
+ fstring keyname;
+ char *oid_string;
+
+ DEBUG(4,("_spoolss_setprinterdataex\n"));
+
+ /* From MSDN documentation of SetPrinterDataEx: pass request to
+ SetPrinterData if key is "PrinterDriverData" */
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_setprinterdataex: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if ( Printer->printer_type == SPLHND_SERVER ) {
+ DEBUG(10,("_spoolss_setprinterdataex: Not implemented for server handles yet\n"));
+ return WERR_INVALID_PARAM;
+ }
+
+ if ( !get_printer_snum(p,handle, &snum, NULL) )
+ return WERR_BADFID;
+
+ /*
+ * Access check : NT returns "access denied" if you make a
+ * SetPrinterData call without the necessary privildge.
+ * we were originally returning OK if nothing changed
+ * which made Win2k issue **a lot** of SetPrinterData
+ * when connecting to a printer --jerry
+ */
+
+ if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER)
+ {
+ DEBUG(3, ("_spoolss_setprinterdataex: change denied by handle access permissions\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ status = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
+ if (!W_ERROR_IS_OK(status))
+ return status;
+
+ unistr2_to_ascii( valuename, &q_u->value, sizeof(valuename));
+ unistr2_to_ascii( keyname, &q_u->key, sizeof(keyname));
+
+ /* check for OID in valuename */
+
+ if ( (oid_string = strchr( valuename, ',' )) != NULL )
+ {
+ *oid_string = '\0';
+ oid_string++;
+ }
+
+ /* save the registry data */
+
+ status = set_printer_dataex( printer, keyname, valuename, type, data, real_len );
+
+ if ( W_ERROR_IS_OK(status) )
+ {
+ /* save the OID if one was specified */
+ if ( oid_string ) {
+ fstrcat( keyname, "\\" );
+ fstrcat( keyname, SPOOL_OID_KEY );
+
+ /*
+ * I'm not checking the status here on purpose. Don't know
+ * if this is right, but I'm returning the status from the
+ * previous set_printer_dataex() call. I have no idea if
+ * this is right. --jerry
+ */
+
+ set_printer_dataex( printer, keyname, valuename,
+ REG_SZ, (uint8 *)oid_string,
+ strlen(oid_string)+1 );
+ }
+
+ status = mod_a_printer(printer, 2);
+ }
+
+ free_a_printer(&printer, 2);
+
+ return status;
+}
+
+
+/********************************************************************
+ * spoolss_deleteprinterdataex
+ ********************************************************************/
+
+WERROR _spoolss_deleteprinterdataex(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATAEX *q_u, SPOOL_R_DELETEPRINTERDATAEX *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ UNISTR2 *value = &q_u->valuename;
+ UNISTR2 *key = &q_u->keyname;
+
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ int snum=0;
+ WERROR status = WERR_OK;
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+ char *valuename = NULL;
+ char *keyname = NULL;
+ TALLOC_CTX *ctx = p->mem_ctx;
+
+ DEBUG(5,("spoolss_deleteprinterdataex\n"));
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_deleteprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if (!get_printer_snum(p, handle, &snum, NULL))
+ return WERR_BADFID;
+
+ if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
+ DEBUG(3, ("_spoolss_deleteprinterdataex: printer properties change denied by handle\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ valuename = unistr2_to_ascii_talloc(ctx, value);
+ keyname = unistr2_to_ascii_talloc(ctx, key);
+ if (!valuename || !keyname) {
+ return WERR_NOMEM;
+ }
+
+ status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
+ if (!W_ERROR_IS_OK(status))
+ return status;
+
+ status = delete_printer_dataex( printer, keyname, valuename );
+
+ if ( W_ERROR_IS_OK(status) )
+ mod_a_printer( printer, 2 );
+
+ free_a_printer(&printer, 2);
+
+ return status;
+}
+
+/********************************************************************
+ * spoolss_enumprinterkey
+ ********************************************************************/
+
+
+WERROR _spoolss_enumprinterkey(pipes_struct *p, SPOOL_Q_ENUMPRINTERKEY *q_u, SPOOL_R_ENUMPRINTERKEY *r_u)
+{
+ fstring key;
+ fstring *keynames = NULL;
+ uint16 *enumkeys = NULL;
+ int num_keys;
+ int printerkey_len;
+ POLICY_HND *handle = &q_u->handle;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+ NT_PRINTER_DATA *data;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ int snum = 0;
+ WERROR status = WERR_BADFILE;
+
+
+ DEBUG(4,("_spoolss_enumprinterkey\n"));
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_enumprinterkey: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if ( !get_printer_snum(p,handle, &snum, NULL) )
+ return WERR_BADFID;
+
+ status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
+ if (!W_ERROR_IS_OK(status))
+ return status;
+
+ /* get the list of subkey names */
+
+ unistr2_to_ascii(key, &q_u->key, sizeof(key));
+ data = printer->info_2->data;
+
+ num_keys = get_printer_subkeys( data, key, &keynames );
+
+ if ( num_keys == -1 ) {
+ status = WERR_BADFILE;
+ goto done;
+ }
+
+ printerkey_len = init_unistr_array( &enumkeys, keynames, NULL );
+
+ r_u->needed = printerkey_len*2;
+
+ if ( q_u->size < r_u->needed ) {
+ status = WERR_MORE_DATA;
+ goto done;
+ }
+
+ if (!make_spoolss_buffer5(p->mem_ctx, &r_u->keys, printerkey_len, enumkeys)) {
+ status = WERR_NOMEM;
+ goto done;
+ }
+
+ status = WERR_OK;
+
+ if ( q_u->size < r_u->needed )
+ status = WERR_MORE_DATA;
+
+done:
+ free_a_printer( &printer, 2 );
+ SAFE_FREE( keynames );
+
+ return status;
+}
+
+/********************************************************************
+ * spoolss_deleteprinterkey
+ ********************************************************************/
+
+WERROR _spoolss_deleteprinterkey(pipes_struct *p, SPOOL_Q_DELETEPRINTERKEY *q_u, SPOOL_R_DELETEPRINTERKEY *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, &q_u->handle);
+ fstring key;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ int snum=0;
+ WERROR status;
+
+ DEBUG(5,("spoolss_deleteprinterkey\n"));
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_deleteprinterkey: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ /* if keyname == NULL, return error */
+
+ if ( !q_u->keyname.buffer )
+ return WERR_INVALID_PARAM;
+
+ if (!get_printer_snum(p, handle, &snum, NULL))
+ return WERR_BADFID;
+
+ if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
+ DEBUG(3, ("_spoolss_deleteprinterkey: printer properties change denied by handle\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
+ if (!W_ERROR_IS_OK(status))
+ return status;
+
+ /* delete the key and all subneys */
+
+ unistr2_to_ascii(key, &q_u->keyname, sizeof(key));
+
+ status = delete_all_printer_data( printer->info_2, key );
+
+ if ( W_ERROR_IS_OK(status) )
+ status = mod_a_printer(printer, 2);
+
+ free_a_printer( &printer, 2 );
+
+ return status;
+}
+
+
+/********************************************************************
+ * spoolss_enumprinterdataex
+ ********************************************************************/
+
+WERROR _spoolss_enumprinterdataex(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATAEX *q_u, SPOOL_R_ENUMPRINTERDATAEX *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 in_size = q_u->size;
+ uint32 num_entries,
+ needed;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ PRINTER_ENUM_VALUES *enum_values = NULL;
+ NT_PRINTER_DATA *p_data;
+ fstring key;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+ int snum;
+ WERROR result;
+ int key_index;
+ int i;
+ REGISTRY_VALUE *val;
+ char *value_name;
+ uint32 data_len;
+
+
+ DEBUG(4,("_spoolss_enumprinterdataex\n"));
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_enumprinterdataex: Invalid handle (%s:%u:%u1<).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ /*
+ * first check for a keyname of NULL or "". Win2k seems to send
+ * this a lot and we should send back WERR_INVALID_PARAM
+ * no need to spend time looking up the printer in this case.
+ * --jerry
+ */
+
+ unistr2_to_ascii(key, &q_u->key, sizeof(key));
+ if ( !strlen(key) ) {
+ result = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ /* get the printer off of disk */
+
+ if (!get_printer_snum(p,handle, &snum, NULL))
+ return WERR_BADFID;
+
+ ZERO_STRUCT(printer);
+ result = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
+ if (!W_ERROR_IS_OK(result))
+ return result;
+
+ /* now look for a match on the key name */
+
+ p_data = printer->info_2->data;
+
+ unistr2_to_ascii(key, &q_u->key, sizeof(key));
+ if ( (key_index = lookup_printerkey( p_data, key)) == -1 )
+ {
+ DEBUG(10,("_spoolss_enumprinterdataex: Unknown keyname [%s]\n", key));
+ result = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ result = WERR_OK;
+ needed = 0;
+
+ /* allocate the memory for the array of pointers -- if necessary */
+
+ num_entries = regval_ctr_numvals( p_data->keys[key_index].values );
+ if ( num_entries )
+ {
+ if ( (enum_values=TALLOC_ARRAY(p->mem_ctx, PRINTER_ENUM_VALUES, num_entries)) == NULL )
+ {
+ DEBUG(0,("_spoolss_enumprinterdataex: talloc() failed to allocate memory for [%lu] bytes!\n",
+ (unsigned long)num_entries*sizeof(PRINTER_ENUM_VALUES)));
+ result = WERR_NOMEM;
+ goto done;
+ }
+
+ memset( enum_values, 0x0, num_entries*sizeof(PRINTER_ENUM_VALUES) );
+ }
+
+ /*
+ * loop through all params and build the array to pass
+ * back to the client
+ */
+
+ for ( i=0; i<num_entries; i++ )
+ {
+ /* lookup the registry value */
+
+ val = regval_ctr_specific_value( p_data->keys[key_index].values, i );
+ DEBUG(10,("retrieved value number [%d] [%s]\n", i, regval_name(val) ));
+
+ /* copy the data */
+
+ value_name = regval_name( val );
+ init_unistr( &enum_values[i].valuename, value_name );
+ enum_values[i].value_len = (strlen(value_name)+1) * 2;
+ enum_values[i].type = regval_type( val );
+
+ data_len = regval_size( val );
+ if ( data_len ) {
+ if ( !(enum_values[i].data = (uint8 *)TALLOC_MEMDUP(p->mem_ctx, regval_data_p(val), data_len)) )
+ {
+ DEBUG(0,("TALLOC_MEMDUP failed to allocate memory [data_len=%d] for data!\n",
+ data_len ));
+ result = WERR_NOMEM;
+ goto done;
+ }
+ }
+ enum_values[i].data_len = data_len;
+
+ /* keep track of the size of the array in bytes */
+
+ needed += spoolss_size_printer_enum_values(&enum_values[i]);
+ }
+
+ /* housekeeping information in the reply */
+
+ /* Fix from Martin Zielinski <mz@seh.de> - ensure
+ * the hand marshalled container size is a multiple
+ * of 4 bytes for RPC alignment.
+ */
+
+ if (needed % 4) {
+ needed += 4-(needed % 4);
+ }
+
+ r_u->needed = needed;
+ r_u->returned = num_entries;
+
+ if (needed > in_size) {
+ result = WERR_MORE_DATA;
+ goto done;
+ }
+
+ /* copy data into the reply */
+
+ /* mz: Vista x64 returns 0x6f7 (The stub received bad data), if the
+ response buffer size is != the offered buffer size
+
+ r_u->ctr.size = r_u->needed;
+ */
+ r_u->ctr.size = in_size;
+
+ r_u->ctr.size_of_array = r_u->returned;
+ r_u->ctr.values = enum_values;
+
+done:
+ if ( printer )
+ free_a_printer(&printer, 2);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void fill_printprocessordirectory_1(PRINTPROCESSOR_DIRECTORY_1 *info, const char *name)
+{
+ init_unistr(&info->name, name);
+}
+
+static WERROR getprintprocessordirectory_level_1(UNISTR2 *name,
+ UNISTR2 *environment,
+ RPC_BUFFER *buffer,
+ uint32 offered,
+ uint32 *needed)
+{
+ char *long_archi = NULL;
+ PRINTPROCESSOR_DIRECTORY_1 *info=NULL;
+ WERROR result = WERR_OK;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ long_archi = unistr2_to_ascii_talloc(ctx, environment);
+ if (!long_archi) {
+ return WERR_NOMEM;
+ }
+
+ if (!get_short_archi(long_archi))
+ return WERR_INVALID_ENVIRONMENT;
+
+ if((info=SMB_MALLOC_P(PRINTPROCESSOR_DIRECTORY_1)) == NULL)
+ return WERR_NOMEM;
+
+ fill_printprocessordirectory_1(info, "C:\\WINNT\\System32\\spool\\PRTPROCS\\W32X86");
+
+ *needed += spoolss_size_printprocessordirectory_info_1(info);
+
+ if (*needed > offered) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ if (!rpcbuf_alloc_size(buffer, *needed)) {
+ result = WERR_INSUFFICIENT_BUFFER;
+ goto out;
+ }
+
+ smb_io_printprocessordirectory_1("", buffer, info, 0);
+
+out:
+ SAFE_FREE(info);
+
+ return result;
+}
+
+WERROR _spoolss_getprintprocessordirectory(pipes_struct *p, SPOOL_Q_GETPRINTPROCESSORDIRECTORY *q_u, SPOOL_R_GETPRINTPROCESSORDIRECTORY *r_u)
+{
+ uint32 level = q_u->level;
+ RPC_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ WERROR result;
+
+ /* that's an [in out] buffer */
+
+ if (!q_u->buffer && (offered!=0)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ rpcbuf_move(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(5,("_spoolss_getprintprocessordirectory\n"));
+
+ *needed=0;
+
+ switch(level) {
+ case 1:
+ result = getprintprocessordirectory_level_1
+ (&q_u->name, &q_u->environment, buffer, offered, needed);
+ break;
+ default:
+ result = WERR_UNKNOWN_LEVEL;
+ }
+
+ return result;
+}
+
+/*******************************************************************
+ Streams the monitor UI DLL name in UNICODE
+*******************************************************************/
+
+static WERROR xcvtcp_monitorui( NT_USER_TOKEN *token, RPC_BUFFER *in,
+ RPC_BUFFER *out, uint32 *needed )
+{
+ const char *dllname = "tcpmonui.dll";
+
+ *needed = (strlen(dllname)+1) * 2;
+
+ if ( rpcbuf_get_size(out) < *needed ) {
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ if ( !make_monitorui_buf( out, dllname ) ) {
+ return WERR_NOMEM;
+ }
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ Create a new TCP/IP port
+*******************************************************************/
+
+static WERROR xcvtcp_addport( NT_USER_TOKEN *token, RPC_BUFFER *in,
+ RPC_BUFFER *out, uint32 *needed )
+{
+ NT_PORT_DATA_1 port1;
+ TALLOC_CTX *ctx = talloc_tos();
+ char *device_uri = NULL;
+
+ ZERO_STRUCT( port1 );
+
+ /* convert to our internal port data structure */
+
+ if ( !convert_port_data_1( &port1, in ) ) {
+ return WERR_NOMEM;
+ }
+
+ /* create the device URI and call the add_port_hook() */
+
+ switch ( port1.protocol ) {
+ case PORT_PROTOCOL_DIRECT:
+ device_uri = talloc_asprintf(ctx,
+ "socket://%s:%d/", port1.hostaddr, port1.port );
+ break;
+
+ case PORT_PROTOCOL_LPR:
+ device_uri = talloc_asprintf(ctx,
+ "lpr://%s/%s", port1.hostaddr, port1.queue );
+ break;
+
+ default:
+ return WERR_UNKNOWN_PORT;
+ }
+
+ if (!device_uri) {
+ return WERR_NOMEM;
+ }
+
+ return add_port_hook(ctx, token, port1.name, device_uri );
+}
+
+/*******************************************************************
+*******************************************************************/
+
+struct xcv_api_table xcvtcp_cmds[] = {
+ { "MonitorUI", xcvtcp_monitorui },
+ { "AddPort", xcvtcp_addport},
+ { NULL, NULL }
+};
+
+static WERROR process_xcvtcp_command( NT_USER_TOKEN *token, const char *command,
+ RPC_BUFFER *inbuf, RPC_BUFFER *outbuf,
+ uint32 *needed )
+{
+ int i;
+
+ DEBUG(10,("process_xcvtcp_command: Received command \"%s\"\n", command));
+
+ for ( i=0; xcvtcp_cmds[i].name; i++ ) {
+ if ( strcmp( command, xcvtcp_cmds[i].name ) == 0 )
+ return xcvtcp_cmds[i].fn( token, inbuf, outbuf, needed );
+ }
+
+ return WERR_BADFUNC;
+}
+
+/*******************************************************************
+*******************************************************************/
+#if 0 /* don't support management using the "Local Port" monitor */
+
+static WERROR xcvlocal_monitorui( NT_USER_TOKEN *token, RPC_BUFFER *in,
+ RPC_BUFFER *out, uint32 *needed )
+{
+ const char *dllname = "localui.dll";
+
+ *needed = (strlen(dllname)+1) * 2;
+
+ if ( rpcbuf_get_size(out) < *needed ) {
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ if ( !make_monitorui_buf( out, dllname )) {
+ return WERR_NOMEM;
+ }
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+struct xcv_api_table xcvlocal_cmds[] = {
+ { "MonitorUI", xcvlocal_monitorui },
+ { NULL, NULL }
+};
+#else
+struct xcv_api_table xcvlocal_cmds[] = {
+ { NULL, NULL }
+};
+#endif
+
+
+
+/*******************************************************************
+*******************************************************************/
+
+static WERROR process_xcvlocal_command( NT_USER_TOKEN *token, const char *command,
+ RPC_BUFFER *inbuf, RPC_BUFFER *outbuf,
+ uint32 *needed )
+{
+ int i;
+
+ DEBUG(10,("process_xcvlocal_command: Received command \"%s\"\n", command));
+
+ for ( i=0; xcvlocal_cmds[i].name; i++ ) {
+ if ( strcmp( command, xcvlocal_cmds[i].name ) == 0 )
+ return xcvlocal_cmds[i].fn( token, inbuf, outbuf , needed );
+ }
+ return WERR_BADFUNC;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+WERROR _spoolss_xcvdataport(pipes_struct *p, SPOOL_Q_XCVDATAPORT *q_u, SPOOL_R_XCVDATAPORT *r_u)
+{
+ Printer_entry *Printer = find_printer_index_by_hnd(p, &q_u->handle);
+ fstring command;
+
+ if (!Printer) {
+ DEBUG(2,("_spoolss_xcvdataport: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(&q_u->handle)));
+ return WERR_BADFID;
+ }
+
+ /* Has to be a handle to the TCP/IP port monitor */
+
+ if ( !(Printer->printer_type & (SPLHND_PORTMON_LOCAL|SPLHND_PORTMON_TCP)) ) {
+ DEBUG(2,("_spoolss_xcvdataport: Call only valid for Port Monitors\n"));
+ return WERR_BADFID;
+ }
+
+ /* requires administrative access to the server */
+
+ if ( !(Printer->access_granted & SERVER_ACCESS_ADMINISTER) ) {
+ DEBUG(2,("_spoolss_xcvdataport: denied by handle permissions.\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ /* Get the command name. There's numerous commands supported by the
+ TCPMON interface. */
+
+ rpcstr_pull(command, q_u->dataname.buffer, sizeof(command),
+ q_u->dataname.uni_str_len*2, 0);
+
+ /* Allocate the outgoing buffer */
+
+ rpcbuf_init( &r_u->outdata, q_u->offered, p->mem_ctx );
+
+ switch ( Printer->printer_type ) {
+ case SPLHND_PORTMON_TCP:
+ return process_xcvtcp_command( p->pipe_user.nt_user_token, command,
+ &q_u->indata, &r_u->outdata, &r_u->needed );
+ case SPLHND_PORTMON_LOCAL:
+ return process_xcvlocal_command( p->pipe_user.nt_user_token, command,
+ &q_u->indata, &r_u->outdata, &r_u->needed );
+ }
+
+ return WERR_INVALID_PRINT_MONITOR;
+}
diff --git a/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c
new file mode 100644
index 0000000000..bb9c3687fb
--- /dev/null
+++ b/source3/rpc_server/srv_srvsvc_nt.c
@@ -0,0 +1,2624 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Jeremy Allison 2001.
+ * Copyright (C) Nigel Williams 2001.
+ * Copyright (C) Gerald (Jerry) Carter 2006.
+ * Copyright (C) Guenther Deschner 2008.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This is the implementation of the srvsvc pipe. */
+
+#include "includes.h"
+
+extern const struct generic_mapping file_generic_mapping;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+#define MAX_SERVER_DISK_ENTRIES 15
+
+/* Use for enumerating connections, pipes, & files */
+
+struct file_enum_count {
+ TALLOC_CTX *ctx;
+ const char *username;
+ struct srvsvc_NetFileCtr3 *ctr3;
+};
+
+struct sess_file_count {
+ struct server_id pid;
+ uid_t uid;
+ int count;
+};
+
+/****************************************************************************
+ Count the entries belonging to a service in the connection db.
+****************************************************************************/
+
+static int pipe_enum_fn( struct db_record *rec, void *p)
+{
+ struct pipe_open_rec prec;
+ struct file_enum_count *fenum = (struct file_enum_count *)p;
+ struct srvsvc_NetFileInfo3 *f;
+ int i = fenum->ctr3->count;
+ char *fullpath = NULL;
+ const char *username;
+
+ if (rec->value.dsize != sizeof(struct pipe_open_rec))
+ return 0;
+
+ memcpy(&prec, rec->value.dptr, sizeof(struct pipe_open_rec));
+
+ if ( !process_exists(prec.pid) ) {
+ return 0;
+ }
+
+ username = uidtoname(prec.uid);
+
+ if ((fenum->username != NULL)
+ && !strequal(username, fenum->username)) {
+ return 0;
+ }
+
+ fullpath = talloc_asprintf(fenum->ctx, "\\PIPE\\%s", prec.name );
+ if (!fullpath) {
+ return 1;
+ }
+
+ f = TALLOC_REALLOC_ARRAY(fenum->ctx, fenum->ctr3->array,
+ struct srvsvc_NetFileInfo3, i+1);
+ if ( !f ) {
+ DEBUG(0,("conn_enum_fn: realloc failed for %d items\n", i+1));
+ return 1;
+ }
+ fenum->ctr3->array = f;
+
+ init_srvsvc_NetFileInfo3(&fenum->ctr3->array[i],
+ (((uint32_t)(procid_to_pid(&prec.pid))<<16) | prec.pnum),
+ (FILE_READ_DATA|FILE_WRITE_DATA),
+ 0,
+ fullpath,
+ username);
+
+ fenum->ctr3->count++;
+
+ return 0;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static WERROR net_enum_pipes(TALLOC_CTX *ctx,
+ const char *username,
+ struct srvsvc_NetFileCtr3 **ctr3,
+ uint32_t resume )
+{
+ struct file_enum_count fenum;
+
+ fenum.ctx = ctx;
+ fenum.username = username;
+ fenum.ctr3 = *ctr3;
+
+ if (connections_traverse(pipe_enum_fn, &fenum) == -1) {
+ DEBUG(0,("net_enum_pipes: traverse of connections.tdb "
+ "failed\n"));
+ return WERR_NOMEM;
+ }
+
+ *ctr3 = fenum.ctr3;
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static void enum_file_fn( const struct share_mode_entry *e,
+ const char *sharepath, const char *fname,
+ void *private_data )
+{
+ struct file_enum_count *fenum =
+ (struct file_enum_count *)private_data;
+
+ struct srvsvc_NetFileInfo3 *f;
+ int i = fenum->ctr3->count;
+ files_struct fsp;
+ struct byte_range_lock *brl;
+ int num_locks = 0;
+ char *fullpath = NULL;
+ uint32 permissions;
+ const char *username;
+
+ /* If the pid was not found delete the entry from connections.tdb */
+
+ if ( !process_exists(e->pid) ) {
+ return;
+ }
+
+ username = uidtoname(e->uid);
+
+ if ((fenum->username != NULL)
+ && !strequal(username, fenum->username)) {
+ return;
+ }
+
+ f = TALLOC_REALLOC_ARRAY(fenum->ctx, fenum->ctr3->array,
+ struct srvsvc_NetFileInfo3, i+1);
+ if ( !f ) {
+ DEBUG(0,("conn_enum_fn: realloc failed for %d items\n", i+1));
+ return;
+ }
+ fenum->ctr3->array = f;
+
+ /* need to count the number of locks on a file */
+
+ ZERO_STRUCT( fsp );
+ fsp.file_id = e->id;
+
+ if ( (brl = brl_get_locks(talloc_tos(), &fsp)) != NULL ) {
+ num_locks = brl->num_locks;
+ TALLOC_FREE(brl);
+ }
+
+ if ( strcmp( fname, "." ) == 0 ) {
+ fullpath = talloc_asprintf(fenum->ctx, "C:%s", sharepath );
+ } else {
+ fullpath = talloc_asprintf(fenum->ctx, "C:%s/%s",
+ sharepath, fname );
+ }
+ if (!fullpath) {
+ return;
+ }
+ string_replace( fullpath, '/', '\\' );
+
+ /* mask out create (what ever that is) */
+ permissions = e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA);
+
+ /* now fill in the srvsvc_NetFileInfo3 struct */
+ init_srvsvc_NetFileInfo3(&fenum->ctr3->array[i],
+ (((uint32_t)(procid_to_pid(&e->pid))<<16) | e->share_file_id),
+ permissions,
+ num_locks,
+ fullpath,
+ username);
+ fenum->ctr3->count++;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static WERROR net_enum_files(TALLOC_CTX *ctx,
+ const char *username,
+ struct srvsvc_NetFileCtr3 **ctr3,
+ uint32_t resume)
+{
+ struct file_enum_count f_enum_cnt;
+
+ f_enum_cnt.ctx = ctx;
+ f_enum_cnt.username = username;
+ f_enum_cnt.ctr3 = *ctr3;
+
+ share_mode_forall( enum_file_fn, (void *)&f_enum_cnt );
+
+ *ctr3 = f_enum_cnt.ctr3;
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ Utility function to get the 'type' of a share from an snum.
+ ********************************************************************/
+static uint32 get_share_type(int snum)
+{
+ /* work out the share type */
+ uint32 type = STYPE_DISKTREE;
+
+ if (lp_print_ok(snum))
+ type = STYPE_PRINTQ;
+ if (strequal(lp_fstype(snum), "IPC"))
+ type = STYPE_IPC;
+ if (lp_administrative_share(snum))
+ type |= STYPE_HIDDEN;
+
+ return type;
+}
+
+/*******************************************************************
+ Fill in a share info level 0 structure.
+ ********************************************************************/
+
+static void init_srv_share_info_0(pipes_struct *p, struct srvsvc_NetShareInfo0 *r, int snum)
+{
+ const char *net_name = lp_servicename(snum);
+
+ init_srvsvc_NetShareInfo0(r, net_name);
+}
+
+/*******************************************************************
+ Fill in a share info level 1 structure.
+ ********************************************************************/
+
+static void init_srv_share_info_1(pipes_struct *p, struct srvsvc_NetShareInfo1 *r, int snum)
+{
+ char *net_name = lp_servicename(snum);
+ char *remark = talloc_strdup(p->mem_ctx, lp_comment(snum));
+
+ if (remark) {
+ remark = talloc_sub_advanced(
+ p->mem_ctx, lp_servicename(snum),
+ get_current_username(), lp_pathname(snum),
+ p->pipe_user.ut.uid, get_current_username(),
+ "", remark);
+ }
+
+ init_srvsvc_NetShareInfo1(r, net_name,
+ get_share_type(snum),
+ remark ? remark : "");
+}
+
+/*******************************************************************
+ Fill in a share info level 2 structure.
+ ********************************************************************/
+
+static void init_srv_share_info_2(pipes_struct *p, struct srvsvc_NetShareInfo2 *r, int snum)
+{
+ char *remark = NULL;
+ char *path = NULL;
+ int max_connections = lp_max_connections(snum);
+ uint32_t max_uses = max_connections!=0 ? max_connections : (uint32_t)-1;
+ int count = 0;
+ char *net_name = lp_servicename(snum);
+
+ remark = talloc_strdup(p->mem_ctx, lp_comment(snum));
+ if (remark) {
+ remark = talloc_sub_advanced(
+ p->mem_ctx, lp_servicename(snum),
+ get_current_username(), lp_pathname(snum),
+ p->pipe_user.ut.uid, get_current_username(),
+ "", remark);
+ }
+ path = talloc_asprintf(p->mem_ctx,
+ "C:%s", lp_pathname(snum));
+
+ if (path) {
+ /*
+ * Change / to \\ so that win2k will see it as a valid path.
+ * This was added to enable use of browsing in win2k add
+ * share dialog.
+ */
+
+ string_replace(path, '/', '\\');
+ }
+
+ count = count_current_connections(net_name, false);
+
+ init_srvsvc_NetShareInfo2(r, net_name,
+ get_share_type(snum),
+ remark ? remark : "",
+ 0,
+ max_uses,
+ count,
+ path ? path : "",
+ "");
+}
+
+/*******************************************************************
+ Map any generic bits to file specific bits.
+********************************************************************/
+
+static void map_generic_share_sd_bits(SEC_DESC *psd)
+{
+ int i;
+ SEC_ACL *ps_dacl = NULL;
+
+ if (!psd)
+ return;
+
+ ps_dacl = psd->dacl;
+ if (!ps_dacl)
+ return;
+
+ for (i = 0; i < ps_dacl->num_aces; i++) {
+ SEC_ACE *psa = &ps_dacl->aces[i];
+ uint32 orig_mask = psa->access_mask;
+
+ se_map_generic(&psa->access_mask, &file_generic_mapping);
+ psa->access_mask |= orig_mask;
+ }
+}
+
+/*******************************************************************
+ Fill in a share info level 501 structure.
+********************************************************************/
+
+static void init_srv_share_info_501(pipes_struct *p, struct srvsvc_NetShareInfo501 *r, int snum)
+{
+ const char *net_name = lp_servicename(snum);
+ char *remark = talloc_strdup(p->mem_ctx, lp_comment(snum));
+
+ if (remark) {
+ remark = talloc_sub_advanced(
+ p->mem_ctx, lp_servicename(snum),
+ get_current_username(), lp_pathname(snum),
+ p->pipe_user.ut.uid, get_current_username(),
+ "", remark);
+ }
+
+ init_srvsvc_NetShareInfo501(r, net_name,
+ get_share_type(snum),
+ remark ? remark : "",
+ (lp_csc_policy(snum) << 4));
+}
+
+/*******************************************************************
+ Fill in a share info level 502 structure.
+ ********************************************************************/
+
+static void init_srv_share_info_502(pipes_struct *p, struct srvsvc_NetShareInfo502 *r, int snum)
+{
+ const char *net_name = lp_servicename(snum);
+ char *path = NULL;
+ SEC_DESC *sd = NULL;
+ struct sec_desc_buf *sd_buf = NULL;
+ size_t sd_size = 0;
+ TALLOC_CTX *ctx = p->mem_ctx;
+ char *remark = talloc_strdup(ctx, lp_comment(snum));;
+
+ if (remark) {
+ remark = talloc_sub_advanced(
+ p->mem_ctx, lp_servicename(snum),
+ get_current_username(), lp_pathname(snum),
+ p->pipe_user.ut.uid, get_current_username(),
+ "", remark);
+ }
+ path = talloc_asprintf(ctx, "C:%s", lp_pathname(snum));
+ if (path) {
+ /*
+ * Change / to \\ so that win2k will see it as a valid path. This was added to
+ * enable use of browsing in win2k add share dialog.
+ */
+ string_replace(path, '/', '\\');
+ }
+
+ sd = get_share_security(ctx, lp_servicename(snum), &sd_size);
+
+ sd_buf = make_sec_desc_buf(p->mem_ctx, sd_size, sd);
+
+ init_srvsvc_NetShareInfo502(r, net_name,
+ get_share_type(snum),
+ remark ? remark : "",
+ 0,
+ (uint32_t)-1,
+ 1,
+ path ? path : "",
+ "",
+ sd_buf);
+}
+
+/***************************************************************************
+ Fill in a share info level 1004 structure.
+ ***************************************************************************/
+
+static void init_srv_share_info_1004(pipes_struct *p, struct srvsvc_NetShareInfo1004 *r, int snum)
+{
+ char *remark = talloc_strdup(p->mem_ctx, lp_comment(snum));
+
+ if (remark) {
+ remark = talloc_sub_advanced(
+ p->mem_ctx, lp_servicename(snum),
+ get_current_username(), lp_pathname(snum),
+ p->pipe_user.ut.uid, get_current_username(),
+ "", remark);
+ }
+
+ init_srvsvc_NetShareInfo1004(r, remark ? remark : "");
+}
+
+/***************************************************************************
+ Fill in a share info level 1005 structure.
+ ***************************************************************************/
+
+static void init_srv_share_info_1005(pipes_struct *p, struct srvsvc_NetShareInfo1005 *r, int snum)
+{
+ uint32_t dfs_flags = 0;
+
+ if (lp_host_msdfs() && lp_msdfs_root(snum)) {
+ dfs_flags |= SHARE_1005_IN_DFS | SHARE_1005_DFS_ROOT;
+ }
+
+ dfs_flags |= lp_csc_policy(snum) << SHARE_1005_CSC_POLICY_SHIFT;
+
+ init_srvsvc_NetShareInfo1005(r, dfs_flags);
+}
+
+/***************************************************************************
+ Fill in a share info level 1006 structure.
+ ***************************************************************************/
+
+static void init_srv_share_info_1006(pipes_struct *p, struct srvsvc_NetShareInfo1006 *r, int snum)
+{
+ init_srvsvc_NetShareInfo1006(r, (uint32_t)-1);
+}
+
+/***************************************************************************
+ Fill in a share info level 1007 structure.
+ ***************************************************************************/
+
+static void init_srv_share_info_1007(pipes_struct *p, struct srvsvc_NetShareInfo1007 *r, int snum)
+{
+ uint32 flags = 0;
+
+ init_srvsvc_NetShareInfo1007(r, flags, "");
+}
+
+/*******************************************************************
+ Fill in a share info level 1501 structure.
+ ********************************************************************/
+
+static void init_srv_share_info_1501(pipes_struct *p, struct sec_desc_buf *r, int snum)
+{
+ SEC_DESC *sd;
+ size_t sd_size;
+ TALLOC_CTX *ctx = p->mem_ctx;
+
+ sd = get_share_security(ctx, lp_servicename(snum), &sd_size);
+
+ r = make_sec_desc_buf(p->mem_ctx, sd_size, sd);
+}
+
+/*******************************************************************
+ True if it ends in '$'.
+ ********************************************************************/
+
+static bool is_hidden_share(int snum)
+{
+ const char *net_name = lp_servicename(snum);
+
+ return (net_name[strlen(net_name) - 1] == '$') ? True : False;
+}
+
+/*******************************************************************
+ Fill in a share info structure.
+ ********************************************************************/
+
+static WERROR init_srv_share_info_ctr(pipes_struct *p,
+ struct srvsvc_NetShareInfoCtr *info_ctr,
+ uint32_t *resume_handle_p,
+ uint32_t *total_entries,
+ bool all_shares)
+{
+ int num_entries = 0;
+ int alloc_entries = 0;
+ int num_services = 0;
+ int snum;
+ TALLOC_CTX *ctx = p->mem_ctx;
+ int i = 0;
+ int valid_share_count = 0;
+ union srvsvc_NetShareCtr ctr;
+ uint32_t resume_handle = resume_handle_p ? *resume_handle_p : 0;
+
+ DEBUG(5,("init_srv_share_info_ctr\n"));
+
+ /* Ensure all the usershares are loaded. */
+ become_root();
+ load_usershare_shares();
+ load_registry_shares();
+ num_services = lp_numservices();
+ unbecome_root();
+
+ /* Count the number of entries. */
+ for (snum = 0; snum < num_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && (all_shares || !is_hidden_share(snum)) ) {
+ DEBUG(10, ("counting service %s\n", lp_servicename(snum)));
+ num_entries++;
+ } else {
+ DEBUG(10, ("NOT counting service %s\n", lp_servicename(snum)));
+ }
+ }
+
+ if (!num_entries || (resume_handle >= num_entries)) {
+ return WERR_OK;
+ }
+
+ /* Calculate alloc entries. */
+ alloc_entries = num_entries - resume_handle;
+ switch (info_ctr->level) {
+ case 0:
+ ctr.ctr0 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr0);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr0);
+
+ ctr.ctr0->count = alloc_entries;
+ ctr.ctr0->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo0, alloc_entries);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr0->array);
+
+ for (snum = 0; snum < num_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && (all_shares || !is_hidden_share(snum)) &&
+ (resume_handle <= (i + valid_share_count++)) ) {
+ init_srv_share_info_0(p, &ctr.ctr0->array[i++], snum);
+ }
+ }
+
+ break;
+
+ case 1:
+ ctr.ctr1 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr1);
+
+ ctr.ctr1->count = alloc_entries;
+ ctr.ctr1->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo1, alloc_entries);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr1->array);
+
+ for (snum = 0; snum < num_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && (all_shares || !is_hidden_share(snum)) &&
+ (resume_handle <= (i + valid_share_count++)) ) {
+ init_srv_share_info_1(p, &ctr.ctr1->array[i++], snum);
+ }
+ }
+
+ break;
+
+ case 2:
+ ctr.ctr2 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr2);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr2);
+
+ ctr.ctr2->count = alloc_entries;
+ ctr.ctr2->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo2, alloc_entries);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr2->array);
+
+ for (snum = 0; snum < num_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && (all_shares || !is_hidden_share(snum)) &&
+ (resume_handle <= (i + valid_share_count++)) ) {
+ init_srv_share_info_2(p, &ctr.ctr2->array[i++], snum);
+ }
+ }
+
+ break;
+
+ case 501:
+ ctr.ctr501 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr501);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr501);
+
+ ctr.ctr501->count = alloc_entries;
+ ctr.ctr501->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo501, alloc_entries);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr501->array);
+
+ for (snum = 0; snum < num_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && (all_shares || !is_hidden_share(snum)) &&
+ (resume_handle <= (i + valid_share_count++)) ) {
+ init_srv_share_info_501(p, &ctr.ctr501->array[i++], snum);
+ }
+ }
+
+ break;
+
+ case 502:
+ ctr.ctr502 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr502);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr502);
+
+ ctr.ctr502->count = alloc_entries;
+ ctr.ctr502->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo502, alloc_entries);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr502->array);
+
+ for (snum = 0; snum < num_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && (all_shares || !is_hidden_share(snum)) &&
+ (resume_handle <= (i + valid_share_count++)) ) {
+ init_srv_share_info_502(p, &ctr.ctr502->array[i++], snum);
+ }
+ }
+
+ break;
+
+ case 1004:
+ ctr.ctr1004 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1004);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr1004);
+
+ ctr.ctr1004->count = alloc_entries;
+ ctr.ctr1004->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo1004, alloc_entries);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr1004->array);
+
+ for (snum = 0; snum < num_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && (all_shares || !is_hidden_share(snum)) &&
+ (resume_handle <= (i + valid_share_count++)) ) {
+ init_srv_share_info_1004(p, &ctr.ctr1004->array[i++], snum);
+ }
+ }
+
+ break;
+
+ case 1005:
+ ctr.ctr1005 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1005);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr1005);
+
+ ctr.ctr1005->count = alloc_entries;
+ ctr.ctr1005->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo1005, alloc_entries);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr1005->array);
+
+ for (snum = 0; snum < num_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && (all_shares || !is_hidden_share(snum)) &&
+ (resume_handle <= (i + valid_share_count++)) ) {
+ init_srv_share_info_1005(p, &ctr.ctr1005->array[i++], snum);
+ }
+ }
+
+ break;
+
+ case 1006:
+ ctr.ctr1006 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1006);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr1006);
+
+ ctr.ctr1006->count = alloc_entries;
+ ctr.ctr1006->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo1006, alloc_entries);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr1006->array);
+
+ for (snum = 0; snum < num_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && (all_shares || !is_hidden_share(snum)) &&
+ (resume_handle <= (i + valid_share_count++)) ) {
+ init_srv_share_info_1006(p, &ctr.ctr1006->array[i++], snum);
+ }
+ }
+
+ break;
+
+ case 1007:
+ ctr.ctr1007 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1007);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr1007);
+
+ ctr.ctr1007->count = alloc_entries;
+ ctr.ctr1007->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo1007, alloc_entries);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr1007->array);
+
+ for (snum = 0; snum < num_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && (all_shares || !is_hidden_share(snum)) &&
+ (resume_handle <= (i + valid_share_count++)) ) {
+ init_srv_share_info_1007(p, &ctr.ctr1007->array[i++], snum);
+ }
+ }
+
+ break;
+
+ case 1501:
+ ctr.ctr1501 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1501);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr1501);
+
+ ctr.ctr1501->count = alloc_entries;
+ ctr.ctr1501->array = TALLOC_ZERO_ARRAY(ctx, struct sec_desc_buf, alloc_entries);
+ W_ERROR_HAVE_NO_MEMORY(ctr.ctr1501->array);
+
+ for (snum = 0; snum < num_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && (all_shares || !is_hidden_share(snum)) &&
+ (resume_handle <= (i + valid_share_count++)) ) {
+ init_srv_share_info_1501(p, &ctr.ctr1501->array[i++], snum);
+ }
+ }
+
+ break;
+
+ default:
+ DEBUG(5,("init_srv_share_info_ctr: unsupported switch value %d\n",
+ info_ctr->level));
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ *total_entries = alloc_entries;
+ if (resume_handle_p) {
+ if (all_shares) {
+ *resume_handle_p = (num_entries == 0) ? *resume_handle_p : 0;
+ } else {
+ *resume_handle_p = num_entries;
+ }
+ }
+
+ info_ctr->ctr = ctr;
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ fill in a sess info level 0 structure.
+ ********************************************************************/
+
+static WERROR init_srv_sess_info_0(pipes_struct *p,
+ struct srvsvc_NetSessCtr0 *ctr0,
+ uint32_t *resume_handle_p,
+ uint32_t *total_entries)
+{
+ struct sessionid *session_list;
+ uint32_t num_entries = 0;
+ uint32_t resume_handle = resume_handle_p ? *resume_handle_p : 0;
+ *total_entries = list_sessions(p->mem_ctx, &session_list);
+
+ DEBUG(5,("init_srv_sess_info_0\n"));
+
+ if (ctr0 == NULL) {
+ if (resume_handle_p) {
+ *resume_handle_p = 0;
+ }
+ return WERR_OK;
+ }
+
+ for (; resume_handle < *total_entries; resume_handle++) {
+
+ ctr0->array = TALLOC_REALLOC_ARRAY(p->mem_ctx,
+ ctr0->array,
+ struct srvsvc_NetSessInfo0,
+ num_entries+1);
+ W_ERROR_HAVE_NO_MEMORY(ctr0->array);
+
+ init_srvsvc_NetSessInfo0(&ctr0->array[num_entries],
+ session_list[resume_handle].remote_machine);
+ num_entries++;
+ }
+
+ ctr0->count = num_entries;
+
+ if (resume_handle_p) {
+ if (*resume_handle_p >= *total_entries) {
+ *resume_handle_p = 0;
+ } else {
+ *resume_handle_p = resume_handle;
+ }
+ }
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static void sess_file_fn( const struct share_mode_entry *e,
+ const char *sharepath, const char *fname,
+ void *data )
+{
+ struct sess_file_count *sess = (struct sess_file_count *)data;
+
+ if ( procid_equal(&e->pid, &sess->pid) && (sess->uid == e->uid) ) {
+ sess->count++;
+ }
+
+ return;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static int net_count_files( uid_t uid, struct server_id pid )
+{
+ struct sess_file_count s_file_cnt;
+
+ s_file_cnt.count = 0;
+ s_file_cnt.uid = uid;
+ s_file_cnt.pid = pid;
+
+ share_mode_forall( sess_file_fn, &s_file_cnt );
+
+ return s_file_cnt.count;
+}
+
+/*******************************************************************
+ fill in a sess info level 1 structure.
+ ********************************************************************/
+
+static WERROR init_srv_sess_info_1(pipes_struct *p,
+ struct srvsvc_NetSessCtr1 *ctr1,
+ uint32_t *resume_handle_p,
+ uint32_t *total_entries)
+{
+ struct sessionid *session_list;
+ uint32_t num_entries = 0;
+ time_t now = time(NULL);
+ uint32_t resume_handle = resume_handle_p ? *resume_handle_p : 0;
+
+ ZERO_STRUCTP(ctr1);
+
+ if (ctr1 == NULL) {
+ if (resume_handle_p) {
+ *resume_handle_p = 0;
+ }
+ return WERR_OK;
+ }
+
+ *total_entries = list_sessions(p->mem_ctx, &session_list);
+
+ for (; resume_handle < *total_entries; resume_handle++) {
+ uint32 num_files;
+ uint32 connect_time;
+ struct passwd *pw = sys_getpwnam(session_list[resume_handle].username);
+ bool guest;
+
+ if ( !pw ) {
+ DEBUG(10,("init_srv_sess_info_1: failed to find owner: %s\n",
+ session_list[resume_handle].username));
+ continue;
+ }
+
+ connect_time = (uint32_t)(now - session_list[resume_handle].connect_start);
+ num_files = net_count_files(pw->pw_uid, session_list[resume_handle].pid);
+ guest = strequal( session_list[resume_handle].username, lp_guestaccount() );
+
+ ctr1->array = TALLOC_REALLOC_ARRAY(p->mem_ctx,
+ ctr1->array,
+ struct srvsvc_NetSessInfo1,
+ num_entries+1);
+ W_ERROR_HAVE_NO_MEMORY(ctr1->array);
+
+ init_srvsvc_NetSessInfo1(&ctr1->array[num_entries],
+ session_list[resume_handle].remote_machine,
+ session_list[resume_handle].username,
+ num_files,
+ connect_time,
+ 0,
+ guest);
+ num_entries++;
+ }
+
+ ctr1->count = num_entries;
+
+ if (resume_handle_p) {
+ if (*resume_handle_p >= *total_entries) {
+ *resume_handle_p = 0;
+ } else {
+ *resume_handle_p = resume_handle;
+ }
+ }
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ fill in a conn info level 0 structure.
+ ********************************************************************/
+
+static WERROR init_srv_conn_info_0(struct srvsvc_NetConnCtr0 *ctr0,
+ uint32_t *resume_handle_p,
+ uint32_t *total_entries)
+{
+ uint32_t num_entries = 0;
+ uint32_t resume_handle = resume_handle_p ? *resume_handle_p : 0;
+
+ DEBUG(5,("init_srv_conn_info_0\n"));
+
+ if (ctr0 == NULL) {
+ if (resume_handle_p) {
+ *resume_handle_p = 0;
+ }
+ return WERR_OK;
+ }
+
+ *total_entries = 1;
+
+ ZERO_STRUCTP(ctr0);
+
+ for (; resume_handle < *total_entries; resume_handle++) {
+
+ ctr0->array = TALLOC_REALLOC_ARRAY(talloc_tos(),
+ ctr0->array,
+ struct srvsvc_NetConnInfo0,
+ num_entries+1);
+ if (!ctr0->array) {
+ return WERR_NOMEM;
+ }
+
+ init_srvsvc_NetConnInfo0(&ctr0->array[num_entries],
+ (*total_entries));
+
+ /* move on to creating next connection */
+ num_entries++;
+ }
+
+ ctr0->count = num_entries;
+ *total_entries = num_entries;
+
+ if (resume_handle_p) {
+ if (*resume_handle_p >= *total_entries) {
+ *resume_handle_p = 0;
+ } else {
+ *resume_handle_p = resume_handle;
+ }
+ }
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ fill in a conn info level 1 structure.
+ ********************************************************************/
+
+static WERROR init_srv_conn_info_1(struct srvsvc_NetConnCtr1 *ctr1,
+ uint32_t *resume_handle_p,
+ uint32_t *total_entries)
+{
+ uint32_t num_entries = 0;
+ uint32_t resume_handle = resume_handle_p ? *resume_handle_p : 0;
+
+ DEBUG(5,("init_srv_conn_info_1\n"));
+
+ if (ctr1 == NULL) {
+ if (resume_handle_p) {
+ *resume_handle_p = 0;
+ }
+ return WERR_OK;
+ }
+
+ *total_entries = 1;
+
+ ZERO_STRUCTP(ctr1);
+
+ for (; resume_handle < *total_entries; resume_handle++) {
+
+ ctr1->array = TALLOC_REALLOC_ARRAY(talloc_tos(),
+ ctr1->array,
+ struct srvsvc_NetConnInfo1,
+ num_entries+1);
+ if (!ctr1->array) {
+ return WERR_NOMEM;
+ }
+
+ init_srvsvc_NetConnInfo1(&ctr1->array[num_entries],
+ (*total_entries),
+ 0x3,
+ 1,
+ 1,
+ 3,
+ "dummy_user",
+ "IPC$");
+
+ /* move on to creating next connection */
+ num_entries++;
+ }
+
+ ctr1->count = num_entries;
+ *total_entries = num_entries;
+
+ if (resume_handle_p) {
+ if (*resume_handle_p >= *total_entries) {
+ *resume_handle_p = 0;
+ } else {
+ *resume_handle_p = resume_handle;
+ }
+ }
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ _srvsvc_NetFileEnum
+*******************************************************************/
+
+WERROR _srvsvc_NetFileEnum(pipes_struct *p,
+ struct srvsvc_NetFileEnum *r)
+{
+ TALLOC_CTX *ctx = NULL;
+ struct srvsvc_NetFileCtr3 *ctr3;
+ uint32_t resume_hnd = 0;
+ WERROR werr;
+
+ switch (r->in.info_ctr->level) {
+ case 3:
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ ctx = talloc_tos();
+ ctr3 = r->in.info_ctr->ctr.ctr3;
+ if (!ctr3) {
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ /* TODO -- Windows enumerates
+ (b) active pipes
+ (c) open directories and files */
+
+ werr = net_enum_files(ctx, r->in.user, &ctr3, resume_hnd);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = net_enum_pipes(ctx, r->in.user, &ctr3, resume_hnd);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ *r->out.totalentries = ctr3->count;
+ r->out.info_ctr->ctr.ctr3->array = ctr3->array;
+ r->out.info_ctr->ctr.ctr3->count = ctr3->count;
+
+ werr = WERR_OK;
+
+ done:
+ return werr;
+}
+
+/*******************************************************************
+ _srvsvc_NetSrvGetInfo
+********************************************************************/
+
+WERROR _srvsvc_NetSrvGetInfo(pipes_struct *p,
+ struct srvsvc_NetSrvGetInfo *r)
+{
+ WERROR status = WERR_OK;
+
+ DEBUG(5,("_srvsvc_NetSrvGetInfo: %d\n", __LINE__));
+
+ if (!pipe_access_check(p)) {
+ DEBUG(3, ("access denied to _srvsvc_NetSrvGetInfo\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ switch (r->in.level) {
+
+ /* Technically level 102 should only be available to
+ Administrators but there isn't anything super-secret
+ here, as most of it is made up. */
+
+ case 102: {
+ struct srvsvc_NetSrvInfo102 *info102;
+
+ info102 = TALLOC_P(p->mem_ctx, struct srvsvc_NetSrvInfo102);
+ if (!info102) {
+ return WERR_NOMEM;
+ }
+
+ init_srvsvc_NetSrvInfo102(info102,
+ PLATFORM_ID_NT,
+ global_myname(),
+ lp_major_announce_version(),
+ lp_minor_announce_version(),
+ lp_default_server_announce(),
+ string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH),
+ 0xffffffff, /* users */
+ 0xf, /* disc */
+ 0, /* hidden */
+ 240, /* announce */
+ 3000, /* announce delta */
+ 100000, /* licenses */
+ "c:\\"); /* user path */
+ r->out.info->info102 = info102;
+ break;
+ }
+ case 101: {
+ struct srvsvc_NetSrvInfo101 *info101;
+
+ info101 = TALLOC_P(p->mem_ctx, struct srvsvc_NetSrvInfo101);
+ if (!info101) {
+ return WERR_NOMEM;
+ }
+
+ init_srvsvc_NetSrvInfo101(info101,
+ PLATFORM_ID_NT,
+ global_myname(),
+ lp_major_announce_version(),
+ lp_minor_announce_version(),
+ lp_default_server_announce(),
+ string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
+ r->out.info->info101 = info101;
+ break;
+ }
+ case 100: {
+ struct srvsvc_NetSrvInfo100 *info100;
+
+ info100 = TALLOC_P(p->mem_ctx, struct srvsvc_NetSrvInfo100);
+ if (!info100) {
+ return WERR_NOMEM;
+ }
+
+ init_srvsvc_NetSrvInfo100(info100,
+ PLATFORM_ID_NT,
+ global_myname());
+ r->out.info->info100 = info100;
+
+ break;
+ }
+ default:
+ status = WERR_UNKNOWN_LEVEL;
+ break;
+ }
+
+ DEBUG(5,("_srvsvc_NetSrvGetInfo: %d\n", __LINE__));
+
+ return status;
+}
+
+/*******************************************************************
+ _srvsvc_NetSrvSetInfo
+********************************************************************/
+
+WERROR _srvsvc_NetSrvSetInfo(pipes_struct *p,
+ struct srvsvc_NetSrvSetInfo *r)
+{
+ WERROR status = WERR_OK;
+
+ DEBUG(5,("_srvsvc_NetSrvSetInfo: %d\n", __LINE__));
+
+ /* Set up the net server set info structure. */
+
+ DEBUG(5,("_srvsvc_NetSrvSetInfo: %d\n", __LINE__));
+
+ return status;
+}
+
+/*******************************************************************
+ _srvsvc_NetConnEnum
+********************************************************************/
+
+WERROR _srvsvc_NetConnEnum(pipes_struct *p,
+ struct srvsvc_NetConnEnum *r)
+{
+ WERROR werr;
+
+ DEBUG(5,("_srvsvc_NetConnEnum: %d\n", __LINE__));
+
+ switch (r->in.info_ctr->level) {
+ case 0:
+ werr = init_srv_conn_info_0(r->in.info_ctr->ctr.ctr0,
+ r->in.resume_handle,
+ r->out.totalentries);
+ break;
+ case 1:
+ werr = init_srv_conn_info_1(r->in.info_ctr->ctr.ctr1,
+ r->in.resume_handle,
+ r->out.totalentries);
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ DEBUG(5,("_srvsvc_NetConnEnum: %d\n", __LINE__));
+
+ return werr;
+}
+
+/*******************************************************************
+ _srvsvc_NetSessEnum
+********************************************************************/
+
+WERROR _srvsvc_NetSessEnum(pipes_struct *p,
+ struct srvsvc_NetSessEnum *r)
+{
+ WERROR werr;
+
+ DEBUG(5,("_srvsvc_NetSessEnum: %d\n", __LINE__));
+
+ switch (r->in.info_ctr->level) {
+ case 0:
+ werr = init_srv_sess_info_0(p,
+ r->in.info_ctr->ctr.ctr0,
+ r->in.resume_handle,
+ r->out.totalentries);
+ break;
+ case 1:
+ werr = init_srv_sess_info_1(p,
+ r->in.info_ctr->ctr.ctr1,
+ r->in.resume_handle,
+ r->out.totalentries);
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ DEBUG(5,("_srvsvc_NetSessEnum: %d\n", __LINE__));
+
+ return werr;
+}
+
+/*******************************************************************
+ _srvsvc_NetSessDel
+********************************************************************/
+
+WERROR _srvsvc_NetSessDel(pipes_struct *p,
+ struct srvsvc_NetSessDel *r)
+{
+ struct sessionid *session_list;
+ struct current_user user;
+ int num_sessions, snum;
+ const char *username;
+ const char *machine;
+ bool not_root = False;
+ WERROR werr;
+
+ username = r->in.user;
+ machine = r->in.client;
+
+ /* strip leading backslashes if any */
+ if (machine && machine[0] == '\\' && machine[1] == '\\') {
+ machine += 2;
+ }
+
+ num_sessions = list_sessions(p->mem_ctx, &session_list);
+
+ DEBUG(5,("_srvsvc_NetSessDel: %d\n", __LINE__));
+
+ werr = WERR_ACCESS_DENIED;
+
+ get_current_user(&user, p);
+
+ /* fail out now if you are not root or not a domain admin */
+
+ if ((user.ut.uid != sec_initial_uid()) &&
+ ( ! nt_token_check_domain_rid(p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS))) {
+
+ goto done;
+ }
+
+ for (snum = 0; snum < num_sessions; snum++) {
+
+ if ((strequal(session_list[snum].username, username) || username[0] == '\0' ) &&
+ strequal(session_list[snum].remote_machine, machine)) {
+
+ NTSTATUS ntstat;
+
+ if (user.ut.uid != sec_initial_uid()) {
+ not_root = True;
+ become_root();
+ }
+
+ ntstat = messaging_send(smbd_messaging_context(),
+ session_list[snum].pid,
+ MSG_SHUTDOWN, &data_blob_null);
+
+ if (NT_STATUS_IS_OK(ntstat))
+ werr = WERR_OK;
+
+ if (not_root)
+ unbecome_root();
+ }
+ }
+
+ DEBUG(5,("_srvsvc_NetSessDel: %d\n", __LINE__));
+
+done:
+
+ return werr;
+}
+
+/*******************************************************************
+ _srvsvc_NetShareEnumAll
+********************************************************************/
+
+WERROR _srvsvc_NetShareEnumAll(pipes_struct *p,
+ struct srvsvc_NetShareEnumAll *r)
+{
+ WERROR werr;
+
+ DEBUG(5,("_srvsvc_NetShareEnumAll: %d\n", __LINE__));
+
+ if (!pipe_access_check(p)) {
+ DEBUG(3, ("access denied to _srvsvc_NetShareEnumAll\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ /* Create the list of shares for the response. */
+ werr = init_srv_share_info_ctr(p,
+ r->in.info_ctr,
+ r->in.resume_handle,
+ r->out.totalentries,
+ true);
+
+ DEBUG(5,("_srvsvc_NetShareEnumAll: %d\n", __LINE__));
+
+ return werr;
+}
+
+/*******************************************************************
+ _srvsvc_NetShareEnum
+********************************************************************/
+
+WERROR _srvsvc_NetShareEnum(pipes_struct *p,
+ struct srvsvc_NetShareEnum *r)
+{
+ WERROR werr;
+
+ DEBUG(5,("_srvsvc_NetShareEnum: %d\n", __LINE__));
+
+ if (!pipe_access_check(p)) {
+ DEBUG(3, ("access denied to _srvsvc_NetShareEnum\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ /* Create the list of shares for the response. */
+ werr = init_srv_share_info_ctr(p,
+ r->in.info_ctr,
+ r->in.resume_handle,
+ r->out.totalentries,
+ false);
+
+ DEBUG(5,("_srvsvc_NetShareEnum: %d\n", __LINE__));
+
+ return werr;
+}
+
+/*******************************************************************
+ _srvsvc_NetShareGetInfo
+********************************************************************/
+
+WERROR _srvsvc_NetShareGetInfo(pipes_struct *p,
+ struct srvsvc_NetShareGetInfo *r)
+{
+ WERROR status = WERR_OK;
+ fstring share_name;
+ int snum;
+ union srvsvc_NetShareInfo *info = r->out.info;
+
+ DEBUG(5,("_srvsvc_NetShareGetInfo: %d\n", __LINE__));
+
+ fstrcpy(share_name, r->in.share_name);
+
+ snum = find_service(share_name);
+ if (snum < 0) {
+ return WERR_INVALID_NAME;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ info->info0 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo0);
+ W_ERROR_HAVE_NO_MEMORY(info->info0);
+ init_srv_share_info_0(p, info->info0, snum);
+ break;
+ case 1:
+ info->info1 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo1);
+ W_ERROR_HAVE_NO_MEMORY(info->info1);
+ init_srv_share_info_1(p, info->info1, snum);
+ break;
+ case 2:
+ info->info2 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo2);
+ W_ERROR_HAVE_NO_MEMORY(info->info2);
+ init_srv_share_info_2(p, info->info2, snum);
+ break;
+ case 501:
+ info->info501 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo501);
+ W_ERROR_HAVE_NO_MEMORY(info->info501);
+ init_srv_share_info_501(p, info->info501, snum);
+ break;
+ case 502:
+ info->info502 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo502);
+ W_ERROR_HAVE_NO_MEMORY(info->info502);
+ init_srv_share_info_502(p, info->info502, snum);
+ break;
+ case 1004:
+ info->info1004 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo1004);
+ W_ERROR_HAVE_NO_MEMORY(info->info1004);
+ init_srv_share_info_1004(p, info->info1004, snum);
+ break;
+ case 1005:
+ info->info1005 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo1005);
+ W_ERROR_HAVE_NO_MEMORY(info->info1005);
+ init_srv_share_info_1005(p, info->info1005, snum);
+ break;
+ case 1006:
+ info->info1006 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo1006);
+ W_ERROR_HAVE_NO_MEMORY(info->info1006);
+ init_srv_share_info_1006(p, info->info1006, snum);
+ break;
+ case 1007:
+ info->info1007 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo1007);
+ W_ERROR_HAVE_NO_MEMORY(info->info1007);
+ init_srv_share_info_1007(p, info->info1007, snum);
+ break;
+ case 1501:
+ init_srv_share_info_1501(p, info->info1501, snum);
+ break;
+ default:
+ DEBUG(5,("_srvsvc_NetShareGetInfo: unsupported switch value %d\n",
+ r->in.level));
+ status = WERR_UNKNOWN_LEVEL;
+ break;
+ }
+
+ DEBUG(5,("_srvsvc_NetShareGetInfo: %d\n", __LINE__));
+
+ return status;
+}
+
+/*******************************************************************
+ Check a given DOS pathname is valid for a share.
+********************************************************************/
+
+char *valid_share_pathname(TALLOC_CTX *ctx, const char *dos_pathname)
+{
+ char *ptr = NULL;
+
+ if (!dos_pathname) {
+ return NULL;
+ }
+
+ ptr = talloc_strdup(ctx, dos_pathname);
+ if (!ptr) {
+ return NULL;
+ }
+ /* Convert any '\' paths to '/' */
+ unix_format(ptr);
+ ptr = unix_clean_name(ctx, ptr);
+ if (!ptr) {
+ return NULL;
+ }
+
+ /* NT is braindead - it wants a C: prefix to a pathname ! So strip it. */
+ if (strlen(ptr) > 2 && ptr[1] == ':' && ptr[0] != '/')
+ ptr += 2;
+
+ /* Only absolute paths allowed. */
+ if (*ptr != '/')
+ return NULL;
+
+ return ptr;
+}
+
+/*******************************************************************
+ _srvsvc_NetShareSetInfo. Modify share details.
+********************************************************************/
+
+WERROR _srvsvc_NetShareSetInfo(pipes_struct *p,
+ struct srvsvc_NetShareSetInfo *r)
+{
+ struct current_user user;
+ char *command = NULL;
+ char *share_name = NULL;
+ char *comment = NULL;
+ const char *pathname = NULL;
+ int type;
+ int snum;
+ int ret;
+ char *path = NULL;
+ SEC_DESC *psd = NULL;
+ SE_PRIV se_diskop = SE_DISK_OPERATOR;
+ bool is_disk_op = False;
+ int max_connections = 0;
+ TALLOC_CTX *ctx = p->mem_ctx;
+ union srvsvc_NetShareInfo *info = r->in.info;
+
+ DEBUG(5,("_srvsvc_NetShareSetInfo: %d\n", __LINE__));
+
+ share_name = talloc_strdup(p->mem_ctx, r->in.share_name);
+ if (!share_name) {
+ return WERR_NOMEM;
+ }
+
+ if (r->out.parm_error) {
+ *r->out.parm_error = 0;
+ }
+
+ if ( strequal(share_name,"IPC$")
+ || ( lp_enable_asu_support() && strequal(share_name,"ADMIN$") )
+ || strequal(share_name,"global") )
+ {
+ return WERR_ACCESS_DENIED;
+ }
+
+ snum = find_service(share_name);
+
+ /* Does this share exist ? */
+ if (snum < 0)
+ return WERR_NET_NAME_NOT_FOUND;
+
+ /* No change to printer shares. */
+ if (lp_print_ok(snum))
+ return WERR_ACCESS_DENIED;
+
+ get_current_user(&user,p);
+
+ is_disk_op = user_has_privileges( p->pipe_user.nt_user_token, &se_diskop );
+
+ /* fail out now if you are not root and not a disk op */
+
+ if ( user.ut.uid != sec_initial_uid() && !is_disk_op )
+ return WERR_ACCESS_DENIED;
+
+ switch (r->in.level) {
+ case 1:
+ pathname = talloc_strdup(ctx, lp_pathname(snum));
+ comment = talloc_strdup(ctx, info->info1->comment);
+ type = info->info1->type;
+ psd = NULL;
+ break;
+ case 2:
+ comment = talloc_strdup(ctx, info->info2->comment);
+ pathname = info->info2->path;
+ type = info->info2->type;
+ max_connections = (info->info2->max_users == (uint32_t)-1) ?
+ 0 : info->info2->max_users;
+ psd = NULL;
+ break;
+#if 0
+ /* not supported on set but here for completeness */
+ case 501:
+ comment = talloc_strdup(ctx, info->info501->comment);
+ type = info->info501->type;
+ psd = NULL;
+ break;
+#endif
+ case 502:
+ comment = talloc_strdup(ctx, info->info502->comment);
+ pathname = info->info502->path;
+ type = info->info502->type;
+ psd = info->info502->sd_buf.sd;
+ map_generic_share_sd_bits(psd);
+ break;
+ case 1004:
+ pathname = talloc_strdup(ctx, lp_pathname(snum));
+ comment = talloc_strdup(ctx, info->info1004->comment);
+ type = STYPE_DISKTREE;
+ break;
+ case 1005:
+ /* XP re-sets the csc policy even if it wasn't changed by the
+ user, so we must compare it to see if it's what is set in
+ smb.conf, so that we can contine other ops like setting
+ ACLs on a share */
+ if (((info->info1005->dfs_flags &
+ SHARE_1005_CSC_POLICY_MASK) >>
+ SHARE_1005_CSC_POLICY_SHIFT) == lp_csc_policy(snum))
+ return WERR_OK;
+ else {
+ DEBUG(3, ("_srvsvc_NetShareSetInfo: client is trying to change csc policy from the network; must be done with smb.conf\n"));
+ return WERR_ACCESS_DENIED;
+ }
+ case 1006:
+ case 1007:
+ return WERR_ACCESS_DENIED;
+ case 1501:
+ pathname = talloc_strdup(ctx, lp_pathname(snum));
+ comment = talloc_strdup(ctx, lp_comment(snum));
+ psd = info->info1501->sd;
+ map_generic_share_sd_bits(psd);
+ type = STYPE_DISKTREE;
+ break;
+ default:
+ DEBUG(5,("_srvsvc_NetShareSetInfo: unsupported switch value %d\n",
+ r->in.level));
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ /* We can only modify disk shares. */
+ if (type != STYPE_DISKTREE)
+ return WERR_ACCESS_DENIED;
+
+ if (comment == NULL) {
+ return WERR_NOMEM;
+ }
+
+ /* Check if the pathname is valid. */
+ if (!(path = valid_share_pathname(p->mem_ctx, pathname )))
+ return WERR_OBJECT_PATH_INVALID;
+
+ /* Ensure share name, pathname and comment don't contain '"' characters. */
+ string_replace(share_name, '"', ' ');
+ string_replace(path, '"', ' ');
+ string_replace(comment, '"', ' ');
+
+ DEBUG(10,("_srvsvc_NetShareSetInfo: change share command = %s\n",
+ lp_change_share_cmd() ? lp_change_share_cmd() : "NULL" ));
+
+ /* Only call modify function if something changed. */
+
+ if (strcmp(path, lp_pathname(snum)) || strcmp(comment, lp_comment(snum))
+ || (lp_max_connections(snum) != max_connections)) {
+ if (!lp_change_share_cmd() || !*lp_change_share_cmd()) {
+ DEBUG(10,("_srvsvc_NetShareSetInfo: No change share command\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ command = talloc_asprintf(p->mem_ctx,
+ "%s \"%s\" \"%s\" \"%s\" \"%s\" %d",
+ lp_change_share_cmd(),
+ get_dyn_CONFIGFILE(),
+ share_name,
+ path,
+ comment ? comment : "",
+ max_connections);
+ if (!command) {
+ return WERR_NOMEM;
+ }
+
+ DEBUG(10,("_srvsvc_NetShareSetInfo: Running [%s]\n", command ));
+
+ /********* BEGIN SeDiskOperatorPrivilege BLOCK *********/
+
+ if (is_disk_op)
+ become_root();
+
+ if ( (ret = smbrun(command, NULL)) == 0 ) {
+ /* Tell everyone we updated smb.conf. */
+ message_send_all(smbd_messaging_context(),
+ MSG_SMB_CONF_UPDATED, NULL, 0,
+ NULL);
+ }
+
+ if ( is_disk_op )
+ unbecome_root();
+
+ /********* END SeDiskOperatorPrivilege BLOCK *********/
+
+ DEBUG(3,("_srvsvc_NetShareSetInfo: Running [%s] returned (%d)\n",
+ command, ret ));
+
+ TALLOC_FREE(command);
+
+ if ( ret != 0 )
+ return WERR_ACCESS_DENIED;
+ } else {
+ DEBUG(10,("_srvsvc_NetShareSetInfo: No change to share name (%s)\n",
+ share_name ));
+ }
+
+ /* Replace SD if changed. */
+ if (psd) {
+ SEC_DESC *old_sd;
+ size_t sd_size;
+
+ old_sd = get_share_security(p->mem_ctx, lp_servicename(snum), &sd_size);
+
+ if (old_sd && !sec_desc_equal(old_sd, psd)) {
+ if (!set_share_security(share_name, psd))
+ DEBUG(0,("_srvsvc_NetShareSetInfo: Failed to change security info in share %s.\n",
+ share_name ));
+ }
+ }
+
+ DEBUG(5,("_srvsvc_NetShareSetInfo: %d\n", __LINE__));
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ _srvsvc_NetShareAdd.
+ Call 'add_share_command "sharename" "pathname"
+ "comment" "max connections = "
+********************************************************************/
+
+WERROR _srvsvc_NetShareAdd(pipes_struct *p,
+ struct srvsvc_NetShareAdd *r)
+{
+ struct current_user user;
+ char *command = NULL;
+ char *share_name = NULL;
+ char *comment = NULL;
+ char *pathname = NULL;
+ int type;
+ int snum;
+ int ret;
+ char *path;
+ SEC_DESC *psd = NULL;
+ SE_PRIV se_diskop = SE_DISK_OPERATOR;
+ bool is_disk_op;
+ int max_connections = 0;
+ TALLOC_CTX *ctx = p->mem_ctx;
+
+ DEBUG(5,("_srvsvc_NetShareAdd: %d\n", __LINE__));
+
+ *r->out.parm_error = 0;
+
+ get_current_user(&user,p);
+
+ is_disk_op = user_has_privileges( p->pipe_user.nt_user_token, &se_diskop );
+
+ if (user.ut.uid != sec_initial_uid() && !is_disk_op )
+ return WERR_ACCESS_DENIED;
+
+ if (!lp_add_share_cmd() || !*lp_add_share_cmd()) {
+ DEBUG(10,("_srvsvc_NetShareAdd: No add share command\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ switch (r->in.level) {
+ case 0:
+ /* No path. Not enough info in a level 0 to do anything. */
+ return WERR_ACCESS_DENIED;
+ case 1:
+ /* Not enough info in a level 1 to do anything. */
+ return WERR_ACCESS_DENIED;
+ case 2:
+ share_name = talloc_strdup(ctx, r->in.info->info2->name);
+ comment = talloc_strdup(ctx, r->in.info->info2->comment);
+ pathname = talloc_strdup(ctx, r->in.info->info2->path);
+ max_connections = (r->in.info->info2->max_users == (uint32_t)-1) ?
+ 0 : r->in.info->info2->max_users;
+ type = r->in.info->info2->type;
+ break;
+ case 501:
+ /* No path. Not enough info in a level 501 to do anything. */
+ return WERR_ACCESS_DENIED;
+ case 502:
+ share_name = talloc_strdup(ctx, r->in.info->info502->name);
+ comment = talloc_strdup(ctx, r->in.info->info502->comment);
+ pathname = talloc_strdup(ctx, r->in.info->info502->path);
+ max_connections = (r->in.info->info502->max_users == (uint32_t)-1) ?
+ 0 : r->in.info->info502->max_users;
+ type = r->in.info->info502->type;
+ psd = r->in.info->info502->sd_buf.sd;
+ map_generic_share_sd_bits(psd);
+ break;
+
+ /* none of the following contain share names. NetShareAdd does not have a separate parameter for the share name */
+
+ case 1004:
+ case 1005:
+ case 1006:
+ case 1007:
+ return WERR_ACCESS_DENIED;
+ case 1501:
+ /* DFS only level. */
+ return WERR_ACCESS_DENIED;
+ default:
+ DEBUG(5,("_srvsvc_NetShareAdd: unsupported switch value %d\n",
+ r->in.level));
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ /* check for invalid share names */
+
+ if (!share_name || !validate_net_name(share_name,
+ INVALID_SHARENAME_CHARS,
+ strlen(share_name))) {
+ DEBUG(5,("_srvsvc_NetShareAdd: Bad sharename \"%s\"\n",
+ share_name ? share_name : ""));
+ return WERR_INVALID_NAME;
+ }
+
+ if (strequal(share_name,"IPC$") || strequal(share_name,"global")
+ || (lp_enable_asu_support() &&
+ strequal(share_name,"ADMIN$"))) {
+ return WERR_ACCESS_DENIED;
+ }
+
+ snum = find_service(share_name);
+
+ /* Share already exists. */
+ if (snum >= 0) {
+ return WERR_ALREADY_EXISTS;
+ }
+
+ /* We can only add disk shares. */
+ if (type != STYPE_DISKTREE) {
+ return WERR_ACCESS_DENIED;
+ }
+
+ /* Check if the pathname is valid. */
+ if (!(path = valid_share_pathname(p->mem_ctx, pathname))) {
+ return WERR_OBJECT_PATH_INVALID;
+ }
+
+ /* Ensure share name, pathname and comment don't contain '"' characters. */
+ string_replace(share_name, '"', ' ');
+ string_replace(path, '"', ' ');
+ if (comment) {
+ string_replace(comment, '"', ' ');
+ }
+
+ command = talloc_asprintf(ctx,
+ "%s \"%s\" \"%s\" \"%s\" \"%s\" %d",
+ lp_add_share_cmd(),
+ get_dyn_CONFIGFILE(),
+ share_name,
+ path,
+ comment ? comment : "",
+ max_connections);
+ if (!command) {
+ return WERR_NOMEM;
+ }
+
+ DEBUG(10,("_srvsvc_NetShareAdd: Running [%s]\n", command ));
+
+ /********* BEGIN SeDiskOperatorPrivilege BLOCK *********/
+
+ if ( is_disk_op )
+ become_root();
+
+ /* FIXME: use libnetconf here - gd */
+
+ if ( (ret = smbrun(command, NULL)) == 0 ) {
+ /* Tell everyone we updated smb.conf. */
+ message_send_all(smbd_messaging_context(),
+ MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
+ }
+
+ if ( is_disk_op )
+ unbecome_root();
+
+ /********* END SeDiskOperatorPrivilege BLOCK *********/
+
+ DEBUG(3,("_srvsvc_NetShareAdd: Running [%s] returned (%d)\n",
+ command, ret ));
+
+ TALLOC_FREE(command);
+
+ if ( ret != 0 )
+ return WERR_ACCESS_DENIED;
+
+ if (psd) {
+ if (!set_share_security(share_name, psd)) {
+ DEBUG(0,("_srvsvc_NetShareAdd: Failed to add security info to share %s.\n",
+ share_name ));
+ }
+ }
+
+ /*
+ * We don't call reload_services() here, the message will
+ * cause this to be done before the next packet is read
+ * from the client. JRA.
+ */
+
+ DEBUG(5,("_srvsvc_NetShareAdd: %d\n", __LINE__));
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ _srvsvc_NetShareDel
+ Call "delete share command" with the share name as
+ a parameter.
+********************************************************************/
+
+WERROR _srvsvc_NetShareDel(pipes_struct *p,
+ struct srvsvc_NetShareDel *r)
+{
+ struct current_user user;
+ char *command = NULL;
+ char *share_name = NULL;
+ int ret;
+ int snum;
+ SE_PRIV se_diskop = SE_DISK_OPERATOR;
+ bool is_disk_op;
+ struct share_params *params;
+ TALLOC_CTX *ctx = p->mem_ctx;
+
+ DEBUG(5,("_srvsvc_NetShareDel: %d\n", __LINE__));
+
+ share_name = talloc_strdup(p->mem_ctx, r->in.share_name);
+ if (!share_name) {
+ return WERR_NET_NAME_NOT_FOUND;
+ }
+ if ( strequal(share_name,"IPC$")
+ || ( lp_enable_asu_support() && strequal(share_name,"ADMIN$") )
+ || strequal(share_name,"global") )
+ {
+ return WERR_ACCESS_DENIED;
+ }
+
+ if (!(params = get_share_params(p->mem_ctx, share_name))) {
+ return WERR_NO_SUCH_SHARE;
+ }
+
+ snum = find_service(share_name);
+
+ /* No change to printer shares. */
+ if (lp_print_ok(snum))
+ return WERR_ACCESS_DENIED;
+
+ get_current_user(&user,p);
+
+ is_disk_op = user_has_privileges( p->pipe_user.nt_user_token, &se_diskop );
+
+ if (user.ut.uid != sec_initial_uid() && !is_disk_op )
+ return WERR_ACCESS_DENIED;
+
+ if (!lp_delete_share_cmd() || !*lp_delete_share_cmd()) {
+ DEBUG(10,("_srvsvc_NetShareDel: No delete share command\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ command = talloc_asprintf(ctx,
+ "%s \"%s\" \"%s\"",
+ lp_delete_share_cmd(),
+ get_dyn_CONFIGFILE(),
+ lp_servicename(snum));
+ if (!command) {
+ return WERR_NOMEM;
+ }
+
+ DEBUG(10,("_srvsvc_NetShareDel: Running [%s]\n", command ));
+
+ /********* BEGIN SeDiskOperatorPrivilege BLOCK *********/
+
+ if ( is_disk_op )
+ become_root();
+
+ if ( (ret = smbrun(command, NULL)) == 0 ) {
+ /* Tell everyone we updated smb.conf. */
+ message_send_all(smbd_messaging_context(),
+ MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
+ }
+
+ if ( is_disk_op )
+ unbecome_root();
+
+ /********* END SeDiskOperatorPrivilege BLOCK *********/
+
+ DEBUG(3,("_srvsvc_NetShareDel: Running [%s] returned (%d)\n", command, ret ));
+
+ if ( ret != 0 )
+ return WERR_ACCESS_DENIED;
+
+ /* Delete the SD in the database. */
+ delete_share_security(lp_servicename(params->service));
+
+ lp_killservice(params->service);
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ _srvsvc_NetShareDelSticky
+********************************************************************/
+
+WERROR _srvsvc_NetShareDelSticky(pipes_struct *p,
+ struct srvsvc_NetShareDelSticky *r)
+{
+ struct srvsvc_NetShareDel q;
+
+ DEBUG(5,("_srvsvc_NetShareDelSticky: %d\n", __LINE__));
+
+ q.in.server_unc = r->in.server_unc;
+ q.in.share_name = r->in.share_name;
+ q.in.reserved = r->in.reserved;
+
+ return _srvsvc_NetShareDel(p, &q);
+}
+
+/*******************************************************************
+ _srvsvc_NetRemoteTOD
+********************************************************************/
+
+WERROR _srvsvc_NetRemoteTOD(pipes_struct *p,
+ struct srvsvc_NetRemoteTOD *r)
+{
+ struct srvsvc_NetRemoteTODInfo *tod;
+ struct tm *t;
+ time_t unixdate = time(NULL);
+
+ /* We do this call first as if we do it *after* the gmtime call
+ it overwrites the pointed-to values. JRA */
+
+ uint32 zone = get_time_zone(unixdate)/60;
+
+ DEBUG(5,("_srvsvc_NetRemoteTOD: %d\n", __LINE__));
+
+ if ( !(tod = TALLOC_ZERO_P(p->mem_ctx, struct srvsvc_NetRemoteTODInfo)) )
+ return WERR_NOMEM;
+
+ *r->out.info = tod;
+
+ DEBUG(5,("_srvsvc_NetRemoteTOD: %d\n", __LINE__));
+
+ t = gmtime(&unixdate);
+
+ /* set up the */
+ init_srvsvc_NetRemoteTODInfo(tod,
+ unixdate,
+ 0,
+ t->tm_hour,
+ t->tm_min,
+ t->tm_sec,
+ 0,
+ zone,
+ 10000,
+ t->tm_mday,
+ t->tm_mon + 1,
+ 1900+t->tm_year,
+ t->tm_wday);
+
+ DEBUG(5,("_srvsvc_NetRemoteTOD: %d\n", __LINE__));
+
+ return WERR_OK;
+}
+
+/***********************************************************************************
+ _srvsvc_NetGetFileSecurity
+ Win9x NT tools get security descriptor.
+***********************************************************************************/
+
+WERROR _srvsvc_NetGetFileSecurity(pipes_struct *p,
+ struct srvsvc_NetGetFileSecurity *r)
+{
+ SEC_DESC *psd = NULL;
+ size_t sd_size;
+ fstring servicename;
+ SMB_STRUCT_STAT st;
+ NTSTATUS nt_status;
+ WERROR werr;
+ connection_struct *conn = NULL;
+ struct sec_desc_buf *sd_buf = NULL;
+ files_struct *fsp = NULL;
+ int snum;
+ char *oldcwd = NULL;
+
+ ZERO_STRUCT(st);
+
+ fstrcpy(servicename, r->in.share);
+
+ snum = find_service(servicename);
+ if (snum == -1) {
+ DEBUG(10, ("Could not find service %s\n", servicename));
+ werr = WERR_NET_NAME_NOT_FOUND;
+ goto error_exit;
+ }
+
+ nt_status = create_conn_struct(talloc_tos(), &conn, snum,
+ lp_pathname(snum), &oldcwd);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(10, ("create_conn_struct failed: %s\n",
+ nt_errstr(nt_status)));
+ werr = ntstatus_to_werror(nt_status);
+ goto error_exit;
+ }
+
+ conn->server_info = p->server_info;
+
+ nt_status = create_file(
+ conn, /* conn */
+ NULL, /* req */
+ 0, /* root_dir_fid */
+ r->in.file, /* fname */
+ FILE_READ_ATTRIBUTES, /* access_mask */
+ FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
+ FILE_OPEN, /* create_disposition*/
+ 0, /* create_options */
+ 0, /* file_attributes */
+ INTERNAL_OPEN_ONLY, /* oplock_request */
+ 0, /* allocation_size */
+ NULL, /* sd */
+ NULL, /* ea_list */
+ &fsp, /* result */
+ NULL, /* pinfo */
+ NULL); /* psbuf */
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(3,("_srvsvc_NetGetFileSecurity: can't open %s\n",
+ r->in.file));
+ werr = ntstatus_to_werror(nt_status);
+ goto error_exit;
+ }
+
+ nt_status = SMB_VFS_FGET_NT_ACL(fsp,
+ (OWNER_SECURITY_INFORMATION
+ |GROUP_SECURITY_INFORMATION
+ |DACL_SECURITY_INFORMATION), &psd);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(3,("_srvsvc_NetGetFileSecurity: Unable to get NT ACL "
+ "for file %s\n", r->in.file));
+ werr = ntstatus_to_werror(nt_status);
+ goto error_exit;
+ }
+
+ sd_size = ndr_size_security_descriptor(psd, 0);
+
+ sd_buf = TALLOC_ZERO_P(p->mem_ctx, struct sec_desc_buf);
+ if (!sd_buf) {
+ werr = WERR_NOMEM;
+ goto error_exit;
+ }
+
+ sd_buf->sd_size = sd_size;
+ sd_buf->sd = psd;
+
+ *r->out.sd_buf = sd_buf;
+
+ psd->dacl->revision = NT4_ACL_REVISION;
+
+ close_file(fsp, NORMAL_CLOSE);
+ vfs_ChDir(conn, oldcwd);
+ conn_free_internal(conn);
+ return WERR_OK;
+
+error_exit:
+
+ if (fsp) {
+ close_file(fsp, NORMAL_CLOSE);
+ }
+
+ if (oldcwd) {
+ vfs_ChDir(conn, oldcwd);
+ }
+
+ if (conn) {
+ conn_free_internal(conn);
+ }
+
+ return werr;
+}
+
+/***********************************************************************************
+ _srvsvc_NetSetFileSecurity
+ Win9x NT tools set security descriptor.
+***********************************************************************************/
+
+WERROR _srvsvc_NetSetFileSecurity(pipes_struct *p,
+ struct srvsvc_NetSetFileSecurity *r)
+{
+ fstring servicename;
+ files_struct *fsp = NULL;
+ SMB_STRUCT_STAT st;
+ NTSTATUS nt_status;
+ WERROR werr;
+ connection_struct *conn = NULL;
+ int snum;
+ char *oldcwd = NULL;
+
+ ZERO_STRUCT(st);
+
+ fstrcpy(servicename, r->in.share);
+
+ snum = find_service(servicename);
+ if (snum == -1) {
+ DEBUG(10, ("Could not find service %s\n", servicename));
+ werr = WERR_NET_NAME_NOT_FOUND;
+ goto error_exit;
+ }
+
+ nt_status = create_conn_struct(talloc_tos(), &conn, snum,
+ lp_pathname(snum), &oldcwd);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(10, ("create_conn_struct failed: %s\n",
+ nt_errstr(nt_status)));
+ werr = ntstatus_to_werror(nt_status);
+ goto error_exit;
+ }
+
+ conn->server_info = p->server_info;
+
+ nt_status = create_file(
+ conn, /* conn */
+ NULL, /* req */
+ 0, /* root_dir_fid */
+ r->in.file, /* fname */
+ FILE_WRITE_ATTRIBUTES, /* access_mask */
+ FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
+ FILE_OPEN, /* create_disposition*/
+ 0, /* create_options */
+ 0, /* file_attributes */
+ INTERNAL_OPEN_ONLY, /* oplock_request */
+ 0, /* allocation_size */
+ NULL, /* sd */
+ NULL, /* ea_list */
+ &fsp, /* result */
+ NULL, /* pinfo */
+ NULL); /* psbuf */
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(3,("_srvsvc_NetSetFileSecurity: can't open %s\n",
+ r->in.file));
+ werr = ntstatus_to_werror(nt_status);
+ goto error_exit;
+ }
+
+ nt_status = SMB_VFS_FSET_NT_ACL(fsp,
+ r->in.securityinformation,
+ r->in.sd_buf->sd);
+
+ if (!NT_STATUS_IS_OK(nt_status) ) {
+ DEBUG(3,("_srvsvc_NetSetFileSecurity: Unable to set NT ACL "
+ "on file %s\n", r->in.share));
+ werr = WERR_ACCESS_DENIED;
+ goto error_exit;
+ }
+
+ close_file(fsp, NORMAL_CLOSE);
+ vfs_ChDir(conn, oldcwd);
+ conn_free_internal(conn);
+ return WERR_OK;
+
+error_exit:
+
+ if (fsp) {
+ close_file(fsp, NORMAL_CLOSE);
+ }
+
+ if (oldcwd) {
+ vfs_ChDir(conn, oldcwd);
+ }
+
+ if (conn) {
+ conn_free_internal(conn);
+ }
+
+ return werr;
+}
+
+/***********************************************************************************
+ It may be that we want to limit users to creating shares on certain areas of the UNIX file area.
+ We could define areas by mapping Windows style disks to points on the UNIX directory hierarchy.
+ These disks would the disks listed by this function.
+ Users could then create shares relative to these disks. Watch out for moving these disks around.
+ "Nigel Williams" <nigel@veritas.com>.
+***********************************************************************************/
+
+static const char *server_disks[] = {"C:"};
+
+static uint32 get_server_disk_count(void)
+{
+ return sizeof(server_disks)/sizeof(server_disks[0]);
+}
+
+static uint32 init_server_disk_enum(uint32 *resume)
+{
+ uint32 server_disk_count = get_server_disk_count();
+
+ /*resume can be an offset into the list for now*/
+
+ if(*resume & 0x80000000)
+ *resume = 0;
+
+ if(*resume > server_disk_count)
+ *resume = server_disk_count;
+
+ return server_disk_count - *resume;
+}
+
+static const char *next_server_disk_enum(uint32 *resume)
+{
+ const char *disk;
+
+ if(init_server_disk_enum(resume) == 0)
+ return NULL;
+
+ disk = server_disks[*resume];
+
+ (*resume)++;
+
+ DEBUG(10, ("next_server_disk_enum: reporting disk %s. resume handle %d.\n", disk, *resume));
+
+ return disk;
+}
+
+/********************************************************************
+ _srvsvc_NetDiskEnum
+********************************************************************/
+
+WERROR _srvsvc_NetDiskEnum(pipes_struct *p,
+ struct srvsvc_NetDiskEnum *r)
+{
+ uint32 i;
+ const char *disk_name;
+ TALLOC_CTX *ctx = p->mem_ctx;
+ WERROR werr;
+ uint32_t resume = r->in.resume_handle ? *r->in.resume_handle : 0;
+
+ werr = WERR_OK;
+
+ *r->out.totalentries = init_server_disk_enum(&resume);
+
+ r->out.info->disks = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetDiskInfo0,
+ MAX_SERVER_DISK_ENTRIES);
+ W_ERROR_HAVE_NO_MEMORY(r->out.info->disks);
+
+ /*allow one struct srvsvc_NetDiskInfo0 for null terminator*/
+
+ for(i = 0; i < MAX_SERVER_DISK_ENTRIES -1 && (disk_name = next_server_disk_enum(&resume)); i++) {
+
+ r->out.info->count++;
+
+ /*copy disk name into a unicode string*/
+
+ r->out.info->disks[i].disk = talloc_strdup(ctx, disk_name);
+ W_ERROR_HAVE_NO_MEMORY(r->out.info->disks[i].disk);
+ }
+
+ /* add a terminating null string. Is this there if there is more data to come? */
+
+ r->out.info->count++;
+
+ r->out.info->disks[i].disk = talloc_strdup(ctx, "");
+ W_ERROR_HAVE_NO_MEMORY(r->out.info->disks[i].disk);
+
+ if (r->out.resume_handle) {
+ *r->out.resume_handle = resume;
+ }
+
+ return werr;
+}
+
+/********************************************************************
+ _srvsvc_NetNameValidate
+********************************************************************/
+
+WERROR _srvsvc_NetNameValidate(pipes_struct *p,
+ struct srvsvc_NetNameValidate *r)
+{
+ switch (r->in.name_type) {
+ case 0x9:
+ if (!validate_net_name(r->in.name, INVALID_SHARENAME_CHARS,
+ strlen_m(r->in.name)))
+ {
+ DEBUG(5,("_srvsvc_NetNameValidate: Bad sharename \"%s\"\n",
+ r->in.name));
+ return WERR_INVALID_NAME;
+ }
+ break;
+
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static void enum_file_close_fn( const struct share_mode_entry *e,
+ const char *sharepath, const char *fname,
+ void *private_data )
+{
+ char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
+ struct srvsvc_NetFileClose *r =
+ (struct srvsvc_NetFileClose *)private_data;
+ uint32_t fid = (((uint32_t)(procid_to_pid(&e->pid))<<16) | e->share_file_id);
+
+ if (fid != r->in.fid) {
+ return; /* Not this file. */
+ }
+
+ if (!process_exists(e->pid) ) {
+ return;
+ }
+
+ /* Ok - send the close message. */
+ DEBUG(10,("enum_file_close_fn: request to close file %s, %s\n",
+ sharepath,
+ share_mode_str(talloc_tos(), 0, e) ));
+
+ share_mode_entry_to_message(msg, e);
+
+ r->out.result = ntstatus_to_werror(
+ messaging_send_buf(smbd_messaging_context(),
+ e->pid, MSG_SMB_CLOSE_FILE,
+ (uint8 *)msg,
+ MSG_SMB_SHARE_MODE_ENTRY_SIZE));
+}
+
+/********************************************************************
+ Close a file given a 32-bit file id.
+********************************************************************/
+
+WERROR _srvsvc_NetFileClose(pipes_struct *p, struct srvsvc_NetFileClose *r)
+{
+ struct current_user user;
+ SE_PRIV se_diskop = SE_DISK_OPERATOR;
+ bool is_disk_op;
+
+ DEBUG(5,("_srvsvc_NetFileClose: %d\n", __LINE__));
+
+ get_current_user(&user,p);
+
+ is_disk_op = user_has_privileges( p->pipe_user.nt_user_token, &se_diskop );
+
+ if (user.ut.uid != sec_initial_uid() && !is_disk_op) {
+ return WERR_ACCESS_DENIED;
+ }
+
+ /* enum_file_close_fn sends the close message to
+ * the relevent smbd process. */
+
+ r->out.result = WERR_BADFILE;
+ share_mode_forall( enum_file_close_fn, (void *)r);
+ return r->out.result;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _srvsvc_NetCharDevEnum(pipes_struct *p, struct srvsvc_NetCharDevEnum *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetCharDevGetInfo(pipes_struct *p, struct srvsvc_NetCharDevGetInfo *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetCharDevControl(pipes_struct *p, struct srvsvc_NetCharDevControl *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetCharDevQEnum(pipes_struct *p, struct srvsvc_NetCharDevQEnum *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetCharDevQGetInfo(pipes_struct *p, struct srvsvc_NetCharDevQGetInfo *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetCharDevQSetInfo(pipes_struct *p, struct srvsvc_NetCharDevQSetInfo *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetCharDevQPurge(pipes_struct *p, struct srvsvc_NetCharDevQPurge *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetCharDevQPurgeSelf(pipes_struct *p, struct srvsvc_NetCharDevQPurgeSelf *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetFileGetInfo(pipes_struct *p, struct srvsvc_NetFileGetInfo *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetShareCheck(pipes_struct *p, struct srvsvc_NetShareCheck *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetServerStatisticsGet(pipes_struct *p, struct srvsvc_NetServerStatisticsGet *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetTransportAdd(pipes_struct *p, struct srvsvc_NetTransportAdd *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetTransportEnum(pipes_struct *p, struct srvsvc_NetTransportEnum *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetTransportDel(pipes_struct *p, struct srvsvc_NetTransportDel *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetSetServiceBits(pipes_struct *p, struct srvsvc_NetSetServiceBits *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetPathType(pipes_struct *p, struct srvsvc_NetPathType *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetPathCanonicalize(pipes_struct *p, struct srvsvc_NetPathCanonicalize *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetPathCompare(pipes_struct *p, struct srvsvc_NetPathCompare *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NETRPRNAMECANONICALIZE(pipes_struct *p, struct srvsvc_NETRPRNAMECANONICALIZE *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetPRNameCompare(pipes_struct *p, struct srvsvc_NetPRNameCompare *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetShareDelStart(pipes_struct *p, struct srvsvc_NetShareDelStart *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetShareDelCommit(pipes_struct *p, struct srvsvc_NetShareDelCommit *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetServerTransportAddEx(pipes_struct *p, struct srvsvc_NetServerTransportAddEx *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NetServerSetServiceBitsEx(pipes_struct *p, struct srvsvc_NetServerSetServiceBitsEx *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NETRDFSGETVERSION(pipes_struct *p, struct srvsvc_NETRDFSGETVERSION *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NETRDFSCREATELOCALPARTITION(pipes_struct *p, struct srvsvc_NETRDFSCREATELOCALPARTITION *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NETRDFSDELETELOCALPARTITION(pipes_struct *p, struct srvsvc_NETRDFSDELETELOCALPARTITION *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NETRDFSSETLOCALVOLUMESTATE(pipes_struct *p, struct srvsvc_NETRDFSSETLOCALVOLUMESTATE *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NETRDFSSETSERVERINFO(pipes_struct *p, struct srvsvc_NETRDFSSETSERVERINFO *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NETRDFSCREATEEXITPOINT(pipes_struct *p, struct srvsvc_NETRDFSCREATEEXITPOINT *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NETRDFSDELETEEXITPOINT(pipes_struct *p, struct srvsvc_NETRDFSDELETEEXITPOINT *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NETRDFSMODIFYPREFIX(pipes_struct *p, struct srvsvc_NETRDFSMODIFYPREFIX *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NETRDFSFIXLOCALVOLUME(pipes_struct *p, struct srvsvc_NETRDFSFIXLOCALVOLUME *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NETRDFSMANAGERREPORTSITEINFO(pipes_struct *p, struct srvsvc_NETRDFSMANAGERREPORTSITEINFO *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _srvsvc_NETRSERVERTRANSPORTDELEX(pipes_struct *p, struct srvsvc_NETRSERVERTRANSPORTDELEX *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
diff --git a/source3/rpc_server/srv_svcctl.c b/source3/rpc_server/srv_svcctl.c
new file mode 100644
index 0000000000..483fb8e1e9
--- /dev/null
+++ b/source3/rpc_server/srv_svcctl.c
@@ -0,0 +1,273 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Gerald Carter 2005 - 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+static bool proxy_svcctl_call(pipes_struct *p, uint8 opnum)
+{
+ struct api_struct *fns;
+ int n_fns;
+
+ svcctl_get_pipe_fns(&fns, &n_fns);
+
+ if (opnum >= n_fns)
+ return False;
+
+ if (fns[opnum].opnum != opnum) {
+ smb_panic("SVCCTL function table not sorted\n");
+ }
+
+ return fns[opnum].fn(p);
+}
+
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_svcctl_close_service(pipes_struct *p)
+{
+ return proxy_svcctl_call( p, NDR_SVCCTL_CLOSESERVICEHANDLE );
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_svcctl_open_scmanager(pipes_struct *p)
+{
+ return proxy_svcctl_call(p, NDR_SVCCTL_OPENSCMANAGERW);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_svcctl_open_service(pipes_struct *p)
+{
+ return proxy_svcctl_call(p, NDR_SVCCTL_OPENSERVICEW);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_svcctl_get_display_name(pipes_struct *p)
+{
+ return proxy_svcctl_call(p, NDR_SVCCTL_GETSERVICEDISPLAYNAMEW);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_svcctl_query_status(pipes_struct *p)
+{
+ return proxy_svcctl_call(p, NDR_SVCCTL_QUERYSERVICESTATUS);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_svcctl_enum_services_status(pipes_struct *p)
+{
+ SVCCTL_Q_ENUM_SERVICES_STATUS q_u;
+ SVCCTL_R_ENUM_SERVICES_STATUS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!svcctl_io_q_enum_services_status("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _svcctl_enum_services_status(p, &q_u, &r_u);
+
+ if(!svcctl_io_r_enum_services_status("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_svcctl_query_service_status_ex(pipes_struct *p)
+{
+ SVCCTL_Q_QUERY_SERVICE_STATUSEX q_u;
+ SVCCTL_R_QUERY_SERVICE_STATUSEX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!svcctl_io_q_query_service_status_ex("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _svcctl_query_service_status_ex(p, &q_u, &r_u);
+
+ if(!svcctl_io_r_query_service_status_ex("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_svcctl_enum_dependent_services(pipes_struct *p)
+{
+ return proxy_svcctl_call(p, NDR_SVCCTL_ENUMDEPENDENTSERVICESW);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_svcctl_start_service(pipes_struct *p)
+{
+ return proxy_svcctl_call(p, NDR_SVCCTL_STARTSERVICEW);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_svcctl_control_service(pipes_struct *p)
+{
+ return proxy_svcctl_call(p, NDR_SVCCTL_CONTROLSERVICE);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_svcctl_query_service_config(pipes_struct *p)
+{
+ SVCCTL_Q_QUERY_SERVICE_CONFIG q_u;
+ SVCCTL_R_QUERY_SERVICE_CONFIG r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!svcctl_io_q_query_service_config("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _svcctl_query_service_config(p, &q_u, &r_u);
+
+ if(!svcctl_io_r_query_service_config("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_svcctl_query_service_config2(pipes_struct *p)
+{
+ SVCCTL_Q_QUERY_SERVICE_CONFIG2 q_u;
+ SVCCTL_R_QUERY_SERVICE_CONFIG2 r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!svcctl_io_q_query_service_config2("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _svcctl_query_service_config2(p, &q_u, &r_u);
+
+ if(!svcctl_io_r_query_service_config2("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_svcctl_lock_service_db(pipes_struct *p)
+{
+ return proxy_svcctl_call(p, NDR_SVCCTL_LOCKSERVICEDATABASE);
+}
+
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_svcctl_unlock_service_db(pipes_struct *p)
+{
+ return proxy_svcctl_call(p, NDR_SVCCTL_UNLOCKSERVICEDATABASE);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_svcctl_query_security_sec(pipes_struct *p)
+{
+ return proxy_svcctl_call(p, NDR_SVCCTL_QUERYSERVICEOBJECTSECURITY);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool api_svcctl_set_security_sec(pipes_struct *p)
+{
+ return proxy_svcctl_call(p, NDR_SVCCTL_SETSERVICEOBJECTSECURITY);
+}
+
+
+/*******************************************************************
+ \PIPE\svcctl commands
+ ********************************************************************/
+
+static struct api_struct api_svcctl_cmds[] =
+{
+ { "SVCCTL_CLOSE_SERVICE" , SVCCTL_CLOSE_SERVICE , api_svcctl_close_service },
+ { "SVCCTL_OPEN_SCMANAGER_W" , SVCCTL_OPEN_SCMANAGER_W , api_svcctl_open_scmanager },
+ { "SVCCTL_OPEN_SERVICE_W" , SVCCTL_OPEN_SERVICE_W , api_svcctl_open_service },
+ { "SVCCTL_GET_DISPLAY_NAME" , SVCCTL_GET_DISPLAY_NAME , api_svcctl_get_display_name },
+ { "SVCCTL_QUERY_STATUS" , SVCCTL_QUERY_STATUS , api_svcctl_query_status },
+ { "SVCCTL_QUERY_SERVICE_CONFIG_W" , SVCCTL_QUERY_SERVICE_CONFIG_W , api_svcctl_query_service_config },
+ { "SVCCTL_QUERY_SERVICE_CONFIG2_W" , SVCCTL_QUERY_SERVICE_CONFIG2_W , api_svcctl_query_service_config2 },
+ { "SVCCTL_ENUM_SERVICES_STATUS_W" , SVCCTL_ENUM_SERVICES_STATUS_W , api_svcctl_enum_services_status },
+ { "SVCCTL_ENUM_DEPENDENT_SERVICES_W" , SVCCTL_ENUM_DEPENDENT_SERVICES_W , api_svcctl_enum_dependent_services },
+ { "SVCCTL_START_SERVICE_W" , SVCCTL_START_SERVICE_W , api_svcctl_start_service },
+ { "SVCCTL_CONTROL_SERVICE" , SVCCTL_CONTROL_SERVICE , api_svcctl_control_service },
+ { "SVCCTL_QUERY_SERVICE_STATUSEX_W" , SVCCTL_QUERY_SERVICE_STATUSEX_W , api_svcctl_query_service_status_ex },
+ { "SVCCTL_LOCK_SERVICE_DB" , SVCCTL_LOCK_SERVICE_DB , api_svcctl_lock_service_db },
+ { "SVCCTL_UNLOCK_SERVICE_DB" , SVCCTL_UNLOCK_SERVICE_DB , api_svcctl_unlock_service_db },
+ { "SVCCTL_QUERY_SERVICE_SEC" , SVCCTL_QUERY_SERVICE_SEC , api_svcctl_query_security_sec },
+ { "SVCCTL_SET_SERVICE_SEC" , SVCCTL_SET_SERVICE_SEC , api_svcctl_set_security_sec }
+};
+
+
+void svcctl2_get_pipe_fns( struct api_struct **fns, int *n_fns )
+{
+ *fns = api_svcctl_cmds;
+ *n_fns = sizeof(api_svcctl_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_svcctl2_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION,
+ "svcctl", "ntsvcs",
+ &ndr_table_svcctl.syntax_id,
+ api_svcctl_cmds,
+ sizeof(api_svcctl_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/rpc_server/srv_svcctl_nt.c b/source3/rpc_server/srv_svcctl_nt.c
new file mode 100644
index 0000000000..6bb538a311
--- /dev/null
+++ b/source3/rpc_server/srv_svcctl_nt.c
@@ -0,0 +1,1109 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005.
+ *
+ * Largely Rewritten (Again) by:
+ * Copyright (C) Gerald (Jerry) Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+struct service_control_op {
+ const char *name;
+ SERVICE_CONTROL_OPS *ops;
+};
+
+#define SVCCTL_NUM_INTERNAL_SERVICES 4
+
+/* handle external services */
+extern SERVICE_CONTROL_OPS rcinit_svc_ops;
+
+/* builtin services (see service_db.c and services/svc_*.c */
+extern SERVICE_CONTROL_OPS spoolss_svc_ops;
+extern SERVICE_CONTROL_OPS netlogon_svc_ops;
+extern SERVICE_CONTROL_OPS winreg_svc_ops;
+extern SERVICE_CONTROL_OPS wins_svc_ops;
+
+/* make sure this number patches the number of builtin
+ SERVICE_CONTROL_OPS structure listed above */
+
+#define SVCCTL_NUM_INTERNAL_SERVICES 4
+
+struct service_control_op *svcctl_ops;
+
+static const struct generic_mapping scm_generic_map =
+ { SC_MANAGER_READ_ACCESS, SC_MANAGER_WRITE_ACCESS, SC_MANAGER_EXECUTE_ACCESS, SC_MANAGER_ALL_ACCESS };
+static const struct generic_mapping svc_generic_map =
+ { SERVICE_READ_ACCESS, SERVICE_WRITE_ACCESS, SERVICE_EXECUTE_ACCESS, SERVICE_ALL_ACCESS };
+
+
+/********************************************************************
+********************************************************************/
+
+bool init_service_op_table( void )
+{
+ const char **service_list = lp_svcctl_list();
+ int num_services = SVCCTL_NUM_INTERNAL_SERVICES + str_list_count( service_list );
+ int i;
+
+ if ( !(svcctl_ops = TALLOC_ARRAY( NULL, struct service_control_op, num_services+1)) ) {
+ DEBUG(0,("init_service_op_table: talloc() failed!\n"));
+ return False;
+ }
+
+ /* services listed in smb.conf get the rc.init interface */
+
+ for ( i=0; service_list && service_list[i]; i++ ) {
+ svcctl_ops[i].name = talloc_strdup( svcctl_ops, service_list[i] );
+ svcctl_ops[i].ops = &rcinit_svc_ops;
+ }
+
+ /* add builtin services */
+
+ svcctl_ops[i].name = talloc_strdup( svcctl_ops, "Spooler" );
+ svcctl_ops[i].ops = &spoolss_svc_ops;
+ i++;
+
+ svcctl_ops[i].name = talloc_strdup( svcctl_ops, "NETLOGON" );
+ svcctl_ops[i].ops = &netlogon_svc_ops;
+ i++;
+
+ svcctl_ops[i].name = talloc_strdup( svcctl_ops, "RemoteRegistry" );
+ svcctl_ops[i].ops = &winreg_svc_ops;
+ i++;
+
+ svcctl_ops[i].name = talloc_strdup( svcctl_ops, "WINS" );
+ svcctl_ops[i].ops = &wins_svc_ops;
+ i++;
+
+ /* NULL terminate the array */
+
+ svcctl_ops[i].name = NULL;
+ svcctl_ops[i].ops = NULL;
+
+ return True;
+}
+
+/********************************************************************
+********************************************************************/
+
+static struct service_control_op* find_service_by_name( const char *name )
+{
+ int i;
+
+ for ( i=0; svcctl_ops[i].name; i++ ) {
+ if ( strequal( name, svcctl_ops[i].name ) )
+ return &svcctl_ops[i];
+ }
+
+ return NULL;
+}
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS svcctl_access_check( SEC_DESC *sec_desc, NT_USER_TOKEN *token,
+ uint32 access_desired, uint32 *access_granted )
+{
+ NTSTATUS result;
+
+ if ( geteuid() == sec_initial_uid() ) {
+ DEBUG(5,("svcctl_access_check: using root's token\n"));
+ token = get_root_nt_token();
+ }
+
+ se_access_check( sec_desc, token, access_desired, access_granted, &result );
+
+ return result;
+}
+
+/********************************************************************
+********************************************************************/
+
+static SEC_DESC* construct_scm_sd( TALLOC_CTX *ctx )
+{
+ SEC_ACE ace[2];
+ SEC_ACCESS mask;
+ size_t i = 0;
+ SEC_DESC *sd;
+ SEC_ACL *acl;
+ size_t sd_size;
+
+ /* basic access for Everyone */
+
+ init_sec_access(&mask, SC_MANAGER_READ_ACCESS );
+ init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ /* Full Access 'BUILTIN\Administrators' */
+
+ init_sec_access(&mask,SC_MANAGER_ALL_ACCESS );
+ init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+
+ /* create the security descriptor */
+
+ if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
+ return NULL;
+
+ if ( !(sd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
+ SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL,
+ acl, &sd_size)) )
+ return NULL;
+
+ return sd;
+}
+
+/******************************************************************
+ free() function for REGISTRY_KEY
+ *****************************************************************/
+
+static void free_service_handle_info(void *ptr)
+{
+ TALLOC_FREE( ptr );
+}
+
+/******************************************************************
+ Find a registry key handle and return a SERVICE_INFO
+ *****************************************************************/
+
+static SERVICE_INFO *find_service_info_by_hnd(pipes_struct *p, POLICY_HND *hnd)
+{
+ SERVICE_INFO *service_info = NULL;
+
+ if( !find_policy_by_hnd( p, hnd, (void **)(void *)&service_info) ) {
+ DEBUG(2,("find_service_info_by_hnd: handle not found\n"));
+ return NULL;
+ }
+
+ return service_info;
+}
+
+/******************************************************************
+ *****************************************************************/
+
+static WERROR create_open_service_handle( pipes_struct *p, POLICY_HND *handle, uint32 type,
+ const char *service, uint32 access_granted )
+{
+ SERVICE_INFO *info = NULL;
+ WERROR result = WERR_OK;
+ struct service_control_op *s_op;
+
+ if ( !(info = TALLOC_ZERO_P( NULL, SERVICE_INFO )) )
+ return WERR_NOMEM;
+
+ /* the Service Manager has a NULL name */
+
+ info->type = SVC_HANDLE_IS_SCM;
+
+ switch ( type ) {
+ case SVC_HANDLE_IS_SCM:
+ info->type = SVC_HANDLE_IS_SCM;
+ break;
+
+ case SVC_HANDLE_IS_DBLOCK:
+ info->type = SVC_HANDLE_IS_DBLOCK;
+ break;
+
+ case SVC_HANDLE_IS_SERVICE:
+ info->type = SVC_HANDLE_IS_SERVICE;
+
+ /* lookup the SERVICE_CONTROL_OPS */
+
+ if ( !(s_op = find_service_by_name( service )) ) {
+ result = WERR_NO_SUCH_SERVICE;
+ goto done;
+ }
+
+ info->ops = s_op->ops;
+
+ if ( !(info->name = talloc_strdup( info, s_op->name )) ) {
+ result = WERR_NOMEM;
+ goto done;
+ }
+ break;
+
+ default:
+ result = WERR_NO_SUCH_SERVICE;
+ goto done;
+ }
+
+ info->access_granted = access_granted;
+
+ /* store the SERVICE_INFO and create an open handle */
+
+ if ( !create_policy_hnd( p, handle, free_service_handle_info, info ) ) {
+ result = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+done:
+ if ( !W_ERROR_IS_OK(result) )
+ free_service_handle_info( info );
+
+ return result;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _svcctl_OpenSCManagerW(pipes_struct *p,
+ struct svcctl_OpenSCManagerW *r)
+{
+ SEC_DESC *sec_desc;
+ uint32 access_granted = 0;
+ NTSTATUS status;
+
+ /* perform access checks */
+
+ if ( !(sec_desc = construct_scm_sd( p->mem_ctx )) )
+ return WERR_NOMEM;
+
+ se_map_generic( &r->in.access_mask, &scm_generic_map );
+ status = svcctl_access_check( sec_desc, p->pipe_user.nt_user_token, r->in.access_mask, &access_granted );
+ if ( !NT_STATUS_IS_OK(status) )
+ return ntstatus_to_werror( status );
+
+ return create_open_service_handle( p, r->out.handle, SVC_HANDLE_IS_SCM, NULL, access_granted );
+}
+
+/********************************************************************
+ _svcctl_OpenServiceW
+********************************************************************/
+
+WERROR _svcctl_OpenServiceW(pipes_struct *p,
+ struct svcctl_OpenServiceW *r)
+{
+ SEC_DESC *sec_desc;
+ uint32 access_granted = 0;
+ NTSTATUS status;
+ const char *service = NULL;
+
+ service = r->in.ServiceName;
+ if (!service) {
+ return WERR_NOMEM;
+ }
+ DEBUG(5, ("_svcctl_OpenServiceW: Attempting to open Service [%s], \n", service));
+
+ /* based on my tests you can open a service if you have a valid scm handle */
+
+ if ( !find_service_info_by_hnd( p, r->in.scmanager_handle) )
+ return WERR_BADFID;
+
+ /* perform access checks. Use the root token in order to ensure that we
+ retrieve the security descriptor */
+
+ if ( !(sec_desc = svcctl_get_secdesc( p->mem_ctx, service, get_root_nt_token() )) )
+ return WERR_NOMEM;
+
+ se_map_generic( &r->in.access_mask, &svc_generic_map );
+ status = svcctl_access_check( sec_desc, p->pipe_user.nt_user_token, r->in.access_mask, &access_granted );
+ if ( !NT_STATUS_IS_OK(status) )
+ return ntstatus_to_werror( status );
+
+ return create_open_service_handle( p, r->out.handle, SVC_HANDLE_IS_SERVICE, service, access_granted );
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _svcctl_CloseServiceHandle(pipes_struct *p, struct svcctl_CloseServiceHandle *r)
+{
+ if ( !close_policy_hnd( p, r->in.handle ) )
+ return WERR_BADFID;
+
+ ZERO_STRUCTP(r->out.handle);
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ _svcctl_GetServiceDisplayNameW
+********************************************************************/
+
+WERROR _svcctl_GetServiceDisplayNameW(pipes_struct *p,
+ struct svcctl_GetServiceDisplayNameW *r)
+{
+ const char *service;
+ const char *display_name;
+ SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle );
+
+ /* can only use an SCM handle here */
+
+ if ( !info || (info->type != SVC_HANDLE_IS_SCM) )
+ return WERR_BADFID;
+
+ service = r->in.service_name;
+
+ display_name = svcctl_lookup_dispname(p->mem_ctx, service, p->pipe_user.nt_user_token );
+ if (!display_name) {
+ display_name = "";
+ }
+
+ *r->out.display_name = display_name;
+ *r->out.display_name_length = strlen(display_name);
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ _svcctl_QueryServiceStatus
+********************************************************************/
+
+WERROR _svcctl_QueryServiceStatus(pipes_struct *p,
+ struct svcctl_QueryServiceStatus *r)
+{
+ SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle );
+
+ /* perform access checks */
+
+ if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
+ return WERR_BADFID;
+
+ if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) )
+ return WERR_ACCESS_DENIED;
+
+ /* try the service specific status call */
+
+ return info->ops->service_status( info->name, r->out.service_status );
+}
+
+/********************************************************************
+********************************************************************/
+
+static int enumerate_status( TALLOC_CTX *ctx, ENUM_SERVICES_STATUS **status, NT_USER_TOKEN *token )
+{
+ int num_services = 0;
+ int i;
+ ENUM_SERVICES_STATUS *st;
+ const char *display_name;
+
+ /* just count */
+ while ( svcctl_ops[num_services].name )
+ num_services++;
+
+ if ( !(st = TALLOC_ARRAY( ctx, ENUM_SERVICES_STATUS, num_services )) ) {
+ DEBUG(0,("enumerate_status: talloc() failed!\n"));
+ return -1;
+ }
+
+ for ( i=0; i<num_services; i++ ) {
+ init_unistr( &st[i].servicename, svcctl_ops[i].name );
+
+ display_name = svcctl_lookup_dispname(ctx, svcctl_ops[i].name, token );
+ init_unistr( &st[i].displayname, display_name ? display_name : "");
+
+ svcctl_ops[i].ops->service_status( svcctl_ops[i].name, &st[i].status );
+ }
+
+ *status = st;
+
+ return num_services;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _svcctl_enum_services_status(pipes_struct *p, SVCCTL_Q_ENUM_SERVICES_STATUS *q_u, SVCCTL_R_ENUM_SERVICES_STATUS *r_u)
+{
+ ENUM_SERVICES_STATUS *services = NULL;
+ int num_services;
+ int i = 0;
+ size_t buffer_size = 0;
+ WERROR result = WERR_OK;
+ SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
+ NT_USER_TOKEN *token = p->pipe_user.nt_user_token;
+
+ /* perform access checks */
+
+ if ( !info || (info->type != SVC_HANDLE_IS_SCM) )
+ return WERR_BADFID;
+
+ if ( !(info->access_granted & SC_RIGHT_MGR_ENUMERATE_SERVICE) ) {
+ return WERR_ACCESS_DENIED;
+ }
+
+ num_services = enumerate_status( p->mem_ctx, &services, token );
+ if (num_services == -1 ) {
+ return WERR_NOMEM;
+ }
+
+ for ( i=0; i<num_services; i++ ) {
+ buffer_size += svcctl_sizeof_enum_services_status(&services[i]);
+ }
+
+ buffer_size += buffer_size % 4;
+
+ if (buffer_size > q_u->buffer_size ) {
+ num_services = 0;
+ result = WERR_MORE_DATA;
+ }
+
+ rpcbuf_init(&r_u->buffer, q_u->buffer_size, p->mem_ctx);
+
+ if ( W_ERROR_IS_OK(result) ) {
+ for ( i=0; i<num_services; i++ )
+ svcctl_io_enum_services_status( "", &services[i], &r_u->buffer, 0 );
+ }
+
+ r_u->needed = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size;
+ r_u->returned = (uint32)num_services;
+
+ if ( !(r_u->resume = TALLOC_P( p->mem_ctx, uint32 )) )
+ return WERR_NOMEM;
+
+ *r_u->resume = 0x0;
+
+ return result;
+}
+
+/********************************************************************
+ _svcctl_StartServiceW
+********************************************************************/
+
+WERROR _svcctl_StartServiceW(pipes_struct *p,
+ struct svcctl_StartServiceW *r)
+{
+ SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle );
+
+ /* perform access checks */
+
+ if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
+ return WERR_BADFID;
+
+ if ( !(info->access_granted & SC_RIGHT_SVC_START) )
+ return WERR_ACCESS_DENIED;
+
+ return info->ops->start_service( info->name );
+}
+
+/********************************************************************
+ _svcctl_ControlService
+********************************************************************/
+
+WERROR _svcctl_ControlService(pipes_struct *p,
+ struct svcctl_ControlService *r)
+{
+ SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle );
+
+ /* perform access checks */
+
+ if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
+ return WERR_BADFID;
+
+ switch ( r->in.control ) {
+ case SVCCTL_CONTROL_STOP:
+ if ( !(info->access_granted & SC_RIGHT_SVC_STOP) )
+ return WERR_ACCESS_DENIED;
+
+ return info->ops->stop_service( info->name,
+ r->out.service_status );
+
+ case SVCCTL_CONTROL_INTERROGATE:
+ if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) )
+ return WERR_ACCESS_DENIED;
+
+ return info->ops->service_status( info->name,
+ r->out.service_status );
+ }
+
+ /* default control action */
+
+ return WERR_ACCESS_DENIED;
+}
+
+/********************************************************************
+ _svcctl_EnumDependentServicesW
+********************************************************************/
+
+WERROR _svcctl_EnumDependentServicesW(pipes_struct *p,
+ struct svcctl_EnumDependentServicesW *r)
+{
+ SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.service );
+
+ /* perform access checks */
+
+ if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
+ return WERR_BADFID;
+
+ if ( !(info->access_granted & SC_RIGHT_SVC_ENUMERATE_DEPENDENTS) )
+ return WERR_ACCESS_DENIED;
+
+ /* we have to set the outgoing buffer size to the same as the
+ incoming buffer size (even in the case of failure */
+ /* this is done in the autogenerated server already - gd */
+
+ *r->out.bytes_needed = r->in.buf_size;
+
+ /* no dependent services...basically a stub function */
+ *r->out.services_returned = 0;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _svcctl_query_service_status_ex( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_STATUSEX *q_u, SVCCTL_R_QUERY_SERVICE_STATUSEX *r_u )
+{
+ SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
+ uint32 buffer_size;
+
+ /* perform access checks */
+
+ if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
+ return WERR_BADFID;
+
+ if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) )
+ return WERR_ACCESS_DENIED;
+
+ /* we have to set the outgoing buffer size to the same as the
+ incoming buffer size (even in the case of failure) */
+
+ rpcbuf_init( &r_u->buffer, q_u->buffer_size, p->mem_ctx );
+ r_u->needed = q_u->buffer_size;
+
+ switch ( q_u->level ) {
+ case SVC_STATUS_PROCESS_INFO:
+ {
+ SERVICE_STATUS_PROCESS svc_stat_proc;
+
+ /* Get the status of the service.. */
+ info->ops->service_status( info->name, &svc_stat_proc.status );
+ svc_stat_proc.process_id = sys_getpid();
+ svc_stat_proc.service_flags = 0x0;
+
+ svcctl_io_service_status_process( "", &svc_stat_proc, &r_u->buffer, 0 );
+ buffer_size = sizeof(SERVICE_STATUS_PROCESS);
+ break;
+ }
+
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+
+ buffer_size += buffer_size % 4;
+ r_u->needed = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size;
+
+ if (buffer_size > q_u->buffer_size )
+ return WERR_MORE_DATA;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+static WERROR fill_svc_config( TALLOC_CTX *ctx, const char *name, SERVICE_CONFIG *config, NT_USER_TOKEN *token )
+{
+ REGVAL_CTR *values;
+ REGISTRY_VALUE *val;
+
+ /* retrieve the registry values for this service */
+
+ if ( !(values = svcctl_fetch_regvalues( name, token )) )
+ return WERR_REG_CORRUPT;
+
+ /* now fill in the individual values */
+
+ config->displayname = TALLOC_ZERO_P( ctx, UNISTR2 );
+ if ( (val = regval_ctr_getvalue( values, "DisplayName" )) != NULL )
+ init_unistr2( config->displayname, regval_sz( val ), UNI_STR_TERMINATE );
+ else
+ init_unistr2( config->displayname, name, UNI_STR_TERMINATE );
+
+ if ( (val = regval_ctr_getvalue( values, "ObjectName" )) != NULL ) {
+ config->startname = TALLOC_ZERO_P( ctx, UNISTR2 );
+ init_unistr2( config->startname, regval_sz( val ), UNI_STR_TERMINATE );
+ }
+
+ if ( (val = regval_ctr_getvalue( values, "ImagePath" )) != NULL ) {
+ config->executablepath = TALLOC_ZERO_P( ctx, UNISTR2 );
+ init_unistr2( config->executablepath, regval_sz( val ), UNI_STR_TERMINATE );
+ }
+
+ /* a few hard coded values */
+ /* loadordergroup and dependencies are empty */
+
+ config->tag_id = 0x00000000; /* unassigned loadorder group */
+ config->service_type = SVCCTL_WIN32_OWN_PROC;
+ config->error_control = SVCCTL_SVC_ERROR_NORMAL;
+
+ /* set the start type. NetLogon and WINS are disabled to prevent
+ the client from showing the "Start" button (if of course the services
+ are not running */
+
+ if ( strequal( name, "NETLOGON" ) && ( lp_servicenumber(name) == -1 ) )
+ config->start_type = SVCCTL_DISABLED;
+ else if ( strequal( name, "WINS" ) && ( !lp_wins_support() ))
+ config->start_type = SVCCTL_DISABLED;
+ else
+ config->start_type = SVCCTL_DEMAND_START;
+
+
+ TALLOC_FREE( values );
+
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG *r_u )
+{
+ SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
+ uint32 buffer_size;
+ WERROR wresult;
+
+ /* perform access checks */
+
+ if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
+ return WERR_BADFID;
+
+ if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_CONFIG) )
+ return WERR_ACCESS_DENIED;
+
+ /* we have to set the outgoing buffer size to the same as the
+ incoming buffer size (even in the case of failure */
+
+ r_u->needed = q_u->buffer_size;
+
+ wresult = fill_svc_config( p->mem_ctx, info->name, &r_u->config, p->pipe_user.nt_user_token );
+ if ( !W_ERROR_IS_OK(wresult) )
+ return wresult;
+
+ buffer_size = svcctl_sizeof_service_config( &r_u->config );
+ r_u->needed = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size;
+
+ if (buffer_size > q_u->buffer_size ) {
+ ZERO_STRUCTP( &r_u->config );
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _svcctl_query_service_config2( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG2 *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG2 *r_u )
+{
+ SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
+ uint32 buffer_size;
+
+ /* perform access checks */
+
+ if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
+ return WERR_BADFID;
+
+ if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_CONFIG) )
+ return WERR_ACCESS_DENIED;
+
+ /* we have to set the outgoing buffer size to the same as the
+ incoming buffer size (even in the case of failure */
+
+ rpcbuf_init( &r_u->buffer, q_u->buffer_size, p->mem_ctx );
+ r_u->needed = q_u->buffer_size;
+
+ switch ( q_u->level ) {
+ case SERVICE_CONFIG_DESCRIPTION:
+ {
+ SERVICE_DESCRIPTION desc_buf;
+ const char *description;
+
+ description = svcctl_lookup_description(p->mem_ctx, info->name, p->pipe_user.nt_user_token );
+
+ ZERO_STRUCTP( &desc_buf );
+
+ init_service_description_buffer( &desc_buf, description ? description : "");
+ svcctl_io_service_description( "", &desc_buf, &r_u->buffer, 0 );
+ buffer_size = svcctl_sizeof_service_description( &desc_buf );
+
+ break;
+ }
+ break;
+ case SERVICE_CONFIG_FAILURE_ACTIONS:
+ {
+ SERVICE_FAILURE_ACTIONS actions;
+
+ /* nothing to say...just service the request */
+
+ ZERO_STRUCTP( &actions );
+ svcctl_io_service_fa( "", &actions, &r_u->buffer, 0 );
+ buffer_size = svcctl_sizeof_service_fa( &actions );
+
+ break;
+ }
+ break;
+
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ buffer_size += buffer_size % 4;
+ r_u->needed = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size;
+
+ if (buffer_size > q_u->buffer_size )
+ return WERR_INSUFFICIENT_BUFFER;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ _svcctl_LockServiceDatabase
+********************************************************************/
+
+WERROR _svcctl_LockServiceDatabase(pipes_struct *p,
+ struct svcctl_LockServiceDatabase *r)
+{
+ SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle );
+
+ /* perform access checks */
+
+ if ( !info || (info->type != SVC_HANDLE_IS_SCM) )
+ return WERR_BADFID;
+
+ if ( !(info->access_granted & SC_RIGHT_MGR_LOCK) )
+ return WERR_ACCESS_DENIED;
+
+ /* Just open a handle. Doesn't actually lock anything */
+
+ return create_open_service_handle( p, r->out.lock, SVC_HANDLE_IS_DBLOCK, NULL, 0 );
+}
+
+/********************************************************************
+ _svcctl_UnlockServiceDatabase
+********************************************************************/
+
+WERROR _svcctl_UnlockServiceDatabase(pipes_struct *p,
+ struct svcctl_UnlockServiceDatabase *r)
+{
+ SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.lock );
+
+
+ if ( !info || (info->type != SVC_HANDLE_IS_DBLOCK) )
+ return WERR_BADFID;
+
+ return close_policy_hnd( p, r->out.lock) ? WERR_OK : WERR_BADFID;
+}
+
+/********************************************************************
+ _svcctl_QueryServiceObjectSecurity
+********************************************************************/
+
+WERROR _svcctl_QueryServiceObjectSecurity(pipes_struct *p,
+ struct svcctl_QueryServiceObjectSecurity *r)
+{
+ SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle );
+ SEC_DESC *sec_desc;
+ NTSTATUS status;
+ uint8_t *buffer = NULL;
+ size_t len = 0;
+
+
+ /* only support the SCM and individual services */
+
+ if ( !info || !(info->type & (SVC_HANDLE_IS_SERVICE|SVC_HANDLE_IS_SCM)) )
+ return WERR_BADFID;
+
+ /* check access reights (according to MSDN) */
+
+ if ( !(info->access_granted & STD_RIGHT_READ_CONTROL_ACCESS) )
+ return WERR_ACCESS_DENIED;
+
+ /* TODO: handle something besides DACL_SECURITY_INFORMATION */
+
+ if ( (r->in.security_flags & DACL_SECURITY_INFORMATION) != DACL_SECURITY_INFORMATION )
+ return WERR_INVALID_PARAM;
+
+ /* lookup the security descriptor and marshall it up for a reply */
+
+ if ( !(sec_desc = svcctl_get_secdesc( p->mem_ctx, info->name, get_root_nt_token() )) )
+ return WERR_NOMEM;
+
+ *r->out.needed = ndr_size_security_descriptor( sec_desc, 0 );
+
+ if ( *r->out.needed > r->in.buffer_size ) {
+ ZERO_STRUCTP( &r->out.buffer );
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ status = marshall_sec_desc(p->mem_ctx, sec_desc, &buffer, &len);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ *r->out.needed = len;
+ r->out.buffer = buffer;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ _svcctl_SetServiceObjectSecurity
+********************************************************************/
+
+WERROR _svcctl_SetServiceObjectSecurity(pipes_struct *p,
+ struct svcctl_SetServiceObjectSecurity *r)
+{
+ SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle );
+ SEC_DESC *sec_desc = NULL;
+ uint32 required_access;
+ NTSTATUS status;
+
+ if ( !info || !(info->type & (SVC_HANDLE_IS_SERVICE|SVC_HANDLE_IS_SCM)) )
+ return WERR_BADFID;
+
+ /* can't set the security de4scriptor on the ServiceControlManager */
+
+ if ( info->type == SVC_HANDLE_IS_SCM )
+ return WERR_ACCESS_DENIED;
+
+ /* check the access on the open handle */
+
+ switch ( r->in.security_flags ) {
+ case DACL_SECURITY_INFORMATION:
+ required_access = STD_RIGHT_WRITE_DAC_ACCESS;
+ break;
+
+ case OWNER_SECURITY_INFORMATION:
+ case GROUP_SECURITY_INFORMATION:
+ required_access = STD_RIGHT_WRITE_OWNER_ACCESS;
+ break;
+
+ case SACL_SECURITY_INFORMATION:
+ return WERR_INVALID_PARAM;
+ default:
+ return WERR_INVALID_PARAM;
+ }
+
+ if ( !(info->access_granted & required_access) )
+ return WERR_ACCESS_DENIED;
+
+ /* read the security descfriptor */
+
+ status = unmarshall_sec_desc(p->mem_ctx,
+ r->in.buffer, r->in.buffer_size,
+ &sec_desc);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ /* store the new SD */
+
+ if ( !svcctl_set_secdesc( p->mem_ctx, info->name, sec_desc, p->pipe_user.nt_user_token ) )
+ return WERR_ACCESS_DENIED;
+
+ return WERR_OK;
+}
+
+
+WERROR _svcctl_DeleteService(pipes_struct *p, struct svcctl_DeleteService *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_SetServiceStatus(pipes_struct *p, struct svcctl_SetServiceStatus *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_NotifyBootConfigStatus(pipes_struct *p, struct svcctl_NotifyBootConfigStatus *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_SCSetServiceBitsW(pipes_struct *p, struct svcctl_SCSetServiceBitsW *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_ChangeServiceConfigW(pipes_struct *p, struct svcctl_ChangeServiceConfigW *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_CreateServiceW(pipes_struct *p, struct svcctl_CreateServiceW *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_EnumServicesStatusW(pipes_struct *p, struct svcctl_EnumServicesStatusW *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_QueryServiceConfigW(pipes_struct *p, struct svcctl_QueryServiceConfigW *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_QueryServiceLockStatusW(pipes_struct *p, struct svcctl_QueryServiceLockStatusW *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_GetServiceKeyNameW(pipes_struct *p, struct svcctl_GetServiceKeyNameW *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_SCSetServiceBitsA(pipes_struct *p, struct svcctl_SCSetServiceBitsA *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_ChangeServiceConfigA(pipes_struct *p, struct svcctl_ChangeServiceConfigA *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_CreateServiceA(pipes_struct *p, struct svcctl_CreateServiceA *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_EnumDependentServicesA(pipes_struct *p, struct svcctl_EnumDependentServicesA *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_EnumServicesStatusA(pipes_struct *p, struct svcctl_EnumServicesStatusA *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_OpenSCManagerA(pipes_struct *p, struct svcctl_OpenSCManagerA *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_OpenServiceA(pipes_struct *p, struct svcctl_OpenServiceA *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_QueryServiceConfigA(pipes_struct *p, struct svcctl_QueryServiceConfigA *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_QueryServiceLockStatusA(pipes_struct *p, struct svcctl_QueryServiceLockStatusA *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_StartServiceA(pipes_struct *p, struct svcctl_StartServiceA *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_GetServiceDisplayNameA(pipes_struct *p, struct svcctl_GetServiceDisplayNameA *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_GetServiceKeyNameA(pipes_struct *p, struct svcctl_GetServiceKeyNameA *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_GetCurrentGroupeStateW(pipes_struct *p, struct svcctl_GetCurrentGroupeStateW *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_EnumServiceGroupW(pipes_struct *p, struct svcctl_EnumServiceGroupW *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_ChangeServiceConfig2A(pipes_struct *p, struct svcctl_ChangeServiceConfig2A *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_ChangeServiceConfig2W(pipes_struct *p, struct svcctl_ChangeServiceConfig2W *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_QueryServiceConfig2A(pipes_struct *p, struct svcctl_QueryServiceConfig2A *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_QueryServiceConfig2W(pipes_struct *p, struct svcctl_QueryServiceConfig2W *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_QueryServiceStatusEx(pipes_struct *p, struct svcctl_QueryServiceStatusEx *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _EnumServicesStatusExA(pipes_struct *p, struct EnumServicesStatusExA *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _EnumServicesStatusExW(pipes_struct *p, struct EnumServicesStatusExW *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+WERROR _svcctl_SCSendTSMessage(pipes_struct *p, struct svcctl_SCSendTSMessage *r)
+{
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
diff --git a/source3/rpc_server/srv_util.c b/source3/rpc_server/srv_util.c
new file mode 100644
index 0000000000..d4804b98ad
--- /dev/null
+++ b/source3/rpc_server/srv_util.c
@@ -0,0 +1,82 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Paul Ashton 1997-1998,
+ * Copyright (C) Andrew Bartlett 2004.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* 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"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+#if 0 /* these aren't used currently but are here if you need them */
+/*
+ * A list of the rids of well known BUILTIN and Domain users
+ * and groups.
+ */
+
+static const 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. */
+static const 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. */
+static const 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 }
+};
+#endif
+
diff --git a/source3/rpc_server/srv_winreg_nt.c b/source3/rpc_server/srv_winreg_nt.c
new file mode 100644
index 0000000000..3991c5ae02
--- /dev/null
+++ b/source3/rpc_server/srv_winreg_nt.c
@@ -0,0 +1,965 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ *
+ * Copyright (C) Gerald Carter 2002-2006.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Implementation of registry functions. */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+/******************************************************************
+ free() function for struct registry_key
+ *****************************************************************/
+
+static void free_regkey(void *ptr)
+{
+ struct registry_key *key = (struct registry_key *)ptr;
+ TALLOC_FREE(key);
+}
+
+/******************************************************************
+ Find a registry key handle and return a struct registry_key *
+ *****************************************************************/
+
+static struct registry_key *find_regkey_by_hnd(pipes_struct *p,
+ POLICY_HND *hnd)
+{
+ struct registry_key *regkey = NULL;
+
+ if(!find_policy_by_hnd(p,hnd,(void **)(void *)&regkey)) {
+ DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: "));
+ return NULL;
+ }
+
+ return regkey;
+}
+
+/*******************************************************************
+ Function for open a new registry handle and creating a handle
+ Note that P should be valid & hnd should already have space
+
+ When we open a key, we store the full path to the key as
+ HK[LM|U]\<key>\<key>\...
+ *******************************************************************/
+
+static WERROR open_registry_key( pipes_struct *p, POLICY_HND *hnd,
+ struct registry_key *parent,
+ const char *subkeyname,
+ uint32 access_desired )
+{
+ WERROR result = WERR_OK;
+ struct registry_key *key;
+
+ if (parent == NULL) {
+ result = reg_openhive(NULL, subkeyname, access_desired,
+ p->pipe_user.nt_user_token, &key);
+ }
+ else {
+ result = reg_openkey(NULL, parent, subkeyname, access_desired,
+ &key);
+ }
+
+ if ( !W_ERROR_IS_OK(result) ) {
+ return result;
+ }
+
+ if ( !create_policy_hnd( p, hnd, free_regkey, key ) ) {
+ return WERR_BADFILE;
+ }
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ Function for open a new registry handle and creating a handle
+ Note that P should be valid & hnd should already have space
+ *******************************************************************/
+
+static bool close_registry_key(pipes_struct *p, POLICY_HND *hnd)
+{
+ struct registry_key *regkey = find_regkey_by_hnd(p, hnd);
+
+ if ( !regkey ) {
+ DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n",
+ OUR_HANDLE(hnd)));
+ return False;
+ }
+
+ close_policy_hnd(p, hnd);
+
+ return True;
+}
+
+/********************************************************************
+ reg_close
+ ********************************************************************/
+
+WERROR _winreg_CloseKey(pipes_struct *p, struct winreg_CloseKey *r)
+{
+ /* close the policy handle */
+
+ if (!close_registry_key(p, r->in.handle))
+ return WERR_BADFID;
+
+ ZERO_STRUCTP(r->out.handle);
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_OpenHKLM(pipes_struct *p, struct winreg_OpenHKLM *r)
+{
+ return open_registry_key(p, r->out.handle, NULL, KEY_HKLM, r->in.access_mask);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_OpenHKPD(pipes_struct *p, struct winreg_OpenHKPD *r)
+{
+ return open_registry_key(p, r->out.handle, NULL, KEY_HKPD, r->in.access_mask);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_OpenHKPT(pipes_struct *p, struct winreg_OpenHKPT *r)
+{
+ return open_registry_key(p, r->out.handle, NULL, KEY_HKPT, r->in.access_mask);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_OpenHKCR(pipes_struct *p, struct winreg_OpenHKCR *r)
+{
+ return open_registry_key(p, r->out.handle, NULL, KEY_HKCR, r->in.access_mask);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_OpenHKU(pipes_struct *p, struct winreg_OpenHKU *r)
+{
+ return open_registry_key(p, r->out.handle, NULL, KEY_HKU, r->in.access_mask);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_OpenHKCU(pipes_struct *p, struct winreg_OpenHKCU *r)
+{
+ return open_registry_key(p, r->out.handle, NULL, KEY_HKCU, r->in.access_mask);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_OpenHKCC(pipes_struct *p, struct winreg_OpenHKCC *r)
+{
+ return open_registry_key(p, r->out.handle, NULL, KEY_HKCC, r->in.access_mask);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_OpenHKDD(pipes_struct *p, struct winreg_OpenHKDD *r)
+{
+ return open_registry_key(p, r->out.handle, NULL, KEY_HKDD, r->in.access_mask);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_OpenHKPN(pipes_struct *p, struct winreg_OpenHKPN *r)
+{
+ return open_registry_key(p, r->out.handle, NULL, KEY_HKPN, r->in.access_mask);
+}
+
+/*******************************************************************
+ reg_reply_open_entry
+ ********************************************************************/
+
+WERROR _winreg_OpenKey(pipes_struct *p, struct winreg_OpenKey *r)
+{
+ struct registry_key *parent = find_regkey_by_hnd(p, r->in.parent_handle );
+
+ if ( !parent )
+ return WERR_BADFID;
+
+ return open_registry_key(p, r->out.handle, parent, r->in.keyname.name, r->in.access_mask);
+}
+
+/*******************************************************************
+ reg_reply_info
+ ********************************************************************/
+
+WERROR _winreg_QueryValue(pipes_struct *p, struct winreg_QueryValue *r)
+{
+ WERROR status = WERR_BADFILE;
+ struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
+ prs_struct prs_hkpd;
+
+ uint8_t *outbuf;
+ uint32_t outbuf_size;
+
+ DATA_BLOB val_blob;
+ bool free_buf = False;
+ bool free_prs = False;
+
+ if ( !regkey )
+ return WERR_BADFID;
+
+ if ((r->out.value_length == NULL) || (r->out.type == NULL)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ *r->out.value_length = *r->out.type = REG_NONE;
+
+ DEBUG(7,("_reg_info: policy key name = [%s]\n", regkey->key->name));
+ DEBUG(7,("_reg_info: policy key type = [%08x]\n", regkey->key->type));
+
+ /* Handle QueryValue calls on HKEY_PERFORMANCE_DATA */
+ if(regkey->key->type == REG_KEY_HKPD)
+ {
+ if (strequal(r->in.value_name->name, "Global")) {
+ if (!prs_init(&prs_hkpd, *r->in.data_size, p->mem_ctx, MARSHALL))
+ return WERR_NOMEM;
+ status = reg_perfcount_get_hkpd(
+ &prs_hkpd, *r->in.data_size, &outbuf_size, NULL);
+ outbuf = (uint8_t *)prs_hkpd.data_p;
+ free_prs = True;
+ }
+ else if (strequal(r->in.value_name->name, "Counter 009")) {
+ outbuf_size = reg_perfcount_get_counter_names(
+ reg_perfcount_get_base_index(),
+ (char **)(void *)&outbuf);
+ free_buf = True;
+ }
+ else if (strequal(r->in.value_name->name, "Explain 009")) {
+ outbuf_size = reg_perfcount_get_counter_help(
+ reg_perfcount_get_base_index(),
+ (char **)(void *)&outbuf);
+ free_buf = True;
+ }
+ else if (isdigit(r->in.value_name->name[0])) {
+ /* we probably have a request for a specific object
+ * here */
+ if (!prs_init(&prs_hkpd, *r->in.data_size, p->mem_ctx, MARSHALL))
+ return WERR_NOMEM;
+ status = reg_perfcount_get_hkpd(
+ &prs_hkpd, *r->in.data_size, &outbuf_size,
+ r->in.value_name->name);
+ outbuf = (uint8_t *)prs_hkpd.data_p;
+ free_prs = True;
+ }
+ else {
+ DEBUG(3,("Unsupported key name [%s] for HKPD.\n",
+ r->in.value_name->name));
+ return WERR_BADFILE;
+ }
+
+ *r->out.type = REG_BINARY;
+ }
+ else {
+ struct registry_value *val;
+
+ status = reg_queryvalue(p->mem_ctx, regkey, r->in.value_name->name,
+ &val);
+ if (!W_ERROR_IS_OK(status)) {
+ if (r->out.data_size) {
+ *r->out.data_size = 0;
+ }
+ if (r->out.value_length) {
+ *r->out.value_length = 0;
+ }
+ return status;
+ }
+
+ status = registry_push_value(p->mem_ctx, val, &val_blob);
+ if (!W_ERROR_IS_OK(status)) {
+ return status;
+ }
+
+ outbuf = val_blob.data;
+ outbuf_size = val_blob.length;
+ *r->out.type = val->type;
+ }
+
+ *r->out.value_length = outbuf_size;
+
+ if ( *r->in.data_size == 0 || !r->out.data ) {
+ status = WERR_OK;
+ } else if ( *r->out.value_length > *r->in.data_size ) {
+ status = WERR_MORE_DATA;
+ } else {
+ memcpy( r->out.data, outbuf, *r->out.value_length );
+ status = WERR_OK;
+ }
+
+ *r->out.data_size = *r->out.value_length;
+
+ if (free_prs) prs_mem_free(&prs_hkpd);
+ if (free_buf) SAFE_FREE(outbuf);
+
+ return status;
+}
+
+/*****************************************************************************
+ Implementation of REG_QUERY_KEY
+ ****************************************************************************/
+
+WERROR _winreg_QueryInfoKey(pipes_struct *p, struct winreg_QueryInfoKey *r)
+{
+ WERROR status = WERR_OK;
+ struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
+
+ if ( !regkey )
+ return WERR_BADFID;
+
+ r->out.classname->name = NULL;
+
+ status = reg_queryinfokey(regkey, r->out.num_subkeys, r->out.max_subkeylen,
+ r->out.max_classlen, r->out.num_values, r->out.max_valnamelen,
+ r->out.max_valbufsize, r->out.secdescsize,
+ r->out.last_changed_time);
+ if (!W_ERROR_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * These calculations account for the registry buffers being
+ * UTF-16. They are inexact at best, but so far they worked.
+ */
+
+ *r->out.max_subkeylen *= 2;
+
+ *r->out.max_valnamelen += 1;
+ *r->out.max_valnamelen *= 2;
+
+ return WERR_OK;
+}
+
+
+/*****************************************************************************
+ Implementation of REG_GETVERSION
+ ****************************************************************************/
+
+WERROR _winreg_GetVersion(pipes_struct *p, struct winreg_GetVersion *r)
+{
+ struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
+
+ if ( !regkey )
+ return WERR_BADFID;
+
+ return reg_getversion(r->out.version);
+}
+
+
+/*****************************************************************************
+ Implementation of REG_ENUM_KEY
+ ****************************************************************************/
+
+WERROR _winreg_EnumKey(pipes_struct *p, struct winreg_EnumKey *r)
+{
+ WERROR err;
+ struct registry_key *key = find_regkey_by_hnd( p, r->in.handle );
+
+ if ( !key )
+ return WERR_BADFID;
+
+ if ( !r->in.name || !r->in.keyclass )
+ return WERR_INVALID_PARAM;
+
+ DEBUG(8,("_reg_enum_key: enumerating key [%s]\n", key->key->name));
+
+ err = reg_enumkey(p->mem_ctx, key, r->in.enum_index, (char **)&r->out.name->name,
+ r->out.last_changed_time);
+ if (!W_ERROR_IS_OK(err)) {
+ return err;
+ }
+ r->out.keyclass->name = "";
+ return WERR_OK;
+}
+
+/*****************************************************************************
+ Implementation of REG_ENUM_VALUE
+ ****************************************************************************/
+
+WERROR _winreg_EnumValue(pipes_struct *p, struct winreg_EnumValue *r)
+{
+ WERROR err;
+ struct registry_key *key = find_regkey_by_hnd( p, r->in.handle );
+ char *valname;
+ struct registry_value *val;
+ DATA_BLOB value_blob;
+
+ if ( !key )
+ return WERR_BADFID;
+
+ if ( !r->in.name )
+ return WERR_INVALID_PARAM;
+
+ DEBUG(8,("_winreg_EnumValue: enumerating values for key [%s]\n",
+ key->key->name));
+
+ err = reg_enumvalue(p->mem_ctx, key, r->in.enum_index, &valname, &val);
+ if (!W_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ err = registry_push_value(p->mem_ctx, val, &value_blob);
+ if (!W_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ if (r->out.name != NULL) {
+ r->out.name->name = valname;
+ }
+
+ if (r->out.type != NULL) {
+ *r->out.type = val->type;
+ }
+
+ if (r->out.value != NULL) {
+ if ((r->out.size == NULL) || (r->out.length == NULL)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ if (value_blob.length > *r->out.size) {
+ return WERR_MORE_DATA;
+ }
+
+ memcpy( r->out.value, value_blob.data, value_blob.length );
+ }
+
+ if (r->out.length != NULL) {
+ *r->out.length = value_blob.length;
+ }
+ if (r->out.size != NULL) {
+ *r->out.size = value_blob.length;
+ }
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ reg_shutdwon
+ ********************************************************************/
+
+WERROR _winreg_InitiateSystemShutdown(pipes_struct *p, struct winreg_InitiateSystemShutdown *r)
+{
+ struct winreg_InitiateSystemShutdownEx s;
+
+ s.in.hostname = r->in.hostname;
+ s.in.message = r->in.message;
+ s.in.timeout = r->in.timeout;
+ s.in.force_apps = r->in.force_apps;
+ s.in.do_reboot = r->in.do_reboot;
+ s.in.reason = 0;
+
+ /* thunk down to _winreg_InitiateSystemShutdownEx()
+ (just returns a status) */
+
+ return _winreg_InitiateSystemShutdownEx( p, &s );
+}
+
+/*******************************************************************
+ reg_shutdown_ex
+ ********************************************************************/
+
+#define SHUTDOWN_R_STRING "-r"
+#define SHUTDOWN_F_STRING "-f"
+
+
+WERROR _winreg_InitiateSystemShutdownEx(pipes_struct *p, struct winreg_InitiateSystemShutdownEx *r)
+{
+ char *shutdown_script = NULL;
+ char *msg = NULL;
+ char *chkmsg = NULL;
+ fstring str_timeout;
+ fstring str_reason;
+ fstring do_reboot;
+ fstring f;
+ int ret;
+ bool can_shutdown;
+
+ shutdown_script = talloc_strdup(p->mem_ctx, lp_shutdown_script());
+ if (!shutdown_script) {
+ return WERR_NOMEM;
+ }
+ if (!*shutdown_script) {
+ return WERR_ACCESS_DENIED;
+ }
+
+ /* pull the message string and perform necessary sanity checks on it */
+
+ if ( r->in.message && r->in.message->name && r->in.message->name->name ) {
+ if ( (msg = talloc_strdup(p->mem_ctx, r->in.message->name->name )) == NULL ) {
+ return WERR_NOMEM;
+ }
+ chkmsg = TALLOC_ARRAY(p->mem_ctx, char, strlen(msg)+1);
+ if (!chkmsg) {
+ return WERR_NOMEM;
+ }
+ alpha_strcpy(chkmsg, msg, NULL, strlen(msg)+1);
+ }
+
+ fstr_sprintf(str_timeout, "%d", r->in.timeout);
+ fstr_sprintf(do_reboot, r->in.do_reboot ? SHUTDOWN_R_STRING : "");
+ fstr_sprintf(f, r->in.force_apps ? SHUTDOWN_F_STRING : "");
+ fstr_sprintf(str_reason, "%d", r->in.reason );
+
+ shutdown_script = talloc_all_string_sub(p->mem_ctx,
+ shutdown_script, "%z", chkmsg ? chkmsg : "");
+ if (!shutdown_script) {
+ return WERR_NOMEM;
+ }
+ shutdown_script = talloc_all_string_sub(p->mem_ctx,
+ shutdown_script, "%t", str_timeout);
+ if (!shutdown_script) {
+ return WERR_NOMEM;
+ }
+ shutdown_script = talloc_all_string_sub(p->mem_ctx,
+ shutdown_script, "%r", do_reboot);
+ if (!shutdown_script) {
+ return WERR_NOMEM;
+ }
+ shutdown_script = talloc_all_string_sub(p->mem_ctx,
+ shutdown_script, "%f", f);
+ if (!shutdown_script) {
+ return WERR_NOMEM;
+ }
+ shutdown_script = talloc_all_string_sub(p->mem_ctx,
+ shutdown_script, "%x", str_reason);
+ if (!shutdown_script) {
+ return WERR_NOMEM;
+ }
+
+ can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
+
+ /* IF someone has privs, run the shutdown script as root. OTHERWISE run it as not root
+ Take the error return from the script and provide it as the Windows return code. */
+
+ /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
+
+ if ( can_shutdown )
+ become_root();
+
+ ret = smbrun( shutdown_script, NULL );
+
+ if ( can_shutdown )
+ unbecome_root();
+
+ /********** END SeRemoteShutdownPrivilege BLOCK **********/
+
+ DEBUG(3,("_reg_shutdown_ex: Running the command `%s' gave %d\n",
+ shutdown_script, ret));
+
+ return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
+}
+
+/*******************************************************************
+ reg_abort_shutdwon
+ ********************************************************************/
+
+WERROR _winreg_AbortSystemShutdown(pipes_struct *p, struct winreg_AbortSystemShutdown *r)
+{
+ const char *abort_shutdown_script;
+ int ret;
+ bool can_shutdown;
+
+ abort_shutdown_script = lp_abort_shutdown_script();
+
+ if (!*abort_shutdown_script)
+ return WERR_ACCESS_DENIED;
+
+ can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
+
+ /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
+
+ if ( can_shutdown )
+ become_root();
+
+ ret = smbrun( abort_shutdown_script, NULL );
+
+ if ( can_shutdown )
+ unbecome_root();
+
+ /********** END SeRemoteShutdownPrivilege BLOCK **********/
+
+ DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",
+ abort_shutdown_script, ret));
+
+ return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static int validate_reg_filename(TALLOC_CTX *ctx, char **pp_fname )
+{
+ char *p = NULL;
+ int num_services = lp_numservices();
+ int snum = -1;
+ const char *share_path;
+ char *fname = *pp_fname;
+
+ /* convert to a unix path, stripping the C:\ along the way */
+
+ if (!(p = valid_share_pathname(ctx, fname))) {
+ return -1;
+ }
+
+ /* has to exist within a valid file share */
+
+ for (snum=0; snum<num_services; snum++) {
+ if (!lp_snum_ok(snum) || lp_print_ok(snum)) {
+ continue;
+ }
+
+ share_path = lp_pathname(snum);
+
+ /* make sure we have a path (e.g. [homes] ) */
+ if (strlen(share_path) == 0) {
+ continue;
+ }
+
+ if (strncmp(share_path, p, strlen(share_path)) == 0) {
+ break;
+ }
+ }
+
+ *pp_fname = p;
+ return (snum < num_services) ? snum : -1;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_RestoreKey(pipes_struct *p, struct winreg_RestoreKey *r)
+{
+ struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
+ char *fname = NULL;
+ int snum;
+
+ if ( !regkey )
+ return WERR_BADFID;
+
+ if ( !r->in.filename || !r->in.filename->name )
+ return WERR_INVALID_PARAM;
+
+ fname = talloc_strdup(p->mem_ctx, r->in.filename->name);
+ if (!fname) {
+ return WERR_NOMEM;
+ }
+
+ DEBUG(8,("_winreg_RestoreKey: verifying restore of key [%s] from "
+ "\"%s\"\n", regkey->key->name, fname));
+
+ if ((snum = validate_reg_filename(p->mem_ctx, &fname)) == -1)
+ return WERR_OBJECT_PATH_INVALID;
+
+ /* user must posses SeRestorePrivilege for this this proceed */
+
+ if ( !user_has_privileges( p->pipe_user.nt_user_token, &se_restore ) )
+ return WERR_ACCESS_DENIED;
+
+ DEBUG(2,("_winreg_RestoreKey: Restoring [%s] from %s in share %s\n",
+ regkey->key->name, fname, lp_servicename(snum) ));
+
+ return reg_restorekey(regkey, fname);
+}
+
+WERROR _winreg_SaveKey(pipes_struct *p, struct winreg_SaveKey *r)
+{
+ struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle );
+ char *fname = NULL;
+ int snum = -1;
+
+ if ( !regkey )
+ return WERR_BADFID;
+
+ if ( !r->in.filename || !r->in.filename->name )
+ return WERR_INVALID_PARAM;
+
+ fname = talloc_strdup(p->mem_ctx, r->in.filename->name);
+ if (!fname) {
+ return WERR_NOMEM;
+ }
+
+ DEBUG(8,("_winreg_SaveKey: verifying backup of key [%s] to \"%s\"\n",
+ regkey->key->name, fname));
+
+ if ((snum = validate_reg_filename(p->mem_ctx, &fname)) == -1 )
+ return WERR_OBJECT_PATH_INVALID;
+
+ DEBUG(2,("_winreg_SaveKey: Saving [%s] to %s in share %s\n",
+ regkey->key->name, fname, lp_servicename(snum) ));
+
+ return reg_savekey(regkey, fname);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_SaveKeyEx(pipes_struct *p, struct winreg_SaveKeyEx *r)
+{
+ /* fill in your code here if you think this call should
+ do anything */
+
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_CreateKey( pipes_struct *p, struct winreg_CreateKey *r)
+{
+ struct registry_key *parent = find_regkey_by_hnd(p, r->in.handle);
+ struct registry_key *new_key;
+ WERROR result;
+
+ if ( !parent )
+ return WERR_BADFID;
+
+ DEBUG(10, ("_winreg_CreateKey called with parent key '%s' and "
+ "subkey name '%s'\n", parent->key->name, r->in.name.name));
+
+ result = reg_createkey(NULL, parent, r->in.name.name, r->in.access_mask,
+ &new_key, r->out.action_taken);
+ if (!W_ERROR_IS_OK(result)) {
+ return result;
+ }
+
+ if (!create_policy_hnd(p, r->out.new_handle, free_regkey, new_key)) {
+ TALLOC_FREE(new_key);
+ return WERR_BADFILE;
+ }
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_SetValue(pipes_struct *p, struct winreg_SetValue *r)
+{
+ struct registry_key *key = find_regkey_by_hnd(p, r->in.handle);
+ struct registry_value *val;
+ WERROR status;
+
+ if ( !key )
+ return WERR_BADFID;
+
+ DEBUG(8,("_reg_set_value: Setting value for [%s:%s]\n",
+ key->key->name, r->in.name.name));
+
+ status = registry_pull_value(p->mem_ctx, &val, r->in.type, r->in.data,
+ r->in.size, r->in.size);
+ if (!W_ERROR_IS_OK(status)) {
+ return status;
+ }
+
+ return reg_setvalue(key, r->in.name.name, val);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_DeleteKey(pipes_struct *p, struct winreg_DeleteKey *r)
+{
+ struct registry_key *parent = find_regkey_by_hnd(p, r->in.handle);
+
+ if ( !parent )
+ return WERR_BADFID;
+
+ return reg_deletekey(parent, r->in.key.name);
+}
+
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_DeleteValue(pipes_struct *p, struct winreg_DeleteValue *r)
+{
+ struct registry_key *key = find_regkey_by_hnd(p, r->in.handle);
+
+ if ( !key )
+ return WERR_BADFID;
+
+ return reg_deletevalue(key, r->in.value.name);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_GetKeySecurity(pipes_struct *p, struct winreg_GetKeySecurity *r)
+{
+ struct registry_key *key = find_regkey_by_hnd(p, r->in.handle);
+ WERROR err;
+ struct security_descriptor *secdesc;
+ uint8 *data;
+ size_t len;
+
+ if ( !key )
+ return WERR_BADFID;
+
+ /* access checks first */
+
+ if ( !(key->key->access_granted & STD_RIGHT_READ_CONTROL_ACCESS) )
+ return WERR_ACCESS_DENIED;
+
+ err = reg_getkeysecurity(p->mem_ctx, key, &secdesc);
+ if (!W_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ err = ntstatus_to_werror(marshall_sec_desc(p->mem_ctx, secdesc,
+ &data, &len));
+ if (!W_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ if (len > r->out.sd->size) {
+ r->out.sd->size = len;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ r->out.sd->size = len;
+ r->out.sd->len = len;
+ r->out.sd->data = data;
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_SetKeySecurity(pipes_struct *p, struct winreg_SetKeySecurity *r)
+{
+ struct registry_key *key = find_regkey_by_hnd(p, r->in.handle);
+ struct security_descriptor *secdesc;
+ WERROR err;
+
+ if ( !key )
+ return WERR_BADFID;
+
+ /* access checks first */
+
+ if ( !(key->key->access_granted & STD_RIGHT_WRITE_DAC_ACCESS) )
+ return WERR_ACCESS_DENIED;
+
+ err = ntstatus_to_werror(unmarshall_sec_desc(p->mem_ctx, r->in.sd->data,
+ r->in.sd->len, &secdesc));
+ if (!W_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ return reg_setkeysecurity(key, secdesc);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_FlushKey(pipes_struct *p, struct winreg_FlushKey *r)
+{
+ /* I'm just replying OK because there's not a lot
+ here I see to do i --jerry */
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_UnLoadKey(pipes_struct *p, struct winreg_UnLoadKey *r)
+{
+ /* fill in your code here if you think this call should
+ do anything */
+
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_ReplaceKey(pipes_struct *p, struct winreg_ReplaceKey *r)
+{
+ /* fill in your code here if you think this call should
+ do anything */
+
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_LoadKey(pipes_struct *p, struct winreg_LoadKey *r)
+{
+ /* fill in your code here if you think this call should
+ do anything */
+
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_NotifyChangeKeyValue(pipes_struct *p, struct winreg_NotifyChangeKeyValue *r)
+{
+ /* fill in your code here if you think this call should
+ do anything */
+
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_QueryMultipleValues(pipes_struct *p, struct winreg_QueryMultipleValues *r)
+{
+ /* fill in your code here if you think this call should
+ do anything */
+
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _winreg_QueryMultipleValues2(pipes_struct *p, struct winreg_QueryMultipleValues2 *r)
+{
+ /* fill in your code here if you think this call should
+ do anything */
+
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
diff --git a/source3/rpc_server/srv_wkssvc_nt.c b/source3/rpc_server/srv_wkssvc_nt.c
new file mode 100644
index 0000000000..c96439cc1a
--- /dev/null
+++ b/source3/rpc_server/srv_wkssvc_nt.c
@@ -0,0 +1,494 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ *
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Gerald (Jerry) Carter 2006.
+ * Copyright (C) Guenther Deschner 2007-2008.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This is the implementation of the wks interface. */
+
+#include "includes.h"
+#include "libnet/libnet.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+/*******************************************************************
+ Fill in the values for the struct wkssvc_NetWkstaInfo100.
+ ********************************************************************/
+
+static void create_wks_info_100(struct wkssvc_NetWkstaInfo100 *info100)
+{
+ info100->platform_id = PLATFORM_ID_NT; /* unknown */
+ info100->version_major = lp_major_announce_version();
+ info100->version_minor = lp_minor_announce_version();
+
+ info100->server_name = talloc_asprintf_strupper_m(
+ info100, "%s", global_myname());
+ info100->domain_name = talloc_asprintf_strupper_m(
+ info100, "%s", lp_workgroup());
+
+ return;
+}
+
+/********************************************************************
+ only supports info level 100 at the moment.
+ ********************************************************************/
+
+WERROR _wkssvc_NetWkstaGetInfo(pipes_struct *p, struct wkssvc_NetWkstaGetInfo *r)
+{
+ struct wkssvc_NetWkstaInfo100 *wks100 = NULL;
+
+ /* We only support info level 100 currently */
+
+ if ( r->in.level != 100 ) {
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ if ( (wks100 = TALLOC_ZERO_P(p->mem_ctx, struct wkssvc_NetWkstaInfo100)) == NULL ) {
+ return WERR_NOMEM;
+ }
+
+ create_wks_info_100( wks100 );
+
+ r->out.info->info100 = wks100;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetWkstaSetInfo(pipes_struct *p, struct wkssvc_NetWkstaSetInfo *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetWkstaEnumUsers(pipes_struct *p, struct wkssvc_NetWkstaEnumUsers *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrWkstaUserGetInfo(pipes_struct *p, struct wkssvc_NetrWkstaUserGetInfo *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrWkstaUserSetInfo(pipes_struct *p, struct wkssvc_NetrWkstaUserSetInfo *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetWkstaTransportEnum(pipes_struct *p, struct wkssvc_NetWkstaTransportEnum *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrWkstaTransportAdd(pipes_struct *p, struct wkssvc_NetrWkstaTransportAdd *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrWkstaTransportDel(pipes_struct *p, struct wkssvc_NetrWkstaTransportDel *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrUseAdd(pipes_struct *p, struct wkssvc_NetrUseAdd *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrUseGetInfo(pipes_struct *p, struct wkssvc_NetrUseGetInfo *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrUseDel(pipes_struct *p, struct wkssvc_NetrUseDel *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrUseEnum(pipes_struct *p, struct wkssvc_NetrUseEnum *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrMessageBufferSend(pipes_struct *p, struct wkssvc_NetrMessageBufferSend *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrWorkstationStatisticsGet(pipes_struct *p, struct wkssvc_NetrWorkstationStatisticsGet *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrLogonDomainNameAdd(pipes_struct *p, struct wkssvc_NetrLogonDomainNameAdd *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrLogonDomainNameDel(pipes_struct *p, struct wkssvc_NetrLogonDomainNameDel *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrJoinDomain(pipes_struct *p, struct wkssvc_NetrJoinDomain *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrUnjoinDomain(pipes_struct *p, struct wkssvc_NetrUnjoinDomain *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrRenameMachineInDomain(pipes_struct *p, struct wkssvc_NetrRenameMachineInDomain *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrValidateName(pipes_struct *p, struct wkssvc_NetrValidateName *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrGetJoinInformation(pipes_struct *p, struct wkssvc_NetrGetJoinInformation *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrGetJoinableOus(pipes_struct *p, struct wkssvc_NetrGetJoinableOus *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ _wkssvc_NetrJoinDomain2
+ ********************************************************************/
+
+WERROR _wkssvc_NetrJoinDomain2(pipes_struct *p,
+ struct wkssvc_NetrJoinDomain2 *r)
+{
+ struct libnet_JoinCtx *j = NULL;
+ char *cleartext_pwd = NULL;
+ char *admin_domain = NULL;
+ char *admin_account = NULL;
+ WERROR werr;
+ struct nt_user_token *token = p->pipe_user.nt_user_token;
+
+ if (!r->in.domain_name) {
+ return WERR_INVALID_PARAM;
+ }
+
+ if (!r->in.admin_account || !r->in.encrypted_password) {
+ return WERR_INVALID_PARAM;
+ }
+
+ if (!user_has_privileges(token, &se_machine_account) &&
+ !nt_token_check_domain_rid(token, DOMAIN_GROUP_RID_ADMINS) &&
+ !nt_token_check_domain_rid(token, BUILTIN_ALIAS_RID_ADMINS)) {
+ DEBUG(5,("_wkssvc_NetrJoinDomain2: account doesn't have "
+ "sufficient privileges\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED) ||
+ (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
+ return WERR_NOT_SUPPORTED;
+ }
+
+ werr = decode_wkssvc_join_password_buffer(
+ p->mem_ctx, r->in.encrypted_password,
+ &p->server_info->user_session_key, &cleartext_pwd);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ split_domain_user(p->mem_ctx,
+ r->in.admin_account,
+ &admin_domain,
+ &admin_account);
+
+ werr = libnet_init_JoinCtx(p->mem_ctx, &j);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ j->in.domain_name = r->in.domain_name;
+ j->in.account_ou = r->in.account_ou;
+ j->in.join_flags = r->in.join_flags;
+ j->in.admin_account = admin_account;
+ j->in.admin_password = cleartext_pwd;
+ j->in.debug = true;
+ j->in.modify_config = lp_config_backend_is_registry();
+ j->in.msg_ctx = smbd_messaging_context();
+
+ become_root();
+ werr = libnet_Join(p->mem_ctx, j);
+ unbecome_root();
+
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(5,("_wkssvc_NetrJoinDomain2: libnet_Join failed with: %s\n",
+ j->out.error_string ? j->out.error_string :
+ dos_errstr(werr)));
+ }
+
+ TALLOC_FREE(j);
+ return werr;
+}
+
+/********************************************************************
+ _wkssvc_NetrUnjoinDomain2
+ ********************************************************************/
+
+WERROR _wkssvc_NetrUnjoinDomain2(pipes_struct *p,
+ struct wkssvc_NetrUnjoinDomain2 *r)
+{
+ struct libnet_UnjoinCtx *u = NULL;
+ char *cleartext_pwd = NULL;
+ char *admin_domain = NULL;
+ char *admin_account = NULL;
+ WERROR werr;
+ struct nt_user_token *token = p->pipe_user.nt_user_token;
+
+ if (!r->in.account || !r->in.encrypted_password) {
+ return WERR_INVALID_PARAM;
+ }
+
+ if (!user_has_privileges(token, &se_machine_account) &&
+ !nt_token_check_domain_rid(token, DOMAIN_GROUP_RID_ADMINS) &&
+ !nt_token_check_domain_rid(token, BUILTIN_ALIAS_RID_ADMINS)) {
+ DEBUG(5,("_wkssvc_NetrUnjoinDomain2: account doesn't have "
+ "sufficient privileges\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ werr = decode_wkssvc_join_password_buffer(
+ p->mem_ctx, r->in.encrypted_password,
+ &p->server_info->user_session_key, &cleartext_pwd);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ split_domain_user(p->mem_ctx,
+ r->in.account,
+ &admin_domain,
+ &admin_account);
+
+ werr = libnet_init_UnjoinCtx(p->mem_ctx, &u);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ u->in.domain_name = lp_realm();
+ u->in.unjoin_flags = r->in.unjoin_flags |
+ WKSSVC_JOIN_FLAGS_JOIN_TYPE;
+ u->in.admin_account = admin_account;
+ u->in.admin_password = cleartext_pwd;
+ u->in.debug = true;
+ u->in.modify_config = lp_config_backend_is_registry();
+ u->in.msg_ctx = smbd_messaging_context();
+
+ become_root();
+ werr = libnet_Unjoin(p->mem_ctx, u);
+ unbecome_root();
+
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(5,("_wkssvc_NetrUnjoinDomain2: libnet_Unjoin failed with: %s\n",
+ u->out.error_string ? u->out.error_string :
+ dos_errstr(werr)));
+ }
+
+ TALLOC_FREE(u);
+ return werr;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrRenameMachineInDomain2(pipes_struct *p, struct wkssvc_NetrRenameMachineInDomain2 *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrValidateName2(pipes_struct *p, struct wkssvc_NetrValidateName2 *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrGetJoinableOus2(pipes_struct *p, struct wkssvc_NetrGetJoinableOus2 *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrAddAlternateComputerName(pipes_struct *p, struct wkssvc_NetrAddAlternateComputerName *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrRemoveAlternateComputerName(pipes_struct *p, struct wkssvc_NetrRemoveAlternateComputerName *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrSetPrimaryComputername(pipes_struct *p, struct wkssvc_NetrSetPrimaryComputername *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrEnumerateComputerNames(pipes_struct *p, struct wkssvc_NetrEnumerateComputerNames *r)
+{
+ /* FIXME: Add implementation code here */
+ p->rng_fault_state = True;
+ return WERR_NOT_SUPPORTED;
+}
+
diff --git a/source3/rpcclient/cmd_dfs.c b/source3/rpcclient/cmd_dfs.c
new file mode 100644
index 0000000000..d55261bea3
--- /dev/null
+++ b/source3/rpcclient/cmd_dfs.c
@@ -0,0 +1,329 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Jelmer Vernooij 2005.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+/* Check DFS is supported by the remote server */
+
+static WERROR cmd_dfs_version(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ enum dfs_ManagerVersion version;
+ NTSTATUS result;
+
+ if (argc != 1) {
+ printf("Usage: %s\n", argv[0]);
+ return WERR_OK;
+ }
+
+ result = rpccli_dfs_GetManagerVersion(cli, mem_ctx, &version);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ return ntstatus_to_werror(result);
+ }
+
+ if (version > 0) {
+ printf("dfs is present (%d)\n", version);
+ } else {
+ printf("dfs is not present\n");
+ }
+
+ return WERR_OK;
+}
+
+static WERROR cmd_dfs_add(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ NTSTATUS result;
+ WERROR werr;
+ const char *path, *servername, *sharename, *comment;
+ uint32 flags = 0;
+
+ if (argc != 5) {
+ printf("Usage: %s path servername sharename comment\n",
+ argv[0]);
+ return WERR_OK;
+ }
+
+ path = argv[1];
+ servername = argv[2];
+ sharename = argv[3];
+ comment = argv[4];
+
+ result = rpccli_dfs_Add(cli, mem_ctx, path, servername,
+ sharename, comment, flags, &werr);
+ if (!NT_STATUS_IS_OK(result)) {
+ return ntstatus_to_werror(result);
+ }
+
+ return werr;
+}
+
+static WERROR cmd_dfs_remove(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ NTSTATUS result;
+ WERROR werr;
+ const char *path, *servername, *sharename;
+
+ if (argc != 4) {
+ printf("Usage: %s path servername sharename\n", argv[0]);
+ return WERR_OK;
+ }
+
+ path = argv[1];
+ servername = argv[2];
+ sharename = argv[3];
+
+ result = rpccli_dfs_Remove(cli, mem_ctx, path, servername,
+ sharename, &werr);
+ if (!NT_STATUS_IS_OK(result)) {
+ return ntstatus_to_werror(result);
+ }
+
+ return werr;
+}
+
+/* Display a DFS_INFO_1 structure */
+
+static void display_dfs_info_1(struct dfs_Info1 *info1)
+{
+ printf("path: %s\n", info1->path);
+}
+
+/* Display a DFS_INFO_2 structure */
+
+static void display_dfs_info_2(struct dfs_Info2 *info2)
+{
+ printf("path: %s\n", info2->path);
+ printf("\tcomment: %s\n", info2->comment);
+
+ printf("\tstate: %d\n", info2->state);
+ printf("\tnum_stores: %d\n", info2->num_stores);
+}
+
+/* Display a DFS_INFO_3 structure */
+
+static void display_dfs_info_3(struct dfs_Info3 *info3)
+{
+ int i;
+
+ printf("path: %s\n", info3->path);
+
+ printf("\tcomment: %s\n", info3->comment);
+
+ printf("\tstate: %d\n", info3->state);
+ printf("\tnum_stores: %d\n", info3->num_stores);
+
+ for (i = 0; i < info3->num_stores; i++) {
+ struct dfs_StorageInfo *dsi = &info3->stores[i];
+
+ printf("\t\tstorage[%d] server: %s\n", i, dsi->server);
+
+ printf("\t\tstorage[%d] share: %s\n", i, dsi->share);
+ }
+}
+
+
+/* Display a DFS_INFO_CTR structure */
+static void display_dfs_info(uint32 level, union dfs_Info *ctr)
+{
+ switch (level) {
+ case 0x01:
+ display_dfs_info_1(ctr->info1);
+ break;
+ case 0x02:
+ display_dfs_info_2(ctr->info2);
+ break;
+ case 0x03:
+ display_dfs_info_3(ctr->info3);
+ break;
+ default:
+ printf("unsupported info level %d\n",
+ level);
+ break;
+ }
+}
+
+static void display_dfs_enumstruct(struct dfs_EnumStruct *ctr)
+{
+ int i;
+
+ /* count is always the first element, so we can just use info1 here */
+ for (i = 0; i < ctr->e.info1->count; i++) {
+ switch (ctr->level) {
+ case 1: display_dfs_info_1(&ctr->e.info1->s[i]); break;
+ case 2: display_dfs_info_2(&ctr->e.info2->s[i]); break;
+ case 3: display_dfs_info_3(&ctr->e.info3->s[i]); break;
+ default:
+ printf("unsupported info level %d\n",
+ ctr->level);
+ return;
+ }
+ }
+}
+
+/* Enumerate dfs shares */
+
+static WERROR cmd_dfs_enum(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ struct dfs_EnumStruct str;
+ struct dfs_EnumArray1 info1;
+ struct dfs_EnumArray2 info2;
+ struct dfs_EnumArray3 info3;
+ struct dfs_EnumArray4 info4;
+ struct dfs_EnumArray200 info200;
+ struct dfs_EnumArray300 info300;
+
+ NTSTATUS result;
+ WERROR werr;
+ uint32 total = 0;
+
+ if (argc > 2) {
+ printf("Usage: %s [info_level]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ str.level = 1;
+ if (argc == 2)
+ str.level = atoi(argv[1]);
+
+ switch (str.level) {
+ case 1: str.e.info1 = &info1; ZERO_STRUCT(info1); break;
+ case 2: str.e.info2 = &info2; ZERO_STRUCT(info2); break;
+ case 3: str.e.info3 = &info3; ZERO_STRUCT(info3); break;
+ case 4: str.e.info4 = &info4; ZERO_STRUCT(info4); break;
+ case 200: str.e.info200 = &info200; ZERO_STRUCT(info200); break;
+ case 300: str.e.info300 = &info300; ZERO_STRUCT(info300); break;
+ default:
+ printf("Unknown info level %d\n", str.level);
+ break;
+ }
+
+ result = rpccli_dfs_Enum(cli, mem_ctx, str.level, 0xFFFFFFFF, &str,
+ &total, &werr);
+
+ if (NT_STATUS_IS_OK(result)) {
+ display_dfs_enumstruct(&str);
+ }
+
+ return werr;
+}
+
+/* Enumerate dfs shares */
+
+static WERROR cmd_dfs_enumex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ struct dfs_EnumStruct str;
+ struct dfs_EnumArray1 info1;
+ struct dfs_EnumArray2 info2;
+ struct dfs_EnumArray3 info3;
+ struct dfs_EnumArray4 info4;
+ struct dfs_EnumArray200 info200;
+ struct dfs_EnumArray300 info300;
+
+ NTSTATUS result;
+ WERROR werr;
+ uint32 total = 0;
+
+ if (argc < 2 || argc > 3) {
+ printf("Usage: %s dfs_name [info_level]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ str.level = 1;
+
+ if (argc == 3)
+ str.level = atoi(argv[2]);
+
+ switch (str.level) {
+ case 1: str.e.info1 = &info1; ZERO_STRUCT(info1); break;
+ case 2: str.e.info2 = &info2; ZERO_STRUCT(info2); break;
+ case 3: str.e.info3 = &info3; ZERO_STRUCT(info3); break;
+ case 4: str.e.info4 = &info4; ZERO_STRUCT(info4); break;
+ case 200: str.e.info200 = &info200; ZERO_STRUCT(info200); break;
+ case 300: str.e.info300 = &info300; ZERO_STRUCT(info300); break;
+ default:
+ printf("Unknown info level %d\n", str.level);
+ break;
+ }
+
+ result = rpccli_dfs_EnumEx(cli, mem_ctx, argv[1], str.level,
+ 0xFFFFFFFF, &str, &total, &werr);
+
+ if (NT_STATUS_IS_OK(result)) {
+ display_dfs_enumstruct(&str);
+ }
+
+ return werr;
+}
+
+
+static WERROR cmd_dfs_getinfo(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ NTSTATUS result;
+ WERROR werr;
+ const char *path, *servername, *sharename;
+ uint32 info_level = 1;
+ union dfs_Info ctr;
+
+ if (argc < 4 || argc > 5) {
+ printf("Usage: %s path servername sharename "
+ "[info_level]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ path = argv[1];
+ servername = argv[2];
+ sharename = argv[3];
+
+ if (argc == 5)
+ info_level = atoi(argv[4]);
+
+ result = rpccli_dfs_GetInfo(cli, mem_ctx, path, servername,
+ sharename, info_level, &ctr, &werr);
+
+ if (NT_STATUS_IS_OK(result)) {
+ display_dfs_info(info_level, &ctr);
+ }
+
+ return werr;
+}
+
+/* List of commands exported by this module */
+
+struct cmd_set dfs_commands[] = {
+
+ { "DFS" },
+
+ { "dfsversion", RPC_RTYPE_WERROR, NULL, cmd_dfs_version, &ndr_table_netdfs.syntax_id, NULL, "Query DFS support", "" },
+ { "dfsadd", RPC_RTYPE_WERROR, NULL, cmd_dfs_add, &ndr_table_netdfs.syntax_id, NULL, "Add a DFS share", "" },
+ { "dfsremove", RPC_RTYPE_WERROR, NULL, cmd_dfs_remove, &ndr_table_netdfs.syntax_id, NULL, "Remove a DFS share", "" },
+ { "dfsgetinfo", RPC_RTYPE_WERROR, NULL, cmd_dfs_getinfo, &ndr_table_netdfs.syntax_id, NULL, "Query DFS share info", "" },
+ { "dfsenum", RPC_RTYPE_WERROR, NULL, cmd_dfs_enum, &ndr_table_netdfs.syntax_id, NULL, "Enumerate dfs shares", "" },
+ { "dfsenumex", RPC_RTYPE_WERROR, NULL, cmd_dfs_enumex, &ndr_table_netdfs.syntax_id, NULL, "Enumerate dfs shares", "" },
+
+ { NULL }
+};
diff --git a/source3/rpcclient/cmd_drsuapi.c b/source3/rpcclient/cmd_drsuapi.c
new file mode 100644
index 0000000000..71757f5ea3
--- /dev/null
+++ b/source3/rpcclient/cmd_drsuapi.c
@@ -0,0 +1,566 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Guenther Deschner 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+static WERROR cracknames(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *bind_handle,
+ enum drsuapi_DsNameFormat format_offered,
+ enum drsuapi_DsNameFormat format_desired,
+ int argc,
+ const char **argv,
+ union drsuapi_DsNameCtr *ctr)
+{
+ NTSTATUS status;
+ WERROR werr;
+ int i;
+ int32_t level = 1;
+ union drsuapi_DsNameRequest req;
+ int32_t level_out;
+ struct drsuapi_DsNameString *names;
+
+ names = TALLOC_ZERO_ARRAY(mem_ctx, struct drsuapi_DsNameString, argc);
+ W_ERROR_HAVE_NO_MEMORY(names);
+
+ for (i=0; i<argc; i++) {
+ names[i].str = argv[i];
+ }
+
+ req.req1.codepage = 1252; /* german */
+ req.req1.language = 0x00000407; /* german */
+ req.req1.count = argc;
+ req.req1.names = names;
+ req.req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS;
+ req.req1.format_offered = format_offered;
+ req.req1.format_desired = format_desired;
+
+ status = rpccli_drsuapi_DsCrackNames(cli, mem_ctx,
+ bind_handle,
+ level,
+ &req,
+ &level_out,
+ ctr,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ return WERR_OK;
+}
+
+static WERROR cmd_drsuapi_cracknames(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ WERROR werr;
+ int i;
+
+ struct GUID bind_guid;
+ struct policy_handle bind_handle;
+
+ union drsuapi_DsNameCtr ctr;
+
+ if (argc < 2) {
+ printf("usage: %s name\n", argv[0]);
+ return WERR_OK;
+ }
+
+ GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);
+
+ status = rpccli_drsuapi_DsBind(cli, mem_ctx,
+ &bind_guid,
+ NULL,
+ &bind_handle,
+ &werr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ werr = cracknames(cli, mem_ctx,
+ &bind_handle,
+ DRSUAPI_DS_NAME_FORMAT_UKNOWN,
+ DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ 1,
+ argv+1,
+ &ctr);
+
+ if (!W_ERROR_IS_OK(werr)) {
+ goto out;
+ }
+
+ for (i=0; i < ctr.ctr1->count; i++) {
+ printf("status: %d\n",
+ ctr.ctr1->array[i].status);
+ printf("dns_domain_name: %s\n",
+ ctr.ctr1->array[i].dns_domain_name);
+ printf("result_name: %s\n",
+ ctr.ctr1->array[i].result_name);
+ }
+
+ out:
+ if (is_valid_policy_hnd(&bind_handle)) {
+ rpccli_drsuapi_DsUnbind(cli, mem_ctx, &bind_handle, &werr);
+ }
+
+ return werr;
+}
+
+static void display_domain_controller_info_01(struct drsuapi_DsGetDCConnection01 *r)
+{
+ printf("client_ip_address:\t%s\n", r->client_ip_address);
+ printf("unknown2:\t%d\n", r->unknown2);
+ printf("connection_time:\t%d\n", r->connection_time);
+ printf("unknown4:\t%d\n", r->unknown4);
+ printf("unknown5:\t%d\n", r->unknown5);
+ printf("unknown6:\t%d\n", r->unknown6);
+ printf("client_account:\t%s\n", r->client_account);
+}
+
+static void display_domain_controller_info_1(struct drsuapi_DsGetDCInfo1 *r)
+{
+ printf("netbios_name:\t%s\n", r->netbios_name);
+ printf("dns_name:\t%s\n", r->dns_name);
+ printf("site_name:\t%s\n", r->site_name);
+ printf("computer_dn:\t%s\n", r->computer_dn);
+ printf("server_dn:\t%s\n", r->server_dn);
+ printf("is_pdc:\t\t%s\n", r->is_pdc ? "true" : "false");
+ printf("is_enabled:\t%s\n", r->is_enabled ? "true" : "false");
+}
+
+static void display_domain_controller_info_2(struct drsuapi_DsGetDCInfo2 *r)
+{
+ printf("netbios_name:\t%s\n", r->netbios_name);
+ printf("dns_name:\t%s\n", r->dns_name);
+ printf("site_name:\t%s\n", r->site_name);
+ printf("site_dn:\t%s\n", r->site_dn);
+ printf("computer_dn:\t%s\n", r->computer_dn);
+ printf("server_dn:\t%s\n", r->server_dn);
+ printf("ntds_dn:\t%s\n", r->ntds_dn);
+ printf("is_pdc:\t\t%s\n", r->is_pdc ? "true" : "false");
+ printf("is_enabled:\t%s\n", r->is_enabled ? "true" : "false");
+ printf("is_gc:\t\t%s\n", r->is_gc ? "true" : "false");
+ printf("site_guid:\t%s\n", GUID_string(talloc_tos(), &r->site_guid));
+ printf("computer_guid:\t%s\n", GUID_string(talloc_tos(), &r->computer_guid));
+ printf("server_guid:\t%s\n", GUID_string(talloc_tos(), &r->server_guid));
+ printf("ntds_guid:\t%s\n", GUID_string(talloc_tos(), &r->ntds_guid));
+}
+
+static void display_domain_controller_info_3(struct drsuapi_DsGetDCInfo3 *r)
+{
+ printf("netbios_name:\t%s\n", r->netbios_name);
+ printf("dns_name:\t%s\n", r->dns_name);
+ printf("site_name:\t%s\n", r->site_name);
+ printf("site_dn:\t%s\n", r->site_dn);
+ printf("computer_dn:\t%s\n", r->computer_dn);
+ printf("server_dn:\t%s\n", r->server_dn);
+ printf("ntds_dn:\t%s\n", r->ntds_dn);
+ printf("is_pdc:\t\t%s\n", r->is_pdc ? "true" : "false");
+ printf("is_enabled:\t%s\n", r->is_enabled ? "true" : "false");
+ printf("is_gc:\t\t%s\n", r->is_gc ? "true" : "false");
+ printf("is_rodc:\t%s\n", r->is_rodc ? "true" : "false");
+ printf("site_guid:\t%s\n", GUID_string(talloc_tos(), &r->site_guid));
+ printf("computer_guid:\t%s\n", GUID_string(talloc_tos(), &r->computer_guid));
+ printf("server_guid:\t%s\n", GUID_string(talloc_tos(), &r->server_guid));
+ printf("ntds_guid:\t%s\n", GUID_string(talloc_tos(), &r->ntds_guid));
+}
+
+static void display_domain_controller_info(int32_t level,
+ union drsuapi_DsGetDCInfoCtr *ctr)
+{
+ int i;
+
+ switch (level) {
+ case DRSUAPI_DC_CONNECTION_CTR_01:
+ for (i=0; i<ctr->ctr01.count; i++) {
+ printf("----------\n");
+ display_domain_controller_info_01(&ctr->ctr01.array[i]);
+ }
+ break;
+ case DRSUAPI_DC_INFO_CTR_1:
+ for (i=0; i<ctr->ctr1.count; i++) {
+ printf("----------\n");
+ display_domain_controller_info_1(&ctr->ctr1.array[i]);
+ }
+ break;
+ case DRSUAPI_DC_INFO_CTR_2:
+ for (i=0; i<ctr->ctr2.count; i++) {
+ printf("----------\n");
+ display_domain_controller_info_2(&ctr->ctr2.array[i]);
+ }
+ break;
+ case DRSUAPI_DC_INFO_CTR_3:
+ for (i=0; i<ctr->ctr3.count; i++) {
+ printf("----------\n");
+ display_domain_controller_info_3(&ctr->ctr3.array[i]);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static WERROR cmd_drsuapi_getdcinfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ WERROR werr;
+
+ struct GUID bind_guid;
+ struct policy_handle bind_handle;
+
+ const char *domain = NULL;
+ int32_t level = 1;
+ int32_t level_out;
+ union drsuapi_DsGetDCInfoRequest req;
+ union drsuapi_DsGetDCInfoCtr ctr;
+
+ if (argc < 2) {
+ printf("usage: %s domain [level]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ domain = argv[1];
+ if (argc >= 3) {
+ level = atoi(argv[2]);
+ }
+
+ GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);
+
+ status = rpccli_drsuapi_DsBind(cli, mem_ctx,
+ &bind_guid,
+ NULL,
+ &bind_handle,
+ &werr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ req.req1.domain_name = domain;
+ req.req1.level = level;
+
+ status = rpccli_drsuapi_DsGetDomainControllerInfo(cli, mem_ctx,
+ &bind_handle,
+ 1,
+ &req,
+ &level_out,
+ &ctr,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto out;
+ }
+
+ if (!W_ERROR_IS_OK(werr)) {
+ goto out;
+ }
+
+ display_domain_controller_info(level_out, &ctr);
+ out:
+ if (is_valid_policy_hnd(&bind_handle)) {
+ rpccli_drsuapi_DsUnbind(cli, mem_ctx, &bind_handle, &werr);
+ }
+
+ return werr;
+}
+
+static WERROR cmd_drsuapi_getncchanges(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ WERROR werr;
+
+ struct policy_handle bind_handle;
+
+ struct GUID bind_guid;
+ struct drsuapi_DsBindInfoCtr bind_info;
+ struct drsuapi_DsBindInfo28 info28;
+
+ const char *nc_dn = NULL;
+
+ DATA_BLOB session_key;
+
+ int32_t level = 8;
+ bool single = false;
+ int32_t level_out = 0;
+ union drsuapi_DsGetNCChangesRequest req;
+ union drsuapi_DsGetNCChangesCtr ctr;
+ struct drsuapi_DsReplicaObjectIdentifier nc;
+ struct dom_sid null_sid;
+
+ struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
+ struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
+ int32_t out_level = 0;
+ int y;
+
+ uint32_t supported_extensions = 0;
+ uint32_t replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE |
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP |
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS |
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS |
+ DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED;
+
+ if (argc > 3) {
+ printf("usage: %s [naming_context_or_object_dn [single]]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 2) {
+ nc_dn = argv[1];
+ }
+
+ if (argc == 3) {
+ if (strequal(argv[2], "single")) {
+ single = true;
+ } else {
+ printf("warning: ignoring unknown argument '%s'\n",
+ argv[2]);
+ }
+ }
+
+ ZERO_STRUCT(info28);
+
+ ZERO_STRUCT(null_sid);
+ ZERO_STRUCT(req);
+
+ GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);
+
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
+ info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
+ info28.site_guid = GUID_zero();
+ info28.pid = 0;
+ info28.repl_epoch = 0;
+
+ bind_info.length = 28;
+ bind_info.info.info28 = info28;
+
+ status = rpccli_drsuapi_DsBind(cli, mem_ctx,
+ &bind_guid,
+ &bind_info,
+ &bind_handle,
+ &werr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ if (bind_info.length == 24) {
+ supported_extensions = bind_info.info.info24.supported_extensions;
+ } else if (bind_info.length == 28) {
+ supported_extensions = bind_info.info.info28.supported_extensions;
+ } else if (bind_info.length == 48) {
+ supported_extensions = bind_info.info.info48.supported_extensions;
+ }
+
+ if (!nc_dn) {
+
+ union drsuapi_DsNameCtr crack_ctr;
+ const char *name;
+
+ name = talloc_asprintf(mem_ctx, "%s\\", lp_workgroup());
+ W_ERROR_HAVE_NO_MEMORY(name);
+
+ werr = cracknames(cli, mem_ctx,
+ &bind_handle,
+ DRSUAPI_DS_NAME_FORMAT_UKNOWN,
+ DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ 1,
+ &name,
+ &crack_ctr);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ if (crack_ctr.ctr1->count != 1) {
+ return WERR_NO_SUCH_DOMAIN;
+ }
+
+ if (crack_ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ return WERR_NO_SUCH_DOMAIN;
+ }
+
+ nc_dn = talloc_strdup(mem_ctx, crack_ctr.ctr1->array[0].result_name);
+ W_ERROR_HAVE_NO_MEMORY(nc_dn);
+
+ printf("using: %s\n", nc_dn);
+ }
+
+ nc.dn = nc_dn;
+ nc.guid = GUID_zero();
+ nc.sid = null_sid;
+
+ if (supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
+ level = 8;
+ req.req8.naming_context = &nc;
+ req.req8.replica_flags = replica_flags;
+ req.req8.max_object_count = 402;
+ req.req8.max_ndr_size = 402116;
+ if (single) {
+ req.req8.extended_op = DRSUAPI_EXOP_REPL_OBJ;
+ }
+ } else {
+ level = 5;
+ req.req5.naming_context = &nc;
+ req.req5.replica_flags = replica_flags;
+ req.req5.max_object_count = 402;
+ req.req5.max_ndr_size = 402116;
+ if (single) {
+ req.req5.extended_op = DRSUAPI_EXOP_REPL_OBJ;
+ }
+ }
+
+ for (y=0; ;y++) {
+
+ if (level == 8) {
+ DEBUG(1,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y,
+ (long long)req.req8.highwatermark.tmp_highest_usn,
+ (long long)req.req8.highwatermark.highest_usn));
+ }
+
+ status = rpccli_drsuapi_DsGetNCChanges(cli, mem_ctx,
+ &bind_handle,
+ level,
+ &req,
+ &level_out,
+ &ctr,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to get NC Changes: %s",
+ get_friendly_werror_msg(werr));
+ goto out;
+ }
+
+ if (!W_ERROR_IS_OK(werr)) {
+ status = werror_to_ntstatus(werr);
+ goto out;
+ }
+
+ if (level_out == 1) {
+ out_level = 1;
+ ctr1 = &ctr.ctr1;
+ } else if (level_out == 2) {
+ out_level = 1;
+ ctr1 = ctr.ctr2.ctr.mszip1.ctr1;
+ }
+
+ status = cli_get_session_key(mem_ctx, cli, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to get Session Key: %s",
+ nt_errstr(status));
+ return ntstatus_to_werror(status);
+ }
+
+ if (out_level == 1) {
+ DEBUG(1,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y,
+ (long long)ctr1->new_highwatermark.tmp_highest_usn,
+ (long long)ctr1->new_highwatermark.highest_usn));
+#if 0
+ libnet_dssync_decrypt_attributes(mem_ctx,
+ &session_key,
+ ctr1->first_object);
+#endif
+ if (ctr1->more_data) {
+ req.req5.highwatermark = ctr1->new_highwatermark;
+ continue;
+ }
+ }
+
+ if (level_out == 6) {
+ out_level = 6;
+ ctr6 = &ctr.ctr6;
+ } else if (level_out == 7
+ && ctr.ctr7.level == 6
+ && ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP) {
+ out_level = 6;
+ ctr6 = ctr.ctr7.ctr.mszip6.ctr6;
+ }
+
+ if (out_level == 6) {
+ DEBUG(1,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y,
+ (long long)ctr6->new_highwatermark.tmp_highest_usn,
+ (long long)ctr6->new_highwatermark.highest_usn));
+#if 0
+ libnet_dssync_decrypt_attributes(mem_ctx,
+ &session_key,
+ ctr6->first_object);
+#endif
+ if (ctr6->more_data) {
+ req.req8.highwatermark = ctr6->new_highwatermark;
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ out:
+ return werr;
+}
+
+/* List of commands exported by this module */
+
+struct cmd_set drsuapi_commands[] = {
+
+ { "DRSUAPI" },
+ { "dscracknames", RPC_RTYPE_WERROR, NULL, cmd_drsuapi_cracknames, &ndr_table_drsuapi.syntax_id, NULL, "Crack Name", "" },
+ { "dsgetdcinfo", RPC_RTYPE_WERROR, NULL, cmd_drsuapi_getdcinfo, &ndr_table_drsuapi.syntax_id, NULL, "Get Domain Controller Info", "" },
+ { "dsgetncchanges", RPC_RTYPE_WERROR, NULL, cmd_drsuapi_getncchanges, &ndr_table_drsuapi.syntax_id, NULL, "Get NC Changes", "" },
+ { NULL }
+};
diff --git a/source3/rpcclient/cmd_dssetup.c b/source3/rpcclient/cmd_dssetup.c
new file mode 100644
index 0000000000..f2fd124967
--- /dev/null
+++ b/source3/rpcclient/cmd_dssetup.c
@@ -0,0 +1,69 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Gerald Carter 2002
+ Copyright (C) Guenther Deschner 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+/* Look up domain related information on a remote host */
+
+static WERROR cmd_ds_dsrole_getprimarydominfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ WERROR werr;
+ union dssetup_DsRoleInfo info;
+
+ status = rpccli_dssetup_DsRoleGetPrimaryDomainInformation(cli, mem_ctx,
+ DS_ROLE_BASIC_INFORMATION,
+ &info,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ printf ("Machine Role = [%d]\n", info.basic.role);
+
+ if (info.basic.flags & DS_ROLE_PRIMARY_DS_RUNNING) {
+ printf("Directory Service is running.\n");
+ printf("Domain is in %s mode.\n",
+ (info.basic.flags & DS_ROLE_PRIMARY_DS_MIXED_MODE) ? "mixed" : "native" );
+ } else {
+ printf("Directory Service not running on server\n");
+ }
+
+ return werr;
+}
+
+/* List of commands exported by this module */
+
+struct cmd_set ds_commands[] = {
+
+ { "LSARPC-DS" },
+
+ { "dsroledominfo", RPC_RTYPE_WERROR, NULL, cmd_ds_dsrole_getprimarydominfo, &ndr_table_dssetup.syntax_id, NULL, "Get Primary Domain Information", "" },
+
+{ NULL }
+};
diff --git a/source3/rpcclient/cmd_echo.c b/source3/rpcclient/cmd_echo.c
new file mode 100644
index 0000000000..d90ef3499f
--- /dev/null
+++ b/source3/rpcclient/cmd_echo.c
@@ -0,0 +1,184 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Tim Potter 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+static NTSTATUS cmd_echo_add_one(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ uint32 request = 1, response;
+ NTSTATUS result;
+
+ if (argc > 2) {
+ printf("Usage: %s [num]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2)
+ request = atoi(argv[1]);
+
+ result = rpccli_echo_AddOne(cli, mem_ctx, request, &response);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ printf("%d + 1 = %d\n", request, response);
+
+done:
+ return result;
+}
+
+static NTSTATUS cmd_echo_data(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ uint32 size, i;
+ NTSTATUS result;
+ uint8_t *in_data = NULL, *out_data = NULL;
+
+ if (argc != 2) {
+ printf("Usage: %s num\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ size = atoi(argv[1]);
+ if ( (in_data = (uint8_t*)SMB_MALLOC(size)) == NULL ) {
+ printf("Failure to allocate buff of %d bytes\n",
+ size);
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ if ( (out_data = (uint8_t*)SMB_MALLOC(size)) == NULL ) {
+ printf("Failure to allocate buff of %d bytes\n",
+ size);
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i = 0; i < size; i++)
+ in_data[i] = i & 0xff;
+
+ result = rpccli_echo_EchoData(cli, mem_ctx, size, in_data, out_data);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ for (i = 0; i < size; i++) {
+ if (in_data[i] != out_data[i]) {
+ printf("mismatch at offset %d, %d != %d\n",
+ i, in_data[i], out_data[i]);
+ result = NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+done:
+ SAFE_FREE(in_data);
+ SAFE_FREE(out_data);
+
+ return result;
+}
+
+static NTSTATUS cmd_echo_source_data(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ uint32 size, i;
+ NTSTATUS result;
+ uint8_t *out_data = NULL;
+
+ if (argc != 2) {
+ printf("Usage: %s num\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ size = atoi(argv[1]);
+ if ( (out_data = (uint8_t*)SMB_MALLOC(size)) == NULL ) {
+ printf("Failure to allocate buff of %d bytes\n",
+ size);
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+
+ result = rpccli_echo_SourceData(cli, mem_ctx, size, out_data);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ for (i = 0; i < size; i++) {
+ if (out_data && out_data[i] != (i & 0xff)) {
+ printf("mismatch at offset %d, %d != %d\n",
+ i, out_data[i], i & 0xff);
+ result = NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+done:
+
+ SAFE_FREE(out_data);
+ return result;
+}
+
+static NTSTATUS cmd_echo_sink_data(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ uint32 size, i;
+ NTSTATUS result;
+ uint8_t *in_data = NULL;
+
+ if (argc != 2) {
+ printf("Usage: %s num\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ size = atoi(argv[1]);
+ if ( (in_data = (uint8_t*)SMB_MALLOC(size)) == NULL ) {
+ printf("Failure to allocate buff of %d bytes\n",
+ size);
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i = 0; i < size; i++)
+ in_data[i] = i & 0xff;
+
+ result = rpccli_echo_SinkData(cli, mem_ctx, size, in_data);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+done:
+ SAFE_FREE(in_data);
+
+ return result;
+}
+
+/* List of commands exported by this module */
+
+struct cmd_set echo_commands[] = {
+
+ { "ECHO" },
+
+ { "echoaddone", RPC_RTYPE_NTSTATUS, cmd_echo_add_one, NULL, &ndr_table_rpcecho.syntax_id, NULL, "Add one to a number", "" },
+ { "echodata", RPC_RTYPE_NTSTATUS, cmd_echo_data, NULL, &ndr_table_rpcecho.syntax_id, NULL, "Echo data", "" },
+ { "sinkdata", RPC_RTYPE_NTSTATUS, cmd_echo_sink_data, NULL, &ndr_table_rpcecho.syntax_id, NULL, "Sink data", "" },
+ { "sourcedata", RPC_RTYPE_NTSTATUS, cmd_echo_source_data, NULL, &ndr_table_rpcecho.syntax_id, NULL, "Source data", "" },
+ { NULL }
+};
diff --git a/source3/rpcclient/cmd_lsarpc.c b/source3/rpcclient/cmd_lsarpc.c
new file mode 100644
index 0000000000..5b5b4ff78c
--- /dev/null
+++ b/source3/rpcclient/cmd_lsarpc.c
@@ -0,0 +1,1395 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Rafal Szczesniak 2002
+ Copyright (C) Guenther Deschner 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+/* useful function to allow entering a name instead of a SID and
+ * looking it up automatically */
+static NTSTATUS name_to_sid(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ DOM_SID *sid, const char *name)
+{
+ POLICY_HND pol;
+ enum lsa_SidType *sid_types;
+ NTSTATUS result;
+ DOM_SID *sids;
+
+ /* maybe its a raw SID */
+ if (strncmp(name, "S-", 2) == 0 &&
+ string_to_sid(sid, name)) {
+ return NT_STATUS_OK;
+ }
+
+ result = rpccli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_lookup_names(cli, mem_ctx, &pol, 1, &name, NULL, 1, &sids, &sid_types);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ rpccli_lsa_Close(cli, mem_ctx, &pol);
+
+ *sid = sids[0];
+
+done:
+ return result;
+}
+
+static void display_query_info_1(struct lsa_AuditLogInfo *r)
+{
+ d_printf("percent_full:\t%d\n", r->percent_full);
+ d_printf("log_size:\t%d\n", r->log_size);
+ d_printf("retention_time:\t%lld\n", (long long)r->retention_time);
+ d_printf("shutdown_in_progress:\t%d\n", r->shutdown_in_progress);
+ d_printf("time_to_shutdown:\t%lld\n", (long long)r->time_to_shutdown);
+ d_printf("next_audit_record:\t%d\n", r->next_audit_record);
+ d_printf("unknown:\t%d\n", r->unknown);
+}
+
+static void display_query_info_2(struct lsa_AuditEventsInfo *r)
+{
+ int i;
+ d_printf("Auditing enabled:\t%d\n", r->auditing_mode);
+ d_printf("Auditing categories:\t%d\n", r->count);
+ d_printf("Auditsettings:\n");
+ for (i=0; i<r->count; i++) {
+ const char *val = audit_policy_str(talloc_tos(), r->settings[i]);
+ const char *policy = audit_description_str(i);
+ d_printf("%s:\t%s\n", policy, val);
+ }
+}
+
+static void display_query_info_3(struct lsa_DomainInfo *r)
+{
+ d_printf("Domain Name: %s\n", r->name.string);
+ d_printf("Domain Sid: %s\n", sid_string_tos(r->sid));
+}
+
+static void display_query_info_5(struct lsa_DomainInfo *r)
+{
+ d_printf("Domain Name: %s\n", r->name.string);
+ d_printf("Domain Sid: %s\n", sid_string_tos(r->sid));
+}
+
+static void display_query_info_10(struct lsa_AuditFullSetInfo *r)
+{
+ d_printf("Shutdown on full: %d\n", r->shutdown_on_full);
+}
+
+static void display_query_info_11(struct lsa_AuditFullQueryInfo *r)
+{
+ d_printf("Shutdown on full: %d\n", r->shutdown_on_full);
+ d_printf("Log is full: %d\n", r->log_is_full);
+ d_printf("Unknown: %d\n", r->unknown);
+}
+
+static void display_query_info_12(struct lsa_DnsDomainInfo *r)
+{
+ d_printf("Domain NetBios Name: %s\n", r->name.string);
+ d_printf("Domain DNS Name: %s\n", r->dns_domain.string);
+ d_printf("Domain Forest Name: %s\n", r->dns_forest.string);
+ d_printf("Domain Sid: %s\n", sid_string_tos(r->sid));
+ d_printf("Domain GUID: %s\n", smb_uuid_string(talloc_tos(),
+ r->domain_guid));
+}
+
+static void display_lsa_query_info(union lsa_PolicyInformation *info,
+ enum lsa_PolicyInfo level)
+{
+ switch (level) {
+ case 1:
+ display_query_info_1(&info->audit_log);
+ break;
+ case 2:
+ display_query_info_2(&info->audit_events);
+ break;
+ case 3:
+ display_query_info_3(&info->domain);
+ break;
+ case 5:
+ display_query_info_5(&info->account_domain);
+ break;
+ case 10:
+ display_query_info_10(&info->auditfullset);
+ break;
+ case 11:
+ display_query_info_11(&info->auditfullquery);
+ break;
+ case 12:
+ display_query_info_12(&info->dns);
+ break;
+ default:
+ printf("can't display info level: %d\n", level);
+ break;
+ }
+}
+
+static NTSTATUS cmd_lsa_query_info_policy(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ union lsa_PolicyInformation *info = NULL;
+
+ uint32 info_class = 3;
+
+ if (argc > 2) {
+ printf("Usage: %s [info_class]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2)
+ info_class = atoi(argv[1]);
+
+ switch (info_class) {
+ case 12:
+ result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_QueryInfoPolicy2(cli, mem_ctx,
+ &pol,
+ info_class,
+ &info);
+ break;
+ default:
+ result = rpccli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_QueryInfoPolicy(cli, mem_ctx,
+ &pol,
+ info_class,
+ &info);
+ }
+
+ if (NT_STATUS_IS_OK(result)) {
+ display_lsa_query_info(info, info_class);
+ }
+
+ rpccli_lsa_Close(cli, mem_ctx, &pol);
+
+ done:
+ return result;
+}
+
+/* Resolve a list of names to a list of sids */
+
+static NTSTATUS cmd_lsa_lookup_names(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_SID *sids;
+ enum lsa_SidType *types;
+ int i;
+
+ if (argc == 1) {
+ printf("Usage: %s [name1 [name2 [...]]]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = rpccli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_lookup_names(cli, mem_ctx, &pol, argc - 1,
+ (const char**)(argv + 1), NULL, 1, &sids, &types);
+
+ if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) !=
+ NT_STATUS_V(STATUS_SOME_UNMAPPED))
+ goto done;
+
+ result = NT_STATUS_OK;
+
+ /* Print results */
+
+ for (i = 0; i < (argc - 1); i++) {
+ fstring sid_str;
+ sid_to_fstring(sid_str, &sids[i]);
+ printf("%s %s (%s: %d)\n", argv[i + 1], sid_str,
+ sid_type_lookup(types[i]), types[i]);
+ }
+
+ rpccli_lsa_Close(cli, mem_ctx, &pol);
+
+ done:
+ return result;
+}
+
+/* Resolve a list of names to a list of sids */
+
+static NTSTATUS cmd_lsa_lookup_names_level(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_SID *sids;
+ enum lsa_SidType *types;
+ int i, level;
+
+ if (argc < 3) {
+ printf("Usage: %s [level] [name1 [name2 [...]]]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = rpccli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ level = atoi(argv[1]);
+
+ result = rpccli_lsa_lookup_names(cli, mem_ctx, &pol, argc - 2,
+ (const char**)(argv + 2), NULL, level, &sids, &types);
+
+ if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) !=
+ NT_STATUS_V(STATUS_SOME_UNMAPPED))
+ goto done;
+
+ result = NT_STATUS_OK;
+
+ /* Print results */
+
+ for (i = 0; i < (argc - 2); i++) {
+ fstring sid_str;
+ sid_to_fstring(sid_str, &sids[i]);
+ printf("%s %s (%s: %d)\n", argv[i + 2], sid_str,
+ sid_type_lookup(types[i]), types[i]);
+ }
+
+ rpccli_lsa_Close(cli, mem_ctx, &pol);
+
+ done:
+ return result;
+}
+
+
+/* Resolve a list of SIDs to a list of names */
+
+static NTSTATUS cmd_lsa_lookup_sids(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_SID *sids;
+ char **domains;
+ char **names;
+ enum lsa_SidType *types;
+ int i;
+
+ if (argc == 1) {
+ printf("Usage: %s [sid1 [sid2 [...]]]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = rpccli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Convert arguments to sids */
+
+ sids = TALLOC_ARRAY(mem_ctx, DOM_SID, argc - 1);
+
+ if (!sids) {
+ printf("could not allocate memory for %d sids\n", argc - 1);
+ goto done;
+ }
+
+ for (i = 0; i < argc - 1; i++)
+ if (!string_to_sid(&sids[i], argv[i + 1])) {
+ result = NT_STATUS_INVALID_SID;
+ goto done;
+ }
+
+ /* Lookup the SIDs */
+
+ result = rpccli_lsa_lookup_sids(cli, mem_ctx, &pol, argc - 1, sids,
+ &domains, &names, &types);
+
+ if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) !=
+ NT_STATUS_V(STATUS_SOME_UNMAPPED))
+ goto done;
+
+ result = NT_STATUS_OK;
+
+ /* Print results */
+
+ for (i = 0; i < (argc - 1); i++) {
+ fstring sid_str;
+
+ sid_to_fstring(sid_str, &sids[i]);
+ printf("%s %s\\%s (%d)\n", sid_str,
+ domains[i] ? domains[i] : "*unknown*",
+ names[i] ? names[i] : "*unknown*", types[i]);
+ }
+
+ rpccli_lsa_Close(cli, mem_ctx, &pol);
+
+ done:
+ return result;
+}
+
+/* Enumerate list of trusted domains */
+
+static NTSTATUS cmd_lsa_enum_trust_dom(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct lsa_DomainList domain_list;
+
+ /* defaults, but may be changed using params */
+ uint32 enum_ctx = 0;
+ int i;
+ uint32_t max_size = (uint32_t)-1;
+
+ if (argc > 2) {
+ printf("Usage: %s [enum context (0)]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2 && argv[1]) {
+ enum_ctx = atoi(argv[2]);
+ }
+
+ result = rpccli_lsa_open_policy(cli, mem_ctx, True,
+ LSA_POLICY_VIEW_LOCAL_INFORMATION,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = STATUS_MORE_ENTRIES;
+
+ while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) {
+
+ /* Lookup list of trusted domains */
+
+ result = rpccli_lsa_EnumTrustDom(cli, mem_ctx,
+ &pol,
+ &enum_ctx,
+ &domain_list,
+ max_size);
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, NT_STATUS_NO_MORE_ENTRIES) &&
+ !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
+ goto done;
+
+ /* Print results: list of names and sids returned in this
+ * response. */
+ for (i = 0; i < domain_list.count; i++) {
+ fstring sid_str;
+
+ sid_to_fstring(sid_str, domain_list.domains[i].sid);
+ printf("%s %s\n",
+ domain_list.domains[i].name.string ?
+ domain_list.domains[i].name.string : "*unknown*",
+ sid_str);
+ }
+ }
+
+ rpccli_lsa_Close(cli, mem_ctx, &pol);
+ done:
+ return result;
+}
+
+/* Enumerates privileges */
+
+static NTSTATUS cmd_lsa_enum_privilege(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct lsa_PrivArray priv_array;
+
+ uint32 enum_context=0;
+ uint32 pref_max_length=0x1000;
+ int i;
+
+ if (argc > 3) {
+ printf("Usage: %s [enum context] [max length]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc>=2)
+ enum_context=atoi(argv[1]);
+
+ if (argc==3)
+ pref_max_length=atoi(argv[2]);
+
+ result = rpccli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_EnumPrivs(cli, mem_ctx,
+ &pol,
+ &enum_context,
+ &priv_array,
+ pref_max_length);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Print results */
+ printf("found %d privileges\n\n", priv_array.count);
+
+ for (i = 0; i < priv_array.count; i++) {
+ printf("%s \t\t%d:%d (0x%x:0x%x)\n",
+ priv_array.privs[i].name.string ? priv_array.privs[i].name.string : "*unknown*",
+ priv_array.privs[i].luid.high,
+ priv_array.privs[i].luid.low,
+ priv_array.privs[i].luid.high,
+ priv_array.privs[i].luid.low);
+ }
+
+ rpccli_lsa_Close(cli, mem_ctx, &pol);
+ done:
+ return result;
+}
+
+/* Get privilege name */
+
+static NTSTATUS cmd_lsa_get_dispname(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ uint16 lang_id=0;
+ uint16 lang_id_sys=0;
+ uint16 lang_id_desc;
+ struct lsa_String lsa_name;
+ struct lsa_StringLarge *description = NULL;
+
+ if (argc != 2) {
+ printf("Usage: %s privilege name\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = rpccli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ init_lsa_String(&lsa_name, argv[1]);
+
+ result = rpccli_lsa_LookupPrivDisplayName(cli, mem_ctx,
+ &pol,
+ &lsa_name,
+ lang_id,
+ lang_id_sys,
+ &description,
+ &lang_id_desc);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Print results */
+ printf("%s -> %s (language: 0x%x)\n", argv[1], description->string, lang_id_desc);
+
+ rpccli_lsa_Close(cli, mem_ctx, &pol);
+ done:
+ return result;
+}
+
+/* Enumerate the LSA SIDS */
+
+static NTSTATUS cmd_lsa_enum_sids(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ uint32 enum_context=0;
+ uint32 pref_max_length=0x1000;
+ struct lsa_SidArray sid_array;
+ int i;
+
+ if (argc > 3) {
+ printf("Usage: %s [enum context] [max length]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc>=2)
+ enum_context=atoi(argv[1]);
+
+ if (argc==3)
+ pref_max_length=atoi(argv[2]);
+
+ result = rpccli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_EnumAccounts(cli, mem_ctx,
+ &pol,
+ &enum_context,
+ &sid_array,
+ pref_max_length);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Print results */
+ printf("found %d SIDs\n\n", sid_array.num_sids);
+
+ for (i = 0; i < sid_array.num_sids; i++) {
+ fstring sid_str;
+
+ sid_to_fstring(sid_str, sid_array.sids[i].sid);
+ printf("%s\n", sid_str);
+ }
+
+ rpccli_lsa_Close(cli, mem_ctx, &pol);
+ done:
+ return result;
+}
+
+/* Create a new account */
+
+static NTSTATUS cmd_lsa_create_account(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND dom_pol;
+ POLICY_HND user_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 des_access = 0x000f000f;
+
+ DOM_SID sid;
+
+ if (argc != 2 ) {
+ printf("Usage: %s SID\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = name_to_sid(cli, mem_ctx, &sid, argv[1]);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &dom_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_CreateAccount(cli, mem_ctx,
+ &dom_pol,
+ &sid,
+ des_access,
+ &user_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ printf("Account for SID %s successfully created\n\n", argv[1]);
+ result = NT_STATUS_OK;
+
+ rpccli_lsa_Close(cli, mem_ctx, &dom_pol);
+ done:
+ return result;
+}
+
+
+/* Enumerate the privileges of an SID */
+
+static NTSTATUS cmd_lsa_enum_privsaccounts(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND dom_pol;
+ POLICY_HND user_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 access_desired = 0x000f000f;
+ DOM_SID sid;
+ struct lsa_PrivilegeSet *privs = NULL;
+ int i;
+
+ if (argc != 2 ) {
+ printf("Usage: %s SID\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = name_to_sid(cli, mem_ctx, &sid, argv[1]);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &dom_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_OpenAccount(cli, mem_ctx,
+ &dom_pol,
+ &sid,
+ access_desired,
+ &user_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_EnumPrivsAccount(cli, mem_ctx,
+ &user_pol,
+ &privs);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Print results */
+ printf("found %d privileges for SID %s\n\n", privs->count, argv[1]);
+ printf("high\tlow\tattribute\n");
+
+ for (i = 0; i < privs->count; i++) {
+ printf("%u\t%u\t%u\n",
+ privs->set[i].luid.high,
+ privs->set[i].luid.low,
+ privs->set[i].attribute);
+ }
+
+ rpccli_lsa_Close(cli, mem_ctx, &dom_pol);
+ done:
+ return result;
+}
+
+
+/* Enumerate the privileges of an SID via LsaEnumerateAccountRights */
+
+static NTSTATUS cmd_lsa_enum_acct_rights(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND dom_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_SID sid;
+ struct lsa_RightSet rights;
+
+ int i;
+
+ if (argc != 2 ) {
+ printf("Usage: %s SID\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = name_to_sid(cli, mem_ctx, &sid, argv[1]);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &dom_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_EnumAccountRights(cli, mem_ctx,
+ &dom_pol,
+ &sid,
+ &rights);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ printf("found %d privileges for SID %s\n", rights.count,
+ sid_string_tos(&sid));
+
+ for (i = 0; i < rights.count; i++) {
+ printf("\t%s\n", rights.names[i].string);
+ }
+
+ rpccli_lsa_Close(cli, mem_ctx, &dom_pol);
+ done:
+ return result;
+}
+
+
+/* add some privileges to a SID via LsaAddAccountRights */
+
+static NTSTATUS cmd_lsa_add_acct_rights(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND dom_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct lsa_RightSet rights;
+ DOM_SID sid;
+ int i;
+
+ if (argc < 3 ) {
+ printf("Usage: %s SID [rights...]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = name_to_sid(cli, mem_ctx, &sid, argv[1]);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &dom_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ rights.count = argc-2;
+ rights.names = TALLOC_ARRAY(mem_ctx, struct lsa_StringLarge,
+ rights.count);
+ if (!rights.names) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<argc-1; i++) {
+ init_lsa_StringLarge(&rights.names[i], argv[i+2]);
+ }
+
+ result = rpccli_lsa_AddAccountRights(cli, mem_ctx,
+ &dom_pol,
+ &sid,
+ &rights);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ rpccli_lsa_Close(cli, mem_ctx, &dom_pol);
+ done:
+ return result;
+}
+
+
+/* remove some privileges to a SID via LsaRemoveAccountRights */
+
+static NTSTATUS cmd_lsa_remove_acct_rights(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND dom_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct lsa_RightSet rights;
+ DOM_SID sid;
+ int i;
+
+ if (argc < 3 ) {
+ printf("Usage: %s SID [rights...]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = name_to_sid(cli, mem_ctx, &sid, argv[1]);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &dom_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ rights.count = argc-2;
+ rights.names = TALLOC_ARRAY(mem_ctx, struct lsa_StringLarge,
+ rights.count);
+ if (!rights.names) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<argc-2; i++) {
+ init_lsa_StringLarge(&rights.names[i], argv[i+2]);
+ }
+
+ result = rpccli_lsa_RemoveAccountRights(cli, mem_ctx,
+ &dom_pol,
+ &sid,
+ false,
+ &rights);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ rpccli_lsa_Close(cli, mem_ctx, &dom_pol);
+
+ done:
+ return result;
+}
+
+
+/* Get a privilege value given its name */
+
+static NTSTATUS cmd_lsa_lookup_priv_value(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct lsa_LUID luid;
+ struct lsa_String name;
+
+ if (argc != 2 ) {
+ printf("Usage: %s name\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ init_lsa_String(&name, argv[1]);
+
+ result = rpccli_lsa_LookupPrivValue(cli, mem_ctx,
+ &pol,
+ &name,
+ &luid);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Print results */
+
+ printf("%u:%u (0x%x:0x%x)\n", luid.high, luid.low, luid.high, luid.low);
+
+ rpccli_lsa_Close(cli, mem_ctx, &pol);
+ done:
+ return result;
+}
+
+/* Query LSA security object */
+
+static NTSTATUS cmd_lsa_query_secobj(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ SEC_DESC_BUF *sdb;
+ uint32 sec_info = DACL_SECURITY_INFORMATION;
+
+ if (argc < 1 || argc > 2) {
+ printf("Usage: %s [sec_info]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (argc == 2)
+ sscanf(argv[1], "%x", &sec_info);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_QuerySecurity(cli, mem_ctx,
+ &pol,
+ sec_info,
+ &sdb);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Print results */
+
+ display_sec_desc(sdb->sd);
+
+ rpccli_lsa_Close(cli, mem_ctx, &pol);
+ done:
+ return result;
+}
+
+static void display_trust_dom_info_4(struct lsa_TrustDomainInfoPassword *p,
+ uint8_t nt_hash[16])
+{
+ char *pwd, *pwd_old;
+
+ DATA_BLOB data = data_blob(NULL, p->password->length);
+ DATA_BLOB data_old = data_blob(NULL, p->old_password->length);
+
+ memcpy(data.data, p->password->data, p->password->length);
+ memcpy(data_old.data, p->old_password->data, p->old_password->length);
+
+ pwd = decrypt_trustdom_secret(nt_hash, &data);
+ pwd_old = decrypt_trustdom_secret(nt_hash, &data_old);
+
+ d_printf("Password:\t%s\n", pwd);
+ d_printf("Old Password:\t%s\n", pwd_old);
+
+ SAFE_FREE(pwd);
+ SAFE_FREE(pwd_old);
+
+ data_blob_free(&data);
+ data_blob_free(&data_old);
+}
+
+static void display_trust_dom_info(TALLOC_CTX *mem_ctx,
+ union lsa_TrustedDomainInfo *info,
+ enum lsa_TrustDomInfoEnum info_class,
+ uint8_t nt_hash[16])
+{
+ switch (info_class) {
+ case LSA_TRUSTED_DOMAIN_INFO_PASSWORD:
+ display_trust_dom_info_4(&info->password, nt_hash);
+ break;
+ default: {
+ const char *str = NULL;
+ str = NDR_PRINT_UNION_STRING(mem_ctx,
+ lsa_TrustedDomainInfo,
+ info_class, info);
+ if (str) {
+ d_printf("%s\n", str);
+ }
+ break;
+ }
+ }
+}
+
+static NTSTATUS cmd_lsa_query_trustdominfobysid(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_SID dom_sid;
+ uint32 access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
+ union lsa_TrustedDomainInfo *info = NULL;
+ enum lsa_TrustDomInfoEnum info_class = 1;
+ uint8_t nt_hash[16];
+
+ if (argc > 3 || argc < 2) {
+ printf("Usage: %s [sid] [info_class]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (!string_to_sid(&dom_sid, argv[1]))
+ return NT_STATUS_NO_MEMORY;
+
+ if (argc == 3)
+ info_class = atoi(argv[2]);
+
+ result = rpccli_lsa_open_policy2(cli, mem_ctx, True, access_mask, &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_QueryTrustedDomainInfoBySid(cli, mem_ctx,
+ &pol,
+ &dom_sid,
+ info_class,
+ &info);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ if (!rpccli_get_pwd_hash(cli, nt_hash)) {
+ d_fprintf(stderr, "Could not get pwd hash\n");
+ goto done;
+ }
+
+ display_trust_dom_info(mem_ctx, info, info_class, nt_hash);
+
+ done:
+ rpccli_lsa_Close(cli, mem_ctx, &pol);
+
+ return result;
+}
+
+static NTSTATUS cmd_lsa_query_trustdominfobyname(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
+ union lsa_TrustedDomainInfo *info = NULL;
+ enum lsa_TrustDomInfoEnum info_class = 1;
+ struct lsa_String trusted_domain;
+ uint8_t nt_hash[16];
+
+ if (argc > 3 || argc < 2) {
+ printf("Usage: %s [name] [info_class]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 3)
+ info_class = atoi(argv[2]);
+
+ result = rpccli_lsa_open_policy2(cli, mem_ctx, True, access_mask, &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ init_lsa_String(&trusted_domain, argv[1]);
+
+ result = rpccli_lsa_QueryTrustedDomainInfoByName(cli, mem_ctx,
+ &pol,
+ &trusted_domain,
+ info_class,
+ &info);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ if (!rpccli_get_pwd_hash(cli, nt_hash)) {
+ d_fprintf(stderr, "Could not get pwd hash\n");
+ goto done;
+ }
+
+ display_trust_dom_info(mem_ctx, info, info_class, nt_hash);
+
+ done:
+ rpccli_lsa_Close(cli, mem_ctx, &pol);
+
+ return result;
+}
+
+static NTSTATUS cmd_lsa_query_trustdominfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND pol, trustdom_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
+ union lsa_TrustedDomainInfo *info = NULL;
+ DOM_SID dom_sid;
+ enum lsa_TrustDomInfoEnum info_class = 1;
+ uint8_t nt_hash[16];
+
+ if (argc > 3 || argc < 2) {
+ printf("Usage: %s [sid] [info_class]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (!string_to_sid(&dom_sid, argv[1]))
+ return NT_STATUS_NO_MEMORY;
+
+
+ if (argc == 3)
+ info_class = atoi(argv[2]);
+
+ result = rpccli_lsa_open_policy2(cli, mem_ctx, True, access_mask, &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_OpenTrustedDomain(cli, mem_ctx,
+ &pol,
+ &dom_sid,
+ access_mask,
+ &trustdom_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_lsa_QueryTrustedDomainInfo(cli, mem_ctx,
+ &trustdom_pol,
+ info_class,
+ &info);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ if (!rpccli_get_pwd_hash(cli, nt_hash)) {
+ d_fprintf(stderr, "Could not get pwd hash\n");
+ goto done;
+ }
+
+ display_trust_dom_info(mem_ctx, info, info_class, nt_hash);
+
+ done:
+ rpccli_lsa_Close(cli, mem_ctx, &pol);
+
+ return result;
+}
+
+static NTSTATUS cmd_lsa_get_username(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ const char *servername = cli->desthost;
+ struct lsa_String *account_name = NULL;
+ struct lsa_String *authority_name = NULL;
+
+ if (argc > 2) {
+ printf("Usage: %s servername\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = rpccli_lsa_open_policy(cli, mem_ctx, true,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_lsa_GetUserName(cli, mem_ctx,
+ servername,
+ &account_name,
+ &authority_name);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Print results */
+
+ printf("Account Name: %s, Authority Name: %s\n",
+ account_name->string, authority_name->string);
+
+ rpccli_lsa_Close(cli, mem_ctx, &pol);
+ done:
+ return result;
+}
+
+static NTSTATUS cmd_lsa_add_priv(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND dom_pol, user_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct lsa_PrivilegeSet privs;
+ struct lsa_LUIDAttribute *set = NULL;
+ DOM_SID sid;
+ int i;
+
+ ZERO_STRUCT(privs);
+
+ if (argc < 3 ) {
+ printf("Usage: %s SID [rights...]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = name_to_sid(cli, mem_ctx, &sid, argv[1]);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &dom_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_lsa_OpenAccount(cli, mem_ctx,
+ &dom_pol,
+ &sid,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &user_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ for (i=2; i<argc; i++) {
+
+ struct lsa_String priv_name;
+ struct lsa_LUID luid;
+
+ init_lsa_String(&priv_name, argv[i]);
+
+ result = rpccli_lsa_LookupPrivValue(cli, mem_ctx,
+ &dom_pol,
+ &priv_name,
+ &luid);
+ if (!NT_STATUS_IS_OK(result)) {
+ continue;
+ }
+
+ privs.count++;
+ set = TALLOC_REALLOC_ARRAY(mem_ctx, set,
+ struct lsa_LUIDAttribute,
+ privs.count);
+ if (!set) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ set[privs.count-1].luid = luid;
+ set[privs.count-1].attribute = 0;
+ }
+
+ privs.set = set;
+
+ result = rpccli_lsa_AddPrivilegesToAccount(cli, mem_ctx,
+ &user_pol,
+ &privs);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ rpccli_lsa_Close(cli, mem_ctx, &user_pol);
+ rpccli_lsa_Close(cli, mem_ctx, &dom_pol);
+ done:
+ return result;
+}
+
+static NTSTATUS cmd_lsa_del_priv(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND dom_pol, user_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct lsa_PrivilegeSet privs;
+ struct lsa_LUIDAttribute *set = NULL;
+ DOM_SID sid;
+ int i;
+
+ ZERO_STRUCT(privs);
+
+ if (argc < 3 ) {
+ printf("Usage: %s SID [rights...]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = name_to_sid(cli, mem_ctx, &sid, argv[1]);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &dom_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_lsa_OpenAccount(cli, mem_ctx,
+ &dom_pol,
+ &sid,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &user_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ for (i=2; i<argc; i++) {
+
+ struct lsa_String priv_name;
+ struct lsa_LUID luid;
+
+ init_lsa_String(&priv_name, argv[i]);
+
+ result = rpccli_lsa_LookupPrivValue(cli, mem_ctx,
+ &dom_pol,
+ &priv_name,
+ &luid);
+ if (!NT_STATUS_IS_OK(result)) {
+ continue;
+ }
+
+ privs.count++;
+ set = TALLOC_REALLOC_ARRAY(mem_ctx, set,
+ struct lsa_LUIDAttribute,
+ privs.count);
+ if (!set) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ set[privs.count-1].luid = luid;
+ set[privs.count-1].attribute = 0;
+ }
+
+ privs.set = set;
+
+
+ result = rpccli_lsa_RemovePrivilegesFromAccount(cli, mem_ctx,
+ &user_pol,
+ false,
+ &privs);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ rpccli_lsa_Close(cli, mem_ctx, &user_pol);
+ rpccli_lsa_Close(cli, mem_ctx, &dom_pol);
+ done:
+ return result;
+}
+
+
+/* List of commands exported by this module */
+
+struct cmd_set lsarpc_commands[] = {
+
+ { "LSARPC" },
+
+ { "lsaquery", RPC_RTYPE_NTSTATUS, cmd_lsa_query_info_policy, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Query info policy", "" },
+ { "lookupsids", RPC_RTYPE_NTSTATUS, cmd_lsa_lookup_sids, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Convert SIDs to names", "" },
+ { "lookupnames", RPC_RTYPE_NTSTATUS, cmd_lsa_lookup_names, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Convert names to SIDs", "" },
+ { "lookupnames_level", RPC_RTYPE_NTSTATUS, cmd_lsa_lookup_names_level, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Convert names to SIDs", "" },
+ { "enumtrust", RPC_RTYPE_NTSTATUS, cmd_lsa_enum_trust_dom, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Enumerate trusted domains", "Usage: [preferred max number] [enum context (0)]" },
+ { "enumprivs", RPC_RTYPE_NTSTATUS, cmd_lsa_enum_privilege, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Enumerate privileges", "" },
+ { "getdispname", RPC_RTYPE_NTSTATUS, cmd_lsa_get_dispname, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Get the privilege name", "" },
+ { "lsaenumsid", RPC_RTYPE_NTSTATUS, cmd_lsa_enum_sids, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Enumerate the LSA SIDS", "" },
+ { "lsacreateaccount", RPC_RTYPE_NTSTATUS, cmd_lsa_create_account, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Create a new lsa account", "" },
+ { "lsaenumprivsaccount", RPC_RTYPE_NTSTATUS, cmd_lsa_enum_privsaccounts, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Enumerate the privileges of an SID", "" },
+ { "lsaenumacctrights", RPC_RTYPE_NTSTATUS, cmd_lsa_enum_acct_rights, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Enumerate the rights of an SID", "" },
+ { "lsaaddpriv", RPC_RTYPE_NTSTATUS, cmd_lsa_add_priv, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Assign a privilege to a SID", "" },
+ { "lsadelpriv", RPC_RTYPE_NTSTATUS, cmd_lsa_del_priv, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Revoke a privilege from a SID", "" },
+ { "lsaaddacctrights", RPC_RTYPE_NTSTATUS, cmd_lsa_add_acct_rights, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Add rights to an account", "" },
+ { "lsaremoveacctrights", RPC_RTYPE_NTSTATUS, cmd_lsa_remove_acct_rights, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Remove rights from an account", "" },
+ { "lsalookupprivvalue", RPC_RTYPE_NTSTATUS, cmd_lsa_lookup_priv_value, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Get a privilege value given its name", "" },
+ { "lsaquerysecobj", RPC_RTYPE_NTSTATUS, cmd_lsa_query_secobj, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Query LSA security object", "" },
+ { "lsaquerytrustdominfo",RPC_RTYPE_NTSTATUS, cmd_lsa_query_trustdominfo, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Query LSA trusted domains info (given a SID)", "" },
+ { "lsaquerytrustdominfobyname",RPC_RTYPE_NTSTATUS, cmd_lsa_query_trustdominfobyname, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Query LSA trusted domains info (given a name), only works for Windows > 2k", "" },
+ { "lsaquerytrustdominfobysid",RPC_RTYPE_NTSTATUS, cmd_lsa_query_trustdominfobysid, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Query LSA trusted domains info (given a SID)", "" },
+ { "getusername", RPC_RTYPE_NTSTATUS, cmd_lsa_get_username, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Get username", "" },
+
+ { NULL }
+};
+
diff --git a/source3/rpcclient/cmd_netlogon.c b/source3/rpcclient/cmd_netlogon.c
new file mode 100644
index 0000000000..87ba65c14b
--- /dev/null
+++ b/source3/rpcclient/cmd_netlogon.c
@@ -0,0 +1,1034 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Guenther Deschner 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+static WERROR cmd_netlogon_logon_ctrl2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ WERROR werr;
+ const char *logon_server = cli->desthost;
+ enum netr_LogonControlCode function_code = NETLOGON_CONTROL_REDISCOVER;
+ uint32_t level = 1;
+ union netr_CONTROL_DATA_INFORMATION data;
+ union netr_CONTROL_QUERY_INFORMATION query;
+ const char *domain = lp_workgroup();
+
+ if (argc > 5) {
+ fprintf(stderr, "Usage: %s <logon_server> <function_code> "
+ "<level> <domain>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 2) {
+ logon_server = argv[1];
+ }
+
+ if (argc >= 3) {
+ function_code = atoi(argv[2]);
+ }
+
+ if (argc >= 4) {
+ level = atoi(argv[3]);
+ }
+
+ if (argc >= 5) {
+ domain = argv[4];
+ }
+
+ switch (function_code) {
+ case NETLOGON_CONTROL_REDISCOVER:
+ case NETLOGON_CONTROL_TC_QUERY:
+ data.domain = domain;
+ break;
+ default:
+ break;
+ }
+
+ status = rpccli_netr_LogonControl2(cli, mem_ctx,
+ logon_server,
+ function_code,
+ level,
+ &data,
+ &query,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ /* Display results */
+
+ return werr;
+}
+
+static WERROR cmd_netlogon_getanydcname(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ const char *dcname = NULL;
+ WERROR werr;
+ NTSTATUS status;
+ int old_timeout;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s domainname\n", argv[0]);
+ return WERR_OK;
+ }
+
+ /* Make sure to wait for our DC's reply */
+ old_timeout = rpccli_set_timeout(cli, 30000); /* 30 seconds. */
+ rpccli_set_timeout(cli, MAX(old_timeout, 30000)); /* At least 30 sec */
+
+ status = rpccli_netr_GetAnyDCName(cli, mem_ctx,
+ cli->desthost,
+ argv[1],
+ &dcname,
+ &werr);
+ rpccli_set_timeout(cli, old_timeout);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ /* Display results */
+
+ printf("%s\n", dcname);
+
+ return werr;
+}
+
+static WERROR cmd_netlogon_getdcname(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ const char *dcname = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ int old_timeout;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s domainname\n", argv[0]);
+ return WERR_OK;
+ }
+
+ /* Make sure to wait for our DC's reply */
+ old_timeout = rpccli_set_timeout(cli, 30000); /* 30 seconds. */
+ rpccli_set_timeout(cli, MAX(30000, old_timeout)); /* At least 30 sec */
+
+ status = rpccli_netr_GetDcName(cli, mem_ctx,
+ cli->desthost,
+ argv[1],
+ &dcname,
+ &werr);
+ rpccli_set_timeout(cli, old_timeout);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ /* Display results */
+
+ printf("%s\n", dcname);
+
+ return werr;
+}
+
+static WERROR cmd_netlogon_dsr_getdcname(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS result;
+ WERROR werr = WERR_OK;
+ uint32 flags = DS_RETURN_DNS_NAME;
+ const char *server_name = cli->desthost;
+ const char *domain_name;
+ struct GUID domain_guid = GUID_zero();
+ struct GUID site_guid = GUID_zero();
+ struct netr_DsRGetDCNameInfo *info = NULL;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s [domain_name] [domain_guid] "
+ "[site_guid] [flags]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 2)
+ domain_name = argv[1];
+
+ if (argc >= 3) {
+ if (!NT_STATUS_IS_OK(GUID_from_string(argv[2], &domain_guid))) {
+ return WERR_NOMEM;
+ }
+ }
+
+ if (argc >= 4) {
+ if (!NT_STATUS_IS_OK(GUID_from_string(argv[3], &site_guid))) {
+ return WERR_NOMEM;
+ }
+ }
+
+ if (argc >= 5)
+ sscanf(argv[4], "%x", &flags);
+
+ debug_dsdcinfo_flags(1,flags);
+
+ result = rpccli_netr_DsRGetDCName(cli, mem_ctx,
+ server_name,
+ domain_name,
+ &domain_guid,
+ &site_guid,
+ flags,
+ &info,
+ &werr);
+
+ if (W_ERROR_IS_OK(werr)) {
+ d_printf("DsGetDcName gave: %s\n",
+ NDR_PRINT_STRUCT_STRING(mem_ctx, netr_DsRGetDCNameInfo, info));
+ return WERR_OK;
+ }
+
+ printf("rpccli_netlogon_dsr_getdcname returned %s\n",
+ dos_errstr(werr));
+
+ return werr;
+}
+
+static WERROR cmd_netlogon_dsr_getdcnameex(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ WERROR result;
+ NTSTATUS status;
+ uint32_t flags = DS_RETURN_DNS_NAME;
+ const char *server_name = cli->desthost;
+ const char *domain_name;
+ const char *site_name = NULL;
+ struct GUID domain_guid = GUID_zero();
+ struct netr_DsRGetDCNameInfo *info = NULL;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s [domain_name] [domain_guid] "
+ "[site_name] [flags]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ domain_name = argv[1];
+
+ if (argc >= 3) {
+ if (!NT_STATUS_IS_OK(GUID_from_string(argv[2], &domain_guid))) {
+ return WERR_NOMEM;
+ }
+ }
+
+ if (argc >= 4) {
+ site_name = argv[3];
+ }
+
+ if (argc >= 5) {
+ sscanf(argv[4], "%x", &flags);
+ }
+
+ debug_dsdcinfo_flags(1,flags);
+
+ status = rpccli_netr_DsRGetDCNameEx(cli, mem_ctx,
+ server_name,
+ domain_name,
+ &domain_guid,
+ site_name,
+ flags,
+ &info,
+ &result);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ if (!W_ERROR_IS_OK(result)) {
+ return result;
+ }
+
+ d_printf("DsRGetDCNameEx gave %s\n",
+ NDR_PRINT_STRUCT_STRING(mem_ctx, netr_DsRGetDCNameInfo, info));
+
+ return result;
+}
+
+static WERROR cmd_netlogon_dsr_getdcnameex2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ WERROR result;
+ NTSTATUS status;
+ uint32_t flags = DS_RETURN_DNS_NAME;
+ const char *server_name = cli->desthost;
+ const char *domain_name = NULL;
+ const char *client_account = NULL;
+ uint32_t mask = 0;
+ const char *site_name = NULL;
+ struct GUID domain_guid = GUID_zero();
+ struct netr_DsRGetDCNameInfo *info = NULL;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s [client_account] [acb_mask] "
+ "[domain_name] [domain_guid] [site_name] "
+ "[flags]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 2) {
+ client_account = argv[1];
+ }
+
+ if (argc >= 3) {
+ mask = atoi(argv[2]);
+ }
+
+ if (argc >= 4) {
+ domain_name = argv[3];
+ }
+
+ if (argc >= 5) {
+ if (!NT_STATUS_IS_OK(GUID_from_string(argv[4], &domain_guid))) {
+ return WERR_NOMEM;
+ }
+ }
+
+ if (argc >= 6) {
+ site_name = argv[5];
+ }
+
+ if (argc >= 7) {
+ sscanf(argv[6], "%x", &flags);
+ }
+
+ debug_dsdcinfo_flags(1,flags);
+
+ status = rpccli_netr_DsRGetDCNameEx2(cli, mem_ctx,
+ server_name,
+ client_account,
+ mask,
+ domain_name,
+ &domain_guid,
+ site_name,
+ flags,
+ &info,
+ &result);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ if (!W_ERROR_IS_OK(result)) {
+ return result;
+ }
+
+ d_printf("DsRGetDCNameEx2 gave %s\n",
+ NDR_PRINT_STRUCT_STRING(mem_ctx, netr_DsRGetDCNameInfo, info));
+
+ return result;
+}
+
+
+static WERROR cmd_netlogon_dsr_getsitename(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ WERROR werr;
+ NTSTATUS status;
+ const char *sitename = NULL;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s computername\n", argv[0]);
+ return WERR_OK;
+ }
+
+ status = rpccli_netr_DsRGetSiteName(cli, mem_ctx,
+ argv[1],
+ &sitename,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ if (!W_ERROR_IS_OK(werr)) {
+ printf("rpccli_netlogon_dsr_gesitename returned %s\n",
+ nt_errstr(werror_to_ntstatus(werr)));
+ return werr;
+ }
+
+ printf("Computer %s is on Site: %s\n", argv[1], sitename);
+
+ return WERR_OK;
+}
+
+static WERROR cmd_netlogon_logon_ctrl(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ WERROR werr;
+ const char *logon_server = cli->desthost;
+ enum netr_LogonControlCode function_code = 1;
+ uint32_t level = 1;
+ union netr_CONTROL_QUERY_INFORMATION info;
+
+ if (argc > 4) {
+ fprintf(stderr, "Usage: %s <logon_server> <function_code> "
+ "<level>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 2) {
+ logon_server = argv[1];
+ }
+
+ if (argc >= 3) {
+ function_code = atoi(argv[2]);
+ }
+
+ if (argc >= 4) {
+ level = atoi(argv[3]);
+ }
+
+ status = rpccli_netr_LogonControl(cli, mem_ctx,
+ logon_server,
+ function_code,
+ level,
+ &info,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ /* Display results */
+
+ return werr;
+}
+
+/* Display sam synchronisation information */
+
+static void display_sam_sync(struct netr_DELTA_ENUM_ARRAY *r)
+{
+ uint32_t i, j;
+
+ for (i=0; i < r->num_deltas; i++) {
+
+ union netr_DELTA_UNION u = r->delta_enum[i].delta_union;
+ union netr_DELTA_ID_UNION id = r->delta_enum[i].delta_id_union;
+
+ switch (r->delta_enum[i].delta_type) {
+ case NETR_DELTA_DOMAIN:
+ printf("Domain: %s\n",
+ u.domain->domain_name.string);
+ break;
+ case NETR_DELTA_GROUP:
+ printf("Group: %s\n",
+ u.group->group_name.string);
+ break;
+ case NETR_DELTA_DELETE_GROUP:
+ printf("Delete Group: %d\n",
+ u.delete_account.unknown);
+ break;
+ case NETR_DELTA_RENAME_GROUP:
+ printf("Rename Group: %s -> %s\n",
+ u.rename_group->OldName.string,
+ u.rename_group->NewName.string);
+ break;
+ case NETR_DELTA_USER:
+ printf("Account: %s\n",
+ u.user->account_name.string);
+ break;
+ case NETR_DELTA_DELETE_USER:
+ printf("Delete User: %d\n",
+ id.rid);
+ break;
+ case NETR_DELTA_RENAME_USER:
+ printf("Rename user: %s -> %s\n",
+ u.rename_user->OldName.string,
+ u.rename_user->NewName.string);
+ break;
+ case NETR_DELTA_GROUP_MEMBER:
+ for (j=0; j < u.group_member->num_rids; j++) {
+ printf("rid 0x%x, attrib 0x%08x\n",
+ u.group_member->rids[j],
+ u.group_member->attribs[j]);
+ }
+ break;
+ case NETR_DELTA_ALIAS:
+ printf("Alias: %s\n",
+ u.alias->alias_name.string);
+ break;
+ case NETR_DELTA_DELETE_ALIAS:
+ printf("Delete Alias: %d\n",
+ r->delta_enum[i].delta_id_union.rid);
+ break;
+ case NETR_DELTA_RENAME_ALIAS:
+ printf("Rename alias: %s -> %s\n",
+ u.rename_alias->OldName.string,
+ u.rename_alias->NewName.string);
+ break;
+ case NETR_DELTA_ALIAS_MEMBER:
+ for (j=0; j < u.alias_member->sids.num_sids; j++) {
+ fstring sid_str;
+ sid_to_fstring(sid_str,
+ u.alias_member->sids.sids[j].sid);
+ printf("%s\n", sid_str);
+ }
+ break;
+ case NETR_DELTA_POLICY:
+ printf("Policy\n");
+ break;
+ case NETR_DELTA_TRUSTED_DOMAIN:
+ printf("Trusted Domain: %s\n",
+ u.trusted_domain->domain_name.string);
+ break;
+ case NETR_DELTA_DELETE_TRUST:
+ printf("Delete Trust: %d\n",
+ u.delete_trust.unknown);
+ break;
+ case NETR_DELTA_ACCOUNT:
+ printf("Account\n");
+ break;
+ case NETR_DELTA_DELETE_ACCOUNT:
+ printf("Delete Account: %d\n",
+ u.delete_account.unknown);
+ break;
+ case NETR_DELTA_SECRET:
+ printf("Secret\n");
+ break;
+ case NETR_DELTA_DELETE_SECRET:
+ printf("Delete Secret: %d\n",
+ u.delete_secret.unknown);
+ break;
+ case NETR_DELTA_DELETE_GROUP2:
+ printf("Delete Group2: %s\n",
+ u.delete_group->account_name);
+ break;
+ case NETR_DELTA_DELETE_USER2:
+ printf("Delete User2: %s\n",
+ u.delete_user->account_name);
+ break;
+ case NETR_DELTA_MODIFY_COUNT:
+ printf("sam sequence update: 0x%016llx\n",
+ (unsigned long long) *u.modified_count);
+ break;
+ default:
+ printf("unknown delta type 0x%02x\n",
+ r->delta_enum[i].delta_type);
+ break;
+ }
+ }
+}
+
+/* Perform sam synchronisation */
+
+static NTSTATUS cmd_netlogon_sam_sync(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ const char *logon_server = cli->desthost;
+ const char *computername = global_myname();
+ struct netr_Authenticator credential;
+ struct netr_Authenticator return_authenticator;
+ enum netr_SamDatabaseID database_id = SAM_DATABASE_DOMAIN;
+ uint16_t restart_state = 0;
+ uint32_t sync_context = 0;
+
+ if (argc > 2) {
+ fprintf(stderr, "Usage: %s [database_id]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2) {
+ database_id = atoi(argv[1]);
+ }
+
+ /* Synchronise sam database */
+
+ do {
+ struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
+
+ netlogon_creds_client_step(cli->dc, &credential);
+
+ result = rpccli_netr_DatabaseSync2(cli, mem_ctx,
+ logon_server,
+ computername,
+ &credential,
+ &return_authenticator,
+ database_id,
+ restart_state,
+ &sync_context,
+ &delta_enum_array,
+ 0xffff);
+
+ /* Check returned credentials. */
+ if (!netlogon_creds_client_check(cli->dc,
+ &return_authenticator.cred)) {
+ DEBUG(0,("credentials chain check failed\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (NT_STATUS_IS_ERR(result)) {
+ break;
+ }
+
+ /* Display results */
+
+ display_sam_sync(delta_enum_array);
+
+ TALLOC_FREE(delta_enum_array);
+
+ } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
+
+ return result;
+}
+
+/* Perform sam delta synchronisation */
+
+static NTSTATUS cmd_netlogon_sam_deltas(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32_t tmp;
+ const char *logon_server = cli->desthost;
+ const char *computername = global_myname();
+ struct netr_Authenticator credential;
+ struct netr_Authenticator return_authenticator;
+ enum netr_SamDatabaseID database_id = SAM_DATABASE_DOMAIN;
+ uint64_t sequence_num;
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s database_id seqnum\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ database_id = atoi(argv[1]);
+ tmp = atoi(argv[2]);
+
+ sequence_num = tmp & 0xffff;
+
+ do {
+ struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
+
+ netlogon_creds_client_step(cli->dc, &credential);
+
+ result = rpccli_netr_DatabaseDeltas(cli, mem_ctx,
+ logon_server,
+ computername,
+ &credential,
+ &return_authenticator,
+ database_id,
+ &sequence_num,
+ &delta_enum_array,
+ 0xffff);
+
+ /* Check returned credentials. */
+ if (!netlogon_creds_client_check(cli->dc,
+ &return_authenticator.cred)) {
+ DEBUG(0,("credentials chain check failed\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (NT_STATUS_IS_ERR(result)) {
+ break;
+ }
+
+ /* Display results */
+
+ display_sam_sync(delta_enum_array);
+
+ TALLOC_FREE(delta_enum_array);
+
+ } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
+
+ return result;
+}
+
+/* Log on a domain user */
+
+static NTSTATUS cmd_netlogon_sam_logon(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ int logon_type = NET_LOGON_TYPE;
+ const char *username, *password;
+ int auth_level = 2;
+ uint32 logon_param = 0;
+ const char *workstation = NULL;
+
+ /* Check arguments */
+
+ if (argc < 3 || argc > 7) {
+ fprintf(stderr, "Usage: samlogon <username> <password> [workstation]"
+ "[logon_type (1 or 2)] [auth level (2 or 3)] [logon_parameter]\n");
+ return NT_STATUS_OK;
+ }
+
+ username = argv[1];
+ password = argv[2];
+
+ if (argc >= 4)
+ workstation = argv[3];
+
+ if (argc >= 5)
+ sscanf(argv[4], "%i", &logon_type);
+
+ if (argc >= 6)
+ sscanf(argv[5], "%i", &auth_level);
+
+ if (argc == 7)
+ sscanf(argv[6], "%x", &logon_param);
+
+ /* Perform the sam logon */
+
+ result = rpccli_netlogon_sam_logon(cli, mem_ctx, logon_param, lp_workgroup(), username, password, workstation, logon_type);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ done:
+ return result;
+}
+
+/* Change the trust account password */
+
+static NTSTATUS cmd_netlogon_change_trust_pw(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ /* Check arguments */
+
+ if (argc > 1) {
+ fprintf(stderr, "Usage: change_trust_pw");
+ return NT_STATUS_OK;
+ }
+
+ /* Perform the sam logon */
+
+ result = trust_pw_find_change_and_store_it(cli, mem_ctx,
+ lp_workgroup());
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ done:
+ return result;
+}
+
+static WERROR cmd_netlogon_gettrustrid(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ WERROR werr = WERR_GENERAL_FAILURE;
+ const char *server_name = cli->desthost;
+ const char *domain_name = lp_workgroup();
+ uint32_t rid = 0;
+
+ if (argc < 1 || argc > 3) {
+ fprintf(stderr, "Usage: %s <server_name> <domain_name>\n",
+ argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 2) {
+ server_name = argv[1];
+ }
+
+ if (argc >= 3) {
+ domain_name = argv[2];
+ }
+
+ status = rpccli_netr_LogonGetTrustRid(cli, mem_ctx,
+ server_name,
+ domain_name,
+ &rid,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (W_ERROR_IS_OK(werr)) {
+ printf("Rid: %d\n", rid);
+ }
+ done:
+ return werr;
+}
+
+static WERROR cmd_netlogon_dsr_enumtrustdom(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ WERROR werr = WERR_GENERAL_FAILURE;
+ const char *server_name = cli->desthost;
+ uint32_t trust_flags = NETR_TRUST_FLAG_IN_FOREST;
+ struct netr_DomainTrustList trusts;
+
+ if (argc < 1 || argc > 3) {
+ fprintf(stderr, "Usage: %s <server_name> <trust_flags>\n",
+ argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 2) {
+ server_name = argv[1];
+ }
+
+ if (argc >= 3) {
+ sscanf(argv[2], "%x", &trust_flags);
+ }
+
+ status = rpccli_netr_DsrEnumerateDomainTrusts(cli, mem_ctx,
+ server_name,
+ trust_flags,
+ &trusts,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (W_ERROR_IS_OK(werr)) {
+ int i;
+
+ printf("%d domains returned\n", trusts.count);
+
+ for (i=0; i<trusts.count; i++ ) {
+ printf("%s (%s)\n",
+ trusts.array[i].dns_name,
+ trusts.array[i].netbios_name);
+ }
+ }
+ done:
+ return werr;
+}
+
+static WERROR cmd_netlogon_deregisterdnsrecords(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ WERROR werr = WERR_GENERAL_FAILURE;
+ const char *server_name = cli->desthost;
+ const char *domain = lp_workgroup();
+ const char *dns_host = NULL;
+
+ if (argc < 1 || argc > 4) {
+ fprintf(stderr, "Usage: %s <server_name> <domain_name> "
+ "<dns_host>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 2) {
+ server_name = argv[1];
+ }
+
+ if (argc >= 3) {
+ domain = argv[2];
+ }
+
+ if (argc >= 4) {
+ dns_host = argv[3];
+ }
+
+ status = rpccli_netr_DsrDeregisterDNSHostRecords(cli, mem_ctx,
+ server_name,
+ domain,
+ NULL,
+ NULL,
+ dns_host,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (W_ERROR_IS_OK(werr)) {
+ printf("success\n");
+ }
+ done:
+ return werr;
+}
+
+static WERROR cmd_netlogon_dsr_getforesttrustinfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ WERROR werr = WERR_GENERAL_FAILURE;
+ const char *server_name = cli->desthost;
+ const char *trusted_domain_name = NULL;
+ struct lsa_ForestTrustInformation *info = NULL;
+ uint32_t flags = 0;
+
+ if (argc < 1 || argc > 4) {
+ fprintf(stderr, "Usage: %s <server_name> <trusted_domain_name> "
+ "<flags>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 2) {
+ server_name = argv[1];
+ }
+
+ if (argc >= 3) {
+ trusted_domain_name = argv[2];
+ }
+
+ if (argc >= 4) {
+ sscanf(argv[3], "%x", &flags);
+ }
+
+ status = rpccli_netr_DsRGetForestTrustInformation(cli, mem_ctx,
+ server_name,
+ trusted_domain_name,
+ flags,
+ &info,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (W_ERROR_IS_OK(werr)) {
+ printf("success\n");
+ }
+ done:
+ return werr;
+}
+
+static WERROR cmd_netlogon_enumtrusteddomains(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ WERROR werr = WERR_GENERAL_FAILURE;
+ const char *server_name = cli->desthost;
+ struct netr_Blob blob;
+
+
+ if (argc < 1 || argc > 3) {
+ fprintf(stderr, "Usage: %s <server_name>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 2) {
+ server_name = argv[1];
+ }
+
+ status = rpccli_netr_NetrEnumerateTrustedDomains(cli, mem_ctx,
+ server_name,
+ &blob,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (W_ERROR_IS_OK(werr)) {
+ printf("success\n");
+ dump_data(1, blob.data, blob.length);
+ }
+ done:
+ return werr;
+}
+
+static WERROR cmd_netlogon_enumtrusteddomainsex(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ WERROR werr = WERR_GENERAL_FAILURE;
+ const char *server_name = cli->desthost;
+ struct netr_DomainTrustList list;
+
+ if (argc < 1 || argc > 3) {
+ fprintf(stderr, "Usage: %s <server_name>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 2) {
+ server_name = argv[1];
+ }
+
+ status = rpccli_netr_NetrEnumerateTrustedDomainsEx(cli, mem_ctx,
+ server_name,
+ &list,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (W_ERROR_IS_OK(werr)) {
+ printf("success\n");
+ }
+ done:
+ return werr;
+}
+
+
+/* List of commands exported by this module */
+
+struct cmd_set netlogon_commands[] = {
+
+ { "NETLOGON" },
+
+ { "logonctrl2", RPC_RTYPE_WERROR, NULL, cmd_netlogon_logon_ctrl2, &ndr_table_netlogon.syntax_id, NULL, "Logon Control 2", "" },
+ { "getanydcname", RPC_RTYPE_WERROR, NULL, cmd_netlogon_getanydcname, &ndr_table_netlogon.syntax_id, NULL, "Get trusted DC name", "" },
+ { "getdcname", RPC_RTYPE_WERROR, NULL, cmd_netlogon_getdcname, &ndr_table_netlogon.syntax_id, NULL, "Get trusted PDC name", "" },
+ { "dsr_getdcname", RPC_RTYPE_WERROR, NULL, cmd_netlogon_dsr_getdcname, &ndr_table_netlogon.syntax_id, NULL, "Get trusted DC name", "" },
+ { "dsr_getdcnameex", RPC_RTYPE_WERROR, NULL, cmd_netlogon_dsr_getdcnameex, &ndr_table_netlogon.syntax_id, NULL, "Get trusted DC name", "" },
+ { "dsr_getdcnameex2", RPC_RTYPE_WERROR, NULL, cmd_netlogon_dsr_getdcnameex2, &ndr_table_netlogon.syntax_id, NULL, "Get trusted DC name", "" },
+ { "dsr_getsitename", RPC_RTYPE_WERROR, NULL, cmd_netlogon_dsr_getsitename, &ndr_table_netlogon.syntax_id, NULL, "Get sitename", "" },
+ { "dsr_getforesttrustinfo", RPC_RTYPE_WERROR, NULL, cmd_netlogon_dsr_getforesttrustinfo, &ndr_table_netlogon.syntax_id, NULL, "Get Forest Trust Info", "" },
+ { "logonctrl", RPC_RTYPE_WERROR, NULL, cmd_netlogon_logon_ctrl, &ndr_table_netlogon.syntax_id, NULL, "Logon Control", "" },
+ { "samsync", RPC_RTYPE_NTSTATUS, cmd_netlogon_sam_sync, NULL, &ndr_table_netlogon.syntax_id, NULL, "Sam Synchronisation", "" },
+ { "samdeltas", RPC_RTYPE_NTSTATUS, cmd_netlogon_sam_deltas, NULL, &ndr_table_netlogon.syntax_id, NULL, "Query Sam Deltas", "" },
+ { "samlogon", RPC_RTYPE_NTSTATUS, cmd_netlogon_sam_logon, NULL, &ndr_table_netlogon.syntax_id, NULL, "Sam Logon", "" },
+ { "change_trust_pw", RPC_RTYPE_NTSTATUS, cmd_netlogon_change_trust_pw, NULL, &ndr_table_netlogon.syntax_id, NULL, "Change Trust Account Password", "" },
+ { "gettrustrid", RPC_RTYPE_WERROR, NULL, cmd_netlogon_gettrustrid, &ndr_table_netlogon.syntax_id, NULL, "Get trust rid", "" },
+ { "dsr_enumtrustdom", RPC_RTYPE_WERROR, NULL, cmd_netlogon_dsr_enumtrustdom, &ndr_table_netlogon.syntax_id, NULL, "Enumerate trusted domains", "" },
+ { "dsenumdomtrusts", RPC_RTYPE_WERROR, NULL, cmd_netlogon_dsr_enumtrustdom, &ndr_table_netlogon.syntax_id, NULL, "Enumerate all trusted domains in an AD forest", "" },
+ { "deregisterdnsrecords", RPC_RTYPE_WERROR, NULL, cmd_netlogon_deregisterdnsrecords, &ndr_table_netlogon.syntax_id, NULL, "Deregister DNS records", "" },
+ { "netrenumtrusteddomains", RPC_RTYPE_WERROR, NULL, cmd_netlogon_enumtrusteddomains, &ndr_table_netlogon.syntax_id, NULL, "Enumerate trusted domains", "" },
+ { "netrenumtrusteddomainsex", RPC_RTYPE_WERROR, NULL, cmd_netlogon_enumtrusteddomainsex, &ndr_table_netlogon.syntax_id, NULL, "Enumerate trusted domains", "" },
+
+ { NULL }
+};
diff --git a/source3/rpcclient/cmd_ntsvcs.c b/source3/rpcclient/cmd_ntsvcs.c
new file mode 100644
index 0000000000..377a8a2a00
--- /dev/null
+++ b/source3/rpcclient/cmd_ntsvcs.c
@@ -0,0 +1,229 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Günther Deschner 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+static WERROR cmd_ntsvcs_get_version(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ WERROR werr;
+ uint16_t version;
+
+ status = rpccli_PNP_GetVersion(cli, mem_ctx,
+ &version, &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ if (W_ERROR_IS_OK(werr)) {
+ printf("version: %d\n", version);
+ }
+
+ return werr;
+}
+
+static WERROR cmd_ntsvcs_validate_dev_inst(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ WERROR werr;
+ const char *devicepath = NULL;
+ uint32_t flags = 0;
+
+ if (argc < 2 || argc > 3) {
+ printf("usage: %s [devicepath] <flags>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ devicepath = argv[1];
+
+ if (argc >= 3) {
+ flags = atoi(argv[2]);
+ }
+
+ status = rpccli_PNP_ValidateDeviceInstance(cli, mem_ctx,
+ devicepath,
+ flags,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ return werr;
+}
+
+static WERROR cmd_ntsvcs_get_device_list_size(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ WERROR werr;
+ const char *devicename = NULL;
+ uint32_t flags = 0;
+ uint32_t size = 0;
+
+ if (argc < 2 || argc > 4) {
+ printf("usage: %s [devicename] <flags>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ devicename = argv[1];
+
+ if (argc >= 3) {
+ flags = atoi(argv[2]);
+ }
+
+ status = rpccli_PNP_GetDeviceListSize(cli, mem_ctx,
+ devicename,
+ &size,
+ flags,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ if (W_ERROR_IS_OK(werr)) {
+ printf("size: %d\n", size);
+ }
+
+ return werr;
+}
+
+static WERROR cmd_ntsvcs_hw_prof_flags(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ WERROR werr;
+ const char *devicepath = NULL;
+ uint32_t unk3 = 0;
+ uint16_t unk4 = 0;
+ const char *unk5 = NULL;
+ const char *unk5a = NULL;
+
+ if (argc < 2) {
+ printf("usage: %s [devicepath]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ devicepath = argv[1];
+
+ status = rpccli_PNP_HwProfFlags(cli, mem_ctx,
+ 0,
+ devicepath,
+ 0,
+ &unk3,
+ &unk4,
+ unk5,
+ &unk5a,
+ 0,
+ 0,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ return werr;
+}
+
+static WERROR cmd_ntsvcs_get_hw_prof_info(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ WERROR werr;
+ uint32_t idx = 0;
+ struct PNP_HwProfInfo info;
+ uint32_t unknown1 = 0, unknown2 = 0;
+
+ ZERO_STRUCT(info);
+
+ status = rpccli_PNP_GetHwProfInfo(cli, mem_ctx,
+ idx,
+ &info,
+ unknown1,
+ unknown2,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ return werr;
+}
+
+static WERROR cmd_ntsvcs_get_dev_reg_prop(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ WERROR werr;
+ const char *devicepath = NULL;
+ uint32_t property = DEV_REGPROP_DESC;
+ uint32_t unknown1 = 0;
+ uint8_t buffer;
+ uint32_t buffer_size = 0;
+ uint32_t unknown2 = 0;
+ uint32_t unknown3 = 0;
+
+ if (argc < 2) {
+ printf("usage: %s [devicepath]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ devicepath = argv[1];
+
+ status = rpccli_PNP_GetDeviceRegProp(cli, mem_ctx,
+ devicepath,
+ property,
+ &unknown1,
+ &buffer,
+ &buffer_size,
+ &unknown2,
+ unknown3,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ return werr;
+}
+
+
+struct cmd_set ntsvcs_commands[] = {
+
+ { "NTSVCS" },
+ { "ntsvcs_getversion", RPC_RTYPE_WERROR, NULL, cmd_ntsvcs_get_version, &ndr_table_ntsvcs.syntax_id, NULL, "Query NTSVCS version", "" },
+ { "ntsvcs_validatedevinst", RPC_RTYPE_WERROR, NULL, cmd_ntsvcs_validate_dev_inst, &ndr_table_ntsvcs.syntax_id, NULL, "Query NTSVCS device instance", "" },
+ { "ntsvcs_getdevlistsize", RPC_RTYPE_WERROR, NULL, cmd_ntsvcs_get_device_list_size, &ndr_table_ntsvcs.syntax_id, NULL, "Query NTSVCS get device list", "" },
+ { "ntsvcs_hwprofflags", RPC_RTYPE_WERROR, NULL, cmd_ntsvcs_hw_prof_flags, &ndr_table_ntsvcs.syntax_id, NULL, "Query NTSVCS HW prof flags", "" },
+ { "ntsvcs_hwprofinfo", RPC_RTYPE_WERROR, NULL, cmd_ntsvcs_get_hw_prof_info, &ndr_table_ntsvcs.syntax_id, NULL, "Query NTSVCS HW prof info", "" },
+ { "ntsvcs_getdevregprop", RPC_RTYPE_WERROR, NULL, cmd_ntsvcs_get_dev_reg_prop, &ndr_table_ntsvcs.syntax_id, NULL, "Query NTSVCS device registry property", "" },
+ { NULL }
+};
diff --git a/source3/rpcclient/cmd_samr.c b/source3/rpcclient/cmd_samr.c
new file mode 100644
index 0000000000..fa1e0fda4d
--- /dev/null
+++ b/source3/rpcclient/cmd_samr.c
@@ -0,0 +1,2763 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Andrew Tridgell 1992-2000,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ Copyright (C) Elrond 2000,
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Guenther Deschner 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+extern DOM_SID domain_sid;
+
+/****************************************************************************
+ display samr_user_info_7 structure
+ ****************************************************************************/
+static void display_samr_user_info_7(struct samr_UserInfo7 *r)
+{
+ printf("\tUser Name :\t%s\n", r->account_name.string);
+}
+
+/****************************************************************************
+ display samr_user_info_9 structure
+ ****************************************************************************/
+static void display_samr_user_info_9(struct samr_UserInfo9 *r)
+{
+ printf("\tPrimary group RID :\tox%x\n", r->primary_gid);
+}
+
+/****************************************************************************
+ display samr_user_info_16 structure
+ ****************************************************************************/
+static void display_samr_user_info_16(struct samr_UserInfo16 *r)
+{
+ printf("\tAcct Flags :\tox%x\n", r->acct_flags);
+}
+
+/****************************************************************************
+ display samr_user_info_20 structure
+ ****************************************************************************/
+static void display_samr_user_info_20(struct samr_UserInfo20 *r)
+{
+ printf("\tRemote Dial :\n");
+ dump_data(0, (uint8_t *)r->parameters.array, r->parameters.length*2);
+}
+
+
+/****************************************************************************
+ display samr_user_info_21 structure
+ ****************************************************************************/
+static void display_samr_user_info_21(struct samr_UserInfo21 *r)
+{
+ printf("\tUser Name :\t%s\n", r->account_name.string);
+ printf("\tFull Name :\t%s\n", r->full_name.string);
+ printf("\tHome Drive :\t%s\n", r->home_directory.string);
+ printf("\tDir Drive :\t%s\n", r->home_drive.string);
+ printf("\tProfile Path:\t%s\n", r->profile_path.string);
+ printf("\tLogon Script:\t%s\n", r->logon_script.string);
+ printf("\tDescription :\t%s\n", r->description.string);
+ printf("\tWorkstations:\t%s\n", r->workstations.string);
+ printf("\tComment :\t%s\n", r->comment.string);
+ printf("\tRemote Dial :\n");
+ dump_data(0, (uint8_t *)r->parameters.array, r->parameters.length*2);
+
+ printf("\tLogon Time :\t%s\n",
+ http_timestring(nt_time_to_unix(r->last_logon)));
+ printf("\tLogoff Time :\t%s\n",
+ http_timestring(nt_time_to_unix(r->last_logoff)));
+ printf("\tKickoff Time :\t%s\n",
+ http_timestring(nt_time_to_unix(r->acct_expiry)));
+ printf("\tPassword last set Time :\t%s\n",
+ http_timestring(nt_time_to_unix(r->last_password_change)));
+ printf("\tPassword can change Time :\t%s\n",
+ http_timestring(nt_time_to_unix(r->allow_password_change)));
+ printf("\tPassword must change Time:\t%s\n",
+ http_timestring(nt_time_to_unix(r->force_password_change)));
+
+ printf("\tunknown_2[0..31]...\n"); /* user passwords? */
+
+ printf("\tuser_rid :\t0x%x\n" , r->rid); /* User ID */
+ printf("\tgroup_rid:\t0x%x\n" , r->primary_gid); /* Group ID */
+ printf("\tacb_info :\t0x%08x\n", r->acct_flags); /* Account Control Info */
+
+ printf("\tfields_present:\t0x%08x\n", r->fields_present); /* 0x00ff ffff */
+ printf("\tlogon_divs:\t%d\n", r->logon_hours.units_per_week); /* 0x0000 00a8 which is 168 which is num hrs in a week */
+ printf("\tbad_password_count:\t0x%08x\n", r->bad_password_count);
+ printf("\tlogon_count:\t0x%08x\n", r->logon_count);
+
+ printf("\tpadding1[0..7]...\n");
+
+ if (r->logon_hours.bits) {
+ printf("\tlogon_hrs[0..%d]...\n", r->logon_hours.units_per_week/8);
+ }
+}
+
+
+static void display_password_properties(uint32_t password_properties)
+{
+ printf("password_properties: 0x%08x\n", password_properties);
+
+ if (password_properties & DOMAIN_PASSWORD_COMPLEX)
+ printf("\tDOMAIN_PASSWORD_COMPLEX\n");
+
+ if (password_properties & DOMAIN_PASSWORD_NO_ANON_CHANGE)
+ printf("\tDOMAIN_PASSWORD_NO_ANON_CHANGE\n");
+
+ if (password_properties & DOMAIN_PASSWORD_NO_CLEAR_CHANGE)
+ printf("\tDOMAIN_PASSWORD_NO_CLEAR_CHANGE\n");
+
+ if (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)
+ printf("\tDOMAIN_PASSWORD_LOCKOUT_ADMINS\n");
+
+ if (password_properties & DOMAIN_PASSWORD_STORE_CLEARTEXT)
+ printf("\tDOMAIN_PASSWORD_STORE_CLEARTEXT\n");
+
+ if (password_properties & DOMAIN_REFUSE_PASSWORD_CHANGE)
+ printf("\tDOMAIN_REFUSE_PASSWORD_CHANGE\n");
+}
+
+static void display_sam_dom_info_1(struct samr_DomInfo1 *info1)
+{
+ printf("Minimum password length:\t\t\t%d\n",
+ info1->min_password_length);
+ printf("Password uniqueness (remember x passwords):\t%d\n",
+ info1->password_history_length);
+ display_password_properties(info1->password_properties);
+ printf("password expire in:\t\t\t\t%s\n",
+ display_time(info1->max_password_age));
+ printf("Min password age (allow changing in x days):\t%s\n",
+ display_time(info1->min_password_age));
+}
+
+static void display_sam_dom_info_2(struct samr_DomInfo2 *info2)
+{
+ printf("Domain:\t\t%s\n", info2->domain_name.string);
+ printf("Server:\t\t%s\n", info2->primary.string);
+ printf("Comment:\t%s\n", info2->comment.string);
+
+ printf("Total Users:\t%d\n", info2->num_users);
+ printf("Total Groups:\t%d\n", info2->num_groups);
+ printf("Total Aliases:\t%d\n", info2->num_aliases);
+
+ printf("Sequence No:\t%llu\n", (unsigned long long)info2->sequence_num);
+
+ printf("Force Logoff:\t%d\n",
+ (int)nt_time_to_unix_abs(&info2->force_logoff_time));
+
+ printf("Unknown 2:\t0x%x\n", info2->unknown2);
+ printf("Server Role:\t%s\n", server_role_str(info2->role));
+ printf("Unknown 3:\t0x%x\n", info2->unknown3);
+}
+
+static void display_sam_dom_info_3(struct samr_DomInfo3 *info3)
+{
+ printf("Force Logoff:\t%d\n",
+ (int)nt_time_to_unix_abs(&info3->force_logoff_time));
+}
+
+static void display_sam_dom_info_4(struct samr_DomInfo4 *info4)
+{
+ printf("Comment:\t%s\n", info4->comment.string);
+}
+
+static void display_sam_dom_info_5(struct samr_DomInfo5 *info5)
+{
+ printf("Domain:\t\t%s\n", info5->domain_name.string);
+}
+
+static void display_sam_dom_info_6(struct samr_DomInfo6 *info6)
+{
+ printf("Server:\t\t%s\n", info6->primary.string);
+}
+
+static void display_sam_dom_info_7(struct samr_DomInfo7 *info7)
+{
+ printf("Server Role:\t%s\n", server_role_str(info7->role));
+}
+
+static void display_sam_dom_info_8(struct samr_DomInfo8 *info8)
+{
+ printf("Sequence No:\t%llu\n", (unsigned long long)info8->sequence_num);
+ printf("Domain Create Time:\t%s\n",
+ http_timestring(nt_time_to_unix(info8->domain_create_time)));
+}
+
+static void display_sam_dom_info_9(struct samr_DomInfo9 *info9)
+{
+ printf("unknown:\t%d (0x%08x)\n", info9->unknown, info9->unknown);
+}
+
+static void display_sam_dom_info_12(struct samr_DomInfo12 *info12)
+{
+ printf("Bad password lockout duration: %s\n",
+ display_time(info12->lockout_duration));
+ printf("Reset Lockout after: %s\n",
+ display_time(info12->lockout_window));
+ printf("Lockout after bad attempts: %d\n",
+ info12->lockout_threshold);
+}
+
+static void display_sam_dom_info_13(struct samr_DomInfo13 *info13)
+{
+ printf("Sequence No:\t%llu\n", (unsigned long long)info13->sequence_num);
+ printf("Domain Create Time:\t%s\n",
+ http_timestring(nt_time_to_unix(info13->domain_create_time)));
+ printf("Unknown1:\t%d\n", info13->unknown1);
+ printf("Unknown2:\t%d\n", info13->unknown2);
+
+}
+
+static void display_sam_info_1(struct samr_DispEntryGeneral *r)
+{
+ printf("index: 0x%x ", r->idx);
+ printf("RID: 0x%x ", r->rid);
+ printf("acb: 0x%08x ", r->acct_flags);
+ printf("Account: %s\t", r->account_name.string);
+ printf("Name: %s\t", r->full_name.string);
+ printf("Desc: %s\n", r->description.string);
+}
+
+static void display_sam_info_2(struct samr_DispEntryFull *r)
+{
+ printf("index: 0x%x ", r->idx);
+ printf("RID: 0x%x ", r->rid);
+ printf("acb: 0x%08x ", r->acct_flags);
+ printf("Account: %s\t", r->account_name.string);
+ printf("Desc: %s\n", r->description.string);
+}
+
+static void display_sam_info_3(struct samr_DispEntryFullGroup *r)
+{
+ printf("index: 0x%x ", r->idx);
+ printf("RID: 0x%x ", r->rid);
+ printf("acb: 0x%08x ", r->acct_flags);
+ printf("Account: %s\t", r->account_name.string);
+ printf("Desc: %s\n", r->description.string);
+}
+
+static void display_sam_info_4(struct samr_DispEntryAscii *r)
+{
+ printf("index: 0x%x ", r->idx);
+ printf("Account: %s\n", r->account_name.string);
+}
+
+static void display_sam_info_5(struct samr_DispEntryAscii *r)
+{
+ printf("index: 0x%x ", r->idx);
+ printf("Account: %s\n", r->account_name.string);
+}
+
+/**********************************************************************
+ * Query user information
+ */
+static NTSTATUS cmd_samr_query_user(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, user_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 info_level = 21;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ union samr_UserInfo *info = NULL;
+ uint32 user_rid = 0;
+
+ if ((argc < 2) || (argc > 4)) {
+ printf("Usage: %s rid [info level] [access mask] \n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ sscanf(argv[1], "%i", &user_rid);
+
+ if (argc > 2)
+ sscanf(argv[2], "%i", &info_level);
+
+ if (argc > 3)
+ sscanf(argv[3], "%x", &access_mask);
+
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid,
+ &domain_pol);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_OpenUser(cli, mem_ctx,
+ &domain_pol,
+ access_mask,
+ user_rid,
+ &user_pol);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) &&
+ (user_rid == 0)) {
+
+ /* Probably this was a user name, try lookupnames */
+ struct samr_Ids rids, types;
+ struct lsa_String lsa_acct_name;
+
+ init_lsa_String(&lsa_acct_name, argv[1]);
+
+ result = rpccli_samr_LookupNames(cli, mem_ctx,
+ &domain_pol,
+ 1,
+ &lsa_acct_name,
+ &rids,
+ &types);
+
+ if (NT_STATUS_IS_OK(result)) {
+ result = rpccli_samr_OpenUser(cli, mem_ctx,
+ &domain_pol,
+ access_mask,
+ rids.ids[0],
+ &user_pol);
+ }
+ }
+
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_QueryUserInfo(cli, mem_ctx,
+ &user_pol,
+ info_level,
+ &info);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ switch (info_level) {
+ case 7:
+ display_samr_user_info_7(&info->info7);
+ break;
+ case 9:
+ display_samr_user_info_9(&info->info9);
+ break;
+ case 16:
+ display_samr_user_info_16(&info->info16);
+ break;
+ case 20:
+ display_samr_user_info_20(&info->info20);
+ break;
+ case 21:
+ display_samr_user_info_21(&info->info21);
+ break;
+ default:
+ printf("Unsupported infolevel: %d\n", info_level);
+ break;
+ }
+
+ rpccli_samr_Close(cli, mem_ctx, &user_pol);
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+
+done:
+ return result;
+}
+
+/****************************************************************************
+ display group info
+ ****************************************************************************/
+static void display_group_info1(struct samr_GroupInfoAll *info1)
+{
+ printf("\tGroup Name:\t%s\n", info1->name.string);
+ printf("\tDescription:\t%s\n", info1->description.string);
+ printf("\tGroup Attribute:%d\n", info1->attributes);
+ printf("\tNum Members:%d\n", info1->num_members);
+}
+
+/****************************************************************************
+ display group info
+ ****************************************************************************/
+static void display_group_info2(struct lsa_String *info2)
+{
+ printf("\tGroup Description:%s\n", info2->string);
+}
+
+
+/****************************************************************************
+ display group info
+ ****************************************************************************/
+static void display_group_info3(struct samr_GroupInfoAttributes *info3)
+{
+ printf("\tGroup Attribute:%d\n", info3->attributes);
+}
+
+
+/****************************************************************************
+ display group info
+ ****************************************************************************/
+static void display_group_info4(struct lsa_String *info4)
+{
+ printf("\tGroup Description:%s\n", info4->string);
+}
+
+/****************************************************************************
+ display group info
+ ****************************************************************************/
+static void display_group_info5(struct samr_GroupInfoAll *info5)
+{
+ printf("\tGroup Name:\t%s\n", info5->name.string);
+ printf("\tDescription:\t%s\n", info5->description.string);
+ printf("\tGroup Attribute:%d\n", info5->attributes);
+ printf("\tNum Members:%d\n", info5->num_members);
+}
+
+/****************************************************************************
+ display sam sync structure
+ ****************************************************************************/
+static void display_group_info(union samr_GroupInfo *info,
+ enum samr_GroupInfoEnum level)
+{
+ switch (level) {
+ case 1:
+ display_group_info1(&info->all);
+ break;
+ case 2:
+ display_group_info2(&info->name);
+ break;
+ case 3:
+ display_group_info3(&info->attributes);
+ break;
+ case 4:
+ display_group_info4(&info->description);
+ break;
+ case 5:
+ display_group_info5(&info->all2);
+ break;
+ }
+}
+
+/***********************************************************************
+ * Query group information
+ */
+static NTSTATUS cmd_samr_query_group(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, group_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ enum samr_GroupInfoEnum info_level = GROUPINFOALL;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ union samr_GroupInfo *group_info = NULL;
+ uint32 group_rid;
+
+ if ((argc < 2) || (argc > 4)) {
+ printf("Usage: %s rid [info level] [access mask]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ sscanf(argv[1], "%i", &group_rid);
+
+ if (argc > 2)
+ info_level = atoi(argv[2]);
+
+ if (argc > 3)
+ sscanf(argv[3], "%x", &access_mask);
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_OpenGroup(cli, mem_ctx,
+ &domain_pol,
+ access_mask,
+ group_rid,
+ &group_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_QueryGroupInfo(cli, mem_ctx,
+ &group_pol,
+ info_level,
+ &group_info);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ display_group_info(group_info, info_level);
+
+ rpccli_samr_Close(cli, mem_ctx, &group_pol);
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+done:
+ return result;
+}
+
+/* Query groups a user is a member of */
+
+static NTSTATUS cmd_samr_query_usergroups(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol,
+ domain_pol,
+ user_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 user_rid;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ int i;
+ struct samr_RidWithAttributeArray *rid_array = NULL;
+
+ if ((argc < 2) || (argc > 3)) {
+ printf("Usage: %s rid [access mask]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ sscanf(argv[1], "%i", &user_rid);
+
+ if (argc > 2)
+ sscanf(argv[2], "%x", &access_mask);
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid, &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_OpenUser(cli, mem_ctx,
+ &domain_pol,
+ access_mask,
+ user_rid,
+ &user_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_GetGroupsForUser(cli, mem_ctx,
+ &user_pol,
+ &rid_array);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ for (i = 0; i < rid_array->count; i++) {
+ printf("\tgroup rid:[0x%x] attr:[0x%x]\n",
+ rid_array->rids[i].rid,
+ rid_array->rids[i].attributes);
+ }
+
+ rpccli_samr_Close(cli, mem_ctx, &user_pol);
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ done:
+ return result;
+}
+
+/* Query aliases a user is a member of */
+
+static NTSTATUS cmd_samr_query_useraliases(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_SID *sids;
+ size_t num_sids;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ int i;
+ struct lsa_SidArray sid_array;
+ struct samr_Ids alias_rids;
+
+ if (argc < 3) {
+ printf("Usage: %s builtin|domain sid1 sid2 ...\n", argv[0]);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ sids = NULL;
+ num_sids = 0;
+
+ for (i=2; i<argc; i++) {
+ DOM_SID tmp_sid;
+ if (!string_to_sid(&tmp_sid, argv[i])) {
+ printf("%s is not a legal SID\n", argv[i]);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ result = add_sid_to_array(mem_ctx, &tmp_sid, &sids, &num_sids);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+ }
+
+ if (num_sids) {
+ sid_array.sids = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_SidPtr, num_sids);
+ if (sid_array.sids == NULL)
+ return NT_STATUS_NO_MEMORY;
+ } else {
+ sid_array.sids = NULL;
+ }
+
+ for (i=0; i<num_sids; i++) {
+ sid_array.sids[i].sid = sid_dup_talloc(mem_ctx, &sids[i]);
+ if (!sid_array.sids[i].sid) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ sid_array.num_sids = num_sids;
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ if (StrCaseCmp(argv[1], "domain")==0)
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ access_mask,
+ &domain_sid, &domain_pol);
+ else if (StrCaseCmp(argv[1], "builtin")==0)
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ access_mask,
+ CONST_DISCARD(struct dom_sid2 *, &global_sid_Builtin),
+ &domain_pol);
+ else {
+ printf("Usage: %s builtin|domain sid1 sid2 ...\n", argv[0]);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_GetAliasMembership(cli, mem_ctx,
+ &domain_pol,
+ &sid_array,
+ &alias_rids);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ for (i = 0; i < alias_rids.count; i++) {
+ printf("\tgroup rid:[0x%x]\n", alias_rids.ids[i]);
+ }
+
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ done:
+ return result;
+}
+
+/* Query members of a group */
+
+static NTSTATUS cmd_samr_query_groupmem(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, group_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 group_rid;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ int i;
+ unsigned int old_timeout;
+ struct samr_RidTypeArray *rids = NULL;
+
+ if ((argc < 2) || (argc > 3)) {
+ printf("Usage: %s rid [access mask]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ sscanf(argv[1], "%i", &group_rid);
+
+ if (argc > 2)
+ sscanf(argv[2], "%x", &access_mask);
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_OpenGroup(cli, mem_ctx,
+ &domain_pol,
+ access_mask,
+ group_rid,
+ &group_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Make sure to wait for our DC's reply */
+ old_timeout = rpccli_set_timeout(cli, 30000); /* 30 seconds. */
+ rpccli_set_timeout(cli, MAX(30000, old_timeout)); /* At least 30 sec */
+
+ result = rpccli_samr_QueryGroupMember(cli, mem_ctx,
+ &group_pol,
+ &rids);
+
+ rpccli_set_timeout(cli, old_timeout);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ for (i = 0; i < rids->count; i++) {
+ printf("\trid:[0x%x] attr:[0x%x]\n", rids->rids[i],
+ rids->types[i]);
+ }
+
+ rpccli_samr_Close(cli, mem_ctx, &group_pol);
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ done:
+ return result;
+}
+
+/* Enumerate domain users */
+
+static NTSTATUS cmd_samr_enum_dom_users(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 start_idx, size, num_dom_users, i;
+ struct samr_SamArray *dom_users = NULL;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ uint32 acb_mask = ACB_NORMAL;
+ bool got_connect_pol = False, got_domain_pol = False;
+
+ if ((argc < 1) || (argc > 3)) {
+ printf("Usage: %s [access_mask] [acb_mask]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc > 1)
+ sscanf(argv[1], "%x", &access_mask);
+
+ if (argc > 2)
+ sscanf(argv[2], "%x", &acb_mask);
+
+ /* Get sam policy handle */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ got_connect_pol = True;
+
+ /* Get domain policy handle */
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ access_mask,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ got_domain_pol = True;
+
+ /* Enumerate domain users */
+
+ start_idx = 0;
+ size = 0xffff;
+
+ do {
+ result = rpccli_samr_EnumDomainUsers(cli, mem_ctx,
+ &domain_pol,
+ &start_idx,
+ acb_mask,
+ &dom_users,
+ size,
+ &num_dom_users);
+
+ if (NT_STATUS_IS_OK(result) ||
+ NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES)) {
+
+ for (i = 0; i < num_dom_users; i++)
+ printf("user:[%s] rid:[0x%x]\n",
+ dom_users->entries[i].name.string,
+ dom_users->entries[i].idx);
+ }
+
+ } while (NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES));
+
+ done:
+ if (got_domain_pol)
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+
+ if (got_connect_pol)
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+
+ return result;
+}
+
+/* Enumerate domain groups */
+
+static NTSTATUS cmd_samr_enum_dom_groups(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 start_idx, size, num_dom_groups, i;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ struct samr_SamArray *dom_groups = NULL;
+ bool got_connect_pol = False, got_domain_pol = False;
+
+ if ((argc < 1) || (argc > 2)) {
+ printf("Usage: %s [access_mask]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc > 1)
+ sscanf(argv[1], "%x", &access_mask);
+
+ /* Get sam policy handle */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ got_connect_pol = True;
+
+ /* Get domain policy handle */
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ access_mask,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ got_domain_pol = True;
+
+ /* Enumerate domain groups */
+
+ start_idx = 0;
+ size = 0xffff;
+
+ do {
+ result = rpccli_samr_EnumDomainGroups(cli, mem_ctx,
+ &domain_pol,
+ &start_idx,
+ &dom_groups,
+ size,
+ &num_dom_groups);
+ if (NT_STATUS_IS_OK(result) ||
+ NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES)) {
+
+ for (i = 0; i < num_dom_groups; i++)
+ printf("group:[%s] rid:[0x%x]\n",
+ dom_groups->entries[i].name.string,
+ dom_groups->entries[i].idx);
+ }
+
+ } while (NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES));
+
+ done:
+ if (got_domain_pol)
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+
+ if (got_connect_pol)
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+
+ return result;
+}
+
+/* Enumerate alias groups */
+
+static NTSTATUS cmd_samr_enum_als_groups(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 start_idx, size, num_als_groups, i;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ struct samr_SamArray *als_groups = NULL;
+ bool got_connect_pol = False, got_domain_pol = False;
+
+ if ((argc < 2) || (argc > 3)) {
+ printf("Usage: %s builtin|domain [access mask]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc > 2)
+ sscanf(argv[2], "%x", &access_mask);
+
+ /* Get sam policy handle */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ got_connect_pol = True;
+
+ /* Get domain policy handle */
+
+ if (StrCaseCmp(argv[1], "domain")==0)
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ access_mask,
+ &domain_sid,
+ &domain_pol);
+ else if (StrCaseCmp(argv[1], "builtin")==0)
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ access_mask,
+ CONST_DISCARD(struct dom_sid2 *, &global_sid_Builtin),
+ &domain_pol);
+ else
+ return NT_STATUS_OK;
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ got_domain_pol = True;
+
+ /* Enumerate alias groups */
+
+ start_idx = 0;
+ size = 0xffff; /* Number of groups to retrieve */
+
+ do {
+ result = rpccli_samr_EnumDomainAliases(cli, mem_ctx,
+ &domain_pol,
+ &start_idx,
+ &als_groups,
+ size,
+ &num_als_groups);
+
+ if (NT_STATUS_IS_OK(result) ||
+ NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES)) {
+
+ for (i = 0; i < num_als_groups; i++)
+ printf("group:[%s] rid:[0x%x]\n",
+ als_groups->entries[i].name.string,
+ als_groups->entries[i].idx);
+ }
+ } while (NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES));
+
+ done:
+ if (got_domain_pol)
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+
+ if (got_connect_pol)
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+
+ return result;
+}
+
+/* Enumerate domains */
+
+static NTSTATUS cmd_samr_enum_domains(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 start_idx, size, num_entries, i;
+ uint32 access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ bool got_connect_pol = false;
+ struct samr_SamArray *sam = NULL;
+
+ if ((argc < 1) || (argc > 2)) {
+ printf("Usage: %s [access mask]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc > 1) {
+ sscanf(argv[1], "%x", &access_mask);
+ }
+
+ /* Get sam policy handle */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ access_mask,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ got_connect_pol = true;
+
+ /* Enumerate alias groups */
+
+ start_idx = 0;
+ size = 0xffff;
+
+ do {
+ result = rpccli_samr_EnumDomains(cli, mem_ctx,
+ &connect_pol,
+ &start_idx,
+ &sam,
+ size,
+ &num_entries);
+
+ if (NT_STATUS_IS_OK(result) ||
+ NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES)) {
+
+ for (i = 0; i < num_entries; i++)
+ printf("name:[%s] idx:[0x%x]\n",
+ sam->entries[i].name.string,
+ sam->entries[i].idx);
+ }
+ } while (NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES));
+
+ done:
+ if (got_connect_pol) {
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ }
+
+ return result;
+}
+
+
+/* Query alias membership */
+
+static NTSTATUS cmd_samr_query_aliasmem(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, alias_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 alias_rid, i;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ struct lsa_SidArray sid_array;
+
+ if ((argc < 3) || (argc > 4)) {
+ printf("Usage: %s builtin|domain rid [access mask]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ sscanf(argv[2], "%i", &alias_rid);
+
+ if (argc > 3)
+ sscanf(argv[3], "%x", &access_mask);
+
+ /* Open SAMR handle */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Open handle on domain */
+
+ if (StrCaseCmp(argv[1], "domain")==0)
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid,
+ &domain_pol);
+ else if (StrCaseCmp(argv[1], "builtin")==0)
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ CONST_DISCARD(struct dom_sid2 *, &global_sid_Builtin),
+ &domain_pol);
+ else
+ return NT_STATUS_OK;
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Open handle on alias */
+
+ result = rpccli_samr_OpenAlias(cli, mem_ctx,
+ &domain_pol,
+ access_mask,
+ alias_rid,
+ &alias_pol);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_GetMembersInAlias(cli, mem_ctx,
+ &alias_pol,
+ &sid_array);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ for (i = 0; i < sid_array.num_sids; i++) {
+ fstring sid_str;
+
+ sid_to_fstring(sid_str, sid_array.sids[i].sid);
+ printf("\tsid:[%s]\n", sid_str);
+ }
+
+ rpccli_samr_Close(cli, mem_ctx, &alias_pol);
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ done:
+ return result;
+}
+
+/* Query alias info */
+
+static NTSTATUS cmd_samr_query_aliasinfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, alias_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32_t alias_rid;
+ uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ union samr_AliasInfo *info = NULL;
+ enum samr_AliasInfoEnum level = ALIASINFOALL;
+
+ if ((argc < 3) || (argc > 4)) {
+ printf("Usage: %s builtin|domain rid [level] [access mask]\n",
+ argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ sscanf(argv[2], "%i", &alias_rid);
+
+ if (argc > 2) {
+ level = atoi(argv[3]);
+ }
+
+ if (argc > 3) {
+ sscanf(argv[4], "%x", &access_mask);
+ }
+
+ /* Open SAMR handle */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Open handle on domain */
+
+ if (strequal(argv[1], "domain")) {
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ &domain_sid,
+ &domain_pol);
+
+ } else if (strequal(argv[1], "builtin")) {
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ CONST_DISCARD(struct dom_sid2 *, &global_sid_Builtin),
+ &domain_pol);
+
+ } else {
+ return NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Open handle on alias */
+
+ result = rpccli_samr_OpenAlias(cli, mem_ctx,
+ &domain_pol,
+ access_mask,
+ alias_rid,
+ &alias_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_samr_QueryAliasInfo(cli, mem_ctx,
+ &alias_pol,
+ level,
+ &info);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ switch (level) {
+ case ALIASINFOALL:
+ printf("Name: %s\n", info->all.name.string);
+ printf("Description: %s\n", info->all.description.string);
+ printf("Num Members: %d\n", info->all.num_members);
+ break;
+ case ALIASINFONAME:
+ printf("Name: %s\n", info->name.string);
+ break;
+ case ALIASINFODESCRIPTION:
+ printf("Description: %s\n", info->description.string);
+ break;
+ default:
+ break;
+ }
+
+ rpccli_samr_Close(cli, mem_ctx, &alias_pol);
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ done:
+ return result;
+}
+
+
+/* Query delete an alias membership */
+
+static NTSTATUS cmd_samr_delete_alias(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, alias_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 alias_rid;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+
+ if (argc != 3) {
+ printf("Usage: %s builtin|domain [rid|name]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ alias_rid = strtoul(argv[2], NULL, 10);
+
+ /* Open SAMR handle */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Open handle on domain */
+
+ if (StrCaseCmp(argv[1], "domain")==0)
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid,
+ &domain_pol);
+ else if (StrCaseCmp(argv[1], "builtin")==0)
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ CONST_DISCARD(struct dom_sid2 *, &global_sid_Builtin),
+ &domain_pol);
+ else
+ return NT_STATUS_INVALID_PARAMETER;
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Open handle on alias */
+
+ result = rpccli_samr_OpenAlias(cli, mem_ctx,
+ &domain_pol,
+ access_mask,
+ alias_rid,
+ &alias_pol);
+ if (!NT_STATUS_IS_OK(result) && (alias_rid == 0)) {
+ /* Probably this was a user name, try lookupnames */
+ struct samr_Ids rids, types;
+ struct lsa_String lsa_acct_name;
+
+ init_lsa_String(&lsa_acct_name, argv[2]);
+
+ result = rpccli_samr_LookupNames(cli, mem_ctx,
+ &domain_pol,
+ 1,
+ &lsa_acct_name,
+ &rids,
+ &types);
+
+ if (NT_STATUS_IS_OK(result)) {
+ result = rpccli_samr_OpenAlias(cli, mem_ctx,
+ &domain_pol,
+ access_mask,
+ rids.ids[0],
+ &alias_pol);
+ }
+ }
+
+ result = rpccli_samr_DeleteDomAlias(cli, mem_ctx,
+ &alias_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ done:
+ return result;
+}
+
+/* Query display info */
+
+static NTSTATUS cmd_samr_query_dispinfo_internal(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv,
+ uint32_t opcode)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 start_idx=0, max_entries=250, max_size = 0xffff, num_entries = 0, i;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ uint32 info_level = 1;
+ union samr_DispInfo info;
+ int loop_count = 0;
+ bool got_params = False; /* Use get_query_dispinfo_params() or not? */
+ uint32_t total_size, returned_size;
+
+ if (argc > 6) {
+ printf("Usage: %s [info level] [start index] [max entries] [max size] [access mask]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc >= 2)
+ sscanf(argv[1], "%i", &info_level);
+
+ if (argc >= 3)
+ sscanf(argv[2], "%i", &start_idx);
+
+ if (argc >= 4) {
+ sscanf(argv[3], "%i", &max_entries);
+ got_params = True;
+ }
+
+ if (argc >= 5) {
+ sscanf(argv[4], "%i", &max_size);
+ got_params = True;
+ }
+
+ if (argc >= 6)
+ sscanf(argv[5], "%x", &access_mask);
+
+ /* Get sam policy handle */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Get domain policy handle */
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ access_mask,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Query display info */
+
+ do {
+
+ if (!got_params)
+ get_query_dispinfo_params(
+ loop_count, &max_entries, &max_size);
+
+ switch (opcode) {
+ case NDR_SAMR_QUERYDISPLAYINFO:
+ result = rpccli_samr_QueryDisplayInfo(cli, mem_ctx,
+ &domain_pol,
+ info_level,
+ start_idx,
+ max_entries,
+ max_size,
+ &total_size,
+ &returned_size,
+ &info);
+ break;
+ case NDR_SAMR_QUERYDISPLAYINFO2:
+ result = rpccli_samr_QueryDisplayInfo2(cli, mem_ctx,
+ &domain_pol,
+ info_level,
+ start_idx,
+ max_entries,
+ max_size,
+ &total_size,
+ &returned_size,
+ &info);
+
+ break;
+ case NDR_SAMR_QUERYDISPLAYINFO3:
+ result = rpccli_samr_QueryDisplayInfo3(cli, mem_ctx,
+ &domain_pol,
+ info_level,
+ start_idx,
+ max_entries,
+ max_size,
+ &total_size,
+ &returned_size,
+ &info);
+
+ break;
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, NT_STATUS_NO_MORE_ENTRIES) &&
+ !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) {
+ break;
+ }
+
+ loop_count++;
+
+ switch (info_level) {
+ case 1:
+ num_entries = info.info1.count;
+ break;
+ case 2:
+ num_entries = info.info2.count;
+ break;
+ case 3:
+ num_entries = info.info3.count;
+ break;
+ case 4:
+ num_entries = info.info4.count;
+ break;
+ case 5:
+ num_entries = info.info5.count;
+ break;
+ default:
+ break;
+ }
+
+ start_idx += num_entries;
+
+ if (num_entries == 0)
+ break;
+
+ for (i = 0; i < num_entries; i++) {
+ switch (info_level) {
+ case 1:
+ display_sam_info_1(&info.info1.entries[i]);
+ break;
+ case 2:
+ display_sam_info_2(&info.info2.entries[i]);
+ break;
+ case 3:
+ display_sam_info_3(&info.info3.entries[i]);
+ break;
+ case 4:
+ display_sam_info_4(&info.info4.entries[i]);
+ break;
+ case 5:
+ display_sam_info_5(&info.info5.entries[i]);
+ break;
+ }
+ }
+ } while ( NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
+
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ done:
+ return result;
+}
+
+static NTSTATUS cmd_samr_query_dispinfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ return cmd_samr_query_dispinfo_internal(cli, mem_ctx, argc, argv,
+ NDR_SAMR_QUERYDISPLAYINFO);
+}
+
+static NTSTATUS cmd_samr_query_dispinfo2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ return cmd_samr_query_dispinfo_internal(cli, mem_ctx, argc, argv,
+ NDR_SAMR_QUERYDISPLAYINFO2);
+}
+
+static NTSTATUS cmd_samr_query_dispinfo3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ return cmd_samr_query_dispinfo_internal(cli, mem_ctx, argc, argv,
+ NDR_SAMR_QUERYDISPLAYINFO3);
+}
+
+/* Query domain info */
+
+static NTSTATUS cmd_samr_query_dominfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 switch_level = 2;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ union samr_DomainInfo *info = NULL;
+
+ if (argc > 3) {
+ printf("Usage: %s [info level] [access mask]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc > 1)
+ sscanf(argv[1], "%i", &switch_level);
+
+ if (argc > 2)
+ sscanf(argv[2], "%x", &access_mask);
+
+ /* Get sam policy handle */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Get domain policy handle */
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ access_mask,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Query domain info */
+
+ result = rpccli_samr_QueryDomainInfo(cli, mem_ctx,
+ &domain_pol,
+ switch_level,
+ &info);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Display domain info */
+
+ switch (switch_level) {
+ case 1:
+ display_sam_dom_info_1(&info->info1);
+ break;
+ case 2:
+ display_sam_dom_info_2(&info->info2);
+ break;
+ case 3:
+ display_sam_dom_info_3(&info->info3);
+ break;
+ case 4:
+ display_sam_dom_info_4(&info->info4);
+ break;
+ case 5:
+ display_sam_dom_info_5(&info->info5);
+ break;
+ case 6:
+ display_sam_dom_info_6(&info->info6);
+ break;
+ case 7:
+ display_sam_dom_info_7(&info->info7);
+ break;
+ case 8:
+ display_sam_dom_info_8(&info->info8);
+ break;
+ case 9:
+ display_sam_dom_info_9(&info->info9);
+ break;
+ case 12:
+ display_sam_dom_info_12(&info->info12);
+ break;
+ case 13:
+ display_sam_dom_info_13(&info->info13);
+ break;
+
+ default:
+ printf("cannot display domain info for switch value %d\n",
+ switch_level);
+ break;
+ }
+
+ done:
+
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ return result;
+}
+
+/* Create domain user */
+
+static NTSTATUS cmd_samr_create_dom_user(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, user_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct lsa_String acct_name;
+ uint32 acb_info;
+ uint32 acct_flags, user_rid;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ uint32_t access_granted = 0;
+
+ if ((argc < 2) || (argc > 3)) {
+ printf("Usage: %s username [access mask]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ init_lsa_String(&acct_name, argv[1]);
+
+ if (argc > 2)
+ sscanf(argv[2], "%x", &access_mask);
+
+ /* Get sam policy handle */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Get domain policy handle */
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ access_mask,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Create domain user */
+
+ acb_info = ACB_NORMAL;
+ acct_flags = SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
+ SEC_STD_WRITE_DAC | SEC_STD_DELETE |
+ SAMR_USER_ACCESS_SET_PASSWORD |
+ SAMR_USER_ACCESS_GET_ATTRIBUTES |
+ SAMR_USER_ACCESS_SET_ATTRIBUTES;
+
+ result = rpccli_samr_CreateUser2(cli, mem_ctx,
+ &domain_pol,
+ &acct_name,
+ acb_info,
+ acct_flags,
+ &user_pol,
+ &access_granted,
+ &user_rid);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_Close(cli, mem_ctx, &user_pol);
+ if (!NT_STATUS_IS_OK(result)) goto done;
+
+ result = rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) goto done;
+
+ result = rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) goto done;
+
+ done:
+ return result;
+}
+
+/* Create domain group */
+
+static NTSTATUS cmd_samr_create_dom_group(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, group_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct lsa_String grp_name;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ uint32_t rid = 0;
+
+ if ((argc < 2) || (argc > 3)) {
+ printf("Usage: %s groupname [access mask]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ init_lsa_String(&grp_name, argv[1]);
+
+ if (argc > 2)
+ sscanf(argv[2], "%x", &access_mask);
+
+ /* Get sam policy handle */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Get domain policy handle */
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ access_mask,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Create domain user */
+ result = rpccli_samr_CreateDomainGroup(cli, mem_ctx,
+ &domain_pol,
+ &grp_name,
+ MAXIMUM_ALLOWED_ACCESS,
+ &group_pol,
+ &rid);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_Close(cli, mem_ctx, &group_pol);
+ if (!NT_STATUS_IS_OK(result)) goto done;
+
+ result = rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) goto done;
+
+ result = rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) goto done;
+
+ done:
+ return result;
+}
+
+/* Create domain alias */
+
+static NTSTATUS cmd_samr_create_dom_alias(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, alias_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct lsa_String alias_name;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ uint32_t rid = 0;
+
+ if ((argc < 2) || (argc > 3)) {
+ printf("Usage: %s aliasname [access mask]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ init_lsa_String(&alias_name, argv[1]);
+
+ if (argc > 2)
+ sscanf(argv[2], "%x", &access_mask);
+
+ /* Get sam policy handle */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Get domain policy handle */
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ access_mask,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Create domain user */
+
+ result = rpccli_samr_CreateDomAlias(cli, mem_ctx,
+ &domain_pol,
+ &alias_name,
+ MAXIMUM_ALLOWED_ACCESS,
+ &alias_pol,
+ &rid);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_Close(cli, mem_ctx, &alias_pol);
+ if (!NT_STATUS_IS_OK(result)) goto done;
+
+ result = rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) goto done;
+
+ result = rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) goto done;
+
+ done:
+ return result;
+}
+
+/* Lookup sam names */
+
+static NTSTATUS cmd_samr_lookup_names(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ POLICY_HND connect_pol, domain_pol;
+ uint32 num_names;
+ struct samr_Ids rids, name_types;
+ int i;
+ struct lsa_String *names = NULL;;
+
+ if (argc < 3) {
+ printf("Usage: %s domain|builtin name1 [name2 [name3] [...]]\n", argv[0]);
+ printf("check on the domain SID: S-1-5-21-x-y-z\n");
+ printf("or check on the builtin SID: S-1-5-32\n");
+ return NT_STATUS_OK;
+ }
+
+ /* Get sam policy and domain handles */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ if (StrCaseCmp(argv[1], "domain")==0)
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid,
+ &domain_pol);
+ else if (StrCaseCmp(argv[1], "builtin")==0)
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ CONST_DISCARD(struct dom_sid2 *, &global_sid_Builtin),
+ &domain_pol);
+ else
+ return NT_STATUS_OK;
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Look up names */
+
+ num_names = argc - 2;
+
+ if ((names = TALLOC_ARRAY(mem_ctx, struct lsa_String, num_names)) == NULL) {
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i = 0; i < num_names; i++) {
+ init_lsa_String(&names[i], argv[i + 2]);
+ }
+
+ result = rpccli_samr_LookupNames(cli, mem_ctx,
+ &domain_pol,
+ num_names,
+ names,
+ &rids,
+ &name_types);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Display results */
+
+ for (i = 0; i < num_names; i++)
+ printf("name %s: 0x%x (%d)\n", names[i].string, rids.ids[i],
+ name_types.ids[i]);
+
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ done:
+ return result;
+}
+
+/* Lookup sam rids */
+
+static NTSTATUS cmd_samr_lookup_rids(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ POLICY_HND connect_pol, domain_pol;
+ uint32_t num_rids, *rids;
+ struct lsa_Strings names;
+ struct samr_Ids types;
+
+ int i;
+
+ if (argc < 3) {
+ printf("Usage: %s domain|builtin rid1 [rid2 [rid3] [...]]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ /* Get sam policy and domain handles */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ if (StrCaseCmp(argv[1], "domain")==0)
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid,
+ &domain_pol);
+ else if (StrCaseCmp(argv[1], "builtin")==0)
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ CONST_DISCARD(struct dom_sid2 *, &global_sid_Builtin),
+ &domain_pol);
+ else
+ return NT_STATUS_OK;
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Look up rids */
+
+ num_rids = argc - 2;
+
+ if ((rids = TALLOC_ARRAY(mem_ctx, uint32, num_rids)) == NULL) {
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i = 0; i < argc - 2; i++)
+ sscanf(argv[i + 2], "%i", &rids[i]);
+
+ result = rpccli_samr_LookupRids(cli, mem_ctx,
+ &domain_pol,
+ num_rids,
+ rids,
+ &names,
+ &types);
+
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED))
+ goto done;
+
+ /* Display results */
+
+ for (i = 0; i < num_rids; i++) {
+ printf("rid 0x%x: %s (%d)\n",
+ rids[i], names.names[i].string, types.ids[i]);
+ }
+
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ done:
+ return result;
+}
+
+/* Delete domain group */
+
+static NTSTATUS cmd_samr_delete_dom_group(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ POLICY_HND connect_pol, domain_pol, group_pol;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+
+ if ((argc < 2) || (argc > 3)) {
+ printf("Usage: %s groupname\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc > 2)
+ sscanf(argv[2], "%x", &access_mask);
+
+ /* Get sam policy and domain handles */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Get handle on group */
+
+ {
+ struct samr_Ids group_rids, name_types;
+ struct lsa_String lsa_acct_name;
+
+ init_lsa_String(&lsa_acct_name, argv[1]);
+
+ result = rpccli_samr_LookupNames(cli, mem_ctx,
+ &domain_pol,
+ 1,
+ &lsa_acct_name,
+ &group_rids,
+ &name_types);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_OpenGroup(cli, mem_ctx,
+ &domain_pol,
+ access_mask,
+ group_rids.ids[0],
+ &group_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+ }
+
+ /* Delete group */
+
+ result = rpccli_samr_DeleteDomainGroup(cli, mem_ctx,
+ &group_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Display results */
+
+ rpccli_samr_Close(cli, mem_ctx, &group_pol);
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+
+ done:
+ return result;
+}
+
+/* Delete domain user */
+
+static NTSTATUS cmd_samr_delete_dom_user(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ POLICY_HND connect_pol, domain_pol, user_pol;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+
+ if ((argc < 2) || (argc > 3)) {
+ printf("Usage: %s username\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc > 2)
+ sscanf(argv[2], "%x", &access_mask);
+
+ /* Get sam policy and domain handles */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Get handle on user */
+
+ {
+ struct samr_Ids user_rids, name_types;
+ struct lsa_String lsa_acct_name;
+
+ init_lsa_String(&lsa_acct_name, argv[1]);
+
+ result = rpccli_samr_LookupNames(cli, mem_ctx,
+ &domain_pol,
+ 1,
+ &lsa_acct_name,
+ &user_rids,
+ &name_types);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_OpenUser(cli, mem_ctx,
+ &domain_pol,
+ access_mask,
+ user_rids.ids[0],
+ &user_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+ }
+
+ /* Delete user */
+
+ result = rpccli_samr_DeleteUser(cli, mem_ctx,
+ &user_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Display results */
+
+ rpccli_samr_Close(cli, mem_ctx, &user_pol);
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+
+ done:
+ return result;
+}
+
+/**********************************************************************
+ * Query user security object
+ */
+static NTSTATUS cmd_samr_query_sec_obj(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, user_pol, *pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 sec_info = DACL_SECURITY_INFORMATION;
+ uint32 user_rid = 0;
+ TALLOC_CTX *ctx = NULL;
+ SEC_DESC_BUF *sec_desc_buf=NULL;
+ bool domain = False;
+
+ ctx=talloc_init("cmd_samr_query_sec_obj");
+
+ if ((argc < 1) || (argc > 3)) {
+ printf("Usage: %s [rid|-d] [sec_info]\n", argv[0]);
+ printf("\tSpecify rid for security on user, -d for security on domain\n");
+ talloc_destroy(ctx);
+ return NT_STATUS_OK;
+ }
+
+ if (argc > 1) {
+ if (strcmp(argv[1], "-d") == 0)
+ domain = True;
+ else
+ sscanf(argv[1], "%i", &user_rid);
+ }
+
+ if (argc == 3) {
+ sec_info = atoi(argv[2]);
+ }
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ if (domain || user_rid)
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ if (user_rid)
+ result = rpccli_samr_OpenUser(cli, mem_ctx,
+ &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ user_rid,
+ &user_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Pick which query pol to use */
+
+ pol = &connect_pol;
+
+ if (domain)
+ pol = &domain_pol;
+
+ if (user_rid)
+ pol = &user_pol;
+
+ /* Query SAM security object */
+
+ result = rpccli_samr_QuerySecurity(cli, mem_ctx,
+ pol,
+ sec_info,
+ &sec_desc_buf);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ display_sec_desc(sec_desc_buf->sd);
+
+ rpccli_samr_Close(cli, mem_ctx, &user_pol);
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+done:
+ talloc_destroy(ctx);
+ return result;
+}
+
+static NTSTATUS cmd_samr_get_usrdom_pwinfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ POLICY_HND connect_pol, domain_pol, user_pol;
+ struct samr_PwInfo info;
+ uint32_t rid;
+
+ if (argc != 2) {
+ printf("Usage: %s rid\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ sscanf(argv[1], "%i", &rid);
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_samr_OpenUser(cli, mem_ctx,
+ &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ rid,
+ &user_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_samr_GetUserPwInfo(cli, mem_ctx, &user_pol, &info);
+ if (NT_STATUS_IS_OK(result)) {
+ printf("min_password_length: %d\n", info.min_password_length);
+ printf("%s\n",
+ NDR_PRINT_STRUCT_STRING(mem_ctx,
+ samr_PasswordProperties, &info.password_properties));
+ }
+
+ done:
+ rpccli_samr_Close(cli, mem_ctx, &user_pol);
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+
+ return result;
+}
+
+static NTSTATUS cmd_samr_get_dom_pwinfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct lsa_String domain_name;
+ struct samr_PwInfo info;
+
+ if (argc < 1 || argc > 3) {
+ printf("Usage: %s <domain>\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ init_lsa_String(&domain_name, argv[1]);
+
+ result = rpccli_samr_GetDomPwInfo(cli, mem_ctx, &domain_name, &info);
+
+ if (NT_STATUS_IS_OK(result)) {
+ printf("min_password_length: %d\n", info.min_password_length);
+ display_password_properties(info.password_properties);
+ }
+
+ return result;
+}
+
+/* Look up domain name */
+
+static NTSTATUS cmd_samr_lookup_domain(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ fstring sid_string;
+ struct lsa_String domain_name;
+ DOM_SID *sid = NULL;
+
+ if (argc != 2) {
+ printf("Usage: %s domain_name\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ init_lsa_String(&domain_name, argv[1]);
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ access_mask,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ access_mask,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_LookupDomain(cli, mem_ctx,
+ &connect_pol,
+ &domain_name,
+ &sid);
+
+ if (NT_STATUS_IS_OK(result)) {
+ sid_to_fstring(sid_string, sid);
+ printf("SAMR_LOOKUP_DOMAIN: Domain Name: %s Domain SID: %s\n",
+ argv[1], sid_string);
+ }
+
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+done:
+ return result;
+}
+
+/* Change user password */
+
+static NTSTATUS cmd_samr_chgpasswd(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, user_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ const char *user, *oldpass, *newpass;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ struct samr_Ids rids, types;
+ struct lsa_String lsa_acct_name;
+
+ if (argc < 3) {
+ printf("Usage: %s username oldpass newpass\n", argv[0]);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ user = argv[1];
+ oldpass = argv[2];
+ newpass = argv[3];
+
+ /* Get sam policy handle */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Get domain policy handle */
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ access_mask,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_acct_name, user);
+
+ result = rpccli_samr_LookupNames(cli, mem_ctx,
+ &domain_pol,
+ 1,
+ &lsa_acct_name,
+ &rids,
+ &types);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_samr_OpenUser(cli, mem_ctx,
+ &domain_pol,
+ access_mask,
+ rids.ids[0],
+ &user_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Change user password */
+ result = rpccli_samr_chgpasswd_user(cli, mem_ctx,
+ &user_pol,
+ newpass,
+ oldpass);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ done:
+ if (is_valid_policy_hnd(&user_pol)) {
+ rpccli_samr_Close(cli, mem_ctx, &user_pol);
+ }
+ if (is_valid_policy_hnd(&domain_pol)) {
+ rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ }
+ if (is_valid_policy_hnd(&connect_pol)) {
+ rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ }
+
+ return result;
+}
+
+
+/* Change user password */
+
+static NTSTATUS cmd_samr_chgpasswd2(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ const char *user, *oldpass, *newpass;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+
+ if (argc < 3) {
+ printf("Usage: %s username oldpass newpass\n", argv[0]);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ user = argv[1];
+ oldpass = argv[2];
+ newpass = argv[3];
+
+ /* Get sam policy handle */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Get domain policy handle */
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ access_mask,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Change user password */
+ result = rpccli_samr_chgpasswd_user2(cli, mem_ctx, user, newpass, oldpass);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) goto done;
+
+ result = rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) goto done;
+
+ done:
+ return result;
+}
+
+
+/* Change user password */
+
+static NTSTATUS cmd_samr_chgpasswd3(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ const char *user, *oldpass, *newpass;
+ uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+ struct samr_DomInfo1 *info = NULL;
+ struct samr_ChangeReject *reject = NULL;
+
+ if (argc < 3) {
+ printf("Usage: %s username oldpass newpass\n", argv[0]);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ user = argv[1];
+ oldpass = argv[2];
+ newpass = argv[3];
+
+ /* Get sam policy handle */
+
+ result = rpccli_try_samr_connects(cli, mem_ctx,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Get domain policy handle */
+
+ result = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_pol,
+ access_mask,
+ &domain_sid,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Change user password */
+ result = rpccli_samr_chgpasswd_user3(cli, mem_ctx,
+ user,
+ newpass,
+ oldpass,
+ &info,
+ &reject);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION)) {
+
+ display_sam_dom_info_1(info);
+
+ switch (reject->reason) {
+ case SAMR_REJECT_TOO_SHORT:
+ d_printf("SAMR_REJECT_TOO_SHORT\n");
+ break;
+ case SAMR_REJECT_IN_HISTORY:
+ d_printf("SAMR_REJECT_IN_HISTORY\n");
+ break;
+ case SAMR_REJECT_COMPLEXITY:
+ d_printf("SAMR_REJECT_COMPLEXITY\n");
+ break;
+ case SAMR_REJECT_OTHER:
+ d_printf("SAMR_REJECT_OTHER\n");
+ break;
+ default:
+ d_printf("unknown reject reason: %d\n",
+ reject->reason);
+ break;
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_Close(cli, mem_ctx, &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) goto done;
+
+ result = rpccli_samr_Close(cli, mem_ctx, &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) goto done;
+
+ done:
+ return result;
+}
+
+static NTSTATUS cmd_samr_get_dispinfo_idx(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ NTSTATUS status;
+ struct policy_handle connect_handle;
+ struct policy_handle domain_handle;
+ uint16_t level = 1;
+ struct lsa_String name;
+ uint32_t idx = 0;
+
+ if (argc < 2 || argc > 3) {
+ printf("Usage: %s name level\n", argv[0]);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ init_lsa_String(&name, argv[1]);
+
+ if (argc == 3) {
+ level = atoi(argv[2]);
+ }
+
+ status = rpccli_try_samr_connects(cli, mem_ctx,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &connect_handle);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = rpccli_samr_OpenDomain(cli, mem_ctx,
+ &connect_handle,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &domain_sid,
+ &domain_handle);
+
+ if (!NT_STATUS_IS_OK(status))
+ goto done;
+
+
+ status = rpccli_samr_GetDisplayEnumerationIndex(cli, mem_ctx,
+ &domain_handle,
+ level,
+ &name,
+ &idx);
+
+ if (NT_STATUS_IS_OK(status) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
+ printf("idx: %d (0x%08x)\n", idx, idx);
+ }
+ done:
+
+ if (is_valid_policy_hnd(&domain_handle)) {
+ rpccli_samr_Close(cli, mem_ctx, &domain_handle);
+ }
+ if (is_valid_policy_hnd(&connect_handle)) {
+ rpccli_samr_Close(cli, mem_ctx, &connect_handle);
+ }
+
+ return status;
+
+}
+/* List of commands exported by this module */
+
+struct cmd_set samr_commands[] = {
+
+ { "SAMR" },
+
+ { "queryuser", RPC_RTYPE_NTSTATUS, cmd_samr_query_user, NULL, &ndr_table_samr.syntax_id, NULL, "Query user info", "" },
+ { "querygroup", RPC_RTYPE_NTSTATUS, cmd_samr_query_group, NULL, &ndr_table_samr.syntax_id, NULL, "Query group info", "" },
+ { "queryusergroups", RPC_RTYPE_NTSTATUS, cmd_samr_query_usergroups, NULL, &ndr_table_samr.syntax_id, NULL, "Query user groups", "" },
+ { "queryuseraliases", RPC_RTYPE_NTSTATUS, cmd_samr_query_useraliases, NULL, &ndr_table_samr.syntax_id, NULL, "Query user aliases", "" },
+ { "querygroupmem", RPC_RTYPE_NTSTATUS, cmd_samr_query_groupmem, NULL, &ndr_table_samr.syntax_id, NULL, "Query group membership", "" },
+ { "queryaliasmem", RPC_RTYPE_NTSTATUS, cmd_samr_query_aliasmem, NULL, &ndr_table_samr.syntax_id, NULL, "Query alias membership", "" },
+ { "queryaliasinfo", RPC_RTYPE_NTSTATUS, cmd_samr_query_aliasinfo, NULL, &ndr_table_samr.syntax_id, NULL, "Query alias info", "" },
+ { "deletealias", RPC_RTYPE_NTSTATUS, cmd_samr_delete_alias, NULL, &ndr_table_samr.syntax_id, NULL, "Delete an alias", "" },
+ { "querydispinfo", RPC_RTYPE_NTSTATUS, cmd_samr_query_dispinfo, NULL, &ndr_table_samr.syntax_id, NULL, "Query display info", "" },
+ { "querydispinfo2", RPC_RTYPE_NTSTATUS, cmd_samr_query_dispinfo2, NULL, &ndr_table_samr.syntax_id, NULL, "Query display info", "" },
+ { "querydispinfo3", RPC_RTYPE_NTSTATUS, cmd_samr_query_dispinfo3, NULL, &ndr_table_samr.syntax_id, NULL, "Query display info", "" },
+ { "querydominfo", RPC_RTYPE_NTSTATUS, cmd_samr_query_dominfo, NULL, &ndr_table_samr.syntax_id, NULL, "Query domain info", "" },
+ { "enumdomusers", RPC_RTYPE_NTSTATUS, cmd_samr_enum_dom_users, NULL, &ndr_table_samr.syntax_id, NULL, "Enumerate domain users", "" },
+ { "enumdomgroups", RPC_RTYPE_NTSTATUS, cmd_samr_enum_dom_groups, NULL, &ndr_table_samr.syntax_id, NULL, "Enumerate domain groups", "" },
+ { "enumalsgroups", RPC_RTYPE_NTSTATUS, cmd_samr_enum_als_groups, NULL, &ndr_table_samr.syntax_id, NULL, "Enumerate alias groups", "" },
+ { "enumdomains", RPC_RTYPE_NTSTATUS, cmd_samr_enum_domains, NULL, &ndr_table_samr.syntax_id, NULL, "Enumerate domains", "" },
+
+ { "createdomuser", RPC_RTYPE_NTSTATUS, cmd_samr_create_dom_user, NULL, &ndr_table_samr.syntax_id, NULL, "Create domain user", "" },
+ { "createdomgroup", RPC_RTYPE_NTSTATUS, cmd_samr_create_dom_group, NULL, &ndr_table_samr.syntax_id, NULL, "Create domain group", "" },
+ { "createdomalias", RPC_RTYPE_NTSTATUS, cmd_samr_create_dom_alias, NULL, &ndr_table_samr.syntax_id, NULL, "Create domain alias", "" },
+ { "samlookupnames", RPC_RTYPE_NTSTATUS, cmd_samr_lookup_names, NULL, &ndr_table_samr.syntax_id, NULL, "Look up names", "" },
+ { "samlookuprids", RPC_RTYPE_NTSTATUS, cmd_samr_lookup_rids, NULL, &ndr_table_samr.syntax_id, NULL, "Look up names", "" },
+ { "deletedomgroup", RPC_RTYPE_NTSTATUS, cmd_samr_delete_dom_group, NULL, &ndr_table_samr.syntax_id, NULL, "Delete domain group", "" },
+ { "deletedomuser", RPC_RTYPE_NTSTATUS, cmd_samr_delete_dom_user, NULL, &ndr_table_samr.syntax_id, NULL, "Delete domain user", "" },
+ { "samquerysecobj", RPC_RTYPE_NTSTATUS, cmd_samr_query_sec_obj, NULL, &ndr_table_samr.syntax_id, NULL, "Query SAMR security object", "" },
+ { "getdompwinfo", RPC_RTYPE_NTSTATUS, cmd_samr_get_dom_pwinfo, NULL, &ndr_table_samr.syntax_id, NULL, "Retrieve domain password info", "" },
+ { "getusrdompwinfo", RPC_RTYPE_NTSTATUS, cmd_samr_get_usrdom_pwinfo, NULL, &ndr_table_samr.syntax_id, NULL, "Retrieve user domain password info", "" },
+
+ { "lookupdomain", RPC_RTYPE_NTSTATUS, cmd_samr_lookup_domain, NULL, &ndr_table_samr.syntax_id, NULL, "Lookup Domain Name", "" },
+ { "chgpasswd", RPC_RTYPE_NTSTATUS, cmd_samr_chgpasswd, NULL, &ndr_table_samr.syntax_id, NULL, "Change user password", "" },
+ { "chgpasswd2", RPC_RTYPE_NTSTATUS, cmd_samr_chgpasswd2, NULL, &ndr_table_samr.syntax_id, NULL, "Change user password", "" },
+ { "chgpasswd3", RPC_RTYPE_NTSTATUS, cmd_samr_chgpasswd3, NULL, &ndr_table_samr.syntax_id, NULL, "Change user password", "" },
+ { "getdispinfoidx", RPC_RTYPE_NTSTATUS, cmd_samr_get_dispinfo_idx, NULL, &ndr_table_samr.syntax_id, NULL, "Get Display Information Index", "" },
+ { NULL }
+};
diff --git a/source3/rpcclient/cmd_shutdown.c b/source3/rpcclient/cmd_shutdown.c
new file mode 100644
index 0000000000..f79c9aad02
--- /dev/null
+++ b/source3/rpcclient/cmd_shutdown.c
@@ -0,0 +1,117 @@
+/*
+ Unix SMB/CIFS implementation.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-1997,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ Copyright (C) Simo Sorce 2001,
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+#if 0 /* don't uncomment this unless you remove the getopt() calls */
+ /* use net rpc shutdown instead */
+
+/****************************************************************************
+nt shutdown init
+****************************************************************************/
+static NTSTATUS cmd_shutdown_init(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ fstring msg;
+ uint32 timeout = 20;
+ bool force = False;
+ bool reboot = False;
+ int opt;
+
+ *msg = 0;
+ optind = 0; /* TODO: test if this hack works on other systems too --simo */
+
+ while ((opt = getopt(argc, argv, "m:t:rf")) != EOF)
+ {
+ /*fprintf (stderr, "[%s]\n", argv[argc-1]);*/
+
+ switch (opt)
+ {
+ case 'm':
+ fstrcpy(msg, optarg);
+ /*fprintf (stderr, "[%s|%s]\n", optarg, msg);*/
+ break;
+
+ case 't':
+ timeout = atoi(optarg);
+ /*fprintf (stderr, "[%s|%d]\n", optarg, timeout);*/
+ break;
+
+ case 'r':
+ reboot = True;
+ break;
+
+ case 'f':
+ force = True;
+ break;
+
+ }
+ }
+
+ /* create an entry */
+ result = cli_shutdown_init(cli, mem_ctx, msg, timeout, reboot, force);
+
+ if (NT_STATUS_IS_OK(result))
+ DEBUG(5,("cmd_shutdown_init: query succeeded\n"));
+ else
+ DEBUG(5,("cmd_shutdown_init: query failed\n"));
+
+ return result;
+}
+
+/****************************************************************************
+abort a shutdown
+****************************************************************************/
+static NTSTATUS cmd_shutdown_abort(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ result = cli_shutdown_abort(cli, mem_ctx);
+
+ if (NT_STATUS_IS_OK(result))
+ DEBUG(5,("cmd_shutdown_abort: query succeeded\n"));
+ else
+ DEBUG(5,("cmd_shutdown_abort: query failed\n"));
+
+ return result;
+}
+#endif
+
+
+/* List of commands exported by this module */
+struct cmd_set shutdown_commands[] = {
+
+ { "SHUTDOWN" },
+
+#if 0
+ { "shutdowninit", RPC_RTYPE_NTSTATUS, cmd_shutdown_init, NULL, &ndr_table_initshutdown.syntax_id, "Remote Shutdown (over shutdown pipe)",
+ "syntax: shutdown [-m message] [-t timeout] [-r] [-h] [-f] (-r == reboot, -h == halt, -f == force)" },
+
+ { "shutdownabort", RPC_RTYPE_NTSTATUS, cmd_shutdown_abort, NULL, &ndr_table_initshutdown.syntax_id, "Abort Shutdown (over shutdown pipe)",
+ "syntax: shutdownabort" },
+#endif
+ { NULL }
+};
diff --git a/source3/rpcclient/cmd_spoolss.c b/source3/rpcclient/cmd_spoolss.c
new file mode 100644
index 0000000000..2a9f2b82bb
--- /dev/null
+++ b/source3/rpcclient/cmd_spoolss.c
@@ -0,0 +1,2782 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Gerald Carter 2001-2005
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+struct table_node {
+ const char *long_archi;
+ const char *short_archi;
+ int version;
+};
+
+/* The version int is used by getdrivers. Note that
+ all architecture strings that support mutliple
+ versions must be grouped together since enumdrivers
+ uses this property to prevent issuing multiple
+ enumdriver calls for the same arch */
+
+
+static const struct table_node archi_table[]= {
+
+ {"Windows 4.0", "WIN40", 0 },
+ {"Windows NT x86", "W32X86", 2 },
+ {"Windows NT x86", "W32X86", 3 },
+ {"Windows NT R4000", "W32MIPS", 2 },
+ {"Windows NT Alpha_AXP", "W32ALPHA", 2 },
+ {"Windows NT PowerPC", "W32PPC", 2 },
+ {"Windows IA64", "IA64", 3 },
+ {"Windows x64", "x64", 3 },
+ {NULL, "", -1 }
+};
+
+/**
+ * @file
+ *
+ * rpcclient module for SPOOLSS rpc pipe.
+ *
+ * This generally just parses and checks command lines, and then calls
+ * a cli_spoolss function.
+ **/
+
+/****************************************************************************
+ function to do the mapping between the long architecture name and
+ the short one.
+****************************************************************************/
+
+static const char *cmd_spoolss_get_short_archi(const char *long_archi)
+{
+ int i=-1;
+
+ DEBUG(107,("Getting architecture dependant directory\n"));
+ do {
+ i++;
+ } while ( (archi_table[i].long_archi!=NULL ) &&
+ StrCaseCmp(long_archi, archi_table[i].long_archi) );
+
+ if (archi_table[i].long_archi==NULL) {
+ DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
+ return NULL;
+ }
+
+ /* this might be client code - but shouldn't this be an fstrcpy etc? */
+
+
+ DEBUGADD(108,("index: [%d]\n", i));
+ DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
+ DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
+
+ return archi_table[i].short_archi;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_open_printer_ex(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ WERROR werror;
+ fstring printername;
+ fstring servername, user;
+ POLICY_HND hnd;
+
+ if (argc != 2) {
+ printf("Usage: %s <printername>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (!cli)
+ return WERR_GENERAL_FAILURE;
+
+ slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ fstrcpy(user, cli->auth->user_name);
+ fstrcpy(printername, argv[1]);
+
+ /* Open the printer handle */
+
+ werror = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
+ "", PRINTER_ALL_ACCESS,
+ servername, user, &hnd);
+
+ if (W_ERROR_IS_OK(werror)) {
+ printf("Printer %s opened successfully\n", printername);
+ werror = rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ printf("Error closing printer handle! (%s)\n",
+ get_dos_error_msg(werror));
+ }
+ }
+
+ return werror;
+}
+
+
+/****************************************************************************
+****************************************************************************/
+
+static void display_print_info_0(PRINTER_INFO_0 *i0)
+{
+ fstring name = "";
+ fstring servername = "";
+
+ if (!i0)
+ return;
+
+ rpcstr_pull(name, i0->printername.buffer, sizeof(name), -1, STR_TERMINATE);
+
+ rpcstr_pull(servername, i0->servername.buffer, sizeof(servername), -1,STR_TERMINATE);
+
+ printf("\tprintername:[%s]\n", name);
+ printf("\tservername:[%s]\n", servername);
+ printf("\tcjobs:[0x%x]\n", i0->cjobs);
+ printf("\ttotal_jobs:[0x%x]\n", i0->total_jobs);
+
+ printf("\t:date: [%d]-[%d]-[%d] (%d)\n", i0->year, i0->month,
+ i0->day, i0->dayofweek);
+ printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", i0->hour, i0->minute,
+ i0->second, i0->milliseconds);
+
+ printf("\tglobal_counter:[0x%x]\n", i0->global_counter);
+ printf("\ttotal_pages:[0x%x]\n", i0->total_pages);
+
+ printf("\tmajorversion:[0x%x]\n", i0->major_version);
+ printf("\tbuildversion:[0x%x]\n", i0->build_version);
+
+ printf("\tunknown7:[0x%x]\n", i0->unknown7);
+ printf("\tunknown8:[0x%x]\n", i0->unknown8);
+ printf("\tunknown9:[0x%x]\n", i0->unknown9);
+ printf("\tsession_counter:[0x%x]\n", i0->session_counter);
+ printf("\tunknown11:[0x%x]\n", i0->unknown11);
+ printf("\tprinter_errors:[0x%x]\n", i0->printer_errors);
+ printf("\tunknown13:[0x%x]\n", i0->unknown13);
+ printf("\tunknown14:[0x%x]\n", i0->unknown14);
+ printf("\tunknown15:[0x%x]\n", i0->unknown15);
+ printf("\tunknown16:[0x%x]\n", i0->unknown16);
+ printf("\tchange_id:[0x%x]\n", i0->change_id);
+ printf("\tunknown18:[0x%x]\n", i0->unknown18);
+ printf("\tstatus:[0x%x]\n", i0->status);
+ printf("\tunknown20:[0x%x]\n", i0->unknown20);
+ printf("\tc_setprinter:[0x%x]\n", i0->c_setprinter);
+ printf("\tunknown22:[0x%x]\n", i0->unknown22);
+ printf("\tunknown23:[0x%x]\n", i0->unknown23);
+ printf("\tunknown24:[0x%x]\n", i0->unknown24);
+ printf("\tunknown25:[0x%x]\n", i0->unknown25);
+ printf("\tunknown26:[0x%x]\n", i0->unknown26);
+ printf("\tunknown27:[0x%x]\n", i0->unknown27);
+ printf("\tunknown28:[0x%x]\n", i0->unknown28);
+ printf("\tunknown29:[0x%x]\n", i0->unknown29);
+
+ printf("\n");
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void display_print_info_1(PRINTER_INFO_1 *i1)
+{
+ fstring desc = "";
+ fstring name = "";
+ fstring comm = "";
+
+ rpcstr_pull(desc, i1->description.buffer, sizeof(desc), -1,
+ STR_TERMINATE);
+
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
+ rpcstr_pull(comm, i1->comment.buffer, sizeof(comm), -1, STR_TERMINATE);
+
+ printf("\tflags:[0x%x]\n", i1->flags);
+ printf("\tname:[%s]\n", name);
+ printf("\tdescription:[%s]\n", desc);
+ printf("\tcomment:[%s]\n", comm);
+
+ printf("\n");
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void display_print_info_2(PRINTER_INFO_2 *i2)
+{
+ fstring servername = "";
+ fstring printername = "";
+ fstring sharename = "";
+ fstring portname = "";
+ fstring drivername = "";
+ fstring comment = "";
+ fstring location = "";
+ fstring sepfile = "";
+ fstring printprocessor = "";
+ fstring datatype = "";
+ fstring parameters = "";
+
+ rpcstr_pull(servername, i2->servername.buffer,sizeof(servername), -1, STR_TERMINATE);
+ rpcstr_pull(printername, i2->printername.buffer,sizeof(printername), -1, STR_TERMINATE);
+ rpcstr_pull(sharename, i2->sharename.buffer,sizeof(sharename), -1, STR_TERMINATE);
+ rpcstr_pull(portname, i2->portname.buffer,sizeof(portname), -1, STR_TERMINATE);
+ rpcstr_pull(drivername, i2->drivername.buffer,sizeof(drivername), -1, STR_TERMINATE);
+ rpcstr_pull(comment, i2->comment.buffer,sizeof(comment), -1, STR_TERMINATE);
+ rpcstr_pull(location, i2->location.buffer,sizeof(location), -1, STR_TERMINATE);
+ rpcstr_pull(sepfile, i2->sepfile.buffer,sizeof(sepfile), -1, STR_TERMINATE);
+ rpcstr_pull(printprocessor, i2->printprocessor.buffer,sizeof(printprocessor), -1, STR_TERMINATE);
+ rpcstr_pull(datatype, i2->datatype.buffer,sizeof(datatype), -1, STR_TERMINATE);
+ rpcstr_pull(parameters, i2->parameters.buffer,sizeof(parameters), -1, STR_TERMINATE);
+
+ printf("\tservername:[%s]\n", servername);
+ printf("\tprintername:[%s]\n", printername);
+ printf("\tsharename:[%s]\n", sharename);
+ printf("\tportname:[%s]\n", portname);
+ printf("\tdrivername:[%s]\n", drivername);
+ printf("\tcomment:[%s]\n", comment);
+ printf("\tlocation:[%s]\n", location);
+ printf("\tsepfile:[%s]\n", sepfile);
+ printf("\tprintprocessor:[%s]\n", printprocessor);
+ printf("\tdatatype:[%s]\n", datatype);
+ printf("\tparameters:[%s]\n", parameters);
+ printf("\tattributes:[0x%x]\n", i2->attributes);
+ printf("\tpriority:[0x%x]\n", i2->priority);
+ printf("\tdefaultpriority:[0x%x]\n", i2->defaultpriority);
+ printf("\tstarttime:[0x%x]\n", i2->starttime);
+ printf("\tuntiltime:[0x%x]\n", i2->untiltime);
+ printf("\tstatus:[0x%x]\n", i2->status);
+ printf("\tcjobs:[0x%x]\n", i2->cjobs);
+ printf("\taverageppm:[0x%x]\n", i2->averageppm);
+
+ if (i2->secdesc)
+ display_sec_desc(i2->secdesc);
+
+ printf("\n");
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void display_print_info_3(PRINTER_INFO_3 *i3)
+{
+ display_sec_desc(i3->secdesc);
+
+ printf("\n");
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void display_print_info_7(PRINTER_INFO_7 *i7)
+{
+ fstring guid = "";
+ rpcstr_pull(guid, i7->guid.buffer,sizeof(guid), -1, STR_TERMINATE);
+ printf("\tguid:[%s]\n", guid);
+ printf("\taction:[0x%x]\n", i7->action);
+}
+
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_enum_printers(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ WERROR result;
+ uint32 info_level = 1;
+ PRINTER_INFO_CTR ctr;
+ uint32 i = 0, num_printers;
+ fstring name;
+
+ if (argc > 3)
+ {
+ printf("Usage: %s [level] [name]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 2)
+ info_level = atoi(argv[1]);
+
+ if (argc == 3)
+ fstrcpy(name, argv[2]);
+ else {
+ slprintf(name, sizeof(name)-1, "\\\\%s", cli->desthost);
+ strupper_m(name);
+ }
+
+ ZERO_STRUCT(ctr);
+
+ result = rpccli_spoolss_enum_printers(cli, mem_ctx, name, PRINTER_ENUM_LOCAL,
+ info_level, &num_printers, &ctr);
+
+ if (W_ERROR_IS_OK(result)) {
+
+ if (!num_printers) {
+ printf ("No printers returned.\n");
+ goto done;
+ }
+
+ for (i = 0; i < num_printers; i++) {
+ switch(info_level) {
+ case 0:
+ display_print_info_0(&ctr.printers_0[i]);
+ break;
+ case 1:
+ display_print_info_1(&ctr.printers_1[i]);
+ break;
+ case 2:
+ display_print_info_2(&ctr.printers_2[i]);
+ break;
+ case 3:
+ display_print_info_3(&ctr.printers_3[i]);
+ break;
+ default:
+ printf("unknown info level %d\n", info_level);
+ goto done;
+ }
+ }
+ }
+ done:
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void display_port_info_1(PORT_INFO_1 *i1)
+{
+ fstring buffer;
+
+ rpcstr_pull(buffer, i1->port_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
+ printf("\tPort Name:\t[%s]\n", buffer);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void display_port_info_2(PORT_INFO_2 *i2)
+{
+ fstring buffer;
+
+ rpcstr_pull(buffer, i2->port_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
+ printf("\tPort Name:\t[%s]\n", buffer);
+ rpcstr_pull(buffer, i2->monitor_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
+
+ printf("\tMonitor Name:\t[%s]\n", buffer);
+ rpcstr_pull(buffer, i2->description.buffer, sizeof(buffer), -1, STR_TERMINATE);
+
+ printf("\tDescription:\t[%s]\n", buffer);
+ printf("\tPort Type:\t" );
+ if ( i2->port_type ) {
+ int comma = 0; /* hack */
+ printf( "[" );
+ if ( i2->port_type & PORT_TYPE_READ ) {
+ printf( "Read" );
+ comma = 1;
+ }
+ if ( i2->port_type & PORT_TYPE_WRITE ) {
+ printf( "%sWrite", comma ? ", " : "" );
+ comma = 1;
+ }
+ /* These two have slightly different interpretations
+ on 95/98/ME but I'm disregarding that for now */
+ if ( i2->port_type & PORT_TYPE_REDIRECTED ) {
+ printf( "%sRedirected", comma ? ", " : "" );
+ comma = 1;
+ }
+ if ( i2->port_type & PORT_TYPE_NET_ATTACHED ) {
+ printf( "%sNet-Attached", comma ? ", " : "" );
+ }
+ printf( "]\n" );
+ } else {
+ printf( "[Unset]\n" );
+ }
+ printf("\tReserved:\t[%d]\n", i2->reserved);
+ printf("\n");
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_enum_ports(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ WERROR result;
+ uint32 info_level = 1;
+ PORT_INFO_CTR ctr;
+ uint32 returned;
+
+ if (argc > 2) {
+ printf("Usage: %s [level]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc == 2)
+ info_level = atoi(argv[1]);
+
+ /* Enumerate ports */
+
+ ZERO_STRUCT(ctr);
+
+ result = rpccli_spoolss_enum_ports(cli, mem_ctx, info_level, &returned, &ctr);
+
+ if (W_ERROR_IS_OK(result)) {
+ int i;
+
+ for (i = 0; i < returned; i++) {
+ switch (info_level) {
+ case 1:
+ display_port_info_1(&ctr.port.info_1[i]);
+ break;
+ case 2:
+ display_port_info_2(&ctr.port.info_2[i]);
+ break;
+ default:
+ printf("unknown info level %d\n", info_level);
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_setprinter(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND pol;
+ WERROR result;
+ uint32 info_level = 2;
+ bool opened_hnd = False;
+ PRINTER_INFO_CTR ctr;
+ fstring printername,
+ servername,
+ user,
+ comment;
+
+ if (argc == 1 || argc > 3) {
+ printf("Usage: %s printername comment\n", argv[0]);
+
+ return WERR_OK;
+ }
+
+ /* Open a printer handle */
+ if (argc == 3) {
+ fstrcpy(comment, argv[2]);
+ }
+
+ slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]);
+ fstrcpy(user, cli->auth->user_name);
+
+ /* get a printer handle */
+ result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
+ PRINTER_ALL_ACCESS, servername,
+ user, &pol);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ opened_hnd = True;
+
+ /* Get printer info */
+ result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+
+ /* Modify the comment. */
+ init_unistr(&ctr.printers_2->comment, comment);
+ ctr.printers_2->devmode = NULL;
+ ctr.printers_2->secdesc = NULL;
+
+ result = rpccli_spoolss_setprinter(cli, mem_ctx, &pol, info_level, &ctr, 0);
+ if (W_ERROR_IS_OK(result))
+ printf("Success in setting comment.\n");
+
+ done:
+ if (opened_hnd)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_setprintername(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND pol;
+ WERROR result;
+ uint32 info_level = 2;
+ bool opened_hnd = False;
+ PRINTER_INFO_CTR ctr;
+ fstring printername,
+ servername,
+ user,
+ new_printername;
+
+ if (argc == 1 || argc > 3) {
+ printf("Usage: %s printername new_printername\n", argv[0]);
+
+ return WERR_OK;
+ }
+
+ /* Open a printer handle */
+ if (argc == 3) {
+ fstrcpy(new_printername, argv[2]);
+ }
+
+ slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]);
+ fstrcpy(user, cli->auth->user_name);
+
+ /* get a printer handle */
+ result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
+ PRINTER_ALL_ACCESS, servername,
+ user, &pol);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ opened_hnd = True;
+
+ /* Get printer info */
+ result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ /* Modify the printername. */
+ init_unistr(&ctr.printers_2->printername, new_printername);
+ ctr.printers_2->devmode = NULL;
+ ctr.printers_2->secdesc = NULL;
+
+ result = rpccli_spoolss_setprinter(cli, mem_ctx, &pol, info_level, &ctr, 0);
+ if (W_ERROR_IS_OK(result))
+ printf("Success in setting printername.\n");
+
+ done:
+ if (opened_hnd)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_getprinter(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND pol;
+ WERROR result;
+ uint32 info_level = 1;
+ bool opened_hnd = False;
+ PRINTER_INFO_CTR ctr;
+ fstring printername,
+ servername,
+ user;
+
+ if (argc == 1 || argc > 3) {
+ printf("Usage: %s <printername> [level]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ /* Open a printer handle */
+ if (argc == 3) {
+ info_level = atoi(argv[2]);
+ }
+
+ slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]);
+ fstrcpy(user, cli->auth->user_name);
+
+ /* get a printer handle */
+
+ result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
+ "", MAXIMUM_ALLOWED_ACCESS,
+ servername, user, &pol);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ opened_hnd = True;
+
+ /* Get printer info */
+
+ result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ /* Display printer info */
+
+ switch (info_level) {
+ case 0:
+ display_print_info_0(ctr.printers_0);
+ break;
+ case 1:
+ display_print_info_1(ctr.printers_1);
+ break;
+ case 2:
+ display_print_info_2(ctr.printers_2);
+ break;
+ case 3:
+ display_print_info_3(ctr.printers_3);
+ break;
+ case 7:
+ display_print_info_7(ctr.printers_7);
+ break;
+ default:
+ printf("unknown info level %d\n", info_level);
+ break;
+ }
+
+ done:
+ if (opened_hnd)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void display_reg_value(REGISTRY_VALUE value)
+{
+ char *text = NULL;
+
+ switch(value.type) {
+ case REG_DWORD:
+ printf("%s: REG_DWORD: 0x%08x\n", value.valuename,
+ *((uint32 *) value.data_p));
+ break;
+ case REG_SZ:
+ rpcstr_pull_talloc(talloc_tos(),
+ &text,
+ value.data_p,
+ value.size,
+ STR_TERMINATE);
+ printf("%s: REG_SZ: %s\n", value.valuename, text ? text : "");
+ break;
+ case REG_BINARY: {
+ char *hex = hex_encode(NULL, value.data_p, value.size);
+ size_t i, len;
+ printf("%s: REG_BINARY:", value.valuename);
+ len = strlen(hex);
+ for (i=0; i<len; i++) {
+ if (hex[i] == '\0') {
+ break;
+ }
+ if (i%40 == 0) {
+ putchar('\n');
+ }
+ putchar(hex[i]);
+ }
+ TALLOC_FREE(hex);
+ putchar('\n');
+ break;
+ }
+ case REG_MULTI_SZ: {
+ uint32 i, num_values;
+ char **values;
+
+ if (!W_ERROR_IS_OK(reg_pull_multi_sz(NULL, value.data_p,
+ value.size, &num_values,
+ &values))) {
+ d_printf("reg_pull_multi_sz failed\n");
+ break;
+ }
+
+ for (i=0; i<num_values; i++) {
+ d_printf("%s\n", values[i]);
+ }
+ TALLOC_FREE(values);
+ break;
+ }
+ default:
+ printf("%s: unknown type %d\n", value.valuename, value.type);
+ }
+
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_getprinterdata(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND pol;
+ WERROR result;
+ bool opened_hnd = False;
+ fstring printername,
+ servername,
+ user;
+ const char *valuename;
+ REGISTRY_VALUE value;
+
+ if (argc != 3) {
+ printf("Usage: %s <printername> <valuename>\n", argv[0]);
+ printf("<printername> of . queries print server\n");
+ return WERR_OK;
+ }
+ valuename = argv[2];
+
+ /* Open a printer handle */
+
+ slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ if (strncmp(argv[1], ".", sizeof(".")) == 0)
+ fstrcpy(printername, servername);
+ else
+ slprintf(printername, sizeof(servername)-1, "%s\\%s",
+ servername, argv[1]);
+ fstrcpy(user, cli->auth->user_name);
+
+ /* get a printer handle */
+
+ result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
+ "", MAXIMUM_ALLOWED_ACCESS,
+ servername, user, &pol);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ opened_hnd = True;
+
+ /* Get printer info */
+
+ result = rpccli_spoolss_getprinterdata(cli, mem_ctx, &pol, valuename, &value);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ /* Display printer data */
+
+ fstrcpy(value.valuename, valuename);
+ display_reg_value(value);
+
+
+ done:
+ if (opened_hnd)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_getprinterdataex(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND pol;
+ WERROR result;
+ bool opened_hnd = False;
+ fstring printername,
+ servername,
+ user;
+ const char *valuename, *keyname;
+ REGISTRY_VALUE value;
+
+ if (argc != 4) {
+ printf("Usage: %s <printername> <keyname> <valuename>\n",
+ argv[0]);
+ printf("<printername> of . queries print server\n");
+ return WERR_OK;
+ }
+ valuename = argv[3];
+ keyname = argv[2];
+
+ /* Open a printer handle */
+
+ slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ if (strncmp(argv[1], ".", sizeof(".")) == 0)
+ fstrcpy(printername, servername);
+ else
+ slprintf(printername, sizeof(printername)-1, "%s\\%s",
+ servername, argv[1]);
+ fstrcpy(user, cli->auth->user_name);
+
+ /* get a printer handle */
+
+ result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
+ "", MAXIMUM_ALLOWED_ACCESS,
+ servername, user, &pol);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ opened_hnd = True;
+
+ /* Get printer info */
+
+ result = rpccli_spoolss_getprinterdataex(cli, mem_ctx, &pol, keyname,
+ valuename, &value);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ /* Display printer data */
+
+ fstrcpy(value.valuename, valuename);
+ display_reg_value(value);
+
+
+ done:
+ if (opened_hnd)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void display_print_driver_1(DRIVER_INFO_1 *i1)
+{
+ fstring name;
+ if (i1 == NULL)
+ return;
+
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
+
+ printf ("Printer Driver Info 1:\n");
+ printf ("\tDriver Name: [%s]\n\n", name);
+
+ return;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void display_print_driver_2(DRIVER_INFO_2 *i1)
+{
+ fstring name;
+ fstring architecture;
+ fstring driverpath;
+ fstring datafile;
+ fstring configfile;
+ if (i1 == NULL)
+ return;
+
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
+ rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE);
+ rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE);
+ rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE);
+ rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE);
+
+ printf ("Printer Driver Info 2:\n");
+ printf ("\tVersion: [%x]\n", i1->version);
+ printf ("\tDriver Name: [%s]\n", name);
+ printf ("\tArchitecture: [%s]\n", architecture);
+ printf ("\tDriver Path: [%s]\n", driverpath);
+ printf ("\tDatafile: [%s]\n", datafile);
+ printf ("\tConfigfile: [%s]\n\n", configfile);
+
+ return;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void display_print_driver_3(DRIVER_INFO_3 *i1)
+{
+ fstring name = "";
+ fstring architecture = "";
+ fstring driverpath = "";
+ fstring datafile = "";
+ fstring configfile = "";
+ fstring helpfile = "";
+ fstring dependentfiles = "";
+ fstring monitorname = "";
+ fstring defaultdatatype = "";
+
+ int length=0;
+ bool valid = True;
+
+ if (i1 == NULL)
+ return;
+
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
+ rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE);
+ rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE);
+ rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE);
+ rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE);
+ rpcstr_pull(helpfile, i1->helpfile.buffer, sizeof(helpfile), -1, STR_TERMINATE);
+ rpcstr_pull(monitorname, i1->monitorname.buffer, sizeof(monitorname), -1, STR_TERMINATE);
+ rpcstr_pull(defaultdatatype, i1->defaultdatatype.buffer, sizeof(defaultdatatype), -1, STR_TERMINATE);
+
+ printf ("Printer Driver Info 3:\n");
+ printf ("\tVersion: [%x]\n", i1->version);
+ printf ("\tDriver Name: [%s]\n",name);
+ printf ("\tArchitecture: [%s]\n", architecture);
+ printf ("\tDriver Path: [%s]\n", driverpath);
+ printf ("\tDatafile: [%s]\n", datafile);
+ printf ("\tConfigfile: [%s]\n", configfile);
+ printf ("\tHelpfile: [%s]\n\n", helpfile);
+
+ while (valid)
+ {
+ rpcstr_pull(dependentfiles, i1->dependentfiles+length, sizeof(dependentfiles), -1, STR_TERMINATE);
+
+ length+=strlen(dependentfiles)+1;
+
+ if (strlen(dependentfiles) > 0)
+ {
+ printf ("\tDependentfiles: [%s]\n", dependentfiles);
+ }
+ else
+ {
+ valid = False;
+ }
+ }
+
+ printf ("\n");
+
+ printf ("\tMonitorname: [%s]\n", monitorname);
+ printf ("\tDefaultdatatype: [%s]\n\n", defaultdatatype);
+
+ return;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_getdriver(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND pol;
+ WERROR werror;
+ uint32 info_level = 3;
+ bool opened_hnd = False;
+ PRINTER_DRIVER_CTR ctr;
+ fstring printername,
+ servername,
+ user;
+ uint32 i;
+ bool success = False;
+
+ if ((argc == 1) || (argc > 3))
+ {
+ printf("Usage: %s <printername> [level]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ /* get the arguments need to open the printer handle */
+ slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ fstrcpy(user, cli->auth->user_name);
+ slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]);
+ if (argc == 3)
+ info_level = atoi(argv[2]);
+
+ /* Open a printer handle */
+
+ werror = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
+ PRINTER_ACCESS_USE,
+ servername, user, &pol);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ printf("Error opening printer handle for %s!\n", printername);
+ return werror;
+ }
+
+ opened_hnd = True;
+
+ /* loop through and print driver info level for each architecture */
+
+ for (i=0; archi_table[i].long_archi!=NULL; i++) {
+
+ werror = rpccli_spoolss_getprinterdriver( cli, mem_ctx, &pol, info_level,
+ archi_table[i].long_archi, archi_table[i].version,
+ &ctr);
+
+ if (!W_ERROR_IS_OK(werror))
+ continue;
+
+ /* need at least one success */
+
+ success = True;
+
+ printf ("\n[%s]\n", archi_table[i].long_archi);
+
+ switch (info_level) {
+ case 1:
+ display_print_driver_1 (ctr.info1);
+ break;
+ case 2:
+ display_print_driver_2 (ctr.info2);
+ break;
+ case 3:
+ display_print_driver_3 (ctr.info3);
+ break;
+ default:
+ printf("unknown info level %d\n", info_level);
+ break;
+ }
+ }
+
+ /* Cleanup */
+
+ if (opened_hnd)
+ rpccli_spoolss_close_printer (cli, mem_ctx, &pol);
+
+ if ( success )
+ werror = WERR_OK;
+
+ return werror;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_enum_drivers(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ WERROR werror = WERR_OK;
+ uint32 info_level = 1;
+ PRINTER_DRIVER_CTR ctr;
+ uint32 i, j,
+ returned;
+
+ if (argc > 2) {
+ printf("Usage: enumdrivers [level]\n");
+ return WERR_OK;
+ }
+
+ if (argc == 2)
+ info_level = atoi(argv[1]);
+
+
+ /* loop through and print driver info level for each architecture */
+ for (i=0; archi_table[i].long_archi!=NULL; i++) {
+ /* check to see if we already asked for this architecture string */
+
+ if ( i>0 && strequal(archi_table[i].long_archi, archi_table[i-1].long_archi) )
+ continue;
+
+ werror = rpccli_spoolss_enumprinterdrivers(
+ cli, mem_ctx, info_level,
+ archi_table[i].long_archi, &returned, &ctr);
+
+ if (W_ERROR_V(werror) == W_ERROR_V(WERR_INVALID_ENVIRONMENT)) {
+ printf ("Server does not support environment [%s]\n",
+ archi_table[i].long_archi);
+ werror = WERR_OK;
+ continue;
+ }
+
+ if (returned == 0)
+ continue;
+
+ if (!W_ERROR_IS_OK(werror)) {
+ printf ("Error getting driver for environment [%s] - %d\n",
+ archi_table[i].long_archi, W_ERROR_V(werror));
+ continue;
+ }
+
+ printf ("\n[%s]\n", archi_table[i].long_archi);
+ switch (info_level)
+ {
+
+ case 1:
+ for (j=0; j < returned; j++) {
+ display_print_driver_1 (&ctr.info1[j]);
+ }
+ break;
+ case 2:
+ for (j=0; j < returned; j++) {
+ display_print_driver_2 (&ctr.info2[j]);
+ }
+ break;
+ case 3:
+ for (j=0; j < returned; j++) {
+ display_print_driver_3 (&ctr.info3[j]);
+ }
+ break;
+ default:
+ printf("unknown info level %d\n", info_level);
+ return WERR_UNKNOWN_LEVEL;
+ }
+ }
+
+ return werror;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void display_printdriverdir_1(DRIVER_DIRECTORY_1 *i1)
+{
+ fstring name;
+ if (i1 == NULL)
+ return;
+
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
+
+ printf ("\tDirectory Name:[%s]\n", name);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_getdriverdir(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ WERROR result;
+ fstring env;
+ DRIVER_DIRECTORY_CTR ctr;
+
+ if (argc > 2) {
+ printf("Usage: %s [environment]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ /* Get the arguments need to open the printer handle */
+
+ if (argc == 2)
+ fstrcpy (env, argv[1]);
+ else
+ fstrcpy (env, "Windows NT x86");
+
+ /* Get the directory. Only use Info level 1 */
+
+ result = rpccli_spoolss_getprinterdriverdir(cli, mem_ctx, 1, env, &ctr);
+
+ if (W_ERROR_IS_OK(result))
+ display_printdriverdir_1(ctr.info1);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void set_drv_info_3_env (DRIVER_INFO_3 *info, const char *arch)
+{
+
+ int i;
+
+ for (i=0; archi_table[i].long_archi != NULL; i++)
+ {
+ if (strcmp(arch, archi_table[i].short_archi) == 0)
+ {
+ info->version = archi_table[i].version;
+ init_unistr (&info->architecture, archi_table[i].long_archi);
+ break;
+ }
+ }
+
+ if (archi_table[i].long_archi == NULL)
+ {
+ DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
+ }
+
+ return;
+}
+
+
+/**************************************************************************
+ wrapper for strtok to get the next parameter from a delimited list.
+ Needed to handle the empty parameter string denoted by "NULL"
+ *************************************************************************/
+
+static char* get_driver_3_param (char* str, const char* delim, UNISTR* dest,
+ char **saveptr)
+{
+ char *ptr;
+
+ /* get the next token */
+ ptr = strtok_r(str, delim, saveptr);
+
+ /* a string of 'NULL' is used to represent an empty
+ parameter because two consecutive delimiters
+ will not return an empty string. See man strtok(3)
+ for details */
+ if (ptr && (StrCaseCmp(ptr, "NULL") == 0))
+ ptr = NULL;
+
+ if (dest != NULL)
+ init_unistr(dest, ptr);
+
+ return ptr;
+}
+
+/********************************************************************************
+ fill in the members of a DRIVER_INFO_3 struct using a character
+ string in the form of
+ <Long Printer Name>:<Driver File Name>:<Data File Name>:\
+ <Config File Name>:<Help File Name>:<Language Monitor Name>:\
+ <Default Data Type>:<Comma Separated list of Files>
+ *******************************************************************************/
+static bool init_drv_info_3_members ( TALLOC_CTX *mem_ctx, DRIVER_INFO_3 *info,
+ char *args )
+{
+ char *str, *str2;
+ uint32 len, i;
+ char *saveptr = NULL;
+
+ /* fill in the UNISTR fields */
+ str = get_driver_3_param (args, ":", &info->name, &saveptr);
+ str = get_driver_3_param (NULL, ":", &info->driverpath, &saveptr);
+ str = get_driver_3_param (NULL, ":", &info->datafile, &saveptr);
+ str = get_driver_3_param (NULL, ":", &info->configfile, &saveptr);
+ str = get_driver_3_param (NULL, ":", &info->helpfile, &saveptr);
+ str = get_driver_3_param (NULL, ":", &info->monitorname, &saveptr);
+ str = get_driver_3_param (NULL, ":", &info->defaultdatatype, &saveptr);
+
+ /* <Comma Separated List of Dependent Files> */
+ /* save the beginning of the string */
+ str2 = get_driver_3_param (NULL, ":", NULL, &saveptr);
+ str = str2;
+
+ /* begin to strip out each filename */
+ str = strtok_r(str, ",", &saveptr);
+ len = 0;
+ while (str != NULL)
+ {
+ /* keep a cumlative count of the str lengths */
+ len += strlen(str)+1;
+ str = strtok_r(NULL, ",", &saveptr);
+ }
+
+ /* allocate the space; add one extra slot for a terminating NULL.
+ Each filename is NULL terminated and the end contains a double
+ NULL */
+ if ((info->dependentfiles=TALLOC_ARRAY(mem_ctx, uint16, len+1)) == NULL)
+ {
+ DEBUG(0,("init_drv_info_3_members: Unable to malloc memory for dependenfiles\n"));
+ return False;
+ }
+ for (i=0; i<len; i++)
+ {
+ SSVAL(&info->dependentfiles[i], 0, str2[i]);
+ }
+ info->dependentfiles[len] = '\0';
+
+ return True;
+}
+
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_addprinterdriver(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ WERROR result;
+ uint32 level = 3;
+ PRINTER_DRIVER_CTR ctr;
+ DRIVER_INFO_3 info3;
+ const char *arch;
+ fstring driver_name;
+ char *driver_args;
+
+ /* parse the command arguments */
+ if (argc != 3 && argc != 4)
+ {
+ printf ("Usage: %s <Environment> \\\n", argv[0]);
+ printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
+ printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
+ printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n");
+ printf ("\t[version]\n");
+
+ return WERR_OK;
+ }
+
+ /* Fill in the DRIVER_INFO_3 struct */
+ ZERO_STRUCT(info3);
+ if (!(arch = cmd_spoolss_get_short_archi(argv[1])))
+ {
+ printf ("Error Unknown architechture [%s]\n", argv[1]);
+ return WERR_INVALID_PARAM;
+ }
+ else
+ set_drv_info_3_env(&info3, arch);
+
+ driver_args = talloc_strdup( mem_ctx, argv[2] );
+ if (!init_drv_info_3_members(mem_ctx, &info3, driver_args ))
+ {
+ printf ("Error Invalid parameter list - %s.\n", argv[2]);
+ return WERR_INVALID_PARAM;
+ }
+
+ /* if printer driver version specified, override the default version
+ * used by the architecture. This allows installation of Windows
+ * 2000 (version 3) printer drivers. */
+ if (argc == 4)
+ {
+ info3.version = atoi(argv[3]);
+ }
+
+
+ ctr.info3 = &info3;
+ result = rpccli_spoolss_addprinterdriver (cli, mem_ctx, level, &ctr);
+
+ if (W_ERROR_IS_OK(result)) {
+ rpcstr_pull(driver_name, info3.name.buffer,
+ sizeof(driver_name), -1, STR_TERMINATE);
+ printf ("Printer Driver %s successfully installed.\n",
+ driver_name);
+ }
+
+ return result;
+}
+
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_addprinterex(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ WERROR result;
+ uint32 level = 2;
+ PRINTER_INFO_CTR ctr;
+ PRINTER_INFO_2 info2;
+ fstring servername;
+
+ /* parse the command arguments */
+ if (argc != 5)
+ {
+ printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+
+ /* Fill in the DRIVER_INFO_2 struct */
+ ZERO_STRUCT(info2);
+
+ init_unistr( &info2.printername, argv[1]);
+ init_unistr( &info2.sharename, argv[2]);
+ init_unistr( &info2.drivername, argv[3]);
+ init_unistr( &info2.portname, argv[4]);
+ init_unistr( &info2.comment, "Created by rpcclient");
+ init_unistr( &info2.printprocessor, "winprint");
+ init_unistr( &info2.datatype, "RAW");
+ info2.devmode = NULL;
+ info2.secdesc = NULL;
+ info2.attributes = PRINTER_ATTRIBUTE_SHARED;
+ info2.priority = 0;
+ info2.defaultpriority = 0;
+ info2.starttime = 0;
+ info2.untiltime = 0;
+
+ /* These three fields must not be used by AddPrinter()
+ as defined in the MS Platform SDK documentation..
+ --jerry
+ info2.status = 0;
+ info2.cjobs = 0;
+ info2.averageppm = 0;
+ */
+
+ ctr.printers_2 = &info2;
+ result = rpccli_spoolss_addprinterex (cli, mem_ctx, level, &ctr);
+
+ if (W_ERROR_IS_OK(result))
+ printf ("Printer %s successfully installed.\n", argv[1]);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_setdriver(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND pol;
+ WERROR result;
+ uint32 level = 2;
+ bool opened_hnd = False;
+ PRINTER_INFO_CTR ctr;
+ PRINTER_INFO_2 info2;
+ fstring servername,
+ printername,
+ user;
+
+ /* parse the command arguments */
+ if (argc != 3)
+ {
+ printf ("Usage: %s <printer> <driver>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]);
+ fstrcpy(user, cli->auth->user_name);
+
+ /* Get a printer handle */
+
+ result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
+ PRINTER_ALL_ACCESS,
+ servername, user, &pol);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ opened_hnd = True;
+
+ /* Get printer info */
+
+ ZERO_STRUCT (info2);
+ ctr.printers_2 = &info2;
+
+ result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, level, &ctr);
+
+ if (!W_ERROR_IS_OK(result)) {
+ printf ("Unable to retrieve printer information!\n");
+ goto done;
+ }
+
+ /* Set the printer driver */
+
+ init_unistr(&ctr.printers_2->drivername, argv[2]);
+
+ result = rpccli_spoolss_setprinter(cli, mem_ctx, &pol, level, &ctr, 0);
+
+ if (!W_ERROR_IS_OK(result)) {
+ printf("SetPrinter call failed!\n");
+ goto done;;
+ }
+
+ printf("Successfully set %s to driver %s.\n", argv[1], argv[2]);
+
+done:
+ /* Cleanup */
+
+ if (opened_hnd)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
+
+ return result;
+}
+
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_deletedriverex(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ WERROR result, ret = WERR_UNKNOWN_PRINTER_DRIVER;
+
+ int i;
+ int vers = -1;
+
+ const char *arch = NULL;
+
+ /* parse the command arguments */
+ if (argc < 2 || argc > 4) {
+ printf ("Usage: %s <driver> [arch] [version]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 3)
+ arch = argv[2];
+ if (argc == 4)
+ vers = atoi (argv[3]);
+
+
+ /* delete the driver for all architectures */
+ for (i=0; archi_table[i].long_archi; i++) {
+
+ if (arch && !strequal( archi_table[i].long_archi, arch))
+ continue;
+
+ if (vers >= 0 && archi_table[i].version != vers)
+ continue;
+
+ /* make the call to remove the driver */
+ result = rpccli_spoolss_deleteprinterdriverex(
+ cli, mem_ctx, archi_table[i].long_archi, argv[1], archi_table[i].version);
+
+ if ( !W_ERROR_IS_OK(result) )
+ {
+ if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
+ printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n",
+ argv[1], archi_table[i].long_archi, archi_table[i].version, dos_errstr(result));
+ }
+ }
+ else
+ {
+ printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv[1],
+ archi_table[i].long_archi, archi_table[i].version);
+ ret = WERR_OK;
+ }
+ }
+
+ return ret;
+}
+
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_deletedriver(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ WERROR result = WERR_OK;
+ fstring servername;
+ int i;
+
+ /* parse the command arguments */
+ if (argc != 2) {
+ printf ("Usage: %s <driver>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+
+ /* delete the driver for all architectures */
+ for (i=0; archi_table[i].long_archi; i++) {
+ /* make the call to remove the driver */
+ result = rpccli_spoolss_deleteprinterdriver(
+ cli, mem_ctx, archi_table[i].long_archi, argv[1]);
+
+ if ( !W_ERROR_IS_OK(result) ) {
+ if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
+ printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n",
+ argv[1], archi_table[i].long_archi,
+ W_ERROR_V(result));
+ }
+ } else {
+ printf ("Driver %s removed for arch [%s].\n", argv[1],
+ archi_table[i].long_archi);
+ }
+ }
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_getprintprocdir(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ WERROR result;
+ char *servername = NULL, *environment = NULL;
+ fstring procdir;
+
+ /* parse the command arguments */
+ if (argc > 2) {
+ printf ("Usage: %s [environment]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (asprintf(&servername, "\\\\%s", cli->desthost) < 0)
+ return WERR_NOMEM;
+ strupper_m(servername);
+
+ if (asprintf(&environment, "%s", (argc == 2) ? argv[1] :
+ PRINTER_DRIVER_ARCHITECTURE) < 0) {
+ SAFE_FREE(servername);
+ return WERR_NOMEM;
+ }
+
+ result = rpccli_spoolss_getprintprocessordirectory(
+ cli, mem_ctx, servername, environment, procdir);
+
+ if (W_ERROR_IS_OK(result))
+ printf("%s\n", procdir);
+
+ SAFE_FREE(servername);
+ SAFE_FREE(environment);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND handle;
+ WERROR werror;
+ char *servername = NULL, *printername = NULL;
+ FORM form;
+ bool got_handle = False;
+
+ /* Parse the command arguments */
+
+ if (argc != 3) {
+ printf ("Usage: %s <printer> <formname>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ /* Get a printer handle */
+
+ asprintf(&servername, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ asprintf(&printername, "%s\\%s", servername, argv[1]);
+
+ werror = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
+ PRINTER_ALL_ACCESS,
+ servername, cli->auth->user_name,
+ &handle);
+
+ if (!W_ERROR_IS_OK(werror))
+ goto done;
+
+ got_handle = True;
+
+ /* Dummy up some values for the form data */
+
+ form.flags = FORM_USER;
+ form.size_x = form.size_y = 100;
+ form.left = 0;
+ form.top = 10;
+ form.right = 20;
+ form.bottom = 30;
+
+ init_unistr2(&form.name, argv[2], UNI_STR_TERMINATE);
+
+ /* Add the form */
+
+
+ werror = rpccli_spoolss_addform(cli, mem_ctx, &handle, 1, &form);
+
+ done:
+ if (got_handle)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
+
+ SAFE_FREE(servername);
+ SAFE_FREE(printername);
+
+ return werror;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND handle;
+ WERROR werror;
+ char *servername = NULL, *printername = NULL;
+ FORM form;
+ bool got_handle = False;
+
+ /* Parse the command arguments */
+
+ if (argc != 3) {
+ printf ("Usage: %s <printer> <formname>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ /* Get a printer handle */
+
+ asprintf(&servername, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ asprintf(&printername, "%s\\%s", servername, argv[1]);
+
+ werror = rpccli_spoolss_open_printer_ex(
+ cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS,
+ servername, cli->auth->user_name, &handle);
+
+ if (!W_ERROR_IS_OK(werror))
+ goto done;
+
+ got_handle = True;
+
+ /* Dummy up some values for the form data */
+
+ form.flags = FORM_PRINTER;
+ form.size_x = form.size_y = 100;
+ form.left = 0;
+ form.top = 1000;
+ form.right = 2000;
+ form.bottom = 3000;
+
+ init_unistr2(&form.name, argv[2], UNI_STR_TERMINATE);
+
+ /* Set the form */
+
+ werror = rpccli_spoolss_setform(cli, mem_ctx, &handle, 1, argv[2], &form);
+
+ done:
+ if (got_handle)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
+
+ SAFE_FREE(servername);
+ SAFE_FREE(printername);
+
+ return werror;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static const char *get_form_flag(int form_flag)
+{
+ switch (form_flag) {
+ case FORM_USER:
+ return "FORM_USER";
+ case FORM_BUILTIN:
+ return "FORM_BUILTIN";
+ case FORM_PRINTER:
+ return "FORM_PRINTER";
+ default:
+ return "unknown";
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void display_form(FORM_1 *form)
+{
+ fstring form_name = "";
+
+ if (form->name.buffer)
+ rpcstr_pull(form_name, form->name.buffer,
+ sizeof(form_name), -1, STR_TERMINATE);
+
+ printf("%s\n" \
+ "\tflag: %s (%d)\n" \
+ "\twidth: %d, length: %d\n" \
+ "\tleft: %d, right: %d, top: %d, bottom: %d\n\n",
+ form_name, get_form_flag(form->flag), form->flag,
+ form->width, form->length,
+ form->left, form->right,
+ form->top, form->bottom);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND handle;
+ WERROR werror;
+ char *servername = NULL, *printername = NULL;
+ FORM_1 form;
+ bool got_handle = False;
+
+ /* Parse the command arguments */
+
+ if (argc != 3) {
+ printf ("Usage: %s <printer> <formname>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ /* Get a printer handle */
+
+ asprintf(&servername, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ asprintf(&printername, "%s\\%s", servername, argv[1]);
+
+ werror = rpccli_spoolss_open_printer_ex(
+ cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS,
+ servername, cli->auth->user_name, &handle);
+
+ if (!W_ERROR_IS_OK(werror))
+ goto done;
+
+ got_handle = True;
+
+ /* Get the form */
+
+ werror = rpccli_spoolss_getform(cli, mem_ctx, &handle, argv[2], 1, &form);
+
+ if (!W_ERROR_IS_OK(werror))
+ goto done;
+
+ display_form(&form);
+
+ done:
+ if (got_handle)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
+
+ SAFE_FREE(servername);
+ SAFE_FREE(printername);
+
+ return werror;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_deleteform(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND handle;
+ WERROR werror;
+ char *servername = NULL, *printername = NULL;
+ bool got_handle = False;
+
+ /* Parse the command arguments */
+
+ if (argc != 3) {
+ printf ("Usage: %s <printer> <formname>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ /* Get a printer handle */
+
+ asprintf(&servername, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ asprintf(&printername, "%s\\%s", servername, argv[1]);
+
+ werror = rpccli_spoolss_open_printer_ex(
+ cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS,
+ servername, cli->auth->user_name, &handle);
+
+ if (!W_ERROR_IS_OK(werror))
+ goto done;
+
+ got_handle = True;
+
+ /* Delete the form */
+
+ werror = rpccli_spoolss_deleteform(cli, mem_ctx, &handle, argv[2]);
+
+ done:
+ if (got_handle)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
+
+ SAFE_FREE(servername);
+ SAFE_FREE(printername);
+
+ return werror;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_enum_forms(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ POLICY_HND handle;
+ WERROR werror;
+ char *servername = NULL, *printername = NULL;
+ bool got_handle = False;
+ uint32 num_forms, level = 1, i;
+ FORM_1 *forms;
+
+ /* Parse the command arguments */
+
+ if (argc != 2) {
+ printf ("Usage: %s <printer>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ /* Get a printer handle */
+
+ asprintf(&servername, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ asprintf(&printername, "%s\\%s", servername, argv[1]);
+
+ werror = rpccli_spoolss_open_printer_ex(
+ cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS,
+ servername, cli->auth->user_name, &handle);
+
+ if (!W_ERROR_IS_OK(werror))
+ goto done;
+
+ got_handle = True;
+
+ /* Enumerate forms */
+
+ werror = rpccli_spoolss_enumforms(cli, mem_ctx, &handle, level, &num_forms, &forms);
+
+ if (!W_ERROR_IS_OK(werror))
+ goto done;
+
+ /* Display output */
+
+ for (i = 0; i < num_forms; i++) {
+
+ display_form(&forms[i]);
+
+ }
+
+ done:
+ if (got_handle)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
+
+ SAFE_FREE(servername);
+ SAFE_FREE(printername);
+
+ return werror;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ WERROR result;
+ fstring servername, printername, user;
+ POLICY_HND pol;
+ bool opened_hnd = False;
+ PRINTER_INFO_CTR ctr;
+ PRINTER_INFO_0 info;
+ REGISTRY_VALUE value;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ /* parse the command arguments */
+ if (argc < 5) {
+ printf ("Usage: %s <printer> <string|binary|dword|multistring>"
+ " <value> <data>\n",
+ argv[0]);
+ result = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]);
+ fstrcpy(user, cli->auth->user_name);
+
+ value.type = REG_NONE;
+
+ if (strequal(argv[2], "string")) {
+ value.type = REG_SZ;
+ }
+
+ if (strequal(argv[2], "binary")) {
+ value.type = REG_BINARY;
+ }
+
+ if (strequal(argv[2], "dword")) {
+ value.type = REG_DWORD;
+ }
+
+ if (strequal(argv[2], "multistring")) {
+ value.type = REG_MULTI_SZ;
+ }
+
+ if (value.type == REG_NONE) {
+ printf("Unknown data type: %s\n", argv[2]);
+ result = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ /* get a printer handle */
+ result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
+ MAXIMUM_ALLOWED_ACCESS, servername,
+ user, &pol);
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ opened_hnd = True;
+
+ ctr.printers_0 = &info;
+
+ result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, 0, &ctr);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ printf("%s\n", current_timestring(tmp_ctx, True));
+ printf("\tchange_id (before set)\t:[0x%x]\n", info.change_id);
+
+ /* Set the printer data */
+
+ fstrcpy(value.valuename, argv[3]);
+
+ switch (value.type) {
+ case REG_SZ: {
+ UNISTR2 data;
+ init_unistr2(&data, argv[4], UNI_STR_TERMINATE);
+ value.size = data.uni_str_len * 2;
+ if (value.size) {
+ value.data_p = (uint8 *)TALLOC_MEMDUP(mem_ctx, data.buffer,
+ value.size);
+ } else {
+ value.data_p = NULL;
+ }
+ break;
+ }
+ case REG_DWORD: {
+ uint32 data = strtoul(argv[4], NULL, 10);
+ value.size = sizeof(data);
+ if (sizeof(data)) {
+ value.data_p = (uint8 *)TALLOC_MEMDUP(mem_ctx, &data,
+ sizeof(data));
+ } else {
+ value.data_p = NULL;
+ }
+ break;
+ }
+ case REG_BINARY: {
+ DATA_BLOB data = strhex_to_data_blob(mem_ctx, argv[4]);
+ value.data_p = data.data;
+ value.size = data.length;
+ break;
+ }
+ case REG_MULTI_SZ: {
+ int i;
+ size_t len = 0;
+ char *p;
+
+ for (i=4; i<argc; i++) {
+ if (strcmp(argv[i], "NULL") == 0) {
+ argv[i] = "";
+ }
+ len += strlen(argv[i])+1;
+ }
+
+ value.size = len*2;
+ value.data_p = TALLOC_ARRAY(mem_ctx, unsigned char, value.size);
+ if (value.data_p == NULL) {
+ result = WERR_NOMEM;
+ goto done;
+ }
+
+ p = (char *)value.data_p;
+ len = value.size;
+ for (i=4; i<argc; i++) {
+ size_t l = (strlen(argv[i])+1)*2;
+ rpcstr_push(p, argv[i], len, STR_TERMINATE);
+ p += l;
+ len -= l;
+ }
+ SMB_ASSERT(len == 0);
+ break;
+ }
+ default:
+ printf("Unknown data type: %s\n", argv[2]);
+ result = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ result = rpccli_spoolss_setprinterdata(cli, mem_ctx, &pol, &value);
+
+ if (!W_ERROR_IS_OK(result)) {
+ printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
+ goto done;
+ }
+ printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]);
+
+ result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, 0, &ctr);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ printf("%s\n", current_timestring(tmp_ctx, True));
+ printf("\tchange_id (after set)\t:[0x%x]\n", info.change_id);
+
+done:
+ /* cleanup */
+ TALLOC_FREE(tmp_ctx);
+ if (opened_hnd)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void display_job_info_1(JOB_INFO_1 *job)
+{
+ fstring username = "", document = "", text_status = "";
+
+ rpcstr_pull(username, job->username.buffer,
+ sizeof(username), -1, STR_TERMINATE);
+
+ rpcstr_pull(document, job->document.buffer,
+ sizeof(document), -1, STR_TERMINATE);
+
+ rpcstr_pull(text_status, job->text_status.buffer,
+ sizeof(text_status), -1, STR_TERMINATE);
+
+ printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", job->position, job->jobid,
+ username, document, text_status, job->pagesprinted,
+ job->totalpages);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void display_job_info_2(JOB_INFO_2 *job)
+{
+ fstring username = "", document = "", text_status = "";
+
+ rpcstr_pull(username, job->username.buffer,
+ sizeof(username), -1, STR_TERMINATE);
+
+ rpcstr_pull(document, job->document.buffer,
+ sizeof(document), -1, STR_TERMINATE);
+
+ rpcstr_pull(text_status, job->text_status.buffer,
+ sizeof(text_status), -1, STR_TERMINATE);
+
+ printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n", job->position, job->jobid,
+ username, document, text_status, job->pagesprinted,
+ job->totalpages, job->size);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ WERROR result;
+ uint32 level = 1, num_jobs, i;
+ bool got_hnd = False;
+ char *printername = NULL;
+ fstring servername, user;
+ POLICY_HND hnd;
+ JOB_INFO_CTR ctr;
+
+ if (argc < 2 || argc > 3) {
+ printf("Usage: %s printername [level]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc == 3)
+ level = atoi(argv[2]);
+
+ /* Open printer handle */
+
+ slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ fstrcpy(user, cli->auth->user_name);
+ printername = talloc_asprintf(mem_ctx, "\\\\%s\\", cli->desthost);
+ if (!printername) {
+ return WERR_NOMEM;
+ }
+ strupper_m(printername);
+ printername = talloc_asprintf_append(printername, "%s", argv[1]);
+ if (!printername) {
+ return WERR_NOMEM;
+ }
+
+ result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
+ "", MAXIMUM_ALLOWED_ACCESS,
+ servername, user, &hnd);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ got_hnd = True;
+
+ /* Enumerate ports */
+
+ result = rpccli_spoolss_enumjobs(cli, mem_ctx, &hnd, level, 0, 1000,
+ &num_jobs, &ctr);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ for (i = 0; i < num_jobs; i++) {
+ switch(level) {
+ case 1:
+ display_job_info_1(&ctr.job.job_info_1[i]);
+ break;
+ case 2:
+ display_job_info_2(&ctr.job.job_info_2[i]);
+ break;
+ default:
+ d_printf("unknown info level %d\n", level);
+ break;
+ }
+ }
+
+done:
+ if (got_hnd)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_enum_data( struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ WERROR result;
+ uint32 i=0, val_needed, data_needed;
+ bool got_hnd = False;
+ char *printername = NULL;
+ fstring servername, user;
+ POLICY_HND hnd;
+
+ if (argc != 2) {
+ printf("Usage: %s printername\n", argv[0]);
+ return WERR_OK;
+ }
+
+ /* Open printer handle */
+
+ slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ fstrcpy(user, cli->auth->user_name);
+ printername = talloc_asprintf(mem_ctx, "\\\\%s\\", cli->desthost);
+ if (!printername) {
+ return WERR_NOMEM;
+ }
+ strupper_m(printername);
+ printername = talloc_asprintf_append(printername, "%s", argv[1]);
+ if (!printername) {
+ return WERR_NOMEM;
+ }
+
+ result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
+ "", MAXIMUM_ALLOWED_ACCESS,
+ servername, user, &hnd);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ got_hnd = True;
+
+ /* Enumerate data */
+
+ result = rpccli_spoolss_enumprinterdata(cli, mem_ctx, &hnd, i, 0, 0,
+ &val_needed, &data_needed,
+ NULL);
+ while (W_ERROR_IS_OK(result)) {
+ REGISTRY_VALUE value;
+ result = rpccli_spoolss_enumprinterdata(
+ cli, mem_ctx, &hnd, i++, val_needed,
+ data_needed, 0, 0, &value);
+ if (W_ERROR_IS_OK(result))
+ display_reg_value(value);
+ }
+ if (W_ERROR_V(result) == ERRnomoreitems)
+ result = W_ERROR(ERRsuccess);
+
+done:
+ if (got_hnd)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ WERROR result;
+ uint32 i;
+ bool got_hnd = False;
+ char *printername = NULL;
+ fstring servername, user;
+ const char *keyname = NULL;
+ POLICY_HND hnd;
+ REGVAL_CTR *ctr = NULL;
+
+ if (argc != 3) {
+ printf("Usage: %s printername <keyname>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ keyname = argv[2];
+
+ /* Open printer handle */
+
+ slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ fstrcpy(user, cli->auth->user_name);
+
+ printername = talloc_asprintf(mem_ctx, "\\\\%s\\", cli->desthost);
+ if (!printername) {
+ return WERR_NOMEM;
+ }
+ strupper_m(printername);
+ printername = talloc_asprintf_append(printername, "%s", argv[1]);
+ if (!printername) {
+ return WERR_NOMEM;
+ }
+
+ result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
+ "", MAXIMUM_ALLOWED_ACCESS,
+ servername, user, &hnd);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ got_hnd = True;
+
+ /* Enumerate subkeys */
+
+ if ( !(ctr = TALLOC_ZERO_P( mem_ctx, REGVAL_CTR )) )
+ return WERR_NOMEM;
+
+ result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &hnd, keyname, ctr);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ for (i=0; i < ctr->num_values; i++) {
+ display_reg_value(*(ctr->values[i]));
+ }
+
+ TALLOC_FREE( ctr );
+
+done:
+ if (got_hnd)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_enum_printerkey( struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ WERROR result;
+ bool got_hnd = False;
+ char *printername = NULL;
+ fstring servername, user;
+ const char *keyname = NULL;
+ POLICY_HND hnd;
+ uint16 *keylist = NULL, *curkey;
+
+ if (argc < 2 || argc > 3) {
+ printf("Usage: %s printername [keyname]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc == 3)
+ keyname = argv[2];
+ else
+ keyname = "";
+
+ /* Open printer handle */
+
+ slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ fstrcpy(user, cli->auth->user_name);
+
+ printername = talloc_asprintf(mem_ctx, "\\\\%s\\", cli->desthost);
+ if (!printername) {
+ return WERR_NOMEM;
+ }
+ strupper_m(printername);
+ printername = talloc_asprintf_append(printername, "%s", argv[1]);
+ if (!printername) {
+ return WERR_NOMEM;
+ }
+
+
+ result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
+ "", MAXIMUM_ALLOWED_ACCESS,
+ servername, user, &hnd);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ got_hnd = True;
+
+ /* Enumerate subkeys */
+
+ result = rpccli_spoolss_enumprinterkey(cli, mem_ctx, &hnd, keyname, &keylist, NULL);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ curkey = keylist;
+ while (*curkey != 0) {
+ char *subkey = NULL;
+ rpcstr_pull_talloc(mem_ctx, &subkey, curkey, -1,
+ STR_TERMINATE);
+ if (!subkey) {
+ break;
+ }
+ printf("%s\n", subkey);
+ curkey += strlen(subkey) + 1;
+ }
+
+done:
+
+ SAFE_FREE(keylist);
+
+ if (got_hnd)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ fstring servername, printername;
+ POLICY_HND hnd;
+ bool got_hnd = False;
+ WERROR result;
+ SPOOL_NOTIFY_OPTION option;
+
+ if (argc != 2) {
+ printf("Usage: %s printername\n", argv[0]);
+ result = WERR_OK;
+ goto done;
+ }
+
+ /* Open printer */
+
+ slprintf(servername, sizeof(servername) - 1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+
+ slprintf(printername, sizeof(printername) - 1, "\\\\%s\\%s",
+ cli->desthost, argv[1]);
+ strupper_m(printername);
+
+ result = rpccli_spoolss_open_printer_ex(
+ cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS,
+ servername, cli->auth->user_name, &hnd);
+
+ if (!W_ERROR_IS_OK(result)) {
+ printf("Error opening %s\n", argv[1]);
+ goto done;
+ }
+
+ got_hnd = True;
+
+ /* Create spool options */
+
+ ZERO_STRUCT(option);
+
+ option.version = 2;
+ option.option_type_ptr = 1;
+ option.count = option.ctr.count = 2;
+
+ option.ctr.type = TALLOC_ARRAY(mem_ctx, SPOOL_NOTIFY_OPTION_TYPE, 2);
+ if (option.ctr.type == NULL) {
+ result = WERR_NOMEM;
+ goto done;
+ }
+
+ ZERO_STRUCT(option.ctr.type[0]);
+ option.ctr.type[0].type = PRINTER_NOTIFY_TYPE;
+ option.ctr.type[0].count = option.ctr.type[0].count2 = 1;
+ option.ctr.type[0].fields_ptr = 1;
+ option.ctr.type[0].fields[0] = PRINTER_NOTIFY_SERVER_NAME;
+
+ ZERO_STRUCT(option.ctr.type[1]);
+ option.ctr.type[1].type = JOB_NOTIFY_TYPE;
+ option.ctr.type[1].count = option.ctr.type[1].count2 = 1;
+ option.ctr.type[1].fields_ptr = 1;
+ option.ctr.type[1].fields[0] = JOB_NOTIFY_PRINTER_NAME;
+
+ /* Send rffpcnex */
+
+ slprintf(servername, sizeof(servername) - 1, "\\\\%s", myhostname());
+ strupper_m(servername);
+
+ result = rpccli_spoolss_rffpcnex(
+ cli, mem_ctx, &hnd, 0, 0, servername, 123, &option);
+
+ if (!W_ERROR_IS_OK(result)) {
+ printf("Error rffpcnex %s\n", argv[1]);
+ goto done;
+ }
+
+done:
+ if (got_hnd)
+ rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool compare_printer( struct rpc_pipe_client *cli1, POLICY_HND *hnd1,
+ struct rpc_pipe_client *cli2, POLICY_HND *hnd2 )
+{
+ PRINTER_INFO_CTR ctr1, ctr2;
+ WERROR werror;
+ TALLOC_CTX *mem_ctx = talloc_init("compare_printer");
+
+ printf("Retrieving printer propertiesfor %s...", cli1->desthost);
+ werror = rpccli_spoolss_getprinter( cli1, mem_ctx, hnd1, 2, &ctr1);
+ if ( !W_ERROR_IS_OK(werror) ) {
+ printf("failed (%s)\n", dos_errstr(werror));
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+ printf("ok\n");
+
+ printf("Retrieving printer properties for %s...", cli2->desthost);
+ werror = rpccli_spoolss_getprinter( cli2, mem_ctx, hnd2, 2, &ctr2);
+ if ( !W_ERROR_IS_OK(werror) ) {
+ printf("failed (%s)\n", dos_errstr(werror));
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+ printf("ok\n");
+
+ talloc_destroy(mem_ctx);
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool compare_printer_secdesc( struct rpc_pipe_client *cli1, POLICY_HND *hnd1,
+ struct rpc_pipe_client *cli2, POLICY_HND *hnd2 )
+{
+ PRINTER_INFO_CTR ctr1, ctr2;
+ WERROR werror;
+ TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc");
+ SEC_DESC *sd1, *sd2;
+ bool result = True;
+
+
+ printf("Retrieving printer security for %s...", cli1->desthost);
+ werror = rpccli_spoolss_getprinter( cli1, mem_ctx, hnd1, 3, &ctr1);
+ if ( !W_ERROR_IS_OK(werror) ) {
+ printf("failed (%s)\n", dos_errstr(werror));
+ result = False;
+ goto done;
+ }
+ printf("ok\n");
+
+ printf("Retrieving printer security for %s...", cli2->desthost);
+ werror = rpccli_spoolss_getprinter( cli2, mem_ctx, hnd2, 3, &ctr2);
+ if ( !W_ERROR_IS_OK(werror) ) {
+ printf("failed (%s)\n", dos_errstr(werror));
+ result = False;
+ goto done;
+ }
+ printf("ok\n");
+
+
+ printf("++ ");
+
+ if ( (ctr1.printers_3 != ctr2.printers_3) && (!ctr1.printers_3 || !ctr2.printers_3) ) {
+ printf("NULL PRINTER_INFO_3!\n");
+ result = False;
+ goto done;
+ }
+
+ sd1 = ctr1.printers_3->secdesc;
+ sd2 = ctr2.printers_3->secdesc;
+
+ if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) {
+ printf("NULL secdesc!\n");
+ result = False;
+ goto done;
+ }
+
+ if (!sec_desc_equal( sd1, sd2 ) ) {
+ printf("Security Descriptors *not* equal!\n");
+ result = False;
+ goto done;
+ }
+
+ printf("Security descriptors match\n");
+
+done:
+ talloc_destroy(mem_ctx);
+ return result;
+}
+
+
+/****************************************************************************
+****************************************************************************/
+
+static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ const char **argv)
+{
+ fstring printername, servername1, servername2;
+ char *printername_path = NULL;
+ struct cli_state *cli_server1 = rpc_pipe_np_smb_conn(cli);
+ struct cli_state *cli_server2 = NULL;
+ struct rpc_pipe_client *cli2 = NULL;
+ POLICY_HND hPrinter1, hPrinter2;
+ NTSTATUS nt_status;
+ WERROR werror;
+
+ if ( argc != 3 ) {
+ printf("Usage: %s <printer> <server>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ fstrcpy( printername, argv[1] );
+
+ fstrcpy( servername1, cli->desthost );
+ fstrcpy( servername2, argv[2] );
+ strupper_m( servername1 );
+ strupper_m( servername2 );
+
+ /* first get the connection to the remote server */
+
+ nt_status = cli_full_connection(&cli_server2, global_myname(), servername2,
+ NULL, 0,
+ "IPC$", "IPC",
+ get_cmdline_auth_info_username(),
+ lp_workgroup(),
+ get_cmdline_auth_info_password(),
+ get_cmdline_auth_info_use_kerberos() ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
+ get_cmdline_auth_info_signing_state(), NULL);
+
+ if ( !NT_STATUS_IS_OK(nt_status) )
+ return WERR_GENERAL_FAILURE;
+
+ nt_status = cli_rpc_pipe_open_noauth(cli_server2, &syntax_spoolss,
+ &cli2);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ printf("failed to open spoolss pipe on server %s (%s)\n",
+ servername2, nt_errstr(nt_status));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ /* now open up both printers */
+
+ printername_path = talloc_asprintf(mem_ctx,
+ "\\\\%s\\%s",
+ servername1,
+ printername);
+ if (!printername_path) {
+ return WERR_NOMEM;
+ }
+ printf("Opening %s...", printername_path);
+ werror = rpccli_spoolss_open_printer_ex( cli, mem_ctx, printername_path,
+ "", PRINTER_ALL_ACCESS, servername1, cli_server1->user_name, &hPrinter1);
+ if ( !W_ERROR_IS_OK(werror) ) {
+ printf("failed (%s)\n", dos_errstr(werror));
+ goto done;
+ }
+ printf("ok\n");
+
+ printername_path = talloc_asprintf(mem_ctx,
+ "\\\\%s\\%s",
+ servername2,
+ printername);
+ if (!printername_path) {
+ return WERR_NOMEM;
+ }
+ printf("Opening %s...", printername_path);
+ werror = rpccli_spoolss_open_printer_ex( cli2, mem_ctx, printername_path,
+ "", PRINTER_ALL_ACCESS, servername2, cli_server2->user_name, &hPrinter2 );
+ if ( !W_ERROR_IS_OK(werror) ) {
+ printf("failed (%s)\n", dos_errstr(werror));
+ goto done;
+ }
+ printf("ok\n");
+
+ compare_printer( cli, &hPrinter1, cli2, &hPrinter2 );
+ compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 );
+#if 0
+ compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 );
+#endif
+
+
+done:
+ /* cleanup */
+
+ printf("Closing printers...");
+ rpccli_spoolss_close_printer( cli, mem_ctx, &hPrinter1 );
+ rpccli_spoolss_close_printer( cli2, mem_ctx, &hPrinter2 );
+ printf("ok\n");
+
+ /* close the second remote connection */
+
+ cli_shutdown( cli_server2 );
+ return WERR_OK;
+}
+
+/* List of commands exported by this module */
+struct cmd_set spoolss_commands[] = {
+
+ { "SPOOLSS" },
+
+ { "adddriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver, &syntax_spoolss, NULL, "Add a print driver", "" },
+ { "addprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex, &syntax_spoolss, NULL, "Add a printer", "" },
+ { "deldriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver, &syntax_spoolss, NULL, "Delete a printer driver", "" },
+ { "deldriverex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex, &syntax_spoolss, NULL, "Delete a printer driver with files", "" },
+ { "enumdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data, &syntax_spoolss, NULL, "Enumerate printer data", "" },
+ { "enumdataex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex, &syntax_spoolss, NULL, "Enumerate printer data for a key", "" },
+ { "enumkey", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey, &syntax_spoolss, NULL, "Enumerate printer keys", "" },
+ { "enumjobs", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs, &syntax_spoolss, NULL, "Enumerate print jobs", "" },
+ { "enumports", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports, &syntax_spoolss, NULL, "Enumerate printer ports", "" },
+ { "enumdrivers", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers, &syntax_spoolss, NULL, "Enumerate installed printer drivers", "" },
+ { "enumprinters", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers, &syntax_spoolss, NULL, "Enumerate printers", "" },
+ { "getdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata, &syntax_spoolss, NULL, "Get print driver data", "" },
+ { "getdataex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex, &syntax_spoolss, NULL, "Get printer driver data with keyname", ""},
+ { "getdriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver, &syntax_spoolss, NULL, "Get print driver information", "" },
+ { "getdriverdir", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir, &syntax_spoolss, NULL, "Get print driver upload directory", "" },
+ { "getprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter, &syntax_spoolss, NULL, "Get printer info", "" },
+ { "openprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex, &syntax_spoolss, NULL, "Open printer handle", "" },
+ { "setdriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver, &syntax_spoolss, NULL, "Set printer driver", "" },
+ { "getprintprocdir", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir, &syntax_spoolss, NULL, "Get print processor directory", "" },
+ { "addform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform, &syntax_spoolss, NULL, "Add form", "" },
+ { "setform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform, &syntax_spoolss, NULL, "Set form", "" },
+ { "getform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform, &syntax_spoolss, NULL, "Get form", "" },
+ { "deleteform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform, &syntax_spoolss, NULL, "Delete form", "" },
+ { "enumforms", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms, &syntax_spoolss, NULL, "Enumerate forms", "" },
+ { "setprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter, &syntax_spoolss, NULL, "Set printer comment", "" },
+ { "setprintername", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername, &syntax_spoolss, NULL, "Set printername", "" },
+ { "setprinterdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata, &syntax_spoolss, NULL, "Set REG_SZ printer data", "" },
+ { "rffpcnex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex, &syntax_spoolss, NULL, "Rffpcnex test", "" },
+ { "printercmp", RPC_RTYPE_WERROR, NULL, cmd_spoolss_printercmp, &syntax_spoolss, NULL, "Printer comparison test", "" },
+
+ { NULL }
+};
diff --git a/source3/rpcclient/cmd_srvsvc.c b/source3/rpcclient/cmd_srvsvc.c
new file mode 100644
index 0000000000..10017fa19b
--- /dev/null
+++ b/source3/rpcclient/cmd_srvsvc.c
@@ -0,0 +1,891 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996 - 1999
+ Copyright (C) Tim Potter 2000,2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+/* Display server query info */
+
+static char *get_server_type_str(uint32 type)
+{
+ static fstring typestr;
+ int i;
+
+ if (type == SV_TYPE_ALL) {
+ fstrcpy(typestr, "All");
+ return typestr;
+ }
+
+ typestr[0] = 0;
+
+ for (i = 0; i < 32; i++) {
+ if (type & (1 << i)) {
+ switch (1 << i) {
+ case SV_TYPE_WORKSTATION:
+ fstrcat(typestr, "Wk ");
+ break;
+ case SV_TYPE_SERVER:
+ fstrcat(typestr, "Sv ");
+ break;
+ case SV_TYPE_SQLSERVER:
+ fstrcat(typestr, "Sql ");
+ break;
+ case SV_TYPE_DOMAIN_CTRL:
+ fstrcat(typestr, "PDC ");
+ break;
+ case SV_TYPE_DOMAIN_BAKCTRL:
+ fstrcat(typestr, "BDC ");
+ break;
+ case SV_TYPE_TIME_SOURCE:
+ fstrcat(typestr, "Tim ");
+ break;
+ case SV_TYPE_AFP:
+ fstrcat(typestr, "AFP ");
+ break;
+ case SV_TYPE_NOVELL:
+ fstrcat(typestr, "Nov ");
+ break;
+ case SV_TYPE_DOMAIN_MEMBER:
+ fstrcat(typestr, "Dom ");
+ break;
+ case SV_TYPE_PRINTQ_SERVER:
+ fstrcat(typestr, "PrQ ");
+ break;
+ case SV_TYPE_DIALIN_SERVER:
+ fstrcat(typestr, "Din ");
+ break;
+ case SV_TYPE_SERVER_UNIX:
+ fstrcat(typestr, "Unx ");
+ break;
+ case SV_TYPE_NT:
+ fstrcat(typestr, "NT ");
+ break;
+ case SV_TYPE_WFW:
+ fstrcat(typestr, "Wfw ");
+ break;
+ case SV_TYPE_SERVER_MFPN:
+ fstrcat(typestr, "Mfp ");
+ break;
+ case SV_TYPE_SERVER_NT:
+ fstrcat(typestr, "SNT ");
+ break;
+ case SV_TYPE_POTENTIAL_BROWSER:
+ fstrcat(typestr, "PtB ");
+ break;
+ case SV_TYPE_BACKUP_BROWSER:
+ fstrcat(typestr, "BMB ");
+ break;
+ case SV_TYPE_MASTER_BROWSER:
+ fstrcat(typestr, "LMB ");
+ break;
+ case SV_TYPE_DOMAIN_MASTER:
+ fstrcat(typestr, "DMB ");
+ break;
+ case SV_TYPE_SERVER_OSF:
+ fstrcat(typestr, "OSF ");
+ break;
+ case SV_TYPE_SERVER_VMS:
+ fstrcat(typestr, "VMS ");
+ break;
+ case SV_TYPE_WIN95_PLUS:
+ fstrcat(typestr, "W95 ");
+ break;
+ case SV_TYPE_ALTERNATE_XPORT:
+ fstrcat(typestr, "Xpt ");
+ break;
+ case SV_TYPE_LOCAL_LIST_ONLY:
+ fstrcat(typestr, "Dom ");
+ break;
+ case SV_TYPE_DOMAIN_ENUM:
+ fstrcat(typestr, "Loc ");
+ break;
+ }
+ }
+ }
+
+ i = strlen(typestr) - 1;
+
+ if (typestr[i] == ' ')
+ typestr[i] = 0;
+
+ return typestr;
+}
+
+static void display_server(const char *sname, uint32 type, const char *comment)
+{
+ printf("\t%-15.15s%-20s %s\n", sname, get_server_type_str(type),
+ comment);
+}
+
+static void display_srv_info_101(struct srvsvc_NetSrvInfo101 *r)
+{
+ display_server(r->server_name, r->server_type, r->comment);
+
+ printf("\tplatform_id :\t%d\n", r->platform_id);
+ printf("\tos version :\t%d.%d\n",
+ r->version_major, r->version_minor);
+ printf("\tserver type :\t0x%x\n", r->server_type);
+}
+
+static void display_srv_info_102(struct srvsvc_NetSrvInfo102 *r)
+{
+ display_server(r->server_name, r->server_type, r->comment);
+
+ printf("\tplatform_id :\t%d\n", r->platform_id);
+ printf("\tos version :\t%d.%d\n",
+ r->version_major, r->version_minor);
+ printf("\tserver type :\t0x%x\n", r->server_type);
+
+ printf("\tusers :\t%x\n", r->users);
+ printf("\tdisc, hidden :\t%x, %x\n", r->disc, r->hidden);
+ printf("\tannounce, delta :\t%d, %d\n", r->announce,
+ r->anndelta);
+ printf("\tlicenses :\t%d\n", r->licenses);
+ printf("\tuser path :\t%s\n", r->userpath);
+}
+
+/* Server query info */
+static WERROR cmd_srvsvc_srv_query_info(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ uint32 info_level = 101;
+ union srvsvc_NetSrvInfo info;
+ WERROR result;
+ NTSTATUS status;
+
+ if (argc > 2) {
+ printf("Usage: %s [infolevel]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc == 2)
+ info_level = atoi(argv[1]);
+
+ status = rpccli_srvsvc_NetSrvGetInfo(cli, mem_ctx,
+ cli->srv_name_slash,
+ info_level,
+ &info,
+ &result);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ if (!W_ERROR_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Display results */
+
+ switch (info_level) {
+ case 101:
+ display_srv_info_101(info.info101);
+ break;
+ case 102:
+ display_srv_info_102(info.info102);
+ break;
+ default:
+ printf("unsupported info level %d\n", info_level);
+ break;
+ }
+
+ done:
+ return result;
+}
+
+static void display_share_info_1(struct srvsvc_NetShareInfo1 *r)
+{
+ printf("netname: %s\n", r->name);
+ printf("\tremark:\t%s\n", r->comment);
+}
+
+static void display_share_info_2(struct srvsvc_NetShareInfo2 *r)
+{
+ printf("netname: %s\n", r->name);
+ printf("\tremark:\t%s\n", r->comment);
+ printf("\tpath:\t%s\n", r->path);
+ printf("\tpassword:\t%s\n", r->password);
+}
+
+static void display_share_info_502(struct srvsvc_NetShareInfo502 *r)
+{
+ printf("netname: %s\n", r->name);
+ printf("\tremark:\t%s\n", r->comment);
+ printf("\tpath:\t%s\n", r->path);
+ printf("\tpassword:\t%s\n", r->password);
+
+ printf("\ttype:\t0x%x\n", r->type);
+ printf("\tperms:\t%d\n", r->permissions);
+ printf("\tmax_uses:\t%d\n", r->max_users);
+ printf("\tnum_uses:\t%d\n", r->current_users);
+
+ if (r->sd_buf.sd)
+ display_sec_desc(r->sd_buf.sd);
+
+}
+
+static WERROR cmd_srvsvc_net_share_enum_int(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv,
+ uint32_t opcode)
+{
+ uint32 info_level = 2;
+ struct srvsvc_NetShareInfoCtr info_ctr;
+ struct srvsvc_NetShareCtr0 ctr0;
+ struct srvsvc_NetShareCtr1 ctr1;
+ struct srvsvc_NetShareCtr2 ctr2;
+ struct srvsvc_NetShareCtr501 ctr501;
+ struct srvsvc_NetShareCtr502 ctr502;
+ struct srvsvc_NetShareCtr1004 ctr1004;
+ struct srvsvc_NetShareCtr1005 ctr1005;
+ struct srvsvc_NetShareCtr1006 ctr1006;
+ struct srvsvc_NetShareCtr1007 ctr1007;
+ struct srvsvc_NetShareCtr1501 ctr1501;
+ WERROR result;
+ NTSTATUS status;
+ uint32_t totalentries = 0;
+ uint32_t resume_handle = 0;
+ uint32_t *resume_handle_p = NULL;
+ uint32 preferred_len = 0xffffffff, i;
+
+ if (argc > 3) {
+ printf("Usage: %s [infolevel] [resume_handle]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 2) {
+ info_level = atoi(argv[1]);
+ }
+
+ if (argc == 3) {
+ resume_handle = atoi(argv[2]);
+ resume_handle_p = &resume_handle;
+ }
+
+ ZERO_STRUCT(info_ctr);
+
+ info_ctr.level = info_level;
+
+ switch (info_level) {
+ case 0:
+ ZERO_STRUCT(ctr0);
+ info_ctr.ctr.ctr0 = &ctr0;
+ break;
+ case 1:
+ ZERO_STRUCT(ctr1);
+ info_ctr.ctr.ctr1 = &ctr1;
+ break;
+ case 2:
+ ZERO_STRUCT(ctr2);
+ info_ctr.ctr.ctr2 = &ctr2;
+ break;
+ case 501:
+ ZERO_STRUCT(ctr501);
+ info_ctr.ctr.ctr501 = &ctr501;
+ break;
+ case 502:
+ ZERO_STRUCT(ctr502);
+ info_ctr.ctr.ctr502 = &ctr502;
+ break;
+ case 1004:
+ ZERO_STRUCT(ctr1004);
+ info_ctr.ctr.ctr1004 = &ctr1004;
+ break;
+ case 1005:
+ ZERO_STRUCT(ctr1005);
+ info_ctr.ctr.ctr1005 = &ctr1005;
+ break;
+ case 1006:
+ ZERO_STRUCT(ctr1006);
+ info_ctr.ctr.ctr1006 = &ctr1006;
+ break;
+ case 1007:
+ ZERO_STRUCT(ctr1007);
+ info_ctr.ctr.ctr1007 = &ctr1007;
+ break;
+ case 1501:
+ ZERO_STRUCT(ctr1501);
+ info_ctr.ctr.ctr1501 = &ctr1501;
+ break;
+ }
+
+ switch (opcode) {
+ case NDR_SRVSVC_NETSHAREENUM:
+ status = rpccli_srvsvc_NetShareEnum(cli, mem_ctx,
+ cli->desthost,
+ &info_ctr,
+ preferred_len,
+ &totalentries,
+ resume_handle_p,
+ &result);
+ break;
+ case NDR_SRVSVC_NETSHAREENUMALL:
+ status = rpccli_srvsvc_NetShareEnumAll(cli, mem_ctx,
+ cli->desthost,
+ &info_ctr,
+ preferred_len,
+ &totalentries,
+ resume_handle_p,
+ &result);
+ break;
+ default:
+ return WERR_INVALID_PARAM;
+ }
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Display results */
+
+ switch (info_level) {
+ case 1:
+ for (i = 0; i < totalentries; i++)
+ display_share_info_1(&info_ctr.ctr.ctr1->array[i]);
+ break;
+ case 2:
+ for (i = 0; i < totalentries; i++)
+ display_share_info_2(&info_ctr.ctr.ctr2->array[i]);
+ break;
+ case 502:
+ for (i = 0; i < totalentries; i++)
+ display_share_info_502(&info_ctr.ctr.ctr502->array[i]);
+ break;
+ default:
+ printf("unsupported info level %d\n", info_level);
+ break;
+ }
+
+ done:
+ return result;
+}
+
+static WERROR cmd_srvsvc_net_share_enum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ return cmd_srvsvc_net_share_enum_int(cli, mem_ctx,
+ argc, argv,
+ NDR_SRVSVC_NETSHAREENUM);
+}
+
+static WERROR cmd_srvsvc_net_share_enum_all(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ return cmd_srvsvc_net_share_enum_int(cli, mem_ctx,
+ argc, argv,
+ NDR_SRVSVC_NETSHAREENUMALL);
+}
+
+static WERROR cmd_srvsvc_net_share_get_info(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ uint32 info_level = 502;
+ union srvsvc_NetShareInfo info;
+ WERROR result;
+ NTSTATUS status;
+
+ if (argc < 2 || argc > 3) {
+ printf("Usage: %s [sharename] [infolevel]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc == 3)
+ info_level = atoi(argv[2]);
+
+ status = rpccli_srvsvc_NetShareGetInfo(cli, mem_ctx,
+ cli->desthost,
+ argv[1],
+ info_level,
+ &info,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Display results */
+
+ switch (info_level) {
+ case 1:
+ display_share_info_1(info.info1);
+ break;
+ case 2:
+ display_share_info_2(info.info2);
+ break;
+ case 502:
+ display_share_info_502(info.info502);
+ break;
+ default:
+ printf("unsupported info level %d\n", info_level);
+ break;
+ }
+
+ done:
+ return result;
+}
+
+static WERROR cmd_srvsvc_net_share_set_info(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ uint32 info_level = 502;
+ union srvsvc_NetShareInfo info_get;
+ WERROR result;
+ NTSTATUS status;
+ uint32_t parm_err = 0;
+
+ if (argc > 3) {
+ printf("Usage: %s [sharename] [comment]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ /* retrieve share info */
+ status = rpccli_srvsvc_NetShareGetInfo(cli, mem_ctx,
+ cli->desthost,
+ argv[1],
+ info_level,
+ &info_get,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ goto done;
+ }
+
+ info_get.info502->comment = argv[2];
+
+ /* set share info */
+ status = rpccli_srvsvc_NetShareSetInfo(cli, mem_ctx,
+ cli->desthost,
+ argv[1],
+ info_level,
+ &info_get,
+ &parm_err,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ goto done;
+ }
+
+ /* re-retrieve share info and display */
+ status = rpccli_srvsvc_NetShareGetInfo(cli, mem_ctx,
+ cli->desthost,
+ argv[1],
+ info_level,
+ &info_get,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ goto done;
+ }
+
+ display_share_info_502(info_get.info502);
+
+ done:
+ return result;
+}
+
+static WERROR cmd_srvsvc_net_remote_tod(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ struct srvsvc_NetRemoteTODInfo *tod = NULL;
+ WERROR result;
+ NTSTATUS status;
+
+ if (argc > 1) {
+ printf("Usage: %s\n", argv[0]);
+ return WERR_OK;
+ }
+
+ status = rpccli_srvsvc_NetRemoteTOD(cli, mem_ctx,
+ cli->srv_name_slash,
+ &tod,
+ &result);
+ if (!NT_STATUS_IS_OK(status)) {
+ result = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ done:
+ return result;
+}
+
+static WERROR cmd_srvsvc_net_file_enum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ uint32 info_level = 3;
+ struct srvsvc_NetFileInfoCtr info_ctr;
+ struct srvsvc_NetFileCtr3 ctr3;
+ WERROR result;
+ NTSTATUS status;
+ uint32 preferred_len = 0xffff;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+
+ if (argc > 2) {
+ printf("Usage: %s [infolevel]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc == 2)
+ info_level = atoi(argv[1]);
+
+ ZERO_STRUCT(info_ctr);
+ ZERO_STRUCT(ctr3);
+
+ info_ctr.level = info_level;
+ info_ctr.ctr.ctr3 = &ctr3;
+
+ status = rpccli_srvsvc_NetFileEnum(cli, mem_ctx,
+ cli->desthost,
+ NULL,
+ NULL,
+ &info_ctr,
+ preferred_len,
+ &total_entries,
+ &resume_handle,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result))
+ goto done;
+
+ done:
+ return result;
+}
+
+static WERROR cmd_srvsvc_net_name_validate(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ WERROR result;
+ NTSTATUS status;
+ uint32_t name_type = 9;
+ uint32_t flags = 0;
+
+ if (argc < 2 || argc > 3) {
+ printf("Usage: %s [sharename] [type]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc == 3) {
+ name_type = atoi(argv[2]);
+ }
+
+ status = rpccli_srvsvc_NetNameValidate(cli, mem_ctx,
+ cli->desthost,
+ argv[1],
+ name_type,
+ flags,
+ &result);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ done:
+ return result;
+}
+
+static WERROR cmd_srvsvc_net_file_get_sec(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ WERROR result;
+ NTSTATUS status;
+ struct sec_desc_buf *sd_buf = NULL;
+
+ if (argc < 2 || argc > 4) {
+ printf("Usage: %s [sharename] [file]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ status = rpccli_srvsvc_NetGetFileSecurity(cli, mem_ctx,
+ cli->desthost,
+ argv[1],
+ argv[2],
+ SECINFO_DACL,
+ &sd_buf,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ goto done;
+ }
+
+ display_sec_desc(sd_buf->sd);
+
+ done:
+ return result;
+}
+
+static WERROR cmd_srvsvc_net_sess_del(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ WERROR result;
+ NTSTATUS status;
+
+ if (argc < 2 || argc > 4) {
+ printf("Usage: %s [client] [user]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ status = rpccli_srvsvc_NetSessDel(cli, mem_ctx,
+ cli->desthost,
+ argv[1],
+ argv[2],
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ goto done;
+ }
+
+ done:
+ return result;
+}
+
+static WERROR cmd_srvsvc_net_sess_enum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ WERROR result;
+ NTSTATUS status;
+ struct srvsvc_NetSessInfoCtr info_ctr;
+ struct srvsvc_NetSessCtr0 ctr0;
+ struct srvsvc_NetSessCtr1 ctr1;
+ struct srvsvc_NetSessCtr2 ctr2;
+ struct srvsvc_NetSessCtr10 ctr10;
+ struct srvsvc_NetSessCtr502 ctr502;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ uint32_t *resume_handle_p = NULL;
+ uint32_t level = 1;
+ const char *client = NULL;
+ const char *user = NULL;
+
+ if (argc > 6) {
+ printf("Usage: %s [client] [user] [level] [resume_handle]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 2) {
+ client = argv[1];
+ }
+
+ if (argc >= 3) {
+ user = argv[2];
+ }
+
+ if (argc >= 4) {
+ level = atoi(argv[3]);
+ }
+
+ if (argc >= 5) {
+ resume_handle = atoi(argv[4]);
+ resume_handle_p = &resume_handle;
+ }
+
+ ZERO_STRUCT(info_ctr);
+
+ info_ctr.level = level;
+
+ d_printf("trying level: %d\n", level);
+
+ switch (level) {
+ case 0:
+ ZERO_STRUCT(ctr0);
+ info_ctr.ctr.ctr0 = &ctr0;
+ break;
+ case 1:
+ ZERO_STRUCT(ctr1);
+ info_ctr.ctr.ctr1 = &ctr1;
+ break;
+ case 2:
+ ZERO_STRUCT(ctr2);
+ info_ctr.ctr.ctr2 = &ctr2;
+ break;
+ case 10:
+ ZERO_STRUCT(ctr10);
+ info_ctr.ctr.ctr10 = &ctr10;
+ break;
+ case 502:
+ ZERO_STRUCT(ctr502);
+ info_ctr.ctr.ctr502 = &ctr502;
+ break;
+ }
+
+ status = rpccli_srvsvc_NetSessEnum(cli, mem_ctx,
+ cli->desthost,
+ client,
+ user,
+ &info_ctr,
+ 0xffffffff,
+ &total_entries,
+ resume_handle_p,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ goto done;
+ }
+
+ done:
+ return result;
+}
+
+static WERROR cmd_srvsvc_net_disk_enum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ struct srvsvc_NetDiskInfo info;
+ WERROR result;
+ NTSTATUS status;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ uint32_t level = 0;
+
+ if (argc > 4) {
+ printf("Usage: %s [level] [resume_handle]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 2) {
+ level = atoi(argv[1]);
+ }
+
+ if (argc >= 3) {
+ resume_handle = atoi(argv[2]);
+ }
+
+ ZERO_STRUCT(info);
+
+ status = rpccli_srvsvc_NetDiskEnum(cli, mem_ctx,
+ cli->desthost,
+ level,
+ &info,
+ 0xffffffff,
+ &total_entries,
+ &resume_handle,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ goto done;
+ }
+
+ done:
+ return result;
+}
+
+static WERROR cmd_srvsvc_net_conn_enum(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ struct srvsvc_NetConnInfoCtr info_ctr;
+ struct srvsvc_NetConnCtr0 ctr0;
+ struct srvsvc_NetConnCtr1 ctr1;
+ WERROR result;
+ NTSTATUS status;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ uint32_t *resume_handle_p = NULL;
+ uint32_t level = 1;
+ const char *path = "IPC$";
+
+ if (argc > 4) {
+ printf("Usage: %s [level] [path] [resume_handle]\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc >= 2) {
+ level = atoi(argv[1]);
+ }
+
+ if (argc >= 3) {
+ path = argv[2];
+ }
+
+ if (argc >= 4) {
+ resume_handle = atoi(argv[3]);
+ resume_handle_p = &resume_handle;
+ }
+
+ ZERO_STRUCT(info_ctr);
+
+ info_ctr.level = level;
+
+ switch (level) {
+ case 0:
+ ZERO_STRUCT(ctr0);
+ info_ctr.ctr.ctr0 = &ctr0;
+ break;
+ case 1:
+ ZERO_STRUCT(ctr1);
+ info_ctr.ctr.ctr1 = &ctr1;
+ break;
+ default:
+ return WERR_INVALID_PARAM;
+ }
+
+ status = rpccli_srvsvc_NetConnEnum(cli, mem_ctx,
+ cli->desthost,
+ path,
+ &info_ctr,
+ 0xffffffff,
+ &total_entries,
+ resume_handle_p,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ goto done;
+ }
+
+ done:
+ return result;
+}
+
+
+/* List of commands exported by this module */
+
+struct cmd_set srvsvc_commands[] = {
+
+ { "SRVSVC" },
+
+ { "srvinfo", RPC_RTYPE_WERROR, NULL, cmd_srvsvc_srv_query_info, &ndr_table_srvsvc.syntax_id, NULL, "Server query info", "" },
+ { "netshareenum",RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_share_enum, &ndr_table_srvsvc.syntax_id, NULL, "Enumerate shares", "" },
+ { "netshareenumall",RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_share_enum_all, &ndr_table_srvsvc.syntax_id, NULL, "Enumerate all shares", "" },
+ { "netsharegetinfo",RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_share_get_info, &ndr_table_srvsvc.syntax_id, NULL, "Get Share Info", "" },
+ { "netsharesetinfo",RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_share_set_info, &ndr_table_srvsvc.syntax_id, NULL, "Set Share Info", "" },
+ { "netfileenum", RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_file_enum, &ndr_table_srvsvc.syntax_id, NULL, "Enumerate open files", "" },
+ { "netremotetod",RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_remote_tod, &ndr_table_srvsvc.syntax_id, NULL, "Fetch remote time of day", "" },
+ { "netnamevalidate", RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_name_validate, &ndr_table_srvsvc.syntax_id, NULL, "Validate sharename", "" },
+ { "netfilegetsec", RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_file_get_sec, &ndr_table_srvsvc.syntax_id, NULL, "Get File security", "" },
+ { "netsessdel", RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_sess_del, &ndr_table_srvsvc.syntax_id, NULL, "Delete Session", "" },
+ { "netsessenum", RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_sess_enum, &ndr_table_srvsvc.syntax_id, NULL, "Enumerate Sessions", "" },
+ { "netdiskenum", RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_disk_enum, &ndr_table_srvsvc.syntax_id, NULL, "Enumerate Disks", "" },
+ { "netconnenum", RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_conn_enum, &ndr_table_srvsvc.syntax_id, NULL, "Enumerate Connections", "" },
+
+ { NULL }
+};
diff --git a/source3/rpcclient/cmd_test.c b/source3/rpcclient/cmd_test.c
new file mode 100644
index 0000000000..0f1d4221ca
--- /dev/null
+++ b/source3/rpcclient/cmd_test.c
@@ -0,0 +1,75 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+static NTSTATUS cmd_testme(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ struct rpc_pipe_client *lsa_pipe = NULL, *samr_pipe = NULL;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ POLICY_HND pol;
+
+ d_printf("testme\n");
+
+ status = cli_rpc_pipe_open_noauth(rpc_pipe_np_smb_conn(cli),
+ &ndr_table_lsarpc.syntax_id,
+ &lsa_pipe);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = cli_rpc_pipe_open_noauth(rpc_pipe_np_smb_conn(cli),
+ &ndr_table_samr.syntax_id,
+ &samr_pipe);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, False,
+ SEC_RIGHTS_QUERY_VALUE, &pol);
+
+ if (!NT_STATUS_IS_OK(status))
+ goto done;
+
+ status = rpccli_lsa_Close(lsa_pipe, mem_ctx, &pol);
+
+ if (!NT_STATUS_IS_OK(status))
+ goto done;
+
+ done:
+ TALLOC_FREE(lsa_pipe);
+ TALLOC_FREE(samr_pipe);
+
+ return status;
+}
+
+/* List of commands exported by this module */
+
+struct cmd_set test_commands[] = {
+
+ { "TESTING" },
+
+ { "testme", RPC_RTYPE_NTSTATUS, cmd_testme, NULL,
+ NULL, NULL, "Sample test", "testme" },
+
+ { NULL }
+};
diff --git a/source3/rpcclient/cmd_wkssvc.c b/source3/rpcclient/cmd_wkssvc.c
new file mode 100644
index 0000000000..7a34c450ab
--- /dev/null
+++ b/source3/rpcclient/cmd_wkssvc.c
@@ -0,0 +1,170 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Günther Deschner 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+static WERROR cmd_wkssvc_wkstagetinfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ WERROR werr;
+ uint32_t level = 100;
+ union wkssvc_NetWkstaInfo info;
+ const char *server_name;
+
+ if (argc > 2) {
+ printf("usage: %s <level>\n", argv[0]);
+ return WERR_OK;
+ }
+
+ if (argc > 1) {
+ level = atoi(argv[1]);
+ }
+
+ server_name = cli->desthost;
+
+ status = rpccli_wkssvc_NetWkstaGetInfo(cli, mem_ctx,
+ server_name,
+ level,
+ &info,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ return werr;
+}
+
+static WERROR cmd_wkssvc_getjoininformation(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ const char *server_name;
+ const char *name_buffer;
+ enum wkssvc_NetJoinStatus name_type;
+ NTSTATUS status;
+ WERROR werr;
+
+ server_name = cli->desthost;
+ name_buffer = "";
+
+ status = rpccli_wkssvc_NetrGetJoinInformation(cli, mem_ctx,
+ server_name,
+ &name_buffer,
+ &name_type,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ if (W_ERROR_IS_OK(werr)) {
+ printf("%s (%d)\n", name_buffer, name_type);
+ }
+
+ return werr;
+}
+
+static WERROR cmd_wkssvc_messagebuffersend(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ const char *server_name = cli->desthost;
+ const char *message_name = cli->desthost;
+ const char *message_sender_name = cli->desthost;
+ smb_ucs2_t *message_buffer = NULL;
+ size_t message_size = 0;
+ const char *message = "my message";
+ NTSTATUS status;
+ WERROR werr;
+
+ if (argc > 1) {
+ message = argv[1];
+ }
+
+ if (!push_ucs2_talloc(mem_ctx, &message_buffer, message,
+ &message_size))
+ {
+ return WERR_NOMEM;
+ }
+
+ status = rpccli_wkssvc_NetrMessageBufferSend(cli, mem_ctx,
+ server_name,
+ message_name,
+ message_sender_name,
+ (uint8_t *)message_buffer,
+ message_size,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ return werr;
+}
+
+static WERROR cmd_wkssvc_enumeratecomputernames(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ const char *server_name;
+ enum wkssvc_ComputerNameType name_type = NetAllComputerNames;
+ NTSTATUS status;
+ struct wkssvc_ComputerNamesCtr *ctr = NULL;
+ WERROR werr;
+
+ server_name = cli->desthost;
+
+ if (argc >= 2) {
+ name_type = atoi(argv[1]);
+ }
+
+ status = rpccli_wkssvc_NetrEnumerateComputerNames(cli, mem_ctx,
+ server_name,
+ name_type, 0,
+ &ctr,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ if (W_ERROR_IS_OK(werr)) {
+ int i=0;
+ for (i = 0; i < ctr->count; i++) {
+ printf("name: %d %s\n", i, ctr->computer_name->string);
+ }
+ }
+
+ return werr;
+}
+
+struct cmd_set wkssvc_commands[] = {
+
+ { "WKSSVC" },
+ { "wkssvc_wkstagetinfo", RPC_RTYPE_WERROR, NULL, cmd_wkssvc_wkstagetinfo, &ndr_table_wkssvc.syntax_id, NULL, "Query WKSSVC Workstation Information", "" },
+ { "wkssvc_getjoininformation", RPC_RTYPE_WERROR, NULL, cmd_wkssvc_getjoininformation, &ndr_table_wkssvc.syntax_id, NULL, "Query WKSSVC Join Information", "" },
+ { "wkssvc_messagebuffersend", RPC_RTYPE_WERROR, NULL, cmd_wkssvc_messagebuffersend, &ndr_table_wkssvc.syntax_id, NULL, "Send WKSSVC message", "" },
+ { "wkssvc_enumeratecomputernames", RPC_RTYPE_WERROR, NULL, cmd_wkssvc_enumeratecomputernames, &ndr_table_wkssvc.syntax_id, NULL, "Enumerate WKSSVC computer names", "" },
+ { NULL }
+};
diff --git a/source3/rpcclient/rpcclient.c b/source3/rpcclient/rpcclient.c
new file mode 100644
index 0000000000..e4cdd9c3f3
--- /dev/null
+++ b/source3/rpcclient/rpcclient.c
@@ -0,0 +1,959 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Tim Potter 2000-2001
+ Copyright (C) Martin Pool 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+DOM_SID domain_sid;
+
+static enum pipe_auth_type pipe_default_auth_type = PIPE_AUTH_TYPE_NONE;
+static enum pipe_auth_level pipe_default_auth_level = PIPE_AUTH_LEVEL_NONE;
+static unsigned int timeout = 0;
+
+/* List to hold groups of commands.
+ *
+ * Commands are defined in a list of arrays: arrays are easy to
+ * statically declare, and lists are easier to dynamically extend.
+ */
+
+static struct cmd_list {
+ struct cmd_list *prev, *next;
+ struct cmd_set *cmd_set;
+} *cmd_list;
+
+/****************************************************************************
+handle completion of commands for readline
+****************************************************************************/
+static char **completion_fn(const char *text, int start, int end)
+{
+#define MAX_COMPLETIONS 100
+ char **matches;
+ int i, count=0;
+ struct cmd_list *commands = cmd_list;
+
+#if 0 /* JERRY */
+ /* FIXME!!! -- what to do when completing argument? */
+ /* for words not at the start of the line fallback
+ to filename completion */
+ if (start)
+ return NULL;
+#endif
+
+ /* make sure we have a list of valid commands */
+ if (!commands) {
+ return NULL;
+ }
+
+ matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS);
+ if (!matches) {
+ return NULL;
+ }
+
+ matches[count++] = SMB_STRDUP(text);
+ if (!matches[0]) {
+ SAFE_FREE(matches);
+ return NULL;
+ }
+
+ while (commands && count < MAX_COMPLETIONS-1) {
+ if (!commands->cmd_set) {
+ break;
+ }
+
+ for (i=0; commands->cmd_set[i].name; i++) {
+ if ((strncmp(text, commands->cmd_set[i].name, strlen(text)) == 0) &&
+ (( commands->cmd_set[i].returntype == RPC_RTYPE_NTSTATUS &&
+ commands->cmd_set[i].ntfn ) ||
+ ( commands->cmd_set[i].returntype == RPC_RTYPE_WERROR &&
+ commands->cmd_set[i].wfn))) {
+ matches[count] = SMB_STRDUP(commands->cmd_set[i].name);
+ if (!matches[count]) {
+ for (i = 0; i < count; i++) {
+ SAFE_FREE(matches[count]);
+ }
+ SAFE_FREE(matches);
+ return NULL;
+ }
+ count++;
+ }
+ }
+ commands = commands->next;
+
+ }
+
+ if (count == 2) {
+ SAFE_FREE(matches[0]);
+ matches[0] = SMB_STRDUP(matches[1]);
+ }
+ matches[count] = NULL;
+ return matches;
+}
+
+static char *next_command (char **cmdstr)
+{
+ char *command;
+ char *p;
+
+ if (!cmdstr || !(*cmdstr))
+ return NULL;
+
+ p = strchr_m(*cmdstr, ';');
+ if (p)
+ *p = '\0';
+ command = SMB_STRDUP(*cmdstr);
+ if (p)
+ *cmdstr = p + 1;
+ else
+ *cmdstr = NULL;
+
+ return command;
+}
+
+/* Fetch the SID for this computer */
+
+static void fetch_machine_sid(struct cli_state *cli)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_OK;
+ static bool got_domain_sid;
+ TALLOC_CTX *mem_ctx;
+ struct rpc_pipe_client *lsapipe = NULL;
+ union lsa_PolicyInformation *info = NULL;
+
+ if (got_domain_sid) return;
+
+ if (!(mem_ctx=talloc_init("fetch_machine_sid"))) {
+ DEBUG(0,("fetch_machine_sid: talloc_init returned NULL!\n"));
+ goto error;
+ }
+
+ result = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
+ &lsapipe);
+ if (!NT_STATUS_IS_OK(result)) {
+ fprintf(stderr, "could not initialise lsa pipe. Error was %s\n", nt_errstr(result) );
+ goto error;
+ }
+
+ result = rpccli_lsa_open_policy(lsapipe, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto error;
+ }
+
+ result = rpccli_lsa_QueryInfoPolicy(lsapipe, mem_ctx,
+ &pol,
+ LSA_POLICY_INFO_ACCOUNT_DOMAIN,
+ &info);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto error;
+ }
+
+ got_domain_sid = True;
+ sid_copy(&domain_sid, info->account_domain.sid);
+
+ rpccli_lsa_Close(lsapipe, mem_ctx, &pol);
+ TALLOC_FREE(lsapipe);
+ talloc_destroy(mem_ctx);
+
+ return;
+
+ error:
+
+ if (lsapipe) {
+ TALLOC_FREE(lsapipe);
+ }
+
+ fprintf(stderr, "could not obtain sid for domain %s\n", cli->domain);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ fprintf(stderr, "error: %s\n", nt_errstr(result));
+ }
+
+ exit(1);
+}
+
+/* List the available commands on a given pipe */
+
+static NTSTATUS cmd_listcommands(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ struct cmd_list *tmp;
+ struct cmd_set *tmp_set;
+ int i;
+
+ /* Usage */
+
+ if (argc != 2) {
+ printf("Usage: %s <pipe>\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ /* Help on one command */
+
+ for (tmp = cmd_list; tmp; tmp = tmp->next)
+ {
+ tmp_set = tmp->cmd_set;
+
+ if (!StrCaseCmp(argv[1], tmp_set->name))
+ {
+ printf("Available commands on the %s pipe:\n\n", tmp_set->name);
+
+ i = 0;
+ tmp_set++;
+ while(tmp_set->name) {
+ printf("%30s", tmp_set->name);
+ tmp_set++;
+ i++;
+ if (i%3 == 0)
+ printf("\n");
+ }
+
+ /* drop out of the loop */
+ break;
+ }
+ }
+ printf("\n\n");
+
+ return NT_STATUS_OK;
+}
+
+/* Display help on commands */
+
+static NTSTATUS cmd_help(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ struct cmd_list *tmp;
+ struct cmd_set *tmp_set;
+
+ /* Usage */
+
+ if (argc > 2) {
+ printf("Usage: %s [command]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ /* Help on one command */
+
+ if (argc == 2) {
+ for (tmp = cmd_list; tmp; tmp = tmp->next) {
+
+ tmp_set = tmp->cmd_set;
+
+ while(tmp_set->name) {
+ if (strequal(argv[1], tmp_set->name)) {
+ if (tmp_set->usage &&
+ tmp_set->usage[0])
+ printf("%s\n", tmp_set->usage);
+ else
+ printf("No help for %s\n", tmp_set->name);
+
+ return NT_STATUS_OK;
+ }
+
+ tmp_set++;
+ }
+ }
+
+ printf("No such command: %s\n", argv[1]);
+ return NT_STATUS_OK;
+ }
+
+ /* List all commands */
+
+ for (tmp = cmd_list; tmp; tmp = tmp->next) {
+
+ tmp_set = tmp->cmd_set;
+
+ while(tmp_set->name) {
+
+ printf("%15s\t\t%s\n", tmp_set->name,
+ tmp_set->description ? tmp_set->description:
+ "");
+
+ tmp_set++;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/* Change the debug level */
+
+static NTSTATUS cmd_debuglevel(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ if (argc > 2) {
+ printf("Usage: %s [debuglevel]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2) {
+ DEBUGLEVEL = atoi(argv[1]);
+ }
+
+ printf("debuglevel is %d\n", DEBUGLEVEL);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_quit(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ exit(0);
+ return NT_STATUS_OK; /* NOTREACHED */
+}
+
+static NTSTATUS cmd_set_ss_level(void)
+{
+ struct cmd_list *tmp;
+
+ /* Close any existing connections not at this level. */
+
+ for (tmp = cmd_list; tmp; tmp = tmp->next) {
+ struct cmd_set *tmp_set;
+
+ for (tmp_set = tmp->cmd_set; tmp_set->name; tmp_set++) {
+ if (tmp_set->rpc_pipe == NULL) {
+ continue;
+ }
+
+ if ((tmp_set->rpc_pipe->auth->auth_type
+ != pipe_default_auth_type)
+ || (tmp_set->rpc_pipe->auth->auth_level
+ != pipe_default_auth_level)) {
+ TALLOC_FREE(tmp_set->rpc_pipe);
+ tmp_set->rpc_pipe = NULL;
+ }
+ }
+ }
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_sign(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ const char *type = "NTLMSSP";
+
+ pipe_default_auth_level = PIPE_AUTH_LEVEL_INTEGRITY;
+ pipe_default_auth_type = PIPE_AUTH_TYPE_NTLMSSP;
+
+ if (argc > 2) {
+ printf("Usage: %s [NTLMSSP|NTLMSSP_SPNEGO|SCHANNEL]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2) {
+ type = argv[1];
+ if (strequal(type, "NTLMSSP")) {
+ pipe_default_auth_type = PIPE_AUTH_TYPE_NTLMSSP;
+ } else if (strequal(type, "NTLMSSP_SPNEGO")) {
+ pipe_default_auth_type = PIPE_AUTH_TYPE_SPNEGO_NTLMSSP;
+ } else if (strequal(type, "SCHANNEL")) {
+ pipe_default_auth_type = PIPE_AUTH_TYPE_SCHANNEL;
+ } else {
+ printf("unknown type %s\n", type);
+ return NT_STATUS_INVALID_LEVEL;
+ }
+ }
+
+ d_printf("Setting %s - sign\n", type);
+
+ return cmd_set_ss_level();
+}
+
+static NTSTATUS cmd_seal(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ const char *type = "NTLMSSP";
+
+ pipe_default_auth_level = PIPE_AUTH_LEVEL_PRIVACY;
+ pipe_default_auth_type = PIPE_AUTH_TYPE_NTLMSSP;
+
+ if (argc > 2) {
+ printf("Usage: %s [NTLMSSP|NTLMSSP_SPNEGO|SCHANNEL]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2) {
+ type = argv[1];
+ if (strequal(type, "NTLMSSP")) {
+ pipe_default_auth_type = PIPE_AUTH_TYPE_NTLMSSP;
+ } else if (strequal(type, "NTLMSSP_SPNEGO")) {
+ pipe_default_auth_type = PIPE_AUTH_TYPE_SPNEGO_NTLMSSP;
+ } else if (strequal(type, "SCHANNEL")) {
+ pipe_default_auth_type = PIPE_AUTH_TYPE_SCHANNEL;
+ } else {
+ printf("unknown type %s\n", type);
+ return NT_STATUS_INVALID_LEVEL;
+ }
+ }
+
+ d_printf("Setting %s - sign and seal\n", type);
+
+ return cmd_set_ss_level();
+}
+
+static NTSTATUS cmd_timeout(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ struct cmd_list *tmp;
+
+ if (argc > 2) {
+ printf("Usage: %s timeout\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2) {
+ timeout = atoi(argv[1]);
+
+ for (tmp = cmd_list; tmp; tmp = tmp->next) {
+
+ struct cmd_set *tmp_set;
+
+ for (tmp_set = tmp->cmd_set; tmp_set->name; tmp_set++) {
+ if (tmp_set->rpc_pipe == NULL) {
+ continue;
+ }
+
+ rpccli_set_timeout(tmp_set->rpc_pipe, timeout);
+ }
+ }
+ }
+
+ printf("timeout is %d\n", timeout);
+
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_none(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ pipe_default_auth_level = PIPE_AUTH_LEVEL_NONE;
+ pipe_default_auth_type = PIPE_AUTH_TYPE_NONE;
+
+ return cmd_set_ss_level();
+}
+
+static NTSTATUS cmd_schannel(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ d_printf("Setting schannel - sign and seal\n");
+ pipe_default_auth_level = PIPE_AUTH_LEVEL_PRIVACY;
+ pipe_default_auth_type = PIPE_AUTH_TYPE_SCHANNEL;
+
+ return cmd_set_ss_level();
+}
+
+static NTSTATUS cmd_schannel_sign(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ d_printf("Setting schannel - sign only\n");
+ pipe_default_auth_level = PIPE_AUTH_LEVEL_INTEGRITY;
+ pipe_default_auth_type = PIPE_AUTH_TYPE_SCHANNEL;
+
+ return cmd_set_ss_level();
+}
+
+
+/* Built in rpcclient commands */
+
+static struct cmd_set rpcclient_commands[] = {
+
+ { "GENERAL OPTIONS" },
+
+ { "help", RPC_RTYPE_NTSTATUS, cmd_help, NULL, NULL, NULL, "Get help on commands", "[command]" },
+ { "?", RPC_RTYPE_NTSTATUS, cmd_help, NULL, NULL, NULL, "Get help on commands", "[command]" },
+ { "debuglevel", RPC_RTYPE_NTSTATUS, cmd_debuglevel, NULL, NULL, NULL, "Set debug level", "level" },
+ { "debug", RPC_RTYPE_NTSTATUS, cmd_debuglevel, NULL, NULL, NULL, "Set debug level", "level" },
+ { "list", RPC_RTYPE_NTSTATUS, cmd_listcommands, NULL, NULL, NULL, "List available commands on <pipe>", "pipe" },
+ { "exit", RPC_RTYPE_NTSTATUS, cmd_quit, NULL, NULL, NULL, "Exit program", "" },
+ { "quit", RPC_RTYPE_NTSTATUS, cmd_quit, NULL, NULL, NULL, "Exit program", "" },
+ { "sign", RPC_RTYPE_NTSTATUS, cmd_sign, NULL, NULL, NULL, "Force RPC pipe connections to be signed", "" },
+ { "seal", RPC_RTYPE_NTSTATUS, cmd_seal, NULL, NULL, NULL, "Force RPC pipe connections to be sealed", "" },
+ { "schannel", RPC_RTYPE_NTSTATUS, cmd_schannel, NULL, NULL, NULL, "Force RPC pipe connections to be sealed with 'schannel'. Assumes valid machine account to this domain controller.", "" },
+ { "schannelsign", RPC_RTYPE_NTSTATUS, cmd_schannel_sign, NULL, NULL, NULL, "Force RPC pipe connections to be signed (not sealed) with 'schannel'. Assumes valid machine account to this domain controller.", "" },
+ { "timeout", RPC_RTYPE_NTSTATUS, cmd_timeout, NULL, NULL, NULL, "Set timeout (in milliseonds) for RPC operations", "" },
+ { "none", RPC_RTYPE_NTSTATUS, cmd_none, NULL, NULL, NULL, "Force RPC pipe connections to have no special properties", "" },
+
+ { NULL }
+};
+
+static struct cmd_set separator_command[] = {
+ { "---------------", MAX_RPC_RETURN_TYPE, NULL, NULL, NULL, NULL, "----------------------" },
+ { NULL }
+};
+
+
+/* Various pipe commands */
+
+extern struct cmd_set lsarpc_commands[];
+extern struct cmd_set samr_commands[];
+extern struct cmd_set spoolss_commands[];
+extern struct cmd_set netlogon_commands[];
+extern struct cmd_set srvsvc_commands[];
+extern struct cmd_set dfs_commands[];
+extern struct cmd_set ds_commands[];
+extern struct cmd_set echo_commands[];
+extern struct cmd_set shutdown_commands[];
+extern struct cmd_set test_commands[];
+extern struct cmd_set wkssvc_commands[];
+extern struct cmd_set ntsvcs_commands[];
+extern struct cmd_set drsuapi_commands[];
+
+static struct cmd_set *rpcclient_command_list[] = {
+ rpcclient_commands,
+ lsarpc_commands,
+ ds_commands,
+ samr_commands,
+ spoolss_commands,
+ netlogon_commands,
+ srvsvc_commands,
+ dfs_commands,
+ echo_commands,
+ shutdown_commands,
+ test_commands,
+ wkssvc_commands,
+ ntsvcs_commands,
+ drsuapi_commands,
+ NULL
+};
+
+static void add_command_set(struct cmd_set *cmd_set)
+{
+ struct cmd_list *entry;
+
+ if (!(entry = SMB_MALLOC_P(struct cmd_list))) {
+ DEBUG(0, ("out of memory\n"));
+ return;
+ }
+
+ ZERO_STRUCTP(entry);
+
+ entry->cmd_set = cmd_set;
+ DLIST_ADD(cmd_list, entry);
+}
+
+
+/**
+ * Call an rpcclient function, passing an argv array.
+ *
+ * @param cmd Command to run, as a single string.
+ **/
+static NTSTATUS do_cmd(struct cli_state *cli,
+ struct cmd_set *cmd_entry,
+ int argc, char **argv)
+{
+ NTSTATUS ntresult;
+ WERROR wresult;
+
+ TALLOC_CTX *mem_ctx;
+
+ /* Create mem_ctx */
+
+ if (!(mem_ctx = talloc_init("do_cmd"))) {
+ DEBUG(0, ("talloc_init() failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Open pipe */
+
+ if ((cmd_entry->interface != NULL) && (cmd_entry->rpc_pipe == NULL)) {
+ switch (pipe_default_auth_type) {
+ case PIPE_AUTH_TYPE_NONE:
+ ntresult = cli_rpc_pipe_open_noauth(
+ cli, cmd_entry->interface,
+ &cmd_entry->rpc_pipe);
+ break;
+ case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP:
+ ntresult = cli_rpc_pipe_open_spnego_ntlmssp(
+ cli, cmd_entry->interface,
+ pipe_default_auth_level,
+ lp_workgroup(),
+ get_cmdline_auth_info_username(),
+ get_cmdline_auth_info_password(),
+ &cmd_entry->rpc_pipe);
+ break;
+ case PIPE_AUTH_TYPE_NTLMSSP:
+ ntresult = cli_rpc_pipe_open_ntlmssp(
+ cli, cmd_entry->interface,
+ pipe_default_auth_level,
+ lp_workgroup(),
+ get_cmdline_auth_info_username(),
+ get_cmdline_auth_info_password(),
+ &cmd_entry->rpc_pipe);
+ break;
+ case PIPE_AUTH_TYPE_SCHANNEL:
+ ntresult = cli_rpc_pipe_open_schannel(
+ cli, cmd_entry->interface,
+ pipe_default_auth_level,
+ lp_workgroup(),
+ &cmd_entry->rpc_pipe);
+ break;
+ default:
+ DEBUG(0, ("Could not initialise %s. Invalid "
+ "auth type %u\n",
+ cli_get_pipe_name_from_iface(
+ debug_ctx(), cli,
+ cmd_entry->interface),
+ pipe_default_auth_type ));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ if (!NT_STATUS_IS_OK(ntresult)) {
+ DEBUG(0, ("Could not initialise %s. Error was %s\n",
+ cli_get_pipe_name_from_iface(
+ debug_ctx(), cli,
+ cmd_entry->interface),
+ nt_errstr(ntresult) ));
+ return ntresult;
+ }
+
+ if (ndr_syntax_id_equal(cmd_entry->interface,
+ &ndr_table_netlogon.syntax_id)) {
+ uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+ uint32 sec_channel_type;
+ uchar trust_password[16];
+
+ if (!secrets_fetch_trust_account_password(lp_workgroup(),
+ trust_password,
+ NULL, &sec_channel_type)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ntresult = rpccli_netlogon_setup_creds(cmd_entry->rpc_pipe,
+ cli->desthost, /* server name */
+ lp_workgroup(), /* domain */
+ global_myname(), /* client name */
+ global_myname(), /* machine account name */
+ trust_password,
+ sec_channel_type,
+ &neg_flags);
+
+ if (!NT_STATUS_IS_OK(ntresult)) {
+ DEBUG(0, ("Could not initialise credentials for %s.\n",
+ cli_get_pipe_name_from_iface(
+ debug_ctx(), cli,
+ cmd_entry->interface)));
+ return ntresult;
+ }
+ }
+ }
+
+ /* Run command */
+
+ if ( cmd_entry->returntype == RPC_RTYPE_NTSTATUS ) {
+ ntresult = cmd_entry->ntfn(cmd_entry->rpc_pipe, mem_ctx, argc, (const char **) argv);
+ if (!NT_STATUS_IS_OK(ntresult)) {
+ printf("result was %s\n", nt_errstr(ntresult));
+ }
+ } else {
+ wresult = cmd_entry->wfn(cmd_entry->rpc_pipe, mem_ctx, argc, (const char **) argv);
+ /* print out the DOS error */
+ if (!W_ERROR_IS_OK(wresult)) {
+ printf( "result was %s\n", dos_errstr(wresult));
+ }
+ ntresult = W_ERROR_IS_OK(wresult)?NT_STATUS_OK:NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* Cleanup */
+
+ talloc_destroy(mem_ctx);
+
+ return ntresult;
+}
+
+
+/**
+ * Process a command entered at the prompt or as part of -c
+ *
+ * @returns The NTSTATUS from running the command.
+ **/
+static NTSTATUS process_cmd(struct cli_state *cli, char *cmd)
+{
+ struct cmd_list *temp_list;
+ NTSTATUS result = NT_STATUS_OK;
+ int ret;
+ int argc;
+ char **argv = NULL;
+
+ if ((ret = poptParseArgvString(cmd, &argc, (const char ***) &argv)) != 0) {
+ fprintf(stderr, "rpcclient: %s\n", poptStrerror(ret));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+
+ /* Walk through a dlist of arrays of commands. */
+ for (temp_list = cmd_list; temp_list; temp_list = temp_list->next) {
+ struct cmd_set *temp_set = temp_list->cmd_set;
+
+ while (temp_set->name) {
+ if (strequal(argv[0], temp_set->name)) {
+ if (!(temp_set->returntype == RPC_RTYPE_NTSTATUS && temp_set->ntfn ) &&
+ !(temp_set->returntype == RPC_RTYPE_WERROR && temp_set->wfn )) {
+ fprintf (stderr, "Invalid command\n");
+ goto out_free;
+ }
+
+ result = do_cmd(cli, temp_set, argc, argv);
+
+ goto out_free;
+ }
+ temp_set++;
+ }
+ }
+
+ if (argv[0]) {
+ printf("command not found: %s\n", argv[0]);
+ }
+
+out_free:
+/* moved to do_cmd()
+ if (!NT_STATUS_IS_OK(result)) {
+ printf("result was %s\n", nt_errstr(result));
+ }
+*/
+
+ /* NOTE: popt allocates the whole argv, including the
+ * strings, as a single block. So a single free is
+ * enough to release it -- we don't free the
+ * individual strings. rtfm. */
+ free(argv);
+
+ return result;
+}
+
+
+/* Main function */
+
+ int main(int argc, char *argv[])
+{
+ int opt;
+ static char *cmdstr = NULL;
+ const char *server;
+ struct cli_state *cli = NULL;
+ static char *opt_ipaddr=NULL;
+ struct cmd_set **cmd_set;
+ struct sockaddr_storage server_ss;
+ NTSTATUS nt_status;
+ static int opt_port = 0;
+ fstring new_workgroup;
+ int result = 0;
+ TALLOC_CTX *frame = talloc_stackframe();
+ uint32_t flags = 0;
+
+ /* make sure the vars that get altered (4th field) are in
+ a fixed location or certain compilers complain */
+ poptContext pc;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated cmds", "COMMANDS"},
+ {"dest-ip", 'I', POPT_ARG_STRING, &opt_ipaddr, 'I', "Specify destination IP address", "IP"},
+ {"port", 'p', POPT_ARG_INT, &opt_port, 'p', "Specify port number", "PORT"},
+ POPT_COMMON_SAMBA
+ POPT_COMMON_CONNECTION
+ POPT_COMMON_CREDENTIALS
+ POPT_TABLEEND
+ };
+
+ load_case_tables();
+
+ zero_addr(&server_ss);
+
+ setlinebuf(stdout);
+
+ /* the following functions are part of the Samba debugging
+ facilities. See lib/debug.c */
+ setup_logging("rpcclient", True);
+
+ /* Parse options */
+
+ pc = poptGetContext("rpcclient", argc, (const char **) argv,
+ long_options, 0);
+
+ if (argc == 1) {
+ poptPrintHelp(pc, stderr, 0);
+ goto done;
+ }
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+
+ case 'I':
+ if (!interpret_string_addr(&server_ss,
+ opt_ipaddr,
+ AI_NUMERICHOST)) {
+ fprintf(stderr, "%s not a valid IP address\n",
+ opt_ipaddr);
+ result = 1;
+ goto done;
+ }
+ }
+ }
+
+ /* Get server as remaining unparsed argument. Print usage if more
+ than one unparsed argument is present. */
+
+ server = poptGetArg(pc);
+
+ if (!server || poptGetArg(pc)) {
+ poptPrintHelp(pc, stderr, 0);
+ result = 1;
+ goto done;
+ }
+
+ poptFreeContext(pc);
+
+ load_interfaces();
+
+ if (!init_names()) {
+ result = 1;
+ goto done;
+ }
+
+ /* save the workgroup...
+
+ FIXME!! do we need to do this for other options as well
+ (or maybe a generic way to keep lp_load() from overwriting
+ everything)? */
+
+ fstrcpy( new_workgroup, lp_workgroup() );
+
+ /* Load smb.conf file */
+
+ if (!lp_load(get_dyn_CONFIGFILE(),True,False,False,True))
+ fprintf(stderr, "Can't load %s\n", get_dyn_CONFIGFILE());
+
+ if ( strlen(new_workgroup) != 0 )
+ set_global_myworkgroup( new_workgroup );
+
+ /*
+ * Get password
+ * from stdin if necessary
+ */
+
+ if (get_cmdline_auth_info_use_machine_account() &&
+ !set_cmdline_auth_info_machine_account_creds()) {
+ result = 1;
+ goto done;
+ }
+
+ if (!get_cmdline_auth_info_got_pass()) {
+ char *pass = getpass("Password:");
+ if (pass) {
+ set_cmdline_auth_info_password(pass);
+ }
+ }
+
+ if ((server[0] == '/' && server[1] == '/') ||
+ (server[0] == '\\' && server[1] == '\\')) {
+ server += 2;
+ }
+
+ if (get_cmdline_auth_info_use_kerberos()) {
+ flags |= CLI_FULL_CONNECTION_USE_KERBEROS |
+ CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
+ }
+
+
+ nt_status = cli_full_connection(&cli, global_myname(), server,
+ opt_ipaddr ? &server_ss : NULL, opt_port,
+ "IPC$", "IPC",
+ get_cmdline_auth_info_username(),
+ lp_workgroup(),
+ get_cmdline_auth_info_password(),
+ flags,
+ get_cmdline_auth_info_signing_state(),NULL);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0,("Cannot connect to server. Error was %s\n", nt_errstr(nt_status)));
+ result = 1;
+ goto done;
+ }
+
+ if (get_cmdline_auth_info_smb_encrypt()) {
+ nt_status = cli_cm_force_encryption(cli,
+ get_cmdline_auth_info_username(),
+ get_cmdline_auth_info_password(),
+ lp_workgroup(),
+ "IPC$");
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ result = 1;
+ goto done;
+ }
+ }
+
+#if 0 /* COMMENT OUT FOR TESTING */
+ memset(cmdline_auth_info.password,'X',sizeof(cmdline_auth_info.password));
+#endif
+
+ /* Load command lists */
+
+ timeout = cli_set_timeout(cli, 10000);
+
+ cmd_set = rpcclient_command_list;
+
+ while(*cmd_set) {
+ add_command_set(*cmd_set);
+ add_command_set(separator_command);
+ cmd_set++;
+ }
+
+ fetch_machine_sid(cli);
+
+ /* Do anything specified with -c */
+ if (cmdstr && cmdstr[0]) {
+ char *cmd;
+ char *p = cmdstr;
+
+ result = 0;
+
+ while((cmd=next_command(&p)) != NULL) {
+ NTSTATUS cmd_result = process_cmd(cli, cmd);
+ SAFE_FREE(cmd);
+ result = NT_STATUS_IS_ERR(cmd_result);
+ }
+
+ goto done;
+ }
+
+ /* Loop around accepting commands */
+
+ while(1) {
+ char *line = NULL;
+
+ line = smb_readline("rpcclient $> ", NULL, completion_fn);
+
+ if (line == NULL)
+ break;
+
+ if (line[0] != '\n')
+ process_cmd(cli, line);
+ SAFE_FREE(line);
+ }
+
+done:
+ if (cli != NULL) {
+ cli_shutdown(cli);
+ }
+ TALLOC_FREE(frame);
+ return result;
+}
diff --git a/source3/rpcclient/rpcclient.h b/source3/rpcclient/rpcclient.h
new file mode 100644
index 0000000000..91810b63a9
--- /dev/null
+++ b/source3/rpcclient/rpcclient.h
@@ -0,0 +1,42 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef RPCCLIENT_H
+#define RPCCLIENT_H
+
+typedef enum {
+ RPC_RTYPE_NTSTATUS = 0,
+ RPC_RTYPE_WERROR,
+ MAX_RPC_RETURN_TYPE
+} RPC_RETURN_TYPE;
+
+struct cmd_set {
+ const char *name;
+ RPC_RETURN_TYPE returntype;
+ NTSTATUS (*ntfn)(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc,
+ const char **argv);
+ WERROR (*wfn)(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv);
+ const struct ndr_syntax_id *interface;
+ struct rpc_pipe_client *rpc_pipe;
+ const char *description;
+ const char *usage;
+};
+
+#endif /* RPCCLIENT_H */
diff --git a/source3/script/build_env.sh b/source3/script/build_env.sh
new file mode 100755
index 0000000000..eb54f37aed
--- /dev/null
+++ b/source3/script/build_env.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+if [ $# -lt 3 ]
+then
+ echo "Usage: $0 srcdir builddir compiler"
+ exit 1
+fi
+
+uname=`uname -a`
+date=`date`
+srcdir=$1
+builddir=$2
+compiler=$3
+
+if [ ! "x$USER" = "x" ]; then
+ whoami=$USER
+else
+ if [ ! "x$LOGNAME" = "x" ]; then
+ whoami=$LOGNAME
+ else
+ whoami=`whoami || id -un`
+ fi
+fi
+
+host=`hostname`
+
+cat <<EOF
+/* This file is automatically generated with "make include/build_env.h". DO NOT EDIT */
+
+#ifndef _BUILD_ENV_H
+#define _BUILD_ENV_H
+
+#define BUILD_ENV_UNAME "${uname}"
+#define BUILD_ENV_DATE "${date}"
+#define BUILD_ENV_SRCDIR "${srcdir}"
+#define BUILD_ENV_BUILDDIR "${builddir}"
+#define BUILD_ENV_USER "${whoami}"
+#define BUILD_ENV_HOST "${host}"
+#define BUILD_ENV_COMPILER "${compiler}"
+#endif /* _BUILD_ENV_H */
+EOF
diff --git a/source3/script/build_idl.sh b/source3/script/build_idl.sh
new file mode 100755
index 0000000000..7aaddc70c7
--- /dev/null
+++ b/source3/script/build_idl.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+PIDL_ARGS="--outputdir librpc/gen_ndr --header --ndr-parser --samba3-ndr-server --samba3-ndr-client --"
+PIDL_EXTRA_ARGS="$*"
+
+oldpwd=`pwd`
+cd ${srcdir}
+
+[ -d librpc/gen_ndr ] || mkdir -p librpc/gen_ndr || exit 1
+
+if [ -z "$PIDL" ] ; then
+ PIDL=pidl
+fi
+
+PIDL="$PIDL ${PIDL_ARGS} ${PIDL_EXTRA_ARGS}"
+
+##
+## Find newer files rather than rebuild all of them
+##
+
+list=""
+for f in ${IDL_FILES}; do
+ basename=`basename $f .idl`
+ ndr="librpc/gen_ndr/ndr_$basename.c"
+
+ if [ -f $ndr ] && false; then
+ if [ "x`find librpc/idl/$f -newer $ndr -print`" = "xlibrpc/idl/$f" ]; then
+ list="$list librpc/idl/$f"
+ fi
+ else
+ list="$list librpc/idl/$f"
+ fi
+done
+
+##
+## generate the ndr stubs
+##
+
+if [ "x$list" != x ]; then
+ # echo "${PIDL} ${list}"
+ $PIDL $list || exit 1
+fi
+
+cd ${oldpwd}
+
+exit 0
+
diff --git a/source3/script/count_80_col.pl b/source3/script/count_80_col.pl
new file mode 100755
index 0000000000..8b226228c9
--- /dev/null
+++ b/source3/script/count_80_col.pl
@@ -0,0 +1,16 @@
+#!/usr/bin/perl -w
+
+open( INFILE, "$ARGV[0]" ) || die $@;
+
+$count = 0;
+while ( <INFILE> ) {
+ next if ($_ =~ /^#define/);
+ $count++ if (length($_) > 80);
+}
+
+close( INFILE );
+print "$ARGV[0]: $count lines > 80 characters\n" if ($count > 0);
+
+exit( 0 );
+
+
diff --git a/source3/script/creategroup b/source3/script/creategroup
new file mode 100755
index 0000000000..01fb065944
--- /dev/null
+++ b/source3/script/creategroup
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# Example script for 'add group command'. Handle weird NT group
+# names. First attempt to create the group directly, if that fails
+# then create a random group and print the numeric group id.
+#
+# Note that this is only an example and assumes /dev/urandom.
+#
+# Volker
+
+GROUPNAME="$1"
+ITERS=0
+
+while ! /usr/sbin/groupadd "$GROUPNAME" > /dev/null 2>&1
+do
+ # we had difficulties creating that group. Maybe the name was
+ # too weird, or it already existed. Create a random name.
+ GROUPNAME=nt-$(dd if=/dev/urandom bs=16 count=1 2>/dev/null | md5sum | cut -b 1-5)
+ ITERS=$(expr "$ITERS" + 1)
+ if [ "$ITERS" -gt 10 ]
+ then
+ # Too many attempts
+ exit 1
+ fi
+done
+
+getent group | grep ^"$GROUPNAME": | cut -d : -f 3
diff --git a/source3/script/extract_allparms.sh b/source3/script/extract_allparms.sh
new file mode 100755
index 0000000000..f16068b3fd
--- /dev/null
+++ b/source3/script/extract_allparms.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+grep '{".*P_[GL]' param/loadparm.c | sed -e 's/&.*$//g' -e 's/",.*P_LOCAL.*$/ S/' -e 's/",.*P_GLOBAL.*$/ G/' -e 's/^ .*{"//g' | sort -f
diff --git a/source3/script/findsmb.in b/source3/script/findsmb.in
new file mode 100755
index 0000000000..546cf8ce7b
--- /dev/null
+++ b/source3/script/findsmb.in
@@ -0,0 +1,161 @@
+#!@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 [-d|-D] [-r] [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.
+#
+# Options:
+#
+# -d|-D enable debug
+# -r add -r option to nmblookup when finding netbios name
+#
+
+$SAMBABIN = "@prefix@/bin";
+
+for ($i = 0; $i < 2; $i++) { # test for -d and -r options
+ $_ = shift;
+ if (m/-d|-D/) {
+ $DEBUG = 1;
+ } elsif (m/-r/) {
+ $R_OPTION = "-r";
+ }
+}
+
+if ($_) { # set broadcast address if it was specified
+ $BCAST = "-B $_";
+}
+
+
+######################################################################
+# do numeric sort on last field of IP address
+sub ipsort
+{
+ @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 '*' --debuglevel=0|") ||
+ 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 "\n *=DMB\n";
+print " +=LMB\n";
+print "IP 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_OPTION -A $ip --debuglevel=0|") ||
+ 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 {
+ # The Netbios name can contain lot of characters also '<' '>'
+ # and spaces. The follwing cure inside name space but not
+ # names starting or ending with spaces
+ /(.{1,15})\s+<00>\s+/;
+ $name = $1;
+ $name =~ s/^\s+//g;
+ }
+
+ # do an smbclient command on the netbios name.
+
+ if ( "$name" ) {
+ open(SMB,"$SAMBABIN/smbclient -L $name -I $ip -N --debuglevel=1 2>&1 |") ||
+ 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 ($_) {
+ # Same as before for space and characters
+ /(.{1,15})\s+<00>\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/source3/script/findstatic.pl b/source3/script/findstatic.pl
new file mode 100755
index 0000000000..43a4916435
--- /dev/null
+++ b/source3/script/findstatic.pl
@@ -0,0 +1,70 @@
+#!/usr/bin/perl -w
+# find a list of fns and variables in the code that could be static
+# usually called with something like this:
+# findstatic.pl `find . -name "*.o"`
+# Andrew Tridgell <tridge@samba.org>
+
+use strict;
+
+# use nm to find the symbols
+my($saved_delim) = $/;
+undef $/;
+my($syms) = `nm -o @ARGV`;
+$/ = $saved_delim;
+
+my(@lines) = split(/\n/s, $syms);
+
+my(%def);
+my(%undef);
+my(%stype);
+
+my(%typemap) = (
+ "T" => "function",
+ "C" => "uninitialised variable",
+ "D" => "initialised variable"
+ );
+
+
+# parse the symbols into defined and undefined
+for (my($i)=0; $i <= $#{@lines}; $i++) {
+ my($line) = $lines[$i];
+ if ($line =~ /(.*):[a-f0-9]* ([TCD]) (.*)/) {
+ my($fname) = $1;
+ my($symbol) = $3;
+ push(@{$def{$fname}}, $symbol);
+ $stype{$symbol} = $2;
+ }
+ if ($line =~ /(.*):\s* U (.*)/) {
+ my($fname) = $1;
+ my($symbol) = $2;
+ push(@{$undef{$fname}}, $symbol);
+ }
+}
+
+# look for defined symbols that are never referenced outside the place they
+# are defined
+foreach my $f (keys %def) {
+ print "Checking $f\n";
+ my($found_one) = 0;
+ foreach my $s (@{$def{$f}}) {
+ my($found) = 0;
+ foreach my $f2 (keys %undef) {
+ if ($f2 ne $f) {
+ foreach my $s2 (@{$undef{$f2}}) {
+ if ($s2 eq $s) {
+ $found = 1;
+ $found_one = 1;
+ }
+ }
+ }
+ }
+ if ($found == 0) {
+ my($t) = $typemap{$stype{$s}};
+ print " '$s' is unique to $f ($t)\n";
+ }
+ }
+ if ($found_one == 0) {
+ print " all symbols in '$f' are unused (main program?)\n";
+ }
+}
+
diff --git a/source3/script/fix_bool.pl b/source3/script/fix_bool.pl
new file mode 100755
index 0000000000..c09645de7c
--- /dev/null
+++ b/source3/script/fix_bool.pl
@@ -0,0 +1,19 @@
+#!/usr/bin/perl -w
+
+open(INFILE, "$ARGV[0]") || die $@;
+open(OUTFILE, ">$ARGV[0].new") || die $@;
+
+while (<INFILE>) {
+ $_ =~ s/True/true/;
+ $_ =~ s/False/false/;
+ print OUTFILE "$_";
+}
+
+close(INFILE);
+close(OUTFILE);
+
+rename("$ARGV[0].new", "$ARGV[0]") || die @_;
+
+exit(0);
+
+
diff --git a/source3/script/format_indent.sh b/source3/script/format_indent.sh
new file mode 100755
index 0000000000..2af1ab41fa
--- /dev/null
+++ b/source3/script/format_indent.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# -npro Do no read the '.indent.pro' files.
+# -kr Use K&R formatting rules
+# -i8 Set indentation level to 8 spaces.
+# -ts8 Set tab size to 8 spaces
+# -sob Swallow optional blank lines.
+# -l80 Set the maximum line length at 80 characters.
+# -ss On one-line for and while statments, force a blank before the semicolon
+# -ncs Do not put a space after cast operators.
+
+indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs "$@"
diff --git a/source3/script/gap.awk b/source3/script/gap.awk
new file mode 100644
index 0000000000..11680d10f9
--- /dev/null
+++ b/source3/script/gap.awk
@@ -0,0 +1,39 @@
+BEGIN { hv["0"] = 0; hv["1"] = 1; hv["2"] = 2; hv["3"] = 3;
+ hv["4"] = 4; hv["5"] = 5; hv["6"] = 6; hv["7"] = 7;
+ hv["8"] = 8; hv["9"] = 9; hv["A"] = 10; hv["B"] = 11;
+ hv["C"] = 12; hv["D"] = 13; hv["E"] = 14; hv["F"] = 15;
+ hv["a"] = 10; hv["b"] = 11; hv["c"] = 12; hv["d"] = 13;
+ hv["e"] = 14; hv["f"] = 15;
+
+ first = 0; last = 0; idx = 0;
+}
+
+function tonum(str)
+{
+ num=0;
+ cnt=1;
+ while (cnt <= length(str)) {
+ num *= 16;
+ num += hv[substr(str,cnt,1)];
+ ++cnt;
+ }
+ return num;
+}
+
+{
+ u = tonum($1);
+ if (u - last > 6)
+ {
+ if (last)
+ {
+ printf (" { 0x%04x, 0x%04x, %5d },\n",
+ first, last, idx);
+ idx -= u - last - 1;
+ }
+ first = u;
+ }
+ last = u;
+}
+
+END { printf (" { 0x%04x, 0x%04x, %5d },\n",
+ first, last, idx); }
diff --git a/source3/script/gaptab.awk b/source3/script/gaptab.awk
new file mode 100644
index 0000000000..a309089cd5
--- /dev/null
+++ b/source3/script/gaptab.awk
@@ -0,0 +1,48 @@
+BEGIN { hv["0"] = 0; hv["1"] = 1; hv["2"] = 2; hv["3"] = 3;
+ hv["4"] = 4; hv["5"] = 5; hv["6"] = 6; hv["7"] = 7;
+ hv["8"] = 8; hv["9"] = 9; hv["A"] = 10; hv["B"] = 11;
+ hv["C"] = 12; hv["D"] = 13; hv["E"] = 14; hv["F"] = 15;
+ hv["a"] = 10; hv["b"] = 11; hv["c"] = 12; hv["d"] = 13;
+ hv["e"] = 14; hv["f"] = 15;
+
+ first = 0; last = 0; idx = 0; f = 0;
+}
+
+function tonum(str)
+{
+ num=0;
+ cnt=1;
+ while (cnt <= length(str)) {
+ num *= 16;
+ num += hv[substr(str,cnt,1)];
+ ++cnt;
+ }
+ return num;
+}
+
+function fmt(val)
+{
+ if (f++ % 8 == 0)
+ { printf ("\n 0x%02x,", val); }
+ else
+ { printf (" 0x%02x,", val); }
+}
+
+{
+ u = tonum($1); c = tonum($2);
+
+ if (u - last > 6)
+ {
+ if (last) { idx += last - first + 1; }
+ first = u;
+ }
+ else
+ {
+ for (m = last+1; m < u; m++) { fmt(0); }
+ }
+
+ fmt(c);
+ last = u;
+}
+
+END { print "" }
diff --git a/source3/script/gen-8bit-gap.awk b/source3/script/gen-8bit-gap.awk
new file mode 100644
index 0000000000..59a1a23be0
--- /dev/null
+++ b/source3/script/gen-8bit-gap.awk
@@ -0,0 +1,18 @@
+BEGIN {
+ for (i=0; i<256; i++) {
+ tbl[sprintf("%02x",i)] = "0x0000";
+ }
+}
+
+/^<U([[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]])>[[:space:]]*.x([[:xdigit:]][[:xdigit:]])[:space:]*.*$/ {
+ tbl[substr($2,3,2)]=sprintf("0x%s",substr($1,3,4));
+}
+
+END {
+ for(i=0; i<32; i++) {
+ for(j=0; j<8; j++) {
+ printf(" %s,", tbl[sprintf("%02x",i*8+j)]);
+ }
+ printf "\n"
+ }
+} \ No newline at end of file
diff --git a/source3/script/gen-8bit-gap.sh.in b/source3/script/gen-8bit-gap.sh.in
new file mode 100755
index 0000000000..0ceaa8128b
--- /dev/null
+++ b/source3/script/gen-8bit-gap.sh.in
@@ -0,0 +1,48 @@
+#!/bin/sh
+if test $# -ne 2 ; then
+ echo "Usage: $0 <charmap file> <CHARSET NAME>"
+ exit 1
+fi
+
+CHARMAP=$1
+CHARSETNAME=$2
+
+echo "/* "
+echo " * Conversion table for $CHARSETNAME charset "
+echo " * "
+echo " * Conversion tables are generated using $CHARMAP table "
+echo " * and source/script/gen-8bit-gap.sh script "
+echo " * "
+echo " * This program is free software; you can redistribute it and/or modify "
+echo " * it under the terms of the GNU General Public License as published by "
+echo " * the Free Software Foundation; either version 3 of the License, or "
+echo " * (at your option) any later version. "
+echo " * "
+echo " * This program is distributed in the hope that it will be useful,"
+echo " * but WITHOUT ANY WARRANTY; without even the implied warranty of "
+echo " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
+echo " * GNU General Public License for more details. "
+echo " * "
+echo " * You should have received a copy of the GNU General Public License "
+echo " * along with this program; if not, see <http://www.gnu.org/licenses/>."
+echo " */"
+
+echo '#include "includes.h"'
+echo
+echo "static const uint16 to_ucs2[256] = {"
+cat "$CHARMAP" | @AWK@ -f @srcdir@/script/gen-8bit-gap.awk
+echo "};"
+echo
+echo "static const struct charset_gap_table from_idx[] = {"
+sed -ne 's/^<U\(....\).*/\1/p' \
+ "$CHARMAP" | sort -u | @AWK@ -f @srcdir@/script/gap.awk
+echo " { 0xffff, 0xffff, 0 }"
+echo "};"
+echo
+echo "static const unsigned char from_ucs2[] = {"
+sed -ne 's/^<U\(....\)>[[:space:]]*.x\(..\).*/\1 \2/p' \
+ "$CHARMAP" | sort -u | @AWK@ -f @srcdir@/script/gaptab.awk
+echo "};"
+echo
+echo "SMB_GENERATE_CHARSET_MODULE_8_BIT_GAP($CHARSETNAME)"
+echo
diff --git a/source3/script/installbin.sh.in b/source3/script/installbin.sh.in
new file mode 100755
index 0000000000..c607d9e445
--- /dev/null
+++ b/source3/script/installbin.sh.in
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+INSTALLPERMS=$1
+DESTDIR=$2
+prefix=`echo $3 | sed 's/\/\//\//g'`
+BINDIR=`echo $4 | sed 's/\/\//\//g'`
+SBINDIR=@sbindir@
+shift
+shift
+shift
+shift
+
+for p in $*; do
+ p2=`basename $p`
+ echo "Installing $p as $DESTDIR/$BINDIR/$p2 "
+ if [ -f $DESTDIR/$BINDIR/$p2 ]; then
+ rm -f $DESTDIR/$BINDIR/$p2.old
+ mv $DESTDIR/$BINDIR/$p2 $DESTDIR/$BINDIR/$p2.old
+ fi
+ cp $p $DESTDIR/$BINDIR/
+ chmod $INSTALLPERMS $DESTDIR/$BINDIR/$p2
+done
+
+
+cat << EOF
+======================================================================
+The binaries are installed. You may restore the old binaries (if there
+were any) using the command "make revert". You may uninstall the binaries
+using the command "make uninstallbin" or "make uninstall" to uninstall
+binaries, man pages and shell scripts.
+======================================================================
+EOF
+
+exit 0
diff --git a/source3/script/installdat.sh b/source3/script/installdat.sh
new file mode 100755
index 0000000000..59bf2f919d
--- /dev/null
+++ b/source3/script/installdat.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+#fist version March 2002, Herb Lewis
+
+DESTDIR=$1
+DATDIR=`echo $2 | sed 's/\/\//\//g'`
+SRCDIR=$3/
+shift
+shift
+shift
+
+case $0 in
+ *uninstall*)
+ if test ! -d "$DESTDIR/$DATDIR"; then
+ echo "Directory $DESTDIR/$DATDIR does not exist! "
+ echo "Do a "make installmsg" or "make install" first. "
+ exit 1
+ fi
+ mode='uninstall'
+ ;;
+ *) mode='install' ;;
+esac
+
+for f in $SRCDIR/codepages/*.dat; do
+ FNAME="$DESTDIR/$DATDIR/`basename $f`"
+ if test "$mode" = 'install'; then
+ echo "Installing $f as $FNAME "
+ cp "$f" "$FNAME"
+ if test ! -f "$FNAME"; then
+ echo "Cannot install $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ chmod 0644 "$FNAME"
+ elif test "$mode" = 'uninstall'; then
+ echo "Removing $FNAME "
+ rm -f "$FNAME"
+ if test -f "$FNAME"; then
+ echo "Cannot remove $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ else
+ echo "Unknown mode, $mode. Script called as $0 "
+ exit 1
+ fi
+done
+
+if test "$mode" = 'install'; then
+ cat << EOF
+======================================================================
+The dat files have been installed. You may uninstall the dat files
+using the command "make uninstalldat" or "make uninstall" to uninstall
+binaries, man pages, dat files, and shell scripts.
+======================================================================
+EOF
+else
+ cat << EOF
+======================================================================
+The dat files have been removed. You may restore these files using
+the command "make installdat" or "make install" to install binaries,
+man pages, modules, dat files, and shell scripts.
+======================================================================
+EOF
+fi
+
+exit 0
+
diff --git a/source3/script/installdirs.sh b/source3/script/installdirs.sh
new file mode 100755
index 0000000000..062b34b8c6
--- /dev/null
+++ b/source3/script/installdirs.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+INSTALLPERMS=$1
+DESTDIR=`echo $2 | sed 's/\/\//\//g'`
+shift
+shift
+
+for dir in $@; do
+ DIRNAME=`echo $dir | sed 's/\/\//\//g'`
+ if [ ! -d $DESTDIR/$DIRNAME ]; then
+ mkdir -m $INSTALLPERMS -p $DESTDIR/$DIRNAME
+ fi
+
+ if [ ! -d $DESTDIR/$DIRNAME ]; then
+ echo "Failed to make directory $DESTDIR/$DIRNAME "
+ exit 1
+ fi
+done
diff --git a/source3/script/installman.sh b/source3/script/installman.sh
new file mode 100755
index 0000000000..ab9bfe506d
--- /dev/null
+++ b/source3/script/installman.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+#5 July 96 Dan.Shearer@unisa.edu.au removed hardcoded values
+#
+# 13 Aug 2001 Rafal Szczesniak <mimir@spin.ict.pwr.wroc.pl>
+# modified to accomodate international man pages (inspired
+# by Japanese edition's approach)
+
+MANDIR=`echo $1 | sed 's/\/\//\//g'`
+SRCDIR=$2/
+langs=$3
+
+if [ $# -ge 4 ] ; then
+ GROFF=$4 # sh cmd line, including options
+fi
+
+if test ! -d $SRCDIR../docs/manpages; then
+ echo "No manpages present. Development version maybe?"
+ exit 0
+fi
+
+# Get the configured feature set
+test -f "${SRCDIR}/config.log" && \
+ eval `grep "^[[:alnum:]]*=.*" "${SRCDIR}/config.log"`
+
+for lang in $langs; do
+ if [ "X$lang" = XC ]; then
+ echo Installing default man pages in $MANDIR/
+ lang=.
+ else
+ echo Installing \"$lang\" man pages in $MANDIR/lang/$lang
+ fi
+
+ langdir=$MANDIR/$lang
+ for d in $MANDIR $langdir $langdir/man1 $langdir/man5 $langdir/man7 $langdir/man8; do
+ if [ ! -d $d ]; then
+ mkdir $d
+ if [ ! -d $d ]; then
+ echo Failed to make directory $d, does $USER have privileges?
+ exit 1
+ fi
+ fi
+ done
+
+ for sect in 1 5 7 8 ; do
+ for m in $langdir/man$sect ; do
+ for s in $SRCDIR../docs/manpages/$lang/*$sect; do
+ MP_BASENAME=`basename $s`
+
+ # Check if this man page if required by the configured feature set
+ case "${MP_BASENAME}" in
+ smbsh.1) test -z "${SMBWRAPPER}" && continue ;;
+ *) ;;
+ esac
+
+ FNAME="$m/${MP_BASENAME}"
+
+ # Test for writability. Involves
+ # blowing away existing files.
+
+ if (rm -f $FNAME && touch $FNAME); then
+ if [ "x$GROFF" = x ] ; then
+ cp $s $m # Copy raw nroff
+ else
+ echo "\t$FNAME" # groff'ing can be slow, give the user
+ # a warm fuzzy.
+ $GROFF $s > $FNAME # Process nroff, because man(1) (on
+ # this system) doesn't .
+ fi
+ chmod 0644 $FNAME
+ else
+ echo Cannot create $FNAME... does $USER have privileges?
+ fi
+ done
+ done
+ done
+done
+cat << EOF
+======================================================================
+The man pages have been installed. You may uninstall them using the command
+the command "make uninstallman" or make "uninstall" to uninstall binaries,
+man pages and shell scripts.
+======================================================================
+EOF
+
+exit 0
+
diff --git a/source3/script/installmodules.sh b/source3/script/installmodules.sh
new file mode 100755
index 0000000000..f70db003ed
--- /dev/null
+++ b/source3/script/installmodules.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+INSTALLPERMS=$1
+DESTDIR=$2
+prefix=`echo $3 | sed 's/\/\//\//g'`
+LIBDIR=`echo $4 | sed 's/\/\//\//g'`
+shift
+shift
+shift
+shift
+
+for d in $prefix $LIBDIR; do
+if [ ! -d $DESTDIR/$d ]; then
+mkdir $DESTDIR/$d
+if [ ! -d $DESTDIR/$d ]; then
+ echo Failed to make directory $DESTDIR/$d
+ exit 1
+fi
+fi
+done
+
+# We expect the last component of LIBDIR to be the module type, eg. idmap,
+# pdb. By stripping this from the installation name, you can have multiple
+# modules of the same name but different types by creating eg. idmap_foo
+# and pdb_foo. This makes the most sense for idmap and pdb module, where
+# they need to be consistent.
+mtype=`basename $LIBDIR`
+
+for p in $*; do
+ p2=`basename $p`
+ name=`echo $p2 | sed -es/${mtype}_//`
+ echo Installing $p as $DESTDIR/$LIBDIR/$name
+ cp -f $p $DESTDIR/$LIBDIR/$name
+ chmod $INSTALLPERMS $DESTDIR/$LIBDIR/$name
+done
+
+exit 0
diff --git a/source3/script/installmsg.sh b/source3/script/installmsg.sh
new file mode 100644
index 0000000000..859e4c10cf
--- /dev/null
+++ b/source3/script/installmsg.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+# first version (Sept 2003) written by Shiro Yamada <shiro@miraclelinux.com>
+# based on the first verion (March 2002) of installdat.sh written by Herb Lewis
+
+DESTDIR=$1
+MSGDIR=`echo $2 | sed 's/\/\//\//g'`
+SRCDIR=$3/
+shift
+shift
+shift
+
+case $0 in
+ *uninstall*)
+ if test ! -d "$DESTDIR/$MSGDIR"; then
+ echo "Directory $DESTDIR/$MSGDIR does not exist! "
+ echo "Do a "make installmsg" or "make install" first. "
+ exit 1
+ fi
+ mode='uninstall'
+ ;;
+ *) mode='install' ;;
+esac
+
+for f in $SRCDIR/po/*.msg; do
+ FNAME="$DESTDIR/$MSGDIR/`basename $f`"
+ if test "$mode" = 'install'; then
+ echo "Installing $f as $FNAME "
+ cp "$f" "$FNAME"
+ if test ! -f "$FNAME"; then
+ echo "Cannot install $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ chmod 0644 "$FNAME"
+ elif test "$mode" = 'uninstall'; then
+ echo "Removing $FNAME "
+ rm -f "$FNAME"
+ if test -f "$FNAME"; then
+ echo "Cannot remove $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ else
+ echo "Unknown mode, $mode. Script called as $0 "
+ exit 1
+ fi
+done
+
+if test "$mode" = 'install'; then
+ cat << EOF
+==============================================================================
+The SWAT msg files have been installed. You may uninstall the msg files using
+the command "make uninstallmsg" or "make uninstall" to uninstall binaries, man
+pages, msg files, and shell scripts.
+==============================================================================
+EOF
+else
+ cat << EOF
+=============================================================================
+The SWAT msg files have been removed. You may restore these files using the
+command "make installmsg" or "make install" to install binaries, man pages,
+modules, msg files, and shell scripts.
+======================================================================
+EOF
+fi
+
+exit 0
diff --git a/source3/script/installscripts.sh b/source3/script/installscripts.sh
new file mode 100755
index 0000000000..81608c3682
--- /dev/null
+++ b/source3/script/installscripts.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# this script courtesy of James_K._Foote.PARC@xerox.com
+# 5 July 96 Dan.Shearer@UniSA.Edu.Au Don't hardcode script names, get from Make
+
+INSTALLPERMS=$1
+BINDIR=`echo $2 | sed 's/\/\//\//g'`
+
+shift
+shift
+
+echo Installing scripts in $BINDIR
+
+for d in $BINDIR; do
+ if [ ! -d $d ]; then
+ mkdir $d
+ if [ ! -d $d ]; then
+ echo Failed to make directory $d
+ echo Have you run installbin first?
+ exit 1
+ fi
+ fi
+done
+
+for p in $*; do
+ p2=`basename $p`
+ echo Installing $BINDIR/$p2
+ if [ -f $BINDIR/$p2 ]; then
+ rm -f $BINDIR/$p2.old
+ mv $BINDIR/$p2 $BINDIR/$p2.old
+ fi
+ cp $p $BINDIR/
+ chmod $INSTALLPERMS $BINDIR/$p2
+ if [ ! -f $BINDIR/$p2 ]; then
+ echo Cannot copy $p2... does $USER have privileges?
+ fi
+done
+
+cat << EOF
+======================================================================
+The scripts have been installed. You may uninstall them using
+the command "make uninstallscripts" or "make install" to install binaries,
+man pages and shell scripts. You may recover the previous version (if any
+by "make revert".
+======================================================================
+EOF
+
+exit 0
diff --git a/source3/script/installswat.sh b/source3/script/installswat.sh
new file mode 100755
index 0000000000..40596f3bd8
--- /dev/null
+++ b/source3/script/installswat.sh
@@ -0,0 +1,296 @@
+#!/bin/sh
+#first version March 1998, Andrew Tridgell
+
+DESTDIR=$1
+SWATDIR=`echo $2 | sed 's/\/\//\//g'`
+SRCDIR=$3/
+BOOKDIR="$DESTDIR/$SWATDIR/using_samba"
+
+case $0 in
+ *uninstall*)
+ echo "Removing SWAT from $DESTDIR/$SWATDIR "
+ echo "Removing the Samba Web Administration Tool "
+ printf "%s" "Removed "
+ mode='uninstall'
+ ;;
+ *)
+ echo "Installing SWAT in $DESTDIR/$SWATDIR "
+ echo "Installing the Samba Web Administration Tool "
+ printf "%s" "Installing "
+ mode='install'
+ ;;
+esac
+
+LANGS=". `cd $SRCDIR../swat/; /bin/echo lang/??`"
+echo "langs are `cd $SRCDIR../swat/lang/; /bin/echo ??` "
+
+if test "$mode" = 'install'; then
+ for ln in $LANGS; do
+ SWATLANGDIR="$DESTDIR/$SWATDIR/$ln"
+ for d in $SWATLANGDIR $SWATLANGDIR/help $SWATLANGDIR/images \
+ $SWATLANGDIR/include $SWATLANGDIR/js; do
+ if [ ! -d $d ]; then
+ mkdir -p $d
+ if [ ! -d $d ]; then
+ echo "Failed to make directory $d, does $USER have privileges? "
+ exit 1
+ fi
+ fi
+ done
+ done
+fi
+
+for ln in $LANGS; do
+
+ # images
+ for f in $SRCDIR../swat/$ln/images/*.gif; do
+ if [ ! -f $f ] ; then
+ continue
+ fi
+ FNAME="$DESTDIR/$SWATDIR/$ln/images/`basename $f`"
+ echo $FNAME
+ if test "$mode" = 'install'; then
+ cp "$f" "$FNAME"
+ if test ! -f "$FNAME"; then
+ echo "Cannot install $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ chmod 0644 "$FNAME"
+ elif test "$mode" = 'uninstall'; then
+ rm -f "$FNAME"
+ if test -f "$FNAME"; then
+ echo "Cannot remove $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ else
+ echo "Unknown mode, $mode. Script called as $0 "
+ exit 1
+ fi
+ done
+
+ # html help
+ for f in $SRCDIR../swat/$ln/help/*.html; do
+ if [ ! -f $f ] ; then
+ continue
+ fi
+ FNAME="$DESTDIR/$SWATDIR/$ln/help/`basename $f`"
+ echo $FNAME
+ if test "$mode" = 'install'; then
+ if [ "x$BOOKDIR" = "x" ]; then
+ cat $f | sed 's/@BOOKDIR@.*$//' > $FNAME.tmp
+ else
+ cat $f | sed 's/@BOOKDIR@//' > $FNAME.tmp
+ fi
+ if test ! -f "$FNAME.tmp"; then
+ echo "Cannot install $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ f=$FNAME.tmp
+ cp "$f" "$FNAME"
+ rm -f "$f"
+ if test ! -f "$FNAME"; then
+ echo "Cannot install $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ chmod 0644 "$FNAME"
+ elif test "$mode" = 'uninstall'; then
+ rm -f "$FNAME"
+ if test -f "$FNAME"; then
+ echo "Cannot remove $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ fi
+ done
+
+ # "server-side" includes
+ for f in $SRCDIR../swat/$ln/include/*; do
+ if [ ! -f $f ] ; then
+ continue
+ fi
+ FNAME="$DESTDIR/$SWATDIR/$ln/include/`basename $f`"
+ echo $FNAME
+ if test "$mode" = 'install'; then
+ cp "$f" "$FNAME"
+ if test ! -f "$FNAME"; then
+ echo "Cannot install $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ chmod 0644 $FNAME
+ elif test "$mode" = 'uninstall'; then
+ rm -f "$FNAME"
+ if test -f "$FNAME"; then
+ echo "Cannot remove $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ fi
+ done
+
+done
+
+# Install/ remove html documentation (if html documentation tree is here)
+
+if [ -d $SRCDIR../docs/htmldocs/ ]; then
+
+ for dir in htmldocs/manpages htmldocs/Samba3-ByExample htmldocs/Samba3-Developers-Guide htmldocs/Samba3-HOWTO
+ do
+
+ if [ ! -d $SRCDIR../docs/$dir ]; then
+ continue
+ fi
+
+ INSTALLDIR="$DESTDIR/$SWATDIR/help/`echo $dir | sed 's/htmldocs\///g'`"
+ if test ! -d "$INSTALLDIR" -a "$mode" = 'install'; then
+ mkdir "$INSTALLDIR"
+ if test ! -d "$INSTALLDIR"; then
+ echo "Failed to make directory $INSTALLDIR, does $USER have privileges? "
+ exit 1
+ fi
+ fi
+
+ for f in $SRCDIR../docs/$dir/*.html; do
+ FNAME=$INSTALLDIR/`basename $f`
+ echo $FNAME
+ if test "$mode" = 'install'; then
+ cp "$f" "$FNAME"
+ if test ! -f "$FNAME"; then
+ echo "Cannot install $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ chmod 0644 $FNAME
+ elif test "$mode" = 'uninstall'; then
+ rm -f "$FNAME"
+ if test -f "$FNAME"; then
+ echo "Cannot remove $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ fi
+ done
+
+ if test -d "$SRCDIR../docs/$dir/images/"; then
+ if test ! -d "$INSTALLDIR/images/" -a "$mode" = 'install'; then
+ mkdir "$INSTALLDIR/images"
+ if test ! -d "$INSTALLDIR/images/"; then
+ echo "Failed to make directory $INSTALLDIR/images, does $USER have privileges? "
+ exit 1
+ fi
+ fi
+ for f in $SRCDIR../docs/$dir/images/*.png; do
+ FNAME=$INSTALLDIR/images/`basename $f`
+ echo $FNAME
+ if test "$mode" = 'install'; then
+ cp "$f" "$FNAME"
+ if test ! -f "$FNAME"; then
+ echo "Cannot install $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ chmod 0644 $FNAME
+ elif test "$mode" = 'uninstall'; then
+ rm -f "$FNAME"
+ if test -f "$FNAME"; then
+ echo "Cannot remove $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ fi
+ done
+ fi
+ done
+fi
+
+# Install/ remove Using Samba book (but only if it is there)
+
+if [ "x$BOOKDIR" != "x" -a -f $SRCDIR../docs/htmldocs/using_samba/toc.html ]; then
+
+ # Create directories
+
+ for d in $BOOKDIR $BOOKDIR/figs ; do
+ if test ! -d "$d" -a "$mode" = 'install'; then
+ mkdir $d
+ if test ! -d "$d"; then
+ echo "Failed to make directory $d, does $USER have privileges? "
+ exit 1
+ fi
+ fi
+ done
+
+ # HTML files
+
+ for f in $SRCDIR../docs/htmldocs/using_samba/*.html; do
+ FNAME=$BOOKDIR/`basename $f`
+ echo $FNAME
+ if test "$mode" = 'install'; then
+ cp "$f" "$FNAME"
+ if test ! -f "$FNAME"; then
+ echo "Cannot install $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ chmod 0644 $FNAME
+ elif test "$mode" = 'uninstall'; then
+ rm -f "$FNAME"
+ if test -f "$FNAME"; then
+ echo "Cannot remove $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ fi
+ done
+
+ for f in $SRCDIR../docs/htmldocs/using_samba/*.gif; do
+ FNAME=$BOOKDIR/`basename $f`
+ echo $FNAME
+ if test "$mode" = 'install'; then
+ cp "$f" "$FNAME"
+ if test ! -f "$FNAME"; then
+ echo "Cannot install $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ chmod 0644 $FNAME
+ elif test "$mode" = 'uninstall'; then
+ rm -f "$FNAME"
+ if test -f "$FNAME"; then
+ echo "Cannot remove $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ fi
+ done
+
+ # Figures
+
+ for f in $SRCDIR../docs/htmldocs/using_samba/figs/*.gif; do
+ FNAME=$BOOKDIR/figs/`basename $f`
+ echo $FNAME
+ if test "$mode" = 'install'; then
+ cp "$f" "$FNAME"
+ if test ! -f "$FNAME"; then
+ echo "Cannot install $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ chmod 0644 $FNAME
+ elif test "$mode" = 'uninstall'; then
+ rm -f "$FNAME"
+ if test -f "$FNAME"; then
+ echo "Cannot remove $FNAME. Does $USER have privileges? "
+ exit 1
+ fi
+ fi
+ done
+
+fi
+
+if test "$mode" = 'install'; then
+ cat << EOF
+======================================================================
+The SWAT files have been installed. Remember to read the documentation
+for information on enabling and using SWAT
+======================================================================
+EOF
+else
+ cat << EOF
+======================================================================
+The SWAT files have been removed. You may restore these files using
+the command "make installswat" or "make install" to install binaries,
+man pages, modules, SWAT, and shell scripts.
+======================================================================
+EOF
+fi
+
+exit 0
+
diff --git a/source3/script/linkmodules.sh b/source3/script/linkmodules.sh
new file mode 100755
index 0000000000..16a04cc064
--- /dev/null
+++ b/source3/script/linkmodules.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+cd "$1"
+test -f "$2" || exit 0
+
+for I in $3 $4 $5 $6 $7 $8
+do
+ echo "Linking $I to $2"
+ ln -s $2 $I
+done
+
+exit 0
diff --git a/source3/script/makeunicodecasemap.awk b/source3/script/makeunicodecasemap.awk
new file mode 100644
index 0000000000..8424b6c672
--- /dev/null
+++ b/source3/script/makeunicodecasemap.awk
@@ -0,0 +1,59 @@
+function reset_vals() {
+ upperstr = "";
+ lowerstr = "";
+ flagstr = "0";
+}
+
+function print_val() {
+ upperstr = $13;
+ lowerstr = $14;
+ if ( upperstr == "" )
+ upperstr = strval;
+ if ( lowerstr == "" )
+ lowerstr = strval;
+
+ if ( $3 == "Lu" )
+ flagstr = sprintf("%s|%s", flagstr, "UNI_UPPER");
+ if ( $3 == "Ll" )
+ flagstr = sprintf("%s|%s", flagstr, "UNI_LOWER");
+ if ( val >= 48 && val <= 57)
+ flagstr = sprintf("%s|%s", flagstr, "UNI_DIGIT");
+ if ((val >= 48 && val <= 57) || (val >= 65 && val <= 70) || (val >=97 && val <= 102))
+ flagstr = sprintf("%s|%s", flagstr, "UNI_XDIGIT");
+ if ( val == 32 || (val >=9 && val <= 13))
+ flagstr = sprintf("%s|%s", flagstr, "UNI_SPACE");
+ if( index(flagstr, "0|") == 1)
+ flagstr = substr(flagstr, 3, length(flagstr) - 2);
+ printf("{ 0x%s, 0x%s, %s }, \t\t\t/* %s %s */\n", lowerstr, upperstr, flagstr, strval, $2);
+ val++;
+ strval=sprintf("%04X", val);
+ reset_vals();
+}
+
+BEGIN {
+ val=0
+ FS=";"
+ strval=sprintf("%04X", val);
+ reset_vals();
+}
+
+{
+ if ( $1 == strval ) {
+ print_val();
+ } else {
+ while ( $1 != strval) {
+ printf("{ 0x%04X, 0x%04X, 0 }, \t\t\t/* %s NOMAP */\n", val, val, strval);
+ val++;
+ strval=sprintf("%04X", val);
+ }
+ print_val();
+ }
+}
+
+END {
+ while ( val < 65536 ) {
+ printf("{ 0x%04X, 0x%04X, 0 }, \t\t\t/* %s NOMAP */\n", val, val, strval);
+ val++;
+ strval=sprintf("%04X", val);
+ }
+}
diff --git a/source3/script/mkbuildoptions.awk b/source3/script/mkbuildoptions.awk
new file mode 100644
index 0000000000..02562cf7b2
--- /dev/null
+++ b/source3/script/mkbuildoptions.awk
@@ -0,0 +1,270 @@
+BEGIN {
+ print "/* ";
+ print " Unix SMB/CIFS implementation.";
+ print " Build Options for Samba Suite";
+ print " Copyright (C) Vance Lankhaar <vlankhaar@linux.ca> 2003";
+ print " Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001";
+ print " ";
+ print " This program is free software; you can redistribute it and/or modify";
+ print " it under the terms of the GNU General Public License as published by";
+ print " the Free Software Foundation; either version 3 of the License, or";
+ print " (at your option) any later version.";
+ print " ";
+ print " This program is distributed in the hope that it will be useful,";
+ print " but WITHOUT ANY WARRANTY; without even the implied warranty of";
+ print " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the";
+ print " GNU General Public License for more details.";
+ print " ";
+ print " You should have received a copy of the GNU General Public License";
+ print " along with this program; if not, see <http://www.gnu.org/licenses/>."
+ print "*/";
+ print "";
+ print "#include \"includes.h\"";
+ print "#include \"build_env.h\"";
+ print "#include \"dynconfig.h\"";
+ print "";
+ print "static void output(bool screen, const char *format, ...) PRINTF_ATTRIBUTE(2,3);";
+ print "void build_options(bool screen);";
+ print "";
+ print "";
+ print "/****************************************************************************";
+ print "helper function for build_options";
+ print "****************************************************************************/";
+ print "static void output(bool screen, const char *format, ...)";
+ print "{";
+ print " char *ptr;";
+ print " va_list ap;";
+ print " ";
+ print " va_start(ap, format);";
+ print " vasprintf(&ptr,format,ap);";
+ print " va_end(ap);";
+ print "";
+ print " if (screen) {";
+ print " d_printf(\"%s\", ptr);";
+ print " } else {";
+ print " DEBUG(4,(\"%s\", ptr));";
+ print " }";
+ print " ";
+ print " SAFE_FREE(ptr);";
+ print "}";
+ print "";
+ print "/****************************************************************************";
+ print "options set at build time for the samba suite";
+ print "****************************************************************************/";
+ print "void build_options(bool screen)";
+ print "{";
+ print " if ((DEBUGLEVEL < 4) && (!screen)) {";
+ print " return;";
+ print " }";
+ print "";
+ print "#ifdef _BUILD_ENV_H";
+ print " /* Output information about the build environment */";
+ print " output(screen,\"Build environment:\\n\");";
+ print " output(screen,\" Built by: %s@%s\\n\",BUILD_ENV_USER,BUILD_ENV_HOST);";
+ print " output(screen,\" Built on: %s\\n\",BUILD_ENV_DATE);";
+ print "";
+ print " output(screen,\" Built using: %s\\n\",BUILD_ENV_COMPILER);";
+ print " output(screen,\" Build host: %s\\n\",BUILD_ENV_UNAME);";
+ print " output(screen,\" SRCDIR: %s\\n\",BUILD_ENV_SRCDIR);";
+ print " output(screen,\" BUILDDIR: %s\\n\",BUILD_ENV_BUILDDIR);";
+ print "";
+ print " ";
+ print "#endif";
+ print "";
+
+ print " /* Output various paths to files and directories */";
+ print " output(screen,\"\\nPaths:\\n\");";
+
+ print " output(screen,\" SBINDIR: %s\\n\", get_dyn_SBINDIR());";
+ print " output(screen,\" BINDIR: %s\\n\", get_dyn_BINDIR());";
+ print " output(screen,\" SWATDIR: %s\\n\", get_dyn_SWATDIR());";
+
+ print " output(screen,\" CONFIGFILE: %s\\n\", get_dyn_CONFIGFILE());";
+ print " output(screen,\" LOGFILEBASE: %s\\n\", get_dyn_LOGFILEBASE());";
+ print " output(screen,\" LMHOSTSFILE: %s\\n\",get_dyn_LMHOSTSFILE());";
+
+ print " output(screen,\" LIBDIR: %s\\n\",get_dyn_LIBDIR());";
+ print " output(screen,\" MODULESDIR: %s\\n\",get_dyn_MODULESDIR());";
+ print " output(screen,\" SHLIBEXT: %s\\n\",get_dyn_SHLIBEXT());";
+
+ print " output(screen,\" LOCKDIR: %s\\n\",get_dyn_LOCKDIR());";
+ print " output(screen,\" PIDDIR: %s\\n\", get_dyn_PIDDIR());";
+
+ print " output(screen,\" SMB_PASSWD_FILE: %s\\n\",get_dyn_SMB_PASSWD_FILE());";
+ print " output(screen,\" PRIVATE_DIR: %s\\n\",get_dyn_PRIVATE_DIR());";
+ print "";
+
+
+##################################################
+# predefine first element of *_ary
+# predefine *_i (num of elements in *_ary)
+ with_ary[0]="";
+ with_i=0;
+ have_ary[0]="";
+ have_i=0;
+ utmp_ary[0]="";
+ utmp_i=0;
+ misc_ary[0]="";
+ misc_i=0;
+ sys_ary[0]="";
+ sys_i=0;
+ headers_ary[0]="";
+ headers_i=0;
+ in_comment = 0;
+}
+
+# capture single line comments
+/^\/\* (.*?)\*\// {
+ last_comment = $0;
+ next;
+}
+
+# end capture multi-line comments
+/(.*?)\*\// {
+ last_comment = last_comment $0;
+ in_comment = 0;
+ next;
+}
+
+# capture middle lines of multi-line comments
+in_comment {
+ last_comment = last_comment $0;
+ next;
+}
+
+# begin capture multi-line comments
+/^\/\* (.*?)/ {
+ last_comment = $0;
+ in_comment = 1;
+ next
+}
+
+##################################################
+# if we have an #undef and a last_comment, store it
+/^\#undef/ {
+ split($0,a);
+ comments_ary[a[2]] = last_comment;
+ last_comment = "";
+}
+
+##################################################
+# for each line, sort into appropriate section
+# then move on
+
+/^\#undef WITH/ {
+ with_ary[with_i++] = a[2];
+ # we want (I think) to allow --with to show up in more than one place, so no next
+}
+
+
+/^\#undef HAVE_UT_UT_/ || /^\#undef .*UTMP/ {
+ utmp_ary[utmp_i++] = a[2];
+ next;
+}
+
+/^\#undef HAVE_SYS_.*?_H$/ {
+ sys_ary[sys_i++] = a[2];
+ next;
+}
+
+/^\#undef HAVE_.*?_H$/ {
+ headers_ary[headers_i++] = a[2];
+ next;
+}
+
+/^\#undef HAVE_/ {
+ have_ary[have_i++] = a[2];
+ next;
+}
+
+/^\#undef/ {
+ misc_ary[misc_i++] = a[2];
+ next;
+}
+
+
+##################################################
+# simple sort function
+function sort(ARRAY, ELEMENTS) {
+ for (i = 1; i <= ELEMENTS; ++i) {
+ for (j = i; (j-1) in ARRAY && (j) in ARRAY && ARRAY[j-1] > ARRAY[j]; --j) {
+ temp = ARRAY[j];
+ ARRAY[j] = ARRAY[j-1];
+ ARRAY[j-1] = temp;
+ }
+ }
+ return;
+}
+
+
+##################################################
+# output code from list of defined
+# expects: ARRAY an array of things defined
+# ELEMENTS number of elements in ARRAY
+# TITLE title for section
+# returns: nothing
+function output(ARRAY, ELEMENTS, TITLE) {
+
+ # add section header
+ print "\n\t/* Show " TITLE " */";
+ print "\toutput(screen, \"\\n " TITLE ":\\n\");\n";
+
+
+ # sort element using bubble sort (slow, but easy)
+ sort(ARRAY, ELEMENTS);
+
+ # loop through array of defines, outputting code
+ for (i = 0; i < ELEMENTS; i++) {
+ print "#ifdef " ARRAY[i];
+
+ # I don't know which one to use....
+
+ print "\toutput(screen, \" " ARRAY[i] "\\n\");";
+ #printf "\toutput(screen, \" %s\\n %s\\n\\n\");\n", comments_ary[ARRAY[i]], ARRAY[i];
+ #printf "\toutput(screen, \" %-35s %s\\n\");\n", ARRAY[i], comments_ary[ARRAY[i]];
+
+ print "#endif";
+ }
+ return;
+}
+
+END {
+ ##################################################
+ # add code to show various options
+ print "/* Output various other options (as gleaned from include/config.h.in) */";
+ output(sys_ary, sys_i, "System Headers");
+ output(headers_ary, headers_i, "Headers");
+ output(utmp_ary, utmp_i, "UTMP Options");
+ output(have_ary, have_i, "HAVE_* Defines");
+ output(with_ary, with_i, "--with Options");
+ output(misc_ary, misc_i, "Build Options");
+
+ ##################################################
+ # add code to display the various type sizes
+ print " /* Output the sizes of the various types */";
+ print " output(screen, \"\\nType sizes:\\n\");";
+ print " output(screen, \" sizeof(char): %lu\\n\",(unsigned long)sizeof(char));";
+ print " output(screen, \" sizeof(int): %lu\\n\",(unsigned long)sizeof(int));";
+ print " output(screen, \" sizeof(long): %lu\\n\",(unsigned long)sizeof(long));";
+ print "#if HAVE_LONGLONG"
+ print " output(screen, \" sizeof(long long): %lu\\n\",(unsigned long)sizeof(long long));";
+ print "#endif"
+ print " output(screen, \" sizeof(uint8): %lu\\n\",(unsigned long)sizeof(uint8));";
+ print " output(screen, \" sizeof(uint16): %lu\\n\",(unsigned long)sizeof(uint16));";
+ print " output(screen, \" sizeof(uint32): %lu\\n\",(unsigned long)sizeof(uint32));";
+ print " output(screen, \" sizeof(short): %lu\\n\",(unsigned long)sizeof(short));";
+ print " output(screen, \" sizeof(void*): %lu\\n\",(unsigned long)sizeof(void*));";
+ print " output(screen, \" sizeof(size_t): %lu\\n\",(unsigned long)sizeof(size_t));";
+ print " output(screen, \" sizeof(off_t): %lu\\n\",(unsigned long)sizeof(off_t));";
+ print " output(screen, \" sizeof(ino_t): %lu\\n\",(unsigned long)sizeof(ino_t));";
+ print " output(screen, \" sizeof(dev_t): %lu\\n\",(unsigned long)sizeof(dev_t));";
+
+ ##################################################
+ # add code to give information about modules
+ print " output(screen, \"\\nBuiltin modules:\\n\");";
+ print " output(screen, \" %s\\n\", STRING_STATIC_MODULES);";
+
+ print "}";
+
+}
+
diff --git a/source3/script/mkinstalldirs b/source3/script/mkinstalldirs
new file mode 100755
index 0000000000..f945dbf2bc
--- /dev/null
+++ b/source3/script/mkinstalldirs
@@ -0,0 +1,38 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+errstatus=0
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp" 1>&2
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/source3/script/mknissmbpasswd.sh b/source3/script/mknissmbpasswd.sh
new file mode 100755
index 0000000000..a94c963bdc
--- /dev/null
+++ b/source3/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/source3/script/mknissmbpwdtbl.sh b/source3/script/mknissmbpwdtbl.sh
new file mode 100755
index 0000000000..a9b34ff9a7
--- /dev/null
+++ b/source3/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/source3/script/mksmbpasswd.sh b/source3/script/mksmbpasswd.sh
new file mode 100755
index 0000000000..119a55611e
--- /dev/null
+++ b/source3/script/mksmbpasswd.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+awk 'BEGIN {FS=":"
+ printf("#\n# SMB password file.\n#\n")
+ }
+{ printf( "%s:%s:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:[UD ]:LCT-00000000:%s\n", $1, $3, $5) }
+'
diff --git a/source3/script/mksyms.awk b/source3/script/mksyms.awk
new file mode 100644
index 0000000000..a30bea4d34
--- /dev/null
+++ b/source3/script/mksyms.awk
@@ -0,0 +1,76 @@
+#
+# mksyms.awk
+#
+# Extract symbols to export from C-header files.
+# output in version-script format for linking shared libraries.
+#
+# Copyright (C) 2008 Micheal Adam <obnox@samba.org>
+#
+BEGIN {
+ inheader=0;
+ current_file="";
+ print "#"
+ print "# This file is automatically generated with \"make symbols\". DO NOT EDIT "
+ print "#"
+ print "{"
+ print "\tglobal:"
+}
+
+END {
+ print""
+ print "\tlocal: *;"
+ print "};"
+}
+
+{
+ if (FILENAME!=current_file) {
+ print "\t\t# The following definitions come from",FILENAME
+ current_file=FILENAME
+ }
+ if (inheader) {
+ if (match($0,"[)][ \t]*[;][ \t]*$")) {
+ inheader = 0;
+ }
+ next;
+ }
+}
+
+/^static/ || /^[ \t]*typedef/ || !/^[a-zA-Z\_]/ {
+ next;
+}
+
+/^extern[ \t]+[^()]+[;][ \t]*$/ {
+ gsub(/[^ \t]+[ \t]+/, "");
+ sub(/[;][ \t]*$/, "");
+ printf "\t\t%s;\n", $0;
+ next;
+}
+
+# look for function headers:
+{
+ gotstart = 0;
+ if ($0 ~ /^[A-Za-z_][A-Za-z0-9_]+/) {
+ gotstart = 1;
+ }
+ if(!gotstart) {
+ next;
+ }
+}
+
+/[_A-Za-z0-9]+[ \t]*[(].*[)][ \t]*;[ \t]*$/ {
+ sub(/[(].*$/, "");
+ gsub(/[^ \t]+[ \t]+/, "");
+ gsub(/^[*]/, "");
+ printf "\t\t%s;\n",$0;
+ next;
+}
+
+/[_A-Za-z0-9]+[ \t]*[(]/ {
+ inheader=1;
+ sub(/[(].*$/, "");
+ gsub(/[^ \t]+[ \t]+/, "");
+ gsub(/^[*]/, "");
+ printf "\t\t%s;\n",$0;
+ next;
+}
+
diff --git a/source3/script/mksyms.sh b/source3/script/mksyms.sh
new file mode 100755
index 0000000000..51d3fbd999
--- /dev/null
+++ b/source3/script/mksyms.sh
@@ -0,0 +1,45 @@
+#! /bin/sh
+
+#
+# mksyms.sh
+#
+# Extract symbols to export from C-header files.
+# output in version-script format for linking shared libraries.
+#
+# This is the shell warpper for the mksyms.awk core script.
+#
+# Copyright (C) 2008 Micheal Adam <obnox@samba.org>
+#
+
+LANG=C; export LANG
+LC_ALL=C; export LC_ALL
+LC_COLLATE=C; export LC_COLLATE
+
+if [ $# -lt 2 ]
+then
+ echo "Usage: $0 awk output_file header_files"
+ exit 1
+fi
+
+awk="$1"
+shift
+
+symsfile="$1"
+shift
+symsfile_tmp="$symsfile.$$.tmp~"
+
+proto_src="`echo $@ | tr ' ' '\n' | sort | uniq `"
+
+echo creating $symsfile
+
+mkdir -p `dirname $symsfile`
+
+${awk} -f `dirname $0`/mksyms.awk $proto_src > $symsfile_tmp
+
+if cmp -s $symsfile $symsfile_tmp 2>/dev/null
+then
+ echo "$symsfile unchanged"
+ rm $symsfile_tmp
+else
+ mv $symsfile_tmp $symsfile
+fi
diff --git a/source3/script/mkversion.sh b/source3/script/mkversion.sh
new file mode 100755
index 0000000000..a55aafcd0c
--- /dev/null
+++ b/source3/script/mkversion.sh
@@ -0,0 +1,145 @@
+#!/bin/sh
+
+VERSION_FILE=$1
+OUTPUT_FILE=$2
+
+if test -z "$VERSION_FILE";then
+ VERSION_FILE="VERSION"
+fi
+
+if test -z "$OUTPUT_FILE";then
+ OUTPUT_FILE="include/version.h"
+fi
+
+SOURCE_DIR=$3
+
+SAMBA_VERSION_MAJOR=`sed -n 's/^SAMBA_VERSION_MAJOR=//p' $SOURCE_DIR$VERSION_FILE`
+SAMBA_VERSION_MINOR=`sed -n 's/^SAMBA_VERSION_MINOR=//p' $SOURCE_DIR$VERSION_FILE`
+SAMBA_VERSION_RELEASE=`sed -n 's/^SAMBA_VERSION_RELEASE=//p' $SOURCE_DIR$VERSION_FILE`
+
+SAMBA_VERSION_REVISION=`sed -n 's/^SAMBA_VERSION_REVISION=//p' $SOURCE_DIR$VERSION_FILE`
+
+SAMBA_VERSION_TP_RELEASE=`sed -n 's/^SAMBA_VERSION_TP_RELEASE=//p' $SOURCE_DIR$VERSION_FILE`
+SAMBA_VERSION_PRE_RELEASE=`sed -n 's/^SAMBA_VERSION_PRE_RELEASE=//p' $SOURCE_DIR$VERSION_FILE`
+SAMBA_VERSION_RC_RELEASE=`sed -n 's/^SAMBA_VERSION_RC_RELEASE=//p' $SOURCE_DIR$VERSION_FILE`
+
+SAMBA_VERSION_IS_GIT_SNAPSHOT=`sed -n 's/^SAMBA_VERSION_IS_GIT_SNAPSHOT=//p' $SOURCE_DIR$VERSION_FILE`
+
+SAMBA_VERSION_RELEASE_NICKNAME=`sed -n 's/^SAMBA_VERSION_RELEASE_NICKNAME=//p' $SOURCE_DIR$VERSION_FILE`
+
+SAMBA_VERSION_VENDOR_SUFFIX=`sed -n 's/^SAMBA_VERSION_VENDOR_SUFFIX=//p' $SOURCE_DIR$VERSION_FILE`
+SAMBA_VERSION_VENDOR_PATCH=`sed -n 's/^SAMBA_VERSION_VENDOR_PATCH=//p' $SOURCE_DIR$VERSION_FILE`
+
+SAMBA_VERSION_VENDOR_FUNCTION=`sed -n 's/^SAMBA_VERSION_VENDOR_FUNCTION=//p' $SOURCE_DIR$VERSION_FILE`
+
+echo "/* Autogenerated by script/mkversion.sh */" > $OUTPUT_FILE
+
+echo "#define SAMBA_VERSION_MAJOR ${SAMBA_VERSION_MAJOR}" >> $OUTPUT_FILE
+echo "#define SAMBA_VERSION_MINOR ${SAMBA_VERSION_MINOR}" >> $OUTPUT_FILE
+echo "#define SAMBA_VERSION_RELEASE ${SAMBA_VERSION_RELEASE}" >> $OUTPUT_FILE
+
+
+##
+## start with "3.0.22"
+##
+SAMBA_VERSION_STRING="${SAMBA_VERSION_MAJOR}.${SAMBA_VERSION_MINOR}.${SAMBA_VERSION_RELEASE}"
+
+
+##
+## maybe add "3.0.22a" or "4.0.0tp11" or "3.0.22pre1" or "3.0.22rc1"
+## We do not do pre or rc version on patch/letter releases
+##
+if test -n "${SAMBA_VERSION_REVISION}";then
+ SAMBA_VERSION_STRING="${SAMBA_VERSION_STRING}${SAMBA_VERSION_REVISION}"
+ echo "#define SAMBA_VERSION_REVISION \"${SAMBA_VERSION_REVISION}\"" >> $OUTPUT_FILE
+elif test -n "${SAMBA_VERSION_TP_RELEASE}";then
+ SAMBA_VERSION_STRING="${SAMBA_VERSION_STRING}tp${SAMBA_VERSION_TP_RELEASE}"
+ echo "#define SAMBA_VERSION_TP_RELEASE ${SAMBA_VERSION_TP_RELEASE}" >> $OUTPUT_FILE
+elif test -n "${SAMBA_VERSION_PRE_RELEASE}";then
+ ## maybe add "3.0.22pre2"
+ SAMBA_VERSION_STRING="${SAMBA_VERSION_STRING}pre${SAMBA_VERSION_PRE_RELEASE}"
+ echo "#define SAMBA_VERSION_PRE_RELEASE ${SAMBA_VERSION_PRE_RELEASE}" >> $OUTPUT_FILE
+elif test -n "${SAMBA_VERSION_RC_RELEASE}";then
+ SAMBA_VERSION_STRING="${SAMBA_VERSION_STRING}rc${SAMBA_VERSION_RC_RELEASE}"
+ echo "#define SAMBA_VERSION_RC_RELEASE ${SAMBA_VERSION_RC_RELEASE}" >> $OUTPUT_FILE
+fi
+
+##
+## GIT commit details
+##
+if test x"${SAMBA_VERSION_IS_GIT_SNAPSHOT}" = x"yes";then
+ _SAVE_LANG=${LANG}
+ LANG="C"
+ HAVEVER="no"
+
+ if test x"${HAVEVER}" != x"yes" -a -d "${SOURCE_DIR}../.git";then
+ HAVEGIT=no
+ GIT_INFO=`git show --pretty=format:"%h%n%ct%n%H%n%cd" --stat HEAD 2>/dev/null`
+ GIT_COMMIT_ABBREV=`printf "%s" "${GIT_INFO}" | sed -n 1p`
+ GIT_COMMIT_TIME=`printf "%s" "${GIT_INFO}" | sed -n 2p`
+ GIT_COMMIT_FULLREV=`printf "%s" "${GIT_INFO}" | sed -n 3p`
+ GIT_COMMIT_DATE=`printf "%s" "${GIT_INFO}" | sed -n 4p`
+ if test -n "${GIT_COMMIT_ABBREV}";then
+ HAVEGIT=yes
+ HAVEVER=yes
+ fi
+ fi
+
+ if test x"${HAVEGIT}" = x"yes";then
+ SAMBA_VERSION_STRING="${SAMBA_VERSION_STRING}-GIT-${GIT_COMMIT_ABBREV}"
+
+ echo "#define SAMBA_VERSION_GIT_COMMIT_ABBREV \"${GIT_COMMIT_ABBREV}\"" >> $OUTPUT_FILE
+ echo "#define SAMBA_VERSION_GIT_COMMIT_TIME ${GIT_COMMIT_TIME}" >> $OUTPUT_FILE
+ echo "#define SAMBA_VERSION_GIT_COMMIT_FULLREV \"${GIT_COMMIT_FULLREV}\"" >> $OUTPUT_FILE
+ echo "#define SAMBA_VERSION_GIT_COMMIT_DATE \"${GIT_COMMIT_DATE}\"" >> $OUTPUT_FILE
+ else
+ SAMBA_VERSION_STRING="${SAMBA_VERSION_STRING}-GIT-UNKNOWN"
+ fi
+ LANG=${_SAVE_LANG}
+fi
+
+echo "#define SAMBA_VERSION_OFFICIAL_STRING \"${SAMBA_VERSION_STRING}\"" >> $OUTPUT_FILE
+
+##
+## Add the vendor string if present
+##
+if test -n "${SAMBA_VERSION_VENDOR_FUNCTION}"; then
+ echo "#define SAMBA_VERSION_VENDOR_FUNCTION ${SAMBA_VERSION_VENDOR_FUNCTION}" >> $OUTPUT_FILE
+fi
+
+if test -n "${SAMBA_VERSION_VENDOR_SUFFIX}";then
+ echo "#define SAMBA_VERSION_VENDOR_SUFFIX ${SAMBA_VERSION_VENDOR_SUFFIX}" >> $OUTPUT_FILE
+ SAMBA_VERSION_STRING="${SAMBA_VERSION_STRING}-${SAMBA_VERSION_VENDOR_SUFFIX}"
+ if test -n "${SAMBA_VERSION_VENDOR_PATCH}";then
+ echo "#define SAMBA_VERSION_VENDOR_PATCH ${SAMBA_VERSION_VENDOR_PATCH}" >> $OUTPUT_FILE
+ SAMBA_VERSION_STRING="${SAMBA_VERSION_STRING}-${SAMBA_VERSION_VENDOR_PATCH}"
+ fi
+fi
+
+##
+## Add a release nickname
+##
+if test -n "${SAMBA_VERSION_RELEASE_NICKNAME}";then
+ echo "#define SAMBA_VERSION_RELEASE_NICKNAME ${SAMBA_VERSION_RELEASE_NICKNAME}" >> $OUTPUT_FILE
+ SAMBA_VERSION_STRING="${SAMBA_VERSION_STRING} (${SAMBA_VERSION_RELEASE_NICKNAME})"
+fi
+
+cat >>$OUTPUT_FILE<<CEOF
+#ifdef SAMBA_VERSION_VENDOR_FUNCTION
+# define SAMBA_VERSION_STRING SAMBA_VERSION_VENDOR_FUNCTION
+#else /* SAMBA_VERSION_VENDOR_FUNCTION */
+# ifdef SAMBA_VERSION_VENDOR_SUFFIX
+# ifdef SAMBA_VERSION_VENDOR_PATCH
+# define SAMBA_VERSION_STRING SAMBA_VERSION_OFFICIAL_STRING "-" SAMBA_VERSION_VENDOR_SUFFIX "-" SAMBA_VERSION_VENDOR_PATCH
+# else /* SAMBA_VERSION_VENDOR_PATCH */
+# define SAMBA_VERSION_STRING SAMBA_VERSION_OFFICIAL_STRING "-" SAMBA_VERSION_VENDOR_SUFFIX
+# endif /* SAMBA_VERSION_VENDOR_SUFFIX */
+# else /* SAMBA_VERSION_VENDOR_FUNCTION */
+# define SAMBA_VERSION_STRING SAMBA_VERSION_OFFICIAL_STRING
+# endif
+#endif
+CEOF
+
+echo "$0: '$OUTPUT_FILE' created for Samba(\"${SAMBA_VERSION_STRING}\")"
+
+exit 0
diff --git a/source3/script/revert.sh b/source3/script/revert.sh
new file mode 100755
index 0000000000..8df5fd2fbd
--- /dev/null
+++ b/source3/script/revert.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+BINDIR=$1
+shift
+
+for p in $*; do
+ 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
+
+exit 0
+
diff --git a/source3/script/scancvslog.pl b/source3/script/scancvslog.pl
new file mode 100755
index 0000000000..c39f9111c1
--- /dev/null
+++ b/source3/script/scancvslog.pl
@@ -0,0 +1,112 @@
+#!/usr/bin/perl
+require"timelocal.pl";
+
+#
+# usage scancvslog.pl logfile starttime tag
+#
+# this will extract all entries from the specified cvs log file
+# that have a date later than or equal to starttime and a tag
+# value of tag. If starttime is not specified, all entries are
+# extracted. If tag is not specified then entries for all
+# branches are extracted. starttime must be specified as
+# "monthname day, year"
+#
+# Example to extract all entries for SAMBA_2_2 branch from the
+# log file named cvs.log
+#
+# scancvslog.pl cvs.log "" SAMBA_2_2
+#
+#
+# To extract all log entries after Jan 10, 1999 (Note month name
+# must be spelled out completely).
+#
+# scancvslog.pl cvs.log "January 10, 1999"
+#
+
+open(INFILE,@ARGV[0]) || die "Unable to open @ARGV[0]\n";
+
+%Monthnum = (
+ "January", 0,
+ "February", 1,
+ "March", 2,
+ "April", 3,
+ "May", 4,
+ "June", 5,
+ "July", 6,
+ "August", 7,
+ "September", 8,
+ "October", 9,
+ "November", 10,
+ "December", 11,
+ "Jan", 0,
+ "Feb", 1,
+ "Mar", 2,
+ "Apr", 3,
+ "May", 4,
+ "Jun", 5,
+ "Jul", 6,
+ "Aug", 7,
+ "Sep", 8,
+ "Oct", 9,
+ "Nov", 10,
+ "Dec", 11
+);
+
+$Starttime = (@ARGV[1]) ? &make_time(@ARGV[1]) : 0;
+$Tagvalue = @ARGV[2];
+
+while (&get_entry) {
+ $_=$Entry[0];
+# get rid of extra white space
+ s/\s+/ /g;
+# get rid of any time string in date
+ s/ \d\d:\d\d:\d\d/,/;
+ s/^Date:\s*\w*\s*(\w*)\s*(\w*),\s*(\w*).*/$1 $2 $3/;
+ $Testtime = &make_time($_);
+ $Testtag = &get_tag;
+ if (($Testtime >= $Starttime) && ($Tagvalue eq $Testtag)) {
+ print join("\n",@Entry),"\n";
+ }
+}
+close(INFILE);
+
+sub make_time {
+ $_ = @_[0];
+ s/,//;
+ ($month, $day, $year) = split(" ",$_);
+ if (($year < 1900)||($day < 1)||($day > 31)||not length($Monthnum{$month})) {
+ print "Bad date format @_[0]\n";
+ print "Date needs to be specified as \"Monthname day, year\"\n";
+ print "eg: \"January 10, 1999\"\n";
+ exit 1;
+ }
+ $year = ($year == 19100) ? 2000 : $year;
+ $month = $Monthnum{$month};
+ $Mytime=&timelocal((0,0,0,$day,$month,$year));
+}
+
+sub get_tag {
+ @Mytag = grep (/Tag:/,@Entry);
+ $_ = @Mytag[0];
+ s/^.*Tag:\s*(\w*).*/$1/;
+ return $_;
+}
+
+sub get_entry {
+ @Entry=();
+ if (not eof(INFILE)) {
+ while (not eof(INFILE)) {
+ $_ = <INFILE>;
+ chomp $_;
+ next if (not ($_));
+ if (/^\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/) {
+ next if ($#Entry == -1);
+ push(Entry,$_);
+ return @Entry;
+ } else {
+ push(Entry,$_);
+ }
+ }
+ }
+ return @Entry;
+}
diff --git a/source3/script/smbtar b/source3/script/smbtar
new file mode 100644
index 0000000000..67a794553c
--- /dev/null
+++ b/source3/script/smbtar
@@ -0,0 +1,165 @@
+#!/bin/sh
+#
+# smbtar script - front end to smbclient
+#
+# Authors: Martin.Kraemer <Martin.Kraemer@mch.sni.de>
+# and Ricky Poulten (ricky@logcam.co.uk)
+#
+# (May need to change shell to ksh for HPUX or OSF for better getopts)
+#
+# sandy nov 3 '98 added -a flag
+#
+# Richard Sharpe, added -c 'tarmode full' so that we back up all files to
+# fix a bug in clitar when a patch was added to stop system and hidden files
+# being backed up.
+
+case $0 in
+ # when called by absolute path, assume smbclient is in the same directory
+ /*)
+ SMBCLIENT="`dirname $0`/smbclient";;
+ *) # 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
+# you're doing, but beware: better not store a plain text password!
+server=""
+service="backup" # Default: a service called "backup"
+password=""
+username=$LOGNAME # Default: same user name as in *nix
+verbose="2>/dev/null" # Default: no echo to stdout
+log="-d 2"
+newer=""
+newerarg=""
+blocksize=""
+blocksizearg=""
+clientargs="-c 'tarmode full'"
+tarcmd="c"
+tarargs=""
+cdcmd="\\"
+tapefile=${TAPE-tar.out}
+
+Usage(){
+ ex=$1
+ shift
+echo >&2 "Usage: `basename $0` [<options>] [<include/exclude files>]
+Function: backup/restore a Windows PC directories to a local tape file
+Options: (Description) (Default)
+ -r Restore from tape file to PC Save from PC to tapefile
+ -i Incremental mode Full backup mode
+ -a Reset archive bit mode Don't reset archive bit
+ -v Verbose mode: echo command Don't echo anything
+ -s <server> Specify PC Server $server
+ -p <password> Specify PC Password $password
+ -x <share> Specify PC Share $service
+ -X Exclude mode Include
+ -N <newer> File for date comparison `set -- $newer; echo $2`
+ -b <blocksize> Specify tape's blocksize `set -- $blocksize; echo $2`
+ -d <dir> Specify a directory in share $cdcmd
+ -l <log> Specify a Samba Log Level `set -- $log; echo $2`
+ -u <user> Specify User Name $username
+ -t <tape> Specify Tape device $tapefile
+"
+ echo >&2 "$@"
+ 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 riavl:b:d:N:s:p:x:u:Xt: c; do
+ case $c in
+ r) # [r]estore to Windows (instead of the default "Save from Windows")
+ tarcmd="x"
+ ;;
+ i) # [i]ncremental
+ tarargs=${tarargs}ga
+ clientargs="-c 'tarmode inc'"
+ ;;
+ a) # [a]rchive
+ tarargs=${tarargs}a
+ ;;
+ l) # specify [l]og file
+ log="-d $OPTARG"
+ case "$OPTARG" in
+ [0-9]*) ;;
+ *) echo >&2 "$0: Error, log level not numeric: -l $OPTARG"
+ exit 1
+ esac
+ ;;
+ d) # specify [d]irectory to change to in server's share
+ cdcmd="$OPTARG"
+ ;;
+ N) # compare with a file, test if [n]ewer
+ if [ -f $OPTARG ]; then
+ newer=$OPTARG
+ newerarg="N"
+ else
+ echo >&2 $0: Warning, $OPTARG not found
+ fi
+ ;;
+ X) # Add exclude flag
+ tarargs=${tarargs}X
+ ;;
+ s) # specify [s]erver's share to connect to - this MUST be given.
+ server="$OPTARG"
+ ;;
+ b) # specify [b]locksize
+ blocksize="$OPTARG"
+ case "$OPTARG" in
+ [0-9]*) ;;
+ *) echo >&2 "$0: Error, block size not numeric: -b $OPTARG"
+ exit 1
+ esac
+ blocksizearg="b"
+ ;;
+ p) # specify [p]assword to use
+ password="$OPTARG"
+ ;;
+ x) # specify windows [s]hare to use
+ service="$OPTARG"
+ ;;
+ t) # specify [t]apefile on local host
+ tapefile="$OPTARG"
+ ;;
+ u) # specify [u]sername for connection
+ username="$OPTARG"
+ ;;
+ v) # be [v]erbose and display what's going on
+ verbose=""
+ ;;
+ '?') # any other switch
+ Usage 2 "Invalid switch specified - abort."
+ ;;
+ esac
+done
+
+shift `expr $OPTIND - 1`
+
+if [ "$server" = "" ] || [ "$service" = "" ]; then
+ Usage 1 "No server or no service specified - abort."
+fi
+
+# if the -v switch is set, the echo the current parameters
+if [ -z "$verbose" ]; then
+ echo "server is $server"
+# echo "share is $service"
+ echo "share is $service\\$cdcmd"
+ echo "tar args is $tarargs"
+# echo "password is $password" # passwords should never be sent to screen
+ echo "tape is $tapefile"
+ echo "blocksize is $blocksize"
+fi
+
+tarargs=${tarargs}${blocksizearg}${newerarg}
+
+eval $SMBCLIENT "'\\\\$server\\$service'" "'$password'" -U "'$username'" \
+-E $log -D "'$cdcmd'" ${clientargs} \
+-T${tarcmd}${tarargs} $blocksize $newer $tapefile '${1+"$@"}' $verbose
diff --git a/source3/script/strip_trail_ws.pl b/source3/script/strip_trail_ws.pl
new file mode 100755
index 0000000000..c2c39e21e3
--- /dev/null
+++ b/source3/script/strip_trail_ws.pl
@@ -0,0 +1,18 @@
+#!/usr/bin/perl -w
+
+open( INFILE, "$ARGV[0]" ) || die $@;
+open( OUTFILE, ">$ARGV[0].new" ) || die $@;
+
+while ( <INFILE> ) {
+ $_ =~ s/[ \t\r]*$//;
+ print OUTFILE "$_";
+}
+
+close( INFILE );
+close( OUTFILE );
+
+rename( "$ARGV[0].new", "$ARGV[0]" ) || die @_;
+
+exit( 0 );
+
+
diff --git a/source3/script/tests/dlopen.sh b/source3/script/tests/dlopen.sh
new file mode 100755
index 0000000000..edf44719d3
--- /dev/null
+++ b/source3/script/tests/dlopen.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+#
+# Copyright (C) Nalin Dahyabhai <nalin@redhat.com> 2003
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+tempdir=`mktemp -d /tmp/dlopenXXXXXX`
+test -n "$tempdir" || exit 1
+cat >> $tempdir/dlopen.c << _EOF
+#include <dlfcn.h>
+#include <stdio.h>
+#include <limits.h>
+#include <sys/stat.h>
+/* Simple program to see if dlopen() would succeed. */
+int main(int argc, char **argv)
+{
+ int i;
+ struct stat st;
+ char buf[PATH_MAX];
+ for (i = 1; i < argc; i++) {
+ if (dlopen(argv[i], RTLD_NOW)) {
+ fprintf(stdout, "dlopen() of \"%s\" succeeded.\n",
+ argv[i]);
+ } else {
+ snprintf(buf, sizeof(buf), "./%s", argv[i]);
+ if ((stat(buf, &st) == 0) && dlopen(buf, RTLD_NOW)) {
+ fprintf(stdout, "dlopen() of \"./%s\" "
+ "succeeded.\n", argv[i]);
+ } else {
+ fprintf(stdout, "dlopen() of \"%s\" failed: "
+ "%s\n", argv[i], dlerror());
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+_EOF
+
+for arg in $@ ; do
+ case "$arg" in
+ "")
+ ;;
+ -I*|-D*|-f*|-m*|-g*|-O*|-W*)
+ cflags="$cflags $arg"
+ ;;
+ -l*|-L*)
+ ldflags="$ldflags $arg"
+ ;;
+ /*)
+ modules="$modules $arg"
+ ;;
+ *)
+ modules="$modules $arg"
+ ;;
+ esac
+done
+
+${CC:-gcc} $RPM_OPT_FLAGS $CFLAGS -o $tempdir/dlopen $cflags $tempdir/dlopen.c $ldflags -ldl
+
+retval=0
+for module in $modules ; do
+ case "$module" in
+ "")
+ ;;
+ /*)
+ $tempdir/dlopen "$module"
+ retval=$?
+ ;;
+ *)
+ $tempdir/dlopen ./"$module"
+ retval=$?
+ ;;
+ esac
+done
+
+rm -f $tempdir/dlopen $tempdir/dlopen.c
+rmdir $tempdir
+exit $retval
diff --git a/source3/script/tests/gdb_backtrace b/source3/script/tests/gdb_backtrace
new file mode 100755
index 0000000000..826381e900
--- /dev/null
+++ b/source3/script/tests/gdb_backtrace
@@ -0,0 +1,87 @@
+#!/bin/sh
+
+BASENAME=`basename $0`
+
+if [ -n "$VALGRIND" -o -n "$SMBD_VALGRIND" ]; then
+ echo "${BASENAME}: Not running debugger under valgrind"
+ exit 1
+fi
+
+# we want everything on stderr, so the program is not disturbed
+exec 1>&2
+
+BASENAME=`basename $0`
+UNAME=`uname`
+
+PID=$1
+BINARY=$2
+
+test x"${PID}" = x"" && {
+ echo "Usage: ${BASENAME} <pid> [<binary>]"
+ exit 1
+}
+
+DB_LIST="gdb"
+case "${UNAME}" in
+ #
+ # on Tru64 we need to try ladebug first
+ # because gdb crashes itself...
+ #
+ OSF1)
+ DB_LIST="ladebug ${DB_LIST}"
+ ;;
+esac
+
+for DB in ${DB_LIST}; do
+ DB_BIN=`which ${DB} 2>/dev/null | grep '^/'`
+ test x"${DB_BIN}" != x"" && {
+ break
+ }
+done
+
+test x"${DB_BIN}" = x"" && {
+ echo "${BASENAME}: ERROR: No debugger found."
+ exit 1
+}
+
+#
+# we first try to use /proc/${PID}/exe
+# then fallback to the binary from the commandline
+# then we search for the commandline argument with
+# 'which'
+#
+test -f "/proc/${PID}/exe" && BINARY="/proc/${PID}/exe"
+test x"${BINARY}" = x"" && BINARY="/proc/${PID}/exe"
+test -f "${BINARY}" || BINARY=`which ${BINARY}`
+
+test -f "${BINARY}" || {
+ echo "${BASENAME}: ERROR: Cannot find binary '${BINARY}'."
+ exit 1
+}
+
+echo "${BASENAME}: Trying to use ${DB_BIN} on ${BINARY} on PID ${PID}"
+
+BATCHFILE_PRE=/tmp/gdb_backtrace_pre.$$
+BATCHFILE_MAIN=/tmp/gdb_backtrace_main.$$
+case "${DB}" in
+ ladebug)
+cat << EOF > ${BATCHFILE_PRE}
+set \$stoponattach
+EOF
+
+cat << EOF > ${BATCHFILE_MAIN}
+where
+quit
+EOF
+ ${DB_BIN} -c "${BATCHFILE_MAIN}" -i "${BATCHFILE_PRE}" -pid "${PID}" "${BINARY}"
+ ;;
+ gdb)
+cat << EOF > ${BATCHFILE_MAIN}
+set height 1000
+bt full
+quit
+EOF
+ ${DB_BIN} -x "${BATCHFILE_MAIN}" "${BINARY}" "${PID}"
+ ;;
+esac
+/bin/rm -f ${BATCHFILE_PRE} ${BATCHFILE_MAIN}
diff --git a/source3/script/tests/selftest.sh b/source3/script/tests/selftest.sh
new file mode 100755
index 0000000000..15e48b00ef
--- /dev/null
+++ b/source3/script/tests/selftest.sh
@@ -0,0 +1,324 @@
+#!/bin/sh
+
+if [ $# != 3 ]; then
+ echo "$0 <directory> <all | quick> <smbtorture4>"
+ exit 1
+fi
+
+SMBTORTURE4=$3
+SUBTESTS=$2
+
+##
+## create the test directory
+##
+PREFIX=`echo $1 | sed s+//+/+`
+mkdir -p $PREFIX || exit $?
+OLD_PWD=`pwd`
+cd $PREFIX || exit $?
+PREFIX_ABS=`pwd`
+cd $OLD_PWD
+
+if [ -z "$TORTURE_MAXTIME" ]; then
+ TORTURE_MAXTIME=300
+fi
+export TORTURE_MAXTIME
+
+##
+## setup the various environment variables we need
+##
+
+WORKGROUP=SAMBA-TEST
+SERVER=localhost2
+SERVER_IP=127.0.0.2
+USERNAME=`PATH=/usr/ucb:$PATH whoami`
+USERID=`PATH=/usr/ucb:$PATH id | cut -d ' ' -f1 | sed -e 's/uid=\([0-9]*\).*/\1/g'`
+GROUPID=`PATH=/usr/ucb:$PATH id | cut -d ' ' -f2 | sed -e 's/gid=\([0-9]*\).*/\1/g'`
+PASSWORD=test
+
+SRCDIR="`dirname $0`/../.."
+BINDIR="`pwd`/bin"
+SCRIPTDIR=$SRCDIR/script/tests
+SHRDIR=$PREFIX_ABS/tmp
+LIBDIR=$PREFIX_ABS/lib
+PIDDIR=$PREFIX_ABS/pid
+CONFFILE=$LIBDIR/client.conf
+SAMBA4CONFFILE=$LIBDIR/samba4client.conf
+SERVERCONFFILE=$LIBDIR/server.conf
+COMMONCONFFILE=$LIBDIR/common.conf
+PRIVATEDIR=$PREFIX_ABS/private
+LOCKDIR=$PREFIX_ABS/lockdir
+LOGDIR=$PREFIX_ABS/logs
+SOCKET_WRAPPER_DIR=$PREFIX/sw
+CONFIGURATION="--configfile $CONFFILE"
+SAMBA4CONFIGURATION="-s $SAMBA4CONFFILE"
+NSS_WRAPPER_PASSWD="$PRIVATEDIR/passwd"
+NSS_WRAPPER_GROUP="$PRIVATEDIR/group"
+WINBINDD_SOCKET_DIR=$PREFIX_ABS/winbindd
+WINBINDD_PRIV_PIPE_DIR=$LOCKDIR/winbindd_privileged
+
+export PREFIX PREFIX_ABS
+export CONFIGURATION CONFFILE SAMBA4CONFIGURATION SAMBA4CONFFILE
+export PATH SOCKET_WRAPPER_DIR DOMAIN
+export PRIVATEDIR LIBDIR PIDDIR LOCKDIR LOGDIR SERVERCONFFILE
+export SRCDIR SCRIPTDIR BINDIR
+export USERNAME PASSWORD
+export WORKGROUP SERVER SERVER_IP
+export NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
+export WINBINDD_SOCKET_DIR WINBINDD_PRIV_PIPE_DIR
+
+PATH=bin:$PATH
+export PATH
+
+if test x"$LD_LIBRARY_PATH" != x""; then
+ LD_LIBRARY_PATH="$BINDIR:$LD_LIBRARY_PATH"
+else
+ LD_LIBRARY_PATH="$BINDIR"
+fi
+echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH"
+export LD_LIBRARY_PATH
+
+SAMBA4BINDIR=`dirname $SMBTORTURE4`
+SAMBA4SHAREDDIR="$SAMBA4BINDIR/shared"
+
+export SAMBA4SHAREDDIR
+export SMBTORTURE4
+
+##
+## verify that we were built with --enable-socket-wrapper
+##
+
+if test "x`smbd -b | grep SOCKET_WRAPPER`" = "x"; then
+ echo "***"
+ echo "*** You must include --enable-socket-wrapper when compiling Samba"
+ echo "*** in order to execute 'make test'. Exiting...."
+ echo "***"
+ exit 1
+fi
+
+if test "x`smbd -b | grep NSS_WRAPPER`" = "x"; then
+ echo "***"
+ echo "*** You must include --enable-nss-wrapper when compiling Samba"
+ echo "*** in order to execute 'make test'. Exiting...."
+ echo "***"
+ exit 1
+fi
+
+
+##
+## create the test directory layout
+##
+printf "%s" "CREATE TEST ENVIRONMENT IN '$PREFIX'"...
+/bin/rm -rf $PREFIX/*
+mkdir -p $PRIVATEDIR $LIBDIR $PIDDIR $LOCKDIR $LOGDIR
+mkdir -p $SOCKET_WRAPPER_DIR
+mkdir -p $WINBINDD_SOCKET_DIR
+chmod 755 $WINBINDD_SOCKET_DIR
+mkdir -p $PREFIX_ABS/tmp
+chmod 777 $PREFIX_ABS/tmp
+
+##
+## Create the common config include file with the basic settings
+##
+
+cat >$COMMONCONFFILE<<EOF
+ workgroup = $WORKGROUP
+
+ private dir = $PRIVATEDIR
+ pid directory = $PIDDIR
+ lock directory = $LOCKDIR
+ log file = $LOGDIR/log.%m
+ log level = 0
+
+ name resolve order = bcast
+EOF
+
+TORTURE_INTERFACES='127.0.0.6/8,127.0.0.7/8,127.0.0.8/8,127.0.0.9/8,127.0.0.10/8,127.0.0.11/8'
+
+cat >$CONFFILE<<EOF
+[global]
+ netbios name = TORTURE_6
+ interfaces = $TORTURE_INTERFACES
+ panic action = $SCRIPTDIR/gdb_backtrace %d %\$(MAKE_TEST_BINARY)
+ include = $COMMONCONFFILE
+
+ passdb backend = tdbsam
+EOF
+
+cat >$SAMBA4CONFFILE<<EOF
+[global]
+ netbios name = TORTURE_6
+ interfaces = $TORTURE_INTERFACES
+ panic action = $SCRIPTDIR/gdb_backtrace %PID% %PROG%
+ include = $COMMONCONFFILE
+EOF
+
+cat >$SERVERCONFFILE<<EOF
+[global]
+ netbios name = $SERVER
+ interfaces = $SERVER_IP/8
+ bind interfaces only = yes
+ panic action = $SCRIPTDIR/gdb_backtrace %d %\$(MAKE_TEST_BINARY)
+ include = $COMMONCONFFILE
+
+ passdb backend = tdbsam
+
+ domain master = yes
+ domain logons = yes
+ time server = yes
+
+ add user script = $PERL $SRCDIR/lib/nss_wrapper/nss_wrapper.pl --path $NSS_WRAPPER_PASSWD --type passwd --action add --name %u
+ add machine script = $PERL $SRCDIR/lib/nss_wrapper/nss_wrapper.pl --path $NSS_WRAPPER_PASSWD --type passwd --action add --name %u
+ delete user script = $PERL $SRCDIR/lib/nss_wrapper/nss_wrapper.pl --path $NSS_WRAPPER_PASSWD --type passwd --action delete --name %u
+
+ kernel oplocks = no
+ kernel change notify = no
+
+ syslog = no
+ printing = bsd
+ printcap name = /dev/null
+
+ winbindd:socket dir = $WINBINDD_SOCKET_DIR
+ idmap uid = 100000-200000
+ idmap gid = 100000-200000
+
+# min receivefile size = 4000
+
+[tmp]
+ path = $PREFIX_ABS/tmp
+ read only = no
+ smbd:sharedelay = 100000
+ smbd:writetimeupdatedelay = 500000
+ map hidden = yes
+ map system = yes
+ create mask = 755
+ vfs objects = $BINDIR/xattr_tdb.so $BINDIR/streams_xattr.so
+[hideunread]
+ copy = tmp
+ hide unreadable = yes
+[hideunwrite]
+ copy = tmp
+ hide unwriteable files = yes
+[print1]
+ copy = tmp
+ printable = yes
+ printing = test
+[print2]
+ copy = print1
+[print3]
+ copy = print1
+[print4]
+ copy = print1
+EOF
+
+##
+## create a test account
+##
+
+cat >$NSS_WRAPPER_PASSWD<<EOF
+nobody:x:65534:65533:nobody gecos:$PREFIX_ABS:/bin/false
+$USERNAME:x:$USERID:$GROUPID:$USERNAME gecos:$PREFIX_ABS:/bin/false
+EOF
+
+cat >$NSS_WRAPPER_GROUP<<EOF
+nobody:x:65533:
+nogroup:x:65534:nobody
+$USERNAME-group:x:$GROUPID:
+EOF
+
+MAKE_TEST_BINARY="bin/smbpasswd"
+export MAKE_TEST_BINARY
+
+(echo $PASSWORD; echo $PASSWORD) | \
+ bin/smbpasswd -c $CONFFILE -L -s -a $USERNAME >/dev/null || exit 1
+
+echo "DONE";
+
+MAKE_TEST_BINARY=""
+
+SERVER_TEST_FIFO="$PREFIX/server_test.fifo"
+export SERVER_TEST_FIFO
+NMBD_TEST_LOG="$PREFIX/nmbd_test.log"
+export NMBD_TEST_LOG
+WINBINDD_TEST_LOG="$PREFIX/winbindd_test.log"
+export WINBINDD_TEST_LOG
+SMBD_TEST_LOG="$PREFIX/smbd_test.log"
+export SMBD_TEST_LOG
+
+# start off with 0 failures
+failed=0
+export failed
+
+. $SCRIPTDIR/test_functions.sh
+
+SOCKET_WRAPPER_DEFAULT_IFACE=2
+export SOCKET_WRAPPER_DEFAULT_IFACE
+samba3_check_or_start
+
+
+# ensure any one smbtorture call doesn't run too long
+# and smbtorture will use 127.0.0.6 as source address by default
+SOCKET_WRAPPER_DEFAULT_IFACE=6
+export SOCKET_WRAPPER_DEFAULT_IFACE
+TORTURE4_OPTIONS="$SAMBA4CONFIGURATION"
+TORTURE4_OPTIONS="$TORTURE4_OPTIONS --maximum-runtime=$TORTURE_MAXTIME"
+TORTURE4_OPTIONS="$TORTURE4_OPTIONS --target=samba3"
+TORTURE4_OPTIONS="$TORTURE4_OPTIONS --option=torture:localdir=$PREFIX_ABS/tmp"
+export TORTURE4_OPTIONS
+
+if [ x"$RUN_FROM_BUILD_FARM" = x"yes" ];then
+ TORTURE4_OPTIONS="$TORTURE4_OPTIONS --option=torture:progress=no"
+fi
+
+
+##
+## ready to go...now loop through the tests
+##
+
+START=`date`
+(
+ # give time for nbt server to register its names
+ echo "delaying for nbt name registration"
+ sleep 10
+ # This will return quickly when things are up, but be slow if we need to wait for (eg) SSL init
+ MAKE_TEST_BINARY="bin/nmblookup"
+ bin/nmblookup $CONFIGURATION -U $SERVER_IP __SAMBA__
+ bin/nmblookup $CONFIGURATION __SAMBA__
+ bin/nmblookup $CONFIGURATION -U 127.255.255.255 __SAMBA__
+ bin/nmblookup $CONFIGURATION -U $SERVER_IP $SERVER
+ bin/nmblookup $CONFIGURATION $SERVER
+ # make sure smbd is also up set
+ echo "wait for smbd"
+ MAKE_TEST_BINARY="bin/smbclient"
+ bin/smbclient $CONFIGURATION -L $SERVER_IP -U% -p 139 | head -2
+ bin/smbclient $CONFIGURATION -L $SERVER_IP -U% -p 139 | head -2
+ MAKE_TEST_BINARY=""
+
+ failed=0
+
+ . $SCRIPTDIR/tests_$SUBTESTS.sh
+ exit $failed
+)
+failed=$?
+
+samba3_stop_sig_term
+
+END=`date`
+echo "START: $START ($0)";
+echo "END: $END ($0)";
+
+# if there were any valgrind failures, show them
+count=`find $PREFIX -name 'valgrind.log*' | wc -l`
+if [ "$count" != 0 ]; then
+ for f in $PREFIX/valgrind.log*; do
+ if [ -s $f ]; then
+ echo "VALGRIND FAILURE";
+ failed=`expr $failed + 1`
+ cat $f
+ fi
+ done
+fi
+
+sleep 2
+samba3_stop_sig_kill
+
+teststatus $0 $failed
diff --git a/source3/script/tests/test_functions.sh b/source3/script/tests/test_functions.sh
new file mode 100644
index 0000000000..407d46aa9e
--- /dev/null
+++ b/source3/script/tests/test_functions.sh
@@ -0,0 +1,333 @@
+
+samba3_stop_sig_term() {
+ RET=0
+ kill -USR1 `cat $PIDDIR/timelimit.nmbd.pid` >/dev/null 2>&1 || \
+ kill -ALRM `cat $PIDDIR/timelimit.nmbd.pid` || RET=$?
+
+ kill -USR1 `cat $PIDDIR/timelimit.winbindd.pid` >/dev/null 2>&1 || \
+ kill -ALRM `cat $PIDDIR/timelimit.winbindd.pid` || RET=$?
+
+ kill -USR1 `cat $PIDDIR/timelimit.smbd.pid` >/dev/null 2>&1 || \
+ kill -ALRM `cat $PIDDIR/timelimit.smbd.pid` || RET=$?
+
+ return $RET;
+}
+
+samba3_stop_sig_kill() {
+ kill -ALRM `cat $PIDDIR/timelimit.nmbd.pid` >/dev/null 2>&1
+ kill -ALRM `cat $PIDDIR/timelimit.winbindd.pid` >/dev/null 2>&1
+ kill -ALRM `cat $PIDDIR/timelimit.smbd.pid` >/dev/null 2>&1
+ return 0;
+}
+
+samba3_check_or_start() {
+ if [ -n "$SERVER_TEST_FIFO" ];then
+
+ trap samba3_stop_sig_kill INT QUIT
+ trap samba3_stop_sig_kill TERM
+
+ if [ -p "$SERVER_TEST_FIFO" ];then
+ return 0;
+ fi
+
+ if [ -n "$SOCKET_WRAPPER_DIR" ];then
+ if [ -d "$SOCKET_WRAPPER_DIR" ]; then
+ rm -f $SOCKET_WRAPPER_DIR/*
+ else
+ mkdir -p $SOCKET_WRAPPER_DIR
+ fi
+ fi
+
+ rm -f $SERVER_TEST_FIFO
+ mkfifo $SERVER_TEST_FIFO
+
+ rm -f $NMBD_TEST_LOG
+ printf "%s" "STARTING NMBD..."
+ ((
+ if test x"$NMBD_MAXTIME" = x; then
+ NMBD_MAXTIME=2700
+ fi
+ MAKE_TEST_BINARY=$BINDIR/nmbd
+ export MAKE_TEST_BINARY
+ timelimit $NMBD_MAXTIME $NMBD_VALGRIND $BINDIR/nmbd -F -S --no-process-group -d0 -s $SERVERCONFFILE > $NMBD_TEST_LOG 2>&1 &
+ TIMELIMIT_NMBD_PID=$!
+ MAKE_TEST_BINARY=
+ echo $TIMELIMIT_NMBD_PID > $PIDDIR/timelimit.nmbd.pid
+ wait $TIMELIMIT_NMBD_PID
+ ret=$?;
+ rm -f $SERVER_TEST_FIFO
+ if [ -n "$SOCKET_WRAPPER_DIR" -a -d "$SOCKET_WRAPPER_DIR" ]; then
+ rm -f $SOCKET_WRAPPER_DIR/*
+ fi
+ if [ x"$ret" = x"0" ];then
+ echo "nmbd exits with status $ret";
+ echo "nmbd exits with status $ret" >>$NMBD_TEST_LOG;
+ elif [ x"$ret" = x"137" ];then
+ echo "nmbd got SIGXCPU and exits with status $ret!"
+ echo "nmbd got SIGXCPU and exits with status $ret!">>$NMBD_TEST_LOG;
+ else
+ echo "nmbd failed with status $ret!"
+ echo "nmbd failed with status $ret!">>$NMBD_TEST_LOG;
+ fi
+ exit $ret;
+ ) || exit $? &) 2>/dev/null || exit $?
+ echo "DONE"
+
+ rm -f $WINBINDD_TEST_LOG
+ printf "%s" "STARTING WINBINDD..."
+ ((
+ if test x"$WINBINDD_MAXTIME" = x; then
+ WINBINDD_MAXTIME=2700
+ fi
+ MAKE_TEST_BINARY=$BINDIR/winbindd
+ export MAKE_TEST_BINARY
+ timelimit $WINBINDD_MAXTIME $WINBINDD_VALGRIND $BINDIR/winbindd -F -S --no-process-group -d0 -s $SERVERCONFFILE > $WINBINDD_TEST_LOG 2>&1 &
+ TIMELIMIT_WINBINDD_PID=$!
+ MAKE_TEST_BINARY=
+ echo $TIMELIMIT_WINBINDD_PID > $PIDDIR/timelimit.winbindd.pid
+ wait $TIMELIMIT_WINBINDD_PID
+ ret=$?;
+ rm -f $SERVER_TEST_FIFO
+ if [ -n "$SOCKET_WRAPPER_DIR" -a -d "$SOCKET_WRAPPER_DIR" ]; then
+ rm -f $SOCKET_WRAPPER_DIR/*
+ fi
+ if [ x"$ret" = x"0" ];then
+ echo "winbindd exits with status $ret";
+ echo "winbindd exits with status $ret" >>$WINBINDD_TEST_LOG;
+ elif [ x"$ret" = x"137" ];then
+ echo "winbindd got SIGXCPU and exits with status $ret!"
+ echo "winbindd got SIGXCPU and exits with status $ret!">>$WINBINDD_TEST_LOG;
+ else
+ echo "winbindd failed with status $ret!"
+ echo "winbindd failed with status $ret!">>$WINBINDD_TEST_LOG;
+ fi
+ exit $ret;
+ ) || exit $? &) 2>/dev/null || exit $?
+ echo "DONE"
+
+ rm -f $SMBD_TEST_LOG
+ printf "%s" "STARTING SMBD..."
+ ((
+ if test x"$SMBD_MAXTIME" = x; then
+ SMBD_MAXTIME=2700
+ fi
+ MAKE_TEST_BINARY=$BINDIR/smbd
+ export MAKE_TEST_BINARY
+ timelimit $SMBD_MAXTIME $SMBD_VALGRIND $BINDIR/smbd -F -S --no-process-group -d0 -s $SERVERCONFFILE > $SMBD_TEST_LOG 2>&1 &
+ TIMELIMIT_SMBD_PID=$!
+ MAKE_TEST_BINARY=
+ echo $TIMELIMIT_SMBD_PID > $PIDDIR/timelimit.smbd.pid
+ wait $TIMELIMIT_SMBD_PID
+ ret=$?;
+ rm -f $SERVER_TEST_FIFO
+ if [ -n "$SOCKET_WRAPPER_DIR" -a -d "$SOCKET_WRAPPER_DIR" ]; then
+ rm -f $SOCKET_WRAPPER_DIR/*
+ fi
+ if [ x"$ret" = x"0" ];then
+ echo "smbd exits with status $ret";
+ echo "smbd exits with status $ret" >>$SMBD_TEST_LOG;
+ elif [ x"$ret" = x"137" ];then
+ echo "smbd got SIGXCPU and exits with status $ret!"
+ echo "smbd got SIGXCPU and exits with status $ret!">>$SMBD_TEST_LOG;
+ else
+ echo "smbd failed with status $ret!"
+ echo "smbd failed with status $ret!">>$SMBD_TEST_LOG;
+ fi
+ exit $ret;
+ ) || exit $? &) 2>/dev/null || exit $?
+ echo "DONE"
+ fi
+ return 0;
+}
+
+samba3_nmbd_test_log() {
+ if [ -n "$NMBD_TEST_LOG" ];then
+ if [ -r "$NMBD_TEST_LOG" ];then
+ return 0;
+ fi
+ fi
+ return 1;
+}
+
+samba3_winbindd_test_log() {
+ if [ -n "$WINBINDD_TEST_LOG" ];then
+ if [ -r "$WINBINDD_TEST_LOG" ];then
+ return 0;
+ fi
+ fi
+ return 1;
+}
+
+samba3_smbd_test_log() {
+ if [ -n "$SMBD_TEST_LOG" ];then
+ if [ -r "$SMBD_TEST_LOG" ];then
+ return 0;
+ fi
+ fi
+ return 1;
+}
+
+samba3_check_only() {
+ if [ -n "$SERVER_TEST_FIFO" ];then
+ if [ -p "$SERVER_TEST_FIFO" ];then
+ return 0;
+ fi
+ return 1;
+ fi
+ return 0;
+}
+
+testit() {
+ if [ -z "$PREFIX" ]; then
+ PREFIX=test_prefix
+ mkdir -p $PREFIX
+ fi
+ name=$1
+ shift 1
+ binary=$1
+ cmdline="$*"
+
+ SERVERS_ARE_UP="no"
+
+ shname=`echo $name | \
+ sed -e 's%[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\-]%_%g'`
+
+ UNIQUE_PID=`/bin/sh -c 'echo $$'`
+ TEST_LOG="$PREFIX/test_log.${UNIQUE_PID}"
+ TEST_PCAP="$PREFIX/test_${shname}_${UNIQUE_PID}.pcap"
+ trap "rm -f $TEST_LOG $TEST_PCAP" EXIT
+
+ if [ -z "$nmbd_log_size" ]; then
+ nmbd_log_size=`wc -l < $NMBD_TEST_LOG`;
+ fi
+ if [ -z "$winbindd_log_size" ]; then
+ winbindd_log_size=`wc -l < $WINBINDD_TEST_LOG`;
+ fi
+ if [ -z "$smbd_log_size" ]; then
+ smbd_log_size=`wc -l < $SMBD_TEST_LOG`;
+ fi
+
+ if [ x"$RUN_FROM_BUILD_FARM" = x"yes" ];then
+ echo "--==--==--==--==--==--==--==--==--==--==--"
+ echo "Running test $name (level 0 stdout)"
+ echo "--==--==--==--==--==--==--==--==--==--==--"
+ date
+ echo "Testing $name"
+ else
+ echo "Testing $name ($failed)"
+ fi
+
+ samba3_check_only && SERVERS_ARE_UP="yes"
+ if [ x"$SERVERS_ARE_UP" != x"yes" ];then
+ if [ x"$RUN_FROM_BUILD_FARM" = x"yes" ];then
+ echo "SERVERS are down! Skipping: $cmdline"
+ echo "=========================================="
+ echo "TEST SKIPPED: $name (reason SERVERS are down)"
+ echo "=========================================="
+ else
+ echo "TEST SKIPPED: $name (reason SERVERS are down)"
+ fi
+ return 1
+ fi
+
+ if [ x"$MAKE_TEST_ENABLE_PCAP" = x"yes" ];then
+ SOCKET_WRAPPER_PCAP_FILE=$TEST_PCAP
+ export SOCKET_WRAPPER_PCAP_FILE
+ fi
+
+ MAKE_TEST_BINARY=$binary
+ export MAKE_TEST_BINARY
+ ( $cmdline > $TEST_LOG 2>&1 )
+ status=$?
+ MAKE_TEST_BINARY=
+ # show any additional output from smbd that has happened in this test
+ samba3_nmbd_test_log && {
+ new_log_size=`wc -l < $NMBD_TEST_LOG`;
+ test "$new_log_size" = "$nmbd_log_size" || {
+ echo "NMBD OUTPUT:";
+ incr_log_size=`expr $new_log_size - $nmbd_log_size`;
+ tail -$incr_log_size $NMBD_TEST_LOG;
+ nmbd_log_size=$new_log_size;
+ }
+ }
+ samba3_winbindd_test_log && {
+ new_log_size=`wc -l < $WINBINDD_TEST_LOG`;
+ test "$new_log_size" = "$winbindd_log_size" || {
+ echo "WINBINDD OUTPUT:";
+ incr_log_size=`expr $new_log_size - $winbindd_log_size`;
+ tail -$incr_log_size $WINBINDD_TEST_LOG;
+ winbindd_log_size=$new_log_size;
+ }
+ }
+ samba3_smbd_test_log && {
+ new_log_size=`wc -l < $SMBD_TEST_LOG`;
+ test "$new_log_size" = "$smbd_log_size" || {
+ echo "SMBD OUTPUT:";
+ incr_log_size=`expr $new_log_size - $smbd_log_size`;
+ tail -$incr_log_size $SMBD_TEST_LOG;
+ smbd_log_size=$new_log_size;
+ }
+ }
+
+ if [ x"$status" != x"0" ]; then
+ echo "TEST OUTPUT:"
+ cat $TEST_LOG;
+ rm -f $TEST_LOG;
+ if [ x"$MAKE_TEST_ENABLE_PCAP" = x"yes" ];then
+ echo "TEST PCAP: $TEST_PCAP"
+ fi
+ if [ x"$RUN_FROM_BUILD_FARM" = x"yes" ];then
+ echo "=========================================="
+ echo "TEST FAILED: $name (status $status)"
+ echo "=========================================="
+ else
+ echo "TEST FAILED: $cmdline (status $status)"
+ fi
+ trap "" EXIT
+ return 1;
+ fi
+ rm -f $TEST_LOG;
+ if [ x"$MAKE_TEST_KEEP_PCAP" = x"yes" ];then
+ echo "TEST PCAP: $TEST_PCAP"
+ else
+ rm -f $TEST_PCAP;
+ fi
+ if [ x"$RUN_FROM_BUILD_FARM" = x"yes" ];then
+ echo "ALL OK: $cmdline"
+ echo "=========================================="
+ echo "TEST PASSED: $name"
+ echo "=========================================="
+ fi
+ trap "" EXIT
+ return 0;
+}
+
+testok() {
+ name=`basename $1`
+ failed=$2
+
+ if [ x"$failed" = x"0" ];then
+ :
+ else
+ echo "$failed TESTS FAILED or SKIPPED ($name)";
+ fi
+ exit $failed
+}
+
+teststatus() {
+ name=`basename $1`
+ failed=$2
+
+ if [ x"$failed" = x"0" ];then
+ echo "TEST STATUS: $failed";
+ else
+ echo "TEST STATUS: $failed";
+ fi
+ exit $failed
+}
+
+if [ -z "$VALGRIND" ]; then
+ MALLOC_CHECK_=2
+ export MALLOC_CHECK_
+fi
+
diff --git a/source3/script/tests/test_groupmap.sh b/source3/script/tests/test_groupmap.sh
new file mode 100755
index 0000000000..46640a9131
--- /dev/null
+++ b/source3/script/tests/test_groupmap.sh
@@ -0,0 +1,214 @@
+#!/bin/sh
+# test groupmap code tridge@samba.org September 2006
+# note that this needs root access to add unix groups,
+# so this cannot be run on the build farm
+
+testone() {
+ echo $*
+ $VALGRIND bin/net groupmap $*
+}
+
+tstart() {
+ TBASE=`date '+%s'`
+}
+
+treport() {
+ TNOW=`date '+%s'`
+ echo "Took `expr $TNOW - $TBASE` seconds"
+ TBASE=$TNOW
+}
+
+rm -f $PREFIX_ABS/var/locks/group_mapping.?db
+
+NLOCAL=12
+NGROUP=11
+NBUILTIN=10
+DOMSID=`bin/net getlocalsid | awk '{print $6}'`
+FORSID="S-1-2-3-4-5"
+
+echo "DOMSID $DOMSID"
+echo "FORSID $FORSID"
+
+tstart
+echo "Creating unix groups"
+for i in `seq 1 1 $NLOCAL`; do
+ unixgroup=testlocal$i;
+ gid=`expr 30000 + $i`;
+ groupdel $unixgroup 2> /dev/null
+ groupadd -g $gid $unixgroup || exit 1
+done
+for i in `seq 1 1 $NGROUP`; do
+ unixgroup=testgrp$i;
+ gid=`expr 40000 + $i`;
+ groupdel $unixgroup 2> /dev/null
+ groupadd -g $gid $unixgroup || exit 1
+done
+for i in `seq 1 1 $NBUILTIN`; do
+ unixgroup=testb$i;
+ gid=`expr 50000 + $i`;
+ groupdel $unixgroup 2> /dev/null
+ groupadd -g $gid $unixgroup || exit 1
+done
+date
+
+treport
+
+echo "Creating local groups"
+for i in `seq 1 1 $NLOCAL`; do
+ unixgroup=testlocal$i;
+ ntgroup=ntlgrp$i;
+ rid=`expr 10000 + $i`;
+ testone add rid=$rid unixgroup=$unixgroup ntgroup=$ntgroup type=local || exit 1
+done
+
+echo "trying a duplicate add"
+testone add rid=10001 unixgroup=testlocal1 ntgroup=foo type=local && exit 1
+
+treport
+
+echo "Creating domain groups"
+for i in `seq 1 1 $NGROUP`; do
+ unixgroup=testgrp$i;
+ ntgroup=ntgrp$i;
+ rid=`expr 20000 + $i`;
+ testone add rid=$rid unixgroup=$unixgroup ntgroup=$ntgroup type=domain || exit 1
+done
+
+treport
+
+echo "Creating builtin groups"
+for i in `seq 1 1 $NBUILTIN`; do
+ unixgroup=testb$i;
+ ntgroup=ntbgrp$i;
+ rid=`expr 30000 + $i`;
+ testone add rid=$rid unixgroup=$unixgroup ntgroup=$ntgroup type=builtin || exit 1
+done
+
+treport
+
+echo "Adding domain groups to local groups"
+for i in `seq 1 1 $NLOCAL`; do
+ for j in `seq 1 1 $i`; do
+
+ lrid=`expr 10000 + $i`;
+ drid=`expr 20000 + $j`;
+
+ testone addmem $DOMSID-$lrid $DOMSID-$drid || exit 1
+ ( testone listmem $DOMSID-$lrid | sort -r ) || exit 1
+ done
+done
+
+echo "trying a duplicate addmem"
+testone addmem $DOMSID-10001 $DOMSID-20001 && exit 1
+
+echo "Adding foreign SIDs to local groups"
+for i in `seq 1 1 $NLOCAL`; do
+ for j in `seq 1 1 $i`; do
+
+ lrid=`expr 10000 + $i`;
+ frid=`expr 70000 + $j`;
+
+ testone addmem $DOMSID-$lrid $FORSID-$frid || exit 1
+ ( testone listmem $DOMSID-$lrid | sort -r ) || exit 1
+ done
+done
+
+echo "trying a duplicate foreign addmem"
+testone addmem $DOMSID-10001 $FORSID-70001 && exit 1
+
+treport
+
+echo "Listing local group memberships of domain groups"
+for i in `seq 1 1 $NGROUP`; do
+ rid=`expr 20000 + $i`;
+ ( testone memberships $DOMSID-$rid | sort -r ) || exit 1
+done
+
+echo "Trying memberships on bogus sid"
+testone memberships $DOMSID-999999 || exit 1
+
+treport
+
+testone list | sort
+
+echo "Deleting some domain groups"
+for i in `seq 2 2 $NGROUP`; do
+ drid=`expr 20000 + $i`;
+ testone delete sid=$DOMSID-$drid || exit 1
+done
+
+echo "Trying duplicate domain group delete"
+testone delete sid=$DOMSID-20002 && exit 1
+
+treport
+
+echo "Deleting some local groups"
+for i in `seq 2 4 $NLOCAL`; do
+ lrid=`expr 10000 + $i`;
+ testone delete sid=$DOMSID-$lrid || exit 1
+done
+
+echo "Trying duplicate local group delete"
+testone delete sid=$DOMSID-10002 && exit 1
+
+treport
+
+echo "Modifying some domain groups"
+for i in `seq 3 2 $NGROUP`; do
+ drid=`expr 20000 + $i`;
+ testone modify sid=$DOMSID-$drid comment="newcomment-$i" type=domain || exit 1
+done
+
+treport
+
+testone list | sort
+
+echo "Listing local group memberships"
+for i in `seq 1 1 $NLOCAL`; do
+ rid=`expr 20000 + $i`;
+ ( testone memberships $DOMSID-$rid | sort -r ) || exit 1
+done
+
+treport
+
+echo "Removing some domain groups from local groups"
+for i in `seq 1 2 $NLOCAL`; do
+ for j in `seq 1 3 $i`; do
+
+ lrid=`expr 10000 + $i`;
+ drid=`expr 20000 + $j`;
+
+ testone delmem $DOMSID-$lrid $DOMSID-$drid || exit 1
+ done
+done
+
+echo "Trying duplicate delmem"
+testone delmem $DOMSID-10001 $DOMSID-20001 && exit 1
+
+treport
+
+echo "Listing local group memberships"
+for i in `seq 1 1 $NLOCAL`; do
+ rid=`expr 20000 + $i`;
+ ( testone memberships $DOMSID-$rid | sort -r ) || exit 1
+done
+
+treport
+
+echo "Deleting unix groups"
+for i in `seq 1 1 $NLOCAL`; do
+ unixgroup=testlocal$i;
+ groupdel $unixgroup 2> /dev/null
+done
+for i in `seq 1 1 $NGROUP`; do
+ unixgroup=testgrp$i;
+ groupdel $unixgroup 2> /dev/null
+done
+for i in `seq 1 1 $NBUILTIN`; do
+ unixgroup=testb$i;
+ groupdel $unixgroup 2> /dev/null
+done
+
+treport
+
+echo "ALL DONE"
diff --git a/source3/script/tests/test_local_s3.sh b/source3/script/tests/test_local_s3.sh
new file mode 100755
index 0000000000..aed8637abd
--- /dev/null
+++ b/source3/script/tests/test_local_s3.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+# this runs the file serving tests that are expected to pass with samba3
+
+if [ $# != 0 ]; then
+cat <<EOF
+Usage: test_local_s3.sh
+EOF
+exit 1;
+fi
+
+incdir=`dirname $0`
+. $incdir/test_functions.sh
+
+failed=0
+
+testit "talloctort" $VALGRIND $BINDIR/talloctort || \
+ failed=`expr $failed + 1`
+
+testit "replacetort" $VALGRIND $BINDIR/replacetort || \
+ failed=`expr $failed + 1`
+
+testit "tdbtorture" $VALGRIND $BINDIR/tdbtorture || \
+ failed=`expr $failed + 1`
+
+testit "smbconftort" $VALGRIND $BINDIR/smbconftort $CONFIGURATION || \
+ failed=`expr $failed + 1`
+
+testok $0 $failed
diff --git a/source3/script/tests/test_net_misc.sh b/source3/script/tests/test_net_misc.sh
new file mode 100755
index 0000000000..0a0636ac8a
--- /dev/null
+++ b/source3/script/tests/test_net_misc.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+# various tests for the "net" command
+
+NET="$VALGRIND ${NET:-$BINDIR/net} $CONFIGURATION"
+
+NETTIME="${NET} time"
+NETLOOKUP="${NET} lookup"
+
+incdir=`dirname $0`
+. $incdir/test_functions.sh
+
+failed=0
+
+test_time()
+{
+ PARAM="$1"
+
+ ${NETTIME} ${PARAM} -S localhost2
+}
+
+test_lookup()
+{
+ PARAM="$1"
+
+ ${NETLOOKUP} ${PARAM}
+}
+
+testit "get the time" \
+ test_time || \
+ failed=`expr $failed + 1`
+
+testit "get the system time" \
+ test_time system || \
+ failed=`expr $failed + 1`
+
+testit "get the time zone" \
+ test_time zone || \
+ failed=`expr $failed + 1`
+
+testit "lookup the PDC" \
+ test_lookup pdc || \
+ failed=`expr $failed + 1`
+
+testit "lookup the master browser" \
+ test_lookup master || \
+ failed=`expr $failed + 1`
+
+testok $0 $failed
+
diff --git a/source3/script/tests/test_net_registry.sh b/source3/script/tests/test_net_registry.sh
new file mode 100755
index 0000000000..5edcb061ee
--- /dev/null
+++ b/source3/script/tests/test_net_registry.sh
@@ -0,0 +1,442 @@
+#!/bin/sh
+
+# Tests for the "net registry" and "net rpc registry" commands.
+# rpc tests are chose by specifying "rpc" as commandline parameter.
+
+RPC="$1"
+
+NET="$VALGRIND ${NET:-$BINDIR/net} $CONFIGURATION"
+
+if test "x${RPC}" = "xrpc" ; then
+ NETREG="${NET} -U${USERNAME}%${PASSWORD} -I ${SERVER_IP} rpc registry"
+else
+ NETREG="${NET} registry"
+fi
+
+incdir=`dirname $0`
+. $incdir/test_functions.sh
+
+failed=0
+
+test_enumerate()
+{
+ KEY="$1"
+
+ ${NETREG} enumerate ${KEY}
+}
+
+test_getsd()
+{
+ KEY="$1"
+
+ ${NETREG} getsd ${KEY}
+}
+
+test_enumerate_nonexisting()
+{
+ KEY="$1"
+ ${NETREG} enumerate ${KEY}
+
+ if test "x$?" = "x0" ; then
+ echo "ERROR: enumerate succeeded with key '${KEY}'"
+ false
+ else
+ true
+ fi
+}
+
+test_enumerate_no_key()
+{
+ ${NETREG} enumerate
+ if test "x$?" = "x0" ; then
+ echo "ERROR: enumerate succeeded without any key spcified"
+ false
+ else
+ true
+ fi
+}
+
+test_create_existing()
+{
+ KEY="HKLM"
+ EXPECTED="createkey opened existing ${KEY}"
+
+ OUTPUT=`${NETREG} createkey ${KEY}`
+ if test "x$?" = "x0" ; then
+ if test "$OUTPUT" = "$EXPECTED" ; then
+ true
+ else
+ echo "got '$OUTPUT', expected '$EXPECTED'"
+ false
+ fi
+ else
+ printf "%s\n" "$OUTPUT"
+ false
+ fi
+}
+
+test_createkey()
+{
+ KEY="$1"
+ BASEKEY=`dirname $KEY`
+ SUBKEY=`basename $KEY`
+
+ OUTPUT=`${NETREG} createkey ${KEY}`
+ if test "x$?" != "x0" ; then
+ echo "ERROR: createkey ${KEY} failed"
+ echo "output:"
+ printf "%s\n" "$OUTPUT"
+ false
+ return
+ fi
+
+ # check enumerate of basekey lists new key:
+ OUTPUT=`${NETREG} enumerate ${BASEKEY}`
+ if test "x$?" != "x0" ; then
+ echo "ERROR: failed to enumerate key '${BASEKEY}'"
+ echo "output:"
+ printf "%s\n" "$OUTPUT"
+ false
+ return
+ fi
+
+ EXPECTED="Keyname = ${SUBKEY}"
+ printf "%s\n" "$OUTPUT" | grep '^Keyname' | grep ${SUBKEY}
+ if test "x$?" != "x0" ; then
+ echo "ERROR: did not find expexted '$EXPECTED' in output"
+ echo "output:"
+ printf "%s\n" "$OUTPUT"
+ false
+ fi
+
+ # check enumerate of new key works:
+ ${NETREG} enumerate ${KEY}
+}
+
+test_deletekey()
+{
+ KEY="$1"
+ BASEKEY=`dirname ${KEY}`
+ SUBKEY=`basename ${KEY}`
+
+ OUTPUT=`test_createkey "${KEY}"`
+ if test "x$?" != "x0" ; then
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ OUTPUT=`${NETREG} deletekey ${KEY}`
+ if test "x$?" != "x0" ; then
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ # check enumerate of basekey does not show key anymore:
+ OUTPUT=`${NETREG} enumerate ${BASEKEY}`
+ if test "x$?" != "x0" ; then
+ printf "%s\n" "$OUTPUT"
+ false
+ return
+ fi
+
+ UNEXPECTED="Keyname = ${SUBKEY}"
+ printf "%s\n" "$OUTPUT" | 'grep ^Keyname' | grep ${SUBKEY}
+ if test "x$?" = "x0" ; then
+ echo "ERROR: found '$UNEXPECTED' after delete in output"
+ echo "output:"
+ printf "%s\n" "$OUTPUT"
+ false
+ fi
+
+ # check enumerate of key itself does not work anymore:
+ ${NETREG} enumerate ${KEY}
+ if test "x$?" = "x0" ; then
+ echo "ERROR: 'enumerate ${KEY}' works after 'deletekey ${KEY}'"
+ false
+ else
+ true
+ fi
+}
+
+test_deletekey_nonexisting()
+{
+ KEY="$1"
+
+ OUTPUT=`test_deletekey "${KEY}"`
+ if test "x$?" != "x0" ; then
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ ${NETREG} deletekey "${KEY}"
+ if test "x$?" = "x0" ; then
+ echo "ERROR: delete after delete succeeded for key '${KEY}'"
+ false
+ fi
+}
+
+test_createkey_with_subkey()
+{
+ KEY="$1"
+ KEY2=`dirname ${KEY}`
+ SUBKEYNAME2=`basename ${KEY}`
+ BASENAME=`dirname ${KEY2}`
+ SUBKEYNAME1=`basename ${KEY2}`
+
+ OUTPUT=`${NETREG} createkey ${KEY}`
+ if test "x$?" != "x0" ; then
+ echo "ERROR: createkey ${KEY} failed"
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ # check we can enumerate to level key
+ OUTPUT=`${NETREG} enumerate ${KEY}`
+ if test "x$?" != "x0" ; then
+ echo "ERROR: failed to enumerate '${KEY}' after creation"
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ # clear:
+ ${NETREG} deletekey ${KEY} && ${NETREG} deletekey ${KEY2}
+}
+
+test_deletekey_with_subkey()
+{
+ KEY="$1"
+ KEY2=`dirname ${KEY}`
+
+ OUTPUT=`${NETREG} createkey ${KEY}`
+ if test "x$?" != "x0" ; then
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ OUTPUT=`${NETREG} deletekey ${KEY2}`
+
+ if test "x$?" = "x0" ; then
+ echo "ERROR: delete of key with subkey succeeded"
+ echo "output:"
+ printf "%s\n" "$OUTPUT"
+ false
+ return
+ fi
+
+ ${NETREG} deletekey ${KEY} && ${NETREG} deletekey ${KEY2}
+}
+
+test_setvalue()
+{
+ KEY="$1"
+ VALNAME="$2"
+ VALTYPE="$3"
+ VALVALUE="$4"
+
+ OUTPUT=`test_createkey ${KEY}`
+ if test "x$?" != "x0" ; then
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ OUTPUT=`${NETREG} setvalue ${KEY} ${VALNAME} ${VALTYPE} ${VALVALUE}`
+ if test "x$?" != "x0" ; then
+ echo "ERROR: failed to set value testval in key ${KEY}"
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ OUTPUT=`${NETREG} enumerate ${KEY}`
+ if test "x$?" != "x0" ; then
+ echo "ERROR: failure calling enumerate for key ${KEY}"
+ echo output:
+ printf "%s\n" "${OUTPUT}"
+ false
+ return
+ fi
+
+ printf "%s\n" "$OUTPUT" | {
+ FOUND=0
+ while read LINE ; do
+ SEARCH1=`echo $LINE | grep '^Valuename' | grep ${VALNAME}`
+ if test "x$?" = "x0" ; then
+ read LINE
+ read LINE
+ SEARCH2=`echo $LINE | grep '^Value ' | grep ${VALVALUE}`
+ if test "x$?" = "x0" ; then
+ FOUND=1
+ break
+ fi
+ fi
+ done
+
+ if test "x$FOUND" != "x1" ; then
+ echo "ERROR: did not find value '${VALNAME}' with enumerate"
+ echo "enumerate output:"
+ printf "%s\n" "$OUTPUT"
+ false
+ return
+ fi
+ }
+}
+
+test_deletevalue()
+{
+ KEY="$1"
+ VALNAME="$2"
+
+ ${NETREG} deletevalue ${KEY} ${VALNAME}
+}
+
+test_deletevalue_nonexisting()
+{
+ KEY="$1"
+ VALNAME="$2"
+
+ ${NETREG} deletevalue ${KEY} ${VALNAME}
+ if test "x$?" = "x0" ; then
+ echo "ERROR: succeeded deleting value ${VALNAME}"
+ false
+ else
+ true
+ fi
+}
+
+test_setvalue_twice()
+{
+ KEY="$1"
+ VALNAME="$2"
+ VALTYPE1="$3"
+ VALVALUE1="$4"
+ VALTYPE2="$5"
+ VALVALUE2="$6"
+
+ OUTPUT=`test_setvalue ${KEY} ${VALNAME} ${VALTYPE1} ${VALVALUE1}`
+ if test "x$?" != "x0" ; then
+ echo "ERROR: first setvalue call failed"
+ printf "%s\n" "$OUTPUT"
+ false
+ return
+ fi
+
+ ${NETREG} setvalue ${KEY} ${VALNAME} ${VALTYPE2} ${VALVALUE2}
+}
+
+give_administrative_rights()
+{
+ bin/net -s $SERVERCONFFILE sam createbuiltingroup Administrators
+ if test "x$?" != "x0" ; then
+ echo "ERROR: creating builtin group Administrators"
+ false
+ return
+ fi
+
+ bin/net -s $SERVERCONFFILE sam addmem BUILTIN\\Administrators $USERNAME
+ if test "x$?" != "x0" ; then
+ echo "ERROR: adding user $USERNAME to BUILTIN\\Administrators"
+ false
+ else
+ true
+ fi
+}
+
+take_administrative_rights()
+{
+ bin/net -s $SERVERCONFFILE sam delmem BUILTIN\\Administrators $USERNAME
+ if test "x$?" != "x0" ; then
+ echo "ERROR: removing user $USERNAME from BUILTIN\\Administrators"
+ false
+ else
+ true
+ fi
+}
+
+if test "x${RPC}" = "xrpc" ; then
+testit "giving user ${USERNAME} administrative rights" \
+ give_administrative_rights || \
+ failed=`expr $failed + 1`
+fi
+
+testit "enumerate HKLM" \
+ test_enumerate HKLM || \
+ failed=`expr $failed + 1`
+
+testit "enumerate nonexisting hive" \
+ test_enumerate_nonexisting XYZ || \
+ failed=`expr $failed + 1`
+
+testit "enumerate without key" \
+ test_enumerate_no_key || \
+ failed=`expr $failed + 1`
+
+# skip getsd test for registry currently: it fails
+if test "x${RPC}" != "xrpc" ; then
+testit "getsd HKLM" \
+ test_getsd HKLM || \
+ failed=`expr $failed + 1`
+fi
+
+testit "create existing HKLM" \
+ test_create_existing || \
+ failed=`expr $failed + 1`
+
+testit "create key" \
+ test_createkey HKLM/testkey || \
+ failed=`expr $failed + 1`
+
+testit "delete key" \
+ test_deletekey HKLM/testkey || \
+ failed=`expr $failed + 1`
+
+testit "delete^2 key" \
+ test_deletekey_nonexisting HKLM/testkey || \
+ failed=`expr $failed + 1`
+
+testit "enumerate nonexisting key" \
+ test_enumerate_nonexisting HKLM/testkey || \
+ failed=`expr $failed + 1`
+
+testit "create key with subkey" \
+ test_createkey_with_subkey HKLM/testkey/subkey || \
+ failed=`expr $failed + 1`
+
+testit "delete key with subkey" \
+ test_deletekey_with_subkey HKLM/testkey/subkey || \
+ failed=`expr $failed + 1`
+
+testit "set value" \
+ test_setvalue HKLM/testkey testval sz moin || \
+ failed=`expr $failed + 1`
+
+testit "delete value" \
+ test_deletevalue HKLM/testkey testval || \
+ failed=`expr $failed + 1`
+
+testit "delete nonexisting value" \
+ test_deletevalue_nonexisting HKLM/testkey testval || \
+ failed=`expr $failed + 1`
+
+testit "set value to different type" \
+ test_setvalue_twice HKLM/testkey testval sz moin dword 42 || \
+ failed=`expr $failed + 1`
+
+testit "delete key with value" \
+ test_deletekey HKLM/testkey || \
+ failed=`expr $failed + 1`
+
+if test "x${RPC}" = "xrpc" ; then
+testit "taking administrative rights from user ${USERNAME}" \
+ take_administrative_rights || \
+ failed=`expr $failed + 1`
+fi
+
+testok $0 $failed
+
diff --git a/source3/script/tests/test_net_s3.sh b/source3/script/tests/test_net_s3.sh
new file mode 100755
index 0000000000..f7dc2b7e10
--- /dev/null
+++ b/source3/script/tests/test_net_s3.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+# tests for the "net" command
+
+incdir=`dirname $0`
+. $incdir/test_functions.sh
+
+failed=0
+
+net_misc() {
+ echo "RUNNING SUBTESTS net_misc"
+ $SCRIPTDIR/test_net_misc.sh \
+ || failed=`expr $failed + $?`
+}
+
+net_registry() {
+ echo "RUNNING SUBTESTS net_registry"
+ $SCRIPTDIR/test_net_registry.sh \
+ || failed=`expr $failed + $?`
+}
+
+net_rpc_registry() {
+ echo "RUNNING SUBTESTS net_rpc_registry"
+ $SCRIPTDIR/test_net_registry.sh rpc \
+ || failed=`expr $failed + $?`
+}
+
+net_misc
+net_registry
+net_rpc_registry
+
+testok $0 $failed
+
diff --git a/source3/script/tests/test_ntlm_auth_s3.sh b/source3/script/tests/test_ntlm_auth_s3.sh
new file mode 100755
index 0000000000..6c97f2e650
--- /dev/null
+++ b/source3/script/tests/test_ntlm_auth_s3.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+incdir=`dirname $0`
+. $incdir/test_functions.sh
+
+failed=0
+
+(/usr/bin/env python --version > /dev/null 2>&1)
+
+if test $? -ne 0;
+then
+ echo "Python binary not found in path. Skipping ntlm_auth tests."
+ exit 0
+fi
+
+testit "ntlm_auth" $VALGRIND $SRCDIR/torture/test_ntlm_auth.py $BINDIR/ntlm_auth --configfile=$CONFFILE || failed=`expr $failed + 1`
+# This should work even with NTLMv2
+testit "ntlm_auth" $VALGRIND $SRCDIR/torture/test_ntlm_auth.py $BINDIR/ntlm_auth --configfile=$CONFFILE --client-domain=fOo --server-domain=fOo || failed=`expr $failed + 1`
+
+
+testok $0 $failed
diff --git a/source3/script/tests/test_posix_s3.sh b/source3/script/tests/test_posix_s3.sh
new file mode 100755
index 0000000000..3e9998666c
--- /dev/null
+++ b/source3/script/tests/test_posix_s3.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+
+# this runs the file serving tests that are expected to pass with samba3
+
+if [ $# -lt 3 ]; then
+cat <<EOF
+Usage: test_posix_s3.sh UNC USERNAME PASSWORD <first> <smbtorture args>
+EOF
+exit 1;
+fi
+
+unc="$1"
+username="$2"
+password="$3"
+start="$4"
+shift 4
+ADDARGS="$*"
+
+incdir=`dirname $0`
+. $incdir/test_functions.sh
+
+base="BASE-ATTR BASE-CHARSET BASE-CHKPATH BASE-DEFER_OPEN BASE-DELAYWRITE BASE-DELETE"
+base="$base BASE-DENY1 BASE-DENY2 BASE-DENY3 BASE-DENYDOS BASE-DIR1 BASE-DIR2"
+base="$base BASE-DISCONNECT BASE-FDPASS BASE-LOCK"
+base="$base BASE-MANGLE BASE-NEGNOWAIT BASE-NTDENY1"
+base="$base BASE-NTDENY2 BASE-OPEN BASE-OPENATTR BASE-PROPERTIES BASE-RENAME BASE-RW1"
+base="$base BASE-SECLEAK BASE-TCON BASE-TCONDEV BASE-TRANS2 BASE-UNLINK BASE-VUID"
+base="$base BASE-XCOPY BASE-SAMBA3ERROR"
+
+raw="RAW-ACLS RAW-CHKPATH RAW-CLOSE RAW-COMPOSITE RAW-CONTEXT RAW-EAS"
+raw="$raw RAW-IOCTL RAW-LOCK RAW-MKDIR RAW-MUX RAW-NOTIFY RAW-OPEN RAW-OPLOCK"
+raw="$raw RAW-QFILEINFO RAW-QFSINFO RAW-READ RAW-RENAME RAW-SEARCH RAW-SEEK"
+raw="$raw RAW-SFILEINFO RAW-SFILEINFO-BUG RAW-STREAMS RAW-UNLINK RAW-WRITE"
+raw="$raw RAW-SAMBA3HIDE RAW-SAMBA3BADPATH RAW-SFILEINFO-RENAME"
+raw="$raw RAW-SAMBA3CASEINSENSITIVE RAW-SAMBA3POSIXTIMEDLOCK"
+raw="$raw RAW-SAMBA3ROOTDIRFID"
+
+rpc="RPC-AUTHCONTEXT RPC-BINDSAMBA3 RPC-SAMBA3-SRVSVC RPC-SAMBA3-SHARESEC"
+rpc="$rpc RPC-SAMBA3-SPOOLSS RPC-SAMBA3-WKSSVC"
+rpc="$rpc RPC-NETLOGSAMBA3 RPC-SAMBA3SESSIONKEY RPC-SAMBA3-GETUSERNAME"
+
+# NOTE: to enable the UNIX-WHOAMI test, we need to change the default share
+# config to allow guest access. I'm not sure whether this would break other
+# tests, so leaving it alone for now -- jpeach
+unix="UNIX-INFO2"
+
+tests="$base $raw $rpc $unix"
+
+if test "x$POSIX_SUBTESTS" != "x" ; then
+ tests="$POSIX_SUBTESTS"
+fi
+
+skipped="BASE-CHARSET BASE-TCONDEV"
+skipped="$skipped RAW-ACLS RAW-COMPOSITE RAW-CONTEXT"
+skipped="$skipped RAW-IOCTL"
+skipped="$skipped RAW-QFILEINFO RAW-QFSINFO"
+skipped="$skipped RAW-SFILEINFO"
+
+echo "WARNING: Skipping tests $skipped"
+
+ADDARGS="$ADDARGS --option=torture:sharedelay=100000"
+ADDARGS="$ADDARGS --option=torture:writetimeupdatedelay=500000"
+
+failed=0
+for t in $tests; do
+ if [ ! -z "$start" -a "$start" != $t ]; then
+ continue;
+ fi
+ skip=0
+ for s in $skipped; do
+ if [ x"$s" = x"$t" ]; then
+ skip=1;
+ break;
+ fi
+ done
+ if [ $skip = 1 ]; then
+ continue;
+ fi
+ start=""
+ name="$t"
+ testit "$name" $VALGRIND $SMBTORTURE4 $TORTURE4_OPTIONS $ADDARGS $unc -U"$username"%"$password" $t || failed=`expr $failed + 1`
+done
+
+testok $0 $failed
diff --git a/source3/script/tests/test_smbclient_s3.sh b/source3/script/tests/test_smbclient_s3.sh
new file mode 100755
index 0000000000..c10aed0ee6
--- /dev/null
+++ b/source3/script/tests/test_smbclient_s3.sh
@@ -0,0 +1,87 @@
+#!/bin/sh
+
+# this runs the file serving tests that are expected to pass with samba3
+
+if [ $# -lt 2 ]; then
+cat <<EOF
+Usage: test_smbclient_s3.sh SERVER SERVER_IP
+EOF
+exit 1;
+fi
+
+SERVER="$1"
+SERVER_IP="$2"
+SMBCLIENT="$VALGRIND ${SMBCLIENT:-$BINDIR/smbclient} $CONFIGURATION"
+shift 2
+ADDARGS="$*"
+
+incdir=`dirname $0`
+. $incdir/test_functions.sh
+
+failed=0
+
+# Test that a noninteractive smbclient does not prompt
+test_noninteractive_no_prompt()
+{
+ prompt="smb"
+
+ echo du | \
+ $SMBCLIENT $CONFIGURATION "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I SERVER_IP $ADDARGS 2>&1 | \
+ grep $prompt
+
+ if [ $? = 0 ] ; then
+ # got a prompt .. fail
+ echo matched interactive prompt in non-interactive mode
+ false
+ else
+ true
+ fi
+}
+
+# Test that an interactive smbclient prompts to stdout
+test_interactive_prompt_stdout()
+{
+ prompt="smb"
+ tmpfile=/tmp/smbclient.in.$$
+
+ cat > $tmpfile <<EOF
+du
+quit
+EOF
+
+ CLI_FORCE_INTERACTIVE=yes \
+ $SMBCLIENT $CONFIGURATION "$@" -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP \
+ $ADDARGS < $tmpfile 2>/dev/null | \
+ grep $prompt
+
+ if [ $? = 0 ] ; then
+ # got a prompt .. succeed
+ rm -f $tmpfile
+ true
+ else
+ echo failed to match interactive prompt on stdout
+ rm -f $tmpfile
+ false
+ fi
+}
+
+testit "smbclient -L $SERVER_IP" $SMBCLIENT $CONFIGURATION -L $SERVER_IP -N -p 139 || failed=`expr $failed + 1`
+testit "smbclient -L $SERVER -I $SERVER_IP" $SMBCLIENT $CONFIGURATION -L $SERVER -I $SERVER_IP -N -p 139 || failed=`expr $failed + 1`
+
+testit "noninteractive smbclient does not prompt" \
+ test_noninteractive_no_prompt || \
+ failed=`expr $failed + 1`
+
+testit "noninteractive smbclient -l does not prompt" \
+ test_noninteractive_no_prompt -l /tmp || \
+ failed=`expr $failed + 1`
+
+testit "interactive smbclient prompts on stdout" \
+ test_interactive_prompt_stdout || \
+ failed=`expr $failed + 1`
+
+testit "interactive smbclient -l prompts on stdout" \
+ test_interactive_prompt_stdout -l /tmp || \
+ failed=`expr $failed + 1`
+
+testok $0 $failed
diff --git a/source3/script/tests/test_smbtorture_s3.sh b/source3/script/tests/test_smbtorture_s3.sh
new file mode 100755
index 0000000000..acb641b9fb
--- /dev/null
+++ b/source3/script/tests/test_smbtorture_s3.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+# this runs the file serving tests that are expected to pass with samba3
+
+if [ $# -lt 3 ]; then
+cat <<EOF
+Usage: test_smbtorture_s3.sh UNC USERNAME PASSWORD <first> <smbtorture args>
+EOF
+exit 1;
+fi
+
+unc="$1"
+username="$2"
+password="$3"
+start="$4"
+shift 4
+ADDARGS="$*"
+
+incdir=`dirname $0`
+. $incdir/test_functions.sh
+
+tests="FDPASS LOCK1 LOCK2 LOCK3 LOCK4 LOCK5 LOCK6 LOCK7"
+#tests="$tests UNLINK BROWSE ATTR TRANS2 MAXFID TORTURE "
+tests="$tests UNLINK BROWSE ATTR TRANS2 TORTURE "
+tests="$tests OPLOCK1 OPLOCK2 OPLOCK3"
+tests="$tests DIR DIR1 TCON TCONDEV RW1 RW2 RW3"
+tests="$tests OPEN XCOPY RENAME DELETE PROPERTIES W2K"
+tests="$tests TCON2 IOCTL CHKPATH FDSESS LOCAL-SUBSTITUTE"
+
+skipped1="RANDOMIPC NEGNOWAIT NBENCH ERRMAPEXTRACT TRANS2SCAN NTTRANSSCAN"
+skipped2="DENY1 DENY2 OPENATTR CASETABLE EATEST"
+skipped3="MANGLE UTABLE PIPE_NUMBER"
+echo "Skipping the following tests:"
+echo "$skipped1"
+echo "$skipped2"
+echo "$skipped3"
+
+failed=0
+for t in $tests; do
+ if [ ! -z "$start" -a "$start" != $t ]; then
+ continue;
+ fi
+ start=""
+ name="$t"
+ testit "$name" $VALGRIND $BINDIR/smbtorture $unc -U"$username"%"$password" $ADDARGS $t || failed=`expr $failed + 1`
+done
+
+testok $0 $failed
diff --git a/source3/script/tests/test_testparm_s3.sh b/source3/script/tests/test_testparm_s3.sh
new file mode 100755
index 0000000000..0962ca0764
--- /dev/null
+++ b/source3/script/tests/test_testparm_s3.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+
+# Tests for lp_load() via testparm.
+#
+# The main purpose (for now) is to test all the special handlers
+# and the macro expansions.
+
+TEMP_CONFFILE=${LIBDIR}/smb.conf.tmp
+TESTPARM="$VALGRIND ${TESTPARM:-$BINDIR/testparm} --suppress-prompt --skip-logic-checks"
+
+incdir=`dirname $0`
+. $incdir/test_functions.sh
+
+failed=0
+
+test_include_expand_macro()
+{
+ MACRO=$1
+ rm -f ${TEMP_CONFFILE}
+ cat >${TEMP_CONFFILE}<<EOF
+[global]
+ include = ${TEMP_CONFFILE}.%${MACRO}
+EOF
+ ${TESTPARM} ${TEMP_CONFFILE}
+}
+
+test_one_global_option()
+{
+ OPTION=$1
+ rm -f ${TEMP_CONFFILE}
+ cat > ${TEMP_CONFFILE}<<EOF
+[global]
+ ${OPTION}
+EOF
+ ${TESTPARM} ${TEMP_CONFFILE}
+}
+
+test_copy()
+{
+ rm -f ${TEMP_CONFFILE}
+ cat > ${TEMP_CONFFILE}<<EOF
+[share1]
+ path = /tmp
+ read only = no
+
+[share2]
+ copy = share1
+EOF
+ ${TESTPARM} ${TEMP_CONFFILE}
+}
+
+
+testit "netbios name" \
+ test_one_global_option "netbios name = funky" || \
+ failed=`expr ${failed} + 1`
+
+testit "netbios aliases" \
+ test_one_global_option "netbios aliases = funky1 funky2 funky3" || \
+ failed=`expr ${failed} + 1`
+
+testit "netbios scope" \
+ test_one_global_option "netbios scope = abc" || \
+ failed=`expr ${failed} + 1`
+
+testit "workgroup" \
+ test_one_global_option "workgroup = samba" || \
+ failed=`expr ${failed} + 1`
+
+testit "display charset" \
+ test_one_global_option "display charset = UTF8" || \
+ failed=`expr ${failed} + 1`
+
+testit "ldap debug level" \
+ test_one_global_option "ldap debug level = 7" || \
+ failed=`expr ${failed} + 1`
+
+for LETTER in U G D I i L N M R T a d h m v w V ; do
+testit "include with %${LETTER} macro expansion" \
+ test_include_expand_macro "${LETTER}" || \
+ failed=`expr ${failed} + 1`
+done
+
+testit "copy" \
+ test_copy || \
+ failed=`expr ${failed} + 1`
+
+rm -f ${TEMP_CONFFILE}
+
+testok $0 ${failed}
+
diff --git a/source3/script/tests/test_wbinfo_s3.sh b/source3/script/tests/test_wbinfo_s3.sh
new file mode 100755
index 0000000000..e3bf1b9e70
--- /dev/null
+++ b/source3/script/tests/test_wbinfo_s3.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+if [ $# -lt 4 ]; then
+cat <<EOF
+Usage: test_wbinfo_s3.sh DOMAIN SERVER USERNAME PASSWORD <wbinfo args>
+EOF
+exit 1;
+fi
+
+domain="$1"
+server="$2"
+username="$3"
+password="$4"
+shift 4
+ADDARGS="$*"
+
+incdir=`dirname $0`
+. $incdir/test_functions.sh
+
+OLDIFS=$IFS;
+
+tests="--ping"
+tests="$tests:--separator"
+tests="$tests:--own-domain"
+tests="$tests:--all-domains"
+tests="$tests:--trusted-domains"
+tests="$tests:--domain-info=BUILTIN"
+tests="$tests:--domain-info=$domain"
+tests="$tests:--online-status"
+tests="$tests:--online-status --domain=BUILTIN"
+tests="$tests:--online-status --domain=$domain"
+#Didn't pass yet# tests="$tests:--domain-users"
+tests="$tests:--domain-groups"
+tests="$tests:--name-to-sid=$username"
+#Didn't pass yet# tests="$tests:--user-info=$username"
+tests="$tests:--user-groups=$username"
+
+failed=0
+
+OLDIFS=$IFS
+NEWIFS=$':'
+IFS=$NEWIFS
+for t in $tests; do
+ IFS=$OLDIFS
+ testit "wbinfo $t" $VALGRIND $BINDIR/wbinfo $CONFIGURATION $ADDARGS $t || failed=`expr $failed + 1`
+ IFS=$NEWIFS
+done
+IFS=$OLDIFS
+
+testok $0 $failed
diff --git a/source3/script/tests/tests_all.sh b/source3/script/tests/tests_all.sh
new file mode 100755
index 0000000000..2b46da0e77
--- /dev/null
+++ b/source3/script/tests/tests_all.sh
@@ -0,0 +1,94 @@
+local_s3() {
+ echo "RUNNING TESTS local_s3"
+ $SCRIPTDIR/test_local_s3.sh \
+ || failed=`expr $failed + $?`
+}
+
+smbtorture_s3() {
+ echo "RUNNING TESTS smbtorture_s3"
+ $SCRIPTDIR/test_smbtorture_s3.sh \
+ //$SERVER_IP/tmp $USERNAME $PASSWORD "" \
+ || failed=`expr $failed + $?`
+}
+
+smbtorture_s3_encrypted() {
+ echo "RUNNING TESTS smbtorture_s3_encrypted"
+ $SCRIPTDIR/test_smbtorture_s3.sh \
+ //$SERVER_IP/tmp $USERNAME $PASSWORD "" "-e" \
+ || failed=`expr $failed + $?`
+}
+
+smbclient_s3() {
+ echo "RUNNING TESTS smbclient_s3"
+ $SCRIPTDIR/test_smbclient_s3.sh $SERVER $SERVER_IP \
+ || failed=`expr $failed + $?`
+}
+
+smbclient_s3_encrypted() {
+ echo "RUNNING TESTS smbclient_s3_encrypted"
+ $SCRIPTDIR/test_smbclient_s3.sh $SERVER $SERVER_IP "-e" \
+ || failed=`expr $failed + $?`
+}
+
+wbinfo_s3() {
+ echo "RUNNING TESTS wbinfo_s3"
+ $SCRIPTDIR/test_wbinfo_s3.sh $WORKGROUP $SERVER $USERNAME $PASSWORD \
+ || failed=`expr $failed + $?`
+}
+
+ntlm_auth_s3() {
+ echo "RUNNING TESTS ntlm_auth_s3"
+ $SCRIPTDIR/test_ntlm_auth_s3.sh \
+ || failed=`expr $failed + $?`
+}
+
+net_s3() {
+ echo "RUNNING TESTS net_s3"
+ $SCRIPTDIR/test_net_s3.sh \
+ || failed=`expr $failed + $?`
+}
+
+testparm_s3() {
+ echo "RUNNING TESTS testparm_s3"
+ $SCRIPTDIR/test_testparm_s3.sh \
+ || failed=`expr $failed + $?`
+}
+
+posix_s3() {
+ echo "RUNNING TESTS posix_s3"
+ eval "$LIB_PATH_VAR="\$SAMBA4SHAREDDIR:\$$LIB_PATH_VAR"; export $LIB_PATH_VAR"
+ eval echo "$LIB_PATH_VAR=\$$LIB_PATH_VAR"
+ if [ -x "$SMBTORTURE4" ]; then
+ SMBTORTURE4VERSION=`$SMBTORTURE4 --version`
+ fi
+ if [ -n "$SMBTORTURE4" -a -n "$SMBTORTURE4VERSION" ];then
+ echo "Running Tests with Samba4's smbtorture"
+ echo $SMBTORTURE4VERSION
+ $SCRIPTDIR/test_posix_s3.sh \
+ //$SERVER_IP/tmp $USERNAME $PASSWORD "" \
+ || failed=`expr $failed + $?`
+ else
+ echo "Skip Tests with Samba4's smbtorture"
+ echo "Try to compile with --with-smbtorture4-path=PATH to enable"
+ fi
+}
+
+failed=0
+
+if test "x$TESTS" = "x" ; then
+ local_s3
+ smbtorture_s3
+ smbtorture_s3_encrypted
+ smbclient_s3
+ smbclient_s3_encrypted
+ wbinfo_s3
+ ntlm_auth_s3
+ net_s3
+ testparm_s3
+ posix_s3
+else
+ for THIS_TEST in $TESTS; do
+ $THIS_TEST
+ done
+fi
+
diff --git a/source3/script/tests/tests_smbclient_s3.sh b/source3/script/tests/tests_smbclient_s3.sh
new file mode 100644
index 0000000000..d48a692d4b
--- /dev/null
+++ b/source3/script/tests/tests_smbclient_s3.sh
@@ -0,0 +1 @@
+. $SCRIPTDIR/test_smbclient_s3.sh $SERVER $SERVER_IP
diff --git a/source3/script/tests/timelimit.c b/source3/script/tests/timelimit.c
new file mode 100644
index 0000000000..886256cb37
--- /dev/null
+++ b/source3/script/tests/timelimit.c
@@ -0,0 +1,102 @@
+/* run a command with a limited timeout
+ tridge@samba.org, June 2005
+ metze@samba.org, March 2006
+
+ attempt to be as portable as possible (fighting posix all the way)
+*/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+static pid_t child_pid;
+
+static void usage(void)
+{
+ printf("usage: timelimit <time> <command>\n");
+ printf(" SIGUSR1 - passes SIGTERM to command's process group\n");
+ printf(" SIGALRM - passes SIGTERM to command's process group\n");
+ printf(" after 5s SIGKILL will be passed and exit(1)\n");
+ printf(" SIGTERM - passes SIGTERM to command's process group\n");
+ printf(" after 1s SIGKILL will be passed and exit(1)\n");
+}
+
+static void sig_alrm_kill(int sig)
+{
+ fprintf(stderr, "\nMaximum time expired in timelimit - killing\n");
+ kill(-child_pid, SIGKILL);
+ exit(1);
+}
+
+static void sig_alrm_term(int sig)
+{
+ kill(-child_pid, SIGTERM);
+ alarm(5);
+ signal(SIGALRM, sig_alrm_kill);
+}
+
+static void sig_term(int sig)
+{
+ kill(-child_pid, SIGTERM);
+ alarm(1);
+ signal(SIGALRM, sig_alrm_kill);
+}
+
+static void sig_usr1(int sig)
+{
+ kill(-child_pid, SIGTERM);
+}
+
+static void new_process_group(void)
+{
+ if (setpgid(0,0) == -1) {
+ perror("setpgid");
+ exit(1);
+ }
+}
+
+
+int main(int argc, char *argv[])
+{
+ int maxtime, ret=1;
+
+ if (argc < 3) {
+ usage();
+ exit(1);
+ }
+
+ maxtime = atoi(argv[1]);
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ new_process_group();
+ execvp(argv[2], argv+2);
+ perror(argv[2]);
+ exit(1);
+ }
+
+ signal(SIGTERM, sig_term);
+ signal(SIGINT, sig_term);
+ signal(SIGQUIT, sig_term);
+ signal(SIGUSR1, sig_usr1);
+ signal(SIGALRM, sig_alrm_term);
+ alarm(maxtime);
+
+ do {
+ int status;
+ pid_t pid = wait(&status);
+ if (pid != -1) {
+ ret = WEXITSTATUS(status);
+ } else if (errno == ECHILD) {
+ break;
+ }
+ } while (1);
+
+ kill(-child_pid, SIGKILL);
+
+ exit(ret);
+}
diff --git a/source3/script/uninstallbin.sh.in b/source3/script/uninstallbin.sh.in
new file mode 100755
index 0000000000..8064db8d95
--- /dev/null
+++ b/source3/script/uninstallbin.sh.in
@@ -0,0 +1,41 @@
+#!/bin/sh
+#4 July 96 Dan.Shearer@UniSA.edu.au
+
+INSTALLPERMS=$1
+DESTDIR=$2
+prefix=`echo $3 | sed 's/\/\//\//g'`
+BINDIR=`echo $4 | sed 's/\/\//\//g'`
+SBINDIR=@sbindir@
+shift
+shift
+shift
+shift
+
+if [ ! -d $DESTDIR/$BINDIR ]; then
+ echo "Directory $DESTDIR/$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 $DESTDIR/$BINDIR/$p2 ]; then
+ echo "Removing $DESTDIR/$BINDIR/$p2 "
+ rm -f $DESTDIR/$BINDIR/$p2
+ if [ -f $DESTDIR/$BINDIR/$p2 ]; then
+ echo "Cannot remove $DESTDIR/$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, modules 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/source3/script/uninstalldat.sh b/source3/script/uninstalldat.sh
new file mode 120000
index 0000000000..656142745c
--- /dev/null
+++ b/source3/script/uninstalldat.sh
@@ -0,0 +1 @@
+installdat.sh \ No newline at end of file
diff --git a/source3/script/uninstallman.sh b/source3/script/uninstallman.sh
new file mode 100755
index 0000000000..0fea11cd1b
--- /dev/null
+++ b/source3/script/uninstallman.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+#4 July 96 Dan.Shearer@UniSA.edu.au
+#
+# 13 Aug 2001 Rafal Szczesniak <mimir@spin.ict.pwr.wroc.pl>
+# modified to accomodate international man pages (inspired
+# by Japanese edition's approach)
+
+
+MANDIR=`echo $1 | sed 's/\/\//\//g'`
+SRCDIR=$2
+langs=$3
+
+for lang in $langs; do
+ echo Uninstalling \"$lang\" man pages from $MANDIR/$lang
+
+ for sect in 1 5 7 8 ; do
+ for m in $MANDIR/$lang/man$sect ; do
+ for s in $SRCDIR/../docs/manpages/$lang/*$sect; do
+ FNAME=$m/`basename $s`
+ if test -f $FNAME; then
+ echo Deleting $FNAME
+ rm -f $FNAME
+ test -f $FNAME && echo Cannot remove $FNAME... does $USER have privileges?
+ fi
+ done
+ done
+ done
+done
+
+cat << EOF
+======================================================================
+The man pages have been uninstalled. You may install them again using
+the command "make installman" or make "install" to install binaries,
+man pages and shell scripts.
+======================================================================
+EOF
+exit 0
diff --git a/source3/script/uninstallmodules.sh b/source3/script/uninstallmodules.sh
new file mode 100755
index 0000000000..fc80565cb5
--- /dev/null
+++ b/source3/script/uninstallmodules.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+#4 July 96 Dan.Shearer@UniSA.edu.au
+
+INSTALLPERMS=$1
+DESTDIR=$2
+prefix=`echo $3 | sed 's/\/\//\//g'`
+LIBDIR=`echo $4 | sed 's/\/\//\//g'`
+shift
+shift
+shift
+shift
+
+if [ ! -d $DESTDIR/$LIBDIR ]; then
+ echo "Directory $DESTDIR/$LIBDIR does not exist! "
+ echo "Do a "make installmodules" or "make install" first. "
+ exit 1
+fi
+
+for p in $*; do
+ p2=`basename $p`
+ if [ -f $DESTDIR/$LIBDIR/$p2 ]; then
+ echo "Removing $DESTDIR/$LIBDIR/$p2 "
+ rm -f $DESTDIR/$LIBDIR/$p2
+ if [ -f $DESTDIR/$LIBDIR/$p2 ]; then
+ echo "Cannot remove $DESTDIR/$LIBDIR/$p2 ... does $USER have privileges? "
+ fi
+ fi
+done
+
+
+cat << EOF
+======================================================================
+The modules have been uninstalled. You may restore the modules using
+the command "make installmodules" or "make install" to install
+binaries, modules, man pages and shell scripts.
+======================================================================
+EOF
+
+exit 0
diff --git a/source3/script/uninstallmsg.sh b/source3/script/uninstallmsg.sh
new file mode 120000
index 0000000000..c108fa4416
--- /dev/null
+++ b/source3/script/uninstallmsg.sh
@@ -0,0 +1 @@
+installmsg.sh \ No newline at end of file
diff --git a/source3/script/uninstallscripts.sh b/source3/script/uninstallscripts.sh
new file mode 100755
index 0000000000..cf7fd71999
--- /dev/null
+++ b/source3/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=`echo $2 | sed 's/\/\//\//g'`
+
+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/source3/script/uninstallswat.sh b/source3/script/uninstallswat.sh
new file mode 120000
index 0000000000..0dffe646f0
--- /dev/null
+++ b/source3/script/uninstallswat.sh
@@ -0,0 +1 @@
+installswat.sh \ No newline at end of file
diff --git a/source3/script/updatesmbpasswd.sh b/source3/script/updatesmbpasswd.sh
new file mode 100755
index 0000000000..1d7e0d7332
--- /dev/null
+++ b/source3/script/updatesmbpasswd.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+nawk 'BEGIN {FS=":"}
+{
+ if( $0 ~ "^#" ) {
+ print $0
+ } else if( (length($4) == 32) && (($4 ~ "^[0-9A-F]*$") || ($4 ~ "^[X]*$") || ( $4 ~ "^[*]*$"))) {
+ print $0
+ } else {
+ printf( "%s:%s:%s:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:", $1, $2, $3);
+ for(i = 4; i <= NF; i++)
+ printf("%s:", $i)
+ printf("\n")
+ }
+}'
diff --git a/source3/services/services_db.c b/source3/services/services_db.c
new file mode 100644
index 0000000000..49761c3233
--- /dev/null
+++ b/source3/services/services_db.c
@@ -0,0 +1,746 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Service Control API Implementation
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005.
+ * Largely Rewritten by:
+ * Copyright (C) Gerald (Jerry) Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+struct rcinit_file_information {
+ char *description;
+};
+
+struct service_display_info {
+ const char *servicename;
+ const char *daemon;
+ const char *dispname;
+ const char *description;
+};
+
+struct service_display_info builtin_svcs[] = {
+ { "Spooler", "smbd", "Print Spooler", "Internal service for spooling files to print devices" },
+ { "NETLOGON", "smbd", "Net Logon", "File service providing access to policy and profile data (not remotely manageable)" },
+ { "RemoteRegistry", "smbd", "Remote Registry Service", "Internal service providing remote access to "
+ "the Samba registry" },
+ { "WINS", "nmbd", "Windows Internet Name Service (WINS)", "Internal service providing a "
+ "NetBIOS point-to-point name server (not remotely manageable)" },
+ { NULL, NULL, NULL, NULL }
+};
+
+struct service_display_info common_unix_svcs[] = {
+ { "cups", NULL, "Common Unix Printing System","Provides unified printing support for all operating systems" },
+ { "postfix", NULL, "Internet Mail Service", "Provides support for sending and receiving electonic mail" },
+ { "sendmail", NULL, "Internet Mail Service", "Provides support for sending and receiving electonic mail" },
+ { "portmap", NULL, "TCP Port to RPC PortMapper",NULL },
+ { "xinetd", NULL, "Internet Meta-Daemon", NULL },
+ { "inet", NULL, "Internet Meta-Daemon", NULL },
+ { "xntpd", NULL, "Network Time Service", NULL },
+ { "ntpd", NULL, "Network Time Service", NULL },
+ { "lpd", NULL, "BSD Print Spooler", NULL },
+ { "nfsserver", NULL, "Network File Service", NULL },
+ { "cron", NULL, "Scheduling Service", NULL },
+ { "at", NULL, "Scheduling Service", NULL },
+ { "nscd", NULL, "Name Service Cache Daemon", NULL },
+ { "slapd", NULL, "LDAP Directory Service", NULL },
+ { "ldap", NULL, "LDAP DIrectory Service", NULL },
+ { "ypbind", NULL, "NIS Directory Service", NULL },
+ { "courier-imap", NULL, "IMAP4 Mail Service", NULL },
+ { "courier-pop3", NULL, "POP3 Mail Service", NULL },
+ { "named", NULL, "Domain Name Service", NULL },
+ { "bind", NULL, "Domain Name Service", NULL },
+ { "httpd", NULL, "HTTP Server", NULL },
+ { "apache", NULL, "HTTP Server", "Provides s highly scalable and flexible web server "
+ "capable of implementing various protocols incluing "
+ "but not limited to HTTP" },
+ { "autofs", NULL, "Automounter", NULL },
+ { "squid", NULL, "Web Cache Proxy ", NULL },
+ { "perfcountd", NULL, "Performance Monitoring Daemon", NULL },
+ { "pgsql", NULL, "PgSQL Database Server", "Provides service for SQL database from Postgresql.org" },
+ { "arpwatch", NULL, "ARP Tables watcher", "Provides service for monitoring ARP tables for changes" },
+ { "dhcpd", NULL, "DHCP Server", "Provides service for dynamic host configuration and IP assignment" },
+ { "nwserv", NULL, "NetWare Server Emulator", "Provides service for emulating Novell NetWare 3.12 server" },
+ { "proftpd", NULL, "Professional FTP Server", "Provides high configurable service for FTP connection and "
+ "file transferring" },
+ { "ssh2", NULL, "SSH Secure Shell", "Provides service for secure connection for remote administration" },
+ { "sshd", NULL, "SSH Secure Shell", "Provides service for secure connection for remote administration" },
+ { NULL, NULL, NULL, NULL }
+};
+
+
+/********************************************************************
+********************************************************************/
+
+static SEC_DESC* construct_service_sd( TALLOC_CTX *ctx )
+{
+ SEC_ACE ace[4];
+ SEC_ACCESS mask;
+ size_t i = 0;
+ SEC_DESC *sd;
+ SEC_ACL *acl;
+ size_t sd_size;
+
+ /* basic access for Everyone */
+
+ init_sec_access(&mask, SERVICE_READ_ACCESS );
+ init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ init_sec_access(&mask,SERVICE_EXECUTE_ACCESS );
+ init_sec_ace(&ace[i++], &global_sid_Builtin_Power_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ init_sec_access(&mask,SERVICE_ALL_ACCESS );
+ init_sec_ace(&ace[i++], &global_sid_Builtin_Server_Operators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+ init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ /* create the security descriptor */
+
+ if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
+ return NULL;
+
+ if ( !(sd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
+ SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL,
+ acl, &sd_size)) )
+ return NULL;
+
+ return sd;
+}
+
+/********************************************************************
+ This is where we do the dirty work of filling in things like the
+ Display name, Description, etc...
+********************************************************************/
+
+static char *get_common_service_dispname( const char *servicename )
+{
+ int i;
+
+ for ( i=0; common_unix_svcs[i].servicename; i++ ) {
+ if (strequal(servicename, common_unix_svcs[i].servicename)) {
+ char *dispname;
+ if (asprintf(&dispname,
+ "%s (%s)",
+ common_unix_svcs[i].dispname,
+ common_unix_svcs[i].servicename) < 0) {
+ return NULL;
+ }
+ return dispname;
+ }
+ }
+
+ return SMB_STRDUP(servicename );
+}
+
+/********************************************************************
+********************************************************************/
+
+static char *cleanup_string( const char *string )
+{
+ char *clean = NULL;
+ char *begin, *end;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ clean = talloc_strdup(ctx, string);
+ if (!clean) {
+ return NULL;
+ }
+ begin = clean;
+
+ /* trim any beginning whilespace */
+
+ while (isspace(*begin)) {
+ begin++;
+ }
+
+ if (*begin == '\0') {
+ return NULL;
+ }
+
+ /* trim any trailing whitespace or carriage returns.
+ Start at the end and move backwards */
+
+ end = begin + strlen(begin) - 1;
+
+ while ( isspace(*end) || *end=='\n' || *end=='\r' ) {
+ *end = '\0';
+ end--;
+ }
+
+ return begin;
+}
+
+/********************************************************************
+********************************************************************/
+
+static bool read_init_file( const char *servicename, struct rcinit_file_information **service_info )
+{
+ struct rcinit_file_information *info;
+ char *filepath = NULL;
+ char str[1024];
+ XFILE *f;
+ char *p;
+
+ if ( !(info = TALLOC_ZERO_P( NULL, struct rcinit_file_information ) ) )
+ return False;
+
+ /* attempt the file open */
+
+ filepath = talloc_asprintf(info, "%s/%s/%s", get_dyn_MODULESDIR(),
+ SVCCTL_SCRIPT_DIR, servicename);
+ if (!filepath) {
+ TALLOC_FREE(info);
+ return false;
+ }
+ if (!(f = x_fopen( filepath, O_RDONLY, 0 ))) {
+ DEBUG(0,("read_init_file: failed to open [%s]\n", filepath));
+ TALLOC_FREE(info);
+ return false;
+ }
+
+ while ( (x_fgets( str, sizeof(str)-1, f )) != NULL ) {
+ /* ignore everything that is not a full line
+ comment starting with a '#' */
+
+ if ( str[0] != '#' )
+ continue;
+
+ /* Look for a line like '^#.*Description:' */
+
+ if ( (p = strstr( str, "Description:" )) != NULL ) {
+ char *desc;
+
+ p += strlen( "Description:" ) + 1;
+ if ( !p )
+ break;
+
+ if ( (desc = cleanup_string(p)) != NULL )
+ info->description = talloc_strdup( info, desc );
+ }
+ }
+
+ x_fclose( f );
+
+ if ( !info->description )
+ info->description = talloc_strdup( info, "External Unix Service" );
+
+ *service_info = info;
+ TALLOC_FREE(filepath);
+
+ return True;
+}
+
+/********************************************************************
+ This is where we do the dirty work of filling in things like the
+ Display name, Description, etc...
+********************************************************************/
+
+static void fill_service_values( const char *name, REGVAL_CTR *values )
+{
+ UNISTR2 data, dname, ipath, description;
+ uint32 dword;
+ int i;
+
+ /* These values are hardcoded in all QueryServiceConfig() replies.
+ I'm just storing them here for cosmetic purposes */
+
+ dword = SVCCTL_AUTO_START;
+ regval_ctr_addvalue( values, "Start", REG_DWORD, (char*)&dword, sizeof(uint32));
+
+ dword = SVCCTL_WIN32_OWN_PROC;
+ regval_ctr_addvalue( values, "Type", REG_DWORD, (char*)&dword, sizeof(uint32));
+
+ dword = SVCCTL_SVC_ERROR_NORMAL;
+ regval_ctr_addvalue( values, "ErrorControl", REG_DWORD, (char*)&dword, sizeof(uint32));
+
+ /* everything runs as LocalSystem */
+
+ init_unistr2( &data, "LocalSystem", UNI_STR_TERMINATE );
+ regval_ctr_addvalue( values, "ObjectName", REG_SZ, (char*)data.buffer, data.uni_str_len*2);
+
+ /* special considerations for internal services and the DisplayName value */
+
+ for ( i=0; builtin_svcs[i].servicename; i++ ) {
+ if ( strequal( name, builtin_svcs[i].servicename ) ) {
+ char *pstr = NULL;
+ if (asprintf(&pstr, "%s/%s/%s",
+ get_dyn_MODULESDIR(), SVCCTL_SCRIPT_DIR,
+ builtin_svcs[i].daemon) > 0) {
+ init_unistr2( &ipath, pstr, UNI_STR_TERMINATE );
+ SAFE_FREE(pstr);
+ } else {
+ init_unistr2( &ipath, "", UNI_STR_TERMINATE );
+ }
+ init_unistr2( &description, builtin_svcs[i].description, UNI_STR_TERMINATE );
+ init_unistr2( &dname, builtin_svcs[i].dispname, UNI_STR_TERMINATE );
+ break;
+ }
+ }
+
+ /* default to an external service if we haven't found a match */
+
+ if ( builtin_svcs[i].servicename == NULL ) {
+ char *pstr = NULL;
+ char *dispname = NULL;
+ struct rcinit_file_information *init_info = NULL;
+
+ if (asprintf(&pstr, "%s/%s/%s",get_dyn_MODULESDIR(),
+ SVCCTL_SCRIPT_DIR, name) > 0) {
+ init_unistr2( &ipath, pstr, UNI_STR_TERMINATE );
+ SAFE_FREE(pstr);
+ } else {
+ init_unistr2( &ipath, "", UNI_STR_TERMINATE );
+ }
+
+ /* lookup common unix display names */
+ dispname = get_common_service_dispname(name);
+ init_unistr2( &dname, dispname ? dispname : "", UNI_STR_TERMINATE );
+ SAFE_FREE(dispname);
+
+ /* get info from init file itself */
+ if ( read_init_file( name, &init_info ) ) {
+ init_unistr2( &description, init_info->description, UNI_STR_TERMINATE );
+ TALLOC_FREE( init_info );
+ }
+ else {
+ init_unistr2( &description, "External Unix Service", UNI_STR_TERMINATE );
+ }
+ }
+
+ /* add the new values */
+
+ regval_ctr_addvalue( values, "DisplayName", REG_SZ, (char*)dname.buffer, dname.uni_str_len*2);
+ regval_ctr_addvalue( values, "ImagePath", REG_SZ, (char*)ipath.buffer, ipath.uni_str_len*2);
+ regval_ctr_addvalue( values, "Description", REG_SZ, (char*)description.buffer, description.uni_str_len*2);
+
+ return;
+}
+
+/********************************************************************
+********************************************************************/
+
+static void add_new_svc_name( REGISTRY_KEY *key_parent, REGSUBKEY_CTR *subkeys,
+ const char *name )
+{
+ REGISTRY_KEY *key_service, *key_secdesc;
+ WERROR wresult;
+ char *path = NULL;
+ REGVAL_CTR *values;
+ REGSUBKEY_CTR *svc_subkeys;
+ SEC_DESC *sd;
+ DATA_BLOB sd_blob;
+ NTSTATUS status;
+
+ /* add to the list and create the subkey path */
+
+ regsubkey_ctr_addkey( subkeys, name );
+ store_reg_keys( key_parent, subkeys );
+
+ /* open the new service key */
+
+ if (asprintf(&path, "%s\\%s", KEY_SERVICES, name) < 0) {
+ return;
+ }
+ wresult = regkey_open_internal( NULL, &key_service, path,
+ get_root_nt_token(), REG_KEY_ALL );
+ if ( !W_ERROR_IS_OK(wresult) ) {
+ DEBUG(0,("add_new_svc_name: key lookup failed! [%s] (%s)\n",
+ path, dos_errstr(wresult)));
+ SAFE_FREE(path);
+ return;
+ }
+ SAFE_FREE(path);
+
+ /* add the 'Security' key */
+
+ if ( !(svc_subkeys = TALLOC_ZERO_P( key_service, REGSUBKEY_CTR )) ) {
+ DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
+ TALLOC_FREE( key_service );
+ return;
+ }
+
+ fetch_reg_keys( key_service, svc_subkeys );
+ regsubkey_ctr_addkey( svc_subkeys, "Security" );
+ store_reg_keys( key_service, svc_subkeys );
+
+ /* now for the service values */
+
+ if ( !(values = TALLOC_ZERO_P( key_service, REGVAL_CTR )) ) {
+ DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
+ TALLOC_FREE( key_service );
+ return;
+ }
+
+ fill_service_values( name, values );
+ store_reg_values( key_service, values );
+
+ /* cleanup the service key*/
+
+ TALLOC_FREE( key_service );
+
+ /* now add the security descriptor */
+
+ if (asprintf(&path, "%s\\%s\\%s", KEY_SERVICES, name, "Security") < 0) {
+ return;
+ }
+ wresult = regkey_open_internal( NULL, &key_secdesc, path,
+ get_root_nt_token(), REG_KEY_ALL );
+ if ( !W_ERROR_IS_OK(wresult) ) {
+ DEBUG(0,("add_new_svc_name: key lookup failed! [%s] (%s)\n",
+ path, dos_errstr(wresult)));
+ TALLOC_FREE( key_secdesc );
+ SAFE_FREE(path);
+ return;
+ }
+ SAFE_FREE(path);
+
+ if ( !(values = TALLOC_ZERO_P( key_secdesc, REGVAL_CTR )) ) {
+ DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
+ TALLOC_FREE( key_secdesc );
+ return;
+ }
+
+ if ( !(sd = construct_service_sd(key_secdesc)) ) {
+ DEBUG(0,("add_new_svc_name: Failed to create default sec_desc!\n"));
+ TALLOC_FREE( key_secdesc );
+ return;
+ }
+
+ status = marshall_sec_desc(key_secdesc, sd, &sd_blob.data,
+ &sd_blob.length);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("marshall_sec_desc failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(key_secdesc);
+ return;
+ }
+
+ regval_ctr_addvalue(values, "Security", REG_BINARY,
+ (const char *)sd_blob.data, sd_blob.length);
+ store_reg_values( key_secdesc, values );
+
+ TALLOC_FREE( key_secdesc );
+
+ return;
+}
+
+/********************************************************************
+********************************************************************/
+
+void svcctl_init_keys( void )
+{
+ const char **service_list = lp_svcctl_list();
+ int i;
+ REGSUBKEY_CTR *subkeys;
+ REGISTRY_KEY *key = NULL;
+ WERROR wresult;
+
+ /* bad mojo here if the lookup failed. Should not happen */
+
+ wresult = regkey_open_internal( NULL, &key, KEY_SERVICES,
+ get_root_nt_token(), REG_KEY_ALL );
+
+ if ( !W_ERROR_IS_OK(wresult) ) {
+ DEBUG(0,("svcctl_init_keys: key lookup failed! (%s)\n",
+ dos_errstr(wresult)));
+ return;
+ }
+
+ /* lookup the available subkeys */
+
+ if ( !(subkeys = TALLOC_ZERO_P( key, REGSUBKEY_CTR )) ) {
+ DEBUG(0,("svcctl_init_keys: talloc() failed!\n"));
+ TALLOC_FREE( key );
+ return;
+ }
+
+ fetch_reg_keys( key, subkeys );
+
+ /* the builtin services exist */
+
+ for ( i=0; builtin_svcs[i].servicename; i++ )
+ add_new_svc_name( key, subkeys, builtin_svcs[i].servicename );
+
+ for ( i=0; service_list && service_list[i]; i++ ) {
+
+ /* only add new services */
+ if ( regsubkey_ctr_key_exists( subkeys, service_list[i] ) )
+ continue;
+
+ /* Add the new service key and initialize the appropriate values */
+
+ add_new_svc_name( key, subkeys, service_list[i] );
+ }
+
+ TALLOC_FREE( key );
+
+ /* initialize the control hooks */
+
+ init_service_op_table();
+
+ return;
+}
+
+/********************************************************************
+ This is where we do the dirty work of filling in things like the
+ Display name, Description, etc...Always return a default secdesc
+ in case of any failure.
+********************************************************************/
+
+SEC_DESC *svcctl_get_secdesc( TALLOC_CTX *ctx, const char *name, NT_USER_TOKEN *token )
+{
+ REGISTRY_KEY *key;
+ REGVAL_CTR *values;
+ REGISTRY_VALUE *val;
+ SEC_DESC *ret_sd = NULL;
+ char *path= NULL;
+ WERROR wresult;
+ NTSTATUS status;
+
+ /* now add the security descriptor */
+
+ if (asprintf(&path, "%s\\%s\\%s", KEY_SERVICES, name, "Security") < 0) {
+ return NULL;
+ }
+ wresult = regkey_open_internal( NULL, &key, path, token,
+ REG_KEY_ALL );
+ if ( !W_ERROR_IS_OK(wresult) ) {
+ DEBUG(0,("svcctl_get_secdesc: key lookup failed! [%s] (%s)\n",
+ path, dos_errstr(wresult)));
+ goto done;
+ }
+
+ if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
+ DEBUG(0,("svcctl_get_secdesc: talloc() failed!\n"));
+ goto done;
+ }
+
+ if (fetch_reg_values( key, values ) == -1) {
+ DEBUG(0, ("Error getting registry values\n"));
+ goto done;
+ }
+
+ if ( !(val = regval_ctr_getvalue( values, "Security" )) ) {
+ goto fallback_to_default_sd;
+ }
+
+ /* stream the service security descriptor */
+
+ status = unmarshall_sec_desc(ctx, regval_data_p(val),
+ regval_size(val), &ret_sd);
+
+ if (NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+fallback_to_default_sd:
+ DEBUG(6, ("svcctl_get_secdesc: constructing default secdesc for "
+ "service [%s]\n", name));
+ ret_sd = construct_service_sd(ctx);
+
+done:
+ SAFE_FREE(path);
+ TALLOC_FREE(key);
+ return ret_sd;
+}
+
+/********************************************************************
+ Wrapper to make storing a Service sd easier
+********************************************************************/
+
+bool svcctl_set_secdesc( TALLOC_CTX *ctx, const char *name, SEC_DESC *sec_desc, NT_USER_TOKEN *token )
+{
+ REGISTRY_KEY *key;
+ WERROR wresult;
+ char *path = NULL;
+ REGVAL_CTR *values;
+ prs_struct ps;
+ bool ret = False;
+
+ /* now add the security descriptor */
+
+ if (asprintf(&path, "%s\\%s\\%s", KEY_SERVICES, name, "Security") < 0) {
+ return false;
+ }
+ wresult = regkey_open_internal( NULL, &key, path, token,
+ REG_KEY_ALL );
+ if ( !W_ERROR_IS_OK(wresult) ) {
+ DEBUG(0,("svcctl_get_secdesc: key lookup failed! [%s] (%s)\n",
+ path, dos_errstr(wresult)));
+ SAFE_FREE(path);
+ return False;
+ }
+ SAFE_FREE(path);
+
+ if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
+ DEBUG(0,("svcctl_set_secdesc: talloc() failed!\n"));
+ TALLOC_FREE( key );
+ return False;
+ }
+
+ /* stream the printer security descriptor */
+
+ if (!prs_init( &ps, RPC_MAX_PDU_FRAG_LEN, key, MARSHALL)) {
+ DEBUG(0,("svcctl_set_secdesc: prs_init() failed!\n"));
+ TALLOC_FREE( key );
+ return False;
+ }
+
+ if ( sec_io_desc("sec_desc", &sec_desc, &ps, 0 ) ) {
+ uint32 offset = prs_offset( &ps );
+ regval_ctr_addvalue( values, "Security", REG_BINARY, prs_data_p(&ps), offset );
+ ret = store_reg_values( key, values );
+ }
+
+ /* cleanup */
+
+ prs_mem_free( &ps );
+ TALLOC_FREE( key);
+
+ return ret;
+}
+
+/********************************************************************
+********************************************************************/
+
+const char *svcctl_lookup_dispname(TALLOC_CTX *ctx, const char *name, NT_USER_TOKEN *token )
+{
+ char *display_name = NULL;
+ REGISTRY_KEY *key = NULL;
+ REGVAL_CTR *values;
+ REGISTRY_VALUE *val;
+ char *path = NULL;
+ WERROR wresult;
+
+ /* now add the security descriptor */
+
+ if (asprintf(&path, "%s\\%s", KEY_SERVICES, name) < 0) {
+ return NULL;
+ }
+ wresult = regkey_open_internal( NULL, &key, path, token,
+ REG_KEY_READ );
+ if ( !W_ERROR_IS_OK(wresult) ) {
+ DEBUG(0,("svcctl_lookup_dispname: key lookup failed! [%s] (%s)\n",
+ path, dos_errstr(wresult)));
+ SAFE_FREE(path);
+ goto fail;
+ }
+ SAFE_FREE(path);
+
+ if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
+ DEBUG(0,("svcctl_lookup_dispname: talloc() failed!\n"));
+ TALLOC_FREE( key );
+ goto fail;
+ }
+
+ fetch_reg_values( key, values );
+
+ if ( !(val = regval_ctr_getvalue( values, "DisplayName" )) )
+ goto fail;
+
+ rpcstr_pull_talloc(ctx, &display_name, regval_data_p(val), regval_size(val), 0 );
+
+ TALLOC_FREE( key );
+
+ return display_name;
+
+fail:
+ /* default to returning the service name */
+ TALLOC_FREE( key );
+ return talloc_strdup(ctx, name);
+}
+
+/********************************************************************
+********************************************************************/
+
+const char *svcctl_lookup_description(TALLOC_CTX *ctx, const char *name, NT_USER_TOKEN *token )
+{
+ char *description = NULL;
+ REGISTRY_KEY *key = NULL;
+ REGVAL_CTR *values;
+ REGISTRY_VALUE *val;
+ char *path = NULL;
+ WERROR wresult;
+
+ /* now add the security descriptor */
+
+ if (asprintf(&path, "%s\\%s", KEY_SERVICES, name) < 0) {
+ return NULL;
+ }
+ wresult = regkey_open_internal( NULL, &key, path, token,
+ REG_KEY_READ );
+ if ( !W_ERROR_IS_OK(wresult) ) {
+ DEBUG(0,("svcctl_lookup_description: key lookup failed! [%s] (%s)\n",
+ path, dos_errstr(wresult)));
+ SAFE_FREE(path);
+ return NULL;
+ }
+ SAFE_FREE(path);
+
+ if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
+ DEBUG(0,("svcctl_lookup_description: talloc() failed!\n"));
+ TALLOC_FREE( key );
+ return NULL;
+ }
+
+ fetch_reg_values( key, values );
+
+ if ( !(val = regval_ctr_getvalue( values, "Description" )) ) {
+ TALLOC_FREE( key );
+ return "Unix Service";
+ }
+ rpcstr_pull_talloc(ctx, &description, regval_data_p(val), regval_size(val), 0 );
+ TALLOC_FREE(key);
+
+ return description;
+}
+
+
+/********************************************************************
+********************************************************************/
+
+REGVAL_CTR *svcctl_fetch_regvalues( const char *name, NT_USER_TOKEN *token )
+{
+ REGISTRY_KEY *key = NULL;
+ REGVAL_CTR *values;
+ char *path = NULL;
+ WERROR wresult;
+
+ /* now add the security descriptor */
+
+ if (asprintf(&path, "%s\\%s", KEY_SERVICES, name) < 0) {
+ return NULL;
+ }
+ wresult = regkey_open_internal( NULL, &key, path, token,
+ REG_KEY_READ );
+ if ( !W_ERROR_IS_OK(wresult) ) {
+ DEBUG(0,("svcctl_fetch_regvalues: key lookup failed! [%s] (%s)\n",
+ path, dos_errstr(wresult)));
+ SAFE_FREE(path);
+ return NULL;
+ }
+ SAFE_FREE(path);
+
+ if ( !(values = TALLOC_ZERO_P( NULL, REGVAL_CTR )) ) {
+ DEBUG(0,("svcctl_fetch_regvalues: talloc() failed!\n"));
+ TALLOC_FREE( key );
+ return NULL;
+ }
+ fetch_reg_values( key, values );
+
+ TALLOC_FREE( key );
+ return values;
+}
diff --git a/source3/services/svc_netlogon.c b/source3/services/svc_netlogon.c
new file mode 100644
index 0000000000..c5a5385cdd
--- /dev/null
+++ b/source3/services/svc_netlogon.c
@@ -0,0 +1,74 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Service Control API Implementation
+ * Copyright (C) Gerald Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/* Implementation for internal netlogon service */
+
+/*********************************************************************
+*********************************************************************/
+
+static WERROR netlogon_status( const char *service, SERVICE_STATUS *service_status )
+{
+ ZERO_STRUCTP( service_status );
+
+ service_status->type = 0x20;
+ service_status->controls_accepted = SVCCTL_ACCEPT_NONE;
+
+ if ( lp_servicenumber("NETLOGON") != -1 ) {
+ service_status->state = SVCCTL_RUNNING;
+ service_status->win32_exit_code = WERR_SERVICE_NEVER_STARTED;
+ }
+ else
+ service_status->state = SVCCTL_STOPPED;
+
+ return WERR_OK;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static WERROR netlogon_stop( const char *service, SERVICE_STATUS *service_status )
+{
+ netlogon_status( service, service_status );
+
+ return WERR_ACCESS_DENIED;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static WERROR netlogon_start( const char *service )
+{
+ if ( lp_servicenumber("NETLOGON") == -1 )
+ return WERR_SERVICE_DISABLED;
+
+ return WERR_ACCESS_DENIED;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+/* struct for svcctl control to manipulate netlogon service */
+
+SERVICE_CONTROL_OPS netlogon_svc_ops = {
+ netlogon_stop,
+ netlogon_start,
+ netlogon_status
+};
diff --git a/source3/services/svc_rcinit.c b/source3/services/svc_rcinit.c
new file mode 100644
index 0000000000..3d9e6673a0
--- /dev/null
+++ b/source3/services/svc_rcinit.c
@@ -0,0 +1,124 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Service Control API Implementation
+ * Copyright (C) Gerald Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/*********************************************************************
+*********************************************************************/
+
+static WERROR rcinit_stop( const char *service, SERVICE_STATUS *status )
+{
+ char *command = NULL;
+ int ret, fd;
+
+ if (asprintf(&command, "%s/%s/%s stop",
+ get_dyn_MODULESDIR(), SVCCTL_SCRIPT_DIR, service) < 0) {
+ return WERR_NOMEM;
+ }
+
+ /* we've already performed the access check when the service was opened */
+
+ become_root();
+ ret = smbrun( command , &fd );
+ unbecome_root();
+
+ DEBUGADD(5, ("rcinit_start: [%s] returned [%d]\n", command, ret));
+ close(fd);
+
+ SAFE_FREE(command);
+
+ ZERO_STRUCTP( status );
+ status->type = 0x0020;
+ status->state = (ret == 0 ) ? 0x0001 : 0x0004;
+ status->controls_accepted = 0x0005;
+
+ return ( ret == 0 ) ? WERR_OK : WERR_ACCESS_DENIED;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static WERROR rcinit_start( const char *service )
+{
+ char *command = NULL;
+ int ret, fd;
+
+ if (asprintf(&command, "%s/%s/%s start",
+ get_dyn_MODULESDIR(), SVCCTL_SCRIPT_DIR, service) < 0) {
+ return WERR_NOMEM;
+ }
+
+ /* we've already performed the access check when the service was opened */
+
+ become_root();
+ ret = smbrun( command , &fd );
+ unbecome_root();
+
+ DEBUGADD(5, ("rcinit_start: [%s] returned [%d]\n", command, ret));
+ close(fd);
+
+ SAFE_FREE(command);
+
+ return ( ret == 0 ) ? WERR_OK : WERR_ACCESS_DENIED;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static WERROR rcinit_status( const char *service, SERVICE_STATUS *status )
+{
+ char *command = NULL;
+ int ret, fd;
+
+ if (asprintf(&command, "%s/%s/%s status",
+ get_dyn_MODULESDIR(), SVCCTL_SCRIPT_DIR, service) < 0) {
+ return WERR_NOMEM;
+ }
+
+ /* we've already performed the access check when the service was opened */
+ /* assume as return code of 0 means that the service is ok. Anything else
+ is STOPPED */
+
+ become_root();
+ ret = smbrun( command , &fd );
+ unbecome_root();
+
+ DEBUGADD(5, ("rcinit_start: [%s] returned [%d]\n", command, ret));
+ close(fd);
+
+ SAFE_FREE(command);
+
+ ZERO_STRUCTP( status );
+ status->type = 0x0020;
+ status->state = (ret == 0 ) ? 0x0004 : 0x0001;
+ status->controls_accepted = 0x0005;
+
+ return WERR_OK;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+/* struct for svcctl control to manipulate rcinit service */
+
+SERVICE_CONTROL_OPS rcinit_svc_ops = {
+ rcinit_stop,
+ rcinit_start,
+ rcinit_status
+};
diff --git a/source3/services/svc_spoolss.c b/source3/services/svc_spoolss.c
new file mode 100644
index 0000000000..9d4113cadf
--- /dev/null
+++ b/source3/services/svc_spoolss.c
@@ -0,0 +1,80 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Service Control API Implementation
+ * Copyright (C) Gerald Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/* Implementation for internal spoolss service */
+
+/*********************************************************************
+*********************************************************************/
+
+static WERROR spoolss_stop( const char *service, SERVICE_STATUS *service_status )
+{
+ ZERO_STRUCTP( service_status );
+
+ lp_set_spoolss_state( SVCCTL_STOPPED );
+
+ service_status->type = 0x110;
+ service_status->state = SVCCTL_STOPPED;
+ service_status->controls_accepted = SVCCTL_ACCEPT_STOP;
+
+ DEBUG(6,("spoolss_stop: spooler stopped (not really)\n"));
+
+ return WERR_OK;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static WERROR spoolss_start( const char *service )
+{
+ /* see if the smb.conf will support this anyways */
+
+ if ( _lp_disable_spoolss() )
+ return WERR_ACCESS_DENIED;
+
+ lp_set_spoolss_state( SVCCTL_RUNNING );
+
+ return WERR_OK;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static WERROR spoolss_status( const char *service, SERVICE_STATUS *service_status )
+{
+ ZERO_STRUCTP( service_status );
+
+ service_status->type = 0x110;
+ service_status->state = lp_get_spoolss_state();
+ service_status->controls_accepted = SVCCTL_ACCEPT_STOP;
+
+ return WERR_OK;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+/* struct for svcctl control to manipulate spoolss service */
+
+SERVICE_CONTROL_OPS spoolss_svc_ops = {
+ spoolss_stop,
+ spoolss_start,
+ spoolss_status
+};
diff --git a/source3/services/svc_winreg.c b/source3/services/svc_winreg.c
new file mode 100644
index 0000000000..09d25f45e4
--- /dev/null
+++ b/source3/services/svc_winreg.c
@@ -0,0 +1,63 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Service Control API Implementation
+ * Copyright (C) Gerald Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/* Implementation for internal winreg service */
+
+/*********************************************************************
+*********************************************************************/
+
+static WERROR winreg_stop( const char *service, SERVICE_STATUS *service_status )
+{
+ return WERR_ACCESS_DENIED;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static WERROR winreg_start( const char *service )
+{
+ return WERR_ACCESS_DENIED;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static WERROR winreg_status( const char *service, SERVICE_STATUS *service_status )
+{
+ ZERO_STRUCTP( service_status );
+
+ service_status->type = 0x20;
+ service_status->controls_accepted = SVCCTL_ACCEPT_NONE;
+ service_status->state = SVCCTL_RUNNING;
+
+ return WERR_OK;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+/* struct for svcctl control to manipulate winreg service */
+
+SERVICE_CONTROL_OPS winreg_svc_ops = {
+ winreg_stop,
+ winreg_start,
+ winreg_status
+};
diff --git a/source3/services/svc_wins.c b/source3/services/svc_wins.c
new file mode 100644
index 0000000000..c9ef5e5b51
--- /dev/null
+++ b/source3/services/svc_wins.c
@@ -0,0 +1,71 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Service Control API Implementation
+ * Copyright (C) Gerald Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/* Implementation for internal wins service */
+
+/*********************************************************************
+*********************************************************************/
+
+static WERROR wins_status( const char *service, SERVICE_STATUS *service_status )
+{
+ ZERO_STRUCTP( service_status );
+
+ service_status->type = 0x10;
+ service_status->controls_accepted = SVCCTL_ACCEPT_NONE;
+
+ if ( lp_wins_support() )
+ service_status->state = SVCCTL_RUNNING;
+ else {
+ service_status->state = SVCCTL_STOPPED;
+ service_status->win32_exit_code = WERR_SERVICE_NEVER_STARTED;
+ }
+
+ return WERR_OK;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static WERROR wins_stop( const char *service, SERVICE_STATUS *service_status )
+{
+ wins_status( service, service_status );
+
+ return WERR_ACCESS_DENIED;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static WERROR wins_start( const char *service )
+{
+ return WERR_ACCESS_DENIED;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+/* struct for svcctl control to manipulate wins service */
+
+SERVICE_CONTROL_OPS wins_svc_ops = {
+ wins_stop,
+ wins_start,
+ wins_status
+};
diff --git a/source3/smbadduser.in b/source3/smbadduser.in
new file mode 100644
index 0000000000..4b9671319a
--- /dev/null
+++ b/source3/smbadduser.in
@@ -0,0 +1,79 @@
+#!/bin/csh
+#
+# smbadduser - Written by Mike Zakharoff
+#
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+LIBDIR=@libdir@
+PRIVATEDIR=@privatedir@
+CONFIGDIR=@configdir@
+
+unalias *
+set path = ($path /usr/bin)
+
+set smbpasswd = $PRIVATEDIR/smbpasswd
+set user_map = $CONFIGDIR/smbusers
+
+#
+# Set to site specific passwd command
+#
+set passwd = "getent 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"
+ /usr/bin/smbpasswd -a -n $unix
+ 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/source3/smbd/aio.c b/source3/smbd/aio.c
new file mode 100644
index 0000000000..74275368bd
--- /dev/null
+++ b/source3/smbd/aio.c
@@ -0,0 +1,832 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ async_io read handling using POSIX async io.
+ Copyright (C) Jeremy Allison 2005.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#if defined(WITH_AIO)
+
+/* The signal we'll use to signify aio done. */
+#ifndef RT_SIGNAL_AIO
+#define RT_SIGNAL_AIO (SIGRTMIN+3)
+#endif
+
+/****************************************************************************
+ The buffer we keep around whilst an aio request is in process.
+*****************************************************************************/
+
+struct aio_extra {
+ struct aio_extra *next, *prev;
+ SMB_STRUCT_AIOCB acb;
+ files_struct *fsp;
+ bool read_req;
+ uint16 mid;
+ char *inbuf;
+ char *outbuf;
+};
+
+static struct aio_extra *aio_list_head;
+
+/****************************************************************************
+ Create the extended aio struct we must keep around for the lifetime
+ of the aio_read call.
+*****************************************************************************/
+
+static struct aio_extra *create_aio_ex_read(files_struct *fsp, size_t buflen,
+ uint16 mid)
+{
+ struct aio_extra *aio_ex = SMB_MALLOC_P(struct aio_extra);
+
+ if (!aio_ex) {
+ return NULL;
+ }
+ ZERO_STRUCTP(aio_ex);
+ /* The output buffer stored in the aio_ex is the start of
+ the smb return buffer. The buffer used in the acb
+ is the start of the reply data portion of that buffer. */
+ aio_ex->outbuf = SMB_MALLOC_ARRAY(char, buflen);
+ if (!aio_ex->outbuf) {
+ SAFE_FREE(aio_ex);
+ return NULL;
+ }
+ DLIST_ADD(aio_list_head, aio_ex);
+ aio_ex->fsp = fsp;
+ aio_ex->read_req = True;
+ aio_ex->mid = mid;
+ return aio_ex;
+}
+
+/****************************************************************************
+ Create the extended aio struct we must keep around for the lifetime
+ of the aio_write call.
+*****************************************************************************/
+
+static struct aio_extra *create_aio_ex_write(files_struct *fsp,
+ size_t inbuflen,
+ size_t outbuflen,
+ uint16 mid)
+{
+ struct aio_extra *aio_ex = SMB_MALLOC_P(struct aio_extra);
+
+ if (!aio_ex) {
+ return NULL;
+ }
+ ZERO_STRUCTP(aio_ex);
+
+ /* We need space for an output reply of outbuflen bytes. */
+ aio_ex->outbuf = SMB_MALLOC_ARRAY(char, outbuflen);
+ if (!aio_ex->outbuf) {
+ SAFE_FREE(aio_ex);
+ return NULL;
+ }
+
+ if (!(aio_ex->inbuf = SMB_MALLOC_ARRAY(char, inbuflen))) {
+ SAFE_FREE(aio_ex->outbuf);
+ SAFE_FREE(aio_ex);
+ return NULL;
+ }
+
+ DLIST_ADD(aio_list_head, aio_ex);
+ aio_ex->fsp = fsp;
+ aio_ex->read_req = False;
+ aio_ex->mid = mid;
+ return aio_ex;
+}
+
+/****************************************************************************
+ Delete the extended aio struct.
+*****************************************************************************/
+
+static void delete_aio_ex(struct aio_extra *aio_ex)
+{
+ DLIST_REMOVE(aio_list_head, aio_ex);
+ SAFE_FREE(aio_ex->inbuf);
+ SAFE_FREE(aio_ex->outbuf);
+ SAFE_FREE(aio_ex);
+}
+
+/****************************************************************************
+ Given the aiocb struct find the extended aio struct containing it.
+*****************************************************************************/
+
+static struct aio_extra *find_aio_ex(uint16 mid)
+{
+ struct aio_extra *p;
+
+ for( p = aio_list_head; p; p = p->next) {
+ if (mid == p->mid) {
+ return p;
+ }
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ We can have these many aio buffers in flight.
+*****************************************************************************/
+
+static int aio_pending_size;
+static sig_atomic_t signals_received;
+static int outstanding_aio_calls;
+static uint16 *aio_pending_array;
+
+/****************************************************************************
+ Signal handler when an aio request completes.
+*****************************************************************************/
+
+void aio_request_done(uint16_t mid)
+{
+ if (signals_received < aio_pending_size) {
+ aio_pending_array[signals_received] = mid;
+ signals_received++;
+ }
+ /* Else signal is lost. */
+}
+
+static void signal_handler(int sig, siginfo_t *info, void *unused)
+{
+ aio_request_done(info->si_value.sival_int);
+ sys_select_signal(RT_SIGNAL_AIO);
+}
+
+/****************************************************************************
+ Is there a signal waiting ?
+*****************************************************************************/
+
+bool aio_finished(void)
+{
+ return (signals_received != 0);
+}
+
+/****************************************************************************
+ Initialize the signal handler for aio read/write.
+*****************************************************************************/
+
+void initialize_async_io_handler(void)
+{
+ struct sigaction act;
+
+ aio_pending_size = lp_maxmux();
+ aio_pending_array = SMB_MALLOC_ARRAY(uint16, aio_pending_size);
+ SMB_ASSERT(aio_pending_array != NULL);
+
+ ZERO_STRUCT(act);
+ act.sa_sigaction = signal_handler;
+ act.sa_flags = SA_SIGINFO;
+ sigemptyset( &act.sa_mask );
+ if (sigaction(RT_SIGNAL_AIO, &act, NULL) != 0) {
+ DEBUG(0,("Failed to setup RT_SIGNAL_AIO handler\n"));
+ }
+
+ /* the signal can start off blocked due to a bug in bash */
+ BlockSignals(False, RT_SIGNAL_AIO);
+}
+
+/****************************************************************************
+ Set up an aio request from a SMBreadX call.
+*****************************************************************************/
+
+bool schedule_aio_read_and_X(connection_struct *conn,
+ struct smb_request *req,
+ files_struct *fsp, SMB_OFF_T startpos,
+ size_t smb_maxcnt)
+{
+ struct aio_extra *aio_ex;
+ SMB_STRUCT_AIOCB *a;
+ size_t bufsize;
+ size_t min_aio_read_size = lp_aio_read_size(SNUM(conn));
+
+ if (fsp->base_fsp != NULL) {
+ /* No AIO on streams yet */
+ DEBUG(10, ("AIO on streams not yet supported\n"));
+ return false;
+ }
+
+ if ((!min_aio_read_size || (smb_maxcnt < min_aio_read_size))
+ && !SMB_VFS_AIO_FORCE(fsp)) {
+ /* Too small a read for aio request. */
+ DEBUG(10,("schedule_aio_read_and_X: read size (%u) too small "
+ "for minimum aio_read of %u\n",
+ (unsigned int)smb_maxcnt,
+ (unsigned int)min_aio_read_size ));
+ return False;
+ }
+
+ /* Only do this on non-chained and non-chaining reads not using the
+ * write cache. */
+ if (chain_size !=0 || (CVAL(req->inbuf,smb_vwv0) != 0xFF)
+ || (lp_write_cache_size(SNUM(conn)) != 0) ) {
+ return False;
+ }
+
+ if (outstanding_aio_calls >= aio_pending_size) {
+ DEBUG(10,("schedule_aio_read_and_X: Already have %d aio "
+ "activities outstanding.\n",
+ outstanding_aio_calls ));
+ return False;
+ }
+
+ /* The following is safe from integer wrap as we've already checked
+ smb_maxcnt is 128k or less. Wct is 12 for read replies */
+
+ bufsize = smb_size + 12 * 2 + smb_maxcnt;
+
+ if ((aio_ex = create_aio_ex_read(fsp, bufsize, req->mid)) == NULL) {
+ DEBUG(10,("schedule_aio_read_and_X: malloc fail.\n"));
+ return False;
+ }
+
+ construct_reply_common((char *)req->inbuf, aio_ex->outbuf);
+ srv_set_message(aio_ex->outbuf, 12, 0, True);
+ SCVAL(aio_ex->outbuf,smb_vwv0,0xFF); /* Never a chained reply. */
+
+ a = &aio_ex->acb;
+
+ /* Now set up the aio record for the read call. */
+
+ a->aio_fildes = fsp->fh->fd;
+ a->aio_buf = smb_buf(aio_ex->outbuf);
+ a->aio_nbytes = smb_maxcnt;
+ a->aio_offset = startpos;
+ a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ a->aio_sigevent.sigev_signo = RT_SIGNAL_AIO;
+ a->aio_sigevent.sigev_value.sival_int = aio_ex->mid;
+
+ become_root();
+ if (SMB_VFS_AIO_READ(fsp,a) == -1) {
+ DEBUG(0,("schedule_aio_read_and_X: aio_read failed. "
+ "Error %s\n", strerror(errno) ));
+ delete_aio_ex(aio_ex);
+ unbecome_root();
+ return False;
+ }
+ unbecome_root();
+
+ DEBUG(10,("schedule_aio_read_and_X: scheduled aio_read for file %s, "
+ "offset %.0f, len = %u (mid = %u)\n",
+ fsp->fsp_name, (double)startpos, (unsigned int)smb_maxcnt,
+ (unsigned int)aio_ex->mid ));
+
+ srv_defer_sign_response(aio_ex->mid);
+ outstanding_aio_calls++;
+ return True;
+}
+
+/****************************************************************************
+ Set up an aio request from a SMBwriteX call.
+*****************************************************************************/
+
+bool schedule_aio_write_and_X(connection_struct *conn,
+ struct smb_request *req,
+ files_struct *fsp, char *data,
+ SMB_OFF_T startpos,
+ size_t numtowrite)
+{
+ struct aio_extra *aio_ex;
+ SMB_STRUCT_AIOCB *a;
+ size_t inbufsize, outbufsize;
+ bool write_through = BITSETW(req->inbuf+smb_vwv7,0);
+ size_t min_aio_write_size = lp_aio_write_size(SNUM(conn));
+
+ if (fsp->base_fsp != NULL) {
+ /* No AIO on streams yet */
+ DEBUG(10, ("AIO on streams not yet supported\n"));
+ return false;
+ }
+
+ if ((!min_aio_write_size || (numtowrite < min_aio_write_size))
+ && !SMB_VFS_AIO_FORCE(fsp)) {
+ /* Too small a write for aio request. */
+ DEBUG(10,("schedule_aio_write_and_X: write size (%u) too "
+ "small for minimum aio_write of %u\n",
+ (unsigned int)numtowrite,
+ (unsigned int)min_aio_write_size ));
+ return False;
+ }
+
+ /* Only do this on non-chained and non-chaining reads not using the
+ * write cache. */
+ if (chain_size !=0 || (CVAL(req->inbuf,smb_vwv0) != 0xFF)
+ || (lp_write_cache_size(SNUM(conn)) != 0) ) {
+ return False;
+ }
+
+ if (outstanding_aio_calls >= aio_pending_size) {
+ DEBUG(3,("schedule_aio_write_and_X: Already have %d aio "
+ "activities outstanding.\n",
+ outstanding_aio_calls ));
+ DEBUG(10,("schedule_aio_write_and_X: failed to schedule "
+ "aio_write for file %s, offset %.0f, len = %u "
+ "(mid = %u)\n",
+ fsp->fsp_name, (double)startpos,
+ (unsigned int)numtowrite,
+ (unsigned int)req->mid ));
+ return False;
+ }
+
+ inbufsize = smb_len(req->inbuf) + 4;
+ reply_outbuf(req, 6, 0);
+ outbufsize = smb_len(req->outbuf) + 4;
+ if (!(aio_ex = create_aio_ex_write(fsp, inbufsize, outbufsize,
+ req->mid))) {
+ DEBUG(0,("schedule_aio_write_and_X: malloc fail.\n"));
+ return False;
+ }
+
+ /* Copy the SMB header already setup in outbuf. */
+ memcpy(aio_ex->inbuf, req->inbuf, inbufsize);
+
+ /* Copy the SMB header already setup in outbuf. */
+ memcpy(aio_ex->outbuf, req->outbuf, outbufsize);
+ TALLOC_FREE(req->outbuf);
+ SCVAL(aio_ex->outbuf,smb_vwv0,0xFF); /* Never a chained reply. */
+
+ a = &aio_ex->acb;
+
+ /* Now set up the aio record for the write call. */
+
+ a->aio_fildes = fsp->fh->fd;
+ a->aio_buf = aio_ex->inbuf + (PTR_DIFF(data, req->inbuf));
+ a->aio_nbytes = numtowrite;
+ a->aio_offset = startpos;
+ a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ a->aio_sigevent.sigev_signo = RT_SIGNAL_AIO;
+ a->aio_sigevent.sigev_value.sival_int = aio_ex->mid;
+
+ become_root();
+ if (SMB_VFS_AIO_WRITE(fsp,a) == -1) {
+ DEBUG(3,("schedule_aio_wrote_and_X: aio_write failed. "
+ "Error %s\n", strerror(errno) ));
+ delete_aio_ex(aio_ex);
+ unbecome_root();
+ return False;
+ }
+ unbecome_root();
+
+ release_level_2_oplocks_on_change(fsp);
+
+ if (!write_through && !lp_syncalways(SNUM(fsp->conn))
+ && fsp->aio_write_behind) {
+ /* Lie to the client and immediately claim we finished the
+ * write. */
+ SSVAL(aio_ex->outbuf,smb_vwv2,numtowrite);
+ SSVAL(aio_ex->outbuf,smb_vwv4,(numtowrite>>16)&1);
+ show_msg(aio_ex->outbuf);
+ if (!srv_send_smb(smbd_server_fd(),aio_ex->outbuf,
+ IS_CONN_ENCRYPTED(fsp->conn))) {
+ exit_server_cleanly("handle_aio_write: srv_send_smb "
+ "failed.");
+ }
+ DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write "
+ "behind for file %s\n", fsp->fsp_name ));
+ } else {
+ srv_defer_sign_response(aio_ex->mid);
+ }
+ outstanding_aio_calls++;
+
+ DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write for file "
+ "%s, offset %.0f, len = %u (mid = %u) "
+ "outstanding_aio_calls = %d\n",
+ fsp->fsp_name, (double)startpos, (unsigned int)numtowrite,
+ (unsigned int)aio_ex->mid, outstanding_aio_calls ));
+
+ return True;
+}
+
+
+/****************************************************************************
+ Complete the read and return the data or error back to the client.
+ Returns errno or zero if all ok.
+*****************************************************************************/
+
+static int handle_aio_read_complete(struct aio_extra *aio_ex)
+{
+ int ret = 0;
+ int outsize;
+ char *outbuf = aio_ex->outbuf;
+ char *data = smb_buf(outbuf);
+ ssize_t nread = SMB_VFS_AIO_RETURN(aio_ex->fsp,&aio_ex->acb);
+
+ if (nread < 0) {
+ /* We're relying here on the fact that if the fd is
+ closed then the aio will complete and aio_return
+ will return an error. Hopefully this is
+ true.... JRA. */
+
+ /* If errno is ECANCELED then don't return anything to the
+ * client. */
+ if (errno == ECANCELED) {
+ srv_cancel_sign_response(aio_ex->mid);
+ return 0;
+ }
+
+ DEBUG( 3,( "handle_aio_read_complete: file %s nread == -1. "
+ "Error = %s\n",
+ aio_ex->fsp->fsp_name, strerror(errno) ));
+
+ ret = errno;
+ ERROR_NT(map_nt_error_from_unix(ret));
+ outsize = srv_set_message(outbuf,0,0,true);
+ } else {
+ outsize = srv_set_message(outbuf,12,nread,False);
+ SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be * -1. */
+ SSVAL(outbuf,smb_vwv5,nread);
+ SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
+ SSVAL(outbuf,smb_vwv7,((nread >> 16) & 1));
+ SSVAL(smb_buf(outbuf),-2,nread);
+
+ aio_ex->fsp->fh->pos = aio_ex->acb.aio_offset + nread;
+ aio_ex->fsp->fh->position_information = aio_ex->fsp->fh->pos;
+
+ DEBUG( 3, ( "handle_aio_read_complete file %s max=%d "
+ "nread=%d\n",
+ aio_ex->fsp->fsp_name,
+ (int)aio_ex->acb.aio_nbytes, (int)nread ) );
+
+ }
+ smb_setlen(outbuf,outsize - 4);
+ show_msg(outbuf);
+ if (!srv_send_smb(smbd_server_fd(),outbuf,
+ IS_CONN_ENCRYPTED(aio_ex->fsp->conn))) {
+ exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
+ "failed.");
+ }
+
+ DEBUG(10,("handle_aio_read_complete: scheduled aio_read completed "
+ "for file %s, offset %.0f, len = %u\n",
+ aio_ex->fsp->fsp_name, (double)aio_ex->acb.aio_offset,
+ (unsigned int)nread ));
+
+ return ret;
+}
+
+/****************************************************************************
+ Complete the write and return the data or error back to the client.
+ Returns errno or zero if all ok.
+*****************************************************************************/
+
+static int handle_aio_write_complete(struct aio_extra *aio_ex)
+{
+ int ret = 0;
+ files_struct *fsp = aio_ex->fsp;
+ char *outbuf = aio_ex->outbuf;
+ ssize_t numtowrite = aio_ex->acb.aio_nbytes;
+ ssize_t nwritten = SMB_VFS_AIO_RETURN(fsp,&aio_ex->acb);
+
+ if (fsp->aio_write_behind) {
+ if (nwritten != numtowrite) {
+ if (nwritten == -1) {
+ DEBUG(5,("handle_aio_write_complete: "
+ "aio_write_behind failed ! File %s "
+ "is corrupt ! Error %s\n",
+ fsp->fsp_name, strerror(errno) ));
+ ret = errno;
+ } else {
+ DEBUG(0,("handle_aio_write_complete: "
+ "aio_write_behind failed ! File %s "
+ "is corrupt ! Wanted %u bytes but "
+ "only wrote %d\n", fsp->fsp_name,
+ (unsigned int)numtowrite,
+ (int)nwritten ));
+ ret = EIO;
+ }
+ } else {
+ DEBUG(10,("handle_aio_write_complete: "
+ "aio_write_behind completed for file %s\n",
+ fsp->fsp_name ));
+ }
+ return 0;
+ }
+
+ /* We don't need outsize or set_message here as we've already set the
+ fixed size length when we set up the aio call. */
+
+ if(nwritten == -1) {
+ DEBUG( 3,( "handle_aio_write: file %s wanted %u bytes. "
+ "nwritten == %d. Error = %s\n",
+ fsp->fsp_name, (unsigned int)numtowrite,
+ (int)nwritten, strerror(errno) ));
+
+ /* If errno is ECANCELED then don't return anything to the
+ * client. */
+ if (errno == ECANCELED) {
+ srv_cancel_sign_response(aio_ex->mid);
+ return 0;
+ }
+
+ ret = errno;
+ ERROR_BOTH(map_nt_error_from_unix(ret), ERRHRD, ERRdiskfull);
+ srv_set_message(outbuf,0,0,true);
+ } else {
+ bool write_through = BITSETW(aio_ex->inbuf+smb_vwv7,0);
+ NTSTATUS status;
+
+ SSVAL(outbuf,smb_vwv2,nwritten);
+ SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1);
+ if (nwritten < (ssize_t)numtowrite) {
+ SCVAL(outbuf,smb_rcls,ERRHRD);
+ SSVAL(outbuf,smb_err,ERRdiskfull);
+ }
+
+ DEBUG(3,("handle_aio_write: fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, (int)numtowrite, (int)nwritten));
+ status = sync_file(fsp->conn,fsp, write_through);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = errno;
+ ERROR_BOTH(map_nt_error_from_unix(ret),
+ ERRHRD, ERRdiskfull);
+ srv_set_message(outbuf,0,0,true);
+ DEBUG(5,("handle_aio_write: sync_file for %s returned %s\n",
+ fsp->fsp_name, nt_errstr(status) ));
+ }
+
+ aio_ex->fsp->fh->pos = aio_ex->acb.aio_offset + nwritten;
+ }
+
+ show_msg(outbuf);
+ if (!srv_send_smb(smbd_server_fd(),outbuf,IS_CONN_ENCRYPTED(fsp->conn))) {
+ exit_server_cleanly("handle_aio_write: srv_send_smb failed.");
+ }
+
+ DEBUG(10,("handle_aio_write_complete: scheduled aio_write completed "
+ "for file %s, offset %.0f, requested %u, written = %u\n",
+ fsp->fsp_name, (double)aio_ex->acb.aio_offset,
+ (unsigned int)numtowrite, (unsigned int)nwritten ));
+
+ return ret;
+}
+
+/****************************************************************************
+ Handle any aio completion. Returns True if finished (and sets *perr if err
+ was non-zero), False if not.
+*****************************************************************************/
+
+static bool handle_aio_completed(struct aio_extra *aio_ex, int *perr)
+{
+ int err;
+
+ /* Ensure the operation has really completed. */
+ if (SMB_VFS_AIO_ERROR(aio_ex->fsp, &aio_ex->acb) == EINPROGRESS) {
+ DEBUG(10,( "handle_aio_completed: operation mid %u still in "
+ "process for file %s\n",
+ aio_ex->mid, aio_ex->fsp->fsp_name ));
+ return False;
+ }
+
+ if (aio_ex->read_req) {
+ err = handle_aio_read_complete(aio_ex);
+ } else {
+ err = handle_aio_write_complete(aio_ex);
+ }
+
+ if (err) {
+ *perr = err; /* Only save non-zero errors. */
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Handle any aio completion inline.
+ Returns non-zero errno if fail or zero if all ok.
+*****************************************************************************/
+
+int process_aio_queue(void)
+{
+ int i;
+ int ret = 0;
+
+ BlockSignals(True, RT_SIGNAL_AIO);
+
+ DEBUG(10,("process_aio_queue: signals_received = %d\n",
+ (int)signals_received));
+ DEBUG(10,("process_aio_queue: outstanding_aio_calls = %d\n",
+ outstanding_aio_calls));
+
+ if (!signals_received) {
+ BlockSignals(False, RT_SIGNAL_AIO);
+ return 0;
+ }
+
+ /* Drain all the complete aio_reads. */
+ for (i = 0; i < signals_received; i++) {
+ uint16 mid = aio_pending_array[i];
+ files_struct *fsp = NULL;
+ struct aio_extra *aio_ex = find_aio_ex(mid);
+
+ if (!aio_ex) {
+ DEBUG(3,("process_aio_queue: Can't find record to "
+ "match mid %u.\n", (unsigned int)mid));
+ srv_cancel_sign_response(mid);
+ continue;
+ }
+
+ fsp = aio_ex->fsp;
+ if (fsp == NULL) {
+ /* file was closed whilst I/O was outstanding. Just
+ * ignore. */
+ DEBUG( 3,( "process_aio_queue: file closed whilst "
+ "aio outstanding.\n"));
+ srv_cancel_sign_response(mid);
+ continue;
+ }
+
+ if (!handle_aio_completed(aio_ex, &ret)) {
+ continue;
+ }
+
+ delete_aio_ex(aio_ex);
+ }
+
+ outstanding_aio_calls -= signals_received;
+ signals_received = 0;
+ BlockSignals(False, RT_SIGNAL_AIO);
+ return ret;
+}
+
+/****************************************************************************
+ We're doing write behind and the client closed the file. Wait up to 30
+ seconds (my arbitrary choice) for the aio to complete. Return 0 if all writes
+ completed, errno to return if not.
+*****************************************************************************/
+
+#define SMB_TIME_FOR_AIO_COMPLETE_WAIT 29
+
+int wait_for_aio_completion(files_struct *fsp)
+{
+ struct aio_extra *aio_ex;
+ const SMB_STRUCT_AIOCB **aiocb_list;
+ int aio_completion_count = 0;
+ time_t start_time = time(NULL);
+ int seconds_left;
+
+ for (seconds_left = SMB_TIME_FOR_AIO_COMPLETE_WAIT;
+ seconds_left >= 0;) {
+ int err = 0;
+ int i;
+ struct timespec ts;
+
+ aio_completion_count = 0;
+ for( aio_ex = aio_list_head; aio_ex; aio_ex = aio_ex->next) {
+ if (aio_ex->fsp == fsp) {
+ aio_completion_count++;
+ }
+ }
+
+ if (!aio_completion_count) {
+ return 0;
+ }
+
+ DEBUG(3,("wait_for_aio_completion: waiting for %d aio events "
+ "to complete.\n", aio_completion_count ));
+
+ aiocb_list = SMB_MALLOC_ARRAY(const SMB_STRUCT_AIOCB *,
+ aio_completion_count);
+ if (!aiocb_list) {
+ return ENOMEM;
+ }
+
+ for( i = 0, aio_ex = aio_list_head;
+ aio_ex;
+ aio_ex = aio_ex->next) {
+ if (aio_ex->fsp == fsp) {
+ aiocb_list[i++] = &aio_ex->acb;
+ }
+ }
+
+ /* Now wait up to seconds_left for completion. */
+ ts.tv_sec = seconds_left;
+ ts.tv_nsec = 0;
+
+ DEBUG(10,("wait_for_aio_completion: %d events, doing a wait "
+ "of %d seconds.\n",
+ aio_completion_count, seconds_left ));
+
+ err = SMB_VFS_AIO_SUSPEND(fsp, aiocb_list,
+ aio_completion_count, &ts);
+
+ DEBUG(10,("wait_for_aio_completion: returned err = %d, "
+ "errno = %s\n", err, strerror(errno) ));
+
+ if (err == -1 && errno == EAGAIN) {
+ DEBUG(0,("wait_for_aio_completion: aio_suspend timed "
+ "out waiting for %d events after a wait of "
+ "%d seconds\n", aio_completion_count,
+ seconds_left));
+ /* Timeout. */
+ cancel_aio_by_fsp(fsp);
+ SAFE_FREE(aiocb_list);
+ return EIO;
+ }
+
+ /* One or more events might have completed - process them if
+ * so. */
+ for( i = 0; i < aio_completion_count; i++) {
+ uint16 mid = aiocb_list[i]->aio_sigevent.sigev_value.sival_int;
+
+ aio_ex = find_aio_ex(mid);
+
+ if (!aio_ex) {
+ DEBUG(0, ("wait_for_aio_completion: mid %u "
+ "doesn't match an aio record\n",
+ (unsigned int)mid ));
+ continue;
+ }
+
+ if (!handle_aio_completed(aio_ex, &err)) {
+ continue;
+ }
+ delete_aio_ex(aio_ex);
+ }
+
+ SAFE_FREE(aiocb_list);
+ seconds_left = SMB_TIME_FOR_AIO_COMPLETE_WAIT
+ - (time(NULL) - start_time);
+ }
+
+ /* We timed out - we don't know why. Return ret if already an error,
+ * else EIO. */
+ DEBUG(10,("wait_for_aio_completion: aio_suspend timed out waiting "
+ "for %d events\n",
+ aio_completion_count));
+
+ return EIO;
+}
+
+/****************************************************************************
+ Cancel any outstanding aio requests. The client doesn't care about the reply.
+*****************************************************************************/
+
+void cancel_aio_by_fsp(files_struct *fsp)
+{
+ struct aio_extra *aio_ex;
+
+ for( aio_ex = aio_list_head; aio_ex; aio_ex = aio_ex->next) {
+ if (aio_ex->fsp == fsp) {
+ /* Don't delete the aio_extra record as we may have
+ completed and don't yet know it. Just do the
+ aio_cancel call and return. */
+ SMB_VFS_AIO_CANCEL(fsp, &aio_ex->acb);
+ aio_ex->fsp = NULL; /* fsp will be closed when we
+ * return. */
+ }
+ }
+}
+
+#else
+bool aio_finished(void)
+{
+ return False;
+}
+
+void initialize_async_io_handler(void)
+{
+}
+
+int process_aio_queue(void)
+{
+ return False;
+}
+
+bool schedule_aio_read_and_X(connection_struct *conn,
+ struct smb_request *req,
+ files_struct *fsp, SMB_OFF_T startpos,
+ size_t smb_maxcnt)
+{
+ return False;
+}
+
+bool schedule_aio_write_and_X(connection_struct *conn,
+ struct smb_request *req,
+ files_struct *fsp, char *data,
+ SMB_OFF_T startpos,
+ size_t numtowrite)
+{
+ return False;
+}
+
+void cancel_aio_by_fsp(files_struct *fsp)
+{
+}
+
+int wait_for_aio_completion(files_struct *fsp)
+{
+ return ENOSYS;
+}
+#endif
diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c
new file mode 100644
index 0000000000..479361a8c1
--- /dev/null
+++ b/source3/smbd/blocking.c
@@ -0,0 +1,931 @@
+/*
+ Unix SMB/CIFS implementation.
+ Blocking Locking functions
+ Copyright (C) Jeremy Allison 1998-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_LOCKING
+
+/****************************************************************************
+ This is the structure to queue to implement blocking locks.
+ notify. It consists of the requesting SMB and the expiry time.
+*****************************************************************************/
+
+typedef struct _blocking_lock_record {
+ struct _blocking_lock_record *next;
+ struct _blocking_lock_record *prev;
+ int com_type;
+ files_struct *fsp;
+ struct timeval expire_time;
+ int lock_num;
+ SMB_BIG_UINT offset;
+ SMB_BIG_UINT count;
+ uint32 lock_pid;
+ uint32 blocking_pid; /* PID that blocks us. */
+ enum brl_flavour lock_flav;
+ enum brl_type lock_type;
+ char *inbuf;
+ int length;
+ bool encrypted;
+} blocking_lock_record;
+
+/* dlink list we store pending lock records on. */
+static blocking_lock_record *blocking_lock_queue;
+
+/* dlink list we move cancelled lock records onto. */
+static blocking_lock_record *blocking_lock_cancelled_queue;
+
+/* The event that makes us process our blocking lock queue */
+static struct timed_event *brl_timeout;
+
+/****************************************************************************
+ Destructor for the above structure.
+****************************************************************************/
+
+static void free_blocking_lock_record(blocking_lock_record *blr)
+{
+ SAFE_FREE(blr->inbuf);
+ SAFE_FREE(blr);
+}
+
+/****************************************************************************
+ Determine if this is a secondary element of a chained SMB.
+ **************************************************************************/
+
+static bool in_chained_smb(void)
+{
+ return (chain_size != 0);
+}
+
+static void received_unlock_msg(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data);
+static void process_blocking_lock_queue(void);
+
+static void brl_timeout_fn(struct event_context *event_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ SMB_ASSERT(brl_timeout == te);
+ TALLOC_FREE(brl_timeout);
+
+ change_to_root_user(); /* TODO: Possibly run all timed events as
+ * root */
+
+ process_blocking_lock_queue();
+}
+
+/****************************************************************************
+ After a change to blocking_lock_queue, recalculate the timed_event for the
+ next processing.
+****************************************************************************/
+
+static bool recalc_brl_timeout(void)
+{
+ blocking_lock_record *brl;
+ struct timeval next_timeout;
+
+ TALLOC_FREE(brl_timeout);
+
+ next_timeout = timeval_zero();
+
+ for (brl = blocking_lock_queue; brl; brl = brl->next) {
+ if (timeval_is_zero(&brl->expire_time)) {
+ /*
+ * If we're blocked on pid 0xFFFFFFFF this is
+ * a POSIX lock, so calculate a timeout of
+ * 10 seconds into the future.
+ */
+ if (brl->blocking_pid == 0xFFFFFFFF) {
+ struct timeval psx_to = timeval_current_ofs(10, 0);
+ next_timeout = timeval_min(&next_timeout, &psx_to);
+ }
+
+ continue;
+ }
+
+ if (timeval_is_zero(&next_timeout)) {
+ next_timeout = brl->expire_time;
+ }
+ else {
+ next_timeout = timeval_min(&next_timeout,
+ &brl->expire_time);
+ }
+ }
+
+ if (timeval_is_zero(&next_timeout)) {
+ return True;
+ }
+
+ if (!(brl_timeout = event_add_timed(smbd_event_context(), NULL,
+ next_timeout, "brl_timeout",
+ brl_timeout_fn, NULL))) {
+ return False;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+ Function to push a blocking lock request onto the lock queue.
+****************************************************************************/
+
+bool push_blocking_lock_request( struct byte_range_lock *br_lck,
+ const struct smb_request *req,
+ files_struct *fsp,
+ int lock_timeout,
+ int lock_num,
+ uint32 lock_pid,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ SMB_BIG_UINT offset,
+ SMB_BIG_UINT count,
+ uint32 blocking_pid)
+{
+ static bool set_lock_msg;
+ size_t length = smb_len(req->inbuf)+4;
+ blocking_lock_record *blr;
+ NTSTATUS status;
+
+ 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 = SMB_MALLOC_P(blocking_lock_record)) == NULL) {
+ DEBUG(0,("push_blocking_lock_request: Malloc fail !\n" ));
+ return False;
+ }
+
+ blr->next = NULL;
+ blr->prev = NULL;
+
+ if((blr->inbuf = (char *)SMB_MALLOC(length)) == NULL) {
+ DEBUG(0,("push_blocking_lock_request: Malloc fail (2)!\n" ));
+ SAFE_FREE(blr);
+ return False;
+ }
+
+ blr->com_type = CVAL(req->inbuf,smb_com);
+ blr->fsp = fsp;
+ if (lock_timeout == -1) {
+ blr->expire_time.tv_sec = 0;
+ blr->expire_time.tv_usec = 0; /* Never expire. */
+ } else {
+ blr->expire_time = timeval_current_ofs(lock_timeout/1000,
+ (lock_timeout % 1000) * 1000);
+ }
+ blr->lock_num = lock_num;
+ blr->lock_pid = lock_pid;
+ blr->blocking_pid = blocking_pid;
+ blr->lock_flav = lock_flav;
+ blr->lock_type = lock_type;
+ blr->offset = offset;
+ blr->count = count;
+ memcpy(blr->inbuf, req->inbuf, length);
+ blr->length = length;
+ blr->encrypted = req->encrypted;
+
+ /* Add a pending lock record for this. */
+ status = brl_lock(smbd_messaging_context(), br_lck,
+ lock_pid,
+ procid_self(),
+ offset,
+ count,
+ lock_type == READ_LOCK ? PENDING_READ_LOCK : PENDING_WRITE_LOCK,
+ blr->lock_flav,
+ lock_timeout ? True : False, /* blocking_lock. */
+ NULL);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
+ DLIST_REMOVE(blocking_lock_queue, blr);
+ free_blocking_lock_record(blr);
+ return False;
+ }
+
+ DLIST_ADD_END(blocking_lock_queue, blr, blocking_lock_record *);
+ recalc_brl_timeout();
+
+ /* Ensure we'll receive messages when this is unlocked. */
+ if (!set_lock_msg) {
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_SMB_UNLOCK, received_unlock_msg);
+ set_lock_msg = True;
+ }
+
+ DEBUG(3,("push_blocking_lock_request: lock request length=%u blocked with "
+ "expiry time (%u sec. %u usec) (+%d msec) for fnum = %d, name = %s\n",
+ (unsigned int)length, (unsigned int)blr->expire_time.tv_sec,
+ (unsigned int)blr->expire_time.tv_usec, lock_timeout,
+ blr->fsp->fnum, blr->fsp->fsp_name ));
+
+ /* Push the MID of this packet on the signing queue. */
+ srv_defer_sign_response(SVAL(req->inbuf,smb_mid));
+
+ return True;
+}
+
+/****************************************************************************
+ Return a lockingX success SMB.
+*****************************************************************************/
+
+static void reply_lockingX_success(blocking_lock_record *blr)
+{
+ struct smb_request *req;
+
+ if (!(req = talloc(talloc_tos(), struct smb_request))) {
+ smb_panic("Could not allocate smb_request");
+ }
+
+ init_smb_request(req, (uint8 *)blr->inbuf, 0, blr->encrypted);
+ reply_outbuf(req, 2, 0);
+
+ /*
+ * 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.
+ */
+
+ chain_reply(req);
+
+ if (!srv_send_smb(smbd_server_fd(),
+ (char *)req->outbuf,
+ IS_CONN_ENCRYPTED(blr->fsp->conn))) {
+ exit_server_cleanly("send_blocking_reply: srv_send_smb failed.");
+ }
+}
+
+/****************************************************************************
+ Return a generic lock fail error blocking call.
+*****************************************************************************/
+
+static void generic_blocking_lock_error(blocking_lock_record *blr, NTSTATUS status)
+{
+ char outbuf[smb_size];
+ char *inbuf = blr->inbuf;
+
+ construct_reply_common(inbuf, outbuf);
+
+ /* whenever a timeout is given w2k maps LOCK_NOT_GRANTED to
+ FILE_LOCK_CONFLICT! (tridge) */
+ if (NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) {
+ status = NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) {
+ /* Store the last lock error. */
+ files_struct *fsp = blr->fsp;
+
+ if (fsp) {
+ fsp->last_lock_failure.context.smbpid = blr->lock_pid;
+ fsp->last_lock_failure.context.tid = fsp->conn->cnum;
+ fsp->last_lock_failure.context.pid = procid_self();
+ fsp->last_lock_failure.start = blr->offset;
+ fsp->last_lock_failure.size = blr->count;
+ fsp->last_lock_failure.fnum = fsp->fnum;
+ fsp->last_lock_failure.lock_type = READ_LOCK; /* Don't care. */
+ fsp->last_lock_failure.lock_flav = blr->lock_flav;
+ }
+ }
+
+ ERROR_NT(status);
+ if (!srv_send_smb(smbd_server_fd(),outbuf, blr->encrypted)) {
+ exit_server_cleanly("generic_blocking_lock_error: srv_send_smb failed.");
+ }
+}
+
+/****************************************************************************
+ Return a lock fail error for a lockingX call. Undo all the locks we have
+ obtained first.
+*****************************************************************************/
+
+static void reply_lockingX_error(blocking_lock_record *blr, NTSTATUS status)
+{
+ char *inbuf = blr->inbuf;
+ files_struct *fsp = blr->fsp;
+ uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
+ SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT) 0;
+ uint32 lock_pid;
+ unsigned char locktype = CVAL(inbuf,smb_vwv3);
+ bool large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
+ char *data;
+ int i;
+
+ data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks);
+
+ /*
+ * Data now points at the beginning of the list
+ * of smb_lkrng structs.
+ */
+
+ /*
+ * Ensure we don't do a remove on the lock that just failed,
+ * as under POSIX rules, if we have a lock already there, we
+ * will delete it (and we shouldn't) .....
+ */
+
+ for(i = blr->lock_num - 1; i >= 0; i--) {
+ bool err;
+
+ lock_pid = get_lock_pid( data, i, large_file_format);
+ count = get_lock_count( data, i, large_file_format);
+ offset = get_lock_offset( data, i, large_file_format, &err);
+
+ /*
+ * We know err cannot be set as if it was the lock
+ * request would never have been queued. JRA.
+ */
+
+ do_unlock(smbd_messaging_context(),
+ fsp,
+ lock_pid,
+ count,
+ offset,
+ WINDOWS_LOCK);
+ }
+
+ generic_blocking_lock_error(blr, status);
+}
+
+/****************************************************************************
+ Return a lock fail error.
+*****************************************************************************/
+
+static void blocking_lock_reply_error(blocking_lock_record *blr, NTSTATUS status)
+{
+ switch(blr->com_type) {
+ case SMBlockingX:
+ reply_lockingX_error(blr, status);
+ break;
+ case SMBtrans2:
+ case SMBtranss2:
+ {
+ char outbuf[smb_size];
+ char *inbuf = blr->inbuf;
+ construct_reply_common(inbuf, outbuf);
+ /* construct_reply_common has done us the favor to pre-fill the
+ * command field with SMBtranss2 which is wrong :-)
+ */
+ SCVAL(outbuf,smb_com,SMBtrans2);
+ ERROR_NT(status);
+ if (!srv_send_smb(smbd_server_fd(),
+ outbuf,
+ IS_CONN_ENCRYPTED(blr->fsp->conn))) {
+ exit_server_cleanly("blocking_lock_reply_error: srv_send_smb failed.");
+ }
+ 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 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;
+ uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
+ uint16 num_locks = SVAL(inbuf,smb_vwv7);
+ SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT)0;
+ uint32 lock_pid;
+ bool large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
+ char *data;
+ NTSTATUS status = NT_STATUS_OK;
+
+ data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks);
+
+ /*
+ * Data now points at the beginning of the list
+ * of smb_lkrng structs.
+ */
+
+ for(; blr->lock_num < num_locks; blr->lock_num++) {
+ struct byte_range_lock *br_lck = NULL;
+ bool err;
+
+ lock_pid = get_lock_pid( data, blr->lock_num, large_file_format);
+ count = get_lock_count( data, blr->lock_num, large_file_format);
+ offset = get_lock_offset( data, blr->lock_num, large_file_format, &err);
+
+ /*
+ * We know err cannot be set as if it was the lock
+ * request would never have been queued. JRA.
+ */
+ errno = 0;
+ br_lck = do_lock(smbd_messaging_context(),
+ fsp,
+ lock_pid,
+ count,
+ offset,
+ ((locktype & LOCKING_ANDX_SHARED_LOCK) ?
+ READ_LOCK : WRITE_LOCK),
+ WINDOWS_LOCK,
+ True,
+ &status,
+ &blr->blocking_pid);
+
+ TALLOC_FREE(br_lck);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ break;
+ }
+ }
+
+ if(blr->lock_num == num_locks) {
+ /*
+ * Success - we got all the locks.
+ */
+
+ DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d num_locks=%d\n",
+ fsp->fsp_name, fsp->fnum, (unsigned int)locktype, num_locks) );
+
+ reply_lockingX_success(blr);
+ return True;
+ } else if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
+ !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
+ /*
+ * We have other than a "can't get lock"
+ * error. Free any locks we had and return an error.
+ * Return True so we get dequeued.
+ */
+
+ blocking_lock_reply_error(blr, status);
+ return True;
+ }
+
+ /*
+ * Still can't get all the locks - keep waiting.
+ */
+
+ DEBUG(10,("process_lockingX: only got %d locks of %d needed for file %s, fnum = %d. \
+Waiting....\n",
+ blr->lock_num, num_locks, fsp->fsp_name, fsp->fnum));
+
+ return False;
+}
+
+/****************************************************************************
+ Attempt to get the posix lock request from a SMBtrans2 call.
+ Returns True if we want to be removed from the list.
+*****************************************************************************/
+
+static bool process_trans2(blocking_lock_record *blr)
+{
+ struct smb_request *req;
+ char params[2];
+ NTSTATUS status;
+ struct byte_range_lock *br_lck = do_lock(smbd_messaging_context(),
+ blr->fsp,
+ blr->lock_pid,
+ blr->count,
+ blr->offset,
+ blr->lock_type,
+ blr->lock_flav,
+ True,
+ &status,
+ &blr->blocking_pid);
+ TALLOC_FREE(br_lck);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ if (ERROR_WAS_LOCK_DENIED(status)) {
+ /* Still can't get the lock, just keep waiting. */
+ return False;
+ }
+ /*
+ * We have other than a "can't get lock"
+ * error. Send an error and return True so we get dequeued.
+ */
+ blocking_lock_reply_error(blr, status);
+ return True;
+ }
+
+ /* We finally got the lock, return success. */
+
+ if (!(req = talloc(talloc_tos(), struct smb_request))) {
+ blocking_lock_reply_error(blr, NT_STATUS_NO_MEMORY);
+ return True;
+ }
+
+ init_smb_request(req, (uint8 *)blr->inbuf, 0, blr->encrypted);
+
+ SCVAL(req->inbuf, smb_com, SMBtrans2);
+ SSVAL(params,0,0);
+ /* Fake up max_data_bytes here - we know it fits. */
+ send_trans2_replies(blr->fsp->conn, req, params, 2, NULL, 0, 0xffff);
+ return True;
+}
+
+
+/****************************************************************************
+ 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 SMBlockingX:
+ return process_lockingX(blr);
+ case SMBtrans2:
+ case SMBtranss2:
+ return process_trans2(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. */
+}
+
+/****************************************************************************
+ Cancel entries by fnum from the blocking lock pending queue.
+*****************************************************************************/
+
+void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck)
+{
+ blocking_lock_record *blr, *next = NULL;
+
+ for(blr = blocking_lock_queue; blr; blr = next) {
+ next = blr->next;
+ if(blr->fsp->fnum == fsp->fnum) {
+ unsigned char locktype = 0;
+
+ if (blr->com_type == SMBlockingX) {
+ locktype = CVAL(blr->inbuf,smb_vwv3);
+ }
+
+ if (br_lck) {
+ 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 ));
+
+ brl_lock_cancel(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+
+ blocking_lock_cancel(fsp,
+ blr->lock_pid,
+ blr->offset,
+ blr->count,
+ blr->lock_flav,
+ locktype,
+ NT_STATUS_RANGE_NOT_LOCKED);
+ }
+ /* We're closing the file fsp here, so ensure
+ * we don't have a dangling pointer. */
+ blr->fsp = NULL;
+ }
+ }
+}
+
+/****************************************************************************
+ 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, *next = NULL;
+
+ for(blr = blocking_lock_queue; blr; blr = next) {
+ next = blr->next;
+ if(SVAL(blr->inbuf,smb_mid) == mid) {
+ files_struct *fsp = blr->fsp;
+ struct byte_range_lock *br_lck = brl_get_locks(talloc_tos(), fsp);
+
+ if (br_lck) {
+ 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 ));
+
+ brl_lock_cancel(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+ }
+
+ blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
+ DLIST_REMOVE(blocking_lock_queue, blr);
+ free_blocking_lock_record(blr);
+ }
+ }
+}
+
+/****************************************************************************
+ Is this mid a blocking lock request on the queue ?
+*****************************************************************************/
+
+bool blocking_lock_was_deferred(int mid)
+{
+ blocking_lock_record *blr, *next = NULL;
+
+ for(blr = blocking_lock_queue; blr; blr = next) {
+ next = blr->next;
+ if(SVAL(blr->inbuf,smb_mid) == mid) {
+ return True;
+ }
+ }
+ return False;
+}
+
+/****************************************************************************
+ Set a flag as an unlock request affects one of our pending locks.
+*****************************************************************************/
+
+static void received_unlock_msg(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ DEBUG(10,("received_unlock_msg\n"));
+ process_blocking_lock_queue();
+}
+
+/****************************************************************************
+ Process the blocking lock queue. Note that this is only called as root.
+*****************************************************************************/
+
+static void process_blocking_lock_queue(void)
+{
+ struct timeval tv_curr = timeval_current();
+ blocking_lock_record *blr, *next = NULL;
+ bool recalc_timeout = False;
+
+ /*
+ * Go through the queue and see if we can get any of the locks.
+ */
+
+ for (blr = blocking_lock_queue; blr; blr = next) {
+ connection_struct *conn = NULL;
+ uint16 vuid;
+ files_struct *fsp = NULL;
+
+ next = blr->next;
+
+ /*
+ * 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(!change_to_user(conn,vuid)) {
+ struct byte_range_lock *br_lck = brl_get_locks(talloc_tos(), fsp);
+
+ /*
+ * Remove the entry and return an error to the client.
+ */
+
+ if (br_lck) {
+ brl_lock_cancel(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+ }
+
+ DEBUG(0,("process_blocking_lock_queue: Unable to become user vuid=%d.\n",
+ vuid ));
+ blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
+ DLIST_REMOVE(blocking_lock_queue, blr);
+ free_blocking_lock_record(blr);
+ recalc_timeout = True;
+ continue;
+ }
+
+ if(!set_current_service(conn,SVAL(blr->inbuf,smb_flg),True)) {
+ struct byte_range_lock *br_lck = brl_get_locks(talloc_tos(), fsp);
+
+ /*
+ * Remove the entry and return an error to the client.
+ */
+
+ if (br_lck) {
+ brl_lock_cancel(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+ }
+
+ DEBUG(0,("process_blocking_lock_queue: Unable to become service Error was %s.\n", strerror(errno) ));
+ blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
+ DLIST_REMOVE(blocking_lock_queue, blr);
+ free_blocking_lock_record(blr);
+ recalc_timeout = True;
+ change_to_root_user();
+ continue;
+ }
+
+ /*
+ * Go through the remaining locks and try and obtain them.
+ * The call returns True if all locks were obtained successfully
+ * and False if we still need to wait.
+ */
+
+ if(blocking_lock_record_process(blr)) {
+ struct byte_range_lock *br_lck = brl_get_locks(talloc_tos(), fsp);
+
+ if (br_lck) {
+ brl_lock_cancel(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+ }
+
+ DLIST_REMOVE(blocking_lock_queue, blr);
+ free_blocking_lock_record(blr);
+ recalc_timeout = True;
+ change_to_root_user();
+ continue;
+ }
+
+ change_to_root_user();
+
+ /*
+ * We couldn't get the locks for this record on the list.
+ * If the time has expired, return a lock error.
+ */
+
+ if (!timeval_is_zero(&blr->expire_time) && timeval_compare(&blr->expire_time, &tv_curr) <= 0) {
+ struct byte_range_lock *br_lck = brl_get_locks(talloc_tos(), fsp);
+
+ /*
+ * Lock expired - throw away all previously
+ * obtained locks and return lock error.
+ */
+
+ if (br_lck) {
+ DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n",
+ fsp->fnum, fsp->fsp_name ));
+
+ brl_lock_cancel(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ TALLOC_FREE(br_lck);
+ }
+
+ blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
+ DLIST_REMOVE(blocking_lock_queue, blr);
+ free_blocking_lock_record(blr);
+ recalc_timeout = True;
+ }
+ }
+
+ if (recalc_timeout) {
+ recalc_brl_timeout();
+ }
+}
+
+/****************************************************************************
+ Handle a cancel message. Lock already moved onto the cancel queue.
+*****************************************************************************/
+
+#define MSG_BLOCKING_LOCK_CANCEL_SIZE (sizeof(blocking_lock_record *) + sizeof(NTSTATUS))
+
+static void process_blocking_lock_cancel_message(struct messaging_context *ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ NTSTATUS err;
+ const char *msg = (const char *)data->data;
+ blocking_lock_record *blr;
+
+ if (data->data == NULL) {
+ smb_panic("process_blocking_lock_cancel_message: null msg");
+ }
+
+ if (data->length != MSG_BLOCKING_LOCK_CANCEL_SIZE) {
+ DEBUG(0, ("process_blocking_lock_cancel_message: "
+ "Got invalid msg len %d\n", (int)data->length));
+ smb_panic("process_blocking_lock_cancel_message: bad msg");
+ }
+
+ memcpy(&blr, msg, sizeof(blr));
+ memcpy(&err, &msg[sizeof(blr)], sizeof(NTSTATUS));
+
+ DEBUG(10,("process_blocking_lock_cancel_message: returning error %s\n",
+ nt_errstr(err) ));
+
+ blocking_lock_reply_error(blr, err);
+ DLIST_REMOVE(blocking_lock_cancelled_queue, blr);
+ free_blocking_lock_record(blr);
+}
+
+/****************************************************************************
+ Send ourselves a blocking lock cancelled message. Handled asynchronously above.
+*****************************************************************************/
+
+bool blocking_lock_cancel(files_struct *fsp,
+ uint32 lock_pid,
+ SMB_BIG_UINT offset,
+ SMB_BIG_UINT count,
+ enum brl_flavour lock_flav,
+ unsigned char locktype,
+ NTSTATUS err)
+{
+ static bool initialized;
+ char msg[MSG_BLOCKING_LOCK_CANCEL_SIZE];
+ blocking_lock_record *blr;
+
+ if (!initialized) {
+ /* Register our message. */
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_SMB_BLOCKING_LOCK_CANCEL,
+ process_blocking_lock_cancel_message);
+
+ initialized = True;
+ }
+
+ for (blr = blocking_lock_queue; blr; blr = blr->next) {
+ if (fsp == blr->fsp &&
+ lock_pid == blr->lock_pid &&
+ offset == blr->offset &&
+ count == blr->count &&
+ lock_flav == blr->lock_flav) {
+ break;
+ }
+ }
+
+ if (!blr) {
+ return False;
+ }
+
+ /* Check the flags are right. */
+ if (blr->com_type == SMBlockingX &&
+ (locktype & LOCKING_ANDX_LARGE_FILES) !=
+ (CVAL(blr->inbuf,smb_vwv3) & LOCKING_ANDX_LARGE_FILES)) {
+ return False;
+ }
+
+ /* Move to cancelled queue. */
+ DLIST_REMOVE(blocking_lock_queue, blr);
+ DLIST_ADD(blocking_lock_cancelled_queue, blr);
+
+ /* Create the message. */
+ memcpy(msg, &blr, sizeof(blr));
+ memcpy(&msg[sizeof(blr)], &err, sizeof(NTSTATUS));
+
+ messaging_send_buf(smbd_messaging_context(), procid_self(),
+ MSG_SMB_BLOCKING_LOCK_CANCEL,
+ (uint8 *)&msg, sizeof(msg));
+
+ return True;
+}
diff --git a/source3/smbd/change_trust_pw.c b/source3/smbd/change_trust_pw.c
new file mode 100644
index 0000000000..72a72a78b5
--- /dev/null
+++ b/source3/smbd/change_trust_pw.c
@@ -0,0 +1,101 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Periodic Trust account password changing.
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 1998.
+ * Copyright (C) Andrew Bartlett 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+/************************************************************************
+ Change the trust account password for a domain.
+************************************************************************/
+
+NTSTATUS change_trust_account_password( const char *domain, const char *remote_machine)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ struct sockaddr_storage pdc_ss;
+ fstring dc_name;
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *netlogon_pipe = NULL;
+
+ DEBUG(5,("change_trust_account_password: Attempting to change trust account password in domain %s....\n",
+ domain));
+
+ if (remote_machine == NULL || !strcmp(remote_machine, "*")) {
+ /* Use the PDC *only* for this */
+
+ if ( !get_pdc_ip(domain, &pdc_ss) ) {
+ DEBUG(0,("Can't get IP for PDC for domain %s\n", domain));
+ goto failed;
+ }
+
+ if ( !name_status_find( domain, 0x1b, 0x20, &pdc_ss, dc_name) )
+ goto failed;
+ } else {
+ /* supoport old deprecated "smbpasswd -j DOMAIN -r MACHINE" behavior */
+ fstrcpy( dc_name, remote_machine );
+ }
+
+ /* if this next call fails, then give up. We can't do
+ password changes on BDC's --jerry */
+
+ if (!NT_STATUS_IS_OK(cli_full_connection(&cli, global_myname(), dc_name,
+ NULL, 0,
+ "IPC$", "IPC",
+ "", "",
+ "", 0, Undefined, NULL))) {
+ DEBUG(0,("modify_trust_password: Connection to %s failed!\n", dc_name));
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto failed;
+ }
+
+ /*
+ * Ok - we have an anonymous connection to the IPC$ share.
+ * Now start the NT Domain stuff :-).
+ */
+
+ /* Shouldn't we open this with schannel ? JRA. */
+
+ nt_status = cli_rpc_pipe_open_noauth(
+ cli, &ndr_table_netlogon.syntax_id, &netlogon_pipe);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0,("modify_trust_password: unable to open the domain client session to machine %s. Error was : %s.\n",
+ dc_name, nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ cli = NULL;
+ goto failed;
+ }
+
+ nt_status = trust_pw_find_change_and_store_it(
+ netlogon_pipe, netlogon_pipe, domain);
+
+ cli_shutdown(cli);
+ cli = NULL;
+
+failed:
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0,("%s : change_trust_account_password: Failed to change password for domain %s.\n",
+ current_timestring(debug_ctx(), False), domain));
+ }
+ else
+ DEBUG(5,("change_trust_account_password: sucess!\n"));
+
+ return nt_status;
+}
diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c
new file mode 100644
index 0000000000..2596e73380
--- /dev/null
+++ b/source3/smbd/chgpasswd.c
@@ -0,0 +1,1208 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Andrew Bartlett 2001-2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* These comments regard the code to change the user's unix password: */
+
+/* fork a child process to exec passwd and write to its
+ * tty to change a users password. This is running as the
+ * user who is attempting to change the password.
+ */
+
+/*
+ * This code was copied/borrowed and stolen from various sources.
+ * The primary source was the poppasswd.c from the authors of POPMail. This software
+ * was included as a client to change passwords using the 'passwd' program
+ * on the remote machine.
+ *
+ * This code has been hacked by Bob Nance (nance@niehs.nih.gov) and Evan Patterson
+ * (patters2@niehs.nih.gov) at the National Institute of Environmental Health Sciences
+ * and rights to modify, distribute or incorporate this change to the CAP suite or
+ * using it for any other reason are granted, so long as this disclaimer is left intact.
+ */
+
+/*
+ This code was hacked considerably for inclusion in Samba, primarily
+ by Andrew.Tridgell@anu.edu.au. The biggest change was the addition
+ of the "password chat" option, which allows the easy runtime
+ specification of the expected sequence of events to change a
+ password.
+ */
+
+#include "includes.h"
+
+extern struct passdb_ops pdb_ops;
+
+static NTSTATUS check_oem_password(const char *user,
+ uchar password_encrypted_with_lm_hash[516],
+ const uchar old_lm_hash_encrypted[16],
+ uchar password_encrypted_with_nt_hash[516],
+ const uchar old_nt_hash_encrypted[16],
+ struct samu **hnd,
+ char **pp_new_passwd);
+
+#if ALLOW_CHANGE_PASSWORD
+
+static int findpty(char **slave)
+{
+ int master = -1;
+ char *line = NULL;
+ SMB_STRUCT_DIR *dirp = NULL;
+ const char *dpname;
+
+ *slave = NULL;
+
+#if defined(HAVE_GRANTPT)
+ /* Try to open /dev/ptmx. If that fails, fall through to old method. */
+ if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0) {
+ grantpt(master);
+ unlockpt(master);
+ line = (char *)ptsname(master);
+ if (line) {
+ *slave = SMB_STRDUP(line);
+ }
+
+ if (*slave == NULL) {
+ DEBUG(0,
+ ("findpty: Unable to create master/slave pty pair.\n"));
+ /* Stop fd leak on error. */
+ close(master);
+ return -1;
+ } else {
+ DEBUG(10,
+ ("findpty: Allocated slave pty %s\n", *slave));
+ return (master);
+ }
+ }
+#endif /* HAVE_GRANTPT */
+
+ line = SMB_STRDUP("/dev/ptyXX");
+ if (!line) {
+ return (-1);
+ }
+
+ dirp = sys_opendir("/dev");
+ if (!dirp) {
+ SAFE_FREE(line);
+ return (-1);
+ }
+
+ while ((dpname = readdirname(dirp)) != NULL) {
+ if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) {
+ DEBUG(3,
+ ("pty: try to open %s, line was %s\n", dpname,
+ line));
+ line[8] = dpname[3];
+ line[9] = dpname[4];
+ if ((master = sys_open(line, O_RDWR, 0)) >= 0) {
+ DEBUG(3, ("pty: opened %s\n", line));
+ line[5] = 't';
+ *slave = line;
+ sys_closedir(dirp);
+ return (master);
+ }
+ }
+ }
+ sys_closedir(dirp);
+ SAFE_FREE(line);
+ return (-1);
+}
+
+static int dochild(int master, const char *slavedev, const struct passwd *pass,
+ const char *passwordprogram, bool as_root)
+{
+ int slave;
+ struct termios stermios;
+ gid_t gid;
+ uid_t uid;
+ char * const eptrs[1] = { NULL };
+
+ if (pass == NULL)
+ {
+ DEBUG(0,
+ ("dochild: user doesn't exist in the UNIX password database.\n"));
+ return False;
+ }
+
+ gid = pass->pw_gid;
+ uid = pass->pw_uid;
+
+ gain_root_privilege();
+
+ /* Start new session - gets rid of controlling terminal. */
+ if (setsid() < 0)
+ {
+ DEBUG(3,
+ ("Weirdness, couldn't let go of controlling terminal\n"));
+ return (False);
+ }
+
+ /* Open slave pty and acquire as new controlling terminal. */
+ if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0)
+ {
+ DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
+ return (False);
+ }
+#if defined(TIOCSCTTY) && !defined(SUNOS5)
+ /*
+ * On patched Solaris 10 TIOCSCTTY is defined but seems not to work,
+ * see the discussion under
+ * https://bugzilla.samba.org/show_bug.cgi?id=5366.
+ */
+ if (ioctl(slave, TIOCSCTTY, 0) < 0)
+ {
+ DEBUG(3, ("Error in ioctl call for slave pty\n"));
+ /* return(False); */
+ }
+#elif defined(I_PUSH) && defined(I_FIND)
+ if (ioctl(slave, I_FIND, "ptem") == 0) {
+ ioctl(slave, I_PUSH, "ptem");
+ }
+ if (ioctl(slave, I_FIND, "ldterm") == 0) {
+ ioctl(slave, I_PUSH, "ldterm");
+ }
+#endif
+
+ /* Close master. */
+ close(master);
+
+ /* Make slave stdin/out/err of child. */
+
+ if (sys_dup2(slave, STDIN_FILENO) != STDIN_FILENO)
+ {
+ DEBUG(3, ("Could not re-direct stdin\n"));
+ return (False);
+ }
+ if (sys_dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
+ {
+ DEBUG(3, ("Could not re-direct stdout\n"));
+ return (False);
+ }
+ if (sys_dup2(slave, STDERR_FILENO) != STDERR_FILENO)
+ {
+ DEBUG(3, ("Could not re-direct stderr\n"));
+ return (False);
+ }
+ if (slave > 2)
+ close(slave);
+
+ /* Set proper terminal attributes - no echo, canonical input processing,
+ no map NL to CR/NL on output. */
+
+ if (tcgetattr(0, &stermios) < 0)
+ {
+ DEBUG(3,
+ ("could not read default terminal attributes on pty\n"));
+ return (False);
+ }
+ stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+ stermios.c_lflag |= ICANON;
+#ifdef ONLCR
+ stermios.c_oflag &= ~(ONLCR);
+#endif
+ if (tcsetattr(0, TCSANOW, &stermios) < 0)
+ {
+ DEBUG(3, ("could not set attributes of pty\n"));
+ return (False);
+ }
+
+ /* make us completely into the right uid */
+ if (!as_root)
+ {
+ become_user_permanently(uid, gid);
+ }
+
+ DEBUG(10,
+ ("Invoking '%s' as password change program.\n",
+ passwordprogram));
+
+ /* execl() password-change application */
+ if (execle("/bin/sh", "sh", "-c", passwordprogram, NULL, eptrs) < 0)
+ {
+ DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
+ return (False);
+ }
+ return (True);
+}
+
+static int expect(int master, char *issue, char *expected)
+{
+ char buffer[1024];
+ int attempts, timeout, nread;
+ size_t len;
+ bool match = False;
+
+ for (attempts = 0; attempts < 2; attempts++) {
+ NTSTATUS status;
+ if (!strequal(issue, ".")) {
+ if (lp_passwd_chat_debug())
+ DEBUG(100, ("expect: sending [%s]\n", issue));
+
+ if ((len = sys_write(master, issue, strlen(issue))) != strlen(issue)) {
+ DEBUG(2,("expect: (short) write returned %d\n",
+ (int)len ));
+ return False;
+ }
+ }
+
+ if (strequal(expected, "."))
+ return True;
+
+ /* Initial timeout. */
+ timeout = lp_passwd_chat_timeout() * 1000;
+ nread = 0;
+ buffer[nread] = 0;
+
+ while (True) {
+ status = read_socket_with_timeout(
+ master, buffer + nread, 1,
+ sizeof(buffer) - nread - 1,
+ timeout, &len);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ break;
+ }
+ nread += len;
+ buffer[nread] = 0;
+
+ {
+ /* Eat leading/trailing whitespace before match. */
+ char *str = SMB_STRDUP(buffer);
+ if (!str) {
+ DEBUG(2,("expect: ENOMEM\n"));
+ return False;
+ }
+ trim_char(str, ' ', ' ');
+
+ if ((match = unix_wild_match(expected, str)) == True) {
+ /* Now data has started to return, lower timeout. */
+ timeout = lp_passwd_chat_timeout() * 100;
+ }
+ SAFE_FREE(str);
+ }
+ }
+
+ if (lp_passwd_chat_debug())
+ DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
+ expected, buffer, match ? "yes" : "no" ));
+
+ if (match)
+ break;
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(2, ("expect: %s\n", nt_errstr(status)));
+ return False;
+ }
+ }
+
+ DEBUG(10,("expect: returning %s\n", match ? "True" : "False" ));
+ return match;
+}
+
+static void pwd_sub(char *buf)
+{
+ all_string_sub(buf, "\\n", "\n", 0);
+ all_string_sub(buf, "\\r", "\r", 0);
+ all_string_sub(buf, "\\s", " ", 0);
+ all_string_sub(buf, "\\t", "\t", 0);
+}
+
+static int talktochild(int master, const char *seq)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ int count = 0;
+ char *issue;
+ char *expected;
+
+ issue = talloc_strdup(frame, ".");
+ if (!issue) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ while (next_token_talloc(frame, &seq, &expected, NULL)) {
+ pwd_sub(expected);
+ count++;
+
+ if (!expect(master, issue, expected)) {
+ DEBUG(3, ("Response %d incorrect\n", count));
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ if (!next_token_talloc(frame, &seq, &issue, NULL)) {
+ issue = talloc_strdup(frame, ".");
+ if (!issue) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+ }
+ pwd_sub(issue);
+ }
+
+ if (!strequal(issue, ".")) {
+ /* we have one final issue to send */
+ expected = talloc_strdup(frame, ".");
+ if (!expected) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+ if (!expect(master, issue, expected)) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+ }
+ TALLOC_FREE(frame);
+ return (count > 0);
+}
+
+static bool chat_with_program(char *passwordprogram, const struct passwd *pass,
+ char *chatsequence, bool as_root)
+{
+ char *slavedev = NULL;
+ int master;
+ pid_t pid, wpid;
+ int wstat;
+ bool chstat = False;
+
+ if (pass == NULL) {
+ DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
+ return False;
+ }
+
+ /* allocate a pseudo-terminal device */
+ if ((master = findpty(&slavedev)) < 0) {
+ DEBUG(3, ("chat_with_program: Cannot Allocate pty for password change: %s\n", pass->pw_name));
+ return (False);
+ }
+
+ /*
+ * We need to temporarily stop CatchChild from eating
+ * SIGCLD signals as it also eats the exit status code. JRA.
+ */
+
+ CatchChildLeaveStatus();
+
+ if ((pid = sys_fork()) < 0) {
+ DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass->pw_name));
+ SAFE_FREE(slavedev);
+ close(master);
+ CatchChild();
+ return (False);
+ }
+
+ /* we now have a pty */
+ if (pid > 0) { /* This is the parent process */
+ /* Don't need this anymore in parent. */
+ SAFE_FREE(slavedev);
+
+ if ((chstat = talktochild(master, chatsequence)) == False) {
+ DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass->pw_name));
+ kill(pid, SIGKILL); /* be sure to end this process */
+ }
+
+ while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
+ if (errno == EINTR) {
+ errno = 0;
+ continue;
+ }
+ break;
+ }
+
+ if (wpid < 0) {
+ DEBUG(3, ("chat_with_program: The process is no longer waiting!\n\n"));
+ close(master);
+ CatchChild();
+ return (False);
+ }
+
+ /*
+ * Go back to ignoring children.
+ */
+ CatchChild();
+
+ close(master);
+
+ if (pid != wpid) {
+ DEBUG(3, ("chat_with_program: We were waiting for the wrong process ID\n"));
+ return (False);
+ }
+ if (WIFEXITED(wstat) && (WEXITSTATUS(wstat) != 0)) {
+ DEBUG(3, ("chat_with_program: The process exited with status %d \
+while we were waiting\n", WEXITSTATUS(wstat)));
+ return (False);
+ }
+#if defined(WIFSIGNALLED) && defined(WTERMSIG)
+ else if (WIFSIGNALLED(wstat)) {
+ DEBUG(3, ("chat_with_program: The process was killed by signal %d \
+while we were waiting\n", WTERMSIG(wstat)));
+ return (False);
+ }
+#endif
+ } else {
+ /* CHILD */
+
+ /*
+ * Lose any elevated privileges.
+ */
+ drop_effective_capability(KERNEL_OPLOCK_CAPABILITY);
+ drop_effective_capability(DMAPI_ACCESS_CAPABILITY);
+
+ /* make sure it doesn't freeze */
+ alarm(20);
+
+ if (as_root)
+ become_root();
+
+ DEBUG(3, ("chat_with_program: Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass->pw_name,
+ (int)getuid(), (int)getgid(), BOOLSTR(as_root) ));
+ chstat = dochild(master, slavedev, pass, passwordprogram, as_root);
+
+ if (as_root)
+ unbecome_root();
+
+ /*
+ * The child should never return from dochild() ....
+ */
+
+ DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat));
+ exit(1);
+ }
+
+ if (chstat)
+ DEBUG(3, ("chat_with_program: Password change %ssuccessful for user %s\n",
+ (chstat ? "" : "un"), pass->pw_name));
+ return (chstat);
+}
+
+bool chgpasswd(const char *name, const struct passwd *pass,
+ const char *oldpass, const char *newpass, bool as_root)
+{
+ char *passwordprogram = NULL;
+ char *chatsequence = NULL;
+ size_t i;
+ size_t len;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if (!oldpass) {
+ oldpass = "";
+ }
+
+ DEBUG(3, ("chgpasswd: Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root), name));
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("chgpasswd: Passwords: old=%s new=%s\n", oldpass, newpass));
+#endif
+
+ /* Take the passed information and test it for minimum criteria */
+
+ /* Password is same as old password */
+ if (strcmp(oldpass, newpass) == 0) {
+ /* don't allow same password */
+ DEBUG(2, ("chgpasswd: Password Change: %s, New password is same as old\n", name)); /* log the attempt */
+ return (False); /* inform the user */
+ }
+
+ /*
+ * Check the old and new passwords don't contain any control
+ * characters.
+ */
+
+ len = strlen(oldpass);
+ for (i = 0; i < len; i++) {
+ if (iscntrl((int)oldpass[i])) {
+ DEBUG(0, ("chgpasswd: oldpass contains control characters (disallowed).\n"));
+ return False;
+ }
+ }
+
+ len = strlen(newpass);
+ for (i = 0; i < len; i++) {
+ if (iscntrl((int)newpass[i])) {
+ DEBUG(0, ("chgpasswd: newpass contains control characters (disallowed).\n"));
+ return False;
+ }
+ }
+
+#ifdef WITH_PAM
+ if (lp_pam_password_change()) {
+ bool ret;
+#ifdef HAVE_SETLOCALE
+ const char *prevlocale = setlocale(LC_ALL, "C");
+#endif
+
+ if (as_root)
+ become_root();
+
+ if (pass) {
+ ret = smb_pam_passchange(pass->pw_name, oldpass, newpass);
+ } else {
+ ret = smb_pam_passchange(name, oldpass, newpass);
+ }
+
+ if (as_root)
+ unbecome_root();
+
+#ifdef HAVE_SETLOCALE
+ setlocale(LC_ALL, prevlocale);
+#endif
+
+ return ret;
+ }
+#endif
+
+ /* A non-PAM password change just doen't make sense without a valid local user */
+
+ if (pass == NULL) {
+ DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name));
+ return false;
+ }
+
+ passwordprogram = talloc_strdup(ctx, lp_passwd_program());
+ if (!passwordprogram || !*passwordprogram) {
+ DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
+ return false;
+ }
+ chatsequence = talloc_strdup(ctx, lp_passwd_chat());
+ if (!chatsequence || !*chatsequence) {
+ DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
+ return false;
+ }
+
+ if (as_root) {
+ /* The password program *must* contain the user name to work. Fail if not. */
+ if (strstr_m(passwordprogram, "%u") == NULL) {
+ DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
+the string %%u, and the given string %s does not.\n", passwordprogram ));
+ return false;
+ }
+ }
+
+ passwordprogram = talloc_string_sub(ctx, passwordprogram, "%u", name);
+ if (!passwordprogram) {
+ return false;
+ }
+
+ /* note that we do NOT substitute the %o and %n in the password program
+ as this would open up a security hole where the user could use
+ a new password containing shell escape characters */
+
+ chatsequence = talloc_string_sub(ctx, chatsequence, "%u", name);
+ if (!chatsequence) {
+ return false;
+ }
+ chatsequence = talloc_all_string_sub(ctx,
+ chatsequence,
+ "%o",
+ oldpass);
+ if (!chatsequence) {
+ return false;
+ }
+ chatsequence = talloc_all_string_sub(ctx,
+ chatsequence,
+ "%n",
+ newpass);
+ return chat_with_program(passwordprogram,
+ pass,
+ chatsequence,
+ as_root);
+}
+
+#else /* ALLOW_CHANGE_PASSWORD */
+
+bool chgpasswd(const char *name, const struct passwd *pass,
+ const char *oldpass, const char *newpass, bool as_root)
+{
+ DEBUG(0, ("chgpasswd: Unix Password changing not compiled in (user=%s)\n", name));
+ return (False);
+}
+#endif /* ALLOW_CHANGE_PASSWORD */
+
+/***********************************************************
+ Code to check the lanman hashed password.
+************************************************************/
+
+bool check_lanman_password(char *user, uchar * pass1,
+ uchar * pass2, struct samu **hnd)
+{
+ uchar unenc_new_pw[16];
+ uchar unenc_old_pw[16];
+ struct samu *sampass = NULL;
+ uint32 acct_ctrl;
+ const uint8 *lanman_pw;
+ bool ret;
+
+ if ( !(sampass = samu_new(NULL)) ) {
+ DEBUG(0, ("samu_new() failed!\n"));
+ return False;
+ }
+
+ become_root();
+ ret = pdb_getsampwnam(sampass, user);
+ unbecome_root();
+
+ if (ret == False) {
+ DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n"));
+ TALLOC_FREE(sampass);
+ return False;
+ }
+
+ acct_ctrl = pdb_get_acct_ctrl (sampass);
+ lanman_pw = pdb_get_lanman_passwd (sampass);
+
+ if (acct_ctrl & ACB_DISABLED) {
+ DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
+ TALLOC_FREE(sampass);
+ return False;
+ }
+
+ if (lanman_pw == NULL) {
+ if (acct_ctrl & ACB_PWNOTREQ) {
+ /* this saves the pointer for the caller */
+ *hnd = sampass;
+ return True;
+ } else {
+ DEBUG(0, ("check_lanman_password: no lanman password !\n"));
+ TALLOC_FREE(sampass);
+ return False;
+ }
+ }
+
+ /* Get the new lanman hash. */
+ D_P16(lanman_pw, pass2, unenc_new_pw);
+
+ /* Use this to get the old lanman hash. */
+ D_P16(unenc_new_pw, pass1, unenc_old_pw);
+
+ /* Check that the two old passwords match. */
+ if (memcmp(lanman_pw, unenc_old_pw, 16)) {
+ DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
+ TALLOC_FREE(sampass);
+ return False;
+ }
+
+ /* this saves the pointer for the caller */
+ *hnd = sampass;
+ return True;
+}
+
+/***********************************************************
+ Code to change the lanman hashed password.
+ It nulls out the NT hashed password as it will
+ no longer be valid.
+ NOTE this function is designed to be called as root. Check the old password
+ is correct before calling. JRA.
+************************************************************/
+
+bool change_lanman_password(struct samu *sampass, uchar *pass2)
+{
+ static uchar null_pw[16];
+ uchar unenc_new_pw[16];
+ bool ret;
+ uint32 acct_ctrl;
+ const uint8 *pwd;
+
+ if (sampass == NULL) {
+ DEBUG(0,("change_lanman_password: no smb password entry.\n"));
+ return False;
+ }
+
+ acct_ctrl = pdb_get_acct_ctrl(sampass);
+ pwd = pdb_get_lanman_passwd(sampass);
+
+ if (acct_ctrl & ACB_DISABLED) {
+ DEBUG(0,("change_lanman_password: account %s disabled.\n",
+ pdb_get_username(sampass)));
+ return False;
+ }
+
+ if (pwd == NULL) {
+ if (acct_ctrl & ACB_PWNOTREQ) {
+ uchar no_pw[14];
+ memset(no_pw, '\0', 14);
+ E_P16(no_pw, null_pw);
+
+ /* Get the new lanman hash. */
+ D_P16(null_pw, pass2, unenc_new_pw);
+ } else {
+ DEBUG(0,("change_lanman_password: no lanman password !\n"));
+ return False;
+ }
+ } else {
+ /* Get the new lanman hash. */
+ D_P16(pwd, pass2, unenc_new_pw);
+ }
+
+ if (!pdb_set_lanman_passwd(sampass, unenc_new_pw, PDB_CHANGED)) {
+ return False;
+ }
+
+ if (!pdb_set_nt_passwd (sampass, NULL, PDB_CHANGED)) {
+ return False; /* We lose the NT hash. Sorry. */
+ }
+
+ if (!pdb_set_pass_last_set_time (sampass, time(NULL), PDB_CHANGED)) {
+ TALLOC_FREE(sampass);
+ /* Not quite sure what this one qualifies as, but this will do */
+ return False;
+ }
+
+ /* Now flush the sam_passwd struct to persistent storage */
+ ret = NT_STATUS_IS_OK(pdb_update_sam_account (sampass));
+
+ return ret;
+}
+
+/***********************************************************
+ Code to check and change the OEM hashed password.
+************************************************************/
+
+NTSTATUS pass_oem_change(char *user,
+ uchar password_encrypted_with_lm_hash[516],
+ const uchar old_lm_hash_encrypted[16],
+ uchar password_encrypted_with_nt_hash[516],
+ const uchar old_nt_hash_encrypted[16],
+ uint32 *reject_reason)
+{
+ char *new_passwd = NULL;
+ struct samu *sampass = NULL;
+ NTSTATUS nt_status = check_oem_password(user,
+ password_encrypted_with_lm_hash,
+ old_lm_hash_encrypted,
+ password_encrypted_with_nt_hash,
+ old_nt_hash_encrypted,
+ &sampass,
+ &new_passwd);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ /* We've already checked the old password here.... */
+ become_root();
+ nt_status = change_oem_password(sampass, NULL, new_passwd, True, reject_reason);
+ unbecome_root();
+
+ memset(new_passwd, 0, strlen(new_passwd));
+
+ TALLOC_FREE(sampass);
+
+ return nt_status;
+}
+
+/***********************************************************
+ Decrypt and verify a user password change.
+
+ The 516 byte long buffers are encrypted with the old NT and
+ old LM passwords, and if the NT passwords are present, both
+ buffers contain a unicode string.
+
+ After decrypting the buffers, check the password is correct by
+ matching the old hashed passwords with the passwords in the passdb.
+
+************************************************************/
+
+static NTSTATUS check_oem_password(const char *user,
+ uchar password_encrypted_with_lm_hash[516],
+ const uchar old_lm_hash_encrypted[16],
+ uchar password_encrypted_with_nt_hash[516],
+ const uchar old_nt_hash_encrypted[16],
+ struct samu **hnd,
+ char **pp_new_passwd)
+{
+ static uchar null_pw[16];
+ static uchar null_ntpw[16];
+ struct samu *sampass = NULL;
+ uint8 *password_encrypted;
+ const uint8 *encryption_key;
+ const uint8 *lanman_pw, *nt_pw;
+ uint32 acct_ctrl;
+ uint32 new_pw_len;
+ uchar new_nt_hash[16];
+ uchar new_lm_hash[16];
+ uchar verifier[16];
+ char no_pw[2];
+ bool ret;
+
+ bool nt_pass_set = (password_encrypted_with_nt_hash && old_nt_hash_encrypted);
+ bool lm_pass_set = (password_encrypted_with_lm_hash && old_lm_hash_encrypted);
+
+ *hnd = NULL;
+
+ if ( !(sampass = samu_new( NULL )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+ ret = pdb_getsampwnam(sampass, user);
+ unbecome_root();
+
+ if (ret == False) {
+ DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ acct_ctrl = pdb_get_acct_ctrl(sampass);
+
+ if (acct_ctrl & ACB_DISABLED) {
+ DEBUG(2,("check_lanman_password: account %s disabled.\n", user));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_ACCOUNT_DISABLED;
+ }
+
+ if ((acct_ctrl & ACB_PWNOTREQ) && lp_null_passwords()) {
+ /* construct a null password (in case one is needed */
+ no_pw[0] = 0;
+ no_pw[1] = 0;
+ nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
+ lanman_pw = null_pw;
+ nt_pw = null_pw;
+
+ } else {
+ /* save pointers to passwords so we don't have to keep looking them up */
+ if (lp_lanman_auth()) {
+ lanman_pw = pdb_get_lanman_passwd(sampass);
+ } else {
+ lanman_pw = NULL;
+ }
+ nt_pw = pdb_get_nt_passwd(sampass);
+ }
+
+ if (nt_pw && nt_pass_set) {
+ /* IDEAL Case: passwords are in unicode, and we can
+ * read use the password encrypted with the NT hash
+ */
+ password_encrypted = password_encrypted_with_nt_hash;
+ encryption_key = nt_pw;
+ } else if (lanman_pw && lm_pass_set) {
+ /* password may still be in unicode, but use LM hash version */
+ password_encrypted = password_encrypted_with_lm_hash;
+ encryption_key = lanman_pw;
+ } else if (nt_pass_set) {
+ DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n",
+ user));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_WRONG_PASSWORD;
+ } else if (lm_pass_set) {
+ if (lp_lanman_auth()) {
+ DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n",
+ user));
+ } else {
+ DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n",
+ user));
+ }
+ TALLOC_FREE(sampass);
+ return NT_STATUS_WRONG_PASSWORD;
+ } else {
+ DEBUG(1, ("password change requested for user %s, but no password supplied!\n",
+ user));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /*
+ * Decrypt the password with the key
+ */
+ SamOEMhash( password_encrypted, encryption_key, 516);
+
+ if (!decode_pw_buffer(talloc_tos(),
+ password_encrypted,
+ pp_new_passwd,
+ &new_pw_len,
+ nt_pass_set ? STR_UNICODE : STR_ASCII)) {
+ TALLOC_FREE(sampass);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /*
+ * To ensure we got the correct new password, hash it and
+ * use it as a key to test the passed old password.
+ */
+
+ if (nt_pass_set) {
+ /* NT passwords, verify the NT hash. */
+
+ /* Calculate the MD4 hash (NT compatible) of the password */
+ memset(new_nt_hash, '\0', 16);
+ E_md4hash(*pp_new_passwd, new_nt_hash);
+
+ if (nt_pw) {
+ /*
+ * check the NT verifier
+ */
+ E_old_pw_hash(new_nt_hash, nt_pw, verifier);
+ if (memcmp(verifier, old_nt_hash_encrypted, 16)) {
+ DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /* We could check the LM password here, but there is
+ * little point, we already know the password is
+ * correct, and the LM password might not even be
+ * present. */
+
+ /* Further, LM hash generation algorithms
+ * differ with charset, so we could
+ * incorrectly fail a perfectly valid password
+ * change */
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,
+ ("check_oem_password: password %s ok\n", *pp_new_passwd));
+#endif
+ *hnd = sampass;
+ return NT_STATUS_OK;
+ }
+
+ if (lanman_pw) {
+ /*
+ * check the lm verifier
+ */
+ E_old_pw_hash(new_nt_hash, lanman_pw, verifier);
+ if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
+ DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,
+ ("check_oem_password: password %s ok\n", *pp_new_passwd));
+#endif
+ *hnd = sampass;
+ return NT_STATUS_OK;
+ }
+ }
+
+ if (lanman_pw && lm_pass_set) {
+
+ E_deshash(*pp_new_passwd, new_lm_hash);
+
+ /*
+ * check the lm verifier
+ */
+ E_old_pw_hash(new_lm_hash, lanman_pw, verifier);
+ if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
+ DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,
+ ("check_oem_password: password %s ok\n", *pp_new_passwd));
+#endif
+ *hnd = sampass;
+ return NT_STATUS_OK;
+ }
+
+ /* should not be reached */
+ TALLOC_FREE(sampass);
+ return NT_STATUS_WRONG_PASSWORD;
+}
+
+/***********************************************************
+ This routine takes the given password and checks it against
+ the password history. Returns True if this password has been
+ found in the history list.
+************************************************************/
+
+static bool check_passwd_history(struct samu *sampass, const char *plaintext)
+{
+ uchar new_nt_p16[NT_HASH_LEN];
+ uchar zero_md5_nt_pw[SALTED_MD5_HASH_LEN];
+ const uint8 *nt_pw;
+ const uint8 *pwhistory;
+ bool found = False;
+ int i;
+ uint32 pwHisLen, curr_pwHisLen;
+
+ pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHisLen);
+ if (pwHisLen == 0) {
+ return False;
+ }
+
+ pwhistory = pdb_get_pw_history(sampass, &curr_pwHisLen);
+ if (!pwhistory || curr_pwHisLen == 0) {
+ return False;
+ }
+
+ /* Only examine the minimum of the current history len and
+ the stored history len. Avoids race conditions. */
+ pwHisLen = MIN(pwHisLen,curr_pwHisLen);
+
+ nt_pw = pdb_get_nt_passwd(sampass);
+
+ E_md4hash(plaintext, new_nt_p16);
+
+ if (!memcmp(nt_pw, new_nt_p16, NT_HASH_LEN)) {
+ DEBUG(10,("check_passwd_history: proposed new password for user %s is the same as the current password !\n",
+ pdb_get_username(sampass) ));
+ return True;
+ }
+
+ dump_data(100, new_nt_p16, NT_HASH_LEN);
+ dump_data(100, pwhistory, PW_HISTORY_ENTRY_LEN*pwHisLen);
+
+ memset(zero_md5_nt_pw, '\0', SALTED_MD5_HASH_LEN);
+ for (i=0; i<pwHisLen; i++) {
+ uchar new_nt_pw_salted_md5_hash[SALTED_MD5_HASH_LEN];
+ const uchar *current_salt = &pwhistory[i*PW_HISTORY_ENTRY_LEN];
+ const uchar *old_nt_pw_salted_md5_hash = &pwhistory[(i*PW_HISTORY_ENTRY_LEN)+
+ PW_HISTORY_SALT_LEN];
+ if (!memcmp(zero_md5_nt_pw, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) {
+ /* Ignore zero valued entries. */
+ continue;
+ }
+ /* Create salted versions of new to compare. */
+ E_md5hash(current_salt, new_nt_p16, new_nt_pw_salted_md5_hash);
+
+ if (!memcmp(new_nt_pw_salted_md5_hash, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) {
+ DEBUG(1,("check_passwd_history: proposed new password for user %s found in history list !\n",
+ pdb_get_username(sampass) ));
+ found = True;
+ break;
+ }
+ }
+ return found;
+}
+
+/***********************************************************
+ Code to change the oem password. Changes both the lanman
+ and NT hashes. Old_passwd is almost always NULL.
+ NOTE this function is designed to be called as root. Check the old password
+ is correct before calling. JRA.
+************************************************************/
+
+NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passwd, bool as_root, uint32 *samr_reject_reason)
+{
+ uint32 min_len;
+ uint32 refuse;
+ struct passwd *pass = NULL;
+ const char *username = pdb_get_username(hnd);
+ time_t can_change_time = pdb_get_pass_can_change_time(hnd);
+
+ if (samr_reject_reason) {
+ *samr_reject_reason = Undefined;
+ }
+
+ /* check to see if the secdesc has previously been set to disallow */
+ if (!pdb_get_pass_can_change(hnd)) {
+ DEBUG(1, ("user %s does not have permissions to change password\n", username));
+ if (samr_reject_reason) {
+ *samr_reject_reason = SAMR_REJECT_OTHER;
+ }
+ return NT_STATUS_ACCOUNT_RESTRICTION;
+ }
+
+ /* check to see if it is a Machine account and if the policy
+ * denies machines to change the password. *
+ * Should we deny also SRVTRUST and/or DOMSTRUST ? .SSS. */
+ if (pdb_get_acct_ctrl(hnd) & ACB_WSTRUST) {
+ if (pdb_get_account_policy(AP_REFUSE_MACHINE_PW_CHANGE, &refuse) && refuse) {
+ DEBUG(1, ("Machine %s cannot change password now, "
+ "denied by Refuse Machine Password Change policy\n",
+ username));
+ if (samr_reject_reason) {
+ *samr_reject_reason = SAMR_REJECT_OTHER;
+ }
+ return NT_STATUS_ACCOUNT_RESTRICTION;
+ }
+ }
+
+ /* removed calculation here, becuase passdb now calculates
+ based on policy. jmcd */
+ if ((can_change_time != 0) && (time(NULL) < can_change_time)) {
+ DEBUG(1, ("user %s cannot change password now, must "
+ "wait until %s\n", username,
+ http_timestring(can_change_time)));
+ if (samr_reject_reason) {
+ *samr_reject_reason = SAMR_REJECT_OTHER;
+ }
+ return NT_STATUS_ACCOUNT_RESTRICTION;
+ }
+
+ if (pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) {
+ DEBUG(1, ("user %s cannot change password - password too short\n",
+ username));
+ DEBUGADD(1, (" account policy min password len = %d\n", min_len));
+ if (samr_reject_reason) {
+ *samr_reject_reason = SAMR_REJECT_TOO_SHORT;
+ }
+ return NT_STATUS_PASSWORD_RESTRICTION;
+/* return NT_STATUS_PWD_TOO_SHORT; */
+ }
+
+ if (check_passwd_history(hnd,new_passwd)) {
+ if (samr_reject_reason) {
+ *samr_reject_reason = SAMR_REJECT_IN_HISTORY;
+ }
+ return NT_STATUS_PASSWORD_RESTRICTION;
+ }
+
+ pass = Get_Pwnam_alloc(talloc_tos(), username);
+ if (!pass) {
+ DEBUG(1, ("change_oem_password: Username %s does not exist in system !?!\n", username));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* Use external script to check password complexity */
+ if (lp_check_password_script() && *(lp_check_password_script())) {
+ int check_ret;
+
+ check_ret = smbrunsecret(lp_check_password_script(), new_passwd);
+ DEBUG(5, ("change_oem_password: check password script (%s) returned [%d]\n", lp_check_password_script(), check_ret));
+
+ if (check_ret != 0) {
+ DEBUG(1, ("change_oem_password: check password script said new password is not good enough!\n"));
+ if (samr_reject_reason) {
+ *samr_reject_reason = SAMR_REJECT_COMPLEXITY;
+ }
+ TALLOC_FREE(pass);
+ return NT_STATUS_PASSWORD_RESTRICTION;
+ }
+ }
+
+ /*
+ * If unix password sync was requested, attempt to change
+ * the /etc/passwd database first. Return failure if this cannot
+ * be done.
+ *
+ * This occurs before the oem change, because we don't want to
+ * update it if chgpasswd failed.
+ *
+ * Conditional on lp_unix_password_sync() because we don't want
+ * to touch the unix db unless we have admin permission.
+ */
+
+ if(lp_unix_password_sync() &&
+ !chgpasswd(username, pass, old_passwd, new_passwd, as_root)) {
+ TALLOC_FREE(pass);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ TALLOC_FREE(pass);
+
+ if (!pdb_set_plaintext_passwd (hnd, new_passwd)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* Now write it into the file. */
+ return pdb_update_sam_account (hnd);
+}
diff --git a/source3/smbd/close.c b/source3/smbd/close.c
new file mode 100644
index 0000000000..818b4c70a8
--- /dev/null
+++ b/source3/smbd/close.c
@@ -0,0 +1,772 @@
+/*
+ Unix SMB/CIFS implementation.
+ file closing
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1992-2007.
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern struct current_user current_user;
+
+/****************************************************************************
+ Run a file if it is a magic script.
+****************************************************************************/
+
+static void check_magic(struct files_struct *fsp)
+{
+ int ret;
+ const char *magic_output = NULL;
+ SMB_STRUCT_STAT st;
+ int tmp_fd, outfd;
+ TALLOC_CTX *ctx = NULL;
+ const char *p;
+ struct connection_struct *conn = fsp->conn;
+
+ if (!*lp_magicscript(SNUM(conn))) {
+ return;
+ }
+
+ DEBUG(5,("checking magic for %s\n",fsp->fsp_name));
+
+ if (!(p = strrchr_m(fsp->fsp_name,'/'))) {
+ p = fsp->fsp_name;
+ } else {
+ p++;
+ }
+
+ if (!strequal(lp_magicscript(SNUM(conn)),p)) {
+ return;
+ }
+
+ ctx = talloc_stackframe();
+
+ if (*lp_magicoutput(SNUM(conn))) {
+ magic_output = lp_magicoutput(SNUM(conn));
+ } else {
+ magic_output = talloc_asprintf(ctx,
+ "%s.out",
+ fsp->fsp_name);
+ }
+ if (!magic_output) {
+ TALLOC_FREE(ctx);
+ return;
+ }
+
+ chmod(fsp->fsp_name,0755);
+ ret = smbrun(fsp->fsp_name,&tmp_fd);
+ DEBUG(3,("Invoking magic command %s gave %d\n",
+ fsp->fsp_name,ret));
+
+ unlink(fsp->fsp_name);
+ if (ret != 0 || tmp_fd == -1) {
+ if (tmp_fd != -1) {
+ close(tmp_fd);
+ }
+ TALLOC_FREE(ctx);
+ return;
+ }
+ outfd = open(magic_output, O_CREAT|O_EXCL|O_RDWR, 0600);
+ if (outfd == -1) {
+ close(tmp_fd);
+ TALLOC_FREE(ctx);
+ return;
+ }
+
+ if (sys_fstat(tmp_fd,&st) == -1) {
+ close(tmp_fd);
+ close(outfd);
+ return;
+ }
+
+ transfer_file(tmp_fd,outfd,(SMB_OFF_T)st.st_size);
+ close(tmp_fd);
+ close(outfd);
+ TALLOC_FREE(ctx);
+}
+
+/****************************************************************************
+ Common code to close a file or a directory.
+****************************************************************************/
+
+static NTSTATUS close_filestruct(files_struct *fsp)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ connection_struct *conn = fsp->conn;
+
+ if (fsp->fh->fd != -1) {
+ if(flush_write_cache(fsp, CLOSE_FLUSH) == -1) {
+ status = map_nt_error_from_unix(errno);
+ }
+ delete_write_cache(fsp);
+ }
+
+ conn->num_files_open--;
+ return status;
+}
+
+/****************************************************************************
+ If any deferred opens are waiting on this close, notify them.
+****************************************************************************/
+
+static void notify_deferred_opens(struct share_mode_lock *lck)
+{
+ int i;
+
+ for (i=0; i<lck->num_share_modes; i++) {
+ struct share_mode_entry *e = &lck->share_modes[i];
+
+ if (!is_deferred_open_entry(e)) {
+ continue;
+ }
+
+ if (procid_is_me(&e->pid)) {
+ /*
+ * We need to notify ourself to retry the open. Do
+ * this by finding the queued SMB record, moving it to
+ * the head of the queue and changing the wait time to
+ * zero.
+ */
+ schedule_deferred_open_smb_message(e->op_mid);
+ } else {
+ char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
+
+ share_mode_entry_to_message(msg, e);
+
+ messaging_send_buf(smbd_messaging_context(),
+ e->pid, MSG_SMB_OPEN_RETRY,
+ (uint8 *)msg,
+ MSG_SMB_SHARE_MODE_ENTRY_SIZE);
+ }
+ }
+}
+
+/****************************************************************************
+ Delete all streams
+****************************************************************************/
+
+static NTSTATUS delete_all_streams(connection_struct *conn, const char *fname)
+{
+ struct stream_struct *stream_info;
+ int i;
+ unsigned int num_streams;
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+
+ status = SMB_VFS_STREAMINFO(conn, NULL, fname, talloc_tos(),
+ &num_streams, &stream_info);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
+ DEBUG(10, ("no streams around\n"));
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("SMB_VFS_STREAMINFO failed: %s\n",
+ nt_errstr(status)));
+ goto fail;
+ }
+
+ DEBUG(10, ("delete_all_streams found %d streams\n",
+ num_streams));
+
+ if (num_streams == 0) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
+
+ for (i=0; i<num_streams; i++) {
+ int res;
+ char *streamname;
+
+ if (strequal(stream_info[i].name, "::$DATA")) {
+ continue;
+ }
+
+ streamname = talloc_asprintf(talloc_tos(), "%s%s", fname,
+ stream_info[i].name);
+
+ if (streamname == NULL) {
+ DEBUG(0, ("talloc_aprintf failed\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ res = SMB_VFS_UNLINK(conn, streamname);
+
+ TALLOC_FREE(streamname);
+
+ if (res == -1) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(10, ("Could not delete stream %s: %s\n",
+ streamname, strerror(errno)));
+ break;
+ }
+ }
+
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/****************************************************************************
+ Deal with removing a share mode on last close.
+****************************************************************************/
+
+static NTSTATUS close_remove_share_mode(files_struct *fsp,
+ enum file_close_type close_type)
+{
+ connection_struct *conn = fsp->conn;
+ bool delete_file = false;
+ bool changed_user = false;
+ struct share_mode_lock *lck;
+ SMB_STRUCT_STAT sbuf;
+ NTSTATUS status = NT_STATUS_OK;
+ int ret;
+ struct file_id id;
+
+ /*
+ * Lock the share entries, and determine if we should delete
+ * on close. If so delete whilst the lock is still in effect.
+ * This prevents race conditions with the file being created. JRA.
+ */
+
+ lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
+ NULL);
+
+ if (lck == NULL) {
+ DEBUG(0, ("close_remove_share_mode: Could not get share mode "
+ "lock for file %s\n", fsp->fsp_name));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (fsp->write_time_forced) {
+ set_close_write_time(fsp, lck->changed_write_time);
+ }
+
+ if (!del_share_mode(lck, fsp)) {
+ DEBUG(0, ("close_remove_share_mode: Could not delete share "
+ "entry for file %s\n", fsp->fsp_name));
+ }
+
+ if (fsp->initial_delete_on_close && (lck->delete_token == NULL)) {
+ bool became_user = False;
+
+ /* Initial delete on close was set and no one else
+ * wrote a real delete on close. */
+
+ if (current_user.vuid != fsp->vuid) {
+ become_user(conn, fsp->vuid);
+ became_user = True;
+ }
+ set_delete_on_close_lck(lck, True, &current_user.ut);
+ if (became_user) {
+ unbecome_user();
+ }
+ }
+
+ delete_file = lck->delete_on_close;
+
+ if (delete_file) {
+ int i;
+ /* See if others still have the file open. If this is the
+ * case, then don't delete. If all opens are POSIX delete now. */
+ for (i=0; i<lck->num_share_modes; i++) {
+ struct share_mode_entry *e = &lck->share_modes[i];
+ if (is_valid_share_mode_entry(e)) {
+ if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
+ continue;
+ }
+ delete_file = False;
+ break;
+ }
+ }
+ }
+
+ /* Notify any deferred opens waiting on this close. */
+ notify_deferred_opens(lck);
+ reply_to_oplock_break_requests(fsp);
+
+ /*
+ * NT can set delete_on_close of the last open
+ * reference to a file.
+ */
+
+ if (!(close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE)
+ || !delete_file
+ || (lck->delete_token == NULL)) {
+ TALLOC_FREE(lck);
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * Ok, we have to delete the file
+ */
+
+ DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set "
+ "- deleting file.\n", fsp->fsp_name));
+
+ /*
+ * Don't try to update the write time when we delete the file
+ */
+ fsp->update_write_time_on_close = false;
+
+ if (!unix_token_equal(lck->delete_token, &current_user.ut)) {
+ /* Become the user who requested the delete. */
+
+ DEBUG(5,("close_remove_share_mode: file %s. "
+ "Change user to uid %u\n",
+ fsp->fsp_name,
+ (unsigned int)lck->delete_token->uid));
+
+ if (!push_sec_ctx()) {
+ smb_panic("close_remove_share_mode: file %s. failed to push "
+ "sec_ctx.\n");
+ }
+
+ set_sec_ctx(lck->delete_token->uid,
+ lck->delete_token->gid,
+ lck->delete_token->ngroups,
+ lck->delete_token->groups,
+ NULL);
+
+ changed_user = true;
+ }
+
+ /* We can only delete the file if the name we have is still valid and
+ hasn't been renamed. */
+
+ if (fsp->posix_open) {
+ ret = SMB_VFS_LSTAT(conn,fsp->fsp_name,&sbuf);
+ } else {
+ ret = SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf);
+ }
+
+ if (ret != 0) {
+ DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
+ "was set and stat failed with error %s\n",
+ fsp->fsp_name, strerror(errno) ));
+ /*
+ * Don't save the errno here, we ignore this error
+ */
+ goto done;
+ }
+
+ id = vfs_file_id_from_sbuf(conn, &sbuf);
+
+ if (!file_id_equal(&fsp->file_id, &id)) {
+ DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
+ "was set and dev and/or inode does not match\n",
+ fsp->fsp_name ));
+ DEBUG(5,("close_remove_share_mode: file %s. stored file_id %s, "
+ "stat file_id %s\n",
+ fsp->fsp_name,
+ file_id_string_tos(&fsp->file_id),
+ file_id_string_tos(&id)));
+ /*
+ * Don't save the errno here, we ignore this error
+ */
+ goto done;
+ }
+
+ if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
+ && !is_ntfs_stream_name(fsp->fsp_name)) {
+
+ status = delete_all_streams(conn, fsp->fsp_name);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("delete_all_streams failed: %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+ }
+
+
+ if (SMB_VFS_UNLINK(conn,fsp->fsp_name) != 0) {
+ /*
+ * This call can potentially fail as another smbd may
+ * have had the file open with delete on close set and
+ * deleted it when its last reference to this file
+ * went away. Hence we log this but not at debug level
+ * zero.
+ */
+
+ DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
+ "was set and unlink failed with error %s\n",
+ fsp->fsp_name, strerror(errno) ));
+
+ status = map_nt_error_from_unix(errno);
+ }
+
+ notify_fname(conn, NOTIFY_ACTION_REMOVED,
+ FILE_NOTIFY_CHANGE_FILE_NAME,
+ fsp->fsp_name);
+
+ /* As we now have POSIX opens which can unlink
+ * with other open files we may have taken
+ * this code path with more than one share mode
+ * entry - ensure we only delete once by resetting
+ * the delete on close flag. JRA.
+ */
+
+ set_delete_on_close_lck(lck, False, NULL);
+
+ done:
+
+ if (changed_user) {
+ /* unbecome user. */
+ pop_sec_ctx();
+ }
+
+ TALLOC_FREE(lck);
+ return status;
+}
+
+void set_close_write_time(struct files_struct *fsp, struct timespec ts)
+{
+ DEBUG(6,("close_write_time: %s" , time_to_asc(convert_timespec_to_time_t(ts))));
+
+ if (null_timespec(ts)) {
+ return;
+ }
+ /*
+ * if the write time on close is explict set, then don't
+ * need to fix it up to the value in the locking db
+ */
+ fsp->write_time_forced = false;
+
+ fsp->update_write_time_on_close = true;
+ fsp->close_write_time = ts;
+}
+
+static NTSTATUS update_write_time_on_close(struct files_struct *fsp)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct timespec ts[2];
+ NTSTATUS status;
+
+ ZERO_STRUCT(sbuf);
+ ZERO_STRUCT(ts);
+
+ if (!fsp->update_write_time_on_close) {
+ return NT_STATUS_OK;
+ }
+
+ if (null_timespec(fsp->close_write_time)) {
+ fsp->close_write_time = timespec_current();
+ }
+
+ /* Ensure we have a valid stat struct for the source. */
+ if (fsp->fh->fd != -1) {
+ if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+ } else {
+ if (SMB_VFS_STAT(fsp->conn,fsp->fsp_name,&sbuf) == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+ }
+
+ if (!VALID_STAT(sbuf)) {
+ /* if it doesn't seem to be a real file */
+ return NT_STATUS_OK;
+ }
+
+ ts[1] = fsp->close_write_time;
+ status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name,
+ &sbuf, ts, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Close a file.
+
+ close_type can be NORMAL_CLOSE=0,SHUTDOWN_CLOSE,ERROR_CLOSE.
+ printing and magic scripts are only run on normal close.
+ delete on close is done on normal and shutdown close.
+****************************************************************************/
+
+static NTSTATUS close_normal_file(files_struct *fsp, enum file_close_type close_type)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ NTSTATUS saved_status1 = NT_STATUS_OK;
+ NTSTATUS saved_status2 = NT_STATUS_OK;
+ NTSTATUS saved_status3 = NT_STATUS_OK;
+ NTSTATUS saved_status4 = NT_STATUS_OK;
+ connection_struct *conn = fsp->conn;
+
+ if (fsp->aio_write_behind) {
+ /*
+ * If we're finishing write behind on a close we can get a write
+ * error here, we must remember this.
+ */
+ int ret = wait_for_aio_completion(fsp);
+ if (ret) {
+ saved_status1 = map_nt_error_from_unix(ret);
+ }
+ } else {
+ cancel_aio_by_fsp(fsp);
+ }
+
+ /*
+ * If we're flushing on a close we can get a write
+ * error here, we must remember this.
+ */
+
+ saved_status2 = close_filestruct(fsp);
+
+ if (fsp->print_file) {
+ print_fsp_end(fsp, close_type);
+ file_free(fsp);
+ return NT_STATUS_OK;
+ }
+
+ /* If this is an old DOS or FCB open and we have multiple opens on
+ the same handle we only have one share mode. Ensure we only remove
+ the share mode on the last close. */
+
+ if (fsp->fh->ref_count == 1) {
+ /* Should we return on error here... ? */
+ saved_status3 = close_remove_share_mode(fsp, close_type);
+ }
+
+ if(fsp->oplock_type) {
+ release_file_oplock(fsp);
+ }
+
+ locking_close_file(smbd_messaging_context(), fsp);
+
+ status = fd_close(fsp);
+
+ /* check for magic scripts */
+ if (close_type == NORMAL_CLOSE) {
+ check_magic(fsp);
+ }
+
+ /*
+ * Ensure pending modtime is set after close.
+ */
+
+ saved_status4 = update_write_time_on_close(fsp);
+
+ if (NT_STATUS_IS_OK(status)) {
+ if (!NT_STATUS_IS_OK(saved_status1)) {
+ status = saved_status1;
+ } else if (!NT_STATUS_IS_OK(saved_status2)) {
+ status = saved_status2;
+ } else if (!NT_STATUS_IS_OK(saved_status3)) {
+ status = saved_status3;
+ } else if (!NT_STATUS_IS_OK(saved_status4)) {
+ status = saved_status4;
+ }
+ }
+
+ DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
+ conn->server_info->unix_name,fsp->fsp_name,
+ conn->num_files_open,
+ nt_errstr(status) ));
+
+ file_free(fsp);
+ return status;
+}
+
+/****************************************************************************
+ Close a directory opened by an NT SMB call.
+****************************************************************************/
+
+static NTSTATUS close_directory(files_struct *fsp, enum file_close_type close_type)
+{
+ struct share_mode_lock *lck = 0;
+ bool delete_dir = False;
+ NTSTATUS status = NT_STATUS_OK;
+
+ /*
+ * NT can set delete_on_close of the last open
+ * reference to a directory also.
+ */
+
+ lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
+ NULL);
+
+ if (lck == NULL) {
+ DEBUG(0, ("close_directory: Could not get share mode lock for %s\n", fsp->fsp_name));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!del_share_mode(lck, fsp)) {
+ DEBUG(0, ("close_directory: Could not delete share entry for %s\n", fsp->fsp_name));
+ }
+
+ if (fsp->initial_delete_on_close) {
+ bool became_user = False;
+
+ /* Initial delete on close was set - for
+ * directories we don't care if anyone else
+ * wrote a real delete on close. */
+
+ if (current_user.vuid != fsp->vuid) {
+ become_user(fsp->conn, fsp->vuid);
+ became_user = True;
+ }
+ send_stat_cache_delete_message(fsp->fsp_name);
+ set_delete_on_close_lck(lck, True, &current_user.ut);
+ if (became_user) {
+ unbecome_user();
+ }
+ }
+
+ delete_dir = lck->delete_on_close;
+
+ if (delete_dir) {
+ int i;
+ /* See if others still have the dir open. If this is the
+ * case, then don't delete. If all opens are POSIX delete now. */
+ for (i=0; i<lck->num_share_modes; i++) {
+ struct share_mode_entry *e = &lck->share_modes[i];
+ if (is_valid_share_mode_entry(e)) {
+ if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
+ continue;
+ }
+ delete_dir = False;
+ break;
+ }
+ }
+ }
+
+ if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
+ delete_dir &&
+ lck->delete_token) {
+
+ /* Become the user who requested the delete. */
+
+ if (!push_sec_ctx()) {
+ smb_panic("close_directory: failed to push sec_ctx.\n");
+ }
+
+ set_sec_ctx(lck->delete_token->uid,
+ lck->delete_token->gid,
+ lck->delete_token->ngroups,
+ lck->delete_token->groups,
+ NULL);
+
+ TALLOC_FREE(lck);
+
+ status = rmdir_internals(talloc_tos(),
+ fsp->conn, fsp->fsp_name);
+
+ DEBUG(5,("close_directory: %s. Delete on close was set - "
+ "deleting directory returned %s.\n",
+ fsp->fsp_name, nt_errstr(status)));
+
+ /* unbecome user. */
+ pop_sec_ctx();
+
+ /*
+ * Ensure we remove any change notify requests that would
+ * now fail as the directory has been deleted.
+ */
+
+ if(NT_STATUS_IS_OK(status)) {
+ remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_DELETE_PENDING);
+ }
+ } else {
+ TALLOC_FREE(lck);
+ remove_pending_change_notify_requests_by_fid(
+ fsp, NT_STATUS_OK);
+ }
+
+ /*
+ * Do the code common to files and directories.
+ */
+ close_filestruct(fsp);
+ file_free(fsp);
+ return status;
+}
+
+/****************************************************************************
+ Close a files_struct.
+****************************************************************************/
+
+NTSTATUS close_file(files_struct *fsp, enum file_close_type close_type)
+{
+ NTSTATUS status;
+ struct files_struct *base_fsp = fsp->base_fsp;
+
+ if(fsp->is_directory) {
+ status = close_directory(fsp, close_type);
+ } else if (fsp->fake_file_handle != NULL) {
+ status = close_fake_file(fsp);
+ } else {
+ status = close_normal_file(fsp, close_type);
+ }
+
+ if ((base_fsp != NULL) && (close_type != SHUTDOWN_CLOSE)) {
+
+ /*
+ * fsp was a stream, the base fsp can't be a stream as well
+ *
+ * For SHUTDOWN_CLOSE this is not possible here, because
+ * SHUTDOWN_CLOSE only happens from files.c which walks the
+ * complete list of files. If we mess with more than one fsp
+ * those loops will become confused.
+ */
+
+ SMB_ASSERT(base_fsp->base_fsp == NULL);
+ close_file(base_fsp, close_type);
+ }
+
+ return status;
+}
+
+/****************************************************************************
+ Deal with an (authorized) message to close a file given the share mode
+ entry.
+****************************************************************************/
+
+void msg_close_file(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ files_struct *fsp = NULL;
+ struct share_mode_entry e;
+
+ message_to_share_mode_entry(&e, (char *)data->data);
+
+ if(DEBUGLVL(10)) {
+ char *sm_str = share_mode_str(NULL, 0, &e);
+ if (!sm_str) {
+ smb_panic("talloc failed");
+ }
+ DEBUG(10,("msg_close_file: got request to close share mode "
+ "entry %s\n", sm_str));
+ TALLOC_FREE(sm_str);
+ }
+
+ fsp = file_find_dif(e.id, e.share_file_id);
+ if (!fsp) {
+ DEBUG(10,("msg_close_file: failed to find file.\n"));
+ return;
+ }
+ close_file(fsp, NORMAL_CLOSE);
+}
diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c
new file mode 100644
index 0000000000..b9433bb965
--- /dev/null
+++ b/source3/smbd/conn.c
@@ -0,0 +1,329 @@
+/*
+ Unix SMB/CIFS implementation.
+ Manage connections_struct structures
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Alexander Bokovoy 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* The connections bitmap is expanded in increments of BITMAP_BLOCK_SZ. The
+ * maximum size of the bitmap is the largest positive integer, but you will hit
+ * the "max connections" limit, looong before that.
+ */
+#define BITMAP_BLOCK_SZ 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(BITMAP_BLOCK_SZ);
+}
+
+/****************************************************************************
+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->params->service == snum) {
+ return(True);
+ }
+ }
+ return(False);
+}
+
+/****************************************************************************
+ Find a conn given a cnum.
+****************************************************************************/
+
+connection_struct *conn_find(unsigned 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;
+ int find_offset = 1;
+
+find_again:
+ i = bitmap_find(bmap, find_offset);
+
+ if (i == -1) {
+ /* Expand the connections bitmap. */
+ int oldsz = bmap->n;
+ int newsz = bmap->n + BITMAP_BLOCK_SZ;
+ struct bitmap * nbmap;
+
+ if (newsz <= oldsz) {
+ /* Integer wrap. */
+ DEBUG(0,("ERROR! Out of connection structures\n"));
+ return NULL;
+ }
+
+ DEBUG(4,("resizing connections bitmap from %d to %d\n",
+ oldsz, newsz));
+
+ nbmap = bitmap_allocate(newsz);
+ if (!nbmap) {
+ DEBUG(0,("ERROR! malloc fail.\n"));
+ return NULL;
+ }
+
+ bitmap_copy(nbmap, bmap);
+ bitmap_free(bmap);
+
+ bmap = nbmap;
+ find_offset = oldsz; /* Start next search in the new portion. */
+
+ goto find_again;
+ }
+
+ /* The bitmap position is used below as the connection number
+ * conn->cnum). This ends up as the TID field in the SMB header,
+ * which is limited to 16 bits (we skip 0xffff which is the
+ * NULL TID).
+ */
+ if (i > 65534) {
+ DEBUG(0, ("Maximum connection limit reached\n"));
+ return NULL;
+ }
+
+ if (!(conn=TALLOC_ZERO_P(NULL, connection_struct)) ||
+ !(conn->params = TALLOC_P(conn, struct share_params))) {
+ DEBUG(0,("TALLOC_ZERO() failed!\n"));
+ TALLOC_FREE(conn);
+ return NULL;
+ }
+ conn->cnum = i;
+
+ bitmap_set(bmap, i);
+
+ num_open++;
+
+ string_set(&conn->dirpath,"");
+ string_set(&conn->connectpath,"");
+ string_set(&conn->origpath,"");
+
+ DLIST_ADD(Connections, conn);
+
+ return conn;
+}
+
+/****************************************************************************
+ Close all conn structures.
+return true if any were closed
+****************************************************************************/
+bool conn_close_all(void)
+{
+ connection_struct *conn, *next;
+ bool ret = false;
+ for (conn=Connections;conn;conn=next) {
+ next=conn->next;
+ set_current_service(conn, 0, True);
+ close_cnum(conn, conn->vuid);
+ ret = true;
+ }
+ return ret;
+}
+
+/****************************************************************************
+ Idle inactive connections.
+****************************************************************************/
+
+bool conn_idle_all(time_t t)
+{
+ int deadtime = lp_deadtime()*60;
+ pipes_struct *plist = NULL;
+ connection_struct *conn;
+
+ if (deadtime <= 0)
+ deadtime = DEFAULT_SMBD_TIMEOUT;
+
+ for (conn=Connections;conn;conn=conn->next) {
+
+ time_t age = t - conn->lastused;
+
+ /* Update if connection wasn't idle. */
+ if (conn->lastused != conn->lastused_count) {
+ conn->lastused = t;
+ conn->lastused_count = t;
+ }
+
+ /* close dirptrs on connections that are idle */
+ if (age > DPTR_IDLE_TIMEOUT) {
+ dptr_idlecnum(conn);
+ }
+
+ if (conn->num_files_open > 0 || age < deadtime) {
+ return False;
+ }
+ }
+
+ /*
+ * Check all pipes for any open handles. We cannot
+ * idle with a handle open.
+ */
+
+ for (plist = get_first_internal_pipe(); plist;
+ plist = get_next_internal_pipe(plist)) {
+ if (plist->pipe_handles && plist->pipe_handles->count) {
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Clear a vuid out of the validity cache, and as the 'owner' of a connection.
+****************************************************************************/
+
+void conn_clear_vuid_caches(uint16_t vuid)
+{
+ connection_struct *conn;
+
+ for (conn=Connections;conn;conn=conn->next) {
+ if (conn->vuid == vuid) {
+ conn->vuid = UID_FIELD_INVALID;
+ }
+ conn_clear_vuid_cache(conn, vuid);
+ }
+}
+
+/****************************************************************************
+ Free a conn structure - internal part.
+****************************************************************************/
+
+void conn_free_internal(connection_struct *conn)
+{
+ vfs_handle_struct *handle = NULL, *thandle = NULL;
+ struct trans_state *state = NULL;
+
+ /* Free vfs_connection_struct */
+ handle = conn->vfs_handles;
+ while(handle) {
+ DLIST_REMOVE(conn->vfs_handles, handle);
+ thandle = handle->next;
+ if (handle->free_data)
+ handle->free_data(&handle->data);
+ handle = thandle;
+ }
+
+ /* Free any pending transactions stored on this conn. */
+ for (state = conn->pending_trans; state; state = state->next) {
+ /* state->setup is a talloc child of state. */
+ SAFE_FREE(state->param);
+ SAFE_FREE(state->data);
+ }
+
+ free_namearray(conn->veto_list);
+ free_namearray(conn->hide_list);
+ free_namearray(conn->veto_oplock_list);
+ free_namearray(conn->aio_write_behind_list);
+
+ string_free(&conn->dirpath);
+ string_free(&conn->connectpath);
+ string_free(&conn->origpath);
+
+ ZERO_STRUCTP(conn);
+ talloc_destroy(conn);
+}
+
+/****************************************************************************
+ Free a conn structure.
+****************************************************************************/
+
+void conn_free(connection_struct *conn)
+{
+ DLIST_REMOVE(Connections, conn);
+
+ bitmap_clear(bmap, conn->cnum);
+
+ SMB_ASSERT(num_open > 0);
+ num_open--;
+
+ conn_free_internal(conn);
+}
+
+/****************************************************************************
+receive a smbcontrol message to forcibly unmount a share
+the message contains just a share name and all instances of that
+share are unmounted
+the special sharename '*' forces unmount of all shares
+****************************************************************************/
+void msg_force_tdis(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ connection_struct *conn, *next;
+ fstring sharename;
+
+ fstrcpy(sharename, (const char *)data->data);
+
+ if (strcmp(sharename, "*") == 0) {
+ DEBUG(1,("Forcing close of all shares\n"));
+ conn_close_all();
+ return;
+ }
+
+ for (conn=Connections;conn;conn=next) {
+ next=conn->next;
+ if (strequal(lp_servicename(SNUM(conn)), sharename)) {
+ DEBUG(1,("Forcing close of share %s cnum=%d\n",
+ sharename, conn->cnum));
+ close_cnum(conn, (uint16)-1);
+ }
+ }
+}
diff --git a/source3/smbd/connection.c b/source3/smbd/connection.c
new file mode 100644
index 0000000000..8dd5964f5f
--- /dev/null
+++ b/source3/smbd/connection.c
@@ -0,0 +1,332 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Delete a connection record.
+****************************************************************************/
+
+bool yield_connection(connection_struct *conn, const char *name)
+{
+ struct db_record *rec;
+ NTSTATUS status;
+
+ DEBUG(3,("Yielding connection to %s\n",name));
+
+ if (!(rec = connections_fetch_entry(NULL, conn, name))) {
+ DEBUG(0, ("connections_fetch_entry failed\n"));
+ return False;
+ }
+
+ status = rec->delete_rec(rec);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG( NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) ? 3 : 0,
+ ("deleting connection record returned %s\n",
+ nt_errstr(status)));
+ }
+
+ TALLOC_FREE(rec);
+ return NT_STATUS_IS_OK(status);
+}
+
+struct count_stat {
+ pid_t mypid;
+ int curr_connections;
+ const char *name;
+ bool Clear;
+};
+
+/****************************************************************************
+ Count the entries belonging to a service in the connection db.
+****************************************************************************/
+
+static int count_fn(struct db_record *rec,
+ const struct connections_key *ckey,
+ const struct connections_data *crec,
+ void *udp)
+{
+ struct count_stat *cs = (struct count_stat *)udp;
+
+ if (crec->cnum == -1) {
+ return 0;
+ }
+
+ /* If the pid was not found delete the entry from connections.tdb */
+
+ if (cs->Clear && !process_exists(crec->pid) && (errno == ESRCH)) {
+ NTSTATUS status;
+ DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n",
+ procid_str_static(&crec->pid), crec->cnum,
+ crec->servicename));
+
+ status = rec->delete_rec(rec);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("count_fn: tdb_delete failed with error %s\n",
+ nt_errstr(status)));
+ }
+ return 0;
+ }
+
+ if (strequal(crec->servicename, cs->name))
+ cs->curr_connections++;
+
+ return 0;
+}
+
+/****************************************************************************
+ Claim an entry in the connections database.
+****************************************************************************/
+
+int count_current_connections( const char *sharename, bool clear )
+{
+ struct count_stat cs;
+
+ cs.mypid = sys_getpid();
+ cs.curr_connections = 0;
+ cs.name = sharename;
+ cs.Clear = clear;
+
+ /*
+ * This has a race condition, but locking the chain before hand is worse
+ * as it leads to deadlock.
+ */
+
+ if (connections_forall(count_fn, &cs) == -1) {
+ DEBUG(0,("count_current_connections: traverse of "
+ "connections.tdb failed\n"));
+ return False;
+ }
+
+ return cs.curr_connections;
+}
+
+/****************************************************************************
+ Count the number of connections open across all shares.
+****************************************************************************/
+
+int count_all_current_connections(void)
+{
+ return count_current_connections(NULL, True /* clear stale entries */);
+}
+
+/****************************************************************************
+ Claim an entry in the connections database.
+****************************************************************************/
+
+bool claim_connection(connection_struct *conn, const char *name,
+ uint32 msg_flags)
+{
+ struct db_record *rec;
+ struct connections_data crec;
+ TDB_DATA dbuf;
+ NTSTATUS status;
+ char addr[INET6_ADDRSTRLEN];
+
+ DEBUG(5,("claiming [%s]\n", name));
+
+ if (!(rec = connections_fetch_entry(talloc_tos(), conn, name))) {
+ DEBUG(0, ("connections_fetch_entry failed\n"));
+ return False;
+ }
+
+ /* fill in the crec */
+ ZERO_STRUCT(crec);
+ crec.magic = 0x280267;
+ crec.pid = procid_self();
+ crec.cnum = conn?conn->cnum:-1;
+ if (conn) {
+ crec.uid = conn->server_info->utok.uid;
+ crec.gid = conn->server_info->utok.gid;
+ strlcpy(crec.servicename, lp_servicename(SNUM(conn)),
+ sizeof(crec.servicename));
+ }
+ crec.start = time(NULL);
+ crec.bcast_msg_flags = msg_flags;
+
+ strlcpy(crec.machine,get_remote_machine_name(),sizeof(crec.machine));
+ strlcpy(crec.addr,conn?conn->client_address:
+ client_addr(get_client_fd(),addr,sizeof(addr)),
+ sizeof(crec.addr));
+
+ dbuf.dptr = (uint8 *)&crec;
+ dbuf.dsize = sizeof(crec);
+
+ status = rec->store(rec, dbuf, TDB_REPLACE);
+
+ TALLOC_FREE(rec);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("claim_connection: tdb_store failed with error %s.\n",
+ nt_errstr(status)));
+ return False;
+ }
+
+ return True;
+}
+
+bool register_message_flags(bool doreg, uint32 msg_flags)
+{
+ struct db_record *rec;
+ struct connections_data *pcrec;
+ NTSTATUS status;
+
+ DEBUG(10,("register_message_flags: %s flags 0x%x\n",
+ doreg ? "adding" : "removing",
+ (unsigned int)msg_flags ));
+
+ if (!(rec = connections_fetch_entry(NULL, NULL, ""))) {
+ DEBUG(0, ("connections_fetch_entry failed\n"));
+ return False;
+ }
+
+ if (rec->value.dsize != sizeof(struct connections_data)) {
+ DEBUG(0,("register_message_flags: Got wrong record size\n"));
+ TALLOC_FREE(rec);
+ return False;
+ }
+
+ pcrec = (struct connections_data *)rec->value.dptr;
+ if (doreg)
+ pcrec->bcast_msg_flags |= msg_flags;
+ else
+ pcrec->bcast_msg_flags &= ~msg_flags;
+
+ status = rec->store(rec, rec->value, TDB_REPLACE);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("register_message_flags: tdb_store failed: %s.\n",
+ nt_errstr(status)));
+ TALLOC_FREE(rec);
+ return False;
+ }
+
+ DEBUG(10,("register_message_flags: new flags 0x%x\n",
+ (unsigned int)pcrec->bcast_msg_flags ));
+
+ TALLOC_FREE(rec);
+
+ return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static TDB_DATA* make_pipe_rec_key( struct pipe_open_rec *prec )
+{
+ TDB_DATA *kbuf = NULL;
+ fstring key_string;
+
+ if ( !prec )
+ return NULL;
+
+ if ( (kbuf = TALLOC_P(prec, TDB_DATA)) == NULL ) {
+ return NULL;
+ }
+
+ snprintf( key_string, sizeof(key_string), "%s/%d/%d",
+ prec->name, procid_to_pid(&prec->pid), prec->pnum );
+
+ *kbuf = string_term_tdb_data(talloc_strdup(prec, key_string));
+ if (kbuf->dptr == NULL )
+ return NULL;
+
+ return kbuf;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static void fill_pipe_open_rec( struct pipe_open_rec *prec, smb_np_struct *p )
+{
+ prec->pid = pid_to_procid(sys_getpid());
+ prec->pnum = p->pnum;
+ prec->uid = geteuid();
+ fstrcpy( prec->name, p->name );
+
+ return;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+bool store_pipe_opendb( smb_np_struct *p )
+{
+ struct db_record *dbrec;
+ struct pipe_open_rec *prec;
+ TDB_DATA *key;
+ TDB_DATA data;
+ bool ret = False;
+
+ if ( (prec = TALLOC_P( NULL, struct pipe_open_rec)) == NULL ) {
+ DEBUG(0,("store_pipe_opendb: talloc failed!\n"));
+ return False;
+ }
+
+ fill_pipe_open_rec( prec, p );
+ if ( (key = make_pipe_rec_key( prec )) == NULL ) {
+ goto done;
+ }
+
+ data.dptr = (uint8 *)prec;
+ data.dsize = sizeof(struct pipe_open_rec);
+
+ if (!(dbrec = connections_fetch_record(prec, *key))) {
+ DEBUG(0, ("connections_fetch_record failed\n"));
+ goto done;
+ }
+
+ ret = NT_STATUS_IS_OK(dbrec->store(dbrec, data, TDB_REPLACE));
+
+done:
+ TALLOC_FREE( prec );
+ return ret;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+bool delete_pipe_opendb( smb_np_struct *p )
+{
+ struct db_record *dbrec;
+ struct pipe_open_rec *prec;
+ TDB_DATA *key;
+ bool ret = False;
+
+ if ( (prec = TALLOC_P( NULL, struct pipe_open_rec)) == NULL ) {
+ DEBUG(0,("store_pipe_opendb: talloc failed!\n"));
+ return False;
+ }
+
+ fill_pipe_open_rec( prec, p );
+ if ( (key = make_pipe_rec_key( prec )) == NULL ) {
+ goto done;
+ }
+
+ if (!(dbrec = connections_fetch_record(prec, *key))) {
+ DEBUG(0, ("connections_fetch_record failed\n"));
+ goto done;
+ }
+
+ ret = NT_STATUS_IS_OK(dbrec->delete_rec(dbrec));
+
+done:
+ TALLOC_FREE( prec );
+ return ret;
+}
diff --git a/source3/smbd/dfree.c b/source3/smbd/dfree.c
new file mode 100644
index 0000000000..1ddcd48d40
--- /dev/null
+++ b/source3/smbd/dfree.c
@@ -0,0 +1,223 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Normalise for DOS usage.
+****************************************************************************/
+
+static void disk_norm(bool small_query, SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+{
+ /* check if the disk is beyond the max disk size */
+ SMB_BIG_UINT maxdisksize = lp_maxdisksize();
+ if (maxdisksize) {
+ /* convert to blocks - and don't overflow */
+ maxdisksize = ((maxdisksize*1024)/(*bsize))*1024;
+ if (*dsize > maxdisksize) *dsize = maxdisksize;
+ if (*dfree > maxdisksize) *dfree = maxdisksize-1;
+ /* the -1 should stop applications getting div by 0
+ errors */
+ }
+
+ if(small_query) {
+ while (*dfree > WORDMAX || *dsize > WORDMAX || *bsize < 512) {
+ *dfree /= 2;
+ *dsize /= 2;
+ *bsize *= 2;
+ /*
+ * Force max to fit in 16 bit fields.
+ */
+ if (*bsize > (WORDMAX*512)) {
+ *bsize = (WORDMAX*512);
+ if (*dsize > WORDMAX)
+ *dsize = WORDMAX;
+ if (*dfree > WORDMAX)
+ *dfree = WORDMAX;
+ break;
+ }
+ }
+ }
+}
+
+
+
+/****************************************************************************
+ Return number of 1K blocks available on a path and total number.
+****************************************************************************/
+
+SMB_BIG_UINT sys_disk_free(connection_struct *conn, const char *path, bool small_query,
+ SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+{
+ SMB_BIG_UINT dfree_retval;
+ SMB_BIG_UINT dfree_q = 0;
+ SMB_BIG_UINT bsize_q = 0;
+ SMB_BIG_UINT dsize_q = 0;
+ const char *dfree_command;
+
+ (*dfree) = (*dsize) = 0;
+ (*bsize) = 512;
+
+ /*
+ * If external disk calculation specified, use it.
+ */
+
+ dfree_command = lp_dfree_command(SNUM(conn));
+ if (dfree_command && *dfree_command) {
+ const char *p;
+ char **lines = NULL;
+ char *syscmd = NULL;
+
+ syscmd = talloc_asprintf(talloc_tos(),
+ "%s %s",
+ dfree_command,
+ path);
+
+ if (!syscmd) {
+ return (SMB_BIG_UINT)-1;
+ }
+
+ DEBUG (3, ("disk_free: Running command %s\n", syscmd));
+
+ lines = file_lines_pload(syscmd, NULL);
+ if (lines) {
+ char *line = lines[0];
+
+ DEBUG (3, ("Read input from dfree, \"%s\"\n", line));
+
+ *dsize = STR_TO_SMB_BIG_UINT(line, &p);
+ while (p && *p && isspace(*p))
+ p++;
+ if (p && *p)
+ *dfree = STR_TO_SMB_BIG_UINT(p, &p);
+ while (p && *p && isspace(*p))
+ p++;
+ if (p && *p)
+ *bsize = STR_TO_SMB_BIG_UINT(p, NULL);
+ else
+ *bsize = 1024;
+ file_lines_free(lines);
+ DEBUG (3, ("Parsed output of dfree, dsize=%u, dfree=%u, bsize=%u\n",
+ (unsigned int)*dsize, (unsigned int)*dfree, (unsigned int)*bsize));
+
+ if (!*dsize)
+ *dsize = 2048;
+ if (!*dfree)
+ *dfree = 1024;
+ } else {
+ DEBUG (0, ("disk_free: sys_popen() failed for command %s. Error was : %s\n",
+ syscmd, strerror(errno) ));
+ if (sys_fsusage(path, dfree, dsize) != 0) {
+ DEBUG (0, ("disk_free: sys_fsusage() failed. Error was : %s\n",
+ strerror(errno) ));
+ return (SMB_BIG_UINT)-1;
+ }
+ }
+ } else {
+ if (sys_fsusage(path, dfree, dsize) != 0) {
+ DEBUG (0, ("disk_free: sys_fsusage() failed. Error was : %s\n",
+ strerror(errno) ));
+ return (SMB_BIG_UINT)-1;
+ }
+ }
+
+ if (disk_quotas(path, &bsize_q, &dfree_q, &dsize_q)) {
+ (*bsize) = bsize_q;
+ (*dfree) = MIN(*dfree,dfree_q);
+ (*dsize) = MIN(*dsize,dsize_q);
+ }
+
+ /* FIXME : Any reason for this assumption ? */
+ if (*bsize < 256) {
+ DEBUG(5,("disk_free:Warning: bsize == %d < 256 . Changing to assumed correct bsize = 512\n",(int)*bsize));
+ *bsize = 512;
+ }
+
+ if ((*dsize)<1) {
+ static bool done = false;
+ if (!done) {
+ DEBUG(0,("WARNING: dfree is broken on this system\n"));
+ done=true;
+ }
+ *dsize = 20*1024*1024/(*bsize);
+ *dfree = MAX(1,*dfree);
+ }
+
+ disk_norm(small_query,bsize,dfree,dsize);
+
+ if ((*bsize) < 1024) {
+ dfree_retval = (*dfree)/(1024/(*bsize));
+ } else {
+ dfree_retval = ((*bsize)/1024)*(*dfree);
+ }
+
+ return(dfree_retval);
+}
+
+/****************************************************************************
+ Potentially returned cached dfree info.
+****************************************************************************/
+
+SMB_BIG_UINT get_dfree_info(connection_struct *conn,
+ const char *path,
+ bool small_query,
+ SMB_BIG_UINT *bsize,
+ SMB_BIG_UINT *dfree,
+ SMB_BIG_UINT *dsize)
+{
+ int dfree_cache_time = lp_dfree_cache_time(SNUM(conn));
+ struct dfree_cached_info *dfc = conn->dfree_info;
+ SMB_BIG_UINT dfree_ret;
+
+ if (!dfree_cache_time) {
+ return SMB_VFS_DISK_FREE(conn,path,small_query,bsize,dfree,dsize);
+ }
+
+ if (dfc && (conn->lastused - dfc->last_dfree_time < dfree_cache_time)) {
+ /* Return cached info. */
+ *bsize = dfc->bsize;
+ *dfree = dfc->dfree;
+ *dsize = dfc->dsize;
+ return dfc->dfree_ret;
+ }
+
+ dfree_ret = SMB_VFS_DISK_FREE(conn,path,small_query,bsize,dfree,dsize);
+
+ if (dfree_ret == (SMB_BIG_UINT)-1) {
+ /* Don't cache bad data. */
+ return dfree_ret;
+ }
+
+ /* No cached info or time to refresh. */
+ if (!dfc) {
+ dfc = TALLOC_P(conn, struct dfree_cached_info);
+ if (!dfc) {
+ return dfree_ret;
+ }
+ conn->dfree_info = dfc;
+ }
+
+ dfc->bsize = *bsize;
+ dfc->dfree = *dfree;
+ dfc->dsize = *dsize;
+ dfc->dfree_ret = dfree_ret;
+ dfc->last_dfree_time = conn->lastused;
+
+ return dfree_ret;
+}
diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
new file mode 100644
index 0000000000..c2735c032a
--- /dev/null
+++ b/source3/smbd/dir.c
@@ -0,0 +1,1316 @@
+/*
+ Unix SMB/CIFS implementation.
+ Directory handling routines
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*
+ This module implements directory related functions for Samba.
+*/
+
+/* "Special" directory offsets. */
+#define END_OF_DIRECTORY_OFFSET ((long)-1)
+#define START_OF_DIRECTORY_OFFSET ((long)0)
+#define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
+
+/* Make directory handle internals available. */
+
+struct name_cache_entry {
+ char *name;
+ long offset;
+};
+
+struct smb_Dir {
+ connection_struct *conn;
+ SMB_STRUCT_DIR *dir;
+ long offset;
+ char *dir_path;
+ size_t name_cache_size;
+ struct name_cache_entry *name_cache;
+ unsigned int name_cache_index;
+ unsigned int file_number;
+};
+
+struct dptr_struct {
+ struct dptr_struct *next, *prev;
+ int dnum;
+ uint16 spid;
+ struct connection_struct *conn;
+ struct smb_Dir *dir_hnd;
+ bool expect_close;
+ char *wcard;
+ uint32 attr;
+ char *path;
+ bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
+ bool did_stat; /* Optimisation for non-wcard searches. */
+};
+
+static struct bitmap *dptr_bmap;
+static struct dptr_struct *dirptrs;
+static int dirhandles_open = 0;
+
+#define INVALID_DPTR_KEY (-3)
+
+/****************************************************************************
+ Make a dir struct.
+****************************************************************************/
+
+bool make_dir_struct(TALLOC_CTX *ctx,
+ char *buf,
+ const char *mask,
+ const char *fname,
+ SMB_OFF_T size,
+ uint32 mode,
+ time_t date,
+ bool uc)
+{
+ char *p;
+ char *mask2 = talloc_strdup(ctx, mask);
+
+ if (!mask2) {
+ return False;
+ }
+
+ if ((mode & aDIR) != 0) {
+ size = 0;
+ }
+
+ memset(buf+1,' ',11);
+ if ((p = strchr_m(mask2,'.')) != NULL) {
+ *p = 0;
+ push_ascii(buf+1,mask2,8, 0);
+ push_ascii(buf+9,p+1,3, 0);
+ *p = '.';
+ } else {
+ push_ascii(buf+1,mask2,11, 0);
+ }
+
+ memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
+ SCVAL(buf,21,mode);
+ srv_put_dos_date(buf,22,date);
+ SSVAL(buf,26,size & 0xFFFF);
+ SSVAL(buf,28,(size >> 16)&0xFFFF);
+ /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
+ Strange, but verified on W2K3. Needed for OS/2. JRA. */
+ push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
+ DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
+ return True;
+}
+
+/****************************************************************************
+ Initialise the dir bitmap.
+****************************************************************************/
+
+void init_dptrs(void)
+{
+ static bool dptrs_init=False;
+
+ if (dptrs_init)
+ return;
+
+ dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
+
+ if (!dptr_bmap)
+ exit_server("out of memory in init_dptrs");
+
+ dptrs_init = True;
+}
+
+/****************************************************************************
+ Idle a dptr - the directory is closed but the control info is kept.
+****************************************************************************/
+
+static void dptr_idle(struct dptr_struct *dptr)
+{
+ if (dptr->dir_hnd) {
+ DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
+ TALLOC_FREE(dptr->dir_hnd);
+ }
+}
+
+/****************************************************************************
+ Idle the oldest dptr.
+****************************************************************************/
+
+static void dptr_idleoldest(void)
+{
+ struct dptr_struct *dptr;
+
+ /*
+ * Go to the end of the list.
+ */
+ for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
+ ;
+
+ if(!dptr) {
+ DEBUG(0,("No dptrs available to idle ?\n"));
+ return;
+ }
+
+ /*
+ * Idle the oldest pointer.
+ */
+
+ for(; dptr; dptr = dptr->prev) {
+ if (dptr->dir_hnd) {
+ dptr_idle(dptr);
+ return;
+ }
+ }
+}
+
+/****************************************************************************
+ Get the struct dptr_struct for a dir index.
+****************************************************************************/
+
+static struct dptr_struct *dptr_get(int key, bool forclose)
+{
+ struct dptr_struct *dptr;
+
+ for(dptr = dirptrs; dptr; dptr = dptr->next) {
+ if(dptr->dnum == key) {
+ if (!forclose && !dptr->dir_hnd) {
+ if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
+ dptr_idleoldest();
+ DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
+ if (!(dptr->dir_hnd = OpenDir(
+ NULL, dptr->conn, dptr->path,
+ dptr->wcard, dptr->attr))) {
+ DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
+ strerror(errno)));
+ return False;
+ }
+ }
+ DLIST_PROMOTE(dirptrs,dptr);
+ return dptr;
+ }
+ }
+ return(NULL);
+}
+
+/****************************************************************************
+ Get the dir path for a dir index.
+****************************************************************************/
+
+char *dptr_path(int key)
+{
+ struct dptr_struct *dptr = dptr_get(key, False);
+ if (dptr)
+ return(dptr->path);
+ return(NULL);
+}
+
+/****************************************************************************
+ Get the dir wcard for a dir index.
+****************************************************************************/
+
+char *dptr_wcard(int key)
+{
+ struct dptr_struct *dptr = dptr_get(key, False);
+ if (dptr)
+ return(dptr->wcard);
+ return(NULL);
+}
+
+/****************************************************************************
+ Get the dir attrib for a dir index.
+****************************************************************************/
+
+uint16 dptr_attr(int key)
+{
+ struct dptr_struct *dptr = dptr_get(key, False);
+ if (dptr)
+ return(dptr->attr);
+ return(0);
+}
+
+/****************************************************************************
+ Close a dptr (internal func).
+****************************************************************************/
+
+static void dptr_close_internal(struct dptr_struct *dptr)
+{
+ DEBUG(4,("closing dptr key %d\n",dptr->dnum));
+
+ DLIST_REMOVE(dirptrs, dptr);
+
+ /*
+ * Free the dnum in the bitmap. Remember the dnum value is always
+ * biased by one with respect to the bitmap.
+ */
+
+ if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
+ DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
+ dptr->dnum ));
+ }
+
+ bitmap_clear(dptr_bmap, dptr->dnum - 1);
+
+ TALLOC_FREE(dptr->dir_hnd);
+
+ /* Lanman 2 specific code */
+ SAFE_FREE(dptr->wcard);
+ string_set(&dptr->path,"");
+ SAFE_FREE(dptr);
+}
+
+/****************************************************************************
+ Close a dptr given a key.
+****************************************************************************/
+
+void dptr_close(int *key)
+{
+ struct dptr_struct *dptr;
+
+ if(*key == INVALID_DPTR_KEY)
+ return;
+
+ /* OS/2 seems to use -1 to indicate "close all directories" */
+ if (*key == -1) {
+ struct dptr_struct *next;
+ for(dptr = dirptrs; dptr; dptr = next) {
+ next = dptr->next;
+ dptr_close_internal(dptr);
+ }
+ *key = INVALID_DPTR_KEY;
+ return;
+ }
+
+ dptr = dptr_get(*key, True);
+
+ if (!dptr) {
+ DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
+ return;
+ }
+
+ dptr_close_internal(dptr);
+
+ *key = INVALID_DPTR_KEY;
+}
+
+/****************************************************************************
+ Close all dptrs for a cnum.
+****************************************************************************/
+
+void dptr_closecnum(connection_struct *conn)
+{
+ struct dptr_struct *dptr, *next;
+ for(dptr = dirptrs; dptr; dptr = next) {
+ next = dptr->next;
+ if (dptr->conn == conn)
+ dptr_close_internal(dptr);
+ }
+}
+
+/****************************************************************************
+ Idle all dptrs for a cnum.
+****************************************************************************/
+
+void dptr_idlecnum(connection_struct *conn)
+{
+ struct dptr_struct *dptr;
+ for(dptr = dirptrs; dptr; dptr = dptr->next) {
+ if (dptr->conn == conn && dptr->dir_hnd)
+ dptr_idle(dptr);
+ }
+}
+
+/****************************************************************************
+ Close a dptr that matches a given path, only if it matches the spid also.
+****************************************************************************/
+
+void dptr_closepath(char *path,uint16 spid)
+{
+ struct dptr_struct *dptr, *next;
+ for(dptr = dirptrs; dptr; dptr = next) {
+ next = dptr->next;
+ if (spid == dptr->spid && strequal(dptr->path,path))
+ dptr_close_internal(dptr);
+ }
+}
+
+/****************************************************************************
+ Try and close the oldest handle not marked for
+ expect close in the hope that the client has
+ finished with that one.
+****************************************************************************/
+
+static void dptr_close_oldest(bool old)
+{
+ struct dptr_struct *dptr;
+
+ /*
+ * Go to the end of the list.
+ */
+ for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
+ ;
+
+ if(!dptr) {
+ DEBUG(0,("No old dptrs available to close oldest ?\n"));
+ return;
+ }
+
+ /*
+ * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
+ * does not have expect_close set. If 'old' is false, close
+ * one of the new dnum handles.
+ */
+
+ for(; dptr; dptr = dptr->prev) {
+ if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
+ (!old && (dptr->dnum > 255))) {
+ dptr_close_internal(dptr);
+ return;
+ }
+ }
+}
+
+/****************************************************************************
+ Create a new dir ptr. If the flag old_handle is true then we must allocate
+ from the bitmap range 0 - 255 as old SMBsearch directory handles are only
+ one byte long. If old_handle is false we allocate from the range
+ 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
+ a directory handle is never zero.
+ wcard must not be zero.
+****************************************************************************/
+
+NTSTATUS dptr_create(connection_struct *conn, const char *path, bool old_handle, bool expect_close,uint16 spid,
+ const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
+{
+ struct dptr_struct *dptr = NULL;
+ struct smb_Dir *dir_hnd;
+ NTSTATUS status;
+
+ DEBUG(5,("dptr_create dir=%s\n", path));
+
+ if (!wcard) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = check_name(conn,path);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ dir_hnd = OpenDir(NULL, conn, path, wcard, attr);
+ if (!dir_hnd) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ string_set(&conn->dirpath,path);
+
+ if (dirhandles_open >= MAX_OPEN_DIRECTORIES) {
+ dptr_idleoldest();
+ }
+
+ dptr = SMB_MALLOC_P(struct dptr_struct);
+ if(!dptr) {
+ DEBUG(0,("malloc fail in dptr_create.\n"));
+ TALLOC_FREE(dir_hnd);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCTP(dptr);
+
+ if(old_handle) {
+
+ /*
+ * This is an old-style SMBsearch request. Ensure the
+ * value we return will fit in the range 1-255.
+ */
+
+ dptr->dnum = bitmap_find(dptr_bmap, 0);
+
+ if(dptr->dnum == -1 || dptr->dnum > 254) {
+
+ /*
+ * Try and close the oldest handle not marked for
+ * expect close in the hope that the client has
+ * finished with that one.
+ */
+
+ dptr_close_oldest(True);
+
+ /* Now try again... */
+ dptr->dnum = bitmap_find(dptr_bmap, 0);
+ if(dptr->dnum == -1 || dptr->dnum > 254) {
+ DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
+ SAFE_FREE(dptr);
+ TALLOC_FREE(dir_hnd);
+ return NT_STATUS_TOO_MANY_OPENED_FILES;
+ }
+ }
+ } else {
+
+ /*
+ * This is a new-style trans2 request. Allocate from
+ * a range that will return 256 - MAX_DIRECTORY_HANDLES.
+ */
+
+ dptr->dnum = bitmap_find(dptr_bmap, 255);
+
+ if(dptr->dnum == -1 || dptr->dnum < 255) {
+
+ /*
+ * Try and close the oldest handle close in the hope that
+ * the client has finished with that one. This will only
+ * happen in the case of the Win98 client bug where it leaks
+ * directory handles.
+ */
+
+ dptr_close_oldest(False);
+
+ /* Now try again... */
+ dptr->dnum = bitmap_find(dptr_bmap, 255);
+
+ if(dptr->dnum == -1 || dptr->dnum < 255) {
+ DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
+ SAFE_FREE(dptr);
+ TALLOC_FREE(dir_hnd);
+ return NT_STATUS_TOO_MANY_OPENED_FILES;
+ }
+ }
+ }
+
+ bitmap_set(dptr_bmap, dptr->dnum);
+
+ dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
+
+ string_set(&dptr->path,path);
+ dptr->conn = conn;
+ dptr->dir_hnd = dir_hnd;
+ dptr->spid = spid;
+ dptr->expect_close = expect_close;
+ dptr->wcard = SMB_STRDUP(wcard);
+ if (!dptr->wcard) {
+ bitmap_clear(dptr_bmap, dptr->dnum - 1);
+ SAFE_FREE(dptr);
+ TALLOC_FREE(dir_hnd);
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
+ dptr->has_wild = True;
+ } else {
+ dptr->has_wild = wcard_has_wild;
+ }
+
+ dptr->attr = attr;
+
+ DLIST_ADD(dirptrs, dptr);
+
+ DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
+ dptr->dnum,path,expect_close));
+
+ *dptr_ret = dptr;
+
+ return NT_STATUS_OK;
+}
+
+
+/****************************************************************************
+ Wrapper functions to access the lower level directory handles.
+****************************************************************************/
+
+int dptr_CloseDir(struct dptr_struct *dptr)
+{
+ DLIST_REMOVE(dirptrs, dptr);
+ TALLOC_FREE(dptr->dir_hnd);
+ return 0;
+}
+
+void dptr_SeekDir(struct dptr_struct *dptr, long offset)
+{
+ SeekDir(dptr->dir_hnd, offset);
+}
+
+long dptr_TellDir(struct dptr_struct *dptr)
+{
+ return TellDir(dptr->dir_hnd);
+}
+
+bool dptr_has_wild(struct dptr_struct *dptr)
+{
+ return dptr->has_wild;
+}
+
+int dptr_dnum(struct dptr_struct *dptr)
+{
+ return dptr->dnum;
+}
+
+/****************************************************************************
+ Return the next visible file name, skipping veto'd and invisible files.
+****************************************************************************/
+
+static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
+{
+ /* Normal search for the next file. */
+ const char *name;
+ while ((name = ReadDirName(dptr->dir_hnd, poffset)) != NULL) {
+ if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
+ return name;
+ }
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ Return the next visible file name, skipping veto'd and invisible files.
+****************************************************************************/
+
+const char *dptr_ReadDirName(TALLOC_CTX *ctx,
+ struct dptr_struct *dptr,
+ long *poffset,
+ SMB_STRUCT_STAT *pst)
+{
+ SET_STAT_INVALID(*pst);
+
+ if (dptr->has_wild) {
+ return dptr_normal_ReadDirName(dptr, poffset, pst);
+ }
+
+ /* If poffset is -1 then we know we returned this name before and we have
+ no wildcards. We're at the end of the directory. */
+ if (*poffset == END_OF_DIRECTORY_OFFSET) {
+ return NULL;
+ }
+
+ if (!dptr->did_stat) {
+ char *pathreal = NULL;
+
+ /* We know the stored wcard contains no wildcard characters. See if we can match
+ with a stat call. If we can't, then set did_stat to true to
+ ensure we only do this once and keep searching. */
+
+ dptr->did_stat = True;
+
+ /* First check if it should be visible. */
+ if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard, pst, True)) {
+ /* This only returns False if the file was found, but
+ is explicitly not visible. Set us to end of directory,
+ but return NULL as we know we can't ever find it. */
+ dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
+ return NULL;
+ }
+
+ if (VALID_STAT(*pst)) {
+ /* We need to set the underlying dir_hnd offset to -1 also as
+ this function is usually called with the output from TellDir. */
+ dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
+ return dptr->wcard;
+ }
+
+ pathreal = talloc_asprintf(ctx,
+ "%s/%s",
+ dptr->path,
+ dptr->wcard);
+ if (!pathreal) {
+ return NULL;
+ }
+
+ if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) {
+ /* We need to set the underlying dir_hnd offset to -1 also as
+ this function is usually called with the output from TellDir. */
+ dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
+ TALLOC_FREE(pathreal);
+ return dptr->wcard;
+ } else {
+ /* If we get any other error than ENOENT or ENOTDIR
+ then the file exists we just can't stat it. */
+ if (errno != ENOENT && errno != ENOTDIR) {
+ /* We need to set the underlying dir_hdn offset to -1 also as
+ this function is usually called with the output from TellDir. */
+ dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
+ TALLOC_FREE(pathreal);
+ return dptr->wcard;
+ }
+ }
+
+ TALLOC_FREE(pathreal);
+
+ /* Stat failed. We know this is authoratiative if we are
+ * providing case sensitive semantics or the underlying
+ * filesystem is case sensitive.
+ */
+
+ if (dptr->conn->case_sensitive ||
+ !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
+ /* We need to set the underlying dir_hnd offset to -1 also as
+ this function is usually called with the output from TellDir. */
+ dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
+ return NULL;
+ }
+ }
+ return dptr_normal_ReadDirName(dptr, poffset, pst);
+}
+
+/****************************************************************************
+ Search for a file by name, skipping veto'ed and not visible files.
+****************************************************************************/
+
+bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
+{
+ SET_STAT_INVALID(*pst);
+
+ if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
+ /* This is a singleton directory and we're already at the end. */
+ *poffset = END_OF_DIRECTORY_OFFSET;
+ return False;
+ }
+
+ return SearchDir(dptr->dir_hnd, name, poffset);
+}
+
+/****************************************************************************
+ Add the name we're returning into the underlying cache.
+****************************************************************************/
+
+void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset)
+{
+ DirCacheAdd(dptr->dir_hnd, name, offset);
+}
+
+/****************************************************************************
+ Fill the 5 byte server reserved dptr field.
+****************************************************************************/
+
+bool dptr_fill(char *buf1,unsigned int key)
+{
+ unsigned char *buf = (unsigned char *)buf1;
+ struct dptr_struct *dptr = dptr_get(key, False);
+ uint32 offset;
+ if (!dptr) {
+ DEBUG(1,("filling null dirptr %d\n",key));
+ return(False);
+ }
+ offset = (uint32)TellDir(dptr->dir_hnd);
+ DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
+ (long)dptr->dir_hnd,(int)offset));
+ buf[0] = key;
+ SIVAL(buf,1,offset);
+ return(True);
+}
+
+/****************************************************************************
+ Fetch the dir ptr and seek it given the 5 byte server field.
+****************************************************************************/
+
+struct dptr_struct *dptr_fetch(char *buf,int *num)
+{
+ unsigned int key = *(unsigned char *)buf;
+ struct dptr_struct *dptr = dptr_get(key, False);
+ uint32 offset;
+ long seekoff;
+
+ if (!dptr) {
+ DEBUG(3,("fetched null dirptr %d\n",key));
+ return(NULL);
+ }
+ *num = key;
+ offset = IVAL(buf,1);
+ if (offset == (uint32)-1) {
+ seekoff = END_OF_DIRECTORY_OFFSET;
+ } else {
+ seekoff = (long)offset;
+ }
+ SeekDir(dptr->dir_hnd,seekoff);
+ DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
+ key,dptr_path(key),(int)seekoff));
+ return(dptr);
+}
+
+/****************************************************************************
+ Fetch the dir ptr.
+****************************************************************************/
+
+struct dptr_struct *dptr_fetch_lanman2(int dptr_num)
+{
+ struct dptr_struct *dptr = dptr_get(dptr_num, False);
+
+ if (!dptr) {
+ DEBUG(3,("fetched null dirptr %d\n",dptr_num));
+ return(NULL);
+ }
+ DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
+ return(dptr);
+}
+
+/****************************************************************************
+ Check that a file matches a particular file type.
+****************************************************************************/
+
+bool dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
+{
+ uint32 mask;
+
+ /* Check the "may have" search bits. */
+ if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
+ return False;
+
+ /* Check the "must have" bits, which are the may have bits shifted eight */
+ /* If must have bit is set, the file/dir can not be returned in search unless the matching
+ file attribute is set */
+ mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
+ if(mask) {
+ if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask) /* check if matching attribute present */
+ return True;
+ else
+ return False;
+ }
+
+ return True;
+}
+
+static bool mangle_mask_match(connection_struct *conn,
+ const char *filename,
+ const char *mask)
+{
+ char mname[13];
+
+ if (!name_to_8_3(filename,mname,False,conn->params)) {
+ return False;
+ }
+ return mask_match_search(mname,mask,False);
+}
+
+/****************************************************************************
+ Get an 8.3 directory entry.
+****************************************************************************/
+
+bool get_dir_entry(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ const char *mask,
+ uint32 dirtype,
+ char **pp_fname_out,
+ SMB_OFF_T *size,
+ uint32 *mode,
+ time_t *date,
+ bool check_descend,
+ bool ask_sharemode)
+{
+ const char *dname = NULL;
+ bool found = False;
+ SMB_STRUCT_STAT sbuf;
+ char *pathreal = NULL;
+ const char *filename = NULL;
+ bool needslash;
+
+ *pp_fname_out = NULL;
+
+ needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
+
+ if (!conn->dirptr) {
+ return(False);
+ }
+
+ while (!found) {
+ long curoff = dptr_TellDir(conn->dirptr);
+ dname = dptr_ReadDirName(ctx, conn->dirptr, &curoff, &sbuf);
+
+ DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n",
+ (long)conn->dirptr,TellDir(conn->dirptr->dir_hnd)));
+
+ if (dname == NULL) {
+ return(False);
+ }
+
+ filename = dname;
+
+ /* notice the special *.* handling. This appears to be the only difference
+ between the wildcard handling in this routine and in the trans2 routines.
+ see masktest for a demo
+ */
+ if ((strcmp(mask,"*.*") == 0) ||
+ mask_match_search(filename,mask,False) ||
+ mangle_mask_match(conn,filename,mask)) {
+ char mname[13];
+
+ if (!mangle_is_8_3(filename, False, conn->params)) {
+ if (!name_to_8_3(filename,mname,False,
+ conn->params)) {
+ continue;
+ }
+ filename = mname;
+ }
+
+ if (needslash) {
+ pathreal = talloc_asprintf(ctx,
+ "%s/%s",
+ conn->dirpath,
+ dname);
+ } else {
+ pathreal = talloc_asprintf(ctx,
+ "%s%s",
+ conn->dirpath,
+ dname);
+ }
+ if (!pathreal) {
+ return False;
+ }
+
+ if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn, pathreal, &sbuf)) != 0) {
+ DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",
+ pathreal, strerror(errno) ));
+ TALLOC_FREE(pathreal);
+ continue;
+ }
+
+ *mode = dos_mode(conn,pathreal,&sbuf);
+
+ if (!dir_check_ftype(conn,*mode,dirtype)) {
+ DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",filename,(unsigned int)*mode,(unsigned int)dirtype));
+ TALLOC_FREE(pathreal);
+ continue;
+ }
+
+ *size = sbuf.st_size;
+ *date = sbuf.st_mtime;
+
+ if (ask_sharemode) {
+ struct timespec write_time_ts;
+ struct file_id fileid;
+
+ fileid = vfs_file_id_from_sbuf(conn, &sbuf);
+ get_file_infos(fileid, NULL, &write_time_ts);
+ if (!null_timespec(write_time_ts)) {
+ *date = convert_timespec_to_time_t(write_time_ts);
+ }
+ }
+
+ DEBUG(3,("get_dir_entry mask=[%s] found %s "
+ "fname=%s (%s)\n",
+ mask,
+ pathreal,
+ dname,
+ filename));
+
+ found = True;
+
+ *pp_fname_out = talloc_strdup(ctx, filename);
+ if (!*pp_fname_out) {
+ return False;
+ }
+
+ DirCacheAdd(conn->dirptr->dir_hnd, dname, curoff);
+ TALLOC_FREE(pathreal);
+ }
+ }
+
+ return(found);
+}
+
+/*******************************************************************
+ Check to see if a user can read a file. This is only approximate,
+ it is used as part of the "hide unreadable" option. Don't
+ use it for anything security sensitive.
+********************************************************************/
+
+static bool user_can_read_file(connection_struct *conn, char *name)
+{
+ /*
+ * If user is a member of the Admin group
+ * we never hide files from them.
+ */
+
+ if (conn->admin_user) {
+ return True;
+ }
+
+ return can_access_file_acl(conn, name, FILE_READ_DATA);
+}
+
+/*******************************************************************
+ Check to see if a user can write a file (and only files, we do not
+ check dirs on this one). This is only approximate,
+ it is used as part of the "hide unwriteable" option. Don't
+ use it for anything security sensitive.
+********************************************************************/
+
+static bool user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
+{
+ /*
+ * If user is a member of the Admin group
+ * we never hide files from them.
+ */
+
+ if (conn->admin_user) {
+ return True;
+ }
+
+ SMB_ASSERT(VALID_STAT(*pst));
+
+ /* Pseudo-open the file */
+
+ if(S_ISDIR(pst->st_mode)) {
+ return True;
+ }
+
+ return can_write_to_file(conn, name, pst);
+}
+
+/*******************************************************************
+ Is a file a "special" type ?
+********************************************************************/
+
+static bool file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
+{
+ /*
+ * If user is a member of the Admin group
+ * we never hide files from them.
+ */
+
+ if (conn->admin_user)
+ return False;
+
+ SMB_ASSERT(VALID_STAT(*pst));
+
+ if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Should the file be seen by the client ? NOTE: A successful return
+ is no guarantee of the file's existence ... you also have to check
+ whether pst is valid.
+********************************************************************/
+
+bool is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
+{
+ bool hide_unreadable = lp_hideunreadable(SNUM(conn));
+ bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
+ bool hide_special = lp_hide_special_files(SNUM(conn));
+
+ SET_STAT_INVALID(*pst);
+
+ if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
+ return True; /* . and .. are always visible. */
+ }
+
+ /* If it's a vetoed file, pretend it doesn't even exist */
+ if (use_veto && IS_VETO_PATH(conn, name)) {
+ DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
+ return False;
+ }
+
+ if (hide_unreadable || hide_unwriteable || hide_special) {
+ char *entry = NULL;
+
+ if (asprintf(&entry, "%s/%s", dir_path, name) == -1) {
+ return False;
+ }
+
+ /* If it's a dfs symlink, ignore _hide xxxx_ options */
+ if (lp_host_msdfs() &&
+ lp_msdfs_root(SNUM(conn)) &&
+ is_msdfs_link(conn, entry, NULL)) {
+ SAFE_FREE(entry);
+ return True;
+ }
+
+ /* If the file name does not exist, there's no point checking
+ * the configuration options. We succeed, on the basis that the
+ * checks *might* have passed if the file was present.
+ */
+ if (SMB_VFS_STAT(conn, entry, pst) != 0) {
+ SAFE_FREE(entry);
+ return True;
+ }
+
+ /* Honour _hide unreadable_ option */
+ if (hide_unreadable && !user_can_read_file(conn, entry)) {
+ DEBUG(10,("is_visible_file: file %s is unreadable.\n", entry ));
+ SAFE_FREE(entry);
+ return False;
+ }
+ /* Honour _hide unwriteable_ option */
+ if (hide_unwriteable && !user_can_write_file(conn, entry, pst)) {
+ DEBUG(10,("is_visible_file: file %s is unwritable.\n", entry ));
+ SAFE_FREE(entry);
+ return False;
+ }
+ /* Honour _hide_special_ option */
+ if (hide_special && file_is_special(conn, entry, pst)) {
+ DEBUG(10,("is_visible_file: file %s is special.\n", entry ));
+ SAFE_FREE(entry);
+ return False;
+ }
+ SAFE_FREE(entry);
+ }
+ return True;
+}
+
+static int smb_Dir_destructor(struct smb_Dir *dirp)
+{
+ if (dirp->dir) {
+ SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
+ }
+ dirhandles_open--;
+ return 0;
+}
+
+/*******************************************************************
+ Open a directory.
+********************************************************************/
+
+struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
+ const char *name, const char *mask, uint32 attr)
+{
+ struct smb_Dir *dirp = TALLOC_ZERO_P(mem_ctx, struct smb_Dir);
+
+ if (!dirp) {
+ return NULL;
+ }
+
+ dirp->conn = conn;
+ dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
+
+ dirp->dir_path = talloc_strdup(dirp, name);
+ if (!dirp->dir_path) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ dirhandles_open++;
+ talloc_set_destructor(dirp, smb_Dir_destructor);
+
+ dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
+ if (!dirp->dir) {
+ DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
+ strerror(errno) ));
+ goto fail;
+ }
+
+ return dirp;
+
+ fail:
+ TALLOC_FREE(dirp);
+ return NULL;
+}
+
+/*******************************************************************
+ Read from a directory. Also return current offset.
+ Don't check for veto or invisible files.
+********************************************************************/
+
+const char *ReadDirName(struct smb_Dir *dirp, long *poffset)
+{
+ const char *n;
+ connection_struct *conn = dirp->conn;
+
+ /* Cheat to allow . and .. to be the first entries returned. */
+ if (((*poffset == START_OF_DIRECTORY_OFFSET) || (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2)) {
+ if (dirp->file_number == 0) {
+ n = ".";
+ *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
+ } else {
+ *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
+ n = "..";
+ }
+ dirp->file_number++;
+ return n;
+ } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
+ *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
+ return NULL;
+ } else {
+ /* A real offset, seek to it. */
+ SeekDir(dirp, *poffset);
+ }
+
+ while ((n = vfs_readdirname(conn, dirp->dir))) {
+ /* Ignore . and .. - we've already returned them. */
+ if (*n == '.') {
+ if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
+ continue;
+ }
+ }
+ *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
+ dirp->file_number++;
+ return n;
+ }
+ *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
+ return NULL;
+}
+
+/*******************************************************************
+ Rewind to the start.
+********************************************************************/
+
+void RewindDir(struct smb_Dir *dirp, long *poffset)
+{
+ SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
+ dirp->file_number = 0;
+ dirp->offset = START_OF_DIRECTORY_OFFSET;
+ *poffset = START_OF_DIRECTORY_OFFSET;
+}
+
+/*******************************************************************
+ Seek a dir.
+********************************************************************/
+
+void SeekDir(struct smb_Dir *dirp, long offset)
+{
+ if (offset != dirp->offset) {
+ if (offset == START_OF_DIRECTORY_OFFSET) {
+ RewindDir(dirp, &offset);
+ /*
+ * Ok we should really set the file number here
+ * to 1 to enable ".." to be returned next. Trouble
+ * is I'm worried about callers using SeekDir(dirp,0)
+ * as equivalent to RewindDir(). So leave this alone
+ * for now.
+ */
+ } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
+ RewindDir(dirp, &offset);
+ /*
+ * Set the file number to 2 - we want to get the first
+ * real file entry (the one we return after "..")
+ * on the next ReadDir.
+ */
+ dirp->file_number = 2;
+ } else if (offset == END_OF_DIRECTORY_OFFSET) {
+ ; /* Don't seek in this case. */
+ } else {
+ SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
+ }
+ dirp->offset = offset;
+ }
+}
+
+/*******************************************************************
+ Tell a dir position.
+********************************************************************/
+
+long TellDir(struct smb_Dir *dirp)
+{
+ return(dirp->offset);
+}
+
+/*******************************************************************
+ Add an entry into the dcache.
+********************************************************************/
+
+void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
+{
+ struct name_cache_entry *e;
+
+ if (dirp->name_cache_size == 0) {
+ return;
+ }
+
+ if (dirp->name_cache == NULL) {
+ dirp->name_cache = TALLOC_ZERO_ARRAY(
+ dirp, struct name_cache_entry, dirp->name_cache_size);
+
+ if (dirp->name_cache == NULL) {
+ return;
+ }
+ }
+
+ dirp->name_cache_index = (dirp->name_cache_index+1) %
+ dirp->name_cache_size;
+ e = &dirp->name_cache[dirp->name_cache_index];
+ TALLOC_FREE(e->name);
+ e->name = talloc_strdup(dirp, name);
+ e->offset = offset;
+}
+
+/*******************************************************************
+ Find an entry by name. Leave us at the offset after it.
+ Don't check for veto or invisible files.
+********************************************************************/
+
+bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
+{
+ int i;
+ const char *entry;
+ connection_struct *conn = dirp->conn;
+
+ /* Search back in the name cache. */
+ if (dirp->name_cache_size && dirp->name_cache) {
+ for (i = dirp->name_cache_index; i >= 0; i--) {
+ struct name_cache_entry *e = &dirp->name_cache[i];
+ if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
+ *poffset = e->offset;
+ SeekDir(dirp, e->offset);
+ return True;
+ }
+ }
+ for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
+ struct name_cache_entry *e = &dirp->name_cache[i];
+ if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
+ *poffset = e->offset;
+ SeekDir(dirp, e->offset);
+ return True;
+ }
+ }
+ }
+
+ /* Not found in the name cache. Rewind directory and start from scratch. */
+ SMB_VFS_REWINDDIR(conn, dirp->dir);
+ dirp->file_number = 0;
+ *poffset = START_OF_DIRECTORY_OFFSET;
+ while ((entry = ReadDirName(dirp, poffset))) {
+ if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
+ return True;
+ }
+ }
+ return False;
+}
+
+/*****************************************************************
+ Is this directory empty ?
+*****************************************************************/
+
+NTSTATUS can_delete_directory(struct connection_struct *conn,
+ const char *dirname)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ long dirpos = 0;
+ const char *dname;
+ struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, dirname,
+ NULL, 0);
+
+ if (!dir_hnd) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ while ((dname = ReadDirName(dir_hnd,&dirpos))) {
+ SMB_STRUCT_STAT st;
+
+ /* Quick check for "." and ".." */
+ if (dname[0] == '.') {
+ if (!dname[1] || (dname[1] == '.' && !dname[2])) {
+ continue;
+ }
+ }
+
+ if (!is_visible_file(conn, dirname, dname, &st, True)) {
+ continue;
+ }
+
+ DEBUG(10,("can_delete_directory: got name %s - can't delete\n", dname ));
+ status = NT_STATUS_DIRECTORY_NOT_EMPTY;
+ break;
+ }
+ TALLOC_FREE(dir_hnd);
+
+ return status;
+}
diff --git a/source3/smbd/dmapi.c b/source3/smbd/dmapi.c
new file mode 100644
index 0000000000..1049c95a39
--- /dev/null
+++ b/source3/smbd/dmapi.c
@@ -0,0 +1,340 @@
+/*
+ Unix SMB/CIFS implementation.
+ DMAPI Support routines
+
+ Copyright (C) James Peach 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_DMAPI
+
+#ifndef USE_DMAPI
+
+uint32 dmapi_file_flags(const char * const path) { return 0; }
+bool dmapi_have_session(void) { return False; }
+const void * dmapi_get_current_session(void) { return NULL; }
+
+#else /* USE_DMAPI */
+
+#ifdef HAVE_XFS_DMAPI_H
+#include <xfs/dmapi.h>
+#elif defined(HAVE_SYS_DMI_H)
+#include <sys/dmi.h>
+#elif defined(HAVE_SYS_JFSDMAPI_H)
+#include <sys/jfsdmapi.h>
+#elif defined(HAVE_SYS_DMAPI_H)
+#include <sys/dmapi.h>
+#elif defined(HAVE_DMAPI_H)
+#include <dmapi.h>
+#endif
+
+#define DMAPI_SESSION_NAME "samba"
+#define DMAPI_TRACE 10
+
+static dm_sessid_t samba_dmapi_session = DM_NO_SESSION;
+static unsigned session_num;
+
+/*
+ Initialise DMAPI session. The session is persistant kernel state,
+ so it might already exist, in which case we merely want to
+ reconnect to it. This function should be called as root.
+*/
+static int dmapi_init_session(void)
+{
+ char buf[DM_SESSION_INFO_LEN];
+ size_t buflen;
+ uint nsessions = 5;
+ dm_sessid_t *sessions = NULL;
+ char *version;
+ char *session_name;
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+
+ int i, err;
+
+ if (session_num == 0) {
+ session_name = DMAPI_SESSION_NAME;
+ } else {
+ session_name = talloc_asprintf(tmp_ctx, "%s%u", DMAPI_SESSION_NAME,
+ session_num);
+ }
+
+ if (session_name == NULL) {
+ DEBUG(0,("Out of memory in dmapi_init_session\n"));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+
+ if (dm_init_service(&version) < 0) {
+ DEBUG(0, ("dm_init_service failed - disabling DMAPI\n"));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ ZERO_STRUCT(buf);
+
+ /* Fetch kernel DMAPI sessions until we get any of them */
+ do {
+ dm_sessid_t *new_sessions;
+ nsessions *= 2;
+ new_sessions = TALLOC_REALLOC_ARRAY(tmp_ctx, sessions,
+ dm_sessid_t, nsessions);
+ if (new_sessions == NULL) {
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ sessions = new_sessions;
+ err = dm_getall_sessions(nsessions, sessions, &nsessions);
+ } while (err == -1 && errno == E2BIG);
+
+ if (err == -1) {
+ DEBUGADD(DMAPI_TRACE,
+ ("failed to retrieve DMAPI sessions: %s\n",
+ strerror(errno)));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ /* Look through existing kernel DMAPI sessions to find out ours */
+ for (i = 0; i < nsessions; ++i) {
+ err = dm_query_session(sessions[i], sizeof(buf), buf, &buflen);
+ buf[sizeof(buf) - 1] = '\0';
+ if (err == 0 && strcmp(session_name, buf) == 0) {
+ samba_dmapi_session = sessions[i];
+ DEBUGADD(DMAPI_TRACE,
+ ("attached to existing DMAPI session "
+ "named '%s'\n", buf));
+ break;
+ }
+ }
+
+ /* No session already defined. */
+ if (samba_dmapi_session == DM_NO_SESSION) {
+ err = dm_create_session(DM_NO_SESSION,
+ session_name,
+ &samba_dmapi_session);
+ if (err < 0) {
+ DEBUGADD(DMAPI_TRACE,
+ ("failed to create new DMAPI session: %s\n",
+ strerror(errno)));
+ samba_dmapi_session = DM_NO_SESSION;
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ DEBUG(0, ("created new DMAPI session named '%s' for %s\n",
+ session_name, version));
+ }
+
+ if (samba_dmapi_session != DM_NO_SESSION) {
+ set_effective_capability(DMAPI_ACCESS_CAPABILITY);
+ }
+
+ /*
+ Note that we never end the DMAPI session. It gets re-used if possiblie.
+ DMAPI session is a kernel resource that is usually lives until server reboot
+ and doesn't get destroed when an application finishes.
+
+ However, we free list of references to DMAPI sessions we've got from the kernel
+ as it is not needed anymore once we have found (or created) our session.
+ */
+
+ talloc_free(tmp_ctx);
+ return 0;
+}
+
+/*
+ Return a pointer to our DMAPI session, if available.
+ This assumes that you have called dmapi_have_session() first.
+*/
+const void *dmapi_get_current_session(void)
+{
+ if (samba_dmapi_session == DM_NO_SESSION) {
+ return NULL;
+ }
+
+ return (void *)&samba_dmapi_session;
+}
+
+/*
+ dmapi_have_session() must be the first DMAPI call you make in Samba. It will
+ initialize DMAPI, if available, and tell you if you can get a DMAPI session.
+ This should be called in the client-specific child process.
+*/
+
+bool dmapi_have_session(void)
+{
+ static bool initialized;
+ if (!initialized) {
+ initialized = true;
+
+ become_root();
+ dmapi_init_session();
+ unbecome_root();
+
+ }
+
+ return samba_dmapi_session != DM_NO_SESSION;
+}
+
+/*
+ only call this when you get back an EINVAL error indicating that the
+ session you are using is invalid. This destroys the existing session
+ and creates a new one.
+ */
+bool dmapi_new_session(void)
+{
+ if (dmapi_have_session()) {
+ /* try to destroy the old one - this may not succeed */
+ dm_destroy_session(samba_dmapi_session);
+ }
+ samba_dmapi_session = DM_NO_SESSION;
+ become_root();
+ session_num++;
+ dmapi_init_session();
+ unbecome_root();
+ return samba_dmapi_session != DM_NO_SESSION;
+}
+
+/*
+ only call this when exiting from master smbd process. DMAPI sessions
+ are long-lived kernel resources we ought to share across smbd processes.
+ However, we must free them when all smbd processes are finished to
+ allow other subsystems clean up properly. Not freeing DMAPI session
+ blocks certain HSM implementations from proper shutdown.
+*/
+bool dmapi_destroy_session(void)
+{
+ if (samba_dmapi_session != DM_NO_SESSION) {
+ become_root();
+ if (0 == dm_destroy_session(samba_dmapi_session)) {
+ session_num--;
+ samba_dmapi_session = DM_NO_SESSION;
+ } else {
+ DEBUG(0,("Couldn't destroy DMAPI session: %s\n",
+ strerror(errno)));
+ }
+ unbecome_root();
+ }
+ return samba_dmapi_session == DM_NO_SESSION;
+}
+
+
+/*
+ This is default implementation of dmapi_file_flags() that is
+ called from VFS is_offline() call to know whether file is offline.
+ For GPFS-specific version see modules/vfs_tsmsm.c. It might be
+ that approach on quering existence of a specific attribute that
+ is used in vfs_tsmsm.c will work with other DMAPI-based HSM
+ implementations as well.
+*/
+uint32 dmapi_file_flags(const char * const path)
+{
+ int err;
+ dm_eventset_t events = {0};
+ uint nevents;
+
+ dm_sessid_t dmapi_session;
+ const void *dmapi_session_ptr;
+ void *dm_handle = NULL;
+ size_t dm_handle_len = 0;
+
+ uint32 flags = 0;
+
+ dmapi_session_ptr = dmapi_get_current_session();
+ if (dmapi_session_ptr == NULL) {
+ return 0;
+ }
+
+ dmapi_session = *(dm_sessid_t *)dmapi_session_ptr;
+ if (dmapi_session == DM_NO_SESSION) {
+ return 0;
+ }
+
+ /* AIX has DMAPI but no POSIX capablities support. In this case,
+ * we need to be root to do DMAPI manipulations.
+ */
+#ifndef HAVE_POSIX_CAPABILITIES
+ become_root();
+#endif
+
+ err = dm_path_to_handle(CONST_DISCARD(char *, path),
+ &dm_handle, &dm_handle_len);
+ if (err < 0) {
+ DEBUG(DMAPI_TRACE, ("dm_path_to_handle(%s): %s\n",
+ path, strerror(errno)));
+
+ if (errno != EPERM) {
+ goto done;
+ }
+
+ /* Linux capabilities are broken in that changing our
+ * user ID will clobber out effective capabilities irrespective
+ * of whether we have set PR_SET_KEEPCAPS. Fortunately, the
+ * capabilities are not removed from our permitted set, so we
+ * can re-acquire them if necessary.
+ */
+
+ set_effective_capability(DMAPI_ACCESS_CAPABILITY);
+
+ err = dm_path_to_handle(CONST_DISCARD(char *, path),
+ &dm_handle, &dm_handle_len);
+ if (err < 0) {
+ DEBUG(DMAPI_TRACE,
+ ("retrying dm_path_to_handle(%s): %s\n",
+ path, strerror(errno)));
+ goto done;
+ }
+ }
+
+ err = dm_get_eventlist(dmapi_session, dm_handle, dm_handle_len,
+ DM_NO_TOKEN, DM_EVENT_MAX, &events, &nevents);
+ if (err < 0) {
+ DEBUG(DMAPI_TRACE, ("dm_get_eventlist(%s): %s\n",
+ path, strerror(errno)));
+ dm_handle_free(dm_handle, dm_handle_len);
+ goto done;
+ }
+
+ /* We figure that the only reason a DMAPI application would be
+ * interested in trapping read events is that part of the file is
+ * offline.
+ */
+ DEBUG(DMAPI_TRACE, ("DMAPI event list for %s\n", path));
+ if (DMEV_ISSET(DM_EVENT_READ, events)) {
+ flags = FILE_ATTRIBUTE_OFFLINE;
+ }
+
+ dm_handle_free(dm_handle, dm_handle_len);
+
+ if (flags & FILE_ATTRIBUTE_OFFLINE) {
+ DEBUG(DMAPI_TRACE, ("%s is OFFLINE\n", path));
+ }
+
+done:
+
+#ifndef HAVE_POSIX_CAPABILITIES
+ unbecome_root();
+#endif
+
+ return flags;
+}
+
+
+#endif /* USE_DMAPI */
diff --git a/source3/smbd/dnsregister.c b/source3/smbd/dnsregister.c
new file mode 100644
index 0000000000..2319097ca5
--- /dev/null
+++ b/source3/smbd/dnsregister.c
@@ -0,0 +1,212 @@
+/*
+ Unix SMB/CIFS implementation.
+ DNS-SD registration
+ Copyright (C) Rishi Srivatsavai 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <includes.h>
+
+/* Uses DNS service discovery (libdns_sd) to
+ * register the SMB service. SMB service is registered
+ * on ".local" domain via Multicast DNS & any
+ * other unicast DNS domains available.
+ *
+ * Users use the smbclient -B (Browse) option to
+ * browse for advertised SMB services.
+ */
+
+#define DNS_REG_RETRY_INTERVAL (5*60) /* in seconds */
+
+#ifdef WITH_DNSSD_SUPPORT
+
+#include <dns_sd.h>
+
+struct dns_reg_state {
+ DNSServiceRef srv_ref;
+ struct timed_event *retry_handler;
+};
+
+void dns_register_close(struct dns_reg_state **dns_state_ptr)
+{
+ struct dns_reg_state *dns_state = *dns_state_ptr;
+
+ if (dns_state == NULL) {
+ return;
+ }
+
+ if (dns_state->srv_ref != NULL) {
+ /* Close connection to the mDNS daemon */
+ DNSServiceRefDeallocate(dns_state->srv_ref);
+ dns_state->srv_ref = NULL;
+ }
+
+ /* Clear event handler */
+ if (dns_state->retry_handler != NULL) {
+ TALLOC_FREE(dns_state->retry_handler);
+ dns_state->retry_handler = NULL;
+ }
+
+ talloc_free(dns_state);
+ *dns_state_ptr = NULL;
+}
+
+static void dns_register_smbd_retry(struct event_context *ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ struct dns_reg_state *dns_state = (struct dns_reg_state *)private_data;
+
+ /* Clear previous registration state to force new
+ * registration attempt. Clears event handler.
+ */
+ dns_register_close(&dns_state);
+}
+
+static void schedule_dns_register_smbd_retry(struct dns_reg_state *dns_state,
+ struct timeval *timeout)
+{
+ struct timed_event * event;
+
+ dns_state->srv_ref = NULL;
+ event= event_add_timed(smbd_event_context(),
+ NULL,
+ timeval_current_ofs(DNS_REG_RETRY_INTERVAL, 0),
+ "DNS registration handler",
+ dns_register_smbd_retry,
+ dns_state);
+
+ dns_state->retry_handler = event;
+ get_timed_events_timeout(smbd_event_context(), timeout);
+}
+
+/* Kick off a mDNS request to register the "_smb._tcp" on the specified port.
+ * We really ought to register on all the ports we are listening on. This will
+ * have to be an exercise for some-one who knows the DNS registration API a bit
+ * better.
+ */
+void dns_register_smbd(struct dns_reg_state ** dns_state_ptr,
+ unsigned port,
+ int *maxfd,
+ fd_set *listen_set,
+ struct timeval *timeout)
+{
+ int mdnsd_conn_fd;
+ DNSServiceErrorType err;
+ struct dns_reg_state *dns_state = *dns_state_ptr;
+
+ if (dns_state == NULL) {
+ *dns_state_ptr = dns_state = talloc(NULL, struct dns_reg_state);
+ if (dns_state == NULL) {
+ return;
+ }
+ }
+
+ /* Quit if a re-try attempt has been scheduled. */
+ if (dns_state->retry_handler != NULL) {
+ return;
+ }
+
+ /* If a registration is active add conn
+ * fd to select listen_set and return
+ */
+ if (dns_state->srv_ref != NULL) {
+ mdnsd_conn_fd = DNSServiceRefSockFD(dns_state->srv_ref);
+ FD_SET(mdnsd_conn_fd, listen_set);
+ return;
+ }
+
+ DEBUG(6, ("registering _smb._tcp service on port %d\n", port));
+
+ /* Register service with DNS. Connects with the mDNS
+ * daemon running on the local system to perform DNS
+ * service registration.
+ */
+ err = DNSServiceRegister(&dns_state->srv_ref, 0 /* flags */,
+ kDNSServiceInterfaceIndexAny,
+ NULL /* service name */,
+ "_smb._tcp" /* service type */,
+ NULL /* domain */,
+ "" /* SRV target host name */,
+ htons(port),
+ 0 /* TXT record len */,
+ NULL /* TXT record data */,
+ NULL /* callback func */,
+ NULL /* callback context */);
+
+ if (err != kDNSServiceErr_NoError) {
+ /* Failed to register service. Schedule a re-try attempt.
+ */
+ DEBUG(3, ("unable to register with mDNS (err %d)\n", err));
+ schedule_dns_register_smbd_retry(dns_state, timeout);
+ return;
+ }
+
+ mdnsd_conn_fd = DNSServiceRefSockFD(dns_state->srv_ref);
+ FD_SET(mdnsd_conn_fd, listen_set);
+ *maxfd = MAX(*maxfd, mdnsd_conn_fd);
+ *timeout = timeval_zero();
+
+}
+
+/* Processes reply from mDNS daemon. Returns true if a reply was received */
+bool dns_register_smbd_reply(struct dns_reg_state *dns_state,
+ fd_set *lfds, struct timeval *timeout)
+{
+ int mdnsd_conn_fd = -1;
+
+ if (dns_state->srv_ref == NULL) {
+ return false;
+ }
+
+ mdnsd_conn_fd = DNSServiceRefSockFD(dns_state->srv_ref);
+
+ /* Process reply from daemon. Handles any errors. */
+ if ((mdnsd_conn_fd != -1) && (FD_ISSET(mdnsd_conn_fd,lfds)) ) {
+ DNSServiceErrorType err;
+
+ err = DNSServiceProcessResult(dns_state->srv_ref);
+ if (err != kDNSServiceErr_NoError) {
+ DEBUG(3, ("failed to process mDNS result (err %d), re-trying\n",
+ err));
+ schedule_dns_register_smbd_retry(dns_state, timeout);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+#else /* WITH_DNSSD_SUPPORT */
+
+ void dns_register_smbd(struct dns_reg_state ** dns_state_ptr,
+ unsigned port,
+ int *maxfd,
+ fd_set *listen_set,
+ struct timeval *timeout)
+{}
+
+ void dns_register_close(struct dns_reg_state ** dns_state_ptr)
+{}
+
+ bool dns_register_smbd_reply(struct dns_reg_state *dns_state,
+ fd_set *lfds, struct timeval *timeout)
+{
+ return false;
+}
+
+#endif /* WITH_DNSSD_SUPPORT */
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
new file mode 100644
index 0000000000..88c6a51770
--- /dev/null
+++ b/source3/smbd/dosmode.c
@@ -0,0 +1,666 @@
+/*
+ Unix SMB/CIFS implementation.
+ dos mode handling functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) James Peach 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
+{
+#if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
+ if (sbuf->st_size > sbuf->st_blocks * (SMB_OFF_T)STAT_ST_BLOCKSIZE) {
+ return FILE_ATTRIBUTE_SPARSE;
+ }
+#endif
+ return 0;
+}
+
+/****************************************************************************
+ Change a dos mode to a unix mode.
+ Base permission for files:
+ if creating file and inheriting (i.e. parent_dir != NULL)
+ apply read/write bits from parent directory.
+ else
+ everybody gets read bit set
+ dos readonly is represented in unix by removing everyone's write bit
+ dos archive is represented in unix by the user's execute bit
+ dos system is represented in unix by the group's execute bit
+ dos hidden is represented in unix by the other's execute bit
+ if !inheriting {
+ Then apply create mask,
+ then add force bits.
+ }
+ Base permission for directories:
+ dos directory is represented in unix by unix's dir bit and the exec bit
+ if !inheriting {
+ Then apply create mask,
+ then add force bits.
+ }
+****************************************************************************/
+
+mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname,
+ const char *inherit_from_dir)
+{
+ mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
+ mode_t dir_mode = 0; /* Mode of the inherit_from directory if
+ * inheriting. */
+
+ if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
+ result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+ }
+
+ if (fname && (inherit_from_dir != NULL)
+ && lp_inherit_perms(SNUM(conn))) {
+ SMB_STRUCT_STAT sbuf;
+
+ DEBUG(2, ("unix_mode(%s) inheriting from %s\n", fname,
+ inherit_from_dir));
+ if (SMB_VFS_STAT(conn, inherit_from_dir, &sbuf) != 0) {
+ DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n", fname,
+ inherit_from_dir, strerror(errno)));
+ return(0); /* *** shouldn't happen! *** */
+ }
+
+ /* Save for later - but explicitly remove setuid bit for safety. */
+ dir_mode = sbuf.st_mode & ~S_ISUID;
+ DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode));
+ /* Clear "result" */
+ result = 0;
+ }
+
+ if (IS_DOS_DIR(dosmode)) {
+ /* We never make directories read only for the owner as under DOS a user
+ can always create a file in a read-only directory. */
+ result |= (S_IFDIR | S_IWUSR);
+
+ if (dir_mode) {
+ /* Inherit mode of parent directory. */
+ result |= dir_mode;
+ } else {
+ /* Provisionally add all 'x' bits */
+ result |= (S_IXUSR | S_IXGRP | S_IXOTH);
+
+ /* Apply directory mask */
+ result &= lp_dir_mask(SNUM(conn));
+ /* Add in force bits */
+ result |= lp_force_dir_mode(SNUM(conn));
+ }
+ } else {
+ if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
+ result |= S_IXUSR;
+
+ if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
+ result |= S_IXGRP;
+
+ if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
+ result |= S_IXOTH;
+
+ if (dir_mode) {
+ /* Inherit 666 component of parent directory mode */
+ result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
+ } else {
+ /* Apply mode mask */
+ result &= lp_create_mask(SNUM(conn));
+ /* Add in force bits */
+ result |= lp_force_create_mode(SNUM(conn));
+ }
+ }
+
+ DEBUG(3,("unix_mode(%s) returning 0%o\n",fname,(int)result ));
+ return(result);
+}
+
+/****************************************************************************
+ Change a unix mode to a dos mode.
+****************************************************************************/
+
+static uint32 dos_mode_from_sbuf(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
+{
+ int result = 0;
+ enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
+
+ if (ro_opts == MAP_READONLY_YES) {
+ /* Original Samba method - map inverse of user "w" bit. */
+ if ((sbuf->st_mode & S_IWUSR) == 0) {
+ result |= aRONLY;
+ }
+ } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
+ /* Check actual permissions for read-only. */
+ if (!can_write_to_file(conn, path, sbuf)) {
+ result |= aRONLY;
+ }
+ } /* Else never set the readonly bit. */
+
+ 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);
+
+ result |= set_sparse_flag(sbuf);
+
+#ifdef S_ISLNK
+#if LINKS_READ_ONLY
+ if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
+ result |= aRONLY;
+#endif
+#endif
+
+ DEBUG(8,("dos_mode_from_sbuf 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;
+}
+
+/****************************************************************************
+ Get DOS attributes from an EA.
+****************************************************************************/
+
+static bool get_ea_dos_attribute(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf, uint32 *pattr)
+{
+ ssize_t sizeret;
+ fstring attrstr;
+ unsigned int dosattr;
+
+ if (!lp_store_dos_attributes(SNUM(conn))) {
+ return False;
+ }
+
+ /* Don't reset pattr to zero as we may already have filename-based attributes we
+ need to preserve. */
+
+ sizeret = SMB_VFS_GETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, sizeof(attrstr));
+ if (sizeret == -1) {
+#if defined(ENOTSUP) && defined(ENOATTR)
+ if ((errno != ENOTSUP) && (errno != ENOATTR) && (errno != EACCES) && (errno != EPERM)) {
+ DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n",
+ path, strerror(errno) ));
+ set_store_dos_attributes(SNUM(conn), False);
+ }
+#endif
+ return False;
+ }
+ /* Null terminate string. */
+ attrstr[sizeret] = 0;
+ DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path, attrstr));
+
+ if (sizeret < 2 || attrstr[0] != '0' || attrstr[1] != 'x' ||
+ sscanf(attrstr, "%x", &dosattr) != 1) {
+ DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path, attrstr));
+ return False;
+ }
+
+ if (S_ISDIR(sbuf->st_mode)) {
+ dosattr |= aDIR;
+ }
+ *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK);
+
+ DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
+
+ if (dosattr & aHIDDEN) DEBUG(8, ("h"));
+ if (dosattr & aRONLY ) DEBUG(8, ("r"));
+ if (dosattr & aSYSTEM) DEBUG(8, ("s"));
+ if (dosattr & aDIR ) DEBUG(8, ("d"));
+ if (dosattr & aARCH ) DEBUG(8, ("a"));
+
+ DEBUG(8,("\n"));
+
+ return True;
+}
+
+/****************************************************************************
+ Set DOS attributes in an EA.
+****************************************************************************/
+
+static bool set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, uint32 dosmode)
+{
+ fstring attrstr;
+ files_struct *fsp = NULL;
+ bool ret = False;
+
+ if (!lp_store_dos_attributes(SNUM(conn))) {
+ return False;
+ }
+
+ snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK);
+ if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) {
+ if((errno != EPERM) && (errno != EACCES)) {
+ if (errno == ENOSYS
+#if defined(ENOTSUP)
+ || errno == ENOTSUP) {
+#else
+ ) {
+#endif
+ set_store_dos_attributes(SNUM(conn), False);
+ }
+ return False;
+ }
+
+ /* We want DOS semantics, ie allow non owner with write permission to change the
+ bits on a file. Just like file_ntimes below.
+ */
+
+ /* Check if we have write access. */
+ if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
+ return False;
+
+ /*
+ * We need to open the file with write access whilst
+ * still in our current user context. This ensures we
+ * are not violating security in doing the setxattr.
+ */
+
+ if (!NT_STATUS_IS_OK(open_file_fchmod(conn,path,sbuf,&fsp)))
+ return ret;
+ become_root();
+ if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == 0) {
+ ret = True;
+ }
+ unbecome_root();
+ close_file_fchmod(fsp);
+ return ret;
+ }
+ DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, path));
+ return True;
+}
+
+/****************************************************************************
+ Change a unix mode to a dos mode for an ms dfs link.
+****************************************************************************/
+
+uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
+{
+ uint32 result = 0;
+
+ DEBUG(8,("dos_mode_msdfs: %s\n", path));
+
+ if (!VALID_STAT(*sbuf)) {
+ return 0;
+ }
+
+ /* First do any modifications that depend on the path name. */
+ /* hide files with a name starting with a . */
+ if (lp_hide_dot_files(SNUM(conn))) {
+ const char *p = strrchr_m(path,'/');
+ if (p) {
+ p++;
+ } else {
+ p = path;
+ }
+
+ if (p[0] == '.' && p[1] != '.' && p[1] != 0) {
+ result |= aHIDDEN;
+ }
+ }
+
+ result |= dos_mode_from_sbuf(conn, path, sbuf);
+
+ /* 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_msdfs 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"));
+ if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
+
+ DEBUG(8,("\n"));
+
+ return(result);
+}
+
+/****************************************************************************
+ Change a unix mode to a dos mode.
+****************************************************************************/
+
+uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
+{
+ uint32 result = 0;
+ bool offline;
+
+ DEBUG(8,("dos_mode: %s\n", path));
+
+ if (!VALID_STAT(*sbuf)) {
+ return 0;
+ }
+
+ /* First do any modifications that depend on the path name. */
+ /* hide files with a name starting with a . */
+ if (lp_hide_dot_files(SNUM(conn))) {
+ const char *p = strrchr_m(path,'/');
+ if (p) {
+ p++;
+ } else {
+ p = path;
+ }
+
+ if (p[0] == '.' && p[1] != '.' && p[1] != 0) {
+ result |= aHIDDEN;
+ }
+ }
+
+ /* Get the DOS attributes from an EA by preference. */
+ if (get_ea_dos_attribute(conn, path, sbuf, &result)) {
+ result |= set_sparse_flag(sbuf);
+ } else {
+ result |= dos_mode_from_sbuf(conn, path, sbuf);
+ }
+
+
+ offline = SMB_VFS_IS_OFFLINE(conn, path, sbuf);
+ if (S_ISREG(sbuf->st_mode) && offline) {
+ result |= FILE_ATTRIBUTE_OFFLINE;
+ }
+
+ /* 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"));
+ if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
+
+ DEBUG(8,("\n"));
+
+ return(result);
+}
+
+/*******************************************************************
+ chmod a file - but preserve some bits.
+********************************************************************/
+
+int file_set_dosmode(connection_struct *conn, const char *fname,
+ uint32 dosmode, SMB_STRUCT_STAT *st,
+ const char *parent_dir,
+ bool newfile)
+{
+ SMB_STRUCT_STAT st1;
+ int mask=0;
+ mode_t tmp;
+ mode_t unixmode;
+ int ret = -1, lret = -1;
+ uint32_t old_mode;
+
+ /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
+ dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
+
+ DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname));
+
+ if (st == NULL) {
+ SET_STAT_INVALID(st1);
+ st = &st1;
+ }
+
+ if (!VALID_STAT(*st)) {
+ if (SMB_VFS_STAT(conn,fname,st))
+ return(-1);
+ }
+
+ unixmode = st->st_mode;
+
+ get_acl_group_bits(conn, fname, &st->st_mode);
+
+ if (S_ISDIR(st->st_mode))
+ dosmode |= aDIR;
+ else
+ dosmode &= ~aDIR;
+
+ old_mode = dos_mode(conn,fname,st);
+
+ if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
+ if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
+ lret = SMB_VFS_SET_OFFLINE(conn, fname);
+ if (lret == -1) {
+ DEBUG(0, ("set_dos_mode: client has asked to set "
+ "FILE_ATTRIBUTE_OFFLINE to %s/%s but there was "
+ "an error while setting it or it is not supported.\n",
+ parent_dir, fname));
+ }
+ }
+ }
+
+ dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
+ old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
+
+ if (old_mode == dosmode) {
+ st->st_mode = unixmode;
+ return(0);
+ }
+
+ /* Store the DOS attributes in an EA by preference. */
+ if (set_ea_dos_attribute(conn, fname, st, dosmode)) {
+ if (!newfile) {
+ notify_fname(conn, NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
+ }
+ st->st_mode = unixmode;
+ return 0;
+ }
+
+ unixmode = unix_mode(conn,dosmode,fname, parent_dir);
+
+ /* preserve the s bits */
+ mask |= (S_ISUID | S_ISGID);
+
+ /* preserve the t bit */
+#ifdef S_ISVTX
+ mask |= S_ISVTX;
+#endif
+
+ /* possibly preserve the x bits */
+ if (!MAP_ARCHIVE(conn))
+ mask |= S_IXUSR;
+ if (!MAP_SYSTEM(conn))
+ mask |= S_IXGRP;
+ if (!MAP_HIDDEN(conn))
+ mask |= S_IXOTH;
+
+ unixmode |= (st->st_mode & mask);
+
+ /* if we previously had any r bits set then leave them alone */
+ if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
+ unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
+ unixmode |= tmp;
+ }
+
+ /* if we previously had any w bits set then leave them alone
+ whilst adding in the new w bits, if the new mode is not rdonly */
+ if (!IS_DOS_READONLY(dosmode)) {
+ unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
+ }
+
+ ret = SMB_VFS_CHMOD(conn, fname, unixmode);
+ if (ret == 0) {
+ if(!newfile || (lret != -1)) {
+ notify_fname(conn, NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
+ }
+ st->st_mode = unixmode;
+ return 0;
+ }
+
+ if((errno != EPERM) && (errno != EACCES))
+ return -1;
+
+ if(!lp_dos_filemode(SNUM(conn)))
+ return -1;
+
+ /* We want DOS semantics, ie allow non owner with write permission to change the
+ bits on a file. Just like file_ntimes below.
+ */
+
+ /* Check if we have write access. */
+ if (CAN_WRITE(conn)) {
+ /*
+ * We need to open the file with write access whilst
+ * still in our current user context. This ensures we
+ * are not violating security in doing the fchmod.
+ * This file open does *not* break any oplocks we are
+ * holding. We need to review this.... may need to
+ * break batch oplocks open by others. JRA.
+ */
+ files_struct *fsp;
+ if (!NT_STATUS_IS_OK(open_file_fchmod(conn,fname,st,&fsp)))
+ return -1;
+ become_root();
+ ret = SMB_VFS_FCHMOD(fsp, unixmode);
+ unbecome_root();
+ close_file_fchmod(fsp);
+ if (!newfile) {
+ notify_fname(conn, NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
+ }
+ if (ret == 0) {
+ st->st_mode = unixmode;
+ }
+ }
+
+ return( ret );
+}
+
+/*******************************************************************
+ Wrapper around the VFS ntimes that possibly allows DOS semantics rather
+ than POSIX.
+*******************************************************************/
+
+int file_ntimes(connection_struct *conn, const char *fname, const struct timespec ts[2])
+{
+ SMB_STRUCT_STAT sbuf;
+ int ret = -1;
+
+ errno = 0;
+ ZERO_STRUCT(sbuf);
+
+ DEBUG(6, ("file_ntime: actime: %s",
+ time_to_asc(convert_timespec_to_time_t(ts[0]))));
+ DEBUG(6, ("file_ntime: modtime: %s",
+ time_to_asc(convert_timespec_to_time_t(ts[1]))));
+
+ /* Don't update the time on read-only shares */
+ /* We need this as set_filetime (which can be called on
+ close and other paths) can end up calling this function
+ without the NEED_WRITE protection. Found by :
+ Leo Weppelman <leo@wau.mis.ah.nl>
+ */
+
+ if (!CAN_WRITE(conn)) {
+ return 0;
+ }
+
+ if(SMB_VFS_NTIMES(conn, fname, ts) == 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).
+ */
+
+ /* Check if we have write access. */
+ if (can_write_to_file(conn, fname, &sbuf)) {
+ /* We are allowed to become root and change the filetime. */
+ become_root();
+ ret = SMB_VFS_NTIMES(conn, fname, ts);
+ unbecome_root();
+ }
+
+ return ret;
+}
+
+/******************************************************************
+ Force a "sticky" write time on a pathname. This will always be
+ returned on all future write time queries and set on close.
+******************************************************************/
+
+bool set_sticky_write_time_path(connection_struct *conn, const char *fname,
+ struct file_id fileid, const struct timespec mtime)
+{
+ if (null_timespec(mtime)) {
+ return true;
+ }
+
+ if (!set_sticky_write_time(fileid, mtime)) {
+ return false;
+ }
+
+ return true;
+}
+
+/******************************************************************
+ Force a "sticky" write time on an fsp. This will always be
+ returned on all future write time queries and set on close.
+******************************************************************/
+
+bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime)
+{
+ fsp->write_time_forced = true;
+ TALLOC_FREE(fsp->update_write_time_event);
+
+ return set_sticky_write_time_path(fsp->conn, fsp->fsp_name,
+ fsp->file_id, mtime);
+}
+
+/******************************************************************
+ Update a write time immediately, without the 2 second delay.
+******************************************************************/
+
+bool update_write_time(struct files_struct *fsp)
+{
+ if (!set_write_time(fsp->file_id, timespec_current())) {
+ return false;
+ }
+
+ notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name);
+
+ return true;
+}
diff --git a/source3/smbd/error.c b/source3/smbd/error.c
new file mode 100644
index 0000000000..de2de088ec
--- /dev/null
+++ b/source3/smbd/error.c
@@ -0,0 +1,169 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* From lib/error.c */
+extern struct unix_error_map unix_dos_nt_errmap[];
+
+extern uint32 global_client_caps;
+
+bool use_nt_status(void)
+{
+ return lp_nt_status_support() && (global_client_caps & CAP_STATUS32);
+}
+
+/****************************************************************************
+ Create an error packet. Normally called using the ERROR() macro.
+ Setting eclass and ecode only and status to NT_STATUS_OK forces DOS errors.
+ Setting status only and eclass and ecode to zero forces NT errors.
+ If the override errors are set they take precedence over any passed in values.
+****************************************************************************/
+
+void error_packet_set(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file)
+{
+ bool force_nt_status = False;
+ bool force_dos_status = False;
+
+ if (eclass == (uint8)-1) {
+ force_nt_status = True;
+ } else if (NT_STATUS_IS_DOS(ntstatus)) {
+ force_dos_status = True;
+ }
+
+ if (force_nt_status || (!force_dos_status && lp_nt_status_support() && (global_client_caps & CAP_STATUS32))) {
+ /* We're returning an NT error. */
+ if (NT_STATUS_V(ntstatus) == 0 && eclass) {
+ ntstatus = dos_to_ntstatus(eclass, ecode);
+ }
+ SIVAL(outbuf,smb_rcls,NT_STATUS_V(ntstatus));
+ SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2)|FLAGS2_32_BIT_ERROR_CODES);
+ DEBUG(3,("error packet at %s(%d) cmd=%d (%s) %s\n",
+ file, line,
+ (int)CVAL(outbuf,smb_com),
+ smb_fn_name(CVAL(outbuf,smb_com)),
+ nt_errstr(ntstatus)));
+ } else {
+ /* We're returning a DOS error only. */
+ if (NT_STATUS_IS_DOS(ntstatus)) {
+ eclass = NT_STATUS_DOS_CLASS(ntstatus);
+ ecode = NT_STATUS_DOS_CODE(ntstatus);
+ } else if (eclass == 0 && NT_STATUS_V(ntstatus)) {
+ ntstatus_to_dos(ntstatus, &eclass, &ecode);
+ }
+
+ SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2)&~FLAGS2_32_BIT_ERROR_CODES);
+ SSVAL(outbuf,smb_rcls,eclass);
+ SSVAL(outbuf,smb_err,ecode);
+
+ DEBUG(3,("error packet at %s(%d) cmd=%d (%s) eclass=%d ecode=%d\n",
+ file, line,
+ (int)CVAL(outbuf,smb_com),
+ smb_fn_name(CVAL(outbuf,smb_com)),
+ eclass,
+ ecode));
+ }
+}
+
+int error_packet(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file)
+{
+ int outsize = srv_set_message(outbuf,0,0,True);
+ error_packet_set(outbuf, eclass, ecode, ntstatus, line, file);
+ return outsize;
+}
+
+void reply_nt_error(struct smb_request *req, NTSTATUS ntstatus,
+ int line, const char *file)
+{
+ TALLOC_FREE(req->outbuf);
+ reply_outbuf(req, 0, 0);
+ error_packet_set((char *)req->outbuf, 0, 0, ntstatus, line, file);
+}
+
+void reply_force_nt_error(struct smb_request *req, NTSTATUS ntstatus,
+ int line, const char *file)
+{
+ TALLOC_FREE(req->outbuf);
+ reply_outbuf(req, 0, 0);
+ error_packet_set((char *)req->outbuf, -1, -1, ntstatus, line, file);
+}
+
+void reply_dos_error(struct smb_request *req, uint8 eclass, uint32 ecode,
+ int line, const char *file)
+{
+ TALLOC_FREE(req->outbuf);
+ reply_outbuf(req, 0, 0);
+ error_packet_set((char *)req->outbuf, eclass, ecode, NT_STATUS_OK, line,
+ file);
+}
+
+void reply_both_error(struct smb_request *req, uint8 eclass, uint32 ecode,
+ NTSTATUS status, int line, const char *file)
+{
+ TALLOC_FREE(req->outbuf);
+ reply_outbuf(req, 0, 0);
+ error_packet_set((char *)req->outbuf, eclass, ecode, status,
+ line, file);
+}
+
+void reply_openerror(struct smb_request *req, NTSTATUS status)
+{
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+ /*
+ * We hit an existing file, and if we're returning DOS
+ * error codes OBJECT_NAME_COLLISION would map to
+ * ERRDOS/183, we need to return ERRDOS/80, see bug
+ * 4852.
+ */
+ reply_botherror(req, NT_STATUS_OBJECT_NAME_COLLISION,
+ ERRDOS, ERRfilexists);
+ } else {
+ reply_nterror(req, status);
+ }
+}
+
+void reply_unix_error(struct smb_request *req, uint8 defclass, uint32 defcode,
+ NTSTATUS defstatus, int line, const char *file)
+{
+ int eclass=defclass;
+ int ecode=defcode;
+ NTSTATUS ntstatus = defstatus;
+ int i=0;
+
+ TALLOC_FREE(req->outbuf);
+ reply_outbuf(req, 0, 0);
+
+ if (errno != 0) {
+ DEBUG(3,("unix_error_packet: error string = %s\n",
+ strerror(errno)));
+
+ while (unix_dos_nt_errmap[i].dos_class != 0) {
+ if (unix_dos_nt_errmap[i].unix_error == errno) {
+ eclass = unix_dos_nt_errmap[i].dos_class;
+ ecode = unix_dos_nt_errmap[i].dos_code;
+ ntstatus = unix_dos_nt_errmap[i].nt_error;
+ break;
+ }
+ i++;
+ }
+ }
+
+ error_packet_set((char *)req->outbuf, eclass, ecode, ntstatus,
+ line, file);
+}
diff --git a/source3/smbd/fake_file.c b/source3/smbd/fake_file.c
new file mode 100644
index 0000000000..8dd9abee1a
--- /dev/null
+++ b/source3/smbd/fake_file.c
@@ -0,0 +1,161 @@
+/*
+ Unix SMB/CIFS implementation.
+ FAKE FILE suppport, for faking up special files windows want access to
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+struct fake_file_type {
+ const char *name;
+ enum FAKE_FILE_TYPE type;
+ void *(*init_pd)(TALLOC_CTX *mem_ctx);
+};
+
+static struct fake_file_type fake_files[] = {
+#ifdef WITH_QUOTAS
+ {FAKE_FILE_NAME_QUOTA_UNIX, FAKE_FILE_TYPE_QUOTA, init_quota_handle},
+#endif /* WITH_QUOTAS */
+ {NULL, FAKE_FILE_TYPE_NONE, NULL}
+};
+
+/****************************************************************************
+ Create a fake file handle
+****************************************************************************/
+
+static struct fake_file_handle *init_fake_file_handle(enum FAKE_FILE_TYPE type)
+{
+ struct fake_file_handle *fh = NULL;
+ int i;
+
+ for (i=0; fake_files[i].name!=NULL; i++) {
+ if (fake_files[i].type==type) {
+ break;
+ }
+ }
+
+ if (fake_files[i].name == NULL) {
+ return NULL;
+ }
+
+ DEBUG(5,("init_fake_file_handle: for [%s]\n",fake_files[i].name));
+
+ fh = talloc(NULL, struct fake_file_handle);
+ if (fh == NULL) {
+ DEBUG(0,("TALLOC_ZERO() failed.\n"));
+ return NULL;
+ }
+
+ fh->type = type;
+
+ if (fake_files[i].init_pd) {
+ fh->private_data = fake_files[i].init_pd(fh);
+ }
+ return fh;
+}
+
+/****************************************************************************
+ Does this name match a fake filename ?
+****************************************************************************/
+
+enum FAKE_FILE_TYPE is_fake_file(const char *fname)
+{
+#ifdef HAVE_SYS_QUOTAS
+ int i;
+#endif
+
+ if (!fname) {
+ return FAKE_FILE_TYPE_NONE;
+ }
+
+#ifdef HAVE_SYS_QUOTAS
+ for (i=0;fake_files[i].name!=NULL;i++) {
+ if (strncmp(fname,fake_files[i].name,strlen(fake_files[i].name))==0) {
+ DEBUG(5,("is_fake_file: [%s] is a fake file\n",fname));
+ return fake_files[i].type;
+ }
+ }
+#endif
+
+ return FAKE_FILE_TYPE_NONE;
+}
+
+
+/****************************************************************************
+ Open a fake quota file with a share mode.
+****************************************************************************/
+
+NTSTATUS open_fake_file(connection_struct *conn,
+ uint16_t current_vuid,
+ enum FAKE_FILE_TYPE fake_file_type,
+ const char *fname,
+ uint32 access_mask,
+ files_struct **result)
+{
+ files_struct *fsp = NULL;
+ NTSTATUS status;
+
+ /* access check */
+ if (conn->server_info->utok.uid != 0) {
+ DEBUG(3, ("open_fake_file_shared: access_denied to "
+ "service[%s] file[%s] user[%s]\n",
+ lp_servicename(SNUM(conn)), fname,
+ conn->server_info->unix_name));
+ return NT_STATUS_ACCESS_DENIED;
+
+ }
+
+ status = file_new(conn, &fsp);
+ if(!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(5,("open_fake_file_shared: fname = %s, FID = %d, access_mask = 0x%x\n",
+ fname, fsp->fnum, (unsigned int)access_mask));
+
+ fsp->conn = conn;
+ fsp->fh->fd = -1;
+ fsp->vuid = current_vuid;
+ fsp->fh->pos = -1;
+ fsp->can_lock = False; /* Should this be true ? - No, JRA */
+ fsp->access_mask = access_mask;
+ string_set(&fsp->fsp_name,fname);
+
+ fsp->fake_file_handle = init_fake_file_handle(fake_file_type);
+
+ if (fsp->fake_file_handle==NULL) {
+ file_free(fsp);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ conn->num_files_open++;
+ *result = fsp;
+ return NT_STATUS_OK;
+}
+
+void destroy_fake_file_handle(struct fake_file_handle **fh)
+{
+ if (!fh) {
+ return;
+ }
+ TALLOC_FREE(*fh);
+}
+
+NTSTATUS close_fake_file(files_struct *fsp)
+{
+ file_free(fsp);
+ return NT_STATUS_OK;
+}
diff --git a/source3/smbd/file_access.c b/source3/smbd/file_access.c
new file mode 100644
index 0000000000..84c993d06b
--- /dev/null
+++ b/source3/smbd/file_access.c
@@ -0,0 +1,222 @@
+/*
+ Unix SMB/CIFS implementation.
+ Check access to files based on security descriptors.
+ Copyright (C) Jeremy Allison 2005-2006.
+ Copyright (C) Michael Adam 2007.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_ACLS
+
+/**
+ * Security descriptor / NT Token level access check function.
+ */
+bool can_access_file_acl(struct connection_struct *conn,
+ const char * fname,
+ uint32_t access_mask)
+{
+ bool result;
+ NTSTATUS status;
+ uint32_t access_granted;
+ struct security_descriptor *secdesc = NULL;
+
+ status = SMB_VFS_GET_NT_ACL(conn, fname,
+ (OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION),
+ &secdesc);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("Could not get acl: %s\n", nt_errstr(status)));
+ return false;
+ }
+
+ result = se_access_check(secdesc, conn->server_info->ptok,
+ access_mask, &access_granted, &status);
+ TALLOC_FREE(secdesc);
+ return result;
+}
+
+/****************************************************************************
+ Actually emulate the in-kernel access checking for delete access. We need
+ this to successfully return ACCESS_DENIED on a file open for delete access.
+****************************************************************************/
+
+bool can_delete_file_in_directory(connection_struct *conn, const char *fname)
+{
+ SMB_STRUCT_STAT sbuf;
+ TALLOC_CTX *ctx = talloc_tos();
+ char *dname = NULL;
+
+ if (!CAN_WRITE(conn)) {
+ return False;
+ }
+
+ /* Get the parent directory permission mask and owners. */
+ if (!parent_dirname_talloc(ctx,
+ fname,
+ &dname,
+ NULL)) {
+ return False;
+ }
+ if(SMB_VFS_STAT(conn, dname, &sbuf) != 0) {
+ return False;
+ }
+
+ /* fast paths first */
+
+ if (!S_ISDIR(sbuf.st_mode)) {
+ return False;
+ }
+ if (conn->server_info->utok.uid == 0 || conn->admin_user) {
+ /* I'm sorry sir, I didn't know you were root... */
+ return True;
+ }
+
+#ifdef S_ISVTX
+ /* sticky bit means delete only by owner or root. */
+ if (sbuf.st_mode & S_ISVTX) {
+ SMB_STRUCT_STAT sbuf_file;
+ if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) {
+ if (errno == ENOENT) {
+ /* If the file doesn't already exist then
+ * yes we'll be able to delete it. */
+ return True;
+ }
+ return False;
+ }
+ /*
+ * Patch from SATOH Fumiyasu <fumiyas@miraclelinux.com>
+ * for bug #3348. Don't assume owning sticky bit
+ * directory means write access allowed.
+ */
+ if (conn->server_info->utok.uid != sbuf_file.st_uid) {
+ return False;
+ }
+ }
+#endif
+
+ /* now for ACL checks */
+
+ /*
+ * There's two ways to get the permission to delete a file: First by
+ * having the DELETE bit on the file itself and second if that does
+ * not help, by the DELETE_CHILD bit on the containing directory.
+ *
+ * Here we check the other way round because with just posix
+ * permissions looking at the file itself will never grant DELETE, so
+ * by looking at the directory first we save one get_acl call.
+ */
+
+ if (can_access_file_acl(conn, dname, FILE_DELETE_CHILD)) {
+ return true;
+ }
+
+ return can_access_file_acl(conn, fname, DELETE_ACCESS);
+}
+
+/****************************************************************************
+ Actually emulate the in-kernel access checking for read/write access. We need
+ this to successfully check for ability to write for dos filetimes.
+ Note this doesn't take into account share write permissions.
+****************************************************************************/
+
+bool can_access_file_data(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask)
+{
+ if (!(access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))) {
+ return False;
+ }
+ access_mask &= (FILE_READ_DATA|FILE_WRITE_DATA);
+
+ /* some fast paths first */
+
+ DEBUG(10,("can_access_file_data: requesting 0x%x on file %s\n",
+ (unsigned int)access_mask, fname ));
+
+ if (conn->server_info->utok.uid == 0 || conn->admin_user) {
+ /* I'm sorry sir, I didn't know you were root... */
+ return True;
+ }
+
+ if (!VALID_STAT(*psbuf)) {
+ /* Get the file permission mask and owners. */
+ if(SMB_VFS_STAT(conn, fname, psbuf) != 0) {
+ return False;
+ }
+ }
+
+ /* Check primary owner access. */
+ if (conn->server_info->utok.uid == psbuf->st_uid) {
+ switch (access_mask) {
+ case FILE_READ_DATA:
+ return (psbuf->st_mode & S_IRUSR) ? True : False;
+
+ case FILE_WRITE_DATA:
+ return (psbuf->st_mode & S_IWUSR) ? True : False;
+
+ default: /* FILE_READ_DATA|FILE_WRITE_DATA */
+
+ if ((psbuf->st_mode & (S_IWUSR|S_IRUSR)) == (S_IWUSR|S_IRUSR)) {
+ return True;
+ } else {
+ return False;
+ }
+ }
+ }
+
+ /* now for ACL checks */
+
+ return can_access_file_acl(conn, fname, access_mask);
+}
+
+/****************************************************************************
+ Userspace check for write access.
+ Note this doesn't take into account share write permissions.
+****************************************************************************/
+
+bool can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf)
+{
+ return can_access_file_data(conn, fname, psbuf, FILE_WRITE_DATA);
+}
+
+/****************************************************************************
+ Check for an existing default Windows ACL on a directory.
+****************************************************************************/
+
+bool directory_has_default_acl(connection_struct *conn, const char *fname)
+{
+ /* returns talloced off tos. */
+ struct security_descriptor *secdesc = NULL;
+ unsigned int i;
+ NTSTATUS status = SMB_VFS_GET_NT_ACL(conn, fname,
+ DACL_SECURITY_INFORMATION, &secdesc);
+
+ if (!NT_STATUS_IS_OK(status) || secdesc == NULL) {
+ return false;
+ }
+
+ for (i = 0; i < secdesc->dacl->num_aces; i++) {
+ struct security_ace *psa = &secdesc->dacl->aces[i];
+ if (psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
+ SEC_ACE_FLAG_CONTAINER_INHERIT)) {
+ TALLOC_FREE(secdesc);
+ return true;
+ }
+ }
+ TALLOC_FREE(secdesc);
+ return false;
+}
diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c
new file mode 100644
index 0000000000..60aeeef1e2
--- /dev/null
+++ b/source3/smbd/fileio.c
@@ -0,0 +1,955 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ read/write to a files_struct
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2000-2002. - write cache.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static bool setup_write_cache(files_struct *, SMB_OFF_T);
+
+/****************************************************************************
+ Read from write cache if we can.
+****************************************************************************/
+
+static bool read_from_write_cache(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
+{
+ write_cache *wcp = fsp->wcp;
+
+ if(!wcp) {
+ return False;
+ }
+
+ if( n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size) {
+ return False;
+ }
+
+ memcpy(data, wcp->data + (pos - wcp->offset), n);
+
+ DO_PROFILE_INC(writecache_read_hits);
+
+ return True;
+}
+
+/****************************************************************************
+ Read from a file.
+****************************************************************************/
+
+ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
+{
+ ssize_t ret=0,readret;
+
+ /* you can't read from print files */
+ if (fsp->print_file) {
+ return -1;
+ }
+
+ /*
+ * Serve from write cache if we can.
+ */
+
+ if(read_from_write_cache(fsp, data, pos, n)) {
+ fsp->fh->pos = pos + n;
+ fsp->fh->position_information = fsp->fh->pos;
+ return n;
+ }
+
+ flush_write_cache(fsp, READ_FLUSH);
+
+ fsp->fh->pos = pos;
+
+ if (n > 0) {
+#ifdef DMF_FIX
+ int numretries = 3;
+tryagain:
+ readret = SMB_VFS_PREAD(fsp,data,n,pos);
+
+ if (readret == -1) {
+ if ((errno == EAGAIN) && numretries) {
+ DEBUG(3,("read_file EAGAIN retry in 10 seconds\n"));
+ (void)sleep(10);
+ --numretries;
+ goto tryagain;
+ }
+ return -1;
+ }
+#else /* NO DMF fix. */
+ readret = SMB_VFS_PREAD(fsp,data,n,pos);
+
+ if (readret == -1) {
+ return -1;
+ }
+#endif
+ if (readret > 0) {
+ ret += readret;
+ }
+ }
+
+ DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n",
+ fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret ));
+
+ fsp->fh->pos += ret;
+ fsp->fh->position_information = fsp->fh->pos;
+
+ return(ret);
+}
+
+/* how many write cache buffers have been allocated */
+static unsigned int allocated_write_caches;
+
+/****************************************************************************
+ *Really* write to a file.
+****************************************************************************/
+
+static ssize_t real_write_file(struct smb_request *req,
+ files_struct *fsp,
+ const char *data,
+ SMB_OFF_T pos,
+ size_t n)
+{
+ ssize_t ret;
+
+ if (pos == -1) {
+ ret = vfs_write_data(req, fsp, data, n);
+ } else {
+ fsp->fh->pos = pos;
+ if (pos && lp_strict_allocate(SNUM(fsp->conn))) {
+ if (vfs_fill_sparse(fsp, pos) == -1) {
+ return -1;
+ }
+ }
+ ret = vfs_pwrite_data(req, fsp, data, n, pos);
+ }
+
+ DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n",
+ fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret ));
+
+ if (ret != -1) {
+ fsp->fh->pos += ret;
+
+/* Yes - this is correct - writes don't update this. JRA. */
+/* Found by Samba4 tests. */
+#if 0
+ fsp->position_information = fsp->pos;
+#endif
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ File size cache change.
+ Updates size on disk but doesn't flush the cache.
+****************************************************************************/
+
+static int wcp_file_size_change(files_struct *fsp)
+{
+ int ret;
+ write_cache *wcp = fsp->wcp;
+
+ wcp->file_size = wcp->offset + wcp->data_size;
+ ret = SMB_VFS_FTRUNCATE(fsp, wcp->file_size);
+ if (ret == -1) {
+ DEBUG(0,("wcp_file_size_change (%s): ftruncate of size %.0f error %s\n",
+ fsp->fsp_name, (double)wcp->file_size, strerror(errno) ));
+ }
+ return ret;
+}
+
+static void update_write_time_handler(struct event_context *ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ files_struct *fsp = (files_struct *)private_data;
+
+ /* Remove the timed event handler. */
+ TALLOC_FREE(fsp->update_write_time_event);
+ DEBUG(5, ("Update write time on %s\n", fsp->fsp_name));
+
+ /* change the write time if not already changed by someone else */
+ update_write_time(fsp);
+}
+
+/*********************************************************
+ Schedule a write time update for WRITE_TIME_UPDATE_USEC_DELAY
+ in the future.
+*********************************************************/
+
+void trigger_write_time_update(struct files_struct *fsp)
+{
+ int delay;
+
+ if (fsp->write_time_forced) {
+ /* No point - "sticky" write times
+ * in effect.
+ */
+ return;
+ }
+
+ if (fsp->update_write_time_triggered) {
+ /*
+ * We only update the write time
+ * on the first write. After that
+ * no other writes affect this.
+ */
+ return;
+ }
+ fsp->update_write_time_triggered = true;
+
+ delay = lp_parm_int(SNUM(fsp->conn),
+ "smbd", "writetimeupdatedelay",
+ WRITE_TIME_UPDATE_USEC_DELAY);
+
+ /* trigger the update 2 seconds later */
+ fsp->update_write_time_on_close = true;
+ fsp->update_write_time_event =
+ event_add_timed(smbd_event_context(), NULL,
+ timeval_current_ofs(0, delay),
+ "update_write_time_handler",
+ update_write_time_handler, fsp);
+}
+
+void trigger_write_time_update_immediate(struct files_struct *fsp)
+{
+ if (fsp->write_time_forced) {
+ /*
+ * No point - "sticky" write times
+ * in effect.
+ */
+ return;
+ }
+
+ TALLOC_FREE(fsp->update_write_time_event);
+ DEBUG(5, ("Update write time immediate on %s\n", fsp->fsp_name));
+
+ fsp->update_write_time_triggered = true;
+
+ fsp->update_write_time_on_close = false;
+ update_write_time(fsp);
+}
+
+/****************************************************************************
+ Write to a file.
+****************************************************************************/
+
+ssize_t write_file(struct smb_request *req,
+ files_struct *fsp,
+ const char *data,
+ SMB_OFF_T pos,
+ size_t n)
+{
+ write_cache *wcp = fsp->wcp;
+ ssize_t total_written = 0;
+ int write_path = -1;
+
+ if (fsp->print_file) {
+ fstring sharename;
+ uint32 jobid;
+
+ if (!rap_to_pjobid(fsp->rap_print_jobid, sharename, &jobid)) {
+ DEBUG(3,("write_file: Unable to map RAP jobid %u to jobid.\n",
+ (unsigned int)fsp->rap_print_jobid ));
+ errno = EBADF;
+ return -1;
+ }
+
+ return print_job_write(SNUM(fsp->conn), jobid, data, pos, n);
+ }
+
+ if (!fsp->can_write) {
+ errno = EPERM;
+ return -1;
+ }
+
+ if (!fsp->modified) {
+ SMB_STRUCT_STAT st;
+ fsp->modified = True;
+
+ if (SMB_VFS_FSTAT(fsp, &st) == 0) {
+ int dosmode;
+ trigger_write_time_update(fsp);
+ dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
+ if ((lp_store_dos_attributes(SNUM(fsp->conn)) ||
+ MAP_ARCHIVE(fsp->conn)) &&
+ !IS_DOS_ARCHIVE(dosmode)) {
+ file_set_dosmode(fsp->conn,fsp->fsp_name,
+ dosmode | aARCH,&st,
+ NULL,
+ false);
+ }
+
+ /*
+ * If this is the first write and we have an exclusive oplock then setup
+ * the write cache.
+ */
+
+ if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) {
+ setup_write_cache(fsp, st.st_size);
+ wcp = fsp->wcp;
+ }
+ }
+ }
+
+#ifdef WITH_PROFILE
+ DO_PROFILE_INC(writecache_total_writes);
+ if (!fsp->oplock_type) {
+ DO_PROFILE_INC(writecache_non_oplock_writes);
+ }
+#endif
+
+ /*
+ * If this file is level II oplocked then we need
+ * to grab the shared memory lock and inform all
+ * other files with a level II lock that they need
+ * to flush their read caches. We keep the lock over
+ * the shared memory area whilst doing this.
+ */
+
+ release_level_2_oplocks_on_change(fsp);
+
+#ifdef WITH_PROFILE
+ if (profile_p && profile_p->writecache_total_writes % 500 == 0) {
+ DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \
+nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
+ profile_p->writecache_init_writes,
+ profile_p->writecache_abutted_writes,
+ profile_p->writecache_total_writes,
+ profile_p->writecache_non_oplock_writes,
+ profile_p->writecache_allocated_write_caches,
+ profile_p->writecache_num_write_caches,
+ profile_p->writecache_direct_writes,
+ profile_p->writecache_num_perfect_writes,
+ profile_p->writecache_read_hits ));
+
+ DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n",
+ profile_p->writecache_flushed_writes[SEEK_FLUSH],
+ profile_p->writecache_flushed_writes[READ_FLUSH],
+ profile_p->writecache_flushed_writes[WRITE_FLUSH],
+ profile_p->writecache_flushed_writes[READRAW_FLUSH],
+ profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH],
+ profile_p->writecache_flushed_writes[CLOSE_FLUSH],
+ profile_p->writecache_flushed_writes[SYNC_FLUSH] ));
+ }
+#endif
+
+ if (wcp && req->unread_bytes) {
+ /* If we're using receivefile don't
+ * deal with a write cache.
+ */
+ flush_write_cache(fsp, WRITE_FLUSH);
+ delete_write_cache(fsp);
+ wcp = NULL;
+ }
+
+ if(!wcp) {
+ DO_PROFILE_INC(writecache_direct_writes);
+ total_written = real_write_file(req, fsp, data, pos, n);
+ return total_written;
+ }
+
+ DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n",
+ fsp->fsp_name, fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size));
+
+ fsp->fh->pos = pos + n;
+
+ /*
+ * If we have active cache and it isn't contiguous then we flush.
+ * NOTE: There is a small problem with running out of disk ....
+ */
+
+ if (wcp->data_size) {
+ bool cache_flush_needed = False;
+
+ if ((pos >= wcp->offset) && (pos <= wcp->offset + wcp->data_size)) {
+
+ /* ASCII art.... JRA.
+
+ +--------------+-----
+ | Cached data | Rest of allocated cache buffer....
+ +--------------+-----
+
+ +-------------------+
+ | Data to write |
+ +-------------------+
+
+ */
+
+ /*
+ * Start of write overlaps or abutts the existing data.
+ */
+
+ size_t data_used = MIN((wcp->alloc_size - (pos - wcp->offset)), n);
+
+ memcpy(wcp->data + (pos - wcp->offset), data, data_used);
+
+ /*
+ * Update the current buffer size with the new data.
+ */
+
+ if(pos + data_used > wcp->offset + wcp->data_size) {
+ wcp->data_size = pos + data_used - wcp->offset;
+ }
+
+ /*
+ * Update the file size if changed.
+ */
+
+ if (wcp->offset + wcp->data_size > wcp->file_size) {
+ if (wcp_file_size_change(fsp) == -1) {
+ return -1;
+ }
+ }
+
+ /*
+ * If we used all the data then
+ * return here.
+ */
+
+ if(n == data_used) {
+ return n;
+ } else {
+ cache_flush_needed = True;
+ }
+ /*
+ * Move the start of data forward by the amount used,
+ * cut down the amount left by the same amount.
+ */
+
+ data += data_used;
+ pos += data_used;
+ n -= data_used;
+
+ DO_PROFILE_INC(writecache_abutted_writes);
+ total_written = data_used;
+
+ write_path = 1;
+
+ } else if ((pos < wcp->offset) && (pos + n > wcp->offset) &&
+ (pos + n <= wcp->offset + wcp->alloc_size)) {
+
+ /* ASCII art.... JRA.
+
+ +---------------+
+ | Cache buffer |
+ +---------------+
+
+ +-------------------+
+ | Data to write |
+ +-------------------+
+
+ */
+
+ /*
+ * End of write overlaps the existing data.
+ */
+
+ size_t data_used = pos + n - wcp->offset;
+
+ memcpy(wcp->data, data + n - data_used, data_used);
+
+ /*
+ * Update the current buffer size with the new data.
+ */
+
+ if(pos + n > wcp->offset + wcp->data_size) {
+ wcp->data_size = pos + n - wcp->offset;
+ }
+
+ /*
+ * Update the file size if changed.
+ */
+
+ if (wcp->offset + wcp->data_size > wcp->file_size) {
+ if (wcp_file_size_change(fsp) == -1) {
+ return -1;
+ }
+ }
+
+ /*
+ * We don't need to move the start of data, but we
+ * cut down the amount left by the amount used.
+ */
+
+ n -= data_used;
+
+ /*
+ * We cannot have used all the data here.
+ */
+
+ cache_flush_needed = True;
+
+ DO_PROFILE_INC(writecache_abutted_writes);
+ total_written = data_used;
+
+ write_path = 2;
+
+ } else if ( (pos >= wcp->file_size) &&
+ (wcp->offset + wcp->data_size == wcp->file_size) &&
+ (pos > wcp->offset + wcp->data_size) &&
+ (pos < wcp->offset + wcp->alloc_size) ) {
+
+ /* ASCII art.... JRA.
+
+ End of file ---->|
+
+ +---------------+---------------+
+ | Cached data | Cache buffer |
+ +---------------+---------------+
+
+ +-------------------+
+ | Data to write |
+ +-------------------+
+
+ */
+
+ /*
+ * Non-contiguous write part of which fits within
+ * the cache buffer and is extending the file
+ * and the cache contents reflect the current
+ * data up to the current end of the file.
+ */
+
+ size_t data_used;
+
+ if(pos + n <= wcp->offset + wcp->alloc_size) {
+ data_used = n;
+ } else {
+ data_used = wcp->offset + wcp->alloc_size - pos;
+ }
+
+ /*
+ * Fill in the non-continuous area with zeros.
+ */
+
+ memset(wcp->data + wcp->data_size, '\0',
+ pos - (wcp->offset + wcp->data_size) );
+
+ memcpy(wcp->data + (pos - wcp->offset), data, data_used);
+
+ /*
+ * Update the current buffer size with the new data.
+ */
+
+ if(pos + data_used > wcp->offset + wcp->data_size) {
+ wcp->data_size = pos + data_used - wcp->offset;
+ }
+
+ /*
+ * Update the file size if changed.
+ */
+
+ if (wcp->offset + wcp->data_size > wcp->file_size) {
+ if (wcp_file_size_change(fsp) == -1) {
+ return -1;
+ }
+ }
+
+ /*
+ * If we used all the data then
+ * return here.
+ */
+
+ if(n == data_used) {
+ return n;
+ } else {
+ cache_flush_needed = True;
+ }
+
+ /*
+ * Move the start of data forward by the amount used,
+ * cut down the amount left by the same amount.
+ */
+
+ data += data_used;
+ pos += data_used;
+ n -= data_used;
+
+ DO_PROFILE_INC(writecache_abutted_writes);
+ total_written = data_used;
+
+ write_path = 3;
+
+ } else if ( (pos >= wcp->file_size) &&
+ (n == 1) &&
+ (wcp->file_size == wcp->offset + wcp->data_size) &&
+ (pos < wcp->file_size + wcp->alloc_size)) {
+
+ /*
+
+ End of file ---->|
+
+ +---------------+---------------+
+ | Cached data | Cache buffer |
+ +---------------+---------------+
+
+ |<------- allocated size ---------------->|
+
+ +--------+
+ | 1 Byte |
+ +--------+
+
+ MS-Office seems to do this a lot to determine if there's enough
+ space on the filesystem to write a new file.
+
+ Change to :
+
+ End of file ---->|
+ +-----------------------+--------+
+ | Zeroed Cached data | 1 Byte |
+ +-----------------------+--------+
+ */
+
+ flush_write_cache(fsp, WRITE_FLUSH);
+ wcp->offset = wcp->file_size;
+ wcp->data_size = pos - wcp->file_size + 1;
+ memset(wcp->data, '\0', wcp->data_size);
+ memcpy(wcp->data + wcp->data_size-1, data, 1);
+
+ /*
+ * Update the file size if changed.
+ */
+
+ if (wcp->offset + wcp->data_size > wcp->file_size) {
+ if (wcp_file_size_change(fsp) == -1) {
+ return -1;
+ }
+ }
+
+ return n;
+
+ } else {
+
+ /* ASCII art..... JRA.
+
+ Case 1).
+
+ +---------------+---------------+
+ | Cached data | Cache buffer |
+ +---------------+---------------+
+
+ +-------------------+
+ | Data to write |
+ +-------------------+
+
+ Case 2).
+
+ +---------------+---------------+
+ | Cached data | Cache buffer |
+ +---------------+---------------+
+
+ +-------------------+
+ | Data to write |
+ +-------------------+
+
+ Case 3).
+
+ +---------------+---------------+
+ | Cached data | Cache buffer |
+ +---------------+---------------+
+
+ +-----------------------------------------------------+
+ | Data to write |
+ +-----------------------------------------------------+
+
+ */
+
+ /*
+ * Write is bigger than buffer, or there is no overlap on the
+ * low or high ends.
+ */
+
+ DEBUG(9,("write_file: non cacheable write : fd = %d, pos = %.0f, len = %u, current cache pos = %.0f \
+len = %u\n",fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size ));
+
+ /*
+ * If write would fit in the cache, and is larger than
+ * the data already in the cache, flush the cache and
+ * preferentially copy the data new data into it. Otherwise
+ * just write the data directly.
+ */
+
+ if ( n <= wcp->alloc_size && n > wcp->data_size) {
+ cache_flush_needed = True;
+ } else {
+ ssize_t ret = real_write_file(NULL,fsp, data, pos, n);
+
+ /*
+ * If the write overlaps the entire cache, then
+ * discard the current contents of the cache.
+ * Fix from Rasmus Borup Hansen rbh@math.ku.dk.
+ */
+
+ if ((pos <= wcp->offset) &&
+ (pos + n >= wcp->offset + wcp->data_size) ) {
+ DEBUG(9,("write_file: discarding overwritten write \
+cache: fd = %d, off=%.0f, size=%u\n", fsp->fh->fd, (double)wcp->offset, (unsigned int)wcp->data_size ));
+ wcp->data_size = 0;
+ }
+
+ DO_PROFILE_INC(writecache_direct_writes);
+ if (ret == -1) {
+ return ret;
+ }
+
+ if (pos + ret > wcp->file_size) {
+ wcp->file_size = pos + ret;
+ }
+
+ return ret;
+ }
+
+ write_path = 4;
+
+ }
+
+ if (cache_flush_needed) {
+ DEBUG(3,("WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \
+n = %u, wcp->offset=%.0f, wcp->data_size=%u\n",
+ write_path, fsp->fh->fd, (double)wcp->file_size, (double)pos, (unsigned int)n,
+ (double)wcp->offset, (unsigned int)wcp->data_size ));
+
+ flush_write_cache(fsp, WRITE_FLUSH);
+ }
+ }
+
+ /*
+ * If the write request is bigger than the cache
+ * size, write it all out.
+ */
+
+ if (n > wcp->alloc_size ) {
+ ssize_t ret = real_write_file(NULL,fsp, data, pos, n);
+ if (ret == -1) {
+ return -1;
+ }
+
+ if (pos + ret > wcp->file_size) {
+ wcp->file_size = pos + n;
+ }
+
+ DO_PROFILE_INC(writecache_direct_writes);
+ return total_written + n;
+ }
+
+ /*
+ * If there's any data left, cache it.
+ */
+
+ if (n) {
+#ifdef WITH_PROFILE
+ if (wcp->data_size) {
+ DO_PROFILE_INC(writecache_abutted_writes);
+ } else {
+ DO_PROFILE_INC(writecache_init_writes);
+ }
+#endif
+ memcpy(wcp->data+wcp->data_size, data, n);
+ if (wcp->data_size == 0) {
+ wcp->offset = pos;
+ DO_PROFILE_INC(writecache_num_write_caches);
+ }
+ wcp->data_size += n;
+
+ /*
+ * Update the file size if changed.
+ */
+
+ if (wcp->offset + wcp->data_size > wcp->file_size) {
+ if (wcp_file_size_change(fsp) == -1) {
+ return -1;
+ }
+ }
+ DEBUG(9,("wcp->offset = %.0f wcp->data_size = %u cache return %u\n",
+ (double)wcp->offset, (unsigned int)wcp->data_size, (unsigned int)n));
+
+ total_written += n;
+ return total_written; /* .... that's a write :) */
+ }
+
+ return total_written;
+}
+
+/****************************************************************************
+ Delete the write cache structure.
+****************************************************************************/
+
+void delete_write_cache(files_struct *fsp)
+{
+ write_cache *wcp;
+
+ if(!fsp) {
+ return;
+ }
+
+ if(!(wcp = fsp->wcp)) {
+ return;
+ }
+
+ DO_PROFILE_DEC(writecache_allocated_write_caches);
+ allocated_write_caches--;
+
+ SMB_ASSERT(wcp->data_size == 0);
+
+ SAFE_FREE(wcp->data);
+ SAFE_FREE(fsp->wcp);
+
+ DEBUG(10,("delete_write_cache: File %s deleted write cache\n", fsp->fsp_name ));
+}
+
+/****************************************************************************
+ Setup the write cache structure.
+****************************************************************************/
+
+static bool setup_write_cache(files_struct *fsp, SMB_OFF_T file_size)
+{
+ ssize_t alloc_size = lp_write_cache_size(SNUM(fsp->conn));
+ write_cache *wcp;
+
+ if (allocated_write_caches >= MAX_WRITE_CACHES) {
+ return False;
+ }
+
+ if(alloc_size == 0 || fsp->wcp) {
+ return False;
+ }
+
+ if((wcp = SMB_MALLOC_P(write_cache)) == NULL) {
+ DEBUG(0,("setup_write_cache: malloc fail.\n"));
+ return False;
+ }
+
+ wcp->file_size = file_size;
+ wcp->offset = 0;
+ wcp->alloc_size = alloc_size;
+ wcp->data_size = 0;
+ if((wcp->data = (char *)SMB_MALLOC(wcp->alloc_size)) == NULL) {
+ DEBUG(0,("setup_write_cache: malloc fail for buffer size %u.\n",
+ (unsigned int)wcp->alloc_size ));
+ SAFE_FREE(wcp);
+ return False;
+ }
+
+ memset(wcp->data, '\0', wcp->alloc_size );
+
+ fsp->wcp = wcp;
+ DO_PROFILE_INC(writecache_allocated_write_caches);
+ allocated_write_caches++;
+
+ DEBUG(10,("setup_write_cache: File %s allocated write cache size %lu\n",
+ fsp->fsp_name, (unsigned long)wcp->alloc_size ));
+
+ return True;
+}
+
+/****************************************************************************
+ Cope with a size change.
+****************************************************************************/
+
+void set_filelen_write_cache(files_struct *fsp, SMB_OFF_T file_size)
+{
+ if(fsp->wcp) {
+ /* The cache *must* have been flushed before we do this. */
+ if (fsp->wcp->data_size != 0) {
+ char *msg;
+ asprintf(&msg, "set_filelen_write_cache: size change "
+ "on file %s with write cache size = %lu\n",
+ fsp->fsp_name,
+ (unsigned long)fsp->wcp->data_size);
+ smb_panic(msg);
+ }
+ fsp->wcp->file_size = file_size;
+ }
+}
+
+/*******************************************************************
+ Flush a write cache struct to disk.
+********************************************************************/
+
+ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason)
+{
+ write_cache *wcp = fsp->wcp;
+ size_t data_size;
+ ssize_t ret;
+
+ if(!wcp || !wcp->data_size) {
+ return 0;
+ }
+
+ data_size = wcp->data_size;
+ wcp->data_size = 0;
+
+ DO_PROFILE_DEC_INC(writecache_num_write_caches,writecache_flushed_writes[reason]);
+
+ DEBUG(9,("flushing write cache: fd = %d, off=%.0f, size=%u\n",
+ fsp->fh->fd, (double)wcp->offset, (unsigned int)data_size));
+
+#ifdef WITH_PROFILE
+ if(data_size == wcp->alloc_size) {
+ DO_PROFILE_INC(writecache_num_perfect_writes);
+ }
+#endif
+
+ ret = real_write_file(NULL, fsp, wcp->data, wcp->offset, data_size);
+
+ /*
+ * Ensure file size if kept up to date if write extends file.
+ */
+
+ if ((ret != -1) && (wcp->offset + ret > wcp->file_size)) {
+ wcp->file_size = wcp->offset + ret;
+ }
+
+ return ret;
+}
+
+/*******************************************************************
+sync a file
+********************************************************************/
+
+NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, bool write_through)
+{
+ if (fsp->fh->fd == -1)
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (lp_strict_sync(SNUM(conn)) &&
+ (lp_syncalways(SNUM(conn)) || write_through)) {
+ int ret = flush_write_cache(fsp, SYNC_FLUSH);
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+ ret = SMB_VFS_FSYNC(fsp);
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+ }
+ return NT_STATUS_OK;
+}
+
+/************************************************************
+ Perform a stat whether a valid fd or not.
+************************************************************/
+
+int fsp_stat(files_struct *fsp, SMB_STRUCT_STAT *pst)
+{
+ if (fsp->fh->fd == -1) {
+ return SMB_VFS_STAT(fsp->conn, fsp->fsp_name, pst);
+ } else {
+ return SMB_VFS_FSTAT(fsp, pst);
+ }
+}
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
new file mode 100644
index 0000000000..41a0b9296a
--- /dev/null
+++ b/source3/smbd/filename.c
@@ -0,0 +1,956 @@
+/*
+ Unix SMB/CIFS implementation.
+ filename handling routines
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1999-2007
+ Copyright (C) Ying Chen 2000
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * New hash table stat cache code added by Ying Chen.
+ */
+
+#include "includes.h"
+
+static bool scan_directory(connection_struct *conn, const char *path,
+ char *name, char **found_name);
+static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
+ connection_struct *conn,
+ const char *orig_path,
+ const char *basepath,
+ const char *streamname,
+ SMB_STRUCT_STAT *pst,
+ char **path);
+
+/****************************************************************************
+ Mangle the 2nd name and check if it is then equal to the first name.
+****************************************************************************/
+
+static bool mangled_equal(const char *name1,
+ const char *name2,
+ const struct share_params *p)
+{
+ char mname[13];
+
+ if (!name_to_8_3(name2, mname, False, p)) {
+ return False;
+ }
+ return strequal(name1, mname);
+}
+
+/****************************************************************************
+ Cope with the differing wildcard and non-wildcard error cases.
+****************************************************************************/
+
+static NTSTATUS determine_path_error(const char *name,
+ bool allow_wcard_last_component)
+{
+ const char *p;
+
+ if (!allow_wcard_last_component) {
+ /* Error code within a pathname. */
+ return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+
+ /* We're terminating here so we
+ * can be a little slower and get
+ * the error code right. Windows
+ * treats the last part of the pathname
+ * separately I think, so if the last
+ * component is a wildcard then we treat
+ * this ./ as "end of component" */
+
+ p = strchr(name, '/');
+
+ if (!p && (ms_has_wild(name) || ISDOT(name))) {
+ /* Error code at the end of a pathname. */
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ } else {
+ /* Error code within a pathname. */
+ return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+}
+
+/****************************************************************************
+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 an NTSTATUS error if some part of the name except for
+the last part cannot be resolved, else NT_STATUS_OK.
+
+Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we didn't
+get any fatal errors that should immediately terminate the calling
+SMB processing whilst resolving.
+
+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.
+
+If last_component_wcard is true then a MS wildcard was detected and
+should be allowed in the last component of the path only.
+
+On exit from unix_convert, if *pst was not null, then the file stat
+struct will be returned if the file exists and was found, if not this
+stat struct will be filled with zeros (and this can be detected by checking
+for nlinks = 0, which can never be true for any file).
+****************************************************************************/
+
+NTSTATUS unix_convert(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ const char *orig_path,
+ bool allow_wcard_last_component,
+ char **pp_conv_path,
+ char **pp_saved_last_component,
+ SMB_STRUCT_STAT *pst)
+{
+ SMB_STRUCT_STAT st;
+ char *start, *end;
+ char *dirpath = NULL;
+ char *name = NULL;
+ char *stream = NULL;
+ bool component_was_mangled = False;
+ bool name_has_wildcard = False;
+ NTSTATUS result;
+
+ SET_STAT_INVALID(*pst);
+ *pp_conv_path = NULL;
+ if(pp_saved_last_component) {
+ *pp_saved_last_component = NULL;
+ }
+
+ if (conn->printer) {
+ /* we don't ever use the filenames on a printer share as a
+ filename - so don't convert them */
+ if (!(*pp_conv_path = talloc_strdup(ctx,orig_path))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(5, ("unix_convert called on file \"%s\"\n", orig_path));
+
+ /*
+ * Conversion to basic unix format is already done in
+ * check_path_syntax().
+ */
+
+ /*
+ * Names must be relative to the root of the service - any leading /.
+ * and trailing /'s should have been trimmed by check_path_syntax().
+ */
+
+#ifdef DEVELOPER
+ SMB_ASSERT(*orig_path != '/');
+#endif
+
+ /*
+ * If we trimmed down to a single '\0' character
+ * then we should use the "." directory to avoid
+ * searching the cache, but not if we are in a
+ * printing share.
+ * As we know this is valid we can return true here.
+ */
+
+ if (!*orig_path) {
+ if (!(name = talloc_strdup(ctx,"."))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (SMB_VFS_STAT(conn,name,&st) == 0) {
+ *pst = st;
+ } else {
+ return map_nt_error_from_unix(errno);
+ }
+ DEBUG(5,("conversion finished \"\" -> %s\n",name));
+ goto done;
+ }
+
+ if (orig_path[0] == '.' && (orig_path[1] == '/' ||
+ orig_path[1] == '\0')) {
+ /* Start of pathname can't be "." only. */
+ if (orig_path[1] == '\0' || orig_path[2] == '\0') {
+ result = NT_STATUS_OBJECT_NAME_INVALID;
+ } else {
+ result =determine_path_error(
+ &orig_path[2], allow_wcard_last_component);
+ }
+ return result;
+ }
+
+ /*
+ * Ensure saved_last_component is valid even if file exists.
+ */
+
+ if(pp_saved_last_component) {
+ end = strrchr_m(orig_path, '/');
+ if (end) {
+ *pp_saved_last_component = talloc_strdup(ctx, end + 1);
+ } else {
+ *pp_saved_last_component = talloc_strdup(ctx,
+ orig_path);
+ }
+ }
+
+ if (!(name = talloc_strdup(ctx, orig_path))) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!lp_posix_pathnames()) {
+ stream = strchr_m(name, ':');
+
+ if (stream != NULL) {
+ char *tmp = talloc_strdup(ctx, stream);
+ if (tmp == NULL) {
+ TALLOC_FREE(name);
+ return NT_STATUS_NO_MEMORY;
+ }
+ *stream = '\0';
+ stream = tmp;
+ }
+ }
+
+ /*
+ * Large directory fix normalization. If we're case sensitive, and
+ * the case preserving parameters are set to "no", normalize the case of
+ * the incoming filename from the client WHETHER IT EXISTS OR NOT !
+ * This is in conflict with the current (3.0.20) man page, but is
+ * what people expect from the "large directory howto". I'll update
+ * the man page. Thanks to jht@samba.org for finding this. JRA.
+ */
+
+ if (conn->case_sensitive && !conn->case_preserve &&
+ !conn->short_case_preserve) {
+ strnorm(name, lp_defaultcase(SNUM(conn)));
+ }
+
+ start = name;
+
+ /* If we're providing case insentive semantics or
+ * the underlying filesystem is case insensitive,
+ * then a case-normalized hit in the stat-cache is
+ * authoratitive. JRA.
+ */
+
+ if((!conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) &&
+ stat_cache_lookup(conn, &name, &dirpath, &start, &st)) {
+ *pst = st;
+ goto done;
+ }
+
+ /*
+ * Make sure "dirpath" is an allocated string, we use this for
+ * building the directories with asprintf and free it.
+ */
+
+ if ((dirpath == NULL) && (!(dirpath = talloc_strdup(ctx,"")))) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ TALLOC_FREE(name);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * stat the name - if it exists then we are all done!
+ */
+
+ if (SMB_VFS_STAT(conn,name,&st) == 0) {
+ /* Ensure we catch all names with in "/."
+ this is disallowed under Windows. */
+ const char *p = strstr(name, "/."); /* mb safe. */
+ if (p) {
+ if (p[2] == '/') {
+ /* Error code within a pathname. */
+ result = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ goto fail;
+ } else if (p[2] == '\0') {
+ /* Error code at the end of a pathname. */
+ result = NT_STATUS_OBJECT_NAME_INVALID;
+ goto fail;
+ }
+ }
+ stat_cache_add(orig_path, name, conn->case_sensitive);
+ DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
+ *pst = st;
+ goto done;
+ }
+
+ 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 or the underlying filesystem is case insentive then searching
+ * won't help.
+ */
+
+ if ((conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) &&
+ !mangle_is_mangled(name, conn->params)) {
+ goto done;
+ }
+
+ /*
+ * is_mangled() was changed to look at an entire pathname, not
+ * just a component. JRA.
+ */
+
+ if (mangle_is_mangled(start, conn->params)) {
+ component_was_mangled = True;
+ }
+
+ /*
+ * Now we need to recursively match the name against the real
+ * directory structure.
+ */
+
+ /*
+ * Match each part of the path name separately, trying the names
+ * as is first, then trying to scan the directory for matching names.
+ */
+
+ for (; start ; start = (end?end+1:(char *)NULL)) {
+ /*
+ * Pinpoint the end of this section of the filename.
+ */
+ /* mb safe. '/' can't be in any encoded char. */
+ end = strchr(start, '/');
+
+ /*
+ * Chop the name at this point.
+ */
+ if (end) {
+ *end = 0;
+ }
+
+ if (pp_saved_last_component) {
+ TALLOC_FREE(*pp_saved_last_component);
+ *pp_saved_last_component = talloc_strdup(ctx,
+ end ? end + 1 : start);
+ if (!*pp_saved_last_component) {
+ DEBUG(0, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ /* The name cannot have a component of "." */
+
+ if (ISDOT(start)) {
+ if (!end) {
+ /* Error code at the end of a pathname. */
+ result = NT_STATUS_OBJECT_NAME_INVALID;
+ } else {
+ result = determine_path_error(end+1,
+ allow_wcard_last_component);
+ }
+ goto fail;
+ }
+
+ /* The name cannot have a wildcard if it's not
+ the last component. */
+
+ name_has_wildcard = ms_has_wild(start);
+
+ /* Wildcard not valid anywhere. */
+ if (name_has_wildcard && !allow_wcard_last_component) {
+ result = NT_STATUS_OBJECT_NAME_INVALID;
+ goto fail;
+ }
+
+ /* Wildcards never valid within a pathname. */
+ if (name_has_wildcard && end) {
+ result = NT_STATUS_OBJECT_NAME_INVALID;
+ goto fail;
+ }
+
+ /*
+ * Check if the name exists up to this point.
+ */
+
+ if (SMB_VFS_STAT(conn,name, &st) == 0) {
+ /*
+ * It exists. it must either be a directory or this must
+ * be the last part of the path for it to be OK.
+ */
+ if (end && !(st.st_mode & S_IFDIR)) {
+ /*
+ * An intermediate part of the name isn't
+ * a directory.
+ */
+ DEBUG(5,("Not a dir %s\n",start));
+ *end = '/';
+ /*
+ * 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.
+ */
+ result = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ goto fail;
+ }
+
+ if (!end) {
+ /*
+ * We just scanned for, and found the end of
+ * the path. We must return the valid stat
+ * struct. JRA.
+ */
+
+ *pst = st;
+ }
+
+ } else {
+ char *found_name = NULL;
+
+ /* Stat failed - ensure we don't use it. */
+ SET_STAT_INVALID(st);
+
+ /*
+ * Reset errno so we can detect
+ * directory open errors.
+ */
+ errno = 0;
+
+ /*
+ * Try to find this part of the path in the directory.
+ */
+
+ if (name_has_wildcard ||
+ !scan_directory(conn, dirpath,
+ start, &found_name)) {
+ char *unmangled;
+
+ 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.
+ */
+
+ /*
+ * ENOENT, ENOTDIR and ELOOP all map
+ * to NT_STATUS_OBJECT_PATH_NOT_FOUND
+ * in the filename walk.
+ */
+
+ if (errno == ENOENT ||
+ errno == ENOTDIR ||
+ errno == ELOOP) {
+ result =
+ NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+ else {
+ result =
+ map_nt_error_from_unix(errno);
+ }
+ goto fail;
+ }
+
+ /* ENOENT is the only valid error here. */
+ if ((errno != 0) && (errno != ENOENT)) {
+ /*
+ * ENOTDIR and ELOOP both map to
+ * NT_STATUS_OBJECT_PATH_NOT_FOUND
+ * in the filename walk.
+ */
+ if (errno == ENOTDIR ||
+ errno == ELOOP) {
+ result =
+ NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+ else {
+ result =
+ map_nt_error_from_unix(errno);
+ }
+ goto fail;
+ }
+
+ /*
+ * Just the last part of the name doesn't exist.
+ * We need to strupper() or strlower() it as
+ * this conversion may be used for file creation
+ * purposes. Fix inspired by
+ * Thomas Neumann <t.neumann@iku-ag.de>.
+ */
+ if (!conn->case_preserve ||
+ (mangle_is_8_3(start, False,
+ conn->params) &&
+ !conn->short_case_preserve)) {
+ strnorm(start,
+ lp_defaultcase(SNUM(conn)));
+ }
+
+ /*
+ * check on the mangled stack to see if we can
+ * recover the base of the filename.
+ */
+
+ if (mangle_is_mangled(start, conn->params)
+ && mangle_lookup_name_from_8_3(ctx,
+ start,
+ &unmangled,
+ conn->params)) {
+ char *tmp;
+ size_t start_ofs = start - name;
+
+ if (*dirpath != '\0') {
+ tmp = talloc_asprintf(ctx,
+ "%s/%s", dirpath,
+ unmangled);
+ TALLOC_FREE(unmangled);
+ }
+ else {
+ tmp = unmangled;
+ }
+ if (tmp == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ TALLOC_FREE(name);
+ name = tmp;
+ start = name + start_ofs;
+ end = start + strlen(start);
+ }
+
+ DEBUG(5,("New file %s\n",start));
+ goto done;
+ }
+
+
+ /*
+ * Restore the rest of the string. If the string was
+ * mangled the size may have changed.
+ */
+ if (end) {
+ char *tmp;
+ size_t start_ofs = start - name;
+
+ if (*dirpath != '\0') {
+ tmp = talloc_asprintf(ctx,
+ "%s/%s/%s", dirpath,
+ found_name, end+1);
+ }
+ else {
+ tmp = talloc_asprintf(ctx,
+ "%s/%s", found_name,
+ end+1);
+ }
+ if (tmp == NULL) {
+ DEBUG(0, ("talloc_asprintf failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ TALLOC_FREE(name);
+ name = tmp;
+ start = name + start_ofs;
+ end = start + strlen(found_name);
+ *end = '\0';
+ } else {
+ char *tmp;
+ size_t start_ofs = start - name;
+
+ if (*dirpath != '\0') {
+ tmp = talloc_asprintf(ctx,
+ "%s/%s", dirpath,
+ found_name);
+ } else {
+ tmp = talloc_strdup(ctx,
+ found_name);
+ }
+ if (tmp == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ TALLOC_FREE(name);
+ name = tmp;
+ start = name + start_ofs;
+
+ /*
+ * We just scanned for, and found the end of
+ * the path. We must return a valid stat struct
+ * if it exists. JRA.
+ */
+
+ if (SMB_VFS_STAT(conn,name, &st) == 0) {
+ *pst = st;
+ } else {
+ SET_STAT_INVALID(st);
+ }
+ }
+
+ TALLOC_FREE(found_name);
+ } /* end else */
+
+#ifdef DEVELOPER
+ /*
+ * This sucks!
+ * We should never provide different behaviors
+ * depending on DEVELOPER!!!
+ */
+ if (VALID_STAT(st)) {
+ bool delete_pending;
+ get_file_infos(vfs_file_id_from_sbuf(conn, &st),
+ &delete_pending, NULL);
+ if (delete_pending) {
+ result = NT_STATUS_DELETE_PENDING;
+ goto fail;
+ }
+ }
+#endif
+
+ /*
+ * Add to the dirpath that we have resolved so far.
+ */
+
+ if (*dirpath != '\0') {
+ char *tmp = talloc_asprintf(ctx,
+ "%s/%s", dirpath, start);
+ if (!tmp) {
+ DEBUG(0, ("talloc_asprintf failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ TALLOC_FREE(dirpath);
+ dirpath = tmp;
+ }
+ else {
+ TALLOC_FREE(dirpath);
+ if (!(dirpath = talloc_strdup(ctx,start))) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ /*
+ * 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,
+ conn->case_sensitive);
+ }
+
+ /*
+ * 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, conn->case_sensitive);
+ }
+
+ /*
+ * The name has been resolved.
+ */
+
+ DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
+
+ done:
+ if (stream != NULL) {
+ char *tmp = NULL;
+
+ result = build_stream_path(ctx, conn, orig_path, name, stream,
+ pst, &tmp);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto fail;
+ }
+
+ DEBUG(10, ("build_stream_path returned %s\n", tmp));
+
+ TALLOC_FREE(name);
+ name = tmp;
+ }
+ *pp_conv_path = name;
+ TALLOC_FREE(dirpath);
+ return NT_STATUS_OK;
+ fail:
+ DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start));
+ if (*dirpath != '\0') {
+ *pp_conv_path = talloc_asprintf(ctx,
+ "%s/%s", dirpath, start);
+ } else {
+ *pp_conv_path = talloc_strdup(ctx, start);
+ }
+ if (!*pp_conv_path) {
+ DEBUG(0, ("talloc_asprintf failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ TALLOC_FREE(name);
+ TALLOC_FREE(dirpath);
+ return result;
+}
+
+/****************************************************************************
+ Check a filename - possibly calling check_reduced_name.
+ 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.
+****************************************************************************/
+
+NTSTATUS check_name(connection_struct *conn, const char *name)
+{
+ if (IS_VETO_PATH(conn, name)) {
+ /* Is it not dot or dot dot. */
+ if (!((name[0] == '.') && (!name[1] ||
+ (name[1] == '.' && !name[2])))) {
+ DEBUG(5,("check_name: file path name %s vetoed\n",
+ name));
+ return map_nt_error_from_unix(ENOENT);
+ }
+ }
+
+ if (!lp_widelinks(SNUM(conn)) || !lp_symlinks(SNUM(conn))) {
+ NTSTATUS status = check_reduced_name(conn,name);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("check_name: name %s failed with %s\n",name,
+ nt_errstr(status)));
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Check if two filenames are equal.
+ This needs to be careful about whether we are case sensitive.
+****************************************************************************/
+
+static bool fname_equal(const char *name1, const char *name2,
+ bool case_sensitive)
+{
+ /* Normal filename handling */
+ if (case_sensitive) {
+ return(strcmp(name1,name2) == 0);
+ }
+
+ return(strequal(name1,name2));
+}
+
+/****************************************************************************
+ 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(connection_struct *conn, const char *path,
+ char *name, char **found_name)
+{
+ struct smb_Dir *cur_dir;
+ const char *dname;
+ bool mangled;
+ char *unmangled_name = NULL;
+ long curpos;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ mangled = mangle_is_mangled(name, conn->params);
+
+ /* handle null paths */
+ if ((path == NULL) || (*path == 0)) {
+ path = ".";
+ }
+
+ /* If we have a case-sensitive filesystem, it doesn't do us any
+ * good to search for a name. If a case variation of the name was
+ * there, then the original stat(2) would have found it.
+ */
+ if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
+ errno = ENOENT;
+ return False;
+ }
+
+ /*
+ * 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_to_8_3()
+ * call. We need to mangle both names or neither.
+ * (JRA).
+ *
+ * Fix for bug found by Dina Fine. If in case sensitive mode then
+ * the mangle cache is no good (3 letter extension could be wrong
+ * case - so don't demangle in this case - leave as mangled and
+ * allow the mangling of the directory entry read (which is done
+ * case insensitively) to match instead. This will lead to more
+ * false positive matches but we fail completely without it. JRA.
+ */
+
+ if (mangled && !conn->case_sensitive) {
+ mangled = !mangle_lookup_name_from_8_3(ctx,
+ name,
+ &unmangled_name,
+ conn->params);
+ if (!mangled) {
+ /* Name is now unmangled. */
+ name = unmangled_name;
+ }
+ }
+
+ /* open the directory */
+ if (!(cur_dir = OpenDir(talloc_tos(), conn, path, NULL, 0))) {
+ DEBUG(3,("scan dir didn't open dir [%s]\n",path));
+ TALLOC_FREE(unmangled_name);
+ return(False);
+ }
+
+ /* now scan for matching names */
+ curpos = 0;
+ while ((dname = ReadDirName(cur_dir, &curpos))) {
+
+ /* Is it dot or dot dot. */
+ if (ISDOT(dname) || ISDOTDOT(dname)) {
+ continue;
+ }
+
+ /*
+ * At this point dname is the unmangled name.
+ * name is either mangled or not, depending on the state
+ * of the "mangled" variable. JRA.
+ */
+
+ /*
+ * Check mangled name against mangled name, or unmangled name
+ * against unmangled name.
+ */
+
+ if ((mangled && mangled_equal(name,dname,conn->params)) ||
+ fname_equal(name, dname, conn->case_sensitive)) {
+ /* we've found the file, change it's name and return */
+ *found_name = talloc_strdup(ctx,dname);
+ TALLOC_FREE(unmangled_name);
+ TALLOC_FREE(cur_dir);
+ if (!*found_name) {
+ errno = ENOMEM;
+ return False;
+ }
+ return(True);
+ }
+ }
+
+ TALLOC_FREE(unmangled_name);
+ TALLOC_FREE(cur_dir);
+ errno = ENOENT;
+ return False;
+}
+
+static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
+ connection_struct *conn,
+ const char *orig_path,
+ const char *basepath,
+ const char *streamname,
+ SMB_STRUCT_STAT *pst,
+ char **path)
+{
+ SMB_STRUCT_STAT st;
+ char *result = NULL;
+ NTSTATUS status;
+ unsigned int i, num_streams;
+ struct stream_struct *streams = NULL;
+
+ result = talloc_asprintf(mem_ctx, "%s%s", basepath, streamname);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (SMB_VFS_STAT(conn, result, &st) == 0) {
+ *pst = st;
+ *path = result;
+ return NT_STATUS_OK;
+ }
+
+ if (errno != ENOENT) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(10, ("vfs_stat failed: %s\n", nt_errstr(status)));
+ goto fail;
+ }
+
+ status = SMB_VFS_STREAMINFO(conn, NULL, basepath, mem_ctx,
+ &num_streams, &streams);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ SET_STAT_INVALID(*pst);
+ *path = result;
+ return NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("vfs_streaminfo failed: %s\n", nt_errstr(status)));
+ goto fail;
+ }
+
+ for (i=0; i<num_streams; i++) {
+ DEBUG(10, ("comparing [%s] and [%s]: ",
+ streamname, streams[i].name));
+ if (fname_equal(streamname, streams[i].name,
+ conn->case_sensitive)) {
+ DEBUGADD(10, ("equal\n"));
+ break;
+ }
+ DEBUGADD(10, ("not equal\n"));
+ }
+
+ if (i == num_streams) {
+ SET_STAT_INVALID(*pst);
+ *path = result;
+ TALLOC_FREE(streams);
+ return NT_STATUS_OK;
+ }
+
+ TALLOC_FREE(result);
+
+ result = talloc_asprintf(mem_ctx, "%s%s", basepath, streams[i].name);
+ if (result == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ SET_STAT_INVALID(*pst);
+
+ if (SMB_VFS_STAT(conn, result, pst) == 0) {
+ stat_cache_add(orig_path, result, conn->case_sensitive);
+ }
+
+ *path = result;
+ TALLOC_FREE(streams);
+ return NT_STATUS_OK;
+
+ fail:
+ TALLOC_FREE(result);
+ TALLOC_FREE(streams);
+ return status;
+}
diff --git a/source3/smbd/files.c b/source3/smbd/files.c
new file mode 100644
index 0000000000..17c473f028
--- /dev/null
+++ b/source3/smbd/files.c
@@ -0,0 +1,547 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static int real_max_open_files;
+
+#define VALID_FNUM(fnum) (((fnum) >= 0) && ((fnum) < real_max_open_files))
+
+#define FILE_HANDLE_OFFSET 0x1000
+
+static struct bitmap *file_bmap;
+
+static files_struct *Files;
+
+/* a fsp to use when chaining */
+static files_struct *chain_fsp = NULL;
+
+static int files_used;
+
+/* A singleton cache to speed up searching by dev/inode. */
+static struct fsp_singleton_cache {
+ files_struct *fsp;
+ struct file_id id;
+} fsp_fi_cache;
+
+/****************************************************************************
+ Return a unique number identifying this fsp over the life of this pid.
+****************************************************************************/
+
+static unsigned long get_gen_count(void)
+{
+ static unsigned long file_gen_counter;
+
+ if ((++file_gen_counter) == 0)
+ return ++file_gen_counter;
+ return file_gen_counter;
+}
+
+/****************************************************************************
+ Find first available file slot.
+****************************************************************************/
+
+NTSTATUS file_new(connection_struct *conn, files_struct **result)
+{
+ int i;
+ static int first_file;
+ files_struct *fsp;
+
+ /* we want to give out file handles differently on each new
+ connection because of a common bug in MS clients where they try to
+ reuse a file descriptor from an earlier smb connection. This code
+ increases the chance that the errant client will get an error rather
+ than causing corruption */
+ if (first_file == 0) {
+ first_file = (sys_getpid() ^ (int)time(NULL)) % real_max_open_files;
+ }
+
+ /* TODO: Port the id-tree implementation from Samba4 */
+
+ i = bitmap_find(file_bmap, first_file);
+ if (i == -1) {
+ DEBUG(0,("ERROR! Out of file structures\n"));
+ /* TODO: We have to unconditionally return a DOS error here,
+ * W2k3 even returns ERRDOS/ERRnofids for ntcreate&x with
+ * NTSTATUS negotiated */
+ return NT_STATUS_TOO_MANY_OPENED_FILES;
+ }
+
+ fsp = SMB_MALLOC_P(files_struct);
+ if (!fsp) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCTP(fsp);
+
+ fsp->fh = SMB_MALLOC_P(struct fd_handle);
+ if (!fsp->fh) {
+ SAFE_FREE(fsp);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCTP(fsp->fh);
+
+ fsp->fh->ref_count = 1;
+ fsp->fh->fd = -1;
+
+ fsp->conn = conn;
+ fsp->fh->gen_id = get_gen_count();
+ GetTimeOfDay(&fsp->open_time);
+
+ first_file = (i+1) % real_max_open_files;
+
+ bitmap_set(file_bmap, i);
+ files_used++;
+
+ fsp->fnum = i + FILE_HANDLE_OFFSET;
+ SMB_ASSERT(fsp->fnum < 65536);
+
+ string_set(&fsp->fsp_name,"");
+
+ DLIST_ADD(Files, fsp);
+
+ DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n",
+ i, fsp->fnum, files_used));
+
+ chain_fsp = fsp;
+
+ /* A new fsp invalidates a negative fsp_fi_cache. */
+ if (fsp_fi_cache.fsp == NULL) {
+ ZERO_STRUCT(fsp_fi_cache);
+ }
+
+ *result = fsp;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Close all open files for a connection.
+****************************************************************************/
+
+void file_close_conn(connection_struct *conn)
+{
+ files_struct *fsp, *next;
+
+ for (fsp=Files;fsp;fsp=next) {
+ next = fsp->next;
+ if (fsp->conn == conn) {
+ close_file(fsp,SHUTDOWN_CLOSE);
+ }
+ }
+}
+
+/****************************************************************************
+ Close all open files for a pid and a vuid.
+****************************************************************************/
+
+void file_close_pid(uint16 smbpid, int vuid)
+{
+ files_struct *fsp, *next;
+
+ for (fsp=Files;fsp;fsp=next) {
+ next = fsp->next;
+ if ((fsp->file_pid == smbpid) && (fsp->vuid == vuid)) {
+ close_file(fsp,SHUTDOWN_CLOSE);
+ }
+ }
+}
+
+/****************************************************************************
+ Initialise file structures.
+****************************************************************************/
+
+#define MAX_OPEN_FUDGEFACTOR 20
+
+void file_init(void)
+{
+ int request_max_open_files = lp_max_open_files();
+ int real_lim;
+
+ /*
+ * Set the max_open files to be the requested
+ * max plus a fudgefactor to allow for the extra
+ * fd's we need such as log files etc...
+ */
+ real_lim = set_maxfiles(request_max_open_files + MAX_OPEN_FUDGEFACTOR);
+
+ real_max_open_files = real_lim - MAX_OPEN_FUDGEFACTOR;
+
+ if (real_max_open_files + FILE_HANDLE_OFFSET + MAX_OPEN_PIPES > 65536)
+ real_max_open_files = 65536 - FILE_HANDLE_OFFSET - MAX_OPEN_PIPES;
+
+ if(real_max_open_files != request_max_open_files) {
+ DEBUG(1,("file_init: Information only: requested %d \
+open files, %d are available.\n", request_max_open_files, real_max_open_files));
+ }
+
+ SMB_ASSERT(real_max_open_files > 100);
+
+ file_bmap = bitmap_allocate(real_max_open_files);
+
+ if (!file_bmap) {
+ exit_server("out of memory in file_init");
+ }
+
+ /*
+ * Ensure that pipe_handle_oppset is set correctly.
+ */
+ set_pipe_handle_offset(real_max_open_files);
+}
+
+/****************************************************************************
+ Close files open by a specified vuid.
+****************************************************************************/
+
+void file_close_user(int vuid)
+{
+ files_struct *fsp, *next;
+
+ for (fsp=Files;fsp;fsp=next) {
+ next=fsp->next;
+ if (fsp->vuid == vuid) {
+ close_file(fsp,SHUTDOWN_CLOSE);
+ }
+ }
+}
+
+/****************************************************************************
+ Debug to enumerate all open files in the smbd.
+****************************************************************************/
+
+void file_dump_open_table(void)
+{
+ int count=0;
+ files_struct *fsp;
+
+ for (fsp=Files;fsp;fsp=fsp->next,count++) {
+ DEBUG(10,("Files[%d], fnum = %d, name %s, fd = %d, gen = %lu, fileid=%s\n",
+ count, fsp->fnum, fsp->fsp_name, fsp->fh->fd, (unsigned long)fsp->fh->gen_id,
+ file_id_string_tos(&fsp->file_id)));
+ }
+}
+
+/****************************************************************************
+ Find a fsp given a file descriptor.
+****************************************************************************/
+
+files_struct *file_find_fd(int fd)
+{
+ int count=0;
+ files_struct *fsp;
+
+ for (fsp=Files;fsp;fsp=fsp->next,count++) {
+ if (fsp->fh->fd == fd) {
+ if (count > 10) {
+ DLIST_PROMOTE(Files, fsp);
+ }
+ return fsp;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Find a fsp given a device, inode and file_id.
+****************************************************************************/
+
+files_struct *file_find_dif(struct file_id id, unsigned long gen_id)
+{
+ int count=0;
+ files_struct *fsp;
+
+ for (fsp=Files;fsp;fsp=fsp->next,count++) {
+ /* We can have a fsp->fh->fd == -1 here as it could be a stat open. */
+ if (file_id_equal(&fsp->file_id, &id) &&
+ fsp->fh->gen_id == gen_id ) {
+ if (count > 10) {
+ DLIST_PROMOTE(Files, fsp);
+ }
+ /* Paranoia check. */
+ if ((fsp->fh->fd == -1) &&
+ (fsp->oplock_type != NO_OPLOCK) &&
+ (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK)) {
+ DEBUG(0,("file_find_dif: file %s file_id = %s, gen = %u \
+oplock_type = %u is a stat open with oplock type !\n", fsp->fsp_name,
+ file_id_string_tos(&fsp->file_id),
+ (unsigned int)fsp->fh->gen_id,
+ (unsigned int)fsp->oplock_type ));
+ smb_panic("file_find_dif");
+ }
+ return fsp;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Check if an fsp still exists.
+****************************************************************************/
+
+files_struct *file_find_fsp(files_struct *orig_fsp)
+{
+ files_struct *fsp;
+
+ for (fsp=Files;fsp;fsp=fsp->next) {
+ if (fsp == orig_fsp)
+ return fsp;
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Find the first fsp given a device and inode.
+ We use a singleton cache here to speed up searching from getfilepathinfo
+ calls.
+****************************************************************************/
+
+files_struct *file_find_di_first(struct file_id id)
+{
+ files_struct *fsp;
+
+ if (file_id_equal(&fsp_fi_cache.id, &id)) {
+ /* Positive or negative cache hit. */
+ return fsp_fi_cache.fsp;
+ }
+
+ fsp_fi_cache.id = id;
+
+ for (fsp=Files;fsp;fsp=fsp->next) {
+ if ( fsp->fh->fd != -1 &&
+ file_id_equal(&fsp->file_id, &id)) {
+ /* Setup positive cache. */
+ fsp_fi_cache.fsp = fsp;
+ return fsp;
+ }
+ }
+
+ /* Setup negative cache. */
+ fsp_fi_cache.fsp = NULL;
+ return NULL;
+}
+
+/****************************************************************************
+ Find the next fsp having the same device and inode.
+****************************************************************************/
+
+files_struct *file_find_di_next(files_struct *start_fsp)
+{
+ files_struct *fsp;
+
+ for (fsp = start_fsp->next;fsp;fsp=fsp->next) {
+ if ( fsp->fh->fd != -1 &&
+ file_id_equal(&fsp->file_id, &start_fsp->file_id)) {
+ return fsp;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Find a fsp that is open for printing.
+****************************************************************************/
+
+files_struct *file_find_print(void)
+{
+ files_struct *fsp;
+
+ for (fsp=Files;fsp;fsp=fsp->next) {
+ if (fsp->print_file) {
+ return fsp;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Sync open files on a connection.
+****************************************************************************/
+
+void file_sync_all(connection_struct *conn)
+{
+ files_struct *fsp, *next;
+
+ for (fsp=Files;fsp;fsp=next) {
+ next=fsp->next;
+ if ((conn == fsp->conn) && (fsp->fh->fd != -1)) {
+ sync_file(conn, fsp, True /* write through */);
+ }
+ }
+}
+
+/****************************************************************************
+ Free up a fsp.
+****************************************************************************/
+
+void file_free(files_struct *fsp)
+{
+ DLIST_REMOVE(Files, fsp);
+
+ string_free(&fsp->fsp_name);
+
+ if (fsp->fake_file_handle) {
+ destroy_fake_file_handle(&fsp->fake_file_handle);
+ }
+
+ if (fsp->fh->ref_count == 1) {
+ SAFE_FREE(fsp->fh);
+ } else {
+ fsp->fh->ref_count--;
+ }
+
+ if (fsp->notify) {
+ notify_remove(fsp->conn->notify_ctx, fsp);
+ TALLOC_FREE(fsp->notify);
+ }
+
+ /* Ensure this event will never fire. */
+ TALLOC_FREE(fsp->oplock_timeout);
+
+ /* Ensure this event will never fire. */
+ TALLOC_FREE(fsp->update_write_time_event);
+
+ 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;
+ }
+
+ /* Closing a file can invalidate the positive cache. */
+ if (fsp == fsp_fi_cache.fsp) {
+ ZERO_STRUCT(fsp_fi_cache);
+ }
+
+ /* Drop all remaining extensions. */
+ while (fsp->vfs_extension) {
+ vfs_remove_fsp_extension(fsp->vfs_extension->owner, fsp);
+ }
+
+ SAFE_FREE(fsp);
+}
+
+/****************************************************************************
+ Get an fsp from a 16 bit fnum.
+****************************************************************************/
+
+files_struct *file_fnum(uint16 fnum)
+{
+ files_struct *fsp;
+ int count=0;
+
+ for (fsp=Files;fsp;fsp=fsp->next, count++) {
+ if (fsp->fnum == fnum) {
+ if (count > 10) {
+ DLIST_PROMOTE(Files, fsp);
+ }
+ return fsp;
+ }
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ Get an fsp from a packet given the offset of a 16 bit fnum.
+****************************************************************************/
+
+files_struct *file_fsp(uint16 fid)
+{
+ files_struct *fsp;
+
+ if (chain_fsp) {
+ return chain_fsp;
+ }
+
+ fsp = file_fnum(fid);
+ if (fsp) {
+ chain_fsp = fsp;
+ }
+ return fsp;
+}
+
+/****************************************************************************
+ Reset the chained fsp - done at the start of a packet reply.
+****************************************************************************/
+
+void file_chain_reset(void)
+{
+ chain_fsp = NULL;
+}
+
+/****************************************************************************
+ Duplicate the file handle part for a DOS or FCB open.
+****************************************************************************/
+
+NTSTATUS dup_file_fsp(files_struct *fsp,
+ uint32 access_mask,
+ uint32 share_access,
+ uint32 create_options,
+ files_struct **result)
+{
+ NTSTATUS status;
+ files_struct *dup_fsp;
+
+ status = file_new(fsp->conn, &dup_fsp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ SAFE_FREE(dup_fsp->fh);
+
+ dup_fsp->fh = fsp->fh;
+ dup_fsp->fh->ref_count++;
+
+ dup_fsp->file_id = fsp->file_id;
+ dup_fsp->initial_allocation_size = fsp->initial_allocation_size;
+ dup_fsp->mode = fsp->mode;
+ dup_fsp->file_pid = fsp->file_pid;
+ dup_fsp->vuid = fsp->vuid;
+ dup_fsp->open_time = fsp->open_time;
+ dup_fsp->access_mask = access_mask;
+ dup_fsp->share_access = share_access;
+ dup_fsp->oplock_type = fsp->oplock_type;
+ dup_fsp->can_lock = fsp->can_lock;
+ dup_fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False;
+ if (!CAN_WRITE(fsp->conn)) {
+ dup_fsp->can_write = False;
+ } else {
+ dup_fsp->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ? True : False;
+ }
+ dup_fsp->print_file = fsp->print_file;
+ dup_fsp->modified = fsp->modified;
+ dup_fsp->is_directory = fsp->is_directory;
+ dup_fsp->aio_write_behind = fsp->aio_write_behind;
+ string_set(&dup_fsp->fsp_name,fsp->fsp_name);
+
+ *result = dup_fsp;
+ return NT_STATUS_OK;
+}
diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c
new file mode 100644
index 0000000000..f4c45999ba
--- /dev/null
+++ b/source3/smbd/ipc.c
@@ -0,0 +1,813 @@
+/*
+ Unix SMB/CIFS implementation.
+ Inter-process communication and named pipe handling
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ SMB Version handling
+ Copyright (C) John H Terpstra 1995-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ This file handles the named pipe and mailslot calls
+ in the SMBtrans protocol
+ */
+
+#include "includes.h"
+
+extern int max_send;
+
+#define NERR_notsupported 50
+
+static void api_no_reply(connection_struct *conn, struct smb_request *req);
+
+/*******************************************************************
+ 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,
+ char *rparam, int param_offset, int param_len,
+ char *rdata, int data_offset, int data_len)
+{
+ char *copy_into = smb_buf(outbuf);
+
+ if(param_len < 0)
+ param_len = 0;
+
+ if(data_len < 0)
+ data_len = 0;
+
+ DEBUG(5,("copy_trans_params_and_data: params[%d..%d] data[%d..%d] (align %d)\n",
+ param_offset, param_offset + param_len,
+ data_offset , data_offset + data_len,
+ align));
+
+ *copy_into = '\0';
+
+ copy_into += 1;
+
+ if (param_len)
+ memcpy(copy_into, &rparam[param_offset], param_len);
+
+ copy_into += param_len;
+ if (align) {
+ memset(copy_into, '\0', align);
+ }
+
+ copy_into += align;
+
+ if (data_len )
+ memcpy(copy_into, &rdata[data_offset], data_len);
+}
+
+/****************************************************************************
+ Send a trans reply.
+ ****************************************************************************/
+
+void send_trans_reply(connection_struct *conn, const uint8_t *inbuf,
+ char *rparam, int rparam_len,
+ char *rdata, int rdata_len,
+ bool buffer_too_large)
+{
+ int this_ldata,this_lparam;
+ int tot_data_sent = 0;
+ int tot_param_sent = 0;
+ int align;
+ char *outbuf;
+
+ int ldata = rdata ? rdata_len : 0;
+ int lparam = rparam ? rparam_len : 0;
+
+ if (buffer_too_large)
+ DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata ));
+
+ this_lparam = MIN(lparam,max_send - 500); /* hack */
+ this_ldata = MIN(ldata,max_send - (500+this_lparam));
+
+ align = ((this_lparam)%4);
+
+ if (!create_outbuf(talloc_tos(), (char *)inbuf, &outbuf,
+ 10, 1+align+this_ldata+this_lparam)) {
+ smb_panic("could not allocate outbuf");
+ }
+
+ copy_trans_params_and_data(outbuf, align,
+ rparam, tot_param_sent, this_lparam,
+ rdata, tot_data_sent, this_ldata);
+
+ SSVAL(outbuf,smb_vwv0,lparam);
+ SSVAL(outbuf,smb_vwv1,ldata);
+ SSVAL(outbuf,smb_vwv3,this_lparam);
+ SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
+ SSVAL(outbuf,smb_vwv5,0);
+ SSVAL(outbuf,smb_vwv6,this_ldata);
+ SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,
+ outbuf));
+ SSVAL(outbuf,smb_vwv8,0);
+ SSVAL(outbuf,smb_vwv9,0);
+
+ if (buffer_too_large) {
+ error_packet_set((char *)outbuf, ERRDOS, ERRmoredata,
+ STATUS_BUFFER_OVERFLOW, __LINE__, __FILE__);
+ }
+
+ show_msg(outbuf);
+ if (!srv_send_smb(smbd_server_fd(), (char *)outbuf,
+ IS_CONN_ENCRYPTED(conn))) {
+ exit_server_cleanly("send_trans_reply: srv_send_smb failed.");
+ }
+
+ TALLOC_FREE(outbuf);
+
+ tot_data_sent = this_ldata;
+ tot_param_sent = this_lparam;
+
+ while (tot_data_sent < ldata || tot_param_sent < lparam)
+ {
+ this_lparam = MIN(lparam-tot_param_sent,
+ max_send - 500); /* hack */
+ this_ldata = MIN(ldata -tot_data_sent,
+ max_send - (500+this_lparam));
+
+ if(this_lparam < 0)
+ this_lparam = 0;
+
+ if(this_ldata < 0)
+ this_ldata = 0;
+
+ align = (this_lparam%4);
+
+ if (!create_outbuf(talloc_tos(), (char *)inbuf, &outbuf,
+ 10, 1+align+this_ldata+this_lparam)) {
+ smb_panic("could not allocate outbuf");
+ }
+
+ copy_trans_params_and_data(outbuf, align,
+ rparam, tot_param_sent, this_lparam,
+ rdata, tot_data_sent, 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_sent);
+ SSVAL(outbuf,smb_vwv6,this_ldata);
+ SSVAL(outbuf,smb_vwv7,
+ smb_offset(smb_buf(outbuf)+1+this_lparam+align, outbuf));
+ SSVAL(outbuf,smb_vwv8,tot_data_sent);
+ SSVAL(outbuf,smb_vwv9,0);
+
+ if (buffer_too_large) {
+ error_packet_set(outbuf, ERRDOS, ERRmoredata,
+ STATUS_BUFFER_OVERFLOW,
+ __LINE__, __FILE__);
+ }
+
+ show_msg(outbuf);
+ if (!srv_send_smb(smbd_server_fd(), outbuf,
+ IS_CONN_ENCRYPTED(conn)))
+ exit_server_cleanly("send_trans_reply: srv_send_smb "
+ "failed.");
+
+ tot_data_sent += this_ldata;
+ tot_param_sent += this_lparam;
+ TALLOC_FREE(outbuf);
+ }
+}
+
+/****************************************************************************
+ Start the first part of an RPC reply which began with an SMBtrans request.
+****************************************************************************/
+
+static void api_rpc_trans_reply(connection_struct *conn, struct smb_request *req, smb_np_struct *p)
+{
+ bool is_data_outstanding;
+ char *rdata = (char *)SMB_MALLOC(p->max_trans_reply);
+ int data_len;
+
+ if(rdata == NULL) {
+ DEBUG(0,("api_rpc_trans_reply: malloc fail.\n"));
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+
+ if((data_len = read_from_pipe( p, rdata, p->max_trans_reply,
+ &is_data_outstanding)) < 0) {
+ SAFE_FREE(rdata);
+ api_no_reply(conn,req);
+ return;
+ }
+
+ send_trans_reply(conn, req->inbuf, NULL, 0, rdata, data_len,
+ is_data_outstanding);
+ SAFE_FREE(rdata);
+ return;
+}
+
+/****************************************************************************
+ WaitNamedPipeHandleState
+****************************************************************************/
+
+static void api_WNPHS(connection_struct *conn, struct smb_request *req, smb_np_struct *p,
+ char *param, int param_len)
+{
+ uint16 priority;
+
+ if (!param || param_len < 2) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ priority = SVAL(param,0);
+ DEBUG(4,("WaitNamedPipeHandleState priority %x\n", priority));
+
+ if (wait_rpc_pipe_hnd_state(p, priority)) {
+ /* now send the reply */
+ send_trans_reply(conn, req->inbuf, NULL, 0, NULL, 0, False);
+ return;
+ }
+ api_no_reply(conn,req);
+}
+
+
+/****************************************************************************
+ SetNamedPipeHandleState
+****************************************************************************/
+
+static void api_SNPHS(connection_struct *conn, struct smb_request *req, smb_np_struct *p,
+ char *param, int param_len)
+{
+ uint16 id;
+
+ if (!param || param_len < 2) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ id = SVAL(param,0);
+ DEBUG(4,("SetNamedPipeHandleState to code %x\n", id));
+
+ if (set_rpc_pipe_hnd_state(p, id)) {
+ /* now send the reply */
+ send_trans_reply(conn, req->inbuf, NULL, 0, NULL, 0, False);
+ return;
+ }
+ api_no_reply(conn,req);
+}
+
+
+/****************************************************************************
+ When no reply is generated, indicate unsupported.
+ ****************************************************************************/
+
+static void api_no_reply(connection_struct *conn, struct smb_request *req)
+{
+ char rparam[4];
+
+ /* unsupported */
+ SSVAL(rparam,0,NERR_notsupported);
+ SSVAL(rparam,2,0); /* converter word */
+
+ DEBUG(3,("Unsupported API fd command\n"));
+
+ /* now send the reply */
+ send_trans_reply(conn, req->inbuf, rparam, 4, NULL, 0, False);
+
+ return;
+}
+
+/****************************************************************************
+ Handle remote api calls delivered to a named pipe already opened.
+ ****************************************************************************/
+
+static void api_fd_reply(connection_struct *conn, uint16 vuid,
+ struct smb_request *req,
+ uint16 *setup, char *data, char *params,
+ int suwcnt, int tdscnt, int tpscnt,
+ int mdrcnt, int mprcnt)
+{
+ bool reply = False;
+ smb_np_struct *p = NULL;
+ int pnum;
+ int subcommand;
+
+ DEBUG(5,("api_fd_reply\n"));
+
+ /* First find out the name of this file. */
+ if (suwcnt != 2) {
+ DEBUG(0,("Unexpected named pipe transaction.\n"));
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ /* Get the file handle and hence the file name. */
+ /*
+ * NB. The setup array has already been transformed
+ * via SVAL and so is in gost byte order.
+ */
+ pnum = ((int)setup[1]) & 0xFFFF;
+ subcommand = ((int)setup[0]) & 0xFFFF;
+
+ if(!(p = get_rpc_pipe(pnum))) {
+ if (subcommand == TRANSACT_WAITNAMEDPIPEHANDLESTATE) {
+ /* Win9x does this call with a unicode pipe name, not a pnum. */
+ /* Just return success for now... */
+ DEBUG(3,("Got TRANSACT_WAITNAMEDPIPEHANDLESTATE on text pipe name\n"));
+ send_trans_reply(conn, req->inbuf, NULL, 0, NULL, 0,
+ False);
+ return;
+ }
+
+ DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ return;
+ }
+
+ if (vuid != p->vuid) {
+ DEBUG(1, ("Got pipe request (pnum %x) using invalid VUID %d, "
+ "expected %d\n", pnum, vuid, p->vuid));
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ return;
+ }
+
+ DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)\n", subcommand, p->name, pnum));
+
+ /* record maximum data length that can be transmitted in an SMBtrans */
+ p->max_trans_reply = mdrcnt;
+
+ DEBUG(10,("api_fd_reply: p:%p max_trans_reply: %d\n", p, p->max_trans_reply));
+
+ switch (subcommand) {
+ case TRANSACT_DCERPCCMD:
+ /* dce/rpc command */
+ reply = write_to_pipe(p, data, tdscnt);
+ if (!reply) {
+ api_no_reply(conn, req);
+ return;
+ }
+ api_rpc_trans_reply(conn, req, p);
+ break;
+ case TRANSACT_WAITNAMEDPIPEHANDLESTATE:
+ /* Wait Named Pipe Handle state */
+ api_WNPHS(conn, req, p, params, tpscnt);
+ break;
+ case TRANSACT_SETNAMEDPIPEHANDLESTATE:
+ /* Set Named Pipe Handle state */
+ api_SNPHS(conn, req, p, params, tpscnt);
+ break;
+ default:
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+}
+
+/****************************************************************************
+ Handle named pipe commands.
+****************************************************************************/
+
+static void named_pipe(connection_struct *conn, uint16 vuid,
+ struct smb_request *req,
+ const 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")) {
+ api_reply(conn, vuid, req,
+ data, params,
+ tdscnt, tpscnt,
+ mdrcnt, mprcnt);
+ return;
+ }
+
+ if (strequal(name,"WKSSVC") ||
+ strequal(name,"SRVSVC") ||
+ strequal(name,"WINREG") ||
+ strequal(name,"SAMR") ||
+ strequal(name,"LSARPC")) {
+
+ DEBUG(4,("named pipe command from Win95 (wow!)\n"));
+
+ api_fd_reply(conn, vuid, req,
+ setup, data, params,
+ suwcnt, tdscnt, tpscnt,
+ mdrcnt, mprcnt);
+ return;
+ }
+
+ if (strlen(name) < 1) {
+ api_fd_reply(conn, vuid, req,
+ setup, data,
+ params, suwcnt, tdscnt,
+ tpscnt, mdrcnt, mprcnt);
+ return;
+ }
+
+ if (setup)
+ DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n",
+ (int)setup[0],(int)setup[1]));
+
+ reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
+ return;
+}
+
+static void handle_trans(connection_struct *conn, struct smb_request *req,
+ struct trans_state *state)
+{
+ char *local_machine_name;
+ int name_offset = 0;
+
+ DEBUG(3,("trans <%s> data=%u params=%u setup=%u\n",
+ state->name,(unsigned int)state->total_data,(unsigned int)state->total_param,
+ (unsigned int)state->setup_count));
+
+ /*
+ * WinCE wierdness....
+ */
+
+ local_machine_name = talloc_asprintf(state, "\\%s\\",
+ get_local_machine_name());
+
+ if (local_machine_name == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+
+ if (strnequal(state->name, local_machine_name,
+ strlen(local_machine_name))) {
+ name_offset = strlen(local_machine_name)-1;
+ }
+
+ if (!strnequal(&state->name[name_offset], "\\PIPE",
+ strlen("\\PIPE"))) {
+ reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
+ return;
+ }
+
+ name_offset += strlen("\\PIPE");
+
+ /* Win9x weirdness. When talking to a unicode server Win9x
+ only sends \PIPE instead of \PIPE\ */
+
+ if (state->name[name_offset] == '\\')
+ name_offset++;
+
+ DEBUG(5,("calling named_pipe\n"));
+ named_pipe(conn, state->vuid, req,
+ state->name+name_offset,
+ state->setup,state->data,
+ state->param,
+ state->setup_count,state->total_data,
+ state->total_param,
+ state->max_setup_return,
+ state->max_data_return,
+ state->max_param_return);
+
+ if (state->close_on_completion) {
+ close_cnum(conn,state->vuid);
+ req->conn = NULL;
+ }
+
+ return;
+}
+
+/****************************************************************************
+ Reply to a SMBtrans.
+ ****************************************************************************/
+
+void reply_trans(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ unsigned int dsoff;
+ unsigned int dscnt;
+ unsigned int psoff;
+ unsigned int pscnt;
+ struct trans_state *state;
+ NTSTATUS result;
+ unsigned int size;
+ unsigned int av_size;
+
+ START_PROFILE(SMBtrans);
+
+ if (req->wct < 14) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBtrans);
+ return;
+ }
+
+ size = smb_len(req->inbuf) + 4;
+ av_size = smb_len(req->inbuf);
+ dsoff = SVAL(req->inbuf, smb_dsoff);
+ dscnt = SVAL(req->inbuf, smb_dscnt);
+ psoff = SVAL(req->inbuf, smb_psoff);
+ pscnt = SVAL(req->inbuf, smb_pscnt);
+
+ result = allow_new_trans(conn->pending_trans, req->mid);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(2, ("Got invalid trans request: %s\n",
+ nt_errstr(result)));
+ reply_nterror(req, result);
+ END_PROFILE(SMBtrans);
+ return;
+ }
+
+ if ((state = TALLOC_P(conn, struct trans_state)) == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBtrans);
+ return;
+ }
+
+ state->cmd = SMBtrans;
+
+ state->mid = req->mid;
+ state->vuid = req->vuid;
+ state->setup_count = CVAL(req->inbuf, smb_suwcnt);
+ state->setup = NULL;
+ state->total_param = SVAL(req->inbuf, smb_tpscnt);
+ state->param = NULL;
+ state->total_data = SVAL(req->inbuf, smb_tdscnt);
+ state->data = NULL;
+ state->max_param_return = SVAL(req->inbuf, smb_mprcnt);
+ state->max_data_return = SVAL(req->inbuf, smb_mdrcnt);
+ state->max_setup_return = CVAL(req->inbuf, smb_msrcnt);
+ state->close_on_completion = BITSETW(req->inbuf+smb_vwv5,0);
+ state->one_way = BITSETW(req->inbuf+smb_vwv5,1);
+
+ srvstr_pull_buf_talloc(state, req->inbuf, req->flags2, &state->name,
+ smb_buf(req->inbuf), STR_TERMINATE);
+
+ if ((dscnt > state->total_data) || (pscnt > state->total_param) ||
+ !state->name)
+ goto bad_param;
+
+ if (state->total_data) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. Out of paranoia, 100 bytes too many. */
+ state->data = (char *)SMB_MALLOC(state->total_data+100);
+ if (state->data == NULL) {
+ DEBUG(0,("reply_trans: data malloc fail for %u "
+ "bytes !\n", (unsigned int)state->total_data));
+ TALLOC_FREE(state);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBtrans);
+ return;
+ }
+ /* null-terminate the slack space */
+ memset(&state->data[state->total_data], 0, 100);
+
+ if (dscnt > state->total_data ||
+ dsoff+dscnt < dsoff) {
+ goto bad_param;
+ }
+
+ if (dsoff > av_size ||
+ dscnt > av_size ||
+ dsoff+dscnt > av_size) {
+ goto bad_param;
+ }
+
+ memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
+ }
+
+ if (state->total_param) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. Out of paranoia, 100 bytes too many */
+ state->param = (char *)SMB_MALLOC(state->total_param+100);
+ if (state->param == NULL) {
+ DEBUG(0,("reply_trans: param malloc fail for %u "
+ "bytes !\n", (unsigned int)state->total_param));
+ SAFE_FREE(state->data);
+ TALLOC_FREE(state);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBtrans);
+ return;
+ }
+ /* null-terminate the slack space */
+ memset(&state->param[state->total_param], 0, 100);
+
+ if (pscnt > state->total_param ||
+ psoff+pscnt < psoff) {
+ goto bad_param;
+ }
+
+ if (psoff > av_size ||
+ pscnt > av_size ||
+ psoff+pscnt > av_size) {
+ goto bad_param;
+ }
+
+ memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
+ }
+
+ state->received_data = dscnt;
+ state->received_param = pscnt;
+
+ if (state->setup_count) {
+ unsigned int i;
+ if((state->setup = TALLOC_ARRAY(
+ state, uint16, state->setup_count)) == NULL) {
+ DEBUG(0,("reply_trans: setup malloc fail for %u "
+ "bytes !\n", (unsigned int)
+ (state->setup_count * sizeof(uint16))));
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBtrans);
+ return;
+ }
+ if (req->inbuf+smb_vwv14+(state->setup_count*SIZEOFWORD) >
+ req->inbuf + size)
+ goto bad_param;
+ if ((smb_vwv14+(state->setup_count*SIZEOFWORD) < smb_vwv14) ||
+ (smb_vwv14+(state->setup_count*SIZEOFWORD) <
+ (state->setup_count*SIZEOFWORD)))
+ goto bad_param;
+
+ for (i=0;i<state->setup_count;i++)
+ state->setup[i] = SVAL(req->inbuf,
+ smb_vwv14+i*SIZEOFWORD);
+ }
+
+ state->received_param = pscnt;
+
+ if ((state->received_param != state->total_param) ||
+ (state->received_data != state->total_data)) {
+ DLIST_ADD(conn->pending_trans, state);
+
+ /* We need to send an interim response then receive the rest
+ of the parameter/data bytes */
+ reply_outbuf(req, 0, 0);
+ show_msg((char *)req->outbuf);
+ END_PROFILE(SMBtrans);
+ return;
+ }
+
+ handle_trans(conn, req, state);
+
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+
+ END_PROFILE(SMBtrans);
+ return;
+
+ bad_param:
+
+ DEBUG(0,("reply_trans: invalid trans parameters\n"));
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtrans);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+}
+
+/****************************************************************************
+ Reply to a secondary SMBtrans.
+ ****************************************************************************/
+
+void reply_transs(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
+ struct trans_state *state;
+ unsigned int av_size;
+
+ START_PROFILE(SMBtranss);
+
+ show_msg((char *)req->inbuf);
+
+ if (req->wct < 8) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBtranss);
+ return;
+ }
+
+ for (state = conn->pending_trans; state != NULL;
+ state = state->next) {
+ if (state->mid == req->mid) {
+ break;
+ }
+ }
+
+ if ((state == NULL) || (state->cmd != SMBtrans)) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBtranss);
+ return;
+ }
+
+ /* Revise total_params and total_data in case they have changed
+ * downwards */
+
+ if (SVAL(req->inbuf, smb_vwv0) < state->total_param)
+ state->total_param = SVAL(req->inbuf,smb_vwv0);
+ if (SVAL(req->inbuf, smb_vwv1) < state->total_data)
+ state->total_data = SVAL(req->inbuf,smb_vwv1);
+
+ av_size = smb_len(req->inbuf);
+
+ pcnt = SVAL(req->inbuf, smb_spscnt);
+ poff = SVAL(req->inbuf, smb_spsoff);
+ pdisp = SVAL(req->inbuf, smb_spsdisp);
+
+ dcnt = SVAL(req->inbuf, smb_sdscnt);
+ doff = SVAL(req->inbuf, smb_sdsoff);
+ ddisp = SVAL(req->inbuf, smb_sdsdisp);
+
+ state->received_param += pcnt;
+ state->received_data += dcnt;
+
+ if ((state->received_data > state->total_data) ||
+ (state->received_param > state->total_param))
+ goto bad_param;
+
+ if (pcnt) {
+ if (pdisp > state->total_param ||
+ pcnt > state->total_param ||
+ pdisp+pcnt > state->total_param ||
+ pdisp+pcnt < pdisp) {
+ goto bad_param;
+ }
+
+ if (poff > av_size ||
+ pcnt > av_size ||
+ poff+pcnt > av_size ||
+ poff+pcnt < poff) {
+ goto bad_param;
+ }
+
+ memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,
+ pcnt);
+ }
+
+ if (dcnt) {
+ if (ddisp > state->total_data ||
+ dcnt > state->total_data ||
+ ddisp+dcnt > state->total_data ||
+ ddisp+dcnt < ddisp) {
+ goto bad_param;
+ }
+
+ if (ddisp > av_size ||
+ dcnt > av_size ||
+ ddisp+dcnt > av_size ||
+ ddisp+dcnt < ddisp) {
+ goto bad_param;
+ }
+
+ memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,
+ dcnt);
+ }
+
+ if ((state->received_param < state->total_param) ||
+ (state->received_data < state->total_data)) {
+ END_PROFILE(SMBtranss);
+ return;
+ }
+
+ /*
+ * construct_reply_common will copy smb_com from inbuf to
+ * outbuf. SMBtranss is wrong here.
+ */
+ SCVAL(req->inbuf,smb_com,SMBtrans);
+
+ handle_trans(conn, req, state);
+
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+
+ END_PROFILE(SMBtranss);
+ return;
+
+ bad_param:
+
+ DEBUG(0,("reply_transs: invalid trans parameters\n"));
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBtranss);
+ return;
+}
diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c
new file mode 100644
index 0000000000..fe1d766b9d
--- /dev/null
+++ b/source3/smbd/lanman.c
@@ -0,0 +1,4642 @@
+/*
+ Unix SMB/CIFS implementation.
+ Inter-process communication and named pipe handling
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2007.
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ This file handles the named pipe and mailslot calls
+ in the SMBtrans protocol
+ */
+
+#include "includes.h"
+
+#ifdef CHECK_TYPES
+#undef CHECK_TYPES
+#endif
+#define CHECK_TYPES 0
+
+#define NERR_Success 0
+#define NERR_badpass 86
+#define NERR_notsupported 50
+
+#define NERR_BASE (2100)
+#define NERR_BufTooSmall (NERR_BASE+23)
+#define NERR_JobNotFound (NERR_BASE+51)
+#define NERR_DestNotFound (NERR_BASE+52)
+
+#define ACCESS_READ 0x01
+#define ACCESS_WRITE 0x02
+#define ACCESS_CREATE 0x04
+
+#define SHPWLEN 8 /* share password length */
+
+/* Limit size of ipc replies */
+
+static char *smb_realloc_limit(void *ptr, size_t size)
+{
+ char *val;
+
+ size = MAX((size),4*1024);
+ val = (char *)SMB_REALLOC(ptr,size);
+ if (val) {
+ memset(val,'\0',size);
+ }
+ return val;
+}
+
+static bool api_Unsupported(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt, int mprcnt,
+ char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len);
+
+static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
+ int mdrcnt, int mprcnt,
+ char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len);
+
+
+static int CopyExpanded(connection_struct *conn,
+ int snum, char **dst, char *src, int *p_space_remaining)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *buf = NULL;
+ int l;
+
+ if (!src || !dst || !p_space_remaining || !(*dst) ||
+ *p_space_remaining <= 0) {
+ return 0;
+ }
+
+ buf = talloc_strdup(ctx, src);
+ if (!buf) {
+ *p_space_remaining = 0;
+ return 0;
+ }
+ buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
+ if (!buf) {
+ *p_space_remaining = 0;
+ return 0;
+ }
+ buf = talloc_sub_advanced(ctx,
+ lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name,
+ conn->connectpath,
+ conn->server_info->utok.gid,
+ conn->server_info->sanitized_username,
+ pdb_get_domain(conn->server_info->sam_account),
+ buf);
+ if (!buf) {
+ *p_space_remaining = 0;
+ return 0;
+ }
+ l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
+ if (l == -1) {
+ return 0;
+ }
+ (*dst) += l;
+ (*p_space_remaining) -= l;
+ return l;
+}
+
+static int CopyAndAdvance(char **dst, char *src, int *n)
+{
+ int l;
+ if (!src || !dst || !n || !(*dst)) {
+ return 0;
+ }
+ l = push_ascii(*dst,src,*n, STR_TERMINATE);
+ if (l == -1) {
+ return 0;
+ }
+ (*dst) += l;
+ (*n) -= l;
+ return l;
+}
+
+static int StrlenExpanded(connection_struct *conn, int snum, char *s)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *buf = NULL;
+ if (!s) {
+ return 0;
+ }
+ buf = talloc_strdup(ctx,s);
+ if (!buf) {
+ return 0;
+ }
+ buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
+ if (!buf) {
+ return 0;
+ }
+ buf = talloc_sub_advanced(ctx,
+ lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name,
+ conn->connectpath,
+ conn->server_info->utok.gid,
+ conn->server_info->sanitized_username,
+ pdb_get_domain(conn->server_info->sam_account),
+ buf);
+ if (!buf) {
+ return 0;
+ }
+ return strlen(buf) + 1;
+}
+
+static char *Expand(connection_struct *conn, int snum, char *s)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *buf = NULL;
+
+ if (!s) {
+ return NULL;
+ }
+ buf = talloc_strdup(ctx,s);
+ if (!buf) {
+ return 0;
+ }
+ buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
+ if (!buf) {
+ return 0;
+ }
+ return talloc_sub_advanced(ctx,
+ lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name,
+ conn->connectpath,
+ conn->server_info->utok.gid,
+ conn->server_info->sanitized_username,
+ pdb_get_domain(conn->server_info->sam_account),
+ buf);
+}
+
+/*******************************************************************
+ Check a API string for validity when we only need to check the prefix.
+******************************************************************/
+
+static bool prefix_ok(const char *str, const char *prefix)
+{
+ return(strncmp(str,prefix,strlen(prefix)) == 0);
+}
+
+struct pack_desc {
+ const char *format; /* formatstring for structure */
+ const char *subformat; /* subformat for structure */
+ char *base; /* baseaddress of buffer */
+ int buflen; /* remaining size for fixed part; on init: length of base */
+ int subcount; /* count of substructures */
+ char *structbuf; /* pointer into buffer for remaining fixed part */
+ int stringlen; /* remaining size for variable part */
+ char *stringbuf; /* pointer into buffer for remaining variable part */
+ int neededlen; /* total needed size */
+ int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
+ const char *curpos; /* current position; pointer into format or subformat */
+ int errcode;
+};
+
+static int get_counter(const char **p)
+{
+ int i, n;
+ if (!p || !(*p)) {
+ return 1;
+ }
+ if (!isdigit((int)**p)) {
+ return 1;
+ }
+ for (n = 0;;) {
+ i = **p;
+ if (isdigit(i)) {
+ n = 10 * n + (i - '0');
+ } else {
+ return n;
+ }
+ (*p)++;
+ }
+}
+
+static int getlen(const char *p)
+{
+ int n = 0;
+ if (!p) {
+ return 0;
+ }
+
+ while (*p) {
+ switch( *p++ ) {
+ case 'W': /* word (2 byte) */
+ n += 2;
+ break;
+ case 'K': /* status word? (2 byte) */
+ n += 2;
+ break;
+ case 'N': /* count of substructures (word) at end */
+ n += 2;
+ break;
+ case 'D': /* double word (4 byte) */
+ case 'z': /* offset to zero terminated string (4 byte) */
+ case 'l': /* offset to user data (4 byte) */
+ n += 4;
+ break;
+ case 'b': /* offset to data (with counter) (4 byte) */
+ n += 4;
+ get_counter(&p);
+ break;
+ case 'B': /* byte (with optional counter) */
+ n += get_counter(&p);
+ break;
+ }
+ }
+ return n;
+}
+
+static bool init_package(struct pack_desc *p, int count, int subcount)
+{
+ int n = p->buflen;
+ int i;
+
+ if (!p->format || !p->base) {
+ return False;
+ }
+
+ i = count * getlen(p->format);
+ if (p->subformat) {
+ i += subcount * getlen(p->subformat);
+ }
+ p->structbuf = p->base;
+ p->neededlen = 0;
+ p->usedlen = 0;
+ p->subcount = 0;
+ p->curpos = p->format;
+ if (i > n) {
+ p->neededlen = i;
+ i = n = 0;
+#if 0
+ /*
+ * This is the old error code we used. Aparently
+ * WinNT/2k systems return ERRbuftoosmall (2123) and
+ * OS/2 needs this. I'm leaving this here so we can revert
+ * if needed. JRA.
+ */
+ p->errcode = ERRmoredata;
+#else
+ p->errcode = ERRbuftoosmall;
+#endif
+ } else {
+ p->errcode = NERR_Success;
+ }
+ p->buflen = i;
+ n -= i;
+ p->stringbuf = p->base + i;
+ p->stringlen = n;
+ return (p->errcode == NERR_Success);
+}
+
+static int package(struct pack_desc *p, ...)
+{
+ va_list args;
+ int needed=0, stringneeded;
+ const char *str=NULL;
+ int is_string=0, stringused;
+ int32 temp;
+
+ va_start(args,p);
+
+ if (!*p->curpos) {
+ if (!p->subcount) {
+ p->curpos = p->format;
+ } else {
+ p->curpos = p->subformat;
+ p->subcount--;
+ }
+ }
+#if CHECK_TYPES
+ str = va_arg(args,char*);
+ SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
+#endif
+ stringneeded = -1;
+
+ if (!p->curpos) {
+ va_end(args);
+ return 0;
+ }
+
+ switch( *p->curpos++ ) {
+ case 'W': /* word (2 byte) */
+ needed = 2;
+ temp = va_arg(args,int);
+ if (p->buflen >= needed) {
+ SSVAL(p->structbuf,0,temp);
+ }
+ break;
+ case 'K': /* status word? (2 byte) */
+ needed = 2;
+ temp = va_arg(args,int);
+ if (p->buflen >= needed) {
+ SSVAL(p->structbuf,0,temp);
+ }
+ break;
+ case 'N': /* count of substructures (word) at end */
+ needed = 2;
+ p->subcount = va_arg(args,int);
+ if (p->buflen >= needed) {
+ SSVAL(p->structbuf,0,p->subcount);
+ }
+ break;
+ case 'D': /* double word (4 byte) */
+ needed = 4;
+ temp = va_arg(args,int);
+ if (p->buflen >= needed) {
+ SIVAL(p->structbuf,0,temp);
+ }
+ break;
+ case 'B': /* byte (with optional counter) */
+ needed = get_counter(&p->curpos);
+ {
+ char *s = va_arg(args,char*);
+ if (p->buflen >= needed) {
+ StrnCpy(p->structbuf,s?s:"",needed-1);
+ }
+ }
+ break;
+ case 'z': /* offset to zero terminated string (4 byte) */
+ str = va_arg(args,char*);
+ stringneeded = (str ? strlen(str)+1 : 0);
+ is_string = 1;
+ break;
+ case 'l': /* offset to user data (4 byte) */
+ str = va_arg(args,char*);
+ stringneeded = va_arg(args,int);
+ is_string = 0;
+ break;
+ case 'b': /* offset to data (with counter) (4 byte) */
+ str = va_arg(args,char*);
+ stringneeded = get_counter(&p->curpos);
+ is_string = 0;
+ break;
+ }
+
+ va_end(args);
+ if (stringneeded >= 0) {
+ needed = 4;
+ if (p->buflen >= needed) {
+ stringused = stringneeded;
+ if (stringused > p->stringlen) {
+ stringused = (is_string ? p->stringlen : 0);
+ if (p->errcode == NERR_Success) {
+ p->errcode = ERRmoredata;
+ }
+ }
+ if (!stringused) {
+ SIVAL(p->structbuf,0,0);
+ } else {
+ SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
+ memcpy(p->stringbuf,str?str:"",stringused);
+ if (is_string) {
+ p->stringbuf[stringused-1] = '\0';
+ }
+ p->stringbuf += stringused;
+ p->stringlen -= stringused;
+ p->usedlen += stringused;
+ }
+ }
+ p->neededlen += stringneeded;
+ }
+
+ p->neededlen += needed;
+ if (p->buflen >= needed) {
+ p->structbuf += needed;
+ p->buflen -= needed;
+ p->usedlen += needed;
+ } else {
+ if (p->errcode == NERR_Success) {
+ p->errcode = ERRmoredata;
+ }
+ }
+ return 1;
+}
+
+#if CHECK_TYPES
+#define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
+#define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
+#else
+#define PACK(desc,t,v) package(desc,v)
+#define PACKl(desc,t,v,l) package(desc,v,l)
+#endif
+
+static void PACKI(struct pack_desc* desc, const char *t,int v)
+{
+ PACK(desc,t,v);
+}
+
+static void PACKS(struct pack_desc* desc,const char *t,const char *v)
+{
+ PACK(desc,t,v);
+}
+
+/****************************************************************************
+ Get a print queue.
+****************************************************************************/
+
+static void PackDriverData(struct pack_desc* desc)
+{
+ char drivdata[4+4+32];
+ SIVAL(drivdata,0,sizeof drivdata); /* cb */
+ SIVAL(drivdata,4,1000); /* lVersion */
+ memset(drivdata+8,0,32); /* szDeviceName */
+ push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
+ PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
+}
+
+static int check_printq_info(struct pack_desc* desc,
+ unsigned int uLevel, char *id1, char *id2)
+{
+ desc->subformat = NULL;
+ switch( uLevel ) {
+ case 0:
+ desc->format = "B13";
+ break;
+ case 1:
+ desc->format = "B13BWWWzzzzzWW";
+ break;
+ case 2:
+ desc->format = "B13BWWWzzzzzWN";
+ desc->subformat = "WB21BB16B10zWWzDDz";
+ break;
+ case 3:
+ desc->format = "zWWWWzzzzWWzzl";
+ break;
+ case 4:
+ desc->format = "zWWWWzzzzWNzzl";
+ desc->subformat = "WWzWWDDzz";
+ break;
+ case 5:
+ desc->format = "z";
+ break;
+ case 51:
+ desc->format = "K";
+ break;
+ case 52:
+ desc->format = "WzzzzzzzzN";
+ desc->subformat = "z";
+ break;
+ default:
+ DEBUG(0,("check_printq_info: invalid level %d\n",
+ uLevel ));
+ return False;
+ }
+ if (id1 == NULL || strcmp(desc->format,id1) != 0) {
+ DEBUG(0,("check_printq_info: invalid format %s\n",
+ id1 ? id1 : "<NULL>" ));
+ return False;
+ }
+ if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
+ DEBUG(0,("check_printq_info: invalid subformat %s\n",
+ id2 ? id2 : "<NULL>" ));
+ return False;
+ }
+ return True;
+}
+
+
+#define RAP_JOB_STATUS_QUEUED 0
+#define RAP_JOB_STATUS_PAUSED 1
+#define RAP_JOB_STATUS_SPOOLING 2
+#define RAP_JOB_STATUS_PRINTING 3
+#define RAP_JOB_STATUS_PRINTED 4
+
+#define RAP_QUEUE_STATUS_PAUSED 1
+#define RAP_QUEUE_STATUS_ERROR 2
+
+/* turn a print job status into a on the wire status
+*/
+static int printj_status(int v)
+{
+ switch (v) {
+ case LPQ_QUEUED:
+ return RAP_JOB_STATUS_QUEUED;
+ case LPQ_PAUSED:
+ return RAP_JOB_STATUS_PAUSED;
+ case LPQ_SPOOLING:
+ return RAP_JOB_STATUS_SPOOLING;
+ case LPQ_PRINTING:
+ return RAP_JOB_STATUS_PRINTING;
+ }
+ return 0;
+}
+
+/* turn a print queue status into a on the wire status
+*/
+static int printq_status(int v)
+{
+ switch (v) {
+ case LPQ_QUEUED:
+ return 0;
+ case LPQ_PAUSED:
+ return RAP_QUEUE_STATUS_PAUSED;
+ }
+ return RAP_QUEUE_STATUS_ERROR;
+}
+
+static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
+ struct pack_desc *desc,
+ print_queue_struct *queue, int n)
+{
+ time_t t = queue->time;
+
+ /* the client expects localtime */
+ t -= get_time_zone(t);
+
+ PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
+ if (uLevel == 1) {
+ PACKS(desc,"B21",queue->fs_user); /* szUserName */
+ PACKS(desc,"B",""); /* pad */
+ PACKS(desc,"B16",""); /* szNotifyName */
+ PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
+ PACKS(desc,"z",""); /* pszParms */
+ PACKI(desc,"W",n+1); /* uPosition */
+ PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
+ PACKS(desc,"z",""); /* pszStatus */
+ PACKI(desc,"D",t); /* ulSubmitted */
+ PACKI(desc,"D",queue->size); /* ulSize */
+ PACKS(desc,"z",queue->fs_file); /* pszComment */
+ }
+ if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
+ PACKI(desc,"W",queue->priority); /* uPriority */
+ PACKS(desc,"z",queue->fs_user); /* pszUserName */
+ PACKI(desc,"W",n+1); /* uPosition */
+ PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
+ PACKI(desc,"D",t); /* ulSubmitted */
+ PACKI(desc,"D",queue->size); /* ulSize */
+ PACKS(desc,"z","Samba"); /* pszComment */
+ PACKS(desc,"z",queue->fs_file); /* pszDocument */
+ if (uLevel == 3) {
+ PACKS(desc,"z",""); /* pszNotifyName */
+ PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
+ PACKS(desc,"z",""); /* pszParms */
+ PACKS(desc,"z",""); /* pszStatus */
+ PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
+ PACKS(desc,"z","lpd"); /* pszQProcName */
+ PACKS(desc,"z",""); /* pszQProcParms */
+ PACKS(desc,"z","NULL"); /* pszDriverName */
+ PackDriverData(desc); /* pDriverData */
+ PACKS(desc,"z",""); /* pszPrinterName */
+ } else if (uLevel == 4) { /* OS2 */
+ PACKS(desc,"z",""); /* pszSpoolFileName */
+ PACKS(desc,"z",""); /* pszPortName */
+ PACKS(desc,"z",""); /* pszStatus */
+ PACKI(desc,"D",0); /* ulPagesSpooled */
+ PACKI(desc,"D",0); /* ulPagesSent */
+ PACKI(desc,"D",0); /* ulPagesPrinted */
+ PACKI(desc,"D",0); /* ulTimePrinted */
+ PACKI(desc,"D",0); /* ulExtendJobStatus */
+ PACKI(desc,"D",0); /* ulStartPage */
+ PACKI(desc,"D",0); /* ulEndPage */
+ }
+ }
+}
+
+/********************************************************************
+ Return a driver name given an snum.
+ Returns True if from tdb, False otherwise.
+ ********************************************************************/
+
+static bool get_driver_name(int snum, char **pp_drivername)
+{
+ NT_PRINTER_INFO_LEVEL *info = NULL;
+ bool in_tdb = false;
+
+ get_a_printer (NULL, &info, 2, lp_servicename(snum));
+ if (info != NULL) {
+ *pp_drivername = talloc_strdup(talloc_tos(),
+ info->info_2->drivername);
+ in_tdb = true;
+ free_a_printer(&info, 2);
+ if (!*pp_drivername) {
+ return false;
+ }
+ }
+
+ return in_tdb;
+}
+
+/********************************************************************
+ Respond to the DosPrintQInfo command with a level of 52
+ This is used to get printer driver information for Win9x clients
+ ********************************************************************/
+static void fill_printq_info_52(connection_struct *conn, int snum,
+ struct pack_desc* desc, int count )
+{
+ int i;
+ fstring location;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+ ZERO_STRUCT(driver);
+
+ if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
+ DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
+ lp_servicename(snum)));
+ goto err;
+ }
+
+ if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
+ "Windows 4.0", 0)) )
+ {
+ DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
+ printer->info_2->drivername));
+ goto err;
+ }
+
+ trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
+ trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
+ trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
+
+ PACKI(desc, "W", 0x0400); /* don't know */
+ PACKS(desc, "z", driver.info_3->name); /* long printer name */
+ PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
+ PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
+ PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
+
+ fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
+ standard_sub_basic( "", "", location, sizeof(location)-1 );
+ PACKS(desc,"z", location); /* share to retrieve files */
+
+ PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
+ PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
+ PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
+
+ DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
+ DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
+ DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
+ DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
+ DEBUG(3,("Driver Location: %s:\n",location));
+ DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
+ DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
+ PACKI(desc,"N",count); /* number of files to copy */
+
+ for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
+ {
+ trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
+ PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
+ DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
+ }
+
+ /* sanity check */
+ if ( i != count )
+ DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
+ count, i));
+
+ DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
+
+ desc->errcode=NERR_Success;
+ goto done;
+
+err:
+ DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
+ desc->errcode=NERR_notsupported;
+
+done:
+ if ( printer )
+ free_a_printer( &printer, 2 );
+
+ if ( driver.info_3 )
+ free_a_printer_driver( driver, 3 );
+}
+
+
+static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
+ struct pack_desc* desc,
+ int count, print_queue_struct* queue,
+ print_status_struct* status)
+{
+ switch (uLevel) {
+ case 1:
+ case 2:
+ PACKS(desc,"B13",SERVICE(snum));
+ break;
+ case 3:
+ case 4:
+ case 5:
+ PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
+ break;
+ case 51:
+ PACKI(desc,"K",printq_status(status->status));
+ break;
+ }
+
+ if (uLevel == 1 || uLevel == 2) {
+ PACKS(desc,"B",""); /* alignment */
+ PACKI(desc,"W",5); /* priority */
+ PACKI(desc,"W",0); /* start time */
+ PACKI(desc,"W",0); /* until time */
+ PACKS(desc,"z",""); /* pSepFile */
+ PACKS(desc,"z","lpd"); /* pPrProc */
+ PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
+ PACKS(desc,"z",""); /* pParms */
+ if (snum < 0) {
+ PACKS(desc,"z","UNKNOWN PRINTER");
+ PACKI(desc,"W",LPSTAT_ERROR);
+ }
+ else if (!status || !status->message[0]) {
+ PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
+ PACKI(desc,"W",LPSTAT_OK); /* status */
+ } else {
+ PACKS(desc,"z",status->message);
+ PACKI(desc,"W",printq_status(status->status)); /* status */
+ }
+ PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
+ }
+
+ if (uLevel == 3 || uLevel == 4) {
+ char *drivername = NULL;
+
+ PACKI(desc,"W",5); /* uPriority */
+ PACKI(desc,"W",0); /* uStarttime */
+ PACKI(desc,"W",0); /* uUntiltime */
+ PACKI(desc,"W",5); /* pad1 */
+ PACKS(desc,"z",""); /* pszSepFile */
+ PACKS(desc,"z","WinPrint"); /* pszPrProc */
+ PACKS(desc,"z",NULL); /* pszParms */
+ PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
+ /* "don't ask" that it's done this way to fix corrupted
+ Win9X/ME printer comments. */
+ if (!status) {
+ PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
+ } else {
+ PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
+ }
+ PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
+ PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
+ get_driver_name(snum,&drivername);
+ if (!drivername) {
+ return;
+ }
+ PACKS(desc,"z",drivername); /* pszDriverName */
+ PackDriverData(desc); /* pDriverData */
+ }
+
+ if (uLevel == 2 || uLevel == 4) {
+ int i;
+ for (i=0;i<count;i++)
+ fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
+ }
+
+ if (uLevel==52)
+ fill_printq_info_52( conn, snum, desc, count );
+}
+
+/* This function returns the number of files for a given driver */
+static int get_printerdrivernumber(int snum)
+{
+ int result = 0;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+ ZERO_STRUCT(driver);
+
+ if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
+ DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
+ lp_servicename(snum)));
+ goto done;
+ }
+
+ if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
+ "Windows 4.0", 0)) )
+ {
+ DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
+ printer->info_2->drivername));
+ goto done;
+ }
+
+ /* count the number of files */
+ while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
+ result++;
+ \
+ done:
+ if ( printer )
+ free_a_printer( &printer, 2 );
+
+ if ( driver.info_3 )
+ free_a_printer_driver( driver, 3 );
+
+ return result;
+}
+
+static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ char *QueueName = p;
+ unsigned int uLevel;
+ int count=0;
+ int snum;
+ char *str3;
+ struct pack_desc desc;
+ print_queue_struct *queue=NULL;
+ print_status_struct status;
+ char* tmpdata=NULL;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+ memset((char *)&status,'\0',sizeof(status));
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ p = skip_string(param,tpscnt,p);
+ if (!p) {
+ return False;
+ }
+ uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+ str3 = get_safe_str_ptr(param,tpscnt,p,4);
+ /* str3 may be null here and is checked in check_printq_info(). */
+
+ /* remove any trailing username */
+ if ((p = strchr_m(QueueName,'%')))
+ *p = 0;
+
+ DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
+
+ /* check it's a supported varient */
+ if (!prefix_ok(str1,"zWrLh"))
+ return False;
+ if (!check_printq_info(&desc,uLevel,str2,str3)) {
+ /*
+ * Patch from Scott Moomaw <scott@bridgewater.edu>
+ * to return the 'invalid info level' error if an
+ * unknown level was requested.
+ */
+ *rdata_len = 0;
+ *rparam_len = 6;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVALS(*rparam,0,ERRunknownlevel);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,0);
+ return(True);
+ }
+
+ snum = find_service(QueueName);
+ if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
+ return False;
+
+ if (uLevel==52) {
+ count = get_printerdrivernumber(snum);
+ DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
+ } else {
+ count = print_queue_status(snum, &queue,&status);
+ }
+
+ if (mdrcnt > 0) {
+ *rdata = smb_realloc_limit(*rdata,mdrcnt);
+ if (!*rdata) {
+ SAFE_FREE(queue);
+ return False;
+ }
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ } else {
+ /*
+ * Don't return data but need to get correct length
+ * init_package will return wrong size if buflen=0
+ */
+ desc.buflen = getlen(desc.format);
+ desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
+ }
+
+ if (init_package(&desc,1,count)) {
+ desc.subcount = count;
+ fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
+ }
+
+ *rdata_len = desc.usedlen;
+
+ /*
+ * We must set the return code to ERRbuftoosmall
+ * in order to support lanman style printing with Win NT/2k
+ * clients --jerry
+ */
+ if (!mdrcnt && lp_disable_spoolss())
+ desc.errcode = ERRbuftoosmall;
+
+ *rdata_len = desc.usedlen;
+ *rparam_len = 6;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ SAFE_FREE(queue);
+ SAFE_FREE(tmpdata);
+ return False;
+ }
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,desc.neededlen);
+
+ DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
+
+ SAFE_FREE(queue);
+ SAFE_FREE(tmpdata);
+
+ return(True);
+}
+
+/****************************************************************************
+ View list of all print jobs on all queues.
+****************************************************************************/
+
+static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt, int mprcnt,
+ char **rdata, char** rparam,
+ int *rdata_len, int *rparam_len)
+{
+ char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
+ char *output_format1 = skip_string(param,tpscnt,param_format);
+ char *p = skip_string(param,tpscnt,output_format1);
+ unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+ char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
+ int services = lp_numservices();
+ int i, n;
+ struct pack_desc desc;
+ print_queue_struct **queue = NULL;
+ print_status_struct *status = NULL;
+ int *subcntarr = NULL;
+ int queuecnt = 0, subcnt = 0, succnt = 0;
+
+ if (!param_format || !output_format1 || !p) {
+ return False;
+ }
+
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
+
+ if (!prefix_ok(param_format,"WrLeh")) {
+ return False;
+ }
+ if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
+ /*
+ * Patch from Scott Moomaw <scott@bridgewater.edu>
+ * to return the 'invalid info level' error if an
+ * unknown level was requested.
+ */
+ *rdata_len = 0;
+ *rparam_len = 6;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVALS(*rparam,0,ERRunknownlevel);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,0);
+ return(True);
+ }
+
+ for (i = 0; i < services; i++) {
+ if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
+ queuecnt++;
+ }
+ }
+
+ if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
+ DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
+ goto err;
+ }
+ memset(queue,0,queuecnt*sizeof(print_queue_struct*));
+ if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
+ DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
+ goto err;
+ }
+ memset(status,0,queuecnt*sizeof(print_status_struct));
+ if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
+ DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
+ goto err;
+ }
+
+ subcnt = 0;
+ n = 0;
+ for (i = 0; i < services; i++) {
+ if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
+ subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
+ subcnt += subcntarr[n];
+ n++;
+ }
+ }
+
+ if (mdrcnt > 0) {
+ *rdata = smb_realloc_limit(*rdata,mdrcnt);
+ if (!*rdata) {
+ goto err;
+ }
+ }
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+
+ if (init_package(&desc,queuecnt,subcnt)) {
+ n = 0;
+ succnt = 0;
+ for (i = 0; i < services; i++) {
+ if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
+ fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
+ n++;
+ if (desc.errcode == NERR_Success) {
+ succnt = n;
+ }
+ }
+ }
+ }
+
+ SAFE_FREE(subcntarr);
+
+ *rdata_len = desc.usedlen;
+ *rparam_len = 8;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ goto err;
+ }
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,succnt);
+ SSVAL(*rparam,6,queuecnt);
+
+ for (i = 0; i < queuecnt; i++) {
+ if (queue) {
+ SAFE_FREE(queue[i]);
+ }
+ }
+
+ SAFE_FREE(queue);
+ SAFE_FREE(status);
+
+ return True;
+
+ err:
+
+ SAFE_FREE(subcntarr);
+ for (i = 0; i < queuecnt; i++) {
+ if (queue) {
+ SAFE_FREE(queue[i]);
+ }
+ }
+ SAFE_FREE(queue);
+ SAFE_FREE(status);
+
+ return False;
+}
+
+/****************************************************************************
+ Get info level for a server list query.
+****************************************************************************/
+
+static bool check_server_info(int uLevel, char* id)
+{
+ switch( uLevel ) {
+ case 0:
+ if (strcmp(id,"B16") != 0) {
+ return False;
+ }
+ break;
+ case 1:
+ if (strcmp(id,"B16BBDz") != 0) {
+ return False;
+ }
+ break;
+ default:
+ return False;
+ }
+ return True;
+}
+
+struct srv_info_struct {
+ fstring name;
+ uint32 type;
+ fstring comment;
+ fstring domain;
+ bool server_added;
+};
+
+/*******************************************************************
+ Get server info lists from the files saved by nmbd. Return the
+ number of entries.
+******************************************************************/
+
+static int get_server_info(uint32 servertype,
+ struct srv_info_struct **servers,
+ const char *domain)
+{
+ int count=0;
+ int alloced=0;
+ char **lines;
+ bool local_list_only;
+ int i;
+
+ lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
+ if (!lines) {
+ DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
+ return 0;
+ }
+
+ /* request for everything is code for request all servers */
+ if (servertype == SV_TYPE_ALL) {
+ servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
+ }
+
+ local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
+
+ DEBUG(4,("Servertype search: %8x\n",servertype));
+
+ for (i=0;lines[i];i++) {
+ fstring stype;
+ struct srv_info_struct *s;
+ const char *ptr = lines[i];
+ bool ok = True;
+ TALLOC_CTX *frame = NULL;
+ char *p;
+
+ if (!*ptr) {
+ continue;
+ }
+
+ if (count == alloced) {
+ alloced += 10;
+ *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
+ if (!*servers) {
+ DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
+ file_lines_free(lines);
+ return 0;
+ }
+ memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
+ }
+ s = &(*servers)[count];
+
+ frame = talloc_stackframe();
+ s->name[0] = '\0';
+ if (!next_token_talloc(frame,&ptr,&p, NULL)) {
+ TALLOC_FREE(frame);
+ continue;
+ }
+ fstrcpy(s->name, p);
+
+ stype[0] = '\0';
+ if (!next_token_talloc(frame,&ptr, &p, NULL)) {
+ TALLOC_FREE(frame);
+ continue;
+ }
+ fstrcpy(stype, p);
+
+ s->comment[0] = '\0';
+ if (!next_token_talloc(frame,&ptr, &p, NULL)) {
+ TALLOC_FREE(frame);
+ continue;
+ }
+ fstrcpy(s->comment, p);
+
+ s->domain[0] = '\0';
+ if (!next_token_talloc(frame,&ptr,&p, NULL)) {
+ /* this allows us to cope with an old nmbd */
+ fstrcpy(s->domain,lp_workgroup());
+ } else {
+ fstrcpy(s->domain, p);
+ }
+ TALLOC_FREE(frame);
+
+ if (sscanf(stype,"%X",&s->type) != 1) {
+ DEBUG(4,("r:host file "));
+ ok = False;
+ }
+
+ /* Filter the servers/domains we return based on what was asked for. */
+
+ /* Check to see if we are being asked for a local list only. */
+ if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
+ DEBUG(4,("r: local list only"));
+ ok = False;
+ }
+
+ /* doesn't match up: don't want it */
+ if (!(servertype & s->type)) {
+ DEBUG(4,("r:serv type "));
+ ok = False;
+ }
+
+ if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
+ (s->type & SV_TYPE_DOMAIN_ENUM)) {
+ DEBUG(4,("s: dom mismatch "));
+ ok = False;
+ }
+
+ if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
+ ok = False;
+ }
+
+ /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
+ s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ if (ok) {
+ DEBUG(4,("**SV** %20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+ s->server_added = True;
+ count++;
+ } else {
+ DEBUG(4,("%20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+ }
+ }
+
+ file_lines_free(lines);
+ return count;
+}
+
+/*******************************************************************
+ Fill in a server info structure.
+******************************************************************/
+
+static int fill_srv_info(struct srv_info_struct *service,
+ int uLevel, char **buf, int *buflen,
+ char **stringbuf, int *stringspace, char *baseaddr)
+{
+ int struct_len;
+ char* p;
+ char* p2;
+ int l2;
+ int len;
+
+ switch (uLevel) {
+ case 0:
+ struct_len = 16;
+ break;
+ case 1:
+ struct_len = 26;
+ break;
+ default:
+ return -1;
+ }
+
+ if (!buf) {
+ len = 0;
+ switch (uLevel) {
+ case 1:
+ len = strlen(service->comment)+1;
+ break;
+ }
+
+ *buflen = struct_len;
+ *stringspace = len;
+ return struct_len + len;
+ }
+
+ len = struct_len;
+ p = *buf;
+ if (*buflen < struct_len) {
+ return -1;
+ }
+ if (stringbuf) {
+ p2 = *stringbuf;
+ l2 = *stringspace;
+ } else {
+ p2 = p + struct_len;
+ l2 = *buflen - struct_len;
+ }
+ if (!baseaddr) {
+ baseaddr = p;
+ }
+
+ switch (uLevel) {
+ case 0:
+ push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
+ break;
+
+ case 1:
+ push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
+ SIVAL(p,18,service->type);
+ SIVAL(p,22,PTR_DIFF(p2,baseaddr));
+ len += CopyAndAdvance(&p2,service->comment,&l2);
+ break;
+ }
+
+ if (stringbuf) {
+ *buf = p + struct_len;
+ *buflen -= struct_len;
+ *stringbuf = p2;
+ *stringspace = l2;
+ } else {
+ *buf = p2;
+ *buflen -= len;
+ }
+ return len;
+}
+
+
+static bool srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
+{
+ return(strcmp(s1->name,s2->name));
+}
+
+/****************************************************************************
+ View list of servers available (or possibly domains). The info is
+ extracted from lists saved by nmbd on the local host.
+****************************************************************************/
+
+static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt, int mprcnt, char **rdata,
+ char **rparam, int *rdata_len, int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
+ int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
+ uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
+ char *p2;
+ int data_len, fixed_len, string_len;
+ int f_len = 0, s_len = 0;
+ struct srv_info_struct *servers=NULL;
+ int counted=0,total=0;
+ int i,missed;
+ fstring domain;
+ bool domain_request;
+ bool local_request;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+
+ /* 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 its own) they
+ want all the locally seen servers. However this bit can be
+ set on its own so set the requested servers to be
+ ALL - DOMAIN_ENUM. */
+
+ if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
+ servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
+ }
+
+ domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
+ local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
+
+ p += 8;
+
+ if (!prefix_ok(str1,"WrLehD")) {
+ return False;
+ }
+ if (!check_server_info(uLevel,str2)) {
+ return False;
+ }
+
+ DEBUG(4, ("server request level: %s %8x ", str2, servertype));
+ DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
+ DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
+
+ if (strcmp(str1, "WrLehDz") == 0) {
+ if (skip_string(param,tpscnt,p) == NULL) {
+ return False;
+ }
+ pull_ascii_fstring(domain, p);
+ } else {
+ fstrcpy(domain, lp_workgroup());
+ }
+
+ if (lp_browse_list()) {
+ total = get_server_info(servertype,&servers,domain);
+ }
+
+ data_len = fixed_len = string_len = 0;
+ missed = 0;
+
+ if (total > 0) {
+ qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
+ }
+
+ {
+ char *lastname=NULL;
+
+ for (i=0;i<total;i++) {
+ struct srv_info_struct *s = &servers[i];
+
+ if (lastname && strequal(lastname,s->name)) {
+ continue;
+ }
+ lastname = s->name;
+ data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
+ DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+
+ if (data_len <= buf_len) {
+ counted++;
+ fixed_len += f_len;
+ string_len += s_len;
+ } else {
+ missed++;
+ }
+ }
+ }
+
+ *rdata_len = fixed_len + string_len;
+ *rdata = smb_realloc_limit(*rdata,*rdata_len);
+ if (!*rdata) {
+ return False;
+ }
+
+ p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
+ p = *rdata;
+ f_len = fixed_len;
+ s_len = string_len;
+
+ {
+ char *lastname=NULL;
+ int count2 = counted;
+
+ for (i = 0; i < total && count2;i++) {
+ struct srv_info_struct *s = &servers[i];
+
+ if (lastname && strequal(lastname,s->name)) {
+ continue;
+ }
+ lastname = s->name;
+ fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
+ DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+ count2--;
+ }
+ }
+
+ *rparam_len = 8;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,counted);
+ SSVAL(*rparam,6,counted+missed);
+
+ SAFE_FREE(servers);
+
+ DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
+ domain,uLevel,counted,counted+missed));
+
+ return True;
+}
+
+/****************************************************************************
+ command 0x34 - suspected of being a "Lookup Names" stub api
+ ****************************************************************************/
+
+static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt, int mprcnt, char **rdata,
+ char **rparam, int *rdata_len, int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+ int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
+ int counted=0;
+ int missed=0;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+
+ DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
+ str1, str2, p, uLevel, buf_len));
+
+ if (!prefix_ok(str1,"zWrLeh")) {
+ return False;
+ }
+
+ *rdata_len = 0;
+
+ *rparam_len = 8;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+
+ SSVAL(*rparam,0,0x08AC); /* informational warning message */
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,counted);
+ SSVAL(*rparam,6,counted+missed);
+
+ return True;
+}
+
+/****************************************************************************
+ get info about a share
+ ****************************************************************************/
+
+static bool check_share_info(int uLevel, char* id)
+{
+ switch( uLevel ) {
+ case 0:
+ if (strcmp(id,"B13") != 0) {
+ return False;
+ }
+ break;
+ case 1:
+ if (strcmp(id,"B13BWz") != 0) {
+ return False;
+ }
+ break;
+ case 2:
+ if (strcmp(id,"B13BWzWWWzB9B") != 0) {
+ return False;
+ }
+ break;
+ case 91:
+ if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
+ return False;
+ }
+ break;
+ default:
+ return False;
+ }
+ return True;
+}
+
+static int fill_share_info(connection_struct *conn, int snum, int uLevel,
+ char** buf, int* buflen,
+ char** stringbuf, int* stringspace, char* baseaddr)
+{
+ int struct_len;
+ char* p;
+ char* p2;
+ int l2;
+ int len;
+
+ switch( uLevel ) {
+ case 0:
+ struct_len = 13;
+ break;
+ case 1:
+ struct_len = 20;
+ break;
+ case 2:
+ struct_len = 40;
+ break;
+ case 91:
+ struct_len = 68;
+ break;
+ default:
+ return -1;
+ }
+
+
+ if (!buf) {
+ len = 0;
+
+ if (uLevel > 0) {
+ len += StrlenExpanded(conn,snum,lp_comment(snum));
+ }
+ if (uLevel > 1) {
+ len += strlen(lp_pathname(snum)) + 1;
+ }
+ if (buflen) {
+ *buflen = struct_len;
+ }
+ if (stringspace) {
+ *stringspace = len;
+ }
+ return struct_len + len;
+ }
+
+ len = struct_len;
+ p = *buf;
+ if ((*buflen) < struct_len) {
+ return -1;
+ }
+
+ if (stringbuf) {
+ p2 = *stringbuf;
+ l2 = *stringspace;
+ } else {
+ p2 = p + struct_len;
+ l2 = (*buflen) - struct_len;
+ }
+
+ if (!baseaddr) {
+ baseaddr = p;
+ }
+
+ push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
+
+ if (uLevel > 0) {
+ int type;
+
+ SCVAL(p,13,0);
+ type = STYPE_DISKTREE;
+ if (lp_print_ok(snum)) {
+ type = STYPE_PRINTQ;
+ }
+ if (strequal("IPC",lp_fstype(snum))) {
+ type = STYPE_IPC;
+ }
+ SSVAL(p,14,type); /* device type */
+ SIVAL(p,16,PTR_DIFF(p2,baseaddr));
+ len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
+ }
+
+ if (uLevel > 1) {
+ SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
+ SSVALS(p,22,-1); /* max uses */
+ SSVAL(p,24,1); /* current uses */
+ SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
+ len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
+ memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
+ }
+
+ if (uLevel > 2) {
+ memset(p+40,0,SHPWLEN+2);
+ SSVAL(p,50,0);
+ SIVAL(p,52,0);
+ SSVAL(p,56,0);
+ SSVAL(p,58,0);
+ SIVAL(p,60,0);
+ SSVAL(p,64,0);
+ SSVAL(p,66,0);
+ }
+
+ if (stringbuf) {
+ (*buf) = p + struct_len;
+ (*buflen) -= struct_len;
+ (*stringbuf) = p2;
+ (*stringspace) = l2;
+ } else {
+ (*buf) = p2;
+ (*buflen) -= len;
+ }
+
+ return len;
+}
+
+static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *netname = skip_string(param,tpscnt,str2);
+ char *p = skip_string(param,tpscnt,netname);
+ int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+ int snum;
+
+ if (!str1 || !str2 || !netname || !p) {
+ return False;
+ }
+
+ snum = find_service(netname);
+ if (snum < 0) {
+ return False;
+ }
+
+ /* check it's a supported varient */
+ if (!prefix_ok(str1,"zWrLh")) {
+ return False;
+ }
+ if (!check_share_info(uLevel,str2)) {
+ return False;
+ }
+
+ *rdata = smb_realloc_limit(*rdata,mdrcnt);
+ if (!*rdata) {
+ return False;
+ }
+ p = *rdata;
+ *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
+ if (*rdata_len < 0) {
+ return False;
+ }
+
+ *rparam_len = 6;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
+ SSVAL(*rparam,4,*rdata_len);
+
+ return True;
+}
+
+/****************************************************************************
+ View the list of available shares.
+
+ This function is the server side of the NetShareEnum() RAP call.
+ It fills the return buffer with share names and share comments.
+ Note that the return buffer normally (in all known cases) allows only
+ twelve byte strings for share names (plus one for a nul terminator).
+ Share names longer than 12 bytes must be skipped.
+ ****************************************************************************/
+
+static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,
+ int mprcnt,
+ char **rdata,
+ char **rparam,
+ int *rdata_len,
+ int *rparam_len )
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+ int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
+ char *p2;
+ int count = 0;
+ int total=0,counted=0;
+ bool missed = False;
+ int i;
+ int data_len, fixed_len, string_len;
+ int f_len = 0, s_len = 0;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+
+ if (!prefix_ok(str1,"WrLeh")) {
+ return False;
+ }
+ if (!check_share_info(uLevel,str2)) {
+ return False;
+ }
+
+ /* Ensure all the usershares are loaded. */
+ become_root();
+ load_registry_shares();
+ count = load_usershare_shares();
+ unbecome_root();
+
+ data_len = fixed_len = string_len = 0;
+ for (i=0;i<count;i++) {
+ fstring servicename_dos;
+ if (!(lp_browseable(i) && lp_snum_ok(i))) {
+ continue;
+ }
+ push_ascii_fstring(servicename_dos, lp_servicename(i));
+ /* Maximum name length = 13. */
+ if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
+ total++;
+ data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
+ if (data_len <= buf_len) {
+ counted++;
+ fixed_len += f_len;
+ string_len += s_len;
+ } else {
+ missed = True;
+ }
+ }
+ }
+
+ *rdata_len = fixed_len + string_len;
+ *rdata = smb_realloc_limit(*rdata,*rdata_len);
+ if (!*rdata) {
+ return False;
+ }
+
+ p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
+ p = *rdata;
+ f_len = fixed_len;
+ s_len = string_len;
+
+ for( i = 0; i < count; i++ ) {
+ fstring servicename_dos;
+ if (!(lp_browseable(i) && lp_snum_ok(i))) {
+ continue;
+ }
+
+ push_ascii_fstring(servicename_dos, lp_servicename(i));
+ if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
+ if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
+ break;
+ }
+ }
+ }
+
+ *rparam_len = 8;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,counted);
+ SSVAL(*rparam,6,total);
+
+ DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
+ counted,total,uLevel,
+ buf_len,*rdata_len,mdrcnt));
+
+ return True;
+}
+
+/****************************************************************************
+ Add a share
+ ****************************************************************************/
+
+static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+ fstring sharename;
+ fstring comment;
+ char *pathname = NULL;
+ char *command, *cmdname;
+ unsigned int offset;
+ int snum;
+ int res = ERRunsup;
+ size_t converted_size;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+
+ /* check it's a supported varient */
+ if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
+ return False;
+ }
+ if (!check_share_info(uLevel,str2)) {
+ return False;
+ }
+ if (uLevel != 2) {
+ return False;
+ }
+
+ /* Do we have a string ? */
+ if (skip_string(data,mdrcnt,data) == NULL) {
+ return False;
+ }
+ pull_ascii_fstring(sharename,data);
+ snum = find_service(sharename);
+ if (snum >= 0) { /* already exists */
+ res = ERRfilexists;
+ goto error_exit;
+ }
+
+ if (mdrcnt < 28) {
+ return False;
+ }
+
+ /* only support disk share adds */
+ if (SVAL(data,14)!=STYPE_DISKTREE) {
+ return False;
+ }
+
+ offset = IVAL(data, 16);
+ if (offset >= mdrcnt) {
+ res = ERRinvalidparam;
+ goto error_exit;
+ }
+
+ /* Do we have a string ? */
+ if (skip_string(data,mdrcnt,data+offset) == NULL) {
+ return False;
+ }
+ pull_ascii_fstring(comment, offset? (data+offset) : "");
+
+ offset = IVAL(data, 26);
+
+ if (offset >= mdrcnt) {
+ res = ERRinvalidparam;
+ goto error_exit;
+ }
+
+ /* Do we have a string ? */
+ if (skip_string(data,mdrcnt,data+offset) == NULL) {
+ return False;
+ }
+
+ if (!pull_ascii_talloc(talloc_tos(), &pathname,
+ offset ? (data+offset) : "", &converted_size))
+ {
+ DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
+ strerror(errno)));
+ }
+
+ if (!pathname) {
+ return false;
+ }
+
+ string_replace(sharename, '"', ' ');
+ string_replace(pathname, '"', ' ');
+ string_replace(comment, '"', ' ');
+
+ cmdname = lp_add_share_cmd();
+
+ if (!cmdname || *cmdname == '\0') {
+ return False;
+ }
+
+ if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
+ lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
+ pathname, comment) == -1) {
+ return false;
+ }
+
+ DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
+
+ if ((res = smbrun(command, NULL)) != 0) {
+ DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
+ command, res ));
+ SAFE_FREE(command);
+ res = ERRnoaccess;
+ goto error_exit;
+ } else {
+ SAFE_FREE(command);
+ message_send_all(smbd_messaging_context(),
+ MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
+ }
+
+ *rparam_len = 6;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
+ SSVAL(*rparam,4,*rdata_len);
+ *rdata_len = 0;
+
+ return True;
+
+ error_exit:
+
+ *rparam_len = 4;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ *rdata_len = 0;
+ SSVAL(*rparam,0,res);
+ SSVAL(*rparam,2,0);
+ return True;
+}
+
+/****************************************************************************
+ view list of groups available
+ ****************************************************************************/
+
+static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ int i;
+ int errflags=0;
+ int resume_context, cli_buf_size;
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+
+ struct pdb_search *search;
+ struct samr_displayentry *entries;
+
+ int num_entries;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+
+ if (strcmp(str1,"WrLeh") != 0) {
+ return False;
+ }
+
+ /* parameters
+ * W-> resume context (number of users to skip)
+ * r -> return parameter pointer to receive buffer
+ * L -> length of receive buffer
+ * e -> return parameter number of entries
+ * h -> return parameter total number of users
+ */
+
+ if (strcmp("B21",str2) != 0) {
+ return False;
+ }
+
+ /* get list of domain groups SID_DOMAIN_GRP=2 */
+ become_root();
+ search = pdb_search_groups();
+ unbecome_root();
+
+ if (search == NULL) {
+ DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
+ return False;
+ }
+
+ resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
+ cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
+ DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
+ "%d\n", resume_context, cli_buf_size));
+
+ become_root();
+ num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
+ &entries);
+ unbecome_root();
+
+ *rdata_len = cli_buf_size;
+ *rdata = smb_realloc_limit(*rdata,*rdata_len);
+ if (!*rdata) {
+ return False;
+ }
+
+ p = *rdata;
+
+ for(i=0; i<num_entries; i++) {
+ fstring name;
+ fstrcpy(name, entries[i].account_name);
+ if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
+ /* truncate the name at 21 chars. */
+ memcpy(p, name, 21);
+ DEBUG(10,("adding entry %d group %s\n", i, p));
+ p += 21;
+ p += 5; /* Both NT4 and W2k3SP1 do padding here.
+ No idea why... */
+ } else {
+ /* set overflow error */
+ DEBUG(3,("overflow on entry %d group %s\n", i, name));
+ errflags=234;
+ break;
+ }
+ }
+
+ pdb_search_destroy(search);
+
+ *rdata_len = PTR_DIFF(p,*rdata);
+
+ *rparam_len = 8;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVAL(*rparam, 0, errflags);
+ SSVAL(*rparam, 2, 0); /* converter word */
+ SSVAL(*rparam, 4, i); /* is this right?? */
+ SSVAL(*rparam, 6, resume_context+num_entries); /* is this right?? */
+
+ return(True);
+}
+
+/*******************************************************************
+ Get groups that a user is a member of.
+******************************************************************/
+
+static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *UserName = skip_string(param,tpscnt,str2);
+ char *p = skip_string(param,tpscnt,UserName);
+ int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+ const char *level_string;
+ int count=0;
+ struct samu *sampw = NULL;
+ bool ret = False;
+ DOM_SID *sids;
+ gid_t *gids;
+ size_t num_groups;
+ size_t i;
+ NTSTATUS result;
+ DOM_SID user_sid;
+ enum lsa_SidType type;
+ char *endp = NULL;
+ TALLOC_CTX *mem_ctx;
+
+ if (!str1 || !str2 || !UserName || !p) {
+ return False;
+ }
+
+ *rparam_len = 8;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+
+ /* check it's a supported varient */
+
+ if ( strcmp(str1,"zWrLeh") != 0 )
+ return False;
+
+ switch( uLevel ) {
+ case 0:
+ level_string = "B21";
+ break;
+ default:
+ return False;
+ }
+
+ if (strcmp(level_string,str2) != 0)
+ return False;
+
+ *rdata_len = mdrcnt + 1024;
+ *rdata = smb_realloc_limit(*rdata,*rdata_len);
+ if (!*rdata) {
+ return False;
+ }
+
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ p = *rdata;
+ endp = *rdata + *rdata_len;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return False;
+ }
+
+ if ( !(sampw = samu_new(mem_ctx)) ) {
+ DEBUG(0, ("samu_new() failed!\n"));
+ TALLOC_FREE(mem_ctx);
+ return False;
+ }
+
+ /* Lookup the user information; This should only be one of
+ our accounts (not remote domains) */
+
+ become_root(); /* ROOT BLOCK */
+
+ if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
+ NULL, NULL, &user_sid, &type)) {
+ DEBUG(10, ("lookup_name(%s) failed\n", UserName));
+ goto done;
+ }
+
+ if (type != SID_NAME_USER) {
+ DEBUG(10, ("%s is a %s, not a user\n", UserName,
+ sid_type_lookup(type)));
+ goto done;
+ }
+
+ if ( !pdb_getsampwsid(sampw, &user_sid) ) {
+ DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
+ sid_string_dbg(&user_sid), UserName));
+ goto done;
+ }
+
+ gids = NULL;
+ sids = NULL;
+ num_groups = 0;
+
+ result = pdb_enum_group_memberships(mem_ctx, sampw,
+ &sids, &gids, &num_groups);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
+ UserName));
+ goto done;
+ }
+
+ for (i=0; i<num_groups; i++) {
+ const char *grp_name;
+
+ if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
+ strlcpy(p, grp_name, PTR_DIFF(endp,p));
+ p += 21;
+ count++;
+ }
+ }
+
+ *rdata_len = PTR_DIFF(p,*rdata);
+
+ SSVAL(*rparam,4,count); /* is this right?? */
+ SSVAL(*rparam,6,count); /* is this right?? */
+
+ ret = True;
+
+done:
+ unbecome_root(); /* END ROOT BLOCK */
+
+ TALLOC_FREE(mem_ctx);
+
+ return ret;
+}
+
+/*******************************************************************
+ Get all users.
+******************************************************************/
+
+static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ int count_sent=0;
+ int num_users=0;
+ int errflags=0;
+ int i, resume_context, cli_buf_size;
+ struct pdb_search *search;
+ struct samr_displayentry *users;
+
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ char *endp = NULL;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+
+ if (strcmp(str1,"WrLeh") != 0)
+ return False;
+ /* parameters
+ * W-> resume context (number of users to skip)
+ * r -> return parameter pointer to receive buffer
+ * L -> length of receive buffer
+ * e -> return parameter number of entries
+ * h -> return parameter total number of users
+ */
+
+ resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
+ cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
+ DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
+ resume_context, cli_buf_size));
+
+ *rparam_len = 8;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+
+ /* check it's a supported varient */
+ if (strcmp("B21",str2) != 0)
+ return False;
+
+ *rdata_len = cli_buf_size;
+ *rdata = smb_realloc_limit(*rdata,*rdata_len);
+ if (!*rdata) {
+ return False;
+ }
+
+ p = *rdata;
+ endp = *rdata + *rdata_len;
+
+ become_root();
+ search = pdb_search_users(ACB_NORMAL);
+ unbecome_root();
+ if (search == NULL) {
+ DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
+ return False;
+ }
+
+ become_root();
+ num_users = pdb_search_entries(search, resume_context, 0xffffffff,
+ &users);
+ unbecome_root();
+
+ errflags=NERR_Success;
+
+ for (i=0; i<num_users; i++) {
+ const char *name = users[i].account_name;
+
+ if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
+ strlcpy(p,name,PTR_DIFF(endp,p));
+ DEBUG(10,("api_RNetUserEnum:adding entry %d username "
+ "%s\n",count_sent,p));
+ p += 21;
+ count_sent++;
+ } else {
+ /* set overflow error */
+ DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
+ "username %s\n",count_sent,name));
+ errflags=234;
+ break;
+ }
+ }
+
+ pdb_search_destroy(search);
+
+ *rdata_len = PTR_DIFF(p,*rdata);
+
+ SSVAL(*rparam,0,errflags);
+ SSVAL(*rparam,2,0); /* converter word */
+ SSVAL(*rparam,4,count_sent); /* is this right?? */
+ SSVAL(*rparam,6,num_users); /* is this right?? */
+
+ return True;
+}
+
+/****************************************************************************
+ Get the time of day info.
+****************************************************************************/
+
+static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ struct tm *t;
+ time_t unixdate = time(NULL);
+ char *p;
+
+ *rparam_len = 4;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+
+ *rdata_len = 21;
+ *rdata = smb_realloc_limit(*rdata,*rdata_len);
+ if (!*rdata) {
+ return False;
+ }
+
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ p = *rdata;
+
+ srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
+ by NT in a "net time" operation,
+ it seems to ignore the one below */
+
+ /* the client expects to get localtime, not GMT, in this bit
+ (I think, this needs testing) */
+ t = localtime(&unixdate);
+ if (!t) {
+ return False;
+ }
+
+ SIVAL(p,4,0); /* msecs ? */
+ SCVAL(p,8,t->tm_hour);
+ SCVAL(p,9,t->tm_min);
+ SCVAL(p,10,t->tm_sec);
+ SCVAL(p,11,0); /* hundredths of seconds */
+ SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
+ SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
+ SCVAL(p,16,t->tm_mday);
+ SCVAL(p,17,t->tm_mon + 1);
+ SSVAL(p,18,1900+t->tm_year);
+ SCVAL(p,20,t->tm_wday);
+
+ return True;
+}
+
+/****************************************************************************
+ Set the user password.
+*****************************************************************************/
+
+static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *np = get_safe_str_ptr(param,tpscnt,param,2);
+ char *p = NULL;
+ fstring user;
+ fstring pass1,pass2;
+
+ /* Skip 2 strings. */
+ p = skip_string(param,tpscnt,np);
+ p = skip_string(param,tpscnt,p);
+
+ if (!np || !p) {
+ return False;
+ }
+
+ /* Do we have a string ? */
+ if (skip_string(param,tpscnt,p) == NULL) {
+ return False;
+ }
+ pull_ascii_fstring(user,p);
+
+ p = skip_string(param,tpscnt,p);
+ if (!p) {
+ return False;
+ }
+
+ memset(pass1,'\0',sizeof(pass1));
+ memset(pass2,'\0',sizeof(pass2));
+ /*
+ * We use 31 here not 32 as we're checking
+ * the last byte we want to access is safe.
+ */
+ if (!is_offset_safe(param,tpscnt,p,31)) {
+ return False;
+ }
+ memcpy(pass1,p,16);
+ memcpy(pass2,p+16,16);
+
+ *rparam_len = 4;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+
+ *rdata_len = 0;
+
+ SSVAL(*rparam,0,NERR_badpass);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ DEBUG(3,("Set password for <%s>\n",user));
+
+ /*
+ * Attempt to verify the old password against smbpasswd entries
+ * Win98 clients send old and new password in plaintext for this call.
+ */
+
+ {
+ auth_serversupplied_info *server_info = NULL;
+ DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
+
+ if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
+
+ become_root();
+ if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
+ SSVAL(*rparam,0,NERR_Success);
+ }
+ unbecome_root();
+
+ TALLOC_FREE(server_info);
+ }
+ data_blob_clear_free(&password);
+ }
+
+ /*
+ * If the plaintext change failed, attempt
+ * the old encrypted method. NT will generate this
+ * after trying the samr method. Note that this
+ * method is done as a last resort as this
+ * password change method loses the NT password hash
+ * and cannot change the UNIX password as no plaintext
+ * is received.
+ */
+
+ if(SVAL(*rparam,0) != NERR_Success) {
+ struct samu *hnd = NULL;
+
+ if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
+ become_root();
+ if (change_lanman_password(hnd,(uchar *)pass2)) {
+ SSVAL(*rparam,0,NERR_Success);
+ }
+ unbecome_root();
+ TALLOC_FREE(hnd);
+ }
+ }
+
+ memset((char *)pass1,'\0',sizeof(fstring));
+ memset((char *)pass2,'\0',sizeof(fstring));
+
+ return(True);
+}
+
+/****************************************************************************
+ Set the user password (SamOEM version - gets plaintext).
+****************************************************************************/
+
+static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ fstring user;
+ char *p = get_safe_str_ptr(param,tpscnt,param,2);
+ *rparam_len = 2;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+
+ if (!p) {
+ return False;
+ }
+ *rdata_len = 0;
+
+ SSVAL(*rparam,0,NERR_badpass);
+
+ /*
+ * Check the parameter definition is correct.
+ */
+
+ /* Do we have a string ? */
+ if (skip_string(param,tpscnt,p) == 0) {
+ return False;
+ }
+ if(!strequal(p, "zsT")) {
+ DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
+ return False;
+ }
+ p = skip_string(param, tpscnt, p);
+ if (!p) {
+ return False;
+ }
+
+ /* Do we have a string ? */
+ if (skip_string(param,tpscnt,p) == 0) {
+ return False;
+ }
+ if(!strequal(p, "B516B16")) {
+ DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
+ return False;
+ }
+ p = skip_string(param,tpscnt,p);
+ if (!p) {
+ return False;
+ }
+ /* Do we have a string ? */
+ if (skip_string(param,tpscnt,p) == 0) {
+ return False;
+ }
+ p += pull_ascii_fstring(user,p);
+
+ DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
+
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user);
+
+ if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
+ SSVAL(*rparam,0,NERR_Success);
+ }
+
+ return(True);
+}
+
+/****************************************************************************
+ delete a print job
+ Form: <W> <>
+ ****************************************************************************/
+
+static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ int function = get_safe_SVAL(param,tpscnt,param,0,0);
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ uint32 jobid;
+ int snum;
+ fstring sharename;
+ int errcode;
+ WERROR werr = WERR_OK;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+ /*
+ * We use 1 here not 2 as we're checking
+ * the last byte we want to access is safe.
+ */
+ if (!is_offset_safe(param,tpscnt,p,1)) {
+ return False;
+ }
+ if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
+ return False;
+
+ /* check it's a supported varient */
+ if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
+ return(False);
+
+ *rparam_len = 4;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ *rdata_len = 0;
+
+ if (!print_job_exists(sharename, jobid)) {
+ errcode = NERR_JobNotFound;
+ goto out;
+ }
+
+ snum = lp_servicenumber( sharename);
+ if (snum == -1) {
+ errcode = NERR_DestNotFound;
+ goto out;
+ }
+
+ errcode = NERR_notsupported;
+
+ switch (function) {
+ case 81: /* delete */
+ if (print_job_delete(conn->server_info, snum, jobid, &werr))
+ errcode = NERR_Success;
+ break;
+ case 82: /* pause */
+ if (print_job_pause(conn->server_info, snum, jobid, &werr))
+ errcode = NERR_Success;
+ break;
+ case 83: /* resume */
+ if (print_job_resume(conn->server_info, snum, jobid, &werr))
+ errcode = NERR_Success;
+ break;
+ }
+
+ if (!W_ERROR_IS_OK(werr))
+ errcode = W_ERROR_V(werr);
+
+ out:
+ SSVAL(*rparam,0,errcode);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ return(True);
+}
+
+/****************************************************************************
+ Purge a print queue - or pause or resume it.
+ ****************************************************************************/
+
+static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ int function = get_safe_SVAL(param,tpscnt,param,0,0);
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *QueueName = skip_string(param,tpscnt,str2);
+ int errcode = NERR_notsupported;
+ int snum;
+ WERROR werr = WERR_OK;
+
+ if (!str1 || !str2 || !QueueName) {
+ return False;
+ }
+
+ /* check it's a supported varient */
+ if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
+ return(False);
+
+ *rparam_len = 4;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ *rdata_len = 0;
+
+ if (skip_string(param,tpscnt,QueueName) == NULL) {
+ return False;
+ }
+ snum = print_queue_snum(QueueName);
+
+ if (snum == -1) {
+ errcode = NERR_JobNotFound;
+ goto out;
+ }
+
+ switch (function) {
+ case 74: /* Pause queue */
+ if (print_queue_pause(conn->server_info, snum, &werr)) {
+ errcode = NERR_Success;
+ }
+ break;
+ case 75: /* Resume queue */
+ if (print_queue_resume(conn->server_info, snum, &werr)) {
+ errcode = NERR_Success;
+ }
+ break;
+ case 103: /* Purge */
+ if (print_queue_purge(conn->server_info, snum, &werr)) {
+ errcode = NERR_Success;
+ }
+ break;
+ }
+
+ if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
+
+ out:
+ SSVAL(*rparam,0,errcode);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ return(True);
+}
+
+/****************************************************************************
+ set the property of a print job (undocumented?)
+ ? function = 0xb -> set name of print job
+ ? function = 0x6 -> move print job up/down
+ Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
+ or <WWsTP> <WB21BB16B10zWWzDDz>
+****************************************************************************/
+
+static int check_printjob_info(struct pack_desc* desc,
+ int uLevel, char* id)
+{
+ desc->subformat = NULL;
+ switch( uLevel ) {
+ case 0: desc->format = "W"; break;
+ case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
+ case 2: desc->format = "WWzWWDDzz"; break;
+ case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
+ case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
+ default:
+ DEBUG(0,("check_printjob_info: invalid level %d\n",
+ uLevel ));
+ return False;
+ }
+ if (id == NULL || strcmp(desc->format,id) != 0) {
+ DEBUG(0,("check_printjob_info: invalid format %s\n",
+ id ? id : "<NULL>" ));
+ return False;
+ }
+ return True;
+}
+
+static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ struct pack_desc desc;
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ uint32 jobid;
+ fstring sharename;
+ int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
+ int function = get_safe_SVAL(param,tpscnt,p,4,-1);
+ int place, errcode;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+ /*
+ * We use 1 here not 2 as we're checking
+ * the last byte we want to access is safe.
+ */
+ if (!is_offset_safe(param,tpscnt,p,1)) {
+ return False;
+ }
+ if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
+ return False;
+ *rparam_len = 4;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+
+ if (!share_defined(sharename)) {
+ DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
+ sharename));
+ return False;
+ }
+
+ *rdata_len = 0;
+
+ /* check it's a supported varient */
+ if ((strcmp(str1,"WWsTP")) ||
+ (!check_printjob_info(&desc,uLevel,str2)))
+ return(False);
+
+ if (!print_job_exists(sharename, jobid)) {
+ errcode=NERR_JobNotFound;
+ goto out;
+ }
+
+ errcode = NERR_notsupported;
+
+ switch (function) {
+ case 0x6:
+ /* change job place in the queue,
+ data gives the new place */
+ place = SVAL(data,0);
+ if (print_job_set_place(sharename, jobid, place)) {
+ errcode=NERR_Success;
+ }
+ break;
+
+ case 0xb:
+ /* change print job name, data gives the name */
+ if (print_job_set_name(sharename, jobid, data)) {
+ errcode=NERR_Success;
+ }
+ break;
+
+ default:
+ return False;
+ }
+
+ out:
+ SSVALS(*rparam,0,errcode);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ return(True);
+}
+
+
+/****************************************************************************
+ Get info about the server.
+****************************************************************************/
+
+static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+ char *p2;
+ int struct_len;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+
+ DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
+
+ /* check it's a supported varient */
+ if (!prefix_ok(str1,"WrLh")) {
+ return False;
+ }
+
+ switch( uLevel ) {
+ case 0:
+ if (strcmp(str2,"B16") != 0) {
+ return False;
+ }
+ struct_len = 16;
+ break;
+ case 1:
+ if (strcmp(str2,"B16BBDz") != 0) {
+ return False;
+ }
+ struct_len = 26;
+ break;
+ case 2:
+ if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
+ return False;
+ }
+ struct_len = 134;
+ break;
+ case 3:
+ if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
+ return False;
+ }
+ struct_len = 144;
+ break;
+ case 20:
+ if (strcmp(str2,"DN") != 0) {
+ return False;
+ }
+ struct_len = 6;
+ break;
+ case 50:
+ if (strcmp(str2,"B16BBDzWWzzz") != 0) {
+ return False;
+ }
+ struct_len = 42;
+ break;
+ default:
+ return False;
+ }
+
+ *rdata_len = mdrcnt;
+ *rdata = smb_realloc_limit(*rdata,*rdata_len);
+ if (!*rdata) {
+ return False;
+ }
+
+ p = *rdata;
+ p2 = p + struct_len;
+ if (uLevel != 20) {
+ srvstr_push(NULL, 0, p,global_myname(),16,
+ STR_ASCII|STR_UPPER|STR_TERMINATE);
+ }
+ p += 16;
+ if (uLevel > 0) {
+ struct srv_info_struct *servers=NULL;
+ int i,count;
+ char *comment = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+ uint32 servertype= lp_default_server_announce();
+
+ comment = talloc_strdup(ctx,lp_serverstring());
+ if (!comment) {
+ return false;
+ }
+
+ if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
+ for (i=0;i<count;i++) {
+ if (strequal(servers[i].name,global_myname())) {
+ servertype = servers[i].type;
+ TALLOC_FREE(comment);
+ comment = talloc_strdup(ctx,
+ servers[i].comment);
+ if (comment) {
+ return false;
+ }
+ }
+ }
+ }
+
+ SAFE_FREE(servers);
+
+ SCVAL(p,0,lp_major_announce_version());
+ SCVAL(p,1,lp_minor_announce_version());
+ SIVAL(p,2,servertype);
+
+ if (mdrcnt == struct_len) {
+ SIVAL(p,6,0);
+ } else {
+ SIVAL(p,6,PTR_DIFF(p2,*rdata));
+ comment = talloc_sub_advanced(
+ ctx,
+ lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name,
+ conn->connectpath,
+ conn->server_info->utok.gid,
+ conn->server_info->sanitized_username,
+ pdb_get_domain(conn->server_info->sam_account),
+ comment);
+ if (comment) {
+ return false;
+ }
+ if (mdrcnt - struct_len <= 0) {
+ return false;
+ }
+ push_ascii(p2,
+ comment,
+ MIN(mdrcnt - struct_len,
+ MAX_SERVER_STRING_LENGTH),
+ STR_TERMINATE);
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+ }
+ }
+
+ if (uLevel > 1) {
+ return False; /* not yet implemented */
+ }
+
+ *rdata_len = PTR_DIFF(p2,*rdata);
+
+ *rparam_len = 6;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
+ SSVAL(*rparam,4,*rdata_len);
+
+ return True;
+}
+
+/****************************************************************************
+ Get info about the server.
+****************************************************************************/
+
+static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ char *p2;
+ char *endp;
+ int level = get_safe_SVAL(param,tpscnt,p,0,-1);
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+
+ DEBUG(4,("NetWkstaGetInfo level %d\n",level));
+
+ *rparam_len = 6;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+
+ /* check it's a supported varient */
+ if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
+ return False;
+ }
+
+ *rdata_len = mdrcnt + 1024;
+ *rdata = smb_realloc_limit(*rdata,*rdata_len);
+ if (!*rdata) {
+ return False;
+ }
+
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ p = *rdata;
+ endp = *rdata + *rdata_len;
+
+ p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
+ if (!p2) {
+ return False;
+ }
+
+ SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
+ strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
+ strupper_m(p2);
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+ p += 4;
+
+ SIVAL(p,0,PTR_DIFF(p2,*rdata));
+ strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+ p += 4;
+
+ SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
+ strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
+ strupper_m(p2);
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+ p += 4;
+
+ SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
+ SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
+ p += 2;
+
+ SIVAL(p,0,PTR_DIFF(p2,*rdata));
+ strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+ p += 4;
+
+ SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
+ strlcpy(p2,"",PTR_DIFF(endp,p2));
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+ p += 4;
+
+ *rdata_len = PTR_DIFF(p2,*rdata);
+
+ SSVAL(*rparam,4,*rdata_len);
+
+ return True;
+}
+
+/****************************************************************************
+ get info about a user
+
+ struct user_info_11 {
+ char usri11_name[21]; 0-20
+ char usri11_pad; 21
+ char *usri11_comment; 22-25
+ char *usri11_usr_comment; 26-29
+ unsigned short usri11_priv; 30-31
+ unsigned long usri11_auth_flags; 32-35
+ long usri11_password_age; 36-39
+ char *usri11_homedir; 40-43
+ char *usri11_parms; 44-47
+ long usri11_last_logon; 48-51
+ long usri11_last_logoff; 52-55
+ unsigned short usri11_bad_pw_count; 56-57
+ unsigned short usri11_num_logons; 58-59
+ char *usri11_logon_server; 60-63
+ unsigned short usri11_country_code; 64-65
+ char *usri11_workstations; 66-69
+ unsigned long usri11_max_storage; 70-73
+ unsigned short usri11_units_per_week; 74-75
+ unsigned char *usri11_logon_hours; 76-79
+ unsigned short usri11_code_page; 80-81
+ };
+
+where:
+
+ usri11_name specifies the user name for which information is retrieved
+
+ usri11_pad aligns the next data structure element to a word boundary
+
+ usri11_comment is a null terminated ASCII comment
+
+ usri11_user_comment is a null terminated ASCII comment about the user
+
+ usri11_priv specifies the level of the privilege assigned to the user.
+ The possible values are:
+
+Name Value Description
+USER_PRIV_GUEST 0 Guest privilege
+USER_PRIV_USER 1 User privilege
+USER_PRV_ADMIN 2 Administrator privilege
+
+ usri11_auth_flags specifies the account operator privileges. The
+ possible values are:
+
+Name Value Description
+AF_OP_PRINT 0 Print operator
+
+
+Leach, Naik [Page 28]
+
+
+
+INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
+
+
+AF_OP_COMM 1 Communications operator
+AF_OP_SERVER 2 Server operator
+AF_OP_ACCOUNTS 3 Accounts operator
+
+
+ usri11_password_age specifies how many seconds have elapsed since the
+ password was last changed.
+
+ usri11_home_dir points to a null terminated ASCII string that contains
+ the path name of the user's home directory.
+
+ usri11_parms points to a null terminated ASCII string that is set
+ aside for use by applications.
+
+ usri11_last_logon specifies the time when the user last logged on.
+ This value is stored as the number of seconds elapsed since
+ 00:00:00, January 1, 1970.
+
+ usri11_last_logoff specifies the time when the user last logged off.
+ This value is stored as the number of seconds elapsed since
+ 00:00:00, January 1, 1970. A value of 0 means the last logoff
+ time is unknown.
+
+ usri11_bad_pw_count specifies the number of incorrect passwords
+ entered since the last successful logon.
+
+ usri11_log1_num_logons specifies the number of times this user has
+ logged on. A value of -1 means the number of logons is unknown.
+
+ usri11_logon_server points to a null terminated ASCII string that
+ contains the name of the server to which logon requests are sent.
+ A null string indicates logon requests should be sent to the
+ domain controller.
+
+ usri11_country_code specifies the country code for the user's language
+ of choice.
+
+ usri11_workstations points to a null terminated ASCII string that
+ contains the names of workstations the user may log on from.
+ There may be up to 8 workstations, with the names separated by
+ commas. A null strings indicates there are no restrictions.
+
+ usri11_max_storage specifies the maximum amount of disk space the user
+ can occupy. A value of 0xffffffff indicates there are no
+ restrictions.
+
+ usri11_units_per_week specifies the equal number of time units into
+ which a week is divided. This value must be equal to 168.
+
+ usri11_logon_hours points to a 21 byte (168 bits) string that
+ specifies the time during which the user can log on. Each bit
+ represents one unique hour in a week. The first bit (bit 0, word
+ 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
+
+
+
+Leach, Naik [Page 29]
+
+
+
+INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
+
+
+ Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
+ are no restrictions.
+
+ usri11_code_page specifies the code page for the user's language of
+ choice
+
+All of the pointers in this data structure need to be treated
+specially. The pointer is a 32 bit pointer. The higher 16 bits need
+to be ignored. The converter word returned in the parameters section
+needs to be subtracted from the lower 16 bits to calculate an offset
+into the return buffer where this ASCII string resides.
+
+There is no auxiliary data in the response.
+
+ ****************************************************************************/
+
+#define usri11_name 0
+#define usri11_pad 21
+#define usri11_comment 22
+#define usri11_usr_comment 26
+#define usri11_full_name 30
+#define usri11_priv 34
+#define usri11_auth_flags 36
+#define usri11_password_age 40
+#define usri11_homedir 44
+#define usri11_parms 48
+#define usri11_last_logon 52
+#define usri11_last_logoff 56
+#define usri11_bad_pw_count 60
+#define usri11_num_logons 62
+#define usri11_logon_server 64
+#define usri11_country_code 68
+#define usri11_workstations 70
+#define usri11_max_storage 74
+#define usri11_units_per_week 78
+#define usri11_logon_hours 80
+#define usri11_code_page 84
+#define usri11_end 86
+
+#define USER_PRIV_GUEST 0
+#define USER_PRIV_USER 1
+#define USER_PRIV_ADMIN 2
+
+#define AF_OP_PRINT 0
+#define AF_OP_COMM 1
+#define AF_OP_SERVER 2
+#define AF_OP_ACCOUNTS 3
+
+
+static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *UserName = skip_string(param,tpscnt,str2);
+ char *p = skip_string(param,tpscnt,UserName);
+ int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+ char *p2;
+ char *endp;
+ const char *level_string;
+
+ /* get NIS home of a previously validated user - simeon */
+ /* With share level security vuid will always be zero.
+ Don't depend on vuser being non-null !!. JRA */
+ user_struct *vuser = get_valid_user_struct(vuid);
+ if(vuser != NULL) {
+ DEBUG(3,(" Username of UID %d is %s\n",
+ (int)vuser->server_info->utok.uid,
+ vuser->server_info->unix_name));
+ }
+
+ if (!str1 || !str2 || !UserName || !p) {
+ return False;
+ }
+
+ *rparam_len = 6;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+
+ DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
+
+ /* check it's a supported variant */
+ if (strcmp(str1,"zWrLh") != 0) {
+ return False;
+ }
+ switch( uLevel ) {
+ case 0: level_string = "B21"; break;
+ case 1: level_string = "B21BB16DWzzWz"; break;
+ case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
+ case 10: level_string = "B21Bzzz"; break;
+ case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
+ default: return False;
+ }
+
+ if (strcmp(level_string,str2) != 0) {
+ return False;
+ }
+
+ *rdata_len = mdrcnt + 1024;
+ *rdata = smb_realloc_limit(*rdata,*rdata_len);
+ if (!*rdata) {
+ return False;
+ }
+
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ p = *rdata;
+ endp = *rdata + *rdata_len;
+ p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
+ if (!p2) {
+ return False;
+ }
+
+ memset(p,0,21);
+ fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
+
+ if (uLevel > 0) {
+ SCVAL(p,usri11_pad,0); /* padding - 1 byte */
+ *p2 = 0;
+ }
+
+ if (uLevel >= 10) {
+ SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
+ strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+
+ SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
+ strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+
+ /* EEK! the cifsrap.txt doesn't have this in!!!! */
+ SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
+ strlcpy(p2,((vuser != NULL)
+ ? pdb_get_fullname(vuser->server_info->sam_account)
+ : UserName),PTR_DIFF(endp,p2));
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+ }
+
+ if (uLevel == 11) {
+ const char *homedir = "";
+ if (vuser != NULL) {
+ homedir = pdb_get_homedir(
+ vuser->server_info->sam_account);
+ }
+ /* 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 */
+ strlcpy(p2, homedir, PTR_DIFF(endp,p2));
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+ SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
+ strlcpy(p2,"",PTR_DIFF(endp,p2));
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+ 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 */
+ strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+ SSVAL(p,usri11_country_code,0); /* country code */
+
+ SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
+ strlcpy(p2,"",PTR_DIFF(endp,p2));
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+
+ 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(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+
+ 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 */
+ strlcpy(p2, vuser ? pdb_get_homedir(
+ vuser->server_info->sam_account) : "",
+ PTR_DIFF(endp,p2));
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+ SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
+ *p2++ = 0;
+ SSVAL(p,52,0); /* flags */
+ SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
+ strlcpy(p2, vuser ? pdb_get_logon_script(
+ vuser->server_info->sam_account) : "",
+ PTR_DIFF(endp,p2));
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+ if (uLevel == 2) {
+ SIVAL(p,60,0); /* auth_flags */
+ SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
+ strlcpy(p2,((vuser != NULL)
+ ? pdb_get_fullname(vuser->server_info->sam_account)
+ : UserName),PTR_DIFF(endp,p2));
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+ SIVAL(p,68,0); /* urs_comment */
+ SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
+ strlcpy(p2,"",PTR_DIFF(endp,p2));
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+ 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 */
+ {
+ TALLOC_CTX *ctx = talloc_tos();
+ int space_rem = *rdata_len - (p2 - *rdata);
+ char *tmp;
+
+ if (space_rem <= 0) {
+ return false;
+ }
+ tmp = talloc_strdup(ctx, "\\\\%L");
+ if (!tmp) {
+ return false;
+ }
+ tmp = talloc_sub_basic(ctx,
+ "",
+ "",
+ tmp);
+ if (!tmp) {
+ return false;
+ }
+
+ push_ascii(p2,
+ tmp,
+ space_rem,
+ STR_TERMINATE);
+ }
+ p2 = skip_string(*rdata,*rdata_len,p2);
+ if (!p2) {
+ return False;
+ }
+ SSVAL(p,110,49); /* country_code */
+ SSVAL(p,112,860); /* code page */
+ }
+ }
+
+ *rdata_len = PTR_DIFF(p2,*rdata);
+
+ SSVAL(*rparam,4,*rdata_len); /* is this right?? */
+
+ return(True);
+}
+
+static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ int uLevel;
+ struct pack_desc desc;
+ char* name;
+ /* 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 (!str1 || !str2 || !p) {
+ return False;
+ }
+
+ if(vuser != NULL) {
+ DEBUG(3,(" Username of UID %d is %s\n",
+ (int)vuser->server_info->utok.uid,
+ vuser->server_info->unix_name));
+ }
+
+ uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+ name = get_safe_str_ptr(param,tpscnt,p,2);
+ if (!name) {
+ return False;
+ }
+
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"OOWb54WrLh") != 0) {
+ return False;
+ }
+ if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
+ return False;
+ }
+ if (mdrcnt > 0) {
+ *rdata = smb_realloc_limit(*rdata,mdrcnt);
+ if (!*rdata) {
+ return False;
+ }
+ }
+
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ desc.subformat = NULL;
+ desc.format = str2;
+
+ if (init_package(&desc,1,0)) {
+ PACKI(&desc,"W",0); /* code */
+ PACKS(&desc,"B21",name); /* eff. name */
+ PACKS(&desc,"B",""); /* pad */
+ PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
+ PACKI(&desc,"D",0); /* auth flags XXX */
+ PACKI(&desc,"W",0); /* num logons */
+ PACKI(&desc,"W",0); /* bad pw count */
+ PACKI(&desc,"D",0); /* last logon */
+ PACKI(&desc,"D",-1); /* last logoff */
+ PACKI(&desc,"D",-1); /* logoff time */
+ PACKI(&desc,"D",-1); /* kickoff time */
+ PACKI(&desc,"D",0); /* password age */
+ PACKI(&desc,"D",0); /* password can change */
+ PACKI(&desc,"D",-1); /* password must change */
+
+ {
+ fstring mypath;
+ fstrcpy(mypath,"\\\\");
+ fstrcat(mypath,get_local_machine_name());
+ strupper_m(mypath);
+ PACKS(&desc,"z",mypath); /* computer */
+ }
+
+ PACKS(&desc,"z",lp_workgroup());/* domain */
+ PACKS(&desc,"z", vuser ? pdb_get_logon_script(
+ vuser->server_info->sam_account) : ""); /* script path */
+ PACKI(&desc,"D",0x00000000); /* reserved */
+ }
+
+ *rdata_len = desc.usedlen;
+ *rparam_len = 6;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,desc.neededlen);
+
+ DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
+
+ return True;
+}
+
+/****************************************************************************
+ api_WAccessGetUserPerms
+****************************************************************************/
+
+static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *user = skip_string(param,tpscnt,str2);
+ char *resource = skip_string(param,tpscnt,user);
+
+ if (!str1 || !str2 || !user || !resource) {
+ return False;
+ }
+
+ if (skip_string(param,tpscnt,resource) == NULL) {
+ return False;
+ }
+ DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"zzh") != 0) {
+ return False;
+ }
+ if (strcmp(str2,"") != 0) {
+ return False;
+ }
+
+ *rparam_len = 6;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVALS(*rparam,0,0); /* errorcode */
+ SSVAL(*rparam,2,0); /* converter word */
+ SSVAL(*rparam,4,0x7f); /* permission flags */
+
+ return True;
+}
+
+/****************************************************************************
+ api_WPrintJobEnumerate
+ ****************************************************************************/
+
+static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ int uLevel;
+ int count;
+ int i;
+ int snum;
+ fstring sharename;
+ uint32 jobid;
+ struct pack_desc desc;
+ print_queue_struct *queue=NULL;
+ print_status_struct status;
+ char *tmpdata=NULL;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+
+ uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
+
+ memset((char *)&desc,'\0',sizeof(desc));
+ memset((char *)&status,'\0',sizeof(status));
+
+ DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"WWrLh") != 0) {
+ return False;
+ }
+ if (!check_printjob_info(&desc,uLevel,str2)) {
+ return False;
+ }
+
+ if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
+ return False;
+ }
+
+ snum = lp_servicenumber( sharename);
+ if (snum < 0 || !VALID_SNUM(snum)) {
+ return(False);
+ }
+
+ count = print_queue_status(snum,&queue,&status);
+ for (i = 0; i < count; i++) {
+ if (queue[i].job == jobid) {
+ break;
+ }
+ }
+
+ if (mdrcnt > 0) {
+ *rdata = smb_realloc_limit(*rdata,mdrcnt);
+ if (!*rdata) {
+ return False;
+ }
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ } else {
+ /*
+ * Don't return data but need to get correct length
+ * init_package will return wrong size if buflen=0
+ */
+ desc.buflen = getlen(desc.format);
+ desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
+ }
+
+ if (init_package(&desc,1,0)) {
+ if (i < count) {
+ fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
+ *rdata_len = desc.usedlen;
+ } else {
+ desc.errcode = NERR_JobNotFound;
+ *rdata_len = 0;
+ }
+ }
+
+ *rparam_len = 6;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,desc.neededlen);
+
+ SAFE_FREE(queue);
+ SAFE_FREE(tmpdata);
+
+ DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
+
+ return True;
+}
+
+static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ char *name = p;
+ int uLevel;
+ int count;
+ int i, succnt=0;
+ int snum;
+ struct pack_desc desc;
+ print_queue_struct *queue=NULL;
+ print_status_struct status;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+
+ memset((char *)&desc,'\0',sizeof(desc));
+ memset((char *)&status,'\0',sizeof(status));
+
+ p = skip_string(param,tpscnt,p);
+ if (!p) {
+ return False;
+ }
+ uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+
+ DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
+
+ /* check it's a supported variant */
+ if (strcmp(str1,"zWrLeh") != 0) {
+ return False;
+ }
+
+ if (uLevel > 2) {
+ return False; /* defined only for uLevel 0,1,2 */
+ }
+
+ if (!check_printjob_info(&desc,uLevel,str2)) {
+ return False;
+ }
+
+ snum = find_service(name);
+ if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
+ return False;
+ }
+
+ count = print_queue_status(snum,&queue,&status);
+ if (mdrcnt > 0) {
+ *rdata = smb_realloc_limit(*rdata,mdrcnt);
+ if (!*rdata) {
+ return False;
+ }
+ }
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+
+ if (init_package(&desc,count,0)) {
+ succnt = 0;
+ for (i = 0; i < count; i++) {
+ fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
+ if (desc.errcode == NERR_Success) {
+ succnt = i+1;
+ }
+ }
+ }
+
+ *rdata_len = desc.usedlen;
+
+ *rparam_len = 8;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,succnt);
+ SSVAL(*rparam,6,count);
+
+ SAFE_FREE(queue);
+
+ DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
+
+ return True;
+}
+
+static int check_printdest_info(struct pack_desc* desc,
+ int uLevel, char* id)
+{
+ desc->subformat = NULL;
+ switch( uLevel ) {
+ case 0:
+ desc->format = "B9";
+ break;
+ case 1:
+ desc->format = "B9B21WWzW";
+ break;
+ case 2:
+ desc->format = "z";
+ break;
+ case 3:
+ desc->format = "zzzWWzzzWW";
+ break;
+ default:
+ DEBUG(0,("check_printdest_info: invalid level %d\n",
+ uLevel));
+ return False;
+ }
+ if (id == NULL || strcmp(desc->format,id) != 0) {
+ DEBUG(0,("check_printdest_info: invalid string %s\n",
+ id ? id : "<NULL>" ));
+ return False;
+ }
+ return True;
+}
+
+static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
+ struct pack_desc* desc)
+{
+ char buf[100];
+
+ strncpy(buf,SERVICE(snum),sizeof(buf)-1);
+ buf[sizeof(buf)-1] = 0;
+ strupper_m(buf);
+
+ if (uLevel <= 1) {
+ PACKS(desc,"B9",buf); /* szName */
+ if (uLevel == 1) {
+ PACKS(desc,"B21",""); /* szUserName */
+ PACKI(desc,"W",0); /* uJobId */
+ PACKI(desc,"W",0); /* fsStatus */
+ PACKS(desc,"z",""); /* pszStatus */
+ PACKI(desc,"W",0); /* time */
+ }
+ }
+
+ if (uLevel == 2 || uLevel == 3) {
+ PACKS(desc,"z",buf); /* pszPrinterName */
+ if (uLevel == 3) {
+ PACKS(desc,"z",""); /* pszUserName */
+ PACKS(desc,"z",""); /* pszLogAddr */
+ PACKI(desc,"W",0); /* uJobId */
+ PACKI(desc,"W",0); /* fsStatus */
+ PACKS(desc,"z",""); /* pszStatus */
+ PACKS(desc,"z",""); /* pszComment */
+ PACKS(desc,"z","NULL"); /* pszDrivers */
+ PACKI(desc,"W",0); /* time */
+ PACKI(desc,"W",0); /* pad1 */
+ }
+ }
+}
+
+static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ char* PrinterName = p;
+ int uLevel;
+ struct pack_desc desc;
+ int snum;
+ char *tmpdata=NULL;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ p = skip_string(param,tpscnt,p);
+ if (!p) {
+ return False;
+ }
+ uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+
+ DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"zWrLh") != 0) {
+ return False;
+ }
+ if (!check_printdest_info(&desc,uLevel,str2)) {
+ return False;
+ }
+
+ snum = find_service(PrinterName);
+ if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
+ *rdata_len = 0;
+ desc.errcode = NERR_DestNotFound;
+ desc.neededlen = 0;
+ } else {
+ if (mdrcnt > 0) {
+ *rdata = smb_realloc_limit(*rdata,mdrcnt);
+ if (!*rdata) {
+ return False;
+ }
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ } else {
+ /*
+ * Don't return data but need to get correct length
+ * init_package will return wrong size if buflen=0
+ */
+ desc.buflen = getlen(desc.format);
+ desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
+ }
+ if (init_package(&desc,1,0)) {
+ fill_printdest_info(conn,snum,uLevel,&desc);
+ }
+ *rdata_len = desc.usedlen;
+ }
+
+ *rparam_len = 6;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,desc.neededlen);
+
+ DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
+ SAFE_FREE(tmpdata);
+
+ return True;
+}
+
+static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ int uLevel;
+ int queuecnt;
+ int i, n, succnt=0;
+ struct pack_desc desc;
+ int services = lp_numservices();
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+
+ DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"WrLeh") != 0) {
+ return False;
+ }
+ if (!check_printdest_info(&desc,uLevel,str2)) {
+ return False;
+ }
+
+ queuecnt = 0;
+ for (i = 0; i < services; i++) {
+ if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
+ queuecnt++;
+ }
+ }
+
+ if (mdrcnt > 0) {
+ *rdata = smb_realloc_limit(*rdata,mdrcnt);
+ if (!*rdata) {
+ return False;
+ }
+ }
+
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ if (init_package(&desc,queuecnt,0)) {
+ succnt = 0;
+ n = 0;
+ for (i = 0; i < services; i++) {
+ if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
+ fill_printdest_info(conn,i,uLevel,&desc);
+ n++;
+ if (desc.errcode == NERR_Success) {
+ succnt = n;
+ }
+ }
+ }
+ }
+
+ *rdata_len = desc.usedlen;
+
+ *rparam_len = 8;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,succnt);
+ SSVAL(*rparam,6,queuecnt);
+
+ DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
+
+ return True;
+}
+
+static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ int uLevel;
+ int succnt;
+ struct pack_desc desc;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+
+ DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"WrLeh") != 0) {
+ return False;
+ }
+ if (uLevel != 0 || strcmp(str2,"B41") != 0) {
+ return False;
+ }
+
+ if (mdrcnt > 0) {
+ *rdata = smb_realloc_limit(*rdata,mdrcnt);
+ if (!*rdata) {
+ return False;
+ }
+ }
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ if (init_package(&desc,1,0)) {
+ PACKS(&desc,"B41","NULL");
+ }
+
+ succnt = (desc.errcode == NERR_Success ? 1 : 0);
+
+ *rdata_len = desc.usedlen;
+
+ *rparam_len = 8;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,succnt);
+ SSVAL(*rparam,6,1);
+
+ DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
+
+ return True;
+}
+
+static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ int uLevel;
+ int succnt;
+ struct pack_desc desc;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+
+ DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"WrLeh") != 0) {
+ return False;
+ }
+ if (uLevel != 0 || strcmp(str2,"B13") != 0) {
+ return False;
+ }
+
+ if (mdrcnt > 0) {
+ *rdata = smb_realloc_limit(*rdata,mdrcnt);
+ if (!*rdata) {
+ return False;
+ }
+ }
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ desc.format = str2;
+ if (init_package(&desc,1,0)) {
+ PACKS(&desc,"B13","lpd");
+ }
+
+ succnt = (desc.errcode == NERR_Success ? 1 : 0);
+
+ *rdata_len = desc.usedlen;
+
+ *rparam_len = 8;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,succnt);
+ SSVAL(*rparam,6,1);
+
+ DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
+
+ return True;
+}
+
+static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ int uLevel;
+ int succnt;
+ struct pack_desc desc;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+
+ DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"WrLeh") != 0) {
+ return False;
+ }
+ if (uLevel != 0 || strcmp(str2,"B9") != 0) {
+ return False;
+ }
+
+ if (mdrcnt > 0) {
+ *rdata = smb_realloc_limit(*rdata,mdrcnt);
+ if (!*rdata) {
+ return False;
+ }
+ }
+ memset((char *)&desc,'\0',sizeof(desc));
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ desc.format = str2;
+ if (init_package(&desc,1,0)) {
+ PACKS(&desc,"B13","lp0");
+ }
+
+ succnt = (desc.errcode == NERR_Success ? 1 : 0);
+
+ *rdata_len = desc.usedlen;
+
+ *rparam_len = 8;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,succnt);
+ SSVAL(*rparam,6,1);
+
+ DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
+
+ return True;
+}
+
+/****************************************************************************
+ List open sessions
+ ****************************************************************************/
+
+static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+
+{
+ char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
+ char *str2 = skip_string(param,tpscnt,str1);
+ char *p = skip_string(param,tpscnt,str2);
+ int uLevel;
+ struct pack_desc desc;
+ struct sessionid *session_list;
+ int i, num_sessions;
+
+ if (!str1 || !str2 || !p) {
+ return False;
+ }
+
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
+
+ DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
+ DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
+ DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
+ return False;
+ }
+ if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
+ return False;
+ }
+
+ num_sessions = list_sessions(talloc_tos(), &session_list);
+
+ if (mdrcnt > 0) {
+ *rdata = smb_realloc_limit(*rdata,mdrcnt);
+ if (!*rdata) {
+ return False;
+ }
+ }
+ memset((char *)&desc,'\0',sizeof(desc));
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ desc.format = str2;
+ if (!init_package(&desc,num_sessions,0)) {
+ return False;
+ }
+
+ for(i=0; i<num_sessions; i++) {
+ PACKS(&desc, "z", session_list[i].remote_machine);
+ PACKS(&desc, "z", session_list[i].username);
+ PACKI(&desc, "W", 1); /* num conns */
+ PACKI(&desc, "W", 0); /* num opens */
+ PACKI(&desc, "W", 1); /* num users */
+ PACKI(&desc, "D", 0); /* session time */
+ PACKI(&desc, "D", 0); /* idle time */
+ PACKI(&desc, "D", 0); /* flags */
+ PACKS(&desc, "z", "Unknown Client"); /* client type string */
+ }
+
+ *rdata_len = desc.usedlen;
+
+ *rparam_len = 8;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0); /* converter */
+ SSVAL(*rparam,4,num_sessions); /* count */
+
+ DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
+
+ return True;
+}
+
+
+/****************************************************************************
+ The buffer was too small.
+ ****************************************************************************/
+
+static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
+ int mdrcnt, int mprcnt,
+ char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
+{
+ *rparam_len = MIN(*rparam_len,mprcnt);
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+
+ *rdata_len = 0;
+
+ SSVAL(*rparam,0,NERR_BufTooSmall);
+
+ DEBUG(3,("Supplied buffer too small in API command\n"));
+
+ return True;
+}
+
+/****************************************************************************
+ The request is not supported.
+ ****************************************************************************/
+
+static bool api_Unsupported(connection_struct *conn, uint16 vuid,
+ char *param, int tpscnt,
+ char *data, int tdscnt,
+ int mdrcnt, int mprcnt,
+ char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
+{
+ *rparam_len = 4;
+ *rparam = smb_realloc_limit(*rparam,*rparam_len);
+ if (!*rparam) {
+ return False;
+ }
+
+ *rdata_len = 0;
+
+ SSVAL(*rparam,0,NERR_notsupported);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ DEBUG(3,("Unsupported API command\n"));
+
+ return True;
+}
+
+static const struct {
+ const char *name;
+ int id;
+ bool (*fn)(connection_struct *, uint16,
+ char *, int,
+ char *, int,
+ int,int,char **,char **,int *,int *);
+ bool auth_user; /* Deny anonymous access? */
+} api_commands[] = {
+ {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
+ {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
+ {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
+ {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
+ {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
+ {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
+ {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
+ {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
+ {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
+ {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
+ {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
+ {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
+ {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
+ {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
+ {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
+ {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
+ {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
+ {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
+ {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
+ {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
+ {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
+ {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
+ {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
+ {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
+ {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
+ {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
+ {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
+ {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
+ {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
+ {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
+ {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
+ {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
+ {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
+ {NULL, -1, api_Unsupported}
+ /* The following RAP calls are not implemented by Samba:
+
+ RAP_WFileEnum2 - anon not OK
+ */
+};
+
+
+/****************************************************************************
+ Handle remote api calls.
+****************************************************************************/
+
+void api_reply(connection_struct *conn, uint16 vuid,
+ struct smb_request *req,
+ char *data, char *params,
+ int tdscnt, int tpscnt,
+ int mdrcnt, int mprcnt)
+{
+ int api_command;
+ char *rdata = NULL;
+ char *rparam = NULL;
+ const char *name1 = NULL;
+ const char *name2 = NULL;
+ int rdata_len = 0;
+ int rparam_len = 0;
+ bool reply=False;
+ int i;
+
+ if (!params) {
+ DEBUG(0,("ERROR: NULL params in api_reply()\n"));
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ if (tpscnt < 2) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+ api_command = SVAL(params,0);
+ /* Is there a string at position params+2 ? */
+ if (skip_string(params,tpscnt,params+2)) {
+ name1 = params + 2;
+ } else {
+ name1 = "";
+ }
+ name2 = skip_string(params,tpscnt,params+2);
+ if (!name2) {
+ name2 = "";
+ }
+
+ DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
+ api_command,
+ name1,
+ name2,
+ tdscnt,tpscnt,mdrcnt,mprcnt));
+
+ for (i=0;api_commands[i].name;i++) {
+ if (api_commands[i].id == api_command && api_commands[i].fn) {
+ DEBUG(3,("Doing %s\n",api_commands[i].name));
+ break;
+ }
+ }
+
+ /* Check whether this api call can be done anonymously */
+
+ if (api_commands[i].auth_user && lp_restrict_anonymous()) {
+ user_struct *user = get_valid_user_struct(vuid);
+
+ if (!user || user->server_info->guest) {
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+ }
+
+ rdata = (char *)SMB_MALLOC(1024);
+ if (rdata) {
+ memset(rdata,'\0',1024);
+ }
+
+ rparam = (char *)SMB_MALLOC(1024);
+ if (rparam) {
+ memset(rparam,'\0',1024);
+ }
+
+ if(!rdata || !rparam) {
+ DEBUG(0,("api_reply: malloc fail !\n"));
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+
+ reply = api_commands[i].fn(conn,
+ vuid,
+ params,tpscnt, /* params + length */
+ data,tdscnt, /* data + length */
+ mdrcnt,mprcnt,
+ &rdata,&rparam,&rdata_len,&rparam_len);
+
+
+ if (rdata_len > mdrcnt || rparam_len > mprcnt) {
+ reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
+ &rdata,&rparam,&rdata_len,&rparam_len);
+ }
+
+ /* if we get False back then it's actually unsupported */
+ if (!reply) {
+ reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
+ &rdata,&rparam,&rdata_len,&rparam_len);
+ }
+
+ /* If api_Unsupported returns false we can't return anything. */
+ if (reply) {
+ send_trans_reply(conn, req->inbuf, rparam, rparam_len,
+ rdata, rdata_len, False);
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return;
+}
diff --git a/source3/smbd/mangle.c b/source3/smbd/mangle.c
new file mode 100644
index 0000000000..360692c546
--- /dev/null
+++ b/source3/smbd/mangle.c
@@ -0,0 +1,152 @@
+/*
+ Unix SMB/CIFS implementation.
+ Name mangling interface
+ Copyright (C) Andrew Tridgell 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static struct mangle_fns *mangle_fns;
+
+/* this allows us to add more mangling backends */
+static const struct {
+ const char *name;
+ struct mangle_fns *(*init_fn)(void);
+} mangle_backends[] = {
+ { "hash", mangle_hash_init },
+ { "hash2", mangle_hash2_init },
+ { "posix", posix_mangle_init },
+ /*{ "tdb", mangle_tdb_init }, */
+ { NULL, NULL }
+};
+
+/*
+ initialise the mangling subsystem
+*/
+static void mangle_init(void)
+{
+ int i;
+ const char *method;
+
+ if (mangle_fns)
+ return;
+
+ method = lp_mangling_method();
+
+ /* find the first mangling method that manages to initialise and
+ matches the "mangling method" parameter */
+ for (i=0; mangle_backends[i].name && !mangle_fns; i++) {
+ if (!method || !*method || strcmp(method, mangle_backends[i].name) == 0) {
+ mangle_fns = mangle_backends[i].init_fn();
+ }
+ }
+
+ if (!mangle_fns) {
+ DEBUG(0,("Failed to initialise mangling system '%s'\n", method));
+ exit_server("mangling init failed");
+ }
+}
+
+
+/*
+ reset the cache. This is called when smb.conf has been reloaded
+*/
+void mangle_reset_cache(void)
+{
+ mangle_init();
+ mangle_fns->reset();
+}
+
+void mangle_change_to_posix(void)
+{
+ mangle_fns = NULL;
+ lp_set_mangling_method("posix");
+ mangle_reset_cache();
+}
+
+/*
+ see if a filename has come out of our mangling code
+*/
+bool mangle_is_mangled(const char *s, const struct share_params *p)
+{
+ return mangle_fns->is_mangled(s, p);
+}
+
+/*
+ see if a filename matches the rules of a 8.3 filename
+*/
+bool mangle_is_8_3(const char *fname, bool check_case,
+ const struct share_params *p)
+{
+ return mangle_fns->is_8_3(fname, check_case, False, p);
+}
+
+bool mangle_is_8_3_wildcards(const char *fname, bool check_case,
+ const struct share_params *p)
+{
+ return mangle_fns->is_8_3(fname, check_case, True, p);
+}
+
+bool mangle_must_mangle(const char *fname,
+ const struct share_params *p)
+{
+ if (!lp_manglednames(p)) {
+ return False;
+ }
+ return mangle_fns->must_mangle(fname, p);
+}
+
+/*
+ try to reverse map a 8.3 name to the original filename. This doesn't have to
+ always succeed, as the directory handling code in smbd will scan the directory
+ looking for a matching name if it doesn't. It should succeed most of the time
+ or there will be a huge performance penalty
+*/
+bool mangle_lookup_name_from_8_3(TALLOC_CTX *ctx,
+ const char *in,
+ char **out, /* talloced on the given context. */
+ const struct share_params *p)
+{
+ return mangle_fns->lookup_name_from_8_3(ctx, in, out, p);
+}
+
+/*
+ mangle a long filename to a 8.3 name.
+ Return True if we did mangle the name (ie. out is filled in).
+ False on error.
+ JRA.
+ */
+
+bool name_to_8_3(const char *in,
+ char out[13],
+ bool cache83,
+ const struct share_params *p)
+{
+ memset(out,'\0',13);
+
+ /* name mangling can be disabled for speed, in which case
+ we just truncate the string */
+ if (!lp_manglednames(p)) {
+ safe_strcpy(out,in,12);
+ return True;
+ }
+
+ return mangle_fns->name_to_8_3(in,
+ out,
+ cache83,
+ lp_defaultcase(p->service),
+ p);
+}
diff --git a/source3/smbd/mangle_hash.c b/source3/smbd/mangle_hash.c
new file mode 100644
index 0000000000..69ecf77834
--- /dev/null
+++ b/source3/smbd/mangle_hash.c
@@ -0,0 +1,695 @@
+/*
+ Unix SMB/CIFS implementation.
+ Name mangling
+ Copyright (C) Andrew Tridgell 1992-2002
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Jeremy Allison 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* -------------------------------------------------------------------------- **
+ * 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.
+ *
+ * MANGLE_BASE - This is the number of characters we use for name mangling.
+ *
+ * basechars - The set characters used for name mangling. This
+ * is static (scope is this file only).
+ *
+ * mangle() - Macro used to select a character from basechars (i.e.,
+ * mangle(n) will return the nth digit, modulo MANGLE_BASE).
+ *
+ * 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 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.
+ *
+ * isbasecahr() - Given a character, check the chartest array to see
+ * if that character is in the basechars set. This is
+ * faster than using strchr_m().
+ *
+ */
+
+static char magic_char = '~';
+
+static const char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%";
+#define MANGLE_BASE (sizeof(basechars)/sizeof(char)-1)
+
+static unsigned char *chartest;
+
+#define mangle(V) ((char)(basechars[(V) % MANGLE_BASE]))
+#define BASECHAR_MASK 0xf0
+#define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK )
+
+static TDB_CONTEXT *tdb_mangled_cache;
+
+/* -------------------------------------------------------------------- */
+
+static NTSTATUS has_valid_83_chars(const smb_ucs2_t *s, bool allow_wildcards)
+{
+ if (!*s) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!allow_wildcards && ms_has_wild_w(s)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ while (*s) {
+ if(!isvalid83_w(*s)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ s++;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS has_illegal_chars(const smb_ucs2_t *s, bool allow_wildcards)
+{
+ if (!allow_wildcards && ms_has_wild_w(s)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ while (*s) {
+ if (*s <= 0x1f) {
+ /* Control characters. */
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ switch(*s) {
+ case UCS2_CHAR('\\'):
+ case UCS2_CHAR('/'):
+ case UCS2_CHAR('|'):
+ case UCS2_CHAR(':'):
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ s++;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/* return False if something fail and
+ * return 2 alloced unicode strings that contain prefix and extension
+ */
+
+static NTSTATUS mangle_get_prefix(const smb_ucs2_t *ucs2_string, smb_ucs2_t **prefix,
+ smb_ucs2_t **extension, bool allow_wildcards)
+{
+ size_t ext_len;
+ smb_ucs2_t *p;
+
+ *extension = 0;
+ *prefix = strdup_w(ucs2_string);
+ if (!*prefix) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ if ((p = strrchr_w(*prefix, UCS2_CHAR('.')))) {
+ ext_len = strlen_w(p+1);
+ if ((ext_len > 0) && (ext_len < 4) && (p != *prefix) &&
+ (NT_STATUS_IS_OK(has_valid_83_chars(p+1,allow_wildcards)))) /* check extension */ {
+ *p = 0;
+ *extension = strdup_w(p+1);
+ if (!*extension) {
+ SAFE_FREE(*prefix);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ }
+ return NT_STATUS_OK;
+}
+
+/* ************************************************************************** **
+ * Return NT_STATUS_UNSUCCESSFUL if a name is a special msdos reserved name.
+ * or contains illegal characters.
+ *
+ * Input: fname - String containing the name to be tested.
+ *
+ * Output: NT_STATUS_UNSUCCESSFUL, if the condition above is true.
+ *
+ * Notes: This is a static function called by is_8_3(), below.
+ *
+ * ************************************************************************** **
+ */
+
+static NTSTATUS is_valid_name(const smb_ucs2_t *fname, bool allow_wildcards, bool only_8_3)
+{
+ smb_ucs2_t *str, *p;
+ size_t num_ucs2_chars;
+ NTSTATUS ret = NT_STATUS_OK;
+
+ if (!fname || !*fname)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ /* . and .. are valid names. */
+ if (strcmp_wa(fname, ".")==0 || strcmp_wa(fname, "..")==0)
+ return NT_STATUS_OK;
+
+ if (only_8_3) {
+ ret = has_valid_83_chars(fname, allow_wildcards);
+ if (!NT_STATUS_IS_OK(ret))
+ return ret;
+ }
+
+ ret = has_illegal_chars(fname, allow_wildcards);
+ if (!NT_STATUS_IS_OK(ret))
+ return ret;
+
+ /* Name can't end in '.' or ' ' */
+ num_ucs2_chars = strlen_w(fname);
+ if (fname[num_ucs2_chars-1] == UCS2_CHAR('.') || fname[num_ucs2_chars-1] == UCS2_CHAR(' ')) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ str = strdup_w(fname);
+
+ /* Truncate copy after the first dot. */
+ p = strchr_w(str, UCS2_CHAR('.'));
+ if (p) {
+ *p = 0;
+ }
+
+ strupper_w(str);
+ p = &str[1];
+
+ switch(str[0])
+ {
+ case UCS2_CHAR('A'):
+ if(strcmp_wa(p, "UX") == 0)
+ ret = NT_STATUS_UNSUCCESSFUL;
+ break;
+ case UCS2_CHAR('C'):
+ if((strcmp_wa(p, "LOCK$") == 0)
+ || (strcmp_wa(p, "ON") == 0)
+ || (strcmp_wa(p, "OM1") == 0)
+ || (strcmp_wa(p, "OM2") == 0)
+ || (strcmp_wa(p, "OM3") == 0)
+ || (strcmp_wa(p, "OM4") == 0)
+ )
+ ret = NT_STATUS_UNSUCCESSFUL;
+ break;
+ case UCS2_CHAR('L'):
+ if((strcmp_wa(p, "PT1") == 0)
+ || (strcmp_wa(p, "PT2") == 0)
+ || (strcmp_wa(p, "PT3") == 0)
+ )
+ ret = NT_STATUS_UNSUCCESSFUL;
+ break;
+ case UCS2_CHAR('N'):
+ if(strcmp_wa(p, "UL") == 0)
+ ret = NT_STATUS_UNSUCCESSFUL;
+ break;
+ case UCS2_CHAR('P'):
+ if(strcmp_wa(p, "RN") == 0)
+ ret = NT_STATUS_UNSUCCESSFUL;
+ break;
+ default:
+ break;
+ }
+
+ SAFE_FREE(str);
+ return ret;
+}
+
+static NTSTATUS is_8_3_w(const smb_ucs2_t *fname, bool allow_wildcards)
+{
+ smb_ucs2_t *pref = 0, *ext = 0;
+ size_t plen;
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ if (!fname || !*fname)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ if (strlen_w(fname) > 12)
+ return NT_STATUS_UNSUCCESSFUL;
+
+ if (strcmp_wa(fname, ".") == 0 || strcmp_wa(fname, "..") == 0)
+ return NT_STATUS_OK;
+
+ /* Name cannot start with '.' */
+ if (*fname == UCS2_CHAR('.'))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ if (!NT_STATUS_IS_OK(is_valid_name(fname, allow_wildcards, True)))
+ goto done;
+
+ if (!NT_STATUS_IS_OK(mangle_get_prefix(fname, &pref, &ext, allow_wildcards)))
+ goto done;
+ plen = strlen_w(pref);
+
+ if (strchr_wa(pref, '.'))
+ goto done;
+ if (plen < 1 || plen > 8)
+ goto done;
+ if (ext && (strlen_w(ext) > 3))
+ goto done;
+
+ ret = NT_STATUS_OK;
+
+done:
+ SAFE_FREE(pref);
+ SAFE_FREE(ext);
+ return ret;
+}
+
+static bool is_8_3(const char *fname, bool check_case, bool allow_wildcards,
+ const struct share_params *p)
+{
+ const char *f;
+ smb_ucs2_t *ucs2name;
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ size_t size;
+
+ magic_char = lp_magicchar(p);
+
+ if (!fname || !*fname)
+ return False;
+ if ((f = strrchr(fname, '/')) == NULL)
+ f = fname;
+ else
+ f++;
+
+ if (strlen(f) > 12)
+ return False;
+
+ if (!push_ucs2_allocate(&ucs2name, f, &size)) {
+ DEBUG(0,("is_8_3: internal error push_ucs2_allocate() failed!\n"));
+ goto done;
+ }
+
+ ret = is_8_3_w(ucs2name, allow_wildcards);
+
+done:
+ SAFE_FREE(ucs2name);
+
+ if (!NT_STATUS_IS_OK(ret)) {
+ return False;
+ }
+
+ return True;
+}
+
+/* -------------------------------------------------------------------------- **
+ * 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 )
+{
+ const unsigned char *s;
+
+ chartest = SMB_MALLOC_ARRAY(unsigned char, 256);
+
+ SMB_ASSERT(chartest != NULL);
+
+ for( s = (const unsigned char *)basechars; *s; s++ ) {
+ chartest[*s] |= BASECHAR_MASK;
+ }
+}
+
+/* ************************************************************************** **
+ * 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).
+ *
+ * ************************************************************************** **
+ */
+
+static bool is_mangled(const char *s, const struct share_params *p)
+{
+ char *magic;
+
+ magic_char = lp_magicchar(p);
+
+ if (chartest == NULL) {
+ init_chartest();
+ }
+
+ magic = strchr_m( 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_ascii(magic[1]) ) /* is 2nd char basechar? */
+ && isbasechar( toupper_ascii(magic[2]) ) ) /* is 3rd char basechar? */
+ return( True ); /* If all above, then true, */
+ magic = strchr_m( magic+1, magic_char ); /* else seek next magic. */
+ }
+ return( False );
+}
+
+/***************************************************************************
+ Initializes or clears the mangled cache.
+***************************************************************************/
+
+static void mangle_reset( void )
+{
+ /* We could close and re-open the tdb here... should we ? The old code did
+ the equivalent... JRA. */
+}
+
+/***************************************************************************
+ Add a mangled name into the cache.
+ 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 consistent
+ 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( const char mangled_name[13],
+ const char *raw_name )
+{
+ TDB_DATA data_val;
+ char mangled_name_key[13];
+ char *s1;
+ char *s2;
+
+ /* If the cache isn't initialized, give up. */
+ if( !tdb_mangled_cache )
+ return;
+
+ /* Init the string lengths. */
+ safe_strcpy(mangled_name_key, mangled_name, sizeof(mangled_name_key)-1);
+
+ /* See if the extensions are unmangled. If so, store the entry
+ * without the extension, thus creating a "group" reverse map.
+ */
+ s1 = strrchr( mangled_name_key, '.' );
+ if( s1 && (s2 = strrchr( raw_name, '.' )) ) {
+ size_t i = 1;
+ while( s1[i] && (tolower_ascii( s1[i] ) == s2[i]) )
+ i++;
+ if( !s1[i] && !s2[i] ) {
+ /* Truncate at the '.' */
+ *s1 = '\0';
+ *s2 = '\0';
+ }
+ }
+
+ /* Allocate a new cache entry. If the allocation fails, just return. */
+ data_val = string_term_tdb_data(raw_name);
+ if (tdb_store_bystring(tdb_mangled_cache, mangled_name_key, data_val, TDB_REPLACE) != 0) {
+ DEBUG(0,("cache_mangled_name: Error storing entry %s -> %s\n", mangled_name_key, raw_name));
+ } else {
+ DEBUG(5,("cache_mangled_name: Stored entry %s -> %s\n", mangled_name_key, raw_name));
+ }
+}
+
+/* ************************************************************************** **
+ * Check for a name on the mangled name stack
+ *
+ * Input: s - Input *and* output string buffer.
+ * maxlen - space in i/o 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.
+ *
+ * ************************************************************************** **
+ */
+
+static bool lookup_name_from_8_3(TALLOC_CTX *ctx,
+ const char *in,
+ char **out, /* talloced on the given context. */
+ const struct share_params *p)
+{
+ TDB_DATA data_val;
+ char *saved_ext = NULL;
+ char *s = talloc_strdup(ctx, in);
+
+ magic_char = lp_magicchar(p);
+
+ /* If the cache isn't initialized, give up. */
+ if(!s || !tdb_mangled_cache ) {
+ TALLOC_FREE(s);
+ return False;
+ }
+
+ data_val = tdb_fetch_bystring(tdb_mangled_cache, s);
+
+ /* If we didn't find the name *with* the extension, try without. */
+ if(data_val.dptr == NULL || data_val.dsize == 0) {
+ char *ext_start = strrchr( s, '.' );
+ if( ext_start ) {
+ if((saved_ext = talloc_strdup(ctx,ext_start)) == NULL) {
+ TALLOC_FREE(s);
+ return False;
+ }
+
+ *ext_start = '\0';
+ data_val = tdb_fetch_bystring(tdb_mangled_cache, s);
+ /*
+ * At this point s is the name without the
+ * extension. We re-add the extension if saved_ext
+ * is not null, before freeing saved_ext.
+ */
+ }
+ }
+
+ /* Okay, if we haven't found it we're done. */
+ if(data_val.dptr == NULL || data_val.dsize == 0) {
+ TALLOC_FREE(saved_ext);
+ TALLOC_FREE(s);
+ return False;
+ }
+
+ /* If we *did* find it, we need to talloc it on the given ctx. */
+ if (saved_ext) {
+ *out = talloc_asprintf(ctx, "%s%s",
+ (char *)data_val.dptr,
+ saved_ext);
+ } else {
+ *out = talloc_strdup(ctx, (char *)data_val.dptr);
+ }
+
+ TALLOC_FREE(s);
+ TALLOC_FREE(saved_ext);
+ SAFE_FREE(data_val.dptr);
+
+ return *out ? True : False;
+}
+
+/*****************************************************************************
+ Do the actual mangling to 8.3 format.
+*****************************************************************************/
+
+static bool to_8_3(const char *in, char out[13], int default_case)
+{
+ int csum;
+ char *p;
+ char extension[4];
+ char base[9];
+ int baselen = 0;
+ int extlen = 0;
+ char *s = SMB_STRDUP(in);
+
+ extension[0] = 0;
+ base[0] = 0;
+
+ if (!s) {
+ return False;
+ }
+
+ p = strrchr(s,'.');
+ if( p && (strlen(p+1) < (size_t)4) ) {
+ bool all_normal = ( strisnormal(p+1, default_case) ); /* XXXXXXXXX */
+
+ if( all_normal && p[1] != 0 ) {
+ *p = 0;
+ csum = str_checksum( s );
+ *p = '.';
+ } else
+ csum = str_checksum(s);
+ } else
+ csum = str_checksum(s);
+
+ strupper_m( s );
+
+ if( p ) {
+ if( p == s )
+ safe_strcpy( extension, "___", 3 );
+ else {
+ *p++ = 0;
+ while( *p && extlen < 3 ) {
+ if ( *p != '.') {
+ extension[extlen++] = p[0];
+ }
+ p++;
+ }
+ extension[extlen] = 0;
+ }
+ }
+
+ p = s;
+
+ while( *p && baselen < 5 ) {
+ if (isbasechar(*p)) {
+ base[baselen++] = p[0];
+ }
+ p++;
+ }
+ base[baselen] = 0;
+
+ csum = csum % (MANGLE_BASE*MANGLE_BASE);
+
+ memcpy(out, base, baselen);
+ out[baselen] = magic_char;
+ out[baselen+1] = mangle( csum/MANGLE_BASE );
+ out[baselen+2] = mangle( csum );
+
+ if( *extension ) {
+ out[baselen+3] = '.';
+ safe_strcpy(&out[baselen+4], extension, 3);
+ }
+
+ SAFE_FREE(s);
+ return True;
+}
+
+static bool must_mangle(const char *name,
+ const struct share_params *p)
+{
+ smb_ucs2_t *name_ucs2 = NULL;
+ NTSTATUS status;
+ size_t converted_size;
+
+ magic_char = lp_magicchar(p);
+
+ if (!push_ucs2_allocate(&name_ucs2, name, &converted_size)) {
+ DEBUG(0, ("push_ucs2_allocate failed!\n"));
+ return False;
+ }
+ status = is_valid_name(name_ucs2, False, False);
+ SAFE_FREE(name_ucs2);
+ return NT_STATUS_IS_OK(status);
+}
+
+/*****************************************************************************
+ * Convert a filename to DOS format. Return True if successful.
+ * Input: in Incoming name.
+ *
+ * out 8.3 DOS name.
+ *
+ * cache83 - If False, the mangled name cache will not be updated.
+ * This is usually used to prevent that we overwrite
+ * a conflicting cache entry prematurely, i.e. before
+ * we know whether the client is really interested in the
+ * current name. (See PR#13758). UKD.
+ *
+ * ****************************************************************************
+ */
+
+static bool hash_name_to_8_3(const char *in,
+ char out[13],
+ bool cache83,
+ int default_case,
+ const struct share_params *p)
+{
+ smb_ucs2_t *in_ucs2 = NULL;
+ size_t converted_size;
+
+ magic_char = lp_magicchar(p);
+
+ DEBUG(5,("hash_name_to_8_3( %s, cache83 = %s)\n", in,
+ cache83 ? "True" : "False"));
+
+ if (!push_ucs2_allocate(&in_ucs2, in, &converted_size)) {
+ DEBUG(0, ("push_ucs2_allocate failed!\n"));
+ return False;
+ }
+
+ /* If it's already 8.3, just copy. */
+ if (NT_STATUS_IS_OK(is_valid_name(in_ucs2, False, False)) &&
+ NT_STATUS_IS_OK(is_8_3_w(in_ucs2, False))) {
+ SAFE_FREE(in_ucs2);
+ safe_strcpy(out, in, 12);
+ return True;
+ }
+
+ SAFE_FREE(in_ucs2);
+ if (!to_8_3(in, out, default_case)) {
+ return False;
+ }
+
+ cache_mangled_name(out, in);
+
+ DEBUG(5,("hash_name_to_8_3(%s) ==> [%s]\n", in, out));
+ return True;
+}
+
+/*
+ the following provides the abstraction layer to make it easier
+ to drop in an alternative mangling implementation
+*/
+static struct mangle_fns mangle_fns = {
+ mangle_reset,
+ is_mangled,
+ must_mangle,
+ is_8_3,
+ lookup_name_from_8_3,
+ hash_name_to_8_3
+};
+
+/* return the methods for this mangling implementation */
+struct mangle_fns *mangle_hash_init(void)
+{
+ mangle_reset();
+
+ /* Create the in-memory tdb using our custom hash function. */
+ tdb_mangled_cache = tdb_open_ex("mangled_cache", 1031, TDB_INTERNAL,
+ (O_RDWR|O_CREAT), 0644, NULL, fast_string_hash);
+
+ return &mangle_fns;
+}
diff --git a/source3/smbd/mangle_hash2.c b/source3/smbd/mangle_hash2.c
new file mode 100644
index 0000000000..a9b94aabc3
--- /dev/null
+++ b/source3/smbd/mangle_hash2.c
@@ -0,0 +1,761 @@
+/*
+ Unix SMB/CIFS implementation.
+ new hash based name mangling implementation
+ Copyright (C) Andrew Tridgell 2002
+ Copyright (C) Simo Sorce 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ this mangling scheme uses the following format
+
+ Annnn~n.AAA
+
+ where nnnnn is a base 36 hash, and A represents characters from the original string
+
+ The hash is taken of the leading part of the long filename, in uppercase
+
+ for simplicity, we only allow ascii characters in 8.3 names
+ */
+
+ /* hash alghorithm changed to FNV1 by idra@samba.org (Simo Sorce).
+ * see http://www.isthe.com/chongo/tech/comp/fnv/index.html for a
+ * discussion on Fowler / Noll / Vo (FNV) Hash by one of it's authors
+ */
+
+/*
+ ===============================================================================
+ NOTE NOTE NOTE!!!
+
+ This file deliberately uses non-multibyte string functions in many places. This
+ is *not* a mistake. This code is multi-byte safe, but it gets this property
+ through some very subtle knowledge of the way multi-byte strings are encoded
+ and the fact that this mangling algorithm only supports ascii characters in
+ 8.3 names.
+
+ please don't convert this file to use the *_m() functions!!
+ ===============================================================================
+*/
+
+
+#include "includes.h"
+
+#if 1
+#define M_DEBUG(level, x) DEBUG(level, x)
+#else
+#define M_DEBUG(level, x)
+#endif
+
+/* these flags are used to mark characters in as having particular
+ properties */
+#define FLAG_BASECHAR 1
+#define FLAG_ASCII 2
+#define FLAG_ILLEGAL 4
+#define FLAG_WILDCARD 8
+
+/* the "possible" flags are used as a fast way to find possible DOS
+ reserved filenames */
+#define FLAG_POSSIBLE1 16
+#define FLAG_POSSIBLE2 32
+#define FLAG_POSSIBLE3 64
+#define FLAG_POSSIBLE4 128
+
+/* by default have a max of 4096 entries in the cache. */
+#ifndef MANGLE_CACHE_SIZE
+#define MANGLE_CACHE_SIZE 4096
+#endif
+
+#define FNV1_PRIME 0x01000193
+/*the following number is a fnv1 of the string: idra@samba.org 2002 */
+#define FNV1_INIT 0xa6b93095
+
+/* these tables are used to provide fast tests for characters */
+static unsigned char char_flags[256];
+
+#define FLAG_CHECK(c, flag) (char_flags[(unsigned char)(c)] & (flag))
+
+/*
+ this determines how many characters are used from the original filename
+ in the 8.3 mangled name. A larger value leads to a weaker hash and more collisions.
+ The largest possible value is 6.
+*/
+static unsigned mangle_prefix;
+
+/* these are the characters we use in the 8.3 hash. Must be 36 chars long */
+static const char *basechars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+static unsigned char base_reverse[256];
+#define base_forward(v) basechars[v]
+
+/* the list of reserved dos names - all of these are illegal */
+static const char *reserved_names[] =
+{ "AUX", "LOCK$", "CON", "COM1", "COM2", "COM3", "COM4",
+ "LPT1", "LPT2", "LPT3", "NUL", "PRN", NULL };
+
+/*
+ hash a string of the specified length. The string does not need to be
+ null terminated
+
+ this hash needs to be fast with a low collision rate (what hash doesn't?)
+*/
+static unsigned int mangle_hash(const char *key, unsigned int length)
+{
+ unsigned int value;
+ unsigned int i;
+ fstring str;
+
+ /* we have to uppercase here to ensure that the mangled name
+ doesn't depend on the case of the long name. Note that this
+ is the only place where we need to use a multi-byte string
+ function */
+ length = MIN(length,sizeof(fstring)-1);
+ strncpy(str, key, length);
+ str[length] = 0;
+ strupper_m(str);
+
+ /* the length of a multi-byte string can change after a strupper_m */
+ length = strlen(str);
+
+ /* Set the initial value from the key size. */
+ for (value = FNV1_INIT, i=0; i < length; i++) {
+ value *= (unsigned int)FNV1_PRIME;
+ value ^= (unsigned int)(str[i]);
+ }
+
+ /* note that we force it to a 31 bit hash, to keep within the limits
+ of the 36^6 mangle space */
+ return value & ~0x80000000;
+}
+
+/*
+ insert an entry into the prefix cache. The string might not be null
+ terminated */
+static void cache_insert(const char *prefix, int length, unsigned int hash)
+{
+ char *str = SMB_STRNDUP(prefix, length);
+
+ if (str == NULL) {
+ return;
+ }
+
+ memcache_add(smbd_memcache(), MANGLE_HASH2_CACHE,
+ data_blob_const(&hash, sizeof(hash)),
+ data_blob_const(str, length+1));
+ SAFE_FREE(str);
+}
+
+/*
+ lookup an entry in the prefix cache. Return NULL if not found.
+*/
+static char *cache_lookup(TALLOC_CTX *mem_ctx, unsigned int hash)
+{
+ DATA_BLOB value;
+
+ if (!memcache_lookup(smbd_memcache(), MANGLE_HASH2_CACHE,
+ data_blob_const(&hash, sizeof(hash)), &value)) {
+ return NULL;
+ }
+
+ SMB_ASSERT((value.length > 0)
+ && (value.data[value.length-1] == '\0'));
+
+ return talloc_strdup(mem_ctx, (char *)value.data);
+}
+
+
+/*
+ determine if a string is possibly in a mangled format, ignoring
+ case
+
+ In this algorithm, mangled names use only pure ascii characters (no
+ multi-byte) so we can avoid doing a UCS2 conversion
+ */
+static bool is_mangled_component(const char *name, size_t len)
+{
+ unsigned int i;
+
+ M_DEBUG(10,("is_mangled_component %s (len %lu) ?\n", name, (unsigned long)len));
+
+ /* check the length */
+ if (len > 12 || len < 8)
+ return False;
+
+ /* the best distinguishing characteristic is the ~ */
+ if (name[6] != '~')
+ return False;
+
+ /* check extension */
+ if (len > 8) {
+ if (name[8] != '.')
+ return False;
+ for (i=9; name[i] && i < len; i++) {
+ if (! FLAG_CHECK(name[i], FLAG_ASCII)) {
+ return False;
+ }
+ }
+ }
+
+ /* check lead characters */
+ for (i=0;i<mangle_prefix;i++) {
+ if (! FLAG_CHECK(name[i], FLAG_ASCII)) {
+ return False;
+ }
+ }
+
+ /* check rest of hash */
+ if (! FLAG_CHECK(name[7], FLAG_BASECHAR)) {
+ return False;
+ }
+ for (i=mangle_prefix;i<6;i++) {
+ if (! FLAG_CHECK(name[i], FLAG_BASECHAR)) {
+ return False;
+ }
+ }
+
+ M_DEBUG(10,("is_mangled_component %s (len %lu) -> yes\n", name, (unsigned long)len));
+
+ return True;
+}
+
+
+
+/*
+ determine if a string is possibly in a mangled format, ignoring
+ case
+
+ In this algorithm, mangled names use only pure ascii characters (no
+ multi-byte) so we can avoid doing a UCS2 conversion
+
+ NOTE! This interface must be able to handle a path with unix
+ directory separators. It should return true if any component is
+ mangled
+ */
+static bool is_mangled(const char *name, const struct share_params *parm)
+{
+ const char *p;
+ const char *s;
+
+ M_DEBUG(10,("is_mangled %s ?\n", name));
+
+ for (s=name; (p=strchr(s, '/')); s=p+1) {
+ if (is_mangled_component(s, PTR_DIFF(p, s))) {
+ return True;
+ }
+ }
+
+ /* and the last part ... */
+ return is_mangled_component(s,strlen(s));
+}
+
+
+/*
+ see if a filename is an allowable 8.3 name.
+
+ we are only going to allow ascii characters in 8.3 names, as this
+ simplifies things greatly (it means that we know the string won't
+ get larger when converted from UNIX to DOS formats)
+*/
+static bool is_8_3(const char *name, bool check_case, bool allow_wildcards, const struct share_params *p)
+{
+ int len, i;
+ char *dot_p;
+
+ /* as a special case, the names '.' and '..' are allowable 8.3 names */
+ if (name[0] == '.') {
+ if (!name[1] || (name[1] == '.' && !name[2])) {
+ return True;
+ }
+ }
+
+ /* the simplest test is on the overall length of the
+ filename. Note that we deliberately use the ascii string
+ length (not the multi-byte one) as it is faster, and gives us
+ the result we need in this case. Using strlen_m would not
+ only be slower, it would be incorrect */
+ len = strlen(name);
+ if (len > 12)
+ return False;
+
+ /* find the '.'. Note that once again we use the non-multibyte
+ function */
+ dot_p = strchr(name, '.');
+
+ if (!dot_p) {
+ /* if the name doesn't contain a '.' then its length
+ must be less than 8 */
+ if (len > 8) {
+ return False;
+ }
+ } else {
+ int prefix_len, suffix_len;
+
+ /* if it does contain a dot then the prefix must be <=
+ 8 and the suffix <= 3 in length */
+ prefix_len = PTR_DIFF(dot_p, name);
+ suffix_len = len - (prefix_len+1);
+
+ if (prefix_len > 8 || suffix_len > 3 || suffix_len == 0) {
+ return False;
+ }
+
+ /* a 8.3 name cannot contain more than 1 '.' */
+ if (strchr(dot_p+1, '.')) {
+ return False;
+ }
+ }
+
+ /* the length are all OK. Now check to see if the characters themselves are OK */
+ for (i=0; name[i]; i++) {
+ /* note that we may allow wildcard petterns! */
+ if (!FLAG_CHECK(name[i], FLAG_ASCII|(allow_wildcards ? FLAG_WILDCARD : 0)) && name[i] != '.') {
+ return False;
+ }
+ }
+
+ /* it is a good 8.3 name */
+ return True;
+}
+
+
+/*
+ reset the mangling cache on a smb.conf reload. This only really makes sense for
+ mangling backends that have parameters in smb.conf, and as this backend doesn't
+ this is a NULL operation
+*/
+static void mangle_reset(void)
+{
+ /* noop */
+}
+
+
+/*
+ try to find a 8.3 name in the cache, and if found then
+ replace the string with the original long name.
+*/
+static bool lookup_name_from_8_3(TALLOC_CTX *ctx,
+ const char *name,
+ char **pp_out, /* talloced on the given context. */
+ const struct share_params *p)
+{
+ unsigned int hash, multiplier;
+ unsigned int i;
+ char *prefix;
+ char extension[4];
+
+ *pp_out = NULL;
+
+ /* make sure that this is a mangled name from this cache */
+ if (!is_mangled(name, p)) {
+ M_DEBUG(10,("lookup_name_from_8_3: %s -> not mangled\n", name));
+ return False;
+ }
+
+ /* we need to extract the hash from the 8.3 name */
+ hash = base_reverse[(unsigned char)name[7]];
+ for (multiplier=36, i=5;i>=mangle_prefix;i--) {
+ unsigned int v = base_reverse[(unsigned char)name[i]];
+ hash += multiplier * v;
+ multiplier *= 36;
+ }
+
+ /* now look in the prefix cache for that hash */
+ prefix = cache_lookup(ctx, hash);
+ if (!prefix) {
+ M_DEBUG(10,("lookup_name_from_8_3: %s -> %08X -> not found\n",
+ name, hash));
+ return False;
+ }
+
+ /* we found it - construct the full name */
+ if (name[8] == '.') {
+ strncpy(extension, name+9, 3);
+ extension[3] = 0;
+ } else {
+ extension[0] = 0;
+ }
+
+ if (extension[0]) {
+ M_DEBUG(10,("lookup_name_from_8_3: %s -> %s.%s\n",
+ name, prefix, extension));
+ *pp_out = talloc_asprintf(ctx, "%s.%s", prefix, extension);
+ } else {
+ M_DEBUG(10,("lookup_name_from_8_3: %s -> %s\n", name, prefix));
+ *pp_out = talloc_strdup(ctx, prefix);
+ }
+
+ TALLOC_FREE(prefix);
+
+ if (!*pp_out) {
+ M_DEBUG(0,("talloc_fail"));
+ return False;
+ }
+
+ return True;
+}
+
+/*
+ look for a DOS reserved name
+*/
+static bool is_reserved_name(const char *name)
+{
+ if (FLAG_CHECK(name[0], FLAG_POSSIBLE1) &&
+ FLAG_CHECK(name[1], FLAG_POSSIBLE2) &&
+ FLAG_CHECK(name[2], FLAG_POSSIBLE3) &&
+ FLAG_CHECK(name[3], FLAG_POSSIBLE4)) {
+ /* a likely match, scan the lot */
+ int i;
+ for (i=0; reserved_names[i]; i++) {
+ int len = strlen(reserved_names[i]);
+ /* note that we match on COM1 as well as COM1.foo */
+ if (strnequal(name, reserved_names[i], len) &&
+ (name[len] == '.' || name[len] == 0)) {
+ return True;
+ }
+ }
+ }
+
+ return False;
+}
+
+/*
+ See if a filename is a legal long filename.
+ A filename ending in a '.' is not legal unless it's "." or "..". JRA.
+ A filename ending in ' ' is not legal either. See bug id #2769.
+*/
+
+static bool is_legal_name(const char *name)
+{
+ const char *dot_pos = NULL;
+ bool alldots = True;
+ size_t numdots = 0;
+
+ while (*name) {
+ if (((unsigned int)name[0]) > 128 && (name[1] != 0)) {
+ /* Possible start of mb character. */
+ char mbc[2];
+ /*
+ * Note that if CH_UNIX is utf8 a string may be 3
+ * bytes, but this is ok as mb utf8 characters don't
+ * contain embedded ascii bytes. We are really checking
+ * for mb UNIX asian characters like Japanese (SJIS) here.
+ * JRA.
+ */
+ if (convert_string(CH_UNIX, CH_UTF16LE, name, 2, mbc, 2, False) == 2) {
+ /* Was a good mb string. */
+ name += 2;
+ continue;
+ }
+ }
+
+ if (FLAG_CHECK(name[0], FLAG_ILLEGAL)) {
+ return False;
+ }
+ if (name[0] == '.') {
+ dot_pos = name;
+ numdots++;
+ } else {
+ alldots = False;
+ }
+ if ((name[0] == ' ') && (name[1] == '\0')) {
+ /* Can't end in ' ' */
+ return False;
+ }
+ name++;
+ }
+
+ if (dot_pos) {
+ if (alldots && (numdots == 1 || numdots == 2))
+ return True; /* . or .. is a valid name */
+
+ /* A valid long name cannot end in '.' */
+ if (dot_pos[1] == '\0')
+ return False;
+ }
+ return True;
+}
+
+static bool must_mangle(const char *name,
+ const struct share_params *p)
+{
+ if (is_reserved_name(name)) {
+ return True;
+ }
+ return !is_legal_name(name);
+}
+
+/*
+ the main forward mapping function, which converts a long filename to
+ a 8.3 name
+
+ if cache83 is not set then we don't cache the result
+
+*/
+static bool hash2_name_to_8_3(const char *name,
+ char new_name[13],
+ bool cache83,
+ int default_case,
+ const struct share_params *p)
+{
+ char *dot_p;
+ char lead_chars[7];
+ char extension[4];
+ unsigned int extension_length, i;
+ unsigned int prefix_len;
+ unsigned int hash, v;
+
+ /* reserved names are handled specially */
+ if (!is_reserved_name(name)) {
+ /* if the name is already a valid 8.3 name then we don't need to
+ * change anything */
+ if (is_legal_name(name) && is_8_3(name, False, False, p)) {
+ safe_strcpy(new_name, name, 12);
+ return True;
+ }
+ }
+
+ /* find the '.' if any */
+ dot_p = strrchr(name, '.');
+
+ if (dot_p) {
+ /* if the extension contains any illegal characters or
+ is too long or zero length then we treat it as part
+ of the prefix */
+ for (i=0; i<4 && dot_p[i+1]; i++) {
+ if (! FLAG_CHECK(dot_p[i+1], FLAG_ASCII)) {
+ dot_p = NULL;
+ break;
+ }
+ }
+ if (i == 0 || i == 4) {
+ dot_p = NULL;
+ }
+ }
+
+ /* the leading characters in the mangled name is taken from
+ the first characters of the name, if they are ascii otherwise
+ '_' is used
+ */
+ for (i=0;i<mangle_prefix && name[i];i++) {
+ lead_chars[i] = name[i];
+ if (! FLAG_CHECK(lead_chars[i], FLAG_ASCII)) {
+ lead_chars[i] = '_';
+ }
+ lead_chars[i] = toupper_ascii(lead_chars[i]);
+ }
+ for (;i<mangle_prefix;i++) {
+ lead_chars[i] = '_';
+ }
+
+ /* the prefix is anything up to the first dot */
+ if (dot_p) {
+ prefix_len = PTR_DIFF(dot_p, name);
+ } else {
+ prefix_len = strlen(name);
+ }
+
+ /* the extension of the mangled name is taken from the first 3
+ ascii chars after the dot */
+ extension_length = 0;
+ if (dot_p) {
+ for (i=1; extension_length < 3 && dot_p[i]; i++) {
+ char c = dot_p[i];
+ if (FLAG_CHECK(c, FLAG_ASCII)) {
+ extension[extension_length++] =
+ toupper_ascii(c);
+ }
+ }
+ }
+
+ /* find the hash for this prefix */
+ v = hash = mangle_hash(name, prefix_len);
+
+ /* now form the mangled name. */
+ for (i=0;i<mangle_prefix;i++) {
+ new_name[i] = lead_chars[i];
+ }
+ new_name[7] = base_forward(v % 36);
+ new_name[6] = '~';
+ for (i=5; i>=mangle_prefix; i--) {
+ v = v / 36;
+ new_name[i] = base_forward(v % 36);
+ }
+
+ /* add the extension */
+ if (extension_length) {
+ new_name[8] = '.';
+ memcpy(&new_name[9], extension, extension_length);
+ new_name[9+extension_length] = 0;
+ } else {
+ new_name[8] = 0;
+ }
+
+ if (cache83) {
+ /* put it in the cache */
+ cache_insert(name, prefix_len, hash);
+ }
+
+ M_DEBUG(10,("hash2_name_to_8_3: %s -> %08X -> %s (cache=%d)\n",
+ name, hash, new_name, cache83));
+
+ return True;
+}
+
+/* initialise the flags table
+
+ we allow only a very restricted set of characters as 'ascii' in this
+ mangling backend. This isn't a significant problem as modern clients
+ use the 'long' filenames anyway, and those don't have these
+ restrictions.
+*/
+static void init_tables(void)
+{
+ int i;
+
+ memset(char_flags, 0, sizeof(char_flags));
+
+ for (i=1;i<128;i++) {
+ if (i <= 0x1f) {
+ /* Control characters. */
+ char_flags[i] |= FLAG_ILLEGAL;
+ }
+
+ if ((i >= '0' && i <= '9') ||
+ (i >= 'a' && i <= 'z') ||
+ (i >= 'A' && i <= 'Z')) {
+ char_flags[i] |= (FLAG_ASCII | FLAG_BASECHAR);
+ }
+ if (strchr("_-$~", i)) {
+ char_flags[i] |= FLAG_ASCII;
+ }
+
+ if (strchr("*\\/?<>|\":", i)) {
+ char_flags[i] |= FLAG_ILLEGAL;
+ }
+
+ if (strchr("*?\"<>", i)) {
+ char_flags[i] |= FLAG_WILDCARD;
+ }
+ }
+
+ memset(base_reverse, 0, sizeof(base_reverse));
+ for (i=0;i<36;i++) {
+ base_reverse[(unsigned char)base_forward(i)] = i;
+ }
+
+ /* fill in the reserved names flags. These are used as a very
+ fast filter for finding possible DOS reserved filenames */
+ for (i=0; reserved_names[i]; i++) {
+ unsigned char c1, c2, c3, c4;
+
+ c1 = (unsigned char)reserved_names[i][0];
+ c2 = (unsigned char)reserved_names[i][1];
+ c3 = (unsigned char)reserved_names[i][2];
+ c4 = (unsigned char)reserved_names[i][3];
+
+ char_flags[c1] |= FLAG_POSSIBLE1;
+ char_flags[c2] |= FLAG_POSSIBLE2;
+ char_flags[c3] |= FLAG_POSSIBLE3;
+ char_flags[c4] |= FLAG_POSSIBLE4;
+ char_flags[tolower_ascii(c1)] |= FLAG_POSSIBLE1;
+ char_flags[tolower_ascii(c2)] |= FLAG_POSSIBLE2;
+ char_flags[tolower_ascii(c3)] |= FLAG_POSSIBLE3;
+ char_flags[tolower_ascii(c4)] |= FLAG_POSSIBLE4;
+
+ char_flags[(unsigned char)'.'] |= FLAG_POSSIBLE4;
+ }
+}
+
+/*
+ the following provides the abstraction layer to make it easier
+ to drop in an alternative mangling implementation */
+static struct mangle_fns mangle_fns = {
+ mangle_reset,
+ is_mangled,
+ must_mangle,
+ is_8_3,
+ lookup_name_from_8_3,
+ hash2_name_to_8_3
+};
+
+/* return the methods for this mangling implementation */
+struct mangle_fns *mangle_hash2_init(void)
+{
+ /* the mangle prefix can only be in the mange 1 to 6 */
+ mangle_prefix = lp_mangle_prefix();
+ if (mangle_prefix > 6) {
+ mangle_prefix = 6;
+ }
+ if (mangle_prefix < 1) {
+ mangle_prefix = 1;
+ }
+
+ init_tables();
+ mangle_reset();
+
+ return &mangle_fns;
+}
+
+static void posix_mangle_reset(void)
+{;}
+
+static bool posix_is_mangled(const char *s, const struct share_params *p)
+{
+ return False;
+}
+
+static bool posix_must_mangle(const char *s, const struct share_params *p)
+{
+ return False;
+}
+
+static bool posix_is_8_3(const char *fname,
+ bool check_case,
+ bool allow_wildcards,
+ const struct share_params *p)
+{
+ return False;
+}
+
+static bool posix_lookup_name_from_8_3(TALLOC_CTX *ctx,
+ const char *in,
+ char **out, /* talloced on the given context. */
+ const struct share_params *p)
+{
+ return False;
+}
+
+static bool posix_name_to_8_3(const char *in,
+ char out[13],
+ bool cache83,
+ int default_case,
+ const struct share_params *p)
+{
+ memset(out, '\0', 13);
+ return True;
+}
+
+/* POSIX paths backend - no mangle. */
+static struct mangle_fns posix_mangle_fns = {
+ posix_mangle_reset,
+ posix_is_mangled,
+ posix_must_mangle,
+ posix_is_8_3,
+ posix_lookup_name_from_8_3,
+ posix_name_to_8_3
+};
+
+struct mangle_fns *posix_mangle_init(void)
+{
+ return &posix_mangle_fns;
+}
diff --git a/source3/smbd/map_username.c b/source3/smbd/map_username.c
new file mode 100644
index 0000000000..7536758bcb
--- /dev/null
+++ b/source3/smbd/map_username.c
@@ -0,0 +1,215 @@
+/*
+ Unix SMB/CIFS implementation.
+ Username handling
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1997-2001.
+ Copyright (C) Volker Lendecke 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*******************************************************************
+ Map a username from a dos name to a unix name by looking in the username
+ map. Note that this modifies the name in place.
+ This is the main function that should be called *once* on
+ any incoming or new username - in order to canonicalize the name.
+ This is being done to de-couple the case conversions from the user mapping
+ function. Previously, the map_username was being called
+ every time Get_Pwnam_alloc was called.
+ Returns True if username was changed, false otherwise.
+********************************************************************/
+
+static char *last_from, *last_to;
+
+static const char *get_last_from(void)
+{
+ if (!last_from) {
+ return "";
+ }
+ return last_from;
+}
+
+static const char *get_last_to(void)
+{
+ if (!last_to) {
+ return "";
+ }
+ return last_to;
+}
+
+static bool set_last_from_to(const char *from, const char *to)
+{
+ char *orig_from = last_from;
+ char *orig_to = last_to;
+
+ last_from = SMB_STRDUP(from);
+ last_to = SMB_STRDUP(to);
+
+ SAFE_FREE(orig_from);
+ SAFE_FREE(orig_to);
+
+ if (!last_from || !last_to) {
+ SAFE_FREE(last_from);
+ SAFE_FREE(last_to);
+ return false;
+ }
+ return true;
+}
+
+bool map_username(fstring user)
+{
+ XFILE *f;
+ char *mapfile = lp_username_map();
+ char *s;
+ char buf[512];
+ bool mapped_user = False;
+ char *cmd = lp_username_map_script();
+
+ if (!*user)
+ return false;
+
+ if (strequal(user,get_last_to()))
+ return false;
+
+ if (strequal(user,get_last_from())) {
+ DEBUG(3,("Mapped user %s to %s\n",user,get_last_to()));
+ fstrcpy(user,get_last_to());
+ return true;
+ }
+
+ /* first try the username map script */
+
+ if ( *cmd ) {
+ char **qlines;
+ char *command = NULL;
+ int numlines, ret, fd;
+
+ command = talloc_asprintf(talloc_tos(),
+ "%s \"%s\"",
+ cmd,
+ user);
+ if (!command) {
+ return false;
+ }
+
+ DEBUG(10,("Running [%s]\n", command));
+ ret = smbrun(command, &fd);
+ DEBUGADD(10,("returned [%d]\n", ret));
+
+ if ( ret != 0 ) {
+ if (fd != -1)
+ close(fd);
+ return False;
+ }
+
+ numlines = 0;
+ qlines = fd_lines_load(fd, &numlines,0);
+ DEBUGADD(10,("Lines returned = [%d]\n", numlines));
+ close(fd);
+
+ /* should be either no lines or a single line with the mapped username */
+
+ if (numlines && qlines) {
+ DEBUG(3,("Mapped user %s to %s\n", user, qlines[0] ));
+ fstrcpy( user, qlines[0] );
+ }
+
+ file_lines_free(qlines);
+
+ return numlines != 0;
+ }
+
+ /* ok. let's try the mapfile */
+ if (!*mapfile)
+ return False;
+
+ f = x_fopen(mapfile,O_RDONLY, 0);
+ if (!f) {
+ DEBUG(0,("can't open username map %s. Error %s\n",mapfile, strerror(errno) ));
+ return False;
+ }
+
+ DEBUG(4,("Scanning username map %s\n",mapfile));
+
+ while((s=fgets_slash(buf,sizeof(buf),f))!=NULL) {
+ char *unixname = s;
+ char *dosname = strchr_m(unixname,'=');
+ char **dosuserlist;
+ bool return_if_mapped = False;
+
+ if (!dosname)
+ continue;
+
+ *dosname++ = 0;
+
+ while (isspace((int)*unixname))
+ unixname++;
+
+ if ('!' == *unixname) {
+ return_if_mapped = True;
+ unixname++;
+ while (*unixname && isspace((int)*unixname))
+ unixname++;
+ }
+
+ if (!*unixname || strchr_m("#;",*unixname))
+ continue;
+
+ {
+ int l = strlen(unixname);
+ while (l && isspace((int)unixname[l-1])) {
+ unixname[l-1] = 0;
+ l--;
+ }
+ }
+
+ /* skip lines like 'user = ' */
+
+ dosuserlist = str_list_make(talloc_tos(), dosname, NULL);
+ if (!dosuserlist) {
+ DEBUG(0,("Bad username map entry. Unable to build user list. Ignoring.\n"));
+ continue;
+ }
+
+ if (strchr_m(dosname,'*') ||
+ user_in_list(user, (const char **)dosuserlist)) {
+ DEBUG(3,("Mapped user %s to %s\n",user,unixname));
+ mapped_user = True;
+
+ set_last_from_to(user, unixname);
+ fstrcpy( user, unixname );
+
+ if ( return_if_mapped ) {
+ TALLOC_FREE(dosuserlist);
+ x_fclose(f);
+ return True;
+ }
+ }
+
+ TALLOC_FREE(dosuserlist);
+ }
+
+ x_fclose(f);
+
+ /*
+ * Setup the last_from and last_to as an optimization so
+ * that we don't scan the file again for the same user.
+ */
+
+ set_last_from_to(user, user);
+
+ return mapped_user;
+}
diff --git a/source3/smbd/message.c b/source3/smbd/message.c
new file mode 100644
index 0000000000..62df5c37eb
--- /dev/null
+++ b/source3/smbd/message.c
@@ -0,0 +1,309 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB messaging
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ This file handles the messaging system calls for winpopup style
+ messages
+*/
+
+
+#include "includes.h"
+
+extern userdom_struct current_user_info;
+
+struct msg_state {
+ char *from;
+ char *to;
+ char *msg;
+};
+
+static struct msg_state *smbd_msg_state;
+
+/****************************************************************************
+ Deliver the message.
+****************************************************************************/
+
+static void msg_deliver(struct msg_state *state)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *name = NULL;
+ int i;
+ int fd;
+ char *msg;
+ size_t len;
+ ssize_t sz;
+ fstring alpha_buf;
+ char *s;
+
+ if (! (*lp_msg_command())) {
+ DEBUG(1,("no messaging command specified\n"));
+ goto done;
+ }
+
+ /* put it in a temporary file */
+ name = talloc_asprintf(talloc_tos(), "%s/msg.XXXXXX", tmpdir());
+ if (!name) {
+ goto done;
+ }
+ fd = smb_mkstemp(name);
+
+ if (fd == -1) {
+ DEBUG(1, ("can't open message file %s: %s\n", name,
+ strerror(errno)));
+ goto done;
+ }
+
+ /*
+ * Incoming message is in DOS codepage format. Convert to UNIX.
+ */
+
+ if (!convert_string_talloc(talloc_tos(), CH_DOS, CH_UNIX, state->msg,
+ talloc_get_size(state->msg), (void *)&msg,
+ &len, true)) {
+ DEBUG(3, ("Conversion failed, delivering message in DOS "
+ "codepage format\n"));
+ msg = state->msg;
+ }
+
+ for (i = 0; i < len; i++) {
+ if ((msg[i] == '\r') &&
+ (i < (len-1)) && (msg[i+1] == '\n')) {
+ continue;
+ }
+ sz = write(fd, &msg[i], 1);
+ if ( sz != 1 ) {
+ DEBUG(0, ("Write error to fd %d: %ld(%s)\n", fd,
+ (long)sz, strerror(errno)));
+ }
+ }
+
+ close(fd);
+
+ /* run the command */
+ s = talloc_strdup(talloc_tos(), lp_msg_command());
+ if (s == NULL) {
+ goto done;
+ }
+
+ alpha_strcpy(alpha_buf, state->from, NULL, sizeof(alpha_buf));
+
+ s = talloc_string_sub(talloc_tos(), s, "%f", alpha_buf);
+ if (s == NULL) {
+ goto done;
+ }
+
+ alpha_strcpy(alpha_buf, state->to, NULL, sizeof(alpha_buf));
+
+ s = talloc_string_sub(talloc_tos(), s, "%t", alpha_buf);
+ if (s == NULL) {
+ goto done;
+ }
+
+ s = talloc_sub_basic(talloc_tos(), current_user_info.smb_name,
+ current_user_info.domain, s);
+ if (s == NULL) {
+ goto done;
+ }
+
+ s = talloc_string_sub(talloc_tos(), s, "%s", name);
+ if (s == NULL) {
+ goto done;
+ }
+ smbrun(s,NULL);
+
+ done:
+ TALLOC_FREE(frame);
+ return;
+}
+
+/****************************************************************************
+ Reply to a sends.
+ conn POINTER CAN BE NULL HERE !
+****************************************************************************/
+
+void reply_sends(struct smb_request *req)
+{
+ struct msg_state *state;
+ int len;
+ char *msg;
+ char *p;
+
+ START_PROFILE(SMBsends);
+
+ if (!(*lp_msg_command())) {
+ reply_doserror(req, ERRSRV, ERRmsgoff);
+ END_PROFILE(SMBsends);
+ return;
+ }
+
+ state = talloc(talloc_tos(), struct msg_state);
+
+ p = smb_buf(req->inbuf)+1;
+ p += srvstr_pull_buf_talloc(
+ state, (char *)req->inbuf, req->flags2, &state->from, p,
+ STR_ASCII|STR_TERMINATE) + 1;
+ p += srvstr_pull_buf_talloc(
+ state, (char *)req->inbuf, req->flags2, &state->to, p,
+ STR_ASCII|STR_TERMINATE) + 1;
+
+ msg = p;
+
+ len = SVAL(msg,0);
+ len = MIN(len, smb_bufrem(req->inbuf, msg+2));
+
+ state->msg = talloc_array(state, char, len);
+
+ if (state->msg == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBsends);
+ return;
+ }
+
+ memcpy(state->msg, msg+2, len);
+
+ msg_deliver(state);
+
+ reply_outbuf(req, 0, 0);
+
+ END_PROFILE(SMBsends);
+ return;
+}
+
+/****************************************************************************
+ Reply to a sendstrt.
+ conn POINTER CAN BE NULL HERE !
+****************************************************************************/
+
+void reply_sendstrt(struct smb_request *req)
+{
+ char *p;
+
+ START_PROFILE(SMBsendstrt);
+
+ if (!(*lp_msg_command())) {
+ reply_doserror(req, ERRSRV, ERRmsgoff);
+ END_PROFILE(SMBsendstrt);
+ return;
+ }
+
+ TALLOC_FREE(smbd_msg_state);
+
+ smbd_msg_state = TALLOC_ZERO_P(NULL, struct msg_state);
+
+ if (smbd_msg_state == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBsendstrt);
+ return;
+ }
+
+ p = smb_buf(req->inbuf)+1;
+ p += srvstr_pull_buf_talloc(
+ smbd_msg_state, (char *)req->inbuf, req->flags2,
+ &smbd_msg_state->from, p, STR_ASCII|STR_TERMINATE) + 1;
+ p += srvstr_pull_buf_talloc(
+ smbd_msg_state, (char *)req->inbuf, req->flags2,
+ &smbd_msg_state->to, p, STR_ASCII|STR_TERMINATE) + 1;
+
+ DEBUG( 3, ( "SMBsendstrt (from %s to %s)\n", smbd_msg_state->from,
+ smbd_msg_state->to ) );
+
+ reply_outbuf(req, 0, 0);
+
+ END_PROFILE(SMBsendstrt);
+ return;
+}
+
+/****************************************************************************
+ Reply to a sendtxt.
+ conn POINTER CAN BE NULL HERE !
+****************************************************************************/
+
+void reply_sendtxt(struct smb_request *req)
+{
+ int len;
+ char *msg;
+ char *tmp;
+ size_t old_len;
+
+ START_PROFILE(SMBsendtxt);
+
+ if (! (*lp_msg_command())) {
+ reply_doserror(req, ERRSRV, ERRmsgoff);
+ END_PROFILE(SMBsendtxt);
+ return;
+ }
+
+ if (smbd_msg_state == NULL) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBsendtxt);
+ return;
+ }
+
+ msg = smb_buf(req->inbuf) + 1;
+
+ old_len = talloc_get_size(smbd_msg_state->msg);
+
+ len = MIN(SVAL(msg, 0), smb_bufrem(req->inbuf, msg+2));
+
+ tmp = TALLOC_REALLOC_ARRAY(smbd_msg_state, smbd_msg_state->msg,
+ char, old_len + len);
+
+ if (tmp == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBsendtxt);
+ return;
+ }
+
+ smbd_msg_state->msg = tmp;
+
+ memcpy(&smbd_msg_state->msg[old_len], msg+2, len);
+
+ DEBUG( 3, ( "SMBsendtxt\n" ) );
+
+ reply_outbuf(req, 0, 0);
+
+ END_PROFILE(SMBsendtxt);
+ return;
+}
+
+/****************************************************************************
+ Reply to a sendend.
+ conn POINTER CAN BE NULL HERE !
+****************************************************************************/
+
+void reply_sendend(struct smb_request *req)
+{
+ START_PROFILE(SMBsendend);
+
+ if (! (*lp_msg_command())) {
+ reply_doserror(req, ERRSRV, ERRmsgoff);
+ END_PROFILE(SMBsendend);
+ return;
+ }
+
+ DEBUG(3,("SMBsendend\n"));
+
+ msg_deliver(smbd_msg_state);
+
+ TALLOC_FREE(smbd_msg_state);
+
+ reply_outbuf(req, 0, 0);
+
+ END_PROFILE(SMBsendend);
+ return;
+}
diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c
new file mode 100644
index 0000000000..32240ff0d5
--- /dev/null
+++ b/source3/smbd/msdfs.c
@@ -0,0 +1,1724 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ MSDFS services for Samba
+ Copyright (C) Shirish Kalele 2000
+ Copyright (C) Jeremy Allison 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#define DBGC_CLASS DBGC_MSDFS
+#include "includes.h"
+
+extern uint32 global_client_caps;
+
+/**********************************************************************
+ Parse a DFS pathname of the form \hostname\service\reqpath
+ into the dfs_path structure.
+ If POSIX pathnames is true, the pathname may also be of the
+ form /hostname/service/reqpath.
+ We cope with either here.
+
+ Unfortunately, due to broken clients who might set the
+ SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
+ send a local path, we have to cope with that too....
+
+ If conn != NULL then ensure the provided service is
+ the one pointed to by the connection.
+
+ This version does everything using pointers within one copy of the
+ pathname string, talloced on the struct dfs_path pointer (which
+ must be talloced). This may be too clever to live....
+ JRA.
+**********************************************************************/
+
+static NTSTATUS parse_dfs_path(connection_struct *conn,
+ const char *pathname,
+ bool allow_wcards,
+ struct dfs_path *pdp, /* MUST BE TALLOCED */
+ bool *ppath_contains_wcard)
+{
+ char *pathname_local;
+ char *p,*temp;
+ char *servicename;
+ char *eos_ptr;
+ NTSTATUS status = NT_STATUS_OK;
+ char sepchar;
+
+ ZERO_STRUCTP(pdp);
+
+ /*
+ * This is the only talloc we should need to do
+ * on the struct dfs_path. All the pointers inside
+ * it should point to offsets within this string.
+ */
+
+ pathname_local = talloc_strdup(pdp, pathname);
+ if (!pathname_local) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ /* Get a pointer to the terminating '\0' */
+ eos_ptr = &pathname_local[strlen(pathname_local)];
+ p = temp = pathname_local;
+
+ pdp->posix_path = (lp_posix_pathnames() && *pathname == '/');
+
+ sepchar = pdp->posix_path ? '/' : '\\';
+
+ if (*pathname != sepchar) {
+ DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
+ pathname, sepchar ));
+ /*
+ * Possibly client sent a local path by mistake.
+ * Try and convert to a local path.
+ */
+
+ pdp->hostname = eos_ptr; /* "" */
+ pdp->servicename = eos_ptr; /* "" */
+
+ /* We've got no info about separators. */
+ pdp->posix_path = lp_posix_pathnames();
+ p = temp;
+ DEBUG(10,("parse_dfs_path: trying to convert %s to a "
+ "local path\n",
+ temp));
+ goto local_path;
+ }
+
+ /*
+ * Safe to use on talloc'ed string as it only shrinks.
+ * It also doesn't affect the eos_ptr.
+ */
+ trim_char(temp,sepchar,sepchar);
+
+ DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
+ temp, sepchar));
+
+ /* Now tokenize. */
+ /* Parse out hostname. */
+ p = strchr_m(temp,sepchar);
+ if(p == NULL) {
+ DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
+ temp));
+ /*
+ * Possibly client sent a local path by mistake.
+ * Try and convert to a local path.
+ */
+
+ pdp->hostname = eos_ptr; /* "" */
+ pdp->servicename = eos_ptr; /* "" */
+
+ p = temp;
+ DEBUG(10,("parse_dfs_path: trying to convert %s "
+ "to a local path\n",
+ temp));
+ goto local_path;
+ }
+ *p = '\0';
+ pdp->hostname = temp;
+
+ DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
+
+ /* Parse out servicename. */
+ servicename = p+1;
+ p = strchr_m(servicename,sepchar);
+ if (p) {
+ *p = '\0';
+ }
+
+ /* Is this really our servicename ? */
+ if (conn && !( strequal(servicename, lp_servicename(SNUM(conn)))
+ || (strequal(servicename, HOMES_NAME)
+ && strequal(lp_servicename(SNUM(conn)),
+ get_current_username()) )) ) {
+ DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
+ servicename));
+
+ /*
+ * Possibly client sent a local path by mistake.
+ * Try and convert to a local path.
+ */
+
+ pdp->hostname = eos_ptr; /* "" */
+ pdp->servicename = eos_ptr; /* "" */
+
+ /* Repair the path - replace the sepchar's
+ we nulled out */
+ servicename--;
+ *servicename = sepchar;
+ if (p) {
+ *p = sepchar;
+ }
+
+ p = temp;
+ DEBUG(10,("parse_dfs_path: trying to convert %s "
+ "to a local path\n",
+ temp));
+ goto local_path;
+ }
+
+ pdp->servicename = servicename;
+
+ DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
+
+ if(p == NULL) {
+ /* Client sent self referral \server\share. */
+ pdp->reqpath = eos_ptr; /* "" */
+ return NT_STATUS_OK;
+ }
+
+ p++;
+
+ local_path:
+
+ *ppath_contains_wcard = False;
+
+ pdp->reqpath = p;
+
+ /* Rest is reqpath. */
+ if (pdp->posix_path) {
+ status = check_path_syntax_posix(pdp->reqpath);
+ } else {
+ if (allow_wcards) {
+ status = check_path_syntax_wcard(pdp->reqpath,
+ ppath_contains_wcard);
+ } else {
+ status = check_path_syntax(pdp->reqpath);
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
+ p, nt_errstr(status) ));
+ return status;
+ }
+
+ DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
+ return NT_STATUS_OK;
+}
+
+/********************************************************
+ Fake up a connection struct for the VFS layer.
+ Note this CHANGES CWD !!!! JRA.
+*********************************************************/
+
+NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
+ connection_struct **pconn,
+ int snum,
+ const char *path,
+ char **poldcwd)
+{
+ connection_struct *conn;
+ char *connpath;
+ char *oldcwd;
+
+ conn = TALLOC_ZERO_P(ctx, connection_struct);
+ if (conn == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ connpath = talloc_strdup(conn, path);
+ if (!connpath) {
+ TALLOC_FREE(conn);
+ return NT_STATUS_NO_MEMORY;
+ }
+ connpath = talloc_string_sub(conn,
+ connpath,
+ "%S",
+ lp_servicename(snum));
+ if (!connpath) {
+ TALLOC_FREE(conn);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* needed for smbd_vfs_init() */
+
+ if (!(conn->params = TALLOC_ZERO_P(conn, struct share_params))) {
+ DEBUG(0, ("TALLOC failed\n"));
+ TALLOC_FREE(conn);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ conn->params->service = snum;
+
+ set_conn_connectpath(conn, connpath);
+
+ if (!smbd_vfs_init(conn)) {
+ NTSTATUS status = map_nt_error_from_unix(errno);
+ DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
+ conn_free_internal(conn);
+ return status;
+ }
+
+ /*
+ * Windows seems to insist on doing trans2getdfsreferral() calls on
+ * the IPC$ share as the anonymous user. If we try to chdir as that
+ * user we will fail.... WTF ? JRA.
+ */
+
+ oldcwd = vfs_GetWd(ctx, conn);
+ if (oldcwd == NULL) {
+ NTSTATUS status = map_nt_error_from_unix(errno);
+ DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
+ conn_free_internal(conn);
+ return status;
+ }
+
+ if (vfs_ChDir(conn,conn->connectpath) != 0) {
+ NTSTATUS status = map_nt_error_from_unix(errno);
+ DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
+ "Error was %s\n",
+ conn->connectpath, strerror(errno) ));
+ conn_free_internal(conn);
+ return status;
+ }
+
+ *pconn = conn;
+ *poldcwd = oldcwd;
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Parse the contents of a symlink to verify if it is an msdfs referral
+ A valid referral is of the form:
+
+ msdfs:server1\share1,server2\share2
+ msdfs:server1\share1\pathname,server2\share2\pathname
+ msdfs:server1/share1,server2/share2
+ msdfs:server1/share1/pathname,server2/share2/pathname.
+
+ Note that the alternate paths returned here must be of the canonicalized
+ form:
+
+ \server\share or
+ \server\share\path\to\file,
+
+ even in posix path mode. This is because we have no knowledge if the
+ server we're referring to understands posix paths.
+ **********************************************************************/
+
+static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
+ const char *target,
+ struct referral **preflist,
+ int *refcount)
+{
+ char *temp = NULL;
+ char *prot;
+ char **alt_path = NULL;
+ int count = 0, i;
+ struct referral *reflist;
+ char *saveptr;
+
+ temp = talloc_strdup(ctx, target);
+ if (!temp) {
+ return False;
+ }
+ prot = strtok_r(temp, ":", &saveptr);
+ if (!prot) {
+ DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
+ return False;
+ }
+
+ alt_path = TALLOC_ARRAY(ctx, char *, MAX_REFERRAL_COUNT);
+ if (!alt_path) {
+ return False;
+ }
+
+ /* parse out the alternate paths */
+ while((count<MAX_REFERRAL_COUNT) &&
+ ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
+ count++;
+ }
+
+ DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
+
+ if (count) {
+ reflist = *preflist = TALLOC_ZERO_ARRAY(ctx,
+ struct referral, count);
+ if(reflist == NULL) {
+ TALLOC_FREE(alt_path);
+ return False;
+ }
+ } else {
+ reflist = *preflist = NULL;
+ }
+
+ for(i=0;i<count;i++) {
+ char *p;
+
+ /* Canonicalize link target.
+ * Replace all /'s in the path by a \ */
+ string_replace(alt_path[i], '/', '\\');
+
+ /* Remove leading '\\'s */
+ p = alt_path[i];
+ while (*p && (*p == '\\')) {
+ p++;
+ }
+
+ reflist[i].alternate_path = talloc_asprintf(ctx,
+ "\\%s",
+ p);
+ if (!reflist[i].alternate_path) {
+ return False;
+ }
+
+ reflist[i].proximity = 0;
+ reflist[i].ttl = REFERRAL_TTL;
+ DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
+ reflist[i].alternate_path));
+ }
+
+ *refcount = count;
+
+ TALLOC_FREE(alt_path);
+ return True;
+}
+
+/**********************************************************************
+ Returns true if the unix path is a valid msdfs symlink and also
+ returns the target string from inside the link.
+**********************************************************************/
+
+static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ const char *path,
+ char **pp_link_target,
+ SMB_STRUCT_STAT *sbufp)
+{
+ SMB_STRUCT_STAT st;
+ int referral_len = 0;
+ char link_target_buf[7];
+ size_t bufsize = 0;
+ char *link_target = NULL;
+
+ if (pp_link_target) {
+ bufsize = 1024;
+ link_target = TALLOC_ARRAY(ctx, char, bufsize);
+ if (!link_target) {
+ return False;
+ }
+ *pp_link_target = link_target;
+ } else {
+ bufsize = sizeof(link_target_buf);
+ link_target = link_target_buf;
+ }
+
+ if (sbufp == NULL) {
+ sbufp = &st;
+ }
+
+ if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
+ DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
+ path));
+ goto err;
+ }
+
+ if (!S_ISLNK(sbufp->st_mode)) {
+ DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
+ path));
+ goto err;
+ }
+
+ referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
+ if (referral_len == -1) {
+ DEBUG(0,("is_msdfs_link_read_target: Error reading "
+ "msdfs link %s: %s\n",
+ path, strerror(errno)));
+ goto err;
+ }
+ link_target[referral_len] = '\0';
+
+ DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
+ link_target));
+
+ if (!strnequal(link_target, "msdfs:", 6)) {
+ goto err;
+ }
+ return True;
+
+ err:
+
+ if (link_target != link_target_buf) {
+ TALLOC_FREE(link_target);
+ }
+ return False;
+}
+
+/**********************************************************************
+ Returns true if the unix path is a valid msdfs symlink.
+**********************************************************************/
+
+bool is_msdfs_link(connection_struct *conn,
+ const char *path,
+ SMB_STRUCT_STAT *sbufp)
+{
+ return is_msdfs_link_internal(talloc_tos(),
+ conn,
+ path,
+ NULL,
+ sbufp);
+}
+
+/*****************************************************************
+ Used by other functions to decide if a dfs path is remote,
+ and to get the list of referred locations for that remote path.
+
+ search_flag: For findfirsts, dfs links themselves are not
+ redirected, but paths beyond the links are. For normal smb calls,
+ even dfs links need to be redirected.
+
+ consumedcntp: how much of the dfs path is being redirected. the client
+ should try the remaining path on the redirected server.
+
+ If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
+ link redirect are in targetpath.
+*****************************************************************/
+
+static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ const char *dfspath, /* Incoming complete dfs path */
+ const struct dfs_path *pdp, /* Parsed out
+ server+share+extrapath. */
+ bool search_flag, /* Called from a findfirst ? */
+ int *consumedcntp,
+ char **pp_targetpath)
+{
+ char *p = NULL;
+ char *q = NULL;
+ SMB_STRUCT_STAT sbuf;
+ NTSTATUS status;
+ char *localpath = NULL;
+ char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
+ components). */
+
+ DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
+ conn->connectpath, pdp->reqpath));
+
+ /*
+ * Note the unix path conversion here we're doing we can
+ * throw away. We're looking for a symlink for a dfs
+ * resolution, if we don't find it we'll do another
+ * unix_convert later in the codepath.
+ * If we needed to remember what we'd resolved in
+ * dp->reqpath (as the original code did) we'd
+ * copy (localhost, dp->reqpath) on any code
+ * path below that returns True - but I don't
+ * think this is needed. JRA.
+ */
+
+ status = unix_convert(ctx, conn, pdp->reqpath, search_flag, &localpath,
+ NULL, &sbuf);
+ if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
+ NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
+ return status;
+ }
+
+ /* Optimization - check if we can redirect the whole path. */
+
+ if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) {
+ if (search_flag) {
+ DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
+ "for dfs link %s.\n", dfspath));
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(6,("dfs_path_lookup: %s resolves to a "
+ "valid dfs link %s.\n", dfspath,
+ pp_targetpath ? *pp_targetpath : ""));
+
+ if (consumedcntp) {
+ *consumedcntp = strlen(dfspath);
+ }
+ return NT_STATUS_PATH_NOT_COVERED;
+ }
+
+ /* Prepare to test only for '/' components in the given path,
+ * so if a Windows path replace all '\\' characters with '/'.
+ * For a POSIX DFS path we know all separators are already '/'. */
+
+ canon_dfspath = talloc_strdup(ctx, dfspath);
+ if (!canon_dfspath) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (!pdp->posix_path) {
+ string_replace(canon_dfspath, '\\', '/');
+ }
+
+ /*
+ * localpath comes out of unix_convert, so it has
+ * no trailing backslash. Make sure that canon_dfspath hasn't either.
+ * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
+ */
+
+ trim_char(canon_dfspath,0,'/');
+
+ /*
+ * Redirect if any component in the path is a link.
+ * We do this by walking backwards through the
+ * local path, chopping off the last component
+ * in both the local path and the canonicalized
+ * DFS path. If we hit a DFS link then we're done.
+ */
+
+ p = strrchr_m(localpath, '/');
+ if (consumedcntp) {
+ q = strrchr_m(canon_dfspath, '/');
+ }
+
+ while (p) {
+ *p = '\0';
+ if (q) {
+ *q = '\0';
+ }
+
+ if (is_msdfs_link_internal(ctx, conn,
+ localpath, pp_targetpath, NULL)) {
+ DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
+ "parent %s is dfs link\n", dfspath, localpath));
+
+ if (consumedcntp) {
+ *consumedcntp = strlen(canon_dfspath);
+ DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
+ "(%d)\n",
+ canon_dfspath,
+ *consumedcntp));
+ }
+
+ return NT_STATUS_PATH_NOT_COVERED;
+ }
+
+ /* Step back on the filesystem. */
+ p = strrchr_m(localpath, '/');
+
+ if (consumedcntp) {
+ /* And in the canonicalized dfs path. */
+ q = strrchr_m(canon_dfspath, '/');
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*****************************************************************
+ Decides if a dfs pathname should be redirected or not.
+ If not, the pathname is converted to a tcon-relative local unix path
+
+ search_wcard_flag: this flag performs 2 functions both related
+ to searches. See resolve_dfs_path() and parse_dfs_path_XX()
+ for details.
+
+ This function can return NT_STATUS_OK, meaning use the returned path as-is
+ (mapped into a local path).
+ or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
+ any other NT_STATUS error which is a genuine error to be
+ returned to the client.
+*****************************************************************/
+
+static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ const char *path_in,
+ bool search_wcard_flag,
+ char **pp_path_out,
+ bool *ppath_contains_wcard)
+{
+ NTSTATUS status;
+ struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
+
+ if (!pdp) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = parse_dfs_path(conn, path_in, search_wcard_flag, pdp,
+ ppath_contains_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(pdp);
+ return status;
+ }
+
+ if (pdp->reqpath[0] == '\0') {
+ TALLOC_FREE(pdp);
+ *pp_path_out = talloc_strdup(ctx, "");
+ if (!*pp_path_out) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ DEBUG(5,("dfs_redirect: self-referral.\n"));
+ return NT_STATUS_OK;
+ }
+
+ /* If dfs pathname for a non-dfs share, convert to tcon-relative
+ path and return OK */
+
+ if (!lp_msdfs_root(SNUM(conn))) {
+ *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
+ TALLOC_FREE(pdp);
+ if (!*pp_path_out) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+ }
+
+ /* If it looked like a local path (zero hostname/servicename)
+ * just treat as a tcon-relative path. */
+
+ if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
+ *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
+ TALLOC_FREE(pdp);
+ if (!*pp_path_out) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+ }
+
+ if (!( strequal(pdp->servicename, lp_servicename(SNUM(conn)))
+ || (strequal(pdp->servicename, HOMES_NAME)
+ && strequal(lp_servicename(SNUM(conn)),
+ conn->server_info->sanitized_username) )) ) {
+
+ /* The given sharename doesn't match this connection. */
+ TALLOC_FREE(pdp);
+
+ return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+
+ status = dfs_path_lookup(ctx, conn, path_in, pdp,
+ search_wcard_flag, NULL, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
+ DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
+ } else {
+ DEBUG(10,("dfs_redirect: dfs_path_lookup "
+ "failed for %s with %s\n",
+ path_in, nt_errstr(status) ));
+ }
+ return status;
+ }
+
+ DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
+
+ /* Form non-dfs tcon-relative path */
+ *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
+ TALLOC_FREE(pdp);
+ if (!*pp_path_out) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
+ path_in,
+ *pp_path_out));
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Return a self referral.
+**********************************************************************/
+
+static NTSTATUS self_ref(TALLOC_CTX *ctx,
+ const char *dfs_path,
+ struct junction_map *jucn,
+ int *consumedcntp,
+ bool *self_referralp)
+{
+ struct referral *ref;
+
+ *self_referralp = True;
+
+ jucn->referral_count = 1;
+ if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ref->alternate_path = talloc_strdup(ctx, dfs_path);
+ if (!ref->alternate_path) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ ref->proximity = 0;
+ ref->ttl = REFERRAL_TTL;
+ jucn->referral_list = ref;
+ *consumedcntp = strlen(dfs_path);
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Gets valid referrals for a dfs path and fills up the
+ junction_map structure.
+**********************************************************************/
+
+NTSTATUS get_referred_path(TALLOC_CTX *ctx,
+ const char *dfs_path,
+ struct junction_map *jucn,
+ int *consumedcntp,
+ bool *self_referralp)
+{
+ struct connection_struct *conn;
+ char *targetpath = NULL;
+ int snum;
+ NTSTATUS status = NT_STATUS_NOT_FOUND;
+ bool dummy;
+ struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
+ char *oldpath;
+
+ if (!pdp) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *self_referralp = False;
+
+ status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ jucn->service_name = talloc_strdup(ctx, pdp->servicename);
+ jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
+ if (!jucn->service_name || !jucn->volume_name) {
+ TALLOC_FREE(pdp);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Verify the share is a dfs root */
+ snum = lp_servicenumber(jucn->service_name);
+ if(snum < 0) {
+ fstring service_name;
+ fstrcpy(service_name, jucn->service_name);
+ if ((snum = find_service(service_name)) < 0) {
+ return NT_STATUS_NOT_FOUND;
+ }
+ TALLOC_FREE(jucn->service_name);
+ jucn->service_name = talloc_strdup(ctx, service_name);
+ if (!jucn->service_name) {
+ TALLOC_FREE(pdp);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(snum) == '\0')) {
+ DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
+ "a dfs root.\n",
+ pdp->servicename, dfs_path));
+ TALLOC_FREE(pdp);
+ return NT_STATUS_NOT_FOUND;
+ }
+
+ /*
+ * Self referrals are tested with a anonymous IPC connection and
+ * a GET_DFS_REFERRAL call to \\server\share. (which means
+ * dp.reqpath[0] points to an empty string). create_conn_struct cd's
+ * into the directory and will fail if it cannot (as the anonymous
+ * user). Cope with this.
+ */
+
+ if (pdp->reqpath[0] == '\0') {
+ char *tmp;
+ struct referral *ref;
+
+ if (*lp_msdfs_proxy(snum) == '\0') {
+ TALLOC_FREE(pdp);
+ return self_ref(ctx,
+ dfs_path,
+ jucn,
+ consumedcntp,
+ self_referralp);
+ }
+
+ /*
+ * It's an msdfs proxy share. Redirect to
+ * the configured target share.
+ */
+
+ jucn->referral_count = 1;
+ if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
+ TALLOC_FREE(pdp);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(snum)))) {
+ TALLOC_FREE(pdp);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ trim_string(tmp, "\\", 0);
+
+ ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
+ TALLOC_FREE(tmp);
+
+ if (!ref->alternate_path) {
+ TALLOC_FREE(pdp);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (pdp->reqpath[0] != '\0') {
+ ref->alternate_path = talloc_asprintf_append(
+ ref->alternate_path,
+ "%s",
+ pdp->reqpath);
+ if (!ref->alternate_path) {
+ TALLOC_FREE(pdp);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ ref->proximity = 0;
+ ref->ttl = REFERRAL_TTL;
+ jucn->referral_list = ref;
+ *consumedcntp = strlen(dfs_path);
+ TALLOC_FREE(pdp);
+ return NT_STATUS_OK;
+ }
+
+ status = create_conn_struct(ctx, &conn, snum, lp_pathname(snum),
+ &oldpath);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(pdp);
+ return status;
+ }
+
+ /* If this is a DFS path dfs_lookup should return
+ * NT_STATUS_PATH_NOT_COVERED. */
+
+ status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
+ False, consumedcntp, &targetpath);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
+ DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
+ dfs_path));
+ vfs_ChDir(conn, oldpath);
+ conn_free_internal(conn);
+ TALLOC_FREE(pdp);
+ return status;
+ }
+
+ /* We know this is a valid dfs link. Parse the targetpath. */
+ if (!parse_msdfs_symlink(ctx, targetpath,
+ &jucn->referral_list,
+ &jucn->referral_count)) {
+ DEBUG(3,("get_referred_path: failed to parse symlink "
+ "target %s\n", targetpath ));
+ vfs_ChDir(conn, oldpath);
+ conn_free_internal(conn);
+ TALLOC_FREE(pdp);
+ return NT_STATUS_NOT_FOUND;
+ }
+
+ vfs_ChDir(conn, oldpath);
+ conn_free_internal(conn);
+ TALLOC_FREE(pdp);
+ return NT_STATUS_OK;
+}
+
+static int setup_ver2_dfs_referral(const char *pathname,
+ char **ppdata,
+ struct junction_map *junction,
+ int consumedcnt,
+ bool self_referral)
+{
+ char* pdata = *ppdata;
+
+ smb_ucs2_t *uni_requestedpath = NULL;
+ int uni_reqpathoffset1,uni_reqpathoffset2;
+ int uni_curroffset;
+ int requestedpathlen=0;
+ int offset;
+ int reply_size = 0;
+ int i=0;
+
+ DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
+
+ requestedpathlen = rpcstr_push_talloc(talloc_tos(),
+ &uni_requestedpath, pathname);
+ if (uni_requestedpath == NULL || requestedpathlen == 0) {
+ return -1;
+ }
+
+ if (DEBUGLVL(10)) {
+ dump_data(0, (unsigned char *)uni_requestedpath,
+ requestedpathlen);
+ }
+
+ DEBUG(10,("ref count = %u\n",junction->referral_count));
+
+ uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
+ VERSION2_REFERRAL_SIZE * junction->referral_count;
+
+ uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
+
+ uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
+
+ reply_size = REFERRAL_HEADER_SIZE +
+ VERSION2_REFERRAL_SIZE*junction->referral_count +
+ 2 * requestedpathlen;
+ DEBUG(10,("reply_size: %u\n",reply_size));
+
+ /* add up the unicode lengths of all the referral paths */
+ for(i=0;i<junction->referral_count;i++) {
+ DEBUG(10,("referral %u : %s\n",
+ i,
+ junction->referral_list[i].alternate_path));
+ reply_size +=
+ (strlen(junction->referral_list[i].alternate_path)+1)*2;
+ }
+
+ DEBUG(10,("reply_size = %u\n",reply_size));
+ /* add the unexplained 0x16 bytes */
+ reply_size += 0x16;
+
+ pdata = (char *)SMB_REALLOC(pdata,reply_size);
+ if(pdata == NULL) {
+ DEBUG(0,("Realloc failed!\n"));
+ return -1;
+ }
+ *ppdata = pdata;
+
+ /* copy in the dfs requested paths.. required for offset calculations */
+ memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
+ memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
+
+ /* create the header */
+ SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
+ /* number of referral in this pkt */
+ SSVAL(pdata,2,junction->referral_count);
+ if(self_referral) {
+ SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
+ } else {
+ SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
+ }
+
+ offset = 8;
+ /* add the referral elements */
+ for(i=0;i<junction->referral_count;i++) {
+ struct referral* ref = &junction->referral_list[i];
+ int unilen;
+
+ SSVAL(pdata,offset,2); /* version 2 */
+ SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
+ if(self_referral) {
+ SSVAL(pdata,offset+4,1);
+ } else {
+ SSVAL(pdata,offset+4,0);
+ }
+
+ /* ref_flags :use path_consumed bytes? */
+ SSVAL(pdata,offset+6,0);
+ SIVAL(pdata,offset+8,ref->proximity);
+ SIVAL(pdata,offset+12,ref->ttl);
+
+ SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
+ SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
+ /* copy referred path into current offset */
+ unilen = rpcstr_push(pdata+uni_curroffset,
+ ref->alternate_path,
+ reply_size - uni_curroffset,
+ STR_UNICODE);
+
+ SSVAL(pdata,offset+20,uni_curroffset-offset);
+
+ uni_curroffset += unilen;
+ offset += VERSION2_REFERRAL_SIZE;
+ }
+ /* add in the unexplained 22 (0x16) bytes at the end */
+ memset(pdata+uni_curroffset,'\0',0x16);
+ return reply_size;
+}
+
+static int setup_ver3_dfs_referral(const char *pathname,
+ char **ppdata,
+ struct junction_map *junction,
+ int consumedcnt,
+ bool self_referral)
+{
+ char *pdata = *ppdata;
+
+ smb_ucs2_t *uni_reqpath = NULL;
+ int uni_reqpathoffset1, uni_reqpathoffset2;
+ int uni_curroffset;
+ int reply_size = 0;
+
+ int reqpathlen = 0;
+ int offset,i=0;
+
+ DEBUG(10,("setting up version3 referral\n"));
+
+ reqpathlen = rpcstr_push_talloc(talloc_tos(), &uni_reqpath, pathname);
+ if (uni_reqpath == NULL || reqpathlen == 0) {
+ return -1;
+ }
+
+ if (DEBUGLVL(10)) {
+ dump_data(0, (unsigned char *)uni_reqpath,
+ reqpathlen);
+ }
+
+ uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
+ VERSION3_REFERRAL_SIZE * junction->referral_count;
+ uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
+ reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
+
+ for(i=0;i<junction->referral_count;i++) {
+ DEBUG(10,("referral %u : %s\n",
+ i,
+ junction->referral_list[i].alternate_path));
+ reply_size +=
+ (strlen(junction->referral_list[i].alternate_path)+1)*2;
+ }
+
+ pdata = (char *)SMB_REALLOC(pdata,reply_size);
+ if(pdata == NULL) {
+ DEBUG(0,("version3 referral setup:"
+ "malloc failed for Realloc!\n"));
+ return -1;
+ }
+ *ppdata = pdata;
+
+ /* create the header */
+ SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
+ SSVAL(pdata,2,junction->referral_count); /* number of referral */
+ if(self_referral) {
+ SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
+ } else {
+ SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
+ }
+
+ /* copy in the reqpaths */
+ memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
+ memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
+
+ offset = 8;
+ for(i=0;i<junction->referral_count;i++) {
+ struct referral* ref = &(junction->referral_list[i]);
+ int unilen;
+
+ SSVAL(pdata,offset,3); /* version 3 */
+ SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
+ if(self_referral) {
+ SSVAL(pdata,offset+4,1);
+ } else {
+ SSVAL(pdata,offset+4,0);
+ }
+
+ /* ref_flags :use path_consumed bytes? */
+ SSVAL(pdata,offset+6,0);
+ SIVAL(pdata,offset+8,ref->ttl);
+
+ SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
+ SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
+ /* copy referred path into current offset */
+ unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
+ reply_size - uni_curroffset,
+ STR_UNICODE | STR_TERMINATE);
+ SSVAL(pdata,offset+16,uni_curroffset-offset);
+ /* copy 0x10 bytes of 00's in the ServiceSite GUID */
+ memset(pdata+offset+18,'\0',16);
+
+ uni_curroffset += unilen;
+ offset += VERSION3_REFERRAL_SIZE;
+ }
+ return reply_size;
+}
+
+/******************************************************************
+ Set up the DFS referral for the dfs pathname. This call returns
+ the amount of the path covered by this server, and where the
+ client should be redirected to. This is the meat of the
+ TRANS2_GET_DFS_REFERRAL call.
+******************************************************************/
+
+int setup_dfs_referral(connection_struct *orig_conn,
+ const char *dfs_path,
+ int max_referral_level,
+ char **ppdata, NTSTATUS *pstatus)
+{
+ struct junction_map *junction = NULL;
+ int consumedcnt = 0;
+ bool self_referral = False;
+ int reply_size = 0;
+ char *pathnamep = NULL;
+ char *local_dfs_path = NULL;
+ TALLOC_CTX *ctx;
+
+ if (!(ctx=talloc_init("setup_dfs_referral"))) {
+ *pstatus = NT_STATUS_NO_MEMORY;
+ return -1;
+ }
+
+ /* get the junction entry */
+ if (!dfs_path) {
+ talloc_destroy(ctx);
+ *pstatus = NT_STATUS_NOT_FOUND;
+ return -1;
+ }
+
+ /*
+ * Trim pathname sent by client so it begins with only one backslash.
+ * Two backslashes confuse some dfs clients
+ */
+
+ local_dfs_path = talloc_strdup(ctx,dfs_path);
+ if (!local_dfs_path) {
+ *pstatus = NT_STATUS_NO_MEMORY;
+ talloc_destroy(ctx);
+ return -1;
+ }
+ pathnamep = local_dfs_path;
+ while (IS_DIRECTORY_SEP(pathnamep[0]) &&
+ IS_DIRECTORY_SEP(pathnamep[1])) {
+ pathnamep++;
+ }
+
+ junction = TALLOC_ZERO_P(ctx, struct junction_map);
+ if (!junction) {
+ *pstatus = NT_STATUS_NO_MEMORY;
+ talloc_destroy(ctx);
+ return -1;
+ }
+
+ /* The following call can change cwd. */
+ *pstatus = get_referred_path(ctx, pathnamep, junction,
+ &consumedcnt, &self_referral);
+ if (!NT_STATUS_IS_OK(*pstatus)) {
+ vfs_ChDir(orig_conn,orig_conn->connectpath);
+ talloc_destroy(ctx);
+ return -1;
+ }
+ vfs_ChDir(orig_conn,orig_conn->connectpath);
+
+ if (!self_referral) {
+ pathnamep[consumedcnt] = '\0';
+
+ if( DEBUGLVL( 3 ) ) {
+ int i=0;
+ dbgtext("setup_dfs_referral: Path %s to "
+ "alternate path(s):",
+ pathnamep);
+ for(i=0;i<junction->referral_count;i++)
+ dbgtext(" %s",
+ junction->referral_list[i].alternate_path);
+ dbgtext(".\n");
+ }
+ }
+
+ /* create the referral depeding on version */
+ DEBUG(10,("max_referral_level :%d\n",max_referral_level));
+
+ if (max_referral_level < 2) {
+ max_referral_level = 2;
+ }
+ if (max_referral_level > 3) {
+ max_referral_level = 3;
+ }
+
+ switch(max_referral_level) {
+ case 2:
+ reply_size = setup_ver2_dfs_referral(pathnamep,
+ ppdata, junction,
+ consumedcnt, self_referral);
+ break;
+ case 3:
+ reply_size = setup_ver3_dfs_referral(pathnamep, ppdata,
+ junction, consumedcnt, self_referral);
+ break;
+ default:
+ DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
+ "version: %d\n",
+ max_referral_level));
+ talloc_destroy(ctx);
+ *pstatus = NT_STATUS_INVALID_LEVEL;
+ return -1;
+ }
+
+ if (DEBUGLVL(10)) {
+ DEBUGADD(0,("DFS Referral pdata:\n"));
+ dump_data(0,(uint8 *)*ppdata,reply_size);
+ }
+
+ talloc_destroy(ctx);
+ *pstatus = NT_STATUS_OK;
+ return reply_size;
+}
+
+/**********************************************************************
+ The following functions are called by the NETDFS RPC pipe functions
+ **********************************************************************/
+
+/*********************************************************************
+ Creates a junction structure from a DFS pathname
+**********************************************************************/
+
+bool create_junction(TALLOC_CTX *ctx,
+ const char *dfs_path,
+ struct junction_map *jucn)
+{
+ int snum;
+ bool dummy;
+ struct dfs_path *pdp = TALLOC_P(ctx,struct dfs_path);
+ NTSTATUS status;
+
+ if (!pdp) {
+ return False;
+ }
+ status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ /* check if path is dfs : validate first token */
+ if (!is_myname_or_ipaddr(pdp->hostname)) {
+ DEBUG(4,("create_junction: Invalid hostname %s "
+ "in dfs path %s\n",
+ pdp->hostname, dfs_path));
+ TALLOC_FREE(pdp);
+ return False;
+ }
+
+ /* Check for a non-DFS share */
+ snum = lp_servicenumber(pdp->servicename);
+
+ if(snum < 0 || !lp_msdfs_root(snum)) {
+ DEBUG(4,("create_junction: %s is not an msdfs root.\n",
+ pdp->servicename));
+ TALLOC_FREE(pdp);
+ return False;
+ }
+
+ jucn->service_name = talloc_strdup(ctx, pdp->servicename);
+ jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
+ jucn->comment = talloc_strdup(ctx, lp_comment(snum));
+
+ TALLOC_FREE(pdp);
+ if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
+ return False;
+ }
+ return True;
+}
+
+/**********************************************************************
+ Forms a valid Unix pathname from the junction
+ **********************************************************************/
+
+static bool junction_to_local_path(const struct junction_map *jucn,
+ char **pp_path_out,
+ connection_struct **conn_out,
+ char **oldpath)
+{
+ int snum;
+ NTSTATUS status;
+
+ snum = lp_servicenumber(jucn->service_name);
+ if(snum < 0) {
+ return False;
+ }
+ status = create_conn_struct(talloc_tos(), conn_out, snum,
+ lp_pathname(snum), oldpath);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ *pp_path_out = talloc_asprintf(*conn_out,
+ "%s/%s",
+ lp_pathname(snum),
+ jucn->volume_name);
+ if (!*pp_path_out) {
+ vfs_ChDir(*conn_out, *oldpath);
+ conn_free_internal(*conn_out);
+ return False;
+ }
+ return True;
+}
+
+bool create_msdfs_link(const struct junction_map *jucn)
+{
+ char *path = NULL;
+ char *cwd;
+ char *msdfs_link = NULL;
+ connection_struct *conn;
+ int i=0;
+ bool insert_comma = False;
+ bool ret = False;
+
+ if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
+ return False;
+ }
+
+ /* Form the msdfs_link contents */
+ msdfs_link = talloc_strdup(conn, "msdfs:");
+ if (!msdfs_link) {
+ goto out;
+ }
+ for(i=0; i<jucn->referral_count; i++) {
+ char *refpath = jucn->referral_list[i].alternate_path;
+
+ /* Alternate paths always use Windows separators. */
+ trim_char(refpath, '\\', '\\');
+ if(*refpath == '\0') {
+ if (i == 0) {
+ insert_comma = False;
+ }
+ continue;
+ }
+ if (i > 0 && insert_comma) {
+ msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
+ ",%s",
+ refpath);
+ } else {
+ msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
+ "%s",
+ refpath);
+ }
+
+ if (!msdfs_link) {
+ goto out;
+ }
+ if (!insert_comma) {
+ insert_comma = True;
+ }
+ }
+
+ DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
+ path, msdfs_link));
+
+ if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
+ if (errno == EEXIST) {
+ if(SMB_VFS_UNLINK(conn,path)!=0) {
+ goto out;
+ }
+ }
+ if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
+ DEBUG(1,("create_msdfs_link: symlink failed "
+ "%s -> %s\nError: %s\n",
+ path, msdfs_link, strerror(errno)));
+ goto out;
+ }
+ }
+
+ ret = True;
+
+out:
+ vfs_ChDir(conn, cwd);
+ conn_free_internal(conn);
+ return ret;
+}
+
+bool remove_msdfs_link(const struct junction_map *jucn)
+{
+ char *path = NULL;
+ char *cwd;
+ connection_struct *conn;
+ bool ret = False;
+
+ if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
+ return false;
+ }
+
+ if( SMB_VFS_UNLINK(conn, path) == 0 ) {
+ ret = True;
+ }
+
+ vfs_ChDir(conn, cwd);
+ conn_free_internal(conn);
+ return ret;
+}
+
+/*********************************************************************
+ Return the number of DFS links at the root of this share.
+*********************************************************************/
+
+static int count_dfs_links(TALLOC_CTX *ctx, int snum)
+{
+ size_t cnt = 0;
+ SMB_STRUCT_DIR *dirp = NULL;
+ char *dname = NULL;
+ const char *connect_path = lp_pathname(snum);
+ const char *msdfs_proxy = lp_msdfs_proxy(snum);
+ connection_struct *conn;
+ NTSTATUS status;
+ char *cwd;
+
+ if(*connect_path == '\0') {
+ return 0;
+ }
+
+ /*
+ * Fake up a connection struct for the VFS layer.
+ */
+
+ status = create_conn_struct(talloc_tos(), &conn, snum, connect_path,
+ &cwd);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("create_conn_struct failed: %s\n",
+ nt_errstr(status)));
+ return 0;
+ }
+
+ /* Count a link for the msdfs root - convention */
+ cnt = 1;
+
+ /* No more links if this is an msdfs proxy. */
+ if (*msdfs_proxy != '\0') {
+ goto out;
+ }
+
+ /* Now enumerate all dfs links */
+ dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
+ if(!dirp) {
+ goto out;
+ }
+
+ while ((dname = vfs_readdirname(conn, dirp)) != NULL) {
+ if (is_msdfs_link(conn,
+ dname,
+ NULL)) {
+ cnt++;
+ }
+ }
+
+ SMB_VFS_CLOSEDIR(conn,dirp);
+
+out:
+ vfs_ChDir(conn, cwd);
+ conn_free_internal(conn);
+ return cnt;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static int form_junctions(TALLOC_CTX *ctx,
+ int snum,
+ struct junction_map *jucn,
+ size_t jn_remain)
+{
+ size_t cnt = 0;
+ SMB_STRUCT_DIR *dirp = NULL;
+ char *dname = NULL;
+ const char *connect_path = lp_pathname(snum);
+ char *service_name = lp_servicename(snum);
+ const char *msdfs_proxy = lp_msdfs_proxy(snum);
+ connection_struct *conn;
+ struct referral *ref = NULL;
+ char *cwd;
+ NTSTATUS status;
+
+ if (jn_remain == 0) {
+ return 0;
+ }
+
+ if(*connect_path == '\0') {
+ return 0;
+ }
+
+ /*
+ * Fake up a connection struct for the VFS layer.
+ */
+
+ status = create_conn_struct(ctx, &conn, snum, connect_path, &cwd);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("create_conn_struct failed: %s\n",
+ nt_errstr(status)));
+ return 0;
+ }
+
+ /* form a junction for the msdfs root - convention
+ DO NOT REMOVE THIS: NT clients will not work with us
+ if this is not present
+ */
+ jucn[cnt].service_name = talloc_strdup(ctx,service_name);
+ jucn[cnt].volume_name = talloc_strdup(ctx, "");
+ if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
+ goto out;
+ }
+ jucn[cnt].comment = "";
+ jucn[cnt].referral_count = 1;
+
+ ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
+ if (jucn[cnt].referral_list == NULL) {
+ goto out;
+ }
+
+ ref->proximity = 0;
+ ref->ttl = REFERRAL_TTL;
+ if (*msdfs_proxy != '\0') {
+ ref->alternate_path = talloc_strdup(ctx,
+ msdfs_proxy);
+ } else {
+ ref->alternate_path = talloc_asprintf(ctx,
+ "\\\\%s\\%s",
+ get_local_machine_name(),
+ service_name);
+ }
+
+ if (!ref->alternate_path) {
+ goto out;
+ }
+ cnt++;
+
+ /* Don't enumerate if we're an msdfs proxy. */
+ if (*msdfs_proxy != '\0') {
+ goto out;
+ }
+
+ /* Now enumerate all dfs links */
+ dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
+ if(!dirp) {
+ goto out;
+ }
+
+ while ((dname = vfs_readdirname(conn, dirp)) != NULL) {
+ char *link_target = NULL;
+ if (cnt >= jn_remain) {
+ DEBUG(2, ("form_junctions: ran out of MSDFS "
+ "junction slots"));
+ goto out;
+ }
+ if (is_msdfs_link_internal(ctx,
+ conn,
+ dname, &link_target,
+ NULL)) {
+ if (parse_msdfs_symlink(ctx,
+ link_target,
+ &jucn[cnt].referral_list,
+ &jucn[cnt].referral_count)) {
+
+ jucn[cnt].service_name = talloc_strdup(ctx,
+ service_name);
+ jucn[cnt].volume_name = talloc_strdup(ctx,
+ dname);
+ if (!jucn[cnt].service_name ||
+ !jucn[cnt].volume_name) {
+ goto out;
+ }
+ jucn[cnt].comment = "";
+ cnt++;
+ }
+ TALLOC_FREE(link_target);
+ }
+ }
+
+out:
+
+ if (dirp) {
+ SMB_VFS_CLOSEDIR(conn,dirp);
+ }
+
+ vfs_ChDir(conn, cwd);
+ conn_free_internal(conn);
+ return cnt;
+}
+
+struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
+{
+ struct junction_map *jn = NULL;
+ int i=0;
+ size_t jn_count = 0;
+ int sharecount = 0;
+
+ *p_num_jn = 0;
+ if(!lp_host_msdfs()) {
+ return NULL;
+ }
+
+ /* Ensure all the usershares are loaded. */
+ become_root();
+ load_registry_shares();
+ sharecount = load_usershare_shares();
+ unbecome_root();
+
+ for(i=0;i < sharecount;i++) {
+ if(lp_msdfs_root(i)) {
+ jn_count += count_dfs_links(ctx, i);
+ }
+ }
+ if (jn_count == 0) {
+ return NULL;
+ }
+ jn = TALLOC_ARRAY(ctx, struct junction_map, jn_count);
+ if (!jn) {
+ return NULL;
+ }
+ for(i=0; i < sharecount; i++) {
+ if (*p_num_jn >= jn_count) {
+ break;
+ }
+ if(lp_msdfs_root(i)) {
+ *p_num_jn += form_junctions(ctx, i,
+ &jn[*p_num_jn],
+ jn_count - *p_num_jn);
+ }
+ }
+ return jn;
+}
+
+/******************************************************************************
+ Core function to resolve a dfs pathname.
+******************************************************************************/
+
+NTSTATUS resolve_dfspath(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ bool dfs_pathnames,
+ const char *name_in,
+ char **pp_name_out)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ bool dummy;
+ if (dfs_pathnames) {
+ status = dfs_redirect(ctx,
+ conn,
+ name_in,
+ False,
+ pp_name_out,
+ &dummy);
+ } else {
+ /*
+ * Cheat and just return a copy of the in ptr.
+ * Once srvstr_get_path() uses talloc it'll
+ * be a talloced ptr anyway.
+ */
+ *pp_name_out = CONST_DISCARD(char *,name_in);
+ }
+ return status;
+}
+
+/******************************************************************************
+ Core function to resolve a dfs pathname possibly containing a wildcard.
+ This function is identical to the above except for the bool param to
+ dfs_redirect but I need this to be separate so it's really clear when
+ we're allowing wildcards and when we're not. JRA.
+******************************************************************************/
+
+NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ bool dfs_pathnames,
+ const char *name_in,
+ char **pp_name_out,
+ bool *ppath_contains_wcard)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ if (dfs_pathnames) {
+ status = dfs_redirect(ctx,
+ conn,
+ name_in,
+ True,
+ pp_name_out,
+ ppath_contains_wcard);
+ } else {
+ /*
+ * Cheat and just return a copy of the in ptr.
+ * Once srvstr_get_path() uses talloc it'll
+ * be a talloced ptr anyway.
+ */
+ *pp_name_out = CONST_DISCARD(char *,name_in);
+ }
+ return status;
+}
diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c
new file mode 100644
index 0000000000..84f111fb02
--- /dev/null
+++ b/source3/smbd/negprot.c
@@ -0,0 +1,691 @@
+/*
+ Unix SMB/CIFS implementation.
+ negprot reply code
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern fstring remote_proto;
+extern enum protocol_types Protocol;
+extern int max_recv;
+
+bool global_encrypted_passwords_negotiated = False;
+bool global_spnego_negotiated = False;
+struct auth_context *negprot_global_auth_context = NULL;
+
+static void get_challenge(uint8 buff[8])
+{
+ NTSTATUS nt_status;
+ const uint8 *cryptkey;
+
+ /* We might be called more than once, multiple negprots are
+ * permitted */
+ if (negprot_global_auth_context) {
+ DEBUG(3, ("get challenge: is this a secondary negprot? negprot_global_auth_context is non-NULL!\n"));
+ (negprot_global_auth_context->free)(&negprot_global_auth_context);
+ }
+
+ DEBUG(10, ("get challenge: creating negprot_global_auth_context\n"));
+ if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&negprot_global_auth_context))) {
+ DEBUG(0, ("make_auth_context_subsystem returned %s", nt_errstr(nt_status)));
+ smb_panic("cannot make_negprot_global_auth_context!");
+ }
+ DEBUG(10, ("get challenge: getting challenge\n"));
+ cryptkey = negprot_global_auth_context->get_ntlm_challenge(negprot_global_auth_context);
+ memcpy(buff, cryptkey, 8);
+}
+
+/****************************************************************************
+ Reply for the core protocol.
+****************************************************************************/
+
+static void reply_corep(struct smb_request *req, uint16 choice)
+{
+ reply_outbuf(req, 1, 0);
+ SSVAL(req->outbuf, smb_vwv0, choice);
+
+ Protocol = PROTOCOL_CORE;
+}
+
+/****************************************************************************
+ Reply for the coreplus protocol.
+****************************************************************************/
+
+static void reply_coreplus(struct smb_request *req, uint16 choice)
+{
+ int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
+
+ reply_outbuf(req, 13, 0);
+
+ SSVAL(req->outbuf,smb_vwv0,choice);
+ SSVAL(req->outbuf,smb_vwv5,raw); /* tell redirector we support
+ readbraw and writebraw (possibly) */
+ /* Reply, SMBlockread, SMBwritelock supported. */
+ SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
+ SSVAL(req->outbuf,smb_vwv1,0x1); /* user level security, don't
+ * encrypt */
+ Protocol = PROTOCOL_COREPLUS;
+}
+
+/****************************************************************************
+ Reply for the lanman 1.0 protocol.
+****************************************************************************/
+
+static void reply_lanman1(struct smb_request *req, uint16 choice)
+{
+ int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
+ int secword=0;
+ time_t t = time(NULL);
+
+ global_encrypted_passwords_negotiated = lp_encrypted_passwords();
+
+ if (lp_security()>=SEC_USER)
+ secword |= NEGOTIATE_SECURITY_USER_LEVEL;
+ if (global_encrypted_passwords_negotiated)
+ secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
+
+ reply_outbuf(req, 13, global_encrypted_passwords_negotiated?8:0);
+
+ SSVAL(req->outbuf,smb_vwv0,choice);
+ SSVAL(req->outbuf,smb_vwv1,secword);
+ /* Create a token value and add it to the outgoing packet. */
+ if (global_encrypted_passwords_negotiated) {
+ get_challenge((uint8 *)smb_buf(req->outbuf));
+ SSVAL(req->outbuf,smb_vwv11, 8);
+ }
+
+ Protocol = PROTOCOL_LANMAN1;
+
+ /* Reply, SMBlockread, SMBwritelock supported. */
+ SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
+ SSVAL(req->outbuf,smb_vwv2,max_recv);
+ SSVAL(req->outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
+ SSVAL(req->outbuf,smb_vwv4,1);
+ SSVAL(req->outbuf,smb_vwv5,raw); /* tell redirector we support
+ readbraw writebraw (possibly) */
+ SIVAL(req->outbuf,smb_vwv6,sys_getpid());
+ SSVAL(req->outbuf,smb_vwv10, set_server_zone_offset(t)/60);
+
+ srv_put_dos_date((char *)req->outbuf,smb_vwv8,t);
+
+ return;
+}
+
+/****************************************************************************
+ Reply for the lanman 2.0 protocol.
+****************************************************************************/
+
+static void reply_lanman2(struct smb_request *req, uint16 choice)
+{
+ int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
+ int secword=0;
+ time_t t = time(NULL);
+
+ global_encrypted_passwords_negotiated = lp_encrypted_passwords();
+
+ if (lp_security()>=SEC_USER)
+ secword |= NEGOTIATE_SECURITY_USER_LEVEL;
+ if (global_encrypted_passwords_negotiated)
+ secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
+
+ reply_outbuf(req, 13, global_encrypted_passwords_negotiated?8:0);
+
+ SSVAL(req->outbuf,smb_vwv0,choice);
+ SSVAL(req->outbuf,smb_vwv1,secword);
+ SIVAL(req->outbuf,smb_vwv6,sys_getpid());
+
+ /* Create a token value and add it to the outgoing packet. */
+ if (global_encrypted_passwords_negotiated) {
+ get_challenge((uint8 *)smb_buf(req->outbuf));
+ SSVAL(req->outbuf,smb_vwv11, 8);
+ }
+
+ Protocol = PROTOCOL_LANMAN2;
+
+ /* Reply, SMBlockread, SMBwritelock supported. */
+ SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
+ SSVAL(req->outbuf,smb_vwv2,max_recv);
+ SSVAL(req->outbuf,smb_vwv3,lp_maxmux());
+ SSVAL(req->outbuf,smb_vwv4,1);
+ SSVAL(req->outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
+ SSVAL(req->outbuf,smb_vwv10, set_server_zone_offset(t)/60);
+ srv_put_dos_date((char *)req->outbuf,smb_vwv8,t);
+}
+
+/****************************************************************************
+ Generate the spnego negprot reply blob. Return the number of bytes used.
+****************************************************************************/
+
+static DATA_BLOB negprot_spnego(void)
+{
+ DATA_BLOB blob;
+ nstring dos_name;
+ fstring unix_name;
+#ifdef DEVELOPER
+ size_t slen;
+#endif
+ char guid[17];
+ const char *OIDs_krb5[] = {OID_KERBEROS5,
+ OID_KERBEROS5_OLD,
+ OID_NTLMSSP,
+ NULL};
+ const char *OIDs_plain[] = {OID_NTLMSSP, NULL};
+
+ global_spnego_negotiated = True;
+
+ memset(guid, '\0', sizeof(guid));
+
+ safe_strcpy(unix_name, global_myname(), sizeof(unix_name)-1);
+ strlower_m(unix_name);
+ push_ascii_nstring(dos_name, unix_name);
+ safe_strcpy(guid, dos_name, sizeof(guid)-1);
+
+#ifdef DEVELOPER
+ /* Fix valgrind 'uninitialized bytes' issue. */
+ slen = strlen(dos_name);
+ if (slen < sizeof(guid)) {
+ memset(guid+slen, '\0', sizeof(guid) - slen);
+ }
+#endif
+
+ /* strangely enough, NT does not sent the single OID NTLMSSP when
+ not a ADS member, it sends no OIDs at all
+
+ OLD COMMENT : "we can't do this until we teach our sesssion setup parser to know
+ about raw NTLMSSP (clients send no ASN.1 wrapping if we do this)"
+
+ Our sessionsetup code now handles raw NTLMSSP connects, so we can go
+ back to doing what W2K3 does here. This is needed to make PocketPC 2003
+ CIFS connections work with SPNEGO. See bugzilla bugs #1828 and #3133
+ for details. JRA.
+
+ */
+
+ if (lp_security() != SEC_ADS && !lp_use_kerberos_keytab()) {
+#if 0
+ /* Code for PocketPC client */
+ blob = data_blob(guid, 16);
+#else
+ /* Code for standalone WXP client */
+ blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE");
+#endif
+ } else {
+ fstring myname;
+ char *host_princ_s = NULL;
+ name_to_fqdn(myname, global_myname());
+ strlower_m(myname);
+ if (asprintf(&host_princ_s, "cifs/%s@%s", myname, lp_realm())
+ == -1) {
+ return data_blob_null;
+ }
+ blob = spnego_gen_negTokenInit(guid, OIDs_krb5, host_princ_s);
+ SAFE_FREE(host_princ_s);
+ }
+
+ return blob;
+}
+
+/****************************************************************************
+ Reply for the nt protocol.
+****************************************************************************/
+
+static void reply_nt1(struct smb_request *req, uint16 choice)
+{
+ /* dual names + lock_and_read + nt SMBs + remote API calls */
+ int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
+ CAP_LEVEL_II_OPLOCKS;
+
+ int secword=0;
+ char *p, *q;
+ bool negotiate_spnego = False;
+ time_t t = time(NULL);
+ ssize_t ret;
+
+ global_encrypted_passwords_negotiated = lp_encrypted_passwords();
+
+ /* Check the flags field to see if this is Vista.
+ WinXP sets it and Vista does not. But we have to
+ distinguish from NT which doesn't set it either. */
+
+ if ( (req->flags2 & FLAGS2_EXTENDED_SECURITY) &&
+ ((req->flags2 & FLAGS2_UNKNOWN_BIT4) == 0) )
+ {
+ if (get_remote_arch() != RA_SAMBA) {
+ set_remote_arch( RA_VISTA );
+ }
+ }
+
+ reply_outbuf(req,17,0);
+
+ /* do spnego in user level security if the client
+ supports it and we can do encrypted passwords */
+
+ if (global_encrypted_passwords_negotiated &&
+ (lp_security() != SEC_SHARE) &&
+ lp_use_spnego() &&
+ (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
+ negotiate_spnego = True;
+ capabilities |= CAP_EXTENDED_SECURITY;
+ add_to_common_flags2(FLAGS2_EXTENDED_SECURITY);
+ /* Ensure FLAGS2_EXTENDED_SECURITY gets set in this reply
+ (already partially constructed. */
+ SSVAL(req->outbuf, smb_flg2,
+ req->flags2 | FLAGS2_EXTENDED_SECURITY);
+ }
+
+ capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS|CAP_UNICODE;
+
+ if (lp_unix_extensions()) {
+ capabilities |= CAP_UNIX;
+ }
+
+ if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64))
+ capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
+
+ if (SMB_OFF_T_BITS == 64)
+ capabilities |= CAP_LARGE_FILES;
+
+ if (lp_readraw() && lp_writeraw())
+ capabilities |= CAP_RAW_MODE;
+
+ if (lp_nt_status_support())
+ capabilities |= CAP_STATUS32;
+
+ if (lp_host_msdfs())
+ capabilities |= CAP_DFS;
+
+ if (lp_security() >= SEC_USER)
+ secword |= NEGOTIATE_SECURITY_USER_LEVEL;
+ if (global_encrypted_passwords_negotiated)
+ secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
+
+ if (lp_server_signing()) {
+ if (lp_security() >= SEC_USER) {
+ secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
+ /* No raw mode with smb signing. */
+ capabilities &= ~CAP_RAW_MODE;
+ if (lp_server_signing() == Required)
+ secword |=NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
+ srv_set_signing_negotiated();
+ } else {
+ DEBUG(0,("reply_nt1: smb signing is incompatible with share level security !\n"));
+ if (lp_server_signing() == Required) {
+ exit_server_cleanly("reply_nt1: smb signing required and share level security selected.");
+ }
+ }
+ }
+
+ SSVAL(req->outbuf,smb_vwv0,choice);
+ SCVAL(req->outbuf,smb_vwv1,secword);
+
+ Protocol = PROTOCOL_NT1;
+
+ SSVAL(req->outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
+ SSVAL(req->outbuf,smb_vwv2+1,1); /* num vcs */
+ SIVAL(req->outbuf,smb_vwv3+1,max_recv); /* max buffer. LOTS! */
+ SIVAL(req->outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
+ SIVAL(req->outbuf,smb_vwv7+1,sys_getpid()); /* session key */
+ SIVAL(req->outbuf,smb_vwv9+1,capabilities); /* capabilities */
+ put_long_date((char *)req->outbuf+smb_vwv11+1,t);
+ SSVALS(req->outbuf,smb_vwv15+1,set_server_zone_offset(t)/60);
+
+ p = q = smb_buf(req->outbuf);
+ if (!negotiate_spnego) {
+ /* Create a token value and add it to the outgoing packet. */
+ if (global_encrypted_passwords_negotiated) {
+ uint8 chal[8];
+ /* note that we do not send a challenge at all if
+ we are using plaintext */
+ get_challenge(chal);
+ ret = message_push_blob(
+ &req->outbuf, data_blob_const(chal, sizeof(chal)));
+ if (ret == -1) {
+ DEBUG(0, ("Could not push challenge\n"));
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ SCVAL(req->outbuf, smb_vwv16+1, ret);
+ p += ret;
+ }
+ ret = message_push_string(&req->outbuf, lp_workgroup(),
+ STR_UNICODE|STR_TERMINATE
+ |STR_NOALIGN);
+ if (ret == -1) {
+ DEBUG(0, ("Could not push challenge\n"));
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ DEBUG(3,("not using SPNEGO\n"));
+ } else {
+ DATA_BLOB spnego_blob = negprot_spnego();
+
+ if (spnego_blob.data == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+
+ ret = message_push_blob(&req->outbuf, spnego_blob);
+ if (ret == -1) {
+ DEBUG(0, ("Could not push spnego blob\n"));
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ p += ret;
+ data_blob_free(&spnego_blob);
+
+ SCVAL(req->outbuf,smb_vwv16+1, 0);
+ DEBUG(3,("using SPNEGO\n"));
+ }
+
+ SSVAL(req->outbuf,smb_vwv17, p - q); /* length of challenge+domain
+ * strings */
+
+ return;
+}
+
+/* these are the protocol lists used for auto architecture detection:
+
+WinNT 3.51:
+protocol [PC NETWORK PROGRAM 1.0]
+protocol [XENIX CORE]
+protocol [MICROSOFT NETWORKS 1.03]
+protocol [LANMAN1.0]
+protocol [Windows for Workgroups 3.1a]
+protocol [LM1.2X002]
+protocol [LANMAN2.1]
+protocol [NT LM 0.12]
+
+Win95:
+protocol [PC NETWORK PROGRAM 1.0]
+protocol [XENIX CORE]
+protocol [MICROSOFT NETWORKS 1.03]
+protocol [LANMAN1.0]
+protocol [Windows for Workgroups 3.1a]
+protocol [LM1.2X002]
+protocol [LANMAN2.1]
+protocol [NT LM 0.12]
+
+Win2K:
+protocol [PC NETWORK PROGRAM 1.0]
+protocol [LANMAN1.0]
+protocol [Windows for Workgroups 3.1a]
+protocol [LM1.2X002]
+protocol [LANMAN2.1]
+protocol [NT LM 0.12]
+
+Vista:
+protocol [PC NETWORK PROGRAM 1.0]
+protocol [LANMAN1.0]
+protocol [Windows for Workgroups 3.1a]
+protocol [LM1.2X002]
+protocol [LANMAN2.1]
+protocol [NT LM 0.12]
+protocol [SMB 2.001]
+
+OS/2:
+protocol [PC NETWORK PROGRAM 1.0]
+protocol [XENIX CORE]
+protocol [LANMAN1.0]
+protocol [LM1.2X002]
+protocol [LANMAN2.1]
+*/
+
+/*
+ * Modified to recognize the architecture of the remote machine better.
+ *
+ * This appears to be the matrix of which protocol is used by which
+ * MS product.
+ Protocol WfWg Win95 WinNT Win2K OS/2 Vista
+ PC NETWORK PROGRAM 1.0 1 1 1 1 1 1
+ XENIX CORE 2 2
+ MICROSOFT NETWORKS 3.0 2 2
+ DOS LM1.2X002 3 3
+ MICROSOFT NETWORKS 1.03 3
+ DOS LANMAN2.1 4 4
+ LANMAN1.0 4 2 3 2
+ Windows for Workgroups 3.1a 5 5 5 3 3
+ LM1.2X002 6 4 4 4
+ LANMAN2.1 7 5 5 5
+ NT LM 0.12 6 8 6 6
+ SMB 2.001 7
+ *
+ * tim@fsg.com 09/29/95
+ * Win2K added by matty 17/7/99
+ */
+
+#define ARCH_WFWG 0x3 /* This is a fudge because WfWg is like Win95 */
+#define ARCH_WIN95 0x2
+#define ARCH_WINNT 0x4
+#define ARCH_WIN2K 0xC /* Win2K is like NT */
+#define ARCH_OS2 0x14 /* Again OS/2 is like NT */
+#define ARCH_SAMBA 0x20
+#define ARCH_CIFSFS 0x40
+#define ARCH_VISTA 0x8C /* Vista is like XP/2K */
+
+#define ARCH_ALL 0x7F
+
+/* List of supported protocols, most desired first */
+static const struct {
+ const char *proto_name;
+ const char *short_name;
+ void (*proto_reply_fn)(struct smb_request *req, uint16 choice);
+ int protocol_level;
+} supported_protocols[] = {
+ {"NT LANMAN 1.0", "NT1", reply_nt1, PROTOCOL_NT1},
+ {"NT LM 0.12", "NT1", reply_nt1, PROTOCOL_NT1},
+ {"POSIX 2", "NT1", reply_nt1, PROTOCOL_NT1},
+ {"LANMAN2.1", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
+ {"LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
+ {"Samba", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
+ {"DOS LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
+ {"LANMAN1.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1},
+ {"MICROSOFT NETWORKS 3.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1},
+ {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS},
+ {"PC NETWORK PROGRAM 1.0", "CORE", reply_corep, PROTOCOL_CORE},
+ {NULL,NULL,NULL,0},
+};
+
+/****************************************************************************
+ Reply to a negprot.
+ conn POINTER CAN BE NULL HERE !
+****************************************************************************/
+
+void reply_negprot(struct smb_request *req)
+{
+ size_t size = smb_len(req->inbuf) + 4;
+ int choice= -1;
+ int protocol;
+ char *p;
+ int bcc = SVAL(smb_buf(req->inbuf),-2);
+ int arch = ARCH_ALL;
+ int num_cliprotos;
+ char **cliprotos;
+ int i;
+ size_t converted_size;
+
+ static bool done_negprot = False;
+
+ START_PROFILE(SMBnegprot);
+
+ if (done_negprot) {
+ END_PROFILE(SMBnegprot);
+ exit_server_cleanly("multiple negprot's are not permitted");
+ }
+ done_negprot = True;
+
+ if (req->inbuf[size-1] != '\0') {
+ DEBUG(0, ("negprot protocols not 0-terminated\n"));
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBnegprot);
+ return;
+ }
+
+ p = smb_buf(req->inbuf) + 1;
+
+ num_cliprotos = 0;
+ cliprotos = NULL;
+
+ while (p < (smb_buf(req->inbuf) + bcc)) {
+
+ char **tmp;
+
+ tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), cliprotos, char *,
+ num_cliprotos+1);
+ if (tmp == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(cliprotos);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBnegprot);
+ return;
+ }
+
+ cliprotos = tmp;
+
+ if (!pull_ascii_talloc(cliprotos, &cliprotos[num_cliprotos], p,
+ &converted_size)) {
+ DEBUG(0, ("pull_ascii_talloc failed\n"));
+ TALLOC_FREE(cliprotos);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBnegprot);
+ return;
+ }
+
+ DEBUG(3, ("Requested protocol [%s]\n",
+ cliprotos[num_cliprotos]));
+
+ num_cliprotos += 1;
+ p += strlen(p) + 2;
+ }
+
+ for (i=0; i<num_cliprotos; i++) {
+ if (strcsequal(cliprotos[i], "Windows for Workgroups 3.1a"))
+ arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT
+ | ARCH_WIN2K );
+ else if (strcsequal(cliprotos[i], "DOS LM1.2X002"))
+ arch &= ( ARCH_WFWG | ARCH_WIN95 );
+ else if (strcsequal(cliprotos[i], "DOS LANMAN2.1"))
+ arch &= ( ARCH_WFWG | ARCH_WIN95 );
+ else if (strcsequal(cliprotos[i], "NT LM 0.12"))
+ arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K
+ | ARCH_CIFSFS);
+ else if (strcsequal(cliprotos[i], "SMB 2.001"))
+ arch = ARCH_VISTA;
+ else if (strcsequal(cliprotos[i], "LANMAN2.1"))
+ arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
+ else if (strcsequal(cliprotos[i], "LM1.2X002"))
+ arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
+ else if (strcsequal(cliprotos[i], "MICROSOFT NETWORKS 1.03"))
+ arch &= ARCH_WINNT;
+ else if (strcsequal(cliprotos[i], "XENIX CORE"))
+ arch &= ( ARCH_WINNT | ARCH_OS2 );
+ else if (strcsequal(cliprotos[i], "Samba")) {
+ arch = ARCH_SAMBA;
+ break;
+ } else if (strcsequal(cliprotos[i], "POSIX 2")) {
+ arch = ARCH_CIFSFS;
+ break;
+ }
+ }
+
+ /* CIFSFS can send one arch only, NT LM 0.12. */
+ if (i == 1 && (arch & ARCH_CIFSFS)) {
+ arch = ARCH_CIFSFS;
+ }
+
+ switch ( arch ) {
+ case ARCH_CIFSFS:
+ set_remote_arch(RA_CIFSFS);
+ break;
+ case ARCH_SAMBA:
+ set_remote_arch(RA_SAMBA);
+ break;
+ case ARCH_WFWG:
+ set_remote_arch(RA_WFWG);
+ break;
+ case ARCH_WIN95:
+ set_remote_arch(RA_WIN95);
+ break;
+ case ARCH_WINNT:
+ if(req->flags2 == FLAGS2_WIN2K_SIGNATURE)
+ set_remote_arch(RA_WIN2K);
+ else
+ set_remote_arch(RA_WINNT);
+ break;
+ case ARCH_WIN2K:
+ /* Vista may have been set in the negprot so don't
+ override it here */
+ if ( get_remote_arch() != RA_VISTA )
+ set_remote_arch(RA_WIN2K);
+ break;
+ case ARCH_VISTA:
+ set_remote_arch(RA_VISTA);
+ 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);
+
+ /* moved from the netbios session setup code since we don't have that
+ when the client connects to port 445. Of course there is a small
+ window where we are listening to messages -- jerry */
+
+ claim_connection(
+ NULL,"",FLAG_MSG_GENERAL|FLAG_MSG_SMBD|FLAG_MSG_PRINT_GENERAL);
+
+ /* Check for protocols, most desirable first */
+ for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) {
+ i = 0;
+ if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) &&
+ (supported_protocols[protocol].protocol_level >= lp_minprotocol()))
+ while (i < num_cliprotos) {
+ if (strequal(cliprotos[i],supported_protocols[protocol].proto_name))
+ choice = i;
+ i++;
+ }
+ if(choice != -1)
+ break;
+ }
+
+ if(choice != -1) {
+ fstrcpy(remote_proto,supported_protocols[protocol].short_name);
+ reload_services(True);
+ supported_protocols[protocol].proto_reply_fn(req, choice);
+ DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
+ } else {
+ DEBUG(0,("No protocol supported !\n"));
+ reply_outbuf(req, 1, 0);
+ SSVAL(req->outbuf, smb_vwv0, choice);
+ }
+
+ DEBUG( 5, ( "negprot index=%d\n", choice ) );
+
+ if ((lp_server_signing() == Required) && (Protocol < PROTOCOL_NT1)) {
+ exit_server_cleanly("SMB signing is required and "
+ "client negotiated a downlevel protocol");
+ }
+
+ TALLOC_FREE(cliprotos);
+ END_PROFILE(SMBnegprot);
+ return;
+}
diff --git a/source3/smbd/noquotas.c b/source3/smbd/noquotas.c
new file mode 100644
index 0000000000..c8ff8edf62
--- /dev/null
+++ b/source3/smbd/noquotas.c
@@ -0,0 +1,37 @@
+/*
+ Unix SMB/CIFS implementation.
+ No support for quotas :-).
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*
+ * Needed for auto generation of proto.h.
+ */
+
+bool disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+{
+ (*bsize) = 512; /* This value should be ignored */
+
+ /* And just to be sure we set some values that hopefully */
+ /* will be larger that any possible real-world value */
+ (*dfree) = (SMB_BIG_UINT)-1;
+ (*dsize) = (SMB_BIG_UINT)-1;
+
+ /* As we have select not to use quotas, allways fail */
+ return False;
+}
diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c
new file mode 100644
index 0000000000..139dfe7d5b
--- /dev/null
+++ b/source3/smbd/notify.c
@@ -0,0 +1,524 @@
+/*
+ Unix SMB/CIFS implementation.
+ change notify handling
+ Copyright (C) Andrew Tridgell 2000
+ Copyright (C) Jeremy Allison 1994-1998
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+struct notify_change_request {
+ struct notify_change_request *prev, *next;
+ struct files_struct *fsp; /* backpointer for cancel by mid */
+ uint8 request_buf[smb_size];
+ uint32 filter;
+ uint32 max_param;
+ struct notify_mid_map *mid_map;
+ void *backend_data;
+};
+
+static void notify_fsp(files_struct *fsp, uint32 action, const char *name);
+
+static struct notify_mid_map *notify_changes_by_mid;
+
+/*
+ * For NTCancel, we need to find the notify_change_request indexed by
+ * mid. Separate list here.
+ */
+
+struct notify_mid_map {
+ struct notify_mid_map *prev, *next;
+ struct notify_change_request *req;
+ uint16 mid;
+};
+
+static bool notify_change_record_identical(struct notify_change *c1,
+ struct notify_change *c2)
+{
+ /* Note this is deliberately case sensitive. */
+ if (c1->action == c2->action &&
+ strcmp(c1->name, c2->name) == 0) {
+ return True;
+ }
+ return False;
+}
+
+static bool notify_marshall_changes(int num_changes,
+ uint32 max_offset,
+ struct notify_change *changes,
+ prs_struct *ps)
+{
+ int i;
+ UNISTR uni_name;
+
+ uni_name.buffer = NULL;
+
+ for (i=0; i<num_changes; i++) {
+ struct notify_change *c;
+ size_t namelen;
+ uint32 u32_tmp; /* Temp arg to prs_uint32 to avoid
+ * signed/unsigned issues */
+
+ /* Coalesce any identical records. */
+ while (i+1 < num_changes &&
+ notify_change_record_identical(&changes[i],
+ &changes[i+1])) {
+ i++;
+ }
+
+ c = &changes[i];
+
+ if (!convert_string_allocate(NULL, CH_UNIX, CH_UTF16LE,
+ c->name, strlen(c->name)+1, &uni_name.buffer,
+ &namelen, True) || (uni_name.buffer == NULL)) {
+ goto fail;
+ }
+
+ namelen -= 2; /* Dump NULL termination */
+
+ /*
+ * Offset to next entry, only if there is one
+ */
+
+ u32_tmp = (i == num_changes-1) ? 0 : namelen + 12;
+ if (!prs_uint32("offset", ps, 1, &u32_tmp)) goto fail;
+
+ u32_tmp = c->action;
+ if (!prs_uint32("action", ps, 1, &u32_tmp)) goto fail;
+
+ u32_tmp = namelen;
+ if (!prs_uint32("namelen", ps, 1, &u32_tmp)) goto fail;
+
+ if (!prs_unistr("name", ps, 1, &uni_name)) goto fail;
+
+ /*
+ * Not NULL terminated, decrease by the 2 UCS2 \0 chars
+ */
+ prs_set_offset(ps, prs_offset(ps)-2);
+
+ SAFE_FREE(uni_name.buffer);
+
+ if (prs_offset(ps) > max_offset) {
+ /* Too much data for client. */
+ DEBUG(10, ("Client only wanted %d bytes, trying to "
+ "marshall %d bytes\n", (int)max_offset,
+ (int)prs_offset(ps)));
+ return False;
+ }
+ }
+
+ return True;
+
+ fail:
+ SAFE_FREE(uni_name.buffer);
+ return False;
+}
+
+/****************************************************************************
+ Setup the common parts of the return packet and send it.
+*****************************************************************************/
+
+static void change_notify_reply_packet(connection_struct *conn,
+ const uint8 *request_buf,
+ NTSTATUS error_code)
+{
+ char outbuf[smb_size+38];
+
+ memset(outbuf, '\0', sizeof(outbuf));
+ construct_reply_common((char *)request_buf, outbuf);
+
+ ERROR_NT(error_code);
+
+ /*
+ * Seems NT needs a transact command with an error code
+ * in it. This is a longer packet than a simple error.
+ */
+ srv_set_message(outbuf,18,0,False);
+
+ show_msg(outbuf);
+ if (!srv_send_smb(smbd_server_fd(),
+ outbuf,
+ IS_CONN_ENCRYPTED(conn)))
+ exit_server_cleanly("change_notify_reply_packet: srv_send_smb "
+ "failed.");
+}
+
+void change_notify_reply(connection_struct *conn,
+ const uint8 *request_buf, uint32 max_param,
+ struct notify_change_buf *notify_buf)
+{
+ prs_struct ps;
+ struct smb_request *req = NULL;
+ uint8 tmp_request[smb_size];
+
+ if (notify_buf->num_changes == -1) {
+ change_notify_reply_packet(conn, request_buf, NT_STATUS_OK);
+ notify_buf->num_changes = 0;
+ return;
+ }
+
+ prs_init_empty(&ps, NULL, MARSHALL);
+
+ if (!notify_marshall_changes(notify_buf->num_changes, max_param,
+ notify_buf->changes, &ps)) {
+ /*
+ * We exceed what the client is willing to accept. Send
+ * nothing.
+ */
+ change_notify_reply_packet(conn, request_buf, NT_STATUS_OK);
+ goto done;
+ }
+
+ if (!(req = talloc(talloc_tos(), struct smb_request))) {
+ change_notify_reply_packet(conn, request_buf, NT_STATUS_NO_MEMORY);
+ goto done;
+ }
+
+ memcpy(tmp_request, request_buf, smb_size);
+
+ /*
+ * We're only interested in the header fields here
+ */
+
+ smb_setlen((char *)tmp_request, smb_size);
+ SCVAL(tmp_request, smb_wct, 0);
+
+ init_smb_request(req, tmp_request,0, conn->encrypted_tid);
+
+ send_nt_replies(conn, req, NT_STATUS_OK, prs_data_p(&ps),
+ prs_offset(&ps), NULL, 0);
+
+ done:
+ TALLOC_FREE(req);
+ prs_mem_free(&ps);
+
+ TALLOC_FREE(notify_buf->changes);
+ notify_buf->num_changes = 0;
+}
+
+static void notify_callback(void *private_data, const struct notify_event *e)
+{
+ files_struct *fsp = (files_struct *)private_data;
+ DEBUG(10, ("notify_callback called for %s\n", fsp->fsp_name));
+ notify_fsp(fsp, e->action, e->path);
+}
+
+NTSTATUS change_notify_create(struct files_struct *fsp, uint32 filter,
+ bool recursive)
+{
+ char *fullpath;
+ struct notify_entry e;
+ NTSTATUS status;
+
+ SMB_ASSERT(fsp->notify == NULL);
+
+ if (!(fsp->notify = TALLOC_ZERO_P(NULL, struct notify_change_buf))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (asprintf(&fullpath, "%s/%s", fsp->conn->connectpath,
+ fsp->fsp_name) == -1) {
+ DEBUG(0, ("asprintf failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCT(e);
+ e.path = fullpath;
+ e.filter = filter;
+ e.subdir_filter = 0;
+ if (recursive) {
+ e.subdir_filter = filter;
+ }
+
+ status = notify_add(fsp->conn->notify_ctx, &e, notify_callback, fsp);
+ SAFE_FREE(fullpath);
+
+ return status;
+}
+
+NTSTATUS change_notify_add_request(const struct smb_request *req,
+ uint32 max_param,
+ uint32 filter, bool recursive,
+ struct files_struct *fsp)
+{
+ struct notify_change_request *request = NULL;
+ struct notify_mid_map *map = NULL;
+
+ DEBUG(10, ("change_notify_add_request: Adding request for %s: "
+ "max_param = %d\n", fsp->fsp_name, (int)max_param));
+
+ if (!(request = SMB_MALLOC_P(struct notify_change_request))
+ || !(map = SMB_MALLOC_P(struct notify_mid_map))) {
+ SAFE_FREE(request);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ request->mid_map = map;
+ map->req = request;
+
+ memcpy(request->request_buf, req->inbuf, sizeof(request->request_buf));
+ request->max_param = max_param;
+ request->filter = filter;
+ request->fsp = fsp;
+ request->backend_data = NULL;
+
+ DLIST_ADD_END(fsp->notify->requests, request,
+ struct notify_change_request *);
+
+ map->mid = SVAL(req->inbuf, smb_mid);
+ DLIST_ADD(notify_changes_by_mid, map);
+
+ /* Push the MID of this packet on the signing queue. */
+ srv_defer_sign_response(SVAL(req->inbuf,smb_mid));
+
+ return NT_STATUS_OK;
+}
+
+static void change_notify_remove_request(struct notify_change_request *remove_req)
+{
+ files_struct *fsp;
+ struct notify_change_request *req;
+
+ /*
+ * Paranoia checks, the fsp referenced must must have the request in
+ * its list of pending requests
+ */
+
+ fsp = remove_req->fsp;
+ SMB_ASSERT(fsp->notify != NULL);
+
+ for (req = fsp->notify->requests; req; req = req->next) {
+ if (req == remove_req) {
+ break;
+ }
+ }
+
+ if (req == NULL) {
+ smb_panic("notify_req not found in fsp's requests");
+ }
+
+ DLIST_REMOVE(fsp->notify->requests, req);
+ DLIST_REMOVE(notify_changes_by_mid, req->mid_map);
+ SAFE_FREE(req->mid_map);
+ TALLOC_FREE(req->backend_data);
+ SAFE_FREE(req);
+}
+
+/****************************************************************************
+ Delete entries by mid from the change notify pending queue. Always send reply.
+*****************************************************************************/
+
+void remove_pending_change_notify_requests_by_mid(uint16 mid)
+{
+ struct notify_mid_map *map;
+
+ for (map = notify_changes_by_mid; map; map = map->next) {
+ if (map->mid == mid) {
+ break;
+ }
+ }
+
+ if (map == NULL) {
+ return;
+ }
+
+ change_notify_reply_packet(map->req->fsp->conn,
+ map->req->request_buf, NT_STATUS_CANCELLED);
+ change_notify_remove_request(map->req);
+}
+
+/****************************************************************************
+ Delete entries by fnum from the change notify pending queue.
+*****************************************************************************/
+
+void remove_pending_change_notify_requests_by_fid(files_struct *fsp,
+ NTSTATUS status)
+{
+ if (fsp->notify == NULL) {
+ return;
+ }
+
+ while (fsp->notify->requests != NULL) {
+ change_notify_reply_packet(fsp->conn,
+ fsp->notify->requests->request_buf, status);
+ change_notify_remove_request(fsp->notify->requests);
+ }
+}
+
+void notify_fname(connection_struct *conn, uint32 action, uint32 filter,
+ const char *path)
+{
+ char *fullpath;
+
+ if (asprintf(&fullpath, "%s/%s", conn->connectpath, path) == -1) {
+ DEBUG(0, ("asprintf failed\n"));
+ return;
+ }
+
+ notify_trigger(conn->notify_ctx, action, filter, fullpath);
+ SAFE_FREE(fullpath);
+}
+
+static void notify_fsp(files_struct *fsp, uint32 action, const char *name)
+{
+ struct notify_change *change, *changes;
+ char *tmp;
+
+ if (fsp->notify == NULL) {
+ /*
+ * Nobody is waiting, don't queue
+ */
+ return;
+ }
+
+ /*
+ * Someone has triggered a notify previously, queue the change for
+ * later.
+ */
+
+ if ((fsp->notify->num_changes > 1000) || (name == NULL)) {
+ /*
+ * The real number depends on the client buf, just provide a
+ * guard against a DoS here.
+ */
+ TALLOC_FREE(fsp->notify->changes);
+ fsp->notify->num_changes = -1;
+ return;
+ }
+
+ if (fsp->notify->num_changes == -1) {
+ return;
+ }
+
+ if (!(changes = TALLOC_REALLOC_ARRAY(
+ fsp->notify, fsp->notify->changes,
+ struct notify_change, fsp->notify->num_changes+1))) {
+ DEBUG(0, ("talloc_realloc failed\n"));
+ return;
+ }
+
+ fsp->notify->changes = changes;
+
+ change = &(fsp->notify->changes[fsp->notify->num_changes]);
+
+ if (!(tmp = talloc_strdup(changes, name))) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ return;
+ }
+
+ string_replace(tmp, '/', '\\');
+ change->name = tmp;
+
+ change->action = action;
+ fsp->notify->num_changes += 1;
+
+ if (fsp->notify->requests == NULL) {
+ /*
+ * Nobody is waiting, so don't send anything. The ot
+ */
+ return;
+ }
+
+ if (action == NOTIFY_ACTION_OLD_NAME) {
+ /*
+ * We have to send the two rename events in one reply. So hold
+ * the first part back.
+ */
+ return;
+ }
+
+ /*
+ * Someone is waiting for the change, trigger the reply immediately.
+ *
+ * TODO: do we have to walk the lists of requests pending?
+ */
+
+ change_notify_reply(fsp->conn,
+ fsp->notify->requests->request_buf,
+ fsp->notify->requests->max_param,
+ fsp->notify);
+
+ change_notify_remove_request(fsp->notify->requests);
+}
+
+char *notify_filter_string(TALLOC_CTX *mem_ctx, uint32 filter)
+{
+ char *result = NULL;
+
+ result = talloc_strdup(mem_ctx, "");
+
+ if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
+ result = talloc_asprintf_append(result, "FILE_NAME|");
+ if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
+ result = talloc_asprintf_append(result, "DIR_NAME|");
+ if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
+ result = talloc_asprintf_append(result, "ATTRIBUTES|");
+ if (filter & FILE_NOTIFY_CHANGE_SIZE)
+ result = talloc_asprintf_append(result, "SIZE|");
+ if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
+ result = talloc_asprintf_append(result, "LAST_WRITE|");
+ if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
+ result = talloc_asprintf_append(result, "LAST_ACCESS|");
+ if (filter & FILE_NOTIFY_CHANGE_CREATION)
+ result = talloc_asprintf_append(result, "CREATION|");
+ if (filter & FILE_NOTIFY_CHANGE_EA)
+ result = talloc_asprintf_append(result, "EA|");
+ if (filter & FILE_NOTIFY_CHANGE_SECURITY)
+ result = talloc_asprintf_append(result, "SECURITY|");
+ if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
+ result = talloc_asprintf_append(result, "STREAM_NAME|");
+ if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
+ result = talloc_asprintf_append(result, "STREAM_SIZE|");
+ if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
+ result = talloc_asprintf_append(result, "STREAM_WRITE|");
+
+ if (result == NULL) return NULL;
+ if (*result == '\0') return result;
+
+ result[strlen(result)-1] = '\0';
+ return result;
+}
+
+struct sys_notify_context *sys_notify_context_create(connection_struct *conn,
+ TALLOC_CTX *mem_ctx,
+ struct event_context *ev)
+{
+ struct sys_notify_context *ctx;
+
+ if (!(ctx = TALLOC_P(mem_ctx, struct sys_notify_context))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ ctx->ev = ev;
+ ctx->conn = conn;
+ ctx->private_data = NULL;
+ return ctx;
+}
+
+NTSTATUS sys_notify_watch(struct sys_notify_context *ctx,
+ struct notify_entry *e,
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev),
+ void *private_data, void *handle)
+{
+ return SMB_VFS_NOTIFY_WATCH(ctx->conn, ctx, e, callback, private_data,
+ handle);
+}
+
diff --git a/source3/smbd/notify_inotify.c b/source3/smbd/notify_inotify.c
new file mode 100644
index 0000000000..fa0f0ed51d
--- /dev/null
+++ b/source3/smbd/notify_inotify.c
@@ -0,0 +1,434 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ notify implementation using inotify
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_INOTIFY
+
+#ifdef HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+
+#ifndef HAVE_INOTIFY_INIT
+
+#include <linux/inotify.h>
+#include <asm/unistd.h>
+
+
+/*
+ glibc doesn't define these functions yet (as of March 2006)
+*/
+static int inotify_init(void)
+{
+ return syscall(__NR_inotify_init);
+}
+
+static int inotify_add_watch(int fd, const char *path, __u32 mask)
+{
+ return syscall(__NR_inotify_add_watch, fd, path, mask);
+}
+
+static int inotify_rm_watch(int fd, int wd)
+{
+ return syscall(__NR_inotify_rm_watch, fd, wd);
+}
+#else
+
+#include <sys/inotify.h>
+
+#endif
+
+
+/* older glibc headers don't have these defines either */
+#ifndef IN_ONLYDIR
+#define IN_ONLYDIR 0x01000000
+#endif
+#ifndef IN_MASK_ADD
+#define IN_MASK_ADD 0x20000000
+#endif
+
+struct inotify_private {
+ struct sys_notify_context *ctx;
+ int fd;
+ struct inotify_watch_context *watches;
+};
+
+struct inotify_watch_context {
+ struct inotify_watch_context *next, *prev;
+ struct inotify_private *in;
+ int wd;
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev);
+ void *private_data;
+ uint32_t mask; /* the inotify mask */
+ uint32_t filter; /* the windows completion filter */
+ const char *path;
+};
+
+
+/*
+ destroy the inotify private context
+*/
+static int inotify_destructor(struct inotify_private *in)
+{
+ close(in->fd);
+ return 0;
+}
+
+
+/*
+ see if a particular event from inotify really does match a requested
+ notify event in SMB
+*/
+static bool filter_match(struct inotify_watch_context *w,
+ struct inotify_event *e)
+{
+ DEBUG(10, ("filter_match: e->mask=%x, w->mask=%x, w->filter=%x\n",
+ e->mask, w->mask, w->filter));
+
+ if ((e->mask & w->mask) == 0) {
+ /* this happens because inotify_add_watch() coalesces watches on the same
+ path, oring their masks together */
+ return False;
+ }
+
+ /* SMB separates the filters for files and directories */
+ if (e->mask & IN_ISDIR) {
+ if ((w->filter & FILE_NOTIFY_CHANGE_DIR_NAME) == 0) {
+ return False;
+ }
+ } else {
+ if ((e->mask & IN_ATTRIB) &&
+ (w->filter & (FILE_NOTIFY_CHANGE_ATTRIBUTES|
+ FILE_NOTIFY_CHANGE_LAST_WRITE|
+ FILE_NOTIFY_CHANGE_LAST_ACCESS|
+ FILE_NOTIFY_CHANGE_EA|
+ FILE_NOTIFY_CHANGE_SECURITY))) {
+ return True;
+ }
+ if ((e->mask & IN_MODIFY) &&
+ (w->filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)) {
+ return True;
+ }
+ if ((w->filter & FILE_NOTIFY_CHANGE_FILE_NAME) == 0) {
+ return False;
+ }
+ }
+
+ return True;
+}
+
+
+
+/*
+ dispatch one inotify event
+
+ the cookies are used to correctly handle renames
+*/
+static void inotify_dispatch(struct inotify_private *in,
+ struct inotify_event *e,
+ uint32_t prev_cookie,
+ struct inotify_event *e2)
+{
+ struct inotify_watch_context *w, *next;
+ struct notify_event ne;
+
+ DEBUG(10, ("inotify_dispatch called with mask=%x, name=[%s]\n",
+ e->mask, e->len ? e->name : ""));
+
+ /* ignore extraneous events, such as unmount and IN_IGNORED events */
+ if ((e->mask & (IN_ATTRIB|IN_MODIFY|IN_CREATE|IN_DELETE|
+ IN_MOVED_FROM|IN_MOVED_TO)) == 0) {
+ return;
+ }
+
+ /* map the inotify mask to a action. This gets complicated for
+ renames */
+ if (e->mask & IN_CREATE) {
+ ne.action = NOTIFY_ACTION_ADDED;
+ } else if (e->mask & IN_DELETE) {
+ ne.action = NOTIFY_ACTION_REMOVED;
+ } else if (e->mask & IN_MOVED_FROM) {
+ if (e2 != NULL && e2->cookie == e->cookie) {
+ ne.action = NOTIFY_ACTION_OLD_NAME;
+ } else {
+ ne.action = NOTIFY_ACTION_REMOVED;
+ }
+ } else if (e->mask & IN_MOVED_TO) {
+ if (e->cookie == prev_cookie) {
+ ne.action = NOTIFY_ACTION_NEW_NAME;
+ } else {
+ ne.action = NOTIFY_ACTION_ADDED;
+ }
+ } else {
+ ne.action = NOTIFY_ACTION_MODIFIED;
+ }
+ ne.path = e->name;
+
+ DEBUG(10, ("inotify_dispatch: ne.action = %d, ne.path = %s\n",
+ ne.action, ne.path));
+
+ /* find any watches that have this watch descriptor */
+ for (w=in->watches;w;w=next) {
+ next = w->next;
+ if (w->wd == e->wd && filter_match(w, e)) {
+ w->callback(in->ctx, w->private_data, &ne);
+ }
+ }
+
+ /* SMB expects a file rename to generate three events, two for
+ the rename and the other for a modify of the
+ destination. Strange! */
+ if (ne.action != NOTIFY_ACTION_NEW_NAME ||
+ (e->mask & IN_ISDIR) != 0) {
+ return;
+ }
+
+ ne.action = NOTIFY_ACTION_MODIFIED;
+ e->mask = IN_ATTRIB;
+
+ for (w=in->watches;w;w=next) {
+ next = w->next;
+ if (w->wd == e->wd && filter_match(w, e) &&
+ !(w->filter & FILE_NOTIFY_CHANGE_CREATION)) {
+ w->callback(in->ctx, w->private_data, &ne);
+ }
+ }
+}
+
+/*
+ called when the kernel has some events for us
+*/
+static void inotify_handler(struct event_context *ev, struct fd_event *fde,
+ uint16_t flags, void *private_data)
+{
+ struct inotify_private *in = talloc_get_type(private_data,
+ struct inotify_private);
+ int bufsize = 0;
+ struct inotify_event *e0, *e;
+ uint32_t prev_cookie=0;
+
+ /*
+ we must use FIONREAD as we cannot predict the length of the
+ filenames, and thus can't know how much to allocate
+ otherwise
+ */
+ if (ioctl(in->fd, FIONREAD, &bufsize) != 0 ||
+ bufsize == 0) {
+ DEBUG(0,("No data on inotify fd?!\n"));
+ return;
+ }
+
+ e0 = e = (struct inotify_event *)TALLOC_SIZE(in, bufsize);
+ if (e == NULL) return;
+
+ if (read(in->fd, e0, bufsize) != bufsize) {
+ DEBUG(0,("Failed to read all inotify data\n"));
+ talloc_free(e0);
+ return;
+ }
+
+ /* we can get more than one event in the buffer */
+ while (bufsize >= sizeof(*e)) {
+ struct inotify_event *e2 = NULL;
+ bufsize -= e->len + sizeof(*e);
+ if (bufsize >= sizeof(*e)) {
+ e2 = (struct inotify_event *)(e->len + sizeof(*e) + (char *)e);
+ }
+ inotify_dispatch(in, e, prev_cookie, e2);
+ prev_cookie = e->cookie;
+ e = e2;
+ }
+
+ talloc_free(e0);
+}
+
+/*
+ setup the inotify handle - called the first time a watch is added on
+ this context
+*/
+static NTSTATUS inotify_setup(struct sys_notify_context *ctx)
+{
+ struct inotify_private *in;
+
+ if (!lp_parm_bool(-1, "notify", "inotify", True)) {
+ return NT_STATUS_INVALID_SYSTEM_SERVICE;
+ }
+
+ in = talloc(ctx, struct inotify_private);
+ NT_STATUS_HAVE_NO_MEMORY(in);
+ in->fd = inotify_init();
+ if (in->fd == -1) {
+ DEBUG(0,("Failed to init inotify - %s\n", strerror(errno)));
+ talloc_free(in);
+ return map_nt_error_from_unix(errno);
+ }
+ in->ctx = ctx;
+ in->watches = NULL;
+
+ ctx->private_data = in;
+ talloc_set_destructor(in, inotify_destructor);
+
+ /* add a event waiting for the inotify fd to be readable */
+ event_add_fd(ctx->ev, in, in->fd, EVENT_FD_READ, inotify_handler, in);
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ map from a change notify mask to a inotify mask. Remove any bits
+ which we can handle
+*/
+static const struct {
+ uint32_t notify_mask;
+ uint32_t inotify_mask;
+} inotify_mapping[] = {
+ {FILE_NOTIFY_CHANGE_FILE_NAME, IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO},
+ {FILE_NOTIFY_CHANGE_DIR_NAME, IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO},
+ {FILE_NOTIFY_CHANGE_ATTRIBUTES, IN_ATTRIB|IN_MOVED_TO|IN_MOVED_FROM|IN_MODIFY},
+ {FILE_NOTIFY_CHANGE_LAST_WRITE, IN_ATTRIB},
+ {FILE_NOTIFY_CHANGE_LAST_ACCESS, IN_ATTRIB},
+ {FILE_NOTIFY_CHANGE_EA, IN_ATTRIB},
+ {FILE_NOTIFY_CHANGE_SECURITY, IN_ATTRIB}
+};
+
+static uint32_t inotify_map(struct notify_entry *e)
+{
+ int i;
+ uint32_t out=0;
+ for (i=0;i<ARRAY_SIZE(inotify_mapping);i++) {
+ if (inotify_mapping[i].notify_mask & e->filter) {
+ out |= inotify_mapping[i].inotify_mask;
+ e->filter &= ~inotify_mapping[i].notify_mask;
+ }
+ }
+ return out;
+}
+
+/*
+ destroy a watch
+*/
+static int watch_destructor(struct inotify_watch_context *w)
+{
+ struct inotify_private *in = w->in;
+ int wd = w->wd;
+ DLIST_REMOVE(w->in->watches, w);
+
+ /* only rm the watch if its the last one with this wd */
+ for (w=in->watches;w;w=w->next) {
+ if (w->wd == wd) break;
+ }
+ if (w == NULL) {
+ DEBUG(10, ("Deleting inotify watch %d\n", wd));
+ if (inotify_rm_watch(in->fd, wd) == -1) {
+ DEBUG(1, ("inotify_rm_watch returned %s\n",
+ strerror(errno)));
+ }
+
+ }
+ return 0;
+}
+
+
+/*
+ add a watch. The watch is removed when the caller calls
+ talloc_free() on *handle
+*/
+NTSTATUS inotify_watch(struct sys_notify_context *ctx,
+ struct notify_entry *e,
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev),
+ void *private_data,
+ void *handle_p)
+{
+ struct inotify_private *in;
+ int wd;
+ uint32_t mask;
+ struct inotify_watch_context *w;
+ uint32_t filter = e->filter;
+ void **handle = (void **)handle_p;
+
+ /* maybe setup the inotify fd */
+ if (ctx->private_data == NULL) {
+ NTSTATUS status;
+ status = inotify_setup(ctx);
+ NT_STATUS_NOT_OK_RETURN(status);
+ }
+
+ in = talloc_get_type(ctx->private_data, struct inotify_private);
+
+ mask = inotify_map(e);
+ if (mask == 0) {
+ /* this filter can't be handled by inotify */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* using IN_MASK_ADD allows us to cope with inotify() returning the same
+ watch descriptor for muliple watches on the same path */
+ mask |= (IN_MASK_ADD | IN_ONLYDIR);
+
+ /* get a new watch descriptor for this path */
+ wd = inotify_add_watch(in->fd, e->path, mask);
+ if (wd == -1) {
+ e->filter = filter;
+ DEBUG(1, ("inotify_add_watch returned %s\n", strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+
+ DEBUG(10, ("inotify_add_watch for %s mask %x returned wd %d\n",
+ e->path, mask, wd));
+
+ w = talloc(in, struct inotify_watch_context);
+ if (w == NULL) {
+ inotify_rm_watch(in->fd, wd);
+ e->filter = filter;
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ w->in = in;
+ w->wd = wd;
+ w->callback = callback;
+ w->private_data = private_data;
+ w->mask = mask;
+ w->filter = filter;
+ w->path = talloc_strdup(w, e->path);
+ if (w->path == NULL) {
+ inotify_rm_watch(in->fd, wd);
+ e->filter = filter;
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*handle) = w;
+
+ DLIST_ADD(in->watches, w);
+
+ /* the caller frees the handle to stop watching */
+ talloc_set_destructor(w, watch_destructor);
+
+ return NT_STATUS_OK;
+}
+
+#endif
diff --git a/source3/smbd/notify_internal.c b/source3/smbd/notify_internal.c
new file mode 100644
index 0000000000..84b8e1098e
--- /dev/null
+++ b/source3/smbd/notify_internal.c
@@ -0,0 +1,690 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ this is the change notify database. It implements mechanisms for
+ storing current change notify waiters in a tdb, and checking if a
+ given event matches any of the stored notify waiiters.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_notify.h"
+
+struct notify_context {
+ struct db_context *db;
+ struct server_id server;
+ struct messaging_context *messaging_ctx;
+ struct notify_list *list;
+ struct notify_array *array;
+ int seqnum;
+ struct sys_notify_context *sys_notify_ctx;
+ TDB_DATA key;
+};
+
+
+struct notify_list {
+ struct notify_list *next, *prev;
+ void *private_data;
+ void (*callback)(void *, const struct notify_event *);
+ void *sys_notify_handle;
+ int depth;
+};
+
+#define NOTIFY_KEY "notify array"
+
+#define NOTIFY_ENABLE "notify:enable"
+#define NOTIFY_ENABLE_DEFAULT True
+
+static NTSTATUS notify_remove_all(struct notify_context *notify,
+ const struct server_id *server);
+static void notify_handler(struct messaging_context *msg_ctx, void *private_data,
+ uint32_t msg_type, struct server_id server_id, DATA_BLOB *data);
+
+/*
+ destroy the notify context
+*/
+static int notify_destructor(struct notify_context *notify)
+{
+ messaging_deregister(notify->messaging_ctx, MSG_PVFS_NOTIFY, notify);
+
+ if (notify->list != NULL) {
+ notify_remove_all(notify, &notify->server);
+ }
+
+ return 0;
+}
+
+/*
+ Open up the notify.tdb database. You should close it down using
+ talloc_free(). We need the messaging_ctx to allow for notifications
+ via internal messages
+*/
+struct notify_context *notify_init(TALLOC_CTX *mem_ctx, struct server_id server,
+ struct messaging_context *messaging_ctx,
+ struct event_context *ev,
+ connection_struct *conn)
+{
+ struct notify_context *notify;
+
+ if (!lp_change_notify(conn->params)) {
+ return NULL;
+ }
+
+ notify = talloc(mem_ctx, struct notify_context);
+ if (notify == NULL) {
+ return NULL;
+ }
+
+ notify->db = db_open(notify, lock_path("notify.tdb"),
+ 0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST,
+ O_RDWR|O_CREAT, 0644);
+ if (notify->db == NULL) {
+ talloc_free(notify);
+ return NULL;
+ }
+
+ notify->server = server;
+ notify->messaging_ctx = messaging_ctx;
+ notify->list = NULL;
+ notify->array = NULL;
+ notify->seqnum = notify->db->get_seqnum(notify->db);
+ notify->key = string_term_tdb_data(NOTIFY_KEY);
+
+ talloc_set_destructor(notify, notify_destructor);
+
+ /* register with the messaging subsystem for the notify
+ message type */
+ messaging_register(notify->messaging_ctx, notify,
+ MSG_PVFS_NOTIFY, notify_handler);
+
+ notify->sys_notify_ctx = sys_notify_context_create(conn, notify, ev);
+
+ return notify;
+}
+
+/*
+ lock and fetch the record
+*/
+static NTSTATUS notify_fetch_locked(struct notify_context *notify, struct db_record **rec)
+{
+ *rec = notify->db->fetch_locked(notify->db, notify, notify->key);
+ if (*rec == NULL) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ return NT_STATUS_OK;
+}
+
+/*
+ load the notify array
+*/
+static NTSTATUS notify_load(struct notify_context *notify, struct db_record *rec)
+{
+ TDB_DATA dbuf;
+ DATA_BLOB blob;
+ NTSTATUS status;
+ int seqnum;
+
+ seqnum = notify->db->get_seqnum(notify->db);
+
+ if (seqnum == notify->seqnum && notify->array != NULL) {
+ return NT_STATUS_OK;
+ }
+
+ notify->seqnum = seqnum;
+
+ talloc_free(notify->array);
+ notify->array = TALLOC_ZERO_P(notify, struct notify_array);
+ NT_STATUS_HAVE_NO_MEMORY(notify->array);
+
+ if (!rec) {
+ if (notify->db->fetch(notify->db, notify, notify->key, &dbuf) != 0) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ } else {
+ dbuf = rec->value;
+ }
+
+ blob.data = (uint8 *)dbuf.dptr;
+ blob.length = dbuf.dsize;
+
+ status = NT_STATUS_OK;
+ if (blob.length > 0) {
+ enum ndr_err_code ndr_err;
+ ndr_err = ndr_pull_struct_blob(&blob, notify->array, notify->array,
+ (ndr_pull_flags_fn_t)ndr_pull_notify_array);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ }
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ DEBUG(10, ("notify_load:\n"));
+ NDR_PRINT_DEBUG(notify_array, notify->array);
+ }
+
+ if (!rec) {
+ talloc_free(dbuf.dptr);
+ }
+
+ return status;
+}
+
+/*
+ compare notify entries for sorting
+*/
+static int notify_compare(const void *p1, const void *p2)
+{
+ const struct notify_entry *e1 = (const struct notify_entry *)p1;
+ const struct notify_entry *e2 = (const struct notify_entry *)p2;
+ return strcmp(e1->path, e2->path);
+}
+
+/*
+ save the notify array
+*/
+static NTSTATUS notify_save(struct notify_context *notify, struct db_record *rec)
+{
+ TDB_DATA dbuf;
+ DATA_BLOB blob;
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ TALLOC_CTX *tmp_ctx;
+
+ /* if possible, remove some depth arrays */
+ while (notify->array->num_depths > 0 &&
+ notify->array->depth[notify->array->num_depths-1].num_entries == 0) {
+ notify->array->num_depths--;
+ }
+
+ /* we might just be able to delete the record */
+ if (notify->array->num_depths == 0) {
+ return rec->delete_rec(rec);
+ }
+
+ tmp_ctx = talloc_new(notify);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ ndr_err = ndr_push_struct_blob(&blob, tmp_ctx, notify->array,
+ (ndr_push_flags_fn_t)ndr_push_notify_array);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(tmp_ctx);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ DEBUG(10, ("notify_save:\n"));
+ NDR_PRINT_DEBUG(notify_array, notify->array);
+ }
+
+ dbuf.dptr = blob.data;
+ dbuf.dsize = blob.length;
+
+ status = rec->store(rec, dbuf, TDB_REPLACE);
+ talloc_free(tmp_ctx);
+
+ return status;
+}
+
+
+/*
+ handle incoming notify messages
+*/
+static void notify_handler(struct messaging_context *msg_ctx, void *private_data,
+ uint32_t msg_type, struct server_id server_id, DATA_BLOB *data)
+{
+ struct notify_context *notify = talloc_get_type(private_data, struct notify_context);
+ enum ndr_err_code ndr_err;
+ struct notify_event ev;
+ TALLOC_CTX *tmp_ctx = talloc_new(notify);
+ struct notify_list *listel;
+
+ if (tmp_ctx == NULL) {
+ return;
+ }
+
+ ndr_err = ndr_pull_struct_blob(data, tmp_ctx, &ev,
+ (ndr_pull_flags_fn_t)ndr_pull_notify_event);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ for (listel=notify->list;listel;listel=listel->next) {
+ if (listel->private_data == ev.private_data) {
+ listel->callback(listel->private_data, &ev);
+ break;
+ }
+ }
+
+ talloc_free(tmp_ctx);
+}
+
+/*
+ callback from sys_notify telling us about changes from the OS
+*/
+static void sys_notify_callback(struct sys_notify_context *ctx,
+ void *ptr, struct notify_event *ev)
+{
+ struct notify_list *listel = talloc_get_type(ptr, struct notify_list);
+ ev->private_data = listel;
+ DEBUG(10, ("sys_notify_callback called with action=%d, for %s\n",
+ ev->action, ev->path));
+ listel->callback(listel->private_data, ev);
+}
+
+/*
+ add an entry to the notify array
+*/
+static NTSTATUS notify_add_array(struct notify_context *notify, struct db_record *rec,
+ struct notify_entry *e,
+ void *private_data, int depth)
+{
+ int i;
+ struct notify_depth *d;
+ struct notify_entry *ee;
+
+ /* possibly expand the depths array */
+ if (depth >= notify->array->num_depths) {
+ d = talloc_realloc(notify->array, notify->array->depth,
+ struct notify_depth, depth+1);
+ NT_STATUS_HAVE_NO_MEMORY(d);
+ for (i=notify->array->num_depths;i<=depth;i++) {
+ ZERO_STRUCT(d[i]);
+ }
+ notify->array->depth = d;
+ notify->array->num_depths = depth+1;
+ }
+ d = &notify->array->depth[depth];
+
+ /* expand the entries array */
+ ee = talloc_realloc(notify->array->depth, d->entries, struct notify_entry,
+ d->num_entries+1);
+ NT_STATUS_HAVE_NO_MEMORY(ee);
+ d->entries = ee;
+
+ d->entries[d->num_entries] = *e;
+ d->entries[d->num_entries].private_data = private_data;
+ d->entries[d->num_entries].server = notify->server;
+ d->entries[d->num_entries].path_len = strlen(e->path);
+ d->num_entries++;
+
+ d->max_mask |= e->filter;
+ d->max_mask_subdir |= e->subdir_filter;
+
+ if (d->num_entries > 1) {
+ qsort(d->entries, d->num_entries, sizeof(d->entries[0]), notify_compare);
+ }
+
+ /* recalculate the maximum masks */
+ d->max_mask = 0;
+ d->max_mask_subdir = 0;
+
+ for (i=0;i<d->num_entries;i++) {
+ d->max_mask |= d->entries[i].filter;
+ d->max_mask_subdir |= d->entries[i].subdir_filter;
+ }
+
+ return notify_save(notify, rec);
+}
+
+/*
+ add a notify watch. This is called when a notify is first setup on a open
+ directory handle.
+*/
+NTSTATUS notify_add(struct notify_context *notify, struct notify_entry *e0,
+ void (*callback)(void *, const struct notify_event *),
+ void *private_data)
+{
+ struct notify_entry e = *e0;
+ NTSTATUS status;
+ char *tmp_path = NULL;
+ struct notify_list *listel;
+ size_t len;
+ int depth;
+ struct db_record *rec;
+
+ /* see if change notify is enabled at all */
+ if (notify == NULL) {
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ status = notify_fetch_locked(notify, &rec);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ status = notify_load(notify, rec);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(rec);
+ return status;
+ }
+
+ /* cope with /. on the end of the path */
+ len = strlen(e.path);
+ if (len > 1 && e.path[len-1] == '.' && e.path[len-2] == '/') {
+ tmp_path = talloc_strndup(notify, e.path, len-2);
+ if (tmp_path == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ e.path = tmp_path;
+ }
+
+ depth = count_chars(e.path, '/');
+
+ listel = TALLOC_ZERO_P(notify, struct notify_list);
+ if (listel == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ listel->private_data = private_data;
+ listel->callback = callback;
+ listel->depth = depth;
+ DLIST_ADD(notify->list, listel);
+
+ /* ignore failures from sys_notify */
+ if (notify->sys_notify_ctx != NULL) {
+ /*
+ this call will modify e.filter and e.subdir_filter
+ to remove bits handled by the backend
+ */
+ status = sys_notify_watch(notify->sys_notify_ctx, &e,
+ sys_notify_callback, listel,
+ &listel->sys_notify_handle);
+ if (NT_STATUS_IS_OK(status)) {
+ talloc_steal(listel, listel->sys_notify_handle);
+ }
+ }
+
+ /* if the system notify handler couldn't handle some of the
+ filter bits, or couldn't handle a request for recursion
+ then we need to install it in the array used for the
+ intra-samba notify handling */
+ if (e.filter != 0 || e.subdir_filter != 0) {
+ status = notify_add_array(notify, rec, &e, private_data, depth);
+ }
+
+done:
+ talloc_free(rec);
+ talloc_free(tmp_path);
+
+ return status;
+}
+
+/*
+ remove a notify watch. Called when the directory handle is closed
+*/
+NTSTATUS notify_remove(struct notify_context *notify, void *private_data)
+{
+ NTSTATUS status;
+ struct notify_list *listel;
+ int i, depth;
+ struct notify_depth *d;
+ struct db_record *rec;
+
+ /* see if change notify is enabled at all */
+ if (notify == NULL) {
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ for (listel=notify->list;listel;listel=listel->next) {
+ if (listel->private_data == private_data) {
+ DLIST_REMOVE(notify->list, listel);
+ break;
+ }
+ }
+ if (listel == NULL) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ depth = listel->depth;
+
+ talloc_free(listel);
+
+ status = notify_fetch_locked(notify, &rec);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ status = notify_load(notify, rec);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(rec);
+ return status;
+ }
+
+ if (depth >= notify->array->num_depths) {
+ talloc_free(rec);
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ /* we only have to search at the depth of this element */
+ d = &notify->array->depth[depth];
+
+ for (i=0;i<d->num_entries;i++) {
+ if (private_data == d->entries[i].private_data &&
+ cluster_id_equal(&notify->server, &d->entries[i].server)) {
+ break;
+ }
+ }
+ if (i == d->num_entries) {
+ talloc_free(rec);
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (i < d->num_entries-1) {
+ memmove(&d->entries[i], &d->entries[i+1],
+ sizeof(d->entries[i])*(d->num_entries-(i+1)));
+ }
+ d->num_entries--;
+
+ status = notify_save(notify, rec);
+
+ talloc_free(rec);
+
+ return status;
+}
+
+/*
+ remove all notify watches for a messaging server
+*/
+static NTSTATUS notify_remove_all(struct notify_context *notify,
+ const struct server_id *server)
+{
+ NTSTATUS status;
+ int i, depth, del_count=0;
+ struct db_record *rec;
+
+ status = notify_fetch_locked(notify, &rec);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ status = notify_load(notify, rec);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(rec);
+ return status;
+ }
+
+ /* we have to search for all entries across all depths, looking for matches
+ for the server id */
+ for (depth=0;depth<notify->array->num_depths;depth++) {
+ struct notify_depth *d = &notify->array->depth[depth];
+ for (i=0;i<d->num_entries;i++) {
+ if (cluster_id_equal(server, &d->entries[i].server)) {
+ if (i < d->num_entries-1) {
+ memmove(&d->entries[i], &d->entries[i+1],
+ sizeof(d->entries[i])*(d->num_entries-(i+1)));
+ }
+ i--;
+ d->num_entries--;
+ del_count++;
+ }
+ }
+ }
+
+ if (del_count > 0) {
+ status = notify_save(notify, rec);
+ }
+
+ talloc_free(rec);
+
+ return status;
+}
+
+
+/*
+ send a notify message to another messaging server
+*/
+static NTSTATUS notify_send(struct notify_context *notify, struct notify_entry *e,
+ const char *path, uint32_t action)
+{
+ struct notify_event ev;
+ DATA_BLOB data;
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ TALLOC_CTX *tmp_ctx;
+
+ ev.action = action;
+ ev.path = path;
+ ev.private_data = e->private_data;
+
+ tmp_ctx = talloc_new(notify);
+
+ ndr_err = ndr_push_struct_blob(&data, tmp_ctx, &ev,
+ (ndr_push_flags_fn_t)ndr_push_notify_event);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(tmp_ctx);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ status = messaging_send(notify->messaging_ctx, e->server,
+ MSG_PVFS_NOTIFY, &data);
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+
+/*
+ trigger a notify message for anyone waiting on a matching event
+
+ This function is called a lot, and needs to be very fast. The unusual data structure
+ and traversal is designed to be fast in the average case, even for large numbers of
+ notifies
+*/
+void notify_trigger(struct notify_context *notify,
+ uint32_t action, uint32_t filter, const char *path)
+{
+ NTSTATUS status;
+ int depth;
+ const char *p, *next_p;
+
+ DEBUG(10, ("notify_trigger called action=0x%x, filter=0x%x, "
+ "path=%s\n", (unsigned)action, (unsigned)filter, path));
+
+ /* see if change notify is enabled at all */
+ if (notify == NULL) {
+ return;
+ }
+
+ again:
+ status = notify_load(notify, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ return;
+ }
+
+ /* loop along the given path, working with each directory depth separately */
+ for (depth=0,p=path;
+ p && depth < notify->array->num_depths;
+ p=next_p,depth++) {
+ int p_len = p - path;
+ int min_i, max_i, i;
+ struct notify_depth *d = &notify->array->depth[depth];
+ next_p = strchr(p+1, '/');
+
+ /* see if there are any entries at this depth */
+ if (d->num_entries == 0) continue;
+
+ /* try to skip based on the maximum mask. If next_p is
+ NULL then we know it will be a 'this directory'
+ match, otherwise it must be a subdir match */
+ if (next_p != NULL) {
+ if (0 == (filter & d->max_mask_subdir)) {
+ continue;
+ }
+ } else {
+ if (0 == (filter & d->max_mask)) {
+ continue;
+ }
+ }
+
+ /* we know there is an entry here worth looking
+ for. Use a bisection search to find the first entry
+ with a matching path */
+ min_i = 0;
+ max_i = d->num_entries-1;
+
+ while (min_i < max_i) {
+ struct notify_entry *e;
+ int cmp;
+ i = (min_i+max_i)/2;
+ e = &d->entries[i];
+ cmp = strncmp(path, e->path, p_len);
+ if (cmp == 0) {
+ if (p_len == e->path_len) {
+ max_i = i;
+ } else {
+ max_i = i-1;
+ }
+ } else if (cmp < 0) {
+ max_i = i-1;
+ } else {
+ min_i = i+1;
+ }
+ }
+
+ if (min_i != max_i) {
+ /* none match */
+ continue;
+ }
+
+ /* we now know that the entries start at min_i */
+ for (i=min_i;i<d->num_entries;i++) {
+ struct notify_entry *e = &d->entries[i];
+ if (p_len != e->path_len ||
+ strncmp(path, e->path, p_len) != 0) break;
+ if (next_p != NULL) {
+ if (0 == (filter & e->subdir_filter)) {
+ continue;
+ }
+ } else {
+ if (0 == (filter & e->filter)) {
+ continue;
+ }
+ }
+ status = notify_send(notify, e, path + e->path_len + 1,
+ action);
+
+ if (NT_STATUS_EQUAL(
+ status, NT_STATUS_INVALID_HANDLE)) {
+ struct server_id server = e->server;
+
+ DEBUG(10, ("Deleting notify entries for "
+ "process %s because it's gone\n",
+ procid_str_static(&e->server)));
+ notify_remove_all(notify, &server);
+ goto again;
+ }
+ }
+ }
+}
diff --git a/source3/smbd/ntquotas.c b/source3/smbd/ntquotas.c
new file mode 100644
index 0000000000..c616c494dc
--- /dev/null
+++ b/source3/smbd/ntquotas.c
@@ -0,0 +1,247 @@
+/*
+ Unix SMB/CIFS implementation.
+ NT QUOTA suppport
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_QUOTA
+
+static SMB_BIG_UINT limit_nt2unix(SMB_BIG_UINT in, SMB_BIG_UINT bsize)
+{
+ SMB_BIG_UINT ret = (SMB_BIG_UINT)0;
+
+ ret = (SMB_BIG_UINT)(in/bsize);
+ if (in>0 && ret==0) {
+ /* we have to make sure that a overflow didn't set NO_LIMIT */
+ ret = (SMB_BIG_UINT)1;
+ }
+
+ if (in == SMB_NTQUOTAS_NO_LIMIT)
+ ret = SMB_QUOTAS_NO_LIMIT;
+ else if (in == SMB_NTQUOTAS_NO_SPACE)
+ ret = SMB_QUOTAS_NO_SPACE;
+ else if (in == SMB_NTQUOTAS_NO_ENTRY)
+ ret = SMB_QUOTAS_NO_LIMIT;
+
+ return ret;
+}
+
+static SMB_BIG_UINT limit_unix2nt(SMB_BIG_UINT in, SMB_BIG_UINT bsize)
+{
+ SMB_BIG_UINT ret = (SMB_BIG_UINT)0;
+
+ ret = (SMB_BIG_UINT)(in*bsize);
+
+ if (ret < in) {
+ /* we overflow */
+ ret = SMB_NTQUOTAS_NO_LIMIT;
+ }
+
+ if (in == SMB_QUOTAS_NO_LIMIT)
+ ret = SMB_NTQUOTAS_NO_LIMIT;
+
+ return ret;
+}
+
+static SMB_BIG_UINT limit_blk2inodes(SMB_BIG_UINT in)
+{
+ SMB_BIG_UINT ret = (SMB_BIG_UINT)0;
+
+ ret = (SMB_BIG_UINT)(in/2);
+
+ if (ret == 0 && in != 0)
+ ret = (SMB_BIG_UINT)1;
+
+ return ret;
+}
+
+int vfs_get_ntquota(files_struct *fsp, enum SMB_QUOTA_TYPE qtype, DOM_SID *psid, SMB_NTQUOTA_STRUCT *qt)
+{
+ int ret;
+ SMB_DISK_QUOTA D;
+ unid_t id;
+
+ ZERO_STRUCT(D);
+
+ if (!fsp||!fsp->conn||!qt)
+ return (-1);
+
+ ZERO_STRUCT(*qt);
+
+ id.uid = -1;
+
+ if (psid && !sid_to_uid(psid, &id.uid)) {
+ DEBUG(0,("sid_to_uid: failed, SID[%s]\n",
+ sid_string_dbg(psid)));
+ }
+
+ ret = SMB_VFS_GET_QUOTA(fsp->conn, qtype, id, &D);
+
+ if (psid)
+ qt->sid = *psid;
+
+ if (ret!=0) {
+ return ret;
+ }
+
+ qt->usedspace = (SMB_BIG_UINT)D.curblocks*D.bsize;
+ qt->softlim = limit_unix2nt(D.softlimit, D.bsize);
+ qt->hardlim = limit_unix2nt(D.hardlimit, D.bsize);
+ qt->qflags = D.qflags;
+
+
+ return 0;
+}
+
+int vfs_set_ntquota(files_struct *fsp, enum SMB_QUOTA_TYPE qtype, DOM_SID *psid, SMB_NTQUOTA_STRUCT *qt)
+{
+ int ret;
+ SMB_DISK_QUOTA D;
+ unid_t id;
+ ZERO_STRUCT(D);
+
+ if (!fsp||!fsp->conn||!qt)
+ return (-1);
+
+ id.uid = -1;
+
+ D.bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
+
+ D.softlimit = limit_nt2unix(qt->softlim,D.bsize);
+ D.hardlimit = limit_nt2unix(qt->hardlim,D.bsize);
+ D.qflags = qt->qflags;
+
+ D.isoftlimit = limit_blk2inodes(D.softlimit);
+ D.ihardlimit = limit_blk2inodes(D.hardlimit);
+
+ if (psid && !sid_to_uid(psid, &id.uid)) {
+ DEBUG(0,("sid_to_uid: failed, SID[%s]\n",
+ sid_string_dbg(psid)));
+ }
+
+ ret = SMB_VFS_SET_QUOTA(fsp->conn, qtype, id, &D);
+
+ return ret;
+}
+
+static bool allready_in_quota_list(SMB_NTQUOTA_LIST *qt_list, uid_t uid)
+{
+ SMB_NTQUOTA_LIST *tmp_list = NULL;
+
+ if (!qt_list)
+ return False;
+
+ for (tmp_list=qt_list;tmp_list!=NULL;tmp_list=tmp_list->next) {
+ if (tmp_list->uid == uid) {
+ return True;
+ }
+ }
+
+ return False;
+}
+
+int vfs_get_user_ntquota_list(files_struct *fsp, SMB_NTQUOTA_LIST **qt_list)
+{
+ struct passwd *usr;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if (!fsp||!fsp->conn||!qt_list)
+ return (-1);
+
+ *qt_list = NULL;
+
+ if ((mem_ctx=talloc_init("SMB_USER_QUOTA_LIST"))==NULL) {
+ DEBUG(0,("talloc_init() failed\n"));
+ return (-1);
+ }
+
+ sys_setpwent();
+ while ((usr = sys_getpwent()) != NULL) {
+ SMB_NTQUOTA_STRUCT tmp_qt;
+ SMB_NTQUOTA_LIST *tmp_list_ent;
+ DOM_SID sid;
+
+ ZERO_STRUCT(tmp_qt);
+
+ if (allready_in_quota_list((*qt_list),usr->pw_uid)) {
+ DEBUG(5,("record for uid[%ld] allready in the list\n",(long)usr->pw_uid));
+ continue;
+ }
+
+ uid_to_sid(&sid, usr->pw_uid);
+
+ if (vfs_get_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &tmp_qt)!=0) {
+ DEBUG(5,("no quota entry for sid[%s] path[%s]\n",
+ sid_string_dbg(&sid),
+ fsp->conn->connectpath));
+ continue;
+ }
+
+ DEBUG(15,("quota entry for id[%s] path[%s]\n",
+ sid_string_dbg(&sid), fsp->conn->connectpath));
+
+ if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
+ DEBUG(0,("TALLOC_ZERO() failed\n"));
+ *qt_list = NULL;
+ talloc_destroy(mem_ctx);
+ return (-1);
+ }
+
+ if ((tmp_list_ent->quotas=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
+ DEBUG(0,("TALLOC_ZERO() failed\n"));
+ *qt_list = NULL;
+ talloc_destroy(mem_ctx);
+ return (-1);
+ }
+
+ tmp_list_ent->uid = usr->pw_uid;
+ memcpy(tmp_list_ent->quotas,&tmp_qt,sizeof(tmp_qt));
+ tmp_list_ent->mem_ctx = mem_ctx;
+
+ DLIST_ADD((*qt_list),tmp_list_ent);
+
+ }
+ sys_endpwent();
+
+ return 0;
+}
+
+static int quota_handle_destructor(SMB_NTQUOTA_HANDLE *handle)
+{
+ if (handle->quota_list)
+ free_ntquota_list(&handle->quota_list);
+ return 0;
+}
+
+void *init_quota_handle(TALLOC_CTX *mem_ctx)
+{
+ SMB_NTQUOTA_HANDLE *qt_handle;
+
+ if (!mem_ctx)
+ return False;
+
+ qt_handle = TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_HANDLE);
+ if (qt_handle==NULL) {
+ DEBUG(0,("TALLOC_ZERO() failed\n"));
+ return NULL;
+ }
+
+ talloc_set_destructor(qt_handle, quota_handle_destructor);
+ return (void *)qt_handle;
+}
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
new file mode 100644
index 0000000000..584399c86c
--- /dev/null
+++ b/source3/smbd/nttrans.c
@@ -0,0 +1,2864 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB NT transaction handling
+ Copyright (C) Jeremy Allison 1994-2007
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern int max_send;
+extern enum protocol_types Protocol;
+
+static char *nttrans_realloc(char **ptr, size_t size)
+{
+ if (ptr==NULL) {
+ smb_panic("nttrans_realloc() called with NULL ptr");
+ }
+
+ *ptr = (char *)SMB_REALLOC(*ptr, size);
+ if(*ptr == NULL) {
+ return NULL;
+ }
+ memset(*ptr,'\0',size);
+ return *ptr;
+}
+
+/****************************************************************************
+ 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.
+****************************************************************************/
+
+void send_nt_replies(connection_struct *conn,
+ struct smb_request *req, NTSTATUS nt_error,
+ char *params, int paramsize,
+ char *pdata, int datasize)
+{
+ 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;
+
+ /*
+ * If there genuinely are no parameters or data to send just send
+ * the empty packet.
+ */
+
+ if(params_to_send == 0 && data_to_send == 0) {
+ reply_outbuf(req, 18, 0);
+ show_msg((char *)req->outbuf);
+ return;
+ }
+
+ /*
+ * 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 = max_send - (smb_size
+ + 2 * 18 /* wct */
+ + alignment_offset
+ + data_alignment_offset);
+
+ if (useable_space < 0) {
+ DEBUG(0, ("send_nt_replies failed sanity useable_space "
+ "= %d!!!", useable_space));
+ exit_server_cleanly("send_nt_replies: srv_send_smb failed.");
+ }
+
+ 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;
+
+ /*
+ * We can never send more than useable_space.
+ */
+
+ total_sent_thistime = MIN(total_sent_thistime, useable_space);
+
+ reply_outbuf(req, 18,
+ total_sent_thistime + alignment_offset
+ + data_alignment_offset);
+
+ /*
+ * Set total params and data to be sent.
+ */
+
+ SIVAL(req->outbuf,smb_ntr_TotalParameterCount,paramsize);
+ SIVAL(req->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(req->outbuf, smb_ntr_ParameterCount,
+ params_sent_thistime);
+
+ if(params_sent_thistime == 0) {
+ SIVAL(req->outbuf,smb_ntr_ParameterOffset,0);
+ SIVAL(req->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(req->outbuf,smb_ntr_ParameterOffset,
+ ((smb_buf(req->outbuf)+alignment_offset)
+ - smb_base(req->outbuf)));
+ /*
+ * Absolute displacement of param bytes sent in this packet.
+ */
+
+ SIVAL(req->outbuf, smb_ntr_ParameterDisplacement,
+ pp - params);
+ }
+
+ /*
+ * Deal with the data portion.
+ */
+
+ SIVAL(req->outbuf, smb_ntr_DataCount, data_sent_thistime);
+
+ if(data_sent_thistime == 0) {
+ SIVAL(req->outbuf,smb_ntr_DataOffset,0);
+ SIVAL(req->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(req->outbuf, smb_ntr_DataOffset,
+ ((smb_buf(req->outbuf)+alignment_offset) -
+ smb_base(req->outbuf))
+ + params_sent_thistime + data_alignment_offset);
+ SIVAL(req->outbuf,smb_ntr_DataDisplacement, pd - pdata);
+ }
+
+ /*
+ * Copy the param bytes into the packet.
+ */
+
+ if(params_sent_thistime) {
+ if (alignment_offset != 0) {
+ memset(smb_buf(req->outbuf), 0,
+ alignment_offset);
+ }
+ memcpy((smb_buf(req->outbuf)+alignment_offset), pp,
+ params_sent_thistime);
+ }
+
+ /*
+ * Copy in the data bytes
+ */
+
+ if(data_sent_thistime) {
+ if (data_alignment_offset != 0) {
+ memset((smb_buf(req->outbuf)+alignment_offset+
+ params_sent_thistime), 0,
+ data_alignment_offset);
+ }
+ memcpy(smb_buf(req->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));
+
+ if (NT_STATUS_V(nt_error)) {
+ error_packet_set((char *)req->outbuf,
+ 0, 0, nt_error,
+ __LINE__,__FILE__);
+ }
+
+ /* Send the packet */
+ show_msg((char *)req->outbuf);
+ if (!srv_send_smb(smbd_server_fd(),
+ (char *)req->outbuf,
+ IS_CONN_ENCRYPTED(conn))) {
+ exit_server_cleanly("send_nt_replies: srv_send_smb failed.");
+ }
+
+ TALLOC_FREE(req->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));
+ exit_server_cleanly("send_nt_replies: internal error");
+ }
+ }
+}
+
+/****************************************************************************
+ Is it an NTFS stream name ?
+ An NTFS file name is <path>.<extention>:<stream name>:<stream type>
+ $DATA can be used as both a stream name and a stream type. A missing stream
+ name or type implies $DATA.
+****************************************************************************/
+
+bool is_ntfs_stream_name(const char *fname)
+{
+ if (lp_posix_pathnames()) {
+ return False;
+ }
+ return (strchr_m(fname, ':') != NULL) ? True : False;
+}
+
+/****************************************************************************
+ Reply to an NT create and X call on a pipe
+****************************************************************************/
+
+static void nt_open_pipe(char *fname, connection_struct *conn,
+ struct smb_request *req, int *ppnum)
+{
+ smb_np_struct *p = NULL;
+
+ DEBUG(4,("nt_open_pipe: Opening pipe %s.\n", fname));
+
+ /* See if it is one we want to handle. */
+
+ if (!is_known_pipename(fname)) {
+ reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERRbadpipe);
+ return;
+ }
+
+ /* Strip \\ off the name. */
+ fname++;
+
+ DEBUG(3,("nt_open_pipe: Known pipe %s opening.\n", fname));
+
+ p = open_rpc_pipe_p(fname, conn, req->vuid);
+ if (!p) {
+ reply_doserror(req, ERRSRV, ERRnofids);
+ return;
+ }
+
+ /* TODO: Add pipe to db */
+
+ if ( !store_pipe_opendb( p ) ) {
+ DEBUG(3,("nt_open_pipe: failed to store %s pipe open.\n", fname));
+ }
+
+ *ppnum = p->pnum;
+ return;
+}
+
+/****************************************************************************
+ Reply to an NT create and X call for pipes.
+****************************************************************************/
+
+static void do_ntcreate_pipe_open(connection_struct *conn,
+ struct smb_request *req)
+{
+ char *fname = NULL;
+ int pnum = -1;
+ char *p = NULL;
+ uint32 flags = IVAL(req->inbuf,smb_ntcreate_Flags);
+ TALLOC_CTX *ctx = talloc_tos();
+
+ srvstr_pull_buf_talloc(ctx, (char *)req->inbuf, req->flags2, &fname,
+ smb_buf(req->inbuf), STR_TERMINATE);
+
+ if (!fname) {
+ reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERRbadpipe);
+ return;
+ }
+ nt_open_pipe(fname, conn, req, &pnum);
+
+ if (req->outbuf) {
+ /* error reply */
+ return;
+ }
+
+ /*
+ * Deal with pipe return.
+ */
+
+ if (flags & EXTENDED_RESPONSE_REQUIRED) {
+ /* This is very strange. We
+ * return 50 words, but only set
+ * the wcnt to 42 ? It's definately
+ * what happens on the wire....
+ */
+ reply_outbuf(req, 50, 0);
+ SCVAL(req->outbuf,smb_wct,42);
+ } else {
+ reply_outbuf(req, 34, 0);
+ }
+
+ p = (char *)req->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); /* ? */
+ p += 4;
+
+ if (flags & EXTENDED_RESPONSE_REQUIRED) {
+ p += 25;
+ SIVAL(p,0,FILE_GENERIC_ALL);
+ /*
+ * For pipes W2K3 seems to return
+ * 0x12019B next.
+ * This is ((FILE_GENERIC_READ|FILE_GENERIC_WRITE) & ~FILE_APPEND_DATA)
+ */
+ SIVAL(p,4,(FILE_GENERIC_READ|FILE_GENERIC_WRITE)&~FILE_APPEND_DATA);
+ }
+
+ DEBUG(5,("do_ntcreate_pipe_open: open pipe = %s\n", fname));
+
+ chain_reply(req);
+}
+
+/****************************************************************************
+ Reply to an NT create and X call.
+****************************************************************************/
+
+void reply_ntcreate_and_X(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ char *fname = NULL;
+ uint32 flags;
+ uint32 access_mask;
+ uint32 file_attributes;
+ uint32 share_access;
+ uint32 create_disposition;
+ uint32 create_options;
+ uint16 root_dir_fid;
+ SMB_BIG_UINT allocation_size;
+ /* Breakout the oplock request bits so we can set the
+ reply bits separately. */
+ uint32 fattr=0;
+ SMB_OFF_T file_len = 0;
+ SMB_STRUCT_STAT sbuf;
+ int info = 0;
+ files_struct *fsp = NULL;
+ char *p = NULL;
+ struct timespec c_timespec;
+ struct timespec a_timespec;
+ struct timespec m_timespec;
+ NTSTATUS status;
+ int oplock_request;
+ uint8_t oplock_granted = NO_OPLOCK_RETURN;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ START_PROFILE(SMBntcreateX);
+
+ if (req->wct < 24) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ flags = IVAL(req->inbuf,smb_ntcreate_Flags);
+ access_mask = IVAL(req->inbuf,smb_ntcreate_DesiredAccess);
+ file_attributes = IVAL(req->inbuf,smb_ntcreate_FileAttributes);
+ share_access = IVAL(req->inbuf,smb_ntcreate_ShareAccess);
+ create_disposition = IVAL(req->inbuf,smb_ntcreate_CreateDisposition);
+ create_options = IVAL(req->inbuf,smb_ntcreate_CreateOptions);
+ root_dir_fid = (uint16)IVAL(req->inbuf,smb_ntcreate_RootDirectoryFid);
+
+ allocation_size = (SMB_BIG_UINT)IVAL(req->inbuf,
+ smb_ntcreate_AllocationSize);
+#ifdef LARGE_SMB_OFF_T
+ allocation_size |= (((SMB_BIG_UINT)IVAL(
+ req->inbuf,
+ smb_ntcreate_AllocationSize + 4)) << 32);
+#endif
+
+ srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
+ smb_buf(req->inbuf), 0, STR_TERMINATE, &status);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBntcreateX);
+ return;
+ }
+
+ DEBUG(10,("reply_ntcreate_and_X: flags = 0x%x, access_mask = 0x%x "
+ "file_attributes = 0x%x, share_access = 0x%x, "
+ "create_disposition = 0x%x create_options = 0x%x "
+ "root_dir_fid = 0x%x, fname = %s\n",
+ (unsigned int)flags,
+ (unsigned int)access_mask,
+ (unsigned int)file_attributes,
+ (unsigned int)share_access,
+ (unsigned int)create_disposition,
+ (unsigned int)create_options,
+ (unsigned int)root_dir_fid,
+ fname));
+
+ /*
+ * we need to remove ignored bits when they come directly from the client
+ * because we reuse some of them for internal stuff
+ */
+ create_options &= ~NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
+
+ /*
+ * If it's an IPC, use the pipe handler.
+ */
+
+ if (IS_IPC(conn)) {
+ if (lp_nt_pipe_support()) {
+ do_ntcreate_pipe_open(conn, req);
+ END_PROFILE(SMBntcreateX);
+ return;
+ }
+ reply_doserror(req, ERRDOS, ERRnoaccess);
+ END_PROFILE(SMBntcreateX);
+ return;
+ }
+
+ oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
+ if (oplock_request) {
+ oplock_request |= (flags & REQUEST_BATCH_OPLOCK)
+ ? BATCH_OPLOCK : 0;
+ }
+
+ status = create_file(conn, req, root_dir_fid, fname,
+ access_mask, share_access, create_disposition,
+ create_options, file_attributes, oplock_request,
+ allocation_size, NULL, NULL, &fsp, &info, &sbuf);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ if (open_was_deferred(req->mid)) {
+ /* We have re-scheduled this call, no error. */
+ END_PROFILE(SMBntcreateX);
+ return;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+ reply_botherror(req, status, ERRDOS, ERRfilexists);
+ }
+ else {
+ reply_nterror(req, status);
+ }
+ END_PROFILE(SMBntcreateX);
+ return;
+ }
+
+ /*
+ * 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))
+ || EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))) {
+
+ /*
+ * Exclusive oplock granted
+ */
+
+ if (flags & REQUEST_BATCH_OPLOCK) {
+ oplock_granted = BATCH_OPLOCK_RETURN;
+ } else {
+ oplock_granted = EXCLUSIVE_OPLOCK_RETURN;
+ }
+ } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
+ oplock_granted = LEVEL_II_OPLOCK_RETURN;
+ } else {
+ oplock_granted = NO_OPLOCK_RETURN;
+ }
+
+ file_len = sbuf.st_size;
+ fattr = dos_mode(conn,fsp->fsp_name,&sbuf);
+ if (fattr == 0) {
+ fattr = FILE_ATTRIBUTE_NORMAL;
+ }
+
+ if (flags & EXTENDED_RESPONSE_REQUIRED) {
+ /* This is very strange. We
+ * return 50 words, but only set
+ * the wcnt to 42 ? It's definately
+ * what happens on the wire....
+ */
+ reply_outbuf(req, 50, 0);
+ SCVAL(req->outbuf,smb_wct,42);
+ } else {
+ reply_outbuf(req, 34, 0);
+ }
+
+ p = (char *)req->outbuf + smb_vwv2;
+
+ SCVAL(p, 0, oplock_granted);
+
+ p++;
+ SSVAL(p,0,fsp->fnum);
+ p += 2;
+ if ((create_disposition == FILE_SUPERSEDE)
+ && (info == FILE_WAS_OVERWRITTEN)) {
+ SIVAL(p,0,FILE_WAS_SUPERSEDED);
+ } else {
+ SIVAL(p,0,info);
+ }
+ p += 4;
+
+ /* Create time. */
+ c_timespec = get_create_timespec(
+ &sbuf,lp_fake_dir_create_times(SNUM(conn)));
+ a_timespec = get_atimespec(&sbuf);
+ m_timespec = get_mtimespec(&sbuf);
+
+ if (lp_dos_filetime_resolution(SNUM(conn))) {
+ dos_filetime_timespec(&c_timespec);
+ dos_filetime_timespec(&a_timespec);
+ dos_filetime_timespec(&m_timespec);
+ }
+
+ put_long_date_timespec(p, c_timespec); /* create time. */
+ p += 8;
+ put_long_date_timespec(p, a_timespec); /* access time */
+ p += 8;
+ put_long_date_timespec(p, m_timespec); /* write time */
+ p += 8;
+ put_long_date_timespec(p, m_timespec); /* change time */
+ p += 8;
+ SIVAL(p,0,fattr); /* File Attributes. */
+ p += 4;
+ SOFF_T(p, 0, get_allocation_size(conn,fsp,&sbuf));
+ p += 8;
+ SOFF_T(p,0,file_len);
+ p += 8;
+ if (flags & EXTENDED_RESPONSE_REQUIRED) {
+ SSVAL(p,2,0x7);
+ }
+ p += 4;
+ SCVAL(p,0,fsp->is_directory ? 1 : 0);
+
+ if (flags & EXTENDED_RESPONSE_REQUIRED) {
+ uint32 perms = 0;
+ p += 25;
+ if (fsp->is_directory
+ || can_write_to_file(conn, fsp->fsp_name, &sbuf)) {
+ perms = FILE_GENERIC_ALL;
+ } else {
+ perms = FILE_GENERIC_READ|FILE_EXECUTE;
+ }
+ SIVAL(p,0,perms);
+ }
+
+ DEBUG(5,("reply_ntcreate_and_X: fnum = %d, open name = %s\n",
+ fsp->fnum, fsp->fsp_name));
+
+ chain_reply(req);
+ END_PROFILE(SMBntcreateX);
+ return;
+}
+
+/****************************************************************************
+ Reply to a NT_TRANSACT_CREATE call to open a pipe.
+****************************************************************************/
+
+static void do_nt_transact_create_pipe(connection_struct *conn,
+ struct smb_request *req,
+ uint16 **ppsetup, uint32 setup_count,
+ char **ppparams, uint32 parameter_count,
+ char **ppdata, uint32 data_count)
+{
+ char *fname = NULL;
+ char *params = *ppparams;
+ int pnum = -1;
+ char *p = NULL;
+ NTSTATUS status;
+ size_t param_len;
+ uint32 flags;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ /*
+ * Ensure minimum number of parameters sent.
+ */
+
+ if(parameter_count < 54) {
+ DEBUG(0,("do_nt_transact_create_pipe - insufficient parameters (%u)\n", (unsigned int)parameter_count));
+ reply_doserror(req, ERRDOS, ERRnoaccess);
+ return;
+ }
+
+ flags = IVAL(params,0);
+
+ srvstr_get_path(ctx, params, req->flags2, &fname, params+53,
+ parameter_count-53, STR_TERMINATE,
+ &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+
+ nt_open_pipe(fname, conn, req, &pnum);
+
+ if (req->outbuf) {
+ /* Error return */
+ return;
+ }
+
+ /* Realloc the size of parameters and data we will return */
+ if (flags & EXTENDED_RESPONSE_REQUIRED) {
+ /* Extended response is 32 more byyes. */
+ param_len = 101;
+ } else {
+ param_len = 69;
+ }
+ params = nttrans_realloc(ppparams, param_len);
+ if(params == NULL) {
+ reply_doserror(req, ERRDOS, ERRnomem);
+ return;
+ }
+
+ p = params;
+ SCVAL(p,0,NO_OPLOCK_RETURN);
+
+ p += 2;
+ SSVAL(p,0,pnum);
+ p += 2;
+ SIVAL(p,0,FILE_WAS_OPENED);
+ p += 8;
+
+ p += 32;
+ SIVAL(p,0,FILE_ATTRIBUTE_NORMAL); /* File Attributes. */
+ p += 20;
+ /* File type. */
+ SSVAL(p,0,FILE_TYPE_MESSAGE_MODE_PIPE);
+ /* Device state. */
+ SSVAL(p,2, 0x5FF); /* ? */
+ p += 4;
+
+ if (flags & EXTENDED_RESPONSE_REQUIRED) {
+ p += 25;
+ SIVAL(p,0,FILE_GENERIC_ALL);
+ /*
+ * For pipes W2K3 seems to return
+ * 0x12019B next.
+ * This is ((FILE_GENERIC_READ|FILE_GENERIC_WRITE) & ~FILE_APPEND_DATA)
+ */
+ SIVAL(p,4,(FILE_GENERIC_READ|FILE_GENERIC_WRITE)&~FILE_APPEND_DATA);
+ }
+
+ DEBUG(5,("do_nt_transact_create_pipe: open name = %s\n", fname));
+
+ /* Send the required number of replies */
+ send_nt_replies(conn, req, NT_STATUS_OK, params, param_len, *ppdata, 0);
+
+ return;
+}
+
+/****************************************************************************
+ Internal fn to set security descriptors.
+****************************************************************************/
+
+static NTSTATUS set_sd(files_struct *fsp, uint8 *data, uint32 sd_len,
+ uint32 security_info_sent)
+{
+ SEC_DESC *psd = NULL;
+ NTSTATUS status;
+
+ if (sd_len == 0 || !lp_nt_acl_support(SNUM(fsp->conn))) {
+ return NT_STATUS_OK;
+ }
+
+ status = unmarshall_sec_desc(talloc_tos(), data, sd_len, &psd);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (psd->owner_sid==0) {
+ security_info_sent &= ~OWNER_SECURITY_INFORMATION;
+ }
+ if (psd->group_sid==0) {
+ security_info_sent &= ~GROUP_SECURITY_INFORMATION;
+ }
+ if (psd->sacl==0) {
+ security_info_sent &= ~SACL_SECURITY_INFORMATION;
+ }
+ if (psd->dacl==0) {
+ security_info_sent &= ~DACL_SECURITY_INFORMATION;
+ }
+
+ status = SMB_VFS_FSET_NT_ACL(fsp, security_info_sent, psd);
+
+ TALLOC_FREE(psd);
+
+ return status;
+}
+
+/****************************************************************************
+ Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
+****************************************************************************/
+
+static struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
+{
+ struct ea_list *ea_list_head = NULL;
+ size_t offset = 0;
+
+ if (data_size < 4) {
+ return NULL;
+ }
+
+ while (offset + 4 <= data_size) {
+ size_t next_offset = IVAL(pdata,offset);
+ struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset + 4, data_size - offset - 4, NULL);
+
+ if (!eal) {
+ return NULL;
+ }
+
+ DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
+ if (next_offset == 0) {
+ break;
+ }
+ offset += next_offset;
+ }
+
+ return ea_list_head;
+}
+
+/****************************************************************************
+ Reply to a NT_TRANSACT_CREATE call (needs to process SD's).
+****************************************************************************/
+
+static void call_nt_transact_create(connection_struct *conn,
+ struct smb_request *req,
+ uint16 **ppsetup, uint32 setup_count,
+ char **ppparams, uint32 parameter_count,
+ char **ppdata, uint32 data_count,
+ uint32 max_data_count)
+{
+ char *fname = NULL;
+ char *params = *ppparams;
+ char *data = *ppdata;
+ /* Breakout the oplock request bits so we can set the reply bits separately. */
+ uint32 fattr=0;
+ SMB_OFF_T file_len = 0;
+ SMB_STRUCT_STAT sbuf;
+ int info = 0;
+ files_struct *fsp = NULL;
+ char *p = NULL;
+ uint32 flags;
+ uint32 access_mask;
+ uint32 file_attributes;
+ uint32 share_access;
+ uint32 create_disposition;
+ uint32 create_options;
+ uint32 sd_len;
+ struct security_descriptor *sd = NULL;
+ uint32 ea_len;
+ uint16 root_dir_fid;
+ struct timespec c_timespec;
+ struct timespec a_timespec;
+ struct timespec m_timespec;
+ struct ea_list *ea_list = NULL;
+ NTSTATUS status;
+ size_t param_len;
+ SMB_BIG_UINT allocation_size;
+ int oplock_request;
+ uint8_t oplock_granted;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ DEBUG(5,("call_nt_transact_create\n"));
+
+ /*
+ * If it's an IPC, use the pipe handler.
+ */
+
+ if (IS_IPC(conn)) {
+ if (lp_nt_pipe_support()) {
+ do_nt_transact_create_pipe(
+ conn, req,
+ ppsetup, setup_count,
+ ppparams, parameter_count,
+ ppdata, data_count);
+ return;
+ }
+ reply_doserror(req, ERRDOS, ERRnoaccess);
+ return;
+ }
+
+ /*
+ * Ensure minimum number of parameters sent.
+ */
+
+ if(parameter_count < 54) {
+ DEBUG(0,("call_nt_transact_create - insufficient parameters (%u)\n", (unsigned int)parameter_count));
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ flags = IVAL(params,0);
+ access_mask = IVAL(params,8);
+ file_attributes = IVAL(params,20);
+ share_access = IVAL(params,24);
+ create_disposition = IVAL(params,28);
+ create_options = IVAL(params,32);
+ sd_len = IVAL(params,36);
+ ea_len = IVAL(params,40);
+ root_dir_fid = (uint16)IVAL(params,4);
+ allocation_size = (SMB_BIG_UINT)IVAL(params,12);
+#ifdef LARGE_SMB_OFF_T
+ allocation_size |= (((SMB_BIG_UINT)IVAL(params,16)) << 32);
+#endif
+
+ /*
+ * we need to remove ignored bits when they come directly from the client
+ * because we reuse some of them for internal stuff
+ */
+ create_options &= ~NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
+
+ /* Ensure the data_len is correct for the sd and ea values given. */
+ if ((ea_len + sd_len > data_count)
+ || (ea_len > data_count) || (sd_len > data_count)
+ || (ea_len + sd_len < ea_len) || (ea_len + sd_len < sd_len)) {
+ DEBUG(10, ("call_nt_transact_create - ea_len = %u, sd_len = "
+ "%u, data_count = %u\n", (unsigned int)ea_len,
+ (unsigned int)sd_len, (unsigned int)data_count));
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ if (sd_len) {
+ DEBUG(10, ("call_nt_transact_create - sd_len = %d\n",
+ sd_len));
+
+ status = unmarshall_sec_desc(ctx, (uint8_t *)data, sd_len,
+ &sd);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("call_nt_transact_create: "
+ "unmarshall_sec_desc failed: %s\n",
+ nt_errstr(status)));
+ reply_nterror(req, status);
+ return;
+ }
+ }
+
+ if (ea_len) {
+ if (!lp_ea_support(SNUM(conn))) {
+ DEBUG(10, ("call_nt_transact_create - ea_len = %u but "
+ "EA's not supported.\n",
+ (unsigned int)ea_len));
+ reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
+ return;
+ }
+
+ if (ea_len < 10) {
+ DEBUG(10,("call_nt_transact_create - ea_len = %u - "
+ "too small (should be more than 10)\n",
+ (unsigned int)ea_len ));
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ /* We have already checked that ea_len <= data_count here. */
+ ea_list = read_nttrans_ea_list(talloc_tos(), data + sd_len,
+ ea_len);
+ if (ea_list == NULL) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+ }
+
+ srvstr_get_path(ctx, params, req->flags2, &fname,
+ params+53, parameter_count-53,
+ STR_TERMINATE, &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+
+ oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
+ if (oplock_request) {
+ oplock_request |= (flags & REQUEST_BATCH_OPLOCK)
+ ? BATCH_OPLOCK : 0;
+ }
+
+ status = create_file(conn, req, root_dir_fid, fname,
+ access_mask, share_access, create_disposition,
+ create_options, file_attributes, oplock_request,
+ allocation_size, sd, ea_list, &fsp, &info, &sbuf);
+
+ if(!NT_STATUS_IS_OK(status)) {
+ if (open_was_deferred(req->mid)) {
+ /* We have re-scheduled this call, no error. */
+ return;
+ }
+ reply_openerror(req, status);
+ return;
+ }
+
+ /*
+ * 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))
+ || EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))) {
+
+ /*
+ * Exclusive oplock granted
+ */
+
+ if (flags & REQUEST_BATCH_OPLOCK) {
+ oplock_granted = BATCH_OPLOCK_RETURN;
+ } else {
+ oplock_granted = EXCLUSIVE_OPLOCK_RETURN;
+ }
+ } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
+ oplock_granted = LEVEL_II_OPLOCK_RETURN;
+ } else {
+ oplock_granted = NO_OPLOCK_RETURN;
+ }
+
+ file_len = sbuf.st_size;
+ fattr = dos_mode(conn,fsp->fsp_name,&sbuf);
+ if (fattr == 0) {
+ fattr = FILE_ATTRIBUTE_NORMAL;
+ }
+
+ /* Realloc the size of parameters and data we will return */
+ if (flags & EXTENDED_RESPONSE_REQUIRED) {
+ /* Extended response is 32 more byyes. */
+ param_len = 101;
+ } else {
+ param_len = 69;
+ }
+ params = nttrans_realloc(ppparams, param_len);
+ if(params == NULL) {
+ reply_doserror(req, ERRDOS, ERRnomem);
+ return;
+ }
+
+ p = params;
+ SCVAL(p, 0, oplock_granted);
+
+ p += 2;
+ SSVAL(p,0,fsp->fnum);
+ p += 2;
+ if ((create_disposition == FILE_SUPERSEDE)
+ && (info == FILE_WAS_OVERWRITTEN)) {
+ SIVAL(p,0,FILE_WAS_SUPERSEDED);
+ } else {
+ SIVAL(p,0,info);
+ }
+ p += 8;
+
+ /* Create time. */
+ c_timespec = get_create_timespec(
+ &sbuf,lp_fake_dir_create_times(SNUM(conn)));
+ a_timespec = get_atimespec(&sbuf);
+ m_timespec = get_mtimespec(&sbuf);
+
+ if (lp_dos_filetime_resolution(SNUM(conn))) {
+ dos_filetime_timespec(&c_timespec);
+ dos_filetime_timespec(&a_timespec);
+ dos_filetime_timespec(&m_timespec);
+ }
+
+ put_long_date_timespec(p, c_timespec); /* create time. */
+ p += 8;
+ put_long_date_timespec(p, a_timespec); /* access time */
+ p += 8;
+ put_long_date_timespec(p, m_timespec); /* write time */
+ p += 8;
+ put_long_date_timespec(p, m_timespec); /* change time */
+ p += 8;
+ SIVAL(p,0,fattr); /* File Attributes. */
+ p += 4;
+ SOFF_T(p, 0, get_allocation_size(conn,fsp,&sbuf));
+ p += 8;
+ SOFF_T(p,0,file_len);
+ p += 8;
+ if (flags & EXTENDED_RESPONSE_REQUIRED) {
+ SSVAL(p,2,0x7);
+ }
+ p += 4;
+ SCVAL(p,0,fsp->is_directory ? 1 : 0);
+
+ if (flags & EXTENDED_RESPONSE_REQUIRED) {
+ uint32 perms = 0;
+ p += 25;
+ if (fsp->is_directory
+ || can_write_to_file(conn, fsp->fsp_name, &sbuf)) {
+ perms = FILE_GENERIC_ALL;
+ } else {
+ perms = FILE_GENERIC_READ|FILE_EXECUTE;
+ }
+ SIVAL(p,0,perms);
+ }
+
+ DEBUG(5,("call_nt_transact_create: open name = %s\n", fsp->fsp_name));
+
+ /* Send the required number of replies */
+ send_nt_replies(conn, req, NT_STATUS_OK, params, param_len, *ppdata, 0);
+
+ return;
+}
+
+/****************************************************************************
+ Reply to a NT CANCEL request.
+ conn POINTER CAN BE NULL HERE !
+****************************************************************************/
+
+void reply_ntcancel(struct smb_request *req)
+{
+ /*
+ * Go through and cancel any pending change notifies.
+ */
+
+ START_PROFILE(SMBntcancel);
+ remove_pending_change_notify_requests_by_mid(req->mid);
+ remove_pending_lock_requests_by_mid(req->mid);
+ srv_cancel_sign_response(req->mid);
+
+ DEBUG(3,("reply_ntcancel: cancel called on mid = %d.\n", req->mid));
+
+ END_PROFILE(SMBntcancel);
+ return;
+}
+
+/****************************************************************************
+ Copy a file.
+****************************************************************************/
+
+static NTSTATUS copy_internals(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ struct smb_request *req,
+ const char *oldname_in,
+ const char *newname_in,
+ uint32 attrs)
+{
+ SMB_STRUCT_STAT sbuf1, sbuf2;
+ char *oldname = NULL;
+ char *newname = NULL;
+ char *last_component_oldname = NULL;
+ char *last_component_newname = NULL;
+ files_struct *fsp1,*fsp2;
+ uint32 fattr;
+ int info;
+ SMB_OFF_T ret=-1;
+ NTSTATUS status = NT_STATUS_OK;
+
+ ZERO_STRUCT(sbuf1);
+ ZERO_STRUCT(sbuf2);
+
+ if (!CAN_WRITE(conn)) {
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+ }
+
+ status = unix_convert(ctx, conn, oldname_in, False, &oldname,
+ &last_component_oldname, &sbuf1);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = check_name(conn, oldname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Source must already exist. */
+ if (!VALID_STAT(sbuf1)) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ /* Ensure attributes match. */
+ fattr = dos_mode(conn,oldname,&sbuf1);
+ if ((fattr & ~attrs) & (aHIDDEN | aSYSTEM)) {
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+ status = unix_convert(ctx, conn, newname_in, False, &newname,
+ &last_component_newname, &sbuf2);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = check_name(conn, newname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Disallow if newname already exists. */
+ if (VALID_STAT(sbuf2)) {
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ /* No links from a directory. */
+ if (S_ISDIR(sbuf1.st_mode)) {
+ return NT_STATUS_FILE_IS_A_DIRECTORY;
+ }
+
+ /* Ensure this is within the share. */
+ status = check_reduced_name(conn, oldname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(10,("copy_internals: doing file copy %s to %s\n",
+ oldname, newname));
+
+ status = open_file_ntcreate(conn, req, oldname, &sbuf1,
+ FILE_READ_DATA, /* Read-only. */
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OPEN,
+ 0, /* No create options. */
+ FILE_ATTRIBUTE_NORMAL,
+ NO_OPLOCK,
+ &info, &fsp1);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = open_file_ntcreate(conn, req, newname, &sbuf2,
+ FILE_WRITE_DATA, /* Read-only. */
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_CREATE,
+ 0, /* No create options. */
+ fattr,
+ NO_OPLOCK,
+ &info, &fsp2);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ close_file(fsp1,ERROR_CLOSE);
+ return status;
+ }
+
+ if (sbuf1.st_size) {
+ ret = vfs_transfer_file(fsp1, fsp2, sbuf1.st_size);
+ }
+
+ /*
+ * As we are opening fsp1 read-only we only expect
+ * an error on close on fsp2 if we are out of space.
+ * Thus we don't look at the error return from the
+ * close of fsp1.
+ */
+ close_file(fsp1,NORMAL_CLOSE);
+
+ /* Ensure the modtime is set correctly on the destination file. */
+ set_close_write_time(fsp2, get_mtimespec(&sbuf1));
+
+ status = close_file(fsp2,NORMAL_CLOSE);
+
+ /* Grrr. We have to do this as open_file_ntcreate adds aARCH when it
+ creates the file. This isn't the correct thing to do in the copy
+ case. JRA */
+ file_set_dosmode(conn, newname, fattr, &sbuf2,
+ parent_dirname(newname),false);
+
+ if (ret < (SMB_OFF_T)sbuf1.st_size) {
+ return NT_STATUS_DISK_FULL;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3,("copy_internals: Error %s copy file %s to %s\n",
+ nt_errstr(status), oldname, newname));
+ }
+ return status;
+}
+
+/****************************************************************************
+ Reply to a NT rename request.
+****************************************************************************/
+
+void reply_ntrename(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ char *oldname = NULL;
+ char *newname = NULL;
+ char *p;
+ NTSTATUS status;
+ bool src_has_wcard = False;
+ bool dest_has_wcard = False;
+ uint32 attrs;
+ uint16 rename_type;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ START_PROFILE(SMBntrename);
+
+ if (req->wct < 4) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBntrename);
+ return;
+ }
+
+ attrs = SVAL(req->inbuf,smb_vwv0);
+ rename_type = SVAL(req->inbuf,smb_vwv1);
+
+ p = smb_buf(req->inbuf) + 1;
+ p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &oldname, p,
+ 0, STR_TERMINATE, &status,
+ &src_has_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBntrename);
+ return;
+ }
+
+ if( is_ntfs_stream_name(oldname)) {
+ /* Can't rename a stream. */
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+ END_PROFILE(SMBntrename);
+ return;
+ }
+
+ if (ms_has_wild(oldname)) {
+ reply_nterror(req, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
+ END_PROFILE(SMBntrename);
+ return;
+ }
+
+ p++;
+ p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &newname, p,
+ 0, STR_TERMINATE, &status,
+ &dest_has_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBntrename);
+ return;
+ }
+
+ status = resolve_dfspath(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ oldname,
+ &oldname);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ END_PROFILE(SMBntrename);
+ return;
+ }
+ reply_nterror(req, status);
+ END_PROFILE(SMBntrename);
+ return;
+ }
+
+ status = resolve_dfspath(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ newname,
+ &newname);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ END_PROFILE(SMBntrename);
+ return;
+ }
+ reply_nterror(req, status);
+ END_PROFILE(SMBntrename);
+ return;
+ }
+
+ DEBUG(3,("reply_ntrename : %s -> %s\n",oldname,newname));
+
+ switch(rename_type) {
+ case RENAME_FLAG_RENAME:
+ status = rename_internals(ctx, conn, req, oldname,
+ newname, attrs, False, src_has_wcard,
+ dest_has_wcard, DELETE_ACCESS);
+ break;
+ case RENAME_FLAG_HARD_LINK:
+ if (src_has_wcard || dest_has_wcard) {
+ /* No wildcards. */
+ status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
+ } else {
+ status = hardlink_internals(ctx,
+ conn,
+ oldname,
+ newname);
+ }
+ break;
+ case RENAME_FLAG_COPY:
+ if (src_has_wcard || dest_has_wcard) {
+ /* No wildcards. */
+ status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
+ } else {
+ status = copy_internals(ctx, conn, req, oldname,
+ newname, attrs);
+ }
+ break;
+ case RENAME_FLAG_MOVE_CLUSTER_INFORMATION:
+ status = NT_STATUS_INVALID_PARAMETER;
+ break;
+ default:
+ status = NT_STATUS_ACCESS_DENIED; /* Default error. */
+ break;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ if (open_was_deferred(req->mid)) {
+ /* We have re-scheduled this call. */
+ END_PROFILE(SMBntrename);
+ return;
+ }
+
+ reply_nterror(req, status);
+ END_PROFILE(SMBntrename);
+ return;
+ }
+
+ reply_outbuf(req, 0, 0);
+
+ END_PROFILE(SMBntrename);
+ return;
+}
+
+/****************************************************************************
+ Reply to a notify change - queue the request and
+ don't allow a directory to be opened.
+****************************************************************************/
+
+static void call_nt_transact_notify_change(connection_struct *conn,
+ struct smb_request *req,
+ uint16 **ppsetup,
+ uint32 setup_count,
+ char **ppparams,
+ uint32 parameter_count,
+ char **ppdata, uint32 data_count,
+ uint32 max_data_count,
+ uint32 max_param_count)
+{
+ uint16 *setup = *ppsetup;
+ files_struct *fsp;
+ uint32 filter;
+ NTSTATUS status;
+ bool recursive;
+
+ if(setup_count < 6) {
+ reply_doserror(req, ERRDOS, ERRbadfunc);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(setup,4));
+ filter = IVAL(setup, 0);
+ recursive = (SVAL(setup, 6) != 0) ? True : False;
+
+ DEBUG(3,("call_nt_transact_notify_change\n"));
+
+ if(!fsp) {
+ reply_doserror(req, ERRDOS, ERRbadfid);
+ return;
+ }
+
+ {
+ char *filter_string;
+
+ if (!(filter_string = notify_filter_string(NULL, filter))) {
+ reply_nterror(req,NT_STATUS_NO_MEMORY);
+ return;
+ }
+
+ DEBUG(3,("call_nt_transact_notify_change: notify change "
+ "called on %s, filter = %s, recursive = %d\n",
+ fsp->fsp_name, filter_string, recursive));
+
+ TALLOC_FREE(filter_string);
+ }
+
+ if((!fsp->is_directory) || (conn != fsp->conn)) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ if (fsp->notify == NULL) {
+
+ status = change_notify_create(fsp, filter, recursive);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("change_notify_create returned %s\n",
+ nt_errstr(status)));
+ reply_nterror(req, status);
+ return;
+ }
+ }
+
+ if (fsp->notify->num_changes != 0) {
+
+ /*
+ * We've got changes pending, respond immediately
+ */
+
+ /*
+ * TODO: write a torture test to check the filtering behaviour
+ * here.
+ */
+
+ change_notify_reply(fsp->conn, req->inbuf, max_param_count, fsp->notify);
+
+ /*
+ * change_notify_reply() above has independently sent its
+ * results
+ */
+ return;
+ }
+
+ /*
+ * No changes pending, queue the request
+ */
+
+ status = change_notify_add_request(req,
+ max_param_count,
+ filter,
+ recursive, fsp);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ }
+ return;
+}
+
+/****************************************************************************
+ Reply to an NT transact rename command.
+****************************************************************************/
+
+static void call_nt_transact_rename(connection_struct *conn,
+ struct smb_request *req,
+ uint16 **ppsetup, uint32 setup_count,
+ char **ppparams, uint32 parameter_count,
+ char **ppdata, uint32 data_count,
+ uint32 max_data_count)
+{
+ char *params = *ppparams;
+ char *new_name = NULL;
+ files_struct *fsp = NULL;
+ bool dest_has_wcard = False;
+ NTSTATUS status;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if(parameter_count < 5) {
+ reply_doserror(req, ERRDOS, ERRbadfunc);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(params, 0));
+ if (!check_fsp(conn, req, fsp)) {
+ return;
+ }
+ srvstr_get_path_wcard(ctx, params, req->flags2, &new_name, params+4,
+ parameter_count - 4,
+ STR_TERMINATE, &status, &dest_has_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+
+ /*
+ * W2K3 ignores this request as the RAW-RENAME test
+ * demonstrates, so we do.
+ */
+ send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0);
+
+ DEBUG(3,("nt transact rename from = %s, to = %s ignored!\n",
+ fsp->fsp_name, new_name));
+
+ return;
+}
+
+/******************************************************************************
+ Fake up a completely empty SD.
+*******************************************************************************/
+
+static NTSTATUS get_null_nt_acl(TALLOC_CTX *mem_ctx, SEC_DESC **ppsd)
+{
+ size_t sd_size;
+
+ *ppsd = make_standard_sec_desc( mem_ctx, &global_sid_World, &global_sid_World, NULL, &sd_size);
+ if(!*ppsd) {
+ DEBUG(0,("get_null_nt_acl: Unable to malloc space for security descriptor.\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Reply to query a security descriptor.
+****************************************************************************/
+
+static void call_nt_transact_query_security_desc(connection_struct *conn,
+ struct smb_request *req,
+ uint16 **ppsetup,
+ uint32 setup_count,
+ char **ppparams,
+ uint32 parameter_count,
+ char **ppdata,
+ uint32 data_count,
+ uint32 max_data_count)
+{
+ char *params = *ppparams;
+ char *data = *ppdata;
+ SEC_DESC *psd = NULL;
+ size_t sd_size;
+ uint32 security_info_wanted;
+ files_struct *fsp = NULL;
+ NTSTATUS status;
+ DATA_BLOB blob;
+
+ if(parameter_count < 8) {
+ reply_doserror(req, ERRDOS, ERRbadfunc);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(params,0));
+ if(!fsp) {
+ reply_doserror(req, ERRDOS, ERRbadfid);
+ return;
+ }
+
+ security_info_wanted = IVAL(params,4);
+
+ DEBUG(3,("call_nt_transact_query_security_desc: file = %s, info_wanted = 0x%x\n", fsp->fsp_name,
+ (unsigned int)security_info_wanted ));
+
+ params = nttrans_realloc(ppparams, 4);
+ if(params == NULL) {
+ reply_doserror(req, ERRDOS, ERRnomem);
+ return;
+ }
+
+ /*
+ * Get the permissions to return.
+ */
+
+ if (!lp_nt_acl_support(SNUM(conn))) {
+ status = get_null_nt_acl(talloc_tos(), &psd);
+ } else {
+ status = SMB_VFS_FGET_NT_ACL(
+ fsp, security_info_wanted, &psd);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+
+ sd_size = ndr_size_security_descriptor(psd, 0);
+
+ DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %lu.\n",(unsigned long)sd_size));
+
+ SIVAL(params,0,(uint32)sd_size);
+
+ if (max_data_count < sd_size) {
+ send_nt_replies(conn, req, NT_STATUS_BUFFER_TOO_SMALL,
+ params, 4, *ppdata, 0);
+ return;
+ }
+
+ /*
+ * Allocate the data we will point this at.
+ */
+
+ data = nttrans_realloc(ppdata, sd_size);
+ if(data == NULL) {
+ reply_doserror(req, ERRDOS, ERRnomem);
+ return;
+ }
+
+ status = marshall_sec_desc(talloc_tos(), psd,
+ &blob.data, &blob.length);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+
+ SMB_ASSERT(sd_size == blob.length);
+ memcpy(data, blob.data, sd_size);
+
+ send_nt_replies(conn, req, NT_STATUS_OK, params, 4, data, (int)sd_size);
+
+ return;
+}
+
+/****************************************************************************
+ Reply to set a security descriptor. Map to UNIX perms or POSIX ACLs.
+****************************************************************************/
+
+static void call_nt_transact_set_security_desc(connection_struct *conn,
+ struct smb_request *req,
+ uint16 **ppsetup,
+ uint32 setup_count,
+ char **ppparams,
+ uint32 parameter_count,
+ char **ppdata,
+ uint32 data_count,
+ uint32 max_data_count)
+{
+ char *params= *ppparams;
+ char *data = *ppdata;
+ files_struct *fsp = NULL;
+ uint32 security_info_sent = 0;
+ NTSTATUS status;
+
+ if(parameter_count < 8) {
+ reply_doserror(req, ERRDOS, ERRbadfunc);
+ return;
+ }
+
+ if((fsp = file_fsp(SVAL(params,0))) == NULL) {
+ reply_doserror(req, ERRDOS, ERRbadfid);
+ return;
+ }
+
+ if(!lp_nt_acl_support(SNUM(conn))) {
+ goto done;
+ }
+
+ security_info_sent = IVAL(params,4);
+
+ DEBUG(3,("call_nt_transact_set_security_desc: file = %s, sent 0x%x\n", fsp->fsp_name,
+ (unsigned int)security_info_sent ));
+
+ if (data_count == 0) {
+ reply_doserror(req, ERRDOS, ERRnoaccess);
+ return;
+ }
+
+ status = set_sd(fsp, (uint8 *)data, data_count, security_info_sent);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+
+ done:
+ send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0);
+ return;
+}
+
+/****************************************************************************
+ Reply to NT IOCTL
+****************************************************************************/
+
+static void call_nt_transact_ioctl(connection_struct *conn,
+ struct smb_request *req,
+ uint16 **ppsetup, uint32 setup_count,
+ char **ppparams, uint32 parameter_count,
+ char **ppdata, uint32 data_count,
+ uint32 max_data_count)
+{
+ uint32 function;
+ uint16 fidnum;
+ files_struct *fsp;
+ uint8 isFSctl;
+ uint8 compfilter;
+ static bool logged_message;
+ char *pdata = *ppdata;
+
+ if (setup_count != 8) {
+ DEBUG(3,("call_nt_transact_ioctl: invalid setup count %d\n", setup_count));
+ reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
+ return;
+ }
+
+ function = IVAL(*ppsetup, 0);
+ fidnum = SVAL(*ppsetup, 4);
+ isFSctl = CVAL(*ppsetup, 6);
+ compfilter = CVAL(*ppsetup, 7);
+
+ DEBUG(10,("call_nt_transact_ioctl: function[0x%08X] FID[0x%04X] isFSctl[0x%02X] compfilter[0x%02X]\n",
+ function, fidnum, isFSctl, compfilter));
+
+ fsp=file_fsp(fidnum);
+ /* this check is done in each implemented function case for now
+ because I don't want to break anything... --metze
+ FSP_BELONGS_CONN(fsp,conn);*/
+
+ switch (function) {
+ case FSCTL_SET_SPARSE:
+ /* pretend this succeeded - tho strictly we should
+ mark the file sparse (if the local fs supports it)
+ so we can know if we need to pre-allocate or not */
+
+ DEBUG(10,("FSCTL_SET_SPARSE: called on FID[0x%04X](but not implemented)\n", fidnum));
+ send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0);
+ return;
+
+ case FSCTL_CREATE_OR_GET_OBJECT_ID:
+ {
+ unsigned char objid[16];
+
+ /* This should return the object-id on this file.
+ * I think I'll make this be the inode+dev. JRA.
+ */
+
+ DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on FID[0x%04X]\n",fidnum));
+
+ if (!fsp_belongs_conn(conn, req, fsp)) {
+ return;
+ }
+
+ data_count = 64;
+ pdata = nttrans_realloc(ppdata, data_count);
+ if (pdata == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ push_file_id_16(pdata, &fsp->file_id);
+ memcpy(pdata+16,create_volume_objectid(conn,objid),16);
+ push_file_id_16(pdata+32, &fsp->file_id);
+ send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0,
+ pdata, data_count);
+ return;
+ }
+
+ case FSCTL_GET_REPARSE_POINT:
+ /* pretend this fail - my winXP does it like this
+ * --metze
+ */
+
+ DEBUG(10,("FSCTL_GET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum));
+ reply_nterror(req, NT_STATUS_NOT_A_REPARSE_POINT);
+ return;
+
+ case FSCTL_SET_REPARSE_POINT:
+ /* pretend this fail - I'm assuming this because of the FSCTL_GET_REPARSE_POINT case.
+ * --metze
+ */
+
+ DEBUG(10,("FSCTL_SET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum));
+ reply_nterror(req, NT_STATUS_NOT_A_REPARSE_POINT);
+ return;
+
+ case FSCTL_GET_SHADOW_COPY_DATA: /* don't know if this name is right...*/
+ {
+ /*
+ * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
+ * and return their volume names. If max_data_count is 16, then it is just
+ * asking for the number of volumes and length of the combined names.
+ *
+ * pdata is the data allocated by our caller, but that uses
+ * total_data_count (which is 0 in our case) rather than max_data_count.
+ * Allocate the correct amount and return the pointer to let
+ * it be deallocated when we return.
+ */
+ SHADOW_COPY_DATA *shadow_data = NULL;
+ TALLOC_CTX *shadow_mem_ctx = NULL;
+ bool labels = False;
+ uint32 labels_data_count = 0;
+ uint32 i;
+ char *cur_pdata;
+
+ if (!fsp_belongs_conn(conn, req, fsp)) {
+ return;
+ }
+
+ if (max_data_count < 16) {
+ DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
+ max_data_count));
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ if (max_data_count > 16) {
+ labels = True;
+ }
+
+ shadow_mem_ctx = talloc_init("SHADOW_COPY_DATA");
+ if (shadow_mem_ctx == NULL) {
+ DEBUG(0,("talloc_init(SHADOW_COPY_DATA) failed!\n"));
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+
+ shadow_data = TALLOC_ZERO_P(shadow_mem_ctx,SHADOW_COPY_DATA);
+ if (shadow_data == NULL) {
+ DEBUG(0,("TALLOC_ZERO() failed!\n"));
+ talloc_destroy(shadow_mem_ctx);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+
+ shadow_data->mem_ctx = shadow_mem_ctx;
+
+ /*
+ * Call the VFS routine to actually do the work.
+ */
+ if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
+ talloc_destroy(shadow_data->mem_ctx);
+ if (errno == ENOSYS) {
+ DEBUG(5,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, not supported.\n",
+ conn->connectpath));
+ reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
+ return;
+ } else {
+ DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, failed.\n",
+ conn->connectpath));
+ reply_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ return;
+ }
+ }
+
+ labels_data_count = (shadow_data->num_volumes*2*sizeof(SHADOW_COPY_LABEL))+2;
+
+ if (!labels) {
+ data_count = 16;
+ } else {
+ data_count = 12+labels_data_count+4;
+ }
+
+ if (max_data_count<data_count) {
+ DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
+ max_data_count,data_count));
+ talloc_destroy(shadow_data->mem_ctx);
+ reply_nterror(req, NT_STATUS_BUFFER_TOO_SMALL);
+ return;
+ }
+
+ pdata = nttrans_realloc(ppdata, data_count);
+ if (pdata == NULL) {
+ talloc_destroy(shadow_data->mem_ctx);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+
+ cur_pdata = pdata;
+
+ /* num_volumes 4 bytes */
+ SIVAL(pdata,0,shadow_data->num_volumes);
+
+ if (labels) {
+ /* num_labels 4 bytes */
+ SIVAL(pdata,4,shadow_data->num_volumes);
+ }
+
+ /* needed_data_count 4 bytes */
+ SIVAL(pdata,8,labels_data_count);
+
+ cur_pdata+=12;
+
+ DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
+ shadow_data->num_volumes,fsp->fsp_name));
+ if (labels && shadow_data->labels) {
+ for (i=0;i<shadow_data->num_volumes;i++) {
+ srvstr_push(pdata, req->flags2,
+ cur_pdata, shadow_data->labels[i],
+ 2*sizeof(SHADOW_COPY_LABEL),
+ STR_UNICODE|STR_TERMINATE);
+ cur_pdata+=2*sizeof(SHADOW_COPY_LABEL);
+ DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
+ }
+ }
+
+ talloc_destroy(shadow_data->mem_ctx);
+
+ send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0,
+ pdata, data_count);
+
+ return;
+ }
+
+ case FSCTL_FIND_FILES_BY_SID: /* I hope this name is right */
+ {
+ /* pretend this succeeded -
+ *
+ * we have to send back a list with all files owned by this SID
+ *
+ * but I have to check that --metze
+ */
+ DOM_SID sid;
+ uid_t uid;
+ size_t sid_len = MIN(data_count-4,SID_MAX_SIZE);
+
+ DEBUG(10,("FSCTL_FIND_FILES_BY_SID: called on FID[0x%04X]\n",fidnum));
+
+ if (!fsp_belongs_conn(conn, req, fsp)) {
+ return;
+ }
+
+ /* unknown 4 bytes: this is not the length of the sid :-( */
+ /*unknown = IVAL(pdata,0);*/
+
+ sid_parse(pdata+4,sid_len,&sid);
+ DEBUGADD(10, ("for SID: %s\n", sid_string_dbg(&sid)));
+
+ if (!sid_to_uid(&sid, &uid)) {
+ DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
+ sid_string_dbg(&sid),
+ (unsigned long)sid_len));
+ uid = (-1);
+ }
+
+ /* we can take a look at the find source :-)
+ *
+ * find ./ -uid $uid -name '*' is what we need here
+ *
+ *
+ * and send 4bytes len and then NULL terminated unicode strings
+ * for each file
+ *
+ * but I don't know how to deal with the paged results
+ * (maybe we can hang the result anywhere in the fsp struct)
+ *
+ * we don't send all files at once
+ * and at the next we should *not* start from the beginning,
+ * so we have to cache the result
+ *
+ * --metze
+ */
+
+ /* this works for now... */
+ send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0);
+ return;
+ }
+ default:
+ if (!logged_message) {
+ logged_message = True; /* Only print this once... */
+ DEBUG(0,("call_nt_transact_ioctl(0x%x): Currently not implemented.\n",
+ function));
+ }
+ }
+
+ reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
+}
+
+
+#ifdef HAVE_SYS_QUOTAS
+/****************************************************************************
+ Reply to get user quota
+****************************************************************************/
+
+static void call_nt_transact_get_user_quota(connection_struct *conn,
+ struct smb_request *req,
+ uint16 **ppsetup,
+ uint32 setup_count,
+ char **ppparams,
+ uint32 parameter_count,
+ char **ppdata,
+ uint32 data_count,
+ uint32 max_data_count)
+{
+ NTSTATUS nt_status = NT_STATUS_OK;
+ char *params = *ppparams;
+ char *pdata = *ppdata;
+ char *entry;
+ int data_len=0,param_len=0;
+ int qt_len=0;
+ int entry_len = 0;
+ files_struct *fsp = NULL;
+ uint16 level = 0;
+ size_t sid_len;
+ DOM_SID sid;
+ bool start_enum = True;
+ SMB_NTQUOTA_STRUCT qt;
+ SMB_NTQUOTA_LIST *tmp_list;
+ SMB_NTQUOTA_HANDLE *qt_handle = NULL;
+
+ ZERO_STRUCT(qt);
+
+ /* access check */
+ if (conn->server_info->utok.uid != 0) {
+ DEBUG(1,("get_user_quota: access_denied service [%s] user "
+ "[%s]\n", lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name));
+ reply_doserror(req, ERRDOS, ERRnoaccess);
+ return;
+ }
+
+ /*
+ * Ensure minimum number of parameters sent.
+ */
+
+ if (parameter_count < 4) {
+ DEBUG(0,("TRANSACT_GET_USER_QUOTA: requires %d >= 4 bytes parameters\n",parameter_count));
+ reply_doserror(req, ERRDOS, ERRinvalidparam);
+ return;
+ }
+
+ /* maybe we can check the quota_fnum */
+ fsp = file_fsp(SVAL(params,0));
+ if (!check_fsp_ntquota_handle(conn, req, fsp)) {
+ DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n"));
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ return;
+ }
+
+ /* the NULL pointer checking for fsp->fake_file_handle->pd
+ * is done by CHECK_NTQUOTA_HANDLE_OK()
+ */
+ qt_handle = (SMB_NTQUOTA_HANDLE *)fsp->fake_file_handle->private_data;
+
+ level = SVAL(params,2);
+
+ /* unknown 12 bytes leading in params */
+
+ switch (level) {
+ case TRANSACT_GET_USER_QUOTA_LIST_CONTINUE:
+ /* seems that we should continue with the enum here --metze */
+
+ if (qt_handle->quota_list!=NULL &&
+ qt_handle->tmp_list==NULL) {
+
+ /* free the list */
+ free_ntquota_list(&(qt_handle->quota_list));
+
+ /* Realloc the size of parameters and data we will return */
+ param_len = 4;
+ params = nttrans_realloc(ppparams, param_len);
+ if(params == NULL) {
+ reply_doserror(req, ERRDOS, ERRnomem);
+ return;
+ }
+
+ data_len = 0;
+ SIVAL(params,0,data_len);
+
+ break;
+ }
+
+ start_enum = False;
+
+ case TRANSACT_GET_USER_QUOTA_LIST_START:
+
+ if (qt_handle->quota_list==NULL &&
+ qt_handle->tmp_list==NULL) {
+ start_enum = True;
+ }
+
+ if (start_enum && vfs_get_user_ntquota_list(fsp,&(qt_handle->quota_list))!=0) {
+ reply_doserror(req, ERRSRV, ERRerror);
+ return;
+ }
+
+ /* Realloc the size of parameters and data we will return */
+ param_len = 4;
+ params = nttrans_realloc(ppparams, param_len);
+ if(params == NULL) {
+ reply_doserror(req, ERRDOS, ERRnomem);
+ return;
+ }
+
+ /* we should not trust the value in max_data_count*/
+ max_data_count = MIN(max_data_count,2048);
+
+ pdata = nttrans_realloc(ppdata, max_data_count);/* should be max data count from client*/
+ if(pdata == NULL) {
+ reply_doserror(req, ERRDOS, ERRnomem);
+ return;
+ }
+
+ entry = pdata;
+
+ /* set params Size of returned Quota Data 4 bytes*/
+ /* but set it later when we know it */
+
+ /* for each entry push the data */
+
+ if (start_enum) {
+ qt_handle->tmp_list = qt_handle->quota_list;
+ }
+
+ tmp_list = qt_handle->tmp_list;
+
+ for (;((tmp_list!=NULL)&&((qt_len +40+SID_MAX_SIZE)<max_data_count));
+ tmp_list=tmp_list->next,entry+=entry_len,qt_len+=entry_len) {
+
+ sid_len = ndr_size_dom_sid(
+ &tmp_list->quotas->sid, 0);
+ entry_len = 40 + sid_len;
+
+ /* nextoffset entry 4 bytes */
+ SIVAL(entry,0,entry_len);
+
+ /* then the len of the SID 4 bytes */
+ SIVAL(entry,4,sid_len);
+
+ /* unknown data 8 bytes SMB_BIG_UINT */
+ SBIG_UINT(entry,8,(SMB_BIG_UINT)0); /* this is not 0 in windows...-metze*/
+
+ /* the used disk space 8 bytes SMB_BIG_UINT */
+ SBIG_UINT(entry,16,tmp_list->quotas->usedspace);
+
+ /* the soft quotas 8 bytes SMB_BIG_UINT */
+ SBIG_UINT(entry,24,tmp_list->quotas->softlim);
+
+ /* the hard quotas 8 bytes SMB_BIG_UINT */
+ SBIG_UINT(entry,32,tmp_list->quotas->hardlim);
+
+ /* and now the SID */
+ sid_linearize(entry+40, sid_len, &tmp_list->quotas->sid);
+ }
+
+ qt_handle->tmp_list = tmp_list;
+
+ /* overwrite the offset of the last entry */
+ SIVAL(entry-entry_len,0,0);
+
+ data_len = 4+qt_len;
+ /* overwrite the params quota_data_len */
+ SIVAL(params,0,data_len);
+
+ break;
+
+ case TRANSACT_GET_USER_QUOTA_FOR_SID:
+
+ /* unknown 4 bytes IVAL(pdata,0) */
+
+ if (data_count < 8) {
+ DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: requires %d >= %d bytes data\n",data_count,8));
+ reply_doserror(req, ERRDOS, ERRunknownlevel);
+ return;
+ }
+
+ sid_len = IVAL(pdata,4);
+ /* Ensure this is less than 1mb. */
+ if (sid_len > (1024*1024)) {
+ reply_doserror(req, ERRDOS, ERRnomem);
+ return;
+ }
+
+ if (data_count < 8+sid_len) {
+ DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: requires %d >= %lu bytes data\n",data_count,(unsigned long)(8+sid_len)));
+ reply_doserror(req, ERRDOS, ERRunknownlevel);
+ return;
+ }
+
+ data_len = 4+40+sid_len;
+
+ if (max_data_count < data_len) {
+ DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: max_data_count(%d) < data_len(%d)\n",
+ max_data_count, data_len));
+ param_len = 4;
+ SIVAL(params,0,data_len);
+ data_len = 0;
+ nt_status = NT_STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ sid_parse(pdata+8,sid_len,&sid);
+
+ if (vfs_get_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &qt)!=0) {
+ ZERO_STRUCT(qt);
+ /*
+ * we have to return zero's in all fields
+ * instead of returning an error here
+ * --metze
+ */
+ }
+
+ /* Realloc the size of parameters and data we will return */
+ param_len = 4;
+ params = nttrans_realloc(ppparams, param_len);
+ if(params == NULL) {
+ reply_doserror(req, ERRDOS, ERRnomem);
+ return;
+ }
+
+ pdata = nttrans_realloc(ppdata, data_len);
+ if(pdata == NULL) {
+ reply_doserror(req, ERRDOS, ERRnomem);
+ return;
+ }
+
+ entry = pdata;
+
+ /* set params Size of returned Quota Data 4 bytes*/
+ SIVAL(params,0,data_len);
+
+ /* nextoffset entry 4 bytes */
+ SIVAL(entry,0,0);
+
+ /* then the len of the SID 4 bytes */
+ SIVAL(entry,4,sid_len);
+
+ /* unknown data 8 bytes SMB_BIG_UINT */
+ SBIG_UINT(entry,8,(SMB_BIG_UINT)0); /* this is not 0 in windows...-mezte*/
+
+ /* the used disk space 8 bytes SMB_BIG_UINT */
+ SBIG_UINT(entry,16,qt.usedspace);
+
+ /* the soft quotas 8 bytes SMB_BIG_UINT */
+ SBIG_UINT(entry,24,qt.softlim);
+
+ /* the hard quotas 8 bytes SMB_BIG_UINT */
+ SBIG_UINT(entry,32,qt.hardlim);
+
+ /* and now the SID */
+ sid_linearize(entry+40, sid_len, &sid);
+
+ break;
+
+ default:
+ DEBUG(0,("do_nt_transact_get_user_quota: fnum %d unknown level 0x%04hX\n",fsp->fnum,level));
+ reply_doserror(req, ERRSRV, ERRerror);
+ return;
+ break;
+ }
+
+ send_nt_replies(conn, req, nt_status, params, param_len,
+ pdata, data_len);
+}
+
+/****************************************************************************
+ Reply to set user quota
+****************************************************************************/
+
+static void call_nt_transact_set_user_quota(connection_struct *conn,
+ struct smb_request *req,
+ uint16 **ppsetup,
+ uint32 setup_count,
+ char **ppparams,
+ uint32 parameter_count,
+ char **ppdata,
+ uint32 data_count,
+ uint32 max_data_count)
+{
+ char *params = *ppparams;
+ char *pdata = *ppdata;
+ int data_len=0,param_len=0;
+ SMB_NTQUOTA_STRUCT qt;
+ size_t sid_len;
+ DOM_SID sid;
+ files_struct *fsp = NULL;
+
+ ZERO_STRUCT(qt);
+
+ /* access check */
+ if (conn->server_info->utok.uid != 0) {
+ DEBUG(1,("set_user_quota: access_denied service [%s] user "
+ "[%s]\n", lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name));
+ reply_doserror(req, ERRDOS, ERRnoaccess);
+ return;
+ }
+
+ /*
+ * Ensure minimum number of parameters sent.
+ */
+
+ if (parameter_count < 2) {
+ DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= 2 bytes parameters\n",parameter_count));
+ reply_doserror(req, ERRDOS, ERRinvalidparam);
+ return;
+ }
+
+ /* maybe we can check the quota_fnum */
+ fsp = file_fsp(SVAL(params,0));
+ if (!check_fsp_ntquota_handle(conn, req, fsp)) {
+ DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n"));
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ return;
+ }
+
+ if (data_count < 40) {
+ DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= %d bytes data\n",data_count,40));
+ reply_doserror(req, ERRDOS, ERRunknownlevel);
+ return;
+ }
+
+ /* offset to next quota record.
+ * 4 bytes IVAL(pdata,0)
+ * unused here...
+ */
+
+ /* sid len */
+ sid_len = IVAL(pdata,4);
+
+ if (data_count < 40+sid_len) {
+ DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= %lu bytes data\n",data_count,(unsigned long)40+sid_len));
+ reply_doserror(req, ERRDOS, ERRunknownlevel);
+ return;
+ }
+
+ /* unknown 8 bytes in pdata
+ * maybe its the change time in NTTIME
+ */
+
+ /* the used space 8 bytes (SMB_BIG_UINT)*/
+ qt.usedspace = (SMB_BIG_UINT)IVAL(pdata,16);
+#ifdef LARGE_SMB_OFF_T
+ qt.usedspace |= (((SMB_BIG_UINT)IVAL(pdata,20)) << 32);
+#else /* LARGE_SMB_OFF_T */
+ if ((IVAL(pdata,20) != 0)&&
+ ((qt.usedspace != 0xFFFFFFFF)||
+ (IVAL(pdata,20)!=0xFFFFFFFF))) {
+ /* more than 32 bits? */
+ reply_doserror(req, ERRDOS, ERRunknownlevel);
+ return;
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ /* the soft quotas 8 bytes (SMB_BIG_UINT)*/
+ qt.softlim = (SMB_BIG_UINT)IVAL(pdata,24);
+#ifdef LARGE_SMB_OFF_T
+ qt.softlim |= (((SMB_BIG_UINT)IVAL(pdata,28)) << 32);
+#else /* LARGE_SMB_OFF_T */
+ if ((IVAL(pdata,28) != 0)&&
+ ((qt.softlim != 0xFFFFFFFF)||
+ (IVAL(pdata,28)!=0xFFFFFFFF))) {
+ /* more than 32 bits? */
+ reply_doserror(req, ERRDOS, ERRunknownlevel);
+ return;
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ /* the hard quotas 8 bytes (SMB_BIG_UINT)*/
+ qt.hardlim = (SMB_BIG_UINT)IVAL(pdata,32);
+#ifdef LARGE_SMB_OFF_T
+ qt.hardlim |= (((SMB_BIG_UINT)IVAL(pdata,36)) << 32);
+#else /* LARGE_SMB_OFF_T */
+ if ((IVAL(pdata,36) != 0)&&
+ ((qt.hardlim != 0xFFFFFFFF)||
+ (IVAL(pdata,36)!=0xFFFFFFFF))) {
+ /* more than 32 bits? */
+ reply_doserror(req, ERRDOS, ERRunknownlevel);
+ return;
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ sid_parse(pdata+40,sid_len,&sid);
+ DEBUGADD(8,("SID: %s\n", sid_string_dbg(&sid)));
+
+ /* 44 unknown bytes left... */
+
+ if (vfs_set_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &qt)!=0) {
+ reply_doserror(req, ERRSRV, ERRerror);
+ return;
+ }
+
+ send_nt_replies(conn, req, NT_STATUS_OK, params, param_len,
+ pdata, data_len);
+}
+#endif /* HAVE_SYS_QUOTAS */
+
+static void handle_nttrans(connection_struct *conn,
+ struct trans_state *state,
+ struct smb_request *req)
+{
+ if (Protocol >= PROTOCOL_NT1) {
+ req->flags2 |= 0x40; /* IS_LONG_NAME */
+ SSVAL(req->inbuf,smb_flg2,req->flags2);
+ }
+
+ /* Now we must call the relevant NT_TRANS function */
+ switch(state->call) {
+ case NT_TRANSACT_CREATE:
+ {
+ START_PROFILE(NT_transact_create);
+ call_nt_transact_create(
+ conn, req,
+ &state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(NT_transact_create);
+ break;
+ }
+
+ case NT_TRANSACT_IOCTL:
+ {
+ START_PROFILE(NT_transact_ioctl);
+ call_nt_transact_ioctl(
+ conn, req,
+ &state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(NT_transact_ioctl);
+ break;
+ }
+
+ case NT_TRANSACT_SET_SECURITY_DESC:
+ {
+ START_PROFILE(NT_transact_set_security_desc);
+ call_nt_transact_set_security_desc(
+ conn, req,
+ &state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(NT_transact_set_security_desc);
+ break;
+ }
+
+ case NT_TRANSACT_NOTIFY_CHANGE:
+ {
+ START_PROFILE(NT_transact_notify_change);
+ call_nt_transact_notify_change(
+ conn, req,
+ &state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return,
+ state->max_param_return);
+ END_PROFILE(NT_transact_notify_change);
+ break;
+ }
+
+ case NT_TRANSACT_RENAME:
+ {
+ START_PROFILE(NT_transact_rename);
+ call_nt_transact_rename(
+ conn, req,
+ &state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(NT_transact_rename);
+ break;
+ }
+
+ case NT_TRANSACT_QUERY_SECURITY_DESC:
+ {
+ START_PROFILE(NT_transact_query_security_desc);
+ call_nt_transact_query_security_desc(
+ conn, req,
+ &state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(NT_transact_query_security_desc);
+ break;
+ }
+
+#ifdef HAVE_SYS_QUOTAS
+ case NT_TRANSACT_GET_USER_QUOTA:
+ {
+ START_PROFILE(NT_transact_get_user_quota);
+ call_nt_transact_get_user_quota(
+ conn, req,
+ &state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(NT_transact_get_user_quota);
+ break;
+ }
+
+ case NT_TRANSACT_SET_USER_QUOTA:
+ {
+ START_PROFILE(NT_transact_set_user_quota);
+ call_nt_transact_set_user_quota(
+ conn, req,
+ &state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(NT_transact_set_user_quota);
+ break;
+ }
+#endif /* HAVE_SYS_QUOTAS */
+
+ default:
+ /* Error in request */
+ DEBUG(0,("handle_nttrans: Unknown request %d in "
+ "nttrans call\n", state->call));
+ reply_doserror(req, ERRSRV, ERRerror);
+ return;
+ }
+ return;
+}
+
+/****************************************************************************
+ Reply to a SMBNTtrans.
+****************************************************************************/
+
+void reply_nttrans(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ uint32_t pscnt;
+ uint32_t psoff;
+ uint32_t dscnt;
+ uint32_t dsoff;
+ uint16 function_code;
+ NTSTATUS result;
+ struct trans_state *state;
+ uint32_t size;
+ uint32_t av_size;
+
+ START_PROFILE(SMBnttrans);
+
+ if (req->wct < 19) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBnttrans);
+ return;
+ }
+
+ size = smb_len(req->inbuf) + 4;
+ av_size = smb_len(req->inbuf);
+ pscnt = IVAL(req->inbuf,smb_nt_ParameterCount);
+ psoff = IVAL(req->inbuf,smb_nt_ParameterOffset);
+ dscnt = IVAL(req->inbuf,smb_nt_DataCount);
+ dsoff = IVAL(req->inbuf,smb_nt_DataOffset);
+ function_code = SVAL(req->inbuf, smb_nt_Function);
+
+ if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) {
+ reply_doserror(req, ERRSRV, ERRaccess);
+ END_PROFILE(SMBnttrans);
+ return;
+ }
+
+ result = allow_new_trans(conn->pending_trans, req->mid);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(2, ("Got invalid nttrans request: %s\n", nt_errstr(result)));
+ reply_nterror(req, result);
+ END_PROFILE(SMBnttrans);
+ return;
+ }
+
+ if ((state = TALLOC_P(conn, struct trans_state)) == NULL) {
+ reply_doserror(req, ERRSRV, ERRaccess);
+ END_PROFILE(SMBnttrans);
+ return;
+ }
+
+ state->cmd = SMBnttrans;
+
+ state->mid = req->mid;
+ state->vuid = req->vuid;
+ state->total_data = IVAL(req->inbuf, smb_nt_TotalDataCount);
+ state->data = NULL;
+ state->total_param = IVAL(req->inbuf, smb_nt_TotalParameterCount);
+ state->param = NULL;
+ state->max_data_return = IVAL(req->inbuf,smb_nt_MaxDataCount);
+ state->max_param_return = IVAL(req->inbuf,smb_nt_MaxParameterCount);
+
+ /* setup count is in *words* */
+ state->setup_count = 2*CVAL(req->inbuf,smb_nt_SetupCount);
+ state->setup = NULL;
+ state->call = function_code;
+
+ DEBUG(10, ("num_setup=%u, "
+ "param_total=%u, this_param=%u, max_param=%u, "
+ "data_total=%u, this_data=%u, max_data=%u, "
+ "param_offset=%u, data_offset=%u\n",
+ (unsigned)state->setup_count,
+ (unsigned)state->total_param, (unsigned)pscnt,
+ (unsigned)state->max_param_return,
+ (unsigned)state->total_data, (unsigned)dscnt,
+ (unsigned)state->max_data_return,
+ (unsigned)psoff, (unsigned)dsoff));
+
+ /*
+ * All nttrans messages we handle have smb_wct == 19 +
+ * state->setup_count. Ensure this is so as a sanity check.
+ */
+
+ if(req->wct != 19 + (state->setup_count/2)) {
+ DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n",
+ req->wct, 19 + (state->setup_count/2)));
+ goto bad_param;
+ }
+
+ /* Don't allow more than 128mb for each value. */
+ if ((state->total_data > (1024*1024*128)) ||
+ (state->total_param > (1024*1024*128))) {
+ reply_doserror(req, ERRDOS, ERRnomem);
+ END_PROFILE(SMBnttrans);
+ return;
+ }
+
+ if ((dscnt > state->total_data) || (pscnt > state->total_param))
+ goto bad_param;
+
+ if (state->total_data) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ if ((state->data = (char *)SMB_MALLOC(state->total_data)) == NULL) {
+ DEBUG(0,("reply_nttrans: data malloc fail for %u "
+ "bytes !\n", (unsigned int)state->total_data));
+ TALLOC_FREE(state);
+ reply_doserror(req, ERRDOS, ERRnomem);
+ END_PROFILE(SMBnttrans);
+ return;
+ }
+
+ if (dscnt > state->total_data ||
+ dsoff+dscnt < dsoff) {
+ goto bad_param;
+ }
+
+ if (dsoff > av_size ||
+ dscnt > av_size ||
+ dsoff+dscnt > av_size) {
+ goto bad_param;
+ }
+
+ memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
+ }
+
+ if (state->total_param) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ if ((state->param = (char *)SMB_MALLOC(state->total_param)) == NULL) {
+ DEBUG(0,("reply_nttrans: param malloc fail for %u "
+ "bytes !\n", (unsigned int)state->total_param));
+ SAFE_FREE(state->data);
+ TALLOC_FREE(state);
+ reply_doserror(req, ERRDOS, ERRnomem);
+ END_PROFILE(SMBnttrans);
+ return;
+ }
+
+ if (pscnt > state->total_param ||
+ psoff+pscnt < psoff) {
+ goto bad_param;
+ }
+
+ if (psoff > av_size ||
+ pscnt > av_size ||
+ psoff+pscnt > av_size) {
+ goto bad_param;
+ }
+
+ memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
+ }
+
+ state->received_data = dscnt;
+ state->received_param = pscnt;
+
+ if(state->setup_count > 0) {
+ DEBUG(10,("reply_nttrans: state->setup_count = %d\n",
+ state->setup_count));
+ state->setup = (uint16 *)TALLOC(state, state->setup_count);
+ if (state->setup == NULL) {
+ DEBUG(0,("reply_nttrans : Out of memory\n"));
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ reply_doserror(req, ERRDOS, ERRnomem);
+ END_PROFILE(SMBnttrans);
+ return;
+ }
+
+ if ((smb_nt_SetupStart + state->setup_count < smb_nt_SetupStart) ||
+ (smb_nt_SetupStart + state->setup_count < state->setup_count)) {
+ goto bad_param;
+ }
+ if (smb_nt_SetupStart + state->setup_count > size) {
+ goto bad_param;
+ }
+
+ memcpy( state->setup, &req->inbuf[smb_nt_SetupStart],
+ state->setup_count);
+ dump_data(10, (uint8 *)state->setup, state->setup_count);
+ }
+
+ if ((state->received_data == state->total_data) &&
+ (state->received_param == state->total_param)) {
+ handle_nttrans(conn, state, req);
+ SAFE_FREE(state->param);
+ SAFE_FREE(state->data);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBnttrans);
+ return;
+ }
+
+ DLIST_ADD(conn->pending_trans, state);
+
+ /* We need to send an interim response then receive the rest
+ of the parameter/data bytes */
+ reply_outbuf(req, 0, 0);
+ show_msg((char *)req->outbuf);
+ END_PROFILE(SMBnttrans);
+ return;
+
+ bad_param:
+
+ DEBUG(0,("reply_nttrans: invalid trans parameters\n"));
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBnttrans);
+ return;
+}
+
+/****************************************************************************
+ Reply to a SMBnttranss
+ ****************************************************************************/
+
+void reply_nttranss(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ uint32_t pcnt,poff,dcnt,doff,pdisp,ddisp;
+ struct trans_state *state;
+ uint32_t av_size;
+ uint32_t size;
+
+ START_PROFILE(SMBnttranss);
+
+ show_msg((char *)req->inbuf);
+
+ if (req->wct < 18) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBnttranss);
+ return;
+ }
+
+ for (state = conn->pending_trans; state != NULL;
+ state = state->next) {
+ if (state->mid == req->mid) {
+ break;
+ }
+ }
+
+ if ((state == NULL) || (state->cmd != SMBnttrans)) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBnttranss);
+ return;
+ }
+
+ /* Revise state->total_param and state->total_data in case they have
+ changed downwards */
+ if (IVAL(req->inbuf, smb_nts_TotalParameterCount)
+ < state->total_param) {
+ state->total_param = IVAL(req->inbuf,
+ smb_nts_TotalParameterCount);
+ }
+ if (IVAL(req->inbuf, smb_nts_TotalDataCount) < state->total_data) {
+ state->total_data = IVAL(req->inbuf, smb_nts_TotalDataCount);
+ }
+
+ size = smb_len(req->inbuf) + 4;
+ av_size = smb_len(req->inbuf);
+
+ pcnt = IVAL(req->inbuf,smb_nts_ParameterCount);
+ poff = IVAL(req->inbuf, smb_nts_ParameterOffset);
+ pdisp = IVAL(req->inbuf, smb_nts_ParameterDisplacement);
+
+ dcnt = IVAL(req->inbuf, smb_nts_DataCount);
+ ddisp = IVAL(req->inbuf, smb_nts_DataDisplacement);
+ doff = IVAL(req->inbuf, smb_nts_DataOffset);
+
+ state->received_param += pcnt;
+ state->received_data += dcnt;
+
+ if ((state->received_data > state->total_data) ||
+ (state->received_param > state->total_param))
+ goto bad_param;
+
+ if (pcnt) {
+ if (pdisp > state->total_param ||
+ pcnt > state->total_param ||
+ pdisp+pcnt > state->total_param ||
+ pdisp+pcnt < pdisp) {
+ goto bad_param;
+ }
+
+ if (poff > av_size ||
+ pcnt > av_size ||
+ poff+pcnt > av_size ||
+ poff+pcnt < poff) {
+ goto bad_param;
+ }
+
+ memcpy(state->param+pdisp, smb_base(req->inbuf)+poff,
+ pcnt);
+ }
+
+ if (dcnt) {
+ if (ddisp > state->total_data ||
+ dcnt > state->total_data ||
+ ddisp+dcnt > state->total_data ||
+ ddisp+dcnt < ddisp) {
+ goto bad_param;
+ }
+
+ if (ddisp > av_size ||
+ dcnt > av_size ||
+ ddisp+dcnt > av_size ||
+ ddisp+dcnt < ddisp) {
+ goto bad_param;
+ }
+
+ memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,
+ dcnt);
+ }
+
+ if ((state->received_param < state->total_param) ||
+ (state->received_data < state->total_data)) {
+ END_PROFILE(SMBnttranss);
+ return;
+ }
+
+ /*
+ * construct_reply_common will copy smb_com from inbuf to
+ * outbuf. SMBnttranss is wrong here.
+ */
+ SCVAL(req->inbuf,smb_com,SMBnttrans);
+
+ handle_nttrans(conn, state, req);
+
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBnttranss);
+ return;
+
+ bad_param:
+
+ DEBUG(0,("reply_nttranss: invalid trans parameters\n"));
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBnttranss);
+ return;
+}
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
new file mode 100644
index 0000000000..8b32907a4b
--- /dev/null
+++ b/source3/smbd/open.c
@@ -0,0 +1,3093 @@
+/*
+ Unix SMB/CIFS implementation.
+ file opening and share modes
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2001-2004
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern const struct generic_mapping file_generic_mapping;
+extern bool global_client_failed_oplock_break;
+
+struct deferred_open_record {
+ bool delayed_for_oplocks;
+ struct file_id id;
+};
+
+/****************************************************************************
+ fd support routines - attempt to do a dos_open.
+****************************************************************************/
+
+static NTSTATUS fd_open(struct connection_struct *conn,
+ const char *fname,
+ files_struct *fsp,
+ int flags,
+ mode_t mode)
+{
+ NTSTATUS status = NT_STATUS_OK;
+
+#ifdef O_NOFOLLOW
+ /*
+ * Never follow symlinks on a POSIX client. The
+ * client should be doing this.
+ */
+
+ if (fsp->posix_open || !lp_symlinks(SNUM(conn))) {
+ flags |= O_NOFOLLOW;
+ }
+#endif
+
+ fsp->fh->fd = SMB_VFS_OPEN(conn,fname,fsp,flags,mode);
+ if (fsp->fh->fd == -1) {
+ status = map_nt_error_from_unix(errno);
+ }
+
+ DEBUG(10,("fd_open: name %s, flags = 0%o mode = 0%o, fd = %d. %s\n",
+ fname, flags, (int)mode, fsp->fh->fd,
+ (fsp->fh->fd == -1) ? strerror(errno) : "" ));
+
+ return status;
+}
+
+/****************************************************************************
+ Close the file associated with a fsp.
+****************************************************************************/
+
+NTSTATUS fd_close(files_struct *fsp)
+{
+ int ret;
+
+ if (fsp->fh->fd == -1) {
+ return NT_STATUS_OK; /* What we used to call a stat open. */
+ }
+ if (fsp->fh->ref_count > 1) {
+ return NT_STATUS_OK; /* Shared handle. Only close last reference. */
+ }
+
+ ret = SMB_VFS_CLOSE(fsp);
+ fsp->fh->fd = -1;
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Change the ownership of a file to that of the parent directory.
+ Do this by fd if possible.
+****************************************************************************/
+
+static void change_file_owner_to_parent(connection_struct *conn,
+ const char *inherit_from_dir,
+ files_struct *fsp)
+{
+ SMB_STRUCT_STAT parent_st;
+ int ret;
+
+ ret = SMB_VFS_STAT(conn, inherit_from_dir, &parent_st);
+ if (ret == -1) {
+ DEBUG(0,("change_file_owner_to_parent: failed to stat parent "
+ "directory %s. Error was %s\n",
+ inherit_from_dir, strerror(errno) ));
+ return;
+ }
+
+ become_root();
+ ret = SMB_VFS_FCHOWN(fsp, parent_st.st_uid, (gid_t)-1);
+ unbecome_root();
+ if (ret == -1) {
+ DEBUG(0,("change_file_owner_to_parent: failed to fchown "
+ "file %s to parent directory uid %u. Error "
+ "was %s\n", fsp->fsp_name,
+ (unsigned int)parent_st.st_uid,
+ strerror(errno) ));
+ }
+
+ DEBUG(10,("change_file_owner_to_parent: changed new file %s to "
+ "parent directory uid %u.\n", fsp->fsp_name,
+ (unsigned int)parent_st.st_uid ));
+}
+
+static NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
+ const char *inherit_from_dir,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf)
+{
+ char *saved_dir = NULL;
+ SMB_STRUCT_STAT sbuf;
+ SMB_STRUCT_STAT parent_st;
+ TALLOC_CTX *ctx = talloc_tos();
+ NTSTATUS status = NT_STATUS_OK;
+ int ret;
+
+ ret = SMB_VFS_STAT(conn, inherit_from_dir, &parent_st);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(0,("change_dir_owner_to_parent: failed to stat parent "
+ "directory %s. Error was %s\n",
+ inherit_from_dir, strerror(errno) ));
+ return status;
+ }
+
+ /* We've already done an lstat into psbuf, and we know it's a
+ directory. If we can cd into the directory and the dev/ino
+ are the same then we can safely chown without races as
+ we're locking the directory in place by being in it. This
+ should work on any UNIX (thanks tridge :-). JRA.
+ */
+
+ saved_dir = vfs_GetWd(ctx,conn);
+ if (!saved_dir) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(0,("change_dir_owner_to_parent: failed to get "
+ "current working directory. Error was %s\n",
+ strerror(errno)));
+ return status;
+ }
+
+ /* Chdir into the new path. */
+ if (vfs_ChDir(conn, fname) == -1) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(0,("change_dir_owner_to_parent: failed to change "
+ "current working directory to %s. Error "
+ "was %s\n", fname, strerror(errno) ));
+ goto out;
+ }
+
+ if (SMB_VFS_STAT(conn,".",&sbuf) == -1) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(0,("change_dir_owner_to_parent: failed to stat "
+ "directory '.' (%s) Error was %s\n",
+ fname, strerror(errno)));
+ goto out;
+ }
+
+ /* Ensure we're pointing at the same place. */
+ if (sbuf.st_dev != psbuf->st_dev ||
+ sbuf.st_ino != psbuf->st_ino ||
+ sbuf.st_mode != psbuf->st_mode ) {
+ DEBUG(0,("change_dir_owner_to_parent: "
+ "device/inode/mode on directory %s changed. "
+ "Refusing to chown !\n", fname ));
+ status = NT_STATUS_ACCESS_DENIED;
+ goto out;
+ }
+
+ become_root();
+ ret = SMB_VFS_CHOWN(conn, ".", parent_st.st_uid, (gid_t)-1);
+ unbecome_root();
+ if (ret == -1) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(10,("change_dir_owner_to_parent: failed to chown "
+ "directory %s to parent directory uid %u. "
+ "Error was %s\n", fname,
+ (unsigned int)parent_st.st_uid, strerror(errno) ));
+ goto out;
+ }
+
+ DEBUG(10,("change_dir_owner_to_parent: changed ownership of new "
+ "directory %s to parent directory uid %u.\n",
+ fname, (unsigned int)parent_st.st_uid ));
+
+ out:
+
+ vfs_ChDir(conn,saved_dir);
+ return status;
+}
+
+/****************************************************************************
+ Open a file.
+****************************************************************************/
+
+static NTSTATUS open_file(files_struct *fsp,
+ connection_struct *conn,
+ struct smb_request *req,
+ const char *parent_dir,
+ const char *name,
+ const char *path,
+ SMB_STRUCT_STAT *psbuf,
+ int flags,
+ mode_t unx_mode,
+ uint32 access_mask, /* client requested access mask. */
+ uint32 open_access_mask) /* what we're actually using in the open. */
+{
+ NTSTATUS status = NT_STATUS_OK;
+ int accmode = (flags & O_ACCMODE);
+ int local_flags = flags;
+ bool file_existed = VALID_STAT(*psbuf);
+
+ fsp->fh->fd = -1;
+ errno = EPERM;
+
+ /* Check permissions */
+
+ /*
+ * This code was changed after seeing a client open request
+ * containing the open mode of (DENY_WRITE/read-only) with
+ * the 'create if not exist' bit set. The previous code
+ * would fail to open the file read only on a read-only share
+ * as it was checking the flags parameter directly against O_RDONLY,
+ * this was failing as the flags parameter was set to O_RDONLY|O_CREAT.
+ * JRA.
+ */
+
+ if (!CAN_WRITE(conn)) {
+ /* It's a read-only share - fail if we wanted to write. */
+ if(accmode != O_RDONLY) {
+ DEBUG(3,("Permission denied opening %s\n", path));
+ return NT_STATUS_ACCESS_DENIED;
+ } 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;
+ local_flags &= ~O_CREAT;
+ }
+ }
+
+ /*
+ * This little piece of insanity is inspired by the
+ * fact that an NT client can open a file for O_RDONLY,
+ * but set the create disposition to FILE_EXISTS_TRUNCATE.
+ * If the client *can* write to the file, then it expects to
+ * truncate the file, even though it is opening for readonly.
+ * Quicken uses this stupid trick in backup file creation...
+ * Thanks *greatly* to "David W. Chapman Jr." <dwcjr@inethouston.net>
+ * for helping track this one down. It didn't bite us in 2.0.x
+ * as we always opened files read-write in that release. JRA.
+ */
+
+ if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) {
+ DEBUG(10,("open_file: truncate requested on read-only open "
+ "for file %s\n", path));
+ local_flags = (flags & ~O_ACCMODE)|O_RDWR;
+ }
+
+ if ((open_access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ||
+ (!file_existed && (local_flags & O_CREAT)) ||
+ ((local_flags & O_TRUNC) == O_TRUNC) ) {
+
+ /*
+ * We can't actually truncate here as the file may be locked.
+ * open_file_ntcreate will take care of the truncate later. JRA.
+ */
+
+ local_flags &= ~O_TRUNC;
+
+#if defined(O_NONBLOCK) && defined(S_ISFIFO)
+ /*
+ * We would block on opening a FIFO with no one else on the
+ * other end. Do what we used to do and add O_NONBLOCK to the
+ * open flags. JRA.
+ */
+
+ if (file_existed && S_ISFIFO(psbuf->st_mode)) {
+ local_flags |= O_NONBLOCK;
+ }
+#endif
+
+ /* Don't create files with Microsoft wildcard characters. */
+ if ((local_flags & O_CREAT) && !file_existed &&
+ ms_has_wild(path)) {
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+
+ /* Actually do the open */
+ status = fd_open(conn, path, fsp, local_flags, unx_mode);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3,("Error opening file %s (%s) (local_flags=%d) "
+ "(flags=%d)\n",
+ path,nt_errstr(status),local_flags,flags));
+ return status;
+ }
+
+ if ((local_flags & O_CREAT) && !file_existed) {
+
+ /* Inherit the ACL if required */
+ if (lp_inherit_perms(SNUM(conn))) {
+ inherit_access_posix_acl(conn, parent_dir, path,
+ unx_mode);
+ }
+
+ /* Change the owner if required. */
+ if (lp_inherit_owner(SNUM(conn))) {
+ change_file_owner_to_parent(conn, parent_dir,
+ fsp);
+ }
+
+ notify_fname(conn, NOTIFY_ACTION_ADDED,
+ FILE_NOTIFY_CHANGE_FILE_NAME, path);
+ }
+
+ } else {
+ fsp->fh->fd = -1; /* What we used to call a stat open. */
+ }
+
+ if (!file_existed) {
+ int ret;
+
+ if (fsp->fh->fd == -1) {
+ ret = SMB_VFS_STAT(conn, path, psbuf);
+ } else {
+ ret = SMB_VFS_FSTAT(fsp, psbuf);
+ /* If we have an fd, this stat should succeed. */
+ if (ret == -1) {
+ DEBUG(0,("Error doing fstat on open file %s "
+ "(%s)\n", path,strerror(errno) ));
+ }
+ }
+
+ /* For a non-io open, this stat failing means file not found. JRA */
+ if (ret == -1) {
+ status = map_nt_error_from_unix(errno);
+ fd_close(fsp);
+ return status;
+ }
+ }
+
+ /*
+ * POSIX allows read-only opens of directories. We don't
+ * want to do this (we use a different code path for this)
+ * so catch a directory open and return an EISDIR. JRA.
+ */
+
+ if(S_ISDIR(psbuf->st_mode)) {
+ fd_close(fsp);
+ errno = EISDIR;
+ return NT_STATUS_FILE_IS_A_DIRECTORY;
+ }
+
+ fsp->mode = psbuf->st_mode;
+ fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf);
+ fsp->vuid = req ? req->vuid : UID_FIELD_INVALID;
+ fsp->file_pid = req ? req->smbpid : 0;
+ fsp->can_lock = True;
+ fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False;
+ if (!CAN_WRITE(conn)) {
+ fsp->can_write = False;
+ } else {
+ fsp->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ?
+ True : False;
+ }
+ fsp->print_file = False;
+ fsp->modified = False;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+ fsp->is_directory = False;
+ if (conn->aio_write_behind_list &&
+ is_in_path(path, conn->aio_write_behind_list, conn->case_sensitive)) {
+ fsp->aio_write_behind = True;
+ }
+
+ string_set(&fsp->fsp_name, path);
+ fsp->wcp = NULL; /* Write cache pointer. */
+
+ DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",
+ conn->server_info->unix_name,
+ fsp->fsp_name,
+ BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write),
+ conn->num_files_open + 1));
+
+ errno = 0;
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Return True if the filename is one of the special executable types.
+********************************************************************/
+
+static bool is_executable(const char *fname)
+{
+ if ((fname = strrchr_m(fname,'.'))) {
+ if (strequal(fname,".com") ||
+ strequal(fname,".dll") ||
+ strequal(fname,".exe") ||
+ strequal(fname,".sym")) {
+ return True;
+ }
+ }
+ return False;
+}
+
+/****************************************************************************
+ Check if we can open a file with a share mode.
+ Returns True if conflict, False if not.
+****************************************************************************/
+
+static bool share_conflict(struct share_mode_entry *entry,
+ uint32 access_mask,
+ uint32 share_access)
+{
+ DEBUG(10,("share_conflict: entry->access_mask = 0x%x, "
+ "entry->share_access = 0x%x, "
+ "entry->private_options = 0x%x\n",
+ (unsigned int)entry->access_mask,
+ (unsigned int)entry->share_access,
+ (unsigned int)entry->private_options));
+
+ DEBUG(10,("share_conflict: access_mask = 0x%x, share_access = 0x%x\n",
+ (unsigned int)access_mask, (unsigned int)share_access));
+
+ if ((entry->access_mask & (FILE_WRITE_DATA|
+ FILE_APPEND_DATA|
+ FILE_READ_DATA|
+ FILE_EXECUTE|
+ DELETE_ACCESS)) == 0) {
+ DEBUG(10,("share_conflict: No conflict due to "
+ "entry->access_mask = 0x%x\n",
+ (unsigned int)entry->access_mask ));
+ return False;
+ }
+
+ if ((access_mask & (FILE_WRITE_DATA|
+ FILE_APPEND_DATA|
+ FILE_READ_DATA|
+ FILE_EXECUTE|
+ DELETE_ACCESS)) == 0) {
+ DEBUG(10,("share_conflict: No conflict due to "
+ "access_mask = 0x%x\n",
+ (unsigned int)access_mask ));
+ return False;
+ }
+
+#if 1 /* JRA TEST - Superdebug. */
+#define CHECK_MASK(num, am, right, sa, share) \
+ DEBUG(10,("share_conflict: [%d] am (0x%x) & right (0x%x) = 0x%x\n", \
+ (unsigned int)(num), (unsigned int)(am), \
+ (unsigned int)(right), (unsigned int)(am)&(right) )); \
+ DEBUG(10,("share_conflict: [%d] sa (0x%x) & share (0x%x) = 0x%x\n", \
+ (unsigned int)(num), (unsigned int)(sa), \
+ (unsigned int)(share), (unsigned int)(sa)&(share) )); \
+ if (((am) & (right)) && !((sa) & (share))) { \
+ DEBUG(10,("share_conflict: check %d conflict am = 0x%x, right = 0x%x, \
+sa = 0x%x, share = 0x%x\n", (num), (unsigned int)(am), (unsigned int)(right), (unsigned int)(sa), \
+ (unsigned int)(share) )); \
+ return True; \
+ }
+#else
+#define CHECK_MASK(num, am, right, sa, share) \
+ if (((am) & (right)) && !((sa) & (share))) { \
+ DEBUG(10,("share_conflict: check %d conflict am = 0x%x, right = 0x%x, \
+sa = 0x%x, share = 0x%x\n", (num), (unsigned int)(am), (unsigned int)(right), (unsigned int)(sa), \
+ (unsigned int)(share) )); \
+ return True; \
+ }
+#endif
+
+ CHECK_MASK(1, entry->access_mask, FILE_WRITE_DATA | FILE_APPEND_DATA,
+ share_access, FILE_SHARE_WRITE);
+ CHECK_MASK(2, access_mask, FILE_WRITE_DATA | FILE_APPEND_DATA,
+ entry->share_access, FILE_SHARE_WRITE);
+
+ CHECK_MASK(3, entry->access_mask, FILE_READ_DATA | FILE_EXECUTE,
+ share_access, FILE_SHARE_READ);
+ CHECK_MASK(4, access_mask, FILE_READ_DATA | FILE_EXECUTE,
+ entry->share_access, FILE_SHARE_READ);
+
+ CHECK_MASK(5, entry->access_mask, DELETE_ACCESS,
+ share_access, FILE_SHARE_DELETE);
+ CHECK_MASK(6, access_mask, DELETE_ACCESS,
+ entry->share_access, FILE_SHARE_DELETE);
+
+ DEBUG(10,("share_conflict: No conflict.\n"));
+ return False;
+}
+
+#if defined(DEVELOPER)
+static void validate_my_share_entries(int num,
+ struct share_mode_entry *share_entry)
+{
+ files_struct *fsp;
+
+ if (!procid_is_me(&share_entry->pid)) {
+ return;
+ }
+
+ if (is_deferred_open_entry(share_entry) &&
+ !open_was_deferred(share_entry->op_mid)) {
+ char *str = talloc_asprintf(talloc_tos(),
+ "Got a deferred entry without a request: "
+ "PANIC: %s\n",
+ share_mode_str(talloc_tos(), num, share_entry));
+ smb_panic(str);
+ }
+
+ if (!is_valid_share_mode_entry(share_entry)) {
+ return;
+ }
+
+ fsp = file_find_dif(share_entry->id,
+ share_entry->share_file_id);
+ if (!fsp) {
+ DEBUG(0,("validate_my_share_entries: PANIC : %s\n",
+ share_mode_str(talloc_tos(), num, share_entry) ));
+ smb_panic("validate_my_share_entries: Cannot match a "
+ "share entry with an open file\n");
+ }
+
+ if (is_deferred_open_entry(share_entry) ||
+ is_unused_share_mode_entry(share_entry)) {
+ goto panic;
+ }
+
+ if ((share_entry->op_type == NO_OPLOCK) &&
+ (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK)) {
+ /* Someone has already written to it, but I haven't yet
+ * noticed */
+ return;
+ }
+
+ if (((uint16)fsp->oplock_type) != share_entry->op_type) {
+ goto panic;
+ }
+
+ return;
+
+ panic:
+ {
+ char *str;
+ DEBUG(0,("validate_my_share_entries: PANIC : %s\n",
+ share_mode_str(talloc_tos(), num, share_entry) ));
+ str = talloc_asprintf(talloc_tos(),
+ "validate_my_share_entries: "
+ "file %s, oplock_type = 0x%x, op_type = 0x%x\n",
+ fsp->fsp_name, (unsigned int)fsp->oplock_type,
+ (unsigned int)share_entry->op_type );
+ smb_panic(str);
+ }
+}
+#endif
+
+static bool is_stat_open(uint32 access_mask)
+{
+ return (access_mask &&
+ ((access_mask & ~(SYNCHRONIZE_ACCESS| FILE_READ_ATTRIBUTES|
+ FILE_WRITE_ATTRIBUTES))==0) &&
+ ((access_mask & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|
+ FILE_WRITE_ATTRIBUTES)) != 0));
+}
+
+/****************************************************************************
+ Deal with share modes
+ Invarient: Share mode must be locked on entry and exit.
+ Returns -1 on error, or number of share modes on success (may be zero).
+****************************************************************************/
+
+static NTSTATUS open_mode_check(connection_struct *conn,
+ const char *fname,
+ struct share_mode_lock *lck,
+ uint32 access_mask,
+ uint32 share_access,
+ uint32 create_options,
+ bool *file_existed)
+{
+ int i;
+
+ if(lck->num_share_modes == 0) {
+ return NT_STATUS_OK;
+ }
+
+ *file_existed = True;
+
+ /* A delete on close prohibits everything */
+
+ if (lck->delete_on_close) {
+ return NT_STATUS_DELETE_PENDING;
+ }
+
+ if (is_stat_open(access_mask)) {
+ /* Stat open that doesn't trigger oplock breaks or share mode
+ * checks... ! JRA. */
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * Check if the share modes will give us access.
+ */
+
+#if defined(DEVELOPER)
+ for(i = 0; i < lck->num_share_modes; i++) {
+ validate_my_share_entries(i, &lck->share_modes[i]);
+ }
+#endif
+
+ if (!lp_share_modes(SNUM(conn))) {
+ return NT_STATUS_OK;
+ }
+
+ /* Now we check the share modes, after any oplock breaks. */
+ for(i = 0; i < lck->num_share_modes; i++) {
+
+ if (!is_valid_share_mode_entry(&lck->share_modes[i])) {
+ continue;
+ }
+
+ /* someone else has a share lock on it, check to see if we can
+ * too */
+ if (share_conflict(&lck->share_modes[i],
+ access_mask, share_access)) {
+ return NT_STATUS_SHARING_VIOLATION;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+static bool is_delete_request(files_struct *fsp) {
+ return ((fsp->access_mask == DELETE_ACCESS) &&
+ (fsp->oplock_type == NO_OPLOCK));
+}
+
+/*
+ * 1) No files open at all or internal open: Grant whatever the client wants.
+ *
+ * 2) Exclusive (or batch) oplock around: If the requested access is a delete
+ * request, break if the oplock around is a batch oplock. If it's another
+ * requested access type, break.
+ *
+ * 3) Only level2 around: Grant level2 and do nothing else.
+ */
+
+static bool delay_for_oplocks(struct share_mode_lock *lck,
+ files_struct *fsp,
+ uint16 mid,
+ int pass_number,
+ int oplock_request)
+{
+ int i;
+ struct share_mode_entry *exclusive = NULL;
+ bool valid_entry = False;
+ bool delay_it = False;
+ bool have_level2 = False;
+ NTSTATUS status;
+ char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
+
+ if (oplock_request & INTERNAL_OPEN_ONLY) {
+ fsp->oplock_type = NO_OPLOCK;
+ }
+
+ if ((oplock_request & INTERNAL_OPEN_ONLY) || is_stat_open(fsp->access_mask)) {
+ return False;
+ }
+
+ for (i=0; i<lck->num_share_modes; i++) {
+
+ if (!is_valid_share_mode_entry(&lck->share_modes[i])) {
+ continue;
+ }
+
+ /* At least one entry is not an invalid or deferred entry. */
+ valid_entry = True;
+
+ if (pass_number == 1) {
+ if (BATCH_OPLOCK_TYPE(lck->share_modes[i].op_type)) {
+ SMB_ASSERT(exclusive == NULL);
+ exclusive = &lck->share_modes[i];
+ }
+ } else {
+ if (EXCLUSIVE_OPLOCK_TYPE(lck->share_modes[i].op_type)) {
+ SMB_ASSERT(exclusive == NULL);
+ exclusive = &lck->share_modes[i];
+ }
+ }
+
+ if (lck->share_modes[i].op_type == LEVEL_II_OPLOCK) {
+ SMB_ASSERT(exclusive == NULL);
+ have_level2 = True;
+ }
+ }
+
+ if (!valid_entry) {
+ /* All entries are placeholders or deferred.
+ * Directly grant whatever the client wants. */
+ if (fsp->oplock_type == NO_OPLOCK) {
+ /* Store a level2 oplock, but don't tell the client */
+ fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
+ }
+ return False;
+ }
+
+ if (exclusive != NULL) { /* Found an exclusive oplock */
+ SMB_ASSERT(!have_level2);
+ delay_it = is_delete_request(fsp) ?
+ BATCH_OPLOCK_TYPE(exclusive->op_type) : True;
+ }
+
+ if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ /* We can at most grant level2 as there are other
+ * level2 or NO_OPLOCK entries. */
+ fsp->oplock_type = LEVEL_II_OPLOCK;
+ }
+
+ if ((fsp->oplock_type == NO_OPLOCK) && have_level2) {
+ /* Store a level2 oplock, but don't tell the client */
+ fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
+ }
+
+ if (!delay_it) {
+ return False;
+ }
+
+ /*
+ * Send a break message to the oplock holder and delay the open for
+ * our client.
+ */
+
+ DEBUG(10, ("Sending break request to PID %s\n",
+ procid_str_static(&exclusive->pid)));
+ exclusive->op_mid = mid;
+
+ /* Create the message. */
+ share_mode_entry_to_message(msg, exclusive);
+
+ /* Add in the FORCE_OPLOCK_BREAK_TO_NONE bit in the message if set. We
+ don't want this set in the share mode struct pointed to by lck. */
+
+ if (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE) {
+ SSVAL(msg,6,exclusive->op_type | FORCE_OPLOCK_BREAK_TO_NONE);
+ }
+
+ status = messaging_send_buf(smbd_messaging_context(), exclusive->pid,
+ MSG_SMB_BREAK_REQUEST,
+ (uint8 *)msg,
+ MSG_SMB_SHARE_MODE_ENTRY_SIZE);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Could not send oplock break message: %s\n",
+ nt_errstr(status)));
+ }
+
+ return True;
+}
+
+static bool request_timed_out(struct timeval request_time,
+ struct timeval timeout)
+{
+ struct timeval now, end_time;
+ GetTimeOfDay(&now);
+ end_time = timeval_sum(&request_time, &timeout);
+ return (timeval_compare(&end_time, &now) < 0);
+}
+
+/****************************************************************************
+ Handle the 1 second delay in returning a SHARING_VIOLATION error.
+****************************************************************************/
+
+static void defer_open(struct share_mode_lock *lck,
+ struct timeval request_time,
+ struct timeval timeout,
+ struct smb_request *req,
+ struct deferred_open_record *state)
+{
+ int i;
+
+ /* Paranoia check */
+
+ for (i=0; i<lck->num_share_modes; i++) {
+ struct share_mode_entry *e = &lck->share_modes[i];
+
+ if (!is_deferred_open_entry(e)) {
+ continue;
+ }
+
+ if (procid_is_me(&e->pid) && (e->op_mid == req->mid)) {
+ DEBUG(0, ("Trying to defer an already deferred "
+ "request: mid=%d, exiting\n", req->mid));
+ exit_server("attempt to defer a deferred request");
+ }
+ }
+
+ /* End paranoia check */
+
+ DEBUG(10,("defer_open_sharing_error: time [%u.%06u] adding deferred "
+ "open entry for mid %u\n",
+ (unsigned int)request_time.tv_sec,
+ (unsigned int)request_time.tv_usec,
+ (unsigned int)req->mid));
+
+ if (!push_deferred_smb_message(req, request_time, timeout,
+ (char *)state, sizeof(*state))) {
+ exit_server("push_deferred_smb_message failed");
+ }
+ add_deferred_open(lck, req->mid, request_time, state->id);
+
+ /*
+ * Push the MID of this packet on the signing queue.
+ * We only do this once, the first time we push the packet
+ * onto the deferred open queue, as this has a side effect
+ * of incrementing the response sequence number.
+ */
+
+ srv_defer_sign_response(req->mid);
+}
+
+
+/****************************************************************************
+ On overwrite open ensure that the attributes match.
+****************************************************************************/
+
+static bool open_match_attributes(connection_struct *conn,
+ const char *path,
+ uint32 old_dos_attr,
+ uint32 new_dos_attr,
+ mode_t existing_unx_mode,
+ mode_t new_unx_mode,
+ mode_t *returned_unx_mode)
+{
+ uint32 noarch_old_dos_attr, noarch_new_dos_attr;
+
+ noarch_old_dos_attr = (old_dos_attr & ~FILE_ATTRIBUTE_ARCHIVE);
+ noarch_new_dos_attr = (new_dos_attr & ~FILE_ATTRIBUTE_ARCHIVE);
+
+ if((noarch_old_dos_attr == 0 && noarch_new_dos_attr != 0) ||
+ (noarch_old_dos_attr != 0 && ((noarch_old_dos_attr & noarch_new_dos_attr) == noarch_old_dos_attr))) {
+ *returned_unx_mode = new_unx_mode;
+ } else {
+ *returned_unx_mode = (mode_t)0;
+ }
+
+ DEBUG(10,("open_match_attributes: file %s old_dos_attr = 0x%x, "
+ "existing_unx_mode = 0%o, new_dos_attr = 0x%x "
+ "returned_unx_mode = 0%o\n",
+ path,
+ (unsigned int)old_dos_attr,
+ (unsigned int)existing_unx_mode,
+ (unsigned int)new_dos_attr,
+ (unsigned int)*returned_unx_mode ));
+
+ /* If we're mapping SYSTEM and HIDDEN ensure they match. */
+ if (lp_map_system(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) {
+ if ((old_dos_attr & FILE_ATTRIBUTE_SYSTEM) &&
+ !(new_dos_attr & FILE_ATTRIBUTE_SYSTEM)) {
+ return False;
+ }
+ }
+ if (lp_map_hidden(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) {
+ if ((old_dos_attr & FILE_ATTRIBUTE_HIDDEN) &&
+ !(new_dos_attr & FILE_ATTRIBUTE_HIDDEN)) {
+ return False;
+ }
+ }
+ return True;
+}
+
+/****************************************************************************
+ Special FCB or DOS processing in the case of a sharing violation.
+ Try and find a duplicated file handle.
+****************************************************************************/
+
+static files_struct *fcb_or_dos_open(connection_struct *conn,
+ const char *fname,
+ struct file_id id,
+ uint16 file_pid,
+ uint16 vuid,
+ uint32 access_mask,
+ uint32 share_access,
+ uint32 create_options)
+{
+ files_struct *fsp;
+ files_struct *dup_fsp;
+
+ DEBUG(5,("fcb_or_dos_open: attempting old open semantics for "
+ "file %s.\n", fname ));
+
+ for(fsp = file_find_di_first(id); fsp;
+ fsp = file_find_di_next(fsp)) {
+
+ DEBUG(10,("fcb_or_dos_open: checking file %s, fd = %d, "
+ "vuid = %u, file_pid = %u, private_options = 0x%x "
+ "access_mask = 0x%x\n", fsp->fsp_name,
+ fsp->fh->fd, (unsigned int)fsp->vuid,
+ (unsigned int)fsp->file_pid,
+ (unsigned int)fsp->fh->private_options,
+ (unsigned int)fsp->access_mask ));
+
+ if (fsp->fh->fd != -1 &&
+ fsp->vuid == vuid &&
+ fsp->file_pid == file_pid &&
+ (fsp->fh->private_options & (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
+ NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
+ (fsp->access_mask & FILE_WRITE_DATA) &&
+ strequal(fsp->fsp_name, fname)) {
+ DEBUG(10,("fcb_or_dos_open: file match\n"));
+ break;
+ }
+ }
+
+ if (!fsp) {
+ return NULL;
+ }
+
+ /* quite an insane set of semantics ... */
+ if (is_executable(fname) &&
+ (fsp->fh->private_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
+ DEBUG(10,("fcb_or_dos_open: file fail due to is_executable.\n"));
+ return NULL;
+ }
+
+ /* We need to duplicate this fsp. */
+ if (!NT_STATUS_IS_OK(dup_file_fsp(fsp, access_mask, share_access,
+ create_options, &dup_fsp))) {
+ return NULL;
+ }
+
+ return dup_fsp;
+}
+
+/****************************************************************************
+ Open a file with a share mode - old openX method - map into NTCreate.
+****************************************************************************/
+
+bool map_open_params_to_ntcreate(const char *fname, int deny_mode, int open_func,
+ uint32 *paccess_mask,
+ uint32 *pshare_mode,
+ uint32 *pcreate_disposition,
+ uint32 *pcreate_options)
+{
+ uint32 access_mask;
+ uint32 share_mode;
+ uint32 create_disposition;
+ uint32 create_options = 0;
+
+ DEBUG(10,("map_open_params_to_ntcreate: fname = %s, deny_mode = 0x%x, "
+ "open_func = 0x%x\n",
+ fname, (unsigned int)deny_mode, (unsigned int)open_func ));
+
+ /* Create the NT compatible access_mask. */
+ switch (GET_OPENX_MODE(deny_mode)) {
+ case DOS_OPEN_EXEC: /* Implies read-only - used to be FILE_READ_DATA */
+ case DOS_OPEN_RDONLY:
+ access_mask = FILE_GENERIC_READ;
+ break;
+ case DOS_OPEN_WRONLY:
+ access_mask = FILE_GENERIC_WRITE;
+ break;
+ case DOS_OPEN_RDWR:
+ case DOS_OPEN_FCB:
+ access_mask = FILE_GENERIC_READ|FILE_GENERIC_WRITE;
+ break;
+ default:
+ DEBUG(10,("map_open_params_to_ntcreate: bad open mode = 0x%x\n",
+ (unsigned int)GET_OPENX_MODE(deny_mode)));
+ return False;
+ }
+
+ /* Create the NT compatible create_disposition. */
+ switch (open_func) {
+ case OPENX_FILE_EXISTS_FAIL|OPENX_FILE_CREATE_IF_NOT_EXIST:
+ create_disposition = FILE_CREATE;
+ break;
+
+ case OPENX_FILE_EXISTS_OPEN:
+ create_disposition = FILE_OPEN;
+ break;
+
+ case OPENX_FILE_EXISTS_OPEN|OPENX_FILE_CREATE_IF_NOT_EXIST:
+ create_disposition = FILE_OPEN_IF;
+ break;
+
+ case OPENX_FILE_EXISTS_TRUNCATE:
+ create_disposition = FILE_OVERWRITE;
+ break;
+
+ case OPENX_FILE_EXISTS_TRUNCATE|OPENX_FILE_CREATE_IF_NOT_EXIST:
+ create_disposition = FILE_OVERWRITE_IF;
+ break;
+
+ default:
+ /* From samba4 - to be confirmed. */
+ if (GET_OPENX_MODE(deny_mode) == DOS_OPEN_EXEC) {
+ create_disposition = FILE_CREATE;
+ break;
+ }
+ DEBUG(10,("map_open_params_to_ntcreate: bad "
+ "open_func 0x%x\n", (unsigned int)open_func));
+ return False;
+ }
+
+ /* Create the NT compatible share modes. */
+ switch (GET_DENY_MODE(deny_mode)) {
+ case DENY_ALL:
+ share_mode = FILE_SHARE_NONE;
+ break;
+
+ case DENY_WRITE:
+ share_mode = FILE_SHARE_READ;
+ break;
+
+ case DENY_READ:
+ share_mode = FILE_SHARE_WRITE;
+ break;
+
+ case DENY_NONE:
+ share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
+ break;
+
+ case DENY_DOS:
+ create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
+ if (is_executable(fname)) {
+ share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
+ } else {
+ if (GET_OPENX_MODE(deny_mode) == DOS_OPEN_RDONLY) {
+ share_mode = FILE_SHARE_READ;
+ } else {
+ share_mode = FILE_SHARE_NONE;
+ }
+ }
+ break;
+
+ case DENY_FCB:
+ create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
+ share_mode = FILE_SHARE_NONE;
+ break;
+
+ default:
+ DEBUG(10,("map_open_params_to_ntcreate: bad deny_mode 0x%x\n",
+ (unsigned int)GET_DENY_MODE(deny_mode) ));
+ return False;
+ }
+
+ DEBUG(10,("map_open_params_to_ntcreate: file %s, access_mask = 0x%x, "
+ "share_mode = 0x%x, create_disposition = 0x%x, "
+ "create_options = 0x%x\n",
+ fname,
+ (unsigned int)access_mask,
+ (unsigned int)share_mode,
+ (unsigned int)create_disposition,
+ (unsigned int)create_options ));
+
+ if (paccess_mask) {
+ *paccess_mask = access_mask;
+ }
+ if (pshare_mode) {
+ *pshare_mode = share_mode;
+ }
+ if (pcreate_disposition) {
+ *pcreate_disposition = create_disposition;
+ }
+ if (pcreate_options) {
+ *pcreate_options = create_options;
+ }
+
+ return True;
+
+}
+
+static void schedule_defer_open(struct share_mode_lock *lck,
+ struct timeval request_time,
+ struct smb_request *req)
+{
+ struct deferred_open_record state;
+
+ /* This is a relative time, added to the absolute
+ request_time value to get the absolute timeout time.
+ Note that if this is the second or greater time we enter
+ this codepath for this particular request mid then
+ request_time is left as the absolute time of the *first*
+ time this request mid was processed. This is what allows
+ the request to eventually time out. */
+
+ struct timeval timeout;
+
+ /* Normally the smbd we asked should respond within
+ * OPLOCK_BREAK_TIMEOUT seconds regardless of whether
+ * the client did, give twice the timeout as a safety
+ * measure here in case the other smbd is stuck
+ * somewhere else. */
+
+ timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0);
+
+ /* Nothing actually uses state.delayed_for_oplocks
+ but it's handy to differentiate in debug messages
+ between a 30 second delay due to oplock break, and
+ a 1 second delay for share mode conflicts. */
+
+ state.delayed_for_oplocks = True;
+ state.id = lck->id;
+
+ if (!request_timed_out(request_time, timeout)) {
+ defer_open(lck, request_time, timeout, req, &state);
+ }
+}
+
+/****************************************************************************
+ Open a file with a share mode.
+****************************************************************************/
+
+NTSTATUS open_file_ntcreate(connection_struct *conn,
+ struct smb_request *req,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf,
+ uint32 access_mask, /* access bits (FILE_READ_DATA etc.) */
+ uint32 share_access, /* share constants (FILE_SHARE_READ etc) */
+ uint32 create_disposition, /* FILE_OPEN_IF etc. */
+ uint32 create_options, /* options such as delete on close. */
+ uint32 new_dos_attributes, /* attributes used for new file. */
+ int oplock_request, /* internal Samba oplock codes. */
+ /* Information (FILE_EXISTS etc.) */
+ int *pinfo,
+ files_struct **result)
+{
+ int flags=0;
+ int flags2=0;
+ bool file_existed = VALID_STAT(*psbuf);
+ bool def_acl = False;
+ bool posix_open = False;
+ bool new_file_created = False;
+ struct file_id id;
+ NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED;
+ files_struct *fsp = NULL;
+ mode_t new_unx_mode = (mode_t)0;
+ mode_t unx_mode = (mode_t)0;
+ int info;
+ uint32 existing_dos_attributes = 0;
+ struct pending_message_list *pml = NULL;
+ struct timeval request_time = timeval_zero();
+ struct share_mode_lock *lck = NULL;
+ uint32 open_access_mask = access_mask;
+ NTSTATUS status;
+ int ret_flock;
+ char *parent_dir;
+ const char *newname;
+
+ ZERO_STRUCT(id);
+
+ if (conn->printer) {
+ /*
+ * Printers are handled completely differently.
+ * Most of the passed parameters are ignored.
+ */
+
+ if (pinfo) {
+ *pinfo = FILE_WAS_CREATED;
+ }
+
+ DEBUG(10, ("open_file_ntcreate: printer open fname=%s\n", fname));
+
+ return print_fsp_open(conn, fname, req->vuid, result);
+ }
+
+ if (!parent_dirname_talloc(talloc_tos(), fname, &parent_dir,
+ &newname)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (new_dos_attributes & FILE_FLAG_POSIX_SEMANTICS) {
+ posix_open = True;
+ unx_mode = (mode_t)(new_dos_attributes & ~FILE_FLAG_POSIX_SEMANTICS);
+ new_dos_attributes = 0;
+ } else {
+ /* We add aARCH to this as this mode is only used if the file is
+ * created new. */
+ unx_mode = unix_mode(conn, new_dos_attributes | aARCH, fname,
+ parent_dir);
+ }
+
+ DEBUG(10, ("open_file_ntcreate: fname=%s, dos_attrs=0x%x "
+ "access_mask=0x%x share_access=0x%x "
+ "create_disposition = 0x%x create_options=0x%x "
+ "unix mode=0%o oplock_request=%d\n",
+ fname, new_dos_attributes, access_mask, share_access,
+ create_disposition, create_options, unx_mode,
+ oplock_request));
+
+ if ((req == NULL) && ((oplock_request & INTERNAL_OPEN_ONLY) == 0)) {
+ DEBUG(0, ("No smb request but not an internal only open!\n"));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /*
+ * Only non-internal opens can be deferred at all
+ */
+
+ if ((req != NULL)
+ && ((pml = get_open_deferred_message(req->mid)) != NULL)) {
+ struct deferred_open_record *state =
+ (struct deferred_open_record *)pml->private_data.data;
+
+ /* Remember the absolute time of the original
+ request with this mid. We'll use it later to
+ see if this has timed out. */
+
+ request_time = pml->request_time;
+
+ /* Remove the deferred open entry under lock. */
+ lck = get_share_mode_lock(talloc_tos(), state->id, NULL, NULL,
+ NULL);
+ if (lck == NULL) {
+ DEBUG(0, ("could not get share mode lock\n"));
+ } else {
+ del_deferred_open_entry(lck, req->mid);
+ TALLOC_FREE(lck);
+ }
+
+ /* Ensure we don't reprocess this message. */
+ remove_deferred_open_smb_message(req->mid);
+ }
+
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (!posix_open) {
+ new_dos_attributes &= SAMBA_ATTRIBUTES_MASK;
+ if (file_existed) {
+ existing_dos_attributes = dos_mode(conn, fname, psbuf);
+ }
+ }
+
+ /* ignore any oplock requests if oplocks are disabled */
+ if (!lp_oplocks(SNUM(conn)) || global_client_failed_oplock_break ||
+ IS_VETO_OPLOCK_PATH(conn, fname)) {
+ /* Mask off everything except the private Samba bits. */
+ oplock_request &= SAMBA_PRIVATE_OPLOCK_MASK;
+ }
+
+ /* this is for OS/2 long file names - say we don't support them */
+ if (!lp_posix_pathnames() && strstr(fname,".+,;=[].")) {
+ /* OS/2 Workplace shell fix may be main code stream in a later
+ * release. */
+ DEBUG(5,("open_file_ntcreate: OS/2 long filenames are not "
+ "supported.\n"));
+ if (use_nt_status()) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ return NT_STATUS_DOS(ERRDOS, ERRcannotopen);
+ }
+
+ switch( create_disposition ) {
+ /*
+ * Currently we're using FILE_SUPERSEDE as the same as
+ * FILE_OVERWRITE_IF but they really are
+ * different. FILE_SUPERSEDE deletes an existing file
+ * (requiring delete access) then recreates it.
+ */
+ case FILE_SUPERSEDE:
+ /* If file exists replace/overwrite. If file doesn't
+ * exist create. */
+ flags2 |= (O_CREAT | O_TRUNC);
+ break;
+
+ case FILE_OVERWRITE_IF:
+ /* If file exists replace/overwrite. If file doesn't
+ * exist create. */
+ flags2 |= (O_CREAT | O_TRUNC);
+ break;
+
+ case FILE_OPEN:
+ /* If file exists open. If file doesn't exist error. */
+ if (!file_existed) {
+ DEBUG(5,("open_file_ntcreate: FILE_OPEN "
+ "requested for file %s and file "
+ "doesn't exist.\n", fname ));
+ errno = ENOENT;
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ break;
+
+ case FILE_OVERWRITE:
+ /* If file exists overwrite. If file doesn't exist
+ * error. */
+ if (!file_existed) {
+ DEBUG(5,("open_file_ntcreate: FILE_OVERWRITE "
+ "requested for file %s and file "
+ "doesn't exist.\n", fname ));
+ errno = ENOENT;
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ flags2 |= O_TRUNC;
+ break;
+
+ case FILE_CREATE:
+ /* If file exists error. If file doesn't exist
+ * create. */
+ if (file_existed) {
+ DEBUG(5,("open_file_ntcreate: FILE_CREATE "
+ "requested for file %s and file "
+ "already exists.\n", fname ));
+ if (S_ISDIR(psbuf->st_mode)) {
+ errno = EISDIR;
+ } else {
+ errno = EEXIST;
+ }
+ return map_nt_error_from_unix(errno);
+ }
+ flags2 |= (O_CREAT|O_EXCL);
+ break;
+
+ case FILE_OPEN_IF:
+ /* If file exists open. If file doesn't exist
+ * create. */
+ flags2 |= O_CREAT;
+ break;
+
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* We only care about matching attributes on file exists and
+ * overwrite. */
+
+ if (!posix_open && file_existed && ((create_disposition == FILE_OVERWRITE) ||
+ (create_disposition == FILE_OVERWRITE_IF))) {
+ if (!open_match_attributes(conn, fname,
+ existing_dos_attributes,
+ new_dos_attributes, psbuf->st_mode,
+ unx_mode, &new_unx_mode)) {
+ DEBUG(5,("open_file_ntcreate: attributes missmatch "
+ "for file %s (%x %x) (0%o, 0%o)\n",
+ fname, existing_dos_attributes,
+ new_dos_attributes,
+ (unsigned int)psbuf->st_mode,
+ (unsigned int)unx_mode ));
+ errno = EACCES;
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ /* This is a nasty hack - must fix... JRA. */
+ if (access_mask == MAXIMUM_ALLOWED_ACCESS) {
+ open_access_mask = access_mask = FILE_GENERIC_ALL;
+ }
+
+ /*
+ * Convert GENERIC bits to specific bits.
+ */
+
+ se_map_generic(&access_mask, &file_generic_mapping);
+ open_access_mask = access_mask;
+
+ if ((flags2 & O_TRUNC) || (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE)) {
+ open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */
+ }
+
+ DEBUG(10, ("open_file_ntcreate: fname=%s, after mapping "
+ "access_mask=0x%x\n", fname, access_mask ));
+
+ /*
+ * Note that we ignore the append flag as append does not
+ * mean the same thing under DOS and Unix.
+ */
+
+ if ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ||
+ (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE)) {
+ /* DENY_DOS opens are always underlying read-write on the
+ file handle, no matter what the requested access mask
+ says. */
+ if ((create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS) ||
+ access_mask & (FILE_READ_ATTRIBUTES|FILE_READ_DATA|FILE_READ_EA|FILE_EXECUTE)) {
+ flags = O_RDWR;
+ } else {
+ flags = O_WRONLY;
+ }
+ } else {
+ flags = O_RDONLY;
+ }
+
+ /*
+ * Currently we only look at FILE_WRITE_THROUGH for create options.
+ */
+
+#if defined(O_SYNC)
+ if ((create_options & FILE_WRITE_THROUGH) && lp_strict_sync(SNUM(conn))) {
+ flags2 |= O_SYNC;
+ }
+#endif /* O_SYNC */
+
+ if (posix_open && (access_mask & FILE_APPEND_DATA)) {
+ flags2 |= O_APPEND;
+ }
+
+ if (!posix_open && !CAN_WRITE(conn)) {
+ /*
+ * We should really return a permission denied error if either
+ * O_CREAT or O_TRUNC are set, but for compatibility with
+ * older versions of Samba we just AND them out.
+ */
+ flags2 &= ~(O_CREAT|O_TRUNC);
+ }
+
+ /*
+ * Ensure we can't write on a read-only share or file.
+ */
+
+ if (flags != O_RDONLY && file_existed &&
+ (!CAN_WRITE(conn) || IS_DOS_READONLY(existing_dos_attributes))) {
+ DEBUG(5,("open_file_ntcreate: write access requested for "
+ "file %s on read only %s\n",
+ fname, !CAN_WRITE(conn) ? "share" : "file" ));
+ errno = EACCES;
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = file_new(conn, &fsp);
+ if(!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf);
+ fsp->share_access = share_access;
+ fsp->fh->private_options = create_options;
+ fsp->access_mask = open_access_mask; /* We change this to the
+ * requested access_mask after
+ * the open is done. */
+ fsp->posix_open = posix_open;
+
+ /* Ensure no SAMBA_PRIVATE bits can be set. */
+ fsp->oplock_type = (oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK);
+
+ if (timeval_is_zero(&request_time)) {
+ request_time = fsp->open_time;
+ }
+
+ if (file_existed) {
+ struct timespec old_write_time = get_mtimespec(psbuf);
+ id = vfs_file_id_from_sbuf(conn, psbuf);
+
+ lck = get_share_mode_lock(talloc_tos(), id,
+ conn->connectpath,
+ fname, &old_write_time);
+
+ if (lck == NULL) {
+ file_free(fsp);
+ DEBUG(0, ("Could not get share mode lock\n"));
+ return NT_STATUS_SHARING_VIOLATION;
+ }
+
+ /* First pass - send break only on batch oplocks. */
+ if ((req != NULL)
+ && delay_for_oplocks(lck, fsp, req->mid, 1,
+ oplock_request)) {
+ schedule_defer_open(lck, request_time, req);
+ TALLOC_FREE(lck);
+ file_free(fsp);
+ return NT_STATUS_SHARING_VIOLATION;
+ }
+
+ /* Use the client requested access mask here, not the one we
+ * open with. */
+ status = open_mode_check(conn, fname, lck,
+ access_mask, share_access,
+ create_options, &file_existed);
+
+ if (NT_STATUS_IS_OK(status)) {
+ /* We might be going to allow this open. Check oplock
+ * status again. */
+ /* Second pass - send break for both batch or
+ * exclusive oplocks. */
+ if ((req != NULL)
+ && delay_for_oplocks(lck, fsp, req->mid, 2,
+ oplock_request)) {
+ schedule_defer_open(lck, request_time, req);
+ TALLOC_FREE(lck);
+ file_free(fsp);
+ return NT_STATUS_SHARING_VIOLATION;
+ }
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
+ /* DELETE_PENDING is not deferred for a second */
+ TALLOC_FREE(lck);
+ file_free(fsp);
+ return status;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ uint32 can_access_mask;
+ bool can_access = True;
+
+ SMB_ASSERT(NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION));
+
+ /* Check if this can be done with the deny_dos and fcb
+ * calls. */
+ if (create_options &
+ (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
+ NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
+ files_struct *fsp_dup;
+
+ if (req == NULL) {
+ DEBUG(0, ("DOS open without an SMB "
+ "request!\n"));
+ TALLOC_FREE(lck);
+ file_free(fsp);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /* Use the client requested access mask here,
+ * not the one we open with. */
+ fsp_dup = fcb_or_dos_open(conn, fname, id,
+ req->smbpid,
+ req->vuid,
+ access_mask,
+ share_access,
+ create_options);
+
+ if (fsp_dup) {
+ TALLOC_FREE(lck);
+ file_free(fsp);
+ if (pinfo) {
+ *pinfo = FILE_WAS_OPENED;
+ }
+ conn->num_files_open++;
+ *result = fsp_dup;
+ return NT_STATUS_OK;
+ }
+ }
+
+ /*
+ * This next line is a subtlety we need for
+ * MS-Access. If a file open will fail due to share
+ * permissions and also for security (access) reasons,
+ * we need to return the access failed error, not the
+ * share error. We can't open the file due to kernel
+ * oplock deadlock (it's possible we failed above on
+ * the open_mode_check()) so use a userspace check.
+ */
+
+ if (flags & O_RDWR) {
+ can_access_mask = FILE_READ_DATA|FILE_WRITE_DATA;
+ } else if (flags & O_WRONLY) {
+ can_access_mask = FILE_WRITE_DATA;
+ } else {
+ can_access_mask = FILE_READ_DATA;
+ }
+
+ if (((can_access_mask & FILE_WRITE_DATA) && !CAN_WRITE(conn)) ||
+ !can_access_file_data(conn,fname,psbuf,can_access_mask)) {
+ can_access = False;
+ }
+
+ /*
+ * If we're returning a share violation, ensure we
+ * cope with the braindead 1 second delay.
+ */
+
+ if (!(oplock_request & INTERNAL_OPEN_ONLY) &&
+ lp_defer_sharing_violations()) {
+ struct timeval timeout;
+ struct deferred_open_record state;
+ int timeout_usecs;
+
+ /* this is a hack to speed up torture tests
+ in 'make test' */
+ timeout_usecs = lp_parm_int(SNUM(conn),
+ "smbd","sharedelay",
+ SHARING_VIOLATION_USEC_WAIT);
+
+ /* This is a relative time, added to the absolute
+ request_time value to get the absolute timeout time.
+ Note that if this is the second or greater time we enter
+ this codepath for this particular request mid then
+ request_time is left as the absolute time of the *first*
+ time this request mid was processed. This is what allows
+ the request to eventually time out. */
+
+ timeout = timeval_set(0, timeout_usecs);
+
+ /* Nothing actually uses state.delayed_for_oplocks
+ but it's handy to differentiate in debug messages
+ between a 30 second delay due to oplock break, and
+ a 1 second delay for share mode conflicts. */
+
+ state.delayed_for_oplocks = False;
+ state.id = id;
+
+ if ((req != NULL)
+ && !request_timed_out(request_time,
+ timeout)) {
+ defer_open(lck, request_time, timeout,
+ req, &state);
+ }
+ }
+
+ TALLOC_FREE(lck);
+ if (can_access) {
+ /*
+ * We have detected a sharing violation here
+ * so return the correct error code
+ */
+ status = NT_STATUS_SHARING_VIOLATION;
+ } else {
+ status = NT_STATUS_ACCESS_DENIED;
+ }
+ file_free(fsp);
+ return status;
+ }
+
+ /*
+ * We exit this block with the share entry *locked*.....
+ */
+ }
+
+ SMB_ASSERT(!file_existed || (lck != NULL));
+
+ /*
+ * Ensure we pay attention to default ACLs on directories if required.
+ */
+
+ if ((flags2 & O_CREAT) && lp_inherit_acls(SNUM(conn)) &&
+ (def_acl = directory_has_default_acl(conn, parent_dir))) {
+ unx_mode = 0777;
+ }
+
+ DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o, "
+ "access_mask = 0x%x, open_access_mask = 0x%x\n",
+ (unsigned int)flags, (unsigned int)flags2,
+ (unsigned int)unx_mode, (unsigned int)access_mask,
+ (unsigned int)open_access_mask));
+
+ /*
+ * open_file strips any O_TRUNC flags itself.
+ */
+
+ fsp_open = open_file(fsp, conn, req, parent_dir, newname, fname, psbuf,
+ flags|flags2, unx_mode, access_mask,
+ open_access_mask);
+
+ if (!NT_STATUS_IS_OK(fsp_open)) {
+ if (lck != NULL) {
+ TALLOC_FREE(lck);
+ }
+ file_free(fsp);
+ return fsp_open;
+ }
+
+ if (!file_existed) {
+ struct timespec old_write_time = get_mtimespec(psbuf);
+ /*
+ * Deal with the race condition where two smbd's detect the
+ * file doesn't exist and do the create at the same time. One
+ * of them will win and set a share mode, the other (ie. this
+ * one) should check if the requested share mode for this
+ * create is allowed.
+ */
+
+ /*
+ * Now the file exists and fsp is successfully opened,
+ * fsp->dev and fsp->inode are valid and should replace the
+ * dev=0,inode=0 from a non existent file. Spotted by
+ * Nadav Danieli <nadavd@exanet.com>. JRA.
+ */
+
+ id = fsp->file_id;
+
+ lck = get_share_mode_lock(talloc_tos(), id,
+ conn->connectpath,
+ fname, &old_write_time);
+
+ if (lck == NULL) {
+ DEBUG(0, ("open_file_ntcreate: Could not get share "
+ "mode lock for %s\n", fname));
+ fd_close(fsp);
+ file_free(fsp);
+ return NT_STATUS_SHARING_VIOLATION;
+ }
+
+ /* First pass - send break only on batch oplocks. */
+ if ((req != NULL)
+ && delay_for_oplocks(lck, fsp, req->mid, 1,
+ oplock_request)) {
+ schedule_defer_open(lck, request_time, req);
+ TALLOC_FREE(lck);
+ fd_close(fsp);
+ file_free(fsp);
+ return NT_STATUS_SHARING_VIOLATION;
+ }
+
+ status = open_mode_check(conn, fname, lck,
+ access_mask, share_access,
+ create_options, &file_existed);
+
+ if (NT_STATUS_IS_OK(status)) {
+ /* We might be going to allow this open. Check oplock
+ * status again. */
+ /* Second pass - send break for both batch or
+ * exclusive oplocks. */
+ if ((req != NULL)
+ && delay_for_oplocks(lck, fsp, req->mid, 2,
+ oplock_request)) {
+ schedule_defer_open(lck, request_time, req);
+ TALLOC_FREE(lck);
+ fd_close(fsp);
+ file_free(fsp);
+ return NT_STATUS_SHARING_VIOLATION;
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ struct deferred_open_record state;
+
+ fd_close(fsp);
+ file_free(fsp);
+
+ state.delayed_for_oplocks = False;
+ state.id = id;
+
+ /* Do it all over again immediately. In the second
+ * round we will find that the file existed and handle
+ * the DELETE_PENDING and FCB cases correctly. No need
+ * to duplicate the code here. Essentially this is a
+ * "goto top of this function", but don't tell
+ * anybody... */
+
+ if (req != NULL) {
+ defer_open(lck, request_time, timeval_zero(),
+ req, &state);
+ }
+ TALLOC_FREE(lck);
+ return status;
+ }
+
+ /*
+ * We exit this block with the share entry *locked*.....
+ */
+
+ }
+
+ SMB_ASSERT(lck != NULL);
+
+ /* note that we ignore failure for the following. It is
+ basically a hack for NFS, and NFS will never set one of
+ these only read them. Nobody but Samba can ever set a deny
+ mode and we have already checked our more authoritative
+ locking database for permission to set this deny mode. If
+ the kernel refuses the operations then the kernel is wrong.
+ note that GPFS supports it as well - jmcd */
+
+ if (fsp->fh->fd != -1) {
+ ret_flock = SMB_VFS_KERNEL_FLOCK(fsp, share_access);
+ if(ret_flock == -1 ){
+
+ TALLOC_FREE(lck);
+ fd_close(fsp);
+ file_free(fsp);
+
+ return NT_STATUS_SHARING_VIOLATION;
+ }
+ }
+
+ /*
+ * At this point onwards, we can guarentee that the share entry
+ * is locked, whether we created the file or not, and that the
+ * deny mode is compatible with all current opens.
+ */
+
+ /*
+ * If requested, truncate the file.
+ */
+
+ if (flags2&O_TRUNC) {
+ /*
+ * We are modifing the file after open - update the stat
+ * struct..
+ */
+ if ((SMB_VFS_FTRUNCATE(fsp, 0) == -1) ||
+ (SMB_VFS_FSTAT(fsp, psbuf)==-1)) {
+ status = map_nt_error_from_unix(errno);
+ TALLOC_FREE(lck);
+ fd_close(fsp);
+ file_free(fsp);
+ return status;
+ }
+ }
+
+ /* Record the options we were opened with. */
+ fsp->share_access = share_access;
+ fsp->fh->private_options = create_options;
+ fsp->access_mask = access_mask;
+
+ if (file_existed) {
+ /* stat opens on existing files don't get oplocks. */
+ if (is_stat_open(open_access_mask)) {
+ fsp->oplock_type = NO_OPLOCK;
+ }
+
+ if (!(flags2 & O_TRUNC)) {
+ info = FILE_WAS_OPENED;
+ } else {
+ info = FILE_WAS_OVERWRITTEN;
+ }
+ } else {
+ info = FILE_WAS_CREATED;
+ }
+
+ if (pinfo) {
+ *pinfo = info;
+ }
+
+ /*
+ * Setup the oplock info in both the shared memory and
+ * file structs.
+ */
+
+ if ((fsp->oplock_type != NO_OPLOCK) &&
+ (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK)) {
+ if (!set_file_oplock(fsp, fsp->oplock_type)) {
+ /* Could not get the kernel oplock */
+ fsp->oplock_type = NO_OPLOCK;
+ }
+ }
+
+ if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || info == FILE_WAS_SUPERSEDED) {
+ new_file_created = True;
+ }
+
+ set_share_mode(lck, fsp, conn->server_info->utok.uid, 0,
+ fsp->oplock_type, new_file_created);
+
+ /* Handle strange delete on close create semantics. */
+ if ((create_options & FILE_DELETE_ON_CLOSE)
+ && (is_ntfs_stream_name(fname)
+ || can_set_initial_delete_on_close(lck))) {
+ status = can_set_delete_on_close(fsp, True, new_dos_attributes);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ /* Remember to delete the mode we just added. */
+ del_share_mode(lck, fsp);
+ TALLOC_FREE(lck);
+ fd_close(fsp);
+ file_free(fsp);
+ return status;
+ }
+ /* Note that here we set the *inital* delete on close flag,
+ not the regular one. The magic gets handled in close. */
+ fsp->initial_delete_on_close = True;
+ }
+
+ if (new_file_created) {
+ /* Files should be initially set as archive */
+ if (lp_map_archive(SNUM(conn)) ||
+ lp_store_dos_attributes(SNUM(conn))) {
+ if (!posix_open) {
+ SMB_STRUCT_STAT tmp_sbuf;
+ SET_STAT_INVALID(tmp_sbuf);
+ if (file_set_dosmode(
+ conn, fname,
+ new_dos_attributes | aARCH,
+ &tmp_sbuf, parent_dir,
+ true) == 0) {
+ unx_mode = tmp_sbuf.st_mode;
+ }
+ }
+ }
+ }
+
+ /*
+ * Take care of inherited ACLs on created files - if default ACL not
+ * selected.
+ */
+
+ if (!posix_open && !file_existed && !def_acl) {
+
+ int saved_errno = errno; /* We might get ENOSYS in the next
+ * call.. */
+
+ if (SMB_VFS_FCHMOD_ACL(fsp, unx_mode) == -1 &&
+ errno == ENOSYS) {
+ errno = saved_errno; /* Ignore ENOSYS */
+ }
+
+ } else if (new_unx_mode) {
+
+ int ret = -1;
+
+ /* Attributes need changing. File already existed. */
+
+ {
+ int saved_errno = errno; /* We might get ENOSYS in the
+ * next call.. */
+ ret = SMB_VFS_FCHMOD_ACL(fsp, new_unx_mode);
+
+ if (ret == -1 && errno == ENOSYS) {
+ errno = saved_errno; /* Ignore ENOSYS */
+ } else {
+ DEBUG(5, ("open_file_ntcreate: reset "
+ "attributes of file %s to 0%o\n",
+ fname, (unsigned int)new_unx_mode));
+ ret = 0; /* Don't do the fchmod below. */
+ }
+ }
+
+ if ((ret == -1) &&
+ (SMB_VFS_FCHMOD(fsp, new_unx_mode) == -1))
+ DEBUG(5, ("open_file_ntcreate: failed to reset "
+ "attributes of file %s to 0%o\n",
+ fname, (unsigned int)new_unx_mode));
+ }
+
+ /* If this is a successful open, we must remove any deferred open
+ * records. */
+ if (req != NULL) {
+ del_deferred_open_entry(lck, req->mid);
+ }
+ TALLOC_FREE(lck);
+
+ conn->num_files_open++;
+
+ *result = fsp;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Open a file for for write to ensure that we can fchmod it.
+****************************************************************************/
+
+NTSTATUS open_file_fchmod(connection_struct *conn, const char *fname,
+ SMB_STRUCT_STAT *psbuf, files_struct **result)
+{
+ files_struct *fsp = NULL;
+ NTSTATUS status;
+
+ if (!VALID_STAT(*psbuf)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = file_new(conn, &fsp);
+ if(!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* note! we must use a non-zero desired access or we don't get
+ a real file descriptor. Oh what a twisted web we weave. */
+ status = open_file(fsp, conn, NULL, NULL, NULL, fname, psbuf, O_WRONLY,
+ 0, FILE_WRITE_DATA, FILE_WRITE_DATA);
+
+ /*
+ * This is not a user visible file open.
+ * Don't set a share mode and don't increment
+ * the conn->num_files_open.
+ */
+
+ if (!NT_STATUS_IS_OK(status)) {
+ file_free(fsp);
+ return status;
+ }
+
+ *result = fsp;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Close the fchmod file fd - ensure no locks are lost.
+****************************************************************************/
+
+NTSTATUS close_file_fchmod(files_struct *fsp)
+{
+ NTSTATUS status = fd_close(fsp);
+ file_free(fsp);
+ return status;
+}
+
+static NTSTATUS mkdir_internal(connection_struct *conn,
+ const char *name,
+ uint32 file_attributes,
+ SMB_STRUCT_STAT *psbuf)
+{
+ mode_t mode;
+ char *parent_dir;
+ const char *dirname;
+ NTSTATUS status;
+ bool posix_open = false;
+
+ if(!CAN_WRITE(conn)) {
+ DEBUG(5,("mkdir_internal: failing create on read-only share "
+ "%s\n", lp_servicename(SNUM(conn))));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = check_name(conn, name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (!parent_dirname_talloc(talloc_tos(), name, &parent_dir,
+ &dirname)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) {
+ posix_open = true;
+ mode = (mode_t)(file_attributes & ~FILE_FLAG_POSIX_SEMANTICS);
+ } else {
+ mode = unix_mode(conn, aDIR, name, parent_dir);
+ }
+
+ if (SMB_VFS_MKDIR(conn, name, mode) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ /* Ensure we're checking for a symlink here.... */
+ /* We don't want to get caught by a symlink racer. */
+
+ if (SMB_VFS_LSTAT(conn, name, psbuf) == -1) {
+ DEBUG(2, ("Could not stat directory '%s' just created: %s\n",
+ name, strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+
+ if (!S_ISDIR(psbuf->st_mode)) {
+ DEBUG(0, ("Directory just '%s' created is not a directory\n",
+ name));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (lp_store_dos_attributes(SNUM(conn))) {
+ if (!posix_open) {
+ file_set_dosmode(conn, name,
+ file_attributes | aDIR, NULL,
+ parent_dir,
+ true);
+ }
+ }
+
+ if (lp_inherit_perms(SNUM(conn))) {
+ inherit_access_posix_acl(conn, parent_dir, name, mode);
+ }
+
+ if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) {
+ /*
+ * Check if high bits should have been set,
+ * then (if bits are missing): add them.
+ * Consider bits automagically set by UNIX, i.e. SGID bit from parent
+ * dir.
+ */
+ if (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) && (mode & ~psbuf->st_mode)) {
+ SMB_VFS_CHMOD(conn, name,
+ psbuf->st_mode | (mode & ~psbuf->st_mode));
+ }
+ }
+
+ /* Change the owner if required. */
+ if (lp_inherit_owner(SNUM(conn))) {
+ change_dir_owner_to_parent(conn, parent_dir, name, psbuf);
+ }
+
+ notify_fname(conn, NOTIFY_ACTION_ADDED, FILE_NOTIFY_CHANGE_DIR_NAME,
+ name);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Open a directory from an NT SMB call.
+****************************************************************************/
+
+NTSTATUS open_directory(connection_struct *conn,
+ struct smb_request *req,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf,
+ uint32 access_mask,
+ uint32 share_access,
+ uint32 create_disposition,
+ uint32 create_options,
+ uint32 file_attributes,
+ int *pinfo,
+ files_struct **result)
+{
+ files_struct *fsp = NULL;
+ bool dir_existed = VALID_STAT(*psbuf) ? True : False;
+ struct share_mode_lock *lck = NULL;
+ NTSTATUS status;
+ struct timespec mtimespec;
+ int info = 0;
+
+ DEBUG(5,("open_directory: opening directory %s, access_mask = 0x%x, "
+ "share_access = 0x%x create_options = 0x%x, "
+ "create_disposition = 0x%x, file_attributes = 0x%x\n",
+ fname,
+ (unsigned int)access_mask,
+ (unsigned int)share_access,
+ (unsigned int)create_options,
+ (unsigned int)create_disposition,
+ (unsigned int)file_attributes));
+
+ if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS) && is_ntfs_stream_name(fname)) {
+ DEBUG(2, ("open_directory: %s is a stream name!\n", fname));
+ return NT_STATUS_NOT_A_DIRECTORY;
+ }
+
+ switch( create_disposition ) {
+ case FILE_OPEN:
+
+ info = FILE_WAS_OPENED;
+
+ /*
+ * We want to follow symlinks here.
+ */
+
+ if (SMB_VFS_STAT(conn, fname, psbuf) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ break;
+
+ case FILE_CREATE:
+
+ /* If directory exists error. If directory doesn't
+ * exist create. */
+
+ status = mkdir_internal(conn,
+ fname,
+ file_attributes,
+ psbuf);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(2, ("open_directory: unable to create "
+ "%s. Error was %s\n", fname,
+ nt_errstr(status)));
+ return status;
+ }
+
+ info = FILE_WAS_CREATED;
+ break;
+
+ case FILE_OPEN_IF:
+ /*
+ * If directory exists open. If directory doesn't
+ * exist create.
+ */
+
+ status = mkdir_internal(conn,
+ fname,
+ file_attributes,
+ psbuf);
+
+ if (NT_STATUS_IS_OK(status)) {
+ info = FILE_WAS_CREATED;
+ }
+
+ if (NT_STATUS_EQUAL(status,
+ NT_STATUS_OBJECT_NAME_COLLISION)) {
+ info = FILE_WAS_OPENED;
+ status = NT_STATUS_OK;
+ }
+
+ break;
+
+ case FILE_SUPERSEDE:
+ case FILE_OVERWRITE:
+ case FILE_OVERWRITE_IF:
+ default:
+ DEBUG(5,("open_directory: invalid create_disposition "
+ "0x%x for directory %s\n",
+ (unsigned int)create_disposition, fname));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if(!S_ISDIR(psbuf->st_mode)) {
+ DEBUG(5,("open_directory: %s is not a directory !\n",
+ fname ));
+ return NT_STATUS_NOT_A_DIRECTORY;
+ }
+
+ status = file_new(conn, &fsp);
+ if(!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * Setup the files_struct for it.
+ */
+
+ fsp->mode = psbuf->st_mode;
+ fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf);
+ fsp->vuid = req ? req->vuid : UID_FIELD_INVALID;
+ fsp->file_pid = req ? req->smbpid : 0;
+ fsp->can_lock = False;
+ fsp->can_read = False;
+ fsp->can_write = False;
+
+ fsp->share_access = share_access;
+ fsp->fh->private_options = create_options;
+ fsp->access_mask = access_mask;
+
+ fsp->print_file = False;
+ fsp->modified = False;
+ fsp->oplock_type = NO_OPLOCK;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+ fsp->is_directory = True;
+ fsp->posix_open = (file_attributes & FILE_FLAG_POSIX_SEMANTICS) ? True : False;
+
+ string_set(&fsp->fsp_name,fname);
+
+ mtimespec = get_mtimespec(psbuf);
+
+ lck = get_share_mode_lock(talloc_tos(), fsp->file_id,
+ conn->connectpath,
+ fname, &mtimespec);
+
+ if (lck == NULL) {
+ DEBUG(0, ("open_directory: Could not get share mode lock for %s\n", fname));
+ file_free(fsp);
+ return NT_STATUS_SHARING_VIOLATION;
+ }
+
+ status = open_mode_check(conn, fname, lck,
+ access_mask, share_access,
+ create_options, &dir_existed);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(lck);
+ file_free(fsp);
+ return status;
+ }
+
+ set_share_mode(lck, fsp, conn->server_info->utok.uid, 0, NO_OPLOCK,
+ True);
+
+ /* For directories the delete on close bit at open time seems
+ always to be honored on close... See test 19 in Samba4 BASE-DELETE. */
+ if (create_options & FILE_DELETE_ON_CLOSE) {
+ status = can_set_delete_on_close(fsp, True, 0);
+ if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_DIRECTORY_NOT_EMPTY)) {
+ TALLOC_FREE(lck);
+ file_free(fsp);
+ return status;
+ }
+
+ if (NT_STATUS_IS_OK(status)) {
+ /* Note that here we set the *inital* delete on close flag,
+ not the regular one. The magic gets handled in close. */
+ fsp->initial_delete_on_close = True;
+ }
+ }
+
+ TALLOC_FREE(lck);
+
+ if (pinfo) {
+ *pinfo = info;
+ }
+
+ conn->num_files_open++;
+
+ *result = fsp;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, const char *directory)
+{
+ NTSTATUS status;
+ SMB_STRUCT_STAT sbuf;
+ files_struct *fsp;
+
+ SET_STAT_INVALID(sbuf);
+
+ status = open_directory(conn, req, directory, &sbuf,
+ FILE_READ_ATTRIBUTES, /* Just a stat open */
+ FILE_SHARE_NONE, /* Ignored for stat opens */
+ FILE_CREATE,
+ 0,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NULL,
+ &fsp);
+
+ if (NT_STATUS_IS_OK(status)) {
+ close_file(fsp, NORMAL_CLOSE);
+ }
+
+ return status;
+}
+
+/****************************************************************************
+ Receive notification that one of our open files has been renamed by another
+ smbd process.
+****************************************************************************/
+
+void msg_file_was_renamed(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ files_struct *fsp;
+ char *frm = (char *)data->data;
+ struct file_id id;
+ const char *sharepath;
+ const char *newname;
+ size_t sp_len;
+
+ if (data->data == NULL
+ || data->length < MSG_FILE_RENAMED_MIN_SIZE + 2) {
+ DEBUG(0, ("msg_file_was_renamed: Got invalid msg len %d\n",
+ (int)data->length));
+ return;
+ }
+
+ /* Unpack the message. */
+ pull_file_id_16(frm, &id);
+ sharepath = &frm[16];
+ newname = sharepath + strlen(sharepath) + 1;
+ sp_len = strlen(sharepath);
+
+ DEBUG(10,("msg_file_was_renamed: Got rename message for sharepath %s, new name %s, "
+ "file_id %s\n",
+ sharepath, newname, file_id_string_tos(&id)));
+
+ for(fsp = file_find_di_first(id); fsp; fsp = file_find_di_next(fsp)) {
+ if (memcmp(fsp->conn->connectpath, sharepath, sp_len) == 0) {
+ DEBUG(10,("msg_file_was_renamed: renaming file fnum %d from %s -> %s\n",
+ fsp->fnum, fsp->fsp_name, newname ));
+ string_set(&fsp->fsp_name, newname);
+ } else {
+ /* TODO. JRA. */
+ /* Now we have the complete path we can work out if this is
+ actually within this share and adjust newname accordingly. */
+ DEBUG(10,("msg_file_was_renamed: share mismatch (sharepath %s "
+ "not sharepath %s) "
+ "fnum %d from %s -> %s\n",
+ fsp->conn->connectpath,
+ sharepath,
+ fsp->fnum,
+ fsp->fsp_name,
+ newname ));
+ }
+ }
+}
+
+struct case_semantics_state {
+ connection_struct *conn;
+ bool case_sensitive;
+ bool case_preserve;
+ bool short_case_preserve;
+};
+
+/****************************************************************************
+ Restore case semantics.
+****************************************************************************/
+static int restore_case_semantics(struct case_semantics_state *state)
+{
+ state->conn->case_sensitive = state->case_sensitive;
+ state->conn->case_preserve = state->case_preserve;
+ state->conn->short_case_preserve = state->short_case_preserve;
+ return 0;
+}
+
+/****************************************************************************
+ Save case semantics.
+****************************************************************************/
+static struct case_semantics_state *set_posix_case_semantics(TALLOC_CTX *mem_ctx,
+ connection_struct *conn)
+{
+ struct case_semantics_state *result;
+
+ if (!(result = talloc(mem_ctx, struct case_semantics_state))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ result->conn = conn;
+ result->case_sensitive = conn->case_sensitive;
+ result->case_preserve = conn->case_preserve;
+ result->short_case_preserve = conn->short_case_preserve;
+
+ /* Set to POSIX. */
+ conn->case_sensitive = True;
+ conn->case_preserve = True;
+ conn->short_case_preserve = True;
+
+ talloc_set_destructor(result, restore_case_semantics);
+
+ return result;
+}
+
+/*
+ * If a main file is opened for delete, all streams need to be checked for
+ * !FILE_SHARE_DELETE. Do this by opening with DELETE_ACCESS.
+ * If that works, delete them all by setting the delete on close and close.
+ */
+
+static NTSTATUS open_streams_for_delete(connection_struct *conn,
+ const char *fname)
+{
+ struct stream_struct *stream_info;
+ files_struct **streams;
+ int i;
+ unsigned int num_streams;
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+
+ status = SMB_VFS_STREAMINFO(conn, NULL, fname, talloc_tos(),
+ &num_streams, &stream_info);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)
+ || NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ DEBUG(10, ("no streams around\n"));
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("SMB_VFS_STREAMINFO failed: %s\n",
+ nt_errstr(status)));
+ goto fail;
+ }
+
+ DEBUG(10, ("open_streams_for_delete found %d streams\n",
+ num_streams));
+
+ if (num_streams == 0) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
+
+ streams = TALLOC_ARRAY(talloc_tos(), files_struct *, num_streams);
+ if (streams == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ for (i=0; i<num_streams; i++) {
+ char *streamname;
+
+ if (strequal(stream_info[i].name, "::$DATA")) {
+ streams[i] = NULL;
+ continue;
+ }
+
+ streamname = talloc_asprintf(talloc_tos(), "%s%s", fname,
+ stream_info[i].name);
+
+ if (streamname == NULL) {
+ DEBUG(0, ("talloc_aprintf failed\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ status = create_file_unixpath
+ (conn, /* conn */
+ NULL, /* req */
+ streamname, /* fname */
+ DELETE_ACCESS, /* access_mask */
+ FILE_SHARE_READ | FILE_SHARE_WRITE
+ | FILE_SHARE_DELETE, /* share_access */
+ FILE_OPEN, /* create_disposition*/
+ NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE, /* create_options */
+ FILE_ATTRIBUTE_NORMAL, /* file_attributes */
+ 0, /* oplock_request */
+ 0, /* allocation_size */
+ NULL, /* sd */
+ NULL, /* ea_list */
+ &streams[i], /* result */
+ NULL, /* pinfo */
+ NULL); /* psbuf */
+
+ TALLOC_FREE(streamname);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Could not open stream %s: %s\n",
+ streamname, nt_errstr(status)));
+ break;
+ }
+ }
+
+ /*
+ * don't touch the variable "status" beyond this point :-)
+ */
+
+ for (i -= 1 ; i >= 0; i--) {
+ if (streams[i] == NULL) {
+ continue;
+ }
+
+ DEBUG(10, ("Closing stream # %d, %s\n", i,
+ streams[i]->fsp_name));
+ close_file(streams[i], NORMAL_CLOSE);
+ }
+
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/*
+ * Wrapper around open_file_ntcreate and open_directory
+ */
+
+NTSTATUS create_file_unixpath(connection_struct *conn,
+ struct smb_request *req,
+ const char *fname,
+ uint32_t access_mask,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ uint32_t file_attributes,
+ uint32_t oplock_request,
+ SMB_BIG_UINT allocation_size,
+ struct security_descriptor *sd,
+ struct ea_list *ea_list,
+
+ files_struct **result,
+ int *pinfo,
+ SMB_STRUCT_STAT *psbuf)
+{
+ SMB_STRUCT_STAT sbuf;
+ int info = FILE_WAS_OPENED;
+ files_struct *base_fsp = NULL;
+ files_struct *fsp = NULL;
+ NTSTATUS status;
+
+ DEBUG(10,("create_file_unixpath: access_mask = 0x%x "
+ "file_attributes = 0x%x, share_access = 0x%x, "
+ "create_disposition = 0x%x create_options = 0x%x "
+ "oplock_request = 0x%x ea_list = 0x%p, sd = 0x%p, "
+ "fname = %s\n",
+ (unsigned int)access_mask,
+ (unsigned int)file_attributes,
+ (unsigned int)share_access,
+ (unsigned int)create_disposition,
+ (unsigned int)create_options,
+ (unsigned int)oplock_request,
+ ea_list, sd, fname));
+
+ if (create_options & FILE_OPEN_BY_FILE_ID) {
+ status = NT_STATUS_NOT_SUPPORTED;
+ goto fail;
+ }
+
+ if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ if (req == NULL) {
+ oplock_request |= INTERNAL_OPEN_ONLY;
+ }
+
+ if (psbuf != NULL) {
+ sbuf = *psbuf;
+ }
+ else {
+ if (SMB_VFS_STAT(conn, fname, &sbuf) == -1) {
+ SET_STAT_INVALID(sbuf);
+ }
+ }
+
+ if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
+ && (access_mask & DELETE_ACCESS)
+ && !is_ntfs_stream_name(fname)) {
+ /*
+ * We can't open a file with DELETE access if any of the
+ * streams is open without FILE_SHARE_DELETE
+ */
+ status = open_streams_for_delete(conn, fname);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ }
+
+ /* This is the correct thing to do (check every time) but can_delete
+ * is expensive (it may have to read the parent directory
+ * permissions). So for now we're not doing it unless we have a strong
+ * hint the client is really going to delete this file. If the client
+ * is forcing FILE_CREATE let the filesystem take care of the
+ * permissions. */
+
+ /* Setting FILE_SHARE_DELETE is the hint. */
+
+ if (lp_acl_check_permissions(SNUM(conn))
+ && (create_disposition != FILE_CREATE)
+ && (share_access & FILE_SHARE_DELETE)
+ && (access_mask & DELETE_ACCESS)
+ && (((dos_mode(conn, fname, &sbuf) & FILE_ATTRIBUTE_READONLY)
+ && !lp_delete_readonly(SNUM(conn)))
+ || !can_delete_file_in_directory(conn, fname))) {
+ status = NT_STATUS_ACCESS_DENIED;
+ goto fail;
+ }
+
+#if 0
+ /* We need to support SeSecurityPrivilege for this. */
+ if ((access_mask & SEC_RIGHT_SYSTEM_SECURITY) &&
+ !user_has_privileges(current_user.nt_user_token,
+ &se_security)) {
+ status = NT_STATUS_PRIVILEGE_NOT_HELD;
+ goto fail;
+ }
+#endif
+
+ if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
+ && is_ntfs_stream_name(fname)
+ && (!(create_options & NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE))) {
+ char *base;
+ uint32 base_create_disposition;
+
+ if (create_options & FILE_DIRECTORY_FILE) {
+ status = NT_STATUS_NOT_A_DIRECTORY;
+ goto fail;
+ }
+
+ status = split_ntfs_stream_name(talloc_tos(), fname,
+ &base, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("create_file_unixpath: "
+ "split_ntfs_stream_name failed: %s\n",
+ nt_errstr(status)));
+ goto fail;
+ }
+
+ SMB_ASSERT(!is_ntfs_stream_name(base)); /* paranoia.. */
+
+ switch (create_disposition) {
+ case FILE_OPEN:
+ base_create_disposition = FILE_OPEN;
+ break;
+ default:
+ base_create_disposition = FILE_OPEN_IF;
+ break;
+ }
+
+ status = create_file_unixpath(conn, NULL, base, 0,
+ FILE_SHARE_READ
+ | FILE_SHARE_WRITE
+ | FILE_SHARE_DELETE,
+ base_create_disposition,
+ 0, 0, 0, 0, NULL, NULL,
+ &base_fsp, NULL, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("create_file_unixpath for base %s failed: "
+ "%s\n", base, nt_errstr(status)));
+ goto fail;
+ }
+ }
+
+ /*
+ * If it's a request for a directory open, deal with it separately.
+ */
+
+ if (create_options & FILE_DIRECTORY_FILE) {
+
+ if (create_options & FILE_NON_DIRECTORY_FILE) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ /* Can't open a temp directory. IFS kit test. */
+ if (file_attributes & FILE_ATTRIBUTE_TEMPORARY) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ /*
+ * We will get a create directory here if the Win32
+ * app specified a security descriptor in the
+ * CreateDirectory() call.
+ */
+
+ oplock_request = 0;
+ status = open_directory(
+ conn, req, fname, &sbuf, access_mask, share_access,
+ create_disposition, create_options, file_attributes,
+ &info, &fsp);
+ } else {
+
+ /*
+ * Ordinary file case.
+ */
+
+ status = open_file_ntcreate(
+ conn, req, fname, &sbuf, access_mask, share_access,
+ create_disposition, create_options, file_attributes,
+ oplock_request, &info, &fsp);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
+
+ /*
+ * Fail the open if it was explicitly a non-directory
+ * file.
+ */
+
+ if (create_options & FILE_NON_DIRECTORY_FILE) {
+ status = NT_STATUS_FILE_IS_A_DIRECTORY;
+ goto fail;
+ }
+
+ oplock_request = 0;
+ status = open_directory(
+ conn, req, fname, &sbuf, access_mask,
+ share_access, create_disposition,
+ create_options, file_attributes,
+ &info, &fsp);
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ /*
+ * According to the MS documentation, the only time the security
+ * descriptor is applied to the opened file is iff we *created* the
+ * file; an existing file stays the same.
+ *
+ * Also, it seems (from observation) that you can open the file with
+ * any access mask but you can still write the sd. We need to override
+ * the granted access before we call set_sd
+ * Patch for bug #2242 from Tom Lackemann <cessnatomny@yahoo.com>.
+ */
+
+ if ((sd != NULL) && (info == FILE_WAS_CREATED)
+ && lp_nt_acl_support(SNUM(conn))) {
+
+ uint32_t sec_info_sent = ALL_SECURITY_INFORMATION;
+ uint32_t saved_access_mask = fsp->access_mask;
+
+ if (sd->owner_sid == NULL) {
+ sec_info_sent &= ~OWNER_SECURITY_INFORMATION;
+ }
+ if (sd->group_sid == NULL) {
+ sec_info_sent &= ~GROUP_SECURITY_INFORMATION;
+ }
+ if (sd->sacl == NULL) {
+ sec_info_sent &= ~SACL_SECURITY_INFORMATION;
+ }
+ if (sd->dacl == NULL) {
+ sec_info_sent &= ~DACL_SECURITY_INFORMATION;
+ }
+
+ fsp->access_mask = FILE_GENERIC_ALL;
+
+ status = SMB_VFS_FSET_NT_ACL(fsp, sec_info_sent, sd);
+
+ fsp->access_mask = saved_access_mask;
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ }
+
+ if ((ea_list != NULL) && (info == FILE_WAS_CREATED)) {
+ status = set_ea(conn, fsp, fname, ea_list);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ }
+
+ if (!fsp->is_directory && S_ISDIR(sbuf.st_mode)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ goto fail;
+ }
+
+ /* Save the requested allocation size. */
+ if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) {
+ if (allocation_size
+ && (allocation_size > sbuf.st_size)) {
+ fsp->initial_allocation_size = smb_roundup(
+ fsp->conn, allocation_size);
+ if (fsp->is_directory) {
+ /* Can't set allocation size on a directory. */
+ status = NT_STATUS_ACCESS_DENIED;
+ goto fail;
+ }
+ if (vfs_allocate_file_space(
+ fsp, fsp->initial_allocation_size) == -1) {
+ status = NT_STATUS_DISK_FULL;
+ goto fail;
+ }
+ } else {
+ fsp->initial_allocation_size = smb_roundup(
+ fsp->conn, (SMB_BIG_UINT)sbuf.st_size);
+ }
+ }
+
+ DEBUG(10, ("create_file_unixpath: info=%d\n", info));
+
+ /*
+ * Set fsp->base_fsp late enough that we can't "goto fail" anymore. In
+ * the fail: branch we call close_file(fsp, ERROR_CLOSE) which would
+ * also close fsp->base_fsp which we have to also do explicitly in
+ * this routine here, as not in all "goto fail:" we have the fsp set
+ * up already to be initialized with the base_fsp.
+ */
+
+ fsp->base_fsp = base_fsp;
+
+ *result = fsp;
+ if (pinfo != NULL) {
+ *pinfo = info;
+ }
+ if (psbuf != NULL) {
+ if ((fsp->fh == NULL) || (fsp->fh->fd == -1)) {
+ *psbuf = sbuf;
+ }
+ else {
+ SMB_VFS_FSTAT(fsp, psbuf);
+ }
+ }
+ return NT_STATUS_OK;
+
+ fail:
+ DEBUG(10, ("create_file_unixpath: %s\n", nt_errstr(status)));
+
+ if (fsp != NULL) {
+ close_file(fsp, ERROR_CLOSE);
+ fsp = NULL;
+ }
+ if (base_fsp != NULL) {
+ close_file(base_fsp, ERROR_CLOSE);
+ base_fsp = NULL;
+ }
+ return status;
+}
+
+NTSTATUS create_file(connection_struct *conn,
+ struct smb_request *req,
+ uint16_t root_dir_fid,
+ const char *fname,
+ uint32_t access_mask,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ uint32_t file_attributes,
+ uint32_t oplock_request,
+ SMB_BIG_UINT allocation_size,
+ struct security_descriptor *sd,
+ struct ea_list *ea_list,
+
+ files_struct **result,
+ int *pinfo,
+ SMB_STRUCT_STAT *psbuf)
+{
+ struct case_semantics_state *case_state = NULL;
+ SMB_STRUCT_STAT sbuf;
+ int info = FILE_WAS_OPENED;
+ files_struct *fsp = NULL;
+ NTSTATUS status;
+
+ DEBUG(10,("create_file: access_mask = 0x%x "
+ "file_attributes = 0x%x, share_access = 0x%x, "
+ "create_disposition = 0x%x create_options = 0x%x "
+ "oplock_request = 0x%x "
+ "root_dir_fid = 0x%x, ea_list = 0x%p, sd = 0x%p, "
+ "fname = %s\n",
+ (unsigned int)access_mask,
+ (unsigned int)file_attributes,
+ (unsigned int)share_access,
+ (unsigned int)create_disposition,
+ (unsigned int)create_options,
+ (unsigned int)oplock_request,
+ (unsigned int)root_dir_fid,
+ ea_list, sd, fname));
+
+ /*
+ * Get the file name.
+ */
+
+ if (root_dir_fid != 0) {
+ /*
+ * This filename is relative to a directory fid.
+ */
+ char *parent_fname = NULL;
+ files_struct *dir_fsp = file_fsp(root_dir_fid);
+
+ if (dir_fsp == NULL) {
+ status = NT_STATUS_INVALID_HANDLE;
+ goto fail;
+ }
+
+ if (!dir_fsp->is_directory) {
+
+ /*
+ * Check to see if this is a mac fork of some kind.
+ */
+
+ if (is_ntfs_stream_name(fname)) {
+ status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ goto fail;
+ }
+
+ /*
+ we need to handle the case when we get a
+ relative open relative to a file and the
+ pathname is blank - this is a reopen!
+ (hint from demyn plantenberg)
+ */
+
+ status = NT_STATUS_INVALID_HANDLE;
+ goto fail;
+ }
+
+ if (ISDOT(dir_fsp->fsp_name)) {
+ /*
+ * We're at the toplevel dir, the final file name
+ * must not contain ./, as this is filtered out
+ * normally by srvstr_get_path and unix_convert
+ * explicitly rejects paths containing ./.
+ */
+ parent_fname = talloc_strdup(talloc_tos(), "");
+ if (parent_fname == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ } else {
+ size_t dir_name_len = strlen(dir_fsp->fsp_name);
+
+ /*
+ * Copy in the base directory name.
+ */
+
+ parent_fname = TALLOC_ARRAY(talloc_tos(), char,
+ dir_name_len+2);
+ if (parent_fname == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ memcpy(parent_fname, dir_fsp->fsp_name,
+ dir_name_len+1);
+
+ /*
+ * Ensure it ends in a '/'.
+ * We used TALLOC_SIZE +2 to add space for the '/'.
+ */
+
+ if(dir_name_len
+ && (parent_fname[dir_name_len-1] != '\\')
+ && (parent_fname[dir_name_len-1] != '/')) {
+ parent_fname[dir_name_len] = '/';
+ parent_fname[dir_name_len+1] = '\0';
+ }
+ }
+
+ fname = talloc_asprintf(talloc_tos(), "%s%s", parent_fname,
+ fname);
+ if (fname == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ }
+
+ /*
+ * Check to see if this is a mac fork of some kind.
+ */
+
+ if (is_ntfs_stream_name(fname)) {
+ enum FAKE_FILE_TYPE fake_file_type;
+
+ fake_file_type = is_fake_file(fname);
+
+ if (fake_file_type != FAKE_FILE_TYPE_NONE) {
+
+ /*
+ * Here we go! support for changing the disk quotas
+ * --metze
+ *
+ * We need to fake up to open this MAGIC QUOTA file
+ * and return a valid FID.
+ *
+ * w2k close this file directly after openening xp
+ * also tries a QUERY_FILE_INFO on the file and then
+ * close it
+ */
+ status = open_fake_file(conn, req->vuid,
+ fake_file_type, fname,
+ access_mask, &fsp);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ ZERO_STRUCT(sbuf);
+ goto done;
+ }
+
+ if (!(conn->fs_capabilities & FILE_NAMED_STREAMS)) {
+ status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ goto fail;
+ }
+ }
+
+ if ((req != NULL) && (req->flags2 & FLAGS2_DFS_PATHNAMES)) {
+ char *resolved_fname;
+
+ status = resolve_dfspath(talloc_tos(), conn, true, fname,
+ &resolved_fname);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * For PATH_NOT_COVERED we had
+ * reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ * ERRSRV, ERRbadpath);
+ * Need to fix in callers
+ */
+ goto fail;
+ }
+ fname = resolved_fname;
+ }
+
+ /*
+ * Check if POSIX semantics are wanted.
+ */
+
+ if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) {
+ case_state = set_posix_case_semantics(talloc_tos(), conn);
+ file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
+ }
+
+ {
+ char *converted_fname;
+
+ SET_STAT_INVALID(sbuf);
+
+ status = unix_convert(talloc_tos(), conn, fname, False,
+ &converted_fname, NULL, &sbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ fname = converted_fname;
+ }
+
+ TALLOC_FREE(case_state);
+
+ /* All file access must go through check_name() */
+
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ status = create_file_unixpath(
+ conn, req, fname, access_mask, share_access,
+ create_disposition, create_options, file_attributes,
+ oplock_request, allocation_size, sd, ea_list,
+ &fsp, &info, &sbuf);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ done:
+ DEBUG(10, ("create_file: info=%d\n", info));
+
+ *result = fsp;
+ if (pinfo != NULL) {
+ *pinfo = info;
+ }
+ if (psbuf != NULL) {
+ *psbuf = sbuf;
+ }
+ return NT_STATUS_OK;
+
+ fail:
+ DEBUG(10, ("create_file: %s\n", nt_errstr(status)));
+
+ if (fsp != NULL) {
+ close_file(fsp, ERROR_CLOSE);
+ fsp = NULL;
+ }
+ return status;
+}
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
new file mode 100644
index 0000000000..23411294df
--- /dev/null
+++ b/source3/smbd/oplock.c
@@ -0,0 +1,897 @@
+/*
+ Unix SMB/CIFS implementation.
+ oplock processing
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1998 - 2001
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define DBGC_CLASS DBGC_LOCKING
+#include "includes.h"
+
+/* Current number of oplocks we have outstanding. */
+static int32 exclusive_oplocks_open = 0;
+static int32 level_II_oplocks_open = 0;
+bool global_client_failed_oplock_break = False;
+
+extern uint32 global_client_caps;
+
+static struct kernel_oplocks *koplocks;
+
+/****************************************************************************
+ Get the number of current exclusive oplocks.
+****************************************************************************/
+
+int32 get_number_of_exclusive_open_oplocks(void)
+{
+ return exclusive_oplocks_open;
+}
+
+/****************************************************************************
+ Return True if an oplock message is pending.
+****************************************************************************/
+
+bool oplock_message_waiting(fd_set *fds)
+{
+ if (koplocks && koplocks->msg_waiting(fds)) {
+ return True;
+ }
+
+ return False;
+}
+
+/****************************************************************************
+ Find out if there are any kernel oplock messages waiting and process them
+ if so. pfds is the fd_set from the main select loop (which contains any
+ kernel oplock fd if that's what the system uses (IRIX). If may be NULL if
+ we're calling this in a shutting down state.
+****************************************************************************/
+
+void process_kernel_oplocks(struct messaging_context *msg_ctx, fd_set *pfds)
+{
+ /*
+ * We need to check for kernel oplocks before going into the select
+ * here, as the EINTR generated by the linux kernel oplock may have
+ * already been eaten. JRA.
+ */
+
+ if (!koplocks) {
+ return;
+ }
+
+ while (koplocks->msg_waiting(pfds)) {
+ files_struct *fsp;
+ char msg[MSG_SMB_KERNEL_BREAK_SIZE];
+
+ fsp = koplocks->receive_message(pfds);
+
+ if (fsp == NULL) {
+ DEBUG(3, ("Kernel oplock message announced, but none "
+ "received\n"));
+ return;
+ }
+
+ /* Put the kernel break info into the message. */
+ push_file_id_16(msg, &fsp->file_id);
+ SIVAL(msg,16,fsp->fh->gen_id);
+
+ /* Don't need to be root here as we're only ever
+ sending to ourselves. */
+
+ messaging_send_buf(msg_ctx, procid_self(),
+ MSG_SMB_KERNEL_BREAK,
+ (uint8 *)&msg, MSG_SMB_KERNEL_BREAK_SIZE);
+ }
+}
+
+/****************************************************************************
+ Attempt to set an oplock on a file. Always succeeds if kernel oplocks are
+ disabled (just sets flags). Returns True if oplock set.
+****************************************************************************/
+
+bool set_file_oplock(files_struct *fsp, int oplock_type)
+{
+ if (koplocks && !koplocks->set_oplock(fsp, oplock_type)) {
+ return False;
+ }
+
+ fsp->oplock_type = oplock_type;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+ if (oplock_type == LEVEL_II_OPLOCK) {
+ level_II_oplocks_open++;
+ } else {
+ exclusive_oplocks_open++;
+ }
+
+ DEBUG(5,("set_file_oplock: granted oplock on file %s, %s/%lu, "
+ "tv_sec = %x, tv_usec = %x\n",
+ fsp->fsp_name, file_id_string_tos(&fsp->file_id),
+ fsp->fh->gen_id, (int)fsp->open_time.tv_sec,
+ (int)fsp->open_time.tv_usec ));
+
+ return True;
+}
+
+/****************************************************************************
+ Attempt to release an oplock on a file. Decrements oplock count.
+****************************************************************************/
+
+void release_file_oplock(files_struct *fsp)
+{
+ if ((fsp->oplock_type != NO_OPLOCK) &&
+ (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK) &&
+ koplocks) {
+ koplocks->release_oplock(fsp);
+ }
+
+ if (fsp->oplock_type == LEVEL_II_OPLOCK) {
+ level_II_oplocks_open--;
+ } else if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ exclusive_oplocks_open--;
+ }
+
+ SMB_ASSERT(exclusive_oplocks_open>=0);
+ SMB_ASSERT(level_II_oplocks_open>=0);
+
+ fsp->oplock_type = NO_OPLOCK;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+
+ flush_write_cache(fsp, OPLOCK_RELEASE_FLUSH);
+
+ TALLOC_FREE(fsp->oplock_timeout);
+}
+
+/****************************************************************************
+ Attempt to downgrade an oplock on a file. Doesn't decrement oplock count.
+****************************************************************************/
+
+static void downgrade_file_oplock(files_struct *fsp)
+{
+ if (koplocks) {
+ koplocks->release_oplock(fsp);
+ }
+ fsp->oplock_type = LEVEL_II_OPLOCK;
+ exclusive_oplocks_open--;
+ level_II_oplocks_open++;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+}
+
+/****************************************************************************
+ Remove a file oplock. Copes with level II and exclusive.
+ Locks then unlocks the share mode lock. Client can decide to go directly
+ to none even if a "break-to-level II" was sent.
+****************************************************************************/
+
+bool remove_oplock(files_struct *fsp)
+{
+ bool ret;
+ struct share_mode_lock *lck;
+
+ /* Remove the oplock flag from the sharemode. */
+ lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
+ NULL);
+ if (lck == NULL) {
+ DEBUG(0,("remove_oplock: failed to lock share entry for "
+ "file %s\n", fsp->fsp_name ));
+ return False;
+ }
+ ret = remove_share_oplock(lck, fsp);
+ if (!ret) {
+ DEBUG(0,("remove_oplock: failed to remove share oplock for "
+ "file %s fnum %d, %s\n",
+ fsp->fsp_name, fsp->fnum, file_id_string_tos(&fsp->file_id)));
+ }
+ release_file_oplock(fsp);
+ TALLOC_FREE(lck);
+ return ret;
+}
+
+/*
+ * Deal with a reply when a break-to-level II was sent.
+ */
+bool downgrade_oplock(files_struct *fsp)
+{
+ bool ret;
+ struct share_mode_lock *lck;
+
+ lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
+ NULL);
+ if (lck == NULL) {
+ DEBUG(0,("downgrade_oplock: failed to lock share entry for "
+ "file %s\n", fsp->fsp_name ));
+ return False;
+ }
+ ret = downgrade_share_oplock(lck, fsp);
+ if (!ret) {
+ DEBUG(0,("downgrade_oplock: failed to downgrade share oplock "
+ "for file %s fnum %d, file_id %s\n",
+ fsp->fsp_name, fsp->fnum, file_id_string_tos(&fsp->file_id)));
+ }
+
+ downgrade_file_oplock(fsp);
+ TALLOC_FREE(lck);
+ return ret;
+}
+
+/****************************************************************************
+ Return the fd (if any) used for receiving oplock notifications.
+****************************************************************************/
+
+int oplock_notify_fd(void)
+{
+ if (koplocks) {
+ return koplocks->notification_fd;
+ }
+
+ return -1;
+}
+
+/****************************************************************************
+ Set up an oplock break message.
+****************************************************************************/
+
+static char *new_break_smb_message(TALLOC_CTX *mem_ctx,
+ files_struct *fsp, uint8 cmd)
+{
+ char *result = TALLOC_ARRAY(mem_ctx, char, smb_size + 8*2 + 0);
+
+ if (result == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ memset(result,'\0',smb_size);
+ srv_set_message(result,8,0,true);
+ SCVAL(result,smb_com,SMBlockingX);
+ SSVAL(result,smb_tid,fsp->conn->cnum);
+ SSVAL(result,smb_pid,0xFFFF);
+ SSVAL(result,smb_uid,0);
+ SSVAL(result,smb_mid,0xFFFF);
+ SCVAL(result,smb_vwv0,0xFF);
+ SSVAL(result,smb_vwv2,fsp->fnum);
+ SCVAL(result,smb_vwv3,LOCKING_ANDX_OPLOCK_RELEASE);
+ SCVAL(result,smb_vwv3+1,cmd);
+ return result;
+}
+
+/****************************************************************************
+ Function to do the waiting before sending a local break.
+****************************************************************************/
+
+static void wait_before_sending_break(void)
+{
+ long wait_time = (long)lp_oplock_break_wait_time();
+
+ if (wait_time) {
+ smb_msleep(wait_time);
+ }
+}
+
+/****************************************************************************
+ Ensure that we have a valid oplock.
+****************************************************************************/
+
+static files_struct *initial_break_processing(struct file_id id, unsigned long file_id)
+{
+ files_struct *fsp = NULL;
+
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "initial_break_processing: called for %s/%u\n",
+ file_id_string_tos(&id), (int)file_id);
+ dbgtext( "Current oplocks_open (exclusive = %d, levelII = %d)\n",
+ exclusive_oplocks_open, level_II_oplocks_open );
+ }
+
+ /*
+ * We need to search the file open table for the
+ * entry containing this dev and inode, and ensure
+ * we have an oplock on it.
+ */
+
+ fsp = file_find_dif(id, file_id);
+
+ if(fsp == NULL) {
+ /* The file could have been closed in the meantime - return success. */
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "initial_break_processing: cannot find open file with " );
+ dbgtext( "file_id %s gen_id = %lu", file_id_string_tos(&id), file_id);
+ dbgtext( "allowing break to succeed.\n" );
+ }
+ return NULL;
+ }
+
+ /* Ensure we have an oplock on the file */
+
+ /*
+ * There is a potential race condition in that an oplock could
+ * have been broken due to another udp request, and yet there are
+ * still oplock break messages being sent in the udp message
+ * queue for this file. So return true if we don't have an oplock,
+ * as we may have just freed it.
+ */
+
+ if(fsp->oplock_type == NO_OPLOCK) {
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "initial_break_processing: file %s ", fsp->fsp_name );
+ dbgtext( "(file_id = %s gen_id = %lu) has no oplock.\n",
+ file_id_string_tos(&id), fsp->fh->gen_id );
+ dbgtext( "Allowing break to succeed regardless.\n" );
+ }
+ return NULL;
+ }
+
+ return fsp;
+}
+
+static void oplock_timeout_handler(struct event_context *ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ files_struct *fsp = (files_struct *)private_data;
+
+ /* Remove the timed event handler. */
+ TALLOC_FREE(fsp->oplock_timeout);
+ DEBUG(0, ("Oplock break failed for file %s -- replying anyway\n", fsp->fsp_name));
+ global_client_failed_oplock_break = True;
+ remove_oplock(fsp);
+ reply_to_oplock_break_requests(fsp);
+}
+
+/*******************************************************************
+ Add a timeout handler waiting for the client reply.
+*******************************************************************/
+
+static void add_oplock_timeout_handler(files_struct *fsp)
+{
+ if (fsp->oplock_timeout != NULL) {
+ DEBUG(0, ("Logic problem -- have an oplock event hanging "
+ "around\n"));
+ }
+
+ fsp->oplock_timeout =
+ event_add_timed(smbd_event_context(), NULL,
+ timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0),
+ "oplock_timeout_handler",
+ oplock_timeout_handler, fsp);
+
+ if (fsp->oplock_timeout == NULL) {
+ DEBUG(0, ("Could not add oplock timeout handler\n"));
+ }
+}
+
+/*******************************************************************
+ This handles the case of a write triggering a break to none
+ message on a level2 oplock.
+ When we get this message we may be in any of three states :
+ NO_OPLOCK, LEVEL_II, FAKE_LEVEL2. We only send a message to
+ the client for LEVEL2.
+*******************************************************************/
+
+static void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ DATA_BLOB *data)
+{
+ struct share_mode_entry msg;
+ files_struct *fsp;
+ char *break_msg;
+ bool sign_state;
+
+ if (data->data == NULL) {
+ DEBUG(0, ("Got NULL buffer\n"));
+ return;
+ }
+
+ if (data->length != MSG_SMB_SHARE_MODE_ENTRY_SIZE) {
+ DEBUG(0, ("Got invalid msg len %d\n", (int)data->length));
+ return;
+ }
+
+ /* De-linearize incoming message. */
+ message_to_share_mode_entry(&msg, (char *)data->data);
+
+ DEBUG(10, ("Got oplock async level 2 break message from pid %d: %s/%lu\n",
+ (int)procid_to_pid(&src), file_id_string_tos(&msg.id), msg.share_file_id));
+
+ fsp = initial_break_processing(msg.id, msg.share_file_id);
+
+ if (fsp == NULL) {
+ /* We hit a race here. Break messages are sent, and before we
+ * get to process this message, we have closed the file.
+ * No need to reply as this is an async message. */
+ DEBUG(3, ("process_oplock_async_level2_break_message: Did not find fsp, ignoring\n"));
+ return;
+ }
+
+ if (fsp->oplock_type == NO_OPLOCK) {
+ /* We already got a "break to none" message and we've handled it.
+ * just ignore. */
+ DEBUG(3, ("process_oplock_async_level2_break_message: already broken to none, ignoring.\n"));
+ return;
+ }
+
+ if (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK) {
+ /* Don't tell the client, just downgrade. */
+ DEBUG(3, ("process_oplock_async_level2_break_message: downgrading fake level 2 oplock.\n"));
+ remove_oplock(fsp);
+ return;
+ }
+
+ /* Ensure we're really at level2 state. */
+ SMB_ASSERT(fsp->oplock_type == LEVEL_II_OPLOCK);
+
+ /* Now send a break to none message to our client. */
+
+ break_msg = new_break_smb_message(NULL, fsp, OPLOCKLEVEL_NONE);
+ if (break_msg == NULL) {
+ exit_server("Could not talloc break_msg\n");
+ }
+
+ /* Need to wait before sending a break message if we sent ourselves this message. */
+ if (procid_to_pid(&src) == sys_getpid()) {
+ wait_before_sending_break();
+ }
+
+ /* Save the server smb signing state. */
+ sign_state = srv_oplock_set_signing(False);
+
+ show_msg(break_msg);
+ if (!srv_send_smb(smbd_server_fd(),
+ break_msg,
+ IS_CONN_ENCRYPTED(fsp->conn))) {
+ exit_server_cleanly("oplock_break: srv_send_smb failed.");
+ }
+
+ /* Restore the sign state to what it was. */
+ srv_oplock_set_signing(sign_state);
+
+ TALLOC_FREE(break_msg);
+
+ /* Async level2 request, don't send a reply, just remove the oplock. */
+ remove_oplock(fsp);
+}
+
+/*******************************************************************
+ This handles the generic oplock break message from another smbd.
+*******************************************************************/
+
+static void process_oplock_break_message(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ DATA_BLOB *data)
+{
+ struct share_mode_entry msg;
+ files_struct *fsp;
+ char *break_msg;
+ bool break_to_level2 = False;
+ bool sign_state;
+
+ if (data->data == NULL) {
+ DEBUG(0, ("Got NULL buffer\n"));
+ return;
+ }
+
+ if (data->length != MSG_SMB_SHARE_MODE_ENTRY_SIZE) {
+ DEBUG(0, ("Got invalid msg len %d\n", (int)data->length));
+ return;
+ }
+
+ /* De-linearize incoming message. */
+ message_to_share_mode_entry(&msg, (char *)data->data);
+
+ DEBUG(10, ("Got oplock break message from pid %d: %s/%lu\n",
+ (int)procid_to_pid(&src), file_id_string_tos(&msg.id), msg.share_file_id));
+
+ fsp = initial_break_processing(msg.id, msg.share_file_id);
+
+ if (fsp == NULL) {
+ /* a We hit race here. Break messages are sent, and before we
+ * get to process this message, we have closed the file. Reply
+ * with 'ok, oplock broken' */
+ DEBUG(3, ("Did not find fsp\n"));
+
+ /* We just send the same message back. */
+ messaging_send_buf(msg_ctx, src, MSG_SMB_BREAK_RESPONSE,
+ (uint8 *)data->data,
+ MSG_SMB_SHARE_MODE_ENTRY_SIZE);
+ return;
+ }
+
+ if (fsp->sent_oplock_break != NO_BREAK_SENT) {
+ /* Remember we have to inform the requesting PID when the
+ * client replies */
+ msg.pid = src;
+ ADD_TO_ARRAY(NULL, struct share_mode_entry, msg,
+ &fsp->pending_break_messages,
+ &fsp->num_pending_break_messages);
+ return;
+ }
+
+ if (EXCLUSIVE_OPLOCK_TYPE(msg.op_type) &&
+ !EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ DEBUG(3, ("Already downgraded oplock on %s: %s\n",
+ file_id_string_tos(&fsp->file_id),
+ fsp->fsp_name));
+ /* We just send the same message back. */
+ messaging_send_buf(msg_ctx, src, MSG_SMB_BREAK_RESPONSE,
+ (uint8 *)data->data,
+ MSG_SMB_SHARE_MODE_ENTRY_SIZE);
+ return;
+ }
+
+ if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) &&
+ !(msg.op_type & FORCE_OPLOCK_BREAK_TO_NONE) &&
+ !koplocks && /* NOTE: we force levelII off for kernel oplocks -
+ * this will change when it is supported */
+ lp_level2_oplocks(SNUM(fsp->conn))) {
+ break_to_level2 = True;
+ }
+
+ break_msg = new_break_smb_message(NULL, fsp, break_to_level2 ?
+ OPLOCKLEVEL_II : OPLOCKLEVEL_NONE);
+ if (break_msg == NULL) {
+ exit_server("Could not talloc break_msg\n");
+ }
+
+ /* Need to wait before sending a break message if we sent ourselves this message. */
+ if (procid_to_pid(&src) == sys_getpid()) {
+ wait_before_sending_break();
+ }
+
+ /* Save the server smb signing state. */
+ sign_state = srv_oplock_set_signing(False);
+
+ show_msg(break_msg);
+ if (!srv_send_smb(smbd_server_fd(),
+ break_msg,
+ IS_CONN_ENCRYPTED(fsp->conn))) {
+ exit_server_cleanly("oplock_break: srv_send_smb failed.");
+ }
+
+ /* Restore the sign state to what it was. */
+ srv_oplock_set_signing(sign_state);
+
+ TALLOC_FREE(break_msg);
+
+ fsp->sent_oplock_break = break_to_level2 ? LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT;
+
+ msg.pid = src;
+ ADD_TO_ARRAY(NULL, struct share_mode_entry, msg,
+ &fsp->pending_break_messages,
+ &fsp->num_pending_break_messages);
+
+ add_oplock_timeout_handler(fsp);
+}
+
+/*******************************************************************
+ This handles the kernel oplock break message.
+*******************************************************************/
+
+static void process_kernel_oplock_break(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ DATA_BLOB *data)
+{
+ struct file_id id;
+ unsigned long file_id;
+ files_struct *fsp;
+ char *break_msg;
+ bool sign_state;
+
+ if (data->data == NULL) {
+ DEBUG(0, ("Got NULL buffer\n"));
+ return;
+ }
+
+ if (data->length != MSG_SMB_KERNEL_BREAK_SIZE) {
+ DEBUG(0, ("Got invalid msg len %d\n", (int)data->length));
+ return;
+ }
+
+ /* Pull the data from the message. */
+ pull_file_id_16((char *)data->data, &id);
+ file_id = (unsigned long)IVAL(data->data, 16);
+
+ DEBUG(10, ("Got kernel oplock break message from pid %d: %s/%u\n",
+ (int)procid_to_pid(&src), file_id_string_tos(&id),
+ (unsigned int)file_id));
+
+ fsp = initial_break_processing(id, file_id);
+
+ if (fsp == NULL) {
+ DEBUG(3, ("Got a kernel oplock break message for a file "
+ "I don't know about\n"));
+ return;
+ }
+
+ if (fsp->sent_oplock_break != NO_BREAK_SENT) {
+ /* This is ok, kernel oplocks come in completely async */
+ DEBUG(3, ("Got a kernel oplock request while waiting for a "
+ "break reply\n"));
+ return;
+ }
+
+ break_msg = new_break_smb_message(NULL, fsp, OPLOCKLEVEL_NONE);
+ if (break_msg == NULL) {
+ exit_server("Could not talloc break_msg\n");
+ }
+
+ /* Save the server smb signing state. */
+ sign_state = srv_oplock_set_signing(False);
+
+ show_msg(break_msg);
+ if (!srv_send_smb(smbd_server_fd(),
+ break_msg,
+ IS_CONN_ENCRYPTED(fsp->conn))) {
+ exit_server_cleanly("oplock_break: srv_send_smb failed.");
+ }
+
+ /* Restore the sign state to what it was. */
+ srv_oplock_set_signing(sign_state);
+
+ TALLOC_FREE(break_msg);
+
+ fsp->sent_oplock_break = BREAK_TO_NONE_SENT;
+
+ add_oplock_timeout_handler(fsp);
+}
+
+void reply_to_oplock_break_requests(files_struct *fsp)
+{
+ int i;
+
+ for (i=0; i<fsp->num_pending_break_messages; i++) {
+ struct share_mode_entry *e = &fsp->pending_break_messages[i];
+ char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
+
+ share_mode_entry_to_message(msg, e);
+
+ messaging_send_buf(smbd_messaging_context(), e->pid,
+ MSG_SMB_BREAK_RESPONSE,
+ (uint8 *)msg,
+ MSG_SMB_SHARE_MODE_ENTRY_SIZE);
+ }
+
+ SAFE_FREE(fsp->pending_break_messages);
+ fsp->num_pending_break_messages = 0;
+ if (fsp->oplock_timeout != NULL) {
+ /* Remove the timed event handler. */
+ TALLOC_FREE(fsp->oplock_timeout);
+ fsp->oplock_timeout = NULL;
+ }
+ return;
+}
+
+static void process_oplock_break_response(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ DATA_BLOB *data)
+{
+ struct share_mode_entry msg;
+
+ if (data->data == NULL) {
+ DEBUG(0, ("Got NULL buffer\n"));
+ return;
+ }
+
+ if (data->length != MSG_SMB_SHARE_MODE_ENTRY_SIZE) {
+ DEBUG(0, ("Got invalid msg len %u\n",
+ (unsigned int)data->length));
+ return;
+ }
+
+ /* De-linearize incoming message. */
+ message_to_share_mode_entry(&msg, (char *)data->data);
+
+ DEBUG(10, ("Got oplock break response from pid %d: %s/%lu mid %u\n",
+ (int)procid_to_pid(&src), file_id_string_tos(&msg.id), msg.share_file_id,
+ (unsigned int)msg.op_mid));
+
+ /* Here's the hack from open.c, store the mid in the 'port' field */
+ schedule_deferred_open_smb_message(msg.op_mid);
+}
+
+static void process_open_retry_message(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ DATA_BLOB *data)
+{
+ struct share_mode_entry msg;
+
+ if (data->data == NULL) {
+ DEBUG(0, ("Got NULL buffer\n"));
+ return;
+ }
+
+ if (data->length != MSG_SMB_SHARE_MODE_ENTRY_SIZE) {
+ DEBUG(0, ("Got invalid msg len %d\n", (int)data->length));
+ return;
+ }
+
+ /* De-linearize incoming message. */
+ message_to_share_mode_entry(&msg, (char *)data->data);
+
+ DEBUG(10, ("Got open retry msg from pid %d: %s mid %u\n",
+ (int)procid_to_pid(&src), file_id_string_tos(&msg.id),
+ (unsigned int)msg.op_mid));
+
+ schedule_deferred_open_smb_message(msg.op_mid);
+}
+
+/****************************************************************************
+ This function is called on any file modification or lock request. If a file
+ is level 2 oplocked then it must tell all other level 2 holders to break to
+ none.
+****************************************************************************/
+
+void release_level_2_oplocks_on_change(files_struct *fsp)
+{
+ int i;
+ struct share_mode_lock *lck;
+
+ /*
+ * If this file is level II oplocked then we need
+ * to grab the shared memory lock and inform all
+ * other files with a level II lock that they need
+ * to flush their read caches. We keep the lock over
+ * the shared memory area whilst doing this.
+ */
+
+ if (!LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
+ return;
+
+ lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
+ NULL);
+ if (lck == NULL) {
+ DEBUG(0,("release_level_2_oplocks_on_change: failed to lock "
+ "share mode entry for file %s.\n", fsp->fsp_name ));
+ return;
+ }
+
+ DEBUG(10,("release_level_2_oplocks_on_change: num_share_modes = %d\n",
+ lck->num_share_modes ));
+
+ for(i = 0; i < lck->num_share_modes; i++) {
+ struct share_mode_entry *share_entry = &lck->share_modes[i];
+ char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
+
+ if (!is_valid_share_mode_entry(share_entry)) {
+ continue;
+ }
+
+ /*
+ * As there could have been multiple writes waiting at the
+ * lock_share_entry gate we may not be the first to
+ * enter. Hence the state of the op_types in the share mode
+ * entries may be partly NO_OPLOCK and partly LEVEL_II or FAKE_LEVEL_II
+ * oplock. It will do no harm to re-send break messages to
+ * those smbd's that are still waiting their turn to remove
+ * their LEVEL_II state, and also no harm to ignore existing
+ * NO_OPLOCK states. JRA.
+ */
+
+ DEBUG(10,("release_level_2_oplocks_on_change: "
+ "share_entry[%i]->op_type == %d\n",
+ i, share_entry->op_type ));
+
+ if (share_entry->op_type == NO_OPLOCK) {
+ continue;
+ }
+
+ /* Paranoia .... */
+ if (EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) {
+ DEBUG(0,("release_level_2_oplocks_on_change: PANIC. "
+ "share mode entry %d is an exlusive "
+ "oplock !\n", i ));
+ TALLOC_FREE(lck);
+ abort();
+ }
+
+ share_mode_entry_to_message(msg, share_entry);
+
+ messaging_send_buf(smbd_messaging_context(), share_entry->pid,
+ MSG_SMB_ASYNC_LEVEL2_BREAK,
+ (uint8 *)msg,
+ MSG_SMB_SHARE_MODE_ENTRY_SIZE);
+ }
+
+ /* We let the message receivers handle removing the oplock state
+ in the share mode lock db. */
+
+ TALLOC_FREE(lck);
+}
+
+/****************************************************************************
+ Linearize a share mode entry struct to an internal oplock break message.
+****************************************************************************/
+
+void share_mode_entry_to_message(char *msg, const struct share_mode_entry *e)
+{
+ SIVAL(msg,0,(uint32)e->pid.pid);
+ SSVAL(msg,4,e->op_mid);
+ SSVAL(msg,6,e->op_type);
+ SIVAL(msg,8,e->access_mask);
+ SIVAL(msg,12,e->share_access);
+ SIVAL(msg,16,e->private_options);
+ SIVAL(msg,20,(uint32)e->time.tv_sec);
+ SIVAL(msg,24,(uint32)e->time.tv_usec);
+ push_file_id_16(msg+28, &e->id);
+ SIVAL(msg,44,e->share_file_id);
+ SIVAL(msg,48,e->uid);
+ SSVAL(msg,52,e->flags);
+#ifdef CLUSTER_SUPPORT
+ SIVAL(msg,54,e->pid.vnn);
+#endif
+}
+
+/****************************************************************************
+ De-linearize an internal oplock break message to a share mode entry struct.
+****************************************************************************/
+
+void message_to_share_mode_entry(struct share_mode_entry *e, char *msg)
+{
+ e->pid.pid = (pid_t)IVAL(msg,0);
+ e->op_mid = SVAL(msg,4);
+ e->op_type = SVAL(msg,6);
+ e->access_mask = IVAL(msg,8);
+ e->share_access = IVAL(msg,12);
+ e->private_options = IVAL(msg,16);
+ e->time.tv_sec = (time_t)IVAL(msg,20);
+ e->time.tv_usec = (int)IVAL(msg,24);
+ pull_file_id_16(msg+28, &e->id);
+ e->share_file_id = (unsigned long)IVAL(msg,44);
+ e->uid = (uint32)IVAL(msg,48);
+ e->flags = (uint16)SVAL(msg,52);
+#ifdef CLUSTER_SUPPORT
+ e->pid.vnn = IVAL(msg,54);
+#endif
+}
+
+/****************************************************************************
+ Setup oplocks for this process.
+****************************************************************************/
+
+bool init_oplocks(struct messaging_context *msg_ctx)
+{
+ DEBUG(3,("init_oplocks: initializing messages.\n"));
+
+ messaging_register(msg_ctx, NULL, MSG_SMB_BREAK_REQUEST,
+ process_oplock_break_message);
+ messaging_register(msg_ctx, NULL, MSG_SMB_ASYNC_LEVEL2_BREAK,
+ process_oplock_async_level2_break_message);
+ messaging_register(msg_ctx, NULL, MSG_SMB_BREAK_RESPONSE,
+ process_oplock_break_response);
+ messaging_register(msg_ctx, NULL, MSG_SMB_KERNEL_BREAK,
+ process_kernel_oplock_break);
+ messaging_register(msg_ctx, NULL, MSG_SMB_OPEN_RETRY,
+ process_open_retry_message);
+
+ if (lp_kernel_oplocks()) {
+#if HAVE_KERNEL_OPLOCKS_IRIX
+ koplocks = irix_init_kernel_oplocks();
+#elif HAVE_KERNEL_OPLOCKS_LINUX
+ koplocks = linux_init_kernel_oplocks();
+#endif
+ }
+
+ return True;
+}
diff --git a/source3/smbd/oplock_irix.c b/source3/smbd/oplock_irix.c
new file mode 100644
index 0000000000..8c287c9836
--- /dev/null
+++ b/source3/smbd/oplock_irix.c
@@ -0,0 +1,301 @@
+/*
+ Unix SMB/CIFS implementation.
+ IRIX kernel oplock processing
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define DBGC_CLASS DBGC_LOCKING
+#include "includes.h"
+
+#if HAVE_KERNEL_OPLOCKS_IRIX
+
+static int oplock_pipe_write = -1;
+static int oplock_pipe_read = -1;
+
+/****************************************************************************
+ Test to see if IRIX kernel oplocks work.
+****************************************************************************/
+
+static bool irix_oplocks_available(void)
+{
+ int fd;
+ int pfd[2];
+ TALLOC_CTX *ctx = talloc_stackframe();
+ char *tmpname = NULL;
+
+ set_effective_capability(KERNEL_OPLOCK_CAPABILITY);
+
+ tmpname = talloc_asprintf(ctx,
+ "%s/koplock.%d",
+ lp_lockdir(),
+ (int)sys_getpid());
+ if (!tmpname) {
+ TALLOC_FREE(ctx);
+ return False;
+ }
+
+ if(pipe(pfd) != 0) {
+ DEBUG(0,("check_kernel_oplocks: Unable to create pipe. Error "
+ "was %s\n",
+ strerror(errno) ));
+ TALLOC_FREE(ctx);
+ return False;
+ }
+
+ if((fd = sys_open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600)) < 0) {
+ DEBUG(0,("check_kernel_oplocks: Unable to open temp test file "
+ "%s. Error was %s\n",
+ tmpname, strerror(errno) ));
+ unlink( tmpname );
+ close(pfd[0]);
+ close(pfd[1]);
+ TALLOC_FREE(ctx);
+ return False;
+ }
+
+ unlink(tmpname);
+
+ TALLOC_FREE(ctx);
+
+ if(sys_fcntl_long(fd, F_OPLKREG, pfd[1]) == -1) {
+ DEBUG(0,("check_kernel_oplocks: Kernel oplocks are not "
+ "available on this machine. Disabling kernel oplock "
+ "support.\n" ));
+ close(pfd[0]);
+ close(pfd[1]);
+ close(fd);
+ return False;
+ }
+
+ if(sys_fcntl_long(fd, F_OPLKACK, OP_REVOKE) < 0 ) {
+ DEBUG(0,("check_kernel_oplocks: Error when removing kernel "
+ "oplock. Error was %s. Disabling kernel oplock "
+ "support.\n", strerror(errno) ));
+ close(pfd[0]);
+ close(pfd[1]);
+ close(fd);
+ return False;
+ }
+
+ close(pfd[0]);
+ close(pfd[1]);
+ close(fd);
+
+ return True;
+}
+
+/****************************************************************************
+ * Deal with the IRIX kernel <--> smbd
+ * oplock break protocol.
+****************************************************************************/
+
+static files_struct *irix_oplock_receive_message(fd_set *fds)
+{
+ oplock_stat_t os;
+ char dummy;
+ struct file_id fileid;
+ files_struct *fsp;
+
+ /* Ensure we only get one call per select fd set. */
+ FD_CLR(oplock_pipe_read, fds);
+
+ /*
+ * Read one byte of zero to clear the
+ * kernel break notify message.
+ */
+
+ if(read(oplock_pipe_read, &dummy, 1) != 1) {
+ DEBUG(0,("irix_oplock_receive_message: read of kernel "
+ "notification failed. Error was %s.\n",
+ strerror(errno) ));
+ return NULL;
+ }
+
+ /*
+ * Do a query to get the
+ * device and inode of the file that has the break
+ * request outstanding.
+ */
+
+ if(sys_fcntl_ptr(oplock_pipe_read, F_OPLKSTAT, &os) < 0) {
+ DEBUG(0,("irix_oplock_receive_message: fcntl of kernel "
+ "notification failed. Error was %s.\n",
+ strerror(errno) ));
+ if(errno == EAGAIN) {
+ /*
+ * Duplicate kernel break message - ignore.
+ */
+ return NULL;
+ }
+ return NULL;
+ }
+
+ /*
+ * We only have device and inode info here - we have to guess that this
+ * is the first fsp open with this dev,ino pair.
+ *
+ * NOTE: this doesn't work if any VFS modules overloads
+ * the file_id_create() hook!
+ */
+
+ fileid = file_id_create_dev((SMB_DEV_T)os.os_dev,
+ (SMB_INO_T)os.os_ino);
+ if ((fsp = file_find_di_first(fileid)) == NULL) {
+ DEBUG(0,("irix_oplock_receive_message: unable to find open "
+ "file with dev = %x, inode = %.0f\n",
+ (unsigned int)os.os_dev, (double)os.os_ino ));
+ return NULL;
+ }
+
+ DEBUG(5,("irix_oplock_receive_message: kernel oplock break request "
+ "received for file_id %s gen_id = %ul",
+ file_id_string_tos(&fsp->file_id),
+ fsp->fh->gen_id ));
+
+ return fsp;
+}
+
+/****************************************************************************
+ Attempt to set an kernel oplock on a file.
+****************************************************************************/
+
+static bool irix_set_kernel_oplock(files_struct *fsp, int oplock_type)
+{
+ if (sys_fcntl_long(fsp->fh->fd, F_OPLKREG, oplock_pipe_write) == -1) {
+ if(errno != EAGAIN) {
+ DEBUG(0,("irix_set_kernel_oplock: Unable to get "
+ "kernel oplock on file %s, file_id %s "
+ "gen_id = %ul. Error was %s\n",
+ fsp->fsp_name, file_id_string_tos(&fsp->file_id),
+ fsp->fh->gen_id,
+ strerror(errno) ));
+ } else {
+ DEBUG(5,("irix_set_kernel_oplock: Refused oplock on "
+ "file %s, fd = %d, file_id = %s, "
+ "gen_id = %ul. Another process had the file "
+ "open.\n",
+ fsp->fsp_name, fsp->fh->fd,
+ file_id_string_tos(&fsp->file_id),
+ fsp->fh->gen_id ));
+ }
+ return False;
+ }
+
+ DEBUG(10,("irix_set_kernel_oplock: got kernel oplock on file %s, file_id = %s "
+ "gen_id = %ul\n",
+ fsp->fsp_name, file_id_string_tos(&fsp->file_id),
+ fsp->fh->gen_id));
+
+ return True;
+}
+
+/****************************************************************************
+ Release a kernel oplock on a file.
+****************************************************************************/
+
+static void irix_release_kernel_oplock(files_struct *fsp)
+{
+ if (DEBUGLVL(10)) {
+ /*
+ * Check and print out the current kernel
+ * oplock state of this file.
+ */
+ int state = sys_fcntl_long(fsp->fh->fd, F_OPLKACK, -1);
+ dbgtext("irix_release_kernel_oplock: file %s, file_id = %s"
+ "gen_id = %ul, has kernel oplock state "
+ "of %x.\n", fsp->fsp_name, file_id_string_tos(&fsp->file_id),
+ fsp->fh->gen_id, state );
+ }
+
+ /*
+ * Remove the kernel oplock on this file.
+ */
+ if(sys_fcntl_long(fsp->fh->fd, F_OPLKACK, OP_REVOKE) < 0) {
+ if( DEBUGLVL( 0 )) {
+ dbgtext("irix_release_kernel_oplock: Error when "
+ "removing kernel oplock on file " );
+ dbgtext("%s, file_id = %s gen_id = %ul. "
+ "Error was %s\n",
+ fsp->fsp_name, file_id_string_tos(&fsp->file_id),
+ fsp->fh->gen_id,
+ strerror(errno) );
+ }
+ }
+}
+
+/****************************************************************************
+ See if there is a message waiting in this fd set.
+ Note that fds MAY BE NULL ! If so we must do our own select.
+****************************************************************************/
+
+static bool irix_oplock_msg_waiting(fd_set *fds)
+{
+ int selrtn;
+ fd_set myfds;
+ struct timeval to;
+
+ if (oplock_pipe_read == -1)
+ return False;
+
+ if (fds) {
+ return FD_ISSET(oplock_pipe_read, fds);
+ }
+
+ /* Do a zero-time select. We just need to find out if there
+ * are any outstanding messages. We use sys_select_intr as
+ * we need to ignore any signals. */
+
+ FD_ZERO(&myfds);
+ FD_SET(oplock_pipe_read, &myfds);
+
+ to = timeval_set(0, 0);
+ selrtn = sys_select_intr(oplock_pipe_read+1,&myfds,NULL,NULL,&to);
+ return (selrtn == 1) ? True : False;
+}
+
+/****************************************************************************
+ Setup kernel oplocks.
+****************************************************************************/
+
+struct kernel_oplocks *irix_init_kernel_oplocks(void)
+{
+ int pfd[2];
+ static struct kernel_oplocks koplocks;
+
+ if (!irix_oplocks_available())
+ return NULL;
+
+ if(pipe(pfd) != 0) {
+ DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. "
+ "Error was %s\n", strerror(errno) ));
+ return False;
+ }
+
+ oplock_pipe_read = pfd[0];
+ oplock_pipe_write = pfd[1];
+
+ koplocks.receive_message = irix_oplock_receive_message;
+ koplocks.set_oplock = irix_set_kernel_oplock;
+ koplocks.release_oplock = irix_release_kernel_oplock;
+ koplocks.msg_waiting = irix_oplock_msg_waiting;
+ koplocks.notification_fd = oplock_pipe_read;
+
+ return &koplocks;
+}
+#else
+ void oplock_irix_dummy(void);
+ void oplock_irix_dummy(void) {}
+#endif /* HAVE_KERNEL_OPLOCKS_IRIX */
diff --git a/source3/smbd/oplock_linux.c b/source3/smbd/oplock_linux.c
new file mode 100644
index 0000000000..08df228f8f
--- /dev/null
+++ b/source3/smbd/oplock_linux.c
@@ -0,0 +1,249 @@
+/*
+ Unix SMB/CIFS implementation.
+ kernel oplock processing for Linux
+ Copyright (C) Andrew Tridgell 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define DBGC_CLASS DBGC_LOCKING
+#include "includes.h"
+
+#if HAVE_KERNEL_OPLOCKS_LINUX
+
+static SIG_ATOMIC_T signals_received;
+#define FD_PENDING_SIZE 100
+static SIG_ATOMIC_T fd_pending_array[FD_PENDING_SIZE];
+
+#ifndef F_SETLEASE
+#define F_SETLEASE 1024
+#endif
+
+#ifndef F_GETLEASE
+#define F_GETLEASE 1025
+#endif
+
+#ifndef CAP_LEASE
+#define CAP_LEASE 28
+#endif
+
+#ifndef RT_SIGNAL_LEASE
+#define RT_SIGNAL_LEASE (SIGRTMIN+1)
+#endif
+
+#ifndef F_SETSIG
+#define F_SETSIG 10
+#endif
+
+/****************************************************************************
+ Handle a LEASE signal, incrementing the signals_received and blocking the signal.
+****************************************************************************/
+
+static void signal_handler(int sig, siginfo_t *info, void *unused)
+{
+ if (signals_received < FD_PENDING_SIZE - 1) {
+ fd_pending_array[signals_received] = (SIG_ATOMIC_T)info->si_fd;
+ signals_received++;
+ } /* Else signal is lost. */
+ sys_select_signal(RT_SIGNAL_LEASE);
+}
+
+/*
+ * public function to get linux lease capability. Needed by some VFS modules (eg. gpfs.c)
+ */
+void linux_set_lease_capability(void)
+{
+ set_effective_capability(LEASE_CAPABILITY);
+}
+
+/*
+ * Call to set the kernel lease signal handler
+ */
+int linux_set_lease_sighandler(int fd)
+{
+ if (fcntl(fd, F_SETSIG, RT_SIGNAL_LEASE) == -1) {
+ DEBUG(3,("Failed to set signal handler for kernel lease\n"));
+ return -1;
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Call SETLEASE. If we get EACCES then we try setting up the right capability and
+ try again.
+ Use the SMB_VFS_LINUX_SETLEASE instead of this call directly.
+****************************************************************************/
+
+int linux_setlease(int fd, int leasetype)
+{
+ int ret;
+
+ ret = fcntl(fd, F_SETLEASE, leasetype);
+ if (ret == -1 && errno == EACCES) {
+ set_effective_capability(LEASE_CAPABILITY);
+ ret = fcntl(fd, F_SETLEASE, leasetype);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Deal with the Linux kernel <--> smbd
+ * oplock break protocol.
+****************************************************************************/
+
+static files_struct *linux_oplock_receive_message(fd_set *fds)
+{
+ int fd;
+ files_struct *fsp;
+
+ BlockSignals(True, RT_SIGNAL_LEASE);
+ fd = fd_pending_array[0];
+ fsp = file_find_fd(fd);
+ fd_pending_array[0] = (SIG_ATOMIC_T)-1;
+ if (signals_received > 1)
+ memmove(CONST_DISCARD(void *, &fd_pending_array[0]),
+ CONST_DISCARD(void *, &fd_pending_array[1]),
+ sizeof(SIG_ATOMIC_T)*(signals_received-1));
+ signals_received--;
+ /* now we can receive more signals */
+ BlockSignals(False, RT_SIGNAL_LEASE);
+
+ return fsp;
+}
+
+/****************************************************************************
+ Attempt to set an kernel oplock on a file.
+****************************************************************************/
+
+static bool linux_set_kernel_oplock(files_struct *fsp, int oplock_type)
+{
+ if ( SMB_VFS_LINUX_SETLEASE(fsp, F_WRLCK) == -1) {
+ DEBUG(3,("linux_set_kernel_oplock: Refused oplock on file %s, "
+ "fd = %d, file_id = %s. (%s)\n",
+ fsp->fsp_name, fsp->fh->fd,
+ file_id_string_tos(&fsp->file_id),
+ strerror(errno)));
+ return False;
+ }
+
+ DEBUG(3,("linux_set_kernel_oplock: got kernel oplock on file %s, "
+ "file_id = %s gen_id = %lu\n",
+ fsp->fsp_name, file_id_string_tos(&fsp->file_id),
+ fsp->fh->gen_id));
+
+ return True;
+}
+
+/****************************************************************************
+ Release a kernel oplock on a file.
+****************************************************************************/
+
+static void linux_release_kernel_oplock(files_struct *fsp)
+{
+ if (DEBUGLVL(10)) {
+ /*
+ * Check and print out the current kernel
+ * oplock state of this file.
+ */
+ int state = fcntl(fsp->fh->fd, F_GETLEASE, 0);
+ dbgtext("linux_release_kernel_oplock: file %s, file_id = %s "
+ "gen_id = %lu has kernel oplock state "
+ "of %x.\n", fsp->fsp_name, file_id_string_tos(&fsp->file_id),
+ fsp->fh->gen_id, state );
+ }
+
+ /*
+ * Remove the kernel oplock on this file.
+ */
+ if ( SMB_VFS_LINUX_SETLEASE(fsp, F_UNLCK) == -1) {
+ if (DEBUGLVL(0)) {
+ dbgtext("linux_release_kernel_oplock: Error when "
+ "removing kernel oplock on file " );
+ dbgtext("%s, file_id = %s, gen_id = %lu. "
+ "Error was %s\n", fsp->fsp_name,
+ file_id_string_tos(&fsp->file_id),
+ fsp->fh->gen_id, strerror(errno) );
+ }
+ }
+}
+
+/****************************************************************************
+ See if a oplock message is waiting.
+****************************************************************************/
+
+static bool linux_oplock_msg_waiting(fd_set *fds)
+{
+ return signals_received != 0;
+}
+
+/****************************************************************************
+ See if the kernel supports oplocks.
+****************************************************************************/
+
+static bool linux_oplocks_available(void)
+{
+ int fd, ret;
+ fd = open("/dev/null", O_RDONLY);
+ if (fd == -1)
+ return False; /* uggh! */
+ ret = fcntl(fd, F_GETLEASE, 0);
+ close(fd);
+ return ret == F_UNLCK;
+}
+
+/****************************************************************************
+ Setup kernel oplocks.
+****************************************************************************/
+
+struct kernel_oplocks *linux_init_kernel_oplocks(void)
+{
+ static struct kernel_oplocks koplocks;
+ struct sigaction act;
+
+ if (!linux_oplocks_available()) {
+ DEBUG(3,("Linux kernel oplocks not available\n"));
+ return NULL;
+ }
+
+ ZERO_STRUCT(act);
+
+ act.sa_handler = NULL;
+ act.sa_sigaction = signal_handler;
+ act.sa_flags = SA_SIGINFO;
+ sigemptyset( &act.sa_mask );
+ if (sigaction(RT_SIGNAL_LEASE, &act, NULL) != 0) {
+ DEBUG(0,("Failed to setup RT_SIGNAL_LEASE handler\n"));
+ return NULL;
+ }
+
+ koplocks.receive_message = linux_oplock_receive_message;
+ koplocks.set_oplock = linux_set_kernel_oplock;
+ koplocks.release_oplock = linux_release_kernel_oplock;
+ koplocks.msg_waiting = linux_oplock_msg_waiting;
+ koplocks.notification_fd = -1;
+
+ /* the signal can start off blocked due to a bug in bash */
+ BlockSignals(False, RT_SIGNAL_LEASE);
+
+ DEBUG(3,("Linux kernel oplocks enabled\n"));
+
+ return &koplocks;
+}
+#else
+ void oplock_linux_dummy(void);
+
+ void oplock_linux_dummy(void) {}
+#endif /* HAVE_KERNEL_OPLOCKS_LINUX */
diff --git a/source3/smbd/password.c b/source3/smbd/password.c
new file mode 100644
index 0000000000..1d3514429f
--- /dev/null
+++ b/source3/smbd/password.c
@@ -0,0 +1,829 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2007.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* users from session setup */
+static char *session_userlist = NULL;
+/* workgroup from session setup. */
+static char *session_workgroup = NULL;
+
+/* this holds info on user ids that are already validated for this VC */
+static user_struct *validated_users;
+static int next_vuid = VUID_OFFSET;
+static int num_validated_vuids;
+
+enum server_allocated_state { SERVER_ALLOCATED_REQUIRED_YES,
+ SERVER_ALLOCATED_REQUIRED_NO,
+ SERVER_ALLOCATED_REQUIRED_ANY};
+
+static user_struct *get_valid_user_struct_internal(uint16 vuid,
+ enum server_allocated_state server_allocated)
+{
+ user_struct *usp;
+ int count=0;
+
+ if (vuid == UID_FIELD_INVALID)
+ return NULL;
+
+ for (usp=validated_users;usp;usp=usp->next,count++) {
+ if (vuid == usp->vuid) {
+ switch (server_allocated) {
+ case SERVER_ALLOCATED_REQUIRED_YES:
+ if (usp->server_info == NULL) {
+ continue;
+ }
+ break;
+ case SERVER_ALLOCATED_REQUIRED_NO:
+ if (usp->server_info != NULL) {
+ continue;
+ }
+ case SERVER_ALLOCATED_REQUIRED_ANY:
+ break;
+ }
+ if (count > 10) {
+ DLIST_PROMOTE(validated_users, usp);
+ }
+ return usp;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Check if a uid has been validated, and return an pointer to the user_struct
+ 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(uint16 vuid)
+{
+ return get_valid_user_struct_internal(vuid,
+ SERVER_ALLOCATED_REQUIRED_YES);
+}
+
+bool is_partial_auth_vuid(uint16 vuid)
+{
+ if (vuid == UID_FIELD_INVALID) {
+ return False;
+ }
+ return get_valid_user_struct_internal(vuid,
+ SERVER_ALLOCATED_REQUIRED_NO) ? True : False;
+}
+
+/****************************************************************************
+ Get the user struct of a partial NTLMSSP login
+****************************************************************************/
+
+user_struct *get_partial_auth_user_struct(uint16 vuid)
+{
+ return get_valid_user_struct_internal(vuid,
+ SERVER_ALLOCATED_REQUIRED_NO);
+}
+
+/****************************************************************************
+ Invalidate a uid.
+****************************************************************************/
+
+void invalidate_vuid(uint16 vuid)
+{
+ user_struct *vuser = NULL;
+
+ if (vuid == UID_FIELD_INVALID) {
+ return;
+ }
+
+ vuser = get_valid_user_struct_internal(vuid,
+ SERVER_ALLOCATED_REQUIRED_ANY);
+ if (vuser == NULL) {
+ return;
+ }
+
+ session_yield(vuser);
+
+ if (vuser->auth_ntlmssp_state) {
+ auth_ntlmssp_end(&vuser->auth_ntlmssp_state);
+ }
+
+ DLIST_REMOVE(validated_users, vuser);
+
+ /* clear the vuid from the 'cache' on each connection, and
+ from the vuid 'owner' of connections */
+ conn_clear_vuid_caches(vuid);
+
+ TALLOC_FREE(vuser);
+ num_validated_vuids--;
+}
+
+/****************************************************************************
+ Invalidate all vuid entries for this process.
+****************************************************************************/
+
+void invalidate_all_vuids(void)
+{
+ user_struct *usp, *next=NULL;
+
+ for (usp=validated_users;usp;usp=next) {
+ next = usp->next;
+ invalidate_vuid(usp->vuid);
+ }
+}
+
+/****************************************************
+ Create a new partial auth user struct.
+*****************************************************/
+
+int register_initial_vuid(void)
+{
+ user_struct *vuser;
+
+ /* Paranoia check. */
+ if(lp_security() == SEC_SHARE) {
+ smb_panic("register_initial_vuid: "
+ "Tried to register uid in security=share");
+ }
+
+ /* Limit allowed vuids to 16bits - VUID_OFFSET. */
+ if (num_validated_vuids >= 0xFFFF-VUID_OFFSET) {
+ return UID_FIELD_INVALID;
+ }
+
+ if((vuser = talloc_zero(NULL, user_struct)) == NULL) {
+ DEBUG(0,("register_initial_vuid: "
+ "Failed to talloc users struct!\n"));
+ return UID_FIELD_INVALID;
+ }
+
+ /* Allocate a free vuid. Yes this is a linear search... */
+ while( get_valid_user_struct_internal(next_vuid,
+ SERVER_ALLOCATED_REQUIRED_ANY) != NULL ) {
+ next_vuid++;
+ /* Check for vuid wrap. */
+ if (next_vuid == UID_FIELD_INVALID) {
+ next_vuid = VUID_OFFSET;
+ }
+ }
+
+ DEBUG(10,("register_initial_vuid: allocated vuid = %u\n",
+ (unsigned int)next_vuid ));
+
+ vuser->vuid = next_vuid;
+
+ /*
+ * This happens in an unfinished NTLMSSP session setup. We
+ * need to allocate a vuid between the first and second calls
+ * to NTLMSSP.
+ */
+ next_vuid++;
+ num_validated_vuids++;
+
+ DLIST_ADD(validated_users, vuser);
+ return vuser->vuid;
+}
+
+static int register_homes_share(const char *username)
+{
+ int result;
+ struct passwd *pwd;
+
+ result = lp_servicenumber(username);
+ if (result != -1) {
+ DEBUG(3, ("Using static (or previously created) service for "
+ "user '%s'; path = '%s'\n", username,
+ lp_pathname(result)));
+ return result;
+ }
+
+ pwd = getpwnam_alloc(talloc_tos(), username);
+
+ if ((pwd == NULL) || (pwd->pw_dir[0] == '\0')) {
+ DEBUG(3, ("No home directory defined for user '%s'\n",
+ username));
+ TALLOC_FREE(pwd);
+ return -1;
+ }
+
+ DEBUG(3, ("Adding homes service for user '%s' using home directory: "
+ "'%s'\n", username, pwd->pw_dir));
+
+ result = add_home_service(username, username, pwd->pw_dir);
+
+ TALLOC_FREE(pwd);
+ return result;
+}
+
+/**
+ * register that a valid login has been performed, establish 'session'.
+ * @param server_info The token returned from the authentication process.
+ * (now 'owned' by register_existing_vuid)
+ *
+ * @param session_key The User session key for the login session (now also
+ * 'owned' by register_existing_vuid)
+ *
+ * @param respose_blob The NT challenge-response, if available. (May be
+ * freed after this call)
+ *
+ * @param smb_name The untranslated name of the user
+ *
+ * @return Newly allocated vuid, biased by an offset. (This allows us to
+ * tell random client vuid's (normally zero) from valid vuids.)
+ *
+ */
+
+int register_existing_vuid(uint16 vuid,
+ auth_serversupplied_info *server_info,
+ DATA_BLOB response_blob,
+ const char *smb_name)
+{
+ fstring tmp;
+ user_struct *vuser;
+
+ vuser = get_partial_auth_user_struct(vuid);
+ if (!vuser) {
+ goto fail;
+ }
+
+ /* Use this to keep tabs on all our info from the authentication */
+ vuser->server_info = talloc_move(vuser, &server_info);
+
+ /* This is a potentially untrusted username */
+ alpha_strcpy(tmp, smb_name, ". _-$", sizeof(tmp));
+
+ vuser->server_info->sanitized_username = talloc_strdup(
+ vuser->server_info, tmp);
+
+ DEBUG(10,("register_existing_vuid: (%u,%u) %s %s %s guest=%d\n",
+ (unsigned int)vuser->server_info->utok.uid,
+ (unsigned int)vuser->server_info->utok.gid,
+ vuser->server_info->unix_name,
+ vuser->server_info->sanitized_username,
+ pdb_get_domain(vuser->server_info->sam_account),
+ vuser->server_info->guest ));
+
+ DEBUG(3, ("register_existing_vuid: User name: %s\t"
+ "Real name: %s\n", vuser->server_info->unix_name,
+ pdb_get_fullname(vuser->server_info->sam_account)));
+
+ if (!vuser->server_info->ptok) {
+ DEBUG(1, ("register_existing_vuid: server_info does not "
+ "contain a user_token - cannot continue\n"));
+ goto fail;
+ }
+
+ DEBUG(3,("register_existing_vuid: UNIX uid %d is UNIX user %s, "
+ "and will be vuid %u\n", (int)vuser->server_info->utok.uid,
+ vuser->server_info->unix_name, vuser->vuid));
+
+ next_vuid++;
+ num_validated_vuids++;
+
+ if (!session_claim(vuser)) {
+ DEBUG(1, ("register_existing_vuid: Failed to claim session "
+ "for vuid=%d\n",
+ vuser->vuid));
+ goto fail;
+ }
+
+ /* Register a home dir service for this user if
+ (a) This is not a guest connection,
+ (b) we have a home directory defined
+ (c) there s not an existing static share by that name
+ If a share exists by this name (autoloaded or not) reuse it . */
+
+ vuser->homes_snum = -1;
+
+ if (!vuser->server_info->guest) {
+ vuser->homes_snum = register_homes_share(
+ vuser->server_info->unix_name);
+ }
+
+ if (srv_is_signing_negotiated() && !vuser->server_info->guest &&
+ !srv_signing_started()) {
+ /* Try and turn on server signing on the first non-guest
+ * sessionsetup. */
+ srv_set_signing(vuser->server_info->user_session_key, response_blob);
+ }
+
+ /* fill in the current_user_info struct */
+ set_current_user_info(
+ vuser->server_info->sanitized_username,
+ vuser->server_info->unix_name,
+ pdb_get_fullname(vuser->server_info->sam_account),
+ pdb_get_domain(vuser->server_info->sam_account));
+
+ return vuser->vuid;
+
+ fail:
+
+ if (vuser) {
+ invalidate_vuid(vuid);
+ }
+ return UID_FIELD_INVALID;
+}
+
+/****************************************************************************
+ Add a name to the session users list.
+****************************************************************************/
+
+void add_session_user(const char *user)
+{
+ struct passwd *pw;
+ char *tmp;
+
+ pw = Get_Pwnam_alloc(talloc_tos(), user);
+
+ if (pw == NULL) {
+ return;
+ }
+
+ if (session_userlist == NULL) {
+ session_userlist = SMB_STRDUP(pw->pw_name);
+ goto done;
+ }
+
+ if (in_list(pw->pw_name,session_userlist,False) ) {
+ goto done;
+ }
+
+ if (strlen(session_userlist) > 128 * 1024) {
+ DEBUG(3,("add_session_user: session userlist already "
+ "too large.\n"));
+ goto done;
+ }
+
+ if (asprintf(&tmp, "%s %s", session_userlist, pw->pw_name) == -1) {
+ DEBUG(3, ("asprintf failed\n"));
+ goto done;
+ }
+
+ SAFE_FREE(session_userlist);
+ session_userlist = tmp;
+ done:
+ TALLOC_FREE(pw);
+}
+
+/****************************************************************************
+ In security=share mode we need to store the client workgroup, as that's
+ what Vista uses for the NTLMv2 calculation.
+****************************************************************************/
+
+void add_session_workgroup(const char *workgroup)
+{
+ if (session_workgroup) {
+ SAFE_FREE(session_workgroup);
+ }
+ session_workgroup = smb_xstrdup(workgroup);
+}
+
+/****************************************************************************
+ In security=share mode we need to return the client workgroup, as that's
+ what Vista uses for the NTLMv2 calculation.
+****************************************************************************/
+
+const char *get_session_workgroup(void)
+{
+ return session_workgroup;
+}
+
+/****************************************************************************
+ Check if a user is in a netgroup user list. If at first we don't succeed,
+ try lower case.
+****************************************************************************/
+
+bool user_in_netgroup(const char *user, const char *ngname)
+{
+#ifdef HAVE_NETGROUP
+ static char *mydomain = NULL;
+ fstring lowercase_user;
+
+ if (mydomain == NULL)
+ yp_get_default_domain(&mydomain);
+
+ if(mydomain == NULL) {
+ DEBUG(5,("Unable to get default yp domain, "
+ "let's try without specifying it\n"));
+ }
+
+ DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
+ user, mydomain?mydomain:"(ANY)", ngname));
+
+ if (innetgr(ngname, NULL, user, mydomain)) {
+ DEBUG(5,("user_in_netgroup: Found\n"));
+ return (True);
+ } else {
+
+ /*
+ * Ok, innetgr is case sensitive. Try once more with lowercase
+ * just in case. Attempt to fix #703. JRA.
+ */
+
+ fstrcpy(lowercase_user, user);
+ strlower_m(lowercase_user);
+
+ DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
+ lowercase_user, mydomain?mydomain:"(ANY)", ngname));
+
+ if (innetgr(ngname, NULL, lowercase_user, mydomain)) {
+ DEBUG(5,("user_in_netgroup: Found\n"));
+ return (True);
+ }
+ }
+#endif /* HAVE_NETGROUP */
+ return False;
+}
+
+/****************************************************************************
+ Check if a user is in a user list - can check combinations of UNIX
+ and netgroup lists.
+****************************************************************************/
+
+bool user_in_list(const char *user,const char **list)
+{
+ if (!list || !*list)
+ return False;
+
+ DEBUG(10,("user_in_list: checking user %s in list\n", user));
+
+ while (*list) {
+
+ DEBUG(10,("user_in_list: checking user |%s| against |%s|\n",
+ user, *list));
+
+ /*
+ * Check raw username.
+ */
+ if (strequal(user, *list))
+ return(True);
+
+ /*
+ * Now check to see if any combination
+ * of UNIX and netgroups has been specified.
+ */
+
+ if(**list == '@') {
+ /*
+ * Old behaviour. Check netgroup list
+ * followed by UNIX list.
+ */
+ if(user_in_netgroup(user, *list +1))
+ return True;
+ if(user_in_group(user, *list +1))
+ return True;
+ } else if (**list == '+') {
+
+ if((*(*list +1)) == '&') {
+ /*
+ * Search UNIX list followed by netgroup.
+ */
+ if(user_in_group(user, *list +2))
+ return True;
+ if(user_in_netgroup(user, *list +2))
+ return True;
+
+ } else {
+
+ /*
+ * Just search UNIX list.
+ */
+
+ if(user_in_group(user, *list +1))
+ return True;
+ }
+
+ } else if (**list == '&') {
+
+ if(*(*list +1) == '+') {
+ /*
+ * Search netgroup list followed by UNIX list.
+ */
+ if(user_in_netgroup(user, *list +2))
+ return True;
+ if(user_in_group(user, *list +2))
+ return True;
+ } else {
+ /*
+ * Just search netgroup list.
+ */
+ if(user_in_netgroup(user, *list +1))
+ return True;
+ }
+ }
+
+ list++;
+ }
+ return(False);
+}
+
+/****************************************************************************
+ Check if a username is valid.
+****************************************************************************/
+
+static bool user_ok(const char *user, int snum)
+{
+ char **valid, **invalid;
+ bool ret;
+
+ valid = invalid = NULL;
+ ret = True;
+
+ if (lp_invalid_users(snum)) {
+ str_list_copy(talloc_tos(), &invalid, lp_invalid_users(snum));
+ if (invalid &&
+ str_list_substitute(invalid, "%S", lp_servicename(snum))) {
+
+ /* This is used in sec=share only, so no current user
+ * around to pass to str_list_sub_basic() */
+
+ if ( invalid && str_list_sub_basic(invalid, "", "") ) {
+ ret = !user_in_list(user,
+ (const char **)invalid);
+ }
+ }
+ }
+ TALLOC_FREE(invalid);
+
+ if (ret && lp_valid_users(snum)) {
+ str_list_copy(talloc_tos(), &valid, lp_valid_users(snum));
+ if ( valid &&
+ str_list_substitute(valid, "%S", lp_servicename(snum)) ) {
+
+ /* This is used in sec=share only, so no current user
+ * around to pass to str_list_sub_basic() */
+
+ if ( valid && str_list_sub_basic(valid, "", "") ) {
+ ret = user_in_list(user, (const char **)valid);
+ }
+ }
+ }
+ TALLOC_FREE(valid);
+
+ if (ret && lp_onlyuser(snum)) {
+ char **user_list = str_list_make(
+ talloc_tos(), lp_username(snum), NULL);
+ if (user_list &&
+ str_list_substitute(user_list, "%S",
+ lp_servicename(snum))) {
+ ret = user_in_list(user, (const char **)user_list);
+ }
+ TALLOC_FREE(user_list);
+ }
+
+ return(ret);
+}
+
+/****************************************************************************
+ Validate a group username entry. Return the username or NULL.
+****************************************************************************/
+
+static char *validate_group(char *group, DATA_BLOB password,int snum)
+{
+#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)) {
+ endnetgrent();
+ return(user);
+ }
+ }
+ }
+ endnetgrent();
+ }
+#endif
+
+#ifdef HAVE_GETGRENT
+ {
+ struct group *gptr;
+ setgrent();
+ while ((gptr = (struct group *)getgrent())) {
+ if (strequal(gptr->gr_name,group))
+ break;
+ }
+
+ /*
+ * As user_ok can recurse doing a getgrent(), we must
+ * copy the member list onto the heap before
+ * use. Bug pointed out by leon@eatworms.swmed.edu.
+ */
+
+ if (gptr) {
+ char *member_list = NULL;
+ size_t list_len = 0;
+ char *member;
+ int i;
+
+ for(i = 0; gptr->gr_mem && gptr->gr_mem[i]; i++) {
+ list_len += strlen(gptr->gr_mem[i])+1;
+ }
+ list_len++;
+
+ member_list = (char *)SMB_MALLOC(list_len);
+ if (!member_list) {
+ endgrent();
+ return NULL;
+ }
+
+ *member_list = '\0';
+ member = member_list;
+
+ for(i = 0; gptr->gr_mem && gptr->gr_mem[i]; i++) {
+ size_t member_len = strlen(gptr->gr_mem[i])+1;
+
+ DEBUG(10,("validate_group: = gr_mem = "
+ "%s\n", gptr->gr_mem[i]));
+
+ safe_strcpy(member, gptr->gr_mem[i],
+ list_len - (member-member_list));
+ member += member_len;
+ }
+
+ endgrent();
+
+ member = member_list;
+ while (*member) {
+ if (user_ok(member,snum) &&
+ password_ok(member,password)) {
+ char *name = talloc_strdup(talloc_tos(),
+ member);
+ SAFE_FREE(member_list);
+ return name;
+ }
+
+ DEBUG(10,("validate_group = member = %s\n",
+ member));
+
+ member += strlen(member) + 1;
+ }
+
+ SAFE_FREE(member_list);
+ } else {
+ endgrent();
+ return NULL;
+ }
+ }
+#endif
+ return(NULL);
+}
+
+/****************************************************************************
+ Check for authority to login to a service with a given username/password.
+ Note this is *NOT* used when logging on using sessionsetup_and_X.
+****************************************************************************/
+
+bool authorise_login(int snum, fstring user, DATA_BLOB password,
+ bool *guest)
+{
+ bool ok = False;
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("authorise_login: checking authorisation on "
+ "user=%s pass=%s\n", user,password.data));
+#endif
+
+ *guest = False;
+
+ /* there are several possibilities:
+ 1) login as the given user with given password
+ 2) login as a previously registered username with the given
+ password
+ 3) login as a session list username with the given password
+ 4) login as a previously validated user/password pair
+ 5) login as the "user =" user with given password
+ 6) login as the "user =" user with no password
+ (guest connection)
+ 7) login as guest user with no password
+
+ if the service is guest_only then steps 1 to 5 are skipped
+ */
+
+ /* now check the list of session users */
+ if (!ok) {
+ char *auser;
+ char *user_list = NULL;
+ char *saveptr;
+
+ if ( session_userlist )
+ user_list = SMB_STRDUP(session_userlist);
+ else
+ user_list = SMB_STRDUP("");
+
+ if (!user_list)
+ return(False);
+
+ for (auser = strtok_r(user_list, LIST_SEP, &saveptr);
+ !ok && auser;
+ auser = strtok_r(NULL, LIST_SEP, &saveptr)) {
+ fstring user2;
+ fstrcpy(user2,auser);
+ if (!user_ok(user2,snum))
+ continue;
+
+ if (password_ok(user2,password)) {
+ ok = True;
+ fstrcpy(user,user2);
+ DEBUG(3,("authorise_login: ACCEPTED: session "
+ "list username (%s) and given "
+ "password ok\n", user));
+ }
+ }
+
+ SAFE_FREE(user_list);
+ }
+
+ /* check the user= fields and the given password */
+ if (!ok && lp_username(snum)) {
+ TALLOC_CTX *ctx = talloc_tos();
+ char *auser;
+ char *user_list = talloc_strdup(ctx, lp_username(snum));
+ char *saveptr;
+
+ if (!user_list) {
+ goto check_guest;
+ }
+
+ user_list = talloc_string_sub(ctx,
+ user_list,
+ "%S",
+ lp_servicename(snum));
+
+ if (!user_list) {
+ goto check_guest;
+ }
+
+ for (auser = strtok_r(user_list, LIST_SEP, &saveptr);
+ auser && !ok;
+ auser = strtok_r(NULL, LIST_SEP, &saveptr)) {
+ if (*auser == '@') {
+ auser = validate_group(auser+1,password,snum);
+ if (auser) {
+ ok = True;
+ fstrcpy(user,auser);
+ DEBUG(3,("authorise_login: ACCEPTED: "
+ "group username and given "
+ "password ok (%s)\n", user));
+ }
+ } else {
+ fstring user2;
+ fstrcpy(user2,auser);
+ if (user_ok(user2,snum) &&
+ password_ok(user2,password)) {
+ ok = True;
+ fstrcpy(user,user2);
+ DEBUG(3,("authorise_login: ACCEPTED: "
+ "user list username and "
+ "given password ok (%s)\n",
+ user));
+ }
+ }
+ }
+ }
+
+ check_guest:
+
+ /* check for a normal guest connection */
+ if (!ok && GUEST_OK(snum)) {
+ struct passwd *guest_pw;
+ fstring guestname;
+ fstrcpy(guestname,lp_guestaccount());
+ guest_pw = Get_Pwnam_alloc(talloc_tos(), guestname);
+ if (guest_pw != NULL) {
+ fstrcpy(user,guestname);
+ ok = True;
+ DEBUG(3,("authorise_login: ACCEPTED: guest account "
+ "and guest ok (%s)\n", user));
+ } else {
+ DEBUG(0,("authorise_login: Invalid guest account "
+ "%s??\n",guestname));
+ }
+ TALLOC_FREE(guest_pw);
+ *guest = True;
+ }
+
+ if (ok && !user_ok(user, snum)) {
+ DEBUG(0,("authorise_login: rejected invalid user %s\n",user));
+ ok = False;
+ }
+
+ return(ok);
+}
diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c
new file mode 100644
index 0000000000..4fdcdcc557
--- /dev/null
+++ b/source3/smbd/pipes.c
@@ -0,0 +1,320 @@
+/*
+ Unix SMB/CIFS implementation.
+ Pipe SMB reply routines
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Paul Ashton 1997-1998.
+ Copyright (C) Jeremy Allison 2005.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ This file handles reply_ calls on named pipes that the server
+ makes to handle specific protocols
+*/
+
+
+#include "includes.h"
+
+#define PIPE "\\PIPE\\"
+#define PIPELEN strlen(PIPE)
+
+#define MAX_PIPE_NAME_LEN 24
+
+/* PIPE/<name>/<pid>/<pnum> */
+#define PIPEDB_KEY_FORMAT "PIPE/%s/%u/%d"
+
+struct pipe_dbrec {
+ struct server_id pid;
+ int pnum;
+ uid_t uid;
+
+ char name[MAX_PIPE_NAME_LEN];
+ fstring user;
+};
+
+/****************************************************************************
+ 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.
+****************************************************************************/
+
+void reply_open_pipe_and_X(connection_struct *conn, struct smb_request *req)
+{
+ const char *fname = NULL;
+ char *pipe_name = NULL;
+ smb_np_struct *p;
+ int size=0,fmode=0,mtime=0,rmode=0;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ /* XXXX we need to handle passed times, sattr and flags */
+ srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2, &pipe_name,
+ smb_buf(req->inbuf), STR_TERMINATE);
+ if (!pipe_name) {
+ reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERRbadpipe);
+ return;
+ }
+
+ /* If the name doesn't start \PIPE\ then this is directed */
+ /* at a mailslot or something we really, really don't understand, */
+ /* not just something we really don't understand. */
+ if ( strncmp(pipe_name,PIPE,PIPELEN) != 0 ) {
+ reply_doserror(req, ERRSRV, ERRaccess);
+ return;
+ }
+
+ DEBUG(4,("Opening pipe %s.\n", pipe_name));
+
+ /* See if it is one we want to handle. */
+ if (!is_known_pipename(pipe_name)) {
+ reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERRbadpipe);
+ return;
+ }
+
+ /* Strip \PIPE\ off the name. */
+ fname = pipe_name + PIPELEN;
+
+#if 0
+ /*
+ * Hack for NT printers... JRA.
+ */
+ if(should_fail_next_srvsvc_open(fname)) {
+ reply_doserror(req, ERRSRV, ERRaccess);
+ return;
+ }
+#endif
+
+ /* Known pipes arrive with DIR attribs. Remove it so a regular file */
+ /* can be opened and add it in after the open. */
+ DEBUG(3,("Known pipe %s opening.\n",fname));
+
+ p = open_rpc_pipe_p(fname, conn, req->vuid);
+ if (!p) {
+ reply_doserror(req, ERRSRV, ERRnofids);
+ return;
+ }
+
+ /* Prepare the reply */
+ reply_outbuf(req, 15, 0);
+
+ /* Mark the opened file as an existing named pipe in message mode. */
+ SSVAL(req->outbuf,smb_vwv9,2);
+ SSVAL(req->outbuf,smb_vwv10,0xc700);
+
+ if (rmode == 2) {
+ DEBUG(4,("Resetting open result to open from create.\n"));
+ rmode = 1;
+ }
+
+ SSVAL(req->outbuf,smb_vwv2, p->pnum);
+ SSVAL(req->outbuf,smb_vwv3,fmode);
+ srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
+ SIVAL(req->outbuf,smb_vwv6,size);
+ SSVAL(req->outbuf,smb_vwv8,rmode);
+ SSVAL(req->outbuf,smb_vwv11,0x0001);
+
+ chain_reply(req);
+ return;
+}
+
+/****************************************************************************
+ Reply to a write on a pipe.
+****************************************************************************/
+
+void reply_pipe_write(struct smb_request *req)
+{
+ smb_np_struct *p = get_rpc_pipe_p(SVAL(req->inbuf,smb_vwv0));
+ size_t numtowrite = SVAL(req->inbuf,smb_vwv1);
+ int nwritten;
+ char *data;
+
+ if (!p) {
+ reply_doserror(req, ERRDOS, ERRbadfid);
+ return;
+ }
+
+ if (p->vuid != req->vuid) {
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ return;
+ }
+
+ data = smb_buf(req->inbuf) + 3;
+
+ if (numtowrite == 0) {
+ nwritten = 0;
+ } else {
+ nwritten = write_to_pipe(p, data, numtowrite);
+ }
+
+ if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) {
+ reply_unixerror(req, ERRDOS, ERRnoaccess);
+ return;
+ }
+
+ reply_outbuf(req, 1, 0);
+
+ SSVAL(req->outbuf,smb_vwv0,nwritten);
+
+ DEBUG(3,("write-IPC pnum=%04x nwritten=%d\n", p->pnum, nwritten));
+
+ return;
+}
+
+/****************************************************************************
+ Reply to a write and X.
+
+ This code is basically stolen from reply_write_and_X with some
+ wrinkles to handle pipes.
+****************************************************************************/
+
+void reply_pipe_write_and_X(struct smb_request *req)
+{
+ smb_np_struct *p = get_rpc_pipe_p(SVAL(req->inbuf,smb_vwv2));
+ size_t numtowrite = SVAL(req->inbuf,smb_vwv10);
+ int nwritten = -1;
+ int smb_doff = SVAL(req->inbuf, smb_vwv11);
+ bool pipe_start_message_raw =
+ ((SVAL(req->inbuf, smb_vwv7)
+ & (PIPE_START_MESSAGE|PIPE_RAW_MODE))
+ == (PIPE_START_MESSAGE|PIPE_RAW_MODE));
+ char *data;
+
+ if (!p) {
+ reply_doserror(req, ERRDOS, ERRbadfid);
+ return;
+ }
+
+ if (p->vuid != req->vuid) {
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ return;
+ }
+
+ data = smb_base(req->inbuf) + smb_doff;
+
+ if (numtowrite == 0) {
+ nwritten = 0;
+ } else {
+ if(pipe_start_message_raw) {
+ /*
+ * For the start of a message in named pipe byte mode,
+ * the first two bytes are a length-of-pdu field. Ignore
+ * them (we don't trust the client). JRA.
+ */
+ if(numtowrite < 2) {
+ DEBUG(0,("reply_pipe_write_and_X: start of "
+ "message set and not enough data "
+ "sent.(%u)\n",
+ (unsigned int)numtowrite ));
+ reply_unixerror(req, ERRDOS, ERRnoaccess);
+ return;
+ }
+
+ data += 2;
+ numtowrite -= 2;
+ }
+ nwritten = write_to_pipe(p, data, numtowrite);
+ }
+
+ if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) {
+ reply_unixerror(req, ERRDOS,ERRnoaccess);
+ return;
+ }
+
+ reply_outbuf(req, 6, 0);
+
+ nwritten = (pipe_start_message_raw ? nwritten + 2 : nwritten);
+ SSVAL(req->outbuf,smb_vwv2,nwritten);
+
+ DEBUG(3,("writeX-IPC pnum=%04x nwritten=%d\n", p->pnum, nwritten));
+
+ chain_reply(req);
+}
+
+/****************************************************************************
+ Reply to a read and X.
+ This code is basically stolen from reply_read_and_X with some
+ wrinkles to handle pipes.
+****************************************************************************/
+
+void reply_pipe_read_and_X(struct smb_request *req)
+{
+ smb_np_struct *p = get_rpc_pipe_p(SVAL(req->inbuf,smb_vwv2));
+ int smb_maxcnt = SVAL(req->inbuf,smb_vwv5);
+ int smb_mincnt = SVAL(req->inbuf,smb_vwv6);
+ int nread = -1;
+ char *data;
+ bool unused;
+
+ /* we don't use the offset given to use for pipe reads. This
+ is deliberate, instead we always return the next lump of
+ data on the pipe */
+#if 0
+ uint32 smb_offs = IVAL(req->inbuf,smb_vwv3);
+#endif
+
+ if (!p) {
+ reply_doserror(req, ERRDOS, ERRbadfid);
+ return;
+ }
+
+ reply_outbuf(req, 12, smb_maxcnt);
+
+ data = smb_buf(req->outbuf);
+
+ nread = read_from_pipe(p, data, smb_maxcnt, &unused);
+
+ if (nread < 0) {
+ reply_doserror(req, ERRDOS, ERRnoaccess);
+ return;
+ }
+
+ srv_set_message((char *)req->outbuf, 12, nread, False);
+
+ SSVAL(req->outbuf,smb_vwv5,nread);
+ SSVAL(req->outbuf,smb_vwv6,smb_offset(data,req->outbuf));
+ SSVAL(smb_buf(req->outbuf),-2,nread);
+
+ DEBUG(3,("readX-IPC pnum=%04x min=%d max=%d nread=%d\n",
+ p->pnum, smb_mincnt, smb_maxcnt, nread));
+
+ chain_reply(req);
+}
+
+/****************************************************************************
+ Reply to a close.
+****************************************************************************/
+
+void reply_pipe_close(connection_struct *conn, struct smb_request *req)
+{
+ smb_np_struct *p = get_rpc_pipe_p(SVAL(req->inbuf,smb_vwv0));
+
+ if (!p) {
+ reply_doserror(req, ERRDOS, ERRbadfid);
+ return;
+ }
+
+ DEBUG(5,("reply_pipe_close: pnum:%x\n", p->pnum));
+
+ if (!close_rpc_pipe_hnd(p)) {
+ reply_doserror(req, ERRDOS, ERRbadfid);
+ return;
+ }
+
+ /* TODO: REMOVE PIPE FROM DB */
+
+ reply_outbuf(req, 0, 0);
+ return;
+}
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
new file mode 100644
index 0000000000..7479aea076
--- /dev/null
+++ b/source3/smbd/posix_acls.c
@@ -0,0 +1,4322 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB NT Security Descriptor / Unix permission conversion.
+ Copyright (C) Jeremy Allison 1994-2000.
+ Copyright (C) Andreas Gruenbacher 2002.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern struct current_user current_user;
+extern const struct generic_mapping file_generic_mapping;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_ACLS
+
+/****************************************************************************
+ Data structures representing the internal ACE format.
+****************************************************************************/
+
+enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
+enum ace_attribute {ALLOW_ACE, DENY_ACE}; /* Used for incoming NT ACLS. */
+
+typedef union posix_id {
+ uid_t uid;
+ gid_t gid;
+ int world;
+} posix_id;
+
+typedef struct canon_ace {
+ struct canon_ace *next, *prev;
+ SMB_ACL_TAG_T type;
+ mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
+ DOM_SID trustee;
+ enum ace_owner owner_type;
+ enum ace_attribute attr;
+ posix_id unix_ug;
+ bool inherited;
+} canon_ace;
+
+#define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR)
+
+/*
+ * EA format of user.SAMBA_PAI (Samba_Posix_Acl_Interitance)
+ * attribute on disk.
+ *
+ * | 1 | 1 | 2 | 2 | ....
+ * +------+------+-------------+---------------------+-------------+--------------------+
+ * | vers | flag | num_entries | num_default_entries | ..entries.. | default_entries... |
+ * +------+------+-------------+---------------------+-------------+--------------------+
+ */
+
+#define PAI_VERSION_OFFSET 0
+#define PAI_FLAG_OFFSET 1
+#define PAI_NUM_ENTRIES_OFFSET 2
+#define PAI_NUM_DEFAULT_ENTRIES_OFFSET 4
+#define PAI_ENTRIES_BASE 6
+
+#define PAI_VERSION 1
+#define PAI_ACL_FLAG_PROTECTED 0x1
+#define PAI_ENTRY_LENGTH 5
+
+/*
+ * In memory format of user.SAMBA_PAI attribute.
+ */
+
+struct pai_entry {
+ struct pai_entry *next, *prev;
+ enum ace_owner owner_type;
+ posix_id unix_ug;
+};
+
+struct pai_val {
+ bool pai_protected;
+ unsigned int num_entries;
+ struct pai_entry *entry_list;
+ unsigned int num_def_entries;
+ struct pai_entry *def_entry_list;
+};
+
+/************************************************************************
+ Return a uint32 of the pai_entry principal.
+************************************************************************/
+
+static uint32 get_pai_entry_val(struct pai_entry *paie)
+{
+ switch (paie->owner_type) {
+ case UID_ACE:
+ DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie->unix_ug.uid ));
+ return (uint32)paie->unix_ug.uid;
+ case GID_ACE:
+ DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie->unix_ug.gid ));
+ return (uint32)paie->unix_ug.gid;
+ case WORLD_ACE:
+ default:
+ DEBUG(10,("get_pai_entry_val: world ace\n"));
+ return (uint32)-1;
+ }
+}
+
+/************************************************************************
+ Return a uint32 of the entry principal.
+************************************************************************/
+
+static uint32 get_entry_val(canon_ace *ace_entry)
+{
+ switch (ace_entry->owner_type) {
+ case UID_ACE:
+ DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry->unix_ug.uid ));
+ return (uint32)ace_entry->unix_ug.uid;
+ case GID_ACE:
+ DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry->unix_ug.gid ));
+ return (uint32)ace_entry->unix_ug.gid;
+ case WORLD_ACE:
+ default:
+ DEBUG(10,("get_entry_val: world ace\n"));
+ return (uint32)-1;
+ }
+}
+
+/************************************************************************
+ Count the inherited entries.
+************************************************************************/
+
+static unsigned int num_inherited_entries(canon_ace *ace_list)
+{
+ unsigned int num_entries = 0;
+
+ for (; ace_list; ace_list = ace_list->next)
+ if (ace_list->inherited)
+ num_entries++;
+ return num_entries;
+}
+
+/************************************************************************
+ Create the on-disk format. Caller must free.
+************************************************************************/
+
+static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, bool pai_protected, size_t *store_size)
+{
+ char *pai_buf = NULL;
+ canon_ace *ace_list = NULL;
+ char *entry_offset = NULL;
+ unsigned int num_entries = 0;
+ unsigned int num_def_entries = 0;
+
+ for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next)
+ if (ace_list->inherited)
+ num_entries++;
+
+ for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next)
+ if (ace_list->inherited)
+ num_def_entries++;
+
+ DEBUG(10,("create_pai_buf: num_entries = %u, num_def_entries = %u\n", num_entries, num_def_entries ));
+
+ *store_size = PAI_ENTRIES_BASE + ((num_entries + num_def_entries)*PAI_ENTRY_LENGTH);
+
+ pai_buf = (char *)SMB_MALLOC(*store_size);
+ if (!pai_buf) {
+ return NULL;
+ }
+
+ /* Set up the header. */
+ memset(pai_buf, '\0', PAI_ENTRIES_BASE);
+ SCVAL(pai_buf,PAI_VERSION_OFFSET,PAI_VERSION);
+ SCVAL(pai_buf,PAI_FLAG_OFFSET,(pai_protected ? PAI_ACL_FLAG_PROTECTED : 0));
+ SSVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET,num_entries);
+ SSVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET,num_def_entries);
+
+ entry_offset = pai_buf + PAI_ENTRIES_BASE;
+
+ for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) {
+ if (ace_list->inherited) {
+ uint8 type_val = (unsigned char)ace_list->owner_type;
+ uint32 entry_val = get_entry_val(ace_list);
+
+ SCVAL(entry_offset,0,type_val);
+ SIVAL(entry_offset,1,entry_val);
+ entry_offset += PAI_ENTRY_LENGTH;
+ }
+ }
+
+ for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) {
+ if (ace_list->inherited) {
+ uint8 type_val = (unsigned char)ace_list->owner_type;
+ uint32 entry_val = get_entry_val(ace_list);
+
+ SCVAL(entry_offset,0,type_val);
+ SIVAL(entry_offset,1,entry_val);
+ entry_offset += PAI_ENTRY_LENGTH;
+ }
+ }
+
+ return pai_buf;
+}
+
+/************************************************************************
+ Store the user.SAMBA_PAI attribute on disk.
+************************************************************************/
+
+static void store_inheritance_attributes(files_struct *fsp, canon_ace *file_ace_list,
+ canon_ace *dir_ace_list, bool pai_protected)
+{
+ int ret;
+ size_t store_size;
+ char *pai_buf;
+
+ if (!lp_map_acl_inherit(SNUM(fsp->conn)))
+ return;
+
+ /*
+ * Don't store if this ACL isn't protected and
+ * none of the entries in it are marked as inherited.
+ */
+
+ if (!pai_protected && num_inherited_entries(file_ace_list) == 0 && num_inherited_entries(dir_ace_list) == 0) {
+ /* Instead just remove the attribute if it exists. */
+ if (fsp->fh->fd != -1)
+ SMB_VFS_FREMOVEXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME);
+ else
+ SMB_VFS_REMOVEXATTR(fsp->conn, fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME);
+ return;
+ }
+
+ pai_buf = create_pai_buf(file_ace_list, dir_ace_list, pai_protected, &store_size);
+
+ if (fsp->fh->fd != -1)
+ ret = SMB_VFS_FSETXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME,
+ pai_buf, store_size, 0);
+ else
+ ret = SMB_VFS_SETXATTR(fsp->conn,fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME,
+ pai_buf, store_size, 0);
+
+ SAFE_FREE(pai_buf);
+
+ DEBUG(10,("store_inheritance_attribute:%s for file %s\n", pai_protected ? " (protected)" : "", fsp->fsp_name));
+ if (ret == -1 && !no_acl_syscall_error(errno))
+ DEBUG(1,("store_inheritance_attribute: Error %s\n", strerror(errno) ));
+}
+
+/************************************************************************
+ Delete the in memory inheritance info.
+************************************************************************/
+
+static void free_inherited_info(struct pai_val *pal)
+{
+ if (pal) {
+ struct pai_entry *paie, *paie_next;
+ for (paie = pal->entry_list; paie; paie = paie_next) {
+ paie_next = paie->next;
+ SAFE_FREE(paie);
+ }
+ for (paie = pal->def_entry_list; paie; paie = paie_next) {
+ paie_next = paie->next;
+ SAFE_FREE(paie);
+ }
+ SAFE_FREE(pal);
+ }
+}
+
+/************************************************************************
+ Was this ACL protected ?
+************************************************************************/
+
+static bool get_protected_flag(struct pai_val *pal)
+{
+ if (!pal)
+ return False;
+ return pal->pai_protected;
+}
+
+/************************************************************************
+ Was this ACE inherited ?
+************************************************************************/
+
+static bool get_inherited_flag(struct pai_val *pal, canon_ace *ace_entry, bool default_ace)
+{
+ struct pai_entry *paie;
+
+ if (!pal)
+ return False;
+
+ /* If the entry exists it is inherited. */
+ for (paie = (default_ace ? pal->def_entry_list : pal->entry_list); paie; paie = paie->next) {
+ if (ace_entry->owner_type == paie->owner_type &&
+ get_entry_val(ace_entry) == get_pai_entry_val(paie))
+ return True;
+ }
+ return False;
+}
+
+/************************************************************************
+ Ensure an attribute just read is valid.
+************************************************************************/
+
+static bool check_pai_ok(char *pai_buf, size_t pai_buf_data_size)
+{
+ uint16 num_entries;
+ uint16 num_def_entries;
+
+ if (pai_buf_data_size < PAI_ENTRIES_BASE) {
+ /* Corrupted - too small. */
+ return False;
+ }
+
+ if (CVAL(pai_buf,PAI_VERSION_OFFSET) != PAI_VERSION)
+ return False;
+
+ num_entries = SVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET);
+ num_def_entries = SVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET);
+
+ /* Check the entry lists match. */
+ /* Each entry is 5 bytes (type plus 4 bytes of uid or gid). */
+
+ if (((num_entries + num_def_entries)*PAI_ENTRY_LENGTH) + PAI_ENTRIES_BASE != pai_buf_data_size)
+ return False;
+
+ return True;
+}
+
+
+/************************************************************************
+ Convert to in-memory format.
+************************************************************************/
+
+static struct pai_val *create_pai_val(char *buf, size_t size)
+{
+ char *entry_offset;
+ struct pai_val *paiv = NULL;
+ int i;
+
+ if (!check_pai_ok(buf, size))
+ return NULL;
+
+ paiv = SMB_MALLOC_P(struct pai_val);
+ if (!paiv)
+ return NULL;
+
+ memset(paiv, '\0', sizeof(struct pai_val));
+
+ paiv->pai_protected = (CVAL(buf,PAI_FLAG_OFFSET) == PAI_ACL_FLAG_PROTECTED);
+
+ paiv->num_entries = SVAL(buf,PAI_NUM_ENTRIES_OFFSET);
+ paiv->num_def_entries = SVAL(buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET);
+
+ entry_offset = buf + PAI_ENTRIES_BASE;
+
+ DEBUG(10,("create_pai_val:%s num_entries = %u, num_def_entries = %u\n",
+ paiv->pai_protected ? " (pai_protected)" : "", paiv->num_entries, paiv->num_def_entries ));
+
+ for (i = 0; i < paiv->num_entries; i++) {
+ struct pai_entry *paie;
+
+ paie = SMB_MALLOC_P(struct pai_entry);
+ if (!paie) {
+ free_inherited_info(paiv);
+ return NULL;
+ }
+
+ paie->owner_type = (enum ace_owner)CVAL(entry_offset,0);
+ switch( paie->owner_type) {
+ case UID_ACE:
+ paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1);
+ DEBUG(10,("create_pai_val: uid = %u\n", (unsigned int)paie->unix_ug.uid ));
+ break;
+ case GID_ACE:
+ paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1);
+ DEBUG(10,("create_pai_val: gid = %u\n", (unsigned int)paie->unix_ug.gid ));
+ break;
+ case WORLD_ACE:
+ paie->unix_ug.world = -1;
+ DEBUG(10,("create_pai_val: world ace\n"));
+ break;
+ default:
+ free_inherited_info(paiv);
+ return NULL;
+ }
+ entry_offset += PAI_ENTRY_LENGTH;
+ DLIST_ADD(paiv->entry_list, paie);
+ }
+
+ for (i = 0; i < paiv->num_def_entries; i++) {
+ struct pai_entry *paie;
+
+ paie = SMB_MALLOC_P(struct pai_entry);
+ if (!paie) {
+ free_inherited_info(paiv);
+ return NULL;
+ }
+
+ paie->owner_type = (enum ace_owner)CVAL(entry_offset,0);
+ switch( paie->owner_type) {
+ case UID_ACE:
+ paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1);
+ DEBUG(10,("create_pai_val: (def) uid = %u\n", (unsigned int)paie->unix_ug.uid ));
+ break;
+ case GID_ACE:
+ paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1);
+ DEBUG(10,("create_pai_val: (def) gid = %u\n", (unsigned int)paie->unix_ug.gid ));
+ break;
+ case WORLD_ACE:
+ paie->unix_ug.world = -1;
+ DEBUG(10,("create_pai_val: (def) world ace\n"));
+ break;
+ default:
+ free_inherited_info(paiv);
+ return NULL;
+ }
+ entry_offset += PAI_ENTRY_LENGTH;
+ DLIST_ADD(paiv->def_entry_list, paie);
+ }
+
+ return paiv;
+}
+
+/************************************************************************
+ Load the user.SAMBA_PAI attribute.
+************************************************************************/
+
+static struct pai_val *fload_inherited_info(files_struct *fsp)
+{
+ char *pai_buf;
+ size_t pai_buf_size = 1024;
+ struct pai_val *paiv = NULL;
+ ssize_t ret;
+
+ if (!lp_map_acl_inherit(SNUM(fsp->conn)))
+ return NULL;
+
+ if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL)
+ return NULL;
+
+ do {
+ if (fsp->fh->fd != -1)
+ ret = SMB_VFS_FGETXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME,
+ pai_buf, pai_buf_size);
+ else
+ ret = SMB_VFS_GETXATTR(fsp->conn,fsp->fsp_name,SAMBA_POSIX_INHERITANCE_EA_NAME,
+ pai_buf, pai_buf_size);
+
+ if (ret == -1) {
+ if (errno != ERANGE) {
+ break;
+ }
+ /* Buffer too small - enlarge it. */
+ pai_buf_size *= 2;
+ SAFE_FREE(pai_buf);
+ if (pai_buf_size > 1024*1024) {
+ return NULL; /* Limit malloc to 1mb. */
+ }
+ if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL)
+ return NULL;
+ }
+ } while (ret == -1);
+
+ DEBUG(10,("load_inherited_info: ret = %lu for file %s\n", (unsigned long)ret, fsp->fsp_name));
+
+ if (ret == -1) {
+ /* No attribute or not supported. */
+#if defined(ENOATTR)
+ if (errno != ENOATTR)
+ DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
+#else
+ if (errno != ENOSYS)
+ DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
+#endif
+ SAFE_FREE(pai_buf);
+ return NULL;
+ }
+
+ paiv = create_pai_val(pai_buf, ret);
+
+ if (paiv && paiv->pai_protected)
+ DEBUG(10,("load_inherited_info: ACL is protected for file %s\n", fsp->fsp_name));
+
+ SAFE_FREE(pai_buf);
+ return paiv;
+}
+
+/************************************************************************
+ Load the user.SAMBA_PAI attribute.
+************************************************************************/
+
+static struct pai_val *load_inherited_info(const struct connection_struct *conn,
+ const char *fname)
+{
+ char *pai_buf;
+ size_t pai_buf_size = 1024;
+ struct pai_val *paiv = NULL;
+ ssize_t ret;
+
+ if (!lp_map_acl_inherit(SNUM(conn))) {
+ return NULL;
+ }
+
+ if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL) {
+ return NULL;
+ }
+
+ do {
+ ret = SMB_VFS_GETXATTR(conn, fname,
+ SAMBA_POSIX_INHERITANCE_EA_NAME,
+ pai_buf, pai_buf_size);
+
+ if (ret == -1) {
+ if (errno != ERANGE) {
+ break;
+ }
+ /* Buffer too small - enlarge it. */
+ pai_buf_size *= 2;
+ SAFE_FREE(pai_buf);
+ if (pai_buf_size > 1024*1024) {
+ return NULL; /* Limit malloc to 1mb. */
+ }
+ if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL)
+ return NULL;
+ }
+ } while (ret == -1);
+
+ DEBUG(10,("load_inherited_info: ret = %lu for file %s\n", (unsigned long)ret, fname));
+
+ if (ret == -1) {
+ /* No attribute or not supported. */
+#if defined(ENOATTR)
+ if (errno != ENOATTR)
+ DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
+#else
+ if (errno != ENOSYS)
+ DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
+#endif
+ SAFE_FREE(pai_buf);
+ return NULL;
+ }
+
+ paiv = create_pai_val(pai_buf, ret);
+
+ if (paiv && paiv->pai_protected) {
+ DEBUG(10,("load_inherited_info: ACL is protected for file %s\n", fname));
+ }
+
+ SAFE_FREE(pai_buf);
+ return paiv;
+}
+
+/****************************************************************************
+ Functions to manipulate the internal ACE format.
+****************************************************************************/
+
+/****************************************************************************
+ Count a linked list of canonical ACE entries.
+****************************************************************************/
+
+static size_t count_canon_ace_list( canon_ace *list_head )
+{
+ size_t count = 0;
+ canon_ace *ace;
+
+ for (ace = list_head; ace; ace = ace->next)
+ count++;
+
+ return count;
+}
+
+/****************************************************************************
+ Free a linked list of canonical ACE entries.
+****************************************************************************/
+
+static void free_canon_ace_list( canon_ace *list_head )
+{
+ canon_ace *list, *next;
+
+ for (list = list_head; list; list = next) {
+ next = list->next;
+ DLIST_REMOVE(list_head, list);
+ SAFE_FREE(list);
+ }
+}
+
+/****************************************************************************
+ Function to duplicate a canon_ace entry.
+****************************************************************************/
+
+static canon_ace *dup_canon_ace( canon_ace *src_ace)
+{
+ canon_ace *dst_ace = SMB_MALLOC_P(canon_ace);
+
+ if (dst_ace == NULL)
+ return NULL;
+
+ *dst_ace = *src_ace;
+ dst_ace->prev = dst_ace->next = NULL;
+ return dst_ace;
+}
+
+/****************************************************************************
+ Print out a canon ace.
+****************************************************************************/
+
+static void print_canon_ace(canon_ace *pace, int num)
+{
+ dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" );
+ dbgtext( "SID = %s ", sid_string_dbg(&pace->trustee));
+ if (pace->owner_type == UID_ACE) {
+ const char *u_name = uidtoname(pace->unix_ug.uid);
+ dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name );
+ } else if (pace->owner_type == GID_ACE) {
+ char *g_name = gidtoname(pace->unix_ug.gid);
+ dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name );
+ } else
+ dbgtext( "other ");
+ switch (pace->type) {
+ case SMB_ACL_USER:
+ dbgtext( "SMB_ACL_USER ");
+ break;
+ case SMB_ACL_USER_OBJ:
+ dbgtext( "SMB_ACL_USER_OBJ ");
+ break;
+ case SMB_ACL_GROUP:
+ dbgtext( "SMB_ACL_GROUP ");
+ break;
+ case SMB_ACL_GROUP_OBJ:
+ dbgtext( "SMB_ACL_GROUP_OBJ ");
+ break;
+ case SMB_ACL_OTHER:
+ dbgtext( "SMB_ACL_OTHER ");
+ break;
+ default:
+ dbgtext( "MASK " );
+ break;
+ }
+ if (pace->inherited)
+ dbgtext( "(inherited) ");
+ dbgtext( "perms ");
+ dbgtext( "%c", pace->perms & S_IRUSR ? 'r' : '-');
+ dbgtext( "%c", pace->perms & S_IWUSR ? 'w' : '-');
+ dbgtext( "%c\n", pace->perms & S_IXUSR ? 'x' : '-');
+}
+
+/****************************************************************************
+ Print out a canon ace list.
+****************************************************************************/
+
+static void print_canon_ace_list(const char *name, canon_ace *ace_list)
+{
+ int count = 0;
+
+ if( DEBUGLVL( 10 )) {
+ dbgtext( "print_canon_ace_list: %s\n", name );
+ for (;ace_list; ace_list = ace_list->next, count++)
+ print_canon_ace(ace_list, count );
+ }
+}
+
+/****************************************************************************
+ Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
+****************************************************************************/
+
+static mode_t convert_permset_to_mode_t(connection_struct *conn, SMB_ACL_PERMSET_T permset)
+{
+ mode_t ret = 0;
+
+ ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRUSR : 0);
+ ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
+ ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
+
+ return ret;
+}
+
+/****************************************************************************
+ Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
+****************************************************************************/
+
+static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
+{
+ mode_t ret = 0;
+
+ if (mode & r_mask)
+ ret |= S_IRUSR;
+ if (mode & w_mask)
+ ret |= S_IWUSR;
+ if (mode & x_mask)
+ ret |= S_IXUSR;
+
+ return ret;
+}
+
+/****************************************************************************
+ Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
+ an SMB_ACL_PERMSET_T.
+****************************************************************************/
+
+static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_ACL_PERMSET_T *p_permset)
+{
+ if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) == -1)
+ return -1;
+ if (mode & S_IRUSR) {
+ if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1)
+ return -1;
+ }
+ if (mode & S_IWUSR) {
+ if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1)
+ return -1;
+ }
+ if (mode & S_IXUSR) {
+ if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1)
+ return -1;
+ }
+ return 0;
+}
+
+/****************************************************************************
+ Function to create owner and group SIDs from a SMB_STRUCT_STAT.
+****************************************************************************/
+
+static void create_file_sids(const SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
+{
+ uid_to_sid( powner_sid, psbuf->st_uid );
+ gid_to_sid( pgroup_sid, psbuf->st_gid );
+}
+
+/****************************************************************************
+ Is the identity in two ACEs equal ? Check both SID and uid/gid.
+****************************************************************************/
+
+static bool identity_in_ace_equal(canon_ace *ace1, canon_ace *ace2)
+{
+ if (sid_equal(&ace1->trustee, &ace2->trustee)) {
+ return True;
+ }
+ if (ace1->owner_type == ace2->owner_type) {
+ if (ace1->owner_type == UID_ACE &&
+ ace1->unix_ug.uid == ace2->unix_ug.uid) {
+ return True;
+ } else if (ace1->owner_type == GID_ACE &&
+ ace1->unix_ug.gid == ace2->unix_ug.gid) {
+ return True;
+ }
+ }
+ return False;
+}
+
+/****************************************************************************
+ Merge aces with a common sid - if both are allow or deny, OR the permissions together and
+ delete the second one. If the first is deny, mask the permissions off and delete the allow
+ if the permissions become zero, delete the deny if the permissions are non zero.
+****************************************************************************/
+
+static void merge_aces( canon_ace **pp_list_head )
+{
+ canon_ace *list_head = *pp_list_head;
+ canon_ace *curr_ace_outer;
+ canon_ace *curr_ace_outer_next;
+
+ /*
+ * First, merge allow entries with identical SIDs, and deny entries
+ * with identical SIDs.
+ */
+
+ for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
+ canon_ace *curr_ace;
+ canon_ace *curr_ace_next;
+
+ curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
+
+ for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
+
+ curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
+
+ if (identity_in_ace_equal(curr_ace, curr_ace_outer) &&
+ (curr_ace->attr == curr_ace_outer->attr)) {
+
+ if( DEBUGLVL( 10 )) {
+ dbgtext("merge_aces: Merging ACE's\n");
+ print_canon_ace( curr_ace_outer, 0);
+ print_canon_ace( curr_ace, 0);
+ }
+
+ /* Merge two allow or two deny ACE's. */
+
+ curr_ace_outer->perms |= curr_ace->perms;
+ DLIST_REMOVE(list_head, curr_ace);
+ SAFE_FREE(curr_ace);
+ curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
+ }
+ }
+ }
+
+ /*
+ * Now go through and mask off allow permissions with deny permissions.
+ * We can delete either the allow or deny here as we know that each SID
+ * appears only once in the list.
+ */
+
+ for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
+ canon_ace *curr_ace;
+ canon_ace *curr_ace_next;
+
+ curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
+
+ for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
+
+ curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
+
+ /*
+ * Subtract ACE's with different entries. Due to the ordering constraints
+ * we've put on the ACL, we know the deny must be the first one.
+ */
+
+ if (identity_in_ace_equal(curr_ace, curr_ace_outer) &&
+ (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
+
+ if( DEBUGLVL( 10 )) {
+ dbgtext("merge_aces: Masking ACE's\n");
+ print_canon_ace( curr_ace_outer, 0);
+ print_canon_ace( curr_ace, 0);
+ }
+
+ curr_ace->perms &= ~curr_ace_outer->perms;
+
+ if (curr_ace->perms == 0) {
+
+ /*
+ * The deny overrides the allow. Remove the allow.
+ */
+
+ DLIST_REMOVE(list_head, curr_ace);
+ SAFE_FREE(curr_ace);
+ curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
+
+ } else {
+
+ /*
+ * Even after removing permissions, there
+ * are still allow permissions - delete the deny.
+ * It is safe to delete the deny here,
+ * as we are guarenteed by the deny first
+ * ordering that all the deny entries for
+ * this SID have already been merged into one
+ * before we can get to an allow ace.
+ */
+
+ DLIST_REMOVE(list_head, curr_ace_outer);
+ SAFE_FREE(curr_ace_outer);
+ break;
+ }
+ }
+
+ } /* end for curr_ace */
+ } /* end for curr_ace_outer */
+
+ /* We may have modified the list. */
+
+ *pp_list_head = list_head;
+}
+
+/****************************************************************************
+ Check if we need to return NT4.x compatible ACL entries.
+****************************************************************************/
+
+static bool nt4_compatible_acls(void)
+{
+ int compat = lp_acl_compatibility();
+
+ if (compat == ACL_COMPAT_AUTO) {
+ enum remote_arch_types ra_type = get_remote_arch();
+
+ /* Automatically adapt to client */
+ return (ra_type <= RA_WINNT);
+ } else
+ return (compat == ACL_COMPAT_WINNT);
+}
+
+
+/****************************************************************************
+ Map canon_ace perms to permission bits NT.
+ The attr element is not used here - we only process deny entries on set,
+ not get. Deny entries are implicit on get with ace->perms = 0.
+****************************************************************************/
+
+static SEC_ACCESS map_canon_ace_perms(int snum,
+ enum security_ace_type *pacl_type,
+ mode_t perms,
+ bool directory_ace)
+{
+ SEC_ACCESS sa;
+ uint32 nt_mask = 0;
+
+ *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+
+ if (lp_acl_map_full_control(snum) && ((perms & ALL_ACE_PERMS) == ALL_ACE_PERMS)) {
+ if (directory_ace) {
+ nt_mask = UNIX_DIRECTORY_ACCESS_RWX;
+ } else {
+ nt_mask = (UNIX_ACCESS_RWX & ~DELETE_ACCESS);
+ }
+ } else if ((perms & ALL_ACE_PERMS) == (mode_t)0) {
+ /*
+ * Windows NT refuses to display ACEs with no permissions in them (but
+ * they are perfectly legal with Windows 2000). If the ACE has empty
+ * permissions we cannot use 0, so we use the otherwise unused
+ * WRITE_OWNER permission, which we ignore when we set an ACL.
+ * We abstract this into a #define of UNIX_ACCESS_NONE to allow this
+ * to be changed in the future.
+ */
+
+ if (nt4_compatible_acls())
+ nt_mask = UNIX_ACCESS_NONE;
+ else
+ nt_mask = 0;
+ } else {
+ if (directory_ace) {
+ nt_mask |= ((perms & S_IRUSR) ? UNIX_DIRECTORY_ACCESS_R : 0 );
+ nt_mask |= ((perms & S_IWUSR) ? UNIX_DIRECTORY_ACCESS_W : 0 );
+ nt_mask |= ((perms & S_IXUSR) ? UNIX_DIRECTORY_ACCESS_X : 0 );
+ } else {
+ nt_mask |= ((perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
+ nt_mask |= ((perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
+ nt_mask |= ((perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
+ }
+ }
+
+ DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
+ (unsigned int)perms, (unsigned int)nt_mask ));
+
+ init_sec_access(&sa,nt_mask);
+ return sa;
+}
+
+/****************************************************************************
+ Map NT perms to a UNIX mode_t.
+****************************************************************************/
+
+#define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
+#define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
+#define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
+
+static mode_t map_nt_perms( uint32 *mask, int type)
+{
+ mode_t mode = 0;
+
+ switch(type) {
+ case S_IRUSR:
+ if((*mask) & GENERIC_ALL_ACCESS)
+ mode = S_IRUSR|S_IWUSR|S_IXUSR;
+ else {
+ mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
+ mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
+ mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
+ }
+ break;
+ case S_IRGRP:
+ if((*mask) & GENERIC_ALL_ACCESS)
+ mode = S_IRGRP|S_IWGRP|S_IXGRP;
+ else {
+ mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
+ mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
+ mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
+ }
+ break;
+ case S_IROTH:
+ if((*mask) & GENERIC_ALL_ACCESS)
+ mode = S_IROTH|S_IWOTH|S_IXOTH;
+ else {
+ mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
+ mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
+ mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
+ }
+ break;
+ }
+
+ return mode;
+}
+
+/****************************************************************************
+ Unpack a SEC_DESC into a UNIX owner and group.
+****************************************************************************/
+
+NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
+{
+ DOM_SID owner_sid;
+ DOM_SID grp_sid;
+
+ *puser = (uid_t)-1;
+ *pgrp = (gid_t)-1;
+
+ if(security_info_sent == 0) {
+ DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * Validate the owner and group SID's.
+ */
+
+ memset(&owner_sid, '\0', sizeof(owner_sid));
+ memset(&grp_sid, '\0', sizeof(grp_sid));
+
+ DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
+
+ /*
+ * Don't immediately fail if the owner sid cannot be validated.
+ * This may be a group chown only set.
+ */
+
+ if (security_info_sent & OWNER_SECURITY_INFORMATION) {
+ sid_copy(&owner_sid, psd->owner_sid);
+ if (!sid_to_uid(&owner_sid, puser)) {
+ if (lp_force_unknown_acl_user(snum)) {
+ /* this allows take ownership to work
+ * reasonably */
+ *puser = current_user.ut.uid;
+ } else {
+ DEBUG(3,("unpack_nt_owners: unable to validate"
+ " owner sid for %s\n",
+ sid_string_dbg(&owner_sid)));
+ return NT_STATUS_INVALID_OWNER;
+ }
+ }
+ DEBUG(3,("unpack_nt_owners: owner sid mapped to uid %u\n",
+ (unsigned int)*puser ));
+ }
+
+ /*
+ * Don't immediately fail if the group sid cannot be validated.
+ * This may be an owner chown only set.
+ */
+
+ if (security_info_sent & GROUP_SECURITY_INFORMATION) {
+ sid_copy(&grp_sid, psd->group_sid);
+ if (!sid_to_gid( &grp_sid, pgrp)) {
+ if (lp_force_unknown_acl_user(snum)) {
+ /* this allows take group ownership to work
+ * reasonably */
+ *pgrp = current_user.ut.gid;
+ } else {
+ DEBUG(3,("unpack_nt_owners: unable to validate"
+ " group sid.\n"));
+ return NT_STATUS_INVALID_OWNER;
+ }
+ }
+ DEBUG(3,("unpack_nt_owners: group sid mapped to gid %u\n",
+ (unsigned int)*pgrp));
+ }
+
+ DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Ensure the enforced permissions for this share apply.
+****************************************************************************/
+
+static void apply_default_perms(const struct share_params *params,
+ const bool is_directory, canon_ace *pace,
+ mode_t type)
+{
+ mode_t and_bits = (mode_t)0;
+ mode_t or_bits = (mode_t)0;
+
+ /* Get the initial bits to apply. */
+
+ if (is_directory) {
+ and_bits = lp_dir_security_mask(params->service);
+ or_bits = lp_force_dir_security_mode(params->service);
+ } else {
+ and_bits = lp_security_mask(params->service);
+ or_bits = lp_force_security_mode(params->service);
+ }
+
+ /* Now bounce them into the S_USR space. */
+ switch(type) {
+ case S_IRUSR:
+ /* Ensure owner has read access. */
+ pace->perms |= S_IRUSR;
+ if (is_directory)
+ pace->perms |= (S_IWUSR|S_IXUSR);
+ and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR);
+ or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR);
+ break;
+ case S_IRGRP:
+ and_bits = unix_perms_to_acl_perms(and_bits, S_IRGRP, S_IWGRP, S_IXGRP);
+ or_bits = unix_perms_to_acl_perms(or_bits, S_IRGRP, S_IWGRP, S_IXGRP);
+ break;
+ case S_IROTH:
+ and_bits = unix_perms_to_acl_perms(and_bits, S_IROTH, S_IWOTH, S_IXOTH);
+ or_bits = unix_perms_to_acl_perms(or_bits, S_IROTH, S_IWOTH, S_IXOTH);
+ break;
+ }
+
+ pace->perms = ((pace->perms & and_bits)|or_bits);
+}
+
+/****************************************************************************
+ Check if a given uid/SID is in a group gid/SID. This is probably very
+ expensive and will need optimisation. A *lot* of optimisation :-). JRA.
+****************************************************************************/
+
+static bool uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
+{
+ const char *u_name = NULL;
+
+ /* "Everyone" always matches every uid. */
+
+ if (sid_equal(&group_ace->trustee, &global_sid_World))
+ return True;
+
+ /* Assume that the current user is in the current group (force group) */
+
+ if (uid_ace->unix_ug.uid == current_user.ut.uid && group_ace->unix_ug.gid == current_user.ut.gid)
+ return True;
+
+ /* u_name talloc'ed off tos. */
+ u_name = uidtoname(uid_ace->unix_ug.uid);
+ if (!u_name) {
+ return False;
+ }
+ return user_in_group_sid(u_name, &group_ace->trustee);
+}
+
+/****************************************************************************
+ A well formed POSIX file or default ACL has at least 3 entries, a
+ SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
+ In addition, the owner must always have at least read access.
+ When using this call on get_acl, the pst struct is valid and contains
+ the mode of the file. When using this call on set_acl, the pst struct has
+ been modified to have a mode containing the default for this file or directory
+ type.
+****************************************************************************/
+
+static bool ensure_canon_entry_valid(canon_ace **pp_ace,
+ const struct share_params *params,
+ const bool is_directory,
+ const DOM_SID *pfile_owner_sid,
+ const DOM_SID *pfile_grp_sid,
+ const SMB_STRUCT_STAT *pst,
+ bool setting_acl)
+{
+ canon_ace *pace;
+ bool got_user = False;
+ bool got_grp = False;
+ bool got_other = False;
+ canon_ace *pace_other = NULL;
+
+ for (pace = *pp_ace; pace; pace = pace->next) {
+ if (pace->type == SMB_ACL_USER_OBJ) {
+
+ if (setting_acl)
+ apply_default_perms(params, is_directory, pace, S_IRUSR);
+ got_user = True;
+
+ } else if (pace->type == SMB_ACL_GROUP_OBJ) {
+
+ /*
+ * Ensure create mask/force create mode is respected on set.
+ */
+
+ if (setting_acl)
+ apply_default_perms(params, is_directory, pace, S_IRGRP);
+ got_grp = True;
+
+ } else if (pace->type == SMB_ACL_OTHER) {
+
+ /*
+ * Ensure create mask/force create mode is respected on set.
+ */
+
+ if (setting_acl)
+ apply_default_perms(params, is_directory, pace, S_IROTH);
+ got_other = True;
+ pace_other = pace;
+ }
+ }
+
+ if (!got_user) {
+ if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
+ DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(pace);
+ pace->type = SMB_ACL_USER_OBJ;
+ pace->owner_type = UID_ACE;
+ pace->unix_ug.uid = pst->st_uid;
+ pace->trustee = *pfile_owner_sid;
+ pace->attr = ALLOW_ACE;
+
+ if (setting_acl) {
+ /* See if the owning user is in any of the other groups in
+ the ACE. If so, OR in the permissions from that group. */
+
+ bool group_matched = False;
+ canon_ace *pace_iter;
+
+ for (pace_iter = *pp_ace; pace_iter; pace_iter = pace_iter->next) {
+ if (pace_iter->type == SMB_ACL_GROUP_OBJ || pace_iter->type == SMB_ACL_GROUP) {
+ if (uid_entry_in_group(pace, pace_iter)) {
+ pace->perms |= pace_iter->perms;
+ group_matched = True;
+ }
+ }
+ }
+
+ /* If we only got an "everyone" perm, just use that. */
+ if (!group_matched) {
+ if (got_other)
+ pace->perms = pace_other->perms;
+ else
+ pace->perms = 0;
+ }
+
+ apply_default_perms(params, is_directory, pace, S_IRUSR);
+ } else {
+ pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
+ }
+
+ DLIST_ADD(*pp_ace, pace);
+ }
+
+ if (!got_grp) {
+ if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
+ DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(pace);
+ pace->type = SMB_ACL_GROUP_OBJ;
+ pace->owner_type = GID_ACE;
+ pace->unix_ug.uid = pst->st_gid;
+ pace->trustee = *pfile_grp_sid;
+ pace->attr = ALLOW_ACE;
+ if (setting_acl) {
+ /* If we only got an "everyone" perm, just use that. */
+ if (got_other)
+ pace->perms = pace_other->perms;
+ else
+ pace->perms = 0;
+ apply_default_perms(params, is_directory, pace, S_IRGRP);
+ } else {
+ pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
+ }
+
+ DLIST_ADD(*pp_ace, pace);
+ }
+
+ if (!got_other) {
+ if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
+ DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(pace);
+ pace->type = SMB_ACL_OTHER;
+ pace->owner_type = WORLD_ACE;
+ pace->unix_ug.world = -1;
+ pace->trustee = global_sid_World;
+ pace->attr = ALLOW_ACE;
+ if (setting_acl) {
+ pace->perms = 0;
+ apply_default_perms(params, is_directory, pace, S_IROTH);
+ } else
+ pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
+
+ DLIST_ADD(*pp_ace, pace);
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
+ If it does not have them, check if there are any entries where the trustee is the
+ file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
+****************************************************************************/
+
+static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid)
+{
+ bool got_user_obj, got_group_obj;
+ canon_ace *current_ace;
+ int i, entries;
+
+ entries = count_canon_ace_list(ace);
+ got_user_obj = False;
+ got_group_obj = False;
+
+ for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
+ if (current_ace->type == SMB_ACL_USER_OBJ)
+ got_user_obj = True;
+ else if (current_ace->type == SMB_ACL_GROUP_OBJ)
+ got_group_obj = True;
+ }
+ if (got_user_obj && got_group_obj) {
+ DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
+ return;
+ }
+
+ for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
+ if (!got_user_obj && current_ace->owner_type == UID_ACE &&
+ sid_equal(&current_ace->trustee, pfile_owner_sid)) {
+ current_ace->type = SMB_ACL_USER_OBJ;
+ got_user_obj = True;
+ }
+ if (!got_group_obj && current_ace->owner_type == GID_ACE &&
+ sid_equal(&current_ace->trustee, pfile_grp_sid)) {
+ current_ace->type = SMB_ACL_GROUP_OBJ;
+ got_group_obj = True;
+ }
+ }
+ if (!got_user_obj)
+ DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
+ if (!got_group_obj)
+ DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
+}
+
+/****************************************************************************
+ Unpack a SEC_DESC into two canonical ace lists.
+****************************************************************************/
+
+static bool create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst,
+ DOM_SID *pfile_owner_sid,
+ DOM_SID *pfile_grp_sid,
+ canon_ace **ppfile_ace, canon_ace **ppdir_ace,
+ SEC_ACL *dacl)
+{
+ bool all_aces_are_inherit_only = (fsp->is_directory ? True : False);
+ canon_ace *file_ace = NULL;
+ canon_ace *dir_ace = NULL;
+ canon_ace *current_ace = NULL;
+ bool got_dir_allow = False;
+ bool got_file_allow = False;
+ int i, j;
+
+ *ppfile_ace = NULL;
+ *ppdir_ace = NULL;
+
+ /*
+ * Convert the incoming ACL into a more regular form.
+ */
+
+ for(i = 0; i < dacl->num_aces; i++) {
+ SEC_ACE *psa = &dacl->aces[i];
+
+ if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
+ DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
+ return False;
+ }
+
+ if (nt4_compatible_acls()) {
+ /*
+ * The security mask may be UNIX_ACCESS_NONE which should map into
+ * no permissions (we overload the WRITE_OWNER bit for this) or it
+ * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
+ * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
+ */
+
+ /*
+ * Convert GENERIC bits to specific bits.
+ */
+
+ se_map_generic(&psa->access_mask, &file_generic_mapping);
+
+ psa->access_mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
+
+ if(psa->access_mask != UNIX_ACCESS_NONE)
+ psa->access_mask &= ~UNIX_ACCESS_NONE;
+ }
+ }
+
+ /*
+ * Deal with the fact that NT 4.x re-writes the canonical format
+ * that we return for default ACLs. If a directory ACE is identical
+ * to a inherited directory ACE then NT changes the bits so that the
+ * first ACE is set to OI|IO and the second ACE for this SID is set
+ * to CI. We need to repair this. JRA.
+ */
+
+ for(i = 0; i < dacl->num_aces; i++) {
+ SEC_ACE *psa1 = &dacl->aces[i];
+
+ for (j = i + 1; j < dacl->num_aces; j++) {
+ SEC_ACE *psa2 = &dacl->aces[j];
+
+ if (psa1->access_mask != psa2->access_mask)
+ continue;
+
+ if (!sid_equal(&psa1->trustee, &psa2->trustee))
+ continue;
+
+ /*
+ * Ok - permission bits and SIDs are equal.
+ * Check if flags were re-written.
+ */
+
+ if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+
+ psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
+ psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
+
+ } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+
+ psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
+ psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
+
+ }
+ }
+ }
+
+ for(i = 0; i < dacl->num_aces; i++) {
+ SEC_ACE *psa = &dacl->aces[i];
+
+ /*
+ * Create a cannon_ace entry representing this NT DACL ACE.
+ */
+
+ if ((current_ace = SMB_MALLOC_P(canon_ace)) == NULL) {
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(current_ace);
+
+ sid_copy(&current_ace->trustee, &psa->trustee);
+
+ /*
+ * Try and work out if the SID is a user or group
+ * as we need to flag these differently for POSIX.
+ * Note what kind of a POSIX ACL this should map to.
+ */
+
+ if( sid_equal(&current_ace->trustee, &global_sid_World)) {
+ current_ace->owner_type = WORLD_ACE;
+ current_ace->unix_ug.world = -1;
+ current_ace->type = SMB_ACL_OTHER;
+ } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Owner)) {
+ current_ace->owner_type = UID_ACE;
+ current_ace->unix_ug.uid = pst->st_uid;
+ current_ace->type = SMB_ACL_USER_OBJ;
+
+ /*
+ * The Creator Owner entry only specifies inheritable permissions,
+ * never access permissions. WinNT doesn't always set the ACE to
+ *INHERIT_ONLY, though.
+ */
+
+ if (nt4_compatible_acls())
+ psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+ } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Group)) {
+ current_ace->owner_type = GID_ACE;
+ current_ace->unix_ug.gid = pst->st_gid;
+ current_ace->type = SMB_ACL_GROUP_OBJ;
+
+ /*
+ * The Creator Group entry only specifies inheritable permissions,
+ * never access permissions. WinNT doesn't always set the ACE to
+ *INHERIT_ONLY, though.
+ */
+ if (nt4_compatible_acls())
+ psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+
+ } else if (sid_to_uid( &current_ace->trustee, &current_ace->unix_ug.uid)) {
+ current_ace->owner_type = UID_ACE;
+ /* If it's the owning user, this is a user_obj, not
+ * a user. */
+ if (current_ace->unix_ug.uid == pst->st_uid) {
+ current_ace->type = SMB_ACL_USER_OBJ;
+ } else {
+ current_ace->type = SMB_ACL_USER;
+ }
+ } else if (sid_to_gid( &current_ace->trustee, &current_ace->unix_ug.gid)) {
+ current_ace->owner_type = GID_ACE;
+ /* If it's the primary group, this is a group_obj, not
+ * a group. */
+ if (current_ace->unix_ug.gid == pst->st_gid) {
+ current_ace->type = SMB_ACL_GROUP_OBJ;
+ } else {
+ current_ace->type = SMB_ACL_GROUP;
+ }
+ } else {
+ /*
+ * Silently ignore map failures in non-mappable SIDs (NT Authority, BUILTIN etc).
+ */
+
+ if (non_mappable_sid(&psa->trustee)) {
+ DEBUG(10, ("create_canon_ace_lists: ignoring "
+ "non-mappable SID %s\n",
+ sid_string_dbg(&psa->trustee)));
+ SAFE_FREE(current_ace);
+ continue;
+ }
+
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ DEBUG(0, ("create_canon_ace_lists: unable to map SID "
+ "%s to uid or gid.\n",
+ sid_string_dbg(&current_ace->trustee)));
+ SAFE_FREE(current_ace);
+ return False;
+ }
+
+ /*
+ * Map the given NT permissions into a UNIX mode_t containing only
+ * S_I(R|W|X)USR bits.
+ */
+
+ current_ace->perms |= map_nt_perms( &psa->access_mask, S_IRUSR);
+ current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
+ current_ace->inherited = ((psa->flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False);
+
+ /*
+ * Now add the created ace to either the file list, the directory
+ * list, or both. We *MUST* preserve the order here (hence we use
+ * DLIST_ADD_END) as NT ACLs are order dependent.
+ */
+
+ if (fsp->is_directory) {
+
+ /*
+ * We can only add to the default POSIX ACE list if the ACE is
+ * designed to be inherited by both files and directories.
+ */
+
+ if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
+ (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
+
+ DLIST_ADD_END(dir_ace, current_ace, canon_ace *);
+
+ /*
+ * Note if this was an allow ace. We can't process
+ * any further deny ace's after this.
+ */
+
+ if (current_ace->attr == ALLOW_ACE)
+ got_dir_allow = True;
+
+ if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
+ DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \
+Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ return False;
+ }
+
+ if( DEBUGLVL( 10 )) {
+ dbgtext("create_canon_ace_lists: adding dir ACL:\n");
+ print_canon_ace( current_ace, 0);
+ }
+
+ /*
+ * If this is not an inherit only ACE we need to add a duplicate
+ * to the file acl.
+ */
+
+ if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
+ canon_ace *dup_ace = dup_canon_ace(current_ace);
+
+ if (!dup_ace) {
+ DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ return False;
+ }
+
+ /*
+ * We must not free current_ace here as its
+ * pointer is now owned by the dir_ace list.
+ */
+ current_ace = dup_ace;
+ } else {
+ /*
+ * We must not free current_ace here as its
+ * pointer is now owned by the dir_ace list.
+ */
+ current_ace = NULL;
+ }
+ }
+ }
+
+ /*
+ * Only add to the file ACL if not inherit only.
+ */
+
+ if (current_ace && !(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
+ DLIST_ADD_END(file_ace, current_ace, canon_ace *);
+
+ /*
+ * Note if this was an allow ace. We can't process
+ * any further deny ace's after this.
+ */
+
+ if (current_ace->attr == ALLOW_ACE)
+ got_file_allow = True;
+
+ if ((current_ace->attr == DENY_ACE) && got_file_allow) {
+ DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \
+Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ return False;
+ }
+
+ if( DEBUGLVL( 10 )) {
+ dbgtext("create_canon_ace_lists: adding file ACL:\n");
+ print_canon_ace( current_ace, 0);
+ }
+ all_aces_are_inherit_only = False;
+ /*
+ * We must not free current_ace here as its
+ * pointer is now owned by the file_ace list.
+ */
+ current_ace = NULL;
+ }
+
+ /*
+ * Free if ACE was not added.
+ */
+
+ SAFE_FREE(current_ace);
+ }
+
+ if (fsp->is_directory && all_aces_are_inherit_only) {
+ /*
+ * Windows 2000 is doing one of these weird 'inherit acl'
+ * traverses to conserve NTFS ACL resources. Just pretend
+ * there was no DACL sent. JRA.
+ */
+
+ DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ file_ace = NULL;
+ dir_ace = NULL;
+ } else {
+ /*
+ * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each
+ * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
+ * entries can be converted to *_OBJ. Usually we will already have these
+ * entries in the Default ACL, and the Access ACL will not have them.
+ */
+ if (file_ace) {
+ check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
+ }
+ if (dir_ace) {
+ check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);
+ }
+ }
+
+ *ppfile_ace = file_ace;
+ *ppdir_ace = dir_ace;
+
+ return True;
+}
+
+/****************************************************************************
+ ASCII art time again... JRA :-).
+
+ We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
+ we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
+ entries). Secondly, the merge code has ensured that all duplicate SID entries for
+ allow or deny have been merged, so the same SID can only appear once in the deny
+ list or once in the allow list.
+
+ We then process as follows :
+
+ ---------------------------------------------------------------------------
+ First pass - look for a Everyone DENY entry.
+
+ If it is deny all (rwx) trunate the list at this point.
+ Else, walk the list from this point and use the deny permissions of this
+ entry as a mask on all following allow entries. Finally, delete
+ the Everyone DENY entry (we have applied it to everything possible).
+
+ In addition, in this pass we remove any DENY entries that have
+ no permissions (ie. they are a DENY nothing).
+ ---------------------------------------------------------------------------
+ Second pass - only deal with deny user entries.
+
+ DENY user1 (perms XXX)
+
+ new_perms = 0
+ for all following allow group entries where user1 is in group
+ new_perms |= group_perms;
+
+ user1 entry perms = new_perms & ~ XXX;
+
+ Convert the deny entry to an allow entry with the new perms and
+ push to the end of the list. Note if the user was in no groups
+ this maps to a specific allow nothing entry for this user.
+
+ The common case from the NT ACL choser (userX deny all) is
+ optimised so we don't do the group lookup - we just map to
+ an allow nothing entry.
+
+ What we're doing here is inferring the allow permissions the
+ person setting the ACE on user1 wanted by looking at the allow
+ permissions on the groups the user is currently in. This will
+ be a snapshot, depending on group membership but is the best
+ we can do and has the advantage of failing closed rather than
+ open.
+ ---------------------------------------------------------------------------
+ Third pass - only deal with deny group entries.
+
+ DENY group1 (perms XXX)
+
+ for all following allow user entries where user is in group1
+ user entry perms = user entry perms & ~ XXX;
+
+ If there is a group Everyone allow entry with permissions YYY,
+ convert the group1 entry to an allow entry and modify its
+ permissions to be :
+
+ new_perms = YYY & ~ XXX
+
+ and push to the end of the list.
+
+ If there is no group Everyone allow entry then convert the
+ group1 entry to a allow nothing entry and push to the end of the list.
+
+ Note that the common case from the NT ACL choser (groupX deny all)
+ cannot be optimised here as we need to modify user entries who are
+ in the group to change them to a deny all also.
+
+ What we're doing here is modifying the allow permissions of
+ user entries (which are more specific in POSIX ACLs) to mask
+ out the explicit deny set on the group they are in. This will
+ be a snapshot depending on current group membership but is the
+ best we can do and has the advantage of failing closed rather
+ than open.
+ ---------------------------------------------------------------------------
+ Fourth pass - cope with cumulative permissions.
+
+ for all allow user entries, if there exists an allow group entry with
+ more permissive permissions, and the user is in that group, rewrite the
+ allow user permissions to contain both sets of permissions.
+
+ Currently the code for this is #ifdef'ed out as these semantics make
+ no sense to me. JRA.
+ ---------------------------------------------------------------------------
+
+ Note we *MUST* do the deny user pass first as this will convert deny user
+ entries into allow user entries which can then be processed by the deny
+ group pass.
+
+ The above algorithm took a *lot* of thinking about - hence this
+ explaination :-). JRA.
+****************************************************************************/
+
+/****************************************************************************
+ Process a canon_ace list entries. This is very complex code. We need
+ to go through and remove the "deny" permissions from any allow entry that matches
+ the id of this entry. We have already refused any NT ACL that wasn't in correct
+ order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
+ we just remove it (to fail safe). We have already removed any duplicate ace
+ entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
+ allow entries.
+****************************************************************************/
+
+static void process_deny_list( canon_ace **pp_ace_list )
+{
+ canon_ace *ace_list = *pp_ace_list;
+ canon_ace *curr_ace = NULL;
+ canon_ace *curr_ace_next = NULL;
+
+ /* Pass 1 above - look for an Everyone, deny entry. */
+
+ for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
+ canon_ace *allow_ace_p;
+
+ curr_ace_next = curr_ace->next; /* So we can't lose the link. */
+
+ if (curr_ace->attr != DENY_ACE)
+ continue;
+
+ if (curr_ace->perms == (mode_t)0) {
+
+ /* Deny nothing entry - delete. */
+
+ DLIST_REMOVE(ace_list, curr_ace);
+ continue;
+ }
+
+ if (!sid_equal(&curr_ace->trustee, &global_sid_World))
+ continue;
+
+ /* JRATEST - assert. */
+ SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);
+
+ if (curr_ace->perms == ALL_ACE_PERMS) {
+
+ /*
+ * Optimisation. This is a DENY_ALL to Everyone. Truncate the
+ * list at this point including this entry.
+ */
+
+ canon_ace *prev_entry = curr_ace->prev;
+
+ free_canon_ace_list( curr_ace );
+ if (prev_entry)
+ prev_entry->next = NULL;
+ else {
+ /* We deleted the entire list. */
+ ace_list = NULL;
+ }
+ break;
+ }
+
+ for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
+
+ /*
+ * Only mask off allow entries.
+ */
+
+ if (allow_ace_p->attr != ALLOW_ACE)
+ continue;
+
+ allow_ace_p->perms &= ~curr_ace->perms;
+ }
+
+ /*
+ * Now it's been applied, remove it.
+ */
+
+ DLIST_REMOVE(ace_list, curr_ace);
+ }
+
+ /* Pass 2 above - deal with deny user entries. */
+
+ for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
+ mode_t new_perms = (mode_t)0;
+ canon_ace *allow_ace_p;
+
+ curr_ace_next = curr_ace->next; /* So we can't lose the link. */
+
+ if (curr_ace->attr != DENY_ACE)
+ continue;
+
+ if (curr_ace->owner_type != UID_ACE)
+ continue;
+
+ if (curr_ace->perms == ALL_ACE_PERMS) {
+
+ /*
+ * Optimisation - this is a deny everything to this user.
+ * Convert to an allow nothing and push to the end of the list.
+ */
+
+ curr_ace->attr = ALLOW_ACE;
+ curr_ace->perms = (mode_t)0;
+ DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
+ continue;
+ }
+
+ for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
+
+ if (allow_ace_p->attr != ALLOW_ACE)
+ continue;
+
+ /* We process GID_ACE and WORLD_ACE entries only. */
+
+ if (allow_ace_p->owner_type == UID_ACE)
+ continue;
+
+ if (uid_entry_in_group( curr_ace, allow_ace_p))
+ new_perms |= allow_ace_p->perms;
+ }
+
+ /*
+ * Convert to a allow entry, modify the perms and push to the end
+ * of the list.
+ */
+
+ curr_ace->attr = ALLOW_ACE;
+ curr_ace->perms = (new_perms & ~curr_ace->perms);
+ DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
+ }
+
+ /* Pass 3 above - deal with deny group entries. */
+
+ for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
+ canon_ace *allow_ace_p;
+ canon_ace *allow_everyone_p = NULL;
+
+ curr_ace_next = curr_ace->next; /* So we can't lose the link. */
+
+ if (curr_ace->attr != DENY_ACE)
+ continue;
+
+ if (curr_ace->owner_type != GID_ACE)
+ continue;
+
+ for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
+
+ if (allow_ace_p->attr != ALLOW_ACE)
+ continue;
+
+ /* Store a pointer to the Everyone allow, if it exists. */
+ if (allow_ace_p->owner_type == WORLD_ACE)
+ allow_everyone_p = allow_ace_p;
+
+ /* We process UID_ACE entries only. */
+
+ if (allow_ace_p->owner_type != UID_ACE)
+ continue;
+
+ /* Mask off the deny group perms. */
+
+ if (uid_entry_in_group( allow_ace_p, curr_ace))
+ allow_ace_p->perms &= ~curr_ace->perms;
+ }
+
+ /*
+ * Convert the deny to an allow with the correct perms and
+ * push to the end of the list.
+ */
+
+ curr_ace->attr = ALLOW_ACE;
+ if (allow_everyone_p)
+ curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
+ else
+ curr_ace->perms = (mode_t)0;
+ DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
+ }
+
+ /* Doing this fourth pass allows Windows semantics to be layered
+ * on top of POSIX semantics. I'm not sure if this is desirable.
+ * For example, in W2K ACLs there is no way to say, "Group X no
+ * access, user Y full access" if user Y is a member of group X.
+ * This seems completely broken semantics to me.... JRA.
+ */
+
+#if 0
+ /* Pass 4 above - deal with allow entries. */
+
+ for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
+ canon_ace *allow_ace_p;
+
+ curr_ace_next = curr_ace->next; /* So we can't lose the link. */
+
+ if (curr_ace->attr != ALLOW_ACE)
+ continue;
+
+ if (curr_ace->owner_type != UID_ACE)
+ continue;
+
+ for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) {
+
+ if (allow_ace_p->attr != ALLOW_ACE)
+ continue;
+
+ /* We process GID_ACE entries only. */
+
+ if (allow_ace_p->owner_type != GID_ACE)
+ continue;
+
+ /* OR in the group perms. */
+
+ if (uid_entry_in_group( curr_ace, allow_ace_p))
+ curr_ace->perms |= allow_ace_p->perms;
+ }
+ }
+#endif
+
+ *pp_ace_list = ace_list;
+}
+
+/****************************************************************************
+ Create a default mode that will be used if a security descriptor entry has
+ no user/group/world entries.
+****************************************************************************/
+
+static mode_t create_default_mode(files_struct *fsp, bool interitable_mode)
+{
+ int snum = SNUM(fsp->conn);
+ mode_t and_bits = (mode_t)0;
+ mode_t or_bits = (mode_t)0;
+ mode_t mode = interitable_mode
+ ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name,
+ NULL )
+ : S_IRUSR;
+
+ if (fsp->is_directory)
+ mode |= (S_IWUSR|S_IXUSR);
+
+ /*
+ * Now AND with the create mode/directory mode bits then OR with the
+ * force create mode/force directory mode bits.
+ */
+
+ if (fsp->is_directory) {
+ and_bits = lp_dir_security_mask(snum);
+ or_bits = lp_force_dir_security_mode(snum);
+ } else {
+ and_bits = lp_security_mask(snum);
+ or_bits = lp_force_security_mode(snum);
+ }
+
+ return ((mode & and_bits)|or_bits);
+}
+
+/****************************************************************************
+ Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
+ succeeding.
+****************************************************************************/
+
+static bool unpack_canon_ace(files_struct *fsp,
+ SMB_STRUCT_STAT *pst,
+ DOM_SID *pfile_owner_sid,
+ DOM_SID *pfile_grp_sid,
+ canon_ace **ppfile_ace, canon_ace **ppdir_ace,
+ uint32 security_info_sent, SEC_DESC *psd)
+{
+ canon_ace *file_ace = NULL;
+ canon_ace *dir_ace = NULL;
+
+ *ppfile_ace = NULL;
+ *ppdir_ace = NULL;
+
+ if(security_info_sent == 0) {
+ DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
+ return False;
+ }
+
+ /*
+ * If no DACL then this is a chown only security descriptor.
+ */
+
+ if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
+ return True;
+
+ /*
+ * Now go through the DACL and create the canon_ace lists.
+ */
+
+ if (!create_canon_ace_lists( fsp, pst, pfile_owner_sid, pfile_grp_sid,
+ &file_ace, &dir_ace, psd->dacl))
+ return False;
+
+ if ((file_ace == NULL) && (dir_ace == NULL)) {
+ /* W2K traverse DACL set - ignore. */
+ return True;
+ }
+
+ /*
+ * Go through the canon_ace list and merge entries
+ * belonging to identical users of identical allow or deny type.
+ * We can do this as all deny entries come first, followed by
+ * all allow entries (we have mandated this before accepting this acl).
+ */
+
+ print_canon_ace_list( "file ace - before merge", file_ace);
+ merge_aces( &file_ace );
+
+ print_canon_ace_list( "dir ace - before merge", dir_ace);
+ merge_aces( &dir_ace );
+
+ /*
+ * NT ACLs are order dependent. Go through the acl lists and
+ * process DENY entries by masking the allow entries.
+ */
+
+ print_canon_ace_list( "file ace - before deny", file_ace);
+ process_deny_list( &file_ace);
+
+ print_canon_ace_list( "dir ace - before deny", dir_ace);
+ process_deny_list( &dir_ace);
+
+ /*
+ * A well formed POSIX file or default ACL has at least 3 entries, a
+ * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
+ * and optionally a mask entry. Ensure this is the case.
+ */
+
+ print_canon_ace_list( "file ace - before valid", file_ace);
+
+ /*
+ * A default 3 element mode entry for a file should be r-- --- ---.
+ * A default 3 element mode entry for a directory should be rwx --- ---.
+ */
+
+ pst->st_mode = create_default_mode(fsp, False);
+
+ if (!ensure_canon_entry_valid(&file_ace, fsp->conn->params, fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst, True)) {
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ return False;
+ }
+
+ print_canon_ace_list( "dir ace - before valid", dir_ace);
+
+ /*
+ * A default inheritable 3 element mode entry for a directory should be the
+ * mode Samba will use to create a file within. Ensure user rwx bits are set if
+ * it's a directory.
+ */
+
+ pst->st_mode = create_default_mode(fsp, True);
+
+ if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp->conn->params, fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst, True)) {
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ return False;
+ }
+
+ print_canon_ace_list( "file ace - return", file_ace);
+ print_canon_ace_list( "dir ace - return", dir_ace);
+
+ *ppfile_ace = file_ace;
+ *ppdir_ace = dir_ace;
+ return True;
+
+}
+
+/******************************************************************************
+ When returning permissions, try and fit NT display
+ semantics if possible. Note the the canon_entries here must have been malloced.
+ The list format should be - first entry = owner, followed by group and other user
+ entries, last entry = other.
+
+ Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
+ are not ordered, and match on the most specific entry rather than walking a list,
+ then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
+
+ Entry 0: owner : deny all except read and write.
+ Entry 1: owner : allow read and write.
+ Entry 2: group : deny all except read.
+ Entry 3: group : allow read.
+ Entry 4: Everyone : allow read.
+
+ But NT cannot display this in their ACL editor !
+********************************************************************************/
+
+static void arrange_posix_perms(const char *filename, canon_ace **pp_list_head)
+{
+ canon_ace *list_head = *pp_list_head;
+ canon_ace *owner_ace = NULL;
+ canon_ace *other_ace = NULL;
+ canon_ace *ace = NULL;
+
+ for (ace = list_head; ace; ace = ace->next) {
+ if (ace->type == SMB_ACL_USER_OBJ)
+ owner_ace = ace;
+ else if (ace->type == SMB_ACL_OTHER) {
+ /* Last ace - this is "other" */
+ other_ace = ace;
+ }
+ }
+
+ if (!owner_ace || !other_ace) {
+ DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
+ filename ));
+ return;
+ }
+
+ /*
+ * The POSIX algorithm applies to owner first, and other last,
+ * so ensure they are arranged in this order.
+ */
+
+ if (owner_ace) {
+ DLIST_PROMOTE(list_head, owner_ace);
+ }
+
+ if (other_ace) {
+ DLIST_DEMOTE(list_head, other_ace, canon_ace *);
+ }
+
+ /* We have probably changed the head of the list. */
+
+ *pp_list_head = list_head;
+}
+
+/****************************************************************************
+ Create a linked list of canonical ACE entries.
+****************************************************************************/
+
+static canon_ace *canonicalise_acl(struct connection_struct *conn,
+ const char *fname, SMB_ACL_T posix_acl,
+ const SMB_STRUCT_STAT *psbuf,
+ const DOM_SID *powner, const DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
+{
+ mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
+ canon_ace *list_head = NULL;
+ canon_ace *ace = NULL;
+ canon_ace *next_ace = NULL;
+ int entry_id = SMB_ACL_FIRST_ENTRY;
+ SMB_ACL_ENTRY_T entry;
+ size_t ace_count;
+
+ while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
+ SMB_ACL_TAG_T tagtype;
+ SMB_ACL_PERMSET_T permset;
+ DOM_SID sid;
+ posix_id unix_ug;
+ enum ace_owner owner_type;
+
+ entry_id = SMB_ACL_NEXT_ENTRY;
+
+ /* Is this a MASK entry ? */
+ if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
+ continue;
+
+ if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
+ continue;
+
+ /* Decide which SID to use based on the ACL type. */
+ switch(tagtype) {
+ case SMB_ACL_USER_OBJ:
+ /* Get the SID from the owner. */
+ sid_copy(&sid, powner);
+ unix_ug.uid = psbuf->st_uid;
+ owner_type = UID_ACE;
+ break;
+ case SMB_ACL_USER:
+ {
+ uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+ if (puid == NULL) {
+ DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
+ continue;
+ }
+ /*
+ * A SMB_ACL_USER entry for the owner is shadowed by the
+ * SMB_ACL_USER_OBJ entry and Windows also cannot represent
+ * that entry, so we ignore it. We also don't create such
+ * entries out of the blue when setting ACLs, so a get/set
+ * cycle will drop them.
+ */
+ if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid) {
+ SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
+ continue;
+ }
+ uid_to_sid( &sid, *puid);
+ unix_ug.uid = *puid;
+ owner_type = UID_ACE;
+ SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
+ break;
+ }
+ case SMB_ACL_GROUP_OBJ:
+ /* Get the SID from the owning group. */
+ sid_copy(&sid, pgroup);
+ unix_ug.gid = psbuf->st_gid;
+ owner_type = GID_ACE;
+ break;
+ case SMB_ACL_GROUP:
+ {
+ gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+ if (pgid == NULL) {
+ DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
+ continue;
+ }
+ gid_to_sid( &sid, *pgid);
+ unix_ug.gid = *pgid;
+ owner_type = GID_ACE;
+ SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
+ break;
+ }
+ case SMB_ACL_MASK:
+ acl_mask = convert_permset_to_mode_t(conn, permset);
+ continue; /* Don't count the mask as an entry. */
+ case SMB_ACL_OTHER:
+ /* Use the Everyone SID */
+ sid = global_sid_World;
+ unix_ug.world = -1;
+ owner_type = WORLD_ACE;
+ break;
+ default:
+ DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
+ continue;
+ }
+
+ /*
+ * Add this entry to the list.
+ */
+
+ if ((ace = SMB_MALLOC_P(canon_ace)) == NULL)
+ goto fail;
+
+ ZERO_STRUCTP(ace);
+ ace->type = tagtype;
+ ace->perms = convert_permset_to_mode_t(conn, permset);
+ ace->attr = ALLOW_ACE;
+ ace->trustee = sid;
+ ace->unix_ug = unix_ug;
+ ace->owner_type = owner_type;
+ ace->inherited = get_inherited_flag(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT));
+
+ DLIST_ADD(list_head, ace);
+ }
+
+ /*
+ * This next call will ensure we have at least a user/group/world set.
+ */
+
+ if (!ensure_canon_entry_valid(&list_head, conn->params,
+ S_ISDIR(psbuf->st_mode), powner, pgroup,
+ psbuf, False))
+ goto fail;
+
+ /*
+ * Now go through the list, masking the permissions with the
+ * acl_mask. Ensure all DENY Entries are at the start of the list.
+ */
+
+ DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" ));
+
+ for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) {
+ next_ace = ace->next;
+
+ /* Masks are only applied to entries other than USER_OBJ and OTHER. */
+ if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
+ ace->perms &= acl_mask;
+
+ if (ace->perms == 0) {
+ DLIST_PROMOTE(list_head, ace);
+ }
+
+ if( DEBUGLVL( 10 ) ) {
+ print_canon_ace(ace, ace_count);
+ }
+ }
+
+ arrange_posix_perms(fname,&list_head );
+
+ print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head );
+
+ return list_head;
+
+ fail:
+
+ free_canon_ace_list(list_head);
+ return NULL;
+}
+
+/****************************************************************************
+ Check if the current user group list contains a given group.
+****************************************************************************/
+
+static bool current_user_in_group(gid_t gid)
+{
+ int i;
+
+ for (i = 0; i < current_user.ut.ngroups; i++) {
+ if (current_user.ut.groups[i] == gid) {
+ return True;
+ }
+ }
+
+ return False;
+}
+
+/****************************************************************************
+ Should we override a deny ? Check 'acl group control' and 'dos filemode'.
+****************************************************************************/
+
+static bool acl_group_override(connection_struct *conn,
+ gid_t prim_gid,
+ const char *fname)
+{
+ SMB_STRUCT_STAT sbuf;
+
+ if ((errno != EPERM) && (errno != EACCES)) {
+ return false;
+ }
+
+ /* file primary group == user primary or supplementary group */
+ if (lp_acl_group_control(SNUM(conn)) &&
+ current_user_in_group(prim_gid)) {
+ return true;
+ }
+
+ /* user has writeable permission */
+ if (lp_dos_filemode(SNUM(conn)) &&
+ can_write_to_file(conn, fname, &sbuf)) {
+ return true;
+ }
+
+ return false;
+}
+
+/****************************************************************************
+ Attempt to apply an ACL to a file or directory.
+****************************************************************************/
+
+static bool set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, bool default_ace, gid_t prim_gid, bool *pacl_set_support)
+{
+ connection_struct *conn = fsp->conn;
+ bool ret = False;
+ SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1);
+ canon_ace *p_ace;
+ int i;
+ SMB_ACL_ENTRY_T mask_entry;
+ bool got_mask_entry = False;
+ SMB_ACL_PERMSET_T mask_permset;
+ SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
+ bool needs_mask = False;
+ mode_t mask_perms = 0;
+
+#if defined(POSIX_ACL_NEEDS_MASK)
+ /* HP-UX always wants to have a mask (called "class" there). */
+ needs_mask = True;
+#endif
+
+ if (the_acl == NULL) {
+
+ if (!no_acl_syscall_error(errno)) {
+ /*
+ * Only print this error message if we have some kind of ACL
+ * support that's not working. Otherwise we would always get this.
+ */
+ DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
+ default_ace ? "default" : "file", strerror(errno) ));
+ }
+ *pacl_set_support = False;
+ return False;
+ }
+
+ if( DEBUGLVL( 10 )) {
+ dbgtext("set_canon_ace_list: setting ACL:\n");
+ for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
+ print_canon_ace( p_ace, i);
+ }
+ }
+
+ for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
+ SMB_ACL_ENTRY_T the_entry;
+ SMB_ACL_PERMSET_T the_permset;
+
+ /*
+ * ACLs only "need" an ACL_MASK entry if there are any named user or
+ * named group entries. But if there is an ACL_MASK entry, it applies
+ * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
+ * so that it doesn't deny (i.e., mask off) any permissions.
+ */
+
+ if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
+ needs_mask = True;
+ mask_perms |= p_ace->perms;
+ } else if (p_ace->type == SMB_ACL_GROUP_OBJ) {
+ mask_perms |= p_ace->perms;
+ }
+
+ /*
+ * Get the entry for this ACE.
+ */
+
+ if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
+ i, strerror(errno) ));
+ goto fail;
+ }
+
+ if (p_ace->type == SMB_ACL_MASK) {
+ mask_entry = the_entry;
+ got_mask_entry = True;
+ }
+
+ /*
+ * Ok - we now know the ACL calls should be working, don't
+ * allow fallback to chmod.
+ */
+
+ *pacl_set_support = True;
+
+ /*
+ * Initialise the entry from the canon_ace.
+ */
+
+ /*
+ * First tell the entry what type of ACE this is.
+ */
+
+ if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
+ i, strerror(errno) ));
+ goto fail;
+ }
+
+ /*
+ * Only set the qualifier (user or group id) if the entry is a user
+ * or group id ACE.
+ */
+
+ if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
+ if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
+ i, strerror(errno) ));
+ goto fail;
+ }
+ }
+
+ /*
+ * Convert the mode_t perms in the canon_ace to a POSIX permset.
+ */
+
+ if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
+ i, strerror(errno) ));
+ goto fail;
+ }
+
+ if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
+ (unsigned int)p_ace->perms, i, strerror(errno) ));
+ goto fail;
+ }
+
+ /*
+ * ..and apply them to the entry.
+ */
+
+ if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
+ i, strerror(errno) ));
+ goto fail;
+ }
+
+ if( DEBUGLVL( 10 ))
+ print_canon_ace( p_ace, i);
+
+ }
+
+ if (needs_mask && !got_mask_entry) {
+ if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
+ goto fail;
+ }
+
+ if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
+ goto fail;
+ }
+
+ if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
+ goto fail;
+ }
+
+ if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
+ goto fail;
+ }
+
+ if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
+ goto fail;
+ }
+ }
+
+ /*
+ * Finally apply it to the file or directory.
+ */
+
+ if(default_ace || fsp->is_directory || fsp->fh->fd == -1) {
+ if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) {
+ /*
+ * Some systems allow all the above calls and only fail with no ACL support
+ * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
+ */
+ if (no_acl_syscall_error(errno)) {
+ *pacl_set_support = False;
+ }
+
+ if (acl_group_override(conn, prim_gid, fsp->fsp_name)) {
+ int sret;
+
+ DEBUG(5,("set_canon_ace_list: acl group control on and current user in file %s primary group.\n",
+ fsp->fsp_name ));
+
+ become_root();
+ sret = SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl);
+ unbecome_root();
+ if (sret == 0) {
+ ret = True;
+ }
+ }
+
+ if (ret == False) {
+ DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
+ the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
+ fsp->fsp_name, strerror(errno) ));
+ goto fail;
+ }
+ }
+ } else {
+ if (SMB_VFS_SYS_ACL_SET_FD(fsp, the_acl) == -1) {
+ /*
+ * Some systems allow all the above calls and only fail with no ACL support
+ * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
+ */
+ if (no_acl_syscall_error(errno)) {
+ *pacl_set_support = False;
+ }
+
+ if (acl_group_override(conn, prim_gid, fsp->fsp_name)) {
+ int sret;
+
+ DEBUG(5,("set_canon_ace_list: acl group control on and current user in file %s primary group.\n",
+ fsp->fsp_name ));
+
+ become_root();
+ sret = SMB_VFS_SYS_ACL_SET_FD(fsp, the_acl);
+ unbecome_root();
+ if (sret == 0) {
+ ret = True;
+ }
+ }
+
+ if (ret == False) {
+ DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
+ fsp->fsp_name, strerror(errno) ));
+ goto fail;
+ }
+ }
+ }
+
+ ret = True;
+
+ fail:
+
+ if (the_acl != NULL) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Find a particular canon_ace entry.
+****************************************************************************/
+
+static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id)
+{
+ while (list) {
+ if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) ||
+ (type == SMB_ACL_USER && id && id->uid == list->unix_ug.uid) ||
+ (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid)))
+ break;
+ list = list->next;
+ }
+ return list;
+}
+
+/****************************************************************************
+
+****************************************************************************/
+
+SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
+{
+ SMB_ACL_ENTRY_T entry;
+
+ if (!the_acl)
+ return NULL;
+ if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
+ return NULL;
+ }
+ return the_acl;
+}
+
+/****************************************************************************
+ Convert a canon_ace to a generic 3 element permission - if possible.
+****************************************************************************/
+
+#define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
+
+static bool convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
+{
+ int snum = SNUM(fsp->conn);
+ size_t ace_count = count_canon_ace_list(file_ace_list);
+ canon_ace *ace_p;
+ canon_ace *owner_ace = NULL;
+ canon_ace *group_ace = NULL;
+ canon_ace *other_ace = NULL;
+ mode_t and_bits;
+ mode_t or_bits;
+
+ if (ace_count != 3) {
+ DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
+posix perms.\n", fsp->fsp_name ));
+ return False;
+ }
+
+ for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
+ if (ace_p->owner_type == UID_ACE)
+ owner_ace = ace_p;
+ else if (ace_p->owner_type == GID_ACE)
+ group_ace = ace_p;
+ else if (ace_p->owner_type == WORLD_ACE)
+ other_ace = ace_p;
+ }
+
+ if (!owner_ace || !group_ace || !other_ace) {
+ DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
+ fsp->fsp_name ));
+ return False;
+ }
+
+ *posix_perms = (mode_t)0;
+
+ *posix_perms |= owner_ace->perms;
+ *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
+ *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
+ *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
+ *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
+ *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
+ *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
+
+ /* The owner must have at least read access. */
+
+ *posix_perms |= S_IRUSR;
+ if (fsp->is_directory)
+ *posix_perms |= (S_IWUSR|S_IXUSR);
+
+ /* If requested apply the masks. */
+
+ /* Get the initial bits to apply. */
+
+ if (fsp->is_directory) {
+ and_bits = lp_dir_security_mask(snum);
+ or_bits = lp_force_dir_security_mode(snum);
+ } else {
+ and_bits = lp_security_mask(snum);
+ or_bits = lp_force_security_mode(snum);
+ }
+
+ *posix_perms = (((*posix_perms) & and_bits)|or_bits);
+
+ DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
+ (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms,
+ fsp->fsp_name ));
+
+ return True;
+}
+
+/****************************************************************************
+ Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
+ a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
+ with CI|OI set so it is inherited and also applies to the directory.
+ Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
+****************************************************************************/
+
+static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
+{
+ size_t i, j;
+
+ for (i = 0; i < num_aces; i++) {
+ for (j = i+1; j < num_aces; j++) {
+ uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
+ uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
+ bool i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
+ bool j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
+
+ /* We know the lower number ACE's are file entries. */
+ if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
+ (nt_ace_list[i].size == nt_ace_list[j].size) &&
+ (nt_ace_list[i].access_mask == nt_ace_list[j].access_mask) &&
+ sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
+ (i_inh == j_inh) &&
+ (i_flags_ni == 0) &&
+ (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
+ SEC_ACE_FLAG_CONTAINER_INHERIT|
+ SEC_ACE_FLAG_INHERIT_ONLY))) {
+ /*
+ * W2K wants to have access allowed zero access ACE's
+ * at the end of the list. If the mask is zero, merge
+ * the non-inherited ACE onto the inherited ACE.
+ */
+
+ if (nt_ace_list[i].access_mask == 0) {
+ nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
+ (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
+ if (num_aces - i - 1 > 0)
+ memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) *
+ sizeof(SEC_ACE));
+
+ DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
+ (unsigned int)i, (unsigned int)j ));
+ } else {
+ /*
+ * These are identical except for the flags.
+ * Merge the inherited ACE onto the non-inherited ACE.
+ */
+
+ nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
+ (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
+ if (num_aces - j - 1 > 0)
+ memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
+ sizeof(SEC_ACE));
+
+ DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
+ (unsigned int)j, (unsigned int)i ));
+ }
+ num_aces--;
+ break;
+ }
+ }
+ }
+
+ return num_aces;
+}
+
+/****************************************************************************
+ Reply to query a security descriptor from an fsp. If it succeeds it allocates
+ the space for the return elements and returns the size needed to return the
+ security descriptor. This should be the only external function needed for
+ the UNIX style get ACL.
+****************************************************************************/
+
+static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
+ const char *name,
+ const SMB_STRUCT_STAT *sbuf,
+ struct pai_val *pal,
+ SMB_ACL_T posix_acl,
+ SMB_ACL_T def_acl,
+ uint32_t security_info,
+ SEC_DESC **ppdesc)
+{
+ DOM_SID owner_sid;
+ DOM_SID group_sid;
+ size_t sd_size = 0;
+ SEC_ACL *psa = NULL;
+ size_t num_acls = 0;
+ size_t num_def_acls = 0;
+ size_t num_aces = 0;
+ canon_ace *file_ace = NULL;
+ canon_ace *dir_ace = NULL;
+ SEC_ACE *nt_ace_list = NULL;
+ size_t num_profile_acls = 0;
+ SEC_DESC *psd = NULL;
+
+ /*
+ * Get the owner, group and world SIDs.
+ */
+
+ if (lp_profile_acls(SNUM(conn))) {
+ /* For WXP SP1 the owner must be administrators. */
+ sid_copy(&owner_sid, &global_sid_Builtin_Administrators);
+ sid_copy(&group_sid, &global_sid_Builtin_Users);
+ num_profile_acls = 2;
+ } else {
+ create_file_sids(sbuf, &owner_sid, &group_sid);
+ }
+
+ if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
+
+ /*
+ * In the optimum case Creator Owner and Creator Group would be used for
+ * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
+ * would lead to usability problems under Windows: The Creator entries
+ * are only available in browse lists of directories and not for files;
+ * additionally the identity of the owning group couldn't be determined.
+ * We therefore use those identities only for Default ACLs.
+ */
+
+ /* Create the canon_ace lists. */
+ file_ace = canonicalise_acl(conn, name, posix_acl, sbuf,
+ &owner_sid, &group_sid, pal,
+ SMB_ACL_TYPE_ACCESS);
+
+ /* We must have *some* ACLS. */
+
+ if (count_canon_ace_list(file_ace) == 0) {
+ DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", name));
+ goto done;
+ }
+
+ if (S_ISDIR(sbuf->st_mode) && def_acl) {
+ dir_ace = canonicalise_acl(conn, name, def_acl,
+ sbuf,
+ &global_sid_Creator_Owner,
+ &global_sid_Creator_Group,
+ pal, SMB_ACL_TYPE_DEFAULT);
+ }
+
+ /*
+ * Create the NT ACE list from the canonical ace lists.
+ */
+
+ {
+ canon_ace *ace;
+ enum security_ace_type nt_acl_type;
+
+ if (nt4_compatible_acls() && dir_ace) {
+ /*
+ * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
+ * but no non-INHERIT_ONLY entry for one SID. So we only
+ * remove entries from the Access ACL if the
+ * corresponding Default ACL entries have also been
+ * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
+ * are exceptions. We can do nothing
+ * intelligent if the Default ACL contains entries that
+ * are not also contained in the Access ACL, so this
+ * case will still fail under NT 4.
+ */
+
+ ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
+ if (ace && !ace->perms) {
+ DLIST_REMOVE(dir_ace, ace);
+ SAFE_FREE(ace);
+
+ ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
+ if (ace && !ace->perms) {
+ DLIST_REMOVE(file_ace, ace);
+ SAFE_FREE(ace);
+ }
+ }
+
+ /*
+ * WinNT doesn't usually have Creator Group
+ * in browse lists, so we send this entry to
+ * WinNT even if it contains no relevant
+ * permissions. Once we can add
+ * Creator Group to browse lists we can
+ * re-enable this.
+ */
+
+#if 0
+ ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
+ if (ace && !ace->perms) {
+ DLIST_REMOVE(dir_ace, ace);
+ SAFE_FREE(ace);
+ }
+#endif
+
+ ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
+ if (ace && !ace->perms) {
+ DLIST_REMOVE(file_ace, ace);
+ SAFE_FREE(ace);
+ }
+ }
+
+ num_acls = count_canon_ace_list(file_ace);
+ num_def_acls = count_canon_ace_list(dir_ace);
+
+ /* Allocate the ace list. */
+ if ((nt_ace_list = SMB_MALLOC_ARRAY(SEC_ACE,num_acls + num_profile_acls + num_def_acls)) == NULL) {
+ DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
+ goto done;
+ }
+
+ memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(SEC_ACE) );
+
+ /*
+ * Create the NT ACE list from the canonical ace lists.
+ */
+
+ for (ace = file_ace; ace != NULL; ace = ace->next) {
+ SEC_ACCESS acc;
+
+ acc = map_canon_ace_perms(SNUM(conn),
+ &nt_acl_type,
+ ace->perms,
+ S_ISDIR(sbuf->st_mode));
+ init_sec_ace(&nt_ace_list[num_aces++],
+ &ace->trustee,
+ nt_acl_type,
+ acc,
+ ace->inherited ?
+ SEC_ACE_FLAG_INHERITED_ACE : 0);
+ }
+
+ /* The User must have access to a profile share - even
+ * if we can't map the SID. */
+ if (lp_profile_acls(SNUM(conn))) {
+ SEC_ACCESS acc;
+
+ init_sec_access(&acc,FILE_GENERIC_ALL);
+ init_sec_ace(&nt_ace_list[num_aces++],
+ &global_sid_Builtin_Users,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ acc, 0);
+ }
+
+ for (ace = dir_ace; ace != NULL; ace = ace->next) {
+ SEC_ACCESS acc;
+
+ acc = map_canon_ace_perms(SNUM(conn),
+ &nt_acl_type,
+ ace->perms,
+ S_ISDIR(sbuf->st_mode));
+ init_sec_ace(&nt_ace_list[num_aces++],
+ &ace->trustee,
+ nt_acl_type,
+ acc,
+ SEC_ACE_FLAG_OBJECT_INHERIT|
+ SEC_ACE_FLAG_CONTAINER_INHERIT|
+ SEC_ACE_FLAG_INHERIT_ONLY|
+ (ace->inherited ?
+ SEC_ACE_FLAG_INHERITED_ACE : 0));
+ }
+
+ /* The User must have access to a profile share - even
+ * if we can't map the SID. */
+ if (lp_profile_acls(SNUM(conn))) {
+ SEC_ACCESS acc;
+
+ init_sec_access(&acc,FILE_GENERIC_ALL);
+ init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc,
+ SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
+ SEC_ACE_FLAG_INHERIT_ONLY|0);
+ }
+
+ /*
+ * Merge POSIX default ACLs and normal ACLs into one NT ACE.
+ * Win2K needs this to get the inheritance correct when replacing ACLs
+ * on a directory tree. Based on work by Jim @ IBM.
+ */
+
+ num_aces = merge_default_aces(nt_ace_list, num_aces);
+
+ }
+
+ if (num_aces) {
+ if((psa = make_sec_acl( talloc_tos(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
+ DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
+ goto done;
+ }
+ }
+ } /* security_info & DACL_SECURITY_INFORMATION */
+
+ psd = make_standard_sec_desc( talloc_tos(),
+ (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
+ (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
+ psa,
+ &sd_size);
+
+ if(!psd) {
+ DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
+ sd_size = 0;
+ goto done;
+ }
+
+ /*
+ * Windows 2000: The DACL_PROTECTED flag in the security
+ * descriptor marks the ACL as non-inheriting, i.e., no
+ * ACEs from higher level directories propagate to this
+ * ACL. In the POSIX ACL model permissions are only
+ * inherited at file create time, so ACLs never contain
+ * any ACEs that are inherited dynamically. The DACL_PROTECTED
+ * flag doesn't seem to bother Windows NT.
+ * Always set this if map acl inherit is turned off.
+ */
+ if (get_protected_flag(pal) || !lp_map_acl_inherit(SNUM(conn))) {
+ psd->type |= SE_DESC_DACL_PROTECTED;
+ }
+
+ if (psd->dacl) {
+ dacl_sort_into_canonical_order(psd->dacl->aces, (unsigned int)psd->dacl->num_aces);
+ }
+
+ *ppdesc = psd;
+
+ done:
+
+ if (posix_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+ }
+ if (def_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ }
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ free_inherited_info(pal);
+ SAFE_FREE(nt_ace_list);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info,
+ SEC_DESC **ppdesc)
+{
+ SMB_STRUCT_STAT sbuf;
+ SMB_ACL_T posix_acl = NULL;
+ struct pai_val *pal;
+
+ *ppdesc = NULL;
+
+ DEBUG(10,("posix_fget_nt_acl: called for file %s\n", fsp->fsp_name ));
+
+ /* can it happen that fsp_name == NULL ? */
+ if (fsp->is_directory || fsp->fh->fd == -1) {
+ return posix_get_nt_acl(fsp->conn, fsp->fsp_name,
+ security_info, ppdesc);
+ }
+
+ /* Get the stat struct for the owner info. */
+ if(SMB_VFS_FSTAT(fsp, &sbuf) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ /* Get the ACL from the fd. */
+ posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
+
+ pal = fload_inherited_info(fsp);
+
+ return posix_get_nt_acl_common(fsp->conn, fsp->fsp_name, &sbuf, pal,
+ posix_acl, NULL, security_info, ppdesc);
+}
+
+NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name,
+ uint32_t security_info, SEC_DESC **ppdesc)
+{
+ SMB_STRUCT_STAT sbuf;
+ SMB_ACL_T posix_acl = NULL;
+ SMB_ACL_T def_acl = NULL;
+ struct pai_val *pal;
+
+ *ppdesc = NULL;
+
+ DEBUG(10,("posix_get_nt_acl: called for file %s\n", name ));
+
+ /* Get the stat struct for the owner info. */
+ if(SMB_VFS_STAT(conn, name, &sbuf) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ /* Get the ACL from the path. */
+ posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name, SMB_ACL_TYPE_ACCESS);
+
+ /* If it's a directory get the default POSIX ACL. */
+ if(S_ISDIR(sbuf.st_mode)) {
+ def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name, SMB_ACL_TYPE_DEFAULT);
+ def_acl = free_empty_sys_acl(conn, def_acl);
+ }
+
+ pal = load_inherited_info(conn, name);
+
+ return posix_get_nt_acl_common(conn, name, &sbuf, pal, posix_acl,
+ def_acl, security_info, ppdesc);
+}
+
+/****************************************************************************
+ Try to chown a file. We will be able to chown it under the following conditions.
+
+ 1) If we have root privileges, then it will just work.
+ 2) If we have SeTakeOwnershipPrivilege we can change the user to the current user.
+ 3) If we have SeRestorePrivilege we can change the user to any other user.
+ 4) If we have write permission to the file and dos_filemodes is set
+ then allow chown to the currently authenticated user.
+****************************************************************************/
+
+int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
+{
+ int ret;
+ files_struct *fsp;
+ SMB_STRUCT_STAT st;
+
+ if(!CAN_WRITE(conn)) {
+ return -1;
+ }
+
+ /* Case (1). */
+ /* try the direct way first */
+ ret = SMB_VFS_CHOWN(conn, fname, uid, gid);
+ if (ret == 0)
+ return 0;
+
+ /* Case (2) / (3) */
+ if (lp_enable_privileges()) {
+
+ bool has_take_ownership_priv = user_has_privileges(current_user.nt_user_token,
+ &se_take_ownership);
+ bool has_restore_priv = user_has_privileges(current_user.nt_user_token,
+ &se_restore);
+
+ /* Case (2) */
+ if ( ( has_take_ownership_priv && ( uid == current_user.ut.uid ) ) ||
+ /* Case (3) */
+ ( has_restore_priv ) ) {
+
+ become_root();
+ /* Keep the current file gid the same - take ownership doesn't imply group change. */
+ ret = SMB_VFS_CHOWN(conn, fname, uid, (gid_t)-1);
+ unbecome_root();
+ return ret;
+ }
+ }
+
+ /* Case (4). */
+ if (!lp_dos_filemode(SNUM(conn))) {
+ errno = EPERM;
+ return -1;
+ }
+
+ if (SMB_VFS_STAT(conn,fname,&st)) {
+ return -1;
+ }
+
+ if (!NT_STATUS_IS_OK(open_file_fchmod(conn,fname,&st,&fsp))) {
+ return -1;
+ }
+
+ /* only allow chown to the current user. This is more secure,
+ and also copes with the case where the SID in a take ownership ACL is
+ a local SID on the users workstation
+ */
+ uid = current_user.ut.uid;
+
+ become_root();
+ /* Keep the current file gid the same. */
+ ret = SMB_VFS_FCHOWN(fsp, uid, (gid_t)-1);
+ unbecome_root();
+
+ close_file_fchmod(fsp);
+
+ return ret;
+}
+
+/****************************************************************************
+ Take care of parent ACL inheritance.
+****************************************************************************/
+
+static NTSTATUS append_parent_acl(files_struct *fsp,
+ SMB_STRUCT_STAT *psbuf,
+ SEC_DESC *psd,
+ SEC_DESC **pp_new_sd)
+{
+ SEC_DESC *parent_sd = NULL;
+ files_struct *parent_fsp = NULL;
+ TALLOC_CTX *mem_ctx = talloc_parent(psd);
+ char *parent_name = NULL;
+ SEC_ACE *new_ace = NULL;
+ unsigned int num_aces = psd->dacl->num_aces;
+ SMB_STRUCT_STAT sbuf;
+ NTSTATUS status;
+ int info;
+ unsigned int i, j;
+ bool is_dacl_protected = (psd->type & SE_DESC_DACL_PROTECTED);
+
+ ZERO_STRUCT(sbuf);
+
+ if (mem_ctx == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!parent_dirname_talloc(mem_ctx,
+ fsp->fsp_name,
+ &parent_name,
+ NULL)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = open_directory(fsp->conn,
+ NULL,
+ parent_name,
+ &sbuf,
+ FILE_READ_ATTRIBUTES, /* Just a stat open */
+ FILE_SHARE_NONE, /* Ignored for stat opens */
+ FILE_OPEN,
+ 0,
+ INTERNAL_OPEN_ONLY,
+ &info,
+ &parent_fsp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = SMB_VFS_GET_NT_ACL(parent_fsp->conn, parent_fsp->fsp_name,
+ DACL_SECURITY_INFORMATION, &parent_sd );
+
+ close_file(parent_fsp, NORMAL_CLOSE);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * Make room for potentially all the ACLs from
+ * the parent. We used to add the ugw triple here,
+ * as we knew we were dealing with POSIX ACLs.
+ * We no longer need to do so as we can guarentee
+ * that a default ACL from the parent directory will
+ * be well formed for POSIX ACLs if it came from a
+ * POSIX ACL source, and if we're not writing to a
+ * POSIX ACL sink then we don't care if it's not well
+ * formed. JRA.
+ */
+
+ num_aces += parent_sd->dacl->num_aces;
+
+ if((new_ace = TALLOC_ZERO_ARRAY(mem_ctx, SEC_ACE,
+ num_aces)) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Start by copying in all the given ACE entries. */
+ for (i = 0; i < psd->dacl->num_aces; i++) {
+ sec_ace_copy(&new_ace[i], &psd->dacl->aces[i]);
+ }
+
+ /*
+ * Note that we're ignoring "inherit permissions" here
+ * as that really only applies to newly created files. JRA.
+ */
+
+ /* Finally append any inherited ACEs. */
+ for (j = 0; j < parent_sd->dacl->num_aces; j++) {
+ SEC_ACE *se = &parent_sd->dacl->aces[j];
+
+ if (fsp->is_directory) {
+ if (!(se->flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
+ /* Doesn't apply to a directory - ignore. */
+ DEBUG(10,("append_parent_acl: directory %s "
+ "ignoring non container "
+ "inherit flags %u on ACE with sid %s "
+ "from parent %s\n",
+ fsp->fsp_name,
+ (unsigned int)se->flags,
+ sid_string_dbg(&se->trustee),
+ parent_name));
+ continue;
+ }
+ } else {
+ if (!(se->flags & SEC_ACE_FLAG_OBJECT_INHERIT)) {
+ /* Doesn't apply to a file - ignore. */
+ DEBUG(10,("append_parent_acl: file %s "
+ "ignoring non object "
+ "inherit flags %u on ACE with sid %s "
+ "from parent %s\n",
+ fsp->fsp_name,
+ (unsigned int)se->flags,
+ sid_string_dbg(&se->trustee),
+ parent_name));
+ continue;
+ }
+ }
+
+ if (is_dacl_protected) {
+ /* If the DACL is protected it means we must
+ * not overwrite an existing ACE entry with the
+ * same SID. This is order N^2. Ouch :-(. JRA. */
+ unsigned int k;
+ for (k = 0; k < psd->dacl->num_aces; k++) {
+ if (sid_equal(&psd->dacl->aces[k].trustee,
+ &se->trustee)) {
+ break;
+ }
+ }
+ if (k < psd->dacl->num_aces) {
+ /* SID matched. Ignore. */
+ DEBUG(10,("append_parent_acl: path %s "
+ "ignoring ACE with protected sid %s "
+ "from parent %s\n",
+ fsp->fsp_name,
+ sid_string_dbg(&se->trustee),
+ parent_name));
+ continue;
+ }
+ }
+
+ sec_ace_copy(&new_ace[i], se);
+ if (se->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
+ new_ace[i].flags &= ~(SEC_ACE_FLAG_VALID_INHERIT);
+ }
+ new_ace[i].flags |= SEC_ACE_FLAG_INHERITED_ACE;
+
+ if (fsp->is_directory) {
+ /*
+ * Strip off any inherit only. It's applied.
+ */
+ new_ace[i].flags &= ~(SEC_ACE_FLAG_INHERIT_ONLY);
+ if (se->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
+ /* No further inheritance. */
+ new_ace[i].flags &=
+ ~(SEC_ACE_FLAG_CONTAINER_INHERIT|
+ SEC_ACE_FLAG_OBJECT_INHERIT);
+ }
+ } else {
+ /*
+ * Strip off any container or inherit
+ * flags, they can't apply to objects.
+ */
+ new_ace[i].flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|
+ SEC_ACE_FLAG_INHERIT_ONLY|
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT);
+ }
+ i++;
+
+ DEBUG(10,("append_parent_acl: path %s "
+ "inheriting ACE with sid %s "
+ "from parent %s\n",
+ fsp->fsp_name,
+ sid_string_dbg(&se->trustee),
+ parent_name));
+ }
+
+ /* This sucks. psd should be const and we should
+ * be doing a deep-copy here. We're getting away
+ * with is as we know parent_sd is talloced off
+ * talloc_tos() as well as psd. JRA. */
+
+ psd->dacl->aces = new_ace;
+ psd->dacl->num_aces = i;
+ psd->type &= ~(SE_DESC_DACL_AUTO_INHERITED|
+ SE_DESC_DACL_AUTO_INHERIT_REQ);
+
+ *pp_new_sd = psd;
+ return status;
+}
+
+/****************************************************************************
+ Reply to set a security descriptor on an fsp. security_info_sent is the
+ description of the following NT ACL.
+ This should be the only external function needed for the UNIX style set ACL.
+****************************************************************************/
+
+NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
+{
+ connection_struct *conn = fsp->conn;
+ uid_t user = (uid_t)-1;
+ gid_t grp = (gid_t)-1;
+ SMB_STRUCT_STAT sbuf;
+ DOM_SID file_owner_sid;
+ DOM_SID file_grp_sid;
+ canon_ace *file_ace_list = NULL;
+ canon_ace *dir_ace_list = NULL;
+ bool acl_perms = False;
+ mode_t orig_mode = (mode_t)0;
+ NTSTATUS status;
+ uid_t orig_uid;
+ gid_t orig_gid;
+ bool need_chown = False;
+
+ DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
+
+ if (!CAN_WRITE(conn)) {
+ DEBUG(10,("set acl rejected on read-only share\n"));
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+ }
+
+ /*
+ * Get the current state of the file.
+ */
+
+ if(fsp->is_directory || fsp->fh->fd == -1) {
+ if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0)
+ return map_nt_error_from_unix(errno);
+ } else {
+ if(SMB_VFS_FSTAT(fsp, &sbuf) != 0)
+ return map_nt_error_from_unix(errno);
+ }
+
+ /* Save the original elements we check against. */
+ orig_mode = sbuf.st_mode;
+ orig_uid = sbuf.st_uid;
+ orig_gid = sbuf.st_gid;
+
+ /*
+ * Unpack the user/group/world id's.
+ */
+
+ status = unpack_nt_owners( SNUM(conn), &user, &grp, security_info_sent, psd);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * Do we need to chown ?
+ */
+
+ if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp))) {
+ need_chown = True;
+ }
+
+ if (need_chown && (user == (uid_t)-1 || user == current_user.ut.uid)) {
+
+ DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
+ fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
+
+ if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
+ DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
+ fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
+ if (errno == EPERM) {
+ return NT_STATUS_INVALID_OWNER;
+ }
+ return map_nt_error_from_unix(errno);
+ }
+
+ /*
+ * Recheck the current state of the file, which may have changed.
+ * (suid/sgid bits, for instance)
+ */
+
+ if(fsp->is_directory) {
+ if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+ } else {
+
+ int ret;
+
+ if(fsp->fh->fd == -1)
+ ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf);
+ else
+ ret = SMB_VFS_FSTAT(fsp, &sbuf);
+
+ if(ret != 0)
+ return map_nt_error_from_unix(errno);
+ }
+
+ /* Save the original elements we check against. */
+ orig_mode = sbuf.st_mode;
+ orig_uid = sbuf.st_uid;
+ orig_gid = sbuf.st_gid;
+
+ /* We did chown already, drop the flag */
+ need_chown = False;
+ }
+
+ create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
+
+ if ((security_info_sent & DACL_SECURITY_INFORMATION) &&
+ psd->dacl != NULL &&
+ (psd->type & (SE_DESC_DACL_AUTO_INHERITED|
+ SE_DESC_DACL_AUTO_INHERIT_REQ))==
+ (SE_DESC_DACL_AUTO_INHERITED|
+ SE_DESC_DACL_AUTO_INHERIT_REQ) ) {
+ status = append_parent_acl(fsp, &sbuf, psd, &psd);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
+ &file_ace_list, &dir_ace_list, security_info_sent, psd);
+
+ /* Ignore W2K traverse DACL set. */
+ if (file_ace_list || dir_ace_list) {
+
+ if (!acl_perms) {
+ DEBUG(3,("set_nt_acl: cannot set permissions\n"));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /*
+ * Only change security if we got a DACL.
+ */
+
+ if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
+
+ bool acl_set_support = False;
+ bool ret = False;
+
+ /*
+ * Try using the POSIX ACL set first. Fall back to chmod if
+ * we have no ACL support on this filesystem.
+ */
+
+ if (acl_perms && file_ace_list) {
+ ret = set_canon_ace_list(fsp, file_ace_list, False, sbuf.st_gid, &acl_set_support);
+ if (acl_set_support && ret == False) {
+ DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return map_nt_error_from_unix(errno);
+ }
+ }
+
+ if (acl_perms && acl_set_support && fsp->is_directory) {
+ if (dir_ace_list) {
+ if (!set_canon_ace_list(fsp, dir_ace_list, True, sbuf.st_gid, &acl_set_support)) {
+ DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return map_nt_error_from_unix(errno);
+ }
+ } else {
+
+ /*
+ * No default ACL - delete one if it exists.
+ */
+
+ if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) {
+ int sret = -1;
+
+ if (acl_group_override(conn, sbuf.st_gid, fsp->fsp_name)) {
+ DEBUG(5,("set_nt_acl: acl group control on and "
+ "current user in file %s primary group. Override delete_def_acl\n",
+ fsp->fsp_name ));
+
+ become_root();
+ sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name);
+ unbecome_root();
+ }
+
+ if (sret == -1) {
+ DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return map_nt_error_from_unix(errno);
+ }
+ }
+ }
+ }
+
+ if (acl_set_support) {
+ store_inheritance_attributes(fsp, file_ace_list, dir_ace_list,
+ (psd->type & SE_DESC_DACL_PROTECTED) ? True : False);
+ }
+
+ /*
+ * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
+ */
+
+ if(!acl_set_support && acl_perms) {
+ mode_t posix_perms;
+
+ if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
+ fsp->fsp_name ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (orig_mode != posix_perms) {
+
+ DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
+ fsp->fsp_name, (unsigned int)posix_perms ));
+
+ if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) {
+ int sret = -1;
+ if (acl_group_override(conn, sbuf.st_gid, fsp->fsp_name)) {
+ DEBUG(5,("set_nt_acl: acl group control on and "
+ "current user in file %s primary group. Override chmod\n",
+ fsp->fsp_name ));
+
+ become_root();
+ sret = SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms);
+ unbecome_root();
+ }
+
+ if (sret == -1) {
+ DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
+ fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return map_nt_error_from_unix(errno);
+ }
+ }
+ }
+ }
+ }
+
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ }
+
+ /* Any chown pending? */
+ if (need_chown) {
+ DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
+ fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
+
+ if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
+ DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
+ fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
+ if (errno == EPERM) {
+ return NT_STATUS_INVALID_OWNER;
+ }
+ return map_nt_error_from_unix(errno);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Get the actual group bits stored on a file with an ACL. Has no effect if
+ the file has no ACL. Needed in dosmode code where the stat() will return
+ the mask bits, not the real group bits, for a file with an ACL.
+****************************************************************************/
+
+int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode )
+{
+ int entry_id = SMB_ACL_FIRST_ENTRY;
+ SMB_ACL_ENTRY_T entry;
+ SMB_ACL_T posix_acl;
+ int result = -1;
+
+ posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
+ if (posix_acl == (SMB_ACL_T)NULL)
+ return -1;
+
+ while (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
+ SMB_ACL_TAG_T tagtype;
+ SMB_ACL_PERMSET_T permset;
+
+ entry_id = SMB_ACL_NEXT_ENTRY;
+
+ if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) ==-1)
+ break;
+
+ if (tagtype == SMB_ACL_GROUP_OBJ) {
+ if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
+ break;
+ } else {
+ *mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP);
+ *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRGRP : 0);
+ *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
+ *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
+ result = 0;
+ break;
+ }
+ }
+ }
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+ return result;
+}
+
+/****************************************************************************
+ Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
+ and set the mask to rwx. Needed to preserve complex ACLs set by NT.
+****************************************************************************/
+
+static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
+{
+ int entry_id = SMB_ACL_FIRST_ENTRY;
+ SMB_ACL_ENTRY_T entry;
+ int num_entries = 0;
+
+ while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
+ SMB_ACL_TAG_T tagtype;
+ SMB_ACL_PERMSET_T permset;
+ mode_t perms;
+
+ entry_id = SMB_ACL_NEXT_ENTRY;
+
+ if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
+ return -1;
+
+ if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
+ return -1;
+
+ num_entries++;
+
+ switch(tagtype) {
+ case SMB_ACL_USER_OBJ:
+ perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
+ break;
+ case SMB_ACL_GROUP_OBJ:
+ perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
+ break;
+ case SMB_ACL_MASK:
+ /*
+ * FIXME: The ACL_MASK entry permissions should really be set to
+ * the union of the permissions of all ACL_USER,
+ * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
+ * acl_calc_mask() does, but Samba ACLs doesn't provide it.
+ */
+ perms = S_IRUSR|S_IWUSR|S_IXUSR;
+ break;
+ case SMB_ACL_OTHER:
+ perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
+ break;
+ default:
+ continue;
+ }
+
+ if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
+ return -1;
+
+ if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
+ return -1;
+ }
+
+ /*
+ * If this is a simple 3 element ACL or no elements then it's a standard
+ * UNIX permission set. Just use chmod...
+ */
+
+ if ((num_entries == 3) || (num_entries == 0))
+ return -1;
+
+ return 0;
+}
+
+/****************************************************************************
+ Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
+ GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
+ resulting ACL on TO. Note that name is in UNIX character set.
+****************************************************************************/
+
+static int copy_access_posix_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
+{
+ SMB_ACL_T posix_acl = NULL;
+ int ret = -1;
+
+ if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
+ return -1;
+
+ if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
+ goto done;
+
+ ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
+
+ done:
+
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+ return ret;
+}
+
+/****************************************************************************
+ Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
+ and set the mask to rwx. Needed to preserve complex ACLs set by NT.
+ Note that name is in UNIX character set.
+****************************************************************************/
+
+int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
+{
+ return copy_access_posix_acl(conn, name, name, mode);
+}
+
+/****************************************************************************
+ Check for an existing default POSIX ACL on a directory.
+****************************************************************************/
+
+static bool directory_has_default_posix_acl(connection_struct *conn, const char *fname)
+{
+ SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
+ bool has_acl = False;
+ SMB_ACL_ENTRY_T entry;
+
+ if (def_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
+ has_acl = True;
+ }
+
+ if (def_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ }
+ return has_acl;
+}
+
+/****************************************************************************
+ If the parent directory has no default ACL but it does have an Access ACL,
+ inherit this Access ACL to file name.
+****************************************************************************/
+
+int inherit_access_posix_acl(connection_struct *conn, const char *inherit_from_dir,
+ const char *name, mode_t mode)
+{
+ if (directory_has_default_posix_acl(conn, inherit_from_dir))
+ return 0;
+
+ return copy_access_posix_acl(conn, inherit_from_dir, name, mode);
+}
+
+/****************************************************************************
+ Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
+ and set the mask to rwx. Needed to preserve complex ACLs set by NT.
+****************************************************************************/
+
+int fchmod_acl(files_struct *fsp, mode_t mode)
+{
+ connection_struct *conn = fsp->conn;
+ SMB_ACL_T posix_acl = NULL;
+ int ret = -1;
+
+ if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp)) == NULL)
+ return -1;
+
+ if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
+ goto done;
+
+ ret = SMB_VFS_SYS_ACL_SET_FD(fsp, posix_acl);
+
+ done:
+
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+ return ret;
+}
+
+/****************************************************************************
+ Map from wire type to permset.
+****************************************************************************/
+
+static bool unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset)
+{
+ if (wire_perm & ~(SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE)) {
+ return False;
+ }
+
+ if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) == -1) {
+ return False;
+ }
+
+ if (wire_perm & SMB_POSIX_ACL_READ) {
+ if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1) {
+ return False;
+ }
+ }
+ if (wire_perm & SMB_POSIX_ACL_WRITE) {
+ if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1) {
+ return False;
+ }
+ }
+ if (wire_perm & SMB_POSIX_ACL_EXECUTE) {
+ if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1) {
+ return False;
+ }
+ }
+ return True;
+}
+
+/****************************************************************************
+ Map from wire type to tagtype.
+****************************************************************************/
+
+static bool unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt)
+{
+ switch (wire_tt) {
+ case SMB_POSIX_ACL_USER_OBJ:
+ *p_tt = SMB_ACL_USER_OBJ;
+ break;
+ case SMB_POSIX_ACL_USER:
+ *p_tt = SMB_ACL_USER;
+ break;
+ case SMB_POSIX_ACL_GROUP_OBJ:
+ *p_tt = SMB_ACL_GROUP_OBJ;
+ break;
+ case SMB_POSIX_ACL_GROUP:
+ *p_tt = SMB_ACL_GROUP;
+ break;
+ case SMB_POSIX_ACL_MASK:
+ *p_tt = SMB_ACL_MASK;
+ break;
+ case SMB_POSIX_ACL_OTHER:
+ *p_tt = SMB_ACL_OTHER;
+ break;
+ default:
+ return False;
+ }
+ return True;
+}
+
+/****************************************************************************
+ Create a new POSIX acl from wire permissions.
+ FIXME ! How does the share mask/mode fit into this.... ?
+****************************************************************************/
+
+static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_acls, const char *pdata)
+{
+ unsigned int i;
+ SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, num_acls);
+
+ if (the_acl == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < num_acls; i++) {
+ SMB_ACL_ENTRY_T the_entry;
+ SMB_ACL_PERMSET_T the_permset;
+ SMB_ACL_TAG_T tag_type;
+
+ if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
+ DEBUG(0,("create_posix_acl_from_wire: Failed to create entry %u. (%s)\n",
+ i, strerror(errno) ));
+ goto fail;
+ }
+
+ if (!unix_ex_wire_to_tagtype(CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), &tag_type)) {
+ DEBUG(0,("create_posix_acl_from_wire: invalid wire tagtype %u on entry %u.\n",
+ CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), i ));
+ goto fail;
+ }
+
+ if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, tag_type) == -1) {
+ DEBUG(0,("create_posix_acl_from_wire: Failed to set tagtype on entry %u. (%s)\n",
+ i, strerror(errno) ));
+ goto fail;
+ }
+
+ /* Get the permset pointer from the new ACL entry. */
+ if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
+ DEBUG(0,("create_posix_acl_from_wire: Failed to get permset on entry %u. (%s)\n",
+ i, strerror(errno) ));
+ goto fail;
+ }
+
+ /* Map from wire to permissions. */
+ if (!unix_ex_wire_to_permset(conn, CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+1), &the_permset)) {
+ DEBUG(0,("create_posix_acl_from_wire: invalid permset %u on entry %u.\n",
+ CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE) + 1), i ));
+ goto fail;
+ }
+
+ /* Now apply to the new ACL entry. */
+ if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
+ DEBUG(0,("create_posix_acl_from_wire: Failed to add permset on entry %u. (%s)\n",
+ i, strerror(errno) ));
+ goto fail;
+ }
+
+ if (tag_type == SMB_ACL_USER) {
+ uint32 uidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
+ uid_t uid = (uid_t)uidval;
+ if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&uid) == -1) {
+ DEBUG(0,("create_posix_acl_from_wire: Failed to set uid %u on entry %u. (%s)\n",
+ (unsigned int)uid, i, strerror(errno) ));
+ goto fail;
+ }
+ }
+
+ if (tag_type == SMB_ACL_GROUP) {
+ uint32 gidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
+ gid_t gid = (uid_t)gidval;
+ if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&gid) == -1) {
+ DEBUG(0,("create_posix_acl_from_wire: Failed to set gid %u on entry %u. (%s)\n",
+ (unsigned int)gid, i, strerror(errno) ));
+ goto fail;
+ }
+ }
+ }
+
+ return the_acl;
+
+ fail:
+
+ if (the_acl != NULL) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ Calls from UNIX extensions - Default POSIX ACL set.
+ If num_def_acls == 0 and not a directory just return. If it is a directory
+ and num_def_acls == 0 then remove the default acl. Else set the default acl
+ on the directory.
+****************************************************************************/
+
+bool set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf,
+ uint16 num_def_acls, const char *pdata)
+{
+ SMB_ACL_T def_acl = NULL;
+
+ if (num_def_acls && !S_ISDIR(psbuf->st_mode)) {
+ DEBUG(5,("set_unix_posix_default_acl: Can't set default ACL on non-directory file %s\n", fname ));
+ errno = EISDIR;
+ return False;
+ }
+
+ if (!num_def_acls) {
+ /* Remove the default ACL. */
+ if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fname) == -1) {
+ DEBUG(5,("set_unix_posix_default_acl: acl_delete_def_file failed on directory %s (%s)\n",
+ fname, strerror(errno) ));
+ return False;
+ }
+ return True;
+ }
+
+ if ((def_acl = create_posix_acl_from_wire(conn, num_def_acls, pdata)) == NULL) {
+ return False;
+ }
+
+ if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT, def_acl) == -1) {
+ DEBUG(5,("set_unix_posix_default_acl: acl_set_file failed on directory %s (%s)\n",
+ fname, strerror(errno) ));
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ return False;
+ }
+
+ DEBUG(10,("set_unix_posix_default_acl: set default acl for file %s\n", fname ));
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ return True;
+}
+
+/****************************************************************************
+ Remove an ACL from a file. As we don't have acl_delete_entry() available
+ we must read the current acl and copy all entries except MASK, USER and GROUP
+ to a new acl, then set that. This (at least on Linux) causes any ACL to be
+ removed.
+ FIXME ! How does the share mask/mode fit into this.... ?
+****************************************************************************/
+
+static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname)
+{
+ SMB_ACL_T file_acl = NULL;
+ int entry_id = SMB_ACL_FIRST_ENTRY;
+ SMB_ACL_ENTRY_T entry;
+ bool ret = False;
+ /* Create a new ACL with only 3 entries, u/g/w. */
+ SMB_ACL_T new_file_acl = SMB_VFS_SYS_ACL_INIT(conn, 3);
+ SMB_ACL_ENTRY_T user_ent = NULL;
+ SMB_ACL_ENTRY_T group_ent = NULL;
+ SMB_ACL_ENTRY_T other_ent = NULL;
+
+ if (new_file_acl == NULL) {
+ DEBUG(5,("remove_posix_acl: failed to init new ACL with 3 entries for file %s.\n", fname));
+ return False;
+ }
+
+ /* Now create the u/g/w entries. */
+ if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &user_ent) == -1) {
+ DEBUG(5,("remove_posix_acl: Failed to create user entry for file %s. (%s)\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+ if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, user_ent, SMB_ACL_USER_OBJ) == -1) {
+ DEBUG(5,("remove_posix_acl: Failed to set user entry for file %s. (%s)\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+
+ if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &group_ent) == -1) {
+ DEBUG(5,("remove_posix_acl: Failed to create group entry for file %s. (%s)\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+ if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, group_ent, SMB_ACL_GROUP_OBJ) == -1) {
+ DEBUG(5,("remove_posix_acl: Failed to set group entry for file %s. (%s)\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+
+ if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &other_ent) == -1) {
+ DEBUG(5,("remove_posix_acl: Failed to create other entry for file %s. (%s)\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+ if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, other_ent, SMB_ACL_OTHER) == -1) {
+ DEBUG(5,("remove_posix_acl: Failed to set other entry for file %s. (%s)\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+
+ /* Get the current file ACL. */
+ if (fsp && fsp->fh->fd != -1) {
+ file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
+ } else {
+ file_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_ACCESS);
+ }
+
+ if (file_acl == NULL) {
+ /* This is only returned if an error occurred. Even for a file with
+ no acl a u/g/w acl should be returned. */
+ DEBUG(5,("remove_posix_acl: failed to get ACL from file %s (%s).\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+
+ while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, file_acl, entry_id, &entry) == 1) {
+ SMB_ACL_TAG_T tagtype;
+ SMB_ACL_PERMSET_T permset;
+
+ entry_id = SMB_ACL_NEXT_ENTRY;
+
+ if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
+ DEBUG(5,("remove_posix_acl: failed to get tagtype from ACL on file %s (%s).\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+
+ if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
+ DEBUG(5,("remove_posix_acl: failed to get permset from ACL on file %s (%s).\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+
+ if (tagtype == SMB_ACL_USER_OBJ) {
+ if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, user_ent, permset) == -1) {
+ DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
+ fname, strerror(errno) ));
+ }
+ } else if (tagtype == SMB_ACL_GROUP_OBJ) {
+ if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, group_ent, permset) == -1) {
+ DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
+ fname, strerror(errno) ));
+ }
+ } else if (tagtype == SMB_ACL_OTHER) {
+ if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, other_ent, permset) == -1) {
+ DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
+ fname, strerror(errno) ));
+ }
+ }
+ }
+
+ /* Set the new empty file ACL. */
+ if (fsp && fsp->fh->fd != -1) {
+ if (SMB_VFS_SYS_ACL_SET_FD(fsp, new_file_acl) == -1) {
+ DEBUG(5,("remove_posix_acl: acl_set_file failed on %s (%s)\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+ } else {
+ if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, new_file_acl) == -1) {
+ DEBUG(5,("remove_posix_acl: acl_set_file failed on %s (%s)\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+ }
+
+ ret = True;
+
+ done:
+
+ if (file_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ }
+ if (new_file_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, new_file_acl);
+ }
+ return ret;
+}
+
+/****************************************************************************
+ Calls from UNIX extensions - POSIX ACL set.
+ If num_def_acls == 0 then read/modify/write acl after removing all entries
+ except SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER.
+****************************************************************************/
+
+bool set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname, uint16 num_acls, const char *pdata)
+{
+ SMB_ACL_T file_acl = NULL;
+
+ if (!num_acls) {
+ /* Remove the ACL from the file. */
+ return remove_posix_acl(conn, fsp, fname);
+ }
+
+ if ((file_acl = create_posix_acl_from_wire(conn, num_acls, pdata)) == NULL) {
+ return False;
+ }
+
+ if (fsp && fsp->fh->fd != -1) {
+ /* The preferred way - use an open fd. */
+ if (SMB_VFS_SYS_ACL_SET_FD(fsp, file_acl) == -1) {
+ DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
+ fname, strerror(errno) ));
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ return False;
+ }
+ } else {
+ if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, file_acl) == -1) {
+ DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
+ fname, strerror(errno) ));
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ return False;
+ }
+ }
+
+ DEBUG(10,("set_unix_posix_acl: set acl for file %s\n", fname ));
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ return True;
+}
+
+/********************************************************************
+ Pull the NT ACL from a file on disk or the OpenEventlog() access
+ check. Caller is responsible for freeing the returned security
+ descriptor via TALLOC_FREE(). This is designed for dealing with
+ user space access checks in smbd outside of the VFS. For example,
+ checking access rights in OpenEventlog().
+
+ Assume we are dealing with files (for now)
+********************************************************************/
+
+SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
+{
+ SEC_DESC *psd, *ret_sd;
+ connection_struct *conn;
+ files_struct finfo;
+ struct fd_handle fh;
+
+ conn = TALLOC_ZERO_P(ctx, connection_struct);
+ if (conn == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ if (!(conn->params = TALLOC_P(conn, struct share_params))) {
+ DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n"));
+ TALLOC_FREE(conn);
+ return NULL;
+ }
+
+ conn->params->service = -1;
+
+ set_conn_connectpath(conn, "/");
+
+ if (!smbd_vfs_init(conn)) {
+ DEBUG(0,("get_nt_acl_no_snum: Unable to create a fake connection struct!\n"));
+ conn_free_internal( conn );
+ return NULL;
+ }
+
+ ZERO_STRUCT( finfo );
+ ZERO_STRUCT( fh );
+
+ finfo.fnum = -1;
+ finfo.conn = conn;
+ finfo.fh = &fh;
+ finfo.fh->fd = -1;
+ finfo.fsp_name = CONST_DISCARD(char *,fname);
+
+ if (!NT_STATUS_IS_OK(posix_fget_nt_acl( &finfo, DACL_SECURITY_INFORMATION, &psd))) {
+ DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n"));
+ conn_free_internal( conn );
+ return NULL;
+ }
+
+ ret_sd = dup_sec_desc( ctx, psd );
+
+ conn_free_internal( conn );
+
+ return ret_sd;
+}
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
new file mode 100644
index 0000000000..b2d19e11e3
--- /dev/null
+++ b/source3/smbd/process.c
@@ -0,0 +1,2113 @@
+/*
+ Unix SMB/CIFS implementation.
+ process incoming packets - main loop
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Volker Lendecke 2005-2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern int smb_echo_count;
+
+/*
+ * 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;
+
+SIG_ATOMIC_T reload_after_sighup = 0;
+SIG_ATOMIC_T got_sig_term = 0;
+extern bool global_machine_password_needs_changing;
+extern int max_send;
+
+/* Accessor function for smb_read_error for smbd functions. */
+
+/****************************************************************************
+ Send an smb to a fd.
+****************************************************************************/
+
+bool srv_send_smb(int fd, char *buffer, bool do_encrypt)
+{
+ size_t len;
+ size_t nwritten=0;
+ ssize_t ret;
+ char *buf_out = buffer;
+
+ /* Sign the outgoing packet if required. */
+ srv_calculate_sign_mac(buf_out);
+
+ if (do_encrypt) {
+ NTSTATUS status = srv_encrypt_buffer(buffer, &buf_out);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("send_smb: SMB encryption failed "
+ "on outgoing packet! Error %s\n",
+ nt_errstr(status) ));
+ return false;
+ }
+ }
+
+ len = smb_len(buf_out) + 4;
+
+ while (nwritten < len) {
+ ret = write_data(fd,buf_out+nwritten,len - nwritten);
+ if (ret <= 0) {
+ DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n",
+ (int)len,(int)ret, strerror(errno) ));
+ srv_free_enc_buffer(buf_out);
+ return false;
+ }
+ nwritten += ret;
+ }
+
+ srv_free_enc_buffer(buf_out);
+ return true;
+}
+
+/*******************************************************************
+ Setup the word count and byte count for a smb message.
+********************************************************************/
+
+int srv_set_message(char *buf,
+ int num_words,
+ int num_bytes,
+ bool zero)
+{
+ if (zero && (num_words || num_bytes)) {
+ memset(buf + smb_size,'\0',num_words*2 + num_bytes);
+ }
+ SCVAL(buf,smb_wct,num_words);
+ SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
+ smb_setlen(buf,(smb_size + num_words*2 + num_bytes - 4));
+ return (smb_size + num_words*2 + num_bytes);
+}
+
+static bool valid_smb_header(const uint8_t *inbuf)
+{
+ if (is_encrypted_packet(inbuf)) {
+ return true;
+ }
+ return (strncmp(smb_base(inbuf),"\377SMB",4) == 0);
+}
+
+/* Socket functions for smbd packet processing. */
+
+static bool valid_packet_size(size_t len)
+{
+ /*
+ * A WRITEX with CAP_LARGE_WRITEX can be 64k worth of data plus 65 bytes
+ * of header. Don't print the error if this fits.... JRA.
+ */
+
+ if (len > (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE)) {
+ DEBUG(0,("Invalid packet length! (%lu bytes).\n",
+ (unsigned long)len));
+ return false;
+ }
+ return true;
+}
+
+static NTSTATUS read_packet_remainder(int fd, char *buffer,
+ unsigned int timeout, ssize_t len)
+{
+ if (len <= 0) {
+ return NT_STATUS_OK;
+ }
+
+ return read_socket_with_timeout(fd, buffer, len, len, timeout, NULL);
+}
+
+/****************************************************************************
+ Attempt a zerocopy writeX read. We know here that len > smb_size-4
+****************************************************************************/
+
+/*
+ * Unfortunately, earlier versions of smbclient/libsmbclient
+ * don't send this "standard" writeX header. I've fixed this
+ * for 3.2 but we'll use the old method with earlier versions.
+ * Windows and CIFSFS at least use this standard size. Not
+ * sure about MacOSX.
+ */
+
+#define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
+ (2*14) + /* word count (including bcc) */ \
+ 1 /* pad byte */)
+
+static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx,
+ const char lenbuf[4],
+ int fd, char **buffer,
+ unsigned int timeout,
+ size_t *p_unread,
+ size_t *len_ret)
+{
+ /* Size of a WRITEX call (+4 byte len). */
+ char writeX_header[4 + STANDARD_WRITE_AND_X_HEADER_SIZE];
+ ssize_t len = smb_len_large(lenbuf); /* Could be a UNIX large writeX. */
+ ssize_t toread;
+ NTSTATUS status;
+
+ memcpy(writeX_header, lenbuf, 4);
+
+ status = read_socket_with_timeout(
+ fd, writeX_header + 4,
+ STANDARD_WRITE_AND_X_HEADER_SIZE,
+ STANDARD_WRITE_AND_X_HEADER_SIZE,
+ timeout, NULL);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * Ok - now try and see if this is a possible
+ * valid writeX call.
+ */
+
+ if (is_valid_writeX_buffer((uint8_t *)writeX_header)) {
+ /*
+ * If the data offset is beyond what
+ * we've read, drain the extra bytes.
+ */
+ uint16_t doff = SVAL(writeX_header,smb_vwv11);
+ ssize_t newlen;
+
+ if (doff > STANDARD_WRITE_AND_X_HEADER_SIZE) {
+ size_t drain = doff - STANDARD_WRITE_AND_X_HEADER_SIZE;
+ if (drain_socket(smbd_server_fd(), drain) != drain) {
+ smb_panic("receive_smb_raw_talloc_partial_read:"
+ " failed to drain pending bytes");
+ }
+ } else {
+ doff = STANDARD_WRITE_AND_X_HEADER_SIZE;
+ }
+
+ /* Spoof down the length and null out the bcc. */
+ set_message_bcc(writeX_header, 0);
+ newlen = smb_len(writeX_header);
+
+ /* Copy the header we've written. */
+
+ *buffer = (char *)TALLOC_MEMDUP(mem_ctx,
+ writeX_header,
+ sizeof(writeX_header));
+
+ if (*buffer == NULL) {
+ DEBUG(0, ("Could not allocate inbuf of length %d\n",
+ (int)sizeof(writeX_header)));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Work out the remaining bytes. */
+ *p_unread = len - STANDARD_WRITE_AND_X_HEADER_SIZE;
+ *len_ret = newlen + 4;
+ return NT_STATUS_OK;
+ }
+
+ if (!valid_packet_size(len)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /*
+ * Not a valid writeX call. Just do the standard
+ * talloc and return.
+ */
+
+ *buffer = TALLOC_ARRAY(mem_ctx, char, len+4);
+
+ if (*buffer == NULL) {
+ DEBUG(0, ("Could not allocate inbuf of length %d\n",
+ (int)len+4));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Copy in what we already read. */
+ memcpy(*buffer,
+ writeX_header,
+ 4 + STANDARD_WRITE_AND_X_HEADER_SIZE);
+ toread = len - STANDARD_WRITE_AND_X_HEADER_SIZE;
+
+ if(toread > 0) {
+ status = read_packet_remainder(
+ fd, (*buffer) + 4 + STANDARD_WRITE_AND_X_HEADER_SIZE,
+ timeout, toread);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("receive_smb_raw_talloc_partial_read: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+ }
+
+ *len_ret = len + 4;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx, int fd,
+ char **buffer, unsigned int timeout,
+ size_t *p_unread, size_t *plen)
+{
+ char lenbuf[4];
+ size_t len;
+ int min_recv_size = lp_min_receive_file_size();
+ NTSTATUS status;
+
+ *p_unread = 0;
+
+ status = read_smb_length_return_keepalive(fd, lenbuf, timeout, &len);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("receive_smb_raw: %s\n", nt_errstr(status)));
+ return status;
+ }
+
+ if (CVAL(lenbuf,0) == 0 &&
+ min_recv_size &&
+ smb_len_large(lenbuf) > min_recv_size && /* Could be a UNIX large writeX. */
+ !srv_is_signing_active()) {
+
+ return receive_smb_raw_talloc_partial_read(
+ mem_ctx, lenbuf, fd, buffer, timeout, p_unread, plen);
+ }
+
+ if (!valid_packet_size(len)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /*
+ * The +4 here can't wrap, we've checked the length above already.
+ */
+
+ *buffer = TALLOC_ARRAY(mem_ctx, char, len+4);
+
+ if (*buffer == NULL) {
+ DEBUG(0, ("Could not allocate inbuf of length %d\n",
+ (int)len+4));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ memcpy(*buffer, lenbuf, sizeof(lenbuf));
+
+ status = read_packet_remainder(fd, (*buffer)+4, timeout, len);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ *plen = len + 4;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS receive_smb_talloc(TALLOC_CTX *mem_ctx, int fd,
+ char **buffer, unsigned int timeout,
+ size_t *p_unread, bool *p_encrypted,
+ size_t *p_len)
+{
+ size_t len = 0;
+ NTSTATUS status;
+
+ *p_encrypted = false;
+
+ status = receive_smb_raw_talloc(mem_ctx, fd, buffer, timeout,
+ p_unread, &len);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (is_encrypted_packet((uint8_t *)*buffer)) {
+ status = srv_decrypt_buffer(*buffer);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("receive_smb_talloc: SMB decryption failed on "
+ "incoming packet! Error %s\n",
+ nt_errstr(status) ));
+ return status;
+ }
+ *p_encrypted = true;
+ }
+
+ /* Check the incoming SMB signature. */
+ if (!srv_check_sign_mac(*buffer, true)) {
+ DEBUG(0, ("receive_smb: SMB Signature verification failed on "
+ "incoming packet!\n"));
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ *p_len = len;
+ return NT_STATUS_OK;
+}
+
+/*
+ * Initialize a struct smb_request from an inbuf
+ */
+
+void init_smb_request(struct smb_request *req,
+ const uint8 *inbuf,
+ size_t unread_bytes,
+ bool encrypted)
+{
+ size_t req_size = smb_len(inbuf) + 4;
+ /* Ensure we have at least smb_size bytes. */
+ if (req_size < smb_size) {
+ DEBUG(0,("init_smb_request: invalid request size %u\n",
+ (unsigned int)req_size ));
+ exit_server_cleanly("Invalid SMB request");
+ }
+ req->flags2 = SVAL(inbuf, smb_flg2);
+ req->smbpid = SVAL(inbuf, smb_pid);
+ req->mid = SVAL(inbuf, smb_mid);
+ req->vuid = SVAL(inbuf, smb_uid);
+ req->tid = SVAL(inbuf, smb_tid);
+ req->wct = CVAL(inbuf, smb_wct);
+ req->unread_bytes = unread_bytes;
+ req->encrypted = encrypted;
+ req->conn = conn_find(req->tid);
+
+ /* Ensure we have at least wct words and 2 bytes of bcc. */
+ if (smb_size + req->wct*2 > req_size) {
+ DEBUG(0,("init_smb_request: invalid wct number %u (size %u)\n",
+ (unsigned int)req->wct,
+ (unsigned int)req_size));
+ exit_server_cleanly("Invalid SMB request");
+ }
+ /* Ensure bcc is correct. */
+ if (((uint8 *)smb_buf(inbuf)) + smb_buflen(inbuf) > inbuf + req_size) {
+ DEBUG(0,("init_smb_request: invalid bcc number %u "
+ "(wct = %u, size %u)\n",
+ (unsigned int)smb_buflen(inbuf),
+ (unsigned int)req->wct,
+ (unsigned int)req_size));
+ exit_server_cleanly("Invalid SMB request");
+ }
+ req->inbuf = inbuf;
+ req->outbuf = NULL;
+}
+
+/****************************************************************************
+ structure to hold a linked list of queued messages.
+ for processing.
+****************************************************************************/
+
+static struct pending_message_list *deferred_open_queue;
+
+/****************************************************************************
+ Function to push a message onto the tail of a linked list of smb messages ready
+ for processing.
+****************************************************************************/
+
+static bool push_queued_message(struct smb_request *req,
+ struct timeval request_time,
+ struct timeval end_time,
+ char *private_data, size_t private_len)
+{
+ int msg_len = smb_len(req->inbuf) + 4;
+ struct pending_message_list *msg;
+
+ msg = TALLOC_ZERO_P(NULL, struct pending_message_list);
+
+ if(msg == NULL) {
+ DEBUG(0,("push_message: malloc fail (1)\n"));
+ return False;
+ }
+
+ msg->buf = data_blob_talloc(msg, req->inbuf, msg_len);
+ if(msg->buf.data == NULL) {
+ DEBUG(0,("push_message: malloc fail (2)\n"));
+ TALLOC_FREE(msg);
+ return False;
+ }
+
+ msg->request_time = request_time;
+ msg->end_time = end_time;
+ msg->encrypted = req->encrypted;
+
+ if (private_data) {
+ msg->private_data = data_blob_talloc(msg, private_data,
+ private_len);
+ if (msg->private_data.data == NULL) {
+ DEBUG(0,("push_message: malloc fail (3)\n"));
+ TALLOC_FREE(msg);
+ return False;
+ }
+ }
+
+ DLIST_ADD_END(deferred_open_queue, msg, struct pending_message_list *);
+
+ DEBUG(10,("push_message: pushed message length %u on "
+ "deferred_open_queue\n", (unsigned int)msg_len));
+
+ return True;
+}
+
+/****************************************************************************
+ Function to delete a sharing violation open message by mid.
+****************************************************************************/
+
+void remove_deferred_open_smb_message(uint16 mid)
+{
+ struct pending_message_list *pml;
+
+ for (pml = deferred_open_queue; pml; pml = pml->next) {
+ if (mid == SVAL(pml->buf.data,smb_mid)) {
+ DEBUG(10,("remove_sharing_violation_open_smb_message: "
+ "deleting mid %u len %u\n",
+ (unsigned int)mid,
+ (unsigned int)pml->buf.length ));
+ DLIST_REMOVE(deferred_open_queue, pml);
+ TALLOC_FREE(pml);
+ return;
+ }
+ }
+}
+
+/****************************************************************************
+ Move a sharing violation open retry message to the front of the list and
+ schedule it for immediate processing.
+****************************************************************************/
+
+void schedule_deferred_open_smb_message(uint16 mid)
+{
+ struct pending_message_list *pml;
+ int i = 0;
+
+ for (pml = deferred_open_queue; pml; pml = pml->next) {
+ uint16 msg_mid = SVAL(pml->buf.data,smb_mid);
+ DEBUG(10,("schedule_deferred_open_smb_message: [%d] msg_mid = %u\n", i++,
+ (unsigned int)msg_mid ));
+ if (mid == msg_mid) {
+ DEBUG(10,("schedule_deferred_open_smb_message: scheduling mid %u\n",
+ mid ));
+ pml->end_time.tv_sec = 0;
+ pml->end_time.tv_usec = 0;
+ DLIST_PROMOTE(deferred_open_queue, pml);
+ return;
+ }
+ }
+
+ DEBUG(10,("schedule_deferred_open_smb_message: failed to find message mid %u\n",
+ mid ));
+}
+
+/****************************************************************************
+ Return true if this mid is on the deferred queue.
+****************************************************************************/
+
+bool open_was_deferred(uint16 mid)
+{
+ struct pending_message_list *pml;
+
+ for (pml = deferred_open_queue; pml; pml = pml->next) {
+ if (SVAL(pml->buf.data,smb_mid) == mid) {
+ return True;
+ }
+ }
+ return False;
+}
+
+/****************************************************************************
+ Return the message queued by this mid.
+****************************************************************************/
+
+struct pending_message_list *get_open_deferred_message(uint16 mid)
+{
+ struct pending_message_list *pml;
+
+ for (pml = deferred_open_queue; pml; pml = pml->next) {
+ if (SVAL(pml->buf.data,smb_mid) == mid) {
+ return pml;
+ }
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ Function to push a deferred open smb message onto a linked list of local smb
+ messages ready for processing.
+****************************************************************************/
+
+bool push_deferred_smb_message(struct smb_request *req,
+ struct timeval request_time,
+ struct timeval timeout,
+ char *private_data, size_t priv_len)
+{
+ struct timeval end_time;
+
+ if (req->unread_bytes) {
+ DEBUG(0,("push_deferred_smb_message: logic error ! "
+ "unread_bytes = %u\n",
+ (unsigned int)req->unread_bytes ));
+ smb_panic("push_deferred_smb_message: "
+ "logic error unread_bytes != 0" );
+ }
+
+ end_time = timeval_sum(&request_time, &timeout);
+
+ DEBUG(10,("push_deferred_open_smb_message: pushing message len %u mid %u "
+ "timeout time [%u.%06u]\n",
+ (unsigned int) smb_len(req->inbuf)+4, (unsigned int)req->mid,
+ (unsigned int)end_time.tv_sec,
+ (unsigned int)end_time.tv_usec));
+
+ return push_queued_message(req, request_time, end_time,
+ private_data, priv_len);
+}
+
+struct idle_event {
+ struct timed_event *te;
+ struct timeval interval;
+ char *name;
+ bool (*handler)(const struct timeval *now, void *private_data);
+ void *private_data;
+};
+
+static void idle_event_handler(struct event_context *ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ struct idle_event *event =
+ talloc_get_type_abort(private_data, struct idle_event);
+
+ TALLOC_FREE(event->te);
+
+ if (!event->handler(now, event->private_data)) {
+ /* Don't repeat, delete ourselves */
+ TALLOC_FREE(event);
+ return;
+ }
+
+ event->te = event_add_timed(ctx, event,
+ timeval_sum(now, &event->interval),
+ event->name,
+ idle_event_handler, event);
+
+ /* We can't do much but fail here. */
+ SMB_ASSERT(event->te != NULL);
+}
+
+struct idle_event *event_add_idle(struct event_context *event_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct timeval interval,
+ const char *name,
+ bool (*handler)(const struct timeval *now,
+ void *private_data),
+ void *private_data)
+{
+ struct idle_event *result;
+ struct timeval now = timeval_current();
+
+ result = TALLOC_P(mem_ctx, struct idle_event);
+ if (result == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ result->interval = interval;
+ result->handler = handler;
+ result->private_data = private_data;
+
+ if (!(result->name = talloc_asprintf(result, "idle_evt(%s)", name))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ result->te = event_add_timed(event_ctx, result,
+ timeval_sum(&now, &interval),
+ result->name,
+ idle_event_handler, result);
+ if (result->te == NULL) {
+ DEBUG(0, ("event_add_timed failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+/****************************************************************************
+ Do all async processing in here. This includes kernel oplock messages, change
+ notify events etc.
+****************************************************************************/
+
+static void async_processing(fd_set *pfds)
+{
+ DEBUG(10,("async_processing: Doing async processing.\n"));
+
+ process_aio_queue();
+
+ process_kernel_oplocks(smbd_messaging_context(), pfds);
+
+ /* Do the aio check again after receive_local_message as it does a
+ select and may have eaten our signal. */
+ /* Is this till true? -- vl */
+ process_aio_queue();
+
+ if (got_sig_term) {
+ exit_server_cleanly("termination signal");
+ }
+
+ /* check for sighup processing */
+ if (reload_after_sighup) {
+ change_to_root_user();
+ DEBUG(1,("Reloading services after SIGHUP\n"));
+ reload_services(False);
+ reload_after_sighup = 0;
+ }
+}
+
+/****************************************************************************
+ Add a fd to the set we will be select(2)ing on.
+****************************************************************************/
+
+static int select_on_fd(int fd, int maxfd, fd_set *fds)
+{
+ if (fd != -1) {
+ FD_SET(fd, fds);
+ maxfd = MAX(maxfd, fd);
+ }
+
+ return maxfd;
+}
+
+/****************************************************************************
+ Do a select on an two fd's - with timeout.
+
+ If a local udp message has been pushed onto the
+ queue (this can only happen during oplock break
+ processing) call async_processing()
+
+ If a pending smb message has been pushed onto the
+ queue (this can only happen during oplock break
+ processing) return this next.
+
+ If the first smbfd is ready then read an smb from it.
+ if the second (loopback UDP) fd is ready then read a message
+ from it and setup the buffer header to identify the length
+ and from address.
+ Returns False on timeout or error.
+ Else returns True.
+
+The timeout is in milliseconds
+****************************************************************************/
+
+static NTSTATUS receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer,
+ size_t *buffer_len, int timeout,
+ size_t *p_unread, bool *p_encrypted)
+{
+ fd_set r_fds, w_fds;
+ int selrtn;
+ struct timeval to;
+ int maxfd = 0;
+ size_t len = 0;
+ NTSTATUS status;
+
+ *p_unread = 0;
+
+ again:
+
+ if (timeout >= 0) {
+ to.tv_sec = timeout / 1000;
+ to.tv_usec = (timeout % 1000) * 1000;
+ } else {
+ to.tv_sec = SMBD_SELECT_TIMEOUT;
+ to.tv_usec = 0;
+ }
+
+ /*
+ * Note that this call must be before processing any SMB
+ * messages as we need to synchronously process any messages
+ * we may have sent to ourselves from the previous SMB.
+ */
+ message_dispatch(smbd_messaging_context());
+
+ /*
+ * Check to see if we already have a message on the deferred open queue
+ * and it's time to schedule.
+ */
+ if(deferred_open_queue != NULL) {
+ bool pop_message = False;
+ struct pending_message_list *msg = deferred_open_queue;
+
+ if (timeval_is_zero(&msg->end_time)) {
+ pop_message = True;
+ } else {
+ struct timeval tv;
+ SMB_BIG_INT tdif;
+
+ GetTimeOfDay(&tv);
+ tdif = usec_time_diff(&msg->end_time, &tv);
+ if (tdif <= 0) {
+ /* Timed out. Schedule...*/
+ pop_message = True;
+ DEBUG(10,("receive_message_or_smb: queued message timed out.\n"));
+ } else {
+ /* Make a more accurate select timeout. */
+ to.tv_sec = tdif / 1000000;
+ to.tv_usec = tdif % 1000000;
+ DEBUG(10,("receive_message_or_smb: select with timeout of [%u.%06u]\n",
+ (unsigned int)to.tv_sec, (unsigned int)to.tv_usec ));
+ }
+ }
+
+ if (pop_message) {
+
+ *buffer = (char *)talloc_memdup(mem_ctx, msg->buf.data,
+ msg->buf.length);
+ if (*buffer == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ *buffer_len = msg->buf.length;
+ *p_encrypted = msg->encrypted;
+
+ /* We leave this message on the queue so the open code can
+ know this is a retry. */
+ DEBUG(5,("receive_message_or_smb: returning deferred open smb message.\n"));
+ return NT_STATUS_OK;
+ }
+ }
+
+ /*
+ * Setup the select fd sets.
+ */
+
+ FD_ZERO(&r_fds);
+ FD_ZERO(&w_fds);
+
+ /*
+ * Ensure we process oplock break messages by preference.
+ * We have to do this before the select, after the select
+ * and if the select returns EINTR. This is due to the fact
+ * that the selects called from async_processing can eat an EINTR
+ * caused by a signal (we can't take the break message there).
+ * This is hideously complex - *MUST* be simplified for 3.0 ! JRA.
+ */
+
+ if (oplock_message_waiting(&r_fds)) {
+ DEBUG(10,("receive_message_or_smb: oplock_message is waiting.\n"));
+ async_processing(&r_fds);
+ /*
+ * After async processing we must go and do the select again, as
+ * the state of the flag in fds for the server file descriptor is
+ * indeterminate - we may have done I/O on it in the oplock processing. JRA.
+ */
+ goto again;
+ }
+
+ /*
+ * Are there any timed events waiting ? If so, ensure we don't
+ * select for longer than it would take to wait for them.
+ */
+
+ {
+ struct timeval now;
+ GetTimeOfDay(&now);
+
+ event_add_to_select_args(smbd_event_context(), &now,
+ &r_fds, &w_fds, &to, &maxfd);
+ }
+
+ if (timeval_is_zero(&to)) {
+ /* Process a timed event now... */
+ if (run_events(smbd_event_context(), 0, NULL, NULL)) {
+ goto again;
+ }
+ }
+
+ {
+ int sav;
+ START_PROFILE(smbd_idle);
+
+ maxfd = select_on_fd(smbd_server_fd(), maxfd, &r_fds);
+ maxfd = select_on_fd(oplock_notify_fd(), maxfd, &r_fds);
+
+ selrtn = sys_select(maxfd+1,&r_fds,&w_fds,NULL,&to);
+ sav = errno;
+
+ END_PROFILE(smbd_idle);
+ errno = sav;
+ }
+
+ if (run_events(smbd_event_context(), selrtn, &r_fds, &w_fds)) {
+ goto again;
+ }
+
+ /* if we get EINTR then maybe we have received an oplock
+ signal - treat this as select returning 1. This is ugly, but
+ is the best we can do until the oplock code knows more about
+ signals */
+ if (selrtn == -1 && errno == EINTR) {
+ async_processing(&r_fds);
+ /*
+ * After async processing we must go and do the select again, as
+ * the state of the flag in fds for the server file descriptor is
+ * indeterminate - we may have done I/O on it in the oplock processing. JRA.
+ */
+ goto again;
+ }
+
+ /* Check if error */
+ if (selrtn == -1) {
+ /* something is wrong. Maybe the socket is dead? */
+ return map_nt_error_from_unix(errno);
+ }
+
+ /* Did we timeout ? */
+ if (selrtn == 0) {
+ return NT_STATUS_IO_TIMEOUT;
+ }
+
+ /*
+ * Ensure we process oplock break messages by preference.
+ * This is IMPORTANT ! Otherwise we can starve other processes
+ * sending us an oplock break message. JRA.
+ */
+
+ if (oplock_message_waiting(&r_fds)) {
+ async_processing(&r_fds);
+ /*
+ * After async processing we must go and do the select again, as
+ * the state of the flag in fds for the server file descriptor is
+ * indeterminate - we may have done I/O on it in the oplock processing. JRA.
+ */
+ goto again;
+ }
+
+ /*
+ * We've just woken up from a protentially long select sleep.
+ * Ensure we process local messages as we need to synchronously
+ * process any messages from other smbd's to avoid file rename race
+ * conditions. This call is cheap if there are no messages waiting.
+ * JRA.
+ */
+ message_dispatch(smbd_messaging_context());
+
+ status = receive_smb_talloc(mem_ctx, smbd_server_fd(), buffer, 0,
+ p_unread, p_encrypted, &len);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ *buffer_len = len;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * Only allow 5 outstanding trans requests. We're allocating memory, so
+ * prevent a DoS.
+ */
+
+NTSTATUS allow_new_trans(struct trans_state *list, int mid)
+{
+ int count = 0;
+ for (; list != NULL; list = list->next) {
+
+ if (list->mid == mid) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ count += 1;
+ }
+ if (count > 5) {
+ return NT_STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ We're terminating and have closed all our files/connections etc.
+ If there are any pending local messages we need to respond to them
+ before termination so that other smbds don't think we just died whilst
+ holding oplocks.
+****************************************************************************/
+
+void respond_to_all_remaining_local_messages(void)
+{
+ /*
+ * Assert we have no exclusive open oplocks.
+ */
+
+ if(get_number_of_exclusive_open_oplocks()) {
+ DEBUG(0,("respond_to_all_remaining_local_messages: PANIC : we have %d exclusive oplocks.\n",
+ get_number_of_exclusive_open_oplocks() ));
+ return;
+ }
+
+ process_kernel_oplocks(smbd_messaging_context(), NULL);
+
+ return;
+}
+
+
+/*
+These flags determine some of the permissions required to do an operation
+
+Note that I don't set NEED_WRITE on some write operations because they
+are used by some brain-dead clients when printing, and I don't want to
+force write permissions on print services.
+*/
+#define AS_USER (1<<0)
+#define NEED_WRITE (1<<1) /* Must be paired with AS_USER */
+#define TIME_INIT (1<<2)
+#define CAN_IPC (1<<3) /* Must be paired with AS_USER */
+#define AS_GUEST (1<<5) /* Must *NOT* be paired with AS_USER */
+#define DO_CHDIR (1<<6)
+
+/*
+ define a list of possible SMB messages and their corresponding
+ functions. Any message that has a NULL function is unimplemented -
+ please feel free to contribute implementations!
+*/
+static const struct smb_message_struct {
+ const char *name;
+ void (*fn_new)(struct smb_request *req);
+ int flags;
+} smb_messages[256] = {
+
+/* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
+/* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
+/* 0x02 */ { "SMBopen",reply_open,AS_USER },
+/* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
+/* 0x04 */ { "SMBclose",reply_close,AS_USER | CAN_IPC },
+/* 0x05 */ { "SMBflush",reply_flush,AS_USER},
+/* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE },
+/* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE },
+/* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
+/* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
+/* 0x0a */ { "SMBread",reply_read,AS_USER},
+/* 0x0b */ { "SMBwrite",reply_write,AS_USER | CAN_IPC },
+/* 0x0c */ { "SMBlock",reply_lock,AS_USER},
+/* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
+/* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
+/* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
+/* 0x10 */ { "SMBcheckpath",reply_checkpath,AS_USER},
+/* 0x11 */ { "SMBexit",reply_exit,DO_CHDIR},
+/* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
+/* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
+/* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
+/* 0x15 */ { NULL, NULL, 0 },
+/* 0x16 */ { NULL, NULL, 0 },
+/* 0x17 */ { NULL, NULL, 0 },
+/* 0x18 */ { NULL, NULL, 0 },
+/* 0x19 */ { NULL, NULL, 0 },
+/* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
+/* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
+/* 0x1c */ { "SMBreadBs",reply_readbs,AS_USER },
+/* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
+/* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
+/* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
+/* 0x20 */ { "SMBwritec", NULL,0},
+/* 0x21 */ { NULL, NULL, 0 },
+/* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
+/* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
+/* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
+/* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC },
+/* 0x26 */ { "SMBtranss",reply_transs,AS_USER | CAN_IPC},
+/* 0x27 */ { "SMBioctl",reply_ioctl,0},
+/* 0x28 */ { "SMBioctls", NULL,AS_USER},
+/* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE },
+/* 0x2a */ { "SMBmove", NULL,AS_USER | NEED_WRITE },
+/* 0x2b */ { "SMBecho",reply_echo,0},
+/* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
+/* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC },
+/* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
+/* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
+/* 0x30 */ { NULL, NULL, 0 },
+/* 0x31 */ { NULL, NULL, 0 },
+/* 0x32 */ { "SMBtrans2",reply_trans2, AS_USER | CAN_IPC },
+/* 0x33 */ { "SMBtranss2",reply_transs2, AS_USER},
+/* 0x34 */ { "SMBfindclose",reply_findclose,AS_USER},
+/* 0x35 */ { "SMBfindnclose",reply_findnclose,AS_USER},
+/* 0x36 */ { NULL, NULL, 0 },
+/* 0x37 */ { NULL, NULL, 0 },
+/* 0x38 */ { NULL, NULL, 0 },
+/* 0x39 */ { NULL, NULL, 0 },
+/* 0x3a */ { NULL, NULL, 0 },
+/* 0x3b */ { NULL, NULL, 0 },
+/* 0x3c */ { NULL, NULL, 0 },
+/* 0x3d */ { NULL, NULL, 0 },
+/* 0x3e */ { NULL, NULL, 0 },
+/* 0x3f */ { NULL, NULL, 0 },
+/* 0x40 */ { NULL, NULL, 0 },
+/* 0x41 */ { NULL, NULL, 0 },
+/* 0x42 */ { NULL, NULL, 0 },
+/* 0x43 */ { NULL, NULL, 0 },
+/* 0x44 */ { NULL, NULL, 0 },
+/* 0x45 */ { NULL, NULL, 0 },
+/* 0x46 */ { NULL, NULL, 0 },
+/* 0x47 */ { NULL, NULL, 0 },
+/* 0x48 */ { NULL, NULL, 0 },
+/* 0x49 */ { NULL, NULL, 0 },
+/* 0x4a */ { NULL, NULL, 0 },
+/* 0x4b */ { NULL, NULL, 0 },
+/* 0x4c */ { NULL, NULL, 0 },
+/* 0x4d */ { NULL, NULL, 0 },
+/* 0x4e */ { NULL, NULL, 0 },
+/* 0x4f */ { NULL, NULL, 0 },
+/* 0x50 */ { NULL, NULL, 0 },
+/* 0x51 */ { NULL, NULL, 0 },
+/* 0x52 */ { NULL, NULL, 0 },
+/* 0x53 */ { NULL, NULL, 0 },
+/* 0x54 */ { NULL, NULL, 0 },
+/* 0x55 */ { NULL, NULL, 0 },
+/* 0x56 */ { NULL, NULL, 0 },
+/* 0x57 */ { NULL, NULL, 0 },
+/* 0x58 */ { NULL, NULL, 0 },
+/* 0x59 */ { NULL, NULL, 0 },
+/* 0x5a */ { NULL, NULL, 0 },
+/* 0x5b */ { NULL, NULL, 0 },
+/* 0x5c */ { NULL, NULL, 0 },
+/* 0x5d */ { NULL, NULL, 0 },
+/* 0x5e */ { NULL, NULL, 0 },
+/* 0x5f */ { NULL, NULL, 0 },
+/* 0x60 */ { NULL, NULL, 0 },
+/* 0x61 */ { NULL, NULL, 0 },
+/* 0x62 */ { NULL, NULL, 0 },
+/* 0x63 */ { NULL, NULL, 0 },
+/* 0x64 */ { NULL, NULL, 0 },
+/* 0x65 */ { NULL, NULL, 0 },
+/* 0x66 */ { NULL, NULL, 0 },
+/* 0x67 */ { NULL, NULL, 0 },
+/* 0x68 */ { NULL, NULL, 0 },
+/* 0x69 */ { NULL, NULL, 0 },
+/* 0x6a */ { NULL, NULL, 0 },
+/* 0x6b */ { NULL, NULL, 0 },
+/* 0x6c */ { NULL, NULL, 0 },
+/* 0x6d */ { NULL, NULL, 0 },
+/* 0x6e */ { NULL, NULL, 0 },
+/* 0x6f */ { NULL, NULL, 0 },
+/* 0x70 */ { "SMBtcon",reply_tcon,0},
+/* 0x71 */ { "SMBtdis",reply_tdis,DO_CHDIR},
+/* 0x72 */ { "SMBnegprot",reply_negprot,0},
+/* 0x73 */ { "SMBsesssetupX",reply_sesssetup_and_X,0},
+/* 0x74 */ { "SMBulogoffX",reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
+/* 0x75 */ { "SMBtconX",reply_tcon_and_X,0},
+/* 0x76 */ { NULL, NULL, 0 },
+/* 0x77 */ { NULL, NULL, 0 },
+/* 0x78 */ { NULL, NULL, 0 },
+/* 0x79 */ { NULL, NULL, 0 },
+/* 0x7a */ { NULL, NULL, 0 },
+/* 0x7b */ { NULL, NULL, 0 },
+/* 0x7c */ { NULL, NULL, 0 },
+/* 0x7d */ { NULL, NULL, 0 },
+/* 0x7e */ { NULL, NULL, 0 },
+/* 0x7f */ { NULL, NULL, 0 },
+/* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
+/* 0x81 */ { "SMBsearch",reply_search,AS_USER},
+/* 0x82 */ { "SMBffirst",reply_search,AS_USER},
+/* 0x83 */ { "SMBfunique",reply_search,AS_USER},
+/* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
+/* 0x85 */ { NULL, NULL, 0 },
+/* 0x86 */ { NULL, NULL, 0 },
+/* 0x87 */ { NULL, NULL, 0 },
+/* 0x88 */ { NULL, NULL, 0 },
+/* 0x89 */ { NULL, NULL, 0 },
+/* 0x8a */ { NULL, NULL, 0 },
+/* 0x8b */ { NULL, NULL, 0 },
+/* 0x8c */ { NULL, NULL, 0 },
+/* 0x8d */ { NULL, NULL, 0 },
+/* 0x8e */ { NULL, NULL, 0 },
+/* 0x8f */ { NULL, NULL, 0 },
+/* 0x90 */ { NULL, NULL, 0 },
+/* 0x91 */ { NULL, NULL, 0 },
+/* 0x92 */ { NULL, NULL, 0 },
+/* 0x93 */ { NULL, NULL, 0 },
+/* 0x94 */ { NULL, NULL, 0 },
+/* 0x95 */ { NULL, NULL, 0 },
+/* 0x96 */ { NULL, NULL, 0 },
+/* 0x97 */ { NULL, NULL, 0 },
+/* 0x98 */ { NULL, NULL, 0 },
+/* 0x99 */ { NULL, NULL, 0 },
+/* 0x9a */ { NULL, NULL, 0 },
+/* 0x9b */ { NULL, NULL, 0 },
+/* 0x9c */ { NULL, NULL, 0 },
+/* 0x9d */ { NULL, NULL, 0 },
+/* 0x9e */ { NULL, NULL, 0 },
+/* 0x9f */ { NULL, NULL, 0 },
+/* 0xa0 */ { "SMBnttrans",reply_nttrans, AS_USER | CAN_IPC },
+/* 0xa1 */ { "SMBnttranss",reply_nttranss, AS_USER | CAN_IPC },
+/* 0xa2 */ { "SMBntcreateX",reply_ntcreate_and_X, AS_USER | CAN_IPC },
+/* 0xa3 */ { NULL, NULL, 0 },
+/* 0xa4 */ { "SMBntcancel",reply_ntcancel, 0 },
+/* 0xa5 */ { "SMBntrename",reply_ntrename, AS_USER | NEED_WRITE },
+/* 0xa6 */ { NULL, NULL, 0 },
+/* 0xa7 */ { NULL, NULL, 0 },
+/* 0xa8 */ { NULL, NULL, 0 },
+/* 0xa9 */ { NULL, NULL, 0 },
+/* 0xaa */ { NULL, NULL, 0 },
+/* 0xab */ { NULL, NULL, 0 },
+/* 0xac */ { NULL, NULL, 0 },
+/* 0xad */ { NULL, NULL, 0 },
+/* 0xae */ { NULL, NULL, 0 },
+/* 0xaf */ { NULL, NULL, 0 },
+/* 0xb0 */ { NULL, NULL, 0 },
+/* 0xb1 */ { NULL, NULL, 0 },
+/* 0xb2 */ { NULL, NULL, 0 },
+/* 0xb3 */ { NULL, NULL, 0 },
+/* 0xb4 */ { NULL, NULL, 0 },
+/* 0xb5 */ { NULL, NULL, 0 },
+/* 0xb6 */ { NULL, NULL, 0 },
+/* 0xb7 */ { NULL, NULL, 0 },
+/* 0xb8 */ { NULL, NULL, 0 },
+/* 0xb9 */ { NULL, NULL, 0 },
+/* 0xba */ { NULL, NULL, 0 },
+/* 0xbb */ { NULL, NULL, 0 },
+/* 0xbc */ { NULL, NULL, 0 },
+/* 0xbd */ { NULL, NULL, 0 },
+/* 0xbe */ { NULL, NULL, 0 },
+/* 0xbf */ { NULL, NULL, 0 },
+/* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER},
+/* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
+/* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
+/* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
+/* 0xc4 */ { NULL, NULL, 0 },
+/* 0xc5 */ { NULL, NULL, 0 },
+/* 0xc6 */ { NULL, NULL, 0 },
+/* 0xc7 */ { NULL, NULL, 0 },
+/* 0xc8 */ { NULL, NULL, 0 },
+/* 0xc9 */ { NULL, NULL, 0 },
+/* 0xca */ { NULL, NULL, 0 },
+/* 0xcb */ { NULL, NULL, 0 },
+/* 0xcc */ { NULL, NULL, 0 },
+/* 0xcd */ { NULL, NULL, 0 },
+/* 0xce */ { NULL, NULL, 0 },
+/* 0xcf */ { NULL, NULL, 0 },
+/* 0xd0 */ { "SMBsends",reply_sends,AS_GUEST},
+/* 0xd1 */ { "SMBsendb", NULL,AS_GUEST},
+/* 0xd2 */ { "SMBfwdname", NULL,AS_GUEST},
+/* 0xd3 */ { "SMBcancelf", NULL,AS_GUEST},
+/* 0xd4 */ { "SMBgetmac", NULL,AS_GUEST},
+/* 0xd5 */ { "SMBsendstrt",reply_sendstrt,AS_GUEST},
+/* 0xd6 */ { "SMBsendend",reply_sendend,AS_GUEST},
+/* 0xd7 */ { "SMBsendtxt",reply_sendtxt,AS_GUEST},
+/* 0xd8 */ { NULL, NULL, 0 },
+/* 0xd9 */ { NULL, NULL, 0 },
+/* 0xda */ { NULL, NULL, 0 },
+/* 0xdb */ { NULL, NULL, 0 },
+/* 0xdc */ { NULL, NULL, 0 },
+/* 0xdd */ { NULL, NULL, 0 },
+/* 0xde */ { NULL, NULL, 0 },
+/* 0xdf */ { NULL, NULL, 0 },
+/* 0xe0 */ { NULL, NULL, 0 },
+/* 0xe1 */ { NULL, NULL, 0 },
+/* 0xe2 */ { NULL, NULL, 0 },
+/* 0xe3 */ { NULL, NULL, 0 },
+/* 0xe4 */ { NULL, NULL, 0 },
+/* 0xe5 */ { NULL, NULL, 0 },
+/* 0xe6 */ { NULL, NULL, 0 },
+/* 0xe7 */ { NULL, NULL, 0 },
+/* 0xe8 */ { NULL, NULL, 0 },
+/* 0xe9 */ { NULL, NULL, 0 },
+/* 0xea */ { NULL, NULL, 0 },
+/* 0xeb */ { NULL, NULL, 0 },
+/* 0xec */ { NULL, NULL, 0 },
+/* 0xed */ { NULL, NULL, 0 },
+/* 0xee */ { NULL, NULL, 0 },
+/* 0xef */ { NULL, NULL, 0 },
+/* 0xf0 */ { NULL, NULL, 0 },
+/* 0xf1 */ { NULL, NULL, 0 },
+/* 0xf2 */ { NULL, NULL, 0 },
+/* 0xf3 */ { NULL, NULL, 0 },
+/* 0xf4 */ { NULL, NULL, 0 },
+/* 0xf5 */ { NULL, NULL, 0 },
+/* 0xf6 */ { NULL, NULL, 0 },
+/* 0xf7 */ { NULL, NULL, 0 },
+/* 0xf8 */ { NULL, NULL, 0 },
+/* 0xf9 */ { NULL, NULL, 0 },
+/* 0xfa */ { NULL, NULL, 0 },
+/* 0xfb */ { NULL, NULL, 0 },
+/* 0xfc */ { NULL, NULL, 0 },
+/* 0xfd */ { NULL, NULL, 0 },
+/* 0xfe */ { NULL, NULL, 0 },
+/* 0xff */ { NULL, NULL, 0 }
+
+};
+
+/*******************************************************************
+ allocate and initialize a reply packet
+********************************************************************/
+
+bool create_outbuf(TALLOC_CTX *mem_ctx, const char *inbuf, char **outbuf,
+ uint8_t num_words, uint32_t num_bytes)
+{
+ /*
+ * Protect against integer wrap
+ */
+ if ((num_bytes > 0xffffff)
+ || ((num_bytes + smb_size + num_words*2) > 0xffffff)) {
+ char *msg;
+ if (asprintf(&msg, "num_bytes too large: %u",
+ (unsigned)num_bytes) == -1) {
+ msg = CONST_DISCARD(char *, "num_bytes too large");
+ }
+ smb_panic(msg);
+ }
+
+ *outbuf = TALLOC_ARRAY(mem_ctx, char,
+ smb_size + num_words*2 + num_bytes);
+ if (*outbuf == NULL) {
+ return false;
+ }
+
+ construct_reply_common(inbuf, *outbuf);
+ srv_set_message(*outbuf, num_words, num_bytes, false);
+ /*
+ * Zero out the word area, the caller has to take care of the bcc area
+ * himself
+ */
+ if (num_words != 0) {
+ memset(*outbuf + smb_vwv0, 0, num_words*2);
+ }
+
+ return true;
+}
+
+void reply_outbuf(struct smb_request *req, uint8 num_words, uint32 num_bytes)
+{
+ char *outbuf;
+ if (!create_outbuf(req, (char *)req->inbuf, &outbuf, num_words,
+ num_bytes)) {
+ smb_panic("could not allocate output buffer\n");
+ }
+ req->outbuf = (uint8_t *)outbuf;
+}
+
+
+/*******************************************************************
+ Dump a packet to a file.
+********************************************************************/
+
+static void smb_dump(const char *name, int type, const char *data, ssize_t len)
+{
+ int fd, i;
+ char *fname = NULL;
+ if (DEBUGLEVEL < 50) {
+ return;
+ }
+
+ if (len < 4) len = smb_len(data)+4;
+ for (i=1;i<100;i++) {
+ if (asprintf(&fname, "/tmp/%s.%d.%s", name, i,
+ type ? "req" : "resp") == -1) {
+ return;
+ }
+ fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
+ if (fd != -1 || errno != EEXIST) break;
+ }
+ if (fd != -1) {
+ ssize_t ret = write(fd, data, len);
+ if (ret != len)
+ DEBUG(0,("smb_dump: problem: write returned %d\n", (int)ret ));
+ close(fd);
+ DEBUG(0,("created %s len %lu\n", fname, (unsigned long)len));
+ }
+ SAFE_FREE(fname);
+}
+
+/****************************************************************************
+ Prepare everything for calling the actual request function, and potentially
+ call the request function via the "new" interface.
+
+ Return False if the "legacy" function needs to be called, everything is
+ prepared.
+
+ Return True if we're done.
+
+ I know this API sucks, but it is the one with the least code change I could
+ find.
+****************************************************************************/
+
+static connection_struct *switch_message(uint8 type, struct smb_request *req, int size)
+{
+ int flags;
+ uint16 session_tag;
+ connection_struct *conn = NULL;
+
+ static uint16 last_session_tag = UID_FIELD_INVALID;
+
+ errno = 0;
+
+ /* Make sure this is an SMB packet. smb_size contains NetBIOS header
+ * so subtract 4 from it. */
+ if (!valid_smb_header(req->inbuf)
+ || (size < (smb_size - 4))) {
+ DEBUG(2,("Non-SMB packet of length %d. Terminating server\n",
+ smb_len(req->inbuf)));
+ exit_server_cleanly("Non-SMB packet");
+ }
+
+ if (smb_messages[type].fn_new == NULL) {
+ DEBUG(0,("Unknown message type %d!\n",type));
+ smb_dump("Unknown", 1, (char *)req->inbuf, size);
+ reply_unknown_new(req, type);
+ return NULL;
+ }
+
+ flags = smb_messages[type].flags;
+
+ /* In share mode security we must ignore the vuid. */
+ session_tag = (lp_security() == SEC_SHARE)
+ ? UID_FIELD_INVALID : req->vuid;
+ conn = req->conn;
+
+ DEBUG(3,("switch message %s (pid %d) conn 0x%lx\n", smb_fn_name(type),
+ (int)sys_getpid(), (unsigned long)conn));
+
+ smb_dump(smb_fn_name(type), 1, (char *)req->inbuf, size);
+
+ /* Ensure this value is replaced in the incoming packet. */
+ SSVAL(req->inbuf,smb_uid,session_tag);
+
+ /*
+ * Ensure the correct username is in current_user_info. This is a
+ * really ugly bugfix for problems with multiple session_setup_and_X's
+ * being done and allowing %U and %G substitutions to work correctly.
+ * There is a reason this code is done here, don't move it unless you
+ * know what you're doing... :-).
+ * JRA.
+ */
+
+ if (session_tag != last_session_tag) {
+ user_struct *vuser = NULL;
+
+ last_session_tag = session_tag;
+ if(session_tag != UID_FIELD_INVALID) {
+ vuser = get_valid_user_struct(session_tag);
+ if (vuser) {
+ set_current_user_info(
+ vuser->server_info->sanitized_username,
+ vuser->server_info->unix_name,
+ pdb_get_fullname(vuser->server_info
+ ->sam_account),
+ pdb_get_domain(vuser->server_info
+ ->sam_account));
+ }
+ }
+ }
+
+ /* Does this call need to be run as the connected user? */
+ if (flags & AS_USER) {
+
+ /* Does this call need a valid tree connection? */
+ if (!conn) {
+ /*
+ * Amazingly, the error code depends on the command
+ * (from Samba4).
+ */
+ if (type == SMBntcreateX) {
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ } else {
+ reply_doserror(req, ERRSRV, ERRinvnid);
+ }
+ return NULL;
+ }
+
+ if (!change_to_user(conn,session_tag)) {
+ reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRbaduid));
+ return conn;
+ }
+
+ /* All NEED_WRITE and CAN_IPC flags must also have AS_USER. */
+
+ /* Does it need write permission? */
+ if ((flags & NEED_WRITE) && !CAN_WRITE(conn)) {
+ reply_nterror(req, NT_STATUS_MEDIA_WRITE_PROTECTED);
+ return conn;
+ }
+
+ /* IPC services are limited */
+ if (IS_IPC(conn) && !(flags & CAN_IPC)) {
+ reply_doserror(req, ERRSRV,ERRaccess);
+ return conn;
+ }
+ } else {
+ /* This call needs to be run as root */
+ change_to_root_user();
+ }
+
+ /* load service specific parameters */
+ if (conn) {
+ if (req->encrypted) {
+ conn->encrypted_tid = true;
+ /* encrypted required from now on. */
+ conn->encrypt_level = Required;
+ } else if (ENCRYPTION_REQUIRED(conn)) {
+ uint8 com = CVAL(req->inbuf,smb_com);
+ if (com != SMBtrans2 && com != SMBtranss2) {
+ exit_server_cleanly("encryption required "
+ "on connection");
+ return conn;
+ }
+ }
+
+ if (!set_current_service(conn,SVAL(req->inbuf,smb_flg),
+ (flags & (AS_USER|DO_CHDIR)
+ ?True:False))) {
+ reply_doserror(req, ERRSRV, ERRaccess);
+ return conn;
+ }
+ conn->num_smb_operations++;
+ }
+
+ /* does this protocol need to be run as guest? */
+ if ((flags & AS_GUEST)
+ && (!change_to_guest() ||
+ !check_access(smbd_server_fd(), lp_hostsallow(-1),
+ lp_hostsdeny(-1)))) {
+ reply_doserror(req, ERRSRV, ERRaccess);
+ return conn;
+ }
+
+ smb_messages[type].fn_new(req);
+ return req->conn;
+}
+
+/****************************************************************************
+ Construct a reply to the incoming packet.
+****************************************************************************/
+
+static void construct_reply(char *inbuf, int size, size_t unread_bytes, bool encrypted)
+{
+ uint8 type = CVAL(inbuf,smb_com);
+ connection_struct *conn;
+ struct smb_request *req;
+
+ chain_size = 0;
+ file_chain_reset();
+ reset_chain_p();
+
+ if (!(req = talloc(talloc_tos(), struct smb_request))) {
+ smb_panic("could not allocate smb_request");
+ }
+ init_smb_request(req, (uint8 *)inbuf, unread_bytes, encrypted);
+
+ conn = switch_message(type, req, size);
+
+ if (req->unread_bytes) {
+ /* writeX failed. drain socket. */
+ if (drain_socket(smbd_server_fd(), req->unread_bytes) !=
+ req->unread_bytes) {
+ smb_panic("failed to drain pending bytes");
+ }
+ req->unread_bytes = 0;
+ }
+
+ if (req->outbuf == NULL) {
+ return;
+ }
+
+ if (CVAL(req->outbuf,0) == 0) {
+ show_msg((char *)req->outbuf);
+ }
+
+ if (!srv_send_smb(smbd_server_fd(),
+ (char *)req->outbuf,
+ IS_CONN_ENCRYPTED(conn)||req->encrypted)) {
+ exit_server_cleanly("construct_reply: srv_send_smb failed.");
+ }
+
+ TALLOC_FREE(req);
+
+ return;
+}
+
+/****************************************************************************
+ Process an smb from the client
+****************************************************************************/
+
+static void process_smb(char *inbuf, size_t nread, size_t unread_bytes, bool encrypted)
+{
+ static int trans_num;
+ int msg_type = CVAL(inbuf,0);
+
+ DO_PROFILE_INC(smb_count);
+
+ if (trans_num == 0) {
+ char addr[INET6_ADDRSTRLEN];
+
+ /* 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(smbd_server_fd(), lp_hostsallow(-1),
+ lp_hostsdeny(-1))) {
+ /* send a negative session response "not listening on calling name" */
+ static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
+ DEBUG( 1, ( "Connection denied from %s\n",
+ client_addr(get_client_fd(),addr,sizeof(addr)) ) );
+ (void)srv_send_smb(smbd_server_fd(),(char *)buf,false);
+ exit_server_cleanly("connection denied");
+ }
+ }
+
+ DEBUG( 6, ( "got message type 0x%x of len 0x%x\n", msg_type,
+ smb_len(inbuf) ) );
+ DEBUG( 3, ( "Transaction %d of length %d (%u toread)\n", trans_num,
+ (int)nread,
+ (unsigned int)unread_bytes ));
+
+ if (msg_type != 0) {
+ /*
+ * NetBIOS session request, keepalive, etc.
+ */
+ reply_special(inbuf);
+ return;
+ }
+
+ show_msg(inbuf);
+
+ construct_reply(inbuf,nread,unread_bytes,encrypted);
+
+ trans_num++;
+}
+
+/****************************************************************************
+ Return a string containing the function name of a SMB command.
+****************************************************************************/
+
+const char *smb_fn_name(int type)
+{
+ const char *unknown_name = "SMBunknown";
+
+ if (smb_messages[type].name == NULL)
+ return(unknown_name);
+
+ return(smb_messages[type].name);
+}
+
+/****************************************************************************
+ Helper functions for contruct_reply.
+****************************************************************************/
+
+static uint32 common_flags2 = FLAGS2_LONG_PATH_COMPONENTS|FLAGS2_32_BIT_ERROR_CODES;
+
+void add_to_common_flags2(uint32 v)
+{
+ common_flags2 |= v;
+}
+
+void remove_from_common_flags2(uint32 v)
+{
+ common_flags2 &= ~v;
+}
+
+void construct_reply_common(const char *inbuf, char *outbuf)
+{
+ srv_set_message(outbuf,0,0,false);
+
+ SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com));
+ SIVAL(outbuf,smb_rcls,0);
+ SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES));
+ SSVAL(outbuf,smb_flg2,
+ (SVAL(inbuf,smb_flg2) & FLAGS2_UNICODE_STRINGS) |
+ common_flags2);
+ memset(outbuf+smb_pidhigh,'\0',(smb_tid-smb_pidhigh));
+
+ 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
+****************************************************************************/
+
+void chain_reply(struct smb_request *req)
+{
+ static char *orig_inbuf;
+
+ /*
+ * Dirty little const_discard: We mess with req->inbuf, which is
+ * declared as const. If maybe at some point this routine gets
+ * rewritten, this const_discard could go away.
+ */
+ char *inbuf = CONST_DISCARD(char *, req->inbuf);
+ int size = smb_len(req->inbuf)+4;
+
+ int smb_com1, smb_com2 = CVAL(inbuf,smb_vwv0);
+ unsigned smb_off2 = SVAL(inbuf,smb_vwv1);
+ char *inbuf2;
+ int outsize2;
+ int new_size;
+ char inbuf_saved[smb_wct];
+ char *outbuf = (char *)req->outbuf;
+ size_t outsize = smb_len(outbuf) + 4;
+ size_t outsize_padded;
+ size_t padding;
+ size_t ofs, to_move;
+
+ struct smb_request *req2;
+ size_t caller_outputlen;
+ char *caller_output;
+
+ /* Maybe its not chained, or it's an error packet. */
+ if (smb_com2 == 0xFF || SVAL(outbuf,smb_rcls) != 0) {
+ SCVAL(outbuf,smb_vwv0,0xFF);
+ return;
+ }
+
+ if (chain_size == 0) {
+ /* this is the first part of the chain */
+ orig_inbuf = inbuf;
+ }
+
+ /*
+ * We need to save the output the caller added to the chain so that we
+ * can splice it into the final output buffer later.
+ */
+
+ caller_outputlen = outsize - smb_wct;
+
+ caller_output = (char *)memdup(outbuf + smb_wct, caller_outputlen);
+
+ if (caller_output == NULL) {
+ /* TODO: NT_STATUS_NO_MEMORY */
+ smb_panic("could not dup outbuf");
+ }
+
+ /*
+ * The original Win95 redirector dies on a reply to
+ * a lockingX and read chain unless the chain reply is
+ * 4 byte aligned. JRA.
+ */
+
+ outsize_padded = (outsize + 3) & ~3;
+ padding = outsize_padded - outsize;
+
+ /*
+ * remember how much the caller added to the chain, only counting
+ * stuff after the parameter words
+ */
+ chain_size += (outsize_padded - 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;
+
+ /* 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);
+
+ /* give the new packet the same header as the last part of the SMB */
+ memmove(inbuf2,inbuf,smb_wct);
+
+ /* create the in buffer */
+ SCVAL(inbuf2,smb_com,smb_com2);
+
+ /* work out the new size for the in buffer. */
+ new_size = size - (inbuf2 - inbuf);
+ if (new_size < 0) {
+ DEBUG(0,("chain_reply: chain packet size incorrect "
+ "(orig size = %d, offset = %d)\n",
+ size, (int)(inbuf2 - inbuf) ));
+ exit_server_cleanly("Bad chained packet");
+ return;
+ }
+
+ /* And set it in the header. */
+ smb_setlen(inbuf2, new_size - 4);
+
+ DEBUG(3,("Chained message\n"));
+ show_msg(inbuf2);
+
+ if (!(req2 = talloc(talloc_tos(), struct smb_request))) {
+ smb_panic("could not allocate smb_request");
+ }
+ init_smb_request(req2, (uint8 *)inbuf2,0, req->encrypted);
+
+ /* process the request */
+ switch_message(smb_com2, req2, new_size);
+
+ /*
+ * We don't accept deferred operations in chained requests.
+ */
+ SMB_ASSERT(req2->outbuf != NULL);
+ outsize2 = smb_len(req2->outbuf)+4;
+
+ /*
+ * Move away the new command output so that caller_output fits in,
+ * copy in the caller_output saved above.
+ */
+
+ SMB_ASSERT(outsize_padded >= smb_wct);
+
+ /*
+ * "ofs" is the space we need for caller_output. Equal to
+ * caller_outputlen plus the padding.
+ */
+
+ ofs = outsize_padded - smb_wct;
+
+ /*
+ * "to_move" is the amount of bytes the secondary routine gave us
+ */
+
+ to_move = outsize2 - smb_wct;
+
+ if (to_move + ofs + smb_wct + chain_size > max_send) {
+ smb_panic("replies too large -- would have to cut");
+ }
+
+ /*
+ * In the "new" API "outbuf" is allocated via reply_outbuf, just for
+ * the first request in the chain. So we have to re-allocate it. In
+ * the "old" API the only outbuf ever used is the global OutBuffer
+ * which is always large enough.
+ */
+
+ outbuf = TALLOC_REALLOC_ARRAY(NULL, outbuf, char,
+ to_move + ofs + smb_wct);
+ if (outbuf == NULL) {
+ smb_panic("could not realloc outbuf");
+ }
+
+ req->outbuf = (uint8 *)outbuf;
+
+ memmove(outbuf + smb_wct + ofs, req2->outbuf + smb_wct, to_move);
+ memcpy(outbuf + smb_wct, caller_output, caller_outputlen);
+
+ /*
+ * copy the new reply header over the old one but preserve the smb_com
+ * field
+ */
+ memmove(outbuf, req2->outbuf, smb_wct);
+ SCVAL(outbuf, smb_com, smb_com1);
+
+ /*
+ * We've just copied in the whole "wct" area from the secondary
+ * function. Fix up the chaining: com2 and the offset need to be
+ * readjusted.
+ */
+
+ SCVAL(outbuf, smb_vwv0, smb_com2);
+ SSVAL(outbuf, smb_vwv1, chain_size + smb_wct - 4);
+
+ if (padding != 0) {
+
+ /*
+ * Due to padding we have some uninitialized bytes after the
+ * caller's output
+ */
+
+ memset(outbuf + outsize, 0, padding);
+ }
+
+ smb_setlen(outbuf, outsize2 + caller_outputlen + padding - 4);
+
+ /*
+ * restore the saved data, being careful not to overwrite any data
+ * from the reply header
+ */
+ memcpy(inbuf2,inbuf_saved,smb_wct);
+
+ SAFE_FREE(caller_output);
+ TALLOC_FREE(req2);
+
+ /*
+ * Reset the chain_size for our caller's offset calculations
+ */
+
+ chain_size -= (outsize_padded - smb_wct);
+
+ return;
+}
+
+/****************************************************************************
+ Setup the needed select timeout in milliseconds.
+****************************************************************************/
+
+static int setup_select_timeout(void)
+{
+ int select_timeout;
+
+ select_timeout = SMBD_SELECT_TIMEOUT*1000;
+
+ if (print_notify_messages_pending()) {
+ select_timeout = MIN(select_timeout, 1000);
+ }
+
+ return select_timeout;
+}
+
+/****************************************************************************
+ Check if services need reloading.
+****************************************************************************/
+
+void check_reload(time_t t)
+{
+ static pid_t mypid = 0;
+ static time_t last_smb_conf_reload_time = 0;
+ static time_t last_printer_reload_time = 0;
+ time_t printcap_cache_time = (time_t)lp_printcap_cache_time();
+
+ if(last_smb_conf_reload_time == 0) {
+ last_smb_conf_reload_time = t;
+ /* Our printing subsystem might not be ready at smbd start up.
+ Then no printer is available till the first printers check
+ is performed. A lower initial interval circumvents this. */
+ if ( printcap_cache_time > 60 )
+ last_printer_reload_time = t - printcap_cache_time + 60;
+ else
+ last_printer_reload_time = t;
+ }
+
+ if (mypid != getpid()) { /* First time or fork happened meanwhile */
+ /* randomize over 60 second the printcap reload to avoid all
+ * process hitting cupsd at the same time */
+ int time_range = 60;
+
+ last_printer_reload_time += random() % time_range;
+ mypid = getpid();
+ }
+
+ if (reload_after_sighup || (t >= last_smb_conf_reload_time+SMBD_RELOAD_CHECK)) {
+ reload_services(True);
+ reload_after_sighup = False;
+ last_smb_conf_reload_time = t;
+ }
+
+ /* 'printcap cache time = 0' disable the feature */
+
+ if ( printcap_cache_time != 0 )
+ {
+ /* see if it's time to reload or if the clock has been set back */
+
+ if ( (t >= last_printer_reload_time+printcap_cache_time)
+ || (t-last_printer_reload_time < 0) )
+ {
+ DEBUG( 3,( "Printcap cache time expired.\n"));
+ reload_printers();
+ last_printer_reload_time = t;
+ }
+ }
+}
+
+/****************************************************************************
+ Process any timeout housekeeping. Return False if the caller should exit.
+****************************************************************************/
+
+static void timeout_processing(int *select_timeout,
+ time_t *last_timeout_processing_time)
+{
+ time_t t;
+
+ *last_timeout_processing_time = t = time(NULL);
+
+ /* become root again if waiting */
+ change_to_root_user();
+
+ /* check if we need to reload services */
+ check_reload(t);
+
+ if(global_machine_password_needs_changing &&
+ /* for ADS we need to do a regular ADS password change, not a domain
+ password change */
+ lp_security() == SEC_DOMAIN) {
+
+ unsigned char trust_passwd_hash[16];
+ time_t lct;
+ void *lock;
+
+ /*
+ * 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.
+ */
+
+ lock = secrets_get_trust_account_lock(NULL, lp_workgroup());
+
+ if (lock == NULL) {
+ DEBUG(0,("process: unable to lock the machine account password for \
+machine %s in domain %s.\n", global_myname(), lp_workgroup() ));
+ return;
+ }
+
+ if(!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd_hash, &lct, NULL)) {
+ DEBUG(0,("process: unable to read the machine account password for \
+machine %s in domain %s.\n", global_myname(), lp_workgroup()));
+ TALLOC_FREE(lock);
+ return;
+ }
+
+ /*
+ * Make sure someone else hasn't already done this.
+ */
+
+ if(t < lct + lp_machine_password_timeout()) {
+ global_machine_password_needs_changing = False;
+ TALLOC_FREE(lock);
+ return;
+ }
+
+ /* always just contact the PDC here */
+
+ change_trust_account_password( lp_workgroup(), NULL);
+ global_machine_password_needs_changing = False;
+ TALLOC_FREE(lock);
+ }
+
+ /* update printer queue caches if necessary */
+
+ update_monitored_printq_cache();
+
+ /*
+ * Now we are root, check if the log files need pruning.
+ * Force a log file check.
+ */
+ force_check_log_size();
+ check_log_size();
+
+ /* Send any queued printer notify message to interested smbd's. */
+
+ print_notify_send_messages(smbd_messaging_context(), 0);
+
+ /*
+ * Modify the select timeout depending upon
+ * what we have remaining in our queues.
+ */
+
+ *select_timeout = setup_select_timeout();
+
+ return;
+}
+
+/****************************************************************************
+ Process commands from the client
+****************************************************************************/
+
+void smbd_process(void)
+{
+ time_t last_timeout_processing_time = time(NULL);
+ unsigned int num_smbs = 0;
+ size_t unread_bytes = 0;
+
+ max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
+
+ while (True) {
+ int select_timeout = setup_select_timeout();
+ int num_echos;
+ char *inbuf = NULL;
+ size_t inbuf_len = 0;
+ bool encrypted = false;
+ TALLOC_CTX *frame = talloc_stackframe_pool(8192);
+
+ errno = 0;
+
+ /* Did someone ask for immediate checks on things like blocking locks ? */
+ if (select_timeout == 0) {
+ timeout_processing(&select_timeout,
+ &last_timeout_processing_time);
+ num_smbs = 0; /* Reset smb counter. */
+ }
+
+ run_events(smbd_event_context(), 0, NULL, NULL);
+
+ while (True) {
+ NTSTATUS status;
+
+ status = receive_message_or_smb(
+ talloc_tos(), &inbuf, &inbuf_len,
+ select_timeout, &unread_bytes, &encrypted);
+
+ if (NT_STATUS_IS_OK(status)) {
+ break;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ timeout_processing(
+ &select_timeout,
+ &last_timeout_processing_time);
+ continue;
+ }
+
+ DEBUG(3, ("receive_message_or_smb failed: %s, "
+ "exiting\n", nt_errstr(status)));
+ return;
+
+ num_smbs = 0; /* Reset smb counter. */
+ }
+
+
+ /*
+ * Ensure we do timeout processing if the SMB we just got was
+ * only an echo request. This allows us to set the select
+ * timeout in 'receive_message_or_smb()' to any value we like
+ * without worrying that the client will send echo requests
+ * faster than the select timeout, thus starving out the
+ * essential processing (change notify, blocking locks) that
+ * the timeout code does. JRA.
+ */
+ num_echos = smb_echo_count;
+
+ process_smb(inbuf, inbuf_len, unread_bytes, encrypted);
+
+ TALLOC_FREE(inbuf);
+
+ if (smb_echo_count != num_echos) {
+ timeout_processing(&select_timeout,
+ &last_timeout_processing_time);
+ num_smbs = 0; /* Reset smb counter. */
+ }
+
+ num_smbs++;
+
+ /*
+ * If we are getting smb requests in a constant stream
+ * with no echos, make sure we attempt timeout processing
+ * every select_timeout milliseconds - but only check for this
+ * every 200 smb requests.
+ */
+
+ if ((num_smbs % 200) == 0) {
+ time_t new_check_time = time(NULL);
+ if(new_check_time - last_timeout_processing_time >= (select_timeout/1000)) {
+ timeout_processing(
+ &select_timeout,
+ &last_timeout_processing_time);
+ num_smbs = 0; /* Reset smb counter. */
+ last_timeout_processing_time = new_check_time; /* Reset time. */
+ }
+ }
+
+ /* The timeout_processing function isn't run nearly
+ often enough to implement 'max log size' without
+ overrunning the size of the file by many megabytes.
+ This is especially true if we are running at debug
+ level 10. Checking every 50 SMBs is a nice
+ tradeoff of performance vs log file size overrun. */
+
+ if ((num_smbs % 50) == 0 && need_to_check_log_size()) {
+ change_to_root_user();
+ check_log_size();
+ }
+ TALLOC_FREE(frame);
+ }
+}
diff --git a/source3/smbd/quotas.c b/source3/smbd/quotas.c
new file mode 100644
index 0000000000..f47e89bd22
--- /dev/null
+++ b/source3/smbd/quotas.c
@@ -0,0 +1,1539 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*
+ * 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"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_QUOTA
+
+#ifndef HAVE_SYS_QUOTAS
+
+/* just a quick hack because sysquotas.h is included before linux/quota.h */
+#ifdef QUOTABLOCK_SIZE
+#undef QUOTABLOCK_SIZE
+#endif
+
+#ifdef WITH_QUOTAS
+
+#if defined(VXFS_QUOTA)
+
+/*
+ * In addition to their native filesystems, some systems have Veritas VxFS.
+ * Declare here, define at end: reduces likely "include" interaction problems.
+ * David Lee <T.D.Lee@durham.ac.uk>
+ */
+bool disk_quotas_vxfs(const char *name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
+
+#endif /* VXFS_QUOTA */
+
+#ifdef LINUX
+
+#include <sys/types.h>
+#include <mntent.h>
+
+/*
+ * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
+ * So we include all the files has *should* be in the system into a large,
+ * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA.
+ */
+
+#include "samba_linux_quota.h"
+
+typedef struct _LINUX_SMB_DISK_QUOTA {
+ SMB_BIG_UINT bsize;
+ SMB_BIG_UINT hardlimit; /* In bsize units. */
+ SMB_BIG_UINT softlimit; /* In bsize units. */
+ SMB_BIG_UINT curblocks; /* In bsize units. */
+ SMB_BIG_UINT ihardlimit; /* inode hard limit. */
+ SMB_BIG_UINT isoftlimit; /* inode soft limit. */
+ SMB_BIG_UINT curinodes; /* Current used inodes. */
+} LINUX_SMB_DISK_QUOTA;
+
+
+#ifdef HAVE_LINUX_DQBLK_XFS_H
+#include <linux/dqblk_xfs.h>
+
+/****************************************************************************
+ Abstract out the XFS Quota Manager quota get call.
+****************************************************************************/
+
+static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
+{
+ struct fs_disk_quota D;
+ int ret;
+
+ ZERO_STRUCT(D);
+
+ ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
+
+ if (ret)
+ ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
+
+ if (ret)
+ return ret;
+
+ dp->bsize = (SMB_BIG_UINT)512;
+ dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit;
+ dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit;
+ dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit;
+ dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit;
+ dp->curinodes = (SMB_BIG_UINT)D.d_icount;
+ dp->curblocks = (SMB_BIG_UINT)D.d_bcount;
+
+ return ret;
+}
+#else
+static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
+{
+ DEBUG(0,("XFS quota support not available\n"));
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+
+/****************************************************************************
+ Abstract out the old and new Linux quota get calls.
+****************************************************************************/
+
+static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
+{
+ struct v1_kern_dqblk D;
+ int ret;
+
+ ZERO_STRUCT(D);
+
+ ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
+
+ if (ret && errno != EDQUOT)
+ ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
+
+ if (ret && errno != EDQUOT)
+ return ret;
+
+ dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
+ dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
+ dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
+ dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
+ dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
+ dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
+ dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
+
+ return ret;
+}
+
+static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
+{
+ struct v2_kern_dqblk D;
+ int ret;
+
+ ZERO_STRUCT(D);
+
+ ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
+
+ if (ret && errno != EDQUOT)
+ ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
+
+ if (ret && errno != EDQUOT)
+ return ret;
+
+ dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
+ dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
+ dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
+ dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
+ dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
+ dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
+ dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize;
+
+ return ret;
+}
+
+/****************************************************************************
+ Brand-new generic quota interface.
+****************************************************************************/
+
+static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
+{
+ struct if_dqblk D;
+ int ret;
+
+ ZERO_STRUCT(D);
+
+ ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
+
+ if (ret && errno != EDQUOT)
+ ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
+
+ if (ret && errno != EDQUOT)
+ return ret;
+
+ dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
+ dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
+ dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
+ dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
+ dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
+ dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
+ dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize;
+
+ return ret;
+}
+
+/****************************************************************************
+ Try to get the disk space from disk quotas (LINUX version).
+****************************************************************************/
+
+bool disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ int r;
+ SMB_STRUCT_STAT S;
+ FILE *fp;
+ LINUX_SMB_DISK_QUOTA D;
+ struct mntent *mnt;
+ SMB_DEV_T devno;
+ int found;
+ uid_t euser_id;
+ gid_t egrp_id;
+
+ ZERO_STRUCT(D);
+
+ euser_id = geteuid();
+ egrp_id = getegid();
+
+ /* find the block device file */
+
+ if ( sys_stat(path, &S) == -1 )
+ return(False) ;
+
+ devno = S.st_dev ;
+
+ if ((fp = setmntent(MOUNTED,"r")) == NULL)
+ return(False) ;
+
+ 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);
+
+ become_root();
+
+ if (strcmp(mnt->mnt_type, "xfs")==0) {
+ r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
+ } else {
+ r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
+ if (r == -1 && errno != EDQUOT) {
+ r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
+ if (r == -1 && errno != EDQUOT)
+ r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
+ }
+ }
+
+ unbecome_root();
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ *bsize = D.bsize;
+ if (r == -1) {
+ if (errno == EDQUOT) {
+ *dfree =0;
+ *dsize =D.curblocks;
+ return (True);
+ } else {
+ return(False);
+ }
+ }
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ if (
+ (D.softlimit && D.curblocks >= D.softlimit) ||
+ (D.hardlimit && D.curblocks >= D.hardlimit) ||
+ (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
+ (D.ihardlimit && D.curinodes>=D.ihardlimit)
+ ) {
+ *dfree = 0;
+ *dsize = D.curblocks;
+ } else if (D.softlimit==0 && D.hardlimit==0) {
+ return(False);
+ } else {
+ if (D.softlimit == 0)
+ D.softlimit = D.hardlimit;
+ *dfree = D.softlimit - D.curblocks;
+ *dsize = D.softlimit;
+ }
+
+ return (True);
+}
+
+#elif defined(CRAY)
+
+#include <sys/quota.h>
+#include <mntent.h>
+
+/****************************************************************************
+try to get the disk space from disk quotas (CRAY VERSION)
+****************************************************************************/
+
+bool disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ struct mntent *mnt;
+ FILE *fd;
+ SMB_STRUCT_STAT sbuf;
+ SMB_DEV_T devno ;
+ struct q_request request ;
+ struct qf_header header ;
+ int quota_default = 0 ;
+ bool found = false;
+
+ if (sys_stat(path,&sbuf) == -1) {
+ return false;
+ }
+
+ devno = sbuf.st_dev ;
+
+ if ((fd = setmntent(KMTAB)) == NULL) {
+ return false;
+ }
+
+ while ((mnt = getmntent(fd)) != NULL) {
+ if (sys_stat(mnt->mnt_dir,&sbuf) == -1) {
+ continue;
+ }
+ if (sbuf.st_dev == devno) {
+ found = frue ;
+ break;
+ }
+ }
+
+ name = talloc_strdup(talloc_tos(), mnt->mnt_dir);
+ endmntent(fd);
+ if (!found) {
+ return false;
+ }
+
+ if (!name) {
+ return false;
+ }
+
+ request.qf_magic = QF_MAGIC ;
+ request.qf_entry.id = geteuid() ;
+
+ if (quotactl(name, Q_GETQUOTA, &request) == -1) {
+ return false;
+ }
+
+ if (!request.user) {
+ return False;
+ }
+
+ if (request.qf_entry.user_q.f_quota == QFV_DEFAULT) {
+ if (!quota_default) {
+ if (quotactl(name, Q_GETHEADER, &header) == -1) {
+ return false;
+ } else {
+ quota_default = header.user_h.def_fq;
+ }
+ }
+ *dfree = quota_default;
+ } else if (request.qf_entry.user_q.f_quota == QFV_PREVENT) {
+ *dfree = 0;
+ } else {
+ *dfree = request.qf_entry.user_q.f_quota;
+ }
+
+ *dsize = request.qf_entry.user_q.f_use;
+
+ if (*dfree < *dsize) {
+ *dfree = 0;
+ } else {
+ *dfree -= *dsize;
+ }
+
+ *bsize = 4096 ; /* Cray blocksize */
+ return true;
+}
+
+
+#elif defined(SUNOS5) || defined(SUNOS4)
+
+#include <fcntl.h>
+#include <sys/param.h>
+#if defined(SUNOS5)
+#include <sys/fs/ufs_quota.h>
+#include <sys/mnttab.h>
+#include <sys/mntent.h>
+#else /* defined(SUNOS4) */
+#include <ufs/quota.h>
+#include <mntent.h>
+#endif
+
+#if defined(SUNOS5)
+
+/****************************************************************************
+ Allows querying of remote hosts for quotas on NFS mounted shares.
+ Supports normal NFS and AMD mounts.
+ Alan Romeril <a.romeril@ic.ac.uk> July 2K.
+****************************************************************************/
+
+#include <rpc/rpc.h>
+#include <rpc/types.h>
+#include <rpcsvc/rquota.h>
+#include <rpc/nettype.h>
+#include <rpc/xdr.h>
+
+static int quotastat;
+
+static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
+{
+ if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
+ return(0);
+ if (!xdr_int(xdrsp, &args->gqa_uid))
+ return(0);
+ return (1);
+}
+
+static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
+{
+ if (!xdr_int(xdrsp, &quotastat)) {
+ DEBUG(6,("nfs_quotas: Status bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
+ DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
+ DEBUG(6,("nfs_quotas: Active bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
+ DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
+ DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
+ DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
+ return 0;
+ }
+ return (1);
+}
+
+/* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
+static bool nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ uid_t uid = euser_id;
+ struct dqblk D;
+ char *mnttype = nfspath;
+ CLIENT *clnt;
+ struct getquota_rslt gqr;
+ struct getquota_args args;
+ char *cutstr, *pathname, *host, *testpath;
+ int len;
+ static struct timeval timeout = {2,0};
+ enum clnt_stat clnt_stat;
+ bool ret = True;
+
+ *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
+
+ len=strcspn(mnttype, ":");
+ pathname=strstr(mnttype, ":");
+ cutstr = (char *) SMB_MALLOC(len+1);
+ if (!cutstr)
+ return False;
+
+ memset(cutstr, '\0', len+1);
+ host = strncat(cutstr,mnttype, sizeof(char) * len );
+ DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
+ DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
+ testpath=strchr_m(mnttype, ':');
+ args.gqa_pathp = testpath+1;
+ args.gqa_uid = uid;
+
+ DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
+
+ if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
+ ret = False;
+ goto out;
+ }
+
+ clnt->cl_auth = authunix_create_default();
+ DEBUG(9,("nfs_quotas: auth_success\n"));
+
+ clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
+
+ if (clnt_stat != RPC_SUCCESS) {
+ DEBUG(9,("nfs_quotas: clnt_call fail\n"));
+ ret = False;
+ goto out;
+ }
+
+ /*
+ * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
+ * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
+ * something sensible.
+ */
+
+ switch ( quotastat ) {
+ case 0:
+ DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
+ ret = False;
+ goto out;
+
+ case 1:
+ DEBUG(9,("nfs_quotas: Good quota data\n"));
+ D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
+ D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
+ D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
+ break;
+
+ case 2:
+ case 3:
+ D.dqb_bsoftlimit = 1;
+ D.dqb_curblocks = 1;
+ DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
+ break;
+
+ default:
+ DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
+ break;
+ }
+
+ DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
+ quotastat,
+ gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
+ gqr.getquota_rslt_u.gqr_rquota.rq_active,
+ gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
+ gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
+ gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
+
+ *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
+ *dsize = D.dqb_bsoftlimit;
+
+ if (D.dqb_curblocks == D.dqb_curblocks == 1)
+ *bsize = 512;
+
+ if (D.dqb_curblocks > D.dqb_bsoftlimit) {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ } else
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+
+ out:
+
+ if (clnt) {
+ if (clnt->cl_auth)
+ auth_destroy(clnt->cl_auth);
+ clnt_destroy(clnt);
+ }
+
+ DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
+
+ SAFE_FREE(cutstr);
+ DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
+ return ret;
+}
+#endif
+
+/****************************************************************************
+try to get the disk space from disk quotas (SunOS & Solaris2 version)
+Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
+****************************************************************************/
+
+bool disk_quotas(const char *path,
+ SMB_BIG_UINT *bsize,
+ SMB_BIG_UINT *dfree,
+ SMB_BIG_UINT *dsize)
+{
+ uid_t euser_id;
+ int ret;
+ struct dqblk D;
+#if defined(SUNOS5)
+ struct quotctl command;
+ int file;
+ struct mnttab mnt;
+#else /* SunOS4 */
+ struct mntent *mnt;
+#endif
+ char *name = NULL;
+ FILE *fd;
+ SMB_STRUCT_STAT sbuf;
+ SMB_DEV_T devno;
+ bool found = false;
+
+ euser_id = geteuid();
+
+ if (sys_stat(path,&sbuf) == -1) {
+ return false;
+ }
+
+ devno = sbuf.st_dev ;
+ DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
+ path, (unsigned int)devno));
+#if defined(SUNOS5)
+ if ((fd = sys_fopen(MNTTAB, "r")) == NULL) {
+ return false;
+ }
+
+ while (getmntent(fd, &mnt) == 0) {
+ if (sys_stat(mnt.mnt_mountp, &sbuf) == -1) {
+ continue;
+ }
+
+ DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
+ mnt.mnt_mountp, (unsigned int)devno));
+
+ /* quotas are only on vxfs, UFS or NFS */
+ if ((sbuf.st_dev == devno) && (
+ strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
+ strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
+ strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) {
+ found = true;
+ name = talloc_asprintf(talloc_tos(),
+ "%s/quotas",
+ mnt.mnt_mountp);
+ break;
+ }
+ }
+
+ fclose(fd);
+#else /* SunOS4 */
+ if ((fd = setmntent(MOUNTED, "r")) == NULL) {
+ return false;
+ }
+
+ while ((mnt = getmntent(fd)) != NULL) {
+ if (sys_stat(mnt->mnt_dir,&sbuf) == -1) {
+ continue;
+ }
+ DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
+ mnt->mnt_dir,
+ (unsigned int)sbuf.st_dev));
+ if (sbuf.st_dev == devno) {
+ found = true;
+ name = talloc_strdup(talloc_tos(),
+ mnt->mnt_fsname);
+ break;
+ }
+ }
+
+ endmntent(fd);
+#endif
+ if (!found) {
+ return false;
+ }
+
+ if (!name) {
+ return false;
+ }
+ become_root();
+
+#if defined(SUNOS5)
+ if (strcmp(mnt.mnt_fstype, "nfs") == 0) {
+ bool retval;
+ DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n",
+ mnt.mnt_special));
+ retval = nfs_quotas(mnt.mnt_special,
+ euser_id, bsize, dfree, dsize);
+ unbecome_root();
+ return retval;
+ }
+
+ DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
+ if((file=sys_open(name, O_RDONLY,0))<0) {
+ unbecome_root();
+ 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
+
+ unbecome_root();
+
+ if (ret < 0) {
+ DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n",
+ strerror(errno) ));
+
+#if defined(SUNOS5) && defined(VXFS_QUOTA)
+ /* If normal quotactl() fails, try vxfs private calls */
+ set_effective_uid(euser_id);
+ DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
+ if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
+ bool retval;
+ retval = disk_quotas_vxfs(name, path,
+ bsize, dfree, dsize);
+ return retval;
+ }
+#else
+ return false;
+#endif
+ }
+
+ /* If softlimit is zero, set it equal to hardlimit.
+ */
+
+ if (D.dqb_bsoftlimit==0) {
+ D.dqb_bsoftlimit = D.dqb_bhardlimit;
+ }
+
+ /* Use softlimit to determine disk space. A user exceeding the quota
+ * is told that there's no space left. Writes might actually work for
+ * a bit if the hardlimit is set higher than softlimit. Effectively
+ * the disk becomes made of rubber latex and begins to expand to
+ * accommodate the user :-)
+ */
+
+ if (D.dqb_bsoftlimit==0)
+ return(False);
+ *bsize = DEV_BSIZE;
+ *dsize = D.dqb_bsoftlimit;
+
+ if (D.dqb_curblocks > D.dqb_bsoftlimit) {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ } else {
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+ }
+
+ DEBUG(5,("disk_quotas for path \"%s\" returning "
+ "bsize %.0f, dfree %.0f, dsize %.0f\n",
+ path,(double)*bsize,(double)*dfree,(double)*dsize));
+
+ return true;
+}
+
+
+#elif defined(OSF1)
+#include <ufs/quota.h>
+
+/****************************************************************************
+try to get the disk space from disk quotas - OSF1 version
+****************************************************************************/
+
+bool disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ int r, save_errno;
+ struct dqblk D;
+ SMB_STRUCT_STAT S;
+ uid_t euser_id;
+
+ /*
+ * This code presumes that OSF1 will only
+ * give out quota info when the real uid
+ * matches the effective uid. JRA.
+ */
+ euser_id = geteuid();
+ save_re_uid();
+ if (set_re_uid() != 0) return False;
+
+ r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
+ if (r) {
+ save_errno = errno;
+ }
+
+ restore_re_uid();
+
+ *bsize = DEV_BSIZE;
+
+ if (r)
+ {
+ if (save_errno == EDQUOT) /* disk quota exceeded */
+ {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ return (True);
+ }
+ else
+ return (False);
+ }
+
+ /* If softlimit is zero, set it equal to hardlimit.
+ */
+
+ if (D.dqb_bsoftlimit==0)
+ D.dqb_bsoftlimit = D.dqb_bhardlimit;
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+
+ if (D.dqb_bsoftlimit==0)
+ return(False);
+
+ if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ } else {
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+ *dsize = D.dqb_bsoftlimit;
+ }
+ return (True);
+}
+
+#elif defined (IRIX6)
+/****************************************************************************
+try to get the disk space from disk quotas (IRIX 6.2 version)
+****************************************************************************/
+
+#include <sys/quota.h>
+#include <mntent.h>
+
+bool disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ uid_t euser_id;
+ int r;
+ struct dqblk D;
+ struct fs_disk_quota F;
+ SMB_STRUCT_STAT S;
+ FILE *fp;
+ struct mntent *mnt;
+ SMB_DEV_T devno;
+ int found;
+
+ /* find the block device file */
+
+ if ( sys_stat(path, &S) == -1 ) {
+ return(False) ;
+ }
+
+ devno = S.st_dev ;
+
+ fp = setmntent(MOUNTED,"r");
+ found = False ;
+
+ while ((mnt = getmntent(fp))) {
+ if ( sys_stat(mnt->mnt_dir,&S) == -1 )
+ continue ;
+ if (S.st_dev == devno) {
+ found = True ;
+ break ;
+ }
+ }
+ endmntent(fp) ;
+
+ if (!found) {
+ return(False);
+ }
+
+ euser_id=geteuid();
+ become_root();
+
+ /* 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);
+
+ unbecome_root();
+
+ 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);
+
+ unbecome_root();
+
+ if (r==-1)
+ {
+ DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
+ return(False);
+ }
+
+ /* No quota for this user. */
+ if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
+ {
+ return(False);
+ }
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ if (
+ (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
+ (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
+ (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
+ (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
+ )
+ {
+ *dfree = 0;
+ *dsize = F.d_bcount;
+ }
+ else
+ {
+ *dfree = (F.d_blk_softlimit - F.d_bcount);
+ *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
+ }
+
+ }
+ else
+ {
+ unbecome_root();
+ return(False);
+ }
+
+ return (True);
+
+}
+
+#else
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+#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
+#ifdef _AIXVERSION_530
+#include <sys/statfs.h>
+#include <sys/vmount.h>
+#endif /* AIX 5.3 */
+#else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
+#include <sys/quota.h>
+#include <devnm.h>
+#endif
+
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+
+#include <rpc/rpc.h>
+#include <rpc/types.h>
+#include <rpcsvc/rquota.h>
+#ifdef HAVE_RPC_NETTYPE_H
+#include <rpc/nettype.h>
+#endif
+#include <rpc/xdr.h>
+
+static int quotastat;
+
+static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
+{
+ if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
+ return(0);
+ if (!xdr_int(xdrsp, &args->gqa_uid))
+ return(0);
+ return (1);
+}
+
+static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
+{
+ if (!xdr_int(xdrsp, &quotastat)) {
+ DEBUG(6,("nfs_quotas: Status bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
+ DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
+ DEBUG(6,("nfs_quotas: Active bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
+ DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
+ DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
+ DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
+ return 0;
+ }
+ return (1);
+}
+
+/* Works on FreeBSD, too. :-) */
+static bool nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ uid_t uid = euser_id;
+ struct dqblk D;
+ char *mnttype = nfspath;
+ CLIENT *clnt;
+ struct getquota_rslt gqr;
+ struct getquota_args args;
+ char *cutstr, *pathname, *host, *testpath;
+ int len;
+ static struct timeval timeout = {2,0};
+ enum clnt_stat clnt_stat;
+ bool ret = True;
+
+ *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
+
+ len=strcspn(mnttype, ":");
+ pathname=strstr(mnttype, ":");
+ cutstr = (char *) SMB_MALLOC(len+1);
+ if (!cutstr)
+ return False;
+
+ memset(cutstr, '\0', len+1);
+ host = strncat(cutstr,mnttype, sizeof(char) * len );
+ DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
+ DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
+ testpath=strchr_m(mnttype, ':');
+ args.gqa_pathp = testpath+1;
+ args.gqa_uid = uid;
+
+ DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
+
+ if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
+ ret = False;
+ goto out;
+ }
+
+ clnt->cl_auth = authunix_create_default();
+ DEBUG(9,("nfs_quotas: auth_success\n"));
+
+ clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, (const xdrproc_t) my_xdr_getquota_args, (caddr_t)&args, (const xdrproc_t) my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
+
+ if (clnt_stat != RPC_SUCCESS) {
+ DEBUG(9,("nfs_quotas: clnt_call fail\n"));
+ ret = False;
+ goto out;
+ }
+
+ /*
+ * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
+ * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
+ * something sensible.
+ */
+
+ switch ( quotastat ) {
+ case 0:
+ DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
+ ret = False;
+ goto out;
+
+ case 1:
+ DEBUG(9,("nfs_quotas: Good quota data\n"));
+ D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
+ D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
+ D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
+ break;
+
+ case 2:
+ case 3:
+ D.dqb_bsoftlimit = 1;
+ D.dqb_curblocks = 1;
+ DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
+ break;
+
+ default:
+ DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
+ break;
+ }
+
+ DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
+ quotastat,
+ gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
+ gqr.getquota_rslt_u.gqr_rquota.rq_active,
+ gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
+ gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
+ gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
+
+ if (D.dqb_bsoftlimit == 0)
+ D.dqb_bsoftlimit = D.dqb_bhardlimit;
+ if (D.dqb_bsoftlimit == 0)
+ return False;
+
+ *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
+ *dsize = D.dqb_bsoftlimit;
+
+ if (D.dqb_curblocks == D.dqb_curblocks == 1)
+ *bsize = DEV_BSIZE;
+
+ if (D.dqb_curblocks > D.dqb_bsoftlimit) {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ } else
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+
+ out:
+
+ if (clnt) {
+ if (clnt->cl_auth)
+ auth_destroy(clnt->cl_auth);
+ clnt_destroy(clnt);
+ }
+
+ DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
+
+ SAFE_FREE(cutstr);
+ DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
+ return ret;
+}
+
+#endif
+
+/****************************************************************************
+try to get the disk space from disk quotas - default version
+****************************************************************************/
+
+bool disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ int r;
+ struct dqblk D;
+ uid_t euser_id;
+#if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
+ char dev_disk[256];
+ SMB_STRUCT_STAT S;
+
+ /* find the block device file */
+
+#ifdef HPUX
+ /* Need to set the cache flag to 1 for HPUX. Seems
+ * to have a significant performance boost when
+ * lstat calls on /dev access this function.
+ */
+ if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0))
+#else
+ if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0))
+ return (False);
+#endif /* ifdef HPUX */
+
+#endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
+
+ euser_id = geteuid();
+
+#ifdef HPUX
+ /* for HPUX, real uid must be same as euid to execute quotactl for euid */
+ save_re_uid();
+ if (set_re_uid() != 0) return False;
+
+ r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
+
+ restore_re_uid();
+#else
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+ {
+ /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
+ gid_t egrp_id;
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+ SMB_DEV_T devno;
+ struct statfs *mnts;
+ SMB_STRUCT_STAT st;
+ int mntsize, i;
+
+ if (sys_stat(path,&st) < 0)
+ return False;
+ devno = st.st_dev;
+
+ mntsize = getmntinfo(&mnts,MNT_NOWAIT);
+ if (mntsize <= 0)
+ return False;
+
+ for (i = 0; i < mntsize; i++) {
+ if (sys_stat(mnts[i].f_mntonname,&st) < 0)
+ return False;
+ if (st.st_dev == devno)
+ break;
+ }
+ if (i == mntsize)
+ return False;
+#endif
+
+ become_root();
+
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+ if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
+ bool retval;
+ retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
+ unbecome_root();
+ return retval;
+ }
+#endif
+
+ egrp_id = getegid();
+ r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
+
+ /* As FreeBSD has group quotas, if getting the user
+ quota fails, try getting the group instead. */
+ if (r) {
+ r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
+ }
+
+ unbecome_root();
+ }
+#elif defined(AIX)
+ /* AIX has both USER and GROUP quotas:
+ Get the USER quota (ohnielse@fysik.dtu.dk) */
+#ifdef _AIXVERSION_530
+ {
+ struct statfs statbuf;
+ quota64_t user_quota;
+ if (statfs(path,&statbuf) != 0)
+ return False;
+ if(statbuf.f_vfstype == MNT_J2)
+ {
+ /* For some reason we need to be root for jfs2 */
+ become_root();
+ r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
+ unbecome_root();
+ /* Copy results to old struct to let the following code work as before */
+ D.dqb_curblocks = user_quota.bused;
+ D.dqb_bsoftlimit = user_quota.bsoft;
+ D.dqb_bhardlimit = user_quota.bhard;
+ D.dqb_curfiles = user_quota.iused;
+ D.dqb_fsoftlimit = user_quota.isoft;
+ D.dqb_fhardlimit = user_quota.ihard;
+ }
+ else if(statbuf.f_vfstype == MNT_JFS)
+ {
+#endif /* AIX 5.3 */
+ save_re_uid();
+ if (set_re_uid() != 0)
+ return False;
+ r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
+ restore_re_uid();
+#ifdef _AIXVERSION_530
+ }
+ else
+ r = 1; /* Fail for other FS-types */
+ }
+#endif /* AIX 5.3 */
+#else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
+ r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
+#endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
+#endif /* HPUX */
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+ *bsize = DEV_BSIZE;
+#else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
+ *bsize = 1024;
+#endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
+
+ if (r)
+ {
+ if (errno == EDQUOT)
+ {
+ *dfree =0;
+ *dsize =D.dqb_curblocks;
+ return (True);
+ }
+ else return(False);
+ }
+
+ /* If softlimit is zero, set it equal to hardlimit.
+ */
+
+ if (D.dqb_bsoftlimit==0)
+ D.dqb_bsoftlimit = D.dqb_bhardlimit;
+
+ if (D.dqb_bsoftlimit==0)
+ return(False);
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ if ((D.dqb_curblocks>D.dqb_bsoftlimit)
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
+||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
+#endif
+ ) {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ }
+ else {
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+ *dsize = D.dqb_bsoftlimit;
+ }
+ return (True);
+}
+
+#endif
+
+#if defined(VXFS_QUOTA)
+
+/****************************************************************************
+Try to get the disk space from Veritas disk quotas.
+ David Lee <T.D.Lee@durham.ac.uk> August 1999.
+
+Background assumptions:
+ Potentially under many Operating Systems. Initially Solaris 2.
+
+ My guess is that Veritas is largely, though not entirely,
+ independent of OS. So I have separated it out.
+
+ There may be some details. For example, OS-specific "include" files.
+
+ It is understood that HPUX 10 somehow gets Veritas quotas without
+ any special effort; if so, this routine need not be compiled in.
+ Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
+
+Warning:
+ It is understood that Veritas do not publicly support this ioctl interface.
+ Rather their preference would be for the user (us) to call the native
+ OS and then for the OS itself to call through to the VxFS filesystem.
+ Presumably HPUX 10, see above, does this.
+
+Hints for porting:
+ Add your OS to "IFLIST" below.
+ Get it to compile successfully:
+ Almost certainly "include"s require attention: see SUNOS5.
+ In the main code above, arrange for it to be called: see SUNOS5.
+ Test!
+
+****************************************************************************/
+
+/* "IFLIST"
+ * This "if" is a list of ports:
+ * if defined(OS1) || defined(OS2) || ...
+ */
+#if defined(SUNOS5)
+
+#if defined(SUNOS5)
+#include <sys/fs/vx_solaris.h>
+#endif
+#include <sys/fs/vx_machdep.h>
+#include <sys/fs/vx_layout.h>
+#include <sys/fs/vx_quota.h>
+#include <sys/fs/vx_aioctl.h>
+#include <sys/fs/vx_ioctl.h>
+
+bool disk_quotas_vxfs(const char *name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ uid_t user_id, euser_id;
+ int ret;
+ struct vx_dqblk D;
+ struct vx_quotctl quotabuf;
+ struct vx_genioctl genbuf;
+ char *qfname;
+ int file;
+
+ /*
+ * "name" may or may not include a trailing "/quotas".
+ * Arranging consistency of calling here in "quotas.c" may not be easy and
+ * it might be easier to examine and adjust it here.
+ * Fortunately, VxFS seems not to mind at present.
+ */
+ qfname = talloc_strdup(talloc_tos(), name);
+ if (!qfname) {
+ return false;
+ }
+ /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
+
+ euser_id = geteuid();
+ set_effective_uid(0);
+
+ DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
+ if((file=sys_open(qfname, O_RDONLY,0))<0) {
+ set_effective_uid(euser_id);
+ return(False);
+ }
+ genbuf.ioc_cmd = VX_QUOTACTL;
+ genbuf.ioc_up = (void *) &quotabuf;
+
+ quotabuf.cmd = VX_GETQUOTA;
+ quotabuf.uid = euser_id;
+ quotabuf.addr = (caddr_t) &D;
+ ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
+ close(file);
+
+ set_effective_uid(euser_id);
+
+ if (ret < 0) {
+ DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
+ return(False);
+ }
+
+ /* If softlimit is zero, set it equal to hardlimit.
+ */
+
+ if (D.dqb_bsoftlimit==0)
+ D.dqb_bsoftlimit = D.dqb_bhardlimit;
+
+ /* Use softlimit to determine disk space. A user exceeding the quota is told
+ * that there's no space left. Writes might actually work for a bit if the
+ * hardlimit is set higher than softlimit. Effectively the disk becomes
+ * made of rubber latex and begins to expand to accommodate the user :-)
+ */
+ DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
+ path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
+ D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
+
+ if (D.dqb_bsoftlimit==0)
+ return(False);
+ *bsize = DEV_BSIZE;
+ *dsize = D.dqb_bsoftlimit;
+
+ if (D.dqb_curblocks > D.dqb_bsoftlimit) {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ } else
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+
+ DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
+ path,(double)*bsize,(double)*dfree,(double)*dsize));
+
+ return(True);
+}
+
+#endif /* SUNOS5 || ... */
+
+#endif /* VXFS_QUOTA */
+
+#else /* WITH_QUOTAS */
+
+bool disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+{
+ (*bsize) = 512; /* This value should be ignored */
+
+ /* And just to be sure we set some values that hopefully */
+ /* will be larger that any possible real-world value */
+ (*dfree) = (SMB_BIG_UINT)-1;
+ (*dsize) = (SMB_BIG_UINT)-1;
+
+ /* As we have select not to use quotas, allways fail */
+ return false;
+}
+#endif /* WITH_QUOTAS */
+
+#else /* HAVE_SYS_QUOTAS */
+/* wrapper to the new sys_quota interface
+ this file should be removed later
+ */
+bool disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+{
+ int r;
+ SMB_DISK_QUOTA D;
+ unid_t id;
+
+ id.uid = geteuid();
+
+ ZERO_STRUCT(D);
+ r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ *bsize = D.bsize;
+ if (r == -1) {
+ if (errno == EDQUOT) {
+ *dfree =0;
+ *dsize =D.curblocks;
+ return (True);
+ } else {
+ goto try_group_quota;
+ }
+ }
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ if (
+ (D.softlimit && D.curblocks >= D.softlimit) ||
+ (D.hardlimit && D.curblocks >= D.hardlimit) ||
+ (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
+ (D.ihardlimit && D.curinodes>=D.ihardlimit)
+ ) {
+ *dfree = 0;
+ *dsize = D.curblocks;
+ } else if (D.softlimit==0 && D.hardlimit==0) {
+ goto try_group_quota;
+ } else {
+ if (D.softlimit == 0)
+ D.softlimit = D.hardlimit;
+ *dfree = D.softlimit - D.curblocks;
+ *dsize = D.softlimit;
+ }
+
+ return True;
+
+try_group_quota:
+ id.gid = getegid();
+
+ ZERO_STRUCT(D);
+ r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ *bsize = D.bsize;
+ if (r == -1) {
+ if (errno == EDQUOT) {
+ *dfree =0;
+ *dsize =D.curblocks;
+ return (True);
+ } else {
+ return False;
+ }
+ }
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ if (
+ (D.softlimit && D.curblocks >= D.softlimit) ||
+ (D.hardlimit && D.curblocks >= D.hardlimit) ||
+ (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
+ (D.ihardlimit && D.curinodes>=D.ihardlimit)
+ ) {
+ *dfree = 0;
+ *dsize = D.curblocks;
+ } else if (D.softlimit==0 && D.hardlimit==0) {
+ return False;
+ } else {
+ if (D.softlimit == 0)
+ D.softlimit = D.hardlimit;
+ *dfree = D.softlimit - D.curblocks;
+ *dsize = D.softlimit;
+ }
+
+ return (True);
+}
+#endif /* HAVE_SYS_QUOTAS */
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
new file mode 100644
index 0000000000..6933533672
--- /dev/null
+++ b/source3/smbd/reply.c
@@ -0,0 +1,7184 @@
+/*
+ Unix SMB/CIFS implementation.
+ Main SMB reply routines
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Andrew Bartlett 2001
+ Copyright (C) Jeremy Allison 1992-2007.
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ This file handles most of the reply_ calls that the server
+ makes to handle specific protocols
+*/
+
+#include "includes.h"
+
+/* look in server.c for some explanation of these variables */
+extern enum protocol_types Protocol;
+extern int max_recv;
+unsigned int smb_echo_count = 0;
+extern uint32 global_client_caps;
+
+extern bool global_encrypted_passwords_negotiated;
+
+/****************************************************************************
+ Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
+ path or anything including wildcards.
+ We're assuming here that '/' is not the second byte in any multibyte char
+ set (a safe assumption). '\\' *may* be the second byte in a multibyte char
+ set.
+****************************************************************************/
+
+/* Custom version for processing POSIX paths. */
+#define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
+
+static NTSTATUS check_path_syntax_internal(char *path,
+ bool posix_path,
+ bool *p_last_component_contains_wcard)
+{
+ char *d = path;
+ const char *s = path;
+ NTSTATUS ret = NT_STATUS_OK;
+ bool start_of_name_component = True;
+
+ *p_last_component_contains_wcard = False;
+
+ while (*s) {
+ if (IS_PATH_SEP(*s,posix_path)) {
+ /*
+ * Safe to assume is not the second part of a mb char
+ * as this is handled below.
+ */
+ /* Eat multiple '/' or '\\' */
+ while (IS_PATH_SEP(*s,posix_path)) {
+ s++;
+ }
+ if ((d != path) && (*s != '\0')) {
+ /* We only care about non-leading or trailing '/' or '\\' */
+ *d++ = '/';
+ }
+
+ start_of_name_component = True;
+ /* New component. */
+ *p_last_component_contains_wcard = False;
+ continue;
+ }
+
+ if (start_of_name_component) {
+ if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
+ /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
+
+ /*
+ * No mb char starts with '.' so we're safe checking the directory separator here.
+ */
+
+ /* If we just added a '/' - delete it */
+ if ((d > path) && (*(d-1) == '/')) {
+ *(d-1) = '\0';
+ d--;
+ }
+
+ /* Are we at the start ? Can't go back further if so. */
+ if (d <= path) {
+ ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
+ break;
+ }
+ /* Go back one level... */
+ /* We know this is safe as '/' cannot be part of a mb sequence. */
+ /* NOTE - if this assumption is invalid we are not in good shape... */
+ /* Decrement d first as d points to the *next* char to write into. */
+ for (d--; d > path; d--) {
+ if (*d == '/')
+ break;
+ }
+ s += 2; /* Else go past the .. */
+ /* We're still at the start of a name component, just the previous one. */
+ continue;
+
+ } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
+ if (posix_path) {
+ /* Eat the '.' */
+ s++;
+ continue;
+ }
+ }
+
+ }
+
+ if (!(*s & 0x80)) {
+ if (!posix_path) {
+ if (*s <= 0x1f) {
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+ switch (*s) {
+ case '*':
+ case '?':
+ case '<':
+ case '>':
+ case '"':
+ *p_last_component_contains_wcard = True;
+ break;
+ default:
+ break;
+ }
+ }
+ *d++ = *s++;
+ } else {
+ size_t siz;
+ /* Get the size of the next MB character. */
+ next_codepoint(s,&siz);
+ switch(siz) {
+ case 5:
+ *d++ = *s++;
+ /*fall through*/
+ case 4:
+ *d++ = *s++;
+ /*fall through*/
+ case 3:
+ *d++ = *s++;
+ /*fall through*/
+ case 2:
+ *d++ = *s++;
+ /*fall through*/
+ case 1:
+ *d++ = *s++;
+ break;
+ default:
+ DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
+ *d = '\0';
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+ start_of_name_component = False;
+ }
+
+ *d = '\0';
+
+ return ret;
+}
+
+/****************************************************************************
+ Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
+ No wildcards allowed.
+****************************************************************************/
+
+NTSTATUS check_path_syntax(char *path)
+{
+ bool ignore;
+ return check_path_syntax_internal(path, False, &ignore);
+}
+
+/****************************************************************************
+ Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
+ Wildcards allowed - p_contains_wcard returns true if the last component contained
+ a wildcard.
+****************************************************************************/
+
+NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
+{
+ return check_path_syntax_internal(path, False, p_contains_wcard);
+}
+
+/****************************************************************************
+ Check the path for a POSIX client.
+ We're assuming here that '/' is not the second byte in any multibyte char
+ set (a safe assumption).
+****************************************************************************/
+
+NTSTATUS check_path_syntax_posix(char *path)
+{
+ bool ignore;
+ return check_path_syntax_internal(path, True, &ignore);
+}
+
+/****************************************************************************
+ Pull a string and check the path allowing a wilcard - provide for error return.
+****************************************************************************/
+
+size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
+ const char *inbuf,
+ uint16 smb_flags2,
+ char **pp_dest,
+ const char *src,
+ size_t src_len,
+ int flags,
+ NTSTATUS *err,
+ bool *contains_wcard)
+{
+ size_t ret;
+
+ *pp_dest = NULL;
+
+ if (src_len == 0) {
+ ret = srvstr_pull_buf_talloc(ctx,
+ inbuf,
+ smb_flags2,
+ pp_dest,
+ src,
+ flags);
+ } else {
+ ret = srvstr_pull_talloc(ctx,
+ inbuf,
+ smb_flags2,
+ pp_dest,
+ src,
+ src_len,
+ flags);
+ }
+
+ if (!*pp_dest) {
+ *err = NT_STATUS_INVALID_PARAMETER;
+ return ret;
+ }
+
+ *contains_wcard = False;
+
+ if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
+ /*
+ * For a DFS path the function parse_dfs_path()
+ * will do the path processing, just make a copy.
+ */
+ *err = NT_STATUS_OK;
+ return ret;
+ }
+
+ if (lp_posix_pathnames()) {
+ *err = check_path_syntax_posix(*pp_dest);
+ } else {
+ *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Pull a string and check the path - provide for error return.
+****************************************************************************/
+
+size_t srvstr_get_path(TALLOC_CTX *ctx,
+ const char *inbuf,
+ uint16 smb_flags2,
+ char **pp_dest,
+ const char *src,
+ size_t src_len,
+ int flags,
+ NTSTATUS *err)
+{
+ size_t ret;
+
+ *pp_dest = NULL;
+
+ if (src_len == 0) {
+ ret = srvstr_pull_buf_talloc(ctx,
+ inbuf,
+ smb_flags2,
+ pp_dest,
+ src,
+ flags);
+ } else {
+ ret = srvstr_pull_talloc(ctx,
+ inbuf,
+ smb_flags2,
+ pp_dest,
+ src,
+ src_len,
+ flags);
+ }
+
+ if (!*pp_dest) {
+ *err = NT_STATUS_INVALID_PARAMETER;
+ return ret;
+ }
+
+ if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
+ /*
+ * For a DFS path the function parse_dfs_path()
+ * will do the path processing, just make a copy.
+ */
+ *err = NT_STATUS_OK;
+ return ret;
+ }
+
+ if (lp_posix_pathnames()) {
+ *err = check_path_syntax_posix(*pp_dest);
+ } else {
+ *err = check_path_syntax(*pp_dest);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Check if we have a correct fsp pointing to a file. Basic check for open fsp.
+****************************************************************************/
+
+bool check_fsp_open(connection_struct *conn, struct smb_request *req,
+ files_struct *fsp)
+{
+ if (!(fsp) || !(conn)) {
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ return False;
+ }
+ if (((conn) != (fsp)->conn) || req->vuid != (fsp)->vuid) {
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ return False;
+ }
+ return True;
+}
+
+/****************************************************************************
+ Check if we have a correct fsp pointing to a file. Replacement for the
+ CHECK_FSP macro.
+****************************************************************************/
+
+bool check_fsp(connection_struct *conn, struct smb_request *req,
+ files_struct *fsp)
+{
+ if (!check_fsp_open(conn, req, fsp)) {
+ return False;
+ }
+ if ((fsp)->is_directory) {
+ reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
+ return False;
+ }
+ if ((fsp)->fh->fd == -1) {
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return False;
+ }
+ (fsp)->num_smb_operations++;
+ return True;
+}
+
+/****************************************************************************
+ Check if we have a correct fsp pointing to a quota fake file. Replacement for
+ the CHECK_NTQUOTA_HANDLE_OK macro.
+****************************************************************************/
+
+bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
+ files_struct *fsp)
+{
+ if (!check_fsp_open(conn, req, fsp)) {
+ return false;
+ }
+
+ if (fsp->is_directory) {
+ return false;
+ }
+
+ if (fsp->fake_file_handle == NULL) {
+ return false;
+ }
+
+ if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
+ return false;
+ }
+
+ if (fsp->fake_file_handle->private_data == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************************
+ Check if we have a correct fsp. Replacement for the FSP_BELONGS_CONN macro
+****************************************************************************/
+
+bool fsp_belongs_conn(connection_struct *conn, struct smb_request *req,
+ files_struct *fsp)
+{
+ if ((fsp) && (conn) && ((conn)==(fsp)->conn)
+ && (req->vuid == (fsp)->vuid)) {
+ return True;
+ }
+
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ return False;
+}
+
+/****************************************************************************
+ Reply to a (netbios-level) special message.
+****************************************************************************/
+
+void reply_special(char *inbuf)
+{
+ int msg_type = CVAL(inbuf,0);
+ int msg_flags = CVAL(inbuf,1);
+ fstring name1,name2;
+ char name_type = 0;
+
+ /*
+ * We only really use 4 bytes of the outbuf, but for the smb_setlen
+ * calculation & friends (srv_send_smb uses that) we need the full smb
+ * header.
+ */
+ char outbuf[smb_size];
+
+ static bool already_got_session = False;
+
+ *name1 = *name2 = 0;
+
+ memset(outbuf, '\0', sizeof(outbuf));
+
+ smb_setlen(outbuf,0);
+
+ switch (msg_type) {
+ case 0x81: /* session request */
+
+ if (already_got_session) {
+ exit_server_cleanly("multiple session request not permitted");
+ }
+
+ SCVAL(outbuf,0,0x82);
+ SCVAL(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;
+ }
+ name_extract(inbuf,4,name1);
+ name_type = name_extract(inbuf,4 + name_len(inbuf + 4),name2);
+ DEBUG(2,("netbios connect: name1=%s name2=%s\n",
+ name1,name2));
+
+ set_local_machine_name(name1, True);
+ set_remote_machine_name(name2, True);
+
+ DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
+ get_local_machine_name(), get_remote_machine_name(),
+ name_type));
+
+ if (name_type == 'R') {
+ /* We are being asked for a pathworks session ---
+ no thanks! */
+ SCVAL(outbuf, 0,0x83);
+ break;
+ }
+
+ /* only add the client's machine name to the list
+ of possibly valid usernames if we are operating
+ in share mode security */
+ if (lp_security() == SEC_SHARE) {
+ add_session_user(get_remote_machine_name());
+ }
+
+ reload_services(True);
+ reopen_logs();
+
+ already_got_session = True;
+ break;
+
+ case 0x89: /* session keepalive request
+ (some old clients produce this?) */
+ SCVAL(outbuf,0,SMBkeepalive);
+ SCVAL(outbuf,3,0);
+ break;
+
+ case 0x82: /* positive session response */
+ case 0x83: /* negative session response */
+ case 0x84: /* retarget session response */
+ DEBUG(0,("Unexpected session response\n"));
+ break;
+
+ case SMBkeepalive: /* session keepalive */
+ default:
+ return;
+ }
+
+ DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
+ msg_type, msg_flags));
+
+ srv_send_smb(smbd_server_fd(), outbuf, false);
+ return;
+}
+
+/****************************************************************************
+ Reply to a tcon.
+ conn POINTER CAN BE NULL HERE !
+****************************************************************************/
+
+void reply_tcon(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ const char *service;
+ char *service_buf = NULL;
+ char *password = NULL;
+ char *dev = NULL;
+ int pwlen=0;
+ NTSTATUS nt_status;
+ char *p;
+ DATA_BLOB password_blob;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ START_PROFILE(SMBtcon);
+
+ if (smb_buflen(req->inbuf) < 4) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBtcon);
+ return;
+ }
+
+ p = smb_buf(req->inbuf)+1;
+ p += srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2,
+ &service_buf, p, STR_TERMINATE) + 1;
+ pwlen = srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2,
+ &password, p, STR_TERMINATE) + 1;
+ p += pwlen;
+ p += srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2,
+ &dev, p, STR_TERMINATE) + 1;
+
+ if (service_buf == NULL || password == NULL || dev == NULL) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBtcon);
+ return;
+ }
+ p = strrchr_m(service_buf,'\\');
+ if (p) {
+ service = p+1;
+ } else {
+ service = service_buf;
+ }
+
+ password_blob = data_blob(password, pwlen+1);
+
+ conn = make_connection(service,password_blob,dev,req->vuid,&nt_status);
+ req->conn = conn;
+
+ data_blob_clear_free(&password_blob);
+
+ if (!conn) {
+ reply_nterror(req, nt_status);
+ END_PROFILE(SMBtcon);
+ return;
+ }
+
+ reply_outbuf(req, 2, 0);
+ SSVAL(req->outbuf,smb_vwv0,max_recv);
+ SSVAL(req->outbuf,smb_vwv1,conn->cnum);
+ SSVAL(req->outbuf,smb_tid,conn->cnum);
+
+ DEBUG(3,("tcon service=%s cnum=%d\n",
+ service, conn->cnum));
+
+ END_PROFILE(SMBtcon);
+ return;
+}
+
+/****************************************************************************
+ Reply to a tcon and X.
+ conn POINTER CAN BE NULL HERE !
+****************************************************************************/
+
+void reply_tcon_and_X(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ char *service = NULL;
+ DATA_BLOB password;
+ TALLOC_CTX *ctx = talloc_tos();
+ /* what the cleint thinks the device is */
+ char *client_devicetype = NULL;
+ /* what the server tells the client the share represents */
+ const char *server_devicetype;
+ NTSTATUS nt_status;
+ int passlen;
+ char *path = NULL;
+ char *p, *q;
+ uint16 tcon_flags;
+
+ START_PROFILE(SMBtconX);
+
+ if (req->wct < 4) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBtconX);
+ return;
+ }
+
+ passlen = SVAL(req->inbuf,smb_vwv3);
+ tcon_flags = SVAL(req->inbuf,smb_vwv2);
+
+ /* we might have to close an old one */
+ if ((tcon_flags & 0x1) && conn) {
+ close_cnum(conn,req->vuid);
+ req->conn = NULL;
+ conn = NULL;
+ }
+
+ if ((passlen > MAX_PASS_LEN) || (passlen >= smb_buflen(req->inbuf))) {
+ reply_doserror(req, ERRDOS, ERRbuftoosmall);
+ END_PROFILE(SMBtconX);
+ return;
+ }
+
+ if (global_encrypted_passwords_negotiated) {
+ password = data_blob_talloc(talloc_tos(), smb_buf(req->inbuf),
+ passlen);
+ if (lp_security() == SEC_SHARE) {
+ /*
+ * Security = share always has a pad byte
+ * after the password.
+ */
+ p = smb_buf(req->inbuf) + passlen + 1;
+ } else {
+ p = smb_buf(req->inbuf) + passlen;
+ }
+ } else {
+ password = data_blob_talloc(talloc_tos(), smb_buf(req->inbuf),
+ passlen+1);
+ /* Ensure correct termination */
+ password.data[passlen]=0;
+ p = smb_buf(req->inbuf) + passlen + 1;
+ }
+
+ p += srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2, &path, p,
+ STR_TERMINATE);
+
+ if (path == NULL) {
+ data_blob_clear_free(&password);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBtconX);
+ return;
+ }
+
+ /*
+ * the service name can be either: \\server\share
+ * or share directly like on the DELL PowerVault 705
+ */
+ if (*path=='\\') {
+ q = strchr_m(path+2,'\\');
+ if (!q) {
+ data_blob_clear_free(&password);
+ reply_doserror(req, ERRDOS, ERRnosuchshare);
+ END_PROFILE(SMBtconX);
+ return;
+ }
+ service = q+1;
+ } else {
+ service = path;
+ }
+
+ p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
+ &client_devicetype, p,
+ MIN(6,smb_bufrem(req->inbuf, p)), STR_ASCII);
+
+ if (client_devicetype == NULL) {
+ data_blob_clear_free(&password);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBtconX);
+ return;
+ }
+
+ DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
+
+ conn = make_connection(service, password, client_devicetype,
+ req->vuid, &nt_status);
+ req->conn =conn;
+
+ data_blob_clear_free(&password);
+
+ if (!conn) {
+ reply_nterror(req, nt_status);
+ END_PROFILE(SMBtconX);
+ return;
+ }
+
+ if ( IS_IPC(conn) )
+ server_devicetype = "IPC";
+ else if ( IS_PRINT(conn) )
+ server_devicetype = "LPT1:";
+ else
+ server_devicetype = "A:";
+
+ if (Protocol < PROTOCOL_NT1) {
+ reply_outbuf(req, 2, 0);
+ if (message_push_string(&req->outbuf, server_devicetype,
+ STR_TERMINATE|STR_ASCII) == -1) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBtconX);
+ return;
+ }
+ } else {
+ /* NT sets the fstype of IPC$ to the null string */
+ const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
+
+ if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
+ /* Return permissions. */
+ uint32 perm1 = 0;
+ uint32 perm2 = 0;
+
+ reply_outbuf(req, 7, 0);
+
+ if (IS_IPC(conn)) {
+ perm1 = FILE_ALL_ACCESS;
+ perm2 = FILE_ALL_ACCESS;
+ } else {
+ perm1 = CAN_WRITE(conn) ?
+ SHARE_ALL_ACCESS :
+ SHARE_READ_ONLY;
+ }
+
+ SIVAL(req->outbuf, smb_vwv3, perm1);
+ SIVAL(req->outbuf, smb_vwv5, perm2);
+ } else {
+ reply_outbuf(req, 3, 0);
+ }
+
+ if ((message_push_string(&req->outbuf, server_devicetype,
+ STR_TERMINATE|STR_ASCII) == -1)
+ || (message_push_string(&req->outbuf, fstype,
+ STR_TERMINATE) == -1)) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBtconX);
+ return;
+ }
+
+ /* what does setting this bit do? It is set by NT4 and
+ may affect the ability to autorun mounted cdroms */
+ SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
+ (lp_csc_policy(SNUM(conn)) << 2));
+
+ init_dfsroot(conn, req->inbuf, req->outbuf);
+ }
+
+
+ DEBUG(3,("tconX service=%s \n",
+ service));
+
+ /* set the incoming and outgoing tid to the just created one */
+ SSVAL(req->inbuf,smb_tid,conn->cnum);
+ SSVAL(req->outbuf,smb_tid,conn->cnum);
+
+ END_PROFILE(SMBtconX);
+
+ chain_reply(req);
+ return;
+}
+
+/****************************************************************************
+ Reply to an unknown type.
+****************************************************************************/
+
+void reply_unknown_new(struct smb_request *req, uint8 type)
+{
+ DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
+ smb_fn_name(type), type, type));
+ reply_doserror(req, ERRSRV, ERRunknownsmb);
+ return;
+}
+
+/****************************************************************************
+ Reply to an ioctl.
+ conn POINTER CAN BE NULL HERE !
+****************************************************************************/
+
+void reply_ioctl(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ uint16 device;
+ uint16 function;
+ uint32 ioctl_code;
+ int replysize;
+ char *p;
+
+ START_PROFILE(SMBioctl);
+
+ if (req->wct < 3) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBioctl);
+ return;
+ }
+
+ device = SVAL(req->inbuf,smb_vwv1);
+ function = SVAL(req->inbuf,smb_vwv2);
+ ioctl_code = (device << 16) + function;
+
+ DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
+
+ switch (ioctl_code) {
+ case IOCTL_QUERY_JOB_INFO:
+ replysize = 32;
+ break;
+ default:
+ reply_doserror(req, ERRSRV, ERRnosupport);
+ END_PROFILE(SMBioctl);
+ return;
+ }
+
+ reply_outbuf(req, 8, replysize+1);
+ SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
+ SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
+ SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
+ p = smb_buf(req->outbuf);
+ memset(p, '\0', replysize+1); /* valgrind-safe. */
+ p += 1; /* Allow for alignment */
+
+ switch (ioctl_code) {
+ case IOCTL_QUERY_JOB_INFO:
+ {
+ files_struct *fsp = file_fsp(SVAL(req->inbuf,
+ smb_vwv0));
+ if (!fsp) {
+ reply_doserror(req, ERRDOS, ERRbadfid);
+ END_PROFILE(SMBioctl);
+ return;
+ }
+ SSVAL(p,0,fsp->rap_print_jobid); /* Job number */
+ srvstr_push((char *)req->outbuf, req->flags2, p+2,
+ global_myname(), 15,
+ STR_TERMINATE|STR_ASCII);
+ if (conn) {
+ srvstr_push((char *)req->outbuf, req->flags2,
+ p+18, lp_servicename(SNUM(conn)),
+ 13, STR_TERMINATE|STR_ASCII);
+ } else {
+ memset(p+18, 0, 13);
+ }
+ break;
+ }
+ }
+
+ END_PROFILE(SMBioctl);
+ return;
+}
+
+/****************************************************************************
+ Strange checkpath NTSTATUS mapping.
+****************************************************************************/
+
+static NTSTATUS map_checkpath_error(const char *inbuf, NTSTATUS status)
+{
+ /* Strange DOS error code semantics only for checkpath... */
+ if (!(SVAL(inbuf,smb_flg2) & FLAGS2_32_BIT_ERROR_CODES)) {
+ if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
+ /* We need to map to ERRbadpath */
+ return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+ }
+ return status;
+}
+
+/****************************************************************************
+ Reply to a checkpath.
+****************************************************************************/
+
+void reply_checkpath(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ char *name = NULL;
+ SMB_STRUCT_STAT sbuf;
+ NTSTATUS status;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ START_PROFILE(SMBcheckpath);
+
+ srvstr_get_path(ctx,(char *)req->inbuf, req->flags2, &name,
+ smb_buf(req->inbuf) + 1, 0,
+ STR_TERMINATE, &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ status = map_checkpath_error((char *)req->inbuf, status);
+ reply_nterror(req, status);
+ END_PROFILE(SMBcheckpath);
+ return;
+ }
+
+ status = resolve_dfspath(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ name,
+ &name);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ END_PROFILE(SMBcheckpath);
+ return;
+ }
+ goto path_err;
+ }
+
+ DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->inbuf,smb_vwv0)));
+
+ status = unix_convert(ctx, conn, name, False, &name, NULL, &sbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto path_err;
+ }
+
+ status = check_name(conn, name);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3,("reply_checkpath: check_name of %s failed (%s)\n",name,nt_errstr(status)));
+ goto path_err;
+ }
+
+ if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,name,&sbuf) != 0)) {
+ DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",name,strerror(errno)));
+ status = map_nt_error_from_unix(errno);
+ goto path_err;
+ }
+
+ if (!S_ISDIR(sbuf.st_mode)) {
+ reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
+ ERRDOS, ERRbadpath);
+ END_PROFILE(SMBcheckpath);
+ return;
+ }
+
+ reply_outbuf(req, 0, 0);
+
+ END_PROFILE(SMBcheckpath);
+ return;
+
+ path_err:
+
+ END_PROFILE(SMBcheckpath);
+
+ /* 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.
+ */
+ status = map_checkpath_error((char *)req->inbuf, status);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ /*
+ * Windows returns different error codes if
+ * the parent directory is valid but not the
+ * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
+ * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
+ * if the path is invalid.
+ */
+ reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERRbadpath);
+ return;
+ }
+
+ reply_nterror(req, status);
+}
+
+/****************************************************************************
+ Reply to a getatr.
+****************************************************************************/
+
+void reply_getatr(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ char *fname = NULL;
+ SMB_STRUCT_STAT sbuf;
+ int mode=0;
+ SMB_OFF_T size=0;
+ time_t mtime=0;
+ char *p;
+ NTSTATUS status;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ START_PROFILE(SMBgetatr);
+
+ p = smb_buf(req->inbuf) + 1;
+ p += srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname, p,
+ 0, STR_TERMINATE, &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBgetatr);
+ return;
+ }
+
+ status = resolve_dfspath(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ fname,
+ &fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ END_PROFILE(SMBgetatr);
+ return;
+ }
+ reply_nterror(req, status);
+ END_PROFILE(SMBgetatr);
+ return;
+ }
+
+ /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
+ under WfWg - weird! */
+ if (*fname == '\0') {
+ mode = aHIDDEN | aDIR;
+ if (!CAN_WRITE(conn)) {
+ mode |= aRONLY;
+ }
+ size = 0;
+ mtime = 0;
+ } else {
+ status = unix_convert(ctx, conn, fname, False, &fname, NULL,&sbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBgetatr);
+ return;
+ }
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3,("reply_getatr: check_name of %s failed (%s)\n",fname,nt_errstr(status)));
+ reply_nterror(req, status);
+ END_PROFILE(SMBgetatr);
+ return;
+ }
+ if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,fname,&sbuf) != 0)) {
+ DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",fname,strerror(errno)));
+ reply_unixerror(req, ERRDOS,ERRbadfile);
+ END_PROFILE(SMBgetatr);
+ return;
+ }
+
+ mode = dos_mode(conn,fname,&sbuf);
+ size = sbuf.st_size;
+ mtime = sbuf.st_mtime;
+ if (mode & aDIR) {
+ size = 0;
+ }
+ }
+
+ reply_outbuf(req, 10, 0);
+
+ SSVAL(req->outbuf,smb_vwv0,mode);
+ if(lp_dos_filetime_resolution(SNUM(conn)) ) {
+ srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
+ } else {
+ srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
+ }
+ SIVAL(req->outbuf,smb_vwv3,(uint32)size);
+
+ if (Protocol >= PROTOCOL_NT1) {
+ SSVAL(req->outbuf, smb_flg2,
+ SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
+ }
+
+ DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n", fname, mode, (unsigned int)size ) );
+
+ END_PROFILE(SMBgetatr);
+ return;
+}
+
+/****************************************************************************
+ Reply to a setatr.
+****************************************************************************/
+
+void reply_setatr(struct smb_request *req)
+{
+ struct timespec ts[2];
+ connection_struct *conn = req->conn;
+ char *fname = NULL;
+ int mode;
+ time_t mtime;
+ SMB_STRUCT_STAT sbuf;
+ char *p;
+ NTSTATUS status;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ START_PROFILE(SMBsetatr);
+
+ ZERO_STRUCT(ts);
+
+ if (req->wct < 2) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ p = smb_buf(req->inbuf) + 1;
+ p += srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname, p,
+ 0, STR_TERMINATE, &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBsetatr);
+ return;
+ }
+
+ status = resolve_dfspath(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ fname,
+ &fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ END_PROFILE(SMBsetatr);
+ return;
+ }
+ reply_nterror(req, status);
+ END_PROFILE(SMBsetatr);
+ return;
+ }
+
+ status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBsetatr);
+ return;
+ }
+
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBsetatr);
+ return;
+ }
+
+ if (fname[0] == '.' && fname[1] == '\0') {
+ /*
+ * Not sure here is the right place to catch this
+ * condition. Might be moved to somewhere else later -- vl
+ */
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+ END_PROFILE(SMBsetatr);
+ return;
+ }
+
+ mode = SVAL(req->inbuf,smb_vwv0);
+ mtime = srv_make_unix_date3(req->inbuf+smb_vwv1);
+
+ ts[1] = convert_time_t_to_timespec(mtime);
+ status = smb_set_file_time(conn, NULL, fname,
+ &sbuf, ts, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_unixerror(req, ERRDOS, ERRnoaccess);
+ END_PROFILE(SMBsetatr);
+ return;
+ }
+
+ if (mode != FILE_ATTRIBUTE_NORMAL) {
+ if (VALID_STAT_OF_DIR(sbuf))
+ mode |= aDIR;
+ else
+ mode &= ~aDIR;
+
+ if (file_set_dosmode(conn,fname,mode,&sbuf,NULL,false) != 0) {
+ reply_unixerror(req, ERRDOS, ERRnoaccess);
+ END_PROFILE(SMBsetatr);
+ return;
+ }
+ }
+
+ reply_outbuf(req, 0, 0);
+
+ DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
+
+ END_PROFILE(SMBsetatr);
+ return;
+}
+
+/****************************************************************************
+ Reply to a dskattr.
+****************************************************************************/
+
+void reply_dskattr(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ SMB_BIG_UINT dfree,dsize,bsize;
+ START_PROFILE(SMBdskattr);
+
+ if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (SMB_BIG_UINT)-1) {
+ reply_unixerror(req, ERRHRD, ERRgeneral);
+ END_PROFILE(SMBdskattr);
+ return;
+ }
+
+ reply_outbuf(req, 5, 0);
+
+ if (Protocol <= PROTOCOL_LANMAN2) {
+ double total_space, free_space;
+ /* we need to scale this to a number that DOS6 can handle. We
+ use floating point so we can handle large drives on systems
+ that don't have 64 bit integers
+
+ we end up displaying a maximum of 2G to DOS systems
+ */
+ total_space = dsize * (double)bsize;
+ free_space = dfree * (double)bsize;
+
+ dsize = (SMB_BIG_UINT)((total_space+63*512) / (64*512));
+ dfree = (SMB_BIG_UINT)((free_space+63*512) / (64*512));
+
+ if (dsize > 0xFFFF) dsize = 0xFFFF;
+ if (dfree > 0xFFFF) dfree = 0xFFFF;
+
+ SSVAL(req->outbuf,smb_vwv0,dsize);
+ SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
+ SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
+ SSVAL(req->outbuf,smb_vwv3,dfree);
+ } else {
+ SSVAL(req->outbuf,smb_vwv0,dsize);
+ SSVAL(req->outbuf,smb_vwv1,bsize/512);
+ SSVAL(req->outbuf,smb_vwv2,512);
+ SSVAL(req->outbuf,smb_vwv3,dfree);
+ }
+
+ DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
+
+ END_PROFILE(SMBdskattr);
+ return;
+}
+
+/****************************************************************************
+ Reply to a search.
+ Can be called from SMBsearch, SMBffirst or SMBfunique.
+****************************************************************************/
+
+void reply_search(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ char *mask = NULL;
+ char *directory = NULL;
+ char *fname = NULL;
+ SMB_OFF_T size;
+ uint32 mode;
+ time_t date;
+ uint32 dirtype;
+ unsigned int numentries = 0;
+ unsigned int maxentries = 0;
+ bool finished = False;
+ char *p;
+ int status_len;
+ char *path = NULL;
+ char status[21];
+ int dptr_num= -1;
+ bool check_descend = False;
+ bool expect_close = False;
+ NTSTATUS nt_status;
+ bool mask_contains_wcard = False;
+ bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
+ TALLOC_CTX *ctx = talloc_tos();
+ bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
+
+ START_PROFILE(SMBsearch);
+
+ if (req->wct < 2) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBsearch);
+ return;
+ }
+
+ if (lp_posix_pathnames()) {
+ reply_unknown_new(req, CVAL(req->inbuf, smb_com));
+ END_PROFILE(SMBsearch);
+ return;
+ }
+
+ /* If we were called as SMBffirst then we must expect close. */
+ if(CVAL(req->inbuf,smb_com) == SMBffirst) {
+ expect_close = True;
+ }
+
+ reply_outbuf(req, 1, 3);
+ maxentries = SVAL(req->inbuf,smb_vwv0);
+ dirtype = SVAL(req->inbuf,smb_vwv1);
+ p = smb_buf(req->inbuf) + 1;
+ p += srvstr_get_path_wcard(ctx,
+ (char *)req->inbuf,
+ req->flags2,
+ &path,
+ p,
+ 0,
+ STR_TERMINATE,
+ &nt_status,
+ &mask_contains_wcard);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ reply_nterror(req, nt_status);
+ END_PROFILE(SMBsearch);
+ return;
+ }
+
+ nt_status = resolve_dfspath_wcard(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ path,
+ &path,
+ &mask_contains_wcard);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ END_PROFILE(SMBsearch);
+ return;
+ }
+ reply_nterror(req, nt_status);
+ END_PROFILE(SMBsearch);
+ return;
+ }
+
+ p++;
+ status_len = SVAL(p, 0);
+ p += 2;
+
+ /* dirtype &= ~aDIR; */
+
+ if (status_len == 0) {
+ SMB_STRUCT_STAT sbuf;
+
+ nt_status = unix_convert(ctx, conn, path, True,
+ &directory, NULL, &sbuf);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ reply_nterror(req, nt_status);
+ END_PROFILE(SMBsearch);
+ return;
+ }
+
+ nt_status = check_name(conn, directory);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ reply_nterror(req, nt_status);
+ END_PROFILE(SMBsearch);
+ return;
+ }
+
+ p = strrchr_m(directory,'/');
+ if (!p) {
+ mask = directory;
+ directory = talloc_strdup(ctx,".");
+ if (!directory) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBsearch);
+ return;
+ }
+ } else {
+ *p = 0;
+ mask = p+1;
+ }
+
+ if (*directory == '\0') {
+ directory = talloc_strdup(ctx,".");
+ if (!directory) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBsearch);
+ return;
+ }
+ }
+ memset((char *)status,'\0',21);
+ SCVAL(status,0,(dirtype & 0x1F));
+
+ nt_status = dptr_create(conn,
+ directory,
+ True,
+ expect_close,
+ req->smbpid,
+ mask,
+ mask_contains_wcard,
+ dirtype,
+ &conn->dirptr);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ reply_nterror(req, nt_status);
+ END_PROFILE(SMBsearch);
+ return;
+ }
+ dptr_num = dptr_dnum(conn->dirptr);
+ } else {
+ int status_dirtype;
+
+ memcpy(status,p,21);
+ status_dirtype = CVAL(status,0) & 0x1F;
+ if (status_dirtype != (dirtype & 0x1F)) {
+ dirtype = status_dirtype;
+ }
+
+ conn->dirptr = dptr_fetch(status+12,&dptr_num);
+ if (!conn->dirptr) {
+ goto SearchEmpty;
+ }
+ string_set(&conn->dirpath,dptr_path(dptr_num));
+ mask = dptr_wcard(dptr_num);
+ if (!mask) {
+ goto SearchEmpty;
+ }
+ /*
+ * For a 'continue' search we have no string. So
+ * check from the initial saved string.
+ */
+ mask_contains_wcard = ms_has_wild(mask);
+ dirtype = dptr_attr(dptr_num);
+ }
+
+ DEBUG(4,("dptr_num is %d\n",dptr_num));
+
+ if ((dirtype&0x1F) == aVOLID) {
+ char buf[DIR_STRUCT_SIZE];
+ memcpy(buf,status,21);
+ if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
+ 0,aVOLID,0,!allow_long_path_components)) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBsearch);
+ return;
+ }
+ dptr_fill(buf+12,dptr_num);
+ if (dptr_zero(buf+12) && (status_len==0)) {
+ numentries = 1;
+ } else {
+ numentries = 0;
+ }
+ if (message_push_blob(&req->outbuf,
+ data_blob_const(buf, sizeof(buf)))
+ == -1) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBsearch);
+ return;
+ }
+ } else {
+ unsigned int i;
+ maxentries = MIN(
+ maxentries,
+ ((BUFFER_SIZE -
+ ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
+ /DIR_STRUCT_SIZE));
+
+ 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(ctx,
+ conn,
+ mask,
+ dirtype,
+ &fname,
+ &size,
+ &mode,
+ &date,
+ check_descend,
+ ask_sharemode);
+ if (!finished) {
+ char buf[DIR_STRUCT_SIZE];
+ memcpy(buf,status,21);
+ if (!make_dir_struct(ctx,
+ buf,
+ mask,
+ fname,
+ size,
+ mode,
+ date,
+ !allow_long_path_components)) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBsearch);
+ return;
+ }
+ if (!dptr_fill(buf+12,dptr_num)) {
+ break;
+ }
+ if (message_push_blob(&req->outbuf,
+ data_blob_const(buf, sizeof(buf)))
+ == -1) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBsearch);
+ return;
+ }
+ numentries++;
+ }
+ }
+ }
+
+ SearchEmpty:
+
+ /* If we were called as SMBffirst with smb_search_id == NULL
+ and no entries were found then return error and close dirptr
+ (X/Open spec) */
+
+ if (numentries == 0) {
+ dptr_close(&dptr_num);
+ } else if(expect_close && status_len == 0) {
+ /* Close the dptr - we know it's gone */
+ dptr_close(&dptr_num);
+ }
+
+ /* If we were called as SMBfunique, then we can close the dirptr now ! */
+ if(dptr_num >= 0 && CVAL(req->inbuf,smb_com) == SMBfunique) {
+ dptr_close(&dptr_num);
+ }
+
+ if ((numentries == 0) && !mask_contains_wcard) {
+ reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
+ END_PROFILE(SMBsearch);
+ return;
+ }
+
+ SSVAL(req->outbuf,smb_vwv0,numentries);
+ SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
+ SCVAL(smb_buf(req->outbuf),0,5);
+ SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
+
+ /* The replies here are never long name. */
+ SSVAL(req->outbuf, smb_flg2,
+ SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
+ if (!allow_long_path_components) {
+ SSVAL(req->outbuf, smb_flg2,
+ SVAL(req->outbuf, smb_flg2)
+ & (~FLAGS2_LONG_PATH_COMPONENTS));
+ }
+
+ /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
+ SSVAL(req->outbuf, smb_flg2,
+ (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
+
+ if (!directory) {
+ directory = dptr_path(dptr_num);
+ }
+
+ DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
+ smb_fn_name(CVAL(req->inbuf,smb_com)),
+ mask,
+ directory ? directory : "./",
+ dirtype,
+ numentries,
+ maxentries ));
+
+ END_PROFILE(SMBsearch);
+ return;
+}
+
+/****************************************************************************
+ Reply to a fclose (stop directory search).
+****************************************************************************/
+
+void reply_fclose(struct smb_request *req)
+{
+ int status_len;
+ char status[21];
+ int dptr_num= -2;
+ char *p;
+ char *path = NULL;
+ NTSTATUS err;
+ bool path_contains_wcard = False;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ START_PROFILE(SMBfclose);
+
+ if (lp_posix_pathnames()) {
+ reply_unknown_new(req, CVAL(req->inbuf, smb_com));
+ END_PROFILE(SMBfclose);
+ return;
+ }
+
+ p = smb_buf(req->inbuf) + 1;
+ p += srvstr_get_path_wcard(ctx,
+ (char *)req->inbuf,
+ req->flags2,
+ &path,
+ p,
+ 0,
+ STR_TERMINATE,
+ &err,
+ &path_contains_wcard);
+ if (!NT_STATUS_IS_OK(err)) {
+ reply_nterror(req, err);
+ END_PROFILE(SMBfclose);
+ return;
+ }
+ p++;
+ status_len = SVAL(p,0);
+ p += 2;
+
+ if (status_len == 0) {
+ reply_doserror(req, ERRSRV, ERRsrverror);
+ END_PROFILE(SMBfclose);
+ return;
+ }
+
+ memcpy(status,p,21);
+
+ if(dptr_fetch(status+12,&dptr_num)) {
+ /* Close the dptr - we know it's gone */
+ dptr_close(&dptr_num);
+ }
+
+ reply_outbuf(req, 1, 0);
+ SSVAL(req->outbuf,smb_vwv0,0);
+
+ DEBUG(3,("search close\n"));
+
+ END_PROFILE(SMBfclose);
+ return;
+}
+
+/****************************************************************************
+ Reply to an open.
+****************************************************************************/
+
+void reply_open(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ char *fname = NULL;
+ uint32 fattr=0;
+ SMB_OFF_T size = 0;
+ time_t mtime=0;
+ int info;
+ SMB_STRUCT_STAT sbuf;
+ files_struct *fsp;
+ int oplock_request;
+ int deny_mode;
+ uint32 dos_attr;
+ uint32 access_mask;
+ uint32 share_mode;
+ uint32 create_disposition;
+ uint32 create_options = 0;
+ NTSTATUS status;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ START_PROFILE(SMBopen);
+
+ if (req->wct < 2) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBopen);
+ return;
+ }
+
+ oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
+ deny_mode = SVAL(req->inbuf,smb_vwv0);
+ dos_attr = SVAL(req->inbuf,smb_vwv1);
+
+ srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
+ smb_buf(req->inbuf)+1, 0,
+ STR_TERMINATE, &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBopen);
+ return;
+ }
+
+ if (!map_open_params_to_ntcreate(
+ fname, deny_mode, OPENX_FILE_EXISTS_OPEN, &access_mask,
+ &share_mode, &create_disposition, &create_options)) {
+ reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess));
+ END_PROFILE(SMBopen);
+ return;
+ }
+
+ status = create_file(conn, /* conn */
+ req, /* req */
+ 0, /* root_dir_fid */
+ fname, /* fname */
+ access_mask, /* access_mask */
+ share_mode, /* share_access */
+ create_disposition, /* create_disposition*/
+ create_options, /* create_options */
+ dos_attr, /* file_attributes */
+ oplock_request, /* oplock_request */
+ 0, /* allocation_size */
+ NULL, /* sd */
+ NULL, /* ea_list */
+ &fsp, /* result */
+ &info, /* pinfo */
+ &sbuf); /* psbuf */
+
+ if (!NT_STATUS_IS_OK(status)) {
+ if (open_was_deferred(req->mid)) {
+ /* We have re-scheduled this call. */
+ END_PROFILE(SMBopen);
+ return;
+ }
+ reply_openerror(req, status);
+ END_PROFILE(SMBopen);
+ return;
+ }
+
+ size = sbuf.st_size;
+ fattr = dos_mode(conn,fsp->fsp_name,&sbuf);
+ mtime = sbuf.st_mtime;
+
+ if (fattr & aDIR) {
+ DEBUG(3,("attempt to open a directory %s\n",fsp->fsp_name));
+ close_file(fsp,ERROR_CLOSE);
+ reply_doserror(req, ERRDOS,ERRnoaccess);
+ END_PROFILE(SMBopen);
+ return;
+ }
+
+ reply_outbuf(req, 7, 0);
+ SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
+ SSVAL(req->outbuf,smb_vwv1,fattr);
+ if(lp_dos_filetime_resolution(SNUM(conn)) ) {
+ srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
+ } else {
+ srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
+ }
+ SIVAL(req->outbuf,smb_vwv4,(uint32)size);
+ SSVAL(req->outbuf,smb_vwv6,deny_mode);
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ SCVAL(req->outbuf,smb_flg,
+ CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
+ }
+
+ if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ SCVAL(req->outbuf,smb_flg,
+ CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
+ }
+ END_PROFILE(SMBopen);
+ return;
+}
+
+/****************************************************************************
+ Reply to an open and X.
+****************************************************************************/
+
+void reply_open_and_X(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ char *fname = NULL;
+ uint16 open_flags;
+ int deny_mode;
+ uint32 smb_attr;
+ /* Breakout the oplock request bits so we can set the
+ reply bits separately. */
+ int ex_oplock_request;
+ int core_oplock_request;
+ int oplock_request;
+#if 0
+ int smb_sattr = SVAL(req->inbuf,smb_vwv4);
+ uint32 smb_time = make_unix_date3(req->inbuf+smb_vwv6);
+#endif
+ int smb_ofun;
+ uint32 fattr=0;
+ int mtime=0;
+ SMB_STRUCT_STAT sbuf;
+ int smb_action = 0;
+ files_struct *fsp;
+ NTSTATUS status;
+ SMB_BIG_UINT allocation_size;
+ ssize_t retval = -1;
+ uint32 access_mask;
+ uint32 share_mode;
+ uint32 create_disposition;
+ uint32 create_options = 0;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ START_PROFILE(SMBopenX);
+
+ if (req->wct < 15) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBopenX);
+ return;
+ }
+
+ open_flags = SVAL(req->inbuf,smb_vwv2);
+ deny_mode = SVAL(req->inbuf,smb_vwv3);
+ smb_attr = SVAL(req->inbuf,smb_vwv5);
+ ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
+ core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
+ oplock_request = ex_oplock_request | core_oplock_request;
+ smb_ofun = SVAL(req->inbuf,smb_vwv8);
+ allocation_size = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv9);
+
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn)) {
+ if (lp_nt_pipe_support()) {
+ reply_open_pipe_and_X(conn, req);
+ } else {
+ reply_doserror(req, ERRSRV, ERRaccess);
+ }
+ END_PROFILE(SMBopenX);
+ return;
+ }
+
+ /* XXXX we need to handle passed times, sattr and flags */
+ srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
+ smb_buf(req->inbuf), 0, STR_TERMINATE,
+ &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBopenX);
+ return;
+ }
+
+ if (!map_open_params_to_ntcreate(
+ fname, deny_mode, smb_ofun, &access_mask,
+ &share_mode, &create_disposition, &create_options)) {
+ reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess));
+ END_PROFILE(SMBopenX);
+ return;
+ }
+
+ status = create_file(conn, /* conn */
+ req, /* req */
+ 0, /* root_dir_fid */
+ fname, /* fname */
+ access_mask, /* access_mask */
+ share_mode, /* share_access */
+ create_disposition, /* create_disposition*/
+ create_options, /* create_options */
+ smb_attr, /* file_attributes */
+ oplock_request, /* oplock_request */
+ 0, /* allocation_size */
+ NULL, /* sd */
+ NULL, /* ea_list */
+ &fsp, /* result */
+ &smb_action, /* pinfo */
+ &sbuf); /* psbuf */
+
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBopenX);
+ if (open_was_deferred(req->mid)) {
+ /* We have re-scheduled this call. */
+ return;
+ }
+ reply_openerror(req, status);
+ return;
+ }
+
+ /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
+ if the file is truncated or created. */
+ if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
+ fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
+ if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
+ close_file(fsp,ERROR_CLOSE);
+ reply_nterror(req, NT_STATUS_DISK_FULL);
+ END_PROFILE(SMBopenX);
+ return;
+ }
+ retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
+ if (retval < 0) {
+ close_file(fsp,ERROR_CLOSE);
+ reply_nterror(req, NT_STATUS_DISK_FULL);
+ END_PROFILE(SMBopenX);
+ return;
+ }
+ sbuf.st_size = get_allocation_size(conn,fsp,&sbuf);
+ }
+
+ fattr = dos_mode(conn,fsp->fsp_name,&sbuf);
+ mtime = sbuf.st_mtime;
+ if (fattr & aDIR) {
+ close_file(fsp,ERROR_CLOSE);
+ reply_doserror(req, ERRDOS, ERRnoaccess);
+ END_PROFILE(SMBopenX);
+ return;
+ }
+
+ /* If the caller set the extended oplock request bit
+ and we granted one (by whatever means) - set the
+ correct bit for extended oplock reply.
+ */
+
+ if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+ }
+
+ if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+ }
+
+ /* If the caller set the core oplock request bit
+ and we granted one (by whatever means) - set the
+ correct bit for core oplock reply.
+ */
+
+ if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
+ reply_outbuf(req, 19, 0);
+ } else {
+ reply_outbuf(req, 15, 0);
+ }
+
+ if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ SCVAL(req->outbuf, smb_flg,
+ CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
+ }
+
+ if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ SCVAL(req->outbuf, smb_flg,
+ CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
+ }
+
+ SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
+ SSVAL(req->outbuf,smb_vwv3,fattr);
+ if(lp_dos_filetime_resolution(SNUM(conn)) ) {
+ srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
+ } else {
+ srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
+ }
+ SIVAL(req->outbuf,smb_vwv6,(uint32)sbuf.st_size);
+ SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
+ SSVAL(req->outbuf,smb_vwv11,smb_action);
+
+ if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
+ SIVAL(req->outbuf, smb_vwv15, STD_RIGHT_ALL_ACCESS);
+ }
+
+ END_PROFILE(SMBopenX);
+ chain_reply(req);
+ return;
+}
+
+/****************************************************************************
+ Reply to a SMBulogoffX.
+****************************************************************************/
+
+void reply_ulogoffX(struct smb_request *req)
+{
+ user_struct *vuser;
+
+ START_PROFILE(SMBulogoffX);
+
+ vuser = get_valid_user_struct(req->vuid);
+
+ if(vuser == NULL) {
+ DEBUG(3,("ulogoff, vuser id %d does not map to user.\n",
+ req->vuid));
+ }
+
+ /* in user level security we are supposed to close any files
+ open by this user */
+ if ((vuser != NULL) && (lp_security() != SEC_SHARE)) {
+ file_close_user(req->vuid);
+ }
+
+ invalidate_vuid(req->vuid);
+
+ reply_outbuf(req, 2, 0);
+
+ DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) );
+
+ END_PROFILE(SMBulogoffX);
+ chain_reply(req);
+}
+
+/****************************************************************************
+ Reply to a mknew or a create.
+****************************************************************************/
+
+void reply_mknew(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ char *fname = NULL;
+ int com;
+ uint32 fattr = 0;
+ struct timespec ts[2];
+ files_struct *fsp;
+ int oplock_request = 0;
+ SMB_STRUCT_STAT sbuf;
+ NTSTATUS status;
+ uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
+ uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
+ uint32 create_disposition;
+ uint32 create_options = 0;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ START_PROFILE(SMBcreate);
+
+ if (req->wct < 3) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBcreate);
+ return;
+ }
+
+ fattr = SVAL(req->inbuf,smb_vwv0);
+ oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
+ com = SVAL(req->inbuf,smb_com);
+
+ ts[1] =convert_time_t_to_timespec(
+ srv_make_unix_date3(req->inbuf + smb_vwv1));
+ /* mtime. */
+
+ srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
+ smb_buf(req->inbuf) + 1, 0,
+ STR_TERMINATE, &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBcreate);
+ return;
+ }
+
+ if (fattr & aVOLID) {
+ DEBUG(0,("Attempt to create file (%s) with volid set - "
+ "please report this\n", fname));
+ }
+
+ if(com == SMBmknew) {
+ /* We should fail if file exists. */
+ create_disposition = FILE_CREATE;
+ } else {
+ /* Create if file doesn't exist, truncate if it does. */
+ create_disposition = FILE_OVERWRITE_IF;
+ }
+
+ status = create_file(conn, /* conn */
+ req, /* req */
+ 0, /* root_dir_fid */
+ fname, /* fname */
+ access_mask, /* access_mask */
+ share_mode, /* share_access */
+ create_disposition, /* create_disposition*/
+ create_options, /* create_options */
+ fattr, /* file_attributes */
+ oplock_request, /* oplock_request */
+ 0, /* allocation_size */
+ NULL, /* sd */
+ NULL, /* ea_list */
+ &fsp, /* result */
+ NULL, /* pinfo */
+ &sbuf); /* psbuf */
+
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBcreate);
+ if (open_was_deferred(req->mid)) {
+ /* We have re-scheduled this call. */
+ return;
+ }
+ reply_openerror(req, status);
+ return;
+ }
+
+ ts[0] = get_atimespec(&sbuf); /* atime. */
+ status = smb_set_file_time(conn, fsp, fsp->fsp_name, &sbuf, ts, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBcreate);
+ reply_openerror(req, status);
+ return;
+ }
+
+ reply_outbuf(req, 1, 0);
+ SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ SCVAL(req->outbuf,smb_flg,
+ CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
+ }
+
+ if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ SCVAL(req->outbuf,smb_flg,
+ CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
+ }
+
+ DEBUG( 2, ( "reply_mknew: file %s\n", fsp->fsp_name ) );
+ DEBUG( 3, ( "reply_mknew %s fd=%d dmode=0x%x\n",
+ fsp->fsp_name, fsp->fh->fd, (unsigned int)fattr ) );
+
+ END_PROFILE(SMBcreate);
+ return;
+}
+
+/****************************************************************************
+ Reply to a create temporary file.
+****************************************************************************/
+
+void reply_ctemp(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ char *fname = NULL;
+ uint32 fattr;
+ files_struct *fsp;
+ int oplock_request;
+ int tmpfd;
+ SMB_STRUCT_STAT sbuf;
+ char *s;
+ NTSTATUS status;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ START_PROFILE(SMBctemp);
+
+ if (req->wct < 3) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBctemp);
+ return;
+ }
+
+ fattr = SVAL(req->inbuf,smb_vwv0);
+ oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
+
+ srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
+ smb_buf(req->inbuf)+1, 0, STR_TERMINATE,
+ &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBctemp);
+ return;
+ }
+ if (*fname) {
+ fname = talloc_asprintf(ctx,
+ "%s/TMXXXXXX",
+ fname);
+ } else {
+ fname = talloc_strdup(ctx, "TMXXXXXX");
+ }
+
+ if (!fname) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBctemp);
+ return;
+ }
+
+ status = resolve_dfspath(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ fname,
+ &fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ END_PROFILE(SMBctemp);
+ return;
+ }
+ reply_nterror(req, status);
+ END_PROFILE(SMBctemp);
+ return;
+ }
+
+ status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBctemp);
+ return;
+ }
+
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBctemp);
+ return;
+ }
+
+ tmpfd = smb_mkstemp(fname);
+ if (tmpfd == -1) {
+ reply_unixerror(req, ERRDOS, ERRnoaccess);
+ END_PROFILE(SMBctemp);
+ return;
+ }
+
+ SMB_VFS_STAT(conn,fname,&sbuf);
+
+ /* We should fail if file does not exist. */
+ status = open_file_ntcreate(conn, req, fname, &sbuf,
+ FILE_GENERIC_READ | FILE_GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN,
+ 0,
+ fattr,
+ oplock_request,
+ NULL, &fsp);
+
+ /* close fd from smb_mkstemp() */
+ close(tmpfd);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ if (open_was_deferred(req->mid)) {
+ /* We have re-scheduled this call. */
+ END_PROFILE(SMBctemp);
+ return;
+ }
+ reply_openerror(req, status);
+ END_PROFILE(SMBctemp);
+ return;
+ }
+
+ reply_outbuf(req, 1, 0);
+ SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
+
+ /* the returned filename is relative to the directory */
+ s = strrchr_m(fsp->fsp_name, '/');
+ if (!s) {
+ s = fsp->fsp_name;
+ } else {
+ s++;
+ }
+
+#if 0
+ /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
+ thing in the byte section. JRA */
+ SSVALS(p, 0, -1); /* what is this? not in spec */
+#endif
+ if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
+ == -1) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBctemp);
+ return;
+ }
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ SCVAL(req->outbuf, smb_flg,
+ CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
+ }
+
+ if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ SCVAL(req->outbuf, smb_flg,
+ CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
+ }
+
+ DEBUG( 2, ( "reply_ctemp: created temp file %s\n", fsp->fsp_name ) );
+ DEBUG( 3, ( "reply_ctemp %s fd=%d umode=0%o\n", fsp->fsp_name,
+ fsp->fh->fd, (unsigned int)sbuf.st_mode ) );
+
+ END_PROFILE(SMBctemp);
+ return;
+}
+
+/*******************************************************************
+ Check if a user is allowed to rename a file.
+********************************************************************/
+
+static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
+ uint16 dirtype, SMB_STRUCT_STAT *pst)
+{
+ uint32 fmode;
+
+ if (!CAN_WRITE(conn)) {
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+ }
+
+ fmode = dos_mode(conn, fsp->fsp_name, pst);
+ if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) {
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+ if (S_ISDIR(pst->st_mode)) {
+ return NT_STATUS_OK;
+ }
+
+ if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
+ return NT_STATUS_OK;
+ }
+
+ return NT_STATUS_ACCESS_DENIED;
+}
+
+/*******************************************************************
+ * unlink a file with all relevant access checks
+ *******************************************************************/
+
+static NTSTATUS do_unlink(connection_struct *conn,
+ struct smb_request *req,
+ const char *fname,
+ uint32 dirtype)
+{
+ SMB_STRUCT_STAT sbuf;
+ uint32 fattr;
+ files_struct *fsp;
+ uint32 dirtype_orig = dirtype;
+ NTSTATUS status;
+
+ DEBUG(10,("do_unlink: %s, dirtype = %d\n", fname, dirtype ));
+
+ if (!CAN_WRITE(conn)) {
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+ }
+
+ if (SMB_VFS_LSTAT(conn,fname,&sbuf) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ fattr = dos_mode(conn,fname,&sbuf);
+
+ if (dirtype & FILE_ATTRIBUTE_NORMAL) {
+ dirtype = aDIR|aARCH|aRONLY;
+ }
+
+ dirtype &= (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM);
+ if (!dirtype) {
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+ if (!dir_check_ftype(conn, fattr, dirtype)) {
+ if (fattr & aDIR) {
+ return NT_STATUS_FILE_IS_A_DIRECTORY;
+ }
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+ if (dirtype_orig & 0x8000) {
+ /* These will never be set for POSIX. */
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+#if 0
+ if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
+ return NT_STATUS_FILE_IS_A_DIRECTORY;
+ }
+
+ if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+ if (dirtype & 0xFF00) {
+ /* These will never be set for POSIX. */
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+ dirtype &= 0xFF;
+ if (!dirtype) {
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+ /* Can't delete a directory. */
+ if (fattr & aDIR) {
+ return NT_STATUS_FILE_IS_A_DIRECTORY;
+ }
+#endif
+
+#if 0 /* JRATEST */
+ else if (dirtype & aDIR) /* Asked for a directory and it isn't. */
+ return NT_STATUS_OBJECT_NAME_INVALID;
+#endif /* JRATEST */
+
+ /* Fix for bug #3035 from SATOH Fumiyasu <fumiyas@miraclelinux.com>
+
+ On a Windows share, a file with read-only dosmode can be opened with
+ DELETE_ACCESS. But on a Samba share (delete readonly = no), it
+ fails with NT_STATUS_CANNOT_DELETE error.
+
+ This semantic causes a problem that a user can not
+ rename a file with read-only dosmode on a Samba share
+ from a Windows command prompt (i.e. cmd.exe, but can rename
+ from Windows Explorer).
+ */
+
+ if (!lp_delete_readonly(SNUM(conn))) {
+ if (fattr & aRONLY) {
+ return NT_STATUS_CANNOT_DELETE;
+ }
+ }
+
+ /* On open checks the open itself will check the share mode, so
+ don't do it here as we'll get it wrong. */
+
+ status = create_file_unixpath
+ (conn, /* conn */
+ req, /* req */
+ fname, /* fname */
+ DELETE_ACCESS, /* access_mask */
+ FILE_SHARE_NONE, /* share_access */
+ FILE_OPEN, /* create_disposition*/
+ FILE_NON_DIRECTORY_FILE, /* create_options */
+ FILE_ATTRIBUTE_NORMAL, /* file_attributes */
+ 0, /* oplock_request */
+ 0, /* allocation_size */
+ NULL, /* sd */
+ NULL, /* ea_list */
+ &fsp, /* result */
+ NULL, /* pinfo */
+ &sbuf); /* psbuf */
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("create_file_unixpath failed: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ /* The set is across all open files on this dev/inode pair. */
+ if (!set_delete_on_close(fsp, True, &conn->server_info->utok)) {
+ close_file(fsp, NORMAL_CLOSE);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return close_file(fsp,NORMAL_CLOSE);
+}
+
+/****************************************************************************
+ The guts of the unlink command, split out so it may be called by the NT SMB
+ code.
+****************************************************************************/
+
+NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
+ uint32 dirtype, const char *name_in, bool has_wild)
+{
+ const char *directory = NULL;
+ char *mask = NULL;
+ char *name = NULL;
+ char *p = NULL;
+ int count=0;
+ NTSTATUS status = NT_STATUS_OK;
+ SMB_STRUCT_STAT sbuf;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ status = unix_convert(ctx, conn, name_in, has_wild, &name, NULL, &sbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ p = strrchr_m(name,'/');
+ if (!p) {
+ directory = talloc_strdup(ctx, ".");
+ if (!directory) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ mask = name;
+ } else {
+ *p = 0;
+ directory = name;
+ mask = p+1;
+ }
+
+ /*
+ * We should only check the mangled cache
+ * here if unix_convert failed. This means
+ * that the path in 'mask' doesn't exist
+ * on the file system and so we need to look
+ * for a possible mangle. This patch from
+ * Tine Smukavec <valentin.smukavec@hermes.si>.
+ */
+
+ if (!VALID_STAT(sbuf) && mangle_is_mangled(mask,conn->params)) {
+ char *new_mask = NULL;
+ mangle_lookup_name_from_8_3(ctx,
+ mask,
+ &new_mask,
+ conn->params );
+ if (new_mask) {
+ mask = new_mask;
+ }
+ }
+
+ if (!has_wild) {
+ directory = talloc_asprintf(ctx,
+ "%s/%s",
+ directory,
+ mask);
+ if (!directory) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (dirtype == 0) {
+ dirtype = FILE_ATTRIBUTE_NORMAL;
+ }
+
+ status = check_name(conn, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = do_unlink(conn, req, directory, dirtype);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ count++;
+ } else {
+ struct smb_Dir *dir_hnd = NULL;
+ long offset = 0;
+ const char *dname;
+
+ if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) {
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+
+ if (strequal(mask,"????????.???")) {
+ mask[0] = '*';
+ mask[1] = '\0';
+ }
+
+ status = check_name(conn, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ dir_hnd = OpenDir(talloc_tos(), conn, directory, mask,
+ dirtype);
+ if (dir_hnd == NULL) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ /* 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
+ */
+
+ status = NT_STATUS_NO_SUCH_FILE;
+
+ while ((dname = ReadDirName(dir_hnd, &offset))) {
+ SMB_STRUCT_STAT st;
+ char *fname = NULL;
+
+ if (!is_visible_file(conn, directory, dname, &st, True)) {
+ continue;
+ }
+
+ /* Quick check for "." and ".." */
+ if (ISDOT(dname) || ISDOTDOT(dname)) {
+ continue;
+ }
+
+ if(!mask_match(dname, mask, conn->case_sensitive)) {
+ continue;
+ }
+
+ fname = talloc_asprintf(ctx, "%s/%s",
+ directory,
+ dname);
+ if (!fname) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(dir_hnd);
+ return status;
+ }
+
+ status = do_unlink(conn, req, fname, dirtype);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(fname);
+ continue;
+ }
+
+ count++;
+ DEBUG(3,("unlink_internals: successful unlink [%s]\n",
+ fname));
+
+ TALLOC_FREE(fname);
+ }
+ TALLOC_FREE(dir_hnd);
+ }
+
+ if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
+ status = map_nt_error_from_unix(errno);
+ }
+
+ return status;
+}
+
+/****************************************************************************
+ Reply to a unlink
+****************************************************************************/
+
+void reply_unlink(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ char *name = NULL;
+ uint32 dirtype;
+ NTSTATUS status;
+ bool path_contains_wcard = False;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ START_PROFILE(SMBunlink);
+
+ if (req->wct < 1) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBunlink);
+ return;
+ }
+
+ dirtype = SVAL(req->inbuf,smb_vwv0);
+
+ srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &name,
+ smb_buf(req->inbuf) + 1, 0,
+ STR_TERMINATE, &status, &path_contains_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBunlink);
+ return;
+ }
+
+ status = resolve_dfspath_wcard(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ name,
+ &name,
+ &path_contains_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ END_PROFILE(SMBunlink);
+ return;
+ }
+ reply_nterror(req, status);
+ END_PROFILE(SMBunlink);
+ return;
+ }
+
+ DEBUG(3,("reply_unlink : %s\n",name));
+
+ status = unlink_internals(conn, req, dirtype, name,
+ path_contains_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (open_was_deferred(req->mid)) {
+ /* We have re-scheduled this call. */
+ END_PROFILE(SMBunlink);
+ return;
+ }
+ reply_nterror(req, status);
+ END_PROFILE(SMBunlink);
+ return;
+ }
+
+ reply_outbuf(req, 0, 0);
+ END_PROFILE(SMBunlink);
+
+ return;
+}
+
+/****************************************************************************
+ Fail for readbraw.
+****************************************************************************/
+
+static void fail_readraw(void)
+{
+ const char *errstr = talloc_asprintf(talloc_tos(),
+ "FAIL ! reply_readbraw: socket write fail (%s)",
+ strerror(errno));
+ if (!errstr) {
+ errstr = "";
+ }
+ exit_server_cleanly(errstr);
+}
+
+/****************************************************************************
+ Fake (read/write) sendfile. Returns -1 on read or write fail.
+****************************************************************************/
+
+static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos,
+ size_t nread)
+{
+ size_t bufsize;
+ size_t tosend = nread;
+ char *buf;
+
+ if (nread == 0) {
+ return 0;
+ }
+
+ bufsize = MIN(nread, 65536);
+
+ if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
+ return -1;
+ }
+
+ while (tosend > 0) {
+ ssize_t ret;
+ size_t cur_read;
+
+ if (tosend > bufsize) {
+ cur_read = bufsize;
+ } else {
+ cur_read = tosend;
+ }
+ ret = read_file(fsp,buf,startpos,cur_read);
+ if (ret == -1) {
+ SAFE_FREE(buf);
+ return -1;
+ }
+
+ /* If we had a short read, fill with zeros. */
+ if (ret < cur_read) {
+ memset(buf, '\0', cur_read - ret);
+ }
+
+ if (write_data(smbd_server_fd(),buf,cur_read) != cur_read) {
+ SAFE_FREE(buf);
+ return -1;
+ }
+ tosend -= cur_read;
+ startpos += cur_read;
+ }
+
+ SAFE_FREE(buf);
+ return (ssize_t)nread;
+}
+
+/****************************************************************************
+ Return a readbraw error (4 bytes of zero).
+****************************************************************************/
+
+static void reply_readbraw_error(void)
+{
+ char header[4];
+ SIVAL(header,0,0);
+ if (write_data(smbd_server_fd(),header,4) != 4) {
+ fail_readraw();
+ }
+}
+
+/****************************************************************************
+ Use sendfile in readbraw.
+****************************************************************************/
+
+void send_file_readbraw(connection_struct *conn,
+ files_struct *fsp,
+ SMB_OFF_T startpos,
+ size_t nread,
+ ssize_t mincount)
+{
+ char *outbuf = NULL;
+ ssize_t ret=0;
+
+#if defined(WITH_SENDFILE)
+ /*
+ * We can only use sendfile on a non-chained packet
+ * but we can use on a non-oplocked file. tridge proved this
+ * on a train in Germany :-). JRA.
+ * reply_readbraw has already checked the length.
+ */
+
+ if ( (chain_size == 0) && (nread > 0) && (fsp->base_fsp == NULL) &&
+ (fsp->wcp == NULL) && lp_use_sendfile(SNUM(conn)) ) {
+ char header[4];
+ DATA_BLOB header_blob;
+
+ _smb_setlen(header,nread);
+ header_blob = data_blob_const(header, 4);
+
+ if (SMB_VFS_SENDFILE(smbd_server_fd(), fsp,
+ &header_blob, startpos, nread) == -1) {
+ /* Returning ENOSYS means no data at all was sent.
+ * Do this as a normal read. */
+ if (errno == ENOSYS) {
+ goto normal_readbraw;
+ }
+
+ /*
+ * Special hack for broken Linux with no working sendfile. If we
+ * return EINTR we sent the header but not the rest of the data.
+ * Fake this up by doing read/write calls.
+ */
+ if (errno == EINTR) {
+ /* Ensure we don't do this again. */
+ set_use_sendfile(SNUM(conn), False);
+ DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
+
+ if (fake_sendfile(fsp, startpos, nread) == -1) {
+ DEBUG(0,("send_file_readbraw: fake_sendfile failed for file %s (%s).\n",
+ fsp->fsp_name, strerror(errno) ));
+ exit_server_cleanly("send_file_readbraw fake_sendfile failed");
+ }
+ return;
+ }
+
+ DEBUG(0,("send_file_readbraw: sendfile failed for file %s (%s). Terminating\n",
+ fsp->fsp_name, strerror(errno) ));
+ exit_server_cleanly("send_file_readbraw sendfile failed");
+ }
+
+ return;
+ }
+#endif
+
+normal_readbraw:
+
+ outbuf = TALLOC_ARRAY(NULL, char, nread+4);
+ if (!outbuf) {
+ DEBUG(0,("send_file_readbraw: TALLOC_ARRAY failed for size %u.\n",
+ (unsigned)(nread+4)));
+ reply_readbraw_error();
+ return;
+ }
+
+ if (nread > 0) {
+ ret = read_file(fsp,outbuf+4,startpos,nread);
+#if 0 /* mincount appears to be ignored in a W2K server. JRA. */
+ if (ret < mincount)
+ ret = 0;
+#else
+ if (ret < nread)
+ ret = 0;
+#endif
+ }
+
+ _smb_setlen(outbuf,ret);
+ if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret)
+ fail_readraw();
+
+ TALLOC_FREE(outbuf);
+}
+
+/****************************************************************************
+ Reply to a readbraw (core+ protocol).
+****************************************************************************/
+
+void reply_readbraw(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ ssize_t maxcount,mincount;
+ size_t nread = 0;
+ SMB_OFF_T startpos;
+ files_struct *fsp;
+ SMB_STRUCT_STAT st;
+ SMB_OFF_T size = 0;
+
+ START_PROFILE(SMBreadbraw);
+
+ if (srv_is_signing_active() || is_encrypted_packet(req->inbuf)) {
+ exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
+ "raw reads/writes are disallowed.");
+ }
+
+ if (req->wct < 8) {
+ reply_readbraw_error();
+ END_PROFILE(SMBreadbraw);
+ return;
+ }
+
+ /*
+ * 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.
+ */
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
+
+ /*
+ * We have to do a check_fsp by hand here, as
+ * we must always return 4 zero bytes on error,
+ * not a NTSTATUS.
+ */
+
+ if (!fsp || !conn || conn != fsp->conn ||
+ req->vuid != fsp->vuid ||
+ fsp->is_directory || fsp->fh->fd == -1) {
+ /*
+ * fsp could be NULL here so use the value from the packet. JRA.
+ */
+ DEBUG(3,("reply_readbraw: fnum %d not valid "
+ "- cache prime?\n",
+ (int)SVAL(req->inbuf,smb_vwv0)));
+ reply_readbraw_error();
+ END_PROFILE(SMBreadbraw);
+ return;
+ }
+
+ /* Do a "by hand" version of CHECK_READ. */
+ if (!(fsp->can_read ||
+ ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
+ (fsp->access_mask & FILE_EXECUTE)))) {
+ DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
+ (int)SVAL(req->inbuf,smb_vwv0)));
+ reply_readbraw_error();
+ END_PROFILE(SMBreadbraw);
+ return;
+ }
+
+ flush_write_cache(fsp, READRAW_FLUSH);
+
+ startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv1);
+ if(req->wct == 10) {
+ /*
+ * This is a large offset (64 bit) read.
+ */
+#ifdef LARGE_SMB_OFF_T
+
+ startpos |= (((SMB_OFF_T)IVAL(req->inbuf,smb_vwv8)) << 32);
+
+#else /* !LARGE_SMB_OFF_T */
+
+ /*
+ * Ensure we haven't been sent a >32 bit offset.
+ */
+
+ if(IVAL(req->inbuf,smb_vwv8) != 0) {
+ DEBUG(0,("reply_readbraw: large offset "
+ "(%x << 32) used and we don't support "
+ "64 bit offsets.\n",
+ (unsigned int)IVAL(req->inbuf,smb_vwv8) ));
+ reply_readbraw_error();
+ END_PROFILE(SMBreadbraw);
+ return;
+ }
+
+#endif /* LARGE_SMB_OFF_T */
+
+ if(startpos < 0) {
+ DEBUG(0,("reply_readbraw: negative 64 bit "
+ "readraw offset (%.0f) !\n",
+ (double)startpos ));
+ reply_readbraw_error();
+ END_PROFILE(SMBreadbraw);
+ return;
+ }
+ }
+
+ maxcount = (SVAL(req->inbuf,smb_vwv3) & 0xFFFF);
+ mincount = (SVAL(req->inbuf,smb_vwv4) & 0xFFFF);
+
+ /* ensure we don't overrun the packet size */
+ maxcount = MIN(65535,maxcount);
+
+ if (is_locked(fsp,(uint32)req->smbpid,
+ (SMB_BIG_UINT)maxcount,
+ (SMB_BIG_UINT)startpos,
+ READ_LOCK)) {
+ reply_readbraw_error();
+ END_PROFILE(SMBreadbraw);
+ return;
+ }
+
+ if (SMB_VFS_FSTAT(fsp, &st) == 0) {
+ size = st.st_size;
+ }
+
+ if (startpos >= size) {
+ nread = 0;
+ } else {
+ nread = MIN(maxcount,(size - startpos));
+ }
+
+#if 0 /* mincount appears to be ignored in a W2K server. JRA. */
+ if (nread < mincount)
+ nread = 0;
+#endif
+
+ DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
+ "min=%lu nread=%lu\n",
+ fsp->fnum, (double)startpos,
+ (unsigned long)maxcount,
+ (unsigned long)mincount,
+ (unsigned long)nread ) );
+
+ send_file_readbraw(conn, fsp, startpos, nread, mincount);
+
+ DEBUG(5,("reply_readbraw finished\n"));
+ END_PROFILE(SMBreadbraw);
+}
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_LOCKING
+
+/****************************************************************************
+ Reply to a lockread (core+ protocol).
+****************************************************************************/
+
+void reply_lockread(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ ssize_t nread = -1;
+ char *data;
+ SMB_OFF_T startpos;
+ size_t numtoread;
+ NTSTATUS status;
+ files_struct *fsp;
+ struct byte_range_lock *br_lck = NULL;
+ char *p = NULL;
+
+ START_PROFILE(SMBlockread);
+
+ if (req->wct < 5) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBlockread);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
+
+ if (!check_fsp(conn, req, fsp)) {
+ END_PROFILE(SMBlockread);
+ return;
+ }
+
+ if (!CHECK_READ(fsp,req->inbuf)) {
+ reply_doserror(req, ERRDOS, ERRbadaccess);
+ END_PROFILE(SMBlockread);
+ return;
+ }
+
+ release_level_2_oplocks_on_change(fsp);
+
+ numtoread = SVAL(req->inbuf,smb_vwv1);
+ startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
+
+ numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
+
+ reply_outbuf(req, 5, numtoread + 3);
+
+ data = smb_buf(req->outbuf) + 3;
+
+ /*
+ * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
+ * protocol request that predates the read/write lock concept.
+ * Thus instead of asking for a read lock here we need to ask
+ * for a write lock. JRA.
+ * Note that the requested lock size is unaffected by max_recv.
+ */
+
+ br_lck = do_lock(smbd_messaging_context(),
+ fsp,
+ req->smbpid,
+ (SMB_BIG_UINT)numtoread,
+ (SMB_BIG_UINT)startpos,
+ WRITE_LOCK,
+ WINDOWS_LOCK,
+ False, /* Non-blocking lock. */
+ &status,
+ NULL);
+ TALLOC_FREE(br_lck);
+
+ if (NT_STATUS_V(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBlockread);
+ return;
+ }
+
+ /*
+ * However the requested READ size IS affected by max_recv. Insanity.... JRA.
+ */
+
+ if (numtoread > max_recv) {
+ DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
+Returning short read of maximum allowed for compatibility with Windows 2000.\n",
+ (unsigned int)numtoread, (unsigned int)max_recv ));
+ numtoread = MIN(numtoread,max_recv);
+ }
+ nread = read_file(fsp,data,startpos,numtoread);
+
+ if (nread < 0) {
+ reply_unixerror(req, ERRDOS, ERRnoaccess);
+ END_PROFILE(SMBlockread);
+ return;
+ }
+
+ srv_set_message((char *)req->outbuf, 5, nread+3, False);
+
+ SSVAL(req->outbuf,smb_vwv0,nread);
+ SSVAL(req->outbuf,smb_vwv5,nread+3);
+ p = smb_buf(req->outbuf);
+ SCVAL(p,0,0); /* pad byte. */
+ SSVAL(p,1,nread);
+
+ DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
+ fsp->fnum, (int)numtoread, (int)nread));
+
+ END_PROFILE(SMBlockread);
+ return;
+}
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_ALL
+
+/****************************************************************************
+ Reply to a read.
+****************************************************************************/
+
+void reply_read(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ size_t numtoread;
+ ssize_t nread = 0;
+ char *data;
+ SMB_OFF_T startpos;
+ int outsize = 0;
+ files_struct *fsp;
+
+ START_PROFILE(SMBread);
+
+ if (req->wct < 3) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBread);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
+
+ if (!check_fsp(conn, req, fsp)) {
+ END_PROFILE(SMBread);
+ return;
+ }
+
+ if (!CHECK_READ(fsp,req->inbuf)) {
+ reply_doserror(req, ERRDOS, ERRbadaccess);
+ END_PROFILE(SMBread);
+ return;
+ }
+
+ numtoread = SVAL(req->inbuf,smb_vwv1);
+ startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
+
+ numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
+
+ /*
+ * The requested read size cannot be greater than max_recv. JRA.
+ */
+ if (numtoread > max_recv) {
+ DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
+Returning short read of maximum allowed for compatibility with Windows 2000.\n",
+ (unsigned int)numtoread, (unsigned int)max_recv ));
+ numtoread = MIN(numtoread,max_recv);
+ }
+
+ reply_outbuf(req, 5, numtoread+3);
+
+ data = smb_buf(req->outbuf) + 3;
+
+ if (is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)numtoread,
+ (SMB_BIG_UINT)startpos, READ_LOCK)) {
+ reply_doserror(req, ERRDOS,ERRlock);
+ END_PROFILE(SMBread);
+ return;
+ }
+
+ if (numtoread > 0)
+ nread = read_file(fsp,data,startpos,numtoread);
+
+ if (nread < 0) {
+ reply_unixerror(req, ERRDOS,ERRnoaccess);
+ END_PROFILE(SMBread);
+ return;
+ }
+
+ srv_set_message((char *)req->outbuf, 5, nread+3, False);
+
+ SSVAL(req->outbuf,smb_vwv0,nread);
+ SSVAL(req->outbuf,smb_vwv5,nread+3);
+ SCVAL(smb_buf(req->outbuf),0,1);
+ SSVAL(smb_buf(req->outbuf),1,nread);
+
+ DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
+ fsp->fnum, (int)numtoread, (int)nread ) );
+
+ END_PROFILE(SMBread);
+ return;
+}
+
+/****************************************************************************
+ Setup readX header.
+****************************************************************************/
+
+static int setup_readX_header(char *outbuf, size_t smb_maxcnt)
+{
+ int outsize;
+ char *data;
+
+ outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
+ data = smb_buf(outbuf);
+
+ memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
+
+ SCVAL(outbuf,smb_vwv0,0xFF);
+ SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
+ SSVAL(outbuf,smb_vwv5,smb_maxcnt);
+ SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
+ SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
+ SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
+ /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
+ _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
+ return outsize;
+}
+
+/****************************************************************************
+ Reply to a read and X - possibly using sendfile.
+****************************************************************************/
+
+static void send_file_readX(connection_struct *conn, struct smb_request *req,
+ files_struct *fsp, SMB_OFF_T startpos,
+ size_t smb_maxcnt)
+{
+ SMB_STRUCT_STAT sbuf;
+ ssize_t nread = -1;
+
+ if(SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+ reply_unixerror(req, ERRDOS, ERRnoaccess);
+ return;
+ }
+
+ if (startpos > sbuf.st_size) {
+ smb_maxcnt = 0;
+ } else if (smb_maxcnt > (sbuf.st_size - startpos)) {
+ smb_maxcnt = (sbuf.st_size - startpos);
+ }
+
+ if (smb_maxcnt == 0) {
+ goto normal_read;
+ }
+
+#if defined(WITH_SENDFILE)
+ /*
+ * We can only use sendfile on a non-chained packet
+ * but we can use on a non-oplocked file. tridge proved this
+ * on a train in Germany :-). JRA.
+ */
+
+ if ((chain_size == 0) && (CVAL(req->inbuf,smb_vwv0) == 0xFF) &&
+ !is_encrypted_packet(req->inbuf) && (fsp->base_fsp == NULL) &&
+ lp_use_sendfile(SNUM(conn)) && (fsp->wcp == NULL) ) {
+ uint8 headerbuf[smb_size + 12 * 2];
+ DATA_BLOB header;
+
+ /*
+ * Set up the packet header before send. We
+ * assume here the sendfile will work (get the
+ * correct amount of data).
+ */
+
+ header = data_blob_const(headerbuf, sizeof(headerbuf));
+
+ construct_reply_common((char *)req->inbuf, (char *)headerbuf);
+ setup_readX_header((char *)headerbuf, smb_maxcnt);
+
+ if ((nread = SMB_VFS_SENDFILE(smbd_server_fd(), fsp, &header, startpos, smb_maxcnt)) == -1) {
+ /* Returning ENOSYS or EINVAL means no data at all was sent.
+ Do this as a normal read. */
+ if (errno == ENOSYS || errno == EINVAL) {
+ goto normal_read;
+ }
+
+ /*
+ * Special hack for broken Linux with no working sendfile. If we
+ * return EINTR we sent the header but not the rest of the data.
+ * Fake this up by doing read/write calls.
+ */
+
+ if (errno == EINTR) {
+ /* Ensure we don't do this again. */
+ set_use_sendfile(SNUM(conn), False);
+ DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
+ nread = fake_sendfile(fsp, startpos,
+ smb_maxcnt);
+ if (nread == -1) {
+ DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
+ fsp->fsp_name, strerror(errno) ));
+ exit_server_cleanly("send_file_readX: fake_sendfile failed");
+ }
+ DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
+ fsp->fnum, (int)smb_maxcnt, (int)nread ) );
+ /* No outbuf here means successful sendfile. */
+ TALLOC_FREE(req->outbuf);
+ return;
+ }
+
+ DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n",
+ fsp->fsp_name, strerror(errno) ));
+ exit_server_cleanly("send_file_readX sendfile failed");
+ }
+
+ DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
+ fsp->fnum, (int)smb_maxcnt, (int)nread ) );
+ /* No outbuf here means successful sendfile. */
+ TALLOC_FREE(req->outbuf);
+ return;
+ }
+#endif
+
+normal_read:
+
+ if ((smb_maxcnt & 0xFF0000) > 0x10000) {
+ uint8 headerbuf[smb_size + 2*12];
+
+ construct_reply_common((char *)req->inbuf, (char *)headerbuf);
+ setup_readX_header((char *)headerbuf, smb_maxcnt);
+
+ /* Send out the header. */
+ if (write_data(smbd_server_fd(), (char *)headerbuf,
+ sizeof(headerbuf)) != sizeof(headerbuf)) {
+ DEBUG(0,("send_file_readX: write_data failed for file %s (%s). Terminating\n",
+ fsp->fsp_name, strerror(errno) ));
+ exit_server_cleanly("send_file_readX sendfile failed");
+ }
+ nread = fake_sendfile(fsp, startpos, smb_maxcnt);
+ if (nread == -1) {
+ DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
+ fsp->fsp_name, strerror(errno) ));
+ exit_server_cleanly("send_file_readX: fake_sendfile failed");
+ }
+ TALLOC_FREE(req->outbuf);
+ return;
+ }
+
+ reply_outbuf(req, 12, smb_maxcnt);
+
+ nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
+ if (nread < 0) {
+ reply_unixerror(req, ERRDOS, ERRnoaccess);
+ return;
+ }
+
+ setup_readX_header((char *)req->outbuf, nread);
+
+ DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
+ fsp->fnum, (int)smb_maxcnt, (int)nread ) );
+
+ chain_reply(req);
+}
+
+/****************************************************************************
+ Reply to a read and X.
+****************************************************************************/
+
+void reply_read_and_X(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ files_struct *fsp;
+ SMB_OFF_T startpos;
+ size_t smb_maxcnt;
+ bool big_readX = False;
+#if 0
+ size_t smb_mincnt = SVAL(req->inbuf,smb_vwv6);
+#endif
+
+ START_PROFILE(SMBreadX);
+
+ if ((req->wct != 10) && (req->wct != 12)) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv2));
+ startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv3);
+ smb_maxcnt = SVAL(req->inbuf,smb_vwv5);
+
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn)) {
+ reply_pipe_read_and_X(req);
+ END_PROFILE(SMBreadX);
+ return;
+ }
+
+ if (!check_fsp(conn, req, fsp)) {
+ END_PROFILE(SMBreadX);
+ return;
+ }
+
+ if (!CHECK_READ(fsp,req->inbuf)) {
+ reply_doserror(req, ERRDOS,ERRbadaccess);
+ END_PROFILE(SMBreadX);
+ return;
+ }
+
+ if (global_client_caps & CAP_LARGE_READX) {
+ size_t upper_size = SVAL(req->inbuf,smb_vwv7);
+ smb_maxcnt |= (upper_size<<16);
+ if (upper_size > 1) {
+ /* Can't do this on a chained packet. */
+ if ((CVAL(req->inbuf,smb_vwv0) != 0xFF)) {
+ reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
+ END_PROFILE(SMBreadX);
+ return;
+ }
+ /* We currently don't do this on signed or sealed data. */
+ if (srv_is_signing_active() || is_encrypted_packet(req->inbuf)) {
+ reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
+ END_PROFILE(SMBreadX);
+ return;
+ }
+ /* Is there room in the reply for this data ? */
+ if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
+ reply_nterror(req,
+ NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBreadX);
+ return;
+ }
+ big_readX = True;
+ }
+ }
+
+ if (req->wct == 12) {
+#ifdef LARGE_SMB_OFF_T
+ /*
+ * This is a large offset (64 bit) read.
+ */
+ startpos |= (((SMB_OFF_T)IVAL(req->inbuf,smb_vwv10)) << 32);
+
+#else /* !LARGE_SMB_OFF_T */
+
+ /*
+ * Ensure we haven't been sent a >32 bit offset.
+ */
+
+ if(IVAL(req->inbuf,smb_vwv10) != 0) {
+ DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
+ "used and we don't support 64 bit offsets.\n",
+ (unsigned int)IVAL(req->inbuf,smb_vwv10) ));
+ END_PROFILE(SMBreadX);
+ reply_doserror(req, ERRDOS, ERRbadaccess);
+ return;
+ }
+
+#endif /* LARGE_SMB_OFF_T */
+
+ }
+
+ if (is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)smb_maxcnt,
+ (SMB_BIG_UINT)startpos, READ_LOCK)) {
+ END_PROFILE(SMBreadX);
+ reply_doserror(req, ERRDOS, ERRlock);
+ return;
+ }
+
+ if (!big_readX &&
+ schedule_aio_read_and_X(conn, req, fsp, startpos, smb_maxcnt)) {
+ END_PROFILE(SMBreadX);
+ return;
+ }
+
+ send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
+
+ END_PROFILE(SMBreadX);
+ return;
+}
+
+/****************************************************************************
+ Error replies to writebraw must have smb_wct == 1. Fix this up.
+****************************************************************************/
+
+void error_to_writebrawerr(struct smb_request *req)
+{
+ uint8 *old_outbuf = req->outbuf;
+
+ reply_outbuf(req, 1, 0);
+
+ memcpy(req->outbuf, old_outbuf, smb_size);
+ TALLOC_FREE(old_outbuf);
+}
+
+/****************************************************************************
+ Reply to a writebraw (core+ or LANMAN1.0 protocol).
+****************************************************************************/
+
+void reply_writebraw(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ char *buf = NULL;
+ ssize_t nwritten=0;
+ ssize_t total_written=0;
+ size_t numtowrite=0;
+ size_t tcount;
+ SMB_OFF_T startpos;
+ char *data=NULL;
+ bool write_through;
+ files_struct *fsp;
+ NTSTATUS status;
+
+ START_PROFILE(SMBwritebraw);
+
+ /*
+ * If we ever reply with an error, it must have the SMB command
+ * type of SMBwritec, not SMBwriteBraw, as this tells the client
+ * we're finished.
+ */
+ SCVAL(req->inbuf,smb_com,SMBwritec);
+
+ if (srv_is_signing_active()) {
+ END_PROFILE(SMBwritebraw);
+ exit_server_cleanly("reply_writebraw: SMB signing is active - "
+ "raw reads/writes are disallowed.");
+ }
+
+ if (req->wct < 12) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ error_to_writebrawerr(req);
+ END_PROFILE(SMBwritebraw);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
+ if (!check_fsp(conn, req, fsp)) {
+ error_to_writebrawerr(req);
+ END_PROFILE(SMBwritebraw);
+ return;
+ }
+
+ if (!CHECK_WRITE(fsp)) {
+ reply_doserror(req, ERRDOS, ERRbadaccess);
+ error_to_writebrawerr(req);
+ END_PROFILE(SMBwritebraw);
+ return;
+ }
+
+ tcount = IVAL(req->inbuf,smb_vwv1);
+ startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv3);
+ write_through = BITSETW(req->inbuf+smb_vwv7,0);
+
+ /* We have to deal with slightly different formats depending
+ on whether we are using the core+ or lanman1.0 protocol */
+
+ if(Protocol <= PROTOCOL_COREPLUS) {
+ numtowrite = SVAL(smb_buf(req->inbuf),-2);
+ data = smb_buf(req->inbuf);
+ } else {
+ numtowrite = SVAL(req->inbuf,smb_vwv10);
+ data = smb_base(req->inbuf) + SVAL(req->inbuf, smb_vwv11);
+ }
+
+ /* Ensure we don't write bytes past the end of this packet. */
+ if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ error_to_writebrawerr(req);
+ END_PROFILE(SMBwritebraw);
+ return;
+ }
+
+ if (is_locked(fsp,(uint32)req->smbpid,(SMB_BIG_UINT)tcount,
+ (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+ reply_doserror(req, ERRDOS, ERRlock);
+ error_to_writebrawerr(req);
+ END_PROFILE(SMBwritebraw);
+ return;
+ }
+
+ if (numtowrite>0) {
+ nwritten = write_file(req,fsp,data,startpos,numtowrite);
+ }
+
+ DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
+ "wrote=%d sync=%d\n",
+ fsp->fnum, (double)startpos, (int)numtowrite,
+ (int)nwritten, (int)write_through));
+
+ if (nwritten < (ssize_t)numtowrite) {
+ reply_unixerror(req, ERRHRD, ERRdiskfull);
+ error_to_writebrawerr(req);
+ END_PROFILE(SMBwritebraw);
+ return;
+ }
+
+ total_written = nwritten;
+
+ /* Allocate a buffer of 64k + length. */
+ buf = TALLOC_ARRAY(NULL, char, 65540);
+ if (!buf) {
+ reply_doserror(req, ERRDOS, ERRnomem);
+ error_to_writebrawerr(req);
+ END_PROFILE(SMBwritebraw);
+ return;
+ }
+
+ /* Return a SMBwritebraw message to the redirector to tell
+ * it to send more bytes */
+
+ memcpy(buf, req->inbuf, smb_size);
+ srv_set_message(buf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
+ SCVAL(buf,smb_com,SMBwritebraw);
+ SSVALS(buf,smb_vwv0,0xFFFF);
+ show_msg(buf);
+ if (!srv_send_smb(smbd_server_fd(),
+ buf,
+ IS_CONN_ENCRYPTED(conn))) {
+ exit_server_cleanly("reply_writebraw: srv_send_smb "
+ "failed.");
+ }
+
+ /* Now read the raw data into the buffer and write it */
+ status = read_smb_length(smbd_server_fd(), buf, SMB_SECONDARY_WAIT,
+ &numtowrite);
+ if (!NT_STATUS_IS_OK(status)) {
+ exit_server_cleanly("secondary writebraw failed");
+ }
+
+ /* Set up outbuf to return the correct size */
+ reply_outbuf(req, 1, 0);
+
+ if (numtowrite != 0) {
+
+ if (numtowrite > 0xFFFF) {
+ DEBUG(0,("reply_writebraw: Oversize secondary write "
+ "raw requested (%u). Terminating\n",
+ (unsigned int)numtowrite ));
+ exit_server_cleanly("secondary writebraw failed");
+ }
+
+ if (tcount > nwritten+numtowrite) {
+ DEBUG(3,("reply_writebraw: Client overestimated the "
+ "write %d %d %d\n",
+ (int)tcount,(int)nwritten,(int)numtowrite));
+ }
+
+ status = read_data(smbd_server_fd(), buf+4, numtowrite);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("reply_writebraw: Oversize secondary write "
+ "raw read failed (%s). Terminating\n",
+ nt_errstr(status)));
+ exit_server_cleanly("secondary writebraw failed");
+ }
+
+ nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
+ if (nwritten == -1) {
+ TALLOC_FREE(buf);
+ reply_unixerror(req, ERRHRD, ERRdiskfull);
+ error_to_writebrawerr(req);
+ END_PROFILE(SMBwritebraw);
+ return;
+ }
+
+ if (nwritten < (ssize_t)numtowrite) {
+ SCVAL(req->outbuf,smb_rcls,ERRHRD);
+ SSVAL(req->outbuf,smb_err,ERRdiskfull);
+ }
+
+ if (nwritten > 0) {
+ total_written += nwritten;
+ }
+ }
+
+ TALLOC_FREE(buf);
+ SSVAL(req->outbuf,smb_vwv0,total_written);
+
+ status = sync_file(conn, fsp, write_through);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
+ fsp->fsp_name, nt_errstr(status) ));
+ reply_nterror(req, status);
+ error_to_writebrawerr(req);
+ END_PROFILE(SMBwritebraw);
+ return;
+ }
+
+ DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
+ "wrote=%d\n",
+ fsp->fnum, (double)startpos, (int)numtowrite,
+ (int)total_written));
+
+ /* We won't return a status if write through is not selected - this
+ * follows what WfWg does */
+ END_PROFILE(SMBwritebraw);
+
+ if (!write_through && total_written==tcount) {
+
+#if RABBIT_PELLET_FIX
+ /*
+ * Fix for "rabbit pellet" mode, trigger an early TCP ack by
+ * sending a SMBkeepalive. Thanks to DaveCB at Sun for this.
+ * JRA.
+ */
+ if (!send_keepalive(smbd_server_fd())) {
+ exit_server_cleanly("reply_writebraw: send of "
+ "keepalive failed");
+ }
+#endif
+ TALLOC_FREE(req->outbuf);
+ }
+ return;
+}
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_LOCKING
+
+/****************************************************************************
+ Reply to a writeunlock (core+).
+****************************************************************************/
+
+void reply_writeunlock(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ ssize_t nwritten = -1;
+ size_t numtowrite;
+ SMB_OFF_T startpos;
+ char *data;
+ NTSTATUS status = NT_STATUS_OK;
+ files_struct *fsp;
+
+ START_PROFILE(SMBwriteunlock);
+
+ if (req->wct < 5) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBwriteunlock);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
+
+ if (!check_fsp(conn, req, fsp)) {
+ END_PROFILE(SMBwriteunlock);
+ return;
+ }
+
+ if (!CHECK_WRITE(fsp)) {
+ reply_doserror(req, ERRDOS,ERRbadaccess);
+ END_PROFILE(SMBwriteunlock);
+ return;
+ }
+
+ numtowrite = SVAL(req->inbuf,smb_vwv1);
+ startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
+ data = smb_buf(req->inbuf) + 3;
+
+ if (numtowrite
+ && is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)numtowrite,
+ (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+ reply_doserror(req, ERRDOS, ERRlock);
+ END_PROFILE(SMBwriteunlock);
+ return;
+ }
+
+ /* The special X/Open SMB protocol handling of
+ zero length writes is *NOT* done for
+ this call */
+ if(numtowrite == 0) {
+ nwritten = 0;
+ } else {
+ nwritten = write_file(req,fsp,data,startpos,numtowrite);
+ }
+
+ status = sync_file(conn, fsp, False /* write through */);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
+ fsp->fsp_name, nt_errstr(status) ));
+ reply_nterror(req, status);
+ END_PROFILE(SMBwriteunlock);
+ return;
+ }
+
+ if(((nwritten < numtowrite) && (numtowrite != 0))||(nwritten < 0)) {
+ reply_unixerror(req, ERRHRD, ERRdiskfull);
+ END_PROFILE(SMBwriteunlock);
+ return;
+ }
+
+ if (numtowrite) {
+ status = do_unlock(smbd_messaging_context(),
+ fsp,
+ req->smbpid,
+ (SMB_BIG_UINT)numtowrite,
+ (SMB_BIG_UINT)startpos,
+ WINDOWS_LOCK);
+
+ if (NT_STATUS_V(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBwriteunlock);
+ return;
+ }
+ }
+
+ reply_outbuf(req, 1, 0);
+
+ SSVAL(req->outbuf,smb_vwv0,nwritten);
+
+ DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, (int)numtowrite, (int)nwritten));
+
+ END_PROFILE(SMBwriteunlock);
+ return;
+}
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_ALL
+
+/****************************************************************************
+ Reply to a write.
+****************************************************************************/
+
+void reply_write(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ SMB_OFF_T startpos;
+ char *data;
+ files_struct *fsp;
+ NTSTATUS status;
+
+ START_PROFILE(SMBwrite);
+
+ if (req->wct < 5) {
+ END_PROFILE(SMBwrite);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn)) {
+ reply_pipe_write(req);
+ END_PROFILE(SMBwrite);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
+
+ if (!check_fsp(conn, req, fsp)) {
+ END_PROFILE(SMBwrite);
+ return;
+ }
+
+ if (!CHECK_WRITE(fsp)) {
+ reply_doserror(req, ERRDOS, ERRbadaccess);
+ END_PROFILE(SMBwrite);
+ return;
+ }
+
+ numtowrite = SVAL(req->inbuf,smb_vwv1);
+ startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
+ data = smb_buf(req->inbuf) + 3;
+
+ if (is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)numtowrite,
+ (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+ reply_doserror(req, ERRDOS, ERRlock);
+ END_PROFILE(SMBwrite);
+ return;
+ }
+
+ /*
+ * X/Open SMB protocol says that if smb_vwv1 is
+ * zero then the file size should be extended or
+ * truncated to the size given in smb_vwv[2-3].
+ */
+
+ if(numtowrite == 0) {
+ /*
+ * This is actually an allocate call, and set EOF. JRA.
+ */
+ nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
+ if (nwritten < 0) {
+ reply_nterror(req, NT_STATUS_DISK_FULL);
+ END_PROFILE(SMBwrite);
+ return;
+ }
+ nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
+ if (nwritten < 0) {
+ reply_nterror(req, NT_STATUS_DISK_FULL);
+ END_PROFILE(SMBwrite);
+ return;
+ }
+ trigger_write_time_update_immediate(fsp);
+ } else {
+ nwritten = write_file(req,fsp,data,startpos,numtowrite);
+ }
+
+ status = sync_file(conn, fsp, False);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("reply_write: sync_file for %s returned %s\n",
+ fsp->fsp_name, nt_errstr(status) ));
+ reply_nterror(req, status);
+ END_PROFILE(SMBwrite);
+ return;
+ }
+
+ if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
+ reply_unixerror(req, ERRHRD, ERRdiskfull);
+ END_PROFILE(SMBwrite);
+ return;
+ }
+
+ reply_outbuf(req, 1, 0);
+
+ SSVAL(req->outbuf,smb_vwv0,nwritten);
+
+ if (nwritten < (ssize_t)numtowrite) {
+ SCVAL(req->outbuf,smb_rcls,ERRHRD);
+ SSVAL(req->outbuf,smb_err,ERRdiskfull);
+ }
+
+ DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
+
+ END_PROFILE(SMBwrite);
+ return;
+}
+
+/****************************************************************************
+ Ensure a buffer is a valid writeX for recvfile purposes.
+****************************************************************************/
+
+#define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
+ (2*14) + /* word count (including bcc) */ \
+ 1 /* pad byte */)
+
+bool is_valid_writeX_buffer(const uint8_t *inbuf)
+{
+ size_t numtowrite;
+ connection_struct *conn = NULL;
+ unsigned int doff = 0;
+ size_t len = smb_len_large(inbuf);
+
+ if (is_encrypted_packet(inbuf)) {
+ /* Can't do this on encrypted
+ * connections. */
+ return false;
+ }
+
+ if (CVAL(inbuf,smb_com) != SMBwriteX) {
+ return false;
+ }
+
+ if (CVAL(inbuf,smb_vwv0) != 0xFF ||
+ CVAL(inbuf,smb_wct) != 14) {
+ DEBUG(10,("is_valid_writeX_buffer: chained or "
+ "invalid word length.\n"));
+ return false;
+ }
+
+ conn = conn_find(SVAL(inbuf, smb_tid));
+ if (conn == NULL) {
+ DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
+ return false;
+ }
+ if (IS_IPC(conn)) {
+ DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
+ return false;
+ }
+ doff = SVAL(inbuf,smb_vwv11);
+
+ numtowrite = SVAL(inbuf,smb_vwv10);
+
+ if (len > doff && len - doff > 0xFFFF) {
+ numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
+ }
+
+ if (numtowrite == 0) {
+ DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
+ return false;
+ }
+
+ /* Ensure the sizes match up. */
+ if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
+ /* no pad byte...old smbclient :-( */
+ DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
+ (unsigned int)doff,
+ (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
+ return false;
+ }
+
+ if (len - doff != numtowrite) {
+ DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
+ "len = %u, doff = %u, numtowrite = %u\n",
+ (unsigned int)len,
+ (unsigned int)doff,
+ (unsigned int)numtowrite ));
+ return false;
+ }
+
+ DEBUG(10,("is_valid_writeX_buffer: true "
+ "len = %u, doff = %u, numtowrite = %u\n",
+ (unsigned int)len,
+ (unsigned int)doff,
+ (unsigned int)numtowrite ));
+
+ return true;
+}
+
+/****************************************************************************
+ Reply to a write and X.
+****************************************************************************/
+
+void reply_write_and_X(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ files_struct *fsp;
+ SMB_OFF_T startpos;
+ size_t numtowrite;
+ bool write_through;
+ ssize_t nwritten;
+ unsigned int smb_doff;
+ unsigned int smblen;
+ char *data;
+ NTSTATUS status;
+
+ START_PROFILE(SMBwriteX);
+
+ if ((req->wct != 12) && (req->wct != 14)) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBwriteX);
+ return;
+ }
+
+ numtowrite = SVAL(req->inbuf,smb_vwv10);
+ smb_doff = SVAL(req->inbuf,smb_vwv11);
+ smblen = smb_len(req->inbuf);
+
+ if (req->unread_bytes > 0xFFFF ||
+ (smblen > smb_doff &&
+ smblen - smb_doff > 0xFFFF)) {
+ numtowrite |= (((size_t)SVAL(req->inbuf,smb_vwv9))<<16);
+ }
+
+ if (req->unread_bytes) {
+ /* Can't do a recvfile write on IPC$ */
+ if (IS_IPC(conn)) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBwriteX);
+ return;
+ }
+ if (numtowrite != req->unread_bytes) {
+ reply_doserror(req, ERRDOS, ERRbadmem);
+ END_PROFILE(SMBwriteX);
+ return;
+ }
+ } else {
+ if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
+ smb_doff + numtowrite > smblen) {
+ reply_doserror(req, ERRDOS, ERRbadmem);
+ END_PROFILE(SMBwriteX);
+ return;
+ }
+ }
+
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn)) {
+ if (req->unread_bytes) {
+ reply_doserror(req, ERRDOS, ERRbadmem);
+ END_PROFILE(SMBwriteX);
+ return;
+ }
+ reply_pipe_write_and_X(req);
+ END_PROFILE(SMBwriteX);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv2));
+ startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv3);
+ write_through = BITSETW(req->inbuf+smb_vwv7,0);
+
+ if (!check_fsp(conn, req, fsp)) {
+ END_PROFILE(SMBwriteX);
+ return;
+ }
+
+ if (!CHECK_WRITE(fsp)) {
+ reply_doserror(req, ERRDOS, ERRbadaccess);
+ END_PROFILE(SMBwriteX);
+ return;
+ }
+
+ data = smb_base(req->inbuf) + smb_doff;
+
+ if(req->wct == 14) {
+#ifdef LARGE_SMB_OFF_T
+ /*
+ * This is a large offset (64 bit) write.
+ */
+ startpos |= (((SMB_OFF_T)IVAL(req->inbuf,smb_vwv12)) << 32);
+
+#else /* !LARGE_SMB_OFF_T */
+
+ /*
+ * Ensure we haven't been sent a >32 bit offset.
+ */
+
+ if(IVAL(req->inbuf,smb_vwv12) != 0) {
+ DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
+ "used and we don't support 64 bit offsets.\n",
+ (unsigned int)IVAL(req->inbuf,smb_vwv12) ));
+ reply_doserror(req, ERRDOS, ERRbadaccess);
+ END_PROFILE(SMBwriteX);
+ return;
+ }
+
+#endif /* LARGE_SMB_OFF_T */
+ }
+
+ if (is_locked(fsp,(uint32)req->smbpid,
+ (SMB_BIG_UINT)numtowrite,
+ (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+ reply_doserror(req, ERRDOS, ERRlock);
+ END_PROFILE(SMBwriteX);
+ return;
+ }
+
+ /* 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(numtowrite == 0) {
+ nwritten = 0;
+ } else {
+
+ if ((req->unread_bytes == 0) &&
+ schedule_aio_write_and_X(conn, req, fsp, data, startpos,
+ numtowrite)) {
+ END_PROFILE(SMBwriteX);
+ return;
+ }
+
+ nwritten = write_file(req,fsp,data,startpos,numtowrite);
+ }
+
+ if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
+ reply_unixerror(req, ERRHRD, ERRdiskfull);
+ END_PROFILE(SMBwriteX);
+ return;
+ }
+
+ reply_outbuf(req, 6, 0);
+ SSVAL(req->outbuf,smb_vwv2,nwritten);
+ SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
+
+ if (nwritten < (ssize_t)numtowrite) {
+ SCVAL(req->outbuf,smb_rcls,ERRHRD);
+ SSVAL(req->outbuf,smb_err,ERRdiskfull);
+ }
+
+ DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, (int)numtowrite, (int)nwritten));
+
+ status = sync_file(conn, fsp, write_through);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
+ fsp->fsp_name, nt_errstr(status) ));
+ reply_nterror(req, status);
+ END_PROFILE(SMBwriteX);
+ return;
+ }
+
+ END_PROFILE(SMBwriteX);
+ chain_reply(req);
+ return;
+}
+
+/****************************************************************************
+ Reply to a lseek.
+****************************************************************************/
+
+void reply_lseek(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ SMB_OFF_T startpos;
+ SMB_OFF_T res= -1;
+ int mode,umode;
+ files_struct *fsp;
+
+ START_PROFILE(SMBlseek);
+
+ if (req->wct < 4) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBlseek);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
+
+ if (!check_fsp(conn, req, fsp)) {
+ return;
+ }
+
+ flush_write_cache(fsp, SEEK_FLUSH);
+
+ mode = SVAL(req->inbuf,smb_vwv1) & 3;
+ /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
+ startpos = (SMB_OFF_T)IVALS(req->inbuf,smb_vwv2);
+
+ switch (mode) {
+ case 0:
+ umode = SEEK_SET;
+ res = startpos;
+ break;
+ case 1:
+ umode = SEEK_CUR;
+ res = fsp->fh->pos + startpos;
+ break;
+ case 2:
+ umode = SEEK_END;
+ break;
+ default:
+ umode = SEEK_SET;
+ res = startpos;
+ break;
+ }
+
+ if (umode == SEEK_END) {
+ if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
+ if(errno == EINVAL) {
+ SMB_OFF_T current_pos = startpos;
+ SMB_STRUCT_STAT sbuf;
+
+ if(SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+ reply_unixerror(req, ERRDOS,
+ ERRnoaccess);
+ END_PROFILE(SMBlseek);
+ return;
+ }
+
+ current_pos += sbuf.st_size;
+ if(current_pos < 0)
+ res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
+ }
+ }
+
+ if(res == -1) {
+ reply_unixerror(req, ERRDOS, ERRnoaccess);
+ END_PROFILE(SMBlseek);
+ return;
+ }
+ }
+
+ fsp->fh->pos = res;
+
+ reply_outbuf(req, 2, 0);
+ SIVAL(req->outbuf,smb_vwv0,res);
+
+ DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
+ fsp->fnum, (double)startpos, (double)res, mode));
+
+ END_PROFILE(SMBlseek);
+ return;
+}
+
+/****************************************************************************
+ Reply to a flush.
+****************************************************************************/
+
+void reply_flush(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ uint16 fnum;
+ files_struct *fsp;
+
+ START_PROFILE(SMBflush);
+
+ if (req->wct < 1) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ fnum = SVAL(req->inbuf,smb_vwv0);
+ fsp = file_fsp(fnum);
+
+ if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
+ return;
+ }
+
+ if (!fsp) {
+ file_sync_all(conn);
+ } else {
+ NTSTATUS status = sync_file(conn, fsp, True);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
+ fsp->fsp_name, nt_errstr(status) ));
+ reply_nterror(req, status);
+ END_PROFILE(SMBflush);
+ return;
+ }
+ }
+
+ reply_outbuf(req, 0, 0);
+
+ DEBUG(3,("flush\n"));
+ END_PROFILE(SMBflush);
+ return;
+}
+
+/****************************************************************************
+ Reply to a exit.
+ conn POINTER CAN BE NULL HERE !
+****************************************************************************/
+
+void reply_exit(struct smb_request *req)
+{
+ START_PROFILE(SMBexit);
+
+ file_close_pid(req->smbpid, req->vuid);
+
+ reply_outbuf(req, 0, 0);
+
+ DEBUG(3,("exit\n"));
+
+ END_PROFILE(SMBexit);
+ return;
+}
+
+/****************************************************************************
+ Reply to a close - has to deal with closing a directory opened by NT SMB's.
+****************************************************************************/
+
+void reply_close(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ NTSTATUS status = NT_STATUS_OK;
+ files_struct *fsp = NULL;
+ START_PROFILE(SMBclose);
+
+ if (req->wct < 3) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBclose);
+ return;
+ }
+
+ /* If it's an IPC, pass off to the pipe handler. */
+ if (IS_IPC(conn)) {
+ reply_pipe_close(conn, req);
+ END_PROFILE(SMBclose);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
+
+ /*
+ * We can only use CHECK_FSP if we know it's not a directory.
+ */
+
+ if(!fsp || (fsp->conn != conn) || (fsp->vuid != req->vuid)) {
+ reply_doserror(req, ERRDOS, ERRbadfid);
+ END_PROFILE(SMBclose);
+ return;
+ }
+
+ if(fsp->is_directory) {
+ /*
+ * Special case - close NT SMB directory handle.
+ */
+ DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
+ status = close_file(fsp,NORMAL_CLOSE);
+ } else {
+ time_t t;
+ /*
+ * Close ordinary file.
+ */
+
+ DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
+ fsp->fh->fd, fsp->fnum,
+ conn->num_files_open));
+
+ /*
+ * Take care of any time sent in the close.
+ */
+
+ t = srv_make_unix_date3(req->inbuf+smb_vwv1);
+ set_close_write_time(fsp, convert_time_t_to_timespec(t));
+
+ /*
+ * close_file() returns the unix errno if an error
+ * was detected on close - normally this is due to
+ * a disk full error. If not then it was probably an I/O error.
+ */
+
+ status = close_file(fsp,NORMAL_CLOSE);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBclose);
+ return;
+ }
+
+ reply_outbuf(req, 0, 0);
+ END_PROFILE(SMBclose);
+ return;
+}
+
+/****************************************************************************
+ Reply to a writeclose (Core+ protocol).
+****************************************************************************/
+
+void reply_writeclose(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ NTSTATUS close_status = NT_STATUS_OK;
+ SMB_OFF_T startpos;
+ char *data;
+ struct timespec mtime;
+ files_struct *fsp;
+
+ START_PROFILE(SMBwriteclose);
+
+ if (req->wct < 6) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBwriteclose);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
+
+ if (!check_fsp(conn, req, fsp)) {
+ END_PROFILE(SMBwriteclose);
+ return;
+ }
+ if (!CHECK_WRITE(fsp)) {
+ reply_doserror(req, ERRDOS,ERRbadaccess);
+ END_PROFILE(SMBwriteclose);
+ return;
+ }
+
+ numtowrite = SVAL(req->inbuf,smb_vwv1);
+ startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
+ mtime = convert_time_t_to_timespec(srv_make_unix_date3(
+ req->inbuf+smb_vwv4));
+ data = smb_buf(req->inbuf) + 1;
+
+ if (numtowrite
+ && is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)numtowrite,
+ (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+ reply_doserror(req, ERRDOS,ERRlock);
+ END_PROFILE(SMBwriteclose);
+ return;
+ }
+
+ nwritten = write_file(req,fsp,data,startpos,numtowrite);
+
+ set_close_write_time(fsp, mtime);
+
+ /*
+ * More insanity. W2K only closes the file if writelen > 0.
+ * JRA.
+ */
+
+ if (numtowrite) {
+ DEBUG(3,("reply_writeclose: zero length write doesn't close file %s\n",
+ fsp->fsp_name ));
+ close_status = close_file(fsp,NORMAL_CLOSE);
+ }
+
+ DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
+ fsp->fnum, (int)numtowrite, (int)nwritten,
+ conn->num_files_open));
+
+ if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
+ reply_doserror(req, ERRHRD, ERRdiskfull);
+ END_PROFILE(SMBwriteclose);
+ return;
+ }
+
+ if(!NT_STATUS_IS_OK(close_status)) {
+ reply_nterror(req, close_status);
+ END_PROFILE(SMBwriteclose);
+ return;
+ }
+
+ reply_outbuf(req, 1, 0);
+
+ SSVAL(req->outbuf,smb_vwv0,nwritten);
+ END_PROFILE(SMBwriteclose);
+ return;
+}
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_LOCKING
+
+/****************************************************************************
+ Reply to a lock.
+****************************************************************************/
+
+void reply_lock(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ SMB_BIG_UINT count,offset;
+ NTSTATUS status;
+ files_struct *fsp;
+ struct byte_range_lock *br_lck = NULL;
+
+ START_PROFILE(SMBlock);
+
+ if (req->wct < 5) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBlock);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
+
+ if (!check_fsp(conn, req, fsp)) {
+ END_PROFILE(SMBlock);
+ return;
+ }
+
+ release_level_2_oplocks_on_change(fsp);
+
+ count = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv1);
+ offset = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv3);
+
+ DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
+ fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
+
+ br_lck = do_lock(smbd_messaging_context(),
+ fsp,
+ req->smbpid,
+ count,
+ offset,
+ WRITE_LOCK,
+ WINDOWS_LOCK,
+ False, /* Non-blocking lock. */
+ &status,
+ NULL);
+
+ TALLOC_FREE(br_lck);
+
+ if (NT_STATUS_V(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBlock);
+ return;
+ }
+
+ reply_outbuf(req, 0, 0);
+
+ END_PROFILE(SMBlock);
+ return;
+}
+
+/****************************************************************************
+ Reply to a unlock.
+****************************************************************************/
+
+void reply_unlock(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ SMB_BIG_UINT count,offset;
+ NTSTATUS status;
+ files_struct *fsp;
+
+ START_PROFILE(SMBunlock);
+
+ if (req->wct < 5) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBunlock);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
+
+ if (!check_fsp(conn, req, fsp)) {
+ END_PROFILE(SMBunlock);
+ return;
+ }
+
+ count = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv1);
+ offset = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv3);
+
+ status = do_unlock(smbd_messaging_context(),
+ fsp,
+ req->smbpid,
+ count,
+ offset,
+ WINDOWS_LOCK);
+
+ if (NT_STATUS_V(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBunlock);
+ return;
+ }
+
+ DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
+ fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
+
+ reply_outbuf(req, 0, 0);
+
+ END_PROFILE(SMBunlock);
+ return;
+}
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_ALL
+
+/****************************************************************************
+ Reply to a tdis.
+ conn POINTER CAN BE NULL HERE !
+****************************************************************************/
+
+void reply_tdis(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ START_PROFILE(SMBtdis);
+
+ if (!conn) {
+ DEBUG(4,("Invalid connection in tdis\n"));
+ reply_doserror(req, ERRSRV, ERRinvnid);
+ END_PROFILE(SMBtdis);
+ return;
+ }
+
+ conn->used = False;
+
+ close_cnum(conn,req->vuid);
+ req->conn = NULL;
+
+ reply_outbuf(req, 0, 0);
+ END_PROFILE(SMBtdis);
+ return;
+}
+
+/****************************************************************************
+ Reply to a echo.
+ conn POINTER CAN BE NULL HERE !
+****************************************************************************/
+
+void reply_echo(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ int smb_reverb;
+ int seq_num;
+ unsigned int data_len = smb_buflen(req->inbuf);
+
+ START_PROFILE(SMBecho);
+
+ if (req->wct < 1) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBecho);
+ return;
+ }
+
+ if (data_len > BUFFER_SIZE) {
+ DEBUG(0,("reply_echo: data_len too large.\n"));
+ reply_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
+ END_PROFILE(SMBecho);
+ return;
+ }
+
+ smb_reverb = SVAL(req->inbuf,smb_vwv0);
+
+ reply_outbuf(req, 1, data_len);
+
+ /* copy any incoming data back out */
+ if (data_len > 0) {
+ memcpy(smb_buf(req->outbuf),smb_buf(req->inbuf),data_len);
+ }
+
+ 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(req->outbuf,smb_vwv0,seq_num);
+
+ show_msg((char *)req->outbuf);
+ if (!srv_send_smb(smbd_server_fd(),
+ (char *)req->outbuf,
+ IS_CONN_ENCRYPTED(conn)||req->encrypted))
+ exit_server_cleanly("reply_echo: srv_send_smb failed.");
+ }
+
+ DEBUG(3,("echo %d times\n", smb_reverb));
+
+ TALLOC_FREE(req->outbuf);
+
+ smb_echo_count++;
+
+ END_PROFILE(SMBecho);
+ return;
+}
+
+/****************************************************************************
+ Reply to a printopen.
+****************************************************************************/
+
+void reply_printopen(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ files_struct *fsp;
+ NTSTATUS status;
+
+ START_PROFILE(SMBsplopen);
+
+ if (req->wct < 2) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBsplopen);
+ return;
+ }
+
+ if (!CAN_PRINT(conn)) {
+ reply_doserror(req, ERRDOS, ERRnoaccess);
+ END_PROFILE(SMBsplopen);
+ return;
+ }
+
+ /* Open for exclusive use, write only. */
+ status = print_fsp_open(conn, NULL, req->vuid, &fsp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBsplopen);
+ return;
+ }
+
+ reply_outbuf(req, 1, 0);
+ SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
+
+ DEBUG(3,("openprint fd=%d fnum=%d\n",
+ fsp->fh->fd, fsp->fnum));
+
+ END_PROFILE(SMBsplopen);
+ return;
+}
+
+/****************************************************************************
+ Reply to a printclose.
+****************************************************************************/
+
+void reply_printclose(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ files_struct *fsp;
+ NTSTATUS status;
+
+ START_PROFILE(SMBsplclose);
+
+ if (req->wct < 1) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBsplclose);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
+
+ if (!check_fsp(conn, req, fsp)) {
+ END_PROFILE(SMBsplclose);
+ return;
+ }
+
+ if (!CAN_PRINT(conn)) {
+ reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRerror));
+ END_PROFILE(SMBsplclose);
+ return;
+ }
+
+ DEBUG(3,("printclose fd=%d fnum=%d\n",
+ fsp->fh->fd,fsp->fnum));
+
+ status = close_file(fsp,NORMAL_CLOSE);
+
+ if(!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBsplclose);
+ return;
+ }
+
+ reply_outbuf(req, 0, 0);
+
+ END_PROFILE(SMBsplclose);
+ return;
+}
+
+/****************************************************************************
+ Reply to a printqueue.
+****************************************************************************/
+
+void reply_printqueue(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ int max_count;
+ int start_index;
+
+ START_PROFILE(SMBsplretq);
+
+ if (req->wct < 2) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBsplretq);
+ return;
+ }
+
+ max_count = SVAL(req->inbuf,smb_vwv0);
+ start_index = SVAL(req->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)) {
+ reply_doserror(req, ERRDOS, ERRnoaccess);
+ END_PROFILE(SMBsplretq);
+ return;
+ }
+
+ reply_outbuf(req, 2, 3);
+ SSVAL(req->outbuf,smb_vwv0,0);
+ SSVAL(req->outbuf,smb_vwv1,0);
+ SCVAL(smb_buf(req->outbuf),0,1);
+ SSVAL(smb_buf(req->outbuf),1,0);
+
+ DEBUG(3,("printqueue start_index=%d max_count=%d\n",
+ start_index, max_count));
+
+ {
+ print_queue_struct *queue = NULL;
+ print_status_struct status;
+ int count = print_queue_status(SNUM(conn), &queue, &status);
+ 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++) {
+ char blob[28];
+ char *p = blob;
+
+ srv_put_dos_date2(p,0,queue[i].time);
+ SCVAL(p,4,(queue[i].status==LPQ_PRINTING?2:3));
+ SSVAL(p,5, queue[i].job);
+ SIVAL(p,7,queue[i].size);
+ SCVAL(p,11,0);
+ srvstr_push(blob, req->flags2, p+12,
+ queue[i].fs_user, 16, STR_ASCII);
+
+ if (message_push_blob(
+ &req->outbuf,
+ data_blob_const(
+ blob, sizeof(blob))) == -1) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBsplretq);
+ return;
+ }
+ }
+
+ if (count > 0) {
+ SSVAL(req->outbuf,smb_vwv0,count);
+ SSVAL(req->outbuf,smb_vwv1,
+ (max_count>0?first+count:first-1));
+ SCVAL(smb_buf(req->outbuf),0,1);
+ SSVAL(smb_buf(req->outbuf),1,28*count);
+ }
+
+ SAFE_FREE(queue);
+
+ DEBUG(3,("%d entries returned in queue\n",count));
+ }
+
+ END_PROFILE(SMBsplretq);
+ return;
+}
+
+/****************************************************************************
+ Reply to a printwrite.
+****************************************************************************/
+
+void reply_printwrite(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ int numtowrite;
+ char *data;
+ files_struct *fsp;
+
+ START_PROFILE(SMBsplwr);
+
+ if (req->wct < 1) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBsplwr);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
+
+ if (!check_fsp(conn, req, fsp)) {
+ END_PROFILE(SMBsplwr);
+ return;
+ }
+
+ if (!CAN_PRINT(conn)) {
+ reply_doserror(req, ERRDOS, ERRnoaccess);
+ END_PROFILE(SMBsplwr);
+ return;
+ }
+
+ if (!CHECK_WRITE(fsp)) {
+ reply_doserror(req, ERRDOS, ERRbadaccess);
+ END_PROFILE(SMBsplwr);
+ return;
+ }
+
+ numtowrite = SVAL(smb_buf(req->inbuf),1);
+
+ if (smb_buflen(req->inbuf) < numtowrite + 3) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBsplwr);
+ return;
+ }
+
+ data = smb_buf(req->inbuf) + 3;
+
+ if (write_file(req,fsp,data,-1,numtowrite) != numtowrite) {
+ reply_unixerror(req, ERRHRD, ERRdiskfull);
+ END_PROFILE(SMBsplwr);
+ return;
+ }
+
+ DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
+
+ END_PROFILE(SMBsplwr);
+ return;
+}
+
+/****************************************************************************
+ Reply to a mkdir.
+****************************************************************************/
+
+void reply_mkdir(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ char *directory = NULL;
+ NTSTATUS status;
+ SMB_STRUCT_STAT sbuf;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ START_PROFILE(SMBmkdir);
+
+ srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &directory,
+ smb_buf(req->inbuf) + 1, 0,
+ STR_TERMINATE, &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBmkdir);
+ return;
+ }
+
+ status = resolve_dfspath(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ directory,
+ &directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ END_PROFILE(SMBmkdir);
+ return;
+ }
+ reply_nterror(req, status);
+ END_PROFILE(SMBmkdir);
+ return;
+ }
+
+ status = unix_convert(ctx, conn, directory, False, &directory, NULL, &sbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBmkdir);
+ return;
+ }
+
+ status = check_name(conn, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBmkdir);
+ return;
+ }
+
+ status = create_directory(conn, req, directory);
+
+ DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
+
+ if (!NT_STATUS_IS_OK(status)) {
+
+ if (!use_nt_status()
+ && NT_STATUS_EQUAL(status,
+ NT_STATUS_OBJECT_NAME_COLLISION)) {
+ /*
+ * Yes, in the DOS error code case we get a
+ * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
+ * samba4 torture test.
+ */
+ status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
+ }
+
+ reply_nterror(req, status);
+ END_PROFILE(SMBmkdir);
+ return;
+ }
+
+ reply_outbuf(req, 0, 0);
+
+ DEBUG( 3, ( "mkdir %s\n", directory ) );
+
+ END_PROFILE(SMBmkdir);
+ return;
+}
+
+/****************************************************************************
+ Static function used by reply_rmdir to delete an entire directory
+ tree recursively. Return True on ok, False on fail.
+****************************************************************************/
+
+static bool recursive_rmdir(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ char *directory)
+{
+ const char *dname = NULL;
+ bool ret = True;
+ long offset = 0;
+ struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, directory,
+ NULL, 0);
+
+ if(dir_hnd == NULL)
+ return False;
+
+ while((dname = ReadDirName(dir_hnd, &offset))) {
+ char *fullname = NULL;
+ SMB_STRUCT_STAT st;
+
+ if (ISDOT(dname) || ISDOTDOT(dname)) {
+ continue;
+ }
+
+ if (!is_visible_file(conn, directory, dname, &st, False)) {
+ continue;
+ }
+
+ /* Construct the full name. */
+ fullname = talloc_asprintf(ctx,
+ "%s/%s",
+ directory,
+ dname);
+ if (!fullname) {
+ errno = ENOMEM;
+ ret = False;
+ break;
+ }
+
+ if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) {
+ ret = False;
+ break;
+ }
+
+ if(st.st_mode & S_IFDIR) {
+ if(!recursive_rmdir(ctx, conn, fullname)) {
+ ret = False;
+ break;
+ }
+ if(SMB_VFS_RMDIR(conn,fullname) != 0) {
+ ret = False;
+ break;
+ }
+ } else if(SMB_VFS_UNLINK(conn,fullname) != 0) {
+ ret = False;
+ break;
+ }
+ TALLOC_FREE(fullname);
+ }
+ TALLOC_FREE(dir_hnd);
+ return ret;
+}
+
+/****************************************************************************
+ The internals of the rmdir code - called elsewhere.
+****************************************************************************/
+
+NTSTATUS rmdir_internals(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ const char *directory)
+{
+ int ret;
+ SMB_STRUCT_STAT st;
+
+ /* Might be a symlink. */
+ if(SMB_VFS_LSTAT(conn, directory, &st) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ if (S_ISLNK(st.st_mode)) {
+ /* Is what it points to a directory ? */
+ if(SMB_VFS_STAT(conn, directory, &st) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+ if (!(S_ISDIR(st.st_mode))) {
+ return NT_STATUS_NOT_A_DIRECTORY;
+ }
+ ret = SMB_VFS_UNLINK(conn,directory);
+ } else {
+ ret = SMB_VFS_RMDIR(conn,directory);
+ }
+ if (ret == 0) {
+ notify_fname(conn, NOTIFY_ACTION_REMOVED,
+ FILE_NOTIFY_CHANGE_DIR_NAME,
+ directory);
+ return NT_STATUS_OK;
+ }
+
+ if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
+ /*
+ * Check to see if the only thing in this directory are
+ * vetoed files/directories. If so then delete them and
+ * retry. If we fail to delete any of them (and we *don't*
+ * do a recursive delete) then fail the rmdir.
+ */
+ const char *dname;
+ long dirpos = 0;
+ struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn,
+ directory, NULL, 0);
+
+ if(dir_hnd == NULL) {
+ errno = ENOTEMPTY;
+ goto err;
+ }
+
+ while ((dname = ReadDirName(dir_hnd,&dirpos))) {
+ if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+ continue;
+ if (!is_visible_file(conn, directory, dname, &st, False))
+ continue;
+ if(!IS_VETO_PATH(conn, dname)) {
+ TALLOC_FREE(dir_hnd);
+ errno = ENOTEMPTY;
+ goto err;
+ }
+ }
+
+ /* We only have veto files/directories. Recursive delete. */
+
+ RewindDir(dir_hnd,&dirpos);
+ while ((dname = ReadDirName(dir_hnd,&dirpos))) {
+ char *fullname = NULL;
+
+ if (ISDOT(dname) || ISDOTDOT(dname)) {
+ continue;
+ }
+ if (!is_visible_file(conn, directory, dname, &st, False)) {
+ continue;
+ }
+
+ fullname = talloc_asprintf(ctx,
+ "%s/%s",
+ directory,
+ dname);
+
+ if(!fullname) {
+ errno = ENOMEM;
+ break;
+ }
+
+ if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) {
+ break;
+ }
+ if(st.st_mode & S_IFDIR) {
+ if(lp_recursive_veto_delete(SNUM(conn))) {
+ if(!recursive_rmdir(ctx, conn, fullname))
+ break;
+ }
+ if(SMB_VFS_RMDIR(conn,fullname) != 0) {
+ break;
+ }
+ } else if(SMB_VFS_UNLINK(conn,fullname) != 0) {
+ break;
+ }
+ TALLOC_FREE(fullname);
+ }
+ TALLOC_FREE(dir_hnd);
+ /* Retry the rmdir */
+ ret = SMB_VFS_RMDIR(conn,directory);
+ }
+
+ err:
+
+ if (ret != 0) {
+ DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
+ "%s\n", directory,strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+
+ notify_fname(conn, NOTIFY_ACTION_REMOVED,
+ FILE_NOTIFY_CHANGE_DIR_NAME,
+ directory);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Reply to a rmdir.
+****************************************************************************/
+
+void reply_rmdir(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ char *directory = NULL;
+ SMB_STRUCT_STAT sbuf;
+ NTSTATUS status;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ START_PROFILE(SMBrmdir);
+
+ srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &directory,
+ smb_buf(req->inbuf) + 1, 0,
+ STR_TERMINATE, &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBrmdir);
+ return;
+ }
+
+ status = resolve_dfspath(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ directory,
+ &directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ END_PROFILE(SMBrmdir);
+ return;
+ }
+ reply_nterror(req, status);
+ END_PROFILE(SMBrmdir);
+ return;
+ }
+
+ status = unix_convert(ctx, conn, directory, False, &directory,
+ NULL, &sbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBrmdir);
+ return;
+ }
+
+ status = check_name(conn, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBrmdir);
+ return;
+ }
+
+ dptr_closepath(directory, req->smbpid);
+ status = rmdir_internals(ctx, conn, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBrmdir);
+ return;
+ }
+
+ reply_outbuf(req, 0, 0);
+
+ DEBUG( 3, ( "rmdir %s\n", directory ) );
+
+ END_PROFILE(SMBrmdir);
+ return;
+}
+
+/*******************************************************************
+ Resolve wildcards in a filename rename.
+********************************************************************/
+
+static bool resolve_wildcards(TALLOC_CTX *ctx,
+ const char *name1,
+ const char *name2,
+ char **pp_newname)
+{
+ char *name2_copy = NULL;
+ char *root1 = NULL;
+ char *root2 = NULL;
+ char *ext1 = NULL;
+ char *ext2 = NULL;
+ char *p,*p2, *pname1, *pname2;
+
+ name2_copy = talloc_strdup(ctx, name2);
+ if (!name2_copy) {
+ return False;
+ }
+
+ pname1 = strrchr_m(name1,'/');
+ pname2 = strrchr_m(name2_copy,'/');
+
+ if (!pname1 || !pname2) {
+ return False;
+ }
+
+ /* Truncate the copy of name2 at the last '/' */
+ *pname2 = '\0';
+
+ /* Now go past the '/' */
+ pname1++;
+ pname2++;
+
+ root1 = talloc_strdup(ctx, pname1);
+ root2 = talloc_strdup(ctx, pname2);
+
+ if (!root1 || !root2) {
+ return False;
+ }
+
+ p = strrchr_m(root1,'.');
+ if (p) {
+ *p = 0;
+ ext1 = talloc_strdup(ctx, p+1);
+ } else {
+ ext1 = talloc_strdup(ctx, "");
+ }
+ p = strrchr_m(root2,'.');
+ if (p) {
+ *p = 0;
+ ext2 = talloc_strdup(ctx, p+1);
+ } else {
+ ext2 = talloc_strdup(ctx, "");
+ }
+
+ if (!ext1 || !ext2) {
+ return False;
+ }
+
+ p = root1;
+ p2 = root2;
+ while (*p2) {
+ if (*p2 == '?') {
+ /* Hmmm. Should this be mb-aware ? */
+ *p2 = *p;
+ p2++;
+ } else if (*p2 == '*') {
+ *p2 = '\0';
+ root2 = talloc_asprintf(ctx, "%s%s",
+ root2,
+ p);
+ if (!root2) {
+ return False;
+ }
+ break;
+ } else {
+ p2++;
+ }
+ if (*p) {
+ p++;
+ }
+ }
+
+ p = ext1;
+ p2 = ext2;
+ while (*p2) {
+ if (*p2 == '?') {
+ /* Hmmm. Should this be mb-aware ? */
+ *p2 = *p;
+ p2++;
+ } else if (*p2 == '*') {
+ *p2 = '\0';
+ ext2 = talloc_asprintf(ctx, "%s%s",
+ ext2,
+ p);
+ if (!ext2) {
+ return False;
+ }
+ break;
+ } else {
+ p2++;
+ }
+ if (*p) {
+ p++;
+ }
+ }
+
+ if (*ext2) {
+ *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
+ name2_copy,
+ root2,
+ ext2);
+ } else {
+ *pp_newname = talloc_asprintf(ctx, "%s/%s",
+ name2_copy,
+ root2);
+ }
+
+ if (!*pp_newname) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Ensure open files have their names updated. Updated to notify other smbd's
+ asynchronously.
+****************************************************************************/
+
+static void rename_open_files(connection_struct *conn,
+ struct share_mode_lock *lck,
+ const char *newname)
+{
+ files_struct *fsp;
+ bool did_rename = False;
+
+ for(fsp = file_find_di_first(lck->id); fsp;
+ fsp = file_find_di_next(fsp)) {
+ /* fsp_name is a relative path under the fsp. To change this for other
+ sharepaths we need to manipulate relative paths. */
+ /* TODO - create the absolute path and manipulate the newname
+ relative to the sharepath. */
+ if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
+ continue;
+ }
+ DEBUG(10,("rename_open_files: renaming file fnum %d (file_id %s) from %s -> %s\n",
+ fsp->fnum, file_id_string_tos(&fsp->file_id),
+ fsp->fsp_name, newname ));
+ string_set(&fsp->fsp_name, newname);
+ did_rename = True;
+ }
+
+ if (!did_rename) {
+ DEBUG(10,("rename_open_files: no open files on file_id %s for %s\n",
+ file_id_string_tos(&lck->id), newname ));
+ }
+
+ /* Send messages to all smbd's (not ourself) that the name has changed. */
+ rename_share_filename(smbd_messaging_context(), lck, conn->connectpath,
+ newname);
+}
+
+/****************************************************************************
+ We need to check if the source path is a parent directory of the destination
+ (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
+ refuse the rename with a sharing violation. Under UNIX the above call can
+ *succeed* if /foo/bar/baz is a symlink to another area in the share. We
+ probably need to check that the client is a Windows one before disallowing
+ this as a UNIX client (one with UNIX extensions) can know the source is a
+ symlink and make this decision intelligently. Found by an excellent bug
+ report from <AndyLiebman@aol.com>.
+****************************************************************************/
+
+static bool rename_path_prefix_equal(const char *src, const char *dest)
+{
+ const char *psrc = src;
+ const char *pdst = dest;
+ size_t slen;
+
+ if (psrc[0] == '.' && psrc[1] == '/') {
+ psrc += 2;
+ }
+ if (pdst[0] == '.' && pdst[1] == '/') {
+ pdst += 2;
+ }
+ if ((slen = strlen(psrc)) > strlen(pdst)) {
+ return False;
+ }
+ return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
+}
+
+/*
+ * Do the notify calls from a rename
+ */
+
+static void notify_rename(connection_struct *conn, bool is_dir,
+ const char *oldpath, const char *newpath)
+{
+ char *olddir, *newdir;
+ const char *oldname, *newname;
+ uint32 mask;
+
+ mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
+ : FILE_NOTIFY_CHANGE_FILE_NAME;
+
+ if (!parent_dirname_talloc(NULL, oldpath, &olddir, &oldname)
+ || !parent_dirname_talloc(NULL, newpath, &newdir, &newname)) {
+ TALLOC_FREE(olddir);
+ return;
+ }
+
+ if (strcmp(olddir, newdir) == 0) {
+ notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, oldpath);
+ notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, newpath);
+ }
+ else {
+ notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, oldpath);
+ notify_fname(conn, NOTIFY_ACTION_ADDED, mask, newpath);
+ }
+ TALLOC_FREE(olddir);
+ TALLOC_FREE(newdir);
+
+ /* this is a strange one. w2k3 gives an additional event for
+ CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
+ files, but not directories */
+ if (!is_dir) {
+ notify_fname(conn, NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES
+ |FILE_NOTIFY_CHANGE_CREATION,
+ newpath);
+ }
+}
+
+/****************************************************************************
+ Rename an open file - given an fsp.
+****************************************************************************/
+
+NTSTATUS rename_internals_fsp(connection_struct *conn,
+ files_struct *fsp,
+ char *newname,
+ const char *newname_last_component,
+ uint32 attrs,
+ bool replace_if_exists)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ SMB_STRUCT_STAT sbuf, sbuf1;
+ NTSTATUS status = NT_STATUS_OK;
+ struct share_mode_lock *lck = NULL;
+ bool dst_exists;
+
+ ZERO_STRUCT(sbuf);
+
+ status = check_name(conn, newname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Ensure newname contains a '/' */
+ if(strrchr_m(newname,'/') == 0) {
+ newname = talloc_asprintf(ctx,
+ "./%s",
+ newname);
+ if (!newname) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ /*
+ * Check for special case with case preserving and not
+ * case sensitive. If 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((conn->case_sensitive == False) && (conn->case_preserve == True) &&
+ strequal(newname, fsp->fsp_name)) {
+ char *p;
+ char *newname_modified_last_component = NULL;
+
+ /*
+ * Get the last component of the modified name.
+ * Note that we guarantee that newname contains a '/'
+ * character above.
+ */
+ p = strrchr_m(newname,'/');
+ newname_modified_last_component = talloc_strdup(ctx,
+ p+1);
+ if (!newname_modified_last_component) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if(strcsequal(newname_modified_last_component,
+ newname_last_component) == False) {
+ /*
+ * Replace the modified last component with
+ * the original.
+ */
+ *p = '\0'; /* Truncate at the '/' */
+ newname = talloc_asprintf(ctx,
+ "%s/%s",
+ newname,
+ newname_last_component);
+ }
+ }
+
+ /*
+ * If the src and dest names are identical - including case,
+ * don't do the rename, just return success.
+ */
+
+ if (strcsequal(fsp->fsp_name, newname)) {
+ DEBUG(3,("rename_internals_fsp: identical names in rename %s - returning success\n",
+ newname));
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * Have vfs_object_exist also fill sbuf1
+ */
+ dst_exists = vfs_object_exist(conn, newname, &sbuf1);
+
+ if(!replace_if_exists && dst_exists) {
+ DEBUG(3,("rename_internals_fsp: dest exists doing rename %s -> %s\n",
+ fsp->fsp_name,newname));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ if (dst_exists) {
+ struct file_id fileid = vfs_file_id_from_sbuf(conn, &sbuf1);
+ files_struct *dst_fsp = file_find_di_first(fileid);
+ if (dst_fsp) {
+ DEBUG(3, ("rename_internals_fsp: Target file open\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ /* Ensure we have a valid stat struct for the source. */
+ if (fsp->fh->fd != -1) {
+ if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+ } else {
+ if (SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+ }
+
+ status = can_rename(conn, fsp, attrs, &sbuf);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
+ nt_errstr(status), fsp->fsp_name,newname));
+ if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
+ status = NT_STATUS_ACCESS_DENIED;
+ return status;
+ }
+
+ if (rename_path_prefix_equal(fsp->fsp_name, newname)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
+ NULL);
+
+ /*
+ * We have the file open ourselves, so not being able to get the
+ * corresponding share mode lock is a fatal error.
+ */
+
+ SMB_ASSERT(lck != NULL);
+
+ if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) {
+ uint32 create_options = fsp->fh->private_options;
+
+ DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n",
+ fsp->fsp_name,newname));
+
+ rename_open_files(conn, lck, newname);
+
+ notify_rename(conn, fsp->is_directory, fsp->fsp_name, newname);
+
+ /*
+ * A rename acts as a new file create w.r.t. allowing an initial delete
+ * on close, probably because in Windows there is a new handle to the
+ * new file. If initial delete on close was requested but not
+ * originally set, we need to set it here. This is probably not 100% correct,
+ * but will work for the CIFSFS client which in non-posix mode
+ * depends on these semantics. JRA.
+ */
+
+ set_allow_initial_delete_on_close(lck, fsp, True);
+
+ if (create_options & FILE_DELETE_ON_CLOSE) {
+ status = can_set_delete_on_close(fsp, True, 0);
+
+ if (NT_STATUS_IS_OK(status)) {
+ /* Note that here we set the *inital* delete on close flag,
+ * not the regular one. The magic gets handled in close. */
+ fsp->initial_delete_on_close = True;
+ }
+ }
+ TALLOC_FREE(lck);
+ return NT_STATUS_OK;
+ }
+
+ TALLOC_FREE(lck);
+
+ if (errno == ENOTDIR || errno == EISDIR) {
+ status = NT_STATUS_OBJECT_NAME_COLLISION;
+ } else {
+ status = map_nt_error_from_unix(errno);
+ }
+
+ DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
+ nt_errstr(status), fsp->fsp_name,newname));
+
+ return status;
+}
+
+/****************************************************************************
+ The guts of the rename command, split out so it may be called by the NT SMB
+ code.
+****************************************************************************/
+
+NTSTATUS rename_internals(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ struct smb_request *req,
+ const char *name_in,
+ const char *newname_in,
+ uint32 attrs,
+ bool replace_if_exists,
+ bool src_has_wild,
+ bool dest_has_wild,
+ uint32_t access_mask)
+{
+ char *directory = NULL;
+ char *mask = NULL;
+ char *last_component_src = NULL;
+ char *last_component_dest = NULL;
+ char *name = NULL;
+ char *newname = NULL;
+ char *p;
+ int count=0;
+ NTSTATUS status = NT_STATUS_OK;
+ SMB_STRUCT_STAT sbuf1, sbuf2;
+ struct smb_Dir *dir_hnd = NULL;
+ const char *dname;
+ long offset = 0;
+
+ ZERO_STRUCT(sbuf1);
+ ZERO_STRUCT(sbuf2);
+
+ status = unix_convert(ctx, conn, name_in, src_has_wild, &name,
+ &last_component_src, &sbuf1);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = unix_convert(ctx, conn, newname_in, dest_has_wild, &newname,
+ &last_component_dest, &sbuf2);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * Split the old name into directory and last component
+ * strings. Note that unix_convert may have stripped off a
+ * leading ./ from both name and newname if the rename is
+ * at the root of the share. We need to make sure either both
+ * name and newname contain a / character or neither of them do
+ * as this is checked in resolve_wildcards().
+ */
+
+ p = strrchr_m(name,'/');
+ if (!p) {
+ directory = talloc_strdup(ctx, ".");
+ if (!directory) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ mask = name;
+ } else {
+ *p = 0;
+ directory = talloc_strdup(ctx, name);
+ if (!directory) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ mask = p+1;
+ *p = '/'; /* Replace needed for exceptional test below. */
+ }
+
+ /*
+ * We should only check the mangled cache
+ * here if unix_convert failed. This means
+ * that the path in 'mask' doesn't exist
+ * on the file system and so we need to look
+ * for a possible mangle. This patch from
+ * Tine Smukavec <valentin.smukavec@hermes.si>.
+ */
+
+ if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) {
+ char *new_mask = NULL;
+ mangle_lookup_name_from_8_3(ctx,
+ mask,
+ &new_mask,
+ conn->params );
+ if (new_mask) {
+ mask = new_mask;
+ }
+ }
+
+ if (!src_has_wild) {
+ files_struct *fsp;
+
+ /*
+ * No wildcards - just process the one file.
+ */
+ bool is_short_name = mangle_is_8_3(name, True, conn->params);
+
+ /* Add a terminating '/' to the directory name. */
+ directory = talloc_asprintf_append(directory,
+ "/%s",
+ mask);
+ if (!directory) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Ensure newname contains a '/' also */
+ if(strrchr_m(newname,'/') == 0) {
+ newname = talloc_asprintf(ctx,
+ "./%s",
+ newname);
+ if (!newname) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ DEBUG(3, ("rename_internals: case_sensitive = %d, "
+ "case_preserve = %d, short case preserve = %d, "
+ "directory = %s, newname = %s, "
+ "last_component_dest = %s, is_8_3 = %d\n",
+ conn->case_sensitive, conn->case_preserve,
+ conn->short_case_preserve, directory,
+ newname, last_component_dest, is_short_name));
+
+ /* The dest name still may have wildcards. */
+ if (dest_has_wild) {
+ char *mod_newname = NULL;
+ if (!resolve_wildcards(ctx,
+ directory,newname,&mod_newname)) {
+ DEBUG(6, ("rename_internals: resolve_wildcards "
+ "%s %s failed\n",
+ directory,
+ newname));
+ return NT_STATUS_NO_MEMORY;
+ }
+ newname = mod_newname;
+ }
+
+ ZERO_STRUCT(sbuf1);
+ SMB_VFS_STAT(conn, directory, &sbuf1);
+
+ status = S_ISDIR(sbuf1.st_mode) ?
+ open_directory(conn, req, directory, &sbuf1,
+ access_mask,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN, 0, 0, NULL,
+ &fsp)
+ : open_file_ntcreate(conn, req, directory, &sbuf1,
+ access_mask,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN, 0, 0, 0, NULL,
+ &fsp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Could not open rename source %s: %s\n",
+ directory, nt_errstr(status)));
+ return status;
+ }
+
+ status = rename_internals_fsp(conn, fsp, newname,
+ last_component_dest,
+ attrs, replace_if_exists);
+
+ close_file(fsp, NORMAL_CLOSE);
+
+ DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
+ nt_errstr(status), directory,newname));
+
+ return status;
+ }
+
+ /*
+ * Wildcards - process each file that matches.
+ */
+ if (strequal(mask,"????????.???")) {
+ mask[0] = '*';
+ mask[1] = '\0';
+ }
+
+ status = check_name(conn, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, attrs);
+ if (dir_hnd == NULL) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ status = NT_STATUS_NO_SUCH_FILE;
+ /*
+ * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ * - gentest fix. JRA
+ */
+
+ while ((dname = ReadDirName(dir_hnd, &offset))) {
+ files_struct *fsp = NULL;
+ char *fname = NULL;
+ char *destname = NULL;
+ bool sysdir_entry = False;
+
+ /* Quick check for "." and ".." */
+ if (ISDOT(dname) || ISDOTDOT(dname)) {
+ if (attrs & aDIR) {
+ sysdir_entry = True;
+ } else {
+ continue;
+ }
+ }
+
+ if (!is_visible_file(conn, directory, dname, &sbuf1, False)) {
+ continue;
+ }
+
+ if(!mask_match(dname, mask, conn->case_sensitive)) {
+ continue;
+ }
+
+ if (sysdir_entry) {
+ status = NT_STATUS_OBJECT_NAME_INVALID;
+ break;
+ }
+
+ fname = talloc_asprintf(ctx,
+ "%s/%s",
+ directory,
+ dname);
+ if (!fname) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!resolve_wildcards(ctx,
+ fname,newname,&destname)) {
+ DEBUG(6, ("resolve_wildcards %s %s failed\n",
+ fname, destname));
+ TALLOC_FREE(fname);
+ continue;
+ }
+ if (!destname) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCT(sbuf1);
+ SMB_VFS_STAT(conn, fname, &sbuf1);
+
+ status = S_ISDIR(sbuf1.st_mode) ?
+ open_directory(conn, req, fname, &sbuf1,
+ access_mask,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN, 0, 0, NULL,
+ &fsp)
+ : open_file_ntcreate(conn, req, fname, &sbuf1,
+ access_mask,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN, 0, 0, 0, NULL,
+ &fsp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3,("rename_internals: open_file_ntcreate "
+ "returned %s rename %s -> %s\n",
+ nt_errstr(status), directory, newname));
+ break;
+ }
+
+ status = rename_internals_fsp(conn, fsp, destname, dname,
+ attrs, replace_if_exists);
+
+ close_file(fsp, NORMAL_CLOSE);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("rename_internals_fsp returned %s for "
+ "rename %s -> %s\n", nt_errstr(status),
+ directory, newname));
+ break;
+ }
+
+ count++;
+
+ DEBUG(3,("rename_internals: doing rename on %s -> "
+ "%s\n",fname,destname));
+
+ TALLOC_FREE(fname);
+ TALLOC_FREE(destname);
+ }
+ TALLOC_FREE(dir_hnd);
+
+ if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
+ status = map_nt_error_from_unix(errno);
+ }
+
+ return status;
+}
+
+/****************************************************************************
+ Reply to a mv.
+****************************************************************************/
+
+void reply_mv(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ char *name = NULL;
+ char *newname = NULL;
+ char *p;
+ uint32 attrs;
+ NTSTATUS status;
+ bool src_has_wcard = False;
+ bool dest_has_wcard = False;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ START_PROFILE(SMBmv);
+
+ if (req->wct < 1) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBmv);
+ return;
+ }
+
+ attrs = SVAL(req->inbuf,smb_vwv0);
+
+ p = smb_buf(req->inbuf) + 1;
+ p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &name, p,
+ 0, STR_TERMINATE, &status,
+ &src_has_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBmv);
+ return;
+ }
+ p++;
+ p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &newname, p,
+ 0, STR_TERMINATE, &status,
+ &dest_has_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBmv);
+ return;
+ }
+
+ status = resolve_dfspath_wcard(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ name,
+ &name,
+ &src_has_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ END_PROFILE(SMBmv);
+ return;
+ }
+ reply_nterror(req, status);
+ END_PROFILE(SMBmv);
+ return;
+ }
+
+ status = resolve_dfspath_wcard(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ newname,
+ &newname,
+ &dest_has_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ END_PROFILE(SMBmv);
+ return;
+ }
+ reply_nterror(req, status);
+ END_PROFILE(SMBmv);
+ return;
+ }
+
+ DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
+
+ status = rename_internals(ctx, conn, req, name, newname, attrs, False,
+ src_has_wcard, dest_has_wcard, DELETE_ACCESS);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (open_was_deferred(req->mid)) {
+ /* We have re-scheduled this call. */
+ END_PROFILE(SMBmv);
+ return;
+ }
+ reply_nterror(req, status);
+ END_PROFILE(SMBmv);
+ return;
+ }
+
+ reply_outbuf(req, 0, 0);
+
+ END_PROFILE(SMBmv);
+ return;
+}
+
+/*******************************************************************
+ Copy a file as part of a reply_copy.
+******************************************************************/
+
+/*
+ * TODO: check error codes on all callers
+ */
+
+NTSTATUS copy_file(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ const char *src,
+ const char *dest1,
+ int ofun,
+ int count,
+ bool target_is_directory)
+{
+ SMB_STRUCT_STAT src_sbuf, sbuf2;
+ SMB_OFF_T ret=-1;
+ files_struct *fsp1,*fsp2;
+ char *dest = NULL;
+ uint32 dosattrs;
+ uint32 new_create_disposition;
+ NTSTATUS status;
+
+ dest = talloc_strdup(ctx, dest1);
+ if (!dest) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (target_is_directory) {
+ const char *p = strrchr_m(src,'/');
+ if (p) {
+ p++;
+ } else {
+ p = src;
+ }
+ dest = talloc_asprintf_append(dest,
+ "/%s",
+ p);
+ if (!dest) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (!vfs_file_exist(conn,src,&src_sbuf)) {
+ TALLOC_FREE(dest);
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (!target_is_directory && count) {
+ new_create_disposition = FILE_OPEN;
+ } else {
+ if (!map_open_params_to_ntcreate(dest1,0,ofun,
+ NULL, NULL, &new_create_disposition, NULL)) {
+ TALLOC_FREE(dest);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ status = open_file_ntcreate(conn, NULL, src, &src_sbuf,
+ FILE_GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN,
+ 0,
+ FILE_ATTRIBUTE_NORMAL,
+ INTERNAL_OPEN_ONLY,
+ NULL, &fsp1);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(dest);
+ return status;
+ }
+
+ dosattrs = dos_mode(conn, src, &src_sbuf);
+ if (SMB_VFS_STAT(conn,dest,&sbuf2) == -1) {
+ ZERO_STRUCTP(&sbuf2);
+ }
+
+ status = open_file_ntcreate(conn, NULL, dest, &sbuf2,
+ FILE_GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ new_create_disposition,
+ 0,
+ dosattrs,
+ INTERNAL_OPEN_ONLY,
+ NULL, &fsp2);
+
+ TALLOC_FREE(dest);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ close_file(fsp1,ERROR_CLOSE);
+ return status;
+ }
+
+ if ((ofun&3) == 1) {
+ if(SMB_VFS_LSEEK(fsp2,0,SEEK_END) == -1) {
+ DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) ));
+ /*
+ * Stop the copy from occurring.
+ */
+ ret = -1;
+ src_sbuf.st_size = 0;
+ }
+ }
+
+ if (src_sbuf.st_size) {
+ ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size);
+ }
+
+ close_file(fsp1,NORMAL_CLOSE);
+
+ /* Ensure the modtime is set correctly on the destination file. */
+ set_close_write_time(fsp2, get_mtimespec(&src_sbuf));
+
+ /*
+ * As we are opening fsp1 read-only we only expect
+ * an error on close on fsp2 if we are out of space.
+ * Thus we don't look at the error return from the
+ * close of fsp1.
+ */
+ status = close_file(fsp2,NORMAL_CLOSE);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (ret != (SMB_OFF_T)src_sbuf.st_size) {
+ return NT_STATUS_DISK_FULL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Reply to a file copy.
+****************************************************************************/
+
+void reply_copy(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ char *name = NULL;
+ char *newname = NULL;
+ char *directory = NULL;
+ char *mask = NULL;
+ char *p;
+ int count=0;
+ int error = ERRnoaccess;
+ int err = 0;
+ int tid2;
+ int ofun;
+ int flags;
+ bool target_is_directory=False;
+ bool source_has_wild = False;
+ bool dest_has_wild = False;
+ SMB_STRUCT_STAT sbuf1, sbuf2;
+ NTSTATUS status;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ START_PROFILE(SMBcopy);
+
+ if (req->wct < 3) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ tid2 = SVAL(req->inbuf,smb_vwv0);
+ ofun = SVAL(req->inbuf,smb_vwv1);
+ flags = SVAL(req->inbuf,smb_vwv2);
+
+ p = smb_buf(req->inbuf);
+ p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &name, p,
+ 0, STR_TERMINATE, &status,
+ &source_has_wild);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+ p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &newname, p,
+ 0, STR_TERMINATE, &status,
+ &dest_has_wild);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
+
+ if (tid2 != conn->cnum) {
+ /* can't currently handle inter share copies XXXX */
+ DEBUG(3,("Rejecting inter-share copy\n"));
+ reply_doserror(req, ERRSRV, ERRinvdevice);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ status = resolve_dfspath_wcard(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ name,
+ &name,
+ &source_has_wild);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+ reply_nterror(req, status);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ status = resolve_dfspath_wcard(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ newname,
+ &newname,
+ &dest_has_wild);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+ reply_nterror(req, status);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ status = unix_convert(ctx, conn, name, source_has_wild,
+ &name, NULL, &sbuf1);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ status = unix_convert(ctx, conn, newname, dest_has_wild,
+ &newname, NULL, &sbuf2);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ target_is_directory = VALID_STAT_OF_DIR(sbuf2);
+
+ if ((flags&1) && target_is_directory) {
+ reply_doserror(req, ERRDOS, ERRbadfile);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ if ((flags&2) && !target_is_directory) {
+ reply_doserror(req, ERRDOS, ERRbadpath);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) {
+ /* wants a tree copy! XXXX */
+ DEBUG(3,("Rejecting tree copy\n"));
+ reply_doserror(req, ERRSRV, ERRerror);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ p = strrchr_m(name,'/');
+ if (!p) {
+ directory = talloc_strdup(ctx, "./");
+ if (!directory) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+ mask = name;
+ } else {
+ *p = 0;
+ directory = talloc_strdup(ctx, name);
+ if (!directory) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+ mask = p+1;
+ }
+
+ /*
+ * We should only check the mangled cache
+ * here if unix_convert failed. This means
+ * that the path in 'mask' doesn't exist
+ * on the file system and so we need to look
+ * for a possible mangle. This patch from
+ * Tine Smukavec <valentin.smukavec@hermes.si>.
+ */
+
+ if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) {
+ char *new_mask = NULL;
+ mangle_lookup_name_from_8_3(ctx,
+ mask,
+ &new_mask,
+ conn->params );
+ if (new_mask) {
+ mask = new_mask;
+ }
+ }
+
+ if (!source_has_wild) {
+ directory = talloc_asprintf_append(directory,
+ "/%s",
+ mask);
+ if (dest_has_wild) {
+ char *mod_newname = NULL;
+ if (!resolve_wildcards(ctx,
+ directory,newname,&mod_newname)) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+ newname = mod_newname;
+ }
+
+ status = check_name(conn, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ status = check_name(conn, newname);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ status = copy_file(ctx,conn,directory,newname,ofun,
+ count,target_is_directory);
+
+ if(!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBcopy);
+ return;
+ } else {
+ count++;
+ }
+ } else {
+ struct smb_Dir *dir_hnd = NULL;
+ const char *dname = NULL;
+ long offset = 0;
+
+ if (strequal(mask,"????????.???")) {
+ mask[0] = '*';
+ mask[1] = '\0';
+ }
+
+ status = check_name(conn, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, 0);
+ if (dir_hnd == NULL) {
+ status = map_nt_error_from_unix(errno);
+ reply_nterror(req, status);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ error = ERRbadfile;
+
+ while ((dname = ReadDirName(dir_hnd, &offset))) {
+ char *destname = NULL;
+ char *fname = NULL;
+
+ if (ISDOT(dname) || ISDOTDOT(dname)) {
+ continue;
+ }
+
+ if (!is_visible_file(conn, directory, dname, &sbuf1, False)) {
+ continue;
+ }
+
+ if(!mask_match(dname, mask, conn->case_sensitive)) {
+ continue;
+ }
+
+ error = ERRnoaccess;
+ fname = talloc_asprintf(ctx,
+ "%s/%s",
+ directory,
+ dname);
+ if (!fname) {
+ TALLOC_FREE(dir_hnd);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ if (!resolve_wildcards(ctx,
+ fname,newname,&destname)) {
+ continue;
+ }
+ if (!destname) {
+ TALLOC_FREE(dir_hnd);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(dir_hnd);
+ reply_nterror(req, status);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ status = check_name(conn, destname);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(dir_hnd);
+ reply_nterror(req, status);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname, destname));
+
+ status = copy_file(ctx,conn,fname,destname,ofun,
+ count,target_is_directory);
+ if (NT_STATUS_IS_OK(status)) {
+ count++;
+ }
+ TALLOC_FREE(fname);
+ TALLOC_FREE(destname);
+ }
+ TALLOC_FREE(dir_hnd);
+ }
+
+ if (count == 0) {
+ if(err) {
+ /* Error on close... */
+ errno = err;
+ reply_unixerror(req, ERRHRD, ERRgeneral);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ reply_doserror(req, ERRDOS, error);
+ END_PROFILE(SMBcopy);
+ return;
+ }
+
+ reply_outbuf(req, 1, 0);
+ SSVAL(req->outbuf,smb_vwv0,count);
+
+ END_PROFILE(SMBcopy);
+ return;
+}
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_LOCKING
+
+/****************************************************************************
+ Get a lock pid, dealing with large count requests.
+****************************************************************************/
+
+uint32 get_lock_pid( char *data, int data_offset, bool large_file_format)
+{
+ if(!large_file_format)
+ return (uint32)SVAL(data,SMB_LPID_OFFSET(data_offset));
+ else
+ return (uint32)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
+}
+
+/****************************************************************************
+ Get a lock count, dealing with large count requests.
+****************************************************************************/
+
+SMB_BIG_UINT get_lock_count( char *data, int data_offset, bool large_file_format)
+{
+ SMB_BIG_UINT count = 0;
+
+ if(!large_file_format) {
+ count = (SMB_BIG_UINT)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
+ } else {
+
+#if defined(HAVE_LONGLONG)
+ count = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
+ ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
+#else /* HAVE_LONGLONG */
+
+ /*
+ * NT4.x seems to be broken in that it sends large file (64 bit)
+ * lockingX calls even if the CAP_LARGE_FILES was *not*
+ * negotiated. For boxes without large unsigned ints truncate the
+ * lock count by dropping the top 32 bits.
+ */
+
+ if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
+ DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
+ (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
+ (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
+ SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
+ }
+
+ count = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
+#endif /* HAVE_LONGLONG */
+ }
+
+ return count;
+}
+
+#if !defined(HAVE_LONGLONG)
+/****************************************************************************
+ Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
+****************************************************************************/
+
+static uint32 map_lock_offset(uint32 high, uint32 low)
+{
+ unsigned int i;
+ uint32 mask = 0;
+ uint32 highcopy = high;
+
+ /*
+ * Try and find out how many significant bits there are in high.
+ */
+
+ for(i = 0; highcopy; i++)
+ highcopy >>= 1;
+
+ /*
+ * We use 31 bits not 32 here as POSIX
+ * lock offsets may not be negative.
+ */
+
+ mask = (~0) << (31 - i);
+
+ if(low & mask)
+ return 0; /* Fail. */
+
+ high <<= (31 - i);
+
+ return (high|low);
+}
+#endif /* !defined(HAVE_LONGLONG) */
+
+/****************************************************************************
+ Get a lock offset, dealing with large offset requests.
+****************************************************************************/
+
+SMB_BIG_UINT get_lock_offset( char *data, int data_offset, bool large_file_format, bool *err)
+{
+ SMB_BIG_UINT offset = 0;
+
+ *err = False;
+
+ if(!large_file_format) {
+ offset = (SMB_BIG_UINT)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
+ } else {
+
+#if defined(HAVE_LONGLONG)
+ offset = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
+ ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
+#else /* HAVE_LONGLONG */
+
+ /*
+ * NT4.x seems to be broken in that it sends large file (64 bit)
+ * lockingX calls even if the CAP_LARGE_FILES was *not*
+ * negotiated. For boxes without large unsigned ints mangle the
+ * lock offset by mapping the top 32 bits onto the lower 32.
+ */
+
+ if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
+ uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
+ uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
+ uint32 new_low = 0;
+
+ if((new_low = map_lock_offset(high, low)) == 0) {
+ *err = True;
+ return (SMB_BIG_UINT)-1;
+ }
+
+ DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
+ (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
+ SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
+ SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
+ }
+
+ offset = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
+#endif /* HAVE_LONGLONG */
+ }
+
+ return offset;
+}
+
+/****************************************************************************
+ Reply to a lockingX request.
+****************************************************************************/
+
+void reply_lockingX(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ files_struct *fsp;
+ unsigned char locktype;
+ unsigned char oplocklevel;
+ uint16 num_ulocks;
+ uint16 num_locks;
+ SMB_BIG_UINT count = 0, offset = 0;
+ uint32 lock_pid;
+ int32 lock_timeout;
+ int i;
+ char *data;
+ bool large_file_format;
+ bool err;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+ START_PROFILE(SMBlockingX);
+
+ if (req->wct < 8) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBlockingX);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv2));
+ locktype = CVAL(req->inbuf,smb_vwv3);
+ oplocklevel = CVAL(req->inbuf,smb_vwv3+1);
+ num_ulocks = SVAL(req->inbuf,smb_vwv6);
+ num_locks = SVAL(req->inbuf,smb_vwv7);
+ lock_timeout = IVAL(req->inbuf,smb_vwv4);
+ large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
+
+ if (!check_fsp(conn, req, fsp)) {
+ END_PROFILE(SMBlockingX);
+ return;
+ }
+
+ data = smb_buf(req->inbuf);
+
+ if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
+ /* we don't support these - and CANCEL_LOCK makes w2k
+ and XP reboot so I don't really want to be
+ compatible! (tridge) */
+ reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
+ END_PROFILE(SMBlockingX);
+ return;
+ }
+
+ /* Check if this is an oplock break on a file
+ we have granted an oplock on.
+ */
+ if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
+ /* Client can insist on breaking to none. */
+ bool break_to_none = (oplocklevel == 0);
+ bool result;
+
+ DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
+ "for fnum = %d\n", (unsigned int)oplocklevel,
+ fsp->fnum ));
+
+ /*
+ * Make sure we have granted an exclusive or batch oplock on
+ * this file.
+ */
+
+ if (fsp->oplock_type == 0) {
+
+ /* The Samba4 nbench simulator doesn't understand
+ the difference between break to level2 and break
+ to none from level2 - it sends oplock break
+ replies in both cases. Don't keep logging an error
+ message here - just ignore it. JRA. */
+
+ DEBUG(5,("reply_lockingX: Error : oplock break from "
+ "client for fnum = %d (oplock=%d) and no "
+ "oplock granted on this file (%s).\n",
+ fsp->fnum, fsp->oplock_type, fsp->fsp_name));
+
+ /* if this is a pure oplock break request then don't
+ * send a reply */
+ if (num_locks == 0 && num_ulocks == 0) {
+ END_PROFILE(SMBlockingX);
+ return;
+ } else {
+ END_PROFILE(SMBlockingX);
+ reply_doserror(req, ERRDOS, ERRlock);
+ return;
+ }
+ }
+
+ if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
+ (break_to_none)) {
+ result = remove_oplock(fsp);
+ } else {
+ result = downgrade_oplock(fsp);
+ }
+
+ if (!result) {
+ DEBUG(0, ("reply_lockingX: error in removing "
+ "oplock on file %s\n", fsp->fsp_name));
+ /* Hmmm. Is this panic justified? */
+ smb_panic("internal tdb error");
+ }
+
+ reply_to_oplock_break_requests(fsp);
+
+ /* 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(req->inbuf,smb_vwv0) != 0xff)
+ DEBUG(0,("reply_lockingX: Error : pure oplock "
+ "break is a chained %d request !\n",
+ (unsigned int)CVAL(req->inbuf,
+ smb_vwv0) ));
+ END_PROFILE(SMBlockingX);
+ return;
+ }
+ }
+
+ /*
+ * We do this check *after* we have checked this is not a oplock break
+ * response message. JRA.
+ */
+
+ release_level_2_oplocks_on_change(fsp);
+
+ if (smb_buflen(req->inbuf) <
+ (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBlockingX);
+ return;
+ }
+
+ /* Data now points at the beginning of the list
+ of smb_unlkrng structs */
+ for(i = 0; i < (int)num_ulocks; i++) {
+ lock_pid = get_lock_pid( data, i, large_file_format);
+ count = get_lock_count( data, i, large_file_format);
+ offset = get_lock_offset( data, i, large_file_format, &err);
+
+ /*
+ * There is no error code marked "stupid client bug".... :-).
+ */
+ if(err) {
+ END_PROFILE(SMBlockingX);
+ reply_doserror(req, ERRDOS, ERRnoaccess);
+ return;
+ }
+
+ DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for "
+ "pid %u, file %s\n", (double)offset, (double)count,
+ (unsigned int)lock_pid, fsp->fsp_name ));
+
+ status = do_unlock(smbd_messaging_context(),
+ fsp,
+ lock_pid,
+ count,
+ offset,
+ WINDOWS_LOCK);
+
+ if (NT_STATUS_V(status)) {
+ END_PROFILE(SMBlockingX);
+ reply_nterror(req, status);
+ return;
+ }
+ }
+
+ /* Setup the timeout in seconds. */
+
+ if (!lp_blocking_locks(SNUM(conn))) {
+ lock_timeout = 0;
+ }
+
+ /* Now do any requested locks */
+ data += ((large_file_format ? 20 : 10)*num_ulocks);
+
+ /* Data now points at the beginning of the list
+ of smb_lkrng structs */
+
+ for(i = 0; i < (int)num_locks; i++) {
+ enum brl_type lock_type = ((locktype & LOCKING_ANDX_SHARED_LOCK) ?
+ READ_LOCK:WRITE_LOCK);
+ lock_pid = get_lock_pid( data, i, large_file_format);
+ count = get_lock_count( data, i, large_file_format);
+ offset = get_lock_offset( data, i, large_file_format, &err);
+
+ /*
+ * There is no error code marked "stupid client bug".... :-).
+ */
+ if(err) {
+ END_PROFILE(SMBlockingX);
+ reply_doserror(req, ERRDOS, ERRnoaccess);
+ return;
+ }
+
+ DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid "
+ "%u, file %s timeout = %d\n", (double)offset,
+ (double)count, (unsigned int)lock_pid,
+ fsp->fsp_name, (int)lock_timeout ));
+
+ if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
+ if (lp_blocking_locks(SNUM(conn))) {
+
+ /* Schedule a message to ourselves to
+ remove the blocking lock record and
+ return the right error. */
+
+ if (!blocking_lock_cancel(fsp,
+ lock_pid,
+ offset,
+ count,
+ WINDOWS_LOCK,
+ locktype,
+ NT_STATUS_FILE_LOCK_CONFLICT)) {
+ END_PROFILE(SMBlockingX);
+ reply_nterror(
+ req,
+ NT_STATUS_DOS(
+ ERRDOS,
+ ERRcancelviolation));
+ return;
+ }
+ }
+ /* Remove a matching pending lock. */
+ status = do_lock_cancel(fsp,
+ lock_pid,
+ count,
+ offset,
+ WINDOWS_LOCK);
+ } else {
+ bool blocking_lock = lock_timeout ? True : False;
+ bool defer_lock = False;
+ struct byte_range_lock *br_lck;
+ uint32 block_smbpid;
+
+ br_lck = do_lock(smbd_messaging_context(),
+ fsp,
+ lock_pid,
+ count,
+ offset,
+ lock_type,
+ WINDOWS_LOCK,
+ blocking_lock,
+ &status,
+ &block_smbpid);
+
+ if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
+ /* Windows internal resolution for blocking locks seems
+ to be about 200ms... Don't wait for less than that. JRA. */
+ if (lock_timeout != -1 && lock_timeout < lp_lock_spin_time()) {
+ lock_timeout = lp_lock_spin_time();
+ }
+ defer_lock = True;
+ }
+
+ /* This heuristic seems to match W2K3 very well. If a
+ lock sent with timeout of zero would fail with NT_STATUS_FILE_LOCK_CONFLICT
+ it pretends we asked for a timeout of between 150 - 300 milliseconds as
+ far as I can tell. Replacement for do_lock_spin(). JRA. */
+
+ if (br_lck && lp_blocking_locks(SNUM(conn)) && !blocking_lock &&
+ NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT)) {
+ defer_lock = True;
+ lock_timeout = lp_lock_spin_time();
+ }
+
+ if (br_lck && defer_lock) {
+ /*
+ * 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(br_lck,
+ req,
+ fsp,
+ lock_timeout,
+ i,
+ lock_pid,
+ lock_type,
+ WINDOWS_LOCK,
+ offset,
+ count,
+ block_smbpid)) {
+ TALLOC_FREE(br_lck);
+ END_PROFILE(SMBlockingX);
+ return;
+ }
+ }
+
+ TALLOC_FREE(br_lck);
+ }
+
+ if (NT_STATUS_V(status)) {
+ END_PROFILE(SMBlockingX);
+ reply_nterror(req, status);
+ return;
+ }
+ }
+
+ /* If any of the above locks failed, then we must unlock
+ all of the previous locks (X/Open spec). */
+
+ if (!(locktype & LOCKING_ANDX_CANCEL_LOCK) &&
+ (i != num_locks) &&
+ (num_locks != 0)) {
+ /*
+ * Ensure we don't do a remove on the lock that just failed,
+ * as under POSIX rules, if we have a lock already there, we
+ * will delete it (and we shouldn't) .....
+ */
+ for(i--; i >= 0; i--) {
+ lock_pid = get_lock_pid( data, i, large_file_format);
+ count = get_lock_count( data, i, large_file_format);
+ offset = get_lock_offset( data, i, large_file_format,
+ &err);
+
+ /*
+ * There is no error code marked "stupid client
+ * bug".... :-).
+ */
+ if(err) {
+ END_PROFILE(SMBlockingX);
+ reply_doserror(req, ERRDOS, ERRnoaccess);
+ return;
+ }
+
+ do_unlock(smbd_messaging_context(),
+ fsp,
+ lock_pid,
+ count,
+ offset,
+ WINDOWS_LOCK);
+ }
+ END_PROFILE(SMBlockingX);
+ reply_nterror(req, status);
+ return;
+ }
+
+ reply_outbuf(req, 2, 0);
+
+ DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
+ fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
+
+ END_PROFILE(SMBlockingX);
+ chain_reply(req);
+}
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_ALL
+
+/****************************************************************************
+ Reply to a SMBreadbmpx (read block multiplex) request.
+ Always reply with an error, if someone has a platform really needs this,
+ please contact vl@samba.org
+****************************************************************************/
+
+void reply_readbmpx(struct smb_request *req)
+{
+ START_PROFILE(SMBreadBmpx);
+ reply_doserror(req, ERRSRV, ERRuseSTD);
+ END_PROFILE(SMBreadBmpx);
+ return;
+}
+
+/****************************************************************************
+ Reply to a SMBreadbs (read block multiplex secondary) request.
+ Always reply with an error, if someone has a platform really needs this,
+ please contact vl@samba.org
+****************************************************************************/
+
+void reply_readbs(struct smb_request *req)
+{
+ START_PROFILE(SMBreadBs);
+ reply_doserror(req, ERRSRV, ERRuseSTD);
+ END_PROFILE(SMBreadBs);
+ return;
+}
+
+/****************************************************************************
+ Reply to a SMBsetattrE.
+****************************************************************************/
+
+void reply_setattrE(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ struct timespec ts[2];
+ files_struct *fsp;
+ SMB_STRUCT_STAT sbuf;
+ NTSTATUS status;
+
+ START_PROFILE(SMBsetattrE);
+
+ if (req->wct < 7) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBsetattrE);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
+
+ if(!fsp || (fsp->conn != conn)) {
+ reply_doserror(req, ERRDOS, ERRbadfid);
+ END_PROFILE(SMBsetattrE);
+ return;
+ }
+
+
+ /*
+ * Convert the DOS times into unix times. Ignore create
+ * time as UNIX can't set this.
+ */
+
+ ts[0] = convert_time_t_to_timespec(
+ srv_make_unix_date2(req->inbuf+smb_vwv3)); /* atime. */
+ ts[1] = convert_time_t_to_timespec(
+ srv_make_unix_date2(req->inbuf+smb_vwv5)); /* mtime. */
+
+ reply_outbuf(req, 0, 0);
+
+ /*
+ * Patch from Ray Frush <frush@engr.colostate.edu>
+ * Sometimes times are sent as zero - ignore them.
+ */
+
+ /* Ensure we have a valid stat struct for the source. */
+ if (fsp->fh->fd != -1) {
+ if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+ status = map_nt_error_from_unix(errno);
+ reply_nterror(req, status);
+ END_PROFILE(SMBsetattrE);
+ return;
+ }
+ } else {
+ if (SMB_VFS_STAT(conn, fsp->fsp_name, &sbuf) == -1) {
+ status = map_nt_error_from_unix(errno);
+ reply_nterror(req, status);
+ END_PROFILE(SMBsetattrE);
+ return;
+ }
+ }
+
+ status = smb_set_file_time(conn, fsp, fsp->fsp_name,
+ &sbuf, ts, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_doserror(req, ERRDOS, ERRnoaccess);
+ END_PROFILE(SMBsetattrE);
+ return;
+ }
+
+ DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u\n",
+ fsp->fnum,
+ (unsigned int)ts[0].tv_sec,
+ (unsigned int)ts[1].tv_sec));
+
+ END_PROFILE(SMBsetattrE);
+ return;
+}
+
+
+/* Back from the dead for OS/2..... JRA. */
+
+/****************************************************************************
+ Reply to a SMBwritebmpx (write block multiplex primary) request.
+ Always reply with an error, if someone has a platform really needs this,
+ please contact vl@samba.org
+****************************************************************************/
+
+void reply_writebmpx(struct smb_request *req)
+{
+ START_PROFILE(SMBwriteBmpx);
+ reply_doserror(req, ERRSRV, ERRuseSTD);
+ END_PROFILE(SMBwriteBmpx);
+ return;
+}
+
+/****************************************************************************
+ Reply to a SMBwritebs (write block multiplex secondary) request.
+ Always reply with an error, if someone has a platform really needs this,
+ please contact vl@samba.org
+****************************************************************************/
+
+void reply_writebs(struct smb_request *req)
+{
+ START_PROFILE(SMBwriteBs);
+ reply_doserror(req, ERRSRV, ERRuseSTD);
+ END_PROFILE(SMBwriteBs);
+ return;
+}
+
+/****************************************************************************
+ Reply to a SMBgetattrE.
+****************************************************************************/
+
+void reply_getattrE(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ SMB_STRUCT_STAT sbuf;
+ int mode;
+ files_struct *fsp;
+ struct timespec create_ts;
+
+ START_PROFILE(SMBgetattrE);
+
+ if (req->wct < 1) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBgetattrE);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
+
+ if(!fsp || (fsp->conn != conn)) {
+ reply_doserror(req, ERRDOS, ERRbadfid);
+ END_PROFILE(SMBgetattrE);
+ return;
+ }
+
+ /* Do an fstat on this file */
+ if(fsp_stat(fsp, &sbuf)) {
+ reply_unixerror(req, ERRDOS, ERRnoaccess);
+ END_PROFILE(SMBgetattrE);
+ return;
+ }
+
+ 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.
+ */
+
+ reply_outbuf(req, 11, 0);
+
+ create_ts = get_create_timespec(&sbuf,
+ lp_fake_dir_create_times(SNUM(conn)));
+ srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
+ srv_put_dos_date2((char *)req->outbuf, smb_vwv2, sbuf.st_atime);
+ /* Should we check pending modtime here ? JRA */
+ srv_put_dos_date2((char *)req->outbuf, smb_vwv4, sbuf.st_mtime);
+
+ if (mode & aDIR) {
+ SIVAL(req->outbuf, smb_vwv6, 0);
+ SIVAL(req->outbuf, smb_vwv8, 0);
+ } else {
+ uint32 allocation_size = get_allocation_size(conn,fsp, &sbuf);
+ SIVAL(req->outbuf, smb_vwv6, (uint32)sbuf.st_size);
+ SIVAL(req->outbuf, smb_vwv8, allocation_size);
+ }
+ SSVAL(req->outbuf,smb_vwv10, mode);
+
+ DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
+
+ END_PROFILE(SMBgetattrE);
+ return;
+}
diff --git a/source3/smbd/seal.c b/source3/smbd/seal.c
new file mode 100644
index 0000000000..e9dc46aa3c
--- /dev/null
+++ b/source3/smbd/seal.c
@@ -0,0 +1,742 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Transport encryption (sealing) code - server code.
+ Copyright (C) Jeremy Allison 2007.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/******************************************************************************
+ Server side encryption.
+******************************************************************************/
+
+/******************************************************************************
+ Global server state.
+******************************************************************************/
+
+struct smb_srv_trans_enc_ctx {
+ struct smb_trans_enc_state *es;
+ AUTH_NTLMSSP_STATE *auth_ntlmssp_state; /* Must be kept in sync with pointer in ec->ntlmssp_state. */
+};
+
+static struct smb_srv_trans_enc_ctx *partial_srv_trans_enc_ctx;
+static struct smb_srv_trans_enc_ctx *srv_trans_enc_ctx;
+
+/******************************************************************************
+ Return global enc context - this must change if we ever do multiple contexts.
+******************************************************************************/
+
+uint16_t srv_enc_ctx(void)
+{
+ return srv_trans_enc_ctx->es->enc_ctx_num;
+}
+
+/******************************************************************************
+ Is this an incoming encrypted packet ?
+******************************************************************************/
+
+bool is_encrypted_packet(const uint8_t *inbuf)
+{
+ NTSTATUS status;
+ uint16_t enc_num;
+
+ /* Ignore non-session messages or non 0xFF'E' messages. */
+ if(CVAL(inbuf,0) || !(inbuf[4] == 0xFF && inbuf[5] == 'E')) {
+ return false;
+ }
+
+ status = get_enc_ctx_num(inbuf, &enc_num);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ /* Encrypted messages are 0xFF'E'<ctx> */
+ if (srv_trans_enc_ctx && enc_num == srv_enc_ctx()) {
+ return true;
+ }
+ return false;
+}
+
+/******************************************************************************
+ Create an auth_ntlmssp_state and ensure pointer copy is correct.
+******************************************************************************/
+
+static NTSTATUS make_auth_ntlmssp(struct smb_srv_trans_enc_ctx *ec)
+{
+ NTSTATUS status = auth_ntlmssp_start(&ec->auth_ntlmssp_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return nt_status_squash(status);
+ }
+
+ /*
+ * We must remember to update the pointer copy for the common
+ * functions after any auth_ntlmssp_start/auth_ntlmssp_end.
+ */
+ ec->es->s.ntlmssp_state = ec->auth_ntlmssp_state->ntlmssp_state;
+ return status;
+}
+
+/******************************************************************************
+ Destroy an auth_ntlmssp_state and ensure pointer copy is correct.
+******************************************************************************/
+
+static void destroy_auth_ntlmssp(struct smb_srv_trans_enc_ctx *ec)
+{
+ /*
+ * We must remember to update the pointer copy for the common
+ * functions after any auth_ntlmssp_start/auth_ntlmssp_end.
+ */
+
+ if (ec->auth_ntlmssp_state) {
+ auth_ntlmssp_end(&ec->auth_ntlmssp_state);
+ /* The auth_ntlmssp_end killed this already. */
+ ec->es->s.ntlmssp_state = NULL;
+ }
+}
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+
+/******************************************************************************
+ Import a name.
+******************************************************************************/
+
+static NTSTATUS get_srv_gss_creds(const char *service,
+ const char *name,
+ gss_cred_usage_t cred_type,
+ gss_cred_id_t *p_srv_cred)
+{
+ OM_uint32 ret;
+ OM_uint32 min;
+ gss_name_t srv_name;
+ gss_buffer_desc input_name;
+ char *host_princ_s = NULL;
+ NTSTATUS status = NT_STATUS_OK;
+
+ gss_OID_desc nt_hostbased_service =
+ {10, CONST_DISCARD(char *,"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04")};
+
+ asprintf(&host_princ_s, "%s@%s", service, name);
+ if (host_princ_s == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ input_name.value = host_princ_s;
+ input_name.length = strlen(host_princ_s) + 1;
+
+ ret = gss_import_name(&min,
+ &input_name,
+ &nt_hostbased_service,
+ &srv_name);
+
+ DEBUG(10,("get_srv_gss_creds: imported name %s\n",
+ host_princ_s ));
+
+ if (ret != GSS_S_COMPLETE) {
+ SAFE_FREE(host_princ_s);
+ return map_nt_error_from_gss(ret, min);
+ }
+
+ /*
+ * We're accessing the krb5.keytab file here.
+ * ensure we have permissions to do so.
+ */
+ become_root();
+
+ ret = gss_acquire_cred(&min,
+ srv_name,
+ GSS_C_INDEFINITE,
+ GSS_C_NULL_OID_SET,
+ cred_type,
+ p_srv_cred,
+ NULL,
+ NULL);
+ unbecome_root();
+
+ if (ret != GSS_S_COMPLETE) {
+ ADS_STATUS adss = ADS_ERROR_GSS(ret, min);
+ DEBUG(10,("get_srv_gss_creds: gss_acquire_cred failed with %s\n",
+ ads_errstr(adss)));
+ status = map_nt_error_from_gss(ret, min);
+ }
+
+ SAFE_FREE(host_princ_s);
+ gss_release_name(&min, &srv_name);
+ return status;
+}
+
+/******************************************************************************
+ Create a gss state.
+ Try and get the cifs/server@realm principal first, then fall back to
+ host/server@realm.
+******************************************************************************/
+
+static NTSTATUS make_auth_gss(struct smb_srv_trans_enc_ctx *ec)
+{
+ NTSTATUS status;
+ gss_cred_id_t srv_cred;
+ fstring fqdn;
+
+ name_to_fqdn(fqdn, global_myname());
+ strlower_m(fqdn);
+
+ status = get_srv_gss_creds("cifs", fqdn, GSS_C_ACCEPT, &srv_cred);
+ if (!NT_STATUS_IS_OK(status)) {
+ status = get_srv_gss_creds("host", fqdn, GSS_C_ACCEPT, &srv_cred);
+ if (!NT_STATUS_IS_OK(status)) {
+ return nt_status_squash(status);
+ }
+ }
+
+ ec->es->s.gss_state = SMB_MALLOC_P(struct smb_tran_enc_state_gss);
+ if (!ec->es->s.gss_state) {
+ OM_uint32 min;
+ gss_release_cred(&min, &srv_cred);
+ return NT_STATUS_NO_MEMORY;
+ }
+ ZERO_STRUCTP(ec->es->s.gss_state);
+ ec->es->s.gss_state->creds = srv_cred;
+
+ /* No context yet. */
+ ec->es->s.gss_state->gss_ctx = GSS_C_NO_CONTEXT;
+
+ return NT_STATUS_OK;
+}
+#endif
+
+/******************************************************************************
+ Shutdown a server encryption context.
+******************************************************************************/
+
+static void srv_free_encryption_context(struct smb_srv_trans_enc_ctx **pp_ec)
+{
+ struct smb_srv_trans_enc_ctx *ec = *pp_ec;
+
+ if (!ec) {
+ return;
+ }
+
+ if (ec->es) {
+ switch (ec->es->smb_enc_type) {
+ case SMB_TRANS_ENC_NTLM:
+ destroy_auth_ntlmssp(ec);
+ break;
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+ case SMB_TRANS_ENC_GSS:
+ break;
+#endif
+ }
+ common_free_encryption_state(&ec->es);
+ }
+
+ SAFE_FREE(ec);
+ *pp_ec = NULL;
+}
+
+/******************************************************************************
+ Create a server encryption context.
+******************************************************************************/
+
+static NTSTATUS make_srv_encryption_context(enum smb_trans_enc_type smb_enc_type, struct smb_srv_trans_enc_ctx **pp_ec)
+{
+ struct smb_srv_trans_enc_ctx *ec;
+
+ *pp_ec = NULL;
+
+ ec = SMB_MALLOC_P(struct smb_srv_trans_enc_ctx);
+ if (!ec) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ ZERO_STRUCTP(partial_srv_trans_enc_ctx);
+ ec->es = SMB_MALLOC_P(struct smb_trans_enc_state);
+ if (!ec->es) {
+ SAFE_FREE(ec);
+ return NT_STATUS_NO_MEMORY;
+ }
+ ZERO_STRUCTP(ec->es);
+ ec->es->smb_enc_type = smb_enc_type;
+ switch (smb_enc_type) {
+ case SMB_TRANS_ENC_NTLM:
+ {
+ NTSTATUS status = make_auth_ntlmssp(ec);
+ if (!NT_STATUS_IS_OK(status)) {
+ srv_free_encryption_context(&ec);
+ return status;
+ }
+ }
+ break;
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+ case SMB_TRANS_ENC_GSS:
+ /* Acquire our credentials by calling gss_acquire_cred here. */
+ {
+ NTSTATUS status = make_auth_gss(ec);
+ if (!NT_STATUS_IS_OK(status)) {
+ srv_free_encryption_context(&ec);
+ return status;
+ }
+ }
+ break;
+#endif
+ default:
+ srv_free_encryption_context(&ec);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ *pp_ec = ec;
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Free an encryption-allocated buffer.
+******************************************************************************/
+
+void srv_free_enc_buffer(char *buf)
+{
+ /* We know this is an smb buffer, and we
+ * didn't malloc, only copy, for a keepalive,
+ * so ignore non-session messages. */
+
+ if(CVAL(buf,0)) {
+ return;
+ }
+
+ if (srv_trans_enc_ctx) {
+ common_free_enc_buffer(srv_trans_enc_ctx->es, buf);
+ }
+}
+
+/******************************************************************************
+ Decrypt an incoming buffer.
+******************************************************************************/
+
+NTSTATUS srv_decrypt_buffer(char *buf)
+{
+ /* Ignore non-session messages. */
+ if(CVAL(buf,0)) {
+ return NT_STATUS_OK;
+ }
+
+ if (srv_trans_enc_ctx) {
+ return common_decrypt_buffer(srv_trans_enc_ctx->es, buf);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Encrypt an outgoing buffer. Return the encrypted pointer in buf_out.
+******************************************************************************/
+
+NTSTATUS srv_encrypt_buffer(char *buf, char **buf_out)
+{
+ *buf_out = buf;
+
+ /* Ignore non-session messages. */
+ if(CVAL(buf,0)) {
+ return NT_STATUS_OK;
+ }
+
+ if (srv_trans_enc_ctx) {
+ return common_encrypt_buffer(srv_trans_enc_ctx->es, buf, buf_out);
+ }
+ /* Not encrypting. */
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Do the gss encryption negotiation. Parameters are in/out.
+ Until success we do everything on the partial enc ctx.
+******************************************************************************/
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+static NTSTATUS srv_enc_spnego_gss_negotiate(unsigned char **ppdata, size_t *p_data_size, DATA_BLOB secblob)
+{
+ OM_uint32 ret;
+ OM_uint32 min;
+ OM_uint32 flags = 0;
+ gss_buffer_desc in_buf, out_buf;
+ struct smb_tran_enc_state_gss *gss_state;
+ DATA_BLOB auth_reply = data_blob_null;
+ DATA_BLOB response = data_blob_null;
+ NTSTATUS status;
+
+ if (!partial_srv_trans_enc_ctx) {
+ status = make_srv_encryption_context(SMB_TRANS_ENC_GSS, &partial_srv_trans_enc_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ gss_state = partial_srv_trans_enc_ctx->es->s.gss_state;
+
+ in_buf.value = secblob.data;
+ in_buf.length = secblob.length;
+
+ out_buf.value = NULL;
+ out_buf.length = 0;
+
+ become_root();
+
+ ret = gss_accept_sec_context(&min,
+ &gss_state->gss_ctx,
+ gss_state->creds,
+ &in_buf,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ NULL,
+ NULL, /* Ignore oids. */
+ &out_buf, /* To return. */
+ &flags,
+ NULL, /* Ingore time. */
+ NULL); /* Ignore delegated creds. */
+ unbecome_root();
+
+ status = gss_err_to_ntstatus(ret, min);
+ if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) {
+ return status;
+ }
+
+ /* Ensure we've got sign+seal available. */
+ if (ret == GSS_S_COMPLETE) {
+ if ((flags & (GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG|GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)) !=
+ (GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG|GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)) {
+ DEBUG(0,("srv_enc_spnego_gss_negotiate: quality of service not good enough "
+ "for SMB sealing.\n"));
+ gss_release_buffer(&min, &out_buf);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ auth_reply = data_blob(out_buf.value, out_buf.length);
+ gss_release_buffer(&min, &out_buf);
+
+ /* Wrap in SPNEGO. */
+ response = spnego_gen_auth_response(&auth_reply, status, OID_KERBEROS5);
+ data_blob_free(&auth_reply);
+
+ SAFE_FREE(*ppdata);
+ *ppdata = response.data;
+ *p_data_size = response.length;
+
+ return status;
+}
+#endif
+
+/******************************************************************************
+ Do the NTLM SPNEGO (or raw) encryption negotiation. Parameters are in/out.
+ Until success we do everything on the partial enc ctx.
+******************************************************************************/
+
+static NTSTATUS srv_enc_ntlm_negotiate(unsigned char **ppdata, size_t *p_data_size, DATA_BLOB secblob, bool spnego_wrap)
+{
+ NTSTATUS status;
+ DATA_BLOB chal = data_blob_null;
+ DATA_BLOB response = data_blob_null;
+
+ status = make_srv_encryption_context(SMB_TRANS_ENC_NTLM, &partial_srv_trans_enc_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = auth_ntlmssp_update(partial_srv_trans_enc_ctx->auth_ntlmssp_state, secblob, &chal);
+
+ /* status here should be NT_STATUS_MORE_PROCESSING_REQUIRED
+ * for success ... */
+
+ if (spnego_wrap) {
+ response = spnego_gen_auth_response(&chal, status, OID_NTLMSSP);
+ data_blob_free(&chal);
+ } else {
+ /* Return the raw blob. */
+ response = chal;
+ }
+
+ SAFE_FREE(*ppdata);
+ *ppdata = response.data;
+ *p_data_size = response.length;
+ return status;
+}
+
+/******************************************************************************
+ Do the SPNEGO encryption negotiation. Parameters are in/out.
+ Based off code in smbd/sesssionsetup.c
+ Until success we do everything on the partial enc ctx.
+******************************************************************************/
+
+static NTSTATUS srv_enc_spnego_negotiate(connection_struct *conn,
+ unsigned char **ppdata,
+ size_t *p_data_size,
+ unsigned char **pparam,
+ size_t *p_param_size)
+{
+ NTSTATUS status;
+ DATA_BLOB blob = data_blob_null;
+ DATA_BLOB secblob = data_blob_null;
+ char *kerb_mech = NULL;
+
+ blob = data_blob_const(*ppdata, *p_data_size);
+
+ status = parse_spnego_mechanisms(blob, &secblob, &kerb_mech);
+ if (!NT_STATUS_IS_OK(status)) {
+ return nt_status_squash(status);
+ }
+
+ /* We should have no partial context at this point. */
+
+ srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+
+ if (kerb_mech) {
+ SAFE_FREE(kerb_mech);
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+ status = srv_enc_spnego_gss_negotiate(ppdata, p_data_size, secblob);
+#else
+ /* Currently we don't SPNEGO negotiate
+ * back to NTLMSSP as we do in sessionsetupX. We should... */
+ return NT_STATUS_LOGON_FAILURE;
+#endif
+ } else {
+ status = srv_enc_ntlm_negotiate(ppdata, p_data_size, secblob, true);
+ }
+
+ data_blob_free(&secblob);
+
+ if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
+ srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+ return nt_status_squash(status);
+ }
+
+ if (NT_STATUS_IS_OK(status)) {
+ /* Return the context we're using for this encryption state. */
+ if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ SSVAL(*pparam,0,partial_srv_trans_enc_ctx->es->enc_ctx_num);
+ *p_param_size = 2;
+ }
+
+ return status;
+}
+
+/******************************************************************************
+ Complete a SPNEGO encryption negotiation. Parameters are in/out.
+ We only get this for a NTLM auth second stage.
+******************************************************************************/
+
+static NTSTATUS srv_enc_spnego_ntlm_auth(connection_struct *conn,
+ unsigned char **ppdata,
+ size_t *p_data_size,
+ unsigned char **pparam,
+ size_t *p_param_size)
+{
+ NTSTATUS status;
+ DATA_BLOB blob = data_blob_null;
+ DATA_BLOB auth = data_blob_null;
+ DATA_BLOB auth_reply = data_blob_null;
+ DATA_BLOB response = data_blob_null;
+ struct smb_srv_trans_enc_ctx *ec = partial_srv_trans_enc_ctx;
+
+ /* We must have a partial context here. */
+
+ if (!ec || !ec->es || ec->auth_ntlmssp_state == NULL || ec->es->smb_enc_type != SMB_TRANS_ENC_NTLM) {
+ srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ blob = data_blob_const(*ppdata, *p_data_size);
+ if (!spnego_parse_auth(blob, &auth)) {
+ srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = auth_ntlmssp_update(ec->auth_ntlmssp_state, auth, &auth_reply);
+ data_blob_free(&auth);
+
+ /* From RFC4178.
+ *
+ * supportedMech
+ *
+ * This field SHALL only be present in the first reply from the
+ * target.
+ * So set mechOID to NULL here.
+ */
+
+ response = spnego_gen_auth_response(&auth_reply, status, NULL);
+ data_blob_free(&auth_reply);
+
+ if (NT_STATUS_IS_OK(status)) {
+ /* Return the context we're using for this encryption state. */
+ if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ SSVAL(*pparam,0,ec->es->enc_ctx_num);
+ *p_param_size = 2;
+ }
+
+ SAFE_FREE(*ppdata);
+ *ppdata = response.data;
+ *p_data_size = response.length;
+ return status;
+}
+
+/******************************************************************************
+ Raw NTLM encryption negotiation. Parameters are in/out.
+ This function does both steps.
+******************************************************************************/
+
+static NTSTATUS srv_enc_raw_ntlm_auth(connection_struct *conn,
+ unsigned char **ppdata,
+ size_t *p_data_size,
+ unsigned char **pparam,
+ size_t *p_param_size)
+{
+ NTSTATUS status;
+ DATA_BLOB blob = data_blob_const(*ppdata, *p_data_size);
+ DATA_BLOB response = data_blob_null;
+ struct smb_srv_trans_enc_ctx *ec;
+
+ if (!partial_srv_trans_enc_ctx) {
+ /* This is the initial step. */
+ status = srv_enc_ntlm_negotiate(ppdata, p_data_size, blob, false);
+ if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
+ srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+ return nt_status_squash(status);
+ }
+ return status;
+ }
+
+ ec = partial_srv_trans_enc_ctx;
+ if (!ec || !ec->es || ec->auth_ntlmssp_state == NULL || ec->es->smb_enc_type != SMB_TRANS_ENC_NTLM) {
+ srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Second step. */
+ status = auth_ntlmssp_update(partial_srv_trans_enc_ctx->auth_ntlmssp_state, blob, &response);
+
+ if (NT_STATUS_IS_OK(status)) {
+ /* Return the context we're using for this encryption state. */
+ if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ SSVAL(*pparam,0,ec->es->enc_ctx_num);
+ *p_param_size = 2;
+ }
+
+ /* Return the raw blob. */
+ SAFE_FREE(*ppdata);
+ *ppdata = response.data;
+ *p_data_size = response.length;
+ return status;
+}
+
+/******************************************************************************
+ Do the SPNEGO encryption negotiation. Parameters are in/out.
+******************************************************************************/
+
+NTSTATUS srv_request_encryption_setup(connection_struct *conn,
+ unsigned char **ppdata,
+ size_t *p_data_size,
+ unsigned char **pparam,
+ size_t *p_param_size)
+{
+ unsigned char *pdata = *ppdata;
+
+ SAFE_FREE(*pparam);
+ *p_param_size = 0;
+
+ if (*p_data_size < 1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (pdata[0] == ASN1_APPLICATION(0)) {
+ /* its a negTokenTarg packet */
+ return srv_enc_spnego_negotiate(conn, ppdata, p_data_size, pparam, p_param_size);
+ }
+
+ if (pdata[0] == ASN1_CONTEXT(1)) {
+ /* It's an auth packet */
+ return srv_enc_spnego_ntlm_auth(conn, ppdata, p_data_size, pparam, p_param_size);
+ }
+
+ /* Maybe it's a raw unwrapped auth ? */
+ if (*p_data_size < 7) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (strncmp((char *)pdata, "NTLMSSP", 7) == 0) {
+ return srv_enc_raw_ntlm_auth(conn, ppdata, p_data_size, pparam, p_param_size);
+ }
+
+ DEBUG(1,("srv_request_encryption_setup: Unknown packet\n"));
+
+ return NT_STATUS_LOGON_FAILURE;
+}
+
+/******************************************************************************
+ Negotiation was successful - turn on server-side encryption.
+******************************************************************************/
+
+static NTSTATUS check_enc_good(struct smb_srv_trans_enc_ctx *ec)
+{
+ if (!ec || !ec->es) {
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ if (ec->es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
+ if ((ec->es->s.ntlmssp_state->neg_flags & (NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_SEAL)) !=
+ (NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_SEAL)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+ /* Todo - check gssapi case. */
+
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Negotiation was successful - turn on server-side encryption.
+******************************************************************************/
+
+NTSTATUS srv_encryption_start(connection_struct *conn)
+{
+ NTSTATUS status;
+
+ /* Check that we are really doing sign+seal. */
+ status = check_enc_good(partial_srv_trans_enc_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ /* Throw away the context we're using currently (if any). */
+ srv_free_encryption_context(&srv_trans_enc_ctx);
+
+ /* Steal the partial pointer. Deliberate shallow copy. */
+ srv_trans_enc_ctx = partial_srv_trans_enc_ctx;
+ srv_trans_enc_ctx->es->enc_on = true;
+
+ partial_srv_trans_enc_ctx = NULL;
+
+ DEBUG(1,("srv_encryption_start: context negotiated\n"));
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Shutdown all server contexts.
+******************************************************************************/
+
+void server_encryption_shutdown(void)
+{
+ srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+ srv_free_encryption_context(&srv_trans_enc_ctx);
+}
diff --git a/source3/smbd/sec_ctx.c b/source3/smbd/sec_ctx.c
new file mode 100644
index 0000000000..a618f06e6b
--- /dev/null
+++ b/source3/smbd/sec_ctx.c
@@ -0,0 +1,476 @@
+/*
+ Unix SMB/CIFS implementation.
+ uid/user handling
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern struct current_user current_user;
+
+struct sec_ctx {
+ UNIX_USER_TOKEN ut;
+ NT_USER_TOKEN *token;
+};
+
+/* A stack of security contexts. We include the current context as being
+ the first one, so there is room for another MAX_SEC_CTX_DEPTH more. */
+
+static struct sec_ctx sec_ctx_stack[MAX_SEC_CTX_DEPTH + 1];
+static int sec_ctx_stack_ndx;
+
+/****************************************************************************
+ Are two UNIX tokens equal ?
+****************************************************************************/
+
+bool unix_token_equal(const UNIX_USER_TOKEN *t1, const UNIX_USER_TOKEN *t2)
+{
+ if (t1->uid != t2->uid || t1->gid != t2->gid ||
+ t1->ngroups != t2->ngroups) {
+ return false;
+ }
+ if (memcmp(t1->groups, t2->groups,
+ t1->ngroups*sizeof(gid_t)) != 0) {
+ return false;
+ }
+ return true;
+}
+
+/****************************************************************************
+ Become the specified uid.
+****************************************************************************/
+
+static bool become_uid(uid_t uid)
+{
+ /* Check for dodgy uid values */
+
+ if (uid == (uid_t)-1 ||
+ ((sizeof(uid_t) == 2) && (uid == (uid_t)65535))) {
+ static int done;
+
+ if (!done) {
+ DEBUG(1,("WARNING: using uid %d is a security risk\n",
+ (int)uid));
+ done = 1;
+ }
+ }
+
+ /* Set effective user id */
+
+ set_effective_uid(uid);
+
+ DO_PROFILE_INC(uid_changes);
+ return True;
+}
+
+/****************************************************************************
+ Become the specified gid.
+****************************************************************************/
+
+static bool become_gid(gid_t gid)
+{
+ /* Check for dodgy gid values */
+
+ if (gid == (gid_t)-1 || ((sizeof(gid_t) == 2) &&
+ (gid == (gid_t)65535))) {
+ static int done;
+
+ if (!done) {
+ DEBUG(1,("WARNING: using gid %d is a security risk\n",
+ (int)gid));
+ done = 1;
+ }
+ }
+
+ /* Set effective group id */
+
+ set_effective_gid(gid);
+ return True;
+}
+
+/****************************************************************************
+ Become the specified uid and gid.
+****************************************************************************/
+
+static bool become_id(uid_t uid, gid_t gid)
+{
+ return become_gid(gid) && become_uid(uid);
+}
+
+/****************************************************************************
+ Drop back to root privileges in order to change to another user.
+****************************************************************************/
+
+static void gain_root(void)
+{
+ if (non_root_mode()) {
+ return;
+ }
+
+ if (geteuid() != 0) {
+ set_effective_uid(0);
+
+ if (geteuid() != 0) {
+ DEBUG(0,
+ ("Warning: You appear to have a trapdoor "
+ "uid system\n"));
+ }
+ }
+
+ if (getegid() != 0) {
+ set_effective_gid(0);
+
+ if (getegid() != 0) {
+ DEBUG(0,
+ ("Warning: You appear to have a trapdoor "
+ "gid system\n"));
+ }
+ }
+}
+
+/****************************************************************************
+ Get the list of current groups.
+****************************************************************************/
+
+static int get_current_groups(gid_t gid, size_t *p_ngroups, gid_t **p_groups)
+{
+ int i;
+ gid_t grp;
+ int ngroups;
+ gid_t *groups = NULL;
+
+ (*p_ngroups) = 0;
+ (*p_groups) = NULL;
+
+ /* this looks a little strange, but is needed to cope with
+ systems that put the current egid in the group list
+ returned from getgroups() (tridge) */
+ save_re_gid();
+ set_effective_gid(gid);
+ setgid(gid);
+
+ ngroups = sys_getgroups(0,&grp);
+ if (ngroups <= 0) {
+ goto fail;
+ }
+
+ if((groups = SMB_MALLOC_ARRAY(gid_t, ngroups+1)) == NULL) {
+ DEBUG(0,("setup_groups malloc fail !\n"));
+ goto fail;
+ }
+
+ if ((ngroups = sys_getgroups(ngroups,groups)) == -1) {
+ goto fail;
+ }
+
+ restore_re_gid();
+
+ (*p_ngroups) = ngroups;
+ (*p_groups) = groups;
+
+ DEBUG( 3, ( "get_current_groups: user is in %u groups: ", ngroups));
+ for (i = 0; i < ngroups; i++ ) {
+ DEBUG( 3, ( "%s%d", (i ? ", " : ""), (int)groups[i] ) );
+ }
+ DEBUG( 3, ( "\n" ) );
+
+ return ngroups;
+
+fail:
+ SAFE_FREE(groups);
+ restore_re_gid();
+ return -1;
+}
+
+/****************************************************************************
+ Create a new security context on the stack. It is the same as the old
+ one. User changes are done using the set_sec_ctx() function.
+****************************************************************************/
+
+bool push_sec_ctx(void)
+{
+ struct sec_ctx *ctx_p;
+
+ /* Check we don't overflow our stack */
+
+ if (sec_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
+ DEBUG(0, ("Security context stack overflow!\n"));
+ smb_panic("Security context stack overflow!");
+ }
+
+ /* Store previous user context */
+
+ sec_ctx_stack_ndx++;
+
+ ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
+
+ ctx_p->ut.uid = geteuid();
+ ctx_p->ut.gid = getegid();
+
+ DEBUG(3, ("push_sec_ctx(%u, %u) : sec_ctx_stack_ndx = %d\n",
+ (unsigned int)ctx_p->ut.uid, (unsigned int)ctx_p->ut.gid, sec_ctx_stack_ndx ));
+
+ ctx_p->token = dup_nt_token(NULL,
+ sec_ctx_stack[sec_ctx_stack_ndx-1].token);
+
+ ctx_p->ut.ngroups = sys_getgroups(0, NULL);
+
+ if (ctx_p->ut.ngroups != 0) {
+ if (!(ctx_p->ut.groups = SMB_MALLOC_ARRAY(gid_t, ctx_p->ut.ngroups))) {
+ DEBUG(0, ("Out of memory in push_sec_ctx()\n"));
+ TALLOC_FREE(ctx_p->token);
+ return False;
+ }
+
+ sys_getgroups(ctx_p->ut.ngroups, ctx_p->ut.groups);
+ } else {
+ ctx_p->ut.groups = NULL;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Change UNIX security context. Calls panic if not successful so no return value.
+****************************************************************************/
+
+#ifndef HAVE_DARWIN_INITGROUPS
+
+/* Normal credential switch path. */
+
+static void set_unix_security_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups)
+{
+ /* Start context switch */
+ gain_root();
+#ifdef HAVE_SETGROUPS
+ if (sys_setgroups(gid, ngroups, groups) != 0 && !non_root_mode()) {
+ smb_panic("sys_setgroups failed");
+ }
+#endif
+ become_id(uid, gid);
+ /* end context switch */
+}
+
+#else /* HAVE_DARWIN_INITGROUPS */
+
+/* The Darwin groups implementation is a little unusual. The list of
+* groups in the kernel credential is not exhaustive, but more like
+* a cache. The full group list is held in userspace and checked
+* dynamically.
+*
+* This is an optional mechanism, and setgroups(2) opts out
+* of it. That is, if you call setgroups, then the list of groups you
+* set are the only groups that are ever checked. This is not what we
+* want. We want to opt in to the dynamic resolution mechanism, so we
+* need to specify the uid of the user whose group list (cache) we are
+* setting.
+*
+* The Darwin rules are:
+* 1. Thou shalt setegid, initgroups and seteuid IN THAT ORDER
+* 2. Thou shalt not pass more that NGROUPS_MAX to initgroups
+* 3. Thou shalt leave the first entry in the groups list well alone
+*/
+
+#include <sys/syscall.h>
+
+static void set_unix_security_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups)
+{
+ int max = groups_max();
+
+ /* Start context switch */
+ gain_root();
+
+ become_gid(gid);
+
+
+ if (syscall(SYS_initgroups, (ngroups > max) ? max : ngroups,
+ groups, uid) == -1 && !non_root_mode()) {
+ DEBUG(0, ("WARNING: failed to set group list "
+ "(%d groups) for UID %ld: %s\n",
+ ngroups, uid, strerror(errno)));
+ smb_panic("sys_setgroups failed");
+ }
+
+ become_uid(uid);
+ /* end context switch */
+}
+
+#endif /* HAVE_DARWIN_INITGROUPS */
+
+/****************************************************************************
+ Set the current security context to a given user.
+****************************************************************************/
+
+void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN *token)
+{
+ struct sec_ctx *ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
+
+ /* Set the security context */
+
+ DEBUG(3, ("setting sec ctx (%u, %u) - sec_ctx_stack_ndx = %d\n",
+ (unsigned int)uid, (unsigned int)gid, sec_ctx_stack_ndx));
+
+ debug_nt_user_token(DBGC_CLASS, 5, token);
+ debug_unix_user_token(DBGC_CLASS, 5, uid, gid, ngroups, groups);
+
+ /* Change uid, gid and supplementary group list. */
+ set_unix_security_ctx(uid, gid, ngroups, groups);
+
+ ctx_p->ut.ngroups = ngroups;
+
+ SAFE_FREE(ctx_p->ut.groups);
+ if (token && (token == ctx_p->token)) {
+ smb_panic("DUPLICATE_TOKEN");
+ }
+
+ TALLOC_FREE(ctx_p->token);
+
+ if (ngroups) {
+ ctx_p->ut.groups = (gid_t *)memdup(groups,
+ sizeof(gid_t) * ngroups);
+ if (!ctx_p->ut.groups) {
+ smb_panic("memdup failed");
+ }
+ } else {
+ ctx_p->ut.groups = NULL;
+ }
+
+ if (token) {
+ ctx_p->token = dup_nt_token(NULL, token);
+ if (!ctx_p->token) {
+ smb_panic("dup_nt_token failed");
+ }
+ } else {
+ ctx_p->token = NULL;
+ }
+
+ ctx_p->ut.uid = uid;
+ ctx_p->ut.gid = gid;
+
+ /* Update current_user stuff */
+
+ current_user.ut.uid = uid;
+ current_user.ut.gid = gid;
+ current_user.ut.ngroups = ngroups;
+ current_user.ut.groups = groups;
+ current_user.nt_user_token = ctx_p->token;
+}
+
+/****************************************************************************
+ Become root context.
+****************************************************************************/
+
+void set_root_sec_ctx(void)
+{
+ /* May need to worry about supplementary groups at some stage */
+
+ set_sec_ctx(0, 0, 0, NULL, NULL);
+}
+
+/****************************************************************************
+ Pop a security context from the stack.
+****************************************************************************/
+
+bool pop_sec_ctx(void)
+{
+ struct sec_ctx *ctx_p;
+ struct sec_ctx *prev_ctx_p;
+
+ /* Check for stack underflow */
+
+ if (sec_ctx_stack_ndx == 0) {
+ DEBUG(0, ("Security context stack underflow!\n"));
+ smb_panic("Security context stack underflow!");
+ }
+
+ ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
+
+ /* Clear previous user info */
+
+ ctx_p->ut.uid = (uid_t)-1;
+ ctx_p->ut.gid = (gid_t)-1;
+
+ SAFE_FREE(ctx_p->ut.groups);
+ ctx_p->ut.ngroups = 0;
+
+ TALLOC_FREE(ctx_p->token);
+
+ /* Pop back previous user */
+
+ sec_ctx_stack_ndx--;
+
+ prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
+
+ /* Change uid, gid and supplementary group list. */
+ set_unix_security_ctx(prev_ctx_p->ut.uid,
+ prev_ctx_p->ut.gid,
+ prev_ctx_p->ut.ngroups,
+ prev_ctx_p->ut.groups);
+
+ /* Update current_user stuff */
+
+ current_user.ut.uid = prev_ctx_p->ut.uid;
+ current_user.ut.gid = prev_ctx_p->ut.gid;
+ current_user.ut.ngroups = prev_ctx_p->ut.ngroups;
+ current_user.ut.groups = prev_ctx_p->ut.groups;
+ current_user.nt_user_token = prev_ctx_p->token;
+
+ DEBUG(3, ("pop_sec_ctx (%u, %u) - sec_ctx_stack_ndx = %d\n",
+ (unsigned int)geteuid(), (unsigned int)getegid(), sec_ctx_stack_ndx));
+
+ return True;
+}
+
+/* Initialise the security context system */
+
+void init_sec_ctx(void)
+{
+ int i;
+ struct sec_ctx *ctx_p;
+
+ /* Initialise security context stack */
+
+ memset(sec_ctx_stack, 0, sizeof(struct sec_ctx) * MAX_SEC_CTX_DEPTH);
+
+ for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) {
+ sec_ctx_stack[i].ut.uid = (uid_t)-1;
+ sec_ctx_stack[i].ut.gid = (gid_t)-1;
+ }
+
+ /* Initialise first level of stack. It is the current context */
+ ctx_p = &sec_ctx_stack[0];
+
+ ctx_p->ut.uid = geteuid();
+ ctx_p->ut.gid = getegid();
+
+ get_current_groups(ctx_p->ut.gid, &ctx_p->ut.ngroups, &ctx_p->ut.groups);
+
+ ctx_p->token = NULL; /* Maps to guest user. */
+
+ /* Initialise current_user global */
+
+ current_user.ut.uid = ctx_p->ut.uid;
+ current_user.ut.gid = ctx_p->ut.gid;
+ current_user.ut.ngroups = ctx_p->ut.ngroups;
+ current_user.ut.groups = ctx_p->ut.groups;
+
+ /* The conn and vuid are usually taken care of by other modules.
+ We initialise them here. */
+
+ current_user.conn = NULL;
+ current_user.vuid = UID_FIELD_INVALID;
+ current_user.nt_user_token = NULL;
+}
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
new file mode 100644
index 0000000000..53116f3d98
--- /dev/null
+++ b/source3/smbd/server.c
@@ -0,0 +1,1471 @@
+/*
+ Unix SMB/CIFS implementation.
+ Main SMB server routines
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Martin Pool 2002
+ Copyright (C) Jelmer Vernooij 2002-2003
+ Copyright (C) Volker Lendecke 1993-2007
+ Copyright (C) Jeremy Allison 1993-2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static_decl_rpc;
+
+static int am_parent = 1;
+
+extern struct auth_context *negprot_global_auth_context;
+extern SIG_ATOMIC_T got_sig_term;
+extern SIG_ATOMIC_T reload_after_sighup;
+static SIG_ATOMIC_T got_sig_cld;
+
+#ifdef WITH_DFS
+extern int dcelogin_atmost_once;
+#endif /* WITH_DFS */
+
+/* really we should have a top level context structure that has the
+ client file descriptor as an element. That would require a major rewrite :(
+
+ the following 2 functions are an alternative - they make the file
+ descriptor private to smbd
+ */
+static int server_fd = -1;
+
+int smbd_server_fd(void)
+{
+ return server_fd;
+}
+
+static void smbd_set_server_fd(int fd)
+{
+ server_fd = fd;
+}
+
+int get_client_fd(void)
+{
+ return server_fd;
+}
+
+int client_get_tcp_info(struct sockaddr_in *server, struct sockaddr_in *client)
+{
+ socklen_t length;
+ if (server_fd == -1) {
+ return -1;
+ }
+ length = sizeof(*server);
+ if (getsockname(server_fd, (struct sockaddr *)server, &length) != 0) {
+ return -1;
+ }
+ length = sizeof(*client);
+ if (getpeername(server_fd, (struct sockaddr *)client, &length) != 0) {
+ return -1;
+ }
+ return 0;
+}
+
+struct event_context *smbd_event_context(void)
+{
+ static struct event_context *ctx;
+
+ if (!ctx && !(ctx = event_context_init(NULL))) {
+ smb_panic("Could not init smbd event context");
+ }
+ return ctx;
+}
+
+struct messaging_context *smbd_messaging_context(void)
+{
+ static struct messaging_context *ctx;
+
+ if (ctx == NULL) {
+ ctx = messaging_init(NULL, server_id_self(),
+ smbd_event_context());
+ }
+ if (ctx == NULL) {
+ DEBUG(0, ("Could not init smbd messaging context.\n"));
+ }
+ return ctx;
+}
+
+struct memcache *smbd_memcache(void)
+{
+ static struct memcache *cache;
+
+ if (!cache
+ && !(cache = memcache_init(NULL,
+ lp_max_stat_cache_size()*1024))) {
+
+ smb_panic("Could not init smbd memcache");
+ }
+ return cache;
+}
+
+/*******************************************************************
+ What to do when smb.conf is updated.
+ ********************************************************************/
+
+static void smb_conf_updated(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ DEBUG(10,("smb_conf_updated: Got message saying smb.conf was "
+ "updated. Reloading.\n"));
+ reload_services(False);
+}
+
+
+/*******************************************************************
+ Delete a statcache entry.
+ ********************************************************************/
+
+static void smb_stat_cache_delete(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_tnype,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ const char *name = (const char *)data->data;
+ DEBUG(10,("smb_stat_cache_delete: delete name %s\n", name));
+ stat_cache_delete(name);
+}
+
+/****************************************************************************
+ Terminate signal.
+****************************************************************************/
+
+static void sig_term(void)
+{
+ got_sig_term = 1;
+ sys_select_signal(SIGTERM);
+}
+
+/****************************************************************************
+ Catch a sighup.
+****************************************************************************/
+
+static void sig_hup(int sig)
+{
+ reload_after_sighup = 1;
+ sys_select_signal(SIGHUP);
+}
+
+/****************************************************************************
+ Catch a sigcld
+****************************************************************************/
+static void sig_cld(int sig)
+{
+ got_sig_cld = 1;
+ sys_select_signal(SIGCLD);
+}
+
+/****************************************************************************
+ Send a SIGTERM to our process group.
+*****************************************************************************/
+
+static void killkids(void)
+{
+ if(am_parent) kill(0,SIGTERM);
+}
+
+/****************************************************************************
+ Process a sam sync message - not sure whether to do this here or
+ somewhere else.
+****************************************************************************/
+
+static void msg_sam_sync(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ DEBUG(10, ("** sam sync message received, ignoring\n"));
+}
+
+
+/****************************************************************************
+ Open the socket communication - inetd.
+****************************************************************************/
+
+static bool open_sockets_inetd(void)
+{
+ /* Started from inetd. fd 0 is the socket. */
+ /* We will abort gracefully when the client or remote system
+ goes away */
+ smbd_set_server_fd(dup(0));
+
+ /* close our standard file descriptors */
+ close_low_fds(False); /* Don't close stderr */
+
+ set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
+ set_socket_options(smbd_server_fd(), lp_socket_options());
+
+ return True;
+}
+
+static void msg_exit_server(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ DEBUG(3, ("got a SHUTDOWN message\n"));
+ exit_server_cleanly(NULL);
+}
+
+#ifdef DEVELOPER
+static void msg_inject_fault(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ DATA_BLOB *data)
+{
+ int sig;
+
+ if (data->length != sizeof(sig)) {
+
+ DEBUG(0, ("Process %s sent bogus signal injection request\n",
+ procid_str_static(&src)));
+ return;
+ }
+
+ sig = *(int *)data->data;
+ if (sig == -1) {
+ exit_server("internal error injected");
+ return;
+ }
+
+#if HAVE_STRSIGNAL
+ DEBUG(0, ("Process %s requested injection of signal %d (%s)\n",
+ procid_str_static(&src), sig, strsignal(sig)));
+#else
+ DEBUG(0, ("Process %s requested injection of signal %d\n",
+ procid_str_static(&src), sig));
+#endif
+
+ kill(sys_getpid(), sig);
+}
+#endif /* DEVELOPER */
+
+struct child_pid {
+ struct child_pid *prev, *next;
+ pid_t pid;
+};
+
+static struct child_pid *children;
+static int num_children;
+
+static void add_child_pid(pid_t pid)
+{
+ struct child_pid *child;
+
+ if (lp_max_smbd_processes() == 0) {
+ /* Don't bother with the child list if we don't care anyway */
+ return;
+ }
+
+ child = SMB_MALLOC_P(struct child_pid);
+ if (child == NULL) {
+ DEBUG(0, ("Could not add child struct -- malloc failed\n"));
+ return;
+ }
+ child->pid = pid;
+ DLIST_ADD(children, child);
+ num_children += 1;
+}
+
+static void remove_child_pid(pid_t pid, bool unclean_shutdown)
+{
+ struct child_pid *child;
+
+ if (unclean_shutdown) {
+ /* a child terminated uncleanly so tickle all processes to see
+ if they can grab any of the pending locks
+ */
+ DEBUG(3,(__location__ " Unclean shutdown of pid %u\n", pid));
+ messaging_send_buf(smbd_messaging_context(), procid_self(),
+ MSG_SMB_BRL_VALIDATE, NULL, 0);
+ message_send_all(smbd_messaging_context(),
+ MSG_SMB_UNLOCK, NULL, 0, NULL);
+ }
+
+ if (lp_max_smbd_processes() == 0) {
+ /* Don't bother with the child list if we don't care anyway */
+ return;
+ }
+
+ for (child = children; child != NULL; child = child->next) {
+ if (child->pid == pid) {
+ struct child_pid *tmp = child;
+ DLIST_REMOVE(children, child);
+ SAFE_FREE(tmp);
+ num_children -= 1;
+ return;
+ }
+ }
+
+ DEBUG(0, ("Could not find child %d -- ignoring\n", (int)pid));
+}
+
+/****************************************************************************
+ Have we reached the process limit ?
+****************************************************************************/
+
+static bool allowable_number_of_smbd_processes(void)
+{
+ int max_processes = lp_max_smbd_processes();
+
+ if (!max_processes)
+ return True;
+
+ return num_children < max_processes;
+}
+
+/****************************************************************************
+ Open the socket communication.
+****************************************************************************/
+
+static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_ports)
+{
+ int num_interfaces = iface_count();
+ int num_sockets = 0;
+ int fd_listenset[FD_SETSIZE];
+ fd_set listen_set;
+ int s;
+ int maxfd = 0;
+ int i;
+ char *ports;
+ struct dns_reg_state * dns_reg = NULL;
+ unsigned dns_port = 0;
+
+ if (!is_daemon) {
+ return open_sockets_inetd();
+ }
+
+#ifdef HAVE_ATEXIT
+ {
+ static int atexit_set;
+ if(atexit_set == 0) {
+ atexit_set=1;
+ atexit(killkids);
+ }
+ }
+#endif
+
+ /* Stop zombies */
+ CatchSignal(SIGCLD, sig_cld);
+
+ FD_ZERO(&listen_set);
+
+ /* use a reasonable default set of ports - listing on 445 and 139 */
+ if (!smb_ports) {
+ ports = lp_smb_ports();
+ if (!ports || !*ports) {
+ ports = smb_xstrdup(SMB_PORTS);
+ } else {
+ ports = smb_xstrdup(ports);
+ }
+ } else {
+ ports = smb_xstrdup(smb_ports);
+ }
+
+ 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.
+ */
+
+ /* Now open a listen socket for each of the
+ interfaces. */
+ for(i = 0; i < num_interfaces; i++) {
+ TALLOC_CTX *frame = NULL;
+ const struct sockaddr_storage *ifss =
+ iface_n_sockaddr_storage(i);
+ char *tok;
+ const char *ptr;
+
+ if (ifss == NULL) {
+ DEBUG(0,("open_sockets_smbd: "
+ "interface %d has NULL IP address !\n",
+ i));
+ continue;
+ }
+
+ frame = talloc_stackframe();
+ for (ptr=ports;
+ next_token_talloc(frame,&ptr, &tok, " \t,");) {
+ unsigned port = atoi(tok);
+ if (port == 0 || port > 0xffff) {
+ continue;
+ }
+
+ /* Keep the first port for mDNS service
+ * registration.
+ */
+ if (dns_port == 0) {
+ dns_port = port;
+ }
+
+ s = fd_listenset[num_sockets] =
+ open_socket_in(SOCK_STREAM,
+ port,
+ num_sockets == 0 ? 0 : 2,
+ ifss,
+ true);
+ if(s == -1) {
+ continue;
+ }
+
+ /* ready to listen */
+ set_socket_options(s,"SO_KEEPALIVE");
+ set_socket_options(s,lp_socket_options());
+
+ /* Set server socket to
+ * non-blocking for the accept. */
+ set_blocking(s,False);
+
+ if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
+ DEBUG(0,("open_sockets_smbd: listen: "
+ "%s\n", strerror(errno)));
+ close(s);
+ TALLOC_FREE(frame);
+ return False;
+ }
+ FD_SET(s,&listen_set);
+ maxfd = MAX( maxfd, s);
+
+ num_sockets++;
+ if (num_sockets >= FD_SETSIZE) {
+ DEBUG(0,("open_sockets_smbd: Too "
+ "many sockets to bind to\n"));
+ TALLOC_FREE(frame);
+ return False;
+ }
+ }
+ TALLOC_FREE(frame);
+ }
+ } else {
+ /* Just bind to 0.0.0.0 - accept connections
+ from anywhere. */
+
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *tok;
+ const char *ptr;
+ const char *sock_addr = lp_socket_address();
+ char *sock_tok;
+ const char *sock_ptr;
+
+ if (sock_addr[0] == '\0' ||
+ strequal(sock_addr, "0.0.0.0") ||
+ strequal(sock_addr, "::")) {
+#if HAVE_IPV6
+ sock_addr = "::,0.0.0.0";
+#else
+ sock_addr = "0.0.0.0";
+#endif
+ }
+
+ for (sock_ptr=sock_addr;
+ next_token_talloc(frame, &sock_ptr, &sock_tok, " \t,"); ) {
+ for (ptr=ports; next_token_talloc(frame, &ptr, &tok, " \t,"); ) {
+ struct sockaddr_storage ss;
+
+ unsigned port = atoi(tok);
+ if (port == 0 || port > 0xffff) {
+ continue;
+ }
+
+ /* Keep the first port for mDNS service
+ * registration.
+ */
+ if (dns_port == 0) {
+ dns_port = port;
+ }
+
+ /* open an incoming socket */
+ if (!interpret_string_addr(&ss, sock_tok,
+ AI_NUMERICHOST|AI_PASSIVE)) {
+ continue;
+ }
+
+ s = open_socket_in(SOCK_STREAM,
+ port,
+ num_sockets == 0 ? 0 : 2,
+ &ss,
+ true);
+ if (s == -1) {
+ continue;
+ }
+
+ /* ready to listen */
+ set_socket_options(s,"SO_KEEPALIVE");
+ set_socket_options(s,lp_socket_options());
+
+ /* Set server socket to non-blocking
+ * for the accept. */
+ set_blocking(s,False);
+
+ if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
+ DEBUG(0,("open_sockets_smbd: "
+ "listen: %s\n",
+ strerror(errno)));
+ close(s);
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ fd_listenset[num_sockets] = s;
+ FD_SET(s,&listen_set);
+ maxfd = MAX( maxfd, s);
+
+ num_sockets++;
+
+ if (num_sockets >= FD_SETSIZE) {
+ DEBUG(0,("open_sockets_smbd: Too "
+ "many sockets to bind to\n"));
+ TALLOC_FREE(frame);
+ return False;
+ }
+ }
+ }
+ TALLOC_FREE(frame);
+ }
+
+ SAFE_FREE(ports);
+
+ if (num_sockets == 0) {
+ DEBUG(0,("open_sockets_smbd: No "
+ "sockets available to bind to.\n"));
+ return false;
+ }
+
+ /* Setup the main smbd so that we can get messages. Note that
+ do this after starting listening. This is needed as when in
+ clustered mode, ctdb won't allow us to start doing database
+ operations until it has gone thru a full startup, which
+ includes checking to see that smbd is listening. */
+ claim_connection(NULL,"",
+ FLAG_MSG_GENERAL|FLAG_MSG_SMBD|FLAG_MSG_DBWRAP);
+
+ /* Listen to messages */
+
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_SMB_SAM_SYNC, msg_sam_sync);
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_SHUTDOWN, msg_exit_server);
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_SMB_FILE_RENAME, msg_file_was_renamed);
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_SMB_CONF_UPDATED, smb_conf_updated);
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_SMB_STAT_CACHE_DELETE, smb_stat_cache_delete);
+ brl_register_msgs(smbd_messaging_context());
+
+#ifdef CLUSTER_SUPPORT
+ if (lp_clustering()) {
+ ctdbd_register_reconfigure(messaging_ctdbd_connection());
+ }
+#endif
+
+#ifdef DEVELOPER
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_SMB_INJECT_FAULT, msg_inject_fault);
+#endif
+
+ /* now accept incoming connections - forking a new process
+ for each incoming connection */
+ DEBUG(2,("waiting for a connection\n"));
+ while (1) {
+ struct timeval now, idle_timeout;
+ fd_set r_fds, w_fds;
+ int num;
+
+ /* Ensure we respond to PING and DEBUG messages from the main smbd. */
+ message_dispatch(smbd_messaging_context());
+
+ if (got_sig_cld) {
+ pid_t pid;
+ int status;
+
+ got_sig_cld = False;
+
+ while ((pid = sys_waitpid(-1, &status, WNOHANG)) > 0) {
+ bool unclean_shutdown = False;
+
+ /* If the child terminated normally, assume
+ it was an unclean shutdown unless the
+ status is 0
+ */
+ if (WIFEXITED(status)) {
+ unclean_shutdown = WEXITSTATUS(status);
+ }
+ /* If the child terminated due to a signal
+ we always assume it was unclean.
+ */
+ if (WIFSIGNALED(status)) {
+ unclean_shutdown = True;
+ }
+ remove_child_pid(pid, unclean_shutdown);
+ }
+ }
+
+ idle_timeout = timeval_zero();
+
+ memcpy((char *)&r_fds, (char *)&listen_set,
+ sizeof(listen_set));
+ FD_ZERO(&w_fds);
+ GetTimeOfDay(&now);
+
+ /* Kick off our mDNS registration. */
+ if (dns_port != 0) {
+ dns_register_smbd(&dns_reg, dns_port, &maxfd,
+ &r_fds, &idle_timeout);
+ }
+
+ event_add_to_select_args(smbd_event_context(), &now,
+ &r_fds, &w_fds, &idle_timeout,
+ &maxfd);
+
+ num = sys_select(maxfd+1,&r_fds,&w_fds,NULL,
+ timeval_is_zero(&idle_timeout) ?
+ NULL : &idle_timeout);
+
+ if (num == -1 && errno == EINTR) {
+ if (got_sig_term) {
+ exit_server_cleanly(NULL);
+ }
+
+ /* check for sighup processing */
+ if (reload_after_sighup) {
+ change_to_root_user();
+ DEBUG(1,("Reloading services after SIGHUP\n"));
+ reload_services(False);
+ reload_after_sighup = 0;
+ }
+
+ continue;
+ }
+
+
+ /* If the idle timeout fired and we don't have any connected
+ * users, exit gracefully. We should be running under a process
+ * controller that will restart us if necessry.
+ */
+ if (num == 0 && count_all_current_connections() == 0) {
+ exit_server_cleanly("idle timeout");
+ }
+
+ /* process pending nDNS responses */
+ if (dns_register_smbd_reply(dns_reg, &r_fds, &idle_timeout)) {
+ --num;
+ }
+
+ if (run_events(smbd_event_context(), num, &r_fds, &w_fds)) {
+ continue;
+ }
+
+ /* check if we need to reload services */
+ check_reload(time(NULL));
+
+ /* Find the sockets that are read-ready -
+ accept on these. */
+ for( ; num > 0; num--) {
+ struct sockaddr addr;
+ socklen_t in_addrlen = sizeof(addr);
+ pid_t child = 0;
+
+ s = -1;
+ for(i = 0; i < num_sockets; i++) {
+ if(FD_ISSET(fd_listenset[i],&r_fds)) {
+ s = fd_listenset[i];
+ /* Clear this so we don't look
+ at it again. */
+ FD_CLR(fd_listenset[i],&r_fds);
+ break;
+ }
+ }
+
+ smbd_set_server_fd(accept(s,&addr,&in_addrlen));
+
+ if (smbd_server_fd() == -1 && errno == EINTR)
+ continue;
+
+ if (smbd_server_fd() == -1) {
+ DEBUG(2,("open_sockets_smbd: accept: %s\n",
+ strerror(errno)));
+ continue;
+ }
+
+ /* Ensure child is set to blocking mode */
+ set_blocking(smbd_server_fd(),True);
+
+ if (smbd_server_fd() != -1 && interactive)
+ return True;
+
+ if (allowable_number_of_smbd_processes() &&
+ smbd_server_fd() != -1 &&
+ ((child = sys_fork())==0)) {
+ char remaddr[INET6_ADDRSTRLEN];
+
+ /* Child code ... */
+
+ /* Stop zombies, the parent explicitly handles
+ * them, counting worker smbds. */
+ CatchChild();
+
+ /* close the listening socket(s) */
+ for(i = 0; i < num_sockets; i++)
+ close(fd_listenset[i]);
+
+ /* close our mDNS daemon handle */
+ dns_register_close(&dns_reg);
+
+ /* close our standard file
+ descriptors */
+ close_low_fds(False);
+ am_parent = 0;
+
+ set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
+ set_socket_options(smbd_server_fd(),
+ lp_socket_options());
+
+ /* this is needed so that we get decent entries
+ in smbstatus for port 445 connects */
+ set_remote_machine_name(get_peer_addr(smbd_server_fd(),
+ remaddr,
+ sizeof(remaddr)),
+ false);
+
+ if (!reinit_after_fork(
+ smbd_messaging_context(), true)) {
+ DEBUG(0,("reinit_after_fork() failed\n"));
+ smb_panic("reinit_after_fork() failed");
+ }
+
+ return True;
+ }
+ /* The parent doesn't need this socket */
+ close(smbd_server_fd());
+
+ /* Sun May 6 18:56:14 2001 ackley@cs.unm.edu:
+ Clear the closed fd info out of server_fd --
+ and more importantly, out of client_fd in
+ util_sock.c, to avoid a possible
+ getpeername failure if we reopen the logs
+ and use %I in the filename.
+ */
+
+ smbd_set_server_fd(-1);
+
+ if (child != 0) {
+ add_child_pid(child);
+ }
+
+ /* 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();
+
+ } /* end for num */
+ } /* end while 1 */
+
+/* NOTREACHED return True; */
+}
+
+/****************************************************************************
+ Reload printers
+**************************************************************************/
+void reload_printers(void)
+{
+ int snum;
+ int n_services = lp_numservices();
+ int pnum = lp_servicenumber(PRINTERS_NAME);
+ const char *pname;
+
+ pcap_cache_reload();
+
+ /* remove stale printers */
+ for (snum = 0; snum < n_services; snum++) {
+ /* avoid removing PRINTERS_NAME or non-autoloaded printers */
+ if (snum == pnum || !(lp_snum_ok(snum) && lp_print_ok(snum) &&
+ lp_autoloaded(snum)))
+ continue;
+
+ pname = lp_printername(snum);
+ if (!pcap_printername_ok(pname)) {
+ DEBUG(3, ("removing stale printer %s\n", pname));
+
+ if (is_printer_published(NULL, snum, NULL))
+ nt_printer_publish(NULL, snum, SPOOL_DS_UNPUBLISH);
+ del_a_printer(pname);
+ lp_killservice(snum);
+ }
+ }
+
+ load_printers();
+}
+
+/****************************************************************************
+ Reload the services file.
+**************************************************************************/
+
+bool reload_services(bool test)
+{
+ bool ret;
+
+ if (lp_loaded()) {
+ char *fname = lp_configfile();
+ if (file_exist(fname, NULL) &&
+ !strcsequal(fname, get_dyn_CONFIGFILE())) {
+ set_dyn_CONFIGFILE(fname);
+ test = False;
+ }
+ }
+
+ reopen_logs();
+
+ if (test && !lp_file_list_changed())
+ return(True);
+
+ lp_killunused(conn_snum_used);
+
+ ret = lp_load(get_dyn_CONFIGFILE(), False, False, True, True);
+
+ reload_printers();
+
+ /* perhaps the config filename is now set */
+ if (!test)
+ reload_services(True);
+
+ reopen_logs();
+
+ load_interfaces();
+
+ if (smbd_server_fd() != -1) {
+ set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
+ set_socket_options(smbd_server_fd(), lp_socket_options());
+ }
+
+ mangle_reset_cache();
+ reset_stat_cache();
+
+ /* this forces service parameters to be flushed */
+ set_current_service(NULL,0,True);
+
+ return(ret);
+}
+
+/****************************************************************************
+ Exit the server.
+****************************************************************************/
+
+/* Reasons for shutting down a server process. */
+enum server_exit_reason { SERVER_EXIT_NORMAL, SERVER_EXIT_ABNORMAL };
+
+static void exit_server_common(enum server_exit_reason how,
+ const char *const reason) NORETURN_ATTRIBUTE;
+
+static void exit_server_common(enum server_exit_reason how,
+ const char *const reason)
+{
+ static int firsttime=1;
+ bool had_open_conn;
+
+ if (!firsttime)
+ exit(0);
+ firsttime = 0;
+
+ change_to_root_user();
+
+ if (negprot_global_auth_context) {
+ (negprot_global_auth_context->free)(&negprot_global_auth_context);
+ }
+
+ had_open_conn = conn_close_all();
+
+ invalidate_all_vuids();
+
+ /* 3 second timeout. */
+ print_notify_send_messages(smbd_messaging_context(), 3);
+
+ /* delete our entry in the connections database. */
+ yield_connection(NULL,"");
+
+ respond_to_all_remaining_local_messages();
+
+#ifdef WITH_DFS
+ if (dcelogin_atmost_once) {
+ dfs_unlogin();
+ }
+#endif
+
+#ifdef USE_DMAPI
+ /* Destroy Samba DMAPI session only if we are master smbd process */
+ if (am_parent) {
+ if (!dmapi_destroy_session()) {
+ DEBUG(0,("Unable to close Samba DMAPI session\n"));
+ }
+ }
+#endif
+
+ locking_end();
+ printing_end();
+
+ if (how != SERVER_EXIT_NORMAL) {
+ int oldlevel = DEBUGLEVEL;
+
+ DEBUGLEVEL = 10;
+
+ DEBUGSEP(0);
+ DEBUG(0,("Abnormal server exit: %s\n",
+ reason ? reason : "no explanation provided"));
+ DEBUGSEP(0);
+
+ log_stack_trace();
+
+ DEBUGLEVEL = oldlevel;
+ dump_core();
+
+ } else {
+ DEBUG(3,("Server exit (%s)\n",
+ (reason ? reason : "normal exit")));
+ }
+
+ /* if we had any open SMB connections when we exited then we
+ need to tell the parent smbd so that it can trigger a retry
+ of any locks we may have been holding or open files we were
+ blocking */
+ if (had_open_conn) {
+ exit(1);
+ } else {
+ exit(0);
+ }
+}
+
+void exit_server(const char *const explanation)
+{
+ exit_server_common(SERVER_EXIT_ABNORMAL, explanation);
+}
+
+void exit_server_cleanly(const char *const explanation)
+{
+ exit_server_common(SERVER_EXIT_NORMAL, explanation);
+}
+
+void exit_server_fault(void)
+{
+ exit_server("critical server fault");
+}
+
+
+/****************************************************************************
+received when we should release a specific IP
+****************************************************************************/
+static void release_ip(const char *ip, void *priv)
+{
+ char addr[INET6_ADDRSTRLEN];
+
+ if (strcmp(client_socket_addr(get_client_fd(),addr,sizeof(addr)), ip) == 0) {
+ /* we can't afford to do a clean exit - that involves
+ database writes, which would potentially mean we
+ are still running after the failover has finished -
+ we have to get rid of this process ID straight
+ away */
+ DEBUG(0,("Got release IP message for our IP %s - exiting immediately\n",
+ ip));
+ /* note we must exit with non-zero status so the unclean handler gets
+ called in the parent, so that the brl database is tickled */
+ _exit(1);
+ }
+}
+
+static void msg_release_ip(struct messaging_context *msg_ctx, void *private_data,
+ uint32_t msg_type, struct server_id server_id, DATA_BLOB *data)
+{
+ release_ip((char *)data->data, NULL);
+}
+
+/****************************************************************************
+ Initialise connect, service and file structs.
+****************************************************************************/
+
+static bool init_structs(void )
+{
+ /*
+ * Set the machine NETBIOS name if not already
+ * set from the config file.
+ */
+
+ if (!init_names())
+ return False;
+
+ conn_init();
+
+ file_init();
+
+ /* for RPC pipes */
+ init_rpc_pipe_hnd();
+
+ init_dptrs();
+
+ if (!secrets_init())
+ return False;
+
+ return True;
+}
+
+/*
+ * Send keepalive packets to our client
+ */
+static bool keepalive_fn(const struct timeval *now, void *private_data)
+{
+ if (!send_keepalive(smbd_server_fd())) {
+ DEBUG( 2, ( "Keepalive failed - exiting.\n" ) );
+ return False;
+ }
+ return True;
+}
+
+/*
+ * Do the recurring check if we're idle
+ */
+static bool deadtime_fn(const struct timeval *now, void *private_data)
+{
+ if ((conn_num_open() == 0)
+ || (conn_idle_all(now->tv_sec))) {
+ DEBUG( 2, ( "Closing idle connection\n" ) );
+ messaging_send(smbd_messaging_context(), procid_self(),
+ MSG_SHUTDOWN, &data_blob_null);
+ return False;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+ main program.
+****************************************************************************/
+
+/* Declare prototype for build_options() to avoid having to run it through
+ mkproto.h. Mixing $(builddir) and $(srcdir) source files in the current
+ prototype generation system is too complicated. */
+
+extern void build_options(bool screen);
+
+ int main(int argc,const char *argv[])
+{
+ /* shall I run as a daemon */
+ static bool is_daemon = False;
+ static bool interactive = False;
+ static bool Fork = True;
+ static bool no_process_group = False;
+ static bool log_stdout = False;
+ static char *ports = NULL;
+ static char *profile_level = NULL;
+ int opt;
+ poptContext pc;
+ bool print_build_options = False;
+ enum {
+ OPT_DAEMON = 1000,
+ OPT_INTERACTIVE,
+ OPT_FORK,
+ OPT_NO_PROCESS_GROUP,
+ OPT_LOG_STDOUT
+ };
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"daemon", 'D', POPT_ARG_NONE, NULL, OPT_DAEMON, "Become a daemon (default)" },
+ {"interactive", 'i', POPT_ARG_NONE, NULL, OPT_INTERACTIVE, "Run interactive (not a daemon)"},
+ {"foreground", 'F', POPT_ARG_NONE, NULL, OPT_FORK, "Run daemon in foreground (for daemontools, etc.)" },
+ {"no-process-group", '\0', POPT_ARG_NONE, NULL, OPT_NO_PROCESS_GROUP, "Don't create a new process group" },
+ {"log-stdout", 'S', POPT_ARG_NONE, NULL, OPT_LOG_STDOUT, "Log to stdout" },
+ {"build-options", 'b', POPT_ARG_NONE, NULL, 'b', "Print build options" },
+ {"port", 'p', POPT_ARG_STRING, &ports, 0, "Listen on the specified ports"},
+ {"profiling-level", 'P', POPT_ARG_STRING, &profile_level, 0, "Set profiling level","PROFILE_LEVEL"},
+ POPT_COMMON_SAMBA
+ POPT_COMMON_DYNCONFIG
+ POPT_TABLEEND
+ };
+ TALLOC_CTX *frame = talloc_stackframe(); /* Setup tos. */
+
+ TimeInit();
+
+#ifdef HAVE_SET_AUTH_PARAMETERS
+ set_auth_parameters(argc,argv);
+#endif
+
+ pc = poptGetContext("smbd", argc, argv, long_options, 0);
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case OPT_DAEMON:
+ is_daemon = true;
+ break;
+ case OPT_INTERACTIVE:
+ interactive = true;
+ break;
+ case OPT_FORK:
+ Fork = false;
+ break;
+ case OPT_NO_PROCESS_GROUP:
+ no_process_group = true;
+ break;
+ case OPT_LOG_STDOUT:
+ log_stdout = true;
+ break;
+ case 'b':
+ print_build_options = True;
+ break;
+ default:
+ d_fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+ }
+ poptFreeContext(pc);
+
+ if (interactive) {
+ Fork = False;
+ log_stdout = True;
+ }
+
+ setup_logging(argv[0],log_stdout);
+
+ if (print_build_options) {
+ build_options(True); /* Display output to screen as well as debug */
+ exit(0);
+ }
+
+ load_case_tables();
+
+#ifdef HAVE_SETLUID
+ /* needed for SecureWare on SCO */
+ setluid(0);
+#endif
+
+ sec_init();
+
+ set_remote_machine_name("smbd", False);
+
+ if (interactive && (DEBUGLEVEL >= 9)) {
+ talloc_enable_leak_report();
+ }
+
+ if (log_stdout && Fork) {
+ DEBUG(0,("ERROR: Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n"));
+ exit(1);
+ }
+
+ /* we want to re-seed early to prevent time delays causing
+ client problems at a later date. (tridge) */
+ generate_random_buffer(NULL, 0);
+
+ /* make absolutely sure we run as root - to handle cases where people
+ are crazy enough to have it setuid */
+
+ gain_root_privilege();
+ gain_root_group_privilege();
+
+ fault_setup((void (*)(void *))exit_server_fault);
+ dump_core_setup("smbd");
+
+ CatchSignal(SIGTERM , SIGNAL_CAST sig_term);
+ CatchSignal(SIGHUP,SIGNAL_CAST sig_hup);
+
+ /* we are never interested in SIGPIPE */
+ BlockSignals(True,SIGPIPE);
+
+#if defined(SIGFPE)
+ /* we are never interested in SIGFPE */
+ BlockSignals(True,SIGFPE);
+#endif
+
+#if defined(SIGUSR2)
+ /* We are no longer interested in USR2 */
+ BlockSignals(True,SIGUSR2);
+#endif
+
+ /* POSIX demands that signals are inherited. If the invoking process has
+ * these signals masked, we will have problems, as we won't recieve them. */
+ BlockSignals(False, SIGHUP);
+ BlockSignals(False, SIGUSR1);
+ BlockSignals(False, SIGTERM);
+
+ /* we want total control over the permissions on created files,
+ so set our umask to 0 */
+ umask(0);
+
+ init_sec_ctx();
+
+ reopen_logs();
+
+ DEBUG(0,("smbd version %s started.\n", SAMBA_VERSION_STRING));
+ DEBUGADD(0,("%s\n", COPYRIGHT_STARTUP_MESSAGE));
+
+ DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n",
+ (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid()));
+
+ /* Output the build options to the debug log */
+ build_options(False);
+
+ if (sizeof(uint16) < 2 || sizeof(uint32) < 4) {
+ DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n"));
+ exit(1);
+ }
+
+ if (!lp_load_initial_only(get_dyn_CONFIGFILE())) {
+ DEBUG(0, ("error opening config file\n"));
+ exit(1);
+ }
+
+ if (smbd_messaging_context() == NULL)
+ exit(1);
+
+ if (!reload_services(False))
+ return(-1);
+
+ init_structs();
+
+#ifdef WITH_PROFILE
+ if (!profile_setup(smbd_messaging_context(), False)) {
+ DEBUG(0,("ERROR: failed to setup profiling\n"));
+ return -1;
+ }
+ if (profile_level != NULL) {
+ int pl = atoi(profile_level);
+ struct server_id src;
+
+ DEBUG(1, ("setting profiling level: %s\n",profile_level));
+ src.pid = getpid();
+ set_profile_level(pl, src);
+ }
+#endif
+
+ DEBUG(3,( "loaded services\n"));
+
+ if (!is_daemon && !is_a_socket(0)) {
+ if (!interactive)
+ DEBUG(0,("standard input is not a socket, assuming -D option\n"));
+
+ /*
+ * Setting is_daemon here prevents us from eventually calling
+ * the open_sockets_inetd()
+ */
+
+ is_daemon = True;
+ }
+
+ if (is_daemon && !interactive) {
+ DEBUG( 3, ( "Becoming a daemon.\n" ) );
+ become_daemon(Fork, no_process_group);
+ }
+
+#if HAVE_SETPGID
+ /*
+ * If we're interactive we want to set our own process group for
+ * signal management.
+ */
+ if (interactive && !no_process_group)
+ setpgid( (pid_t)0, (pid_t)0);
+#endif
+
+ if (!directory_exist(lp_lockdir(), NULL))
+ mkdir(lp_lockdir(), 0755);
+
+ if (is_daemon)
+ pidfile_create("smbd");
+
+ if (!reinit_after_fork(smbd_messaging_context(), false)) {
+ DEBUG(0,("reinit_after_fork() failed\n"));
+ exit(1);
+ }
+
+ /* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */
+
+ if (smbd_memcache() == NULL) {
+ exit(1);
+ }
+
+ memcache_set_global(smbd_memcache());
+
+ /* Initialise the password backed before the global_sam_sid
+ to ensure that we fetch from ldap before we make a domain sid up */
+
+ if(!initialize_password_db(False, smbd_event_context()))
+ exit(1);
+
+ if (!secrets_init()) {
+ DEBUG(0, ("ERROR: smbd can not open secrets.tdb\n"));
+ exit(1);
+ }
+
+ if(!get_global_sam_sid()) {
+ DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n"));
+ exit(1);
+ }
+
+ if (!session_init())
+ exit(1);
+
+ if (!connections_init(True))
+ exit(1);
+
+ if (!locking_init())
+ exit(1);
+
+ namecache_enable();
+
+ if (!W_ERROR_IS_OK(registry_init_full()))
+ exit(1);
+
+#if 0
+ if (!init_svcctl_db())
+ exit(1);
+#endif
+
+ if (!print_backend_init(smbd_messaging_context()))
+ exit(1);
+
+ if (!init_guest_info()) {
+ DEBUG(0,("ERROR: failed to setup guest info.\n"));
+ return -1;
+ }
+
+ /* only start the background queue daemon if we are
+ running as a daemon -- bad things will happen if
+ smbd is launched via inetd and we fork a copy of
+ ourselves here */
+
+ if (is_daemon && !interactive
+ && lp_parm_bool(-1, "smbd", "backgroundqueue", true)) {
+ start_background_queue();
+ }
+
+ if (!open_sockets_smbd(is_daemon, interactive, ports))
+ exit(1);
+
+ /*
+ * everything after this point is run after the fork()
+ */
+
+ static_init_rpc;
+
+ init_modules();
+
+ /* Possibly reload the services file. Only worth doing in
+ * daemon mode. In inetd mode, we know we only just loaded this.
+ */
+ if (is_daemon) {
+ reload_services(True);
+ }
+
+ if (!init_account_policy()) {
+ DEBUG(0,("Could not open account policy tdb.\n"));
+ exit(1);
+ }
+
+ if (*lp_rootdir()) {
+ if (sys_chroot(lp_rootdir()) == 0)
+ DEBUG(2,("Changed root to %s\n", lp_rootdir()));
+ }
+
+ /* Setup oplocks */
+ if (!init_oplocks(smbd_messaging_context()))
+ exit(1);
+
+ /* Setup aio signal handler. */
+ initialize_async_io_handler();
+
+ /* register our message handlers */
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_SMB_FORCE_TDIS, msg_force_tdis);
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_SMB_RELEASE_IP, msg_release_ip);
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_SMB_CLOSE_FILE, msg_close_file);
+
+ if ((lp_keepalive() != 0)
+ && !(event_add_idle(smbd_event_context(), NULL,
+ timeval_set(lp_keepalive(), 0),
+ "keepalive", keepalive_fn,
+ NULL))) {
+ DEBUG(0, ("Could not add keepalive event\n"));
+ exit(1);
+ }
+
+ if (!(event_add_idle(smbd_event_context(), NULL,
+ timeval_set(IDLE_CLOSED_TIMEOUT, 0),
+ "deadtime", deadtime_fn, NULL))) {
+ DEBUG(0, ("Could not add deadtime event\n"));
+ exit(1);
+ }
+
+#ifdef CLUSTER_SUPPORT
+
+ if (lp_clustering()) {
+ /*
+ * We need to tell ctdb about our client's TCP
+ * connection, so that for failover ctdbd can send
+ * tickle acks, triggering a reconnection by the
+ * client.
+ */
+
+ struct sockaddr_in srv, clnt;
+
+ if (client_get_tcp_info(&srv, &clnt) == 0) {
+
+ NTSTATUS status;
+
+ status = ctdbd_register_ips(
+ messaging_ctdbd_connection(),
+ &srv, &clnt, release_ip, NULL);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("ctdbd_register_ips failed: %s\n",
+ nt_errstr(status)));
+ }
+ } else
+ {
+ DEBUG(0,("Unable to get tcp info for "
+ "CTDB_CONTROL_TCP_CLIENT: %s\n",
+ strerror(errno)));
+ }
+ }
+
+#endif
+
+ TALLOC_FREE(frame);
+
+ smbd_process();
+
+ namecache_shutdown();
+
+ exit_server_cleanly(NULL);
+ return(0);
+}
diff --git a/source3/smbd/service.c b/source3/smbd/service.c
new file mode 100644
index 0000000000..0b851f1e48
--- /dev/null
+++ b/source3/smbd/service.c
@@ -0,0 +1,1353 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern userdom_struct current_user_info;
+
+static bool canonicalize_connect_path(connection_struct *conn)
+{
+#ifdef REALPATH_TAKES_NULL
+ bool ret;
+ char *resolved_name = SMB_VFS_REALPATH(conn,conn->connectpath,NULL);
+ if (!resolved_name) {
+ return false;
+ }
+ ret = set_conn_connectpath(conn,resolved_name);
+ SAFE_FREE(resolved_name);
+ return ret;
+#else
+ char resolved_name_buf[PATH_MAX+1];
+ char *resolved_name = SMB_VFS_REALPATH(conn,conn->connectpath,resolved_name_buf);
+ if (!resolved_name) {
+ return false;
+ }
+ return set_conn_connectpath(conn,resolved_name);
+#endif /* REALPATH_TAKES_NULL */
+}
+
+/****************************************************************************
+ Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
+ absolute path stating in / and not ending in /.
+ Observent people will notice a similarity between this and check_path_syntax :-).
+****************************************************************************/
+
+bool set_conn_connectpath(connection_struct *conn, const char *connectpath)
+{
+ char *destname;
+ char *d;
+ const char *s = connectpath;
+ bool start_of_name_component = true;
+
+ destname = SMB_STRDUP(connectpath);
+ if (!destname) {
+ return false;
+ }
+ d = destname;
+
+ *d++ = '/'; /* Always start with root. */
+
+ while (*s) {
+ if (*s == '/') {
+ /* Eat multiple '/' */
+ while (*s == '/') {
+ s++;
+ }
+ if ((d > destname + 1) && (*s != '\0')) {
+ *d++ = '/';
+ }
+ start_of_name_component = True;
+ continue;
+ }
+
+ if (start_of_name_component) {
+ if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) {
+ /* Uh oh - "/../" or "/..\0" ! */
+
+ /* Go past the ../ or .. */
+ if (s[2] == '/') {
+ s += 3;
+ } else {
+ s += 2; /* Go past the .. */
+ }
+
+ /* If we just added a '/' - delete it */
+ if ((d > destname) && (*(d-1) == '/')) {
+ *(d-1) = '\0';
+ d--;
+ }
+
+ /* Are we at the start ? Can't go back further if so. */
+ if (d <= destname) {
+ *d++ = '/'; /* Can't delete root */
+ continue;
+ }
+ /* Go back one level... */
+ /* Decrement d first as d points to the *next* char to write into. */
+ for (d--; d > destname; d--) {
+ if (*d == '/') {
+ break;
+ }
+ }
+ /* We're still at the start of a name component, just the previous one. */
+ continue;
+ } else if ((s[0] == '.') && ((s[1] == '\0') || s[1] == '/')) {
+ /* Component of pathname can't be "." only - skip the '.' . */
+ if (s[1] == '/') {
+ s += 2;
+ } else {
+ s++;
+ }
+ continue;
+ }
+ }
+
+ if (!(*s & 0x80)) {
+ *d++ = *s++;
+ } else {
+ size_t siz;
+ /* Get the size of the next MB character. */
+ next_codepoint(s,&siz);
+ switch(siz) {
+ case 5:
+ *d++ = *s++;
+ /*fall through*/
+ case 4:
+ *d++ = *s++;
+ /*fall through*/
+ case 3:
+ *d++ = *s++;
+ /*fall through*/
+ case 2:
+ *d++ = *s++;
+ /*fall through*/
+ case 1:
+ *d++ = *s++;
+ break;
+ default:
+ break;
+ }
+ }
+ start_of_name_component = false;
+ }
+ *d = '\0';
+
+ /* And must not end in '/' */
+ if (d > destname + 1 && (*(d-1) == '/')) {
+ *(d-1) = '\0';
+ }
+
+ DEBUG(10,("set_conn_connectpath: service %s, connectpath = %s\n",
+ lp_servicename(SNUM(conn)), destname ));
+
+ string_set(&conn->connectpath, destname);
+ SAFE_FREE(destname);
+ return true;
+}
+
+/****************************************************************************
+ Load parameters specific to a connection/service.
+****************************************************************************/
+
+bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir)
+{
+ static connection_struct *last_conn;
+ static uint16 last_flags;
+ int snum;
+
+ if (!conn) {
+ last_conn = NULL;
+ return(False);
+ }
+
+ conn->lastused_count++;
+
+ snum = SNUM(conn);
+
+ if (do_chdir &&
+ vfs_ChDir(conn,conn->connectpath) != 0 &&
+ vfs_ChDir(conn,conn->origpath) != 0) {
+ DEBUG(0,("chdir (%s) failed\n",
+ conn->connectpath));
+ return(False);
+ }
+
+ if ((conn == last_conn) && (last_flags == flags)) {
+ return(True);
+ }
+
+ last_conn = conn;
+ last_flags = flags;
+
+ /* Obey the client case sensitivity requests - only for clients that support it. */
+ switch (lp_casesensitive(snum)) {
+ case Auto:
+ {
+ /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
+ enum remote_arch_types ra_type = get_remote_arch();
+ if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
+ /* Client can't support per-packet case sensitive pathnames. */
+ conn->case_sensitive = False;
+ } else {
+ conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
+ }
+ }
+ break;
+ case True:
+ conn->case_sensitive = True;
+ break;
+ default:
+ conn->case_sensitive = False;
+ break;
+ }
+ return(True);
+}
+
+static int load_registry_service(const char *servicename)
+{
+ struct registry_key *key;
+ char *path;
+ WERROR err;
+
+ uint32 i;
+ char *value_name;
+ struct registry_value *value;
+
+ int res = -1;
+
+ if (!lp_registry_shares()) {
+ return -1;
+ }
+
+ if (strequal(servicename, GLOBAL_NAME)) {
+ return -2;
+ }
+
+ if (asprintf(&path, "%s\\%s", KEY_SMBCONF, servicename) == -1) {
+ return -1;
+ }
+
+ err = reg_open_path(NULL, path, REG_KEY_READ, get_root_nt_token(),
+ &key);
+ SAFE_FREE(path);
+
+ if (!W_ERROR_IS_OK(err)) {
+ return -1;
+ }
+
+ res = lp_add_service(servicename, -1);
+ if (res == -1) {
+ goto error;
+ }
+
+ for (i=0;
+ W_ERROR_IS_OK(reg_enumvalue(key, key, i, &value_name, &value));
+ i++) {
+ switch (value->type) {
+ case REG_DWORD: {
+ char *tmp;
+ if (asprintf(&tmp, "%d", value->v.dword) == -1) {
+ continue;
+ }
+ lp_do_parameter(res, value_name, tmp);
+ SAFE_FREE(tmp);
+ break;
+ }
+ case REG_SZ: {
+ lp_do_parameter(res, value_name, value->v.sz.str);
+ break;
+ }
+ default:
+ /* Ignore all the rest */
+ break;
+ }
+
+ TALLOC_FREE(value_name);
+ TALLOC_FREE(value);
+ }
+
+ error:
+
+ TALLOC_FREE(key);
+ return res;
+}
+
+void load_registry_shares(void)
+{
+ struct registry_key *key;
+ char *name;
+ WERROR err;
+ int i;
+
+ DEBUG(8, ("load_registry_shares()\n"));
+ if (!lp_registry_shares()) {
+ return;
+ }
+
+ err = reg_open_path(NULL, KEY_SMBCONF, REG_KEY_READ,
+ get_root_nt_token(), &key);
+ if (!(W_ERROR_IS_OK(err))) {
+ return;
+ }
+
+ for (i=0; W_ERROR_IS_OK(reg_enumkey(key, key, i, &name, NULL)); i++) {
+ load_registry_service(name);
+ TALLOC_FREE(name);
+ }
+
+ TALLOC_FREE(key);
+ return;
+}
+
+/****************************************************************************
+ Add a home service. Returns the new service number or -1 if fail.
+****************************************************************************/
+
+int add_home_service(const char *service, const char *username, const char *homedir)
+{
+ int iHomeService;
+
+ if (!service || !homedir)
+ return -1;
+
+ if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0) {
+ if ((iHomeService = load_registry_service(HOMES_NAME)) < 0) {
+ return -1;
+ }
+ }
+
+ /*
+ * If this is a winbindd provided username, remove
+ * the domain component before adding the service.
+ * Log a warning if the "path=" parameter does not
+ * include any macros.
+ */
+
+ {
+ const char *p = strchr(service,*lp_winbind_separator());
+
+ /* We only want the 'user' part of the string */
+ if (p) {
+ service = p + 1;
+ }
+ }
+
+ if (!lp_add_home(service, iHomeService, username, homedir)) {
+ return -1;
+ }
+
+ return lp_servicenumber(service);
+
+}
+
+/**
+ * Find a service entry.
+ *
+ * @param service is modified (to canonical form??)
+ **/
+
+int find_service(fstring service)
+{
+ int iService;
+
+ all_string_sub(service,"\\","/",0);
+
+ iService = lp_servicenumber(service);
+
+ /* now handle the special case of a home directory */
+ if (iService < 0) {
+ char *phome_dir = get_user_home_dir(talloc_tos(), service);
+
+ if(!phome_dir) {
+ /*
+ * Try mapping the servicename, it may
+ * be a Windows to unix mapped user name.
+ */
+ if(map_username(service))
+ phome_dir = get_user_home_dir(
+ talloc_tos(), service);
+ }
+
+ DEBUG(3,("checking for home directory %s gave %s\n",service,
+ phome_dir?phome_dir:"(NULL)"));
+
+ iService = add_home_service(service,service /* 'username' */, phome_dir);
+ }
+
+ /* If we still don't have a service, attempt to add it as a printer. */
+ if (iService < 0) {
+ int iPrinterService;
+
+ if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) < 0) {
+ iPrinterService = load_registry_service(PRINTERS_NAME);
+ }
+ if (iPrinterService) {
+ DEBUG(3,("checking whether %s is a valid printer name...\n", service));
+ if (pcap_printername_ok(service)) {
+ DEBUG(3,("%s is a valid printer name\n", service));
+ DEBUG(3,("adding %s as a printer service\n", service));
+ lp_add_printer(service, iPrinterService);
+ iService = lp_servicenumber(service);
+ if (iService < 0) {
+ DEBUG(0,("failed to add %s as a printer service!\n", service));
+ }
+ } else {
+ DEBUG(3,("%s is not a valid printer name\n", service));
+ }
+ }
+ }
+
+ /* Check for default vfs service? Unsure whether to implement this */
+ if (iService < 0) {
+ }
+
+ if (iService < 0) {
+ iService = load_registry_service(service);
+ }
+
+ /* Is it a usershare service ? */
+ if (iService < 0 && *lp_usershare_path()) {
+ /* Ensure the name is canonicalized. */
+ strlower_m(service);
+ iService = load_usershare_service(service);
+ }
+
+ /* just possibly it's a default service? */
+ if (iService < 0) {
+ char *pdefservice = lp_defaultservice();
+ if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(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>.
+ */
+ char *defservice = SMB_STRDUP(pdefservice);
+
+ if (!defservice) {
+ goto fail;
+ }
+
+ /* Disallow anything except explicit share names. */
+ if (strequal(defservice,HOMES_NAME) ||
+ strequal(defservice, PRINTERS_NAME) ||
+ strequal(defservice, "IPC$")) {
+ SAFE_FREE(defservice);
+ goto fail;
+ }
+
+ iService = find_service(defservice);
+ if (iService >= 0) {
+ all_string_sub(service, "_","/",0);
+ iService = lp_add_service(service, iService);
+ }
+ SAFE_FREE(defservice);
+ }
+ }
+
+ if (iService >= 0) {
+ if (!VALID_SNUM(iService)) {
+ DEBUG(0,("Invalid snum %d for %s\n",iService, service));
+ iService = -1;
+ }
+ }
+
+ fail:
+
+ if (iService < 0)
+ DEBUG(3,("find_service() failed to find service %s\n", service));
+
+ return (iService);
+}
+
+
+/****************************************************************************
+ do some basic sainity checks on the share.
+ This function modifies dev, ecode.
+****************************************************************************/
+
+static NTSTATUS share_sanity_checks(int snum, fstring dev)
+{
+
+ if (!lp_snum_ok(snum) ||
+ !check_access(smbd_server_fd(),
+ lp_hostsallow(snum), lp_hostsdeny(snum))) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (dev[0] == '?' || !dev[0]) {
+ if (lp_print_ok(snum)) {
+ fstrcpy(dev,"LPT1:");
+ } else if (strequal(lp_fstype(snum), "IPC")) {
+ fstrcpy(dev, "IPC");
+ } else {
+ fstrcpy(dev,"A:");
+ }
+ }
+
+ strupper_m(dev);
+
+ if (lp_print_ok(snum)) {
+ if (!strequal(dev, "LPT1:")) {
+ return NT_STATUS_BAD_DEVICE_TYPE;
+ }
+ } else if (strequal(lp_fstype(snum), "IPC")) {
+ if (!strequal(dev, "IPC")) {
+ return NT_STATUS_BAD_DEVICE_TYPE;
+ }
+ } else if (!strequal(dev, "A:")) {
+ return NT_STATUS_BAD_DEVICE_TYPE;
+ }
+
+ /* Behave as a printer if we are supposed to */
+ if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
+ fstrcpy(dev, "LPT1:");
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * Go through lookup_name etc to find the force'd group.
+ *
+ * Create a new token from src_token, replacing the primary group sid with the
+ * one found.
+ */
+
+static NTSTATUS find_forced_group(bool force_user,
+ int snum, const char *username,
+ DOM_SID *pgroup_sid,
+ gid_t *pgid)
+{
+ NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
+ TALLOC_CTX *frame = talloc_stackframe();
+ DOM_SID group_sid;
+ enum lsa_SidType type;
+ char *groupname;
+ bool user_must_be_member = False;
+ gid_t gid;
+
+ groupname = talloc_strdup(talloc_tos(), lp_force_group(snum));
+ if (groupname == NULL) {
+ DEBUG(1, ("talloc_strdup failed\n"));
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if (groupname[0] == '+') {
+ user_must_be_member = True;
+ groupname += 1;
+ }
+
+ groupname = talloc_string_sub(talloc_tos(), groupname,
+ "%S", lp_servicename(snum));
+ if (groupname == NULL) {
+ DEBUG(1, ("talloc_string_sub failed\n"));
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if (!lookup_name_smbconf(talloc_tos(), groupname,
+ LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
+ NULL, NULL, &group_sid, &type)) {
+ DEBUG(10, ("lookup_name_smbconf(%s) failed\n",
+ groupname));
+ goto done;
+ }
+
+ if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
+ (type != SID_NAME_WKN_GRP)) {
+ DEBUG(10, ("%s is a %s, not a group\n", groupname,
+ sid_type_lookup(type)));
+ goto done;
+ }
+
+ if (!sid_to_gid(&group_sid, &gid)) {
+ DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
+ sid_string_dbg(&group_sid), groupname));
+ goto done;
+ }
+
+ /*
+ * If the user has been forced and the forced group starts with a '+',
+ * then we only set the group to be the forced group if the forced
+ * user is a member of that group. Otherwise, the meaning of the '+'
+ * would be ignored.
+ */
+
+ if (force_user && user_must_be_member) {
+ if (user_in_group_sid(username, &group_sid)) {
+ sid_copy(pgroup_sid, &group_sid);
+ *pgid = gid;
+ DEBUG(3,("Forced group %s for member %s\n",
+ groupname, username));
+ } else {
+ DEBUG(0,("find_forced_group: forced user %s is not a member "
+ "of forced group %s. Disallowing access.\n",
+ username, groupname ));
+ result = NT_STATUS_MEMBER_NOT_IN_GROUP;
+ goto done;
+ }
+ } else {
+ sid_copy(pgroup_sid, &group_sid);
+ *pgid = gid;
+ DEBUG(3,("Forced group %s\n", groupname));
+ }
+
+ result = NT_STATUS_OK;
+ done:
+ TALLOC_FREE(frame);
+ return result;
+}
+
+/****************************************************************************
+ Create an auth_serversupplied_info structure for a connection_struct
+****************************************************************************/
+
+static NTSTATUS create_connection_server_info(TALLOC_CTX *mem_ctx, int snum,
+ struct auth_serversupplied_info *vuid_serverinfo,
+ DATA_BLOB password,
+ struct auth_serversupplied_info **presult)
+{
+ if (lp_guest_only(snum)) {
+ return make_server_info_guest(mem_ctx, presult);
+ }
+
+ if (vuid_serverinfo != NULL) {
+
+ struct auth_serversupplied_info *result;
+
+ /*
+ * This is the normal security != share case where we have a
+ * valid vuid from the session setup. */
+
+ if (vuid_serverinfo->guest) {
+ if (!lp_guest_ok(snum)) {
+ DEBUG(2, ("guest user (from session setup) "
+ "not permitted to access this share "
+ "(%s)\n", lp_servicename(snum)));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ } else {
+ if (!user_ok_token(vuid_serverinfo->unix_name,
+ pdb_get_domain(vuid_serverinfo->sam_account),
+ vuid_serverinfo->ptok, snum)) {
+ DEBUG(2, ("user '%s' (from session setup) not "
+ "permitted to access this share "
+ "(%s)\n",
+ vuid_serverinfo->unix_name,
+ lp_servicename(snum)));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ result = copy_serverinfo(mem_ctx, vuid_serverinfo);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *presult = result;
+ return NT_STATUS_OK;
+ }
+
+ if (lp_security() == SEC_SHARE) {
+
+ fstring user;
+ bool guest;
+
+ /* add the sharename as a possible user name if we
+ are in share mode security */
+
+ add_session_user(lp_servicename(snum));
+
+ /* shall we let them in? */
+
+ if (!authorise_login(snum,user,password,&guest)) {
+ DEBUG( 2, ( "Invalid username/password for [%s]\n",
+ lp_servicename(snum)) );
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ return make_serverinfo_from_username(mem_ctx, user, guest,
+ presult);
+ }
+
+ DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
+ return NT_STATUS_ACCESS_DENIED;
+}
+
+
+/****************************************************************************
+ Make a connection, given the snum to connect to, and the vuser of the
+ connecting user if appropriate.
+****************************************************************************/
+
+static connection_struct *make_connection_snum(int snum, user_struct *vuser,
+ DATA_BLOB password,
+ const char *pdev,
+ NTSTATUS *pstatus)
+{
+ connection_struct *conn;
+ SMB_STRUCT_STAT st;
+ fstring dev;
+ int ret;
+ char addr[INET6_ADDRSTRLEN];
+ bool on_err_call_dis_hook = false;
+ NTSTATUS status;
+
+ fstrcpy(dev, pdev);
+ SET_STAT_INVALID(st);
+
+ if (NT_STATUS_IS_ERR(*pstatus = share_sanity_checks(snum, dev))) {
+ return NULL;
+ }
+
+ conn = conn_new();
+ if (!conn) {
+ DEBUG(0,("Couldn't find free connection.\n"));
+ *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
+ return NULL;
+ }
+
+ conn->params->service = snum;
+
+ status = create_connection_server_info(
+ conn, snum, vuser ? vuser->server_info : NULL, password,
+ &conn->server_info);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("create_connection_server_info failed: %s\n",
+ nt_errstr(status)));
+ *pstatus = status;
+ conn_free(conn);
+ return NULL;
+ }
+
+ if ((lp_guest_only(snum)) || (lp_security() == SEC_SHARE)) {
+ conn->force_user = true;
+ }
+
+ add_session_user(conn->server_info->unix_name);
+
+ safe_strcpy(conn->client_address,
+ client_addr(get_client_fd(),addr,sizeof(addr)),
+ sizeof(conn->client_address)-1);
+ conn->num_files_open = 0;
+ conn->lastused = conn->lastused_count = time(NULL);
+ conn->used = True;
+ conn->printer = (strncmp(dev,"LPT",3) == 0);
+ conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
+ ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
+ conn->dirptr = NULL;
+
+ /* Case options for the share. */
+ if (lp_casesensitive(snum) == Auto) {
+ /* We will be setting this per packet. Set to be case
+ * insensitive for now. */
+ conn->case_sensitive = False;
+ } else {
+ conn->case_sensitive = (bool)lp_casesensitive(snum);
+ }
+
+ conn->case_preserve = lp_preservecase(snum);
+ conn->short_case_preserve = lp_shortpreservecase(snum);
+
+ conn->encrypt_level = lp_smb_encrypt(snum);
+
+ conn->veto_list = NULL;
+ conn->hide_list = NULL;
+ conn->veto_oplock_list = NULL;
+ conn->aio_write_behind_list = NULL;
+ string_set(&conn->dirpath,"");
+
+ conn->read_only = lp_readonly(SNUM(conn));
+ conn->admin_user = False;
+
+ if (*lp_force_user(snum)) {
+
+ /*
+ * Replace conn->server_info with a completely faked up one
+ * from the username we are forced into :-)
+ */
+
+ char *fuser;
+ struct auth_serversupplied_info *forced_serverinfo;
+
+ fuser = talloc_string_sub(conn, lp_force_user(snum), "%S",
+ lp_servicename(snum));
+ if (fuser == NULL) {
+ conn_free(conn);
+ *pstatus = NT_STATUS_NO_MEMORY;
+ return NULL;
+ }
+
+ status = make_serverinfo_from_username(
+ conn, fuser, conn->server_info->guest,
+ &forced_serverinfo);
+ if (!NT_STATUS_IS_OK(status)) {
+ conn_free(conn);
+ *pstatus = status;
+ return NULL;
+ }
+
+ TALLOC_FREE(conn->server_info);
+ conn->server_info = forced_serverinfo;
+
+ conn->force_user = True;
+ DEBUG(3,("Forced user %s\n", fuser));
+ }
+
+ /*
+ * If force group is true, then override
+ * any groupid stored for the connecting user.
+ */
+
+ if (*lp_force_group(snum)) {
+
+ status = find_forced_group(
+ conn->force_user, snum, conn->server_info->unix_name,
+ &conn->server_info->ptok->user_sids[1],
+ &conn->server_info->utok.gid);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ conn_free(conn);
+ *pstatus = status;
+ return NULL;
+ }
+ }
+
+ conn->vuid = (vuser != NULL) ? vuser->vuid : UID_FIELD_INVALID;
+
+ {
+ char *s = talloc_sub_advanced(talloc_tos(),
+ lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name,
+ conn->connectpath,
+ conn->server_info->utok.gid,
+ conn->server_info->sanitized_username,
+ pdb_get_domain(conn->server_info->sam_account),
+ lp_pathname(snum));
+ if (!s) {
+ conn_free(conn);
+ *pstatus = NT_STATUS_NO_MEMORY;
+ return NULL;
+ }
+
+ if (!set_conn_connectpath(conn,s)) {
+ TALLOC_FREE(s);
+ conn_free(conn);
+ *pstatus = NT_STATUS_NO_MEMORY;
+ return NULL;
+ }
+ DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
+ lp_servicename(snum)));
+ TALLOC_FREE(s);
+ }
+
+ /*
+ * New code to check if there's a share security descripter
+ * added from NT server manager. This is done after the
+ * smb.conf checks are done as we need a uid and token. JRA.
+ *
+ */
+
+ {
+ bool can_write = False;
+
+ can_write = share_access_check(conn->server_info->ptok,
+ lp_servicename(snum),
+ FILE_WRITE_DATA);
+
+ if (!can_write) {
+ if (!share_access_check(conn->server_info->ptok,
+ lp_servicename(snum),
+ FILE_READ_DATA)) {
+ /* No access, read or write. */
+ DEBUG(0,("make_connection: connection to %s "
+ "denied due to security "
+ "descriptor.\n",
+ lp_servicename(snum)));
+ conn_free(conn);
+ *pstatus = NT_STATUS_ACCESS_DENIED;
+ return NULL;
+ } else {
+ conn->read_only = True;
+ }
+ }
+ }
+ /* Initialise VFS function pointers */
+
+ if (!smbd_vfs_init(conn)) {
+ DEBUG(0, ("vfs_init failed for service %s\n",
+ lp_servicename(snum)));
+ conn_free(conn);
+ *pstatus = NT_STATUS_BAD_NETWORK_NAME;
+ return NULL;
+ }
+
+ /*
+ * If widelinks are disallowed we need to canonicalise the connect
+ * path here to ensure we don't have any symlinks in the
+ * connectpath. We will be checking all paths on this connection are
+ * below this directory. We must do this after the VFS init as we
+ * depend on the realpath() pointer in the vfs table. JRA.
+ */
+ if (!lp_widelinks(snum)) {
+ if (!canonicalize_connect_path(conn)) {
+ DEBUG(0, ("canonicalize_connect_path failed "
+ "for service %s, path %s\n",
+ lp_servicename(snum),
+ conn->connectpath));
+ conn_free(conn);
+ *pstatus = NT_STATUS_BAD_NETWORK_NAME;
+ return NULL;
+ }
+ }
+
+ if ((!conn->printer) && (!conn->ipc)) {
+ conn->notify_ctx = notify_init(conn, server_id_self(),
+ smbd_messaging_context(),
+ smbd_event_context(),
+ conn);
+ }
+
+/* ROOT Activities: */
+ /*
+ * Enforce the max connections parameter.
+ */
+
+ if ((lp_max_connections(snum) > 0)
+ && (count_current_connections(lp_servicename(SNUM(conn)), True) >=
+ lp_max_connections(snum))) {
+
+ DEBUG(1, ("Max connections (%d) exceeded for %s\n",
+ lp_max_connections(snum), lp_servicename(snum)));
+ conn_free(conn);
+ *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
+ return NULL;
+ }
+
+ /*
+ * Get us an entry in the connections db
+ */
+ if (!claim_connection(conn, lp_servicename(snum), 0)) {
+ DEBUG(1, ("Could not store connections entry\n"));
+ conn_free(conn);
+ *pstatus = NT_STATUS_INTERNAL_DB_ERROR;
+ return NULL;
+ }
+
+ /* Preexecs are done here as they might make the dir we are to ChDir
+ * to below */
+ /* execute any "root preexec = " line */
+ if (*lp_rootpreexec(snum)) {
+ char *cmd = talloc_sub_advanced(talloc_tos(),
+ lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name,
+ conn->connectpath,
+ conn->server_info->utok.gid,
+ conn->server_info->sanitized_username,
+ pdb_get_domain(conn->server_info->sam_account),
+ lp_rootpreexec(snum));
+ DEBUG(5,("cmd=%s\n",cmd));
+ ret = smbrun(cmd,NULL);
+ TALLOC_FREE(cmd);
+ if (ret != 0 && lp_rootpreexec_close(snum)) {
+ DEBUG(1,("root preexec gave %d - failing "
+ "connection\n", ret));
+ yield_connection(conn, lp_servicename(snum));
+ conn_free(conn);
+ *pstatus = NT_STATUS_ACCESS_DENIED;
+ return NULL;
+ }
+ }
+
+/* USER Activites: */
+ if (!change_to_user(conn, conn->vuid)) {
+ /* No point continuing if they fail the basic checks */
+ DEBUG(0,("Can't become connected user!\n"));
+ yield_connection(conn, lp_servicename(snum));
+ conn_free(conn);
+ *pstatus = NT_STATUS_LOGON_FAILURE;
+ return NULL;
+ }
+
+ /* Remember that a different vuid can connect later without these
+ * checks... */
+
+ /* Preexecs are done here as they might make the dir we are to ChDir
+ * to below */
+
+ /* execute any "preexec = " line */
+ if (*lp_preexec(snum)) {
+ char *cmd = talloc_sub_advanced(talloc_tos(),
+ lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name,
+ conn->connectpath,
+ conn->server_info->utok.gid,
+ conn->server_info->sanitized_username,
+ pdb_get_domain(conn->server_info->sam_account),
+ lp_preexec(snum));
+ ret = smbrun(cmd,NULL);
+ TALLOC_FREE(cmd);
+ if (ret != 0 && lp_preexec_close(snum)) {
+ DEBUG(1,("preexec gave %d - failing connection\n",
+ ret));
+ *pstatus = NT_STATUS_ACCESS_DENIED;
+ goto err_root_exit;
+ }
+ }
+
+#ifdef WITH_FAKE_KASERVER
+ if (lp_afs_share(snum)) {
+ afs_login(conn);
+ }
+#endif
+
+ /* Add veto/hide lists */
+ if (!IS_IPC(conn) && !IS_PRINT(conn)) {
+ set_namearray( &conn->veto_list, lp_veto_files(snum));
+ set_namearray( &conn->hide_list, lp_hide_files(snum));
+ set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
+ set_namearray( &conn->aio_write_behind_list,
+ lp_aio_write_behind(snum));
+ }
+
+ /* Invoke VFS make connection hook - do this before the VFS_STAT call
+ to allow any filesystems needing user credentials to initialize
+ themselves. */
+
+ if (SMB_VFS_CONNECT(conn, lp_servicename(snum),
+ conn->server_info->unix_name) < 0) {
+ DEBUG(0,("make_connection: VFS make connection failed!\n"));
+ *pstatus = NT_STATUS_UNSUCCESSFUL;
+ goto err_root_exit;
+ }
+
+ /* Any error exit after here needs to call the disconnect hook. */
+ on_err_call_dis_hook = true;
+
+ /* win2000 does not check the permissions on the directory
+ during the tree connect, instead relying on permission
+ check during individual operations. To match this behaviour
+ I have disabled this chdir check (tridge) */
+ /* the alternative is just to check the directory exists */
+ if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 ||
+ !S_ISDIR(st.st_mode)) {
+ if (ret == 0 && !S_ISDIR(st.st_mode)) {
+ DEBUG(0,("'%s' is not a directory, when connecting to "
+ "[%s]\n", conn->connectpath,
+ lp_servicename(snum)));
+ } else {
+ DEBUG(0,("'%s' does not exist or permission denied "
+ "when connecting to [%s] Error was %s\n",
+ conn->connectpath, lp_servicename(snum),
+ strerror(errno) ));
+ }
+ *pstatus = NT_STATUS_BAD_NETWORK_NAME;
+ goto err_root_exit;
+ }
+
+ string_set(&conn->origpath,conn->connectpath);
+
+#if SOFTLINK_OPTIMISATION
+ /* resolve any soft links early if possible */
+ if (vfs_ChDir(conn,conn->connectpath) == 0) {
+ TALLOC_CTX *ctx = talloc_tos();
+ char *s = vfs_GetWd(ctx,s);
+ if (!s) {
+ *status = map_nt_error_from_unix(errno);
+ goto err_root_exit;
+ }
+ if (!set_conn_connectpath(conn,s)) {
+ *status = NT_STATUS_NO_MEMORY;
+ goto err_root_exit;
+ }
+ vfs_ChDir(conn,conn->connectpath);
+ }
+#endif
+
+ /* Figure out the characteristics of the underlying filesystem. This
+ * assumes that all the filesystem mounted withing a share path have
+ * the same characteristics, which is likely but not guaranteed.
+ */
+
+ conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn);
+
+ /*
+ * Print out the 'connected as' stuff here as we need
+ * to know the effective uid and gid we will be using
+ * (at least initially).
+ */
+
+ if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
+ dbgtext( "%s (%s) ", get_remote_machine_name(),
+ conn->client_address );
+ dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
+ dbgtext( "connect to service %s ", lp_servicename(snum) );
+ dbgtext( "initially as user %s ",
+ conn->server_info->unix_name );
+ dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
+ dbgtext( "(pid %d)\n", (int)sys_getpid() );
+ }
+
+ /* we've finished with the user stuff - go back to root */
+ change_to_root_user();
+ return(conn);
+
+ err_root_exit:
+
+ change_to_root_user();
+ if (on_err_call_dis_hook) {
+ /* Call VFS disconnect hook */
+ SMB_VFS_DISCONNECT(conn);
+ }
+ yield_connection(conn, lp_servicename(snum));
+ conn_free(conn);
+ return NULL;
+}
+
+/***************************************************************************************
+ Simple wrapper function for make_connection() to include a call to
+ vfs_chdir()
+ **************************************************************************************/
+
+connection_struct *make_connection_with_chdir(const char *service_in,
+ DATA_BLOB password,
+ const char *dev, uint16 vuid,
+ NTSTATUS *status)
+{
+ connection_struct *conn = NULL;
+
+ conn = make_connection(service_in, password, dev, vuid, status);
+
+ /*
+ * make_connection() does not change the directory for us any more
+ * so we have to do it as a separate step --jerry
+ */
+
+ if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
+ DEBUG(0,("make_connection_with_chdir: Can't change "
+ "directory to %s for [print$] (%s)\n",
+ conn->connectpath,strerror(errno)));
+ yield_connection(conn, lp_servicename(SNUM(conn)));
+ conn_free(conn);
+ *status = NT_STATUS_UNSUCCESSFUL;
+ return NULL;
+ }
+
+ return conn;
+}
+
+/****************************************************************************
+ Make a connection to a service.
+ *
+ * @param service
+****************************************************************************/
+
+connection_struct *make_connection(const char *service_in, DATA_BLOB password,
+ const char *pdev, uint16 vuid,
+ NTSTATUS *status)
+{
+ uid_t euid;
+ user_struct *vuser = NULL;
+ fstring service;
+ fstring dev;
+ int snum = -1;
+ char addr[INET6_ADDRSTRLEN];
+
+ fstrcpy(dev, pdev);
+
+ /* This must ONLY BE CALLED AS ROOT. As it exits this function as
+ * root. */
+ if (!non_root_mode() && (euid = geteuid()) != 0) {
+ DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
+ "(%u)\n", (unsigned int)euid ));
+ smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
+ }
+
+ if (conn_num_open() > 2047) {
+ *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
+ return NULL;
+ }
+
+ if(lp_security() != SEC_SHARE) {
+ vuser = get_valid_user_struct(vuid);
+ if (!vuser) {
+ DEBUG(1,("make_connection: refusing to connect with "
+ "no session setup\n"));
+ *status = NT_STATUS_ACCESS_DENIED;
+ return NULL;
+ }
+ }
+
+ /* Logic to try and connect to the correct [homes] share, preferably
+ without too many getpwnam() lookups. This is particulary nasty for
+ winbind usernames, where the share name isn't the same as unix
+ username.
+
+ The snum of the homes share is stored on the vuser at session setup
+ time.
+ */
+
+ if (strequal(service_in,HOMES_NAME)) {
+ if(lp_security() != SEC_SHARE) {
+ DATA_BLOB no_pw = data_blob_null;
+ if (vuser->homes_snum == -1) {
+ DEBUG(2, ("[homes] share not available for "
+ "this user because it was not found "
+ "or created at session setup "
+ "time\n"));
+ *status = NT_STATUS_BAD_NETWORK_NAME;
+ return NULL;
+ }
+ DEBUG(5, ("making a connection to [homes] service "
+ "created at session setup time\n"));
+ return make_connection_snum(vuser->homes_snum,
+ vuser, no_pw,
+ dev, status);
+ } else {
+ /* Security = share. Try with
+ * current_user_info.smb_name as the username. */
+ if (*current_user_info.smb_name) {
+ fstring unix_username;
+ fstrcpy(unix_username,
+ current_user_info.smb_name);
+ map_username(unix_username);
+ snum = find_service(unix_username);
+ }
+ if (snum != -1) {
+ DEBUG(5, ("making a connection to 'homes' "
+ "service %s based on "
+ "security=share\n", service_in));
+ return make_connection_snum(snum, NULL,
+ password,
+ dev, status);
+ }
+ }
+ } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
+ && strequal(service_in,
+ lp_servicename(vuser->homes_snum))) {
+ DATA_BLOB no_pw = data_blob_null;
+ DEBUG(5, ("making a connection to 'homes' service [%s] "
+ "created at session setup time\n", service_in));
+ return make_connection_snum(vuser->homes_snum,
+ vuser, no_pw,
+ dev, status);
+ }
+
+ fstrcpy(service, service_in);
+
+ strlower_m(service);
+
+ snum = find_service(service);
+
+ if (snum < 0) {
+ if (strequal(service,"IPC$") ||
+ (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
+ DEBUG(3,("refusing IPC connection to %s\n", service));
+ *status = NT_STATUS_ACCESS_DENIED;
+ return NULL;
+ }
+
+ DEBUG(0,("%s (%s) couldn't find service %s\n",
+ get_remote_machine_name(),
+ client_addr(get_client_fd(),addr,sizeof(addr)),
+ service));
+ *status = NT_STATUS_BAD_NETWORK_NAME;
+ return NULL;
+ }
+
+ /* Handle non-Dfs clients attempting connections to msdfs proxy */
+ if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
+ DEBUG(3, ("refusing connection to dfs proxy share '%s' "
+ "(pointing to %s)\n",
+ service, lp_msdfs_proxy(snum)));
+ *status = NT_STATUS_BAD_NETWORK_NAME;
+ return NULL;
+ }
+
+ DEBUG(5, ("making a connection to 'normal' service %s\n", service));
+
+ return make_connection_snum(snum, vuser,
+ password,
+ dev, status);
+}
+
+/****************************************************************************
+ Close a cnum.
+****************************************************************************/
+
+void close_cnum(connection_struct *conn, uint16 vuid)
+{
+ if (IS_IPC(conn)) {
+ pipe_close_conn(conn);
+ } else {
+ file_close_conn(conn);
+ dptr_closecnum(conn);
+ }
+
+ change_to_root_user();
+
+ DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
+ get_remote_machine_name(),
+ conn->client_address,
+ lp_servicename(SNUM(conn))));
+
+ /* Call VFS disconnect hook */
+ SMB_VFS_DISCONNECT(conn);
+
+ yield_connection(conn, lp_servicename(SNUM(conn)));
+
+ /* make sure we leave the directory available for unmount */
+ vfs_ChDir(conn, "/");
+
+ /* execute any "postexec = " line */
+ if (*lp_postexec(SNUM(conn)) &&
+ change_to_user(conn, vuid)) {
+ char *cmd = talloc_sub_advanced(talloc_tos(),
+ lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name,
+ conn->connectpath,
+ conn->server_info->utok.gid,
+ conn->server_info->sanitized_username,
+ pdb_get_domain(conn->server_info->sam_account),
+ lp_postexec(SNUM(conn)));
+ smbrun(cmd,NULL);
+ TALLOC_FREE(cmd);
+ change_to_root_user();
+ }
+
+ change_to_root_user();
+ /* execute any "root postexec = " line */
+ if (*lp_rootpostexec(SNUM(conn))) {
+ char *cmd = talloc_sub_advanced(talloc_tos(),
+ lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name,
+ conn->connectpath,
+ conn->server_info->utok.gid,
+ conn->server_info->sanitized_username,
+ pdb_get_domain(conn->server_info->sam_account),
+ lp_rootpostexec(SNUM(conn)));
+ smbrun(cmd,NULL);
+ TALLOC_FREE(cmd);
+ }
+
+ conn_free(conn);
+}
diff --git a/source3/smbd/session.c b/source3/smbd/session.c
new file mode 100644
index 0000000000..3b431a19be
--- /dev/null
+++ b/source3/smbd/session.c
@@ -0,0 +1,329 @@
+/*
+ Unix SMB/CIFS implementation.
+ session handling for utmp and PAM
+
+ Copyright (C) tridge@samba.org 2001
+ Copyright (C) abartlet@samba.org 2001
+ Copyright (C) Gerald (Jerry) Carter 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* a "session" is claimed when we do a SessionSetupX operation
+ and is yielded when the corresponding vuid is destroyed.
+
+ sessions are used to populate utmp and PAM session structures
+*/
+
+#include "includes.h"
+
+/********************************************************************
+********************************************************************/
+
+static struct db_context *session_db_ctx(void)
+{
+ static struct db_context *ctx;
+
+ if (ctx)
+ return ctx;
+
+ ctx = db_open(NULL, lock_path("sessionid.tdb"), 0,
+ TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
+ O_RDWR | O_CREAT, 0644);
+ return ctx;
+}
+
+bool session_init(void)
+{
+ if (session_db_ctx() == NULL) {
+ DEBUG(1,("session_init: failed to open sessionid tdb\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ called when a session is created
+********************************************************************/
+
+bool session_claim(user_struct *vuser)
+{
+ TDB_DATA key, data;
+ int i = 0;
+ struct sessionid sessionid;
+ struct server_id pid = procid_self();
+ fstring keystr;
+ const char * hostname;
+ struct db_context *ctx;
+ struct db_record *rec;
+ NTSTATUS status;
+ char addr[INET6_ADDRSTRLEN];
+
+ vuser->session_keystr = NULL;
+
+ /* don't register sessions for the guest user - its just too
+ expensive to go through pam session code for browsing etc */
+ if (vuser->server_info->guest) {
+ return True;
+ }
+
+ if (!(ctx = session_db_ctx())) {
+ return False;
+ }
+
+ ZERO_STRUCT(sessionid);
+
+ data.dptr = NULL;
+ data.dsize = 0;
+
+ if (lp_utmp()) {
+
+ for (i=1;i<MAX_SESSION_ID;i++) {
+
+ /*
+ * This is very inefficient and needs fixing -- vl
+ */
+
+ struct server_id sess_pid;
+
+ snprintf(keystr, sizeof(keystr), "ID/%d", i);
+ key = string_term_tdb_data(keystr);
+
+ rec = ctx->fetch_locked(ctx, NULL, key);
+
+ if (rec == NULL) {
+ DEBUG(1, ("Could not lock \"%s\"\n", keystr));
+ return False;
+ }
+
+ if (rec->value.dsize != sizeof(sessionid)) {
+ DEBUG(1, ("Re-using invalid record\n"));
+ break;
+ }
+
+ sess_pid = ((struct sessionid *)rec->value.dptr)->pid;
+
+ if (!process_exists(sess_pid)) {
+ DEBUG(5, ("%s has died -- re-using session\n",
+ procid_str_static(&sess_pid)));
+ break;
+ }
+
+ TALLOC_FREE(rec);
+ }
+
+ if (i == MAX_SESSION_ID) {
+ SMB_ASSERT(rec == NULL);
+ DEBUG(1,("session_claim: out of session IDs "
+ "(max is %d)\n", MAX_SESSION_ID));
+ return False;
+ }
+
+ snprintf(sessionid.id_str, sizeof(sessionid.id_str),
+ SESSION_UTMP_TEMPLATE, i);
+ } else
+ {
+ snprintf(keystr, sizeof(keystr), "ID/%s/%u",
+ procid_str_static(&pid), vuser->vuid);
+ key = string_term_tdb_data(keystr);
+
+ rec = ctx->fetch_locked(ctx, NULL, key);
+
+ if (rec == NULL) {
+ DEBUG(1, ("Could not lock \"%s\"\n", keystr));
+ return False;
+ }
+
+ snprintf(sessionid.id_str, sizeof(sessionid.id_str),
+ SESSION_TEMPLATE, (long unsigned int)sys_getpid(),
+ vuser->vuid);
+ }
+
+ SMB_ASSERT(rec != NULL);
+
+ /* If 'hostname lookup' == yes, then do the DNS lookup. This is
+ needed because utmp and PAM both expect DNS names
+
+ client_name() handles this case internally.
+ */
+
+ hostname = client_name(get_client_fd());
+ if (strcmp(hostname, "UNKNOWN") == 0) {
+ hostname = client_addr(get_client_fd(),addr,sizeof(addr));
+ }
+
+ fstrcpy(sessionid.username, vuser->server_info->unix_name);
+ fstrcpy(sessionid.hostname, hostname);
+ sessionid.id_num = i; /* Only valid for utmp sessions */
+ sessionid.pid = pid;
+ sessionid.uid = vuser->server_info->utok.uid;
+ sessionid.gid = vuser->server_info->utok.gid;
+ fstrcpy(sessionid.remote_machine, get_remote_machine_name());
+ fstrcpy(sessionid.ip_addr_str,
+ client_addr(get_client_fd(),addr,sizeof(addr)));
+ sessionid.connect_start = time(NULL);
+
+ if (!smb_pam_claim_session(sessionid.username, sessionid.id_str,
+ sessionid.hostname)) {
+ DEBUG(1,("pam_session rejected the session for %s [%s]\n",
+ sessionid.username, sessionid.id_str));
+
+ TALLOC_FREE(rec);
+ return False;
+ }
+
+ data.dptr = (uint8 *)&sessionid;
+ data.dsize = sizeof(sessionid);
+
+ status = rec->store(rec, data, TDB_REPLACE);
+
+ TALLOC_FREE(rec);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1,("session_claim: unable to create session id "
+ "record: %s\n", nt_errstr(status)));
+ return False;
+ }
+
+ if (lp_utmp()) {
+ sys_utmp_claim(sessionid.username, sessionid.hostname,
+ sessionid.ip_addr_str,
+ sessionid.id_str, sessionid.id_num);
+ }
+
+ vuser->session_keystr = talloc_strdup(vuser, keystr);
+ if (!vuser->session_keystr) {
+ DEBUG(0, ("session_claim: talloc_strdup() failed for session_keystr\n"));
+ return False;
+ }
+ return True;
+}
+
+/********************************************************************
+ called when a session is destroyed
+********************************************************************/
+
+void session_yield(user_struct *vuser)
+{
+ TDB_DATA key;
+ struct sessionid sessionid;
+ struct db_context *ctx;
+ struct db_record *rec;
+
+ if (!(ctx = session_db_ctx())) return;
+
+ if (!vuser->session_keystr) {
+ return;
+ }
+
+ key = string_term_tdb_data(vuser->session_keystr);
+
+ if (!(rec = ctx->fetch_locked(ctx, NULL, key))) {
+ return;
+ }
+
+ if (rec->value.dsize != sizeof(sessionid))
+ return;
+
+ memcpy(&sessionid, rec->value.dptr, sizeof(sessionid));
+
+ if (lp_utmp()) {
+ sys_utmp_yield(sessionid.username, sessionid.hostname,
+ sessionid.ip_addr_str,
+ sessionid.id_str, sessionid.id_num);
+ }
+
+ smb_pam_close_session(sessionid.username, sessionid.id_str,
+ sessionid.hostname);
+
+ rec->delete_rec(rec);
+
+ TALLOC_FREE(rec);
+}
+
+/********************************************************************
+********************************************************************/
+
+static bool session_traverse(int (*fn)(struct db_record *db,
+ void *private_data),
+ void *private_data)
+{
+ struct db_context *ctx;
+
+ if (!(ctx = session_db_ctx())) {
+ DEBUG(3, ("No tdb opened\n"));
+ return False;
+ }
+
+ ctx->traverse_read(ctx, fn, private_data);
+ return True;
+}
+
+/********************************************************************
+********************************************************************/
+
+struct session_list {
+ TALLOC_CTX *mem_ctx;
+ int count;
+ struct sessionid *sessions;
+};
+
+static int gather_sessioninfo(struct db_record *rec, void *state)
+{
+ struct session_list *sesslist = (struct session_list *) state;
+ const struct sessionid *current =
+ (const struct sessionid *) rec->value.dptr;
+
+ sesslist->sessions = TALLOC_REALLOC_ARRAY(
+ sesslist->mem_ctx, sesslist->sessions, struct sessionid,
+ sesslist->count+1);
+
+ if (!sesslist->sessions) {
+ sesslist->count = 0;
+ return -1;
+ }
+
+ memcpy(&sesslist->sessions[sesslist->count], current,
+ sizeof(struct sessionid));
+
+ sesslist->count++;
+
+ DEBUG(7,("gather_sessioninfo session from %s@%s\n",
+ current->username, current->remote_machine));
+
+ return 0;
+}
+
+/********************************************************************
+********************************************************************/
+
+int list_sessions(TALLOC_CTX *mem_ctx, struct sessionid **session_list)
+{
+ struct session_list sesslist;
+
+ sesslist.mem_ctx = mem_ctx;
+ sesslist.count = 0;
+ sesslist.sessions = NULL;
+
+ if (!session_traverse(gather_sessioninfo, (void *) &sesslist)) {
+ DEBUG(3, ("Session traverse failed\n"));
+ SAFE_FREE(sesslist.sessions);
+ *session_list = NULL;
+ return 0;
+ }
+
+ *session_list = sesslist.sessions;
+ return sesslist.count;
+}
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
new file mode 100644
index 0000000000..9c9d0a97bc
--- /dev/null
+++ b/source3/smbd/sesssetup.c
@@ -0,0 +1,1820 @@
+/*
+ Unix SMB/CIFS implementation.
+ handle SMBsessionsetup
+ Copyright (C) Andrew Tridgell 1998-2001
+ Copyright (C) Andrew Bartlett 2001
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
+ Copyright (C) Luke Howard 2003
+ Copyright (C) Volker Lendecke 2007
+ Copyright (C) Jeremy Allison 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern struct auth_context *negprot_global_auth_context;
+extern bool global_encrypted_passwords_negotiated;
+extern bool global_spnego_negotiated;
+extern enum protocol_types Protocol;
+extern int max_send;
+
+uint32 global_client_caps = 0;
+
+/*
+ on a logon error possibly map the error to success if "map to guest"
+ is set approriately
+*/
+static NTSTATUS do_map_to_guest(NTSTATUS status,
+ auth_serversupplied_info **server_info,
+ const char *user, const char *domain)
+{
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
+ if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
+ (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
+ DEBUG(3,("No such user %s [%s] - using guest account\n",
+ user, domain));
+ status = make_server_info_guest(NULL, server_info);
+ }
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
+ if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
+ DEBUG(3,("Registered username %s for guest access\n",
+ user));
+ status = make_server_info_guest(NULL, server_info);
+ }
+ }
+
+ return status;
+}
+
+/****************************************************************************
+ Add the standard 'Samba' signature to the end of the session setup.
+****************************************************************************/
+
+static int push_signature(uint8 **outbuf)
+{
+ char *lanman;
+ int result, tmp;
+
+ result = 0;
+
+ tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
+
+ if (tmp == -1) return -1;
+ result += tmp;
+
+ if (asprintf(&lanman, "Samba %s", SAMBA_VERSION_STRING) != -1) {
+ tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
+ SAFE_FREE(lanman);
+ }
+ else {
+ tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
+ }
+
+ if (tmp == -1) return -1;
+ result += tmp;
+
+ tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
+
+ if (tmp == -1) return -1;
+ result += tmp;
+
+ return result;
+}
+
+/****************************************************************************
+ Start the signing engine if needed. Don't fail signing here.
+****************************************************************************/
+
+static void sessionsetup_start_signing_engine(
+ const auth_serversupplied_info *server_info,
+ const uint8 *inbuf)
+{
+ if (!server_info->guest && !srv_signing_started()) {
+ /* We need to start the signing engine
+ * here but a W2K client sends the old
+ * "BSRSPYL " signature instead of the
+ * correct one. Subsequent packets will
+ * be correct.
+ */
+ srv_check_sign_mac((char *)inbuf, False);
+ }
+}
+
+/****************************************************************************
+ Send a security blob via a session setup reply.
+****************************************************************************/
+
+static void reply_sesssetup_blob(struct smb_request *req,
+ DATA_BLOB blob,
+ NTSTATUS nt_status)
+{
+ if (!NT_STATUS_IS_OK(nt_status) &&
+ !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ reply_nterror(req, nt_status_squash(nt_status));
+ } else {
+ nt_status = nt_status_squash(nt_status);
+ SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
+ SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
+ SSVAL(req->outbuf, smb_vwv3, blob.length);
+
+ if ((message_push_blob(&req->outbuf, blob) == -1)
+ || (push_signature(&req->outbuf) == -1)) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ }
+ }
+
+ show_msg((char *)req->outbuf);
+ srv_send_smb(smbd_server_fd(),(char *)req->outbuf,req->encrypted);
+ TALLOC_FREE(req->outbuf);
+}
+
+/****************************************************************************
+ Do a 'guest' logon, getting back the
+****************************************************************************/
+
+static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
+{
+ struct auth_context *auth_context;
+ auth_usersupplied_info *user_info = NULL;
+
+ NTSTATUS nt_status;
+ unsigned char chal[8];
+
+ ZERO_STRUCT(chal);
+
+ DEBUG(3,("Got anonymous request\n"));
+
+ if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context,
+ chal))) {
+ return nt_status;
+ }
+
+ if (!make_user_info_guest(&user_info)) {
+ (auth_context->free)(&auth_context);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ nt_status = auth_context->check_ntlm_password(auth_context,
+ user_info,
+ server_info);
+ (auth_context->free)(&auth_context);
+ free_user_info(&user_info);
+ return nt_status;
+}
+
+
+#ifdef HAVE_KRB5
+
+#if 0
+/* Experiment that failed. See "only happens with a KDC" comment below. */
+/****************************************************************************
+ Cerate a clock skew error blob for a Windows client.
+****************************************************************************/
+
+static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
+{
+ krb5_context context = NULL;
+ krb5_error_code kerr = 0;
+ krb5_data reply;
+ krb5_principal host_princ = NULL;
+ char *host_princ_s = NULL;
+ bool ret = False;
+
+ *pblob_out = data_blob_null;
+
+ initialize_krb5_error_table();
+ kerr = krb5_init_context(&context);
+ if (kerr) {
+ return False;
+ }
+ /* Create server principal. */
+ asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
+ if (!host_princ_s) {
+ goto out;
+ }
+ strlower_m(host_princ_s);
+
+ kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
+ if (kerr) {
+ DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
+ "for name %s: Error %s\n",
+ host_princ_s, error_message(kerr) ));
+ goto out;
+ }
+
+ kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
+ host_princ, &reply);
+ if (kerr) {
+ DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
+ "failed: Error %s\n",
+ error_message(kerr) ));
+ goto out;
+ }
+
+ *pblob_out = data_blob(reply.data, reply.length);
+ kerberos_free_data_contents(context,&reply);
+ ret = True;
+
+ out:
+
+ if (host_princ_s) {
+ SAFE_FREE(host_princ_s);
+ }
+ if (host_princ) {
+ krb5_free_principal(context, host_princ);
+ }
+ krb5_free_context(context);
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ Reply to a session setup spnego negotiate packet for kerberos.
+****************************************************************************/
+
+static void reply_spnego_kerberos(struct smb_request *req,
+ DATA_BLOB *secblob,
+ const char *mechOID,
+ uint16 vuid,
+ bool *p_invalidate_vuid)
+{
+ TALLOC_CTX *mem_ctx;
+ DATA_BLOB ticket;
+ char *client, *p, *domain;
+ fstring netbios_domain_name;
+ struct passwd *pw;
+ fstring user;
+ int sess_vuid = req->vuid;
+ NTSTATUS ret = NT_STATUS_OK;
+ struct PAC_DATA *pac_data = NULL;
+ DATA_BLOB ap_rep, ap_rep_wrapped, response;
+ auth_serversupplied_info *server_info = NULL;
+ DATA_BLOB session_key = data_blob_null;
+ uint8 tok_id[2];
+ DATA_BLOB nullblob = data_blob_null;
+ fstring real_username;
+ bool map_domainuser_to_guest = False;
+ bool username_was_mapped;
+ struct PAC_LOGON_INFO *logon_info = NULL;
+
+ ZERO_STRUCT(ticket);
+ ZERO_STRUCT(ap_rep);
+ ZERO_STRUCT(ap_rep_wrapped);
+ ZERO_STRUCT(response);
+
+ /* Normally we will always invalidate the intermediate vuid. */
+ *p_invalidate_vuid = True;
+
+ mem_ctx = talloc_init("reply_spnego_kerberos");
+ if (mem_ctx == NULL) {
+ reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
+ return;
+ }
+
+ if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
+ talloc_destroy(mem_ctx);
+ reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
+ return;
+ }
+
+ ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
+ &client, &pac_data, &ap_rep,
+ &session_key, True);
+
+ data_blob_free(&ticket);
+
+ if (!NT_STATUS_IS_OK(ret)) {
+#if 0
+ /* Experiment that failed.
+ * See "only happens with a KDC" comment below. */
+
+ if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
+
+ /*
+ * Windows in this case returns
+ * NT_STATUS_MORE_PROCESSING_REQUIRED
+ * with a negTokenTarg blob containing an krb5_error
+ * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
+ * The client then fixes its clock and continues rather
+ * than giving an error. JRA.
+ * -- Looks like this only happens with a KDC. JRA.
+ */
+
+ bool ok = make_krb5_skew_error(&ap_rep);
+ if (!ok) {
+ talloc_destroy(mem_ctx);
+ return ERROR_NT(nt_status_squash(
+ NT_STATUS_LOGON_FAILURE));
+ }
+ ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
+ TOK_ID_KRB_ERROR);
+ response = spnego_gen_auth_response(&ap_rep_wrapped,
+ ret, OID_KERBEROS5_OLD);
+ reply_sesssetup_blob(conn, inbuf, outbuf, response,
+ NT_STATUS_MORE_PROCESSING_REQUIRED);
+
+ /*
+ * In this one case we don't invalidate the
+ * intermediate vuid as we're expecting the client
+ * to re-use it for the next sessionsetupX packet. JRA.
+ */
+
+ *p_invalidate_vuid = False;
+
+ data_blob_free(&ap_rep);
+ data_blob_free(&ap_rep_wrapped);
+ data_blob_free(&response);
+ talloc_destroy(mem_ctx);
+ return -1; /* already replied */
+ }
+#else
+ if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
+ ret = NT_STATUS_LOGON_FAILURE;
+ }
+#endif
+ DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
+ nt_errstr(ret)));
+ talloc_destroy(mem_ctx);
+ reply_nterror(req, nt_status_squash(ret));
+ return;
+ }
+
+ DEBUG(3,("Ticket name is [%s]\n", client));
+
+ p = strchr_m(client, '@');
+ if (!p) {
+ DEBUG(3,("Doesn't look like a valid principal\n"));
+ data_blob_free(&ap_rep);
+ data_blob_free(&session_key);
+ SAFE_FREE(client);
+ talloc_destroy(mem_ctx);
+ reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
+ return;
+ }
+
+ *p = 0;
+
+ /* save the PAC data if we have it */
+
+ if (pac_data) {
+ logon_info = get_logon_info_from_pac(pac_data);
+ if (logon_info) {
+ netsamlogon_cache_store( client, &logon_info->info3 );
+ }
+ }
+
+ if (!strequal(p+1, lp_realm())) {
+ DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
+ if (!lp_allow_trusted_domains()) {
+ data_blob_free(&ap_rep);
+ data_blob_free(&session_key);
+ SAFE_FREE(client);
+ talloc_destroy(mem_ctx);
+ reply_nterror(req, nt_status_squash(
+ NT_STATUS_LOGON_FAILURE));
+ return;
+ }
+ }
+
+ /* this gives a fully qualified user name (ie. with full realm).
+ that leads to very long usernames, but what else can we do? */
+
+ domain = p+1;
+
+ if (logon_info && logon_info->info3.base.domain.string) {
+ fstrcpy(netbios_domain_name,
+ logon_info->info3.base.domain.string);
+ domain = netbios_domain_name;
+ DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
+
+ } else {
+
+ /* If we have winbind running, we can (and must) shorten the
+ username by using the short netbios name. Otherwise we will
+ have inconsistent user names. With Kerberos, we get the
+ fully qualified realm, with ntlmssp we get the short
+ name. And even w2k3 does use ntlmssp if you for example
+ connect to an ip address. */
+
+ wbcErr wbc_status;
+ struct wbcDomainInfo *info = NULL;
+
+ DEBUG(10, ("Mapping [%s] to short name\n", domain));
+
+ wbc_status = wbcDomainInfo(domain, &info);
+
+ if (WBC_ERROR_IS_OK(wbc_status)) {
+
+ fstrcpy(netbios_domain_name,
+ info->short_name);
+
+ wbcFreeMemory(info);
+ domain = netbios_domain_name;
+ DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
+ } else {
+ DEBUG(3, ("Could not find short name: %s\n",
+ wbcErrorString(wbc_status)));
+ }
+ }
+
+ fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
+
+ /* lookup the passwd struct, create a new user if necessary */
+
+ username_was_mapped = map_username( user );
+
+ pw = smb_getpwnam( mem_ctx, user, real_username, True );
+
+ if (pw) {
+ /* if a real user check pam account restrictions */
+ /* only really perfomed if "obey pam restriction" is true */
+ /* do this before an eventual mapping to guest occurs */
+ ret = smb_pam_accountcheck(pw->pw_name);
+ if ( !NT_STATUS_IS_OK(ret)) {
+ DEBUG(1,("PAM account restriction "
+ "prevents user login\n"));
+ data_blob_free(&ap_rep);
+ data_blob_free(&session_key);
+ TALLOC_FREE(mem_ctx);
+ reply_nterror(req, nt_status_squash(ret));
+ return;
+ }
+ }
+
+ if (!pw) {
+
+ /* this was originally the behavior of Samba 2.2, if a user
+ did not have a local uid but has been authenticated, then
+ map them to a guest account */
+
+ if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
+ map_domainuser_to_guest = True;
+ fstrcpy(user,lp_guestaccount());
+ pw = smb_getpwnam( mem_ctx, user, real_username, True );
+ }
+
+ /* extra sanity check that the guest account is valid */
+
+ if ( !pw ) {
+ DEBUG(1,("Username %s is invalid on this system\n",
+ user));
+ SAFE_FREE(client);
+ data_blob_free(&ap_rep);
+ data_blob_free(&session_key);
+ TALLOC_FREE(mem_ctx);
+ reply_nterror(req, nt_status_squash(
+ NT_STATUS_LOGON_FAILURE));
+ return;
+ }
+ }
+
+ /* setup the string used by %U */
+
+ sub_set_smb_name( real_username );
+ reload_services(True);
+
+ if ( map_domainuser_to_guest ) {
+ make_server_info_guest(NULL, &server_info);
+ } else if (logon_info) {
+ /* pass the unmapped username here since map_username()
+ will be called again from inside make_server_info_info3() */
+
+ ret = make_server_info_info3(mem_ctx, client, domain,
+ &server_info, &logon_info->info3);
+ if ( !NT_STATUS_IS_OK(ret) ) {
+ DEBUG(1,("make_server_info_info3 failed: %s!\n",
+ nt_errstr(ret)));
+ SAFE_FREE(client);
+ data_blob_free(&ap_rep);
+ data_blob_free(&session_key);
+ TALLOC_FREE(mem_ctx);
+ reply_nterror(req, nt_status_squash(ret));
+ return;
+ }
+
+ } else {
+ ret = make_server_info_pw(&server_info, real_username, pw);
+
+ if ( !NT_STATUS_IS_OK(ret) ) {
+ DEBUG(1,("make_server_info_pw failed: %s!\n",
+ nt_errstr(ret)));
+ SAFE_FREE(client);
+ data_blob_free(&ap_rep);
+ data_blob_free(&session_key);
+ TALLOC_FREE(mem_ctx);
+ reply_nterror(req, nt_status_squash(ret));
+ return;
+ }
+
+ /* make_server_info_pw does not set the domain. Without this
+ * we end up with the local netbios name in substitutions for
+ * %D. */
+
+ if (server_info->sam_account != NULL) {
+ pdb_set_domain(server_info->sam_account,
+ domain, PDB_SET);
+ }
+ }
+
+ server_info->nss_token |= username_was_mapped;
+
+ /* we need to build the token for the user. make_server_info_guest()
+ already does this */
+
+ if ( !server_info->ptok ) {
+ ret = create_local_token( server_info );
+ if ( !NT_STATUS_IS_OK(ret) ) {
+ DEBUG(10,("failed to create local token: %s\n",
+ nt_errstr(ret)));
+ SAFE_FREE(client);
+ data_blob_free(&ap_rep);
+ data_blob_free(&session_key);
+ TALLOC_FREE( mem_ctx );
+ TALLOC_FREE( server_info );
+ reply_nterror(req, nt_status_squash(ret));
+ return;
+ }
+ }
+
+ /* register_existing_vuid keeps the server info */
+ /* register_existing_vuid takes ownership of session_key on success,
+ * no need to free after this on success. A better interface would copy
+ * it.... */
+
+ if (!is_partial_auth_vuid(sess_vuid)) {
+ sess_vuid = register_initial_vuid();
+ }
+
+ data_blob_free(&server_info->user_session_key);
+ server_info->user_session_key = session_key;
+ session_key = data_blob_null;
+
+ sess_vuid = register_existing_vuid(sess_vuid,
+ server_info,
+ nullblob,
+ client);
+
+ SAFE_FREE(client);
+
+ reply_outbuf(req, 4, 0);
+ SSVAL(req->outbuf,smb_uid,sess_vuid);
+
+ if (sess_vuid == UID_FIELD_INVALID ) {
+ ret = NT_STATUS_LOGON_FAILURE;
+ } else {
+ /* current_user_info is changed on new vuid */
+ reload_services( True );
+
+ SSVAL(req->outbuf, smb_vwv3, 0);
+
+ if (server_info->guest) {
+ SSVAL(req->outbuf,smb_vwv2,1);
+ }
+
+ SSVAL(req->outbuf, smb_uid, sess_vuid);
+
+ sessionsetup_start_signing_engine(server_info, req->inbuf);
+ /* Successful logon. Keep this vuid. */
+ *p_invalidate_vuid = False;
+ }
+
+ /* wrap that up in a nice GSS-API wrapping */
+ if (NT_STATUS_IS_OK(ret)) {
+ ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
+ TOK_ID_KRB_AP_REP);
+ } else {
+ ap_rep_wrapped = data_blob_null;
+ }
+ response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
+ mechOID);
+ reply_sesssetup_blob(req, response, ret);
+
+ data_blob_free(&ap_rep);
+ data_blob_free(&ap_rep_wrapped);
+ data_blob_free(&response);
+ TALLOC_FREE(mem_ctx);
+}
+
+#endif
+
+/****************************************************************************
+ Send a session setup reply, wrapped in SPNEGO.
+ Get vuid and check first.
+ End the NTLMSSP exchange context if we are OK/complete fail
+ This should be split into two functions, one to handle each
+ leg of the NTLM auth steps.
+***************************************************************************/
+
+static void reply_spnego_ntlmssp(struct smb_request *req,
+ uint16 vuid,
+ AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
+ DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
+ const char *OID,
+ bool wrap)
+{
+ DATA_BLOB response;
+ struct auth_serversupplied_info *server_info = NULL;
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ server_info = (*auth_ntlmssp_state)->server_info;
+ } else {
+ nt_status = do_map_to_guest(nt_status,
+ &server_info,
+ (*auth_ntlmssp_state)->ntlmssp_state->user,
+ (*auth_ntlmssp_state)->ntlmssp_state->domain);
+ }
+
+ reply_outbuf(req, 4, 0);
+
+ SSVAL(req->outbuf, smb_uid, vuid);
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DATA_BLOB nullblob = data_blob_null;
+
+ if (!is_partial_auth_vuid(vuid)) {
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ goto out;
+ }
+
+ data_blob_free(&server_info->user_session_key);
+ server_info->user_session_key =
+ data_blob_talloc(
+ server_info,
+ (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
+ (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
+
+ /* register_existing_vuid keeps the server info */
+ if (register_existing_vuid(vuid,
+ server_info, nullblob,
+ (*auth_ntlmssp_state)->ntlmssp_state->user) !=
+ vuid) {
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ goto out;
+ }
+
+ (*auth_ntlmssp_state)->server_info = NULL;
+
+ /* current_user_info is changed on new vuid */
+ reload_services( True );
+
+ SSVAL(req->outbuf, smb_vwv3, 0);
+
+ if (server_info->guest) {
+ SSVAL(req->outbuf,smb_vwv2,1);
+ }
+
+ sessionsetup_start_signing_engine(server_info,
+ (uint8 *)req->inbuf);
+ }
+
+ out:
+
+ if (wrap) {
+ response = spnego_gen_auth_response(ntlmssp_blob,
+ nt_status, OID);
+ } else {
+ response = *ntlmssp_blob;
+ }
+
+ reply_sesssetup_blob(req, response, nt_status);
+ if (wrap) {
+ data_blob_free(&response);
+ }
+
+ /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
+ and the other end, that we are not finished yet. */
+
+ if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ /* NB. This is *NOT* an error case. JRA */
+ auth_ntlmssp_end(auth_ntlmssp_state);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ /* Kill the intermediate vuid */
+ invalidate_vuid(vuid);
+ }
+ }
+}
+
+/****************************************************************************
+ Is this a krb5 mechanism ?
+****************************************************************************/
+
+NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
+ DATA_BLOB *pblob_out,
+ char **kerb_mechOID)
+{
+ char *OIDs[ASN1_MAX_OIDS];
+ int i;
+ NTSTATUS ret = NT_STATUS_OK;
+
+ *kerb_mechOID = NULL;
+
+ /* parse out the OIDs and the first sec blob */
+ if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ /* only look at the first OID for determining the mechToken --
+ according to RFC2478, we should choose the one we want
+ and renegotiate, but i smell a client bug here..
+
+ Problem observed when connecting to a member (samba box)
+ of an AD domain as a user in a Samba domain. Samba member
+ server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
+ client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
+ NTLMSSP mechtoken. --jerry */
+
+#ifdef HAVE_KRB5
+ if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
+ strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
+ *kerb_mechOID = SMB_STRDUP(OIDs[0]);
+ if (*kerb_mechOID == NULL) {
+ ret = NT_STATUS_NO_MEMORY;
+ }
+ }
+#endif
+
+ for (i=0;OIDs[i];i++) {
+ DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
+ free(OIDs[i]);
+ }
+ return ret;
+}
+
+/****************************************************************************
+ Fall back from krb5 to NTLMSSP.
+****************************************************************************/
+
+static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
+ uint16 vuid)
+{
+ DATA_BLOB response;
+
+ reply_outbuf(req, 4, 0);
+ SSVAL(req->outbuf,smb_uid,vuid);
+
+ DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
+ "but set to downgrade to NTLMSSP\n"));
+
+ response = spnego_gen_auth_response(NULL,
+ NT_STATUS_MORE_PROCESSING_REQUIRED,
+ OID_NTLMSSP);
+ reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
+ data_blob_free(&response);
+}
+
+/****************************************************************************
+ Reply to a session setup spnego negotiate packet.
+****************************************************************************/
+
+static void reply_spnego_negotiate(struct smb_request *req,
+ uint16 vuid,
+ DATA_BLOB blob1,
+ AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
+{
+ DATA_BLOB secblob;
+ DATA_BLOB chal;
+ char *kerb_mech = NULL;
+ NTSTATUS status;
+
+ status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* Kill the intermediate vuid */
+ invalidate_vuid(vuid);
+ reply_nterror(req, nt_status_squash(status));
+ return;
+ }
+
+ DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
+ (unsigned long)secblob.length));
+
+#ifdef HAVE_KRB5
+ if (kerb_mech && ((lp_security()==SEC_ADS) ||
+ lp_use_kerberos_keytab()) ) {
+ bool destroy_vuid = True;
+ reply_spnego_kerberos(req, &secblob, kerb_mech,
+ vuid, &destroy_vuid);
+ data_blob_free(&secblob);
+ if (destroy_vuid) {
+ /* Kill the intermediate vuid */
+ invalidate_vuid(vuid);
+ }
+ SAFE_FREE(kerb_mech);
+ return;
+ }
+#endif
+
+ if (*auth_ntlmssp_state) {
+ auth_ntlmssp_end(auth_ntlmssp_state);
+ }
+
+ if (kerb_mech) {
+ data_blob_free(&secblob);
+ /* The mechtoken is a krb5 ticket, but
+ * we need to fall back to NTLM. */
+ reply_spnego_downgrade_to_ntlmssp(req, vuid);
+ SAFE_FREE(kerb_mech);
+ return;
+ }
+
+ status = auth_ntlmssp_start(auth_ntlmssp_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* Kill the intermediate vuid */
+ invalidate_vuid(vuid);
+ reply_nterror(req, nt_status_squash(status));
+ return;
+ }
+
+ status = auth_ntlmssp_update(*auth_ntlmssp_state,
+ secblob, &chal);
+
+ data_blob_free(&secblob);
+
+ reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
+ &chal, status, OID_NTLMSSP, true);
+
+ data_blob_free(&chal);
+
+ /* already replied */
+ return;
+}
+
+/****************************************************************************
+ Reply to a session setup spnego auth packet.
+****************************************************************************/
+
+static void reply_spnego_auth(struct smb_request *req,
+ uint16 vuid,
+ DATA_BLOB blob1,
+ AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
+{
+ DATA_BLOB auth = data_blob_null;
+ DATA_BLOB auth_reply = data_blob_null;
+ DATA_BLOB secblob = data_blob_null;
+ NTSTATUS status = NT_STATUS_LOGON_FAILURE;
+
+ if (!spnego_parse_auth(blob1, &auth)) {
+#if 0
+ file_save("auth.dat", blob1.data, blob1.length);
+#endif
+ /* Kill the intermediate vuid */
+ invalidate_vuid(vuid);
+
+ reply_nterror(req, nt_status_squash(
+ NT_STATUS_LOGON_FAILURE));
+ return;
+ }
+
+ if (auth.data[0] == ASN1_APPLICATION(0)) {
+ /* Might be a second negTokenTarg packet */
+ char *kerb_mech = NULL;
+
+ status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ /* Kill the intermediate vuid */
+ invalidate_vuid(vuid);
+ reply_nterror(req, nt_status_squash(status));
+ return;
+ }
+
+ DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
+ (unsigned long)secblob.length));
+#ifdef HAVE_KRB5
+ if (kerb_mech && ((lp_security()==SEC_ADS) ||
+ lp_use_kerberos_keytab()) ) {
+ bool destroy_vuid = True;
+ reply_spnego_kerberos(req, &secblob, kerb_mech,
+ vuid, &destroy_vuid);
+ data_blob_free(&secblob);
+ data_blob_free(&auth);
+ if (destroy_vuid) {
+ /* Kill the intermediate vuid */
+ invalidate_vuid(vuid);
+ }
+ SAFE_FREE(kerb_mech);
+ return;
+ }
+#endif
+ /* Can't blunder into NTLMSSP auth if we have
+ * a krb5 ticket. */
+
+ if (kerb_mech) {
+ /* Kill the intermediate vuid */
+ invalidate_vuid(vuid);
+ DEBUG(3,("reply_spnego_auth: network "
+ "misconfiguration, client sent us a "
+ "krb5 ticket and kerberos security "
+ "not enabled"));
+ reply_nterror(req, nt_status_squash(
+ NT_STATUS_LOGON_FAILURE));
+ SAFE_FREE(kerb_mech);
+ }
+ }
+
+ /* If we get here it wasn't a negTokenTarg auth packet. */
+ data_blob_free(&secblob);
+
+ if (!*auth_ntlmssp_state) {
+ status = auth_ntlmssp_start(auth_ntlmssp_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* Kill the intermediate vuid */
+ invalidate_vuid(vuid);
+ reply_nterror(req, nt_status_squash(status));
+ return;
+ }
+ }
+
+ status = auth_ntlmssp_update(*auth_ntlmssp_state,
+ auth, &auth_reply);
+
+ data_blob_free(&auth);
+
+ /* Don't send the mechid as we've already sent this (RFC4178). */
+
+ reply_spnego_ntlmssp(req, vuid,
+ auth_ntlmssp_state,
+ &auth_reply, status, NULL, true);
+
+ data_blob_free(&auth_reply);
+
+ /* and tell smbd that we have already replied to this packet */
+ return;
+}
+
+/****************************************************************************
+ List to store partial SPNEGO auth fragments.
+****************************************************************************/
+
+static struct pending_auth_data *pd_list;
+
+/****************************************************************************
+ Delete an entry on the list.
+****************************************************************************/
+
+static void delete_partial_auth(struct pending_auth_data *pad)
+{
+ if (!pad) {
+ return;
+ }
+ DLIST_REMOVE(pd_list, pad);
+ data_blob_free(&pad->partial_data);
+ SAFE_FREE(pad);
+}
+
+/****************************************************************************
+ Search for a partial SPNEGO auth fragment matching an smbpid.
+****************************************************************************/
+
+static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
+{
+ struct pending_auth_data *pad;
+
+ for (pad = pd_list; pad; pad = pad->next) {
+ if (pad->smbpid == smbpid) {
+ break;
+ }
+ }
+ return pad;
+}
+
+/****************************************************************************
+ Check the size of an SPNEGO blob. If we need more return
+ NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
+ the blob to be more than 64k.
+****************************************************************************/
+
+static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
+ DATA_BLOB *pblob)
+{
+ struct pending_auth_data *pad = NULL;
+ ASN1_DATA data;
+ size_t needed_len = 0;
+
+ pad = get_pending_auth_data(smbpid);
+
+ /* Ensure we have some data. */
+ if (pblob->length == 0) {
+ /* Caller can cope. */
+ DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
+ delete_partial_auth(pad);
+ return NT_STATUS_OK;
+ }
+
+ /* Were we waiting for more data ? */
+ if (pad) {
+ DATA_BLOB tmp_blob;
+ size_t copy_len = MIN(65536, pblob->length);
+
+ /* Integer wrap paranoia.... */
+
+ if (pad->partial_data.length + copy_len <
+ pad->partial_data.length ||
+ pad->partial_data.length + copy_len < copy_len) {
+
+ DEBUG(2,("check_spnego_blob_complete: integer wrap "
+ "pad->partial_data.length = %u, "
+ "copy_len = %u\n",
+ (unsigned int)pad->partial_data.length,
+ (unsigned int)copy_len ));
+
+ delete_partial_auth(pad);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ DEBUG(10,("check_spnego_blob_complete: "
+ "pad->partial_data.length = %u, "
+ "pad->needed_len = %u, "
+ "copy_len = %u, "
+ "pblob->length = %u,\n",
+ (unsigned int)pad->partial_data.length,
+ (unsigned int)pad->needed_len,
+ (unsigned int)copy_len,
+ (unsigned int)pblob->length ));
+
+ tmp_blob = data_blob(NULL,
+ pad->partial_data.length + copy_len);
+
+ /* Concatenate the two (up to copy_len) bytes. */
+ memcpy(tmp_blob.data,
+ pad->partial_data.data,
+ pad->partial_data.length);
+ memcpy(tmp_blob.data + pad->partial_data.length,
+ pblob->data,
+ copy_len);
+
+ /* Replace the partial data. */
+ data_blob_free(&pad->partial_data);
+ pad->partial_data = tmp_blob;
+ ZERO_STRUCT(tmp_blob);
+
+ /* Are we done ? */
+ if (pblob->length >= pad->needed_len) {
+ /* Yes, replace pblob. */
+ data_blob_free(pblob);
+ *pblob = pad->partial_data;
+ ZERO_STRUCT(pad->partial_data);
+ delete_partial_auth(pad);
+ return NT_STATUS_OK;
+ }
+
+ /* Still need more data. */
+ pad->needed_len -= copy_len;
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
+ (pblob->data[0] != ASN1_CONTEXT(1))) {
+ /* Not something we can determine the
+ * length of.
+ */
+ return NT_STATUS_OK;
+ }
+
+ /* This is a new SPNEGO sessionsetup - see if
+ * the data given in this blob is enough.
+ */
+
+ asn1_load(&data, *pblob);
+ asn1_start_tag(&data, pblob->data[0]);
+ if (data.has_error || data.nesting == NULL) {
+ asn1_free(&data);
+ /* Let caller catch. */
+ return NT_STATUS_OK;
+ }
+
+ /* Integer wrap paranoia.... */
+
+ if (data.nesting->taglen + data.nesting->start < data.nesting->taglen ||
+ data.nesting->taglen + data.nesting->start < data.nesting->start) {
+
+ DEBUG(2,("check_spnego_blob_complete: integer wrap "
+ "data.nesting->taglen = %u, "
+ "data.nesting->start = %u\n",
+ (unsigned int)data.nesting->taglen,
+ (unsigned int)data.nesting->start ));
+
+ asn1_free(&data);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Total length of the needed asn1 is the tag length
+ * plus the current offset. */
+
+ needed_len = data.nesting->taglen + data.nesting->start;
+ asn1_free(&data);
+
+ DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
+ "pblob->length = %u\n",
+ (unsigned int)needed_len,
+ (unsigned int)pblob->length ));
+
+ if (needed_len <= pblob->length) {
+ /* Nothing to do - blob is complete. */
+ return NT_STATUS_OK;
+ }
+
+ /* Refuse the blob if it's bigger than 64k. */
+ if (needed_len > 65536) {
+ DEBUG(2,("check_spnego_blob_complete: needed_len "
+ "too large (%u)\n",
+ (unsigned int)needed_len ));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* We must store this blob until complete. */
+ if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ pad->needed_len = needed_len - pblob->length;
+ pad->partial_data = data_blob(pblob->data, pblob->length);
+ if (pad->partial_data.data == NULL) {
+ SAFE_FREE(pad);
+ return NT_STATUS_NO_MEMORY;
+ }
+ pad->smbpid = smbpid;
+ pad->vuid = vuid;
+ DLIST_ADD(pd_list, pad);
+
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+/****************************************************************************
+ Reply to a session setup command.
+ conn POINTER CAN BE NULL HERE !
+****************************************************************************/
+
+static void reply_sesssetup_and_X_spnego(struct smb_request *req)
+{
+ uint8 *p;
+ DATA_BLOB blob1;
+ size_t bufrem;
+ fstring native_os, native_lanman, primary_domain;
+ const char *p2;
+ uint16 data_blob_len = SVAL(req->inbuf, smb_vwv7);
+ enum remote_arch_types ra_type = get_remote_arch();
+ int vuid = SVAL(req->inbuf,smb_uid);
+ user_struct *vuser = NULL;
+ NTSTATUS status = NT_STATUS_OK;
+ uint16 smbpid = req->smbpid;
+ uint16 smb_flag2 = req->flags2;
+
+ DEBUG(3,("Doing spnego session setup\n"));
+
+ if (global_client_caps == 0) {
+ global_client_caps = IVAL(req->inbuf,smb_vwv10);
+
+ if (!(global_client_caps & CAP_STATUS32)) {
+ remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
+ }
+
+ }
+
+ p = (uint8 *)smb_buf(req->inbuf);
+
+ if (data_blob_len == 0) {
+ /* an invalid request */
+ reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
+ return;
+ }
+
+ bufrem = smb_bufrem(req->inbuf, p);
+ /* pull the spnego blob */
+ blob1 = data_blob(p, MIN(bufrem, data_blob_len));
+
+#if 0
+ file_save("negotiate.dat", blob1.data, blob1.length);
+#endif
+
+ p2 = (char *)req->inbuf + smb_vwv13 + data_blob_len;
+ p2 += srvstr_pull_buf(req->inbuf, smb_flag2, native_os, p2,
+ sizeof(native_os), STR_TERMINATE);
+ p2 += srvstr_pull_buf(req->inbuf, smb_flag2, native_lanman, p2,
+ sizeof(native_lanman), STR_TERMINATE);
+ p2 += srvstr_pull_buf(req->inbuf, smb_flag2, primary_domain, p2,
+ sizeof(primary_domain), STR_TERMINATE);
+ DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
+ native_os, native_lanman, primary_domain));
+
+ if ( ra_type == RA_WIN2K ) {
+ /* Vista sets neither the OS or lanman strings */
+
+ if ( !strlen(native_os) && !strlen(native_lanman) )
+ set_remote_arch(RA_VISTA);
+
+ /* Windows 2003 doesn't set the native lanman string,
+ but does set primary domain which is a bug I think */
+
+ if ( !strlen(native_lanman) ) {
+ ra_lanman_string( primary_domain );
+ } else {
+ ra_lanman_string( native_lanman );
+ }
+ }
+
+ /* Did we get a valid vuid ? */
+ if (!is_partial_auth_vuid(vuid)) {
+ /* No, then try and see if this is an intermediate sessionsetup
+ * for a large SPNEGO packet. */
+ struct pending_auth_data *pad = get_pending_auth_data(smbpid);
+ if (pad) {
+ DEBUG(10,("reply_sesssetup_and_X_spnego: found "
+ "pending vuid %u\n",
+ (unsigned int)pad->vuid ));
+ vuid = pad->vuid;
+ }
+ }
+
+ /* Do we have a valid vuid now ? */
+ if (!is_partial_auth_vuid(vuid)) {
+ /* No, start a new authentication setup. */
+ vuid = register_initial_vuid();
+ if (vuid == UID_FIELD_INVALID) {
+ data_blob_free(&blob1);
+ reply_nterror(req, nt_status_squash(
+ NT_STATUS_INVALID_PARAMETER));
+ return;
+ }
+ }
+
+ vuser = get_partial_auth_user_struct(vuid);
+ /* This MUST be valid. */
+ if (!vuser) {
+ smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
+ }
+
+ /* Large (greater than 4k) SPNEGO blobs are split into multiple
+ * sessionsetup requests as the Windows limit on the security blob
+ * field is 4k. Bug #4400. JRA.
+ */
+
+ status = check_spnego_blob_complete(smbpid, vuid, &blob1);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (!NT_STATUS_EQUAL(status,
+ NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ /* Real error - kill the intermediate vuid */
+ invalidate_vuid(vuid);
+ }
+ data_blob_free(&blob1);
+ reply_nterror(req, nt_status_squash(status));
+ return;
+ }
+
+ if (blob1.data[0] == ASN1_APPLICATION(0)) {
+
+ /* its a negTokenTarg packet */
+
+ reply_spnego_negotiate(req, vuid, blob1,
+ &vuser->auth_ntlmssp_state);
+ data_blob_free(&blob1);
+ return;
+ }
+
+ if (blob1.data[0] == ASN1_CONTEXT(1)) {
+
+ /* its a auth packet */
+
+ reply_spnego_auth(req, vuid, blob1,
+ &vuser->auth_ntlmssp_state);
+ data_blob_free(&blob1);
+ return;
+ }
+
+ if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
+ DATA_BLOB chal;
+
+ if (!vuser->auth_ntlmssp_state) {
+ status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* Kill the intermediate vuid */
+ invalidate_vuid(vuid);
+ data_blob_free(&blob1);
+ reply_nterror(req, nt_status_squash(status));
+ return;
+ }
+ }
+
+ status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
+ blob1, &chal);
+
+ data_blob_free(&blob1);
+
+ reply_spnego_ntlmssp(req, vuid,
+ &vuser->auth_ntlmssp_state,
+ &chal, status, OID_NTLMSSP, false);
+ data_blob_free(&chal);
+ return;
+ }
+
+ /* what sort of packet is this? */
+ DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
+
+ data_blob_free(&blob1);
+
+ reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
+}
+
+/****************************************************************************
+ On new VC == 0, shutdown *all* old connections and users.
+ It seems that only NT4.x does this. At W2K and above (XP etc.).
+ a new session setup with VC==0 is ignored.
+****************************************************************************/
+
+static int shutdown_other_smbds(struct db_record *rec,
+ const struct connections_key *key,
+ const struct connections_data *crec,
+ void *private_data)
+{
+ const char *ip = (const char *)private_data;
+
+ if (!process_exists(crec->pid)) {
+ return 0;
+ }
+
+ if (procid_is_me(&crec->pid)) {
+ return 0;
+ }
+
+ if (strcmp(ip, crec->addr) != 0) {
+ return 0;
+ }
+
+ DEBUG(0,("shutdown_other_smbds: shutting down pid %d "
+ "(IP %s)\n", procid_to_pid(&crec->pid), ip));
+
+ messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
+ &data_blob_null);
+ return 0;
+}
+
+static void setup_new_vc_session(void)
+{
+ char addr[INET6_ADDRSTRLEN];
+
+ DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
+ "compatible we would close all old resources.\n"));
+#if 0
+ conn_close_all();
+ invalidate_all_vuids();
+#endif
+ if (lp_reset_on_zero_vc()) {
+ connections_forall(shutdown_other_smbds,
+ CONST_DISCARD(void *,
+ client_addr(get_client_fd(),addr,sizeof(addr))));
+ }
+}
+
+/****************************************************************************
+ Reply to a session setup command.
+****************************************************************************/
+
+void reply_sesssetup_and_X(struct smb_request *req)
+{
+ int sess_vuid;
+ int smb_bufsize;
+ DATA_BLOB lm_resp;
+ DATA_BLOB nt_resp;
+ DATA_BLOB plaintext_password;
+ fstring user;
+ fstring sub_user; /* Sainitised username for substituion */
+ fstring domain;
+ fstring native_os;
+ fstring native_lanman;
+ fstring primary_domain;
+ static bool done_sesssetup = False;
+ auth_usersupplied_info *user_info = NULL;
+ auth_serversupplied_info *server_info = NULL;
+ uint16 smb_flag2 = req->flags2;
+
+ NTSTATUS nt_status;
+
+ bool doencrypt = global_encrypted_passwords_negotiated;
+
+ START_PROFILE(SMBsesssetupX);
+
+ ZERO_STRUCT(lm_resp);
+ ZERO_STRUCT(nt_resp);
+ ZERO_STRUCT(plaintext_password);
+
+ DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
+
+ /* a SPNEGO session setup has 12 command words, whereas a normal
+ NT1 session setup has 13. See the cifs spec. */
+ if (req->wct == 12 &&
+ (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
+
+ if (!global_spnego_negotiated) {
+ DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
+ "at SPNEGO session setup when it was not "
+ "negotiated.\n"));
+ reply_nterror(req, nt_status_squash(
+ NT_STATUS_LOGON_FAILURE));
+ END_PROFILE(SMBsesssetupX);
+ return;
+ }
+
+ if (SVAL(req->inbuf,smb_vwv4) == 0) {
+ setup_new_vc_session();
+ }
+
+ reply_sesssetup_and_X_spnego(req);
+ END_PROFILE(SMBsesssetupX);
+ return;
+ }
+
+ smb_bufsize = SVAL(req->inbuf,smb_vwv2);
+
+ if (Protocol < PROTOCOL_NT1) {
+ uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
+
+ /* Never do NT status codes with protocols before NT1 as we
+ * don't get client caps. */
+ remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
+
+ if ((passlen1 > MAX_PASS_LEN)
+ || (passlen1 > smb_bufrem(req->inbuf,
+ smb_buf(req->inbuf)))) {
+ reply_nterror(req, nt_status_squash(
+ NT_STATUS_INVALID_PARAMETER));
+ END_PROFILE(SMBsesssetupX);
+ return;
+ }
+
+ if (doencrypt) {
+ lm_resp = data_blob(smb_buf(req->inbuf), passlen1);
+ } else {
+ plaintext_password = data_blob(smb_buf(req->inbuf),
+ passlen1+1);
+ /* Ensure null termination */
+ plaintext_password.data[passlen1] = 0;
+ }
+
+ srvstr_pull_buf(req->inbuf, req->flags2, user,
+ smb_buf(req->inbuf)+passlen1, sizeof(user),
+ STR_TERMINATE);
+ *domain = 0;
+
+ } else {
+ uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
+ uint16 passlen2 = SVAL(req->inbuf,smb_vwv8);
+ enum remote_arch_types ra_type = get_remote_arch();
+ char *p = smb_buf(req->inbuf);
+ char *save_p = smb_buf(req->inbuf);
+ uint16 byte_count;
+
+
+ if(global_client_caps == 0) {
+ global_client_caps = IVAL(req->inbuf,smb_vwv11);
+
+ if (!(global_client_caps & CAP_STATUS32)) {
+ remove_from_common_flags2(
+ FLAGS2_32_BIT_ERROR_CODES);
+ }
+
+ /* client_caps is used as final determination if
+ * client is NT or Win95. This is needed to return
+ * the correct error codes in some circumstances.
+ */
+
+ if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
+ ra_type == RA_WIN95) {
+ if(!(global_client_caps & (CAP_NT_SMBS|
+ CAP_STATUS32))) {
+ set_remote_arch( RA_WIN95);
+ }
+ }
+ }
+
+ if (!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;
+ }
+ }
+
+ /* check for nasty tricks */
+ if (passlen1 > MAX_PASS_LEN
+ || passlen1 > smb_bufrem(req->inbuf, p)) {
+ reply_nterror(req, nt_status_squash(
+ NT_STATUS_INVALID_PARAMETER));
+ END_PROFILE(SMBsesssetupX);
+ return;
+ }
+
+ if (passlen2 > MAX_PASS_LEN
+ || passlen2 > smb_bufrem(req->inbuf, p+passlen1)) {
+ reply_nterror(req, nt_status_squash(
+ NT_STATUS_INVALID_PARAMETER));
+ END_PROFILE(SMBsesssetupX);
+ return;
+ }
+
+ /* Save the lanman2 password and the NT md4 password. */
+
+ if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
+ doencrypt = False;
+ }
+
+ if (doencrypt) {
+ lm_resp = data_blob(p, passlen1);
+ nt_resp = data_blob(p+passlen1, passlen2);
+ } else if (lp_security() != SEC_SHARE) {
+ /*
+ * In share level we should ignore any passwords, so
+ * only read them if we're not.
+ */
+ char *pass = NULL;
+ bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
+
+ if (unic && (passlen2 == 0) && passlen1) {
+ /* Only a ascii plaintext password was sent. */
+ (void)srvstr_pull_talloc(talloc_tos(),
+ req->inbuf,
+ req->flags2,
+ &pass,
+ smb_buf(req->inbuf),
+ passlen1,
+ STR_TERMINATE|STR_ASCII);
+ } else {
+ (void)srvstr_pull_talloc(talloc_tos(),
+ req->inbuf,
+ req->flags2,
+ &pass,
+ smb_buf(req->inbuf),
+ unic ? passlen2 : passlen1,
+ STR_TERMINATE);
+ }
+ if (!pass) {
+ reply_nterror(req, nt_status_squash(
+ NT_STATUS_INVALID_PARAMETER));
+ END_PROFILE(SMBsesssetupX);
+ return;
+ }
+ plaintext_password = data_blob(pass, strlen(pass)+1);
+ }
+
+ p += passlen1 + passlen2;
+ p += srvstr_pull_buf(req->inbuf, req->flags2, user, p,
+ sizeof(user), STR_TERMINATE);
+ p += srvstr_pull_buf(req->inbuf, req->flags2, domain, p,
+ sizeof(domain), STR_TERMINATE);
+ p += srvstr_pull_buf(req->inbuf, req->flags2, native_os,
+ p, sizeof(native_os), STR_TERMINATE);
+ p += srvstr_pull_buf(req->inbuf, req->flags2,
+ native_lanman, p, sizeof(native_lanman),
+ STR_TERMINATE);
+
+ /* not documented or decoded by Ethereal but there is one more
+ * string in the extra bytes which is the same as the
+ * PrimaryDomain when using extended security. Windows NT 4
+ * and 2003 use this string to store the native lanman string.
+ * Windows 9x does not include a string here at all so we have
+ * to check if we have any extra bytes left */
+
+ byte_count = SVAL(req->inbuf, smb_vwv13);
+ if ( PTR_DIFF(p, save_p) < byte_count) {
+ p += srvstr_pull_buf(req->inbuf, req->flags2,
+ primary_domain, p,
+ sizeof(primary_domain),
+ STR_TERMINATE);
+ } else {
+ fstrcpy( primary_domain, "null" );
+ }
+
+ DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
+ "PrimaryDomain=[%s]\n",
+ domain, native_os, native_lanman, primary_domain));
+
+ if ( ra_type == RA_WIN2K ) {
+ if ( strlen(native_lanman) == 0 )
+ ra_lanman_string( primary_domain );
+ else
+ ra_lanman_string( native_lanman );
+ }
+
+ }
+
+ if (SVAL(req->inbuf,smb_vwv4) == 0) {
+ setup_new_vc_session();
+ }
+
+ DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
+ domain, user, get_remote_machine_name()));
+
+ if (*user) {
+ if (global_spnego_negotiated) {
+
+ /* This has to be here, because this is a perfectly
+ * valid behaviour for guest logons :-( */
+
+ DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
+ "at 'normal' session setup after "
+ "negotiating spnego.\n"));
+ reply_nterror(req, nt_status_squash(
+ NT_STATUS_LOGON_FAILURE));
+ END_PROFILE(SMBsesssetupX);
+ return;
+ }
+ fstrcpy(sub_user, user);
+ } else {
+ fstrcpy(sub_user, lp_guestaccount());
+ }
+
+ sub_set_smb_name(sub_user);
+
+ reload_services(True);
+
+ if (lp_security() == SEC_SHARE) {
+ /* In share level we should ignore any passwords */
+
+ data_blob_free(&lm_resp);
+ data_blob_free(&nt_resp);
+ data_blob_clear_free(&plaintext_password);
+
+ map_username(sub_user);
+ add_session_user(sub_user);
+ add_session_workgroup(domain);
+ /* Then force it to null for the benfit of the code below */
+ *user = 0;
+ }
+
+ if (!*user) {
+
+ nt_status = check_guest_password(&server_info);
+
+ } else if (doencrypt) {
+ if (!negprot_global_auth_context) {
+ DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
+ "session setup without negprot denied!\n"));
+ reply_nterror(req, nt_status_squash(
+ NT_STATUS_LOGON_FAILURE));
+ END_PROFILE(SMBsesssetupX);
+ return;
+ }
+ nt_status = make_user_info_for_reply_enc(&user_info, user,
+ domain,
+ lm_resp, nt_resp);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ nt_status = negprot_global_auth_context->check_ntlm_password(
+ negprot_global_auth_context,
+ user_info,
+ &server_info);
+ }
+ } else {
+ struct auth_context *plaintext_auth_context = NULL;
+ const uint8 *chal;
+
+ nt_status = make_auth_context_subsystem(
+ &plaintext_auth_context);
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ chal = plaintext_auth_context->get_ntlm_challenge(
+ plaintext_auth_context);
+
+ if (!make_user_info_for_reply(&user_info,
+ user, domain, chal,
+ plaintext_password)) {
+ nt_status = NT_STATUS_NO_MEMORY;
+ }
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ nt_status = plaintext_auth_context->check_ntlm_password(
+ plaintext_auth_context,
+ user_info,
+ &server_info);
+
+ (plaintext_auth_context->free)(
+ &plaintext_auth_context);
+ }
+ }
+ }
+
+ free_user_info(&user_info);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ nt_status = do_map_to_guest(nt_status, &server_info,
+ user, domain);
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ data_blob_free(&nt_resp);
+ data_blob_free(&lm_resp);
+ data_blob_clear_free(&plaintext_password);
+ reply_nterror(req, nt_status_squash(nt_status));
+ END_PROFILE(SMBsesssetupX);
+ return;
+ }
+
+ /* Ensure we can't possible take a code path leading to a
+ * null defref. */
+ if (!server_info) {
+ reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
+ END_PROFILE(SMBsesssetupX);
+ return;
+ }
+
+ if (!server_info->ptok) {
+ nt_status = create_local_token(server_info);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(10, ("create_local_token failed: %s\n",
+ nt_errstr(nt_status)));
+ data_blob_free(&nt_resp);
+ data_blob_free(&lm_resp);
+ data_blob_clear_free(&plaintext_password);
+ reply_nterror(req, nt_status_squash(nt_status));
+ END_PROFILE(SMBsesssetupX);
+ return;
+ }
+ }
+
+ data_blob_clear_free(&plaintext_password);
+
+ /* it's ok - setup a reply */
+ reply_outbuf(req, 3, 0);
+ if (Protocol >= PROTOCOL_NT1) {
+ push_signature(&req->outbuf);
+ /* perhaps grab OS version here?? */
+ }
+
+ if (server_info->guest) {
+ SSVAL(req->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 */
+
+ if (lp_security() == SEC_SHARE) {
+ sess_vuid = UID_FIELD_INVALID;
+ TALLOC_FREE(server_info);
+ } else {
+ /* Ignore the initial vuid. */
+ sess_vuid = register_initial_vuid();
+ if (sess_vuid == UID_FIELD_INVALID) {
+ data_blob_free(&nt_resp);
+ data_blob_free(&lm_resp);
+ reply_nterror(req, nt_status_squash(
+ NT_STATUS_LOGON_FAILURE));
+ END_PROFILE(SMBsesssetupX);
+ return;
+ }
+ /* register_existing_vuid keeps the server info */
+ sess_vuid = register_existing_vuid(sess_vuid,
+ server_info,
+ nt_resp.data ? nt_resp : lm_resp,
+ sub_user);
+ if (sess_vuid == UID_FIELD_INVALID) {
+ data_blob_free(&nt_resp);
+ data_blob_free(&lm_resp);
+ reply_nterror(req, nt_status_squash(
+ NT_STATUS_LOGON_FAILURE));
+ END_PROFILE(SMBsesssetupX);
+ return;
+ }
+
+ /* current_user_info is changed on new vuid */
+ reload_services( True );
+
+ sessionsetup_start_signing_engine(server_info, req->inbuf);
+ }
+
+ data_blob_free(&nt_resp);
+ data_blob_free(&lm_resp);
+
+ SSVAL(req->outbuf,smb_uid,sess_vuid);
+ SSVAL(req->inbuf,smb_uid,sess_vuid);
+
+ if (!done_sesssetup)
+ max_send = MIN(max_send,smb_bufsize);
+
+ done_sesssetup = True;
+
+ END_PROFILE(SMBsesssetupX);
+ chain_reply(req);
+ return;
+}
diff --git a/source3/smbd/share_access.c b/source3/smbd/share_access.c
new file mode 100644
index 0000000000..f5f79c86e5
--- /dev/null
+++ b/source3/smbd/share_access.c
@@ -0,0 +1,280 @@
+/*
+ Unix SMB/CIFS implementation.
+ Check access based on valid users, read list and friends
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*
+ * No prefix means direct username
+ * @name means netgroup first, then unix group
+ * &name means netgroup
+ * +name means unix group
+ * + and & may be combined
+ */
+
+static bool do_group_checks(const char **name, const char **pattern)
+{
+ if ((*name)[0] == '@') {
+ *pattern = "&+";
+ *name += 1;
+ return True;
+ }
+
+ if (((*name)[0] == '+') && ((*name)[1] == '&')) {
+ *pattern = "+&";
+ *name += 2;
+ return True;
+ }
+
+ if ((*name)[0] == '+') {
+ *pattern = "+";
+ *name += 1;
+ return True;
+ }
+
+ if (((*name)[0] == '&') && ((*name)[1] == '+')) {
+ *pattern = "&+";
+ *name += 2;
+ return True;
+ }
+
+ if ((*name)[0] == '&') {
+ *pattern = "&";
+ *name += 1;
+ return True;
+ }
+
+ return False;
+}
+
+static bool token_contains_name(TALLOC_CTX *mem_ctx,
+ const char *username,
+ const char *domain,
+ const char *sharename,
+ const struct nt_user_token *token,
+ const char *name)
+{
+ const char *prefix;
+ DOM_SID sid;
+ enum lsa_SidType type;
+
+ if (username != NULL) {
+ name = talloc_sub_basic(mem_ctx, username, domain, name);
+ }
+ if (sharename != NULL) {
+ name = talloc_string_sub(mem_ctx, name, "%S", sharename);
+ }
+
+ if (name == NULL) {
+ /* This is too security sensitive, better panic than return a
+ * result that might be interpreted in a wrong way. */
+ smb_panic("substitutions failed");
+ }
+
+ /* check to see is we already have a SID */
+
+ if ( string_to_sid( &sid, name ) ) {
+ DEBUG(5,("token_contains_name: Checking for SID [%s] in token\n", name));
+ return nt_token_check_sid( &sid, token );
+ }
+
+ if (!do_group_checks(&name, &prefix)) {
+ if (!lookup_name_smbconf(mem_ctx, name, LOOKUP_NAME_ALL,
+ NULL, NULL, &sid, &type)) {
+ DEBUG(5, ("lookup_name %s failed\n", name));
+ return False;
+ }
+ if (type != SID_NAME_USER) {
+ DEBUG(5, ("%s is a %s, expected a user\n",
+ name, sid_type_lookup(type)));
+ return False;
+ }
+ return nt_token_check_sid(&sid, token);
+ }
+
+ for (/* initialized above */ ; *prefix != '\0'; prefix++) {
+ if (*prefix == '+') {
+ if (!lookup_name_smbconf(mem_ctx, name,
+ LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
+ NULL, NULL, &sid, &type)) {
+ DEBUG(5, ("lookup_name %s failed\n", name));
+ return False;
+ }
+ if ((type != SID_NAME_DOM_GRP) &&
+ (type != SID_NAME_ALIAS) &&
+ (type != SID_NAME_WKN_GRP)) {
+ DEBUG(5, ("%s is a %s, expected a group\n",
+ name, sid_type_lookup(type)));
+ return False;
+ }
+ if (nt_token_check_sid(&sid, token)) {
+ return True;
+ }
+ continue;
+ }
+ if (*prefix == '&') {
+ if (user_in_netgroup(username, name)) {
+ return True;
+ }
+ continue;
+ }
+ smb_panic("got invalid prefix from do_groups_check");
+ }
+ return False;
+}
+
+/*
+ * Check whether a user is contained in the list provided.
+ *
+ * Please note that the user name and share names passed in here mainly for
+ * the substitution routines that expand the parameter values, the decision
+ * whether a user is in the list is done after a lookup_name on the expanded
+ * parameter value, solely based on comparing the SIDs in token.
+ *
+ * The other use is the netgroup check when using @group or &group.
+ */
+
+bool token_contains_name_in_list(const char *username,
+ const char *domain,
+ const char *sharename,
+ const struct nt_user_token *token,
+ const char **list)
+{
+ TALLOC_CTX *mem_ctx;
+
+ if (list == NULL) {
+ return False;
+ }
+
+ if ( (mem_ctx = talloc_new(NULL)) == NULL ) {
+ smb_panic("talloc_new failed");
+ }
+
+ while (*list != NULL) {
+ if (token_contains_name(mem_ctx, username, domain, sharename,
+ token, *list)) {
+ TALLOC_FREE(mem_ctx);
+ return True;
+ }
+ list += 1;
+ }
+
+ TALLOC_FREE(mem_ctx);
+ return False;
+}
+
+/*
+ * Check whether the user described by "token" has access to share snum.
+ *
+ * This looks at "invalid users", "valid users" and "only user/username"
+ *
+ * Please note that the user name and share names passed in here mainly for
+ * the substitution routines that expand the parameter values, the decision
+ * whether a user is in the list is done after a lookup_name on the expanded
+ * parameter value, solely based on comparing the SIDs in token.
+ *
+ * The other use is the netgroup check when using @group or &group.
+ */
+
+bool user_ok_token(const char *username, const char *domain,
+ struct nt_user_token *token, int snum)
+{
+ if (lp_invalid_users(snum) != NULL) {
+ if (token_contains_name_in_list(username, domain,
+ lp_servicename(snum),
+ token,
+ lp_invalid_users(snum))) {
+ DEBUG(10, ("User %s in 'invalid users'\n", username));
+ return False;
+ }
+ }
+
+ if (lp_valid_users(snum) != NULL) {
+ if (!token_contains_name_in_list(username, domain,
+ lp_servicename(snum), token,
+ lp_valid_users(snum))) {
+ DEBUG(10, ("User %s not in 'valid users'\n",
+ username));
+ return False;
+ }
+ }
+
+ if (lp_onlyuser(snum)) {
+ const char *list[2];
+ list[0] = lp_username(snum);
+ list[1] = NULL;
+ if ((list[0] == NULL) || (*list[0] == '\0')) {
+ DEBUG(0, ("'only user = yes' and no 'username ='\n"));
+ return False;
+ }
+ if (!token_contains_name_in_list(NULL, domain,
+ lp_servicename(snum),
+ token, list)) {
+ DEBUG(10, ("%s != 'username'\n", username));
+ return False;
+ }
+ }
+
+ DEBUG(10, ("user_ok_token: share %s is ok for unix user %s\n",
+ lp_servicename(snum), username));
+
+ return True;
+}
+
+/*
+ * Check whether the user described by "token" is restricted to read-only
+ * access on share snum.
+ *
+ * This looks at "invalid users", "valid users" and "only user/username"
+ *
+ * Please note that the user name and share names passed in here mainly for
+ * the substitution routines that expand the parameter values, the decision
+ * whether a user is in the list is done after a lookup_name on the expanded
+ * parameter value, solely based on comparing the SIDs in token.
+ *
+ * The other use is the netgroup check when using @group or &group.
+ */
+
+bool is_share_read_only_for_token(const char *username,
+ const char *domain,
+ struct nt_user_token *token, int snum)
+{
+ bool result = lp_readonly(snum);
+
+ if (lp_readlist(snum) != NULL) {
+ if (token_contains_name_in_list(username, domain,
+ lp_servicename(snum), token,
+ lp_readlist(snum))) {
+ result = True;
+ }
+ }
+
+ if (lp_writelist(snum) != NULL) {
+ if (token_contains_name_in_list(username, domain,
+ lp_servicename(snum), token,
+ lp_writelist(snum))) {
+ result = False;
+ }
+ }
+
+ DEBUG(10,("is_share_read_only_for_user: share %s is %s for unix user "
+ "%s\n", lp_servicename(snum),
+ result ? "read-only" : "read-write", username));
+
+ return result;
+}
diff --git a/source3/smbd/srvstr.c b/source3/smbd/srvstr.c
new file mode 100644
index 0000000000..bae77d5d4b
--- /dev/null
+++ b/source3/smbd/srvstr.c
@@ -0,0 +1,77 @@
+/*
+ Unix SMB/CIFS implementation.
+ server specific string routines
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+extern int max_send;
+
+/* Make sure we can't write a string past the end of the buffer */
+
+size_t srvstr_push_fn(const char *function, unsigned int line,
+ const char *base_ptr, uint16 smb_flags2, void *dest,
+ const char *src, int dest_len, int flags)
+{
+ if (dest_len < 0) {
+ return 0;
+ }
+
+ /* 'normal' push into size-specified buffer */
+ return push_string_fn(function, line, base_ptr, smb_flags2, dest, src,
+ dest_len, flags);
+}
+
+/*******************************************************************
+ Add a string to the end of a smb_buf, adjusting bcc and smb_len.
+ Return the bytes added
+********************************************************************/
+
+ssize_t message_push_string(uint8 **outbuf, const char *str, int flags)
+{
+ size_t buf_size = smb_len(*outbuf) + 4;
+ size_t grow_size;
+ size_t result;
+ uint8 *tmp;
+
+ /*
+ * We need to over-allocate, now knowing what srvstr_push will
+ * actually use. This is very generous by incorporating potential
+ * padding, the terminating 0 and at most 4 chars per UTF-16 code
+ * point.
+ */
+ grow_size = (strlen(str) + 2) * 4;
+
+ if (!(tmp = TALLOC_REALLOC_ARRAY(NULL, *outbuf, uint8,
+ buf_size + grow_size))) {
+ DEBUG(0, ("talloc failed\n"));
+ return -1;
+ }
+
+ result = srvstr_push((char *)tmp, SVAL(tmp, smb_flg2),
+ tmp + buf_size, str, grow_size, flags);
+
+ if (result == (size_t)-1) {
+ DEBUG(0, ("srvstr_push failed\n"));
+ return -1;
+ }
+ set_message_bcc((char *)tmp, smb_buflen(tmp) + result);
+
+ *outbuf = tmp;
+
+ return result;
+}
diff --git a/source3/smbd/statcache.c b/source3/smbd/statcache.c
new file mode 100644
index 0000000000..72fed008a2
--- /dev/null
+++ b/source3/smbd/statcache.c
@@ -0,0 +1,391 @@
+/*
+ Unix SMB/CIFS implementation.
+ stat cache code
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Jeremy Allison 1999-2007
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Stat cache code used in unix_convert.
+*****************************************************************************/
+
+/**
+ * Add an entry into the stat cache.
+ *
+ * @param full_orig_name The original name as specified by the client
+ * @param orig_translated_path The name on our filesystem.
+ *
+ * @note Only the first strlen(orig_translated_path) characters are stored
+ * into the cache. This means that full_orig_name will be internally
+ * truncated.
+ *
+ */
+
+void stat_cache_add( const char *full_orig_name,
+ char *translated_path,
+ bool case_sensitive)
+{
+ size_t translated_path_length;
+ char *original_path;
+ size_t original_path_length;
+ char saved_char;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if (!lp_stat_cache()) {
+ return;
+ }
+
+ /*
+ * Don't cache trivial valid directory entries such as . and ..
+ */
+
+ if ((*full_orig_name == '\0')
+ || ISDOT(full_orig_name) || ISDOTDOT(full_orig_name)) {
+ return;
+ }
+
+ /*
+ * If we are in case insentive mode, we don't need to
+ * store names that need no translation - else, it
+ * would be a waste.
+ */
+
+ if (case_sensitive && (strcmp(full_orig_name, translated_path) == 0)) {
+ return;
+ }
+
+ /*
+ * Remove any trailing '/' characters from the
+ * translated path.
+ */
+
+ translated_path_length = strlen(translated_path);
+
+ if(translated_path[translated_path_length-1] == '/') {
+ translated_path_length--;
+ }
+
+ if(case_sensitive) {
+ original_path = talloc_strdup(ctx,full_orig_name);
+ } else {
+ original_path = talloc_strdup_upper(ctx,full_orig_name);
+ }
+
+ if (!original_path) {
+ return;
+ }
+
+ original_path_length = strlen(original_path);
+
+ if(original_path[original_path_length-1] == '/') {
+ original_path[original_path_length-1] = '\0';
+ original_path_length--;
+ }
+
+ if (original_path_length != translated_path_length) {
+ if (original_path_length < translated_path_length) {
+ DEBUG(0, ("OOPS - tried to store stat cache entry "
+ "for weird length paths [%s] %lu and [%s] %lu)!\n",
+ original_path,
+ (unsigned long)original_path_length,
+ translated_path,
+ (unsigned long)translated_path_length));
+ TALLOC_FREE(original_path);
+ return;
+ }
+
+ /* we only want to index by the first part of original_path,
+ up to the length of translated_path */
+
+ original_path[translated_path_length] = '\0';
+ original_path_length = translated_path_length;
+ }
+
+ /* Ensure we're null terminated. */
+ saved_char = translated_path[translated_path_length];
+ translated_path[translated_path_length] = '\0';
+
+ /*
+ * New entry or replace old entry.
+ */
+
+ memcache_add(
+ smbd_memcache(), STAT_CACHE,
+ data_blob_const(original_path, original_path_length),
+ data_blob_const(translated_path, translated_path_length + 1));
+
+ DEBUG(5,("stat_cache_add: Added entry (%lx:size %x) %s -> %s\n",
+ (unsigned long)translated_path,
+ (unsigned int)translated_path_length,
+ original_path,
+ translated_path));
+
+ translated_path[translated_path_length] = saved_char;
+ TALLOC_FREE(original_path);
+}
+
+/**
+ * Look through the stat cache for an entry
+ *
+ * @param conn A connection struct to do the stat() with.
+ * @param name The path we are attempting to cache, modified by this routine
+ * to be correct as far as the cache can tell us. We assume that
+ * it is a talloc'ed string from top of stack, we free it if
+ * necessary.
+ * @param dirpath The path as far as the stat cache told us. Also talloced
+ * from top of stack.
+ * @param start A pointer into name, for where to 'start' in fixing the rest
+ * of the name up.
+ * @param psd A stat buffer, NOT from the cache, but just a side-effect.
+ *
+ * @return True if we translated (and did a scuccessful stat on) the entire
+ * name.
+ *
+ */
+
+bool stat_cache_lookup(connection_struct *conn,
+ char **pp_name,
+ char **pp_dirpath,
+ char **pp_start,
+ SMB_STRUCT_STAT *pst)
+{
+ char *chk_name;
+ size_t namelen;
+ bool sizechanged = False;
+ unsigned int num_components = 0;
+ char *translated_path;
+ size_t translated_path_length;
+ DATA_BLOB data_val;
+ char *name;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ *pp_dirpath = NULL;
+ *pp_start = *pp_name;
+
+ if (!lp_stat_cache()) {
+ return False;
+ }
+
+ name = *pp_name;
+ namelen = strlen(name);
+
+ DO_PROFILE_INC(statcache_lookups);
+
+ /*
+ * Don't lookup trivial valid directory entries.
+ */
+ if ((*name == '\0') || ISDOT(name) || ISDOTDOT(name)) {
+ return False;
+ }
+
+ if (conn->case_sensitive) {
+ chk_name = talloc_strdup(ctx,name);
+ if (!chk_name) {
+ DEBUG(0, ("stat_cache_lookup: strdup failed!\n"));
+ return False;
+ }
+
+ } else {
+ chk_name = talloc_strdup_upper(ctx,name);
+ if (!chk_name) {
+ DEBUG(0, ("stat_cache_lookup: strdup_upper failed!\n"));
+ return False;
+ }
+
+ /*
+ * In some language encodings the length changes
+ * if we uppercase. We need to treat this differently
+ * below.
+ */
+ if (strlen(chk_name) != namelen) {
+ sizechanged = True;
+ }
+ }
+
+ while (1) {
+ char *sp;
+
+ data_val = data_blob_null;
+
+ if (memcache_lookup(
+ smbd_memcache(), STAT_CACHE,
+ data_blob_const(chk_name, strlen(chk_name)),
+ &data_val)) {
+ break;
+ }
+
+ DEBUG(10,("stat_cache_lookup: lookup failed for name [%s]\n",
+ chk_name ));
+ /*
+ * Didn't find it - remove last component for next try.
+ */
+ if (!(sp = strrchr_m(chk_name, '/'))) {
+ /*
+ * We reached the end of the name - no match.
+ */
+ DO_PROFILE_INC(statcache_misses);
+ TALLOC_FREE(chk_name);
+ return False;
+ }
+
+ *sp = '\0';
+
+ /*
+ * Count the number of times we have done this, we'll
+ * need it when reconstructing the string.
+ */
+
+ if (sizechanged) {
+ num_components++;
+ }
+
+ if ((*chk_name == '\0')
+ || ISDOT(chk_name) || ISDOTDOT(chk_name)) {
+ DO_PROFILE_INC(statcache_misses);
+ TALLOC_FREE(chk_name);
+ return False;
+ }
+ }
+
+ translated_path = talloc_strdup(ctx,(char *)data_val.data);
+ if (!translated_path) {
+ smb_panic("talloc failed");
+ }
+ translated_path_length = data_val.length - 1;
+
+ DEBUG(10,("stat_cache_lookup: lookup succeeded for name [%s] "
+ "-> [%s]\n", chk_name, translated_path ));
+ DO_PROFILE_INC(statcache_hits);
+
+ if (SMB_VFS_STAT(conn, translated_path, pst) != 0) {
+ /* Discard this entry - it doesn't exist in the filesystem. */
+ memcache_delete(smbd_memcache(), STAT_CACHE,
+ data_blob_const(chk_name, strlen(chk_name)));
+ TALLOC_FREE(chk_name);
+ TALLOC_FREE(translated_path);
+ return False;
+ }
+
+ if (!sizechanged) {
+ memcpy(*pp_name, translated_path,
+ MIN(namelen, translated_path_length));
+ } else {
+ if (num_components == 0) {
+ name = talloc_strndup(ctx, translated_path,
+ translated_path_length);
+ } else {
+ char *sp;
+
+ sp = strnrchr_m(name, '/', num_components);
+ if (sp) {
+ name = talloc_asprintf(ctx,"%.*s%s",
+ (int)translated_path_length,
+ translated_path, sp);
+ } else {
+ name = talloc_strndup(ctx,
+ translated_path,
+ translated_path_length);
+ }
+ }
+ if (name == NULL) {
+ /*
+ * TODO: Get us out of here with a real error message
+ */
+ smb_panic("talloc failed");
+ }
+ TALLOC_FREE(*pp_name);
+ *pp_name = name;
+ }
+
+
+ /* set pointer for 'where to start' on fixing the rest of the name */
+ *pp_start = &name[translated_path_length];
+ if (**pp_start == '/') {
+ ++*pp_start;
+ }
+
+ *pp_dirpath = translated_path;
+ TALLOC_FREE(chk_name);
+ return (namelen == translated_path_length);
+}
+
+/***************************************************************************
+ Tell all smbd's to delete an entry.
+**************************************************************************/
+
+void send_stat_cache_delete_message(const char *name)
+{
+#ifdef DEVELOPER
+ message_send_all(smbd_messaging_context(),
+ MSG_SMB_STAT_CACHE_DELETE,
+ name,
+ strlen(name)+1,
+ NULL);
+#endif
+}
+
+/***************************************************************************
+ Delete an entry.
+**************************************************************************/
+
+void stat_cache_delete(const char *name)
+{
+ char *lname = talloc_strdup_upper(talloc_tos(), name);
+
+ if (!lname) {
+ return;
+ }
+ DEBUG(10,("stat_cache_delete: deleting name [%s] -> %s\n",
+ lname, name ));
+
+ memcache_delete(smbd_memcache(), STAT_CACHE,
+ data_blob_const(lname, talloc_get_size(lname)-1));
+ TALLOC_FREE(lname);
+}
+
+/***************************************************************
+ Compute a hash value based on a string key value.
+ The function returns the bucket index number for the hashed key.
+ JRA. Use a djb-algorithm hash for speed.
+***************************************************************/
+
+unsigned int fast_string_hash(TDB_DATA *key)
+{
+ unsigned int n = 0;
+ const char *p;
+ for (p = (const char *)key->dptr; *p != '\0'; p++) {
+ n = ((n << 5) + n) ^ (unsigned int)(*p);
+ }
+ return n;
+}
+
+/***************************************************************************
+ Initializes or clears the stat cache.
+**************************************************************************/
+
+bool reset_stat_cache( void )
+{
+ if (!lp_stat_cache())
+ return True;
+
+ memcache_flush(smbd_memcache(), STAT_CACHE);
+
+ return True;
+}
diff --git a/source3/smbd/statvfs.c b/source3/smbd/statvfs.c
new file mode 100644
index 0000000000..0e9a2c2ebe
--- /dev/null
+++ b/source3/smbd/statvfs.c
@@ -0,0 +1,149 @@
+/*
+ Unix SMB/CIFS implementation.
+ VFS API's statvfs abstraction
+ Copyright (C) Alexander Bokovoy 2005
+ Copyright (C) Steve French 2005
+ Copyright (C) James Peach 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#if defined(LINUX) && defined(HAVE_FSID_INT)
+static int linux_statvfs(const char *path, vfs_statvfs_struct *statbuf)
+{
+ struct statvfs statvfs_buf;
+ int result;
+
+ result = statvfs(path, &statvfs_buf);
+
+ if (!result) {
+ statbuf->OptimalTransferSize = statvfs_buf.f_frsize;
+ statbuf->BlockSize = statvfs_buf.f_bsize;
+ statbuf->TotalBlocks = statvfs_buf.f_blocks;
+ statbuf->BlocksAvail = statvfs_buf.f_bfree;
+ statbuf->UserBlocksAvail = statvfs_buf.f_bavail;
+ statbuf->TotalFileNodes = statvfs_buf.f_files;
+ statbuf->FreeFileNodes = statvfs_buf.f_ffree;
+ statbuf->FsIdentifier = statvfs_buf.f_fsid;
+
+ /* Good defaults for Linux filesystems are case sensitive
+ * and case preserving.
+ */
+ statbuf->FsCapabilities =
+ FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
+ }
+ return result;
+}
+#endif
+
+#if defined(DARWINOS)
+
+#include <sys/attr.h>
+
+static int darwin_fs_capabilities(const char * path)
+{
+ int caps = 0;
+ vol_capabilities_attr_t *vcaps;
+ struct attrlist attrlist;
+ char attrbuf[sizeof(u_int32_t) + sizeof(vol_capabilities_attr_t)];
+
+#define FORMAT_CAP(vinfo, cap) \
+ ( ((vinfo)->valid[VOL_CAPABILITIES_FORMAT] & (cap)) && \
+ ((vinfo)->capabilities[VOL_CAPABILITIES_FORMAT] & (cap)) )
+
+#define INTERFACE_CAP(vinfo, cap) \
+ ( ((vinfo)->valid[VOL_CAPABILITIES_INTERFACES] & (cap)) && \
+ ((vinfo)->capabilities[VOL_CAPABILITIES_INTERFACES] & (cap)) )
+
+ ZERO_STRUCT(attrlist);
+ attrlist.bitmapcount = ATTR_BIT_MAP_COUNT;
+ attrlist.volattr = ATTR_VOL_CAPABILITIES;
+
+ if (getattrlist(path, &attrlist, attrbuf, sizeof(attrbuf), 0) != 0) {
+ DEBUG(0, ("getattrlist for %s capabilities failed: %s\n",
+ path, strerror(errno)));
+ /* Return no capabilities on failure. */
+ return 0;
+ }
+
+ vcaps =
+ (vol_capabilities_attr_t *)(attrbuf + sizeof(u_int32_t));
+
+ if (FORMAT_CAP(vcaps, VOL_CAP_FMT_SPARSE_FILES)) {
+ caps |= FILE_SUPPORTS_SPARSE_FILES;
+ }
+
+ if (FORMAT_CAP(vcaps, VOL_CAP_FMT_CASE_SENSITIVE)) {
+ caps |= FILE_CASE_SENSITIVE_SEARCH;
+ }
+
+ if (FORMAT_CAP(vcaps, VOL_CAP_FMT_CASE_PRESERVING)) {
+ caps |= FILE_CASE_PRESERVED_NAMES;
+ }
+
+ if (INTERFACE_CAP(vcaps, VOL_CAP_INT_EXTENDED_SECURITY)) {
+ caps |= FILE_PERSISTENT_ACLS;
+ }
+
+ return caps;
+}
+
+static int darwin_statvfs(const char *path, vfs_statvfs_struct *statbuf)
+{
+ struct statfs sbuf;
+ int ret;
+
+ ret = statfs(path, &sbuf);
+ if (ret != 0) {
+ return ret;
+ }
+
+ statbuf->OptimalTransferSize = sbuf.f_iosize;
+ statbuf->BlockSize = sbuf.f_bsize;
+ statbuf->TotalBlocks = sbuf.f_blocks;
+ statbuf->BlocksAvail = sbuf.f_bfree;
+ statbuf->UserBlocksAvail = sbuf.f_bavail;
+ statbuf->TotalFileNodes = sbuf.f_files;
+ statbuf->FreeFileNodes = sbuf.f_ffree;
+ statbuf->FsIdentifier = *(SMB_BIG_UINT *)(&sbuf.f_fsid); /* Ick. */
+ statbuf->FsCapabilities = darwin_fs_capabilities(sbuf.f_mntonname);
+
+ return 0;
+}
+#endif
+
+/*
+ sys_statvfs() is an abstraction layer over system-dependent statvfs()/statfs()
+ for particular POSIX systems. Due to controversy of what is considered more important
+ between LSB and FreeBSD/POSIX.1 (IEEE Std 1003.1-2001) we need to abstract the interface
+ so that particular OS would use its preffered interface.
+*/
+int sys_statvfs(const char *path, vfs_statvfs_struct *statbuf)
+{
+#if defined(LINUX) && defined(HAVE_FSID_INT)
+ return linux_statvfs(path, statbuf);
+#elif defined(DARWINOS)
+ return darwin_statvfs(path, statbuf);
+#else
+ /* BB change this to return invalid level */
+#ifdef EOPNOTSUPP
+ return EOPNOTSUPP;
+#else
+ return -1;
+#endif /* EOPNOTSUPP */
+#endif /* LINUX */
+
+}
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
new file mode 100644
index 0000000000..2e2da5cc71
--- /dev/null
+++ b/source3/smbd/trans2.c
@@ -0,0 +1,7846 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB transaction2 handling
+ Copyright (C) Jeremy Allison 1994-2007
+ Copyright (C) Stefan (metze) Metzmacher 2003
+ Copyright (C) Volker Lendecke 2005-2007
+ Copyright (C) Steve French 2005
+ Copyright (C) James Peach 2006-2007
+
+ Extensively modified by Andrew Tridgell, 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern int max_send;
+extern enum protocol_types Protocol;
+extern uint32 global_client_caps;
+
+#define get_file_size(sbuf) ((sbuf).st_size)
+#define DIR_ENTRY_SAFETY_MARGIN 4096
+
+static char *store_file_unix_basic(connection_struct *conn,
+ char *pdata,
+ files_struct *fsp,
+ const SMB_STRUCT_STAT *psbuf);
+
+static char *store_file_unix_basic_info2(connection_struct *conn,
+ char *pdata,
+ files_struct *fsp,
+ const SMB_STRUCT_STAT *psbuf);
+
+/********************************************************************
+ Roundup a value to the nearest allocation roundup size boundary.
+ Only do this for Windows clients.
+********************************************************************/
+
+SMB_BIG_UINT smb_roundup(connection_struct *conn, SMB_BIG_UINT val)
+{
+ SMB_BIG_UINT rval = lp_allocation_roundup_size(SNUM(conn));
+
+ /* Only roundup for Windows clients. */
+ enum remote_arch_types ra_type = get_remote_arch();
+ if (rval && (ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
+ val = SMB_ROUNDUP(val,rval);
+ }
+ return val;
+}
+
+/********************************************************************
+ Given a stat buffer return the allocated size on disk, taking into
+ account sparse files.
+********************************************************************/
+
+SMB_BIG_UINT get_allocation_size(connection_struct *conn, files_struct *fsp, const SMB_STRUCT_STAT *sbuf)
+{
+ SMB_BIG_UINT ret;
+
+ if(S_ISDIR(sbuf->st_mode)) {
+ return 0;
+ }
+
+#if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
+ ret = (SMB_BIG_UINT)STAT_ST_BLOCKSIZE * (SMB_BIG_UINT)sbuf->st_blocks;
+#else
+ ret = (SMB_BIG_UINT)get_file_size(*sbuf);
+#endif
+
+ if (fsp && fsp->initial_allocation_size)
+ ret = MAX(ret,fsp->initial_allocation_size);
+
+ return smb_roundup(conn, ret);
+}
+
+/****************************************************************************
+ Utility functions for dealing with extended attributes.
+****************************************************************************/
+
+/****************************************************************************
+ Refuse to allow clients to overwrite our private xattrs.
+****************************************************************************/
+
+static bool samba_private_attr_name(const char *unix_ea_name)
+{
+ static const char *prohibited_ea_names[] = {
+ SAMBA_POSIX_INHERITANCE_EA_NAME,
+ SAMBA_XATTR_DOS_ATTRIB,
+ NULL
+ };
+
+ int i;
+
+ for (i = 0; prohibited_ea_names[i]; i++) {
+ if (strequal( prohibited_ea_names[i], unix_ea_name))
+ return true;
+ }
+ if (StrnCaseCmp(unix_ea_name, SAMBA_XATTR_DOSSTREAM_PREFIX,
+ strlen(SAMBA_XATTR_DOSSTREAM_PREFIX)) == 0) {
+ return true;
+ }
+ return false;
+}
+
+/****************************************************************************
+ Get one EA value. Fill in a struct ea_struct.
+****************************************************************************/
+
+NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn,
+ files_struct *fsp, const char *fname,
+ const char *ea_name, struct ea_struct *pea)
+{
+ /* Get the value of this xattr. Max size is 64k. */
+ size_t attr_size = 256;
+ char *val = NULL;
+ ssize_t sizeret;
+
+ again:
+
+ val = TALLOC_REALLOC_ARRAY(mem_ctx, val, char, attr_size);
+ if (!val) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (fsp && fsp->fh->fd != -1) {
+ sizeret = SMB_VFS_FGETXATTR(fsp, ea_name, val, attr_size);
+ } else {
+ sizeret = SMB_VFS_GETXATTR(conn, fname, ea_name, val, attr_size);
+ }
+
+ if (sizeret == -1 && errno == ERANGE && attr_size != 65536) {
+ attr_size = 65536;
+ goto again;
+ }
+
+ if (sizeret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ DEBUG(10,("get_ea_value: EA %s is of length %u\n", ea_name, (unsigned int)sizeret));
+ dump_data(10, (uint8 *)val, sizeret);
+
+ pea->flags = 0;
+ if (strnequal(ea_name, "user.", 5)) {
+ pea->name = talloc_strdup(mem_ctx, &ea_name[5]);
+ } else {
+ pea->name = talloc_strdup(mem_ctx, ea_name);
+ }
+ if (pea->name == NULL) {
+ TALLOC_FREE(val);
+ return NT_STATUS_NO_MEMORY;
+ }
+ pea->value.data = (unsigned char *)val;
+ pea->value.length = (size_t)sizeret;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
+ files_struct *fsp, const char *fname,
+ char ***pnames, size_t *pnum_names)
+{
+ /* Get a list of all xattrs. Max namesize is 64k. */
+ size_t ea_namelist_size = 1024;
+ char *ea_namelist = NULL;
+
+ char *p;
+ char **names, **tmp;
+ size_t num_names;
+ ssize_t sizeret = -1;
+
+ if (!lp_ea_support(SNUM(conn))) {
+ *pnames = NULL;
+ *pnum_names = 0;
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * TALLOC the result early to get the talloc hierarchy right.
+ */
+
+ names = TALLOC_ARRAY(mem_ctx, char *, 1);
+ if (names == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ while (ea_namelist_size <= 65536) {
+
+ ea_namelist = TALLOC_REALLOC_ARRAY(
+ names, ea_namelist, char, ea_namelist_size);
+ if (ea_namelist == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(names);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (fsp && fsp->fh->fd != -1) {
+ sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist,
+ ea_namelist_size);
+ } else {
+ sizeret = SMB_VFS_LISTXATTR(conn, fname, ea_namelist,
+ ea_namelist_size);
+ }
+
+ if ((sizeret == -1) && (errno == ERANGE)) {
+ ea_namelist_size *= 2;
+ }
+ else {
+ break;
+ }
+ }
+
+ if (sizeret == -1) {
+ TALLOC_FREE(names);
+ return map_nt_error_from_unix(errno);
+ }
+
+ DEBUG(10, ("get_ea_list_from_file: ea_namelist size = %u\n",
+ (unsigned int)sizeret));
+
+ if (sizeret == 0) {
+ TALLOC_FREE(names);
+ *pnames = NULL;
+ *pnum_names = 0;
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * Ensure the result is 0-terminated
+ */
+
+ if (ea_namelist[sizeret-1] != '\0') {
+ TALLOC_FREE(names);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /*
+ * count the names
+ */
+ num_names = 0;
+
+ for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
+ num_names += 1;
+ }
+
+ tmp = TALLOC_REALLOC_ARRAY(mem_ctx, names, char *, num_names);
+ if (tmp == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(names);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ names = tmp;
+ num_names = 0;
+
+ for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
+ names[num_names++] = p;
+ }
+
+ *pnames = names;
+ *pnum_names = num_names;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Return a linked list of the total EA's. Plus the total size
+****************************************************************************/
+
+static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
+ const char *fname, size_t *pea_total_len)
+{
+ /* Get a list of all xattrs. Max namesize is 64k. */
+ size_t i, num_names;
+ char **names;
+ struct ea_list *ea_list_head = NULL;
+ NTSTATUS status;
+
+ *pea_total_len = 0;
+
+ if (!lp_ea_support(SNUM(conn))) {
+ return NULL;
+ }
+
+ status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
+ &names, &num_names);
+
+ if (!NT_STATUS_IS_OK(status) || (num_names == 0)) {
+ return NULL;
+ }
+
+ for (i=0; i<num_names; i++) {
+ struct ea_list *listp;
+ fstring dos_ea_name;
+
+ if (strnequal(names[i], "system.", 7)
+ || samba_private_attr_name(names[i]))
+ continue;
+
+ listp = TALLOC_P(mem_ctx, struct ea_list);
+ if (listp == NULL) {
+ return NULL;
+ }
+
+ if (!NT_STATUS_IS_OK(get_ea_value(mem_ctx, conn, fsp,
+ fname, names[i],
+ &listp->ea))) {
+ return NULL;
+ }
+
+ push_ascii_fstring(dos_ea_name, listp->ea.name);
+
+ *pea_total_len +=
+ 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
+
+ DEBUG(10,("get_ea_list_from_file: total_len = %u, %s, val len "
+ "= %u\n", (unsigned int)*pea_total_len, dos_ea_name,
+ (unsigned int)listp->ea.value.length));
+
+ DLIST_ADD_END(ea_list_head, listp, struct ea_list *);
+
+ }
+
+ /* Add on 4 for total length. */
+ if (*pea_total_len) {
+ *pea_total_len += 4;
+ }
+
+ DEBUG(10, ("get_ea_list_from_file: total_len = %u\n",
+ (unsigned int)*pea_total_len));
+
+ return ea_list_head;
+}
+
+/****************************************************************************
+ Fill a qfilepathinfo buffer with EA's. Returns the length of the buffer
+ that was filled.
+****************************************************************************/
+
+static unsigned int fill_ea_buffer(TALLOC_CTX *mem_ctx, char *pdata, unsigned int total_data_size,
+ connection_struct *conn, struct ea_list *ea_list)
+{
+ unsigned int ret_data_size = 4;
+ char *p = pdata;
+
+ SMB_ASSERT(total_data_size >= 4);
+
+ if (!lp_ea_support(SNUM(conn))) {
+ SIVAL(pdata,4,0);
+ return 4;
+ }
+
+ for (p = pdata + 4; ea_list; ea_list = ea_list->next) {
+ size_t dos_namelen;
+ fstring dos_ea_name;
+ push_ascii_fstring(dos_ea_name, ea_list->ea.name);
+ dos_namelen = strlen(dos_ea_name);
+ if (dos_namelen > 255 || dos_namelen == 0) {
+ break;
+ }
+ if (ea_list->ea.value.length > 65535) {
+ break;
+ }
+ if (4 + dos_namelen + 1 + ea_list->ea.value.length > total_data_size) {
+ break;
+ }
+
+ /* We know we have room. */
+ SCVAL(p,0,ea_list->ea.flags);
+ SCVAL(p,1,dos_namelen);
+ SSVAL(p,2,ea_list->ea.value.length);
+ fstrcpy(p+4, dos_ea_name);
+ memcpy( p + 4 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
+
+ total_data_size -= 4 + dos_namelen + 1 + ea_list->ea.value.length;
+ p += 4 + dos_namelen + 1 + ea_list->ea.value.length;
+ }
+
+ ret_data_size = PTR_DIFF(p, pdata);
+ DEBUG(10,("fill_ea_buffer: data_size = %u\n", ret_data_size ));
+ SIVAL(pdata,0,ret_data_size);
+ return ret_data_size;
+}
+
+static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, const char *fname)
+{
+ size_t total_ea_len = 0;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if (!lp_ea_support(SNUM(conn))) {
+ return 0;
+ }
+ mem_ctx = talloc_tos();
+ (void)get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);
+ return total_ea_len;
+}
+
+/****************************************************************************
+ Ensure the EA name is case insensitive by matching any existing EA name.
+****************************************************************************/
+
+static void canonicalize_ea_name(connection_struct *conn, files_struct *fsp, const char *fname, fstring unix_ea_name)
+{
+ size_t total_ea_len;
+ TALLOC_CTX *mem_ctx = talloc_tos();
+ struct ea_list *ea_list = get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);
+
+ for (; ea_list; ea_list = ea_list->next) {
+ if (strequal(&unix_ea_name[5], ea_list->ea.name)) {
+ DEBUG(10,("canonicalize_ea_name: %s -> %s\n",
+ &unix_ea_name[5], ea_list->ea.name));
+ safe_strcpy(&unix_ea_name[5], ea_list->ea.name, sizeof(fstring)-6);
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+ Set or delete an extended attribute.
+****************************************************************************/
+
+NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, const char *fname, struct ea_list *ea_list)
+{
+ if (!lp_ea_support(SNUM(conn))) {
+ return NT_STATUS_EAS_NOT_SUPPORTED;
+ }
+
+ for (;ea_list; ea_list = ea_list->next) {
+ int ret;
+ fstring unix_ea_name;
+
+ fstrcpy(unix_ea_name, "user."); /* All EA's must start with user. */
+ fstrcat(unix_ea_name, ea_list->ea.name);
+
+ canonicalize_ea_name(conn, fsp, fname, unix_ea_name);
+
+ DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, (unsigned int)ea_list->ea.value.length));
+
+ if (samba_private_attr_name(unix_ea_name)) {
+ DEBUG(10,("set_ea: ea name %s is a private Samba name.\n", unix_ea_name));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (ea_list->ea.value.length == 0) {
+ /* Remove the attribute. */
+ if (fsp && (fsp->fh->fd != -1)) {
+ DEBUG(10,("set_ea: deleting ea name %s on file %s by file descriptor.\n",
+ unix_ea_name, fsp->fsp_name));
+ ret = SMB_VFS_FREMOVEXATTR(fsp, unix_ea_name);
+ } else {
+ DEBUG(10,("set_ea: deleting ea name %s on file %s.\n",
+ unix_ea_name, fname));
+ ret = SMB_VFS_REMOVEXATTR(conn, fname, unix_ea_name);
+ }
+#ifdef ENOATTR
+ /* Removing a non existent attribute always succeeds. */
+ if (ret == -1 && errno == ENOATTR) {
+ DEBUG(10,("set_ea: deleting ea name %s didn't exist - succeeding by default.\n",
+ unix_ea_name));
+ ret = 0;
+ }
+#endif
+ } else {
+ if (fsp && (fsp->fh->fd != -1)) {
+ DEBUG(10,("set_ea: setting ea name %s on file %s by file descriptor.\n",
+ unix_ea_name, fsp->fsp_name));
+ ret = SMB_VFS_FSETXATTR(fsp, unix_ea_name,
+ ea_list->ea.value.data, ea_list->ea.value.length, 0);
+ } else {
+ DEBUG(10,("set_ea: setting ea name %s on file %s.\n",
+ unix_ea_name, fname));
+ ret = SMB_VFS_SETXATTR(conn, fname, unix_ea_name,
+ ea_list->ea.value.data, ea_list->ea.value.length, 0);
+ }
+ }
+
+ if (ret == -1) {
+#ifdef ENOTSUP
+ if (errno == ENOTSUP) {
+ return NT_STATUS_EAS_NOT_SUPPORTED;
+ }
+#endif
+ return map_nt_error_from_unix(errno);
+ }
+
+ }
+ return NT_STATUS_OK;
+}
+/****************************************************************************
+ Read a list of EA names from an incoming data buffer. Create an ea_list with them.
+****************************************************************************/
+
+static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
+{
+ struct ea_list *ea_list_head = NULL;
+ size_t converted_size, offset = 0;
+
+ while (offset + 2 < data_size) {
+ struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list);
+ unsigned int namelen = CVAL(pdata,offset);
+
+ offset++; /* Go past the namelen byte. */
+
+ /* integer wrap paranioa. */
+ if ((offset + namelen < offset) || (offset + namelen < namelen) ||
+ (offset > data_size) || (namelen > data_size) ||
+ (offset + namelen >= data_size)) {
+ break;
+ }
+ /* Ensure the name is null terminated. */
+ if (pdata[offset + namelen] != '\0') {
+ return NULL;
+ }
+ if (!pull_ascii_talloc(ctx, &eal->ea.name, &pdata[offset],
+ &converted_size)) {
+ DEBUG(0,("read_ea_name_list: pull_ascii_talloc "
+ "failed: %s", strerror(errno)));
+ }
+ if (!eal->ea.name) {
+ return NULL;
+ }
+
+ offset += (namelen + 1); /* Go past the name + terminating zero. */
+ DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
+ DEBUG(10,("read_ea_name_list: read ea name %s\n", eal->ea.name));
+ }
+
+ return ea_list_head;
+}
+
+/****************************************************************************
+ Read one EA list entry from the buffer.
+****************************************************************************/
+
+struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used)
+{
+ struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list);
+ uint16 val_len;
+ unsigned int namelen;
+ size_t converted_size;
+
+ if (!eal) {
+ return NULL;
+ }
+
+ if (data_size < 6) {
+ return NULL;
+ }
+
+ eal->ea.flags = CVAL(pdata,0);
+ namelen = CVAL(pdata,1);
+ val_len = SVAL(pdata,2);
+
+ if (4 + namelen + 1 + val_len > data_size) {
+ return NULL;
+ }
+
+ /* Ensure the name is null terminated. */
+ if (pdata[namelen + 4] != '\0') {
+ return NULL;
+ }
+ if (!pull_ascii_talloc(ctx, &eal->ea.name, pdata + 4, &converted_size)) {
+ DEBUG(0,("read_ea_list_entry: pull_ascii_talloc failed: %s",
+ strerror(errno)));
+ }
+ if (!eal->ea.name) {
+ return NULL;
+ }
+
+ eal->ea.value = data_blob_talloc(eal, NULL, (size_t)val_len + 1);
+ if (!eal->ea.value.data) {
+ return NULL;
+ }
+
+ memcpy(eal->ea.value.data, pdata + 4 + namelen + 1, val_len);
+
+ /* Ensure we're null terminated just in case we print the value. */
+ eal->ea.value.data[val_len] = '\0';
+ /* But don't count the null. */
+ eal->ea.value.length--;
+
+ if (pbytes_used) {
+ *pbytes_used = 4 + namelen + 1 + val_len;
+ }
+
+ DEBUG(10,("read_ea_list_entry: read ea name %s\n", eal->ea.name));
+ dump_data(10, eal->ea.value.data, eal->ea.value.length);
+
+ return eal;
+}
+
+/****************************************************************************
+ Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
+****************************************************************************/
+
+static struct ea_list *read_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
+{
+ struct ea_list *ea_list_head = NULL;
+ size_t offset = 0;
+ size_t bytes_used = 0;
+
+ while (offset < data_size) {
+ struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset, data_size - offset, &bytes_used);
+
+ if (!eal) {
+ return NULL;
+ }
+
+ DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
+ offset += bytes_used;
+ }
+
+ return ea_list_head;
+}
+
+/****************************************************************************
+ Count the total EA size needed.
+****************************************************************************/
+
+static size_t ea_list_size(struct ea_list *ealist)
+{
+ fstring dos_ea_name;
+ struct ea_list *listp;
+ size_t ret = 0;
+
+ for (listp = ealist; listp; listp = listp->next) {
+ push_ascii_fstring(dos_ea_name, listp->ea.name);
+ ret += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
+ }
+ /* Add on 4 for total length. */
+ if (ret) {
+ ret += 4;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Return a union of EA's from a file list and a list of names.
+ The TALLOC context for the two lists *MUST* be identical as we steal
+ memory from one list to add to another. JRA.
+****************************************************************************/
+
+static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list *file_list, size_t *total_ea_len)
+{
+ struct ea_list *nlistp, *flistp;
+
+ for (nlistp = name_list; nlistp; nlistp = nlistp->next) {
+ for (flistp = file_list; flistp; flistp = flistp->next) {
+ if (strequal(nlistp->ea.name, flistp->ea.name)) {
+ break;
+ }
+ }
+
+ if (flistp) {
+ /* Copy the data from this entry. */
+ nlistp->ea.flags = flistp->ea.flags;
+ nlistp->ea.value = flistp->ea.value;
+ } else {
+ /* Null entry. */
+ nlistp->ea.flags = 0;
+ ZERO_STRUCT(nlistp->ea.value);
+ }
+ }
+
+ *total_ea_len = ea_list_size(name_list);
+ return name_list;
+}
+
+/****************************************************************************
+ 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.
+****************************************************************************/
+
+void send_trans2_replies(connection_struct *conn,
+ struct smb_request *req,
+ const char *params,
+ int paramsize,
+ const char *pdata,
+ int datasize,
+ int max_data_bytes)
+{
+ /* 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 */
+
+ int data_to_send = datasize;
+ int params_to_send = paramsize;
+ int useable_space;
+ const char *pp = params;
+ const char *pd = pdata;
+ int params_sent_thistime, data_sent_thistime, total_sent_thistime;
+ int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */
+ int data_alignment_offset = 0;
+ bool overflow = False;
+
+ /* Modify the data_to_send and datasize and set the error if
+ we're trying to send more than max_data_bytes. We still send
+ the part of the packet(s) that fit. Strange, but needed
+ for OS/2. */
+
+ if (max_data_bytes > 0 && datasize > max_data_bytes) {
+ DEBUG(5,("send_trans2_replies: max_data_bytes %d exceeded by data %d\n",
+ max_data_bytes, datasize ));
+ datasize = data_to_send = max_data_bytes;
+ overflow = 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) {
+ reply_outbuf(req, 10, 0);
+ show_msg((char *)req->outbuf);
+ return;
+ }
+
+ /* 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 an even byte
+ boundary. NT 4.0 Beta needs this to work correctly. */
+
+ useable_space = max_send - (smb_size
+ + 2 * 10 /* wct */
+ + alignment_offset
+ + data_alignment_offset);
+
+ if (useable_space < 0) {
+ DEBUG(0, ("send_trans2_replies failed sanity useable_space "
+ "= %d!!!", useable_space));
+ exit_server_cleanly("send_trans2_replies: Not enough space");
+ }
+
+ 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;
+
+ /* We can never send more than useable_space */
+ /*
+ * Note that 'useable_space' does not include the alignment offsets,
+ * but we must include the alignment offsets in the calculation of
+ * the length of the data we send over the wire, as the alignment offsets
+ * are sent here. Fix from Marc_Jacobsen@hp.com.
+ */
+
+ total_sent_thistime = MIN(total_sent_thistime, useable_space);
+
+ reply_outbuf(req, 10, total_sent_thistime + alignment_offset
+ + data_alignment_offset);
+
+ /* Set total params and data to be sent */
+ SSVAL(req->outbuf,smb_tprcnt,paramsize);
+ SSVAL(req->outbuf,smb_tdrcnt,datasize);
+
+ /* Calculate how many parameters and data we can fit into
+ * this packet. Parameters get precedence
+ */
+
+ params_sent_thistime = MIN(params_to_send,useable_space);
+ data_sent_thistime = useable_space - params_sent_thistime;
+ data_sent_thistime = MIN(data_sent_thistime,data_to_send);
+
+ SSVAL(req->outbuf,smb_prcnt, params_sent_thistime);
+
+ /* smb_proff is the offset from the start of the SMB header to the
+ parameter bytes, however the first 4 bytes of outbuf are
+ the Netbios over TCP header. Thus use smb_base() to subtract
+ them from the calculation */
+
+ SSVAL(req->outbuf,smb_proff,
+ ((smb_buf(req->outbuf)+alignment_offset)
+ - smb_base(req->outbuf)));
+
+ if(params_sent_thistime == 0)
+ SSVAL(req->outbuf,smb_prdisp,0);
+ else
+ /* Absolute displacement of param bytes sent in this packet */
+ SSVAL(req->outbuf,smb_prdisp,pp - params);
+
+ SSVAL(req->outbuf,smb_drcnt, data_sent_thistime);
+ if(data_sent_thistime == 0) {
+ SSVAL(req->outbuf,smb_droff,0);
+ SSVAL(req->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(req->outbuf, smb_droff,
+ ((smb_buf(req->outbuf)+alignment_offset)
+ - smb_base(req->outbuf))
+ + params_sent_thistime + data_alignment_offset);
+ SSVAL(req->outbuf,smb_drdisp, pd - pdata);
+ }
+
+ /* Initialize the padding for alignment */
+
+ if (alignment_offset != 0) {
+ memset(smb_buf(req->outbuf), 0, alignment_offset);
+ }
+
+ /* Copy the param bytes into the packet */
+
+ if(params_sent_thistime) {
+ memcpy((smb_buf(req->outbuf)+alignment_offset), pp,
+ params_sent_thistime);
+ }
+
+ /* Copy in the data bytes */
+ if(data_sent_thistime) {
+ if (data_alignment_offset != 0) {
+ memset((smb_buf(req->outbuf)+alignment_offset+
+ params_sent_thistime), 0,
+ data_alignment_offset);
+ }
+ memcpy(smb_buf(req->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));
+
+ if (overflow) {
+ error_packet_set((char *)req->outbuf,
+ ERRDOS,ERRbufferoverflow,
+ STATUS_BUFFER_OVERFLOW,
+ __LINE__,__FILE__);
+ }
+
+ /* Send the packet */
+ show_msg((char *)req->outbuf);
+ if (!srv_send_smb(smbd_server_fd(),
+ (char *)req->outbuf,
+ IS_CONN_ENCRYPTED(conn)))
+ exit_server_cleanly("send_trans2_replies: srv_send_smb failed.");
+
+ TALLOC_FREE(req->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_trans2_replies failed sanity check pts = %d, dts = %d\n!!!",
+ params_to_send, data_to_send));
+ return;
+ }
+ }
+
+ return;
+}
+
+/****************************************************************************
+ Reply to a TRANSACT2_OPEN.
+****************************************************************************/
+
+static void call_trans2open(connection_struct *conn,
+ struct smb_request *req,
+ char **pparams, int total_params,
+ char **ppdata, int total_data,
+ unsigned int max_data_bytes)
+{
+ char *params = *pparams;
+ char *pdata = *ppdata;
+ int deny_mode;
+ int32 open_attr;
+ bool oplock_request;
+#if 0
+ bool return_additional_info;
+ int16 open_sattr;
+ time_t open_time;
+#endif
+ int open_ofun;
+ uint32 open_size;
+ char *pname;
+ char *fname = NULL;
+ SMB_OFF_T size=0;
+ int fattr=0,mtime=0;
+ SMB_INO_T inode = 0;
+ SMB_STRUCT_STAT sbuf;
+ int smb_action = 0;
+ files_struct *fsp;
+ struct ea_list *ea_list = NULL;
+ uint16 flags = 0;
+ NTSTATUS status;
+ uint32 access_mask;
+ uint32 share_mode;
+ uint32 create_disposition;
+ uint32 create_options = 0;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ /*
+ * Ensure we have enough parameters to perform the operation.
+ */
+
+ if (total_params < 29) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ flags = SVAL(params, 0);
+ deny_mode = SVAL(params, 2);
+ open_attr = SVAL(params,6);
+ oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
+ if (oplock_request) {
+ oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+ }
+
+#if 0
+ return_additional_info = BITSETW(params,0);
+ open_sattr = SVAL(params, 4);
+ open_time = make_unix_date3(params+8);
+#endif
+ open_ofun = SVAL(params,12);
+ open_size = IVAL(params,14);
+ pname = &params[28];
+
+ if (IS_IPC(conn)) {
+ reply_doserror(req, ERRSRV, ERRaccess);
+ return;
+ }
+
+ srvstr_get_path(ctx, params, req->flags2, &fname, pname,
+ total_params - 28, STR_TERMINATE,
+ &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+
+ DEBUG(3,("call_trans2open %s deny_mode=0x%x attr=%d ofun=0x%x size=%d\n",
+ fname, (unsigned int)deny_mode, (unsigned int)open_attr,
+ (unsigned int)open_ofun, open_size));
+
+ if (open_ofun == 0) {
+ reply_nterror(req, NT_STATUS_OBJECT_NAME_COLLISION);
+ return;
+ }
+
+ if (!map_open_params_to_ntcreate(fname, deny_mode, open_ofun,
+ &access_mask,
+ &share_mode,
+ &create_disposition,
+ &create_options)) {
+ reply_doserror(req, ERRDOS, ERRbadaccess);
+ return;
+ }
+
+ /* Any data in this call is an EA list. */
+ if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) {
+ reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
+ return;
+ }
+
+ if (total_data != 4) {
+ if (total_data < 10) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ if (IVAL(pdata,0) > total_data) {
+ DEBUG(10,("call_trans2open: bad total data size (%u) > %u\n",
+ IVAL(pdata,0), (unsigned int)total_data));
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ ea_list = read_ea_list(talloc_tos(), pdata + 4,
+ total_data - 4);
+ if (!ea_list) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+ } else if (IVAL(pdata,0) != 4) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ status = create_file(conn, /* conn */
+ req, /* req */
+ 0, /* root_dir_fid */
+ fname, /* fname */
+ access_mask, /* access_mask */
+ share_mode, /* share_access */
+ create_disposition, /* create_disposition*/
+ create_options, /* create_options */
+ open_attr, /* file_attributes */
+ oplock_request, /* oplock_request */
+ open_size, /* allocation_size */
+ NULL, /* sd */
+ ea_list, /* ea_list */
+ &fsp, /* result */
+ &smb_action, /* pinfo */
+ &sbuf); /* psbuf */
+
+ if (!NT_STATUS_IS_OK(status)) {
+ if (open_was_deferred(req->mid)) {
+ /* We have re-scheduled this call. */
+ return;
+ }
+ reply_openerror(req, status);
+ return;
+ }
+
+ size = get_file_size(sbuf);
+ fattr = dos_mode(conn,fsp->fsp_name,&sbuf);
+ mtime = sbuf.st_mtime;
+ inode = sbuf.st_ino;
+ if (fattr & aDIR) {
+ close_file(fsp,ERROR_CLOSE);
+ reply_doserror(req, ERRDOS,ERRnoaccess);
+ return;
+ }
+
+ /* Realloc the size of parameters and data we will return */
+ *pparams = (char *)SMB_REALLOC(*pparams, 30);
+ if(*pparams == NULL ) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ params = *pparams;
+
+ SSVAL(params,0,fsp->fnum);
+ SSVAL(params,2,fattr);
+ srv_put_dos_date2(params,4, mtime);
+ SIVAL(params,8, (uint32)size);
+ SSVAL(params,12,deny_mode);
+ SSVAL(params,14,0); /* open_type - file or directory. */
+ SSVAL(params,16,0); /* open_state - only valid for IPC device. */
+
+ 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);
+ SSVAL(params,24,0); /* Padding. */
+ if (flags & 8) {
+ uint32 ea_size = estimate_ea_size(conn, fsp, fsp->fsp_name);
+ SIVAL(params, 26, ea_size);
+ } else {
+ SIVAL(params, 26, 0);
+ }
+
+ /* Send the required number of replies */
+ send_trans2_replies(conn, req, params, 30, *ppdata, 0, max_data_bytes);
+}
+
+/*********************************************************
+ Routine to check if a given string matches exactly.
+ as a special case a mask of "." does NOT match. That
+ is required for correct wildcard semantics
+ Case can be significant or not.
+**********************************************************/
+
+static bool exact_match(connection_struct *conn,
+ const char *str,
+ const char *mask)
+{
+ if (mask[0] == '.' && mask[1] == 0)
+ return False;
+ if (conn->case_sensitive)
+ return strcmp(str,mask)==0;
+ if (StrCaseCmp(str,mask) != 0) {
+ return False;
+ }
+ if (dptr_has_wild(conn->dirptr)) {
+ return False;
+ }
+ return True;
+}
+
+/****************************************************************************
+ Return the filetype for UNIX extensions.
+****************************************************************************/
+
+static uint32 unix_filetype(mode_t mode)
+{
+ if(S_ISREG(mode))
+ return UNIX_TYPE_FILE;
+ else if(S_ISDIR(mode))
+ return UNIX_TYPE_DIR;
+#ifdef S_ISLNK
+ else if(S_ISLNK(mode))
+ return UNIX_TYPE_SYMLINK;
+#endif
+#ifdef S_ISCHR
+ else if(S_ISCHR(mode))
+ return UNIX_TYPE_CHARDEV;
+#endif
+#ifdef S_ISBLK
+ else if(S_ISBLK(mode))
+ return UNIX_TYPE_BLKDEV;
+#endif
+#ifdef S_ISFIFO
+ else if(S_ISFIFO(mode))
+ return UNIX_TYPE_FIFO;
+#endif
+#ifdef S_ISSOCK
+ else if(S_ISSOCK(mode))
+ return UNIX_TYPE_SOCKET;
+#endif
+
+ DEBUG(0,("unix_filetype: unknown filetype %u", (unsigned)mode));
+ return UNIX_TYPE_UNKNOWN;
+}
+
+/****************************************************************************
+ Map wire perms onto standard UNIX permissions. Obey share restrictions.
+****************************************************************************/
+
+enum perm_type { PERM_NEW_FILE, PERM_NEW_DIR, PERM_EXISTING_FILE, PERM_EXISTING_DIR};
+
+static NTSTATUS unix_perms_from_wire( connection_struct *conn,
+ SMB_STRUCT_STAT *psbuf,
+ uint32 perms,
+ enum perm_type ptype,
+ mode_t *ret_perms)
+{
+ mode_t ret = 0;
+
+ if (perms == SMB_MODE_NO_CHANGE) {
+ if (!VALID_STAT(*psbuf)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ } else {
+ *ret_perms = psbuf->st_mode;
+ return NT_STATUS_OK;
+ }
+ }
+
+ ret |= ((perms & UNIX_X_OTH ) ? S_IXOTH : 0);
+ ret |= ((perms & UNIX_W_OTH ) ? S_IWOTH : 0);
+ ret |= ((perms & UNIX_R_OTH ) ? S_IROTH : 0);
+ ret |= ((perms & UNIX_X_GRP ) ? S_IXGRP : 0);
+ ret |= ((perms & UNIX_W_GRP ) ? S_IWGRP : 0);
+ ret |= ((perms & UNIX_R_GRP ) ? S_IRGRP : 0);
+ ret |= ((perms & UNIX_X_USR ) ? S_IXUSR : 0);
+ ret |= ((perms & UNIX_W_USR ) ? S_IWUSR : 0);
+ ret |= ((perms & UNIX_R_USR ) ? S_IRUSR : 0);
+#ifdef S_ISVTX
+ ret |= ((perms & UNIX_STICKY ) ? S_ISVTX : 0);
+#endif
+#ifdef S_ISGID
+ ret |= ((perms & UNIX_SET_GID ) ? S_ISGID : 0);
+#endif
+#ifdef S_ISUID
+ ret |= ((perms & UNIX_SET_UID ) ? S_ISUID : 0);
+#endif
+
+ switch (ptype) {
+ case PERM_NEW_FILE:
+ /* Apply mode mask */
+ ret &= lp_create_mask(SNUM(conn));
+ /* Add in force bits */
+ ret |= lp_force_create_mode(SNUM(conn));
+ break;
+ case PERM_NEW_DIR:
+ ret &= lp_dir_mask(SNUM(conn));
+ /* Add in force bits */
+ ret |= lp_force_dir_mode(SNUM(conn));
+ break;
+ case PERM_EXISTING_FILE:
+ /* Apply mode mask */
+ ret &= lp_security_mask(SNUM(conn));
+ /* Add in force bits */
+ ret |= lp_force_security_mode(SNUM(conn));
+ break;
+ case PERM_EXISTING_DIR:
+ /* Apply mode mask */
+ ret &= lp_dir_security_mask(SNUM(conn));
+ /* Add in force bits */
+ ret |= lp_force_dir_security_mode(SNUM(conn));
+ break;
+ }
+
+ *ret_perms = ret;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Needed to show the msdfs symlinks as directories. Modifies psbuf
+ to be a directory if it's a msdfs link.
+****************************************************************************/
+
+static bool check_msdfs_link(connection_struct *conn,
+ const char *pathname,
+ SMB_STRUCT_STAT *psbuf)
+{
+ int saved_errno = errno;
+ if(lp_host_msdfs() &&
+ lp_msdfs_root(SNUM(conn)) &&
+ is_msdfs_link(conn, pathname, psbuf)) {
+
+ DEBUG(5,("check_msdfs_link: Masquerading msdfs link %s "
+ "as a directory\n",
+ pathname));
+ psbuf->st_mode = (psbuf->st_mode & 0xFFF) | S_IFDIR;
+ errno = saved_errno;
+ return true;
+ }
+ errno = saved_errno;
+ return false;
+}
+
+
+/****************************************************************************
+ Get a level dependent lanman2 dir entry.
+****************************************************************************/
+
+static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ uint16 flags2,
+ const char *path_mask,
+ uint32 dirtype,
+ int info_level,
+ int requires_resume_key,
+ bool dont_descend,
+ bool ask_sharemode,
+ char **ppdata,
+ char *base_data,
+ char *end_data,
+ int space_remaining,
+ bool *out_of_space,
+ bool *got_exact_match,
+ int *last_entry_off,
+ struct ea_list *name_list)
+{
+ const char *dname;
+ bool found = False;
+ SMB_STRUCT_STAT sbuf;
+ const char *mask = NULL;
+ char *pathreal = NULL;
+ const char *fname = NULL;
+ char *p, *q, *pdata = *ppdata;
+ uint32 reskey=0;
+ long prev_dirpos=0;
+ uint32 mode=0;
+ SMB_OFF_T file_size = 0;
+ SMB_BIG_UINT allocation_size = 0;
+ uint32 len;
+ struct timespec mdate_ts, adate_ts, create_date_ts;
+ time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0;
+ char *nameptr;
+ char *last_entry_ptr;
+ bool was_8_3;
+ uint32 nt_extmode; /* Used for NT connections instead of mode */
+ bool needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
+ bool check_mangled_names = lp_manglednames(conn->params);
+ char mangled_name[13]; /* mangled 8.3 name. */
+
+ *out_of_space = False;
+ *got_exact_match = False;
+
+ ZERO_STRUCT(mdate_ts);
+ ZERO_STRUCT(adate_ts);
+ ZERO_STRUCT(create_date_ts);
+
+ if (!conn->dirptr) {
+ return(False);
+ }
+
+ p = strrchr_m(path_mask,'/');
+ if(p != NULL) {
+ if(p[1] == '\0') {
+ mask = talloc_strdup(ctx,"*.*");
+ } else {
+ mask = p+1;
+ }
+ } else {
+ mask = path_mask;
+ }
+
+ while (!found) {
+ bool got_match;
+ bool ms_dfs_link = False;
+
+ /* Needed if we run out of space */
+ long curr_dirpos = prev_dirpos = dptr_TellDir(conn->dirptr);
+ dname = dptr_ReadDirName(ctx,conn->dirptr,&curr_dirpos,&sbuf);
+
+ /*
+ * Due to bugs in NT client redirectors we are not using
+ * resume keys any more - set them to zero.
+ * Check out the related comments in findfirst/findnext.
+ * JRA.
+ */
+
+ reskey = 0;
+
+ DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %ld\n",
+ (long)conn->dirptr,curr_dirpos));
+
+ if (!dname) {
+ return(False);
+ }
+
+ /*
+ * fname may get mangled, dname is never mangled.
+ * Whenever we're accessing the filesystem we use
+ * pathreal which is composed from dname.
+ */
+
+ pathreal = NULL;
+ fname = dname;
+
+ /* Mangle fname if it's an illegal name. */
+ if (mangle_must_mangle(dname,conn->params)) {
+ if (!name_to_8_3(dname,mangled_name,True,conn->params)) {
+ continue; /* Error - couldn't mangle. */
+ }
+ fname = mangled_name;
+ }
+
+ if(!(got_match = *got_exact_match = exact_match(conn, fname, mask))) {
+ got_match = mask_match(fname, mask, conn->case_sensitive);
+ }
+
+ if(!got_match && check_mangled_names &&
+ !mangle_is_8_3(fname, False, conn->params)) {
+ /*
+ * It turns out that NT matches wildcards against
+ * both long *and* short names. This may explain some
+ * of the wildcard wierdness from old DOS clients
+ * that some people have been seeing.... JRA.
+ */
+ /* Force the mangling into 8.3. */
+ if (!name_to_8_3( fname, mangled_name, False, conn->params)) {
+ continue; /* Error - couldn't mangle. */
+ }
+
+ if(!(got_match = *got_exact_match = exact_match(conn, mangled_name, mask))) {
+ got_match = mask_match(mangled_name, mask, conn->case_sensitive);
+ }
+ }
+
+ if (got_match) {
+ bool isdots = (ISDOT(dname) || ISDOTDOT(dname));
+
+ if (dont_descend && !isdots) {
+ continue;
+ }
+
+ if (needslash) {
+ pathreal = NULL;
+ pathreal = talloc_asprintf(ctx,
+ "%s/%s",
+ conn->dirpath,
+ dname);
+ } else {
+ pathreal = talloc_asprintf(ctx,
+ "%s%s",
+ conn->dirpath,
+ dname);
+ }
+
+ if (!pathreal) {
+ return False;
+ }
+
+ if (INFO_LEVEL_IS_UNIX(info_level)) {
+ if (SMB_VFS_LSTAT(conn,pathreal,&sbuf) != 0) {
+ DEBUG(5,("get_lanman2_dir_entry:Couldn't lstat [%s] (%s)\n",
+ pathreal,strerror(errno)));
+ TALLOC_FREE(pathreal);
+ continue;
+ }
+ } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) {
+ /* Needed to show the msdfs symlinks as
+ * directories */
+
+ ms_dfs_link = check_msdfs_link(conn, pathreal, &sbuf);
+ if (!ms_dfs_link) {
+ DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",
+ pathreal,strerror(errno)));
+ TALLOC_FREE(pathreal);
+ continue;
+ }
+ }
+
+ if (ms_dfs_link) {
+ mode = dos_mode_msdfs(conn,pathreal,&sbuf);
+ } else {
+ mode = dos_mode(conn,pathreal,&sbuf);
+ }
+
+ if (!dir_check_ftype(conn,mode,dirtype)) {
+ DEBUG(5,("get_lanman2_dir_entry: [%s] attribs didn't match %x\n",fname,dirtype));
+ TALLOC_FREE(pathreal);
+ continue;
+ }
+
+ if (!(mode & aDIR)) {
+ file_size = get_file_size(sbuf);
+ }
+ allocation_size = get_allocation_size(conn,NULL,&sbuf);
+
+ mdate_ts = get_mtimespec(&sbuf);
+ adate_ts = get_atimespec(&sbuf);
+ create_date_ts = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+
+ if (ask_sharemode) {
+ struct timespec write_time_ts;
+ struct file_id fileid;
+
+ fileid = vfs_file_id_from_sbuf(conn, &sbuf);
+ get_file_infos(fileid, NULL, &write_time_ts);
+ if (!null_timespec(write_time_ts)) {
+ mdate_ts = write_time_ts;
+ }
+ }
+
+ if (lp_dos_filetime_resolution(SNUM(conn))) {
+ dos_filetime_timespec(&create_date_ts);
+ dos_filetime_timespec(&mdate_ts);
+ dos_filetime_timespec(&adate_ts);
+ }
+
+ create_date = convert_timespec_to_time_t(create_date_ts);
+ mdate = convert_timespec_to_time_t(mdate_ts);
+ adate = convert_timespec_to_time_t(adate_ts);
+
+ DEBUG(5,("get_lanman2_dir_entry: found %s fname=%s\n",pathreal,fname));
+
+ found = True;
+
+ dptr_DirCacheAdd(conn->dirptr, dname, curr_dirpos);
+ }
+ }
+
+ p = pdata;
+ last_entry_ptr = p;
+
+ nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
+
+ switch (info_level) {
+ case SMB_FIND_INFO_STANDARD:
+ DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_INFO_STANDARD\n"));
+ if(requires_resume_key) {
+ SIVAL(p,0,reskey);
+ p += 4;
+ }
+ srv_put_dos_date2(p,0,create_date);
+ srv_put_dos_date2(p,4,adate);
+ srv_put_dos_date2(p,8,mdate);
+ SIVAL(p,12,(uint32)file_size);
+ SIVAL(p,16,(uint32)allocation_size);
+ SSVAL(p,20,mode);
+ p += 23;
+ nameptr = p;
+ if (flags2 & FLAGS2_UNICODE_STRINGS) {
+ p += ucs2_align(base_data, p, 0);
+ }
+ len = srvstr_push(base_data, flags2, p,
+ fname, PTR_DIFF(end_data, p),
+ STR_TERMINATE);
+ if (flags2 & FLAGS2_UNICODE_STRINGS) {
+ if (len > 2) {
+ SCVAL(nameptr, -1, len - 2);
+ } else {
+ SCVAL(nameptr, -1, 0);
+ }
+ } else {
+ if (len > 1) {
+ SCVAL(nameptr, -1, len - 1);
+ } else {
+ SCVAL(nameptr, -1, 0);
+ }
+ }
+ p += len;
+ break;
+
+ case SMB_FIND_EA_SIZE:
+ DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_SIZE\n"));
+ if(requires_resume_key) {
+ SIVAL(p,0,reskey);
+ p += 4;
+ }
+ srv_put_dos_date2(p,0,create_date);
+ srv_put_dos_date2(p,4,adate);
+ srv_put_dos_date2(p,8,mdate);
+ SIVAL(p,12,(uint32)file_size);
+ SIVAL(p,16,(uint32)allocation_size);
+ SSVAL(p,20,mode);
+ {
+ unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+ SIVAL(p,22,ea_size); /* Extended attributes */
+ }
+ p += 27;
+ nameptr = p - 1;
+ len = srvstr_push(base_data, flags2,
+ p, fname, PTR_DIFF(end_data, p),
+ STR_TERMINATE | STR_NOALIGN);
+ if (flags2 & FLAGS2_UNICODE_STRINGS) {
+ if (len > 2) {
+ len -= 2;
+ } else {
+ len = 0;
+ }
+ } else {
+ if (len > 1) {
+ len -= 1;
+ } else {
+ len = 0;
+ }
+ }
+ SCVAL(nameptr,0,len);
+ p += len;
+ SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
+ break;
+
+ case SMB_FIND_EA_LIST:
+ {
+ struct ea_list *file_list = NULL;
+ size_t ea_len = 0;
+
+ DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_LIST\n"));
+ if (!name_list) {
+ return False;
+ }
+ if(requires_resume_key) {
+ SIVAL(p,0,reskey);
+ p += 4;
+ }
+ srv_put_dos_date2(p,0,create_date);
+ srv_put_dos_date2(p,4,adate);
+ srv_put_dos_date2(p,8,mdate);
+ SIVAL(p,12,(uint32)file_size);
+ SIVAL(p,16,(uint32)allocation_size);
+ SSVAL(p,20,mode);
+ p += 22; /* p now points to the EA area. */
+
+ file_list = get_ea_list_from_file(ctx, conn, NULL, pathreal, &ea_len);
+ name_list = ea_list_union(name_list, file_list, &ea_len);
+
+ /* We need to determine if this entry will fit in the space available. */
+ /* Max string size is 255 bytes. */
+ if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) {
+ /* Move the dirptr back to prev_dirpos */
+ dptr_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 */
+ }
+
+ /* Push the ea_data followed by the name. */
+ p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list);
+ nameptr = p;
+ len = srvstr_push(base_data, flags2,
+ p + 1, fname, PTR_DIFF(end_data, p+1),
+ STR_TERMINATE | STR_NOALIGN);
+ if (flags2 & FLAGS2_UNICODE_STRINGS) {
+ if (len > 2) {
+ len -= 2;
+ } else {
+ len = 0;
+ }
+ } else {
+ if (len > 1) {
+ len -= 1;
+ } else {
+ len = 0;
+ }
+ }
+ SCVAL(nameptr,0,len);
+ p += len + 1;
+ SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
+ break;
+ }
+
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
+ was_8_3 = mangle_is_8_3(fname, True, conn->params);
+ p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ put_long_date_timespec(p,create_date_ts); p += 8;
+ put_long_date_timespec(p,adate_ts); p += 8;
+ put_long_date_timespec(p,mdate_ts); p += 8;
+ put_long_date_timespec(p,mdate_ts); p += 8;
+ SOFF_T(p,0,file_size); p += 8;
+ SOFF_T(p,0,allocation_size); p += 8;
+ SIVAL(p,0,nt_extmode); p += 4;
+ q = p; p += 4; /* q is placeholder for name length. */
+ {
+ unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+ SIVAL(p,0,ea_size); /* Extended attributes */
+ p += 4;
+ }
+ /* Clear the short name buffer. This is
+ * IMPORTANT as not doing so will trigger
+ * a Win2k client bug. JRA.
+ */
+ if (!was_8_3 && check_mangled_names) {
+ if (!name_to_8_3(fname,mangled_name,True,
+ conn->params)) {
+ /* Error - mangle failed ! */
+ memset(mangled_name,'\0',12);
+ }
+ mangled_name[12] = 0;
+ len = srvstr_push(base_data, flags2,
+ p+2, mangled_name, 24,
+ STR_UPPER|STR_UNICODE);
+ if (len < 24) {
+ memset(p + 2 + len,'\0',24 - len);
+ }
+ SSVAL(p, 0, len);
+ } else {
+ memset(p,'\0',26);
+ }
+ p += 2 + 24;
+ len = srvstr_push(base_data, flags2, p,
+ fname, PTR_DIFF(end_data, p),
+ STR_TERMINATE_ASCII);
+ SIVAL(q,0,len);
+ p += len;
+ SIVAL(p,0,0); /* Ensure any padding is null. */
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len);
+ p = pdata + len;
+ break;
+
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
+ p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ put_long_date_timespec(p,create_date_ts); p += 8;
+ put_long_date_timespec(p,adate_ts); p += 8;
+ put_long_date_timespec(p,mdate_ts); p += 8;
+ put_long_date_timespec(p,mdate_ts); p += 8;
+ SOFF_T(p,0,file_size); p += 8;
+ SOFF_T(p,0,allocation_size); p += 8;
+ SIVAL(p,0,nt_extmode); p += 4;
+ len = srvstr_push(base_data, flags2,
+ p + 4, fname, PTR_DIFF(end_data, p+4),
+ STR_TERMINATE_ASCII);
+ SIVAL(p,0,len);
+ p += 4 + len;
+ SIVAL(p,0,0); /* Ensure any padding is null. */
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len);
+ p = pdata + len;
+ break;
+
+ case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+ DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
+ p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ put_long_date_timespec(p,create_date_ts); p += 8;
+ put_long_date_timespec(p,adate_ts); p += 8;
+ put_long_date_timespec(p,mdate_ts); p += 8;
+ put_long_date_timespec(p,mdate_ts); p += 8;
+ SOFF_T(p,0,file_size); p += 8;
+ SOFF_T(p,0,allocation_size); p += 8;
+ SIVAL(p,0,nt_extmode); p += 4;
+ q = p; p += 4; /* q is placeholder for name length. */
+ {
+ unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+ SIVAL(p,0,ea_size); /* Extended attributes */
+ p +=4;
+ }
+ len = srvstr_push(base_data, flags2, p,
+ fname, PTR_DIFF(end_data, p),
+ STR_TERMINATE_ASCII);
+ SIVAL(q, 0, len);
+ p += len;
+
+ SIVAL(p,0,0); /* Ensure any padding is null. */
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len);
+ p = pdata + len;
+ break;
+
+ case SMB_FIND_FILE_NAMES_INFO:
+ DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
+ p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ p += 4;
+ /* this must *not* be null terminated or w2k gets in a loop trying to set an
+ acl on a dir (tridge) */
+ len = srvstr_push(base_data, flags2, p,
+ fname, PTR_DIFF(end_data, p),
+ STR_TERMINATE_ASCII);
+ SIVAL(p, -4, len);
+ p += len;
+ SIVAL(p,0,0); /* Ensure any padding is null. */
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len);
+ p = pdata + len;
+ break;
+
+ case SMB_FIND_ID_FULL_DIRECTORY_INFO:
+ DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
+ p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ put_long_date_timespec(p,create_date_ts); p += 8;
+ put_long_date_timespec(p,adate_ts); p += 8;
+ put_long_date_timespec(p,mdate_ts); p += 8;
+ put_long_date_timespec(p,mdate_ts); p += 8;
+ SOFF_T(p,0,file_size); p += 8;
+ SOFF_T(p,0,allocation_size); p += 8;
+ SIVAL(p,0,nt_extmode); p += 4;
+ q = p; p += 4; /* q is placeholder for name length. */
+ {
+ unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+ SIVAL(p,0,ea_size); /* Extended attributes */
+ p +=4;
+ }
+ SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
+ SIVAL(p,0,sbuf.st_ino); p += 4; /* FileIndexLow */
+ SIVAL(p,0,sbuf.st_dev); p += 4; /* FileIndexHigh */
+ len = srvstr_push(base_data, flags2, p,
+ fname, PTR_DIFF(end_data, p),
+ STR_TERMINATE_ASCII);
+ SIVAL(q, 0, len);
+ p += len;
+ SIVAL(p,0,0); /* Ensure any padding is null. */
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len);
+ p = pdata + len;
+ break;
+
+ case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
+ DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
+ was_8_3 = mangle_is_8_3(fname, True, conn->params);
+ p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ put_long_date_timespec(p,create_date_ts); p += 8;
+ put_long_date_timespec(p,adate_ts); p += 8;
+ put_long_date_timespec(p,mdate_ts); p += 8;
+ put_long_date_timespec(p,mdate_ts); p += 8;
+ SOFF_T(p,0,file_size); p += 8;
+ SOFF_T(p,0,allocation_size); p += 8;
+ SIVAL(p,0,nt_extmode); p += 4;
+ q = p; p += 4; /* q is placeholder for name length */
+ {
+ unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+ SIVAL(p,0,ea_size); /* Extended attributes */
+ p +=4;
+ }
+ /* Clear the short name buffer. This is
+ * IMPORTANT as not doing so will trigger
+ * a Win2k client bug. JRA.
+ */
+ if (!was_8_3 && check_mangled_names) {
+ if (!name_to_8_3(fname,mangled_name,True,
+ conn->params)) {
+ /* Error - mangle failed ! */
+ memset(mangled_name,'\0',12);
+ }
+ mangled_name[12] = 0;
+ len = srvstr_push(base_data, flags2,
+ p+2, mangled_name, 24,
+ STR_UPPER|STR_UNICODE);
+ SSVAL(p, 0, len);
+ if (len < 24) {
+ memset(p + 2 + len,'\0',24 - len);
+ }
+ SSVAL(p, 0, len);
+ } else {
+ memset(p,'\0',26);
+ }
+ p += 26;
+ SSVAL(p,0,0); p += 2; /* Reserved ? */
+ SIVAL(p,0,sbuf.st_ino); p += 4; /* FileIndexLow */
+ SIVAL(p,0,sbuf.st_dev); p += 4; /* FileIndexHigh */
+ len = srvstr_push(base_data, flags2, p,
+ fname, PTR_DIFF(end_data, p),
+ STR_TERMINATE_ASCII);
+ SIVAL(q,0,len);
+ p += len;
+ SIVAL(p,0,0); /* Ensure any padding is null. */
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len);
+ p = pdata + len;
+ break;
+
+ /* CIFS UNIX Extension. */
+
+ case SMB_FIND_FILE_UNIX:
+ case SMB_FIND_FILE_UNIX_INFO2:
+ p+= 4;
+ SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */
+
+ /* Begin of SMB_QUERY_FILE_UNIX_BASIC */
+
+ if (info_level == SMB_FIND_FILE_UNIX) {
+ DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
+ p = store_file_unix_basic(conn, p,
+ NULL, &sbuf);
+ len = srvstr_push(base_data, flags2, p,
+ fname, PTR_DIFF(end_data, p),
+ STR_TERMINATE);
+ } else {
+ DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n"));
+ p = store_file_unix_basic_info2(conn, p,
+ NULL, &sbuf);
+ nameptr = p;
+ p += 4;
+ len = srvstr_push(base_data, flags2, p, fname,
+ PTR_DIFF(end_data, p), 0);
+ SIVAL(nameptr, 0, len);
+ }
+
+ p += len;
+ SIVAL(p,0,0); /* Ensure any padding is null. */
+
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len); /* Offset from this structure to the beginning of the next one */
+ p = pdata + len;
+ /* End of SMB_QUERY_FILE_UNIX_BASIC */
+
+ break;
+
+ default:
+ return(False);
+ }
+
+
+ if (PTR_DIFF(p,pdata) > space_remaining) {
+ /* Move the dirptr back to prev_dirpos */
+ dptr_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 entry pointer, as an offset from base_data */
+ *last_entry_off = PTR_DIFF(last_entry_ptr,base_data);
+ /* Advance the data pointer to the next slot */
+ *ppdata = p;
+
+ return(found);
+}
+
+/****************************************************************************
+ Reply to a TRANS2_FINDFIRST.
+****************************************************************************/
+
+static void call_trans2findfirst(connection_struct *conn,
+ struct smb_request *req,
+ char **pparams, int total_params,
+ char **ppdata, int total_data,
+ unsigned int max_data_bytes)
+{
+ /* We must be careful here that we don't return more than the
+ allowed number of data bytes. If this means returning fewer than
+ maxentries then so be it. We assume that the redirector has
+ enough room for the fixed number of parameter bytes it has
+ requested. */
+ char *params = *pparams;
+ char *pdata = *ppdata;
+ char *data_end;
+ uint32 dirtype;
+ int maxentries;
+ uint16 findfirst_flags;
+ bool close_after_first;
+ bool close_if_end;
+ bool requires_resume_key;
+ int info_level;
+ char *directory = NULL;
+ const char *mask = NULL;
+ char *p;
+ int last_entry_off=0;
+ int dptr_num = -1;
+ int numentries = 0;
+ int i;
+ bool finished = False;
+ bool dont_descend = False;
+ bool out_of_space = False;
+ int space_remaining;
+ bool mask_contains_wcard = False;
+ SMB_STRUCT_STAT sbuf;
+ struct ea_list *ea_list = NULL;
+ NTSTATUS ntstatus = NT_STATUS_OK;
+ bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if (total_params < 13) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ dirtype = SVAL(params,0);
+ maxentries = SVAL(params,2);
+ findfirst_flags = SVAL(params,4);
+ close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
+ close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
+ requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
+ info_level = SVAL(params,6);
+
+ DEBUG(3,("call_trans2findfirst: dirtype = %x, maxentries = %d, close_after_first=%d, \
+close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
+ (unsigned int)dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
+ info_level, max_data_bytes));
+
+ if (!maxentries) {
+ /* W2K3 seems to treat zero as 1. */
+ maxentries = 1;
+ }
+
+ switch (info_level) {
+ case SMB_FIND_INFO_STANDARD:
+ case SMB_FIND_EA_SIZE:
+ case SMB_FIND_EA_LIST:
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+ case SMB_FIND_FILE_NAMES_INFO:
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ case SMB_FIND_ID_FULL_DIRECTORY_INFO:
+ case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
+ break;
+ case SMB_FIND_FILE_UNIX:
+ case SMB_FIND_FILE_UNIX_INFO2:
+ /* Always use filesystem for UNIX mtime query. */
+ ask_sharemode = false;
+ if (!lp_unix_extensions()) {
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+ break;
+ default:
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+ srvstr_get_path_wcard(ctx, params, req->flags2, &directory,
+ params+12, total_params - 12,
+ STR_TERMINATE, &ntstatus, &mask_contains_wcard);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ reply_nterror(req, ntstatus);
+ return;
+ }
+
+ ntstatus = resolve_dfspath_wcard(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ directory,
+ &directory,
+ &mask_contains_wcard);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ return;
+ }
+ reply_nterror(req, ntstatus);
+ return;
+ }
+
+ ntstatus = unix_convert(ctx, conn, directory, True, &directory, NULL, &sbuf);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ reply_nterror(req, ntstatus);
+ return;
+ }
+
+ ntstatus = check_name(conn, directory);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ reply_nterror(req, ntstatus);
+ return;
+ }
+
+ p = strrchr_m(directory,'/');
+ if(p == NULL) {
+ /* Windows and OS/2 systems treat search on the root '\' as if it were '\*' */
+ if((directory[0] == '.') && (directory[1] == '\0')) {
+ mask = "*";
+ mask_contains_wcard = True;
+ } else {
+ mask = directory;
+ }
+ directory = talloc_strdup(talloc_tos(), "./");
+ if (!directory) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ } else {
+ mask = p+1;
+ *p = 0;
+ }
+
+ DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
+
+ if (info_level == SMB_FIND_EA_LIST) {
+ uint32 ea_size;
+
+ if (total_data < 4) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ ea_size = IVAL(pdata,0);
+ if (ea_size != total_data) {
+ DEBUG(4,("call_trans2findfirst: Rejecting EA request with incorrect \
+total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ if (!lp_ea_support(SNUM(conn))) {
+ reply_doserror(req, ERRDOS, ERReasnotsupported);
+ return;
+ }
+
+ /* Pull out the list of names. */
+ ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4);
+ if (!ea_list) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+ }
+
+ *ppdata = (char *)SMB_REALLOC(
+ *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
+ if(*ppdata == NULL ) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ pdata = *ppdata;
+ data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
+
+ /* Realloc the params space */
+ *pparams = (char *)SMB_REALLOC(*pparams, 10);
+ if (*pparams == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ params = *pparams;
+
+ /* Save the wildcard match and attribs we are using on this directory -
+ needed as lanman2 assumes these are being saved between calls */
+
+ ntstatus = dptr_create(conn,
+ directory,
+ False,
+ True,
+ req->smbpid,
+ mask,
+ mask_contains_wcard,
+ dirtype,
+ &conn->dirptr);
+
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ reply_nterror(req, ntstatus);
+ return;
+ }
+
+ dptr_num = dptr_dnum(conn->dirptr);
+ DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n", dptr_num, mask, dirtype));
+
+ /* 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", conn->dirpath,lp_dontdescend(SNUM(conn))));
+ if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
+ dont_descend = True;
+
+ p = pdata;
+ space_remaining = max_data_bytes;
+ out_of_space = False;
+
+ for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
+ bool got_exact_match = False;
+
+ /* this is a heuristic to avoid seeking the dirptr except when
+ absolutely necessary. It allows for a filename of about 40 chars */
+ if (space_remaining < DIRLEN_GUESS && numentries > 0) {
+ out_of_space = True;
+ finished = False;
+ } else {
+ finished = !get_lanman2_dir_entry(ctx,
+ conn,
+ req->flags2,
+ mask,dirtype,info_level,
+ requires_resume_key,dont_descend,
+ ask_sharemode,
+ &p,pdata,data_end,
+ space_remaining, &out_of_space,
+ &got_exact_match,
+ &last_entry_off, ea_list);
+ }
+
+ if (finished && out_of_space)
+ finished = False;
+
+ if (!finished && !out_of_space)
+ numentries++;
+
+ /*
+ * As an optimisation if we know we aren't looking
+ * for a wildcard name (ie. the name matches the wildcard exactly)
+ * then we can finish on any (first) match.
+ * This speeds up large directory searches. JRA.
+ */
+
+ if(got_exact_match)
+ finished = True;
+
+ /* Ensure space_remaining never goes -ve. */
+ if (PTR_DIFF(p,pdata) > max_data_bytes) {
+ space_remaining = 0;
+ out_of_space = true;
+ } else {
+ space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
+ }
+ }
+
+ /* Check if we can close the dirptr */
+ if(close_after_first || (finished && close_if_end)) {
+ DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
+ dptr_close(&dptr_num);
+ }
+
+ /*
+ * If there are no matching entries we must return ERRDOS/ERRbadfile -
+ * from observation of NT. NB. This changes to ERRDOS,ERRnofiles if
+ * the protocol level is less than NT1. Tested with smbclient. JRA.
+ * This should fix the OS/2 client bug #2335.
+ */
+
+ if(numentries == 0) {
+ dptr_close(&dptr_num);
+ if (Protocol < PROTOCOL_NT1) {
+ reply_doserror(req, ERRDOS, ERRnofiles);
+ return;
+ } else {
+ reply_botherror(req, NT_STATUS_NO_SUCH_FILE,
+ ERRDOS, ERRbadfile);
+ return;
+ }
+ }
+
+ /* At this point pdata points to numentries directory entries. */
+
+ /* Set up the return parameter block */
+ SSVAL(params,0,dptr_num);
+ SSVAL(params,2,numentries);
+ SSVAL(params,4,finished);
+ SSVAL(params,6,0); /* Never an EA error */
+ SSVAL(params,8,last_entry_off);
+
+ send_trans2_replies(conn, req, params, 10, pdata, PTR_DIFF(p,pdata),
+ max_data_bytes);
+
+ if ((! *directory) && dptr_path(dptr_num)) {
+ directory = talloc_strdup(talloc_tos(),dptr_path(dptr_num));
+ if (!directory) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ }
+ }
+
+ DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
+ smb_fn_name(CVAL(req->inbuf,smb_com)),
+ mask, directory, dirtype, numentries ) );
+
+ /*
+ * Force a name mangle here to ensure that the
+ * mask as an 8.3 name is top of the mangled cache.
+ * The reasons for this are subtle. Don't remove
+ * this code unless you know what you are doing
+ * (see PR#13758). JRA.
+ */
+
+ if(!mangle_is_8_3_wildcards( mask, False, conn->params)) {
+ char mangled_name[13];
+ name_to_8_3(mask, mangled_name, True, conn->params);
+ }
+
+ return;
+}
+
+/****************************************************************************
+ Reply to a TRANS2_FINDNEXT.
+****************************************************************************/
+
+static void call_trans2findnext(connection_struct *conn,
+ struct smb_request *req,
+ char **pparams, int total_params,
+ char **ppdata, int total_data,
+ unsigned int max_data_bytes)
+{
+ /* We must be careful here that we don't return more than the
+ allowed number of data bytes. If this means returning fewer than
+ maxentries then so be it. We assume that the redirector has
+ enough room for the fixed number of parameter bytes it has
+ requested. */
+ char *params = *pparams;
+ char *pdata = *ppdata;
+ char *data_end;
+ int dptr_num;
+ int maxentries;
+ uint16 info_level;
+ uint32 resume_key;
+ uint16 findnext_flags;
+ bool close_after_request;
+ bool close_if_end;
+ bool requires_resume_key;
+ bool continue_bit;
+ bool mask_contains_wcard = False;
+ char *resume_name = NULL;
+ const char *mask = NULL;
+ const char *directory = NULL;
+ char *p = NULL;
+ uint16 dirtype;
+ int numentries = 0;
+ int i, last_entry_off=0;
+ bool finished = False;
+ bool dont_descend = False;
+ bool out_of_space = False;
+ int space_remaining;
+ struct ea_list *ea_list = NULL;
+ NTSTATUS ntstatus = NT_STATUS_OK;
+ bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if (total_params < 13) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ dptr_num = SVAL(params,0);
+ maxentries = SVAL(params,2);
+ info_level = SVAL(params,4);
+ resume_key = IVAL(params,6);
+ findnext_flags = SVAL(params,10);
+ close_after_request = (findnext_flags & FLAG_TRANS2_FIND_CLOSE);
+ close_if_end = (findnext_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
+ requires_resume_key = (findnext_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
+ continue_bit = (findnext_flags & FLAG_TRANS2_FIND_CONTINUE);
+
+ srvstr_get_path_wcard(ctx, params, req->flags2, &resume_name,
+ params+12,
+ total_params - 12, STR_TERMINATE, &ntstatus,
+ &mask_contains_wcard);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ /* Win9x or OS/2 can send a resume name of ".." or ".". This will cause the parser to
+ complain (it thinks we're asking for the directory above the shared
+ path or an invalid name). Catch this as the resume name is only compared, never used in
+ a file access. JRA. */
+ srvstr_pull_talloc(ctx, params, req->flags2,
+ &resume_name, params+12,
+ total_params - 12,
+ STR_TERMINATE);
+
+ if (!resume_name || !(ISDOT(resume_name) || ISDOTDOT(resume_name))) {
+ reply_nterror(req, ntstatus);
+ return;
+ }
+ }
+
+ 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, resume_name, continue_bit, info_level));
+
+ if (!maxentries) {
+ /* W2K3 seems to treat zero as 1. */
+ maxentries = 1;
+ }
+
+ switch (info_level) {
+ case SMB_FIND_INFO_STANDARD:
+ case SMB_FIND_EA_SIZE:
+ case SMB_FIND_EA_LIST:
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+ case SMB_FIND_FILE_NAMES_INFO:
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ case SMB_FIND_ID_FULL_DIRECTORY_INFO:
+ case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
+ break;
+ case SMB_FIND_FILE_UNIX:
+ case SMB_FIND_FILE_UNIX_INFO2:
+ /* Always use filesystem for UNIX mtime query. */
+ ask_sharemode = false;
+ if (!lp_unix_extensions()) {
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+ break;
+ default:
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+ if (info_level == SMB_FIND_EA_LIST) {
+ uint32 ea_size;
+
+ if (total_data < 4) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ ea_size = IVAL(pdata,0);
+ if (ea_size != total_data) {
+ DEBUG(4,("call_trans2findnext: Rejecting EA request with incorrect \
+total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ if (!lp_ea_support(SNUM(conn))) {
+ reply_doserror(req, ERRDOS, ERReasnotsupported);
+ return;
+ }
+
+ /* Pull out the list of names. */
+ ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4);
+ if (!ea_list) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+ }
+
+ *ppdata = (char *)SMB_REALLOC(
+ *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
+ if(*ppdata == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+
+ pdata = *ppdata;
+ data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
+
+ /* Realloc the params space */
+ *pparams = (char *)SMB_REALLOC(*pparams, 6*SIZEOFWORD);
+ if(*pparams == NULL ) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+
+ params = *pparams;
+
+ /* Check that the dptr is valid */
+ if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num))) {
+ reply_doserror(req, ERRDOS, ERRnofiles);
+ return;
+ }
+
+ 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));
+ reply_doserror(req, ERRDOS, ERRnofiles);
+ return;
+ }
+
+ mask = p;
+ 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%lX,%ld)\n",
+ dptr_num, mask, dirtype,
+ (long)conn->dirptr,
+ dptr_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",conn->dirpath,lp_dontdescend(SNUM(conn))));
+ if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
+ dont_descend = True;
+
+ p = pdata;
+ space_remaining = max_data_bytes;
+ out_of_space = False;
+
+ /*
+ * Seek to the correct position. We no longer use the resume key but
+ * depend on the last file name instead.
+ */
+
+ if(*resume_name && !continue_bit) {
+ SMB_STRUCT_STAT st;
+
+ long current_pos = 0;
+ /*
+ * Remember, name_to_8_3 is called by
+ * get_lanman2_dir_entry(), so the resume name
+ * could be mangled. Ensure we check the unmangled name.
+ */
+
+ if (mangle_is_mangled(resume_name, conn->params)) {
+ char *new_resume_name = NULL;
+ mangle_lookup_name_from_8_3(ctx,
+ resume_name,
+ &new_resume_name,
+ conn->params);
+ if (new_resume_name) {
+ resume_name = new_resume_name;
+ }
+ }
+
+ /*
+ * 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.
+ */
+
+ finished = !dptr_SearchDir(conn->dirptr, resume_name, &current_pos, &st);
+ } /* end if resume_name && !continue_bit */
+
+ for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {
+ bool got_exact_match = False;
+
+ /* this is a heuristic to avoid seeking the dirptr except when
+ absolutely necessary. It allows for a filename of about 40 chars */
+ if (space_remaining < DIRLEN_GUESS && numentries > 0) {
+ out_of_space = True;
+ finished = False;
+ } else {
+ finished = !get_lanman2_dir_entry(ctx,
+ conn,
+ req->flags2,
+ mask,dirtype,info_level,
+ requires_resume_key,dont_descend,
+ ask_sharemode,
+ &p,pdata,data_end,
+ space_remaining, &out_of_space,
+ &got_exact_match,
+ &last_entry_off, ea_list);
+ }
+
+ if (finished && out_of_space)
+ finished = False;
+
+ if (!finished && !out_of_space)
+ numentries++;
+
+ /*
+ * As an optimisation if we know we aren't looking
+ * for a wildcard name (ie. the name matches the wildcard exactly)
+ * then we can finish on any (first) match.
+ * This speeds up large directory searches. JRA.
+ */
+
+ if(got_exact_match)
+ finished = True;
+
+ space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
+ }
+
+ DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
+ smb_fn_name(CVAL(req->inbuf,smb_com)),
+ mask, directory, dirtype, numentries ) );
+
+ /* Check if we can close the dirptr */
+ if(close_after_request || (finished && close_if_end)) {
+ DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
+ dptr_close(&dptr_num); /* This frees up the saved mask */
+ }
+
+ /* Set up the return parameter block */
+ SSVAL(params,0,numentries);
+ SSVAL(params,2,finished);
+ SSVAL(params,4,0); /* Never an EA error */
+ SSVAL(params,6,last_entry_off);
+
+ send_trans2_replies(conn, req, params, 8, pdata, PTR_DIFF(p,pdata),
+ max_data_bytes);
+
+ return;
+}
+
+unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16])
+{
+ E_md4hash(lp_servicename(SNUM(conn)),objid);
+ return objid;
+}
+
+static void samba_extended_info_version(struct smb_extended_info *extended_info)
+{
+ SMB_ASSERT(extended_info != NULL);
+
+ extended_info->samba_magic = SAMBA_EXTENDED_INFO_MAGIC;
+ extended_info->samba_version = ((SAMBA_VERSION_MAJOR & 0xff) << 24)
+ | ((SAMBA_VERSION_MINOR & 0xff) << 16)
+ | ((SAMBA_VERSION_RELEASE & 0xff) << 8);
+#ifdef SAMBA_VERSION_REVISION
+ extended_info->samba_version |= (tolower(*SAMBA_VERSION_REVISION) - 'a' + 1) & 0xff;
+#endif
+ extended_info->samba_subversion = 0;
+#ifdef SAMBA_VERSION_RC_RELEASE
+ extended_info->samba_subversion |= (SAMBA_VERSION_RC_RELEASE & 0xff) << 24;
+#else
+#ifdef SAMBA_VERSION_PRE_RELEASE
+ extended_info->samba_subversion |= (SAMBA_VERSION_PRE_RELEASE & 0xff) << 16;
+#endif
+#endif
+#ifdef SAMBA_VERSION_VENDOR_PATCH
+ extended_info->samba_subversion |= (SAMBA_VERSION_VENDOR_PATCH & 0xffff);
+#endif
+ extended_info->samba_gitcommitdate = 0;
+#ifdef SAMBA_VERSION_GIT_COMMIT_TIME
+ unix_to_nt_time(&extended_info->samba_gitcommitdate, SAMBA_VERSION_GIT_COMMIT_TIME);
+#endif
+
+ memset(extended_info->samba_version_string, 0,
+ sizeof(extended_info->samba_version_string));
+
+ snprintf (extended_info->samba_version_string,
+ sizeof(extended_info->samba_version_string),
+ "%s", samba_version_string());
+}
+
+/****************************************************************************
+ Reply to a TRANS2_QFSINFO (query filesystem info).
+****************************************************************************/
+
+static void call_trans2qfsinfo(connection_struct *conn,
+ struct smb_request *req,
+ char **pparams, int total_params,
+ char **ppdata, int total_data,
+ unsigned int max_data_bytes)
+{
+ char *pdata, *end_data;
+ char *params = *pparams;
+ uint16 info_level;
+ int data_len, len;
+ SMB_STRUCT_STAT st;
+ const char *vname = volume_label(SNUM(conn));
+ int snum = SNUM(conn);
+ char *fstype = lp_fstype(SNUM(conn));
+ uint32 additional_flags = 0;
+
+ if (total_params < 2) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ info_level = SVAL(params,0);
+
+ if (IS_IPC(conn)) {
+ if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
+ DEBUG(0,("call_trans2qfsinfo: not an allowed "
+ "info level (0x%x) on IPC$.\n",
+ (unsigned int)info_level));
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+ }
+
+ if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
+ if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
+ DEBUG(0,("call_trans2qfsinfo: encryption required "
+ "and info level 0x%x sent.\n",
+ (unsigned int)info_level));
+ exit_server_cleanly("encryption required "
+ "on connection");
+ return;
+ }
+ }
+
+ DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
+
+ if(SMB_VFS_STAT(conn,".",&st)!=0) {
+ DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno)));
+ reply_doserror(req, ERRSRV, ERRinvdevice);
+ return;
+ }
+
+ *ppdata = (char *)SMB_REALLOC(
+ *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
+ if (*ppdata == NULL ) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+
+ pdata = *ppdata;
+ memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
+ end_data = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
+
+ switch (info_level) {
+ case SMB_INFO_ALLOCATION:
+ {
+ SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
+ data_len = 18;
+ if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (SMB_BIG_UINT)-1) {
+ reply_unixerror(req, ERRHRD, ERRgeneral);
+ return;
+ }
+
+ block_size = lp_block_size(snum);
+ if (bsize < block_size) {
+ SMB_BIG_UINT factor = block_size/bsize;
+ bsize = block_size;
+ dsize /= factor;
+ dfree /= factor;
+ }
+ if (bsize > block_size) {
+ SMB_BIG_UINT factor = bsize/block_size;
+ bsize = block_size;
+ dsize *= factor;
+ dfree *= factor;
+ }
+ bytes_per_sector = 512;
+ sectors_per_unit = bsize/bytes_per_sector;
+
+ DEBUG(5,("call_trans2qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \
+cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit,
+ (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
+
+ SIVAL(pdata,l1_idFileSystem,st.st_dev);
+ SIVAL(pdata,l1_cSectorUnit,sectors_per_unit);
+ SIVAL(pdata,l1_cUnit,dsize);
+ SIVAL(pdata,l1_cUnitAvail,dfree);
+ SSVAL(pdata,l1_cbSector,bytes_per_sector);
+ break;
+ }
+
+ case SMB_INFO_VOLUME:
+ /* Return volume name */
+ /*
+ * Add volume serial number - hash of a combination of
+ * the called hostname and the service name.
+ */
+ SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(get_local_machine_name())<<16) );
+ /*
+ * Win2k3 and previous mess this up by sending a name length
+ * one byte short. I believe only older clients (OS/2 Win9x) use
+ * this call so try fixing this by adding a terminating null to
+ * the pushed string. The change here was adding the STR_TERMINATE. JRA.
+ */
+ len = srvstr_push(
+ pdata, req->flags2,
+ pdata+l2_vol_szVolLabel, vname,
+ PTR_DIFF(end_data, pdata+l2_vol_szVolLabel),
+ STR_NOALIGN|STR_TERMINATE);
+ SCVAL(pdata,l2_vol_cch,len);
+ data_len = l2_vol_szVolLabel + len;
+ DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",
+ (unsigned)st.st_ctime, len, vname));
+ break;
+
+ case SMB_QUERY_FS_ATTRIBUTE_INFO:
+ case SMB_FS_ATTRIBUTE_INFORMATION:
+
+ additional_flags = 0;
+#if defined(HAVE_SYS_QUOTAS)
+ additional_flags |= FILE_VOLUME_QUOTAS;
+#endif
+
+ if(lp_nt_acl_support(SNUM(conn))) {
+ additional_flags |= FILE_PERSISTENT_ACLS;
+ }
+
+ /* Capabilities are filled in at connection time through STATVFS call */
+ additional_flags |= conn->fs_capabilities;
+
+ SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
+ FILE_SUPPORTS_OBJECT_IDS|FILE_UNICODE_ON_DISK|
+ additional_flags); /* FS ATTRIBUTES */
+
+ SIVAL(pdata,4,255); /* Max filename component length */
+ /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
+ and will think we can't do long filenames */
+ len = srvstr_push(pdata, req->flags2, pdata+12, fstype,
+ PTR_DIFF(end_data, pdata+12),
+ STR_UNICODE);
+ SIVAL(pdata,8,len);
+ data_len = 12 + len;
+ break;
+
+ case SMB_QUERY_FS_LABEL_INFO:
+ case SMB_FS_LABEL_INFORMATION:
+ len = srvstr_push(pdata, req->flags2, pdata+4, vname,
+ PTR_DIFF(end_data, pdata+4), 0);
+ data_len = 4 + len;
+ SIVAL(pdata,0,len);
+ break;
+
+ case SMB_QUERY_FS_VOLUME_INFO:
+ case SMB_FS_VOLUME_INFORMATION:
+
+ /*
+ * 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(get_local_machine_name())<<16));
+
+ /* Max label len is 32 characters. */
+ len = srvstr_push(pdata, req->flags2, pdata+18, vname,
+ PTR_DIFF(end_data, pdata+18),
+ STR_UNICODE);
+ SIVAL(pdata,12,len);
+ data_len = 18+len;
+
+ DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n",
+ (int)strlen(vname),vname, lp_servicename(snum)));
+ break;
+
+ case SMB_QUERY_FS_SIZE_INFO:
+ case SMB_FS_SIZE_INFORMATION:
+ {
+ SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
+ data_len = 24;
+ if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (SMB_BIG_UINT)-1) {
+ reply_unixerror(req, ERRHRD, ERRgeneral);
+ return;
+ }
+ block_size = lp_block_size(snum);
+ if (bsize < block_size) {
+ SMB_BIG_UINT factor = block_size/bsize;
+ bsize = block_size;
+ dsize /= factor;
+ dfree /= factor;
+ }
+ if (bsize > block_size) {
+ SMB_BIG_UINT factor = bsize/block_size;
+ bsize = block_size;
+ dsize *= factor;
+ dfree *= factor;
+ }
+ bytes_per_sector = 512;
+ sectors_per_unit = bsize/bytes_per_sector;
+ DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \
+cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
+ (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
+ SBIG_UINT(pdata,0,dsize);
+ SBIG_UINT(pdata,8,dfree);
+ SIVAL(pdata,16,sectors_per_unit);
+ SIVAL(pdata,20,bytes_per_sector);
+ break;
+ }
+
+ case SMB_FS_FULL_SIZE_INFORMATION:
+ {
+ SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
+ data_len = 32;
+ if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (SMB_BIG_UINT)-1) {
+ reply_unixerror(req, ERRHRD, ERRgeneral);
+ return;
+ }
+ block_size = lp_block_size(snum);
+ if (bsize < block_size) {
+ SMB_BIG_UINT factor = block_size/bsize;
+ bsize = block_size;
+ dsize /= factor;
+ dfree /= factor;
+ }
+ if (bsize > block_size) {
+ SMB_BIG_UINT factor = bsize/block_size;
+ bsize = block_size;
+ dsize *= factor;
+ dfree *= factor;
+ }
+ bytes_per_sector = 512;
+ sectors_per_unit = bsize/bytes_per_sector;
+ DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \
+cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
+ (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
+ SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */
+ SBIG_UINT(pdata,8,dfree); /* Caller available allocation units. */
+ SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */
+ SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */
+ SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */
+ break;
+ }
+
+ case SMB_QUERY_FS_DEVICE_INFO:
+ case SMB_FS_DEVICE_INFORMATION:
+ data_len = 8;
+ SIVAL(pdata,0,0); /* dev type */
+ SIVAL(pdata,4,0); /* characteristics */
+ break;
+
+#ifdef HAVE_SYS_QUOTAS
+ case SMB_FS_QUOTA_INFORMATION:
+ /*
+ * what we have to send --metze:
+ *
+ * Unknown1: 24 NULL bytes
+ * Soft Quota Treshold: 8 bytes seems like SMB_BIG_UINT or so
+ * Hard Quota Limit: 8 bytes seems like SMB_BIG_UINT or so
+ * Quota Flags: 2 byte :
+ * Unknown3: 6 NULL bytes
+ *
+ * 48 bytes total
+ *
+ * details for Quota Flags:
+ *
+ * 0x0020 Log Limit: log if the user exceeds his Hard Quota
+ * 0x0010 Log Warn: log if the user exceeds his Soft Quota
+ * 0x0002 Deny Disk: deny disk access when the user exceeds his Hard Quota
+ * 0x0001 Enable Quotas: enable quota for this fs
+ *
+ */
+ {
+ /* we need to fake up a fsp here,
+ * because its not send in this call
+ */
+ files_struct fsp;
+ SMB_NTQUOTA_STRUCT quotas;
+
+ ZERO_STRUCT(fsp);
+ ZERO_STRUCT(quotas);
+
+ fsp.conn = conn;
+ fsp.fnum = -1;
+
+ /* access check */
+ if (conn->server_info->utok.uid != 0) {
+ DEBUG(0,("set_user_quota: access_denied "
+ "service [%s] user [%s]\n",
+ lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name));
+ reply_doserror(req, ERRDOS, ERRnoaccess);
+ return;
+ }
+
+ if (vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
+ DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
+ reply_doserror(req, ERRSRV, ERRerror);
+ return;
+ }
+
+ data_len = 48;
+
+ DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",lp_servicename(SNUM(conn))));
+
+ /* Unknown1 24 NULL bytes*/
+ SBIG_UINT(pdata,0,(SMB_BIG_UINT)0);
+ SBIG_UINT(pdata,8,(SMB_BIG_UINT)0);
+ SBIG_UINT(pdata,16,(SMB_BIG_UINT)0);
+
+ /* Default Soft Quota 8 bytes */
+ SBIG_UINT(pdata,24,quotas.softlim);
+
+ /* Default Hard Quota 8 bytes */
+ SBIG_UINT(pdata,32,quotas.hardlim);
+
+ /* Quota flag 2 bytes */
+ SSVAL(pdata,40,quotas.qflags);
+
+ /* Unknown3 6 NULL bytes */
+ SSVAL(pdata,42,0);
+ SIVAL(pdata,44,0);
+
+ break;
+ }
+#endif /* HAVE_SYS_QUOTAS */
+ case SMB_FS_OBJECTID_INFORMATION:
+ {
+ unsigned char objid[16];
+ struct smb_extended_info extended_info;
+ memcpy(pdata,create_volume_objectid(conn, objid),16);
+ samba_extended_info_version (&extended_info);
+ SIVAL(pdata,16,extended_info.samba_magic);
+ SIVAL(pdata,20,extended_info.samba_version);
+ SIVAL(pdata,24,extended_info.samba_subversion);
+ SBIG_UINT(pdata,28,extended_info.samba_gitcommitdate);
+ memcpy(pdata+36,extended_info.samba_version_string,28);
+ data_len = 64;
+ break;
+ }
+
+ /*
+ * Query the version and capabilities of the CIFS UNIX extensions
+ * in use.
+ */
+
+ case SMB_QUERY_CIFS_UNIX_INFO:
+ {
+ bool large_write = lp_min_receive_file_size() &&
+ !srv_is_signing_active();
+ bool large_read = !srv_is_signing_active();
+ int encrypt_caps = 0;
+
+ if (!lp_unix_extensions()) {
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+ switch (conn->encrypt_level) {
+ case 0:
+ encrypt_caps = 0;
+ break;
+ case 1:
+ case Auto:
+ encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP;
+ break;
+ case Required:
+ encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP|
+ CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP;
+ large_write = false;
+ large_read = false;
+ break;
+ }
+
+ data_len = 12;
+ SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
+ SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
+
+ /* We have POSIX ACLs, pathname, encryption,
+ * large read/write, and locking capability. */
+
+ SBIG_UINT(pdata,4,((SMB_BIG_UINT)(
+ CIFS_UNIX_POSIX_ACLS_CAP|
+ CIFS_UNIX_POSIX_PATHNAMES_CAP|
+ CIFS_UNIX_FCNTL_LOCKS_CAP|
+ CIFS_UNIX_EXTATTR_CAP|
+ CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP|
+ encrypt_caps|
+ (large_read ? CIFS_UNIX_LARGE_READ_CAP : 0) |
+ (large_write ?
+ CIFS_UNIX_LARGE_WRITE_CAP : 0))));
+ break;
+ }
+
+ case SMB_QUERY_POSIX_FS_INFO:
+ {
+ int rc;
+ vfs_statvfs_struct svfs;
+
+ if (!lp_unix_extensions()) {
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+ rc = SMB_VFS_STATVFS(conn, ".", &svfs);
+
+ if (!rc) {
+ data_len = 56;
+ SIVAL(pdata,0,svfs.OptimalTransferSize);
+ SIVAL(pdata,4,svfs.BlockSize);
+ SBIG_UINT(pdata,8,svfs.TotalBlocks);
+ SBIG_UINT(pdata,16,svfs.BlocksAvail);
+ SBIG_UINT(pdata,24,svfs.UserBlocksAvail);
+ SBIG_UINT(pdata,32,svfs.TotalFileNodes);
+ SBIG_UINT(pdata,40,svfs.FreeFileNodes);
+ SBIG_UINT(pdata,48,svfs.FsIdentifier);
+ DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n"));
+#ifdef EOPNOTSUPP
+ } else if (rc == EOPNOTSUPP) {
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+#endif /* EOPNOTSUPP */
+ } else {
+ DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(SNUM(conn))));
+ reply_doserror(req, ERRSRV, ERRerror);
+ return;
+ }
+ break;
+ }
+
+ case SMB_QUERY_POSIX_WHOAMI:
+ {
+ uint32_t flags = 0;
+ uint32_t sid_bytes;
+ int i;
+
+ if (!lp_unix_extensions()) {
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+ if (max_data_bytes < 40) {
+ reply_nterror(req, NT_STATUS_BUFFER_TOO_SMALL);
+ return;
+ }
+
+ /* We ARE guest if global_sid_Builtin_Guests is
+ * in our list of SIDs.
+ */
+ if (nt_token_check_sid(&global_sid_Builtin_Guests,
+ conn->server_info->ptok)) {
+ flags |= SMB_WHOAMI_GUEST;
+ }
+
+ /* We are NOT guest if global_sid_Authenticated_Users
+ * is in our list of SIDs.
+ */
+ if (nt_token_check_sid(&global_sid_Authenticated_Users,
+ conn->server_info->ptok)) {
+ flags &= ~SMB_WHOAMI_GUEST;
+ }
+
+ /* NOTE: 8 bytes for UID/GID, irrespective of native
+ * platform size. This matches
+ * SMB_QUERY_FILE_UNIX_BASIC and friends.
+ */
+ data_len = 4 /* flags */
+ + 4 /* flag mask */
+ + 8 /* uid */
+ + 8 /* gid */
+ + 4 /* ngroups */
+ + 4 /* num_sids */
+ + 4 /* SID bytes */
+ + 4 /* pad/reserved */
+ + (conn->server_info->utok.ngroups * 8)
+ /* groups list */
+ + (conn->server_info->ptok->num_sids *
+ SID_MAX_SIZE)
+ /* SID list */;
+
+ SIVAL(pdata, 0, flags);
+ SIVAL(pdata, 4, SMB_WHOAMI_MASK);
+ SBIG_UINT(pdata, 8,
+ (SMB_BIG_UINT)conn->server_info->utok.uid);
+ SBIG_UINT(pdata, 16,
+ (SMB_BIG_UINT)conn->server_info->utok.gid);
+
+
+ if (data_len >= max_data_bytes) {
+ /* Potential overflow, skip the GIDs and SIDs. */
+
+ SIVAL(pdata, 24, 0); /* num_groups */
+ SIVAL(pdata, 28, 0); /* num_sids */
+ SIVAL(pdata, 32, 0); /* num_sid_bytes */
+ SIVAL(pdata, 36, 0); /* reserved */
+
+ data_len = 40;
+ break;
+ }
+
+ SIVAL(pdata, 24, conn->server_info->utok.ngroups);
+ SIVAL(pdata, 28, conn->server_info->num_sids);
+
+ /* We walk the SID list twice, but this call is fairly
+ * infrequent, and I don't expect that it's performance
+ * sensitive -- jpeach
+ */
+ for (i = 0, sid_bytes = 0;
+ i < conn->server_info->ptok->num_sids; ++i) {
+ sid_bytes += ndr_size_dom_sid(
+ &conn->server_info->ptok->user_sids[i],
+ 0);
+ }
+
+ /* SID list byte count */
+ SIVAL(pdata, 32, sid_bytes);
+
+ /* 4 bytes pad/reserved - must be zero */
+ SIVAL(pdata, 36, 0);
+ data_len = 40;
+
+ /* GID list */
+ for (i = 0; i < conn->server_info->utok.ngroups; ++i) {
+ SBIG_UINT(pdata, data_len,
+ (SMB_BIG_UINT)conn->server_info->utok.groups[i]);
+ data_len += 8;
+ }
+
+ /* SID list */
+ for (i = 0;
+ i < conn->server_info->ptok->num_sids; ++i) {
+ int sid_len = ndr_size_dom_sid(
+ &conn->server_info->ptok->user_sids[i],
+ 0);
+
+ sid_linearize(pdata + data_len, sid_len,
+ &conn->server_info->ptok->user_sids[i]);
+ data_len += sid_len;
+ }
+
+ break;
+ }
+
+ case SMB_MAC_QUERY_FS_INFO:
+ /*
+ * Thursby MAC extension... ONLY on NTFS filesystems
+ * once we do streams then we don't need this
+ */
+ if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
+ data_len = 88;
+ SIVAL(pdata,84,0x100); /* Don't support mac... */
+ break;
+ }
+ /* drop through */
+ default:
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+
+ send_trans2_replies(conn, req, params, 0, pdata, data_len,
+ max_data_bytes);
+
+ DEBUG( 4, ( "%s info_level = %d\n",
+ smb_fn_name(CVAL(req->inbuf,smb_com)), info_level) );
+
+ return;
+}
+
+/****************************************************************************
+ Reply to a TRANS2_SETFSINFO (set filesystem info).
+****************************************************************************/
+
+static void call_trans2setfsinfo(connection_struct *conn,
+ struct smb_request *req,
+ char **pparams, int total_params,
+ char **ppdata, int total_data,
+ unsigned int max_data_bytes)
+{
+ char *pdata = *ppdata;
+ char *params = *pparams;
+ uint16 info_level;
+
+ DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",lp_servicename(SNUM(conn))));
+
+ /* */
+ if (total_params < 4) {
+ DEBUG(0,("call_trans2setfsinfo: requires total_params(%d) >= 4 bytes!\n",
+ total_params));
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ info_level = SVAL(params,2);
+
+ if (IS_IPC(conn)) {
+ if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION &&
+ info_level != SMB_SET_CIFS_UNIX_INFO) {
+ DEBUG(0,("call_trans2setfsinfo: not an allowed "
+ "info level (0x%x) on IPC$.\n",
+ (unsigned int)info_level));
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+ }
+
+ if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
+ if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION) {
+ DEBUG(0,("call_trans2setfsinfo: encryption required "
+ "and info level 0x%x sent.\n",
+ (unsigned int)info_level));
+ exit_server_cleanly("encryption required "
+ "on connection");
+ return;
+ }
+ }
+
+ switch(info_level) {
+ case SMB_SET_CIFS_UNIX_INFO:
+ {
+ uint16 client_unix_major;
+ uint16 client_unix_minor;
+ uint32 client_unix_cap_low;
+ uint32 client_unix_cap_high;
+
+ if (!lp_unix_extensions()) {
+ reply_nterror(req,
+ NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+ /* There should be 12 bytes of capabilities set. */
+ if (total_data < 8) {
+ reply_nterror(
+ req,
+ NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+ client_unix_major = SVAL(pdata,0);
+ client_unix_minor = SVAL(pdata,2);
+ client_unix_cap_low = IVAL(pdata,4);
+ client_unix_cap_high = IVAL(pdata,8);
+ /* Just print these values for now. */
+ DEBUG(10,("call_trans2setfsinfo: set unix info. major = %u, minor = %u \
+cap_low = 0x%x, cap_high = 0x%x\n",
+ (unsigned int)client_unix_major,
+ (unsigned int)client_unix_minor,
+ (unsigned int)client_unix_cap_low,
+ (unsigned int)client_unix_cap_high ));
+
+ /* Here is where we must switch to posix pathname processing... */
+ if (client_unix_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+ lp_set_posix_pathnames();
+ mangle_change_to_posix();
+ }
+
+ if ((client_unix_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) &&
+ !(client_unix_cap_low & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)) {
+ /* Client that knows how to do posix locks,
+ * but not posix open/mkdir operations. Set a
+ * default type for read/write checks. */
+
+ lp_set_posix_default_cifsx_readwrite_locktype(POSIX_LOCK);
+
+ }
+ break;
+ }
+
+ case SMB_REQUEST_TRANSPORT_ENCRYPTION:
+ {
+ NTSTATUS status;
+ size_t param_len = 0;
+ size_t data_len = total_data;
+
+ if (!lp_unix_extensions()) {
+ reply_nterror(
+ req,
+ NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+ if (lp_smb_encrypt(SNUM(conn)) == false) {
+ reply_nterror(
+ req,
+ NT_STATUS_NOT_SUPPORTED);
+ return;
+ }
+
+ DEBUG( 4,("call_trans2setfsinfo: "
+ "request transport encryption.\n"));
+
+ status = srv_request_encryption_setup(conn,
+ (unsigned char **)ppdata,
+ &data_len,
+ (unsigned char **)pparams,
+ &param_len);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
+ !NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+
+ send_trans2_replies(conn, req,
+ *pparams,
+ param_len,
+ *ppdata,
+ data_len,
+ max_data_bytes);
+
+ if (NT_STATUS_IS_OK(status)) {
+ /* Server-side transport
+ * encryption is now *on*. */
+ status = srv_encryption_start(conn);
+ if (!NT_STATUS_IS_OK(status)) {
+ exit_server_cleanly(
+ "Failure in setting "
+ "up encrypted transport");
+ }
+ }
+ return;
+ }
+
+ case SMB_FS_QUOTA_INFORMATION:
+ {
+ files_struct *fsp = NULL;
+ SMB_NTQUOTA_STRUCT quotas;
+
+ ZERO_STRUCT(quotas);
+
+ /* access check */
+ if ((conn->server_info->utok.uid != 0)
+ ||!CAN_WRITE(conn)) {
+ DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n",
+ lp_servicename(SNUM(conn)),
+ conn->server_info->unix_name));
+ reply_doserror(req, ERRSRV, ERRaccess);
+ return;
+ }
+
+ /* note: normaly there're 48 bytes,
+ * but we didn't use the last 6 bytes for now
+ * --metze
+ */
+ fsp = file_fsp(SVAL(params,0));
+
+ if (!check_fsp_ntquota_handle(conn, req,
+ fsp)) {
+ DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n"));
+ reply_nterror(
+ req, NT_STATUS_INVALID_HANDLE);
+ return;
+ }
+
+ if (total_data < 42) {
+ DEBUG(0,("call_trans2setfsinfo: SET_FS_QUOTA: requires total_data(%d) >= 42 bytes!\n",
+ total_data));
+ reply_nterror(
+ req,
+ NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ /* unknown_1 24 NULL bytes in pdata*/
+
+ /* the soft quotas 8 bytes (SMB_BIG_UINT)*/
+ quotas.softlim = (SMB_BIG_UINT)IVAL(pdata,24);
+#ifdef LARGE_SMB_OFF_T
+ quotas.softlim |= (((SMB_BIG_UINT)IVAL(pdata,28)) << 32);
+#else /* LARGE_SMB_OFF_T */
+ if ((IVAL(pdata,28) != 0)&&
+ ((quotas.softlim != 0xFFFFFFFF)||
+ (IVAL(pdata,28)!=0xFFFFFFFF))) {
+ /* more than 32 bits? */
+ reply_nterror(
+ req,
+ NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ /* the hard quotas 8 bytes (SMB_BIG_UINT)*/
+ quotas.hardlim = (SMB_BIG_UINT)IVAL(pdata,32);
+#ifdef LARGE_SMB_OFF_T
+ quotas.hardlim |= (((SMB_BIG_UINT)IVAL(pdata,36)) << 32);
+#else /* LARGE_SMB_OFF_T */
+ if ((IVAL(pdata,36) != 0)&&
+ ((quotas.hardlim != 0xFFFFFFFF)||
+ (IVAL(pdata,36)!=0xFFFFFFFF))) {
+ /* more than 32 bits? */
+ reply_nterror(
+ req,
+ NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ /* quota_flags 2 bytes **/
+ quotas.qflags = SVAL(pdata,40);
+
+ /* unknown_2 6 NULL bytes follow*/
+
+ /* now set the quotas */
+ if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
+ DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
+ reply_doserror(req, ERRSRV, ERRerror);
+ return;
+ }
+
+ break;
+ }
+ default:
+ DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n",
+ info_level));
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ break;
+ }
+
+ /*
+ * sending this reply works fine,
+ * but I'm not sure it's the same
+ * like windows do...
+ * --metze
+ */
+ reply_outbuf(req, 10, 0);
+}
+
+#if defined(HAVE_POSIX_ACLS)
+/****************************************************************************
+ Utility function to count the number of entries in a POSIX acl.
+****************************************************************************/
+
+static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
+{
+ unsigned int ace_count = 0;
+ int entry_id = SMB_ACL_FIRST_ENTRY;
+ SMB_ACL_ENTRY_T entry;
+
+ while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
+ /* get_next... */
+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
+ entry_id = SMB_ACL_NEXT_ENTRY;
+ }
+ ace_count++;
+ }
+ return ace_count;
+}
+
+/****************************************************************************
+ Utility function to marshall a POSIX acl into wire format.
+****************************************************************************/
+
+static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
+{
+ int entry_id = SMB_ACL_FIRST_ENTRY;
+ SMB_ACL_ENTRY_T entry;
+
+ while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
+ SMB_ACL_TAG_T tagtype;
+ SMB_ACL_PERMSET_T permset;
+ unsigned char perms = 0;
+ unsigned int own_grp;
+
+ /* get_next... */
+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
+ entry_id = SMB_ACL_NEXT_ENTRY;
+ }
+
+ if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
+ DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
+ return False;
+ }
+
+ if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
+ DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
+ return False;
+ }
+
+ perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
+ perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
+ perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
+
+ SCVAL(pdata,1,perms);
+
+ switch (tagtype) {
+ case SMB_ACL_USER_OBJ:
+ SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
+ own_grp = (unsigned int)pst->st_uid;
+ SIVAL(pdata,2,own_grp);
+ SIVAL(pdata,6,0);
+ break;
+ case SMB_ACL_USER:
+ {
+ uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+ if (!puid) {
+ DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
+ return False;
+ }
+ own_grp = (unsigned int)*puid;
+ SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
+ SCVAL(pdata,0,SMB_POSIX_ACL_USER);
+ SIVAL(pdata,2,own_grp);
+ SIVAL(pdata,6,0);
+ break;
+ }
+ case SMB_ACL_GROUP_OBJ:
+ SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
+ own_grp = (unsigned int)pst->st_gid;
+ SIVAL(pdata,2,own_grp);
+ SIVAL(pdata,6,0);
+ break;
+ case SMB_ACL_GROUP:
+ {
+ gid_t *pgid= (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+ if (!pgid) {
+ DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
+ return False;
+ }
+ own_grp = (unsigned int)*pgid;
+ SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
+ SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
+ SIVAL(pdata,2,own_grp);
+ SIVAL(pdata,6,0);
+ break;
+ }
+ case SMB_ACL_MASK:
+ SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
+ SIVAL(pdata,2,0xFFFFFFFF);
+ SIVAL(pdata,6,0xFFFFFFFF);
+ break;
+ case SMB_ACL_OTHER:
+ SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
+ SIVAL(pdata,2,0xFFFFFFFF);
+ SIVAL(pdata,6,0xFFFFFFFF);
+ break;
+ default:
+ DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
+ return False;
+ }
+ pdata += SMB_POSIX_ACL_ENTRY_SIZE;
+ }
+
+ return True;
+}
+#endif
+
+/****************************************************************************
+ Store the FILE_UNIX_BASIC info.
+****************************************************************************/
+
+static char *store_file_unix_basic(connection_struct *conn,
+ char *pdata,
+ files_struct *fsp,
+ const SMB_STRUCT_STAT *psbuf)
+{
+ DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n"));
+ DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_mode));
+
+ SOFF_T(pdata,0,get_file_size(*psbuf)); /* File size 64 Bit */
+ pdata += 8;
+
+ SOFF_T(pdata,0,get_allocation_size(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */
+ pdata += 8;
+
+ put_long_date_timespec(pdata,get_ctimespec(psbuf)); /* Change Time 64 Bit */
+ put_long_date_timespec(pdata+8,get_atimespec(psbuf)); /* Last access time 64 Bit */
+ put_long_date_timespec(pdata+16,get_mtimespec(psbuf)); /* Last modification time 64 Bit */
+ pdata += 24;
+
+ SIVAL(pdata,0,psbuf->st_uid); /* user id for the owner */
+ SIVAL(pdata,4,0);
+ pdata += 8;
+
+ SIVAL(pdata,0,psbuf->st_gid); /* group id of owner */
+ SIVAL(pdata,4,0);
+ pdata += 8;
+
+ SIVAL(pdata,0,unix_filetype(psbuf->st_mode));
+ pdata += 4;
+
+ SIVAL(pdata,0,unix_dev_major(psbuf->st_rdev)); /* Major device number if type is device */
+ SIVAL(pdata,4,0);
+ pdata += 8;
+
+ SIVAL(pdata,0,unix_dev_minor(psbuf->st_rdev)); /* Minor device number if type is device */
+ SIVAL(pdata,4,0);
+ pdata += 8;
+
+ SINO_T_VAL(pdata,0,(SMB_INO_T)psbuf->st_ino); /* inode number */
+ pdata += 8;
+
+ SIVAL(pdata,0, unix_perms_to_wire(psbuf->st_mode)); /* Standard UNIX file permissions */
+ SIVAL(pdata,4,0);
+ pdata += 8;
+
+ SIVAL(pdata,0,psbuf->st_nlink); /* number of hard links */
+ SIVAL(pdata,4,0);
+ pdata += 8;
+
+ return pdata;
+}
+
+/* Forward and reverse mappings from the UNIX_INFO2 file flags field and
+ * the chflags(2) (or equivalent) flags.
+ *
+ * XXX: this really should be behind the VFS interface. To do this, we would
+ * need to alter SMB_STRUCT_STAT so that it included a flags and a mask field.
+ * Each VFS module could then implement its own mapping as appropriate for the
+ * platform. We would then pass the SMB flags into SMB_VFS_CHFLAGS.
+ */
+static const struct {unsigned stat_fflag; unsigned smb_fflag;}
+ info2_flags_map[] =
+{
+#ifdef UF_NODUMP
+ { UF_NODUMP, EXT_DO_NOT_BACKUP },
+#endif
+
+#ifdef UF_IMMUTABLE
+ { UF_IMMUTABLE, EXT_IMMUTABLE },
+#endif
+
+#ifdef UF_APPEND
+ { UF_APPEND, EXT_OPEN_APPEND_ONLY },
+#endif
+
+#ifdef UF_HIDDEN
+ { UF_HIDDEN, EXT_HIDDEN },
+#endif
+
+ /* Do not remove. We need to guarantee that this array has at least one
+ * entry to build on HP-UX.
+ */
+ { 0, 0 }
+
+};
+
+static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf,
+ uint32 *smb_fflags, uint32 *smb_fmask)
+{
+#ifdef HAVE_STAT_ST_FLAGS
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
+ *smb_fmask |= info2_flags_map[i].smb_fflag;
+ if (psbuf->st_flags & info2_flags_map[i].stat_fflag) {
+ *smb_fflags |= info2_flags_map[i].smb_fflag;
+ }
+ }
+#endif /* HAVE_STAT_ST_FLAGS */
+}
+
+static bool map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf,
+ const uint32 smb_fflags,
+ const uint32 smb_fmask,
+ int *stat_fflags)
+{
+#ifdef HAVE_STAT_ST_FLAGS
+ uint32 max_fmask = 0;
+ int i;
+
+ *stat_fflags = psbuf->st_flags;
+
+ /* For each flags requested in smb_fmask, check the state of the
+ * corresponding flag in smb_fflags and set or clear the matching
+ * stat flag.
+ */
+
+ for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
+ max_fmask |= info2_flags_map[i].smb_fflag;
+ if (smb_fmask & info2_flags_map[i].smb_fflag) {
+ if (smb_fflags & info2_flags_map[i].smb_fflag) {
+ *stat_fflags |= info2_flags_map[i].stat_fflag;
+ } else {
+ *stat_fflags &= ~info2_flags_map[i].stat_fflag;
+ }
+ }
+ }
+
+ /* If smb_fmask is asking to set any bits that are not supported by
+ * our flag mappings, we should fail.
+ */
+ if ((smb_fmask & max_fmask) != smb_fmask) {
+ return False;
+ }
+
+ return True;
+#else
+ return False;
+#endif /* HAVE_STAT_ST_FLAGS */
+}
+
+
+/* Just like SMB_QUERY_FILE_UNIX_BASIC, but with the addition
+ * of file flags and birth (create) time.
+ */
+static char *store_file_unix_basic_info2(connection_struct *conn,
+ char *pdata,
+ files_struct *fsp,
+ const SMB_STRUCT_STAT *psbuf)
+{
+ uint32 file_flags = 0;
+ uint32 flags_mask = 0;
+
+ pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
+
+ /* Create (birth) time 64 bit */
+ put_long_date_timespec(pdata, get_create_timespec(psbuf, False));
+ pdata += 8;
+
+ map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask);
+ SIVAL(pdata, 0, file_flags); /* flags */
+ SIVAL(pdata, 4, flags_mask); /* mask */
+ pdata += 8;
+
+ return pdata;
+}
+
+static NTSTATUS marshall_stream_info(unsigned int num_streams,
+ const struct stream_struct *streams,
+ char *data,
+ unsigned int max_data_bytes,
+ unsigned int *data_size)
+{
+ unsigned int i;
+ unsigned int ofs = 0;
+
+ for (i=0; i<num_streams; i++) {
+ unsigned int next_offset;
+ size_t namelen;
+ smb_ucs2_t *namebuf;
+
+ if (!push_ucs2_talloc(talloc_tos(), &namebuf,
+ streams[i].name, &namelen) ||
+ namelen <= 2)
+ {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /*
+ * name_buf is now null-terminated, we need to marshall as not
+ * terminated
+ */
+
+ namelen -= 2;
+
+ if (ofs + 24 + namelen > max_data_bytes) {
+ TALLOC_FREE(namebuf);
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ SIVAL(data, ofs+4, namelen);
+ SOFF_T(data, ofs+8, streams[i].size);
+ SOFF_T(data, ofs+16, streams[i].alloc_size);
+ memcpy(data+ofs+24, namebuf, namelen);
+ TALLOC_FREE(namebuf);
+
+ next_offset = ofs + 24 + namelen;
+
+ if (i == num_streams-1) {
+ SIVAL(data, ofs, 0);
+ }
+ else {
+ unsigned int align = ndr_align_size(next_offset, 8);
+
+ if (next_offset + align > max_data_bytes) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ memset(data+next_offset, 0, align);
+ next_offset += align;
+
+ SIVAL(data, ofs, next_offset - ofs);
+ ofs = next_offset;
+ }
+
+ ofs = next_offset;
+ }
+
+ *data_size = ofs;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Reply to a TRANSACT2_QFILEINFO on a PIPE !
+****************************************************************************/
+
+static void call_trans2qpipeinfo(connection_struct *conn,
+ struct smb_request *req,
+ unsigned int tran_call,
+ char **pparams, int total_params,
+ char **ppdata, int total_data,
+ unsigned int max_data_bytes)
+{
+ char *params = *pparams;
+ char *pdata = *ppdata;
+ unsigned int data_size = 0;
+ unsigned int param_size = 2;
+ uint16 info_level;
+ smb_np_struct *p_pipe = NULL;
+
+ if (!params) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ if (total_params < 4) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ p_pipe = get_rpc_pipe_p(SVAL(params,0));
+ if (p_pipe == NULL) {
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ return;
+ }
+
+ info_level = SVAL(params,2);
+
+ *pparams = (char *)SMB_REALLOC(*pparams,2);
+ if (*pparams == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ params = *pparams;
+ SSVAL(params,0,0);
+ data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
+ *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
+ if (*ppdata == NULL ) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ pdata = *ppdata;
+
+ switch (info_level) {
+ case SMB_FILE_STANDARD_INFORMATION:
+ memset(pdata,0,24);
+ SOFF_T(pdata,0,4096LL);
+ SIVAL(pdata,16,1);
+ SIVAL(pdata,20,1);
+ data_size = 24;
+ break;
+
+ default:
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+ send_trans2_replies(conn, req, params, param_size, *ppdata, data_size,
+ max_data_bytes);
+
+ return;
+}
+
+/****************************************************************************
+ Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
+ file name or file id).
+****************************************************************************/
+
+static void call_trans2qfilepathinfo(connection_struct *conn,
+ struct smb_request *req,
+ unsigned int tran_call,
+ char **pparams, int total_params,
+ char **ppdata, int total_data,
+ unsigned int max_data_bytes)
+{
+ char *params = *pparams;
+ char *pdata = *ppdata;
+ char *dstart, *dend;
+ uint16 info_level;
+ int mode=0;
+ int nlink;
+ SMB_OFF_T file_size=0;
+ SMB_BIG_UINT allocation_size=0;
+ unsigned int data_size = 0;
+ unsigned int param_size = 2;
+ SMB_STRUCT_STAT sbuf;
+ char *dos_fname = NULL;
+ char *fname = NULL;
+ char *fullpathname;
+ char *base_name;
+ char *p;
+ SMB_OFF_T pos = 0;
+ bool delete_pending = False;
+ int len;
+ time_t create_time, mtime, atime;
+ struct timespec create_time_ts, mtime_ts, atime_ts;
+ struct timespec write_time_ts;
+ files_struct *fsp = NULL;
+ struct file_id fileid;
+ struct ea_list *ea_list = NULL;
+ uint32 access_mask = 0x12019F; /* Default - GENERIC_EXECUTE mapping from Windows */
+ char *lock_data = NULL;
+ bool ms_dfs_link = false;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if (!params) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ ZERO_STRUCT(sbuf);
+ ZERO_STRUCT(write_time_ts);
+
+ if (tran_call == TRANSACT2_QFILEINFO) {
+ if (total_params < 4) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ if (IS_IPC(conn)) {
+ call_trans2qpipeinfo(conn, req, tran_call,
+ pparams, total_params,
+ ppdata, total_data,
+ max_data_bytes);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(params,0));
+ info_level = SVAL(params,2);
+
+ DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level));
+
+ if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+ /* Initial check for valid fsp ptr. */
+ if (!check_fsp_open(conn, req, fsp)) {
+ return;
+ }
+
+ fname = talloc_strdup(talloc_tos(),fsp->fsp_name);
+ if (!fname) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+
+ if(fsp->fake_file_handle) {
+ /*
+ * This is actually for the QUOTA_FAKE_FILE --metze
+ */
+
+ /* We know this name is ok, it's already passed the checks. */
+
+ } else if(fsp && (fsp->is_directory || fsp->fh->fd == -1)) {
+ /*
+ * This is actually a QFILEINFO on a directory
+ * handle (returned from an NT SMB). NT5.0 seems
+ * to do this call. JRA.
+ */
+
+ if (INFO_LEVEL_IS_UNIX(info_level)) {
+ /* Always do lstat for UNIX calls. */
+ if (SMB_VFS_LSTAT(conn,fname,&sbuf)) {
+ DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
+ reply_unixerror(req,ERRDOS,ERRbadpath);
+ return;
+ }
+ } else if (SMB_VFS_STAT(conn,fname,&sbuf)) {
+ DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
+ reply_unixerror(req, ERRDOS, ERRbadpath);
+ return;
+ }
+
+ fileid = vfs_file_id_from_sbuf(conn, &sbuf);
+ get_file_infos(fileid, &delete_pending, &write_time_ts);
+ } else {
+ /*
+ * Original code - this is an open file.
+ */
+ if (!check_fsp(conn, req, fsp)) {
+ return;
+ }
+
+ if (SMB_VFS_FSTAT(fsp, &sbuf) != 0) {
+ DEBUG(3,("fstat of fnum %d failed (%s)\n", fsp->fnum, strerror(errno)));
+ reply_unixerror(req, ERRDOS, ERRbadfid);
+ return;
+ }
+ pos = fsp->fh->position_information;
+ fileid = vfs_file_id_from_sbuf(conn, &sbuf);
+ get_file_infos(fileid, &delete_pending, &write_time_ts);
+ access_mask = fsp->access_mask;
+ }
+
+ } else {
+ NTSTATUS status = NT_STATUS_OK;
+
+ /* qpathinfo */
+ if (total_params < 7) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ info_level = SVAL(params,0);
+
+ DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));
+
+ if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+ srvstr_get_path(ctx, params, req->flags2, &fname, &params[6],
+ total_params - 6,
+ STR_TERMINATE, &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+
+ status = resolve_dfspath(ctx,
+ conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ fname,
+ &fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req,
+ NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ }
+ reply_nterror(req, status);
+ return;
+ }
+
+ status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,nt_errstr(status)));
+ reply_nterror(req, status);
+ return;
+ }
+
+ if (INFO_LEVEL_IS_UNIX(info_level)) {
+ /* Always do lstat for UNIX calls. */
+ if (SMB_VFS_LSTAT(conn,fname,&sbuf)) {
+ DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
+ reply_unixerror(req, ERRDOS, ERRbadpath);
+ return;
+ }
+
+ } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf) && (info_level != SMB_INFO_IS_NAME_VALID)) {
+ ms_dfs_link = check_msdfs_link(conn,fname,&sbuf);
+
+ if (!ms_dfs_link) {
+ DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
+ reply_unixerror(req, ERRDOS, ERRbadpath);
+ return;
+ }
+ }
+
+ fileid = vfs_file_id_from_sbuf(conn, &sbuf);
+ get_file_infos(fileid, &delete_pending, &write_time_ts);
+ if (delete_pending) {
+ reply_nterror(req, NT_STATUS_DELETE_PENDING);
+ return;
+ }
+ }
+
+ if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+ DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d total_data=%d\n",
+ fname,fsp ? fsp->fnum : -1, info_level,tran_call,total_data));
+
+ p = strrchr_m(fname,'/');
+ if (!p)
+ base_name = fname;
+ else
+ base_name = p+1;
+
+ if (ms_dfs_link) {
+ mode = dos_mode_msdfs(conn,fname,&sbuf);
+ } else {
+ mode = dos_mode(conn,fname,&sbuf);
+ }
+ if (!mode)
+ mode = FILE_ATTRIBUTE_NORMAL;
+
+ nlink = sbuf.st_nlink;
+
+ if (nlink && (mode&aDIR)) {
+ nlink = 1;
+ }
+
+ if ((nlink > 0) && delete_pending) {
+ nlink -= 1;
+ }
+
+ fullpathname = fname;
+ if (!(mode & aDIR))
+ file_size = get_file_size(sbuf);
+
+ /* Pull out any data sent here before we realloc. */
+ switch (info_level) {
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ {
+ /* Pull any EA list from the data portion. */
+ uint32 ea_size;
+
+ if (total_data < 4) {
+ reply_nterror(
+ req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+ ea_size = IVAL(pdata,0);
+
+ if (total_data > 0 && ea_size != total_data) {
+ DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
+total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
+ reply_nterror(
+ req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ if (!lp_ea_support(SNUM(conn))) {
+ reply_doserror(req, ERRDOS,
+ ERReasnotsupported);
+ return;
+ }
+
+ /* Pull out the list of names. */
+ ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4);
+ if (!ea_list) {
+ reply_nterror(
+ req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+ break;
+ }
+
+ case SMB_QUERY_POSIX_LOCK:
+ {
+ if (fsp == NULL || fsp->fh->fd == -1) {
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ return;
+ }
+
+ if (total_data != POSIX_LOCK_DATA_SIZE) {
+ reply_nterror(
+ req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ /* Copy the lock range data. */
+ lock_data = (char *)TALLOC_MEMDUP(
+ ctx, pdata, total_data);
+ if (!lock_data) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ }
+ default:
+ break;
+ }
+
+ *pparams = (char *)SMB_REALLOC(*pparams,2);
+ if (*pparams == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ params = *pparams;
+ SSVAL(params,0,0);
+ data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
+ *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
+ if (*ppdata == NULL ) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ pdata = *ppdata;
+ dstart = pdata;
+ dend = dstart + data_size - 1;
+
+ create_time_ts = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+ mtime_ts = get_mtimespec(&sbuf);
+ atime_ts = get_atimespec(&sbuf);
+
+ allocation_size = get_allocation_size(conn,fsp,&sbuf);
+
+ if (!fsp) {
+ /* Do we have this path open ? */
+ files_struct *fsp1;
+ fileid = vfs_file_id_from_sbuf(conn, &sbuf);
+ fsp1 = file_find_di_first(fileid);
+ if (fsp1 && fsp1->initial_allocation_size) {
+ allocation_size = get_allocation_size(conn, fsp1, &sbuf);
+ }
+ }
+
+ if (!null_timespec(write_time_ts) && !INFO_LEVEL_IS_UNIX(info_level)) {
+ mtime_ts = write_time_ts;
+ }
+
+ if (lp_dos_filetime_resolution(SNUM(conn))) {
+ dos_filetime_timespec(&create_time_ts);
+ dos_filetime_timespec(&mtime_ts);
+ dos_filetime_timespec(&atime_ts);
+ }
+
+ create_time = convert_timespec_to_time_t(create_time_ts);
+ mtime = convert_timespec_to_time_t(mtime_ts);
+ atime = convert_timespec_to_time_t(atime_ts);
+
+ /* NT expects the name to be in an exact form of the *full*
+ filename. See the trans2 torture test */
+ if (ISDOT(base_name)) {
+ dos_fname = talloc_strdup(ctx, "\\");
+ if (!dos_fname) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ } else {
+ dos_fname = talloc_asprintf(ctx,
+ "\\%s",
+ fname);
+ if (!dos_fname) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ string_replace(dos_fname, '/', '\\');
+ }
+
+ switch (info_level) {
+ case SMB_INFO_STANDARD:
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_STANDARD\n"));
+ data_size = 22;
+ srv_put_dos_date2(pdata,l1_fdateCreation,create_time);
+ srv_put_dos_date2(pdata,l1_fdateLastAccess,atime);
+ srv_put_dos_date2(pdata,l1_fdateLastWrite,mtime); /* write time */
+ SIVAL(pdata,l1_cbFile,(uint32)file_size);
+ SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size);
+ SSVAL(pdata,l1_attrFile,mode);
+ break;
+
+ case SMB_INFO_QUERY_EA_SIZE:
+ {
+ unsigned int ea_size = estimate_ea_size(conn, fsp, fname);
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n"));
+ data_size = 26;
+ srv_put_dos_date2(pdata,0,create_time);
+ srv_put_dos_date2(pdata,4,atime);
+ srv_put_dos_date2(pdata,8,mtime); /* write time */
+ SIVAL(pdata,12,(uint32)file_size);
+ SIVAL(pdata,16,(uint32)allocation_size);
+ SSVAL(pdata,20,mode);
+ SIVAL(pdata,22,ea_size);
+ break;
+ }
+
+ case SMB_INFO_IS_NAME_VALID:
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_IS_NAME_VALID\n"));
+ if (tran_call == TRANSACT2_QFILEINFO) {
+ /* os/2 needs this ? really ?*/
+ reply_doserror(req, ERRDOS, ERRbadfunc);
+ return;
+ }
+ data_size = 0;
+ param_size = 0;
+ break;
+
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ {
+ size_t total_ea_len = 0;
+ struct ea_list *ea_file_list = NULL;
+
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));
+
+ ea_file_list = get_ea_list_from_file(ctx, conn, fsp, fname, &total_ea_len);
+ ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len);
+
+ if (!ea_list || (total_ea_len > data_size)) {
+ data_size = 4;
+ SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
+ break;
+ }
+
+ data_size = fill_ea_buffer(ctx, pdata, data_size, conn, ea_list);
+ break;
+ }
+
+ case SMB_INFO_QUERY_ALL_EAS:
+ {
+ /* We have data_size bytes to put EA's into. */
+ size_t total_ea_len = 0;
+
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
+
+ ea_list = get_ea_list_from_file(ctx, conn, fsp, fname, &total_ea_len);
+ if (!ea_list || (total_ea_len > data_size)) {
+ data_size = 4;
+ SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
+ break;
+ }
+
+ data_size = fill_ea_buffer(ctx, pdata, data_size, conn, ea_list);
+ break;
+ }
+
+ case SMB_FILE_BASIC_INFORMATION:
+ case SMB_QUERY_FILE_BASIC_INFO:
+
+ if (info_level == SMB_QUERY_FILE_BASIC_INFO) {
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n"));
+ data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
+ } else {
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n"));
+ data_size = 40;
+ SIVAL(pdata,36,0);
+ }
+ put_long_date_timespec(pdata,create_time_ts);
+ put_long_date_timespec(pdata+8,atime_ts);
+ put_long_date_timespec(pdata+16,mtime_ts); /* write time */
+ put_long_date_timespec(pdata+24,mtime_ts); /* change time */
+ SIVAL(pdata,32,mode);
+
+ DEBUG(5,("SMB_QFBI - "));
+ DEBUG(5,("create: %s ", ctime(&create_time)));
+ DEBUG(5,("access: %s ", ctime(&atime)));
+ DEBUG(5,("write: %s ", ctime(&mtime)));
+ DEBUG(5,("change: %s ", ctime(&mtime)));
+ DEBUG(5,("mode: %x\n", mode));
+ break;
+
+ case SMB_FILE_STANDARD_INFORMATION:
+ case SMB_QUERY_FILE_STANDARD_INFO:
+
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n"));
+ data_size = 24;
+ SOFF_T(pdata,0,allocation_size);
+ SOFF_T(pdata,8,file_size);
+ SIVAL(pdata,16,nlink);
+ SCVAL(pdata,20,delete_pending?1:0);
+ SCVAL(pdata,21,(mode&aDIR)?1:0);
+ SSVAL(pdata,22,0); /* Padding. */
+ break;
+
+ case SMB_FILE_EA_INFORMATION:
+ case SMB_QUERY_FILE_EA_INFO:
+ {
+ unsigned int ea_size = estimate_ea_size(conn, fsp, fname);
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_EA_INFORMATION\n"));
+ data_size = 4;
+ SIVAL(pdata,0,ea_size);
+ break;
+ }
+
+ /* Get the 8.3 name - used if NT SMB was negotiated. */
+ case SMB_QUERY_FILE_ALT_NAME_INFO:
+ case SMB_FILE_ALTERNATE_NAME_INFORMATION:
+ {
+ char mangled_name[13];
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n"));
+ if (!name_to_8_3(base_name,mangled_name,
+ True,conn->params)) {
+ reply_nterror(
+ req,
+ NT_STATUS_NO_MEMORY);
+ }
+ len = srvstr_push(dstart, req->flags2,
+ pdata+4, mangled_name,
+ PTR_DIFF(dend, pdata+4),
+ STR_UNICODE);
+ data_size = 4 + len;
+ SIVAL(pdata,0,len);
+ break;
+ }
+
+ case SMB_QUERY_FILE_NAME_INFO:
+ /*
+ this must be *exactly* right for ACLs on mapped drives to work
+ */
+ len = srvstr_push(dstart, req->flags2,
+ pdata+4, dos_fname,
+ PTR_DIFF(dend, pdata+4),
+ STR_UNICODE);
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n"));
+ data_size = 4 + len;
+ SIVAL(pdata,0,len);
+ break;
+
+ case SMB_FILE_ALLOCATION_INFORMATION:
+ case SMB_QUERY_FILE_ALLOCATION_INFO:
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n"));
+ data_size = 8;
+ SOFF_T(pdata,0,allocation_size);
+ break;
+
+ case SMB_FILE_END_OF_FILE_INFORMATION:
+ case SMB_QUERY_FILE_END_OF_FILEINFO:
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n"));
+ data_size = 8;
+ SOFF_T(pdata,0,file_size);
+ break;
+
+ case SMB_QUERY_FILE_ALL_INFO:
+ case SMB_FILE_ALL_INFORMATION:
+ {
+ unsigned int ea_size = estimate_ea_size(conn, fsp, fname);
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALL_INFORMATION\n"));
+ put_long_date_timespec(pdata,create_time_ts);
+ put_long_date_timespec(pdata+8,atime_ts);
+ put_long_date_timespec(pdata+16,mtime_ts); /* write time */
+ put_long_date_timespec(pdata+24,mtime_ts); /* change time */
+ SIVAL(pdata,32,mode);
+ SIVAL(pdata,36,0); /* padding. */
+ pdata += 40;
+ SOFF_T(pdata,0,allocation_size);
+ SOFF_T(pdata,8,file_size);
+ SIVAL(pdata,16,nlink);
+ SCVAL(pdata,20,delete_pending);
+ SCVAL(pdata,21,(mode&aDIR)?1:0);
+ SSVAL(pdata,22,0);
+ pdata += 24;
+ SIVAL(pdata,0,ea_size);
+ pdata += 4; /* EA info */
+ len = srvstr_push(dstart, req->flags2,
+ pdata+4, dos_fname,
+ PTR_DIFF(dend, pdata+4),
+ STR_UNICODE);
+ SIVAL(pdata,0,len);
+ pdata += 4 + len;
+ data_size = PTR_DIFF(pdata,(*ppdata));
+ break;
+ }
+ case SMB_FILE_INTERNAL_INFORMATION:
+ /* This should be an index number - looks like
+ dev/ino to me :-)
+
+ I think this causes us to fail the IFSKIT
+ BasicFileInformationTest. -tpot */
+
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n"));
+ SIVAL(pdata,0,sbuf.st_ino); /* FileIndexLow */
+ SIVAL(pdata,4,sbuf.st_dev); /* FileIndexHigh */
+ data_size = 8;
+ break;
+
+ case SMB_FILE_ACCESS_INFORMATION:
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n"));
+ SIVAL(pdata,0,access_mask);
+ data_size = 4;
+ break;
+
+ case SMB_FILE_NAME_INFORMATION:
+ /* Pathname with leading '\'. */
+ {
+ size_t byte_len;
+ byte_len = dos_PutUniCode(pdata+4,dos_fname,(size_t)max_data_bytes,False);
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_NAME_INFORMATION\n"));
+ SIVAL(pdata,0,byte_len);
+ data_size = 4 + byte_len;
+ break;
+ }
+
+ case SMB_FILE_DISPOSITION_INFORMATION:
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n"));
+ data_size = 1;
+ SCVAL(pdata,0,delete_pending);
+ break;
+
+ case SMB_FILE_POSITION_INFORMATION:
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n"));
+ data_size = 8;
+ SOFF_T(pdata,0,pos);
+ break;
+
+ case SMB_FILE_MODE_INFORMATION:
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_MODE_INFORMATION\n"));
+ SIVAL(pdata,0,mode);
+ data_size = 4;
+ break;
+
+ case SMB_FILE_ALIGNMENT_INFORMATION:
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n"));
+ SIVAL(pdata,0,0); /* No alignment needed. */
+ data_size = 4;
+ break;
+
+ /*
+ * NT4 server just returns "invalid query" to this - if we try
+ * to answer it then NTws gets a BSOD! (tridge). W2K seems to
+ * want this. JRA.
+ */
+ /* The first statement above is false - verified using Thursby
+ * client against NT4 -- gcolley.
+ */
+ case SMB_QUERY_FILE_STREAM_INFO:
+ case SMB_FILE_STREAM_INFORMATION: {
+ unsigned int num_streams;
+ struct stream_struct *streams;
+ NTSTATUS status;
+
+ DEBUG(10,("call_trans2qfilepathinfo: "
+ "SMB_FILE_STREAM_INFORMATION\n"));
+
+ status = SMB_VFS_STREAMINFO(
+ conn, fsp, fname, talloc_tos(),
+ &num_streams, &streams);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("could not get stream info: %s\n",
+ nt_errstr(status)));
+ reply_nterror(req, status);
+ return;
+ }
+
+ status = marshall_stream_info(num_streams, streams,
+ pdata, max_data_bytes,
+ &data_size);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("marshall_stream_info failed: %s\n",
+ nt_errstr(status)));
+ reply_nterror(req, status);
+ return;
+ }
+
+ TALLOC_FREE(streams);
+
+ break;
+ }
+ case SMB_QUERY_COMPRESSION_INFO:
+ case SMB_FILE_COMPRESSION_INFORMATION:
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n"));
+ SOFF_T(pdata,0,file_size);
+ SIVAL(pdata,8,0); /* ??? */
+ SIVAL(pdata,12,0); /* ??? */
+ data_size = 16;
+ break;
+
+ case SMB_FILE_NETWORK_OPEN_INFORMATION:
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n"));
+ put_long_date_timespec(pdata,create_time_ts);
+ put_long_date_timespec(pdata+8,atime_ts);
+ put_long_date_timespec(pdata+16,mtime_ts); /* write time */
+ put_long_date_timespec(pdata+24,mtime_ts); /* change time */
+ SOFF_T(pdata,32,allocation_size);
+ SOFF_T(pdata,40,file_size);
+ SIVAL(pdata,48,mode);
+ SIVAL(pdata,52,0); /* ??? */
+ data_size = 56;
+ break;
+
+ case SMB_FILE_ATTRIBUTE_TAG_INFORMATION:
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n"));
+ SIVAL(pdata,0,mode);
+ SIVAL(pdata,4,0);
+ data_size = 8;
+ break;
+
+ /*
+ * CIFS UNIX Extensions.
+ */
+
+ case SMB_QUERY_FILE_UNIX_BASIC:
+
+ pdata = store_file_unix_basic(conn, pdata, fsp, &sbuf);
+ data_size = PTR_DIFF(pdata,(*ppdata));
+
+ {
+ int i;
+ DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC "));
+
+ for (i=0; i<100; i++)
+ DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
+ DEBUG(4,("\n"));
+ }
+
+ break;
+
+ case SMB_QUERY_FILE_UNIX_INFO2:
+
+ pdata = store_file_unix_basic_info2(conn, pdata, fsp, &sbuf);
+ data_size = PTR_DIFF(pdata,(*ppdata));
+
+ {
+ int i;
+ DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 "));
+
+ for (i=0; i<100; i++)
+ DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
+ DEBUG(4,("\n"));
+ }
+
+ break;
+
+ case SMB_QUERY_FILE_UNIX_LINK:
+ {
+ char *buffer = TALLOC_ARRAY(ctx, char, PATH_MAX+1);
+
+ if (!buffer) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+
+ DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_LINK\n"));
+#ifdef S_ISLNK
+ if(!S_ISLNK(sbuf.st_mode)) {
+ reply_unixerror(req, ERRSRV,
+ ERRbadlink);
+ return;
+ }
+#else
+ reply_unixerror(req, ERRDOS, ERRbadlink);
+ return;
+#endif
+ len = SMB_VFS_READLINK(conn,fullpathname,
+ buffer, PATH_MAX);
+ if (len == -1) {
+ reply_unixerror(req, ERRDOS,
+ ERRnoaccess);
+ return;
+ }
+ buffer[len] = 0;
+ len = srvstr_push(dstart, req->flags2,
+ pdata, buffer,
+ PTR_DIFF(dend, pdata),
+ STR_TERMINATE);
+ pdata += len;
+ data_size = PTR_DIFF(pdata,(*ppdata));
+
+ break;
+ }
+
+#if defined(HAVE_POSIX_ACLS)
+ case SMB_QUERY_POSIX_ACL:
+ {
+ SMB_ACL_T file_acl = NULL;
+ SMB_ACL_T def_acl = NULL;
+ uint16 num_file_acls = 0;
+ uint16 num_def_acls = 0;
+
+ if (fsp && !fsp->is_directory && (fsp->fh->fd != -1)) {
+ file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
+ } else {
+ file_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
+ }
+
+ if (file_acl == NULL && no_acl_syscall_error(errno)) {
+ DEBUG(5,("call_trans2qfilepathinfo: ACLs not implemented on filesystem containing %s\n",
+ fname ));
+ reply_nterror(
+ req,
+ NT_STATUS_NOT_IMPLEMENTED);
+ return;
+ }
+
+ if (S_ISDIR(sbuf.st_mode)) {
+ if (fsp && fsp->is_directory) {
+ def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
+ } else {
+ def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT);
+ }
+ def_acl = free_empty_sys_acl(conn, def_acl);
+ }
+
+ num_file_acls = count_acl_entries(conn, file_acl);
+ num_def_acls = count_acl_entries(conn, def_acl);
+
+ if ( data_size < (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) {
+ DEBUG(5,("call_trans2qfilepathinfo: data_size too small (%u) need %u\n",
+ data_size,
+ (unsigned int)((num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE +
+ SMB_POSIX_ACL_HEADER_SIZE) ));
+ if (file_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ }
+ if (def_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ }
+ reply_nterror(
+ req,
+ NT_STATUS_BUFFER_TOO_SMALL);
+ return;
+ }
+
+ SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
+ SSVAL(pdata,2,num_file_acls);
+ SSVAL(pdata,4,num_def_acls);
+ if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE, &sbuf, file_acl)) {
+ if (file_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ }
+ if (def_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ }
+ reply_nterror(
+ req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+ if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE), &sbuf, def_acl)) {
+ if (file_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ }
+ if (def_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ }
+ reply_nterror(
+ req,
+ NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+
+ if (file_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ }
+ if (def_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ }
+ data_size = (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE;
+ break;
+ }
+#endif
+
+
+ case SMB_QUERY_POSIX_LOCK:
+ {
+ NTSTATUS status = NT_STATUS_INVALID_LEVEL;
+ SMB_BIG_UINT count;
+ SMB_BIG_UINT offset;
+ uint32 lock_pid;
+ enum brl_type lock_type;
+
+ if (total_data != POSIX_LOCK_DATA_SIZE) {
+ reply_nterror(
+ req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
+ case POSIX_LOCK_TYPE_READ:
+ lock_type = READ_LOCK;
+ break;
+ case POSIX_LOCK_TYPE_WRITE:
+ lock_type = WRITE_LOCK;
+ break;
+ case POSIX_LOCK_TYPE_UNLOCK:
+ default:
+ /* There's no point in asking for an unlock... */
+ reply_nterror(
+ req,
+ NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET);
+#if defined(HAVE_LONGLONG)
+ offset = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
+ ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_START_OFFSET));
+ count = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
+ ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
+#else /* HAVE_LONGLONG */
+ offset = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_START_OFFSET);
+ count = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
+#endif /* HAVE_LONGLONG */
+
+ status = query_lock(fsp,
+ &lock_pid,
+ &count,
+ &offset,
+ &lock_type,
+ POSIX_LOCK);
+
+ if (ERROR_WAS_LOCK_DENIED(status)) {
+ /* Here we need to report who has it locked... */
+ data_size = POSIX_LOCK_DATA_SIZE;
+
+ SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
+ SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
+ SIVAL(pdata, POSIX_LOCK_PID_OFFSET, lock_pid);
+#if defined(HAVE_LONGLONG)
+ SIVAL(pdata, POSIX_LOCK_START_OFFSET, (uint32)(offset & 0xFFFFFFFF));
+ SIVAL(pdata, POSIX_LOCK_START_OFFSET + 4, (uint32)((offset >> 32) & 0xFFFFFFFF));
+ SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, (uint32)(count & 0xFFFFFFFF));
+ SIVAL(pdata, POSIX_LOCK_LEN_OFFSET + 4, (uint32)((count >> 32) & 0xFFFFFFFF));
+#else /* HAVE_LONGLONG */
+ SIVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
+ SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
+#endif /* HAVE_LONGLONG */
+
+ } else if (NT_STATUS_IS_OK(status)) {
+ /* For success we just return a copy of what we sent
+ with the lock type set to POSIX_LOCK_TYPE_UNLOCK. */
+ data_size = POSIX_LOCK_DATA_SIZE;
+ memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE);
+ SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
+ } else {
+ reply_nterror(req, status);
+ return;
+ }
+ break;
+ }
+
+ default:
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+ send_trans2_replies(conn, req, params, param_size, *ppdata, data_size,
+ max_data_bytes);
+
+ return;
+}
+
+/****************************************************************************
+ Set a hard link (called by UNIX extensions and by NT rename with HARD link
+ code.
+****************************************************************************/
+
+NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ const char *oldname_in,
+ const char *newname_in)
+{
+ SMB_STRUCT_STAT sbuf1, sbuf2;
+ char *last_component_oldname = NULL;
+ char *last_component_newname = NULL;
+ char *oldname = NULL;
+ char *newname = NULL;
+ NTSTATUS status = NT_STATUS_OK;
+
+ ZERO_STRUCT(sbuf1);
+ ZERO_STRUCT(sbuf2);
+
+ status = unix_convert(ctx, conn, oldname_in, False, &oldname,
+ &last_component_oldname, &sbuf1);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = check_name(conn, oldname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* source must already exist. */
+ if (!VALID_STAT(sbuf1)) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ status = unix_convert(ctx, conn, newname_in, False, &newname,
+ &last_component_newname, &sbuf2);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = check_name(conn, newname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Disallow if newname already exists. */
+ if (VALID_STAT(sbuf2)) {
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ /* No links from a directory. */
+ if (S_ISDIR(sbuf1.st_mode)) {
+ return NT_STATUS_FILE_IS_A_DIRECTORY;
+ }
+
+ /* Ensure this is within the share. */
+ status = check_reduced_name(conn, oldname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", newname, oldname ));
+
+ if (SMB_VFS_LINK(conn,oldname,newname) != 0) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
+ nt_errstr(status), newname, oldname));
+ }
+
+ return status;
+}
+
+/****************************************************************************
+ Deal with setting the time from any of the setfilepathinfo functions.
+****************************************************************************/
+
+NTSTATUS smb_set_file_time(connection_struct *conn,
+ files_struct *fsp,
+ const char *fname,
+ const SMB_STRUCT_STAT *psbuf,
+ struct timespec ts[2],
+ bool setting_write_time)
+{
+ uint32 action =
+ FILE_NOTIFY_CHANGE_LAST_ACCESS
+ |FILE_NOTIFY_CHANGE_LAST_WRITE;
+
+ if (!VALID_STAT(*psbuf)) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ /* get some defaults (no modifications) if any info is zero or -1. */
+ if (null_timespec(ts[0])) {
+ ts[0] = get_atimespec(psbuf);
+ action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS;
+ }
+
+ if (null_timespec(ts[1])) {
+ ts[1] = get_mtimespec(psbuf);
+ action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
+ }
+
+ if (!setting_write_time) {
+ /* ts[1] comes from change time, not write time. */
+ action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
+ }
+
+ DEBUG(6,("smb_set_file_time: actime: %s " , time_to_asc(convert_timespec_to_time_t(ts[0])) ));
+ DEBUG(6,("smb_set_file_time: modtime: %s ", time_to_asc(convert_timespec_to_time_t(ts[1])) ));
+
+ /*
+ * Try and set the times of this file if
+ * they are different from the current values.
+ */
+
+ {
+ struct timespec mts = get_mtimespec(psbuf);
+ struct timespec ats = get_atimespec(psbuf);
+ if ((timespec_compare(&ts[0], &ats) == 0) && (timespec_compare(&ts[1], &mts) == 0)) {
+ return NT_STATUS_OK;
+ }
+ }
+
+ if (setting_write_time) {
+ /*
+ * This was a setfileinfo on an open file.
+ * NT does this a lot. We also need to
+ * set the time here, as it can be read by
+ * FindFirst/FindNext and with the patch for bug #2045
+ * in smbd/fileio.c it ensures that this timestamp is
+ * kept sticky even after a write. We save the request
+ * away and will set it on file close and after a write. JRA.
+ */
+
+ DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n",
+ time_to_asc(convert_timespec_to_time_t(ts[1])) ));
+
+ if (fsp != NULL) {
+ set_sticky_write_time_fsp(fsp, ts[1]);
+ } else {
+ set_sticky_write_time_path(conn, fname,
+ vfs_file_id_from_sbuf(conn, psbuf),
+ ts[1]);
+ }
+ }
+
+ DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n"));
+
+ if(file_ntimes(conn, fname, ts)!=0) {
+ return map_nt_error_from_unix(errno);
+ }
+ notify_fname(conn, NOTIFY_ACTION_MODIFIED, action, fname);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Deal with setting the dosmode from any of the setfilepathinfo functions.
+****************************************************************************/
+
+static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf,
+ uint32 dosmode)
+{
+ if (!VALID_STAT(*psbuf)) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (dosmode) {
+ if (S_ISDIR(psbuf->st_mode)) {
+ dosmode |= aDIR;
+ } else {
+ dosmode &= ~aDIR;
+ }
+ }
+
+ DEBUG(6,("smb_set_file_dosmode: dosmode: 0x%x\n", (unsigned int)dosmode));
+
+ /* check the mode isn't different, before changing it */
+ if ((dosmode != 0) && (dosmode != dos_mode(conn, fname, psbuf))) {
+
+ DEBUG(10,("smb_set_file_dosmode: file %s : setting dos mode 0x%x\n",
+ fname, (unsigned int)dosmode ));
+
+ if(file_set_dosmode(conn, fname, dosmode, psbuf, NULL, false)) {
+ DEBUG(2,("smb_set_file_dosmode: file_set_dosmode of %s failed (%s)\n",
+ fname, strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+ }
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Deal with setting the size from any of the setfilepathinfo functions.
+****************************************************************************/
+
+static NTSTATUS smb_set_file_size(connection_struct *conn,
+ struct smb_request *req,
+ files_struct *fsp,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf,
+ SMB_OFF_T size)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ files_struct *new_fsp = NULL;
+
+ if (!VALID_STAT(*psbuf)) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ DEBUG(6,("smb_set_file_size: size: %.0f ", (double)size));
+
+ if (size == get_file_size(*psbuf)) {
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(10,("smb_set_file_size: file %s : setting new size to %.0f\n",
+ fname, (double)size ));
+
+ if (fsp && fsp->fh->fd != -1) {
+ /* Handle based call. */
+ if (vfs_set_filelen(fsp, size) == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+ trigger_write_time_update_immediate(fsp);
+ return NT_STATUS_OK;
+ }
+
+ status = open_file_ntcreate(conn, req, fname, psbuf,
+ FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OPEN,
+ 0,
+ FILE_ATTRIBUTE_NORMAL,
+ FORCE_OPLOCK_BREAK_TO_NONE,
+ NULL, &new_fsp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ /* NB. We check for open_was_deferred in the caller. */
+ return status;
+ }
+
+ if (vfs_set_filelen(new_fsp, size) == -1) {
+ status = map_nt_error_from_unix(errno);
+ close_file(new_fsp,NORMAL_CLOSE);
+ return status;
+ }
+
+ trigger_write_time_update_immediate(new_fsp);
+ close_file(new_fsp,NORMAL_CLOSE);
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Deal with SMB_INFO_SET_EA.
+****************************************************************************/
+
+static NTSTATUS smb_info_set_ea(connection_struct *conn,
+ const char *pdata,
+ int total_data,
+ files_struct *fsp,
+ const char *fname)
+{
+ struct ea_list *ea_list = NULL;
+ TALLOC_CTX *ctx = NULL;
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (total_data < 10) {
+
+ /* OS/2 workplace shell seems to send SET_EA requests of "null"
+ length. They seem to have no effect. Bug #3212. JRA */
+
+ if ((total_data == 4) && (IVAL(pdata,0) == 4)) {
+ /* We're done. We only get EA info in this call. */
+ return NT_STATUS_OK;
+ }
+
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (IVAL(pdata,0) > total_data) {
+ DEBUG(10,("smb_info_set_ea: bad total data size (%u) > %u\n",
+ IVAL(pdata,0), (unsigned int)total_data));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ctx = talloc_tos();
+ ea_list = read_ea_list(ctx, pdata + 4, total_data - 4);
+ if (!ea_list) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ status = set_ea(conn, fsp, fname, ea_list);
+
+ return status;
+}
+
+/****************************************************************************
+ Deal with SMB_SET_FILE_DISPOSITION_INFO.
+****************************************************************************/
+
+static NTSTATUS smb_set_file_disposition_info(connection_struct *conn,
+ const char *pdata,
+ int total_data,
+ files_struct *fsp,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ bool delete_on_close;
+ uint32 dosmode = 0;
+
+ if (total_data < 1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (fsp == NULL) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ delete_on_close = (CVAL(pdata,0) ? True : False);
+ dosmode = dos_mode(conn, fname, psbuf);
+
+ DEBUG(10,("smb_set_file_disposition_info: file %s, dosmode = %u, "
+ "delete_on_close = %u\n",
+ fsp->fsp_name,
+ (unsigned int)dosmode,
+ (unsigned int)delete_on_close ));
+
+ status = can_set_delete_on_close(fsp, delete_on_close, dosmode);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* The set is across all open files on this dev/inode pair. */
+ if (!set_delete_on_close(fsp, delete_on_close,
+ &conn->server_info->utok)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Deal with SMB_FILE_POSITION_INFORMATION.
+****************************************************************************/
+
+static NTSTATUS smb_file_position_information(connection_struct *conn,
+ const char *pdata,
+ int total_data,
+ files_struct *fsp)
+{
+ SMB_BIG_UINT position_information;
+
+ if (total_data < 8) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (fsp == NULL) {
+ /* Ignore on pathname based set. */
+ return NT_STATUS_OK;
+ }
+
+ position_information = (SMB_BIG_UINT)IVAL(pdata,0);
+#ifdef LARGE_SMB_OFF_T
+ position_information |= (((SMB_BIG_UINT)IVAL(pdata,4)) << 32);
+#else /* LARGE_SMB_OFF_T */
+ if (IVAL(pdata,4) != 0) {
+ /* more than 32 bits? */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ DEBUG(10,("smb_file_position_information: Set file position information for file %s to %.0f\n",
+ fsp->fsp_name, (double)position_information ));
+ fsp->fh->position_information = position_information;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Deal with SMB_FILE_MODE_INFORMATION.
+****************************************************************************/
+
+static NTSTATUS smb_file_mode_information(connection_struct *conn,
+ const char *pdata,
+ int total_data)
+{
+ uint32 mode;
+
+ if (total_data < 4) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ mode = IVAL(pdata,0);
+ if (mode != 0 && mode != 2 && mode != 4 && mode != 6) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Deal with SMB_SET_FILE_UNIX_LINK (create a UNIX symlink).
+****************************************************************************/
+
+static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
+ struct smb_request *req,
+ const char *pdata,
+ int total_data,
+ const char *fname)
+{
+ char *link_target = NULL;
+ const char *newname = fname;
+ NTSTATUS status = NT_STATUS_OK;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ /* Set a symbolic link. */
+ /* Don't allow this if follow links is false. */
+
+ if (total_data == 0) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!lp_symlinks(SNUM(conn))) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ srvstr_pull_talloc(ctx, pdata, req->flags2, &link_target, pdata,
+ total_data, STR_TERMINATE);
+
+ if (!link_target) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* !widelinks forces the target path to be within the share. */
+ /* This means we can interpret the target as a pathname. */
+ if (!lp_widelinks(SNUM(conn))) {
+ char *rel_name = NULL;
+ char *last_dirp = NULL;
+
+ if (*link_target == '/') {
+ /* No absolute paths allowed. */
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ rel_name = talloc_strdup(ctx,newname);
+ if (!rel_name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ last_dirp = strrchr_m(rel_name, '/');
+ if (last_dirp) {
+ last_dirp[1] = '\0';
+ } else {
+ rel_name = talloc_strdup(ctx,"./");
+ if (!rel_name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ rel_name = talloc_asprintf_append(rel_name,
+ "%s",
+ link_target);
+ if (!rel_name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = check_name(conn, rel_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
+ newname, link_target ));
+
+ if (SMB_VFS_SYMLINK(conn,link_target,newname) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Deal with SMB_SET_FILE_UNIX_HLINK (create a UNIX hard link).
+****************************************************************************/
+
+static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
+ struct smb_request *req,
+ const char *pdata, int total_data,
+ const char *fname)
+{
+ char *oldname = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+ NTSTATUS status = NT_STATUS_OK;
+
+ /* Set a hard link. */
+ if (total_data == 0) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ srvstr_get_path(ctx, pdata, req->flags2, &oldname, pdata,
+ total_data, STR_TERMINATE, &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = resolve_dfspath(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ oldname,
+ &oldname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
+ fname, oldname));
+
+ return hardlink_internals(ctx, conn, oldname, fname);
+}
+
+/****************************************************************************
+ Deal with SMB_FILE_RENAME_INFORMATION.
+****************************************************************************/
+
+static NTSTATUS smb_file_rename_information(connection_struct *conn,
+ struct smb_request *req,
+ const char *pdata,
+ int total_data,
+ files_struct *fsp,
+ const char *fname)
+{
+ bool overwrite;
+ uint32 root_fid;
+ uint32 len;
+ char *newname = NULL;
+ char *base_name = NULL;
+ bool dest_has_wcard = False;
+ NTSTATUS status = NT_STATUS_OK;
+ char *p;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if (total_data < 13) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ overwrite = (CVAL(pdata,0) ? True : False);
+ root_fid = IVAL(pdata,4);
+ len = IVAL(pdata,8);
+
+ if (len > (total_data - 12) || (len == 0) || (root_fid != 0)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ srvstr_get_path_wcard(ctx, pdata, req->flags2, &newname, &pdata[12],
+ len, 0, &status,
+ &dest_has_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(10,("smb_file_rename_information: got name |%s|\n",
+ newname));
+
+ status = resolve_dfspath_wcard(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ newname,
+ &newname,
+ &dest_has_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Check the new name has no '/' characters. */
+ if (strchr_m(newname, '/')) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ /* Create the base directory. */
+ base_name = talloc_strdup(ctx, fname);
+ if (!base_name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ p = strrchr_m(base_name, '/');
+ if (p) {
+ p[1] = '\0';
+ } else {
+ base_name = talloc_strdup(ctx, "./");
+ if (!base_name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ /* Append the new name. */
+ base_name = talloc_asprintf_append(base_name,
+ "%s",
+ newname);
+ if (!base_name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (fsp) {
+ SMB_STRUCT_STAT sbuf;
+ char *newname_last_component = NULL;
+
+ ZERO_STRUCT(sbuf);
+
+ status = unix_convert(ctx, conn, newname, False,
+ &newname,
+ &newname_last_component,
+ &sbuf);
+
+ /* If an error we expect this to be
+ * NT_STATUS_OBJECT_PATH_NOT_FOUND */
+
+ if (!NT_STATUS_IS_OK(status)
+ && !NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND,
+ status)) {
+ return status;
+ }
+
+ DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n",
+ fsp->fnum, fsp->fsp_name, base_name ));
+ status = rename_internals_fsp(conn, fsp, base_name,
+ newname_last_component, 0,
+ overwrite);
+ } else {
+ DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION %s -> %s\n",
+ fname, base_name ));
+ status = rename_internals(ctx, conn, req, fname, base_name, 0,
+ overwrite, False, dest_has_wcard,
+ FILE_WRITE_ATTRIBUTES);
+ }
+
+ return status;
+}
+
+/****************************************************************************
+ Deal with SMB_SET_POSIX_ACL.
+****************************************************************************/
+
+#if defined(HAVE_POSIX_ACLS)
+static NTSTATUS smb_set_posix_acl(connection_struct *conn,
+ const char *pdata,
+ int total_data,
+ files_struct *fsp,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf)
+{
+ uint16 posix_acl_version;
+ uint16 num_file_acls;
+ uint16 num_def_acls;
+ bool valid_file_acls = True;
+ bool valid_def_acls = True;
+
+ if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ posix_acl_version = SVAL(pdata,0);
+ num_file_acls = SVAL(pdata,2);
+ num_def_acls = SVAL(pdata,4);
+
+ if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
+ valid_file_acls = False;
+ num_file_acls = 0;
+ }
+
+ if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
+ valid_def_acls = False;
+ num_def_acls = 0;
+ }
+
+ if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (total_data < SMB_POSIX_ACL_HEADER_SIZE +
+ (num_file_acls+num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n",
+ fname ? fname : fsp->fsp_name,
+ (unsigned int)num_file_acls,
+ (unsigned int)num_def_acls));
+
+ if (valid_file_acls && !set_unix_posix_acl(conn, fsp, fname, num_file_acls,
+ pdata + SMB_POSIX_ACL_HEADER_SIZE)) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ if (valid_def_acls && !set_unix_posix_default_acl(conn, fname, psbuf, num_def_acls,
+ pdata + SMB_POSIX_ACL_HEADER_SIZE +
+ (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) {
+ return map_nt_error_from_unix(errno);
+ }
+ return NT_STATUS_OK;
+}
+#endif
+
+/****************************************************************************
+ Deal with SMB_SET_POSIX_LOCK.
+****************************************************************************/
+
+static NTSTATUS smb_set_posix_lock(connection_struct *conn,
+ const struct smb_request *req,
+ const char *pdata,
+ int total_data,
+ files_struct *fsp)
+{
+ SMB_BIG_UINT count;
+ SMB_BIG_UINT offset;
+ uint32 lock_pid;
+ bool blocking_lock = False;
+ enum brl_type lock_type;
+
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (fsp == NULL || fsp->fh->fd == -1) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ if (total_data != POSIX_LOCK_DATA_SIZE) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
+ case POSIX_LOCK_TYPE_READ:
+ lock_type = READ_LOCK;
+ break;
+ case POSIX_LOCK_TYPE_WRITE:
+ /* Return the right POSIX-mappable error code for files opened read-only. */
+ if (!fsp->can_write) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+ lock_type = WRITE_LOCK;
+ break;
+ case POSIX_LOCK_TYPE_UNLOCK:
+ lock_type = UNLOCK_LOCK;
+ break;
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_NOWAIT) {
+ blocking_lock = False;
+ } else if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_WAIT) {
+ blocking_lock = True;
+ } else {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!lp_blocking_locks(SNUM(conn))) {
+ blocking_lock = False;
+ }
+
+ lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET);
+#if defined(HAVE_LONGLONG)
+ offset = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
+ ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_START_OFFSET));
+ count = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
+ ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
+#else /* HAVE_LONGLONG */
+ offset = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_START_OFFSET);
+ count = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
+#endif /* HAVE_LONGLONG */
+
+ DEBUG(10,("smb_set_posix_lock: file %s, lock_type = %u,"
+ "lock_pid = %u, count = %.0f, offset = %.0f\n",
+ fsp->fsp_name,
+ (unsigned int)lock_type,
+ (unsigned int)lock_pid,
+ (double)count,
+ (double)offset ));
+
+ if (lock_type == UNLOCK_LOCK) {
+ status = do_unlock(smbd_messaging_context(),
+ fsp,
+ lock_pid,
+ count,
+ offset,
+ POSIX_LOCK);
+ } else {
+ uint32 block_smbpid;
+
+ struct byte_range_lock *br_lck = do_lock(smbd_messaging_context(),
+ fsp,
+ lock_pid,
+ count,
+ offset,
+ lock_type,
+ POSIX_LOCK,
+ blocking_lock,
+ &status,
+ &block_smbpid);
+
+ if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
+ /*
+ * 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(br_lck,
+ req,
+ fsp,
+ -1, /* infinite timeout. */
+ 0,
+ lock_pid,
+ lock_type,
+ POSIX_LOCK,
+ offset,
+ count,
+ block_smbpid)) {
+ TALLOC_FREE(br_lck);
+ return status;
+ }
+ }
+ TALLOC_FREE(br_lck);
+ }
+
+ return status;
+}
+
+/****************************************************************************
+ Deal with SMB_INFO_STANDARD.
+****************************************************************************/
+
+static NTSTATUS smb_set_info_standard(connection_struct *conn,
+ const char *pdata,
+ int total_data,
+ files_struct *fsp,
+ const char *fname,
+ const SMB_STRUCT_STAT *psbuf)
+{
+ struct timespec ts[2];
+
+ if (total_data < 12) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* access time */
+ ts[0] = convert_time_t_to_timespec(srv_make_unix_date2(pdata+l1_fdateLastAccess));
+ /* write time */
+ ts[1] = convert_time_t_to_timespec(srv_make_unix_date2(pdata+l1_fdateLastWrite));
+
+ DEBUG(10,("smb_set_info_standard: file %s\n",
+ fname ? fname : fsp->fsp_name ));
+
+ return smb_set_file_time(conn,
+ fsp,
+ fname,
+ psbuf,
+ ts,
+ true);
+}
+
+/****************************************************************************
+ Deal with SMB_SET_FILE_BASIC_INFO.
+****************************************************************************/
+
+static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
+ const char *pdata,
+ int total_data,
+ files_struct *fsp,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf)
+{
+ /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
+ struct timespec write_time;
+ struct timespec changed_time;
+ uint32 dosmode = 0;
+ struct timespec ts[2];
+ NTSTATUS status = NT_STATUS_OK;
+ bool setting_write_time = true;
+
+ if (total_data < 36) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Set the attributes */
+ dosmode = IVAL(pdata,32);
+ status = smb_set_file_dosmode(conn,
+ fname,
+ psbuf,
+ dosmode);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Ignore create time at offset pdata. */
+
+ /* access time */
+ ts[0] = interpret_long_date(pdata+8);
+
+ write_time = interpret_long_date(pdata+16);
+ changed_time = interpret_long_date(pdata+24);
+
+ /* mtime */
+ ts[1] = timespec_min(&write_time, &changed_time);
+
+ if ((timespec_compare(&write_time, &ts[1]) == 1) && !null_timespec(write_time)) {
+ ts[1] = write_time;
+ }
+
+ /* Prefer a defined time to an undefined one. */
+ if (null_timespec(ts[1])) {
+ if (null_timespec(write_time)) {
+ ts[1] = changed_time;
+ setting_write_time = false;
+ } else {
+ ts[1] = write_time;
+ }
+ }
+
+ DEBUG(10,("smb_set_file_basic_info: file %s\n",
+ fname ? fname : fsp->fsp_name ));
+
+ return smb_set_file_time(conn,
+ fsp,
+ fname,
+ psbuf,
+ ts,
+ setting_write_time);
+}
+
+/****************************************************************************
+ Deal with SMB_SET_FILE_ALLOCATION_INFO.
+****************************************************************************/
+
+static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
+ struct smb_request *req,
+ const char *pdata,
+ int total_data,
+ files_struct *fsp,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf)
+{
+ SMB_BIG_UINT allocation_size = 0;
+ NTSTATUS status = NT_STATUS_OK;
+ files_struct *new_fsp = NULL;
+
+ if (!VALID_STAT(*psbuf)) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (total_data < 8) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ allocation_size = (SMB_BIG_UINT)IVAL(pdata,0);
+#ifdef LARGE_SMB_OFF_T
+ allocation_size |= (((SMB_BIG_UINT)IVAL(pdata,4)) << 32);
+#else /* LARGE_SMB_OFF_T */
+ if (IVAL(pdata,4) != 0) {
+ /* more than 32 bits? */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ DEBUG(10,("smb_set_file_allocation_info: Set file allocation info for file %s to %.0f\n",
+ fname, (double)allocation_size ));
+
+ if (allocation_size) {
+ allocation_size = smb_roundup(conn, allocation_size);
+ }
+
+ DEBUG(10,("smb_set_file_allocation_info: file %s : setting new allocation size to %.0f\n",
+ fname, (double)allocation_size ));
+
+ if (fsp && fsp->fh->fd != -1) {
+ /* Open file handle. */
+ /* Only change if needed. */
+ if (allocation_size != get_file_size(*psbuf)) {
+ if (vfs_allocate_file_space(fsp, allocation_size) == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+ }
+ /* But always update the time. */
+ /*
+ * This is equivalent to a write. Ensure it's seen immediately
+ * if there are no pending writes.
+ */
+ trigger_write_time_update_immediate(fsp);
+ return NT_STATUS_OK;
+ }
+
+ /* Pathname or stat or directory file. */
+
+ status = open_file_ntcreate(conn, req, fname, psbuf,
+ FILE_WRITE_DATA,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OPEN,
+ 0,
+ FILE_ATTRIBUTE_NORMAL,
+ FORCE_OPLOCK_BREAK_TO_NONE,
+ NULL, &new_fsp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ /* NB. We check for open_was_deferred in the caller. */
+ return status;
+ }
+
+ /* Only change if needed. */
+ if (allocation_size != get_file_size(*psbuf)) {
+ if (vfs_allocate_file_space(new_fsp, allocation_size) == -1) {
+ status = map_nt_error_from_unix(errno);
+ close_file(new_fsp,NORMAL_CLOSE);
+ return status;
+ }
+ }
+
+ /* Changing the allocation size should set the last mod time. */
+ /*
+ * This is equivalent to a write. Ensure it's seen immediately
+ * if there are no pending writes.
+ */
+ trigger_write_time_update_immediate(new_fsp);
+
+ close_file(new_fsp,NORMAL_CLOSE);
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Deal with SMB_SET_FILE_END_OF_FILE_INFO.
+****************************************************************************/
+
+static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn,
+ struct smb_request *req,
+ const char *pdata,
+ int total_data,
+ files_struct *fsp,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf)
+{
+ SMB_OFF_T size;
+
+ if (total_data < 8) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ 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 NT_STATUS_INVALID_PARAMETER;
+ }
+#endif /* LARGE_SMB_OFF_T */
+ DEBUG(10,("smb_set_file_end_of_file_info: Set end of file info for "
+ "file %s to %.0f\n", fname, (double)size ));
+
+ return smb_set_file_size(conn, req,
+ fsp,
+ fname,
+ psbuf,
+ size);
+}
+
+/****************************************************************************
+ Allow a UNIX info mknod.
+****************************************************************************/
+
+static NTSTATUS smb_unix_mknod(connection_struct *conn,
+ const char *pdata,
+ int total_data,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf)
+{
+ uint32 file_type = IVAL(pdata,56);
+#if defined(HAVE_MAKEDEV)
+ uint32 dev_major = IVAL(pdata,60);
+ uint32 dev_minor = IVAL(pdata,68);
+#endif
+ SMB_DEV_T dev = (SMB_DEV_T)0;
+ uint32 raw_unixmode = IVAL(pdata,84);
+ NTSTATUS status;
+ mode_t unixmode;
+
+ if (total_data < 100) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = unix_perms_from_wire(conn, psbuf, raw_unixmode, PERM_NEW_FILE, &unixmode);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+#if defined(HAVE_MAKEDEV)
+ dev = makedev(dev_major, dev_minor);
+#endif
+
+ switch (file_type) {
+#if defined(S_IFIFO)
+ case UNIX_TYPE_FIFO:
+ unixmode |= S_IFIFO;
+ break;
+#endif
+#if defined(S_IFSOCK)
+ case UNIX_TYPE_SOCKET:
+ unixmode |= S_IFSOCK;
+ break;
+#endif
+#if defined(S_IFCHR)
+ case UNIX_TYPE_CHARDEV:
+ unixmode |= S_IFCHR;
+ break;
+#endif
+#if defined(S_IFBLK)
+ case UNIX_TYPE_BLKDEV:
+ unixmode |= S_IFBLK;
+ break;
+#endif
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev %.0f mode \
+0%o for file %s\n", (double)dev, (unsigned int)unixmode, fname ));
+
+ /* Ok - do the mknod. */
+ if (SMB_VFS_MKNOD(conn, fname, unixmode, dev) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ /* If any of the other "set" calls fail we
+ * don't want to end up with a half-constructed mknod.
+ */
+
+ if (lp_inherit_perms(SNUM(conn))) {
+ inherit_access_posix_acl(
+ conn, parent_dirname(fname),
+ fname, unixmode);
+ }
+
+ if (SMB_VFS_STAT(conn, fname, psbuf) != 0) {
+ status = map_nt_error_from_unix(errno);
+ SMB_VFS_UNLINK(conn,fname);
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Deal with SMB_SET_FILE_UNIX_BASIC.
+****************************************************************************/
+
+static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
+ struct smb_request *req,
+ const char *pdata,
+ int total_data,
+ files_struct *fsp,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf)
+{
+ struct timespec ts[2];
+ uint32 raw_unixmode;
+ mode_t unixmode;
+ SMB_OFF_T size = 0;
+ uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
+ gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
+ NTSTATUS status = NT_STATUS_OK;
+ bool delete_on_fail = False;
+ enum perm_type ptype;
+
+ if (total_data < 100) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
+ IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
+ size=IVAL(pdata,0); /* first 8 Bytes are size */
+#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 NT_STATUS_INVALID_PARAMETER;
+ }
+#endif /* LARGE_SMB_OFF_T */
+ }
+
+ ts[0] = interpret_long_date(pdata+24); /* access_time */
+ ts[1] = interpret_long_date(pdata+32); /* modification_time */
+ set_owner = (uid_t)IVAL(pdata,40);
+ set_grp = (gid_t)IVAL(pdata,48);
+ raw_unixmode = IVAL(pdata,84);
+
+ if (VALID_STAT(*psbuf)) {
+ if (S_ISDIR(psbuf->st_mode)) {
+ ptype = PERM_EXISTING_DIR;
+ } else {
+ ptype = PERM_EXISTING_FILE;
+ }
+ } else {
+ ptype = PERM_NEW_FILE;
+ }
+
+ status = unix_perms_from_wire(conn, psbuf, raw_unixmode, ptype, &unixmode);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = %s \
+size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
+ fname, (double)size, (unsigned int)set_owner, (unsigned int)set_grp, (int)raw_unixmode));
+
+ if (!VALID_STAT(*psbuf)) {
+ /*
+ * The only valid use of this is to create character and block
+ * devices, and named pipes. This is deprecated (IMHO) and
+ * a new info level should be used for mknod. JRA.
+ */
+
+ status = smb_unix_mknod(conn,
+ pdata,
+ total_data,
+ fname,
+ psbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Ensure we don't try and change anything else. */
+ raw_unixmode = SMB_MODE_NO_CHANGE;
+ size = get_file_size(*psbuf);
+ ts[0] = get_atimespec(psbuf);
+ ts[1] = get_mtimespec(psbuf);
+ /*
+ * We continue here as we might want to change the
+ * owner uid/gid.
+ */
+ delete_on_fail = True;
+ }
+
+#if 1
+ /* Horrible backwards compatibility hack as an old server bug
+ * allowed a CIFS client bug to remain unnoticed :-(. JRA.
+ * */
+
+ if (!size) {
+ size = get_file_size(*psbuf);
+ }
+#endif
+
+ /*
+ * Deal with the UNIX specific mode set.
+ */
+
+ if (raw_unixmode != SMB_MODE_NO_CHANGE) {
+ DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC setting mode 0%o for file %s\n",
+ (unsigned int)unixmode, fname ));
+ if (SMB_VFS_CHMOD(conn, fname, unixmode) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+ }
+
+ /*
+ * Deal with the UNIX specific uid set.
+ */
+
+ if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) && (psbuf->st_uid != set_owner)) {
+ int ret;
+
+ DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC changing owner %u for path %s\n",
+ (unsigned int)set_owner, fname ));
+
+ if (S_ISLNK(psbuf->st_mode)) {
+ ret = SMB_VFS_LCHOWN(conn, fname, set_owner, (gid_t)-1);
+ } else {
+ ret = SMB_VFS_CHOWN(conn, fname, set_owner, (gid_t)-1);
+ }
+
+ if (ret != 0) {
+ status = map_nt_error_from_unix(errno);
+ if (delete_on_fail) {
+ SMB_VFS_UNLINK(conn,fname);
+ }
+ return status;
+ }
+ }
+
+ /*
+ * Deal with the UNIX specific gid set.
+ */
+
+ if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) && (psbuf->st_gid != set_grp)) {
+ DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC changing group %u for file %s\n",
+ (unsigned int)set_owner, fname ));
+ if (SMB_VFS_CHOWN(conn, fname, (uid_t)-1, set_grp) != 0) {
+ status = map_nt_error_from_unix(errno);
+ if (delete_on_fail) {
+ SMB_VFS_UNLINK(conn,fname);
+ }
+ return status;
+ }
+ }
+
+ /* Deal with any size changes. */
+
+ status = smb_set_file_size(conn, req,
+ fsp,
+ fname,
+ psbuf,
+ size);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Deal with any time changes. */
+
+ return smb_set_file_time(conn,
+ fsp,
+ fname,
+ psbuf,
+ ts,
+ true);
+}
+
+/****************************************************************************
+ Deal with SMB_SET_FILE_UNIX_INFO2.
+****************************************************************************/
+
+static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
+ struct smb_request *req,
+ const char *pdata,
+ int total_data,
+ files_struct *fsp,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf)
+{
+ NTSTATUS status;
+ uint32 smb_fflags;
+ uint32 smb_fmask;
+
+ if (total_data < 116) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Start by setting all the fields that are common between UNIX_BASIC
+ * and UNIX_INFO2.
+ */
+ status = smb_set_file_unix_basic(conn, req, pdata, total_data,
+ fsp, fname, psbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ smb_fflags = IVAL(pdata, 108);
+ smb_fmask = IVAL(pdata, 112);
+
+ /* NB: We should only attempt to alter the file flags if the client
+ * sends a non-zero mask.
+ */
+ if (smb_fmask != 0) {
+ int stat_fflags = 0;
+
+ if (!map_info2_flags_to_sbuf(psbuf, smb_fflags, smb_fmask,
+ &stat_fflags)) {
+ /* Client asked to alter a flag we don't understand. */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (fsp && fsp->fh->fd != -1) {
+ /* XXX: we should be using SMB_VFS_FCHFLAGS here. */
+ return NT_STATUS_NOT_SUPPORTED;
+ } else {
+ if (SMB_VFS_CHFLAGS(conn, fname, stat_fflags) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+ }
+ }
+
+ /* XXX: need to add support for changing the create_time here. You
+ * can do this for paths on Darwin with setattrlist(2). The right way
+ * to hook this up is probably by extending the VFS utimes interface.
+ */
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Create a directory with POSIX semantics.
+****************************************************************************/
+
+static NTSTATUS smb_posix_mkdir(connection_struct *conn,
+ struct smb_request *req,
+ char **ppdata,
+ int total_data,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf,
+ int *pdata_return_size)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ uint32 raw_unixmode = 0;
+ uint32 mod_unixmode = 0;
+ mode_t unixmode = (mode_t)0;
+ files_struct *fsp = NULL;
+ uint16 info_level_return = 0;
+ int info;
+ char *pdata = *ppdata;
+
+ if (total_data < 18) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ raw_unixmode = IVAL(pdata,8);
+ /* Next 4 bytes are not yet defined. */
+
+ status = unix_perms_from_wire(conn, psbuf, raw_unixmode, PERM_NEW_DIR, &unixmode);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
+
+ DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
+ fname, (unsigned int)unixmode ));
+
+ status = open_directory(conn, req,
+ fname,
+ psbuf,
+ FILE_READ_ATTRIBUTES, /* Just a stat open */
+ FILE_SHARE_NONE, /* Ignored for stat opens */
+ FILE_CREATE,
+ 0,
+ mod_unixmode,
+ &info,
+ &fsp);
+
+ if (NT_STATUS_IS_OK(status)) {
+ close_file(fsp, NORMAL_CLOSE);
+ }
+
+ info_level_return = SVAL(pdata,16);
+
+ if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
+ *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
+ } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
+ *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
+ } else {
+ *pdata_return_size = 12;
+ }
+
+ /* Realloc the data size */
+ *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
+ if (*ppdata == NULL) {
+ *pdata_return_size = 0;
+ return NT_STATUS_NO_MEMORY;
+ }
+ pdata = *ppdata;
+
+ SSVAL(pdata,0,NO_OPLOCK_RETURN);
+ SSVAL(pdata,2,0); /* No fnum. */
+ SIVAL(pdata,4,info); /* Was directory created. */
+
+ switch (info_level_return) {
+ case SMB_QUERY_FILE_UNIX_BASIC:
+ SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
+ SSVAL(pdata,10,0); /* Padding. */
+ store_file_unix_basic(conn, pdata + 12, fsp, psbuf);
+ break;
+ case SMB_QUERY_FILE_UNIX_INFO2:
+ SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
+ SSVAL(pdata,10,0); /* Padding. */
+ store_file_unix_basic_info2(conn, pdata + 12, fsp, psbuf);
+ break;
+ default:
+ SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
+ SSVAL(pdata,10,0); /* Padding. */
+ break;
+ }
+
+ return status;
+}
+
+/****************************************************************************
+ Open/Create a file with POSIX semantics.
+****************************************************************************/
+
+static NTSTATUS smb_posix_open(connection_struct *conn,
+ struct smb_request *req,
+ char **ppdata,
+ int total_data,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf,
+ int *pdata_return_size)
+{
+ bool extended_oplock_granted = False;
+ char *pdata = *ppdata;
+ uint32 flags = 0;
+ uint32 wire_open_mode = 0;
+ uint32 raw_unixmode = 0;
+ uint32 mod_unixmode = 0;
+ uint32 create_disp = 0;
+ uint32 access_mask = 0;
+ uint32 create_options = 0;
+ NTSTATUS status = NT_STATUS_OK;
+ mode_t unixmode = (mode_t)0;
+ files_struct *fsp = NULL;
+ int oplock_request = 0;
+ int info = 0;
+ uint16 info_level_return = 0;
+
+ if (total_data < 18) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ flags = IVAL(pdata,0);
+ oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
+ if (oplock_request) {
+ oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+ }
+
+ wire_open_mode = IVAL(pdata,4);
+
+ if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
+ return smb_posix_mkdir(conn, req,
+ ppdata,
+ total_data,
+ fname,
+ psbuf,
+ pdata_return_size);
+ }
+
+ switch (wire_open_mode & SMB_ACCMODE) {
+ case SMB_O_RDONLY:
+ access_mask = FILE_READ_DATA;
+ break;
+ case SMB_O_WRONLY:
+ access_mask = FILE_WRITE_DATA;
+ break;
+ case SMB_O_RDWR:
+ access_mask = FILE_READ_DATA|FILE_WRITE_DATA;
+ break;
+ default:
+ DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
+ (unsigned int)wire_open_mode ));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ wire_open_mode &= ~SMB_ACCMODE;
+
+ if((wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) == (SMB_O_CREAT | SMB_O_EXCL)) {
+ create_disp = FILE_CREATE;
+ } else if((wire_open_mode & (SMB_O_CREAT | SMB_O_TRUNC)) == (SMB_O_CREAT | SMB_O_TRUNC)) {
+ create_disp = FILE_OVERWRITE_IF;
+ } else if((wire_open_mode & SMB_O_CREAT) == SMB_O_CREAT) {
+ create_disp = FILE_OPEN_IF;
+ } else {
+ DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
+ (unsigned int)wire_open_mode ));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ raw_unixmode = IVAL(pdata,8);
+ /* Next 4 bytes are not yet defined. */
+
+ status = unix_perms_from_wire(conn,
+ psbuf,
+ raw_unixmode,
+ VALID_STAT(*psbuf) ? PERM_EXISTING_FILE : PERM_NEW_FILE,
+ &unixmode);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
+
+ if (wire_open_mode & SMB_O_SYNC) {
+ create_options |= FILE_WRITE_THROUGH;
+ }
+ if (wire_open_mode & SMB_O_APPEND) {
+ access_mask |= FILE_APPEND_DATA;
+ }
+ if (wire_open_mode & SMB_O_DIRECT) {
+ mod_unixmode |= FILE_FLAG_NO_BUFFERING;
+ }
+
+ DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
+ fname,
+ (unsigned int)wire_open_mode,
+ (unsigned int)unixmode ));
+
+ status = open_file_ntcreate(conn, req,
+ fname,
+ psbuf,
+ access_mask,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ create_disp,
+ 0, /* no create options yet. */
+ mod_unixmode,
+ oplock_request,
+ &info,
+ &fsp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ extended_oplock_granted = True;
+ }
+
+ if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ extended_oplock_granted = True;
+ }
+
+ info_level_return = SVAL(pdata,16);
+
+ /* Allocate the correct return size. */
+
+ if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
+ *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
+ } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
+ *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
+ } else {
+ *pdata_return_size = 12;
+ }
+
+ /* Realloc the data size */
+ *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
+ if (*ppdata == NULL) {
+ close_file(fsp,ERROR_CLOSE);
+ *pdata_return_size = 0;
+ return NT_STATUS_NO_MEMORY;
+ }
+ pdata = *ppdata;
+
+ if (extended_oplock_granted) {
+ if (flags & REQUEST_BATCH_OPLOCK) {
+ SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
+ } else {
+ SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
+ }
+ } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
+ SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
+ } else {
+ SSVAL(pdata,0,NO_OPLOCK_RETURN);
+ }
+
+ SSVAL(pdata,2,fsp->fnum);
+ SIVAL(pdata,4,info); /* Was file created etc. */
+
+ switch (info_level_return) {
+ case SMB_QUERY_FILE_UNIX_BASIC:
+ SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
+ SSVAL(pdata,10,0); /* padding. */
+ store_file_unix_basic(conn, pdata + 12, fsp, psbuf);
+ break;
+ case SMB_QUERY_FILE_UNIX_INFO2:
+ SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
+ SSVAL(pdata,10,0); /* padding. */
+ store_file_unix_basic_info2(conn, pdata + 12, fsp, psbuf);
+ break;
+ default:
+ SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
+ SSVAL(pdata,10,0); /* padding. */
+ break;
+ }
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Delete a file with POSIX semantics.
+****************************************************************************/
+
+static NTSTATUS smb_posix_unlink(connection_struct *conn,
+ struct smb_request *req,
+ const char *pdata,
+ int total_data,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ files_struct *fsp = NULL;
+ uint16 flags = 0;
+ char del = 1;
+ int info = 0;
+ int i;
+ struct share_mode_lock *lck = NULL;
+
+ if (total_data < 2) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ flags = SVAL(pdata,0);
+
+ if (!VALID_STAT(*psbuf)) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
+ !VALID_STAT_OF_DIR(*psbuf)) {
+ return NT_STATUS_NOT_A_DIRECTORY;
+ }
+
+ DEBUG(10,("smb_posix_unlink: %s %s\n",
+ (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
+ fname));
+
+ if (VALID_STAT_OF_DIR(*psbuf)) {
+ status = open_directory(conn, req,
+ fname,
+ psbuf,
+ DELETE_ACCESS,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OPEN,
+ 0,
+ FILE_FLAG_POSIX_SEMANTICS|0777,
+ &info,
+ &fsp);
+ } else {
+
+ status = open_file_ntcreate(conn, req,
+ fname,
+ psbuf,
+ DELETE_ACCESS,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OPEN,
+ 0,
+ FILE_FLAG_POSIX_SEMANTICS|0777,
+ 0, /* No oplock, but break existing ones. */
+ &info,
+ &fsp);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * Don't lie to client. If we can't really delete due to
+ * non-POSIX opens return SHARING_VIOLATION.
+ */
+
+ lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
+ NULL);
+ if (lck == NULL) {
+ DEBUG(0, ("smb_posix_unlink: Could not get share mode "
+ "lock for file %s\n", fsp->fsp_name));
+ close_file(fsp, NORMAL_CLOSE);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /*
+ * See if others still have the file open. If this is the case, then
+ * don't delete. If all opens are POSIX delete we can set the delete
+ * on close disposition.
+ */
+ for (i=0; i<lck->num_share_modes; i++) {
+ struct share_mode_entry *e = &lck->share_modes[i];
+ if (is_valid_share_mode_entry(e)) {
+ if (e->flags & SHARE_MODE_FLAG_POSIX_OPEN) {
+ continue;
+ }
+ /* Fail with sharing violation. */
+ close_file(fsp, NORMAL_CLOSE);
+ TALLOC_FREE(lck);
+ return NT_STATUS_SHARING_VIOLATION;
+ }
+ }
+
+ /*
+ * Set the delete on close.
+ */
+ status = smb_set_file_disposition_info(conn,
+ &del,
+ 1,
+ fsp,
+ fname,
+ psbuf);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ close_file(fsp, NORMAL_CLOSE);
+ TALLOC_FREE(lck);
+ return status;
+ }
+ TALLOC_FREE(lck);
+ return close_file(fsp, NORMAL_CLOSE);
+}
+
+/****************************************************************************
+ Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname).
+****************************************************************************/
+
+static void call_trans2setfilepathinfo(connection_struct *conn,
+ struct smb_request *req,
+ unsigned int tran_call,
+ char **pparams, int total_params,
+ char **ppdata, int total_data,
+ unsigned int max_data_bytes)
+{
+ char *params = *pparams;
+ char *pdata = *ppdata;
+ uint16 info_level;
+ SMB_STRUCT_STAT sbuf;
+ char *fname = NULL;
+ files_struct *fsp = NULL;
+ NTSTATUS status = NT_STATUS_OK;
+ int data_return_size = 0;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if (!params) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ ZERO_STRUCT(sbuf);
+
+ if (tran_call == TRANSACT2_SETFILEINFO) {
+ if (total_params < 4) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ fsp = file_fsp(SVAL(params,0));
+ /* Basic check for non-null fsp. */
+ if (!check_fsp_open(conn, req, fsp)) {
+ return;
+ }
+ info_level = SVAL(params,2);
+
+ fname = talloc_strdup(talloc_tos(),fsp->fsp_name);
+ if (!fname) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+
+ if(fsp->is_directory || fsp->fh->fd == -1) {
+ /*
+ * This is actually a SETFILEINFO on a directory
+ * handle (returned from an NT SMB). NT5.0 seems
+ * to do this call. JRA.
+ */
+ if (INFO_LEVEL_IS_UNIX(info_level)) {
+ /* Always do lstat for UNIX calls. */
+ if (SMB_VFS_LSTAT(conn,fname,&sbuf)) {
+ DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
+ reply_unixerror(req,ERRDOS,ERRbadpath);
+ return;
+ }
+ } else {
+ if (SMB_VFS_STAT(conn,fname,&sbuf) != 0) {
+ DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
+ reply_unixerror(req,ERRDOS,ERRbadpath);
+ return;
+ }
+ }
+ } else if (fsp->print_file) {
+ /*
+ * Doing a DELETE_ON_CLOSE should cancel a print job.
+ */
+ if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) {
+ fsp->fh->private_options |= FILE_DELETE_ON_CLOSE;
+
+ DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n", fsp->fsp_name ));
+
+ SSVAL(params,0,0);
+ send_trans2_replies(conn, req, params, 2,
+ *ppdata, 0,
+ max_data_bytes);
+ return;
+ } else {
+ reply_unixerror(req, ERRDOS, ERRbadpath);
+ return;
+ }
+ } else {
+ /*
+ * Original code - this is an open file.
+ */
+ if (!check_fsp(conn, req, fsp)) {
+ return;
+ }
+
+ if (SMB_VFS_FSTAT(fsp, &sbuf) != 0) {
+ DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno)));
+ reply_unixerror(req, ERRDOS, ERRbadfid);
+ return;
+ }
+ }
+ } else {
+ /* set path info */
+ if (total_params < 7) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ info_level = SVAL(params,0);
+ srvstr_get_path(ctx, params, req->flags2, &fname, &params[6],
+ total_params - 6, STR_TERMINATE,
+ &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+
+ status = resolve_dfspath(ctx, conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ fname,
+ &fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req,
+ NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ return;
+ }
+ reply_nterror(req, status);
+ return;
+ }
+
+ status = unix_convert(ctx, conn, fname, False,
+ &fname, NULL, &sbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+
+ if (INFO_LEVEL_IS_UNIX(info_level)) {
+ /*
+ * For CIFS UNIX extensions the target name may not exist.
+ */
+
+ /* Always do lstat for UNIX calls. */
+ SMB_VFS_LSTAT(conn,fname,&sbuf);
+
+ } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) {
+ DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
+ reply_unixerror(req, ERRDOS, ERRbadpath);
+ return;
+ }
+ }
+
+ if (!CAN_WRITE(conn)) {
+ reply_doserror(req, ERRSRV, ERRaccess);
+ return;
+ }
+
+ if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+ DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d totdata=%d\n",
+ tran_call,fname, fsp ? fsp->fnum : -1, info_level,total_data));
+
+ /* Realloc the parameter size */
+ *pparams = (char *)SMB_REALLOC(*pparams,2);
+ if (*pparams == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ params = *pparams;
+
+ SSVAL(params,0,0);
+
+ switch (info_level) {
+
+ case SMB_INFO_STANDARD:
+ {
+ status = smb_set_info_standard(conn,
+ pdata,
+ total_data,
+ fsp,
+ fname,
+ &sbuf);
+ break;
+ }
+
+ case SMB_INFO_SET_EA:
+ {
+ status = smb_info_set_ea(conn,
+ pdata,
+ total_data,
+ fsp,
+ fname);
+ break;
+ }
+
+ case SMB_SET_FILE_BASIC_INFO:
+ case SMB_FILE_BASIC_INFORMATION:
+ {
+ status = smb_set_file_basic_info(conn,
+ pdata,
+ total_data,
+ fsp,
+ fname,
+ &sbuf);
+ break;
+ }
+
+ case SMB_FILE_ALLOCATION_INFORMATION:
+ case SMB_SET_FILE_ALLOCATION_INFO:
+ {
+ status = smb_set_file_allocation_info(conn, req,
+ pdata,
+ total_data,
+ fsp,
+ fname,
+ &sbuf);
+ break;
+ }
+
+ case SMB_FILE_END_OF_FILE_INFORMATION:
+ case SMB_SET_FILE_END_OF_FILE_INFO:
+ {
+ status = smb_set_file_end_of_file_info(conn, req,
+ pdata,
+ total_data,
+ fsp,
+ fname,
+ &sbuf);
+ break;
+ }
+
+ case SMB_FILE_DISPOSITION_INFORMATION:
+ case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
+ {
+#if 0
+ /* JRA - We used to just ignore this on a path ?
+ * Shouldn't this be invalid level on a pathname
+ * based call ?
+ */
+ if (tran_call != TRANSACT2_SETFILEINFO) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+ }
+#endif
+ status = smb_set_file_disposition_info(conn,
+ pdata,
+ total_data,
+ fsp,
+ fname,
+ &sbuf);
+ break;
+ }
+
+ case SMB_FILE_POSITION_INFORMATION:
+ {
+ status = smb_file_position_information(conn,
+ pdata,
+ total_data,
+ fsp);
+ break;
+ }
+
+ /* From tridge Samba4 :
+ * MODE_INFORMATION in setfileinfo (I have no
+ * idea what "mode information" on a file is - it takes a value of 0,
+ * 2, 4 or 6. What could it be?).
+ */
+
+ case SMB_FILE_MODE_INFORMATION:
+ {
+ status = smb_file_mode_information(conn,
+ pdata,
+ total_data);
+ break;
+ }
+
+ /*
+ * CIFS UNIX extensions.
+ */
+
+ case SMB_SET_FILE_UNIX_BASIC:
+ {
+ status = smb_set_file_unix_basic(conn, req,
+ pdata,
+ total_data,
+ fsp,
+ fname,
+ &sbuf);
+ break;
+ }
+
+ case SMB_SET_FILE_UNIX_INFO2:
+ {
+ status = smb_set_file_unix_info2(conn, req,
+ pdata,
+ total_data,
+ fsp,
+ fname,
+ &sbuf);
+ break;
+ }
+
+ case SMB_SET_FILE_UNIX_LINK:
+ {
+ if (tran_call != TRANSACT2_SETPATHINFO) {
+ /* We must have a pathname for this. */
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+ status = smb_set_file_unix_link(conn, req, pdata,
+ total_data, fname);
+ break;
+ }
+
+ case SMB_SET_FILE_UNIX_HLINK:
+ {
+ if (tran_call != TRANSACT2_SETPATHINFO) {
+ /* We must have a pathname for this. */
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+ status = smb_set_file_unix_hlink(conn, req,
+ pdata, total_data,
+ fname);
+ break;
+ }
+
+ case SMB_FILE_RENAME_INFORMATION:
+ {
+ status = smb_file_rename_information(conn, req,
+ pdata, total_data,
+ fsp, fname);
+ break;
+ }
+
+#if defined(HAVE_POSIX_ACLS)
+ case SMB_SET_POSIX_ACL:
+ {
+ status = smb_set_posix_acl(conn,
+ pdata,
+ total_data,
+ fsp,
+ fname,
+ &sbuf);
+ break;
+ }
+#endif
+
+ case SMB_SET_POSIX_LOCK:
+ {
+ if (tran_call != TRANSACT2_SETFILEINFO) {
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+ status = smb_set_posix_lock(conn, req,
+ pdata, total_data, fsp);
+ break;
+ }
+
+ case SMB_POSIX_PATH_OPEN:
+ {
+ if (tran_call != TRANSACT2_SETPATHINFO) {
+ /* We must have a pathname for this. */
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+ status = smb_posix_open(conn, req,
+ ppdata,
+ total_data,
+ fname,
+ &sbuf,
+ &data_return_size);
+ break;
+ }
+
+ case SMB_POSIX_PATH_UNLINK:
+ {
+ if (tran_call != TRANSACT2_SETPATHINFO) {
+ /* We must have a pathname for this. */
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+ status = smb_posix_unlink(conn, req,
+ pdata,
+ total_data,
+ fname,
+ &sbuf);
+ break;
+ }
+
+ default:
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+
+ if (!NT_STATUS_IS_OK(status)) {
+ if (open_was_deferred(req->mid)) {
+ /* We have re-scheduled this call. */
+ return;
+ }
+ if (blocking_lock_was_deferred(req->mid)) {
+ /* We have re-scheduled this call. */
+ return;
+ }
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ ERRSRV, ERRbadpath);
+ return;
+ }
+ if (info_level == SMB_POSIX_PATH_OPEN) {
+ reply_openerror(req, status);
+ return;
+ }
+
+ reply_nterror(req, status);
+ return;
+ }
+
+ SSVAL(params,0,0);
+ send_trans2_replies(conn, req, params, 2, *ppdata, data_return_size,
+ max_data_bytes);
+
+ return;
+}
+
+/****************************************************************************
+ Reply to a TRANS2_MKDIR (make directory with extended attributes).
+****************************************************************************/
+
+static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
+ char **pparams, int total_params,
+ char **ppdata, int total_data,
+ unsigned int max_data_bytes)
+{
+ char *params = *pparams;
+ char *pdata = *ppdata;
+ char *directory = NULL;
+ SMB_STRUCT_STAT sbuf;
+ NTSTATUS status = NT_STATUS_OK;
+ struct ea_list *ea_list = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ if (!CAN_WRITE(conn)) {
+ reply_doserror(req, ERRSRV, ERRaccess);
+ return;
+ }
+
+ if (total_params < 5) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ srvstr_get_path(ctx, params, req->flags2, &directory, &params[4],
+ total_params - 4, STR_TERMINATE,
+ &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+
+ DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
+
+ status = unix_convert(ctx, conn, directory, False, &directory, NULL, &sbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+
+ status = check_name(conn, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("call_trans2mkdir error (%s)\n", nt_errstr(status)));
+ reply_nterror(req, status);
+ return;
+ }
+
+ /* Any data in this call is an EA list. */
+ if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) {
+ reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
+ return;
+ }
+
+ /*
+ * OS/2 workplace shell seems to send SET_EA requests of "null"
+ * length (4 bytes containing IVAL 4).
+ * They seem to have no effect. Bug #3212. JRA.
+ */
+
+ if (total_data != 4) {
+ if (total_data < 10) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ if (IVAL(pdata,0) > total_data) {
+ DEBUG(10,("call_trans2mkdir: bad total data size (%u) > %u\n",
+ IVAL(pdata,0), (unsigned int)total_data));
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ ea_list = read_ea_list(talloc_tos(), pdata + 4,
+ total_data - 4);
+ if (!ea_list) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+ } else if (IVAL(pdata,0) != 4) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ status = create_directory(conn, req, directory);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+
+ /* Try and set any given EA. */
+ if (ea_list) {
+ status = set_ea(conn, NULL, directory, ea_list);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ return;
+ }
+ }
+
+ /* Realloc the parameter and data sizes */
+ *pparams = (char *)SMB_REALLOC(*pparams,2);
+ if(*pparams == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ params = *pparams;
+
+ SSVAL(params,0,0);
+
+ send_trans2_replies(conn, req, params, 2, *ppdata, 0, max_data_bytes);
+
+ return;
+}
+
+/****************************************************************************
+ Reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes).
+ We don't actually do this - we just send a null response.
+****************************************************************************/
+
+static void call_trans2findnotifyfirst(connection_struct *conn,
+ struct smb_request *req,
+ char **pparams, int total_params,
+ char **ppdata, int total_data,
+ unsigned int max_data_bytes)
+{
+ static uint16 fnf_handle = 257;
+ char *params = *pparams;
+ uint16 info_level;
+
+ if (total_params < 6) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ info_level = SVAL(params,4);
+ DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
+
+ switch (info_level) {
+ case 1:
+ case 2:
+ break;
+ default:
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+ /* Realloc the parameter and data sizes */
+ *pparams = (char *)SMB_REALLOC(*pparams,6);
+ if (*pparams == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ params = *pparams;
+
+ SSVAL(params,0,fnf_handle);
+ SSVAL(params,2,0); /* No changes */
+ SSVAL(params,4,0); /* No EA errors */
+
+ fnf_handle++;
+
+ if(fnf_handle == 0)
+ fnf_handle = 257;
+
+ send_trans2_replies(conn, req, params, 6, *ppdata, 0, max_data_bytes);
+
+ return;
+}
+
+/****************************************************************************
+ Reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for
+ changes). Currently this does nothing.
+****************************************************************************/
+
+static void call_trans2findnotifynext(connection_struct *conn,
+ struct smb_request *req,
+ char **pparams, int total_params,
+ char **ppdata, int total_data,
+ unsigned int max_data_bytes)
+{
+ char *params = *pparams;
+
+ DEBUG(3,("call_trans2findnotifynext\n"));
+
+ /* Realloc the parameter and data sizes */
+ *pparams = (char *)SMB_REALLOC(*pparams,4);
+ if (*pparams == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ params = *pparams;
+
+ SSVAL(params,0,0); /* No changes */
+ SSVAL(params,2,0); /* No EA errors */
+
+ send_trans2_replies(conn, req, params, 4, *ppdata, 0, max_data_bytes);
+
+ return;
+}
+
+/****************************************************************************
+ Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
+****************************************************************************/
+
+static void call_trans2getdfsreferral(connection_struct *conn,
+ struct smb_request *req,
+ char **pparams, int total_params,
+ char **ppdata, int total_data,
+ unsigned int max_data_bytes)
+{
+ char *params = *pparams;
+ char *pathname = NULL;
+ int reply_size = 0;
+ int max_referral_level;
+ NTSTATUS status = NT_STATUS_OK;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ DEBUG(10,("call_trans2getdfsreferral\n"));
+
+ if (total_params < 3) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ max_referral_level = SVAL(params,0);
+
+ if(!lp_host_msdfs()) {
+ reply_doserror(req, ERRDOS, ERRbadfunc);
+ return;
+ }
+
+ srvstr_pull_talloc(ctx, params, req->flags2, &pathname, &params[2],
+ total_params - 2, STR_TERMINATE);
+ if (!pathname) {
+ reply_nterror(req, NT_STATUS_NOT_FOUND);
+ return;
+ }
+ if((reply_size = setup_dfs_referral(conn, pathname, max_referral_level,
+ ppdata,&status)) < 0) {
+ reply_nterror(req, status);
+ return;
+ }
+
+ SSVAL(req->inbuf, smb_flg2,
+ SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
+ send_trans2_replies(conn, req,0,0,*ppdata,reply_size, max_data_bytes);
+
+ return;
+}
+
+#define LMCAT_SPL 0x53
+#define LMFUNC_GETJOBID 0x60
+
+/****************************************************************************
+ Reply to a TRANS2_IOCTL - used for OS/2 printing.
+****************************************************************************/
+
+static void call_trans2ioctl(connection_struct *conn,
+ struct smb_request *req,
+ char **pparams, int total_params,
+ char **ppdata, int total_data,
+ unsigned int max_data_bytes)
+{
+ char *pdata = *ppdata;
+ files_struct *fsp = file_fsp(SVAL(req->inbuf,smb_vwv15));
+
+ /* check for an invalid fid before proceeding */
+
+ if (!fsp) {
+ reply_doserror(req, ERRDOS, ERRbadfid);
+ return;
+ }
+
+ if ((SVAL(req->inbuf,(smb_setup+4)) == LMCAT_SPL)
+ && (SVAL(req->inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
+ *ppdata = (char *)SMB_REALLOC(*ppdata, 32);
+ if (*ppdata == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ pdata = *ppdata;
+
+ /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2
+ CAN ACCEPT THIS IN UNICODE. JRA. */
+
+ SSVAL(pdata,0,fsp->rap_print_jobid); /* Job number */
+ srvstr_push(pdata, req->flags2, pdata + 2,
+ global_myname(), 15,
+ STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */
+ srvstr_push(pdata, req->flags2, pdata+18,
+ lp_servicename(SNUM(conn)), 13,
+ STR_ASCII|STR_TERMINATE); /* Service name */
+ send_trans2_replies(conn, req, *pparams, 0, *ppdata, 32,
+ max_data_bytes);
+ return;
+ }
+
+ DEBUG(2,("Unknown TRANS2_IOCTL\n"));
+ reply_doserror(req, ERRSRV, ERRerror);
+}
+
+/****************************************************************************
+ Reply to a SMBfindclose (stop trans2 directory search).
+****************************************************************************/
+
+void reply_findclose(struct smb_request *req)
+{
+ int dptr_num;
+
+ START_PROFILE(SMBfindclose);
+
+ if (req->wct < 1) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBfindclose);
+ return;
+ }
+
+ dptr_num = SVALS(req->inbuf,smb_vwv0);
+
+ DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num));
+
+ dptr_close(&dptr_num);
+
+ reply_outbuf(req, 0, 0);
+
+ DEBUG(3,("SMBfindclose dptr_num = %d\n", dptr_num));
+
+ END_PROFILE(SMBfindclose);
+ return;
+}
+
+/****************************************************************************
+ Reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search).
+****************************************************************************/
+
+void reply_findnclose(struct smb_request *req)
+{
+ int dptr_num;
+
+ START_PROFILE(SMBfindnclose);
+
+ if (req->wct < 1) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBfindnclose);
+ return;
+ }
+
+ dptr_num = SVAL(req->inbuf,smb_vwv0);
+
+ DEBUG(3,("reply_findnclose, dptr_num = %d\n", dptr_num));
+
+ /* We never give out valid handles for a
+ findnotifyfirst - so any dptr_num is ok here.
+ Just ignore it. */
+
+ reply_outbuf(req, 0, 0);
+
+ DEBUG(3,("SMB_findnclose dptr_num = %d\n", dptr_num));
+
+ END_PROFILE(SMBfindnclose);
+ return;
+}
+
+static void handle_trans2(connection_struct *conn, struct smb_request *req,
+ struct trans_state *state)
+{
+ if (Protocol >= PROTOCOL_NT1) {
+ req->flags2 |= 0x40; /* IS_LONG_NAME */
+ SSVAL(req->inbuf,smb_flg2,req->flags2);
+ }
+
+ if (conn->encrypt_level == Required && !req->encrypted) {
+ if (state->call != TRANSACT2_QFSINFO &&
+ state->call != TRANSACT2_SETFSINFO) {
+ DEBUG(0,("handle_trans2: encryption required "
+ "with call 0x%x\n",
+ (unsigned int)state->call));
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+ }
+
+ /* Now we must call the relevant TRANS2 function */
+ switch(state->call) {
+ case TRANSACT2_OPEN:
+ {
+ START_PROFILE(Trans2_open);
+ call_trans2open(conn, req,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(Trans2_open);
+ break;
+ }
+
+ case TRANSACT2_FINDFIRST:
+ {
+ START_PROFILE(Trans2_findfirst);
+ call_trans2findfirst(conn, req,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(Trans2_findfirst);
+ break;
+ }
+
+ case TRANSACT2_FINDNEXT:
+ {
+ START_PROFILE(Trans2_findnext);
+ call_trans2findnext(conn, req,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(Trans2_findnext);
+ break;
+ }
+
+ case TRANSACT2_QFSINFO:
+ {
+ START_PROFILE(Trans2_qfsinfo);
+ call_trans2qfsinfo(conn, req,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(Trans2_qfsinfo);
+ break;
+ }
+
+ case TRANSACT2_SETFSINFO:
+ {
+ START_PROFILE(Trans2_setfsinfo);
+ call_trans2setfsinfo(conn, req,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(Trans2_setfsinfo);
+ break;
+ }
+
+ case TRANSACT2_QPATHINFO:
+ case TRANSACT2_QFILEINFO:
+ {
+ START_PROFILE(Trans2_qpathinfo);
+ call_trans2qfilepathinfo(conn, req, state->call,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(Trans2_qpathinfo);
+ break;
+ }
+
+ case TRANSACT2_SETPATHINFO:
+ case TRANSACT2_SETFILEINFO:
+ {
+ START_PROFILE(Trans2_setpathinfo);
+ call_trans2setfilepathinfo(conn, req, state->call,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(Trans2_setpathinfo);
+ break;
+ }
+
+ case TRANSACT2_FINDNOTIFYFIRST:
+ {
+ START_PROFILE(Trans2_findnotifyfirst);
+ call_trans2findnotifyfirst(conn, req,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(Trans2_findnotifyfirst);
+ break;
+ }
+
+ case TRANSACT2_FINDNOTIFYNEXT:
+ {
+ START_PROFILE(Trans2_findnotifynext);
+ call_trans2findnotifynext(conn, req,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(Trans2_findnotifynext);
+ break;
+ }
+
+ case TRANSACT2_MKDIR:
+ {
+ START_PROFILE(Trans2_mkdir);
+ call_trans2mkdir(conn, req,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(Trans2_mkdir);
+ break;
+ }
+
+ case TRANSACT2_GET_DFS_REFERRAL:
+ {
+ START_PROFILE(Trans2_get_dfs_referral);
+ call_trans2getdfsreferral(conn, req,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(Trans2_get_dfs_referral);
+ break;
+ }
+
+ case TRANSACT2_IOCTL:
+ {
+ START_PROFILE(Trans2_ioctl);
+ call_trans2ioctl(conn, req,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE(Trans2_ioctl);
+ break;
+ }
+
+ default:
+ /* Error in request */
+ DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
+ reply_doserror(req, ERRSRV,ERRerror);
+ }
+}
+
+/****************************************************************************
+ Reply to a SMBtrans2.
+ ****************************************************************************/
+
+void reply_trans2(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ unsigned int dsoff;
+ unsigned int dscnt;
+ unsigned int psoff;
+ unsigned int pscnt;
+ unsigned int tran_call;
+ unsigned int size;
+ unsigned int av_size;
+ struct trans_state *state;
+ NTSTATUS result;
+
+ START_PROFILE(SMBtrans2);
+
+ if (req->wct < 14) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBtrans2);
+ return;
+ }
+
+ dsoff = SVAL(req->inbuf, smb_dsoff);
+ dscnt = SVAL(req->inbuf, smb_dscnt);
+ psoff = SVAL(req->inbuf, smb_psoff);
+ pscnt = SVAL(req->inbuf, smb_pscnt);
+ tran_call = SVAL(req->inbuf, smb_setup0);
+ size = smb_len(req->inbuf) + 4;
+ av_size = smb_len(req->inbuf);
+
+ result = allow_new_trans(conn->pending_trans, req->mid);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(2, ("Got invalid trans2 request: %s\n",
+ nt_errstr(result)));
+ reply_nterror(req, result);
+ END_PROFILE(SMBtrans2);
+ return;
+ }
+
+ if (IS_IPC(conn)) {
+ switch (tran_call) {
+ /* List the allowed trans2 calls on IPC$ */
+ case TRANSACT2_OPEN:
+ case TRANSACT2_GET_DFS_REFERRAL:
+ case TRANSACT2_QFILEINFO:
+ case TRANSACT2_QFSINFO:
+ case TRANSACT2_SETFSINFO:
+ break;
+ default:
+ reply_doserror(req, ERRSRV, ERRaccess);
+ END_PROFILE(SMBtrans2);
+ return;
+ }
+ }
+
+ if ((state = TALLOC_P(conn, struct trans_state)) == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBtrans2);
+ return;
+ }
+
+ state->cmd = SMBtrans2;
+
+ state->mid = req->mid;
+ state->vuid = req->vuid;
+ state->setup_count = SVAL(req->inbuf, smb_suwcnt);
+ state->setup = NULL;
+ state->total_param = SVAL(req->inbuf, smb_tpscnt);
+ state->param = NULL;
+ state->total_data = SVAL(req->inbuf, smb_tdscnt);
+ state->data = NULL;
+ state->max_param_return = SVAL(req->inbuf, smb_mprcnt);
+ state->max_data_return = SVAL(req->inbuf, smb_mdrcnt);
+ state->max_setup_return = SVAL(req->inbuf, smb_msrcnt);
+ state->close_on_completion = BITSETW(req->inbuf+smb_vwv5,0);
+ state->one_way = BITSETW(req->inbuf+smb_vwv5,1);
+
+ state->call = tran_call;
+
+ /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
+ is so as a sanity check */
+ if (state->setup_count != 1) {
+ /*
+ * Need to have rc=0 for ioctl to get job id for OS/2.
+ * Network printing will fail if function is not successful.
+ * Similar function in reply.c will be used if protocol
+ * is LANMAN1.0 instead of LM1.2X002.
+ * Until DosPrintSetJobInfo with PRJINFO3 is supported,
+ * outbuf doesn't have to be set(only job id is used).
+ */
+ if ( (state->setup_count == 4)
+ && (tran_call == TRANSACT2_IOCTL)
+ && (SVAL(req->inbuf,(smb_setup+4)) == LMCAT_SPL)
+ && (SVAL(req->inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
+ DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
+ } else {
+ DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count));
+ DEBUG(2,("Transaction is %d\n",tran_call));
+ TALLOC_FREE(state);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBtrans2);
+ return;
+ }
+ }
+
+ if ((dscnt > state->total_data) || (pscnt > state->total_param))
+ goto bad_param;
+
+ if (state->total_data) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ state->data = (char *)SMB_MALLOC(state->total_data);
+ if (state->data == NULL) {
+ DEBUG(0,("reply_trans2: data malloc fail for %u "
+ "bytes !\n", (unsigned int)state->total_data));
+ TALLOC_FREE(state);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBtrans2);
+ return;
+ }
+
+ if (dscnt > state->total_data ||
+ dsoff+dscnt < dsoff) {
+ goto bad_param;
+ }
+
+ if (dsoff > av_size ||
+ dscnt > av_size ||
+ dsoff+dscnt > av_size) {
+ goto bad_param;
+ }
+
+ memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
+ }
+
+ if (state->total_param) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ state->param = (char *)SMB_MALLOC(state->total_param);
+ if (state->param == NULL) {
+ DEBUG(0,("reply_trans: param malloc fail for %u "
+ "bytes !\n", (unsigned int)state->total_param));
+ SAFE_FREE(state->data);
+ TALLOC_FREE(state);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBtrans2);
+ return;
+ }
+
+ if (pscnt > state->total_param ||
+ psoff+pscnt < psoff) {
+ goto bad_param;
+ }
+
+ if (psoff > av_size ||
+ pscnt > av_size ||
+ psoff+pscnt > av_size) {
+ goto bad_param;
+ }
+
+ memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
+ }
+
+ state->received_data = dscnt;
+ state->received_param = pscnt;
+
+ if ((state->received_param == state->total_param) &&
+ (state->received_data == state->total_data)) {
+
+ handle_trans2(conn, req, state);
+
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtrans2);
+ return;
+ }
+
+ DLIST_ADD(conn->pending_trans, state);
+
+ /* We need to send an interim response then receive the rest
+ of the parameter/data bytes */
+ reply_outbuf(req, 0, 0);
+ show_msg((char *)req->outbuf);
+ END_PROFILE(SMBtrans2);
+ return;
+
+ bad_param:
+
+ DEBUG(0,("reply_trans2: invalid trans parameters\n"));
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBtrans2);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+}
+
+
+/****************************************************************************
+ Reply to a SMBtranss2
+ ****************************************************************************/
+
+void reply_transs2(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
+ struct trans_state *state;
+ unsigned int size;
+ unsigned int av_size;
+
+ START_PROFILE(SMBtranss2);
+
+ show_msg((char *)req->inbuf);
+
+ if (req->wct < 8) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBtranss2);
+ return;
+ }
+
+ size = smb_len(req->inbuf)+4;
+ av_size = smb_len(req->inbuf);
+
+ for (state = conn->pending_trans; state != NULL;
+ state = state->next) {
+ if (state->mid == req->mid) {
+ break;
+ }
+ }
+
+ if ((state == NULL) || (state->cmd != SMBtrans2)) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBtranss2);
+ return;
+ }
+
+ /* Revise state->total_param and state->total_data in case they have
+ changed downwards */
+
+ if (SVAL(req->inbuf, smb_tpscnt) < state->total_param)
+ state->total_param = SVAL(req->inbuf, smb_tpscnt);
+ if (SVAL(req->inbuf, smb_tdscnt) < state->total_data)
+ state->total_data = SVAL(req->inbuf, smb_tdscnt);
+
+ pcnt = SVAL(req->inbuf, smb_spscnt);
+ poff = SVAL(req->inbuf, smb_spsoff);
+ pdisp = SVAL(req->inbuf, smb_spsdisp);
+
+ dcnt = SVAL(req->inbuf, smb_sdscnt);
+ doff = SVAL(req->inbuf, smb_sdsoff);
+ ddisp = SVAL(req->inbuf, smb_sdsdisp);
+
+ state->received_param += pcnt;
+ state->received_data += dcnt;
+
+ if ((state->received_data > state->total_data) ||
+ (state->received_param > state->total_param))
+ goto bad_param;
+
+ if (pcnt) {
+ if (pdisp > state->total_param ||
+ pcnt > state->total_param ||
+ pdisp+pcnt > state->total_param ||
+ pdisp+pcnt < pdisp) {
+ goto bad_param;
+ }
+
+ if (poff > av_size ||
+ pcnt > av_size ||
+ poff+pcnt > av_size ||
+ poff+pcnt < poff) {
+ goto bad_param;
+ }
+
+ memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,
+ pcnt);
+ }
+
+ if (dcnt) {
+ if (ddisp > state->total_data ||
+ dcnt > state->total_data ||
+ ddisp+dcnt > state->total_data ||
+ ddisp+dcnt < ddisp) {
+ goto bad_param;
+ }
+
+ if (ddisp > av_size ||
+ dcnt > av_size ||
+ ddisp+dcnt > av_size ||
+ ddisp+dcnt < ddisp) {
+ goto bad_param;
+ }
+
+ memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,
+ dcnt);
+ }
+
+ if ((state->received_param < state->total_param) ||
+ (state->received_data < state->total_data)) {
+ END_PROFILE(SMBtranss2);
+ return;
+ }
+
+ /*
+ * construct_reply_common will copy smb_com from inbuf to
+ * outbuf. SMBtranss2 is wrong here.
+ */
+ SCVAL(req->inbuf,smb_com,SMBtrans2);
+
+ handle_trans2(conn, req, state);
+
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+
+ END_PROFILE(SMBtranss2);
+ return;
+
+ bad_param:
+
+ DEBUG(0,("reply_transs2: invalid trans parameters\n"));
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBtranss2);
+ return;
+}
diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c
new file mode 100644
index 0000000000..8998f6a371
--- /dev/null
+++ b/source3/smbd/uid.c
@@ -0,0 +1,449 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* what user is current? */
+extern struct current_user current_user;
+
+/****************************************************************************
+ Become the guest user without changing the security context stack.
+****************************************************************************/
+
+bool change_to_guest(void)
+{
+ static struct passwd *pass=NULL;
+
+ if (!pass) {
+ /* Don't need to free() this as its stored in a static */
+ pass = getpwnam_alloc(NULL, lp_guestaccount());
+ if (!pass)
+ return(False);
+ }
+
+#ifdef AIX
+ /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
+ setting IDs */
+ initgroups(pass->pw_name, pass->pw_gid);
+#endif
+
+ set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
+
+ current_user.conn = NULL;
+ current_user.vuid = UID_FIELD_INVALID;
+
+ TALLOC_FREE(pass);
+ pass = NULL;
+
+ return True;
+}
+
+/*******************************************************************
+ Check if a username is OK.
+
+ This sets up conn->server_info with a copy related to this vuser that
+ later code can then mess with.
+********************************************************************/
+
+static bool check_user_ok(connection_struct *conn, uint16_t vuid,
+ struct auth_serversupplied_info *server_info,
+ int snum)
+{
+ unsigned int i;
+ struct vuid_cache_entry *ent = NULL;
+ bool readonly_share;
+ bool admin_user;
+
+ for (i=0; i<VUID_CACHE_SIZE; i++) {
+ ent = &conn->vuid_cache.array[i];
+ if (ent->vuid == vuid) {
+ conn->server_info = ent->server_info;
+ conn->read_only = ent->read_only;
+ conn->admin_user = ent->admin_user;
+ return(True);
+ }
+ }
+
+ if (!user_ok_token(server_info->unix_name,
+ pdb_get_domain(server_info->sam_account),
+ server_info->ptok, snum))
+ return(False);
+
+ readonly_share = is_share_read_only_for_token(
+ server_info->unix_name,
+ pdb_get_domain(server_info->sam_account),
+ server_info->ptok, snum);
+
+ if (!readonly_share &&
+ !share_access_check(server_info->ptok, lp_servicename(snum),
+ FILE_WRITE_DATA)) {
+ /* smb.conf allows r/w, but the security descriptor denies
+ * write. Fall back to looking at readonly. */
+ readonly_share = True;
+ DEBUG(5,("falling back to read-only access-evaluation due to "
+ "security descriptor\n"));
+ }
+
+ if (!share_access_check(server_info->ptok, lp_servicename(snum),
+ readonly_share ?
+ FILE_READ_DATA : FILE_WRITE_DATA)) {
+ return False;
+ }
+
+ admin_user = token_contains_name_in_list(
+ server_info->unix_name,
+ pdb_get_domain(server_info->sam_account),
+ NULL, server_info->ptok, lp_admin_users(snum));
+
+ ent = &conn->vuid_cache.array[conn->vuid_cache.next_entry];
+
+ conn->vuid_cache.next_entry =
+ (conn->vuid_cache.next_entry + 1) % VUID_CACHE_SIZE;
+
+ TALLOC_FREE(ent->server_info);
+
+ /*
+ * If force_user was set, all server_info's are based on the same
+ * username-based faked one.
+ */
+
+ ent->server_info = copy_serverinfo(
+ conn, conn->force_user ? conn->server_info : server_info);
+
+ if (ent->server_info == NULL) {
+ ent->vuid = UID_FIELD_INVALID;
+ return false;
+ }
+
+ ent->vuid = vuid;
+ ent->read_only = readonly_share;
+ ent->admin_user = admin_user;
+
+ conn->read_only = ent->read_only;
+ conn->admin_user = ent->admin_user;
+ conn->server_info = ent->server_info;
+
+ return(True);
+}
+
+/****************************************************************************
+ Clear a vuid out of the connection's vuid cache
+****************************************************************************/
+
+void conn_clear_vuid_cache(connection_struct *conn, uint16_t vuid)
+{
+ int i;
+
+ for (i=0; i<VUID_CACHE_SIZE; i++) {
+ struct vuid_cache_entry *ent;
+
+ ent = &conn->vuid_cache.array[i];
+
+ if (ent->vuid == vuid) {
+ ent->vuid = UID_FIELD_INVALID;
+ TALLOC_FREE(ent->server_info);
+ ent->read_only = False;
+ ent->admin_user = False;
+ }
+ }
+}
+
+/****************************************************************************
+ Become the user of a connection number without changing the security context
+ stack, but modify the current_user entries.
+****************************************************************************/
+
+bool change_to_user(connection_struct *conn, uint16 vuid)
+{
+ user_struct *vuser = get_valid_user_struct(vuid);
+ int snum;
+ gid_t gid;
+ uid_t uid;
+ char group_c;
+ int num_groups = 0;
+ gid_t *group_list = NULL;
+
+ if (!conn) {
+ DEBUG(2,("change_to_user: Connection not open\n"));
+ return(False);
+ }
+
+ /*
+ * We need a separate check in security=share mode due to vuid
+ * always being UID_FIELD_INVALID. If we don't do this then
+ * in share mode security we are *always* changing uid's between
+ * SMB's - this hurts performance - Badly.
+ */
+
+ if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
+ (current_user.ut.uid == conn->server_info->utok.uid)) {
+ DEBUG(4,("change_to_user: Skipping user change - already "
+ "user\n"));
+ return(True);
+ } else if ((current_user.conn == conn) &&
+ (vuser != NULL) && (current_user.vuid == vuid) &&
+ (current_user.ut.uid == vuser->server_info->utok.uid)) {
+ DEBUG(4,("change_to_user: Skipping user change - already "
+ "user\n"));
+ return(True);
+ }
+
+ snum = SNUM(conn);
+
+ if ((vuser) && !check_user_ok(conn, vuid, vuser->server_info, snum)) {
+ DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) "
+ "not permitted access to share %s.\n",
+ vuser->server_info->sanitized_username,
+ vuser->server_info->unix_name, vuid,
+ lp_servicename(snum)));
+ return False;
+ }
+
+ /*
+ * conn->server_info is now correctly set up with a copy we can mess
+ * with for force_group etc.
+ */
+
+ if (conn->force_user) /* security = share sets this too */ {
+ uid = conn->server_info->utok.uid;
+ gid = conn->server_info->utok.gid;
+ group_list = conn->server_info->utok.groups;
+ num_groups = conn->server_info->utok.ngroups;
+ } else if (vuser) {
+ uid = conn->admin_user ? 0 : vuser->server_info->utok.uid;
+ gid = conn->server_info->utok.gid;
+ num_groups = conn->server_info->utok.ngroups;
+ group_list = conn->server_info->utok.groups;
+ } else {
+ DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
+ "share %s.\n",vuid, lp_servicename(snum) ));
+ return False;
+ }
+
+ /*
+ * See if we should force group for this service.
+ * If so this overrides any group set in the force
+ * user code.
+ */
+
+ if((group_c = *lp_force_group(snum))) {
+
+ if(group_c == '+') {
+
+ /*
+ * Only force group if the user is a member of
+ * the service group. Check the group memberships for
+ * this user (we already have this) to
+ * see if we should force the group.
+ */
+
+ int i;
+ for (i = 0; i < num_groups; i++) {
+ if (group_list[i]
+ == conn->server_info->utok.gid) {
+ gid = conn->server_info->utok.gid;
+ gid_to_sid(&conn->server_info->ptok
+ ->user_sids[1], gid);
+ break;
+ }
+ }
+ } else {
+ gid = conn->server_info->utok.gid;
+ gid_to_sid(&conn->server_info->ptok->user_sids[1],
+ gid);
+ }
+ }
+
+ /* Now set current_user since we will immediately also call
+ set_sec_ctx() */
+
+ current_user.ut.ngroups = num_groups;
+ current_user.ut.groups = group_list;
+
+ set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups,
+ conn->server_info->ptok);
+
+ current_user.conn = conn;
+ current_user.vuid = vuid;
+
+ DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
+ (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
+
+ return(True);
+}
+
+/****************************************************************************
+ Go back to being root without changing the security context stack,
+ but modify the current_user entries.
+****************************************************************************/
+
+bool change_to_root_user(void)
+{
+ set_root_sec_ctx();
+
+ DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
+ (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
+
+ current_user.conn = NULL;
+ current_user.vuid = UID_FIELD_INVALID;
+
+ return(True);
+}
+
+/****************************************************************************
+ Become the user of an authenticated connected named pipe.
+ When this is called we are currently running as the connection
+ user. Doesn't modify current_user.
+****************************************************************************/
+
+bool become_authenticated_pipe_user(pipes_struct *p)
+{
+ if (!push_sec_ctx())
+ return False;
+
+ set_sec_ctx(p->pipe_user.ut.uid, p->pipe_user.ut.gid,
+ p->pipe_user.ut.ngroups, p->pipe_user.ut.groups,
+ p->pipe_user.nt_user_token);
+
+ return True;
+}
+
+/****************************************************************************
+ Unbecome the user of an authenticated connected named pipe.
+ When this is called we are running as the authenticated pipe
+ user and need to go back to being the connection user. Doesn't modify
+ current_user.
+****************************************************************************/
+
+bool unbecome_authenticated_pipe_user(void)
+{
+ return pop_sec_ctx();
+}
+
+/****************************************************************************
+ Utility functions used by become_xxx/unbecome_xxx.
+****************************************************************************/
+
+struct conn_ctx {
+ connection_struct *conn;
+ uint16 vuid;
+};
+
+/* A stack of current_user connection contexts. */
+
+static struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH];
+static int conn_ctx_stack_ndx;
+
+static void push_conn_ctx(void)
+{
+ struct conn_ctx *ctx_p;
+
+ /* Check we don't overflow our stack */
+
+ if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
+ DEBUG(0, ("Connection context stack overflow!\n"));
+ smb_panic("Connection context stack overflow!\n");
+ }
+
+ /* Store previous user context */
+ ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
+
+ ctx_p->conn = current_user.conn;
+ ctx_p->vuid = current_user.vuid;
+
+ DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
+ (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
+
+ conn_ctx_stack_ndx++;
+}
+
+static void pop_conn_ctx(void)
+{
+ struct conn_ctx *ctx_p;
+
+ /* Check for stack underflow. */
+
+ if (conn_ctx_stack_ndx == 0) {
+ DEBUG(0, ("Connection context stack underflow!\n"));
+ smb_panic("Connection context stack underflow!\n");
+ }
+
+ conn_ctx_stack_ndx--;
+ ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
+
+ current_user.conn = ctx_p->conn;
+ current_user.vuid = ctx_p->vuid;
+
+ ctx_p->conn = NULL;
+ ctx_p->vuid = UID_FIELD_INVALID;
+}
+
+/****************************************************************************
+ Temporarily become a root user. Must match with unbecome_root(). Saves and
+ restores the connection context.
+****************************************************************************/
+
+void become_root(void)
+{
+ /*
+ * no good way to handle push_sec_ctx() failing without changing
+ * the prototype of become_root()
+ */
+ if (!push_sec_ctx()) {
+ smb_panic("become_root: push_sec_ctx failed");
+ }
+ push_conn_ctx();
+ set_root_sec_ctx();
+}
+
+/* Unbecome the root user */
+
+void unbecome_root(void)
+{
+ pop_sec_ctx();
+ pop_conn_ctx();
+}
+
+/****************************************************************************
+ Push the current security context then force a change via change_to_user().
+ Saves and restores the connection context.
+****************************************************************************/
+
+bool become_user(connection_struct *conn, uint16 vuid)
+{
+ if (!push_sec_ctx())
+ return False;
+
+ push_conn_ctx();
+
+ if (!change_to_user(conn, vuid)) {
+ pop_sec_ctx();
+ pop_conn_ctx();
+ return False;
+ }
+
+ return True;
+}
+
+bool unbecome_user(void)
+{
+ pop_sec_ctx();
+ pop_conn_ctx();
+ return True;
+}
diff --git a/source3/smbd/utmp.c b/source3/smbd/utmp.c
new file mode 100644
index 0000000000..af947ef462
--- /dev/null
+++ b/source3/smbd/utmp.c
@@ -0,0 +1,630 @@
+/*
+ Unix SMB/CIFS implementation.
+ utmp routines
+ Copyright (C) T.D.Lee@durham.ac.uk 1999
+ Heavily modified by Andrew Bartlett and Tridge, April 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+Reflect connection status in utmp/wtmp files.
+ T.D.Lee@durham.ac.uk September 1999
+
+ With grateful thanks since then to many who have helped port it to
+ different operating systems. The variety of OS quirks thereby
+ uncovered is amazing...
+
+Hints for porting:
+ o Always attempt to use programmatic interface (pututline() etc.)
+ Indeed, at present only programmatic use is supported.
+ o The only currently supported programmatic interface to "wtmp{,x}"
+ is through "updwtmp*()" routines.
+ o The "x" (utmpx/wtmpx; HAVE_UTMPX_H) seems preferable.
+ o The HAVE_* items should identify supported features.
+ o If at all possible, avoid "if defined(MY-OS)" constructions.
+
+OS observations and status:
+ Almost every OS seems to have its own quirks.
+
+ Solaris 2.x:
+ Tested on 2.6 and 2.7; should be OK on other flavours.
+ AIX:
+ Apparently has utmpx.h but doesn't implement.
+ OSF:
+ Has utmpx.h, but (e.g.) no "getutmpx()". (Is this like AIX ?)
+ Redhat 6:
+ utmpx.h seems not to set default filenames. non-x better.
+ IRIX 6.5:
+ Not tested. Appears to have "x".
+ HP-UX 9.x:
+ Not tested. Appears to lack "x".
+ HP-UX 10.x:
+ Not tested.
+ "updwtmp*()" routines seem absent, so no current wtmp* support.
+ Has "ut_addr": probably trivial to implement (although remember
+ that IPv6 is coming...).
+
+ FreeBSD:
+ No "putut*()" type of interface.
+ No "ut_type" and associated defines.
+ Write files directly. Alternatively use its login(3)/logout(3).
+ SunOS 4:
+ Not tested. Resembles FreeBSD, but no login()/logout().
+
+lastlog:
+ Should "lastlog" files, if any, be updated?
+ BSD systems (SunOS 4, FreeBSD):
+ o Prominent mention on man pages.
+ System-V (e.g. Solaris 2):
+ o No mention on man pages, even under "man -k".
+ o Has a "/var/adm/lastlog" file, but pututxline() etc. seem
+ not to touch it.
+ o Despite downplaying (above), nevertheless has <lastlog.h>.
+ So perhaps UN*X "lastlog" facility is intended for tty/terminal only?
+
+Notes:
+ Each connection requires a small number (starting at 0, working up)
+ to represent the line. This must be unique within and across all
+ smbd processes. It is the 'id_num' from Samba's session.c code.
+
+ The 4 byte 'ut_id' component is vital to distinguish connections,
+ of which there could be several hundred or even thousand.
+ Entries seem to be printable characters, with optional NULL pads.
+
+ We need to be distinct from other entries in utmp/wtmp.
+
+ Observed things: therefore avoid them. Add to this list please.
+ From Solaris 2.x (because that's what I have):
+ 'sN' : run-levels; N: [0-9]
+ 'co' : console
+ 'CC' : arbitrary things; C: [a-z]
+ 'rXNN' : rlogin; N: [0-9]; X: [0-9a-z]
+ 'tXNN' : rlogin; N: [0-9]; X: [0-9a-z]
+ '/NNN' : Solaris CDE
+ 'ftpZ' : ftp (Z is the number 255, aka 0377, aka 0xff)
+ Mostly a record uses the same 'ut_id' in both "utmp" and "wtmp",
+ but differences have been seen.
+
+ Arbitrarily I have chosen to use a distinctive 'SM' for the
+ first two bytes.
+
+ The remaining two bytes encode the session 'id_num' (see above).
+ Our caller (session.c) should note our 16-bit limitation.
+
+****************************************************************************/
+
+#ifndef WITH_UTMP
+/*
+ * Not WITH_UTMP? Simply supply dummy routines.
+ */
+
+void sys_utmp_claim(const char *username, const char *hostname,
+ const char *ip_addr_str,
+ const char *id_str, int id_num)
+{}
+
+void sys_utmp_yield(const char *username, const char *hostname,
+ const char *ip_addr_str,
+ const char *id_str, int id_num)
+{}
+
+#else /* WITH_UTMP */
+
+#include <utmp.h>
+
+#ifdef HAVE_UTMPX_H
+#include <utmpx.h>
+#endif
+
+/* BSD systems: some may need lastlog.h (SunOS 4), some may not (FreeBSD) */
+/* Some System-V systems (e.g. Solaris 2) declare this too. */
+#ifdef HAVE_LASTLOG_H
+#include <lastlog.h>
+#endif
+
+/****************************************************************************
+ Default paths to various {u,w}tmp{,x} files.
+****************************************************************************/
+
+#ifdef HAVE_UTMPX_H
+
+static const char *ux_pathname =
+# if defined (UTMPX_FILE)
+ UTMPX_FILE ;
+# elif defined (_UTMPX_FILE)
+ _UTMPX_FILE ;
+# elif defined (_PATH_UTMPX)
+ _PATH_UTMPX ;
+# else
+ "" ;
+# endif
+
+static const char *wx_pathname =
+# if defined (WTMPX_FILE)
+ WTMPX_FILE ;
+# elif defined (_WTMPX_FILE)
+ _WTMPX_FILE ;
+# elif defined (_PATH_WTMPX)
+ _PATH_WTMPX ;
+# else
+ "" ;
+# endif
+
+#endif /* HAVE_UTMPX_H */
+
+static const char *ut_pathname =
+# if defined (UTMP_FILE)
+ UTMP_FILE ;
+# elif defined (_UTMP_FILE)
+ _UTMP_FILE ;
+# elif defined (_PATH_UTMP)
+ _PATH_UTMP ;
+# else
+ "" ;
+# endif
+
+static const char *wt_pathname =
+# if defined (WTMP_FILE)
+ WTMP_FILE ;
+# elif defined (_WTMP_FILE)
+ _WTMP_FILE ;
+# elif defined (_PATH_WTMP)
+ _PATH_WTMP ;
+# else
+ "" ;
+# endif
+
+/* BSD-like systems might want "lastlog" support. */
+#if 0 /* *** Not yet implemented */
+#ifndef HAVE_PUTUTLINE /* see "pututline_my()" */
+static const char *ll_pathname =
+# if defined (_PATH_LASTLOG) /* what other names (if any?) */
+ _PATH_LASTLOG ;
+# else
+ "" ;
+# endif /* _PATH_LASTLOG */
+#endif /* HAVE_PUTUTLINE */
+#endif
+
+/*
+ * Get name of {u,w}tmp{,x} file.
+ * return: fname contains filename
+ * Possibly empty if this code not yet ported to this system.
+ *
+ * utmp{,x}: try "utmp dir", then default (a define)
+ * wtmp{,x}: try "wtmp dir", then "utmp dir", then default (a define)
+ */
+static char *uw_pathname(TALLOC_CTX *ctx,
+ const char *uw_name,
+ const char *uw_default)
+{
+ char *dirname = NULL;
+
+ /* For w-files, first look for explicit "wtmp dir" */
+ if (uw_name[0] == 'w') {
+ dirname = talloc_strdup(ctx, lp_wtmpdir());
+ if (!dirname) {
+ return NULL;
+ }
+ trim_char(dirname,'\0','/');
+ }
+
+ /* For u-files and non-explicit w-dir, look for "utmp dir" */
+ if ((dirname == NULL) || (strlen(dirname) == 0)) {
+ dirname = talloc_strdup(ctx, lp_utmpdir());
+ if (!dirname) {
+ return NULL;
+ }
+ trim_char(dirname,'\0','/');
+ }
+
+ /* If explicit directory above, use it */
+ if (dirname && strlen(dirname) != 0) {
+ return talloc_asprintf(ctx,
+ "%s/%s",
+ dirname,
+ uw_name);
+ }
+
+ /* No explicit directory: attempt to use default paths */
+ if (strlen(uw_default) == 0) {
+ /* No explicit setting, no known default.
+ * Has it yet been ported to this OS?
+ */
+ DEBUG(2,("uw_pathname: unable to determine pathname\n"));
+ }
+ return talloc_strdup(ctx, uw_default);
+}
+
+#ifndef HAVE_PUTUTLINE
+/****************************************************************************
+ Update utmp file directly. No subroutine interface: probably a BSD system.
+****************************************************************************/
+
+static void pututline_my(const char *uname, struct utmp *u, bool claim)
+{
+ DEBUG(1,("pututline_my: not yet implemented\n"));
+ /* BSD implementor: may want to consider (or not) adjusting "lastlog" */
+}
+#endif /* HAVE_PUTUTLINE */
+
+#ifndef HAVE_UPDWTMP
+
+/****************************************************************************
+ Update wtmp file directly. No subroutine interface: probably a BSD system.
+ Credit: Michail Vidiassov <master@iaas.msu.ru>
+****************************************************************************/
+
+static void updwtmp_my(const char *wname, struct utmp *u, bool claim)
+{
+ int fd;
+ struct stat buf;
+
+ if (! claim) {
+ /*
+ * BSD-like systems:
+ * may use empty ut_name to distinguish a logout record.
+ *
+ * May need "if defined(SUNOS4)" etc. around some of these,
+ * but try to avoid if possible.
+ *
+ * SunOS 4:
+ * man page indicates ut_name and ut_host both NULL
+ * FreeBSD 4.0:
+ * man page appears not to specify (hints non-NULL)
+ * A correspondent suggest at least ut_name should be NULL
+ */
+#if defined(HAVE_UT_UT_NAME)
+ memset((char *)&u->ut_name, '\0', sizeof(u->ut_name));
+#endif
+#if defined(HAVE_UT_UT_HOST)
+ memset((char *)&u->ut_host, '\0', sizeof(u->ut_host));
+#endif
+ }
+ /* Stolen from logwtmp function in libutil.
+ * May be more locking/blocking is needed?
+ */
+ if ((fd = open(wname, O_WRONLY|O_APPEND, 0)) < 0)
+ return;
+ if (fstat(fd, &buf) == 0) {
+ if (write(fd, (char *)u, sizeof(struct utmp)) != sizeof(struct utmp))
+ (void) ftruncate(fd, buf.st_size);
+ }
+ (void) close(fd);
+}
+#endif /* HAVE_UPDWTMP */
+
+/****************************************************************************
+ Update via utmp/wtmp (not utmpx/wtmpx).
+****************************************************************************/
+
+static void utmp_nox_update(struct utmp *u, bool claim)
+{
+ char *uname = NULL;
+ char *wname = NULL;
+#if defined(PUTUTLINE_RETURNS_UTMP)
+ struct utmp *urc;
+#endif /* PUTUTLINE_RETURNS_UTMP */
+
+ uname = uw_pathname(talloc_tos(), "utmp", ut_pathname);
+ if (!uname) {
+ return;
+ }
+ DEBUG(2,("utmp_nox_update: uname:%s\n", uname));
+
+#ifdef HAVE_PUTUTLINE
+ if (strlen(uname) != 0) {
+ utmpname(uname);
+ }
+
+# if defined(PUTUTLINE_RETURNS_UTMP)
+ setutent();
+ urc = pututline(u);
+ endutent();
+ if (urc == NULL) {
+ DEBUG(2,("utmp_nox_update: pututline() failed\n"));
+ return;
+ }
+# else /* PUTUTLINE_RETURNS_UTMP */
+ setutent();
+ pututline(u);
+ endutent();
+# endif /* PUTUTLINE_RETURNS_UTMP */
+
+#else /* HAVE_PUTUTLINE */
+ if (strlen(uname) != 0) {
+ pututline_my(uname, u, claim);
+ }
+#endif /* HAVE_PUTUTLINE */
+
+ wname = uw_pathname(talloc_tos(), "wtmp", wt_pathname);
+ if (!wname) {
+ return;
+ }
+ DEBUG(2,("utmp_nox_update: wname:%s\n", wname));
+ if (strlen(wname) != 0) {
+#ifdef HAVE_UPDWTMP
+ updwtmp(wname, u);
+ /*
+ * updwtmp() and the newer updwtmpx() may be unsymmetrical.
+ * At least one OS, Solaris 2.x declares the former in the
+ * "utmpx" (latter) file and context.
+ * In the Solaris case this is irrelevant: it has both and
+ * we always prefer the "x" case, so doesn't come here.
+ * But are there other systems, with no "x", which lack
+ * updwtmp() perhaps?
+ */
+#else
+ updwtmp_my(wname, u, claim);
+#endif /* HAVE_UPDWTMP */
+ }
+}
+
+/****************************************************************************
+ Copy a string in the utmp structure.
+****************************************************************************/
+
+static void utmp_strcpy(char *dest, const char *src, size_t n)
+{
+ size_t len = 0;
+
+ memset(dest, '\0', n);
+ if (src)
+ len = strlen(src);
+ if (len >= n) {
+ memcpy(dest, src, n);
+ } else {
+ if (len)
+ memcpy(dest, src, len);
+ }
+}
+
+/****************************************************************************
+ Update via utmpx/wtmpx (preferred) or via utmp/wtmp.
+****************************************************************************/
+
+static void sys_utmp_update(struct utmp *u, const char *hostname, bool claim)
+{
+#if !defined(HAVE_UTMPX_H)
+ /* No utmpx stuff. Drop to non-x stuff */
+ utmp_nox_update(u, claim);
+#elif !defined(HAVE_PUTUTXLINE)
+ /* Odd. Have utmpx.h but no "pututxline()". Drop to non-x stuff */
+ DEBUG(1,("utmp_update: have utmpx.h but no pututxline() function\n"));
+ utmp_nox_update(u, claim);
+#elif !defined(HAVE_GETUTMPX)
+ /* Odd. Have utmpx.h but no "getutmpx()". Drop to non-x stuff */
+ DEBUG(1,("utmp_update: have utmpx.h but no getutmpx() function\n"));
+ utmp_nox_update(u, claim);
+#elif !defined(HAVE_UPDWTMPX)
+ /* Have utmpx.h but no "updwtmpx()". Drop to non-x stuff */
+ DEBUG(1,("utmp_update: have utmpx.h but no updwtmpx() function\n"));
+ utmp_nox_update(u, claim);
+#else
+ char *uname = NULL;
+ char *wname = NULL;
+ struct utmpx ux, *uxrc;
+
+ getutmpx(u, &ux);
+
+#if defined(HAVE_UX_UT_SYSLEN)
+ if (hostname)
+ ux.ut_syslen = strlen(hostname) + 1; /* include end NULL */
+ else
+ ux.ut_syslen = 0;
+#endif
+#if defined(HAVE_UT_UT_HOST)
+ utmp_strcpy(ux.ut_host, hostname, sizeof(ux.ut_host));
+#endif
+
+ uname = uw_pathname(talloc_tos(), "utmpx", ux_pathname);
+ wname = uw_pathname(talloc_tos(), "wtmpx", wx_pathname);
+ if (uname && wname) {
+ DEBUG(2,("utmp_update: uname:%s wname:%s\n", uname, wname));
+ }
+
+ /*
+ * Check for either uname or wname being empty.
+ * Some systems, such as Redhat 6, have a "utmpx.h" which doesn't
+ * define default filenames.
+ * Also, our local installation has not provided an override.
+ * Drop to non-x method. (E.g. RH6 has good defaults in "utmp.h".)
+ */
+ if (!uname || !wname || (strlen(uname) == 0) || (strlen(wname) == 0)) {
+ utmp_nox_update(u, claim);
+ } else {
+ utmpxname(uname);
+ setutxent();
+ uxrc = pututxline(&ux);
+ endutxent();
+ if (uxrc == NULL) {
+ DEBUG(2,("utmp_update: pututxline() failed\n"));
+ return;
+ }
+ updwtmpx(wname, &ux);
+ }
+#endif /* HAVE_UTMPX_H */
+}
+
+#if defined(HAVE_UT_UT_ID)
+/****************************************************************************
+ Encode the unique connection number into "ut_id".
+****************************************************************************/
+
+static int ut_id_encode(int i, char *fourbyte)
+{
+ int nbase;
+ const char *ut_id_encstr = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ fourbyte[0] = 'S';
+ fourbyte[1] = 'M';
+
+/*
+ * Encode remaining 2 bytes from 'i'.
+ * 'ut_id_encstr' is the character set on which modulo arithmetic is done.
+ * Example: digits would produce the base-10 numbers from '001'.
+ */
+ nbase = strlen(ut_id_encstr);
+
+ fourbyte[3] = ut_id_encstr[i % nbase];
+ i /= nbase;
+ fourbyte[2] = ut_id_encstr[i % nbase];
+ i /= nbase;
+
+ return(i); /* 0: good; else overflow */
+}
+#endif /* defined(HAVE_UT_UT_ID) */
+
+
+/*
+ fill a system utmp structure given all the info we can gather
+*/
+static bool sys_utmp_fill(struct utmp *u,
+ const char *username, const char *hostname,
+ const char *ip_addr_str,
+ const char *id_str, int id_num)
+{
+ struct timeval timeval;
+
+ /*
+ * ut_name, ut_user:
+ * Several (all?) systems seems to define one as the other.
+ * It is easier and clearer simply to let the following take its course,
+ * rather than to try to detect and optimise.
+ */
+#if defined(HAVE_UT_UT_USER)
+ utmp_strcpy(u->ut_user, username, sizeof(u->ut_user));
+#elif defined(HAVE_UT_UT_NAME)
+ utmp_strcpy(u->ut_name, username, sizeof(u->ut_name));
+#endif
+
+ /*
+ * ut_line:
+ * If size limit proves troublesome, then perhaps use "ut_id_encode()".
+ */
+ if (strlen(id_str) > sizeof(u->ut_line)) {
+ DEBUG(1,("id_str [%s] is too long for %lu char utmp field\n",
+ id_str, (unsigned long)sizeof(u->ut_line)));
+ return False;
+ }
+ utmp_strcpy(u->ut_line, id_str, sizeof(u->ut_line));
+
+#if defined(HAVE_UT_UT_PID)
+ u->ut_pid = sys_getpid();
+#endif
+
+/*
+ * ut_time, ut_tv:
+ * Some have one, some the other. Many have both, but defined (aliased).
+ * It is easier and clearer simply to let the following take its course.
+ * But note that we do the more precise ut_tv as the final assignment.
+ */
+#if defined(HAVE_UT_UT_TIME)
+ GetTimeOfDay(&timeval);
+ u->ut_time = timeval.tv_sec;
+#elif defined(HAVE_UT_UT_TV)
+ GetTimeOfDay(&timeval);
+ u->ut_tv = timeval;
+#else
+#error "with-utmp must have UT_TIME or UT_TV"
+#endif
+
+#if defined(HAVE_UT_UT_HOST)
+ utmp_strcpy(u->ut_host, hostname, sizeof(u->ut_host));
+#endif
+#if defined(HAVE_IPV6) && defined(HAVE_UT_UT_ADDR_V6)
+ memset(&u->ut_addr_v6, '\0', sizeof(u->ut_addr_v6));
+ if (ip_addr_str) {
+ struct in6_addr addr;
+ if (inet_pton(AF_INET6, ip_addr_str, &addr) > 0) {
+ memcpy(&u->ut_addr_v6, &addr, sizeof(addr));
+ }
+ }
+#elif defined(HAVE_UT_UT_ADDR)
+ memset(&u->ut_addr, '\0', sizeof(u->ut_addr));
+ if (ip_addr_str) {
+ struct in_addr addr;
+ if (inet_pton(AF_INET, ip_addr_str, &addr) > 0) {
+ memcpy(&u->ut_addr, &addr, sizeof(addr));
+ }
+ }
+ /*
+ * "(unsigned long) ut_addr" apparently exists on at least HP-UX 10.20.
+ * Volunteer to implement, please ...
+ */
+#endif
+
+#if defined(HAVE_UT_UT_ID)
+ if (ut_id_encode(id_num, u->ut_id) != 0) {
+ DEBUG(1,("utmp_fill: cannot encode id %d\n", id_num));
+ return False;
+ }
+#endif
+
+ return True;
+}
+
+/****************************************************************************
+ Close a connection.
+****************************************************************************/
+
+void sys_utmp_yield(const char *username, const char *hostname,
+ const char *ip_addr_str,
+ const char *id_str, int id_num)
+{
+ struct utmp u;
+
+ ZERO_STRUCT(u);
+
+#if defined(HAVE_UT_UT_EXIT)
+ u.ut_exit.e_termination = 0;
+ u.ut_exit.e_exit = 0;
+#endif
+
+#if defined(HAVE_UT_UT_TYPE)
+ u.ut_type = DEAD_PROCESS;
+#endif
+
+ if (!sys_utmp_fill(&u, username, hostname, ip_addr_str, id_str, id_num))
+ return;
+
+ sys_utmp_update(&u, NULL, False);
+}
+
+/****************************************************************************
+ Claim a entry in whatever utmp system the OS uses.
+****************************************************************************/
+
+void sys_utmp_claim(const char *username, const char *hostname,
+ const char *ip_addr_str,
+ const char *id_str, int id_num)
+{
+ struct utmp u;
+
+ ZERO_STRUCT(u);
+
+#if defined(HAVE_UT_UT_TYPE)
+ u.ut_type = USER_PROCESS;
+#endif
+
+ if (!sys_utmp_fill(&u, username, hostname, ip_addr_str, id_str, id_num))
+ return;
+
+ sys_utmp_update(&u, hostname, True);
+}
+
+#endif /* WITH_UTMP */
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
new file mode 100644
index 0000000000..1e137dd908
--- /dev/null
+++ b/source3/smbd/vfs.c
@@ -0,0 +1,968 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ VFS initialisation and support functions
+ Copyright (C) Tim Potter 1999
+ Copyright (C) Alexander Bokovoy 2002
+ Copyright (C) James Peach 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ This work was sponsored by Optifacio Software Services, Inc.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+static_decl_vfs;
+
+struct vfs_init_function_entry {
+ char *name;
+ const vfs_op_tuple *vfs_op_tuples;
+ struct vfs_init_function_entry *prev, *next;
+};
+
+static struct vfs_init_function_entry *backends = NULL;
+
+/****************************************************************************
+ maintain the list of available backends
+****************************************************************************/
+
+static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
+{
+ struct vfs_init_function_entry *entry = backends;
+
+ DEBUG(10, ("vfs_find_backend_entry called for %s\n", name));
+
+ while(entry) {
+ if (strcmp(entry->name, name)==0) return entry;
+ entry = entry->next;
+ }
+
+ return NULL;
+}
+
+NTSTATUS smb_register_vfs(int version, const char *name, const vfs_op_tuple *vfs_op_tuples)
+{
+ struct vfs_init_function_entry *entry = backends;
+
+ if ((version != SMB_VFS_INTERFACE_VERSION)) {
+ DEBUG(0, ("Failed to register vfs module.\n"
+ "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
+ "current SMB_VFS_INTERFACE_VERSION is %d.\n"
+ "Please recompile against the current Samba Version!\n",
+ version, SMB_VFS_INTERFACE_VERSION));
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ if (!name || !name[0] || !vfs_op_tuples) {
+ DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (vfs_find_backend_entry(name)) {
+ DEBUG(0,("VFS module %s already loaded!\n", name));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
+ entry->name = smb_xstrdup(name);
+ entry->vfs_op_tuples = vfs_op_tuples;
+
+ DLIST_ADD(backends, entry);
+ DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ initialise default vfs hooks
+****************************************************************************/
+
+static void vfs_init_default(connection_struct *conn)
+{
+ DEBUG(3, ("Initialising default vfs hooks\n"));
+ vfs_init_custom(conn, DEFAULT_VFS_MODULE_NAME);
+}
+
+/****************************************************************************
+ initialise custom vfs hooks
+ ****************************************************************************/
+
+static inline void vfs_set_operation(struct vfs_ops * vfs, vfs_op_type which,
+ struct vfs_handle_struct * handle, void * op)
+{
+ ((struct vfs_handle_struct **)&vfs->handles)[which] = handle;
+ ((void **)(void *)&vfs->ops)[which] = op;
+}
+
+bool vfs_init_custom(connection_struct *conn, const char *vfs_object)
+{
+ const vfs_op_tuple *ops;
+ char *module_path = NULL;
+ char *module_name = NULL;
+ char *module_param = NULL, *p;
+ int i;
+ vfs_handle_struct *handle;
+ const struct vfs_init_function_entry *entry;
+
+ if (!conn||!vfs_object||!vfs_object[0]) {
+ DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
+ return False;
+ }
+
+ if(!backends) {
+ static_init_vfs;
+ }
+
+ DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
+
+ module_path = smb_xstrdup(vfs_object);
+
+ p = strchr_m(module_path, ':');
+
+ if (p) {
+ *p = 0;
+ module_param = p+1;
+ trim_char(module_param, ' ', ' ');
+ }
+
+ trim_char(module_path, ' ', ' ');
+
+ module_name = smb_xstrdup(module_path);
+
+ if ((module_name[0] == '/') &&
+ (strcmp(module_path, DEFAULT_VFS_MODULE_NAME) != 0)) {
+
+ /*
+ * Extract the module name from the path. Just use the base
+ * name of the last path component.
+ */
+
+ SAFE_FREE(module_name);
+ module_name = smb_xstrdup(strrchr_m(module_path, '/')+1);
+
+ p = strchr_m(module_name, '.');
+
+ if (p != NULL) {
+ *p = '\0';
+ }
+ }
+
+ /* First, try to load the module with the new module system */
+ if((entry = vfs_find_backend_entry(module_name)) ||
+ (NT_STATUS_IS_OK(smb_probe_module("vfs", module_path)) &&
+ (entry = vfs_find_backend_entry(module_name)))) {
+
+ DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
+
+ if ((ops = entry->vfs_op_tuples) == NULL) {
+ DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
+ goto fail;
+ }
+ } else {
+ DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
+ goto fail;
+ }
+
+ handle = TALLOC_ZERO_P(conn, vfs_handle_struct);
+ if (!handle) {
+ DEBUG(0,("TALLOC_ZERO() failed!\n"));
+ goto fail;
+ }
+ memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
+ handle->conn = conn;
+ if (module_param) {
+ handle->param = talloc_strdup(conn, module_param);
+ }
+ DLIST_ADD(conn->vfs_handles, handle);
+
+ for(i=0; ops[i].op != NULL; i++) {
+ DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
+ if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
+ /* If this operation was already made opaque by different module, it
+ * will be overridden here.
+ */
+ DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
+ vfs_set_operation(&conn->vfs_opaque, ops[i].type, handle, ops[i].op);
+ }
+ /* Change current VFS disposition*/
+ DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
+ vfs_set_operation(&conn->vfs, ops[i].type, handle, ops[i].op);
+ }
+
+ SAFE_FREE(module_path);
+ SAFE_FREE(module_name);
+ return True;
+
+ fail:
+ SAFE_FREE(module_path);
+ SAFE_FREE(module_name);
+ return False;
+}
+
+/*****************************************************************
+ Allow VFS modules to extend files_struct with VFS-specific state.
+ This will be ok for small numbers of extensions, but might need to
+ be refactored if it becomes more widely used.
+******************************************************************/
+
+#define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
+
+void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp, size_t ext_size)
+{
+ struct vfs_fsp_data *ext;
+ void * ext_data;
+
+ /* Prevent VFS modules adding multiple extensions. */
+ if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
+ return ext_data;
+ }
+
+ ext = (struct vfs_fsp_data *)TALLOC_ZERO(
+ handle->conn, sizeof(struct vfs_fsp_data) + ext_size);
+ if (ext == NULL) {
+ return NULL;
+ }
+
+ ext->owner = handle;
+ ext->next = fsp->vfs_extension;
+ fsp->vfs_extension = ext;
+ return EXT_DATA_AREA(ext);
+}
+
+void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
+{
+ struct vfs_fsp_data *curr;
+ struct vfs_fsp_data *prev;
+
+ for (curr = fsp->vfs_extension, prev = NULL;
+ curr;
+ prev = curr, curr = curr->next) {
+ if (curr->owner == handle) {
+ if (prev) {
+ prev->next = curr->next;
+ } else {
+ fsp->vfs_extension = curr->next;
+ }
+ TALLOC_FREE(curr);
+ return;
+ }
+ }
+}
+
+void *vfs_memctx_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
+{
+ struct vfs_fsp_data *head;
+
+ for (head = fsp->vfs_extension; head; head = head->next) {
+ if (head->owner == handle) {
+ return head;
+ }
+ }
+
+ return NULL;
+}
+
+void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
+{
+ struct vfs_fsp_data *head;
+
+ head = (struct vfs_fsp_data *)vfs_memctx_fsp_extension(handle, fsp);
+ if (head != NULL) {
+ return EXT_DATA_AREA(head);
+ }
+
+ return NULL;
+}
+
+#undef EXT_DATA_AREA
+
+/*****************************************************************
+ Generic VFS init.
+******************************************************************/
+
+bool smbd_vfs_init(connection_struct *conn)
+{
+ const char **vfs_objects;
+ unsigned int i = 0;
+ int j = 0;
+
+ /* Normal share - initialise with disk access functions */
+ vfs_init_default(conn);
+ vfs_objects = lp_vfs_objects(SNUM(conn));
+
+ /* Override VFS functions if 'vfs object' was not specified*/
+ if (!vfs_objects || !vfs_objects[0])
+ return True;
+
+ for (i=0; vfs_objects[i] ;) {
+ i++;
+ }
+
+ for (j=i-1; j >= 0; j--) {
+ if (!vfs_init_custom(conn, vfs_objects[j])) {
+ DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
+ return False;
+ }
+ }
+ return True;
+}
+
+/*******************************************************************
+ Check if directory exists.
+********************************************************************/
+
+bool vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
+{
+ SMB_STRUCT_STAT st2;
+ bool ret;
+
+ if (!st)
+ st = &st2;
+
+ if (SMB_VFS_STAT(conn,dname,st) != 0)
+ return(False);
+
+ ret = S_ISDIR(st->st_mode);
+ if(!ret)
+ errno = ENOTDIR;
+
+ return ret;
+}
+
+/*******************************************************************
+ Check if an object exists in the vfs.
+********************************************************************/
+
+bool vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
+{
+ SMB_STRUCT_STAT st;
+
+ if (!sbuf)
+ sbuf = &st;
+
+ ZERO_STRUCTP(sbuf);
+
+ if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
+ return(False);
+ return True;
+}
+
+/*******************************************************************
+ Check if a file exists in the vfs.
+********************************************************************/
+
+bool vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
+{
+ SMB_STRUCT_STAT st;
+
+ if (!sbuf)
+ sbuf = &st;
+
+ ZERO_STRUCTP(sbuf);
+
+ if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
+ return False;
+ return(S_ISREG(sbuf->st_mode));
+}
+
+/****************************************************************************
+ Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
+****************************************************************************/
+
+ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
+{
+ size_t total=0;
+
+ while (total < byte_count)
+ {
+ ssize_t ret = SMB_VFS_READ(fsp, buf + total,
+ byte_count - total);
+
+ if (ret == 0) return total;
+ if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+ else
+ return -1;
+ }
+ total += ret;
+ }
+ return (ssize_t)total;
+}
+
+ssize_t vfs_pread_data(files_struct *fsp, char *buf,
+ size_t byte_count, SMB_OFF_T offset)
+{
+ size_t total=0;
+
+ while (total < byte_count)
+ {
+ ssize_t ret = SMB_VFS_PREAD(fsp, buf + total,
+ byte_count - total, offset + total);
+
+ if (ret == 0) return total;
+ if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+ else
+ return -1;
+ }
+ total += ret;
+ }
+ return (ssize_t)total;
+}
+
+/****************************************************************************
+ Write data to a fd on the vfs.
+****************************************************************************/
+
+ssize_t vfs_write_data(struct smb_request *req,
+ files_struct *fsp,
+ const char *buffer,
+ size_t N)
+{
+ size_t total=0;
+ ssize_t ret;
+
+ if (req && req->unread_bytes) {
+ SMB_ASSERT(req->unread_bytes == N);
+ /* VFS_RECVFILE must drain the socket
+ * before returning. */
+ req->unread_bytes = 0;
+ return SMB_VFS_RECVFILE(smbd_server_fd(),
+ fsp,
+ (SMB_OFF_T)-1,
+ N);
+ }
+
+ while (total < N) {
+ ret = SMB_VFS_WRITE(fsp, buffer + total, N - total);
+
+ if (ret == -1)
+ return -1;
+ if (ret == 0)
+ return total;
+
+ total += ret;
+ }
+ return (ssize_t)total;
+}
+
+ssize_t vfs_pwrite_data(struct smb_request *req,
+ files_struct *fsp,
+ const char *buffer,
+ size_t N,
+ SMB_OFF_T offset)
+{
+ size_t total=0;
+ ssize_t ret;
+
+ if (req && req->unread_bytes) {
+ SMB_ASSERT(req->unread_bytes == N);
+ /* VFS_RECVFILE must drain the socket
+ * before returning. */
+ req->unread_bytes = 0;
+ return SMB_VFS_RECVFILE(smbd_server_fd(),
+ fsp,
+ offset,
+ N);
+ }
+
+ while (total < N) {
+ ret = SMB_VFS_PWRITE(fsp, buffer + total, N - total,
+ offset + total);
+
+ if (ret == -1)
+ return -1;
+ if (ret == 0)
+ return total;
+
+ total += ret;
+ }
+ return (ssize_t)total;
+}
+/****************************************************************************
+ An allocate file space call using the vfs interface.
+ Allocates space for a file from a filedescriptor.
+ Returns 0 on success, -1 on failure.
+****************************************************************************/
+
+int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
+{
+ int ret;
+ SMB_STRUCT_STAT st;
+ connection_struct *conn = fsp->conn;
+ SMB_BIG_UINT space_avail;
+ SMB_BIG_UINT bsize,dfree,dsize;
+
+ release_level_2_oplocks_on_change(fsp);
+
+ /*
+ * Actually try and commit the space on disk....
+ */
+
+ DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
+
+ if (((SMB_OFF_T)len) < 0) {
+ DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = SMB_VFS_FSTAT(fsp, &st);
+ if (ret == -1)
+ return ret;
+
+ if (len == (SMB_BIG_UINT)st.st_size)
+ return 0;
+
+ if (len < (SMB_BIG_UINT)st.st_size) {
+ /* Shrink - use ftruncate. */
+
+ DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
+ fsp->fsp_name, (double)st.st_size ));
+
+ flush_write_cache(fsp, SIZECHANGE_FLUSH);
+ if ((ret = SMB_VFS_FTRUNCATE(fsp, (SMB_OFF_T)len)) != -1) {
+ set_filelen_write_cache(fsp, len);
+ }
+ return ret;
+ }
+
+ /* Grow - we need to test if we have enough space. */
+
+ if (!lp_strict_allocate(SNUM(fsp->conn)))
+ return 0;
+
+ len -= st.st_size;
+ len /= 1024; /* Len is now number of 1k blocks needed. */
+ space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
+ if (space_avail == (SMB_BIG_UINT)-1) {
+ return -1;
+ }
+
+ DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
+ fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
+
+ if (len > space_avail) {
+ errno = ENOSPC;
+ return -1;
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ A vfs set_filelen call.
+ set the length of a file from a filedescriptor.
+ Returns 0 on success, -1 on failure.
+****************************************************************************/
+
+int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
+{
+ int ret;
+
+ release_level_2_oplocks_on_change(fsp);
+ DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
+ flush_write_cache(fsp, SIZECHANGE_FLUSH);
+ if ((ret = SMB_VFS_FTRUNCATE(fsp, len)) != -1) {
+ set_filelen_write_cache(fsp, len);
+ notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_SIZE
+ | FILE_NOTIFY_CHANGE_ATTRIBUTES,
+ fsp->fsp_name);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ A vfs fill sparse call.
+ Writes zeros from the end of file to len, if len is greater than EOF.
+ Used only by strict_sync.
+ Returns 0 on success, -1 on failure.
+****************************************************************************/
+
+static char *sparse_buf;
+#define SPARSE_BUF_WRITE_SIZE (32*1024)
+
+int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
+{
+ int ret;
+ SMB_STRUCT_STAT st;
+ SMB_OFF_T offset;
+ size_t total;
+ size_t num_to_write;
+ ssize_t pwrite_ret;
+
+ release_level_2_oplocks_on_change(fsp);
+ ret = SMB_VFS_FSTAT(fsp, &st);
+ if (ret == -1) {
+ return ret;
+ }
+
+ if (len <= st.st_size) {
+ return 0;
+ }
+
+ DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
+ fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
+
+ flush_write_cache(fsp, SIZECHANGE_FLUSH);
+
+ if (!sparse_buf) {
+ sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
+ if (!sparse_buf) {
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+
+ offset = st.st_size;
+ num_to_write = len - st.st_size;
+ total = 0;
+
+ while (total < num_to_write) {
+ size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
+
+ pwrite_ret = SMB_VFS_PWRITE(fsp, sparse_buf, curr_write_size, offset + total);
+ if (pwrite_ret == -1) {
+ DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
+ fsp->fsp_name, strerror(errno) ));
+ return -1;
+ }
+ if (pwrite_ret == 0) {
+ return 0;
+ }
+
+ total += pwrite_ret;
+ }
+
+ set_filelen_write_cache(fsp, len);
+ return 0;
+}
+
+/****************************************************************************
+ Transfer some data (n bytes) between two file_struct's.
+****************************************************************************/
+
+static ssize_t vfs_read_fn(void *file, void *buf, size_t len)
+{
+ struct files_struct *fsp = (struct files_struct *)file;
+
+ return SMB_VFS_READ(fsp, buf, len);
+}
+
+static ssize_t vfs_write_fn(void *file, const void *buf, size_t len)
+{
+ struct files_struct *fsp = (struct files_struct *)file;
+
+ return SMB_VFS_WRITE(fsp, buf, len);
+}
+
+SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
+{
+ return transfer_file_internal((void *)in, (void *)out, n,
+ vfs_read_fn, vfs_write_fn);
+}
+
+/*******************************************************************
+ A vfs_readdir wrapper which just returns the file name.
+********************************************************************/
+
+char *vfs_readdirname(connection_struct *conn, void *p)
+{
+ SMB_STRUCT_DIRENT *ptr= NULL;
+ char *dname;
+
+ if (!p)
+ return(NULL);
+
+ ptr = SMB_VFS_READDIR(conn, (DIR *)p);
+ if (!ptr)
+ return(NULL);
+
+ dname = ptr->d_name;
+
+#ifdef NEXT2
+ if (telldir(p) < 0)
+ return(NULL);
+#endif
+
+#ifdef HAVE_BROKEN_READDIR_NAME
+ /* using /usr/ucb/cc is BAD */
+ dname = dname - 2;
+#endif
+
+ return(dname);
+}
+
+/*******************************************************************
+ A wrapper for vfs_chdir().
+********************************************************************/
+
+int vfs_ChDir(connection_struct *conn, const char *path)
+{
+ int res;
+ static char *LastDir = NULL;
+
+ if (!LastDir) {
+ LastDir = SMB_STRDUP("");
+ }
+
+ if (strcsequal(path,"."))
+ return(0);
+
+ if (*path == '/' && strcsequal(LastDir,path))
+ return(0);
+
+ DEBUG(4,("vfs_ChDir to %s\n",path));
+
+ res = SMB_VFS_CHDIR(conn,path);
+ if (!res) {
+ SAFE_FREE(LastDir);
+ LastDir = SMB_STRDUP(path);
+ }
+ return(res);
+}
+
+/*******************************************************************
+ Return the absolute current directory path - given a UNIX pathname.
+ Note that this path is returned in DOS format, not UNIX
+ format. Note this can be called with conn == NULL.
+********************************************************************/
+
+struct getwd_cache_key {
+ SMB_DEV_T dev;
+ SMB_INO_T ino;
+};
+
+char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
+{
+ char s[PATH_MAX+1];
+ SMB_STRUCT_STAT st, st2;
+ char *result;
+ DATA_BLOB cache_value;
+ struct getwd_cache_key key;
+
+ *s = 0;
+
+ if (!lp_getwd_cache()) {
+ goto nocache;
+ }
+
+ SET_STAT_INVALID(st);
+
+ if (SMB_VFS_STAT(conn, ".",&st) == -1) {
+ /*
+ * Known to fail for root: the directory may be NFS-mounted
+ * and exported with root_squash (so has no root access).
+ */
+ DEBUG(1,("vfs_GetWd: couldn't stat \".\" error %s "
+ "(NFS problem ?)\n", strerror(errno) ));
+ goto nocache;
+ }
+
+ ZERO_STRUCT(key); /* unlikely, but possible padding */
+ key.dev = st.st_dev;
+ key.ino = st.st_ino;
+
+ if (!memcache_lookup(smbd_memcache(), GETWD_CACHE,
+ data_blob_const(&key, sizeof(key)),
+ &cache_value)) {
+ goto nocache;
+ }
+
+ SMB_ASSERT((cache_value.length > 0)
+ && (cache_value.data[cache_value.length-1] == '\0'));
+
+ if ((SMB_VFS_STAT(conn, (char *)cache_value.data, &st2) == 0)
+ && (st.st_dev == st2.st_dev) && (st.st_ino == st2.st_ino)
+ && (S_ISDIR(st.st_mode))) {
+ /*
+ * Ok, we're done
+ */
+ result = talloc_strdup(ctx, (char *)cache_value.data);
+ if (result == NULL) {
+ errno = ENOMEM;
+ }
+ return result;
+ }
+
+ nocache:
+
+ /*
+ * 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 (!SMB_VFS_GETWD(conn,s)) {
+ DEBUG(0, ("vfs_GetWd: SMB_VFS_GETWD call failed: %s\n",
+ strerror(errno)));
+ return NULL;
+ }
+
+ if (lp_getwd_cache() && VALID_STAT(st)) {
+ ZERO_STRUCT(key); /* unlikely, but possible padding */
+ key.dev = st.st_dev;
+ key.ino = st.st_ino;
+
+ memcache_add(smbd_memcache(), GETWD_CACHE,
+ data_blob_const(&key, sizeof(key)),
+ data_blob_const(s, strlen(s)+1));
+ }
+
+ result = talloc_strdup(ctx, s);
+ if (result == NULL) {
+ errno = ENOMEM;
+ }
+ return result;
+}
+
+/*******************************************************************
+ Reduce a file name, removing .. elements and checking that
+ it is below dir in the heirachy. This uses realpath.
+********************************************************************/
+
+NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
+{
+#ifdef REALPATH_TAKES_NULL
+ bool free_resolved_name = True;
+#else
+ char resolved_name_buf[PATH_MAX+1];
+ bool free_resolved_name = False;
+#endif
+ char *resolved_name = NULL;
+ size_t con_path_len = strlen(conn->connectpath);
+ char *p = NULL;
+
+ DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
+
+#ifdef REALPATH_TAKES_NULL
+ resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
+#else
+ resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
+#endif
+
+ if (!resolved_name) {
+ switch (errno) {
+ case ENOTDIR:
+ DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
+ return map_nt_error_from_unix(errno);
+ case ENOENT:
+ {
+ TALLOC_CTX *ctx = talloc_tos();
+ char *tmp_fname = NULL;
+ char *last_component = NULL;
+ /* Last component didn't exist. Remove it and try and canonicalise the directory. */
+
+ tmp_fname = talloc_strdup(ctx, fname);
+ if (!tmp_fname) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ p = strrchr_m(tmp_fname, '/');
+ if (p) {
+ *p++ = '\0';
+ last_component = p;
+ } else {
+ last_component = tmp_fname;
+ tmp_fname = talloc_strdup(ctx,
+ ".");
+ if (!tmp_fname) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+#ifdef REALPATH_TAKES_NULL
+ resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
+#else
+ resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
+#endif
+ if (!resolved_name) {
+ DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
+ return map_nt_error_from_unix(errno);
+ }
+ tmp_fname = talloc_asprintf(ctx,
+ "%s/%s",
+ resolved_name,
+ last_component);
+ if (!tmp_fname) {
+ return NT_STATUS_NO_MEMORY;
+ }
+#ifdef REALPATH_TAKES_NULL
+ SAFE_FREE(resolved_name);
+ resolved_name = SMB_STRDUP(tmp_fname);
+ if (!resolved_name) {
+ DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
+ return NT_STATUS_NO_MEMORY;
+ }
+#else
+ safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
+ resolved_name = resolved_name_buf;
+#endif
+ break;
+ }
+ default:
+ DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
+ return map_nt_error_from_unix(errno);
+ }
+ }
+
+ DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
+
+ if (*resolved_name != '/') {
+ DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
+ if (free_resolved_name) {
+ SAFE_FREE(resolved_name);
+ }
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+
+ /* Check for widelinks allowed. */
+ if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
+ DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
+ if (free_resolved_name) {
+ SAFE_FREE(resolved_name);
+ }
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* 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 ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
+ (S_ISLNK(statbuf.st_mode)) ) {
+ if (free_resolved_name) {
+ SAFE_FREE(resolved_name);
+ }
+ DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+#endif
+
+ DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
+ if (free_resolved_name) {
+ SAFE_FREE(resolved_name);
+ }
+ return NT_STATUS_OK;
+}
diff --git a/source3/stf/README.stf b/source3/stf/README.stf
new file mode 100644
index 0000000000..3fbd33cb6c
--- /dev/null
+++ b/source3/stf/README.stf
@@ -0,0 +1,3 @@
+This directory contains the Samba Testing Framework, a Python-based
+system for exercising Samba in various ways. It is quite small at the
+moment.
diff --git a/source3/stf/comfychair.py b/source3/stf/comfychair.py
new file mode 100644
index 0000000000..247915d7e9
--- /dev/null
+++ b/source3/stf/comfychair.py
@@ -0,0 +1,443 @@
+#! /usr/bin/env python
+
+# Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org>
+# Copyright (C) 2003 by Tim Potter <tpot@samba.org>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+"""comfychair: a Python-based instrument of software torture.
+
+Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org>
+Copyright (C) 2003 by Tim Potter <tpot@samba.org>
+
+This is a test framework designed for testing programs written in
+Python, or (through a fork/exec interface) any other language.
+
+For more information, see the file README.comfychair.
+
+To run a test suite based on ComfyChair, just run it as a program.
+"""
+
+import sys, re
+
+
+class TestCase:
+ """A base class for tests. This class defines required functions which
+ can optionally be overridden by subclasses. It also provides some
+ utility functions for"""
+
+ def __init__(self):
+ self.test_log = ""
+ self.background_pids = []
+ self._cleanups = []
+ self._enter_rundir()
+ self._save_environment()
+ self.add_cleanup(self.teardown)
+
+
+ # --------------------------------------------------
+ # Save and restore directory
+ def _enter_rundir(self):
+ import os
+ self.basedir = os.getcwd()
+ self.add_cleanup(self._restore_directory)
+ self.rundir = os.path.join(self.basedir,
+ 'testtmp',
+ self.__class__.__name__)
+ self.tmpdir = os.path.join(self.rundir, 'tmp')
+ os.system("rm -fr %s" % self.rundir)
+ os.makedirs(self.tmpdir)
+ os.system("mkdir -p %s" % self.rundir)
+ os.chdir(self.rundir)
+
+ def _restore_directory(self):
+ import os
+ os.chdir(self.basedir)
+
+ # --------------------------------------------------
+ # Save and restore environment
+ def _save_environment(self):
+ import os
+ self._saved_environ = os.environ.copy()
+ self.add_cleanup(self._restore_environment)
+
+ def _restore_environment(self):
+ import os
+ os.environ.clear()
+ os.environ.update(self._saved_environ)
+
+
+ def setup(self):
+ """Set up test fixture."""
+ pass
+
+ def teardown(self):
+ """Tear down test fixture."""
+ pass
+
+ def runtest(self):
+ """Run the test."""
+ pass
+
+
+ def add_cleanup(self, c):
+ """Queue a cleanup to be run when the test is complete."""
+ self._cleanups.append(c)
+
+
+ def fail(self, reason = ""):
+ """Say the test failed."""
+ raise AssertionError(reason)
+
+
+ #############################################################
+ # Requisition methods
+
+ def require(self, predicate, message):
+ """Check a predicate for running this test.
+
+If the predicate value is not true, the test is skipped with a message explaining
+why."""
+ if not predicate:
+ raise NotRunError, message
+
+ def require_root(self):
+ """Skip this test unless run by root."""
+ import os
+ self.require(os.getuid() == 0,
+ "must be root to run this test")
+
+ #############################################################
+ # Assertion methods
+
+ def assert_(self, expr, reason = ""):
+ if not expr:
+ raise AssertionError(reason)
+
+ def assert_equal(self, a, b):
+ if not a == b:
+ raise AssertionError("assertEquals failed: %s" % `(a, b)`)
+
+ def assert_notequal(self, a, b):
+ if a == b:
+ raise AssertionError("assertNotEqual failed: %s" % `(a, b)`)
+
+ def assert_re_match(self, pattern, s):
+ """Assert that a string matches a particular pattern
+
+ Inputs:
+ pattern string: regular expression
+ s string: to be matched
+
+ Raises:
+ AssertionError if not matched
+ """
+ if not re.match(pattern, s):
+ raise AssertionError("string does not match regexp\n"
+ " string: %s\n"
+ " re: %s" % (`s`, `pattern`))
+
+ def assert_re_search(self, pattern, s):
+ """Assert that a string *contains* a particular pattern
+
+ Inputs:
+ pattern string: regular expression
+ s string: to be searched
+
+ Raises:
+ AssertionError if not matched
+ """
+ if not re.search(pattern, s):
+ raise AssertionError("string does not contain regexp\n"
+ " string: %s\n"
+ " re: %s" % (`s`, `pattern`))
+
+
+ def assert_no_file(self, filename):
+ import os.path
+ assert not os.path.exists(filename), ("file exists but should not: %s" % filename)
+
+
+ #############################################################
+ # Methods for running programs
+
+ def runcmd_background(self, cmd):
+ import os
+ self.test_log = self.test_log + "Run in background:\n" + `cmd` + "\n"
+ pid = os.fork()
+ if pid == 0:
+ # child
+ try:
+ os.execvp("/bin/sh", ["/bin/sh", "-c", cmd])
+ finally:
+ os._exit(127)
+ self.test_log = self.test_log + "pid: %d\n" % pid
+ return pid
+
+
+ def runcmd(self, cmd, expectedResult = 0):
+ """Run a command, fail if the command returns an unexpected exit
+ code. Return the output produced."""
+ rc, output, stderr = self.runcmd_unchecked(cmd)
+ if rc != expectedResult:
+ raise AssertionError("""command returned %d; expected %s: \"%s\"
+stdout:
+%s
+stderr:
+%s""" % (rc, expectedResult, cmd, output, stderr))
+
+ return output, stderr
+
+
+ def run_captured(self, cmd):
+ """Run a command, capturing stdout and stderr.
+
+ Based in part on popen2.py
+
+ Returns (waitstatus, stdout, stderr)."""
+ import os, types
+ pid = os.fork()
+ if pid == 0:
+ # child
+ try:
+ pid = os.getpid()
+ openmode = os.O_WRONLY|os.O_CREAT|os.O_TRUNC
+
+ outfd = os.open('%d.out' % pid, openmode, 0666)
+ os.dup2(outfd, 1)
+ os.close(outfd)
+
+ errfd = os.open('%d.err' % pid, openmode, 0666)
+ os.dup2(errfd, 2)
+ os.close(errfd)
+
+ if isinstance(cmd, types.StringType):
+ cmd = ['/bin/sh', '-c', cmd]
+
+ os.execvp(cmd[0], cmd)
+ finally:
+ os._exit(127)
+ else:
+ # parent
+ exited_pid, waitstatus = os.waitpid(pid, 0)
+ stdout = open('%d.out' % pid).read()
+ stderr = open('%d.err' % pid).read()
+ return waitstatus, stdout, stderr
+
+
+ def runcmd_unchecked(self, cmd, skip_on_noexec = 0):
+ """Invoke a command; return (exitcode, stdout, stderr)"""
+ import os
+ waitstatus, stdout, stderr = self.run_captured(cmd)
+ assert not os.WIFSIGNALED(waitstatus), \
+ ("%s terminated with signal %d" % (`cmd`, os.WTERMSIG(waitstatus)))
+ rc = os.WEXITSTATUS(waitstatus)
+ self.test_log = self.test_log + ("""Run command: %s
+Wait status: %#x (exit code %d, signal %d)
+stdout:
+%s
+stderr:
+%s""" % (cmd, waitstatus, os.WEXITSTATUS(waitstatus), os.WTERMSIG(waitstatus),
+ stdout, stderr))
+ if skip_on_noexec and rc == 127:
+ # Either we could not execute the command or the command
+ # returned exit code 127. According to system(3) we can't
+ # tell the difference.
+ raise NotRunError, "could not execute %s" % `cmd`
+ return rc, stdout, stderr
+
+
+ def explain_failure(self, exc_info = None):
+ print "test_log:"
+ print self.test_log
+
+
+ def log(self, msg):
+ """Log a message to the test log. This message is displayed if
+ the test fails, or when the runtests function is invoked with
+ the verbose option."""
+ self.test_log = self.test_log + msg + "\n"
+
+
+class NotRunError(Exception):
+ """Raised if a test must be skipped because of missing resources"""
+ def __init__(self, value = None):
+ self.value = value
+
+
+def _report_error(case, debugger):
+ """Ask the test case to explain failure, and optionally run a debugger
+
+ Input:
+ case TestCase instance
+ debugger if true, a debugger function to be applied to the traceback
+"""
+ import sys
+ ex = sys.exc_info()
+ print "-----------------------------------------------------------------"
+ if ex:
+ import traceback
+ traceback.print_exc(file=sys.stdout)
+ case.explain_failure()
+ print "-----------------------------------------------------------------"
+
+ if debugger:
+ tb = ex[2]
+ debugger(tb)
+
+
+def runtests(test_list, verbose = 0, debugger = None):
+ """Run a series of tests.
+
+ Inputs:
+ test_list sequence of TestCase classes
+ verbose print more information as testing proceeds
+ debugger debugger object to be applied to errors
+
+ Returns:
+ unix return code: 0 for success, 1 for failures, 2 for test failure
+ """
+ import traceback
+ ret = 0
+ for test_class in test_list:
+ print "%-30s" % _test_name(test_class),
+ # flush now so that long running tests are easier to follow
+ sys.stdout.flush()
+
+ obj = None
+ try:
+ try: # run test and show result
+ obj = test_class()
+ obj.setup()
+ obj.runtest()
+ print "OK"
+ except KeyboardInterrupt:
+ print "INTERRUPT"
+ _report_error(obj, debugger)
+ ret = 2
+ break
+ except NotRunError, msg:
+ print "NOTRUN, %s" % msg.value
+ except:
+ print "FAIL"
+ _report_error(obj, debugger)
+ ret = 1
+ finally:
+ while obj and obj._cleanups:
+ try:
+ apply(obj._cleanups.pop())
+ except KeyboardInterrupt:
+ print "interrupted during teardown"
+ _report_error(obj, debugger)
+ ret = 2
+ break
+ except:
+ print "error during teardown"
+ _report_error(obj, debugger)
+ ret = 1
+ # Display log file if we're verbose
+ if ret == 0 and verbose:
+ obj.explain_failure()
+
+ return ret
+
+
+def _test_name(test_class):
+ """Return a human-readable name for a test class.
+ """
+ try:
+ return test_class.__name__
+ except:
+ return `test_class`
+
+
+def print_help():
+ """Help for people running tests"""
+ import sys
+ print """%s: software test suite based on ComfyChair
+
+usage:
+ To run all tests, just run this program. To run particular tests,
+ list them on the command line.
+
+options:
+ --help show usage message
+ --list list available tests
+ --verbose, -v show more information while running tests
+ --post-mortem, -p enter Python debugger on error
+""" % sys.argv[0]
+
+
+def print_list(test_list):
+ """Show list of available tests"""
+ for test_class in test_list:
+ print " %s" % _test_name(test_class)
+
+
+def main(tests, extra_tests=[]):
+ """Main entry point for test suites based on ComfyChair.
+
+ inputs:
+ tests Sequence of TestCase subclasses to be run by default.
+ extra_tests Sequence of TestCase subclasses that are available but
+ not run by default.
+
+Test suites should contain this boilerplate:
+
+ if __name__ == '__main__':
+ comfychair.main(tests)
+
+This function handles standard options such as --help and --list, and
+by default runs all tests in the suggested order.
+
+Calls sys.exit() on completion.
+"""
+ from sys import argv
+ import getopt, sys
+
+ opt_verbose = 0
+ debugger = None
+
+ opts, args = getopt.getopt(argv[1:], 'pv',
+ ['help', 'list', 'verbose', 'post-mortem'])
+ for opt, opt_arg in opts:
+ if opt == '--help':
+ print_help()
+ return
+ elif opt == '--list':
+ print_list(tests + extra_tests)
+ return
+ elif opt == '--verbose' or opt == '-v':
+ opt_verbose = 1
+ elif opt == '--post-mortem' or opt == '-p':
+ import pdb
+ debugger = pdb.post_mortem
+
+ if args:
+ all_tests = tests + extra_tests
+ by_name = {}
+ for t in all_tests:
+ by_name[_test_name(t)] = t
+ which_tests = []
+ for name in args:
+ which_tests.append(by_name[name])
+ else:
+ which_tests = tests
+
+ sys.exit(runtests(which_tests, verbose=opt_verbose,
+ debugger=debugger))
+
+
+if __name__ == '__main__':
+ print __doc__
diff --git a/source3/stf/example.py b/source3/stf/example.py
new file mode 100755
index 0000000000..9c97cb7a20
--- /dev/null
+++ b/source3/stf/example.py
@@ -0,0 +1,36 @@
+#! /usr/bin/env python
+
+# Copyright (C) 2003 by Martin Pool <mbp@samba.org>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+
+"""example of using ComfyChair"""
+
+import comfychair
+
+class OnePlusOne(comfychair.TestCase):
+ def runtest(self):
+ self.assert_(1 + 1 == 2)
+
+class FailTest(comfychair.TestCase):
+ def runtest(self):
+ self.assert_(1 + 1 == 3)
+
+tests = [OnePlusOne]
+extra_tests = [FailTest]
+
+if __name__ == '__main__':
+ comfychair.main(tests, extra_tests=extra_tests)
+
diff --git a/source3/stf/info3cache.py b/source3/stf/info3cache.py
new file mode 100755
index 0000000000..96d5a1d459
--- /dev/null
+++ b/source3/stf/info3cache.py
@@ -0,0 +1,54 @@
+#!/usr/bin/python
+#
+# Upon a winbindd authentication, test that an info3 record is cached in
+# netsamlogon_cache.tdb and cache records are removed from winbindd_cache.tdb
+#
+
+import comfychair, stf
+from samba import tdb, winbind
+
+#
+# We want to implement the following test on a win2k native mode domain.
+#
+# 1. trash netsamlogon_cache.tdb
+# 2. wbinfo -r DOMAIN\Administrator [FAIL]
+# 3. wbinfo --auth-crap DOMAIN\Administrator%password [PASS]
+# 4. wbinfo -r DOMAIN\Administrator [PASS]
+#
+# Also for step 3 we want to try 'wbinfo --auth-smbd' and
+# 'wbinfo --auth-plaintext'
+#
+
+#
+# TODO: To implement this test we need to be able to
+#
+# - pass username%password combination for an invidivual winbindd request
+# (so we can get the administrator SID so we can clear the info3 cache)
+#
+# - start/restart winbindd (to trash the winbind cache)
+#
+# - from samba import dynconfig (to find location of info3 cache)
+#
+# - be able to modify the winbindd cache (to set/reset individual winbind
+# cache entries)
+#
+# - have --auth-crap present in HEAD
+#
+
+class WinbindAuthCrap(comfychair.TestCase):
+ def runtest(self):
+ raise comfychair.NotRunError, "not implemented"
+
+class WinbindAuthSmbd(comfychair.TestCase):
+ def runtest(self):
+ # Grr - winbindd in HEAD doesn't contain the auth_smbd function
+ raise comfychair.NotRunError, "no auth_smbd in HEAD"
+
+class WinbindAuthPlaintext(comfychair.TestCase):
+ def runtest(self):
+ raise comfychair.NotRunError, "not implemented"
+
+tests = [WinbindAuthCrap, WinbindAuthSmbd, WinbindAuthPlaintext]
+
+if __name__ == "__main__":
+ comfychair.main(tests)
diff --git a/source3/stf/notes.txt b/source3/stf/notes.txt
new file mode 100644
index 0000000000..68aca63c23
--- /dev/null
+++ b/source3/stf/notes.txt
@@ -0,0 +1,175 @@
+ -*- indented-text -*-
+
+(set lotus no)
+
+
+
+Notes on using comfychair with Samba (samba testing framework units):
+
+The tests need to rely on some external resources, such as
+
+If suitable resources are not available, need to skip particular
+tests. Must include a message indicating what resources would be
+needed to run that test. (e.g. must be root.)
+
+We want to be able to select and run particular subsets of tests, such
+as "all winbind tests".
+
+We want to keep the number of configurable parameters down as much as
+possible, to make it easy on people running the tests.
+
+Wherever possible, the tests should set up their preconditions, but a
+few basic resources need to be provided by the people running the
+tests. So for example, rather than asking the user for the name of a
+non-root user, we should give the tests the administrator name and
+password, and it can create a new user to use.
+
+This makes it simpler to get the tests running, and possible also
+makes them more reproducible.
+
+In the future, rather than using NT machines provided by the test
+person, we might have a way to drive VMWare non-persistent sessions,
+to make tests even more tightly controlled.
+
+
+Another design question is how to communicate this information to the
+tests. If there's a lot of settings, then it might need to be stored
+in a configuration file.
+
+However, if we succeed in cutting down the number of parameters, then
+it might be straightforward to pass the information on the command
+line or in an environment variable.
+
+Environment variables are probably better because they can't be seen
+by other users, and they are more easily passed down through an
+invocation of "make check".
+
+
+
+Notes on Samba Testing Framework for Unittests
+----------------------------------------------
+
+This is to be read after reading the notes.txt from comfychair. I'm
+proposing a slightly more concrete description of what's described
+there.
+
+The model of having tests require named resources looks useful for
+incorporation into a framework that can be run by many people in
+widely different environments.
+
+Some possible environments for running the test framework in are:
+
+ - Casual downloader of Samba compiling from source and just wants
+ to run 'make check'. May only have one Unix machine and a
+ handful of clients.
+
+ - Samba team member with access to a small number of other
+ machines or VMware sessions.
+
+ - PSA developer who may not have intimate knowledge of Samba
+ internals and is only interested in testing against the PSA.
+
+ - Non-team hacker wanting to run test suite after making small
+ hacks.
+
+ - Build farm environment (loaner machine with no physical access
+ or root privilege).
+
+ - HP BAT.
+
+Developers in most of these environments are also potential test case
+authors. It should be easy for people unfamiliar with the framework
+to write new tests and have them work. We should provide examples and
+the existing tests should well written and understandable.
+
+Different types of tests:
+
+ - Tests that check Samba internals and link against
+ libbigballofmud.so. For example:
+
+ - Upper/lowercase string functions
+ - user_in_list() for large lists
+
+ - Tests that use the Samba Python extensions.
+
+ - Tests that execute Samba command line programs, for example
+ smbpasswd.
+
+ - Tests that require other resources on the network such as domain
+ controllers or PSAs.
+
+ - Tests that are performed on the documentation or the source code
+ such as:
+
+ - grep for common spelling mistakes made by abartlet (-:
+ - grep for company copyright (IBM, HP)
+
+ - Link to other existing testing frameworks (smbtorture,
+ abartlet's bash based build farm tests)
+
+I propose a TestResourceManager which would be instantiated by a test
+case. The test case would require("resourcename") as part of its
+constructor and raise a comfychair.NotRun exception if the resource
+was not present. A TestResource class could be defined which could
+read a configuration file or examine a environment variable and
+register a resource only if some condition was satisfied.
+
+It would be nice to be able to completely separate the PSA testing
+from the test framework. This would entail being able to define test
+resources dynamically, possibly with a plugin type system.
+
+class TestResourceManager:
+ def __init__(self, name):
+ self.resources = {}
+
+ def register(self, resource):
+ name = resource.name()
+ if self.resources.has_key(name):
+ raise "Test manager already has resource %s" % name
+ self.resources[name] = resource
+
+ def require(self, resource_name):
+ if not self.resources.has_key(resource_name):
+ raise "Test manager does not have resources %s" % resource_name
+
+class TestResource:
+ def __init__(self, name):
+ self.name = name
+
+ def name(self):
+ return self.name
+
+import os
+
+trm = TestResourceManager()
+
+if os.getuid() == 0:
+ trm.register(TestResource("root"))
+
+A config-o-matic Python module can take a list of machines and
+administrator%password entries and classify them by operating system
+version and service pack. These resources would be registered with
+the TestResourceManager.
+
+Some random thoughts about named resources for network servers:
+
+require("nt4.sp3")
+require("nt4.domaincontroller")
+require("psa")
+
+Some kind of format for location of passwords, libraries:
+
+require("exec(smbpasswd)")
+require("lib(bigballofmud)")
+
+maybe require("exec.smbpasswd") looks nicer...
+
+The require() function could return a dictionary of configuration
+information or some handle to fetch dynamic information on. We may
+need to create and destroy extra users or print queues. How to manage
+cleanup of dynamic resources?
+
+Requirements for running stf:
+
+ - Python, obviously
+ - Samba python extensions
diff --git a/source3/stf/osver.py b/source3/stf/osver.py
new file mode 100755
index 0000000000..68601fa7bb
--- /dev/null
+++ b/source3/stf/osver.py
@@ -0,0 +1,55 @@
+#!/usr/bin/python
+#
+# Utilities for determining the Windows operating system version remotely.
+#
+
+from samba import srvsvc
+
+# Constants
+
+PLATFORM_UNKNOWN = 0
+PLATFORM_WIN9X = 1
+PLATFORM_NT4 = 2
+PLATFORM_NT5 = 3 # Windows 2000
+
+def platform_name(platform_type):
+
+ platform_names = { PLATFORM_UNKNOWN: "Unknown",
+ PLATFORM_WIN9X: "Windows 9x",
+ PLATFORM_NT4: "Windows NT",
+ PLATFORM_NT5: "Windows 2000" }
+
+ if platform_names.has_key(platform_type):
+ return platform_names[platform_type]
+
+ return "Unknown"
+
+def platform_type(info101):
+ """Determine the operating system type from a SRV_INFO_101."""
+
+ if info101['major_version'] == 4 and info101['minor_version'] == 0:
+ return PLATFORM_NT4
+
+ if info101['major_version'] == 5 and info101['minor_version'] == 0:
+ return PLATFORM_NT5
+
+ return PLATFORM_UNKNOWN
+
+def is_domain_controller(info101):
+ """Return true if the server_type field from a SRV_INFO_101
+ indicates a domain controller."""
+ return info101['server_type'] & srvsvc.SV_TYPE_DOMAIN_CTRL
+
+def os_version(name):
+ info = srvsvc.netservergetinfo("\\\\%s" % name, 101)
+ return platform_type(info)
+
+if __name__ == "__main__":
+ import sys
+ if len(sys.argv) != 2:
+ print "Usage: osver.py server"
+ sys.exit(0)
+ info = srvsvc.netservergetinfo("\\\\%s" % sys.argv[1], 101)
+ print "platform type = %d" % platform_type(info)
+ if is_domain_controller(info):
+ print "%s is a domain controller" % sys.argv[1]
diff --git a/source3/stf/pythoncheck.py b/source3/stf/pythoncheck.py
new file mode 100755
index 0000000000..a13f1b3d5c
--- /dev/null
+++ b/source3/stf/pythoncheck.py
@@ -0,0 +1,46 @@
+#! /usr/bin/python
+
+# Comfychair test cases for Samba python extensions
+
+# Copyright (C) 2003 by Tim Potter <tpot@samba.org>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+"""These tests are run by Samba's "make check"."""
+
+import sys, comfychair
+
+class ImportTest(comfychair.TestCase):
+ """Check that all modules can be imported without error."""
+ def runtest(self):
+ python_modules = ['spoolss', 'lsa', 'samr', 'winbind', 'winreg',
+ 'srvsvc', 'tdb', 'smb', 'tdbpack']
+ for m in python_modules:
+ try:
+ __import__('samba.%s' % m)
+ except ImportError, msg:
+ self.log(str(msg))
+ self.fail('error importing %s module' % m)
+
+tests = [ImportTest]
+
+if __name__ == '__main__':
+ # Some magic to repend build directory to python path so we see the
+ # objects we have built and not previously installed stuff.
+ from distutils.util import get_platform
+ from os import getcwd
+ sys.path.insert(0, '%s/build/lib.%s-%s' %
+ (getcwd(), get_platform(), sys.version[0:3]))
+
+ comfychair.main(tests)
diff --git a/source3/stf/sambalib.py b/source3/stf/sambalib.py
new file mode 100644
index 0000000000..552280ed29
--- /dev/null
+++ b/source3/stf/sambalib.py
@@ -0,0 +1,39 @@
+#! /usr/bin/python
+
+# Comfychair test cases for Samba string functions.
+
+# Copyright (C) 2003 by Martin Pool <mbp@samba.org>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+"""Tests for Samba library functions."""
+
+import sys, re, comfychair
+from unicodenames import *
+
+class snprintf_Test(comfychair.TestCase):
+ def runtest(self):
+ # Everything is built in to the test
+ out, err = self.runcmd('t_snprintf')
+
+# Define the tests exported by this module
+tests = [snprintf_Test]
+
+# Handle execution of this file as a main program
+if __name__ == '__main__':
+ comfychair.main(tests)
+
+# Local variables:
+# coding: utf-8
+# End:
diff --git a/source3/stf/smbcontrol.py b/source3/stf/smbcontrol.py
new file mode 100755
index 0000000000..30c331819c
--- /dev/null
+++ b/source3/stf/smbcontrol.py
@@ -0,0 +1,238 @@
+#!/usr/bin/python
+#
+# Test for smbcontrol command line argument handling.
+#
+
+import comfychair
+
+class NoArgs(comfychair.TestCase):
+ """Test no arguments produces usage message."""
+ def runtest(self):
+ out = self.runcmd("smbcontrol", expectedResult = 1)
+ self.assert_re_match("Usage: smbcontrol", out[1])
+
+class OneArg(comfychair.TestCase):
+ """Test single argument produces usage message."""
+ def runtest(self):
+ out = self.runcmd("smbcontrol foo", expectedResult = 1)
+ self.assert_re_match("Usage: smbcontrol", out[1])
+
+class SmbdDest(comfychair.TestCase):
+ """Test the broadcast destination 'smbd'."""
+ def runtest(self):
+ out = self.runcmd("smbcontrol smbd noop")
+
+class NmbdDest(comfychair.TestCase):
+ """Test the destination 'nmbd'."""
+ def runtest(self):
+ # We need a way to start/stop/whatever nmbd
+ raise comfychair.NotRunError, "not implemented"
+
+class PidDest(comfychair.TestCase):
+ """Test a pid number destination'."""
+ def runtest(self):
+ out = self.runcmd("smbcontrol 1234 noop")
+
+class SelfDest(comfychair.TestCase):
+ """Test the destination 'self'."""
+ def runtest(self):
+ out = self.runcmd("smbcontrol self noop")
+
+class WinbinddDest(comfychair.TestCase):
+ """Test the destination 'winbindd'."""
+ def runtest(self):
+ # We need a way to start/stop/whatever winbindd
+ raise comfychair.NotRunError, "not implemented"
+
+class BadDest(comfychair.TestCase):
+ """Test a bad destination."""
+ def runtest(self):
+ out = self.runcmd("smbcontrol foo noop", expectedResult = 1)
+
+class BadCmd(comfychair.TestCase):
+ """Test a bad command."""
+ def runtest(self):
+ out = self.runcmd("smbcontrol self spottyfoot", expectedResult = 1)
+ self.assert_re_match("smbcontrol: unknown command", out[1]);
+
+class NoArgCmdTest(comfychair.TestCase):
+ """A test class that tests a command with no argument."""
+ def runtest(self):
+ self.require_root()
+ out = self.runcmd("smbcontrol self %s" % self.cmd)
+ out = self.runcmd("smbcontrol self %s spottyfoot" % self.cmd,
+ expectedResult = 1)
+
+class ForceElection(NoArgCmdTest):
+ """Test a force-election message."""
+ def setup(self):
+ self.cmd = "force-election"
+
+class SamSync(NoArgCmdTest):
+ """Test a samsync message."""
+ def setup(self):
+ self.cmd = "samsync"
+
+class SamRepl(NoArgCmdTest):
+ """Test a samrepl message."""
+ def setup(self):
+ self.cmd = "samrepl"
+
+class DmallocChanged(NoArgCmdTest):
+ """Test a dmalloc-changed message."""
+ def setup(self):
+ self.cmd = "dmalloc-log-changed"
+
+class DmallocMark(NoArgCmdTest):
+ """Test a dmalloc-mark message."""
+ def setup(self):
+ self.cmd = "dmalloc-mark"
+
+class Shutdown(NoArgCmdTest):
+ """Test a shutdown message."""
+ def setup(self):
+ self.cmd = "shutdown"
+
+class Ping(NoArgCmdTest):
+ """Test a ping message."""
+ def setup(self):
+ self.cmd = "ping"
+
+class Debuglevel(NoArgCmdTest):
+ """Test a debuglevel message."""
+ def setup(self):
+ self.cmd = "debuglevel"
+
+class OneArgCmdTest(comfychair.TestCase):
+ """A test class that tests a command with one argument."""
+ def runtest(self):
+ self.require_root()
+ out = self.runcmd("smbcontrol self %s spottyfoot" % self.cmd)
+ out = self.runcmd("smbcontrol self %s" % self.cmd, expectedResult = 1)
+
+class DrvUpgrade(OneArgCmdTest):
+ """Test driver upgrade message."""
+ def setup(self):
+ self.cmd = "drvupgrade"
+
+class CloseShare(OneArgCmdTest):
+ """Test close share message."""
+ def setup(self):
+ self.cmd = "close-share"
+
+class Debug(OneArgCmdTest):
+ """Test a debug message."""
+ def setup(self):
+ self.cmd = "debug"
+
+class PrintNotify(comfychair.TestCase):
+ """Test print notification commands."""
+ def runtest(self):
+
+ # No subcommand
+
+ out = self.runcmd("smbcontrol self printnotify", expectedResult = 1)
+ self.assert_re_match("Must specify subcommand", out[1]);
+
+ # Invalid subcommand name
+
+ out = self.runcmd("smbcontrol self printnotify spottyfoot",
+ expectedResult = 1)
+ self.assert_re_match("Invalid subcommand", out[1]);
+
+ # Queue commands
+
+ for cmd in ["queuepause", "queueresume"]:
+
+ out = self.runcmd("smbcontrol self printnotify %s" % cmd,
+ expectedResult = 1)
+ self.assert_re_match("Usage:", out[1])
+
+ out = self.runcmd("smbcontrol self printnotify %s spottyfoot"
+ % cmd)
+
+ # Job commands
+
+ for cmd in ["jobpause", "jobresume", "jobdelete"]:
+
+ out = self.runcmd("smbcontrol self printnotify %s" % cmd,
+ expectedResult = 1)
+ self.assert_re_match("Usage:", out[1])
+
+ out = self.runcmd("smbcontrol self printnotify %s spottyfoot"
+ % cmd, expectedResult = 1)
+ self.assert_re_match("Usage:", out[1])
+
+ out = self.runcmd("smbcontrol self printnotify %s spottyfoot 123"
+ % cmd)
+
+ # Printer properties
+
+ out = self.runcmd("smbcontrol self printnotify printer",
+ expectedResult = 1)
+ self.assert_re_match("Usage", out[1])
+
+ out = self.runcmd("smbcontrol self printnotify printer spottyfoot",
+ expectedResult = 1)
+ self.assert_re_match("Usage", out[1])
+
+ for cmd in ["comment", "port", "driver"]:
+
+ out = self.runcmd("smbcontrol self printnotify printer spottyfoot "
+ "%s" % cmd, expectedResult = 1)
+ self.assert_re_match("Usage", out[1])
+
+ out = self.runcmd("smbcontrol self printnotify printer spottyfoot "
+ "%s value" % cmd)
+
+class Profile(comfychair.TestCase):
+ """Test setting the profiling level."""
+ def runtest(self):
+ self.require_root()
+ out = self.runcmd("smbcontrol self profile", expectedResult = 1)
+ self.assert_re_match("Usage", out[1])
+
+ out = self.runcmd("smbcontrol self profile spottyfoot",
+ expectedResult = 1)
+ self.assert_re_match("Unknown", out[1])
+
+ for cmd in ["off", "count", "on", "flush"]:
+ out = self.runcmd("smbcontrol self profile %s" % cmd)
+
+class ProfileLevel(comfychair.TestCase):
+ """Test requesting the current profiling level."""
+ def runtest(self):
+ self.require_root()
+ out = self.runcmd("smbcontrol self profilelevel spottyfoot",
+ expectedResult = 1)
+ self.assert_re_match("Usage", out[1])
+
+ out = self.runcmd("smbcontrol self profilelevel")
+
+class TimeoutArg(comfychair.TestCase):
+ """Test the --timeout argument."""
+ def runtest(self):
+ out = self.runcmd("smbcontrol --timeout 5 self noop")
+ out = self.runcmd("smbcontrol --timeout spottyfoot self noop",
+ expectedResult = 1)
+
+class ConfigFileArg(comfychair.TestCase):
+ """Test the --configfile argument."""
+ def runtest(self):
+ out = self.runcmd("smbcontrol --configfile /dev/null self noop")
+
+class BogusArg(comfychair.TestCase):
+ """Test a bogus command line argument."""
+ def runtest(self):
+ out = self.runcmd("smbcontrol --bogus self noop", expectedResult = 1)
+
+tests = [NoArgs, OneArg, SmbdDest, NmbdDest, WinbinddDest, PidDest,
+ SelfDest, BadDest, BadCmd, Debug, ForceElection, SamSync,
+ SamRepl, DmallocMark, DmallocChanged, Shutdown, DrvUpgrade,
+ CloseShare, Ping, Debuglevel, PrintNotify, Profile, ProfileLevel,
+ TimeoutArg, ConfigFileArg, BogusArg]
+
+# Handle execution of this file as a main program
+
+if __name__ == '__main__':
+ comfychair.main(tests)
diff --git a/source3/stf/spoolss.py b/source3/stf/spoolss.py
new file mode 100755
index 0000000000..735291508b
--- /dev/null
+++ b/source3/stf/spoolss.py
@@ -0,0 +1,288 @@
+#!/usr/bin/python
+
+import re
+import comfychair, stf
+from samba import spoolss
+
+class PrintServerTest(comfychair.TestCase):
+ """An abstract class requiring a print server."""
+ def setUp(self):
+ # TODO: create a test printer
+ self.server = stf.get_server(platform = "nt")
+ self.require(self.server != None, "print server required")
+ # TODO: remove hardcoded printer name
+ self.printername = "p"
+ self.uncname = "\\\\%s\\%s" % \
+ (self.server["hostname"], self.printername)
+
+class W2kPrintServerTest(comfychair.TestCase):
+ """An abstract class requiring a print server."""
+ def setUp(self):
+ # TODO: create a test printer
+ self.server = stf.get_server(platform = "nt5")
+ self.require(self.server != None, "print server required")
+ # TODO: remove hardcoded printer name
+ self.printername = "p"
+ self.uncname = "\\\\%s\\%s" % \
+ (self.server["hostname"], self.printername)
+
+class CredentialTest(PrintServerTest):
+ """An class that calls a function with various sets of credentials."""
+ def runTest(self):
+
+ bad_user_creds = {"username": "spotty",
+ "domain": "dog",
+ "password": "bone"}
+
+ cases = ((self.server["administrator"], "Admin credentials", 1),
+ (bad_user_creds, "Bad credentials", 0))
+
+ # TODO: add unpriv user case
+
+ for creds, testname, result in cases:
+ try:
+ self.runTestArg(creds)
+ except:
+ if result:
+ import traceback
+ traceback.print_exc()
+ self.fail("rpc with creds %s failed when it "
+ "should have suceeded" % creds)
+ return
+
+ if not result:
+ self.fail("rpc with creds %s suceeded when it should "
+ "have failed" % creds)
+
+class ArgTestServer(PrintServerTest):
+ """Test a RPC that takes a UNC print server name."""
+ def runTest(self):
+
+ # List of test cases, %s substituted for server name
+
+ cases = (("", "No server name", 0),
+ ("\\\\%s", "Valid server name", 1),
+ ("\\%s", "Invalid unc server name", 0),
+ ("\\\\%s__", "Invalid unc server name", 0))
+
+ for unc, testname, result in cases:
+ unc = re.sub("%s", self.server["hostname"], unc)
+ try:
+ self.runTestArg(unc)
+ except:
+ if result:
+ self.fail("rpc(\"%s\") failed when it should have "
+ "suceeded" % unc)
+ return
+
+ if not result:
+ # Suceeded when we should have failed
+ self.fail("rpc(\"%s\") suceeded when it should have "
+ "failed" % unc)
+
+class ArgTestServerAndPrinter(ArgTestServer):
+ """Test a RPC that takes a UNC print server or UNC printer name."""
+ def runTest(self):
+
+ ArgTestServer.runTest(self)
+
+ # List of test cases, %s substituted for server name, %p substituted
+ # for printer name.
+
+ cases = (("\\\\%s\\%p", "Valid server and printer name", 1),
+ ("\\\\%s\\%p__", "Valid server, invalid printer name", 0),
+ ("\\\\%s__\\%p", "Invalid server, valid printer name", 0))
+
+ for unc, testname, result in cases:
+ unc = re.sub("%s", self.server["hostname"], unc)
+ unc = re.sub("%p", self.printername, unc)
+ try:
+ self.runTestArg(unc)
+ except:
+ if result:
+ self.fail("openprinter(\"%s\") failed when it should have "
+ "suceeded" % unc)
+ return
+
+ if not result:
+ # Suceeded when we should have failed
+ self.fail("openprinter(\"%s\") suceeded when it should have "
+ "failed" % unc)
+
+class OpenPrinterArg(ArgTestServerAndPrinter):
+ """Test the OpenPrinter RPC with combinations of valid and invalid
+ server and printer names."""
+ def runTestArg(self, unc):
+ spoolss.openprinter(unc)
+
+class OpenPrinterCred(CredentialTest):
+ """Test opening printer with good and bad credentials."""
+ def runTestArg(self, creds):
+ spoolss.openprinter(self.uncname, creds = creds)
+
+class ClosePrinter(PrintServerTest):
+ """Test the ClosePrinter RPC on a printer handle."""
+ def runTest(self):
+ hnd = spoolss.openprinter(self.uncname)
+ spoolss.closeprinter(hnd)
+
+class ClosePrinterServer(PrintServerTest):
+ """Test the ClosePrinter RPC on a print server handle."""
+ def runTest(self):
+ hnd = spoolss.openprinter("\\\\%s" % self.server["hostname"])
+ spoolss.closeprinter(hnd)
+
+class GetPrinterInfo(PrintServerTest):
+ """Retrieve printer info at various levels."""
+
+ # Sample printer data
+
+ sample_info = {
+ 0: {'printer_errors': 0, 'unknown18': 0, 'unknown13': 0, 'unknown26': 0, 'cjobs': 0, 'unknown11': 0, 'server_name': '\\\\win2kdc1', 'total_pages': 0, 'unknown15': 586, 'unknown16': 0, 'month': 2, 'unknown20': 0, 'second': 23, 'unknown22': 983040, 'unknown25': 0, 'total_bytes': 0, 'unknown27': 0, 'year': 2003, 'build_version': 2195, 'unknown28': 0, 'global_counter': 4, 'day': 13, 'minute': 53, 'total_jobs': 0, 'unknown29': 1114112, 'name': '\\\\win2kdc1\\p', 'hour': 2, 'level': 0, 'c_setprinter': 0, 'change_id': 522454169, 'major_version': 5, 'unknown23': 15, 'day_of_week': 4, 'unknown14': 1, 'session_counter': 2, 'status': 1, 'unknown7': 1, 'unknown8': 0, 'unknown9': 0, 'milliseconds': 421, 'unknown24': 0},
+ 1: {'comment': "I'm a teapot!", 'level': 1, 'flags': 8388608, 'name': '\\\\win2kdc1\\p', 'description': '\\\\win2kdc1\\p,HP LaserJet 4,Canberra office'},
+ 2: {'comment': "I'm a teapot!", 'status': 1, 'print_processor': 'WinPrint', 'until_time': 0, 'share_name': 'p', 'start_time': 0, 'device_mode': {'icm_method': 1, 'bits_per_pel': 0, 'log_pixels': 0, 'orientation': 1, 'panning_width': 0, 'color': 2, 'pels_width': 0, 'print_quality': 600, 'driver_version': 24, 'display_flags': 0, 'y_resolution': 600, 'media_type': 0, 'display_frequency': 0, 'icm_intent': 0, 'pels_height': 0, 'reserved1': 0, 'size': 220, 'scale': 100, 'dither_type': 0, 'panning_height': 0, 'default_source': 7, 'duplex': 1, 'fields': 16131, 'spec_version': 1025, 'copies': 1, 'device_name': '\\\\win2kdc1\\p', 'paper_size': 1, 'paper_length': 0, 'private': 'private', 'collate': 0, 'paper_width': 0, 'form_name': 'Letter', 'reserved2': 0, 'tt_option': 0}, 'port_name': 'LPT1:', 'sepfile': '', 'parameters': '', 'security_descriptor': {'group_sid': 'S-1-5-21-1606980848-1677128483-854245398-513', 'sacl': None, 'dacl': {'ace_list': [{'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-544'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-544'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1121'}, {'flags': 10, 'type': 0, 'mask': 131072, 'trustee': 'S-1-3-0'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-3-0'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1124'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-1-0'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-550'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-550'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-549'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-549'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1106'}], 'revision': 2}, 'owner_sid': 'S-1-5-32-544', 'revision': 1}, 'name': '\\\\win2kdc1\\p', 'server_name': '\\\\win2kdc1', 'level': 2, 'datatype': 'RAW', 'cjobs': 0, 'average_ppm': 0, 'priority': 1, 'driver_name': 'HP LaserJet 4', 'location': 'Canberra office', 'attributes': 8776, 'default_priority': 0},
+ 3: {'flags': 4, 'security_descriptor': {'group_sid': 'S-1-5-21-1606980848-1677128483-854245398-513', 'sacl': None, 'dacl': {'ace_list': [{'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-544'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-544'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1121'}, {'flags': 10, 'type': 0, 'mask': 131072, 'trustee': 'S-1-3-0'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-3-0'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1124'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-1-0'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-550'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-550'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-549'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-549'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1106'}], 'revision': 2}, 'owner_sid': 'S-1-5-32-544', 'revision': 1}, 'level': 3}
+ }
+
+ def runTest(self):
+ self.hnd = spoolss.openprinter(self.uncname)
+
+ # Everyone should have getprinter levels 0-3
+
+ for i in (0, 1, 2, 3):
+ info = self.hnd.getprinter(level = i)
+ try:
+ stf.dict_check(self.sample_info[i], info)
+ except ValueError, msg:
+ raise "info%d: %s" % (i, msg)
+
+class EnumPrinters(PrintServerTest):
+ """Enumerate print info at various levels."""
+
+ sample_info = {
+
+ 0: {'q': {'printer_errors': 0, 'unknown18': 0, 'unknown13': 0, 'unknown26': 0, 'cjobs': 0, 'unknown11': 0, 'server_name': '', 'total_pages': 0, 'unknown15': 586, 'unknown16': 0, 'month': 2, 'unknown20': 0, 'second': 23, 'unknown22': 983040, 'unknown25': 0, 'total_bytes': 0, 'unknown27': 0, 'year': 2003, 'build_version': 2195, 'unknown28': 0, 'global_counter': 4, 'day': 13, 'minute': 53, 'total_jobs': 0, 'unknown29': -1833435136, 'name': 'q', 'hour': 2, 'level': 0, 'c_setprinter': 0, 'change_id': 522454169, 'major_version': 5, 'unknown23': 15, 'day_of_week': 4, 'unknown14': 1, 'session_counter': 1, 'status': 0, 'unknown7': 1, 'unknown8': 0, 'unknown9': 0, 'milliseconds': 421, 'unknown24': 0}, 'p': {'printer_errors': 0, 'unknown18': 0, 'unknown13': 0, 'unknown26': 0, 'cjobs': 0, 'unknown11': 0, 'server_name': '', 'total_pages': 0, 'unknown15': 586, 'unknown16': 0, 'month': 2, 'unknown20': 0, 'second': 23, 'unknown22': 983040, 'unknown25': 0, 'total_bytes': 0, 'unknown27': 0, 'year': 2003, 'build_version': 2195, 'unknown28': 0, 'global_counter': 4, 'day': 13, 'minute': 53, 'total_jobs': 0, 'unknown29': -1831337984, 'name': 'p', 'hour': 2, 'level': 0, 'c_setprinter': 0, 'change_id': 522454169, 'major_version': 5, 'unknown23': 15, 'day_of_week': 4, 'unknown14': 1, 'session_counter': 1, 'status': 1, 'unknown7': 1, 'unknown8': 0, 'unknown9': 0, 'milliseconds': 421, 'unknown24': 0}, 'magpie': {'printer_errors': 0, 'unknown18': 0, 'unknown13': 0, 'unknown26': 0, 'cjobs': 0, 'unknown11': 0, 'server_name': '', 'total_pages': 0, 'unknown15': 586, 'unknown16': 0, 'month': 2, 'unknown20': 0, 'second': 23, 'unknown22': 983040, 'unknown25': 0, 'total_bytes': 0, 'unknown27': 0, 'year': 2003, 'build_version': 2195, 'unknown28': 0, 'global_counter': 4, 'day': 13, 'minute': 53, 'total_jobs': 0, 'unknown29': 1114112, 'name': 'magpie', 'hour': 2, 'level': 0, 'c_setprinter': 0, 'change_id': 522454169, 'major_version': 5, 'unknown23': 15, 'day_of_week': 4, 'unknown14': 1, 'session_counter': 1, 'status': 0, 'unknown7': 1, 'unknown8': 0, 'unknown9': 0, 'milliseconds': 421, 'unknown24': 0}},
+
+ 1: {'q': {'comment': 'cheepy birds', 'level': 1, 'flags': 8388608, 'name': 'q', 'description': 'q,HP LaserJet 4,'}, 'p': {'comment': "I'm a teapot!", 'level': 1, 'flags': 8388608, 'name': 'p', 'description': 'p,HP LaserJet 4,Canberra office'}, 'magpie': {'comment': '', 'level': 1, 'flags': 8388608, 'name': 'magpie', 'description': 'magpie,Generic / Text Only,'}}
+ }
+
+ def runTest(self):
+ for i in (0, 1):
+ info = spoolss.enumprinters(
+ "\\\\%s" % self.server["hostname"], level = i)
+ try:
+ stf.dict_check(self.sample_info[i], info)
+ except ValueError, msg:
+ raise "info%d: %s" % (i, msg)
+
+class EnumPrintersArg(ArgTestServer):
+ def runTestArg(self, unc):
+ spoolss.enumprinters(unc)
+
+class EnumPrintersCred(CredentialTest):
+ """Test opening printer with good and bad credentials."""
+ def runTestArg(self, creds):
+ spoolss.enumprinters(
+ "\\\\%s" % self.server["hostname"], creds = creds)
+
+class EnumPrinterdrivers(PrintServerTest):
+
+ sample_info = {
+ 1: {'Okipage 10ex (PCL5E) : STANDARD': {'name': 'Okipage 10ex (PCL5E) : STANDARD', 'level': 1}, 'Generic / Text Only': {'name': 'Generic / Text Only', 'level': 1}, 'Brother HL-1030 series': {'name': 'Brother HL-1030 series', 'level': 1}, 'Brother HL-1240 series': {'name': 'Brother HL-1240 series', 'level': 1}, 'HP DeskJet 1220C Printer': {'name': 'HP DeskJet 1220C Printer', 'level': 1}, 'HP LaserJet 4100 PCL 6': {'name': 'HP LaserJet 4100 PCL 6', 'level': 1}, 'HP LaserJet 4': {'name': 'HP LaserJet 4', 'level': 1}},
+ 2: {'Okipage 10ex (PCL5E) : STANDARD': {'version': 2, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\2\\RASDDUI.DLL', 'name': 'Okipage 10ex (PCL5E) : STANDARD', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\2\\RASDD.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\2\\OKIPAGE.DLL', 'level': 2, 'architecture': 'Windows NT x86'}, 'Generic / Text Only': {'version': 3, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\UNIDRVUI.DLL', 'name': 'Generic / Text Only', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\3\\UNIDRV.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\TTY.GPD', 'level': 2, 'architecture': 'Windows NT x86'}, 'Brother HL-1030 series': {'version': 3, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BRUHL99A.DLL', 'name': 'Brother HL-1030 series', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BROHL99A.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BROHL103.PPD', 'level': 2, 'architecture': 'Windows NT x86'}, 'Brother HL-1240 series': {'version': 3, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BRUHL99A.DLL', 'name': 'Brother HL-1240 series', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BROHL99A.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BROHL124.PPD', 'level': 2, 'architecture': 'Windows NT x86'}, 'HP DeskJet 1220C Printer': {'version': 3, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPW8KMD.DLL', 'name': 'HP DeskJet 1220C Printer', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPW8KMD.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPW8KMD.DLL', 'level': 2, 'architecture': 'Windows NT x86'}, 'HP LaserJet 4100 PCL 6': {'version': 3, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPBF042E.DLL', 'name': 'HP LaserJet 4100 PCL 6', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPBF042G.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPBF042I.PMD', 'level': 2, 'architecture': 'Windows NT x86'}, 'HP LaserJet 4': {'version': 2, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\2\\hpblff0.dll', 'name': 'HP LaserJet 4', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\2\\hpblff2.dll', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\2\\hpblff39.pmd', 'level': 2, 'architecture': 'Windows NT x86'}}
+ }
+
+ def runTest(self):
+ for i in (1, 2):
+ info = spoolss.enumprinterdrivers(
+ "\\\\%s" % self.server["hostname"], level = i)
+ try:
+ if not self.sample_info.has_key(i):
+ self.log("%s" % info)
+ self.fail()
+ stf.dict_check(self.sample_info[i], info)
+ except ValueError, msg:
+ raise "info%d: %s" % (i, msg)
+
+class EnumPrinterdriversArg(ArgTestServer):
+ def runTestArg(self, unc):
+ spoolss.enumprinterdrivers(unc)
+
+class EnumPrinterdriversCred(CredentialTest):
+ """Test opening printer with good and bad credentials."""
+ def runTestArg(self, creds):
+ spoolss.enumprinterdrivers(
+ "\\\\%s" % self.server["hostname"], creds = creds)
+
+def usage():
+ print "Usage: spoolss.py [options] [test1[,test2...]]"
+ print "\t -v/--verbose Display debugging information"
+ print "\t -l/--list-tests List available tests"
+ print
+ print "A list of comma separated test names or regular expressions"
+ print "can be used to filter the tests performed."
+
+def test_match(subtest_list, test_name):
+ """Return true if a test matches a comma separated list of regular
+ expression of test names."""
+ # re.match does an implicit ^ at the start of the pattern.
+ # Explicitly anchor to end to avoid matching substrings.
+ for s in string.split(subtest_list, ","):
+ if re.match(s + "$", test_name):
+ return 1
+ return 0
+
+if __name__ == "__main__":
+ import os, sys, string
+ import getopt
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "vl", \
+ ["verbose", "list-tests"])
+ except getopt.GetoptError:
+ usage()
+ sys.exit(0)
+
+ verbose = 0
+ list_tests = 0
+
+ for opt, arg in opts:
+ if opt in ("-v", "--verbose"):
+ verbose = 1
+ if opt in ("-l", "--list-tests"):
+ list_tests = 1
+
+ if len(args) > 1:
+ usage()
+ sys.exit(0)
+
+ test_list = [
+ OpenPrinterArg,
+ OpenPrinterCred,
+ ClosePrinter,
+ ClosePrinterServer,
+ GetPrinterInfo,
+ EnumPrinters,
+ EnumPrintersCred,
+ EnumPrintersArg,
+ EnumPrinterdrivers,
+ EnumPrinterdriversCred,
+ EnumPrinterdriversArg,
+ ]
+
+ if len(args):
+ t = []
+ for test in test_list:
+ if test_match(args[0], test.__name__):
+ t.append(test)
+ test_list = t
+
+ if os.environ.has_key("SAMBA_DEBUG"):
+ spoolss.setup_logging(interactive = 1)
+ spoolss.set_debuglevel(10)
+
+ if list_tests:
+ for test in test_list:
+ print test.__name__
+ else:
+ comfychair.runtests(test_list, verbose = verbose)
diff --git a/source3/stf/standardcheck.py b/source3/stf/standardcheck.py
new file mode 100644
index 0000000000..3261aed34b
--- /dev/null
+++ b/source3/stf/standardcheck.py
@@ -0,0 +1,32 @@
+#! /usr/bin/python
+
+# Comfychair test cases for Samba
+
+# Copyright (C) 2003 by Martin Pool <mbp@samba.org>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+"""These tests are run by Samba's "make check"."""
+
+import strings, comfychair
+import smbcontrol, sambalib
+
+# There should not be any actual tests in here: this file just serves
+# to define the ones run by default. They're imported from other
+# modules.
+
+tests = strings.tests + smbcontrol.tests + sambalib.tests
+
+if __name__ == '__main__':
+ comfychair.main(tests)
diff --git a/source3/stf/stf.py b/source3/stf/stf.py
new file mode 100755
index 0000000000..ee0ff73561
--- /dev/null
+++ b/source3/stf/stf.py
@@ -0,0 +1,101 @@
+#!/usr/bin/python
+#
+# Samba Testing Framework for Unit-testing
+#
+
+import os, string, re
+import osver
+
+def get_server_list_from_string(s):
+
+ server_list = []
+
+ # Format is a list of server:domain\username%password separated
+ # by commas.
+
+ for entry in string.split(s, ","):
+
+ # Parse entry
+
+ m = re.match("(.*):(.*)(\\\\|/)(.*)%(.*)", entry)
+ if not m:
+ raise "badly formed server list entry '%s'" % entry
+
+ server = m.group(1)
+ domain = m.group(2)
+ username = m.group(4)
+ password = m.group(5)
+
+ # Categorise servers
+
+ server_list.append({"platform": osver.os_version(server),
+ "hostname": server,
+ "administrator": {"username": username,
+ "domain": domain,
+ "password" : password}})
+
+ return server_list
+
+def get_server_list():
+ """Iterate through all sources of server info and append them all
+ in one big list."""
+
+ server_list = []
+
+ # The $STF_SERVERS environment variable
+
+ if os.environ.has_key("STF_SERVERS"):
+ server_list = server_list + \
+ get_server_list_from_string(os.environ["STF_SERVERS"])
+
+ return server_list
+
+def get_server(platform = None):
+ """Return configuration information for a server. The platform
+ argument can be a string either 'nt4' or 'nt5' for Windows NT or
+ Windows 2000 servers, or just 'nt' for Windows NT and higher."""
+
+ server_list = get_server_list()
+
+ for server in server_list:
+ if platform:
+ p = server["platform"]
+ if platform == "nt":
+ if (p == osver.PLATFORM_NT4 or p == osver.PLATFORM_NT5):
+ return server
+ if platform == "nt4" and p == osver.PLATFORM_NT4:
+ return server
+ if platform == "nt5" and p == osver.PLATFORM_NT5:
+ return server
+ else:
+ # No filter defined, return first in list
+ return server
+
+ return None
+
+def dict_check(sample_dict, real_dict):
+ """Check that real_dict contains all the keys present in sample_dict
+ and no extras. Also check that common keys are of them same type."""
+ tmp = real_dict.copy()
+ for key in sample_dict.keys():
+ # Check existing key and type
+ if not real_dict.has_key(key):
+ raise ValueError, "dict does not contain key '%s'" % key
+ if type(sample_dict[key]) != type(real_dict[key]):
+ raise ValueError, "dict has differing types (%s vs %s) for key " \
+ "'%s'" % (type(sample_dict[key]), type(real_dict[key]), key)
+ # Check dictionaries recursively
+ if type(sample_dict[key]) == dict:
+ dict_check(sample_dict[key], real_dict[key])
+ # Delete visited keys from copy
+ del(tmp[key])
+ # Any keys leftover are present in the real dict but not the sample
+ if len(tmp) == 0:
+ return
+ result = "dict has extra keys: "
+ for key in tmp.keys():
+ result = result + key + " "
+ raise ValueError, result
+
+if __name__ == "__main__":
+ print get_server(platform = "nt")
diff --git a/source3/stf/strings.py b/source3/stf/strings.py
new file mode 100755
index 0000000000..4e00021525
--- /dev/null
+++ b/source3/stf/strings.py
@@ -0,0 +1,149 @@
+#! /usr/bin/python
+
+# Comfychair test cases for Samba string functions.
+
+# Copyright (C) 2003 by Martin Pool <mbp@samba.org>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+# XXX: All this code assumes that the Unix character set is UTF-8,
+# which is the most common setting. I guess it would be better to
+# force it to that value while running the tests. I'm not sure of the
+# best way to do that yet.
+#
+# Note that this is NOT the case in C code until the loadparm table is
+# intialized -- the default seems to be ASCII, which rather lets Samba
+# off the hook. :-) The best way seems to be to put this in the test
+# harnesses:
+#
+# lp_load("/dev/null", True, False, False);
+#
+# -- mbp
+
+import sys, re, comfychair
+from unicodenames import *
+
+def signum(a):
+ if a < 0:
+ return -1
+ elif a > 0:
+ return +1
+ else:
+ return 0
+
+
+class PushUCS2_Tests(comfychair.TestCase):
+ """Conversion to/from UCS2"""
+ def runtest(self):
+ OE = LATIN_CAPITAL_LETTER_O_WITH_DIARESIS
+ oe = LATIN_CAPITAL_LETTER_O_WITH_DIARESIS
+ cases = ['hello',
+ 'hello world',
+ 'g' + OE + OE + 'gomobile',
+ 'g' + OE + oe + 'gomobile',
+ u'foo\u0100',
+ KATAKANA_LETTER_A * 20,
+ ]
+ for u8str in cases:
+ out, err = self.runcmd("t_push_ucs2 \"%s\"" % u8str.encode('utf-8'))
+ self.assert_equal(out, "0\n")
+
+
+class StrCaseCmp(comfychair.TestCase):
+ """String comparisons in simple ASCII"""
+ def run_strcmp(self, a, b, expect):
+ out, err = self.runcmd('t_strcmp \"%s\" \"%s\"' % (a.encode('utf-8'), b.encode('utf-8')))
+ if signum(int(out)) != expect:
+ self.fail("comparison failed:\n"
+ " a=%s\n"
+ " b=%s\n"
+ " expected=%s\n"
+ " result=%s\n" % (`a`, `b`, `expect`, `out`))
+
+ def runtest(self):
+ # A, B, strcasecmp(A, B)
+ cases = [('hello', 'hello', 0),
+ ('hello', 'goodbye', +1),
+ ('goodbye', 'hello', -1),
+ ('hell', 'hello', -1),
+ ('', '', 0),
+ ('a', '', +1),
+ ('', 'a', -1),
+ ('a', 'A', 0),
+ ('aa', 'aA', 0),
+ ('Aa', 'aa', 0),
+ ('longstring ' * 100, 'longstring ' * 100, 0),
+ ('longstring ' * 100, 'longstring ' * 100 + 'a', -1),
+ ('longstring ' * 100 + 'a', 'longstring ' * 100, +1),
+ (KATAKANA_LETTER_A, KATAKANA_LETTER_A, 0),
+ (KATAKANA_LETTER_A, 'a', 1),
+ ]
+ for a, b, expect in cases:
+ self.run_strcmp(a, b, expect)
+
+class strstr_m(comfychair.TestCase):
+ """String comparisons in simple ASCII"""
+ def run_strstr(self, a, b, expect):
+ out, err = self.runcmd('t_strstr \"%s\" \"%s\"' % (a.encode('utf-8'), b.encode('utf-8')))
+ if (out != (expect + '\n').encode('utf-8')):
+ self.fail("comparison failed:\n"
+ " a=%s\n"
+ " b=%s\n"
+ " expected=%s\n"
+ " result=%s\n" % (`a`, `b`, `expect+'\n'`, `out`))
+
+ def runtest(self):
+ # A, B, strstr_m(A, B)
+ cases = [('hello', 'hello', 'hello'),
+ ('hello', 'goodbye', '(null)'),
+ ('goodbye', 'hello', '(null)'),
+ ('hell', 'hello', '(null)'),
+ ('hello', 'hell', 'hello'),
+ ('', '', ''),
+ ('a', '', 'a'),
+ ('', 'a', '(null)'),
+ ('a', 'A', '(null)'),
+ ('aa', 'aA', '(null)'),
+ ('Aa', 'aa', '(null)'),
+ ('%v foo', '%v', '%v foo'),
+ ('foo %v foo', '%v', '%v foo'),
+ ('foo %v', '%v', '%v'),
+ ('longstring ' * 100, 'longstring ' * 99, 'longstring ' * 100),
+ ('longstring ' * 99, 'longstring ' * 100, '(null)'),
+ ('longstring a' * 99, 'longstring ' * 100 + 'a', '(null)'),
+ ('longstring ' * 100 + 'a', 'longstring ' * 100, 'longstring ' * 100 + 'a'),
+ (KATAKANA_LETTER_A, KATAKANA_LETTER_A + 'bcd', '(null)'),
+ (KATAKANA_LETTER_A + 'bcde', KATAKANA_LETTER_A + 'bcd', KATAKANA_LETTER_A + 'bcde'),
+ ('d'+KATAKANA_LETTER_A + 'bcd', KATAKANA_LETTER_A + 'bcd', KATAKANA_LETTER_A + 'bcd'),
+ ('d'+KATAKANA_LETTER_A + 'bd', KATAKANA_LETTER_A + 'bcd', '(null)'),
+
+ ('e'+KATAKANA_LETTER_A + 'bcdf', KATAKANA_LETTER_A + 'bcd', KATAKANA_LETTER_A + 'bcdf'),
+ (KATAKANA_LETTER_A, KATAKANA_LETTER_A + 'bcd', '(null)'),
+ (KATAKANA_LETTER_A*3, 'a', '(null)'),
+ ]
+ for a, b, expect in cases:
+ self.run_strstr(a, b, expect)
+
+# Define the tests exported by this module
+tests = [StrCaseCmp,
+ strstr_m,
+ PushUCS2_Tests]
+
+# Handle execution of this file as a main program
+if __name__ == '__main__':
+ comfychair.main(tests)
+
+# Local variables:
+# coding: utf-8
+# End:
diff --git a/source3/stf/test.py b/source3/stf/test.py
new file mode 100755
index 0000000000..fb57926cc3
--- /dev/null
+++ b/source3/stf/test.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+
+# meta-test-case / example for comfychair. Should demonstrate
+# different kinds of failure.
+
+import comfychair
+
+class NormalTest(comfychair.TestCase):
+ def runtest(self):
+ pass
+
+class RootTest(comfychair.TestCase):
+ def setup(self):
+ self.require_root()
+
+ def runTest(self):
+ pass
+
+class GoodExecTest(comfychair.TestCase):
+ def runtest(self):
+ stdout = self.runcmd("ls -l")
+
+class BadExecTest(comfychair.TestCase):
+ def setup(self):
+ exit, stdout = self.runcmd_unchecked("spottyfoot --slobber",
+ skip_on_noexec = 1)
+
+
+tests = [NormalTest, RootTest, GoodExecTest, BadExecTest]
+
+if __name__ == '__main__':
+ comfychair.main(tests)
+
diff --git a/source3/stf/unicodenames.py b/source3/stf/unicodenames.py
new file mode 100644
index 0000000000..34d0a19238
--- /dev/null
+++ b/source3/stf/unicodenames.py
@@ -0,0 +1,31 @@
+#! /usr/bin/python
+
+# Copyright (C) 2003 by Martin Pool <mbp@samba.org>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+
+"""
+Defines symbolic names for a few UNICODE characters, to make test
+source code more readable on machines that don't have all the
+necessary fonts.
+
+You can do "import *" on this file safely.
+"""
+
+LATIN_CAPITAL_LETTER_N_WITH_TILDE = u'\u004e'
+LATIN_CAPITAL_LETTER_O_WITH_DIARESIS = u'\u00d6'
+LATIN_SMALL_LETTER_O_WITH_DIARESIS = u'\u00f6'
+
+KATAKANA_LETTER_A = u'\u30a2'
diff --git a/source3/tests/README b/source3/tests/README
new file mode 100644
index 0000000000..cf1be8b00a
--- /dev/null
+++ b/source3/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/source3/tests/crypttest.c b/source3/tests/crypttest.c
new file mode 100644
index 0000000000..0e500d5481
--- /dev/null
+++ b/source3/tests/crypttest.c
@@ -0,0 +1,851 @@
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include <sys/types.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#if !defined(HAVE_CRYPT)
+
+/*
+ This bit of code was derived from the UFC-crypt package which
+ carries the following copyright
+
+ Modified for use by Samba by Andrew Tridgell, October 1994
+
+ Note that this routine is only faster on some machines. Under Linux 1.1.51
+ libc 4.5.26 I actually found this routine to be slightly slower.
+
+ Under SunOS I found a huge speedup by using these routines
+ (a factor of 20 or so)
+
+ Warning: I've had a report from Steve Kennedy <steve@gbnet.org>
+ that this crypt routine may sometimes get the wrong answer. Only
+ use UFC_CRYT if you really need it.
+
+*/
+
+/*
+ * UFC-crypt: ultra fast crypt(3) implementation
+ *
+ * Copyright (C) 1991-1998, Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 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 Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * @(#)crypt_util.c 2.31 02/08/92
+ *
+ * Support routines
+ *
+ */
+
+
+#ifndef long32
+#if (SIZEOF_INT == 4)
+#define long32 int
+#elif (SIZEOF_LONG == 4)
+#define long32 long
+#elif (SIZEOF_SHORT == 4)
+#define long32 short
+#else
+/* uggh - no 32 bit type?? probably a CRAY. just hope this works ... */
+#define long32 int
+#endif
+#endif
+
+#ifndef long64
+#ifdef HAVE_LONGLONG
+#define long64 long long long
+#endif
+#endif
+
+#ifndef ufc_long
+#define ufc_long unsigned
+#endif
+
+#ifndef _UFC_64_
+#define _UFC_32_
+#endif
+
+/*
+ * Permutation done once on the 56 bit
+ * key derived from the original 8 byte ASCII key.
+ */
+static int pc1[56] = {
+ 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
+ 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
+};
+
+/*
+ * How much to rotate each 28 bit half of the pc1 permutated
+ * 56 bit key before using pc2 to give the i' key
+ */
+static int rots[16] = {
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+};
+
+/*
+ * Permutation giving the key
+ * of the i' DES round
+ */
+static int pc2[48] = {
+ 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
+};
+
+/*
+ * The E expansion table which selects
+ * bits from the 32 bit intermediate result.
+ */
+static int esel[48] = {
+ 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9,
+ 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
+ 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
+ 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1
+};
+static int e_inverse[64];
+
+/*
+ * Permutation done on the
+ * result of sbox lookups
+ */
+static int perm32[32] = {
+ 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
+ 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
+};
+
+/*
+ * The sboxes
+ */
+static int sbox[8][4][16]= {
+ { { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 },
+ { 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 },
+ { 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0 },
+ { 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 }
+ },
+
+ { { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 },
+ { 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 },
+ { 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15 },
+ { 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 }
+ },
+
+ { { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 },
+ { 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 },
+ { 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7 },
+ { 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 }
+ },
+
+ { { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 },
+ { 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 },
+ { 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4 },
+ { 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 }
+ },
+
+ { { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 },
+ { 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 },
+ { 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14 },
+ { 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 }
+ },
+
+ { { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 },
+ { 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 },
+ { 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6 },
+ { 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 }
+ },
+
+ { { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 },
+ { 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 },
+ { 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2 },
+ { 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 }
+ },
+
+ { { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 },
+ { 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 },
+ { 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 },
+ { 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 }
+ }
+};
+
+/*
+ * This is the final
+ * permutation matrix
+ */
+static int final_perm[64] = {
+ 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
+ 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
+ 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
+ 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25
+};
+
+/*
+ * The 16 DES keys in BITMASK format
+ */
+#ifdef _UFC_32_
+long32 _ufc_keytab[16][2];
+#endif
+
+#ifdef _UFC_64_
+long64 _ufc_keytab[16];
+#endif
+
+
+#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.')
+#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
+
+/* Macro to set a bit (0..23) */
+#define BITMASK(i) ( (1<<(11-(i)%12+3)) << ((i)<12?16:0) )
+
+/*
+ * sb arrays:
+ *
+ * Workhorses of the inner loop of the DES implementation.
+ * They do sbox lookup, shifting of this value, 32 bit
+ * permutation and E permutation for the next round.
+ *
+ * Kept in 'BITMASK' format.
+ */
+
+#ifdef _UFC_32_
+long32 _ufc_sb0[8192], _ufc_sb1[8192], _ufc_sb2[8192], _ufc_sb3[8192];
+static long32 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3};
+#endif
+
+#ifdef _UFC_64_
+long64 _ufc_sb0[4096], _ufc_sb1[4096], _ufc_sb2[4096], _ufc_sb3[4096];
+static long64 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3};
+#endif
+
+/*
+ * eperm32tab: do 32 bit permutation and E selection
+ *
+ * The first index is the byte number in the 32 bit value to be permuted
+ * - second - is the value of this byte
+ * - third - selects the two 32 bit values
+ *
+ * The table is used and generated internally in init_des to speed it up
+ */
+static ufc_long eperm32tab[4][256][2];
+
+/*
+ * do_pc1: permform pc1 permutation in the key schedule generation.
+ *
+ * The first index is the byte number in the 8 byte ASCII key
+ * - second - - the two 28 bits halfs of the result
+ * - third - selects the 7 bits actually used of each byte
+ *
+ * The result is kept with 28 bit per 32 bit with the 4 most significant
+ * bits zero.
+ */
+static ufc_long do_pc1[8][2][128];
+
+/*
+ * do_pc2: permform pc2 permutation in the key schedule generation.
+ *
+ * The first index is the septet number in the two 28 bit intermediate values
+ * - second - - - septet values
+ *
+ * Knowledge of the structure of the pc2 permutation is used.
+ *
+ * The result is kept with 28 bit per 32 bit with the 4 most significant
+ * bits zero.
+ */
+static ufc_long do_pc2[8][128];
+
+/*
+ * efp: undo an extra e selection and do final
+ * permutation giving the DES result.
+ *
+ * Invoked 6 bit a time on two 48 bit values
+ * giving two 32 bit longs.
+ */
+static ufc_long efp[16][64][2];
+
+static unsigned char bytemask[8] = {
+ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
+};
+
+static ufc_long longmask[32] = {
+ 0x80000000, 0x40000000, 0x20000000, 0x10000000,
+ 0x08000000, 0x04000000, 0x02000000, 0x01000000,
+ 0x00800000, 0x00400000, 0x00200000, 0x00100000,
+ 0x00080000, 0x00040000, 0x00020000, 0x00010000,
+ 0x00008000, 0x00004000, 0x00002000, 0x00001000,
+ 0x00000800, 0x00000400, 0x00000200, 0x00000100,
+ 0x00000080, 0x00000040, 0x00000020, 0x00000010,
+ 0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+
+/*
+ * Silly rewrite of 'bzero'. I do so
+ * because some machines don't have
+ * bzero and some don't have memset.
+ */
+
+static void clearmem(char *start, int cnt)
+ { while(cnt--)
+ *start++ = '\0';
+ }
+
+static int initialized = 0;
+
+/* lookup a 6 bit value in sbox */
+
+#define s_lookup(i,s) sbox[(i)][(((s)>>4) & 0x2)|((s) & 0x1)][((s)>>1) & 0xf];
+
+/*
+ * Initialize unit - may be invoked directly
+ * by fcrypt users.
+ */
+
+static void ufc_init_des(void)
+ { int comes_from_bit;
+ int bit, sg;
+ ufc_long j;
+ ufc_long mask1, mask2;
+
+ /*
+ * Create the do_pc1 table used
+ * to affect pc1 permutation
+ * when generating keys
+ */
+ for(bit = 0; bit < 56; bit++) {
+ comes_from_bit = pc1[bit] - 1;
+ mask1 = bytemask[comes_from_bit % 8 + 1];
+ mask2 = longmask[bit % 28 + 4];
+ for(j = 0; j < 128; j++) {
+ if(j & mask1)
+ do_pc1[comes_from_bit / 8][bit / 28][j] |= mask2;
+ }
+ }
+
+ /*
+ * Create the do_pc2 table used
+ * to affect pc2 permutation when
+ * generating keys
+ */
+ for(bit = 0; bit < 48; bit++) {
+ comes_from_bit = pc2[bit] - 1;
+ mask1 = bytemask[comes_from_bit % 7 + 1];
+ mask2 = BITMASK(bit % 24);
+ for(j = 0; j < 128; j++) {
+ if(j & mask1)
+ do_pc2[comes_from_bit / 7][j] |= mask2;
+ }
+ }
+
+ /*
+ * Now generate the table used to do combined
+ * 32 bit permutation and e expansion
+ *
+ * We use it because we have to permute 16384 32 bit
+ * longs into 48 bit in order to initialize sb.
+ *
+ * Looping 48 rounds per permutation becomes
+ * just too slow...
+ *
+ */
+
+ clearmem((char*)eperm32tab, sizeof(eperm32tab));
+
+ for(bit = 0; bit < 48; bit++) {
+ ufc_long inner_mask1,comes_from;
+
+ comes_from = perm32[esel[bit]-1]-1;
+ inner_mask1 = bytemask[comes_from % 8];
+
+ for(j = 256; j--;) {
+ if(j & inner_mask1)
+ eperm32tab[comes_from / 8][j][bit / 24] |= BITMASK(bit % 24);
+ }
+ }
+
+ /*
+ * Create the sb tables:
+ *
+ * For each 12 bit segment of an 48 bit intermediate
+ * result, the sb table precomputes the two 4 bit
+ * values of the sbox lookups done with the two 6
+ * bit halves, shifts them to their proper place,
+ * sends them through perm32 and finally E expands
+ * them so that they are ready for the next
+ * DES round.
+ *
+ */
+ for(sg = 0; sg < 4; sg++) {
+ int j1, j2;
+ int s1, s2;
+
+ for(j1 = 0; j1 < 64; j1++) {
+ s1 = s_lookup(2 * sg, j1);
+ for(j2 = 0; j2 < 64; j2++) {
+ ufc_long to_permute, inx;
+
+ s2 = s_lookup(2 * sg + 1, j2);
+ to_permute = ((s1 << 4) | s2) << (24 - 8 * sg);
+
+#ifdef _UFC_32_
+ inx = ((j1 << 6) | j2) << 1;
+ sb[sg][inx ] = eperm32tab[0][(to_permute >> 24) & 0xff][0];
+ sb[sg][inx+1] = eperm32tab[0][(to_permute >> 24) & 0xff][1];
+ sb[sg][inx ] |= eperm32tab[1][(to_permute >> 16) & 0xff][0];
+ sb[sg][inx+1] |= eperm32tab[1][(to_permute >> 16) & 0xff][1];
+ sb[sg][inx ] |= eperm32tab[2][(to_permute >> 8) & 0xff][0];
+ sb[sg][inx+1] |= eperm32tab[2][(to_permute >> 8) & 0xff][1];
+ sb[sg][inx ] |= eperm32tab[3][(to_permute) & 0xff][0];
+ sb[sg][inx+1] |= eperm32tab[3][(to_permute) & 0xff][1];
+#endif
+#ifdef _UFC_64_
+ inx = ((j1 << 6) | j2);
+ sb[sg][inx] =
+ ((long64)eperm32tab[0][(to_permute >> 24) & 0xff][0] << 32) |
+ (long64)eperm32tab[0][(to_permute >> 24) & 0xff][1];
+ sb[sg][inx] |=
+ ((long64)eperm32tab[1][(to_permute >> 16) & 0xff][0] << 32) |
+ (long64)eperm32tab[1][(to_permute >> 16) & 0xff][1];
+ sb[sg][inx] |=
+ ((long64)eperm32tab[2][(to_permute >> 8) & 0xff][0] << 32) |
+ (long64)eperm32tab[2][(to_permute >> 8) & 0xff][1];
+ sb[sg][inx] |=
+ ((long64)eperm32tab[3][(to_permute) & 0xff][0] << 32) |
+ (long64)eperm32tab[3][(to_permute) & 0xff][1];
+#endif
+ }
+ }
+ }
+
+ /*
+ * Create an inverse matrix for esel telling
+ * where to plug out bits if undoing it
+ */
+ for(bit=48; bit--;) {
+ e_inverse[esel[bit] - 1 ] = bit;
+ e_inverse[esel[bit] - 1 + 32] = bit + 48;
+ }
+
+ /*
+ * create efp: the matrix used to
+ * undo the E expansion and effect final permutation
+ */
+ clearmem((char*)efp, sizeof efp);
+ for(bit = 0; bit < 64; bit++) {
+ int o_bit, o_long;
+ ufc_long word_value, inner_mask1, inner_mask2;
+ int comes_from_f_bit, comes_from_e_bit;
+ int comes_from_word, bit_within_word;
+
+ /* See where bit i belongs in the two 32 bit long's */
+ o_long = bit / 32; /* 0..1 */
+ o_bit = bit % 32; /* 0..31 */
+
+ /*
+ * And find a bit in the e permutated value setting this bit.
+ *
+ * Note: the e selection may have selected the same bit several
+ * times. By the initialization of e_inverse, we only look
+ * for one specific instance.
+ */
+ comes_from_f_bit = final_perm[bit] - 1; /* 0..63 */
+ comes_from_e_bit = e_inverse[comes_from_f_bit]; /* 0..95 */
+ comes_from_word = comes_from_e_bit / 6; /* 0..15 */
+ bit_within_word = comes_from_e_bit % 6; /* 0..5 */
+
+ inner_mask1 = longmask[bit_within_word + 26];
+ inner_mask2 = longmask[o_bit];
+
+ for(word_value = 64; word_value--;) {
+ if(word_value & inner_mask1)
+ efp[comes_from_word][word_value][o_long] |= inner_mask2;
+ }
+ }
+ initialized++;
+ }
+
+/*
+ * Process the elements of the sb table permuting the
+ * bits swapped in the expansion by the current salt.
+ */
+
+#ifdef _UFC_32_
+static void shuffle_sb(long32 *k, ufc_long saltbits)
+ { ufc_long j;
+ long32 x;
+ for(j=4096; j--;) {
+ x = (k[0] ^ k[1]) & (long32)saltbits;
+ *k++ ^= x;
+ *k++ ^= x;
+ }
+ }
+#endif
+
+#ifdef _UFC_64_
+static void shuffle_sb(long64 *k, ufc_long saltbits)
+ { ufc_long j;
+ long64 x;
+ for(j=4096; j--;) {
+ x = ((*k >> 32) ^ *k) & (long64)saltbits;
+ *k++ ^= (x << 32) | x;
+ }
+ }
+#endif
+
+/*
+ * Setup the unit for a new salt
+ * Hopefully we'll not see a new salt in each crypt call.
+ */
+
+static unsigned char current_salt[3] = "&&"; /* invalid value */
+static ufc_long current_saltbits = 0;
+static int direction = 0;
+
+static void setup_salt(const char *s1)
+ { ufc_long i, j, saltbits;
+ const unsigned char *s2 = (const unsigned char *)s1;
+
+ if(!initialized)
+ ufc_init_des();
+
+ if(s2[0] == current_salt[0] && s2[1] == current_salt[1])
+ return;
+ current_salt[0] = s2[0]; current_salt[1] = s2[1];
+
+ /*
+ * This is the only crypt change to DES:
+ * entries are swapped in the expansion table
+ * according to the bits set in the salt.
+ */
+ saltbits = 0;
+ for(i = 0; i < 2; i++) {
+ long c=ascii_to_bin(s2[i]);
+ if(c < 0 || c > 63)
+ c = 0;
+ for(j = 0; j < 6; j++) {
+ if((c >> j) & 0x1)
+ saltbits |= BITMASK(6 * i + j);
+ }
+ }
+
+ /*
+ * Permute the sb table values
+ * to reflect the changed e
+ * selection table
+ */
+ shuffle_sb(_ufc_sb0, current_saltbits ^ saltbits);
+ shuffle_sb(_ufc_sb1, current_saltbits ^ saltbits);
+ shuffle_sb(_ufc_sb2, current_saltbits ^ saltbits);
+ shuffle_sb(_ufc_sb3, current_saltbits ^ saltbits);
+
+ current_saltbits = saltbits;
+ }
+
+static void ufc_mk_keytab(char *key)
+ { ufc_long v1, v2, *k1;
+ int i;
+#ifdef _UFC_32_
+ long32 v, *k2 = &_ufc_keytab[0][0];
+#endif
+#ifdef _UFC_64_
+ long64 v, *k2 = &_ufc_keytab[0];
+#endif
+
+ v1 = v2 = 0; k1 = &do_pc1[0][0][0];
+ for(i = 8; i--;) {
+ v1 |= k1[*key & 0x7f]; k1 += 128;
+ v2 |= k1[*key++ & 0x7f]; k1 += 128;
+ }
+
+ for(i = 0; i < 16; i++) {
+ k1 = &do_pc2[0][0];
+
+ v1 = (v1 << rots[i]) | (v1 >> (28 - rots[i]));
+ v = k1[(v1 >> 21) & 0x7f]; k1 += 128;
+ v |= k1[(v1 >> 14) & 0x7f]; k1 += 128;
+ v |= k1[(v1 >> 7) & 0x7f]; k1 += 128;
+ v |= k1[(v1 ) & 0x7f]; k1 += 128;
+
+#ifdef _UFC_32_
+ *k2++ = v;
+ v = 0;
+#endif
+#ifdef _UFC_64_
+ v <<= 32;
+#endif
+
+ v2 = (v2 << rots[i]) | (v2 >> (28 - rots[i]));
+ v |= k1[(v2 >> 21) & 0x7f]; k1 += 128;
+ v |= k1[(v2 >> 14) & 0x7f]; k1 += 128;
+ v |= k1[(v2 >> 7) & 0x7f]; k1 += 128;
+ v |= k1[(v2 ) & 0x7f];
+
+ *k2++ = v;
+ }
+
+ direction = 0;
+ }
+
+/*
+ * Undo an extra E selection and do final permutations
+ */
+
+ufc_long *_ufc_dofinalperm(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2)
+ { ufc_long v1, v2, x;
+ static ufc_long ary[2];
+
+ x = (l1 ^ l2) & current_saltbits; l1 ^= x; l2 ^= x;
+ x = (r1 ^ r2) & current_saltbits; r1 ^= x; r2 ^= x;
+
+ v1=v2=0; l1 >>= 3; l2 >>= 3; r1 >>= 3; r2 >>= 3;
+
+ v1 |= efp[15][ r2 & 0x3f][0]; v2 |= efp[15][ r2 & 0x3f][1];
+ v1 |= efp[14][(r2 >>= 6) & 0x3f][0]; v2 |= efp[14][ r2 & 0x3f][1];
+ v1 |= efp[13][(r2 >>= 10) & 0x3f][0]; v2 |= efp[13][ r2 & 0x3f][1];
+ v1 |= efp[12][(r2 >>= 6) & 0x3f][0]; v2 |= efp[12][ r2 & 0x3f][1];
+
+ v1 |= efp[11][ r1 & 0x3f][0]; v2 |= efp[11][ r1 & 0x3f][1];
+ v1 |= efp[10][(r1 >>= 6) & 0x3f][0]; v2 |= efp[10][ r1 & 0x3f][1];
+ v1 |= efp[ 9][(r1 >>= 10) & 0x3f][0]; v2 |= efp[ 9][ r1 & 0x3f][1];
+ v1 |= efp[ 8][(r1 >>= 6) & 0x3f][0]; v2 |= efp[ 8][ r1 & 0x3f][1];
+
+ v1 |= efp[ 7][ l2 & 0x3f][0]; v2 |= efp[ 7][ l2 & 0x3f][1];
+ v1 |= efp[ 6][(l2 >>= 6) & 0x3f][0]; v2 |= efp[ 6][ l2 & 0x3f][1];
+ v1 |= efp[ 5][(l2 >>= 10) & 0x3f][0]; v2 |= efp[ 5][ l2 & 0x3f][1];
+ v1 |= efp[ 4][(l2 >>= 6) & 0x3f][0]; v2 |= efp[ 4][ l2 & 0x3f][1];
+
+ v1 |= efp[ 3][ l1 & 0x3f][0]; v2 |= efp[ 3][ l1 & 0x3f][1];
+ v1 |= efp[ 2][(l1 >>= 6) & 0x3f][0]; v2 |= efp[ 2][ l1 & 0x3f][1];
+ v1 |= efp[ 1][(l1 >>= 10) & 0x3f][0]; v2 |= efp[ 1][ l1 & 0x3f][1];
+ v1 |= efp[ 0][(l1 >>= 6) & 0x3f][0]; v2 |= efp[ 0][ l1 & 0x3f][1];
+
+ ary[0] = v1; ary[1] = v2;
+ return ary;
+ }
+
+/*
+ * crypt only: convert from 64 bit to 11 bit ASCII
+ * prefixing with the salt
+ */
+
+static char *output_conversion(ufc_long v1, ufc_long v2, const char *salt)
+ { static char outbuf[14];
+ int i, s;
+
+ outbuf[0] = salt[0];
+ outbuf[1] = salt[1] ? salt[1] : salt[0];
+
+ for(i = 0; i < 5; i++)
+ outbuf[i + 2] = bin_to_ascii((v1 >> (26 - 6 * i)) & 0x3f);
+
+ s = (v2 & 0xf) << 2;
+ v2 = (v2 >> 2) | ((v1 & 0x3) << 30);
+
+ for(i = 5; i < 10; i++)
+ outbuf[i + 2] = bin_to_ascii((v2 >> (56 - 6 * i)) & 0x3f);
+
+ outbuf[12] = bin_to_ascii(s);
+ outbuf[13] = 0;
+
+ return outbuf;
+ }
+
+/*
+ * UNIX crypt function
+ */
+
+static ufc_long *_ufc_doit(ufc_long , ufc_long, ufc_long, ufc_long, ufc_long);
+
+char *ufc_crypt(const char *key,const char *salt)
+ { ufc_long *s;
+ char ktab[9];
+
+ /*
+ * Hack DES tables according to salt
+ */
+ setup_salt(salt);
+
+ /*
+ * Setup key schedule
+ */
+ clearmem(ktab, sizeof ktab);
+ strncpy(ktab, key, 8);
+ ufc_mk_keytab(ktab);
+
+ /*
+ * Go for the 25 DES encryptions
+ */
+ s = _ufc_doit((ufc_long)0, (ufc_long)0,
+ (ufc_long)0, (ufc_long)0, (ufc_long)25);
+
+ /*
+ * And convert back to 6 bit ASCII
+ */
+ return output_conversion(s[0], s[1], salt);
+ }
+
+
+#ifdef _UFC_32_
+
+/*
+ * 32 bit version
+ */
+
+extern long32 _ufc_keytab[16][2];
+extern long32 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[];
+
+#define SBA(sb, v) (*(long32*)((char*)(sb)+(v)))
+
+static ufc_long *_ufc_doit(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2, ufc_long itr)
+ { int i;
+ long32 s, *k;
+
+ while(itr--) {
+ k = &_ufc_keytab[0][0];
+ for(i=8; i--; ) {
+ s = *k++ ^ r1;
+ l1 ^= SBA(_ufc_sb1, s & 0xffff); l2 ^= SBA(_ufc_sb1, (s & 0xffff)+4);
+ l1 ^= SBA(_ufc_sb0, s >>= 16); l2 ^= SBA(_ufc_sb0, (s) +4);
+ s = *k++ ^ r2;
+ l1 ^= SBA(_ufc_sb3, s & 0xffff); l2 ^= SBA(_ufc_sb3, (s & 0xffff)+4);
+ l1 ^= SBA(_ufc_sb2, s >>= 16); l2 ^= SBA(_ufc_sb2, (s) +4);
+
+ s = *k++ ^ l1;
+ r1 ^= SBA(_ufc_sb1, s & 0xffff); r2 ^= SBA(_ufc_sb1, (s & 0xffff)+4);
+ r1 ^= SBA(_ufc_sb0, s >>= 16); r2 ^= SBA(_ufc_sb0, (s) +4);
+ s = *k++ ^ l2;
+ r1 ^= SBA(_ufc_sb3, s & 0xffff); r2 ^= SBA(_ufc_sb3, (s & 0xffff)+4);
+ r1 ^= SBA(_ufc_sb2, s >>= 16); r2 ^= SBA(_ufc_sb2, (s) +4);
+ }
+ s=l1; l1=r1; r1=s; s=l2; l2=r2; r2=s;
+ }
+ return _ufc_dofinalperm(l1, l2, r1, r2);
+ }
+
+#endif
+
+#ifdef _UFC_64_
+
+/*
+ * 64 bit version
+ */
+
+extern long64 _ufc_keytab[16];
+extern long64 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[];
+
+#define SBA(sb, v) (*(long64*)((char*)(sb)+(v)))
+
+static ufc_long *_ufc_doit(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2, ufc_long itr)
+ { int i;
+ long64 l, r, s, *k;
+
+ l = (((long64)l1) << 32) | ((long64)l2);
+ r = (((long64)r1) << 32) | ((long64)r2);
+
+ while(itr--) {
+ k = &_ufc_keytab[0];
+ for(i=8; i--; ) {
+ s = *k++ ^ r;
+ l ^= SBA(_ufc_sb3, (s >> 0) & 0xffff);
+ l ^= SBA(_ufc_sb2, (s >> 16) & 0xffff);
+ l ^= SBA(_ufc_sb1, (s >> 32) & 0xffff);
+ l ^= SBA(_ufc_sb0, (s >> 48) & 0xffff);
+
+ s = *k++ ^ l;
+ r ^= SBA(_ufc_sb3, (s >> 0) & 0xffff);
+ r ^= SBA(_ufc_sb2, (s >> 16) & 0xffff);
+ r ^= SBA(_ufc_sb1, (s >> 32) & 0xffff);
+ r ^= SBA(_ufc_sb0, (s >> 48) & 0xffff);
+ }
+ s=l; l=r; r=s;
+ }
+
+ l1 = l >> 32; l2 = l & 0xffffffff;
+ r1 = r >> 32; r2 = r & 0xffffffff;
+ return _ufc_dofinalperm(l1, l2, r1, r2);
+ }
+
+#endif
+
+#define crypt ufc_crypt
+#endif
+
+main()
+{
+ char passwd[9];
+ char salt[9];
+ char c_out1[256];
+ char c_out2[256];
+
+ char expected_out[14];
+
+ strcpy(expected_out, "12yJ.Of/NQ.Pk");
+ strcpy(passwd, "12345678");
+ strcpy(salt, "12345678");
+
+ strcpy(c_out1, crypt(passwd, salt));
+ salt[2] = '\0';
+ strcpy(c_out2, crypt(passwd, salt));
+
+ /*
+ * If the non-trucated salt fails but the
+ * truncated salt succeeds then exit 1.
+ */
+
+ if((strcmp(c_out1, expected_out) != 0) &&
+ (strcmp(c_out2, expected_out) == 0))
+ exit(1);
+
+#ifdef HAVE_BIGCRYPT
+ /*
+ * Try the same with bigcrypt...
+ */
+
+ {
+ char big_passwd[17];
+ char big_salt[17];
+ char big_c_out1[256];
+ char big_c_out2[256];
+ char big_expected_out[27];
+
+ strcpy(big_passwd, "1234567812345678");
+ strcpy(big_salt, "1234567812345678");
+ strcpy(big_expected_out, "12yJ.Of/NQ.PklfyCuHi/rwM");
+
+ strcpy(big_c_out1, bigcrypt(big_passwd, big_salt));
+ big_salt[2] = '\0';
+ strcpy(big_c_out2, bigcrypt(big_passwd, big_salt));
+
+ /*
+ * If the non-trucated salt fails but the
+ * truncated salt succeeds then exit 1.
+ */
+
+ if((strcmp(big_c_out1, big_expected_out) != 0) &&
+ (strcmp(big_c_out2, big_expected_out) == 0))
+ exit(1);
+
+ }
+#endif
+
+ exit(0);
+}
diff --git a/source3/tests/fcntl_lock.c b/source3/tests/fcntl_lock.c
new file mode 100644
index 0000000000..3dc12a3897
--- /dev/null
+++ b/source3/tests/fcntl_lock.c
@@ -0,0 +1,121 @@
+/* test whether fcntl locking works on this system */
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_FCNTL_H
+#include <sys/fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include <errno.h>
+
+static int sys_waitpid(pid_t pid,int *status,int options)
+{
+#ifdef HAVE_WAITPID
+ return waitpid(pid,status,options);
+#else /* USE_WAITPID */
+ return wait4(pid, status, options, NULL);
+#endif /* USE_WAITPID */
+}
+
+#define DATA "conftest.fcntl"
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+/* lock a byte range in a open file */
+int main(int argc, char *argv[])
+{
+ struct flock lock;
+ int fd, ret, status=1;
+ pid_t pid;
+ char *testdir = NULL;
+
+ testdir = getenv("TESTDIR");
+ if (testdir) chdir(testdir);
+
+ alarm(10);
+
+ if (!(pid=fork())) {
+ sleep(2);
+ fd = open(DATA, O_RDONLY);
+
+ if (fd == -1) {
+ fprintf(stderr,"ERROR: failed to open %s (errno=%d)\n",
+ DATA, (int)errno);
+ exit(1);
+ }
+
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 4;
+ lock.l_pid = getpid();
+
+ lock.l_type = F_WRLCK;
+
+ /* check if a lock applies */
+ ret = fcntl(fd,F_GETLK,&lock);
+
+ if ((ret == -1) ||
+ (lock.l_type == F_UNLCK)) {
+ fprintf(stderr,"ERROR: lock test failed (ret=%d errno=%d)\n", ret, (int)errno);
+ exit(1);
+ } else {
+ exit(0);
+ }
+ }
+
+ unlink(DATA);
+ fd = open(DATA, O_RDWR|O_CREAT|O_EXCL, 0600);
+
+ if (fd == -1) {
+ fprintf(stderr,"ERROR: failed to open %s (errno=%d)\n",
+ DATA, (int)errno);
+ exit(1);
+ }
+
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 4;
+ lock.l_pid = getpid();
+
+ /* set a 4 byte write lock */
+ fcntl(fd,F_SETLK,&lock);
+
+ sys_waitpid(pid, &status, 0);
+
+ unlink(DATA);
+
+#if defined(WIFEXITED) && defined(WEXITSTATUS)
+ if(WIFEXITED(status)) {
+ status = WEXITSTATUS(status);
+ } else {
+ status = 1;
+ }
+#else /* defined(WIFEXITED) && defined(WEXITSTATUS) */
+ status = (status == 0) ? 0 : 1;
+#endif /* defined(WIFEXITED) && defined(WEXITSTATUS) */
+
+ if (status) {
+ fprintf(stderr,"ERROR: lock test failed with status=%d\n",
+ status);
+ }
+
+ exit(status);
+}
diff --git a/source3/tests/fcntl_lock64.c b/source3/tests/fcntl_lock64.c
new file mode 100644
index 0000000000..e5ecd88fd0
--- /dev/null
+++ b/source3/tests/fcntl_lock64.c
@@ -0,0 +1,96 @@
+/* test whether 64 bit fcntl locking really works on this system */
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_FCNTL_H
+#include <sys/fcntl.h>
+#endif
+
+#include <errno.h>
+
+static int sys_waitpid(pid_t pid,int *status,int options)
+{
+#ifdef HAVE_WAITPID
+ return waitpid(pid,status,options);
+#else /* USE_WAITPID */
+ return wait4(pid, status, options, NULL);
+#endif /* USE_WAITPID */
+}
+
+#define DATA "conftest.fcntl64"
+
+/* lock a byte range in a open file */
+int main(int argc, char *argv[])
+{
+ struct flock64 lock;
+ int fd, ret, status=1;
+ pid_t pid;
+
+ if (!(pid=fork())) {
+ sleep(2);
+ fd = open64(DATA, O_RDONLY);
+
+ if (fd == -1) exit(1);
+
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 4;
+ lock.l_pid = getpid();
+
+ lock.l_type = F_WRLCK;
+
+ /* check if a lock applies */
+ ret = fcntl(fd,F_GETLK64,&lock);
+
+ if ((ret == -1) ||
+ (lock.l_type == F_UNLCK)) {
+/* printf("No lock conflict\n"); */
+ exit(1);
+ } else {
+/* printf("lock conflict\n"); */
+ exit(0);
+ }
+ }
+
+ fd = open64(DATA, O_RDWR|O_CREAT|O_TRUNC, 0600);
+
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+#if defined(COMPILER_SUPPORTS_LL)
+ lock.l_start = 0x100000000LL;
+#else
+ lock.l_start = 0x100000000;
+#endif
+ lock.l_len = 4;
+ lock.l_pid = getpid();
+
+ /* set a 4 byte write lock */
+ fcntl(fd,F_SETLK64,&lock);
+
+ sys_waitpid(pid, &status, 0);
+
+#if defined(WIFEXITED) && defined(WEXITSTATUS)
+ if(WIFEXITED(status)) {
+ status = WEXITSTATUS(status);
+ } else {
+ status = 1;
+ }
+#else /* defined(WIFEXITED) && defined(WEXITSTATUS) */
+ status = (status == 0) ? 0 : 1;
+#endif /* defined(WIFEXITED) && defined(WEXITSTATUS) */
+
+ unlink(DATA);
+
+ exit(status);
+}
diff --git a/source3/tests/ftruncate.c b/source3/tests/ftruncate.c
new file mode 100644
index 0000000000..93282782ee
--- /dev/null
+++ b/source3/tests/ftruncate.c
@@ -0,0 +1,27 @@
+/* test whether ftruncte() can extend a file */
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define DATA "conftest.trunc"
+#define LEN 7663
+
+main()
+{
+ int *buf;
+ int fd = open(DATA,O_RDWR|O_CREAT|O_TRUNC,0666);
+
+ ftruncate(fd, LEN);
+
+ unlink(DATA);
+
+ if (lseek(fd, 0, SEEK_END) == LEN) {
+ exit(0);
+ }
+ exit(1);
+}
diff --git a/source3/tests/getgroups.c b/source3/tests/getgroups.c
new file mode 100644
index 0000000000..343fd5a184
--- /dev/null
+++ b/source3/tests/getgroups.c
@@ -0,0 +1,66 @@
+/* this tests whether getgroups actually returns lists of integers
+ rather than gid_t. The test only works if the user running
+ the test is in at least 1 group
+
+ The test is designed to check for those broken OSes that define
+ getgroups() as returning an array of gid_t but actually return a
+ array of ints! Ultrix is one culprit
+ */
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <grp.h>
+
+main()
+{
+ int i;
+ int *igroups;
+ char *cgroups;
+ int grp = 0;
+ int ngroups = getgroups(0,&grp);
+
+ if (sizeof(gid_t) == sizeof(int)) {
+ fprintf(stderr,"gid_t and int are the same size\n");
+ exit(1);
+ }
+
+ if (ngroups <= 0)
+ ngroups = 32;
+
+ igroups = (int *)malloc(sizeof(int)*ngroups);
+
+ for (i=0;i<ngroups;i++)
+ igroups[i] = 0x42424242;
+
+ ngroups = getgroups(ngroups,(gid_t *)igroups);
+
+ if (igroups[0] == 0x42424242)
+ ngroups = 0;
+
+ if (ngroups == 0) {
+ printf("WARNING: can't determine getgroups return type\n");
+ exit(1);
+ }
+
+ cgroups = (char *)igroups;
+
+ if (ngroups == 1 &&
+ cgroups[2] == 0x42 && cgroups[3] == 0x42) {
+ fprintf(stderr,"getgroups returns gid_t\n");
+ exit(1);
+ }
+
+ for (i=0;i<ngroups;i++) {
+ if (igroups[i] == 0x42424242) {
+ fprintf(stderr,"getgroups returns gid_t\n");
+ exit(1);
+ }
+ }
+
+ exit(0);
+}
diff --git a/source3/tests/shlib.c b/source3/tests/shlib.c
new file mode 100644
index 0000000000..eddb76ff2a
--- /dev/null
+++ b/source3/tests/shlib.c
@@ -0,0 +1,8 @@
+/* a trivial function used to test building shared libraries */
+
+int foo(void);
+
+int foo(void)
+{
+ return 1;
+}
diff --git a/source3/tests/summary.c b/source3/tests/summary.c
new file mode 100644
index 0000000000..8fcde7bd99
--- /dev/null
+++ b/source3/tests/summary.c
@@ -0,0 +1,31 @@
+#include <stdio.h>
+
+main()
+{
+ exit (0);
+#if !(defined(HAVE_FCNTL_LOCK) || defined(HAVE_STRUCT_FLOCK64))
+ printf("ERROR: No locking available. Running Samba would be unsafe\n");
+ exit(1);
+#endif
+
+#if !(defined(HAVE_IFACE_IFCONF) || defined(HAVE_IFACE_IFREQ) || defined(HAVE_IFACE_AIX))
+ printf("WARNING: No automated network interface determination\n");
+#endif
+
+#if !(defined(USE_SETEUID) || defined(USE_SETREUID) || defined(USE_SETRESUID) || defined(USE_SETUIDX))
+ printf("ERROR: no seteuid method available\n");
+ exit(1);
+#endif
+
+#if !(defined(STAT_STATVFS) || defined(STAT_STATVFS64) || defined(STAT_STATFS3_OSF1) || defined(STAT_STATFS2_BSIZE) || defined(STAT_STATFS4) || defined(STAT_STATFS2_FSIZE) || defined(STAT_STATFS2_FS_DATA))
+ printf("ERROR: No disk free routine!\n");
+ exit(1);
+#endif
+
+#if !((defined(HAVE_RANDOM) || defined(HAVE_RAND)) && (defined(HAVE_SRANDOM) || defined(HAVE_SRAND)))
+ printf("ERROR: No random or srandom routine!\n");
+ exit(1);
+#endif
+
+ exit(0);
+}
diff --git a/source3/tests/sysquotas.c b/source3/tests/sysquotas.c
new file mode 100644
index 0000000000..bf16c8ba6e
--- /dev/null
+++ b/source3/tests/sysquotas.c
@@ -0,0 +1,98 @@
+/* this test should find out what quota api is available on the os */
+
+ int autoconf_quota(void);
+
+#if defined(HAVE_QUOTACTL_4A)
+/* long quotactl(int cmd, char *special, qid_t id, caddr_t addr) */
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+
+#if defined(HAVE_LINUX_QUOTA_H)
+# include <linux/quota.h>
+# if defined(HAVE_STRUCT_IF_DQBLK)
+# define SYS_DQBLK if_dqblk
+# elif defined(HAVE_STRUCT_MEM_DQBLK)
+# define SYS_DQBLK mem_dqblk
+# endif
+#elif defined(HAVE_SYS_QUOTA_H)
+# include <sys/quota.h>
+#endif
+
+#ifndef SYS_DQBLK
+#define SYS_DQBLK dqblk
+#endif
+
+ int autoconf_quota(void);
+
+ int autoconf_quota(void)
+{
+ int ret = -1;
+ struct SYS_DQBLK D;
+
+ ret = quotactl(Q_GETQUOTA,"/dev/hda1",0,(void *)&D);
+
+ return ret;
+}
+
+#elif defined(HAVE_QUOTACTL_4B)
+/* int quotactl(const char *path, int cmd, int id, char *addr); */
+
+#ifdef HAVE_SYS_QUOTA_H
+#include <sys/quota.h>
+#else /* *BSD */
+#include <sys/types.h>
+#include <ufs/ufs/quota.h>
+#include <machine/param.h>
+#endif
+
+ int autoconf_quota(void)
+{
+ int ret = -1;
+ struct dqblk D;
+
+ ret = quotactl("/",Q_GETQUOTA,0,(char *) &D);
+
+ return ret;
+}
+
+#elif defined(HAVE_QUOTACTL_3)
+/* int quotactl (char *spec, int request, char *arg); */
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_QUOTA_H
+#include <sys/quota.h>
+#endif
+
+ int autoconf_quota(void)
+{
+ int ret = -1;
+ struct q_request request;
+
+ ret = quotactl("/", Q_GETQUOTA, &request);
+
+ return ret;
+}
+
+#elif defined(HAVE_QUOTACTL_2)
+
+#error HAVE_QUOTACTL_2 not implemented
+
+#else
+
+#error Unknow QUOTACTL prototype
+
+#endif
+
+ int main(void)
+{
+ autoconf_quota();
+ return 0;
+}
diff --git a/source3/tests/trivial.c b/source3/tests/trivial.c
new file mode 100644
index 0000000000..2723637a0f
--- /dev/null
+++ b/source3/tests/trivial.c
@@ -0,0 +1,4 @@
+main()
+{
+ exit(0);
+}
diff --git a/source3/torture/cmd_vfs.c b/source3/torture/cmd_vfs.c
new file mode 100644
index 0000000000..28400887ef
--- /dev/null
+++ b/source3/torture/cmd_vfs.c
@@ -0,0 +1,1071 @@
+/*
+ Unix SMB/CIFS implementation.
+ VFS module functions
+
+ Copyright (C) Simo Sorce 2002
+ Copyright (C) Eric Lorimer 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "vfstest.h"
+
+static const char *null_string = "";
+
+static NTSTATUS cmd_load_module(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ int i;
+
+ if (argc < 2) {
+ printf("Usage: load <modules>\n");
+ return NT_STATUS_OK;
+ }
+
+ for (i=argc-1;i>0;i--) {
+ if (!vfs_init_custom(vfs->conn, argv[i])) {
+ DEBUG(0, ("load: (vfs_init_custom failed for %s)\n", argv[i]));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+ printf("load: ok\n");
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_populate(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ char c;
+ size_t size;
+ if (argc != 3) {
+ printf("Usage: populate <char> <size>\n");
+ return NT_STATUS_OK;
+ }
+ c = argv[1][0];
+ size = atoi(argv[2]);
+ vfs->data = TALLOC_ARRAY(mem_ctx, char, size);
+ if (vfs->data == NULL) {
+ printf("populate: error=-1 (not enough memory)");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ memset(vfs->data, c, size);
+ vfs->data_size = size;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_show_data(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ size_t offset;
+ size_t len;
+ if (argc != 1 && argc != 3) {
+ printf("Usage: showdata [<offset> <len>]\n");
+ return NT_STATUS_OK;
+ }
+ if (vfs->data == NULL || vfs->data_size == 0) {
+ printf("show_data: error=-1 (buffer empty)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (argc == 3) {
+ offset = atoi(argv[1]);
+ len = atoi(argv[2]);
+ } else {
+ offset = 0;
+ len = vfs->data_size;
+ }
+ if ((offset + len) > vfs->data_size) {
+ printf("show_data: error=-1 (not enough data in buffer)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ dump_data(0, (uint8 *)(vfs->data) + offset, len);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_connect(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ SMB_VFS_CONNECT(vfs->conn, lp_servicename(SNUM(vfs->conn)), "vfstest");
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_disconnect(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ SMB_VFS_DISCONNECT(vfs->conn);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_disk_free(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ SMB_BIG_UINT diskfree, bsize, dfree, dsize;
+ if (argc != 2) {
+ printf("Usage: disk_free <path>\n");
+ return NT_STATUS_OK;
+ }
+
+ diskfree = SMB_VFS_DISK_FREE(vfs->conn, argv[1], False, &bsize, &dfree, &dsize);
+ printf("disk_free: %lu, bsize = %lu, dfree = %lu, dsize = %lu\n",
+ (unsigned long)diskfree,
+ (unsigned long)bsize,
+ (unsigned long)dfree,
+ (unsigned long)dsize);
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_opendir(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ if (argc != 2) {
+ printf("Usage: opendir <fname>\n");
+ return NT_STATUS_OK;
+ }
+
+ vfs->currentdir = SMB_VFS_OPENDIR(vfs->conn, argv[1], NULL, 0);
+ if (vfs->currentdir == NULL) {
+ printf("opendir error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("opendir: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_readdir(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ SMB_STRUCT_DIRENT *dent;
+
+ if (vfs->currentdir == NULL) {
+ printf("readdir: error=-1 (no open directory)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ dent = SMB_VFS_READDIR(vfs->conn, vfs->currentdir);
+ if (dent == NULL) {
+ printf("readdir: NULL\n");
+ return NT_STATUS_OK;
+ }
+
+ printf("readdir: %s\n", dent->d_name);
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_mkdir(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ if (argc != 2) {
+ printf("Usage: mkdir <path>\n");
+ return NT_STATUS_OK;
+ }
+
+ if (SMB_VFS_MKDIR(vfs->conn, argv[1], 00755) == -1) {
+ printf("mkdir error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("mkdir: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_closedir(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ int ret;
+
+ if (vfs->currentdir == NULL) {
+ printf("closedir: failure (no directory open)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ret = SMB_VFS_CLOSEDIR(vfs->conn, vfs->currentdir);
+ if (ret == -1) {
+ printf("closedir failure: %s\n", strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("closedir: ok\n");
+ vfs->currentdir = NULL;
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_open(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ int flags;
+ mode_t mode;
+ const char *flagstr;
+ files_struct *fsp;
+
+ mode = 00400;
+
+ if (argc < 3 || argc > 5) {
+ printf("Usage: open <filename> <flags> <mode>\n");
+ printf(" flags: O = O_RDONLY\n");
+ printf(" R = O_RDWR\n");
+ printf(" W = O_WRONLY\n");
+ printf(" C = O_CREAT\n");
+ printf(" E = O_EXCL\n");
+ printf(" T = O_TRUNC\n");
+ printf(" A = O_APPEND\n");
+ printf(" N = O_NONBLOCK/O_NDELAY\n");
+#ifdef O_SYNC
+ printf(" S = O_SYNC\n");
+#endif
+#ifdef O_NOFOLLOW
+ printf(" F = O_NOFOLLOW\n");
+#endif
+ printf(" mode: see open.2\n");
+ printf(" mode is ignored if C flag not present\n");
+ printf(" mode defaults to 00400\n");
+ return NT_STATUS_OK;
+ }
+ flags = 0;
+ flagstr = argv[2];
+ while (*flagstr) {
+ switch (*flagstr) {
+ case 'O':
+ flags |= O_RDONLY;
+ break;
+ case 'R':
+ flags |= O_RDWR;
+ break;
+ case 'W':
+ flags |= O_WRONLY;
+ break;
+ case 'C':
+ flags |= O_CREAT;
+ break;
+ case 'E':
+ flags |= O_EXCL;
+ break;
+ case 'T':
+ flags |= O_TRUNC;
+ break;
+ case 'A':
+ flags |= O_APPEND;
+ break;
+ case 'N':
+ flags |= O_NONBLOCK;
+ break;
+#ifdef O_SYNC
+ case 'S':
+ flags |= O_SYNC;
+ break;
+#endif
+#ifdef O_NOFOLLOW
+ case 'F':
+ flags |= O_NOFOLLOW;
+ break;
+#endif
+ default:
+ printf("open: error=-1 (invalid flag!)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ flagstr++;
+ }
+ if ((flags & O_CREAT) && argc == 4) {
+ if (sscanf(argv[3], "%o", &mode) == 0) {
+ printf("open: error=-1 (invalid mode!)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ fsp = SMB_MALLOC_P(struct files_struct);
+ if (fsp == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ fsp->fsp_name = SMB_STRDUP(argv[1]);
+ if (fsp->fsp_name == NULL) {
+ SAFE_FREE(fsp);
+ return NT_STATUS_NO_MEMORY;
+ }
+ fsp->fh = SMB_MALLOC_P(struct fd_handle);
+ if (fsp->fh == NULL) {
+ SAFE_FREE(fsp->fsp_name);
+ SAFE_FREE(fsp);
+ return NT_STATUS_NO_MEMORY;
+ }
+ fsp->conn = vfs->conn;
+
+ fsp->fh->fd = SMB_VFS_OPEN(vfs->conn, argv[1], fsp, flags, mode);
+ if (fsp->fh->fd == -1) {
+ printf("open: error=%d (%s)\n", errno, strerror(errno));
+ SAFE_FREE(fsp->fh);
+ SAFE_FREE(fsp->fsp_name);
+ SAFE_FREE(fsp);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ vfs->files[fsp->fh->fd] = fsp;
+ printf("open: fd=%d\n", fsp->fh->fd);
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_pathfunc(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ int ret = -1;
+
+ if (argc != 2) {
+ printf("Usage: %s <path>\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (strcmp("rmdir", argv[0]) == 0 ) {
+ ret = SMB_VFS_RMDIR(vfs->conn, argv[1]);
+ } else if (strcmp("unlink", argv[0]) == 0 ) {
+ ret = SMB_VFS_UNLINK(vfs->conn, argv[1]);
+ } else if (strcmp("chdir", argv[0]) == 0 ) {
+ ret = SMB_VFS_CHDIR(vfs->conn, argv[1]);
+ } else {
+ printf("%s: error=%d (invalid function name!)\n", argv[0], errno);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (ret == -1) {
+ printf("%s: error=%d (%s)\n", argv[0], errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("%s: ok\n", argv[0]);
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_close(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ int fd, ret;
+
+ if (argc != 2) {
+ printf("Usage: close <fd>\n");
+ return NT_STATUS_OK;
+ }
+
+ fd = atoi(argv[1]);
+ if (vfs->files[fd] == NULL) {
+ printf("close: error=-1 (invalid file descriptor)\n");
+ return NT_STATUS_OK;
+ }
+
+ ret = SMB_VFS_CLOSE(vfs->files[fd]);
+ if (ret == -1 )
+ printf("close: error=%d (%s)\n", errno, strerror(errno));
+ else
+ printf("close: ok\n");
+
+ SAFE_FREE(vfs->files[fd]->fsp_name);
+ SAFE_FREE(vfs->files[fd]->fh);
+ SAFE_FREE(vfs->files[fd]);
+ vfs->files[fd] = NULL;
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_read(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ int fd;
+ size_t size, rsize;
+
+ if (argc != 3) {
+ printf("Usage: read <fd> <size>\n");
+ return NT_STATUS_OK;
+ }
+
+ /* do some error checking on these */
+ fd = atoi(argv[1]);
+ size = atoi(argv[2]);
+ vfs->data = TALLOC_ARRAY(mem_ctx, char, size);
+ if (vfs->data == NULL) {
+ printf("read: error=-1 (not enough memory)");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ vfs->data_size = size;
+
+ rsize = SMB_VFS_READ(vfs->files[fd], vfs->data, size);
+ if (rsize == -1) {
+ printf("read: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("read: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_write(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ int fd, size, wsize;
+
+ if (argc != 3) {
+ printf("Usage: write <fd> <size>\n");
+ return NT_STATUS_OK;
+ }
+
+ /* some error checking should go here */
+ fd = atoi(argv[1]);
+ size = atoi(argv[2]);
+ if (vfs->data == NULL) {
+ printf("write: error=-1 (buffer empty, please populate it before writing)");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (vfs->data_size < size) {
+ printf("write: error=-1 (buffer too small, please put some more data in)");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ wsize = SMB_VFS_WRITE(vfs->files[fd], vfs->data, size);
+
+ if (wsize == -1) {
+ printf("write: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("write: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_lseek(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ int fd, offset, whence;
+ SMB_OFF_T pos;
+
+ if (argc != 4) {
+ printf("Usage: lseek <fd> <offset> <whence>\n...where whence is 1 => SEEK_SET, 2 => SEEK_CUR, 3 => SEEK_END\n");
+ return NT_STATUS_OK;
+ }
+
+ fd = atoi(argv[1]);
+ offset = atoi(argv[2]);
+ whence = atoi(argv[3]);
+ switch (whence) {
+ case 1: whence = SEEK_SET; break;
+ case 2: whence = SEEK_CUR; break;
+ default: whence = SEEK_END;
+ }
+
+ pos = SMB_VFS_LSEEK(vfs->files[fd], offset, whence);
+ if (pos == (SMB_OFF_T)-1) {
+ printf("lseek: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("lseek: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_rename(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ int ret;
+ if (argc != 3) {
+ printf("Usage: rename <old> <new>\n");
+ return NT_STATUS_OK;
+ }
+
+ ret = SMB_VFS_RENAME(vfs->conn, argv[1], argv[2]);
+ if (ret == -1) {
+ printf("rename: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("rename: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_fsync(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ int ret, fd;
+ if (argc != 2) {
+ printf("Usage: fsync <fd>\n");
+ return NT_STATUS_OK;
+ }
+
+ fd = atoi(argv[1]);
+ ret = SMB_VFS_FSYNC(vfs->files[fd]);
+ if (ret == -1) {
+ printf("fsync: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("fsync: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_stat(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ int ret;
+ const char *user;
+ const char *group;
+ struct passwd *pwd = NULL;
+ struct group *grp = NULL;
+ SMB_STRUCT_STAT st;
+
+ if (argc != 2) {
+ printf("Usage: stat <fname>\n");
+ return NT_STATUS_OK;
+ }
+
+ ret = SMB_VFS_STAT(vfs->conn, argv[1], &st);
+ if (ret == -1) {
+ printf("stat: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ pwd = sys_getpwuid(st.st_uid);
+ if (pwd != NULL) user = pwd->pw_name;
+ else user = null_string;
+ grp = sys_getgrgid(st.st_gid);
+ if (grp != NULL) group = grp->gr_name;
+ else group = null_string;
+
+ printf("stat: ok\n");
+ printf(" File: %s", argv[1]);
+ if (S_ISREG(st.st_mode)) printf(" Regular File\n");
+ else if (S_ISDIR(st.st_mode)) printf(" Directory\n");
+ else if (S_ISCHR(st.st_mode)) printf(" Character Device\n");
+ else if (S_ISBLK(st.st_mode)) printf(" Block Device\n");
+ else if (S_ISFIFO(st.st_mode)) printf(" Fifo\n");
+ else if (S_ISLNK(st.st_mode)) printf(" Symbolic Link\n");
+ else if (S_ISSOCK(st.st_mode)) printf(" Socket\n");
+ printf(" Size: %10u", (unsigned int)st.st_size);
+#ifdef HAVE_STAT_ST_BLOCKS
+ printf(" Blocks: %9u", (unsigned int)st.st_blocks);
+#endif
+#ifdef HAVE_STAT_ST_BLKSIZE
+ printf(" IO Block: %u\n", (unsigned int)st.st_blksize);
+#endif
+ printf(" Device: 0x%10x", (unsigned int)st.st_dev);
+ printf(" Inode: %10u", (unsigned int)st.st_ino);
+ printf(" Links: %10u\n", (unsigned int)st.st_nlink);
+ printf(" Access: %05o", (st.st_mode) & 007777);
+ printf(" Uid: %5lu/%.16s Gid: %5lu/%.16s\n", (unsigned long)st.st_uid, user,
+ (unsigned long)st.st_gid, group);
+ printf(" Access: %s", ctime(&(st.st_atime)));
+ printf(" Modify: %s", ctime(&(st.st_mtime)));
+ printf(" Change: %s", ctime(&(st.st_ctime)));
+
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_fstat(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ int fd;
+ const char *user;
+ const char *group;
+ struct passwd *pwd = NULL;
+ struct group *grp = NULL;
+ SMB_STRUCT_STAT st;
+
+ if (argc != 2) {
+ printf("Usage: fstat <fd>\n");
+ return NT_STATUS_OK;
+ }
+
+ fd = atoi(argv[1]);
+ if (fd < 0 || fd >= 1024) {
+ printf("fstat: error=%d (file descriptor out of range)\n", EBADF);
+ return NT_STATUS_OK;
+ }
+
+ if (vfs->files[fd] == NULL) {
+ printf("fstat: error=%d (invalid file descriptor)\n", EBADF);
+ return NT_STATUS_OK;
+ }
+
+ if (SMB_VFS_FSTAT(vfs->files[fd], &st) == -1) {
+ printf("fstat: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ pwd = sys_getpwuid(st.st_uid);
+ if (pwd != NULL) user = pwd->pw_name;
+ else user = null_string;
+ grp = sys_getgrgid(st.st_gid);
+ if (grp != NULL) group = grp->gr_name;
+ else group = null_string;
+
+ printf("fstat: ok\n");
+ if (S_ISREG(st.st_mode)) printf(" Regular File\n");
+ else if (S_ISDIR(st.st_mode)) printf(" Directory\n");
+ else if (S_ISCHR(st.st_mode)) printf(" Character Device\n");
+ else if (S_ISBLK(st.st_mode)) printf(" Block Device\n");
+ else if (S_ISFIFO(st.st_mode)) printf(" Fifo\n");
+ else if (S_ISLNK(st.st_mode)) printf(" Symbolic Link\n");
+ else if (S_ISSOCK(st.st_mode)) printf(" Socket\n");
+ printf(" Size: %10u", (unsigned int)st.st_size);
+#ifdef HAVE_STAT_ST_BLOCKS
+ printf(" Blocks: %9u", (unsigned int)st.st_blocks);
+#endif
+#ifdef HAVE_STAT_ST_BLKSIZE
+ printf(" IO Block: %u\n", (unsigned int)st.st_blksize);
+#endif
+ printf(" Device: 0x%10x", (unsigned int)st.st_dev);
+ printf(" Inode: %10u", (unsigned int)st.st_ino);
+ printf(" Links: %10u\n", (unsigned int)st.st_nlink);
+ printf(" Access: %05o", (st.st_mode) & 007777);
+ printf(" Uid: %5lu/%.16s Gid: %5lu/%.16s\n", (unsigned long)st.st_uid, user,
+ (unsigned long)st.st_gid, group);
+ printf(" Access: %s", ctime(&(st.st_atime)));
+ printf(" Modify: %s", ctime(&(st.st_mtime)));
+ printf(" Change: %s", ctime(&(st.st_ctime)));
+
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_lstat(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ const char *user;
+ const char *group;
+ struct passwd *pwd = NULL;
+ struct group *grp = NULL;
+ SMB_STRUCT_STAT st;
+
+ if (argc != 2) {
+ printf("Usage: lstat <path>\n");
+ return NT_STATUS_OK;
+ }
+
+ if (SMB_VFS_LSTAT(vfs->conn, argv[1], &st) == -1) {
+ printf("lstat: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ pwd = sys_getpwuid(st.st_uid);
+ if (pwd != NULL) user = pwd->pw_name;
+ else user = null_string;
+ grp = sys_getgrgid(st.st_gid);
+ if (grp != NULL) group = grp->gr_name;
+ else group = null_string;
+
+ printf("lstat: ok\n");
+ if (S_ISREG(st.st_mode)) printf(" Regular File\n");
+ else if (S_ISDIR(st.st_mode)) printf(" Directory\n");
+ else if (S_ISCHR(st.st_mode)) printf(" Character Device\n");
+ else if (S_ISBLK(st.st_mode)) printf(" Block Device\n");
+ else if (S_ISFIFO(st.st_mode)) printf(" Fifo\n");
+ else if (S_ISLNK(st.st_mode)) printf(" Symbolic Link\n");
+ else if (S_ISSOCK(st.st_mode)) printf(" Socket\n");
+ printf(" Size: %10u", (unsigned int)st.st_size);
+#ifdef HAVE_STAT_ST_BLOCKS
+ printf(" Blocks: %9u", (unsigned int)st.st_blocks);
+#endif
+#ifdef HAVE_STAT_ST_BLKSIZE
+ printf(" IO Block: %u\n", (unsigned int)st.st_blksize);
+#endif
+ printf(" Device: 0x%10x", (unsigned int)st.st_dev);
+ printf(" Inode: %10u", (unsigned int)st.st_ino);
+ printf(" Links: %10u\n", (unsigned int)st.st_nlink);
+ printf(" Access: %05o", (st.st_mode) & 007777);
+ printf(" Uid: %5lu/%.16s Gid: %5lu/%.16s\n", (unsigned long)st.st_uid, user,
+ (unsigned long)st.st_gid, group);
+ printf(" Access: %s", ctime(&(st.st_atime)));
+ printf(" Modify: %s", ctime(&(st.st_mtime)));
+ printf(" Change: %s", ctime(&(st.st_ctime)));
+
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_chmod(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ mode_t mode;
+ if (argc != 3) {
+ printf("Usage: chmod <path> <mode>\n");
+ return NT_STATUS_OK;
+ }
+
+ mode = atoi(argv[2]);
+ if (SMB_VFS_CHMOD(vfs->conn, argv[1], mode) == -1) {
+ printf("chmod: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("chmod: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_fchmod(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ int fd;
+ mode_t mode;
+ if (argc != 3) {
+ printf("Usage: fchmod <fd> <mode>\n");
+ return NT_STATUS_OK;
+ }
+
+ fd = atoi(argv[1]);
+ mode = atoi(argv[2]);
+ if (fd < 0 || fd >= 1024) {
+ printf("fchmod: error=%d (file descriptor out of range)\n", EBADF);
+ return NT_STATUS_OK;
+ }
+ if (vfs->files[fd] == NULL) {
+ printf("fchmod: error=%d (invalid file descriptor)\n", EBADF);
+ return NT_STATUS_OK;
+ }
+
+ if (SMB_VFS_FCHMOD(vfs->files[fd], mode) == -1) {
+ printf("fchmod: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("fchmod: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_chown(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ uid_t uid;
+ gid_t gid;
+ if (argc != 4) {
+ printf("Usage: chown <path> <uid> <gid>\n");
+ return NT_STATUS_OK;
+ }
+
+ uid = atoi(argv[2]);
+ gid = atoi(argv[3]);
+ if (SMB_VFS_CHOWN(vfs->conn, argv[1], uid, gid) == -1) {
+ printf("chown: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("chown: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_fchown(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ uid_t uid;
+ gid_t gid;
+ int fd;
+ if (argc != 4) {
+ printf("Usage: fchown <fd> <uid> <gid>\n");
+ return NT_STATUS_OK;
+ }
+
+ uid = atoi(argv[2]);
+ gid = atoi(argv[3]);
+ fd = atoi(argv[1]);
+ if (fd < 0 || fd >= 1024) {
+ printf("fchown: faliure=%d (file descriptor out of range)\n", EBADF);
+ return NT_STATUS_OK;
+ }
+ if (vfs->files[fd] == NULL) {
+ printf("fchown: error=%d (invalid file descriptor)\n", EBADF);
+ return NT_STATUS_OK;
+ }
+ if (SMB_VFS_FCHOWN(vfs->files[fd], uid, gid) == -1) {
+ printf("fchown error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("fchown: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_getwd(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ char buf[PATH_MAX];
+ if (SMB_VFS_GETWD(vfs->conn, buf) == NULL) {
+ printf("getwd: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("getwd: %s\n", buf);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_utime(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ struct timespec ts[2];
+ if (argc != 4) {
+ printf("Usage: utime <path> <access> <modify>\n");
+ return NT_STATUS_OK;
+ }
+ ts[0] = convert_time_t_to_timespec(atoi(argv[2]));
+ ts[1] = convert_time_t_to_timespec(atoi(argv[3]));
+ if (SMB_VFS_NTIMES(vfs->conn, argv[1], ts) != 0) {
+ printf("utime: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("utime: ok\n");
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_ftruncate(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ int fd;
+ SMB_OFF_T off;
+ if (argc != 3) {
+ printf("Usage: ftruncate <fd> <length>\n");
+ return NT_STATUS_OK;
+ }
+
+ fd = atoi(argv[1]);
+ off = atoi(argv[2]);
+ if (fd < 0 || fd >= 1024) {
+ printf("ftruncate: error=%d (file descriptor out of range)\n", EBADF);
+ return NT_STATUS_OK;
+ }
+ if (vfs->files[fd] == NULL) {
+ printf("ftruncate: error=%d (invalid file descriptor)\n", EBADF);
+ return NT_STATUS_OK;
+ }
+
+ if (SMB_VFS_FTRUNCATE(vfs->files[fd], off) == -1) {
+ printf("ftruncate: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("ftruncate: ok\n");
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_lock(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ int fd;
+ int op;
+ long offset;
+ long count;
+ int type;
+ const char *typestr;
+
+ if (argc != 6) {
+ printf("Usage: lock <fd> <op> <offset> <count> <type>\n");
+ printf(" ops: G = F_GETLK\n");
+ printf(" S = F_SETLK\n");
+ printf(" W = F_SETLKW\n");
+ printf(" type: R = F_RDLCK\n");
+ printf(" W = F_WRLCK\n");
+ printf(" U = F_UNLCK\n");
+ return NT_STATUS_OK;
+ }
+
+ if (sscanf(argv[1], "%d", &fd) == 0) {
+ printf("lock: error=-1 (error parsing fd)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ op = 0;
+ switch (*argv[2]) {
+ case 'G':
+ op = F_GETLK;
+ break;
+ case 'S':
+ op = F_SETLK;
+ break;
+ case 'W':
+ op = F_SETLKW;
+ break;
+ default:
+ printf("lock: error=-1 (invalid op flag!)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (sscanf(argv[3], "%ld", &offset) == 0) {
+ printf("lock: error=-1 (error parsing fd)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (sscanf(argv[4], "%ld", &count) == 0) {
+ printf("lock: error=-1 (error parsing fd)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ type = 0;
+ typestr = argv[5];
+ while(*typestr) {
+ switch (*typestr) {
+ case 'R':
+ type |= F_RDLCK;
+ break;
+ case 'W':
+ type |= F_WRLCK;
+ break;
+ case 'U':
+ type |= F_UNLCK;
+ break;
+ default:
+ printf("lock: error=-1 (invalid type flag!)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ typestr++;
+ }
+
+ printf("lock: debug lock(fd=%d, op=%d, offset=%ld, count=%ld, type=%d))\n", fd, op, offset, count, type);
+
+ if (SMB_VFS_LOCK(vfs->files[fd], op, offset, count, type) == False) {
+ printf("lock: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("lock: ok\n");
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_symlink(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ if (argc != 3) {
+ printf("Usage: symlink <path> <link>\n");
+ return NT_STATUS_OK;
+ }
+
+ if (SMB_VFS_SYMLINK(vfs->conn, argv[1], argv[2]) == -1) {
+ printf("symlink: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("symlink: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_readlink(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ char buffer[PATH_MAX];
+ int size;
+
+ if (argc != 2) {
+ printf("Usage: readlink <path>\n");
+ return NT_STATUS_OK;
+ }
+
+ if ((size = SMB_VFS_READLINK(vfs->conn, argv[1], buffer, PATH_MAX)) == -1) {
+ printf("readlink: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ buffer[size] = '\0';
+ printf("readlink: %s\n", buffer);
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_link(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ if (argc != 3) {
+ printf("Usage: link <path> <link>\n");
+ return NT_STATUS_OK;
+ }
+
+ if (SMB_VFS_LINK(vfs->conn, argv[1], argv[2]) == -1) {
+ printf("link: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("link: ok\n");
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_mknod(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ mode_t mode;
+ unsigned int dev_val;
+ SMB_DEV_T dev;
+
+ if (argc != 4) {
+ printf("Usage: mknod <path> <mode> <dev>\n");
+ printf(" mode is octal\n");
+ printf(" dev is hex\n");
+ return NT_STATUS_OK;
+ }
+
+ if (sscanf(argv[2], "%o", &mode) == 0) {
+ printf("open: error=-1 (invalid mode!)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (sscanf(argv[3], "%x", &dev_val) == 0) {
+ printf("open: error=-1 (invalid dev!)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ dev = (SMB_DEV_T)dev_val;
+
+ if (SMB_VFS_MKNOD(vfs->conn, argv[1], mode, dev) == -1) {
+ printf("mknod: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("mknod: ok\n");
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_realpath(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ char respath[PATH_MAX];
+
+ if (argc != 2) {
+ printf("Usage: realpath <path>\n");
+ return NT_STATUS_OK;
+ }
+
+ if (SMB_VFS_REALPATH(vfs->conn, argv[1], respath) == NULL) {
+ printf("realpath: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("realpath: ok\n");
+ return NT_STATUS_OK;
+}
+
+struct cmd_set vfs_commands[] = {
+
+ { "VFS Commands" },
+
+ { "load", cmd_load_module, "Load a module", "load <module.so>" },
+ { "populate", cmd_populate, "Populate a data buffer", "populate <char> <size>" },
+ { "showdata", cmd_show_data, "Show data currently in data buffer", "show_data [<offset> <len>]"},
+ { "connect", cmd_connect, "VFS connect()", "connect" },
+ { "disconnect", cmd_disconnect, "VFS disconnect()", "disconnect" },
+ { "disk_free", cmd_disk_free, "VFS disk_free()", "disk_free <path>" },
+ { "opendir", cmd_opendir, "VFS opendir()", "opendir <fname>" },
+ { "readdir", cmd_readdir, "VFS readdir()", "readdir" },
+ { "mkdir", cmd_mkdir, "VFS mkdir()", "mkdir <path>" },
+ { "rmdir", cmd_pathfunc, "VFS rmdir()", "rmdir <path>" },
+ { "closedir", cmd_closedir, "VFS closedir()", "closedir" },
+ { "open", cmd_open, "VFS open()", "open <fname>" },
+ { "close", cmd_close, "VFS close()", "close <fd>" },
+ { "read", cmd_read, "VFS read()", "read <fd> <size>" },
+ { "write", cmd_write, "VFS write()", "write <fd> <size>" },
+ { "lseek", cmd_lseek, "VFS lseek()", "lseek <fd> <offset> <whence>" },
+ { "rename", cmd_rename, "VFS rename()", "rename <old> <new>" },
+ { "fsync", cmd_fsync, "VFS fsync()", "fsync <fd>" },
+ { "stat", cmd_stat, "VFS stat()", "stat <fname>" },
+ { "fstat", cmd_fstat, "VFS fstat()", "fstat <fd>" },
+ { "lstat", cmd_lstat, "VFS lstat()", "lstat <fname>" },
+ { "unlink", cmd_pathfunc, "VFS unlink()", "unlink <fname>" },
+ { "chmod", cmd_chmod, "VFS chmod()", "chmod <path> <mode>" },
+ { "fchmod", cmd_fchmod, "VFS fchmod()", "fchmod <fd> <mode>" },
+ { "chown", cmd_chown, "VFS chown()", "chown <path> <uid> <gid>" },
+ { "fchown", cmd_fchown, "VFS fchown()", "fchown <fd> <uid> <gid>" },
+ { "chdir", cmd_pathfunc, "VFS chdir()", "chdir <path>" },
+ { "getwd", cmd_getwd, "VFS getwd()", "getwd" },
+ { "utime", cmd_utime, "VFS utime()", "utime <path> <access> <modify>" },
+ { "ftruncate", cmd_ftruncate, "VFS ftruncate()", "ftruncate <fd> <length>" },
+ { "lock", cmd_lock, "VFS lock()", "lock <f> <op> <offset> <count> <type>" },
+ { "symlink", cmd_symlink, "VFS symlink()", "symlink <old> <new>" },
+ { "readlink", cmd_readlink, "VFS readlink()", "readlink <path>" },
+ { "link", cmd_link, "VFS link()", "link <oldpath> <newpath>" },
+ { "mknod", cmd_mknod, "VFS mknod()", "mknod <path> <mode> <dev>" },
+ { "realpath", cmd_realpath, "VFS realpath()", "realpath <path>" },
+ { NULL }
+};
diff --git a/source3/torture/denytest.c b/source3/torture/denytest.c
new file mode 100644
index 0000000000..9b08552df7
--- /dev/null
+++ b/source3/torture/denytest.c
@@ -0,0 +1,1574 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester - scanning functions
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern bool torture_showall;
+
+enum deny_result {A_0=0, A_X=1, A_R=2, A_W=3, A_RW=5};
+
+
+static const char *denystr(int denymode)
+{
+ struct {
+ int v;
+ const char *name;
+ } deny_modes[] = {
+ {DENY_DOS, "DENY_DOS"},
+ {DENY_ALL, "DENY_ALL"},
+ {DENY_WRITE, "DENY_WRITE"},
+ {DENY_READ, "DENY_READ"},
+ {DENY_NONE, "DENY_NONE"},
+ {DENY_FCB, "DENY_FCB"},
+ {-1, NULL}};
+ int i;
+ for (i=0;deny_modes[i].name;i++) {
+ if (deny_modes[i].v == denymode) return deny_modes[i].name;
+ }
+ return "DENY_XXX";
+}
+
+static const char *openstr(int mode)
+{
+ struct {
+ int v;
+ const char *name;
+ } open_modes[] = {
+ {O_RDWR, "O_RDWR"},
+ {O_RDONLY, "O_RDONLY"},
+ {O_WRONLY, "O_WRONLY"},
+ {-1, NULL}};
+ int i;
+ for (i=0;open_modes[i].name;i++) {
+ if (open_modes[i].v == mode) return open_modes[i].name;
+ }
+ return "O_XXX";
+}
+
+static const char *resultstr(enum deny_result res)
+{
+ struct {
+ enum deny_result res;
+ const char *name;
+ } results[] = {
+ {A_X, "X"},
+ {A_0, "-"},
+ {A_R, "R"},
+ {A_W, "W"},
+ {A_RW,"RW"}};
+ int i;
+ for (i=0;ARRAY_SIZE(results);i++) {
+ if (results[i].res == res) return results[i].name;
+ }
+ return "*";
+}
+
+static struct {
+ int isexe;
+ int mode1, deny1;
+ int mode2, deny2;
+ enum deny_result result;
+} denytable2[] = {
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_READ, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_READ, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_R},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_W},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_READ, A_W},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_RW},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_W},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_READ, A_RW},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_READ, A_R},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_READ, A_W},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_0}
+};
+
+
+static struct {
+ int isexe;
+ int mode1, deny1;
+ int mode2, deny2;
+ enum deny_result result;
+} denytable1[] = {
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_READ, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_READ, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_FCB, A_RW},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_RW},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_FCB, A_RW},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_FCB, A_RW},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_RW},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_R},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_W},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_READ, A_W},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_RW},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_W},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_READ, A_RW},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_READ, A_R},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_READ, A_W},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_FCB, A_RW},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_RW},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_RW}
+};
+
+
+static void progress_bar(unsigned i, unsigned total)
+{
+ if (i % 10 != 0) return;
+ printf("%5d/%5d\r", i, total);
+ fflush(stdout);
+}
+
+/*
+ this produces a matrix of deny mode behaviour for 1 connection
+ */
+bool torture_denytest1(int dummy)
+{
+ struct cli_state *cli1;
+ int fnum1, fnum2;
+ int i;
+ bool correct = True;
+ const char *fnames[2] = {"\\denytest1.dat", "\\denytest1.exe"};
+
+ if (!torture_open_connection(&cli1, 0)) {
+ return False;
+ }
+
+ printf("starting denytest1\n");
+
+ for (i=0;i<2;i++) {
+ cli_unlink(cli1, fnames[i]);
+ fnum1 = cli_open(cli1, fnames[i], O_RDWR|O_CREAT, DENY_NONE);
+ cli_write(cli1, fnum1, 0, fnames[i], 0, strlen(fnames[i]));
+ cli_close(cli1, fnum1);
+ }
+
+ printf("testing %ld entries\n", (unsigned long)ARRAY_SIZE(denytable1));
+
+ for (i=0; i<ARRAY_SIZE(denytable1); i++) {
+ enum deny_result res;
+ const char *fname = fnames[denytable1[i].isexe];
+
+ progress_bar(i, ARRAY_SIZE(denytable1));
+
+ fnum1 = cli_open(cli1, fname,
+ denytable1[i].mode1,
+ denytable1[i].deny1);
+ fnum2 = cli_open(cli1, fname,
+ denytable1[i].mode2,
+ denytable1[i].deny2);
+
+ if (fnum1 == -1) {
+ res = A_X;
+ } else if (fnum2 == -1) {
+ res = A_0;
+ } else {
+ char x = 1;
+ res = A_0;
+ if (cli_read(cli1, fnum2, (char *)&x, 0, 1) == 1) {
+ res += A_R;
+ }
+ if (cli_write(cli1, fnum2, 0, (char *)&x, 0, 1) == 1) {
+ res += A_W;
+ }
+ }
+
+ if (res != denytable1[i].result) {
+ correct = False;
+ }
+
+ if (torture_showall || res != denytable1[i].result) {
+ printf("%s %8s %10s %8s %10s %s (correct=%s)\n",
+ fname,
+ denystr(denytable1[i].deny1),
+ openstr(denytable1[i].mode1),
+ denystr(denytable1[i].deny2),
+ openstr(denytable1[i].mode2),
+ resultstr(res),
+ resultstr(denytable1[i].result));
+ }
+
+ cli_close(cli1, fnum1);
+ cli_close(cli1, fnum2);
+ }
+
+ for (i=0;i<2;i++) {
+ cli_unlink(cli1, fnames[i]);
+ }
+
+ if (!torture_close_connection(cli1)) {
+ correct = False;
+ }
+
+ printf("finshed denytest1\n");
+ return correct;
+}
+
+
+/*
+ this produces a matrix of deny mode behaviour with 2 connections
+ */
+bool torture_denytest2(int dummy)
+{
+ static struct cli_state *cli1, *cli2;
+ int fnum1, fnum2;
+ int i;
+ bool correct = True;
+ const char *fnames[2] = {"\\denytest2.dat", "\\denytest2.exe"};
+
+ if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
+ return False;
+ }
+
+ printf("starting denytest2\n");
+
+ for (i=0;i<2;i++) {
+ cli_unlink(cli1, fnames[i]);
+ fnum1 = cli_open(cli1, fnames[i], O_RDWR|O_CREAT, DENY_NONE);
+ cli_write(cli1, fnum1, 0, fnames[i], 0, strlen(fnames[i]));
+ cli_close(cli1, fnum1);
+ }
+
+ for (i=0; i<ARRAY_SIZE(denytable2); i++) {
+ enum deny_result res;
+ const char *fname = fnames[denytable2[i].isexe];
+
+ progress_bar(i, ARRAY_SIZE(denytable2));
+
+ fnum1 = cli_open(cli1, fname,
+ denytable2[i].mode1,
+ denytable2[i].deny1);
+ fnum2 = cli_open(cli2, fname,
+ denytable2[i].mode2,
+ denytable2[i].deny2);
+
+ if (fnum1 == -1) {
+ res = A_X;
+ } else if (fnum2 == -1) {
+ res = A_0;
+ } else {
+ char x = 1;
+ res = A_0;
+ if (cli_read(cli2, fnum2, (char *)&x, 0, 1) == 1) {
+ res += A_R;
+ }
+ if (cli_write(cli2, fnum2, 0, (char *)&x, 0, 1) == 1) {
+ res += A_W;
+ }
+ }
+
+ if (res != denytable2[i].result) {
+ correct = False;
+ }
+
+ if (torture_showall || res != denytable2[i].result) {
+ printf("%s %8s %10s %8s %10s %s (correct=%s)\n",
+ fname,
+ denystr(denytable2[i].deny1),
+ openstr(denytable2[i].mode1),
+ denystr(denytable2[i].deny2),
+ openstr(denytable2[i].mode2),
+ resultstr(res),
+ resultstr(denytable2[i].result));
+ }
+
+ if (fnum1 != -1) cli_close(cli1, fnum1);
+ if (fnum2 != -1) cli_close(cli2, fnum2);
+ }
+
+ for (i=0;i<2;i++) {
+ cli_unlink(cli1, fnames[i]);
+ }
+
+ if (!torture_close_connection(cli1)) {
+ correct = False;
+ }
+ if (!torture_close_connection(cli2)) {
+ correct = False;
+ }
+
+ printf("finshed denytest2\n");
+ return correct;
+}
+
diff --git a/source3/torture/locktest.c b/source3/torture/locktest.c
new file mode 100644
index 0000000000..2ba5ab8f06
--- /dev/null
+++ b/source3/torture/locktest.c
@@ -0,0 +1,707 @@
+/*
+ Unix SMB/CIFS implementation.
+ randomised byte range lock tester
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static fstring password[2];
+static fstring username[2];
+static int got_user;
+static int got_pass;
+static bool use_kerberos;
+static int numops = 1000;
+static bool showall;
+static bool analyze;
+static bool hide_unlock_fails;
+static bool use_oplocks;
+static unsigned lock_range = 100;
+static unsigned lock_base = 0;
+static unsigned min_length = 0;
+static bool exact_error_codes;
+static bool zero_zero;
+
+extern char *optarg;
+extern int optind;
+
+#define FILENAME "\\locktest.dat"
+
+#define READ_PCT 50
+#define LOCK_PCT 45
+#define UNLOCK_PCT 70
+#define RANGE_MULTIPLE 1
+#define NSERVERS 2
+#define NCONNECTIONS 2
+#define NFILES 2
+#define LOCK_TIMEOUT 0
+
+#define NASTY_POSIX_LOCK_HACK 0
+
+enum lock_op {OP_LOCK, OP_UNLOCK, OP_REOPEN};
+
+static const char *lock_op_type(int op)
+{
+ if (op == WRITE_LOCK) return "write";
+ else if (op == READ_LOCK) return "read";
+ else return "other";
+}
+
+static const char *lock_op_name(enum lock_op op)
+{
+ if (op == OP_LOCK) return "lock";
+ else if (op == OP_UNLOCK) return "unlock";
+ else return "reopen";
+}
+
+struct record {
+ enum lock_op lock_op;
+ enum brl_type lock_type;
+ char conn, f;
+ SMB_BIG_UINT start, len;
+ char needed;
+};
+
+#define PRESETS 0
+
+#if PRESETS
+static struct record preset[] = {
+{OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 3, 0, 1},
+{OP_UNLOCK, 0 , 0, 0, 2, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, READ_LOCK, 0, 0, 1, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 3, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 1, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, READ_LOCK, 0, 0, 1, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, READ_LOCK, 0, 0, 3, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+};
+#endif
+
+static struct record *recorded;
+
+static void print_brl(struct file_id id,
+ struct server_id pid,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ br_off start,
+ br_off size,
+ void *private_data)
+{
+#if NASTY_POSIX_LOCK_HACK
+ {
+ static SMB_INO_T lastino;
+
+ if (lastino != ino) {
+ char *cmd;
+ if (asprintf(&cmd,
+ "egrep POSIX.*%u /proc/locks", (int)ino) > 0) {
+ system(cmd);
+ SAFE_FREE(cmd);
+ }
+ }
+ lastino = ino;
+ }
+#endif
+
+ printf("%s %s %s %.0f:%.0f(%.0f)\n",
+ procid_str_static(&pid), file_id_string_tos(&id),
+ lock_type==READ_LOCK?"R":"W",
+ (double)start, (double)start+size-1,(double)size);
+
+}
+
+
+static void show_locks(void)
+{
+ brl_forall(print_brl, NULL);
+ /* system("cat /proc/locks"); */
+}
+
+
+/*****************************************************
+return a connection to a server
+*******************************************************/
+static struct cli_state *connect_one(char *share, int snum)
+{
+ struct cli_state *c;
+ struct nmb_name called, calling;
+ char *server_n;
+ fstring server;
+ struct sockaddr_storage ss;
+ fstring myname;
+ static int count;
+ NTSTATUS status;
+
+ fstrcpy(server,share+2);
+ share = strchr_m(server,'\\');
+ if (!share) return NULL;
+ *share = 0;
+ share++;
+
+ server_n = server;
+
+ zero_addr(&ss);
+
+ slprintf(myname,sizeof(myname), "lock-%lu-%u", (unsigned long)getpid(), count++);
+
+ make_nmb_name(&calling, myname, 0x0);
+ make_nmb_name(&called , server, 0x20);
+
+ again:
+ zero_addr(&ss);
+
+ /* have to open a new connection */
+ if (!(c=cli_initialise())) {
+ DEBUG(0,("Connection to %s failed\n", server_n));
+ return NULL;
+ }
+
+ status = cli_connect(c, server_n, &ss);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Connection to %s failed. Error %s\n", server_n, nt_errstr(status) ));
+ return NULL;
+ }
+
+ c->use_kerberos = use_kerberos;
+
+ if (!cli_session_request(c, &calling, &called)) {
+ DEBUG(0,("session request to %s failed\n", called.name));
+ cli_shutdown(c);
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ }
+ return NULL;
+ }
+
+ DEBUG(4,(" session request ok\n"));
+
+ if (!cli_negprot(c)) {
+ DEBUG(0,("protocol negotiation failed\n"));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ if (!got_pass) {
+ char *pass = getpass("Password: ");
+ if (pass) {
+ fstrcpy(password[0], pass);
+ fstrcpy(password[1], pass);
+ }
+ }
+
+ if (got_pass == 1) {
+ fstrcpy(password[1], password[0]);
+ fstrcpy(username[1], username[0]);
+ }
+
+ if (!NT_STATUS_IS_OK(cli_session_setup(c, username[snum],
+ password[snum],
+ strlen(password[snum]),
+ password[snum],
+ strlen(password[snum]),
+ lp_workgroup()))) {
+ DEBUG(0,("session setup failed: %s\n", cli_errstr(c)));
+ return NULL;
+ }
+
+ /*
+ * These next two lines are needed to emulate
+ * old client behaviour for people who have
+ * scripts based on client output.
+ * QUESTION ? Do we want to have a 'client compatibility
+ * mode to turn these on/off ? JRA.
+ */
+
+ if (*c->server_domain || *c->server_os || *c->server_type)
+ DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
+ c->server_domain,c->server_os,c->server_type));
+
+ DEBUG(4,(" session setup ok\n"));
+
+ if (!cli_send_tconX(c, share, "?????",
+ password[snum], strlen(password[snum])+1)) {
+ DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ DEBUG(4,(" tconx ok\n"));
+
+ c->use_oplocks = use_oplocks;
+
+ return c;
+}
+
+
+static void reconnect(struct cli_state *cli[NSERVERS][NCONNECTIONS], int fnum[NSERVERS][NCONNECTIONS][NFILES],
+ char *share[NSERVERS])
+{
+ int server, conn, f;
+
+ for (server=0;server<NSERVERS;server++)
+ for (conn=0;conn<NCONNECTIONS;conn++) {
+ if (cli[server][conn]) {
+ for (f=0;f<NFILES;f++) {
+ if (fnum[server][conn][f] != -1) {
+ cli_close(cli[server][conn], fnum[server][conn][f]);
+ fnum[server][conn][f] = -1;
+ }
+ }
+ cli_ulogoff(cli[server][conn]);
+ cli_shutdown(cli[server][conn]);
+ }
+ cli[server][conn] = connect_one(share[server], server);
+ if (!cli[server][conn]) {
+ DEBUG(0,("Failed to connect to %s\n", share[server]));
+ exit(1);
+ }
+ }
+}
+
+
+
+static bool test_one(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ int fnum[NSERVERS][NCONNECTIONS][NFILES],
+ struct record *rec)
+{
+ unsigned conn = rec->conn;
+ unsigned f = rec->f;
+ SMB_BIG_UINT start = rec->start;
+ SMB_BIG_UINT len = rec->len;
+ enum brl_type op = rec->lock_type;
+ int server;
+ bool ret[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ switch (rec->lock_op) {
+ case OP_LOCK:
+ /* set a lock */
+ for (server=0;server<NSERVERS;server++) {
+ ret[server] = cli_lock64(cli[server][conn],
+ fnum[server][conn][f],
+ start, len, LOCK_TIMEOUT, op);
+ status[server] = cli_nt_error(cli[server][conn]);
+ if (!exact_error_codes &&
+ NT_STATUS_EQUAL(status[server],
+ NT_STATUS_FILE_LOCK_CONFLICT)) {
+ status[server] = NT_STATUS_LOCK_NOT_GRANTED;
+ }
+ }
+ if (showall || !NT_STATUS_EQUAL(status[0],status[1])) {
+ printf("lock conn=%u f=%u range=%.0f(%.0f) op=%s -> %s:%s\n",
+ conn, f,
+ (double)start, (double)len,
+ op==READ_LOCK?"READ_LOCK":"WRITE_LOCK",
+ nt_errstr(status[0]), nt_errstr(status[1]));
+ }
+ if (showall || !NT_STATUS_EQUAL(status[0],status[1])) show_locks();
+ if (!NT_STATUS_EQUAL(status[0],status[1])) return False;
+ break;
+
+ case OP_UNLOCK:
+ /* unset a lock */
+ for (server=0;server<NSERVERS;server++) {
+ ret[server] = cli_unlock64(cli[server][conn],
+ fnum[server][conn][f],
+ start, len);
+ status[server] = cli_nt_error(cli[server][conn]);
+ }
+ if (showall ||
+ (!hide_unlock_fails && !NT_STATUS_EQUAL(status[0],status[1]))) {
+ printf("unlock conn=%u f=%u range=%.0f(%.0f) -> %s:%s\n",
+ conn, f,
+ (double)start, (double)len,
+ nt_errstr(status[0]), nt_errstr(status[1]));
+ }
+ if (showall || !NT_STATUS_EQUAL(status[0],status[1])) show_locks();
+ if (!hide_unlock_fails && !NT_STATUS_EQUAL(status[0],status[1]))
+ return False;
+ break;
+
+ case OP_REOPEN:
+ /* reopen the file */
+ for (server=0;server<NSERVERS;server++) {
+ cli_close(cli[server][conn], fnum[server][conn][f]);
+ fnum[server][conn][f] = -1;
+ }
+ for (server=0;server<NSERVERS;server++) {
+ fnum[server][conn][f] = cli_open(cli[server][conn], FILENAME,
+ O_RDWR|O_CREAT,
+ DENY_NONE);
+ if (fnum[server][conn][f] == -1) {
+ printf("failed to reopen on share%d\n", server);
+ return False;
+ }
+ }
+ if (showall) {
+ printf("reopen conn=%u f=%u\n",
+ conn, f);
+ show_locks();
+ }
+ break;
+ }
+
+ return True;
+}
+
+static void close_files(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ int fnum[NSERVERS][NCONNECTIONS][NFILES])
+{
+ int server, conn, f;
+
+ for (server=0;server<NSERVERS;server++)
+ for (conn=0;conn<NCONNECTIONS;conn++)
+ for (f=0;f<NFILES;f++) {
+ if (fnum[server][conn][f] != -1) {
+ cli_close(cli[server][conn], fnum[server][conn][f]);
+ fnum[server][conn][f] = -1;
+ }
+ }
+ for (server=0;server<NSERVERS;server++) {
+ cli_unlink(cli[server][0], FILENAME);
+ }
+}
+
+static void open_files(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ int fnum[NSERVERS][NCONNECTIONS][NFILES])
+{
+ int server, conn, f;
+
+ for (server=0;server<NSERVERS;server++)
+ for (conn=0;conn<NCONNECTIONS;conn++)
+ for (f=0;f<NFILES;f++) {
+ fnum[server][conn][f] = cli_open(cli[server][conn], FILENAME,
+ O_RDWR|O_CREAT,
+ DENY_NONE);
+ if (fnum[server][conn][f] == -1) {
+ fprintf(stderr,"Failed to open fnum[%u][%u][%u]\n",
+ server, conn, f);
+ exit(1);
+ }
+ }
+}
+
+
+static int retest(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ int fnum[NSERVERS][NCONNECTIONS][NFILES],
+ int n)
+{
+ int i;
+ printf("testing %u ...\n", n);
+ for (i=0; i<n; i++) {
+ if (i && i % 100 == 0) {
+ printf("%u\n", i);
+ }
+
+ if (recorded[i].needed &&
+ !test_one(cli, fnum, &recorded[i])) return i;
+ }
+ return n;
+}
+
+
+/* each server has two connections open to it. Each connection has two file
+ descriptors open on the file - 8 file descriptors in total
+
+ we then do random locking ops in tamdem on the 4 fnums from each
+ server and ensure that the results match
+ */
+static void test_locks(char *share[NSERVERS])
+{
+ struct cli_state *cli[NSERVERS][NCONNECTIONS];
+ int fnum[NSERVERS][NCONNECTIONS][NFILES];
+ int n, i, n1, skip, r1, r2;
+
+ ZERO_STRUCT(fnum);
+ ZERO_STRUCT(cli);
+
+ recorded = SMB_MALLOC_ARRAY(struct record, numops);
+
+ for (n=0; n<numops; n++) {
+#if PRESETS
+ if (n < sizeof(preset) / sizeof(preset[0])) {
+ recorded[n] = preset[n];
+ } else {
+#endif
+ recorded[n].conn = random() % NCONNECTIONS;
+ recorded[n].f = random() % NFILES;
+ recorded[n].start = lock_base + ((unsigned)random() % (lock_range-1));
+ recorded[n].len = min_length +
+ random() % (lock_range-(recorded[n].start-lock_base));
+ recorded[n].start *= RANGE_MULTIPLE;
+ recorded[n].len *= RANGE_MULTIPLE;
+ r1 = random() % 100;
+ r2 = random() % 100;
+ if (r1 < READ_PCT) {
+ recorded[n].lock_type = READ_LOCK;
+ } else {
+ recorded[n].lock_type = WRITE_LOCK;
+ }
+ if (r2 < LOCK_PCT) {
+ recorded[n].lock_op = OP_LOCK;
+ } else if (r2 < UNLOCK_PCT) {
+ recorded[n].lock_op = OP_UNLOCK;
+ } else {
+ recorded[n].lock_op = OP_REOPEN;
+ }
+ recorded[n].needed = True;
+ if (!zero_zero && recorded[n].start==0 && recorded[n].len==0) {
+ recorded[n].len = 1;
+ }
+#if PRESETS
+ }
+#endif
+ }
+
+ reconnect(cli, fnum, share);
+ open_files(cli, fnum);
+ n = retest(cli, fnum, numops);
+
+ if (n == numops || !analyze) return;
+ n++;
+
+ skip = n/2;
+
+ while (1) {
+ n1 = n;
+
+ close_files(cli, fnum);
+ reconnect(cli, fnum, share);
+ open_files(cli, fnum);
+
+ for (i=0;i<n-skip;i+=skip) {
+ int m, j;
+ printf("excluding %d-%d\n", i, i+skip-1);
+ for (j=i;j<i+skip;j++) {
+ recorded[j].needed = False;
+ }
+
+ close_files(cli, fnum);
+ open_files(cli, fnum);
+
+ m = retest(cli, fnum, n);
+ if (m == n) {
+ for (j=i;j<i+skip;j++) {
+ recorded[j].needed = True;
+ }
+ } else {
+ if (i+(skip-1) < m) {
+ memmove(&recorded[i], &recorded[i+skip],
+ (m-(i+skip-1))*sizeof(recorded[0]));
+ }
+ n = m-(skip-1);
+ i--;
+ }
+ }
+
+ if (skip > 1) {
+ skip = skip/2;
+ printf("skip=%d\n", skip);
+ continue;
+ }
+
+ if (n1 == n) break;
+ }
+
+ close_files(cli, fnum);
+ reconnect(cli, fnum, share);
+ open_files(cli, fnum);
+ showall = True;
+ n1 = retest(cli, fnum, n);
+ if (n1 != n-1) {
+ printf("ERROR - inconsistent result (%u %u)\n", n1, n);
+ }
+ close_files(cli, fnum);
+
+ for (i=0;i<n;i++) {
+ printf("{%s, %s, conn = %u, file = %u, start = %.0f, len = %.0f, %u},\n",
+ lock_op_name(recorded[i].lock_op),
+ lock_op_type(recorded[i].lock_type),
+ recorded[i].conn,
+ recorded[i].f,
+ (double)recorded[i].start,
+ (double)recorded[i].len,
+ recorded[i].needed);
+ }
+}
+
+
+
+static void usage(void)
+{
+ printf(
+"Usage:\n\
+ locktest //server1/share1 //server2/share2 [options..]\n\
+ options:\n\
+ -U user%%pass (may be specified twice)\n\
+ -k use kerberos\n\
+ -s seed\n\
+ -o numops\n\
+ -u hide unlock fails\n\
+ -a (show all ops)\n\
+ -A analyse for minimal ops\n\
+ -O use oplocks\n\
+ -E enable exact error code checking\n\
+ -Z enable the zero/zero lock\n\
+ -R range set lock range\n\
+ -B base set lock base\n\
+ -M min set min lock length\n\
+");
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ char *share[NSERVERS];
+ int opt;
+ char *p;
+ int seed, server;
+
+ setlinebuf(stdout);
+
+ load_case_tables();
+
+ dbf = x_stderr;
+
+ if (argc < 3 || argv[1][0] == '-') {
+ usage();
+ exit(1);
+ }
+
+ setup_logging(argv[0],True);
+
+ for (server=0;server<NSERVERS;server++) {
+ share[server] = argv[1+server];
+ all_string_sub(share[server],"/","\\",0);
+ }
+
+ argc -= NSERVERS;
+ argv += NSERVERS;
+
+ lp_load(get_dyn_CONFIGFILE(),True,False,False,True);
+ load_interfaces();
+
+ if (getenv("USER")) {
+ fstrcpy(username[0],getenv("USER"));
+ fstrcpy(username[1],getenv("USER"));
+ }
+
+ seed = time(NULL);
+
+ while ((opt = getopt(argc, argv, "U:s:ho:aAW:OkR:B:M:EZ")) != EOF) {
+ switch (opt) {
+ case 'k':
+#ifdef HAVE_KRB5
+ use_kerberos = True;
+#else
+ d_printf("No kerberos support compiled in\n");
+ exit(1);
+#endif
+ break;
+ case 'U':
+ got_user = 1;
+ if (got_pass == 2) {
+ d_printf("Max of 2 usernames\n");
+ exit(1);
+ }
+ fstrcpy(username[got_pass],optarg);
+ p = strchr_m(username[got_pass],'%');
+ if (p) {
+ *p = 0;
+ fstrcpy(password[got_pass], p+1);
+ got_pass++;
+ }
+ break;
+ case 'R':
+ lock_range = strtol(optarg, NULL, 0);
+ break;
+ case 'B':
+ lock_base = strtol(optarg, NULL, 0);
+ break;
+ case 'M':
+ min_length = strtol(optarg, NULL, 0);
+ break;
+ case 's':
+ seed = atoi(optarg);
+ break;
+ case 'u':
+ hide_unlock_fails = True;
+ break;
+ case 'o':
+ numops = atoi(optarg);
+ break;
+ case 'O':
+ use_oplocks = True;
+ break;
+ case 'a':
+ showall = True;
+ break;
+ case 'A':
+ analyze = True;
+ break;
+ case 'Z':
+ zero_zero = True;
+ break;
+ case 'E':
+ exact_error_codes = True;
+ break;
+ case 'h':
+ usage();
+ exit(1);
+ default:
+ printf("Unknown option %c (%d)\n", (char)opt, opt);
+ exit(1);
+ }
+ }
+
+ if(use_kerberos && !got_user) got_pass = True;
+
+ argc -= optind;
+ argv += optind;
+
+ DEBUG(0,("seed=%u\n", seed));
+ srandom(seed);
+
+ test_locks(share);
+
+ return(0);
+}
diff --git a/source3/torture/locktest2.c b/source3/torture/locktest2.c
new file mode 100644
index 0000000000..68e18439e8
--- /dev/null
+++ b/source3/torture/locktest2.c
@@ -0,0 +1,565 @@
+/*
+ Unix SMB/CIFS implementation.
+ byte range lock tester - with local filesystem support
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static fstring password;
+static fstring username;
+static int got_pass;
+static int numops = 1000;
+static bool showall;
+static bool analyze;
+static bool hide_unlock_fails;
+static bool use_oplocks;
+
+extern char *optarg;
+extern int optind;
+
+#define FILENAME "\\locktest.dat"
+#define LOCKRANGE 100
+#define LOCKBASE 0
+
+/*
+#define LOCKBASE (0x40000000 - 50)
+*/
+
+#define READ_PCT 50
+#define LOCK_PCT 25
+#define UNLOCK_PCT 65
+#define RANGE_MULTIPLE 1
+
+#define NSERVERS 2
+#define NCONNECTIONS 2
+#define NUMFSTYPES 2
+#define NFILES 2
+#define LOCK_TIMEOUT 0
+
+#define FSTYPE_SMB 0
+#define FSTYPE_NFS 1
+
+struct record {
+ char r1, r2;
+ char conn, f, fstype;
+ unsigned start, len;
+ char needed;
+};
+
+static struct record *recorded;
+
+static int try_open(struct cli_state *c, char *nfs, int fstype, const char *fname, int flags)
+{
+ char *path;
+
+ switch (fstype) {
+ case FSTYPE_SMB:
+ return cli_open(c, fname, flags, DENY_NONE);
+
+ case FSTYPE_NFS:
+ if (asprintf(&path, "%s%s", nfs, fname) > 0) {
+ int ret;
+ string_replace(path,'\\', '/');
+ ret = open(path, flags, 0666);
+ SAFE_FREE(path);
+ return ret;
+ }
+ break;
+ }
+
+ return -1;
+}
+
+static bool try_close(struct cli_state *c, int fstype, int fd)
+{
+ switch (fstype) {
+ case FSTYPE_SMB:
+ return cli_close(c, fd);
+
+ case FSTYPE_NFS:
+ return close(fd) == 0;
+ }
+
+ return False;
+}
+
+static bool try_lock(struct cli_state *c, int fstype,
+ int fd, unsigned start, unsigned len,
+ enum brl_type op)
+{
+ struct flock lock;
+
+ switch (fstype) {
+ case FSTYPE_SMB:
+ return cli_lock(c, fd, start, len, LOCK_TIMEOUT, op);
+
+ case FSTYPE_NFS:
+ lock.l_type = (op==READ_LOCK) ? F_RDLCK:F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = start;
+ lock.l_len = len;
+ lock.l_pid = getpid();
+ return fcntl(fd,F_SETLK,&lock) == 0;
+ }
+
+ return False;
+}
+
+static bool try_unlock(struct cli_state *c, int fstype,
+ int fd, unsigned start, unsigned len)
+{
+ struct flock lock;
+
+ switch (fstype) {
+ case FSTYPE_SMB:
+ return cli_unlock(c, fd, start, len);
+
+ case FSTYPE_NFS:
+ lock.l_type = F_UNLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = start;
+ lock.l_len = len;
+ lock.l_pid = getpid();
+ return fcntl(fd,F_SETLK,&lock) == 0;
+ }
+
+ return False;
+}
+
+static void print_brl(struct file_id id, struct server_id pid,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ br_off start, br_off size,
+ void *private_data)
+{
+ printf("%6d %s %s %.0f:%.0f(%.0f)\n",
+ (int)procid_to_pid(&pid), file_id_string_tos(&id),
+ lock_type==READ_LOCK?"R":"W",
+ (double)start, (double)start+size-1,(double)size);
+
+}
+
+/*****************************************************
+return a connection to a server
+*******************************************************/
+static struct cli_state *connect_one(char *share)
+{
+ struct cli_state *c;
+ char *server_n;
+ fstring server;
+ fstring myname;
+ static int count;
+ NTSTATUS nt_status;
+
+ fstrcpy(server,share+2);
+ share = strchr_m(server,'\\');
+ if (!share) return NULL;
+ *share = 0;
+ share++;
+
+ server_n = server;
+
+ if (!got_pass) {
+ char *pass = getpass("Password: ");
+ if (pass) {
+ fstrcpy(password, pass);
+ }
+ }
+
+ slprintf(myname,sizeof(myname), "lock-%lu-%u", (unsigned long)getpid(), count++);
+
+ nt_status = cli_full_connection(&c, myname, server_n, NULL, 0, share, "?????",
+ username, lp_workgroup(), password, 0,
+ Undefined, NULL);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("cli_full_connection failed with error %s\n", nt_errstr(nt_status)));
+ return NULL;
+ }
+
+ c->use_oplocks = use_oplocks;
+
+ return c;
+}
+
+
+static void reconnect(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ char *nfs[NSERVERS],
+ int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES],
+ char *share1, char *share2)
+{
+ int server, conn, f, fstype;
+ char *share[2];
+ share[0] = share1;
+ share[1] = share2;
+
+ fstype = FSTYPE_SMB;
+
+ for (server=0;server<NSERVERS;server++)
+ for (conn=0;conn<NCONNECTIONS;conn++) {
+ if (cli[server][conn]) {
+ for (f=0;f<NFILES;f++) {
+ cli_close(cli[server][conn], fnum[server][fstype][conn][f]);
+ }
+ cli_ulogoff(cli[server][conn]);
+ cli_shutdown(cli[server][conn]);
+ }
+ cli[server][conn] = connect_one(share[server]);
+ if (!cli[server][conn]) {
+ DEBUG(0,("Failed to connect to %s\n", share[server]));
+ exit(1);
+ }
+ }
+}
+
+
+
+static bool test_one(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ char *nfs[NSERVERS],
+ int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES],
+ struct record *rec)
+{
+ unsigned conn = rec->conn;
+ unsigned f = rec->f;
+ unsigned fstype = rec->fstype;
+ unsigned start = rec->start;
+ unsigned len = rec->len;
+ unsigned r1 = rec->r1;
+ unsigned r2 = rec->r2;
+ enum brl_type op;
+ int server;
+ bool ret[NSERVERS];
+
+ if (r1 < READ_PCT) {
+ op = READ_LOCK;
+ } else {
+ op = WRITE_LOCK;
+ }
+
+ if (r2 < LOCK_PCT) {
+ /* set a lock */
+ for (server=0;server<NSERVERS;server++) {
+ ret[server] = try_lock(cli[server][conn], fstype,
+ fnum[server][fstype][conn][f],
+ start, len, op);
+ }
+ if (showall || ret[0] != ret[1]) {
+ printf("lock conn=%u fstype=%u f=%u range=%u:%u(%u) op=%s -> %u:%u\n",
+ conn, fstype, f,
+ start, start+len-1, len,
+ op==READ_LOCK?"READ_LOCK":"WRITE_LOCK",
+ ret[0], ret[1]);
+ }
+ if (showall) brl_forall(print_brl, NULL);
+ if (ret[0] != ret[1]) return False;
+ } else if (r2 < LOCK_PCT+UNLOCK_PCT) {
+ /* unset a lock */
+ for (server=0;server<NSERVERS;server++) {
+ ret[server] = try_unlock(cli[server][conn], fstype,
+ fnum[server][fstype][conn][f],
+ start, len);
+ }
+ if (showall || (!hide_unlock_fails && (ret[0] != ret[1]))) {
+ printf("unlock conn=%u fstype=%u f=%u range=%u:%u(%u) -> %u:%u\n",
+ conn, fstype, f,
+ start, start+len-1, len,
+ ret[0], ret[1]);
+ }
+ if (showall) brl_forall(print_brl, NULL);
+ if (!hide_unlock_fails && ret[0] != ret[1]) return False;
+ } else {
+ /* reopen the file */
+ for (server=0;server<NSERVERS;server++) {
+ try_close(cli[server][conn], fstype, fnum[server][fstype][conn][f]);
+ fnum[server][fstype][conn][f] = try_open(cli[server][conn], nfs[server], fstype, FILENAME,
+ O_RDWR|O_CREAT);
+ if (fnum[server][fstype][conn][f] == -1) {
+ printf("failed to reopen on share1\n");
+ return False;
+ }
+ }
+ if (showall) {
+ printf("reopen conn=%u fstype=%u f=%u\n",
+ conn, fstype, f);
+ brl_forall(print_brl, NULL);
+ }
+ }
+ return True;
+}
+
+static void close_files(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ char *nfs[NSERVERS],
+ int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES])
+{
+ int server, conn, f, fstype;
+
+ for (server=0;server<NSERVERS;server++)
+ for (fstype=0;fstype<NUMFSTYPES;fstype++)
+ for (conn=0;conn<NCONNECTIONS;conn++)
+ for (f=0;f<NFILES;f++) {
+ if (fnum[server][fstype][conn][f] != -1) {
+ try_close(cli[server][conn], fstype, fnum[server][fstype][conn][f]);
+ fnum[server][fstype][conn][f] = -1;
+ }
+ }
+ for (server=0;server<NSERVERS;server++) {
+ cli_unlink(cli[server][0], FILENAME);
+ }
+}
+
+static void open_files(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ char *nfs[NSERVERS],
+ int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES])
+{
+ int server, fstype, conn, f;
+
+ for (server=0;server<NSERVERS;server++)
+ for (fstype=0;fstype<NUMFSTYPES;fstype++)
+ for (conn=0;conn<NCONNECTIONS;conn++)
+ for (f=0;f<NFILES;f++) {
+ fnum[server][fstype][conn][f] = try_open(cli[server][conn], nfs[server], fstype, FILENAME,
+ O_RDWR|O_CREAT);
+ if (fnum[server][fstype][conn][f] == -1) {
+ fprintf(stderr,"Failed to open fnum[%u][%u][%u][%u]\n",
+ server, fstype, conn, f);
+ exit(1);
+ }
+ }
+}
+
+
+static int retest(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ char *nfs[NSERVERS],
+ int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES],
+ int n)
+{
+ int i;
+ printf("testing %u ...\n", n);
+ for (i=0; i<n; i++) {
+ if (i && i % 100 == 0) {
+ printf("%u\n", i);
+ }
+
+ if (recorded[i].needed &&
+ !test_one(cli, nfs, fnum, &recorded[i])) return i;
+ }
+ return n;
+}
+
+
+/* each server has two connections open to it. Each connection has two file
+ descriptors open on the file - 8 file descriptors in total
+
+ we then do random locking ops in tamdem on the 4 fnums from each
+ server and ensure that the results match
+ */
+static void test_locks(char *share1, char *share2, char *nfspath1, char *nfspath2)
+{
+ struct cli_state *cli[NSERVERS][NCONNECTIONS];
+ char *nfs[NSERVERS];
+ int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES];
+ int n, i, n1;
+
+ nfs[0] = nfspath1;
+ nfs[1] = nfspath2;
+
+ ZERO_STRUCT(fnum);
+ ZERO_STRUCT(cli);
+
+ recorded = SMB_MALLOC_ARRAY(struct record, numops);
+
+ for (n=0; n<numops; n++) {
+ recorded[n].conn = random() % NCONNECTIONS;
+ recorded[n].fstype = random() % NUMFSTYPES;
+ recorded[n].f = random() % NFILES;
+ recorded[n].start = LOCKBASE + ((unsigned)random() % (LOCKRANGE-1));
+ recorded[n].len = 1 +
+ random() % (LOCKRANGE-(recorded[n].start-LOCKBASE));
+ recorded[n].start *= RANGE_MULTIPLE;
+ recorded[n].len *= RANGE_MULTIPLE;
+ recorded[n].r1 = random() % 100;
+ recorded[n].r2 = random() % 100;
+ recorded[n].needed = True;
+ }
+
+ reconnect(cli, nfs, fnum, share1, share2);
+ open_files(cli, nfs, fnum);
+ n = retest(cli, nfs, fnum, numops);
+
+ if (n == numops || !analyze) return;
+ n++;
+
+ while (1) {
+ n1 = n;
+
+ close_files(cli, nfs, fnum);
+ reconnect(cli, nfs, fnum, share1, share2);
+ open_files(cli, nfs, fnum);
+
+ for (i=0;i<n-1;i++) {
+ int m;
+ recorded[i].needed = False;
+
+ close_files(cli, nfs, fnum);
+ open_files(cli, nfs, fnum);
+
+ m = retest(cli, nfs, fnum, n);
+ if (m == n) {
+ recorded[i].needed = True;
+ } else {
+ if (i < m) {
+ memmove(&recorded[i], &recorded[i+1],
+ (m-i)*sizeof(recorded[0]));
+ }
+ n = m;
+ i--;
+ }
+ }
+
+ if (n1 == n) break;
+ }
+
+ close_files(cli, nfs, fnum);
+ reconnect(cli, nfs, fnum, share1, share2);
+ open_files(cli, nfs, fnum);
+ showall = True;
+ n1 = retest(cli, nfs, fnum, n);
+ if (n1 != n-1) {
+ printf("ERROR - inconsistent result (%u %u)\n", n1, n);
+ }
+ close_files(cli, nfs, fnum);
+
+ for (i=0;i<n;i++) {
+ printf("{%u, %u, %u, %u, %u, %u, %u, %u},\n",
+ recorded[i].r1,
+ recorded[i].r2,
+ recorded[i].conn,
+ recorded[i].fstype,
+ recorded[i].f,
+ recorded[i].start,
+ recorded[i].len,
+ recorded[i].needed);
+ }
+}
+
+
+
+static void usage(void)
+{
+ printf(
+"Usage:\n\
+ locktest //server1/share1 //server2/share2 /path1 /path2 [options..]\n\
+ options:\n\
+ -U user%%pass\n\
+ -s seed\n\
+ -o numops\n\
+ -u hide unlock fails\n\
+ -a (show all ops)\n\
+ -O use oplocks\n\
+");
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ char *share1, *share2, *nfspath1, *nfspath2;
+ int opt;
+ char *p;
+ int seed;
+
+ setlinebuf(stdout);
+
+ dbf = x_stderr;
+
+ if (argc < 5 || argv[1][0] == '-') {
+ usage();
+ exit(1);
+ }
+
+ share1 = argv[1];
+ share2 = argv[2];
+ nfspath1 = argv[3];
+ nfspath2 = argv[4];
+
+ all_string_sub(share1,"/","\\",0);
+ all_string_sub(share2,"/","\\",0);
+
+ setup_logging(argv[0],True);
+
+ argc -= 4;
+ argv += 4;
+
+ lp_load(get_dyn_CONFIGFILE(),True,False,False,True);
+ load_interfaces();
+
+ if (getenv("USER")) {
+ fstrcpy(username,getenv("USER"));
+ }
+
+ seed = time(NULL);
+
+ while ((opt = getopt(argc, argv, "U:s:ho:aAW:O")) != EOF) {
+ switch (opt) {
+ case 'U':
+ fstrcpy(username,optarg);
+ p = strchr_m(username,'%');
+ if (p) {
+ *p = 0;
+ fstrcpy(password, p+1);
+ got_pass = 1;
+ }
+ break;
+ case 's':
+ seed = atoi(optarg);
+ break;
+ case 'u':
+ hide_unlock_fails = True;
+ break;
+ case 'o':
+ numops = atoi(optarg);
+ break;
+ case 'O':
+ use_oplocks = True;
+ break;
+ case 'a':
+ showall = True;
+ break;
+ case 'A':
+ analyze = True;
+ break;
+ case 'h':
+ usage();
+ exit(1);
+ default:
+ printf("Unknown option %c (%d)\n", (char)opt, opt);
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ DEBUG(0,("seed=%u\n", seed));
+ srandom(seed);
+
+ locking_init_readonly();
+ test_locks(share1, share2, nfspath1, nfspath2);
+
+ return(0);
+}
diff --git a/source3/torture/mangle_test.c b/source3/torture/mangle_test.c
new file mode 100644
index 0000000000..00457719a8
--- /dev/null
+++ b/source3/torture/mangle_test.c
@@ -0,0 +1,217 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester - mangling test
+ Copyright (C) Andrew Tridgell 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern int torture_numops;
+
+static TDB_CONTEXT *tdb;
+
+#define NAME_LENGTH 20
+
+static unsigned total, collisions, failures;
+
+static bool test_one(struct cli_state *cli, const char *name)
+{
+ int fnum;
+ fstring shortname;
+ fstring name2;
+ NTSTATUS status;
+ TDB_DATA data;
+
+ total++;
+
+ fnum = cli_open(cli, name, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum == -1) {
+ printf("open of %s failed (%s)\n", name, cli_errstr(cli));
+ return False;
+ }
+
+ if (!cli_close(cli, fnum)) {
+ printf("close of %s failed (%s)\n", name, cli_errstr(cli));
+ return False;
+ }
+
+ /* get the short name */
+ status = cli_qpathinfo_alt_name(cli, name, shortname);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("query altname of %s failed (%s)\n", name, cli_errstr(cli));
+ return False;
+ }
+
+ fstr_sprintf(name2, "\\mangle_test\\%s", shortname);
+ if (!cli_unlink(cli, name2)) {
+ printf("unlink of %s (%s) failed (%s)\n",
+ name2, name, cli_errstr(cli));
+ return False;
+ }
+
+ /* recreate by short name */
+ fnum = cli_open(cli, name2, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum == -1) {
+ printf("open2 of %s failed (%s)\n", name2, cli_errstr(cli));
+ return False;
+ }
+ if (!cli_close(cli, fnum)) {
+ printf("close of %s failed (%s)\n", name, cli_errstr(cli));
+ return False;
+ }
+
+ /* and unlink by long name */
+ if (!cli_unlink(cli, name)) {
+ printf("unlink2 of %s (%s) failed (%s)\n",
+ name, name2, cli_errstr(cli));
+ failures++;
+ cli_unlink(cli, name2);
+ return True;
+ }
+
+ /* see if the short name is already in the tdb */
+ data = tdb_fetch_bystring(tdb, shortname);
+ if (data.dptr) {
+ /* maybe its a duplicate long name? */
+ if (!strequal(name, (const char *)data.dptr)) {
+ /* we have a collision */
+ collisions++;
+ printf("Collision between %s and %s -> %s "
+ " (coll/tot: %u/%u)\n",
+ name, data.dptr, shortname, collisions, total);
+ }
+ free(data.dptr);
+ } else {
+ TDB_DATA namedata;
+ /* store it for later */
+ namedata.dptr = CONST_DISCARD(uint8 *, name);
+ namedata.dsize = strlen(name)+1;
+ tdb_store_bystring(tdb, shortname, namedata, TDB_REPLACE);
+ }
+
+ return True;
+}
+
+
+static void gen_name(char *name)
+{
+ const char *chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._-$~... ";
+ unsigned max_idx = strlen(chars);
+ unsigned len;
+ int i;
+ char *p;
+
+ fstrcpy(name, "\\mangle_test\\");
+ p = name + strlen(name);
+
+ len = 1 + random() % NAME_LENGTH;
+
+ for (i=0;i<len;i++) {
+ p[i] = chars[random() % max_idx];
+ }
+
+ p[i] = 0;
+
+ if (strcmp(p, ".") == 0 || strcmp(p, "..") == 0) {
+ p[0] = '_';
+ }
+
+ /* have a high probability of a common lead char */
+ if (random() % 2 == 0) {
+ p[0] = 'A';
+ }
+
+ /* and a medium probability of a common lead string */
+ if (random() % 10 == 0) {
+ if (strlen(p) <= 5) {
+ fstrcpy(p, "ABCDE");
+ } else {
+ /* try not to kill off the null termination */
+ memcpy(p, "ABCDE", 5);
+ }
+ }
+
+ /* and a high probability of a good extension length */
+ if (random() % 2 == 0) {
+ char *s = strrchr(p, '.');
+ if (s) {
+ s[4] = 0;
+ }
+ }
+
+ /* ..... and a 100% proability of a file not ending in "." */
+ if (p[strlen(p)-1] == '.')
+ p[strlen(p)-1] = '_';
+}
+
+
+bool torture_mangle(int dummy)
+{
+ static struct cli_state *cli;
+ int i;
+ bool ret = True;
+
+ printf("starting mangle test\n");
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ /* we will use an internal tdb to store the names we have used */
+ tdb = tdb_open(NULL, 100000, TDB_INTERNAL, 0, 0);
+ if (!tdb) {
+ printf("ERROR: Failed to open tdb\n");
+ return False;
+ }
+
+ cli_unlink(cli, "\\mangle_test\\*");
+ cli_rmdir(cli, "\\mangle_test");
+
+ if (!cli_mkdir(cli, "\\mangle_test")) {
+ printf("ERROR: Failed to make directory\n");
+ return False;
+ }
+
+ for (i=0;i<torture_numops;i++) {
+ fstring name;
+ ZERO_STRUCT(name);
+
+ gen_name(name);
+
+ if (!test_one(cli, name)) {
+ ret = False;
+ break;
+ }
+ if (total && total % 100 == 0) {
+ printf("collisions %u/%u - %.2f%% (%u failures)\r",
+ collisions, total, (100.0*collisions) / total, failures);
+ }
+ }
+
+ cli_unlink(cli, "\\mangle_test\\*");
+ if (!cli_rmdir(cli, "\\mangle_test")) {
+ printf("ERROR: Failed to remove directory\n");
+ return False;
+ }
+
+ printf("\nTotal collisions %u/%u - %.2f%% (%u failures)\n",
+ collisions, total, (100.0*collisions) / total, failures);
+
+ torture_close_connection(cli);
+
+ printf("mangle test finished\n");
+ return (ret && (failures == 0));
+}
diff --git a/source3/torture/masktest.c b/source3/torture/masktest.c
new file mode 100644
index 0000000000..c5612fefaa
--- /dev/null
+++ b/source3/torture/masktest.c
@@ -0,0 +1,565 @@
+/*
+ Unix SMB/CIFS implementation.
+ mask_match tester
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static fstring password;
+static fstring username;
+static int got_pass;
+static int max_protocol = PROTOCOL_NT1;
+static bool showall = False;
+static bool old_list = False;
+static const char *maskchars = "<>\"?*abc.";
+static const char *filechars = "abcdefghijklm.";
+static int verbose;
+static int die_on_error;
+static int NumLoops = 0;
+static int ignore_dot_errors = 0;
+
+extern char *optarg;
+extern int optind;
+extern bool AllowDebugChange;
+
+/* a test fn for LANMAN mask support */
+static int ms_fnmatch_lanman_core(const char *pattern, const char *string)
+{
+ const char *p = pattern, *n = string;
+ char c;
+
+ if (strcmp(p,"?")==0 && strcmp(n,".")==0) goto match;
+
+ while ((c = *p++)) {
+ switch (c) {
+ case '.':
+ /* if (! *n && ! *p) goto match; */
+ if (*n != '.') goto nomatch;
+ n++;
+ break;
+
+ case '?':
+ if ((*n == '.' && n[1] != '.') || ! *n) goto next;
+ n++;
+ break;
+
+ case '>':
+ if (n[0] == '.') {
+ if (! n[1] && ms_fnmatch_lanman_core(p, n+1) == 0) goto match;
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ goto nomatch;
+ }
+ if (! *n) goto next;
+ n++;
+ break;
+
+ case '*':
+ if (! *p) goto match;
+ for (; *n; n++) {
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ }
+ break;
+
+ case '<':
+ for (; *n; n++) {
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ if (*n == '.' && !strchr_m(n+1,'.')) {
+ n++;
+ break;
+ }
+ }
+ break;
+
+ case '"':
+ if (*n == 0 && ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ if (*n != '.') goto nomatch;
+ n++;
+ break;
+
+ default:
+ if (c != *n) goto nomatch;
+ n++;
+ }
+ }
+
+ if (! *n) goto match;
+
+ nomatch:
+ if (verbose) printf("NOMATCH pattern=[%s] string=[%s]\n", pattern, string);
+ return -1;
+
+next:
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ goto nomatch;
+
+ match:
+ if (verbose) printf("MATCH pattern=[%s] string=[%s]\n", pattern, string);
+ return 0;
+}
+
+static int ms_fnmatch_lanman(const char *pattern, const char *string)
+{
+ if (!strpbrk(pattern, "?*<>\"")) {
+ if (strcmp(string,"..") == 0)
+ string = ".";
+
+ return strcmp(pattern, string);
+ }
+
+ if (strcmp(string,"..") == 0 || strcmp(string,".") == 0) {
+ return ms_fnmatch_lanman_core(pattern, "..") &&
+ ms_fnmatch_lanman_core(pattern, ".");
+ }
+
+ return ms_fnmatch_lanman_core(pattern, string);
+}
+
+static bool reg_match_one(struct cli_state *cli, const char *pattern, const char *file)
+{
+ /* oh what a weird world this is */
+ if (old_list && strcmp(pattern, "*.*") == 0) return True;
+
+ if (strcmp(pattern,".") == 0) return False;
+
+ if (max_protocol <= PROTOCOL_LANMAN2) {
+ return ms_fnmatch_lanman(pattern, file)==0;
+ }
+
+ if (strcmp(file,"..") == 0) file = ".";
+
+ return ms_fnmatch(pattern, file, cli->protocol, False) == 0;
+}
+
+static char *reg_test(struct cli_state *cli, const char *pattern, const char *long_name, const char *short_name)
+{
+ static fstring ret;
+ const char *new_pattern = 1+strrchr_m(pattern,'\\');
+
+ fstrcpy(ret, "---");
+ if (reg_match_one(cli, new_pattern, ".")) ret[0] = '+';
+ if (reg_match_one(cli, new_pattern, "..")) ret[1] = '+';
+ if (reg_match_one(cli, new_pattern, long_name) ||
+ (*short_name && reg_match_one(cli, new_pattern, short_name))) ret[2] = '+';
+ return ret;
+}
+
+
+/*****************************************************
+return a connection to a server
+*******************************************************/
+static struct cli_state *connect_one(char *share)
+{
+ struct cli_state *c;
+ struct nmb_name called, calling;
+ char *server_n;
+ char *server;
+ struct sockaddr_storage ss;
+ NTSTATUS status;
+
+ server = share+2;
+ share = strchr_m(server,'\\');
+ if (!share) return NULL;
+ *share = 0;
+ share++;
+
+ server_n = server;
+
+ zero_addr(&ss);
+
+ make_nmb_name(&calling, "masktest", 0x0);
+ make_nmb_name(&called , server, 0x20);
+
+ again:
+ zero_addr(&ss);
+
+ /* have to open a new connection */
+ if (!(c=cli_initialise())) {
+ DEBUG(0,("Connection to %s failed\n", server_n));
+ return NULL;
+ }
+
+ status = cli_connect(c, server_n, &ss);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Connection to %s failed. Error %s\n", server_n, nt_errstr(status) ));
+ return NULL;
+ }
+
+ c->protocol = max_protocol;
+
+ if (!cli_session_request(c, &calling, &called)) {
+ DEBUG(0,("session request to %s failed\n", called.name));
+ cli_shutdown(c);
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ }
+ return NULL;
+ }
+
+ DEBUG(4,(" session request ok\n"));
+
+ if (!cli_negprot(c)) {
+ DEBUG(0,("protocol negotiation failed\n"));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ if (!got_pass) {
+ char *pass = getpass("Password: ");
+ if (pass) {
+ fstrcpy(password, pass);
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(cli_session_setup(c, username,
+ password, strlen(password),
+ password, strlen(password),
+ lp_workgroup()))) {
+ DEBUG(0,("session setup failed: %s\n", cli_errstr(c)));
+ return NULL;
+ }
+
+ /*
+ * These next two lines are needed to emulate
+ * old client behaviour for people who have
+ * scripts based on client output.
+ * QUESTION ? Do we want to have a 'client compatibility
+ * mode to turn these on/off ? JRA.
+ */
+
+ if (*c->server_domain || *c->server_os || *c->server_type)
+ DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
+ c->server_domain,c->server_os,c->server_type));
+
+ DEBUG(4,(" session setup ok\n"));
+
+ if (!cli_send_tconX(c, share, "?????",
+ password, strlen(password)+1)) {
+ DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ DEBUG(4,(" tconx ok\n"));
+
+ return c;
+}
+
+static char *resultp;
+static file_info *f_info;
+
+static void listfn(const char *mnt, file_info *f, const char *s, void *state)
+{
+ if (strcmp(f->name,".") == 0) {
+ resultp[0] = '+';
+ } else if (strcmp(f->name,"..") == 0) {
+ resultp[1] = '+';
+ } else {
+ resultp[2] = '+';
+ }
+ f_info = f;
+}
+
+static void get_real_name(struct cli_state *cli,
+ char **pp_long_name, fstring short_name)
+{
+ *pp_long_name = NULL;
+ /* nasty hack to force level 260 listings - tridge */
+ cli->capabilities |= CAP_NT_SMBS;
+ if (max_protocol <= PROTOCOL_LANMAN1) {
+ cli_list_new(cli, "\\masktest\\*.*", aHIDDEN | aDIR, listfn, NULL);
+ } else {
+ cli_list_new(cli, "\\masktest\\*", aHIDDEN | aDIR, listfn, NULL);
+ }
+ if (f_info) {
+ fstrcpy(short_name, f_info->short_name);
+ strlower_m(short_name);
+ *pp_long_name = SMB_STRDUP(f_info->name);
+ if (!*pp_long_name) {
+ return;
+ }
+ strlower_m(*pp_long_name);
+ }
+
+ if (*short_name == 0) {
+ fstrcpy(short_name, *pp_long_name);
+ }
+
+#if 0
+ if (!strchr_m(short_name,'.')) {
+ fstrcat(short_name,".");
+ }
+#endif
+}
+
+static void testpair(struct cli_state *cli, const char *mask, const char *file)
+{
+ int fnum;
+ fstring res1;
+ char *res2;
+ static int count;
+ fstring short_name;
+ char *long_name = NULL;
+
+ count++;
+
+ fstrcpy(res1, "---");
+
+ fnum = cli_open(cli, file, O_CREAT|O_TRUNC|O_RDWR, 0);
+ if (fnum == -1) {
+ DEBUG(0,("Can't create %s\n", file));
+ return;
+ }
+ cli_close(cli, fnum);
+
+ resultp = res1;
+ fstrcpy(short_name, "");
+ f_info = NULL;
+ get_real_name(cli, &long_name, short_name);
+ if (!long_name) {
+ return;
+ }
+ f_info = NULL;
+ fstrcpy(res1, "---");
+ cli_list(cli, mask, aHIDDEN | aDIR, listfn, NULL);
+
+ res2 = reg_test(cli, mask, long_name, short_name);
+
+ if (showall ||
+ ((strcmp(res1, res2) && !ignore_dot_errors) ||
+ (strcmp(res1+2, res2+2) && ignore_dot_errors))) {
+ DEBUG(0,("%s %s %d mask=[%s] file=[%s] rfile=[%s/%s]\n",
+ res1, res2, count, mask, file, long_name, short_name));
+ if (die_on_error) exit(1);
+ }
+
+ cli_unlink(cli, file);
+
+ if (count % 100 == 0) DEBUG(0,("%d\n", count));
+ SAFE_FREE(long_name);
+}
+
+static void test_mask(int argc, char *argv[],
+ struct cli_state *cli)
+{
+ char *mask, *file;
+ int l1, l2, i, l;
+ int mc_len = strlen(maskchars);
+ int fc_len = strlen(filechars);
+ TALLOC_CTX *ctx = talloc_tos();
+
+ cli_mkdir(cli, "\\masktest");
+
+ cli_unlink(cli, "\\masktest\\*");
+
+ if (argc >= 2) {
+ while (argc >= 2) {
+ mask = talloc_asprintf(ctx,
+ "\\masktest\\%s",
+ argv[0]);
+ file = talloc_asprintf(ctx,
+ "\\masktest\\%s",
+ argv[1]);
+ if (!mask || !file) {
+ goto finished;
+ }
+ testpair(cli, mask, file);
+ argv += 2;
+ argc -= 2;
+ }
+ goto finished;
+ }
+
+ while (1) {
+ l1 = 1 + random() % 20;
+ l2 = 1 + random() % 20;
+ mask = TALLOC_ARRAY(ctx, char, strlen("\\masktest\\")+1+22);
+ file = TALLOC_ARRAY(ctx, char, strlen("\\masktest\\")+1+22);
+ if (!mask || !file) {
+ goto finished;
+ }
+ memcpy(mask,"\\masktest\\",strlen("\\masktest\\")+1);
+ memcpy(file,"\\masktest\\",strlen("\\masktest\\")+1);
+ l = strlen(mask);
+ for (i=0;i<l1;i++) {
+ mask[i+l] = maskchars[random() % mc_len];
+ }
+ mask[l+l1] = 0;
+
+ for (i=0;i<l2;i++) {
+ file[i+l] = filechars[random() % fc_len];
+ }
+ file[l+l2] = 0;
+
+ if (strcmp(file+l,".") == 0 ||
+ strcmp(file+l,"..") == 0 ||
+ strcmp(mask+l,"..") == 0) continue;
+
+ if (strspn(file+l, ".") == strlen(file+l)) continue;
+
+ testpair(cli, mask, file);
+ if (NumLoops && (--NumLoops == 0))
+ break;
+ TALLOC_FREE(mask);
+ TALLOC_FREE(file);
+ }
+
+ finished:
+ cli_rmdir(cli, "\\masktest");
+}
+
+
+static void usage(void)
+{
+ printf(
+"Usage:\n\
+ masktest //server/share [options..]\n\
+ options:\n\
+ -d debuglevel\n\
+ -n numloops\n\
+ -W workgroup\n\
+ -U user%%pass\n\
+ -s seed\n\
+ -M max protocol\n\
+ -f filechars (default %s)\n\
+ -m maskchars (default %s)\n\
+ -v verbose mode\n\
+ -E die on error\n\
+ -a show all tests\n\
+ -i ignore . and .. errors\n\
+\n\
+ This program tests wildcard matching between two servers. It generates\n\
+ random pairs of filenames/masks and tests that they match in the same\n\
+ way on the servers and internally\n\
+",
+ filechars, maskchars);
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ char *share;
+ struct cli_state *cli;
+ int opt;
+ char *p;
+ int seed;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ setlinebuf(stdout);
+
+ dbf = x_stderr;
+
+ DEBUGLEVEL = 0;
+ AllowDebugChange = False;
+
+ if (argc < 2 || argv[1][0] == '-') {
+ usage();
+ exit(1);
+ }
+
+ share = argv[1];
+
+ all_string_sub(share,"/","\\",0);
+
+ setup_logging(argv[0],True);
+
+ argc -= 1;
+ argv += 1;
+
+ lp_load(get_dyn_CONFIGFILE(),True,False,False,True);
+ load_interfaces();
+
+ if (getenv("USER")) {
+ fstrcpy(username,getenv("USER"));
+ }
+
+ seed = time(NULL);
+
+ while ((opt = getopt(argc, argv, "n:d:U:s:hm:f:aoW:M:vEi")) != EOF) {
+ switch (opt) {
+ case 'n':
+ NumLoops = atoi(optarg);
+ break;
+ case 'd':
+ DEBUGLEVEL = atoi(optarg);
+ break;
+ case 'E':
+ die_on_error = 1;
+ break;
+ case 'i':
+ ignore_dot_errors = 1;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'M':
+ max_protocol = interpret_protocol(optarg, max_protocol);
+ break;
+ case 'U':
+ fstrcpy(username,optarg);
+ p = strchr_m(username,'%');
+ if (p) {
+ *p = 0;
+ fstrcpy(password, p+1);
+ got_pass = 1;
+ }
+ break;
+ case 's':
+ seed = atoi(optarg);
+ break;
+ case 'h':
+ usage();
+ exit(1);
+ case 'm':
+ maskchars = optarg;
+ break;
+ case 'f':
+ filechars = optarg;
+ break;
+ case 'a':
+ showall = 1;
+ break;
+ case 'o':
+ old_list = True;
+ break;
+ default:
+ printf("Unknown option %c (%d)\n", (char)opt, opt);
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+
+ cli = connect_one(share);
+ if (!cli) {
+ DEBUG(0,("Failed to connect to %s\n", share));
+ exit(1);
+ }
+
+ /* need to init seed after connect as clientgen uses random numbers */
+ DEBUG(0,("seed=%d\n", seed));
+ srandom(seed);
+
+ test_mask(argc, argv, cli);
+
+ TALLOC_FREE(frame);
+ return(0);
+}
diff --git a/source3/torture/msgtest.c b/source3/torture/msgtest.c
new file mode 100644
index 0000000000..1bb616f6e1
--- /dev/null
+++ b/source3/torture/msgtest.c
@@ -0,0 +1,145 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Andrew Tridgell 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ test code for internal messaging
+ */
+
+#include "includes.h"
+
+static int pong_count;
+
+
+/****************************************************************************
+a useful function for testing the message system
+****************************************************************************/
+static void pong_message(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id pid,
+ DATA_BLOB *data)
+{
+ pong_count++;
+}
+
+ int main(int argc, char *argv[])
+{
+ struct event_context *evt_ctx;
+ struct messaging_context *msg_ctx;
+ pid_t pid;
+ int i, n;
+ char buf[12];
+
+ load_case_tables();
+
+ setup_logging(argv[0],True);
+
+ lp_load(get_dyn_CONFIGFILE(),False,False,False,True);
+
+ if (!(evt_ctx = event_context_init(NULL)) ||
+ !(msg_ctx = messaging_init(NULL, server_id_self(), evt_ctx))) {
+ fprintf(stderr, "could not init messaging context\n");
+ exit(1);
+ }
+
+ if (argc != 3) {
+ fprintf(stderr, "%s: Usage - %s pid count\n", argv[0],
+ argv[0]);
+ exit(1);
+ }
+
+ pid = atoi(argv[1]);
+ n = atoi(argv[2]);
+
+ messaging_register(msg_ctx, NULL, MSG_PONG, pong_message);
+
+ for (i=0;i<n;i++) {
+ messaging_send(msg_ctx, pid_to_procid(pid), MSG_PING,
+ &data_blob_null);
+ }
+
+ while (pong_count < i) {
+ message_dispatch(msg_ctx);
+ smb_msleep(1);
+ }
+
+ /* Now test that the duplicate filtering code works. */
+ pong_count = 0;
+
+ safe_strcpy(buf, "1234567890", sizeof(buf)-1);
+
+ for (i=0;i<n;i++) {
+ messaging_send(msg_ctx, pid_to_procid(getpid()), MSG_PING,
+ &data_blob_null);
+ messaging_send_buf(msg_ctx, pid_to_procid(getpid()), MSG_PING,
+ (uint8 *)buf, 11);
+ }
+
+ for (i=0;i<n;i++) {
+ message_dispatch(msg_ctx);
+ smb_msleep(1);
+ }
+
+ if (pong_count != 2) {
+ fprintf(stderr, "Duplicate filter failed (%d).\n", pong_count);
+ }
+
+ /* Speed testing */
+
+ pong_count = 0;
+
+ {
+ struct timeval tv = timeval_current();
+ size_t timelimit = n;
+ size_t ping_count = 0;
+
+ printf("Sending pings for %d seconds\n", (int)timelimit);
+ while (timeval_elapsed(&tv) < timelimit) {
+ if(NT_STATUS_IS_OK(messaging_send_buf(
+ msg_ctx, pid_to_procid(pid),
+ MSG_PING,
+ (uint8 *)buf, 11)))
+ ping_count++;
+ if(NT_STATUS_IS_OK(messaging_send(
+ msg_ctx, pid_to_procid(pid),
+ MSG_PING, &data_blob_null)))
+ ping_count++;
+
+ while (ping_count > pong_count + 20) {
+ message_dispatch(msg_ctx);
+ }
+ }
+
+ printf("waiting for %d remaining replies (done %d)\n",
+ (int)(ping_count - pong_count), pong_count);
+ while (timeval_elapsed(&tv) < 30 && pong_count < ping_count) {
+ message_dispatch(msg_ctx);
+ }
+
+ if (ping_count != pong_count) {
+ fprintf(stderr, "ping test failed! received %d, sent "
+ "%d\n", pong_count, (int)ping_count);
+ }
+
+ printf("ping rate of %.0f messages/sec\n",
+ (ping_count+pong_count)/timeval_elapsed(&tv));
+ }
+
+ return (0);
+}
+
diff --git a/source3/torture/nbio.c b/source3/torture/nbio.c
new file mode 100644
index 0000000000..81d0eb816b
--- /dev/null
+++ b/source3/torture/nbio.c
@@ -0,0 +1,315 @@
+#define NBDEBUG 0
+
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#define MAX_FILES 1000
+
+static char buf[70000];
+extern int line_count;
+extern int nbio_id;
+static int nprocs;
+
+static struct {
+ int fd;
+ int handle;
+} ftable[MAX_FILES];
+
+static struct children {
+ double bytes_in, bytes_out;
+ int line;
+ int done;
+} *children;
+
+double nbio_total(void)
+{
+ int i;
+ double total = 0;
+ for (i=0;i<nprocs;i++) {
+ total += children[i].bytes_out + children[i].bytes_in;
+ }
+ return total;
+}
+
+void nb_alarm(int ignore)
+{
+ int i;
+ int lines=0, num_clients=0;
+ if (nbio_id != -1) return;
+
+ for (i=0;i<nprocs;i++) {
+ lines += children[i].line;
+ if (!children[i].done) num_clients++;
+ }
+
+ printf("%4d %8d %.2f MB/sec\r", num_clients, lines/nprocs, 1.0e-6 * nbio_total() / end_timer());
+
+ signal(SIGALRM, nb_alarm);
+ alarm(1);
+}
+
+void nbio_shmem(int n)
+{
+ nprocs = n;
+ children = (struct children *)shm_setup(sizeof(*children) * nprocs);
+ if (!children) {
+ printf("Failed to setup shared memory!\n");
+ exit(1);
+ }
+}
+
+#if 0
+static int ne_find_handle(int handle)
+{
+ int i;
+ children[nbio_id].line = line_count;
+ for (i=0;i<MAX_FILES;i++) {
+ if (ftable[i].handle == handle) return i;
+ }
+ return -1;
+}
+#endif
+
+static int find_handle(int handle)
+{
+ int i;
+ children[nbio_id].line = line_count;
+ for (i=0;i<MAX_FILES;i++) {
+ if (ftable[i].handle == handle) return i;
+ }
+ printf("(%d) ERROR: handle %d was not found\n",
+ line_count, handle);
+ exit(1);
+
+ return -1; /* Not reached */
+}
+
+
+static struct cli_state *c;
+
+static void sigsegv(int sig)
+{
+ char line[200];
+ printf("segv at line %d\n", line_count);
+ slprintf(line, sizeof(line), "/usr/X11R6/bin/xterm -e gdb /proc/%d/exe %d",
+ (int)getpid(), (int)getpid());
+ system(line);
+ exit(1);
+}
+
+void nb_setup(struct cli_state *cli)
+{
+ signal(SIGSEGV, sigsegv);
+ c = cli;
+ start_timer();
+ children[nbio_id].done = 0;
+}
+
+
+void nb_unlink(const char *fname)
+{
+ if (!cli_unlink(c, fname)) {
+#if NBDEBUG
+ printf("(%d) unlink %s failed (%s)\n",
+ line_count, fname, cli_errstr(c));
+#endif
+ }
+}
+
+
+void nb_createx(const char *fname,
+ unsigned create_options, unsigned create_disposition, int handle)
+{
+ int fd, i;
+ uint32 desired_access;
+
+ if (create_options & FILE_DIRECTORY_FILE) {
+ desired_access = FILE_READ_DATA;
+ } else {
+ desired_access = FILE_READ_DATA | FILE_WRITE_DATA;
+ }
+
+ fd = cli_nt_create_full(c, fname, 0,
+ desired_access,
+ 0x0,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ create_disposition,
+ create_options, 0);
+ if (fd == -1 && handle != -1) {
+ printf("ERROR: cli_nt_create_full failed for %s - %s\n",
+ fname, cli_errstr(c));
+ exit(1);
+ }
+ if (fd != -1 && handle == -1) {
+ printf("ERROR: cli_nt_create_full succeeded for %s\n", fname);
+ exit(1);
+ }
+ if (fd == -1) return;
+
+ for (i=0;i<MAX_FILES;i++) {
+ if (ftable[i].handle == 0) break;
+ }
+ if (i == MAX_FILES) {
+ printf("(%d) file table full for %s\n", line_count,
+ fname);
+ exit(1);
+ }
+ ftable[i].handle = handle;
+ ftable[i].fd = fd;
+}
+
+void nb_writex(int handle, int offset, int size, int ret_size)
+{
+ int i;
+
+ if (buf[0] == 0) memset(buf, 1, sizeof(buf));
+
+ i = find_handle(handle);
+ if (cli_write(c, ftable[i].fd, 0, buf, offset, size) != ret_size) {
+ printf("(%d) ERROR: write failed on handle %d, fd %d \
+errno %d (%s)\n", line_count, handle, ftable[i].fd, errno, strerror(errno));
+ exit(1);
+ }
+
+ children[nbio_id].bytes_out += ret_size;
+}
+
+void nb_readx(int handle, int offset, int size, int ret_size)
+{
+ int i, ret;
+
+ i = find_handle(handle);
+ if ((ret=cli_read(c, ftable[i].fd, buf, offset, size)) != ret_size) {
+ printf("(%d) ERROR: read failed on handle %d ofs=%d size=%d res=%d fd %d errno %d (%s)\n",
+ line_count, handle, offset, size, ret, ftable[i].fd, errno, strerror(errno));
+ exit(1);
+ }
+ children[nbio_id].bytes_in += ret_size;
+}
+
+void nb_close(int handle)
+{
+ int i;
+ i = find_handle(handle);
+ if (!cli_close(c, ftable[i].fd)) {
+ printf("(%d) close failed on handle %d\n", line_count, handle);
+ exit(1);
+ }
+ ftable[i].handle = 0;
+}
+
+void nb_rmdir(const char *fname)
+{
+ if (!cli_rmdir(c, fname)) {
+ printf("ERROR: rmdir %s failed (%s)\n",
+ fname, cli_errstr(c));
+ exit(1);
+ }
+}
+
+void nb_rename(const char *oldname, const char *newname)
+{
+ if (!cli_rename(c, oldname, newname)) {
+ printf("ERROR: rename %s %s failed (%s)\n",
+ oldname, newname, cli_errstr(c));
+ exit(1);
+ }
+}
+
+
+void nb_qpathinfo(const char *fname)
+{
+ cli_qpathinfo(c, fname, NULL, NULL, NULL, NULL, NULL);
+}
+
+void nb_qfileinfo(int fnum)
+{
+ int i;
+ i = find_handle(fnum);
+ cli_qfileinfo(c, ftable[i].fd, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+}
+
+void nb_qfsinfo(int level)
+{
+ int bsize, total, avail;
+ /* this is not the right call - we need cli_qfsinfo() */
+ cli_dskattr(c, &bsize, &total, &avail);
+}
+
+static void find_fn(const char *mnt, file_info *finfo, const char *name, void *state)
+{
+ /* noop */
+}
+
+void nb_findfirst(const char *mask)
+{
+ cli_list(c, mask, 0, find_fn, NULL);
+}
+
+void nb_flush(int fnum)
+{
+ int i;
+ i = find_handle(fnum);
+ /* hmmm, we don't have cli_flush() yet */
+}
+
+static int total_deleted;
+
+static void delete_fn(const char *mnt, file_info *finfo, const char *name, void *state)
+{
+ char *s, *n;
+ if (finfo->name[0] == '.') return;
+
+ n = SMB_STRDUP(name);
+ n[strlen(n)-1] = 0;
+ asprintf(&s, "%s%s", n, finfo->name);
+ if (finfo->mode & aDIR) {
+ char *s2;
+ asprintf(&s2, "%s\\*", s);
+ cli_list(c, s2, aDIR, delete_fn, NULL);
+ nb_rmdir(s);
+ } else {
+ total_deleted++;
+ nb_unlink(s);
+ }
+ free(s);
+ free(n);
+}
+
+void nb_deltree(const char *dname)
+{
+ char *mask;
+ asprintf(&mask, "%s\\*", dname);
+
+ total_deleted = 0;
+ cli_list(c, mask, aDIR, delete_fn, NULL);
+ free(mask);
+ cli_rmdir(c, dname);
+
+ if (total_deleted) printf("WARNING: Cleaned up %d files\n", total_deleted);
+}
+
+
+void nb_cleanup(void)
+{
+ cli_rmdir(c, "clients");
+ children[nbio_id].done = 1;
+}
diff --git a/source3/torture/nsstest.c b/source3/torture/nsstest.c
new file mode 100644
index 0000000000..6bd0efe1af
--- /dev/null
+++ b/source3/torture/nsstest.c
@@ -0,0 +1,487 @@
+/*
+ Unix SMB/CIFS implementation.
+ nss tester for winbindd
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Tim Potter 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static const char *so_path = "/lib/libnss_winbind.so";
+static const char *nss_name = "winbind";
+static int nss_errno;
+static NSS_STATUS last_error;
+static int total_errors;
+
+static void *find_fn(const char *name)
+{
+ char *s;
+ static void *h;
+ void *res;
+
+ if (asprintf(&s, "_nss_%s_%s", nss_name, name) < 0) {
+ exit(1);
+ }
+
+ if (!h) {
+ h = sys_dlopen(so_path, RTLD_LAZY);
+ }
+ if (!h) {
+ printf("Can't open shared library %s\n", so_path);
+ exit(1);
+ }
+ res = sys_dlsym(h, s);
+ if (!res) {
+ printf("Can't find function %s\n", s);
+ total_errors++;
+ SAFE_FREE(s);
+ return NULL;
+ }
+ SAFE_FREE(s);
+ return res;
+}
+
+static void report_nss_error(const char *who, NSS_STATUS status)
+{
+ last_error = status;
+ total_errors++;
+ printf("ERROR %s: NSS_STATUS=%d %d (nss_errno=%d)\n",
+ who, status, NSS_STATUS_SUCCESS, nss_errno);
+}
+
+static struct passwd *nss_getpwent(void)
+{
+ NSS_STATUS (*_nss_getpwent_r)(struct passwd *, char *,
+ size_t , int *) =
+ (NSS_STATUS (*)(struct passwd *, char *,
+ size_t, int *))find_fn("getpwent_r");
+ static struct passwd pwd;
+ static char buf[1000];
+ NSS_STATUS status;
+
+ if (!_nss_getpwent_r)
+ return NULL;
+
+ status = _nss_getpwent_r(&pwd, buf, sizeof(buf), &nss_errno);
+ if (status == NSS_STATUS_NOTFOUND) {
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("getpwent", status);
+ return NULL;
+ }
+ return &pwd;
+}
+
+static struct passwd *nss_getpwnam(const char *name)
+{
+ NSS_STATUS (*_nss_getpwnam_r)(const char *, struct passwd *, char *,
+ size_t , int *) =
+ (NSS_STATUS (*)(const char *, struct passwd *, char *,
+ size_t, int *))find_fn("getpwnam_r");
+ static struct passwd pwd;
+ static char buf[1000];
+ NSS_STATUS status;
+
+ if (!_nss_getpwnam_r)
+ return NULL;
+
+ status = _nss_getpwnam_r(name, &pwd, buf, sizeof(buf), &nss_errno);
+ if (status == NSS_STATUS_NOTFOUND) {
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("getpwnam", status);
+ return NULL;
+ }
+ return &pwd;
+}
+
+static struct passwd *nss_getpwuid(uid_t uid)
+{
+ NSS_STATUS (*_nss_getpwuid_r)(uid_t , struct passwd *, char *,
+ size_t , int *) =
+ (NSS_STATUS (*)(uid_t, struct passwd *, char *,
+ size_t, int *))find_fn("getpwuid_r");
+ static struct passwd pwd;
+ static char buf[1000];
+ NSS_STATUS status;
+
+ if (!_nss_getpwuid_r)
+ return NULL;
+
+ status = _nss_getpwuid_r(uid, &pwd, buf, sizeof(buf), &nss_errno);
+ if (status == NSS_STATUS_NOTFOUND) {
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("getpwuid", status);
+ return NULL;
+ }
+ return &pwd;
+}
+
+static void nss_setpwent(void)
+{
+ NSS_STATUS (*_nss_setpwent)(void) =
+ (NSS_STATUS(*)(void))find_fn("setpwent");
+ NSS_STATUS status;
+
+ if (!_nss_setpwent)
+ return;
+
+ status = _nss_setpwent();
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("setpwent", status);
+ }
+}
+
+static void nss_endpwent(void)
+{
+ NSS_STATUS (*_nss_endpwent)(void) =
+ (NSS_STATUS (*)(void))find_fn("endpwent");
+ NSS_STATUS status;
+
+ if (!_nss_endpwent)
+ return;
+
+ status = _nss_endpwent();
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("endpwent", status);
+ }
+}
+
+
+static struct group *nss_getgrent(void)
+{
+ NSS_STATUS (*_nss_getgrent_r)(struct group *, char *,
+ size_t , int *) =
+ (NSS_STATUS (*)(struct group *, char *,
+ size_t, int *))find_fn("getgrent_r");
+ static struct group grp;
+ static char *buf;
+ static int buflen = 1024;
+ NSS_STATUS status;
+
+ if (!_nss_getgrent_r)
+ return NULL;
+
+ if (!buf)
+ buf = SMB_MALLOC_ARRAY(char, buflen);
+
+again:
+ status = _nss_getgrent_r(&grp, buf, buflen, &nss_errno);
+ if (status == NSS_STATUS_TRYAGAIN) {
+ buflen *= 2;
+ buf = SMB_REALLOC_ARRAY(buf, char, buflen);
+ if (!buf) {
+ return NULL;
+ }
+ goto again;
+ }
+ if (status == NSS_STATUS_NOTFOUND) {
+ SAFE_FREE(buf);
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("getgrent", status);
+ SAFE_FREE(buf);
+ return NULL;
+ }
+ return &grp;
+}
+
+static struct group *nss_getgrnam(const char *name)
+{
+ NSS_STATUS (*_nss_getgrnam_r)(const char *, struct group *, char *,
+ size_t , int *) =
+ (NSS_STATUS (*)(const char *, struct group *, char *,
+ size_t, int *))find_fn("getgrnam_r");
+ static struct group grp;
+ static char *buf;
+ static int buflen = 1000;
+ NSS_STATUS status;
+
+ if (!_nss_getgrnam_r)
+ return NULL;
+
+ if (!buf)
+ buf = SMB_MALLOC_ARRAY(char, buflen);
+again:
+ status = _nss_getgrnam_r(name, &grp, buf, buflen, &nss_errno);
+ if (status == NSS_STATUS_TRYAGAIN) {
+ buflen *= 2;
+ buf = SMB_REALLOC_ARRAY(buf, char, buflen);
+ if (!buf) {
+ return NULL;
+ }
+ goto again;
+ }
+ if (status == NSS_STATUS_NOTFOUND) {
+ SAFE_FREE(buf);
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("getgrnam", status);
+ SAFE_FREE(buf);
+ return NULL;
+ }
+ return &grp;
+}
+
+static struct group *nss_getgrgid(gid_t gid)
+{
+ NSS_STATUS (*_nss_getgrgid_r)(gid_t , struct group *, char *,
+ size_t , int *) =
+ (NSS_STATUS (*)(gid_t, struct group *, char *,
+ size_t, int *))find_fn("getgrgid_r");
+ static struct group grp;
+ static char *buf;
+ static int buflen = 1000;
+ NSS_STATUS status;
+
+ if (!_nss_getgrgid_r)
+ return NULL;
+
+ if (!buf)
+ buf = SMB_MALLOC_ARRAY(char, buflen);
+
+again:
+ status = _nss_getgrgid_r(gid, &grp, buf, buflen, &nss_errno);
+ if (status == NSS_STATUS_TRYAGAIN) {
+ buflen *= 2;
+ buf = SMB_REALLOC_ARRAY(buf, char, buflen);
+ if (!buf) {
+ return NULL;
+ }
+ goto again;
+ }
+ if (status == NSS_STATUS_NOTFOUND) {
+ SAFE_FREE(buf);
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("getgrgid", status);
+ SAFE_FREE(buf);
+ return NULL;
+ }
+ return &grp;
+}
+
+static void nss_setgrent(void)
+{
+ NSS_STATUS (*_nss_setgrent)(void) =
+ (NSS_STATUS (*)(void))find_fn("setgrent");
+ NSS_STATUS status;
+
+ if (!_nss_setgrent)
+ return;
+
+ status = _nss_setgrent();
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("setgrent", status);
+ }
+}
+
+static void nss_endgrent(void)
+{
+ NSS_STATUS (*_nss_endgrent)(void) =
+ (NSS_STATUS (*)(void))find_fn("endgrent");
+ NSS_STATUS status;
+
+ if (!_nss_endgrent)
+ return;
+
+ status = _nss_endgrent();
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("endgrent", status);
+ }
+}
+
+static int nss_initgroups(char *user, gid_t group, gid_t **groups, long int *start, long int *size)
+{
+ NSS_STATUS (*_nss_initgroups)(char *, gid_t , long int *,
+ long int *, gid_t **, long int , int *) =
+ (NSS_STATUS (*)(char *, gid_t, long int *,
+ long int *, gid_t **,
+ long int, int *))find_fn("initgroups_dyn");
+ NSS_STATUS status;
+
+ if (!_nss_initgroups)
+ return NSS_STATUS_UNAVAIL;
+
+ status = _nss_initgroups(user, group, start, size, groups, 0, &nss_errno);
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("initgroups", status);
+ }
+ return status;
+}
+
+static void print_passwd(struct passwd *pwd)
+{
+ printf("%s:%s:%lu:%lu:%s:%s:%s\n",
+ pwd->pw_name,
+ pwd->pw_passwd,
+ (unsigned long)pwd->pw_uid,
+ (unsigned long)pwd->pw_gid,
+ pwd->pw_gecos,
+ pwd->pw_dir,
+ pwd->pw_shell);
+}
+
+static void print_group(struct group *grp)
+{
+ int i;
+ printf("%s:%s:%lu: ",
+ grp->gr_name,
+ grp->gr_passwd,
+ (unsigned long)grp->gr_gid);
+
+ if (!grp->gr_mem[0]) {
+ printf("\n");
+ return;
+ }
+
+ for (i=0; grp->gr_mem[i+1]; i++) {
+ printf("%s, ", grp->gr_mem[i]);
+ }
+ printf("%s\n", grp->gr_mem[i]);
+}
+
+static void nss_test_initgroups(char *name, gid_t gid)
+{
+ long int size = 16;
+ long int start = 1;
+ gid_t *groups = NULL;
+ int i;
+ NSS_STATUS status;
+
+ groups = SMB_MALLOC_ARRAY(gid_t, size);
+ groups[0] = gid;
+
+ status = nss_initgroups(name, gid, &groups, &start, &size);
+ if (status == NSS_STATUS_UNAVAIL) {
+ printf("No initgroups fn\n");
+ return;
+ }
+
+ for (i=0; i<start-1; i++) {
+ printf("%lu, ", (unsigned long)groups[i]);
+ }
+ printf("%lu\n", (unsigned long)groups[i]);
+}
+
+
+static void nss_test_users(void)
+{
+ struct passwd *pwd;
+
+ nss_setpwent();
+ /* loop over all users */
+ while ((pwd = nss_getpwent())) {
+ printf("Testing user %s\n", pwd->pw_name);
+ printf("getpwent: "); print_passwd(pwd);
+ pwd = nss_getpwuid(pwd->pw_uid);
+ if (!pwd) {
+ total_errors++;
+ printf("ERROR: can't getpwuid\n");
+ continue;
+ }
+ printf("getpwuid: "); print_passwd(pwd);
+ pwd = nss_getpwnam(pwd->pw_name);
+ if (!pwd) {
+ total_errors++;
+ printf("ERROR: can't getpwnam\n");
+ continue;
+ }
+ printf("getpwnam: "); print_passwd(pwd);
+ printf("initgroups: "); nss_test_initgroups(pwd->pw_name, pwd->pw_gid);
+ printf("\n");
+ }
+ nss_endpwent();
+}
+
+static void nss_test_groups(void)
+{
+ struct group *grp;
+
+ nss_setgrent();
+ /* loop over all groups */
+ while ((grp = nss_getgrent())) {
+ printf("Testing group %s\n", grp->gr_name);
+ printf("getgrent: "); print_group(grp);
+ grp = nss_getgrnam(grp->gr_name);
+ if (!grp) {
+ total_errors++;
+ printf("ERROR: can't getgrnam\n");
+ continue;
+ }
+ printf("getgrnam: "); print_group(grp);
+ grp = nss_getgrgid(grp->gr_gid);
+ if (!grp) {
+ total_errors++;
+ printf("ERROR: can't getgrgid\n");
+ continue;
+ }
+ printf("getgrgid: "); print_group(grp);
+ printf("\n");
+ }
+ nss_endgrent();
+}
+
+static void nss_test_errors(void)
+{
+ struct passwd *pwd;
+ struct group *grp;
+
+ pwd = getpwnam("nosuchname");
+ if (pwd || last_error != NSS_STATUS_NOTFOUND) {
+ total_errors++;
+ printf("ERROR Non existant user gave error %d\n", last_error);
+ }
+
+ pwd = getpwuid(0xFFF0);
+ if (pwd || last_error != NSS_STATUS_NOTFOUND) {
+ total_errors++;
+ printf("ERROR Non existant uid gave error %d\n", last_error);
+ }
+
+ grp = getgrnam("nosuchgroup");
+ if (grp || last_error != NSS_STATUS_NOTFOUND) {
+ total_errors++;
+ printf("ERROR Non existant group gave error %d\n", last_error);
+ }
+
+ grp = getgrgid(0xFFF0);
+ if (grp || last_error != NSS_STATUS_NOTFOUND) {
+ total_errors++;
+ printf("ERROR Non existant gid gave error %d\n", last_error);
+ }
+}
+
+ int main(int argc, char *argv[])
+{
+ if (argc > 1) so_path = argv[1];
+ if (argc > 2) nss_name = argv[2];
+
+ nss_test_users();
+ nss_test_groups();
+ nss_test_errors();
+
+ printf("total_errors=%d\n", total_errors);
+
+ return total_errors;
+}
diff --git a/source3/torture/pdbtest.c b/source3/torture/pdbtest.c
new file mode 100644
index 0000000000..ab7edde85d
--- /dev/null
+++ b/source3/torture/pdbtest.c
@@ -0,0 +1,373 @@
+/*
+ Unix SMB/CIFS implementation.
+ passdb testing utility
+
+ Copyright (C) Wilco Baan Hofman 2006
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+
+static bool samu_correct(struct samu *s1, struct samu *s2)
+{
+ bool ret = True;
+ uint32 s1_len, s2_len;
+ const char *s1_buf, *s2_buf;
+ const uint8 *d1_buf, *d2_buf;
+
+ /* Check Unix username */
+ s1_buf = pdb_get_username(s1);
+ s2_buf = pdb_get_username(s2);
+ if (s2_buf == NULL && s1_buf != NULL) {
+ DEBUG(0, ("Username is not set\n"));
+ ret = False;
+ } else if (s1_buf == NULL) {
+ /* Do nothing */
+ } else if (strcmp(s1_buf,s2_buf)) {
+ DEBUG(0, ("Username not written correctly, want %s, got \"%s\"\n",
+ pdb_get_username(s1),
+ pdb_get_username(s2)));
+ ret = False;
+ }
+
+ /* Check NT username */
+ s1_buf = pdb_get_nt_username(s1);
+ s2_buf = pdb_get_nt_username(s2);
+ if (s2_buf == NULL && s1_buf != NULL) {
+ DEBUG(0, ("NT Username is not set\n"));
+ ret = False;
+ } else if (s1_buf == NULL) {
+ /* Do nothing */
+ } else if (strcmp(s1_buf, s2_buf)) {
+ DEBUG(0, ("NT Username not written correctly, want \"%s\", got \"%s\"\n",
+ pdb_get_nt_username(s1),
+ pdb_get_nt_username(s2)));
+ ret = False;
+ }
+
+ /* Check acct ctrl */
+ if (pdb_get_acct_ctrl(s1) != pdb_get_acct_ctrl(s2)) {
+ DEBUG(0, ("Acct ctrl field not written correctly, want %d (0x%X), got %d (0x%X)\n",
+ pdb_get_acct_ctrl(s1),
+ pdb_get_acct_ctrl(s1),
+ pdb_get_acct_ctrl(s2),
+ pdb_get_acct_ctrl(s2)));
+ ret = False;
+ }
+
+ /* Check NT password */
+ d1_buf = pdb_get_nt_passwd(s1);
+ d2_buf = pdb_get_nt_passwd(s2);
+ if (d2_buf == NULL && d1_buf != NULL) {
+ DEBUG(0, ("NT password is not set\n"));
+ ret = False;
+ } else if (d1_buf == NULL) {
+ /* Do nothing */
+ } else if (memcmp(d1_buf, d2_buf, NT_HASH_LEN)) {
+ DEBUG(0, ("NT password not written correctly\n"));
+ ret = False;
+ }
+
+ /* Check lanman password */
+ d1_buf = pdb_get_lanman_passwd(s1);
+ d2_buf = pdb_get_lanman_passwd(s2);
+ if (d2_buf == NULL && d1_buf != NULL) {
+ DEBUG(0, ("Lanman password is not set\n"));
+ } else if (d1_buf == NULL) {
+ /* Do nothing */
+ } else if (memcmp(d1_buf, d2_buf, NT_HASH_LEN)) {
+ DEBUG(0, ("Lanman password not written correctly\n"));
+ ret = False;
+ }
+
+ /* Check password history */
+ d1_buf = pdb_get_pw_history(s1, &s1_len);
+ d2_buf = pdb_get_pw_history(s2, &s2_len);
+ if (d2_buf == NULL && d1_buf != NULL) {
+ DEBUG(0, ("Password history is not set\n"));
+ } else if (d1_buf == NULL) {
+ /* Do nothing */
+ } else if (s1_len != s1_len) {
+ DEBUG(0, ("Password history not written correctly, lengths differ, want %d, got %d\n",
+ s1_len, s2_len));
+ ret = False;
+ } else if (strncmp(s1_buf, s2_buf, s1_len)) {
+ DEBUG(0, ("Password history not written correctly\n"));
+ ret = False;
+ }
+
+ /* Check logon time */
+ if (pdb_get_logon_time(s1) != pdb_get_logon_time(s2)) {
+ DEBUG(0, ("Logon time is not written correctly\n"));
+ ret = False;
+ }
+
+ /* Check logoff time */
+ if (pdb_get_logoff_time(s1) != pdb_get_logoff_time(s2)) {
+ DEBUG(0, ("Logoff time is not written correctly\n"));
+ ret = False;
+ }
+
+ /* Check kickoff time */
+ if (pdb_get_kickoff_time(s1) != pdb_get_logoff_time(s2)) {
+ DEBUG(0, ("Kickoff time is not written correctly\n"));
+ ret = False;
+ }
+
+ /* Check bad password time */
+ if (pdb_get_bad_password_time(s1) != pdb_get_bad_password_time(s2)) {
+ DEBUG(0, ("Bad password time is not written correctly\n"));
+ ret = False;
+ }
+
+ /* Check password last set time */
+ if (pdb_get_pass_last_set_time(s1) != pdb_get_pass_last_set_time(s2)) {
+ DEBUG(0, ("Password last set time is not written correctly\n"));
+ ret = False;
+ }
+
+ /* Check password can change time */
+ if (pdb_get_pass_can_change_time(s1) != pdb_get_pass_can_change_time(s2)) {
+ DEBUG(0, ("Password can change time is not written correctly\n"));
+ ret = False;
+ }
+
+ /* Check password must change time */
+ if (pdb_get_pass_must_change_time(s1) != pdb_get_pass_must_change_time(s2)) {
+ DEBUG(0, ("Password must change time is not written correctly\n"));
+ ret = False;
+ }
+
+ /* Check logon divs */
+ if (pdb_get_logon_divs(s1) != pdb_get_logon_divs(s2)) {
+ DEBUG(0, ("Logon divs not written correctly\n"));
+ ret = False;
+ }
+
+ /* Check logon hours */
+ if (pdb_get_hours_len(s1) != pdb_get_hours_len(s2)) {
+ DEBUG(0, ("Logon hours length not written correctly\n"));
+ ret = False;
+ } else if (pdb_get_hours_len(s1) != 0) {
+ d1_buf = pdb_get_hours(s1);
+ d2_buf = pdb_get_hours(s2);
+ if (d2_buf == NULL && d2_buf != NULL) {
+ DEBUG(0, ("Logon hours is not set\n"));
+ ret = False;
+ } else if (d1_buf == NULL) {
+ /* Do nothing */
+ } else if (memcmp(d1_buf, d2_buf, MAX_HOURS_LEN)) {
+ DEBUG(0, ("Logon hours is not written correctly\n"));
+ ret = False;
+ }
+ }
+
+ /* Check profile path */
+ s1_buf = pdb_get_profile_path(s1);
+ s2_buf = pdb_get_profile_path(s2);
+ if (s2_buf == NULL && s1_buf != NULL) {
+ DEBUG(0, ("Profile path is not set\n"));
+ ret = False;
+ } else if (s1_buf == NULL) {
+ /* Do nothing */
+ } else if (strcmp(s1_buf, s2_buf)) {
+ DEBUG(0, ("Profile path is not written correctly\n"));
+ ret = False;
+ }
+
+ /* Check home dir */
+ s1_buf = pdb_get_homedir(s1);
+ s2_buf = pdb_get_homedir(s2);
+ if (s2_buf == NULL && s1_buf != NULL) {
+ DEBUG(0, ("Home dir is not set\n"));
+ ret = False;
+ } else if (s1_buf == NULL) {
+ /* Do nothing */
+ } else if (strcmp(s1_buf, s2_buf)) {
+ DEBUG(0, ("Home dir is not written correctly\n"));
+ ret = False;
+ }
+
+ /* Check logon script */
+ s1_buf = pdb_get_logon_script(s1);
+ s2_buf = pdb_get_logon_script(s2);
+ if (s2_buf == NULL && s1_buf != NULL) {
+ DEBUG(0, ("Logon script not set\n"));
+ ret = False;
+ } else if (s1_buf == NULL) {
+ /* Do nothing */
+ } else if (strcmp(s1_buf, s2_buf)) {
+ DEBUG(0, ("Logon script is not written correctly\n"));
+ ret = False;
+ }
+
+ /* TODO Check user and group sids */
+
+ return ret;
+}
+
+
+int main(int argc, char **argv)
+{
+ TALLOC_CTX *ctx;
+ struct samu *out = NULL;
+ struct samu *in = NULL;
+ NTSTATUS rv;
+ int i;
+ struct timeval tv;
+ bool error = False;
+ struct passwd *pwd;
+ uint8 *buf;
+ uint32 expire, min_age, history;
+ struct pdb_methods *pdb;
+ poptContext pc;
+ static const char *backend = NULL;
+ static const char *unix_user = "nobody";
+ struct poptOption long_options[] = {
+ {"username", 'u', POPT_ARG_STRING, &unix_user, 0, "Unix user to use for testing", "USERNAME" },
+ {"backend", 'b', POPT_ARG_STRING, &backend, 0, "Backend to use if not default", "BACKEND[:SETTINGS]" },
+ POPT_AUTOHELP
+ POPT_COMMON_SAMBA
+ POPT_TABLEEND
+ };
+
+ load_case_tables();
+
+ pc = poptGetContext("vfstest", argc, (const char **) argv,
+ long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "backend[:settings] username");
+
+ while(poptGetNextOpt(pc) != -1);
+
+ poptFreeContext(pc);
+
+ /* Load configuration */
+ lp_load(get_dyn_CONFIGFILE(), False, False, True, True);
+ setup_logging("pdbtest", True);
+
+ if (backend == NULL) {
+ backend = lp_passdb_backend();
+ }
+
+ rv = make_pdb_method_name(&pdb, backend);
+ if (NT_STATUS_IS_ERR(rv)) {
+ fprintf(stderr, "Error initializing '%s': %s\n", backend, get_friendly_nt_error_msg(rv));
+ exit(1);
+ }
+
+ ctx = talloc_init("PDBTEST");
+
+ if (!(out = samu_new(ctx))) {
+ fprintf(stderr, "Can't create samu structure.\n");
+ exit(1);
+ }
+
+ if ((pwd = getpwnam_alloc(ctx, unix_user)) == NULL) {
+ fprintf(stderr, "Error getting user information for %s\n", unix_user);
+ exit(1);
+ }
+
+ samu_set_unix(out, pwd);
+
+ pdb_set_profile_path(out, "\\\\torture\\profile", PDB_SET);
+ pdb_set_homedir(out, "\\\\torture\\home", PDB_SET);
+ pdb_set_logon_script(out, "torture_script.cmd", PDB_SET);
+
+ pdb_get_account_policy(AP_PASSWORD_HISTORY, &history);
+ if (history * PW_HISTORY_ENTRY_LEN < NT_HASH_LEN) {
+ buf = (uint8 *)TALLOC(ctx, NT_HASH_LEN);
+ } else {
+ buf = (uint8 *)TALLOC(ctx, history * PW_HISTORY_ENTRY_LEN);
+ }
+
+ /* Generate some random hashes */
+ GetTimeOfDay(&tv);
+ srand(tv.tv_usec);
+ for (i = 0; i < NT_HASH_LEN; i++) {
+ buf[i] = (uint8) rand();
+ }
+ pdb_set_nt_passwd(out, buf, PDB_SET);
+ for (i = 0; i < LM_HASH_LEN; i++) {
+ buf[i] = (uint8) rand();
+ }
+ pdb_set_lanman_passwd(out, buf, PDB_SET);
+ for (i = 0; i < history * PW_HISTORY_ENTRY_LEN; i++) {
+ buf[i] = (uint8) rand();
+ }
+ pdb_set_pw_history(out, buf, history, PDB_SET);
+
+ pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &expire);
+ pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &min_age);
+ pdb_set_pass_last_set_time(out, time(NULL), PDB_SET);
+
+ if (expire == 0 || expire == (uint32)-1) {
+ pdb_set_pass_must_change_time(out, get_time_t_max(), PDB_SET);
+ } else {
+ pdb_set_pass_must_change_time(out, time(NULL)+expire, PDB_SET);
+ }
+
+ if (min_age == (uint32)-1) {
+ pdb_set_pass_can_change_time(out, 0, PDB_SET);
+ } else {
+ pdb_set_pass_can_change_time(out, time(NULL)+min_age, PDB_SET);
+ }
+
+ /* Create account */
+ if (!NT_STATUS_IS_OK(rv = pdb->add_sam_account(pdb, out))) {
+ fprintf(stderr, "Error in add_sam_account: %s\n",
+ get_friendly_nt_error_msg(rv));
+ exit(1);
+ }
+
+ if (!(in = samu_new(ctx))) {
+ fprintf(stderr, "Can't create samu structure.\n");
+ exit(1);
+ }
+
+ /* Get account information through getsampwnam() */
+ if (NT_STATUS_IS_ERR(pdb->getsampwnam(pdb, in, out->username))) {
+ fprintf(stderr, "Error getting sampw of added user %s.\n",
+ out->username);
+ if (!NT_STATUS_IS_OK(rv = pdb->delete_sam_account(pdb, out))) {
+ fprintf(stderr, "Error in delete_sam_account %s\n",
+ get_friendly_nt_error_msg(rv));
+ }
+ TALLOC_FREE(ctx);
+ }
+
+ /* Verify integrity */
+ if (samu_correct(out, in)) {
+ printf("User info written correctly\n");
+ } else {
+ printf("User info NOT written correctly\n");
+ error = True;
+ }
+
+ /* Delete account */
+ if (!NT_STATUS_IS_OK(rv = pdb->delete_sam_account(pdb, out))) {
+ fprintf(stderr, "Error in delete_sam_account %s\n",
+ get_friendly_nt_error_msg(rv));
+ }
+
+ TALLOC_FREE(ctx);
+
+ if (error) {
+ return 1;
+ }
+ return 0;
+}
diff --git a/source3/torture/rpc_open_tcp.c b/source3/torture/rpc_open_tcp.c
new file mode 100644
index 0000000000..14077957c4
--- /dev/null
+++ b/source3/torture/rpc_open_tcp.c
@@ -0,0 +1,109 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * test program for rpc_pipe_open_tcp().
+ *
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#include "librpc/gen_ndr/ndr_dfs.h"
+#include "librpc/gen_ndr/ndr_drsuapi.h"
+#include "librpc/gen_ndr/ndr_dssetup.h"
+#include "librpc/gen_ndr/ndr_echo.h"
+#include "librpc/gen_ndr/ndr_epmapper.h"
+#include "librpc/gen_ndr/ndr_eventlog.h"
+#include "librpc/gen_ndr/ndr_initshutdown.h"
+#include "librpc/gen_ndr/ndr_lsa.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "librpc/gen_ndr/ndr_ntsvcs.h"
+#include "librpc/gen_ndr/ndr_samr.h"
+#include "librpc/gen_ndr/ndr_srvsvc.h"
+#include "librpc/gen_ndr/ndr_svcctl.h"
+#include "librpc/gen_ndr/ndr_winreg.h"
+#include "librpc/gen_ndr/ndr_wkssvc.h"
+
+extern const struct ndr_interface_table ndr_table_netdfs;
+extern const struct ndr_interface_table ndr_table_drsuapi;
+extern const struct ndr_interface_table ndr_table_dssetup;
+extern const struct ndr_interface_table ndr_table_rpcecho;
+extern const struct ndr_interface_table ndr_table_epmapper;
+extern const struct ndr_interface_table ndr_table_eventlog;
+extern const struct ndr_interface_table ndr_table_initshutdown;
+extern const struct ndr_interface_table ndr_table_lsarpc;
+extern const struct ndr_interface_table ndr_table_netlogon;
+extern const struct ndr_interface_table ndr_table_ntsvcs;
+extern const struct ndr_interface_table ndr_table_samr;
+extern const struct ndr_interface_table ndr_table_srvsvc;
+extern const struct ndr_interface_table ndr_table_svcctl;
+extern const struct ndr_interface_table ndr_table_winreg;
+extern const struct ndr_interface_table ndr_table_wkssvc;
+
+const struct ndr_interface_table *tables[] = {
+ &ndr_table_netdfs,
+ &ndr_table_drsuapi,
+ &ndr_table_dssetup,
+ &ndr_table_rpcecho,
+ &ndr_table_epmapper,
+ &ndr_table_eventlog,
+ &ndr_table_initshutdown,
+ &ndr_table_lsarpc,
+ &ndr_table_netlogon,
+ &ndr_table_ntsvcs,
+ &ndr_table_samr,
+ &ndr_table_srvsvc,
+ &ndr_table_svcctl,
+ &ndr_table_winreg,
+ &ndr_table_wkssvc,
+ NULL
+};
+
+int main(int argc, const char **argv)
+{
+ const struct ndr_interface_table **table;
+ NTSTATUS status;
+ struct rpc_pipe_client *rpc_pipe = NULL;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ if (argc != 3) {
+ d_printf("USAGE: %s interface host\n", argv[0]);
+ return -1;
+ }
+
+ for (table = tables; *table != NULL; table++) {
+ if (strequal((*table)->name, argv[1])) {
+ break;
+ }
+ }
+
+ if (*table == NULL) {
+ d_printf("ERROR: unknown interface '%s' given\n", argv[1]);
+ return -1;
+ }
+
+ status = rpc_pipe_open_tcp(mem_ctx, argv[2], &((*table)->syntax_id),
+ &rpc_pipe);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("ERROR calling rpc_pipe_open_tcp(): %s\n",
+ nt_errstr(status));
+ return -1;
+ }
+
+ TALLOC_FREE(mem_ctx);
+
+ return 0;
+}
+
diff --git a/source3/torture/scanner.c b/source3/torture/scanner.c
new file mode 100644
index 0000000000..21b32dcf23
--- /dev/null
+++ b/source3/torture/scanner.c
@@ -0,0 +1,430 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester - scanning functions
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#define VERBOSE 0
+#define OP_MIN 0
+#define OP_MAX 20
+
+#define DATA_SIZE 1024
+#define PARAM_SIZE 1024
+
+/****************************************************************************
+look for a partial hit
+****************************************************************************/
+static void trans2_check_hit(const char *format, int op, int level, NTSTATUS status)
+{
+ if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_LEVEL) ||
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ||
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_SUPPORTED) ||
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) ||
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) {
+ return;
+ }
+#if VERBOSE
+ printf("possible %s hit op=%3d level=%5d status=%s\n",
+ format, op, level, nt_errstr(status));
+#endif
+}
+
+/****************************************************************************
+check for existance of a trans2 call
+****************************************************************************/
+static NTSTATUS try_trans2(struct cli_state *cli,
+ int op,
+ char *param, char *data,
+ int param_len, int data_len,
+ unsigned int *rparam_len, unsigned int *rdata_len)
+{
+ uint16 setup = op;
+ char *rparam=NULL, *rdata=NULL;
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return cli_nt_error(cli);
+ }
+
+ cli_receive_trans(cli, SMBtrans2,
+ &rparam, rparam_len,
+ &rdata, rdata_len);
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return cli_nt_error(cli);
+}
+
+
+static NTSTATUS try_trans2_len(struct cli_state *cli,
+ const char *format,
+ int op, int level,
+ char *param, char *data,
+ int param_len, int *data_len,
+ unsigned int *rparam_len, unsigned int *rdata_len)
+{
+ NTSTATUS ret=NT_STATUS_OK;
+
+ ret = try_trans2(cli, op, param, data, param_len,
+ DATA_SIZE, rparam_len, rdata_len);
+#if VERBOSE
+ printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret));
+#endif
+ if (!NT_STATUS_IS_OK(ret)) return ret;
+
+ *data_len = 0;
+ while (*data_len < DATA_SIZE) {
+ ret = try_trans2(cli, op, param, data, param_len,
+ *data_len, rparam_len, rdata_len);
+ if (NT_STATUS_IS_OK(ret)) break;
+ *data_len += 2;
+ }
+ if (NT_STATUS_IS_OK(ret)) {
+ printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
+ format, level, *data_len, *rparam_len, *rdata_len);
+ } else {
+ trans2_check_hit(format, op, level, ret);
+ }
+ return ret;
+}
+
+/****************************************************************************
+check for existance of a trans2 call
+****************************************************************************/
+static bool scan_trans2(struct cli_state *cli, int op, int level,
+ int fnum, int dnum, const char *fname)
+{
+ int data_len = 0;
+ int param_len = 0;
+ unsigned int rparam_len, rdata_len;
+ char param[PARAM_SIZE], data[DATA_SIZE];
+ NTSTATUS status;
+
+ memset(data, 0, sizeof(data));
+ data_len = 4;
+
+ /* try with a info level only */
+ param_len = 2;
+ SSVAL(param, 0, level);
+ status = try_trans2_len(cli, "void", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ /* try with a file descriptor */
+ param_len = 6;
+ SSVAL(param, 0, fnum);
+ SSVAL(param, 2, level);
+ SSVAL(param, 4, 0);
+ status = try_trans2_len(cli, "fnum", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) return True;
+
+
+ /* try with a notify style */
+ param_len = 6;
+ SSVAL(param, 0, dnum);
+ SSVAL(param, 2, dnum);
+ SSVAL(param, 4, level);
+ status = try_trans2_len(cli, "notify", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ /* try with a file name */
+ param_len = 6;
+ SSVAL(param, 0, level);
+ SSVAL(param, 2, 0);
+ SSVAL(param, 4, 0);
+ param_len += clistr_push(cli, &param[6], fname, -1, STR_TERMINATE);
+
+ status = try_trans2_len(cli, "fname", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ /* try with a new file name */
+ param_len = 6;
+ SSVAL(param, 0, level);
+ SSVAL(param, 2, 0);
+ SSVAL(param, 4, 0);
+ param_len += clistr_push(cli, &param[6], "\\newfile.dat", -1, STR_TERMINATE);
+
+ status = try_trans2_len(cli, "newfile", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ cli_unlink(cli, "\\newfile.dat");
+ cli_rmdir(cli, "\\newfile.dat");
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ /* try dfs style */
+ cli_mkdir(cli, "\\testdir");
+ param_len = 2;
+ SSVAL(param, 0, level);
+ param_len += clistr_push(cli, &param[2], "\\testdir", -1, STR_TERMINATE);
+
+ status = try_trans2_len(cli, "dfs", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ cli_rmdir(cli, "\\testdir");
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ return False;
+}
+
+
+bool torture_trans2_scan(int dummy)
+{
+ static struct cli_state *cli;
+ int op, level;
+ const char *fname = "\\scanner.dat";
+ int fnum, dnum;
+
+ printf("starting trans2 scan test\n");
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ fnum = cli_open(cli, fname, O_RDWR | O_CREAT | O_TRUNC,
+ DENY_NONE);
+ dnum = cli_open(cli, "\\", O_RDONLY, DENY_NONE);
+
+ for (op=OP_MIN; op<=OP_MAX; op++) {
+ printf("Scanning op=%d\n", op);
+ for (level = 0; level <= 50; level++) {
+ scan_trans2(cli, op, level, fnum, dnum, fname);
+ }
+
+ for (level = 0x100; level <= 0x130; level++) {
+ scan_trans2(cli, op, level, fnum, dnum, fname);
+ }
+
+ for (level = 1000; level < 1050; level++) {
+ scan_trans2(cli, op, level, fnum, dnum, fname);
+ }
+ }
+
+ torture_close_connection(cli);
+
+ printf("trans2 scan finished\n");
+ return True;
+}
+
+
+
+
+/****************************************************************************
+look for a partial hit
+****************************************************************************/
+static void nttrans_check_hit(const char *format, int op, int level, NTSTATUS status)
+{
+ if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_LEVEL) ||
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ||
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_SUPPORTED) ||
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) ||
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) {
+ return;
+ }
+#if VERBOSE
+ printf("possible %s hit op=%3d level=%5d status=%s\n",
+ format, op, level, nt_errstr(status));
+#endif
+}
+
+/****************************************************************************
+check for existance of a nttrans call
+****************************************************************************/
+static NTSTATUS try_nttrans(struct cli_state *cli,
+ int op,
+ char *param, char *data,
+ int param_len, int data_len,
+ unsigned int *rparam_len, unsigned int *rdata_len)
+{
+ char *rparam=NULL, *rdata=NULL;
+
+ if (!cli_send_nt_trans(cli, op,
+ 0,
+ NULL, 0, 0,
+ param, param_len, 2, /* param, length, max */
+ data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return cli_nt_error(cli);
+ }
+
+ cli_receive_nt_trans(cli,
+ &rparam, rparam_len,
+ &rdata, rdata_len);
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return cli_nt_error(cli);
+}
+
+
+static NTSTATUS try_nttrans_len(struct cli_state *cli,
+ const char *format,
+ int op, int level,
+ char *param, char *data,
+ int param_len, int *data_len,
+ unsigned int *rparam_len, unsigned int *rdata_len)
+{
+ NTSTATUS ret=NT_STATUS_OK;
+
+ ret = try_nttrans(cli, op, param, data, param_len,
+ DATA_SIZE, rparam_len, rdata_len);
+#if VERBOSE
+ printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret));
+#endif
+ if (!NT_STATUS_IS_OK(ret)) return ret;
+
+ *data_len = 0;
+ while (*data_len < DATA_SIZE) {
+ ret = try_nttrans(cli, op, param, data, param_len,
+ *data_len, rparam_len, rdata_len);
+ if (NT_STATUS_IS_OK(ret)) break;
+ *data_len += 2;
+ }
+ if (NT_STATUS_IS_OK(ret)) {
+ printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
+ format, level, *data_len, *rparam_len, *rdata_len);
+ } else {
+ nttrans_check_hit(format, op, level, ret);
+ }
+ return ret;
+}
+
+/****************************************************************************
+check for existance of a nttrans call
+****************************************************************************/
+static bool scan_nttrans(struct cli_state *cli, int op, int level,
+ int fnum, int dnum, const char *fname)
+{
+ int data_len = 0;
+ int param_len = 0;
+ unsigned int rparam_len, rdata_len;
+ char param[PARAM_SIZE], data[DATA_SIZE];
+ NTSTATUS status;
+
+ memset(data, 0, sizeof(data));
+ data_len = 4;
+
+ /* try with a info level only */
+ param_len = 2;
+ SSVAL(param, 0, level);
+ status = try_nttrans_len(cli, "void", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ /* try with a file descriptor */
+ param_len = 6;
+ SSVAL(param, 0, fnum);
+ SSVAL(param, 2, level);
+ SSVAL(param, 4, 0);
+ status = try_nttrans_len(cli, "fnum", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) return True;
+
+
+ /* try with a notify style */
+ param_len = 6;
+ SSVAL(param, 0, dnum);
+ SSVAL(param, 2, dnum);
+ SSVAL(param, 4, level);
+ status = try_nttrans_len(cli, "notify", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ /* try with a file name */
+ param_len = 6;
+ SSVAL(param, 0, level);
+ SSVAL(param, 2, 0);
+ SSVAL(param, 4, 0);
+ param_len += clistr_push(cli, &param[6], fname, -1, STR_TERMINATE);
+
+ status = try_nttrans_len(cli, "fname", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ /* try with a new file name */
+ param_len = 6;
+ SSVAL(param, 0, level);
+ SSVAL(param, 2, 0);
+ SSVAL(param, 4, 0);
+ param_len += clistr_push(cli, &param[6], "\\newfile.dat", -1, STR_TERMINATE);
+
+ status = try_nttrans_len(cli, "newfile", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ cli_unlink(cli, "\\newfile.dat");
+ cli_rmdir(cli, "\\newfile.dat");
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ /* try dfs style */
+ cli_mkdir(cli, "\\testdir");
+ param_len = 2;
+ SSVAL(param, 0, level);
+ param_len += clistr_push(cli, &param[2], "\\testdir", -1, STR_TERMINATE);
+
+ status = try_nttrans_len(cli, "dfs", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ cli_rmdir(cli, "\\testdir");
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ return False;
+}
+
+
+bool torture_nttrans_scan(int dummy)
+{
+ static struct cli_state *cli;
+ int op, level;
+ const char *fname = "\\scanner.dat";
+ int fnum, dnum;
+
+ printf("starting nttrans scan test\n");
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ fnum = cli_open(cli, fname, O_RDWR | O_CREAT | O_TRUNC,
+ DENY_NONE);
+ dnum = cli_open(cli, "\\", O_RDONLY, DENY_NONE);
+
+ for (op=OP_MIN; op<=OP_MAX; op++) {
+ printf("Scanning op=%d\n", op);
+ for (level = 0; level <= 50; level++) {
+ scan_nttrans(cli, op, level, fnum, dnum, fname);
+ }
+
+ for (level = 0x100; level <= 0x130; level++) {
+ scan_nttrans(cli, op, level, fnum, dnum, fname);
+ }
+
+ for (level = 1000; level < 1050; level++) {
+ scan_nttrans(cli, op, level, fnum, dnum, fname);
+ }
+ }
+
+ torture_close_connection(cli);
+
+ printf("nttrans scan finished\n");
+ return True;
+}
diff --git a/source3/torture/smbiconv.c b/source3/torture/smbiconv.c
new file mode 100644
index 0000000000..72fbdc470f
--- /dev/null
+++ b/source3/torture/smbiconv.c
@@ -0,0 +1,243 @@
+/*
+ Unix SMB/CIFS implementation.
+ Charset module tester
+
+ Copyright (C) Jelmer Vernooij 2003
+ Based on iconv/icon_prog.c from the GNU C Library,
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#undef realloc
+
+static int
+process_block (smb_iconv_t cd, const char *addr, size_t len, FILE *output)
+{
+#define OUTBUF_SIZE 32768
+ const char *start = addr;
+ char outbuf[OUTBUF_SIZE];
+ char *outptr;
+ size_t outlen;
+ size_t n;
+
+ while (len > 0)
+ {
+ outptr = outbuf;
+ outlen = OUTBUF_SIZE;
+ n = smb_iconv (cd, &addr, &len, &outptr, &outlen);
+
+ if (outptr != outbuf)
+ {
+ /* We have something to write out. */
+ int errno_save = errno;
+
+ if (fwrite (outbuf, 1, outptr - outbuf, output)
+ < (size_t) (outptr - outbuf)
+ || ferror (output))
+ {
+ /* Error occurred while printing the result. */
+ DEBUG (0, ("conversion stopped due to problem in writing the output"));
+ return -1;
+ }
+
+ errno = errno_save;
+ }
+
+ if (errno != E2BIG)
+ {
+ /* iconv() ran into a problem. */
+ switch (errno)
+ {
+ case EILSEQ:
+ DEBUG(0,("illegal input sequence at position %ld",
+ (long) (addr - start)));
+ break;
+ case EINVAL:
+ DEBUG(0, ("\
+incomplete character or shift sequence at end of buffer"));
+ break;
+ case EBADF:
+ DEBUG(0, ("internal error (illegal descriptor)"));
+ break;
+ default:
+ DEBUG(0, ("unknown iconv() error %d", errno));
+ break;
+ }
+
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+process_fd (smb_iconv_t cd, int fd, FILE *output)
+{
+ /* we have a problem with reading from a descriptor since we must not
+ provide the iconv() function an incomplete character or shift
+ sequence at the end of the buffer. Since we have to deal with
+ arbitrary encodings we must read the whole text in a buffer and
+ process it in one step. */
+ static char *inbuf = NULL;
+ static size_t maxlen = 0;
+ char *inptr = NULL;
+ size_t actlen = 0;
+
+ while (actlen < maxlen)
+ {
+ ssize_t n = read (fd, inptr, maxlen - actlen);
+
+ if (n == 0)
+ /* No more text to read. */
+ break;
+
+ if (n == -1)
+ {
+ /* Error while reading. */
+ DEBUG(0, ("error while reading the input"));
+ return -1;
+ }
+
+ inptr += n;
+ actlen += n;
+ }
+
+ if (actlen == maxlen)
+ while (1)
+ {
+ ssize_t n;
+ char *new_inbuf;
+
+ /* Increase the buffer. */
+ new_inbuf = (char *) realloc (inbuf, maxlen + 32768);
+ if (new_inbuf == NULL)
+ {
+ DEBUG(0, ("unable to allocate buffer for input"));
+ return -1;
+ }
+ inbuf = new_inbuf;
+ maxlen += 32768;
+ inptr = inbuf + actlen;
+
+ do
+ {
+ n = read (fd, inptr, maxlen - actlen);
+
+ if (n == 0)
+ /* No more text to read. */
+ break;
+
+ if (n == -1)
+ {
+ /* Error while reading. */
+ DEBUG(0, ("error while reading the input"));
+ return -1;
+ }
+
+ inptr += n;
+ actlen += n;
+ }
+ while (actlen < maxlen);
+
+ if (n == 0)
+ /* Break again so we leave both loops. */
+ break;
+ }
+
+ /* Now we have all the input in the buffer. Process it in one run. */
+ return process_block (cd, inbuf, actlen, output);
+}
+
+/* Main function */
+
+int main(int argc, char *argv[])
+{
+ const char *file = NULL;
+ const char *from = "";
+ const char *to = "";
+ char *output = NULL;
+ const char *preload_modules[] = {NULL, NULL};
+ FILE *out = stdout;
+ int fd;
+ smb_iconv_t cd;
+
+ /* make sure the vars that get altered (4th field) are in
+ a fixed location or certain compilers complain */
+ poptContext pc;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "from-code", 'f', POPT_ARG_STRING, &from, 0, "Encoding of original text" },
+ { "to-code", 't', POPT_ARG_STRING, &to, 0, "Encoding for output" },
+ { "output", 'o', POPT_ARG_STRING, &output, 0, "Write output to this file" },
+ { "preload-modules", 'p', POPT_ARG_STRING, &preload_modules[0], 0, "Modules to load" },
+ POPT_COMMON_SAMBA
+ POPT_TABLEEND
+ };
+
+ setlinebuf(stdout);
+
+ pc = poptGetContext("smbiconv", argc, (const char **) argv,
+ long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "[FILE] ...");
+
+ while(poptGetNextOpt(pc) != -1);
+
+ /* the following functions are part of the Samba debugging
+ facilities. See lib/debug.c */
+ setup_logging("smbiconv", True);
+
+ if (preload_modules[0]) smb_load_modules(preload_modules);
+
+ if(output) {
+ out = fopen(output, "w");
+
+ if(!out) {
+ DEBUG(0, ("Can't open output file '%s': %s, exiting...\n", output, strerror(errno)));
+ return 1;
+ }
+ }
+
+ cd = smb_iconv_open(to, from);
+ if (cd == (smb_iconv_t)-1) {
+ DEBUG(0,("unable to find from or to encoding, exiting...\n"));
+ return 1;
+ }
+
+ while((file = poptGetArg(pc))) {
+ if(strcmp(file, "-") == 0) fd = 0;
+ else {
+ fd = open(file, O_RDONLY);
+
+ if(!fd) {
+ DEBUG(0, ("Can't open input file '%s': %s, ignoring...\n", file, strerror(errno)));
+ continue;
+ }
+ }
+
+ /* Loop thru all arguments */
+ process_fd(cd, fd, out);
+
+ close(fd);
+ }
+ poptFreeContext(pc);
+
+ fclose(out);
+
+ return 0;
+}
diff --git a/source3/torture/t_asn1.c b/source3/torture/t_asn1.c
new file mode 100644
index 0000000000..5862742bc1
--- /dev/null
+++ b/source3/torture/t_asn1.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2004 by Volker Lendecke
+ *
+ * Test harness for asn1_write_*, inspired by Love Hornquist Astrand
+ */
+
+#include "includes.h"
+
+static DATA_BLOB tests[] = {
+ {"\x02\x01\x00", 3, NULL},
+ {"\x02\x01\x7f", 3, NULL},
+ {"\x02\x02\x00\x80", 4, NULL},
+ {"\x02\x02\x01\x00", 4, NULL},
+ {"\x02\x01\x80", 3, NULL},
+ {"\x02\x02\xff\x7f", 4, NULL},
+ {"\x02\x01\xff", 3, NULL},
+ {"\x02\x02\xff\x01", 4, NULL},
+ {"\x02\x02\x00\xff", 4, NULL},
+ {"\x02\x04\x80\x00\x00\x00", 6, NULL},
+ {"\x02\x04\x7f\xff\xff\xff", 6, NULL},
+ {NULL, 0, NULL}
+};
+
+static int values[] = {0, 127, 128, 256, -128, -129, -1, -255, 255,
+ 0x80000000, 0x7fffffff};
+
+int main(void)
+{
+ int i = 0;
+ int val;
+ bool ok = True;
+
+ for (i=0; tests[i].data != NULL; i++) {
+ ASN1_DATA data;
+ DATA_BLOB blob;
+
+ ZERO_STRUCT(data);
+ asn1_write_Integer(&data, values[i]);
+
+ if ((data.length != tests[i].length) ||
+ (memcmp(data.data, tests[i].data, data.length) != 0)) {
+ printf("Test for %d failed\n", values[i]);
+ ok = False;
+ }
+
+ blob.data = data.data;
+ blob.length = data.length;
+ asn1_load(&data, blob);
+ if (!asn1_read_Integer(&data, &val)) {
+ printf("Could not read our own Integer for %d\n",
+ values[i]);
+ ok = False;
+ }
+ if (val != values[i]) {
+ printf("%d -> ASN -> Int %d\n", values[i], val);
+ ok = False;
+ }
+ }
+
+ return ok ? 0 : 1;
+}
diff --git a/source3/torture/t_push_ucs2.c b/source3/torture/t_push_ucs2.c
new file mode 100644
index 0000000000..b9bf87ba54
--- /dev/null
+++ b/source3/torture/t_push_ucs2.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2003 by Martin Pool
+ * Copyright (C) 2003 by Andrew Bartlett
+ *
+ * Test harness for push_ucs2
+ */
+
+#include "includes.h"
+
+static int check_push_ucs2(const char *orig)
+{
+ smb_ucs2_t *dest = NULL;
+ char *orig2 = NULL;
+ int ret;
+ size_t converted_size;
+
+ push_ucs2_allocate(&dest, orig, &converted_size);
+ pull_ucs2_allocate(&orig2, dest, &converted_size);
+ ret = strcmp(orig, orig2);
+ if (ret) {
+ fprintf(stderr, "orig: %s\n", orig);
+ fprintf(stderr, "orig (UNIX -> UCS2 -> UNIX): %s\n", orig2);
+ }
+
+ SAFE_FREE(dest);
+ SAFE_FREE(orig2);
+
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int i, ret = 0;
+ int count = 1;
+
+ /* Needed to initialize character set */
+ lp_load("/dev/null", True, False, False, True);
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s STRING1 [COUNT]\n"
+ "Checks that a string translated UNIX->UCS2->UNIX is unchanged\n"
+ "Should be always 0\n",
+ argv[0]);
+ return 2;
+ }
+ if (argc >= 3)
+ count = atoi(argv[2]);
+
+ for (i = 0; ((i < count) && (!ret)); i++)
+ ret = check_push_ucs2(argv[1]);
+
+ printf("%d\n", ret);
+
+ return 0;
+}
diff --git a/source3/torture/t_strappend.c b/source3/torture/t_strappend.c
new file mode 100644
index 0000000000..becc691c7f
--- /dev/null
+++ b/source3/torture/t_strappend.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2005 by Volker Lendecke
+ *
+ * Test harness for sprintf_append
+ */
+
+#include "includes.h"
+#include <assert.h>
+
+int main(int argc, char *argv[])
+{
+ TALLOC_CTX *mem_ctx;
+ char *string = NULL;
+ int len = 0;
+ int bufsize = 4;
+ int i;
+
+ mem_ctx = talloc_init("t_strappend");
+ if (mem_ctx == NULL) {
+ fprintf(stderr, "talloc_init failed\n");
+ return 1;
+ }
+
+ sprintf_append(mem_ctx, &string, &len, &bufsize, "");
+ assert(strlen(string) == len);
+ sprintf_append(mem_ctx, &string, &len, &bufsize, "");
+ assert(strlen(string) == len);
+ sprintf_append(mem_ctx, &string, &len, &bufsize,
+ "01234567890123456789012345678901234567890123456789\n");
+ assert(strlen(string) == len);
+
+
+ for (i=0; i<(100000); i++) {
+ if (i%1000 == 0) {
+ printf("%d %d\r", i, bufsize);
+ fflush(stdout);
+ }
+ sprintf_append(mem_ctx, &string, &len, &bufsize, "%d\n", i);
+ assert(strlen(string) == len);
+ }
+
+ talloc_destroy(mem_ctx);
+
+ return 0;
+}
diff --git a/source3/torture/t_strcmp.c b/source3/torture/t_strcmp.c
new file mode 100644
index 0000000000..318423b8be
--- /dev/null
+++ b/source3/torture/t_strcmp.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2003 by Martin Pool
+ *
+ * Test harness for StrCaseCmp
+ */
+
+#include "includes.h"
+
+int main(int argc, char *argv[])
+{
+ int i, ret;
+ int iters = 1;
+
+ /* Needed to initialize character set */
+ lp_load("/dev/null", True, False, False, True);
+
+ if (argc < 3) {
+ fprintf(stderr, "usage: %s STRING1 STRING2 [ITERS]\n"
+ "Compares two strings, prints the results of StrCaseCmp\n",
+ argv[0]);
+ return 2;
+ }
+ if (argc >= 4)
+ iters = atoi(argv[3]);
+
+ for (i = 0; i < iters; i++)
+ ret = StrCaseCmp(argv[1], argv[2]);
+
+ printf("%d\n", ret);
+
+ return 0;
+}
diff --git a/source3/torture/t_stringoverflow.c b/source3/torture/t_stringoverflow.c
new file mode 100644
index 0000000000..ec14d81189
--- /dev/null
+++ b/source3/torture/t_stringoverflow.c
@@ -0,0 +1,23 @@
+#include "includes.h"
+
+ int main(void)
+{
+ fstring dest;
+ char *ptr = dest;
+
+ printf("running on valgrind? %d\n", RUNNING_ON_VALGRIND);
+
+ /* Try copying a string into an fstring buffer. The string
+ * will actually fit, but this is still wrong because you
+ * can't pstrcpy into an fstring. This should trap in a
+ * developer build. */
+
+#if 0
+ /* As of CVS 20030318, this will be trapped at compile time! */
+ pstrcpy(dest, "hello");
+#endif /* 0 */
+
+ pstrcpy(ptr, "hello!");
+
+ return 0;
+}
diff --git a/source3/torture/t_strstr.c b/source3/torture/t_strstr.c
new file mode 100644
index 0000000000..49180b219f
--- /dev/null
+++ b/source3/torture/t_strstr.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2003 by Martin Pool
+ *
+ * Test harness for strstr_m
+ */
+
+#include "includes.h"
+
+int main(int argc, char *argv[])
+{
+ int i;
+ int iters = 1;
+
+ const char *ret = NULL;
+
+ /* Needed to initialize character set */
+ lp_load("/dev/null", True, False, False, True);
+
+ if (argc < 3) {
+ fprintf(stderr, "usage: %s STRING1 STRING2 [ITERS]\n"
+ "Compares two strings, prints the results of strstr_m\n",
+ argv[0]);
+ return 2;
+ }
+ if (argc >= 4)
+ iters = atoi(argv[3]);
+
+ for (i = 0; i < iters; i++) {
+ ret = strstr_m(argv[1], argv[2]);
+ }
+
+ if (ret == NULL)
+ ret = "(null)";
+
+ printf("%s\n", ret);
+
+ return 0;
+}
diff --git a/source3/torture/test_ntlm_auth.py b/source3/torture/test_ntlm_auth.py
new file mode 100755
index 0000000000..12a4dae398
--- /dev/null
+++ b/source3/torture/test_ntlm_auth.py
@@ -0,0 +1,218 @@
+#!/usr/bin/env python
+
+# Unix SMB/CIFS implementation.
+# A test for the ntlm_auth tool
+# Copyright (C) Kai Blin <kai@samba.org> 2008
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+"""Test ntlm_auth
+This test program will start ntlm_auth with the given command line switches and
+see if it will get the expected results.
+"""
+
+import os
+import sys
+from optparse import OptionParser
+
+class ReadChildError(Exception):
+ pass
+
+class WriteChildError(Exception):
+ pass
+
+def readLine(pipe):
+ """readLine(pipe) -> str
+ Read a line from the child's pipe, returns the string read.
+ Throws ReadChildError if the read fails.
+ """
+ buf = os.read(pipe, 2047)
+ newline = buf.find('\n')
+ if newline == -1:
+ raise ReadChildError()
+ return buf[:newline]
+
+def writeLine(pipe, buf):
+ """writeLine(pipe, buf) -> nul
+ Write a line to the child's pipe.
+ Raises WriteChildError if the write fails.
+ """
+ written = os.write(pipe, buf)
+ if written != len(buf):
+ raise WriteChildError()
+ os.write(pipe, "\n")
+
+def parseCommandLine():
+ """parseCommandLine() -> (opts, ntlm_auth_path)
+ Parse the command line.
+ Return a tuple consisting of the options and the path to ntlm_auth.
+ """
+ usage = "usage: %prog [options] path/to/ntlm_auth"
+ parser = OptionParser(usage)
+
+ parser.set_defaults(client_username="foo")
+ parser.set_defaults(client_password="secret")
+ parser.set_defaults(client_domain="FOO")
+ parser.set_defaults(client_helper="ntlmssp-client-1")
+
+ parser.set_defaults(server_username="foo")
+ parser.set_defaults(server_password="secret")
+ parser.set_defaults(server_domain="FOO")
+ parser.set_defaults(server_helper="squid-2.5-ntlmssp")
+ parser.set_defaults(config_file="/etc/samba/smb.conf")
+
+ parser.add_option("--client-username", dest="client_username",\
+ help="User name for the client. [default: foo]")
+ parser.add_option("--client-password", dest="client_password",\
+ help="Password the client will send. [default: secret]")
+ parser.add_option("--client-domain", dest="client_domain",\
+ help="Domain the client authenticates for. [default: FOO]")
+ parser.add_option("--client-helper", dest="client_helper",\
+ help="Helper mode for the ntlm_auth client. [default: ntlmssp-client-1]")
+
+ parser.add_option("--server-username", dest="server_username",\
+ help="User name server uses for local auth. [default: foo]")
+ parser.add_option("--server-password", dest="server_password",\
+ help="Password server uses for local auth. [default: secret]")
+ parser.add_option("--server-domain", dest="server_domain",\
+ help="Domain server uses for local auth. [default: FOO]")
+ parser.add_option("--server-helper", dest="server_helper",\
+ help="Helper mode for the ntlm_auth server. [default: squid-2.5-server]")
+
+ parser.add_option("-s", "--configfile", dest="config_file",\
+ help="Path to smb.conf file. [default:/etc/samba/smb.conf")
+
+ (opts, args) = parser.parse_args()
+ if len(args) != 1:
+ parser.error("Invalid number of arguments.")
+
+ if not os.access(args[0], os.X_OK):
+ parser.error("%s is not executable." % args[0])
+
+ return (opts, args[0])
+
+
+def main():
+ """main() -> int
+ Run the test.
+ Returns 0 if test succeeded, <>0 otherwise.
+ """
+ (opts, ntlm_auth_path) = parseCommandLine()
+
+ (client_in_r, client_in_w) = os.pipe()
+ (client_out_r, client_out_w) = os.pipe()
+
+ client_pid = os.fork()
+
+ if not client_pid:
+ # We're in the client child
+ os.close(0)
+ os.close(1)
+
+ os.dup2(client_out_r, 0)
+ os.close(client_out_r)
+ os.close(client_out_w)
+
+ os.dup2(client_in_w, 1)
+ os.close(client_in_r)
+ os.close(client_in_w)
+
+ client_args = []
+ client_args.append("--helper-protocol=%s" % opts.client_helper)
+ client_args.append("--username=%s" % opts.client_username)
+ client_args.append("--password=%s" % opts.client_password)
+ client_args.append("--domain=%s" % opts.client_domain)
+ client_args.append("--configfile=%s" % opts.config_file)
+
+ os.execv(ntlm_auth_path, client_args)
+
+ client_in = client_in_r
+ os.close(client_in_w)
+
+ client_out = client_out_w
+ os.close(client_out_r)
+
+ (server_in_r, server_in_w) = os.pipe()
+ (server_out_r, server_out_w) = os.pipe()
+
+ server_pid = os.fork()
+
+ if not server_pid:
+ # We're in the server child
+ os.close(0)
+ os.close(1)
+
+ os.dup2(server_out_r, 0)
+ os.close(server_out_r)
+ os.close(server_out_w)
+
+ os.dup2(server_in_w, 1)
+ os.close(server_in_r)
+ os.close(server_in_w)
+
+ server_args = []
+ server_args.append("--helper-protocol=%s" % opts.server_helper)
+ server_args.append("--username=%s" % opts.server_username)
+ server_args.append("--password=%s" % opts.server_password)
+ server_args.append("--domain=%s" % opts.server_domain)
+ server_args.append("--configfile=%s" % opts.config_file)
+
+ os.execv(ntlm_auth_path, server_args)
+
+ server_in = server_in_r
+ os.close(server_in_w)
+
+ server_out = server_out_w
+ os.close(server_out_r)
+
+ # We're in the parent
+ writeLine(client_out, "YR")
+ buf = readLine(client_in)
+
+ if buf.count("YR ", 0, 3) != 1:
+ sys.exit(1)
+
+ writeLine(server_out, buf)
+ buf = readLine(server_in)
+
+ if buf.count("TT ", 0, 3) != 1:
+ sys.exit(2)
+
+ writeLine(client_out, buf)
+ buf = readLine(client_in)
+
+ if buf.count("AF ", 0, 3) != 1:
+ sys.exit(3)
+
+ # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>'
+ buf = buf.replace("AF", "KK", 1)
+
+ writeLine(server_out, buf)
+ buf = readLine(server_in)
+
+ if buf.count("AF ", 0, 3) != 1:
+ sys.exit(4)
+
+ os.close(server_in)
+ os.close(server_out)
+ os.close(client_in)
+ os.close(client_out)
+ os.waitpid(server_pid, 0)
+ os.waitpid(client_pid, 0)
+ sys.exit(0)
+
+if __name__ == "__main__":
+ main()
+
+
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
new file mode 100644
index 0000000000..d8942e42b9
--- /dev/null
+++ b/source3/torture/torture.c
@@ -0,0 +1,5770 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+extern char *optarg;
+extern int optind;
+
+static fstring host, workgroup, share, password, username, myname;
+static int max_protocol = PROTOCOL_NT1;
+static const char *sockops="TCP_NODELAY";
+static int nprocs=1;
+static int port_to_use=0;
+int torture_numops=100;
+static int procnum; /* records process count number when forking */
+static struct cli_state *current_cli;
+static fstring randomfname;
+static bool use_oplocks;
+static bool use_level_II_oplocks;
+static const char *client_txt = "client_oplocks.txt";
+static bool use_kerberos;
+static fstring multishare_conn_fname;
+static bool use_multishare_conn = False;
+static bool do_encrypt;
+
+bool torture_showall = False;
+
+static double create_procs(bool (*fn)(int), bool *result);
+
+
+static struct timeval tp1,tp2;
+
+
+void start_timer(void)
+{
+ GetTimeOfDay(&tp1);
+}
+
+double end_timer(void)
+{
+ GetTimeOfDay(&tp2);
+ return((tp2.tv_sec - tp1.tv_sec) +
+ (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
+}
+
+
+/* return a pointer to a anonymous shared memory segment of size "size"
+ which will persist across fork() but will disappear when all processes
+ exit
+
+ The memory is not zeroed
+
+ This function uses system5 shared memory. It takes advantage of a property
+ that the memory is not destroyed if it is attached when the id is removed
+ */
+void *shm_setup(int size)
+{
+ int shmid;
+ void *ret;
+
+ shmid = shmget(IPC_PRIVATE, size, S_IRUSR | S_IWUSR);
+ if (shmid == -1) {
+ printf("can't get shared memory\n");
+ exit(1);
+ }
+ ret = (void *)shmat(shmid, 0, 0);
+ if (!ret || ret == (void *)-1) {
+ printf("can't attach to shared memory\n");
+ return NULL;
+ }
+ /* the following releases the ipc, but note that this process
+ and all its children will still have access to the memory, its
+ just that the shmid is no longer valid for other shm calls. This
+ means we don't leave behind lots of shm segments after we exit
+
+ See Stevens "advanced programming in unix env" for details
+ */
+ shmctl(shmid, IPC_RMID, 0);
+
+ return ret;
+}
+
+/********************************************************************
+ Ensure a connection is encrypted.
+********************************************************************/
+
+static bool force_cli_encryption(struct cli_state *c,
+ const char *sharename)
+{
+ uint16 major, minor;
+ uint32 caplow, caphigh;
+ NTSTATUS status;
+
+ if (!SERVER_HAS_UNIX_CIFS(c)) {
+ d_printf("Encryption required and "
+ "server that doesn't support "
+ "UNIX extensions - failing connect\n");
+ return false;
+ }
+
+ if (!cli_unix_extensions_version(c, &major, &minor, &caplow, &caphigh)) {
+ d_printf("Encryption required and "
+ "can't get UNIX CIFS extensions "
+ "version from server.\n");
+ return false;
+ }
+
+ if (!(caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)) {
+ d_printf("Encryption required and "
+ "share %s doesn't support "
+ "encryption.\n", sharename);
+ return false;
+ }
+
+ if (c->use_kerberos) {
+ status = cli_gss_smb_encryption_start(c);
+ } else {
+ status = cli_raw_ntlm_smb_encryption_start(c,
+ username,
+ password,
+ workgroup);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("Encryption required and "
+ "setup failed with error %s.\n",
+ nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+static struct cli_state *open_nbt_connection(void)
+{
+ struct nmb_name called, calling;
+ struct sockaddr_storage ss;
+ struct cli_state *c;
+ NTSTATUS status;
+
+ make_nmb_name(&calling, myname, 0x0);
+ make_nmb_name(&called , host, 0x20);
+
+ zero_addr(&ss);
+
+ if (!(c = cli_initialise())) {
+ printf("Failed initialize cli_struct to connect with %s\n", host);
+ return NULL;
+ }
+
+ c->port = port_to_use;
+
+ status = cli_connect(c, host, &ss);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to connect with %s. Error %s\n", host, nt_errstr(status) );
+ return NULL;
+ }
+
+ c->use_kerberos = use_kerberos;
+
+ c->timeout = 120000; /* set a really long timeout (2 minutes) */
+ if (use_oplocks) c->use_oplocks = True;
+ if (use_level_II_oplocks) c->use_level_II_oplocks = True;
+
+ if (!cli_session_request(c, &calling, &called)) {
+ /*
+ * Well, that failed, try *SMBSERVER ...
+ * However, we must reconnect as well ...
+ */
+ status = cli_connect(c, host, &ss);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to connect with %s. Error %s\n", host, nt_errstr(status) );
+ return NULL;
+ }
+
+ make_nmb_name(&called, "*SMBSERVER", 0x20);
+ if (!cli_session_request(c, &calling, &called)) {
+ printf("%s rejected the session\n",host);
+ printf("We tried with a called name of %s & %s\n",
+ host, "*SMBSERVER");
+ cli_shutdown(c);
+ return NULL;
+ }
+ }
+
+ return c;
+}
+
+/* Insert a NULL at the first separator of the given path and return a pointer
+ * to the remainder of the string.
+ */
+static char *
+terminate_path_at_separator(char * path)
+{
+ char * p;
+
+ if (!path) {
+ return NULL;
+ }
+
+ if ((p = strchr_m(path, '/'))) {
+ *p = '\0';
+ return p + 1;
+ }
+
+ if ((p = strchr_m(path, '\\'))) {
+ *p = '\0';
+ return p + 1;
+ }
+
+ /* No separator. */
+ return NULL;
+}
+
+/*
+ parse a //server/share type UNC name
+*/
+bool smbcli_parse_unc(const char *unc_name, TALLOC_CTX *mem_ctx,
+ char **hostname, char **sharename)
+{
+ char *p;
+
+ *hostname = *sharename = NULL;
+
+ if (strncmp(unc_name, "\\\\", 2) &&
+ strncmp(unc_name, "//", 2)) {
+ return False;
+ }
+
+ *hostname = talloc_strdup(mem_ctx, &unc_name[2]);
+ p = terminate_path_at_separator(*hostname);
+
+ if (p && *p) {
+ *sharename = talloc_strdup(mem_ctx, p);
+ terminate_path_at_separator(*sharename);
+ }
+
+ if (*hostname && *sharename) {
+ return True;
+ }
+
+ TALLOC_FREE(*hostname);
+ TALLOC_FREE(*sharename);
+ return False;
+}
+
+static bool torture_open_connection_share(struct cli_state **c,
+ const char *hostname,
+ const char *sharename)
+{
+ bool retry;
+ int flags = 0;
+ NTSTATUS status;
+
+ if (use_kerberos)
+ flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
+
+ status = cli_full_connection(c, myname,
+ hostname, NULL, port_to_use,
+ sharename, "?????",
+ username, workgroup,
+ password, flags, Undefined, &retry);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("failed to open share connection: //%s/%s port:%d - %s\n",
+ hostname, sharename, port_to_use, nt_errstr(status));
+ return False;
+ }
+
+ if (use_oplocks) (*c)->use_oplocks = True;
+ if (use_level_II_oplocks) (*c)->use_level_II_oplocks = True;
+ (*c)->timeout = 120000; /* set a really long timeout (2 minutes) */
+
+ if (do_encrypt) {
+ return force_cli_encryption(*c,
+ sharename);
+ }
+ return True;
+}
+
+void torture_open_connection_free_unclist(char **unc_list)
+{
+ if (unc_list!=NULL)
+ {
+ SAFE_FREE(unc_list[0]);
+ SAFE_FREE(unc_list);
+ }
+}
+
+bool torture_open_connection(struct cli_state **c, int conn_index)
+{
+ char **unc_list = NULL;
+ int num_unc_names = 0;
+ bool result;
+
+ if (use_multishare_conn==True) {
+ char *h, *s;
+ unc_list = file_lines_load(multishare_conn_fname, &num_unc_names, 0);
+ if (!unc_list || num_unc_names <= 0) {
+ printf("Failed to load unc names list from '%s'\n", multishare_conn_fname);
+ exit(1);
+ }
+
+ if (!smbcli_parse_unc(unc_list[conn_index % num_unc_names],
+ NULL, &h, &s)) {
+ printf("Failed to parse UNC name %s\n",
+ unc_list[conn_index % num_unc_names]);
+ torture_open_connection_free_unclist(unc_list);
+ exit(1);
+ }
+
+ result = torture_open_connection_share(c, h, s);
+
+ /* h, s were copied earlier */
+ torture_open_connection_free_unclist(unc_list);
+ return result;
+ }
+
+ return torture_open_connection_share(c, host, share);
+}
+
+bool torture_cli_session_setup2(struct cli_state *cli, uint16 *new_vuid)
+{
+ uint16 old_vuid = cli->vuid;
+ fstring old_user_name;
+ size_t passlen = strlen(password);
+ bool ret;
+
+ fstrcpy(old_user_name, cli->user_name);
+ cli->vuid = 0;
+ ret = NT_STATUS_IS_OK(cli_session_setup(cli, username,
+ password, passlen,
+ password, passlen,
+ workgroup));
+ *new_vuid = cli->vuid;
+ cli->vuid = old_vuid;
+ fstrcpy(cli->user_name, old_user_name);
+ return ret;
+}
+
+
+bool torture_close_connection(struct cli_state *c)
+{
+ bool ret = True;
+ if (!cli_tdis(c)) {
+ printf("tdis failed (%s)\n", cli_errstr(c));
+ ret = False;
+ }
+
+ cli_shutdown(c);
+
+ return ret;
+}
+
+
+/* check if the server produced the expected error code */
+static bool check_error(int line, struct cli_state *c,
+ uint8 eclass, uint32 ecode, NTSTATUS nterr)
+{
+ if (cli_is_dos_error(c)) {
+ uint8 cclass;
+ uint32 num;
+
+ /* Check DOS error */
+
+ cli_dos_error(c, &cclass, &num);
+
+ if (eclass != cclass || ecode != num) {
+ printf("unexpected error code class=%d code=%d\n",
+ (int)cclass, (int)num);
+ printf(" expected %d/%d %s (line=%d)\n",
+ (int)eclass, (int)ecode, nt_errstr(nterr), line);
+ return False;
+ }
+
+ } else {
+ NTSTATUS status;
+
+ /* Check NT error */
+
+ status = cli_nt_error(c);
+
+ if (NT_STATUS_V(nterr) != NT_STATUS_V(status)) {
+ printf("unexpected error code %s\n", nt_errstr(status));
+ printf(" expected %s (line=%d)\n", nt_errstr(nterr), line);
+ return False;
+ }
+ }
+
+ return True;
+}
+
+
+static bool wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
+{
+ while (!cli_lock(c, fnum, offset, len, -1, WRITE_LOCK)) {
+ if (!check_error(__LINE__, c, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return False;
+ }
+ return True;
+}
+
+
+static bool rw_torture(struct cli_state *c)
+{
+ const char *lockfname = "\\torture.lck";
+ fstring fname;
+ int fnum;
+ int fnum2;
+ pid_t pid2, pid = getpid();
+ int i, j;
+ char buf[1024];
+ bool correct = True;
+
+ memset(buf, '\0', sizeof(buf));
+
+ 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<torture_numops;i++) {
+ unsigned n = (unsigned)sys_random()%10;
+ if (i % 10 == 0) {
+ printf("%d\r", i); fflush(stdout);
+ }
+ slprintf(fname, sizeof(fstring) - 1, "\\torture.%u", n);
+
+ if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
+ return False;
+ }
+
+ fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
+ if (fnum == -1) {
+ printf("open failed (%s)\n", cli_errstr(c));
+ correct = False;
+ break;
+ }
+
+ if (cli_write(c, fnum, 0, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
+ printf("write failed (%s)\n", cli_errstr(c));
+ correct = False;
+ }
+
+ for (j=0;j<50;j++) {
+ if (cli_write(c, fnum, 0, (char *)buf,
+ sizeof(pid)+(j*sizeof(buf)),
+ sizeof(buf)) != sizeof(buf)) {
+ printf("write failed (%s)\n", cli_errstr(c));
+ correct = False;
+ }
+ }
+
+ pid2 = 0;
+
+ if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
+ printf("read failed (%s)\n", cli_errstr(c));
+ correct = False;
+ }
+
+ if (pid2 != pid) {
+ printf("data corruption!\n");
+ correct = False;
+ }
+
+ if (!cli_close(c, fnum)) {
+ printf("close failed (%s)\n", cli_errstr(c));
+ correct = False;
+ }
+
+ if (!cli_unlink(c, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(c));
+ correct = False;
+ }
+
+ if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int))) {
+ printf("unlock failed (%s)\n", cli_errstr(c));
+ correct = False;
+ }
+ }
+
+ cli_close(c, fnum2);
+ cli_unlink(c, lockfname);
+
+ printf("%d\n", i);
+
+ return correct;
+}
+
+static bool run_torture(int dummy)
+{
+ struct cli_state *cli;
+ bool ret;
+
+ cli = current_cli;
+
+ cli_sockopt(cli, sockops);
+
+ ret = rw_torture(cli);
+
+ if (!torture_close_connection(cli)) {
+ ret = False;
+ }
+
+ return ret;
+}
+
+static bool rw_torture3(struct cli_state *c, char *lockfname)
+{
+ int fnum = -1;
+ unsigned int i = 0;
+ char buf[131072];
+ char buf_rd[131072];
+ unsigned count;
+ unsigned countprev = 0;
+ ssize_t sent = 0;
+ bool correct = True;
+
+ srandom(1);
+ for (i = 0; i < sizeof(buf); i += sizeof(uint32))
+ {
+ SIVAL(buf, i, sys_random());
+ }
+
+ if (procnum == 0)
+ {
+ fnum = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL,
+ DENY_NONE);
+ if (fnum == -1) {
+ printf("first open read/write of %s failed (%s)\n",
+ lockfname, cli_errstr(c));
+ return False;
+ }
+ }
+ else
+ {
+ for (i = 0; i < 500 && fnum == -1; i++)
+ {
+ fnum = cli_open(c, lockfname, O_RDONLY,
+ DENY_NONE);
+ smb_msleep(10);
+ }
+ if (fnum == -1) {
+ printf("second open read-only of %s failed (%s)\n",
+ lockfname, cli_errstr(c));
+ return False;
+ }
+ }
+
+ i = 0;
+ for (count = 0; count < sizeof(buf); count += sent)
+ {
+ if (count >= countprev) {
+ printf("%d %8d\r", i, count);
+ fflush(stdout);
+ i++;
+ countprev += (sizeof(buf) / 20);
+ }
+
+ if (procnum == 0)
+ {
+ sent = ((unsigned)sys_random()%(20))+ 1;
+ if (sent > sizeof(buf) - count)
+ {
+ sent = sizeof(buf) - count;
+ }
+
+ if (cli_write(c, fnum, 0, buf+count, count, (size_t)sent) != sent) {
+ printf("write failed (%s)\n", cli_errstr(c));
+ correct = False;
+ }
+ }
+ else
+ {
+ sent = cli_read(c, fnum, buf_rd+count, count,
+ sizeof(buf)-count);
+ if (sent < 0)
+ {
+ printf("read failed offset:%d size:%ld (%s)\n",
+ count, (unsigned long)sizeof(buf)-count,
+ cli_errstr(c));
+ correct = False;
+ sent = 0;
+ }
+ if (sent > 0)
+ {
+ if (memcmp(buf_rd+count, buf+count, sent) != 0)
+ {
+ printf("read/write compare failed\n");
+ printf("offset: %d req %ld recvd %ld\n", count, (unsigned long)sizeof(buf)-count, (unsigned long)sent);
+ correct = False;
+ break;
+ }
+ }
+ }
+
+ }
+
+ if (!cli_close(c, fnum)) {
+ printf("close failed (%s)\n", cli_errstr(c));
+ correct = False;
+ }
+
+ return correct;
+}
+
+static bool rw_torture2(struct cli_state *c1, struct cli_state *c2)
+{
+ const char *lockfname = "\\torture2.lck";
+ int fnum1;
+ int fnum2;
+ int i;
+ char buf[131072];
+ char buf_rd[131072];
+ bool correct = True;
+ ssize_t bytes_read;
+
+ if (!cli_unlink(c1, lockfname)) {
+ printf("unlink failed (%s) (normal, this file should not exist)\n", cli_errstr(c1));
+ }
+
+ fnum1 = cli_open(c1, lockfname, O_RDWR | O_CREAT | O_EXCL,
+ DENY_NONE);
+ if (fnum1 == -1) {
+ printf("first open read/write of %s failed (%s)\n",
+ lockfname, cli_errstr(c1));
+ return False;
+ }
+ fnum2 = cli_open(c2, lockfname, O_RDONLY,
+ DENY_NONE);
+ if (fnum2 == -1) {
+ printf("second open read-only of %s failed (%s)\n",
+ lockfname, cli_errstr(c2));
+ cli_close(c1, fnum1);
+ return False;
+ }
+
+ for (i=0;i<torture_numops;i++)
+ {
+ size_t buf_size = ((unsigned)sys_random()%(sizeof(buf)-1))+ 1;
+ if (i % 10 == 0) {
+ printf("%d\r", i); fflush(stdout);
+ }
+
+ generate_random_buffer((unsigned char *)buf, buf_size);
+
+ if (cli_write(c1, fnum1, 0, buf, 0, buf_size) != buf_size) {
+ printf("write failed (%s)\n", cli_errstr(c1));
+ correct = False;
+ break;
+ }
+
+ if ((bytes_read = cli_read(c2, fnum2, buf_rd, 0, buf_size)) != buf_size) {
+ printf("read failed (%s)\n", cli_errstr(c2));
+ printf("read %d, expected %ld\n", (int)bytes_read,
+ (unsigned long)buf_size);
+ correct = False;
+ break;
+ }
+
+ if (memcmp(buf_rd, buf, buf_size) != 0)
+ {
+ printf("read/write compare failed\n");
+ correct = False;
+ break;
+ }
+ }
+
+ if (!cli_close(c2, fnum2)) {
+ printf("close failed (%s)\n", cli_errstr(c2));
+ correct = False;
+ }
+ if (!cli_close(c1, fnum1)) {
+ printf("close failed (%s)\n", cli_errstr(c1));
+ correct = False;
+ }
+
+ if (!cli_unlink(c1, lockfname)) {
+ printf("unlink failed (%s)\n", cli_errstr(c1));
+ correct = False;
+ }
+
+ return correct;
+}
+
+static bool run_readwritetest(int dummy)
+{
+ static struct cli_state *cli1, *cli2;
+ bool test1, test2 = False;
+
+ if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
+ return False;
+ }
+ cli_sockopt(cli1, sockops);
+ cli_sockopt(cli2, sockops);
+
+ printf("starting readwritetest\n");
+
+ test1 = rw_torture2(cli1, cli2);
+ printf("Passed readwritetest v1: %s\n", BOOLSTR(test1));
+
+ if (test1) {
+ test2 = rw_torture2(cli1, cli1);
+ printf("Passed readwritetest v2: %s\n", BOOLSTR(test2));
+ }
+
+ if (!torture_close_connection(cli1)) {
+ test1 = False;
+ }
+
+ if (!torture_close_connection(cli2)) {
+ test2 = False;
+ }
+
+ return (test1 && test2);
+}
+
+static bool run_readwritemulti(int dummy)
+{
+ struct cli_state *cli;
+ bool test;
+
+ cli = current_cli;
+
+ cli_sockopt(cli, sockops);
+
+ printf("run_readwritemulti: fname %s\n", randomfname);
+ test = rw_torture3(cli, randomfname);
+
+ if (!torture_close_connection(cli)) {
+ test = False;
+ }
+
+ return test;
+}
+
+static bool run_readwritelarge(int dummy)
+{
+ static struct cli_state *cli1;
+ int fnum1;
+ const char *lockfname = "\\large.dat";
+ SMB_OFF_T fsize;
+ char buf[126*1024];
+ bool correct = True;
+
+ if (!torture_open_connection(&cli1, 0)) {
+ return False;
+ }
+ cli_sockopt(cli1, sockops);
+ memset(buf,'\0',sizeof(buf));
+
+ cli1->max_xmit = 128*1024;
+
+ printf("starting readwritelarge\n");
+
+ cli_unlink(cli1, lockfname);
+
+ fnum1 = cli_open(cli1, lockfname, O_RDWR | O_CREAT | O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open read/write of %s failed (%s)\n", lockfname, cli_errstr(cli1));
+ return False;
+ }
+
+ cli_write(cli1, fnum1, 0, buf, 0, sizeof(buf));
+
+ if (!cli_qfileinfo(cli1, fnum1, NULL, &fsize, NULL, NULL, NULL, NULL, NULL)) {
+ printf("qfileinfo failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ }
+
+ if (fsize == sizeof(buf))
+ printf("readwritelarge test 1 succeeded (size = %lx)\n",
+ (unsigned long)fsize);
+ else {
+ printf("readwritelarge test 1 failed (size = %lx)\n",
+ (unsigned long)fsize);
+ correct = False;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("close failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ }
+
+ if (!cli_unlink(cli1, lockfname)) {
+ printf("unlink failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ }
+
+ fnum1 = cli_open(cli1, lockfname, O_RDWR | O_CREAT | O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open read/write of %s failed (%s)\n", lockfname, cli_errstr(cli1));
+ return False;
+ }
+
+ cli1->max_xmit = 4*1024;
+
+ cli_smbwrite(cli1, fnum1, buf, 0, sizeof(buf));
+
+ if (!cli_qfileinfo(cli1, fnum1, NULL, &fsize, NULL, NULL, NULL, NULL, NULL)) {
+ printf("qfileinfo failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ }
+
+ if (fsize == sizeof(buf))
+ printf("readwritelarge test 2 succeeded (size = %lx)\n",
+ (unsigned long)fsize);
+ else {
+ printf("readwritelarge test 2 failed (size = %lx)\n",
+ (unsigned long)fsize);
+ correct = False;
+ }
+
+#if 0
+ /* ToDo - set allocation. JRA */
+ if(!cli_set_allocation_size(cli1, fnum1, 0)) {
+ printf("set allocation size to zero failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+ if (!cli_qfileinfo(cli1, fnum1, NULL, &fsize, NULL, NULL, NULL, NULL, NULL)) {
+ printf("qfileinfo failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ }
+ if (fsize != 0)
+ printf("readwritelarge test 3 (truncate test) succeeded (size = %x)\n", fsize);
+#endif
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("close failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ }
+
+ if (!torture_close_connection(cli1)) {
+ correct = False;
+ }
+ return correct;
+}
+
+int line_count = 0;
+int nbio_id;
+
+#define ival(s) strtol(s, NULL, 0)
+
+/* run a test that simulates an approximate netbench client load */
+static bool run_netbench(int client)
+{
+ struct cli_state *cli;
+ int i;
+ char line[1024];
+ char cname[20];
+ FILE *f;
+ const char *params[20];
+ bool correct = True;
+
+ cli = current_cli;
+
+ nbio_id = client;
+
+ cli_sockopt(cli, sockops);
+
+ nb_setup(cli);
+
+ slprintf(cname,sizeof(cname)-1, "client%d", client);
+
+ f = fopen(client_txt, "r");
+
+ if (!f) {
+ perror(client_txt);
+ return False;
+ }
+
+ while (fgets(line, sizeof(line)-1, f)) {
+ char *saveptr;
+ line_count++;
+
+ line[strlen(line)-1] = 0;
+
+ /* printf("[%d] %s\n", line_count, line); */
+
+ all_string_sub(line,"client1", cname, sizeof(line));
+
+ /* parse the command parameters */
+ params[0] = strtok_r(line, " ", &saveptr);
+ i = 0;
+ while (params[i]) params[++i] = strtok_r(NULL, " ", &saveptr);
+
+ params[i] = "";
+
+ if (i < 2) continue;
+
+ if (!strncmp(params[0],"SMB", 3)) {
+ printf("ERROR: You are using a dbench 1 load file\n");
+ exit(1);
+ }
+
+ if (!strcmp(params[0],"NTCreateX")) {
+ nb_createx(params[1], ival(params[2]), ival(params[3]),
+ ival(params[4]));
+ } else if (!strcmp(params[0],"Close")) {
+ nb_close(ival(params[1]));
+ } else if (!strcmp(params[0],"Rename")) {
+ nb_rename(params[1], params[2]);
+ } else if (!strcmp(params[0],"Unlink")) {
+ nb_unlink(params[1]);
+ } else if (!strcmp(params[0],"Deltree")) {
+ nb_deltree(params[1]);
+ } else if (!strcmp(params[0],"Rmdir")) {
+ nb_rmdir(params[1]);
+ } else if (!strcmp(params[0],"QUERY_PATH_INFORMATION")) {
+ nb_qpathinfo(params[1]);
+ } else if (!strcmp(params[0],"QUERY_FILE_INFORMATION")) {
+ nb_qfileinfo(ival(params[1]));
+ } else if (!strcmp(params[0],"QUERY_FS_INFORMATION")) {
+ nb_qfsinfo(ival(params[1]));
+ } else if (!strcmp(params[0],"FIND_FIRST")) {
+ nb_findfirst(params[1]);
+ } else if (!strcmp(params[0],"WriteX")) {
+ nb_writex(ival(params[1]),
+ ival(params[2]), ival(params[3]), ival(params[4]));
+ } else if (!strcmp(params[0],"ReadX")) {
+ nb_readx(ival(params[1]),
+ ival(params[2]), ival(params[3]), ival(params[4]));
+ } else if (!strcmp(params[0],"Flush")) {
+ nb_flush(ival(params[1]));
+ } else {
+ printf("Unknown operation %s\n", params[0]);
+ exit(1);
+ }
+ }
+ fclose(f);
+
+ nb_cleanup();
+
+ if (!torture_close_connection(cli)) {
+ correct = False;
+ }
+
+ return correct;
+}
+
+
+/* run a test that simulates an approximate netbench client load */
+static bool run_nbench(int dummy)
+{
+ double t;
+ bool correct = True;
+
+ nbio_shmem(nprocs);
+
+ nbio_id = -1;
+
+ signal(SIGALRM, nb_alarm);
+ alarm(1);
+ t = create_procs(run_netbench, &correct);
+ alarm(0);
+
+ printf("\nThroughput %g MB/sec\n",
+ 1.0e-6 * nbio_total() / t);
+ return correct;
+}
+
+
+/*
+ This test checks for two things:
+
+ 1) correct support for retaining locks over a close (ie. the server
+ must not use posix semantics)
+ 2) support for lock timeouts
+ */
+static bool run_locktest1(int dummy)
+{
+ struct cli_state *cli1, *cli2;
+ const char *fname = "\\lockt1.lck";
+ int fnum1, fnum2, fnum3;
+ time_t t1, t2;
+ unsigned lock_timeout;
+
+ if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
+ return False;
+ }
+ cli_sockopt(cli1, sockops);
+ cli_sockopt(cli2, sockops);
+
+ printf("starting locktest1\n");
+
+ cli_unlink(cli1, fname);
+
+ fnum1 = cli_open(cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+ fnum2 = cli_open(cli1, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open2 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+ fnum3 = cli_open(cli2, fname, O_RDWR, DENY_NONE);
+ if (fnum3 == -1) {
+ printf("open3 of %s failed (%s)\n", fname, cli_errstr(cli2));
+ return False;
+ }
+
+ if (!cli_lock(cli1, fnum1, 0, 4, 0, WRITE_LOCK)) {
+ printf("lock1 failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+
+ if (cli_lock(cli2, fnum3, 0, 4, 0, WRITE_LOCK)) {
+ printf("lock2 succeeded! This is a locking bug\n");
+ return False;
+ } else {
+ if (!check_error(__LINE__, cli2, ERRDOS, ERRlock,
+ NT_STATUS_LOCK_NOT_GRANTED)) return False;
+ }
+
+
+ lock_timeout = (1 + (random() % 20));
+ printf("Testing lock timeout with timeout=%u\n", lock_timeout);
+ t1 = time(NULL);
+ if (cli_lock(cli2, fnum3, 0, 4, lock_timeout * 1000, WRITE_LOCK)) {
+ printf("lock3 succeeded! This is a locking bug\n");
+ return False;
+ } else {
+ if (!check_error(__LINE__, cli2, ERRDOS, ERRlock,
+ NT_STATUS_FILE_LOCK_CONFLICT)) return False;
+ }
+ t2 = time(NULL);
+
+ if (ABS(t2 - t1) < lock_timeout-1) {
+ printf("error: This server appears not to support timed lock requests\n");
+ }
+
+ printf("server slept for %u seconds for a %u second timeout\n",
+ (unsigned int)(t2-t1), lock_timeout);
+
+ if (!cli_close(cli1, fnum2)) {
+ printf("close1 failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ if (cli_lock(cli2, fnum3, 0, 4, 0, WRITE_LOCK)) {
+ printf("lock4 succeeded! This is a locking bug\n");
+ return False;
+ } else {
+ if (!check_error(__LINE__, cli2, ERRDOS, ERRlock,
+ NT_STATUS_FILE_LOCK_CONFLICT)) return False;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("close2 failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ if (!cli_close(cli2, fnum3)) {
+ printf("close3 failed (%s)\n", cli_errstr(cli2));
+ return False;
+ }
+
+ if (!cli_unlink(cli1, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+
+ if (!torture_close_connection(cli1)) {
+ return False;
+ }
+
+ if (!torture_close_connection(cli2)) {
+ return False;
+ }
+
+ printf("Passed locktest1\n");
+ return True;
+}
+
+/*
+ this checks to see if a secondary tconx can use open files from an
+ earlier tconx
+ */
+static bool run_tcon_test(int dummy)
+{
+ static struct cli_state *cli;
+ const char *fname = "\\tcontest.tmp";
+ int fnum1;
+ uint16 cnum1, cnum2, cnum3;
+ uint16 vuid1, vuid2;
+ char buf[4];
+ bool ret = True;
+
+ memset(buf, '\0', sizeof(buf));
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+ cli_sockopt(cli, sockops);
+
+ printf("starting tcontest\n");
+
+ cli_unlink(cli, fname);
+
+ fnum1 = cli_open(cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(cli));
+ return False;
+ }
+
+ cnum1 = cli->cnum;
+ vuid1 = cli->vuid;
+
+ if (cli_write(cli, fnum1, 0, buf, 130, 4) != 4) {
+ printf("initial write failed (%s)", cli_errstr(cli));
+ return False;
+ }
+
+ if (!cli_send_tconX(cli, share, "?????",
+ password, strlen(password)+1)) {
+ printf("%s refused 2nd tree connect (%s)\n", host,
+ cli_errstr(cli));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ cnum2 = cli->cnum;
+ cnum3 = MAX(cnum1, cnum2) + 1; /* any invalid number */
+ vuid2 = cli->vuid + 1;
+
+ /* try a write with the wrong tid */
+ cli->cnum = cnum2;
+
+ if (cli_write(cli, fnum1, 0, buf, 130, 4) == 4) {
+ printf("* server allows write with wrong TID\n");
+ ret = False;
+ } else {
+ printf("server fails write with wrong TID : %s\n", cli_errstr(cli));
+ }
+
+
+ /* try a write with an invalid tid */
+ cli->cnum = cnum3;
+
+ if (cli_write(cli, fnum1, 0, buf, 130, 4) == 4) {
+ printf("* server allows write with invalid TID\n");
+ ret = False;
+ } else {
+ printf("server fails write with invalid TID : %s\n", cli_errstr(cli));
+ }
+
+ /* try a write with an invalid vuid */
+ cli->vuid = vuid2;
+ cli->cnum = cnum1;
+
+ if (cli_write(cli, fnum1, 0, buf, 130, 4) == 4) {
+ printf("* server allows write with invalid VUID\n");
+ ret = False;
+ } else {
+ printf("server fails write with invalid VUID : %s\n", cli_errstr(cli));
+ }
+
+ cli->cnum = cnum1;
+ cli->vuid = vuid1;
+
+ if (!cli_close(cli, fnum1)) {
+ printf("close failed (%s)\n", cli_errstr(cli));
+ return False;
+ }
+
+ cli->cnum = cnum2;
+
+ if (!cli_tdis(cli)) {
+ printf("secondary tdis failed (%s)\n", cli_errstr(cli));
+ return False;
+ }
+
+ cli->cnum = cnum1;
+
+ if (!torture_close_connection(cli)) {
+ return False;
+ }
+
+ return ret;
+}
+
+
+/*
+ checks for old style tcon support
+ */
+static bool run_tcon2_test(int dummy)
+{
+ static struct cli_state *cli;
+ uint16 cnum, max_xmit;
+ char *service;
+ NTSTATUS status;
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+ cli_sockopt(cli, sockops);
+
+ printf("starting tcon2 test\n");
+
+ asprintf(&service, "\\\\%s\\%s", host, share);
+
+ status = cli_raw_tcon(cli, service, password, "?????", &max_xmit, &cnum);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("tcon2 failed : %s\n", cli_errstr(cli));
+ } else {
+ printf("tcon OK : max_xmit=%d cnum=%d tid=%d\n",
+ (int)max_xmit, (int)cnum, SVAL(cli->inbuf, smb_tid));
+ }
+
+ if (!torture_close_connection(cli)) {
+ return False;
+ }
+
+ printf("Passed tcon2 test\n");
+ return True;
+}
+
+static bool tcon_devtest(struct cli_state *cli,
+ const char *myshare, const char *devtype,
+ const char *return_devtype,
+ NTSTATUS expected_error)
+{
+ bool status;
+ bool ret;
+
+ status = cli_send_tconX(cli, myshare, devtype,
+ password, strlen(password)+1);
+
+ if (NT_STATUS_IS_OK(expected_error)) {
+ if (status) {
+ if (strcmp(cli->dev, return_devtype) == 0) {
+ ret = True;
+ } else {
+ printf("tconX to share %s with type %s "
+ "succeeded but returned the wrong "
+ "device type (got [%s] but should have got [%s])\n",
+ myshare, devtype, cli->dev, return_devtype);
+ ret = False;
+ }
+ } else {
+ printf("tconX to share %s with type %s "
+ "should have succeeded but failed\n",
+ myshare, devtype);
+ ret = False;
+ }
+ cli_tdis(cli);
+ } else {
+ if (status) {
+ printf("tconx to share %s with type %s "
+ "should have failed but succeeded\n",
+ myshare, devtype);
+ ret = False;
+ } else {
+ if (NT_STATUS_EQUAL(cli_nt_error(cli),
+ expected_error)) {
+ ret = True;
+ } else {
+ printf("Returned unexpected error\n");
+ ret = False;
+ }
+ }
+ }
+ return ret;
+}
+
+/*
+ checks for correct tconX support
+ */
+static bool run_tcon_devtype_test(int dummy)
+{
+ static struct cli_state *cli1 = NULL;
+ bool retry;
+ int flags = 0;
+ NTSTATUS status;
+ bool ret = True;
+
+ status = cli_full_connection(&cli1, myname,
+ host, NULL, port_to_use,
+ NULL, NULL,
+ username, workgroup,
+ password, flags, Undefined, &retry);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("could not open connection\n");
+ return False;
+ }
+
+ if (!tcon_devtest(cli1, "IPC$", "A:", NULL, NT_STATUS_BAD_DEVICE_TYPE))
+ ret = False;
+
+ if (!tcon_devtest(cli1, "IPC$", "?????", "IPC", NT_STATUS_OK))
+ ret = False;
+
+ if (!tcon_devtest(cli1, "IPC$", "LPT:", NULL, NT_STATUS_BAD_DEVICE_TYPE))
+ ret = False;
+
+ if (!tcon_devtest(cli1, "IPC$", "IPC", "IPC", NT_STATUS_OK))
+ ret = False;
+
+ if (!tcon_devtest(cli1, "IPC$", "FOOBA", NULL, NT_STATUS_BAD_DEVICE_TYPE))
+ ret = False;
+
+ if (!tcon_devtest(cli1, share, "A:", "A:", NT_STATUS_OK))
+ ret = False;
+
+ if (!tcon_devtest(cli1, share, "?????", "A:", NT_STATUS_OK))
+ ret = False;
+
+ if (!tcon_devtest(cli1, share, "LPT:", NULL, NT_STATUS_BAD_DEVICE_TYPE))
+ ret = False;
+
+ if (!tcon_devtest(cli1, share, "IPC", NULL, NT_STATUS_BAD_DEVICE_TYPE))
+ ret = False;
+
+ if (!tcon_devtest(cli1, share, "FOOBA", NULL, NT_STATUS_BAD_DEVICE_TYPE))
+ ret = False;
+
+ cli_shutdown(cli1);
+
+ if (ret)
+ printf("Passed tcondevtest\n");
+
+ return ret;
+}
+
+
+/*
+ This test checks that
+
+ 1) the server supports multiple locking contexts on the one SMB
+ connection, distinguished by PID.
+
+ 2) the server correctly fails overlapping locks made by the same PID (this
+ goes against POSIX behaviour, which is why it is tricky to implement)
+
+ 3) the server denies unlock requests by an incorrect client PID
+*/
+static bool run_locktest2(int dummy)
+{
+ static struct cli_state *cli;
+ const char *fname = "\\lockt2.lck";
+ int fnum1, fnum2, fnum3;
+ bool correct = True;
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ cli_sockopt(cli, sockops);
+
+ printf("starting locktest2\n");
+
+ cli_unlink(cli, fname);
+
+ cli_setpid(cli, 1);
+
+ fnum1 = cli_open(cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(cli));
+ return False;
+ }
+
+ fnum2 = cli_open(cli, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open2 of %s failed (%s)\n", fname, cli_errstr(cli));
+ return False;
+ }
+
+ cli_setpid(cli, 2);
+
+ fnum3 = cli_open(cli, fname, O_RDWR, DENY_NONE);
+ if (fnum3 == -1) {
+ printf("open3 of %s failed (%s)\n", fname, cli_errstr(cli));
+ return False;
+ }
+
+ cli_setpid(cli, 1);
+
+ if (!cli_lock(cli, fnum1, 0, 4, 0, WRITE_LOCK)) {
+ printf("lock1 failed (%s)\n", cli_errstr(cli));
+ return False;
+ }
+
+ if (cli_lock(cli, fnum1, 0, 4, 0, WRITE_LOCK)) {
+ printf("WRITE lock1 succeeded! This is a locking bug\n");
+ correct = False;
+ } else {
+ if (!check_error(__LINE__, cli, ERRDOS, ERRlock,
+ NT_STATUS_LOCK_NOT_GRANTED)) return False;
+ }
+
+ if (cli_lock(cli, fnum2, 0, 4, 0, WRITE_LOCK)) {
+ printf("WRITE lock2 succeeded! This is a locking bug\n");
+ correct = False;
+ } else {
+ if (!check_error(__LINE__, cli, ERRDOS, ERRlock,
+ NT_STATUS_LOCK_NOT_GRANTED)) return False;
+ }
+
+ if (cli_lock(cli, fnum2, 0, 4, 0, READ_LOCK)) {
+ printf("READ lock2 succeeded! This is a locking bug\n");
+ correct = False;
+ } else {
+ if (!check_error(__LINE__, cli, ERRDOS, ERRlock,
+ NT_STATUS_FILE_LOCK_CONFLICT)) return False;
+ }
+
+ if (!cli_lock(cli, fnum1, 100, 4, 0, WRITE_LOCK)) {
+ printf("lock at 100 failed (%s)\n", cli_errstr(cli));
+ }
+ cli_setpid(cli, 2);
+ if (cli_unlock(cli, fnum1, 100, 4)) {
+ printf("unlock at 100 succeeded! This is a locking bug\n");
+ correct = False;
+ }
+
+ if (cli_unlock(cli, fnum1, 0, 4)) {
+ printf("unlock1 succeeded! This is a locking bug\n");
+ correct = False;
+ } else {
+ if (!check_error(__LINE__, cli,
+ ERRDOS, ERRlock,
+ NT_STATUS_RANGE_NOT_LOCKED)) return False;
+ }
+
+ if (cli_unlock(cli, fnum1, 0, 8)) {
+ printf("unlock2 succeeded! This is a locking bug\n");
+ correct = False;
+ } else {
+ if (!check_error(__LINE__, cli,
+ ERRDOS, ERRlock,
+ NT_STATUS_RANGE_NOT_LOCKED)) return False;
+ }
+
+ if (cli_lock(cli, fnum3, 0, 4, 0, WRITE_LOCK)) {
+ printf("lock3 succeeded! This is a locking bug\n");
+ correct = False;
+ } else {
+ if (!check_error(__LINE__, cli, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return False;
+ }
+
+ cli_setpid(cli, 1);
+
+ if (!cli_close(cli, fnum1)) {
+ printf("close1 failed (%s)\n", cli_errstr(cli));
+ return False;
+ }
+
+ if (!cli_close(cli, fnum2)) {
+ printf("close2 failed (%s)\n", cli_errstr(cli));
+ return False;
+ }
+
+ if (!cli_close(cli, fnum3)) {
+ printf("close3 failed (%s)\n", cli_errstr(cli));
+ return False;
+ }
+
+ if (!torture_close_connection(cli)) {
+ correct = False;
+ }
+
+ printf("locktest2 finished\n");
+
+ return correct;
+}
+
+
+/*
+ This test checks that
+
+ 1) the server supports the full offset range in lock requests
+*/
+static bool run_locktest3(int dummy)
+{
+ static struct cli_state *cli1, *cli2;
+ const char *fname = "\\lockt3.lck";
+ int fnum1, fnum2, i;
+ uint32 offset;
+ bool correct = True;
+
+#define NEXT_OFFSET offset += (~(uint32)0) / torture_numops
+
+ if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
+ return False;
+ }
+ cli_sockopt(cli1, sockops);
+ cli_sockopt(cli2, sockops);
+
+ printf("starting locktest3\n");
+
+ cli_unlink(cli1, fname);
+
+ fnum1 = cli_open(cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+ fnum2 = cli_open(cli2, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open2 of %s failed (%s)\n", fname, cli_errstr(cli2));
+ return False;
+ }
+
+ for (offset=i=0;i<torture_numops;i++) {
+ NEXT_OFFSET;
+ if (!cli_lock(cli1, fnum1, offset-1, 1, 0, WRITE_LOCK)) {
+ printf("lock1 %d failed (%s)\n",
+ i,
+ cli_errstr(cli1));
+ return False;
+ }
+
+ if (!cli_lock(cli2, fnum2, offset-2, 1, 0, WRITE_LOCK)) {
+ printf("lock2 %d failed (%s)\n",
+ i,
+ cli_errstr(cli1));
+ return False;
+ }
+ }
+
+ for (offset=i=0;i<torture_numops;i++) {
+ NEXT_OFFSET;
+
+ if (cli_lock(cli1, fnum1, offset-2, 1, 0, WRITE_LOCK)) {
+ printf("error: lock1 %d succeeded!\n", i);
+ return False;
+ }
+
+ if (cli_lock(cli2, fnum2, offset-1, 1, 0, WRITE_LOCK)) {
+ printf("error: lock2 %d succeeded!\n", i);
+ return False;
+ }
+
+ if (cli_lock(cli1, fnum1, offset-1, 1, 0, WRITE_LOCK)) {
+ printf("error: lock3 %d succeeded!\n", i);
+ return False;
+ }
+
+ if (cli_lock(cli2, fnum2, offset-2, 1, 0, WRITE_LOCK)) {
+ printf("error: lock4 %d succeeded!\n", i);
+ return False;
+ }
+ }
+
+ for (offset=i=0;i<torture_numops;i++) {
+ NEXT_OFFSET;
+
+ if (!cli_unlock(cli1, fnum1, offset-1, 1)) {
+ printf("unlock1 %d failed (%s)\n",
+ i,
+ cli_errstr(cli1));
+ return False;
+ }
+
+ if (!cli_unlock(cli2, fnum2, offset-2, 1)) {
+ printf("unlock2 %d failed (%s)\n",
+ i,
+ cli_errstr(cli1));
+ return False;
+ }
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("close1 failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ if (!cli_close(cli2, fnum2)) {
+ printf("close2 failed (%s)\n", cli_errstr(cli2));
+ return False;
+ }
+
+ if (!cli_unlink(cli1, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ if (!torture_close_connection(cli1)) {
+ correct = False;
+ }
+
+ if (!torture_close_connection(cli2)) {
+ correct = False;
+ }
+
+ printf("finished locktest3\n");
+
+ return correct;
+}
+
+#define EXPECTED(ret, v) if ((ret) != (v)) { \
+ printf("** "); correct = False; \
+ }
+
+/*
+ looks at overlapping locks
+*/
+static bool run_locktest4(int dummy)
+{
+ static struct cli_state *cli1, *cli2;
+ const char *fname = "\\lockt4.lck";
+ int fnum1, fnum2, f;
+ bool ret;
+ char buf[1000];
+ bool correct = True;
+
+ if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
+ return False;
+ }
+
+ cli_sockopt(cli1, sockops);
+ cli_sockopt(cli2, sockops);
+
+ printf("starting locktest4\n");
+
+ cli_unlink(cli1, fname);
+
+ fnum1 = cli_open(cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ fnum2 = cli_open(cli2, fname, O_RDWR, DENY_NONE);
+
+ memset(buf, 0, sizeof(buf));
+
+ if (cli_write(cli1, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
+ printf("Failed to create file\n");
+ correct = False;
+ goto fail;
+ }
+
+ ret = cli_lock(cli1, fnum1, 0, 4, 0, WRITE_LOCK) &&
+ cli_lock(cli1, fnum1, 2, 4, 0, WRITE_LOCK);
+ EXPECTED(ret, False);
+ printf("the same process %s set overlapping write locks\n", ret?"can":"cannot");
+
+ ret = cli_lock(cli1, fnum1, 10, 4, 0, READ_LOCK) &&
+ cli_lock(cli1, fnum1, 12, 4, 0, READ_LOCK);
+ EXPECTED(ret, True);
+ printf("the same process %s set overlapping read locks\n", ret?"can":"cannot");
+
+ ret = cli_lock(cli1, fnum1, 20, 4, 0, WRITE_LOCK) &&
+ cli_lock(cli2, fnum2, 22, 4, 0, WRITE_LOCK);
+ EXPECTED(ret, False);
+ printf("a different connection %s set overlapping write locks\n", ret?"can":"cannot");
+
+ ret = cli_lock(cli1, fnum1, 30, 4, 0, READ_LOCK) &&
+ cli_lock(cli2, fnum2, 32, 4, 0, READ_LOCK);
+ EXPECTED(ret, True);
+ printf("a different connection %s set overlapping read locks\n", ret?"can":"cannot");
+
+ ret = (cli_setpid(cli1, 1), cli_lock(cli1, fnum1, 40, 4, 0, WRITE_LOCK)) &&
+ (cli_setpid(cli1, 2), cli_lock(cli1, fnum1, 42, 4, 0, WRITE_LOCK));
+ EXPECTED(ret, False);
+ printf("a different pid %s set overlapping write locks\n", ret?"can":"cannot");
+
+ ret = (cli_setpid(cli1, 1), cli_lock(cli1, fnum1, 50, 4, 0, READ_LOCK)) &&
+ (cli_setpid(cli1, 2), cli_lock(cli1, fnum1, 52, 4, 0, READ_LOCK));
+ EXPECTED(ret, True);
+ printf("a different pid %s set overlapping read locks\n", ret?"can":"cannot");
+
+ ret = cli_lock(cli1, fnum1, 60, 4, 0, READ_LOCK) &&
+ cli_lock(cli1, fnum1, 60, 4, 0, READ_LOCK);
+ EXPECTED(ret, True);
+ printf("the same process %s set the same read lock twice\n", ret?"can":"cannot");
+
+ ret = cli_lock(cli1, fnum1, 70, 4, 0, WRITE_LOCK) &&
+ cli_lock(cli1, fnum1, 70, 4, 0, WRITE_LOCK);
+ EXPECTED(ret, False);
+ printf("the same process %s set the same write lock twice\n", ret?"can":"cannot");
+
+ ret = cli_lock(cli1, fnum1, 80, 4, 0, READ_LOCK) &&
+ cli_lock(cli1, fnum1, 80, 4, 0, WRITE_LOCK);
+ EXPECTED(ret, False);
+ printf("the same process %s overlay a read lock with a write lock\n", ret?"can":"cannot");
+
+ ret = cli_lock(cli1, fnum1, 90, 4, 0, WRITE_LOCK) &&
+ cli_lock(cli1, fnum1, 90, 4, 0, READ_LOCK);
+ EXPECTED(ret, True);
+ printf("the same process %s overlay a write lock with a read lock\n", ret?"can":"cannot");
+
+ ret = (cli_setpid(cli1, 1), cli_lock(cli1, fnum1, 100, 4, 0, WRITE_LOCK)) &&
+ (cli_setpid(cli1, 2), cli_lock(cli1, fnum1, 100, 4, 0, READ_LOCK));
+ EXPECTED(ret, False);
+ printf("a different pid %s overlay a write lock with a read lock\n", ret?"can":"cannot");
+
+ ret = cli_lock(cli1, fnum1, 110, 4, 0, READ_LOCK) &&
+ cli_lock(cli1, fnum1, 112, 4, 0, READ_LOCK) &&
+ cli_unlock(cli1, fnum1, 110, 6);
+ EXPECTED(ret, False);
+ printf("the same process %s coalesce read locks\n", ret?"can":"cannot");
+
+
+ ret = cli_lock(cli1, fnum1, 120, 4, 0, WRITE_LOCK) &&
+ (cli_read(cli2, fnum2, buf, 120, 4) == 4);
+ EXPECTED(ret, False);
+ printf("this server %s strict write locking\n", ret?"doesn't do":"does");
+
+ ret = cli_lock(cli1, fnum1, 130, 4, 0, READ_LOCK) &&
+ (cli_write(cli2, fnum2, 0, buf, 130, 4) == 4);
+ EXPECTED(ret, False);
+ printf("this server %s strict read locking\n", ret?"doesn't do":"does");
+
+
+ ret = cli_lock(cli1, fnum1, 140, 4, 0, READ_LOCK) &&
+ cli_lock(cli1, fnum1, 140, 4, 0, READ_LOCK) &&
+ cli_unlock(cli1, fnum1, 140, 4) &&
+ cli_unlock(cli1, fnum1, 140, 4);
+ EXPECTED(ret, True);
+ printf("this server %s do recursive read locking\n", ret?"does":"doesn't");
+
+
+ ret = cli_lock(cli1, fnum1, 150, 4, 0, WRITE_LOCK) &&
+ cli_lock(cli1, fnum1, 150, 4, 0, READ_LOCK) &&
+ cli_unlock(cli1, fnum1, 150, 4) &&
+ (cli_read(cli2, fnum2, buf, 150, 4) == 4) &&
+ !(cli_write(cli2, fnum2, 0, buf, 150, 4) == 4) &&
+ cli_unlock(cli1, fnum1, 150, 4);
+ EXPECTED(ret, True);
+ printf("this server %s do recursive lock overlays\n", ret?"does":"doesn't");
+
+ ret = cli_lock(cli1, fnum1, 160, 4, 0, READ_LOCK) &&
+ cli_unlock(cli1, fnum1, 160, 4) &&
+ (cli_write(cli2, fnum2, 0, buf, 160, 4) == 4) &&
+ (cli_read(cli2, fnum2, buf, 160, 4) == 4);
+ EXPECTED(ret, True);
+ printf("the same process %s remove a read lock using write locking\n", ret?"can":"cannot");
+
+ ret = cli_lock(cli1, fnum1, 170, 4, 0, WRITE_LOCK) &&
+ cli_unlock(cli1, fnum1, 170, 4) &&
+ (cli_write(cli2, fnum2, 0, buf, 170, 4) == 4) &&
+ (cli_read(cli2, fnum2, buf, 170, 4) == 4);
+ EXPECTED(ret, True);
+ printf("the same process %s remove a write lock using read locking\n", ret?"can":"cannot");
+
+ ret = cli_lock(cli1, fnum1, 190, 4, 0, WRITE_LOCK) &&
+ cli_lock(cli1, fnum1, 190, 4, 0, READ_LOCK) &&
+ cli_unlock(cli1, fnum1, 190, 4) &&
+ !(cli_write(cli2, fnum2, 0, buf, 190, 4) == 4) &&
+ (cli_read(cli2, fnum2, buf, 190, 4) == 4);
+ EXPECTED(ret, True);
+ printf("the same process %s remove the first lock first\n", ret?"does":"doesn't");
+
+ cli_close(cli1, fnum1);
+ cli_close(cli2, fnum2);
+ fnum1 = cli_open(cli1, fname, O_RDWR, DENY_NONE);
+ f = cli_open(cli1, fname, O_RDWR, DENY_NONE);
+ ret = cli_lock(cli1, fnum1, 0, 8, 0, READ_LOCK) &&
+ cli_lock(cli1, f, 0, 1, 0, READ_LOCK) &&
+ cli_close(cli1, fnum1) &&
+ ((fnum1 = cli_open(cli1, fname, O_RDWR, DENY_NONE)) != -1) &&
+ cli_lock(cli1, fnum1, 7, 1, 0, WRITE_LOCK);
+ cli_close(cli1, f);
+ cli_close(cli1, fnum1);
+ EXPECTED(ret, True);
+ printf("the server %s have the NT byte range lock bug\n", !ret?"does":"doesn't");
+
+ fail:
+ cli_close(cli1, fnum1);
+ cli_close(cli2, fnum2);
+ cli_unlink(cli1, fname);
+ torture_close_connection(cli1);
+ torture_close_connection(cli2);
+
+ printf("finished locktest4\n");
+ return correct;
+}
+
+/*
+ looks at lock upgrade/downgrade.
+*/
+static bool run_locktest5(int dummy)
+{
+ static struct cli_state *cli1, *cli2;
+ const char *fname = "\\lockt5.lck";
+ int fnum1, fnum2, fnum3;
+ bool ret;
+ char buf[1000];
+ bool correct = True;
+
+ if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
+ return False;
+ }
+
+ cli_sockopt(cli1, sockops);
+ cli_sockopt(cli2, sockops);
+
+ printf("starting locktest5\n");
+
+ cli_unlink(cli1, fname);
+
+ fnum1 = cli_open(cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ fnum2 = cli_open(cli2, fname, O_RDWR, DENY_NONE);
+ fnum3 = cli_open(cli1, fname, O_RDWR, DENY_NONE);
+
+ memset(buf, 0, sizeof(buf));
+
+ if (cli_write(cli1, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
+ printf("Failed to create file\n");
+ correct = False;
+ goto fail;
+ }
+
+ /* Check for NT bug... */
+ ret = cli_lock(cli1, fnum1, 0, 8, 0, READ_LOCK) &&
+ cli_lock(cli1, fnum3, 0, 1, 0, READ_LOCK);
+ cli_close(cli1, fnum1);
+ fnum1 = cli_open(cli1, fname, O_RDWR, DENY_NONE);
+ ret = cli_lock(cli1, fnum1, 7, 1, 0, WRITE_LOCK);
+ EXPECTED(ret, True);
+ printf("this server %s the NT locking bug\n", ret ? "doesn't have" : "has");
+ cli_close(cli1, fnum1);
+ fnum1 = cli_open(cli1, fname, O_RDWR, DENY_NONE);
+ cli_unlock(cli1, fnum3, 0, 1);
+
+ ret = cli_lock(cli1, fnum1, 0, 4, 0, WRITE_LOCK) &&
+ cli_lock(cli1, fnum1, 1, 1, 0, READ_LOCK);
+ EXPECTED(ret, True);
+ printf("the same process %s overlay a write with a read lock\n", ret?"can":"cannot");
+
+ ret = cli_lock(cli2, fnum2, 0, 4, 0, READ_LOCK);
+ EXPECTED(ret, False);
+
+ printf("a different processs %s get a read lock on the first process lock stack\n", ret?"can":"cannot");
+
+ /* Unlock the process 2 lock. */
+ cli_unlock(cli2, fnum2, 0, 4);
+
+ ret = cli_lock(cli1, fnum3, 0, 4, 0, READ_LOCK);
+ EXPECTED(ret, False);
+
+ printf("the same processs on a different fnum %s get a read lock\n", ret?"can":"cannot");
+
+ /* Unlock the process 1 fnum3 lock. */
+ cli_unlock(cli1, fnum3, 0, 4);
+
+ /* Stack 2 more locks here. */
+ ret = cli_lock(cli1, fnum1, 0, 4, 0, READ_LOCK) &&
+ cli_lock(cli1, fnum1, 0, 4, 0, READ_LOCK);
+
+ EXPECTED(ret, True);
+ printf("the same process %s stack read locks\n", ret?"can":"cannot");
+
+ /* Unlock the first process lock, then check this was the WRITE lock that was
+ removed. */
+
+ ret = cli_unlock(cli1, fnum1, 0, 4) &&
+ cli_lock(cli2, fnum2, 0, 4, 0, READ_LOCK);
+
+ EXPECTED(ret, True);
+ printf("the first unlock removes the %s lock\n", ret?"WRITE":"READ");
+
+ /* Unlock the process 2 lock. */
+ cli_unlock(cli2, fnum2, 0, 4);
+
+ /* We should have 3 stacked locks here. Ensure we need to do 3 unlocks. */
+
+ ret = cli_unlock(cli1, fnum1, 1, 1) &&
+ cli_unlock(cli1, fnum1, 0, 4) &&
+ cli_unlock(cli1, fnum1, 0, 4);
+
+ EXPECTED(ret, True);
+ printf("the same process %s unlock the stack of 4 locks\n", ret?"can":"cannot");
+
+ /* Ensure the next unlock fails. */
+ ret = cli_unlock(cli1, fnum1, 0, 4);
+ EXPECTED(ret, False);
+ printf("the same process %s count the lock stack\n", !ret?"can":"cannot");
+
+ /* Ensure connection 2 can get a write lock. */
+ ret = cli_lock(cli2, fnum2, 0, 4, 0, WRITE_LOCK);
+ EXPECTED(ret, True);
+
+ printf("a different processs %s get a write lock on the unlocked stack\n", ret?"can":"cannot");
+
+
+ fail:
+ cli_close(cli1, fnum1);
+ cli_close(cli2, fnum2);
+ cli_unlink(cli1, fname);
+ if (!torture_close_connection(cli1)) {
+ correct = False;
+ }
+ if (!torture_close_connection(cli2)) {
+ correct = False;
+ }
+
+ printf("finished locktest5\n");
+
+ return correct;
+}
+
+/*
+ tries the unusual lockingX locktype bits
+*/
+static bool run_locktest6(int dummy)
+{
+ static struct cli_state *cli;
+ const char *fname[1] = { "\\lock6.txt" };
+ int i;
+ int fnum;
+ NTSTATUS status;
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ cli_sockopt(cli, sockops);
+
+ printf("starting locktest6\n");
+
+ for (i=0;i<1;i++) {
+ printf("Testing %s\n", fname[i]);
+
+ cli_unlink(cli, fname[i]);
+
+ fnum = cli_open(cli, fname[i], O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ status = cli_locktype(cli, fnum, 0, 8, 0, LOCKING_ANDX_CHANGE_LOCKTYPE);
+ cli_close(cli, fnum);
+ printf("CHANGE_LOCKTYPE gave %s\n", nt_errstr(status));
+
+ fnum = cli_open(cli, fname[i], O_RDWR, DENY_NONE);
+ status = cli_locktype(cli, fnum, 0, 8, 0, LOCKING_ANDX_CANCEL_LOCK);
+ cli_close(cli, fnum);
+ printf("CANCEL_LOCK gave %s\n", nt_errstr(status));
+
+ cli_unlink(cli, fname[i]);
+ }
+
+ torture_close_connection(cli);
+
+ printf("finished locktest6\n");
+ return True;
+}
+
+static bool run_locktest7(int dummy)
+{
+ struct cli_state *cli1;
+ const char *fname = "\\lockt7.lck";
+ int fnum1;
+ char buf[200];
+ bool correct = False;
+
+ if (!torture_open_connection(&cli1, 0)) {
+ return False;
+ }
+
+ cli_sockopt(cli1, sockops);
+
+ printf("starting locktest7\n");
+
+ cli_unlink(cli1, fname);
+
+ fnum1 = cli_open(cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+
+ memset(buf, 0, sizeof(buf));
+
+ if (cli_write(cli1, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
+ printf("Failed to create file\n");
+ goto fail;
+ }
+
+ cli_setpid(cli1, 1);
+
+ if (!cli_lock(cli1, fnum1, 130, 4, 0, READ_LOCK)) {
+ printf("Unable to apply read lock on range 130:4, error was %s\n", cli_errstr(cli1));
+ goto fail;
+ } else {
+ printf("pid1 successfully locked range 130:4 for READ\n");
+ }
+
+ if (cli_read(cli1, fnum1, buf, 130, 4) != 4) {
+ printf("pid1 unable to read the range 130:4, error was %s\n", cli_errstr(cli1));
+ goto fail;
+ } else {
+ printf("pid1 successfully read the range 130:4\n");
+ }
+
+ if (cli_write(cli1, fnum1, 0, buf, 130, 4) != 4) {
+ printf("pid1 unable to write to the range 130:4, error was %s\n", cli_errstr(cli1));
+ if (NT_STATUS_V(cli_nt_error(cli1)) != NT_STATUS_V(NT_STATUS_FILE_LOCK_CONFLICT)) {
+ printf("Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)\n");
+ goto fail;
+ }
+ } else {
+ printf("pid1 successfully wrote to the range 130:4 (should be denied)\n");
+ goto fail;
+ }
+
+ cli_setpid(cli1, 2);
+
+ if (cli_read(cli1, fnum1, buf, 130, 4) != 4) {
+ printf("pid2 unable to read the range 130:4, error was %s\n", cli_errstr(cli1));
+ } else {
+ printf("pid2 successfully read the range 130:4\n");
+ }
+
+ if (cli_write(cli1, fnum1, 0, buf, 130, 4) != 4) {
+ printf("pid2 unable to write to the range 130:4, error was %s\n", cli_errstr(cli1));
+ if (NT_STATUS_V(cli_nt_error(cli1)) != NT_STATUS_V(NT_STATUS_FILE_LOCK_CONFLICT)) {
+ printf("Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)\n");
+ goto fail;
+ }
+ } else {
+ printf("pid2 successfully wrote to the range 130:4 (should be denied)\n");
+ goto fail;
+ }
+
+ cli_setpid(cli1, 1);
+ cli_unlock(cli1, fnum1, 130, 4);
+
+ if (!cli_lock(cli1, fnum1, 130, 4, 0, WRITE_LOCK)) {
+ printf("Unable to apply write lock on range 130:4, error was %s\n", cli_errstr(cli1));
+ goto fail;
+ } else {
+ printf("pid1 successfully locked range 130:4 for WRITE\n");
+ }
+
+ if (cli_read(cli1, fnum1, buf, 130, 4) != 4) {
+ printf("pid1 unable to read the range 130:4, error was %s\n", cli_errstr(cli1));
+ goto fail;
+ } else {
+ printf("pid1 successfully read the range 130:4\n");
+ }
+
+ if (cli_write(cli1, fnum1, 0, buf, 130, 4) != 4) {
+ printf("pid1 unable to write to the range 130:4, error was %s\n", cli_errstr(cli1));
+ goto fail;
+ } else {
+ printf("pid1 successfully wrote to the range 130:4\n");
+ }
+
+ cli_setpid(cli1, 2);
+
+ if (cli_read(cli1, fnum1, buf, 130, 4) != 4) {
+ printf("pid2 unable to read the range 130:4, error was %s\n", cli_errstr(cli1));
+ if (NT_STATUS_V(cli_nt_error(cli1)) != NT_STATUS_V(NT_STATUS_FILE_LOCK_CONFLICT)) {
+ printf("Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)\n");
+ goto fail;
+ }
+ } else {
+ printf("pid2 successfully read the range 130:4 (should be denied)\n");
+ goto fail;
+ }
+
+ if (cli_write(cli1, fnum1, 0, buf, 130, 4) != 4) {
+ printf("pid2 unable to write to the range 130:4, error was %s\n", cli_errstr(cli1));
+ if (NT_STATUS_V(cli_nt_error(cli1)) != NT_STATUS_V(NT_STATUS_FILE_LOCK_CONFLICT)) {
+ printf("Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)\n");
+ goto fail;
+ }
+ } else {
+ printf("pid2 successfully wrote to the range 130:4 (should be denied)\n");
+ goto fail;
+ }
+
+ cli_unlock(cli1, fnum1, 130, 0);
+ correct = True;
+
+fail:
+ cli_close(cli1, fnum1);
+ cli_unlink(cli1, fname);
+ torture_close_connection(cli1);
+
+ printf("finished locktest7\n");
+ return correct;
+}
+
+/*
+test whether fnums and tids open on one VC are available on another (a major
+security hole)
+*/
+static bool run_fdpasstest(int dummy)
+{
+ struct cli_state *cli1, *cli2;
+ const char *fname = "\\fdpass.tst";
+ int fnum1;
+ char buf[1024];
+
+ if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
+ return False;
+ }
+ cli_sockopt(cli1, sockops);
+ cli_sockopt(cli2, sockops);
+
+ printf("starting fdpasstest\n");
+
+ cli_unlink(cli1, fname);
+
+ fnum1 = cli_open(cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ if (cli_write(cli1, fnum1, 0, "hello world\n", 0, 13) != 13) {
+ printf("write failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ cli2->vuid = cli1->vuid;
+ cli2->cnum = cli1->cnum;
+ cli2->pid = cli1->pid;
+
+ if (cli_read(cli2, fnum1, buf, 0, 13) == 13) {
+ printf("read succeeded! nasty security hole [%s]\n",
+ buf);
+ return False;
+ }
+
+ cli_close(cli1, fnum1);
+ cli_unlink(cli1, fname);
+
+ torture_close_connection(cli1);
+ torture_close_connection(cli2);
+
+ printf("finished fdpasstest\n");
+ return True;
+}
+
+static bool run_fdsesstest(int dummy)
+{
+ struct cli_state *cli;
+ uint16 new_vuid;
+ uint16 saved_vuid;
+ uint16 new_cnum;
+ uint16 saved_cnum;
+ const char *fname = "\\fdsess.tst";
+ const char *fname1 = "\\fdsess1.tst";
+ int fnum1;
+ int fnum2;
+ char buf[1024];
+ bool ret = True;
+
+ if (!torture_open_connection(&cli, 0))
+ return False;
+ cli_sockopt(cli, sockops);
+
+ if (!torture_cli_session_setup2(cli, &new_vuid))
+ return False;
+
+ saved_cnum = cli->cnum;
+ if (!cli_send_tconX(cli, share, "?????", "", 1))
+ return False;
+ new_cnum = cli->cnum;
+ cli->cnum = saved_cnum;
+
+ printf("starting fdsesstest\n");
+
+ cli_unlink(cli, fname);
+ cli_unlink(cli, fname1);
+
+ fnum1 = cli_open(cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(cli));
+ return False;
+ }
+
+ if (cli_write(cli, fnum1, 0, "hello world\n", 0, 13) != 13) {
+ printf("write failed (%s)\n", cli_errstr(cli));
+ return False;
+ }
+
+ saved_vuid = cli->vuid;
+ cli->vuid = new_vuid;
+
+ if (cli_read(cli, fnum1, buf, 0, 13) == 13) {
+ printf("read succeeded with different vuid! nasty security hole [%s]\n",
+ buf);
+ ret = False;
+ }
+ /* Try to open a file with different vuid, samba cnum. */
+ fnum2 = cli_open(cli, fname1, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum2 != -1) {
+ printf("create with different vuid, same cnum succeeded.\n");
+ cli_close(cli, fnum2);
+ cli_unlink(cli, fname1);
+ } else {
+ printf("create with different vuid, same cnum failed.\n");
+ printf("This will cause problems with service clients.\n");
+ ret = False;
+ }
+
+ cli->vuid = saved_vuid;
+
+ /* Try with same vuid, different cnum. */
+ cli->cnum = new_cnum;
+
+ if (cli_read(cli, fnum1, buf, 0, 13) == 13) {
+ printf("read succeeded with different cnum![%s]\n",
+ buf);
+ ret = False;
+ }
+
+ cli->cnum = saved_cnum;
+ cli_close(cli, fnum1);
+ cli_unlink(cli, fname);
+
+ torture_close_connection(cli);
+
+ printf("finished fdsesstest\n");
+ return ret;
+}
+
+/*
+ This test checks that
+
+ 1) the server does not allow an unlink on a file that is open
+*/
+static bool run_unlinktest(int dummy)
+{
+ struct cli_state *cli;
+ const char *fname = "\\unlink.tst";
+ int fnum;
+ bool correct = True;
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ cli_sockopt(cli, sockops);
+
+ printf("starting unlink test\n");
+
+ cli_unlink(cli, fname);
+
+ cli_setpid(cli, 1);
+
+ fnum = cli_open(cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(cli));
+ return False;
+ }
+
+ if (cli_unlink(cli, fname)) {
+ printf("error: server allowed unlink on an open file\n");
+ correct = False;
+ } else {
+ correct = check_error(__LINE__, cli, ERRDOS, ERRbadshare,
+ NT_STATUS_SHARING_VIOLATION);
+ }
+
+ cli_close(cli, fnum);
+ cli_unlink(cli, fname);
+
+ if (!torture_close_connection(cli)) {
+ correct = False;
+ }
+
+ printf("unlink test finished\n");
+
+ return correct;
+}
+
+
+/*
+test how many open files this server supports on the one socket
+*/
+static bool run_maxfidtest(int dummy)
+{
+ struct cli_state *cli;
+ const char *ftemplate = "\\maxfid.%d.%d";
+ fstring fname;
+ int fnums[0x11000], i;
+ int retries=4;
+ bool correct = True;
+
+ cli = current_cli;
+
+ if (retries <= 0) {
+ printf("failed to connect\n");
+ return False;
+ }
+
+ cli_sockopt(cli, sockops);
+
+ for (i=0; i<0x11000; i++) {
+ slprintf(fname,sizeof(fname)-1,ftemplate, i,(int)getpid());
+ if ((fnums[i] = cli_open(cli, fname,
+ O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) ==
+ -1) {
+ printf("open of %s failed (%s)\n",
+ fname, cli_errstr(cli));
+ printf("maximum fnum is %d\n", i);
+ break;
+ }
+ printf("%6d\r", i);
+ }
+ printf("%6d\n", i);
+ i--;
+
+ printf("cleaning up\n");
+ for (;i>=0;i--) {
+ slprintf(fname,sizeof(fname)-1,ftemplate, i,(int)getpid());
+ cli_close(cli, fnums[i]);
+ if (!cli_unlink(cli, fname)) {
+ printf("unlink of %s failed (%s)\n",
+ fname, cli_errstr(cli));
+ correct = False;
+ }
+ printf("%6d\r", i);
+ }
+ printf("%6d\n", 0);
+
+ printf("maxfid test finished\n");
+ if (!torture_close_connection(cli)) {
+ correct = False;
+ }
+ return correct;
+}
+
+/* generate a random buffer */
+static void rand_buf(char *buf, int len)
+{
+ while (len--) {
+ *buf = (char)sys_random();
+ buf++;
+ }
+}
+
+/* send smb negprot commands, not reading the response */
+static bool run_negprot_nowait(int dummy)
+{
+ int i;
+ static struct cli_state *cli;
+ bool correct = True;
+
+ printf("starting negprot nowait test\n");
+
+ if (!(cli = open_nbt_connection())) {
+ return False;
+ }
+
+ for (i=0;i<50000;i++) {
+ cli_negprot_send(cli);
+ }
+
+ if (!torture_close_connection(cli)) {
+ correct = False;
+ }
+
+ printf("finished negprot nowait test\n");
+
+ return correct;
+}
+
+
+/* send random IPC commands */
+static bool run_randomipc(int dummy)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ unsigned int rdrcnt,rprcnt;
+ char param[1024];
+ int api, param_len, i;
+ struct cli_state *cli;
+ bool correct = True;
+ int count = 50000;
+
+ printf("starting random ipc test\n");
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ for (i=0;i<count;i++) {
+ api = sys_random() % 500;
+ param_len = (sys_random() % 64);
+
+ rand_buf(param, param_len);
+
+ SSVAL(param,0,api);
+
+ cli_api(cli,
+ param, param_len, 8,
+ NULL, 0, BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt);
+ if (i % 100 == 0) {
+ printf("%d/%d\r", i,count);
+ }
+ }
+ printf("%d/%d\n", i, count);
+
+ if (!torture_close_connection(cli)) {
+ correct = False;
+ }
+
+ printf("finished random ipc test\n");
+
+ return correct;
+}
+
+
+
+static void browse_callback(const char *sname, uint32 stype,
+ const char *comment, void *state)
+{
+ printf("\t%20.20s %08x %s\n", sname, stype, comment);
+}
+
+
+
+/*
+ This test checks the browse list code
+
+*/
+static bool run_browsetest(int dummy)
+{
+ static struct cli_state *cli;
+ bool correct = True;
+
+ printf("starting browse test\n");
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ printf("domain list:\n");
+ cli_NetServerEnum(cli, cli->server_domain,
+ SV_TYPE_DOMAIN_ENUM,
+ browse_callback, NULL);
+
+ printf("machine list:\n");
+ cli_NetServerEnum(cli, cli->server_domain,
+ SV_TYPE_ALL,
+ browse_callback, NULL);
+
+ if (!torture_close_connection(cli)) {
+ correct = False;
+ }
+
+ printf("browse test finished\n");
+
+ return correct;
+
+}
+
+
+/*
+ This checks how the getatr calls works
+*/
+static bool run_attrtest(int dummy)
+{
+ struct cli_state *cli;
+ int fnum;
+ time_t t, t2;
+ const char *fname = "\\attrib123456789.tst";
+ bool correct = True;
+
+ printf("starting attrib test\n");
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ cli_unlink(cli, fname);
+ fnum = cli_open(cli, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ cli_close(cli, fnum);
+ if (!cli_getatr(cli, fname, NULL, NULL, &t)) {
+ printf("getatr failed (%s)\n", cli_errstr(cli));
+ correct = False;
+ }
+
+ if (abs(t - time(NULL)) > 60*60*24*10) {
+ printf("ERROR: SMBgetatr bug. time is %s",
+ ctime(&t));
+ t = time(NULL);
+ correct = True;
+ }
+
+ t2 = t-60*60*24; /* 1 day ago */
+
+ if (!cli_setatr(cli, fname, 0, t2)) {
+ printf("setatr failed (%s)\n", cli_errstr(cli));
+ correct = True;
+ }
+
+ if (!cli_getatr(cli, fname, NULL, NULL, &t)) {
+ printf("getatr failed (%s)\n", cli_errstr(cli));
+ correct = True;
+ }
+
+ if (t != t2) {
+ printf("ERROR: getatr/setatr bug. times are\n%s",
+ ctime(&t));
+ printf("%s", ctime(&t2));
+ correct = True;
+ }
+
+ cli_unlink(cli, fname);
+
+ if (!torture_close_connection(cli)) {
+ correct = False;
+ }
+
+ printf("attrib test finished\n");
+
+ return correct;
+}
+
+
+/*
+ This checks a couple of trans2 calls
+*/
+static bool run_trans2test(int dummy)
+{
+ struct cli_state *cli;
+ int fnum;
+ SMB_OFF_T size;
+ time_t c_time, a_time, m_time;
+ struct timespec c_time_ts, a_time_ts, m_time_ts, w_time_ts, m_time2_ts;
+ const char *fname = "\\trans2.tst";
+ const char *dname = "\\trans2";
+ const char *fname2 = "\\trans2\\trans2.tst";
+ char pname[1024];
+ bool correct = True;
+
+ printf("starting trans2 test\n");
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ cli_unlink(cli, fname);
+ fnum = cli_open(cli, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ if (!cli_qfileinfo(cli, fnum, NULL, &size, &c_time_ts, &a_time_ts, &w_time_ts,
+ &m_time_ts, NULL)) {
+ printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(cli));
+ correct = False;
+ }
+
+ if (!cli_qfilename(cli, fnum, pname, sizeof(pname))) {
+ printf("ERROR: qfilename failed (%s)\n", cli_errstr(cli));
+ correct = False;
+ }
+
+ if (strcmp(pname, fname)) {
+ printf("qfilename gave different name? [%s] [%s]\n",
+ fname, pname);
+ correct = False;
+ }
+
+ cli_close(cli, fnum);
+
+ sleep(2);
+
+ cli_unlink(cli, fname);
+ fnum = cli_open(cli, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ if (fnum == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(cli));
+ return False;
+ }
+ cli_close(cli, fnum);
+
+ if (!cli_qpathinfo(cli, fname, &c_time, &a_time, &m_time, &size, NULL)) {
+ printf("ERROR: qpathinfo failed (%s)\n", cli_errstr(cli));
+ correct = False;
+ } else {
+ if (c_time != m_time) {
+ printf("create time=%s", ctime(&c_time));
+ printf("modify time=%s", ctime(&m_time));
+ printf("This system appears to have sticky create times\n");
+ }
+ if (a_time % (60*60) == 0) {
+ printf("access time=%s", ctime(&a_time));
+ printf("This system appears to set a midnight access time\n");
+ correct = False;
+ }
+
+ if (abs(m_time - time(NULL)) > 60*60*24*7) {
+ printf("ERROR: totally incorrect times - maybe word reversed? mtime=%s", ctime(&m_time));
+ correct = False;
+ }
+ }
+
+
+ cli_unlink(cli, fname);
+ fnum = cli_open(cli, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ cli_close(cli, fnum);
+ if (!cli_qpathinfo2(cli, fname, &c_time_ts, &a_time_ts, &w_time_ts,
+ &m_time_ts, &size, NULL, NULL)) {
+ printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(cli));
+ correct = False;
+ } else {
+ if (w_time_ts.tv_sec < 60*60*24*2) {
+ printf("write time=%s", ctime(&w_time_ts.tv_sec));
+ printf("This system appears to set a initial 0 write time\n");
+ correct = False;
+ }
+ }
+
+ cli_unlink(cli, fname);
+
+
+ /* check if the server updates the directory modification time
+ when creating a new file */
+ if (!cli_mkdir(cli, dname)) {
+ printf("ERROR: mkdir failed (%s)\n", cli_errstr(cli));
+ correct = False;
+ }
+ sleep(3);
+ if (!cli_qpathinfo2(cli, "\\trans2\\", &c_time_ts, &a_time_ts, &w_time_ts,
+ &m_time_ts, &size, NULL, NULL)) {
+ printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(cli));
+ correct = False;
+ }
+
+ fnum = cli_open(cli, fname2,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ cli_write(cli, fnum, 0, (char *)&fnum, 0, sizeof(fnum));
+ cli_close(cli, fnum);
+ if (!cli_qpathinfo2(cli, "\\trans2\\", &c_time_ts, &a_time_ts, &w_time_ts,
+ &m_time2_ts, &size, NULL, NULL)) {
+ printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(cli));
+ correct = False;
+ } else {
+ if (memcmp(&m_time_ts, &m_time2_ts, sizeof(struct timespec))
+ == 0) {
+ printf("This system does not update directory modification times\n");
+ correct = False;
+ }
+ }
+ cli_unlink(cli, fname2);
+ cli_rmdir(cli, dname);
+
+ if (!torture_close_connection(cli)) {
+ correct = False;
+ }
+
+ printf("trans2 test finished\n");
+
+ return correct;
+}
+
+/*
+ This checks new W2K calls.
+*/
+
+static bool new_trans(struct cli_state *pcli, int fnum, int level)
+{
+ char *buf = NULL;
+ uint32 len;
+ bool correct = True;
+
+ if (!cli_qfileinfo_test(pcli, fnum, level, &buf, &len)) {
+ printf("ERROR: qfileinfo (%d) failed (%s)\n", level, cli_errstr(pcli));
+ correct = False;
+ } else {
+ printf("qfileinfo: level %d, len = %u\n", level, len);
+ dump_data(0, (uint8 *)buf, len);
+ printf("\n");
+ }
+ SAFE_FREE(buf);
+ return correct;
+}
+
+static bool run_w2ktest(int dummy)
+{
+ struct cli_state *cli;
+ int fnum;
+ const char *fname = "\\w2ktest\\w2k.tst";
+ int level;
+ bool correct = True;
+
+ printf("starting w2k test\n");
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ fnum = cli_open(cli, fname,
+ O_RDWR | O_CREAT , DENY_NONE);
+
+ for (level = 1004; level < 1040; level++) {
+ new_trans(cli, fnum, level);
+ }
+
+ cli_close(cli, fnum);
+
+ if (!torture_close_connection(cli)) {
+ correct = False;
+ }
+
+ printf("w2k test finished\n");
+
+ return correct;
+}
+
+
+/*
+ this is a harness for some oplock tests
+ */
+static bool run_oplock1(int dummy)
+{
+ struct cli_state *cli1;
+ const char *fname = "\\lockt1.lck";
+ int fnum1;
+ bool correct = True;
+
+ printf("starting oplock test 1\n");
+
+ if (!torture_open_connection(&cli1, 0)) {
+ return False;
+ }
+
+ cli_unlink(cli1, fname);
+
+ cli_sockopt(cli1, sockops);
+
+ cli1->use_oplocks = True;
+
+ fnum1 = cli_open(cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ cli1->use_oplocks = False;
+
+ cli_unlink(cli1, fname);
+ cli_unlink(cli1, fname);
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("close2 failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ if (!cli_unlink(cli1, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ if (!torture_close_connection(cli1)) {
+ correct = False;
+ }
+
+ printf("finished oplock test 1\n");
+
+ return correct;
+}
+
+static bool run_oplock2(int dummy)
+{
+ struct cli_state *cli1, *cli2;
+ const char *fname = "\\lockt2.lck";
+ int fnum1, fnum2;
+ int saved_use_oplocks = use_oplocks;
+ char buf[4];
+ bool correct = True;
+ volatile bool *shared_correct;
+
+ shared_correct = (volatile bool *)shm_setup(sizeof(bool));
+ *shared_correct = True;
+
+ use_level_II_oplocks = True;
+ use_oplocks = True;
+
+ printf("starting oplock test 2\n");
+
+ if (!torture_open_connection(&cli1, 0)) {
+ use_level_II_oplocks = False;
+ use_oplocks = saved_use_oplocks;
+ return False;
+ }
+
+ cli1->use_oplocks = True;
+ cli1->use_level_II_oplocks = True;
+
+ if (!torture_open_connection(&cli2, 1)) {
+ use_level_II_oplocks = False;
+ use_oplocks = saved_use_oplocks;
+ return False;
+ }
+
+ cli2->use_oplocks = True;
+ cli2->use_level_II_oplocks = True;
+
+ cli_unlink(cli1, fname);
+
+ cli_sockopt(cli1, sockops);
+ cli_sockopt(cli2, sockops);
+
+ fnum1 = cli_open(cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ /* Don't need the globals any more. */
+ use_level_II_oplocks = False;
+ use_oplocks = saved_use_oplocks;
+
+ if (fork() == 0) {
+ /* Child code */
+ fnum2 = cli_open(cli2, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("second open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ *shared_correct = False;
+ exit(0);
+ }
+
+ sleep(2);
+
+ if (!cli_close(cli2, fnum2)) {
+ printf("close2 failed (%s)\n", cli_errstr(cli1));
+ *shared_correct = False;
+ }
+
+ exit(0);
+ }
+
+ sleep(2);
+
+ /* Ensure cli1 processes the break. Empty file should always return 0
+ * bytes. */
+
+ if (cli_read(cli1, fnum1, buf, 0, 4) != 0) {
+ printf("read on fnum1 failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ }
+
+ /* Should now be at level II. */
+ /* Test if sending a write locks causes a break to none. */
+
+ if (!cli_lock(cli1, fnum1, 0, 4, 0, READ_LOCK)) {
+ printf("lock failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ }
+
+ cli_unlock(cli1, fnum1, 0, 4);
+
+ sleep(2);
+
+ if (!cli_lock(cli1, fnum1, 0, 4, 0, WRITE_LOCK)) {
+ printf("lock failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ }
+
+ cli_unlock(cli1, fnum1, 0, 4);
+
+ sleep(2);
+
+ cli_read(cli1, fnum1, buf, 0, 4);
+
+#if 0
+ if (cli_write(cli1, fnum1, 0, buf, 0, 4) != 4) {
+ printf("write on fnum1 failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ }
+#endif
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("close1 failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ }
+
+ sleep(4);
+
+ if (!cli_unlink(cli1, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ }
+
+ if (!torture_close_connection(cli1)) {
+ correct = False;
+ }
+
+ if (!*shared_correct) {
+ correct = False;
+ }
+
+ printf("finished oplock test 2\n");
+
+ return correct;
+}
+
+/* handler for oplock 3 tests */
+static bool oplock3_handler(struct cli_state *cli, int fnum, unsigned char level)
+{
+ printf("got oplock break fnum=%d level=%d\n",
+ fnum, level);
+ return cli_oplock_ack(cli, fnum, level);
+}
+
+static bool run_oplock3(int dummy)
+{
+ struct cli_state *cli;
+ const char *fname = "\\oplockt3.dat";
+ int fnum;
+ char buf[4] = "abcd";
+ bool correct = True;
+ volatile bool *shared_correct;
+
+ shared_correct = (volatile bool *)shm_setup(sizeof(bool));
+ *shared_correct = True;
+
+ printf("starting oplock test 3\n");
+
+ if (fork() == 0) {
+ /* Child code */
+ use_oplocks = True;
+ use_level_II_oplocks = True;
+ if (!torture_open_connection(&cli, 0)) {
+ *shared_correct = False;
+ exit(0);
+ }
+ sleep(2);
+ /* try to trigger a oplock break in parent */
+ fnum = cli_open(cli, fname, O_RDWR, DENY_NONE);
+ cli_write(cli, fnum, 0, buf, 0, 4);
+ exit(0);
+ }
+
+ /* parent code */
+ use_oplocks = True;
+ use_level_II_oplocks = True;
+ if (!torture_open_connection(&cli, 1)) { /* other is forked */
+ return False;
+ }
+ cli_oplock_handler(cli, oplock3_handler);
+ fnum = cli_open(cli, fname, O_RDWR|O_CREAT, DENY_NONE);
+ cli_write(cli, fnum, 0, buf, 0, 4);
+ cli_close(cli, fnum);
+ fnum = cli_open(cli, fname, O_RDWR, DENY_NONE);
+ cli->timeout = 20000;
+ cli_receive_smb(cli);
+ printf("finished oplock test 3\n");
+
+ return (correct && *shared_correct);
+
+/* What are we looking for here? What's sucess and what's FAILURE? */
+}
+
+
+
+/*
+ Test delete on close semantics.
+ */
+static bool run_deletetest(int dummy)
+{
+ struct cli_state *cli1 = NULL;
+ struct cli_state *cli2 = NULL;
+ const char *fname = "\\delete.file";
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool correct = True;
+
+ printf("starting delete test\n");
+
+ if (!torture_open_connection(&cli1, 0)) {
+ return False;
+ }
+
+ cli_sockopt(cli1, sockops);
+
+ /* Test 1 - this should delete the file on close. */
+
+ cli_setatr(cli1, fname, 0, 0);
+ cli_unlink(cli1, fname);
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, GENERIC_ALL_ACCESS|DELETE_ACCESS, FILE_ATTRIBUTE_NORMAL,
+ 0, FILE_OVERWRITE_IF,
+ FILE_DELETE_ON_CLOSE, 0);
+
+ if (fnum1 == -1) {
+ printf("[1] open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+#if 0 /* JRATEST */
+ {
+ uint32 *accinfo = NULL;
+ uint32 len;
+ cli_qfileinfo_test(cli1, fnum1, SMB_FILE_ACCESS_INFORMATION, (char **)&accinfo, &len);
+ if (accinfo)
+ printf("access mode = 0x%lx\n", *accinfo);
+ SAFE_FREE(accinfo);
+ }
+#endif
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("[1] close failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ fnum1 = cli_open(cli1, fname, O_RDWR, DENY_NONE);
+ if (fnum1 != -1) {
+ printf("[1] open of %s succeeded (should fail)\n", fname);
+ correct = False;
+ goto fail;
+ }
+
+ printf("first delete on close test succeeded.\n");
+
+ /* Test 2 - this should delete the file on close. */
+
+ cli_setatr(cli1, fname, 0, 0);
+ cli_unlink(cli1, fname);
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, GENERIC_ALL_ACCESS,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_NONE,
+ FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("[2] open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_nt_delete_on_close(cli1, fnum1, True)) {
+ printf("[2] setting delete_on_close failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("[2] close failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ fnum1 = cli_open(cli1, fname, O_RDONLY, DENY_NONE);
+ if (fnum1 != -1) {
+ printf("[2] open of %s succeeded should have been deleted on close !\n", fname);
+ if (!cli_close(cli1, fnum1)) {
+ printf("[2] close failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+ cli_unlink(cli1, fname);
+ } else
+ printf("second delete on close test succeeded.\n");
+
+ /* Test 3 - ... */
+ cli_setatr(cli1, fname, 0, 0);
+ cli_unlink(cli1, fname);
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, GENERIC_ALL_ACCESS, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("[3] open - 1 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ /* This should fail with a sharing violation - open for delete is only compatible
+ with SHARE_DELETE. */
+
+ fnum2 = cli_nt_create_full(cli1, fname, 0, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0, 0);
+
+ if (fnum2 != -1) {
+ printf("[3] open - 2 of %s succeeded - should have failed.\n", fname);
+ correct = False;
+ goto fail;
+ }
+
+ /* This should succeed. */
+
+ fnum2 = cli_nt_create_full(cli1, fname, 0, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, 0, 0);
+
+ if (fnum2 == -1) {
+ printf("[3] open - 2 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_nt_delete_on_close(cli1, fnum1, True)) {
+ printf("[3] setting delete_on_close failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("[3] close 1 failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_close(cli1, fnum2)) {
+ printf("[3] close 2 failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ /* This should fail - file should no longer be there. */
+
+ fnum1 = cli_open(cli1, fname, O_RDONLY, DENY_NONE);
+ if (fnum1 != -1) {
+ printf("[3] open of %s succeeded should have been deleted on close !\n", fname);
+ if (!cli_close(cli1, fnum1)) {
+ printf("[3] close failed (%s)\n", cli_errstr(cli1));
+ }
+ cli_unlink(cli1, fname);
+ correct = False;
+ goto fail;
+ } else
+ printf("third delete on close test succeeded.\n");
+
+ /* Test 4 ... */
+ cli_setatr(cli1, fname, 0, 0);
+ cli_unlink(cli1, fname);
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, FILE_READ_DATA|FILE_WRITE_DATA|DELETE_ACCESS,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("[4] open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ /* This should succeed. */
+ fnum2 = cli_nt_create_full(cli1, fname, 0, GENERIC_READ_ACCESS,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, 0, 0);
+ if (fnum2 == -1) {
+ printf("[4] open - 2 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_close(cli1, fnum2)) {
+ printf("[4] close - 1 failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_nt_delete_on_close(cli1, fnum1, True)) {
+ printf("[4] setting delete_on_close failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ /* This should fail - no more opens once delete on close set. */
+ fnum2 = cli_nt_create_full(cli1, fname, 0, GENERIC_READ_ACCESS,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OPEN, 0, 0);
+ if (fnum2 != -1) {
+ printf("[4] open - 3 of %s succeeded ! Should have failed.\n", fname );
+ correct = False;
+ goto fail;
+ } else
+ printf("fourth delete on close test succeeded.\n");
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("[4] close - 2 failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ /* Test 5 ... */
+ cli_setatr(cli1, fname, 0, 0);
+ cli_unlink(cli1, fname);
+
+ fnum1 = cli_open(cli1, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("[5] open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ /* This should fail - only allowed on NT opens with DELETE access. */
+
+ if (cli_nt_delete_on_close(cli1, fnum1, True)) {
+ printf("[5] setting delete_on_close on OpenX file succeeded - should fail !\n");
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("[5] close - 2 failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ printf("fifth delete on close test succeeded.\n");
+
+ /* Test 6 ... */
+ cli_setatr(cli1, fname, 0, 0);
+ cli_unlink(cli1, fname);
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, FILE_READ_DATA|FILE_WRITE_DATA,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("[6] open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ /* This should fail - only allowed on NT opens with DELETE access. */
+
+ if (cli_nt_delete_on_close(cli1, fnum1, True)) {
+ printf("[6] setting delete_on_close on file with no delete access succeeded - should fail !\n");
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("[6] close - 2 failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ printf("sixth delete on close test succeeded.\n");
+
+ /* Test 7 ... */
+ cli_setatr(cli1, fname, 0, 0);
+ cli_unlink(cli1, fname);
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, FILE_READ_DATA|FILE_WRITE_DATA|DELETE_ACCESS,
+ FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("[7] open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_nt_delete_on_close(cli1, fnum1, True)) {
+ printf("[7] setting delete_on_close on file failed !\n");
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_nt_delete_on_close(cli1, fnum1, False)) {
+ printf("[7] unsetting delete_on_close on file failed !\n");
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("[7] close - 2 failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ /* This next open should succeed - we reset the flag. */
+
+ fnum1 = cli_open(cli1, fname, O_RDONLY, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("[5] open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("[7] close - 2 failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ printf("seventh delete on close test succeeded.\n");
+
+ /* Test 7 ... */
+ cli_setatr(cli1, fname, 0, 0);
+ cli_unlink(cli1, fname);
+
+ if (!torture_open_connection(&cli2, 1)) {
+ printf("[8] failed to open second connection.\n");
+ correct = False;
+ goto fail;
+ }
+
+ cli_sockopt(cli1, sockops);
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, FILE_READ_DATA|FILE_WRITE_DATA|DELETE_ACCESS,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("[8] open 1 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ fnum2 = cli_nt_create_full(cli2, fname, 0, FILE_READ_DATA|FILE_WRITE_DATA|DELETE_ACCESS,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OPEN, 0, 0);
+
+ if (fnum2 == -1) {
+ printf("[8] open 2 of %s failed (%s)\n", fname, cli_errstr(cli2));
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_nt_delete_on_close(cli1, fnum1, True)) {
+ printf("[8] setting delete_on_close on file failed !\n");
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("[8] close - 1 failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_close(cli2, fnum2)) {
+ printf("[8] close - 2 failed (%s)\n", cli_errstr(cli2));
+ correct = False;
+ goto fail;
+ }
+
+ /* This should fail.. */
+ fnum1 = cli_open(cli1, fname, O_RDONLY, DENY_NONE);
+ if (fnum1 != -1) {
+ printf("[8] open of %s succeeded should have been deleted on close !\n", fname);
+ goto fail;
+ correct = False;
+ } else
+ printf("eighth delete on close test succeeded.\n");
+
+ /* This should fail - we need to set DELETE_ACCESS. */
+ fnum1 = cli_nt_create_full(cli1, fname, 0,FILE_READ_DATA|FILE_WRITE_DATA,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_NONE, FILE_OVERWRITE_IF, FILE_DELETE_ON_CLOSE, 0);
+
+ if (fnum1 != -1) {
+ printf("[9] open of %s succeeded should have failed!\n", fname);
+ correct = False;
+ goto fail;
+ }
+
+ printf("ninth delete on close test succeeded.\n");
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, FILE_READ_DATA|FILE_WRITE_DATA|DELETE_ACCESS,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_NONE, FILE_OVERWRITE_IF, FILE_DELETE_ON_CLOSE, 0);
+ if (fnum1 == -1) {
+ printf("[10] open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ /* This should delete the file. */
+ if (!cli_close(cli1, fnum1)) {
+ printf("[10] close failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ /* This should fail.. */
+ fnum1 = cli_open(cli1, fname, O_RDONLY, DENY_NONE);
+ if (fnum1 != -1) {
+ printf("[10] open of %s succeeded should have been deleted on close !\n", fname);
+ goto fail;
+ correct = False;
+ } else
+ printf("tenth delete on close test succeeded.\n");
+
+ cli_setatr(cli1, fname, 0, 0);
+ cli_unlink(cli1, fname);
+
+ /* What error do we get when attempting to open a read-only file with
+ delete access ? */
+
+ /* Create a readonly file. */
+ fnum1 = cli_nt_create_full(cli1, fname, 0, FILE_READ_DATA|FILE_WRITE_DATA,
+ FILE_ATTRIBUTE_READONLY, FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0, 0);
+ if (fnum1 == -1) {
+ printf("[11] open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("[11] close failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ goto fail;
+ }
+
+ /* Now try open for delete access. */
+ fnum1 = cli_nt_create_full(cli1, fname, 0, FILE_READ_ATTRIBUTES|DELETE_ACCESS,
+ 0, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 != -1) {
+ printf("[11] open of %s succeeded should have been denied with ACCESS_DENIED!\n", fname);
+ cli_close(cli1, fnum1);
+ goto fail;
+ correct = False;
+ } else {
+ NTSTATUS nterr = cli_nt_error(cli1);
+ if (!NT_STATUS_EQUAL(nterr,NT_STATUS_ACCESS_DENIED)) {
+ printf("[11] open of %s should have been denied with ACCESS_DENIED! Got error %s\n", fname, nt_errstr(nterr));
+ goto fail;
+ correct = False;
+ } else {
+ printf("eleventh delete on close test succeeded.\n");
+ }
+ }
+
+ printf("finished delete test\n");
+
+ fail:
+ /* FIXME: This will crash if we aborted before cli2 got
+ * intialized, because these functions don't handle
+ * uninitialized connections. */
+
+ if (fnum1 != -1) cli_close(cli1, fnum1);
+ if (fnum2 != -1) cli_close(cli1, fnum2);
+ cli_setatr(cli1, fname, 0, 0);
+ cli_unlink(cli1, fname);
+
+ if (cli1 && !torture_close_connection(cli1)) {
+ correct = False;
+ }
+ if (cli2 && !torture_close_connection(cli2)) {
+ correct = False;
+ }
+ return correct;
+}
+
+
+/*
+ print out server properties
+ */
+static bool run_properties(int dummy)
+{
+ static struct cli_state *cli;
+ bool correct = True;
+
+ printf("starting properties test\n");
+
+ ZERO_STRUCT(cli);
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ cli_sockopt(cli, sockops);
+
+ d_printf("Capabilities 0x%08x\n", cli->capabilities);
+
+ if (!torture_close_connection(cli)) {
+ correct = False;
+ }
+
+ return correct;
+}
+
+
+
+/* FIRST_DESIRED_ACCESS 0xf019f */
+#define FIRST_DESIRED_ACCESS FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|\
+ FILE_READ_EA| /* 0xf */ \
+ FILE_WRITE_EA|FILE_READ_ATTRIBUTES| /* 0x90 */ \
+ FILE_WRITE_ATTRIBUTES| /* 0x100 */ \
+ DELETE_ACCESS|READ_CONTROL_ACCESS|\
+ WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS /* 0xf0000 */
+/* SECOND_DESIRED_ACCESS 0xe0080 */
+#define SECOND_DESIRED_ACCESS FILE_READ_ATTRIBUTES| /* 0x80 */ \
+ READ_CONTROL_ACCESS|WRITE_DAC_ACCESS|\
+ WRITE_OWNER_ACCESS /* 0xe0000 */
+
+#if 0
+#define THIRD_DESIRED_ACCESS FILE_READ_ATTRIBUTES| /* 0x80 */ \
+ READ_CONTROL_ACCESS|WRITE_DAC_ACCESS|\
+ FILE_READ_DATA|\
+ WRITE_OWNER_ACCESS /* */
+#endif
+
+/*
+ Test ntcreate calls made by xcopy
+ */
+static bool run_xcopy(int dummy)
+{
+ static struct cli_state *cli1;
+ const char *fname = "\\test.txt";
+ bool correct = True;
+ int fnum1, fnum2;
+
+ printf("starting xcopy test\n");
+
+ if (!torture_open_connection(&cli1, 0)) {
+ return False;
+ }
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0,
+ FIRST_DESIRED_ACCESS, FILE_ATTRIBUTE_ARCHIVE,
+ FILE_SHARE_NONE, FILE_OVERWRITE_IF,
+ 0x4044, 0);
+
+ if (fnum1 == -1) {
+ printf("First open failed - %s\n", cli_errstr(cli1));
+ return False;
+ }
+
+ fnum2 = cli_nt_create_full(cli1, fname, 0,
+ SECOND_DESIRED_ACCESS, 0,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN,
+ 0x200000, 0);
+ if (fnum2 == -1) {
+ printf("second open failed - %s\n", cli_errstr(cli1));
+ return False;
+ }
+
+ if (!torture_close_connection(cli1)) {
+ correct = False;
+ }
+
+ return correct;
+}
+
+/*
+ Test rename on files open with share delete and no share delete.
+ */
+static bool run_rename(int dummy)
+{
+ static struct cli_state *cli1;
+ const char *fname = "\\test.txt";
+ const char *fname1 = "\\test1.txt";
+ bool correct = True;
+ int fnum1;
+
+ printf("starting rename test\n");
+
+ if (!torture_open_connection(&cli1, 0)) {
+ return False;
+ }
+
+ cli_unlink(cli1, fname);
+ cli_unlink(cli1, fname1);
+ fnum1 = cli_nt_create_full(cli1, fname, 0, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("First open failed - %s\n", cli_errstr(cli1));
+ return False;
+ }
+
+ if (!cli_rename(cli1, fname, fname1)) {
+ printf("First rename failed (SHARE_READ) (this is correct) - %s\n", cli_errstr(cli1));
+ } else {
+ printf("First rename succeeded (SHARE_READ) - this should have failed !\n");
+ correct = False;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("close - 1 failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ cli_unlink(cli1, fname);
+ cli_unlink(cli1, fname1);
+ fnum1 = cli_nt_create_full(cli1, fname, 0, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL,
+#if 0
+ FILE_SHARE_DELETE|FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0, 0);
+#else
+ FILE_SHARE_DELETE|FILE_SHARE_READ, FILE_OVERWRITE_IF, 0, 0);
+#endif
+
+ if (fnum1 == -1) {
+ printf("Second open failed - %s\n", cli_errstr(cli1));
+ return False;
+ }
+
+ if (!cli_rename(cli1, fname, fname1)) {
+ printf("Second rename failed (SHARE_DELETE | SHARE_READ) - this should have succeeded - %s\n", cli_errstr(cli1));
+ correct = False;
+ } else {
+ printf("Second rename succeeded (SHARE_DELETE | SHARE_READ)\n");
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("close - 2 failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ cli_unlink(cli1, fname);
+ cli_unlink(cli1, fname1);
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, READ_CONTROL_ACCESS, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("Third open failed - %s\n", cli_errstr(cli1));
+ return False;
+ }
+
+
+#if 0
+ {
+ int fnum2;
+
+ fnum2 = cli_nt_create_full(cli1, fname, 0, DELETE_ACCESS, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum2 == -1) {
+ printf("Fourth open failed - %s\n", cli_errstr(cli1));
+ return False;
+ }
+ if (!cli_nt_delete_on_close(cli1, fnum2, True)) {
+ printf("[8] setting delete_on_close on file failed !\n");
+ return False;
+ }
+
+ if (!cli_close(cli1, fnum2)) {
+ printf("close - 4 failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+ }
+#endif
+
+ if (!cli_rename(cli1, fname, fname1)) {
+ printf("Third rename failed (SHARE_NONE) - this should have succeeded - %s\n", cli_errstr(cli1));
+ correct = False;
+ } else {
+ printf("Third rename succeeded (SHARE_NONE)\n");
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("close - 3 failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ cli_unlink(cli1, fname);
+ cli_unlink(cli1, fname1);
+
+ /*----*/
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("Fourth open failed - %s\n", cli_errstr(cli1));
+ return False;
+ }
+
+ if (!cli_rename(cli1, fname, fname1)) {
+ printf("Fourth rename failed (SHARE_READ | SHARE_WRITE) (this is correct) - %s\n", cli_errstr(cli1));
+ } else {
+ printf("Fourth rename succeeded (SHARE_READ | SHARE_WRITE) - this should have failed !\n");
+ correct = False;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("close - 4 failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ cli_unlink(cli1, fname);
+ cli_unlink(cli1, fname1);
+
+ /*--*/
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("Fifth open failed - %s\n", cli_errstr(cli1));
+ return False;
+ }
+
+ if (!cli_rename(cli1, fname, fname1)) {
+ printf("Fifth rename failed (SHARE_READ | SHARE_WRITE | SHARE_DELETE) - this should have succeeded - %s ! \n",
+ cli_errstr(cli1));
+ correct = False;
+ } else {
+ printf("Fifth rename succeeded (SHARE_READ | SHARE_WRITE | SHARE_DELETE) (this is correct) - %s\n", cli_errstr(cli1));
+ }
+
+ /*
+ * Now check if the first name still exists ...
+ */
+
+ /*fnum2 = cli_nt_create_full(cli1, fname, 0, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum2 == -1) {
+ printf("Opening original file after rename of open file fails: %s\n",
+ cli_errstr(cli1));
+ }
+ else {
+ printf("Opening original file after rename of open file works ...\n");
+ (void)cli_close(cli1, fnum2);
+ } */
+
+ /*--*/
+
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("close - 5 failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ cli_unlink(cli1, fname);
+ cli_unlink(cli1, fname1);
+
+ if (!torture_close_connection(cli1)) {
+ correct = False;
+ }
+
+ return correct;
+}
+
+static bool run_pipe_number(int dummy)
+{
+ struct cli_state *cli1;
+ const char *pipe_name = "\\SPOOLSS";
+ int fnum;
+ int num_pipes = 0;
+
+ printf("starting pipenumber test\n");
+ if (!torture_open_connection(&cli1, 0)) {
+ return False;
+ }
+
+ cli_sockopt(cli1, sockops);
+ while(1) {
+ fnum = cli_nt_create_full(cli1, pipe_name, 0, FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN_IF, 0, 0);
+
+ if (fnum == -1) {
+ printf("Open of pipe %s failed with error (%s)\n", pipe_name, cli_errstr(cli1));
+ break;
+ }
+ num_pipes++;
+ printf("\r%6d", num_pipes);
+ }
+
+ printf("pipe_number test - we can open %d %s pipes.\n", num_pipes, pipe_name );
+ torture_close_connection(cli1);
+ return True;
+}
+
+/*
+ Test open mode returns on read-only files.
+ */
+static bool run_opentest(int dummy)
+{
+ static struct cli_state *cli1;
+ static struct cli_state *cli2;
+ const char *fname = "\\readonly.file";
+ int fnum1, fnum2;
+ char buf[20];
+ SMB_OFF_T fsize;
+ bool correct = True;
+ char *tmp_path;
+
+ printf("starting open test\n");
+
+ if (!torture_open_connection(&cli1, 0)) {
+ return False;
+ }
+
+ cli_setatr(cli1, fname, 0, 0);
+ cli_unlink(cli1, fname);
+
+ cli_sockopt(cli1, sockops);
+
+ fnum1 = cli_open(cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("close2 failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ if (!cli_setatr(cli1, fname, aRONLY, 0)) {
+ printf("cli_setatr failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ fnum1 = cli_open(cli1, fname, O_RDONLY, DENY_WRITE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ /* This will fail - but the error should be ERRnoaccess, not ERRbadshare. */
+ fnum2 = cli_open(cli1, fname, O_RDWR, DENY_ALL);
+
+ if (check_error(__LINE__, cli1, ERRDOS, ERRnoaccess,
+ NT_STATUS_ACCESS_DENIED)) {
+ printf("correct error code ERRDOS/ERRnoaccess returned\n");
+ }
+
+ printf("finished open test 1\n");
+
+ cli_close(cli1, fnum1);
+
+ /* Now try not readonly and ensure ERRbadshare is returned. */
+
+ cli_setatr(cli1, fname, 0, 0);
+
+ fnum1 = cli_open(cli1, fname, O_RDONLY, DENY_WRITE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ /* This will fail - but the error should be ERRshare. */
+ fnum2 = cli_open(cli1, fname, O_RDWR, DENY_ALL);
+
+ if (check_error(__LINE__, cli1, ERRDOS, ERRbadshare,
+ NT_STATUS_SHARING_VIOLATION)) {
+ printf("correct error code ERRDOS/ERRbadshare returned\n");
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("close2 failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ cli_unlink(cli1, fname);
+
+ printf("finished open test 2\n");
+
+ /* Test truncate open disposition on file opened for read. */
+
+ fnum1 = cli_open(cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("(3) open (1) of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ /* write 20 bytes. */
+
+ memset(buf, '\0', 20);
+
+ if (cli_write(cli1, fnum1, 0, buf, 0, 20) != 20) {
+ printf("write failed (%s)\n", cli_errstr(cli1));
+ correct = False;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("(3) close1 failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ /* Ensure size == 20. */
+ if (!cli_getatr(cli1, fname, NULL, &fsize, NULL)) {
+ printf("(3) getatr failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ if (fsize != 20) {
+ printf("(3) file size != 20\n");
+ return False;
+ }
+
+ /* Now test if we can truncate a file opened for readonly. */
+
+ fnum1 = cli_open(cli1, fname, O_RDONLY|O_TRUNC, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("(3) open (2) of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("close2 failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ /* Ensure size == 0. */
+ if (!cli_getatr(cli1, fname, NULL, &fsize, NULL)) {
+ printf("(3) getatr failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+ if (fsize != 0) {
+ printf("(3) file size != 0\n");
+ return False;
+ }
+ printf("finished open test 3\n");
+
+ cli_unlink(cli1, fname);
+
+
+ printf("testing ctemp\n");
+ fnum1 = cli_ctemp(cli1, "\\", &tmp_path);
+ if (fnum1 == -1) {
+ printf("ctemp failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+ printf("ctemp gave path %s\n", tmp_path);
+ if (!cli_close(cli1, fnum1)) {
+ printf("close of temp failed (%s)\n", cli_errstr(cli1));
+ }
+ if (!cli_unlink(cli1, tmp_path)) {
+ printf("unlink of temp failed (%s)\n", cli_errstr(cli1));
+ }
+
+ /* Test the non-io opens... */
+
+ if (!torture_open_connection(&cli2, 1)) {
+ return False;
+ }
+
+ cli_setatr(cli2, fname, 0, 0);
+ cli_unlink(cli2, fname);
+
+ cli_sockopt(cli2, sockops);
+
+ printf("TEST #1 testing 2 non-io opens (no delete)\n");
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("test 1 open 1 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ fnum2 = cli_nt_create_full(cli2, fname, 0, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_NONE, FILE_OPEN_IF, 0, 0);
+
+ if (fnum2 == -1) {
+ printf("test 1 open 2 of %s failed (%s)\n", fname, cli_errstr(cli2));
+ return False;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("test 1 close 1 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+ if (!cli_close(cli2, fnum2)) {
+ printf("test 1 close 2 of %s failed (%s)\n", fname, cli_errstr(cli2));
+ return False;
+ }
+
+ printf("non-io open test #1 passed.\n");
+
+ cli_unlink(cli1, fname);
+
+ printf("TEST #2 testing 2 non-io opens (first with delete)\n");
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, DELETE_ACCESS|FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("test 2 open 1 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ fnum2 = cli_nt_create_full(cli2, fname, 0, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_NONE, FILE_OPEN_IF, 0, 0);
+
+ if (fnum2 == -1) {
+ printf("test 2 open 2 of %s failed (%s)\n", fname, cli_errstr(cli2));
+ return False;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("test 1 close 1 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+ if (!cli_close(cli2, fnum2)) {
+ printf("test 1 close 2 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ printf("non-io open test #2 passed.\n");
+
+ cli_unlink(cli1, fname);
+
+ printf("TEST #3 testing 2 non-io opens (second with delete)\n");
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("test 3 open 1 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ fnum2 = cli_nt_create_full(cli2, fname, 0, DELETE_ACCESS|FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_NONE, FILE_OPEN_IF, 0, 0);
+
+ if (fnum2 == -1) {
+ printf("test 3 open 2 of %s failed (%s)\n", fname, cli_errstr(cli2));
+ return False;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("test 3 close 1 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+ if (!cli_close(cli2, fnum2)) {
+ printf("test 3 close 2 of %s failed (%s)\n", fname, cli_errstr(cli2));
+ return False;
+ }
+
+ printf("non-io open test #3 passed.\n");
+
+ cli_unlink(cli1, fname);
+
+ printf("TEST #4 testing 2 non-io opens (both with delete)\n");
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, DELETE_ACCESS|FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("test 4 open 1 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ fnum2 = cli_nt_create_full(cli2, fname, 0, DELETE_ACCESS|FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_NONE, FILE_OPEN_IF, 0, 0);
+
+ if (fnum2 != -1) {
+ printf("test 4 open 2 of %s SUCCEEDED - should have failed (%s)\n", fname, cli_errstr(cli2));
+ return False;
+ }
+
+ printf("test 3 open 2 of %s gave %s (correct error should be %s)\n", fname, cli_errstr(cli2), "sharing violation");
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("test 4 close 1 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ printf("non-io open test #4 passed.\n");
+
+ cli_unlink(cli1, fname);
+
+ printf("TEST #5 testing 2 non-io opens (both with delete - both with file share delete)\n");
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, DELETE_ACCESS|FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_DELETE, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("test 5 open 1 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ fnum2 = cli_nt_create_full(cli2, fname, 0, DELETE_ACCESS|FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_DELETE, FILE_OPEN_IF, 0, 0);
+
+ if (fnum2 == -1) {
+ printf("test 5 open 2 of %s failed (%s)\n", fname, cli_errstr(cli2));
+ return False;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("test 5 close 1 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ if (!cli_close(cli2, fnum2)) {
+ printf("test 5 close 2 of %s failed (%s)\n", fname, cli_errstr(cli2));
+ return False;
+ }
+
+ printf("non-io open test #5 passed.\n");
+
+ printf("TEST #6 testing 1 non-io open, one io open\n");
+
+ cli_unlink(cli1, fname);
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("test 6 open 1 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ fnum2 = cli_nt_create_full(cli2, fname, 0, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ, FILE_OPEN_IF, 0, 0);
+
+ if (fnum2 == -1) {
+ printf("test 6 open 2 of %s failed (%s)\n", fname, cli_errstr(cli2));
+ return False;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("test 6 close 1 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ if (!cli_close(cli2, fnum2)) {
+ printf("test 6 close 2 of %s failed (%s)\n", fname, cli_errstr(cli2));
+ return False;
+ }
+
+ printf("non-io open test #6 passed.\n");
+
+ printf("TEST #7 testing 1 non-io open, one io open with delete\n");
+
+ cli_unlink(cli1, fname);
+
+ fnum1 = cli_nt_create_full(cli1, fname, 0, FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("test 7 open 1 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ fnum2 = cli_nt_create_full(cli2, fname, 0, DELETE_ACCESS|FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ|FILE_SHARE_DELETE, FILE_OPEN_IF, 0, 0);
+
+ if (fnum2 != -1) {
+ printf("test 7 open 2 of %s SUCCEEDED - should have failed (%s)\n", fname, cli_errstr(cli2));
+ return False;
+ }
+
+ printf("test 7 open 2 of %s gave %s (correct error should be %s)\n", fname, cli_errstr(cli2), "sharing violation");
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("test 7 close 1 of %s failed (%s)\n", fname, cli_errstr(cli1));
+ return False;
+ }
+
+ printf("non-io open test #7 passed.\n");
+
+ cli_unlink(cli1, fname);
+
+ if (!torture_close_connection(cli1)) {
+ correct = False;
+ }
+ if (!torture_close_connection(cli2)) {
+ correct = False;
+ }
+
+ return correct;
+}
+
+static uint32 open_attrs_table[] = {
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_ATTRIBUTE_ARCHIVE,
+ FILE_ATTRIBUTE_READONLY,
+ FILE_ATTRIBUTE_HIDDEN,
+ FILE_ATTRIBUTE_SYSTEM,
+
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY,
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN,
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM,
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN,
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM,
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,
+
+ FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN,
+ FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM,
+ FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,
+ FILE_ATTRIBUTE_HIDDEN,FILE_ATTRIBUTE_SYSTEM,
+};
+
+struct trunc_open_results {
+ unsigned int num;
+ uint32 init_attr;
+ uint32 trunc_attr;
+ uint32 result_attr;
+};
+
+static struct trunc_open_results attr_results[] = {
+ { 0, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_ARCHIVE },
+ { 1, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_ARCHIVE },
+ { 2, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY },
+ { 16, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_ARCHIVE },
+ { 17, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_ARCHIVE },
+ { 18, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY },
+ { 51, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 54, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 56, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN },
+ { 68, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 71, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 73, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM },
+ { 99, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_HIDDEN,FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 102, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 104, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN },
+ { 116, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 119, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 121, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM },
+ { 170, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN },
+ { 173, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM },
+ { 227, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 230, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 232, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN },
+ { 244, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 247, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 249, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM }
+};
+
+static bool run_openattrtest(int dummy)
+{
+ static struct cli_state *cli1;
+ const char *fname = "\\openattr.file";
+ int fnum1;
+ bool correct = True;
+ uint16 attr;
+ unsigned int i, j, k, l;
+
+ printf("starting open attr test\n");
+
+ if (!torture_open_connection(&cli1, 0)) {
+ return False;
+ }
+
+ cli_sockopt(cli1, sockops);
+
+ for (k = 0, i = 0; i < sizeof(open_attrs_table)/sizeof(uint32); i++) {
+ cli_setatr(cli1, fname, 0, 0);
+ cli_unlink(cli1, fname);
+ fnum1 = cli_nt_create_full(cli1, fname, 0, FILE_WRITE_DATA, open_attrs_table[i],
+ FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ printf("open %d (1) of %s failed (%s)\n", i, fname, cli_errstr(cli1));
+ return False;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("close %d (1) of %s failed (%s)\n", i, fname, cli_errstr(cli1));
+ return False;
+ }
+
+ for (j = 0; j < sizeof(open_attrs_table)/sizeof(uint32); j++) {
+ fnum1 = cli_nt_create_full(cli1, fname, 0, FILE_READ_DATA|FILE_WRITE_DATA, open_attrs_table[j],
+ FILE_SHARE_NONE, FILE_OVERWRITE, 0, 0);
+
+ if (fnum1 == -1) {
+ for (l = 0; l < sizeof(attr_results)/sizeof(struct trunc_open_results); l++) {
+ if (attr_results[l].num == k) {
+ printf("[%d] trunc open 0x%x -> 0x%x of %s failed - should have succeeded !(0x%x:%s)\n",
+ k, open_attrs_table[i],
+ open_attrs_table[j],
+ fname, NT_STATUS_V(cli_nt_error(cli1)), cli_errstr(cli1));
+ correct = False;
+ }
+ }
+ if (NT_STATUS_V(cli_nt_error(cli1)) != NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) {
+ printf("[%d] trunc open 0x%x -> 0x%x failed with wrong error code %s\n",
+ k, open_attrs_table[i], open_attrs_table[j],
+ cli_errstr(cli1));
+ correct = False;
+ }
+#if 0
+ printf("[%d] trunc open 0x%x -> 0x%x failed\n", k, open_attrs_table[i], open_attrs_table[j]);
+#endif
+ k++;
+ continue;
+ }
+
+ if (!cli_close(cli1, fnum1)) {
+ printf("close %d (2) of %s failed (%s)\n", j, fname, cli_errstr(cli1));
+ return False;
+ }
+
+ if (!cli_getatr(cli1, fname, &attr, NULL, NULL)) {
+ printf("getatr(2) failed (%s)\n", cli_errstr(cli1));
+ return False;
+ }
+
+#if 0
+ printf("[%d] getatr check [0x%x] trunc [0x%x] got attr 0x%x\n",
+ k, open_attrs_table[i], open_attrs_table[j], attr );
+#endif
+
+ for (l = 0; l < sizeof(attr_results)/sizeof(struct trunc_open_results); l++) {
+ if (attr_results[l].num == k) {
+ if (attr != attr_results[l].result_attr ||
+ open_attrs_table[i] != attr_results[l].init_attr ||
+ open_attrs_table[j] != attr_results[l].trunc_attr) {
+ printf("getatr check failed. [0x%x] trunc [0x%x] got attr 0x%x, should be 0x%x\n",
+ open_attrs_table[i],
+ open_attrs_table[j],
+ (unsigned int)attr,
+ attr_results[l].result_attr);
+ correct = False;
+ }
+ break;
+ }
+ }
+ k++;
+ }
+ }
+
+ cli_setatr(cli1, fname, 0, 0);
+ cli_unlink(cli1, fname);
+
+ printf("open attr test %s.\n", correct ? "passed" : "failed");
+
+ if (!torture_close_connection(cli1)) {
+ correct = False;
+ }
+ return correct;
+}
+
+static void list_fn(const char *mnt, file_info *finfo, const char *name, void *state)
+{
+
+}
+
+/*
+ test directory listing speed
+ */
+static bool run_dirtest(int dummy)
+{
+ int i;
+ static struct cli_state *cli;
+ int fnum;
+ double t1;
+ bool correct = True;
+
+ printf("starting directory test\n");
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ cli_sockopt(cli, sockops);
+
+ srandom(0);
+ for (i=0;i<torture_numops;i++) {
+ fstring fname;
+ slprintf(fname, sizeof(fname), "\\%x", (int)random());
+ fnum = cli_open(cli, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ fprintf(stderr,"Failed to open %s\n", fname);
+ return False;
+ }
+ cli_close(cli, fnum);
+ }
+
+ t1 = end_timer();
+
+ printf("Matched %d\n", cli_list(cli, "a*.*", 0, list_fn, NULL));
+ printf("Matched %d\n", cli_list(cli, "b*.*", 0, list_fn, NULL));
+ printf("Matched %d\n", cli_list(cli, "xyzabc", 0, list_fn, NULL));
+
+ printf("dirtest core %g seconds\n", end_timer() - t1);
+
+ srandom(0);
+ for (i=0;i<torture_numops;i++) {
+ fstring fname;
+ slprintf(fname, sizeof(fname), "\\%x", (int)random());
+ cli_unlink(cli, fname);
+ }
+
+ if (!torture_close_connection(cli)) {
+ correct = False;
+ }
+
+ printf("finished dirtest\n");
+
+ return correct;
+}
+
+static void del_fn(const char *mnt, file_info *finfo, const char *mask, void *state)
+{
+ struct cli_state *pcli = (struct cli_state *)state;
+ fstring fname;
+ slprintf(fname, sizeof(fname), "\\LISTDIR\\%s", finfo->name);
+
+ if (strcmp(finfo->name, ".") == 0 || strcmp(finfo->name, "..") == 0)
+ return;
+
+ if (finfo->mode & aDIR) {
+ if (!cli_rmdir(pcli, fname))
+ printf("del_fn: failed to rmdir %s\n,", fname );
+ } else {
+ if (!cli_unlink(pcli, fname))
+ printf("del_fn: failed to unlink %s\n,", fname );
+ }
+}
+
+
+/*
+ sees what IOCTLs are supported
+ */
+bool torture_ioctl_test(int dummy)
+{
+ static struct cli_state *cli;
+ uint16 device, function;
+ int fnum;
+ const char *fname = "\\ioctl.dat";
+ DATA_BLOB blob;
+ NTSTATUS status;
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ printf("starting ioctl test\n");
+
+ cli_unlink(cli, fname);
+
+ fnum = cli_open(cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(cli));
+ return False;
+ }
+
+ status = cli_raw_ioctl(cli, fnum, 0x2d0000 | (0x0420<<2), &blob);
+ printf("ioctl device info: %s\n", cli_errstr(cli));
+
+ status = cli_raw_ioctl(cli, fnum, IOCTL_QUERY_JOB_INFO, &blob);
+ printf("ioctl job info: %s\n", cli_errstr(cli));
+
+ for (device=0;device<0x100;device++) {
+ printf("testing device=0x%x\n", device);
+ for (function=0;function<0x100;function++) {
+ uint32 code = (device<<16) | function;
+
+ status = cli_raw_ioctl(cli, fnum, code, &blob);
+
+ if (NT_STATUS_IS_OK(status)) {
+ printf("ioctl 0x%x OK : %d bytes\n", (int)code,
+ (int)blob.length);
+ data_blob_free(&blob);
+ }
+ }
+ }
+
+ if (!torture_close_connection(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+
+/*
+ tries varients of chkpath
+ */
+bool torture_chkpath_test(int dummy)
+{
+ static struct cli_state *cli;
+ int fnum;
+ bool ret;
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ printf("starting chkpath test\n");
+
+ /* cleanup from an old run */
+ cli_rmdir(cli, "\\chkpath.dir\\dir2");
+ cli_unlink(cli, "\\chkpath.dir\\*");
+ cli_rmdir(cli, "\\chkpath.dir");
+
+ if (!cli_mkdir(cli, "\\chkpath.dir")) {
+ printf("mkdir1 failed : %s\n", cli_errstr(cli));
+ return False;
+ }
+
+ if (!cli_mkdir(cli, "\\chkpath.dir\\dir2")) {
+ printf("mkdir2 failed : %s\n", cli_errstr(cli));
+ return False;
+ }
+
+ fnum = cli_open(cli, "\\chkpath.dir\\foo.txt", O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum == -1) {
+ printf("open1 failed (%s)\n", cli_errstr(cli));
+ return False;
+ }
+ cli_close(cli, fnum);
+
+ if (!cli_chkpath(cli, "\\chkpath.dir")) {
+ printf("chkpath1 failed: %s\n", cli_errstr(cli));
+ ret = False;
+ }
+
+ if (!cli_chkpath(cli, "\\chkpath.dir\\dir2")) {
+ printf("chkpath2 failed: %s\n", cli_errstr(cli));
+ ret = False;
+ }
+
+ if (!cli_chkpath(cli, "\\chkpath.dir\\foo.txt")) {
+ ret = check_error(__LINE__, cli, ERRDOS, ERRbadpath,
+ NT_STATUS_NOT_A_DIRECTORY);
+ } else {
+ printf("* chkpath on a file should fail\n");
+ ret = False;
+ }
+
+ if (!cli_chkpath(cli, "\\chkpath.dir\\bar.txt")) {
+ ret = check_error(__LINE__, cli, ERRDOS, ERRbadfile,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ } else {
+ printf("* chkpath on a non existant file should fail\n");
+ ret = False;
+ }
+
+ if (!cli_chkpath(cli, "\\chkpath.dir\\dirxx\\bar.txt")) {
+ ret = check_error(__LINE__, cli, ERRDOS, ERRbadpath,
+ NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ } else {
+ printf("* chkpath on a non existent component should fail\n");
+ ret = False;
+ }
+
+ cli_rmdir(cli, "\\chkpath.dir\\dir2");
+ cli_unlink(cli, "\\chkpath.dir\\*");
+ cli_rmdir(cli, "\\chkpath.dir");
+
+ if (!torture_close_connection(cli)) {
+ return False;
+ }
+
+ return ret;
+}
+
+static bool run_eatest(int dummy)
+{
+ static struct cli_state *cli;
+ const char *fname = "\\eatest.txt";
+ bool correct = True;
+ int fnum, i;
+ size_t num_eas;
+ struct ea_struct *ea_list = NULL;
+ TALLOC_CTX *mem_ctx = talloc_init("eatest");
+
+ printf("starting eatest\n");
+
+ if (!torture_open_connection(&cli, 0)) {
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ cli_unlink(cli, fname);
+ fnum = cli_nt_create_full(cli, fname, 0,
+ FIRST_DESIRED_ACCESS, FILE_ATTRIBUTE_ARCHIVE,
+ FILE_SHARE_NONE, FILE_OVERWRITE_IF,
+ 0x4044, 0);
+
+ if (fnum == -1) {
+ printf("open failed - %s\n", cli_errstr(cli));
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ for (i = 0; i < 10; i++) {
+ fstring ea_name, ea_val;
+
+ slprintf(ea_name, sizeof(ea_name), "EA_%d", i);
+ memset(ea_val, (char)i+1, i+1);
+ if (!cli_set_ea_fnum(cli, fnum, ea_name, ea_val, i+1)) {
+ printf("ea_set of name %s failed - %s\n", ea_name, cli_errstr(cli));
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+ }
+
+ cli_close(cli, fnum);
+ for (i = 0; i < 10; i++) {
+ fstring ea_name, ea_val;
+
+ slprintf(ea_name, sizeof(ea_name), "EA_%d", i+10);
+ memset(ea_val, (char)i+1, i+1);
+ if (!cli_set_ea_path(cli, fname, ea_name, ea_val, i+1)) {
+ printf("ea_set of name %s failed - %s\n", ea_name, cli_errstr(cli));
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+ }
+
+ if (!cli_get_ea_list_path(cli, fname, mem_ctx, &num_eas, &ea_list)) {
+ printf("ea_get list failed - %s\n", cli_errstr(cli));
+ correct = False;
+ }
+
+ printf("num_eas = %d\n", (int)num_eas);
+
+ if (num_eas != 20) {
+ printf("Should be 20 EA's stored... failing.\n");
+ correct = False;
+ }
+
+ for (i = 0; i < num_eas; i++) {
+ printf("%d: ea_name = %s. Val = ", i, ea_list[i].name);
+ dump_data(0, ea_list[i].value.data,
+ ea_list[i].value.length);
+ }
+
+ /* Setting EA's to zero length deletes them. Test this */
+ printf("Now deleting all EA's - case indepenent....\n");
+
+#if 1
+ cli_set_ea_path(cli, fname, "", "", 0);
+#else
+ for (i = 0; i < 20; i++) {
+ fstring ea_name;
+ slprintf(ea_name, sizeof(ea_name), "ea_%d", i);
+ if (!cli_set_ea_path(cli, fname, ea_name, "", 0)) {
+ printf("ea_set of name %s failed - %s\n", ea_name, cli_errstr(cli));
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+ }
+#endif
+
+ if (!cli_get_ea_list_path(cli, fname, mem_ctx, &num_eas, &ea_list)) {
+ printf("ea_get list failed - %s\n", cli_errstr(cli));
+ correct = False;
+ }
+
+ printf("num_eas = %d\n", (int)num_eas);
+ for (i = 0; i < num_eas; i++) {
+ printf("%d: ea_name = %s. Val = ", i, ea_list[i].name);
+ dump_data(0, ea_list[i].value.data,
+ ea_list[i].value.length);
+ }
+
+ if (num_eas != 0) {
+ printf("deleting EA's failed.\n");
+ correct = False;
+ }
+
+ /* Try and delete a non existant EA. */
+ if (!cli_set_ea_path(cli, fname, "foo", "", 0)) {
+ printf("deleting non-existant EA 'foo' should succeed. %s\n", cli_errstr(cli));
+ correct = False;
+ }
+
+ talloc_destroy(mem_ctx);
+ if (!torture_close_connection(cli)) {
+ correct = False;
+ }
+
+ return correct;
+}
+
+static bool run_dirtest1(int dummy)
+{
+ int i;
+ static struct cli_state *cli;
+ int fnum, num_seen;
+ bool correct = True;
+
+ printf("starting directory test\n");
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ cli_sockopt(cli, sockops);
+
+ cli_list(cli, "\\LISTDIR\\*", 0, del_fn, cli);
+ cli_list(cli, "\\LISTDIR\\*", aDIR, del_fn, cli);
+ cli_rmdir(cli, "\\LISTDIR");
+ cli_mkdir(cli, "\\LISTDIR");
+
+ /* Create 1000 files and 1000 directories. */
+ for (i=0;i<1000;i++) {
+ fstring fname;
+ slprintf(fname, sizeof(fname), "\\LISTDIR\\f%d", i);
+ fnum = cli_nt_create_full(cli, fname, 0, GENERIC_ALL_ACCESS, FILE_ATTRIBUTE_ARCHIVE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OVERWRITE_IF, 0, 0);
+ if (fnum == -1) {
+ fprintf(stderr,"Failed to open %s\n", fname);
+ return False;
+ }
+ cli_close(cli, fnum);
+ }
+ for (i=0;i<1000;i++) {
+ fstring fname;
+ slprintf(fname, sizeof(fname), "\\LISTDIR\\d%d", i);
+ if (!cli_mkdir(cli, fname)) {
+ fprintf(stderr,"Failed to open %s\n", fname);
+ return False;
+ }
+ }
+
+ /* Now ensure that doing an old list sees both files and directories. */
+ num_seen = cli_list_old(cli, "\\LISTDIR\\*", aDIR, list_fn, NULL);
+ printf("num_seen = %d\n", num_seen );
+ /* We should see 100 files + 1000 directories + . and .. */
+ if (num_seen != 2002)
+ correct = False;
+
+ /* Ensure if we have the "must have" bits we only see the
+ * relevent entries.
+ */
+ num_seen = cli_list_old(cli, "\\LISTDIR\\*", (aDIR<<8)|aDIR, list_fn, NULL);
+ printf("num_seen = %d\n", num_seen );
+ if (num_seen != 1002)
+ correct = False;
+
+ num_seen = cli_list_old(cli, "\\LISTDIR\\*", (aARCH<<8)|aDIR, list_fn, NULL);
+ printf("num_seen = %d\n", num_seen );
+ if (num_seen != 1000)
+ correct = False;
+
+ /* Delete everything. */
+ cli_list(cli, "\\LISTDIR\\*", 0, del_fn, cli);
+ cli_list(cli, "\\LISTDIR\\*", aDIR, del_fn, cli);
+ cli_rmdir(cli, "\\LISTDIR");
+
+#if 0
+ printf("Matched %d\n", cli_list(cli, "a*.*", 0, list_fn, NULL));
+ printf("Matched %d\n", cli_list(cli, "b*.*", 0, list_fn, NULL));
+ printf("Matched %d\n", cli_list(cli, "xyzabc", 0, list_fn, NULL));
+#endif
+
+ if (!torture_close_connection(cli)) {
+ correct = False;
+ }
+
+ printf("finished dirtest1\n");
+
+ return correct;
+}
+
+static bool run_error_map_extract(int dummy) {
+
+ static struct cli_state *c_dos;
+ static struct cli_state *c_nt;
+
+ uint32 error;
+
+ uint32 flgs2, errnum;
+ uint8 errclass;
+
+ NTSTATUS nt_status;
+
+ fstring user;
+
+ /* NT-Error connection */
+
+ if (!(c_nt = open_nbt_connection())) {
+ return False;
+ }
+
+ c_nt->use_spnego = False;
+
+ if (!cli_negprot(c_nt)) {
+ printf("%s rejected the NT-error negprot (%s)\n",host, cli_errstr(c_nt));
+ cli_shutdown(c_nt);
+ return False;
+ }
+
+ if (!NT_STATUS_IS_OK(cli_session_setup(c_nt, "", "", 0, "", 0,
+ workgroup))) {
+ printf("%s rejected the NT-error initial session setup (%s)\n",host, cli_errstr(c_nt));
+ return False;
+ }
+
+ /* DOS-Error connection */
+
+ if (!(c_dos = open_nbt_connection())) {
+ return False;
+ }
+
+ c_dos->use_spnego = False;
+ c_dos->force_dos_errors = True;
+
+ if (!cli_negprot(c_dos)) {
+ printf("%s rejected the DOS-error negprot (%s)\n",host, cli_errstr(c_dos));
+ cli_shutdown(c_dos);
+ return False;
+ }
+
+ if (!NT_STATUS_IS_OK(cli_session_setup(c_dos, "", "", 0, "", 0,
+ workgroup))) {
+ printf("%s rejected the DOS-error initial session setup (%s)\n",host, cli_errstr(c_dos));
+ return False;
+ }
+
+ for (error=(0xc0000000 | 0x1); error < (0xc0000000| 0xFFF); error++) {
+ fstr_sprintf(user, "%X", error);
+
+ if (NT_STATUS_IS_OK(cli_session_setup(c_nt, user,
+ password, strlen(password),
+ password, strlen(password),
+ workgroup))) {
+ printf("/** Session setup succeeded. This shouldn't happen...*/\n");
+ }
+
+ flgs2 = SVAL(c_nt->inbuf,smb_flg2);
+
+ /* Case #1: 32-bit NT errors */
+ if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
+ nt_status = NT_STATUS(IVAL(c_nt->inbuf,smb_rcls));
+ } else {
+ printf("/** Dos error on NT connection! (%s) */\n",
+ cli_errstr(c_nt));
+ nt_status = NT_STATUS(0xc0000000);
+ }
+
+ if (NT_STATUS_IS_OK(cli_session_setup(c_dos, user,
+ password, strlen(password),
+ password, strlen(password),
+ workgroup))) {
+ printf("/** Session setup succeeded. This shouldn't happen...*/\n");
+ }
+ flgs2 = SVAL(c_dos->inbuf,smb_flg2), errnum;
+
+ /* Case #1: 32-bit NT errors */
+ if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
+ printf("/** NT error on DOS connection! (%s) */\n",
+ cli_errstr(c_nt));
+ errnum = errclass = 0;
+ } else {
+ cli_dos_error(c_dos, &errclass, &errnum);
+ }
+
+ if (NT_STATUS_V(nt_status) != error) {
+ printf("/*\t{ This NT error code was 'sqashed'\n\t from %s to %s \n\t during the session setup }\n*/\n",
+ get_nt_error_c_code(NT_STATUS(error)),
+ get_nt_error_c_code(nt_status));
+ }
+
+ printf("\t{%s,\t%s,\t%s},\n",
+ smb_dos_err_class(errclass),
+ smb_dos_err_name(errclass, errnum),
+ get_nt_error_c_code(NT_STATUS(error)));
+ }
+ return True;
+}
+
+static bool run_sesssetup_bench(int dummy)
+{
+ static struct cli_state *c;
+ NTSTATUS status;
+ int i;
+
+ if (!(c = open_nbt_connection())) {
+ return false;
+ }
+
+ if (!cli_negprot(c)) {
+ printf("%s rejected the NT-error negprot (%s)\n", host,
+ cli_errstr(c));
+ cli_shutdown(c);
+ return false;
+ }
+
+ for (i=0; i<torture_numops; i++) {
+ status = cli_session_setup(
+ c, username,
+ password, strlen(password),
+ password, strlen(password),
+ workgroup);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("(%s) cli_session_setup failed: %s\n",
+ __location__, nt_errstr(status));
+ return false;
+ }
+
+ if (!cli_ulogoff(c)) {
+ d_printf("(%s) cli_ulogoff failed: %s\n",
+ __location__, cli_errstr(c));
+ return false;
+ }
+ c->vuid = 0;
+ }
+
+ return true;
+}
+
+static bool subst_test(const char *str, const char *user, const char *domain,
+ uid_t uid, gid_t gid, const char *expected)
+{
+ char *subst;
+ bool result = true;
+
+ subst = talloc_sub_specified(talloc_tos(), str, user, domain, uid, gid);
+
+ if (strcmp(subst, expected) != 0) {
+ printf("sub_specified(%s, %s, %s, %d, %d) returned [%s], expected "
+ "[%s]\n", str, user, domain, (int)uid, (int)gid, subst,
+ expected);
+ result = false;
+ }
+
+ TALLOC_FREE(subst);
+ return result;
+}
+
+static void chain1_open_completion(struct async_req *req)
+{
+ int fnum;
+ NTSTATUS status;
+
+ status = cli_open_recv(req, &fnum);
+ TALLOC_FREE(req);
+
+ d_printf("cli_open_recv returned %s: %d\n",
+ nt_errstr(status),
+ NT_STATUS_IS_OK(status) ? fnum : -1);
+}
+
+static void chain1_read_completion(struct async_req *req)
+{
+ NTSTATUS status;
+ ssize_t received;
+ uint8_t *rcvbuf;
+
+ status = cli_read_andx_recv(req, &received, &rcvbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(req);
+ d_printf("cli_read_andx_recv returned %s\n",
+ nt_errstr(status));
+ return;
+ }
+
+ d_printf("got %d bytes: %.*s\n", (int)received, (int)received,
+ (char *)rcvbuf);
+ TALLOC_FREE(req);
+}
+
+static void chain1_close_completion(struct async_req *req)
+{
+ NTSTATUS status;
+
+ status = cli_close_recv(req);
+ *((bool *)(req->async.priv)) = true;
+
+ TALLOC_FREE(req);
+
+ d_printf("cli_close returned %s\n", nt_errstr(status));
+}
+
+static bool run_chain1(int dummy)
+{
+ struct cli_state *cli1;
+ struct event_context *evt = event_context_init(NULL);
+ struct async_req *reqs[4];
+ bool done = false;
+
+ printf("starting chain1 test\n");
+ if (!torture_open_connection(&cli1, 0)) {
+ return False;
+ }
+
+ cli_sockopt(cli1, sockops);
+
+ cli_chain_cork(cli1, evt, 0);
+ reqs[0] = cli_open_send(talloc_tos(), evt, cli1, "\\test",
+ O_CREAT|O_RDWR, 0);
+ reqs[0]->async.fn = chain1_open_completion;
+ reqs[1] = cli_read_andx_send(talloc_tos(), evt, cli1, 0, 0, 10);
+ reqs[1]->async.fn = chain1_read_completion;
+ reqs[2] = cli_read_andx_send(talloc_tos(), evt, cli1, 0, 1, 10);
+ reqs[2]->async.fn = chain1_read_completion;
+ reqs[3] = cli_close_send(talloc_tos(), evt, cli1, 0);
+ reqs[3]->async.fn = chain1_close_completion;
+ reqs[3]->async.priv = (void *)&done;
+ cli_chain_uncork(cli1);
+
+ while (!done) {
+ event_loop_once(evt);
+ }
+
+ torture_close_connection(cli1);
+ return True;
+}
+
+static bool run_cli_echo(int dummy)
+{
+ struct cli_state *cli;
+ struct event_context *ev = event_context_init(NULL);
+ struct async_req *req;
+ NTSTATUS status;
+
+ printf("starting chain1 test\n");
+ if (!torture_open_connection(&cli, 0)) {
+ return false;
+ }
+ cli_sockopt(cli, sockops);
+
+ req = cli_echo_send(ev, ev, cli, 5, data_blob_const("hello", 5));
+ if (req == NULL) {
+ d_printf("cli_echo_send failed\n");
+ return false;
+ }
+
+ while (req->state < ASYNC_REQ_DONE) {
+ event_loop_once(ev);
+ }
+
+ status = cli_echo_recv(req);
+ d_printf("cli_echo returned %s\n", nt_errstr(status));
+
+ TALLOC_FREE(req);
+
+ torture_close_connection(cli);
+ return NT_STATUS_IS_OK(status);
+}
+
+static bool run_local_substitute(int dummy)
+{
+ bool ok = true;
+
+ ok &= subst_test("%U", "bla", "", -1, -1, "bla");
+ ok &= subst_test("%u%U", "bla", "", -1, -1, "blabla");
+ ok &= subst_test("%g", "", "", -1, -1, "NO_GROUP");
+ ok &= subst_test("%G", "", "", -1, -1, "NO_GROUP");
+ ok &= subst_test("%g", "", "", -1, 0, gidtoname(0));
+ ok &= subst_test("%G", "", "", -1, 0, gidtoname(0));
+ ok &= subst_test("%D%u", "u", "dom", -1, 0, "domu");
+ ok &= subst_test("%i %I", "", "", -1, -1, "0.0.0.0 0.0.0.0");
+
+ /* Different captialization rules in sub_basic... */
+
+ ok &= (strcmp(talloc_sub_basic(talloc_tos(), "BLA", "dom", "%U%D"),
+ "blaDOM") == 0);
+
+ return ok;
+}
+
+static bool run_local_gencache(int dummy)
+{
+ char *val;
+ time_t tm;
+ DATA_BLOB blob;
+
+ if (!gencache_init()) {
+ d_printf("%s: gencache_init() failed\n", __location__);
+ return False;
+ }
+
+ if (!gencache_set("foo", "bar", time(NULL) + 1000)) {
+ d_printf("%s: gencache_set() failed\n", __location__);
+ return False;
+ }
+
+ if (!gencache_get("foo", &val, &tm)) {
+ d_printf("%s: gencache_get() failed\n", __location__);
+ return False;
+ }
+
+ if (strcmp(val, "bar") != 0) {
+ d_printf("%s: gencache_get() returned %s, expected %s\n",
+ __location__, val, "bar");
+ SAFE_FREE(val);
+ return False;
+ }
+
+ SAFE_FREE(val);
+
+ if (!gencache_del("foo")) {
+ d_printf("%s: gencache_del() failed\n", __location__);
+ return False;
+ }
+ if (gencache_del("foo")) {
+ d_printf("%s: second gencache_del() succeeded\n",
+ __location__);
+ return False;
+ }
+
+ if (gencache_get("foo", &val, &tm)) {
+ d_printf("%s: gencache_get() on deleted entry "
+ "succeeded\n", __location__);
+ return False;
+ }
+
+ blob = data_blob_string_const("bar");
+ tm = time(NULL);
+
+ if (!gencache_set_data_blob("foo", &blob, tm)) {
+ d_printf("%s: gencache_set_data_blob() failed\n", __location__);
+ return False;
+ }
+
+ data_blob_free(&blob);
+
+ if (!gencache_get_data_blob("foo", &blob, NULL)) {
+ d_printf("%s: gencache_get_data_blob() failed\n", __location__);
+ return False;
+ }
+
+ if (strcmp((const char *)blob.data, "bar") != 0) {
+ d_printf("%s: gencache_get_data_blob() returned %s, expected %s\n",
+ __location__, (const char *)blob.data, "bar");
+ data_blob_free(&blob);
+ return False;
+ }
+
+ data_blob_free(&blob);
+
+ if (!gencache_del("foo")) {
+ d_printf("%s: gencache_del() failed\n", __location__);
+ return False;
+ }
+ if (gencache_del("foo")) {
+ d_printf("%s: second gencache_del() succeeded\n",
+ __location__);
+ return False;
+ }
+
+ if (gencache_get_data_blob("foo", &blob, NULL)) {
+ d_printf("%s: gencache_get_data_blob() on deleted entry "
+ "succeeded\n", __location__);
+ return False;
+ }
+
+ if (!gencache_shutdown()) {
+ d_printf("%s: gencache_shutdown() failed\n", __location__);
+ return False;
+ }
+
+ if (gencache_shutdown()) {
+ d_printf("%s: second gencache_shutdown() succeeded\n",
+ __location__);
+ return False;
+ }
+
+ return True;
+}
+
+static bool rbt_testval(struct db_context *db, const char *key,
+ const char *value)
+{
+ struct db_record *rec;
+ TDB_DATA data = string_tdb_data(value);
+ bool ret = false;
+ NTSTATUS status;
+
+ rec = db->fetch_locked(db, db, string_tdb_data(key));
+ if (rec == NULL) {
+ d_fprintf(stderr, "fetch_locked failed\n");
+ goto done;
+ }
+ status = rec->store(rec, data, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "store failed: %s\n", nt_errstr(status));
+ goto done;
+ }
+ TALLOC_FREE(rec);
+
+ rec = db->fetch_locked(db, db, string_tdb_data(key));
+ if (rec == NULL) {
+ d_fprintf(stderr, "second fetch_locked failed\n");
+ goto done;
+ }
+ if ((rec->value.dsize != data.dsize)
+ || (memcmp(rec->value.dptr, data.dptr, data.dsize) != 0)) {
+ d_fprintf(stderr, "Got wrong data back\n");
+ goto done;
+ }
+
+ ret = true;
+ done:
+ TALLOC_FREE(rec);
+ return ret;
+}
+
+static bool run_local_rbtree(int dummy)
+{
+ struct db_context *db;
+ bool ret = false;
+ int i;
+
+ db = db_open_rbt(NULL);
+
+ if (db == NULL) {
+ d_fprintf(stderr, "db_open_rbt failed\n");
+ return false;
+ }
+
+ for (i=0; i<1000; i++) {
+ char *key, *value;
+
+ asprintf(&key, "key%ld", random());
+ asprintf(&value, "value%ld", random());
+
+ if (!rbt_testval(db, key, value)) {
+ SAFE_FREE(key);
+ SAFE_FREE(value);
+ goto done;
+ }
+
+ SAFE_FREE(value);
+ asprintf(&value, "value%ld", random());
+
+ if (!rbt_testval(db, key, value)) {
+ SAFE_FREE(key);
+ SAFE_FREE(value);
+ goto done;
+ }
+
+ SAFE_FREE(key);
+ SAFE_FREE(value);
+ }
+
+ ret = true;
+
+ done:
+ TALLOC_FREE(db);
+ return ret;
+}
+
+static bool test_stream_name(const char *fname, const char *expected_base,
+ const char *expected_stream,
+ NTSTATUS expected_status)
+{
+ NTSTATUS status;
+ char *base = NULL;
+ char *stream = NULL;
+
+ status = split_ntfs_stream_name(talloc_tos(), fname, &base, &stream);
+ if (!NT_STATUS_EQUAL(status, expected_status)) {
+ goto error;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return true;
+ }
+
+ if (base == NULL) goto error;
+
+ if (strcmp(expected_base, base) != 0) goto error;
+
+ if ((expected_stream != NULL) && (stream == NULL)) goto error;
+ if ((expected_stream == NULL) && (stream != NULL)) goto error;
+
+ if ((stream != NULL) && (strcmp(expected_stream, stream) != 0))
+ goto error;
+
+ TALLOC_FREE(base);
+ TALLOC_FREE(stream);
+ return true;
+
+ error:
+ d_fprintf(stderr, "test_stream(%s, %s, %s, %s)\n",
+ fname, expected_base ? expected_base : "<NULL>",
+ expected_stream ? expected_stream : "<NULL>",
+ nt_errstr(expected_status));
+ d_fprintf(stderr, "-> base=%s, stream=%s, status=%s\n",
+ base ? base : "<NULL>", stream ? stream : "<NULL>",
+ nt_errstr(status));
+ TALLOC_FREE(base);
+ TALLOC_FREE(stream);
+ return false;
+}
+
+static bool run_local_stream_name(int dummy)
+{
+ bool ret = true;
+
+ ret &= test_stream_name(
+ "bla", "bla", NULL, NT_STATUS_OK);
+ ret &= test_stream_name(
+ "bla::$DATA", "bla", NULL, NT_STATUS_OK);
+ ret &= test_stream_name(
+ "bla:blub:", "bla", NULL, NT_STATUS_OBJECT_NAME_INVALID);
+ ret &= test_stream_name(
+ "bla::", NULL, NULL, NT_STATUS_OBJECT_NAME_INVALID);
+ ret &= test_stream_name(
+ "bla::123", "bla", NULL, NT_STATUS_OBJECT_NAME_INVALID);
+ ret &= test_stream_name(
+ "bla:$DATA", "bla", "$DATA:$DATA", NT_STATUS_OK);
+ ret &= test_stream_name(
+ "bla:x:$DATA", "bla", "x:$DATA", NT_STATUS_OK);
+ ret &= test_stream_name(
+ "bla:x", "bla", "x:$DATA", NT_STATUS_OK);
+
+ return ret;
+}
+
+static bool data_blob_equal(DATA_BLOB a, DATA_BLOB b)
+{
+ if (a.length != b.length) {
+ printf("a.length=%d != b.length=%d\n",
+ (int)a.length, (int)b.length);
+ return false;
+ }
+ if (memcmp(a.data, b.data, a.length) != 0) {
+ printf("a.data and b.data differ\n");
+ return false;
+ }
+ return true;
+}
+
+static bool run_local_memcache(int dummy)
+{
+ struct memcache *cache;
+ DATA_BLOB k1, k2;
+ DATA_BLOB d1, d2, d3;
+ DATA_BLOB v1, v2, v3;
+
+ cache = memcache_init(NULL, 100);
+
+ if (cache == NULL) {
+ printf("memcache_init failed\n");
+ return false;
+ }
+
+ d1 = data_blob_const("d1", 2);
+ d2 = data_blob_const("d2", 2);
+ d3 = data_blob_const("d3", 2);
+
+ k1 = data_blob_const("d1", 2);
+ k2 = data_blob_const("d2", 2);
+
+ memcache_add(cache, STAT_CACHE, k1, d1);
+ memcache_add(cache, GETWD_CACHE, k2, d2);
+
+ if (!memcache_lookup(cache, STAT_CACHE, k1, &v1)) {
+ printf("could not find k1\n");
+ return false;
+ }
+ if (!data_blob_equal(d1, v1)) {
+ return false;
+ }
+
+ if (!memcache_lookup(cache, GETWD_CACHE, k2, &v2)) {
+ printf("could not find k2\n");
+ return false;
+ }
+ if (!data_blob_equal(d2, v2)) {
+ return false;
+ }
+
+ memcache_add(cache, STAT_CACHE, k1, d3);
+
+ if (!memcache_lookup(cache, STAT_CACHE, k1, &v3)) {
+ printf("could not find replaced k1\n");
+ return false;
+ }
+ if (!data_blob_equal(d3, v3)) {
+ return false;
+ }
+
+ memcache_add(cache, GETWD_CACHE, k1, d1);
+
+ if (memcache_lookup(cache, GETWD_CACHE, k2, &v2)) {
+ printf("Did find k2, should have been purged\n");
+ return false;
+ }
+
+ TALLOC_FREE(cache);
+ return true;
+}
+
+static double create_procs(bool (*fn)(int), bool *result)
+{
+ int i, status;
+ volatile pid_t *child_status;
+ volatile bool *child_status_out;
+ int synccount;
+ int tries = 8;
+
+ synccount = 0;
+
+ child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*nprocs);
+ if (!child_status) {
+ printf("Failed to setup shared memory\n");
+ return -1;
+ }
+
+ child_status_out = (volatile bool *)shm_setup(sizeof(bool)*nprocs);
+ if (!child_status_out) {
+ printf("Failed to setup result status shared memory\n");
+ return -1;
+ }
+
+ for (i = 0; i < nprocs; i++) {
+ child_status[i] = 0;
+ child_status_out[i] = True;
+ }
+
+ start_timer();
+
+ for (i=0;i<nprocs;i++) {
+ procnum = i;
+ if (fork() == 0) {
+ pid_t mypid = getpid();
+ sys_srandom(((int)mypid) ^ ((int)time(NULL)));
+
+ slprintf(myname,sizeof(myname),"CLIENT%d", i);
+
+ while (1) {
+ if (torture_open_connection(&current_cli, i)) break;
+ if (tries-- == 0) {
+ printf("pid %d failed to start\n", (int)getpid());
+ _exit(1);
+ }
+ smb_msleep(10);
+ }
+
+ child_status[i] = getpid();
+
+ while (child_status[i] && end_timer() < 5) smb_msleep(2);
+
+ child_status_out[i] = fn(i);
+ _exit(0);
+ }
+ }
+
+ do {
+ synccount = 0;
+ for (i=0;i<nprocs;i++) {
+ if (child_status[i]) synccount++;
+ }
+ if (synccount == nprocs) break;
+ smb_msleep(10);
+ } while (end_timer() < 30);
+
+ if (synccount != nprocs) {
+ printf("FAILED TO START %d CLIENTS (started %d)\n", nprocs, synccount);
+ *result = False;
+ return end_timer();
+ }
+
+ /* start the client load */
+ start_timer();
+
+ for (i=0;i<nprocs;i++) {
+ child_status[i] = 0;
+ }
+
+ printf("%d clients started\n", nprocs);
+
+ for (i=0;i<nprocs;i++) {
+ while (waitpid(0, &status, 0) == -1 && errno == EINTR) /* noop */ ;
+ }
+
+ printf("\n");
+
+ for (i=0;i<nprocs;i++) {
+ if (!child_status_out[i]) {
+ *result = False;
+ }
+ }
+ return end_timer();
+}
+
+#define FLAG_MULTIPROC 1
+
+static struct {
+ const char *name;
+ bool (*fn)(int);
+ unsigned flags;
+} torture_ops[] = {
+ {"FDPASS", run_fdpasstest, 0},
+ {"LOCK1", run_locktest1, 0},
+ {"LOCK2", run_locktest2, 0},
+ {"LOCK3", run_locktest3, 0},
+ {"LOCK4", run_locktest4, 0},
+ {"LOCK5", run_locktest5, 0},
+ {"LOCK6", run_locktest6, 0},
+ {"LOCK7", run_locktest7, 0},
+ {"UNLINK", run_unlinktest, 0},
+ {"BROWSE", run_browsetest, 0},
+ {"ATTR", run_attrtest, 0},
+ {"TRANS2", run_trans2test, 0},
+ {"MAXFID", run_maxfidtest, FLAG_MULTIPROC},
+ {"TORTURE",run_torture, FLAG_MULTIPROC},
+ {"RANDOMIPC", run_randomipc, 0},
+ {"NEGNOWAIT", run_negprot_nowait, 0},
+ {"NBENCH", run_nbench, 0},
+ {"OPLOCK1", run_oplock1, 0},
+ {"OPLOCK2", run_oplock2, 0},
+ {"OPLOCK3", run_oplock3, 0},
+ {"DIR", run_dirtest, 0},
+ {"DIR1", run_dirtest1, 0},
+ {"DENY1", torture_denytest1, 0},
+ {"DENY2", torture_denytest2, 0},
+ {"TCON", run_tcon_test, 0},
+ {"TCONDEV", run_tcon_devtype_test, 0},
+ {"RW1", run_readwritetest, 0},
+ {"RW2", run_readwritemulti, FLAG_MULTIPROC},
+ {"RW3", run_readwritelarge, 0},
+ {"OPEN", run_opentest, 0},
+#if 1
+ {"OPENATTR", run_openattrtest, 0},
+#endif
+ {"XCOPY", run_xcopy, 0},
+ {"RENAME", run_rename, 0},
+ {"DELETE", run_deletetest, 0},
+ {"PROPERTIES", run_properties, 0},
+ {"MANGLE", torture_mangle, 0},
+ {"W2K", run_w2ktest, 0},
+ {"TRANS2SCAN", torture_trans2_scan, 0},
+ {"NTTRANSSCAN", torture_nttrans_scan, 0},
+ {"UTABLE", torture_utable, 0},
+ {"CASETABLE", torture_casetable, 0},
+ {"ERRMAPEXTRACT", run_error_map_extract, 0},
+ {"PIPE_NUMBER", run_pipe_number, 0},
+ {"TCON2", run_tcon2_test, 0},
+ {"IOCTL", torture_ioctl_test, 0},
+ {"CHKPATH", torture_chkpath_test, 0},
+ {"FDSESS", run_fdsesstest, 0},
+ { "EATEST", run_eatest, 0},
+ { "SESSSETUP_BENCH", run_sesssetup_bench, 0},
+ { "CHAIN1", run_chain1, 0},
+ { "CLI_ECHO", run_cli_echo, 0},
+ { "LOCAL-SUBSTITUTE", run_local_substitute, 0},
+ { "LOCAL-GENCACHE", run_local_gencache, 0},
+ { "LOCAL-RBTREE", run_local_rbtree, 0},
+ { "LOCAL-MEMCACHE", run_local_memcache, 0},
+ { "LOCAL-STREAM-NAME", run_local_stream_name, 0},
+ {NULL, NULL, 0}};
+
+
+
+/****************************************************************************
+run a specified test or "ALL"
+****************************************************************************/
+static bool run_test(const char *name)
+{
+ bool ret = True;
+ bool result = True;
+ bool found = False;
+ int i;
+ double t;
+ if (strequal(name,"ALL")) {
+ for (i=0;torture_ops[i].name;i++) {
+ run_test(torture_ops[i].name);
+ }
+ found = True;
+ }
+
+ for (i=0;torture_ops[i].name;i++) {
+ fstr_sprintf(randomfname, "\\XX%x",
+ (unsigned)random());
+
+ if (strequal(name, torture_ops[i].name)) {
+ found = True;
+ printf("Running %s\n", name);
+ if (torture_ops[i].flags & FLAG_MULTIPROC) {
+ t = create_procs(torture_ops[i].fn, &result);
+ if (!result) {
+ ret = False;
+ printf("TEST %s FAILED!\n", name);
+ }
+
+ } else {
+ start_timer();
+ if (!torture_ops[i].fn(0)) {
+ ret = False;
+ printf("TEST %s FAILED!\n", name);
+ }
+ t = end_timer();
+ }
+ printf("%s took %g secs\n\n", name, t);
+ }
+ }
+
+ if (!found) {
+ printf("Did not find a test named %s\n", name);
+ ret = False;
+ }
+
+ return ret;
+}
+
+
+static void usage(void)
+{
+ int i;
+
+ printf("WARNING samba4 test suite is much more complete nowadays.\n");
+ printf("Please use samba4 torture.\n\n");
+
+ printf("Usage: smbtorture //server/share <options> TEST1 TEST2 ...\n");
+
+ printf("\t-d debuglevel\n");
+ printf("\t-U user%%pass\n");
+ printf("\t-k use kerberos\n");
+ printf("\t-N numprocs\n");
+ printf("\t-n my_netbios_name\n");
+ printf("\t-W workgroup\n");
+ printf("\t-o num_operations\n");
+ printf("\t-O socket_options\n");
+ printf("\t-m maximum protocol\n");
+ printf("\t-L use oplocks\n");
+ printf("\t-c CLIENT.TXT specify client load file for NBENCH\n");
+ printf("\t-A showall\n");
+ printf("\t-p port\n");
+ printf("\t-s seed\n");
+ printf("\t-b unclist_filename specify multiple shares for multiple connections\n");
+ printf("\n\n");
+
+ printf("tests are:");
+ for (i=0;torture_ops[i].name;i++) {
+ printf(" %s", torture_ops[i].name);
+ }
+ printf("\n");
+
+ printf("default test is ALL\n");
+
+ exit(1);
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ int opt, i;
+ char *p;
+ int gotuser = 0;
+ int gotpass = 0;
+ bool correct = True;
+ TALLOC_CTX *frame = talloc_stackframe();
+ int seed = time(NULL);
+
+ dbf = x_stdout;
+
+#ifdef HAVE_SETBUFFER
+ setbuffer(stdout, NULL, 0);
+#endif
+
+ load_case_tables();
+
+ lp_load(get_dyn_CONFIGFILE(),True,False,False,True);
+ load_interfaces();
+
+ if (argc < 2) {
+ usage();
+ }
+
+ for(p = argv[1]; *p; p++)
+ if(*p == '\\')
+ *p = '/';
+
+ if (strncmp(argv[1], "//", 2)) {
+ usage();
+ }
+
+ fstrcpy(host, &argv[1][2]);
+ p = strchr_m(&host[2],'/');
+ if (!p) {
+ usage();
+ }
+ *p = 0;
+ fstrcpy(share, p+1);
+
+ fstrcpy(myname, get_myname(talloc_tos()));
+ if (!*myname) {
+ fprintf(stderr, "Failed to get my hostname.\n");
+ return 1;
+ }
+
+ if (*username == 0 && getenv("LOGNAME")) {
+ fstrcpy(username,getenv("LOGNAME"));
+ }
+
+ argc--;
+ argv++;
+
+ fstrcpy(workgroup, lp_workgroup());
+
+ while ((opt = getopt(argc, argv, "p:hW:U:n:N:O:o:m:Ld:Aec:ks:b:")) != EOF) {
+ switch (opt) {
+ case 'p':
+ port_to_use = atoi(optarg);
+ break;
+ case 's':
+ seed = atoi(optarg);
+ break;
+ case 'W':
+ fstrcpy(workgroup,optarg);
+ break;
+ case 'm':
+ max_protocol = interpret_protocol(optarg, max_protocol);
+ break;
+ case 'N':
+ nprocs = atoi(optarg);
+ break;
+ case 'o':
+ torture_numops = atoi(optarg);
+ break;
+ case 'd':
+ DEBUGLEVEL = atoi(optarg);
+ break;
+ case 'O':
+ sockops = optarg;
+ break;
+ case 'L':
+ use_oplocks = True;
+ break;
+ case 'A':
+ torture_showall = True;
+ break;
+ case 'n':
+ fstrcpy(myname, optarg);
+ break;
+ case 'c':
+ client_txt = optarg;
+ break;
+ case 'e':
+ do_encrypt = true;
+ break;
+ case 'k':
+#ifdef HAVE_KRB5
+ use_kerberos = True;
+#else
+ d_printf("No kerberos support compiled in\n");
+ exit(1);
+#endif
+ break;
+ case 'U':
+ gotuser = 1;
+ fstrcpy(username,optarg);
+ p = strchr_m(username,'%');
+ if (p) {
+ *p = 0;
+ fstrcpy(password, p+1);
+ gotpass = 1;
+ }
+ break;
+ case 'b':
+ fstrcpy(multishare_conn_fname, optarg);
+ use_multishare_conn = True;
+ break;
+ default:
+ printf("Unknown option %c (%d)\n", (char)opt, opt);
+ usage();
+ }
+ }
+
+ d_printf("using seed %d\n", seed);
+
+ srandom(seed);
+
+ if(use_kerberos && !gotuser) gotpass = True;
+
+ while (!gotpass) {
+ p = getpass("Password:");
+ if (p) {
+ fstrcpy(password, p);
+ gotpass = 1;
+ }
+ }
+
+ printf("host=%s share=%s user=%s myname=%s\n",
+ host, share, username, myname);
+
+ if (argc == optind) {
+ correct = run_test("ALL");
+ } else {
+ for (i=optind;i<argc;i++) {
+ if (!run_test(argv[i])) {
+ correct = False;
+ }
+ }
+ }
+
+ TALLOC_FREE(frame);
+
+ if (correct) {
+ return(0);
+ } else {
+ return(1);
+ }
+}
diff --git a/source3/torture/utable.c b/source3/torture/utable.c
new file mode 100644
index 0000000000..7032cea99b
--- /dev/null
+++ b/source3/torture/utable.c
@@ -0,0 +1,190 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester - unicode table dumper
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+bool torture_utable(int dummy)
+{
+ struct cli_state *cli;
+ fstring fname, alt_name;
+ int fnum;
+ smb_ucs2_t c2;
+ int c, len, fd;
+ int chars_allowed=0, alt_allowed=0;
+ uint8 valid[0x10000];
+
+ printf("starting utable\n");
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ memset(valid, 0, sizeof(valid));
+
+ cli_mkdir(cli, "\\utable");
+ cli_unlink(cli, "\\utable\\*");
+
+ for (c=1; c < 0x10000; c++) {
+ char *p;
+
+ SSVAL(&c2, 0, c);
+ fstrcpy(fname, "\\utable\\x");
+ p = fname+strlen(fname);
+ len = convert_string(CH_UTF16LE, CH_UNIX,
+ &c2, 2,
+ p, sizeof(fname)-strlen(fname), True);
+ p[len] = 0;
+ fstrcat(fname,"_a_long_extension");
+
+ fnum = cli_open(cli, fname, O_RDWR | O_CREAT | O_TRUNC,
+ DENY_NONE);
+ if (fnum == -1) continue;
+
+ chars_allowed++;
+
+ cli_qpathinfo_alt_name(cli, fname, alt_name);
+
+ if (strncmp(alt_name, "X_A_L", 5) != 0) {
+ alt_allowed++;
+ valid[c] = 1;
+ d_printf("fname=[%s] alt_name=[%s]\n", fname, alt_name);
+ }
+
+ cli_close(cli, fnum);
+ cli_unlink(cli, fname);
+
+ if (c % 100 == 0) {
+ printf("%d (%d/%d)\r", c, chars_allowed, alt_allowed);
+ }
+ }
+ printf("%d (%d/%d)\n", c, chars_allowed, alt_allowed);
+
+ cli_rmdir(cli, "\\utable");
+
+ d_printf("%d chars allowed %d alt chars allowed\n", chars_allowed, alt_allowed);
+
+ fd = open("valid.dat", O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (fd == -1) {
+ d_printf("Failed to create valid.dat - %s", strerror(errno));
+ return False;
+ }
+ write(fd, valid, 0x10000);
+ close(fd);
+ d_printf("wrote valid.dat\n");
+
+ return True;
+}
+
+
+static char *form_name(int c)
+{
+ static fstring fname;
+ smb_ucs2_t c2;
+ char *p;
+ int len;
+
+ fstrcpy(fname, "\\utable\\");
+ p = fname+strlen(fname);
+ SSVAL(&c2, 0, c);
+
+ len = convert_string(CH_UTF16LE, CH_UNIX,
+ &c2, 2,
+ p, sizeof(fname)-strlen(fname), True);
+ p[len] = 0;
+ return fname;
+}
+
+bool torture_casetable(int dummy)
+{
+ static struct cli_state *cli;
+ char *fname;
+ int fnum;
+ int c, i;
+#define MAX_EQUIVALENCE 8
+ smb_ucs2_t equiv[0x10000][MAX_EQUIVALENCE];
+ printf("starting casetable\n");
+
+ if (!torture_open_connection(&cli, 0)) {
+ return False;
+ }
+
+ memset(equiv, 0, sizeof(equiv));
+
+ cli_unlink(cli, "\\utable\\*");
+ cli_rmdir(cli, "\\utable");
+ if (!cli_mkdir(cli, "\\utable")) {
+ printf("Failed to create utable directory!\n");
+ return False;
+ }
+
+ for (c=1; c < 0x10000; c++) {
+ SMB_OFF_T size;
+
+ if (c == '.' || c == '\\') continue;
+
+ printf("%04x (%c)\n", c, isprint(c)?c:'.');
+
+ fname = form_name(c);
+ fnum = cli_nt_create_full(cli, fname, 0,
+ GENERIC_ALL_ACCESS,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_NONE,
+ FILE_OPEN_IF, 0, 0);
+
+ if (fnum == -1) {
+ printf("Failed to create file with char %04x\n", c);
+ continue;
+ }
+
+ size = 0;
+
+ if (!cli_qfileinfo(cli, fnum, NULL, &size,
+ NULL, NULL, NULL, NULL, NULL)) continue;
+
+ if (size > 0) {
+ /* found a character equivalence! */
+ int c2[MAX_EQUIVALENCE];
+
+ if (size/sizeof(int) >= MAX_EQUIVALENCE) {
+ printf("too many chars match?? size=%ld c=0x%04x\n",
+ (unsigned long)size, c);
+ cli_close(cli, fnum);
+ return False;
+ }
+
+ cli_read(cli, fnum, (char *)c2, 0, size);
+ printf("%04x: ", c);
+ equiv[c][0] = c;
+ for (i=0; i<size/sizeof(int); i++) {
+ printf("%04x ", c2[i]);
+ equiv[c][i+1] = c2[i];
+ }
+ printf("\n");
+ fflush(stdout);
+ }
+
+ cli_write(cli, fnum, 0, (char *)&c, size, sizeof(c));
+ cli_close(cli, fnum);
+ }
+
+ cli_unlink(cli, "\\utable\\*");
+ cli_rmdir(cli, "\\utable");
+
+ return True;
+}
diff --git a/source3/torture/vfstest.c b/source3/torture/vfstest.c
new file mode 100644
index 0000000000..56e27eec1d
--- /dev/null
+++ b/source3/torture/vfstest.c
@@ -0,0 +1,611 @@
+/*
+ Unix SMB/CIFS implementation.
+ VFS module tester
+
+ Copyright (C) Simo Sorce 2002
+ Copyright (C) Eric Lorimer 2002
+ Copyright (C) Jelmer Vernooij 2002,2003
+
+ Most of this code was ripped off of rpcclient.
+ Copyright (C) Tim Potter 2000-2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "vfstest.h"
+
+/* List to hold groups of commands */
+static struct cmd_list {
+ struct cmd_list *prev, *next;
+ struct cmd_set *cmd_set;
+} *cmd_list;
+
+int get_client_fd(void)
+{
+ return -1;
+}
+
+/****************************************************************************
+handle completion of commands for readline
+****************************************************************************/
+static char **completion_fn(const char *text, int start, int end)
+{
+#define MAX_COMPLETIONS 100
+ char **matches;
+ int i, count=0;
+ struct cmd_list *commands = cmd_list;
+
+ if (start)
+ return NULL;
+
+ /* make sure we have a list of valid commands */
+ if (!commands)
+ return NULL;
+
+ matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS);
+ if (!matches) return NULL;
+
+ matches[count++] = SMB_STRDUP(text);
+ if (!matches[0]) return NULL;
+
+ while (commands && count < MAX_COMPLETIONS-1)
+ {
+ if (!commands->cmd_set)
+ break;
+
+ for (i=0; commands->cmd_set[i].name; i++)
+ {
+ if ((strncmp(text, commands->cmd_set[i].name, strlen(text)) == 0) &&
+ commands->cmd_set[i].fn)
+ {
+ matches[count] = SMB_STRDUP(commands->cmd_set[i].name);
+ if (!matches[count])
+ return NULL;
+ count++;
+ }
+ }
+
+ commands = commands->next;
+
+ }
+
+ if (count == 2) {
+ SAFE_FREE(matches[0]);
+ matches[0] = SMB_STRDUP(matches[1]);
+ }
+ matches[count] = NULL;
+ return matches;
+}
+
+static char *next_command(TALLOC_CTX *ctx, char **cmdstr)
+{
+ char *command;
+ char *p;
+
+ if (!cmdstr || !(*cmdstr))
+ return NULL;
+
+ p = strchr_m(*cmdstr, ';');
+ if (p)
+ *p = '\0';
+ command = talloc_strdup(ctx, *cmdstr);
+ *cmdstr = p;
+
+ return command;
+}
+
+/* Load specified configuration file */
+static NTSTATUS cmd_conf(struct vfs_state *vfs, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ if (argc != 2) {
+ printf("Usage: %s <smb.conf>\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (!lp_load(argv[1], False, True, False, True)) {
+ printf("Error loading \"%s\"\n", argv[1]);
+ return NT_STATUS_OK;
+ }
+
+ printf("\"%s\" successfully loaded\n", argv[1]);
+ return NT_STATUS_OK;
+}
+
+/* Display help on commands */
+static NTSTATUS cmd_help(struct vfs_state *vfs, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ struct cmd_list *tmp;
+ struct cmd_set *tmp_set;
+
+ /* Usage */
+ if (argc > 2) {
+ printf("Usage: %s [command]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ /* Help on one command */
+
+ if (argc == 2) {
+ for (tmp = cmd_list; tmp; tmp = tmp->next) {
+
+ tmp_set = tmp->cmd_set;
+
+ while(tmp_set->name) {
+ if (strequal(argv[1], tmp_set->name)) {
+ if (tmp_set->usage &&
+ tmp_set->usage[0])
+ printf("%s\n", tmp_set->usage);
+ else
+ printf("No help for %s\n", tmp_set->name);
+
+ return NT_STATUS_OK;
+ }
+
+ tmp_set++;
+ }
+ }
+
+ printf("No such command: %s\n", argv[1]);
+ return NT_STATUS_OK;
+ }
+
+ /* List all commands */
+
+ for (tmp = cmd_list; tmp; tmp = tmp->next) {
+
+ tmp_set = tmp->cmd_set;
+
+ while(tmp_set->name) {
+
+ printf("%15s\t\t%s\n", tmp_set->name,
+ tmp_set->description ? tmp_set->description:
+ "");
+
+ tmp_set++;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/* Change the debug level */
+static NTSTATUS cmd_debuglevel(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ if (argc > 2) {
+ printf("Usage: %s [debuglevel]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2) {
+ DEBUGLEVEL = atoi(argv[1]);
+ }
+
+ printf("debuglevel is %d\n", DEBUGLEVEL);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_freemem(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ /* Cleanup */
+ talloc_destroy(mem_ctx);
+ mem_ctx = NULL;
+ vfs->data = NULL;
+ vfs->data_size = 0;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_quit(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ /* Cleanup */
+ talloc_destroy(mem_ctx);
+
+ exit(0);
+ return NT_STATUS_OK; /* NOTREACHED */
+}
+
+static struct cmd_set vfstest_commands[] = {
+
+ { "GENERAL OPTIONS" },
+
+ { "conf", cmd_conf, "Load smb configuration file", "conf <smb.conf>" },
+ { "help", cmd_help, "Get help on commands", "" },
+ { "?", cmd_help, "Get help on commands", "" },
+ { "debuglevel", cmd_debuglevel, "Set debug level", "" },
+ { "freemem", cmd_freemem, "Free currently allocated buffers", "" },
+ { "exit", cmd_quit, "Exit program", "" },
+ { "quit", cmd_quit, "Exit program", "" },
+
+ { NULL }
+};
+
+static struct cmd_set separator_command[] = {
+ { "---------------", NULL, "----------------------" },
+ { NULL }
+};
+
+
+extern struct cmd_set vfs_commands[];
+static struct cmd_set *vfstest_command_list[] = {
+ vfstest_commands,
+ vfs_commands,
+ NULL
+};
+
+static void add_command_set(struct cmd_set *cmd_set)
+{
+ struct cmd_list *entry;
+
+ if (!(entry = SMB_MALLOC_P(struct cmd_list))) {
+ DEBUG(0, ("out of memory\n"));
+ return;
+ }
+
+ ZERO_STRUCTP(entry);
+
+ entry->cmd_set = cmd_set;
+ DLIST_ADD(cmd_list, entry);
+}
+
+static NTSTATUS do_cmd(struct vfs_state *vfs, struct cmd_set *cmd_entry, char *cmd)
+{
+ const char *p = cmd;
+ char **argv = NULL;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ char *buf;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+ int argc = 0, i;
+
+ /* Count number of arguments first time through the loop then
+ allocate memory and strdup them. */
+
+ again:
+ while(next_token_talloc(mem_ctx, &p, &buf, " ")) {
+ if (argv) {
+ argv[argc] = SMB_STRDUP(buf);
+ }
+ argc++;
+ }
+
+ if (!argv) {
+ /* Create argument list */
+
+ argv = SMB_MALLOC_ARRAY(char *, argc);
+ memset(argv, 0, sizeof(char *) * argc);
+
+ if (!argv) {
+ fprintf(stderr, "out of memory\n");
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ p = cmd;
+ argc = 0;
+
+ goto again;
+ }
+
+ /* Call the function */
+
+ if (cmd_entry->fn) {
+ /* Run command */
+ result = cmd_entry->fn(vfs, mem_ctx, argc, (const char **)argv);
+ } else {
+ fprintf (stderr, "Invalid command\n");
+ goto done;
+ }
+
+ done:
+
+ /* Cleanup */
+
+ if (argv) {
+ for (i = 0; i < argc; i++)
+ SAFE_FREE(argv[i]);
+
+ SAFE_FREE(argv);
+ }
+
+ TALLOC_FREE(mem_ctx);
+ return result;
+}
+
+/* Process a command entered at the prompt or as part of -c */
+static NTSTATUS process_cmd(struct vfs_state *vfs, char *cmd)
+{
+ struct cmd_list *temp_list;
+ bool found = False;
+ char *buf;
+ const char *p = cmd;
+ NTSTATUS result = NT_STATUS_OK;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+ int len = 0;
+
+ if (cmd[strlen(cmd) - 1] == '\n')
+ cmd[strlen(cmd) - 1] = '\0';
+
+ if (!next_token_talloc(mem_ctx, &p, &buf, " ")) {
+ TALLOC_FREE(mem_ctx);
+ return NT_STATUS_OK;
+ }
+
+ /* Strip the trailing \n if it exists */
+ len = strlen(buf);
+ if (buf[len-1] == '\n')
+ buf[len-1] = '\0';
+
+ /* Search for matching commands */
+
+ for (temp_list = cmd_list; temp_list; temp_list = temp_list->next) {
+ struct cmd_set *temp_set = temp_list->cmd_set;
+
+ while(temp_set->name) {
+ if (strequal(buf, temp_set->name)) {
+ found = True;
+ result = do_cmd(vfs, temp_set, cmd);
+
+ goto done;
+ }
+ temp_set++;
+ }
+ }
+
+ done:
+ if (!found && buf[0]) {
+ printf("command not found: %s\n", buf);
+ TALLOC_FREE(mem_ctx);
+ return NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(result)) {
+ printf("result was %s\n", nt_errstr(result));
+ }
+
+ TALLOC_FREE(mem_ctx);
+ return result;
+}
+
+static void process_file(struct vfs_state *pvfs, char *filename) {
+ FILE *file;
+ char command[3 * PATH_MAX];
+
+ if (*filename == '-') {
+ file = stdin;
+ } else {
+ file = fopen(filename, "r");
+ if (file == NULL) {
+ printf("vfstest: error reading file (%s)!", filename);
+ printf("errno n.%d: %s", errno, strerror(errno));
+ exit(-1);
+ }
+ }
+
+ while (fgets(command, 3 * PATH_MAX, file) != NULL) {
+ process_cmd(pvfs, command);
+ }
+}
+
+void exit_server(const char *reason)
+{
+ DEBUG(3,("Server exit (%s)\n", (reason ? reason : "")));
+ exit(0);
+}
+
+void exit_server_cleanly(const char *const reason)
+{
+ exit_server("normal exit");
+}
+
+static int server_fd = -1;
+int last_message = -1;
+
+int smbd_server_fd(void)
+{
+ return server_fd;
+}
+
+void reload_printers(void)
+{
+ return;
+}
+
+/****************************************************************************
+ Reload the services file.
+**************************************************************************/
+
+bool reload_services(bool test)
+{
+ bool ret;
+
+ if (lp_loaded()) {
+ const char *fname = lp_configfile();
+ if (file_exist(fname, NULL) &&
+ !strcsequal(fname, get_dyn_CONFIGFILE())) {
+ set_dyn_CONFIGFILE(fname);
+ test = False;
+ }
+ }
+
+ reopen_logs();
+
+ if (test && !lp_file_list_changed())
+ return(True);
+
+ lp_killunused(conn_snum_used);
+
+ ret = lp_load(get_dyn_CONFIGFILE(), False, False, True, True);
+
+ /* perhaps the config filename is now set */
+ if (!test)
+ reload_services(True);
+
+ reopen_logs();
+
+ load_interfaces();
+
+ {
+ if (smbd_server_fd() != -1) {
+ set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
+ set_socket_options(smbd_server_fd(),
+ lp_socket_options());
+ }
+ }
+
+ mangle_reset_cache();
+ reset_stat_cache();
+
+ /* this forces service parameters to be flushed */
+ set_current_service(NULL,0,True);
+
+ return (ret);
+}
+
+struct event_context *smbd_event_context(void)
+{
+ static struct event_context *ctx;
+
+ if (!ctx && !(ctx = event_context_init(NULL))) {
+ smb_panic("Could not init smbd event context\n");
+ }
+ return ctx;
+}
+
+struct messaging_context *smbd_messaging_context(void)
+{
+ static struct messaging_context *ctx;
+
+ if (!ctx && !(ctx = messaging_init(NULL, server_id_self(),
+ smbd_event_context()))) {
+ smb_panic("Could not init smbd messaging context\n");
+ }
+ return ctx;
+}
+
+struct memcache *smbd_memcache(void)
+{
+ static struct memcache *cache;
+
+ if (!cache
+ && !(cache = memcache_init(NULL,
+ lp_max_stat_cache_size()*1024))) {
+
+ smb_panic("Could not init smbd memcache");
+ }
+ return cache;
+}
+
+/* Main function */
+
+int main(int argc, char *argv[])
+{
+ static char *cmdstr = NULL;
+ struct cmd_set **cmd_set;
+ static struct vfs_state vfs;
+ int i;
+ static char *filename = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ /* make sure the vars that get altered (4th field) are in
+ a fixed location or certain compilers complain */
+ poptContext pc;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"file", 'f', POPT_ARG_STRING, &filename, 0, },
+ {"command", 'c', POPT_ARG_STRING, &cmdstr, 0, "Execute specified list of commands" },
+ POPT_COMMON_SAMBA
+ POPT_TABLEEND
+ };
+
+ load_case_tables();
+
+ setlinebuf(stdout);
+
+ pc = poptGetContext("vfstest", argc, (const char **) argv,
+ long_options, 0);
+
+ while(poptGetNextOpt(pc) != -1);
+
+
+ poptFreeContext(pc);
+
+ /* TODO: check output */
+ reload_services(False);
+
+ /* the following functions are part of the Samba debugging
+ facilities. See lib/debug.c */
+ setup_logging("vfstest", True);
+
+ /* Load command lists */
+
+ cmd_set = vfstest_command_list;
+
+ while(*cmd_set) {
+ add_command_set(*cmd_set);
+ add_command_set(separator_command);
+ cmd_set++;
+ }
+
+ /* some basic initialization stuff */
+ sec_init();
+ conn_init();
+ vfs.conn = conn_new();
+ for (i=0; i < 1024; i++)
+ vfs.files[i] = NULL;
+
+ /* some advanced initiliazation stuff */
+ smbd_vfs_init(vfs.conn);
+
+ /* Do we have a file input? */
+ if (filename && filename[0]) {
+ process_file(&vfs, filename);
+ return 0;
+ }
+
+ /* Do anything specified with -c */
+ if (cmdstr && cmdstr[0]) {
+ char *cmd;
+ char *p = cmdstr;
+
+ while((cmd=next_command(frame, &p)) != NULL) {
+ process_cmd(&vfs, cmd);
+ }
+
+ TALLOC_FREE(cmd);
+ return 0;
+ }
+
+ /* Loop around accepting commands */
+
+ while(1) {
+ char *line = NULL;
+
+ line = smb_readline("vfstest $> ", NULL, completion_fn);
+
+ if (line == NULL) {
+ break;
+ }
+
+ if (line[0] != '\n') {
+ process_cmd(&vfs, line);
+ }
+ SAFE_FREE(line);
+ }
+
+ conn_free(vfs.conn);
+ TALLOC_FREE(frame);
+ return 0;
+}
diff --git a/source3/torture/vfstest.h b/source3/torture/vfstest.h
new file mode 100644
index 0000000000..c68f9dcc0d
--- /dev/null
+++ b/source3/torture/vfstest.h
@@ -0,0 +1,44 @@
+/*
+ Unix SMB/CIFS implementation.
+ VFS module tester
+
+ Copyright (C) Simo Sorce 2002
+ Copyright (C) Eric Lorimer 2002
+
+ Most of this code was ripped off of rpcclient.
+ Copyright (C) Tim Potter 2000-2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+struct func_entry {
+ char *name;
+ int (*fn)(struct connection_struct *conn, const char *path);
+};
+
+struct vfs_state {
+ struct connection_struct *conn;
+ struct files_struct *files[1024];
+ DIR *currentdir;
+ void *data;
+ size_t data_size;
+};
+
+struct cmd_set {
+ const char *name;
+ NTSTATUS (*fn)(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc,
+ const char **argv);
+ const char *description;
+ const char *usage;
+};
diff --git a/source3/utils/debug2html.c b/source3/utils/debug2html.c
new file mode 100644
index 0000000000..26096c9de4
--- /dev/null
+++ b/source3/utils/debug2html.c
@@ -0,0 +1,256 @@
+/* ========================================================================== **
+ * debug2html.c
+ *
+ * Copyright (C) 1998 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ *
+ * -------------------------------------------------------------------------- **
+ * Parse Samba debug logs (2.0 & greater) and output the results as HTML.
+ * -------------------------------------------------------------------------- **
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- **
+ * This program provides an example of the use of debugparse.c, and also
+ * does a decent job of converting Samba logs into HTML.
+ * -------------------------------------------------------------------------- **
+ *
+ * Revision 1.4 1998/11/13 03:37:01 tridge
+ * fixes for OSF1 compilation
+ *
+ * Revision 1.3 1998/10/28 20:33:35 crh
+ * I've moved the debugparse module files into the ubiqx directory because I
+ * know that 'make proto' will ignore them there. The debugparse.h header
+ * file is included in includes.h, and includes.h is included in debugparse.c,
+ * so all of the pieces "see" each other. I've compiled and tested this,
+ * and it does seem to work. It's the same compromise model I used when
+ * adding the ubiqx modules into the system, which is why I put it all into
+ * the same directory.
+ *
+ * Chris -)-----
+ *
+ * Revision 1.1 1998/10/26 23:21:37 crh
+ * Here is the simple debug parser and the debug2html converter. Still to do:
+ *
+ * * Debug message filtering.
+ * * I need to add all this to Makefile.in
+ * (If it looks at all strange I'll ask for help.)
+ *
+ * If you want to compile debug2html, you'll need to do it by hand until I
+ * make the changes to Makefile.in. Sorry.
+ *
+ * Chris -)-----
+ *
+ * ========================================================================== **
+ */
+
+#include "debugparse.h"
+
+/* -------------------------------------------------------------------------- **
+ * The size of the read buffer.
+ */
+
+#define DBG_BSIZE 1024
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+static dbg_Token modechange( dbg_Token newmode, dbg_Token mode )
+ /* ------------------------------------------------------------------------ **
+ * Handle a switch between header and message printing.
+ *
+ * Input: new - The token value of the current token. This indicates
+ * the lexical item currently being recognized.
+ * mode - The current mode. This is either dbg_null or
+ * dbg_message. It could really be any toggle
+ * (true/false, etc.)
+ *
+ * Output: The new mode. This will be the same as the input mode unless
+ * there was a transition in or out of message processing.
+ *
+ * Notes: The purpose of the mode value is to mark the beginning and end
+ * of the message text block. In order to show the text in its
+ * correct format, it must be included within a <PRE></PRE> block.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ switch( newmode )
+ {
+ case dbg_null:
+ case dbg_ignore:
+ return( mode );
+ case dbg_message:
+ if( dbg_message != mode )
+ {
+ /* Switching to message mode. */
+ (void)printf( "<PRE>\n" );
+ return( dbg_message );
+ }
+ break;
+ default:
+ if( dbg_message == mode )
+ {
+ /* Switching out of message mode. */
+ (void)printf( "</PRE>\n\n" );
+ return( dbg_null );
+ }
+ }
+
+ return( mode );
+ } /* modechange */
+
+static void newblock( dbg_Token old, dbg_Token newtok )
+ /* ------------------------------------------------------------------------ **
+ * Handle the transition between tokens.
+ *
+ * Input: old - The previous token.
+ * new - The current token.
+ *
+ * Output: none.
+ *
+ * Notes: This is called whenever there is a transition from one token
+ * type to another. It first prints the markup tags that close
+ * the previous token, and then the markup tags for the new
+ * token.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ switch( old )
+ {
+ case dbg_timestamp:
+ (void)printf( ",</B>" );
+ break;
+ case dbg_level:
+ (void)printf( "</FONT>]</B>\n " );
+ break;
+ case dbg_sourcefile:
+ (void)printf( ":" );
+ break;
+ case dbg_lineno:
+ (void)printf( ")" );
+ break;
+ default:
+ break;
+ }
+
+ switch( newtok )
+ {
+ case dbg_timestamp:
+ (void)printf( "<B>[" );
+ break;
+ case dbg_level:
+ (void)printf( " <B><FONT COLOR=MAROON>" );
+ break;
+ case dbg_lineno:
+ (void)printf( "(" );
+ break;
+ default:
+ break;
+ }
+ } /* newblock */
+
+static void charprint( dbg_Token tok, int c )
+ /* ------------------------------------------------------------------------ **
+ * Filter the input characters to determine what goes to output.
+ *
+ * Input: tok - The token value of the current character.
+ * c - The current character.
+ *
+ * Output: none.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ switch( tok )
+ {
+ case dbg_ignore:
+ case dbg_header:
+ break;
+ case dbg_null:
+ case dbg_eof:
+ (void)putchar( '\n' );
+ break;
+ default:
+ switch( c )
+ {
+ case '<':
+ (void)printf( "&lt;" );
+ break;
+ case '>':
+ (void)printf( "&gt;" );
+ break;
+ case '&':
+ (void)printf( "&amp;" );
+ break;
+ case '\"':
+ (void)printf( "&#34;" );
+ break;
+ default:
+ (void)putchar( c );
+ break;
+ }
+ }
+ } /* charprint */
+
+int main( int argc, char *argv[] )
+ /* ------------------------------------------------------------------------ **
+ * This simple program scans and parses Samba debug logs, and produces HTML
+ * output.
+ *
+ * Input: argc - Currently ignored.
+ * argv - Currently ignored.
+ *
+ * Output: Always zero.
+ *
+ * Notes: The HTML output is sent to stdout.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int i;
+ int len;
+ char bufr[DBG_BSIZE];
+ dbg_Token old = dbg_null,
+ newtok = dbg_null,
+ state = dbg_null,
+ mode = dbg_null;
+
+ (void)printf( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n" );
+ (void)printf( "<HTML>\n<HEAD>\n" );
+ (void)printf( " <TITLE>Samba Debug Output</TITLE>\n</HEAD>\n\n<BODY>\n" );
+
+ while( (!feof( stdin ))
+ && ((len = fread( bufr, 1, DBG_BSIZE, stdin )) > 0) )
+ {
+ for( i = 0; i < len; i++ )
+ {
+ old = newtok;
+ newtok = dbg_char2token( &state, bufr[i] );
+ if( newtok != old )
+ {
+ mode = modechange( newtok, mode );
+ newblock( old, newtok );
+ }
+ charprint( newtok, bufr[i] );
+ }
+ }
+ (void)modechange( dbg_eof, mode );
+
+ (void)printf( "</BODY>\n</HTML>\n" );
+ return( 0 );
+ } /* main */
diff --git a/source3/utils/debugparse.c b/source3/utils/debugparse.c
new file mode 100644
index 0000000000..5835de1b8d
--- /dev/null
+++ b/source3/utils/debugparse.c
@@ -0,0 +1,308 @@
+/* ========================================================================== **
+ * debugparse.c
+ *
+ * Copyright (C) 1998 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ *
+ * -------------------------------------------------------------------------- **
+ * This module is a very simple parser for Samba debug log files.
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 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 Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- **
+ * The important function in this module is dbg_char2token(). The rest is
+ * basically fluff. (Potentially useful fluff, but still fluff.)
+ * ========================================================================== **
+ */
+
+#include "debugparse.h"
+
+/* -------------------------------------------------------------------------- **
+ * Constants...
+ *
+ * DBG_BSIZE - This internal constant is used only by dbg_test(). It is the
+ * size of the read buffer. I've tested the function using a
+ * DBG_BSIZE value of 2.
+ */
+
+#define DBG_BSIZE 128
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+const char *dbg_token2string( dbg_Token tok )
+ /* ------------------------------------------------------------------------ **
+ * Given a token, return a string describing the token.
+ *
+ * Input: tok - One of the set of dbg_Tokens defined in debugparse.h.
+ *
+ * Output: A string identifying the token. This is useful for debugging,
+ * etc.
+ *
+ * Note: If the token is not known, this function will return the
+ * string "<unknown>".
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ switch( tok )
+ {
+ case dbg_null:
+ return( "null" );
+ case dbg_ignore:
+ return( "ignore" );
+ case dbg_header:
+ return( "header" );
+ case dbg_timestamp:
+ return( "time stamp" );
+ case dbg_level:
+ return( "level" );
+ case dbg_sourcefile:
+ return( "source file" );
+ case dbg_function:
+ return( "function" );
+ case dbg_lineno:
+ return( "line number" );
+ case dbg_message:
+ return( "message" );
+ case dbg_eof:
+ return( "[EOF]" );
+ }
+ return( "<unknown>" );
+ } /* dbg_token2string */
+
+dbg_Token dbg_char2token( dbg_Token *state, int c )
+ /* ------------------------------------------------------------------------ **
+ * Parse input one character at a time.
+ *
+ * Input: state - A pointer to a token variable. This is used to
+ * maintain the parser state between calls. For
+ * each input stream, you should set up a separate
+ * state variable and initialize it to dbg_null.
+ * Pass a pointer to it into this function with each
+ * character in the input stream. See dbg_test()
+ * for an example.
+ * c - The "current" character in the input stream.
+ *
+ * Output: A token.
+ * The token value will change when delimiters are found,
+ * which indicate a transition between syntactical objects.
+ * Possible return values are:
+ *
+ * dbg_null - The input character was an end-of-line.
+ * This resets the parser to its initial state
+ * in preparation for parsing the next line.
+ * dbg_eof - Same as dbg_null, except that the character
+ * was an end-of-file.
+ * dbg_ignore - Returned for whitespace and delimiters.
+ * These lexical tokens are only of interest
+ * to the parser.
+ * dbg_header - Indicates the start of a header line. The
+ * input character was '[' and was the first on
+ * the line.
+ * dbg_timestamp - Indicates that the input character was part
+ * of a header timestamp.
+ * dbg_level - Indicates that the input character was part
+ * of the debug-level value in the header.
+ * dbg_sourcefile - Indicates that the input character was part
+ * of the sourcefile name in the header.
+ * dbg_function - Indicates that the input character was part
+ * of the function name in the header.
+ * dbg_lineno - Indicates that the input character was part
+ * of the DEBUG call line number in the header.
+ * dbg_message - Indicates that the input character was part
+ * of the DEBUG message text.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ /* The terminating characters that we see will greatly depend upon
+ * how they are read. For example, if gets() is used instead of
+ * fgets(), then we will not see newline characters. A lot also
+ * depends on the calling function, which may handle terminators
+ * itself.
+ *
+ * '\n', '\0', and EOF are all considered line terminators. The
+ * dbg_eof token is sent back if an EOF is encountered.
+ *
+ * Warning: only allow the '\0' character to be sent if you are
+ * using gets() to read whole lines (thus replacing '\n'
+ * with '\0'). Sending '\0' at the wrong time will mess
+ * up the parsing.
+ */
+ switch( c )
+ {
+ case EOF:
+ *state = dbg_null; /* Set state to null (initial state) so */
+ return( dbg_eof ); /* that we can restart with new input. */
+ case '\n':
+ case '\0':
+ *state = dbg_null; /* A newline or eoln resets to the null state. */
+ return( dbg_null );
+ }
+
+ /* When within the body of the message, only a line terminator
+ * can cause a change of state. We've already checked for line
+ * terminators, so if the current state is dbg_msgtxt, simply
+ * return that as our current token.
+ */
+ if( dbg_message == *state )
+ return( dbg_message );
+
+ /* If we are at the start of a new line, and the input character
+ * is an opening bracket, then the line is a header line, otherwise
+ * it's a message body line.
+ */
+ if( dbg_null == *state )
+ {
+ if( '[' == c )
+ {
+ *state = dbg_timestamp;
+ return( dbg_header );
+ }
+ *state = dbg_message;
+ return( dbg_message );
+ }
+
+ /* We've taken care of terminators, text blocks and new lines.
+ * The remaining possibilities are all within the header line
+ * itself.
+ */
+
+ /* Within the header line, whitespace can be ignored *except*
+ * within the timestamp.
+ */
+ if( isspace( c ) )
+ {
+ /* Fudge. The timestamp may contain space characters. */
+ if( (' ' == c) && (dbg_timestamp == *state) )
+ return( dbg_timestamp );
+ /* Otherwise, ignore whitespace. */
+ return( dbg_ignore );
+ }
+
+ /* Okay, at this point we know we're somewhere in the header.
+ * Valid header *states* are: dbg_timestamp, dbg_level,
+ * dbg_sourcefile, dbg_function, and dbg_lineno.
+ */
+ switch( c )
+ {
+ case ',':
+ if( dbg_timestamp == *state )
+ {
+ *state = dbg_level;
+ return( dbg_ignore );
+ }
+ break;
+ case ']':
+ if( dbg_level == *state )
+ {
+ *state = dbg_sourcefile;
+ return( dbg_ignore );
+ }
+ break;
+ case ':':
+ if( dbg_sourcefile == *state )
+ {
+ *state = dbg_function;
+ return( dbg_ignore );
+ }
+ break;
+ case '(':
+ if( dbg_function == *state )
+ {
+ *state = dbg_lineno;
+ return( dbg_ignore );
+ }
+ break;
+ case ')':
+ if( dbg_lineno == *state )
+ {
+ *state = dbg_null;
+ return( dbg_ignore );
+ }
+ break;
+ }
+
+ /* If the previous block did not result in a state change, then
+ * return the current state as the current token.
+ */
+ return( *state );
+ } /* dbg_char2token */
+
+void dbg_test( void );
+void dbg_test( void )
+ /* ------------------------------------------------------------------------ **
+ * Simple test function.
+ *
+ * Input: none.
+ * Output: none.
+ * Notes: This function was used to test dbg_char2token(). It reads a
+ * Samba log file from stdin and prints parsing info to stdout.
+ * It also serves as a simple example.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ char bufr[DBG_BSIZE];
+ int i;
+ int linecount = 1;
+ dbg_Token old = dbg_null,
+ newtok= dbg_null,
+ state = dbg_null;
+
+ while( fgets( bufr, DBG_BSIZE, stdin ) )
+ {
+ for( i = 0; bufr[i]; i++ )
+ {
+ old = newtok;
+ newtok = dbg_char2token( &state, bufr[i] );
+ switch( newtok )
+ {
+ case dbg_header:
+ if( linecount > 1 )
+ (void)putchar( '\n' );
+ break;
+ case dbg_null:
+ linecount++;
+ break;
+ case dbg_ignore:
+ break;
+ default:
+ if( old != newtok )
+ (void)printf( "\n[%05d]%12s: ", linecount, dbg_token2string(newtok) );
+ (void)putchar( bufr[i] );
+ }
+ }
+ }
+ (void)putchar( '\n' );
+ } /* dbg_test */
+
+
+/* -------------------------------------------------------------------------- **
+ * This simple main line can be uncommented and used to test the parser.
+ */
+
+/*
+ * int main( void )
+ * {
+ * dbg_test();
+ * return( 0 );
+ * }
+ */
+
+/* ========================================================================== */
diff --git a/source3/utils/eventlogadm.c b/source3/utils/eventlogadm.c
new file mode 100644
index 0000000000..1b38a7b13b
--- /dev/null
+++ b/source3/utils/eventlogadm.c
@@ -0,0 +1,229 @@
+
+/*
+ * Samba Unix/Linux SMB client utility
+ * Write Eventlog records to a tdb, perform other eventlog related functions
+ *
+ *
+ * Copyright (C) Brian Moran 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_UTIL_EVENTLOG
+
+
+extern int optind;
+extern char *optarg;
+
+int opt_debug = 0;
+
+static void usage( char *s )
+{
+ printf( "\nUsage: %s [OPTION]\n\n", s );
+ printf( " -o write <Eventlog Name> \t\t\t\t\tWrites records to eventlog from STDIN\n" );
+ printf( " -o addsource <EventlogName> <sourcename> <msgfileDLLname> \tAdds the specified source & DLL eventlog registry entry\n" );
+ printf( "\nMiscellaneous options:\n" );
+ printf( " -d\t\t\t\t\t\t\t\tturn debug on\n" );
+ printf( " -h\t\t\t\t\t\t\t\tdisplay help\n\n" );
+}
+
+static void display_eventlog_names( void )
+{
+ const char **elogs;
+ int i;
+
+ elogs = lp_eventlog_list( );
+ printf( "Active eventlog names (from smb.conf):\n" );
+ printf( "--------------------------------------\n" );
+ if ( elogs ) {
+ for ( i = 0; elogs[i]; i++ ) {
+ printf( "\t%s\n", elogs[i] );
+ }
+ }
+ else
+ printf( "\t<None specified>\n");
+}
+
+static int DoAddSourceCommand( int argc, char **argv, bool debugflag, char *exename )
+{
+
+ if ( argc < 3 ) {
+ printf( "need more arguments:\n" );
+ printf( "-o addsource EventlogName SourceName /path/to/EventMessageFile.dll\n" );
+ return -1;
+ }
+ /* must open the registry before we access it */
+ if (!W_ERROR_IS_OK(regdb_init())) {
+ printf( "Can't open the registry.\n" );
+ return -1;
+ }
+
+ if ( !eventlog_add_source( argv[0], argv[1], argv[2] ) )
+ return -2;
+ return 0;
+}
+
+static int DoWriteCommand( int argc, char **argv, bool debugflag, char *exename )
+{
+ FILE *f1;
+ char *argfname;
+ ELOG_TDB *etdb;
+
+ /* fixed constants are bad bad bad */
+ char linein[1024];
+ bool is_eor;
+ Eventlog_entry ee;
+ int rcnum;
+
+ f1 = stdin;
+ if ( !f1 ) {
+ printf( "Can't open STDIN\n" );
+ return -1;
+ }
+
+ if ( debugflag ) {
+ printf( "Starting write for eventlog [%s]\n", argv[0] );
+ display_eventlog_names( );
+ }
+
+ argfname = argv[0];
+
+ if ( !( etdb = elog_open_tdb( argfname, False ) ) ) {
+ printf( "can't open the eventlog TDB (%s)\n", argfname );
+ return -1;
+ }
+
+ ZERO_STRUCT( ee ); /* MUST initialize between records */
+
+ while ( !feof( f1 ) ) {
+ fgets( linein, sizeof( linein ) - 1, f1 );
+ linein[strlen( linein ) - 1] = 0; /* whack the line delimiter */
+
+ if ( debugflag )
+ printf( "Read line [%s]\n", linein );
+
+ is_eor = False;
+
+
+ parse_logentry( ( char * ) &linein, &ee, &is_eor );
+ /* should we do something with the return code? */
+
+ if ( is_eor ) {
+ fixup_eventlog_entry( &ee );
+
+ if ( opt_debug )
+ printf( "record number [%d], tg [%d] , tw [%d]\n", ee.record.record_number, ee.record.time_generated, ee.record.time_written );
+
+ if ( ee.record.time_generated != 0 ) {
+
+ /* printf("Writing to the event log\n"); */
+
+ rcnum = write_eventlog_tdb( ELOG_TDB_CTX(etdb), &ee );
+ if ( !rcnum ) {
+ printf( "Can't write to the event log\n" );
+ } else {
+ if ( opt_debug )
+ printf( "Wrote record %d\n",
+ rcnum );
+ }
+ } else {
+ if ( opt_debug )
+ printf( "<null record>\n" );
+ }
+ ZERO_STRUCT( ee ); /* MUST initialize between records */
+ }
+ }
+
+ elog_close_tdb( etdb , False );
+
+ return 0;
+}
+
+/* would be nice to use the popT stuff here, however doing so forces us to drag in a lot of other infrastructure */
+
+int main( int argc, char *argv[] )
+{
+ int opt, rc;
+ char *exename;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+
+ fstring opname;
+
+ load_case_tables();
+
+ opt_debug = 0; /* todo set this from getopts */
+
+ lp_load(get_dyn_CONFIGFILE(), True, False, False, True);
+
+ exename = argv[0];
+
+ /* default */
+
+ fstrcpy( opname, "write" ); /* the default */
+
+#if 0 /* TESTING CODE */
+ eventlog_add_source( "System", "TestSourceX", "SomeTestPathX" );
+#endif
+ while ( ( opt = getopt( argc, argv, "dho:" ) ) != EOF ) {
+ switch ( opt ) {
+
+ case 'o':
+ fstrcpy( opname, optarg );
+ break;
+
+ case 'h':
+ usage( exename );
+ display_eventlog_names( );
+ exit( 0 );
+ break;
+
+ case 'd':
+ opt_debug = 1;
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if ( argc < 1 ) {
+ printf( "\nNot enough arguments!\n" );
+ usage( exename );
+ exit( 1 );
+ }
+
+ /* note that the separate command types should call usage if they need to... */
+ while ( 1 ) {
+ if ( !StrCaseCmp( opname, "addsource" ) ) {
+ rc = DoAddSourceCommand( argc, argv, opt_debug,
+ exename );
+ break;
+ }
+ if ( !StrCaseCmp( opname, "write" ) ) {
+ rc = DoWriteCommand( argc, argv, opt_debug, exename );
+ break;
+ }
+ printf( "unknown command [%s]\n", opname );
+ usage( exename );
+ exit( 1 );
+ break;
+ }
+ TALLOC_FREE(frame);
+ return rc;
+}
diff --git a/source3/utils/log2pcaphex.c b/source3/utils/log2pcaphex.c
new file mode 100644
index 0000000000..20cc40ca59
--- /dev/null
+++ b/source3/utils/log2pcaphex.c
@@ -0,0 +1,304 @@
+/*
+ Unix SMB/CIFS implementation.
+ Utility to extract pcap files from samba (log level 10) log files
+
+ Copyright (C) Jelmer Vernooij 2003
+ Thanks to Tim Potter for the genial idea
+
+ Portions (from capconvert.c) (C) Andrew Tridgell 1997
+ Portions (from text2pcap.c) (C) Ashok Narayanan 2001
+
+ Example use with -h parameter:
+ log2pcaphex < samba-log-file | text2pcap -T 139,139 - foo.pcap
+
+ TODO: Have correct IP and TCP checksums.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/* We don't care about the paranoid malloc checker in this standalone
+ program */
+#undef malloc
+
+#include <assert.h>
+
+bool quiet = 0;
+bool hexformat = 0;
+
+#define itoa(a) ((a) < 0xa?'0'+(a):'A' + (a-0xa))
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#define TCPDUMP_MAGIC 0xa1b2c3d4
+
+/* tcpdump file format */
+struct tcpdump_file_header {
+ uint32 magic;
+ uint16 major;
+ uint16 minor;
+ int32 zone;
+ uint32 sigfigs;
+ uint32 snaplen;
+ uint32 linktype;
+};
+
+struct tcpdump_packet {
+ struct timeval ts;
+ uint32 caplen;
+ uint32 len;
+};
+
+typedef struct {
+ uint8 ver_hdrlen;
+ uint8 dscp;
+ uint16 packet_length;
+ uint16 identification;
+ uint8 flags;
+ uint8 fragment;
+ uint8 ttl;
+ uint8 protocol;
+ uint16 hdr_checksum;
+ uint32 src_addr;
+ uint32 dest_addr;
+} hdr_ip_t;
+
+static hdr_ip_t HDR_IP = {0x45, 0, 0, 0x3412, 0, 0, 0xff, 6, 0, 0x01010101, 0x02020202};
+
+typedef struct {
+ uint16 source_port;
+ uint16 dest_port;
+ uint32 seq_num;
+ uint32 ack_num;
+ uint8 hdr_length;
+ uint8 flags;
+ uint16 window;
+ uint16 checksum;
+ uint16 urg;
+} hdr_tcp_t;
+
+static hdr_tcp_t HDR_TCP = {139, 139, 0, 0, 0x50, 0, 0, 0, 0};
+
+static void print_pcap_header(FILE *out)
+{
+ struct tcpdump_file_header h;
+ h.magic = TCPDUMP_MAGIC;
+ h.major = 2;
+ h.minor = 4;
+ h.zone = 0;
+ h.sigfigs = 0;
+ h.snaplen = 102400; /* As long packets as possible */
+ h.linktype = 101; /* Raw IP */
+ fwrite(&h, sizeof(struct tcpdump_file_header), 1, out);
+}
+
+static void print_pcap_packet(FILE *out, unsigned char *data, long length, long caplen)
+{
+ static int i = 0;
+ struct tcpdump_packet p;
+ i++;
+ p.ts.tv_usec = 0;
+ p.ts.tv_sec = 0;
+ p.caplen = caplen;
+ p.len = length;
+ fwrite(&p, sizeof(struct tcpdump_packet), 1, out);
+ fwrite(data, sizeof(unsigned char), caplen, out);
+}
+
+static void print_hex_packet(FILE *out, unsigned char *data, long length)
+{
+ long i,cur = 0;
+ while(cur < length) {
+ fprintf(out, "%06lX ", cur);
+ for(i = cur; i < length && i < cur + 16; i++) {
+ fprintf(out, "%02x ", data[i]);
+ }
+
+ cur = i;
+ fprintf(out, "\n");
+ }
+}
+
+static void print_netbios_packet(FILE *out, unsigned char *data, long length, long actual_length)
+{
+ unsigned char *newdata; long offset = 0;
+ long newlen;
+
+ newlen = length+sizeof(HDR_IP)+sizeof(HDR_TCP);
+ newdata = (unsigned char *)malloc(newlen);
+
+ HDR_IP.packet_length = htons(newlen);
+ HDR_TCP.window = htons(0x2000);
+ HDR_TCP.source_port = HDR_TCP.dest_port = htons(139);
+
+ memcpy(newdata+offset, &HDR_IP, sizeof(HDR_IP));offset+=sizeof(HDR_IP);
+ memcpy(newdata+offset, &HDR_TCP, sizeof(HDR_TCP));offset+=sizeof(HDR_TCP);
+ memcpy(newdata+offset,data,length);
+
+ print_pcap_packet(out, newdata, newlen, actual_length+offset);
+ free(newdata);
+}
+
+unsigned char *curpacket = NULL;
+long curpacket_len = 0;
+
+static void read_log_msg(FILE *in, unsigned char **_buffer, long *buffersize, long *data_offset, long *data_length)
+{
+ unsigned char *buffer;
+ int tmp; long i;
+ assert(fscanf(in, " size=%ld\n", buffersize));
+ *buffersize+=4; /* for netbios */
+ buffer = (unsigned char *)malloc(*buffersize);
+ memset(buffer, 0, *buffersize);
+ /* NetBIOS */
+ buffer[0] = 0x00;
+ buffer[1] = 0x00;
+ memcpy(buffer+2, &buffersize, 2);
+ buffer[4] = 0xFF;
+ buffer[5] = 'S';
+ buffer[6] = 'M';
+ buffer[7] = 'B';
+ assert(fscanf(in, " smb_com=0x%x\n", &tmp)); buffer[smb_com] = tmp;
+ assert(fscanf(in, " smb_rcls=%d\n", &tmp)); buffer[smb_rcls] = tmp;
+ assert(fscanf(in, " smb_reh=%d\n", &tmp)); buffer[smb_reh] = tmp;
+ assert(fscanf(in, " smb_err=%d\n", &tmp)); memcpy(buffer+smb_err, &tmp, 2);
+ assert(fscanf(in, " smb_flg=%d\n", &tmp)); buffer[smb_flg] = tmp;
+ assert(fscanf(in, " smb_flg2=%d\n", &tmp)); memcpy(buffer+smb_flg2, &tmp, 2);
+ assert(fscanf(in, " smb_tid=%d\n", &tmp)); memcpy(buffer+smb_tid, &tmp, 2);
+ assert(fscanf(in, " smb_pid=%d\n", &tmp)); memcpy(buffer+smb_pid, &tmp, 2);
+ assert(fscanf(in, " smb_uid=%d\n", &tmp)); memcpy(buffer+smb_uid, &tmp, 2);
+ assert(fscanf(in, " smb_mid=%d\n", &tmp)); memcpy(buffer+smb_mid, &tmp, 2);
+ assert(fscanf(in, " smt_wct=%d\n", &tmp)); buffer[smb_wct] = tmp;
+ for(i = 0; i < buffer[smb_wct]; i++) {
+ assert(fscanf(in, " smb_vwv[%*2d]=%*5d (0x%X)\n", &tmp));
+ memcpy(buffer+smb_vwv+i*2, &tmp, 2);
+ }
+
+ *data_offset = smb_vwv+buffer[smb_wct]*2;
+ assert(fscanf(in, " smb_bcc=%ld\n", data_length)); buffer[(*data_offset)] = *data_length;
+ (*data_offset)+=2;
+ *_buffer = buffer;
+}
+
+static long read_log_data(FILE *in, unsigned char *buffer, long data_length)
+{
+ long i, addr; char real[2][16]; int ret;
+ unsigned int tmp;
+ for(i = 0; i < data_length; i++) {
+ if(i % 16 == 0){
+ if(i != 0) { /* Read data after each line */
+ assert(fscanf(in, "%8s %8s", real[0], real[1]) == 2);
+ }
+ ret = fscanf(in, " [%03lX]", &addr);
+ if(!ret) {
+ if(!quiet)fprintf(stderr, "Only first %ld bytes are logged, packet trace will be incomplete\nTry a higher log level\n", i);
+ return i-1;
+ }
+ assert(addr == i);
+ }
+ if(!fscanf(in, "%02X", &tmp)) {
+ if(!quiet)fprintf(stderr, "Only first %ld bytes are logged, packet trace will be incomplete\nTry a higher log level\n", i-1);
+ return i-1;
+ }
+ buffer[i] = tmp;
+ }
+ return data_length;
+}
+
+int main (int argc, char **argv)
+{
+ const char *infile, *outfile;
+ FILE *out, *in;
+ int opt;
+ poptContext pc;
+ char buffer[4096];
+ long data_offset = 0, data_length;
+ long data_bytes_read = 0;
+ int in_packet = 0;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "quiet", 'q', POPT_ARG_NONE, NULL, 'q', "Be quiet, don't output warnings" },
+ { "hex", 'h', POPT_ARG_NONE, NULL, 'h', "Output format readable by text2pcap" },
+ POPT_TABLEEND
+ };
+
+ pc = poptGetContext(NULL, argc, (const char **) argv, long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+ poptSetOtherOptionHelp(pc, "[<infile> [<outfile>]]");
+
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'q':
+ quiet = true;
+ break;
+ case 'h':
+ hexformat = true;
+ break;
+ }
+ }
+
+ poptGetArg(pc); /* Drop argv[0], the program name */
+
+ infile = poptGetArg(pc);
+
+ if(infile) {
+ in = fopen(infile, "r");
+ if(!in) {
+ perror("fopen");
+ return 1;
+ }
+ } else in = stdin;
+
+ outfile = poptGetArg(pc);
+
+ if(outfile) {
+ out = fopen(outfile, "w+");
+ if(!out) {
+ perror("fopen");
+ fprintf(stderr, "Can't find %s, using stdout...\n", outfile);
+ }
+ }
+
+ if(!outfile) out = stdout;
+
+ if(!hexformat)print_pcap_header(out);
+
+ while(!feof(in)) {
+ fgets(buffer, sizeof(buffer), in);
+ if(buffer[0] == '[') { /* Header */
+ if(strstr(buffer, "show_msg")) {
+ in_packet++;
+ if(in_packet == 1)continue;
+ read_log_msg(in, &curpacket, &curpacket_len, &data_offset, &data_length);
+ } else if(in_packet && strstr(buffer, "dump_data")) {
+ data_bytes_read = read_log_data(in, curpacket+data_offset, data_length);
+ } else {
+ if(in_packet){
+ if(hexformat) print_hex_packet(out, curpacket, curpacket_len);
+ else print_netbios_packet(out, curpacket, curpacket_len, data_bytes_read+data_offset);
+ free(curpacket);
+ }
+ in_packet = 0;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/source3/utils/net.c b/source3/utils/net.c
new file mode 100644
index 0000000000..bab2f41d11
--- /dev/null
+++ b/source3/utils/net.c
@@ -0,0 +1,777 @@
+/*
+ Samba Unix/Linux SMB client library
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) 2001 Steve French (sfrench@us.ibm.com)
+ Copyright (C) 2001 Jim McDonough (jmcd@us.ibm.com)
+ Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+ Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
+ Copyright (C) 2008 Kai Blin (kai@samba.org)
+
+ Originally written by Steve and Jim. Largely rewritten by tridge in
+ November 2001.
+
+ Reworked again by abartlet in December 2001
+
+ Another overhaul, moving functionality into plug-ins loaded on demand by Kai
+ in May 2008.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/*****************************************************/
+/* */
+/* Distributed SMB/CIFS Server Management Utility */
+/* */
+/* The intent was to make the syntax similar */
+/* to the NET utility (first developed in DOS */
+/* with additional interesting & useful functions */
+/* added in later SMB server network operating */
+/* systems). */
+/* */
+/*****************************************************/
+
+#include "includes.h"
+#include "utils/net.h"
+
+extern bool AllowDebugChange;
+
+#ifdef WITH_FAKE_KASERVER
+#include "utils/net_afs.h"
+#endif
+
+/***********************************************************************/
+/* Beginning of internationalization section. Translatable constants */
+/* should be kept in this area and referenced in the rest of the code. */
+/* */
+/* No functions, outside of Samba or LSB (Linux Standards Base) should */
+/* be used (if possible). */
+/***********************************************************************/
+
+#define YES_STRING "Yes"
+#define NO_STRING "No"
+
+/***********************************************************************/
+/* end of internationalization section */
+/***********************************************************************/
+
+uint32 get_sec_channel_type(const char *param)
+{
+ if (!(param && *param)) {
+ return get_default_sec_channel();
+ } else {
+ if (strequal(param, "PDC")) {
+ return SEC_CHAN_BDC;
+ } else if (strequal(param, "BDC")) {
+ return SEC_CHAN_BDC;
+ } else if (strequal(param, "MEMBER")) {
+ return SEC_CHAN_WKSTA;
+#if 0
+ } else if (strequal(param, "DOMAIN")) {
+ return SEC_CHAN_DOMAIN;
+#endif
+ } else {
+ return get_default_sec_channel();
+ }
+ }
+}
+
+static int net_changetrustpw(struct net_context *c, int argc, const char **argv)
+{
+ if (net_ads_check_our_domain(c) == 0)
+ return net_ads_changetrustpw(c, argc, argv);
+
+ return net_rpc_changetrustpw(c, argc, argv);
+}
+
+static void set_line_buffering(FILE *f)
+{
+ setvbuf(f, NULL, _IOLBF, 0);
+}
+
+static int net_changesecretpw(struct net_context *c, int argc,
+ const char **argv)
+{
+ char *trust_pw;
+ uint32 sec_channel_type = SEC_CHAN_WKSTA;
+
+ if(c->opt_force) {
+ if (c->opt_stdin) {
+ set_line_buffering(stdin);
+ set_line_buffering(stdout);
+ set_line_buffering(stderr);
+ }
+
+ trust_pw = get_pass("Enter machine password: ", c->opt_stdin);
+
+ if (!secrets_store_machine_password(trust_pw, lp_workgroup(), sec_channel_type)) {
+ d_fprintf(stderr, "Unable to write the machine account password in the secrets database");
+ return 1;
+ }
+ else {
+ d_printf("Modified trust account password in secrets database\n");
+ }
+ }
+ else {
+ d_printf("Machine account password change requires the -f flag.\n");
+ d_printf("Do NOT use this function unless you know what it does!\n");
+ d_printf("This function will change the ADS Domain member machine account password in the secrets.tdb file!\n");
+ }
+
+ return 0;
+}
+
+/*
+ Retrieve our local SID or the SID for the specified name
+ */
+static int net_getlocalsid(struct net_context *c, int argc, const char **argv)
+{
+ DOM_SID sid;
+ const char *name;
+ fstring sid_str;
+
+ if (argc >= 1) {
+ name = argv[0];
+ }
+ else {
+ name = global_myname();
+ }
+
+ if(!initialize_password_db(false, NULL)) {
+ DEBUG(0, ("WARNING: Could not open passdb - local sid may not reflect passdb\n"
+ "backend knowledge (such as the sid stored in LDAP)\n"));
+ }
+
+ /* first check to see if we can even access secrets, so we don't
+ panic when we can't. */
+
+ if (!secrets_init()) {
+ d_fprintf(stderr, "Unable to open secrets.tdb. Can't fetch domain SID for name: %s\n", name);
+ return 1;
+ }
+
+ /* Generate one, if it doesn't exist */
+ get_global_sam_sid();
+
+ if (!secrets_fetch_domain_sid(name, &sid)) {
+ DEBUG(0, ("Can't fetch domain SID for name: %s\n", name));
+ return 1;
+ }
+ sid_to_fstring(sid_str, &sid);
+ d_printf("SID for domain %s is: %s\n", name, sid_str);
+ return 0;
+}
+
+static int net_setlocalsid(struct net_context *c, int argc, const char **argv)
+{
+ DOM_SID sid;
+
+ if ( (argc != 1)
+ || (strncmp(argv[0], "S-1-5-21-", strlen("S-1-5-21-")) != 0)
+ || (!string_to_sid(&sid, argv[0]))
+ || (sid.num_auths != 4)) {
+ d_printf("usage: net setlocalsid S-1-5-21-x-y-z\n");
+ return 1;
+ }
+
+ if (!secrets_store_domain_sid(global_myname(), &sid)) {
+ DEBUG(0,("Can't store domain SID as a pdc/bdc.\n"));
+ return 1;
+ }
+
+ return 0;
+}
+
+static int net_setdomainsid(struct net_context *c, int argc, const char **argv)
+{
+ DOM_SID sid;
+
+ if ( (argc != 1)
+ || (strncmp(argv[0], "S-1-5-21-", strlen("S-1-5-21-")) != 0)
+ || (!string_to_sid(&sid, argv[0]))
+ || (sid.num_auths != 4)) {
+ d_printf("usage: net setdomainsid S-1-5-21-x-y-z\n");
+ return 1;
+ }
+
+ if (!secrets_store_domain_sid(lp_workgroup(), &sid)) {
+ DEBUG(0,("Can't store domain SID.\n"));
+ return 1;
+ }
+
+ return 0;
+}
+
+static int net_getdomainsid(struct net_context *c, int argc, const char **argv)
+{
+ DOM_SID domain_sid;
+ fstring sid_str;
+
+ if (argc > 0) {
+ d_printf("usage: net getdomainsid\n");
+ return 1;
+ }
+
+ if(!initialize_password_db(false, NULL)) {
+ DEBUG(0, ("WARNING: Could not open passdb - domain SID may "
+ "not reflect passdb\n"
+ "backend knowledge (such as the SID stored in "
+ "LDAP)\n"));
+ }
+
+ /* first check to see if we can even access secrets, so we don't
+ panic when we can't. */
+
+ if (!secrets_init()) {
+ d_fprintf(stderr, "Unable to open secrets.tdb. Can't fetch domain"
+ "SID for name: %s\n", get_global_sam_name());
+ return 1;
+ }
+
+ /* Generate one, if it doesn't exist */
+ get_global_sam_sid();
+
+ if (!secrets_fetch_domain_sid(global_myname(), &domain_sid)) {
+ d_fprintf(stderr, "Could not fetch local SID\n");
+ return 1;
+ }
+ sid_to_fstring(sid_str, &domain_sid);
+ d_printf("SID for local machine %s is: %s\n", global_myname(), sid_str);
+
+ if (!secrets_fetch_domain_sid(c->opt_workgroup, &domain_sid)) {
+ d_fprintf(stderr, "Could not fetch domain SID\n");
+ return 1;
+ }
+
+ sid_to_fstring(sid_str, &domain_sid);
+ d_printf("SID for domain %s is: %s\n", c->opt_workgroup, sid_str);
+
+ return 0;
+}
+
+static bool search_maxrid(struct pdb_search *search, const char *type,
+ uint32 *max_rid)
+{
+ struct samr_displayentry *entries;
+ uint32 i, num_entries;
+
+ if (search == NULL) {
+ d_fprintf(stderr, "get_maxrid: Could not search %s\n", type);
+ return false;
+ }
+
+ num_entries = pdb_search_entries(search, 0, 0xffffffff, &entries);
+ for (i=0; i<num_entries; i++)
+ *max_rid = MAX(*max_rid, entries[i].rid);
+ pdb_search_destroy(search);
+ return true;
+}
+
+static uint32 get_maxrid(void)
+{
+ uint32 max_rid = 0;
+
+ if (!search_maxrid(pdb_search_users(0), "users", &max_rid))
+ return 0;
+
+ if (!search_maxrid(pdb_search_groups(), "groups", &max_rid))
+ return 0;
+
+ if (!search_maxrid(pdb_search_aliases(get_global_sam_sid()),
+ "aliases", &max_rid))
+ return 0;
+
+ return max_rid;
+}
+
+static int net_maxrid(struct net_context *c, int argc, const char **argv)
+{
+ uint32 rid;
+
+ if (argc != 0) {
+ DEBUG(0, ("usage: net maxrid\n"));
+ return 1;
+ }
+
+ if ((rid = get_maxrid()) == 0) {
+ DEBUG(0, ("can't get current maximum rid\n"));
+ return 1;
+ }
+
+ d_printf("Currently used maximum rid: %d\n", rid);
+
+ return 0;
+}
+
+/* main function table */
+static struct functable net_func[] = {
+ {
+ "rpc",
+ net_rpc,
+ NET_TRANSPORT_RPC,
+ "Run functions using RPC transport",
+ " Use 'net help rpc' to get more extensive information about "
+ "'net rpc' commands."
+ },
+ {
+ "rap",
+ net_rap,
+ NET_TRANSPORT_RAP,
+ "Run functions using RAP transport",
+ " Use 'net help rap' to get more extensive information about "
+ "'net rap' commands."
+ },
+ {
+ "ads",
+ net_ads,
+ NET_TRANSPORT_ADS,
+ "Run functions using ADS transport",
+ " Use 'net help ads' to get more extensive information about "
+ "'net ads' commands."
+ },
+
+ /* eventually these should auto-choose the transport ... */
+ {
+ "file",
+ net_file,
+ NET_TRANSPORT_RPC | NET_TRANSPORT_RAP,
+ "Functions on remote opened files",
+ " Use 'net help file' to get more information about 'net "
+ "file' commands."
+ },
+ {
+ "share",
+ net_share,
+ NET_TRANSPORT_RPC | NET_TRANSPORT_RAP,
+ "Functions on shares",
+ " Use 'net help share' to get more information about 'net "
+ "share' commands."
+ },
+ {
+ "session",
+ net_rap_session,
+ NET_TRANSPORT_RAP,
+ "Manage sessions",
+ " Use 'net help session' to get more information about 'net "
+ "session' commands."
+ },
+ {
+ "server",
+ net_rap_server,
+ NET_TRANSPORT_RAP,
+ "List servers in workgroup",
+ " Use 'net help server' to get more information about 'net "
+ "server' commands."
+ },
+ {
+ "domain",
+ net_rap_domain,
+ NET_TRANSPORT_RAP,
+ "List domains/workgroups on network",
+ " Use 'net help domain' to get more information about 'net "
+ "domain' commands."
+ },
+ {
+ "printq",
+ net_rap_printq,
+ NET_TRANSPORT_RAP,
+ "Modify printer queue",
+ " Use 'net help printq' to get more information about 'net "
+ "printq' commands."
+ },
+ {
+ "user",
+ net_user,
+ NET_TRANSPORT_ADS | NET_TRANSPORT_RPC | NET_TRANSPORT_RAP,
+ "Manage users",
+ " Use 'net help user' to get more information about 'net "
+ "user' commands."
+ },
+ {
+ "group",
+ net_group,
+ NET_TRANSPORT_ADS | NET_TRANSPORT_RPC | NET_TRANSPORT_RAP,
+ "Manage groups",
+ " Use 'net help group' to get more information about 'net "
+ "group' commands."
+ },
+ {
+ "groupmap",
+ net_groupmap,
+ NET_TRANSPORT_LOCAL,
+ "Manage group mappings",
+ " Use 'net help groupmap' to get more information about 'net "
+ "groupmap' commands."
+ },
+ {
+ "sam",
+ net_sam,
+ NET_TRANSPORT_LOCAL,
+ "Functions on the SAM database",
+ " Use 'net help sam' to get more information about 'net sam' "
+ "commands."
+ },
+ {
+ "validate",
+ net_rap_validate,
+ NET_TRANSPORT_RAP,
+ "Validate username and password",
+ " Use 'net help validate' to get more information about 'net "
+ "validate' commands."
+ },
+ {
+ "groupmember",
+ net_rap_groupmember,
+ NET_TRANSPORT_RAP,
+ "Modify group memberships",
+ " Use 'net help groupmember' to get more information about "
+ "'net groupmember' commands."
+ },
+ { "admin",
+ net_rap_admin,
+ NET_TRANSPORT_RAP,
+ "Execute remote command on a remote OS/2 server",
+ " Use 'net help admin' to get more information about 'net "
+ "admin' commands."
+ },
+ { "service",
+ net_rap_service,
+ NET_TRANSPORT_RAP,
+ "List/modify running services",
+ " Use 'net help service' to get more information about 'net "
+ "service' commands."
+ },
+ {
+ "password",
+ net_rap_password,
+ NET_TRANSPORT_RAP,
+ "Change user password on target server",
+ " Use 'net help password' to get more information about 'net "
+ "password' commands."
+ },
+ { "changetrustpw",
+ net_changetrustpw,
+ NET_TRANSPORT_ADS | NET_TRANSPORT_RPC,
+ "Change the trust password",
+ " Use 'net help changetrustpw' to get more information about "
+ "'net changetrustpw'."
+ },
+ { "changesecretpw",
+ net_changesecretpw,
+ NET_TRANSPORT_LOCAL,
+ "Change the secret password",
+ " net [options] changesecretpw\n"
+ " Change the ADS domain member machine account password in "
+ "secrets.tdb.\n"
+ " Do NOT use this function unless you know what it does.\n"
+ " Requires the -f flag to work."
+ },
+ { "time",
+ net_time,
+ NET_TRANSPORT_LOCAL,
+ "Show/set time",
+ " Use 'net help time' to get more information about 'net "
+ "time' commands."
+ },
+ { "lookup",
+ net_lookup,
+ NET_TRANSPORT_LOCAL,
+ "Look up host names/IP addresses",
+ " Use 'net help lookup' to get more information about 'net "
+ "lookup' commands."
+ },
+ { "join",
+ net_join,
+ NET_TRANSPORT_ADS | NET_TRANSPORT_RPC,
+ "Join a domain/AD",
+ " Use 'net help join' to get more information about 'net "
+ "join'."
+ },
+ { "dom",
+ net_dom,
+ NET_TRANSPORT_LOCAL,
+ "Join/unjoin (remote) machines to/from a domain/AD",
+ " Use 'net help dom' to get more information about 'net dom' "
+ "commands."
+ },
+ { "cache",
+ net_cache,
+ NET_TRANSPORT_LOCAL,
+ "Operate on the cache tdb file",
+ " Use 'net help cache' to get more information about 'net "
+ "cache' commands."
+ },
+ { "getlocalsid",
+ net_getlocalsid,
+ NET_TRANSPORT_LOCAL,
+ "Get the SID for the local domain",
+ " net getlocalsid"
+ },
+ { "setlocalsid",
+ net_setlocalsid,
+ NET_TRANSPORT_LOCAL,
+ "Set the SID for the local domain",
+ " net setlocalsid S-1-5-21-x-y-z"
+ },
+ { "setdomainsid",
+ net_setdomainsid,
+ NET_TRANSPORT_LOCAL,
+ "Set domain SID on member servers",
+ " net setdomainsid S-1-5-21-x-y-z"
+ },
+ { "getdomainsid",
+ net_getdomainsid,
+ NET_TRANSPORT_LOCAL,
+ "Get domain SID on member servers",
+ " net getdomainsid"
+ },
+ { "maxrid",
+ net_maxrid,
+ NET_TRANSPORT_LOCAL,
+ "Display the maximul RID currently used",
+ " net maxrid"
+ },
+ { "idmap",
+ net_idmap,
+ NET_TRANSPORT_LOCAL,
+ "IDmap functions",
+ " Use 'net help idmap to get more information about 'net "
+ "idmap' commands."
+ },
+ { "status",
+ net_status,
+ NET_TRANSPORT_LOCAL,
+ "Display server status",
+ " Use 'net help status' to get more information about 'net "
+ "status' commands."
+ },
+ { "usershare",
+ net_usershare,
+ NET_TRANSPORT_LOCAL,
+ "Manage user-modifiable shares",
+ " Use 'net help usershare to get more information about 'net "
+ "usershare' commands."
+ },
+ { "usersidlist",
+ net_usersidlist,
+ NET_TRANSPORT_RPC,
+ "Display list of all users with SID",
+ " Use 'net help usersidlist' to get more information about "
+ "'net usersidlist'."
+ },
+ { "conf",
+ net_conf,
+ NET_TRANSPORT_LOCAL,
+ "Manage Samba registry based configuration",
+ " Use 'net help conf' to get more information about 'net "
+ "conf' commands."
+ },
+ { "registry",
+ net_registry,
+ NET_TRANSPORT_LOCAL,
+ "Manage the Samba registry",
+ " Use 'net help registry' to get more information about 'net "
+ "registry' commands."
+ },
+#ifdef WITH_FAKE_KASERVER
+ { "afs",
+ net_afs,
+ NET_TRANSPORT_LOCAL,
+ "Manage AFS tokens",
+ " Use 'net help afs' to get more information about 'net afs' "
+ "commands."
+ },
+#endif
+
+ { "help",
+ net_help,
+ NET_TRANSPORT_LOCAL,
+ "Print usage information",
+ " Use 'net help help' to list usage information for 'net' "
+ "commands."
+ },
+ {NULL, NULL, 0, NULL, NULL}
+};
+
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc, const char **argv)
+{
+ int opt,i;
+ char *p;
+ int rc = 0;
+ int argc_new = 0;
+ const char ** argv_new;
+ poptContext pc;
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct net_context *c = talloc_zero(frame, struct net_context);
+
+ struct poptOption long_options[] = {
+ {"help", 'h', POPT_ARG_NONE, 0, 'h'},
+ {"workgroup", 'w', POPT_ARG_STRING, &c->opt_target_workgroup},
+ {"user", 'U', POPT_ARG_STRING, &c->opt_user_name, 'U'},
+ {"ipaddress", 'I', POPT_ARG_STRING, 0,'I'},
+ {"port", 'p', POPT_ARG_INT, &c->opt_port},
+ {"myname", 'n', POPT_ARG_STRING, &c->opt_requester_name},
+ {"server", 'S', POPT_ARG_STRING, &c->opt_host},
+ {"encrypt", 'e', POPT_ARG_NONE, NULL, 'e', "Encrypt SMB transport (UNIX extended servers only)" },
+ {"container", 'c', POPT_ARG_STRING, &c->opt_container},
+ {"comment", 'C', POPT_ARG_STRING, &c->opt_comment},
+ {"maxusers", 'M', POPT_ARG_INT, &c->opt_maxusers},
+ {"flags", 'F', POPT_ARG_INT, &c->opt_flags},
+ {"long", 'l', POPT_ARG_NONE, &c->opt_long_list_entries},
+ {"reboot", 'r', POPT_ARG_NONE, &c->opt_reboot},
+ {"force", 'f', POPT_ARG_NONE, &c->opt_force},
+ {"stdin", 'i', POPT_ARG_NONE, &c->opt_stdin},
+ {"timeout", 't', POPT_ARG_INT, &c->opt_timeout},
+ {"machine-pass",'P', POPT_ARG_NONE, &c->opt_machine_pass},
+ {"kerberos", 'k', POPT_ARG_NONE, &c->opt_kerberos},
+ {"myworkgroup", 'W', POPT_ARG_STRING, &c->opt_workgroup},
+ {"verbose", 'v', POPT_ARG_NONE, &c->opt_verbose},
+ {"test", 'T', POPT_ARG_NONE, &c->opt_testmode},
+ /* Options for 'net groupmap set' */
+ {"local", 'L', POPT_ARG_NONE, &c->opt_localgroup},
+ {"domain", 'D', POPT_ARG_NONE, &c->opt_domaingroup},
+ {"ntname", 'N', POPT_ARG_STRING, &c->opt_newntname},
+ {"rid", 'R', POPT_ARG_INT, &c->opt_rid},
+ /* Options for 'net rpc share migrate' */
+ {"acls", 0, POPT_ARG_NONE, &c->opt_acls},
+ {"attrs", 0, POPT_ARG_NONE, &c->opt_attrs},
+ {"timestamps", 0, POPT_ARG_NONE, &c->opt_timestamps},
+ {"exclude", 'X', POPT_ARG_STRING, &c->opt_exclude},
+ {"destination", 0, POPT_ARG_STRING, &c->opt_destination},
+ {"tallocreport", 0, POPT_ARG_NONE, &c->do_talloc_report},
+ /* Options for 'net rpc vampire (keytab)' */
+ {"force-full-repl", 0, POPT_ARG_NONE, &c->opt_force_full_repl},
+ {"single-obj-repl", 0, POPT_ARG_NONE, &c->opt_single_obj_repl},
+ {"clean-old-entries", 0, POPT_ARG_NONE, &c->opt_clean_old_entries},
+
+ POPT_COMMON_SAMBA
+ { 0, 0, 0, 0}
+ };
+
+
+ zero_addr(&c->opt_dest_ip);
+
+ load_case_tables();
+
+ /* set default debug level to 0 regardless of what smb.conf sets */
+ DEBUGLEVEL_CLASS[DBGC_ALL] = 0;
+ dbf = x_stderr;
+ c->private_data = net_func;
+
+ pc = poptGetContext(NULL, argc, (const char **) argv, long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'h':
+ c->display_usage = true;
+ break;
+ case 'e':
+ c->smb_encrypt = true;
+ break;
+ case 'I':
+ if (!interpret_string_addr(&c->opt_dest_ip,
+ poptGetOptArg(pc), 0)) {
+ d_fprintf(stderr, "\nInvalid ip address specified\n");
+ } else {
+ c->opt_have_ip = true;
+ }
+ break;
+ case 'U':
+ c->opt_user_specified = true;
+ c->opt_user_name = SMB_STRDUP(c->opt_user_name);
+ p = strchr(c->opt_user_name,'%');
+ if (p) {
+ *p = 0;
+ c->opt_password = p+1;
+ }
+ break;
+ default:
+ d_fprintf(stderr, "\nInvalid option %s: %s\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ net_help(c, argc, argv);
+ exit(1);
+ }
+ }
+
+ /*
+ * Don't load debug level from smb.conf. It should be
+ * set by cmdline arg or remain default (0)
+ */
+ AllowDebugChange = false;
+ lp_load(get_dyn_CONFIGFILE(), true, false, false, true);
+
+ argv_new = (const char **)poptGetArgs(pc);
+
+ argc_new = argc;
+ for (i=0; i<argc; i++) {
+ if (argv_new[i] == NULL) {
+ argc_new = i;
+ break;
+ }
+ }
+
+ if (c->do_talloc_report) {
+ talloc_enable_leak_report();
+ }
+
+ if (c->opt_requester_name) {
+ set_global_myname(c->opt_requester_name);
+ }
+
+ if (!c->opt_user_name && getenv("LOGNAME")) {
+ c->opt_user_name = getenv("LOGNAME");
+ }
+
+ if (!c->opt_workgroup) {
+ c->opt_workgroup = smb_xstrdup(lp_workgroup());
+ }
+
+ if (!c->opt_target_workgroup) {
+ c->opt_target_workgroup = smb_xstrdup(lp_workgroup());
+ }
+
+ if (!init_names())
+ exit(1);
+
+ load_interfaces();
+
+ /* this makes sure that when we do things like call scripts,
+ that it won't assert becouse we are not root */
+ sec_init();
+
+ if (c->opt_machine_pass) {
+ /* it is very useful to be able to make ads queries as the
+ machine account for testing purposes and for domain leave */
+
+ net_use_krb_machine_account(c);
+ }
+
+ if (!c->opt_password) {
+ c->opt_password = getenv("PASSWD");
+ }
+
+ rc = net_run_function(c, argc_new-1, argv_new+1, "net", net_func);
+
+ DEBUG(2,("return code = %d\n", rc));
+
+ libnetapi_free(c->netapi_ctx);
+
+ poptFreeContext(pc);
+
+ TALLOC_FREE(frame);
+ return rc;
+}
diff --git a/source3/utils/net.h b/source3/utils/net.h
new file mode 100644
index 0000000000..5dc2b11d4e
--- /dev/null
+++ b/source3/utils/net.h
@@ -0,0 +1,152 @@
+/*
+ Samba Unix/Linux SMB client library
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/*
+ * A function of this type is passed to the '
+ * run_rpc_command' wrapper. Must go before the net_proto.h
+ * include
+ */
+
+#include "lib/netapi/netapi.h"
+#include "libnet/libnet.h"
+
+struct net_context {
+ const char *opt_requester_name;
+ const char *opt_host;
+ const char *opt_password;
+ const char *opt_user_name;
+ bool opt_user_specified;
+ const char *opt_workgroup;
+ int opt_long_list_entries;
+ int opt_reboot;
+ int opt_force;
+ int opt_stdin;
+ int opt_port;
+ int opt_verbose;
+ int opt_maxusers;
+ const char *opt_comment;
+ const char *opt_container;
+ int opt_flags;
+ int opt_timeout;
+ const char *opt_target_workgroup;
+ int opt_machine_pass;
+ int opt_localgroup;
+ int opt_domaingroup;
+ int do_talloc_report;
+ const char *opt_newntname;
+ int opt_rid;
+ int opt_acls;
+ int opt_attrs;
+ int opt_timestamps;
+ const char *opt_exclude;
+ const char *opt_destination;
+ int opt_testmode;
+ bool opt_kerberos;
+ int opt_force_full_repl;
+ int opt_single_obj_repl;
+ int opt_clean_old_entries;
+
+ int opt_have_ip;
+ struct sockaddr_storage opt_dest_ip;
+ bool smb_encrypt;
+ struct libnetapi_ctx *netapi_ctx;
+
+ bool display_usage;
+ void *private_data;
+};
+
+#define NET_TRANSPORT_LOCAL 0x01
+#define NET_TRANSPORT_RAP 0x02
+#define NET_TRANSPORT_RPC 0x04
+#define NET_TRANSPORT_ADS 0x08
+
+struct functable {
+ const char *funcname;
+ int (*fn)(struct net_context *c, int argc, const char **argv);
+ int valid_transports;
+ const char *description;
+ const char *usage;
+};
+
+typedef NTSTATUS (*rpc_command_fn)(struct net_context *c,
+ const DOM_SID *,
+ const char *,
+ struct cli_state *cli,
+ struct rpc_pipe_client *,
+ TALLOC_CTX *,
+ int,
+ const char **);
+
+typedef struct copy_clistate {
+ TALLOC_CTX *mem_ctx;
+ struct cli_state *cli_share_src;
+ struct cli_state *cli_share_dst;
+ char *cwd;
+ uint16 attribute;
+ struct net_context *c;
+}copy_clistate;
+
+struct rpc_sh_ctx {
+ struct cli_state *cli;
+
+ DOM_SID *domain_sid;
+ const char *domain_name;
+
+ const char *whoami;
+ const char *thiscmd;
+ struct rpc_sh_cmd *cmds;
+ struct rpc_sh_ctx *parent;
+};
+
+struct rpc_sh_cmd {
+ const char *name;
+ struct rpc_sh_cmd *(*sub)(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx);
+ const struct ndr_syntax_id *interface;
+ NTSTATUS (*fn)(struct net_context *c, TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv);
+ const char *help;
+};
+
+enum netdom_domain_t { ND_TYPE_NT4, ND_TYPE_AD };
+
+/* INCLUDE FILES */
+
+#include "utils/net_proto.h"
+#include "utils/net_help_common.h"
+
+/* MACROS & DEFINES */
+
+#define NET_FLAGS_MASTER 0x00000001
+#define NET_FLAGS_DMB 0x00000002
+#define NET_FLAGS_LOCALHOST_DEFAULT_INSANE 0x00000004 /* Would it be insane to set 'localhost'
+ as the default remote host for this
+ operation? For example, localhost
+ is insane for a 'join' operation. */
+#define NET_FLAGS_PDC 0x00000008 /* PDC only */
+#define NET_FLAGS_ANONYMOUS 0x00000010 /* use an anonymous connection */
+#define NET_FLAGS_NO_PIPE 0x00000020 /* don't open an RPC pipe */
+#define NET_FLAGS_SIGN 0x00000040 /* sign RPC connection */
+#define NET_FLAGS_SEAL 0x00000080 /* seal RPC connection */
+
+/* net share operation modes */
+#define NET_MODE_SHARE_MIGRATE 1
+
diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
new file mode 100644
index 0000000000..7dbe518c3d
--- /dev/null
+++ b/source3/utils/net_ads.c
@@ -0,0 +1,2586 @@
+/*
+ Samba Unix/Linux SMB client library
+ net ads commands
+ Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+ Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
+ Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
+ Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+#ifdef HAVE_ADS
+
+/* when we do not have sufficient input parameters to contact a remote domain
+ * we always fall back to our own realm - Guenther*/
+
+static const char *assume_own_realm(struct net_context *c)
+{
+ if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
+ return lp_realm();
+ }
+
+ return NULL;
+}
+
+/*
+ do a cldap netlogon query
+*/
+static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
+{
+ char addr[INET6_ADDRSTRLEN];
+ struct nbt_cldap_netlogon_5 reply;
+
+ print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
+ if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
+ d_fprintf(stderr, "CLDAP query failed!\n");
+ return -1;
+ }
+
+ d_printf("Information for Domain Controller: %s\n\n",
+ addr);
+
+ d_printf("Response Type: ");
+ switch (reply.type) {
+ case SAMLOGON_AD_UNK_R:
+ d_printf("SAMLOGON\n");
+ break;
+ case SAMLOGON_AD_R:
+ d_printf("SAMLOGON_USER\n");
+ break;
+ default:
+ d_printf("0x%x\n", reply.type);
+ break;
+ }
+
+ d_printf("GUID: %s\n", smb_uuid_string(talloc_tos(), reply.domain_uuid));
+
+ d_printf("Flags:\n"
+ "\tIs a PDC: %s\n"
+ "\tIs a GC of the forest: %s\n"
+ "\tIs an LDAP server: %s\n"
+ "\tSupports DS: %s\n"
+ "\tIs running a KDC: %s\n"
+ "\tIs running time services: %s\n"
+ "\tIs the closest DC: %s\n"
+ "\tIs writable: %s\n"
+ "\tHas a hardware clock: %s\n"
+ "\tIs a non-domain NC serviced by LDAP server: %s\n"
+ "\tIs NT6 DC that has some secrets: %s\n"
+ "\tIs NT6 DC that has all secrets: %s\n",
+ (reply.server_type & NBT_SERVER_PDC) ? "yes" : "no",
+ (reply.server_type & NBT_SERVER_GC) ? "yes" : "no",
+ (reply.server_type & NBT_SERVER_LDAP) ? "yes" : "no",
+ (reply.server_type & NBT_SERVER_DS) ? "yes" : "no",
+ (reply.server_type & NBT_SERVER_KDC) ? "yes" : "no",
+ (reply.server_type & NBT_SERVER_TIMESERV) ? "yes" : "no",
+ (reply.server_type & NBT_SERVER_CLOSEST) ? "yes" : "no",
+ (reply.server_type & NBT_SERVER_WRITABLE) ? "yes" : "no",
+ (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? "yes" : "no",
+ (reply.server_type & NBT_SERVER_NDNC) ? "yes" : "no",
+ (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? "yes" : "no",
+ (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? "yes" : "no");
+
+
+ printf("Forest:\t\t\t%s\n", reply.forest);
+ printf("Domain:\t\t\t%s\n", reply.dns_domain);
+ printf("Domain Controller:\t%s\n", reply.pdc_dns_name);
+
+ printf("Pre-Win2k Domain:\t%s\n", reply.domain);
+ printf("Pre-Win2k Hostname:\t%s\n", reply.pdc_name);
+
+ if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
+
+ printf("Server Site Name :\t\t%s\n", reply.server_site);
+ printf("Client Site Name :\t\t%s\n", reply.client_site);
+
+ d_printf("NT Version: %d\n", reply.nt_version);
+ d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
+ d_printf("LM20 Token: %.2x\n", reply.lm20_token);
+
+ return 0;
+}
+
+/*
+ this implements the CLDAP based netlogon lookup requests
+ for finding the domain controller of a ADS domain
+*/
+static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads lookup\n"
+ " Find the ADS DC using CLDAP lookup.\n");
+ return 0;
+ }
+
+ if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
+ d_fprintf(stderr, "Didn't find the cldap server!\n");
+ return -1;
+ }
+
+ if (!ads->config.realm) {
+ ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
+ ads->ldap.port = 389;
+ }
+
+ return net_ads_cldap_netlogon(c, ads);
+}
+
+
+
+static int net_ads_info(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ char addr[INET6_ADDRSTRLEN];
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads info\n"
+ " Display information about an Active Directory "
+ "server.\n");
+ return 0;
+ }
+
+ if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
+ d_fprintf(stderr, "Didn't find the ldap server!\n");
+ return -1;
+ }
+
+ if (!ads || !ads->config.realm) {
+ d_fprintf(stderr, "Didn't find the ldap server!\n");
+ return -1;
+ }
+
+ /* Try to set the server's current time since we didn't do a full
+ TCP LDAP session initially */
+
+ if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
+ d_fprintf( stderr, "Failed to get server's current time!\n");
+ }
+
+ print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
+
+ d_printf("LDAP server: %s\n", addr);
+ d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
+ d_printf("Realm: %s\n", ads->config.realm);
+ d_printf("Bind Path: %s\n", ads->config.bind_path);
+ d_printf("LDAP port: %d\n", ads->ldap.port);
+ d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
+
+ d_printf("KDC server: %s\n", ads->auth.kdc_server );
+ d_printf("Server time offset: %d\n", ads->auth.time_offset );
+
+ return 0;
+}
+
+static void use_in_memory_ccache(void) {
+ /* Use in-memory credentials cache so we do not interfere with
+ * existing credentials */
+ setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
+}
+
+static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
+ uint32 auth_flags, ADS_STRUCT **ads_ret)
+{
+ ADS_STRUCT *ads = NULL;
+ ADS_STATUS status;
+ bool need_password = false;
+ bool second_time = false;
+ char *cp;
+ const char *realm = NULL;
+ bool tried_closest_dc = false;
+
+ /* lp_realm() should be handled by a command line param,
+ However, the join requires that realm be set in smb.conf
+ and compares our realm with the remote server's so this is
+ ok until someone needs more flexibility */
+
+ *ads_ret = NULL;
+
+retry_connect:
+ if (only_own_domain) {
+ realm = lp_realm();
+ } else {
+ realm = assume_own_realm(c);
+ }
+
+ ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
+
+ if (!c->opt_user_name) {
+ c->opt_user_name = "administrator";
+ }
+
+ if (c->opt_user_specified) {
+ need_password = true;
+ }
+
+retry:
+ if (!c->opt_password && need_password && !c->opt_machine_pass) {
+ c->opt_password = net_prompt_pass(c, c->opt_user_name);
+ if (!c->opt_password) {
+ ads_destroy(&ads);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ }
+
+ if (c->opt_password) {
+ use_in_memory_ccache();
+ SAFE_FREE(ads->auth.password);
+ ads->auth.password = smb_xstrdup(c->opt_password);
+ }
+
+ ads->auth.flags |= auth_flags;
+ SAFE_FREE(ads->auth.user_name);
+ ads->auth.user_name = smb_xstrdup(c->opt_user_name);
+
+ /*
+ * If the username is of the form "name@realm",
+ * extract the realm and convert to upper case.
+ * This is only used to establish the connection.
+ */
+ if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
+ *cp++ = '\0';
+ SAFE_FREE(ads->auth.realm);
+ ads->auth.realm = smb_xstrdup(cp);
+ strupper_m(ads->auth.realm);
+ }
+
+ status = ads_connect(ads);
+
+ if (!ADS_ERR_OK(status)) {
+
+ if (NT_STATUS_EQUAL(ads_ntstatus(status),
+ NT_STATUS_NO_LOGON_SERVERS)) {
+ DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
+ ads_destroy(&ads);
+ return status;
+ }
+
+ if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
+ need_password = true;
+ second_time = true;
+ goto retry;
+ } else {
+ ads_destroy(&ads);
+ return status;
+ }
+ }
+
+ /* when contacting our own domain, make sure we use the closest DC.
+ * This is done by reconnecting to ADS because only the first call to
+ * ads_connect will give us our own sitename */
+
+ if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
+
+ tried_closest_dc = true; /* avoid loop */
+
+ if (!ads->config.tried_closest_dc) {
+
+ namecache_delete(ads->server.realm, 0x1C);
+ namecache_delete(ads->server.workgroup, 0x1C);
+
+ ads_destroy(&ads);
+ ads = NULL;
+
+ goto retry_connect;
+ }
+ }
+
+ *ads_ret = ads;
+ return status;
+}
+
+ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
+{
+ return ads_startup_int(c, only_own_domain, 0, ads);
+}
+
+ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
+{
+ return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
+}
+
+/*
+ Check to see if connection can be made via ads.
+ ads_startup() stores the password in opt_password if it needs to so
+ that rpc or rap can use it without re-prompting.
+*/
+static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+
+ if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
+ return -1;
+ }
+
+ ads->auth.flags |= ADS_AUTH_NO_BIND;
+
+ status = ads_connect(ads);
+ if ( !ADS_ERR_OK(status) ) {
+ return -1;
+ }
+
+ ads_destroy(&ads);
+ return 0;
+}
+
+int net_ads_check_our_domain(struct net_context *c)
+{
+ return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
+}
+
+int net_ads_check(struct net_context *c)
+{
+ return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
+}
+
+/*
+ determine the netbios workgroup name for a domain
+ */
+static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ char addr[INET6_ADDRSTRLEN];
+ struct nbt_cldap_netlogon_5 reply;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads workgroup\n"
+ " Print the workgroup name\n");
+ return 0;
+ }
+
+ if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
+ d_fprintf(stderr, "Didn't find the cldap server!\n");
+ return -1;
+ }
+
+ if (!ads->config.realm) {
+ ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
+ ads->ldap.port = 389;
+ }
+
+ print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
+ if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
+ d_fprintf(stderr, "CLDAP query failed!\n");
+ return -1;
+ }
+
+ d_printf("Workgroup: %s\n", reply.domain);
+
+ ads_destroy(&ads);
+
+ return 0;
+}
+
+
+
+static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
+{
+ char **disp_fields = (char **) data_area;
+
+ if (!field) { /* must be end of record */
+ if (disp_fields[0]) {
+ if (!strchr_m(disp_fields[0], '$')) {
+ if (disp_fields[1])
+ d_printf("%-21.21s %s\n",
+ disp_fields[0], disp_fields[1]);
+ else
+ d_printf("%s\n", disp_fields[0]);
+ }
+ }
+ SAFE_FREE(disp_fields[0]);
+ SAFE_FREE(disp_fields[1]);
+ return true;
+ }
+ if (!values) /* must be new field, indicate string field */
+ return true;
+ if (StrCaseCmp(field, "sAMAccountName") == 0) {
+ disp_fields[0] = SMB_STRDUP((char *) values[0]);
+ }
+ if (StrCaseCmp(field, "description") == 0)
+ disp_fields[1] = SMB_STRDUP((char *) values[0]);
+ return true;
+}
+
+static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
+{
+ return net_user_usage(c, argc, argv);
+}
+
+static int ads_user_add(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ char *upn, *userdn;
+ LDAPMessage *res=NULL;
+ int rc = -1;
+ char *ou_str = NULL;
+
+ if (argc < 1 || c->display_usage)
+ return net_ads_user_usage(c, argc, argv);
+
+ if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
+ return -1;
+ }
+
+ status = ads_find_user_acct(ads, &res, argv[0]);
+
+ if (!ADS_ERR_OK(status)) {
+ d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
+ goto done;
+ }
+
+ if (ads_count_replies(ads, res)) {
+ d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
+ goto done;
+ }
+
+ if (c->opt_container) {
+ ou_str = SMB_STRDUP(c->opt_container);
+ } else {
+ ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
+ }
+
+ status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
+
+ if (!ADS_ERR_OK(status)) {
+ d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
+ ads_errstr(status));
+ goto done;
+ }
+
+ /* if no password is to be set, we're done */
+ if (argc == 1) {
+ d_printf("User %s added\n", argv[0]);
+ rc = 0;
+ goto done;
+ }
+
+ /* try setting the password */
+ asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
+ status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
+ ads->auth.time_offset);
+ safe_free(upn);
+ if (ADS_ERR_OK(status)) {
+ d_printf("User %s added\n", argv[0]);
+ rc = 0;
+ goto done;
+ }
+
+ /* password didn't set, delete account */
+ d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
+ argv[0], ads_errstr(status));
+ ads_msgfree(ads, res);
+ status=ads_find_user_acct(ads, &res, argv[0]);
+ if (ADS_ERR_OK(status)) {
+ userdn = ads_get_dn(ads, res);
+ ads_del_dn(ads, userdn);
+ ads_memfree(ads, userdn);
+ }
+
+ done:
+ if (res)
+ ads_msgfree(ads, res);
+ ads_destroy(&ads);
+ SAFE_FREE(ou_str);
+ return rc;
+}
+
+static int ads_user_info(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ LDAPMessage *res;
+ const char *attrs[] = {"memberOf", NULL};
+ char *searchstring=NULL;
+ char **grouplist;
+ char *escaped_user;
+
+ if (argc < 1 || c->display_usage) {
+ return net_ads_user_usage(c, argc, argv);
+ }
+
+ escaped_user = escape_ldap_string_alloc(argv[0]);
+
+ if (!escaped_user) {
+ d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
+ return -1;
+ }
+
+ if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
+ SAFE_FREE(escaped_user);
+ return -1;
+ }
+
+ asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
+ rc = ads_search(ads, &res, searchstring, attrs);
+ safe_free(searchstring);
+
+ if (!ADS_ERR_OK(rc)) {
+ d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
+ ads_destroy(&ads);
+ SAFE_FREE(escaped_user);
+ return -1;
+ }
+
+ grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
+ (LDAPMessage *)res, "memberOf");
+
+ if (grouplist) {
+ int i;
+ char **groupname;
+ for (i=0;grouplist[i];i++) {
+ groupname = ldap_explode_dn(grouplist[i], 1);
+ d_printf("%s\n", groupname[0]);
+ ldap_value_free(groupname);
+ }
+ ldap_value_free(grouplist);
+ }
+
+ ads_msgfree(ads, res);
+ ads_destroy(&ads);
+ SAFE_FREE(escaped_user);
+ return 0;
+}
+
+static int ads_user_delete(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ LDAPMessage *res = NULL;
+ char *userdn;
+
+ if (argc < 1) {
+ return net_ads_user_usage(c, argc, argv);
+ }
+
+ if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
+ return -1;
+ }
+
+ rc = ads_find_user_acct(ads, &res, argv[0]);
+ if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
+ d_printf("User %s does not exist.\n", argv[0]);
+ ads_msgfree(ads, res);
+ ads_destroy(&ads);
+ return -1;
+ }
+ userdn = ads_get_dn(ads, res);
+ ads_msgfree(ads, res);
+ rc = ads_del_dn(ads, userdn);
+ ads_memfree(ads, userdn);
+ if (ADS_ERR_OK(rc)) {
+ d_printf("User %s deleted\n", argv[0]);
+ ads_destroy(&ads);
+ return 0;
+ }
+ d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
+ ads_errstr(rc));
+ ads_destroy(&ads);
+ return -1;
+}
+
+int net_ads_user(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "add",
+ ads_user_add,
+ NET_TRANSPORT_ADS,
+ "Add an AD user",
+ "net ads user add\n"
+ " Add an AD user"
+ },
+ {
+ "info",
+ ads_user_info,
+ NET_TRANSPORT_ADS,
+ "Display information about an AD user",
+ "net ads user info\n"
+ " Display information about an AD user"
+ },
+ {
+ "delete",
+ ads_user_delete,
+ NET_TRANSPORT_ADS,
+ "Delete an AD user",
+ "net ads user delete\n"
+ " Delete an AD user"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ const char *shortattrs[] = {"sAMAccountName", NULL};
+ const char *longattrs[] = {"sAMAccountName", "description", NULL};
+ char *disp_fields[2] = {NULL, NULL};
+
+ if (argc == 0) {
+ if (c->display_usage) {
+ d_printf("Usage:\n");
+ d_printf("net ads user\n"
+ " List AD users\n");
+ net_display_usage_from_functable(func);
+ return 0;
+ }
+
+ if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
+ return -1;
+ }
+
+ if (c->opt_long_list_entries)
+ d_printf("\nUser name Comment"
+ "\n-----------------------------\n");
+
+ rc = ads_do_search_all_fn(ads, ads->config.bind_path,
+ LDAP_SCOPE_SUBTREE,
+ "(objectCategory=user)",
+ c->opt_long_list_entries ? longattrs :
+ shortattrs, usergrp_display,
+ disp_fields);
+ ads_destroy(&ads);
+ return ADS_ERR_OK(rc) ? 0 : -1;
+ }
+
+ return net_run_function(c, argc, argv, "net ads user", func);
+}
+
+static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
+{
+ return net_group_usage(c, argc, argv);
+}
+
+static int ads_group_add(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ LDAPMessage *res=NULL;
+ int rc = -1;
+ char *ou_str = NULL;
+
+ if (argc < 1 || c->display_usage) {
+ return net_ads_group_usage(c, argc, argv);
+ }
+
+ if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
+ return -1;
+ }
+
+ status = ads_find_user_acct(ads, &res, argv[0]);
+
+ if (!ADS_ERR_OK(status)) {
+ d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
+ goto done;
+ }
+
+ if (ads_count_replies(ads, res)) {
+ d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
+ goto done;
+ }
+
+ if (c->opt_container) {
+ ou_str = SMB_STRDUP(c->opt_container);
+ } else {
+ ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
+ }
+
+ status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
+
+ if (ADS_ERR_OK(status)) {
+ d_printf("Group %s added\n", argv[0]);
+ rc = 0;
+ } else {
+ d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
+ ads_errstr(status));
+ }
+
+ done:
+ if (res)
+ ads_msgfree(ads, res);
+ ads_destroy(&ads);
+ SAFE_FREE(ou_str);
+ return rc;
+}
+
+static int ads_group_delete(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ LDAPMessage *res = NULL;
+ char *groupdn;
+
+ if (argc < 1 || c->display_usage) {
+ return net_ads_group_usage(c, argc, argv);
+ }
+
+ if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
+ return -1;
+ }
+
+ rc = ads_find_user_acct(ads, &res, argv[0]);
+ if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
+ d_printf("Group %s does not exist.\n", argv[0]);
+ ads_msgfree(ads, res);
+ ads_destroy(&ads);
+ return -1;
+ }
+ groupdn = ads_get_dn(ads, res);
+ ads_msgfree(ads, res);
+ rc = ads_del_dn(ads, groupdn);
+ ads_memfree(ads, groupdn);
+ if (ADS_ERR_OK(rc)) {
+ d_printf("Group %s deleted\n", argv[0]);
+ ads_destroy(&ads);
+ return 0;
+ }
+ d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
+ ads_errstr(rc));
+ ads_destroy(&ads);
+ return -1;
+}
+
+int net_ads_group(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "add",
+ ads_group_add,
+ NET_TRANSPORT_ADS,
+ "Add an AD group",
+ "net ads group add\n"
+ " Add an AD group"
+ },
+ {
+ "delete",
+ ads_group_delete,
+ NET_TRANSPORT_ADS,
+ "Delete an AD group",
+ "net ads group delete\n"
+ " Delete an AD group"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ const char *shortattrs[] = {"sAMAccountName", NULL};
+ const char *longattrs[] = {"sAMAccountName", "description", NULL};
+ char *disp_fields[2] = {NULL, NULL};
+
+ if (argc == 0) {
+ if (c->display_usage) {
+ d_printf("Usage:\n");
+ d_printf("net ads group\n"
+ " List AD groups\n");
+ net_display_usage_from_functable(func);
+ return 0;
+ }
+
+ if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
+ return -1;
+ }
+
+ if (c->opt_long_list_entries)
+ d_printf("\nGroup name Comment"
+ "\n-----------------------------\n");
+ rc = ads_do_search_all_fn(ads, ads->config.bind_path,
+ LDAP_SCOPE_SUBTREE,
+ "(objectCategory=group)",
+ c->opt_long_list_entries ? longattrs :
+ shortattrs, usergrp_display,
+ disp_fields);
+
+ ads_destroy(&ads);
+ return ADS_ERR_OK(rc) ? 0 : -1;
+ }
+ return net_run_function(c, argc, argv, "net ads group", func);
+}
+
+static int net_ads_status(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ LDAPMessage *res;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads status\n"
+ " Display machine account details\n");
+ return 0;
+ }
+
+ if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
+ return -1;
+ }
+
+ rc = ads_find_machine_acct(ads, &res, global_myname());
+ if (!ADS_ERR_OK(rc)) {
+ d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
+ ads_destroy(&ads);
+ return -1;
+ }
+
+ if (ads_count_replies(ads, res) == 0) {
+ d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
+ ads_destroy(&ads);
+ return -1;
+ }
+
+ ads_dump(ads, res);
+ ads_destroy(&ads);
+ return 0;
+}
+
+/*******************************************************************
+ Leave an AD domain. Windows XP disables the machine account.
+ We'll try the same. The old code would do an LDAP delete.
+ That only worked using the machine creds because added the machine
+ with full control to the computer object's ACL.
+*******************************************************************/
+
+static int net_ads_leave(struct net_context *c, int argc, const char **argv)
+{
+ TALLOC_CTX *ctx;
+ struct libnet_UnjoinCtx *r = NULL;
+ WERROR werr;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads leave\n"
+ " Leave an AD domain\n");
+ return 0;
+ }
+
+ if (!*lp_realm()) {
+ d_fprintf(stderr, "No realm set, are we joined ?\n");
+ return -1;
+ }
+
+ if (!(ctx = talloc_init("net_ads_leave"))) {
+ d_fprintf(stderr, "Could not initialise talloc context.\n");
+ return -1;
+ }
+
+ if (!c->opt_kerberos) {
+ use_in_memory_ccache();
+ }
+
+ werr = libnet_init_UnjoinCtx(ctx, &r);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "Could not initialise unjoin context.\n");
+ return -1;
+ }
+
+ r->in.debug = true;
+ r->in.use_kerberos = c->opt_kerberos;
+ r->in.dc_name = c->opt_host;
+ r->in.domain_name = lp_realm();
+ r->in.admin_account = c->opt_user_name;
+ r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
+ r->in.modify_config = lp_config_backend_is_registry();
+ r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
+ WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
+
+ werr = libnet_Unjoin(ctx, r);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_printf("Failed to leave domain: %s\n",
+ r->out.error_string ? r->out.error_string :
+ get_friendly_werror_msg(werr));
+ goto done;
+ }
+
+ if (W_ERROR_IS_OK(werr)) {
+ d_printf("Deleted account for '%s' in realm '%s'\n",
+ r->in.machine_name, r->out.dns_domain_name);
+ goto done;
+ }
+
+ /* We couldn't delete it - see if the disable succeeded. */
+ if (r->out.disabled_machine_account) {
+ d_printf("Disabled account for '%s' in realm '%s'\n",
+ r->in.machine_name, r->out.dns_domain_name);
+ werr = WERR_OK;
+ goto done;
+ }
+
+ d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
+ r->in.machine_name, r->out.dns_domain_name);
+
+ done:
+ TALLOC_FREE(r);
+ TALLOC_FREE(ctx);
+
+ if (W_ERROR_IS_OK(werr)) {
+ return 0;
+ }
+
+ return -1;
+}
+
+static NTSTATUS net_ads_join_ok(struct net_context *c)
+{
+ ADS_STRUCT *ads = NULL;
+ ADS_STATUS status;
+
+ if (!secrets_init()) {
+ DEBUG(1,("Failed to initialise secrets database\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ net_use_krb_machine_account(c);
+
+ status = ads_startup(c, true, &ads);
+ if (!ADS_ERR_OK(status)) {
+ return ads_ntstatus(status);
+ }
+
+ ads_destroy(&ads);
+ return NT_STATUS_OK;
+}
+
+/*
+ check that an existing join is OK
+ */
+int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
+{
+ NTSTATUS status;
+ use_in_memory_ccache();
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads testjoin\n"
+ " Test if the existing join is ok\n");
+ return 0;
+ }
+
+ /* Display success or failure */
+ status = net_ads_join_ok(c);
+ if (!NT_STATUS_IS_OK(status)) {
+ fprintf(stderr,"Join to domain is not valid: %s\n",
+ get_friendly_nt_error_msg(status));
+ return -1;
+ }
+
+ printf("Join is OK\n");
+ return 0;
+}
+
+/*******************************************************************
+ Simple configu checks before beginning the join
+ ********************************************************************/
+
+static WERROR check_ads_config( void )
+{
+ if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
+ d_printf("Host is not configured as a member server.\n");
+ return WERR_INVALID_DOMAIN_ROLE;
+ }
+
+ if (strlen(global_myname()) > 15) {
+ d_printf("Our netbios name can be at most 15 chars long, "
+ "\"%s\" is %u chars long\n", global_myname(),
+ (unsigned int)strlen(global_myname()));
+ return WERR_INVALID_COMPUTER_NAME;
+ }
+
+ if ( lp_security() == SEC_ADS && !*lp_realm()) {
+ d_fprintf(stderr, "realm must be set in in %s for ADS "
+ "join to succeed.\n", get_dyn_CONFIGFILE());
+ return WERR_INVALID_PARAM;
+ }
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ Send a DNS update request
+*******************************************************************/
+
+#if defined(WITH_DNS_UPDATES)
+#include "dns.h"
+DNS_ERROR DoDNSUpdate(char *pszServerName,
+ const char *pszDomainName, const char *pszHostName,
+ const struct sockaddr_storage *sslist,
+ size_t num_addrs );
+
+static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
+ const char *machine_name,
+ const struct sockaddr_storage *addrs,
+ int num_addrs)
+{
+ struct dns_rr_ns *nameservers = NULL;
+ int ns_count = 0;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ DNS_ERROR dns_err;
+ fstring dns_server;
+ const char *dnsdomain = NULL;
+ char *root_domain = NULL;
+
+ if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
+ d_printf("No DNS domain configured for %s. "
+ "Unable to perform DNS Update.\n", machine_name);
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+ dnsdomain++;
+
+ status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
+ if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
+ /* Child domains often do not have NS records. Look
+ for the NS record for the forest root domain
+ (rootDomainNamingContext in therootDSE) */
+
+ const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
+ LDAPMessage *msg = NULL;
+ char *root_dn;
+ ADS_STATUS ads_status;
+
+ if ( !ads->ldap.ld ) {
+ ads_status = ads_connect( ads );
+ if ( !ADS_ERR_OK(ads_status) ) {
+ DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
+ goto done;
+ }
+ }
+
+ ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
+ "(objectclass=*)", rootname_attrs, &msg);
+ if (!ADS_ERR_OK(ads_status)) {
+ goto done;
+ }
+
+ root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
+ if ( !root_dn ) {
+ ads_msgfree( ads, msg );
+ goto done;
+ }
+
+ root_domain = ads_build_domain( root_dn );
+
+ /* cleanup */
+ ads_msgfree( ads, msg );
+
+ /* try again for NS servers */
+
+ status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
+
+ if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
+ DEBUG(3,("net_ads_join: Failed to find name server for the %s "
+ "realm\n", ads->config.realm));
+ goto done;
+ }
+
+ dnsdomain = root_domain;
+
+ }
+
+ /* Now perform the dns update - we'll try non-secure and if we fail,
+ we'll follow it up with a secure update */
+
+ fstrcpy( dns_server, nameservers[0].hostname );
+
+ dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
+ if (!ERR_DNS_IS_OK(dns_err)) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ }
+
+done:
+
+ SAFE_FREE( root_domain );
+
+ return status;
+}
+
+static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
+{
+ int num_addrs;
+ struct sockaddr_storage *iplist = NULL;
+ fstring machine_name;
+ NTSTATUS status;
+
+ name_to_fqdn( machine_name, global_myname() );
+ strlower_m( machine_name );
+
+ /* Get our ip address (not the 127.0.0.x address but a real ip
+ * address) */
+
+ num_addrs = get_my_ip_address( &iplist );
+ if ( num_addrs <= 0 ) {
+ DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
+ "addresses!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = net_update_dns_internal(mem_ctx, ads, machine_name,
+ iplist, num_addrs);
+ SAFE_FREE( iplist );
+ return status;
+}
+#endif
+
+
+/*******************************************************************
+ ********************************************************************/
+
+static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("net ads join [options]\n");
+ d_printf("Valid options:\n");
+ d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
+ d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
+ d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
+ d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
+ d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
+ d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
+ d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
+ d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
+ d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
+ d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
+ d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
+ d_printf(" the two other attributes.\n");
+
+ return -1;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+int net_ads_join(struct net_context *c, int argc, const char **argv)
+{
+ TALLOC_CTX *ctx = NULL;
+ struct libnet_JoinCtx *r = NULL;
+ const char *domain = lp_realm();
+ WERROR werr = WERR_SETUP_NOT_JOINED;
+ bool createupn = false;
+ const char *machineupn = NULL;
+ const char *create_in_ou = NULL;
+ int i;
+ const char *os_name = NULL;
+ const char *os_version = NULL;
+ bool modify_config = lp_config_backend_is_registry();
+
+ if (c->display_usage)
+ return net_ads_join_usage(c, argc, argv);
+
+ if (!modify_config) {
+
+ werr = check_ads_config();
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "Invalid configuration. Exiting....\n");
+ goto fail;
+ }
+ }
+
+ if (!(ctx = talloc_init("net_ads_join"))) {
+ d_fprintf(stderr, "Could not initialise talloc context.\n");
+ werr = WERR_NOMEM;
+ goto fail;
+ }
+
+ if (!c->opt_kerberos) {
+ use_in_memory_ccache();
+ }
+
+ werr = libnet_init_JoinCtx(ctx, &r);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto fail;
+ }
+
+ /* process additional command line args */
+
+ for ( i=0; i<argc; i++ ) {
+ if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
+ createupn = true;
+ machineupn = get_string_param(argv[i]);
+ }
+ else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
+ if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
+ d_fprintf(stderr, "Please supply a valid OU path.\n");
+ werr = WERR_INVALID_PARAM;
+ goto fail;
+ }
+ }
+ else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
+ if ( (os_name = get_string_param(argv[i])) == NULL ) {
+ d_fprintf(stderr, "Please supply a operating system name.\n");
+ werr = WERR_INVALID_PARAM;
+ goto fail;
+ }
+ }
+ else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
+ if ( (os_version = get_string_param(argv[i])) == NULL ) {
+ d_fprintf(stderr, "Please supply a valid operating system version.\n");
+ werr = WERR_INVALID_PARAM;
+ goto fail;
+ }
+ }
+ else {
+ domain = argv[i];
+ }
+ }
+
+ if (!*domain) {
+ d_fprintf(stderr, "Please supply a valid domain name\n");
+ werr = WERR_INVALID_PARAM;
+ goto fail;
+ }
+
+ /* Do the domain join here */
+
+ r->in.domain_name = domain;
+ r->in.create_upn = createupn;
+ r->in.upn = machineupn;
+ r->in.account_ou = create_in_ou;
+ r->in.os_name = os_name;
+ r->in.os_version = os_version;
+ r->in.dc_name = c->opt_host;
+ r->in.admin_account = c->opt_user_name;
+ r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
+ r->in.debug = true;
+ r->in.use_kerberos = c->opt_kerberos;
+ r->in.modify_config = modify_config;
+ r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
+ WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
+ WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
+
+ werr = libnet_Join(ctx, r);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto fail;
+ }
+
+ /* Check the short name of the domain */
+
+ if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
+ d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
+ d_printf("domain name obtained from the server.\n");
+ d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
+ d_printf("You should set \"workgroup = %s\" in %s.\n",
+ r->out.netbios_domain_name, get_dyn_CONFIGFILE());
+ }
+
+ d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
+
+ if (r->out.dns_domain_name) {
+ d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
+ r->out.dns_domain_name);
+ } else {
+ d_printf("Joined '%s' to domain '%s'\n", r->in.machine_name,
+ r->out.netbios_domain_name);
+ }
+
+#if defined(WITH_DNS_UPDATES)
+ if (r->out.domain_is_ad) {
+ /* We enter this block with user creds */
+ ADS_STRUCT *ads_dns = NULL;
+
+ if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
+ /* kinit with the machine password */
+
+ use_in_memory_ccache();
+ asprintf( &ads_dns->auth.user_name, "%s$", global_myname() );
+ ads_dns->auth.password = secrets_fetch_machine_password(
+ r->out.netbios_domain_name, NULL, NULL );
+ ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
+ strupper_m(ads_dns->auth.realm );
+ ads_kinit_password( ads_dns );
+ }
+
+ if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
+ d_fprintf( stderr, "DNS update failed!\n" );
+ }
+
+ /* exit from this block using machine creds */
+ ads_destroy(&ads_dns);
+ }
+#endif
+ TALLOC_FREE(r);
+ TALLOC_FREE( ctx );
+
+ return 0;
+
+fail:
+ /* issue an overall failure message at the end. */
+ d_printf("Failed to join domain: %s\n",
+ r && r->out.error_string ? r->out.error_string :
+ get_friendly_werror_msg(werr));
+ TALLOC_FREE( ctx );
+
+ return -1;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
+{
+#if defined(WITH_DNS_UPDATES)
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ TALLOC_CTX *ctx;
+
+#ifdef DEVELOPER
+ talloc_enable_leak_report();
+#endif
+
+ if (argc > 0 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads dns register\n"
+ " Register hostname with DNS\n");
+ return -1;
+ }
+
+ if (!(ctx = talloc_init("net_ads_dns"))) {
+ d_fprintf(stderr, "Could not initialise talloc context\n");
+ return -1;
+ }
+
+ status = ads_startup(c, true, &ads);
+ if ( !ADS_ERR_OK(status) ) {
+ DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
+ TALLOC_FREE(ctx);
+ return -1;
+ }
+
+ if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
+ d_fprintf( stderr, "DNS update failed!\n" );
+ ads_destroy( &ads );
+ TALLOC_FREE( ctx );
+ return -1;
+ }
+
+ d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
+
+ ads_destroy(&ads);
+ TALLOC_FREE( ctx );
+
+ return 0;
+#else
+ d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
+ return -1;
+#endif
+}
+
+#if defined(WITH_DNS_UPDATES)
+DNS_ERROR do_gethostbyname(const char *server, const char *host);
+#endif
+
+static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
+{
+#if defined(WITH_DNS_UPDATES)
+ DNS_ERROR err;
+
+#ifdef DEVELOPER
+ talloc_enable_leak_report();
+#endif
+
+ if (argc != 2 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads dns gethostbyname <server> <name>\n"
+ " Look up hostname from the AD\n"
+ " server\tName server to use\n"
+ " name\tName to look up\n");
+ return -1;
+ }
+
+ err = do_gethostbyname(argv[0], argv[1]);
+
+ d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
+#endif
+ return 0;
+}
+
+static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
+{
+ struct functable func[] = {
+ {
+ "register",
+ net_ads_dns_register,
+ NET_TRANSPORT_ADS,
+ "Add host dns entry to AD",
+ "net ads dns register\n"
+ " Add host dns entry to AD"
+ },
+ {
+ "gethostbyname",
+ net_ads_dns_gethostbyname,
+ NET_TRANSPORT_ADS,
+ "Look up host",
+ "net ads dns gethostbyname\n"
+ " Look up host"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net ads dns", func);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(
+"\nnet ads printer search <printer>"
+"\n\tsearch for a printer in the directory\n"
+"\nnet ads printer info <printer> <server>"
+"\n\tlookup info in directory for printer on server"
+"\n\t(note: printer defaults to \"*\", server defaults to local)\n"
+"\nnet ads printer publish <printername>"
+"\n\tpublish printer in directory"
+"\n\t(note: printer name is required)\n"
+"\nnet ads printer remove <printername>"
+"\n\tremove printer from directory"
+"\n\t(note: printer name is required)\n");
+ return -1;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ LDAPMessage *res = NULL;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads printer search\n"
+ " List printers in the AD\n");
+ return 0;
+ }
+
+ if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
+ return -1;
+ }
+
+ rc = ads_find_printers(ads, &res);
+
+ if (!ADS_ERR_OK(rc)) {
+ d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
+ ads_msgfree(ads, res);
+ ads_destroy(&ads);
+ return -1;
+ }
+
+ if (ads_count_replies(ads, res) == 0) {
+ d_fprintf(stderr, "No results found\n");
+ ads_msgfree(ads, res);
+ ads_destroy(&ads);
+ return -1;
+ }
+
+ ads_dump(ads, res);
+ ads_msgfree(ads, res);
+ ads_destroy(&ads);
+ return 0;
+}
+
+static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ const char *servername, *printername;
+ LDAPMessage *res = NULL;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads printer info [printername [servername]]\n"
+ " Display printer info from AD\n"
+ " printername\tPrinter name or wildcard\n"
+ " servername\tName of the print server\n");
+ return 0;
+ }
+
+ if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
+ return -1;
+ }
+
+ if (argc > 0) {
+ printername = argv[0];
+ } else {
+ printername = "*";
+ }
+
+ if (argc > 1) {
+ servername = argv[1];
+ } else {
+ servername = global_myname();
+ }
+
+ rc = ads_find_printer_on_server(ads, &res, printername, servername);
+
+ if (!ADS_ERR_OK(rc)) {
+ d_fprintf(stderr, "Server '%s' not found: %s\n",
+ servername, ads_errstr(rc));
+ ads_msgfree(ads, res);
+ ads_destroy(&ads);
+ return -1;
+ }
+
+ if (ads_count_replies(ads, res) == 0) {
+ d_fprintf(stderr, "Printer '%s' not found\n", printername);
+ ads_msgfree(ads, res);
+ ads_destroy(&ads);
+ return -1;
+ }
+
+ ads_dump(ads, res);
+ ads_msgfree(ads, res);
+ ads_destroy(&ads);
+
+ return 0;
+}
+
+static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ const char *servername, *printername;
+ struct cli_state *cli;
+ struct rpc_pipe_client *pipe_hnd;
+ struct sockaddr_storage server_ss;
+ NTSTATUS nt_status;
+ TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
+ ADS_MODLIST mods = ads_init_mods(mem_ctx);
+ char *prt_dn, *srv_dn, **srv_cn;
+ char *srv_cn_escaped = NULL, *printername_escaped = NULL;
+ LDAPMessage *res = NULL;
+
+ if (argc < 1 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads printer publish <printername> [servername]\n"
+ " Publish printer in AD\n"
+ " printername\tName of the printer\n"
+ " servername\tName of the print server\n");
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ printername = argv[0];
+
+ if (argc == 2) {
+ servername = argv[1];
+ } else {
+ servername = global_myname();
+ }
+
+ /* Get printer data from SPOOLSS */
+
+ resolve_name(servername, &server_ss, 0x20);
+
+ nt_status = cli_full_connection(&cli, global_myname(), servername,
+ &server_ss, 0,
+ "IPC$", "IPC",
+ c->opt_user_name, c->opt_workgroup,
+ c->opt_password ? c->opt_password : "",
+ CLI_FULL_CONNECTION_USE_KERBEROS,
+ Undefined, NULL);
+
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
+ "for %s\n", servername, printername);
+ ads_destroy(&ads);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ /* Publish on AD server */
+
+ ads_find_machine_acct(ads, &res, servername);
+
+ if (ads_count_replies(ads, res) == 0) {
+ d_fprintf(stderr, "Could not find machine account for server %s\n",
+ servername);
+ ads_destroy(&ads);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
+ srv_cn = ldap_explode_dn(srv_dn, 1);
+
+ srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
+ printername_escaped = escape_rdn_val_string_alloc(printername);
+ if (!srv_cn_escaped || !printername_escaped) {
+ SAFE_FREE(srv_cn_escaped);
+ SAFE_FREE(printername_escaped);
+ d_fprintf(stderr, "Internal error, out of memory!");
+ ads_destroy(&ads);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
+
+ SAFE_FREE(srv_cn_escaped);
+ SAFE_FREE(printername_escaped);
+
+ nt_status = cli_rpc_pipe_open_noauth(cli, &syntax_spoolss, &pipe_hnd);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
+ servername);
+ SAFE_FREE(prt_dn);
+ ads_destroy(&ads);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
+ printername))) {
+ SAFE_FREE(prt_dn);
+ ads_destroy(&ads);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
+ if (!ADS_ERR_OK(rc)) {
+ d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
+ SAFE_FREE(prt_dn);
+ ads_destroy(&ads);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ d_printf("published printer\n");
+ SAFE_FREE(prt_dn);
+ ads_destroy(&ads);
+ talloc_destroy(mem_ctx);
+
+ return 0;
+}
+
+static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ const char *servername;
+ char *prt_dn;
+ LDAPMessage *res = NULL;
+
+ if (argc < 1 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads printer remove <printername> [servername]\n"
+ " Remove a printer from the AD\n"
+ " printername\tName of the printer\n"
+ " servername\tName of the print server\n");
+ return -1;
+ }
+
+ if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
+ return -1;
+ }
+
+ if (argc > 1) {
+ servername = argv[1];
+ } else {
+ servername = global_myname();
+ }
+
+ rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
+
+ if (!ADS_ERR_OK(rc)) {
+ d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
+ ads_msgfree(ads, res);
+ ads_destroy(&ads);
+ return -1;
+ }
+
+ if (ads_count_replies(ads, res) == 0) {
+ d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
+ ads_msgfree(ads, res);
+ ads_destroy(&ads);
+ return -1;
+ }
+
+ prt_dn = ads_get_dn(ads, res);
+ ads_msgfree(ads, res);
+ rc = ads_del_dn(ads, prt_dn);
+ ads_memfree(ads, prt_dn);
+
+ if (!ADS_ERR_OK(rc)) {
+ d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
+ ads_destroy(&ads);
+ return -1;
+ }
+
+ ads_destroy(&ads);
+ return 0;
+}
+
+static int net_ads_printer(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "search",
+ net_ads_printer_search,
+ NET_TRANSPORT_ADS,
+ "Search for a printer",
+ "net ads printer search\n"
+ " Search for a printer"
+ },
+ {
+ "info",
+ net_ads_printer_info,
+ NET_TRANSPORT_ADS,
+ "Display printer information",
+ "net ads printer info\n"
+ " Display printer information"
+ },
+ {
+ "publish",
+ net_ads_printer_publish,
+ NET_TRANSPORT_ADS,
+ "Publish a printer",
+ "net ads printer publish\n"
+ " Publish a printer"
+ },
+ {
+ "remove",
+ net_ads_printer_remove,
+ NET_TRANSPORT_ADS,
+ "Delete a printer",
+ "net ads printer remove\n"
+ " Delete a printer"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net ads printer", func);
+}
+
+
+static int net_ads_password(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ const char *auth_principal = c->opt_user_name;
+ const char *auth_password = c->opt_password;
+ char *realm = NULL;
+ char *new_password = NULL;
+ char *chr, *prompt;
+ const char *user;
+ ADS_STATUS ret;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads password <username>\n"
+ " Change password for user\n"
+ " username\tName of user to change password for\n");
+ return 0;
+ }
+
+ if (c->opt_user_name == NULL || c->opt_password == NULL) {
+ d_fprintf(stderr, "You must supply an administrator username/password\n");
+ return -1;
+ }
+
+ if (argc < 1) {
+ d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
+ return -1;
+ }
+
+ user = argv[0];
+ if (!strchr_m(user, '@')) {
+ asprintf(&chr, "%s@%s", argv[0], lp_realm());
+ user = chr;
+ }
+
+ use_in_memory_ccache();
+ chr = strchr_m(auth_principal, '@');
+ if (chr) {
+ realm = ++chr;
+ } else {
+ realm = lp_realm();
+ }
+
+ /* use the realm so we can eventually change passwords for users
+ in realms other than default */
+ if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
+ return -1;
+ }
+
+ /* we don't actually need a full connect, but it's the easy way to
+ fill in the KDC's addresss */
+ ads_connect(ads);
+
+ if (!ads->config.realm) {
+ d_fprintf(stderr, "Didn't find the kerberos server!\n");
+ return -1;
+ }
+
+ if (argv[1]) {
+ new_password = (char *)argv[1];
+ } else {
+ asprintf(&prompt, "Enter new password for %s:", user);
+ new_password = getpass(prompt);
+ free(prompt);
+ }
+
+ ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
+ auth_password, user, new_password, ads->auth.time_offset);
+ if (!ADS_ERR_OK(ret)) {
+ d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
+ ads_destroy(&ads);
+ return -1;
+ }
+
+ d_printf("Password change for %s completed.\n", user);
+ ads_destroy(&ads);
+
+ return 0;
+}
+
+int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ char *host_principal;
+ fstring my_name;
+ ADS_STATUS ret;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads changetrustpw\n"
+ " Change the machine account's trust password\n");
+ return 0;
+ }
+
+ if (!secrets_init()) {
+ DEBUG(1,("Failed to initialise secrets database\n"));
+ return -1;
+ }
+
+ net_use_krb_machine_account(c);
+
+ use_in_memory_ccache();
+
+ if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
+ return -1;
+ }
+
+ fstrcpy(my_name, global_myname());
+ strlower_m(my_name);
+ asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
+ d_printf("Changing password for principal: %s\n", host_principal);
+
+ ret = ads_change_trust_account_password(ads, host_principal);
+
+ if (!ADS_ERR_OK(ret)) {
+ d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
+ ads_destroy(&ads);
+ SAFE_FREE(host_principal);
+ return -1;
+ }
+
+ d_printf("Password change for principal %s succeeded.\n", host_principal);
+
+ if (lp_use_kerberos_keytab()) {
+ d_printf("Attempting to update system keytab with new password.\n");
+ if (ads_keytab_create_default(ads)) {
+ d_printf("Failed to update system keytab.\n");
+ }
+ }
+
+ ads_destroy(&ads);
+ SAFE_FREE(host_principal);
+
+ return 0;
+}
+
+/*
+ help for net ads search
+*/
+static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(
+ "\nnet ads search <expression> <attributes...>\n"
+ "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
+ "The expression is a standard LDAP search expression, and the\n"
+ "attributes are a list of LDAP fields to show in the results.\n\n"
+ "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
+ );
+ net_common_flags_usage(c, argc, argv);
+ return -1;
+}
+
+
+/*
+ general ADS search function. Useful in diagnosing problems in ADS
+*/
+static int net_ads_search(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ const char *ldap_exp;
+ const char **attrs;
+ LDAPMessage *res = NULL;
+
+ if (argc < 1 || c->display_usage) {
+ return net_ads_search_usage(c, argc, argv);
+ }
+
+ if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
+ return -1;
+ }
+
+ ldap_exp = argv[0];
+ attrs = (argv + 1);
+
+ rc = ads_do_search_all(ads, ads->config.bind_path,
+ LDAP_SCOPE_SUBTREE,
+ ldap_exp, attrs, &res);
+ if (!ADS_ERR_OK(rc)) {
+ d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
+ ads_destroy(&ads);
+ return -1;
+ }
+
+ d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
+
+ /* dump the results */
+ ads_dump(ads, res);
+
+ ads_msgfree(ads, res);
+ ads_destroy(&ads);
+
+ return 0;
+}
+
+
+/*
+ help for net ads search
+*/
+static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(
+ "\nnet ads dn <dn> <attributes...>\n"
+ "\nperform a raw LDAP search on a ADS server and dump the results\n"
+ "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
+ "to show in the results\n\n"
+ "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
+ "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
+ );
+ net_common_flags_usage(c, argc, argv);
+ return -1;
+}
+
+
+/*
+ general ADS search function. Useful in diagnosing problems in ADS
+*/
+static int net_ads_dn(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ const char *dn;
+ const char **attrs;
+ LDAPMessage *res = NULL;
+
+ if (argc < 1 || c->display_usage) {
+ return net_ads_dn_usage(c, argc, argv);
+ }
+
+ if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
+ return -1;
+ }
+
+ dn = argv[0];
+ attrs = (argv + 1);
+
+ rc = ads_do_search_all(ads, dn,
+ LDAP_SCOPE_BASE,
+ "(objectclass=*)", attrs, &res);
+ if (!ADS_ERR_OK(rc)) {
+ d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
+ ads_destroy(&ads);
+ return -1;
+ }
+
+ d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
+
+ /* dump the results */
+ ads_dump(ads, res);
+
+ ads_msgfree(ads, res);
+ ads_destroy(&ads);
+
+ return 0;
+}
+
+/*
+ help for net ads sid search
+*/
+static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(
+ "\nnet ads sid <sid> <attributes...>\n"
+ "\nperform a raw LDAP search on a ADS server and dump the results\n"
+ "The SID is in string format, and the attributes are a list of LDAP fields \n"
+ "to show in the results\n\n"
+ "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
+ );
+ net_common_flags_usage(c, argc, argv);
+ return -1;
+}
+
+
+/*
+ general ADS search function. Useful in diagnosing problems in ADS
+*/
+static int net_ads_sid(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ const char *sid_string;
+ const char **attrs;
+ LDAPMessage *res = NULL;
+ DOM_SID sid;
+
+ if (argc < 1 || c->display_usage) {
+ return net_ads_sid_usage(c, argc, argv);
+ }
+
+ if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
+ return -1;
+ }
+
+ sid_string = argv[0];
+ attrs = (argv + 1);
+
+ if (!string_to_sid(&sid, sid_string)) {
+ d_fprintf(stderr, "could not convert sid\n");
+ ads_destroy(&ads);
+ return -1;
+ }
+
+ rc = ads_search_retry_sid(ads, &res, &sid, attrs);
+ if (!ADS_ERR_OK(rc)) {
+ d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
+ ads_destroy(&ads);
+ return -1;
+ }
+
+ d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
+
+ /* dump the results */
+ ads_dump(ads, res);
+
+ ads_msgfree(ads, res);
+ ads_destroy(&ads);
+
+ return 0;
+}
+
+static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
+{
+ int ret;
+ ADS_STRUCT *ads;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads keytab flush\n"
+ " Delete the whole keytab\n");
+ return 0;
+ }
+
+ if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
+ return -1;
+ }
+ ret = ads_keytab_flush(ads);
+ ads_destroy(&ads);
+ return ret;
+}
+
+static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
+{
+ int i;
+ int ret = 0;
+ ADS_STRUCT *ads;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads keytab add <principal> [principal ...]\n"
+ " Add principals to local keytab\n"
+ " principal\tKerberos principal to add to "
+ "keytab\n");
+ return 0;
+ }
+
+ d_printf("Processing principals to add...\n");
+ if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
+ return -1;
+ }
+ for (i = 0; i < argc; i++) {
+ ret |= ads_keytab_add_entry(ads, argv[i]);
+ }
+ ads_destroy(&ads);
+ return ret;
+}
+
+static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ int ret;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads keytab create\n"
+ " Create new default keytab\n");
+ return 0;
+ }
+
+ if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
+ return -1;
+ }
+ ret = ads_keytab_create_default(ads);
+ ads_destroy(&ads);
+ return ret;
+}
+
+static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
+{
+ const char *keytab = NULL;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads keytab list [keytab]\n"
+ " List a local keytab\n"
+ " keytab\tKeytab to list\n");
+ return 0;
+ }
+
+ if (argc >= 1) {
+ keytab = argv[0];
+ }
+
+ return ads_keytab_list(keytab);
+}
+
+
+int net_ads_keytab(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "add",
+ net_ads_keytab_add,
+ NET_TRANSPORT_ADS,
+ "Add a service principal",
+ "net ads keytab add\n"
+ " Add a service principal"
+ },
+ {
+ "create",
+ net_ads_keytab_create,
+ NET_TRANSPORT_ADS,
+ "Create a fresh keytab",
+ "net ads keytab create\n"
+ " Create a fresh keytab"
+ },
+ {
+ "flush",
+ net_ads_keytab_flush,
+ NET_TRANSPORT_ADS,
+ "Remove all keytab entries",
+ "net ads keytab flush\n"
+ " Remove all keytab entries"
+ },
+ {
+ "list",
+ net_ads_keytab_list,
+ NET_TRANSPORT_ADS,
+ "List a keytab",
+ "net ads keytab list\n"
+ " List a keytab"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ if (!lp_use_kerberos_keytab()) {
+ d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
+use keytab functions.\n");
+ }
+
+ return net_run_function(c, argc, argv, "net ads keytab", func);
+}
+
+static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
+{
+ int ret = -1;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads kerberos renew\n"
+ " Renew TGT from existing credential cache\n");
+ return 0;
+ }
+
+ ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
+ if (ret) {
+ d_printf("failed to renew kerberos ticket: %s\n",
+ error_message(ret));
+ }
+ return ret;
+}
+
+static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
+{
+ struct PAC_DATA *pac = NULL;
+ struct PAC_LOGON_INFO *info = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+ NTSTATUS status;
+ int ret = -1;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads kerberos pac\n"
+ " Dump the Kerberos PAC\n");
+ return 0;
+ }
+
+ mem_ctx = talloc_init("net_ads_kerberos_pac");
+ if (!mem_ctx) {
+ goto out;
+ }
+
+ c->opt_password = net_prompt_pass(c, c->opt_user_name);
+
+ status = kerberos_return_pac(mem_ctx,
+ c->opt_user_name,
+ c->opt_password,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ true,
+ true,
+ 2592000, /* one month */
+ &pac);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("failed to query kerberos PAC: %s\n",
+ nt_errstr(status));
+ goto out;
+ }
+
+ info = get_logon_info_from_pac(pac);
+ if (info) {
+ const char *s;
+ s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
+ d_printf("The Pac: %s\n", s);
+ }
+
+ ret = 0;
+ out:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ int ret = -1;
+ NTSTATUS status;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads kerberos kinit\n"
+ " Get Ticket Granting Ticket (TGT) for the user\n");
+ return 0;
+ }
+
+ mem_ctx = talloc_init("net_ads_kerberos_kinit");
+ if (!mem_ctx) {
+ goto out;
+ }
+
+ c->opt_password = net_prompt_pass(c, c->opt_user_name);
+
+ ret = kerberos_kinit_password_ext(c->opt_user_name,
+ c->opt_password,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ true,
+ true,
+ 2592000, /* one month */
+ &status);
+ if (ret) {
+ d_printf("failed to kinit password: %s\n",
+ nt_errstr(status));
+ }
+ out:
+ return ret;
+}
+
+int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "kinit",
+ net_ads_kerberos_kinit,
+ NET_TRANSPORT_ADS,
+ "Retrieve Ticket Granting Ticket (TGT)",
+ "net ads kerberos kinit\n"
+ " Receive Ticket Granting Ticket (TGT)"
+ },
+ {
+ "renew",
+ net_ads_kerberos_renew,
+ NET_TRANSPORT_ADS,
+ "Renew Ticket Granting Ticket from credential cache"
+ "net ads kerberos renew\n"
+ " Renew Ticket Granting Ticket from credential cache"
+ },
+ {
+ "pac",
+ net_ads_kerberos_pac,
+ NET_TRANSPORT_ADS,
+ "Dump Kerberos PAC",
+ "net ads kerberos pac\n"
+ " Dump Kerberos PAC"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net ads kerberos", func);
+}
+
+int net_ads(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "info",
+ net_ads_info,
+ NET_TRANSPORT_ADS,
+ "Display details on remote ADS server",
+ "net ads info\n"
+ " Display details on remote ADS server"
+ },
+ {
+ "join",
+ net_ads_join,
+ NET_TRANSPORT_ADS,
+ "Join the local machine to ADS realm",
+ "net ads join\n"
+ " Join the local machine to ADS realm"
+ },
+ {
+ "testjoin",
+ net_ads_testjoin,
+ NET_TRANSPORT_ADS,
+ "Validate machine account",
+ "net ads testjoin\n"
+ " Validate machine account"
+ },
+ {
+ "leave",
+ net_ads_leave,
+ NET_TRANSPORT_ADS,
+ "Remove the local machine from ADS",
+ "net ads leave\n"
+ " Remove the local machine from ADS"
+ },
+ {
+ "status",
+ net_ads_status,
+ NET_TRANSPORT_ADS,
+ "Display machine account details",
+ "net ads status\n"
+ " Display machine account details"
+ },
+ {
+ "user",
+ net_ads_user,
+ NET_TRANSPORT_ADS,
+ "List/modify users",
+ "net ads user\n"
+ " List/modify users"
+ },
+ {
+ "group",
+ net_ads_group,
+ NET_TRANSPORT_ADS,
+ "List/modify groups",
+ "net ads group\n"
+ " List/modify groups"
+ },
+ {
+ "dns",
+ net_ads_dns,
+ NET_TRANSPORT_ADS,
+ "Issue dynamic DNS update",
+ "net ads dns\n"
+ " Issue dynamic DNS update"
+ },
+ {
+ "password",
+ net_ads_password,
+ NET_TRANSPORT_ADS,
+ "Change user passwords",
+ "net ads password\n"
+ " Change user passwords"
+ },
+ {
+ "changetrustpw",
+ net_ads_changetrustpw,
+ NET_TRANSPORT_ADS,
+ "Change trust account password",
+ "net ads changetrustpw\n"
+ " Change trust account password"
+ },
+ {
+ "printer",
+ net_ads_printer,
+ NET_TRANSPORT_ADS,
+ "List/modify printer entries",
+ "net ads printer\n"
+ " List/modify printer entries"
+ },
+ {
+ "search",
+ net_ads_search,
+ NET_TRANSPORT_ADS,
+ "Issue LDAP search using filter",
+ "net ads search\n"
+ " Issue LDAP search using filter"
+ },
+ {
+ "dn",
+ net_ads_dn,
+ NET_TRANSPORT_ADS,
+ "Issue LDAP search by DN",
+ "net ads dn\n"
+ " Issue LDAP search by DN"
+ },
+ {
+ "sid",
+ net_ads_sid,
+ NET_TRANSPORT_ADS,
+ "Issue LDAP search by SID",
+ "net ads sid\n"
+ " Issue LDAP search by SID"
+ },
+ {
+ "workgroup",
+ net_ads_workgroup,
+ NET_TRANSPORT_ADS,
+ "Display workgroup name",
+ "net ads workgroup\n"
+ " Display the workgroup name"
+ },
+ {
+ "lookup",
+ net_ads_lookup,
+ NET_TRANSPORT_ADS,
+ "Perfom CLDAP query on DC",
+ "net ads lookup\n"
+ " Find the ADS DC using CLDAP lookups"
+ },
+ {
+ "keytab",
+ net_ads_keytab,
+ NET_TRANSPORT_ADS,
+ "Manage local keytab file",
+ "net ads keytab\n"
+ " Manage local keytab file"
+ },
+ {
+ "gpo",
+ net_ads_gpo,
+ NET_TRANSPORT_ADS,
+ "Manage group policy objects",
+ "net ads gpo\n"
+ " Manage group policy objects"
+ },
+ {
+ "kerberos",
+ net_ads_kerberos,
+ NET_TRANSPORT_ADS,
+ "Manage kerberos keytab",
+ "net ads kerberos\n"
+ " Manage kerberos keytab"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net ads", func);
+}
+
+#else
+
+static int net_ads_noads(void)
+{
+ d_fprintf(stderr, "ADS support not compiled in\n");
+ return -1;
+}
+
+int net_ads_keytab(struct net_context *c, int argc, const char **argv)
+{
+ return net_ads_noads();
+}
+
+int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
+{
+ return net_ads_noads();
+}
+
+int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
+{
+ return net_ads_noads();
+}
+
+int net_ads_join(struct net_context *c, int argc, const char **argv)
+{
+ return net_ads_noads();
+}
+
+int net_ads_user(struct net_context *c, int argc, const char **argv)
+{
+ return net_ads_noads();
+}
+
+int net_ads_group(struct net_context *c, int argc, const char **argv)
+{
+ return net_ads_noads();
+}
+
+/* this one shouldn't display a message */
+int net_ads_check(struct net_context *c)
+{
+ return -1;
+}
+
+int net_ads_check_our_domain(struct net_context *c)
+{
+ return -1;
+}
+
+int net_ads(struct net_context *c, int argc, const char **argv)
+{
+ return net_ads_noads();
+}
+
+#endif /* WITH_ADS */
diff --git a/source3/utils/net_ads_gpo.c b/source3/utils/net_ads_gpo.c
new file mode 100644
index 0000000000..3c66325abe
--- /dev/null
+++ b/source3/utils/net_ads_gpo.c
@@ -0,0 +1,695 @@
+/*
+ Samba Unix/Linux SMB client library
+ net ads commands for Group Policy
+ Copyright (C) 2005-2008 Guenther Deschner (gd@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+#ifdef HAVE_ADS
+
+static int net_ads_gpo_refresh(struct net_context *c, int argc, const char **argv)
+{
+ TALLOC_CTX *mem_ctx;
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ const char *dn = NULL;
+ struct GROUP_POLICY_OBJECT *gpo_list = NULL;
+ struct GROUP_POLICY_OBJECT *read_list = NULL;
+ uint32 uac = 0;
+ uint32 flags = 0;
+ struct GROUP_POLICY_OBJECT *gpo;
+ NTSTATUS result;
+ struct nt_user_token *token = NULL;
+
+ if (argc < 1 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads gpo refresh <username|machinename>\n"
+ " Lists all GPOs assigned to an account and "
+ "downloads them\n"
+ " username\tUser to refresh GPOs for\n"
+ " machinename\tMachine to refresh GPOs for\n");
+ return -1;
+ }
+
+ mem_ctx = talloc_init("net_ads_gpo_refresh");
+ if (mem_ctx == NULL) {
+ return -1;
+ }
+
+ status = ads_startup(c, false, &ads);
+ if (!ADS_ERR_OK(status)) {
+ d_printf("failed to connect AD server: %s\n", ads_errstr(status));
+ goto out;
+ }
+
+ status = ads_find_samaccount(ads, mem_ctx, argv[0], &uac, &dn);
+ if (!ADS_ERR_OK(status)) {
+ d_printf("failed to find samaccount for %s\n", argv[0]);
+ goto out;
+ }
+
+ if (uac & UF_WORKSTATION_TRUST_ACCOUNT) {
+ flags |= GPO_LIST_FLAG_MACHINE;
+ }
+
+ d_printf("\n%s: '%s' has dn: '%s'\n\n",
+ (uac & UF_WORKSTATION_TRUST_ACCOUNT) ? "machine" : "user",
+ argv[0], dn);
+
+ d_printf("* fetching token ");
+ if (uac & UF_WORKSTATION_TRUST_ACCOUNT) {
+ status = gp_get_machine_token(ads, mem_ctx, dn, &token);
+ } else {
+ status = ads_get_sid_token(ads, mem_ctx, dn, &token);
+ }
+
+ if (!ADS_ERR_OK(status)) {
+ d_printf("failed: %s\n", ads_errstr(status));
+ goto out;
+ }
+ d_printf("finished\n");
+
+ d_printf("* fetching GPO List ");
+ status = ads_get_gpo_list(ads, mem_ctx, dn, flags, token, &gpo_list);
+ if (!ADS_ERR_OK(status)) {
+ d_printf("failed: %s\n", ads_errstr(status));
+ goto out;
+ }
+ d_printf("finished\n");
+
+ d_printf("* refreshing Group Policy Data ");
+ if (!NT_STATUS_IS_OK(result = check_refresh_gpo_list(ads, mem_ctx,
+ flags,
+ gpo_list))) {
+ d_printf("failed: %s\n", nt_errstr(result));
+ goto out;
+ }
+ d_printf("finished\n");
+
+ d_printf("* storing GPO list to registry ");
+
+ {
+ WERROR werr = gp_reg_state_store(mem_ctx, flags, dn,
+ token, gpo_list);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_printf("failed: %s\n", dos_errstr(werr));
+ goto out;
+ }
+ }
+
+ d_printf("finished\n");
+
+ if (c->opt_verbose) {
+
+ d_printf("* dumping GPO list\n");
+
+ for (gpo = gpo_list; gpo; gpo = gpo->next) {
+
+ dump_gpo(ads, mem_ctx, gpo, 0);
+#if 0
+ char *server, *share, *nt_path, *unix_path;
+
+ d_printf("--------------------------------------\n");
+ d_printf("Name:\t\t\t%s\n", gpo->display_name);
+ d_printf("LDAP GPO version:\t%d (user: %d, machine: %d)\n",
+ gpo->version,
+ GPO_VERSION_USER(gpo->version),
+ GPO_VERSION_MACHINE(gpo->version));
+
+ result = gpo_explode_filesyspath(mem_ctx, gpo->file_sys_path,
+ &server, &share, &nt_path,
+ &unix_path);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_printf("got: %s\n", nt_errstr(result));
+ }
+
+ d_printf("GPO stored on server: %s, share: %s\n", server, share);
+ d_printf("\tremote path:\t%s\n", nt_path);
+ d_printf("\tlocal path:\t%s\n", unix_path);
+#endif
+ }
+ }
+
+ d_printf("* re-reading GPO list from registry ");
+
+ {
+ WERROR werr = gp_reg_state_read(mem_ctx, flags,
+ &token->user_sids[0],
+ &read_list);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_printf("failed: %s\n", dos_errstr(werr));
+ goto out;
+ }
+ }
+
+ d_printf("finished\n");
+
+ if (c->opt_verbose) {
+
+ d_printf("* dumping GPO list from registry\n");
+
+ for (gpo = read_list; gpo; gpo = gpo->next) {
+
+ dump_gpo(ads, mem_ctx, gpo, 0);
+
+#if 0
+ char *server, *share, *nt_path, *unix_path;
+
+ d_printf("--------------------------------------\n");
+ d_printf("Name:\t\t\t%s\n", gpo->display_name);
+ d_printf("LDAP GPO version:\t%d (user: %d, machine: %d)\n",
+ gpo->version,
+ GPO_VERSION_USER(gpo->version),
+ GPO_VERSION_MACHINE(gpo->version));
+
+ result = gpo_explode_filesyspath(mem_ctx, gpo->file_sys_path,
+ &server, &share, &nt_path,
+ &unix_path);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_printf("got: %s\n", nt_errstr(result));
+ }
+
+ d_printf("GPO stored on server: %s, share: %s\n", server, share);
+ d_printf("\tremote path:\t%s\n", nt_path);
+ d_printf("\tlocal path:\t%s\n", unix_path);
+#endif
+ }
+ }
+
+ out:
+ ads_destroy(&ads);
+ talloc_destroy(mem_ctx);
+ return 0;
+}
+
+static int net_ads_gpo_list_all(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ LDAPMessage *res = NULL;
+ int num_reply = 0;
+ LDAPMessage *msg = NULL;
+ struct GROUP_POLICY_OBJECT gpo;
+ TALLOC_CTX *mem_ctx;
+ char *dn;
+ const char *attrs[] = {
+ "versionNumber",
+ "flags",
+ "gPCFileSysPath",
+ "displayName",
+ "name",
+ "gPCMachineExtensionNames",
+ "gPCUserExtensionNames",
+ "ntSecurityDescriptor",
+ NULL
+ };
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads gpo listall\n"
+ " List all GPOs on the DC\n");
+ return 0;
+ }
+
+ mem_ctx = talloc_init("net_ads_gpo_list_all");
+ if (mem_ctx == NULL) {
+ return -1;
+ }
+
+ status = ads_startup(c, false, &ads);
+ if (!ADS_ERR_OK(status)) {
+ goto out;
+ }
+
+ status = ads_do_search_all_sd_flags(ads, ads->config.bind_path,
+ LDAP_SCOPE_SUBTREE,
+ "(objectclass=groupPolicyContainer)",
+ attrs,
+ DACL_SECURITY_INFORMATION,
+ &res);
+
+ if (!ADS_ERR_OK(status)) {
+ d_printf("search failed: %s\n", ads_errstr(status));
+ goto out;
+ }
+
+ num_reply = ads_count_replies(ads, res);
+
+ d_printf("Got %d replies\n\n", num_reply);
+
+ /* dump the results */
+ for (msg = ads_first_entry(ads, res);
+ msg;
+ msg = ads_next_entry(ads, msg)) {
+
+ if ((dn = ads_get_dn(ads, msg)) == NULL) {
+ goto out;
+ }
+
+ status = ads_parse_gpo(ads, mem_ctx, msg, dn, &gpo);
+
+ if (!ADS_ERR_OK(status)) {
+ d_printf("ads_parse_gpo failed: %s\n",
+ ads_errstr(status));
+ ads_memfree(ads, dn);
+ goto out;
+ }
+
+ dump_gpo(ads, mem_ctx, &gpo, 0);
+ ads_memfree(ads, dn);
+ }
+
+out:
+ ads_msgfree(ads, res);
+
+ talloc_destroy(mem_ctx);
+ ads_destroy(&ads);
+
+ return 0;
+}
+
+static int net_ads_gpo_list(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ LDAPMessage *res = NULL;
+ TALLOC_CTX *mem_ctx;
+ const char *dn = NULL;
+ uint32 uac = 0;
+ uint32 flags = 0;
+ struct GROUP_POLICY_OBJECT *gpo_list;
+ struct nt_user_token *token = NULL;
+
+ if (argc < 1 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads gpo list <username|machinename>\n"
+ " Lists all GPOs for machine/user\n"
+ " username\tUser to list GPOs for\n"
+ " machinename\tMachine to list GPOs for\n");
+ return -1;
+ }
+
+ mem_ctx = talloc_init("net_ads_gpo_list");
+ if (mem_ctx == NULL) {
+ goto out;
+ }
+
+ status = ads_startup(c, false, &ads);
+ if (!ADS_ERR_OK(status)) {
+ goto out;
+ }
+
+ status = ads_find_samaccount(ads, mem_ctx, argv[0], &uac, &dn);
+ if (!ADS_ERR_OK(status)) {
+ goto out;
+ }
+
+ if (uac & UF_WORKSTATION_TRUST_ACCOUNT) {
+ flags |= GPO_LIST_FLAG_MACHINE;
+ }
+
+ d_printf("%s: '%s' has dn: '%s'\n",
+ (uac & UF_WORKSTATION_TRUST_ACCOUNT) ? "machine" : "user",
+ argv[0], dn);
+
+ if (uac & UF_WORKSTATION_TRUST_ACCOUNT) {
+ status = gp_get_machine_token(ads, mem_ctx, dn, &token);
+ } else {
+ status = ads_get_sid_token(ads, mem_ctx, dn, &token);
+ }
+
+ if (!ADS_ERR_OK(status)) {
+ goto out;
+ }
+
+ status = ads_get_gpo_list(ads, mem_ctx, dn, flags, token, &gpo_list);
+ if (!ADS_ERR_OK(status)) {
+ goto out;
+ }
+
+ dump_gpo_list(ads, mem_ctx, gpo_list, 0);
+
+out:
+ ads_msgfree(ads, res);
+
+ talloc_destroy(mem_ctx);
+ ads_destroy(&ads);
+
+ return 0;
+}
+
+#if 0
+static int net_ads_gpo_apply(struct net_context *c, int argc, const char **argv)
+{
+ TALLOC_CTX *mem_ctx;
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ const char *dn = NULL;
+ struct GROUP_POLICY_OBJECT *gpo_list;
+ uint32 uac = 0;
+ uint32 flags = 0;
+ struct nt_user_token *token = NULL;
+ const char *filter = NULL;
+
+ if (argc < 1 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads gpo apply <username|machinename>\n"
+ " Apply GPOs for machine/user\n"
+ " username\tUsername to apply GPOs for\n"
+ " machinename\tMachine to apply GPOs for\n");
+ return -1;
+ }
+
+ mem_ctx = talloc_init("net_ads_gpo_apply");
+ if (mem_ctx == NULL) {
+ goto out;
+ }
+
+ if (argc >= 2) {
+ filter = cse_gpo_name_to_guid_string(argv[1]);
+ }
+
+ status = ads_startup(c, false, &ads);
+ if (!ADS_ERR_OK(status)) {
+ d_printf("got: %s\n", ads_errstr(status));
+ goto out;
+ }
+
+ status = ads_find_samaccount(ads, mem_ctx, argv[0], &uac, &dn);
+ if (!ADS_ERR_OK(status)) {
+ d_printf("failed to find samaccount for %s: %s\n",
+ argv[0], ads_errstr(status));
+ goto out;
+ }
+
+ if (uac & UF_WORKSTATION_TRUST_ACCOUNT) {
+ flags |= GPO_LIST_FLAG_MACHINE;
+ }
+
+ if (opt_verbose) {
+ flags |= GPO_INFO_FLAG_VERBOSE;
+ }
+
+ d_printf("%s: '%s' has dn: '%s'\n",
+ (uac & UF_WORKSTATION_TRUST_ACCOUNT) ? "machine" : "user",
+ argv[0], dn);
+
+ if (uac & UF_WORKSTATION_TRUST_ACCOUNT) {
+ status = gp_get_machine_token(ads, mem_ctx, dn, &token);
+ } else {
+ status = ads_get_sid_token(ads, mem_ctx, dn, &token);
+ }
+
+ if (!ADS_ERR_OK(status)) {
+ goto out;
+ }
+
+ status = ads_get_gpo_list(ads, mem_ctx, dn, flags, token, &gpo_list);
+ if (!ADS_ERR_OK(status)) {
+ goto out;
+ }
+
+ status = gpo_process_gpo_list(ads, mem_ctx, token, gpo_list,
+ filter, flags);
+ if (!ADS_ERR_OK(status)) {
+ d_printf("failed to process gpo list: %s\n",
+ ads_errstr(status));
+ goto out;
+ }
+
+out:
+ ads_destroy(&ads);
+ talloc_destroy(mem_ctx);
+ return 0;
+}
+#endif
+
+static int net_ads_gpo_link_get(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ TALLOC_CTX *mem_ctx;
+ struct GP_LINK gp_link;
+
+ if (argc < 1 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads gpo linkget <container>\n"
+ " Lists gPLink of a containter\n"
+ " container\tContainer to get link for\n");
+ return -1;
+ }
+
+ mem_ctx = talloc_init("add_gpo_link");
+ if (mem_ctx == NULL) {
+ return -1;
+ }
+
+ status = ads_startup(c, false, &ads);
+ if (!ADS_ERR_OK(status)) {
+ goto out;
+ }
+
+ status = ads_get_gpo_link(ads, mem_ctx, argv[0], &gp_link);
+ if (!ADS_ERR_OK(status)) {
+ d_printf("get link for %s failed: %s\n", argv[0],
+ ads_errstr(status));
+ goto out;
+ }
+
+ dump_gplink(ads, mem_ctx, &gp_link);
+
+out:
+ talloc_destroy(mem_ctx);
+ ads_destroy(&ads);
+
+ return 0;
+}
+
+static int net_ads_gpo_link_add(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ uint32 gpo_opt = 0;
+ TALLOC_CTX *mem_ctx;
+
+ if (argc < 2 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads gpo linkadd <linkdn> <gpodn> [options]\n"
+ " Link a container to a GPO\n"
+ " linkdn\tContainer to link to a GPO\n"
+ " gpodn\tGPO to link container to\n");
+ d_printf("note: DNs must be provided properly escaped.\n");
+ d_printf("See RFC 4514 for details\n");
+ return -1;
+ }
+
+ mem_ctx = talloc_init("add_gpo_link");
+ if (mem_ctx == NULL) {
+ return -1;
+ }
+
+ if (argc == 3) {
+ gpo_opt = atoi(argv[2]);
+ }
+
+ status = ads_startup(c, false, &ads);
+ if (!ADS_ERR_OK(status)) {
+ goto out;
+ }
+
+ status = ads_add_gpo_link(ads, mem_ctx, argv[0], argv[1], gpo_opt);
+ if (!ADS_ERR_OK(status)) {
+ d_printf("link add failed: %s\n", ads_errstr(status));
+ goto out;
+ }
+
+out:
+ talloc_destroy(mem_ctx);
+ ads_destroy(&ads);
+
+ return 0;
+}
+
+#if 0 /* broken */
+
+static int net_ads_gpo_link_delete(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ TALLOC_CTX *mem_ctx;
+
+ if (argc < 2 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads gpo linkdelete <linkdn> <gpodn>\n"
+ " Delete a GPO link\n"
+ " <linkdn>\tContainer to delete GPO from\n"
+ " <gpodn>\tGPO to delete from container\n");
+ return -1;
+ }
+
+ mem_ctx = talloc_init("delete_gpo_link");
+ if (mem_ctx == NULL) {
+ return -1;
+ }
+
+ status = ads_startup(c, false, &ads);
+ if (!ADS_ERR_OK(status)) {
+ goto out;
+ }
+
+ status = ads_delete_gpo_link(ads, mem_ctx, argv[0], argv[1]);
+ if (!ADS_ERR_OK(status)) {
+ d_printf("delete link failed: %s\n", ads_errstr(status));
+ goto out;
+ }
+
+out:
+ talloc_destroy(mem_ctx);
+ ads_destroy(&ads);
+
+ return 0;
+}
+
+#endif
+
+static int net_ads_gpo_get_gpo(struct net_context *c, int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ TALLOC_CTX *mem_ctx;
+ struct GROUP_POLICY_OBJECT gpo;
+
+ if (argc < 1 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net ads gpo getgpo <gpo>\n"
+ " List speciefied GPO\n"
+ " gpo\t\tGPO to list\n");
+ return -1;
+ }
+
+ mem_ctx = talloc_init("ads_gpo_get_gpo");
+ if (mem_ctx == NULL) {
+ return -1;
+ }
+
+ status = ads_startup(c, false, &ads);
+ if (!ADS_ERR_OK(status)) {
+ goto out;
+ }
+
+ if (strnequal(argv[0], "CN={", strlen("CN={"))) {
+ status = ads_get_gpo(ads, mem_ctx, argv[0], NULL, NULL, &gpo);
+ } else {
+ status = ads_get_gpo(ads, mem_ctx, NULL, argv[0], NULL, &gpo);
+ }
+
+ if (!ADS_ERR_OK(status)) {
+ d_printf("get gpo for [%s] failed: %s\n", argv[0],
+ ads_errstr(status));
+ goto out;
+ }
+
+ dump_gpo(ads, mem_ctx, &gpo, 1);
+
+out:
+ talloc_destroy(mem_ctx);
+ ads_destroy(&ads);
+
+ return 0;
+}
+
+int net_ads_gpo(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+#if 0
+ {
+ "apply",
+ net_ads_gpo_apply,
+ NET_TRANSPORT_ADS,
+ "Apply GPO to container",
+ "net ads gpo apply\n"
+ " Apply GPO to container"
+ },
+#endif
+ {
+ "getgpo",
+ net_ads_gpo_get_gpo,
+ NET_TRANSPORT_ADS,
+ "List specified GPO",
+ "net ads gpo getgpo\n"
+ " List specified GPO"
+ },
+ {
+ "linkadd",
+ net_ads_gpo_link_add,
+ NET_TRANSPORT_ADS,
+ "Link a container to a GPO",
+ "net ads gpo linkadd\n"
+ " Link a container to a GPO"
+ },
+#if 0
+ {
+ "linkdelete",
+ net_ads_gpo_link_delete,
+ NET_TRANSPORT_ADS,
+ "Delete GPO link from a container",
+ "net ads gpo linkdelete\n"
+ " Delete GPO link from a container"
+ },
+#endif
+ {
+ "linkget",
+ net_ads_gpo_link_get,
+ NET_TRANSPORT_ADS,
+ "Lists gPLink of containter",
+ "net ads gpo linkget\n"
+ " Lists gPLink of containter"
+ },
+ {
+ "list",
+ net_ads_gpo_list,
+ NET_TRANSPORT_ADS,
+ "Lists all GPOs for machine/user",
+ "net ads gpo list\n"
+ " Lists all GPOs for machine/user"
+ },
+ {
+ "listall",
+ net_ads_gpo_list_all,
+ NET_TRANSPORT_ADS,
+ "Lists all GPOs on a DC",
+ "net ads gpo listall\n"
+ " Lists all GPOs on a DC"
+ },
+ {
+ "refresh",
+ net_ads_gpo_refresh,
+ NET_TRANSPORT_ADS,
+ "Lists all GPOs assigned to an account and downloads "
+ "them",
+ "net ads gpo refresh\n"
+ " Lists all GPOs assigned to an account and "
+ "downloads them"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net ads gpo", func);
+}
+
+#endif /* HAVE_ADS */
diff --git a/source3/utils/net_afs.c b/source3/utils/net_afs.c
new file mode 100644
index 0000000000..0f19ec1e12
--- /dev/null
+++ b/source3/utils/net_afs.c
@@ -0,0 +1,114 @@
+/*
+ Samba Unix/Linux SMB client library
+ net afs commands
+ Copyright (C) 2003 Volker Lendecke (vl@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+int net_afs_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(" net afs key filename\n"
+ "\tImports a OpenAFS KeyFile into our secrets.tdb\n\n");
+ d_printf(" net afs impersonate <user> <cell>\n"
+ "\tCreates a token for user@cell\n\n");
+ return -1;
+}
+
+int net_afs_key(struct net_context *c, int argc, const char **argv)
+{
+ int fd;
+ struct afs_keyfile keyfile;
+
+ if (argc != 2) {
+ d_printf("usage: 'net afs key <keyfile> cell'\n");
+ return -1;
+ }
+
+ if (!secrets_init()) {
+ d_fprintf(stderr, "Could not open secrets.tdb\n");
+ return -1;
+ }
+
+ if ((fd = open(argv[0], O_RDONLY, 0)) < 0) {
+ d_fprintf(stderr, "Could not open %s\n", argv[0]);
+ return -1;
+ }
+
+ if (read(fd, &keyfile, sizeof(keyfile)) != sizeof(keyfile)) {
+ d_fprintf(stderr, "Could not read keyfile\n");
+ return -1;
+ }
+
+ if (!secrets_store_afs_keyfile(argv[1], &keyfile)) {
+ d_fprintf(stderr, "Could not write keyfile to secrets.tdb\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int net_afs_impersonate(struct net_context *c, int argc,
+ const char **argv)
+{
+ char *token;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: net afs impersonate <user> <cell>\n");
+ exit(1);
+ }
+
+ token = afs_createtoken_str(argv[0], argv[1]);
+
+ if (token == NULL) {
+ fprintf(stderr, "Could not create token\n");
+ exit(1);
+ }
+
+ if (!afs_settoken_str(token)) {
+ fprintf(stderr, "Could not set token into kernel\n");
+ exit(1);
+ }
+
+ printf("Success: %s@%s\n", argv[0], argv[1]);
+ return 0;
+}
+
+int net_afs(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "key",
+ net_afs_key,
+ NET_TRANSPORT_LOCAL,
+ "Import an OpenAFS keyfile",
+ "net afs key <filename>\n"
+ " Import kefile from <filename>."
+ },
+ {
+ "impersonate",
+ net_afs_impersonate,
+ NET_TRANSPORT_LOCAL,
+ "Get a user token",
+ "net afs impersonate <user> <cell>\n"
+ " Create token for user@cell"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+ return net_run_function(c, argc, argv, "net afs", func);
+}
+
diff --git a/source3/utils/net_afs.h b/source3/utils/net_afs.h
new file mode 100644
index 0000000000..31606dd717
--- /dev/null
+++ b/source3/utils/net_afs.h
@@ -0,0 +1,29 @@
+/*
+ Samba Unix/Linux SMB client library
+ net afs commands
+ Copyright (C) 2008 Kai Blin (kai@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NET_AFS_H_
+#define _NET_AFS_H_
+
+int net_afs_usage(struct net_context *c, int argc, const char **argv);
+int net_afs_key(struct net_context *c, int argc, const char **argv);
+int net_afs_impersonate(struct net_context *c, int argc,
+ const char **argv);
+int net_afs(struct net_context *c, int argc, const char **argv);
+
+#endif /*_NET_AFS_H_*/
diff --git a/source3/utils/net_cache.c b/source3/utils/net_cache.c
new file mode 100644
index 0000000000..4e9ae18c0d
--- /dev/null
+++ b/source3/utils/net_cache.c
@@ -0,0 +1,373 @@
+/*
+ Samba Unix/Linux SMB client library
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) Rafal Szczesniak 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "net.h"
+
+/**
+ * @file net_cache.c
+ * @brief This is part of the net tool which is basically command
+ * line wrapper for gencache.c functions (mainly for testing)
+ *
+ **/
+
+
+/*
+ * These routines are used via gencache_iterate() to display the cache's contents
+ * (print_cache_entry) and to flush it (delete_cache_entry).
+ * Both of them are defined by first arg of gencache_iterate() routine.
+ */
+static void print_cache_entry(const char* keystr, const char* datastr,
+ const time_t timeout, void* dptr)
+{
+ char *timeout_str;
+ char *alloc_str = NULL;
+ time_t now_t = time(NULL);
+ struct tm timeout_tm, *now_tm;
+ /* localtime returns statically allocated pointer, so timeout_tm
+ has to be copied somewhere else */
+
+ now_tm = localtime(&timeout);
+ if (!now_tm) {
+ return;
+ }
+ memcpy(&timeout_tm, now_tm, sizeof(struct tm));
+ now_tm = localtime(&now_t);
+ if (!now_tm) {
+ return;
+ }
+
+ /* form up timeout string depending whether it's today's date or not */
+ if (timeout_tm.tm_year != now_tm->tm_year ||
+ timeout_tm.tm_mon != now_tm->tm_mon ||
+ timeout_tm.tm_mday != now_tm->tm_mday) {
+
+ timeout_str = asctime(&timeout_tm);
+ if (!timeout_str) {
+ return;
+ }
+ timeout_str[strlen(timeout_str) - 1] = '\0'; /* remove tailing CR */
+ } else {
+ asprintf(&alloc_str, "%.2d:%.2d:%.2d", timeout_tm.tm_hour,
+ timeout_tm.tm_min, timeout_tm.tm_sec);
+ if (!alloc_str) {
+ return;
+ }
+ timeout_str = alloc_str;
+ }
+
+ d_printf("Key: %s\t Timeout: %s\t Value: %s %s\n", keystr,
+ timeout_str, datastr, timeout > now_t ? "": "(expired)");
+
+ SAFE_FREE(alloc_str);
+}
+
+static void delete_cache_entry(const char* keystr, const char* datastr,
+ const time_t timeout, void* dptr)
+{
+ if (!gencache_del(keystr))
+ d_fprintf(stderr, "Couldn't delete entry! key = %s\n", keystr);
+}
+
+
+/**
+ * Parse text representation of timeout value
+ *
+ * @param timeout_str string containing text representation of the timeout
+ * @return numeric timeout of time_t type
+ **/
+static time_t parse_timeout(const char* timeout_str)
+{
+ char sign = '\0', *number = NULL, unit = '\0';
+ int len, number_begin, number_end;
+ time_t timeout;
+
+ /* sign detection */
+ if (timeout_str[0] == '!' || timeout_str[0] == '+') {
+ sign = timeout_str[0];
+ number_begin = 1;
+ } else {
+ number_begin = 0;
+ }
+
+ /* unit detection */
+ len = strlen(timeout_str);
+ switch (timeout_str[len - 1]) {
+ case 's':
+ case 'm':
+ case 'h':
+ case 'd':
+ case 'w': unit = timeout_str[len - 1];
+ }
+
+ /* number detection */
+ len = (sign) ? strlen(&timeout_str[number_begin]) : len;
+ number_end = (unit) ? len - 1 : len;
+ number = SMB_STRNDUP(&timeout_str[number_begin], number_end);
+
+ /* calculate actual timeout value */
+ timeout = (time_t)atoi(number);
+
+ switch (unit) {
+ case 'm': timeout *= 60; break;
+ case 'h': timeout *= 60*60; break;
+ case 'd': timeout *= 60*60*24; break;
+ case 'w': timeout *= 60*60*24*7; break; /* that's fair enough, I think :) */
+ }
+
+ switch (sign) {
+ case '!': timeout = time(NULL) - timeout; break;
+ case '+':
+ default: timeout += time(NULL); break;
+ }
+
+ if (number) SAFE_FREE(number);
+ return timeout;
+}
+
+
+/**
+ * Add an entry to the cache. If it does exist, then set it.
+ *
+ * @param c A net_context structure
+ * @param argv key, value and timeout are passed in command line
+ * @return 0 on success, otherwise failure
+ **/
+static int net_cache_add(struct net_context *c, int argc, const char **argv)
+{
+ const char *keystr, *datastr, *timeout_str;
+ time_t timeout;
+
+ if (argc < 3 || c->display_usage) {
+ d_printf("\nUsage: net cache add <key string> <data string> <timeout>\n");
+ return -1;
+ }
+
+ keystr = argv[0];
+ datastr = argv[1];
+ timeout_str = argv[2];
+
+ /* parse timeout given in command line */
+ timeout = parse_timeout(timeout_str);
+ if (!timeout) {
+ d_fprintf(stderr, "Invalid timeout argument.\n");
+ return -1;
+ }
+
+ if (gencache_set(keystr, datastr, timeout)) {
+ d_printf("New cache entry stored successfully.\n");
+ gencache_shutdown();
+ return 0;
+ }
+
+ d_fprintf(stderr, "Entry couldn't be added. Perhaps there's already such a key.\n");
+ gencache_shutdown();
+ return -1;
+}
+
+/**
+ * Delete an entry in the cache
+ *
+ * @param c A net_context structure
+ * @param argv key to delete an entry of
+ * @return 0 on success, otherwise failure
+ **/
+static int net_cache_del(struct net_context *c, int argc, const char **argv)
+{
+ const char *keystr = argv[0];
+
+ if (argc < 1 || c->display_usage) {
+ d_printf("\nUsage: net cache del <key string>\n");
+ return -1;
+ }
+
+ if(gencache_del(keystr)) {
+ d_printf("Entry deleted.\n");
+ return 0;
+ }
+
+ d_fprintf(stderr, "Couldn't delete specified entry\n");
+ return -1;
+}
+
+
+/**
+ * Get and display an entry from the cache
+ *
+ * @param c A net_context structure
+ * @param argv key to search an entry of
+ * @return 0 on success, otherwise failure
+ **/
+static int net_cache_get(struct net_context *c, int argc, const char **argv)
+{
+ const char* keystr = argv[0];
+ char* valuestr;
+ time_t timeout;
+
+ if (argc < 1 || c->display_usage) {
+ d_printf("\nUsage: net cache get <key>\n");
+ return -1;
+ }
+
+ if (gencache_get(keystr, &valuestr, &timeout)) {
+ print_cache_entry(keystr, valuestr, timeout, NULL);
+ return 0;
+ }
+
+ d_fprintf(stderr, "Failed to find entry\n");
+ return -1;
+}
+
+
+/**
+ * Search an entry/entries in the cache
+ *
+ * @param c A net_context structure
+ * @param argv key pattern to match the entries to
+ * @return 0 on success, otherwise failure
+ **/
+static int net_cache_search(struct net_context *c, int argc, const char **argv)
+{
+ const char* pattern;
+
+ if (argc < 1 || c->display_usage) {
+ d_printf("Usage: net cache search <pattern>\n");
+ return -1;
+ }
+
+ pattern = argv[0];
+ gencache_iterate(print_cache_entry, NULL, pattern);
+ return 0;
+}
+
+
+/**
+ * List the contents of the cache
+ *
+ * @param c A net_context structure
+ * @param argv ignored in this functionailty
+ * @return always returns 0
+ **/
+static int net_cache_list(struct net_context *c, int argc, const char **argv)
+{
+ const char* pattern = "*";
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net cache list\n"
+ " List all cache entries.\n");
+ return 0;
+ }
+ gencache_iterate(print_cache_entry, NULL, pattern);
+ gencache_shutdown();
+ return 0;
+}
+
+
+/**
+ * Flush the whole cache
+ *
+ * @param c A net_context structure
+ * @param argv ignored in this functionality
+ * @return always returns 0
+ **/
+static int net_cache_flush(struct net_context *c, int argc, const char **argv)
+{
+ const char* pattern = "*";
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net cache flush\n"
+ " Delete all cache entries.\n");
+ return 0;
+ }
+ gencache_iterate(delete_cache_entry, NULL, pattern);
+ gencache_shutdown();
+ return 0;
+}
+
+/**
+ * Entry point to 'net cache' subfunctionality
+ *
+ * @param c A net_context structure
+ * @param argv arguments passed to further called functions
+ * @return whatever further functions return
+ **/
+int net_cache(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "add",
+ net_cache_add,
+ NET_TRANSPORT_LOCAL,
+ "Add new cache entry",
+ "net cache add <key string> <data string> <timeout>\n"
+ " Add new cache entry.\n"
+ " key string\tKey string to add cache data under.\n"
+ " data string\tData to store under given key.\n"
+ " timeout\tTimeout for cache data."
+ },
+ {
+ "del",
+ net_cache_del,
+ NET_TRANSPORT_LOCAL,
+ "Delete existing cache entry by key",
+ "net cache del <key string>\n"
+ " Delete existing cache entry by key.\n"
+ " key string\tKey string to delete."
+ },
+ {
+ "get",
+ net_cache_get,
+ NET_TRANSPORT_LOCAL,
+ "Get cache entry by key",
+ "net cache get <key string>\n"
+ " Get cache entry by key.\n"
+ " key string\tKey string to look up cache entry for."
+
+ },
+ {
+ "search",
+ net_cache_search,
+ NET_TRANSPORT_LOCAL,
+ "Search entry by pattern",
+ "net cache search <pattern>\n"
+ " Search entry by pattern.\n"
+ " pattern\tPattern to search for in cache."
+ },
+ {
+ "list",
+ net_cache_list,
+ NET_TRANSPORT_LOCAL,
+ "List all cache entries",
+ "net cache list\n"
+ " List all cache entries"
+ },
+ {
+ "flush",
+ net_cache_flush,
+ NET_TRANSPORT_LOCAL,
+ "Delete all cache entries",
+ "net cache flush\n"
+ " Delete all cache entries"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net cache", func);
+}
diff --git a/source3/utils/net_conf.c b/source3/utils/net_conf.c
new file mode 100644
index 0000000000..ab1b0f3df7
--- /dev/null
+++ b/source3/utils/net_conf.c
@@ -0,0 +1,1179 @@
+/*
+ * Samba Unix/Linux SMB client library
+ * Distributed SMB/CIFS Server Management Utility
+ * Local configuration interface
+ * Copyright (C) Michael Adam 2007-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This is an interface to Samba's configuration as made available
+ * by the libsmbconf interface (source/lib/smbconf/smbconf.c).
+ *
+ * This currently supports local interaction with the configuration
+ * stored in the registry. But other backends and remote access via
+ * rpc might get implemented in the future.
+ */
+
+#include "includes.h"
+#include "utils/net.h"
+
+/**********************************************************************
+ *
+ * usage functions
+ *
+ **********************************************************************/
+
+static int net_conf_list_usage(struct net_context *c, int argc,
+ const char **argv)
+{
+ d_printf("USAGE: net conf list\n");
+ return -1;
+}
+
+static int net_conf_import_usage(struct net_context *c, int argc,
+ const char**argv)
+{
+ d_printf("USAGE: net conf import [--test|-T] <filename> "
+ "[<servicename>]\n"
+ "\t[--test|-T] testmode - do not act, just print "
+ "what would be done\n"
+ "\t<servicename> only import service <servicename>, "
+ "ignore the rest\n");
+ return -1;
+}
+
+static int net_conf_listshares_usage(struct net_context *c, int argc,
+ const char **argv)
+{
+ d_printf("USAGE: net conf listshares\n");
+ return -1;
+}
+
+static int net_conf_drop_usage(struct net_context *c, int argc,
+ const char **argv)
+{
+ d_printf("USAGE: net conf drop\n");
+ return -1;
+}
+
+static int net_conf_showshare_usage(struct net_context *c, int argc,
+ const char **argv)
+{
+ d_printf("USAGE: net conf showshare <sharename>\n");
+ return -1;
+}
+
+static int net_conf_addshare_usage(struct net_context *c, int argc,
+ const char **argv)
+{
+ d_printf("USAGE: net conf addshare <sharename> <path> "
+ "[writeable={y|N} [guest_ok={y|N} [<comment>]]\n"
+ "\t<sharename> the new share name.\n"
+ "\t<path> the path on the filesystem to export.\n"
+ "\twriteable={y|N} set \"writeable to \"yes\" or "
+ "\"no\" (default) on this share.\n"
+ "\tguest_ok={y|N} set \"guest ok\" to \"yes\" or "
+ "\"no\" (default) on this share.\n"
+ "\t<comment> optional comment for the new share.\n");
+ return -1;
+}
+
+static int net_conf_delshare_usage(struct net_context *c, int argc,
+ const char **argv)
+{
+ d_printf("USAGE: net conf delshare <sharename>\n");
+ return -1;
+}
+
+static int net_conf_setparm_usage(struct net_context *c, int argc,
+ const char **argv)
+{
+ d_printf("USAGE: net conf setparm <section> <param> <value>\n");
+ return -1;
+}
+
+static int net_conf_getparm_usage(struct net_context *c, int argc,
+ const char **argv)
+{
+ d_printf("USAGE: net conf getparm <section> <param>\n");
+ return -1;
+}
+
+static int net_conf_delparm_usage(struct net_context *c, int argc,
+ const char **argv)
+{
+ d_printf("USAGE: net conf delparm <section> <param>\n");
+ return -1;
+}
+
+static int net_conf_getincludes_usage(struct net_context *c, int argc,
+ const char **argv)
+{
+ d_printf("USAGE: net conf getincludes <section>\n");
+ return -1;
+}
+
+static int net_conf_setincludes_usage(struct net_context *c, int argc,
+ const char **argv)
+{
+ d_printf("USAGE: net conf setincludes <section> [<filename>]*\n");
+ return -1;
+}
+
+static int net_conf_delincludes_usage(struct net_context *c, int argc,
+ const char **argv)
+{
+ d_printf("USAGE: net conf delincludes <section>\n");
+ return -1;
+}
+
+
+/**********************************************************************
+ *
+ * Helper functions
+ *
+ **********************************************************************/
+
+/**
+ * This functions process a service previously loaded with libsmbconf.
+ */
+static WERROR import_process_service(struct net_context *c,
+ struct smbconf_ctx *conf_ctx,
+ struct smbconf_service *service)
+{
+ uint32_t idx;
+ WERROR werr = WERR_OK;
+ uint32_t num_includes = 0;
+ char **includes = NULL;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ if (c->opt_testmode) {
+ const char *indent = "";
+ if (service->name != NULL) {
+ d_printf("[%s]\n", service->name);
+ indent = "\t";
+ }
+ for (idx = 0; idx < service->num_params; idx++) {
+ d_printf("%s%s = %s\n", indent,
+ service->param_names[idx],
+ service->param_values[idx]);
+ }
+ d_printf("\n");
+ goto done;
+ }
+
+ if (smbconf_share_exists(conf_ctx, service->name)) {
+ werr = smbconf_delete_share(conf_ctx, service->name);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ }
+ werr = smbconf_create_share(conf_ctx, service->name);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ for (idx = 0; idx < service->num_params; idx ++) {
+ if (strequal(service->param_names[idx], "include")) {
+ includes = TALLOC_REALLOC_ARRAY(mem_ctx,
+ includes,
+ char *,
+ num_includes+1);
+ if (includes == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+ includes[num_includes] = talloc_strdup(includes,
+ service->param_values[idx]);
+ if (includes[num_includes] == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+ num_includes++;
+ } else {
+ werr = smbconf_set_parameter(conf_ctx,
+ service->name,
+ service->param_names[idx],
+ service->param_values[idx]);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ }
+ }
+
+ werr = smbconf_set_includes(conf_ctx, service->name, num_includes,
+ (const char **)includes);
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return werr;
+}
+
+
+/**********************************************************************
+ *
+ * the main conf functions
+ *
+ **********************************************************************/
+
+static int net_conf_list(struct net_context *c, struct smbconf_ctx *conf_ctx,
+ int argc, const char **argv)
+{
+ WERROR werr = WERR_OK;
+ int ret = -1;
+ TALLOC_CTX *mem_ctx;
+ uint32_t num_shares;
+ uint32_t share_count, param_count;
+ struct smbconf_service **shares = NULL;
+
+ mem_ctx = talloc_stackframe();
+
+ if (argc != 0 || c->display_usage) {
+ net_conf_list_usage(c, argc, argv);
+ goto done;
+ }
+
+ werr = smbconf_get_config(conf_ctx, mem_ctx, &num_shares, &shares);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "Error getting config: %s\n",
+ dos_errstr(werr));
+ goto done;
+ }
+
+ for (share_count = 0; share_count < num_shares; share_count++) {
+ const char *indent = "";
+ if (shares[share_count]->name != NULL) {
+ d_printf("[%s]\n", shares[share_count]->name);
+ indent = "\t";
+ }
+ for (param_count = 0;
+ param_count < shares[share_count]->num_params;
+ param_count++)
+ {
+ d_printf("%s%s = %s\n",
+ indent,
+ shares[share_count]->param_names[param_count],
+ shares[share_count]->param_values[param_count]);
+ }
+ d_printf("\n");
+ }
+
+ ret = 0;
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static int net_conf_import(struct net_context *c, struct smbconf_ctx *conf_ctx,
+ int argc, const char **argv)
+{
+ int ret = -1;
+ const char *filename = NULL;
+ const char *servicename = NULL;
+ char *conf_source = NULL;
+ TALLOC_CTX *mem_ctx;
+ struct smbconf_ctx *txt_ctx;
+ WERROR werr;
+
+ if (c->display_usage)
+ return net_conf_import_usage(c, argc, argv);
+
+ mem_ctx = talloc_stackframe();
+
+ switch (argc) {
+ case 0:
+ default:
+ net_conf_import_usage(c, argc, argv);
+ goto done;
+ case 2:
+ servicename = talloc_strdup_lower(mem_ctx, argv[1]);
+ if (servicename == NULL) {
+ d_printf("error: out of memory!\n");
+ goto done;
+ }
+ case 1:
+ filename = argv[0];
+ break;
+ }
+
+ DEBUG(3,("net_conf_import: reading configuration from file %s.\n",
+ filename));
+
+ conf_source = talloc_asprintf(mem_ctx, "file:%s", filename);
+ if (conf_source == NULL) {
+ d_printf("error: out of memory!\n");
+ goto done;
+ }
+
+ werr = smbconf_init(mem_ctx, &txt_ctx, conf_source);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_printf("error loading file '%s': %s\n", filename,
+ dos_errstr(werr));
+ goto done;
+ }
+
+ if (c->opt_testmode) {
+ d_printf("\nTEST MODE - "
+ "would import the following configuration:\n\n");
+ }
+
+ if (servicename != NULL) {
+ struct smbconf_service *service = NULL;
+
+ werr = smbconf_get_share(txt_ctx, mem_ctx,
+ servicename,
+ &service);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ werr = import_process_service(c, conf_ctx, service);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ } else {
+ struct smbconf_service **services = NULL;
+ uint32_t num_shares, sidx;
+
+ werr = smbconf_get_config(txt_ctx, mem_ctx,
+ &num_shares,
+ &services);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ if (!c->opt_testmode) {
+ werr = smbconf_drop(conf_ctx);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ }
+ for (sidx = 0; sidx < num_shares; sidx++) {
+ werr = import_process_service(c, conf_ctx,
+ services[sidx]);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ }
+ }
+
+ ret = 0;
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static int net_conf_listshares(struct net_context *c,
+ struct smbconf_ctx *conf_ctx, int argc,
+ const char **argv)
+{
+ WERROR werr = WERR_OK;
+ int ret = -1;
+ uint32_t count, num_shares = 0;
+ char **share_names = NULL;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_stackframe();
+
+ if (argc != 0 || c->display_usage) {
+ net_conf_listshares_usage(c, argc, argv);
+ goto done;
+ }
+
+ werr = smbconf_get_share_names(conf_ctx, mem_ctx, &num_shares,
+ &share_names);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ for (count = 0; count < num_shares; count++)
+ {
+ d_printf("%s\n", share_names[count]);
+ }
+
+ ret = 0;
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static int net_conf_drop(struct net_context *c, struct smbconf_ctx *conf_ctx,
+ int argc, const char **argv)
+{
+ int ret = -1;
+ WERROR werr;
+
+ if (argc != 0 || c->display_usage) {
+ net_conf_drop_usage(c, argc, argv);
+ goto done;
+ }
+
+ werr = smbconf_drop(conf_ctx);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "Error deleting configuration: %s\n",
+ dos_errstr(werr));
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ return ret;
+}
+
+static int net_conf_showshare(struct net_context *c,
+ struct smbconf_ctx *conf_ctx, int argc,
+ const char **argv)
+{
+ int ret = -1;
+ WERROR werr = WERR_OK;
+ const char *sharename = NULL;
+ TALLOC_CTX *mem_ctx;
+ uint32_t count;
+ struct smbconf_service *service = NULL;
+
+ mem_ctx = talloc_stackframe();
+
+ if (argc != 1 || c->display_usage) {
+ net_conf_showshare_usage(c, argc, argv);
+ goto done;
+ }
+
+ sharename = talloc_strdup_lower(mem_ctx, argv[0]);
+ if (sharename == NULL) {
+ d_printf("error: out of memory!\n");
+ goto done;
+ }
+
+ werr = smbconf_get_share(conf_ctx, mem_ctx, sharename, &service);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_printf("error getting share parameters: %s\n",
+ dos_errstr(werr));
+ goto done;
+ }
+
+ d_printf("[%s]\n", sharename);
+
+ for (count = 0; count < service->num_params; count++) {
+ d_printf("\t%s = %s\n", service->param_names[count],
+ service->param_values[count]);
+ }
+
+ ret = 0;
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+/**
+ * Add a share, with a couple of standard parameters, partly optional.
+ *
+ * This is a high level utility function of the net conf utility,
+ * not a direct frontend to the smbconf API.
+ */
+static int net_conf_addshare(struct net_context *c,
+ struct smbconf_ctx *conf_ctx, int argc,
+ const char **argv)
+{
+ int ret = -1;
+ WERROR werr = WERR_OK;
+ char *sharename = NULL;
+ const char *path = NULL;
+ const char *comment = NULL;
+ const char *guest_ok = "no";
+ const char *writeable = "no";
+ SMB_STRUCT_STAT sbuf;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ if (c->display_usage) {
+ net_conf_addshare_usage(c, argc, argv);
+ ret = 0;
+ goto done;
+ }
+
+ switch (argc) {
+ case 0:
+ case 1:
+ default:
+ net_conf_addshare_usage(c, argc, argv);
+ goto done;
+ case 5:
+ comment = argv[4];
+ case 4:
+ if (!strnequal(argv[3], "guest_ok=", 9)) {
+ net_conf_addshare_usage(c, argc, argv);
+ goto done;
+ }
+ switch (argv[3][9]) {
+ case 'y':
+ case 'Y':
+ guest_ok = "yes";
+ break;
+ case 'n':
+ case 'N':
+ guest_ok = "no";
+ break;
+ default:
+ net_conf_addshare_usage(c, argc, argv);
+ goto done;
+ }
+ case 3:
+ if (!strnequal(argv[2], "writeable=", 10)) {
+ net_conf_addshare_usage(c, argc, argv);
+ goto done;
+ }
+ switch (argv[2][10]) {
+ case 'y':
+ case 'Y':
+ writeable = "yes";
+ break;
+ case 'n':
+ case 'N':
+ writeable = "no";
+ break;
+ default:
+ net_conf_addshare_usage(c, argc, argv);
+ goto done;
+ }
+ case 2:
+ path = argv[1];
+ sharename = talloc_strdup_lower(mem_ctx, argv[0]);
+ if (sharename == NULL) {
+ d_printf("error: out of memory!\n");
+ goto done;
+ }
+
+ break;
+ }
+
+ /*
+ * validate arguments
+ */
+
+ /* validate share name */
+
+ if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS,
+ strlen(sharename)))
+ {
+ d_fprintf(stderr, "ERROR: share name %s contains "
+ "invalid characters (any of %s)\n",
+ sharename, INVALID_SHARENAME_CHARS);
+ goto done;
+ }
+
+ if (getpwnam(sharename)) {
+ d_fprintf(stderr, "ERROR: share name %s is already a valid "
+ "system user name.\n", sharename);
+ goto done;
+ }
+
+ if (strequal(sharename, GLOBAL_NAME)) {
+ d_fprintf(stderr,
+ "ERROR: 'global' is not a valid share name.\n");
+ goto done;
+ }
+
+ if (smbconf_share_exists(conf_ctx, sharename)) {
+ d_fprintf(stderr, "ERROR: share %s already exists.\n",
+ sharename);
+ goto done;
+ }
+
+ /* validate path */
+
+ if (path[0] != '/') {
+ d_fprintf(stderr,
+ "Error: path '%s' is not an absolute path.\n",
+ path);
+ goto done;
+ }
+
+ if (sys_stat(path, &sbuf) != 0) {
+ d_fprintf(stderr,
+ "ERROR: cannot stat path '%s' to ensure "
+ "this is a directory.\n"
+ "Error was '%s'.\n",
+ path, strerror(errno));
+ goto done;
+ }
+
+ if (!S_ISDIR(sbuf.st_mode)) {
+ d_fprintf(stderr,
+ "ERROR: path '%s' is not a directory.\n",
+ path);
+ goto done;
+ }
+
+ /*
+ * create the share
+ */
+
+ werr = smbconf_create_share(conf_ctx, sharename);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "Error creating share %s: %s\n",
+ sharename, dos_errstr(werr));
+ goto done;
+ }
+
+ /*
+ * fill the share with parameters
+ */
+
+ werr = smbconf_set_parameter(conf_ctx, sharename, "path", path);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "Error setting parameter %s: %s\n",
+ "path", dos_errstr(werr));
+ goto done;
+ }
+
+ if (comment != NULL) {
+ werr = smbconf_set_parameter(conf_ctx, sharename, "comment",
+ comment);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "Error setting parameter %s: %s\n",
+ "comment", dos_errstr(werr));
+ goto done;
+ }
+ }
+
+ werr = smbconf_set_parameter(conf_ctx, sharename, "guest ok", guest_ok);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "Error setting parameter %s: %s\n",
+ "'guest ok'", dos_errstr(werr));
+ goto done;
+ }
+
+ werr = smbconf_set_parameter(conf_ctx, sharename, "writeable",
+ writeable);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "Error setting parameter %s: %s\n",
+ "writeable", dos_errstr(werr));
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static int net_conf_delshare(struct net_context *c,
+ struct smbconf_ctx *conf_ctx, int argc,
+ const char **argv)
+{
+ int ret = -1;
+ const char *sharename = NULL;
+ WERROR werr = WERR_OK;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ if (argc != 1 || c->display_usage) {
+ net_conf_delshare_usage(c, argc, argv);
+ goto done;
+ }
+ sharename = talloc_strdup_lower(mem_ctx, argv[0]);
+ if (sharename == NULL) {
+ d_printf("error: out of memory!\n");
+ goto done;
+ }
+
+ werr = smbconf_delete_share(conf_ctx, sharename);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "Error deleting share %s: %s\n",
+ sharename, dos_errstr(werr));
+ goto done;
+ }
+
+ ret = 0;
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static int net_conf_setparm(struct net_context *c, struct smbconf_ctx *conf_ctx,
+ int argc, const char **argv)
+{
+ int ret = -1;
+ WERROR werr = WERR_OK;
+ char *service = NULL;
+ char *param = NULL;
+ const char *value_str = NULL;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ if (argc != 3 || c->display_usage) {
+ net_conf_setparm_usage(c, argc, argv);
+ goto done;
+ }
+ service = talloc_strdup_lower(mem_ctx, argv[0]);
+ if (service == NULL) {
+ d_printf("error: out of memory!\n");
+ goto done;
+ }
+ param = talloc_strdup_lower(mem_ctx, argv[1]);
+ if (param == NULL) {
+ d_printf("error: out of memory!\n");
+ goto done;
+ }
+ value_str = argv[2];
+
+ if (!smbconf_share_exists(conf_ctx, service)) {
+ werr = smbconf_create_share(conf_ctx, service);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "Error creating share '%s': %s\n",
+ service, dos_errstr(werr));
+ goto done;
+ }
+ }
+
+ werr = smbconf_set_parameter(conf_ctx, service, param, value_str);
+
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "Error setting value '%s': %s\n",
+ param, dos_errstr(werr));
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static int net_conf_getparm(struct net_context *c, struct smbconf_ctx *conf_ctx,
+ int argc, const char **argv)
+{
+ int ret = -1;
+ WERROR werr = WERR_OK;
+ char *service = NULL;
+ char *param = NULL;
+ char *valstr = NULL;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_stackframe();
+
+ if (argc != 2 || c->display_usage) {
+ net_conf_getparm_usage(c, argc, argv);
+ goto done;
+ }
+ service = talloc_strdup_lower(mem_ctx, argv[0]);
+ if (service == NULL) {
+ d_printf("error: out of memory!\n");
+ goto done;
+ }
+ param = talloc_strdup_lower(mem_ctx, argv[1]);
+ if (param == NULL) {
+ d_printf("error: out of memory!\n");
+ goto done;
+ }
+
+ werr = smbconf_get_parameter(conf_ctx, mem_ctx, service, param, &valstr);
+
+ if (W_ERROR_EQUAL(werr, WERR_NO_SUCH_SERVICE)) {
+ d_fprintf(stderr,
+ "Error: given service '%s' does not exist.\n",
+ service);
+ goto done;
+ } else if (W_ERROR_EQUAL(werr, WERR_INVALID_PARAM)) {
+ d_fprintf(stderr,
+ "Error: given parameter '%s' is not set.\n",
+ param);
+ goto done;
+ } else if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "Error getting value '%s': %s.\n",
+ param, dos_errstr(werr));
+ goto done;
+ }
+
+ d_printf("%s\n", valstr);
+
+ ret = 0;
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static int net_conf_delparm(struct net_context *c, struct smbconf_ctx *conf_ctx,
+ int argc, const char **argv)
+{
+ int ret = -1;
+ WERROR werr = WERR_OK;
+ char *service = NULL;
+ char *param = NULL;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ if (argc != 2 || c->display_usage) {
+ net_conf_delparm_usage(c, argc, argv);
+ goto done;
+ }
+ service = talloc_strdup_lower(mem_ctx, argv[0]);
+ if (service == NULL) {
+ d_printf("error: out of memory!\n");
+ goto done;
+ }
+ param = talloc_strdup_lower(mem_ctx, argv[1]);
+ if (param == NULL) {
+ d_printf("error: out of memory!\n");
+ goto done;
+ }
+
+ werr = smbconf_delete_parameter(conf_ctx, service, param);
+
+ if (W_ERROR_EQUAL(werr, WERR_NO_SUCH_SERVICE)) {
+ d_fprintf(stderr,
+ "Error: given service '%s' does not exist.\n",
+ service);
+ goto done;
+ } else if (W_ERROR_EQUAL(werr, WERR_INVALID_PARAM)) {
+ d_fprintf(stderr,
+ "Error: given parameter '%s' is not set.\n",
+ param);
+ goto done;
+ } else if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "Error deleting value '%s': %s.\n",
+ param, dos_errstr(werr));
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static int net_conf_getincludes(struct net_context *c,
+ struct smbconf_ctx *conf_ctx,
+ int argc, const char **argv)
+{
+ WERROR werr;
+ uint32_t num_includes;
+ uint32_t count;
+ char *service;
+ char **includes = NULL;
+ int ret = -1;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ if (argc != 1 || c->display_usage) {
+ net_conf_getincludes_usage(c, argc, argv);
+ goto done;
+ }
+
+ service = talloc_strdup_lower(mem_ctx, argv[0]);
+ if (service == NULL) {
+ d_printf("error: out of memory!\n");
+ goto done;
+ }
+
+ werr = smbconf_get_includes(conf_ctx, mem_ctx, service,
+ &num_includes, &includes);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_printf("error getting includes: %s\n", dos_errstr(werr));
+ goto done;
+ }
+
+ for (count = 0; count < num_includes; count++) {
+ d_printf("include = %s\n", includes[count]);
+ }
+
+ ret = 0;
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static int net_conf_setincludes(struct net_context *c,
+ struct smbconf_ctx *conf_ctx,
+ int argc, const char **argv)
+{
+ WERROR werr;
+ char *service;
+ uint32_t num_includes;
+ const char **includes;
+ int ret = -1;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ if (argc < 1 || c->display_usage) {
+ net_conf_setincludes_usage(c, argc, argv);
+ goto done;
+ }
+
+ service = talloc_strdup_lower(mem_ctx, argv[0]);
+ if (service == NULL) {
+ d_printf("error: out of memory!\n");
+ goto done;
+ }
+
+ num_includes = argc - 1;
+ if (num_includes == 0) {
+ includes = NULL;
+ } else {
+ includes = argv + 1;
+ }
+
+ werr = smbconf_set_includes(conf_ctx, service, num_includes, includes);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_printf("error setting includes: %s\n", dos_errstr(werr));
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static int net_conf_delincludes(struct net_context *c,
+ struct smbconf_ctx *conf_ctx,
+ int argc, const char **argv)
+{
+ WERROR werr;
+ char *service;
+ int ret = -1;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ if (argc != 1 || c->display_usage) {
+ net_conf_delincludes_usage(c, argc, argv);
+ goto done;
+ }
+
+ service = talloc_strdup_lower(mem_ctx, argv[0]);
+ if (service == NULL) {
+ d_printf("error: out of memory!\n");
+ goto done;
+ }
+
+ werr = smbconf_delete_includes(conf_ctx, service);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_printf("error deleting includes: %s\n", dos_errstr(werr));
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+
+/**********************************************************************
+ *
+ * Wrapper and net_conf_run_function mechanism.
+ *
+ **********************************************************************/
+
+/**
+ * Wrapper function to call the main conf functions.
+ * The wrapper calls handles opening and closing of the
+ * configuration.
+ */
+static int net_conf_wrap_function(struct net_context *c,
+ int (*fn)(struct net_context *,
+ struct smbconf_ctx *,
+ int, const char **),
+ int argc, const char **argv)
+{
+ WERROR werr;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+ struct smbconf_ctx *conf_ctx;
+ int ret = -1;
+
+ werr = smbconf_init(mem_ctx, &conf_ctx, "registry:");
+
+ if (!W_ERROR_IS_OK(werr)) {
+ return -1;
+ }
+
+ ret = fn(c, conf_ctx, argc, argv);
+
+ smbconf_shutdown(conf_ctx);
+
+ return ret;
+}
+
+/*
+ * We need a functable struct of our own, because the
+ * functions are called through a wrapper that handles
+ * the opening and closing of the configuration, and so on.
+ */
+struct conf_functable {
+ const char *funcname;
+ int (*fn)(struct net_context *c, struct smbconf_ctx *ctx, int argc,
+ const char **argv);
+ int valid_transports;
+ const char *description;
+ const char *usage;
+};
+
+/**
+ * This imitates net_run_function but calls the main functions
+ * through the wrapper net_conf_wrap_function().
+ */
+static int net_conf_run_function(struct net_context *c, int argc,
+ const char **argv, const char *whoami,
+ struct conf_functable *table)
+{
+ int i;
+
+ if (argc != 0) {
+ for (i=0; table[i].funcname; i++) {
+ if (StrCaseCmp(argv[0], table[i].funcname) == 0)
+ return net_conf_wrap_function(c, table[i].fn,
+ argc-1,
+ argv+1);
+ }
+ }
+
+ d_printf("Usage:\n");
+ for (i=0; table[i].funcname; i++) {
+ if (c->display_usage == false)
+ d_printf("%s %-15s %s\n", whoami, table[i].funcname,
+ table[i].description);
+ else
+ d_printf("%s\n", table[i].usage);
+ }
+
+ return c->display_usage?0:-1;
+}
+
+/*
+ * Entry-point for all the CONF functions.
+ */
+
+int net_conf(struct net_context *c, int argc, const char **argv)
+{
+ int ret = -1;
+ struct conf_functable func_table[] = {
+ {
+ "list",
+ net_conf_list,
+ NET_TRANSPORT_LOCAL,
+ "Dump the complete configuration in smb.conf like "
+ "format.",
+ "net conf list\n"
+ " Dump the complete configuration in smb.conf like "
+ "format."
+
+ },
+ {
+ "import",
+ net_conf_import,
+ NET_TRANSPORT_LOCAL,
+ "Import configuration from file in smb.conf format.",
+ "net conf import\n"
+ " Import configuration from file in smb.conf format."
+ },
+ {
+ "listshares",
+ net_conf_listshares,
+ NET_TRANSPORT_LOCAL,
+ "List the share names.",
+ "net conf listshares\n"
+ " List the share names."
+ },
+ {
+ "drop",
+ net_conf_drop,
+ NET_TRANSPORT_LOCAL,
+ "Delete the complete configuration.",
+ "net conf drop\n"
+ " Delete the complete configuration."
+ },
+ {
+ "showshare",
+ net_conf_showshare,
+ NET_TRANSPORT_LOCAL,
+ "Show the definition of a share.",
+ "net conf showshare\n"
+ " Show the definition of a share."
+ },
+ {
+ "addshare",
+ net_conf_addshare,
+ NET_TRANSPORT_LOCAL,
+ "Create a new share.",
+ "net conf addshare\n"
+ " Create a new share."
+ },
+ {
+ "delshare",
+ net_conf_delshare,
+ NET_TRANSPORT_LOCAL,
+ "Delete a share.",
+ "net conf delshare\n"
+ " Delete a share."
+ },
+ {
+ "setparm",
+ net_conf_setparm,
+ NET_TRANSPORT_LOCAL,
+ "Store a parameter.",
+ "net conf setparm\n"
+ " Store a parameter."
+ },
+ {
+ "getparm",
+ net_conf_getparm,
+ NET_TRANSPORT_LOCAL,
+ "Retrieve the value of a parameter.",
+ "net conf getparm\n"
+ " Retrieve the value of a parameter."
+ },
+ {
+ "delparm",
+ net_conf_delparm,
+ NET_TRANSPORT_LOCAL,
+ "Delete a parameter.",
+ "net conf delparm\n"
+ " Delete a parameter."
+ },
+ {
+ "getincludes",
+ net_conf_getincludes,
+ NET_TRANSPORT_LOCAL,
+ "Show the includes of a share definition.",
+ "net conf getincludes\n"
+ " Show the includes of a share definition."
+ },
+ {
+ "setincludes",
+ net_conf_setincludes,
+ NET_TRANSPORT_LOCAL,
+ "Set includes for a share.",
+ "net conf setincludes\n"
+ " Set includes for a share."
+ },
+ {
+ "delincludes",
+ net_conf_delincludes,
+ NET_TRANSPORT_LOCAL,
+ "Delete includes from a share definition.",
+ "net conf setincludes\n"
+ " Delete includes from a share definition."
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ ret = net_conf_run_function(c, argc, argv, "net conf", func_table);
+
+ return ret;
+}
+
diff --git a/source3/utils/net_dns.c b/source3/utils/net_dns.c
new file mode 100644
index 0000000000..14d45e2b0f
--- /dev/null
+++ b/source3/utils/net_dns.c
@@ -0,0 +1,210 @@
+
+/*
+ Samba Unix/Linux Dynamic DNS Update
+ net ads commands
+
+ Copyright (C) Krishna Ganugapati (krishnag@centeris.com) 2006
+ Copyright (C) Gerald Carter 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+#include "dns.h"
+
+#if defined(WITH_DNS_UPDATES)
+
+/*
+ * Silly prototype to get rid of a warning
+ */
+
+DNS_ERROR DoDNSUpdate(char *pszServerName,
+ const char *pszDomainName, const char *pszHostName,
+ const struct sockaddr_storage *sslist,
+ size_t num_addrs );
+
+/*********************************************************************
+*********************************************************************/
+
+DNS_ERROR DoDNSUpdate(char *pszServerName,
+ const char *pszDomainName, const char *pszHostName,
+ const struct sockaddr_storage *sslist, size_t num_addrs )
+{
+ DNS_ERROR err;
+ struct dns_connection *conn;
+ TALLOC_CTX *mem_ctx;
+ OM_uint32 minor;
+ struct dns_update_request *req, *resp;
+
+ if ( (num_addrs <= 0) || !sslist ) {
+ return ERROR_DNS_INVALID_PARAMETER;
+ }
+
+ if (!(mem_ctx = talloc_init("DoDNSUpdate"))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = dns_open_connection( pszServerName, DNS_TCP, mem_ctx, &conn );
+ if (!ERR_DNS_IS_OK(err)) {
+ goto error;
+ }
+
+ /*
+ * Probe if everything's fine
+ */
+
+ err = dns_create_probe(mem_ctx, pszDomainName, pszHostName,
+ num_addrs, sslist, &req);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_update_transaction(mem_ctx, conn, req, &resp);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ if (dns_response_code(resp->flags) == DNS_NO_ERROR) {
+ TALLOC_FREE(mem_ctx);
+ return ERROR_DNS_SUCCESS;
+ }
+
+ /*
+ * First try without signing
+ */
+
+ err = dns_create_update_request(mem_ctx, pszDomainName, pszHostName,
+ sslist, num_addrs, &req);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_update_transaction(mem_ctx, conn, req, &resp);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ if (dns_response_code(resp->flags) == DNS_NO_ERROR) {
+ TALLOC_FREE(mem_ctx);
+ return ERROR_DNS_SUCCESS;
+ }
+
+ /*
+ * Okay, we have to try with signing
+ */
+ {
+ gss_ctx_id_t gss_context;
+ char *keyname;
+
+ if (!(keyname = dns_generate_keyname( mem_ctx ))) {
+ err = ERROR_DNS_NO_MEMORY;
+ goto error;
+ }
+
+ err = dns_negotiate_sec_ctx( pszDomainName, pszServerName,
+ keyname, &gss_context, DNS_SRV_ANY );
+
+ /* retry using the Windows 2000 DNS hack */
+ if (!ERR_DNS_IS_OK(err)) {
+ err = dns_negotiate_sec_ctx( pszDomainName, pszServerName,
+ keyname, &gss_context,
+ DNS_SRV_WIN2000 );
+ }
+
+ if (!ERR_DNS_IS_OK(err))
+ goto error;
+
+
+ err = dns_sign_update(req, gss_context, keyname,
+ "gss.microsoft.com", time(NULL), 3600);
+
+ gss_delete_sec_context(&minor, &gss_context, GSS_C_NO_BUFFER);
+
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_update_transaction(mem_ctx, conn, req, &resp);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = (dns_response_code(resp->flags) == DNS_NO_ERROR) ?
+ ERROR_DNS_SUCCESS : ERROR_DNS_UPDATE_FAILED;
+ }
+
+
+error:
+ TALLOC_FREE(mem_ctx);
+ return err;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+int get_my_ip_address( struct sockaddr_storage **pp_ss )
+
+{
+ struct iface_struct nics[MAX_INTERFACES];
+ int i, n;
+ struct sockaddr_storage *list = NULL;
+ int count = 0;
+
+ /* find the first non-loopback address from our list of interfaces */
+
+ n = get_interfaces(nics, MAX_INTERFACES);
+
+ if (n <= 0) {
+ return -1;
+ }
+
+ if ( (list = SMB_MALLOC_ARRAY( struct sockaddr_storage, n )) == NULL ) {
+ return -1;
+ }
+
+ for ( i=0; i<n; i++ ) {
+ if (is_loopback_addr(&nics[i].ip)) {
+ continue;
+ }
+#if defined(HAVE_IPV6)
+ if ((nics[i].ip.ss_family == AF_INET6)) {
+ memcpy(&list[count++], &nics[i].ip,
+ sizeof(struct sockaddr_storage));
+ } else
+#endif
+ if (nics[i].ip.ss_family == AF_INET) {
+ memcpy(&list[count++], &nics[i].ip,
+ sizeof(struct sockaddr_storage));
+ }
+ }
+ *pp_ss = list;
+
+ return count;
+}
+
+/*
+ * Silly prototype to get rid of a warning
+ */
+
+DNS_ERROR do_gethostbyname(const char *server, const char *host);
+
+DNS_ERROR do_gethostbyname(const char *server, const char *host)
+{
+ struct dns_connection *conn;
+ struct dns_request *req, *resp;
+ DNS_ERROR err;
+
+ err = dns_open_connection(server, DNS_UDP, NULL, &conn);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_create_query(conn, host, QTYPE_A, DNS_CLASS_IN, &req);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_transaction(conn, conn, req, &resp);
+
+ error:
+ TALLOC_FREE(conn);
+ return err;
+}
+
+#endif /* defined(WITH_DNS_UPDATES) */
diff --git a/source3/utils/net_dom.c b/source3/utils/net_dom.c
new file mode 100644
index 0000000000..132630de55
--- /dev/null
+++ b/source3/utils/net_dom.c
@@ -0,0 +1,265 @@
+/*
+ Samba Unix/Linux SMB client library
+ net dom commands for remote join/unjoin
+ Copyright (C) 2007 Günther Deschner
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+int net_dom_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("usage: net dom join "
+ "<domain=DOMAIN> <ou=OU> <account=ACCOUNT> "
+ "<password=PASSWORD> <reboot>\n Join a remote machine\n");
+ d_printf("usage: net dom unjoin "
+ "<account=ACCOUNT> <password=PASSWORD> <reboot>\n"
+ " Unjoin a remote machine\n");
+
+ return -1;
+}
+
+static int net_dom_unjoin(struct net_context *c, int argc, const char **argv)
+{
+ const char *server_name = NULL;
+ const char *account = NULL;
+ const char *password = NULL;
+ uint32_t unjoin_flags = NETSETUP_ACCT_DELETE |
+ NETSETUP_JOIN_DOMAIN;
+ struct cli_state *cli = NULL;
+ bool do_reboot = false;
+ NTSTATUS ntstatus;
+ NET_API_STATUS status;
+ int ret = -1;
+ int i;
+
+ if (argc < 1 || c->display_usage) {
+ return net_dom_usage(c, argc, argv);
+ }
+
+ if (c->opt_host) {
+ server_name = c->opt_host;
+ }
+
+ for (i=0; i<argc; i++) {
+ if (strnequal(argv[i], "account", strlen("account"))) {
+ account = get_string_param(argv[i]);
+ if (!account) {
+ return -1;
+ }
+ }
+ if (strnequal(argv[i], "password", strlen("password"))) {
+ password = get_string_param(argv[i]);
+ if (!password) {
+ return -1;
+ }
+ }
+ if (strequal(argv[i], "reboot")) {
+ do_reboot = true;
+ }
+ }
+
+ if (do_reboot) {
+ ntstatus = net_make_ipc_connection_ex(c, c->opt_workgroup,
+ server_name, NULL, 0,
+ &cli);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ return -1;
+ }
+ }
+
+ status = NetUnjoinDomain(server_name, account, password, unjoin_flags);
+ if (status != 0) {
+ printf("Failed to unjoin domain: %s\n",
+ libnetapi_get_error_string(c->netapi_ctx, status));
+ goto done;
+ }
+
+ if (do_reboot) {
+ c->opt_comment = "Shutting down due to a domain membership "
+ "change";
+ c->opt_reboot = true;
+ c->opt_timeout = 30;
+
+ ret = run_rpc_command(c, cli,
+ &ndr_table_initshutdown.syntax_id,
+ 0, rpc_init_shutdown_internals,
+ argc, argv);
+ if (ret == 0) {
+ goto done;
+ }
+
+ ret = run_rpc_command(c, cli, &ndr_table_winreg.syntax_id, 0,
+ rpc_reg_shutdown_internals,
+ argc, argv);
+ goto done;
+ }
+
+ ret = 0;
+
+ done:
+ if (cli) {
+ cli_shutdown(cli);
+ }
+
+ return ret;
+}
+
+static int net_dom_join(struct net_context *c, int argc, const char **argv)
+{
+ const char *server_name = NULL;
+ const char *domain_name = NULL;
+ const char *account_ou = NULL;
+ const char *Account = NULL;
+ const char *password = NULL;
+ uint32_t join_flags = NETSETUP_ACCT_CREATE |
+ NETSETUP_JOIN_DOMAIN;
+ struct cli_state *cli = NULL;
+ bool do_reboot = false;
+ NTSTATUS ntstatus;
+ NET_API_STATUS status;
+ int ret = -1;
+ int i;
+
+ if (argc < 1 || c->display_usage) {
+ return net_dom_usage(c, argc, argv);
+ }
+
+ if (c->opt_host) {
+ server_name = c->opt_host;
+ }
+
+ if (c->opt_force) {
+ join_flags |= NETSETUP_DOMAIN_JOIN_IF_JOINED;
+ }
+
+ for (i=0; i<argc; i++) {
+ if (strnequal(argv[i], "ou", strlen("ou"))) {
+ account_ou = get_string_param(argv[i]);
+ if (!account_ou) {
+ return -1;
+ }
+ }
+ if (strnequal(argv[i], "domain", strlen("domain"))) {
+ domain_name = get_string_param(argv[i]);
+ if (!domain_name) {
+ return -1;
+ }
+ }
+ if (strnequal(argv[i], "account", strlen("account"))) {
+ Account = get_string_param(argv[i]);
+ if (!Account) {
+ return -1;
+ }
+ }
+ if (strnequal(argv[i], "password", strlen("password"))) {
+ password = get_string_param(argv[i]);
+ if (!password) {
+ return -1;
+ }
+ }
+ if (strequal(argv[i], "reboot")) {
+ do_reboot = true;
+ }
+ }
+
+ if (do_reboot) {
+ ntstatus = net_make_ipc_connection_ex(c, c->opt_workgroup,
+ server_name, NULL, 0,
+ &cli);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ return -1;
+ }
+ }
+
+ /* check if domain is a domain or a workgroup */
+
+ status = NetJoinDomain(server_name, domain_name, account_ou,
+ Account, password, join_flags);
+ if (status != 0) {
+ printf("Failed to join domain: %s\n",
+ libnetapi_get_error_string(c->netapi_ctx, status));
+ goto done;
+ }
+
+ if (do_reboot) {
+ c->opt_comment = "Shutting down due to a domain membership "
+ "change";
+ c->opt_reboot = true;
+ c->opt_timeout = 30;
+
+ ret = run_rpc_command(c, cli, &ndr_table_initshutdown.syntax_id, 0,
+ rpc_init_shutdown_internals,
+ argc, argv);
+ if (ret == 0) {
+ goto done;
+ }
+
+ ret = run_rpc_command(c, cli, &ndr_table_winreg.syntax_id, 0,
+ rpc_reg_shutdown_internals,
+ argc, argv);
+ goto done;
+ }
+
+ ret = 0;
+
+ done:
+ if (cli) {
+ cli_shutdown(cli);
+ }
+
+ return ret;
+}
+
+int net_dom(struct net_context *c, int argc, const char **argv)
+{
+ NET_API_STATUS status;
+
+ struct functable func[] = {
+ {
+ "join",
+ net_dom_join,
+ NET_TRANSPORT_LOCAL,
+ "Join a remote machine",
+ "net dom join <domain=DOMAIN> <ou=OU> "
+ "<account=ACCOUNT> <password=PASSWORD> <reboot>\n"
+ " Join a remote machine"
+ },
+ {
+ "unjoin",
+ net_dom_unjoin,
+ NET_TRANSPORT_LOCAL,
+ "Unjoin a remote machine",
+ "net dom unjoin <account=ACCOUNT> <password=PASSWORD> "
+ "<reboot>\n"
+ " Unjoin a remote machine"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ status = libnetapi_init(&c->netapi_ctx);
+ if (status != 0) {
+ return -1;
+ }
+
+ libnetapi_set_username(c->netapi_ctx, c->opt_user_name);
+ libnetapi_set_password(c->netapi_ctx, c->opt_password);
+ if (c->opt_kerberos) {
+ libnetapi_set_use_kerberos(c->netapi_ctx);
+ }
+
+ return net_run_function(c, argc, argv, "net dom", func);
+}
diff --git a/source3/utils/net_file.c b/source3/utils/net_file.c
new file mode 100644
index 0000000000..8aa1b0e443
--- /dev/null
+++ b/source3/utils/net_file.c
@@ -0,0 +1,57 @@
+/*
+ Samba Unix/Linux SMB client library
+ net file commands
+ Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
+ Copyright (C) 2002 Andrew Tridgell (tridge@samba.org)
+ Copyright (C) 2008 Kai Blin (kai@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+int net_file_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("net [<method>] file [misc. options] [targets]\n"\
+ "\tlists all open files on file server\n\n");
+ d_printf("net [<method>] file USER <username> "\
+ "[misc. options] [targets]"\
+ "\n\tlists all files opened by username on file server\n\n");
+ d_printf("net [<method>] file CLOSE <id> [misc. options] [targets]\n"\
+ "\tcloses specified file on target server\n\n");
+ d_printf("net [rap] file INFO <id> [misc. options] [targets]\n"\
+ "\tdisplays information about the specified open file\n");
+
+ net_common_methods_usage(c, argc, argv);
+ net_common_flags_usage(c, argc, argv);
+ return -1;
+}
+
+int net_file(struct net_context *c, int argc, const char **argv)
+{
+ if (argc < 1)
+ return net_file_usage(c, argc, argv);
+
+ if (StrCaseCmp(argv[0], "HELP") == 0) {
+ net_file_usage(c, argc, argv);
+ return 0;
+ }
+
+ if (net_rpc_check(c, 0))
+ return net_rpc_file(c, argc, argv);
+ return net_rap_file(c, argc, argv);
+}
+
+
diff --git a/source3/utils/net_group.c b/source3/utils/net_group.c
new file mode 100644
index 0000000000..2d5dba8b58
--- /dev/null
+++ b/source3/utils/net_group.c
@@ -0,0 +1,65 @@
+/*
+ Samba Unix/Linux SMB client library
+ net group commands
+ Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
+ Copyright (C) 2002 Andrew Tridgell (tridge@samba.org)
+ Copyright (C) 2008 Kai Blin (kai@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+int net_group_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("net [<method>] group [misc. options] [targets]"\
+ "\n\tList user groups\n\n");
+ d_printf("net rpc group LIST [global|local|builtin]* [misc. options]"\
+ "\n\tList specific user groups\n\n");
+ d_printf("net [<method>] group DELETE <name> "\
+ "[misc. options] [targets]"\
+ "\n\tDelete specified group\n");
+ d_printf("\nnet [<method>] group ADD <name> [-C comment] [-c container]"\
+ " [misc. options] [targets]\n\tCreate specified group\n");
+ d_printf("\nnet rpc group MEMBERS <name>\n\tList Group Members\n\n");
+ d_printf("\nnet rpc group ADDMEM <group> <member>\n\tAdd Group Members\n\n");
+ d_printf("\nnet rpc group DELMEM <group> <member>\n\tDelete Group Members\n\n");
+ net_common_methods_usage(c, argc, argv);
+ net_common_flags_usage(c, argc, argv);
+ d_printf("\t-C or --comment=<comment>\tdescriptive comment (for add only)\n");
+ d_printf("\t-c or --container=<container>\tLDAP container, defaults to cn=Users (for add in ADS only)\n");
+ d_printf("\t-L or --localgroup\t\tWhen adding groups, create a local group (alias)\n");
+ return -1;
+}
+
+int net_group(struct net_context *c, int argc, const char **argv)
+{
+ if (argc < 1)
+ return net_group_usage(c, argc, argv);
+
+ if (StrCaseCmp(argv[0], "HELP") == 0) {
+ net_group_usage(c, argc, argv);
+ return 0;
+ }
+
+ if (net_ads_check(c) == 0)
+ return net_ads_group(c, argc, argv);
+
+ if (argc == 0 && net_rpc_check(c, NET_FLAGS_PDC))
+ return net_rpc_group(c,argc, argv);
+
+ return net_rap_group(c, argc, argv);
+}
+
diff --git a/source3/utils/net_groupmap.c b/source3/utils/net_groupmap.c
new file mode 100644
index 0000000000..b160d840a0
--- /dev/null
+++ b/source3/utils/net_groupmap.c
@@ -0,0 +1,906 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Jean François Micouleau 1998-2001.
+ * Copyright (C) Gerald Carter 2003,
+ * Copyright (C) Volker Lendecke 2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "includes.h"
+#include "utils/net.h"
+
+/*********************************************************
+ Figure out if the input was an NT group or a SID string.
+ Return the SID.
+**********************************************************/
+static bool get_sid_from_input(DOM_SID *sid, char *input)
+{
+ GROUP_MAP map;
+
+ if (StrnCaseCmp( input, "S-", 2)) {
+ /* Perhaps its the NT group name? */
+ if (!pdb_getgrnam(&map, input)) {
+ printf("NT Group %s doesn't exist in mapping DB\n", input);
+ return false;
+ } else {
+ *sid = map.sid;
+ }
+ } else {
+ if (!string_to_sid(sid, input)) {
+ printf("converting sid %s from a string failed!\n", input);
+ return false;
+ }
+ }
+ return true;
+}
+
+/*********************************************************
+ Dump a GROUP_MAP entry to stdout (long or short listing)
+**********************************************************/
+
+static void print_map_entry ( GROUP_MAP map, bool long_list )
+{
+ if (!long_list)
+ d_printf("%s (%s) -> %s\n", map.nt_name,
+ sid_string_tos(&map.sid), gidtoname(map.gid));
+ else {
+ d_printf("%s\n", map.nt_name);
+ d_printf("\tSID : %s\n", sid_string_tos(&map.sid));
+ d_printf("\tUnix gid : %d\n", map.gid);
+ d_printf("\tUnix group: %s\n", gidtoname(map.gid));
+ d_printf("\tGroup type: %s\n",
+ sid_type_lookup(map.sid_name_use));
+ d_printf("\tComment : %s\n", map.comment);
+ }
+
+}
+/*********************************************************
+ List the groups.
+**********************************************************/
+static int net_groupmap_list(struct net_context *c, int argc, const char **argv)
+{
+ size_t entries;
+ bool long_list = false;
+ size_t i;
+ fstring ntgroup = "";
+ fstring sid_string = "";
+ const char list_usage_str[] = "net groupmap list [verbose] "
+ "[ntgroup=NT group] [sid=SID]\n"
+ " verbose\tPrint verbose list\n"
+ " ntgroup\tNT group to list\n"
+ " sid\tSID of group to list";
+
+ if (c->display_usage) {
+ d_printf("Usage:\n%s\n", list_usage_str);
+ return 0;
+ }
+
+ if (c->opt_verbose || c->opt_long_list_entries)
+ long_list = true;
+
+ /* get the options */
+ for ( i=0; i<argc; i++ ) {
+ if ( !StrCaseCmp(argv[i], "verbose")) {
+ long_list = true;
+ }
+ else if ( !StrnCaseCmp(argv[i], "ntgroup", strlen("ntgroup")) ) {
+ fstrcpy( ntgroup, get_string_param( argv[i] ) );
+ if ( !ntgroup[0] ) {
+ d_fprintf(stderr, "must supply a name\n");
+ return -1;
+ }
+ }
+ else if ( !StrnCaseCmp(argv[i], "sid", strlen("sid")) ) {
+ fstrcpy( sid_string, get_string_param( argv[i] ) );
+ if ( !sid_string[0] ) {
+ d_fprintf(stderr, "must supply a SID\n");
+ return -1;
+ }
+ }
+ else {
+ d_fprintf(stderr, "Bad option: %s\n", argv[i]);
+ d_printf("Usage:\n%s\n", list_usage_str);
+ return -1;
+ }
+ }
+
+ /* list a single group is given a name */
+ if ( ntgroup[0] || sid_string[0] ) {
+ DOM_SID sid;
+ GROUP_MAP map;
+
+ if ( sid_string[0] )
+ fstrcpy( ntgroup, sid_string);
+
+ if (!get_sid_from_input(&sid, ntgroup)) {
+ return -1;
+ }
+
+ /* Get the current mapping from the database */
+ if(!pdb_getgrsid(&map, sid)) {
+ d_fprintf(stderr, "Failure to local group SID in the database\n");
+ return -1;
+ }
+
+ print_map_entry( map, long_list );
+ }
+ else {
+ GROUP_MAP *map=NULL;
+ /* enumerate all group mappings */
+ if (!pdb_enum_group_mapping(NULL, SID_NAME_UNKNOWN, &map, &entries, ENUM_ALL_MAPPED))
+ return -1;
+
+ for (i=0; i<entries; i++) {
+ print_map_entry( map[i], long_list );
+ }
+
+ SAFE_FREE(map);
+ }
+
+ return 0;
+}
+
+/*********************************************************
+ Add a new group mapping entry
+**********************************************************/
+
+static int net_groupmap_add(struct net_context *c, int argc, const char **argv)
+{
+ DOM_SID sid;
+ fstring ntgroup = "";
+ fstring unixgrp = "";
+ fstring string_sid = "";
+ fstring type = "";
+ fstring ntcomment = "";
+ enum lsa_SidType sid_type = SID_NAME_DOM_GRP;
+ uint32 rid = 0;
+ gid_t gid;
+ int i;
+ GROUP_MAP map;
+
+ const char *name_type;
+ const char add_usage_str[] = "net groupmap add {rid=<int>|sid=<string>}"
+ " unixgroup=<string> "
+ "[type=<domain|local|builtin>] "
+ "[ntgroup=<string>] [comment=<string>]";
+
+ ZERO_STRUCT(map);
+
+ /* Default is domain group. */
+ map.sid_name_use = SID_NAME_DOM_GRP;
+ name_type = "domain group";
+
+ if (c->display_usage) {
+ d_printf("Usage\n%s\n", add_usage_str);
+ return 0;
+ }
+
+ /* get the options */
+ for ( i=0; i<argc; i++ ) {
+ if ( !StrnCaseCmp(argv[i], "rid", strlen("rid")) ) {
+ rid = get_int_param(argv[i]);
+ if ( rid < DOMAIN_GROUP_RID_ADMINS ) {
+ d_fprintf(stderr, "RID must be greater than %d\n", (uint32)DOMAIN_GROUP_RID_ADMINS-1);
+ return -1;
+ }
+ }
+ else if ( !StrnCaseCmp(argv[i], "unixgroup", strlen("unixgroup")) ) {
+ fstrcpy( unixgrp, get_string_param( argv[i] ) );
+ if ( !unixgrp[0] ) {
+ d_fprintf(stderr, "must supply a name\n");
+ return -1;
+ }
+ }
+ else if ( !StrnCaseCmp(argv[i], "ntgroup", strlen("ntgroup")) ) {
+ fstrcpy( ntgroup, get_string_param( argv[i] ) );
+ if ( !ntgroup[0] ) {
+ d_fprintf(stderr, "must supply a name\n");
+ return -1;
+ }
+ }
+ else if ( !StrnCaseCmp(argv[i], "sid", strlen("sid")) ) {
+ fstrcpy( string_sid, get_string_param( argv[i] ) );
+ if ( !string_sid[0] ) {
+ d_fprintf(stderr, "must supply a SID\n");
+ return -1;
+ }
+ }
+ else if ( !StrnCaseCmp(argv[i], "comment", strlen("comment")) ) {
+ fstrcpy( ntcomment, get_string_param( argv[i] ) );
+ if ( !ntcomment[0] ) {
+ d_fprintf(stderr, "must supply a comment string\n");
+ return -1;
+ }
+ }
+ else if ( !StrnCaseCmp(argv[i], "type", strlen("type")) ) {
+ fstrcpy( type, get_string_param( argv[i] ) );
+ switch ( type[0] ) {
+ case 'b':
+ case 'B':
+ sid_type = SID_NAME_WKN_GRP;
+ name_type = "wellknown group";
+ break;
+ case 'd':
+ case 'D':
+ sid_type = SID_NAME_DOM_GRP;
+ name_type = "domain group";
+ break;
+ case 'l':
+ case 'L':
+ sid_type = SID_NAME_ALIAS;
+ name_type = "alias (local) group";
+ break;
+ default:
+ d_fprintf(stderr, "unknown group type %s\n", type);
+ return -1;
+ }
+ }
+ else {
+ d_fprintf(stderr, "Bad option: %s\n", argv[i]);
+ return -1;
+ }
+ }
+
+ if ( !unixgrp[0] ) {
+ d_printf("Usage:\n%s\n", add_usage_str);
+ return -1;
+ }
+
+ if ( (gid = nametogid(unixgrp)) == (gid_t)-1 ) {
+ d_fprintf(stderr, "Can't lookup UNIX group %s\n", unixgrp);
+ return -1;
+ }
+
+ {
+ if (pdb_getgrgid(&map, gid)) {
+ d_printf("Unix group %s already mapped to SID %s\n",
+ unixgrp, sid_string_tos(&map.sid));
+ return -1;
+ }
+ }
+
+ if ( (rid == 0) && (string_sid[0] == '\0') ) {
+ d_printf("No rid or sid specified, choosing a RID\n");
+ if (pdb_rid_algorithm()) {
+ rid = algorithmic_pdb_gid_to_group_rid(gid);
+ } else {
+ if (!pdb_new_rid(&rid)) {
+ d_printf("Could not get new RID\n");
+ }
+ }
+ d_printf("Got RID %d\n", rid);
+ }
+
+ /* append the rid to our own domain/machine SID if we don't have a full SID */
+ if ( !string_sid[0] ) {
+ sid_copy(&sid, get_global_sam_sid());
+ sid_append_rid(&sid, rid);
+ sid_to_fstring(string_sid, &sid);
+ }
+
+ if (!ntcomment[0]) {
+ switch (sid_type) {
+ case SID_NAME_WKN_GRP:
+ fstrcpy(ntcomment, "Wellknown Unix group");
+ break;
+ case SID_NAME_DOM_GRP:
+ fstrcpy(ntcomment, "Domain Unix group");
+ break;
+ case SID_NAME_ALIAS:
+ fstrcpy(ntcomment, "Local Unix group");
+ break;
+ default:
+ fstrcpy(ntcomment, "Unix group");
+ break;
+ }
+ }
+
+ if (!ntgroup[0] )
+ fstrcpy( ntgroup, unixgrp );
+
+ if (!NT_STATUS_IS_OK(add_initial_entry(gid, string_sid, sid_type, ntgroup, ntcomment))) {
+ d_fprintf(stderr, "adding entry for group %s failed!\n", ntgroup);
+ return -1;
+ }
+
+ d_printf("Successfully added group %s to the mapping db as a %s\n",
+ ntgroup, name_type);
+ return 0;
+}
+
+static int net_groupmap_modify(struct net_context *c, int argc, const char **argv)
+{
+ DOM_SID sid;
+ GROUP_MAP map;
+ fstring ntcomment = "";
+ fstring type = "";
+ fstring ntgroup = "";
+ fstring unixgrp = "";
+ fstring sid_string = "";
+ enum lsa_SidType sid_type = SID_NAME_UNKNOWN;
+ int i;
+ gid_t gid;
+ const char modify_usage_str[] = "net groupmap modify "
+ "{ntgroup=<string>|sid=<SID>} "
+ "[comment=<string>] "
+ "[unixgroup=<string>] "
+ "[type=<domain|local>]";
+
+ if (c->display_usage) {
+ d_printf("Usage:\n%s\n", modify_usage_str);
+ return 0;
+ }
+
+ /* get the options */
+ for ( i=0; i<argc; i++ ) {
+ if ( !StrnCaseCmp(argv[i], "ntgroup", strlen("ntgroup")) ) {
+ fstrcpy( ntgroup, get_string_param( argv[i] ) );
+ if ( !ntgroup[0] ) {
+ d_fprintf(stderr, "must supply a name\n");
+ return -1;
+ }
+ }
+ else if ( !StrnCaseCmp(argv[i], "sid", strlen("sid")) ) {
+ fstrcpy( sid_string, get_string_param( argv[i] ) );
+ if ( !sid_string[0] ) {
+ d_fprintf(stderr, "must supply a name\n");
+ return -1;
+ }
+ }
+ else if ( !StrnCaseCmp(argv[i], "comment", strlen("comment")) ) {
+ fstrcpy( ntcomment, get_string_param( argv[i] ) );
+ if ( !ntcomment[0] ) {
+ d_fprintf(stderr, "must supply a comment string\n");
+ return -1;
+ }
+ }
+ else if ( !StrnCaseCmp(argv[i], "unixgroup", strlen("unixgroup")) ) {
+ fstrcpy( unixgrp, get_string_param( argv[i] ) );
+ if ( !unixgrp[0] ) {
+ d_fprintf(stderr, "must supply a group name\n");
+ return -1;
+ }
+ }
+ else if ( !StrnCaseCmp(argv[i], "type", strlen("type")) ) {
+ fstrcpy( type, get_string_param( argv[i] ) );
+ switch ( type[0] ) {
+ case 'd':
+ case 'D':
+ sid_type = SID_NAME_DOM_GRP;
+ break;
+ case 'l':
+ case 'L':
+ sid_type = SID_NAME_ALIAS;
+ break;
+ }
+ }
+ else {
+ d_fprintf(stderr, "Bad option: %s\n", argv[i]);
+ return -1;
+ }
+ }
+
+ if ( !ntgroup[0] && !sid_string[0] ) {
+ d_printf("Usage:\n%s\n", modify_usage_str);
+ return -1;
+ }
+
+ /* give preference to the SID; if both the ntgroup name and SID
+ are defined, use the SID and assume that the group name could be a
+ new name */
+
+ if ( sid_string[0] ) {
+ if (!get_sid_from_input(&sid, sid_string)) {
+ return -1;
+ }
+ }
+ else {
+ if (!get_sid_from_input(&sid, ntgroup)) {
+ return -1;
+ }
+ }
+
+ /* Get the current mapping from the database */
+ if(!pdb_getgrsid(&map, sid)) {
+ d_fprintf(stderr, "Failure to local group SID in the database\n");
+ return -1;
+ }
+
+ /*
+ * Allow changing of group type only between domain and local
+ * We disallow changing Builtin groups !!! (SID problem)
+ */
+ if (sid_type == SID_NAME_UNKNOWN) {
+ d_fprintf(stderr, "Can't map to an unknown group type.\n");
+ return -1;
+ }
+
+ if (map.sid_name_use == SID_NAME_WKN_GRP) {
+ d_fprintf(stderr, "You can only change between domain and local groups.\n");
+ return -1;
+ }
+
+ map.sid_name_use=sid_type;
+
+ /* Change comment if new one */
+ if ( ntcomment[0] )
+ fstrcpy( map.comment, ntcomment );
+
+ if ( ntgroup[0] )
+ fstrcpy( map.nt_name, ntgroup );
+
+ if ( unixgrp[0] ) {
+ gid = nametogid( unixgrp );
+ if ( gid == -1 ) {
+ d_fprintf(stderr, "Unable to lookup UNIX group %s. Make sure the group exists.\n",
+ unixgrp);
+ return -1;
+ }
+
+ map.gid = gid;
+ }
+
+ if ( !NT_STATUS_IS_OK(pdb_update_group_mapping_entry(&map)) ) {
+ d_fprintf(stderr, "Could not update group database\n");
+ return -1;
+ }
+
+ d_printf("Updated mapping entry for %s\n", map.nt_name);
+
+ return 0;
+}
+
+static int net_groupmap_delete(struct net_context *c, int argc, const char **argv)
+{
+ DOM_SID sid;
+ fstring ntgroup = "";
+ fstring sid_string = "";
+ int i;
+ const char delete_usage_str[] = "net groupmap delete "
+ "{ntgroup=<string>|sid=<SID>}";
+
+ if (c->display_usage) {
+ d_printf("Usage:\n%s\n", delete_usage_str);
+ return 0;
+ }
+
+ /* get the options */
+ for ( i=0; i<argc; i++ ) {
+ if ( !StrnCaseCmp(argv[i], "ntgroup", strlen("ntgroup")) ) {
+ fstrcpy( ntgroup, get_string_param( argv[i] ) );
+ if ( !ntgroup[0] ) {
+ d_fprintf(stderr, "must supply a name\n");
+ return -1;
+ }
+ }
+ else if ( !StrnCaseCmp(argv[i], "sid", strlen("sid")) ) {
+ fstrcpy( sid_string, get_string_param( argv[i] ) );
+ if ( !sid_string[0] ) {
+ d_fprintf(stderr, "must supply a SID\n");
+ return -1;
+ }
+ }
+ else {
+ d_fprintf(stderr, "Bad option: %s\n", argv[i]);
+ return -1;
+ }
+ }
+
+ if ( !ntgroup[0] && !sid_string[0]) {
+ d_printf("Usage:\n%s\n", delete_usage_str);
+ return -1;
+ }
+
+ /* give preference to the SID if we have that */
+
+ if ( sid_string[0] )
+ fstrcpy( ntgroup, sid_string );
+
+ if ( !get_sid_from_input(&sid, ntgroup) ) {
+ d_fprintf(stderr, "Unable to resolve group %s to a SID\n", ntgroup);
+ return -1;
+ }
+
+ if ( !NT_STATUS_IS_OK(pdb_delete_group_mapping_entry(sid)) ) {
+ d_fprintf(stderr, "Failed to removing group %s from the mapping db!\n", ntgroup);
+ return -1;
+ }
+
+ d_printf("Sucessfully removed %s from the mapping db\n", ntgroup);
+
+ return 0;
+}
+
+static int net_groupmap_set(struct net_context *c, int argc, const char **argv)
+{
+ const char *ntgroup = NULL;
+ struct group *grp = NULL;
+ GROUP_MAP map;
+ bool have_map = false;
+
+ if ((argc < 1) || (argc > 2) || c->display_usage) {
+ d_printf("Usage: net groupmap set \"NT Group\" "
+ "[\"unix group\"] [-C \"comment\"] [-L] [-D]\n");
+ return -1;
+ }
+
+ if ( c->opt_localgroup && c->opt_domaingroup ) {
+ d_printf("Can only specify -L or -D, not both\n");
+ return -1;
+ }
+
+ ntgroup = argv[0];
+
+ if (argc == 2) {
+ grp = getgrnam(argv[1]);
+
+ if (grp == NULL) {
+ d_fprintf(stderr, "Could not find unix group %s\n", argv[1]);
+ return -1;
+ }
+ }
+
+ have_map = pdb_getgrnam(&map, ntgroup);
+
+ if (!have_map) {
+ DOM_SID sid;
+ have_map = ( (strncmp(ntgroup, "S-", 2) == 0) &&
+ string_to_sid(&sid, ntgroup) &&
+ pdb_getgrsid(&map, sid) );
+ }
+
+ if (!have_map) {
+
+ /* Ok, add it */
+
+ if (grp == NULL) {
+ d_fprintf(stderr, "Could not find group mapping for %s\n",
+ ntgroup);
+ return -1;
+ }
+
+ map.gid = grp->gr_gid;
+
+ if (c->opt_rid == 0) {
+ if ( pdb_rid_algorithm() )
+ c->opt_rid = algorithmic_pdb_gid_to_group_rid(map.gid);
+ else {
+ if ( !pdb_new_rid((uint32*)&c->opt_rid) ) {
+ d_fprintf( stderr, "Could not allocate new RID\n");
+ return -1;
+ }
+ }
+ }
+
+ sid_copy(&map.sid, get_global_sam_sid());
+ sid_append_rid(&map.sid, c->opt_rid);
+
+ map.sid_name_use = SID_NAME_DOM_GRP;
+ fstrcpy(map.nt_name, ntgroup);
+ fstrcpy(map.comment, "");
+
+ if (!NT_STATUS_IS_OK(pdb_add_group_mapping_entry(&map))) {
+ d_fprintf(stderr, "Could not add mapping entry for %s\n",
+ ntgroup);
+ return -1;
+ }
+ }
+
+ /* Now we have a mapping entry, update that stuff */
+
+ if ( c->opt_localgroup || c->opt_domaingroup ) {
+ if (map.sid_name_use == SID_NAME_WKN_GRP) {
+ d_fprintf(stderr, "Can't change type of the BUILTIN group %s\n",
+ map.nt_name);
+ return -1;
+ }
+ }
+
+ if (c->opt_localgroup)
+ map.sid_name_use = SID_NAME_ALIAS;
+
+ if (c->opt_domaingroup)
+ map.sid_name_use = SID_NAME_DOM_GRP;
+
+ /* The case (opt_domaingroup && opt_localgroup) was tested for above */
+
+ if (strlen(c->opt_comment) > 0)
+ fstrcpy(map.comment, c->opt_comment);
+
+ if (strlen(c->opt_newntname) > 0)
+ fstrcpy(map.nt_name, c->opt_newntname);
+
+ if (grp != NULL)
+ map.gid = grp->gr_gid;
+
+ if (!NT_STATUS_IS_OK(pdb_update_group_mapping_entry(&map))) {
+ d_fprintf(stderr, "Could not update group mapping for %s\n", ntgroup);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int net_groupmap_cleanup(struct net_context *c, int argc, const char **argv)
+{
+ GROUP_MAP *map = NULL;
+ size_t i, entries;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net groupmap cleanup\n"
+ " Delete all group mappings\n");
+ return 0;
+ }
+
+ if (!pdb_enum_group_mapping(NULL, SID_NAME_UNKNOWN, &map, &entries,
+ ENUM_ALL_MAPPED)) {
+ d_fprintf(stderr, "Could not list group mappings\n");
+ return -1;
+ }
+
+ for (i=0; i<entries; i++) {
+
+ if (map[i].gid == -1)
+ printf("Group %s is not mapped\n", map[i].nt_name);
+
+ if (!sid_check_is_in_our_domain(&map[i].sid)) {
+ printf("Deleting mapping for NT Group %s, sid %s\n",
+ map[i].nt_name,
+ sid_string_tos(&map[i].sid));
+ pdb_delete_group_mapping_entry(map[i].sid);
+ }
+ }
+
+ SAFE_FREE(map);
+
+ return 0;
+}
+
+static int net_groupmap_addmem(struct net_context *c, int argc, const char **argv)
+{
+ DOM_SID alias, member;
+
+ if ( (argc != 2) ||
+ c->display_usage ||
+ !string_to_sid(&alias, argv[0]) ||
+ !string_to_sid(&member, argv[1]) ) {
+ d_printf("Usage: net groupmap addmem alias-sid member-sid\n");
+ return -1;
+ }
+
+ if (!NT_STATUS_IS_OK(pdb_add_aliasmem(&alias, &member))) {
+ d_fprintf(stderr, "Could not add sid %s to alias %s\n",
+ argv[1], argv[0]);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int net_groupmap_delmem(struct net_context *c, int argc, const char **argv)
+{
+ DOM_SID alias, member;
+
+ if ( (argc != 2) ||
+ c->display_usage ||
+ !string_to_sid(&alias, argv[0]) ||
+ !string_to_sid(&member, argv[1]) ) {
+ d_printf("Usage: net groupmap delmem alias-sid member-sid\n");
+ return -1;
+ }
+
+ if (!NT_STATUS_IS_OK(pdb_del_aliasmem(&alias, &member))) {
+ d_fprintf(stderr, "Could not delete sid %s from alias %s\n",
+ argv[1], argv[0]);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int net_groupmap_listmem(struct net_context *c, int argc, const char **argv)
+{
+ DOM_SID alias;
+ DOM_SID *members;
+ size_t i, num;
+
+ if ( (argc != 1) ||
+ c->display_usage ||
+ !string_to_sid(&alias, argv[0]) ) {
+ d_printf("Usage: net groupmap listmem alias-sid\n");
+ return -1;
+ }
+
+ members = NULL;
+ num = 0;
+
+ if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(&alias, &members, &num))) {
+ d_fprintf(stderr, "Could not list members for sid %s\n", argv[0]);
+ return -1;
+ }
+
+ for (i = 0; i < num; i++) {
+ printf("%s\n", sid_string_tos(&(members[i])));
+ }
+
+ TALLOC_FREE(members);
+
+ return 0;
+}
+
+static bool print_alias_memberships(TALLOC_CTX *mem_ctx,
+ const DOM_SID *domain_sid,
+ const DOM_SID *member)
+{
+ uint32 *alias_rids;
+ size_t i, num_alias_rids;
+
+ alias_rids = NULL;
+ num_alias_rids = 0;
+
+ if (!NT_STATUS_IS_OK(pdb_enum_alias_memberships(
+ mem_ctx, domain_sid, member, 1,
+ &alias_rids, &num_alias_rids))) {
+ d_fprintf(stderr, "Could not list memberships for sid %s\n",
+ sid_string_tos(member));
+ return false;
+ }
+
+ for (i = 0; i < num_alias_rids; i++) {
+ DOM_SID alias;
+ sid_copy(&alias, domain_sid);
+ sid_append_rid(&alias, alias_rids[i]);
+ printf("%s\n", sid_string_tos(&alias));
+ }
+
+ return true;
+}
+
+static int net_groupmap_memberships(struct net_context *c, int argc, const char **argv)
+{
+ TALLOC_CTX *mem_ctx;
+ DOM_SID *domain_sid, *builtin_sid, member;
+
+ if ( (argc != 1) ||
+ c->display_usage ||
+ !string_to_sid(&member, argv[0]) ) {
+ d_printf("Usage: net groupmap memberof sid\n");
+ return -1;
+ }
+
+ mem_ctx = talloc_init("net_groupmap_memberships");
+ if (mem_ctx == NULL) {
+ d_fprintf(stderr, "talloc_init failed\n");
+ return -1;
+ }
+
+ domain_sid = get_global_sam_sid();
+ builtin_sid = string_sid_talloc(mem_ctx, "S-1-5-32");
+ if ((domain_sid == NULL) || (builtin_sid == NULL)) {
+ d_fprintf(stderr, "Could not get domain sid\n");
+ return -1;
+ }
+
+ if (!print_alias_memberships(mem_ctx, domain_sid, &member) ||
+ !print_alias_memberships(mem_ctx, builtin_sid, &member))
+ return -1;
+
+ talloc_destroy(mem_ctx);
+
+ return 0;
+}
+
+/***********************************************************
+ migrated functionality from smbgroupedit
+ **********************************************************/
+int net_groupmap(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "add",
+ net_groupmap_add,
+ NET_TRANSPORT_LOCAL,
+ "Create a new group mapping",
+ "net groupmap add\n"
+ " Create a new group mapping"
+ },
+ {
+ "modify",
+ net_groupmap_modify,
+ NET_TRANSPORT_LOCAL,
+ "Update a group mapping",
+ "net groupmap modify\n"
+ " Modify an existing group mapping"
+ },
+ {
+ "delete",
+ net_groupmap_delete,
+ NET_TRANSPORT_LOCAL,
+ "Remove a group mapping",
+ "net groupmap delete\n"
+ " Remove a group mapping"
+ },
+ {
+ "set",
+ net_groupmap_set,
+ NET_TRANSPORT_LOCAL,
+ "Set group mapping",
+ "net groupmap set\n"
+ " Set a group mapping"
+ },
+ {
+ "cleanup",
+ net_groupmap_cleanup,
+ NET_TRANSPORT_LOCAL,
+ "Remove foreign group mapping entries",
+ "net groupmap cleanup\n"
+ " Remove foreign group mapping entries"
+ },
+ {
+ "addmem",
+ net_groupmap_addmem,
+ NET_TRANSPORT_LOCAL,
+ "Add a foreign alias member",
+ "net groupmap addmem\n"
+ " Add a foreign alias member"
+ },
+ {
+ "delmem",
+ net_groupmap_delmem,
+ NET_TRANSPORT_LOCAL,
+ "Delete foreign alias member",
+ "net groupmap delmem\n"
+ " Delete foreign alias member"
+ },
+ {
+ "listmem",
+ net_groupmap_listmem,
+ NET_TRANSPORT_LOCAL,
+ "List foreign group members",
+ "net groupmap listmem\n"
+ " List foreign alias members"
+ },
+ {
+ "memberships",
+ net_groupmap_memberships,
+ NET_TRANSPORT_LOCAL,
+ "List foreign group memberships",
+ "net groupmap memberships\n"
+ " List foreign group memberships"
+ },
+ {
+ "list",
+ net_groupmap_list,
+ NET_TRANSPORT_LOCAL,
+ "List current group map",
+ "net groupmap list\n"
+ " List current group map"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ /* we shouldn't have silly checks like this */
+ if (getuid() != 0) {
+ d_fprintf(stderr, "You must be root to edit group mappings.\n");
+ return -1;
+ }
+
+ return net_run_function(c,argc, argv, "net groupmap", func);
+}
+
diff --git a/source3/utils/net_help.c b/source3/utils/net_help.c
new file mode 100644
index 0000000000..0502373aa2
--- /dev/null
+++ b/source3/utils/net_help.c
@@ -0,0 +1,69 @@
+/*
+ Samba Unix/Linux SMB client library
+ net help commands
+ Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+static int net_usage(struct net_context *c, int argc, const char **argv);
+
+static int net_help_usage(struct net_context *c, int argc, const char **argv)
+{
+ c->display_usage = true;
+ return net_usage(c, argc, argv);
+}
+
+static int net_usage(struct net_context *c, int argc, const char **argv)
+{
+ struct functable *table = (struct functable*) c->private_data;
+ int i;
+
+ d_printf("Usage:\n");
+ for (i=0; table[i].funcname != NULL; i++) {
+ if (c->display_usage) {
+ d_printf("net %s usage:\n", table[i].funcname);
+ d_printf("\n%s\n\n", table[i].usage);
+ } else {
+ d_printf("%s %-15s %s\n", "net", table[i].funcname,
+ table[i].description);
+ }
+
+ }
+
+ net_common_flags_usage(c, argc, argv);
+ return -1;
+}
+
+/*
+ handle "net help *" subcommands
+*/
+int net_help(struct net_context *c, int argc, const char **argv)
+{
+ struct functable *func = (struct functable *)c->private_data;
+
+ if (argc == 0) {
+ return net_usage(c, argc, argv);
+ }
+
+ if (StrCaseCmp(argv[0], "help") == 0) {
+ return net_help_usage(c, argc, argv);
+ }
+
+ c->display_usage = true;
+ return net_run_function(c, argc, argv, "net help", func);
+}
diff --git a/source3/utils/net_help_common.c b/source3/utils/net_help_common.c
new file mode 100644
index 0000000000..edf083905a
--- /dev/null
+++ b/source3/utils/net_help_common.c
@@ -0,0 +1,55 @@
+/*
+ Samba Unix/Linux SMB client library
+ net help commands
+ Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+int net_common_methods_usage(struct net_context *c, int argc, const char**argv)
+{
+ d_printf("Valid methods: (auto-detected if not specified)\n");
+ d_printf("\tads\t\t\t\tActive Directory (LDAP/Kerberos)\n");
+ d_printf("\trpc\t\t\t\tDCE-RPC\n");
+ d_printf("\trap\t\t\t\tRAP (older systems)\n");
+ d_printf("\n");
+ return 0;
+}
+
+int net_common_flags_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("Valid targets: choose one (none defaults to localhost)\n");
+ d_printf("\t-S or --server=<server>\t\tserver name\n");
+ d_printf("\t-I or --ipaddress=<ipaddr>\taddress of target server\n");
+ d_printf("\t-w or --workgroup=<wg>\t\ttarget workgroup or domain\n");
+
+ d_printf("\n");
+ d_printf("Valid miscellaneous options are:\n"); /* misc options */
+ d_printf("\t-p or --port=<port>\t\tconnection port on target\n");
+ d_printf("\t-W or --myworkgroup=<wg>\tclient workgroup\n");
+ d_printf("\t-d or --debuglevel=<level>\tdebug level (0-10)\n");
+ d_printf("\t-n or --myname=<name>\t\tclient name\n");
+ d_printf("\t-U or --user=<name>\t\tuser name\n");
+ d_printf("\t-s or --configfile=<path>\tpathname of smb.conf file\n");
+ d_printf("\t-l or --long\t\t\tDisplay full information\n");
+ d_printf("\t-V or --version\t\t\tPrint samba version information\n");
+ d_printf("\t-P or --machine-pass\t\tAuthenticate as machine account\n");
+ d_printf("\t-e or --encrypt\t\t\tEncrypt SMB transport (UNIX extended servers only)\n");
+ d_printf("\t-k or --kerberos\t\tUse kerberos (active directory) authentication\n");
+ return -1;
+}
+
diff --git a/source3/utils/net_help_common.h b/source3/utils/net_help_common.h
new file mode 100644
index 0000000000..ed859936e4
--- /dev/null
+++ b/source3/utils/net_help_common.h
@@ -0,0 +1,49 @@
+/*
+ Samba Unix/Linux SMB client library
+ net help commands
+ Copyright (C) 2008 Kai Blin (kai@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NET_HELP_COMMON_H_
+#define _NET_HELP_COMMON_H_
+
+/**
+ * Get help for common methods.
+ *
+ * This will output some help for using the ADS/RPC/RAP transports.
+ *
+ * @param c A net_context structure
+ * @param argc Normal argc with previous parameters removed
+ * @param argv Normal argv with previous parameters removed
+ * @return 0 on success, nonzero on failure.
+ */
+int net_common_methods_usage(struct net_context *c, int argc, const char**argv);
+
+/**
+ * Get help for common flags.
+ *
+ * This will output some help for using common flags.
+ *
+ * @param c A net_context structure
+ * @param argc Normal argc with previous parameters removed
+ * @param argv Normal argv with previous parameters removed
+ * @return 0 on success, nonzero on failure.
+ */
+int net_common_flags_usage(struct net_context *c, int argc, const char **argv);
+
+
+#endif /* _NET_HELP_COMMON_H_*/
+
diff --git a/source3/utils/net_idmap.c b/source3/utils/net_idmap.c
new file mode 100644
index 0000000000..bd363922f6
--- /dev/null
+++ b/source3/utils/net_idmap.c
@@ -0,0 +1,441 @@
+/*
+ Samba Unix/Linux SMB client library
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) 2003 Andrew Bartlett (abartlet@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+#define ALLOC_CHECK(mem) do { \
+ if (!mem) { \
+ d_fprintf(stderr, "Out of memory!\n"); \
+ talloc_free(ctx); \
+ return -1; \
+ } } while(0)
+
+/***********************************************************
+ Helper function for net_idmap_dump. Dump one entry.
+ **********************************************************/
+static int net_idmap_dump_one_entry(TDB_CONTEXT *tdb,
+ TDB_DATA key,
+ TDB_DATA data,
+ void *unused)
+{
+ if (strcmp((char *)key.dptr, "USER HWM") == 0) {
+ printf("USER HWM %d\n", IVAL(data.dptr,0));
+ return 0;
+ }
+
+ if (strcmp((char *)key.dptr, "GROUP HWM") == 0) {
+ printf("GROUP HWM %d\n", IVAL(data.dptr,0));
+ return 0;
+ }
+
+ if (strncmp((char *)key.dptr, "S-", 2) != 0)
+ return 0;
+
+ printf("%s %s\n", data.dptr, key.dptr);
+ return 0;
+}
+
+/***********************************************************
+ Dump the current idmap
+ **********************************************************/
+static int net_idmap_dump(struct net_context *c, int argc, const char **argv)
+{
+ TDB_CONTEXT *idmap_tdb;
+
+ if ( argc != 1 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net idmap dump <inputfile>\n"
+ " Dump current ID mapping.\n"
+ " inputfile\tTDB file to read mappings from.\n");
+ return c->display_usage?0:-1;
+ }
+
+ idmap_tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDONLY, 0);
+
+ if (idmap_tdb == NULL) {
+ d_fprintf(stderr, "Could not open idmap: %s\n", argv[0]);
+ return -1;
+ }
+
+ tdb_traverse(idmap_tdb, net_idmap_dump_one_entry, NULL);
+
+ tdb_close(idmap_tdb);
+
+ return 0;
+}
+
+/***********************************************************
+ Write entries from stdin to current local idmap
+ **********************************************************/
+
+static int net_idmap_restore(struct net_context *c, int argc, const char **argv)
+{
+ TALLOC_CTX *ctx;
+ FILE *input;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net idmap restore [inputfile]\n"
+ " Restore ID mappings from file\n"
+ " inputfile\tFile to load ID mappings from. If not "
+ "given, load data from stdin.\n");
+ return 0;
+ }
+
+ if (! winbind_ping()) {
+ d_fprintf(stderr, "To use net idmap Winbindd must be running.\n");
+ return -1;
+ }
+
+ ctx = talloc_new(NULL);
+ ALLOC_CHECK(ctx);
+
+ if (argc == 1) {
+ input = fopen(argv[0], "r");
+ } else {
+ input = stdin;
+ }
+
+ while (!feof(input)) {
+ char line[128], sid_string[128];
+ int len;
+ struct wbcDomainSid sid;
+ enum id_type type = ID_TYPE_NOT_SPECIFIED;
+ unsigned long idval;
+ wbcErr wbc_status;
+
+ if (fgets(line, 127, input) == NULL)
+ break;
+
+ len = strlen(line);
+
+ if ( (len > 0) && (line[len-1] == '\n') )
+ line[len-1] = '\0';
+
+ if (sscanf(line, "GID %lu %128s", &idval, sid_string) == 2) {
+ type = ID_TYPE_GID;
+ } else if (sscanf(line, "UID %lu %128s", &idval, sid_string) == 2) {
+ type = ID_TYPE_UID;
+ } else if (sscanf(line, "USER HWM %lu", &idval) == 1) {
+ /* set uid hwm */
+ wbc_status = wbcSetUidHwm(idval);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ d_fprintf(stderr, "Could not set USER HWM: %s\n",
+ wbcErrorString(wbc_status));
+ }
+ continue;
+ } else if (sscanf(line, "GROUP HWM %lu", &idval) == 1) {
+ /* set gid hwm */
+ wbc_status = wbcSetGidHwm(idval);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ d_fprintf(stderr, "Could not set GROUP HWM: %s\n",
+ wbcErrorString(wbc_status));
+ }
+ continue;
+ } else {
+ d_fprintf(stderr, "ignoring invalid line [%s]\n", line);
+ continue;
+ }
+
+ wbc_status = wbcStringToSid(sid_string, &sid);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ d_fprintf(stderr, "ignoring invalid sid [%s]: %s\n",
+ sid_string, wbcErrorString(wbc_status));
+ continue;
+ }
+
+ if (type == ID_TYPE_UID) {
+ wbc_status = wbcSetUidMapping(idval, &sid);
+ } else {
+ wbc_status = wbcSetGidMapping(idval, &sid);
+ }
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ d_fprintf(stderr, "Could not set mapping of %s %lu to sid %s: %s\n",
+ (type == ID_TYPE_GID) ? "GID" : "UID",
+ idval, sid_string,
+ wbcErrorString(wbc_status));
+ continue;
+ }
+ }
+
+ if (input != stdin) {
+ fclose(input);
+ }
+
+ talloc_free(ctx);
+ return 0;
+}
+
+/***********************************************************
+ Delete a SID mapping from a winbindd_idmap.tdb
+ **********************************************************/
+static int net_idmap_delete(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("Not Implemented yet\n");
+ return -1;
+}
+
+static int net_idmap_set(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("Not Implemented yet\n");
+ return -1;
+}
+bool idmap_store_secret(const char *backend, bool alloc,
+ const char *domain, const char *identity,
+ const char *secret)
+{
+ char *tmp;
+ int r;
+ bool ret;
+
+ if (alloc) {
+ r = asprintf(&tmp, "IDMAP_ALLOC_%s", backend);
+ } else {
+ r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain);
+ }
+
+ if (r < 0) return false;
+
+ strupper_m(tmp); /* make sure the key is case insensitive */
+ ret = secrets_store_generic(tmp, identity, secret);
+
+ free(tmp);
+ return ret;
+}
+
+
+static int net_idmap_secret(struct net_context *c, int argc, const char **argv)
+{
+ TALLOC_CTX *ctx;
+ const char *secret;
+ const char *dn;
+ char *domain;
+ char *backend;
+ char *opt = NULL;
+ bool ret;
+
+ if (argc != 2 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net idmap secret {<DOMAIN>|alloc} <secret>\n"
+ " Set the secret for the specified domain "
+ "(or alloc module)\n"
+ " DOMAIN\tDomain to set secret for.\n"
+ " alloc\tSet secret for the alloc module\n"
+ " secret\tNew secret to set.\n");
+ return c->display_usage?0:-1;
+ }
+
+ secret = argv[1];
+
+ ctx = talloc_new(NULL);
+ ALLOC_CHECK(ctx);
+
+ if (strcmp(argv[0], "alloc") == 0) {
+ domain = NULL;
+ backend = lp_idmap_alloc_backend();
+ } else {
+ domain = talloc_strdup(ctx, argv[0]);
+ ALLOC_CHECK(domain);
+
+ opt = talloc_asprintf(ctx, "idmap config %s", domain);
+ ALLOC_CHECK(opt);
+
+ backend = talloc_strdup(ctx, lp_parm_const_string(-1, opt, "backend", "tdb"));
+ ALLOC_CHECK(backend);
+ }
+
+ if ( ( ! backend) || ( ! strequal(backend, "ldap"))) {
+ d_fprintf(stderr, "The only currently supported backend is LDAP\n");
+ talloc_free(ctx);
+ return -1;
+ }
+
+ if (domain) {
+
+ dn = lp_parm_const_string(-1, opt, "ldap_user_dn", NULL);
+ if ( ! dn) {
+ d_fprintf(stderr, "Missing ldap_user_dn option for domain %s\n", domain);
+ talloc_free(ctx);
+ return -1;
+ }
+
+ ret = idmap_store_secret("ldap", false, domain, dn, secret);
+ } else {
+ dn = lp_parm_const_string(-1, "idmap alloc config", "ldap_user_dn", NULL);
+ if ( ! dn) {
+ d_fprintf(stderr, "Missing ldap_user_dn option for alloc backend\n");
+ talloc_free(ctx);
+ return -1;
+ }
+
+ ret = idmap_store_secret("ldap", true, NULL, dn, secret);
+ }
+
+ if ( ! ret) {
+ d_fprintf(stderr, "Failed to store secret\n");
+ talloc_free(ctx);
+ return -1;
+ }
+
+ d_printf("Secret stored\n");
+ return 0;
+}
+
+int net_help_idmap(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("net idmap dump <inputfile>\n"
+ " Dump current id mapping\n");
+
+ d_printf("net idmap restore\n"
+ " Restore entries from stdin\n");
+
+ /* Deliberately *not* document net idmap delete */
+
+ d_printf("net idmap secret <DOMAIN>|alloc <secret>\n"
+ " Set the secret for the specified DOMAIN (or the alloc module)\n");
+
+ return -1;
+}
+
+static int net_idmap_aclmapset(struct net_context *c, int argc, const char **argv)
+{
+ TALLOC_CTX *mem_ctx;
+ int result = -1;
+ DOM_SID src_sid, dst_sid;
+ char *src, *dst;
+ struct db_context *db;
+ struct db_record *rec;
+ NTSTATUS status;
+
+ if (argc != 3 || c->display_usage) {
+ d_fprintf(stderr, "usage: net idmap aclmapset <tdb> "
+ "<src-sid> <dst-sid>\n");
+ return -1;
+ }
+
+ if (!(mem_ctx = talloc_init("net idmap aclmapset"))) {
+ d_fprintf(stderr, "talloc_init failed\n");
+ return -1;
+ }
+
+ if (!(db = db_open(mem_ctx, argv[0], 0, TDB_DEFAULT,
+ O_RDWR|O_CREAT, 0600))) {
+ d_fprintf(stderr, "db_open failed: %s\n", strerror(errno));
+ goto fail;
+ }
+
+ if (!string_to_sid(&src_sid, argv[1])) {
+ d_fprintf(stderr, "%s is not a valid sid\n", argv[1]);
+ goto fail;
+ }
+
+ if (!string_to_sid(&dst_sid, argv[2])) {
+ d_fprintf(stderr, "%s is not a valid sid\n", argv[2]);
+ goto fail;
+ }
+
+ if (!(src = sid_string_talloc(mem_ctx, &src_sid))
+ || !(dst = sid_string_talloc(mem_ctx, &dst_sid))) {
+ d_fprintf(stderr, "talloc_strdup failed\n");
+ goto fail;
+ }
+
+ if (!(rec = db->fetch_locked(
+ db, mem_ctx, string_term_tdb_data(src)))) {
+ d_fprintf(stderr, "could not fetch db record\n");
+ goto fail;
+ }
+
+ status = rec->store(rec, string_term_tdb_data(dst), 0);
+ TALLOC_FREE(rec);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "could not store record: %s\n",
+ nt_errstr(status));
+ goto fail;
+ }
+
+ result = 0;
+fail:
+ TALLOC_FREE(mem_ctx);
+ return result;
+}
+
+/***********************************************************
+ Look at the current idmap
+ **********************************************************/
+int net_idmap(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "dump",
+ net_idmap_dump,
+ NET_TRANSPORT_LOCAL,
+ "Dump the current ID mappings",
+ "net idmap dump\n"
+ " Dump the current ID mappings"
+ },
+ {
+ "restore",
+ net_idmap_restore,
+ NET_TRANSPORT_LOCAL,
+ "Restore entries from stdin",
+ "net idmap restore\n"
+ " Restore entries from stdin"
+ },
+ {
+ "setmap",
+ net_idmap_set,
+ NET_TRANSPORT_LOCAL,
+ "Not implemented yet",
+ "net idmap setmap\n"
+ " Not implemented yet"
+ },
+ {
+ "delete",
+ net_idmap_delete,
+ NET_TRANSPORT_LOCAL,
+ "Not implemented yet",
+ "net idmap delete\n"
+ " Not implemented yet"
+ },
+ {
+ "secret",
+ net_idmap_secret,
+ NET_TRANSPORT_LOCAL,
+ "Set secret for specified domain",
+ "net idmap secret {<DOMAIN>|alloc} <secret>\n"
+ " Set secret for specified domain or alloc module"
+ },
+ {
+ "aclmapset",
+ net_idmap_aclmapset,
+ NET_TRANSPORT_LOCAL,
+ "Set acl map",
+ "net idmap aclmapset\n"
+ " Set acl map"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net idmap", func);
+}
+
+
diff --git a/source3/utils/net_join.c b/source3/utils/net_join.c
new file mode 100644
index 0000000000..98188aae5f
--- /dev/null
+++ b/source3/utils/net_join.c
@@ -0,0 +1,54 @@
+/*
+ Samba Unix/Linux SMB client library
+ net join commands
+ Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
+ Copyright (C) 2008 Kai Blin (kai@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+int net_join_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("\nnet [<method>] join [misc. options]\n"
+ "\tjoins this server to a domain\n");
+ d_printf("Valid methods: (auto-detected if not specified)\n");
+ d_printf("\tads\t\t\t\tActive Directory (LDAP/Kerberos)\n");
+ d_printf("\trpc\t\t\t\tDCE-RPC\n");
+ net_common_flags_usage(c, argc, argv);
+ return -1;
+}
+
+int net_join(struct net_context *c, int argc, const char **argv)
+{
+ if (argc < 1)
+ return net_join_usage(c, argc, argv);
+
+ if (StrCaseCmp(argv[0], "HELP") == 0) {
+ net_join_usage(c, argc, argv);
+ return 0;
+ }
+
+ if (net_ads_check_our_domain(c) == 0) {
+ if (net_ads_join(c, argc, argv) == 0)
+ return 0;
+ else
+ d_fprintf(stderr, "ADS join did not work, falling back to RPC...\n");
+ }
+ return net_rpc_join(c, argc, argv);
+}
+
+
diff --git a/source3/utils/net_lookup.c b/source3/utils/net_lookup.c
new file mode 100644
index 0000000000..8b9ddb62ba
--- /dev/null
+++ b/source3/utils/net_lookup.c
@@ -0,0 +1,447 @@
+/*
+ Samba Unix/Linux SMB client library
+ net lookup command
+ Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "includes.h"
+#include "utils/net.h"
+
+int net_lookup_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(
+" net lookup [host] HOSTNAME[#<type>]\n\tgives IP for a hostname\n\n"
+" net lookup ldap [domain]\n\tgives IP of domain's ldap server\n\n"
+" net lookup kdc [realm]\n\tgives IP of realm's kerberos KDC\n\n"
+" net lookup pdc [domain|realm]\n\tgives IP of realm's kerberos KDC\n\n"
+" net lookup dc [domain]\n\tgives IP of domains Domain Controllers\n\n"
+" net lookup master [domain|wg]\n\tgive IP of master browser\n\n"
+" net lookup name [name]\n\tLookup name's sid and type\n\n"
+" net lookup sid [sid]\n\tGive sid's name and type\n\n"
+" net lookup dsgetdcname [name] [flags] [sitename]\n\n"
+);
+ return -1;
+}
+
+/* lookup a hostname giving an IP */
+static int net_lookup_host(struct net_context *c, int argc, const char **argv)
+{
+ struct sockaddr_storage ss;
+ int name_type = 0x20;
+ char addr[INET6_ADDRSTRLEN];
+ const char *name = argv[0];
+ char *p;
+
+ if (argc == 0)
+ return net_lookup_usage(c, argc, argv);
+
+ p = strchr_m(name,'#');
+ if (p) {
+ *p = '\0';
+ sscanf(++p,"%x",&name_type);
+ }
+
+ if (!resolve_name(name, &ss, name_type)) {
+ /* we deliberately use DEBUG() here to send it to stderr
+ so scripts aren't mucked up */
+ DEBUG(0,("Didn't find %s#%02x\n", name, name_type));
+ return -1;
+ }
+
+ print_sockaddr(addr, sizeof(addr), &ss);
+ d_printf("%s\n", addr);
+ return 0;
+}
+
+#ifdef HAVE_ADS
+static void print_ldap_srvlist(struct dns_rr_srv *dclist, int numdcs )
+{
+ struct sockaddr_storage ss;
+ int i;
+
+ for ( i=0; i<numdcs; i++ ) {
+ if (resolve_name(dclist[i].hostname, &ss, 0x20) ) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr), &ss);
+#ifdef HAVE_IPV6
+ if (ss.ss_family == AF_INET6) {
+ d_printf("[%s]:%d\n", addr, dclist[i].port);
+ }
+#endif
+ if (ss.ss_family == AF_INET) {
+ d_printf("%s:%d\n", addr, dclist[i].port);
+ }
+ }
+ }
+}
+#endif
+
+static int net_lookup_ldap(struct net_context *c, int argc, const char **argv)
+{
+#ifdef HAVE_ADS
+ const char *domain;
+ struct sockaddr_storage ss;
+ struct dns_rr_srv *dcs = NULL;
+ int numdcs = 0;
+ char *sitename;
+ TALLOC_CTX *ctx;
+ NTSTATUS status;
+ int ret;
+ char h_name[MAX_DNS_NAME_LENGTH];
+
+ if (argc > 0)
+ domain = argv[0];
+ else
+ domain = c->opt_target_workgroup;
+
+ sitename = sitename_fetch(domain);
+
+ if ( (ctx = talloc_init("net_lookup_ldap")) == NULL ) {
+ d_fprintf(stderr, "net_lookup_ldap: talloc_init() failed!\n");
+ SAFE_FREE(sitename);
+ return -1;
+ }
+
+ DEBUG(9, ("Lookup up ldap for domain %s\n", domain));
+
+ status = ads_dns_query_dcs( ctx, domain, sitename, &dcs, &numdcs );
+ if ( NT_STATUS_IS_OK(status) && numdcs ) {
+ print_ldap_srvlist(dcs, numdcs);
+ TALLOC_FREE( ctx );
+ SAFE_FREE(sitename);
+ return 0;
+ }
+
+ DEBUG(9, ("Looking up PDC for domain %s\n", domain));
+ if (!get_pdc_ip(domain, &ss)) {
+ TALLOC_FREE( ctx );
+ SAFE_FREE(sitename);
+ return -1;
+ }
+
+ ret = sys_getnameinfo((struct sockaddr *)&ss,
+ sizeof(struct sockaddr_storage),
+ h_name, sizeof(h_name),
+ NULL, 0,
+ NI_NAMEREQD);
+
+ if (ret) {
+ TALLOC_FREE( ctx );
+ SAFE_FREE(sitename);
+ return -1;
+ }
+
+ DEBUG(9, ("Found PDC with DNS name %s\n", h_name));
+ domain = strchr(h_name, '.');
+ if (!domain) {
+ TALLOC_FREE( ctx );
+ SAFE_FREE(sitename);
+ return -1;
+ }
+ domain++;
+
+ DEBUG(9, ("Looking up ldap for domain %s\n", domain));
+
+ status = ads_dns_query_dcs( ctx, domain, sitename, &dcs, &numdcs );
+ if ( NT_STATUS_IS_OK(status) && numdcs ) {
+ print_ldap_srvlist(dcs, numdcs);
+ TALLOC_FREE( ctx );
+ SAFE_FREE(sitename);
+ return 0;
+ }
+
+ TALLOC_FREE( ctx );
+ SAFE_FREE(sitename);
+
+ return -1;
+#endif
+ DEBUG(1,("No ADS support\n"));
+ return -1;
+}
+
+static int net_lookup_dc(struct net_context *c, int argc, const char **argv)
+{
+ struct ip_service *ip_list;
+ struct sockaddr_storage ss;
+ char *pdc_str = NULL;
+ const char *domain = NULL;
+ char *sitename = NULL;
+ int count, i;
+ char addr[INET6_ADDRSTRLEN];
+ bool sec_ads = (lp_security() == SEC_ADS);
+
+ if (sec_ads) {
+ domain = lp_realm();
+ } else {
+ domain = c->opt_target_workgroup;
+ }
+
+ if (argc > 0)
+ domain=argv[0];
+
+ /* first get PDC */
+ if (!get_pdc_ip(domain, &ss))
+ return -1;
+
+ print_sockaddr(addr, sizeof(addr), &ss);
+ asprintf(&pdc_str, "%s", addr);
+ d_printf("%s\n", pdc_str);
+
+ sitename = sitename_fetch(domain);
+ if (!NT_STATUS_IS_OK(get_sorted_dc_list(domain, sitename,
+ &ip_list, &count, sec_ads))) {
+ SAFE_FREE(pdc_str);
+ SAFE_FREE(sitename);
+ return 0;
+ }
+ SAFE_FREE(sitename);
+ for (i=0;i<count;i++) {
+ print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
+ if (!strequal(pdc_str, addr))
+ d_printf("%s\n", addr);
+ }
+ SAFE_FREE(pdc_str);
+ return 0;
+}
+
+static int net_lookup_pdc(struct net_context *c, int argc, const char **argv)
+{
+ struct sockaddr_storage ss;
+ char *pdc_str = NULL;
+ const char *domain;
+ char addr[INET6_ADDRSTRLEN];
+
+ if (lp_security() == SEC_ADS) {
+ domain = lp_realm();
+ } else {
+ domain = c->opt_target_workgroup;
+ }
+
+ if (argc > 0)
+ domain=argv[0];
+
+ /* first get PDC */
+ if (!get_pdc_ip(domain, &ss))
+ return -1;
+
+ print_sockaddr(addr, sizeof(addr), &ss);
+ asprintf(&pdc_str, "%s", addr);
+ d_printf("%s\n", pdc_str);
+ SAFE_FREE(pdc_str);
+ return 0;
+}
+
+
+static int net_lookup_master(struct net_context *c, int argc, const char **argv)
+{
+ struct sockaddr_storage master_ss;
+ const char *domain = c->opt_target_workgroup;
+ char addr[INET6_ADDRSTRLEN];
+
+ if (argc > 0)
+ domain=argv[0];
+
+ if (!find_master_ip(domain, &master_ss))
+ return -1;
+ print_sockaddr(addr, sizeof(addr), &master_ss);
+ d_printf("%s\n", addr);
+ return 0;
+}
+
+static int net_lookup_kdc(struct net_context *c, int argc, const char **argv)
+{
+#ifdef HAVE_KRB5
+ krb5_error_code rc;
+ krb5_context ctx;
+ struct sockaddr_in *addrs;
+ int num_kdcs,i;
+ krb5_data realm;
+ char **realms;
+
+ initialize_krb5_error_table();
+ rc = krb5_init_context(&ctx);
+ if (rc) {
+ DEBUG(1,("krb5_init_context failed (%s)\n",
+ error_message(rc)));
+ return -1;
+ }
+
+ if (argc>0) {
+ realm.data = CONST_DISCARD(char *, argv[0]);
+ realm.length = strlen(argv[0]);
+ } else if (lp_realm() && *lp_realm()) {
+ realm.data = lp_realm();
+ realm.length = strlen((const char *)realm.data);
+ } else {
+ rc = krb5_get_host_realm(ctx, NULL, &realms);
+ if (rc) {
+ DEBUG(1,("krb5_gethost_realm failed (%s)\n",
+ error_message(rc)));
+ return -1;
+ }
+ realm.data = (char *) *realms;
+ realm.length = strlen((const char *)realm.data);
+ }
+
+ rc = smb_krb5_locate_kdc(ctx, &realm, (struct sockaddr **)(void *)&addrs, &num_kdcs, 0);
+ if (rc) {
+ DEBUG(1, ("smb_krb5_locate_kdc failed (%s)\n", error_message(rc)));
+ return -1;
+ }
+ for (i=0;i<num_kdcs;i++)
+ if (addrs[i].sin_family == AF_INET)
+ d_printf("%s:%hd\n", inet_ntoa(addrs[i].sin_addr),
+ ntohs(addrs[i].sin_port));
+ return 0;
+
+#endif
+ DEBUG(1, ("No kerberos support\n"));
+ return -1;
+}
+
+static int net_lookup_name(struct net_context *c, int argc, const char **argv)
+{
+ const char *dom, *name;
+ DOM_SID sid;
+ enum lsa_SidType type;
+
+ if (argc != 1) {
+ d_printf("usage: net lookup name <name>\n");
+ return -1;
+ }
+
+ if (!lookup_name(talloc_tos(), argv[0], LOOKUP_NAME_ALL,
+ &dom, &name, &sid, &type)) {
+ d_printf("Could not lookup name %s\n", argv[0]);
+ return -1;
+ }
+
+ d_printf("%s %d (%s) %s\\%s\n", sid_string_tos(&sid),
+ type, sid_type_lookup(type), dom, name);
+ return 0;
+}
+
+static int net_lookup_sid(struct net_context *c, int argc, const char **argv)
+{
+ const char *dom, *name;
+ DOM_SID sid;
+ enum lsa_SidType type;
+
+ if (argc != 1) {
+ d_printf("usage: net lookup sid <sid>\n");
+ return -1;
+ }
+
+ if (!string_to_sid(&sid, argv[0])) {
+ d_printf("Could not convert %s to SID\n", argv[0]);
+ return -1;
+ }
+
+ if (!lookup_sid(talloc_tos(), &sid,
+ &dom, &name, &type)) {
+ d_printf("Could not lookup name %s\n", argv[0]);
+ return -1;
+ }
+
+ d_printf("%s %d (%s) %s\\%s\n", sid_string_tos(&sid),
+ type, sid_type_lookup(type), dom, name);
+ return 0;
+}
+
+static int net_lookup_dsgetdcname(struct net_context *c, int argc, const char **argv)
+{
+ NTSTATUS status;
+ const char *domain_name = NULL;
+ const char *site_name = NULL;
+ uint32_t flags = 0;
+ struct netr_DsRGetDCNameInfo *info = NULL;
+ TALLOC_CTX *mem_ctx;
+ char *s = NULL;
+
+ if (argc < 1 || argc > 3) {
+ d_printf("usage: net lookup dsgetdcname "
+ "<name> <flags> <sitename>\n");
+ return -1;
+ }
+
+ mem_ctx = talloc_init("net_lookup_dsgetdcname");
+ if (!mem_ctx) {
+ return -1;
+ }
+
+ domain_name = argv[0];
+
+ if (argc >= 2)
+ sscanf(argv[1], "%x", &flags);
+
+ if (!flags) {
+ flags |= DS_DIRECTORY_SERVICE_REQUIRED;
+ }
+
+ if (argc == 3) {
+ site_name = argv[2];
+ }
+
+ status = dsgetdcname(mem_ctx, NULL, domain_name, NULL, site_name,
+ flags, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("failed with: %s\n", nt_errstr(status));
+ TALLOC_FREE(mem_ctx);
+ return -1;
+ }
+
+ s = NDR_PRINT_STRUCT_STRING(mem_ctx, netr_DsRGetDCNameInfo, info);
+ printf("%s\n", s);
+ TALLOC_FREE(s);
+
+ TALLOC_FREE(mem_ctx);
+ return 0;
+}
+
+
+/* lookup hosts or IP addresses using internal samba lookup fns */
+int net_lookup(struct net_context *c, int argc, const char **argv)
+{
+ int i;
+
+ struct functable table[] = {
+ {"HOST", net_lookup_host},
+ {"LDAP", net_lookup_ldap},
+ {"DC", net_lookup_dc},
+ {"PDC", net_lookup_pdc},
+ {"MASTER", net_lookup_master},
+ {"KDC", net_lookup_kdc},
+ {"NAME", net_lookup_name},
+ {"SID", net_lookup_sid},
+ {"DSGETDCNAME", net_lookup_dsgetdcname},
+ {NULL, NULL}
+ };
+
+ if (argc < 1) {
+ d_printf("\nUsage: \n");
+ return net_lookup_usage(c, argc, argv);
+ }
+ for (i=0; table[i].funcname; i++) {
+ if (StrCaseCmp(argv[0], table[i].funcname) == 0)
+ return table[i].fn(c, argc-1, argv+1);
+ }
+
+ /* Default to lookup a hostname so 'net lookup foo#1b' can be
+ used instead of 'net lookup host foo#1b'. The host syntax
+ is a bit confusing as non #00 names can't really be
+ considered hosts as such. */
+
+ return net_lookup_host(c, argc, argv);
+}
diff --git a/source3/utils/net_proto.h b/source3/utils/net_proto.h
new file mode 100644
index 0000000000..1e355e54a3
--- /dev/null
+++ b/source3/utils/net_proto.h
@@ -0,0 +1,489 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * collected prototypes header
+ *
+ * frozen from "make proto" in May 2008
+ *
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _NET_PROTO_H_
+#define _NET_PROTO_H_
+
+
+/* The following definitions come from auth/token_util.c */
+
+bool nt_token_check_sid ( const DOM_SID *sid, const NT_USER_TOKEN *token );
+bool nt_token_check_domain_rid( NT_USER_TOKEN *token, uint32 rid );
+NT_USER_TOKEN *get_root_nt_token( void );
+NTSTATUS add_aliases(const DOM_SID *domain_sid,
+ struct nt_user_token *token);
+struct nt_user_token *create_local_nt_token(TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ bool is_guest,
+ int num_groupsids,
+ const DOM_SID *groupsids);
+void debug_nt_user_token(int dbg_class, int dbg_lev, NT_USER_TOKEN *token);
+void debug_unix_user_token(int dbg_class, int dbg_lev, uid_t uid, gid_t gid,
+ int n_groups, gid_t *groups);
+
+/* The following definitions come from utils/net.c */
+
+uint32 get_sec_channel_type(const char *param);
+
+/* The following definitions come from utils/net_ads.c */
+
+ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads);
+ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads);
+int net_ads_check_our_domain(struct net_context *c);
+int net_ads_check(struct net_context *c);
+int net_ads_user(struct net_context *c, int argc, const char **argv);
+int net_ads_group(struct net_context *c, int argc, const char **argv);
+int net_ads_testjoin(struct net_context *c, int argc, const char **argv);
+int net_ads_join(struct net_context *c, int argc, const char **argv);
+int net_ads_printer_usage(struct net_context *c, int argc, const char **argv);
+int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv);
+int net_ads_keytab(struct net_context *c, int argc, const char **argv);
+int net_ads_kerberos(struct net_context *c, int argc, const char **argv);
+int net_ads(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_ads_gpo.c */
+
+int net_ads_gpo(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_cache.c */
+
+int net_cache(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_conf.c */
+
+int net_conf(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_dns.c */
+
+int get_my_ip_address( struct sockaddr_storage **pp_ss );
+
+/* The following definitions come from utils/net_dom.c */
+
+int net_dom_usage(struct net_context *c, int argc, const char **argv);
+int net_dom(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_file.c */
+
+int net_file_usage(struct net_context *c, int argc, const char **argv);
+int net_file(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_group.c */
+
+int net_group_usage(struct net_context *c, int argc, const char **argv);
+int net_group(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_groupmap.c */
+
+int net_groupmap_usage(struct net_context *c, int argc, const char **argv);
+int net_groupmap(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_help.c */
+
+int net_help(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_idmap.c */
+
+bool idmap_store_secret(const char *backend, bool alloc,
+ const char *domain, const char *identity,
+ const char *secret);
+int net_help_idmap(struct net_context *c, int argc, const char **argv);
+int net_idmap(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_join.c */
+
+int net_join_usage(struct net_context *c, int argc, const char **argv);
+int net_join(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_lookup.c */
+
+int net_lookup_usage(struct net_context *c, int argc, const char **argv);
+int net_lookup(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_rap.c */
+
+int net_rap_file_usage(struct net_context *c, int argc, const char **argv);
+int net_rap_file(struct net_context *c, int argc, const char **argv);
+int net_rap_share_usage(struct net_context *c, int argc, const char **argv);
+int net_rap_share(struct net_context *c, int argc, const char **argv);
+int net_rap_session_usage(struct net_context *c, int argc, const char **argv);
+int net_rap_session(struct net_context *c, int argc, const char **argv);
+int net_rap_server_usage(struct net_context *c, int argc, const char **argv);
+int net_rap_server(struct net_context *c, int argc, const char **argv);
+int net_rap_domain_usage(struct net_context *c, int argc, const char **argv);
+int net_rap_domain(struct net_context *c, int argc, const char **argv);
+int net_rap_printq_usage(struct net_context *c, int argc, const char **argv);
+int net_rap_printq(struct net_context *c, int argc, const char **argv);
+int net_rap_user(struct net_context *c, int argc, const char **argv);
+int net_rap_group_usage(struct net_context *c, int argc, const char **argv);
+int net_rap_group(struct net_context *c, int argc, const char **argv);
+int net_rap_groupmember_usage(struct net_context *c, int argc, const char **argv);
+int net_rap_groupmember(struct net_context *c, int argc, const char **argv);
+int net_rap_validate_usage(struct net_context *c, int argc, const char **argv);
+int net_rap_validate(struct net_context *c, int argc, const char **argv);
+int net_rap_service_usage(struct net_context *c, int argc, const char **argv);
+int net_rap_service(struct net_context *c, int argc, const char **argv);
+int net_rap_password_usage(struct net_context *c, int argc, const char **argv);
+int net_rap_password(struct net_context *c, int argc, const char **argv);
+int net_rap_admin_usage(struct net_context *c, int argc, const char **argv);
+int net_rap_admin(struct net_context *c, int argc, const char **argv);
+int net_rap(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_registry.c */
+
+int net_registry(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_rpc.c */
+
+NTSTATUS net_get_remote_domain_sid(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ DOM_SID **domain_sid,
+ const char **domain_name);
+int run_rpc_command(struct net_context *c,
+ struct cli_state *cli_arg,
+ const struct ndr_syntax_id *interface,
+ int conn_flags,
+ rpc_command_fn fn,
+ int argc,
+ const char **argv);
+int net_rpc_changetrustpw(struct net_context *c, int argc, const char **argv);
+int net_rpc_join(struct net_context *c, int argc, const char **argv);
+NTSTATUS rpc_info_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+int net_rpc_info(struct net_context *c, int argc, const char **argv);
+int net_rpc_getsid(struct net_context *c, int argc, const char **argv);
+int net_rpc_user(struct net_context *c, int argc, const char **argv);
+struct rpc_sh_cmd *net_rpc_user_edit_cmds(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx);
+struct rpc_sh_cmd *net_rpc_user_cmds(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx);
+int net_rpc_group(struct net_context *c, int argc, const char **argv);
+bool copy_top_level_perms(struct net_context *c,
+ struct copy_clistate *cp_clistate,
+ const char *sharename);
+int net_usersidlist(struct net_context *c, int argc, const char **argv);
+int net_usersidlist_usage(struct net_context *c, int argc, const char **argv);
+int net_rpc_share(struct net_context *c, int argc, const char **argv);
+struct rpc_sh_cmd *net_rpc_share_cmds(struct net_context *c, TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx);
+int net_rpc_file(struct net_context *c, int argc, const char **argv);
+NTSTATUS rpc_init_shutdown_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+NTSTATUS rpc_reg_shutdown_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+bool net_rpc_check(struct net_context *c, unsigned flags);
+int rpc_printer_migrate(struct net_context *c, int argc, const char **argv);
+int rpc_printer_usage(struct net_context *c, int argc, const char **argv);
+int net_rpc_printer(struct net_context *c, int argc, const char **argv);
+int net_rpc(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_rpc_audit.c */
+
+int net_rpc_audit(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_rpc_join.c */
+
+NTSTATUS net_rpc_join_ok(struct net_context *c, const char *domain,
+ const char *server, struct sockaddr_storage *pss);
+int net_rpc_join_newstyle(struct net_context *c, int argc, const char **argv);
+int net_rpc_testjoin(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_rpc_printer.c */
+
+NTSTATUS net_copy_fileattr(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct cli_state *cli_share_src,
+ struct cli_state *cli_share_dst,
+ const char *src_name, const char *dst_name,
+ bool copy_acls, bool copy_attrs,
+ bool copy_timestamps, bool is_file);
+NTSTATUS net_copy_file(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct cli_state *cli_share_src,
+ struct cli_state *cli_share_dst,
+ const char *src_name, const char *dst_name,
+ bool copy_acls, bool copy_attrs,
+ bool copy_timestamps, bool is_file);
+NTSTATUS rpc_printer_list_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+NTSTATUS rpc_printer_driver_list_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+NTSTATUS rpc_printer_publish_publish_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+NTSTATUS rpc_printer_publish_unpublish_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+NTSTATUS rpc_printer_publish_update_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+NTSTATUS rpc_printer_publish_list_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+NTSTATUS rpc_printer_migrate_security_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+NTSTATUS rpc_printer_migrate_forms_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+NTSTATUS rpc_printer_migrate_drivers_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+NTSTATUS rpc_printer_migrate_printers_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+NTSTATUS rpc_printer_migrate_settings_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+
+/* The following definitions come from utils/net_rpc_registry.c */
+
+int net_rpc_registry(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_rpc_rights.c */
+
+int net_rpc_rights(struct net_context *c, int argc, const char **argv);
+struct rpc_sh_cmd *net_rpc_rights_cmds(struct net_context *c, TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx);
+
+/* The following definitions come from utils/net_rpc_samsync.c */
+
+NTSTATUS rpc_samdump_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+int rpc_vampire_usage(struct net_context *c, int argc, const char **argv);
+NTSTATUS rpc_vampire_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+int rpc_vampire_ldif(struct net_context *c, int argc, const char **argv);
+NTSTATUS rpc_vampire_ldif_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+NTSTATUS rpc_vampire_keytab_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv);
+int rpc_vampire_keytab(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_rpc_service.c */
+
+const char *svc_status_string( uint32 state );
+int net_rpc_service(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_rpc_sh_acct.c */
+
+struct rpc_sh_cmd *net_rpc_acct_cmds(struct net_context *c, TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx);
+
+/* The following definitions come from utils/net_rpc_shell.c */
+
+int net_rpc_shell(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_sam.c */
+
+int net_sam(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_share.c */
+
+int net_share_usage(struct net_context *c, int argc, const char **argv);
+int net_share(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_status.c */
+
+int net_status_usage(struct net_context *c, int argc, const char **argv);
+int net_status(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_time.c */
+
+int net_time_usage(struct net_context *c, int argc, const char **argv);
+int net_time(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_user.c */
+
+int net_user_usage(struct net_context *c, int argc, const char **argv);
+int net_user(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_usershare.c */
+
+int net_usershare_usage(struct net_context *c, int argc, const char **argv);
+int net_usershare_help(struct net_context *c, int argc, const char **argv);
+int net_usershare(struct net_context *c, int argc, const char **argv);
+
+/* The following definitions come from utils/net_util.c */
+
+NTSTATUS net_rpc_lookup_name(struct net_context *c,
+ TALLOC_CTX *mem_ctx, struct cli_state *cli,
+ const char *name, const char **ret_domain,
+ const char **ret_name, DOM_SID *ret_sid,
+ enum lsa_SidType *ret_type);
+NTSTATUS connect_to_service(struct net_context *c,
+ struct cli_state **cli_ctx,
+ struct sockaddr_storage *server_ss,
+ const char *server_name,
+ const char *service_name,
+ const char *service_type);
+NTSTATUS connect_to_ipc(struct net_context *c,
+ struct cli_state **cli_ctx,
+ struct sockaddr_storage *server_ss,
+ const char *server_name);
+NTSTATUS connect_to_ipc_anonymous(struct net_context *c,
+ struct cli_state **cli_ctx,
+ struct sockaddr_storage *server_ss,
+ const char *server_name);
+NTSTATUS connect_to_ipc_krb5(struct net_context *c,
+ struct cli_state **cli_ctx,
+ struct sockaddr_storage *server_ss,
+ const char *server_name);
+NTSTATUS connect_dst_pipe(struct net_context *c, struct cli_state **cli_dst,
+ struct rpc_pipe_client **pp_pipe_hnd,
+ const struct ndr_syntax_id *interface);
+int net_use_krb_machine_account(struct net_context *c);
+int net_use_machine_account(struct net_context *c);
+bool net_find_server(struct net_context *c,
+ const char *domain,
+ unsigned flags,
+ struct sockaddr_storage *server_ss,
+ char **server_name);
+bool net_find_pdc(struct sockaddr_storage *server_ss,
+ fstring server_name,
+ const char *domain_name);
+NTSTATUS net_make_ipc_connection(struct net_context *c, unsigned flags,
+ struct cli_state **pcli);
+NTSTATUS net_make_ipc_connection_ex(struct net_context *c ,const char *domain,
+ const char *server,
+ struct sockaddr_storage *pss,
+ unsigned flags, struct cli_state **pcli);
+const char *net_prompt_pass(struct net_context *c, const char *user);
+int net_run_function(struct net_context *c, int argc, const char **argv,
+ const char *whoami, struct functable *table);
+void net_display_usage_from_functable(struct functable *table);
+
+/* The following definitions come from utils/netlookup.c */
+
+NTSTATUS net_lookup_name_from_sid(struct net_context *c,
+ TALLOC_CTX *ctx,
+ DOM_SID *psid,
+ const char **ppdomain,
+ const char **ppname);
+NTSTATUS net_lookup_sid_from_name(struct net_context *c, TALLOC_CTX *ctx,
+ const char *full_name, DOM_SID *pret_sid);
+
+/* The following definitions come from utils/passwd_util.c */
+
+char *stdin_new_passwd( void);
+char *get_pass( const char *prompt, bool stdin_get);
+
+#endif /* _NET_PROTO_H_ */
diff --git a/source3/utils/net_rap.c b/source3/utils/net_rap.c
new file mode 100644
index 0000000000..883524dc2d
--- /dev/null
+++ b/source3/utils/net_rap.c
@@ -0,0 +1,1374 @@
+/*
+ Samba Unix/Linux SMB client library
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) 2001 Steve French (sfrench@us.ibm.com)
+ Copyright (C) 2001 Jim McDonough (jmcd@us.ibm.com)
+ Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+ Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
+
+ Originally written by Steve and Jim. Largely rewritten by tridge in
+ November 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "includes.h"
+#include "utils/net.h"
+
+/* The following messages were for error checking that is not properly
+ reported at the moment. Which should be reinstated? */
+#define ERRMSG_TARGET_WG_NOT_VALID "\nTarget workgroup option not valid "\
+ "except on net rap server command, ignored"
+#define ERRMSG_INVALID_HELP_OPTION "\nInvalid help option\n"
+
+#define ERRMSG_BOTH_SERVER_IPADDRESS "\nTarget server and IP address both "\
+ "specified. Do not set both at the same time. The target IP address was used\n"
+
+const char *share_type[] = {
+ "Disk",
+ "Print",
+ "Dev",
+ "IPC"
+};
+
+static int errmsg_not_implemented(void)
+{
+ d_printf("\nNot implemented\n");
+ return 0;
+}
+
+int net_rap_file_usage(struct net_context *c, int argc, const char **argv)
+{
+ return net_file_usage(c, argc, argv);
+}
+
+/***************************************************************************
+ list info on an open file
+***************************************************************************/
+static void file_fn(const char * pPath, const char * pUser, uint16 perms,
+ uint16 locks, uint32 id)
+{
+ d_printf("%-7.1d %-20.20s 0x%-4.2x %-6.1d %s\n",
+ id, pUser, perms, locks, pPath);
+}
+
+static void one_file_fn(const char *pPath, const char *pUser, uint16 perms,
+ uint16 locks, uint32 id)
+{
+ d_printf("File ID %d\n"
+ "User name %s\n"
+ "Locks 0x%-4.2x\n"
+ "Path %s\n"
+ "Permissions 0x%x\n",
+ id, pUser, locks, pPath, perms);
+}
+
+
+static int rap_file_close(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ if (argc == 0 || c->display_usage) {
+ return net_rap_file_usage(c, argc, argv);
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ ret = cli_NetFileClose(cli, atoi(argv[0]));
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_file_info(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ if (argc == 0 || c->display_usage)
+ return net_rap_file_usage(c, argc, argv);
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ ret = cli_NetFileGetInfo(cli, atoi(argv[0]), one_file_fn);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_file_user(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (argc == 0 || c->display_usage)
+ return net_rap_file_usage(c, argc, argv);
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ /* list open files */
+
+ d_printf("\nEnumerating open files on remote server:\n\n"
+ "\nFileId Opened by Perms Locks Path \n"
+ "------ --------- ----- ----- ---- \n");
+ ret = cli_NetFileEnum(cli, argv[0], NULL, file_fn);
+
+ if (ret == -1)
+ d_printf("\nOperation not supported by server!\n\n");
+
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_file(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "close",
+ rap_file_close,
+ NET_TRANSPORT_RAP,
+ "Close specified file on server",
+ "net rap file close\n"
+ " Close specified file on server"
+ },
+ {
+ "user",
+ rap_file_user,
+ NET_TRANSPORT_RAP,
+ "List all files opened by username",
+ "net rap file user\n"
+ " List all files opened by username"
+ },
+ {
+ "info",
+ rap_file_info,
+ NET_TRANSPORT_RAP,
+ "Display info about an opened file",
+ "net rap file info\n"
+ " Display info about an opened file"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ if (argc == 0) {
+ struct cli_state *cli;
+ int ret;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n");
+ d_printf("net rap file\n"
+ " List all open files on rempte server\n");
+ net_display_usage_from_functable(func);
+ return 0;
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ /* list open files */
+
+ d_printf("\nEnumerating open files on remote server:\n\n"
+ "\nFileId Opened by Perms Locks Path \n"
+ "------ --------- ----- ----- ---- \n");
+ ret = cli_NetFileEnum(cli, NULL, NULL, file_fn);
+
+ if (ret == -1)
+ d_printf("\nOperation not supported by server!\n\n");
+
+ cli_shutdown(cli);
+ return ret;
+ }
+
+ return net_run_function(c, argc, argv, "net rap file", func);
+}
+
+int net_rap_share_usage(struct net_context *c, int argc, const char **argv)
+{
+ return net_share_usage(c, argc, argv);
+}
+
+static void long_share_fn(const char *share_name, uint32 type,
+ const char *comment, void *state)
+{
+ d_printf("%-12s %-8.8s %-50s\n",
+ share_name, share_type[type], comment);
+}
+
+static void share_fn(const char *share_name, uint32 type,
+ const char *comment, void *state)
+{
+ d_printf("%s\n", share_name);
+}
+
+static int rap_share_delete(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (argc == 0 || c->display_usage) {
+ return net_rap_share_usage(c, argc, argv);
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ ret = cli_NetShareDelete(cli, argv[0]);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_share_add(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ RAP_SHARE_INFO_2 sinfo;
+ char *p;
+ char *sharename;
+
+ if (argc == 0 || c->display_usage) {
+ return net_rap_share_usage(c, argc, argv);
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ sharename = SMB_STRDUP(argv[0]);
+ p = strchr(sharename, '=');
+ if (p == NULL) {
+ d_printf("Server path not specified\n");
+ SAFE_FREE(sharename);
+ return net_rap_share_usage(c, argc, argv);
+ }
+ *p = 0;
+ strlcpy(sinfo.share_name, sharename, sizeof(sinfo.share_name));
+ sinfo.reserved1 = '\0';
+ sinfo.share_type = 0;
+ sinfo.comment = smb_xstrdup(c->opt_comment);
+ sinfo.perms = 0;
+ sinfo.maximum_users = c->opt_maxusers;
+ sinfo.active_users = 0;
+ sinfo.path = p+1;
+ memset(sinfo.password, '\0', sizeof(sinfo.password));
+ sinfo.reserved2 = '\0';
+
+ ret = cli_NetShareAdd(cli, &sinfo);
+ cli_shutdown(cli);
+ SAFE_FREE(sharename);
+ return ret;
+}
+
+
+int net_rap_share(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "delete",
+ rap_share_delete,
+ NET_TRANSPORT_RAP,
+ "Delete a share from server",
+ "net rap share delete\n"
+ " Delete a share from server"
+ },
+ {
+ "close",
+ rap_share_delete,
+ NET_TRANSPORT_RAP,
+ "Delete a share from server",
+ "net rap share close\n"
+ " Delete a share from server\n"
+ " Alias for net rap share delete"
+ },
+ {
+ "add",
+ rap_share_add,
+ NET_TRANSPORT_RAP,
+ "Add a share to server",
+ "net rap share add\n"
+ " Add a share to server"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ if (argc == 0) {
+ struct cli_state *cli;
+ int ret;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n");
+ d_printf("net rap share\n"
+ " List all shares on remote server\n");
+ net_display_usage_from_functable(func);
+ return 0;
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ if (c->opt_long_list_entries) {
+ d_printf(
+ "\nEnumerating shared resources (exports) on remote server:\n\n"
+ "\nShare name Type Description\n"
+ "---------- ---- -----------\n");
+ ret = cli_RNetShareEnum(cli, long_share_fn, NULL);
+ } else {
+ ret = cli_RNetShareEnum(cli, share_fn, NULL);
+ }
+ cli_shutdown(cli);
+ return ret;
+ }
+
+ return net_run_function(c, argc, argv, "net rap share", func);
+}
+
+int net_rap_session_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(
+ "\nnet rap session [misc. options] [targets]"
+ "\n\tenumerates all active SMB/CIFS sessions on target server\n");
+ d_printf(
+ "\nnet rap session DELETE <client_name> [misc. options] [targets] \n"
+ "\tor"
+ "\nnet rap session CLOSE <client_name> [misc. options] [targets]"
+ "\n\tDeletes (closes) a session from specified client to server\n");
+ d_printf(
+ "\nnet rap session INFO <client_name>"
+ "\n\tEnumerates all open files in specified session\n");
+
+ net_common_flags_usage(c, argc, argv);
+ return -1;
+}
+
+static void list_sessions_func(char *wsname, char *username, uint16 conns,
+ uint16 opens, uint16 users, uint32 sess_time,
+ uint32 idle_time, uint32 user_flags, char *clitype)
+{
+ int hrs = idle_time / 3600;
+ int min = (idle_time / 60) % 60;
+ int sec = idle_time % 60;
+
+ d_printf("\\\\%-18.18s %-20.20s %-18.18s %5d %2.2d:%2.2d:%2.2d\n",
+ wsname, username, clitype, opens, hrs, min, sec);
+}
+
+static void display_session_func(const char *wsname, const char *username,
+ uint16 conns, uint16 opens, uint16 users,
+ uint32 sess_time, uint32 idle_time,
+ uint32 user_flags, const char *clitype)
+{
+ int ihrs = idle_time / 3600;
+ int imin = (idle_time / 60) % 60;
+ int isec = idle_time % 60;
+ int shrs = sess_time / 3600;
+ int smin = (sess_time / 60) % 60;
+ int ssec = sess_time % 60;
+ d_printf("User name %-20.20s\n"
+ "Computer %-20.20s\n"
+ "Guest logon %-20.20s\n"
+ "Client Type %-40.40s\n"
+ "Sess time %2.2d:%2.2d:%2.2d\n"
+ "Idle time %2.2d:%2.2d:%2.2d\n",
+ username, wsname,
+ (user_flags&0x0)?"yes":"no", clitype,
+ shrs, smin, ssec, ihrs, imin, isec);
+}
+
+static void display_conns_func(uint16 conn_id, uint16 conn_type, uint16 opens,
+ uint16 users, uint32 conn_time,
+ const char *username, const char *netname)
+{
+ d_printf("%-14.14s %-8.8s %5d\n",
+ netname, share_type[conn_type], opens);
+}
+
+static int rap_session_info(struct net_context *c, int argc, const char **argv)
+{
+ const char *sessname;
+ struct cli_state *cli;
+ int ret;
+
+ if (argc == 0 || c->display_usage)
+ return net_rap_session_usage(c, argc, argv);
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ sessname = argv[0];
+
+ ret = cli_NetSessionGetInfo(cli, sessname, display_session_func);
+ if (ret < 0) {
+ cli_shutdown(cli);
+ return ret;
+ }
+
+ d_printf("Share name Type # Opens\n-------------------------"
+ "-----------------------------------------------------\n");
+ ret = cli_NetConnectionEnum(cli, sessname, display_conns_func);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_session_delete(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (argc == 0 || c->display_usage)
+ return net_rap_session_usage(c, argc, argv);
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ ret = cli_NetSessionDel(cli, argv[0]);
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_session(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "info",
+ rap_session_info,
+ NET_TRANSPORT_RAP,
+ "Display information about session",
+ "net rap session info\n"
+ " Display information about session"
+ },
+ {
+ "delete",
+ rap_session_delete,
+ NET_TRANSPORT_RAP,
+ "Close specified session",
+ "net rap session delete\n"
+ " Close specified session\n"
+ " Alias for net rap session close"
+ },
+ {
+ "close",
+ rap_session_delete,
+ NET_TRANSPORT_RAP,
+ "Close specified session",
+ "net rap session close\n"
+ " Close specified session"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ if (argc == 0) {
+ struct cli_state *cli;
+ int ret;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n");
+ d_printf("net rap session\n"
+ " List all open sessions on remote server\n");
+ net_display_usage_from_functable(func);
+ return 0;
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ d_printf("Computer User name "
+ "Client Type Opens Idle time\n"
+ "------------------------------------------"
+ "------------------------------------\n");
+ ret = cli_NetSessionEnum(cli, list_sessions_func);
+
+ cli_shutdown(cli);
+ return ret;
+ }
+
+ return net_run_function(c, argc, argv, "net rap session", func);
+}
+
+/****************************************************************************
+list a server name
+****************************************************************************/
+static void display_server_func(const char *name, uint32 m,
+ const char *comment, void * reserved)
+{
+ d_printf("\t%-16.16s %s\n", name, comment);
+}
+
+static int net_rap_server_name(struct net_context *c, int argc, const char *argv[])
+{
+ struct cli_state *cli;
+ char *name;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rap server name\n"
+ " Get the name of the server\n");
+ return 0;
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ if (!cli_get_server_name(NULL, cli, &name)) {
+ d_fprintf(stderr, "cli_get_server_name failed\n");
+ cli_shutdown(cli);
+ return -1;
+ }
+
+ d_printf("Server name = %s\n", name);
+
+ TALLOC_FREE(name);
+ cli_shutdown(cli);
+ return 0;
+}
+
+static int net_rap_server_domain(struct net_context *c, int argc,
+ const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rap server domain\n"
+ " Enumerate servers in this domain/workgroup\n");
+ return 0;
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ d_printf("\nEnumerating servers in this domain or workgroup: \n\n"
+ "\tServer name Server description\n"
+ "\t------------- ----------------------------\n");
+
+ ret = cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL,
+ display_server_func,NULL);
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_server(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "name",
+ net_rap_server_name,
+ NET_TRANSPORT_RAP,
+ "Get the name of the server",
+ "net rap server name\n"
+ " Get the name of the server"
+ },
+ {
+ "domain",
+ net_rap_server_domain,
+ NET_TRANSPORT_RAP,
+ "Get the servers in this domain/workgroup",
+ "net rap server domain\n"
+ " Get the servers in this domain/workgroup"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ /* smb4k uses 'net [rap|rpc] server domain' to query servers in a domain */
+ /* Fall through for 'domain', any other forms will cause to show usage message */
+ return net_run_function(c, argc, argv, "net rap server", func);
+
+}
+
+int net_rap_domain_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("net rap domain [misc. options] [target]\n\tlists the"
+ " domains or workgroups visible on the current network\n");
+
+ net_common_flags_usage(c, argc, argv);
+ return -1;
+}
+
+int net_rap_domain(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (c->display_usage)
+ return net_rap_domain_usage(c, argc, argv);
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ d_printf("\nEnumerating domains:\n\n"
+ "\tDomain name Server name of Browse Master\n"
+ "\t------------- ----------------------------\n");
+
+ ret = cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM,
+ display_server_func,NULL);
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_printq_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(
+ "net rap printq [misc. options] [targets]\n"
+ "\tor\n"
+ "net rap printq list [<queue_name>] [misc. options] [targets]\n"
+ "\tlists the specified queue and jobs on the target server.\n"
+ "\tIf the queue name is not specified, all queues are listed.\n\n");
+ d_printf(
+ "net rap printq delete [<queue name>] [misc. options] [targets]\n"
+ "\tdeletes the specified job number on the target server, or the\n"
+ "\tprinter queue if no job number is specified\n");
+
+ net_common_flags_usage(c, argc, argv);
+
+ return -1;
+}
+
+static void enum_queue(const char *queuename, uint16 pri, uint16 start,
+ uint16 until, const char *sep, const char *pproc,
+ const char *dest, const char *qparms,
+ const char *qcomment, uint16 status, uint16 jobcount)
+{
+ d_printf("%-17.17s Queue %5d jobs ",
+ queuename, jobcount);
+
+ switch (status) {
+ case 0:
+ d_printf("*Printer Active*\n");
+ break;
+ case 1:
+ d_printf("*Printer Paused*\n");
+ break;
+ case 2:
+ d_printf("*Printer error*\n");
+ break;
+ case 3:
+ d_printf("*Delete Pending*\n");
+ break;
+ default:
+ d_printf("**UNKNOWN STATUS**\n");
+ }
+}
+
+static void enum_jobs(uint16 jobid, const char *ownername,
+ const char *notifyname, const char *datatype,
+ const char *jparms, uint16 pos, uint16 status,
+ const char *jstatus, unsigned int submitted, unsigned int jobsize,
+ const char *comment)
+{
+ d_printf(" %-23.23s %5d %9d ",
+ ownername, jobid, jobsize);
+ switch (status) {
+ case 0:
+ d_printf("Waiting\n");
+ break;
+ case 1:
+ d_printf("Held in queue\n");
+ break;
+ case 2:
+ d_printf("Spooling\n");
+ break;
+ case 3:
+ d_printf("Printing\n");
+ break;
+ default:
+ d_printf("**UNKNOWN STATUS**\n");
+ }
+}
+
+#define PRINTQ_ENUM_DISPLAY \
+ "Print queues at \\\\%s\n\n"\
+ "Name Job # Size Status\n\n"\
+ "------------------------------------------------------------------"\
+ "-------------\n"
+
+static int rap_printq_info(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (argc == 0 || c->display_usage)
+ return net_rap_printq_usage(c, argc, argv);
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ d_printf(PRINTQ_ENUM_DISPLAY, cli->desthost); /* list header */
+ ret = cli_NetPrintQGetInfo(cli, argv[0], enum_queue, enum_jobs);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_printq_delete(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (argc == 0 || c->display_usage)
+ return net_rap_printq_usage(c, argc, argv);
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ ret = cli_printjob_del(cli, atoi(argv[0]));
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_printq(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ struct functable func[] = {
+ {
+ "info",
+ rap_printq_info,
+ NET_TRANSPORT_RAP,
+ "Display info about print job",
+ "net rap printq info\n"
+ " Display info about print job"
+ },
+ {
+ "delete",
+ rap_printq_delete,
+ NET_TRANSPORT_RAP,
+ "Delete print job(s)",
+ "net rap printq delete\n"
+ " Delete print job(s)"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ if (argc == 0) {
+ if (c->display_usage) {
+ d_printf("Usage:\n");
+ d_printf("net rap printq\n"
+ " List the print queue\n");
+ net_display_usage_from_functable(func);
+ return 0;
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ d_printf(PRINTQ_ENUM_DISPLAY, cli->desthost); /* list header */
+ ret = cli_NetPrintQEnum(cli, enum_queue, enum_jobs);
+ cli_shutdown(cli);
+ return ret;
+ }
+
+ return net_run_function(c, argc, argv, "net rap printq", func);
+}
+
+static int net_rap_user_usage(struct net_context *c, int argc, const char **argv)
+{
+ return net_user_usage(c, argc, argv);
+}
+
+static void user_fn(const char *user_name, void *state)
+{
+ d_printf("%-21.21s\n", user_name);
+}
+
+static void long_user_fn(const char *user_name, const char *comment,
+ const char * home_dir, const char * logon_script,
+ void *state)
+{
+ d_printf("%-21.21s %s\n",
+ user_name, comment);
+}
+
+static void group_member_fn(const char *user_name, void *state)
+{
+ d_printf("%-21.21s\n", user_name);
+}
+
+static int rap_user_delete(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (argc == 0 || c->display_usage) {
+ return net_rap_user_usage(c, argc, argv);
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ ret = cli_NetUserDelete(cli, argv[0]);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_user_add(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ RAP_USER_INFO_1 userinfo;
+
+ if (argc == 0 || c->display_usage) {
+ return net_rap_user_usage(c, argc, argv);
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ safe_strcpy(userinfo.user_name, argv[0], sizeof(userinfo.user_name)-1);
+ if (c->opt_flags == -1)
+ c->opt_flags = 0x21;
+
+ userinfo.userflags = c->opt_flags;
+ userinfo.reserved1 = '\0';
+ userinfo.comment = smb_xstrdup(c->opt_comment);
+ userinfo.priv = 1;
+ userinfo.home_dir = NULL;
+ userinfo.logon_script = NULL;
+
+ ret = cli_NetUserAdd(cli, &userinfo);
+
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_user_info(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ if (argc == 0 || c->display_usage) {
+ return net_rap_user_usage(c, argc, argv);
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ ret = cli_NetUserGetGroups(cli, argv[0], group_member_fn, NULL);
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_user(struct net_context *c, int argc, const char **argv)
+{
+ int ret = -1;
+ struct functable func[] = {
+ {
+ "add",
+ rap_user_add,
+ NET_TRANSPORT_RAP,
+ "Add specified user",
+ "net rap user add\n"
+ " Add specified user"
+ },
+ {
+ "info",
+ rap_user_info,
+ NET_TRANSPORT_RAP,
+ "List domain groups of specified user",
+ "net rap user info\n"
+ " List domain groups of specified user"
+
+ },
+ {
+ "delete",
+ rap_user_delete,
+ NET_TRANSPORT_RAP,
+ "Remove specified user",
+ "net rap user delete\n"
+ " Remove specified user"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ if (argc == 0) {
+ struct cli_state *cli;
+ if (c->display_usage) {
+ d_printf("Usage:\n");
+ d_printf("net rap user\n"
+ " List all users\n");
+ net_display_usage_from_functable(func);
+ return 0;
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ goto done;
+ if (c->opt_long_list_entries) {
+ d_printf("\nUser name Comment"
+ "\n-----------------------------\n");
+ ret = cli_RNetUserEnum(cli, long_user_fn, NULL);
+ cli_shutdown(cli);
+ goto done;
+ }
+ ret = cli_RNetUserEnum0(cli, user_fn, NULL);
+ cli_shutdown(cli);
+ goto done;
+ }
+
+ ret = net_run_function(c, argc, argv, "net rap user", func);
+ done:
+ if (ret != 0) {
+ DEBUG(1, ("Net user returned: %d\n", ret));
+ }
+ return ret;
+}
+
+
+int net_rap_group_usage(struct net_context *c, int argc, const char **argv)
+{
+ return net_group_usage(c, argc, argv);
+}
+
+static void long_group_fn(const char *group_name, const char *comment,
+ void *state)
+{
+ d_printf("%-21.21s %s\n", group_name, comment);
+}
+
+static void group_fn(const char *group_name, void *state)
+{
+ d_printf("%-21.21s\n", group_name);
+}
+
+static int rap_group_delete(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ if (argc == 0 || c->display_usage) {
+ return net_rap_group_usage(c, argc, argv);
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ ret = cli_NetGroupDelete(cli, argv[0]);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_group_add(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ RAP_GROUP_INFO_1 grinfo;
+
+ if (argc == 0 || c->display_usage) {
+ return net_rap_group_usage(c, argc, argv);
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ /* BB check for length 21 or smaller explicitly ? BB */
+ safe_strcpy(grinfo.group_name, argv[0], sizeof(grinfo.group_name)-1);
+ grinfo.reserved1 = '\0';
+ grinfo.comment = smb_xstrdup(c->opt_comment);
+
+ ret = cli_NetGroupAdd(cli, &grinfo);
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_group(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "add",
+ rap_group_add,
+ NET_TRANSPORT_RAP,
+ "Add specified group",
+ "net rap group add\n"
+ " Add specified group"
+ },
+ {
+ "delete",
+ rap_group_delete,
+ NET_TRANSPORT_RAP,
+ "Delete specified group",
+ "net rap group delete\n"
+ " Delete specified group"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ if (argc == 0) {
+ struct cli_state *cli;
+ int ret;
+ if (c->display_usage) {
+ d_printf("Usage:\n");
+ d_printf("net rap group\n"
+ " List all groups\n");
+ net_display_usage_from_functable(func);
+ return 0;
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+ if (c->opt_long_list_entries) {
+ d_printf("Group name Comment\n");
+ d_printf("-----------------------------\n");
+ ret = cli_RNetGroupEnum(cli, long_group_fn, NULL);
+ cli_shutdown(cli);
+ return ret;
+ }
+ ret = cli_RNetGroupEnum0(cli, group_fn, NULL);
+ cli_shutdown(cli);
+ return ret;
+ }
+
+ return net_run_function(c, argc, argv, "net rap group", func);
+}
+
+int net_rap_groupmember_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(
+ "net rap groupmember LIST <group> [misc. options] [targets]"
+ "\n\t Enumerate users in a group\n"
+ "\nnet rap groupmember DELETE <group> <user> [misc. options] "
+ "[targets]\n\t Delete sepcified user from specified group\n"
+ "\nnet rap groupmember ADD <group> <user> [misc. options] [targets]"
+ "\n\t Add specified user to specified group\n");
+
+ net_common_flags_usage(c, argc, argv);
+ return -1;
+}
+
+
+static int rap_groupmember_add(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ if (argc != 2 || c->display_usage) {
+ return net_rap_groupmember_usage(c, argc, argv);
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ ret = cli_NetGroupAddUser(cli, argv[0], argv[1]);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_groupmember_delete(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ if (argc != 2 || c->display_usage) {
+ return net_rap_groupmember_usage(c, argc, argv);
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ ret = cli_NetGroupDelUser(cli, argv[0], argv[1]);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_groupmember_list(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ if (argc == 0 || c->display_usage) {
+ return net_rap_groupmember_usage(c, argc, argv);
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ ret = cli_NetGroupGetUsers(cli, argv[0], group_member_fn, NULL );
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_groupmember(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "add",
+ rap_groupmember_add,
+ NET_TRANSPORT_RAP,
+ "Add specified user to group",
+ "net rap groupmember add\n"
+ " Add specified user to group"
+ },
+ {
+ "list",
+ rap_groupmember_list,
+ NET_TRANSPORT_RAP,
+ "List users in group",
+ "net rap groupmember list\n"
+ " List users in group"
+ },
+ {
+ "delete",
+ rap_groupmember_delete,
+ NET_TRANSPORT_RAP,
+ "Remove user from group",
+ "net rap groupmember delete\n"
+ " Remove user from group"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net rap groupmember", func);
+}
+
+int net_rap_validate_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("net rap validate <username> [password]\n"
+ "\tValidate user and password to check whether they"
+ " can access target server or domain\n");
+
+ net_common_flags_usage(c, argc, argv);
+ return -1;
+}
+
+int net_rap_validate(struct net_context *c, int argc, const char **argv)
+{
+ return errmsg_not_implemented();
+}
+
+int net_rap_service_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("net rap service [misc. options] [targets] \n"
+ "\tlists all running service daemons on target server\n");
+ d_printf("\nnet rap service START <name> [service startup arguments]"
+ " [misc. options] [targets]"
+ "\n\tStart named service on remote server\n");
+ d_printf("\nnet rap service STOP <name> [misc. options] [targets]\n"
+ "\n\tStop named service on remote server\n");
+
+ net_common_flags_usage(c, argc, argv);
+ return -1;
+}
+
+static int rap_service_start(struct net_context *c, int argc, const char **argv)
+{
+ return errmsg_not_implemented();
+}
+
+static int rap_service_stop(struct net_context *c, int argc, const char **argv)
+{
+ return errmsg_not_implemented();
+}
+
+static void service_fn(const char *service_name, const char *dummy,
+ void *state)
+{
+ d_printf("%-21.21s\n", service_name);
+}
+
+int net_rap_service(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "start",
+ rap_service_start,
+ NET_TRANSPORT_RAP,
+ "Start service on remote server",
+ "net rap service start\n"
+ " Start service on remote server"
+ },
+ {
+ "stop",
+ rap_service_stop,
+ NET_TRANSPORT_RAP,
+ "Stop named serve on remote server",
+ "net rap service stop\n"
+ " Stop named serve on remote server"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ if (argc == 0) {
+ struct cli_state *cli;
+ int ret;
+ if (c->display_usage) {
+ d_printf("Usage:\n");
+ d_printf("net rap service\n"
+ " List services on remote server\n");
+ net_display_usage_from_functable(func);
+ return 0;
+ }
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ if (c->opt_long_list_entries) {
+ d_printf("Service name Comment\n");
+ d_printf("-----------------------------\n");
+ ret = cli_RNetServiceEnum(cli, long_group_fn, NULL);
+ }
+ ret = cli_RNetServiceEnum(cli, service_fn, NULL);
+ cli_shutdown(cli);
+ return ret;
+ }
+
+ return net_run_function(c, argc, argv, "net rap service", func);
+}
+
+int net_rap_password_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(
+ "net rap password <user> <oldpwo> <newpw> [misc. options] [target]\n"
+ "\tchanges the password for the specified user at target\n");
+
+ return -1;
+}
+
+
+int net_rap_password(struct net_context *c, int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (argc < 3 || c->display_usage)
+ return net_rap_password_usage(c, argc, argv);
+
+ if (!NT_STATUS_IS_OK(net_make_ipc_connection(c, 0, &cli)))
+ return -1;
+
+ /* BB Add check for password lengths? */
+ ret = cli_oem_change_password(cli, argv[0], argv[2], argv[1]);
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_admin_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(
+ "net rap admin <remote command> [cmd args [env]] [misc. options] [targets]"
+ "\n\texecutes a remote command on an os/2 target server\n");
+
+ return -1;
+}
+
+
+int net_rap_admin(struct net_context *c, int argc, const char **argv)
+{
+ return errmsg_not_implemented();
+}
+
+/* Entry-point for all the RAP functions. */
+
+int net_rap(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "file",
+ net_rap_file,
+ NET_TRANSPORT_RAP,
+ "List open files",
+ "net rap file\n"
+ " List open files"
+ },
+ {
+ "share",
+ net_rap_share,
+ NET_TRANSPORT_RAP,
+ "List shares exported by server",
+ "net rap share\n"
+ " List shares exported by server"
+ },
+ {
+ "session",
+ net_rap_session,
+ NET_TRANSPORT_RAP,
+ "List open sessions",
+ "net rap session\n"
+ " List open sessions"
+ },
+ {
+ "server",
+ net_rap_server,
+ NET_TRANSPORT_RAP,
+ "List servers in workgroup",
+ "net rap server\n"
+ " List servers in domain/workgroup"
+ },
+ {
+ "domain",
+ net_rap_domain,
+ NET_TRANSPORT_RAP,
+ "List domains in network",
+ "net rap domain\n"
+ " List domains in network"
+ },
+ {
+ "printq",
+ net_rap_printq,
+ NET_TRANSPORT_RAP,
+ "List printer queues on server",
+ "net rap printq\n"
+ " List printer queues on server"
+ },
+ {
+ "user",
+ net_rap_user,
+ NET_TRANSPORT_RAP,
+ "List users",
+ "net rap user\n"
+ " List users"
+ },
+ {
+ "group",
+ net_rap_group,
+ NET_TRANSPORT_RAP,
+ "List user groups",
+ "net rap group\n"
+ " List user groups"
+ },
+ {
+ "validate",
+ net_rap_validate,
+ NET_TRANSPORT_RAP,
+ "Check username/password",
+ "net rap validate\n"
+ " Check username/password"
+ },
+ {
+ "groupmember",
+ net_rap_groupmember,
+ NET_TRANSPORT_RAP,
+ "List/modify group memberships",
+ "net rap groupmember\n"
+ " List/modify group memberships"
+ },
+ {
+ "admin",
+ net_rap_admin,
+ NET_TRANSPORT_RAP,
+ "Execute commands on remote OS/2",
+ "net rap admin\n"
+ " Execute commands on remote OS/2"
+ },
+ {
+ "service",
+ net_rap_service,
+ NET_TRANSPORT_RAP,
+ "Start/stop remote service",
+ "net rap service\n"
+ " Start/stop remote service"
+ },
+ {
+ "password",
+ net_rap_password,
+ NET_TRANSPORT_RAP,
+ "Change user password",
+ "net rap password\n"
+ " Change user password"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net rap", func);
+}
+
diff --git a/source3/utils/net_registry.c b/source3/utils/net_registry.c
new file mode 100644
index 0000000000..26710b3580
--- /dev/null
+++ b/source3/utils/net_registry.c
@@ -0,0 +1,531 @@
+/*
+ * Samba Unix/Linux SMB client library
+ * Distributed SMB/CIFS Server Management Utility
+ * Local registry interface
+ *
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "utils/net.h"
+#include "utils/net_registry_util.h"
+
+
+/*
+ *
+ * Helper functions
+ *
+ */
+
+/**
+ * split given path into hive and remaining path and open the hive key
+ */
+static WERROR open_hive(TALLOC_CTX *ctx, const char *path,
+ uint32 desired_access,
+ struct registry_key **hive,
+ char **subkeyname)
+{
+ WERROR werr;
+ NT_USER_TOKEN *token = NULL;
+ char *hivename = NULL;
+ char *tmp_subkeyname = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ if ((hive == NULL) || (subkeyname == NULL)) {
+ werr = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ werr = split_hive_key(tmp_ctx, path, &hivename, &tmp_subkeyname);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ *subkeyname = talloc_strdup(ctx, tmp_subkeyname);
+ if (*subkeyname == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ werr = ntstatus_to_werror(registry_create_admin_token(tmp_ctx, &token));
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = reg_openhive(ctx, hivename, desired_access, token, hive);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = WERR_OK;
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+}
+
+static WERROR open_key(TALLOC_CTX *ctx, const char *path,
+ uint32 desired_access,
+ struct registry_key **key)
+{
+ WERROR werr;
+ char *subkey_name = NULL;
+ struct registry_key *hive = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ if ((path == NULL) || (key == NULL)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ werr = open_hive(tmp_ctx, path, desired_access, &hive, &subkey_name);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "open_hive failed: %s\n", dos_errstr(werr));
+ goto done;
+ }
+
+ werr = reg_openkey(ctx, hive, subkey_name, desired_access, key);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "reg_openkey failed: %s\n",
+ dos_errstr(werr));
+ goto done;
+ }
+
+ werr = WERR_OK;
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+}
+
+/*
+ *
+ * the main "net registry" function implementations
+ *
+ */
+
+static int net_registry_enumerate(struct net_context *c, int argc,
+ const char **argv)
+{
+ WERROR werr;
+ struct registry_key *key = NULL;
+ TALLOC_CTX *ctx = talloc_stackframe();
+ char *subkey_name;
+ NTTIME modtime;
+ uint32_t count;
+ char *valname = NULL;
+ struct registry_value *valvalue = NULL;
+ int ret = -1;
+
+ if (argc != 1 || c->display_usage) {
+ d_printf("Usage: net registry enumerate <path>\n");
+ d_printf("Example: net registry enumerate "
+ "'HKLM\\Software\\Samba'\n");
+ goto done;
+ }
+
+ werr = open_key(ctx, argv[0], REG_KEY_READ, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "open_key failed: %s\n", dos_errstr(werr));
+ goto done;
+ }
+
+ for (count = 0;
+ werr = reg_enumkey(ctx, key, count, &subkey_name, &modtime),
+ W_ERROR_IS_OK(werr);
+ count++)
+ {
+ print_registry_key(subkey_name, &modtime);
+ }
+ if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
+ goto done;
+ }
+
+ for (count = 0;
+ werr = reg_enumvalue(ctx, key, count, &valname, &valvalue),
+ W_ERROR_IS_OK(werr);
+ count++)
+ {
+ print_registry_value_with_name(valname, valvalue);
+ }
+ if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
+ goto done;
+ }
+
+ ret = 0;
+done:
+ TALLOC_FREE(ctx);
+ return ret;
+}
+
+static int net_registry_createkey(struct net_context *c, int argc,
+ const char **argv)
+{
+ WERROR werr;
+ enum winreg_CreateAction action;
+ char *subkeyname;
+ struct registry_key *hivekey = NULL;
+ struct registry_key *subkey = NULL;
+ TALLOC_CTX *ctx = talloc_stackframe();
+ int ret = -1;
+
+ if (argc != 1 || c->display_usage) {
+ d_printf("Usage: net registry createkey <path>\n");
+ d_printf("Example: net registry createkey "
+ "'HKLM\\Software\\Samba\\smbconf.127.0.0.1'\n");
+ goto done;
+ }
+ if (strlen(argv[0]) == 0) {
+ d_fprintf(stderr, "error: zero length key name given\n");
+ goto done;
+ }
+
+ werr = open_hive(ctx, argv[0], REG_KEY_WRITE, &hivekey, &subkeyname);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "open_hive failed: %s\n", dos_errstr(werr));
+ goto done;
+ }
+
+ werr = reg_createkey(ctx, hivekey, subkeyname, REG_KEY_WRITE,
+ &subkey, &action);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "reg_createkey failed: %s\n",
+ dos_errstr(werr));
+ goto done;
+ }
+ switch (action) {
+ case REG_ACTION_NONE:
+ d_printf("createkey did nothing -- huh?\n");
+ break;
+ case REG_CREATED_NEW_KEY:
+ d_printf("createkey created %s\n", argv[0]);
+ break;
+ case REG_OPENED_EXISTING_KEY:
+ d_printf("createkey opened existing %s\n", argv[0]);
+ break;
+ }
+
+ ret = 0;
+
+done:
+ TALLOC_FREE(ctx);
+ return ret;
+}
+
+static int net_registry_deletekey(struct net_context *c, int argc,
+ const char **argv)
+{
+ WERROR werr;
+ char *subkeyname;
+ struct registry_key *hivekey = NULL;
+ TALLOC_CTX *ctx = talloc_stackframe();
+ int ret = -1;
+
+ if (argc != 1 || c->display_usage) {
+ d_printf("Usage: net registry deletekey <path>\n");
+ d_printf("Example: net registry deletekey "
+ "'HKLM\\Software\\Samba\\smbconf.127.0.0.1'\n");
+ goto done;
+ }
+ if (strlen(argv[0]) == 0) {
+ d_fprintf(stderr, "error: zero length key name given\n");
+ goto done;
+ }
+
+ werr = open_hive(ctx, argv[0], REG_KEY_WRITE, &hivekey, &subkeyname);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "open_hive failed: %s\n", dos_errstr(werr));
+ goto done;
+ }
+
+ werr = reg_deletekey(hivekey, subkeyname);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "reg_deletekey failed: %s\n",
+ dos_errstr(werr));
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ TALLOC_FREE(ctx);
+ return ret;
+}
+
+static int net_registry_getvalue_internal(struct net_context *c, int argc,
+ const char **argv, bool raw)
+{
+ WERROR werr;
+ int ret = -1;
+ struct registry_key *key = NULL;
+ struct registry_value *value = NULL;
+ TALLOC_CTX *ctx = talloc_stackframe();
+
+ if (argc != 2 || c->display_usage) {
+ d_fprintf(stderr, "usage: net rpc registry getvalue <key> "
+ "<valuename>\n");
+ goto done;
+ }
+
+ werr = open_key(ctx, argv[0], REG_KEY_READ, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "open_key failed: %s\n", dos_errstr(werr));
+ goto done;
+ }
+
+ werr = reg_queryvalue(ctx, key, argv[1], &value);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "reg_queryvalue failed: %s\n",
+ dos_errstr(werr));
+ goto done;
+ }
+
+ print_registry_value(value, raw);
+
+ ret = 0;
+
+done:
+ TALLOC_FREE(ctx);
+ return ret;
+}
+
+static int net_registry_getvalue(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_registry_getvalue_internal(c, argc, argv, false);
+}
+
+static int net_registry_getvalueraw(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_registry_getvalue_internal(c, argc, argv, true);
+}
+
+static int net_registry_setvalue(struct net_context *c, int argc,
+ const char **argv)
+{
+ WERROR werr;
+ struct registry_value value;
+ struct registry_key *key = NULL;
+ int ret = -1;
+ TALLOC_CTX *ctx = talloc_stackframe();
+
+ if (argc < 4 || c->display_usage) {
+ d_fprintf(stderr, "usage: net rpc registry setvalue <key> "
+ "<valuename> <type> [<val>]+\n");
+ goto done;
+ }
+
+ if (!strequal(argv[2], "multi_sz") && (argc != 4)) {
+ d_fprintf(stderr, "Too many args for type %s\n", argv[2]);
+ goto done;
+ }
+
+ if (strequal(argv[2], "dword")) {
+ value.type = REG_DWORD;
+ value.v.dword = strtoul(argv[3], NULL, 10);
+ } else if (strequal(argv[2], "sz")) {
+ value.type = REG_SZ;
+ value.v.sz.len = strlen(argv[3])+1;
+ value.v.sz.str = CONST_DISCARD(char *, argv[3]);
+ } else {
+ d_fprintf(stderr, "type \"%s\" not implemented\n", argv[2]);
+ goto done;
+ }
+
+ werr = open_key(ctx, argv[0], REG_KEY_WRITE, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "open_key failed: %s\n", dos_errstr(werr));
+ goto done;
+ }
+
+ werr = reg_setvalue(key, argv[1], &value);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "reg_setvalue failed: %s\n",
+ dos_errstr(werr));
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ TALLOC_FREE(ctx);
+ return ret;
+}
+
+static int net_registry_deletevalue(struct net_context *c, int argc,
+ const char **argv)
+{
+ WERROR werr;
+ struct registry_key *key = NULL;
+ TALLOC_CTX *ctx = talloc_stackframe();
+ int ret = -1;
+
+ if (argc != 2 || c->display_usage) {
+ d_fprintf(stderr, "usage: net rpc registry deletevalue <key> "
+ "<valuename>\n");
+ goto done;
+ }
+
+ werr = open_key(ctx, argv[0], REG_KEY_WRITE, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "open_key failed: %s\n", dos_errstr(werr));
+ goto done;
+ }
+
+ werr = reg_deletevalue(key, argv[1]);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "reg_deletekey failed: %s\n",
+ dos_errstr(werr));
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ TALLOC_FREE(ctx);
+ return ret;
+}
+
+static int net_registry_getsd(struct net_context *c, int argc,
+ const char **argv)
+{
+ WERROR werr;
+ int ret = -1;
+ struct registry_key *key = NULL;
+ struct security_descriptor *secdesc = NULL;
+ TALLOC_CTX *ctx = talloc_stackframe();
+ uint32_t access_mask = REG_KEY_READ |
+ SEC_RIGHT_MAXIMUM_ALLOWED |
+ SEC_RIGHT_SYSTEM_SECURITY;
+
+ /*
+ * net_rpc_regsitry uses SEC_RIGHT_SYSTEM_SECURITY, but access
+ * is denied with these perms right now...
+ */
+ access_mask = REG_KEY_READ;
+
+ if (argc != 1 || c->display_usage) {
+ d_printf("Usage: net registry getsd <path>\n");
+ d_printf("Example: net registry getsd "
+ "'HKLM\\Software\\Samba'\n");
+ goto done;
+ }
+ if (strlen(argv[0]) == 0) {
+ d_fprintf(stderr, "error: zero length key name given\n");
+ goto done;
+ }
+
+ werr = open_key(ctx, argv[0], access_mask, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "open_key failed: %s\n", dos_errstr(werr));
+ goto done;
+ }
+
+ werr = reg_getkeysecurity(ctx, key, &secdesc);
+ if (!W_ERROR_IS_OK(werr)) {
+ d_fprintf(stderr, "reg_getkeysecurity failed: %s\n",
+ dos_errstr(werr));
+ goto done;
+ }
+
+ display_sec_desc(secdesc);
+
+ ret = 0;
+
+done:
+ TALLOC_FREE(ctx);
+ return ret;
+}
+
+int net_registry(struct net_context *c, int argc, const char **argv)
+{
+ int ret = -1;
+
+ struct functable func[] = {
+ {
+ "enumerate",
+ net_registry_enumerate,
+ NET_TRANSPORT_LOCAL,
+ "Enumerate registry keys and values",
+ "net registry enumerate\n"
+ " Enumerate registry keys and values"
+ },
+ {
+ "createkey",
+ net_registry_createkey,
+ NET_TRANSPORT_LOCAL,
+ "Create a new registry key",
+ "net registry createkey\n"
+ " Create a new registry key"
+ },
+ {
+ "deletekey",
+ net_registry_deletekey,
+ NET_TRANSPORT_LOCAL,
+ "Delete a registry key",
+ "net registry deletekey\n"
+ " Delete a registry key"
+ },
+ {
+ "getvalue",
+ net_registry_getvalue,
+ NET_TRANSPORT_LOCAL,
+ "Print a registry value",
+ "net registry getvalue\n"
+ " Print a registry value"
+ },
+ {
+ "getvalueraw",
+ net_registry_getvalueraw,
+ NET_TRANSPORT_LOCAL,
+ "Print a registry value (raw format)",
+ "net registry getvalueraw\n"
+ " Print a registry value (raw format)"
+ },
+ {
+ "setvalue",
+ net_registry_setvalue,
+ NET_TRANSPORT_LOCAL,
+ "Set a new registry value",
+ "net registry setvalue\n"
+ " Set a new registry value"
+ },
+ {
+ "deletevalue",
+ net_registry_deletevalue,
+ NET_TRANSPORT_LOCAL,
+ "Delete a registry value",
+ "net registry deletevalue\n"
+ " Delete a registry value"
+ },
+ {
+ "getsd",
+ net_registry_getsd,
+ NET_TRANSPORT_LOCAL,
+ "Get security descriptor",
+ "net registry getsd\n"
+ " Get security descriptor"
+ },
+ { NULL, NULL, 0, NULL, NULL }
+ };
+
+ if (!W_ERROR_IS_OK(registry_init_basic())) {
+ return -1;
+ }
+
+ ret = net_run_function(c, argc, argv, "net registry", func);
+
+ return ret;
+}
diff --git a/source3/utils/net_registry_util.c b/source3/utils/net_registry_util.c
new file mode 100644
index 0000000000..278377867a
--- /dev/null
+++ b/source3/utils/net_registry_util.c
@@ -0,0 +1,143 @@
+/*
+ * Samba Unix/Linux SMB client library
+ * Distributed SMB/CIFS Server Management Utility
+ * registry utility functions
+ *
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "utils/net_registry_util.h"
+
+void print_registry_key(const char *keyname, NTTIME *modtime)
+{
+ d_printf("Keyname = %s\n", keyname);
+ d_printf("Modtime = %s\n",
+ modtime
+ ? http_timestring(nt_time_to_unix(*modtime))
+ : "None");
+ d_printf("\n");
+}
+
+void print_registry_value(const struct registry_value *valvalue, bool raw)
+{
+ if (!raw) {
+ d_printf("Type = %s\n",
+ reg_type_lookup(valvalue->type));
+ }
+ switch(valvalue->type) {
+ case REG_DWORD:
+ if (!raw) {
+ d_printf("Value = ");
+ }
+ d_printf("%d\n", valvalue->v.dword);
+ break;
+ case REG_SZ:
+ case REG_EXPAND_SZ:
+ if (!raw) {
+ d_printf("Value = \"");
+ }
+ d_printf("%s", valvalue->v.sz.str);
+ if (!raw) {
+ d_printf("\"");
+ }
+ d_printf("\n");
+ break;
+ case REG_MULTI_SZ: {
+ uint32 j;
+ for (j = 0; j < valvalue->v.multi_sz.num_strings; j++) {
+ if (!raw) {
+ d_printf("Value[%3.3d] = \"", j);
+ }
+ d_printf("%s", valvalue->v.multi_sz.strings[j]);
+ if (!raw) {
+ d_printf("\"");
+ }
+ d_printf("\n");
+ }
+ break;
+ }
+ case REG_BINARY:
+ if (!raw) {
+ d_printf("Value = ");
+ }
+ d_printf("%d bytes\n", (int)valvalue->v.binary.length);
+ break;
+ default:
+ if (!raw) {
+ d_printf("Value = ");
+ }
+ d_printf("<unprintable>\n");
+ break;
+ }
+}
+
+void print_registry_value_with_name(const char *valname,
+ const struct registry_value *valvalue)
+{
+ d_printf("Valuename = %s\n", valname);
+ print_registry_value(valvalue, false);
+ d_printf("\n");
+}
+
+/**
+ * Split path into hive name and subkeyname
+ * normalizations performed:
+ * - convert '/' to '\\'
+ * - strip trailing '\\' chars
+ */
+WERROR split_hive_key(TALLOC_CTX *ctx, const char *path, char **hivename,
+ char **subkeyname)
+{
+ char *p;
+ const char *tmp_subkeyname;
+
+ if ((path == NULL) || (hivename == NULL) || (subkeyname == NULL)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ if (strlen(path) == 0) {
+ return WERR_INVALID_PARAM;
+ }
+
+ *hivename = talloc_string_sub(ctx, path, "/", "\\");
+ if (*hivename == NULL) {
+ return WERR_NOMEM;
+ }
+
+ /* strip trailing '\\' chars */
+ p = strrchr(*hivename, '\\');
+ while ((p != NULL) && (p[1] == '\0')) {
+ *p = '\0';
+ p = strrchr(*hivename, '\\');
+ }
+
+ p = strchr(*hivename, '\\');
+
+ if ((p == NULL) || (*p == '\0')) {
+ /* just the hive - no subkey given */
+ tmp_subkeyname = "";
+ } else {
+ *p = '\0';
+ tmp_subkeyname = p+1;
+ }
+ *subkeyname = talloc_strdup(ctx, tmp_subkeyname);
+ if (*subkeyname == NULL) {
+ return WERR_NOMEM;
+ }
+
+ return WERR_OK;
+}
diff --git a/source3/utils/net_registry_util.h b/source3/utils/net_registry_util.h
new file mode 100644
index 0000000000..61fd834a3c
--- /dev/null
+++ b/source3/utils/net_registry_util.h
@@ -0,0 +1,41 @@
+/*
+ * Samba Unix/Linux SMB client library
+ * Distributed SMB/CIFS Server Management Utility
+ * registry utility functions
+ *
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NET_REGISTRY_UTIL_H__
+#define __NET_REGISTRY_UTIL_H__
+
+void print_registry_key(const char *keyname, NTTIME *modtime);
+
+void print_registry_value(const struct registry_value *valvalue, bool raw);
+
+void print_registry_value_with_name(const char *valname,
+ const struct registry_value *valvalue);
+
+/**
+ * Split path into hive name and subkeyname
+ * normalizations performed:
+ * - convert '/' to '\\'
+ * - strip trailing '\\' chars
+ */
+WERROR split_hive_key(TALLOC_CTX *ctx, const char *path, char **hivename,
+ char **subkeyname);
+
+#endif
diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c
new file mode 100644
index 0000000000..a849ec4c10
--- /dev/null
+++ b/source3/utils/net_rpc.c
@@ -0,0 +1,7209 @@
+/*
+ Samba Unix/Linux SMB client library
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
+ Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
+ Copyright (C) 2004,2008 Guenther Deschner (gd@samba.org)
+ Copyright (C) 2005 Jeremy Allison (jra@samba.org)
+ Copyright (C) 2006 Jelmer Vernooij (jelmer@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "includes.h"
+#include "utils/net.h"
+
+static int net_mode_share;
+static bool sync_files(struct copy_clistate *cp_clistate, const char *mask);
+
+extern const char *share_type[];
+
+/**
+ * @file net_rpc.c
+ *
+ * @brief RPC based subcommands for the 'net' utility.
+ *
+ * This file should contain much of the functionality that used to
+ * be found in rpcclient, execpt that the commands should change
+ * less often, and the fucntionality should be sane (the user is not
+ * expected to know a rid/sid before they conduct an operation etc.)
+ *
+ * @todo Perhaps eventually these should be split out into a number
+ * of files, as this could get quite big.
+ **/
+
+
+/**
+ * Many of the RPC functions need the domain sid. This function gets
+ * it at the start of every run
+ *
+ * @param cli A cli_state already connected to the remote machine
+ *
+ * @return The Domain SID of the remote machine.
+ **/
+
+NTSTATUS net_get_remote_domain_sid(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ DOM_SID **domain_sid,
+ const char **domain_name)
+{
+ struct rpc_pipe_client *lsa_pipe;
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_OK;
+ union lsa_PolicyInformation *info = NULL;
+
+ result = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
+ &lsa_pipe);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Could not initialise lsa pipe\n");
+ return result;
+ }
+
+ result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, false,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "open_policy failed: %s\n",
+ nt_errstr(result));
+ return result;
+ }
+
+ result = rpccli_lsa_QueryInfoPolicy(lsa_pipe, mem_ctx,
+ &pol,
+ LSA_POLICY_INFO_ACCOUNT_DOMAIN,
+ &info);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "lsaquery failed: %s\n",
+ nt_errstr(result));
+ return result;
+ }
+
+ *domain_name = info->account_domain.name.string;
+ *domain_sid = info->account_domain.sid;
+
+ rpccli_lsa_Close(lsa_pipe, mem_ctx, &pol);
+ TALLOC_FREE(lsa_pipe);
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Run a single RPC command, from start to finish.
+ *
+ * @param pipe_name the pipe to connect to (usually a PIPE_ constant)
+ * @param conn_flag a NET_FLAG_ combination. Passed to
+ * net_make_ipc_connection.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ * @return A shell status integer (0 for success).
+ */
+
+int run_rpc_command(struct net_context *c,
+ struct cli_state *cli_arg,
+ const struct ndr_syntax_id *interface,
+ int conn_flags,
+ rpc_command_fn fn,
+ int argc,
+ const char **argv)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_hnd = NULL;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS nt_status;
+ DOM_SID *domain_sid;
+ const char *domain_name;
+
+ /* make use of cli_state handed over as an argument, if possible */
+ if (!cli_arg) {
+ nt_status = net_make_ipc_connection(c, conn_flags, &cli);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1, ("failed to make ipc connection: %s\n",
+ nt_errstr(nt_status)));
+ return -1;
+ }
+ } else {
+ cli = cli_arg;
+ }
+
+ if (!cli) {
+ return -1;
+ }
+
+ /* Create mem_ctx */
+
+ if (!(mem_ctx = talloc_init("run_rpc_command"))) {
+ DEBUG(0, ("talloc_init() failed\n"));
+ cli_shutdown(cli);
+ return -1;
+ }
+
+ nt_status = net_get_remote_domain_sid(cli, mem_ctx, &domain_sid,
+ &domain_name);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ cli_shutdown(cli);
+ return -1;
+ }
+
+ if (!(conn_flags & NET_FLAGS_NO_PIPE)) {
+ if (lp_client_schannel()
+ && (ndr_syntax_id_equal(interface,
+ &ndr_table_netlogon.syntax_id))) {
+ /* Always try and create an schannel netlogon pipe. */
+ nt_status = cli_rpc_pipe_open_schannel(
+ cli, interface,
+ PIPE_AUTH_LEVEL_PRIVACY, domain_name,
+ &pipe_hnd);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("Could not initialise schannel netlogon pipe. Error was %s\n",
+ nt_errstr(nt_status) ));
+ cli_shutdown(cli);
+ return -1;
+ }
+ } else {
+ if (conn_flags & NET_FLAGS_SEAL) {
+ nt_status = cli_rpc_pipe_open_ntlmssp(
+ cli, interface,
+ PIPE_AUTH_LEVEL_PRIVACY,
+ lp_workgroup(), c->opt_user_name,
+ c->opt_password, &pipe_hnd);
+ } else {
+ nt_status = cli_rpc_pipe_open_noauth(
+ cli, interface,
+ &pipe_hnd);
+ }
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("Could not initialise pipe %s. Error was %s\n",
+ cli_get_pipe_name_from_iface(
+ debug_ctx(), cli, interface),
+ nt_errstr(nt_status) ));
+ cli_shutdown(cli);
+ return -1;
+ }
+ }
+ }
+
+ nt_status = fn(c, domain_sid, domain_name, cli, pipe_hnd, mem_ctx, argc, argv);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1, ("rpc command function failed! (%s)\n", nt_errstr(nt_status)));
+ } else {
+ DEBUG(5, ("rpc command function succedded\n"));
+ }
+
+ if (!(conn_flags & NET_FLAGS_NO_PIPE)) {
+ if (pipe_hnd) {
+ TALLOC_FREE(pipe_hnd);
+ }
+ }
+
+ /* close the connection only if it was opened here */
+ if (!cli_arg) {
+ cli_shutdown(cli);
+ }
+
+ talloc_destroy(mem_ctx);
+ return (!NT_STATUS_IS_OK(nt_status));
+}
+
+/**
+ * Force a change of the trust acccount password.
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param domain_sid The domain sid acquired from the remote server.
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS rpc_changetrustpw_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+
+ return trust_pw_find_change_and_store_it(pipe_hnd, mem_ctx, c->opt_target_workgroup);
+}
+
+/**
+ * Force a change of the trust acccount password.
+ *
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+
+int net_rpc_changetrustpw(struct net_context *c, int argc, const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc changetrustpw\n"
+ " Change the machine trust password\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_netlogon.syntax_id,
+ NET_FLAGS_ANONYMOUS | NET_FLAGS_PDC,
+ rpc_changetrustpw_internals,
+ argc, argv);
+}
+
+/**
+ * Join a domain, the old way.
+ *
+ * This uses 'machinename' as the inital password, and changes it.
+ *
+ * The password should be created with 'server manager' or equiv first.
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param domain_sid The domain sid acquired from the remote server.
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS rpc_oldjoin_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+
+ fstring trust_passwd;
+ unsigned char orig_trust_passwd_hash[16];
+ NTSTATUS result;
+ uint32 sec_channel_type;
+
+ result = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id,
+ &pipe_hnd);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("rpc_oldjoin_internals: netlogon pipe open to machine %s failed. "
+ "error was %s\n",
+ cli->desthost,
+ nt_errstr(result) ));
+ return result;
+ }
+
+ /*
+ check what type of join - if the user want's to join as
+ a BDC, the server must agree that we are a BDC.
+ */
+ if (argc >= 0) {
+ sec_channel_type = get_sec_channel_type(argv[0]);
+ } else {
+ sec_channel_type = get_sec_channel_type(NULL);
+ }
+
+ fstrcpy(trust_passwd, global_myname());
+ strlower_m(trust_passwd);
+
+ /*
+ * Machine names can be 15 characters, but the max length on
+ * a password is 14. --jerry
+ */
+
+ trust_passwd[14] = '\0';
+
+ E_md4hash(trust_passwd, orig_trust_passwd_hash);
+
+ result = trust_pw_change_and_store_it(pipe_hnd, mem_ctx, c->opt_target_workgroup,
+ orig_trust_passwd_hash,
+ sec_channel_type);
+
+ if (NT_STATUS_IS_OK(result))
+ printf("Joined domain %s.\n", c->opt_target_workgroup);
+
+
+ if (!secrets_store_domain_sid(c->opt_target_workgroup, domain_sid)) {
+ DEBUG(0, ("error storing domain sid for %s\n", c->opt_target_workgroup));
+ result = NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return result;
+}
+
+/**
+ * Join a domain, the old way.
+ *
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+
+static int net_rpc_perform_oldjoin(struct net_context *c, int argc, const char **argv)
+{
+ return run_rpc_command(c, NULL, &ndr_table_netlogon.syntax_id,
+ NET_FLAGS_NO_PIPE | NET_FLAGS_ANONYMOUS | NET_FLAGS_PDC,
+ rpc_oldjoin_internals,
+ argc, argv);
+}
+
+/**
+ * Join a domain, the old way. This function exists to allow
+ * the message to be displayed when oldjoin was explicitly
+ * requested, but not when it was implied by "net rpc join".
+ *
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+
+static int net_rpc_oldjoin(struct net_context *c, int argc, const char **argv)
+{
+ int rc = -1;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc oldjoin\n"
+ " Join a domain the old way\n");
+ return 0;
+ }
+
+ rc = net_rpc_perform_oldjoin(c, argc, argv);
+
+ if (rc) {
+ d_fprintf(stderr, "Failed to join domain\n");
+ }
+
+ return rc;
+}
+
+/**
+ * 'net rpc join' entrypoint.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped
+ *
+ * Main 'net_rpc_join()' (where the admin username/password is used) is
+ * in net_rpc_join.c.
+ * Try to just change the password, but if that doesn't work, use/prompt
+ * for a username/password.
+ **/
+
+int net_rpc_join(struct net_context *c, int argc, const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc join -U <username>[%%password] <type>\n"
+ " Join a domain\n"
+ " username\tName of the admin user"
+ " password\tPassword of the admin user, will "
+ "prompt if not specified\n"
+ " type\tCan be one of the following:\n"
+ "\t\tMEMBER\tJoin as member server (default)\n"
+ "\t\tBDC\tJoin as BDC\n"
+ "\t\tPDC\tJoin as PDC\n");
+ return 0;
+ }
+
+ if (lp_server_role() == ROLE_STANDALONE) {
+ d_printf("cannot join as standalone machine\n");
+ return -1;
+ }
+
+ if (strlen(global_myname()) > 15) {
+ d_printf("Our netbios name can be at most 15 chars long, "
+ "\"%s\" is %u chars long\n",
+ global_myname(), (unsigned int)strlen(global_myname()));
+ return -1;
+ }
+
+ if ((net_rpc_perform_oldjoin(c, argc, argv) == 0))
+ return 0;
+
+ return net_rpc_join_newstyle(c, argc, argv);
+}
+
+/**
+ * display info about a rpc domain
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param domain_sid The domain sid acquired from the remote server
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+NTSTATUS rpc_info_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ union samr_DomainInfo *info = NULL;
+ fstring sid_str;
+
+ sid_to_fstring(sid_str, domain_sid);
+
+ /* Get sam policy handle */
+ result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Could not connect to SAM: %s\n", nt_errstr(result));
+ goto done;
+ }
+
+ /* Get domain policy handle */
+ result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ CONST_DISCARD(struct dom_sid2 *, domain_sid),
+ &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Could not open domain: %s\n", nt_errstr(result));
+ goto done;
+ }
+
+ result = rpccli_samr_QueryDomainInfo(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 2,
+ &info);
+ if (NT_STATUS_IS_OK(result)) {
+ d_printf("Domain Name: %s\n", info->info2.domain_name.string);
+ d_printf("Domain SID: %s\n", sid_str);
+ d_printf("Sequence number: %llu\n",
+ (unsigned long long)info->info2.sequence_num);
+ d_printf("Num users: %u\n", info->info2.num_users);
+ d_printf("Num domain groups: %u\n", info->info2.num_groups);
+ d_printf("Num local groups: %u\n", info->info2.num_aliases);
+ }
+
+ done:
+ return result;
+}
+
+/**
+ * 'net rpc info' entrypoint.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ **/
+
+int net_rpc_info(struct net_context *c, int argc, const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc info\n"
+ " Display information about the domain\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id,
+ NET_FLAGS_PDC, rpc_info_internals,
+ argc, argv);
+}
+
+/**
+ * Fetch domain SID into the local secrets.tdb.
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param domain_sid The domain sid acquired from the remote server.
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS rpc_getsid_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ fstring sid_str;
+
+ sid_to_fstring(sid_str, domain_sid);
+ d_printf("Storing SID %s for Domain %s in secrets.tdb\n",
+ sid_str, domain_name);
+
+ if (!secrets_store_domain_sid(domain_name, domain_sid)) {
+ DEBUG(0,("Can't store domain SID\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * 'net rpc getsid' entrypoint.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ **/
+
+int net_rpc_getsid(struct net_context *c, int argc, const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc getsid\n"
+ " Fetch domain SID into local secrets.tdb\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id,
+ NET_FLAGS_ANONYMOUS | NET_FLAGS_PDC,
+ rpc_getsid_internals,
+ argc, argv);
+}
+
+/****************************************************************************/
+
+/**
+ * Basic usage function for 'net rpc user'.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ **/
+
+static int rpc_user_usage(struct net_context *c, int argc, const char **argv)
+{
+ return net_user_usage(c, argc, argv);
+}
+
+/**
+ * Add a new user to a remote RPC server.
+ *
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+
+static int rpc_user_add(struct net_context *c, int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct USER_INFO_1 info1;
+ uint32_t parm_error = 0;
+
+ if (argc < 1 || c->display_usage) {
+ rpc_user_usage(c, argc, argv);
+ return 0;
+ }
+
+ ZERO_STRUCT(info1);
+
+ info1.usri1_name = argv[0];
+ if (argc == 2) {
+ info1.usri1_password = argv[1];
+ }
+
+ status = NetUserAdd(c->opt_host, 1, (uint8_t *)&info1, &parm_error);
+
+ if (status != 0) {
+ d_fprintf(stderr, "Failed to add user '%s' with: %s.\n",
+ argv[0], libnetapi_get_error_string(c->netapi_ctx,
+ status));
+ return -1;
+ } else {
+ d_printf("Added user '%s'.\n", argv[0]);
+ }
+
+ return 0;
+}
+
+/**
+ * Rename a user on a remote RPC server.
+ *
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+
+static int rpc_user_rename(struct net_context *c, int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct USER_INFO_0 u0;
+ uint32_t parm_err = 0;
+
+ if (argc != 2 || c->display_usage) {
+ rpc_user_usage(c, argc, argv);
+ return 0;
+ }
+
+ u0.usri0_name = argv[1];
+
+ status = NetUserSetInfo(c->opt_host, argv[0],
+ 0, (uint8_t *)&u0, &parm_err);
+ if (status) {
+ d_fprintf(stderr, "Failed to rename user from %s to %s - %s\n",
+ argv[0], argv[1],
+ libnetapi_get_error_string(c->netapi_ctx, status));
+ } else {
+ d_printf("Renamed user from %s to %s\n", argv[0], argv[1]);
+ }
+
+ return status;
+}
+
+/**
+ * Delete a user from a remote RPC server.
+ *
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+
+static int rpc_user_delete(struct net_context *c, int argc, const char **argv)
+{
+ NET_API_STATUS status;
+
+ if (argc < 1 || c->display_usage) {
+ rpc_user_usage(c, argc, argv);
+ return 0;
+ }
+
+ status = NetUserDel(c->opt_host, argv[0]);
+
+ if (status != 0) {
+ d_fprintf(stderr, "Failed to delete user '%s' with: %s.\n",
+ argv[0],
+ libnetapi_get_error_string(c->netapi_ctx, status));
+ return -1;
+ } else {
+ d_printf("Deleted user '%s'.\n", argv[0]);
+ }
+
+ return 0;
+}
+
+/**
+ * Set a user's password on a remote RPC server.
+ *
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+
+static int rpc_user_password(struct net_context *c, int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ char *prompt = NULL;
+ struct USER_INFO_1003 u1003;
+ uint32_t parm_err = 0;
+
+ if (argc < 1 || c->display_usage) {
+ rpc_user_usage(c, argc, argv);
+ return 0;
+ }
+
+ if (argv[1]) {
+ u1003.usri1003_password = argv[1];
+ } else {
+ asprintf(&prompt, "Enter new password for %s:", argv[0]);
+ u1003.usri1003_password = getpass(prompt);
+ SAFE_FREE(prompt);
+ }
+
+ status = NetUserSetInfo(c->opt_host, argv[0], 1003, (uint8_t *)&u1003, &parm_err);
+
+ /* Display results */
+ if (status != 0) {
+ d_fprintf(stderr, "Failed to set password for '%s' with: %s.\n",
+ argv[0], libnetapi_get_error_string(c->netapi_ctx,
+ status));
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * List a user's groups from a remote RPC server.
+ *
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success)
+ **/
+
+static int rpc_user_info(struct net_context *c, int argc, const char **argv)
+
+{
+ NET_API_STATUS status;
+ struct GROUP_USERS_INFO_0 *u0 = NULL;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ int i;
+
+
+ if (argc < 1 || c->display_usage) {
+ rpc_user_usage(c, argc, argv);
+ return 0;
+ }
+
+ status = NetUserGetGroups(c->opt_host,
+ argv[0],
+ 0,
+ (uint8_t **)&u0,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries);
+ if (status != 0) {
+ d_fprintf(stderr, "Failed to get groups for '%s' with: %s.\n",
+ argv[0], libnetapi_get_error_string(c->netapi_ctx,
+ status));
+ return -1;
+ }
+
+ for (i=0; i < entries_read; i++) {
+ printf("%s\n", u0->grui0_name);
+ u0++;
+ }
+
+ return 0;
+}
+
+/**
+ * List users on a remote RPC server.
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param domain_sid The domain sid acquired from the remote server.
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static int rpc_user_list(struct net_context *c, int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ uint32_t start_idx=0, num_entries, i, loop_count = 0;
+ struct NET_DISPLAY_USER *info = NULL;
+ void *buffer = NULL;
+
+ /* Query domain users */
+ if (c->opt_long_list_entries)
+ d_printf("\nUser name Comment"
+ "\n-----------------------------\n");
+ do {
+ uint32_t max_entries, max_size;
+
+ get_query_dispinfo_params(
+ loop_count, &max_entries, &max_size);
+
+ status = NetQueryDisplayInformation(c->opt_host,
+ 1,
+ start_idx,
+ max_entries,
+ max_size,
+ &num_entries,
+ &buffer);
+ if (status != 0 && status != ERROR_MORE_DATA) {
+ return status;
+ }
+
+ info = (struct NET_DISPLAY_USER *)buffer;
+
+ for (i = 0; i < num_entries; i++) {
+
+ if (c->opt_long_list_entries)
+ printf("%-21.21s %s\n", info->usri1_name,
+ info->usri1_comment);
+ else
+ printf("%s\n", info->usri1_name);
+ info++;
+ }
+
+ NetApiBufferFree(buffer);
+
+ loop_count++;
+ start_idx += num_entries;
+
+ } while (status == ERROR_MORE_DATA);
+
+ return status;
+}
+
+/**
+ * 'net rpc user' entrypoint.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ **/
+
+int net_rpc_user(struct net_context *c, int argc, const char **argv)
+{
+ NET_API_STATUS status;
+
+ struct functable func[] = {
+ {
+ "add",
+ rpc_user_add,
+ NET_TRANSPORT_RPC,
+ "Add specified user",
+ "net rpc user add\n"
+ " Add specified user"
+ },
+ {
+ "info",
+ rpc_user_info,
+ NET_TRANSPORT_RPC,
+ "List domain groups of user",
+ "net rpc user info\n"
+ " Lis domain groups of user"
+ },
+ {
+ "delete",
+ rpc_user_delete,
+ NET_TRANSPORT_RPC,
+ "Remove specified user",
+ "net rpc user delete\n"
+ " Remove specified user"
+ },
+ {
+ "password",
+ rpc_user_password,
+ NET_TRANSPORT_RPC,
+ "Change user password",
+ "net rpc user password\n"
+ " Change user password"
+ },
+ {
+ "rename",
+ rpc_user_rename,
+ NET_TRANSPORT_RPC,
+ "Rename specified user",
+ "net rpc user rename\n"
+ " Rename specified user"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ status = libnetapi_init(&c->netapi_ctx);
+ if (status != 0) {
+ return -1;
+ }
+ libnetapi_set_username(c->netapi_ctx, c->opt_user_name);
+ libnetapi_set_password(c->netapi_ctx, c->opt_password);
+ if (c->opt_kerberos) {
+ libnetapi_set_use_kerberos(c->netapi_ctx);
+ }
+
+ if (argc == 0) {
+ if (c->display_usage) {
+ d_printf("Usage:\n");
+ d_printf("net rpc user\n"
+ " List all users\n");
+ net_display_usage_from_functable(func);
+ return 0;
+ }
+
+ return rpc_user_list(c, argc, argv);
+ }
+
+ return net_run_function(c, argc, argv, "net rpc user", func);
+}
+
+static NTSTATUS rpc_sh_user_list(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ return werror_to_ntstatus(W_ERROR(rpc_user_list(c, argc, argv)));
+}
+
+static NTSTATUS rpc_sh_user_info(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ return werror_to_ntstatus(W_ERROR(rpc_user_info(c, argc, argv)));
+}
+
+static NTSTATUS rpc_sh_handle_user(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv,
+ NTSTATUS (*fn)(
+ struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ POLICY_HND *user_hnd,
+ int argc, const char **argv))
+{
+ POLICY_HND connect_pol, domain_pol, user_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_SID sid;
+ uint32 rid;
+ enum lsa_SidType type;
+
+ if (argc == 0) {
+ d_fprintf(stderr, "usage: %s <username>\n", ctx->whoami);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ZERO_STRUCT(connect_pol);
+ ZERO_STRUCT(domain_pol);
+ ZERO_STRUCT(user_pol);
+
+ result = net_rpc_lookup_name(c, mem_ctx, rpc_pipe_np_smb_conn(pipe_hnd),
+ argv[0], NULL, NULL, &sid, &type);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Could not lookup %s: %s\n", argv[0],
+ nt_errstr(result));
+ goto done;
+ }
+
+ if (type != SID_NAME_USER) {
+ d_fprintf(stderr, "%s is a %s, not a user\n", argv[0],
+ sid_type_lookup(type));
+ result = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ }
+
+ if (!sid_peek_check_rid(ctx->domain_sid, &sid, &rid)) {
+ d_fprintf(stderr, "%s is not in our domain\n", argv[0]);
+ result = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ }
+
+ result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ ctx->domain_sid,
+ &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
+ &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ rid,
+ &user_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = fn(c, mem_ctx, ctx, pipe_hnd, &user_pol, argc-1, argv+1);
+
+ done:
+ if (is_valid_policy_hnd(&user_pol)) {
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
+ }
+ if (is_valid_policy_hnd(&domain_pol)) {
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
+ }
+ if (is_valid_policy_hnd(&connect_pol)) {
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &connect_pol);
+ }
+ return result;
+}
+
+static NTSTATUS rpc_sh_user_show_internals(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ POLICY_HND *user_hnd,
+ int argc, const char **argv)
+{
+ NTSTATUS result;
+ union samr_UserInfo *info = NULL;
+
+ if (argc != 0) {
+ d_fprintf(stderr, "usage: %s show <username>\n", ctx->whoami);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ result = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
+ user_hnd,
+ 21,
+ &info);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ d_printf("user rid: %d, group rid: %d\n",
+ info->info21.rid,
+ info->info21.primary_gid);
+
+ return result;
+}
+
+static NTSTATUS rpc_sh_user_show(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ return rpc_sh_handle_user(c, mem_ctx, ctx, pipe_hnd, argc, argv,
+ rpc_sh_user_show_internals);
+}
+
+#define FETCHSTR(name, rec) \
+do { if (strequal(ctx->thiscmd, name)) { \
+ oldval = talloc_strdup(mem_ctx, info->info21.rec.string); } \
+} while (0);
+
+#define SETSTR(name, rec, flag) \
+do { if (strequal(ctx->thiscmd, name)) { \
+ init_lsa_String(&(info->info21.rec), argv[0]); \
+ info->info21.fields_present |= SAMR_FIELD_##flag; } \
+} while (0);
+
+static NTSTATUS rpc_sh_user_str_edit_internals(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ POLICY_HND *user_hnd,
+ int argc, const char **argv)
+{
+ NTSTATUS result;
+ const char *username;
+ const char *oldval = "";
+ union samr_UserInfo *info = NULL;
+
+ if (argc > 1) {
+ d_fprintf(stderr, "usage: %s <username> [new value|NULL]\n",
+ ctx->whoami);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ result = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
+ user_hnd,
+ 21,
+ &info);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ username = talloc_strdup(mem_ctx, info->info21.account_name.string);
+
+ FETCHSTR("fullname", full_name);
+ FETCHSTR("homedir", home_directory);
+ FETCHSTR("homedrive", home_drive);
+ FETCHSTR("logonscript", logon_script);
+ FETCHSTR("profilepath", profile_path);
+ FETCHSTR("description", description);
+
+ if (argc == 0) {
+ d_printf("%s's %s: [%s]\n", username, ctx->thiscmd, oldval);
+ goto done;
+ }
+
+ if (strcmp(argv[0], "NULL") == 0) {
+ argv[0] = "";
+ }
+
+ ZERO_STRUCT(info->info21);
+
+ SETSTR("fullname", full_name, FULL_NAME);
+ SETSTR("homedir", home_directory, HOME_DIRECTORY);
+ SETSTR("homedrive", home_drive, HOME_DRIVE);
+ SETSTR("logonscript", logon_script, LOGON_SCRIPT);
+ SETSTR("profilepath", profile_path, PROFILE_PATH);
+ SETSTR("description", description, DESCRIPTION);
+
+ result = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
+ user_hnd,
+ 21,
+ info);
+
+ d_printf("Set %s's %s from [%s] to [%s]\n", username,
+ ctx->thiscmd, oldval, argv[0]);
+
+ done:
+
+ return result;
+}
+
+#define HANDLEFLG(name, rec) \
+do { if (strequal(ctx->thiscmd, name)) { \
+ oldval = (oldflags & ACB_##rec) ? "yes" : "no"; \
+ if (newval) { \
+ newflags = oldflags | ACB_##rec; \
+ } else { \
+ newflags = oldflags & ~ACB_##rec; \
+ } } } while (0);
+
+static NTSTATUS rpc_sh_user_str_edit(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ return rpc_sh_handle_user(c, mem_ctx, ctx, pipe_hnd, argc, argv,
+ rpc_sh_user_str_edit_internals);
+}
+
+static NTSTATUS rpc_sh_user_flag_edit_internals(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ POLICY_HND *user_hnd,
+ int argc, const char **argv)
+{
+ NTSTATUS result;
+ const char *username;
+ const char *oldval = "unknown";
+ uint32 oldflags, newflags;
+ bool newval;
+ union samr_UserInfo *info = NULL;
+
+ if ((argc > 1) ||
+ ((argc == 1) && !strequal(argv[0], "yes") &&
+ !strequal(argv[0], "no"))) {
+ d_fprintf(stderr, "usage: %s <username> [yes|no]\n",
+ ctx->whoami);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ newval = strequal(argv[0], "yes");
+
+ result = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
+ user_hnd,
+ 21,
+ &info);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ username = talloc_strdup(mem_ctx, info->info21.account_name.string);
+ oldflags = info->info21.acct_flags;
+ newflags = info->info21.acct_flags;
+
+ HANDLEFLG("disabled", DISABLED);
+ HANDLEFLG("pwnotreq", PWNOTREQ);
+ HANDLEFLG("autolock", AUTOLOCK);
+ HANDLEFLG("pwnoexp", PWNOEXP);
+
+ if (argc == 0) {
+ d_printf("%s's %s flag: %s\n", username, ctx->thiscmd, oldval);
+ goto done;
+ }
+
+ ZERO_STRUCT(info->info21);
+
+ info->info21.acct_flags = newflags;
+ info->info21.fields_present = SAMR_FIELD_ACCT_FLAGS;
+
+ result = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
+ user_hnd,
+ 21,
+ info);
+
+ if (NT_STATUS_IS_OK(result)) {
+ d_printf("Set %s's %s flag from [%s] to [%s]\n", username,
+ ctx->thiscmd, oldval, argv[0]);
+ }
+
+ done:
+
+ return result;
+}
+
+static NTSTATUS rpc_sh_user_flag_edit(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ return rpc_sh_handle_user(c, mem_ctx, ctx, pipe_hnd, argc, argv,
+ rpc_sh_user_flag_edit_internals);
+}
+
+struct rpc_sh_cmd *net_rpc_user_edit_cmds(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx)
+{
+ static struct rpc_sh_cmd cmds[] = {
+
+ { "fullname", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_str_edit,
+ "Show/Set a user's full name" },
+
+ { "homedir", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_str_edit,
+ "Show/Set a user's home directory" },
+
+ { "homedrive", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_str_edit,
+ "Show/Set a user's home drive" },
+
+ { "logonscript", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_str_edit,
+ "Show/Set a user's logon script" },
+
+ { "profilepath", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_str_edit,
+ "Show/Set a user's profile path" },
+
+ { "description", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_str_edit,
+ "Show/Set a user's description" },
+
+ { "disabled", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_flag_edit,
+ "Show/Set whether a user is disabled" },
+
+ { "autolock", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_flag_edit,
+ "Show/Set whether a user locked out" },
+
+ { "pwnotreq", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_flag_edit,
+ "Show/Set whether a user does not need a password" },
+
+ { "pwnoexp", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_flag_edit,
+ "Show/Set whether a user's password does not expire" },
+
+ { NULL, NULL, 0, NULL, NULL }
+ };
+
+ return cmds;
+}
+
+struct rpc_sh_cmd *net_rpc_user_cmds(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx)
+{
+ static struct rpc_sh_cmd cmds[] = {
+
+ { "list", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_list,
+ "List available users" },
+
+ { "info", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_info,
+ "List the domain groups a user is member of" },
+
+ { "show", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_show,
+ "Show info about a user" },
+
+ { "edit", net_rpc_user_edit_cmds, 0, NULL,
+ "Show/Modify a user's fields" },
+
+ { NULL, NULL, 0, NULL, NULL }
+ };
+
+ return cmds;
+}
+
+/****************************************************************************/
+
+/**
+ * Basic usage function for 'net rpc group'.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ **/
+
+static int rpc_group_usage(struct net_context *c, int argc, const char **argv)
+{
+ return net_group_usage(c, argc, argv);
+}
+
+/**
+ * Delete group on a remote RPC server.
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param domain_sid The domain sid acquired from the remote server.
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS rpc_group_delete_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, group_pol, user_pol;
+ bool group_is_primary = false;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32_t group_rid;
+ struct samr_RidTypeArray *rids = NULL;
+ /* char **names; */
+ int i;
+ /* DOM_GID *user_gids; */
+
+ struct samr_Ids group_rids, name_types;
+ struct lsa_String lsa_acct_name;
+ union samr_UserInfo *info = NULL;
+
+ if (argc < 1 || c->display_usage) {
+ rpc_group_usage(c, argc,argv);
+ return NT_STATUS_OK; /* ok? */
+ }
+
+ result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Request samr_Connect2 failed\n");
+ goto done;
+ }
+
+ result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ CONST_DISCARD(struct dom_sid2 *, domain_sid),
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Request open_domain failed\n");
+ goto done;
+ }
+
+ init_lsa_String(&lsa_acct_name, argv[0]);
+
+ result = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 1,
+ &lsa_acct_name,
+ &group_rids,
+ &name_types);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Lookup of '%s' failed\n",argv[0]);
+ goto done;
+ }
+
+ switch (name_types.ids[0])
+ {
+ case SID_NAME_DOM_GRP:
+ result = rpccli_samr_OpenGroup(pipe_hnd, mem_ctx,
+ &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ group_rids.ids[0],
+ &group_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Request open_group failed");
+ goto done;
+ }
+
+ group_rid = group_rids.ids[0];
+
+ result = rpccli_samr_QueryGroupMember(pipe_hnd, mem_ctx,
+ &group_pol,
+ &rids);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Unable to query group members of %s",argv[0]);
+ goto done;
+ }
+
+ if (c->opt_verbose) {
+ d_printf("Domain Group %s (rid: %d) has %d members\n",
+ argv[0],group_rid, rids->count);
+ }
+
+ /* Check if group is anyone's primary group */
+ for (i = 0; i < rids->count; i++)
+ {
+ result = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
+ &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ rids->rids[i],
+ &user_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Unable to open group member %d\n",
+ rids->rids[i]);
+ goto done;
+ }
+
+ result = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
+ &user_pol,
+ 21,
+ &info);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Unable to lookup userinfo for group member %d\n",
+ rids->rids[i]);
+ goto done;
+ }
+
+ if (info->info21.primary_gid == group_rid) {
+ if (c->opt_verbose) {
+ d_printf("Group is primary group of %s\n",
+ info->info21.account_name.string);
+ }
+ group_is_primary = true;
+ }
+
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
+ }
+
+ if (group_is_primary) {
+ d_fprintf(stderr, "Unable to delete group because some "
+ "of it's members have it as primary group\n");
+ result = NT_STATUS_MEMBERS_PRIMARY_GROUP;
+ goto done;
+ }
+
+ /* remove all group members */
+ for (i = 0; i < rids->count; i++)
+ {
+ if (c->opt_verbose)
+ d_printf("Remove group member %d...",
+ rids->rids[i]);
+ result = rpccli_samr_DeleteGroupMember(pipe_hnd, mem_ctx,
+ &group_pol,
+ rids->rids[i]);
+
+ if (NT_STATUS_IS_OK(result)) {
+ if (c->opt_verbose)
+ d_printf("ok\n");
+ } else {
+ if (c->opt_verbose)
+ d_printf("failed\n");
+ goto done;
+ }
+ }
+
+ result = rpccli_samr_DeleteDomainGroup(pipe_hnd, mem_ctx,
+ &group_pol);
+
+ break;
+ /* removing a local group is easier... */
+ case SID_NAME_ALIAS:
+ result = rpccli_samr_OpenAlias(pipe_hnd, mem_ctx,
+ &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ group_rids.ids[0],
+ &group_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Request open_alias failed\n");
+ goto done;
+ }
+
+ result = rpccli_samr_DeleteDomAlias(pipe_hnd, mem_ctx,
+ &group_pol);
+ break;
+ default:
+ d_fprintf(stderr, "%s is of type %s. This command is only for deleting local or global groups\n",
+ argv[0],sid_type_lookup(name_types.ids[0]));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (NT_STATUS_IS_OK(result)) {
+ if (c->opt_verbose)
+ d_printf("Deleted %s '%s'\n",sid_type_lookup(name_types.ids[0]),argv[0]);
+ } else {
+ d_fprintf(stderr, "Deleting of %s failed: %s\n",argv[0],
+ get_friendly_nt_error_msg(result));
+ }
+
+ done:
+ return result;
+
+}
+
+static int rpc_group_delete(struct net_context *c, int argc, const char **argv)
+{
+ return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id, 0,
+ rpc_group_delete_internals, argc,argv);
+}
+
+static int rpc_group_add_internals(struct net_context *c, int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct GROUP_INFO_1 info1;
+ uint32_t parm_error = 0;
+
+ if (argc != 1 || c->display_usage) {
+ rpc_group_usage(c, argc, argv);
+ return 0;
+ }
+
+ ZERO_STRUCT(info1);
+
+ info1.grpi1_name = argv[0];
+ if (c->opt_comment && strlen(c->opt_comment) > 0) {
+ info1.grpi1_comment = c->opt_comment;
+ }
+
+ status = NetGroupAdd(c->opt_host, 1, (uint8_t *)&info1, &parm_error);
+
+ if (status != 0) {
+ d_fprintf(stderr, "Failed to add group '%s' with: %s.\n",
+ argv[0], libnetapi_get_error_string(c->netapi_ctx,
+ status));
+ return -1;
+ } else {
+ d_printf("Added group '%s'.\n", argv[0]);
+ }
+
+ return 0;
+}
+
+static int rpc_alias_add_internals(struct net_context *c, int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct LOCALGROUP_INFO_1 info1;
+ uint32_t parm_error = 0;
+
+ if (argc != 1 || c->display_usage) {
+ rpc_group_usage(c, argc, argv);
+ return 0;
+ }
+
+ ZERO_STRUCT(info1);
+
+ info1.lgrpi1_name = argv[0];
+ if (c->opt_comment && strlen(c->opt_comment) > 0) {
+ info1.lgrpi1_comment = c->opt_comment;
+ }
+
+ status = NetLocalGroupAdd(c->opt_host, 1, (uint8_t *)&info1, &parm_error);
+
+ if (status != 0) {
+ d_fprintf(stderr, "Failed to add alias '%s' with: %s.\n",
+ argv[0], libnetapi_get_error_string(c->netapi_ctx,
+ status));
+ return -1;
+ } else {
+ d_printf("Added alias '%s'.\n", argv[0]);
+ }
+
+ return 0;
+}
+
+static int rpc_group_add(struct net_context *c, int argc, const char **argv)
+{
+ if (c->opt_localgroup)
+ return rpc_alias_add_internals(c, argc, argv);
+
+ return rpc_group_add_internals(c, argc, argv);
+}
+
+static NTSTATUS get_sid_from_name(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *name,
+ DOM_SID *sid,
+ enum lsa_SidType *type)
+{
+ DOM_SID *sids = NULL;
+ enum lsa_SidType *types = NULL;
+ struct rpc_pipe_client *pipe_hnd;
+ POLICY_HND lsa_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ result = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
+ &pipe_hnd);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, false,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_lsa_lookup_names(pipe_hnd, mem_ctx, &lsa_pol, 1,
+ &name, NULL, 1, &sids, &types);
+
+ if (NT_STATUS_IS_OK(result)) {
+ sid_copy(sid, &sids[0]);
+ *type = types[0];
+ }
+
+ rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
+
+ done:
+ if (pipe_hnd) {
+ TALLOC_FREE(pipe_hnd);
+ }
+
+ if (!NT_STATUS_IS_OK(result) && (StrnCaseCmp(name, "S-", 2) == 0)) {
+
+ /* Try as S-1-5-whatever */
+
+ DOM_SID tmp_sid;
+
+ if (string_to_sid(&tmp_sid, name)) {
+ sid_copy(sid, &tmp_sid);
+ *type = SID_NAME_UNKNOWN;
+ result = NT_STATUS_OK;
+ }
+ }
+
+ return result;
+}
+
+static NTSTATUS rpc_add_groupmem(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group_sid,
+ const char *member)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result;
+ uint32 group_rid;
+ POLICY_HND group_pol;
+
+ struct samr_Ids rids, rid_types;
+ struct lsa_String lsa_acct_name;
+
+ DOM_SID sid;
+
+ sid_copy(&sid, group_sid);
+
+ if (!sid_split_rid(&sid, &group_rid)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* Get sam policy handle */
+ result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ /* Get domain policy handle */
+ result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &sid,
+ &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ init_lsa_String(&lsa_acct_name, member);
+
+ result = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 1,
+ &lsa_acct_name,
+ &rids,
+ &rid_types);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Could not lookup up group member %s\n", member);
+ goto done;
+ }
+
+ result = rpccli_samr_OpenGroup(pipe_hnd, mem_ctx,
+ &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ group_rid,
+ &group_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_samr_AddGroupMember(pipe_hnd, mem_ctx,
+ &group_pol,
+ rids.ids[0],
+ 0x0005); /* unknown flags */
+
+ done:
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &connect_pol);
+ return result;
+}
+
+static NTSTATUS rpc_add_aliasmem(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *alias_sid,
+ const char *member)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result;
+ uint32 alias_rid;
+ POLICY_HND alias_pol;
+
+ DOM_SID member_sid;
+ enum lsa_SidType member_type;
+
+ DOM_SID sid;
+
+ sid_copy(&sid, alias_sid);
+
+ if (!sid_split_rid(&sid, &alias_rid)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ result = get_sid_from_name(rpc_pipe_np_smb_conn(pipe_hnd), mem_ctx,
+ member, &member_sid, &member_type);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Could not lookup up group member %s\n", member);
+ return result;
+ }
+
+ /* Get sam policy handle */
+ result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Get domain policy handle */
+ result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &sid,
+ &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_samr_OpenAlias(pipe_hnd, mem_ctx,
+ &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ alias_rid,
+ &alias_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ result = rpccli_samr_AddAliasMember(pipe_hnd, mem_ctx,
+ &alias_pol,
+ &member_sid);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ done:
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &connect_pol);
+ return result;
+}
+
+static NTSTATUS rpc_group_addmem_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ DOM_SID group_sid;
+ enum lsa_SidType group_type;
+
+ if (argc != 2 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc group addmem <group> <member>\n"
+ " Add a member to a group\n"
+ " group\tGroup to add member to\n"
+ " member\tMember to add to group\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!NT_STATUS_IS_OK(get_sid_from_name(cli, mem_ctx, argv[0],
+ &group_sid, &group_type))) {
+ d_fprintf(stderr, "Could not lookup group name %s\n", argv[0]);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (group_type == SID_NAME_DOM_GRP) {
+ NTSTATUS result = rpc_add_groupmem(pipe_hnd, mem_ctx,
+ &group_sid, argv[1]);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Could not add %s to %s: %s\n",
+ argv[1], argv[0], nt_errstr(result));
+ }
+ return result;
+ }
+
+ if (group_type == SID_NAME_ALIAS) {
+ NTSTATUS result = rpc_add_aliasmem(pipe_hnd, mem_ctx,
+ &group_sid, argv[1]);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Could not add %s to %s: %s\n",
+ argv[1], argv[0], nt_errstr(result));
+ }
+ return result;
+ }
+
+ d_fprintf(stderr, "Can only add members to global or local groups "
+ "which %s is not\n", argv[0]);
+
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+static int rpc_group_addmem(struct net_context *c, int argc, const char **argv)
+{
+ return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id, 0,
+ rpc_group_addmem_internals,
+ argc, argv);
+}
+
+static NTSTATUS rpc_del_groupmem(struct net_context *c,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group_sid,
+ const char *member)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result;
+ uint32 group_rid;
+ POLICY_HND group_pol;
+
+ struct samr_Ids rids, rid_types;
+ struct lsa_String lsa_acct_name;
+
+ DOM_SID sid;
+
+ sid_copy(&sid, group_sid);
+
+ if (!sid_split_rid(&sid, &group_rid))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ /* Get sam policy handle */
+ result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ /* Get domain policy handle */
+ result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &sid,
+ &domain_pol);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ init_lsa_String(&lsa_acct_name, member);
+
+ result = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 1,
+ &lsa_acct_name,
+ &rids,
+ &rid_types);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Could not lookup up group member %s\n", member);
+ goto done;
+ }
+
+ result = rpccli_samr_OpenGroup(pipe_hnd, mem_ctx,
+ &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ group_rid,
+ &group_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_DeleteGroupMember(pipe_hnd, mem_ctx,
+ &group_pol,
+ rids.ids[0]);
+
+ done:
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &connect_pol);
+ return result;
+}
+
+static NTSTATUS rpc_del_aliasmem(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *alias_sid,
+ const char *member)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result;
+ uint32 alias_rid;
+ POLICY_HND alias_pol;
+
+ DOM_SID member_sid;
+ enum lsa_SidType member_type;
+
+ DOM_SID sid;
+
+ sid_copy(&sid, alias_sid);
+
+ if (!sid_split_rid(&sid, &alias_rid))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ result = get_sid_from_name(rpc_pipe_np_smb_conn(pipe_hnd), mem_ctx,
+ member, &member_sid, &member_type);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Could not lookup up group member %s\n", member);
+ return result;
+ }
+
+ /* Get sam policy handle */
+ result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Get domain policy handle */
+ result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &sid,
+ &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_samr_OpenAlias(pipe_hnd, mem_ctx,
+ &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ alias_rid,
+ &alias_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ result = rpccli_samr_DeleteAliasMember(pipe_hnd, mem_ctx,
+ &alias_pol,
+ &member_sid);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ done:
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &connect_pol);
+ return result;
+}
+
+static NTSTATUS rpc_group_delmem_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ DOM_SID group_sid;
+ enum lsa_SidType group_type;
+
+ if (argc != 2 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc group delmem <group> <member>\n"
+ " Delete a member from a group\n"
+ " group\tGroup to delete member from\n"
+ " member\tMember to delete from group\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!NT_STATUS_IS_OK(get_sid_from_name(cli, mem_ctx, argv[0],
+ &group_sid, &group_type))) {
+ d_fprintf(stderr, "Could not lookup group name %s\n", argv[0]);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (group_type == SID_NAME_DOM_GRP) {
+ NTSTATUS result = rpc_del_groupmem(c, pipe_hnd, mem_ctx,
+ &group_sid, argv[1]);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Could not del %s from %s: %s\n",
+ argv[1], argv[0], nt_errstr(result));
+ }
+ return result;
+ }
+
+ if (group_type == SID_NAME_ALIAS) {
+ NTSTATUS result = rpc_del_aliasmem(pipe_hnd, mem_ctx,
+ &group_sid, argv[1]);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Could not del %s from %s: %s\n",
+ argv[1], argv[0], nt_errstr(result));
+ }
+ return result;
+ }
+
+ d_fprintf(stderr, "Can only delete members from global or local groups "
+ "which %s is not\n", argv[0]);
+
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+static int rpc_group_delmem(struct net_context *c, int argc, const char **argv)
+{
+ return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id, 0,
+ rpc_group_delmem_internals,
+ argc, argv);
+}
+
+/**
+ * List groups on a remote RPC server.
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passes through.
+ *
+ * @param domain_sid The domain sid acquired from the remote server.
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS rpc_group_list_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 start_idx=0, max_entries=250, num_entries, i, loop_count = 0;
+ struct samr_SamArray *groups = NULL;
+ bool global = false;
+ bool local = false;
+ bool builtin = false;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc group list [global] [local] [builtin]\n"
+ " List groups on RPC server\n"
+ " global\tList global groups\n"
+ " local\tList local groups\n"
+ " builtin\tList builtin groups\n"
+ " If none of global, local or builtin is "
+ "specified, all three options are considered set\n");
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 0) {
+ global = true;
+ local = true;
+ builtin = true;
+ }
+
+ for (i=0; i<argc; i++) {
+ if (strequal(argv[i], "global"))
+ global = true;
+
+ if (strequal(argv[i], "local"))
+ local = true;
+
+ if (strequal(argv[i], "builtin"))
+ builtin = true;
+ }
+
+ /* Get sam policy handle */
+
+ result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Get domain policy handle */
+
+ result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ CONST_DISCARD(struct dom_sid2 *, domain_sid),
+ &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Query domain groups */
+ if (c->opt_long_list_entries)
+ d_printf("\nGroup name Comment"
+ "\n-----------------------------\n");
+ do {
+ uint32_t max_size, total_size, returned_size;
+ union samr_DispInfo info;
+
+ if (!global) break;
+
+ get_query_dispinfo_params(
+ loop_count, &max_entries, &max_size);
+
+ result = rpccli_samr_QueryDisplayInfo(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 3,
+ start_idx,
+ max_entries,
+ max_size,
+ &total_size,
+ &returned_size,
+ &info);
+ num_entries = info.info3.count;
+ start_idx += info.info3.count;
+
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
+ break;
+
+ for (i = 0; i < num_entries; i++) {
+
+ const char *group = NULL;
+ const char *desc = NULL;
+
+ group = info.info3.entries[i].account_name.string;
+ desc = info.info3.entries[i].description.string;
+
+ if (c->opt_long_list_entries)
+ printf("%-21.21s %-50.50s\n",
+ group, desc);
+ else
+ printf("%s\n", group);
+ }
+ } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
+ /* query domain aliases */
+ start_idx = 0;
+ do {
+ if (!local) break;
+
+ result = rpccli_samr_EnumDomainAliases(pipe_hnd, mem_ctx,
+ &domain_pol,
+ &start_idx,
+ &groups,
+ 0xffff,
+ &num_entries);
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
+ break;
+
+ for (i = 0; i < num_entries; i++) {
+
+ const char *description = NULL;
+
+ if (c->opt_long_list_entries) {
+
+ POLICY_HND alias_pol;
+ union samr_AliasInfo *info = NULL;
+
+ if ((NT_STATUS_IS_OK(rpccli_samr_OpenAlias(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 0x8,
+ groups->entries[i].idx,
+ &alias_pol))) &&
+ (NT_STATUS_IS_OK(rpccli_samr_QueryAliasInfo(pipe_hnd, mem_ctx,
+ &alias_pol,
+ 3,
+ &info))) &&
+ (NT_STATUS_IS_OK(rpccli_samr_Close(pipe_hnd, mem_ctx,
+ &alias_pol)))) {
+ description = info->description.string;
+ }
+ }
+
+ if (description != NULL) {
+ printf("%-21.21s %-50.50s\n",
+ groups->entries[i].name.string,
+ description);
+ } else {
+ printf("%s\n", groups->entries[i].name.string);
+ }
+ }
+ } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
+ /* Get builtin policy handle */
+
+ result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ CONST_DISCARD(struct dom_sid2 *, &global_sid_Builtin),
+ &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+ /* query builtin aliases */
+ start_idx = 0;
+ do {
+ if (!builtin) break;
+
+ result = rpccli_samr_EnumDomainAliases(pipe_hnd, mem_ctx,
+ &domain_pol,
+ &start_idx,
+ &groups,
+ max_entries,
+ &num_entries);
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
+ break;
+
+ for (i = 0; i < num_entries; i++) {
+
+ const char *description = NULL;
+
+ if (c->opt_long_list_entries) {
+
+ POLICY_HND alias_pol;
+ union samr_AliasInfo *info = NULL;
+
+ if ((NT_STATUS_IS_OK(rpccli_samr_OpenAlias(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 0x8,
+ groups->entries[i].idx,
+ &alias_pol))) &&
+ (NT_STATUS_IS_OK(rpccli_samr_QueryAliasInfo(pipe_hnd, mem_ctx,
+ &alias_pol,
+ 3,
+ &info))) &&
+ (NT_STATUS_IS_OK(rpccli_samr_Close(pipe_hnd, mem_ctx,
+ &alias_pol)))) {
+ description = info->description.string;
+ }
+ }
+
+ if (description != NULL) {
+ printf("%-21.21s %-50.50s\n",
+ groups->entries[i].name.string,
+ description);
+ } else {
+ printf("%s\n", groups->entries[i].name.string);
+ }
+ }
+ } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
+
+ done:
+ return result;
+}
+
+static int rpc_group_list(struct net_context *c, int argc, const char **argv)
+{
+ return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id, 0,
+ rpc_group_list_internals,
+ argc, argv);
+}
+
+static NTSTATUS rpc_list_group_members(struct net_context *c,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ const char *domain_name,
+ const DOM_SID *domain_sid,
+ POLICY_HND *domain_pol,
+ uint32 rid)
+{
+ NTSTATUS result;
+ POLICY_HND group_pol;
+ uint32 num_members, *group_rids;
+ int i;
+ struct samr_RidTypeArray *rids = NULL;
+ struct lsa_Strings names;
+ struct samr_Ids types;
+
+ fstring sid_str;
+ sid_to_fstring(sid_str, domain_sid);
+
+ result = rpccli_samr_OpenGroup(pipe_hnd, mem_ctx,
+ domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ rid,
+ &group_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ result = rpccli_samr_QueryGroupMember(pipe_hnd, mem_ctx,
+ &group_pol,
+ &rids);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ num_members = rids->count;
+ group_rids = rids->rids;
+
+ while (num_members > 0) {
+ int this_time = 512;
+
+ if (num_members < this_time)
+ this_time = num_members;
+
+ result = rpccli_samr_LookupRids(pipe_hnd, mem_ctx,
+ domain_pol,
+ this_time,
+ group_rids,
+ &names,
+ &types);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ /* We only have users as members, but make the output
+ the same as the output of alias members */
+
+ for (i = 0; i < this_time; i++) {
+
+ if (c->opt_long_list_entries) {
+ printf("%s-%d %s\\%s %d\n", sid_str,
+ group_rids[i], domain_name,
+ names.names[i].string,
+ SID_NAME_USER);
+ } else {
+ printf("%s\\%s\n", domain_name,
+ names.names[i].string);
+ }
+ }
+
+ num_members -= this_time;
+ group_rids += 512;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS rpc_list_alias_members(struct net_context *c,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol,
+ uint32 rid)
+{
+ NTSTATUS result;
+ struct rpc_pipe_client *lsa_pipe;
+ POLICY_HND alias_pol, lsa_pol;
+ uint32 num_members;
+ DOM_SID *alias_sids;
+ char **domains;
+ char **names;
+ enum lsa_SidType *types;
+ int i;
+ struct lsa_SidArray sid_array;
+
+ result = rpccli_samr_OpenAlias(pipe_hnd, mem_ctx,
+ domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ rid,
+ &alias_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ result = rpccli_samr_GetMembersInAlias(pipe_hnd, mem_ctx,
+ &alias_pol,
+ &sid_array);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Couldn't list alias members\n");
+ return result;
+ }
+
+ num_members = sid_array.num_sids;
+
+ if (num_members == 0) {
+ return NT_STATUS_OK;
+ }
+
+ result = cli_rpc_pipe_open_noauth(rpc_pipe_np_smb_conn(pipe_hnd),
+ &ndr_table_lsarpc.syntax_id,
+ &lsa_pipe);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Couldn't open LSA pipe. Error was %s\n",
+ nt_errstr(result) );
+ return result;
+ }
+
+ result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, true,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Couldn't open LSA policy handle\n");
+ TALLOC_FREE(lsa_pipe);
+ return result;
+ }
+
+ alias_sids = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_members);
+ if (!alias_sids) {
+ d_fprintf(stderr, "Out of memory\n");
+ TALLOC_FREE(lsa_pipe);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<num_members; i++) {
+ sid_copy(&alias_sids[i], sid_array.sids[i].sid);
+ }
+
+ result = rpccli_lsa_lookup_sids(lsa_pipe, mem_ctx, &lsa_pol,
+ num_members, alias_sids,
+ &domains, &names, &types);
+
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
+ d_fprintf(stderr, "Couldn't lookup SIDs\n");
+ TALLOC_FREE(lsa_pipe);
+ return result;
+ }
+
+ for (i = 0; i < num_members; i++) {
+ fstring sid_str;
+ sid_to_fstring(sid_str, &alias_sids[i]);
+
+ if (c->opt_long_list_entries) {
+ printf("%s %s\\%s %d\n", sid_str,
+ domains[i] ? domains[i] : "*unknown*",
+ names[i] ? names[i] : "*unknown*", types[i]);
+ } else {
+ if (domains[i])
+ printf("%s\\%s\n", domains[i], names[i]);
+ else
+ printf("%s\n", sid_str);
+ }
+ }
+
+ TALLOC_FREE(lsa_pipe);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS rpc_group_members_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS result;
+ POLICY_HND connect_pol, domain_pol;
+ struct samr_Ids rids, rid_types;
+ struct lsa_String lsa_acct_name;
+
+ /* Get sam policy handle */
+
+ result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ /* Get domain policy handle */
+
+ result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ CONST_DISCARD(struct dom_sid2 *, domain_sid),
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ init_lsa_String(&lsa_acct_name, argv[0]); /* sure? */
+
+ result = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 1,
+ &lsa_acct_name,
+ &rids,
+ &rid_types);
+
+ if (!NT_STATUS_IS_OK(result)) {
+
+ /* Ok, did not find it in the global sam, try with builtin */
+
+ DOM_SID sid_Builtin;
+
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
+
+ sid_copy(&sid_Builtin, &global_sid_Builtin);
+
+ result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &sid_Builtin,
+ &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Couldn't find group %s\n", argv[0]);
+ return result;
+ }
+
+ result = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 1,
+ &lsa_acct_name,
+ &rids,
+ &rid_types);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Couldn't find group %s\n", argv[0]);
+ return result;
+ }
+ }
+
+ if (rids.count != 1) {
+ d_fprintf(stderr, "Couldn't find group %s\n", argv[0]);
+ return result;
+ }
+
+ if (rid_types.ids[0] == SID_NAME_DOM_GRP) {
+ return rpc_list_group_members(c, pipe_hnd, mem_ctx, domain_name,
+ domain_sid, &domain_pol,
+ rids.ids[0]);
+ }
+
+ if (rid_types.ids[0] == SID_NAME_ALIAS) {
+ return rpc_list_alias_members(c, pipe_hnd, mem_ctx, &domain_pol,
+ rids.ids[0]);
+ }
+
+ return NT_STATUS_NO_SUCH_GROUP;
+}
+
+static int rpc_group_members(struct net_context *c, int argc, const char **argv)
+{
+ if (argc != 1 || c->display_usage) {
+ return rpc_group_usage(c, argc, argv);
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id, 0,
+ rpc_group_members_internals,
+ argc, argv);
+}
+
+static int rpc_group_rename_internals(struct net_context *c, int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct GROUP_INFO_0 g0;
+ uint32_t parm_err;
+
+ if (argc != 2) {
+ d_printf("Usage: 'net rpc group rename group newname'\n");
+ return -1;
+ }
+
+ g0.grpi0_name = argv[1];
+
+ status = NetGroupSetInfo(c->opt_host,
+ argv[0],
+ 0,
+ (uint8_t *)&g0,
+ &parm_err);
+
+ if (status != 0) {
+ d_fprintf(stderr, "Renaming group %s failed with: %s\n",
+ argv[0], libnetapi_get_error_string(c->netapi_ctx,
+ status));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int rpc_group_rename(struct net_context *c, int argc, const char **argv)
+{
+ if (argc != 2 || c->display_usage) {
+ return rpc_group_usage(c, argc, argv);
+ }
+
+ return rpc_group_rename_internals(c, argc, argv);
+}
+
+/**
+ * 'net rpc group' entrypoint.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ **/
+
+int net_rpc_group(struct net_context *c, int argc, const char **argv)
+{
+ NET_API_STATUS status;
+
+ struct functable func[] = {
+ {
+ "add",
+ rpc_group_add,
+ NET_TRANSPORT_RPC,
+ "Create specified group",
+ "net rpc group add\n"
+ " Create specified group"
+ },
+ {
+ "delete",
+ rpc_group_delete,
+ NET_TRANSPORT_RPC,
+ "Delete specified group",
+ "net rpc group delete\n"
+ " Delete specified group"
+ },
+ {
+ "addmem",
+ rpc_group_addmem,
+ NET_TRANSPORT_RPC,
+ "Add member to group",
+ "net rpc group addmem\n"
+ " Add member to group"
+ },
+ {
+ "delmem",
+ rpc_group_delmem,
+ NET_TRANSPORT_RPC,
+ "Remove member from group",
+ "net rpc group delmem\n"
+ " Remove member from group"
+ },
+ {
+ "list",
+ rpc_group_list,
+ NET_TRANSPORT_RPC,
+ "List groups",
+ "net rpc group list\n"
+ " List groups"
+ },
+ {
+ "members",
+ rpc_group_members,
+ NET_TRANSPORT_RPC,
+ "List group members",
+ "net rpc group members\n"
+ " List group members"
+ },
+ {
+ "rename",
+ rpc_group_rename,
+ NET_TRANSPORT_RPC,
+ "Rename group",
+ "net rpc group rename\n"
+ " Rename group"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ status = libnetapi_init(&c->netapi_ctx);
+ if (status != 0) {
+ return -1;
+ }
+ libnetapi_set_username(c->netapi_ctx, c->opt_user_name);
+ libnetapi_set_password(c->netapi_ctx, c->opt_password);
+ if (c->opt_kerberos) {
+ libnetapi_set_use_kerberos(c->netapi_ctx);
+ }
+
+ if (argc == 0) {
+ if (c->display_usage) {
+ d_printf("Usage:\n");
+ d_printf("net rpc group\n"
+ " Alias for net rpc group list global local "
+ "builtin\n");
+ net_display_usage_from_functable(func);
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id, 0,
+ rpc_group_list_internals,
+ argc, argv);
+ }
+
+ return net_run_function(c, argc, argv, "net rpc group", func);
+}
+
+/****************************************************************************/
+
+static int rpc_share_usage(struct net_context *c, int argc, const char **argv)
+{
+ return net_share_usage(c, argc, argv);
+}
+
+/**
+ * Add a share on a remote RPC server.
+ *
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+
+static int rpc_share_add(struct net_context *c, int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ char *sharename;
+ char *path;
+ uint32 type = STYPE_DISKTREE; /* only allow disk shares to be added */
+ uint32 num_users=0, perms=0;
+ char *password=NULL; /* don't allow a share password */
+ struct SHARE_INFO_2 i2;
+ uint32_t parm_error = 0;
+
+ if ((argc < 1) || !strchr(argv[0], '=') || c->display_usage) {
+ return rpc_share_usage(c, argc, argv);
+ }
+
+ if ((sharename = talloc_strdup(c, argv[0])) == NULL) {
+ return -1;
+ }
+
+ path = strchr(sharename, '=');
+ if (!path) {
+ return -1;
+ }
+
+ *path++ = '\0';
+
+ i2.shi2_netname = sharename;
+ i2.shi2_type = type;
+ i2.shi2_remark = c->opt_comment;
+ i2.shi2_permissions = perms;
+ i2.shi2_max_uses = c->opt_maxusers;
+ i2.shi2_current_uses = num_users;
+ i2.shi2_path = path;
+ i2.shi2_passwd = password;
+
+ status = NetShareAdd(c->opt_host,
+ 2,
+ (uint8_t *)&i2,
+ &parm_error);
+ if (status != 0) {
+ printf("NetShareAdd failed with: %s\n",
+ libnetapi_get_error_string(c->netapi_ctx, status));
+ }
+
+ return status;
+}
+
+/**
+ * Delete a share on a remote RPC server.
+ *
+ * @param domain_sid The domain sid acquired from the remote server.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+static int rpc_share_delete(struct net_context *c, int argc, const char **argv)
+{
+ if (argc < 1 || c->display_usage) {
+ return rpc_share_usage(c, argc, argv);
+ }
+
+ return NetShareDel(c->opt_host, argv[0], 0);
+}
+
+/**
+ * Formatted print of share info
+ *
+ * @param r pointer to SHARE_INFO_1 to format
+ **/
+
+static void display_share_info_1(struct net_context *c,
+ struct SHARE_INFO_1 *r)
+{
+ if (c->opt_long_list_entries) {
+ d_printf("%-12s %-8.8s %-50s\n",
+ r->shi1_netname,
+ share_type[r->shi1_type & ~(STYPE_TEMPORARY|STYPE_HIDDEN)],
+ r->shi1_remark);
+ } else {
+ d_printf("%s\n", r->shi1_netname);
+ }
+}
+
+static WERROR get_share_info(struct net_context *c,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ uint32 level,
+ int argc,
+ const char **argv,
+ struct srvsvc_NetShareInfoCtr *info_ctr)
+{
+ WERROR result;
+ NTSTATUS status;
+ union srvsvc_NetShareInfo info;
+
+ /* no specific share requested, enumerate all */
+ if (argc == 0) {
+
+ uint32_t preferred_len = 0xffffffff;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+
+ info_ctr->level = level;
+
+ status = rpccli_srvsvc_NetShareEnumAll(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ info_ctr,
+ preferred_len,
+ &total_entries,
+ &resume_handle,
+ &result);
+ return result;
+ }
+
+ /* request just one share */
+ status = rpccli_srvsvc_NetShareGetInfo(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ argv[0],
+ level,
+ &info,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ goto done;
+ }
+
+ /* construct ctr */
+ ZERO_STRUCTP(info_ctr);
+
+ info_ctr->level = level;
+
+ switch (level) {
+ case 1:
+ {
+ struct srvsvc_NetShareCtr1 *ctr1;
+
+ ctr1 = TALLOC_ZERO_P(mem_ctx, struct srvsvc_NetShareCtr1);
+ W_ERROR_HAVE_NO_MEMORY(ctr1);
+
+ ctr1->count = 1;
+ ctr1->array = info.info1;
+
+ info_ctr->ctr.ctr1 = ctr1;
+ }
+ case 2:
+ {
+ struct srvsvc_NetShareCtr2 *ctr2;
+
+ ctr2 = TALLOC_ZERO_P(mem_ctx, struct srvsvc_NetShareCtr2);
+ W_ERROR_HAVE_NO_MEMORY(ctr2);
+
+ ctr2->count = 1;
+ ctr2->array = info.info2;
+
+ info_ctr->ctr.ctr2 = ctr2;
+ }
+ case 502:
+ {
+ struct srvsvc_NetShareCtr502 *ctr502;
+
+ ctr502 = TALLOC_ZERO_P(mem_ctx, struct srvsvc_NetShareCtr502);
+ W_ERROR_HAVE_NO_MEMORY(ctr502);
+
+ ctr502->count = 1;
+ ctr502->array = info.info502;
+
+ info_ctr->ctr.ctr502 = ctr502;
+ }
+ } /* switch */
+done:
+ return result;
+}
+
+/***
+ * 'net rpc share list' entrypoint.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ **/
+static int rpc_share_list(struct net_context *c, int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ struct SHARE_INFO_1 *i1 = NULL;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ uint32_t i, level = 1;
+
+ if (c->display_usage) {
+ d_printf("Usage\n"
+ "net rpc share list\n"
+ " List shares on remote server\n");
+ return 0;
+ }
+
+ status = NetShareEnum(c->opt_host,
+ level,
+ (uint8_t **)&i1,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries,
+ &resume_handle);
+ if (status != 0) {
+ goto done;
+ }
+
+ /* Display results */
+
+ if (c->opt_long_list_entries) {
+ d_printf(
+ "\nEnumerating shared resources (exports) on remote server:\n\n"
+ "\nShare name Type Description\n"
+ "---------- ---- -----------\n");
+ }
+ for (i = 0; i < entries_read; i++)
+ display_share_info_1(c, &i1[i]);
+ done:
+ return status;
+}
+
+static bool check_share_availability(struct cli_state *cli, const char *netname)
+{
+ if (!cli_send_tconX(cli, netname, "A:", "", 0)) {
+ d_printf("skipping [%s]: not a file share.\n", netname);
+ return false;
+ }
+
+ if (!cli_tdis(cli))
+ return false;
+
+ return true;
+}
+
+static bool check_share_sanity(struct net_context *c, struct cli_state *cli,
+ const char *netname, uint32 type)
+{
+ /* only support disk shares */
+ if (! ( type == STYPE_DISKTREE || type == (STYPE_DISKTREE | STYPE_HIDDEN)) ) {
+ printf("share [%s] is not a diskshare (type: %x)\n", netname, type);
+ return false;
+ }
+
+ /* skip builtin shares */
+ /* FIXME: should print$ be added too ? */
+ if (strequal(netname,"IPC$") || strequal(netname,"ADMIN$") ||
+ strequal(netname,"global"))
+ return false;
+
+ if (c->opt_exclude && in_list(netname, c->opt_exclude, false)) {
+ printf("excluding [%s]\n", netname);
+ return false;
+ }
+
+ return check_share_availability(cli, netname);
+}
+
+/**
+ * Migrate shares from a remote RPC server to the local RPC server.
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param domain_sid The domain sid acquired from the remote server.
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS rpc_share_migrate_shares_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ WERROR result;
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ struct srvsvc_NetShareInfoCtr ctr_src;
+ uint32 i;
+ struct rpc_pipe_client *srvsvc_pipe = NULL;
+ struct cli_state *cli_dst = NULL;
+ uint32 level = 502; /* includes secdesc */
+ uint32_t parm_error = 0;
+
+ result = get_share_info(c, pipe_hnd, mem_ctx, level, argc, argv,
+ &ctr_src);
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ /* connect destination PI_SRVSVC */
+ nt_status = connect_dst_pipe(c, &cli_dst, &srvsvc_pipe,
+ &ndr_table_srvsvc.syntax_id);
+ if (!NT_STATUS_IS_OK(nt_status))
+ return nt_status;
+
+
+ for (i = 0; i < ctr_src.ctr.ctr502->count; i++) {
+
+ union srvsvc_NetShareInfo info;
+ struct srvsvc_NetShareInfo502 info502 =
+ ctr_src.ctr.ctr502->array[i];
+
+ /* reset error-code */
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+
+ if (!check_share_sanity(c, cli, info502.name, info502.type))
+ continue;
+
+ /* finally add the share on the dst server */
+
+ printf("migrating: [%s], path: %s, comment: %s, without share-ACLs\n",
+ info502.name, info502.path, info502.comment);
+
+ info.info502 = &info502;
+
+ nt_status = rpccli_srvsvc_NetShareAdd(srvsvc_pipe, mem_ctx,
+ srvsvc_pipe->desthost,
+ 502,
+ &info,
+ &parm_error,
+ &result);
+
+ if (W_ERROR_V(result) == W_ERROR_V(WERR_ALREADY_EXISTS)) {
+ printf(" [%s] does already exist\n",
+ info502.name);
+ continue;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status) || !W_ERROR_IS_OK(result)) {
+ printf("cannot add share: %s\n", dos_errstr(result));
+ goto done;
+ }
+
+ }
+
+ nt_status = NT_STATUS_OK;
+
+done:
+ if (cli_dst) {
+ cli_shutdown(cli_dst);
+ }
+
+ return nt_status;
+
+}
+
+/**
+ * Migrate shares from a RPC server to another.
+ *
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+static int rpc_share_migrate_shares(struct net_context *c, int argc,
+ const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc share migrate shares\n"
+ " Migrate shares to local server\n");
+ return 0;
+ }
+
+ if (!c->opt_host) {
+ printf("no server to migrate\n");
+ return -1;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_srvsvc.syntax_id, 0,
+ rpc_share_migrate_shares_internals,
+ argc, argv);
+}
+
+/**
+ * Copy a file/dir
+ *
+ * @param f file_info
+ * @param mask current search mask
+ * @param state arg-pointer
+ *
+ **/
+static void copy_fn(const char *mnt, file_info *f,
+ const char *mask, void *state)
+{
+ static NTSTATUS nt_status;
+ static struct copy_clistate *local_state;
+ static fstring filename, new_mask;
+ fstring dir;
+ char *old_dir;
+ struct net_context *c;
+
+ local_state = (struct copy_clistate *)state;
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+
+ c = local_state->c;
+
+ if (strequal(f->name, ".") || strequal(f->name, ".."))
+ return;
+
+ DEBUG(3,("got mask: %s, name: %s\n", mask, f->name));
+
+ /* DIRECTORY */
+ if (f->mode & aDIR) {
+
+ DEBUG(3,("got dir: %s\n", f->name));
+
+ fstrcpy(dir, local_state->cwd);
+ fstrcat(dir, "\\");
+ fstrcat(dir, f->name);
+
+ switch (net_mode_share)
+ {
+ case NET_MODE_SHARE_MIGRATE:
+ /* create that directory */
+ nt_status = net_copy_file(c, local_state->mem_ctx,
+ local_state->cli_share_src,
+ local_state->cli_share_dst,
+ dir, dir,
+ c->opt_acls? true : false,
+ c->opt_attrs? true : false,
+ c->opt_timestamps? true:false,
+ false);
+ break;
+ default:
+ d_fprintf(stderr, "Unsupported mode %d\n", net_mode_share);
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status))
+ printf("could not handle dir %s: %s\n",
+ dir, nt_errstr(nt_status));
+
+ /* search below that directory */
+ fstrcpy(new_mask, dir);
+ fstrcat(new_mask, "\\*");
+
+ old_dir = local_state->cwd;
+ local_state->cwd = dir;
+ if (!sync_files(local_state, new_mask))
+ printf("could not handle files\n");
+ local_state->cwd = old_dir;
+
+ return;
+ }
+
+
+ /* FILE */
+ fstrcpy(filename, local_state->cwd);
+ fstrcat(filename, "\\");
+ fstrcat(filename, f->name);
+
+ DEBUG(3,("got file: %s\n", filename));
+
+ switch (net_mode_share)
+ {
+ case NET_MODE_SHARE_MIGRATE:
+ nt_status = net_copy_file(c, local_state->mem_ctx,
+ local_state->cli_share_src,
+ local_state->cli_share_dst,
+ filename, filename,
+ c->opt_acls? true : false,
+ c->opt_attrs? true : false,
+ c->opt_timestamps? true: false,
+ true);
+ break;
+ default:
+ d_fprintf(stderr, "Unsupported file mode %d\n", net_mode_share);
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status))
+ printf("could not handle file %s: %s\n",
+ filename, nt_errstr(nt_status));
+
+}
+
+/**
+ * sync files, can be called recursivly to list files
+ * and then call copy_fn for each file
+ *
+ * @param cp_clistate pointer to the copy_clistate we work with
+ * @param mask the current search mask
+ *
+ * @return Boolean result
+ **/
+static bool sync_files(struct copy_clistate *cp_clistate, const char *mask)
+{
+ struct cli_state *targetcli;
+ char *targetpath = NULL;
+
+ DEBUG(3,("calling cli_list with mask: %s\n", mask));
+
+ if ( !cli_resolve_path(talloc_tos(), "", cp_clistate->cli_share_src,
+ mask, &targetcli, &targetpath ) ) {
+ d_fprintf(stderr, "cli_resolve_path %s failed with error: %s\n",
+ mask, cli_errstr(cp_clistate->cli_share_src));
+ return false;
+ }
+
+ if (cli_list(targetcli, targetpath, cp_clistate->attribute, copy_fn, cp_clistate) == -1) {
+ d_fprintf(stderr, "listing %s failed with error: %s\n",
+ mask, cli_errstr(targetcli));
+ return false;
+ }
+
+ return true;
+}
+
+
+/**
+ * Set the top level directory permissions before we do any further copies.
+ * Should set up ACL inheritance.
+ **/
+
+bool copy_top_level_perms(struct net_context *c,
+ struct copy_clistate *cp_clistate,
+ const char *sharename)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+
+ switch (net_mode_share) {
+ case NET_MODE_SHARE_MIGRATE:
+ DEBUG(3,("calling net_copy_fileattr for '.' directory in share %s\n", sharename));
+ nt_status = net_copy_fileattr(c,
+ cp_clistate->mem_ctx,
+ cp_clistate->cli_share_src,
+ cp_clistate->cli_share_dst,
+ "\\", "\\",
+ c->opt_acls? true : false,
+ c->opt_attrs? true : false,
+ c->opt_timestamps? true: false,
+ false);
+ break;
+ default:
+ d_fprintf(stderr, "Unsupported mode %d\n", net_mode_share);
+ break;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ printf("Could handle directory attributes for top level directory of share %s. Error %s\n",
+ sharename, nt_errstr(nt_status));
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Sync all files inside a remote share to another share (over smb).
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param domain_sid The domain sid acquired from the remote server.
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS rpc_share_migrate_files_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ WERROR result;
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ struct srvsvc_NetShareInfoCtr ctr_src;
+ uint32 i;
+ uint32 level = 502;
+ struct copy_clistate cp_clistate;
+ bool got_src_share = false;
+ bool got_dst_share = false;
+ const char *mask = "\\*";
+ char *dst = NULL;
+
+ dst = SMB_STRDUP(c->opt_destination?c->opt_destination:"127.0.0.1");
+ if (dst == NULL) {
+ nt_status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ result = get_share_info(c, pipe_hnd, mem_ctx, level, argc, argv,
+ &ctr_src);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ for (i = 0; i < ctr_src.ctr.ctr502->count; i++) {
+
+ struct srvsvc_NetShareInfo502 info502 =
+ ctr_src.ctr.ctr502->array[i];
+
+ if (!check_share_sanity(c, cli, info502.name, info502.type))
+ continue;
+
+ /* one might not want to mirror whole discs :) */
+ if (strequal(info502.name, "print$") || info502.name[1] == '$') {
+ d_printf("skipping [%s]: builtin/hidden share\n", info502.name);
+ continue;
+ }
+
+ switch (net_mode_share)
+ {
+ case NET_MODE_SHARE_MIGRATE:
+ printf("syncing");
+ break;
+ default:
+ d_fprintf(stderr, "Unsupported mode %d\n", net_mode_share);
+ break;
+ }
+ printf(" [%s] files and directories %s ACLs, %s DOS Attributes %s\n",
+ info502.name,
+ c->opt_acls ? "including" : "without",
+ c->opt_attrs ? "including" : "without",
+ c->opt_timestamps ? "(preserving timestamps)" : "");
+
+ cp_clistate.mem_ctx = mem_ctx;
+ cp_clistate.cli_share_src = NULL;
+ cp_clistate.cli_share_dst = NULL;
+ cp_clistate.cwd = NULL;
+ cp_clistate.attribute = aSYSTEM | aHIDDEN | aDIR;
+ cp_clistate.c = c;
+
+ /* open share source */
+ nt_status = connect_to_service(c, &cp_clistate.cli_share_src,
+ &cli->dest_ss, cli->desthost,
+ info502.name, "A:");
+ if (!NT_STATUS_IS_OK(nt_status))
+ goto done;
+
+ got_src_share = true;
+
+ if (net_mode_share == NET_MODE_SHARE_MIGRATE) {
+ /* open share destination */
+ nt_status = connect_to_service(c, &cp_clistate.cli_share_dst,
+ NULL, dst, info502.name, "A:");
+ if (!NT_STATUS_IS_OK(nt_status))
+ goto done;
+
+ got_dst_share = true;
+ }
+
+ if (!copy_top_level_perms(c, &cp_clistate, info502.name)) {
+ d_fprintf(stderr, "Could not handle the top level directory permissions for the share: %s\n", info502.name);
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!sync_files(&cp_clistate, mask)) {
+ d_fprintf(stderr, "could not handle files for share: %s\n", info502.name);
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ }
+
+ nt_status = NT_STATUS_OK;
+
+done:
+
+ if (got_src_share)
+ cli_shutdown(cp_clistate.cli_share_src);
+
+ if (got_dst_share)
+ cli_shutdown(cp_clistate.cli_share_dst);
+
+ SAFE_FREE(dst);
+ return nt_status;
+
+}
+
+static int rpc_share_migrate_files(struct net_context *c, int argc, const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net share migrate files\n"
+ " Migrate files to local server\n");
+ return 0;
+ }
+
+ if (!c->opt_host) {
+ d_printf("no server to migrate\n");
+ return -1;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_srvsvc.syntax_id, 0,
+ rpc_share_migrate_files_internals,
+ argc, argv);
+}
+
+/**
+ * Migrate share-ACLs from a remote RPC server to the local RPC server.
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param domain_sid The domain sid acquired from the remote server.
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS rpc_share_migrate_security_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ WERROR result;
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ struct srvsvc_NetShareInfoCtr ctr_src;
+ union srvsvc_NetShareInfo info;
+ uint32 i;
+ struct rpc_pipe_client *srvsvc_pipe = NULL;
+ struct cli_state *cli_dst = NULL;
+ uint32 level = 502; /* includes secdesc */
+ uint32_t parm_error = 0;
+
+ result = get_share_info(c, pipe_hnd, mem_ctx, level, argc, argv,
+ &ctr_src);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ /* connect destination PI_SRVSVC */
+ nt_status = connect_dst_pipe(c, &cli_dst, &srvsvc_pipe,
+ &ndr_table_srvsvc.syntax_id);
+ if (!NT_STATUS_IS_OK(nt_status))
+ return nt_status;
+
+
+ for (i = 0; i < ctr_src.ctr.ctr502->count; i++) {
+
+ struct srvsvc_NetShareInfo502 info502 =
+ ctr_src.ctr.ctr502->array[i];
+
+ /* reset error-code */
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+
+ if (!check_share_sanity(c, cli, info502.name, info502.type))
+ continue;
+
+ printf("migrating: [%s], path: %s, comment: %s, including share-ACLs\n",
+ info502.name, info502.path, info502.comment);
+
+ if (c->opt_verbose)
+ display_sec_desc(info502.sd_buf.sd);
+
+ /* FIXME: shouldn't we be able to just set the security descriptor ? */
+ info.info502 = &info502;
+
+ /* finally modify the share on the dst server */
+ nt_status = rpccli_srvsvc_NetShareSetInfo(srvsvc_pipe, mem_ctx,
+ srvsvc_pipe->desthost,
+ info502.name,
+ level,
+ &info,
+ &parm_error,
+ &result);
+ if (!NT_STATUS_IS_OK(nt_status) || !W_ERROR_IS_OK(result)) {
+ printf("cannot set share-acl: %s\n", dos_errstr(result));
+ goto done;
+ }
+
+ }
+
+ nt_status = NT_STATUS_OK;
+
+done:
+ if (cli_dst) {
+ cli_shutdown(cli_dst);
+ }
+
+ return nt_status;
+
+}
+
+/**
+ * Migrate share-acls from a RPC server to another.
+ *
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+static int rpc_share_migrate_security(struct net_context *c, int argc,
+ const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc share migrate security\n"
+ " Migrate share-acls to local server\n");
+ return 0;
+ }
+
+ if (!c->opt_host) {
+ d_printf("no server to migrate\n");
+ return -1;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_srvsvc.syntax_id, 0,
+ rpc_share_migrate_security_internals,
+ argc, argv);
+}
+
+/**
+ * Migrate shares (including share-definitions, share-acls and files with acls/attrs)
+ * from one server to another.
+ *
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ *
+ **/
+static int rpc_share_migrate_all(struct net_context *c, int argc,
+ const char **argv)
+{
+ int ret;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc share migrate all\n"
+ " Migrates shares including all share settings\n");
+ return 0;
+ }
+
+ if (!c->opt_host) {
+ d_printf("no server to migrate\n");
+ return -1;
+ }
+
+ /* order is important. we don't want to be locked out by the share-acl
+ * before copying files - gd */
+
+ ret = run_rpc_command(c, NULL, &ndr_table_srvsvc.syntax_id, 0,
+ rpc_share_migrate_shares_internals, argc, argv);
+ if (ret)
+ return ret;
+
+ ret = run_rpc_command(c, NULL, &ndr_table_srvsvc.syntax_id, 0,
+ rpc_share_migrate_files_internals, argc, argv);
+ if (ret)
+ return ret;
+
+ return run_rpc_command(c, NULL, &ndr_table_srvsvc.syntax_id, 0,
+ rpc_share_migrate_security_internals, argc,
+ argv);
+}
+
+
+/**
+ * 'net rpc share migrate' entrypoint.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ **/
+static int rpc_share_migrate(struct net_context *c, int argc, const char **argv)
+{
+
+ struct functable func[] = {
+ {
+ "all",
+ rpc_share_migrate_all,
+ NET_TRANSPORT_RPC,
+ "Migrate shares from remote to local server",
+ "net rpc share migrate all\n"
+ " Migrate shares from remote to local server"
+ },
+ {
+ "files",
+ rpc_share_migrate_files,
+ NET_TRANSPORT_RPC,
+ "Migrate files from remote to local server",
+ "net rpc share migrate files\n"
+ " Migrate files from remote to local server"
+ },
+ {
+ "security",
+ rpc_share_migrate_security,
+ NET_TRANSPORT_RPC,
+ "Migrate share-ACLs from remote to local server",
+ "net rpc share migrate security\n"
+ " Migrate share-ACLs from remote to local server"
+ },
+ {
+ "shares",
+ rpc_share_migrate_shares,
+ NET_TRANSPORT_RPC,
+ "Migrate shares from remote to local server",
+ "net rpc share migrate shares\n"
+ " Migrate shares from remote to local server"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ net_mode_share = NET_MODE_SHARE_MIGRATE;
+
+ return net_run_function(c, argc, argv, "net rpc share migrate", func);
+}
+
+struct full_alias {
+ DOM_SID sid;
+ uint32 num_members;
+ DOM_SID *members;
+};
+
+static int num_server_aliases;
+static struct full_alias *server_aliases;
+
+/*
+ * Add an alias to the static list.
+ */
+static void push_alias(TALLOC_CTX *mem_ctx, struct full_alias *alias)
+{
+ if (server_aliases == NULL)
+ server_aliases = SMB_MALLOC_ARRAY(struct full_alias, 100);
+
+ server_aliases[num_server_aliases] = *alias;
+ num_server_aliases += 1;
+}
+
+/*
+ * For a specific domain on the server, fetch all the aliases
+ * and their members. Add all of them to the server_aliases.
+ */
+
+static NTSTATUS rpc_fetch_domain_aliases(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *connect_pol,
+ const DOM_SID *domain_sid)
+{
+ uint32 start_idx, max_entries, num_entries, i;
+ struct samr_SamArray *groups = NULL;
+ NTSTATUS result;
+ POLICY_HND domain_pol;
+
+ /* Get domain policy handle */
+
+ result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ CONST_DISCARD(struct dom_sid2 *, domain_sid),
+ &domain_pol);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ start_idx = 0;
+ max_entries = 250;
+
+ do {
+ result = rpccli_samr_EnumDomainAliases(pipe_hnd, mem_ctx,
+ &domain_pol,
+ &start_idx,
+ &groups,
+ max_entries,
+ &num_entries);
+ for (i = 0; i < num_entries; i++) {
+
+ POLICY_HND alias_pol;
+ struct full_alias alias;
+ struct lsa_SidArray sid_array;
+ int j;
+
+ result = rpccli_samr_OpenAlias(pipe_hnd, mem_ctx,
+ &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ groups->entries[i].idx,
+ &alias_pol);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpccli_samr_GetMembersInAlias(pipe_hnd, mem_ctx,
+ &alias_pol,
+ &sid_array);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ alias.num_members = sid_array.num_sids;
+
+ result = rpccli_samr_Close(pipe_hnd, mem_ctx, &alias_pol);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ alias.members = NULL;
+
+ if (alias.num_members > 0) {
+ alias.members = SMB_MALLOC_ARRAY(DOM_SID, alias.num_members);
+
+ for (j = 0; j < alias.num_members; j++)
+ sid_copy(&alias.members[j],
+ sid_array.sids[j].sid);
+ }
+
+ sid_copy(&alias.sid, domain_sid);
+ sid_append_rid(&alias.sid, groups->entries[i].idx);
+
+ push_alias(mem_ctx, &alias);
+ }
+ } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
+
+ result = NT_STATUS_OK;
+
+ done:
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
+
+ return result;
+}
+
+/*
+ * Dump server_aliases as names for debugging purposes.
+ */
+
+static NTSTATUS rpc_aliaslist_dump(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ int i;
+ NTSTATUS result;
+ POLICY_HND lsa_pol;
+
+ result = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &lsa_pol);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ for (i=0; i<num_server_aliases; i++) {
+ char **names;
+ char **domains;
+ enum lsa_SidType *types;
+ int j;
+
+ struct full_alias *alias = &server_aliases[i];
+
+ result = rpccli_lsa_lookup_sids(pipe_hnd, mem_ctx, &lsa_pol, 1,
+ &alias->sid,
+ &domains, &names, &types);
+ if (!NT_STATUS_IS_OK(result))
+ continue;
+
+ DEBUG(1, ("%s\\%s %d: ", domains[0], names[0], types[0]));
+
+ if (alias->num_members == 0) {
+ DEBUG(1, ("\n"));
+ continue;
+ }
+
+ result = rpccli_lsa_lookup_sids(pipe_hnd, mem_ctx, &lsa_pol,
+ alias->num_members,
+ alias->members,
+ &domains, &names, &types);
+
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED))
+ continue;
+
+ for (j=0; j<alias->num_members; j++)
+ DEBUG(1, ("%s\\%s (%d); ",
+ domains[j] ? domains[j] : "*unknown*",
+ names[j] ? names[j] : "*unknown*",types[j]));
+ DEBUG(1, ("\n"));
+ }
+
+ rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * Fetch a list of all server aliases and their members into
+ * server_aliases.
+ */
+
+static NTSTATUS rpc_aliaslist_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS result;
+ POLICY_HND connect_pol;
+
+ result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpc_fetch_domain_aliases(pipe_hnd, mem_ctx, &connect_pol,
+ &global_sid_Builtin);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = rpc_fetch_domain_aliases(pipe_hnd, mem_ctx, &connect_pol,
+ domain_sid);
+
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &connect_pol);
+ done:
+ return result;
+}
+
+static void init_user_token(NT_USER_TOKEN *token, DOM_SID *user_sid)
+{
+ token->num_sids = 4;
+
+ if (!(token->user_sids = SMB_MALLOC_ARRAY(DOM_SID, 4))) {
+ d_fprintf(stderr, "malloc failed\n");
+ token->num_sids = 0;
+ return;
+ }
+
+ token->user_sids[0] = *user_sid;
+ sid_copy(&token->user_sids[1], &global_sid_World);
+ sid_copy(&token->user_sids[2], &global_sid_Network);
+ sid_copy(&token->user_sids[3], &global_sid_Authenticated_Users);
+}
+
+static void free_user_token(NT_USER_TOKEN *token)
+{
+ SAFE_FREE(token->user_sids);
+}
+
+static bool is_sid_in_token(NT_USER_TOKEN *token, DOM_SID *sid)
+{
+ int i;
+
+ for (i=0; i<token->num_sids; i++) {
+ if (sid_compare(sid, &token->user_sids[i]) == 0)
+ return true;
+ }
+ return false;
+}
+
+static void add_sid_to_token(NT_USER_TOKEN *token, DOM_SID *sid)
+{
+ if (is_sid_in_token(token, sid))
+ return;
+
+ token->user_sids = SMB_REALLOC_ARRAY(token->user_sids, DOM_SID, token->num_sids+1);
+ if (!token->user_sids) {
+ return;
+ }
+
+ sid_copy(&token->user_sids[token->num_sids], sid);
+
+ token->num_sids += 1;
+}
+
+struct user_token {
+ fstring name;
+ NT_USER_TOKEN token;
+};
+
+static void dump_user_token(struct user_token *token)
+{
+ int i;
+
+ d_printf("%s\n", token->name);
+
+ for (i=0; i<token->token.num_sids; i++) {
+ d_printf(" %s\n", sid_string_tos(&token->token.user_sids[i]));
+ }
+}
+
+static bool is_alias_member(DOM_SID *sid, struct full_alias *alias)
+{
+ int i;
+
+ for (i=0; i<alias->num_members; i++) {
+ if (sid_compare(sid, &alias->members[i]) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+static void collect_sid_memberships(NT_USER_TOKEN *token, DOM_SID sid)
+{
+ int i;
+
+ for (i=0; i<num_server_aliases; i++) {
+ if (is_alias_member(&sid, &server_aliases[i]))
+ add_sid_to_token(token, &server_aliases[i].sid);
+ }
+}
+
+/*
+ * We got a user token with all the SIDs we can know about without asking the
+ * server directly. These are the user and domain group sids. All of these can
+ * be members of aliases. So scan the list of aliases for each of the SIDs and
+ * add them to the token.
+ */
+
+static void collect_alias_memberships(NT_USER_TOKEN *token)
+{
+ int num_global_sids = token->num_sids;
+ int i;
+
+ for (i=0; i<num_global_sids; i++) {
+ collect_sid_memberships(token, token->user_sids[i]);
+ }
+}
+
+static bool get_user_sids(const char *domain, const char *user, NT_USER_TOKEN *token)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ enum wbcSidType type;
+ fstring full_name;
+ struct wbcDomainSid wsid;
+ char *sid_str = NULL;
+ DOM_SID user_sid;
+ uint32_t num_groups;
+ gid_t *groups = NULL;
+ uint32_t i;
+
+ fstr_sprintf(full_name, "%s%c%s",
+ domain, *lp_winbind_separator(), user);
+
+ /* First let's find out the user sid */
+
+ wbc_status = wbcLookupName(domain, user, &wsid, &type);
+
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ DEBUG(1, ("winbind could not find %s: %s\n",
+ full_name, wbcErrorString(wbc_status)));
+ return false;
+ }
+
+ wbc_status = wbcSidToString(&wsid, &sid_str);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return false;
+ }
+
+ if (type != SID_NAME_USER) {
+ wbcFreeMemory(sid_str);
+ DEBUG(1, ("%s is not a user\n", full_name));
+ return false;
+ }
+
+ string_to_sid(&user_sid, sid_str);
+ wbcFreeMemory(sid_str);
+ sid_str = NULL;
+
+ init_user_token(token, &user_sid);
+
+ /* And now the groups winbind knows about */
+
+ wbc_status = wbcGetGroups(full_name, &num_groups, &groups);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ DEBUG(1, ("winbind could not get groups of %s: %s\n",
+ full_name, wbcErrorString(wbc_status)));
+ return false;
+ }
+
+ for (i = 0; i < num_groups; i++) {
+ gid_t gid = groups[i];
+ DOM_SID sid;
+
+ wbc_status = wbcGidToSid(gid, &wsid);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ DEBUG(1, ("winbind could not find SID of gid %d: %s\n",
+ gid, wbcErrorString(wbc_status)));
+ wbcFreeMemory(groups);
+ return false;
+ }
+
+ wbc_status = wbcSidToString(&wsid, &sid_str);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ wbcFreeMemory(groups);
+ return false;
+ }
+
+ DEBUG(3, (" %s\n", sid_str));
+
+ string_to_sid(&sid, sid_str);
+ wbcFreeMemory(sid_str);
+ sid_str = NULL;
+
+ add_sid_to_token(token, &sid);
+ }
+ wbcFreeMemory(groups);
+
+ return true;
+}
+
+/**
+ * Get a list of all user tokens we want to look at
+ **/
+
+static bool get_user_tokens(struct net_context *c, int *num_tokens,
+ struct user_token **user_tokens)
+{
+ wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ uint32_t i, num_users;
+ const char **users;
+ struct user_token *result;
+ TALLOC_CTX *frame = NULL;
+
+ if (lp_winbind_use_default_domain() &&
+ (c->opt_target_workgroup == NULL)) {
+ d_fprintf(stderr, "winbind use default domain = yes set, "
+ "please specify a workgroup\n");
+ return false;
+ }
+
+ /* Send request to winbind daemon */
+
+ wbc_status = wbcListUsers(NULL, &num_users, &users);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ DEBUG(1, ("winbind could not list users: %s\n",
+ wbcErrorString(wbc_status)));
+ return false;
+ }
+
+ result = SMB_MALLOC_ARRAY(struct user_token, num_users);
+
+ if (result == NULL) {
+ DEBUG(1, ("Could not malloc sid array\n"));
+ wbcFreeMemory(users);
+ return false;
+ }
+
+ frame = talloc_stackframe();
+ for (i=0; i < num_users; i++) {
+ fstring domain, user;
+ char *p;
+
+ fstrcpy(result[i].name, users[i]);
+
+ p = strchr(users[i], *lp_winbind_separator());
+
+ DEBUG(3, ("%s\n", users[i]));
+
+ if (p == NULL) {
+ fstrcpy(domain, c->opt_target_workgroup);
+ fstrcpy(user, users[i]);
+ } else {
+ *p++ = '\0';
+ fstrcpy(domain, users[i]);
+ strupper_m(domain);
+ fstrcpy(user, p);
+ }
+
+ get_user_sids(domain, user, &(result[i].token));
+ i+=1;
+ }
+ TALLOC_FREE(frame);
+ wbcFreeMemory(users);
+
+ *num_tokens = num_users;
+ *user_tokens = result;
+
+ return true;
+}
+
+static bool get_user_tokens_from_file(FILE *f,
+ int *num_tokens,
+ struct user_token **tokens)
+{
+ struct user_token *token = NULL;
+
+ while (!feof(f)) {
+ fstring line;
+
+ if (fgets(line, sizeof(line)-1, f) == NULL) {
+ return true;
+ }
+
+ if (line[strlen(line)-1] == '\n')
+ line[strlen(line)-1] = '\0';
+
+ if (line[0] == ' ') {
+ /* We have a SID */
+
+ DOM_SID sid;
+ string_to_sid(&sid, &line[1]);
+
+ if (token == NULL) {
+ DEBUG(0, ("File does not begin with username"));
+ return false;
+ }
+
+ add_sid_to_token(&token->token, &sid);
+ continue;
+ }
+
+ /* And a new user... */
+
+ *num_tokens += 1;
+ *tokens = SMB_REALLOC_ARRAY(*tokens, struct user_token, *num_tokens);
+ if (*tokens == NULL) {
+ DEBUG(0, ("Could not realloc tokens\n"));
+ return false;
+ }
+
+ token = &((*tokens)[*num_tokens-1]);
+
+ fstrcpy(token->name, line);
+ token->token.num_sids = 0;
+ token->token.user_sids = NULL;
+ continue;
+ }
+
+ return false;
+}
+
+
+/*
+ * Show the list of all users that have access to a share
+ */
+
+static void show_userlist(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ const char *netname,
+ int num_tokens,
+ struct user_token *tokens)
+{
+ int fnum;
+ SEC_DESC *share_sd = NULL;
+ SEC_DESC *root_sd = NULL;
+ struct cli_state *cli = rpc_pipe_np_smb_conn(pipe_hnd);
+ int i;
+ union srvsvc_NetShareInfo info;
+ WERROR result;
+ NTSTATUS status;
+ uint16 cnum;
+
+ status = rpccli_srvsvc_NetShareGetInfo(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ netname,
+ 502,
+ &info,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ DEBUG(1, ("Coult not query secdesc for share %s\n",
+ netname));
+ return;
+ }
+
+ share_sd = info.info502->sd_buf.sd;
+ if (share_sd == NULL) {
+ DEBUG(1, ("Got no secdesc for share %s\n",
+ netname));
+ }
+
+ cnum = cli->cnum;
+
+ if (!cli_send_tconX(cli, netname, "A:", "", 0)) {
+ return;
+ }
+
+ fnum = cli_nt_create(cli, "\\", READ_CONTROL_ACCESS);
+
+ if (fnum != -1) {
+ root_sd = cli_query_secdesc(cli, fnum, mem_ctx);
+ }
+
+ for (i=0; i<num_tokens; i++) {
+ uint32 acc_granted;
+
+ if (share_sd != NULL) {
+ if (!se_access_check(share_sd, &tokens[i].token,
+ 1, &acc_granted, &status)) {
+ DEBUG(1, ("Could not check share_sd for "
+ "user %s\n",
+ tokens[i].name));
+ continue;
+ }
+
+ if (!NT_STATUS_IS_OK(status))
+ continue;
+ }
+
+ if (root_sd == NULL) {
+ d_printf(" %s\n", tokens[i].name);
+ continue;
+ }
+
+ if (!se_access_check(root_sd, &tokens[i].token,
+ 1, &acc_granted, &status)) {
+ DEBUG(1, ("Could not check root_sd for user %s\n",
+ tokens[i].name));
+ continue;
+ }
+
+ if (!NT_STATUS_IS_OK(status))
+ continue;
+
+ d_printf(" %s\n", tokens[i].name);
+ }
+
+ if (fnum != -1)
+ cli_close(cli, fnum);
+ cli_tdis(cli);
+ cli->cnum = cnum;
+
+ return;
+}
+
+struct share_list {
+ int num_shares;
+ char **shares;
+};
+
+static void collect_share(const char *name, uint32 m,
+ const char *comment, void *state)
+{
+ struct share_list *share_list = (struct share_list *)state;
+
+ if (m != STYPE_DISKTREE)
+ return;
+
+ share_list->num_shares += 1;
+ share_list->shares = SMB_REALLOC_ARRAY(share_list->shares, char *, share_list->num_shares);
+ if (!share_list->shares) {
+ share_list->num_shares = 0;
+ return;
+ }
+ share_list->shares[share_list->num_shares-1] = SMB_STRDUP(name);
+}
+
+/**
+ * List shares on a remote RPC server, including the security descriptors.
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param domain_sid The domain sid acquired from the remote server.
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS rpc_share_allowedusers_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ int ret;
+ bool r;
+ ENUM_HND hnd;
+ uint32 i;
+ FILE *f;
+
+ struct user_token *tokens = NULL;
+ int num_tokens = 0;
+
+ struct share_list share_list;
+
+ if (argc == 0) {
+ f = stdin;
+ } else {
+ f = fopen(argv[0], "r");
+ }
+
+ if (f == NULL) {
+ DEBUG(0, ("Could not open userlist: %s\n", strerror(errno)));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ r = get_user_tokens_from_file(f, &num_tokens, &tokens);
+
+ if (f != stdin)
+ fclose(f);
+
+ if (!r) {
+ DEBUG(0, ("Could not read users from file\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ for (i=0; i<num_tokens; i++)
+ collect_alias_memberships(&tokens[i].token);
+
+ init_enum_hnd(&hnd, 0);
+
+ share_list.num_shares = 0;
+ share_list.shares = NULL;
+
+ ret = cli_RNetShareEnum(cli, collect_share, &share_list);
+
+ if (ret == -1) {
+ DEBUG(0, ("Error returning browse list: %s\n",
+ cli_errstr(cli)));
+ goto done;
+ }
+
+ for (i = 0; i < share_list.num_shares; i++) {
+ char *netname = share_list.shares[i];
+
+ if (netname[strlen(netname)-1] == '$')
+ continue;
+
+ d_printf("%s\n", netname);
+
+ show_userlist(pipe_hnd, mem_ctx, netname,
+ num_tokens, tokens);
+ }
+ done:
+ for (i=0; i<num_tokens; i++) {
+ free_user_token(&tokens[i].token);
+ }
+ SAFE_FREE(tokens);
+ SAFE_FREE(share_list.shares);
+
+ return NT_STATUS_OK;
+}
+
+static int rpc_share_allowedusers(struct net_context *c, int argc,
+ const char **argv)
+{
+ int result;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc share allowedusers\n"
+ " List allowed users\n");
+ return 0;
+ }
+
+ result = run_rpc_command(c, NULL, &ndr_table_samr.syntax_id, 0,
+ rpc_aliaslist_internals,
+ argc, argv);
+ if (result != 0)
+ return result;
+
+ result = run_rpc_command(c, NULL, &ndr_table_lsarpc.syntax_id, 0,
+ rpc_aliaslist_dump,
+ argc, argv);
+ if (result != 0)
+ return result;
+
+ return run_rpc_command(c, NULL, &ndr_table_srvsvc.syntax_id, 0,
+ rpc_share_allowedusers_internals,
+ argc, argv);
+}
+
+int net_usersidlist(struct net_context *c, int argc, const char **argv)
+{
+ int num_tokens = 0;
+ struct user_token *tokens = NULL;
+ int i;
+
+ if (argc != 0) {
+ net_usersidlist_usage(c, argc, argv);
+ return 0;
+ }
+
+ if (!get_user_tokens(c, &num_tokens, &tokens)) {
+ DEBUG(0, ("Could not get the user/sid list\n"));
+ return 0;
+ }
+
+ for (i=0; i<num_tokens; i++) {
+ dump_user_token(&tokens[i]);
+ free_user_token(&tokens[i].token);
+ }
+
+ SAFE_FREE(tokens);
+ return 1;
+}
+
+int net_usersidlist_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("net usersidlist\n"
+ "\tprints out a list of all users the running winbind knows\n"
+ "\tabout, together with all their SIDs. This is used as\n"
+ "\tinput to the 'net rpc share allowedusers' command.\n\n");
+
+ net_common_flags_usage(c, argc, argv);
+ return -1;
+}
+
+/**
+ * 'net rpc share' entrypoint.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ **/
+
+int net_rpc_share(struct net_context *c, int argc, const char **argv)
+{
+ NET_API_STATUS status;
+
+ struct functable func[] = {
+ {
+ "add",
+ rpc_share_add,
+ NET_TRANSPORT_RPC,
+ "Add share",
+ "net rpc share add\n"
+ " Add share"
+ },
+ {
+ "delete",
+ rpc_share_delete,
+ NET_TRANSPORT_RPC,
+ "Remove share",
+ "net rpc share delete\n"
+ " Remove share"
+ },
+ {
+ "allowedusers",
+ rpc_share_allowedusers,
+ NET_TRANSPORT_RPC,
+ "Modify allowed users",
+ "net rpc share allowedusers\n"
+ " Modify allowed users"
+ },
+ {
+ "migrate",
+ rpc_share_migrate,
+ NET_TRANSPORT_RPC,
+ "Migrate share to local server",
+ "net rpc share migrate\n"
+ " Migrate share to local server"
+ },
+ {
+ "list",
+ rpc_share_list,
+ NET_TRANSPORT_RPC,
+ "List shares",
+ "net rpc share list\n"
+ " List shares"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ status = libnetapi_init(&c->netapi_ctx);
+ if (status != 0) {
+ return -1;
+ }
+ libnetapi_set_username(c->netapi_ctx, c->opt_user_name);
+ libnetapi_set_password(c->netapi_ctx, c->opt_password);
+ if (c->opt_kerberos) {
+ libnetapi_set_use_kerberos(c->netapi_ctx);
+ }
+
+ if (argc == 0) {
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc share\n"
+ " List shares\n"
+ " Alias for net rpc share list\n");
+ net_display_usage_from_functable(func);
+ return 0;
+ }
+
+ return rpc_share_list(c, argc, argv);
+ }
+
+ return net_run_function(c, argc, argv, "net rpc share", func);
+}
+
+static NTSTATUS rpc_sh_share_list(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+
+ return werror_to_ntstatus(W_ERROR(rpc_share_list(c, argc, argv)));
+}
+
+static NTSTATUS rpc_sh_share_add(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ uint32_t parm_err = 0;
+ struct SHARE_INFO_2 i2;
+
+ if ((argc < 2) || (argc > 3)) {
+ d_fprintf(stderr, "usage: %s <share> <path> [comment]\n",
+ ctx->whoami);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ i2.shi2_netname = argv[0];
+ i2.shi2_type = STYPE_DISKTREE;
+ i2.shi2_remark = (argc == 3) ? argv[2] : "";
+ i2.shi2_permissions = 0;
+ i2.shi2_max_uses = 0;
+ i2.shi2_current_uses = 0;
+ i2.shi2_path = argv[1];
+ i2.shi2_passwd = NULL;
+
+ status = NetShareAdd(pipe_hnd->desthost,
+ 2,
+ (uint8_t *)&i2,
+ &parm_err);
+
+ return werror_to_ntstatus(W_ERROR(status));
+}
+
+static NTSTATUS rpc_sh_share_delete(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ if (argc != 1) {
+ d_fprintf(stderr, "usage: %s <share>\n", ctx->whoami);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ return werror_to_ntstatus(W_ERROR(NetShareDel(pipe_hnd->desthost, argv[0], 0)));
+}
+
+static NTSTATUS rpc_sh_share_info(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ union srvsvc_NetShareInfo info;
+ WERROR result;
+ NTSTATUS status;
+
+ if (argc != 1) {
+ d_fprintf(stderr, "usage: %s <share>\n", ctx->whoami);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = rpccli_srvsvc_NetShareGetInfo(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ argv[0],
+ 2,
+ &info,
+ &result);
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ goto done;
+ }
+
+ d_printf("Name: %s\n", info.info2->name);
+ d_printf("Comment: %s\n", info.info2->comment);
+ d_printf("Path: %s\n", info.info2->path);
+ d_printf("Password: %s\n", info.info2->password);
+
+ done:
+ return werror_to_ntstatus(result);
+}
+
+struct rpc_sh_cmd *net_rpc_share_cmds(struct net_context *c, TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx)
+{
+ static struct rpc_sh_cmd cmds[] = {
+
+ { "list", NULL, &ndr_table_srvsvc.syntax_id, rpc_sh_share_list,
+ "List available shares" },
+
+ { "add", NULL, &ndr_table_srvsvc.syntax_id, rpc_sh_share_add,
+ "Add a share" },
+
+ { "delete", NULL, &ndr_table_srvsvc.syntax_id, rpc_sh_share_delete,
+ "Delete a share" },
+
+ { "info", NULL, &ndr_table_srvsvc.syntax_id, rpc_sh_share_info,
+ "Get information about a share" },
+
+ { NULL, NULL, 0, NULL, NULL }
+ };
+
+ return cmds;
+}
+
+/****************************************************************************/
+
+static int rpc_file_usage(struct net_context *c, int argc, const char **argv)
+{
+ return net_file_usage(c, argc, argv);
+}
+
+/**
+ * Close a file on a remote RPC server.
+ *
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+static int rpc_file_close(struct net_context *c, int argc, const char **argv)
+{
+ if (argc < 1 || c->display_usage) {
+ return rpc_file_usage(c, argc, argv);
+ }
+
+ return NetFileClose(c->opt_host, atoi(argv[0]));
+}
+
+/**
+ * Formatted print of open file info
+ *
+ * @param r struct FILE_INFO_3 contents
+ **/
+
+static void display_file_info_3(struct FILE_INFO_3 *r)
+{
+ d_printf("%-7.1d %-20.20s 0x%-4.2x %-6.1d %s\n",
+ r->fi3_id, r->fi3_username, r->fi3_permissions,
+ r->fi3_num_locks, r->fi3_pathname);
+}
+
+/**
+ * List files for a user on a remote RPC server.
+ *
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success)..
+ **/
+
+static int rpc_file_user(struct net_context *c, int argc, const char **argv)
+{
+ NET_API_STATUS status;
+ uint32 preferred_len = 0xffffffff, i;
+ const char *username=NULL;
+ uint32_t total_entries = 0;
+ uint32_t entries_read = 0;
+ uint32_t resume_handle = 0;
+ struct FILE_INFO_3 *i3 = NULL;
+
+ if (c->display_usage) {
+ return rpc_file_usage(c, argc, argv);
+ }
+
+ /* if argc > 0, must be user command */
+ if (argc > 0) {
+ username = smb_xstrdup(argv[0]);
+ }
+
+ status = NetFileEnum(c->opt_host,
+ NULL,
+ username,
+ 3,
+ (uint8_t **)&i3,
+ preferred_len,
+ &entries_read,
+ &total_entries,
+ &resume_handle);
+
+ if (status != 0) {
+ goto done;
+ }
+
+ /* Display results */
+
+ d_printf(
+ "\nEnumerating open files on remote server:\n\n"
+ "\nFileId Opened by Perms Locks Path"
+ "\n------ --------- ----- ----- ---- \n");
+ for (i = 0; i < entries_read; i++) {
+ display_file_info_3(&i3[i]);
+ }
+ done:
+ return status;
+}
+
+/**
+ * 'net rpc file' entrypoint.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ **/
+
+int net_rpc_file(struct net_context *c, int argc, const char **argv)
+{
+ NET_API_STATUS status;
+
+ struct functable func[] = {
+ {
+ "close",
+ rpc_file_close,
+ NET_TRANSPORT_RPC,
+ "Close opened file",
+ "net rpc file close\n"
+ " Close opened file"
+ },
+ {
+ "user",
+ rpc_file_user,
+ NET_TRANSPORT_RPC,
+ "List files opened by user",
+ "net rpc file user\n"
+ " List files opened by user"
+ },
+#if 0
+ {
+ "info",
+ rpc_file_info,
+ NET_TRANSPORT_RPC,
+ "Display information about opened file",
+ "net rpc file info\n"
+ " Display information about opened file"
+ },
+#endif
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ status = libnetapi_init(&c->netapi_ctx);
+ if (status != 0) {
+ return -1;
+ }
+ libnetapi_set_username(c->netapi_ctx, c->opt_user_name);
+ libnetapi_set_password(c->netapi_ctx, c->opt_password);
+ if (c->opt_kerberos) {
+ libnetapi_set_use_kerberos(c->netapi_ctx);
+ }
+
+ if (argc == 0) {
+ if (c->display_usage) {
+ d_printf("Usage:\n");
+ d_printf("net rpc file\n"
+ " List opened files\n");
+ net_display_usage_from_functable(func);
+ return 0;
+ }
+
+ return rpc_file_user(c, argc, argv);
+ }
+
+ return net_run_function(c, argc, argv, "net rpc file", func);
+}
+
+/**
+ * ABORT the shutdown of a remote RPC Server, over initshutdown pipe.
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param c A net_context structure.
+ * @param domain_sid The domain sid acquired from the remote server.
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS rpc_shutdown_abort_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ result = rpccli_initshutdown_Abort(pipe_hnd, mem_ctx, NULL, NULL);
+
+ if (NT_STATUS_IS_OK(result)) {
+ d_printf("\nShutdown successfully aborted\n");
+ DEBUG(5,("cmd_shutdown_abort: query succeeded\n"));
+ } else
+ DEBUG(5,("cmd_shutdown_abort: query failed\n"));
+
+ return result;
+}
+
+/**
+ * ABORT the shutdown of a remote RPC Server, over winreg pipe.
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param c A net_context structure.
+ * @param domain_sid The domain sid acquired from the remote server.
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS rpc_reg_shutdown_abort_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ result = rpccli_winreg_AbortSystemShutdown(pipe_hnd, mem_ctx, NULL, NULL);
+
+ if (NT_STATUS_IS_OK(result)) {
+ d_printf("\nShutdown successfully aborted\n");
+ DEBUG(5,("cmd_reg_abort_shutdown: query succeeded\n"));
+ } else
+ DEBUG(5,("cmd_reg_abort_shutdown: query failed\n"));
+
+ return result;
+}
+
+/**
+ * ABORT the shutdown of a remote RPC server.
+ *
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+
+static int rpc_shutdown_abort(struct net_context *c, int argc,
+ const char **argv)
+{
+ int rc = -1;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc abortshutdown\n"
+ " Abort a scheduled shutdown\n");
+ return 0;
+ }
+
+ rc = run_rpc_command(c, NULL, &ndr_table_initshutdown.syntax_id, 0,
+ rpc_shutdown_abort_internals, argc, argv);
+
+ if (rc == 0)
+ return rc;
+
+ DEBUG(1, ("initshutdown pipe didn't work, trying winreg pipe\n"));
+
+ return run_rpc_command(c, NULL, &ndr_table_winreg.syntax_id, 0,
+ rpc_reg_shutdown_abort_internals,
+ argc, argv);
+}
+
+/**
+ * Shut down a remote RPC Server via initshutdown pipe.
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param c A net_context structure.
+ * @param domain_sid The domain sid acquired from the remote server.
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+NTSTATUS rpc_init_shutdown_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ const char *msg = "This machine will be shutdown shortly";
+ uint32 timeout = 20;
+ struct initshutdown_String msg_string;
+ struct initshutdown_String_sub s;
+
+ if (c->opt_comment) {
+ msg = c->opt_comment;
+ }
+ if (c->opt_timeout) {
+ timeout = c->opt_timeout;
+ }
+
+ s.name = msg;
+ msg_string.name = &s;
+
+ /* create an entry */
+ result = rpccli_initshutdown_Init(pipe_hnd, mem_ctx, NULL,
+ &msg_string, timeout, c->opt_force, c->opt_reboot,
+ NULL);
+
+ if (NT_STATUS_IS_OK(result)) {
+ d_printf("\nShutdown of remote machine succeeded\n");
+ DEBUG(5,("Shutdown of remote machine succeeded\n"));
+ } else {
+ DEBUG(1,("Shutdown of remote machine failed!\n"));
+ }
+ return result;
+}
+
+/**
+ * Shut down a remote RPC Server via winreg pipe.
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param c A net_context structure.
+ * @param domain_sid The domain sid acquired from the remote server.
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+NTSTATUS rpc_reg_shutdown_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ const char *msg = "This machine will be shutdown shortly";
+ uint32 timeout = 20;
+ struct initshutdown_String msg_string;
+ struct initshutdown_String_sub s;
+ NTSTATUS result;
+ WERROR werr;
+
+ if (c->opt_comment) {
+ msg = c->opt_comment;
+ }
+ s.name = msg;
+ msg_string.name = &s;
+
+ if (c->opt_timeout) {
+ timeout = c->opt_timeout;
+ }
+
+ /* create an entry */
+ result = rpccli_winreg_InitiateSystemShutdown(pipe_hnd, mem_ctx, NULL,
+ &msg_string, timeout, c->opt_force, c->opt_reboot,
+ &werr);
+
+ if (NT_STATUS_IS_OK(result)) {
+ d_printf("\nShutdown of remote machine succeeded\n");
+ } else {
+ d_fprintf(stderr, "\nShutdown of remote machine failed\n");
+ if ( W_ERROR_EQUAL(werr, WERR_MACHINE_LOCKED) )
+ d_fprintf(stderr, "\nMachine locked, use -f switch to force\n");
+ else
+ d_fprintf(stderr, "\nresult was: %s\n", dos_errstr(werr));
+ }
+
+ return result;
+}
+
+/**
+ * Shut down a remote RPC server.
+ *
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+
+static int rpc_shutdown(struct net_context *c, int argc, const char **argv)
+{
+ int rc = -1;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc shutdown\n"
+ " Shut down a remote RPC server\n");
+ return 0;
+ }
+
+ rc = run_rpc_command(c, NULL, &ndr_table_initshutdown.syntax_id, 0,
+ rpc_init_shutdown_internals, argc, argv);
+
+ if (rc) {
+ DEBUG(1, ("initshutdown pipe failed, trying winreg pipe\n"));
+ rc = run_rpc_command(c, NULL, &ndr_table_winreg.syntax_id, 0,
+ rpc_reg_shutdown_internals, argc, argv);
+ }
+
+ return rc;
+}
+
+/***************************************************************************
+ NT Domain trusts code (i.e. 'net rpc trustdom' functionality)
+ ***************************************************************************/
+
+/**
+ * Add interdomain trust account to the RPC server.
+ * All parameters (except for argc and argv) are passed by run_rpc_command
+ * function.
+ *
+ * @param c A net_context structure.
+ * @param domain_sid The domain sid acquired from the server.
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return normal NTSTATUS return code.
+ */
+
+static NTSTATUS rpc_trustdom_add_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, user_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ char *acct_name;
+ struct lsa_String lsa_acct_name;
+ uint32 acb_info;
+ uint32 acct_flags=0;
+ uint32 user_rid;
+ uint32_t access_granted = 0;
+ union samr_UserInfo info;
+ unsigned int orig_timeout;
+
+ if (argc != 2) {
+ d_printf("Usage: net rpc trustdom add <domain_name> "
+ "<trust password>\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /*
+ * Make valid trusting domain account (ie. uppercased and with '$' appended)
+ */
+
+ if (asprintf(&acct_name, "%s$", argv[0]) < 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ strupper_m(acct_name);
+
+ init_lsa_String(&lsa_acct_name, acct_name);
+
+ /* Get samr policy handle */
+ result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Get domain policy handle */
+ result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ CONST_DISCARD(struct dom_sid2 *, domain_sid),
+ &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* This call can take a long time - allow the server to time out.
+ * 35 seconds should do it. */
+
+ orig_timeout = rpccli_set_timeout(pipe_hnd, 35000);
+
+ /* Create trusting domain's account */
+ acb_info = ACB_NORMAL;
+ acct_flags = SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
+ SEC_STD_WRITE_DAC | SEC_STD_DELETE |
+ SAMR_USER_ACCESS_SET_PASSWORD |
+ SAMR_USER_ACCESS_GET_ATTRIBUTES |
+ SAMR_USER_ACCESS_SET_ATTRIBUTES;
+
+ result = rpccli_samr_CreateUser2(pipe_hnd, mem_ctx,
+ &domain_pol,
+ &lsa_acct_name,
+ acb_info,
+ acct_flags,
+ &user_pol,
+ &access_granted,
+ &user_rid);
+
+ /* And restore our original timeout. */
+ rpccli_set_timeout(pipe_hnd, orig_timeout);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_printf("net rpc trustdom add: create user %s failed %s\n",
+ acct_name, nt_errstr(result));
+ goto done;
+ }
+
+ {
+ NTTIME notime;
+ struct samr_LogonHours hours;
+ struct lsa_BinaryString parameters;
+ const int units_per_week = 168;
+ struct samr_CryptPassword crypt_pwd;
+
+ ZERO_STRUCT(notime);
+ ZERO_STRUCT(hours);
+ ZERO_STRUCT(parameters);
+
+ hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
+ if (!hours.bits) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ hours.units_per_week = units_per_week;
+ memset(hours.bits, 0xFF, units_per_week);
+
+ init_samr_CryptPassword(argv[1],
+ &cli->user_session_key,
+ &crypt_pwd);
+
+ init_samr_user_info23(&info.info23,
+ notime, notime, notime,
+ notime, notime, notime,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, &parameters,
+ 0, 0, ACB_DOMTRUST, SAMR_FIELD_ACCT_FLAGS,
+ hours,
+ 0, 0, 0, 0, 0, 0, 0,
+ crypt_pwd.data, 24);
+
+ result = rpccli_samr_SetUserInfo2(pipe_hnd, mem_ctx,
+ &user_pol,
+ 23,
+ &info);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("Could not set trust account password: %s\n",
+ nt_errstr(result)));
+ goto done;
+ }
+ }
+
+ done:
+ SAFE_FREE(acct_name);
+ return result;
+}
+
+/**
+ * Create interdomain trust account for a remote domain.
+ *
+ * @param argc Standard argc.
+ * @param argv Standard argv without initial components.
+ *
+ * @return Integer status (0 means success).
+ **/
+
+static int rpc_trustdom_add(struct net_context *c, int argc, const char **argv)
+{
+ if (argc > 0 && !c->display_usage) {
+ return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id, 0,
+ rpc_trustdom_add_internals, argc, argv);
+ } else {
+ d_printf("Usage:\n"
+ "net rpc trustdom add <domain_name> <trust password>\n");
+ return -1;
+ }
+}
+
+
+/**
+ * Remove interdomain trust account from the RPC server.
+ * All parameters (except for argc and argv) are passed by run_rpc_command
+ * function.
+ *
+ * @param c A net_context structure.
+ * @param domain_sid The domain sid acquired from the server.
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destroyed on completion of the function.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return normal NTSTATUS return code.
+ */
+
+static NTSTATUS rpc_trustdom_del_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, user_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ char *acct_name;
+ DOM_SID trust_acct_sid;
+ struct samr_Ids user_rids, name_types;
+ struct lsa_String lsa_acct_name;
+
+ if (argc != 1) {
+ d_printf("Usage: net rpc trustdom del <domain_name>\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /*
+ * Make valid trusting domain account (ie. uppercased and with '$' appended)
+ */
+ acct_name = talloc_asprintf(mem_ctx, "%s$", argv[0]);
+
+ if (acct_name == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ strupper_m(acct_name);
+
+ /* Get samr policy handle */
+ result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Get domain policy handle */
+ result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ CONST_DISCARD(struct dom_sid2 *, domain_sid),
+ &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ init_lsa_String(&lsa_acct_name, acct_name);
+
+ result = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 1,
+ &lsa_acct_name,
+ &user_rids,
+ &name_types);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_printf("net rpc trustdom del: LookupNames on user %s failed %s\n",
+ acct_name, nt_errstr(result) );
+ goto done;
+ }
+
+ result = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
+ &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ user_rids.ids[0],
+ &user_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_printf("net rpc trustdom del: OpenUser on user %s failed %s\n",
+ acct_name, nt_errstr(result) );
+ goto done;
+ }
+
+ /* append the rid to the domain sid */
+ sid_copy(&trust_acct_sid, domain_sid);
+ if (!sid_append_rid(&trust_acct_sid, user_rids.ids[0])) {
+ goto done;
+ }
+
+ /* remove the sid */
+
+ result = rpccli_samr_RemoveMemberFromForeignDomain(pipe_hnd, mem_ctx,
+ &user_pol,
+ &trust_acct_sid);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_printf("net rpc trustdom del: RemoveMemberFromForeignDomain on user %s failed %s\n",
+ acct_name, nt_errstr(result) );
+ goto done;
+ }
+
+ /* Delete user */
+
+ result = rpccli_samr_DeleteUser(pipe_hnd, mem_ctx,
+ &user_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_printf("net rpc trustdom del: DeleteUser on user %s failed %s\n",
+ acct_name, nt_errstr(result) );
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_printf("Could not set trust account password: %s\n",
+ nt_errstr(result));
+ goto done;
+ }
+
+ done:
+ return result;
+}
+
+/**
+ * Delete interdomain trust account for a remote domain.
+ *
+ * @param argc Standard argc.
+ * @param argv Standard argv without initial components.
+ *
+ * @return Integer status (0 means success).
+ **/
+
+static int rpc_trustdom_del(struct net_context *c, int argc, const char **argv)
+{
+ if (argc > 0 && !c->display_usage) {
+ return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id, 0,
+ rpc_trustdom_del_internals, argc, argv);
+ } else {
+ d_printf("Usage:\n"
+ "net rpc trustdom del <domain>\n");
+ return -1;
+ }
+}
+
+static NTSTATUS rpc_trustdom_get_pdc(struct net_context *c,
+ struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ const char *domain_name)
+{
+ char *dc_name = NULL;
+ const char *buffer = NULL;
+ struct rpc_pipe_client *netr;
+ NTSTATUS status;
+
+ /* Use NetServerEnum2 */
+
+ if (cli_get_pdc_name(cli, domain_name, &dc_name)) {
+ SAFE_FREE(dc_name);
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(1,("NetServerEnum2 error: Couldn't find primary domain controller\
+ for domain %s\n", domain_name));
+
+ /* Try netr_GetDcName */
+
+ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id,
+ &netr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = rpccli_netr_GetDcName(netr, mem_ctx,
+ cli->desthost,
+ domain_name,
+ &buffer,
+ NULL);
+ TALLOC_FREE(netr);
+
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(1,("netr_GetDcName error: Couldn't find primary domain controller\
+ for domain %s\n", domain_name));
+
+ return status;
+}
+
+/**
+ * Establish trust relationship to a trusting domain.
+ * Interdomain account must already be created on remote PDC.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard argc.
+ * @param argv Standard argv without initial components.
+ *
+ * @return Integer status (0 means success).
+ **/
+
+static int rpc_trustdom_establish(struct net_context *c, int argc,
+ const char **argv)
+{
+ struct cli_state *cli = NULL;
+ struct sockaddr_storage server_ss;
+ struct rpc_pipe_client *pipe_hnd = NULL;
+ POLICY_HND connect_hnd;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS nt_status;
+ DOM_SID *domain_sid;
+
+ char* domain_name;
+ char* acct_name;
+ fstring pdc_name;
+ union lsa_PolicyInformation *info = NULL;
+
+ /*
+ * Connect to \\server\ipc$ as 'our domain' account with password
+ */
+
+ if (argc != 1 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc trustdom establish <domain_name>\n");
+ return -1;
+ }
+
+ domain_name = smb_xstrdup(argv[0]);
+ strupper_m(domain_name);
+
+ /* account name used at first is our domain's name with '$' */
+ asprintf(&acct_name, "%s$", lp_workgroup());
+ strupper_m(acct_name);
+
+ /*
+ * opt_workgroup will be used by connection functions further,
+ * hence it should be set to remote domain name instead of ours
+ */
+ if (c->opt_workgroup) {
+ c->opt_workgroup = smb_xstrdup(domain_name);
+ };
+
+ c->opt_user_name = acct_name;
+
+ /* find the domain controller */
+ if (!net_find_pdc(&server_ss, pdc_name, domain_name)) {
+ DEBUG(0, ("Couldn't find domain controller for domain %s\n", domain_name));
+ return -1;
+ }
+
+ /* connect to ipc$ as username/password */
+ nt_status = connect_to_ipc(c, &cli, &server_ss, pdc_name);
+ if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT)) {
+
+ /* Is it trusting domain account for sure ? */
+ DEBUG(0, ("Couldn't verify trusting domain account. Error was %s\n",
+ nt_errstr(nt_status)));
+ return -1;
+ }
+
+ /* store who we connected to */
+
+ saf_store( domain_name, pdc_name );
+
+ /*
+ * Connect to \\server\ipc$ again (this time anonymously)
+ */
+
+ nt_status = connect_to_ipc_anonymous(c, &cli, &server_ss,
+ (char*)pdc_name);
+
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ DEBUG(0, ("Couldn't connect to domain %s controller. Error was %s.\n",
+ domain_name, nt_errstr(nt_status)));
+ return -1;
+ }
+
+ if (!(mem_ctx = talloc_init("establishing trust relationship to "
+ "domain %s", domain_name))) {
+ DEBUG(0, ("talloc_init() failed\n"));
+ cli_shutdown(cli);
+ return -1;
+ }
+
+ /* Make sure we're talking to a proper server */
+
+ nt_status = rpc_trustdom_get_pdc(c, cli, mem_ctx, domain_name);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ /*
+ * Call LsaOpenPolicy and LsaQueryInfo
+ */
+
+ nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
+ &pipe_hnd);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("Could not initialise lsa pipe. Error was %s\n", nt_errstr(nt_status) ));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ nt_status = rpccli_lsa_open_policy2(pipe_hnd, mem_ctx, true, SEC_RIGHTS_QUERY_VALUE,
+ &connect_hnd);
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ DEBUG(0, ("Couldn't open policy handle. Error was %s\n",
+ nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ /* Querying info level 5 */
+
+ nt_status = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
+ &connect_hnd,
+ LSA_POLICY_INFO_ACCOUNT_DOMAIN,
+ &info);
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ DEBUG(0, ("LSA Query Info failed. Returned error was %s\n",
+ nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ domain_sid = info->account_domain.sid;
+
+ /* There should be actually query info level 3 (following nt serv behaviour),
+ but I still don't know if it's _really_ necessary */
+
+ /*
+ * Store the password in secrets db
+ */
+
+ if (!pdb_set_trusteddom_pw(domain_name, c->opt_password, domain_sid)) {
+ DEBUG(0, ("Storing password for trusted domain failed.\n"));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ /*
+ * Close the pipes and clean up
+ */
+
+ nt_status = rpccli_lsa_Close(pipe_hnd, mem_ctx, &connect_hnd);
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ DEBUG(0, ("Couldn't close LSA pipe. Error was %s\n",
+ nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ cli_shutdown(cli);
+
+ talloc_destroy(mem_ctx);
+
+ d_printf("Trust to domain %s established\n", domain_name);
+ return 0;
+}
+
+/**
+ * Revoke trust relationship to the remote domain.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard argc.
+ * @param argv Standard argv without initial components.
+ *
+ * @return Integer status (0 means success).
+ **/
+
+static int rpc_trustdom_revoke(struct net_context *c, int argc,
+ const char **argv)
+{
+ char* domain_name;
+ int rc = -1;
+
+ if (argc < 1 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc trustdom revoke <domain_name>\n"
+ " Revoke trust relationship\n"
+ " domain_name\tName of domain to revoke trust\n");
+ return -1;
+ }
+
+ /* generate upper cased domain name */
+ domain_name = smb_xstrdup(argv[0]);
+ strupper_m(domain_name);
+
+ /* delete password of the trust */
+ if (!pdb_del_trusteddom_pw(domain_name)) {
+ DEBUG(0, ("Failed to revoke relationship to the trusted domain %s\n",
+ domain_name));
+ goto done;
+ };
+
+ rc = 0;
+done:
+ SAFE_FREE(domain_name);
+ return rc;
+}
+
+static NTSTATUS rpc_query_domain_sid(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ fstring str_sid;
+ sid_to_fstring(str_sid, domain_sid);
+ d_printf("%s\n", str_sid);
+ return NT_STATUS_OK;
+}
+
+static void print_trusted_domain(DOM_SID *dom_sid, const char *trusted_dom_name)
+{
+ fstring ascii_sid, padding;
+ int pad_len, col_len = 20;
+
+ /* convert sid into ascii string */
+ sid_to_fstring(ascii_sid, dom_sid);
+
+ /* calculate padding space for d_printf to look nicer */
+ pad_len = col_len - strlen(trusted_dom_name);
+ padding[pad_len] = 0;
+ do padding[--pad_len] = ' '; while (pad_len);
+
+ d_printf("%s%s%s\n", trusted_dom_name, padding, ascii_sid);
+}
+
+static NTSTATUS vampire_trusted_domain(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol,
+ DOM_SID dom_sid,
+ const char *trusted_dom_name)
+{
+ NTSTATUS nt_status;
+ union lsa_TrustedDomainInfo *info = NULL;
+ char *cleartextpwd = NULL;
+ uint8_t nt_hash[16];
+ DATA_BLOB data;
+
+ nt_status = rpccli_lsa_QueryTrustedDomainInfoBySid(pipe_hnd, mem_ctx,
+ pol,
+ &dom_sid,
+ LSA_TRUSTED_DOMAIN_INFO_PASSWORD,
+ &info);
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ DEBUG(0,("Could not query trusted domain info. Error was %s\n",
+ nt_errstr(nt_status)));
+ goto done;
+ }
+
+ data = data_blob(info->password.password->data,
+ info->password.password->length);
+
+ if (!rpccli_get_pwd_hash(pipe_hnd, nt_hash)) {
+ DEBUG(0, ("Could not retrieve password hash\n"));
+ goto done;
+ }
+
+ cleartextpwd = decrypt_trustdom_secret(nt_hash, &data);
+
+ if (cleartextpwd == NULL) {
+ DEBUG(0,("retrieved NULL password\n"));
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!pdb_set_trusteddom_pw(trusted_dom_name, cleartextpwd, &dom_sid)) {
+ DEBUG(0, ("Storing password for trusted domain failed.\n"));
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("successfully vampired trusted domain [%s], sid: [%s], "
+ "password: [%s]\n", trusted_dom_name,
+ sid_string_dbg(&dom_sid), cleartextpwd));
+#endif
+
+done:
+ SAFE_FREE(cleartextpwd);
+ data_blob_free(&data);
+
+ return nt_status;
+}
+
+static int rpc_trustdom_vampire(struct net_context *c, int argc,
+ const char **argv)
+{
+ /* common variables */
+ TALLOC_CTX* mem_ctx;
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_hnd = NULL;
+ NTSTATUS nt_status;
+ const char *domain_name = NULL;
+ DOM_SID *queried_dom_sid;
+ POLICY_HND connect_hnd;
+ union lsa_PolicyInformation *info = NULL;
+
+ /* trusted domains listing variables */
+ unsigned int enum_ctx = 0;
+ int i;
+ struct lsa_DomainList dom_list;
+ fstring pdc_name;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc trustdom vampire\n"
+ " Vampire trust relationship from remote server\n");
+ return 0;
+ }
+
+ /*
+ * Listing trusted domains (stored in secrets.tdb, if local)
+ */
+
+ mem_ctx = talloc_init("trust relationships vampire");
+
+ /*
+ * set domain and pdc name to local samba server (default)
+ * or to remote one given in command line
+ */
+
+ if (StrCaseCmp(c->opt_workgroup, lp_workgroup())) {
+ domain_name = c->opt_workgroup;
+ c->opt_target_workgroup = c->opt_workgroup;
+ } else {
+ fstrcpy(pdc_name, global_myname());
+ domain_name = talloc_strdup(mem_ctx, lp_workgroup());
+ c->opt_target_workgroup = domain_name;
+ };
+
+ /* open \PIPE\lsarpc and open policy handle */
+ nt_status = net_make_ipc_connection(c, NET_FLAGS_PDC, &cli);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("Couldn't connect to domain controller: %s\n",
+ nt_errstr(nt_status)));
+ talloc_destroy(mem_ctx);
+ return -1;
+ };
+
+ nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
+ &pipe_hnd);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("Could not initialise lsa pipe. Error was %s\n",
+ nt_errstr(nt_status) ));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ };
+
+ nt_status = rpccli_lsa_open_policy2(pipe_hnd, mem_ctx, false, SEC_RIGHTS_QUERY_VALUE,
+ &connect_hnd);
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ DEBUG(0, ("Couldn't open policy handle. Error was %s\n",
+ nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ };
+
+ /* query info level 5 to obtain sid of a domain being queried */
+ nt_status = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
+ &connect_hnd,
+ LSA_POLICY_INFO_ACCOUNT_DOMAIN,
+ &info);
+
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ DEBUG(0, ("LSA Query Info failed. Returned error was %s\n",
+ nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ queried_dom_sid = info->account_domain.sid;
+
+ /*
+ * Keep calling LsaEnumTrustdom over opened pipe until
+ * the end of enumeration is reached
+ */
+
+ d_printf("Vampire trusted domains:\n\n");
+
+ do {
+ nt_status = rpccli_lsa_EnumTrustDom(pipe_hnd, mem_ctx,
+ &connect_hnd,
+ &enum_ctx,
+ &dom_list,
+ (uint32_t)-1);
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ DEBUG(0, ("Couldn't enumerate trusted domains. Error was %s\n",
+ nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ };
+
+ for (i = 0; i < dom_list.count; i++) {
+
+ print_trusted_domain(dom_list.domains[i].sid,
+ dom_list.domains[i].name.string);
+
+ nt_status = vampire_trusted_domain(pipe_hnd, mem_ctx, &connect_hnd,
+ *dom_list.domains[i].sid,
+ dom_list.domains[i].name.string);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+ };
+
+ /*
+ * in case of no trusted domains say something rather
+ * than just display blank line
+ */
+ if (!dom_list.count) d_printf("none\n");
+
+ } while (NT_STATUS_EQUAL(nt_status, STATUS_MORE_ENTRIES));
+
+ /* close this connection before doing next one */
+ nt_status = rpccli_lsa_Close(pipe_hnd, mem_ctx, &connect_hnd);
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ DEBUG(0, ("Couldn't properly close lsa policy handle. Error was %s\n",
+ nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ };
+
+ /* close lsarpc pipe and connection to IPC$ */
+ cli_shutdown(cli);
+
+ talloc_destroy(mem_ctx);
+ return 0;
+}
+
+static int rpc_trustdom_list(struct net_context *c, int argc, const char **argv)
+{
+ /* common variables */
+ TALLOC_CTX* mem_ctx;
+ struct cli_state *cli = NULL, *remote_cli = NULL;
+ struct rpc_pipe_client *pipe_hnd = NULL;
+ NTSTATUS nt_status;
+ const char *domain_name = NULL;
+ DOM_SID *queried_dom_sid;
+ fstring padding;
+ int ascii_dom_name_len;
+ POLICY_HND connect_hnd;
+ union lsa_PolicyInformation *info = NULL;
+
+ /* trusted domains listing variables */
+ unsigned int num_domains, enum_ctx = 0;
+ int i, pad_len, col_len = 20;
+ struct lsa_DomainList dom_list;
+ fstring pdc_name;
+
+ /* trusting domains listing variables */
+ POLICY_HND domain_hnd;
+ struct samr_SamArray *trusts = NULL;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc trustdom list\n"
+ " List trust relationships\n");
+ return 0;
+ }
+
+ /*
+ * Listing trusted domains (stored in secrets.tdb, if local)
+ */
+
+ mem_ctx = talloc_init("trust relationships listing");
+
+ /*
+ * set domain and pdc name to local samba server (default)
+ * or to remote one given in command line
+ */
+
+ if (StrCaseCmp(c->opt_workgroup, lp_workgroup())) {
+ domain_name = c->opt_workgroup;
+ c->opt_target_workgroup = c->opt_workgroup;
+ } else {
+ fstrcpy(pdc_name, global_myname());
+ domain_name = talloc_strdup(mem_ctx, lp_workgroup());
+ c->opt_target_workgroup = domain_name;
+ };
+
+ /* open \PIPE\lsarpc and open policy handle */
+ nt_status = net_make_ipc_connection(c, NET_FLAGS_PDC, &cli);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("Couldn't connect to domain controller: %s\n",
+ nt_errstr(nt_status)));
+ talloc_destroy(mem_ctx);
+ return -1;
+ };
+
+ nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
+ &pipe_hnd);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("Could not initialise lsa pipe. Error was %s\n",
+ nt_errstr(nt_status) ));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ };
+
+ nt_status = rpccli_lsa_open_policy2(pipe_hnd, mem_ctx, false, SEC_RIGHTS_QUERY_VALUE,
+ &connect_hnd);
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ DEBUG(0, ("Couldn't open policy handle. Error was %s\n",
+ nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ };
+
+ /* query info level 5 to obtain sid of a domain being queried */
+ nt_status = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
+ &connect_hnd,
+ LSA_POLICY_INFO_ACCOUNT_DOMAIN,
+ &info);
+
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ DEBUG(0, ("LSA Query Info failed. Returned error was %s\n",
+ nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ queried_dom_sid = info->account_domain.sid;
+
+ /*
+ * Keep calling LsaEnumTrustdom over opened pipe until
+ * the end of enumeration is reached
+ */
+
+ d_printf("Trusted domains list:\n\n");
+
+ do {
+ nt_status = rpccli_lsa_EnumTrustDom(pipe_hnd, mem_ctx,
+ &connect_hnd,
+ &enum_ctx,
+ &dom_list,
+ (uint32_t)-1);
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ DEBUG(0, ("Couldn't enumerate trusted domains. Error was %s\n",
+ nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ };
+
+ for (i = 0; i < dom_list.count; i++) {
+ print_trusted_domain(dom_list.domains[i].sid,
+ dom_list.domains[i].name.string);
+ };
+
+ /*
+ * in case of no trusted domains say something rather
+ * than just display blank line
+ */
+ if (!dom_list.count) d_printf("none\n");
+
+ } while (NT_STATUS_EQUAL(nt_status, STATUS_MORE_ENTRIES));
+
+ /* close this connection before doing next one */
+ nt_status = rpccli_lsa_Close(pipe_hnd, mem_ctx, &connect_hnd);
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ DEBUG(0, ("Couldn't properly close lsa policy handle. Error was %s\n",
+ nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ };
+
+ TALLOC_FREE(pipe_hnd);
+
+ /*
+ * Listing trusting domains (stored in passdb backend, if local)
+ */
+
+ d_printf("\nTrusting domains list:\n\n");
+
+ /*
+ * Open \PIPE\samr and get needed policy handles
+ */
+ nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
+ &pipe_hnd);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("Could not initialise samr pipe. Error was %s\n", nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ };
+
+ /* SamrConnect2 */
+ nt_status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ SA_RIGHT_SAM_OPEN_DOMAIN,
+ &connect_hnd);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("Couldn't open SAMR policy handle. Error was %s\n",
+ nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ };
+
+ /* SamrOpenDomain - we have to open domain policy handle in order to be
+ able to enumerate accounts*/
+ nt_status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &connect_hnd,
+ SA_RIGHT_DOMAIN_ENUM_ACCOUNTS,
+ queried_dom_sid,
+ &domain_hnd);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("Couldn't open domain object. Error was %s\n",
+ nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ };
+
+ /*
+ * perform actual enumeration
+ */
+
+ enum_ctx = 0; /* reset enumeration context from last enumeration */
+ do {
+
+ nt_status = rpccli_samr_EnumDomainUsers(pipe_hnd, mem_ctx,
+ &domain_hnd,
+ &enum_ctx,
+ ACB_DOMTRUST,
+ &trusts,
+ 0xffff,
+ &num_domains);
+ if (NT_STATUS_IS_ERR(nt_status)) {
+ DEBUG(0, ("Couldn't enumerate accounts. Error was: %s\n",
+ nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ talloc_destroy(mem_ctx);
+ return -1;
+ };
+
+ for (i = 0; i < num_domains; i++) {
+
+ char *str = CONST_DISCARD(char *, trusts->entries[i].name.string);
+
+ /*
+ * get each single domain's sid (do we _really_ need this ?):
+ * 1) connect to domain's pdc
+ * 2) query the pdc for domain's sid
+ */
+
+ /* get rid of '$' tail */
+ ascii_dom_name_len = strlen(str);
+ if (ascii_dom_name_len && ascii_dom_name_len < FSTRING_LEN)
+ str[ascii_dom_name_len - 1] = '\0';
+
+ /* calculate padding space for d_printf to look nicer */
+ pad_len = col_len - strlen(str);
+ padding[pad_len] = 0;
+ do padding[--pad_len] = ' '; while (pad_len);
+
+ /* set opt_* variables to remote domain */
+ strupper_m(str);
+ c->opt_workgroup = talloc_strdup(mem_ctx, str);
+ c->opt_target_workgroup = c->opt_workgroup;
+
+ d_printf("%s%s", str, padding);
+
+ /* connect to remote domain controller */
+ nt_status = net_make_ipc_connection(c,
+ NET_FLAGS_PDC | NET_FLAGS_ANONYMOUS,
+ &remote_cli);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ /* query for domain's sid */
+ if (run_rpc_command(
+ c, remote_cli,
+ &ndr_table_lsarpc.syntax_id, 0,
+ rpc_query_domain_sid, argc,
+ argv))
+ d_fprintf(stderr, "couldn't get domain's sid\n");
+
+ cli_shutdown(remote_cli);
+
+ } else {
+ d_fprintf(stderr, "domain controller is not "
+ "responding: %s\n",
+ nt_errstr(nt_status));
+ };
+ };
+
+ if (!num_domains) d_printf("none\n");
+
+ } while (NT_STATUS_EQUAL(nt_status, STATUS_MORE_ENTRIES));
+
+ /* close opened samr and domain policy handles */
+ nt_status = rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_hnd);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("Couldn't properly close domain policy handle for domain %s\n", domain_name));
+ };
+
+ nt_status = rpccli_samr_Close(pipe_hnd, mem_ctx, &connect_hnd);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("Couldn't properly close samr policy handle for domain %s\n", domain_name));
+ };
+
+ /* close samr pipe and connection to IPC$ */
+ cli_shutdown(cli);
+
+ talloc_destroy(mem_ctx);
+ return 0;
+}
+
+/**
+ * Entrypoint for 'net rpc trustdom' code.
+ *
+ * @param argc Standard argc.
+ * @param argv Standard argv without initial components.
+ *
+ * @return Integer status (0 means success).
+ */
+
+static int rpc_trustdom(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "add",
+ rpc_trustdom_add,
+ NET_TRANSPORT_RPC,
+ "Add trusted domain's account",
+ "net rpc trustdom add\n"
+ " Add trusted domain's account"
+ },
+ {
+ "del",
+ rpc_trustdom_del,
+ NET_TRANSPORT_RPC,
+ "Remove trusted domain's account",
+ "net rpc trustdom del\n"
+ " Remove trusted domain's account"
+ },
+ {
+ "establish",
+ rpc_trustdom_establish,
+ NET_TRANSPORT_RPC,
+ "Establish trust relationship",
+ "net rpc trustdom establish\n"
+ " Establish trust relationship"
+ },
+ {
+ "revoke",
+ rpc_trustdom_revoke,
+ NET_TRANSPORT_RPC,
+ "Revoke trust relationship",
+ "net rpc trustdom revoke\n"
+ " Revoke trust relationship"
+ },
+ {
+ "list",
+ rpc_trustdom_list,
+ NET_TRANSPORT_RPC,
+ "List domain trusts",
+ "net rpc trustdom list\n"
+ " List domain trusts"
+ },
+ {
+ "vampire",
+ rpc_trustdom_vampire,
+ NET_TRANSPORT_RPC,
+ "Vampire trusts from remote server",
+ "net rpc trustdom vampire\n"
+ " Vampire trusts from remote server"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net rpc trustdom", func);
+}
+
+/**
+ * Check if a server will take rpc commands
+ * @param flags Type of server to connect to (PDC, DMB, localhost)
+ * if the host is not explicitly specified
+ * @return bool (true means rpc supported)
+ */
+bool net_rpc_check(struct net_context *c, unsigned flags)
+{
+ struct cli_state *cli;
+ bool ret = false;
+ struct sockaddr_storage server_ss;
+ char *server_name = NULL;
+ NTSTATUS status;
+
+ /* flags (i.e. server type) may depend on command */
+ if (!net_find_server(c, NULL, flags, &server_ss, &server_name))
+ return false;
+
+ if ((cli = cli_initialise()) == NULL) {
+ return false;
+ }
+
+ status = cli_connect(cli, server_name, &server_ss);
+ if (!NT_STATUS_IS_OK(status))
+ goto done;
+ if (!attempt_netbios_session_request(&cli, global_myname(),
+ server_name, &server_ss))
+ goto done;
+ if (!cli_negprot(cli))
+ goto done;
+ if (cli->protocol < PROTOCOL_NT1)
+ goto done;
+
+ ret = true;
+ done:
+ cli_shutdown(cli);
+ return ret;
+}
+
+/* dump sam database via samsync rpc calls */
+static int rpc_samdump(struct net_context *c, int argc, const char **argv) {
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc samdump\n"
+ " Dump remote SAM database\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_netlogon.syntax_id,
+ NET_FLAGS_ANONYMOUS,
+ rpc_samdump_internals, argc, argv);
+}
+
+/* syncronise sam database via samsync rpc calls */
+static int rpc_vampire(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "ldif",
+ rpc_vampire_ldif,
+ NET_TRANSPORT_RPC,
+ "Dump remote SAM database to ldif",
+ "net rpc vampire ldif\n"
+ " Dump remote SAM database to LDIF file or stdout"
+ },
+ {
+ "keytab",
+ rpc_vampire_keytab,
+ NET_TRANSPORT_RPC,
+ "Dump remote SAM database to Kerberos Keytab",
+ "net rpc vampire keytab\n"
+ " Dump remote SAM database to Kerberos keytab file"
+ },
+
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ if (argc == 0) {
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc vampire\n"
+ " Vampire remote SAM database\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_netlogon.syntax_id,
+ NET_FLAGS_ANONYMOUS,
+ rpc_vampire_internals,
+ argc, argv);
+ }
+
+ return net_run_function(c, argc, argv, "net rpc vampire", func);
+}
+
+/**
+ * Migrate everything from a print server.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ *
+ * The order is important !
+ * To successfully add drivers the print queues have to exist !
+ * Applying ACLs should be the last step, because you're easily locked out.
+ *
+ **/
+static int rpc_printer_migrate_all(struct net_context *c, int argc,
+ const char **argv)
+{
+ int ret;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc printer migrate all\n"
+ " Migrate everything from a print server\n");
+ return 0;
+ }
+
+ if (!c->opt_host) {
+ d_printf("no server to migrate\n");
+ return -1;
+ }
+
+ ret = run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_migrate_printers_internals, argc,
+ argv);
+ if (ret)
+ return ret;
+
+ ret = run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_migrate_drivers_internals, argc,
+ argv);
+ if (ret)
+ return ret;
+
+ ret = run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_migrate_forms_internals, argc, argv);
+ if (ret)
+ return ret;
+
+ ret = run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_migrate_settings_internals, argc,
+ argv);
+ if (ret)
+ return ret;
+
+ return run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_migrate_security_internals, argc,
+ argv);
+
+}
+
+/**
+ * Migrate print drivers from a print server.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+static int rpc_printer_migrate_drivers(struct net_context *c, int argc,
+ const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc printer migrate drivers\n"
+ " Migrate print-drivers from a print-server\n");
+ return 0;
+ }
+
+ if (!c->opt_host) {
+ d_printf("no server to migrate\n");
+ return -1;
+ }
+
+ return run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_migrate_drivers_internals,
+ argc, argv);
+}
+
+/**
+ * Migrate print-forms from a print-server.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+static int rpc_printer_migrate_forms(struct net_context *c, int argc,
+ const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc printer migrate forms\n"
+ " Migrate print-forms from a print-server\n");
+ return 0;
+ }
+
+ if (!c->opt_host) {
+ d_printf("no server to migrate\n");
+ return -1;
+ }
+
+ return run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_migrate_forms_internals,
+ argc, argv);
+}
+
+/**
+ * Migrate printers from a print-server.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+static int rpc_printer_migrate_printers(struct net_context *c, int argc,
+ const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc printer migrate printers\n"
+ " Migrate printers from a print-server\n");
+ return 0;
+ }
+
+ if (!c->opt_host) {
+ d_printf("no server to migrate\n");
+ return -1;
+ }
+
+ return run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_migrate_printers_internals,
+ argc, argv);
+}
+
+/**
+ * Migrate printer-ACLs from a print-server
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+static int rpc_printer_migrate_security(struct net_context *c, int argc,
+ const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc printer migrate security\n"
+ " Migrate printer-ACLs from a print-server\n");
+ return 0;
+ }
+
+ if (!c->opt_host) {
+ d_printf("no server to migrate\n");
+ return -1;
+ }
+
+ return run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_migrate_security_internals,
+ argc, argv);
+}
+
+/**
+ * Migrate printer-settings from a print-server.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+static int rpc_printer_migrate_settings(struct net_context *c, int argc,
+ const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc printer migrate settings\n"
+ " Migrate printer-settings from a print-server\n");
+ return 0;
+ }
+
+ if (!c->opt_host) {
+ d_printf("no server to migrate\n");
+ return -1;
+ }
+
+ return run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_migrate_settings_internals,
+ argc, argv);
+}
+
+/**
+ * 'net rpc printer' entrypoint.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ **/
+
+int rpc_printer_migrate(struct net_context *c, int argc, const char **argv)
+{
+
+ /* ouch: when addriver and setdriver are called from within
+ rpc_printer_migrate_drivers_internals, the printer-queue already
+ *has* to exist */
+
+ struct functable func[] = {
+ {
+ "all",
+ rpc_printer_migrate_all,
+ NET_TRANSPORT_RPC,
+ "Migrate all from remote to local print server",
+ "net rpc printer migrate all\n"
+ " Migrate all from remote to local print server"
+ },
+ {
+ "drivers",
+ rpc_printer_migrate_drivers,
+ NET_TRANSPORT_RPC,
+ "Migrate drivers to local server",
+ "net rpc printer migrate drivers\n"
+ " Migrate drivers to local server"
+ },
+ {
+ "forms",
+ rpc_printer_migrate_forms,
+ NET_TRANSPORT_RPC,
+ "Migrate froms to local server",
+ "net rpc printer migrate forms\n"
+ " Migrate froms to local server"
+ },
+ {
+ "printers",
+ rpc_printer_migrate_printers,
+ NET_TRANSPORT_RPC,
+ "Migrate printers to local server",
+ "net rpc printer migrate printers\n"
+ " Migrate printers to local server"
+ },
+ {
+ "security",
+ rpc_printer_migrate_security,
+ NET_TRANSPORT_RPC,
+ "Mirgate printer ACLs to local server",
+ "net rpc printer migrate security\n"
+ " Mirgate printer ACLs to local server"
+ },
+ {
+ "settings",
+ rpc_printer_migrate_settings,
+ NET_TRANSPORT_RPC,
+ "Migrate printer settings to local server",
+ "net rpc printer migrate settings\n"
+ " Migrate printer settings to local server"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net rpc printer migrate",func);
+}
+
+
+/**
+ * List printers on a remote RPC server.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+static int rpc_printer_list(struct net_context *c, int argc, const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc printer list\n"
+ " List printers on a remote RPC server\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_list_internals,
+ argc, argv);
+}
+
+/**
+ * List printer-drivers on a remote RPC server.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+static int rpc_printer_driver_list(struct net_context *c, int argc,
+ const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc printer driver\n"
+ " List printer-drivers on a remote RPC server\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_driver_list_internals,
+ argc, argv);
+}
+
+/**
+ * Publish printer in ADS via MSRPC.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+static int rpc_printer_publish_publish(struct net_context *c, int argc,
+ const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc printer publish publish\n"
+ " Publish printer in ADS via MSRPC\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_publish_publish_internals,
+ argc, argv);
+}
+
+/**
+ * Update printer in ADS via MSRPC.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+static int rpc_printer_publish_update(struct net_context *c, int argc, const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc printer publish update\n"
+ " Update printer in ADS via MSRPC\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_publish_update_internals,
+ argc, argv);
+}
+
+/**
+ * UnPublish printer in ADS via MSRPC.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+static int rpc_printer_publish_unpublish(struct net_context *c, int argc,
+ const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc printer publish unpublish\n"
+ " UnPublish printer in ADS via MSRPC\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_publish_unpublish_internals,
+ argc, argv);
+}
+
+/**
+ * List published printers via MSRPC.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+static int rpc_printer_publish_list(struct net_context *c, int argc,
+ const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc printer publish list\n"
+ " List published printers via MSRPC\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_publish_list_internals,
+ argc, argv);
+}
+
+
+/**
+ * Publish printer in ADS.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ *
+ * @return A shell status integer (0 for success).
+ **/
+static int rpc_printer_publish(struct net_context *c, int argc,
+ const char **argv)
+{
+
+ struct functable func[] = {
+ {
+ "publish",
+ rpc_printer_publish_publish,
+ NET_TRANSPORT_RPC,
+ "Publish printer in AD",
+ "net rpc printer publish publish\n"
+ " Publish printer in AD"
+ },
+ {
+ "update",
+ rpc_printer_publish_update,
+ NET_TRANSPORT_RPC,
+ "Update printer in AD",
+ "net rpc printer publish update\n"
+ " Update printer in AD"
+ },
+ {
+ "unpublish",
+ rpc_printer_publish_unpublish,
+ NET_TRANSPORT_RPC,
+ "Unpublish printer",
+ "net rpc printer publish unpublish\n"
+ " Unpublish printer"
+ },
+ {
+ "list",
+ rpc_printer_publish_list,
+ NET_TRANSPORT_RPC,
+ "List published printers",
+ "net rpc printer publish list\n"
+ " List published printers"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ if (argc == 0) {
+ if (c->display_usage) {
+ d_printf("Usage:\n");
+ d_printf("net rpc printer publish\n"
+ " List published printers\n"
+ " Alias of net rpc printer publish list\n");
+ net_display_usage_from_functable(func);
+ return 0;
+ }
+ return run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_publish_list_internals,
+ argc, argv);
+ }
+
+ return net_run_function(c, argc, argv, "net rpc printer publish",func);
+
+}
+
+
+/**
+ * Display rpc printer help page.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ **/
+int rpc_printer_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("net rpc printer LIST [printer] [misc. options] [targets]\n"
+ "\tlists all printers on print-server\n\n");
+ d_printf("net rpc printer DRIVER [printer] [misc. options] [targets]\n"
+ "\tlists all printer-drivers on print-server\n\n");
+ d_printf("net rpc printer PUBLISH action [printer] [misc. options] [targets]\n"
+ "\tpublishes printer settings in Active Directory\n"
+ "\taction can be one of PUBLISH, UPDATE, UNPUBLISH or LIST\n\n");
+ d_printf("net rpc printer MIGRATE PRINTERS [printer] [misc. options] [targets]"
+ "\n\tmigrates printers from remote to local server\n\n");
+ d_printf("net rpc printer MIGRATE SETTINGS [printer] [misc. options] [targets]"
+ "\n\tmigrates printer-settings from remote to local server\n\n");
+ d_printf("net rpc printer MIGRATE DRIVERS [printer] [misc. options] [targets]"
+ "\n\tmigrates printer-drivers from remote to local server\n\n");
+ d_printf("net rpc printer MIGRATE FORMS [printer] [misc. options] [targets]"
+ "\n\tmigrates printer-forms from remote to local server\n\n");
+ d_printf("net rpc printer MIGRATE SECURITY [printer] [misc. options] [targets]"
+ "\n\tmigrates printer-ACLs from remote to local server\n\n");
+ d_printf("net rpc printer MIGRATE ALL [printer] [misc. options] [targets]"
+ "\n\tmigrates drivers, forms, queues, settings and acls from\n"
+ "\tremote to local print-server\n\n");
+ net_common_methods_usage(c, argc, argv);
+ net_common_flags_usage(c, argc, argv);
+ d_printf(
+ "\t-v or --verbose\t\t\tgive verbose output\n"
+ "\t --destination\t\tmigration target server (default: localhost)\n");
+
+ return -1;
+}
+
+/**
+ * 'net rpc printer' entrypoint.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ **/
+int net_rpc_printer(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "list",
+ rpc_printer_list,
+ NET_TRANSPORT_RPC,
+ "List all printers on print server",
+ "net rpc printer list\n"
+ " List all printers on print server"
+ },
+ {
+ "migrate",
+ rpc_printer_migrate,
+ NET_TRANSPORT_RPC,
+ "Migrate printer to local server",
+ "net rpc printer migrate\n"
+ " Migrate printer to local server"
+ },
+ {
+ "driver",
+ rpc_printer_driver_list,
+ NET_TRANSPORT_RPC,
+ "List printer drivers",
+ "net rpc printer driver\n"
+ " List printer drivers"
+ },
+ {
+ "publish",
+ rpc_printer_publish,
+ NET_TRANSPORT_RPC,
+ "Publish printer in AD",
+ "net rpc printer publish\n"
+ " Publish printer in AD"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ if (argc == 0) {
+ if (c->display_usage) {
+ d_printf("Usage:\n");
+ d_printf("net rpc printer\n"
+ " List printers\n");
+ net_display_usage_from_functable(func);
+ return 0;
+ }
+ return run_rpc_command(c, NULL, &syntax_spoolss, 0,
+ rpc_printer_list_internals,
+ argc, argv);
+ }
+
+ return net_run_function(c, argc, argv, "net rpc printer", func);
+}
+
+/**
+ * 'net rpc' entrypoint.
+ *
+ * @param c A net_context structure.
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped.
+ **/
+
+int net_rpc(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "audit",
+ net_rpc_audit,
+ NET_TRANSPORT_RPC,
+ "Modify global audit settings",
+ "net rpc audit\n"
+ " Modify global audit settings"
+ },
+ {
+ "info",
+ net_rpc_info,
+ NET_TRANSPORT_RPC,
+ "Show basic info about a domain",
+ "net rpc info\n"
+ " Show basic info about a domain"
+ },
+ {
+ "join",
+ net_rpc_join,
+ NET_TRANSPORT_RPC,
+ "Join a domain",
+ "net rpc join\n"
+ " Join a domain"
+ },
+ {
+ "oldjoin",
+ net_rpc_oldjoin,
+ NET_TRANSPORT_RPC,
+ "Join a domain created in server manager",
+ "net rpc oldjoin\n"
+ " Join a domain created in server manager"
+ },
+ {
+ "testjoin",
+ net_rpc_testjoin,
+ NET_TRANSPORT_RPC,
+ "Test that a join is valid",
+ "net rpc testjoin\n"
+ " Test that a join is valid"
+ },
+ {
+ "user",
+ net_rpc_user,
+ NET_TRANSPORT_RPC,
+ "List/modify users",
+ "net rpc user\n"
+ " List/modify users"
+ },
+ {
+ "password",
+ rpc_user_password,
+ NET_TRANSPORT_RPC,
+ "Change a user password",
+ "net rpc password\n"
+ " Change a user password\n"
+ " Alias for net rpc user password"
+ },
+ {
+ "group",
+ net_rpc_group,
+ NET_TRANSPORT_RPC,
+ "List/modify groups",
+ "net rpc group\n"
+ " List/modify groups"
+ },
+ {
+ "share",
+ net_rpc_share,
+ NET_TRANSPORT_RPC,
+ "List/modify shares",
+ "net rpc share\n"
+ " List/modify shares"
+ },
+ {
+ "file",
+ net_rpc_file,
+ NET_TRANSPORT_RPC,
+ "List open files",
+ "net rpc file\n"
+ " List open files"
+ },
+ {
+ "printer",
+ net_rpc_printer,
+ NET_TRANSPORT_RPC,
+ "List/modify printers",
+ "net rpc printer\n"
+ " List/modify printers"
+ },
+ {
+ "changetrustpw",
+ net_rpc_changetrustpw,
+ NET_TRANSPORT_RPC,
+ "Change trust account password",
+ "net rpc changetrustpw\n"
+ " Change trust account password"
+ },
+ {
+ "trustdom",
+ rpc_trustdom,
+ NET_TRANSPORT_RPC,
+ "Modify domain trusts",
+ "net rpc trustdom\n"
+ " Modify domain trusts"
+ },
+ {
+ "abortshutdown",
+ rpc_shutdown_abort,
+ NET_TRANSPORT_RPC,
+ "Abort a remote shutdown",
+ "net rpc abortshutdown\n"
+ " Abort a remote shutdown"
+ },
+ {
+ "shutdown",
+ rpc_shutdown,
+ NET_TRANSPORT_RPC,
+ "Shutdown a remote server",
+ "net rpc shutdown\n"
+ " Shutdown a remote server"
+ },
+ {
+ "samdump",
+ rpc_samdump,
+ NET_TRANSPORT_RPC,
+ "Dump SAM data of remote NT PDC",
+ "net rpc samdump\n"
+ " Dump SAM data of remote NT PDC"
+ },
+ {
+ "vampire",
+ rpc_vampire,
+ NET_TRANSPORT_RPC,
+ "Sync a remote NT PDC's data into local passdb",
+ "net rpc vampire\n"
+ " Sync a remote NT PDC's data into local passdb"
+ },
+ {
+ "getsid",
+ net_rpc_getsid,
+ NET_TRANSPORT_RPC,
+ "Fetch the domain sid into local secrets.tdb",
+ "net rpc getsid\n"
+ " Fetch the domain sid into local secrets.tdb"
+ },
+ {
+ "rights",
+ net_rpc_rights,
+ NET_TRANSPORT_RPC,
+ "Manage privileges assigned to SID",
+ "net rpc rights\n"
+ " Manage privileges assigned to SID"
+ },
+ {
+ "service",
+ net_rpc_service,
+ NET_TRANSPORT_RPC,
+ "Start/stop/query remote services",
+ "net rpc service\n"
+ " Start/stop/query remote services"
+ },
+ {
+ "registry",
+ net_rpc_registry,
+ NET_TRANSPORT_RPC,
+ "Manage registry hives",
+ "net rpc registry\n"
+ " Manage registry hives"
+ },
+ {
+ "shell",
+ net_rpc_shell,
+ NET_TRANSPORT_RPC,
+ "Open interactive shell on remote server",
+ "net rpc shell\n"
+ " Open interactive shell on remote server"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+ return net_run_function(c, argc, argv, "net rpc", func);
+}
diff --git a/source3/utils/net_rpc_audit.c b/source3/utils/net_rpc_audit.c
new file mode 100644
index 0000000000..dc4c796c17
--- /dev/null
+++ b/source3/utils/net_rpc_audit.c
@@ -0,0 +1,494 @@
+/*
+ Samba Unix/Linux SMB client library
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) 2006,2008 Guenther Deschner
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "includes.h"
+#include "utils/net.h"
+
+/********************************************************************
+********************************************************************/
+
+static int net_help_audit(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("net rpc audit list View configured Auditing policies\n");
+ d_printf("net rpc audit enable Enable Auditing\n");
+ d_printf("net rpc audit disable Disable Auditing\n");
+ d_printf("net rpc audit get <category> View configured Auditing policy setting\n");
+ d_printf("net rpc audit set <category> <policy> Set Auditing policies\n\n");
+ d_printf("\tcategory can be one of: SYSTEM, LOGON, OBJECT, PRIVILEGE, PROCESS, POLICY, SAM, DIRECTORY or ACCOUNT\n");
+ d_printf("\tpolicy can be one of: SUCCESS, FAILURE, ALL or NONE\n\n");
+
+ return -1;
+}
+
+/********************************************************************
+********************************************************************/
+
+static void print_auditing_category(const char *policy, const char *value)
+{
+ fstring padding;
+ int pad_len, col_len = 30;
+
+ if (policy == NULL) {
+ policy = "Unknown";
+ }
+ if (value == NULL) {
+ value = "Invalid";
+ }
+
+ /* calculate padding space for d_printf to look nicer */
+ pad_len = col_len - strlen(policy);
+ padding[pad_len] = 0;
+ do padding[--pad_len] = ' '; while (pad_len > 0);
+
+ d_printf("\t%s%s%s\n", policy, padding, value);
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_audit_get_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ union lsa_PolicyInformation *info = NULL;
+ int i;
+ uint32_t audit_category;
+
+ if (argc < 1 || argc > 2) {
+ d_printf("insufficient arguments\n");
+ net_help_audit(c, argc, argv);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!get_audit_category_from_param(argv[0], &audit_category)) {
+ d_printf("invalid auditing category: %s\n", argv[0]);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ result = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
+ &pol,
+ LSA_POLICY_INFO_AUDIT_EVENTS,
+ &info);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ for (i=0; i < info->audit_events.count; i++) {
+
+ const char *val = NULL, *policy = NULL;
+
+ if (i != audit_category) {
+ continue;
+ }
+
+ val = audit_policy_str(mem_ctx, info->audit_events.settings[i]);
+ policy = audit_description_str(i);
+ print_auditing_category(policy, val);
+ }
+
+ done:
+ if (!NT_STATUS_IS_OK(result)) {
+ d_printf("failed to get auditing policy: %s\n",
+ nt_errstr(result));
+ }
+
+ return result;
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_audit_set_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ union lsa_PolicyInformation *info = NULL;
+ uint32_t audit_policy, audit_category;
+
+ if (argc < 2 || argc > 3) {
+ d_printf("insufficient arguments\n");
+ net_help_audit(c, argc, argv);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!get_audit_category_from_param(argv[0], &audit_category)) {
+ d_printf("invalid auditing category: %s\n", argv[0]);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ audit_policy = LSA_AUDIT_POLICY_CLEAR;
+
+ if (strequal(argv[1], "Success")) {
+ audit_policy |= LSA_AUDIT_POLICY_SUCCESS;
+ } else if (strequal(argv[1], "Failure")) {
+ audit_policy |= LSA_AUDIT_POLICY_FAILURE;
+ } else if (strequal(argv[1], "All")) {
+ audit_policy |= LSA_AUDIT_POLICY_ALL;
+ } else if (strequal(argv[1], "None")) {
+ audit_policy = LSA_AUDIT_POLICY_CLEAR;
+ } else {
+ d_printf("invalid auditing policy: %s\n", argv[1]);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ result = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
+ &pol,
+ LSA_POLICY_INFO_AUDIT_EVENTS,
+ &info);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ info->audit_events.settings[audit_category] = audit_policy;
+
+ result = rpccli_lsa_SetInfoPolicy(pipe_hnd, mem_ctx,
+ &pol,
+ LSA_POLICY_INFO_AUDIT_EVENTS,
+ info);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
+ &pol,
+ LSA_POLICY_INFO_AUDIT_EVENTS,
+ &info);
+ {
+ const char *val = audit_policy_str(mem_ctx, info->audit_events.settings[audit_category]);
+ const char *policy = audit_description_str(audit_category);
+ print_auditing_category(policy, val);
+ }
+
+ done:
+ if (!NT_STATUS_IS_OK(result)) {
+ d_printf("failed to set audit policy: %s\n", nt_errstr(result));
+ }
+
+ return result;
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_audit_enable_internal_ext(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv,
+ bool enable)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ union lsa_PolicyInformation *info = NULL;
+
+ result = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
+ &pol,
+ LSA_POLICY_INFO_AUDIT_EVENTS,
+ &info);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ info->audit_events.auditing_mode = enable;
+
+ result = rpccli_lsa_SetInfoPolicy(pipe_hnd, mem_ctx,
+ &pol,
+ LSA_POLICY_INFO_AUDIT_EVENTS,
+ info);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ done:
+ if (!NT_STATUS_IS_OK(result)) {
+ d_printf("failed to %s audit policy: %s\n",
+ enable ? "enable":"disable", nt_errstr(result));
+ }
+
+ return result;
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_audit_disable_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ return rpc_audit_enable_internal_ext(pipe_hnd, mem_ctx, argc, argv,
+ false);
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_audit_enable_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ return rpc_audit_enable_internal_ext(pipe_hnd, mem_ctx, argc, argv,
+ true);
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_audit_list_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ union lsa_PolicyInformation *info = NULL;
+ int i;
+
+ result = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
+ &pol,
+ LSA_POLICY_INFO_AUDIT_EVENTS,
+ &info);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ printf("Auditing:\t\t");
+ switch (info->audit_events.auditing_mode) {
+ case true:
+ printf("Enabled");
+ break;
+ case false:
+ printf("Disabled");
+ break;
+ default:
+ printf("unknown (%d)", info->audit_events.auditing_mode);
+ break;
+ }
+ printf("\n");
+
+ printf("Auditing categories:\t%d\n", info->audit_events.count);
+ printf("Auditing settings:\n");
+
+ for (i=0; i < info->audit_events.count; i++) {
+ const char *val = audit_policy_str(mem_ctx, info->audit_events.settings[i]);
+ const char *policy = audit_description_str(i);
+ print_auditing_category(policy, val);
+ }
+
+ done:
+ if (!NT_STATUS_IS_OK(result)) {
+ d_printf("failed to list auditing policies: %s\n",
+ nt_errstr(result));
+ }
+
+ return result;
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_audit_get(struct net_context *c, int argc, const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc audit get\n"
+ " View configured audit setting\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_lsarpc.syntax_id, 0,
+ rpc_audit_get_internal, argc, argv);
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_audit_set(struct net_context *c, int argc, const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc audit set\n"
+ " Set audit policies\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_lsarpc.syntax_id, 0,
+ rpc_audit_set_internal, argc, argv);
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_audit_enable(struct net_context *c, int argc, const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc audit enable\n"
+ " Enable auditing\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_lsarpc.syntax_id, 0,
+ rpc_audit_enable_internal, argc, argv);
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_audit_disable(struct net_context *c, int argc, const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc audit disable\n"
+ " Disable auditing\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_lsarpc.syntax_id, 0,
+ rpc_audit_disable_internal, argc, argv);
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_audit_list(struct net_context *c, int argc, const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc audit list\n"
+ " List auditing settings\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_lsarpc.syntax_id, 0,
+ rpc_audit_list_internal, argc, argv);
+}
+
+/********************************************************************
+********************************************************************/
+
+int net_rpc_audit(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "get",
+ rpc_audit_get,
+ NET_TRANSPORT_RPC,
+ "View configured auditing settings",
+ "net rpc audit get\n"
+ " View configured auditing settings"
+ },
+ {
+ "set",
+ rpc_audit_set,
+ NET_TRANSPORT_RPC,
+ "Set auditing policies",
+ "net rpc audit set\n"
+ " Set auditing policies"
+ },
+ {
+ "enable",
+ rpc_audit_enable,
+ NET_TRANSPORT_RPC,
+ "Enable auditing",
+ "net rpc audit enable\n"
+ " Enable auditing"
+ },
+ {
+ "disable",
+ rpc_audit_disable,
+ NET_TRANSPORT_RPC,
+ "Disable auditing",
+ "net rpc audit disable\n"
+ " Disable auditing"
+ },
+ {
+ "list",
+ rpc_audit_list,
+ NET_TRANSPORT_RPC,
+ "List configured auditing settings",
+ "net rpc audit list\n"
+ " List configured auditing settings"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net rpc audit", func);
+}
diff --git a/source3/utils/net_rpc_join.c b/source3/utils/net_rpc_join.c
new file mode 100644
index 0000000000..5bc38f979f
--- /dev/null
+++ b/source3/utils/net_rpc_join.c
@@ -0,0 +1,506 @@
+/*
+ Samba Unix/Linux SMB client library
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
+ Copyright (C) Tim Potter 2001
+ Copyright (C) 2008 Guenther Deschner
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "includes.h"
+#include "utils/net.h"
+
+/* Macro for checking RPC error codes to make things more readable */
+
+#define CHECK_RPC_ERR(rpc, msg) \
+ if (!NT_STATUS_IS_OK(result = rpc)) { \
+ DEBUG(0, (msg ": %s\n", nt_errstr(result))); \
+ goto done; \
+ }
+
+#define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
+ if (!NT_STATUS_IS_OK(result = rpc)) { \
+ DEBUG(0, debug_args); \
+ goto done; \
+ }
+
+/**
+ * confirm that a domain join is still valid
+ *
+ * @return A shell status integer (0 for success)
+ *
+ **/
+NTSTATUS net_rpc_join_ok(struct net_context *c, const char *domain,
+ const char *server, struct sockaddr_storage *pss)
+{
+ enum security_types sec;
+ unsigned int conn_flags = NET_FLAGS_PDC;
+ uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_hnd = NULL;
+ struct rpc_pipe_client *netlogon_pipe = NULL;
+ NTSTATUS ntret = NT_STATUS_UNSUCCESSFUL;
+
+ sec = (enum security_types)lp_security();
+
+ if (sec == SEC_ADS) {
+ /* Connect to IPC$ using machine account's credentials. We don't use anonymous
+ connection here, as it may be denied by server's local policy. */
+ net_use_machine_account(c);
+
+ } else {
+ /* some servers (e.g. WinNT) don't accept machine-authenticated
+ smb connections */
+ conn_flags |= NET_FLAGS_ANONYMOUS;
+ }
+
+ /* Connect to remote machine */
+ ntret = net_make_ipc_connection_ex(c, domain, server, pss, conn_flags,
+ &cli);
+ if (!NT_STATUS_IS_OK(ntret)) {
+ return ntret;
+ }
+
+ /* Setup the creds as though we're going to do schannel... */
+ ntret = get_schannel_session_key(cli, domain, &neg_flags,
+ &netlogon_pipe);
+
+ /* We return NT_STATUS_INVALID_NETWORK_RESPONSE if the server is refusing
+ to negotiate schannel, but the creds were set up ok. That'll have to do. */
+
+ if (!NT_STATUS_IS_OK(ntret)) {
+ if (NT_STATUS_EQUAL(ntret, NT_STATUS_INVALID_NETWORK_RESPONSE)) {
+ cli_shutdown(cli);
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(0,("net_rpc_join_ok: failed to get schannel session "
+ "key from server %s for domain %s. Error was %s\n",
+ cli->desthost, domain, nt_errstr(ntret) ));
+ cli_shutdown(cli);
+ return ntret;
+ }
+ }
+
+ /* Only do the rest of the schannel test if the client is allowed to do this. */
+ if (!lp_client_schannel()) {
+ cli_shutdown(cli);
+ /* We're good... */
+ return ntret;
+ }
+
+ ntret = cli_rpc_pipe_open_schannel_with_key(
+ cli, &ndr_table_netlogon.syntax_id, PIPE_AUTH_LEVEL_PRIVACY,
+ domain, netlogon_pipe->dc, &pipe_hnd);
+
+ if (!NT_STATUS_IS_OK(ntret)) {
+ DEBUG(0,("net_rpc_join_ok: failed to open schannel session "
+ "on netlogon pipe to server %s for domain %s. Error was %s\n",
+ cli->desthost, domain, nt_errstr(ntret) ));
+ /*
+ * Note: here, we have:
+ * (pipe_hnd != NULL) if and only if NT_STATUS_IS_OK(ntret)
+ */
+ }
+
+ cli_shutdown(cli);
+ return ntret;
+}
+
+/**
+ * Join a domain using the administrator username and password
+ *
+ * @param argc Standard main() style argc
+ * @param argc Standard main() style argv. Initial components are already
+ * stripped. Currently not used.
+ * @return A shell status integer (0 for success)
+ *
+ **/
+
+int net_rpc_join_newstyle(struct net_context *c, int argc, const char **argv)
+{
+
+ /* libsmb variables */
+
+ struct cli_state *cli;
+ TALLOC_CTX *mem_ctx;
+ uint32 acb_info = ACB_WSTRUST;
+ uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+ uint32 sec_channel_type;
+ struct rpc_pipe_client *pipe_hnd = NULL;
+
+ /* rpc variables */
+
+ POLICY_HND lsa_pol, sam_pol, domain_pol, user_pol;
+ DOM_SID *domain_sid;
+ uint32 user_rid;
+
+ /* Password stuff */
+
+ char *clear_trust_password = NULL;
+ struct samr_CryptPassword crypt_pwd;
+ uchar md4_trust_password[16];
+ union samr_UserInfo set_info;
+
+ /* Misc */
+
+ NTSTATUS result;
+ int retval = 1;
+ const char *domain = NULL;
+ char *acct_name;
+ struct lsa_String lsa_acct_name;
+ uint32 acct_flags=0;
+ uint32_t access_granted = 0;
+ union lsa_PolicyInformation *info = NULL;
+ struct samr_Ids user_rids;
+ struct samr_Ids name_types;
+
+ /* check what type of join */
+ if (argc >= 0) {
+ sec_channel_type = get_sec_channel_type(argv[0]);
+ } else {
+ sec_channel_type = get_sec_channel_type(NULL);
+ }
+
+ switch (sec_channel_type) {
+ case SEC_CHAN_WKSTA:
+ acb_info = ACB_WSTRUST;
+ break;
+ case SEC_CHAN_BDC:
+ acb_info = ACB_SVRTRUST;
+ break;
+#if 0
+ case SEC_CHAN_DOMAIN:
+ acb_info = ACB_DOMTRUST;
+ break;
+#endif
+ }
+
+ /* Make authenticated connection to remote machine */
+
+ result = net_make_ipc_connection(c, NET_FLAGS_PDC, &cli);
+ if (!NT_STATUS_IS_OK(result)) {
+ return 1;
+ }
+
+ if (!(mem_ctx = talloc_init("net_rpc_join_newstyle"))) {
+ DEBUG(0, ("Could not initialise talloc context\n"));
+ goto done;
+ }
+
+ /* Fetch domain sid */
+
+ result = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
+ &pipe_hnd);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n",
+ nt_errstr(result) ));
+ goto done;
+ }
+
+
+ CHECK_RPC_ERR(rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &lsa_pol),
+ "error opening lsa policy handle");
+
+ CHECK_RPC_ERR(rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
+ &lsa_pol,
+ LSA_POLICY_INFO_ACCOUNT_DOMAIN,
+ &info),
+ "error querying info policy");
+
+ domain = info->account_domain.name.string;
+ domain_sid = info->account_domain.sid;
+
+ rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
+ TALLOC_FREE(pipe_hnd); /* Done with this pipe */
+
+ /* Bail out if domain didn't get set. */
+ if (!domain) {
+ DEBUG(0, ("Could not get domain name.\n"));
+ goto done;
+ }
+
+ /* Create domain user */
+ result = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
+ &pipe_hnd);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
+ nt_errstr(result) ));
+ goto done;
+ }
+
+ CHECK_RPC_ERR(rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &sam_pol),
+ "could not connect to SAM database");
+
+
+ CHECK_RPC_ERR(rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &sam_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ domain_sid,
+ &domain_pol),
+ "could not open domain");
+
+ /* Create domain user */
+ if ((acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname())) == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ strlower_m(acct_name);
+
+ init_lsa_String(&lsa_acct_name, acct_name);
+
+ acct_flags = SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
+ SEC_STD_WRITE_DAC | SEC_STD_DELETE |
+ SAMR_USER_ACCESS_SET_PASSWORD |
+ SAMR_USER_ACCESS_GET_ATTRIBUTES |
+ SAMR_USER_ACCESS_SET_ATTRIBUTES;
+
+ DEBUG(10, ("Creating account with flags: %d\n",acct_flags));
+
+ result = rpccli_samr_CreateUser2(pipe_hnd, mem_ctx,
+ &domain_pol,
+ &lsa_acct_name,
+ acb_info,
+ acct_flags,
+ &user_pol,
+ &access_granted,
+ &user_rid);
+
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, NT_STATUS_USER_EXISTS)) {
+ d_fprintf(stderr, "Creation of workstation account failed\n");
+
+ /* If NT_STATUS_ACCESS_DENIED then we have a valid
+ username/password combo but the user does not have
+ administrator access. */
+
+ if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
+ d_fprintf(stderr, "User specified does not have administrator privileges\n");
+
+ goto done;
+ }
+
+ /* We *must* do this.... don't ask... */
+
+ if (NT_STATUS_IS_OK(result)) {
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
+ }
+
+ CHECK_RPC_ERR_DEBUG(rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 1,
+ &lsa_acct_name,
+ &user_rids,
+ &name_types),
+ ("error looking up rid for user %s: %s\n",
+ acct_name, nt_errstr(result)));
+
+ if (name_types.ids[0] != SID_NAME_USER) {
+ DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types.ids[0]));
+ goto done;
+ }
+
+ user_rid = user_rids.ids[0];
+
+ /* Open handle on user */
+
+ CHECK_RPC_ERR_DEBUG(
+ rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
+ &domain_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ user_rid,
+ &user_pol),
+ ("could not re-open existing user %s: %s\n",
+ acct_name, nt_errstr(result)));
+
+ /* Create a random machine account password */
+
+ {
+ char *str;
+ str = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
+ clear_trust_password = SMB_STRDUP(str);
+ E_md4hash(clear_trust_password, md4_trust_password);
+ }
+
+ /* Set password on machine account */
+
+ init_samr_CryptPassword(clear_trust_password,
+ &cli->user_session_key,
+ &crypt_pwd);
+
+ init_samr_user_info24(&set_info.info24, crypt_pwd.data, 24);
+
+ CHECK_RPC_ERR(rpccli_samr_SetUserInfo2(pipe_hnd, mem_ctx,
+ &user_pol,
+ 24,
+ &set_info),
+ "error setting trust account password");
+
+ /* Why do we have to try to (re-)set the ACB to be the same as what
+ we passed in the samr_create_dom_user() call? When a NT
+ workstation is joined to a domain by an administrator the
+ acb_info is set to 0x80. For a normal user with "Add
+ workstations to the domain" rights the acb_info is 0x84. I'm
+ not sure whether it is supposed to make a difference or not. NT
+ seems to cope with either value so don't bomb out if the set
+ userinfo2 level 0x10 fails. -tpot */
+
+ set_info.info16.acct_flags = acb_info;
+
+ /* Ignoring the return value is necessary for joining a domain
+ as a normal user with "Add workstation to domain" privilege. */
+
+ result = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
+ &user_pol,
+ 16,
+ &set_info);
+
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
+ TALLOC_FREE(pipe_hnd); /* Done with this pipe */
+
+ /* Now check the whole process from top-to-bottom */
+
+ result = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id,
+ &pipe_hnd);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("Error connecting to NETLOGON pipe. Error was %s\n",
+ nt_errstr(result) ));
+ goto done;
+ }
+
+ result = rpccli_netlogon_setup_creds(pipe_hnd,
+ cli->desthost, /* server name */
+ domain, /* domain */
+ global_myname(), /* client name */
+ global_myname(), /* machine account name */
+ md4_trust_password,
+ sec_channel_type,
+ &neg_flags);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0, ("Error in domain join verification (credential setup failed): %s\n\n",
+ nt_errstr(result)));
+
+ if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) &&
+ (sec_channel_type == SEC_CHAN_BDC) ) {
+ d_fprintf(stderr, "Please make sure that no computer account\n"
+ "named like this machine (%s) exists in the domain\n",
+ global_myname());
+ }
+
+ goto done;
+ }
+
+ /* We can only check the schannel connection if the client is allowed
+ to do this and the server supports it. If not, just assume success
+ (after all the rpccli_netlogon_setup_creds() succeeded, and we'll
+ do the same again (setup creds) in net_rpc_join_ok(). JRA. */
+
+ if (lp_client_schannel() && (neg_flags & NETLOGON_NEG_SCHANNEL)) {
+ struct rpc_pipe_client *netlogon_schannel_pipe;
+
+ result = cli_rpc_pipe_open_schannel_with_key(
+ cli, &ndr_table_netlogon.syntax_id,
+ PIPE_AUTH_LEVEL_PRIVACY, domain, pipe_hnd->dc,
+ &netlogon_schannel_pipe);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0, ("Error in domain join verification (schannel setup failed): %s\n\n",
+ nt_errstr(result)));
+
+ if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) &&
+ (sec_channel_type == SEC_CHAN_BDC) ) {
+ d_fprintf(stderr, "Please make sure that no computer account\n"
+ "named like this machine (%s) exists in the domain\n",
+ global_myname());
+ }
+
+ goto done;
+ }
+ TALLOC_FREE(netlogon_schannel_pipe);
+ }
+
+ TALLOC_FREE(pipe_hnd);
+
+ /* Now store the secret in the secrets database */
+
+ strupper_m(CONST_DISCARD(char *, domain));
+
+ if (!secrets_store_domain_sid(domain, domain_sid)) {
+ DEBUG(0, ("error storing domain sid for %s\n", domain));
+ goto done;
+ }
+
+ if (!secrets_store_machine_password(clear_trust_password, domain, sec_channel_type)) {
+ DEBUG(0, ("error storing plaintext domain secrets for %s\n", domain));
+ }
+
+ /* double-check, connection from scratch */
+ result = net_rpc_join_ok(c, domain, cli->desthost, &cli->dest_ss);
+ retval = NT_STATUS_IS_OK(result) ? 0 : -1;
+
+done:
+
+ /* Display success or failure */
+
+ if (domain) {
+ if (retval != 0) {
+ fprintf(stderr,"Unable to join domain %s.\n",domain);
+ } else {
+ printf("Joined domain %s.\n",domain);
+ }
+ }
+
+ cli_shutdown(cli);
+
+ SAFE_FREE(clear_trust_password);
+
+ return retval;
+}
+
+/**
+ * check that a join is OK
+ *
+ * @return A shell status integer (0 for success)
+ *
+ **/
+int net_rpc_testjoin(struct net_context *c, int argc, const char **argv)
+{
+ char *domain = smb_xstrdup(c->opt_target_workgroup);
+ NTSTATUS nt_status;
+
+ if (c->display_usage) {
+ d_printf("Usage\n"
+ "net rpc testjoin\n"
+ " Test if a join is OK\n");
+ return 0;
+ }
+
+ /* Display success or failure */
+ nt_status = net_rpc_join_ok(c, domain, NULL, NULL);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ fprintf(stderr,"Join to domain '%s' is not valid: %s\n",
+ domain, nt_errstr(nt_status));
+ free(domain);
+ return -1;
+ }
+
+ printf("Join to '%s' is OK\n",domain);
+ free(domain);
+ return 0;
+}
diff --git a/source3/utils/net_rpc_printer.c b/source3/utils/net_rpc_printer.c
new file mode 100644
index 0000000000..f4b305d4ab
--- /dev/null
+++ b/source3/utils/net_rpc_printer.c
@@ -0,0 +1,2517 @@
+/*
+ Samba Unix/Linux SMB client library
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) 2004 Guenther Deschner (gd@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "utils/net.h"
+
+struct table_node {
+ const char *long_archi;
+ const char *short_archi;
+ int version;
+};
+
+
+/* support itanium as well */
+static const struct table_node archi_table[]= {
+
+ {"Windows 4.0", "WIN40", 0 },
+ {"Windows NT x86", "W32X86", 2 },
+ {"Windows NT x86", "W32X86", 3 },
+ {"Windows NT R4000", "W32MIPS", 2 },
+ {"Windows NT Alpha_AXP", "W32ALPHA", 2 },
+ {"Windows NT PowerPC", "W32PPC", 2 },
+ {"Windows IA64", "IA64", 3 },
+ {"Windows x64", "x64", 3 },
+ {NULL, "", -1 }
+};
+
+
+/**
+ * This display-printdriver-functions was borrowed from rpcclient/cmd_spoolss.c.
+ * It is here for debugging purpose and should be removed later on.
+ **/
+
+/****************************************************************************
+ Printer info level 3 display function.
+****************************************************************************/
+
+static void display_print_driver_3(DRIVER_INFO_3 *i1)
+{
+ fstring name = "";
+ fstring architecture = "";
+ fstring driverpath = "";
+ fstring datafile = "";
+ fstring configfile = "";
+ fstring helpfile = "";
+ fstring dependentfiles = "";
+ fstring monitorname = "";
+ fstring defaultdatatype = "";
+
+ int length=0;
+ bool valid = true;
+
+ if (i1 == NULL)
+ return;
+
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
+ rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE);
+ rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE);
+ rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE);
+ rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE);
+ rpcstr_pull(helpfile, i1->helpfile.buffer, sizeof(helpfile), -1, STR_TERMINATE);
+ rpcstr_pull(monitorname, i1->monitorname.buffer, sizeof(monitorname), -1, STR_TERMINATE);
+ rpcstr_pull(defaultdatatype, i1->defaultdatatype.buffer, sizeof(defaultdatatype), -1, STR_TERMINATE);
+
+ d_printf ("Printer Driver Info 3:\n");
+ d_printf ("\tVersion: [%x]\n", i1->version);
+ d_printf ("\tDriver Name: [%s]\n",name);
+ d_printf ("\tArchitecture: [%s]\n", architecture);
+ d_printf ("\tDriver Path: [%s]\n", driverpath);
+ d_printf ("\tDatafile: [%s]\n", datafile);
+ d_printf ("\tConfigfile: [%s]\n", configfile);
+ d_printf ("\tHelpfile: [%s]\n\n", helpfile);
+
+ while (valid) {
+ rpcstr_pull(dependentfiles, i1->dependentfiles+length, sizeof(dependentfiles), -1, STR_TERMINATE);
+
+ length+=strlen(dependentfiles)+1;
+
+ if (strlen(dependentfiles) > 0) {
+ d_printf ("\tDependentfiles: [%s]\n", dependentfiles);
+ } else {
+ valid = false;
+ }
+ }
+
+ printf ("\n");
+
+ d_printf ("\tMonitorname: [%s]\n", monitorname);
+ d_printf ("\tDefaultdatatype: [%s]\n\n", defaultdatatype);
+
+ return;
+}
+
+static void display_reg_value(const char *subkey, REGISTRY_VALUE value)
+{
+ char *text;
+
+ switch(value.type) {
+ case REG_DWORD:
+ d_printf("\t[%s:%s]: REG_DWORD: 0x%08x\n", subkey, value.valuename,
+ *((uint32 *) value.data_p));
+ break;
+
+ case REG_SZ:
+ rpcstr_pull_talloc(talloc_tos(),
+ &text,
+ value.data_p,
+ value.size,
+ STR_TERMINATE);
+ if (!text) {
+ break;
+ }
+ d_printf("\t[%s:%s]: REG_SZ: %s\n", subkey, value.valuename, text);
+ break;
+
+ case REG_BINARY:
+ d_printf("\t[%s:%s]: REG_BINARY: unknown length value not displayed\n",
+ subkey, value.valuename);
+ break;
+
+ case REG_MULTI_SZ: {
+ uint32 i, num_values;
+ char **values;
+
+ if (!W_ERROR_IS_OK(reg_pull_multi_sz(NULL, value.data_p,
+ value.size, &num_values,
+ &values))) {
+ d_printf("reg_pull_multi_sz failed\n");
+ break;
+ }
+
+ for (i=0; i<num_values; i++) {
+ d_printf("%s\n", values[i]);
+ }
+ TALLOC_FREE(values);
+ break;
+ }
+
+ default:
+ d_printf("\t%s: unknown type %d\n", value.valuename, value.type);
+ }
+
+}
+
+/**
+ * Copies ACLs, DOS-attributes and timestamps from one
+ * file or directory from one connected share to another connected share
+ *
+ * @param c A net_context structure
+ * @param mem_ctx A talloc-context
+ * @param cli_share_src A connected cli_state
+ * @param cli_share_dst A connected cli_state
+ * @param src_file The source file-name
+ * @param dst_file The destination file-name
+ * @param copy_acls Whether to copy acls
+ * @param copy_attrs Whether to copy DOS attributes
+ * @param copy_timestamps Whether to preserve timestamps
+ * @param is_file Whether this file is a file or a dir
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+NTSTATUS net_copy_fileattr(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct cli_state *cli_share_src,
+ struct cli_state *cli_share_dst,
+ const char *src_name, const char *dst_name,
+ bool copy_acls, bool copy_attrs,
+ bool copy_timestamps, bool is_file)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ int fnum_src = 0;
+ int fnum_dst = 0;
+ SEC_DESC *sd = NULL;
+ uint16 attr;
+ time_t f_atime, f_ctime, f_mtime;
+
+
+ if (!copy_timestamps && !copy_acls && !copy_attrs)
+ return NT_STATUS_OK;
+
+ /* open file/dir on the originating server */
+
+ DEBUGADD(3,("opening %s %s on originating server\n",
+ is_file?"file":"dir", src_name));
+
+ fnum_src = cli_nt_create(cli_share_src, src_name, READ_CONTROL_ACCESS);
+ if (fnum_src == -1) {
+ DEBUGADD(0,("cannot open %s %s on originating server %s\n",
+ is_file?"file":"dir", src_name, cli_errstr(cli_share_src)));
+ nt_status = cli_nt_error(cli_share_src);
+ goto out;
+ }
+
+
+ if (copy_acls) {
+
+ /* get the security descriptor */
+ sd = cli_query_secdesc(cli_share_src, fnum_src, mem_ctx);
+ if (!sd) {
+ DEBUG(0,("failed to get security descriptor: %s\n",
+ cli_errstr(cli_share_src)));
+ nt_status = cli_nt_error(cli_share_src);
+ goto out;
+ }
+
+ if (c->opt_verbose && DEBUGLEVEL >= 3)
+ display_sec_desc(sd);
+ }
+
+
+ if (copy_attrs || copy_timestamps) {
+
+ /* get file attributes */
+ if (!cli_getattrE(cli_share_src, fnum_src, &attr, NULL,
+ &f_ctime, &f_atime, &f_mtime)) {
+ DEBUG(0,("failed to get file-attrs: %s\n",
+ cli_errstr(cli_share_src)));
+ nt_status = cli_nt_error(cli_share_src);
+ goto out;
+ }
+ }
+
+
+ /* open the file/dir on the destination server */
+
+ fnum_dst = cli_nt_create(cli_share_dst, dst_name, WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS);
+ if (fnum_dst == -1) {
+ DEBUG(0,("failed to open %s on the destination server: %s: %s\n",
+ is_file?"file":"dir", dst_name, cli_errstr(cli_share_dst)));
+ nt_status = cli_nt_error(cli_share_dst);
+ goto out;
+ }
+
+ if (copy_timestamps) {
+
+ /* set timestamps */
+ if (!cli_setattrE(cli_share_dst, fnum_dst, f_ctime, f_atime, f_mtime)) {
+ DEBUG(0,("failed to set file-attrs (timestamps): %s\n",
+ cli_errstr(cli_share_dst)));
+ nt_status = cli_nt_error(cli_share_dst);
+ goto out;
+ }
+ }
+
+ if (copy_acls) {
+
+ /* set acls */
+ if (!cli_set_secdesc(cli_share_dst, fnum_dst, sd)) {
+ DEBUG(0,("could not set secdesc on %s: %s\n",
+ dst_name, cli_errstr(cli_share_dst)));
+ nt_status = cli_nt_error(cli_share_dst);
+ goto out;
+ }
+ }
+
+ if (copy_attrs) {
+
+ /* set attrs */
+ if (!cli_setatr(cli_share_dst, dst_name, attr, 0)) {
+ DEBUG(0,("failed to set file-attrs: %s\n",
+ cli_errstr(cli_share_dst)));
+ nt_status = cli_nt_error(cli_share_dst);
+ goto out;
+ }
+ }
+
+
+ /* closing files */
+
+ if (!cli_close(cli_share_src, fnum_src)) {
+ d_fprintf(stderr, "could not close %s on originating server: %s\n",
+ is_file?"file":"dir", cli_errstr(cli_share_src));
+ nt_status = cli_nt_error(cli_share_src);
+ goto out;
+ }
+
+ if (!cli_close(cli_share_dst, fnum_dst)) {
+ d_fprintf(stderr, "could not close %s on destination server: %s\n",
+ is_file?"file":"dir", cli_errstr(cli_share_dst));
+ nt_status = cli_nt_error(cli_share_dst);
+ goto out;
+ }
+
+
+ nt_status = NT_STATUS_OK;
+
+out:
+
+ /* cleaning up */
+ if (fnum_src)
+ cli_close(cli_share_src, fnum_src);
+
+ if (fnum_dst)
+ cli_close(cli_share_dst, fnum_dst);
+
+ return nt_status;
+}
+
+/**
+ * Copy a file or directory from a connected share to another connected share
+ *
+ * @param c A net_context structure
+ * @param mem_ctx A talloc-context
+ * @param cli_share_src A connected cli_state
+ * @param cli_share_dst A connected cli_state
+ * @param src_file The source file-name
+ * @param dst_file The destination file-name
+ * @param copy_acls Whether to copy acls
+ * @param copy_attrs Whether to copy DOS attributes
+ * @param copy_timestamps Whether to preserve timestamps
+ * @param is_file Whether this file is a file or a dir
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+NTSTATUS net_copy_file(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct cli_state *cli_share_src,
+ struct cli_state *cli_share_dst,
+ const char *src_name, const char *dst_name,
+ bool copy_acls, bool copy_attrs,
+ bool copy_timestamps, bool is_file)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ int fnum_src = 0;
+ int fnum_dst = 0;
+ static int io_bufsize = 64512;
+ int read_size = io_bufsize;
+ char *data = NULL;
+ off_t nread = 0;
+
+
+ if (!src_name || !dst_name)
+ goto out;
+
+ if (cli_share_src == NULL || cli_share_dst == NULL)
+ goto out;
+
+ /* open on the originating server */
+ DEBUGADD(3,("opening %s %s on originating server\n",
+ is_file ? "file":"dir", src_name));
+ if (is_file)
+ fnum_src = cli_open(cli_share_src, src_name, O_RDONLY, DENY_NONE);
+ else
+ fnum_src = cli_nt_create(cli_share_src, src_name, READ_CONTROL_ACCESS);
+
+ if (fnum_src == -1) {
+ DEBUGADD(0,("cannot open %s %s on originating server %s\n",
+ is_file ? "file":"dir",
+ src_name, cli_errstr(cli_share_src)));
+ nt_status = cli_nt_error(cli_share_src);
+ goto out;
+ }
+
+
+ if (is_file) {
+
+ /* open file on the destination server */
+ DEBUGADD(3,("opening file %s on destination server\n", dst_name));
+ fnum_dst = cli_open(cli_share_dst, dst_name,
+ O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
+
+ if (fnum_dst == -1) {
+ DEBUGADD(1,("cannot create file %s on destination server: %s\n",
+ dst_name, cli_errstr(cli_share_dst)));
+ nt_status = cli_nt_error(cli_share_dst);
+ goto out;
+ }
+
+ /* allocate memory */
+ if (!(data = (char *)SMB_MALLOC(read_size))) {
+ d_fprintf(stderr, "malloc fail for size %d\n", read_size);
+ nt_status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ }
+
+
+ if (c->opt_verbose) {
+
+ d_printf("copying [\\\\%s\\%s%s] => [\\\\%s\\%s%s] "
+ "%s ACLs and %s DOS Attributes %s\n",
+ cli_share_src->desthost, cli_share_src->share, src_name,
+ cli_share_dst->desthost, cli_share_dst->share, dst_name,
+ copy_acls ? "with" : "without",
+ copy_attrs ? "with" : "without",
+ copy_timestamps ? "(preserving timestamps)" : "" );
+ }
+
+
+ while (is_file) {
+
+ /* copying file */
+ int n, ret;
+ n = cli_read(cli_share_src, fnum_src, data, nread,
+ read_size);
+
+ if (n <= 0)
+ break;
+
+ ret = cli_write(cli_share_dst, fnum_dst, 0, data,
+ nread, n);
+
+ if (n != ret) {
+ d_fprintf(stderr, "Error writing file: %s\n",
+ cli_errstr(cli_share_dst));
+ nt_status = cli_nt_error(cli_share_dst);
+ goto out;
+ }
+
+ nread += n;
+ }
+
+
+ if (!is_file && !cli_chkpath(cli_share_dst, dst_name)) {
+
+ /* creating dir */
+ DEBUGADD(3,("creating dir %s on the destination server\n",
+ dst_name));
+
+ if (!cli_mkdir(cli_share_dst, dst_name)) {
+ DEBUG(0,("cannot create directory %s: %s\n",
+ dst_name, cli_errstr(cli_share_dst)));
+ nt_status = NT_STATUS_NO_SUCH_FILE;
+ }
+
+ if (!cli_chkpath(cli_share_dst, dst_name)) {
+ d_fprintf(stderr, "cannot check for directory %s: %s\n",
+ dst_name, cli_errstr(cli_share_dst));
+ goto out;
+ }
+ }
+
+
+ /* closing files */
+ if (!cli_close(cli_share_src, fnum_src)) {
+ d_fprintf(stderr, "could not close file on originating server: %s\n",
+ cli_errstr(cli_share_src));
+ nt_status = cli_nt_error(cli_share_src);
+ goto out;
+ }
+
+ if (is_file && !cli_close(cli_share_dst, fnum_dst)) {
+ d_fprintf(stderr, "could not close file on destination server: %s\n",
+ cli_errstr(cli_share_dst));
+ nt_status = cli_nt_error(cli_share_dst);
+ goto out;
+ }
+
+ /* possibly we have to copy some file-attributes / acls / sd */
+ nt_status = net_copy_fileattr(c, mem_ctx, cli_share_src, cli_share_dst,
+ src_name, dst_name, copy_acls,
+ copy_attrs, copy_timestamps, is_file);
+ if (!NT_STATUS_IS_OK(nt_status))
+ goto out;
+
+
+ nt_status = NT_STATUS_OK;
+
+out:
+
+ /* cleaning up */
+ if (fnum_src)
+ cli_close(cli_share_src, fnum_src);
+
+ if (fnum_dst)
+ cli_close(cli_share_dst, fnum_dst);
+
+ SAFE_FREE(data);
+
+ return nt_status;
+}
+
+/**
+ * Copy a driverfile from on connected share to another connected share
+ * This silently assumes that a driver-file is picked up from
+ *
+ * \\src_server\print$\{arch}\{version}\file
+ *
+ * and copied to
+ *
+ * \\dst_server\print$\{arch}\file
+ *
+ * to be added via setdriver-calls later.
+ * @param c A net_context structure
+ * @param mem_ctx A talloc-context
+ * @param cli_share_src A cli_state connected to source print$-share
+ * @param cli_share_dst A cli_state connected to destination print$-share
+ * @param file The file-name to be copied
+ * @param short_archi The name of the driver-architecture (short form)
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS net_copy_driverfile(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct cli_state *cli_share_src,
+ struct cli_state *cli_share_dst,
+ char *file, const char *short_archi) {
+
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ const char *p;
+ char *src_name;
+ char *dst_name;
+ char *version;
+ char *filename;
+ char *tok;
+
+ /* scroll through the file until we have the part
+ beyond archi_table.short_archi */
+ p = file;
+ while (next_token_talloc(mem_ctx, &p, &tok, "\\")) {
+ if (strequal(tok, short_archi)) {
+ next_token_talloc(mem_ctx, &p, &version, "\\");
+ next_token_talloc(mem_ctx, &p, &filename, "\\");
+ }
+ }
+
+ /* build source file name */
+ if (asprintf(&src_name, "\\%s\\%s\\%s", short_archi, version, filename) < 0 )
+ return NT_STATUS_NO_MEMORY;
+
+
+ /* create destination file name */
+ if (asprintf(&dst_name, "\\%s\\%s", short_archi, filename) < 0 )
+ return NT_STATUS_NO_MEMORY;
+
+
+ /* finally copy the file */
+ nt_status = net_copy_file(c, mem_ctx, cli_share_src, cli_share_dst,
+ src_name, dst_name, false, false, false, true);
+ if (!NT_STATUS_IS_OK(nt_status))
+ goto out;
+
+ nt_status = NT_STATUS_OK;
+
+out:
+ SAFE_FREE(src_name);
+ SAFE_FREE(dst_name);
+
+ return nt_status;
+}
+
+/**
+ * Check for existing Architecture directory on a given server
+ *
+ * @param cli_share A cli_state connected to a print$-share
+ * @param short_archi The Architecture for the print-driver
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS check_arch_dir(struct cli_state *cli_share, const char *short_archi)
+{
+
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ char *dir;
+
+ if (asprintf(&dir, "\\%s", short_archi) < 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(10,("creating print-driver dir for architecture: %s\n",
+ short_archi));
+
+ if (!cli_mkdir(cli_share, dir)) {
+ DEBUG(1,("cannot create directory %s: %s\n",
+ dir, cli_errstr(cli_share)));
+ nt_status = NT_STATUS_NO_SUCH_FILE;
+ }
+
+ if (!cli_chkpath(cli_share, dir)) {
+ d_fprintf(stderr, "cannot check %s: %s\n",
+ dir, cli_errstr(cli_share));
+ goto out;
+ }
+
+ nt_status = NT_STATUS_OK;
+
+out:
+ SAFE_FREE(dir);
+ return nt_status;
+}
+
+/**
+ * Copy a print-driver (level 3) from one connected print$-share to another
+ * connected print$-share
+ *
+ * @param c A net_context structure
+ * @param mem_ctx A talloc-context
+ * @param cli_share_src A cli_state connected to a print$-share
+ * @param cli_share_dst A cli_state connected to a print$-share
+ * @param short_archi The Architecture for the print-driver
+ * @param i1 The DRIVER_INFO_3-struct
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS copy_print_driver_3(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct cli_state *cli_share_src,
+ struct cli_state *cli_share_dst,
+ const char *short_archi, DRIVER_INFO_3 *i1)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ int length = 0;
+ bool valid = true;
+
+ fstring name = "";
+ fstring driverpath = "";
+ fstring datafile = "";
+ fstring configfile = "";
+ fstring helpfile = "";
+ fstring dependentfiles = "";
+
+ if (i1 == NULL)
+ return nt_status;
+
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
+ rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE);
+ rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE);
+ rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE);
+ rpcstr_pull(helpfile, i1->helpfile.buffer, sizeof(helpfile), -1, STR_TERMINATE);
+
+
+ if (c->opt_verbose)
+ d_printf("copying driver: [%s], for architecture: [%s], version: [%d]\n",
+ name, short_archi, i1->version);
+
+ nt_status = net_copy_driverfile(c, mem_ctx, cli_share_src, cli_share_dst,
+ driverpath, short_archi);
+ if (!NT_STATUS_IS_OK(nt_status))
+ return nt_status;
+
+ nt_status = net_copy_driverfile(c, mem_ctx, cli_share_src, cli_share_dst,
+ datafile, short_archi);
+ if (!NT_STATUS_IS_OK(nt_status))
+ return nt_status;
+
+ nt_status = net_copy_driverfile(c, mem_ctx, cli_share_src, cli_share_dst,
+ configfile, short_archi);
+ if (!NT_STATUS_IS_OK(nt_status))
+ return nt_status;
+
+ nt_status = net_copy_driverfile(c, mem_ctx, cli_share_src, cli_share_dst,
+ helpfile, short_archi);
+ if (!NT_STATUS_IS_OK(nt_status))
+ return nt_status;
+
+ while (valid) {
+
+ rpcstr_pull(dependentfiles, i1->dependentfiles+length, sizeof(dependentfiles), -1, STR_TERMINATE);
+ length += strlen(dependentfiles)+1;
+
+ if (strlen(dependentfiles) > 0) {
+
+ nt_status = net_copy_driverfile(c, mem_ctx,
+ cli_share_src, cli_share_dst,
+ dependentfiles, short_archi);
+ if (!NT_STATUS_IS_OK(nt_status))
+ return nt_status;
+ } else {
+ valid = false;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * net_spoolss-functions
+ * =====================
+ *
+ * the net_spoolss-functions aim to simplify spoolss-client-functions
+ * required during the migration-process wrt buffer-sizes, returned
+ * error-codes, etc.
+ *
+ * this greatly reduces the complexitiy of the migrate-functions.
+ *
+ **/
+
+static bool net_spoolss_enum_printers(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ char *name,
+ uint32 flags,
+ uint32 level,
+ uint32 *num_printers,
+ PRINTER_INFO_CTR *ctr)
+{
+ WERROR result;
+
+ /* enum printers */
+ result = rpccli_spoolss_enum_printers(pipe_hnd, mem_ctx, name, flags,
+ level, num_printers, ctr);
+
+ if (!W_ERROR_IS_OK(result)) {
+ printf("cannot enum printers: %s\n", dos_errstr(result));
+ return false;
+ }
+
+ return true;
+}
+
+static bool net_spoolss_open_printer_ex(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ const char *printername,
+ uint32 access_required,
+ const char *username,
+ POLICY_HND *hnd)
+{
+ WERROR result;
+ fstring servername, printername2;
+
+ slprintf(servername, sizeof(servername)-1, "\\\\%s",
+ pipe_hnd->desthost);
+
+ fstrcpy(printername2, servername);
+ fstrcat(printername2, "\\");
+ fstrcat(printername2, printername);
+
+ DEBUG(10,("connecting to: %s as %s for %s and access: %x\n",
+ servername, username, printername2, access_required));
+
+ /* open printer */
+ result = rpccli_spoolss_open_printer_ex(pipe_hnd, mem_ctx, printername2,
+ "", access_required,
+ servername, username, hnd);
+
+ /* be more verbose */
+ if (W_ERROR_V(result) == W_ERROR_V(WERR_ACCESS_DENIED)) {
+ d_fprintf(stderr, "no access to printer [%s] on [%s] for user [%s] granted\n",
+ printername2, servername, username);
+ return false;
+ }
+
+ if (!W_ERROR_IS_OK(result)) {
+ d_fprintf(stderr, "cannot open printer %s on server %s: %s\n",
+ printername2, servername, dos_errstr(result));
+ return false;
+ }
+
+ DEBUG(2,("got printer handle for printer: %s, server: %s\n",
+ printername2, servername));
+
+ return true;
+}
+
+static bool net_spoolss_getprinter(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd,
+ uint32 level,
+ PRINTER_INFO_CTR *ctr)
+{
+ WERROR result;
+
+ /* getprinter call */
+ result = rpccli_spoolss_getprinter(pipe_hnd, mem_ctx, hnd, level, ctr);
+
+ if (!W_ERROR_IS_OK(result)) {
+ printf("cannot get printer-info: %s\n", dos_errstr(result));
+ return false;
+ }
+
+ return true;
+}
+
+static bool net_spoolss_setprinter(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd,
+ uint32 level,
+ PRINTER_INFO_CTR *ctr)
+{
+ WERROR result;
+
+ /* setprinter call */
+ result = rpccli_spoolss_setprinter(pipe_hnd, mem_ctx, hnd, level, ctr, 0);
+
+ if (!W_ERROR_IS_OK(result)) {
+ printf("cannot set printer-info: %s\n", dos_errstr(result));
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool net_spoolss_setprinterdata(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd,
+ REGISTRY_VALUE *value)
+{
+ WERROR result;
+
+ /* setprinterdata call */
+ result = rpccli_spoolss_setprinterdata(pipe_hnd, mem_ctx, hnd, value);
+
+ if (!W_ERROR_IS_OK(result)) {
+ printf ("unable to set printerdata: %s\n", dos_errstr(result));
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool net_spoolss_enumprinterkey(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd,
+ const char *keyname,
+ uint16 **keylist)
+{
+ WERROR result;
+
+ /* enumprinterkey call */
+ result = rpccli_spoolss_enumprinterkey(pipe_hnd, mem_ctx, hnd, keyname, keylist, NULL);
+
+ if (!W_ERROR_IS_OK(result)) {
+ printf("enumprinterkey failed: %s\n", dos_errstr(result));
+ return false;
+ }
+
+ return true;
+}
+
+static bool net_spoolss_enumprinterdataex(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ uint32 offered,
+ POLICY_HND *hnd,
+ const char *keyname,
+ REGVAL_CTR *ctr)
+{
+ WERROR result;
+
+ /* enumprinterdataex call */
+ result = rpccli_spoolss_enumprinterdataex(pipe_hnd, mem_ctx, hnd, keyname, ctr);
+
+ if (!W_ERROR_IS_OK(result)) {
+ printf("enumprinterdataex failed: %s\n", dos_errstr(result));
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool net_spoolss_setprinterdataex(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd,
+ char *keyname,
+ REGISTRY_VALUE *value)
+{
+ WERROR result;
+
+ /* setprinterdataex call */
+ result = rpccli_spoolss_setprinterdataex(pipe_hnd, mem_ctx, hnd,
+ keyname, value);
+
+ if (!W_ERROR_IS_OK(result)) {
+ printf("could not set printerdataex: %s\n", dos_errstr(result));
+ return false;
+ }
+
+ return true;
+}
+
+static bool net_spoolss_enumforms(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd,
+ int level,
+ uint32 *num_forms,
+ FORM_1 **forms)
+{
+ WERROR result;
+
+ /* enumforms call */
+ result = rpccli_spoolss_enumforms(pipe_hnd, mem_ctx, hnd, level, num_forms, forms);
+
+ if (!W_ERROR_IS_OK(result)) {
+ printf("could not enum forms: %s\n", dos_errstr(result));
+ return false;
+ }
+
+ return true;
+}
+
+static bool net_spoolss_enumprinterdrivers (struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ uint32 level, const char *env,
+ uint32 *num_drivers,
+ PRINTER_DRIVER_CTR *ctr)
+{
+ WERROR result;
+
+ /* enumprinterdrivers call */
+ result = rpccli_spoolss_enumprinterdrivers(
+ pipe_hnd, mem_ctx, level,
+ env, num_drivers, ctr);
+
+ if (!W_ERROR_IS_OK(result)) {
+ printf("cannot enum drivers: %s\n", dos_errstr(result));
+ return false;
+ }
+
+ return true;
+}
+
+static bool net_spoolss_getprinterdriver(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *hnd, uint32 level,
+ const char *env, int version,
+ PRINTER_DRIVER_CTR *ctr)
+{
+ WERROR result;
+
+ /* getprinterdriver call */
+ result = rpccli_spoolss_getprinterdriver(
+ pipe_hnd, mem_ctx, hnd, level,
+ env, version, ctr);
+
+ if (!W_ERROR_IS_OK(result)) {
+ DEBUG(1,("cannot get driver (for architecture: %s): %s\n",
+ env, dos_errstr(result)));
+ if (W_ERROR_V(result) != W_ERROR_V(WERR_UNKNOWN_PRINTER_DRIVER) &&
+ W_ERROR_V(result) != W_ERROR_V(WERR_INVALID_ENVIRONMENT)) {
+ printf("cannot get driver: %s\n", dos_errstr(result));
+ }
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool net_spoolss_addprinterdriver(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx, uint32 level,
+ PRINTER_DRIVER_CTR *ctr)
+{
+ WERROR result;
+
+ /* addprinterdriver call */
+ result = rpccli_spoolss_addprinterdriver(pipe_hnd, mem_ctx, level, ctr);
+
+ /* be more verbose */
+ if (W_ERROR_V(result) == W_ERROR_V(WERR_ACCESS_DENIED)) {
+ printf("You are not allowed to add drivers\n");
+ return false;
+ }
+ if (!W_ERROR_IS_OK(result)) {
+ printf("cannot add driver: %s\n", dos_errstr(result));
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * abstraction function to get uint32 num_printers and PRINTER_INFO_CTR ctr
+ * for a single printer or for all printers depending on argc/argv
+ **/
+
+static bool get_printer_info(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int level,
+ int argc,
+ const char **argv,
+ uint32 *num_printers,
+ PRINTER_INFO_CTR *ctr)
+{
+
+ POLICY_HND hnd;
+
+ /* no arguments given, enumerate all printers */
+ if (argc == 0) {
+
+ if (!net_spoolss_enum_printers(pipe_hnd, mem_ctx, NULL,
+ PRINTER_ENUM_LOCAL|PRINTER_ENUM_SHARED,
+ level, num_printers, ctr))
+ return false;
+
+ goto out;
+ }
+
+
+ /* argument given, get a single printer by name */
+ if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, argv[0],
+ MAXIMUM_ALLOWED_ACCESS,
+ pipe_hnd->auth->user_name,
+ &hnd))
+ return false;
+
+ if (!net_spoolss_getprinter(pipe_hnd, mem_ctx, &hnd, level, ctr)) {
+ rpccli_spoolss_close_printer(pipe_hnd, mem_ctx, &hnd);
+ return false;
+ }
+
+ rpccli_spoolss_close_printer(pipe_hnd, mem_ctx, &hnd);
+
+ *num_printers = 1;
+
+out:
+ DEBUG(3,("got %d printers\n", *num_printers));
+
+ return true;
+
+}
+
+/**
+ * List print-queues (including local printers that are not shared)
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param c A net_context structure
+ * @param domain_sid The domain sid aquired from the remote server
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destoyed on compleation of the function.
+ * @param argc Standard main() style argc
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+NTSTATUS rpc_printer_list_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ uint32 i, num_printers;
+ uint32 level = 2;
+ char *printername, *sharename;
+ PRINTER_INFO_CTR ctr;
+
+ printf("listing printers\n");
+
+ if (!get_printer_info(pipe_hnd, mem_ctx, level, argc, argv, &num_printers, &ctr))
+ return nt_status;
+
+ for (i = 0; i < num_printers; i++) {
+ /* do some initialization */
+ rpcstr_pull_talloc(mem_ctx,
+ &printername,
+ ctr.printers_2[i].printername.buffer,
+ -1,
+ STR_TERMINATE);
+ rpcstr_pull_talloc(mem_ctx,
+ &sharename,
+ ctr.printers_2[i].sharename.buffer,
+ -1,
+ STR_TERMINATE);
+
+ if (printername && sharename) {
+ d_printf("printer %d: %s, shared as: %s\n",
+ i+1, printername, sharename);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * List printer-drivers from a server
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param c A net_context structure
+ * @param domain_sid The domain sid aquired from the remote server
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destoyed on compleation of the function.
+ * @param argc Standard main() style argc
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+NTSTATUS rpc_printer_driver_list_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ uint32 i;
+ uint32 level = 3;
+ PRINTER_DRIVER_CTR drv_ctr_enum;
+ int d;
+
+ ZERO_STRUCT(drv_ctr_enum);
+
+ printf("listing printer-drivers\n");
+
+ for (i=0; archi_table[i].long_archi!=NULL; i++) {
+
+ uint32 num_drivers;
+
+ /* enum remote drivers */
+ if (!net_spoolss_enumprinterdrivers(pipe_hnd, mem_ctx, level,
+ archi_table[i].long_archi,
+ &num_drivers, &drv_ctr_enum)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (num_drivers == 0) {
+ d_printf ("no drivers found on server for architecture: [%s].\n",
+ archi_table[i].long_archi);
+ continue;
+ }
+
+ d_printf("got %d printer-drivers for architecture: [%s]\n",
+ num_drivers, archi_table[i].long_archi);
+
+
+ /* do something for all drivers for architecture */
+ for (d = 0; d < num_drivers; d++) {
+ display_print_driver_3(&(drv_ctr_enum.info3[d]));
+ }
+ }
+
+ nt_status = NT_STATUS_OK;
+
+done:
+ return nt_status;
+
+}
+
+/**
+ * Publish print-queues with args-wrapper
+ *
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destoyed on compleation of the function.
+ * @param argc Standard main() style argc
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped
+ * @param action
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS rpc_printer_publish_internals_args(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv,
+ uint32 action)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ uint32 i, num_printers;
+ uint32 level = 7;
+ char *printername, *sharename;
+ PRINTER_INFO_CTR ctr, ctr_pub;
+ POLICY_HND hnd;
+ bool got_hnd = false;
+ WERROR result;
+ const char *action_str;
+
+ if (!get_printer_info(pipe_hnd, mem_ctx, 2, argc, argv, &num_printers, &ctr))
+ return nt_status;
+
+ for (i = 0; i < num_printers; i++) {
+ /* do some initialization */
+ rpcstr_pull_talloc(mem_ctx,
+ &printername,
+ ctr.printers_2[i].printername.buffer,
+ -1,
+ STR_TERMINATE);
+ rpcstr_pull_talloc(mem_ctx,
+ &sharename,
+ ctr.printers_2[i].sharename.buffer,
+ -1,
+ STR_TERMINATE);
+ if (!printername || !sharename) {
+ goto done;
+ }
+
+ /* open printer handle */
+ if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
+ PRINTER_ALL_ACCESS, pipe_hnd->auth->user_name, &hnd))
+ goto done;
+
+ got_hnd = true;
+
+ /* check for existing dst printer */
+ if (!net_spoolss_getprinter(pipe_hnd, mem_ctx, &hnd, level, &ctr_pub))
+ goto done;
+
+ /* check action and set string */
+ switch (action) {
+ case SPOOL_DS_PUBLISH:
+ action_str = "published";
+ break;
+ case SPOOL_DS_UPDATE:
+ action_str = "updated";
+ break;
+ case SPOOL_DS_UNPUBLISH:
+ action_str = "unpublished";
+ break;
+ default:
+ action_str = "unknown action";
+ printf("unkown action: %d\n", action);
+ break;
+ }
+
+ ctr_pub.printers_7->action = action;
+
+ result = rpccli_spoolss_setprinter(pipe_hnd, mem_ctx, &hnd, level, &ctr_pub, 0);
+ if (!W_ERROR_IS_OK(result) && (W_ERROR_V(result) != W_ERROR_V(WERR_IO_PENDING))) {
+ printf("cannot set printer-info: %s\n", dos_errstr(result));
+ goto done;
+ }
+
+ printf("successfully %s printer %s in Active Directory\n", action_str, sharename);
+ }
+
+ nt_status = NT_STATUS_OK;
+
+done:
+ if (got_hnd)
+ rpccli_spoolss_close_printer(pipe_hnd, mem_ctx, &hnd);
+
+ return nt_status;
+}
+
+NTSTATUS rpc_printer_publish_publish_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ return rpc_printer_publish_internals_args(pipe_hnd, mem_ctx, argc, argv, SPOOL_DS_PUBLISH);
+}
+
+NTSTATUS rpc_printer_publish_unpublish_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ return rpc_printer_publish_internals_args(pipe_hnd, mem_ctx, argc, argv, SPOOL_DS_UNPUBLISH);
+}
+
+NTSTATUS rpc_printer_publish_update_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ return rpc_printer_publish_internals_args(pipe_hnd, mem_ctx, argc, argv, SPOOL_DS_UPDATE);
+}
+
+/**
+ * List print-queues w.r.t. their publishing state
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param c A net_context structure
+ * @param domain_sid The domain sid aquired from the remote server
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destoyed on compleation of the function.
+ * @param argc Standard main() style argc
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+NTSTATUS rpc_printer_publish_list_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ uint32 i, num_printers;
+ uint32 level = 7;
+ char *printername, *sharename;
+ char *guid;
+ PRINTER_INFO_CTR ctr, ctr_pub;
+ POLICY_HND hnd;
+ bool got_hnd = false;
+ int state;
+
+ if (!get_printer_info(pipe_hnd, mem_ctx, 2, argc, argv, &num_printers, &ctr))
+ return nt_status;
+
+ for (i = 0; i < num_printers; i++) {
+ ZERO_STRUCT(ctr_pub);
+
+ /* do some initialization */
+ rpcstr_pull_talloc(mem_ctx,
+ &printername,
+ ctr.printers_2[i].printername.buffer,
+ -1,
+ STR_TERMINATE);
+ rpcstr_pull_talloc(mem_ctx,
+ &sharename,
+ ctr.printers_2[i].sharename.buffer,
+ -1,
+ STR_TERMINATE);
+ if (!printername || !sharename) {
+ goto done;
+ }
+
+ /* open printer handle */
+ if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
+ PRINTER_ALL_ACCESS, cli->user_name, &hnd))
+ goto done;
+
+ got_hnd = true;
+
+ /* check for existing dst printer */
+ if (!net_spoolss_getprinter(pipe_hnd, mem_ctx, &hnd, level, &ctr_pub))
+ goto done;
+
+ rpcstr_pull_talloc(mem_ctx,
+ &guid,
+ ctr_pub.printers_7->guid.buffer,
+ -1,
+ STR_TERMINATE);
+ if (!guid) {
+ goto done;
+ }
+ state = ctr_pub.printers_7->action;
+ switch (state) {
+ case SPOOL_DS_PUBLISH:
+ printf("printer [%s] is published", sharename);
+ if (c->opt_verbose)
+ printf(", guid: %s", guid);
+ printf("\n");
+ break;
+ case SPOOL_DS_UNPUBLISH:
+ printf("printer [%s] is unpublished\n", sharename);
+ break;
+ case SPOOL_DS_UPDATE:
+ printf("printer [%s] is currently updating\n", sharename);
+ break;
+ default:
+ printf("unkown state: %d\n", state);
+ break;
+ }
+ }
+
+ nt_status = NT_STATUS_OK;
+
+done:
+ if (got_hnd)
+ rpccli_spoolss_close_printer(pipe_hnd, mem_ctx, &hnd);
+
+ return nt_status;
+}
+
+/**
+ * Migrate Printer-ACLs from a source server to the destination server
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param c A net_context structure
+ * @param domain_sid The domain sid aquired from the remote server
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destoyed on compleation of the function.
+ * @param argc Standard main() style argc
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+NTSTATUS rpc_printer_migrate_security_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ /* TODO: what now, info2 or info3 ?
+ convince jerry that we should add clientside setacls level 3 at least
+ */
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ uint32 i = 0;
+ uint32 num_printers;
+ uint32 level = 2;
+ char *printername, *sharename;
+ bool got_hnd_src = false;
+ bool got_hnd_dst = false;
+ struct rpc_pipe_client *pipe_hnd_dst = NULL;
+ POLICY_HND hnd_src, hnd_dst;
+ PRINTER_INFO_CTR ctr_src, ctr_dst, ctr_enum;
+ struct cli_state *cli_dst = NULL;
+
+ ZERO_STRUCT(ctr_src);
+
+ DEBUG(3,("copying printer ACLs\n"));
+
+ /* connect destination PI_SPOOLSS */
+ nt_status = connect_dst_pipe(c, &cli_dst, &pipe_hnd_dst,
+ &syntax_spoolss);
+ if (!NT_STATUS_IS_OK(nt_status))
+ return nt_status;
+
+
+ /* enum source printers */
+ if (!get_printer_info(pipe_hnd, mem_ctx, level, argc, argv, &num_printers, &ctr_enum)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!num_printers) {
+ printf ("no printers found on server.\n");
+ nt_status = NT_STATUS_OK;
+ goto done;
+ }
+
+ /* do something for all printers */
+ for (i = 0; i < num_printers; i++) {
+ /* do some initialization */
+ rpcstr_pull_talloc(mem_ctx,
+ &printername,
+ ctr_enum.printers_2[i].printername.buffer,
+ -1,
+ STR_TERMINATE);
+ rpcstr_pull_talloc(mem_ctx,
+ &sharename,
+ ctr_enum.printers_2[i].sharename.buffer,
+ -1,
+ STR_TERMINATE);
+ if (!printername || !sharename) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* we can reset NT_STATUS here because we do not
+ get any real NT_STATUS-codes anymore from now on */
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+
+ d_printf("migrating printer ACLs for: [%s] / [%s]\n",
+ printername, sharename);
+
+ /* according to msdn you have specify these access-rights
+ to see the security descriptor
+ - READ_CONTROL (DACL)
+ - ACCESS_SYSTEM_SECURITY (SACL)
+ */
+
+ /* open src printer handle */
+ if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
+ MAXIMUM_ALLOWED_ACCESS, cli->user_name, &hnd_src))
+ goto done;
+
+ got_hnd_src = true;
+
+ /* open dst printer handle */
+ if (!net_spoolss_open_printer_ex(pipe_hnd_dst, mem_ctx, sharename,
+ PRINTER_ALL_ACCESS, cli_dst->user_name, &hnd_dst))
+ goto done;
+
+ got_hnd_dst = true;
+
+ /* check for existing dst printer */
+ if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, level, &ctr_dst))
+ goto done;
+
+ /* check for existing src printer */
+ if (!net_spoolss_getprinter(pipe_hnd, mem_ctx, &hnd_src, 3, &ctr_src))
+ goto done;
+
+ /* Copy Security Descriptor */
+
+ /* copy secdesc (info level 2) */
+ ctr_dst.printers_2->devmode = NULL;
+ ctr_dst.printers_2->secdesc = dup_sec_desc(mem_ctx, ctr_src.printers_3->secdesc);
+
+ if (c->opt_verbose)
+ display_sec_desc(ctr_dst.printers_2->secdesc);
+
+ if (!net_spoolss_setprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, 2, &ctr_dst))
+ goto done;
+
+ DEBUGADD(1,("\tSetPrinter of SECDESC succeeded\n"));
+
+
+ /* close printer handles here */
+ if (got_hnd_src) {
+ rpccli_spoolss_close_printer(pipe_hnd, mem_ctx, &hnd_src);
+ got_hnd_src = false;
+ }
+
+ if (got_hnd_dst) {
+ rpccli_spoolss_close_printer(pipe_hnd_dst, mem_ctx, &hnd_dst);
+ got_hnd_dst = false;
+ }
+
+ }
+
+ nt_status = NT_STATUS_OK;
+
+done:
+
+ if (got_hnd_src) {
+ rpccli_spoolss_close_printer(pipe_hnd, mem_ctx, &hnd_src);
+ }
+
+ if (got_hnd_dst) {
+ rpccli_spoolss_close_printer(pipe_hnd_dst, mem_ctx, &hnd_dst);
+ }
+
+ if (cli_dst) {
+ cli_shutdown(cli_dst);
+ }
+ return nt_status;
+}
+
+/**
+ * Migrate printer-forms from a src server to the dst server
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param c A net_context structure
+ * @param domain_sid The domain sid aquired from the remote server
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destoyed on compleation of the function.
+ * @param argc Standard main() style argc
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+NTSTATUS rpc_printer_migrate_forms_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ WERROR result;
+ uint32 i, f;
+ uint32 num_printers;
+ uint32 level = 1;
+ char *printername, *sharename;
+ bool got_hnd_src = false;
+ bool got_hnd_dst = false;
+ struct rpc_pipe_client *pipe_hnd_dst = NULL;
+ POLICY_HND hnd_src, hnd_dst;
+ PRINTER_INFO_CTR ctr_enum, ctr_dst;
+ uint32 num_forms;
+ FORM_1 *forms;
+ struct cli_state *cli_dst = NULL;
+
+ ZERO_STRUCT(ctr_enum);
+
+ DEBUG(3,("copying forms\n"));
+
+ /* connect destination PI_SPOOLSS */
+ nt_status = connect_dst_pipe(c, &cli_dst, &pipe_hnd_dst,
+ &syntax_spoolss);
+ if (!NT_STATUS_IS_OK(nt_status))
+ return nt_status;
+
+ /* enum src printers */
+ if (!get_printer_info(pipe_hnd, mem_ctx, 2, argc, argv, &num_printers, &ctr_enum)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!num_printers) {
+ printf ("no printers found on server.\n");
+ nt_status = NT_STATUS_OK;
+ goto done;
+ }
+
+ /* do something for all printers */
+ for (i = 0; i < num_printers; i++) {
+ /* do some initialization */
+ rpcstr_pull_talloc(mem_ctx,
+ &printername,
+ ctr_enum.printers_2[i].printername.buffer,
+ -1,
+ STR_TERMINATE);
+ rpcstr_pull_talloc(mem_ctx,
+ &sharename,
+ ctr_enum.printers_2[i].sharename.buffer,
+ -1,
+ STR_TERMINATE);
+ if (!printername || !sharename) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ /* we can reset NT_STATUS here because we do not
+ get any real NT_STATUS-codes anymore from now on */
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+
+ d_printf("migrating printer forms for: [%s] / [%s]\n",
+ printername, sharename);
+
+
+ /* open src printer handle */
+ if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
+ MAXIMUM_ALLOWED_ACCESS, cli->user_name, &hnd_src))
+ goto done;
+
+ got_hnd_src = true;
+
+
+ /* open dst printer handle */
+ if (!net_spoolss_open_printer_ex(pipe_hnd_dst, mem_ctx, sharename,
+ PRINTER_ALL_ACCESS, cli->user_name, &hnd_dst))
+ goto done;
+
+ got_hnd_dst = true;
+
+
+ /* check for existing dst printer */
+ if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, level, &ctr_dst))
+ goto done;
+
+ /* finally migrate forms */
+ if (!net_spoolss_enumforms(pipe_hnd, mem_ctx, &hnd_src, level, &num_forms, &forms))
+ goto done;
+
+ DEBUG(1,("got %d forms for printer\n", num_forms));
+
+
+ for (f = 0; f < num_forms; f++) {
+
+ FORM form;
+ fstring form_name;
+
+ /* only migrate FORM_PRINTER types, according to jerry
+ FORM_BUILTIN-types are hard-coded in samba */
+ if (forms[f].flag != FORM_PRINTER)
+ continue;
+
+ if (forms[f].name.buffer)
+ rpcstr_pull(form_name, forms[f].name.buffer,
+ sizeof(form_name), -1, STR_TERMINATE);
+
+ if (c->opt_verbose)
+ d_printf("\tmigrating form # %d [%s] of type [%d]\n",
+ f, form_name, forms[f].flag);
+
+ /* is there a more elegant way to do that ? */
+ form.flags = FORM_PRINTER;
+ form.size_x = forms[f].width;
+ form.size_y = forms[f].length;
+ form.left = forms[f].left;
+ form.top = forms[f].top;
+ form.right = forms[f].right;
+ form.bottom = forms[f].bottom;
+
+ init_unistr2(&form.name, form_name, UNI_STR_TERMINATE);
+
+ /* FIXME: there might be something wrong with samba's
+ builtin-forms */
+ result = rpccli_spoolss_addform(pipe_hnd_dst, mem_ctx,
+ &hnd_dst, 1, &form);
+ if (!W_ERROR_IS_OK(result)) {
+ d_printf("\tAddForm form %d: [%s] refused.\n",
+ f, form_name);
+ continue;
+ }
+
+ DEBUGADD(1,("\tAddForm of [%s] succeeded\n", form_name));
+ }
+
+
+ /* close printer handles here */
+ if (got_hnd_src) {
+ rpccli_spoolss_close_printer(pipe_hnd, mem_ctx, &hnd_src);
+ got_hnd_src = false;
+ }
+
+ if (got_hnd_dst) {
+ rpccli_spoolss_close_printer(pipe_hnd_dst, mem_ctx, &hnd_dst);
+ got_hnd_dst = false;
+ }
+ }
+
+ nt_status = NT_STATUS_OK;
+
+done:
+
+ if (got_hnd_src)
+ rpccli_spoolss_close_printer(pipe_hnd, mem_ctx, &hnd_src);
+
+ if (got_hnd_dst)
+ rpccli_spoolss_close_printer(pipe_hnd_dst, mem_ctx, &hnd_dst);
+
+ if (cli_dst) {
+ cli_shutdown(cli_dst);
+ }
+ return nt_status;
+}
+
+/**
+ * Migrate printer-drivers from a src server to the dst server
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param c A net_context structure
+ * @param domain_sid The domain sid aquired from the remote server
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destoyed on compleation of the function.
+ * @param argc Standard main() style argc
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+NTSTATUS rpc_printer_migrate_drivers_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ uint32 i, p;
+ uint32 num_printers;
+ uint32 level = 3;
+ char *printername, *sharename;
+ bool got_hnd_src = false;
+ bool got_hnd_dst = false;
+ bool got_src_driver_share = false;
+ bool got_dst_driver_share = false;
+ struct rpc_pipe_client *pipe_hnd_dst = NULL;
+ POLICY_HND hnd_src, hnd_dst;
+ PRINTER_DRIVER_CTR drv_ctr_src, drv_ctr_dst;
+ PRINTER_INFO_CTR info_ctr_enum, info_ctr_dst;
+ struct cli_state *cli_dst = NULL;
+ struct cli_state *cli_share_src = NULL;
+ struct cli_state *cli_share_dst = NULL;
+ fstring drivername = "";
+
+ ZERO_STRUCT(drv_ctr_src);
+ ZERO_STRUCT(drv_ctr_dst);
+ ZERO_STRUCT(info_ctr_enum);
+ ZERO_STRUCT(info_ctr_dst);
+
+ DEBUG(3,("copying printer-drivers\n"));
+
+ nt_status = connect_dst_pipe(c, &cli_dst, &pipe_hnd_dst,
+ &syntax_spoolss);
+ if (!NT_STATUS_IS_OK(nt_status))
+ return nt_status;
+
+ /* open print$-share on the src server */
+ nt_status = connect_to_service(c, &cli_share_src, &cli->dest_ss,
+ cli->desthost, "print$", "A:");
+ if (!NT_STATUS_IS_OK(nt_status))
+ goto done;
+
+ got_src_driver_share = true;
+
+
+ /* open print$-share on the dst server */
+ nt_status = connect_to_service(c, &cli_share_dst, &cli_dst->dest_ss,
+ cli_dst->desthost, "print$", "A:");
+ if (!NT_STATUS_IS_OK(nt_status))
+ return nt_status;
+
+ got_dst_driver_share = true;
+
+
+ /* enum src printers */
+ if (!get_printer_info(pipe_hnd, mem_ctx, 2, argc, argv, &num_printers, &info_ctr_enum)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (num_printers == 0) {
+ printf ("no printers found on server.\n");
+ nt_status = NT_STATUS_OK;
+ goto done;
+ }
+
+
+ /* do something for all printers */
+ for (p = 0; p < num_printers; p++) {
+ /* do some initialization */
+ rpcstr_pull_talloc(mem_ctx,
+ &printername,
+ info_ctr_enum.printers_2[p].printername.buffer,
+ -1,
+ STR_TERMINATE);
+ rpcstr_pull_talloc(mem_ctx,
+ &sharename,
+ info_ctr_enum.printers_2[p].sharename.buffer,
+ -1,
+ STR_TERMINATE);
+ if (!printername || !sharename) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* we can reset NT_STATUS here because we do not
+ get any real NT_STATUS-codes anymore from now on */
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+
+ d_printf("migrating printer driver for: [%s] / [%s]\n",
+ printername, sharename);
+
+ /* open dst printer handle */
+ if (!net_spoolss_open_printer_ex(pipe_hnd_dst, mem_ctx, sharename,
+ PRINTER_ALL_ACCESS, cli->user_name, &hnd_dst))
+ goto done;
+
+ got_hnd_dst = true;
+
+ /* check for existing dst printer */
+ if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, 2, &info_ctr_dst))
+ goto done;
+
+
+ /* open src printer handle */
+ if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
+ MAXIMUM_ALLOWED_ACCESS,
+ pipe_hnd->auth->user_name,
+ &hnd_src))
+ goto done;
+
+ got_hnd_src = true;
+
+
+ /* in a first step call getdriver for each shared printer (per arch)
+ to get a list of all files that have to be copied */
+
+ for (i=0; archi_table[i].long_archi!=NULL; i++) {
+
+ /* getdriver src */
+ if (!net_spoolss_getprinterdriver(pipe_hnd, mem_ctx, &hnd_src,
+ level, archi_table[i].long_archi,
+ archi_table[i].version, &drv_ctr_src))
+ continue;
+
+ rpcstr_pull(drivername, drv_ctr_src.info3->name.buffer,
+ sizeof(drivername), -1, STR_TERMINATE);
+
+ if (c->opt_verbose)
+ display_print_driver_3(drv_ctr_src.info3);
+
+
+ /* check arch dir */
+ nt_status = check_arch_dir(cli_share_dst, archi_table[i].short_archi);
+ if (!NT_STATUS_IS_OK(nt_status))
+ goto done;
+
+
+ /* copy driver-files */
+ nt_status = copy_print_driver_3(c, mem_ctx, cli_share_src, cli_share_dst,
+ archi_table[i].short_archi,
+ drv_ctr_src.info3);
+ if (!NT_STATUS_IS_OK(nt_status))
+ goto done;
+
+
+ /* adddriver dst */
+ if (!net_spoolss_addprinterdriver(pipe_hnd_dst, mem_ctx, level, &drv_ctr_src)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ DEBUGADD(1,("Sucessfully added driver [%s] for printer [%s]\n",
+ drivername, printername));
+
+ }
+
+ if (strlen(drivername) == 0) {
+ DEBUGADD(1,("Did not get driver for printer %s\n",
+ printername));
+ goto done;
+ }
+
+ /* setdriver dst */
+ init_unistr(&info_ctr_dst.printers_2->drivername, drivername);
+
+ if (!net_spoolss_setprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, 2, &info_ctr_dst)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ DEBUGADD(1,("Sucessfully set driver %s for printer %s\n",
+ drivername, printername));
+
+ /* close dst */
+ if (got_hnd_dst) {
+ rpccli_spoolss_close_printer(pipe_hnd_dst, mem_ctx, &hnd_dst);
+ got_hnd_dst = false;
+ }
+
+ /* close src */
+ if (got_hnd_src) {
+ rpccli_spoolss_close_printer(pipe_hnd, mem_ctx, &hnd_src);
+ got_hnd_src = false;
+ }
+ }
+
+ nt_status = NT_STATUS_OK;
+
+done:
+
+ if (got_hnd_src)
+ rpccli_spoolss_close_printer(pipe_hnd, mem_ctx, &hnd_src);
+
+ if (got_hnd_dst)
+ rpccli_spoolss_close_printer(pipe_hnd_dst, mem_ctx, &hnd_dst);
+
+ if (cli_dst) {
+ cli_shutdown(cli_dst);
+ }
+
+ if (got_src_driver_share)
+ cli_shutdown(cli_share_src);
+
+ if (got_dst_driver_share)
+ cli_shutdown(cli_share_dst);
+
+ return nt_status;
+
+}
+
+/**
+ * Migrate printer-queues from a src to the dst server
+ * (requires a working "addprinter command" to be installed for the local smbd)
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param c A net_context structure
+ * @param domain_sid The domain sid aquired from the remote server
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destoyed on compleation of the function.
+ * @param argc Standard main() style argc
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+NTSTATUS rpc_printer_migrate_printers_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ WERROR result;
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ uint32 i = 0, num_printers;
+ uint32 level = 2;
+ PRINTER_INFO_CTR ctr_src, ctr_dst, ctr_enum;
+ struct cli_state *cli_dst = NULL;
+ POLICY_HND hnd_dst, hnd_src;
+ char *printername, *sharename;
+ bool got_hnd_src = false;
+ bool got_hnd_dst = false;
+ struct rpc_pipe_client *pipe_hnd_dst = NULL;
+
+ DEBUG(3,("copying printers\n"));
+
+ /* connect destination PI_SPOOLSS */
+ nt_status = connect_dst_pipe(c, &cli_dst, &pipe_hnd_dst,
+ &syntax_spoolss);
+ if (!NT_STATUS_IS_OK(nt_status))
+ return nt_status;
+
+ /* enum printers */
+ if (!get_printer_info(pipe_hnd, mem_ctx, level, argc, argv, &num_printers, &ctr_enum)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!num_printers) {
+ printf ("no printers found on server.\n");
+ nt_status = NT_STATUS_OK;
+ goto done;
+ }
+
+ /* do something for all printers */
+ for (i = 0; i < num_printers; i++) {
+ /* do some initialization */
+ rpcstr_pull_talloc(mem_ctx,
+ &printername,
+ ctr_enum.printers_2[i].printername.buffer,
+ -1,
+ STR_TERMINATE);
+ rpcstr_pull_talloc(mem_ctx,
+ &sharename,
+ ctr_enum.printers_2[i].sharename.buffer,
+ -1,
+ STR_TERMINATE);
+ if (!printername || !sharename) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ /* we can reset NT_STATUS here because we do not
+ get any real NT_STATUS-codes anymore from now on */
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+
+ d_printf("migrating printer queue for: [%s] / [%s]\n",
+ printername, sharename);
+
+ /* open dst printer handle */
+ if (!net_spoolss_open_printer_ex(pipe_hnd_dst, mem_ctx, sharename,
+ PRINTER_ALL_ACCESS, cli->user_name, &hnd_dst)) {
+
+ DEBUG(1,("could not open printer: %s\n", sharename));
+ } else {
+ got_hnd_dst = true;
+ }
+
+ /* check for existing dst printer */
+ if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, level, &ctr_dst)) {
+ printf ("could not get printer, creating printer.\n");
+ } else {
+ DEBUG(1,("printer already exists: %s\n", sharename));
+ /* close printer handle here - dst only, not got src yet. */
+ if (got_hnd_dst) {
+ rpccli_spoolss_close_printer(pipe_hnd_dst, mem_ctx, &hnd_dst);
+ got_hnd_dst = false;
+ }
+ continue;
+ }
+
+ /* now get again src printer ctr via getprinter,
+ we first need a handle for that */
+
+ /* open src printer handle */
+ if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
+ MAXIMUM_ALLOWED_ACCESS, cli->user_name, &hnd_src))
+ goto done;
+
+ got_hnd_src = true;
+
+ /* getprinter on the src server */
+ if (!net_spoolss_getprinter(pipe_hnd, mem_ctx, &hnd_src, level, &ctr_src))
+ goto done;
+
+ /* copy each src printer to a dst printer 1:1,
+ maybe some values have to be changed though */
+ d_printf("creating printer: %s\n", printername);
+ result = rpccli_spoolss_addprinterex (pipe_hnd_dst, mem_ctx, level, &ctr_src);
+
+ if (W_ERROR_IS_OK(result))
+ d_printf ("printer [%s] successfully added.\n", printername);
+ else if (W_ERROR_V(result) == W_ERROR_V(WERR_PRINTER_ALREADY_EXISTS))
+ d_fprintf (stderr, "printer [%s] already exists.\n", printername);
+ else {
+ d_fprintf (stderr, "could not create printer [%s]\n", printername);
+ goto done;
+ }
+
+ /* close printer handles here */
+ if (got_hnd_src) {
+ rpccli_spoolss_close_printer(pipe_hnd, mem_ctx, &hnd_src);
+ got_hnd_src = false;
+ }
+
+ if (got_hnd_dst) {
+ rpccli_spoolss_close_printer(pipe_hnd_dst, mem_ctx, &hnd_dst);
+ got_hnd_dst = false;
+ }
+ }
+
+ nt_status = NT_STATUS_OK;
+
+done:
+ if (got_hnd_src)
+ rpccli_spoolss_close_printer(pipe_hnd, mem_ctx, &hnd_src);
+
+ if (got_hnd_dst)
+ rpccli_spoolss_close_printer(pipe_hnd_dst, mem_ctx, &hnd_dst);
+
+ if (cli_dst) {
+ cli_shutdown(cli_dst);
+ }
+ return nt_status;
+}
+
+/**
+ * Migrate Printer-Settings from a src server to the dst server
+ * (for this to work, printers and drivers already have to be migrated earlier)
+ *
+ * All parameters are provided by the run_rpc_command function, except for
+ * argc, argv which are passed through.
+ *
+ * @param c A net_context structure
+ * @param domain_sid The domain sid aquired from the remote server
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destoyed on compleation of the function.
+ * @param argc Standard main() style argc
+ * @param argv Standard main() style argv. Initial components are already
+ * stripped
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+NTSTATUS rpc_printer_migrate_settings_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+
+ /* FIXME: Here the nightmare begins */
+
+ WERROR result;
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ uint32 i = 0, p = 0, j = 0;
+ uint32 num_printers, val_needed, data_needed;
+ uint32 level = 2;
+ char *printername, *sharename;
+ bool got_hnd_src = false;
+ bool got_hnd_dst = false;
+ struct rpc_pipe_client *pipe_hnd_dst = NULL;
+ POLICY_HND hnd_src, hnd_dst;
+ PRINTER_INFO_CTR ctr_enum, ctr_dst, ctr_dst_publish;
+ REGVAL_CTR *reg_ctr;
+ struct cli_state *cli_dst = NULL;
+ char *devicename = NULL, *unc_name = NULL, *url = NULL;
+ const char *longname;
+
+ uint16 *keylist = NULL, *curkey;
+
+ ZERO_STRUCT(ctr_enum);
+
+ DEBUG(3,("copying printer settings\n"));
+
+ /* connect destination PI_SPOOLSS */
+ nt_status = connect_dst_pipe(c, &cli_dst, &pipe_hnd_dst,
+ &syntax_spoolss);
+ if (!NT_STATUS_IS_OK(nt_status))
+ return nt_status;
+
+ /* enum src printers */
+ if (!get_printer_info(pipe_hnd, mem_ctx, level, argc, argv, &num_printers, &ctr_enum)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!num_printers) {
+ printf ("no printers found on server.\n");
+ nt_status = NT_STATUS_OK;
+ goto done;
+ }
+
+
+ /* needed for dns-strings in regkeys */
+ longname = get_mydnsfullname();
+ if (!longname) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* do something for all printers */
+ for (i = 0; i < num_printers; i++) {
+ /* do some initialization */
+ rpcstr_pull_talloc(mem_ctx,
+ &printername,
+ ctr_enum.printers_2[i].printername.buffer,
+ -1,
+ STR_TERMINATE);
+ rpcstr_pull_talloc(mem_ctx,
+ &sharename,
+ ctr_enum.printers_2[i].sharename.buffer,
+ -1,
+ STR_TERMINATE);
+ if (!printername || !sharename) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ /* we can reset NT_STATUS here because we do not
+ get any real NT_STATUS-codes anymore from now on */
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+
+ d_printf("migrating printer settings for: [%s] / [%s]\n",
+ printername, sharename);
+
+
+ /* open src printer handle */
+ if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
+ MAXIMUM_ALLOWED_ACCESS, cli->user_name, &hnd_src))
+ goto done;
+
+ got_hnd_src = true;
+
+
+ /* open dst printer handle */
+ if (!net_spoolss_open_printer_ex(pipe_hnd_dst, mem_ctx, sharename,
+ PRINTER_ALL_ACCESS, cli_dst->user_name, &hnd_dst))
+ goto done;
+
+ got_hnd_dst = true;
+
+
+ /* check for existing dst printer */
+ if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst,
+ level, &ctr_dst))
+ goto done;
+
+
+ /* STEP 1: COPY DEVICE-MODE and other
+ PRINTER_INFO_2-attributes
+ */
+
+ ctr_dst.printers_2 = &ctr_enum.printers_2[i];
+
+ /* why is the port always disconnected when the printer
+ is correctly installed (incl. driver ???) */
+ init_unistr( &ctr_dst.printers_2->portname, SAMBA_PRINTER_PORT_NAME);
+
+ /* check if printer is published */
+ if (ctr_enum.printers_2[i].attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
+
+ /* check for existing dst printer */
+ if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, 7, &ctr_dst_publish))
+ goto done;
+
+ ctr_dst_publish.printers_7->action = SPOOL_DS_PUBLISH;
+
+ /* ignore false from setprinter due to WERR_IO_PENDING */
+ net_spoolss_setprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, 7, &ctr_dst_publish);
+
+ DEBUG(3,("republished printer\n"));
+ }
+
+ if (ctr_enum.printers_2[i].devmode != NULL) {
+
+ /* copy devmode (info level 2) */
+ ctr_dst.printers_2->devmode = (DEVICEMODE *)
+ TALLOC_MEMDUP(mem_ctx,
+ ctr_enum.printers_2[i].devmode,
+ sizeof(DEVICEMODE));
+
+ /* do not copy security descriptor (we have another
+ * command for that) */
+ ctr_dst.printers_2->secdesc = NULL;
+
+#if 0
+ if (asprintf(&devicename, "\\\\%s\\%s", longname,
+ printername) < 0) {
+ nt_status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ init_unistr(&ctr_dst.printers_2->devmode->devicename,
+ devicename);
+#endif
+ if (!net_spoolss_setprinter(pipe_hnd_dst, mem_ctx, &hnd_dst,
+ level, &ctr_dst))
+ goto done;
+
+ DEBUGADD(1,("\tSetPrinter of DEVICEMODE succeeded\n"));
+ }
+
+ /* STEP 2: COPY REGISTRY VALUES */
+
+ /* please keep in mind that samba parse_spools gives horribly
+ crippled results when used to rpccli_spoolss_enumprinterdataex
+ a win2k3-server. (Bugzilla #1851)
+ FIXME: IIRC I've seen it too on a win2k-server
+ */
+
+ /* enumerate data on src handle */
+ result = rpccli_spoolss_enumprinterdata(pipe_hnd, mem_ctx, &hnd_src, p, 0, 0,
+ &val_needed, &data_needed, NULL);
+
+ /* loop for all printerdata of "PrinterDriverData" */
+ while (W_ERROR_IS_OK(result)) {
+
+ REGISTRY_VALUE value;
+
+ result = rpccli_spoolss_enumprinterdata(
+ pipe_hnd, mem_ctx, &hnd_src, p++, val_needed,
+ data_needed, 0, 0, &value);
+
+ /* loop for all reg_keys */
+ if (W_ERROR_IS_OK(result)) {
+
+ /* display_value */
+ if (c->opt_verbose)
+ display_reg_value(SPOOL_PRINTERDATA_KEY, value);
+
+ /* set_value */
+ if (!net_spoolss_setprinterdata(pipe_hnd_dst, mem_ctx,
+ &hnd_dst, &value))
+ goto done;
+
+ DEBUGADD(1,("\tSetPrinterData of [%s] succeeded\n",
+ value.valuename));
+ }
+ }
+
+ /* STEP 3: COPY SUBKEY VALUES */
+
+ /* here we need to enum all printer_keys and then work
+ on the result with enum_printer_key_ex. nt4 does not
+ respond to enumprinterkey, win2k does, so continue
+ in case of an error */
+
+ if (!net_spoolss_enumprinterkey(pipe_hnd, mem_ctx, &hnd_src, "", &keylist)) {
+ printf("got no key-data\n");
+ continue;
+ }
+
+
+ /* work on a list of printer keys
+ each key has to be enumerated to get all required
+ information. information is then set via setprinterdataex-calls */
+
+ if (keylist == NULL)
+ continue;
+
+ curkey = keylist;
+ while (*curkey != 0) {
+ char *subkey;
+ rpcstr_pull_talloc(mem_ctx,
+ &subkey,
+ curkey,
+ -1,
+ STR_TERMINATE);
+ if (!subkey) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ curkey += strlen(subkey) + 1;
+
+ if ( !(reg_ctr = TALLOC_ZERO_P( mem_ctx, REGVAL_CTR )) )
+ return NT_STATUS_NO_MEMORY;
+
+ /* enumerate all src subkeys */
+ if (!net_spoolss_enumprinterdataex(pipe_hnd, mem_ctx, 0,
+ &hnd_src, subkey,
+ reg_ctr))
+ goto done;
+
+ for (j=0; j < reg_ctr->num_values; j++) {
+
+ REGISTRY_VALUE value;
+ UNISTR2 data;
+
+ /* although samba replies with sane data in most cases we
+ should try to avoid writing wrong registry data */
+
+ if (strequal(reg_ctr->values[j]->valuename, SPOOL_REG_PORTNAME) ||
+ strequal(reg_ctr->values[j]->valuename, SPOOL_REG_UNCNAME) ||
+ strequal(reg_ctr->values[j]->valuename, SPOOL_REG_URL) ||
+ strequal(reg_ctr->values[j]->valuename, SPOOL_REG_SHORTSERVERNAME) ||
+ strequal(reg_ctr->values[j]->valuename, SPOOL_REG_SERVERNAME)) {
+
+ if (strequal(reg_ctr->values[j]->valuename, SPOOL_REG_PORTNAME)) {
+
+ /* although windows uses a multi-sz, we use a sz */
+ init_unistr2(&data, SAMBA_PRINTER_PORT_NAME, UNI_STR_TERMINATE);
+ fstrcpy(value.valuename, SPOOL_REG_PORTNAME);
+ }
+
+ if (strequal(reg_ctr->values[j]->valuename, SPOOL_REG_UNCNAME)) {
+
+ if (asprintf(&unc_name, "\\\\%s\\%s", longname, sharename) < 0) {
+ nt_status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ init_unistr2(&data, unc_name, UNI_STR_TERMINATE);
+ fstrcpy(value.valuename, SPOOL_REG_UNCNAME);
+ }
+
+ if (strequal(reg_ctr->values[j]->valuename, SPOOL_REG_URL)) {
+
+ continue;
+
+#if 0
+ /* FIXME: should we really do that ??? */
+ if (asprintf(&url, "http://%s:631/printers/%s", longname, sharename) < 0) {
+ nt_status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ init_unistr2(&data, url, UNI_STR_TERMINATE);
+ fstrcpy(value.valuename, SPOOL_REG_URL);
+#endif
+ }
+
+ if (strequal(reg_ctr->values[j]->valuename, SPOOL_REG_SERVERNAME)) {
+
+ init_unistr2(&data, longname, UNI_STR_TERMINATE);
+ fstrcpy(value.valuename, SPOOL_REG_SERVERNAME);
+ }
+
+ if (strequal(reg_ctr->values[j]->valuename, SPOOL_REG_SHORTSERVERNAME)) {
+
+ init_unistr2(&data, global_myname(), UNI_STR_TERMINATE);
+ fstrcpy(value.valuename, SPOOL_REG_SHORTSERVERNAME);
+ }
+
+ value.type = REG_SZ;
+ value.size = data.uni_str_len * 2;
+ if (value.size) {
+ value.data_p = (uint8 *)TALLOC_MEMDUP(mem_ctx, data.buffer, value.size);
+ } else {
+ value.data_p = NULL;
+ }
+
+ if (c->opt_verbose)
+ display_reg_value(subkey, value);
+
+ /* here we have to set all subkeys on the dst server */
+ if (!net_spoolss_setprinterdataex(pipe_hnd_dst, mem_ctx, &hnd_dst,
+ subkey, &value))
+ goto done;
+
+ } else {
+
+ if (c->opt_verbose)
+ display_reg_value(subkey, *(reg_ctr->values[j]));
+
+ /* here we have to set all subkeys on the dst server */
+ if (!net_spoolss_setprinterdataex(pipe_hnd_dst, mem_ctx, &hnd_dst,
+ subkey, reg_ctr->values[j]))
+ goto done;
+
+ }
+
+ DEBUGADD(1,("\tSetPrinterDataEx of key [%s\\%s] succeeded\n",
+ subkey, reg_ctr->values[j]->valuename));
+
+ }
+
+ TALLOC_FREE( reg_ctr );
+ }
+
+ safe_free(keylist);
+
+ /* close printer handles here */
+ if (got_hnd_src) {
+ rpccli_spoolss_close_printer(pipe_hnd, mem_ctx, &hnd_src);
+ got_hnd_src = false;
+ }
+
+ if (got_hnd_dst) {
+ rpccli_spoolss_close_printer(pipe_hnd_dst, mem_ctx, &hnd_dst);
+ got_hnd_dst = false;
+ }
+
+ }
+
+ nt_status = NT_STATUS_OK;
+
+done:
+ SAFE_FREE(devicename);
+ SAFE_FREE(url);
+ SAFE_FREE(unc_name);
+
+ if (got_hnd_src)
+ rpccli_spoolss_close_printer(pipe_hnd, mem_ctx, &hnd_src);
+
+ if (got_hnd_dst)
+ rpccli_spoolss_close_printer(pipe_hnd_dst, mem_ctx, &hnd_dst);
+
+ if (cli_dst) {
+ cli_shutdown(cli_dst);
+ }
+ return nt_status;
+}
diff --git a/source3/utils/net_rpc_registry.c b/source3/utils/net_rpc_registry.c
new file mode 100644
index 0000000000..124af00b57
--- /dev/null
+++ b/source3/utils/net_rpc_registry.c
@@ -0,0 +1,1311 @@
+/*
+ Samba Unix/Linux SMB client library
+ Distributed SMB/CIFS Server Management Utility
+
+ Copyright (C) Gerald (Jerry) Carter 2005-2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "includes.h"
+#include "utils/net.h"
+#include "utils/net_registry_util.h"
+#include "regfio.h"
+#include "reg_objects.h"
+
+static bool reg_hive_key(TALLOC_CTX *ctx, const char *fullname,
+ uint32 *reg_type, const char **key_name)
+{
+ WERROR werr;
+ char *hivename = NULL;
+ char *tmp_keyname = NULL;
+ bool ret = false;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ werr = split_hive_key(tmp_ctx, fullname, &hivename, &tmp_keyname);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ *key_name = talloc_strdup(ctx, tmp_keyname);
+ if (*key_name == NULL) {
+ goto done;
+ }
+
+ if (strequal(hivename, "HKLM") ||
+ strequal(hivename, "HKEY_LOCAL_MACHINE"))
+ {
+ (*reg_type) = HKEY_LOCAL_MACHINE;
+ } else if (strequal(hivename, "HKCR") ||
+ strequal(hivename, "HKEY_CLASSES_ROOT"))
+ {
+ (*reg_type) = HKEY_CLASSES_ROOT;
+ } else if (strequal(hivename, "HKU") ||
+ strequal(hivename, "HKEY_USERS"))
+ {
+ (*reg_type) = HKEY_USERS;
+ } else if (strequal(hivename, "HKCU") ||
+ strequal(hivename, "HKEY_CURRENT_USER"))
+ {
+ (*reg_type) = HKEY_CURRENT_USER;
+ } else if (strequal(hivename, "HKPD") ||
+ strequal(hivename, "HKEY_PERFORMANCE_DATA"))
+ {
+ (*reg_type) = HKEY_PERFORMANCE_DATA;
+ } else {
+ DEBUG(10,("reg_hive_key: unrecognised hive key %s\n",
+ fullname));
+ goto done;
+ }
+
+ ret = true;
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return ret;
+}
+
+static NTSTATUS registry_openkey(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ const char *name, uint32 access_mask,
+ struct policy_handle *hive_hnd,
+ struct policy_handle *key_hnd)
+{
+ uint32 hive;
+ NTSTATUS status;
+ struct winreg_String key;
+
+ ZERO_STRUCT(key);
+
+ if (!reg_hive_key(mem_ctx, name, &hive, &key.name)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = rpccli_winreg_Connect(pipe_hnd, mem_ctx, hive, access_mask,
+ hive_hnd);
+ if (!(NT_STATUS_IS_OK(status))) {
+ return status;
+ }
+
+ status = rpccli_winreg_OpenKey(pipe_hnd, mem_ctx, hive_hnd, key, 0,
+ access_mask, key_hnd, NULL);
+ if (!(NT_STATUS_IS_OK(status))) {
+ rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, hive_hnd, NULL);
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS registry_enumkeys(TALLOC_CTX *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ struct policy_handle *key_hnd,
+ uint32 *pnum_keys, char ***pnames,
+ char ***pclasses, NTTIME ***pmodtimes)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ uint32 num_subkeys, max_subkeylen, max_classlen;
+ uint32 num_values, max_valnamelen, max_valbufsize;
+ uint32 i;
+ NTTIME last_changed_time;
+ uint32 secdescsize;
+ struct winreg_String classname;
+ char **names, **classes;
+ NTTIME **modtimes;
+
+ if (!(mem_ctx = talloc_new(ctx))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCT(classname);
+ status = rpccli_winreg_QueryInfoKey(
+ pipe_hnd, mem_ctx, key_hnd, &classname, &num_subkeys,
+ &max_subkeylen, &max_classlen, &num_values, &max_valnamelen,
+ &max_valbufsize, &secdescsize, &last_changed_time, NULL );
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto error;
+ }
+
+ if (num_subkeys == 0) {
+ *pnum_keys = 0;
+ TALLOC_FREE(mem_ctx);
+ return NT_STATUS_OK;
+ }
+
+ if ((!(names = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_subkeys))) ||
+ (!(classes = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_subkeys))) ||
+ (!(modtimes = TALLOC_ZERO_ARRAY(mem_ctx, NTTIME *,
+ num_subkeys)))) {
+ status = NT_STATUS_NO_MEMORY;
+ goto error;
+ }
+
+ for (i=0; i<num_subkeys; i++) {
+ char c, n;
+ struct winreg_StringBuf class_buf;
+ struct winreg_StringBuf name_buf;
+ NTTIME modtime;
+ WERROR werr;
+
+ c = '\0';
+ class_buf.name = &c;
+ class_buf.size = max_classlen+2;
+
+ n = '\0';
+ name_buf.name = &n;
+ name_buf.size = max_subkeylen+2;
+
+ ZERO_STRUCT(modtime);
+
+ status = rpccli_winreg_EnumKey(pipe_hnd, mem_ctx, key_hnd,
+ i, &name_buf, &class_buf,
+ &modtime, &werr);
+
+ if (W_ERROR_EQUAL(werr,
+ WERR_NO_MORE_ITEMS) ) {
+ status = NT_STATUS_OK;
+ break;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ goto error;
+ }
+
+ classes[i] = NULL;
+
+ if (class_buf.name &&
+ (!(classes[i] = talloc_strdup(classes, class_buf.name)))) {
+ status = NT_STATUS_NO_MEMORY;
+ goto error;
+ }
+
+ if (!(names[i] = talloc_strdup(names, name_buf.name))) {
+ status = NT_STATUS_NO_MEMORY;
+ goto error;
+ }
+
+ if ((!(modtimes[i] = (NTTIME *)talloc_memdup(
+ modtimes, &modtime, sizeof(modtime))))) {
+ status = NT_STATUS_NO_MEMORY;
+ goto error;
+ }
+ }
+
+ *pnum_keys = num_subkeys;
+
+ if (pnames) {
+ *pnames = talloc_move(ctx, &names);
+ }
+ if (pclasses) {
+ *pclasses = talloc_move(ctx, &classes);
+ }
+ if (pmodtimes) {
+ *pmodtimes = talloc_move(ctx, &modtimes);
+ }
+
+ status = NT_STATUS_OK;
+
+ error:
+ TALLOC_FREE(mem_ctx);
+ return status;
+}
+
+static NTSTATUS registry_enumvalues(TALLOC_CTX *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ struct policy_handle *key_hnd,
+ uint32 *pnum_values, char ***pvalnames,
+ struct registry_value ***pvalues)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ uint32 num_subkeys, max_subkeylen, max_classlen;
+ uint32 num_values, max_valnamelen, max_valbufsize;
+ uint32 i;
+ NTTIME last_changed_time;
+ uint32 secdescsize;
+ struct winreg_String classname;
+ struct registry_value **values;
+ char **names;
+
+ if (!(mem_ctx = talloc_new(ctx))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCT(classname);
+ status = rpccli_winreg_QueryInfoKey(
+ pipe_hnd, mem_ctx, key_hnd, &classname, &num_subkeys,
+ &max_subkeylen, &max_classlen, &num_values, &max_valnamelen,
+ &max_valbufsize, &secdescsize, &last_changed_time, NULL );
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto error;
+ }
+
+ if (num_values == 0) {
+ *pnum_values = 0;
+ TALLOC_FREE(mem_ctx);
+ return NT_STATUS_OK;
+ }
+
+ if ((!(names = TALLOC_ARRAY(mem_ctx, char *, num_values))) ||
+ (!(values = TALLOC_ARRAY(mem_ctx, struct registry_value *,
+ num_values)))) {
+ status = NT_STATUS_NO_MEMORY;
+ goto error;
+ }
+
+ for (i=0; i<num_values; i++) {
+ enum winreg_Type type = REG_NONE;
+ uint8 *data = NULL;
+ uint32 data_size;
+ uint32 value_length;
+
+ char n;
+ struct winreg_ValNameBuf name_buf;
+ WERROR err;
+
+ n = '\0';
+ name_buf.name = &n;
+ name_buf.size = max_valnamelen + 2;
+
+ data_size = max_valbufsize;
+ data = (uint8 *)TALLOC(mem_ctx, data_size);
+ value_length = 0;
+
+ status = rpccli_winreg_EnumValue(pipe_hnd, mem_ctx, key_hnd,
+ i, &name_buf, &type,
+ data, &data_size,
+ &value_length, &err);
+
+ if ( W_ERROR_EQUAL(err,
+ WERR_NO_MORE_ITEMS) ) {
+ status = NT_STATUS_OK;
+ break;
+ }
+
+ if (!(NT_STATUS_IS_OK(status))) {
+ goto error;
+ }
+
+ if (name_buf.name == NULL) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto error;
+ }
+
+ if (!(names[i] = talloc_strdup(names, name_buf.name))) {
+ status = NT_STATUS_NO_MEMORY;
+ goto error;
+ }
+
+ err = registry_pull_value(values, &values[i], type, data,
+ data_size, value_length);
+ if (!W_ERROR_IS_OK(err)) {
+ status = werror_to_ntstatus(err);
+ goto error;
+ }
+ }
+
+ *pnum_values = num_values;
+
+ if (pvalnames) {
+ *pvalnames = talloc_move(ctx, &names);
+ }
+ if (pvalues) {
+ *pvalues = talloc_move(ctx, &values);
+ }
+
+ status = NT_STATUS_OK;
+
+ error:
+ TALLOC_FREE(mem_ctx);
+ return status;
+}
+
+static NTSTATUS registry_getsd(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ struct policy_handle *key_hnd,
+ uint32_t sec_info,
+ struct KeySecurityData *sd)
+{
+ return rpccli_winreg_GetKeySecurity(pipe_hnd, mem_ctx, key_hnd,
+ sec_info, sd, NULL);
+}
+
+
+static NTSTATUS registry_setvalue(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ struct policy_handle *key_hnd,
+ const char *name,
+ const struct registry_value *value)
+{
+ struct winreg_String name_string;
+ DATA_BLOB blob;
+ NTSTATUS result;
+ WERROR err;
+
+ err = registry_push_value(mem_ctx, value, &blob);
+ if (!W_ERROR_IS_OK(err)) {
+ return werror_to_ntstatus(err);
+ }
+
+ ZERO_STRUCT(name_string);
+
+ name_string.name = name;
+ result = rpccli_winreg_SetValue(pipe_hnd, blob.data, key_hnd,
+ name_string, value->type,
+ blob.data, blob.length, NULL);
+ TALLOC_FREE(blob.data);
+ return result;
+}
+
+static NTSTATUS rpc_registry_setvalue_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv )
+{
+ struct policy_handle hive_hnd, key_hnd;
+ NTSTATUS status;
+ struct registry_value value;
+
+ status = registry_openkey(mem_ctx, pipe_hnd, argv[0],
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &hive_hnd, &key_hnd);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "registry_openkey failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+
+ if (!strequal(argv[2], "multi_sz") && (argc != 4)) {
+ d_fprintf(stderr, "Too many args for type %s\n", argv[2]);
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (strequal(argv[2], "dword")) {
+ value.type = REG_DWORD;
+ value.v.dword = strtoul(argv[3], NULL, 10);
+ }
+ else if (strequal(argv[2], "sz")) {
+ value.type = REG_SZ;
+ value.v.sz.len = strlen(argv[3])+1;
+ value.v.sz.str = CONST_DISCARD(char *, argv[3]);
+ }
+ else {
+ d_fprintf(stderr, "type \"%s\" not implemented\n", argv[2]);
+ status = NT_STATUS_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ status = registry_setvalue(mem_ctx, pipe_hnd, &key_hnd,
+ argv[1], &value);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "registry_setvalue failed: %s\n",
+ nt_errstr(status));
+ }
+
+ error:
+ rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &key_hnd, NULL);
+ rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
+
+ return NT_STATUS_OK;
+}
+
+static int rpc_registry_setvalue(struct net_context *c, int argc,
+ const char **argv )
+{
+ if (argc < 4 || c->display_usage) {
+ d_fprintf(stderr, "usage: net rpc registry setvalue <key> "
+ "<valuename> <type> [<val>]+\n");
+ return -1;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_winreg.syntax_id, 0,
+ rpc_registry_setvalue_internal, argc, argv );
+}
+
+static NTSTATUS rpc_registry_deletevalue_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv )
+{
+ struct policy_handle hive_hnd, key_hnd;
+ NTSTATUS status;
+ struct winreg_String valuename;
+
+ ZERO_STRUCT(valuename);
+
+ status = registry_openkey(mem_ctx, pipe_hnd, argv[0],
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &hive_hnd, &key_hnd);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "registry_openkey failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+
+ valuename.name = argv[1];
+
+ status = rpccli_winreg_DeleteValue(pipe_hnd, mem_ctx, &key_hnd,
+ valuename, NULL);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "registry_deletevalue failed: %s\n",
+ nt_errstr(status));
+ }
+
+ rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &key_hnd, NULL);
+ rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
+
+ return status;
+}
+
+static int rpc_registry_deletevalue(struct net_context *c, int argc,
+ const char **argv )
+{
+ if (argc != 2 || c->display_usage) {
+ d_fprintf(stderr, "usage: net rpc registry deletevalue <key> "
+ "<valuename>\n");
+ return -1;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_winreg.syntax_id, 0,
+ rpc_registry_deletevalue_internal, argc, argv );
+}
+
+static NTSTATUS rpc_registry_getvalue_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ bool raw,
+ int argc,
+ const char **argv)
+{
+ struct policy_handle hive_hnd, key_hnd;
+ NTSTATUS status;
+ WERROR werr;
+ struct winreg_String valuename;
+ struct registry_value *value = NULL;
+ enum winreg_Type type = REG_NONE;
+ uint8_t *data = NULL;
+ uint32_t data_size = 0;
+ uint32_t value_length = 0;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ ZERO_STRUCT(valuename);
+
+ status = registry_openkey(tmp_ctx, pipe_hnd, argv[0],
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &hive_hnd, &key_hnd);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "registry_openkey failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+
+ valuename.name = argv[1];
+
+ /*
+ * call QueryValue once with data == NULL to get the
+ * needed memory size to be allocated, then allocate
+ * data buffer and call again.
+ */
+ status = rpccli_winreg_QueryValue(pipe_hnd, tmp_ctx, &key_hnd,
+ &valuename,
+ &type,
+ data,
+ &data_size,
+ &value_length,
+ NULL);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "registry_queryvalue failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+
+ data = (uint8 *)TALLOC(tmp_ctx, data_size);
+ value_length = 0;
+
+ status = rpccli_winreg_QueryValue(pipe_hnd, tmp_ctx, &key_hnd,
+ &valuename,
+ &type,
+ data,
+ &data_size,
+ &value_length,
+ NULL);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "registry_queryvalue failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+
+ werr = registry_pull_value(tmp_ctx, &value, type, data,
+ data_size, value_length);
+ if (!W_ERROR_IS_OK(werr)) {
+ status = werror_to_ntstatus(werr);
+ goto done;
+ }
+
+ print_registry_value(value, raw);
+
+done:
+ rpccli_winreg_CloseKey(pipe_hnd, tmp_ctx, &key_hnd, NULL);
+ rpccli_winreg_CloseKey(pipe_hnd, tmp_ctx, &hive_hnd, NULL);
+
+ TALLOC_FREE(tmp_ctx);
+
+ return status;
+}
+
+static NTSTATUS rpc_registry_getvalue_full(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ return rpc_registry_getvalue_internal(c, domain_sid, domain_name,
+ cli, pipe_hnd, mem_ctx, false,
+ argc, argv);
+}
+
+static int rpc_registry_getvalue(struct net_context *c, int argc,
+ const char **argv)
+{
+ if (argc != 2 || c->display_usage) {
+ d_fprintf(stderr, "usage: net rpc registry getvalue <key> "
+ "<valuename>\n");
+ return -1;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_winreg.syntax_id, 0,
+ rpc_registry_getvalue_full, argc, argv);
+}
+
+static NTSTATUS rpc_registry_getvalue_raw(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ return rpc_registry_getvalue_internal(c, domain_sid, domain_name,
+ cli, pipe_hnd, mem_ctx, true,
+ argc, argv);
+}
+
+static int rpc_registry_getvalueraw(struct net_context *c, int argc,
+ const char **argv)
+{
+ if (argc != 2 || c->display_usage) {
+ d_fprintf(stderr, "usage: net rpc registry getvalue <key> "
+ "<valuename>\n");
+ return -1;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_winreg.syntax_id, 0,
+ rpc_registry_getvalue_raw, argc, argv);
+}
+
+static NTSTATUS rpc_registry_createkey_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv )
+{
+ uint32 hive;
+ struct policy_handle hive_hnd, key_hnd;
+ struct winreg_String key, keyclass;
+ enum winreg_CreateAction action;
+ NTSTATUS status;
+
+ ZERO_STRUCT(key);
+ ZERO_STRUCT(keyclass);
+
+ if (!reg_hive_key(mem_ctx, argv[0], &hive, &key.name)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = rpccli_winreg_Connect(pipe_hnd, mem_ctx, hive,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &hive_hnd);
+ if (!(NT_STATUS_IS_OK(status))) {
+ return status;
+ }
+
+ action = REG_ACTION_NONE;
+ keyclass.name = "";
+
+ status = rpccli_winreg_CreateKey(pipe_hnd, mem_ctx, &hive_hnd, key,
+ keyclass, 0, REG_KEY_READ, NULL,
+ &key_hnd, &action, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "createkey returned %s\n",
+ nt_errstr(status));
+ rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
+ return status;
+ }
+
+ switch (action) {
+ case REG_ACTION_NONE:
+ d_printf("createkey did nothing -- huh?\n");
+ break;
+ case REG_CREATED_NEW_KEY:
+ d_printf("createkey created %s\n", argv[0]);
+ break;
+ case REG_OPENED_EXISTING_KEY:
+ d_printf("createkey opened existing %s\n", argv[0]);
+ break;
+ }
+
+ rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &key_hnd, NULL);
+ rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
+
+ return status;
+}
+
+static int rpc_registry_createkey(struct net_context *c, int argc,
+ const char **argv )
+{
+ if (argc != 1 || c->display_usage) {
+ d_fprintf(stderr, "usage: net rpc registry createkey <key>\n");
+ return -1;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_winreg.syntax_id, 0,
+ rpc_registry_createkey_internal, argc, argv );
+}
+
+static NTSTATUS rpc_registry_deletekey_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv )
+{
+ uint32 hive;
+ struct policy_handle hive_hnd;
+ struct winreg_String key;
+ NTSTATUS status;
+
+ ZERO_STRUCT(key);
+
+ if (!reg_hive_key(mem_ctx, argv[0], &hive, &key.name)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = rpccli_winreg_Connect(pipe_hnd, mem_ctx, hive,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &hive_hnd);
+ if (!(NT_STATUS_IS_OK(status))) {
+ return status;
+ }
+
+ status = rpccli_winreg_DeleteKey(pipe_hnd, mem_ctx, &hive_hnd, key, NULL);
+ rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "deletekey returned %s\n",
+ nt_errstr(status));
+ }
+
+ return status;
+}
+
+static int rpc_registry_deletekey(struct net_context *c, int argc, const char **argv )
+{
+ if (argc != 1 || c->display_usage) {
+ d_fprintf(stderr, "usage: net rpc registry deletekey <key>\n");
+ return -1;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_winreg.syntax_id, 0,
+ rpc_registry_deletekey_internal, argc, argv );
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_registry_enumerate_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv )
+{
+ POLICY_HND pol_hive, pol_key;
+ NTSTATUS status;
+ uint32 num_subkeys = 0;
+ uint32 num_values = 0;
+ char **names = NULL, **classes = NULL;
+ NTTIME **modtimes = NULL;
+ uint32 i;
+ struct registry_value **values = NULL;
+
+ if (argc != 1 || c->display_usage) {
+ d_printf("Usage: net rpc registry enumerate <path>\n");
+ d_printf("Example: net rpc registry enumerate 'HKLM\\Software\\Samba'\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = registry_openkey(mem_ctx, pipe_hnd, argv[0], REG_KEY_READ,
+ &pol_hive, &pol_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "registry_openkey failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+
+ status = registry_enumkeys(mem_ctx, pipe_hnd, &pol_key, &num_subkeys,
+ &names, &classes, &modtimes);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "enumerating keys failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+
+ for (i=0; i<num_subkeys; i++) {
+ print_registry_key(names[i], modtimes[i]);
+ }
+
+ status = registry_enumvalues(mem_ctx, pipe_hnd, &pol_key, &num_values,
+ &names, &values);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "enumerating values failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+
+ for (i=0; i<num_values; i++) {
+ print_registry_value_with_name(names[i], values[i]);
+ }
+
+ rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_key, NULL);
+ rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_hive, NULL);
+
+ return status;
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_registry_enumerate(struct net_context *c, int argc,
+ const char **argv )
+{
+ return run_rpc_command(c, NULL, &ndr_table_winreg.syntax_id, 0,
+ rpc_registry_enumerate_internal, argc, argv );
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_registry_save_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv )
+{
+ WERROR result = WERR_GENERAL_FAILURE;
+ POLICY_HND pol_hive, pol_key;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ struct winreg_String filename;
+
+ if (argc != 2 || c->display_usage) {
+ d_printf("Usage: net rpc registry backup <path> <file> \n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = registry_openkey(mem_ctx, pipe_hnd, argv[0], REG_KEY_ALL,
+ &pol_hive, &pol_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "registry_openkey failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+
+ filename.name = argv[1];
+ status = rpccli_winreg_SaveKey( pipe_hnd, mem_ctx, &pol_key, &filename, NULL, NULL);
+ if ( !W_ERROR_IS_OK(result) ) {
+ d_fprintf(stderr, "Unable to save [%s] to %s:%s\n", argv[0], cli->desthost, argv[1]);
+ }
+
+ /* cleanup */
+
+ rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_key, NULL);
+ rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_hive, NULL);
+
+ return status;
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_registry_save(struct net_context *c, int argc, const char **argv )
+{
+ return run_rpc_command(c, NULL, &ndr_table_winreg.syntax_id, 0,
+ rpc_registry_save_internal, argc, argv );
+}
+
+
+/********************************************************************
+********************************************************************/
+
+static void dump_values( REGF_NK_REC *nk )
+{
+ int i, j;
+ char *data_str = NULL;
+ uint32 data_size, data;
+
+ if ( !nk->values )
+ return;
+
+ for ( i=0; i<nk->num_values; i++ ) {
+ d_printf( "\"%s\" = ", nk->values[i].valuename ? nk->values[i].valuename : "(default)" );
+ d_printf( "(%s) ", reg_type_lookup( nk->values[i].type ) );
+
+ data_size = nk->values[i].data_size & ~VK_DATA_IN_OFFSET;
+ switch ( nk->values[i].type ) {
+ case REG_SZ:
+ rpcstr_pull_talloc(talloc_tos(),
+ &data_str,
+ nk->values[i].data,
+ -1,
+ STR_TERMINATE);
+ if (!data_str) {
+ break;
+ }
+ d_printf( "%s", data_str );
+ break;
+ case REG_MULTI_SZ:
+ case REG_EXPAND_SZ:
+ for ( j=0; j<data_size; j++ ) {
+ d_printf( "%c", nk->values[i].data[j] );
+ }
+ break;
+ case REG_DWORD:
+ data = IVAL( nk->values[i].data, 0 );
+ d_printf("0x%x", data );
+ break;
+ case REG_BINARY:
+ for ( j=0; j<data_size; j++ ) {
+ d_printf( "%x", nk->values[i].data[j] );
+ }
+ break;
+ default:
+ d_printf("unknown");
+ break;
+ }
+
+ d_printf( "\n" );
+ }
+
+}
+
+/********************************************************************
+********************************************************************/
+
+static bool dump_registry_tree( REGF_FILE *file, REGF_NK_REC *nk, const char *parent )
+{
+ REGF_NK_REC *key;
+
+ /* depth first dump of the registry tree */
+
+ while ( (key = regfio_fetch_subkey( file, nk )) ) {
+ char *regpath;
+ if (asprintf(&regpath, "%s\\%s", parent, key->keyname) < 0) {
+ break;
+ }
+ d_printf("[%s]\n", regpath );
+ dump_values( key );
+ d_printf("\n");
+ dump_registry_tree( file, key, regpath );
+ SAFE_FREE(regpath);
+ }
+
+ return true;
+}
+
+/********************************************************************
+********************************************************************/
+
+static bool write_registry_tree( REGF_FILE *infile, REGF_NK_REC *nk,
+ REGF_NK_REC *parent, REGF_FILE *outfile,
+ const char *parentpath )
+{
+ REGF_NK_REC *key, *subkey;
+ REGVAL_CTR *values = NULL;
+ REGSUBKEY_CTR *subkeys = NULL;
+ int i;
+ char *path = NULL;
+
+ if ( !( subkeys = TALLOC_ZERO_P( infile->mem_ctx, REGSUBKEY_CTR )) ) {
+ DEBUG(0,("write_registry_tree: talloc() failed!\n"));
+ return false;
+ }
+
+ if ( !(values = TALLOC_ZERO_P( subkeys, REGVAL_CTR )) ) {
+ DEBUG(0,("write_registry_tree: talloc() failed!\n"));
+ TALLOC_FREE(subkeys);
+ return false;
+ }
+
+ /* copy values into the REGVAL_CTR */
+
+ for ( i=0; i<nk->num_values; i++ ) {
+ regval_ctr_addvalue( values, nk->values[i].valuename, nk->values[i].type,
+ (const char *)nk->values[i].data, (nk->values[i].data_size & ~VK_DATA_IN_OFFSET) );
+ }
+
+ /* copy subkeys into the REGSUBKEY_CTR */
+
+ while ( (subkey = regfio_fetch_subkey( infile, nk )) ) {
+ regsubkey_ctr_addkey( subkeys, subkey->keyname );
+ }
+
+ key = regfio_write_key( outfile, nk->keyname, values, subkeys, nk->sec_desc->sec_desc, parent );
+
+ /* write each one of the subkeys out */
+
+ path = talloc_asprintf(subkeys,
+ "%s%s%s",
+ parentpath,
+ parent ? "\\" : "",
+ nk->keyname);
+ if (!path) {
+ TALLOC_FREE(subkeys);
+ return false;
+ }
+
+ nk->subkey_index = 0;
+ while ( (subkey = regfio_fetch_subkey( infile, nk )) ) {
+ write_registry_tree( infile, subkey, key, outfile, path );
+ }
+
+ d_printf("[%s]\n", path );
+ TALLOC_FREE(subkeys);
+
+ return true;
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_registry_dump(struct net_context *c, int argc, const char **argv)
+{
+ REGF_FILE *registry;
+ REGF_NK_REC *nk;
+
+ if (argc != 1 || c->display_usage) {
+ d_printf("Usage: net rpc registry dump <file> \n");
+ return -1;
+ }
+
+ d_printf("Opening %s....", argv[0]);
+ if ( !(registry = regfio_open( argv[0], O_RDONLY, 0)) ) {
+ d_fprintf(stderr, "Failed to open %s for reading\n", argv[0]);
+ return 1;
+ }
+ d_printf("ok\n");
+
+ /* get the root of the registry file */
+
+ if ((nk = regfio_rootkey( registry )) == NULL) {
+ d_fprintf(stderr, "Could not get rootkey\n");
+ regfio_close( registry );
+ return 1;
+ }
+ d_printf("[%s]\n", nk->keyname);
+ dump_values( nk );
+ d_printf("\n");
+
+ dump_registry_tree( registry, nk, nk->keyname );
+
+#if 0
+ talloc_report_full( registry->mem_ctx, stderr );
+#endif
+ d_printf("Closing registry...");
+ regfio_close( registry );
+ d_printf("ok\n");
+
+ return 0;
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_registry_copy(struct net_context *c, int argc, const char **argv )
+{
+ REGF_FILE *infile = NULL, *outfile = NULL;
+ REGF_NK_REC *nk;
+ int result = 1;
+
+ if (argc != 2 || c->display_usage) {
+ d_printf("Usage: net rpc registry copy <srcfile> <newfile>\n");
+ return -1;
+ }
+
+ d_printf("Opening %s....", argv[0]);
+ if ( !(infile = regfio_open( argv[0], O_RDONLY, 0 )) ) {
+ d_fprintf(stderr, "Failed to open %s for reading\n", argv[0]);
+ return 1;
+ }
+ d_printf("ok\n");
+
+ d_printf("Opening %s....", argv[1]);
+ if ( !(outfile = regfio_open( argv[1], (O_RDWR|O_CREAT|O_TRUNC), (S_IREAD|S_IWRITE) )) ) {
+ d_fprintf(stderr, "Failed to open %s for writing\n", argv[1]);
+ goto out;
+ }
+ d_printf("ok\n");
+
+ /* get the root of the registry file */
+
+ if ((nk = regfio_rootkey( infile )) == NULL) {
+ d_fprintf(stderr, "Could not get rootkey\n");
+ goto out;
+ }
+ d_printf("RootKey: [%s]\n", nk->keyname);
+
+ write_registry_tree( infile, nk, NULL, outfile, "" );
+
+ result = 0;
+
+out:
+
+ d_printf("Closing %s...", argv[1]);
+ if (outfile) {
+ regfio_close( outfile );
+ }
+ d_printf("ok\n");
+
+ d_printf("Closing %s...", argv[0]);
+ if (infile) {
+ regfio_close( infile );
+ }
+ d_printf("ok\n");
+
+ return( result);
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_registry_getsd_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ POLICY_HND pol_hive, pol_key;
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ struct KeySecurityData *sd = NULL;
+ uint32_t sec_info;
+ DATA_BLOB blob;
+ struct security_descriptor sec_desc;
+ uint32_t access_mask = REG_KEY_READ |
+ SEC_RIGHT_MAXIMUM_ALLOWED |
+ SEC_RIGHT_SYSTEM_SECURITY;
+
+ if (argc <1 || argc > 2 || c->display_usage) {
+ d_printf("Usage: net rpc registry getsd <path> <secinfo>\n");
+ d_printf("Example: net rpc registry getsd 'HKLM\\Software\\Samba'\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = registry_openkey(mem_ctx, pipe_hnd, argv[0],
+ access_mask,
+ &pol_hive, &pol_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "registry_openkey failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+
+ sd = TALLOC_ZERO_P(mem_ctx, struct KeySecurityData);
+ if (!sd) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ sd->size = 0x1000;
+
+ if (argc >= 2) {
+ sscanf(argv[1], "%x", &sec_info);
+ } else {
+ sec_info = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL;
+ }
+
+ status = registry_getsd(mem_ctx, pipe_hnd, &pol_key, sec_info, sd);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "getting sd failed: %s\n",
+ nt_errstr(status));
+ goto out;
+ }
+
+ blob.data = sd->data;
+ blob.length = sd->size;
+
+ ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &sec_desc,
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ goto out;
+ }
+ status = NT_STATUS_OK;
+
+ display_sec_desc(&sec_desc);
+
+ out:
+ rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_key, NULL);
+ rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_hive, NULL);
+
+ return status;
+}
+
+
+static int rpc_registry_getsd(struct net_context *c, int argc, const char **argv)
+{
+ return run_rpc_command(c, NULL, &ndr_table_winreg.syntax_id, 0,
+ rpc_registry_getsd_internal, argc, argv);
+}
+
+/********************************************************************
+********************************************************************/
+
+int net_rpc_registry(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "enumerate",
+ rpc_registry_enumerate,
+ NET_TRANSPORT_RPC,
+ "Enumerate registry keys and values",
+ "net rpc registry enumerate\n"
+ " Enumerate registry keys and values"
+ },
+ {
+ "createkey",
+ rpc_registry_createkey,
+ NET_TRANSPORT_RPC,
+ "Create a new registry key",
+ "net rpc registry createkey\n"
+ " Create a new registry key"
+ },
+ {
+ "deletekey",
+ rpc_registry_deletekey,
+ NET_TRANSPORT_RPC,
+ "Delete a registry key",
+ "net rpc registry deletekey\n"
+ " Delete a registry key"
+ },
+ {
+ "getvalue",
+ rpc_registry_getvalue,
+ NET_TRANSPORT_RPC,
+ "Print a registry value",
+ "net rpc registry getvalue\n"
+ " Print a registry value"
+ },
+ {
+ "getvalueraw",
+ rpc_registry_getvalueraw,
+ NET_TRANSPORT_RPC,
+ "Print a registry value",
+ "net rpc registry getvalueraw\n"
+ " Print a registry value (raw version)"
+ },
+ {
+ "setvalue",
+ rpc_registry_setvalue,
+ NET_TRANSPORT_RPC,
+ "Set a new registry value",
+ "net rpc registry setvalue\n"
+ " Set a new registry value"
+ },
+ {
+ "deletevalue",
+ rpc_registry_deletevalue,
+ NET_TRANSPORT_RPC,
+ "Delete a registry value",
+ "net rpc registry deletevalue\n"
+ " Delete a registry value"
+ },
+ {
+ "save",
+ rpc_registry_save,
+ NET_TRANSPORT_RPC,
+ "Save a registry file",
+ "net rpc registry save\n"
+ " Save a registry file"
+ },
+ {
+ "dump",
+ rpc_registry_dump,
+ NET_TRANSPORT_RPC,
+ "Dump a registry file",
+ "net rpc registry dump\n"
+ " Dump a registry file"
+ },
+ {
+ "copy",
+ rpc_registry_copy,
+ NET_TRANSPORT_RPC,
+ "Copy a registry file",
+ "net rpc registry copy\n"
+ " Copy a registry file"
+ },
+ {
+ "getsd",
+ rpc_registry_getsd,
+ NET_TRANSPORT_RPC,
+ "Get security descriptor",
+ "net rpc registry getsd\n"
+ " Get security descriptior"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net rpc registry", func);
+}
diff --git a/source3/utils/net_rpc_rights.c b/source3/utils/net_rpc_rights.c
new file mode 100644
index 0000000000..2bc5efe3cf
--- /dev/null
+++ b/source3/utils/net_rpc_rights.c
@@ -0,0 +1,708 @@
+/*
+ Samba Unix/Linux SMB client library
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) Gerald (Jerry) Carter 2004
+ Copyright (C) Guenther Deschner 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "utils/net.h"
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS sid_to_name(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ DOM_SID *sid,
+ fstring name)
+{
+ POLICY_HND pol;
+ enum lsa_SidType *sid_types = NULL;
+ NTSTATUS result;
+ char **domains = NULL, **names = NULL;
+
+ result = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, &pol);
+
+ if ( !NT_STATUS_IS_OK(result) )
+ return result;
+
+ result = rpccli_lsa_lookup_sids(pipe_hnd, mem_ctx, &pol, 1, sid, &domains, &names, &sid_types);
+
+ if ( NT_STATUS_IS_OK(result) ) {
+ if ( *domains[0] )
+ fstr_sprintf( name, "%s\\%s", domains[0], names[0] );
+ else
+ fstrcpy( name, names[0] );
+ }
+
+ rpccli_lsa_Close(pipe_hnd, mem_ctx, &pol);
+ return result;
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS name_to_sid(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ DOM_SID *sid, const char *name)
+{
+ POLICY_HND pol;
+ enum lsa_SidType *sid_types;
+ NTSTATUS result;
+ DOM_SID *sids;
+
+ /* maybe its a raw SID */
+ if ( strncmp(name, "S-", 2) == 0 && string_to_sid(sid, name) ) {
+ return NT_STATUS_OK;
+ }
+
+ result = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, &pol);
+
+ if ( !NT_STATUS_IS_OK(result) )
+ return result;
+
+ result = rpccli_lsa_lookup_names(pipe_hnd, mem_ctx, &pol, 1, &name,
+ NULL, 1, &sids, &sid_types);
+
+ if ( NT_STATUS_IS_OK(result) )
+ sid_copy( sid, &sids[0] );
+
+ rpccli_lsa_Close(pipe_hnd, mem_ctx, &pol);
+ return result;
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS enum_privileges(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *ctx,
+ POLICY_HND *pol )
+{
+ NTSTATUS result;
+ uint32 enum_context = 0;
+ uint32 pref_max_length=0x1000;
+ int i;
+ uint16 lang_id=0;
+ uint16 lang_id_sys=0;
+ uint16 lang_id_desc;
+ struct lsa_StringLarge *description = NULL;
+ struct lsa_PrivArray priv_array;
+
+ result = rpccli_lsa_EnumPrivs(pipe_hnd, ctx,
+ pol,
+ &enum_context,
+ &priv_array,
+ pref_max_length);
+
+ if ( !NT_STATUS_IS_OK(result) )
+ return result;
+
+ /* Print results */
+
+ for (i = 0; i < priv_array.count; i++) {
+
+ struct lsa_String lsa_name;
+
+ d_printf("%30s ",
+ priv_array.privs[i].name.string ? priv_array.privs[i].name.string : "*unknown*" );
+
+ /* try to get the description */
+
+ init_lsa_String(&lsa_name, priv_array.privs[i].name.string);
+
+ result = rpccli_lsa_LookupPrivDisplayName(pipe_hnd, ctx,
+ pol,
+ &lsa_name,
+ lang_id,
+ lang_id_sys,
+ &description,
+ &lang_id_desc);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_printf("??????\n");
+ continue;
+ }
+
+ d_printf("%s\n", description->string);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS check_privilege_for_user(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *ctx,
+ POLICY_HND *pol,
+ DOM_SID *sid,
+ const char *right)
+{
+ NTSTATUS result;
+ struct lsa_RightSet rights;
+ int i;
+
+ result = rpccli_lsa_EnumAccountRights(pipe_hnd, ctx,
+ pol,
+ sid,
+ &rights);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ if (rights.count == 0) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ for (i = 0; i < rights.count; i++) {
+ if (StrCaseCmp(rights.names[i].string, right) == 0) {
+ return NT_STATUS_OK;
+ }
+ }
+
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS enum_privileges_for_user(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *ctx,
+ POLICY_HND *pol,
+ DOM_SID *sid )
+{
+ NTSTATUS result;
+ struct lsa_RightSet rights;
+ int i;
+
+ result = rpccli_lsa_EnumAccountRights(pipe_hnd, ctx,
+ pol,
+ sid,
+ &rights);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ if (rights.count == 0) {
+ d_printf("No privileges assigned\n");
+ }
+
+ for (i = 0; i < rights.count; i++) {
+ printf("%s\n", rights.names[i].string);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS enum_accounts_for_privilege(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *ctx,
+ POLICY_HND *pol,
+ const char *privilege)
+{
+ NTSTATUS result;
+ uint32 enum_context=0;
+ uint32 pref_max_length=0x1000;
+ struct lsa_SidArray sid_array;
+ int i;
+ fstring name;
+
+ result = rpccli_lsa_EnumAccounts(pipe_hnd, ctx,
+ pol,
+ &enum_context,
+ &sid_array,
+ pref_max_length);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ d_printf("%s:\n", privilege);
+
+ for ( i=0; i<sid_array.num_sids; i++ ) {
+
+ result = check_privilege_for_user(pipe_hnd, ctx, pol,
+ sid_array.sids[i].sid,
+ privilege);
+
+ if ( ! NT_STATUS_IS_OK(result)) {
+ if ( ! NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ return result;
+ }
+ continue;
+ }
+
+ /* try to convert the SID to a name. Fall back to
+ printing the raw SID if necessary */
+ result = sid_to_name( pipe_hnd, ctx, sid_array.sids[i].sid, name );
+ if ( !NT_STATUS_IS_OK (result) )
+ sid_to_fstring(name, sid_array.sids[i].sid);
+
+ d_printf(" %s\n", name);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS enum_privileges_for_accounts(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *ctx,
+ POLICY_HND *pol)
+{
+ NTSTATUS result;
+ uint32 enum_context=0;
+ uint32 pref_max_length=0x1000;
+ struct lsa_SidArray sid_array;
+ int i;
+ fstring name;
+
+ result = rpccli_lsa_EnumAccounts(pipe_hnd, ctx,
+ pol,
+ &enum_context,
+ &sid_array,
+ pref_max_length);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ for ( i=0; i<sid_array.num_sids; i++ ) {
+
+ /* try to convert the SID to a name. Fall back to
+ printing the raw SID if necessary */
+
+ result = sid_to_name(pipe_hnd, ctx, sid_array.sids[i].sid, name);
+ if ( !NT_STATUS_IS_OK (result) )
+ sid_to_fstring(name, sid_array.sids[i].sid);
+
+ d_printf("%s\n", name);
+
+ result = enum_privileges_for_user(pipe_hnd, ctx, pol,
+ sid_array.sids[i].sid);
+ if ( !NT_STATUS_IS_OK(result) )
+ return result;
+
+ d_printf("\n");
+ }
+
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_rights_list_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv )
+{
+ POLICY_HND pol;
+ NTSTATUS result;
+ DOM_SID sid;
+ fstring privname;
+ struct lsa_String lsa_name;
+ struct lsa_StringLarge *description = NULL;
+ uint16 lang_id = 0;
+ uint16 lang_id_sys = 0;
+ uint16 lang_id_desc;
+
+ result = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, &pol);
+
+ if ( !NT_STATUS_IS_OK(result) )
+ return result;
+
+ /* backwards compatibility; just list available privileges if no arguement */
+
+ if (argc == 0) {
+ result = enum_privileges(pipe_hnd, mem_ctx, &pol );
+ goto done;
+ }
+
+ if (strequal(argv[0], "privileges")) {
+ int i = 1;
+
+ if (argv[1] == NULL) {
+ result = enum_privileges(pipe_hnd, mem_ctx, &pol );
+ goto done;
+ }
+
+ while ( argv[i] != NULL ) {
+ fstrcpy(privname, argv[i]);
+ init_lsa_String(&lsa_name, argv[i]);
+ i++;
+
+ /* verify that this is a valid privilege for error reporting */
+ result = rpccli_lsa_LookupPrivDisplayName(pipe_hnd, mem_ctx,
+ &pol,
+ &lsa_name,
+ lang_id,
+ lang_id_sys,
+ &description,
+ &lang_id_desc);
+
+ if ( !NT_STATUS_IS_OK(result) ) {
+ if ( NT_STATUS_EQUAL( result, NT_STATUS_NO_SUCH_PRIVILEGE ) )
+ d_fprintf(stderr, "No such privilege exists: %s.\n", privname);
+ else
+ d_fprintf(stderr, "Error resolving privilege display name [%s].\n", nt_errstr(result));
+ continue;
+ }
+
+ result = enum_accounts_for_privilege(pipe_hnd, mem_ctx, &pol, privname);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Error enumerating accounts for privilege %s [%s].\n",
+ privname, nt_errstr(result));
+ continue;
+ }
+ }
+ goto done;
+ }
+
+ /* special case to enumerate all privileged SIDs with associated rights */
+
+ if (strequal( argv[0], "accounts")) {
+ int i = 1;
+
+ if (argv[1] == NULL) {
+ result = enum_privileges_for_accounts(pipe_hnd, mem_ctx, &pol);
+ goto done;
+ }
+
+ while (argv[i] != NULL) {
+ result = name_to_sid(pipe_hnd, mem_ctx, &sid, argv[i]);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+ result = enum_privileges_for_user(pipe_hnd, mem_ctx, &pol, &sid);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+ i++;
+ }
+ goto done;
+ }
+
+ /* backward comaptibility: if no keyword provided, treat the key
+ as an account name */
+ if (argc > 1) {
+ d_printf("Usage: net rpc rights list [[accounts|privileges] [name|SID]]\n");
+ result = NT_STATUS_OK;
+ goto done;
+ }
+
+ result = name_to_sid(pipe_hnd, mem_ctx, &sid, argv[0]);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+ result = enum_privileges_for_user(pipe_hnd, mem_ctx, &pol, &sid );
+
+done:
+ rpccli_lsa_Close(pipe_hnd, mem_ctx, &pol);
+
+ return result;
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_rights_grant_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv )
+{
+ POLICY_HND dom_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct lsa_RightSet rights;
+ int i;
+
+ DOM_SID sid;
+
+ if (argc < 2 ) {
+ d_printf("Usage: net rpc rights grant <name|SID> <rights...>\n");
+ return NT_STATUS_OK;
+ }
+
+ result = name_to_sid(pipe_hnd, mem_ctx, &sid, argv[0]);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ result = rpccli_lsa_open_policy2(pipe_hnd, mem_ctx, true,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &dom_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ rights.count = argc-1;
+ rights.names = TALLOC_ARRAY(mem_ctx, struct lsa_StringLarge,
+ rights.count);
+ if (!rights.names) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<argc-1; i++) {
+ init_lsa_StringLarge(&rights.names[i], argv[i+1]);
+ }
+
+ result = rpccli_lsa_AddAccountRights(pipe_hnd, mem_ctx,
+ &dom_pol,
+ &sid,
+ &rights);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ d_printf("Successfully granted rights.\n");
+
+ done:
+ if ( !NT_STATUS_IS_OK(result) ) {
+ d_fprintf(stderr, "Failed to grant privileges for %s (%s)\n",
+ argv[0], nt_errstr(result));
+ }
+
+ rpccli_lsa_Close(pipe_hnd, mem_ctx, &dom_pol);
+
+ return result;
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_rights_revoke_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv )
+{
+ POLICY_HND dom_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct lsa_RightSet rights;
+ DOM_SID sid;
+ int i;
+
+ if (argc < 2 ) {
+ d_printf("Usage: net rpc rights revoke <name|SID> <rights...>\n");
+ return NT_STATUS_OK;
+ }
+
+ result = name_to_sid(pipe_hnd, mem_ctx, &sid, argv[0]);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ result = rpccli_lsa_open_policy2(pipe_hnd, mem_ctx, true,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &dom_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ rights.count = argc-1;
+ rights.names = TALLOC_ARRAY(mem_ctx, struct lsa_StringLarge,
+ rights.count);
+ if (!rights.names) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<argc-1; i++) {
+ init_lsa_StringLarge(&rights.names[i], argv[i+1]);
+ }
+
+ result = rpccli_lsa_RemoveAccountRights(pipe_hnd, mem_ctx,
+ &dom_pol,
+ &sid,
+ false,
+ &rights);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ d_printf("Successfully revoked rights.\n");
+
+done:
+ if ( !NT_STATUS_IS_OK(result) ) {
+ d_fprintf(stderr, "Failed to revoke privileges for %s (%s)\n",
+ argv[0], nt_errstr(result));
+ }
+
+ rpccli_lsa_Close(pipe_hnd, mem_ctx, &dom_pol);
+
+ return result;
+}
+
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_rights_list(struct net_context *c, int argc, const char **argv )
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc rights list [{accounts|privileges} "
+ "[name|SID]]\n"
+ " View available/assigned privileges\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_lsarpc.syntax_id, 0,
+ rpc_rights_list_internal, argc, argv );
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_rights_grant(struct net_context *c, int argc, const char **argv )
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc rights grant <name|SID> <right>\n"
+ " Assign privilege[s]\n");
+ d_printf("For example:\n");
+ d_printf(" net rpc rights grant 'VALE\\biddle' "
+ "SePrintOperatorPrivilege SeDiskOperatorPrivilege\n");
+ d_printf(" would grant the printer admin and disk manager "
+ "rights to the user 'VALE\\biddle'\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_lsarpc.syntax_id, 0,
+ rpc_rights_grant_internal, argc, argv );
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_rights_revoke(struct net_context *c, int argc, const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc rights revoke <name|SID> <right>\n"
+ " Revoke privilege[s]\n");
+ d_printf("For example:\n");
+ d_printf(" net rpc rights revoke 'VALE\\biddle' "
+ "SePrintOperatorPrivilege SeDiskOperatorPrivilege\n");
+ d_printf(" would revoke the printer admin and disk manager "
+ "rights from the user 'VALE\\biddle'\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_lsarpc.syntax_id, 0,
+ rpc_rights_revoke_internal, argc, argv );
+}
+
+/********************************************************************
+********************************************************************/
+
+int net_rpc_rights(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "list",
+ rpc_rights_list,
+ NET_TRANSPORT_RPC,
+ "View available/assigned privileges",
+ "net rpc rights list\n"
+ " View available/assigned privileges"
+ },
+ {
+ "grant",
+ rpc_rights_grant,
+ NET_TRANSPORT_RPC,
+ "Assign privilege[s]",
+ "net rpc rights grant\n"
+ " Assign privilege[s]"
+ },
+ {
+ "revoke",
+ rpc_rights_revoke,
+ NET_TRANSPORT_RPC,
+ "Revoke privilege[s]",
+ "net rpc rights revoke\n"
+ " Revoke privilege[s]"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net rpc rights", func);
+}
+
+static NTSTATUS rpc_sh_rights_list(struct net_context *c,
+ TALLOC_CTX *mem_ctx, struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ return rpc_rights_list_internal(c, ctx->domain_sid, ctx->domain_name,
+ ctx->cli, pipe_hnd, mem_ctx,
+ argc, argv);
+}
+
+static NTSTATUS rpc_sh_rights_grant(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ return rpc_rights_grant_internal(c, ctx->domain_sid, ctx->domain_name,
+ ctx->cli, pipe_hnd, mem_ctx,
+ argc, argv);
+}
+
+static NTSTATUS rpc_sh_rights_revoke(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ return rpc_rights_revoke_internal(c, ctx->domain_sid, ctx->domain_name,
+ ctx->cli, pipe_hnd, mem_ctx,
+ argc, argv);
+}
+
+struct rpc_sh_cmd *net_rpc_rights_cmds(struct net_context *c, TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx)
+{
+ static struct rpc_sh_cmd cmds[] = {
+
+ { "list", NULL, &ndr_table_lsarpc.syntax_id, rpc_sh_rights_list,
+ "View available or assigned privileges" },
+
+ { "grant", NULL, &ndr_table_lsarpc.syntax_id, rpc_sh_rights_grant,
+ "Assign privilege[s]" },
+
+ { "revoke", NULL, &ndr_table_lsarpc.syntax_id, rpc_sh_rights_revoke,
+ "Revoke privilege[s]" },
+
+ { NULL, NULL, 0, NULL, NULL }
+ };
+
+ return cmds;
+}
+
diff --git a/source3/utils/net_rpc_samsync.c b/source3/utils/net_rpc_samsync.c
new file mode 100644
index 0000000000..c0922efe6b
--- /dev/null
+++ b/source3/utils/net_rpc_samsync.c
@@ -0,0 +1,362 @@
+/*
+ Unix SMB/CIFS implementation.
+ dump the remote SAM using rpc samsync operations
+
+ Copyright (C) Andrew Tridgell 2002
+ Copyright (C) Tim Potter 2001,2002
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
+ Modified by Volker Lendecke 2002
+ Copyright (C) Jeremy Allison 2005.
+ Copyright (C) Guenther Deschner 2008.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+/* dump sam database via samsync rpc calls */
+NTSTATUS rpc_samdump_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ struct samsync_context *ctx = NULL;
+ NTSTATUS status;
+
+ status = libnet_samsync_init_context(mem_ctx,
+ domain_sid,
+ &ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ctx->mode = NET_SAMSYNC_MODE_DUMP;
+ ctx->cli = pipe_hnd;
+ ctx->delta_fn = display_sam_entries;
+ ctx->domain_name = domain_name;
+
+ libnet_samsync(SAM_DATABASE_DOMAIN, ctx);
+
+ libnet_samsync(SAM_DATABASE_BUILTIN, ctx);
+
+ libnet_samsync(SAM_DATABASE_PRIVS, ctx);
+
+ TALLOC_FREE(ctx);
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Basic usage function for 'net rpc vampire'
+ *
+ * @param c A net_context structure
+ * @param argc Standard main() style argc
+ * @param argc Standard main() style argv. Initial components are already
+ * stripped
+ **/
+
+int rpc_vampire_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("net rpc vampire ([ldif [<ldif-filename>] | [keytab] [<keytab-filename]) [options]\n"
+ "\t to pull accounts from a remote PDC where we are a BDC\n"
+ "\t\t no args puts accounts in local passdb from smb.conf\n"
+ "\t\t ldif - put accounts in ldif format (file defaults to "
+ "/tmp/tmp.ldif)\n"
+ "\t\t keytab - put account passwords in krb5 keytab (defaults "
+ "to system keytab)\n");
+
+ net_common_flags_usage(c, argc, argv);
+ return -1;
+}
+
+
+/* dump sam database via samsync rpc calls */
+NTSTATUS rpc_vampire_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS result;
+ struct samsync_context *ctx = NULL;
+
+ if (!sid_equal(domain_sid, get_global_sam_sid())) {
+ d_printf("Cannot import users from %s at this time, "
+ "as the current domain:\n\t%s: %s\nconflicts "
+ "with the remote domain\n\t%s: %s\n"
+ "Perhaps you need to set: \n\n\tsecurity=user\n\t"
+ "workgroup=%s\n\n in your smb.conf?\n",
+ domain_name,
+ get_global_sam_name(),
+ sid_string_dbg(get_global_sam_sid()),
+ domain_name,
+ sid_string_dbg(domain_sid),
+ domain_name);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ result = libnet_samsync_init_context(mem_ctx,
+ domain_sid,
+ &ctx);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ ctx->mode = NET_SAMSYNC_MODE_FETCH_PASSDB;
+ ctx->cli = pipe_hnd;
+ ctx->delta_fn = fetch_sam_entries;
+ ctx->domain_name = domain_name;
+
+ /* fetch domain */
+ result = libnet_samsync(SAM_DATABASE_DOMAIN, ctx);
+
+ if (!NT_STATUS_IS_OK(result) && ctx->error_message) {
+ d_fprintf(stderr, "%s\n", ctx->error_message);
+ goto fail;
+ }
+
+ if (ctx->result_message) {
+ d_fprintf(stdout, "%s\n", ctx->result_message);
+ }
+
+ /* fetch builtin */
+ ctx->domain_sid = sid_dup_talloc(mem_ctx, &global_sid_Builtin);
+ ctx->domain_sid_str = sid_string_talloc(mem_ctx, ctx->domain_sid);
+ result = libnet_samsync(SAM_DATABASE_BUILTIN, ctx);
+
+ if (!NT_STATUS_IS_OK(result) && ctx->error_message) {
+ d_fprintf(stderr, "%s\n", ctx->error_message);
+ goto fail;
+ }
+
+ if (ctx->result_message) {
+ d_fprintf(stdout, "%s\n", ctx->result_message);
+ }
+
+ fail:
+ TALLOC_FREE(ctx);
+ return result;
+}
+
+NTSTATUS rpc_vampire_ldif_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ struct samsync_context *ctx = NULL;
+
+ status = libnet_samsync_init_context(mem_ctx,
+ domain_sid,
+ &ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (argc >= 1) {
+ ctx->output_filename = argv[0];
+ }
+
+ ctx->mode = NET_SAMSYNC_MODE_FETCH_LDIF;
+ ctx->cli = pipe_hnd;
+ ctx->delta_fn = fetch_sam_entries_ldif;
+ ctx->domain_name = domain_name;
+
+ /* fetch domain */
+ status = libnet_samsync(SAM_DATABASE_DOMAIN, ctx);
+
+ if (!NT_STATUS_IS_OK(status) && ctx->error_message) {
+ d_fprintf(stderr, "%s\n", ctx->error_message);
+ goto fail;
+ }
+
+ if (ctx->result_message) {
+ d_fprintf(stdout, "%s\n", ctx->result_message);
+ }
+
+ /* fetch builtin */
+ ctx->domain_sid = sid_dup_talloc(mem_ctx, &global_sid_Builtin);
+ ctx->domain_sid_str = sid_string_talloc(mem_ctx, ctx->domain_sid);
+ status = libnet_samsync(SAM_DATABASE_BUILTIN, ctx);
+
+ if (!NT_STATUS_IS_OK(status) && ctx->error_message) {
+ d_fprintf(stderr, "%s\n", ctx->error_message);
+ goto fail;
+ }
+
+ if (ctx->result_message) {
+ d_fprintf(stdout, "%s\n", ctx->result_message);
+ }
+
+ fail:
+ TALLOC_FREE(ctx);
+ return status;
+}
+
+int rpc_vampire_ldif(struct net_context *c, int argc, const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc vampire ldif\n"
+ " Dump remote SAM database to LDIF file or stdout\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_netlogon.syntax_id, 0,
+ rpc_vampire_ldif_internals, argc, argv);
+}
+
+
+NTSTATUS rpc_vampire_keytab_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ struct samsync_context *ctx = NULL;
+
+ status = libnet_samsync_init_context(mem_ctx,
+ domain_sid,
+ &ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (argc >= 1) {
+ ctx->output_filename = argv[0];
+ }
+
+ ctx->mode = NET_SAMSYNC_MODE_FETCH_KEYTAB;
+ ctx->cli = pipe_hnd;
+ ctx->delta_fn = fetch_sam_entries_keytab;
+ ctx->domain_name = domain_name;
+ ctx->username = c->opt_user_name;
+ ctx->password = c->opt_password;
+
+ /* fetch domain */
+ status = libnet_samsync(SAM_DATABASE_DOMAIN, ctx);
+
+ if (!NT_STATUS_IS_OK(status) && ctx->error_message) {
+ d_fprintf(stderr, "%s\n", ctx->error_message);
+ goto out;
+ }
+
+ if (ctx->result_message) {
+ d_fprintf(stdout, "%s\n", ctx->result_message);
+ }
+
+ out:
+ TALLOC_FREE(ctx);
+
+ return status;
+}
+
+static NTSTATUS rpc_vampire_keytab_ds_internals(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ struct dssync_context *ctx = NULL;
+
+ status = libnet_dssync_init_context(mem_ctx,
+ &ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ctx->force_full_replication = c->opt_force_full_repl ? true : false;
+ ctx->clean_old_entries = c->opt_clean_old_entries ? true : false;
+
+ if (argc >= 1) {
+ ctx->output_filename = argv[0];
+ }
+ if (argc >= 2) {
+ ctx->object_dns = &argv[1];
+ ctx->object_count = argc - 1;
+ ctx->single_object_replication = c->opt_single_obj_repl ? true
+ : false;
+ }
+
+ ctx->cli = pipe_hnd;
+ ctx->domain_name = domain_name;
+ ctx->ops = &libnet_dssync_keytab_ops;
+
+ status = libnet_dssync(mem_ctx, ctx);
+ if (!NT_STATUS_IS_OK(status) && ctx->error_message) {
+ d_fprintf(stderr, "%s\n", ctx->error_message);
+ goto out;
+ }
+
+ if (ctx->result_message) {
+ d_fprintf(stdout, "%s\n", ctx->result_message);
+ }
+
+ out:
+ TALLOC_FREE(ctx);
+
+ return status;
+}
+
+/**
+ * Basic function for 'net rpc vampire keytab'
+ *
+ * @param c A net_context structure
+ * @param argc Standard main() style argc
+ * @param argc Standard main() style argv. Initial components are already
+ * stripped
+ **/
+
+int rpc_vampire_keytab(struct net_context *c, int argc, const char **argv)
+{
+ int ret = 0;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc vampire keytab\n"
+ " Dump remote SAM database to Kerberos keytab file\n");
+ return 0;
+ }
+
+ ret = run_rpc_command(c, NULL, &ndr_table_drsuapi.syntax_id,
+ NET_FLAGS_SEAL,
+ rpc_vampire_keytab_ds_internals, argc, argv);
+ if (ret == 0) {
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_netlogon.syntax_id, 0,
+ rpc_vampire_keytab_internals,
+ argc, argv);
+}
diff --git a/source3/utils/net_rpc_service.c b/source3/utils/net_rpc_service.c
new file mode 100644
index 0000000000..d1349a903d
--- /dev/null
+++ b/source3/utils/net_rpc_service.c
@@ -0,0 +1,725 @@
+/*
+ Samba Unix/Linux SMB client library
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) Gerald (Jerry) Carter 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "includes.h"
+#include "utils/net.h"
+
+
+struct svc_state_msg {
+ uint32 flag;
+ const char *message;
+};
+
+static struct svc_state_msg state_msg_table[] = {
+ { SVCCTL_STOPPED, "stopped" },
+ { SVCCTL_START_PENDING, "start pending" },
+ { SVCCTL_STOP_PENDING, "stop pending" },
+ { SVCCTL_RUNNING, "running" },
+ { SVCCTL_CONTINUE_PENDING, "resume pending" },
+ { SVCCTL_PAUSE_PENDING, "pause pending" },
+ { SVCCTL_PAUSED, "paused" },
+ { 0, NULL }
+};
+
+
+/********************************************************************
+********************************************************************/
+const char *svc_status_string( uint32 state )
+{
+ fstring msg;
+ int i;
+
+ fstr_sprintf( msg, "Unknown State [%d]", state );
+
+ for ( i=0; state_msg_table[i].message; i++ ) {
+ if ( state_msg_table[i].flag == state ) {
+ fstrcpy( msg, state_msg_table[i].message );
+ break;
+ }
+ }
+
+ return talloc_strdup(talloc_tos(), msg);
+}
+
+/********************************************************************
+********************************************************************/
+
+static WERROR query_service_state(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *hSCM,
+ const char *service,
+ uint32 *state )
+{
+ POLICY_HND hService;
+ SERVICE_STATUS service_status;
+ WERROR result = WERR_GENERAL_FAILURE;
+ NTSTATUS status;
+
+ /* now cycle until the status is actually 'watch_state' */
+
+ status = rpccli_svcctl_OpenServiceW(pipe_hnd, mem_ctx,
+ hSCM,
+ service,
+ SC_RIGHT_SVC_QUERY_STATUS,
+ &hService,
+ &result);
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
+ d_fprintf(stderr, "Failed to open service. [%s]\n", dos_errstr(result));
+ return result;
+ }
+
+ status = rpccli_svcctl_QueryServiceStatus(pipe_hnd, mem_ctx,
+ &hService,
+ &service_status,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
+ *state = service_status.state;
+ }
+
+ rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hService, NULL);
+
+ return result;
+}
+
+/********************************************************************
+********************************************************************/
+
+static WERROR watch_service_state(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *hSCM,
+ const char *service,
+ uint32 watch_state,
+ uint32 *final_state )
+{
+ uint32 i;
+ uint32 state = 0;
+ WERROR result = WERR_GENERAL_FAILURE;
+
+
+ i = 0;
+ while ( (state != watch_state ) && i<30 ) {
+ /* get the status */
+
+ result = query_service_state(pipe_hnd, mem_ctx, hSCM, service, &state );
+ if ( !W_ERROR_IS_OK(result) ) {
+ break;
+ }
+
+ d_printf(".");
+ i++;
+ sys_usleep( 100 );
+ }
+ d_printf("\n");
+
+ *final_state = state;
+
+ return result;
+}
+
+/********************************************************************
+********************************************************************/
+
+static WERROR control_service(struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *hSCM,
+ const char *service,
+ uint32 control,
+ uint32 watch_state )
+{
+ POLICY_HND hService;
+ WERROR result = WERR_GENERAL_FAILURE;
+ NTSTATUS status;
+ SERVICE_STATUS service_status;
+ uint32 state = 0;
+
+ /* Open the Service */
+
+ status = rpccli_svcctl_OpenServiceW(pipe_hnd, mem_ctx,
+ hSCM,
+ service,
+ (SC_RIGHT_SVC_STOP|SC_RIGHT_SVC_PAUSE_CONTINUE),
+ &hService,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
+ d_fprintf(stderr, "Failed to open service. [%s]\n", dos_errstr(result));
+ goto done;
+ }
+
+ /* get the status */
+
+ status = rpccli_svcctl_ControlService(pipe_hnd, mem_ctx,
+ &hService,
+ control,
+ &service_status,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
+ d_fprintf(stderr, "Control service request failed. [%s]\n", dos_errstr(result));
+ goto done;
+ }
+
+ /* loop -- checking the state until we are where we want to be */
+
+ result = watch_service_state(pipe_hnd, mem_ctx, hSCM, service, watch_state, &state );
+
+ d_printf("%s service is %s.\n", service, svc_status_string(state));
+
+done:
+ rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hService, NULL);
+
+ return result;
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_service_list_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv )
+{
+ POLICY_HND hSCM;
+ ENUM_SERVICES_STATUS *services;
+ WERROR result = WERR_GENERAL_FAILURE;
+ NTSTATUS status;
+ fstring servicename;
+ fstring displayname;
+ uint32 num_services = 0;
+ int i;
+
+ if (argc != 0 ) {
+ d_printf("Usage: net rpc service list\n");
+ return NT_STATUS_OK;
+ }
+
+ status = rpccli_svcctl_OpenSCManagerW(pipe_hnd, mem_ctx,
+ pipe_hnd->srv_name_slash,
+ NULL,
+ SC_RIGHT_MGR_ENUMERATE_SERVICE,
+ &hSCM,
+ &result);
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ d_fprintf(stderr, "Failed to open Service Control Manager. [%s]\n", dos_errstr(result));
+ return werror_to_ntstatus(result);
+ }
+
+ result = rpccli_svcctl_enumerate_services(pipe_hnd, mem_ctx, &hSCM, SVCCTL_TYPE_WIN32,
+ SVCCTL_STATE_ALL, &num_services, &services );
+
+ if ( !W_ERROR_IS_OK(result) ) {
+ d_fprintf(stderr, "Failed to enumerate services. [%s]\n", dos_errstr(result));
+ goto done;
+ }
+
+ if ( num_services == 0 )
+ d_printf("No services returned\n");
+
+ for ( i=0; i<num_services; i++ ) {
+ rpcstr_pull( servicename, services[i].servicename.buffer, sizeof(servicename), -1, STR_TERMINATE );
+ rpcstr_pull( displayname, services[i].displayname.buffer, sizeof(displayname), -1, STR_TERMINATE );
+
+ d_printf("%-20s \"%s\"\n", servicename, displayname);
+ }
+
+done:
+ rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hSCM, NULL);
+
+ return werror_to_ntstatus(result);
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_service_status_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv )
+{
+ POLICY_HND hSCM, hService;
+ WERROR result = WERR_GENERAL_FAILURE;
+ NTSTATUS status;
+ SERVICE_STATUS service_status;
+ SERVICE_CONFIG config;
+ fstring ascii_string;
+
+ if (argc != 1 ) {
+ d_printf("Usage: net rpc service status <service>\n");
+ return NT_STATUS_OK;
+ }
+
+ /* Open the Service Control Manager */
+ status = rpccli_svcctl_OpenSCManagerW(pipe_hnd, mem_ctx,
+ pipe_hnd->srv_name_slash,
+ NULL,
+ SC_RIGHT_MGR_ENUMERATE_SERVICE,
+ &hSCM,
+ &result);
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ d_fprintf(stderr, "Failed to open Service Control Manager. [%s]\n", dos_errstr(result));
+ return werror_to_ntstatus(result);
+ }
+
+ /* Open the Service */
+
+ status = rpccli_svcctl_OpenServiceW(pipe_hnd, mem_ctx,
+ &hSCM,
+ argv[0],
+ (SC_RIGHT_SVC_QUERY_STATUS|SC_RIGHT_SVC_QUERY_CONFIG),
+ &hService,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
+ d_fprintf(stderr, "Failed to open service. [%s]\n", dos_errstr(result));
+ goto done;
+ }
+
+ /* get the status */
+
+ status = rpccli_svcctl_QueryServiceStatus(pipe_hnd, mem_ctx,
+ &hService,
+ &service_status,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
+ d_fprintf(stderr, "Query status request failed. [%s]\n", dos_errstr(result));
+ goto done;
+ }
+
+ d_printf("%s service is %s.\n", argv[0], svc_status_string(service_status.state));
+
+ /* get the config */
+
+ result = rpccli_svcctl_query_config(pipe_hnd, mem_ctx, &hService, &config );
+ if ( !W_ERROR_IS_OK(result) ) {
+ d_fprintf(stderr, "Query config request failed. [%s]\n", dos_errstr(result));
+ goto done;
+ }
+
+ /* print out the configuration information for the service */
+
+ d_printf("Configuration details:\n");
+ d_printf("\tControls Accepted = 0x%x\n", service_status.controls_accepted);
+ d_printf("\tService Type = 0x%x\n", config.service_type);
+ d_printf("\tStart Type = 0x%x\n", config.start_type);
+ d_printf("\tError Control = 0x%x\n", config.error_control);
+ d_printf("\tTag ID = 0x%x\n", config.tag_id);
+
+ if ( config.executablepath ) {
+ rpcstr_pull( ascii_string, config.executablepath->buffer, sizeof(ascii_string), -1, STR_TERMINATE );
+ d_printf("\tExecutable Path = %s\n", ascii_string);
+ }
+
+ if ( config.loadordergroup ) {
+ rpcstr_pull( ascii_string, config.loadordergroup->buffer, sizeof(ascii_string), -1, STR_TERMINATE );
+ d_printf("\tLoad Order Group = %s\n", ascii_string);
+ }
+
+ if ( config.dependencies ) {
+ rpcstr_pull( ascii_string, config.dependencies->buffer, sizeof(ascii_string), -1, STR_TERMINATE );
+ d_printf("\tDependencies = %s\n", ascii_string);
+ }
+
+ if ( config.startname ) {
+ rpcstr_pull( ascii_string, config.startname->buffer, sizeof(ascii_string), -1, STR_TERMINATE );
+ d_printf("\tStart Name = %s\n", ascii_string);
+ }
+
+ if ( config.displayname ) {
+ rpcstr_pull( ascii_string, config.displayname->buffer, sizeof(ascii_string), -1, STR_TERMINATE );
+ d_printf("\tDisplay Name = %s\n", ascii_string);
+ }
+
+done:
+ rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hService, NULL);
+ rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hSCM, NULL);
+
+ return werror_to_ntstatus(result);
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_service_stop_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv )
+{
+ POLICY_HND hSCM;
+ WERROR result = WERR_GENERAL_FAILURE;
+ NTSTATUS status;
+ fstring servicename;
+
+ if (argc != 1 ) {
+ d_printf("Usage: net rpc service status <service>\n");
+ return NT_STATUS_OK;
+ }
+
+ fstrcpy( servicename, argv[0] );
+
+ /* Open the Service Control Manager */
+ status = rpccli_svcctl_OpenSCManagerW(pipe_hnd, mem_ctx,
+ pipe_hnd->srv_name_slash,
+ NULL,
+ SC_RIGHT_MGR_ENUMERATE_SERVICE,
+ &hSCM,
+ &result);
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ d_fprintf(stderr, "Failed to open Service Control Manager. [%s]\n", dos_errstr(result));
+ return werror_to_ntstatus(result);
+ }
+
+ result = control_service(pipe_hnd, mem_ctx, &hSCM, servicename,
+ SVCCTL_CONTROL_STOP, SVCCTL_STOPPED );
+
+ rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hSCM, NULL);
+
+ return werror_to_ntstatus(result);
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_service_pause_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv )
+{
+ POLICY_HND hSCM;
+ WERROR result = WERR_GENERAL_FAILURE;
+ NTSTATUS status;
+ fstring servicename;
+
+ if (argc != 1 ) {
+ d_printf("Usage: net rpc service status <service>\n");
+ return NT_STATUS_OK;
+ }
+
+ fstrcpy( servicename, argv[0] );
+
+ /* Open the Service Control Manager */
+ status = rpccli_svcctl_OpenSCManagerW(pipe_hnd, mem_ctx,
+ pipe_hnd->srv_name_slash,
+ NULL,
+ SC_RIGHT_MGR_ENUMERATE_SERVICE,
+ &hSCM,
+ &result);
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ d_fprintf(stderr, "Failed to open Service Control Manager. [%s]\n", dos_errstr(result));
+ return werror_to_ntstatus(result);
+ }
+
+ result = control_service(pipe_hnd, mem_ctx, &hSCM, servicename,
+ SVCCTL_CONTROL_PAUSE, SVCCTL_PAUSED );
+
+ rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hSCM, NULL);
+
+ return werror_to_ntstatus(result);
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_service_resume_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv )
+{
+ POLICY_HND hSCM;
+ WERROR result = WERR_GENERAL_FAILURE;
+ NTSTATUS status;
+ fstring servicename;
+
+ if (argc != 1 ) {
+ d_printf("Usage: net rpc service status <service>\n");
+ return NT_STATUS_OK;
+ }
+
+ fstrcpy( servicename, argv[0] );
+
+ /* Open the Service Control Manager */
+ status = rpccli_svcctl_OpenSCManagerW(pipe_hnd, mem_ctx,
+ pipe_hnd->srv_name_slash,
+ NULL,
+ SC_RIGHT_MGR_ENUMERATE_SERVICE,
+ &hSCM,
+ &result);
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ d_fprintf(stderr, "Failed to open Service Control Manager. [%s]\n", dos_errstr(result));
+ return werror_to_ntstatus(result);
+ }
+
+ result = control_service(pipe_hnd, mem_ctx, &hSCM, servicename,
+ SVCCTL_CONTROL_CONTINUE, SVCCTL_RUNNING );
+
+ rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hSCM, NULL);
+
+ return werror_to_ntstatus(result);
+}
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS rpc_service_start_internal(struct net_context *c,
+ const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ struct rpc_pipe_client *pipe_hnd,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv )
+{
+ POLICY_HND hSCM, hService;
+ WERROR result = WERR_GENERAL_FAILURE;
+ NTSTATUS status;
+ uint32 state = 0;
+
+ if (argc != 1 ) {
+ d_printf("Usage: net rpc service status <service>\n");
+ return NT_STATUS_OK;
+ }
+
+ /* Open the Service Control Manager */
+ status = rpccli_svcctl_OpenSCManagerW(pipe_hnd, mem_ctx,
+ pipe_hnd->srv_name_slash,
+ NULL,
+ SC_RIGHT_MGR_ENUMERATE_SERVICE,
+ &hSCM,
+ &result);
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
+ d_fprintf(stderr, "Failed to open Service Control Manager. [%s]\n", dos_errstr(result));
+ return werror_to_ntstatus(result);
+ }
+
+ /* Open the Service */
+
+ status = rpccli_svcctl_OpenServiceW(pipe_hnd, mem_ctx,
+ &hSCM,
+ argv[0],
+ SC_RIGHT_SVC_START,
+ &hService,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
+ d_fprintf(stderr, "Failed to open service. [%s]\n", dos_errstr(result));
+ goto done;
+ }
+
+ /* get the status */
+
+ status = rpccli_svcctl_StartServiceW(pipe_hnd, mem_ctx,
+ &hService,
+ 0,
+ NULL,
+ &result);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
+ d_fprintf(stderr, "Query status request failed. [%s]\n", dos_errstr(result));
+ goto done;
+ }
+
+ result = watch_service_state(pipe_hnd, mem_ctx, &hSCM, argv[0], SVCCTL_RUNNING, &state );
+
+ if ( W_ERROR_IS_OK(result) && (state == SVCCTL_RUNNING) )
+ d_printf("Successfully started service: %s\n", argv[0] );
+ else
+ d_fprintf(stderr, "Failed to start service: %s [%s]\n", argv[0], dos_errstr(result) );
+
+done:
+ rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hService, NULL);
+ rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hSCM, NULL);
+
+ return werror_to_ntstatus(result);
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_service_list(struct net_context *c, int argc, const char **argv )
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc service list\n"
+ " View configured Win32 services\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_svcctl.syntax_id, 0,
+ rpc_service_list_internal, argc, argv );
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_service_start(struct net_context *c, int argc, const char **argv )
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc service start <service>\n"
+ " Start a Win32 service\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_svcctl.syntax_id, 0,
+ rpc_service_start_internal, argc, argv );
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_service_stop(struct net_context *c, int argc, const char **argv )
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc service stop <service>\n"
+ " Stop a Win32 service\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_svcctl.syntax_id, 0,
+ rpc_service_stop_internal, argc, argv );
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_service_resume(struct net_context *c, int argc, const char **argv )
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc service resume <service>\n"
+ " Resume a Win32 service\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_svcctl.syntax_id, 0,
+ rpc_service_resume_internal, argc, argv );
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_service_pause(struct net_context *c, int argc, const char **argv )
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc service pause <service>\n"
+ " Pause a Win32 service\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_svcctl.syntax_id, 0,
+ rpc_service_pause_internal, argc, argv );
+}
+
+/********************************************************************
+********************************************************************/
+
+static int rpc_service_status(struct net_context *c, int argc, const char **argv )
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc service status <service>\n"
+ " Show the current status of a service\n");
+ return 0;
+ }
+
+ return run_rpc_command(c, NULL, &ndr_table_svcctl.syntax_id, 0,
+ rpc_service_status_internal, argc, argv );
+}
+
+/********************************************************************
+********************************************************************/
+
+int net_rpc_service(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "list",
+ rpc_service_list,
+ NET_TRANSPORT_RPC,
+ "View configured Win32 services",
+ "net rpc service list\n"
+ " View configured Win32 services"
+ },
+ {
+ "start",
+ rpc_service_start,
+ NET_TRANSPORT_RPC,
+ "Start a service",
+ "net rpc service start\n"
+ " Start a service"
+ },
+ {
+ "stop",
+ rpc_service_stop,
+ NET_TRANSPORT_RPC,
+ "Stop a service",
+ "net rpc service stop\n"
+ " Stop a service"
+ },
+ {
+ "pause",
+ rpc_service_pause,
+ NET_TRANSPORT_RPC,
+ "Pause a service",
+ "net rpc service pause\n"
+ " Pause a service"
+ },
+ {
+ "resume",
+ rpc_service_resume,
+ NET_TRANSPORT_RPC,
+ "Resume a paused service",
+ "net rpc service resume\n"
+ " Resume a service"
+ },
+ {
+ "status",
+ rpc_service_status,
+ NET_TRANSPORT_RPC,
+ "View current status of a service",
+ "net rpc service status\n"
+ " View current status of a service"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net rpc service",func);
+}
diff --git a/source3/utils/net_rpc_sh_acct.c b/source3/utils/net_rpc_sh_acct.c
new file mode 100644
index 0000000000..977e1e2a0a
--- /dev/null
+++ b/source3/utils/net_rpc_sh_acct.c
@@ -0,0 +1,453 @@
+/*
+ Samba Unix/Linux SMB client library
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) 2006 Volker Lendecke (vl@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "utils/net.h"
+
+/*
+ * Do something with the account policies. Read them all, run a function on
+ * them and possibly write them back. "fn" has to return the container index
+ * it has modified, it can return 0 for no change.
+ */
+
+static NTSTATUS rpc_sh_acct_do(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv,
+ int (*fn)(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct samr_DomInfo1 *i1,
+ struct samr_DomInfo3 *i3,
+ struct samr_DomInfo12 *i12,
+ int argc, const char **argv))
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ union samr_DomainInfo *info1 = NULL;
+ union samr_DomainInfo *info3 = NULL;
+ union samr_DomainInfo *info12 = NULL;
+ int store;
+
+ ZERO_STRUCT(connect_pol);
+ ZERO_STRUCT(domain_pol);
+
+ /* Get sam policy handle */
+
+ result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Get domain policy handle */
+
+ result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
+ &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ ctx->domain_sid,
+ &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_samr_QueryDomainInfo(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 1,
+ &info1);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "query_domain_info level 1 failed: %s\n",
+ nt_errstr(result));
+ goto done;
+ }
+
+ result = rpccli_samr_QueryDomainInfo(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 3,
+ &info3);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "query_domain_info level 3 failed: %s\n",
+ nt_errstr(result));
+ goto done;
+ }
+
+ result = rpccli_samr_QueryDomainInfo(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 12,
+ &info12);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "query_domain_info level 12 failed: %s\n",
+ nt_errstr(result));
+ goto done;
+ }
+
+ store = fn(c, mem_ctx, ctx, &info1->info1, &info3->info3,
+ &info12->info12, argc, argv);
+
+ if (store <= 0) {
+ /* Don't save anything */
+ goto done;
+ }
+
+ switch (store) {
+ case 1:
+ result = rpccli_samr_SetDomainInfo(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 1,
+ info1);
+ break;
+ case 3:
+ result = rpccli_samr_SetDomainInfo(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 3,
+ info3);
+ break;
+ case 12:
+ result = rpccli_samr_SetDomainInfo(pipe_hnd, mem_ctx,
+ &domain_pol,
+ 12,
+ info12);
+ break;
+ default:
+ d_fprintf(stderr, "Got unexpected info level %d\n", store);
+ result = NT_STATUS_INTERNAL_ERROR;
+ goto done;
+ }
+
+ done:
+ if (is_valid_policy_hnd(&domain_pol)) {
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
+ }
+ if (is_valid_policy_hnd(&connect_pol)) {
+ rpccli_samr_Close(pipe_hnd, mem_ctx, &connect_pol);
+ }
+
+ return result;
+}
+
+static int account_show(struct net_context *c,
+ TALLOC_CTX *mem_ctx, struct rpc_sh_ctx *ctx,
+ struct samr_DomInfo1 *i1,
+ struct samr_DomInfo3 *i3,
+ struct samr_DomInfo12 *i12,
+ int argc, const char **argv)
+{
+ if (argc != 0) {
+ d_fprintf(stderr, "usage: %s\n", ctx->whoami);
+ return -1;
+ }
+
+ d_printf("Minimum password length: %d\n", i1->min_password_length);
+ d_printf("Password history length: %d\n", i1->password_history_length);
+
+ d_printf("Minimum password age: ");
+ if (!nt_time_is_zero((NTTIME *)&i1->min_password_age)) {
+ time_t t = nt_time_to_unix_abs((NTTIME *)&i1->min_password_age);
+ d_printf("%d seconds\n", (int)t);
+ } else {
+ d_printf("not set\n");
+ }
+
+ d_printf("Maximum password age: ");
+ if (nt_time_is_set((NTTIME *)&i1->max_password_age)) {
+ time_t t = nt_time_to_unix_abs((NTTIME *)&i1->max_password_age);
+ d_printf("%d seconds\n", (int)t);
+ } else {
+ d_printf("not set\n");
+ }
+
+ d_printf("Bad logon attempts: %d\n", i12->lockout_threshold);
+
+ if (i12->lockout_threshold != 0) {
+
+ d_printf("Account lockout duration: ");
+ if (nt_time_is_set(&i12->lockout_duration)) {
+ time_t t = nt_time_to_unix_abs(&i12->lockout_duration);
+ d_printf("%d seconds\n", (int)t);
+ } else {
+ d_printf("not set\n");
+ }
+
+ d_printf("Bad password count reset after: ");
+ if (nt_time_is_set(&i12->lockout_window)) {
+ time_t t = nt_time_to_unix_abs(&i12->lockout_window);
+ d_printf("%d seconds\n", (int)t);
+ } else {
+ d_printf("not set\n");
+ }
+ }
+
+ d_printf("Disconnect users when logon hours expire: %s\n",
+ nt_time_is_zero(&i3->force_logoff_time) ? "yes" : "no");
+
+ d_printf("User must logon to change password: %s\n",
+ (i1->password_properties & 0x2) ? "yes" : "no");
+
+ return 0; /* Don't save */
+}
+
+static NTSTATUS rpc_sh_acct_pol_show(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv) {
+ return rpc_sh_acct_do(c, mem_ctx, ctx, pipe_hnd, argc, argv,
+ account_show);
+}
+
+static int account_set_badpw(struct net_context *c,
+ TALLOC_CTX *mem_ctx, struct rpc_sh_ctx *ctx,
+ struct samr_DomInfo1 *i1,
+ struct samr_DomInfo3 *i3,
+ struct samr_DomInfo12 *i12,
+ int argc, const char **argv)
+{
+ if (argc != 1) {
+ d_fprintf(stderr, "usage: %s <count>\n", ctx->whoami);
+ return -1;
+ }
+
+ i12->lockout_threshold = atoi(argv[0]);
+ d_printf("Setting bad password count to %d\n",
+ i12->lockout_threshold);
+
+ return 12;
+}
+
+static NTSTATUS rpc_sh_acct_set_badpw(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ return rpc_sh_acct_do(c, mem_ctx, ctx, pipe_hnd, argc, argv,
+ account_set_badpw);
+}
+
+static int account_set_lockduration(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct samr_DomInfo1 *i1,
+ struct samr_DomInfo3 *i3,
+ struct samr_DomInfo12 *i12,
+ int argc, const char **argv)
+{
+ if (argc != 1) {
+ d_fprintf(stderr, "usage: %s <count>\n", ctx->whoami);
+ return -1;
+ }
+
+ unix_to_nt_time_abs(&i12->lockout_duration, atoi(argv[0]));
+ d_printf("Setting lockout duration to %d seconds\n",
+ (int)nt_time_to_unix_abs(&i12->lockout_duration));
+
+ return 12;
+}
+
+static NTSTATUS rpc_sh_acct_set_lockduration(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ return rpc_sh_acct_do(c, mem_ctx, ctx, pipe_hnd, argc, argv,
+ account_set_lockduration);
+}
+
+static int account_set_resetduration(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct samr_DomInfo1 *i1,
+ struct samr_DomInfo3 *i3,
+ struct samr_DomInfo12 *i12,
+ int argc, const char **argv)
+{
+ if (argc != 1) {
+ d_fprintf(stderr, "usage: %s <count>\n", ctx->whoami);
+ return -1;
+ }
+
+ unix_to_nt_time_abs(&i12->lockout_window, atoi(argv[0]));
+ d_printf("Setting bad password reset duration to %d seconds\n",
+ (int)nt_time_to_unix_abs(&i12->lockout_window));
+
+ return 12;
+}
+
+static NTSTATUS rpc_sh_acct_set_resetduration(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ return rpc_sh_acct_do(c, mem_ctx, ctx, pipe_hnd, argc, argv,
+ account_set_resetduration);
+}
+
+static int account_set_minpwage(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct samr_DomInfo1 *i1,
+ struct samr_DomInfo3 *i3,
+ struct samr_DomInfo12 *i12,
+ int argc, const char **argv)
+{
+ if (argc != 1) {
+ d_fprintf(stderr, "usage: %s <count>\n", ctx->whoami);
+ return -1;
+ }
+
+ unix_to_nt_time_abs((NTTIME *)&i1->min_password_age, atoi(argv[0]));
+ d_printf("Setting minimum password age to %d seconds\n",
+ (int)nt_time_to_unix_abs((NTTIME *)&i1->min_password_age));
+
+ return 1;
+}
+
+static NTSTATUS rpc_sh_acct_set_minpwage(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ return rpc_sh_acct_do(c, mem_ctx, ctx, pipe_hnd, argc, argv,
+ account_set_minpwage);
+}
+
+static int account_set_maxpwage(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct samr_DomInfo1 *i1,
+ struct samr_DomInfo3 *i3,
+ struct samr_DomInfo12 *i12,
+ int argc, const char **argv)
+{
+ if (argc != 1) {
+ d_fprintf(stderr, "usage: %s <count>\n", ctx->whoami);
+ return -1;
+ }
+
+ unix_to_nt_time_abs((NTTIME *)&i1->max_password_age, atoi(argv[0]));
+ d_printf("Setting maximum password age to %d seconds\n",
+ (int)nt_time_to_unix_abs((NTTIME *)&i1->max_password_age));
+
+ return 1;
+}
+
+static NTSTATUS rpc_sh_acct_set_maxpwage(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ return rpc_sh_acct_do(c, mem_ctx, ctx, pipe_hnd, argc, argv,
+ account_set_maxpwage);
+}
+
+static int account_set_minpwlen(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct samr_DomInfo1 *i1,
+ struct samr_DomInfo3 *i3,
+ struct samr_DomInfo12 *i12,
+ int argc, const char **argv)
+{
+ if (argc != 1) {
+ d_fprintf(stderr, "usage: %s <count>\n", ctx->whoami);
+ return -1;
+ }
+
+ i1->min_password_length = atoi(argv[0]);
+ d_printf("Setting minimum password length to %d\n",
+ i1->min_password_length);
+
+ return 1;
+}
+
+static NTSTATUS rpc_sh_acct_set_minpwlen(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ return rpc_sh_acct_do(c, mem_ctx, ctx, pipe_hnd, argc, argv,
+ account_set_minpwlen);
+}
+
+static int account_set_pwhistlen(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct samr_DomInfo1 *i1,
+ struct samr_DomInfo3 *i3,
+ struct samr_DomInfo12 *i12,
+ int argc, const char **argv)
+{
+ if (argc != 1) {
+ d_fprintf(stderr, "usage: %s <count>\n", ctx->whoami);
+ return -1;
+ }
+
+ i1->password_history_length = atoi(argv[0]);
+ d_printf("Setting password history length to %d\n",
+ i1->password_history_length);
+
+ return 1;
+}
+
+static NTSTATUS rpc_sh_acct_set_pwhistlen(struct net_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ return rpc_sh_acct_do(c, mem_ctx, ctx, pipe_hnd, argc, argv,
+ account_set_pwhistlen);
+}
+
+struct rpc_sh_cmd *net_rpc_acct_cmds(struct net_context *c, TALLOC_CTX *mem_ctx,
+ struct rpc_sh_ctx *ctx)
+{
+ static struct rpc_sh_cmd cmds[9] = {
+ { "show", NULL, &ndr_table_samr.syntax_id, rpc_sh_acct_pol_show,
+ "Show current account policy settings" },
+ { "badpw", NULL, &ndr_table_samr.syntax_id, rpc_sh_acct_set_badpw,
+ "Set bad password count before lockout" },
+ { "lockduration", NULL, &ndr_table_samr.syntax_id, rpc_sh_acct_set_lockduration,
+ "Set account lockout duration" },
+ { "resetduration", NULL, &ndr_table_samr.syntax_id,
+ rpc_sh_acct_set_resetduration,
+ "Set bad password count reset duration" },
+ { "minpwage", NULL, &ndr_table_samr.syntax_id, rpc_sh_acct_set_minpwage,
+ "Set minimum password age" },
+ { "maxpwage", NULL, &ndr_table_samr.syntax_id, rpc_sh_acct_set_maxpwage,
+ "Set maximum password age" },
+ { "minpwlen", NULL, &ndr_table_samr.syntax_id, rpc_sh_acct_set_minpwlen,
+ "Set minimum password length" },
+ { "pwhistlen", NULL, &ndr_table_samr.syntax_id, rpc_sh_acct_set_pwhistlen,
+ "Set the password history length" },
+ { NULL, NULL, 0, NULL, NULL }
+ };
+
+ return cmds;
+}
diff --git a/source3/utils/net_rpc_shell.c b/source3/utils/net_rpc_shell.c
new file mode 100644
index 0000000000..3aaed1ed18
--- /dev/null
+++ b/source3/utils/net_rpc_shell.c
@@ -0,0 +1,298 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Shell around net rpc subcommands
+ * Copyright (C) Volker Lendecke 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "includes.h"
+#include "utils/net.h"
+
+static NTSTATUS rpc_sh_info(struct net_context *c,
+ TALLOC_CTX *mem_ctx, struct rpc_sh_ctx *ctx,
+ struct rpc_pipe_client *pipe_hnd,
+ int argc, const char **argv)
+{
+ return rpc_info_internals(c, ctx->domain_sid, ctx->domain_name,
+ ctx->cli, pipe_hnd, mem_ctx,
+ argc, argv);
+}
+
+static struct rpc_sh_ctx *this_ctx;
+
+static char **completion_fn(const char *text, int start, int end)
+{
+ char **cmds = NULL;
+ int n_cmds = 0;
+ struct rpc_sh_cmd *c;
+
+ if (start != 0) {
+ return NULL;
+ }
+
+ ADD_TO_ARRAY(NULL, char *, SMB_STRDUP(text), &cmds, &n_cmds);
+
+ for (c = this_ctx->cmds; c->name != NULL; c++) {
+ bool match = (strncmp(text, c->name, strlen(text)) == 0);
+
+ if (match) {
+ ADD_TO_ARRAY(NULL, char *, SMB_STRDUP(c->name),
+ &cmds, &n_cmds);
+ }
+ }
+
+ if (n_cmds == 2) {
+ SAFE_FREE(cmds[0]);
+ cmds[0] = cmds[1];
+ n_cmds -= 1;
+ }
+
+ ADD_TO_ARRAY(NULL, char *, NULL, &cmds, &n_cmds);
+ return cmds;
+}
+
+static NTSTATUS net_sh_run(struct net_context *c,
+ struct rpc_sh_ctx *ctx, struct rpc_sh_cmd *cmd,
+ int argc, const char **argv)
+{
+ TALLOC_CTX *mem_ctx;
+ struct rpc_pipe_client *pipe_hnd;
+ NTSTATUS status;
+
+ mem_ctx = talloc_new(ctx);
+ if (mem_ctx == NULL) {
+ d_fprintf(stderr, "talloc_new failed\n");
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = cli_rpc_pipe_open_noauth(ctx->cli, cmd->interface,
+ &pipe_hnd);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "Could not open pipe: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+
+ status = cmd->fn(c, mem_ctx, ctx, pipe_hnd, argc, argv);
+
+ TALLOC_FREE(pipe_hnd);
+
+ talloc_destroy(mem_ctx);
+
+ return status;
+}
+
+static bool net_sh_process(struct net_context *c,
+ struct rpc_sh_ctx *ctx,
+ int argc, const char **argv)
+{
+ struct rpc_sh_cmd *cmd;
+ struct rpc_sh_ctx *new_ctx;
+ NTSTATUS status;
+
+ if (argc == 0) {
+ return true;
+ }
+
+ if (ctx == this_ctx) {
+
+ /* We've been called from the cmd line */
+ if (strequal(argv[0], "..") &&
+ (this_ctx->parent != NULL)) {
+ new_ctx = this_ctx->parent;
+ TALLOC_FREE(this_ctx);
+ this_ctx = new_ctx;
+ return true;
+ }
+ }
+
+ if (strequal(argv[0], "exit") || strequal(argv[0], "quit")) {
+ return false;
+ }
+
+ if (strequal(argv[0], "help") || strequal(argv[0], "?")) {
+ for (cmd = ctx->cmds; cmd->name != NULL; cmd++) {
+ if (ctx != this_ctx) {
+ d_printf("%s ", ctx->whoami);
+ }
+ d_printf("%-15s %s\n", cmd->name, cmd->help);
+ }
+ return true;
+ }
+
+ for (cmd = ctx->cmds; cmd->name != NULL; cmd++) {
+ if (strequal(cmd->name, argv[0])) {
+ break;
+ }
+ }
+
+ if (cmd->name == NULL) {
+ /* None found */
+ d_fprintf(stderr, "%s: unknown cmd\n", argv[0]);
+ return true;
+ }
+
+ new_ctx = TALLOC_P(ctx, struct rpc_sh_ctx);
+ if (new_ctx == NULL) {
+ d_fprintf(stderr, "talloc failed\n");
+ return false;
+ }
+ new_ctx->cli = ctx->cli;
+ new_ctx->whoami = talloc_asprintf(new_ctx, "%s %s",
+ ctx->whoami, cmd->name);
+ new_ctx->thiscmd = talloc_strdup(new_ctx, cmd->name);
+
+ if (cmd->sub != NULL) {
+ new_ctx->cmds = cmd->sub(c, new_ctx, ctx);
+ } else {
+ new_ctx->cmds = NULL;
+ }
+
+ new_ctx->parent = ctx;
+ new_ctx->domain_name = ctx->domain_name;
+ new_ctx->domain_sid = ctx->domain_sid;
+
+ argc -= 1;
+ argv += 1;
+
+ if (cmd->sub != NULL) {
+ if (argc == 0) {
+ this_ctx = new_ctx;
+ return true;
+ }
+ return net_sh_process(c, new_ctx, argc, argv);
+ }
+
+ status = net_sh_run(c, new_ctx, cmd, argc, argv);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "%s failed: %s\n", new_ctx->whoami,
+ nt_errstr(status));
+ }
+
+ return true;
+}
+
+static struct rpc_sh_cmd sh_cmds[6] = {
+
+ { "info", NULL, &ndr_table_samr.syntax_id, rpc_sh_info,
+ "Print information about the domain connected to" },
+
+ { "rights", net_rpc_rights_cmds, 0, NULL,
+ "List/Grant/Revoke user rights" },
+
+ { "share", net_rpc_share_cmds, 0, NULL,
+ "List/Add/Remove etc shares" },
+
+ { "user", net_rpc_user_cmds, 0, NULL,
+ "List/Add/Remove user info" },
+
+ { "account", net_rpc_acct_cmds, 0, NULL,
+ "Show/Change account policy settings" },
+
+ { NULL, NULL, 0, NULL, NULL }
+};
+
+int net_rpc_shell(struct net_context *c, int argc, const char **argv)
+{
+ NTSTATUS status;
+ struct rpc_sh_ctx *ctx;
+
+ if (argc != 0 || c->display_usage) {
+ d_printf("Usage:\n"
+ "net rpc shell\n");
+ return -1;
+ }
+
+ if (libnetapi_init(&c->netapi_ctx) != 0) {
+ return -1;
+ }
+ libnetapi_set_username(c->netapi_ctx, c->opt_user_name);
+ libnetapi_set_password(c->netapi_ctx, c->opt_password);
+ if (c->opt_kerberos) {
+ libnetapi_set_use_kerberos(c->netapi_ctx);
+ }
+
+ ctx = TALLOC_P(NULL, struct rpc_sh_ctx);
+ if (ctx == NULL) {
+ d_fprintf(stderr, "talloc failed\n");
+ return -1;
+ }
+
+ status = net_make_ipc_connection(c, 0, &(ctx->cli));
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "Could not open connection: %s\n",
+ nt_errstr(status));
+ return -1;
+ }
+
+ ctx->cmds = sh_cmds;
+ ctx->whoami = "net rpc";
+ ctx->parent = NULL;
+
+ status = net_get_remote_domain_sid(ctx->cli, ctx, &ctx->domain_sid,
+ &ctx->domain_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ d_printf("Talking to domain %s (%s)\n", ctx->domain_name,
+ sid_string_tos(ctx->domain_sid));
+
+ this_ctx = ctx;
+
+ while(1) {
+ char *prompt = NULL;
+ char *line = NULL;
+ int ret;
+
+ if (asprintf(&prompt, "%s> ", this_ctx->whoami) < 0) {
+ break;
+ }
+
+ line = smb_readline(prompt, NULL, completion_fn);
+ SAFE_FREE(prompt);
+
+ if (line == NULL) {
+ break;
+ }
+
+ ret = poptParseArgvString(line, &argc, &argv);
+ if (ret == POPT_ERROR_NOARG) {
+ SAFE_FREE(line);
+ continue;
+ }
+ if (ret != 0) {
+ d_fprintf(stderr, "cmdline invalid: %s\n",
+ poptStrerror(ret));
+ SAFE_FREE(line);
+ return false;
+ }
+
+ if ((line[0] != '\n') &&
+ (!net_sh_process(c, this_ctx, argc, argv))) {
+ SAFE_FREE(line);
+ break;
+ }
+ SAFE_FREE(line);
+ }
+
+ cli_shutdown(ctx->cli);
+
+ TALLOC_FREE(ctx);
+
+ return 0;
+}
diff --git a/source3/utils/net_sam.c b/source3/utils/net_sam.c
new file mode 100644
index 0000000000..ce132131f7
--- /dev/null
+++ b/source3/utils/net_sam.c
@@ -0,0 +1,1938 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Local SAM access routines
+ * Copyright (C) Volker Lendecke 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "includes.h"
+#include "utils/net.h"
+
+/*
+ * Set a user's data
+ */
+
+static int net_sam_userset(struct net_context *c, int argc, const char **argv,
+ const char *field,
+ bool (*fn)(struct samu *, const char *,
+ enum pdb_value_state))
+{
+ struct samu *sam_acct = NULL;
+ DOM_SID sid;
+ enum lsa_SidType type;
+ const char *dom, *name;
+ NTSTATUS status;
+
+ if (argc != 2 || c->display_usage) {
+ d_fprintf(stderr, "usage: net sam set %s <user> <value>\n",
+ field);
+ return -1;
+ }
+
+ if (!lookup_name(talloc_tos(), argv[0], LOOKUP_NAME_LOCAL,
+ &dom, &name, &sid, &type)) {
+ d_fprintf(stderr, "Could not find name %s\n", argv[0]);
+ return -1;
+ }
+
+ if (type != SID_NAME_USER) {
+ d_fprintf(stderr, "%s is a %s, not a user\n", argv[0],
+ sid_type_lookup(type));
+ return -1;
+ }
+
+ if ( !(sam_acct = samu_new( NULL )) ) {
+ d_fprintf(stderr, "Internal error\n");
+ return -1;
+ }
+
+ if (!pdb_getsampwsid(sam_acct, &sid)) {
+ d_fprintf(stderr, "Loading user %s failed\n", argv[0]);
+ return -1;
+ }
+
+ if (!fn(sam_acct, argv[1], PDB_CHANGED)) {
+ d_fprintf(stderr, "Internal error\n");
+ return -1;
+ }
+
+ status = pdb_update_sam_account(sam_acct);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "Updating sam account %s failed with %s\n",
+ argv[0], nt_errstr(status));
+ return -1;
+ }
+
+ TALLOC_FREE(sam_acct);
+
+ d_printf("Updated %s for %s\\%s to %s\n", field, dom, name, argv[1]);
+ return 0;
+}
+
+static int net_sam_set_fullname(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_sam_userset(c, argc, argv, "fullname",
+ pdb_set_fullname);
+}
+
+static int net_sam_set_logonscript(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_sam_userset(c, argc, argv, "logonscript",
+ pdb_set_logon_script);
+}
+
+static int net_sam_set_profilepath(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_sam_userset(c, argc, argv, "profilepath",
+ pdb_set_profile_path);
+}
+
+static int net_sam_set_homedrive(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_sam_userset(c, argc, argv, "homedrive",
+ pdb_set_dir_drive);
+}
+
+static int net_sam_set_homedir(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_sam_userset(c, argc, argv, "homedir",
+ pdb_set_homedir);
+}
+
+static int net_sam_set_workstations(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_sam_userset(c, argc, argv, "workstations",
+ pdb_set_workstations);
+}
+
+/*
+ * Set account flags
+ */
+
+static int net_sam_set_userflag(struct net_context *c, int argc,
+ const char **argv, const char *field,
+ uint16 flag)
+{
+ struct samu *sam_acct = NULL;
+ DOM_SID sid;
+ enum lsa_SidType type;
+ const char *dom, *name;
+ NTSTATUS status;
+ uint16 acct_flags;
+
+ if ((argc != 2) || c->display_usage ||
+ (!strequal(argv[1], "yes") &&
+ !strequal(argv[1], "no"))) {
+ d_fprintf(stderr, "usage: net sam set %s <user> [yes|no]\n",
+ field);
+ return -1;
+ }
+
+ if (!lookup_name(talloc_tos(), argv[0], LOOKUP_NAME_LOCAL,
+ &dom, &name, &sid, &type)) {
+ d_fprintf(stderr, "Could not find name %s\n", argv[0]);
+ return -1;
+ }
+
+ if (type != SID_NAME_USER) {
+ d_fprintf(stderr, "%s is a %s, not a user\n", argv[0],
+ sid_type_lookup(type));
+ return -1;
+ }
+
+ if ( !(sam_acct = samu_new( NULL )) ) {
+ d_fprintf(stderr, "Internal error\n");
+ return -1;
+ }
+
+ if (!pdb_getsampwsid(sam_acct, &sid)) {
+ d_fprintf(stderr, "Loading user %s failed\n", argv[0]);
+ return -1;
+ }
+
+ acct_flags = pdb_get_acct_ctrl(sam_acct);
+
+ if (strequal(argv[1], "yes")) {
+ acct_flags |= flag;
+ } else {
+ acct_flags &= ~flag;
+ }
+
+ pdb_set_acct_ctrl(sam_acct, acct_flags, PDB_CHANGED);
+
+ status = pdb_update_sam_account(sam_acct);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "Updating sam account %s failed with %s\n",
+ argv[0], nt_errstr(status));
+ return -1;
+ }
+
+ TALLOC_FREE(sam_acct);
+
+ d_fprintf(stderr, "Updated flag %s for %s\\%s to %s\n", field, dom,
+ name, argv[1]);
+ return 0;
+}
+
+static int net_sam_set_disabled(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_sam_set_userflag(c, argc, argv, "disabled", ACB_DISABLED);
+}
+
+static int net_sam_set_pwnotreq(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_sam_set_userflag(c, argc, argv, "pwnotreq", ACB_PWNOTREQ);
+}
+
+static int net_sam_set_autolock(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_sam_set_userflag(c, argc, argv, "autolock", ACB_AUTOLOCK);
+}
+
+static int net_sam_set_pwnoexp(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_sam_set_userflag(c, argc, argv, "pwnoexp", ACB_PWNOEXP);
+}
+
+/*
+ * Set pass last change time, based on force pass change now
+ */
+
+static int net_sam_set_pwdmustchangenow(struct net_context *c, int argc,
+ const char **argv)
+{
+ struct samu *sam_acct = NULL;
+ DOM_SID sid;
+ enum lsa_SidType type;
+ const char *dom, *name;
+ NTSTATUS status;
+
+ if ((argc != 2) || c->display_usage ||
+ (!strequal(argv[1], "yes") &&
+ !strequal(argv[1], "no"))) {
+ d_fprintf(stderr, "usage: net sam set pwdmustchangenow <user> [yes|no]\n");
+ return -1;
+ }
+
+ if (!lookup_name(talloc_tos(), argv[0], LOOKUP_NAME_LOCAL,
+ &dom, &name, &sid, &type)) {
+ d_fprintf(stderr, "Could not find name %s\n", argv[0]);
+ return -1;
+ }
+
+ if (type != SID_NAME_USER) {
+ d_fprintf(stderr, "%s is a %s, not a user\n", argv[0],
+ sid_type_lookup(type));
+ return -1;
+ }
+
+ if ( !(sam_acct = samu_new( NULL )) ) {
+ d_fprintf(stderr, "Internal error\n");
+ return -1;
+ }
+
+ if (!pdb_getsampwsid(sam_acct, &sid)) {
+ d_fprintf(stderr, "Loading user %s failed\n", argv[0]);
+ return -1;
+ }
+
+ if (strequal(argv[1], "yes")) {
+ pdb_set_pass_last_set_time(sam_acct, 0, PDB_CHANGED);
+ } else {
+ pdb_set_pass_last_set_time(sam_acct, time(NULL), PDB_CHANGED);
+ }
+
+ status = pdb_update_sam_account(sam_acct);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "Updating sam account %s failed with %s\n",
+ argv[0], nt_errstr(status));
+ return -1;
+ }
+
+ TALLOC_FREE(sam_acct);
+
+ d_fprintf(stderr, "Updated 'user must change password at next logon' for %s\\%s to %s\n", dom,
+ name, argv[1]);
+ return 0;
+}
+
+
+/*
+ * Set a user's or a group's comment
+ */
+
+static int net_sam_set_comment(struct net_context *c, int argc,
+ const char **argv)
+{
+ GROUP_MAP map;
+ DOM_SID sid;
+ enum lsa_SidType type;
+ const char *dom, *name;
+ NTSTATUS status;
+
+ if (argc != 2 || c->display_usage) {
+ d_fprintf(stderr, "usage: net sam set comment <name> "
+ "<comment>\n");
+ return -1;
+ }
+
+ if (!lookup_name(talloc_tos(), argv[0], LOOKUP_NAME_LOCAL,
+ &dom, &name, &sid, &type)) {
+ d_fprintf(stderr, "Could not find name %s\n", argv[0]);
+ return -1;
+ }
+
+ if (type == SID_NAME_USER) {
+ return net_sam_userset(c, argc, argv, "comment",
+ pdb_set_acct_desc);
+ }
+
+ if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
+ (type != SID_NAME_WKN_GRP)) {
+ d_fprintf(stderr, "%s is a %s, not a group\n", argv[0],
+ sid_type_lookup(type));
+ return -1;
+ }
+
+ if (!pdb_getgrsid(&map, sid)) {
+ d_fprintf(stderr, "Could not load group %s\n", argv[0]);
+ return -1;
+ }
+
+ fstrcpy(map.comment, argv[1]);
+
+ status = pdb_update_group_mapping_entry(&map);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "Updating group mapping entry failed with "
+ "%s\n", nt_errstr(status));
+ return -1;
+ }
+
+ d_printf("Updated comment of group %s\\%s to %s\n", dom, name,
+ argv[1]);
+
+ return 0;
+}
+
+static int net_sam_set(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "homedir",
+ net_sam_set_homedir,
+ NET_TRANSPORT_LOCAL,
+ "Change a user's home directory",
+ "net sam set homedir\n"
+ " Change a user's home directory"
+ },
+ {
+ "profilepath",
+ net_sam_set_profilepath,
+ NET_TRANSPORT_LOCAL,
+ "Change a user's profile path",
+ "net sam set profilepath\n"
+ " Change a user's profile path"
+ },
+ {
+ "comment",
+ net_sam_set_comment,
+ NET_TRANSPORT_LOCAL,
+ "Change a users or groups description",
+ "net sam set comment\n"
+ " Change a users or groups description"
+ },
+ {
+ "fullname",
+ net_sam_set_fullname,
+ NET_TRANSPORT_LOCAL,
+ "Change a user's full name",
+ "net sam set fullname\n"
+ " Change a user's full name"
+ },
+ {
+ "logonscript",
+ net_sam_set_logonscript,
+ NET_TRANSPORT_LOCAL,
+ "Change a user's logon script",
+ "net sam set logonscript\n"
+ " Change a user's logon script"
+ },
+ {
+ "homedrive",
+ net_sam_set_homedrive,
+ NET_TRANSPORT_LOCAL,
+ "Change a user's home drive",
+ "net sam set homedrive\n"
+ " Change a user's home drive"
+ },
+ {
+ "workstations",
+ net_sam_set_workstations,
+ NET_TRANSPORT_LOCAL,
+ "Change a user's allowed workstations",
+ "net sam set workstations\n"
+ " Change a user's allowed workstations"
+ },
+ {
+ "disabled",
+ net_sam_set_disabled,
+ NET_TRANSPORT_LOCAL,
+ "Disable/Enable a user",
+ "net sam set disable\n"
+ " Disable/Enable a user"
+ },
+ {
+ "pwnotreq",
+ net_sam_set_pwnotreq,
+ NET_TRANSPORT_LOCAL,
+ "Disable/Enable the password not required flag",
+ "net sam set pwnotreq\n"
+ " Disable/Enable the password not required flag"
+ },
+ {
+ "autolock",
+ net_sam_set_autolock,
+ NET_TRANSPORT_LOCAL,
+ "Disable/Enable a user's lockout flag",
+ "net sam set autolock\n"
+ " Disable/Enable a user's lockout flag"
+ },
+ {
+ "pwnoexp",
+ net_sam_set_pwnoexp,
+ NET_TRANSPORT_LOCAL,
+ "Disable/Enable whether a user's pw does not expire",
+ "net sam set pwnoexp\n"
+ " Disable/Enable whether a user's pw does not expire"
+ },
+ {
+ "pwdmustchangenow",
+ net_sam_set_pwdmustchangenow,
+ NET_TRANSPORT_LOCAL,
+ "Force users password must change at next logon",
+ "net sam set pwdmustchangenow\n"
+ " Force users password must change at next logon"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net sam set", func);
+}
+
+/*
+ * Manage account policies
+ */
+
+static int net_sam_policy_set(struct net_context *c, int argc, const char **argv)
+{
+ const char *account_policy = NULL;
+ uint32 value = 0;
+ uint32 old_value = 0;
+ int field;
+ char *endptr;
+
+ if (argc != 2 || c->display_usage) {
+ d_fprintf(stderr, "usage: net sam policy set "
+ "\"<account policy>\" <value> \n");
+ return -1;
+ }
+
+ account_policy = argv[0];
+ field = account_policy_name_to_fieldnum(account_policy);
+
+ if (strequal(argv[1], "forever") || strequal(argv[1], "never")
+ || strequal(argv[1], "off")) {
+ value = -1;
+ }
+ else {
+ value = strtoul(argv[1], &endptr, 10);
+
+ if ((endptr == argv[1]) || (endptr[0] != '\0')) {
+ d_printf("Unable to set policy \"%s\"! Invalid value "
+ "\"%s\".\n",
+ account_policy, argv[1]);
+ return -1;
+ }
+ }
+
+ if (field == 0) {
+ const char **names;
+ int i, count;
+
+ account_policy_names_list(&names, &count);
+ d_fprintf(stderr, "No account policy \"%s\"!\n\n", argv[0]);
+ d_fprintf(stderr, "Valid account policies are:\n");
+
+ for (i=0; i<count; i++) {
+ d_fprintf(stderr, "%s\n", names[i]);
+ }
+
+ SAFE_FREE(names);
+ return -1;
+ }
+
+ if (!pdb_get_account_policy(field, &old_value)) {
+ d_fprintf(stderr, "Valid account policy, but unable to fetch "
+ "value!\n");
+ } else {
+ d_printf("Account policy \"%s\" value was: %d\n", account_policy,
+ old_value);
+ }
+
+ if (!pdb_set_account_policy(field, value)) {
+ d_fprintf(stderr, "Valid account policy, but unable to "
+ "set value!\n");
+ return -1;
+ } else {
+ d_printf("Account policy \"%s\" value is now: %d\n", account_policy,
+ value);
+ }
+
+ return 0;
+}
+
+static int net_sam_policy_show(struct net_context *c, int argc, const char **argv)
+{
+ const char *account_policy = NULL;
+ uint32 old_value;
+ int field;
+
+ if (argc != 1 || c->display_usage) {
+ d_fprintf(stderr, "usage: net sam policy show"
+ " \"<account policy>\" \n");
+ return -1;
+ }
+
+ account_policy = argv[0];
+ field = account_policy_name_to_fieldnum(account_policy);
+
+ if (field == 0) {
+ const char **names;
+ int count;
+ int i;
+ account_policy_names_list(&names, &count);
+ d_fprintf(stderr, "No account policy by that name!\n");
+ if (count != 0) {
+ d_fprintf(stderr, "Valid account policies "
+ "are:\n");
+ for (i=0; i<count; i++) {
+ d_fprintf(stderr, "%s\n", names[i]);
+ }
+ }
+ SAFE_FREE(names);
+ return -1;
+ }
+
+ if (!pdb_get_account_policy(field, &old_value)) {
+ fprintf(stderr, "Valid account policy, but unable to "
+ "fetch value!\n");
+ return -1;
+ }
+
+ printf("Account policy \"%s\" description: %s\n",
+ account_policy, account_policy_get_desc(field));
+ printf("Account policy \"%s\" value is: %d\n", account_policy,
+ old_value);
+ return 0;
+}
+
+static int net_sam_policy_list(struct net_context *c, int argc, const char **argv)
+{
+ const char **names;
+ int count;
+ int i;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net sam policy list\n"
+ " List account policies\n");
+ return 0;
+ }
+
+ account_policy_names_list(&names, &count);
+ if (count != 0) {
+ d_fprintf(stderr, "Valid account policies "
+ "are:\n");
+ for (i = 0; i < count ; i++) {
+ d_fprintf(stderr, "%s\n", names[i]);
+ }
+ }
+ SAFE_FREE(names);
+ return -1;
+}
+
+static int net_sam_policy(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "list",
+ net_sam_policy_list,
+ NET_TRANSPORT_LOCAL,
+ "List account policies",
+ "net sam policy list\n"
+ " List account policies"
+ },
+ {
+ "show",
+ net_sam_policy_show,
+ NET_TRANSPORT_LOCAL,
+ "Show account policies",
+ "net sam policy show\n"
+ " Show account policies"
+ },
+ {
+ "set",
+ net_sam_policy_set,
+ NET_TRANSPORT_LOCAL,
+ "Change account policies",
+ "net sam policy set\n"
+ " Change account policies"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net sam policy", func);
+}
+
+extern PRIVS privs[];
+
+static int net_sam_rights_list(struct net_context *c, int argc,
+ const char **argv)
+{
+ SE_PRIV mask;
+
+ if (argc > 1 || c->display_usage) {
+ d_fprintf(stderr, "usage: net sam rights list [privilege name]\n");
+ return -1;
+ }
+
+ if (argc == 0) {
+ int i;
+ int num = count_all_privileges();
+
+ for (i=0; i<num; i++) {
+ d_printf("%s\n", privs[i].name);
+ }
+ return 0;
+ }
+
+ if (se_priv_from_name(argv[0], &mask)) {
+ DOM_SID *sids;
+ int i, num_sids;
+ NTSTATUS status;
+
+ status = privilege_enum_sids(&mask, talloc_tos(),
+ &sids, &num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "Could not list rights: %s\n",
+ nt_errstr(status));
+ return -1;
+ }
+
+ for (i=0; i<num_sids; i++) {
+ const char *dom, *name;
+ enum lsa_SidType type;
+
+ if (lookup_sid(talloc_tos(), &sids[i], &dom, &name,
+ &type)) {
+ d_printf("%s\\%s\n", dom, name);
+ }
+ else {
+ d_printf("%s\n", sid_string_tos(&sids[i]));
+ }
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
+static int net_sam_rights_grant(struct net_context *c, int argc,
+ const char **argv)
+{
+ DOM_SID sid;
+ enum lsa_SidType type;
+ const char *dom, *name;
+ SE_PRIV mask;
+
+ if (argc != 2 || c->display_usage) {
+ d_fprintf(stderr, "usage: net sam rights grant <name> "
+ "<right>\n");
+ return -1;
+ }
+
+ if (!lookup_name(talloc_tos(), argv[0], LOOKUP_NAME_LOCAL,
+ &dom, &name, &sid, &type)) {
+ d_fprintf(stderr, "Could not find name %s\n", argv[0]);
+ return -1;
+ }
+
+ if (!se_priv_from_name(argv[1], &mask)) {
+ d_fprintf(stderr, "%s unknown\n", argv[1]);
+ return -1;
+ }
+
+ if (!grant_privilege(&sid, &mask)) {
+ d_fprintf(stderr, "Could not grant privilege\n");
+ return -1;
+ }
+
+ d_printf("Granted %s to %s\\%s\n", argv[1], dom, name);
+ return 0;
+}
+
+static int net_sam_rights_revoke(struct net_context *c, int argc, const char **argv)
+{
+ DOM_SID sid;
+ enum lsa_SidType type;
+ const char *dom, *name;
+ SE_PRIV mask;
+
+ if (argc != 2 || c->display_usage) {
+ d_fprintf(stderr, "usage: net sam rights revoke <name> "
+ "<right>\n");
+ return -1;
+ }
+
+ if (!lookup_name(talloc_tos(), argv[0], LOOKUP_NAME_LOCAL,
+ &dom, &name, &sid, &type)) {
+ d_fprintf(stderr, "Could not find name %s\n", argv[0]);
+ return -1;
+ }
+
+ if (!se_priv_from_name(argv[1], &mask)) {
+ d_fprintf(stderr, "%s unknown\n", argv[1]);
+ return -1;
+ }
+
+ if (!revoke_privilege(&sid, &mask)) {
+ d_fprintf(stderr, "Could not revoke privilege\n");
+ return -1;
+ }
+
+ d_printf("Revoked %s from %s\\%s\n", argv[1], dom, name);
+ return 0;
+}
+
+static int net_sam_rights(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "list",
+ net_sam_rights_list,
+ NET_TRANSPORT_LOCAL,
+ "List possible user rights",
+ "net sam rights list\n"
+ " List possible user rights"
+ },
+ {
+ "grant",
+ net_sam_rights_grant,
+ NET_TRANSPORT_LOCAL,
+ "Grant a right",
+ "net sam rights grant\n"
+ " Grant a right"
+ },
+ {
+ "revoke",
+ net_sam_rights_revoke,
+ NET_TRANSPORT_LOCAL,
+ "Revoke a right",
+ "net sam rights revoke\n"
+ " Revoke a right"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+ return net_run_function(c, argc, argv, "net sam rights", func);
+}
+
+/*
+ * Map a unix group to a domain group
+ */
+
+static NTSTATUS map_unix_group(const struct group *grp, GROUP_MAP *pmap)
+{
+ NTSTATUS status;
+ GROUP_MAP map;
+ const char *grpname, *dom, *name;
+ uint32 rid;
+
+ if (pdb_getgrgid(&map, grp->gr_gid)) {
+ return NT_STATUS_GROUP_EXISTS;
+ }
+
+ map.gid = grp->gr_gid;
+ grpname = grp->gr_name;
+
+ if (lookup_name(talloc_tos(), grpname, LOOKUP_NAME_LOCAL,
+ &dom, &name, NULL, NULL)) {
+
+ const char *tmp = talloc_asprintf(
+ talloc_tos(), "Unix Group %s", grp->gr_name);
+
+ DEBUG(5, ("%s exists as %s\\%s, retrying as \"%s\"\n",
+ grpname, dom, name, tmp));
+ grpname = tmp;
+ }
+
+ if (lookup_name(talloc_tos(), grpname, LOOKUP_NAME_LOCAL,
+ NULL, NULL, NULL, NULL)) {
+ DEBUG(3, ("\"%s\" exists, can't map it\n", grp->gr_name));
+ return NT_STATUS_GROUP_EXISTS;
+ }
+
+ fstrcpy(map.nt_name, grpname);
+
+ if (pdb_rid_algorithm()) {
+ rid = algorithmic_pdb_gid_to_group_rid( grp->gr_gid );
+ } else {
+ if (!pdb_new_rid(&rid)) {
+ DEBUG(3, ("Could not get a new RID for %s\n",
+ grp->gr_name));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ sid_compose(&map.sid, get_global_sam_sid(), rid);
+ map.sid_name_use = SID_NAME_DOM_GRP;
+ fstrcpy(map.comment, talloc_asprintf(talloc_tos(), "Unix Group %s",
+ grp->gr_name));
+
+ status = pdb_add_group_mapping_entry(&map);
+ if (NT_STATUS_IS_OK(status)) {
+ *pmap = map;
+ }
+ return status;
+}
+
+static int net_sam_mapunixgroup(struct net_context *c, int argc, const char **argv)
+{
+ NTSTATUS status;
+ GROUP_MAP map;
+ struct group *grp;
+
+ if (argc != 1 || c->display_usage) {
+ d_fprintf(stderr, "usage: net sam mapunixgroup <name>\n");
+ return -1;
+ }
+
+ grp = getgrnam(argv[0]);
+ if (grp == NULL) {
+ d_fprintf(stderr, "Could not find group %s\n", argv[0]);
+ return -1;
+ }
+
+ status = map_unix_group(grp, &map);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "Mapping group %s failed with %s\n",
+ argv[0], nt_errstr(status));
+ return -1;
+ }
+
+ d_printf("Mapped unix group %s to SID %s\n", argv[0],
+ sid_string_tos(&map.sid));
+
+ return 0;
+}
+
+/*
+ * Remove a group mapping
+ */
+
+static NTSTATUS unmap_unix_group(const struct group *grp, GROUP_MAP *pmap)
+{
+ NTSTATUS status;
+ GROUP_MAP map;
+ const char *grpname;
+ DOM_SID dom_sid;
+
+ map.gid = grp->gr_gid;
+ grpname = grp->gr_name;
+
+ if (!lookup_name(talloc_tos(), grpname, LOOKUP_NAME_LOCAL,
+ NULL, NULL, NULL, NULL)) {
+ DEBUG(3, ("\"%s\" does not exist, can't unmap it\n", grp->gr_name));
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ fstrcpy(map.nt_name, grpname);
+
+ if (!pdb_gid_to_sid(map.gid, &dom_sid)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ status = pdb_delete_group_mapping_entry(dom_sid);
+
+ return status;
+}
+
+static int net_sam_unmapunixgroup(struct net_context *c, int argc, const char **argv)
+{
+ NTSTATUS status;
+ GROUP_MAP map;
+ struct group *grp;
+
+ if (argc != 1 || c->display_usage) {
+ d_fprintf(stderr, "usage: net sam unmapunixgroup <name>\n");
+ return -1;
+ }
+
+ grp = getgrnam(argv[0]);
+ if (grp == NULL) {
+ d_fprintf(stderr, "Could not find mapping for group %s.\n", argv[0]);
+ return -1;
+ }
+
+ status = unmap_unix_group(grp, &map);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "Unmapping group %s failed with %s.\n",
+ argv[0], nt_errstr(status));
+ return -1;
+ }
+
+ d_printf("Unmapped unix group %s.\n", argv[0]);
+
+ return 0;
+}
+
+/*
+ * Create a local group
+ */
+
+static int net_sam_createlocalgroup(struct net_context *c, int argc, const char **argv)
+{
+ NTSTATUS status;
+ uint32 rid;
+
+ if (argc != 1 || c->display_usage) {
+ d_fprintf(stderr, "usage: net sam createlocalgroup <name>\n");
+ return -1;
+ }
+
+ if (!winbind_ping()) {
+ d_fprintf(stderr, "winbind seems not to run. createlocalgroup "
+ "only works when winbind runs.\n");
+ return -1;
+ }
+
+ status = pdb_create_alias(argv[0], &rid);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "Creating %s failed with %s\n",
+ argv[0], nt_errstr(status));
+ return -1;
+ }
+
+ d_printf("Created local group %s with RID %d\n", argv[0], rid);
+
+ return 0;
+}
+
+/*
+ * Delete a local group
+ */
+
+static int net_sam_deletelocalgroup(struct net_context *c, int argc, const char **argv)
+{
+ DOM_SID sid;
+ enum lsa_SidType type;
+ const char *dom, *name;
+ NTSTATUS status;
+
+ if (argc != 1 || c->display_usage) {
+ d_fprintf(stderr, "usage: net sam deletelocalgroup <name>\n");
+ return -1;
+ }
+
+ if (!lookup_name(talloc_tos(), argv[0], LOOKUP_NAME_LOCAL,
+ &dom, &name, &sid, &type)) {
+ d_fprintf(stderr, "Could not find %s.\n", argv[0]);
+ return -1;
+ }
+
+ if (type != SID_NAME_ALIAS) {
+ d_fprintf(stderr, "%s is a %s, not a local group.\n", argv[0],
+ sid_type_lookup(type));
+ return -1;
+ }
+
+ status = pdb_delete_alias(&sid);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "Deleting local group %s failed with %s\n",
+ argv[0], nt_errstr(status));
+ return -1;
+ }
+
+ d_printf("Deleted local group %s.\n", argv[0]);
+
+ return 0;
+}
+
+/*
+ * Create a builtin group
+ */
+
+static int net_sam_createbuiltingroup(struct net_context *c, int argc, const char **argv)
+{
+ NTSTATUS status;
+ uint32 rid;
+ enum lsa_SidType type;
+ fstring groupname;
+ DOM_SID sid;
+
+ if (argc != 1 || c->display_usage) {
+ d_fprintf(stderr, "usage: net sam createbuiltingroup <name>\n");
+ return -1;
+ }
+
+ if (!winbind_ping()) {
+ d_fprintf(stderr, "winbind seems not to run. createbuiltingroup "
+ "only works when winbind runs.\n");
+ return -1;
+ }
+
+ /* validate the name and get the group */
+
+ fstrcpy( groupname, "BUILTIN\\" );
+ fstrcat( groupname, argv[0] );
+
+ if ( !lookup_name(talloc_tos(), groupname, LOOKUP_NAME_ALL, NULL,
+ NULL, &sid, &type)) {
+ d_fprintf(stderr, "%s is not a BUILTIN group\n", argv[0]);
+ return -1;
+ }
+
+ if ( !sid_peek_rid( &sid, &rid ) ) {
+ d_fprintf(stderr, "Failed to get RID for %s\n", argv[0]);
+ return -1;
+ }
+
+ status = pdb_create_builtin_alias( rid );
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "Creating %s failed with %s\n",
+ argv[0], nt_errstr(status));
+ return -1;
+ }
+
+ d_printf("Created BUILTIN group %s with RID %d\n", argv[0], rid);
+
+ return 0;
+}
+
+/*
+ * Add a group member
+ */
+
+static int net_sam_addmem(struct net_context *c, int argc, const char **argv)
+{
+ const char *groupdomain, *groupname, *memberdomain, *membername;
+ DOM_SID group, member;
+ enum lsa_SidType grouptype, membertype;
+ NTSTATUS status;
+
+ if (argc != 2 || c->display_usage) {
+ d_fprintf(stderr, "usage: net sam addmem <group> <member>\n");
+ return -1;
+ }
+
+ if (!lookup_name(talloc_tos(), argv[0], LOOKUP_NAME_LOCAL,
+ &groupdomain, &groupname, &group, &grouptype)) {
+ d_fprintf(stderr, "Could not find group %s\n", argv[0]);
+ return -1;
+ }
+
+ /* check to see if the member to be added is a name or a SID */
+
+ if (!lookup_name(talloc_tos(), argv[1], LOOKUP_NAME_LOCAL,
+ &memberdomain, &membername, &member, &membertype))
+ {
+ /* try it as a SID */
+
+ if ( !string_to_sid( &member, argv[1] ) ) {
+ d_fprintf(stderr, "Could not find member %s\n", argv[1]);
+ return -1;
+ }
+
+ if ( !lookup_sid(talloc_tos(), &member, &memberdomain,
+ &membername, &membertype) )
+ {
+ d_fprintf(stderr, "Could not resolve SID %s\n", argv[1]);
+ return -1;
+ }
+ }
+
+ if ((grouptype == SID_NAME_ALIAS) || (grouptype == SID_NAME_WKN_GRP)) {
+ if ((membertype != SID_NAME_USER) &&
+ (membertype != SID_NAME_DOM_GRP)) {
+ d_fprintf(stderr, "%s is a local group, only users "
+ "and domain groups can be added.\n"
+ "%s is a %s\n", argv[0], argv[1],
+ sid_type_lookup(membertype));
+ return -1;
+ }
+ status = pdb_add_aliasmem(&group, &member);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "Adding local group member failed "
+ "with %s\n", nt_errstr(status));
+ return -1;
+ }
+ } else {
+ d_fprintf(stderr, "Can only add members to local groups so "
+ "far, %s is a %s\n", argv[0],
+ sid_type_lookup(grouptype));
+ return -1;
+ }
+
+ d_printf("Added %s\\%s to %s\\%s\n", memberdomain, membername,
+ groupdomain, groupname);
+
+ return 0;
+}
+
+/*
+ * Delete a group member
+ */
+
+static int net_sam_delmem(struct net_context *c, int argc, const char **argv)
+{
+ const char *groupdomain, *groupname;
+ const char *memberdomain = NULL;
+ const char *membername = NULL;
+ DOM_SID group, member;
+ enum lsa_SidType grouptype;
+ NTSTATUS status;
+
+ if (argc != 2 || c->display_usage) {
+ d_fprintf(stderr, "usage: net sam delmem <group> <member>\n");
+ return -1;
+ }
+
+ if (!lookup_name(talloc_tos(), argv[0], LOOKUP_NAME_LOCAL,
+ &groupdomain, &groupname, &group, &grouptype)) {
+ d_fprintf(stderr, "Could not find group %s\n", argv[0]);
+ return -1;
+ }
+
+ if (!lookup_name(talloc_tos(), argv[1], LOOKUP_NAME_LOCAL,
+ &memberdomain, &membername, &member, NULL)) {
+ if (!string_to_sid(&member, argv[1])) {
+ d_fprintf(stderr, "Could not find member %s\n",
+ argv[1]);
+ return -1;
+ }
+ }
+
+ if ((grouptype == SID_NAME_ALIAS) ||
+ (grouptype == SID_NAME_WKN_GRP)) {
+ status = pdb_del_aliasmem(&group, &member);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "Deleting local group member failed "
+ "with %s\n", nt_errstr(status));
+ return -1;
+ }
+ } else {
+ d_fprintf(stderr, "Can only delete members from local groups "
+ "so far, %s is a %s\n", argv[0],
+ sid_type_lookup(grouptype));
+ return -1;
+ }
+
+ if (membername != NULL) {
+ d_printf("Deleted %s\\%s from %s\\%s\n",
+ memberdomain, membername, groupdomain, groupname);
+ } else {
+ d_printf("Deleted %s from %s\\%s\n",
+ sid_string_tos(&member), groupdomain, groupname);
+ }
+
+ return 0;
+}
+
+/*
+ * List group members
+ */
+
+static int net_sam_listmem(struct net_context *c, int argc, const char **argv)
+{
+ const char *groupdomain, *groupname;
+ DOM_SID group;
+ enum lsa_SidType grouptype;
+ NTSTATUS status;
+
+ if (argc != 1 || c->display_usage) {
+ d_fprintf(stderr, "usage: net sam listmem <group>\n");
+ return -1;
+ }
+
+ if (!lookup_name(talloc_tos(), argv[0], LOOKUP_NAME_LOCAL,
+ &groupdomain, &groupname, &group, &grouptype)) {
+ d_fprintf(stderr, "Could not find group %s\n", argv[0]);
+ return -1;
+ }
+
+ if ((grouptype == SID_NAME_ALIAS) ||
+ (grouptype == SID_NAME_WKN_GRP)) {
+ DOM_SID *members = NULL;
+ size_t i, num_members = 0;
+
+ status = pdb_enum_aliasmem(&group, &members, &num_members);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf(stderr, "Listing group members failed with "
+ "%s\n", nt_errstr(status));
+ return -1;
+ }
+
+ d_printf("%s\\%s has %u members\n", groupdomain, groupname,
+ (unsigned int)num_members);
+ for (i=0; i<num_members; i++) {
+ const char *dom, *name;
+ if (lookup_sid(talloc_tos(), &members[i],
+ &dom, &name, NULL)) {
+ d_printf(" %s\\%s\n", dom, name);
+ } else {
+ d_printf(" %s\n", sid_string_tos(&members[i]));
+ }
+ }
+
+ TALLOC_FREE(members);
+ } else {
+ d_fprintf(stderr, "Can only list local group members so far.\n"
+ "%s is a %s\n", argv[0], sid_type_lookup(grouptype));
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Do the listing
+ */
+static int net_sam_do_list(struct net_context *c, int argc, const char **argv,
+ struct pdb_search *search, const char *what)
+{
+ bool verbose = (argc == 1);
+
+ if ((argc > 1) || c->display_usage ||
+ ((argc == 1) && !strequal(argv[0], "verbose"))) {
+ d_fprintf(stderr, "usage: net sam list %s [verbose]\n", what);
+ return -1;
+ }
+
+ if (search == NULL) {
+ d_fprintf(stderr, "Could not start search\n");
+ return -1;
+ }
+
+ while (true) {
+ struct samr_displayentry entry;
+ if (!search->next_entry(search, &entry)) {
+ break;
+ }
+ if (verbose) {
+ d_printf("%s:%d:%s\n",
+ entry.account_name,
+ entry.rid,
+ entry.description);
+ } else {
+ d_printf("%s\n", entry.account_name);
+ }
+ }
+
+ pdb_search_destroy(search);
+ return 0;
+}
+
+static int net_sam_list_users(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_sam_do_list(c, argc, argv, pdb_search_users(ACB_NORMAL),
+ "users");
+}
+
+static int net_sam_list_groups(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_sam_do_list(c, argc, argv, pdb_search_groups(), "groups");
+}
+
+static int net_sam_list_localgroups(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_sam_do_list(c, argc, argv,
+ pdb_search_aliases(get_global_sam_sid()),
+ "localgroups");
+}
+
+static int net_sam_list_builtin(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_sam_do_list(c, argc, argv,
+ pdb_search_aliases(&global_sid_Builtin),
+ "builtin");
+}
+
+static int net_sam_list_workstations(struct net_context *c, int argc,
+ const char **argv)
+{
+ return net_sam_do_list(c, argc, argv,
+ pdb_search_users(ACB_WSTRUST),
+ "workstations");
+}
+
+/*
+ * List stuff
+ */
+
+static int net_sam_list(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "users",
+ net_sam_list_users,
+ NET_TRANSPORT_LOCAL,
+ "List SAM users",
+ "net sam list users\n"
+ " List SAM users"
+ },
+ {
+ "groups",
+ net_sam_list_groups,
+ NET_TRANSPORT_LOCAL,
+ "List SAM groups",
+ "net sam list groups\n"
+ " List SAM groups"
+ },
+ {
+ "localgroups",
+ net_sam_list_localgroups,
+ NET_TRANSPORT_LOCAL,
+ "List SAM local groups",
+ "net sam list localgroups\n"
+ " List SAM local groups"
+ },
+ {
+ "builtin",
+ net_sam_list_builtin,
+ NET_TRANSPORT_LOCAL,
+ "List builtin groups",
+ "net sam list builtin\n"
+ " List builtin groups"
+ },
+ {
+ "workstations",
+ net_sam_list_workstations,
+ NET_TRANSPORT_LOCAL,
+ "List domain member workstations",
+ "net sam list workstations\n"
+ " List domain member workstations"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ return net_run_function(c, argc, argv, "net sam list", func);
+}
+
+/*
+ * Show details of SAM entries
+ */
+
+static int net_sam_show(struct net_context *c, int argc, const char **argv)
+{
+ DOM_SID sid;
+ enum lsa_SidType type;
+ const char *dom, *name;
+
+ if (argc != 1 || c->display_usage) {
+ d_fprintf(stderr, "usage: net sam show <name>\n");
+ return -1;
+ }
+
+ if (!lookup_name(talloc_tos(), argv[0], LOOKUP_NAME_LOCAL,
+ &dom, &name, &sid, &type)) {
+ d_fprintf(stderr, "Could not find name %s\n", argv[0]);
+ return -1;
+ }
+
+ d_printf("%s\\%s is a %s with SID %s\n", dom, name,
+ sid_type_lookup(type), sid_string_tos(&sid));
+
+ return 0;
+}
+
+#ifdef HAVE_LDAP
+
+/*
+ * Init an LDAP tree with default users and Groups
+ * if ldapsam:editposix is enabled
+ */
+
+static int net_sam_provision(struct net_context *c, int argc, const char **argv)
+{
+ TALLOC_CTX *tc;
+ char *ldap_bk;
+ char *ldap_uri = NULL;
+ char *p;
+ struct smbldap_state *ls;
+ GROUP_MAP gmap;
+ DOM_SID gsid;
+ gid_t domusers_gid = -1;
+ gid_t domadmins_gid = -1;
+ struct samu *samuser;
+ struct passwd *pwd;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net sam provision\n"
+ " Init an LDAP tree with default users/groups\n");
+ return 0;
+ }
+
+ tc = talloc_new(NULL);
+ if (!tc) {
+ d_fprintf(stderr, "Out of Memory!\n");
+ return -1;
+ }
+
+ if ((ldap_bk = talloc_strdup(tc, lp_passdb_backend())) == NULL) {
+ d_fprintf(stderr, "talloc failed\n");
+ talloc_free(tc);
+ return -1;
+ }
+ p = strchr(ldap_bk, ':');
+ if (p) {
+ *p = 0;
+ ldap_uri = talloc_strdup(tc, p+1);
+ trim_char(ldap_uri, ' ', ' ');
+ }
+
+ trim_char(ldap_bk, ' ', ' ');
+
+ if (strcmp(ldap_bk, "ldapsam") != 0) {
+ d_fprintf(stderr, "Provisioning works only with ldapsam backend\n");
+ goto failed;
+ }
+
+ if (!lp_parm_bool(-1, "ldapsam", "trusted", false) ||
+ !lp_parm_bool(-1, "ldapsam", "editposix", false)) {
+
+ d_fprintf(stderr, "Provisioning works only if ldapsam:trusted"
+ " and ldapsam:editposix are enabled.\n");
+ goto failed;
+ }
+
+ if (!winbind_ping()) {
+ d_fprintf(stderr, "winbind seems not to run. Provisioning "
+ "LDAP only works when winbind runs.\n");
+ goto failed;
+ }
+
+ if (!NT_STATUS_IS_OK(smbldap_init(tc, NULL, ldap_uri, &ls))) {
+ d_fprintf(stderr, "Unable to connect to the LDAP server.\n");
+ goto failed;
+ }
+
+ d_printf("Checking for Domain Users group.\n");
+
+ sid_compose(&gsid, get_global_sam_sid(), DOMAIN_GROUP_RID_USERS);
+
+ if (!pdb_getgrsid(&gmap, gsid)) {
+ LDAPMod **mods = NULL;
+ char *dn;
+ char *uname;
+ char *wname;
+ char *gidstr;
+ char *gtype;
+ int rc;
+
+ d_printf("Adding the Domain Users group.\n");
+
+ /* lets allocate a new groupid for this group */
+ if (!winbind_allocate_gid(&domusers_gid)) {
+ d_fprintf(stderr, "Unable to allocate a new gid to create Domain Users group!\n");
+ goto domu_done;
+ }
+
+ uname = talloc_strdup(tc, "domusers");
+ wname = talloc_strdup(tc, "Domain Users");
+ dn = talloc_asprintf(tc, "cn=%s,%s", "domusers", lp_ldap_group_suffix());
+ gidstr = talloc_asprintf(tc, "%d", domusers_gid);
+ gtype = talloc_asprintf(tc, "%d", SID_NAME_DOM_GRP);
+
+ if (!uname || !wname || !dn || !gidstr || !gtype) {
+ d_fprintf(stderr, "Out of Memory!\n");
+ goto failed;
+ }
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_POSIXGROUP);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_GROUPMAP);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "cn", uname);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "displayName", wname);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "gidNumber", gidstr);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaSid",
+ sid_string_talloc(tc, &gsid));
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaGroupType", gtype);
+
+ talloc_autofree_ldapmod(tc, mods);
+
+ rc = smbldap_add(ls, dn, mods);
+
+ if (rc != LDAP_SUCCESS) {
+ d_fprintf(stderr, "Failed to add Domain Users group to ldap directory\n");
+ }
+ } else {
+ domusers_gid = gmap.gid;
+ d_printf("found!\n");
+ }
+
+domu_done:
+
+ d_printf("Checking for Domain Admins group.\n");
+
+ sid_compose(&gsid, get_global_sam_sid(), DOMAIN_GROUP_RID_ADMINS);
+
+ if (!pdb_getgrsid(&gmap, gsid)) {
+ LDAPMod **mods = NULL;
+ char *dn;
+ char *uname;
+ char *wname;
+ char *gidstr;
+ char *gtype;
+ int rc;
+
+ d_printf("Adding the Domain Admins group.\n");
+
+ /* lets allocate a new groupid for this group */
+ if (!winbind_allocate_gid(&domadmins_gid)) {
+ d_fprintf(stderr, "Unable to allocate a new gid to create Domain Admins group!\n");
+ goto doma_done;
+ }
+
+ uname = talloc_strdup(tc, "domadmins");
+ wname = talloc_strdup(tc, "Domain Admins");
+ dn = talloc_asprintf(tc, "cn=%s,%s", "domadmins", lp_ldap_group_suffix());
+ gidstr = talloc_asprintf(tc, "%d", domadmins_gid);
+ gtype = talloc_asprintf(tc, "%d", SID_NAME_DOM_GRP);
+
+ if (!uname || !wname || !dn || !gidstr || !gtype) {
+ d_fprintf(stderr, "Out of Memory!\n");
+ goto failed;
+ }
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_POSIXGROUP);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_GROUPMAP);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "cn", uname);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "displayName", wname);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "gidNumber", gidstr);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaSid",
+ sid_string_talloc(tc, &gsid));
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaGroupType", gtype);
+
+ talloc_autofree_ldapmod(tc, mods);
+
+ rc = smbldap_add(ls, dn, mods);
+
+ if (rc != LDAP_SUCCESS) {
+ d_fprintf(stderr, "Failed to add Domain Admins group to ldap directory\n");
+ }
+ } else {
+ domadmins_gid = gmap.gid;
+ d_printf("found!\n");
+ }
+
+doma_done:
+
+ d_printf("Check for Administrator account.\n");
+
+ samuser = samu_new(tc);
+ if (!samuser) {
+ d_fprintf(stderr, "Out of Memory!\n");
+ goto failed;
+ }
+
+ if (!pdb_getsampwnam(samuser, "Administrator")) {
+ LDAPMod **mods = NULL;
+ DOM_SID sid;
+ char *dn;
+ char *name;
+ char *uidstr;
+ char *gidstr;
+ char *shell;
+ char *dir;
+ uid_t uid;
+ int rc;
+
+ d_printf("Adding the Administrator user.\n");
+
+ if (domadmins_gid == -1) {
+ d_fprintf(stderr, "Can't create Administrator user, Domain Admins group not available!\n");
+ goto done;
+ }
+ if (!winbind_allocate_uid(&uid)) {
+ d_fprintf(stderr, "Unable to allocate a new uid to create the Administrator user!\n");
+ goto done;
+ }
+ name = talloc_strdup(tc, "Administrator");
+ dn = talloc_asprintf(tc, "uid=Administrator,%s", lp_ldap_user_suffix());
+ uidstr = talloc_asprintf(tc, "%d", uid);
+ gidstr = talloc_asprintf(tc, "%d", domadmins_gid);
+ dir = talloc_sub_specified(tc, lp_template_homedir(),
+ "Administrator",
+ get_global_sam_name(),
+ uid, domadmins_gid);
+ shell = talloc_sub_specified(tc, lp_template_shell(),
+ "Administrator",
+ get_global_sam_name(),
+ uid, domadmins_gid);
+
+ if (!name || !dn || !uidstr || !gidstr || !dir || !shell) {
+ d_fprintf(stderr, "Out of Memory!\n");
+ goto failed;
+ }
+
+ sid_compose(&sid, get_global_sam_sid(), DOMAIN_USER_RID_ADMIN);
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_ACCOUNT);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_POSIXACCOUNT);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SAMBASAMACCOUNT);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "uid", name);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "cn", name);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "displayName", name);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "uidNumber", uidstr);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "gidNumber", gidstr);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "homeDirectory", dir);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "loginShell", shell);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaSID",
+ sid_string_talloc(tc, &sid));
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaAcctFlags",
+ pdb_encode_acct_ctrl(ACB_NORMAL|ACB_DISABLED,
+ NEW_PW_FORMAT_SPACE_PADDED_LEN));
+
+ talloc_autofree_ldapmod(tc, mods);
+
+ rc = smbldap_add(ls, dn, mods);
+
+ if (rc != LDAP_SUCCESS) {
+ d_fprintf(stderr, "Failed to add Administrator user to ldap directory\n");
+ }
+ } else {
+ d_printf("found!\n");
+ }
+
+ d_printf("Checking for Guest user.\n");
+
+ samuser = samu_new(tc);
+ if (!samuser) {
+ d_fprintf(stderr, "Out of Memory!\n");
+ goto failed;
+ }
+
+ if (!pdb_getsampwnam(samuser, lp_guestaccount())) {
+ LDAPMod **mods = NULL;
+ DOM_SID sid;
+ char *dn;
+ char *uidstr;
+ char *gidstr;
+ int rc;
+
+ d_printf("Adding the Guest user.\n");
+
+ pwd = getpwnam_alloc(tc, lp_guestaccount());
+
+ if (!pwd) {
+ if (domusers_gid == -1) {
+ d_fprintf(stderr, "Can't create Guest user, Domain Users group not available!\n");
+ goto done;
+ }
+ if ((pwd = talloc(tc, struct passwd)) == NULL) {
+ d_fprintf(stderr, "talloc failed\n");
+ goto done;
+ }
+ pwd->pw_name = talloc_strdup(pwd, lp_guestaccount());
+ if (!winbind_allocate_uid(&(pwd->pw_uid))) {
+ d_fprintf(stderr, "Unable to allocate a new uid to create the Guest user!\n");
+ goto done;
+ }
+ pwd->pw_gid = domusers_gid;
+ pwd->pw_dir = talloc_strdup(tc, "/");
+ pwd->pw_shell = talloc_strdup(tc, "/bin/false");
+ if (!pwd->pw_dir || !pwd->pw_shell) {
+ d_fprintf(stderr, "Out of Memory!\n");
+ goto failed;
+ }
+ }
+
+ sid_compose(&sid, get_global_sam_sid(), DOMAIN_USER_RID_GUEST);
+
+ dn = talloc_asprintf(tc, "uid=%s,%s", pwd->pw_name, lp_ldap_user_suffix ());
+ uidstr = talloc_asprintf(tc, "%d", pwd->pw_uid);
+ gidstr = talloc_asprintf(tc, "%d", pwd->pw_gid);
+ if (!dn || !uidstr || !gidstr) {
+ d_fprintf(stderr, "Out of Memory!\n");
+ goto failed;
+ }
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_ACCOUNT);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_POSIXACCOUNT);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SAMBASAMACCOUNT);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "uid", pwd->pw_name);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "cn", pwd->pw_name);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "displayName", pwd->pw_name);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "uidNumber", uidstr);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "gidNumber", gidstr);
+ if ((pwd->pw_dir != NULL) && (pwd->pw_dir[0] != '\0')) {
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "homeDirectory", pwd->pw_dir);
+ }
+ if ((pwd->pw_shell != NULL) && (pwd->pw_shell[0] != '\0')) {
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "loginShell", pwd->pw_shell);
+ }
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaSID",
+ sid_string_talloc(tc, &sid));
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaAcctFlags",
+ pdb_encode_acct_ctrl(ACB_NORMAL|ACB_DISABLED,
+ NEW_PW_FORMAT_SPACE_PADDED_LEN));
+
+ talloc_autofree_ldapmod(tc, mods);
+
+ rc = smbldap_add(ls, dn, mods);
+
+ if (rc != LDAP_SUCCESS) {
+ d_fprintf(stderr, "Failed to add Guest user to ldap directory\n");
+ }
+ } else {
+ d_printf("found!\n");
+ }
+
+ d_printf("Checking Guest's group.\n");
+
+ pwd = getpwnam_alloc(NULL, lp_guestaccount());
+ if (!pwd) {
+ d_fprintf(stderr, "Failed to find just created Guest account!\n"
+ " Is nss properly configured?!\n");
+ goto failed;
+ }
+
+ if (pwd->pw_gid == domusers_gid) {
+ d_printf("found!\n");
+ goto done;
+ }
+
+ if (!pdb_getgrgid(&gmap, pwd->pw_gid)) {
+ LDAPMod **mods = NULL;
+ char *dn;
+ char *uname;
+ char *wname;
+ char *gidstr;
+ char *gtype;
+ int rc;
+
+ d_printf("Adding the Domain Guests group.\n");
+
+ uname = talloc_strdup(tc, "domguests");
+ wname = talloc_strdup(tc, "Domain Guests");
+ dn = talloc_asprintf(tc, "cn=%s,%s", "domguests", lp_ldap_group_suffix());
+ gidstr = talloc_asprintf(tc, "%d", pwd->pw_gid);
+ gtype = talloc_asprintf(tc, "%d", SID_NAME_DOM_GRP);
+
+ if (!uname || !wname || !dn || !gidstr || !gtype) {
+ d_fprintf(stderr, "Out of Memory!\n");
+ goto failed;
+ }
+
+ sid_compose(&gsid, get_global_sam_sid(), DOMAIN_GROUP_RID_GUESTS);
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_POSIXGROUP);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_GROUPMAP);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "cn", uname);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "displayName", wname);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "gidNumber", gidstr);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaSid",
+ sid_string_talloc(tc, &gsid));
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaGroupType", gtype);
+
+ talloc_autofree_ldapmod(tc, mods);
+
+ rc = smbldap_add(ls, dn, mods);
+
+ if (rc != LDAP_SUCCESS) {
+ d_fprintf(stderr, "Failed to add Domain Guests group to ldap directory\n");
+ }
+ } else {
+ d_printf("found!\n");
+ }
+
+
+done:
+ talloc_free(tc);
+ return 0;
+
+failed:
+ talloc_free(tc);
+ return -1;
+}
+
+#endif
+
+/***********************************************************
+ migrated functionality from smbgroupedit
+ **********************************************************/
+int net_sam(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "createbuiltingroup",
+ net_sam_createbuiltingroup,
+ NET_TRANSPORT_LOCAL,
+ "Create a new BUILTIN group",
+ "net sam createbuiltingroup\n"
+ " Create a new BUILTIN group"
+ },
+ {
+ "createlocalgroup",
+ net_sam_createlocalgroup,
+ NET_TRANSPORT_LOCAL,
+ "Create a new local group",
+ "net sam createlocalgroup\n"
+ " Create a new local group"
+ },
+ {
+ "deletelocalgroup",
+ net_sam_deletelocalgroup,
+ NET_TRANSPORT_LOCAL,
+ "Delete an existing local group",
+ "net sam deletelocalgroup\n"
+ " Delete an existing local group"
+ },
+ {
+ "mapunixgroup",
+ net_sam_mapunixgroup,
+ NET_TRANSPORT_LOCAL,
+ "Map a unix group to a domain group",
+ "net sam mapunixgroup\n"
+ " Map a unix group to a domain group"
+ },
+ {
+ "unmapunixgroup",
+ net_sam_unmapunixgroup,
+ NET_TRANSPORT_LOCAL,
+ "Remove a group mapping of an unix group to a domain "
+ "group",
+ "net sam unmapunixgroup\n"
+ " Remove a group mapping of an unix group to a "
+ "domain group"
+ },
+ {
+ "addmem",
+ net_sam_addmem,
+ NET_TRANSPORT_LOCAL,
+ "Add a member to a group",
+ "net sam addmem\n"
+ " Add a member to a group"
+ },
+ {
+ "delmem",
+ net_sam_delmem,
+ NET_TRANSPORT_LOCAL,
+ "Delete a member from a group",
+ "net sam delmem\n"
+ " Delete a member from a group"
+ },
+ {
+ "listmem",
+ net_sam_listmem,
+ NET_TRANSPORT_LOCAL,
+ "List group members",
+ "net sam listmem\n"
+ " List group members"
+ },
+ {
+ "list",
+ net_sam_list,
+ NET_TRANSPORT_LOCAL,
+ "List users, groups and local groups",
+ "net sam list\n"
+ " List users, groups and local groups"
+ },
+ {
+ "show",
+ net_sam_show,
+ NET_TRANSPORT_LOCAL,
+ "Show details of a SAM entry",
+ "net sam show\n"
+ " Show details of a SAM entry"
+ },
+ {
+ "set",
+ net_sam_set,
+ NET_TRANSPORT_LOCAL,
+ "Set details of a SAM account",
+ "net sam set\n"
+ " Set details of a SAM account"
+ },
+ {
+ "policy",
+ net_sam_policy,
+ NET_TRANSPORT_LOCAL,
+ "Set account policies",
+ "net sam policy\n"
+ " Set account policies"
+ },
+ {
+ "rights",
+ net_sam_rights,
+ NET_TRANSPORT_LOCAL,
+ "Manipulate user privileges",
+ "net sam rights\n"
+ " Manipulate user privileges"
+ },
+#ifdef HAVE_LDAP
+ {
+ "provision",
+ net_sam_provision,
+ NET_TRANSPORT_LOCAL,
+ "Provision a clean user database",
+ "net sam privison\n"
+ " Provision a clear user database"
+ },
+#endif
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ if (getuid() != 0) {
+ d_fprintf(stderr, "You are not root, most things won't "
+ "work\n");
+ }
+
+ return net_run_function(c, argc, argv, "net sam", func);
+}
+
diff --git a/source3/utils/net_share.c b/source3/utils/net_share.c
new file mode 100644
index 0000000000..68fcd3b3bd
--- /dev/null
+++ b/source3/utils/net_share.c
@@ -0,0 +1,77 @@
+/*
+ Samba Unix/Linux SMB client library
+ net share commands
+ Copyright (C) 2002 Andrew Tridgell (tridge@samba.org)
+ Copyright (C) 2008 Kai Blin (kai@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+int net_share_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(
+ "\nnet [<method>] share [misc. options] [targets] \n"
+ "\tenumerates all exported resources (network shares) "
+ "on target server\n\n"
+ "net [<method>] share ADD <name=serverpath> [misc. options] [targets]"
+ "\n\tadds a share from a server (makes the export active)\n\n"
+ "net [<method>] share DELETE <sharename> [misc. options] [targets]"
+ "\n\tdeletes a share from a server (makes the export inactive)\n\n"
+ "net [<method>] share ALLOWEDUSERS [<filename>] "
+ "[misc. options] [targets]"
+ "\n\tshows a list of all shares together with all users allowed to"
+ "\n\taccess them. This needs the output of 'net usersidlist' on"
+ "\n\tstdin or in <filename>.\n\n"
+ "net [<method>] share MIGRATE FILES <sharename> [misc. options] [targets]"
+ "\n\tMigrates files from remote to local server\n\n"
+ "net [<method>] share MIGRATE SHARES <sharename> [misc. options] [targets]"
+ "\n\tMigrates shares from remote to local server\n\n"
+ "net [<method>] share MIGRATE SECURITY <sharename> [misc. options] [targets]"
+ "\n\tMigrates share-ACLs from remote to local server\n\n"
+ "net [<method>] share MIGRATE ALL <sharename> [misc. options] [targets]"
+ "\n\tMigrates shares (including directories, files) from remote\n"
+ "\tto local server\n\n"
+ );
+ net_common_methods_usage(c, argc, argv);
+ net_common_flags_usage(c, argc, argv);
+ d_printf(
+ "\t-C or --comment=<comment>\tdescriptive comment (for add only)\n"
+ "\t-M or --maxusers=<num>\t\tmax users allowed for share\n"
+ "\t --acls\t\t\tcopies ACLs as well\n"
+ "\t --attrs\t\t\tcopies DOS Attributes as well\n"
+ "\t --timestamps\t\tpreserve timestamps while copying files\n"
+ "\t --destination\t\tmigration target server (default: localhost)\n"
+ "\t-e or --exclude\t\t\tlist of shares to be excluded from mirroring\n"
+ "\t-v or --verbose\t\t\tgive verbose output\n");
+ return -1;
+}
+
+int net_share(struct net_context *c, int argc, const char **argv)
+{
+ if (argc < 1)
+ return net_share_usage(c, argc, argv);
+
+ if (StrCaseCmp(argv[0], "HELP") == 0) {
+ net_share_usage(c, argc, argv);
+ return 0;
+ }
+
+ if (net_rpc_check(c, 0))
+ return net_rpc_share(c, argc, argv);
+ return net_rap_share(c, argc, argv);
+}
+
diff --git a/source3/utils/net_status.c b/source3/utils/net_status.c
new file mode 100644
index 0000000000..4e355e48b3
--- /dev/null
+++ b/source3/utils/net_status.c
@@ -0,0 +1,269 @@
+/*
+ Samba Unix/Linux SMB client library
+ net status command -- possible replacement for smbstatus
+ Copyright (C) 2003 Volker Lendecke (vl@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "includes.h"
+#include "utils/net.h"
+
+int net_status_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(" net status sessions [parseable] "
+ "Show list of open sessions\n");
+ d_printf(" net status shares [parseable] "
+ "Show list of open shares\n");
+ return -1;
+}
+
+static int show_session(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
+ void *state)
+{
+ bool *parseable = (bool *)state;
+ struct sessionid sessionid;
+
+ if (dbuf.dsize != sizeof(sessionid))
+ return 0;
+
+ memcpy(&sessionid, dbuf.dptr, sizeof(sessionid));
+
+ if (!process_exists(sessionid.pid)) {
+ return 0;
+ }
+
+ if (*parseable) {
+ d_printf("%s\\%s\\%s\\%s\\%s\n",
+ procid_str_static(&sessionid.pid), uidtoname(sessionid.uid),
+ gidtoname(sessionid.gid),
+ sessionid.remote_machine, sessionid.hostname);
+ } else {
+ d_printf("%7s %-12s %-12s %-12s (%s)\n",
+ procid_str_static(&sessionid.pid), uidtoname(sessionid.uid),
+ gidtoname(sessionid.gid),
+ sessionid.remote_machine, sessionid.hostname);
+ }
+
+ return 0;
+}
+
+static int net_status_sessions(struct net_context *c, int argc, const char **argv)
+{
+ TDB_CONTEXT *tdb;
+ bool parseable;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net status sessions [parseable]\n"
+ " Display open user sessions.\n"
+ " If parseable is specified, output is machine-"
+ "readable.\n");
+ return 0;
+ }
+
+ if (argc == 0) {
+ parseable = false;
+ } else if ((argc == 1) && strequal(argv[0], "parseable")) {
+ parseable = true;
+ } else {
+ return net_status_usage(c, argc, argv);
+ }
+
+ if (!parseable) {
+ d_printf("PID Username Group Machine"
+ " \n");
+ d_printf("-------------------------------------------"
+ "------------------------\n");
+ }
+
+ tdb = tdb_open_log(lock_path("sessionid.tdb"), 0,
+ TDB_DEFAULT, O_RDONLY, 0);
+
+ if (tdb == NULL) {
+ d_fprintf(stderr, "%s not initialised\n", lock_path("sessionid.tdb"));
+ return -1;
+ }
+
+ tdb_traverse(tdb, show_session, &parseable);
+ tdb_close(tdb);
+
+ return 0;
+}
+
+static int show_share(struct db_record *rec,
+ const struct connections_key *key,
+ const struct connections_data *crec,
+ void *state)
+{
+ if (crec->cnum == -1)
+ return 0;
+
+ if (!process_exists(crec->pid)) {
+ return 0;
+ }
+
+ d_printf("%-10.10s %s %-12s %s",
+ crec->servicename, procid_str_static(&crec->pid),
+ crec->machine,
+ time_to_asc(crec->start));
+
+ return 0;
+}
+
+struct sessionids {
+ int num_entries;
+ struct sessionid *entries;
+};
+
+static int collect_pid(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
+ void *state)
+{
+ struct sessionids *ids = (struct sessionids *)state;
+ struct sessionid sessionid;
+
+ if (dbuf.dsize != sizeof(sessionid))
+ return 0;
+
+ memcpy(&sessionid, dbuf.dptr, sizeof(sessionid));
+
+ if (!process_exists(sessionid.pid))
+ return 0;
+
+ ids->num_entries += 1;
+ ids->entries = SMB_REALLOC_ARRAY(ids->entries, struct sessionid, ids->num_entries);
+ if (!ids->entries) {
+ ids->num_entries = 0;
+ return 0;
+ }
+ ids->entries[ids->num_entries-1] = sessionid;
+
+ return 0;
+}
+
+static int show_share_parseable(struct db_record *rec,
+ const struct connections_key *key,
+ const struct connections_data *crec,
+ void *state)
+{
+ struct sessionids *ids = (struct sessionids *)state;
+ int i;
+ bool guest = true;
+
+ if (crec->cnum == -1)
+ return 0;
+
+ if (!process_exists(crec->pid)) {
+ return 0;
+ }
+
+ for (i=0; i<ids->num_entries; i++) {
+ struct server_id id = ids->entries[i].pid;
+ if (procid_equal(&id, &crec->pid)) {
+ guest = false;
+ break;
+ }
+ }
+
+ d_printf("%s\\%s\\%s\\%s\\%s\\%s\\%s",
+ crec->servicename,procid_str_static(&crec->pid),
+ guest ? "" : uidtoname(ids->entries[i].uid),
+ guest ? "" : gidtoname(ids->entries[i].gid),
+ crec->machine,
+ guest ? "" : ids->entries[i].hostname,
+ time_to_asc(crec->start));
+
+ return 0;
+}
+
+static int net_status_shares_parseable(struct net_context *c, int argc, const char **argv)
+{
+ struct sessionids ids;
+ TDB_CONTEXT *tdb;
+
+ ids.num_entries = 0;
+ ids.entries = NULL;
+
+ tdb = tdb_open_log(lock_path("sessionid.tdb"), 0,
+ TDB_DEFAULT, O_RDONLY, 0);
+
+ if (tdb == NULL) {
+ d_fprintf(stderr, "%s not initialised\n", lock_path("sessionid.tdb"));
+ return -1;
+ }
+
+ tdb_traverse(tdb, collect_pid, &ids);
+ tdb_close(tdb);
+
+ connections_forall(show_share_parseable, &ids);
+
+ SAFE_FREE(ids.entries);
+
+ return 0;
+}
+
+static int net_status_shares(struct net_context *c, int argc, const char **argv)
+{
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net status shares [parseable]\n"
+ " Display open user shares.\n"
+ " If parseable is specified, output is machine-"
+ "readable.\n");
+ return 0;
+ }
+
+ if (argc == 0) {
+
+ d_printf("\nService pid machine "
+ "Connected at\n");
+ d_printf("-------------------------------------"
+ "------------------\n");
+
+ connections_forall(show_share, NULL);
+
+ return 0;
+ }
+
+ if ((argc != 1) || !strequal(argv[0], "parseable")) {
+ return net_status_usage(c, argc, argv);
+ }
+
+ return net_status_shares_parseable(c, argc, argv);
+}
+
+int net_status(struct net_context *c, int argc, const char **argv)
+{
+ struct functable func[] = {
+ {
+ "sessions",
+ net_status_sessions,
+ NET_TRANSPORT_LOCAL,
+ "Show list of open sessions",
+ "net status sessions [parseable]\n"
+ " If parseable is specified, output is presented "
+ "in a machine-parseable fashion."
+ },
+ {
+ "shares",
+ net_status_shares,
+ NET_TRANSPORT_LOCAL,
+ "Show list of open shares",
+ "net status shares [parseable]\n"
+ " If parseable is specified, output is presented "
+ "in a machine-parseable fashion."
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+ return net_run_function(c, argc, argv, "net status", func);
+}
diff --git a/source3/utils/net_time.c b/source3/utils/net_time.c
new file mode 100644
index 0000000000..f569538fac
--- /dev/null
+++ b/source3/utils/net_time.c
@@ -0,0 +1,238 @@
+/*
+ Samba Unix/Linux SMB client library
+ net time command
+ Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "utils/net.h"
+
+/*
+ return the time on a server. This does not require any authentication
+*/
+static time_t cli_servertime(const char *host, struct sockaddr_storage *pss, int *zone)
+{
+ struct nmb_name calling, called;
+ time_t ret = 0;
+ struct cli_state *cli = NULL;
+ NTSTATUS status;
+
+ cli = cli_initialise();
+ if (!cli) {
+ goto done;
+ }
+
+ status = cli_connect(cli, host, pss);
+ if (!NT_STATUS_IS_OK(status)) {
+ fprintf(stderr,"Can't contact server %s. Error %s\n", host, nt_errstr(status));
+ goto done;
+ }
+
+ make_nmb_name(&calling, global_myname(), 0x0);
+ if (host) {
+ make_nmb_name(&called, host, 0x20);
+ } else {
+ make_nmb_name(&called, "*SMBSERVER", 0x20);
+ }
+
+ if (!cli_session_request(cli, &calling, &called)) {
+ fprintf(stderr,"Session request failed\n");
+ goto done;
+ }
+ if (!cli_negprot(cli)) {
+ fprintf(stderr,"Protocol negotiation failed\n");
+ goto done;
+ }
+
+ ret = cli->servertime;
+ if (zone) *zone = cli->serverzone;
+
+done:
+ if (cli) {
+ cli_shutdown(cli);
+ }
+ return ret;
+}
+
+/* find the servers time on the opt_host host */
+static time_t nettime(struct net_context *c, int *zone)
+{
+ return cli_servertime(c->opt_host,
+ c->opt_have_ip? &c->opt_dest_ip : NULL, zone);
+}
+
+/* return a time as a string ready to be passed to /bin/date */
+static const char *systime(time_t t)
+{
+ static fstring s;
+ struct tm *tm;
+
+ tm = localtime(&t);
+ if (!tm) {
+ return "unknown";
+ }
+
+ fstr_sprintf(s, "%02d%02d%02d%02d%04d.%02d",
+ tm->tm_mon+1, tm->tm_mday, tm->tm_hour,
+ tm->tm_min, tm->tm_year + 1900, tm->tm_sec);
+ return s;
+}
+
+int net_time_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(
+"net time\n\tdisplays time on a server\n\n"
+"net time system\n\tdisplays time on a server in a format ready for /bin/date\n\n"
+"net time set\n\truns /bin/date with the time from the server\n\n"
+"net time zone\n\tdisplays the timezone in hours from GMT on the remote computer\n\n"
+"\n");
+ net_common_flags_usage(c, argc, argv);
+ return -1;
+}
+
+/* try to set the system clock using /bin/date */
+static int net_time_set(struct net_context *c, int argc, const char **argv)
+{
+ time_t t = nettime(c, NULL);
+ char *cmd;
+ int result;
+
+ if (t == 0) return -1;
+
+ /* yes, I know this is cheesy. Use "net time system" if you want to
+ roll your own. I'm putting this in as it works on a large number
+ of systems and the user has a choice in whether its used or not */
+ asprintf(&cmd, "/bin/date %s", systime(t));
+ result = system(cmd);
+ if (result)
+ d_fprintf(stderr, "%s failed. Error was (%s)\n",
+ cmd, strerror(errno));
+ free(cmd);
+
+ return result;
+}
+
+/* display the time on a remote box in a format ready for /bin/date */
+static int net_time_system(struct net_context *c, int argc, const char **argv)
+{
+ time_t t;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net time system\n"
+ " Output remote time server time in a format ready "
+ "for /bin/date\n");
+ return 0;
+ }
+
+ t = nettime(c, NULL);
+ if (t == 0) return -1;
+
+ printf("%s\n", systime(t));
+
+ return 0;
+}
+
+/* display the remote time server's offset to UTC */
+static int net_time_zone(struct net_context *c, int argc, const char **argv)
+{
+ int zone = 0;
+ int hours, mins;
+ char zsign;
+ time_t t;
+
+ if (c->display_usage) {
+ d_printf("Usage:\n"
+ "net time zone\n"
+ " Display the remote time server's offset to UTC\n");
+ return 0;
+ }
+
+ t = nettime(c, &zone);
+
+ if (t == 0) return -1;
+
+ zsign = (zone > 0) ? '-' : '+';
+ if (zone < 0) zone = -zone;
+
+ zone /= 60;
+ hours = zone / 60;
+ mins = zone % 60;
+
+ printf("%c%02d%02d\n", zsign, hours, mins);
+
+ return 0;
+}
+
+/* display or set the time on a host */
+int net_time(struct net_context *c, int argc, const char **argv)
+{
+ time_t t;
+ struct functable func[] = {
+ {
+ "system",
+ net_time_system,
+ NET_TRANSPORT_LOCAL,
+ "Display time ready for /bin/date",
+ "net time system\n"
+ " Display time ready for /bin/date"
+ },
+ {
+ "set",
+ net_time_set,
+ NET_TRANSPORT_LOCAL,
+ "Set the system time from time server",
+ "net time set\n"
+ " Set the system time from time server"
+ },
+ {
+ "zone",
+ net_time_zone,
+ NET_TRANSPORT_LOCAL,
+ "Display timezone offset from UTC",
+ "net time zone\n"
+ " Display timezone offset from UTC"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ if (argc != 0) {
+ return net_run_function(c, argc, argv, "net time", func);
+ }
+
+ if (c->display_usage) {
+ d_printf("Usage:\n");
+ d_printf("net time\n"
+ " Display the remote time server's time\n");
+ net_display_usage_from_functable(func);
+ return 0;
+ }
+
+ if (!c->opt_host && !c->opt_have_ip &&
+ !find_master_ip(c->opt_target_workgroup, &c->opt_dest_ip)) {
+ d_fprintf(stderr, "Could not locate a time server. Try "
+ "specifying a target host.\n");
+ net_time_usage(c, argc,argv);
+ return -1;
+ }
+
+ /* default - print the time */
+ t = cli_servertime(c->opt_host, c->opt_have_ip? &c->opt_dest_ip : NULL,
+ NULL);
+ if (t == 0) return -1;
+
+ d_printf("%s", ctime(&t));
+ return 0;
+}
diff --git a/source3/utils/net_user.c b/source3/utils/net_user.c
new file mode 100644
index 0000000000..b98b6a13a7
--- /dev/null
+++ b/source3/utils/net_user.c
@@ -0,0 +1,67 @@
+/*
+ Samba Unix/Linux SMB client library
+ net user commands
+ Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
+ Copyright (C) 2002 Andrew Tridgell (tridge@samba.org)
+ Copyright (C) 2008 Kai Blin (kai@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+int net_user_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("\nnet [<method>] user [misc. options] [targets]"\
+ "\n\tList users\n\n");
+ d_printf("net [<method>] user DELETE <name> [misc. options] [targets]"\
+ "\n\tDelete specified user\n");
+ d_printf("\nnet [<method>] user INFO <name> [misc. options] [targets]"\
+ "\n\tList the domain groups of the specified user\n");
+ d_printf("\nnet [<method>] user ADD <name> [password] [-c container] "\
+ "[-F user flags] [misc. options]"\
+ " [targets]\n\tAdd specified user\n");
+ d_printf("\nnet [<method>] user RENAME <oldusername> <newusername>"\
+ " [targets]\n\tRename specified user\n\n");
+
+ net_common_methods_usage(c, argc, argv);
+ net_common_flags_usage(c, argc, argv);
+ d_printf("\t-C or --comment=<comment>\tdescriptive comment "\
+ "(for add only)\n");
+ d_printf("\t-c or --container=<container>\tLDAP container, defaults "\
+ "to cn=Users (for add in ADS only)\n");
+ return -1;
+}
+
+int net_user(struct net_context *c, int argc, const char **argv)
+{
+ if (argc < 1)
+ return net_user_usage(c, argc, argv);
+
+ if (StrCaseCmp(argv[0], "HELP") == 0) {
+ net_user_usage(c, argc, argv);
+ return 0;
+ }
+
+ if (net_ads_check(c) == 0)
+ return net_ads_user(c, argc, argv);
+
+ /* if server is not specified, default to PDC? */
+ if (net_rpc_check(c, NET_FLAGS_PDC))
+ return net_rpc_user(c, argc, argv);
+
+ return net_rap_user(c, argc, argv);
+}
+
diff --git a/source3/utils/net_usershare.c b/source3/utils/net_usershare.c
new file mode 100644
index 0000000000..8f263c636c
--- /dev/null
+++ b/source3/utils/net_usershare.c
@@ -0,0 +1,1073 @@
+/*
+ Samba Unix/Linux SMB client library
+ Distributed SMB/CIFS Server Management Utility
+
+ Copyright (C) Jeremy Allison (jra@samba.org) 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+struct {
+ const char *us_errstr;
+ enum usershare_err us_err;
+} us_errs [] = {
+ {"",USERSHARE_OK},
+ {"Malformed usershare file", USERSHARE_MALFORMED_FILE},
+ {"Bad version number", USERSHARE_BAD_VERSION},
+ {"Malformed path entry", USERSHARE_MALFORMED_PATH},
+ {"Malformed comment entryfile", USERSHARE_MALFORMED_COMMENT_DEF},
+ {"Malformed acl definition", USERSHARE_MALFORMED_ACL_DEF},
+ {"Acl parse error", USERSHARE_ACL_ERR},
+ {"Path not absolute", USERSHARE_PATH_NOT_ABSOLUTE},
+ {"Path is denied", USERSHARE_PATH_IS_DENIED},
+ {"Path not allowed", USERSHARE_PATH_NOT_ALLOWED},
+ {"Path is not a directory", USERSHARE_PATH_NOT_DIRECTORY},
+ {"System error", USERSHARE_POSIX_ERR},
+ {NULL,(enum usershare_err)-1}
+};
+
+static const char *get_us_error_code(enum usershare_err us_err)
+{
+ char *result;
+ int idx = 0;
+
+ while (us_errs[idx].us_errstr != NULL) {
+ if (us_errs[idx].us_err == us_err) {
+ return us_errs[idx].us_errstr;
+ }
+ idx++;
+ }
+
+ result = talloc_asprintf(talloc_tos(), "Usershare error code (0x%x)",
+ (unsigned int)us_err);
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+/* The help subsystem for the USERSHARE subcommand */
+
+static int net_usershare_add_usage(struct net_context *c, int argc, const char **argv)
+{
+ char chr = *lp_winbind_separator();
+ d_printf(
+ "net usershare add [-l|--long] <sharename> <path> [<comment>] [<acl>] [<guest_ok=[y|n]>]\n"
+ "\tAdds the specified share name for this user.\n"
+ "\t<sharename> is the new share name.\n"
+ "\t<path> is the path on the filesystem to export.\n"
+ "\t<comment> is the optional comment for the new share.\n"
+ "\t<acl> is an optional share acl in the format \"DOMAIN%cname:X,DOMAIN%cname:X,....\"\n"
+ "\t<guest_ok=y> if present sets \"guest ok = yes\" on this usershare.\n"
+ "\t\t\"X\" represents a permission and can be any one of the characters f, r or d\n"
+ "\t\twhere \"f\" means full control, \"r\" means read-only, \"d\" means deny access.\n"
+ "\t\tname may be a domain user or group. For local users use the local server name "
+ "instead of \"DOMAIN\"\n"
+ "\t\tThe default acl is \"Everyone:r\" which allows everyone read-only access.\n"
+ "\tAdd -l or --long to print the info on the newly added share.\n",
+ chr, chr );
+ return -1;
+}
+
+static int net_usershare_delete_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(
+ "net usershare delete <sharename>\n"
+ "\tdeletes the specified share name for this user.\n");
+ return -1;
+}
+
+static int net_usershare_info_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(
+ "net usershare info [-l|--long] [wildcard sharename]\n"
+ "\tPrints out the path, comment and acl elements of shares that match the wildcard.\n"
+ "\tBy default only gives info on shares owned by the current user\n"
+ "\tAdd -l or --long to apply this to all shares\n"
+ "\tOmit the sharename or use a wildcard of '*' to see all shares\n");
+ return -1;
+}
+
+static int net_usershare_list_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf(
+ "net usershare list [-l|--long] [wildcard sharename]\n"
+ "\tLists the names of all shares that match the wildcard.\n"
+ "\tBy default only lists shares owned by the current user\n"
+ "\tAdd -l or --long to apply this to all shares\n"
+ "\tOmit the sharename or use a wildcard of '*' to see all shares\n");
+ return -1;
+}
+
+int net_usershare_usage(struct net_context *c, int argc, const char **argv)
+{
+ d_printf("net usershare add <sharename> <path> [<comment>] [<acl>] [<guest_ok=[y|n]>] to "
+ "add or change a user defined share.\n"
+ "net usershare delete <sharename> to delete a user defined share.\n"
+ "net usershare info [-l|--long] [wildcard sharename] to print info about a user defined share.\n"
+ "net usershare list [-l|--long] [wildcard sharename] to list user defined shares.\n"
+ "net usershare help\n"
+ "\nType \"net usershare help <option>\" to get more information on that option\n\n");
+
+ net_common_flags_usage(c, argc, argv);
+ return -1;
+}
+
+/***************************************************************************
+***************************************************************************/
+
+static char *get_basepath(TALLOC_CTX *ctx)
+{
+ char *basepath = talloc_strdup(ctx, lp_usershare_path());
+
+ if (!basepath) {
+ return NULL;
+ }
+ if ((basepath[0] != '\0') && (basepath[strlen(basepath)-1] == '/')) {
+ basepath[strlen(basepath)-1] = '\0';
+ }
+ return basepath;
+}
+
+/***************************************************************************
+ Delete a single userlevel share.
+***************************************************************************/
+
+static int net_usershare_delete(struct net_context *c, int argc, const char **argv)
+{
+ char *us_path;
+ char *sharename;
+
+ if (argc != 1 || c->display_usage) {
+ return net_usershare_delete_usage(c, argc, argv);
+ }
+
+ if ((sharename = strdup_lower(argv[0])) == NULL) {
+ d_fprintf(stderr, "strdup failed\n");
+ return -1;
+ }
+
+ if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS, strlen(sharename))) {
+ d_fprintf(stderr, "net usershare delete: share name %s contains "
+ "invalid characters (any of %s)\n",
+ sharename, INVALID_SHARENAME_CHARS);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ us_path = talloc_asprintf(talloc_tos(),
+ "%s/%s",
+ lp_usershare_path(),
+ sharename);
+ if (!us_path) {
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ if (unlink(us_path) != 0) {
+ d_fprintf(stderr, "net usershare delete: unable to remove usershare %s. "
+ "Error was %s\n",
+ us_path, strerror(errno));
+ SAFE_FREE(sharename);
+ return -1;
+ }
+ SAFE_FREE(sharename);
+ return 0;
+}
+
+/***************************************************************************
+ Data structures to handle a list of usershare files.
+***************************************************************************/
+
+struct file_list {
+ struct file_list *next, *prev;
+ const char *pathname;
+};
+
+static struct file_list *flist;
+
+/***************************************************************************
+***************************************************************************/
+
+static int get_share_list(TALLOC_CTX *ctx, const char *wcard, bool only_ours)
+{
+ SMB_STRUCT_DIR *dp;
+ SMB_STRUCT_DIRENT *de;
+ uid_t myuid = geteuid();
+ struct file_list *fl = NULL;
+ char *basepath = get_basepath(ctx);
+
+ if (!basepath) {
+ return -1;
+ }
+ dp = sys_opendir(basepath);
+ if (!dp) {
+ d_fprintf(stderr, "get_share_list: cannot open usershare directory %s. Error %s\n",
+ basepath, strerror(errno) );
+ return -1;
+ }
+
+ while((de = sys_readdir(dp)) != 0) {
+ SMB_STRUCT_STAT sbuf;
+ char *path;
+ const char *n = de->d_name;
+
+ /* Ignore . and .. */
+ if (*n == '.') {
+ if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
+ continue;
+ }
+ }
+
+ if (!validate_net_name(n, INVALID_SHARENAME_CHARS, strlen(n))) {
+ d_fprintf(stderr, "get_share_list: ignoring bad share name %s\n",n);
+ continue;
+ }
+ path = talloc_asprintf(ctx,
+ "%s/%s",
+ basepath,
+ n);
+ if (!path) {
+ sys_closedir(dp);
+ return -1;
+ }
+
+ if (sys_lstat(path, &sbuf) != 0) {
+ d_fprintf(stderr, "get_share_list: can't lstat file %s. Error was %s\n",
+ path, strerror(errno) );
+ continue;
+ }
+
+ if (!S_ISREG(sbuf.st_mode)) {
+ d_fprintf(stderr, "get_share_list: file %s is not a regular file. Ignoring.\n",
+ path );
+ continue;
+ }
+
+ if (only_ours && sbuf.st_uid != myuid) {
+ continue;
+ }
+
+ if (!unix_wild_match(wcard, n)) {
+ continue;
+ }
+
+ /* (Finally) - add to list. */
+ fl = TALLOC_P(ctx, struct file_list);
+ if (!fl) {
+ sys_closedir(dp);
+ return -1;
+ }
+ fl->pathname = talloc_strdup(ctx, n);
+ if (!fl->pathname) {
+ sys_closedir(dp);
+ return -1;
+ }
+
+ DLIST_ADD(flist, fl);
+ }
+
+ sys_closedir(dp);
+ return 0;
+}
+
+enum us_priv_op { US_LIST_OP, US_INFO_OP};
+
+struct us_priv_info {
+ TALLOC_CTX *ctx;
+ enum us_priv_op op;
+ struct net_context *c;
+};
+
+/***************************************************************************
+ Call a function for every share on the list.
+***************************************************************************/
+
+static int process_share_list(int (*fn)(struct file_list *, void *), void *priv)
+{
+ struct file_list *fl;
+ int ret = 0;
+
+ for (fl = flist; fl; fl = fl->next) {
+ ret = (*fn)(fl, priv);
+ }
+
+ return ret;
+}
+
+/***************************************************************************
+ Info function.
+***************************************************************************/
+
+static int info_fn(struct file_list *fl, void *priv)
+{
+ SMB_STRUCT_STAT sbuf;
+ char **lines = NULL;
+ struct us_priv_info *pi = (struct us_priv_info *)priv;
+ TALLOC_CTX *ctx = pi->ctx;
+ struct net_context *c = pi->c;
+ int fd = -1;
+ int numlines = 0;
+ SEC_DESC *psd = NULL;
+ char *basepath;
+ char *sharepath = NULL;
+ char *comment = NULL;
+ char *acl_str;
+ int num_aces;
+ char sep_str[2];
+ enum usershare_err us_err;
+ bool guest_ok = false;
+
+ sep_str[0] = *lp_winbind_separator();
+ sep_str[1] = '\0';
+
+ basepath = get_basepath(ctx);
+ if (!basepath) {
+ return -1;
+ }
+ basepath = talloc_asprintf_append(basepath,
+ "/%s",
+ fl->pathname);
+ if (!basepath) {
+ return -1;
+ }
+
+#ifdef O_NOFOLLOW
+ fd = sys_open(basepath, O_RDONLY|O_NOFOLLOW, 0);
+#else
+ fd = sys_open(basepath, O_RDONLY, 0);
+#endif
+
+ if (fd == -1) {
+ d_fprintf(stderr, "info_fn: unable to open %s. %s\n",
+ basepath, strerror(errno) );
+ return -1;
+ }
+
+ /* Paranoia... */
+ if (sys_fstat(fd, &sbuf) != 0) {
+ d_fprintf(stderr, "info_fn: can't fstat file %s. Error was %s\n",
+ basepath, strerror(errno) );
+ close(fd);
+ return -1;
+ }
+
+ if (!S_ISREG(sbuf.st_mode)) {
+ d_fprintf(stderr, "info_fn: file %s is not a regular file. Ignoring.\n",
+ basepath );
+ close(fd);
+ return -1;
+ }
+
+ lines = fd_lines_load(fd, &numlines, 10240);
+ close(fd);
+
+ if (lines == NULL) {
+ return -1;
+ }
+
+ /* Ensure it's well formed. */
+ us_err = parse_usershare_file(ctx, &sbuf, fl->pathname, -1, lines, numlines,
+ &sharepath,
+ &comment,
+ &psd,
+ &guest_ok);
+
+ file_lines_free(lines);
+
+ if (us_err != USERSHARE_OK) {
+ d_fprintf(stderr, "info_fn: file %s is not a well formed usershare file.\n",
+ basepath );
+ d_fprintf(stderr, "info_fn: Error was %s.\n",
+ get_us_error_code(us_err) );
+ return -1;
+ }
+
+ acl_str = talloc_strdup(ctx, "usershare_acl=");
+ if (!acl_str) {
+ return -1;
+ }
+
+ for (num_aces = 0; num_aces < psd->dacl->num_aces; num_aces++) {
+ const char *domain;
+ const char *name;
+ NTSTATUS ntstatus;
+
+ ntstatus = net_lookup_name_from_sid(c, ctx,
+ &psd->dacl->aces[num_aces].trustee,
+ &domain, &name);
+
+ if (NT_STATUS_IS_OK(ntstatus)) {
+ if (domain && *domain) {
+ acl_str = talloc_asprintf_append(acl_str,
+ "%s%s",
+ domain,
+ sep_str);
+ if (!acl_str) {
+ return -1;
+ }
+ }
+ acl_str = talloc_asprintf_append(acl_str,
+ "%s",
+ name);
+ if (!acl_str) {
+ return -1;
+ }
+
+ } else {
+ fstring sidstr;
+ sid_to_fstring(sidstr,
+ &psd->dacl->aces[num_aces].trustee);
+ acl_str = talloc_asprintf_append(acl_str,
+ "%s",
+ sidstr);
+ if (!acl_str) {
+ return -1;
+ }
+ }
+ acl_str = talloc_asprintf_append(acl_str, ":");
+ if (!acl_str) {
+ return -1;
+ }
+
+ if (psd->dacl->aces[num_aces].type == SEC_ACE_TYPE_ACCESS_DENIED) {
+ acl_str = talloc_asprintf_append(acl_str, "D,");
+ if (!acl_str) {
+ return -1;
+ }
+ } else {
+ if (psd->dacl->aces[num_aces].access_mask & GENERIC_ALL_ACCESS) {
+ acl_str = talloc_asprintf_append(acl_str, "F,");
+ } else {
+ acl_str = talloc_asprintf_append(acl_str, "R,");
+ }
+ if (!acl_str) {
+ return -1;
+ }
+ }
+ }
+
+ if (pi->op == US_INFO_OP) {
+ d_printf("[%s]\n", fl->pathname );
+ d_printf("path=%s\n", sharepath );
+ d_printf("comment=%s\n", comment);
+ d_printf("%s\n", acl_str);
+ d_printf("guest_ok=%c\n\n", guest_ok ? 'y' : 'n');
+ } else if (pi->op == US_LIST_OP) {
+ d_printf("%s\n", fl->pathname);
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ Print out info (internal detail) on userlevel shares.
+***************************************************************************/
+
+static int net_usershare_info(struct net_context *c, int argc, const char **argv)
+{
+ fstring wcard;
+ bool only_ours = true;
+ int ret = -1;
+ struct us_priv_info pi;
+ TALLOC_CTX *ctx;
+
+ fstrcpy(wcard, "*");
+
+ if (c->display_usage)
+ return net_usershare_info_usage(c, argc, argv);
+
+ if (c->opt_long_list_entries) {
+ only_ours = false;
+ }
+
+ switch (argc) {
+ case 0:
+ break;
+ case 1:
+ fstrcpy(wcard, argv[0]);
+ break;
+ default:
+ return net_usershare_info_usage(c, argc, argv);
+ }
+
+ strlower_m(wcard);
+
+ ctx = talloc_init("share_info");
+ ret = get_share_list(ctx, wcard, only_ours);
+ if (ret) {
+ return ret;
+ }
+
+ pi.ctx = ctx;
+ pi.op = US_INFO_OP;
+ pi.c = c;
+
+ ret = process_share_list(info_fn, &pi);
+ talloc_destroy(ctx);
+ return ret;
+}
+
+/***************************************************************************
+ Count the current total number of usershares.
+***************************************************************************/
+
+static int count_num_usershares(void)
+{
+ SMB_STRUCT_DIR *dp;
+ SMB_STRUCT_DIRENT *de;
+ int num_usershares = 0;
+ TALLOC_CTX *ctx = talloc_tos();
+ char *basepath = get_basepath(ctx);
+
+ if (!basepath) {
+ return -1;
+ }
+
+ dp = sys_opendir(basepath);
+ if (!dp) {
+ d_fprintf(stderr, "count_num_usershares: cannot open usershare directory %s. Error %s\n",
+ basepath, strerror(errno) );
+ return -1;
+ }
+
+ while((de = sys_readdir(dp)) != 0) {
+ SMB_STRUCT_STAT sbuf;
+ char *path;
+ const char *n = de->d_name;
+
+ /* Ignore . and .. */
+ if (*n == '.') {
+ if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
+ continue;
+ }
+ }
+
+ if (!validate_net_name(n, INVALID_SHARENAME_CHARS, strlen(n))) {
+ d_fprintf(stderr, "count_num_usershares: ignoring bad share name %s\n",n);
+ continue;
+ }
+ path = talloc_asprintf(ctx,
+ "%s/%s",
+ basepath,
+ n);
+ if (!path) {
+ sys_closedir(dp);
+ return -1;
+ }
+
+ if (sys_lstat(path, &sbuf) != 0) {
+ d_fprintf(stderr, "count_num_usershares: can't lstat file %s. Error was %s\n",
+ path, strerror(errno) );
+ continue;
+ }
+
+ if (!S_ISREG(sbuf.st_mode)) {
+ d_fprintf(stderr, "count_num_usershares: file %s is not a regular file. Ignoring.\n",
+ path );
+ continue;
+ }
+ num_usershares++;
+ }
+
+ sys_closedir(dp);
+ return num_usershares;
+}
+
+/***************************************************************************
+ Add a single userlevel share.
+***************************************************************************/
+
+static int net_usershare_add(struct net_context *c, int argc, const char **argv)
+{
+ TALLOC_CTX *ctx = talloc_stackframe();
+ SMB_STRUCT_STAT sbuf;
+ SMB_STRUCT_STAT lsbuf;
+ char *sharename;
+ char *full_path;
+ char *full_path_tmp;
+ const char *us_path;
+ const char *us_comment;
+ const char *arg_acl;
+ char *us_acl;
+ char *file_img;
+ int num_aces = 0;
+ int i;
+ int tmpfd;
+ const char *pacl;
+ size_t to_write;
+ uid_t myeuid = geteuid();
+ bool guest_ok = false;
+ int num_usershares;
+
+ us_comment = "";
+ arg_acl = "S-1-1-0:R";
+
+ if (c->display_usage)
+ return net_usershare_add_usage(c, argc, argv);
+
+ switch (argc) {
+ case 0:
+ case 1:
+ default:
+ return net_usershare_add_usage(c, argc, argv);
+ case 2:
+ sharename = strdup_lower(argv[0]);
+ us_path = argv[1];
+ break;
+ case 3:
+ sharename = strdup_lower(argv[0]);
+ us_path = argv[1];
+ us_comment = argv[2];
+ break;
+ case 4:
+ sharename = strdup_lower(argv[0]);
+ us_path = argv[1];
+ us_comment = argv[2];
+ arg_acl = argv[3];
+ break;
+ case 5:
+ sharename = strdup_lower(argv[0]);
+ us_path = argv[1];
+ us_comment = argv[2];
+ arg_acl = argv[3];
+ if (strlen(arg_acl) == 0) {
+ arg_acl = "S-1-1-0:R";
+ }
+ if (!strnequal(argv[4], "guest_ok=", 9)) {
+ TALLOC_FREE(ctx);
+ return net_usershare_add_usage(c, argc, argv);
+ }
+ switch (argv[4][9]) {
+ case 'y':
+ case 'Y':
+ guest_ok = true;
+ break;
+ case 'n':
+ case 'N':
+ guest_ok = false;
+ break;
+ default:
+ TALLOC_FREE(ctx);
+ return net_usershare_add_usage(c, argc, argv);
+ }
+ break;
+ }
+
+ /* Ensure we're under the "usershare max shares" number. Advisory only. */
+ num_usershares = count_num_usershares();
+ if (num_usershares >= lp_usershare_max_shares()) {
+ d_fprintf(stderr, "net usershare add: maximum number of allowed usershares (%d) reached\n",
+ lp_usershare_max_shares() );
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS, strlen(sharename))) {
+ d_fprintf(stderr, "net usershare add: share name %s contains "
+ "invalid characters (any of %s)\n",
+ sharename, INVALID_SHARENAME_CHARS);
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ /* Disallow shares the same as users. */
+ if (getpwnam(sharename)) {
+ d_fprintf(stderr, "net usershare add: share name %s is already a valid system user name\n",
+ sharename );
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ /* Construct the full path for the usershare file. */
+ full_path = get_basepath(ctx);
+ if (!full_path) {
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+ full_path_tmp = talloc_asprintf(ctx,
+ "%s/:tmpXXXXXX",
+ full_path);
+ if (!full_path_tmp) {
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ full_path = talloc_asprintf_append(full_path,
+ "/%s",
+ sharename);
+ if (!full_path) {
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ /* The path *must* be absolute. */
+ if (us_path[0] != '/') {
+ d_fprintf(stderr,"net usershare add: path %s is not an absolute path.\n",
+ us_path);
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ /* Check the directory to be shared exists. */
+ if (sys_stat(us_path, &sbuf) != 0) {
+ d_fprintf(stderr, "net usershare add: cannot stat path %s to ensure "
+ "this is a directory. Error was %s\n",
+ us_path, strerror(errno) );
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ if (!S_ISDIR(sbuf.st_mode)) {
+ d_fprintf(stderr, "net usershare add: path %s is not a directory.\n",
+ us_path );
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ /* If we're not root, check if we're restricted to sharing out directories
+ that we own only. */
+
+ if ((myeuid != 0) && lp_usershare_owner_only() && (myeuid != sbuf.st_uid)) {
+ d_fprintf(stderr, "net usershare add: cannot share path %s as "
+ "we are restricted to only sharing directories we own.\n"
+ "\tAsk the administrator to add the line \"usershare owner only = false\" \n"
+ "\tto the [global] section of the smb.conf to allow this.\n",
+ us_path );
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ /* No validation needed on comment. Now go through and validate the
+ acl string. Convert names to SID's as needed. Then run it through
+ parse_usershare_acl to ensure it's valid. */
+
+ /* Start off the string we'll append to. */
+ us_acl = talloc_strdup(ctx, "");
+ if (!us_acl) {
+ TALLOC_FREE(ctx);
+ return -1;
+ }
+
+ pacl = arg_acl;
+ num_aces = 1;
+
+ /* Add the number of ',' characters to get the number of aces. */
+ num_aces += count_chars(pacl,',');
+
+ for (i = 0; i < num_aces; i++) {
+ DOM_SID sid;
+ const char *pcolon = strchr_m(pacl, ':');
+ const char *name;
+
+ if (pcolon == NULL) {
+ d_fprintf(stderr, "net usershare add: malformed acl %s (missing ':').\n",
+ pacl );
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ switch(pcolon[1]) {
+ case 'f':
+ case 'F':
+ case 'd':
+ case 'r':
+ case 'R':
+ break;
+ default:
+ d_fprintf(stderr, "net usershare add: malformed acl %s "
+ "(access control must be 'r', 'f', or 'd')\n",
+ pacl );
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ if (pcolon[2] != ',' && pcolon[2] != '\0') {
+ d_fprintf(stderr, "net usershare add: malformed terminating character for acl %s\n",
+ pacl );
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ /* Get the name */
+ if ((name = talloc_strndup(ctx, pacl, pcolon - pacl)) == NULL) {
+ d_fprintf(stderr, "talloc_strndup failed\n");
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+ if (!string_to_sid(&sid, name)) {
+ /* Convert to a SID */
+ NTSTATUS ntstatus = net_lookup_sid_from_name(c, ctx, name, &sid);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ d_fprintf(stderr, "net usershare add: cannot convert name \"%s\" to a SID. %s.",
+ name, get_friendly_nt_error_msg(ntstatus) );
+ if (NT_STATUS_EQUAL(ntstatus, NT_STATUS_CONNECTION_REFUSED)) {
+ d_fprintf(stderr, " Maybe smbd is not running.\n");
+ } else {
+ d_fprintf(stderr, "\n");
+ }
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+ }
+ us_acl = talloc_asprintf_append(
+ us_acl, "%s:%c,", sid_string_tos(&sid), pcolon[1]);
+
+ /* Move to the next ACL entry. */
+ if (pcolon[2] == ',') {
+ pacl = &pcolon[3];
+ }
+ }
+
+ /* Remove the last ',' */
+ us_acl[strlen(us_acl)-1] = '\0';
+
+ if (guest_ok && !lp_usershare_allow_guests()) {
+ d_fprintf(stderr, "net usershare add: guest_ok=y requested "
+ "but the \"usershare allow guests\" parameter is not enabled "
+ "by this server.\n");
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ /* Create a temporary filename for this share. */
+ tmpfd = smb_mkstemp(full_path_tmp);
+
+ if (tmpfd == -1) {
+ d_fprintf(stderr, "net usershare add: cannot create tmp file %s\n",
+ full_path_tmp );
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ /* Ensure we opened the file we thought we did. */
+ if (sys_lstat(full_path_tmp, &lsbuf) != 0) {
+ d_fprintf(stderr, "net usershare add: cannot lstat tmp file %s\n",
+ full_path_tmp );
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ /* Check this is the same as the file we opened. */
+ if (sys_fstat(tmpfd, &sbuf) != 0) {
+ d_fprintf(stderr, "net usershare add: cannot fstat tmp file %s\n",
+ full_path_tmp );
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ if (!S_ISREG(sbuf.st_mode) || sbuf.st_dev != lsbuf.st_dev || sbuf.st_ino != lsbuf.st_ino) {
+ d_fprintf(stderr, "net usershare add: tmp file %s is not a regular file ?\n",
+ full_path_tmp );
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ if (fchmod(tmpfd, 0644) == -1) {
+ d_fprintf(stderr, "net usershare add: failed to fchmod tmp file %s to 0644n",
+ full_path_tmp );
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ /* Create the in-memory image of the file. */
+ file_img = talloc_strdup(ctx, "#VERSION 2\npath=");
+ file_img = talloc_asprintf_append(file_img, "%s\ncomment=%s\nusershare_acl=%s\nguest_ok=%c\n",
+ us_path, us_comment, us_acl, guest_ok ? 'y' : 'n');
+
+ to_write = strlen(file_img);
+
+ if (write(tmpfd, file_img, to_write) != to_write) {
+ d_fprintf(stderr, "net usershare add: failed to write %u bytes to file %s. Error was %s\n",
+ (unsigned int)to_write, full_path_tmp, strerror(errno));
+ unlink(full_path_tmp);
+ TALLOC_FREE(ctx);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ /* Attempt to replace any existing share by this name. */
+ if (rename(full_path_tmp, full_path) != 0) {
+ unlink(full_path_tmp);
+ d_fprintf(stderr, "net usershare add: failed to add share %s. Error was %s\n",
+ sharename, strerror(errno));
+ TALLOC_FREE(ctx);
+ close(tmpfd);
+ SAFE_FREE(sharename);
+ return -1;
+ }
+
+ close(tmpfd);
+
+ if (c->opt_long_list_entries) {
+ const char *my_argv[2];
+ my_argv[0] = sharename;
+ my_argv[1] = NULL;
+ net_usershare_info(c, 1, my_argv);
+ }
+
+ SAFE_FREE(sharename);
+ TALLOC_FREE(ctx);
+ return 0;
+}
+
+#if 0
+/***************************************************************************
+ List function.
+***************************************************************************/
+
+static int list_fn(struct file_list *fl, void *priv)
+{
+ d_printf("%s\n", fl->pathname);
+ return 0;
+}
+#endif
+
+/***************************************************************************
+ List userlevel shares.
+***************************************************************************/
+
+static int net_usershare_list(struct net_context *c, int argc,
+ const char **argv)
+{
+ fstring wcard;
+ bool only_ours = true;
+ int ret = -1;
+ struct us_priv_info pi;
+ TALLOC_CTX *ctx;
+
+ fstrcpy(wcard, "*");
+
+ if (c->display_usage)
+ return net_usershare_list_usage(c, argc, argv);
+
+ if (c->opt_long_list_entries) {
+ only_ours = false;
+ }
+
+ switch (argc) {
+ case 0:
+ break;
+ case 1:
+ fstrcpy(wcard, argv[0]);
+ break;
+ default:
+ return net_usershare_list_usage(c, argc, argv);
+ }
+
+ strlower_m(wcard);
+
+ ctx = talloc_init("share_list");
+ ret = get_share_list(ctx, wcard, only_ours);
+ if (ret) {
+ return ret;
+ }
+
+ pi.ctx = ctx;
+ pi.op = US_LIST_OP;
+
+ ret = process_share_list(info_fn, &pi);
+ talloc_destroy(ctx);
+ return ret;
+}
+
+/***************************************************************************
+ Entry-point for all the USERSHARE functions.
+***************************************************************************/
+
+int net_usershare(struct net_context *c, int argc, const char **argv)
+{
+ SMB_STRUCT_DIR *dp;
+
+ struct functable func[] = {
+ {
+ "add",
+ net_usershare_add,
+ NET_TRANSPORT_LOCAL,
+ "Add/modify user defined share",
+ "net usershare add\n"
+ " Add/modify user defined share"
+ },
+ {
+ "delete",
+ net_usershare_delete,
+ NET_TRANSPORT_LOCAL,
+ "Delete user defined share",
+ "net usershare delete\n"
+ " Delete user defined share"
+ },
+ {
+ "info",
+ net_usershare_info,
+ NET_TRANSPORT_LOCAL,
+ "Display information about a user defined share",
+ "net usershare info\n"
+ " Display information about a user defined share"
+ },
+ {
+ "list",
+ net_usershare_list,
+ NET_TRANSPORT_LOCAL,
+ "List user defined shares",
+ "net usershare list\n"
+ " List user defined shares"
+ },
+ {NULL, NULL, 0, NULL, NULL}
+ };
+
+ if (lp_usershare_max_shares() == 0) {
+ d_fprintf(stderr, "net usershare: usershares are currently disabled\n");
+ return -1;
+ }
+
+ dp = sys_opendir(lp_usershare_path());
+ if (!dp) {
+ int err = errno;
+ d_fprintf(stderr, "net usershare: cannot open usershare directory %s. Error %s\n",
+ lp_usershare_path(), strerror(err) );
+ if (err == EACCES) {
+ d_fprintf(stderr, "You do not have permission to create a usershare. Ask your "
+ "administrator to grant you permissions to create a share.\n");
+ } else if (err == ENOENT) {
+ d_fprintf(stderr, "Please ask your system administrator to "
+ "enable user sharing.\n");
+ }
+ return -1;
+ }
+ sys_closedir(dp);
+
+ return net_run_function(c, argc, argv, "net usershare", func);
+}
diff --git a/source3/utils/net_util.c b/source3/utils/net_util.c
new file mode 100644
index 0000000000..88850d29df
--- /dev/null
+++ b/source3/utils/net_util.c
@@ -0,0 +1,597 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Helper routines for net
+ * Copyright (C) Volker Lendecke 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "includes.h"
+#include "utils/net.h"
+
+NTSTATUS net_rpc_lookup_name(struct net_context *c,
+ TALLOC_CTX *mem_ctx, struct cli_state *cli,
+ const char *name, const char **ret_domain,
+ const char **ret_name, DOM_SID *ret_sid,
+ enum lsa_SidType *ret_type)
+{
+ struct rpc_pipe_client *lsa_pipe;
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_OK;
+ const char **dom_names;
+ DOM_SID *sids;
+ enum lsa_SidType *types;
+
+ ZERO_STRUCT(pol);
+
+ result = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
+ &lsa_pipe);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "Could not initialise lsa pipe\n");
+ return result;
+ }
+
+ result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, false,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_fprintf(stderr, "open_policy failed: %s\n",
+ nt_errstr(result));
+ return result;
+ }
+
+ result = rpccli_lsa_lookup_names(lsa_pipe, mem_ctx, &pol, 1,
+ &name, &dom_names, 1, &sids, &types);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ /* This can happen easily, don't log an error */
+ goto done;
+ }
+
+ if (ret_domain != NULL) {
+ *ret_domain = dom_names[0];
+ }
+ if (ret_name != NULL) {
+ *ret_name = talloc_strdup(mem_ctx, name);
+ }
+ if (ret_sid != NULL) {
+ sid_copy(ret_sid, &sids[0]);
+ }
+ if (ret_type != NULL) {
+ *ret_type = types[0];
+ }
+
+ done:
+ if (is_valid_policy_hnd(&pol)) {
+ rpccli_lsa_Close(lsa_pipe, mem_ctx, &pol);
+ }
+ TALLOC_FREE(lsa_pipe);
+
+ return result;
+}
+
+/****************************************************************************
+ Connect to \\server\service.
+****************************************************************************/
+
+NTSTATUS connect_to_service(struct net_context *c,
+ struct cli_state **cli_ctx,
+ struct sockaddr_storage *server_ss,
+ const char *server_name,
+ const char *service_name,
+ const char *service_type)
+{
+ NTSTATUS nt_status;
+ int flags = 0;
+
+ c->opt_password = net_prompt_pass(c, c->opt_user_name);
+
+ if (c->opt_kerberos) {
+ flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
+ }
+
+ if (c->opt_kerberos && c->opt_password) {
+ flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
+ }
+
+ nt_status = cli_full_connection(cli_ctx, NULL, server_name,
+ server_ss, c->opt_port,
+ service_name, service_type,
+ c->opt_user_name, c->opt_workgroup,
+ c->opt_password, flags, Undefined, NULL);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ d_fprintf(stderr, "Could not connect to server %s\n", server_name);
+
+ /* Display a nicer message depending on the result */
+
+ if (NT_STATUS_V(nt_status) ==
+ NT_STATUS_V(NT_STATUS_LOGON_FAILURE))
+ d_fprintf(stderr, "The username or password was not correct.\n");
+
+ if (NT_STATUS_V(nt_status) ==
+ NT_STATUS_V(NT_STATUS_ACCOUNT_LOCKED_OUT))
+ d_fprintf(stderr, "The account was locked out.\n");
+
+ if (NT_STATUS_V(nt_status) ==
+ NT_STATUS_V(NT_STATUS_ACCOUNT_DISABLED))
+ d_fprintf(stderr, "The account was disabled.\n");
+ return nt_status;
+ }
+
+ if (c->smb_encrypt) {
+ nt_status = cli_force_encryption(*cli_ctx,
+ c->opt_user_name,
+ c->opt_password,
+ c->opt_workgroup);
+
+ if (NT_STATUS_EQUAL(nt_status,NT_STATUS_NOT_SUPPORTED)) {
+ d_printf("Encryption required and "
+ "server that doesn't support "
+ "UNIX extensions - failing connect\n");
+ } else if (NT_STATUS_EQUAL(nt_status,NT_STATUS_UNKNOWN_REVISION)) {
+ d_printf("Encryption required and "
+ "can't get UNIX CIFS extensions "
+ "version from server.\n");
+ } else if (NT_STATUS_EQUAL(nt_status,NT_STATUS_UNSUPPORTED_COMPRESSION)) {
+ d_printf("Encryption required and "
+ "share %s doesn't support "
+ "encryption.\n", service_name);
+ } else if (!NT_STATUS_IS_OK(nt_status)) {
+ d_printf("Encryption required and "
+ "setup failed with error %s.\n",
+ nt_errstr(nt_status));
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ cli_shutdown(*cli_ctx);
+ *cli_ctx = NULL;
+ }
+ }
+
+ return nt_status;
+}
+
+/****************************************************************************
+ Connect to \\server\ipc$.
+****************************************************************************/
+
+NTSTATUS connect_to_ipc(struct net_context *c,
+ struct cli_state **cli_ctx,
+ struct sockaddr_storage *server_ss,
+ const char *server_name)
+{
+ return connect_to_service(c, cli_ctx, server_ss, server_name, "IPC$",
+ "IPC");
+}
+
+/****************************************************************************
+ Connect to \\server\ipc$ anonymously.
+****************************************************************************/
+
+NTSTATUS connect_to_ipc_anonymous(struct net_context *c,
+ struct cli_state **cli_ctx,
+ struct sockaddr_storage *server_ss,
+ const char *server_name)
+{
+ NTSTATUS nt_status;
+
+ nt_status = cli_full_connection(cli_ctx, c->opt_requester_name,
+ server_name, server_ss, c->opt_port,
+ "IPC$", "IPC",
+ "", "",
+ "", 0, Undefined, NULL);
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ } else {
+ DEBUG(1,("Cannot connect to server (anonymously). Error was %s\n", nt_errstr(nt_status)));
+ return nt_status;
+ }
+}
+
+/****************************************************************************
+ Return malloced user@realm for krb5 login.
+****************************************************************************/
+
+static char *get_user_and_realm(const char *username)
+{
+ char *user_and_realm = NULL;
+
+ if (!username) {
+ return NULL;
+ }
+ if (strchr_m(username, '@')) {
+ user_and_realm = SMB_STRDUP(username);
+ } else {
+ if (asprintf(&user_and_realm, "%s@%s", username, lp_realm()) == -1) {
+ user_and_realm = NULL;
+ }
+ }
+ return user_and_realm;
+}
+
+/****************************************************************************
+ Connect to \\server\ipc$ using KRB5.
+****************************************************************************/
+
+NTSTATUS connect_to_ipc_krb5(struct net_context *c,
+ struct cli_state **cli_ctx,
+ struct sockaddr_storage *server_ss,
+ const char *server_name)
+{
+ NTSTATUS nt_status;
+ char *user_and_realm = NULL;
+
+ /* FIXME: Should get existing kerberos ticket if possible. */
+ c->opt_password = net_prompt_pass(c, c->opt_user_name);
+ if (!c->opt_password) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ user_and_realm = get_user_and_realm(c->opt_user_name);
+ if (!user_and_realm) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ nt_status = cli_full_connection(cli_ctx, NULL, server_name,
+ server_ss, c->opt_port,
+ "IPC$", "IPC",
+ user_and_realm, c->opt_workgroup,
+ c->opt_password,
+ CLI_FULL_CONNECTION_USE_KERBEROS,
+ Undefined, NULL);
+
+ SAFE_FREE(user_and_realm);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1,("Cannot connect to server using kerberos. Error was %s\n", nt_errstr(nt_status)));
+ return nt_status;
+ }
+
+ if (c->smb_encrypt) {
+ nt_status = cli_cm_force_encryption(*cli_ctx,
+ user_and_realm,
+ c->opt_password,
+ c->opt_workgroup,
+ "IPC$");
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ cli_shutdown(*cli_ctx);
+ *cli_ctx = NULL;
+ }
+ }
+
+ return nt_status;
+}
+
+/**
+ * Connect a server and open a given pipe
+ *
+ * @param cli_dst A cli_state
+ * @param pipe The pipe to open
+ * @param got_pipe boolean that stores if we got a pipe
+ *
+ * @return Normal NTSTATUS return.
+ **/
+NTSTATUS connect_dst_pipe(struct net_context *c, struct cli_state **cli_dst,
+ struct rpc_pipe_client **pp_pipe_hnd,
+ const struct ndr_syntax_id *interface)
+{
+ NTSTATUS nt_status;
+ char *server_name = SMB_STRDUP("127.0.0.1");
+ struct cli_state *cli_tmp = NULL;
+ struct rpc_pipe_client *pipe_hnd = NULL;
+
+ if (server_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (c->opt_destination) {
+ SAFE_FREE(server_name);
+ if ((server_name = SMB_STRDUP(c->opt_destination)) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ /* make a connection to a named pipe */
+ nt_status = connect_to_ipc(c, &cli_tmp, NULL, server_name);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ SAFE_FREE(server_name);
+ return nt_status;
+ }
+
+ nt_status = cli_rpc_pipe_open_noauth(cli_tmp, interface,
+ &pipe_hnd);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("couldn't not initialize pipe\n"));
+ cli_shutdown(cli_tmp);
+ SAFE_FREE(server_name);
+ return nt_status;
+ }
+
+ *cli_dst = cli_tmp;
+ *pp_pipe_hnd = pipe_hnd;
+ SAFE_FREE(server_name);
+
+ return nt_status;
+}
+
+/****************************************************************************
+ Use the local machine account (krb) and password for this session.
+****************************************************************************/
+
+int net_use_krb_machine_account(struct net_context *c)
+{
+ char *user_name = NULL;
+
+ if (!secrets_init()) {
+ d_fprintf(stderr, "ERROR: Unable to open secrets database\n");
+ exit(1);
+ }
+
+ c->opt_password = secrets_fetch_machine_password(
+ c->opt_target_workgroup, NULL, NULL);
+ if (asprintf(&user_name, "%s$@%s", global_myname(), lp_realm()) == -1) {
+ return -1;
+ }
+ c->opt_user_name = user_name;
+ return 0;
+}
+
+/****************************************************************************
+ Use the machine account name and password for this session.
+****************************************************************************/
+
+int net_use_machine_account(struct net_context *c)
+{
+ char *user_name = NULL;
+
+ if (!secrets_init()) {
+ d_fprintf(stderr, "ERROR: Unable to open secrets database\n");
+ exit(1);
+ }
+
+ c->opt_password = secrets_fetch_machine_password(
+ c->opt_target_workgroup, NULL, NULL);
+ if (asprintf(&user_name, "%s$", global_myname()) == -1) {
+ return -1;
+ }
+ c->opt_user_name = user_name;
+ return 0;
+}
+
+bool net_find_server(struct net_context *c,
+ const char *domain,
+ unsigned flags,
+ struct sockaddr_storage *server_ss,
+ char **server_name)
+{
+ const char *d = domain ? domain : c->opt_target_workgroup;
+
+ if (c->opt_host) {
+ *server_name = SMB_STRDUP(c->opt_host);
+ }
+
+ if (c->opt_have_ip) {
+ *server_ss = c->opt_dest_ip;
+ if (!*server_name) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr), &c->opt_dest_ip);
+ *server_name = SMB_STRDUP(addr);
+ }
+ } else if (*server_name) {
+ /* resolve the IP address */
+ if (!resolve_name(*server_name, server_ss, 0x20)) {
+ DEBUG(1,("Unable to resolve server name\n"));
+ return false;
+ }
+ } else if (flags & NET_FLAGS_PDC) {
+ fstring dc_name;
+ struct sockaddr_storage pdc_ss;
+
+ if (!get_pdc_ip(d, &pdc_ss)) {
+ DEBUG(1,("Unable to resolve PDC server address\n"));
+ return false;
+ }
+
+ if (is_zero_addr(&pdc_ss)) {
+ return false;
+ }
+
+ if (!name_status_find(d, 0x1b, 0x20, &pdc_ss, dc_name)) {
+ return false;
+ }
+
+ *server_name = SMB_STRDUP(dc_name);
+ *server_ss = pdc_ss;
+ } else if (flags & NET_FLAGS_DMB) {
+ struct sockaddr_storage msbrow_ss;
+ char addr[INET6_ADDRSTRLEN];
+
+ /* if (!resolve_name(MSBROWSE, &msbrow_ip, 1)) */
+ if (!resolve_name(d, &msbrow_ss, 0x1B)) {
+ DEBUG(1,("Unable to resolve domain browser via name lookup\n"));
+ return false;
+ }
+ *server_ss = msbrow_ss;
+ print_sockaddr(addr, sizeof(addr), server_ss);
+ *server_name = SMB_STRDUP(addr);
+ } else if (flags & NET_FLAGS_MASTER) {
+ struct sockaddr_storage brow_ss;
+ char addr[INET6_ADDRSTRLEN];
+ if (!resolve_name(d, &brow_ss, 0x1D)) {
+ /* go looking for workgroups */
+ DEBUG(1,("Unable to resolve master browser via name lookup\n"));
+ return false;
+ }
+ *server_ss = brow_ss;
+ print_sockaddr(addr, sizeof(addr), server_ss);
+ *server_name = SMB_STRDUP(addr);
+ } else if (!(flags & NET_FLAGS_LOCALHOST_DEFAULT_INSANE)) {
+ if (!interpret_string_addr(server_ss,
+ "127.0.0.1", AI_NUMERICHOST)) {
+ DEBUG(1,("Unable to resolve 127.0.0.1\n"));
+ return false;
+ }
+ *server_name = SMB_STRDUP("127.0.0.1");
+ }
+
+ if (!*server_name) {
+ DEBUG(1,("no server to connect to\n"));
+ return false;
+ }
+
+ return true;
+}
+
+bool net_find_pdc(struct sockaddr_storage *server_ss,
+ fstring server_name,
+ const char *domain_name)
+{
+ if (!get_pdc_ip(domain_name, server_ss)) {
+ return false;
+ }
+ if (is_zero_addr(server_ss)) {
+ return false;
+ }
+
+ if (!name_status_find(domain_name, 0x1b, 0x20, server_ss, server_name)) {
+ return false;
+ }
+
+ return true;
+}
+
+NTSTATUS net_make_ipc_connection(struct net_context *c, unsigned flags,
+ struct cli_state **pcli)
+{
+ return net_make_ipc_connection_ex(c, c->opt_workgroup, NULL, NULL, flags, pcli);
+}
+
+NTSTATUS net_make_ipc_connection_ex(struct net_context *c ,const char *domain,
+ const char *server,
+ struct sockaddr_storage *pss,
+ unsigned flags, struct cli_state **pcli)
+{
+ char *server_name = NULL;
+ struct sockaddr_storage server_ss;
+ struct cli_state *cli = NULL;
+ NTSTATUS nt_status;
+
+ if ( !server || !pss ) {
+ if (!net_find_server(c, domain, flags, &server_ss,
+ &server_name)) {
+ d_fprintf(stderr, "Unable to find a suitable server "
+ "for domain %s\n", domain);
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ } else {
+ server_name = SMB_STRDUP( server );
+ server_ss = *pss;
+ }
+
+ if (flags & NET_FLAGS_ANONYMOUS) {
+ nt_status = connect_to_ipc_anonymous(c, &cli, &server_ss,
+ server_name);
+ } else {
+ nt_status = connect_to_ipc(c, &cli, &server_ss,
+ server_name);
+ }
+
+ /* store the server in the affinity cache if it was a PDC */
+
+ if ( (flags & NET_FLAGS_PDC) && NT_STATUS_IS_OK(nt_status) )
+ saf_store( cli->server_domain, cli->desthost );
+
+ SAFE_FREE(server_name);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ d_fprintf(stderr, "Connection failed: %s\n",
+ nt_errstr(nt_status));
+ cli = NULL;
+ }
+
+done:
+ if (pcli != NULL) {
+ *pcli = cli;
+ }
+ return nt_status;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+const char *net_prompt_pass(struct net_context *c, const char *user)
+{
+ char *prompt = NULL;
+ const char *pass = NULL;
+
+ if (c->opt_password) {
+ return c->opt_password;
+ }
+
+ if (c->opt_machine_pass) {
+ return NULL;
+ }
+
+ if (c->opt_kerberos && !c->opt_user_specified) {
+ return NULL;
+ }
+
+ asprintf(&prompt, "Enter %s's password:", user);
+ if (!prompt) {
+ return NULL;
+ }
+
+ pass = getpass(prompt);
+ SAFE_FREE(prompt);
+
+ return pass;
+}
+
+int net_run_function(struct net_context *c, int argc, const char **argv,
+ const char *whoami, struct functable *table)
+{
+ int i;
+
+ if (argc != 0) {
+ for (i=0; table[i].funcname != NULL; i++) {
+ if (StrCaseCmp(argv[0], table[i].funcname) == 0)
+ return table[i].fn(c, argc-1, argv+1);
+ }
+ }
+
+ if (c->display_usage == false) {
+ d_fprintf(stderr, "Invalid command: %s %s\n", whoami,
+ (argc > 0)?argv[0]:"");
+ }
+ d_printf("Usage:\n");
+ for (i=0; table[i].funcname != NULL; i++) {
+ if(c->display_usage == false)
+ d_printf("%s %-15s %s\n", whoami, table[i].funcname,
+ table[i].description);
+ else
+ d_printf("%s\n", table[i].usage);
+ }
+
+ return c->display_usage?0:-1;
+}
+
+void net_display_usage_from_functable(struct functable *table)
+{
+ int i;
+ for (i=0; table[i].funcname != NULL; i++) {
+ d_printf("%s\n", table[i].usage);
+ }
+}
diff --git a/source3/utils/netlookup.c b/source3/utils/netlookup.c
new file mode 100644
index 0000000000..14f2dddebc
--- /dev/null
+++ b/source3/utils/netlookup.c
@@ -0,0 +1,227 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Name lookup.
+
+ Copyright (C) Jeremy Allison 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+/********************************************************
+ Connection cachine struct. Goes away when ctx destroyed.
+********************************************************/
+
+struct con_struct {
+ bool failed_connect;
+ NTSTATUS err;
+ struct cli_state *cli;
+ struct rpc_pipe_client *lsapipe;
+ POLICY_HND pol;
+};
+
+static struct con_struct *cs;
+
+/********************************************************
+ Close connection on context destruction.
+********************************************************/
+
+static int cs_destructor(struct con_struct *p)
+{
+ if (cs->cli) {
+ cli_shutdown(cs->cli);
+ }
+ cs = NULL;
+ return 0;
+}
+
+/********************************************************
+ Create the connection to localhost.
+********************************************************/
+
+static struct con_struct *create_cs(struct net_context *c,
+ TALLOC_CTX *ctx, NTSTATUS *perr)
+{
+ NTSTATUS nt_status;
+ struct sockaddr_storage loopback_ss;
+
+ *perr = NT_STATUS_OK;
+
+ if (!interpret_string_addr(&loopback_ss, "127.0.0.1", AI_NUMERICHOST)) {
+ *perr = NT_STATUS_INVALID_PARAMETER;
+ return NULL;
+ }
+
+ if (cs) {
+ if (cs->failed_connect) {
+ *perr = cs->err;
+ return NULL;
+ }
+ return cs;
+ }
+
+ cs = TALLOC_P(ctx, struct con_struct);
+ if (!cs) {
+ *perr = NT_STATUS_NO_MEMORY;
+ return NULL;
+ }
+
+ ZERO_STRUCTP(cs);
+ talloc_set_destructor(cs, cs_destructor);
+
+ /* Connect to localhost with given username/password. */
+ /* JRA. Pretty sure we can just do this anonymously.... */
+#if 0
+ if (!opt_password && !opt_machine_pass) {
+ char *pass = getpass("Password:");
+ if (pass) {
+ opt_password = SMB_STRDUP(pass);
+ }
+ }
+#endif
+
+ nt_status = cli_full_connection(&cs->cli, global_myname(), global_myname(),
+ &loopback_ss, 0,
+ "IPC$", "IPC",
+#if 0
+ c->opt_user_name,
+ c->opt_workgroup,
+ c->opt_password,
+#else
+ "",
+ c->opt_workgroup,
+ "",
+#endif
+ 0,
+ Undefined,
+ NULL);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(2,("create_cs: Connect failed. Error was %s\n", nt_errstr(nt_status)));
+ cs->failed_connect = true;
+ cs->err = nt_status;
+ *perr = nt_status;
+ return NULL;
+ }
+
+ nt_status = cli_rpc_pipe_open_noauth(cs->cli,
+ &ndr_table_lsarpc.syntax_id,
+ &cs->lsapipe);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(2,("create_cs: open LSA pipe failed. Error was %s\n", nt_errstr(nt_status)));
+ cs->failed_connect = true;
+ cs->err = nt_status;
+ *perr = nt_status;
+ return NULL;
+ }
+
+ nt_status = rpccli_lsa_open_policy(cs->lsapipe, ctx, true,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &cs->pol);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(2,("create_cs: rpccli_lsa_open_policy failed. Error was %s\n", nt_errstr(nt_status)));
+ cs->failed_connect = true;
+ cs->err = nt_status;
+ *perr = nt_status;
+ return NULL;
+ }
+
+ return cs;
+}
+
+/********************************************************
+ Do a lookup_sids call to localhost.
+ Check if the local machine is authoritative for this sid. We can't
+ check if this is our SID as that's stored in the root-read-only
+ secrets.tdb.
+ The local smbd will also ask winbindd for us, so we don't have to.
+********************************************************/
+
+NTSTATUS net_lookup_name_from_sid(struct net_context *c,
+ TALLOC_CTX *ctx,
+ DOM_SID *psid,
+ const char **ppdomain,
+ const char **ppname)
+{
+ NTSTATUS nt_status;
+ struct con_struct *csp = NULL;
+ char **domains;
+ char **names;
+ enum lsa_SidType *types;
+
+ *ppdomain = NULL;
+ *ppname = NULL;
+
+ csp = create_cs(c, ctx, &nt_status);
+ if (csp == NULL) {
+ return nt_status;
+ }
+
+ nt_status = rpccli_lsa_lookup_sids(csp->lsapipe, ctx,
+ &csp->pol,
+ 1, psid,
+ &domains,
+ &names,
+ &types);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ *ppdomain = domains[0];
+ *ppname = names[0];
+ /* Don't care about type here. */
+
+ /* Converted OK */
+ return NT_STATUS_OK;
+}
+
+/********************************************************
+ Do a lookup_names call to localhost.
+********************************************************/
+
+NTSTATUS net_lookup_sid_from_name(struct net_context *c, TALLOC_CTX *ctx,
+ const char *full_name, DOM_SID *pret_sid)
+{
+ NTSTATUS nt_status;
+ struct con_struct *csp = NULL;
+ DOM_SID *sids = NULL;
+ enum lsa_SidType *types = NULL;
+
+ csp = create_cs(c, ctx, &nt_status);
+ if (csp == NULL) {
+ return nt_status;
+ }
+
+ nt_status = rpccli_lsa_lookup_names(csp->lsapipe, ctx,
+ &csp->pol,
+ 1,
+ &full_name,
+ NULL, 1,
+ &sids, &types);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ *pret_sid = sids[0];
+
+ /* Converted OK */
+ return NT_STATUS_OK;
+}
diff --git a/source3/utils/nmblookup.c b/source3/utils/nmblookup.c
new file mode 100644
index 0000000000..c04b628b1b
--- /dev/null
+++ b/source3/utils/nmblookup.c
@@ -0,0 +1,369 @@
+/*
+ Unix SMB/CIFS implementation.
+ NBT client - used to lookup netbios names
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Jelmer Vernooij 2003 (Conversion to popt)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+extern bool AllowDebugChange;
+
+static bool give_flags = false;
+static bool use_bcast = true;
+static bool got_bcast = false;
+static struct sockaddr_storage bcast_addr;
+static bool recursion_desired = false;
+static bool translate_addresses = false;
+static int ServerFD= -1;
+static bool RootPort = false;
+static bool find_status = false;
+
+/****************************************************************************
+ Open the socket communication.
+**************************************************************************/
+
+static bool open_sockets(void)
+{
+ struct sockaddr_storage ss;
+ const char *sock_addr = lp_socket_address();
+
+ if (!interpret_string_addr(&ss, sock_addr,
+ AI_NUMERICHOST|AI_PASSIVE)) {
+ DEBUG(0,("open_sockets: unable to get socket address "
+ "from string %s", sock_addr));
+ return false;
+ }
+ ServerFD = open_socket_in( SOCK_DGRAM,
+ (RootPort ? 137 : 0),
+ (RootPort ? 0 : 3),
+ &ss, true );
+
+ if (ServerFD == -1) {
+ return false;
+ }
+
+ set_socket_options( ServerFD, "SO_BROADCAST" );
+
+ DEBUG(3, ("Socket opened.\n"));
+ return true;
+}
+
+/****************************************************************************
+turn a node status flags field into a string
+****************************************************************************/
+static char *node_status_flags(unsigned char flags)
+{
+ static fstring ret;
+ fstrcpy(ret,"");
+
+ fstrcat(ret, (flags & 0x80) ? "<GROUP> " : " ");
+ if ((flags & 0x60) == 0x00) fstrcat(ret,"B ");
+ if ((flags & 0x60) == 0x20) fstrcat(ret,"P ");
+ if ((flags & 0x60) == 0x40) fstrcat(ret,"M ");
+ if ((flags & 0x60) == 0x60) fstrcat(ret,"H ");
+ if (flags & 0x10) fstrcat(ret,"<DEREGISTERING> ");
+ if (flags & 0x08) fstrcat(ret,"<CONFLICT> ");
+ if (flags & 0x04) fstrcat(ret,"<ACTIVE> ");
+ if (flags & 0x02) fstrcat(ret,"<PERMANENT> ");
+
+ return ret;
+}
+
+/****************************************************************************
+ Turn the NMB Query flags into a string.
+****************************************************************************/
+
+static char *query_flags(int flags)
+{
+ static fstring ret1;
+ fstrcpy(ret1, "");
+
+ if (flags & NM_FLAGS_RS) fstrcat(ret1, "Response ");
+ if (flags & NM_FLAGS_AA) fstrcat(ret1, "Authoritative ");
+ if (flags & NM_FLAGS_TC) fstrcat(ret1, "Truncated ");
+ if (flags & NM_FLAGS_RD) fstrcat(ret1, "Recursion_Desired ");
+ if (flags & NM_FLAGS_RA) fstrcat(ret1, "Recursion_Available ");
+ if (flags & NM_FLAGS_B) fstrcat(ret1, "Broadcast ");
+
+ return ret1;
+}
+
+/****************************************************************************
+ Do a node status query.
+****************************************************************************/
+
+static void do_node_status(int fd,
+ const char *name,
+ int type,
+ struct sockaddr_storage *pss)
+{
+ struct nmb_name nname;
+ int count, i, j;
+ NODE_STATUS_STRUCT *status;
+ struct node_status_extra extra;
+ fstring cleanname;
+ char addr[INET6_ADDRSTRLEN];
+
+ print_sockaddr(addr, sizeof(addr), pss);
+ d_printf("Looking up status of %s\n",addr);
+ make_nmb_name(&nname, name, type);
+ status = node_status_query(fd, &nname, pss, &count, &extra);
+ if (status) {
+ for (i=0;i<count;i++) {
+ pull_ascii_fstring(cleanname, status[i].name);
+ for (j=0;cleanname[j];j++) {
+ if (!isprint((int)cleanname[j])) {
+ cleanname[j] = '.';
+ }
+ }
+ d_printf("\t%-15s <%02x> - %s\n",
+ cleanname,status[i].type,
+ node_status_flags(status[i].flags));
+ }
+ d_printf("\n\tMAC Address = %02X-%02X-%02X-%02X-%02X-%02X\n",
+ extra.mac_addr[0], extra.mac_addr[1],
+ extra.mac_addr[2], extra.mac_addr[3],
+ extra.mac_addr[4], extra.mac_addr[5]);
+ d_printf("\n");
+ SAFE_FREE(status);
+ } else {
+ d_printf("No reply from %s\n\n",addr);
+ }
+}
+
+
+/****************************************************************************
+ Send out one query.
+****************************************************************************/
+
+static bool query_one(const char *lookup, unsigned int lookup_type)
+{
+ int j, count, flags = 0;
+ struct sockaddr_storage *ip_list=NULL;
+
+ if (got_bcast) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr), &bcast_addr);
+ d_printf("querying %s on %s\n", lookup, addr);
+ ip_list = name_query(ServerFD,lookup,lookup_type,use_bcast,
+ use_bcast?true:recursion_desired,
+ &bcast_addr, &count, &flags, NULL);
+ } else {
+ const struct in_addr *bcast;
+ for (j=iface_count() - 1;
+ !ip_list && j >= 0;
+ j--) {
+ char addr[INET6_ADDRSTRLEN];
+ struct sockaddr_storage bcast_ss;
+
+ bcast = iface_n_bcast_v4(j);
+ if (!bcast) {
+ continue;
+ }
+ in_addr_to_sockaddr_storage(&bcast_ss, *bcast);
+ print_sockaddr(addr, sizeof(addr), &bcast_ss);
+ d_printf("querying %s on %s\n",
+ lookup, addr);
+ ip_list = name_query(ServerFD,lookup,lookup_type,
+ use_bcast,
+ use_bcast?True:recursion_desired,
+ &bcast_ss,&count, &flags, NULL);
+ }
+ }
+
+ if (!ip_list) {
+ return false;
+ }
+
+ if (give_flags) {
+ d_printf("Flags: %s\n", query_flags(flags));
+ }
+
+ for (j=0;j<count;j++) {
+ char addr[INET6_ADDRSTRLEN];
+ if (translate_addresses) {
+ char h_name[MAX_DNS_NAME_LENGTH];
+ h_name[0] = '\0';
+ if (sys_getnameinfo((const struct sockaddr *)&ip_list[j],
+ sizeof(struct sockaddr_storage),
+ h_name, sizeof(h_name),
+ NULL, 0,
+ NI_NAMEREQD)) {
+ continue;
+ }
+ d_printf("%s, ", h_name);
+ }
+ print_sockaddr(addr, sizeof(addr), &ip_list[j]);
+ d_printf("%s %s<%02x>\n", addr,lookup, lookup_type);
+ /* We can only do find_status if the ip address returned
+ was valid - ie. name_query returned true.
+ */
+ if (find_status) {
+ do_node_status(ServerFD, lookup,
+ lookup_type, &ip_list[j]);
+ }
+ }
+
+ safe_free(ip_list);
+
+ return (ip_list != NULL);
+}
+
+
+/****************************************************************************
+ main program
+****************************************************************************/
+int main(int argc,char *argv[])
+{
+ int opt;
+ unsigned int lookup_type = 0x0;
+ fstring lookup;
+ static bool find_master=False;
+ static bool lookup_by_ip = False;
+ poptContext pc;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "broadcast", 'B', POPT_ARG_STRING, NULL, 'B', "Specify address to use for broadcasts", "BROADCAST-ADDRESS" },
+ { "flags", 'f', POPT_ARG_NONE, NULL, 'f', "List the NMB flags returned" },
+ { "unicast", 'U', POPT_ARG_STRING, NULL, 'U', "Specify address to use for unicast" },
+ { "master-browser", 'M', POPT_ARG_NONE, NULL, 'M', "Search for a master browser" },
+ { "recursion", 'R', POPT_ARG_NONE, NULL, 'R', "Set recursion desired in package" },
+ { "status", 'S', POPT_ARG_NONE, NULL, 'S', "Lookup node status as well" },
+ { "translate", 'T', POPT_ARG_NONE, NULL, 'T', "Translate IP addresses into names" },
+ { "root-port", 'r', POPT_ARG_NONE, NULL, 'r', "Use root port 137 (Win95 only replies to this)" },
+ { "lookup-by-ip", 'A', POPT_ARG_NONE, NULL, 'A', "Do a node status on <name> as an IP Address" },
+ POPT_COMMON_SAMBA
+ POPT_COMMON_CONNECTION
+ { 0, 0, 0, 0 }
+ };
+
+ *lookup = 0;
+
+ load_case_tables();
+
+ setup_logging(argv[0],True);
+
+ pc = poptGetContext("nmblookup", argc, (const char **)argv,
+ long_options, POPT_CONTEXT_KEEP_FIRST);
+
+ poptSetOtherOptionHelp(pc, "<NODE> ...");
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'f':
+ give_flags = true;
+ break;
+ case 'M':
+ find_master = true;
+ break;
+ case 'R':
+ recursion_desired = true;
+ break;
+ case 'S':
+ find_status = true;
+ break;
+ case 'r':
+ RootPort = true;
+ break;
+ case 'A':
+ lookup_by_ip = true;
+ break;
+ case 'B':
+ if (interpret_string_addr(&bcast_addr,
+ poptGetOptArg(pc),
+ NI_NUMERICHOST)) {
+ got_bcast = True;
+ use_bcast = True;
+ }
+ break;
+ case 'U':
+ if (interpret_string_addr(&bcast_addr,
+ poptGetOptArg(pc),
+ 0)) {
+ got_bcast = True;
+ use_bcast = False;
+ }
+ break;
+ case 'T':
+ translate_addresses = !translate_addresses;
+ break;
+ }
+ }
+
+ poptGetArg(pc); /* Remove argv[0] */
+
+ if(!poptPeekArg(pc)) {
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+
+ if (!lp_load(get_dyn_CONFIGFILE(),True,False,False,True)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n",
+ get_dyn_CONFIGFILE());
+ }
+
+ load_interfaces();
+ if (!open_sockets()) {
+ return(1);
+ }
+
+ while(poptPeekArg(pc)) {
+ char *p;
+ struct in_addr ip;
+
+ fstrcpy(lookup,poptGetArg(pc));
+
+ if(lookup_by_ip) {
+ struct sockaddr_storage ss;
+ (void)interpret_addr2(&ip, lookup);
+ in_addr_to_sockaddr_storage(&ss, ip);
+ fstrcpy(lookup,"*");
+ do_node_status(ServerFD, lookup, lookup_type, &ss);
+ continue;
+ }
+
+ if (find_master) {
+ if (*lookup == '-') {
+ fstrcpy(lookup,"\01\02__MSBROWSE__\02");
+ lookup_type = 1;
+ } else {
+ lookup_type = 0x1d;
+ }
+ }
+
+ p = strchr_m(lookup,'#');
+ if (p) {
+ *p = '\0';
+ sscanf(++p,"%x",&lookup_type);
+ }
+
+ if (!query_one(lookup, lookup_type)) {
+ d_printf( "name_query failed to find name %s", lookup );
+ if( 0 != lookup_type ) {
+ d_printf( "#%02x", lookup_type );
+ }
+ d_printf( "\n" );
+ }
+ }
+
+ poptFreeContext(pc);
+ TALLOC_FREE(frame);
+ return(0);
+}
diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c
new file mode 100644
index 0000000000..4586086d73
--- /dev/null
+++ b/source3/utils/ntlm_auth.c
@@ -0,0 +1,2491 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind status program.
+
+ Copyright (C) Tim Potter 2000-2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
+ Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000
+ Copyright (C) Robert O'Callahan 2006 (added cached credential code).
+ Copyright (C) Kai Blin <kai@samba.org> 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/ntlm_auth.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+#define INITIAL_BUFFER_SIZE 300
+#define MAX_BUFFER_SIZE 630000
+
+enum stdio_helper_mode {
+ SQUID_2_4_BASIC,
+ SQUID_2_5_BASIC,
+ SQUID_2_5_NTLMSSP,
+ NTLMSSP_CLIENT_1,
+ GSS_SPNEGO,
+ GSS_SPNEGO_CLIENT,
+ NTLM_SERVER_1,
+ NTLM_CHANGE_PASSWORD_1,
+ NUM_HELPER_MODES
+};
+
+enum ntlm_auth_cli_state {
+ CLIENT_INITIAL = 0,
+ CLIENT_RESPONSE,
+ CLIENT_FINISHED,
+ CLIENT_ERROR
+};
+
+enum ntlm_auth_svr_state {
+ SERVER_INITIAL = 0,
+ SERVER_CHALLENGE,
+ SERVER_FINISHED,
+ SERVER_ERROR
+};
+
+struct ntlm_auth_state {
+ TALLOC_CTX *mem_ctx;
+ enum stdio_helper_mode helper_mode;
+ enum ntlm_auth_cli_state cli_state;
+ enum ntlm_auth_svr_state svr_state;
+ struct ntlmssp_state *ntlmssp_state;
+ uint32_t neg_flags;
+ char *want_feature_list;
+ bool have_session_key;
+ DATA_BLOB session_key;
+ DATA_BLOB initial_message;
+};
+
+typedef void (*stdio_helper_function)(struct ntlm_auth_state *state, char *buf,
+ int length);
+
+static void manage_squid_basic_request (struct ntlm_auth_state *state,
+ char *buf, int length);
+
+static void manage_squid_ntlmssp_request (struct ntlm_auth_state *state,
+ char *buf, int length);
+
+static void manage_client_ntlmssp_request (struct ntlm_auth_state *state,
+ char *buf, int length);
+
+static void manage_gss_spnego_request (struct ntlm_auth_state *state,
+ char *buf, int length);
+
+static void manage_gss_spnego_client_request (struct ntlm_auth_state *state,
+ char *buf, int length);
+
+static void manage_ntlm_server_1_request (struct ntlm_auth_state *state,
+ char *buf, int length);
+
+static void manage_ntlm_change_password_1_request(struct ntlm_auth_state *state,
+ char *buf, int length);
+
+static const struct {
+ enum stdio_helper_mode mode;
+ const char *name;
+ stdio_helper_function fn;
+} stdio_helper_protocols[] = {
+ { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
+ { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
+ { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
+ { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_client_ntlmssp_request},
+ { GSS_SPNEGO, "gss-spnego", manage_gss_spnego_request},
+ { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request},
+ { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
+ { NTLM_CHANGE_PASSWORD_1, "ntlm-change-password-1", manage_ntlm_change_password_1_request},
+ { NUM_HELPER_MODES, NULL, NULL}
+};
+
+const char *opt_username;
+const char *opt_domain;
+const char *opt_workstation;
+const char *opt_password;
+static DATA_BLOB opt_challenge;
+static DATA_BLOB opt_lm_response;
+static DATA_BLOB opt_nt_response;
+static int request_lm_key;
+static int request_user_session_key;
+static int use_cached_creds;
+
+static const char *require_membership_of;
+static const char *require_membership_of_sid;
+
+static char winbind_separator(void)
+{
+ struct winbindd_response response;
+ static bool got_sep;
+ static char sep;
+
+ if (got_sep)
+ return sep;
+
+ ZERO_STRUCT(response);
+
+ /* Send off request */
+
+ if (winbindd_request_response(WINBINDD_INFO, NULL, &response) !=
+ NSS_STATUS_SUCCESS) {
+ d_printf("could not obtain winbind separator!\n");
+ return *lp_winbind_separator();
+ }
+
+ sep = response.data.info.winbind_separator;
+ got_sep = True;
+
+ if (!sep) {
+ d_printf("winbind separator was NULL!\n");
+ return *lp_winbind_separator();
+ }
+
+ return sep;
+}
+
+const char *get_winbind_domain(void)
+{
+ struct winbindd_response response;
+
+ static fstring winbind_domain;
+ if (*winbind_domain) {
+ return winbind_domain;
+ }
+
+ ZERO_STRUCT(response);
+
+ /* Send off request */
+
+ if (winbindd_request_response(WINBINDD_DOMAIN_NAME, NULL, &response) !=
+ NSS_STATUS_SUCCESS) {
+ DEBUG(0, ("could not obtain winbind domain name!\n"));
+ return lp_workgroup();
+ }
+
+ fstrcpy(winbind_domain, response.data.domain_name);
+
+ return winbind_domain;
+
+}
+
+const char *get_winbind_netbios_name(void)
+{
+ struct winbindd_response response;
+
+ static fstring winbind_netbios_name;
+
+ if (*winbind_netbios_name) {
+ return winbind_netbios_name;
+ }
+
+ ZERO_STRUCT(response);
+
+ /* Send off request */
+
+ if (winbindd_request_response(WINBINDD_NETBIOS_NAME, NULL, &response) !=
+ NSS_STATUS_SUCCESS) {
+ DEBUG(0, ("could not obtain winbind netbios name!\n"));
+ return global_myname();
+ }
+
+ fstrcpy(winbind_netbios_name, response.data.netbios_name);
+
+ return winbind_netbios_name;
+
+}
+
+DATA_BLOB get_challenge(void)
+{
+ static DATA_BLOB chal;
+ if (opt_challenge.length)
+ return opt_challenge;
+
+ chal = data_blob(NULL, 8);
+
+ generate_random_buffer(chal.data, chal.length);
+ return chal;
+}
+
+/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
+ form DOMAIN/user into a domain and a user */
+
+static bool parse_ntlm_auth_domain_user(const char *domuser, fstring domain,
+ fstring user)
+{
+
+ char *p = strchr(domuser,winbind_separator());
+
+ if (!p) {
+ return False;
+ }
+
+ fstrcpy(user, p+1);
+ fstrcpy(domain, domuser);
+ domain[PTR_DIFF(p, domuser)] = 0;
+ strupper_m(domain);
+
+ return True;
+}
+
+static bool get_require_membership_sid(void) {
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ if (!require_membership_of) {
+ return True;
+ }
+
+ if (require_membership_of_sid) {
+ return True;
+ }
+
+ /* Otherwise, ask winbindd for the name->sid request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if (!parse_ntlm_auth_domain_user(require_membership_of,
+ request.data.name.dom_name,
+ request.data.name.name)) {
+ DEBUG(0, ("Could not parse %s into seperate domain/name parts!\n",
+ require_membership_of));
+ return False;
+ }
+
+ if (winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response) !=
+ NSS_STATUS_SUCCESS) {
+ DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
+ require_membership_of));
+ return False;
+ }
+
+ require_membership_of_sid = SMB_STRDUP(response.data.sid.sid);
+
+ if (require_membership_of_sid)
+ return True;
+
+ return False;
+}
+/* Authenticate a user with a plaintext password */
+
+static bool check_plaintext_auth(const char *user, const char *pass,
+ bool stdout_diagnostics)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+
+ if (!get_require_membership_sid()) {
+ return False;
+ }
+
+ /* Send off request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.auth.user, user);
+ fstrcpy(request.data.auth.pass, pass);
+ if (require_membership_of_sid) {
+ strlcpy(request.data.auth.require_membership_of_sid,
+ require_membership_of_sid,
+ sizeof(request.data.auth.require_membership_of_sid));
+ }
+
+ result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
+
+ /* Display response */
+
+ if (stdout_diagnostics) {
+ if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
+ d_printf("Reading winbind reply failed! (0x01)\n");
+ }
+
+ d_printf("%s: %s (0x%x)\n",
+ response.data.auth.nt_status_string,
+ response.data.auth.error_string,
+ response.data.auth.nt_status);
+ } else {
+ if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
+ DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
+ }
+
+ DEBUG(3, ("%s: %s (0x%x)\n",
+ response.data.auth.nt_status_string,
+ response.data.auth.error_string,
+ response.data.auth.nt_status));
+ }
+
+ return (result == NSS_STATUS_SUCCESS);
+}
+
+/* authenticate a user with an encrypted username/password */
+
+NTSTATUS contact_winbind_auth_crap(const char *username,
+ const char *domain,
+ const char *workstation,
+ const DATA_BLOB *challenge,
+ const DATA_BLOB *lm_response,
+ const DATA_BLOB *nt_response,
+ uint32 flags,
+ uint8 lm_key[8],
+ uint8 user_session_key[16],
+ char **error_string,
+ char **unix_name)
+{
+ NTSTATUS nt_status;
+ NSS_STATUS result;
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ if (!get_require_membership_sid()) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.flags = flags;
+
+ request.data.auth_crap.logon_parameters = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
+
+ if (require_membership_of_sid)
+ fstrcpy(request.data.auth_crap.require_membership_of_sid, require_membership_of_sid);
+
+ fstrcpy(request.data.auth_crap.user, username);
+ fstrcpy(request.data.auth_crap.domain, domain);
+
+ fstrcpy(request.data.auth_crap.workstation,
+ workstation);
+
+ memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8));
+
+ if (lm_response && lm_response->length) {
+ memcpy(request.data.auth_crap.lm_resp,
+ lm_response->data,
+ MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp)));
+ request.data.auth_crap.lm_resp_len = lm_response->length;
+ }
+
+ if (nt_response && nt_response->length) {
+ memcpy(request.data.auth_crap.nt_resp,
+ nt_response->data,
+ MIN(nt_response->length, sizeof(request.data.auth_crap.nt_resp)));
+ request.data.auth_crap.nt_resp_len = nt_response->length;
+ }
+
+ result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response);
+
+ /* Display response */
+
+ if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ if (error_string)
+ *error_string = smb_xstrdup("Reading winbind reply failed!");
+ winbindd_free_response(&response);
+ return nt_status;
+ }
+
+ nt_status = (NT_STATUS(response.data.auth.nt_status));
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ if (error_string)
+ *error_string = smb_xstrdup(response.data.auth.error_string);
+ winbindd_free_response(&response);
+ return nt_status;
+ }
+
+ if ((flags & WBFLAG_PAM_LMKEY) && lm_key) {
+ memcpy(lm_key, response.data.auth.first_8_lm_hash,
+ sizeof(response.data.auth.first_8_lm_hash));
+ }
+ if ((flags & WBFLAG_PAM_USER_SESSION_KEY) && user_session_key) {
+ memcpy(user_session_key, response.data.auth.user_session_key,
+ sizeof(response.data.auth.user_session_key));
+ }
+
+ if (flags & WBFLAG_PAM_UNIX_NAME) {
+ *unix_name = SMB_STRDUP(response.data.auth.unix_username);
+ if (!*unix_name) {
+ winbindd_free_response(&response);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ winbindd_free_response(&response);
+ return nt_status;
+}
+
+/* contact server to change user password using auth crap */
+static NTSTATUS contact_winbind_change_pswd_auth_crap(const char *username,
+ const char *domain,
+ const DATA_BLOB new_nt_pswd,
+ const DATA_BLOB old_nt_hash_enc,
+ const DATA_BLOB new_lm_pswd,
+ const DATA_BLOB old_lm_hash_enc,
+ char **error_string)
+{
+ NTSTATUS nt_status;
+ NSS_STATUS result;
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ if (!get_require_membership_sid())
+ {
+ if(error_string)
+ *error_string = smb_xstrdup("Can't get membership sid.");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if(username != NULL)
+ fstrcpy(request.data.chng_pswd_auth_crap.user, username);
+ if(domain != NULL)
+ fstrcpy(request.data.chng_pswd_auth_crap.domain,domain);
+
+ if(new_nt_pswd.length)
+ {
+ memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd, new_nt_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_nt_pswd));
+ request.data.chng_pswd_auth_crap.new_nt_pswd_len = new_nt_pswd.length;
+ }
+
+ if(old_nt_hash_enc.length)
+ {
+ memcpy(request.data.chng_pswd_auth_crap.old_nt_hash_enc, old_nt_hash_enc.data, sizeof(request.data.chng_pswd_auth_crap.old_nt_hash_enc));
+ request.data.chng_pswd_auth_crap.old_nt_hash_enc_len = old_nt_hash_enc.length;
+ }
+
+ if(new_lm_pswd.length)
+ {
+ memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd, new_lm_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_lm_pswd));
+ request.data.chng_pswd_auth_crap.new_lm_pswd_len = new_lm_pswd.length;
+ }
+
+ if(old_lm_hash_enc.length)
+ {
+ memcpy(request.data.chng_pswd_auth_crap.old_lm_hash_enc, old_lm_hash_enc.data, sizeof(request.data.chng_pswd_auth_crap.old_lm_hash_enc));
+ request.data.chng_pswd_auth_crap.old_lm_hash_enc_len = old_lm_hash_enc.length;
+ }
+
+ result = winbindd_request_response(WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, &request, &response);
+
+ /* Display response */
+
+ if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0))
+ {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ if (error_string)
+ *error_string = smb_xstrdup("Reading winbind reply failed!");
+ winbindd_free_response(&response);
+ return nt_status;
+ }
+
+ nt_status = (NT_STATUS(response.data.auth.nt_status));
+ if (!NT_STATUS_IS_OK(nt_status))
+ {
+ if (error_string)
+ *error_string = smb_xstrdup(response.data.auth.error_string);
+ winbindd_free_response(&response);
+ return nt_status;
+ }
+
+ winbindd_free_response(&response);
+
+ return nt_status;
+}
+
+static NTSTATUS winbind_pw_check(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
+{
+ static const char zeros[16] = { 0, };
+ NTSTATUS nt_status;
+ char *error_string;
+ uint8 lm_key[8];
+ uint8 user_sess_key[16];
+ char *unix_name;
+
+ nt_status = contact_winbind_auth_crap(ntlmssp_state->user, ntlmssp_state->domain,
+ ntlmssp_state->workstation,
+ &ntlmssp_state->chal,
+ &ntlmssp_state->lm_resp,
+ &ntlmssp_state->nt_resp,
+ WBFLAG_PAM_LMKEY | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_UNIX_NAME,
+ lm_key, user_sess_key,
+ &error_string, &unix_name);
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ if (memcmp(lm_key, zeros, 8) != 0) {
+ *lm_session_key = data_blob(NULL, 16);
+ memcpy(lm_session_key->data, lm_key, 8);
+ memset(lm_session_key->data+8, '\0', 8);
+ }
+
+ if (memcmp(user_sess_key, zeros, 16) != 0) {
+ *user_session_key = data_blob(user_sess_key, 16);
+ }
+ ntlmssp_state->auth_context = talloc_strdup(ntlmssp_state->mem_ctx, unix_name);
+ SAFE_FREE(unix_name);
+ } else {
+ DEBUG(NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED) ? 0 : 3,
+ ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
+ ntlmssp_state->domain, ntlmssp_state->user,
+ ntlmssp_state->workstation,
+ error_string ? error_string : "unknown error (NULL)"));
+ ntlmssp_state->auth_context = NULL;
+ }
+ return nt_status;
+}
+
+static NTSTATUS local_pw_check(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
+{
+ NTSTATUS nt_status;
+ uint8 lm_pw[16], nt_pw[16];
+
+ nt_lm_owf_gen (opt_password, nt_pw, lm_pw);
+
+ nt_status = ntlm_password_check(ntlmssp_state->mem_ctx,
+ &ntlmssp_state->chal,
+ &ntlmssp_state->lm_resp,
+ &ntlmssp_state->nt_resp,
+ NULL, NULL,
+ ntlmssp_state->user,
+ ntlmssp_state->user,
+ ntlmssp_state->domain,
+ lm_pw, nt_pw, user_session_key, lm_session_key);
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ ntlmssp_state->auth_context = talloc_asprintf(ntlmssp_state->mem_ctx,
+ "%s%c%s", ntlmssp_state->domain,
+ *lp_winbind_separator(),
+ ntlmssp_state->user);
+ } else {
+ DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
+ ntlmssp_state->domain, ntlmssp_state->user, ntlmssp_state->workstation,
+ nt_errstr(nt_status)));
+ ntlmssp_state->auth_context = NULL;
+ }
+ return nt_status;
+}
+
+static NTSTATUS ntlm_auth_start_ntlmssp_client(NTLMSSP_STATE **client_ntlmssp_state)
+{
+ NTSTATUS status;
+ if ( (opt_username == NULL) || (opt_domain == NULL) ) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ DEBUG(1, ("Need username and domain for NTLMSSP\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = ntlmssp_client_start(client_ntlmssp_state);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Could not start NTLMSSP client: %s\n",
+ nt_errstr(status)));
+ ntlmssp_end(client_ntlmssp_state);
+ return status;
+ }
+
+ status = ntlmssp_set_username(*client_ntlmssp_state, opt_username);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Could not set username: %s\n",
+ nt_errstr(status)));
+ ntlmssp_end(client_ntlmssp_state);
+ return status;
+ }
+
+ status = ntlmssp_set_domain(*client_ntlmssp_state, opt_domain);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Could not set domain: %s\n",
+ nt_errstr(status)));
+ ntlmssp_end(client_ntlmssp_state);
+ return status;
+ }
+
+ if (opt_password) {
+ status = ntlmssp_set_password(*client_ntlmssp_state, opt_password);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Could not set password: %s\n",
+ nt_errstr(status)));
+ ntlmssp_end(client_ntlmssp_state);
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ntlm_auth_start_ntlmssp_server(NTLMSSP_STATE **ntlmssp_state)
+{
+ NTSTATUS status = ntlmssp_server_start(ntlmssp_state);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Could not start NTLMSSP server: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ /* Have we been given a local password, or should we ask winbind? */
+ if (opt_password) {
+ (*ntlmssp_state)->check_password = local_pw_check;
+ (*ntlmssp_state)->get_domain = lp_workgroup;
+ (*ntlmssp_state)->get_global_myname = global_myname;
+ } else {
+ (*ntlmssp_state)->check_password = winbind_pw_check;
+ (*ntlmssp_state)->get_domain = get_winbind_domain;
+ (*ntlmssp_state)->get_global_myname = get_winbind_netbios_name;
+ }
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Used by firefox to drive NTLM auth to IIS servers.
+*******************************************************************/
+
+static NTSTATUS do_ccache_ntlm_auth(DATA_BLOB initial_msg, DATA_BLOB challenge_msg,
+ DATA_BLOB *reply)
+{
+ struct winbindd_request wb_request;
+ struct winbindd_response wb_response;
+ NSS_STATUS result;
+
+ /* get winbindd to do the ntlmssp step on our behalf */
+ ZERO_STRUCT(wb_request);
+ ZERO_STRUCT(wb_response);
+
+ fstr_sprintf(wb_request.data.ccache_ntlm_auth.user,
+ "%s%c%s", opt_domain, winbind_separator(), opt_username);
+ wb_request.data.ccache_ntlm_auth.uid = geteuid();
+ wb_request.data.ccache_ntlm_auth.initial_blob_len = initial_msg.length;
+ wb_request.data.ccache_ntlm_auth.challenge_blob_len = challenge_msg.length;
+ wb_request.extra_len = initial_msg.length + challenge_msg.length;
+
+ if (wb_request.extra_len > 0) {
+ wb_request.extra_data.data = SMB_MALLOC_ARRAY(char, wb_request.extra_len);
+ if (wb_request.extra_data.data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ memcpy(wb_request.extra_data.data, initial_msg.data, initial_msg.length);
+ memcpy(wb_request.extra_data.data + initial_msg.length,
+ challenge_msg.data, challenge_msg.length);
+ }
+
+ result = winbindd_request_response(WINBINDD_CCACHE_NTLMAUTH, &wb_request, &wb_response);
+ SAFE_FREE(wb_request.extra_data.data);
+
+ if (result != NSS_STATUS_SUCCESS) {
+ winbindd_free_response(&wb_response);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (reply) {
+ *reply = data_blob(wb_response.extra_data.data,
+ wb_response.data.ccache_ntlm_auth.auth_blob_len);
+ if (wb_response.data.ccache_ntlm_auth.auth_blob_len > 0 &&
+ reply->data == NULL) {
+ winbindd_free_response(&wb_response);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ winbindd_free_response(&wb_response);
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state,
+ char *buf, int length)
+{
+ DATA_BLOB request, reply;
+ NTSTATUS nt_status;
+
+ if (strlen(buf) < 2) {
+ DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
+ x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
+ return;
+ }
+
+ if (strlen(buf) > 3) {
+ if(strncmp(buf, "SF ", 3) == 0){
+ DEBUG(10, ("Setting flags to negotioate\n"));
+ TALLOC_FREE(state->want_feature_list);
+ state->want_feature_list = talloc_strdup(state->mem_ctx,
+ buf+3);
+ x_fprintf(x_stdout, "OK\n");
+ return;
+ }
+ request = base64_decode_data_blob(buf + 3);
+ } else {
+ request = data_blob_null;
+ }
+
+ if ((strncmp(buf, "PW ", 3) == 0)) {
+ /* The calling application wants us to use a local password
+ * (rather than winbindd) */
+
+ opt_password = SMB_STRNDUP((const char *)request.data,
+ request.length);
+
+ if (opt_password == NULL) {
+ DEBUG(1, ("Out of memory\n"));
+ x_fprintf(x_stdout, "BH Out of memory\n");
+ data_blob_free(&request);
+ return;
+ }
+
+ x_fprintf(x_stdout, "OK\n");
+ data_blob_free(&request);
+ return;
+ }
+
+ if (strncmp(buf, "YR", 2) == 0) {
+ if (state->ntlmssp_state)
+ ntlmssp_end(&state->ntlmssp_state);
+ state->svr_state = SERVER_INITIAL;
+ } else if (strncmp(buf, "KK", 2) == 0) {
+ /* No special preprocessing required */
+ } else if (strncmp(buf, "GF", 2) == 0) {
+ DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
+
+ if (state->svr_state == SERVER_FINISHED) {
+ x_fprintf(x_stdout, "GF 0x%08x\n", state->neg_flags);
+ }
+ else {
+ x_fprintf(x_stdout, "BH\n");
+ }
+ data_blob_free(&request);
+ return;
+ } else if (strncmp(buf, "GK", 2) == 0) {
+ DEBUG(10, ("Requested NTLMSSP session key\n"));
+ if(state->have_session_key) {
+ char *key64 = base64_encode_data_blob(state->mem_ctx,
+ state->session_key);
+ x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>");
+ TALLOC_FREE(key64);
+ } else {
+ x_fprintf(x_stdout, "BH\n");
+ }
+
+ data_blob_free(&request);
+ return;
+ } else {
+ DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
+ x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
+ return;
+ }
+
+ if (!state->ntlmssp_state) {
+ nt_status = ntlm_auth_start_ntlmssp_server(
+ &state->ntlmssp_state);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
+ return;
+ }
+ ntlmssp_want_feature_list(state->ntlmssp_state,
+ state->want_feature_list);
+ }
+
+ DEBUG(10, ("got NTLMSSP packet:\n"));
+ dump_data(10, request.data, request.length);
+
+ nt_status = ntlmssp_update(state->ntlmssp_state, request, &reply);
+
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ char *reply_base64 = base64_encode_data_blob(state->mem_ctx,
+ reply);
+ x_fprintf(x_stdout, "TT %s\n", reply_base64);
+ TALLOC_FREE(reply_base64);
+ data_blob_free(&reply);
+ state->svr_state = SERVER_CHALLENGE;
+ DEBUG(10, ("NTLMSSP challenge\n"));
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
+ x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
+ DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
+
+ ntlmssp_end(&state->ntlmssp_state);
+ } else if (!NT_STATUS_IS_OK(nt_status)) {
+ x_fprintf(x_stdout, "NA %s\n", nt_errstr(nt_status));
+ DEBUG(10, ("NTLMSSP %s\n", nt_errstr(nt_status)));
+ } else {
+ x_fprintf(x_stdout, "AF %s\n",
+ (char *)state->ntlmssp_state->auth_context);
+ DEBUG(10, ("NTLMSSP OK!\n"));
+
+ if(state->have_session_key)
+ data_blob_free(&state->session_key);
+ state->session_key = data_blob(
+ state->ntlmssp_state->session_key.data,
+ state->ntlmssp_state->session_key.length);
+ state->neg_flags = state->ntlmssp_state->neg_flags;
+ state->have_session_key = true;
+ state->svr_state = SERVER_FINISHED;
+ }
+
+ data_blob_free(&request);
+}
+
+static void manage_client_ntlmssp_request(struct ntlm_auth_state *state,
+ char *buf, int length)
+{
+ DATA_BLOB request, reply;
+ NTSTATUS nt_status;
+
+ if (!opt_username || !*opt_username) {
+ x_fprintf(x_stderr, "username must be specified!\n\n");
+ exit(1);
+ }
+
+ if (strlen(buf) < 2) {
+ DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
+ x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
+ return;
+ }
+
+ if (strlen(buf) > 3) {
+ if(strncmp(buf, "SF ", 3) == 0) {
+ DEBUG(10, ("Looking for flags to negotiate\n"));
+ talloc_free(state->want_feature_list);
+ state->want_feature_list = talloc_strdup(state->mem_ctx,
+ buf+3);
+ x_fprintf(x_stdout, "OK\n");
+ return;
+ }
+ request = base64_decode_data_blob(buf + 3);
+ } else {
+ request = data_blob_null;
+ }
+
+ if (strncmp(buf, "PW ", 3) == 0) {
+ /* We asked for a password and obviously got it :-) */
+
+ opt_password = SMB_STRNDUP((const char *)request.data,
+ request.length);
+
+ if (opt_password == NULL) {
+ DEBUG(1, ("Out of memory\n"));
+ x_fprintf(x_stdout, "BH Out of memory\n");
+ data_blob_free(&request);
+ return;
+ }
+
+ x_fprintf(x_stdout, "OK\n");
+ data_blob_free(&request);
+ return;
+ }
+
+ if (!state->ntlmssp_state && use_cached_creds) {
+ /* check whether cached credentials are usable. */
+ DATA_BLOB empty_blob = data_blob_null;
+
+ nt_status = do_ccache_ntlm_auth(empty_blob, empty_blob, NULL);
+ if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ /* failed to use cached creds */
+ use_cached_creds = False;
+ }
+ }
+
+ if (opt_password == NULL && !use_cached_creds) {
+ /* Request a password from the calling process. After
+ sending it, the calling process should retry asking for the
+ negotiate. */
+
+ DEBUG(10, ("Requesting password\n"));
+ x_fprintf(x_stdout, "PW\n");
+ return;
+ }
+
+ if (strncmp(buf, "YR", 2) == 0) {
+ if (state->ntlmssp_state)
+ ntlmssp_end(&state->ntlmssp_state);
+ state->cli_state = CLIENT_INITIAL;
+ } else if (strncmp(buf, "TT", 2) == 0) {
+ /* No special preprocessing required */
+ } else if (strncmp(buf, "GF", 2) == 0) {
+ DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
+
+ if(state->cli_state == CLIENT_FINISHED) {
+ x_fprintf(x_stdout, "GF 0x%08x\n", state->neg_flags);
+ }
+ else {
+ x_fprintf(x_stdout, "BH\n");
+ }
+
+ data_blob_free(&request);
+ return;
+ } else if (strncmp(buf, "GK", 2) == 0 ) {
+ DEBUG(10, ("Requested session key\n"));
+
+ if(state->cli_state == CLIENT_FINISHED) {
+ char *key64 = base64_encode_data_blob(state->mem_ctx,
+ state->session_key);
+ x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>");
+ TALLOC_FREE(key64);
+ }
+ else {
+ x_fprintf(x_stdout, "BH\n");
+ }
+
+ data_blob_free(&request);
+ return;
+ } else {
+ DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
+ x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
+ return;
+ }
+
+ if (!state->ntlmssp_state) {
+ nt_status = ntlm_auth_start_ntlmssp_client(
+ &state->ntlmssp_state);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
+ return;
+ }
+ ntlmssp_want_feature_list(state->ntlmssp_state,
+ state->want_feature_list);
+ state->initial_message = data_blob_null;
+ }
+
+ DEBUG(10, ("got NTLMSSP packet:\n"));
+ dump_data(10, request.data, request.length);
+
+ if (use_cached_creds && !opt_password &&
+ (state->cli_state == CLIENT_RESPONSE)) {
+ nt_status = do_ccache_ntlm_auth(state->initial_message, request,
+ &reply);
+ } else {
+ nt_status = ntlmssp_update(state->ntlmssp_state, request,
+ &reply);
+ }
+
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ char *reply_base64 = base64_encode_data_blob(state->mem_ctx,
+ reply);
+ if (state->cli_state == CLIENT_INITIAL) {
+ x_fprintf(x_stdout, "YR %s\n", reply_base64);
+ state->initial_message = reply;
+ state->cli_state = CLIENT_RESPONSE;
+ } else {
+ x_fprintf(x_stdout, "KK %s\n", reply_base64);
+ data_blob_free(&reply);
+ }
+ TALLOC_FREE(reply_base64);
+ DEBUG(10, ("NTLMSSP challenge\n"));
+ } else if (NT_STATUS_IS_OK(nt_status)) {
+ char *reply_base64 = base64_encode_data_blob(talloc_tos(),
+ reply);
+ x_fprintf(x_stdout, "AF %s\n", reply_base64);
+ TALLOC_FREE(reply_base64);
+
+ if(state->have_session_key)
+ data_blob_free(&state->session_key);
+
+ state->session_key = data_blob(
+ state->ntlmssp_state->session_key.data,
+ state->ntlmssp_state->session_key.length);
+ state->neg_flags = state->ntlmssp_state->neg_flags;
+ state->have_session_key = true;
+
+ DEBUG(10, ("NTLMSSP OK!\n"));
+ state->cli_state = CLIENT_FINISHED;
+ if (state->ntlmssp_state)
+ ntlmssp_end(&state->ntlmssp_state);
+ } else {
+ x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
+ DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
+ state->cli_state = CLIENT_ERROR;
+ if (state->ntlmssp_state)
+ ntlmssp_end(&state->ntlmssp_state);
+ }
+
+ data_blob_free(&request);
+}
+
+static void manage_squid_basic_request(struct ntlm_auth_state *state,
+ char *buf, int length)
+{
+ char *user, *pass;
+ user=buf;
+
+ pass=(char *)memchr(buf,' ',length);
+ if (!pass) {
+ DEBUG(2, ("Password not found. Denying access\n"));
+ x_fprintf(x_stdout, "ERR\n");
+ return;
+ }
+ *pass='\0';
+ pass++;
+
+ if (state->helper_mode == SQUID_2_5_BASIC) {
+ rfc1738_unescape(user);
+ rfc1738_unescape(pass);
+ }
+
+ if (check_plaintext_auth(user, pass, False)) {
+ x_fprintf(x_stdout, "OK\n");
+ } else {
+ x_fprintf(x_stdout, "ERR\n");
+ }
+}
+
+static void offer_gss_spnego_mechs(void) {
+
+ DATA_BLOB token;
+ SPNEGO_DATA spnego;
+ ssize_t len;
+ char *reply_base64;
+ TALLOC_CTX *ctx = talloc_tos();
+ char *principal;
+ char *myname_lower;
+
+ ZERO_STRUCT(spnego);
+
+ myname_lower = talloc_strdup(ctx, global_myname());
+ if (!myname_lower) {
+ return;
+ }
+ strlower_m(myname_lower);
+
+ principal = talloc_asprintf(ctx, "%s$@%s", myname_lower, lp_realm());
+ if (!principal) {
+ return;
+ }
+
+ /* Server negTokenInit (mech offerings) */
+ spnego.type = SPNEGO_NEG_TOKEN_INIT;
+ spnego.negTokenInit.mechTypes = SMB_XMALLOC_ARRAY(const char *, 2);
+#ifdef HAVE_KRB5
+ spnego.negTokenInit.mechTypes[0] = smb_xstrdup(OID_KERBEROS5_OLD);
+ spnego.negTokenInit.mechTypes[1] = smb_xstrdup(OID_NTLMSSP);
+ spnego.negTokenInit.mechTypes[2] = NULL;
+#else
+ spnego.negTokenInit.mechTypes[0] = smb_xstrdup(OID_NTLMSSP);
+ spnego.negTokenInit.mechTypes[1] = NULL;
+#endif
+
+
+ spnego.negTokenInit.mechListMIC = data_blob(principal,
+ strlen(principal));
+
+ len = write_spnego_data(&token, &spnego);
+ free_spnego_data(&spnego);
+
+ if (len == -1) {
+ DEBUG(1, ("Could not write SPNEGO data blob\n"));
+ x_fprintf(x_stdout, "BH Could not write SPNEGO data blob\n");
+ return;
+ }
+
+ reply_base64 = base64_encode_data_blob(talloc_tos(), token);
+ x_fprintf(x_stdout, "TT %s *\n", reply_base64);
+
+ TALLOC_FREE(reply_base64);
+ data_blob_free(&token);
+ DEBUG(10, ("sent SPNEGO negTokenInit\n"));
+ return;
+}
+
+static void manage_gss_spnego_request(struct ntlm_auth_state *state,
+ char *buf, int length)
+{
+ static NTLMSSP_STATE *ntlmssp_state = NULL;
+ SPNEGO_DATA request, response;
+ DATA_BLOB token;
+ NTSTATUS status;
+ ssize_t len;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ char *user = NULL;
+ char *domain = NULL;
+
+ const char *reply_code;
+ char *reply_base64;
+ char *reply_argument = NULL;
+
+ if (strlen(buf) < 2) {
+ DEBUG(1, ("SPENGO query [%s] invalid", buf));
+ x_fprintf(x_stdout, "BH SPENGO query invalid\n");
+ return;
+ }
+
+ if (strncmp(buf, "YR", 2) == 0) {
+ if (ntlmssp_state)
+ ntlmssp_end(&ntlmssp_state);
+ } else if (strncmp(buf, "KK", 2) == 0) {
+ ;
+ } else {
+ DEBUG(1, ("SPENGO query [%s] invalid", buf));
+ x_fprintf(x_stdout, "BH SPENGO query invalid\n");
+ return;
+ }
+
+ if ( (strlen(buf) == 2)) {
+
+ /* no client data, get the negTokenInit offering
+ mechanisms */
+
+ offer_gss_spnego_mechs();
+ return;
+ }
+
+ /* All subsequent requests have a blob. This might be negTokenInit or negTokenTarg */
+
+ if (strlen(buf) <= 3) {
+ DEBUG(1, ("GSS-SPNEGO query [%s] invalid\n", buf));
+ x_fprintf(x_stdout, "BH GSS-SPNEGO query invalid\n");
+ return;
+ }
+
+ token = base64_decode_data_blob(buf + 3);
+ len = read_spnego_data(token, &request);
+ data_blob_free(&token);
+
+ if (len == -1) {
+ DEBUG(1, ("GSS-SPNEGO query [%s] invalid", buf));
+ x_fprintf(x_stdout, "BH GSS-SPNEGO query invalid\n");
+ return;
+ }
+
+ if (request.type == SPNEGO_NEG_TOKEN_INIT) {
+
+ /* Second request from Client. This is where the
+ client offers its mechanism to use. */
+
+ if ( (request.negTokenInit.mechTypes == NULL) ||
+ (request.negTokenInit.mechTypes[0] == NULL) ) {
+ DEBUG(1, ("Client did not offer any mechanism"));
+ x_fprintf(x_stdout, "BH Client did not offer any "
+ "mechanism\n");
+ return;
+ }
+
+ status = NT_STATUS_UNSUCCESSFUL;
+ if (strcmp(request.negTokenInit.mechTypes[0], OID_NTLMSSP) == 0) {
+
+ if ( request.negTokenInit.mechToken.data == NULL ) {
+ DEBUG(1, ("Client did not provide NTLMSSP data\n"));
+ x_fprintf(x_stdout, "BH Client did not provide "
+ "NTLMSSP data\n");
+ return;
+ }
+
+ if ( ntlmssp_state != NULL ) {
+ DEBUG(1, ("Client wants a new NTLMSSP challenge, but "
+ "already got one\n"));
+ x_fprintf(x_stdout, "BH Client wants a new "
+ "NTLMSSP challenge, but "
+ "already got one\n");
+ ntlmssp_end(&ntlmssp_state);
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_server(&ntlmssp_state))) {
+ x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
+ return;
+ }
+
+ DEBUG(10, ("got NTLMSSP packet:\n"));
+ dump_data(10, request.negTokenInit.mechToken.data,
+ request.negTokenInit.mechToken.length);
+
+ response.type = SPNEGO_NEG_TOKEN_TARG;
+ response.negTokenTarg.supportedMech = SMB_STRDUP(OID_NTLMSSP);
+ response.negTokenTarg.mechListMIC = data_blob_null;
+
+ status = ntlmssp_update(ntlmssp_state,
+ request.negTokenInit.mechToken,
+ &response.negTokenTarg.responseToken);
+ }
+
+#ifdef HAVE_KRB5
+ if (strcmp(request.negTokenInit.mechTypes[0], OID_KERBEROS5_OLD) == 0) {
+
+ TALLOC_CTX *mem_ctx = talloc_init("manage_gss_spnego_request");
+ char *principal;
+ DATA_BLOB ap_rep;
+ DATA_BLOB session_key;
+ struct PAC_DATA *pac_data = NULL;
+
+ if ( request.negTokenInit.mechToken.data == NULL ) {
+ DEBUG(1, ("Client did not provide Kerberos data\n"));
+ x_fprintf(x_stdout, "BH Client did not provide "
+ "Kerberos data\n");
+ return;
+ }
+
+ response.type = SPNEGO_NEG_TOKEN_TARG;
+ response.negTokenTarg.supportedMech = SMB_STRDUP(OID_KERBEROS5_OLD);
+ response.negTokenTarg.mechListMIC = data_blob_null;
+ response.negTokenTarg.responseToken = data_blob_null;
+
+ status = ads_verify_ticket(mem_ctx, lp_realm(), 0,
+ &request.negTokenInit.mechToken,
+ &principal, &pac_data, &ap_rep,
+ &session_key, True);
+
+ talloc_destroy(mem_ctx);
+
+ /* Now in "principal" we have the name we are
+ authenticated as. */
+
+ if (NT_STATUS_IS_OK(status)) {
+
+ domain = strchr_m(principal, '@');
+
+ if (domain == NULL) {
+ DEBUG(1, ("Did not get a valid principal "
+ "from ads_verify_ticket\n"));
+ x_fprintf(x_stdout, "BH Did not get a "
+ "valid principal from "
+ "ads_verify_ticket\n");
+ return;
+ }
+
+ *domain++ = '\0';
+ domain = SMB_STRDUP(domain);
+ user = SMB_STRDUP(principal);
+
+ data_blob_free(&ap_rep);
+
+ SAFE_FREE(principal);
+ }
+ }
+#endif
+
+ } else {
+
+ if ( (request.negTokenTarg.supportedMech == NULL) ||
+ ( strcmp(request.negTokenTarg.supportedMech, OID_NTLMSSP) != 0 ) ) {
+ /* Kerberos should never send a negTokenTarg, OID_NTLMSSP
+ is the only one we support that sends this stuff */
+ DEBUG(1, ("Got a negTokenTarg for something non-NTLMSSP: %s\n",
+ request.negTokenTarg.supportedMech));
+ x_fprintf(x_stdout, "BH Got a negTokenTarg for "
+ "something non-NTLMSSP\n");
+ return;
+ }
+
+ if (request.negTokenTarg.responseToken.data == NULL) {
+ DEBUG(1, ("Got a negTokenTarg without a responseToken!\n"));
+ x_fprintf(x_stdout, "BH Got a negTokenTarg without a "
+ "responseToken!\n");
+ return;
+ }
+
+ status = ntlmssp_update(ntlmssp_state,
+ request.negTokenTarg.responseToken,
+ &response.negTokenTarg.responseToken);
+
+ response.type = SPNEGO_NEG_TOKEN_TARG;
+ response.negTokenTarg.supportedMech = SMB_STRDUP(OID_NTLMSSP);
+ response.negTokenTarg.mechListMIC = data_blob_null;
+
+ if (NT_STATUS_IS_OK(status)) {
+ user = SMB_STRDUP(ntlmssp_state->user);
+ domain = SMB_STRDUP(ntlmssp_state->domain);
+ ntlmssp_end(&ntlmssp_state);
+ }
+ }
+
+ free_spnego_data(&request);
+
+ if (NT_STATUS_IS_OK(status)) {
+ response.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
+ reply_code = "AF";
+ reply_argument = talloc_asprintf(ctx, "%s\\%s", domain, user);
+ } else if (NT_STATUS_EQUAL(status,
+ NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ response.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
+ reply_code = "TT";
+ reply_argument = talloc_strdup(ctx, "*");
+ } else {
+ response.negTokenTarg.negResult = SPNEGO_REJECT;
+ reply_code = "NA";
+ reply_argument = talloc_strdup(ctx, nt_errstr(status));
+ }
+
+ if (!reply_argument) {
+ DEBUG(1, ("Could not write SPNEGO data blob\n"));
+ x_fprintf(x_stdout, "BH Could not write SPNEGO data blob\n");
+ return;
+ }
+
+ SAFE_FREE(user);
+ SAFE_FREE(domain);
+
+ len = write_spnego_data(&token, &response);
+ free_spnego_data(&response);
+
+ if (len == -1) {
+ DEBUG(1, ("Could not write SPNEGO data blob\n"));
+ x_fprintf(x_stdout, "BH Could not write SPNEGO data blob\n");
+ return;
+ }
+
+ reply_base64 = base64_encode_data_blob(talloc_tos(), token);
+
+ x_fprintf(x_stdout, "%s %s %s\n",
+ reply_code, reply_base64, reply_argument);
+
+ TALLOC_FREE(reply_base64);
+ data_blob_free(&token);
+
+ return;
+}
+
+static NTLMSSP_STATE *client_ntlmssp_state = NULL;
+
+static bool manage_client_ntlmssp_init(SPNEGO_DATA spnego)
+{
+ NTSTATUS status;
+ DATA_BLOB null_blob = data_blob_null;
+ DATA_BLOB to_server;
+ char *to_server_base64;
+ const char *my_mechs[] = {OID_NTLMSSP, NULL};
+
+ DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
+
+ if (client_ntlmssp_state != NULL) {
+ DEBUG(1, ("Request for initial SPNEGO request where "
+ "we already have a state\n"));
+ return False;
+ }
+
+ if (!client_ntlmssp_state) {
+ if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state))) {
+ x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
+ return False;
+ }
+ }
+
+
+ if (opt_password == NULL) {
+
+ /* Request a password from the calling process. After
+ sending it, the calling process should retry with
+ the negTokenInit. */
+
+ DEBUG(10, ("Requesting password\n"));
+ x_fprintf(x_stdout, "PW\n");
+ return True;
+ }
+
+ spnego.type = SPNEGO_NEG_TOKEN_INIT;
+ spnego.negTokenInit.mechTypes = my_mechs;
+ spnego.negTokenInit.reqFlags = 0;
+ spnego.negTokenInit.mechListMIC = null_blob;
+
+ status = ntlmssp_update(client_ntlmssp_state, null_blob,
+ &spnego.negTokenInit.mechToken);
+
+ if ( !(NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) ||
+ NT_STATUS_IS_OK(status)) ) {
+ DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
+ nt_errstr(status)));
+ ntlmssp_end(&client_ntlmssp_state);
+ return False;
+ }
+
+ write_spnego_data(&to_server, &spnego);
+ data_blob_free(&spnego.negTokenInit.mechToken);
+
+ to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
+ data_blob_free(&to_server);
+ x_fprintf(x_stdout, "KK %s\n", to_server_base64);
+ TALLOC_FREE(to_server_base64);
+ return True;
+}
+
+static void manage_client_ntlmssp_targ(SPNEGO_DATA spnego)
+{
+ NTSTATUS status;
+ DATA_BLOB null_blob = data_blob_null;
+ DATA_BLOB request;
+ DATA_BLOB to_server;
+ char *to_server_base64;
+
+ DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
+
+ if (client_ntlmssp_state == NULL) {
+ DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
+ x_fprintf(x_stdout, "BH Got NTLMSSP tArg without a client state\n");
+ return;
+ }
+
+ if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
+ x_fprintf(x_stdout, "NA\n");
+ ntlmssp_end(&client_ntlmssp_state);
+ return;
+ }
+
+ if (spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
+ x_fprintf(x_stdout, "AF\n");
+ ntlmssp_end(&client_ntlmssp_state);
+ return;
+ }
+
+ status = ntlmssp_update(client_ntlmssp_state,
+ spnego.negTokenTarg.responseToken,
+ &request);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED from "
+ "ntlmssp_client_update, got: %s\n",
+ nt_errstr(status)));
+ x_fprintf(x_stdout, "BH Expected MORE_PROCESSING_REQUIRED from "
+ "ntlmssp_client_update\n");
+ data_blob_free(&request);
+ ntlmssp_end(&client_ntlmssp_state);
+ return;
+ }
+
+ spnego.type = SPNEGO_NEG_TOKEN_TARG;
+ spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
+ spnego.negTokenTarg.supportedMech = (char *)OID_NTLMSSP;
+ spnego.negTokenTarg.responseToken = request;
+ spnego.negTokenTarg.mechListMIC = null_blob;
+
+ write_spnego_data(&to_server, &spnego);
+ data_blob_free(&request);
+
+ to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
+ data_blob_free(&to_server);
+ x_fprintf(x_stdout, "KK %s\n", to_server_base64);
+ TALLOC_FREE(to_server_base64);
+ return;
+}
+
+#ifdef HAVE_KRB5
+
+static bool manage_client_krb5_init(SPNEGO_DATA spnego)
+{
+ char *principal;
+ DATA_BLOB tkt, to_server;
+ DATA_BLOB session_key_krb5 = data_blob_null;
+ SPNEGO_DATA reply;
+ char *reply_base64;
+ int retval;
+
+ const char *my_mechs[] = {OID_KERBEROS5_OLD, NULL};
+ ssize_t len;
+
+ if ( (spnego.negTokenInit.mechListMIC.data == NULL) ||
+ (spnego.negTokenInit.mechListMIC.length == 0) ) {
+ DEBUG(1, ("Did not get a principal for krb5\n"));
+ return False;
+ }
+
+ principal = (char *)SMB_MALLOC(
+ spnego.negTokenInit.mechListMIC.length+1);
+
+ if (principal == NULL) {
+ DEBUG(1, ("Could not malloc principal\n"));
+ return False;
+ }
+
+ memcpy(principal, spnego.negTokenInit.mechListMIC.data,
+ spnego.negTokenInit.mechListMIC.length);
+ principal[spnego.negTokenInit.mechListMIC.length] = '\0';
+
+ retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL, NULL);
+
+ if (retval) {
+ char *user = NULL;
+
+ /* Let's try to first get the TGT, for that we need a
+ password. */
+
+ if (opt_password == NULL) {
+ DEBUG(10, ("Requesting password\n"));
+ x_fprintf(x_stdout, "PW\n");
+ return True;
+ }
+
+ user = talloc_asprintf(talloc_tos(), "%s@%s", opt_username, opt_domain);
+ if (!user) {
+ return false;
+ }
+
+ if ((retval = kerberos_kinit_password(user, opt_password, 0, NULL))) {
+ DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval)));
+ return False;
+ }
+
+ retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL, NULL);
+
+ if (retval) {
+ DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval)));
+ return False;
+ }
+ }
+
+ data_blob_free(&session_key_krb5);
+
+ ZERO_STRUCT(reply);
+
+ reply.type = SPNEGO_NEG_TOKEN_INIT;
+ reply.negTokenInit.mechTypes = my_mechs;
+ reply.negTokenInit.reqFlags = 0;
+ reply.negTokenInit.mechToken = tkt;
+ reply.negTokenInit.mechListMIC = data_blob_null;
+
+ len = write_spnego_data(&to_server, &reply);
+ data_blob_free(&tkt);
+
+ if (len == -1) {
+ DEBUG(1, ("Could not write SPNEGO data blob\n"));
+ return False;
+ }
+
+ reply_base64 = base64_encode_data_blob(talloc_tos(), to_server);
+ x_fprintf(x_stdout, "KK %s *\n", reply_base64);
+
+ TALLOC_FREE(reply_base64);
+ data_blob_free(&to_server);
+ DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
+ return True;
+}
+
+static void manage_client_krb5_targ(SPNEGO_DATA spnego)
+{
+ switch (spnego.negTokenTarg.negResult) {
+ case SPNEGO_ACCEPT_INCOMPLETE:
+ DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
+ x_fprintf(x_stdout, "BH Got a Kerberos negTokenTarg with "
+ "ACCEPT_INCOMPLETE\n");
+ break;
+ case SPNEGO_ACCEPT_COMPLETED:
+ DEBUG(10, ("Accept completed\n"));
+ x_fprintf(x_stdout, "AF\n");
+ break;
+ case SPNEGO_REJECT:
+ DEBUG(10, ("Rejected\n"));
+ x_fprintf(x_stdout, "NA\n");
+ break;
+ default:
+ DEBUG(1, ("Got an invalid negTokenTarg\n"));
+ x_fprintf(x_stdout, "AF\n");
+ }
+}
+
+#endif
+
+static void manage_gss_spnego_client_request(struct ntlm_auth_state *state,
+ char *buf, int length)
+{
+ DATA_BLOB request;
+ SPNEGO_DATA spnego;
+ ssize_t len;
+
+ if (!opt_username || !*opt_username) {
+ x_fprintf(x_stderr, "username must be specified!\n\n");
+ exit(1);
+ }
+
+ if (strlen(buf) <= 3) {
+ DEBUG(1, ("SPNEGO query [%s] too short\n", buf));
+ x_fprintf(x_stdout, "BH SPNEGO query too short\n");
+ return;
+ }
+
+ request = base64_decode_data_blob(buf+3);
+
+ if (strncmp(buf, "PW ", 3) == 0) {
+
+ /* We asked for a password and obviously got it :-) */
+
+ opt_password = SMB_STRNDUP((const char *)request.data, request.length);
+
+ if (opt_password == NULL) {
+ DEBUG(1, ("Out of memory\n"));
+ x_fprintf(x_stdout, "BH Out of memory\n");
+ data_blob_free(&request);
+ return;
+ }
+
+ x_fprintf(x_stdout, "OK\n");
+ data_blob_free(&request);
+ return;
+ }
+
+ if ( (strncmp(buf, "TT ", 3) != 0) &&
+ (strncmp(buf, "AF ", 3) != 0) &&
+ (strncmp(buf, "NA ", 3) != 0) ) {
+ DEBUG(1, ("SPNEGO request [%s] invalid\n", buf));
+ x_fprintf(x_stdout, "BH SPNEGO request invalid\n");
+ data_blob_free(&request);
+ return;
+ }
+
+ /* So we got a server challenge to generate a SPNEGO
+ client-to-server request... */
+
+ len = read_spnego_data(request, &spnego);
+ data_blob_free(&request);
+
+ if (len == -1) {
+ DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf));
+ x_fprintf(x_stdout, "BH Could not read SPNEGO data\n");
+ return;
+ }
+
+ if (spnego.type == SPNEGO_NEG_TOKEN_INIT) {
+
+ /* The server offers a list of mechanisms */
+
+ const char **mechType = (const char **)spnego.negTokenInit.mechTypes;
+
+ while (*mechType != NULL) {
+
+#ifdef HAVE_KRB5
+ if ( (strcmp(*mechType, OID_KERBEROS5_OLD) == 0) ||
+ (strcmp(*mechType, OID_KERBEROS5) == 0) ) {
+ if (manage_client_krb5_init(spnego))
+ goto out;
+ }
+#endif
+
+ if (strcmp(*mechType, OID_NTLMSSP) == 0) {
+ if (manage_client_ntlmssp_init(spnego))
+ goto out;
+ }
+
+ mechType++;
+ }
+
+ DEBUG(1, ("Server offered no compatible mechanism\n"));
+ x_fprintf(x_stdout, "BH Server offered no compatible mechanism\n");
+ return;
+ }
+
+ if (spnego.type == SPNEGO_NEG_TOKEN_TARG) {
+
+ if (spnego.negTokenTarg.supportedMech == NULL) {
+ /* On accept/reject Windows does not send the
+ mechanism anymore. Handle that here and
+ shut down the mechanisms. */
+
+ switch (spnego.negTokenTarg.negResult) {
+ case SPNEGO_ACCEPT_COMPLETED:
+ x_fprintf(x_stdout, "AF\n");
+ break;
+ case SPNEGO_REJECT:
+ x_fprintf(x_stdout, "NA\n");
+ break;
+ default:
+ DEBUG(1, ("Got a negTokenTarg with no mech and an "
+ "unknown negResult: %d\n",
+ spnego.negTokenTarg.negResult));
+ x_fprintf(x_stdout, "BH Got a negTokenTarg with"
+ " no mech and an unknown "
+ "negResult\n");
+ }
+
+ ntlmssp_end(&client_ntlmssp_state);
+ goto out;
+ }
+
+ if (strcmp(spnego.negTokenTarg.supportedMech,
+ OID_NTLMSSP) == 0) {
+ manage_client_ntlmssp_targ(spnego);
+ goto out;
+ }
+
+#if HAVE_KRB5
+ if (strcmp(spnego.negTokenTarg.supportedMech,
+ OID_KERBEROS5_OLD) == 0) {
+ manage_client_krb5_targ(spnego);
+ goto out;
+ }
+#endif
+
+ }
+
+ DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf));
+ x_fprintf(x_stdout, "BH Got an SPNEGO token I could not handle\n");
+ return;
+
+ out:
+ free_spnego_data(&spnego);
+ return;
+}
+
+static void manage_ntlm_server_1_request(struct ntlm_auth_state *state,
+ char *buf, int length)
+{
+ char *request, *parameter;
+ static DATA_BLOB challenge;
+ static DATA_BLOB lm_response;
+ static DATA_BLOB nt_response;
+ static char *full_username;
+ static char *username;
+ static char *domain;
+ static char *plaintext_password;
+ static bool ntlm_server_1_user_session_key;
+ static bool ntlm_server_1_lm_session_key;
+
+ if (strequal(buf, ".")) {
+ if (!full_username && !username) {
+ x_fprintf(x_stdout, "Error: No username supplied!\n");
+ } else if (plaintext_password) {
+ /* handle this request as plaintext */
+ if (!full_username) {
+ if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) {
+ x_fprintf(x_stdout, "Error: Out of memory in asprintf!\n.\n");
+ return;
+ }
+ }
+ if (check_plaintext_auth(full_username, plaintext_password, False)) {
+ x_fprintf(x_stdout, "Authenticated: Yes\n");
+ } else {
+ x_fprintf(x_stdout, "Authenticated: No\n");
+ }
+ } else if (!lm_response.data && !nt_response.data) {
+ x_fprintf(x_stdout, "Error: No password supplied!\n");
+ } else if (!challenge.data) {
+ x_fprintf(x_stdout, "Error: No lanman-challenge supplied!\n");
+ } else {
+ char *error_string = NULL;
+ uchar lm_key[8];
+ uchar user_session_key[16];
+ uint32 flags = 0;
+
+ if (full_username && !username) {
+ fstring fstr_user;
+ fstring fstr_domain;
+
+ if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
+ /* username might be 'tainted', don't print into our new-line deleimianted stream */
+ x_fprintf(x_stdout, "Error: Could not parse into domain and username\n");
+ }
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ username = smb_xstrdup(fstr_user);
+ domain = smb_xstrdup(fstr_domain);
+ }
+
+ if (!domain) {
+ domain = smb_xstrdup(get_winbind_domain());
+ }
+
+ if (ntlm_server_1_lm_session_key)
+ flags |= WBFLAG_PAM_LMKEY;
+
+ if (ntlm_server_1_user_session_key)
+ flags |= WBFLAG_PAM_USER_SESSION_KEY;
+
+ if (!NT_STATUS_IS_OK(
+ contact_winbind_auth_crap(username,
+ domain,
+ global_myname(),
+ &challenge,
+ &lm_response,
+ &nt_response,
+ flags,
+ lm_key,
+ user_session_key,
+ &error_string,
+ NULL))) {
+
+ x_fprintf(x_stdout, "Authenticated: No\n");
+ x_fprintf(x_stdout, "Authentication-Error: %s\n.\n", error_string);
+ SAFE_FREE(error_string);
+ } else {
+ static char zeros[16];
+ char *hex_lm_key;
+ char *hex_user_session_key;
+
+ x_fprintf(x_stdout, "Authenticated: Yes\n");
+
+ if (ntlm_server_1_lm_session_key
+ && (memcmp(zeros, lm_key,
+ sizeof(lm_key)) != 0)) {
+ hex_lm_key = hex_encode(NULL,
+ (const unsigned char *)lm_key,
+ sizeof(lm_key));
+ x_fprintf(x_stdout, "LANMAN-Session-Key: %s\n", hex_lm_key);
+ TALLOC_FREE(hex_lm_key);
+ }
+
+ if (ntlm_server_1_user_session_key
+ && (memcmp(zeros, user_session_key,
+ sizeof(user_session_key)) != 0)) {
+ hex_user_session_key = hex_encode(NULL,
+ (const unsigned char *)user_session_key,
+ sizeof(user_session_key));
+ x_fprintf(x_stdout, "User-Session-Key: %s\n", hex_user_session_key);
+ TALLOC_FREE(hex_user_session_key);
+ }
+ }
+ }
+ /* clear out the state */
+ challenge = data_blob_null;
+ nt_response = data_blob_null;
+ lm_response = data_blob_null;
+ SAFE_FREE(full_username);
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ SAFE_FREE(plaintext_password);
+ ntlm_server_1_user_session_key = False;
+ ntlm_server_1_lm_session_key = False;
+ x_fprintf(x_stdout, ".\n");
+
+ return;
+ }
+
+ request = buf;
+
+ /* Indicates a base64 encoded structure */
+ parameter = strstr_m(request, ":: ");
+ if (!parameter) {
+ parameter = strstr_m(request, ": ");
+
+ if (!parameter) {
+ DEBUG(0, ("Parameter not found!\n"));
+ x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
+ return;
+ }
+
+ parameter[0] ='\0';
+ parameter++;
+ parameter[0] ='\0';
+ parameter++;
+
+ } else {
+ parameter[0] ='\0';
+ parameter++;
+ parameter[0] ='\0';
+ parameter++;
+ parameter[0] ='\0';
+ parameter++;
+
+ base64_decode_inplace(parameter);
+ }
+
+ if (strequal(request, "LANMAN-Challenge")) {
+ challenge = strhex_to_data_blob(NULL, parameter);
+ if (challenge.length != 8) {
+ x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
+ parameter,
+ (int)challenge.length);
+ challenge = data_blob_null;
+ }
+ } else if (strequal(request, "NT-Response")) {
+ nt_response = strhex_to_data_blob(NULL, parameter);
+ if (nt_response.length < 24) {
+ x_fprintf(x_stdout, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
+ parameter,
+ (int)nt_response.length);
+ nt_response = data_blob_null;
+ }
+ } else if (strequal(request, "LANMAN-Response")) {
+ lm_response = strhex_to_data_blob(NULL, parameter);
+ if (lm_response.length != 24) {
+ x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
+ parameter,
+ (int)lm_response.length);
+ lm_response = data_blob_null;
+ }
+ } else if (strequal(request, "Password")) {
+ plaintext_password = smb_xstrdup(parameter);
+ } else if (strequal(request, "NT-Domain")) {
+ domain = smb_xstrdup(parameter);
+ } else if (strequal(request, "Username")) {
+ username = smb_xstrdup(parameter);
+ } else if (strequal(request, "Full-Username")) {
+ full_username = smb_xstrdup(parameter);
+ } else if (strequal(request, "Request-User-Session-Key")) {
+ ntlm_server_1_user_session_key = strequal(parameter, "Yes");
+ } else if (strequal(request, "Request-LanMan-Session-Key")) {
+ ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
+ } else {
+ x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
+ }
+}
+
+static void manage_ntlm_change_password_1_request(struct ntlm_auth_state *state,
+ char *buf, int length)
+{
+ char *request, *parameter;
+ static DATA_BLOB new_nt_pswd;
+ static DATA_BLOB old_nt_hash_enc;
+ static DATA_BLOB new_lm_pswd;
+ static DATA_BLOB old_lm_hash_enc;
+ static char *full_username = NULL;
+ static char *username = NULL;
+ static char *domain = NULL;
+ static char *newpswd = NULL;
+ static char *oldpswd = NULL;
+
+ if (strequal(buf, ".")) {
+ if(newpswd && oldpswd) {
+ uchar old_nt_hash[16];
+ uchar old_lm_hash[16];
+ uchar new_nt_hash[16];
+ uchar new_lm_hash[16];
+
+ new_nt_pswd = data_blob(NULL, 516);
+ old_nt_hash_enc = data_blob(NULL, 16);
+
+ /* Calculate the MD4 hash (NT compatible) of the
+ * password */
+ E_md4hash(oldpswd, old_nt_hash);
+ E_md4hash(newpswd, new_nt_hash);
+
+ /* E_deshash returns false for 'long'
+ passwords (> 14 DOS chars).
+
+ Therefore, don't send a buffer
+ encrypted with the truncated hash
+ (it could allow an even easier
+ attack on the password)
+
+ Likewise, obey the admin's restriction
+ */
+
+ if (lp_client_lanman_auth() &&
+ E_deshash(newpswd, new_lm_hash) &&
+ E_deshash(oldpswd, old_lm_hash)) {
+ new_lm_pswd = data_blob(NULL, 516);
+ old_lm_hash_enc = data_blob(NULL, 16);
+ encode_pw_buffer(new_lm_pswd.data, newpswd,
+ STR_UNICODE);
+
+ SamOEMhash(new_lm_pswd.data, old_nt_hash, 516);
+ E_old_pw_hash(new_nt_hash, old_lm_hash,
+ old_lm_hash_enc.data);
+ } else {
+ new_lm_pswd.data = NULL;
+ new_lm_pswd.length = 0;
+ old_lm_hash_enc.data = NULL;
+ old_lm_hash_enc.length = 0;
+ }
+
+ encode_pw_buffer(new_nt_pswd.data, newpswd,
+ STR_UNICODE);
+
+ SamOEMhash(new_nt_pswd.data, old_nt_hash, 516);
+ E_old_pw_hash(new_nt_hash, old_nt_hash,
+ old_nt_hash_enc.data);
+ }
+
+ if (!full_username && !username) {
+ x_fprintf(x_stdout, "Error: No username supplied!\n");
+ } else if ((!new_nt_pswd.data || !old_nt_hash_enc.data) &&
+ (!new_lm_pswd.data || old_lm_hash_enc.data) ) {
+ x_fprintf(x_stdout, "Error: No NT or LM password "
+ "blobs supplied!\n");
+ } else {
+ char *error_string = NULL;
+
+ if (full_username && !username) {
+ fstring fstr_user;
+ fstring fstr_domain;
+
+ if (!parse_ntlm_auth_domain_user(full_username,
+ fstr_user,
+ fstr_domain)) {
+ /* username might be 'tainted', don't
+ * print into our new-line
+ * deleimianted stream */
+ x_fprintf(x_stdout, "Error: Could not "
+ "parse into domain and "
+ "username\n");
+ SAFE_FREE(username);
+ username = smb_xstrdup(full_username);
+ } else {
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ username = smb_xstrdup(fstr_user);
+ domain = smb_xstrdup(fstr_domain);
+ }
+
+ }
+
+ if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
+ username, domain,
+ new_nt_pswd,
+ old_nt_hash_enc,
+ new_lm_pswd,
+ old_lm_hash_enc,
+ &error_string))) {
+ x_fprintf(x_stdout, "Password-Change: No\n");
+ x_fprintf(x_stdout, "Password-Change-Error: "
+ "%s\n.\n", error_string);
+ } else {
+ x_fprintf(x_stdout, "Password-Change: Yes\n");
+ }
+
+ SAFE_FREE(error_string);
+ }
+ /* clear out the state */
+ new_nt_pswd = data_blob_null;
+ old_nt_hash_enc = data_blob_null;
+ new_lm_pswd = data_blob_null;
+ old_nt_hash_enc = data_blob_null;
+ SAFE_FREE(full_username);
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ SAFE_FREE(newpswd);
+ SAFE_FREE(oldpswd);
+ x_fprintf(x_stdout, ".\n");
+
+ return;
+ }
+
+ request = buf;
+
+ /* Indicates a base64 encoded structure */
+ parameter = strstr_m(request, ":: ");
+ if (!parameter) {
+ parameter = strstr_m(request, ": ");
+
+ if (!parameter) {
+ DEBUG(0, ("Parameter not found!\n"));
+ x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
+ return;
+ }
+
+ parameter[0] ='\0';
+ parameter++;
+ parameter[0] ='\0';
+ parameter++;
+ } else {
+ parameter[0] ='\0';
+ parameter++;
+ parameter[0] ='\0';
+ parameter++;
+ parameter[0] ='\0';
+ parameter++;
+
+ base64_decode_inplace(parameter);
+ }
+
+ if (strequal(request, "new-nt-password-blob")) {
+ new_nt_pswd = strhex_to_data_blob(NULL, parameter);
+ if (new_nt_pswd.length != 516) {
+ x_fprintf(x_stdout, "Error: hex decode of %s failed! "
+ "(got %d bytes, expected 516)\n.\n",
+ parameter,
+ (int)new_nt_pswd.length);
+ new_nt_pswd = data_blob_null;
+ }
+ } else if (strequal(request, "old-nt-hash-blob")) {
+ old_nt_hash_enc = strhex_to_data_blob(NULL, parameter);
+ if (old_nt_hash_enc.length != 16) {
+ x_fprintf(x_stdout, "Error: hex decode of %s failed! "
+ "(got %d bytes, expected 16)\n.\n",
+ parameter,
+ (int)old_nt_hash_enc.length);
+ old_nt_hash_enc = data_blob_null;
+ }
+ } else if (strequal(request, "new-lm-password-blob")) {
+ new_lm_pswd = strhex_to_data_blob(NULL, parameter);
+ if (new_lm_pswd.length != 516) {
+ x_fprintf(x_stdout, "Error: hex decode of %s failed! "
+ "(got %d bytes, expected 516)\n.\n",
+ parameter,
+ (int)new_lm_pswd.length);
+ new_lm_pswd = data_blob_null;
+ }
+ }
+ else if (strequal(request, "old-lm-hash-blob")) {
+ old_lm_hash_enc = strhex_to_data_blob(NULL, parameter);
+ if (old_lm_hash_enc.length != 16)
+ {
+ x_fprintf(x_stdout, "Error: hex decode of %s failed! "
+ "(got %d bytes, expected 16)\n.\n",
+ parameter,
+ (int)old_lm_hash_enc.length);
+ old_lm_hash_enc = data_blob_null;
+ }
+ } else if (strequal(request, "nt-domain")) {
+ domain = smb_xstrdup(parameter);
+ } else if(strequal(request, "username")) {
+ username = smb_xstrdup(parameter);
+ } else if(strequal(request, "full-username")) {
+ username = smb_xstrdup(parameter);
+ } else if(strequal(request, "new-password")) {
+ newpswd = smb_xstrdup(parameter);
+ } else if (strequal(request, "old-password")) {
+ oldpswd = smb_xstrdup(parameter);
+ } else {
+ x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
+ }
+}
+
+static void manage_squid_request(struct ntlm_auth_state *state,
+ stdio_helper_function fn)
+{
+ char *buf;
+ char tmp[INITIAL_BUFFER_SIZE+1];
+ int length, buf_size = 0;
+ char *c;
+
+ buf = talloc_strdup(state->mem_ctx, "");
+ if (!buf) {
+ DEBUG(0, ("Failed to allocate input buffer.\n"));
+ x_fprintf(x_stderr, "ERR\n");
+ exit(1);
+ }
+
+ do {
+
+ /* this is not a typo - x_fgets doesn't work too well under
+ * squid */
+ if (fgets(tmp, sizeof(tmp)-1, stdin) == NULL) {
+ if (ferror(stdin)) {
+ DEBUG(1, ("fgets() failed! dying..... errno=%d "
+ "(%s)\n", ferror(stdin),
+ strerror(ferror(stdin))));
+
+ exit(1);
+ }
+ exit(0);
+ }
+
+ buf = talloc_strdup_append_buffer(buf, tmp);
+ buf_size += INITIAL_BUFFER_SIZE;
+
+ if (buf_size > MAX_BUFFER_SIZE) {
+ DEBUG(2, ("Oversized message\n"));
+ x_fprintf(x_stderr, "ERR\n");
+ talloc_free(buf);
+ return;
+ }
+
+ c = strchr(buf, '\n');
+ } while (c == NULL);
+
+ *c = '\0';
+ length = c-buf;
+
+ DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
+
+ if (buf[0] == '\0') {
+ DEBUG(2, ("Invalid Request\n"));
+ x_fprintf(x_stderr, "ERR\n");
+ talloc_free(buf);
+ return;
+ }
+
+ fn(state, buf, length);
+ talloc_free(buf);
+}
+
+
+static void squid_stream(enum stdio_helper_mode stdio_mode, stdio_helper_function fn) {
+ TALLOC_CTX *mem_ctx;
+ struct ntlm_auth_state *state;
+
+ /* initialize FDescs */
+ x_setbuf(x_stdout, NULL);
+ x_setbuf(x_stderr, NULL);
+
+ mem_ctx = talloc_init("ntlm_auth");
+ if (!mem_ctx) {
+ DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
+ x_fprintf(x_stderr, "ERR\n");
+ exit(1);
+ }
+
+ state = talloc_zero(mem_ctx, struct ntlm_auth_state);
+ if (!state) {
+ DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
+ x_fprintf(x_stderr, "ERR\n");
+ exit(1);
+ }
+
+ state->mem_ctx = mem_ctx;
+ state->helper_mode = stdio_mode;
+
+ while(1) {
+ manage_squid_request(state, fn);
+ }
+}
+
+
+/* Authenticate a user with a challenge/response */
+
+static bool check_auth_crap(void)
+{
+ NTSTATUS nt_status;
+ uint32 flags = 0;
+ char lm_key[8];
+ char user_session_key[16];
+ char *hex_lm_key;
+ char *hex_user_session_key;
+ char *error_string;
+ static uint8 zeros[16];
+
+ x_setbuf(x_stdout, NULL);
+
+ if (request_lm_key)
+ flags |= WBFLAG_PAM_LMKEY;
+
+ if (request_user_session_key)
+ flags |= WBFLAG_PAM_USER_SESSION_KEY;
+
+ flags |= WBFLAG_PAM_NT_STATUS_SQUASH;
+
+ nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
+ opt_workstation,
+ &opt_challenge,
+ &opt_lm_response,
+ &opt_nt_response,
+ flags,
+ (unsigned char *)lm_key,
+ (unsigned char *)user_session_key,
+ &error_string, NULL);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ x_fprintf(x_stdout, "%s (0x%x)\n",
+ error_string,
+ NT_STATUS_V(nt_status));
+ SAFE_FREE(error_string);
+ return False;
+ }
+
+ if (request_lm_key
+ && (memcmp(zeros, lm_key,
+ sizeof(lm_key)) != 0)) {
+ hex_lm_key = hex_encode(NULL, (const unsigned char *)lm_key,
+ sizeof(lm_key));
+ x_fprintf(x_stdout, "LM_KEY: %s\n", hex_lm_key);
+ TALLOC_FREE(hex_lm_key);
+ }
+ if (request_user_session_key
+ && (memcmp(zeros, user_session_key,
+ sizeof(user_session_key)) != 0)) {
+ hex_user_session_key = hex_encode(NULL, (const unsigned char *)user_session_key,
+ sizeof(user_session_key));
+ x_fprintf(x_stdout, "NT_KEY: %s\n", hex_user_session_key);
+ TALLOC_FREE(hex_user_session_key);
+ }
+
+ return True;
+}
+
+/* Main program */
+
+enum {
+ OPT_USERNAME = 1000,
+ OPT_DOMAIN,
+ OPT_WORKSTATION,
+ OPT_CHALLENGE,
+ OPT_RESPONSE,
+ OPT_LM,
+ OPT_NT,
+ OPT_PASSWORD,
+ OPT_LM_KEY,
+ OPT_USER_SESSION_KEY,
+ OPT_DIAGNOSTICS,
+ OPT_REQUIRE_MEMBERSHIP,
+ OPT_USE_CACHED_CREDS
+};
+
+ int main(int argc, const char **argv)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ int opt;
+ static const char *helper_protocol;
+ static int diagnostics;
+
+ static const char *hex_challenge;
+ static const char *hex_lm_response;
+ static const char *hex_nt_response;
+
+ poptContext pc;
+
+ /* NOTE: DO NOT change this interface without considering the implications!
+ This is an external interface, which other programs will use to interact
+ with this helper.
+ */
+
+ /* We do not use single-letter command abbreviations, because they harm future
+ interface stability. */
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
+ { "username", 0, POPT_ARG_STRING, &opt_username, OPT_USERNAME, "username"},
+ { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"},
+ { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"},
+ { "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"},
+ { "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
+ { "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
+ { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"},
+ { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retrieve LM session key"},
+ { "request-nt-key", 0, POPT_ARG_NONE, &request_user_session_key, OPT_USER_SESSION_KEY, "Retrieve User (NT) session key"},
+ { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "Use cached credentials if no password is given"},
+ { "diagnostics", 0, POPT_ARG_NONE, &diagnostics, OPT_DIAGNOSTICS, "Perform diagnostics on the authentictaion chain"},
+ { "require-membership-of", 0, POPT_ARG_STRING, &require_membership_of, OPT_REQUIRE_MEMBERSHIP, "Require that a user be a member of this group (either name or SID) for authentication to succeed" },
+ POPT_COMMON_CONFIGFILE
+ POPT_COMMON_VERSION
+ POPT_TABLEEND
+ };
+
+ /* Samba client initialisation */
+ load_case_tables();
+
+ dbf = x_stderr;
+
+ /* Parse options */
+
+ pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
+
+ /* Parse command line options */
+
+ if (argc == 1) {
+ poptPrintHelp(pc, stderr, 0);
+ return 1;
+ }
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ /* Get generic config options like --configfile */
+ }
+
+ poptFreeContext(pc);
+
+ if (!lp_load(get_dyn_CONFIGFILE(), True, False, False, True)) {
+ d_fprintf(stderr, "ntlm_auth: error opening config file %s. Error was %s\n",
+ get_dyn_CONFIGFILE(), strerror(errno));
+ exit(1);
+ }
+
+ pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case OPT_CHALLENGE:
+ opt_challenge = strhex_to_data_blob(NULL, hex_challenge);
+ if (opt_challenge.length != 8) {
+ x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
+ hex_challenge,
+ (int)opt_challenge.length);
+ exit(1);
+ }
+ break;
+ case OPT_LM:
+ opt_lm_response = strhex_to_data_blob(NULL, hex_lm_response);
+ if (opt_lm_response.length != 24) {
+ x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
+ hex_lm_response,
+ (int)opt_lm_response.length);
+ exit(1);
+ }
+ break;
+
+ case OPT_NT:
+ opt_nt_response = strhex_to_data_blob(NULL, hex_nt_response);
+ if (opt_nt_response.length < 24) {
+ x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
+ hex_nt_response,
+ (int)opt_nt_response.length);
+ exit(1);
+ }
+ break;
+
+ case OPT_REQUIRE_MEMBERSHIP:
+ if (StrnCaseCmp("S-", require_membership_of, 2) == 0) {
+ require_membership_of_sid = require_membership_of;
+ }
+ break;
+ }
+ }
+
+ if (opt_username) {
+ char *domain = SMB_STRDUP(opt_username);
+ char *p = strchr_m(domain, *lp_winbind_separator());
+ if (p) {
+ opt_username = p+1;
+ *p = '\0';
+ if (opt_domain && !strequal(opt_domain, domain)) {
+ x_fprintf(x_stderr, "Domain specified in username (%s) "
+ "doesn't match specified domain (%s)!\n\n",
+ domain, opt_domain);
+ poptPrintHelp(pc, stderr, 0);
+ exit(1);
+ }
+ opt_domain = domain;
+ } else {
+ SAFE_FREE(domain);
+ }
+ }
+
+ /* Note: if opt_domain is "" then send no domain */
+ if (opt_domain == NULL) {
+ opt_domain = get_winbind_domain();
+ }
+
+ if (opt_workstation == NULL) {
+ opt_workstation = "";
+ }
+
+ if (helper_protocol) {
+ int i;
+ for (i=0; i<NUM_HELPER_MODES; i++) {
+ if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
+ squid_stream(stdio_helper_protocols[i].mode, stdio_helper_protocols[i].fn);
+ exit(0);
+ }
+ }
+ x_fprintf(x_stderr, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol);
+
+ for (i=0; i<NUM_HELPER_MODES; i++) {
+ x_fprintf(x_stderr, "%s\n", stdio_helper_protocols[i].name);
+ }
+
+ exit(1);
+ }
+
+ if (!opt_username || !*opt_username) {
+ x_fprintf(x_stderr, "username must be specified!\n\n");
+ poptPrintHelp(pc, stderr, 0);
+ exit(1);
+ }
+
+ if (opt_challenge.length) {
+ if (!check_auth_crap()) {
+ exit(1);
+ }
+ exit(0);
+ }
+
+ if (!opt_password) {
+ opt_password = getpass("password: ");
+ }
+
+ if (diagnostics) {
+ if (!diagnose_ntlm_auth()) {
+ return 1;
+ }
+ } else {
+ fstring user;
+
+ fstr_sprintf(user, "%s%c%s", opt_domain, winbind_separator(), opt_username);
+ if (!check_plaintext_auth(user, opt_password, True)) {
+ return 1;
+ }
+ }
+
+ /* Exit code */
+
+ poptFreeContext(pc);
+ TALLOC_FREE(frame);
+ return 0;
+}
diff --git a/source3/utils/ntlm_auth.h b/source3/utils/ntlm_auth.h
new file mode 100644
index 0000000000..fb1dd62a19
--- /dev/null
+++ b/source3/utils/ntlm_auth.h
@@ -0,0 +1,26 @@
+/*
+ Samba Unix/Linux NTLM authentication tool
+
+ Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "utils/ntlm_auth_proto.h"
+
+/* Some of the popt variables are needed in the diagnostics code */
+extern const char *opt_username;
+extern const char *opt_domain;
+extern const char *opt_workstation;
+extern const char *opt_password;
+
diff --git a/source3/utils/ntlm_auth_diagnostics.c b/source3/utils/ntlm_auth_diagnostics.c
new file mode 100644
index 0000000000..dcdc8e9a40
--- /dev/null
+++ b/source3/utils/ntlm_auth_diagnostics.c
@@ -0,0 +1,607 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind status program.
+
+ Copyright (C) Tim Potter 2000-2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
+ Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/ntlm_auth.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+enum ntlm_break {
+ BREAK_NONE,
+ BREAK_LM,
+ BREAK_NT,
+ NO_LM,
+ NO_NT
+};
+
+/*
+ Authenticate a user with a challenge/response, checking session key
+ and valid authentication types
+*/
+
+/*
+ * Test the normal 'LM and NTLM' combination
+ */
+
+static bool test_lm_ntlm_broken(enum ntlm_break break_which)
+{
+ bool pass = True;
+ NTSTATUS nt_status;
+ uint32 flags = 0;
+ DATA_BLOB lm_response = data_blob(NULL, 24);
+ DATA_BLOB nt_response = data_blob(NULL, 24);
+ DATA_BLOB session_key = data_blob(NULL, 16);
+
+ uchar lm_key[8];
+ uchar user_session_key[16];
+ uchar lm_hash[16];
+ uchar nt_hash[16];
+ DATA_BLOB chall = get_challenge();
+ char *error_string;
+
+ ZERO_STRUCT(lm_key);
+ ZERO_STRUCT(user_session_key);
+
+ flags |= WBFLAG_PAM_LMKEY;
+ flags |= WBFLAG_PAM_USER_SESSION_KEY;
+
+ SMBencrypt(opt_password,chall.data,lm_response.data);
+ E_deshash(opt_password, lm_hash);
+
+ SMBNTencrypt(opt_password,chall.data,nt_response.data);
+
+ E_md4hash(opt_password, nt_hash);
+ SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+
+ switch (break_which) {
+ case BREAK_NONE:
+ break;
+ case BREAK_LM:
+ lm_response.data[0]++;
+ break;
+ case BREAK_NT:
+ nt_response.data[0]++;
+ break;
+ case NO_LM:
+ data_blob_free(&lm_response);
+ break;
+ case NO_NT:
+ data_blob_free(&nt_response);
+ break;
+ }
+
+ nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
+ opt_workstation,
+ &chall,
+ &lm_response,
+ &nt_response,
+ flags,
+ lm_key,
+ user_session_key,
+ &error_string, NULL);
+
+ data_blob_free(&lm_response);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ d_printf("%s (0x%x)\n",
+ error_string,
+ NT_STATUS_V(nt_status));
+ SAFE_FREE(error_string);
+ return break_which == BREAK_NT;
+ }
+
+ if (memcmp(lm_hash, lm_key,
+ sizeof(lm_key)) != 0) {
+ DEBUG(1, ("LM Key does not match expectations!\n"));
+ DEBUG(1, ("lm_key:\n"));
+ dump_data(1, lm_key, 8);
+ DEBUG(1, ("expected:\n"));
+ dump_data(1, lm_hash, 8);
+ pass = False;
+ }
+
+ if (break_which == NO_NT) {
+ if (memcmp(lm_hash, user_session_key,
+ 8) != 0) {
+ DEBUG(1, ("NT Session Key does not match expectations (should be LM hash)!\n"));
+ DEBUG(1, ("user_session_key:\n"));
+ dump_data(1, user_session_key, sizeof(user_session_key));
+ DEBUG(1, ("expected:\n"));
+ dump_data(1, lm_hash, sizeof(lm_hash));
+ pass = False;
+ }
+ } else {
+ if (memcmp(session_key.data, user_session_key,
+ sizeof(user_session_key)) != 0) {
+ DEBUG(1, ("NT Session Key does not match expectations!\n"));
+ DEBUG(1, ("user_session_key:\n"));
+ dump_data(1, user_session_key, 16);
+ DEBUG(1, ("expected:\n"));
+ dump_data(1, session_key.data, session_key.length);
+ pass = False;
+ }
+ }
+ return pass;
+}
+
+/*
+ * Test LM authentication, no NT response supplied
+ */
+
+static bool test_lm(void)
+{
+
+ return test_lm_ntlm_broken(NO_NT);
+}
+
+/*
+ * Test the NTLM response only, no LM.
+ */
+
+static bool test_ntlm(void)
+{
+ return test_lm_ntlm_broken(NO_LM);
+}
+
+/*
+ * Test the NTLM response only, but in the LM field.
+ */
+
+static bool test_ntlm_in_lm(void)
+{
+ bool pass = True;
+ NTSTATUS nt_status;
+ uint32 flags = 0;
+ DATA_BLOB nt_response = data_blob(NULL, 24);
+
+ uchar lm_key[8];
+ uchar lm_hash[16];
+ uchar user_session_key[16];
+ DATA_BLOB chall = get_challenge();
+ char *error_string;
+
+ ZERO_STRUCT(user_session_key);
+
+ flags |= WBFLAG_PAM_LMKEY;
+ flags |= WBFLAG_PAM_USER_SESSION_KEY;
+
+ SMBNTencrypt(opt_password,chall.data,nt_response.data);
+
+ E_deshash(opt_password, lm_hash);
+
+ nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
+ opt_workstation,
+ &chall,
+ &nt_response,
+ NULL,
+ flags,
+ lm_key,
+ user_session_key,
+ &error_string, NULL);
+
+ data_blob_free(&nt_response);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ d_printf("%s (0x%x)\n",
+ error_string,
+ NT_STATUS_V(nt_status));
+ SAFE_FREE(error_string);
+ return False;
+ }
+
+ if (memcmp(lm_hash, lm_key,
+ sizeof(lm_key)) != 0) {
+ DEBUG(1, ("LM Key does not match expectations!\n"));
+ DEBUG(1, ("lm_key:\n"));
+ dump_data(1, lm_key, 8);
+ DEBUG(1, ("expected:\n"));
+ dump_data(1, lm_hash, 8);
+ pass = False;
+ }
+ if (memcmp(lm_hash, user_session_key, 8) != 0) {
+ DEBUG(1, ("Session Key (first 8 lm hash) does not match expectations!\n"));
+ DEBUG(1, ("user_session_key:\n"));
+ dump_data(1, user_session_key, 16);
+ DEBUG(1, ("expected:\n"));
+ dump_data(1, lm_hash, 8);
+ pass = False;
+ }
+ return pass;
+}
+
+/*
+ * Test the NTLM response only, but in the both the NT and LM fields.
+ */
+
+static bool test_ntlm_in_both(void)
+{
+ bool pass = True;
+ NTSTATUS nt_status;
+ uint32 flags = 0;
+ DATA_BLOB nt_response = data_blob(NULL, 24);
+ DATA_BLOB session_key = data_blob(NULL, 16);
+
+ uint8 lm_key[8];
+ uint8 lm_hash[16];
+ uint8 user_session_key[16];
+ uint8 nt_hash[16];
+ DATA_BLOB chall = get_challenge();
+ char *error_string;
+
+ ZERO_STRUCT(lm_key);
+ ZERO_STRUCT(user_session_key);
+
+ flags |= WBFLAG_PAM_LMKEY;
+ flags |= WBFLAG_PAM_USER_SESSION_KEY;
+
+ SMBNTencrypt(opt_password,chall.data,nt_response.data);
+ E_md4hash(opt_password, nt_hash);
+ SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+
+ E_deshash(opt_password, lm_hash);
+
+ nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
+ opt_workstation,
+ &chall,
+ &nt_response,
+ &nt_response,
+ flags,
+ lm_key,
+ user_session_key,
+ &error_string, NULL);
+
+ data_blob_free(&nt_response);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ d_printf("%s (0x%x)\n",
+ error_string,
+ NT_STATUS_V(nt_status));
+ SAFE_FREE(error_string);
+ return False;
+ }
+
+ if (memcmp(lm_hash, lm_key,
+ sizeof(lm_key)) != 0) {
+ DEBUG(1, ("LM Key does not match expectations!\n"));
+ DEBUG(1, ("lm_key:\n"));
+ dump_data(1, lm_key, 8);
+ DEBUG(1, ("expected:\n"));
+ dump_data(1, lm_hash, 8);
+ pass = False;
+ }
+ if (memcmp(session_key.data, user_session_key,
+ sizeof(user_session_key)) != 0) {
+ DEBUG(1, ("NT Session Key does not match expectations!\n"));
+ DEBUG(1, ("user_session_key:\n"));
+ dump_data(1, user_session_key, 16);
+ DEBUG(1, ("expected:\n"));
+ dump_data(1, session_key.data, session_key.length);
+ pass = False;
+ }
+
+
+ return pass;
+}
+
+/*
+ * Test the NTLMv2 and LMv2 responses
+ */
+
+static bool test_lmv2_ntlmv2_broken(enum ntlm_break break_which)
+{
+ bool pass = True;
+ NTSTATUS nt_status;
+ uint32 flags = 0;
+ DATA_BLOB ntlmv2_response = data_blob_null;
+ DATA_BLOB lmv2_response = data_blob_null;
+ DATA_BLOB ntlmv2_session_key = data_blob_null;
+ DATA_BLOB names_blob = NTLMv2_generate_names_blob(get_winbind_netbios_name(), get_winbind_domain());
+
+ uchar user_session_key[16];
+ DATA_BLOB chall = get_challenge();
+ char *error_string;
+
+ ZERO_STRUCT(user_session_key);
+
+ flags |= WBFLAG_PAM_USER_SESSION_KEY;
+
+ if (!SMBNTLMv2encrypt(opt_username, opt_domain, opt_password, &chall,
+ &names_blob,
+ &lmv2_response, &ntlmv2_response,
+ &ntlmv2_session_key)) {
+ data_blob_free(&names_blob);
+ return False;
+ }
+ data_blob_free(&names_blob);
+
+ switch (break_which) {
+ case BREAK_NONE:
+ break;
+ case BREAK_LM:
+ lmv2_response.data[0]++;
+ break;
+ case BREAK_NT:
+ ntlmv2_response.data[0]++;
+ break;
+ case NO_LM:
+ data_blob_free(&lmv2_response);
+ break;
+ case NO_NT:
+ data_blob_free(&ntlmv2_response);
+ break;
+ }
+
+ nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
+ opt_workstation,
+ &chall,
+ &lmv2_response,
+ &ntlmv2_response,
+ flags,
+ NULL,
+ user_session_key,
+ &error_string, NULL);
+
+ data_blob_free(&lmv2_response);
+ data_blob_free(&ntlmv2_response);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ d_printf("%s (0x%x)\n",
+ error_string,
+ NT_STATUS_V(nt_status));
+ SAFE_FREE(error_string);
+ return break_which == BREAK_NT;
+ }
+
+ if (break_which != NO_NT && break_which != BREAK_NT && memcmp(ntlmv2_session_key.data, user_session_key,
+ sizeof(user_session_key)) != 0) {
+ DEBUG(1, ("USER (NTLMv2) Session Key does not match expectations!\n"));
+ DEBUG(1, ("user_session_key:\n"));
+ dump_data(1, user_session_key, 16);
+ DEBUG(1, ("expected:\n"));
+ dump_data(1, ntlmv2_session_key.data, ntlmv2_session_key.length);
+ pass = False;
+ }
+ return pass;
+}
+
+/*
+ * Test the NTLMv2 and LMv2 responses
+ */
+
+static bool test_lmv2_ntlmv2(void)
+{
+ return test_lmv2_ntlmv2_broken(BREAK_NONE);
+}
+
+/*
+ * Test the LMv2 response only
+ */
+
+static bool test_lmv2(void)
+{
+ return test_lmv2_ntlmv2_broken(NO_NT);
+}
+
+/*
+ * Test the NTLMv2 response only
+ */
+
+static bool test_ntlmv2(void)
+{
+ return test_lmv2_ntlmv2_broken(NO_LM);
+}
+
+static bool test_lm_ntlm(void)
+{
+ return test_lm_ntlm_broken(BREAK_NONE);
+}
+
+static bool test_ntlm_lm_broken(void)
+{
+ return test_lm_ntlm_broken(BREAK_LM);
+}
+
+static bool test_ntlm_ntlm_broken(void)
+{
+ return test_lm_ntlm_broken(BREAK_NT);
+}
+
+static bool test_ntlmv2_lmv2_broken(void)
+{
+ return test_lmv2_ntlmv2_broken(BREAK_LM);
+}
+
+static bool test_ntlmv2_ntlmv2_broken(void)
+{
+ return test_lmv2_ntlmv2_broken(BREAK_NT);
+}
+
+static bool test_plaintext(enum ntlm_break break_which)
+{
+ NTSTATUS nt_status;
+ uint32 flags = 0;
+ DATA_BLOB nt_response = data_blob_null;
+ DATA_BLOB lm_response = data_blob_null;
+ char *password;
+ smb_ucs2_t *nt_response_ucs2;
+ size_t converted_size;
+
+ uchar user_session_key[16];
+ uchar lm_key[16];
+ static const uchar zeros[8] = { 0, };
+ DATA_BLOB chall = data_blob(zeros, sizeof(zeros));
+ char *error_string;
+
+ ZERO_STRUCT(user_session_key);
+
+ flags |= WBFLAG_PAM_LMKEY;
+ flags |= WBFLAG_PAM_USER_SESSION_KEY;
+
+ if (!push_ucs2_allocate(&nt_response_ucs2, opt_password,
+ &converted_size))
+ {
+ DEBUG(0, ("push_ucs2_allocate failed!\n"));
+ exit(1);
+ }
+
+ nt_response.data = (unsigned char *)nt_response_ucs2;
+ nt_response.length = strlen_w(nt_response_ucs2)*sizeof(smb_ucs2_t);
+
+ if ((password = strdup_upper(opt_password)) == NULL) {
+ DEBUG(0, ("strdup_upper failed!\n"));
+ exit(1);
+ }
+
+ if (!convert_string_allocate(NULL, CH_UNIX,
+ CH_DOS, password,
+ strlen(password)+1,
+ &lm_response.data,
+ &lm_response.length, True)) {
+ DEBUG(0, ("convert_string_allocate failed!\n"));
+ exit(1);
+ }
+
+ SAFE_FREE(password);
+
+ switch (break_which) {
+ case BREAK_NONE:
+ break;
+ case BREAK_LM:
+ lm_response.data[0]++;
+ break;
+ case BREAK_NT:
+ nt_response.data[0]++;
+ break;
+ case NO_LM:
+ SAFE_FREE(lm_response.data);
+ lm_response.length = 0;
+ break;
+ case NO_NT:
+ SAFE_FREE(nt_response.data);
+ nt_response.length = 0;
+ break;
+ }
+
+ nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
+ opt_workstation,
+ &chall,
+ &lm_response,
+ &nt_response,
+ flags,
+ lm_key,
+ user_session_key,
+ &error_string, NULL);
+
+ SAFE_FREE(nt_response.data);
+ SAFE_FREE(lm_response.data);
+ data_blob_free(&chall);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ d_printf("%s (0x%x)\n",
+ error_string,
+ NT_STATUS_V(nt_status));
+ SAFE_FREE(error_string);
+ return break_which == BREAK_NT;
+ }
+
+ return break_which != BREAK_NT;
+}
+
+static bool test_plaintext_none_broken(void) {
+ return test_plaintext(BREAK_NONE);
+}
+
+static bool test_plaintext_lm_broken(void) {
+ return test_plaintext(BREAK_LM);
+}
+
+static bool test_plaintext_nt_broken(void) {
+ return test_plaintext(BREAK_NT);
+}
+
+static bool test_plaintext_nt_only(void) {
+ return test_plaintext(NO_LM);
+}
+
+static bool test_plaintext_lm_only(void) {
+ return test_plaintext(NO_NT);
+}
+
+/*
+ Tests:
+
+ - LM only
+ - NT and LM
+ - NT
+ - NT in LM field
+ - NT in both fields
+ - NTLMv2
+ - NTLMv2 and LMv2
+ - LMv2
+ - plaintext tests (in challenge-response feilds)
+
+ check we get the correct session key in each case
+ check what values we get for the LM session key
+
+*/
+
+static const struct ntlm_tests {
+ bool (*fn)(void);
+ const char *name;
+} test_table[] = {
+ {test_lm, "LM"},
+ {test_lm_ntlm, "LM and NTLM"},
+ {test_ntlm, "NTLM"},
+ {test_ntlm_in_lm, "NTLM in LM"},
+ {test_ntlm_in_both, "NTLM in both"},
+ {test_ntlmv2, "NTLMv2"},
+ {test_lmv2_ntlmv2, "NTLMv2 and LMv2"},
+ {test_lmv2, "LMv2"},
+ {test_ntlmv2_lmv2_broken, "NTLMv2 and LMv2, LMv2 broken"},
+ {test_ntlmv2_ntlmv2_broken, "NTLMv2 and LMv2, NTLMv2 broken"},
+ {test_ntlm_lm_broken, "NTLM and LM, LM broken"},
+ {test_ntlm_ntlm_broken, "NTLM and LM, NTLM broken"},
+ {test_plaintext_none_broken, "Plaintext"},
+ {test_plaintext_lm_broken, "Plaintext LM broken"},
+ {test_plaintext_nt_broken, "Plaintext NT broken"},
+ {test_plaintext_nt_only, "Plaintext NT only"},
+ {test_plaintext_lm_only, "Plaintext LM only"},
+ {NULL, NULL}
+};
+
+bool diagnose_ntlm_auth(void)
+{
+ unsigned int i;
+ bool pass = True;
+
+ for (i=0; test_table[i].fn; i++) {
+ if (!test_table[i].fn()) {
+ DEBUG(1, ("Test %s failed!\n", test_table[i].name));
+ pass = False;
+ }
+ }
+
+ return pass;
+}
+
diff --git a/source3/utils/ntlm_auth_proto.h b/source3/utils/ntlm_auth_proto.h
new file mode 100644
index 0000000000..e48a190ed6
--- /dev/null
+++ b/source3/utils/ntlm_auth_proto.h
@@ -0,0 +1,48 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * collected prototypes header
+ *
+ * frozen from "make proto" in May 2008
+ *
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _NTLM_AUTH_PROTO_H_
+#define _NTLM_AUTH_PROTO_H_
+
+
+/* The following definitions come from utils/ntlm_auth.c */
+
+const char *get_winbind_domain(void);
+const char *get_winbind_netbios_name(void);
+DATA_BLOB get_challenge(void) ;
+NTSTATUS contact_winbind_auth_crap(const char *username,
+ const char *domain,
+ const char *workstation,
+ const DATA_BLOB *challenge,
+ const DATA_BLOB *lm_response,
+ const DATA_BLOB *nt_response,
+ uint32 flags,
+ uint8 lm_key[8],
+ uint8 user_session_key[16],
+ char **error_string,
+ char **unix_name);
+
+/* The following definitions come from utils/ntlm_auth_diagnostics.c */
+
+bool diagnose_ntlm_auth(void);
+
+#endif /* _NTLM_AUTH_PROTO_H_ */
diff --git a/source3/utils/passwd_proto.h b/source3/utils/passwd_proto.h
new file mode 100644
index 0000000000..104e00a65c
--- /dev/null
+++ b/source3/utils/passwd_proto.h
@@ -0,0 +1,32 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * collected prototypes header
+ *
+ * frozen from "make proto" in May 2008
+ *
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _PASSWD_PROTO_H_
+#define _PASSWD_PROTO_H_
+
+
+/* The following definitions come from utils/passwd_util.c */
+
+char *stdin_new_passwd( void);
+char *get_pass( const char *prompt, bool stdin_get);
+
+#endif /* _PASSWD_PROTO_H_ */
diff --git a/source3/utils/passwd_util.c b/source3/utils/passwd_util.c
new file mode 100644
index 0000000000..293f16364e
--- /dev/null
+++ b/source3/utils/passwd_util.c
@@ -0,0 +1,68 @@
+/*
+ Unix SMB/CIFS implementation.
+ passdb editing frontend
+
+ Copyright (C) Jeremy Allison 1998
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Simo Sorce 2000
+ Copyright (C) Martin Pool 2001
+ Copyright (C) Gerald Carter 2002
+ Copyright (C) Andrew Bartlett 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/*************************************************************
+ Utility function to prompt for passwords from stdin. Each
+ password entered must end with a newline.
+*************************************************************/
+char *stdin_new_passwd( void)
+{
+ static fstring new_pw;
+ size_t len;
+
+ ZERO_ARRAY(new_pw);
+
+ /*
+ * if no error is reported from fgets() and string at least contains
+ * the newline that ends the password, then replace the newline with
+ * a null terminator.
+ */
+ if ( fgets(new_pw, sizeof(new_pw), stdin) != NULL) {
+ if ((len = strlen(new_pw)) > 0) {
+ if(new_pw[len-1] == '\n')
+ new_pw[len - 1] = 0;
+ }
+ }
+ return(new_pw);
+}
+
+/*************************************************************
+ Utility function to get passwords via tty or stdin
+ Used if the '-s' (smbpasswd) or '-t' (pdbedit) option is set
+ to silently get passwords to enable scripting.
+*************************************************************/
+char *get_pass( const char *prompt, bool stdin_get)
+{
+ char *p;
+ if (stdin_get) {
+ p = stdin_new_passwd();
+ } else {
+ p = getpass( prompt);
+ }
+ return smb_xstrdup( p);
+}
diff --git a/source3/utils/pdbedit.c b/source3/utils/pdbedit.c
new file mode 100644
index 0000000000..e1d6709073
--- /dev/null
+++ b/source3/utils/pdbedit.c
@@ -0,0 +1,1101 @@
+/*
+ Unix SMB/CIFS implementation.
+ passdb editing frontend
+
+ Copyright (C) Simo Sorce 2000
+ Copyright (C) Andrew Bartlett 2001
+ Copyright (C) Jelmer Vernooij 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#define BIT_BACKEND 0x00000004
+#define BIT_VERBOSE 0x00000008
+#define BIT_SPSTYLE 0x00000010
+#define BIT_CAN_CHANGE 0x00000020
+#define BIT_MUST_CHANGE 0x00000040
+#define BIT_USERSIDS 0x00000080
+#define BIT_FULLNAME 0x00000100
+#define BIT_HOMEDIR 0x00000200
+#define BIT_HDIRDRIVE 0x00000400
+#define BIT_LOGSCRIPT 0x00000800
+#define BIT_PROFILE 0x00001000
+#define BIT_MACHINE 0x00002000
+#define BIT_USERDOMAIN 0x00004000
+#define BIT_USER 0x00008000
+#define BIT_LIST 0x00010000
+#define BIT_MODIFY 0x00020000
+#define BIT_CREATE 0x00040000
+#define BIT_DELETE 0x00080000
+#define BIT_ACCPOLICY 0x00100000
+#define BIT_ACCPOLVAL 0x00200000
+#define BIT_ACCTCTRL 0x00400000
+#define BIT_RESERV_7 0x00800000
+#define BIT_IMPORT 0x01000000
+#define BIT_EXPORT 0x02000000
+#define BIT_FIX_INIT 0x04000000
+#define BIT_BADPWRESET 0x08000000
+#define BIT_LOGONHOURS 0x10000000
+
+#define MASK_ALWAYS_GOOD 0x0000001F
+#define MASK_USER_GOOD 0x00405FE0
+
+/*********************************************************
+ Add all currently available users to another db
+ ********************************************************/
+
+static int export_database (struct pdb_methods *in,
+ struct pdb_methods *out,
+ const char *username)
+{
+ NTSTATUS status;
+ struct pdb_search *u_search;
+ struct samr_displayentry userentry;
+
+ DEBUG(3, ("export_database: username=\"%s\"\n", username ? username : "(NULL)"));
+
+ u_search = pdb_search_init(PDB_USER_SEARCH);
+ if (u_search == NULL) {
+ DEBUG(0, ("pdb_search_init failed\n"));
+ return 1;
+ }
+
+ if (!in->search_users(in, u_search, 0)) {
+ DEBUG(0, ("Could not start searching users\n"));
+ pdb_search_destroy(u_search);
+ return 1;
+ }
+
+ while (u_search->next_entry(u_search, &userentry)) {
+ struct samu *user;
+ struct samu *account;
+ DOM_SID user_sid;
+
+ DEBUG(4, ("Processing account %s\n", userentry.account_name));
+
+ if ((username != NULL)
+ && (strcmp(username, userentry.account_name) != 0)) {
+ /*
+ * ignore unwanted users
+ */
+ continue;
+ }
+
+ user = samu_new(talloc_tos());
+ if (user == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ break;
+ }
+
+ sid_compose(&user_sid, get_global_sam_sid(), userentry.rid);
+
+ status = in->getsampwsid(in, user, &user_sid);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(2, ("getsampwsid failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(user);
+ continue;
+ }
+
+ account = samu_new(NULL);
+ if (account == NULL) {
+ fprintf(stderr, "export_database: Memory allocation "
+ "failure!\n");
+ TALLOC_FREE( user );
+ pdb_search_destroy(u_search);
+ return 1;
+ }
+
+ printf("Importing account for %s...", user->username);
+ status = out->getsampwnam(out, account, user->username);
+
+ if (NT_STATUS_IS_OK(status)) {
+ status = out->update_sam_account( out, user );
+ } else {
+ status = out->add_sam_account(out, user);
+ }
+
+ if ( NT_STATUS_IS_OK(status) ) {
+ printf( "ok\n");
+ } else {
+ printf( "failed\n");
+ }
+
+ TALLOC_FREE( account );
+ TALLOC_FREE( user );
+ }
+
+ pdb_search_destroy(u_search);
+
+ return 0;
+}
+
+/*********************************************************
+ Add all currently available group mappings to another db
+ ********************************************************/
+
+static int export_groups (struct pdb_methods *in, struct pdb_methods *out)
+{
+ GROUP_MAP *maps = NULL;
+ size_t i, entries = 0;
+ NTSTATUS status;
+
+ status = in->enum_group_mapping(in, get_global_sam_sid(),
+ SID_NAME_DOM_GRP, &maps, &entries, False);
+
+ if ( NT_STATUS_IS_ERR(status) ) {
+ fprintf(stderr, "Unable to enumerate group map entries.\n");
+ return 1;
+ }
+
+ for (i=0; i<entries; i++) {
+ out->add_group_mapping_entry(out, &(maps[i]));
+ }
+
+ SAFE_FREE( maps );
+
+ return 0;
+}
+
+/*********************************************************
+ Reset account policies to their default values and remove marker
+ ********************************************************/
+
+static int reinit_account_policies (void)
+{
+ int i;
+
+ for (i=1; decode_account_policy_name(i) != NULL; i++) {
+ uint32 policy_value;
+ if (!account_policy_get_default(i, &policy_value)) {
+ fprintf(stderr, "Can't get default account policy\n");
+ return -1;
+ }
+ if (!account_policy_set(i, policy_value)) {
+ fprintf(stderr, "Can't set account policy in tdb\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+/*********************************************************
+ Add all currently available account policy from tdb to one backend
+ ********************************************************/
+
+static int export_account_policies (struct pdb_methods *in, struct pdb_methods *out)
+{
+ int i;
+
+ for ( i=1; decode_account_policy_name(i) != NULL; i++ ) {
+ uint32 policy_value;
+ NTSTATUS status;
+
+ status = in->get_account_policy(in, i, &policy_value);
+
+ if ( NT_STATUS_IS_ERR(status) ) {
+ fprintf(stderr, "Unable to get account policy from %s\n", in->name);
+ return -1;
+ }
+
+ status = out->set_account_policy(out, i, policy_value);
+
+ if ( NT_STATUS_IS_ERR(status) ) {
+ fprintf(stderr, "Unable to migrate account policy to %s\n", out->name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+/*********************************************************
+ Print info from sam structure
+**********************************************************/
+
+static int print_sam_info (struct samu *sam_pwent, bool verbosity, bool smbpwdstyle)
+{
+ uid_t uid;
+ time_t tmp;
+
+ /* TODO: chaeck if entry is a user or a workstation */
+ if (!sam_pwent) return -1;
+
+ if (verbosity) {
+ char temp[44];
+ const uint8 *hours;
+
+ printf ("Unix username: %s\n", pdb_get_username(sam_pwent));
+ printf ("NT username: %s\n", pdb_get_nt_username(sam_pwent));
+ printf ("Account Flags: %s\n", pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sam_pwent), NEW_PW_FORMAT_SPACE_PADDED_LEN));
+ printf ("User SID: %s\n",
+ sid_string_tos(pdb_get_user_sid(sam_pwent)));
+ printf ("Primary Group SID: %s\n",
+ sid_string_tos(pdb_get_group_sid(sam_pwent)));
+ printf ("Full Name: %s\n", pdb_get_fullname(sam_pwent));
+ printf ("Home Directory: %s\n", pdb_get_homedir(sam_pwent));
+ printf ("HomeDir Drive: %s\n", pdb_get_dir_drive(sam_pwent));
+ printf ("Logon Script: %s\n", pdb_get_logon_script(sam_pwent));
+ printf ("Profile Path: %s\n", pdb_get_profile_path(sam_pwent));
+ printf ("Domain: %s\n", pdb_get_domain(sam_pwent));
+ printf ("Account desc: %s\n", pdb_get_acct_desc(sam_pwent));
+ printf ("Workstations: %s\n", pdb_get_workstations(sam_pwent));
+ printf ("Munged dial: %s\n", pdb_get_munged_dial(sam_pwent));
+
+ tmp = pdb_get_logon_time(sam_pwent);
+ printf ("Logon time: %s\n", tmp ? http_timestring(tmp) : "0");
+
+ tmp = pdb_get_logoff_time(sam_pwent);
+ printf ("Logoff time: %s\n", tmp ? http_timestring(tmp) : "0");
+
+ tmp = pdb_get_kickoff_time(sam_pwent);
+ printf ("Kickoff time: %s\n", tmp ? http_timestring(tmp) : "0");
+
+ tmp = pdb_get_pass_last_set_time(sam_pwent);
+ printf ("Password last set: %s\n", tmp ? http_timestring(tmp) : "0");
+
+ tmp = pdb_get_pass_can_change_time(sam_pwent);
+ printf ("Password can change: %s\n", tmp ? http_timestring(tmp) : "0");
+
+ tmp = pdb_get_pass_must_change_time(sam_pwent);
+ printf ("Password must change: %s\n", tmp ? http_timestring(tmp) : "0");
+
+ tmp = pdb_get_bad_password_time(sam_pwent);
+ printf ("Last bad password : %s\n", tmp ? http_timestring(tmp) : "0");
+ printf ("Bad password count : %d\n",
+ pdb_get_bad_password_count(sam_pwent));
+
+ hours = pdb_get_hours(sam_pwent);
+ pdb_sethexhours(temp, hours);
+ printf ("Logon hours : %s\n", temp);
+
+ } else if (smbpwdstyle) {
+ char lm_passwd[33];
+ char nt_passwd[33];
+
+ uid = nametouid(pdb_get_username(sam_pwent));
+ pdb_sethexpwd(lm_passwd, pdb_get_lanman_passwd(sam_pwent), pdb_get_acct_ctrl(sam_pwent));
+ pdb_sethexpwd(nt_passwd, pdb_get_nt_passwd(sam_pwent), pdb_get_acct_ctrl(sam_pwent));
+
+ printf("%s:%lu:%s:%s:%s:LCT-%08X:\n",
+ pdb_get_username(sam_pwent),
+ (unsigned long)uid,
+ lm_passwd,
+ nt_passwd,
+ pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sam_pwent),NEW_PW_FORMAT_SPACE_PADDED_LEN),
+ (uint32)convert_time_t_to_uint32(pdb_get_pass_last_set_time(sam_pwent)));
+ } else {
+ uid = nametouid(pdb_get_username(sam_pwent));
+ printf ("%s:%lu:%s\n", pdb_get_username(sam_pwent), (unsigned long)uid,
+ pdb_get_fullname(sam_pwent));
+ }
+
+ return 0;
+}
+
+/*********************************************************
+ Get an Print User Info
+**********************************************************/
+
+static int print_user_info (struct pdb_methods *in, const char *username, bool verbosity, bool smbpwdstyle)
+{
+ struct samu *sam_pwent=NULL;
+ bool ret;
+
+ if ( (sam_pwent = samu_new( NULL )) == NULL ) {
+ return -1;
+ }
+
+ ret = NT_STATUS_IS_OK(in->getsampwnam (in, sam_pwent, username));
+
+ if (ret==False) {
+ fprintf (stderr, "Username not found!\n");
+ TALLOC_FREE(sam_pwent);
+ return -1;
+ }
+
+ ret=print_sam_info (sam_pwent, verbosity, smbpwdstyle);
+ TALLOC_FREE(sam_pwent);
+
+ return ret;
+}
+
+/*********************************************************
+ List Users
+**********************************************************/
+static int print_users_list (struct pdb_methods *in, bool verbosity, bool smbpwdstyle)
+{
+ struct pdb_search *u_search;
+ struct samr_displayentry userentry;
+
+ u_search = pdb_search_init(PDB_USER_SEARCH);
+ if (u_search == NULL) {
+ DEBUG(0, ("pdb_search_init failed\n"));
+ return 1;
+ }
+
+ if (!in->search_users(in, u_search, 0)) {
+ DEBUG(0, ("Could not start searching users\n"));
+ pdb_search_destroy(u_search);
+ return 1;
+ }
+
+ while (u_search->next_entry(u_search, &userentry)) {
+ struct samu *sam_pwent;
+ DOM_SID user_sid;
+ NTSTATUS status;
+
+ sam_pwent = samu_new(talloc_tos());
+ if (sam_pwent == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ break;
+ }
+
+ sid_compose(&user_sid, get_global_sam_sid(), userentry.rid);
+
+ status = in->getsampwsid(in, sam_pwent, &user_sid);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(2, ("getsampwsid failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(sam_pwent);
+ continue;
+ }
+
+ if (verbosity)
+ printf ("---------------\n");
+ print_sam_info (sam_pwent, verbosity, smbpwdstyle);
+ TALLOC_FREE(sam_pwent);
+ }
+ pdb_search_destroy(u_search);
+
+ return 0;
+}
+
+/*********************************************************
+ Fix a list of Users for uninitialised passwords
+**********************************************************/
+static int fix_users_list (struct pdb_methods *in)
+{
+ struct pdb_search *u_search;
+ struct samr_displayentry userentry;
+
+ u_search = pdb_search_init(PDB_USER_SEARCH);
+ if (u_search == NULL) {
+ DEBUG(0, ("pdb_search_init failed\n"));
+ return 1;
+ }
+
+ if (!in->search_users(in, u_search, 0)) {
+ DEBUG(0, ("Could not start searching users\n"));
+ pdb_search_destroy(u_search);
+ return 1;
+ }
+
+ while (u_search->next_entry(u_search, &userentry)) {
+ struct samu *sam_pwent;
+ DOM_SID user_sid;
+ NTSTATUS status;
+
+ sam_pwent = samu_new(talloc_tos());
+ if (sam_pwent == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ break;
+ }
+
+ sid_compose(&user_sid, get_global_sam_sid(), userentry.rid);
+
+ status = in->getsampwsid(in, sam_pwent, &user_sid);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(2, ("getsampwsid failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(sam_pwent);
+ continue;
+ }
+
+ if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_pwent))) {
+ printf("Update of user %s failed!\n",
+ pdb_get_username(sam_pwent));
+ }
+ TALLOC_FREE(sam_pwent);
+ }
+ pdb_search_destroy(u_search);
+ return 0;
+}
+
+/*********************************************************
+ Set User Info
+**********************************************************/
+
+static int set_user_info (struct pdb_methods *in, const char *username,
+ const char *fullname, const char *homedir,
+ const char *acct_desc,
+ const char *drive, const char *script,
+ const char *profile, const char *account_control,
+ const char *user_sid, const char *user_domain,
+ const bool badpw, const bool hours)
+{
+ bool updated_autolock = False, updated_badpw = False;
+ struct samu *sam_pwent=NULL;
+ bool ret;
+
+ if ( (sam_pwent = samu_new( NULL )) == NULL ) {
+ return 1;
+ }
+
+ ret = NT_STATUS_IS_OK(in->getsampwnam (in, sam_pwent, username));
+ if (ret==False) {
+ fprintf (stderr, "Username not found!\n");
+ TALLOC_FREE(sam_pwent);
+ return -1;
+ }
+
+ if (hours) {
+ uint8 hours_array[MAX_HOURS_LEN];
+ uint32 hours_len;
+
+ hours_len = pdb_get_hours_len(sam_pwent);
+ memset(hours_array, 0xff, hours_len);
+
+ pdb_set_hours(sam_pwent, hours_array, PDB_CHANGED);
+ }
+
+ if (!pdb_update_autolock_flag(sam_pwent, &updated_autolock)) {
+ DEBUG(2,("pdb_update_autolock_flag failed.\n"));
+ }
+
+ if (!pdb_update_bad_password_count(sam_pwent, &updated_badpw)) {
+ DEBUG(2,("pdb_update_bad_password_count failed.\n"));
+ }
+
+ if (fullname)
+ pdb_set_fullname(sam_pwent, fullname, PDB_CHANGED);
+ if (acct_desc)
+ pdb_set_acct_desc(sam_pwent, acct_desc, PDB_CHANGED);
+ if (homedir)
+ pdb_set_homedir(sam_pwent, homedir, PDB_CHANGED);
+ if (drive)
+ pdb_set_dir_drive(sam_pwent,drive, PDB_CHANGED);
+ if (script)
+ pdb_set_logon_script(sam_pwent, script, PDB_CHANGED);
+ if (profile)
+ pdb_set_profile_path (sam_pwent, profile, PDB_CHANGED);
+ if (user_domain)
+ pdb_set_domain(sam_pwent, user_domain, PDB_CHANGED);
+
+ if (account_control) {
+ uint32 not_settable = ~(ACB_DISABLED|ACB_HOMDIRREQ|ACB_PWNOTREQ|
+ ACB_PWNOEXP|ACB_AUTOLOCK);
+
+ uint32 newflag = pdb_decode_acct_ctrl(account_control);
+
+ if (newflag & not_settable) {
+ fprintf(stderr, "Can only set [NDHLX] flags\n");
+ TALLOC_FREE(sam_pwent);
+ return -1;
+ }
+
+ pdb_set_acct_ctrl(sam_pwent,
+ (pdb_get_acct_ctrl(sam_pwent) & not_settable) | newflag,
+ PDB_CHANGED);
+ }
+ if (user_sid) {
+ DOM_SID u_sid;
+ if (!string_to_sid(&u_sid, user_sid)) {
+ /* not a complete sid, may be a RID, try building a SID */
+ int u_rid;
+
+ if (sscanf(user_sid, "%d", &u_rid) != 1) {
+ fprintf(stderr, "Error passed string is not a complete user SID or RID!\n");
+ return -1;
+ }
+ sid_copy(&u_sid, get_global_sam_sid());
+ sid_append_rid(&u_sid, u_rid);
+ }
+ pdb_set_user_sid (sam_pwent, &u_sid, PDB_CHANGED);
+ }
+
+ if (badpw) {
+ pdb_set_bad_password_count(sam_pwent, 0, PDB_CHANGED);
+ pdb_set_bad_password_time(sam_pwent, 0, PDB_CHANGED);
+ }
+
+ if (NT_STATUS_IS_OK(in->update_sam_account (in, sam_pwent)))
+ print_user_info (in, username, True, False);
+ else {
+ fprintf (stderr, "Unable to modify entry!\n");
+ TALLOC_FREE(sam_pwent);
+ return -1;
+ }
+ TALLOC_FREE(sam_pwent);
+ return 0;
+}
+
+/*********************************************************
+ Add New User
+**********************************************************/
+static int new_user (struct pdb_methods *in, const char *username,
+ const char *fullname, const char *homedir,
+ const char *drive, const char *script,
+ const char *profile, char *user_sid, bool stdin_get)
+{
+ struct samu *sam_pwent;
+ char *password1, *password2;
+ int rc_pwd_cmp;
+ struct passwd *pwd;
+
+ get_global_sam_sid();
+
+ if ( !(pwd = getpwnam_alloc( NULL, username )) ) {
+ DEBUG(0,("Cannot locate Unix account for %s\n", username));
+ return -1;
+ }
+
+ if ( (sam_pwent = samu_new( NULL )) == NULL ) {
+ DEBUG(0, ("Memory allocation failure!\n"));
+ return -1;
+ }
+
+ if (!NT_STATUS_IS_OK(samu_alloc_rid_unix(sam_pwent, pwd ))) {
+ TALLOC_FREE( sam_pwent );
+ TALLOC_FREE( pwd );
+ DEBUG(0, ("could not create account to add new user %s\n", username));
+ return -1;
+ }
+
+ password1 = get_pass( "new password:", stdin_get);
+ password2 = get_pass( "retype new password:", stdin_get);
+ if ((rc_pwd_cmp = strcmp (password1, password2))) {
+ fprintf (stderr, "Passwords do not match!\n");
+ TALLOC_FREE(sam_pwent);
+ } else {
+ pdb_set_plaintext_passwd(sam_pwent, password1);
+ }
+
+ memset(password1, 0, strlen(password1));
+ SAFE_FREE(password1);
+ memset(password2, 0, strlen(password2));
+ SAFE_FREE(password2);
+
+ /* pwds do _not_ match? */
+ if (rc_pwd_cmp)
+ return -1;
+
+ if (fullname)
+ pdb_set_fullname(sam_pwent, fullname, PDB_CHANGED);
+ if (homedir)
+ pdb_set_homedir (sam_pwent, homedir, PDB_CHANGED);
+ if (drive)
+ pdb_set_dir_drive (sam_pwent, drive, PDB_CHANGED);
+ if (script)
+ pdb_set_logon_script(sam_pwent, script, PDB_CHANGED);
+ if (profile)
+ pdb_set_profile_path (sam_pwent, profile, PDB_CHANGED);
+ if (user_sid) {
+ DOM_SID u_sid;
+ if (!string_to_sid(&u_sid, user_sid)) {
+ /* not a complete sid, may be a RID, try building a SID */
+ int u_rid;
+
+ if (sscanf(user_sid, "%d", &u_rid) != 1) {
+ fprintf(stderr, "Error passed string is not a complete user SID or RID!\n");
+ TALLOC_FREE(sam_pwent);
+ return -1;
+ }
+ sid_copy(&u_sid, get_global_sam_sid());
+ sid_append_rid(&u_sid, u_rid);
+ }
+ pdb_set_user_sid (sam_pwent, &u_sid, PDB_CHANGED);
+ }
+
+ pdb_set_acct_ctrl (sam_pwent, ACB_NORMAL, PDB_CHANGED);
+
+ if (NT_STATUS_IS_OK(in->add_sam_account (in, sam_pwent))) {
+ print_user_info (in, username, True, False);
+ } else {
+ fprintf (stderr, "Unable to add user! (does it already exist?)\n");
+ TALLOC_FREE(sam_pwent);
+ return -1;
+ }
+ TALLOC_FREE(sam_pwent);
+ return 0;
+}
+
+/*********************************************************
+ Add New Machine
+**********************************************************/
+
+static int new_machine (struct pdb_methods *in, const char *machine_in)
+{
+ struct samu *sam_pwent=NULL;
+ fstring machinename;
+ fstring machineaccount;
+ struct passwd *pwd = NULL;
+
+ get_global_sam_sid();
+
+ if (strlen(machine_in) == 0) {
+ fprintf(stderr, "No machine name given\n");
+ return -1;
+ }
+
+ fstrcpy(machinename, machine_in);
+ machinename[15]= '\0';
+
+ if (machinename[strlen (machinename) -1] == '$')
+ machinename[strlen (machinename) -1] = '\0';
+
+ strlower_m(machinename);
+
+ fstrcpy(machineaccount, machinename);
+ fstrcat(machineaccount, "$");
+
+ if ( !(pwd = getpwnam_alloc( NULL, machineaccount )) ) {
+ DEBUG(0,("Cannot locate Unix account for %s\n", machineaccount));
+ return -1;
+ }
+
+ if ( (sam_pwent = samu_new( NULL )) == NULL ) {
+ fprintf(stderr, "Memory allocation error!\n");
+ TALLOC_FREE(pwd);
+ return -1;
+ }
+
+ if ( !NT_STATUS_IS_OK(samu_alloc_rid_unix(sam_pwent, pwd )) ) {
+ fprintf(stderr, "Could not init sam from pw\n");
+ TALLOC_FREE(pwd);
+ return -1;
+ }
+
+ TALLOC_FREE(pwd);
+
+ pdb_set_plaintext_passwd (sam_pwent, machinename);
+ pdb_set_username (sam_pwent, machineaccount, PDB_CHANGED);
+ pdb_set_acct_ctrl (sam_pwent, ACB_WSTRUST, PDB_CHANGED);
+
+ if (NT_STATUS_IS_OK(in->add_sam_account (in, sam_pwent))) {
+ print_user_info (in, machineaccount, True, False);
+ } else {
+ fprintf (stderr, "Unable to add machine! (does it already exist?)\n");
+ TALLOC_FREE(sam_pwent);
+ return -1;
+ }
+ TALLOC_FREE(sam_pwent);
+ return 0;
+}
+
+/*********************************************************
+ Delete user entry
+**********************************************************/
+
+static int delete_user_entry (struct pdb_methods *in, const char *username)
+{
+ struct samu *samaccount = NULL;
+
+ if ( (samaccount = samu_new( NULL )) == NULL ) {
+ return -1;
+ }
+
+ if (!NT_STATUS_IS_OK(in->getsampwnam(in, samaccount, username))) {
+ fprintf (stderr, "user %s does not exist in the passdb\n", username);
+ return -1;
+ }
+
+ if (!NT_STATUS_IS_OK(in->delete_sam_account (in, samaccount))) {
+ fprintf (stderr, "Unable to delete user %s\n", username);
+ return -1;
+ }
+ return 0;
+}
+
+/*********************************************************
+ Delete machine entry
+**********************************************************/
+
+static int delete_machine_entry (struct pdb_methods *in, const char *machinename)
+{
+ fstring name;
+ struct samu *samaccount = NULL;
+
+ if (strlen(machinename) == 0) {
+ fprintf(stderr, "No machine name given\n");
+ return -1;
+ }
+
+ fstrcpy(name, machinename);
+ name[15] = '\0';
+ if (name[strlen(name)-1] != '$')
+ fstrcat (name, "$");
+
+ if ( (samaccount = samu_new( NULL )) == NULL ) {
+ return -1;
+ }
+
+ if (!NT_STATUS_IS_OK(in->getsampwnam(in, samaccount, name))) {
+ fprintf (stderr, "machine %s does not exist in the passdb\n", name);
+ return -1;
+ }
+
+ if (!NT_STATUS_IS_OK(in->delete_sam_account (in, samaccount))) {
+ fprintf (stderr, "Unable to delete machine %s\n", name);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*********************************************************
+ Start here.
+**********************************************************/
+
+int main (int argc, char **argv)
+{
+ static int list_users = False;
+ static int verbose = False;
+ static int spstyle = False;
+ static int machine = False;
+ static int add_user = False;
+ static int delete_user = False;
+ static int modify_user = False;
+ uint32 setparms, checkparms;
+ int opt;
+ static char *full_name = NULL;
+ static char *acct_desc = NULL;
+ static const char *user_name = NULL;
+ static char *home_dir = NULL;
+ static char *home_drive = NULL;
+ static char *backend = NULL;
+ static char *backend_in = NULL;
+ static char *backend_out = NULL;
+ static int transfer_groups = False;
+ static int transfer_account_policies = False;
+ static int reset_account_policies = False;
+ static int force_initialised_password = False;
+ static char *logon_script = NULL;
+ static char *profile_path = NULL;
+ static char *user_domain = NULL;
+ static char *account_control = NULL;
+ static char *account_policy = NULL;
+ static char *user_sid = NULL;
+ static long int account_policy_value = 0;
+ bool account_policy_value_set = False;
+ static int badpw_reset = False;
+ static int hours_reset = False;
+ static char *pwd_time_format = NULL;
+ static int pw_from_stdin = False;
+ struct pdb_methods *bin, *bout, *bdef;
+ char *configfile = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+ poptContext pc;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"list", 'L', POPT_ARG_NONE, &list_users, 0, "list all users", NULL},
+ {"verbose", 'v', POPT_ARG_NONE, &verbose, 0, "be verbose", NULL },
+ {"smbpasswd-style", 'w',POPT_ARG_NONE, &spstyle, 0, "give output in smbpasswd style", NULL},
+ {"user", 'u', POPT_ARG_STRING, &user_name, 0, "use username", "USER" },
+ {"account-desc", 'N', POPT_ARG_STRING, &acct_desc, 0, "set account description", NULL},
+ {"fullname", 'f', POPT_ARG_STRING, &full_name, 0, "set full name", NULL},
+ {"homedir", 'h', POPT_ARG_STRING, &home_dir, 0, "set home directory", NULL},
+ {"drive", 'D', POPT_ARG_STRING, &home_drive, 0, "set home drive", NULL},
+ {"script", 'S', POPT_ARG_STRING, &logon_script, 0, "set logon script", NULL},
+ {"profile", 'p', POPT_ARG_STRING, &profile_path, 0, "set profile path", NULL},
+ {"domain", 'I', POPT_ARG_STRING, &user_domain, 0, "set a users' domain", NULL},
+ {"user SID", 'U', POPT_ARG_STRING, &user_sid, 0, "set user SID or RID", NULL},
+ {"create", 'a', POPT_ARG_NONE, &add_user, 0, "create user", NULL},
+ {"modify", 'r', POPT_ARG_NONE, &modify_user, 0, "modify user", NULL},
+ {"machine", 'm', POPT_ARG_NONE, &machine, 0, "account is a machine account", NULL},
+ {"delete", 'x', POPT_ARG_NONE, &delete_user, 0, "delete user", NULL},
+ {"backend", 'b', POPT_ARG_STRING, &backend, 0, "use different passdb backend as default backend", NULL},
+ {"import", 'i', POPT_ARG_STRING, &backend_in, 0, "import user accounts from this backend", NULL},
+ {"export", 'e', POPT_ARG_STRING, &backend_out, 0, "export user accounts to this backend", NULL},
+ {"group", 'g', POPT_ARG_NONE, &transfer_groups, 0, "use -i and -e for groups", NULL},
+ {"policies", 'y', POPT_ARG_NONE, &transfer_account_policies, 0, "use -i and -e to move account policies between backends", NULL},
+ {"policies-reset", 0, POPT_ARG_NONE, &reset_account_policies, 0, "restore default policies", NULL},
+ {"account-policy", 'P', POPT_ARG_STRING, &account_policy, 0,"value of an account policy (like maximum password age)",NULL},
+ {"value", 'C', POPT_ARG_LONG, &account_policy_value, 'C',"set the account policy to this value", NULL},
+ {"account-control", 'c', POPT_ARG_STRING, &account_control, 0, "Values of account control", NULL},
+ {"force-initialized-passwords", 0, POPT_ARG_NONE, &force_initialised_password, 0, "Force initialization of corrupt password strings in a passdb backend", NULL},
+ {"bad-password-count-reset", 'z', POPT_ARG_NONE, &badpw_reset, 0, "reset bad password count", NULL},
+ {"logon-hours-reset", 'Z', POPT_ARG_NONE, &hours_reset, 0, "reset logon hours", NULL},
+ {"time-format", 0, POPT_ARG_STRING, &pwd_time_format, 0, "The time format for time parameters", NULL },
+ {"password-from-stdin", 't', POPT_ARG_NONE, &pw_from_stdin, 0, "get password from standard in", NULL},
+ POPT_COMMON_SAMBA
+ POPT_TABLEEND
+ };
+
+ /* we shouldn't have silly checks like this */
+ if (getuid() != 0) {
+ d_fprintf(stderr, "You must be root to use pdbedit\n");
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ bin = bout = bdef = NULL;
+
+ load_case_tables();
+
+ setup_logging("pdbedit", True);
+
+ pc = poptGetContext(NULL, argc, (const char **) argv, long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'C':
+ account_policy_value_set = True;
+ break;
+ case 's':
+ configfile = optarg;
+ break;
+ }
+ }
+
+ poptGetArg(pc); /* Drop argv[0], the program name */
+
+ if (user_name == NULL)
+ user_name = poptGetArg(pc);
+
+ if (!lp_load(get_dyn_CONFIGFILE(),True,False,False,True)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n", get_dyn_CONFIGFILE());
+ exit(1);
+ }
+
+ if(!initialize_password_db(False, NULL))
+ exit(1);
+
+ if (!init_names())
+ exit(1);
+
+ setparms = (backend ? BIT_BACKEND : 0) +
+ (verbose ? BIT_VERBOSE : 0) +
+ (spstyle ? BIT_SPSTYLE : 0) +
+ (full_name ? BIT_FULLNAME : 0) +
+ (home_dir ? BIT_HOMEDIR : 0) +
+ (home_drive ? BIT_HDIRDRIVE : 0) +
+ (logon_script ? BIT_LOGSCRIPT : 0) +
+ (profile_path ? BIT_PROFILE : 0) +
+ (user_domain ? BIT_USERDOMAIN : 0) +
+ (machine ? BIT_MACHINE : 0) +
+ (user_name ? BIT_USER : 0) +
+ (list_users ? BIT_LIST : 0) +
+ (force_initialised_password ? BIT_FIX_INIT : 0) +
+ (user_sid ? BIT_USERSIDS : 0) +
+ (modify_user ? BIT_MODIFY : 0) +
+ (add_user ? BIT_CREATE : 0) +
+ (delete_user ? BIT_DELETE : 0) +
+ (account_control ? BIT_ACCTCTRL : 0) +
+ (account_policy ? BIT_ACCPOLICY : 0) +
+ (account_policy_value_set ? BIT_ACCPOLVAL : 0) +
+ (backend_in ? BIT_IMPORT : 0) +
+ (backend_out ? BIT_EXPORT : 0) +
+ (badpw_reset ? BIT_BADPWRESET : 0) +
+ (hours_reset ? BIT_LOGONHOURS : 0);
+
+ if (setparms & BIT_BACKEND) {
+ if (!NT_STATUS_IS_OK(make_pdb_method_name( &bdef, backend ))) {
+ fprintf(stderr, "Can't initialize passdb backend.\n");
+ return 1;
+ }
+ } else {
+ if (!NT_STATUS_IS_OK(make_pdb_method_name(&bdef, lp_passdb_backend()))) {
+ fprintf(stderr, "Can't initialize passdb backend.\n");
+ return 1;
+ }
+ }
+
+ /* the lowest bit options are always accepted */
+ checkparms = setparms & ~MASK_ALWAYS_GOOD;
+
+ if (checkparms & BIT_FIX_INIT) {
+ return fix_users_list(bdef);
+ }
+
+ /* account policy operations */
+ if ((checkparms & BIT_ACCPOLICY) && !(checkparms & ~(BIT_ACCPOLICY + BIT_ACCPOLVAL))) {
+ uint32 value;
+ int field = account_policy_name_to_fieldnum(account_policy);
+ if (field == 0) {
+ const char **names;
+ int count;
+ int i;
+ account_policy_names_list(&names, &count);
+ fprintf(stderr, "No account policy by that name!\n");
+ if (count !=0) {
+ fprintf(stderr, "Account policy names are:\n");
+ for (i = 0; i < count ; i++) {
+ d_fprintf(stderr, "%s\n", names[i]);
+ }
+ }
+ SAFE_FREE(names);
+ exit(1);
+ }
+ if (!pdb_get_account_policy(field, &value)) {
+ fprintf(stderr, "valid account policy, but unable to fetch value!\n");
+ if (!account_policy_value_set)
+ exit(1);
+ }
+ printf("account policy \"%s\" description: %s\n", account_policy, account_policy_get_desc(field));
+ if (account_policy_value_set) {
+ printf("account policy \"%s\" value was: %u\n", account_policy, value);
+ if (!pdb_set_account_policy(field, account_policy_value)) {
+ fprintf(stderr, "valid account policy, but unable to set value!\n");
+ exit(1);
+ }
+ printf("account policy \"%s\" value is now: %lu\n", account_policy, account_policy_value);
+ exit(0);
+ } else {
+ printf("account policy \"%s\" value is: %u\n", account_policy, value);
+ exit(0);
+ }
+ }
+
+ if (reset_account_policies) {
+ if (!reinit_account_policies()) {
+ exit(1);
+ }
+
+ exit(0);
+ }
+
+ /* import and export operations */
+
+ if ( ((checkparms & BIT_IMPORT)
+ || (checkparms & BIT_EXPORT))
+ && !(checkparms & ~(BIT_IMPORT +BIT_EXPORT +BIT_USER)) )
+ {
+ NTSTATUS status;
+
+ bin = bout = bdef;
+
+ if (backend_in) {
+ status = make_pdb_method_name(&bin, backend_in);
+
+ if ( !NT_STATUS_IS_OK(status) ) {
+ fprintf(stderr, "Unable to initialize %s.\n", backend_in);
+ return 1;
+ }
+ }
+
+ if (backend_out) {
+ status = make_pdb_method_name(&bout, backend_out);
+
+ if ( !NT_STATUS_IS_OK(status) ) {
+ fprintf(stderr, "Unable to initialize %s.\n", backend_out);
+ return 1;
+ }
+ }
+
+ if (transfer_account_policies) {
+
+ if (!(checkparms & BIT_USER))
+ return export_account_policies(bin, bout);
+
+ } else if (transfer_groups) {
+
+ if (!(checkparms & BIT_USER))
+ return export_groups(bin, bout);
+
+ } else {
+ return export_database(bin, bout,
+ (checkparms & BIT_USER) ? user_name : NULL );
+ }
+ }
+
+ /* if BIT_USER is defined but nothing else then threat it as -l -u for compatibility */
+ /* fake up BIT_LIST if only BIT_USER is defined */
+ if ((checkparms & BIT_USER) && !(checkparms & ~BIT_USER)) {
+ checkparms += BIT_LIST;
+ }
+
+ /* modify flag is optional to maintain backwards compatibility */
+ /* fake up BIT_MODIFY if BIT_USER and at least one of MASK_USER_GOOD is defined */
+ if (!((checkparms & ~MASK_USER_GOOD) & ~BIT_USER) && (checkparms & MASK_USER_GOOD)) {
+ checkparms += BIT_MODIFY;
+ }
+
+ /* list users operations */
+ if (checkparms & BIT_LIST) {
+ if (!(checkparms & ~BIT_LIST)) {
+ return print_users_list (bdef, verbose, spstyle);
+ }
+ if (!(checkparms & ~(BIT_USER + BIT_LIST))) {
+ return print_user_info (bdef, user_name, verbose, spstyle);
+ }
+ }
+
+ /* mask out users options */
+ checkparms &= ~MASK_USER_GOOD;
+
+ /* if bad password count is reset, we must be modifying */
+ if (checkparms & BIT_BADPWRESET) {
+ checkparms |= BIT_MODIFY;
+ checkparms &= ~BIT_BADPWRESET;
+ }
+
+ /* if logon hours is reset, must modify */
+ if (checkparms & BIT_LOGONHOURS) {
+ checkparms |= BIT_MODIFY;
+ checkparms &= ~BIT_LOGONHOURS;
+ }
+
+ /* account operation */
+ if ((checkparms & BIT_CREATE) || (checkparms & BIT_MODIFY) || (checkparms & BIT_DELETE)) {
+ /* check use of -u option */
+ if (!(checkparms & BIT_USER)) {
+ fprintf (stderr, "Username not specified! (use -u option)\n");
+ return -1;
+ }
+
+ /* account creation operations */
+ if (!(checkparms & ~(BIT_CREATE + BIT_USER + BIT_MACHINE))) {
+ if (checkparms & BIT_MACHINE) {
+ return new_machine (bdef, user_name);
+ } else {
+ return new_user (bdef, user_name, full_name, home_dir,
+ home_drive, logon_script, profile_path, user_sid, pw_from_stdin);
+ }
+ }
+
+ /* account deletion operations */
+ if (!(checkparms & ~(BIT_DELETE + BIT_USER + BIT_MACHINE))) {
+ if (checkparms & BIT_MACHINE) {
+ return delete_machine_entry (bdef, user_name);
+ } else {
+ return delete_user_entry (bdef, user_name);
+ }
+ }
+
+ /* account modification operations */
+ if (!(checkparms & ~(BIT_MODIFY + BIT_USER))) {
+ return set_user_info (bdef, user_name, full_name, home_dir,
+ acct_desc, home_drive, logon_script, profile_path, account_control,
+ user_sid, user_domain, badpw_reset, hours_reset);
+ }
+ }
+
+ if (setparms >= 0x20) {
+ fprintf (stderr, "Incompatible or insufficient options on command line!\n");
+ }
+ poptPrintHelp(pc, stderr, 0);
+
+ TALLOC_FREE(frame);
+ return 1;
+}
diff --git a/source3/utils/profiles.c b/source3/utils/profiles.c
new file mode 100644
index 0000000000..0b8a0d4278
--- /dev/null
+++ b/source3/utils/profiles.c
@@ -0,0 +1,303 @@
+/*
+ Samba Unix/Linux SMB client utility profiles.c
+
+ Copyright (C) Richard Sharpe, <rsharpe@richardsharpe.com> 2002
+ Copyright (C) Jelmer Vernooij (conversion to popt) 2003
+ Copyright (C) Gerald (Jerry) Carter 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "regfio.h"
+
+/* GLOBAL VARIABLES */
+
+DOM_SID old_sid, new_sid;
+int change = 0, new_val = 0;
+int opt_verbose = False;
+
+/********************************************************************
+********************************************************************/
+
+static void verbose_output(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
+static void verbose_output(const char *format, ...)
+{
+ va_list args;
+ char *var = NULL;
+
+ if (!opt_verbose) {
+ return;
+ }
+
+ va_start(args, format);
+ if ((vasprintf(&var, format, args)) == -1) {
+ va_end(args);
+ return;
+ }
+
+ fprintf(stdout, var);
+ va_end(args);
+ SAFE_FREE(var);
+}
+
+/********************************************************************
+********************************************************************/
+
+static bool swap_sid_in_acl( SEC_DESC *sd, DOM_SID *s1, DOM_SID *s2 )
+{
+ SEC_ACL *acl;
+ int i;
+ bool update = False;
+
+ verbose_output(" Owner SID: %s\n", sid_string_tos(sd->owner_sid));
+ if ( sid_equal( sd->owner_sid, s1 ) ) {
+ sid_copy( sd->owner_sid, s2 );
+ update = True;
+ verbose_output(" New Owner SID: %s\n",
+ sid_string_tos(sd->owner_sid));
+
+ }
+
+ verbose_output(" Group SID: %s\n", sid_string_tos(sd->group_sid));
+ if ( sid_equal( sd->group_sid, s1 ) ) {
+ sid_copy( sd->group_sid, s2 );
+ update = True;
+ verbose_output(" New Group SID: %s\n",
+ sid_string_tos(sd->group_sid));
+ }
+
+ acl = sd->dacl;
+ verbose_output(" DACL: %d entries:\n", acl->num_aces);
+ for ( i=0; i<acl->num_aces; i++ ) {
+ verbose_output(" Trustee SID: %s\n",
+ sid_string_tos(&acl->aces[i].trustee));
+ if ( sid_equal( &acl->aces[i].trustee, s1 ) ) {
+ sid_copy( &acl->aces[i].trustee, s2 );
+ update = True;
+ verbose_output(" New Trustee SID: %s\n",
+ sid_string_tos(&acl->aces[i].trustee));
+ }
+ }
+
+#if 0
+ acl = sd->sacl;
+ verbose_output(" SACL: %d entries: \n", acl->num_aces);
+ for ( i=0; i<acl->num_aces; i++ ) {
+ verbose_output(" Trustee SID: %s\n",
+ sid_string_tos(&acl->aces[i].trustee));
+ if ( sid_equal( &acl->aces[i].trustee, s1 ) ) {
+ sid_copy( &acl->aces[i].trustee, s2 );
+ update = True;
+ verbose_output(" New Trustee SID: %s\n",
+ sid_string_tos(&acl->aces[i].trustee));
+ }
+ }
+#endif
+ return update;
+}
+
+/********************************************************************
+********************************************************************/
+
+static bool copy_registry_tree( REGF_FILE *infile, REGF_NK_REC *nk,
+ REGF_NK_REC *parent, REGF_FILE *outfile,
+ const char *parentpath )
+{
+ REGF_NK_REC *key, *subkey;
+ SEC_DESC *new_sd;
+ REGVAL_CTR *values;
+ REGSUBKEY_CTR *subkeys;
+ int i;
+ char *path;
+
+ /* swap out the SIDs in the security descriptor */
+
+ if ( !(new_sd = dup_sec_desc( outfile->mem_ctx, nk->sec_desc->sec_desc )) ) {
+ fprintf( stderr, "Failed to copy security descriptor!\n" );
+ return False;
+ }
+
+ verbose_output("ACL for %s%s%s\n", parentpath, parent ? "\\" : "", nk->keyname);
+ swap_sid_in_acl( new_sd, &old_sid, &new_sid );
+
+ if ( !(subkeys = TALLOC_ZERO_P( NULL, REGSUBKEY_CTR )) ) {
+ DEBUG(0,("copy_registry_tree: talloc() failure!\n"));
+ return False;
+ }
+
+ if ( !(values = TALLOC_ZERO_P( subkeys, REGVAL_CTR )) ) {
+ TALLOC_FREE( subkeys );
+ DEBUG(0,("copy_registry_tree: talloc() failure!\n"));
+ return False;
+ }
+
+ /* copy values into the REGVAL_CTR */
+
+ for ( i=0; i<nk->num_values; i++ ) {
+ regval_ctr_addvalue( values, nk->values[i].valuename, nk->values[i].type,
+ (const char *)nk->values[i].data, (nk->values[i].data_size & ~VK_DATA_IN_OFFSET) );
+ }
+
+ /* copy subkeys into the REGSUBKEY_CTR */
+
+ while ( (subkey = regfio_fetch_subkey( infile, nk )) ) {
+ regsubkey_ctr_addkey( subkeys, subkey->keyname );
+ }
+
+ key = regfio_write_key( outfile, nk->keyname, values, subkeys, new_sd, parent );
+
+ /* write each one of the subkeys out */
+
+ path = talloc_asprintf(subkeys, "%s%s%s",
+ parentpath, parent ? "\\" : "",nk->keyname);
+ if (!path) {
+ TALLOC_FREE( subkeys );
+ return false;
+ }
+
+ nk->subkey_index = 0;
+ while ((subkey = regfio_fetch_subkey(infile, nk))) {
+ if (!copy_registry_tree( infile, subkey, key, outfile, path)) {
+ TALLOC_FREE(subkeys);
+ return false;
+ }
+ }
+
+ /* values is a talloc()'d child of subkeys here so just throw it all away */
+
+ TALLOC_FREE( subkeys );
+
+ verbose_output("[%s]\n", path);
+
+ return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+int main( int argc, char *argv[] )
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ int opt;
+ REGF_FILE *infile, *outfile;
+ REGF_NK_REC *nk;
+ char *orig_filename, *new_filename;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "change-sid", 'c', POPT_ARG_STRING, NULL, 'c', "Provides SID to change" },
+ { "new-sid", 'n', POPT_ARG_STRING, NULL, 'n', "Provides SID to change to" },
+ { "verbose", 'v', POPT_ARG_NONE, &opt_verbose, 'v', "Verbose output" },
+ POPT_COMMON_SAMBA
+ POPT_COMMON_VERSION
+ POPT_TABLEEND
+ };
+ poptContext pc;
+
+ load_case_tables();
+
+ /* setup logging options */
+
+ setup_logging( "profiles", True );
+ dbf = x_stderr;
+ x_setbuf( x_stderr, NULL );
+
+ pc = poptGetContext("profiles", argc, (const char **)argv, long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+
+ poptSetOtherOptionHelp(pc, "<profilefile>");
+
+ /* Now, process the arguments */
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'c':
+ change = 1;
+ if (!string_to_sid(&old_sid, poptGetOptArg(pc))) {
+ fprintf(stderr, "Argument to -c should be a SID in form of S-1-5-...\n");
+ poptPrintUsage(pc, stderr, 0);
+ exit(254);
+ }
+ break;
+
+ case 'n':
+ new_val = 1;
+ if (!string_to_sid(&new_sid, poptGetOptArg(pc))) {
+ fprintf(stderr, "Argument to -n should be a SID in form of S-1-5-...\n");
+ poptPrintUsage(pc, stderr, 0);
+ exit(253);
+ }
+ break;
+
+ }
+ }
+
+ poptGetArg(pc);
+
+ if (!poptPeekArg(pc)) {
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+
+ if ((!change && new_val) || (change && !new_val)) {
+ fprintf(stderr, "You must specify both -c and -n if one or the other is set!\n");
+ poptPrintUsage(pc, stderr, 0);
+ exit(252);
+ }
+
+ orig_filename = talloc_strdup(frame, poptPeekArg(pc));
+ if (!orig_filename) {
+ exit(ENOMEM);
+ }
+ new_filename = talloc_asprintf(frame,
+ "%s.new",
+ orig_filename);
+ if (!new_filename) {
+ exit(ENOMEM);
+ }
+
+ if (!(infile = regfio_open( orig_filename, O_RDONLY, 0))) {
+ fprintf( stderr, "Failed to open %s!\n", orig_filename );
+ fprintf( stderr, "Error was (%s)\n", strerror(errno) );
+ exit (1);
+ }
+
+ if ( !(outfile = regfio_open( new_filename, (O_RDWR|O_CREAT|O_TRUNC), (S_IREAD|S_IWRITE) )) ) {
+ fprintf( stderr, "Failed to open new file %s!\n", new_filename );
+ fprintf( stderr, "Error was (%s)\n", strerror(errno) );
+ exit (1);
+ }
+
+ /* actually do the update now */
+
+ if ((nk = regfio_rootkey( infile )) == NULL) {
+ fprintf(stderr, "Could not get rootkey\n");
+ exit(3);
+ }
+
+ if (!copy_registry_tree( infile, nk, NULL, outfile, "")) {
+ fprintf(stderr, "Failed to write updated registry file!\n");
+ exit(2);
+ }
+
+ /* cleanup */
+
+ regfio_close(infile);
+ regfio_close(outfile);
+
+ poptFreeContext(pc);
+
+ TALLOC_FREE(frame);
+ return 0;
+}
diff --git a/source3/utils/rpccheck.c b/source3/utils/rpccheck.c
new file mode 100644
index 0000000000..87632db16d
--- /dev/null
+++ b/source3/utils/rpccheck.c
@@ -0,0 +1,62 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Jean François Micouleau 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+main()
+{
+ char filter[]="0123456789ABCDEF";
+
+ char s[128];
+ char d=0;
+ int x=0;
+ prs_struct ps;
+ TALLOC_CTX *ctx;
+
+ /* change that struct */
+ SAMR_R_QUERY_USERINFO rpc_stub;
+
+ ZERO_STRUCT(rpc_stub);
+
+ setup_logging("", True);
+ DEBUGLEVEL=10;
+
+ ctx=talloc_init("main");
+ if (!ctx) exit(1);
+
+ if (!prs_init(&ps, 1600, 4, ctx, MARSHALL))
+ exit(1);
+
+ while (scanf("%s", s)!=-1) {
+ if (strlen(s)==2 && strchr_m(filter, *s)!=NULL && strchr_m(filter, *(s+1))!=NULL) {
+ d=strtol(s, NULL, 16);
+ if(!prs_append_data(&ps, &d, 1))
+ printf("error while reading data\n");
+ }
+ }
+
+ prs_switch_type(&ps, UNMARSHALL);
+ prs_set_offset(&ps, 0);
+
+ /* change that call */
+ if(!samr_io_r_query_userinfo("", &rpc_stub, &ps, 0))
+ printf("error while UNMARSHALLING the data\n");
+
+ printf("\n");
+}
diff --git a/source3/utils/sharesec.c b/source3/utils/sharesec.c
new file mode 100644
index 0000000000..9409690c8b
--- /dev/null
+++ b/source3/utils/sharesec.c
@@ -0,0 +1,619 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Utility for managing share permissions
+ *
+ * Copyright (C) Tim Potter 2000
+ * Copyright (C) Jeremy Allison 2000
+ * Copyright (C) Jelmer Vernooij 2003
+ * Copyright (C) Gerald (Jerry) Carter 2005.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "includes.h"
+
+static TALLOC_CTX *ctx;
+
+enum acl_mode {SMB_ACL_DELETE, SMB_ACL_MODIFY, SMB_ACL_ADD, SMB_ACL_SET, SMB_ACL_VIEW };
+
+struct perm_value {
+ const char *perm;
+ uint32 mask;
+};
+
+/* These values discovered by inspection */
+
+static const struct perm_value special_values[] = {
+ { "R", SEC_RIGHTS_FILE_READ },
+ { "W", SEC_RIGHTS_FILE_WRITE },
+ { "X", SEC_RIGHTS_FILE_EXECUTE },
+ { "D", SEC_STD_DELETE },
+ { "P", SEC_STD_WRITE_DAC },
+ { "O", SEC_STD_WRITE_OWNER },
+ { NULL, 0 },
+};
+
+#define SEC_RIGHTS_DIR_CHANGE ( SEC_RIGHTS_DIR_READ|SEC_STD_DELETE|SEC_RIGHTS_DIR_WRITE|SEC_DIR_TRAVERSE )
+
+static const struct perm_value standard_values[] = {
+ { "READ", SEC_RIGHTS_DIR_READ|SEC_DIR_TRAVERSE },
+ { "CHANGE", SEC_RIGHTS_DIR_CHANGE },
+ { "FULL", SEC_RIGHTS_DIR_ALL },
+ { NULL, 0 },
+};
+
+/********************************************************************
+ print an ACE on a FILE
+********************************************************************/
+
+static void print_ace(FILE *f, SEC_ACE *ace)
+{
+ const struct perm_value *v;
+ int do_print = 0;
+ uint32 got_mask;
+
+ fprintf(f, "%s:", sid_string_tos(&ace->trustee));
+
+ /* Ace type */
+
+ if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) {
+ fprintf(f, "ALLOWED");
+ } else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) {
+ fprintf(f, "DENIED");
+ } else {
+ fprintf(f, "%d", ace->type);
+ }
+
+ /* Not sure what flags can be set in a file ACL */
+
+ fprintf(f, "/%d/", ace->flags);
+
+ /* Standard permissions */
+
+ for (v = standard_values; v->perm; v++) {
+ if (ace->access_mask == v->mask) {
+ fprintf(f, "%s", v->perm);
+ return;
+ }
+ }
+
+ /* Special permissions. Print out a hex value if we have
+ leftover bits in the mask. */
+
+ got_mask = ace->access_mask;
+
+ again:
+ for (v = special_values; v->perm; v++) {
+ if ((ace->access_mask & v->mask) == v->mask) {
+ if (do_print) {
+ fprintf(f, "%s", v->perm);
+ }
+ got_mask &= ~v->mask;
+ }
+ }
+
+ if (!do_print) {
+ if (got_mask != 0) {
+ fprintf(f, "0x%08x", ace->access_mask);
+ } else {
+ do_print = 1;
+ goto again;
+ }
+ }
+}
+
+/********************************************************************
+ print a ascii version of a security descriptor on a FILE handle
+********************************************************************/
+
+static void sec_desc_print(FILE *f, SEC_DESC *sd)
+{
+ uint32 i;
+
+ fprintf(f, "REVISION:%d\n", sd->revision);
+
+ /* Print owner and group sid */
+
+ fprintf(f, "OWNER:%s\n", sid_string_tos(sd->owner_sid));
+
+ fprintf(f, "GROUP:%s\n", sid_string_tos(sd->group_sid));
+
+ /* Print aces */
+ for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
+ SEC_ACE *ace = &sd->dacl->aces[i];
+ fprintf(f, "ACL:");
+ print_ace(f, ace);
+ fprintf(f, "\n");
+ }
+
+}
+
+/********************************************************************
+ parse an ACE in the same format as print_ace()
+********************************************************************/
+
+static bool parse_ace(SEC_ACE *ace, const char *orig_str)
+{
+ char *p;
+ const char *cp;
+ char *tok;
+ unsigned int atype = 0;
+ unsigned int aflags = 0;
+ unsigned int amask = 0;
+ DOM_SID sid;
+ SEC_ACCESS mask;
+ const struct perm_value *v;
+ char *str = SMB_STRDUP(orig_str);
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!str) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ ZERO_STRUCTP(ace);
+ p = strchr_m(str,':');
+ if (!p) {
+ printf("ACE '%s': missing ':'.\n", orig_str);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
+ return False;
+ }
+ *p = '\0';
+ p++;
+ /* Try to parse numeric form */
+
+ if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 &&
+ string_to_sid(&sid, str)) {
+ goto done;
+ }
+
+ /* Try to parse text form */
+
+ if (!string_to_sid(&sid, str)) {
+ printf("ACE '%s': failed to convert '%s' to SID\n",
+ orig_str, str);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ cp = p;
+ if (!next_token_talloc(frame, &cp, &tok, "/")) {
+ printf("ACE '%s': failed to find '/' character.\n",
+ orig_str);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ if (strncmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
+ atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ } else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) {
+ atype = SEC_ACE_TYPE_ACCESS_DENIED;
+ } else {
+ printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
+ orig_str, tok);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ /* Only numeric form accepted for flags at present */
+ /* no flags on share permissions */
+
+ if (!(next_token_talloc(frame, &cp, &tok, "/") &&
+ sscanf(tok, "%i", &aflags) && aflags == 0)) {
+ printf("ACE '%s': bad integer flags entry at '%s'\n",
+ orig_str, tok);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ if (!next_token_talloc(frame, &cp, &tok, "/")) {
+ printf("ACE '%s': missing / at '%s'\n",
+ orig_str, tok);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ if (strncmp(tok, "0x", 2) == 0) {
+ if (sscanf(tok, "%i", &amask) != 1) {
+ printf("ACE '%s': bad hex number at '%s'\n",
+ orig_str, tok);
+ TALLOC_FREE(frame);
+ SAFE_FREE(str);
+ return False;
+ }
+ goto done;
+ }
+
+ for (v = standard_values; v->perm; v++) {
+ if (strcmp(tok, v->perm) == 0) {
+ amask = v->mask;
+ goto done;
+ }
+ }
+
+ p = tok;
+
+ while(*p) {
+ bool found = False;
+
+ for (v = special_values; v->perm; v++) {
+ if (v->perm[0] == *p) {
+ amask |= v->mask;
+ found = True;
+ }
+ }
+
+ if (!found) {
+ printf("ACE '%s': bad permission value at '%s'\n",
+ orig_str, p);
+ TALLOC_FREE(frame);
+ SAFE_FREE(str);
+ return False;
+ }
+ p++;
+ }
+
+ if (*p) {
+ TALLOC_FREE(frame);
+ SAFE_FREE(str);
+ return False;
+ }
+
+ done:
+ mask = amask;
+ init_sec_ace(ace, &sid, atype, mask, aflags);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
+ return True;
+}
+
+
+/********************************************************************
+********************************************************************/
+
+static SEC_DESC* parse_acl_string(TALLOC_CTX *mem_ctx, const char *szACL, size_t *sd_size )
+{
+ SEC_DESC *sd = NULL;
+ SEC_ACE *ace;
+ SEC_ACL *acl;
+ int num_ace;
+ const char *pacl;
+ int i;
+
+ if ( !szACL )
+ return NULL;
+
+ pacl = szACL;
+ num_ace = count_chars( pacl, ',' ) + 1;
+
+ if ( !(ace = TALLOC_ZERO_ARRAY( mem_ctx, SEC_ACE, num_ace )) )
+ return NULL;
+
+ for ( i=0; i<num_ace; i++ ) {
+ char *end_acl = strchr_m( pacl, ',' );
+ fstring acl_string;
+
+ strncpy( acl_string, pacl, MIN( PTR_DIFF( end_acl, pacl ), sizeof(fstring)-1) );
+ acl_string[MIN( PTR_DIFF( end_acl, pacl ), sizeof(fstring)-1)] = '\0';
+
+ if ( !parse_ace( &ace[i], acl_string ) )
+ return NULL;
+
+ pacl = end_acl;
+ pacl++;
+ }
+
+ if ( !(acl = make_sec_acl( mem_ctx, NT4_ACL_REVISION, num_ace, ace )) )
+ return NULL;
+
+ sd = make_sec_desc( mem_ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
+ NULL, NULL, NULL, acl, sd_size);
+
+ return sd;
+}
+
+/* add an ACE to a list of ACEs in a SEC_ACL */
+static bool add_ace(TALLOC_CTX *mem_ctx, SEC_ACL **the_acl, SEC_ACE *ace)
+{
+ SEC_ACL *new_ace;
+ SEC_ACE *aces;
+ if (! *the_acl) {
+ return (((*the_acl) = make_sec_acl(mem_ctx, 3, 1, ace)) != NULL);
+ }
+
+ if (!(aces = SMB_CALLOC_ARRAY(SEC_ACE, 1+(*the_acl)->num_aces))) {
+ return False;
+ }
+ memcpy(aces, (*the_acl)->aces, (*the_acl)->num_aces * sizeof(SEC_ACE));
+ memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE));
+ new_ace = make_sec_acl(mem_ctx,(*the_acl)->revision,1+(*the_acl)->num_aces, aces);
+ SAFE_FREE(aces);
+ (*the_acl) = new_ace;
+ return True;
+}
+
+/* The MSDN is contradictory over the ordering of ACE entries in an ACL.
+ However NT4 gives a "The information may have been modified by a
+ computer running Windows NT 5.0" if denied ACEs do not appear before
+ allowed ACEs. */
+
+static int ace_compare(SEC_ACE *ace1, SEC_ACE *ace2)
+{
+ if (sec_ace_equal(ace1, ace2))
+ return 0;
+
+ if (ace1->type != ace2->type)
+ return ace2->type - ace1->type;
+
+ if (sid_compare(&ace1->trustee, &ace2->trustee))
+ return sid_compare(&ace1->trustee, &ace2->trustee);
+
+ if (ace1->flags != ace2->flags)
+ return ace1->flags - ace2->flags;
+
+ if (ace1->access_mask != ace2->access_mask)
+ return ace1->access_mask - ace2->access_mask;
+
+ if (ace1->size != ace2->size)
+ return ace1->size - ace2->size;
+
+ return memcmp(ace1, ace2, sizeof(SEC_ACE));
+}
+
+static void sort_acl(SEC_ACL *the_acl)
+{
+ uint32 i;
+ if (!the_acl) return;
+
+ qsort(the_acl->aces, the_acl->num_aces, sizeof(the_acl->aces[0]), QSORT_CAST ace_compare);
+
+ for (i=1;i<the_acl->num_aces;) {
+ if (sec_ace_equal(&the_acl->aces[i-1], &the_acl->aces[i])) {
+ int j;
+ for (j=i; j<the_acl->num_aces-1; j++) {
+ the_acl->aces[j] = the_acl->aces[j+1];
+ }
+ the_acl->num_aces--;
+ } else {
+ i++;
+ }
+ }
+}
+
+
+static int change_share_sec(TALLOC_CTX *mem_ctx, const char *sharename, char *the_acl, enum acl_mode mode)
+{
+ SEC_DESC *sd;
+ SEC_DESC *old = NULL;
+ size_t sd_size = 0;
+ uint32 i, j;
+
+ if (mode != SMB_ACL_SET) {
+ if (!(old = get_share_security( mem_ctx, sharename, &sd_size )) ) {
+ fprintf(stderr, "Unable to retrieve permissions for share [%s]\n", sharename);
+ return -1;
+ }
+ }
+
+ if ( (mode != SMB_ACL_VIEW) && !(sd = parse_acl_string(mem_ctx, the_acl, &sd_size )) ) {
+ fprintf( stderr, "Failed to parse acl\n");
+ return -1;
+ }
+
+ switch (mode) {
+ case SMB_ACL_VIEW:
+ sec_desc_print( stdout, old);
+ return 0;
+ case SMB_ACL_DELETE:
+ for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
+ bool found = False;
+
+ for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
+ if (sec_ace_equal(&sd->dacl->aces[i], &old->dacl->aces[j])) {
+ uint32 k;
+ for (k=j; k<old->dacl->num_aces-1;k++) {
+ old->dacl->aces[k] = old->dacl->aces[k+1];
+ }
+ old->dacl->num_aces--;
+ found = True;
+ break;
+ }
+ }
+
+ if (!found) {
+ printf("ACL for ACE:");
+ print_ace(stdout, &sd->dacl->aces[i]);
+ printf(" not found\n");
+ }
+ }
+
+ break;
+ case SMB_ACL_MODIFY:
+ for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
+ bool found = False;
+
+ for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
+ if (sid_equal(&sd->dacl->aces[i].trustee,
+ &old->dacl->aces[j].trustee)) {
+ old->dacl->aces[j] = sd->dacl->aces[i];
+ found = True;
+ }
+ }
+
+ if (!found) {
+ printf("ACL for SID %s not found\n",
+ sid_string_tos(&sd->dacl->aces[i].trustee));
+ }
+ }
+
+ if (sd->owner_sid) {
+ old->owner_sid = sd->owner_sid;
+ }
+
+ if (sd->group_sid) {
+ old->group_sid = sd->group_sid;
+ }
+ break;
+ case SMB_ACL_ADD:
+ for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
+ add_ace(mem_ctx, &old->dacl, &sd->dacl->aces[i]);
+ }
+ break;
+ case SMB_ACL_SET:
+ old = sd;
+ break;
+ }
+
+ /* Denied ACE entries must come before allowed ones */
+ sort_acl(old->dacl);
+
+ if ( !set_share_security( sharename, old ) ) {
+ fprintf( stderr, "Failed to store acl for share [%s]\n", sharename );
+ return 2;
+ }
+ return 0;
+}
+
+/********************************************************************
+ main program
+********************************************************************/
+
+int main(int argc, const char *argv[])
+{
+ int opt;
+ int retval = 0;
+ enum acl_mode mode = SMB_ACL_SET;
+ static char *the_acl = NULL;
+ fstring sharename;
+ bool force_acl = False;
+ int snum;
+ poptContext pc;
+ bool initialize_sid = False;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "remove", 'r', POPT_ARG_STRING, &the_acl, 'r', "Delete an ACE", "ACL" },
+ { "modify", 'm', POPT_ARG_STRING, &the_acl, 'm', "Modify an acl", "ACL" },
+ { "add", 'a', POPT_ARG_STRING, &the_acl, 'a', "Add an ACE", "ACL" },
+ { "replace", 'R', POPT_ARG_STRING, &the_acl, 'R', "Set share mission ACL", "ACLS" },
+ { "view", 'v', POPT_ARG_NONE, NULL, 'v', "View current share permissions" },
+ { "machine-sid", 'M', POPT_ARG_NONE, NULL, 'M', "Initialize the machine SID" },
+ { "force", 'F', POPT_ARG_NONE, NULL, 'F', "Force storing the ACL", "ACLS" },
+ POPT_COMMON_SAMBA
+ { NULL }
+ };
+
+ if ( !(ctx = talloc_stackframe()) ) {
+ fprintf( stderr, "Failed to initialize talloc context!\n");
+ return -1;
+ }
+
+ /* set default debug level to 1 regardless of what smb.conf sets */
+ setup_logging( "sharesec", True );
+ DEBUGLEVEL_CLASS[DBGC_ALL] = 1;
+ dbf = x_stderr;
+ x_setbuf( x_stderr, NULL );
+
+ pc = poptGetContext("sharesec", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "sharename\n");
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'r':
+ the_acl = smb_xstrdup(poptGetOptArg(pc));
+ mode = SMB_ACL_DELETE;
+ break;
+
+ case 'm':
+ the_acl = smb_xstrdup(poptGetOptArg(pc));
+ mode = SMB_ACL_MODIFY;
+ break;
+
+ case 'a':
+ the_acl = smb_xstrdup(poptGetOptArg(pc));
+ mode = SMB_ACL_ADD;
+ break;
+ case 'R':
+ the_acl = smb_xstrdup(poptGetOptArg(pc));
+ mode = SMB_ACL_SET;
+ break;
+
+ case 'v':
+ mode = SMB_ACL_VIEW;
+ break;
+
+ case 'F':
+ force_acl = True;
+ break;
+
+ case 'M':
+ initialize_sid = True;
+ break;
+ }
+ }
+
+ setlinebuf(stdout);
+
+ load_case_tables();
+
+ lp_load( get_dyn_CONFIGFILE(), False, False, False, True );
+
+ /* check for initializing secrets.tdb first */
+
+ if ( initialize_sid ) {
+ DOM_SID *sid = get_global_sam_sid();
+
+ if ( !sid ) {
+ fprintf( stderr, "Failed to retrieve Machine SID!\n");
+ return 3;
+ }
+
+ printf ("%s\n", sid_string_tos( sid ) );
+ return 0;
+ }
+
+ if ( mode == SMB_ACL_VIEW && force_acl ) {
+ fprintf( stderr, "Invalid combination of -F and -v\n");
+ return -1;
+ }
+
+ /* get the sharename */
+
+ if(!poptPeekArg(pc)) {
+ poptPrintUsage(pc, stderr, 0);
+ return -1;
+ }
+
+ fstrcpy(sharename, poptGetArg(pc));
+
+ snum = lp_servicenumber( sharename );
+
+ if ( snum == -1 && !force_acl ) {
+ fprintf( stderr, "Invalid sharename: %s\n", sharename);
+ return -1;
+ }
+
+ retval = change_share_sec(ctx, sharename, the_acl, mode);
+
+ talloc_destroy(ctx);
+
+ return retval;
+}
diff --git a/source3/utils/smbcacls.c b/source3/utils/smbcacls.c
new file mode 100644
index 0000000000..d488ce2187
--- /dev/null
+++ b/source3/utils/smbcacls.c
@@ -0,0 +1,1032 @@
+/*
+ Unix SMB/CIFS implementation.
+ ACL get/set utility
+
+ Copyright (C) Andrew Tridgell 2000
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Jeremy Allison 2000
+ Copyright (C) Jelmer Vernooij 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static int test_args = False;
+
+#define CREATE_ACCESS_READ READ_CONTROL_ACCESS
+
+/* numeric is set when the user wants numeric SIDs and ACEs rather
+ than going via LSA calls to resolve them */
+static int numeric = False;
+
+enum acl_mode {SMB_ACL_SET, SMB_ACL_DELETE, SMB_ACL_MODIFY, SMB_ACL_ADD };
+enum chown_mode {REQUEST_NONE, REQUEST_CHOWN, REQUEST_CHGRP};
+enum exit_values {EXIT_OK, EXIT_FAILED, EXIT_PARSE_ERROR};
+
+struct perm_value {
+ const char *perm;
+ uint32 mask;
+};
+
+/* These values discovered by inspection */
+
+static const struct perm_value special_values[] = {
+ { "R", 0x00120089 },
+ { "W", 0x00120116 },
+ { "X", 0x001200a0 },
+ { "D", 0x00010000 },
+ { "P", 0x00040000 },
+ { "O", 0x00080000 },
+ { NULL, 0 },
+};
+
+static const struct perm_value standard_values[] = {
+ { "READ", 0x001200a9 },
+ { "CHANGE", 0x001301bf },
+ { "FULL", 0x001f01ff },
+ { NULL, 0 },
+};
+
+/* Open cli connection and policy handle */
+
+static NTSTATUS cli_lsa_lookup_sid(struct cli_state *cli,
+ const DOM_SID *sid,
+ TALLOC_CTX *mem_ctx,
+ enum lsa_SidType *type,
+ char **domain, char **name)
+{
+ uint16 orig_cnum = cli->cnum;
+ struct rpc_pipe_client *p;
+ struct policy_handle handle;
+ NTSTATUS status;
+ TALLOC_CTX *frame = talloc_stackframe();
+ enum lsa_SidType *types;
+ char **domains;
+ char **names;
+
+ if (!cli_send_tconX(cli, "IPC$", "?????", "", 0)) {
+ return cli_nt_error(cli);
+ }
+
+ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
+ &p);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ status = rpccli_lsa_open_policy(p, talloc_tos(), True,
+ GENERIC_EXECUTE_ACCESS, &handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ status = rpccli_lsa_lookup_sids(p, talloc_tos(), &handle, 1, sid,
+ &domains, &names, &types);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ *type = types[0];
+ *domain = talloc_move(mem_ctx, &domains[0]);
+ *name = talloc_move(mem_ctx, &names[0]);
+
+ status = NT_STATUS_OK;
+ fail:
+ TALLOC_FREE(p);
+ cli_tdis(cli);
+ cli->cnum = orig_cnum;
+ TALLOC_FREE(frame);
+ return status;
+}
+
+static NTSTATUS cli_lsa_lookup_name(struct cli_state *cli,
+ const char *name,
+ enum lsa_SidType *type,
+ DOM_SID *sid)
+{
+ uint16 orig_cnum = cli->cnum;
+ struct rpc_pipe_client *p;
+ struct policy_handle handle;
+ NTSTATUS status;
+ TALLOC_CTX *frame = talloc_stackframe();
+ DOM_SID *sids;
+ enum lsa_SidType *types;
+
+ if (!cli_send_tconX(cli, "IPC$", "?????", "", 0)) {
+ return cli_nt_error(cli);
+ }
+
+ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
+ &p);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ status = rpccli_lsa_open_policy(p, talloc_tos(), True,
+ GENERIC_EXECUTE_ACCESS, &handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ status = rpccli_lsa_lookup_names(p, talloc_tos(), &handle, 1, &name,
+ NULL, 1, &sids, &types);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ *type = types[0];
+ *sid = sids[0];
+
+ status = NT_STATUS_OK;
+ fail:
+ TALLOC_FREE(p);
+ cli_tdis(cli);
+ cli->cnum = orig_cnum;
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/* convert a SID to a string, either numeric or username/group */
+static void SidToString(struct cli_state *cli, fstring str, const DOM_SID *sid)
+{
+ char *domain = NULL;
+ char *name = NULL;
+ enum lsa_SidType type;
+ NTSTATUS status;
+
+ sid_to_fstring(str, sid);
+
+ if (numeric) {
+ return;
+ }
+
+ status = cli_lsa_lookup_sid(cli, sid, talloc_tos(), &type,
+ &domain, &name);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return;
+ }
+
+ slprintf(str, sizeof(fstring) - 1, "%s%s%s",
+ domain, lp_winbind_separator(), name);
+
+}
+
+/* convert a string to a SID, either numeric or username/group */
+static bool StringToSid(struct cli_state *cli, DOM_SID *sid, const char *str)
+{
+ enum lsa_SidType type;
+
+ if (strncmp(str, "S-", 2) == 0) {
+ return string_to_sid(sid, str);
+ }
+
+ return NT_STATUS_IS_OK(cli_lsa_lookup_name(cli, str, &type, sid));
+}
+
+
+/* print an ACE on a FILE, using either numeric or ascii representation */
+static void print_ace(struct cli_state *cli, FILE *f, SEC_ACE *ace)
+{
+ const struct perm_value *v;
+ fstring sidstr;
+ int do_print = 0;
+ uint32 got_mask;
+
+ SidToString(cli, sidstr, &ace->trustee);
+
+ fprintf(f, "%s:", sidstr);
+
+ if (numeric) {
+ fprintf(f, "%d/%d/0x%08x",
+ ace->type, ace->flags, ace->access_mask);
+ return;
+ }
+
+ /* Ace type */
+
+ if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) {
+ fprintf(f, "ALLOWED");
+ } else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) {
+ fprintf(f, "DENIED");
+ } else {
+ fprintf(f, "%d", ace->type);
+ }
+
+ /* Not sure what flags can be set in a file ACL */
+
+ fprintf(f, "/%d/", ace->flags);
+
+ /* Standard permissions */
+
+ for (v = standard_values; v->perm; v++) {
+ if (ace->access_mask == v->mask) {
+ fprintf(f, "%s", v->perm);
+ return;
+ }
+ }
+
+ /* Special permissions. Print out a hex value if we have
+ leftover bits in the mask. */
+
+ got_mask = ace->access_mask;
+
+ again:
+ for (v = special_values; v->perm; v++) {
+ if ((ace->access_mask & v->mask) == v->mask) {
+ if (do_print) {
+ fprintf(f, "%s", v->perm);
+ }
+ got_mask &= ~v->mask;
+ }
+ }
+
+ if (!do_print) {
+ if (got_mask != 0) {
+ fprintf(f, "0x%08x", ace->access_mask);
+ } else {
+ do_print = 1;
+ goto again;
+ }
+ }
+}
+
+
+/* parse an ACE in the same format as print_ace() */
+static bool parse_ace(struct cli_state *cli, SEC_ACE *ace,
+ const char *orig_str)
+{
+ char *p;
+ const char *cp;
+ char *tok;
+ unsigned int atype = 0;
+ unsigned int aflags = 0;
+ unsigned int amask = 0;
+ DOM_SID sid;
+ SEC_ACCESS mask;
+ const struct perm_value *v;
+ char *str = SMB_STRDUP(orig_str);
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!str) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ ZERO_STRUCTP(ace);
+ p = strchr_m(str,':');
+ if (!p) {
+ printf("ACE '%s': missing ':'.\n", orig_str);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
+ return False;
+ }
+ *p = '\0';
+ p++;
+ /* Try to parse numeric form */
+
+ if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 &&
+ StringToSid(cli, &sid, str)) {
+ goto done;
+ }
+
+ /* Try to parse text form */
+
+ if (!StringToSid(cli, &sid, str)) {
+ printf("ACE '%s': failed to convert '%s' to SID\n",
+ orig_str, str);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ cp = p;
+ if (!next_token_talloc(frame, &cp, &tok, "/")) {
+ printf("ACE '%s': failed to find '/' character.\n",
+ orig_str);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ if (strncmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
+ atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ } else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) {
+ atype = SEC_ACE_TYPE_ACCESS_DENIED;
+ } else {
+ printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
+ orig_str, tok);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ /* Only numeric form accepted for flags at present */
+
+ if (!(next_token_talloc(frame, &cp, &tok, "/") &&
+ sscanf(tok, "%i", &aflags))) {
+ printf("ACE '%s': bad integer flags entry at '%s'\n",
+ orig_str, tok);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ if (!next_token_talloc(frame, &cp, &tok, "/")) {
+ printf("ACE '%s': missing / at '%s'\n",
+ orig_str, tok);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ if (strncmp(tok, "0x", 2) == 0) {
+ if (sscanf(tok, "%i", &amask) != 1) {
+ printf("ACE '%s': bad hex number at '%s'\n",
+ orig_str, tok);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
+ return False;
+ }
+ goto done;
+ }
+
+ for (v = standard_values; v->perm; v++) {
+ if (strcmp(tok, v->perm) == 0) {
+ amask = v->mask;
+ goto done;
+ }
+ }
+
+ p = tok;
+
+ while(*p) {
+ bool found = False;
+
+ for (v = special_values; v->perm; v++) {
+ if (v->perm[0] == *p) {
+ amask |= v->mask;
+ found = True;
+ }
+ }
+
+ if (!found) {
+ printf("ACE '%s': bad permission value at '%s'\n",
+ orig_str, p);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
+ return False;
+ }
+ p++;
+ }
+
+ if (*p) {
+ TALLOC_FREE(frame);
+ SAFE_FREE(str);
+ return False;
+ }
+
+ done:
+ mask = amask;
+ init_sec_ace(ace, &sid, atype, mask, aflags);
+ TALLOC_FREE(frame);
+ SAFE_FREE(str);
+ return True;
+}
+
+/* add an ACE to a list of ACEs in a SEC_ACL */
+static bool add_ace(SEC_ACL **the_acl, SEC_ACE *ace)
+{
+ SEC_ACL *new_ace;
+ SEC_ACE *aces;
+ if (! *the_acl) {
+ return (((*the_acl) = make_sec_acl(talloc_tos(), 3, 1, ace))
+ != NULL);
+ }
+
+ if (!(aces = SMB_CALLOC_ARRAY(SEC_ACE, 1+(*the_acl)->num_aces))) {
+ return False;
+ }
+ memcpy(aces, (*the_acl)->aces, (*the_acl)->num_aces * sizeof(SEC_ACE));
+ memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE));
+ new_ace = make_sec_acl(talloc_tos(),(*the_acl)->revision,1+(*the_acl)->num_aces, aces);
+ SAFE_FREE(aces);
+ (*the_acl) = new_ace;
+ return True;
+}
+
+/* parse a ascii version of a security descriptor */
+static SEC_DESC *sec_desc_parse(TALLOC_CTX *ctx, struct cli_state *cli, char *str)
+{
+ const char *p = str;
+ char *tok;
+ SEC_DESC *ret = NULL;
+ size_t sd_size;
+ DOM_SID *grp_sid=NULL, *owner_sid=NULL;
+ SEC_ACL *dacl=NULL;
+ int revision=1;
+
+ while (next_token_talloc(ctx, &p, &tok, "\t,\r\n")) {
+ if (strncmp(tok,"REVISION:", 9) == 0) {
+ revision = strtol(tok+9, NULL, 16);
+ continue;
+ }
+
+ if (strncmp(tok,"OWNER:", 6) == 0) {
+ if (owner_sid) {
+ printf("Only specify owner once\n");
+ goto done;
+ }
+ owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
+ if (!owner_sid ||
+ !StringToSid(cli, owner_sid, tok+6)) {
+ printf("Failed to parse owner sid\n");
+ goto done;
+ }
+ continue;
+ }
+
+ if (strncmp(tok,"GROUP:", 6) == 0) {
+ if (grp_sid) {
+ printf("Only specify group once\n");
+ goto done;
+ }
+ grp_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
+ if (!grp_sid ||
+ !StringToSid(cli, grp_sid, tok+6)) {
+ printf("Failed to parse group sid\n");
+ goto done;
+ }
+ continue;
+ }
+
+ if (strncmp(tok,"ACL:", 4) == 0) {
+ SEC_ACE ace;
+ if (!parse_ace(cli, &ace, tok+4)) {
+ goto done;
+ }
+ if(!add_ace(&dacl, &ace)) {
+ printf("Failed to add ACL %s\n", tok);
+ goto done;
+ }
+ continue;
+ }
+
+ printf("Failed to parse token '%s' in security descriptor,\n", tok);
+ goto done;
+ }
+
+ ret = make_sec_desc(ctx,revision, SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid,
+ NULL, dacl, &sd_size);
+
+ done:
+ SAFE_FREE(grp_sid);
+ SAFE_FREE(owner_sid);
+
+ return ret;
+}
+
+
+/* print a ascii version of a security descriptor on a FILE handle */
+static void sec_desc_print(struct cli_state *cli, FILE *f, SEC_DESC *sd)
+{
+ fstring sidstr;
+ uint32 i;
+
+ fprintf(f, "REVISION:%d\n", sd->revision);
+
+ /* Print owner and group sid */
+
+ if (sd->owner_sid) {
+ SidToString(cli, sidstr, sd->owner_sid);
+ } else {
+ fstrcpy(sidstr, "");
+ }
+
+ fprintf(f, "OWNER:%s\n", sidstr);
+
+ if (sd->group_sid) {
+ SidToString(cli, sidstr, sd->group_sid);
+ } else {
+ fstrcpy(sidstr, "");
+ }
+
+ fprintf(f, "GROUP:%s\n", sidstr);
+
+ /* Print aces */
+ for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
+ SEC_ACE *ace = &sd->dacl->aces[i];
+ fprintf(f, "ACL:");
+ print_ace(cli, f, ace);
+ fprintf(f, "\n");
+ }
+
+}
+
+/*****************************************************
+dump the acls for a file
+*******************************************************/
+static int cacl_dump(struct cli_state *cli, char *filename)
+{
+ int result = EXIT_FAILED;
+ int fnum = -1;
+ SEC_DESC *sd;
+
+ if (test_args)
+ return EXIT_OK;
+
+ fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
+
+ if (fnum == -1) {
+ printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
+ goto done;
+ }
+
+ sd = cli_query_secdesc(cli, fnum, talloc_tos());
+
+ if (!sd) {
+ printf("ERROR: secdesc query failed: %s\n", cli_errstr(cli));
+ goto done;
+ }
+
+ sec_desc_print(cli, stdout, sd);
+
+ result = EXIT_OK;
+
+done:
+ if (fnum != -1)
+ cli_close(cli, fnum);
+
+ return result;
+}
+
+/*****************************************************
+Change the ownership or group ownership of a file. Just
+because the NT docs say this can't be done :-). JRA.
+*******************************************************/
+
+static int owner_set(struct cli_state *cli, enum chown_mode change_mode,
+ const char *filename, const char *new_username)
+{
+ int fnum;
+ DOM_SID sid;
+ SEC_DESC *sd, *old;
+ size_t sd_size;
+
+ fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
+
+ if (fnum == -1) {
+ printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
+ return EXIT_FAILED;
+ }
+
+ if (!StringToSid(cli, &sid, new_username))
+ return EXIT_PARSE_ERROR;
+
+ old = cli_query_secdesc(cli, fnum, talloc_tos());
+
+ cli_close(cli, fnum);
+
+ if (!old) {
+ printf("owner_set: Failed to query old descriptor\n");
+ return EXIT_FAILED;
+ }
+
+ sd = make_sec_desc(talloc_tos(),old->revision, old->type,
+ (change_mode == REQUEST_CHOWN) ? &sid : NULL,
+ (change_mode == REQUEST_CHGRP) ? &sid : NULL,
+ NULL, NULL, &sd_size);
+
+ fnum = cli_nt_create(cli, filename, WRITE_OWNER_ACCESS);
+
+ if (fnum == -1) {
+ printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
+ return EXIT_FAILED;
+ }
+
+ if (!cli_set_secdesc(cli, fnum, sd)) {
+ printf("ERROR: secdesc set failed: %s\n", cli_errstr(cli));
+ }
+
+ cli_close(cli, fnum);
+
+ return EXIT_OK;
+}
+
+
+/* The MSDN is contradictory over the ordering of ACE entries in an ACL.
+ However NT4 gives a "The information may have been modified by a
+ computer running Windows NT 5.0" if denied ACEs do not appear before
+ allowed ACEs. */
+
+static int ace_compare(SEC_ACE *ace1, SEC_ACE *ace2)
+{
+ if (sec_ace_equal(ace1, ace2))
+ return 0;
+
+ if (ace1->type != ace2->type)
+ return ace2->type - ace1->type;
+
+ if (sid_compare(&ace1->trustee, &ace2->trustee))
+ return sid_compare(&ace1->trustee, &ace2->trustee);
+
+ if (ace1->flags != ace2->flags)
+ return ace1->flags - ace2->flags;
+
+ if (ace1->access_mask != ace2->access_mask)
+ return ace1->access_mask - ace2->access_mask;
+
+ if (ace1->size != ace2->size)
+ return ace1->size - ace2->size;
+
+ return memcmp(ace1, ace2, sizeof(SEC_ACE));
+}
+
+static void sort_acl(SEC_ACL *the_acl)
+{
+ uint32 i;
+ if (!the_acl) return;
+
+ qsort(the_acl->aces, the_acl->num_aces, sizeof(the_acl->aces[0]), QSORT_CAST ace_compare);
+
+ for (i=1;i<the_acl->num_aces;) {
+ if (sec_ace_equal(&the_acl->aces[i-1], &the_acl->aces[i])) {
+ int j;
+ for (j=i; j<the_acl->num_aces-1; j++) {
+ the_acl->aces[j] = the_acl->aces[j+1];
+ }
+ the_acl->num_aces--;
+ } else {
+ i++;
+ }
+ }
+}
+
+/*****************************************************
+set the ACLs on a file given an ascii description
+*******************************************************/
+static int cacl_set(struct cli_state *cli, char *filename,
+ char *the_acl, enum acl_mode mode)
+{
+ int fnum;
+ SEC_DESC *sd, *old;
+ uint32 i, j;
+ size_t sd_size;
+ int result = EXIT_OK;
+
+ sd = sec_desc_parse(talloc_tos(), cli, the_acl);
+
+ if (!sd) return EXIT_PARSE_ERROR;
+ if (test_args) return EXIT_OK;
+
+ /* The desired access below is the only one I could find that works
+ with NT4, W2KP and Samba */
+
+ fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
+
+ if (fnum == -1) {
+ printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli));
+ return EXIT_FAILED;
+ }
+
+ old = cli_query_secdesc(cli, fnum, talloc_tos());
+
+ if (!old) {
+ printf("calc_set: Failed to query old descriptor\n");
+ return EXIT_FAILED;
+ }
+
+ cli_close(cli, fnum);
+
+ /* the logic here is rather more complex than I would like */
+ switch (mode) {
+ case SMB_ACL_DELETE:
+ for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
+ bool found = False;
+
+ for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
+ if (sec_ace_equal(&sd->dacl->aces[i],
+ &old->dacl->aces[j])) {
+ uint32 k;
+ for (k=j; k<old->dacl->num_aces-1;k++) {
+ old->dacl->aces[k] = old->dacl->aces[k+1];
+ }
+ old->dacl->num_aces--;
+ found = True;
+ break;
+ }
+ }
+
+ if (!found) {
+ printf("ACL for ACE:");
+ print_ace(cli, stdout, &sd->dacl->aces[i]);
+ printf(" not found\n");
+ }
+ }
+ break;
+
+ case SMB_ACL_MODIFY:
+ for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
+ bool found = False;
+
+ for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
+ if (sid_equal(&sd->dacl->aces[i].trustee,
+ &old->dacl->aces[j].trustee)) {
+ old->dacl->aces[j] = sd->dacl->aces[i];
+ found = True;
+ }
+ }
+
+ if (!found) {
+ fstring str;
+
+ SidToString(cli, str,
+ &sd->dacl->aces[i].trustee);
+ printf("ACL for SID %s not found\n", str);
+ }
+ }
+
+ if (sd->owner_sid) {
+ old->owner_sid = sd->owner_sid;
+ }
+
+ if (sd->group_sid) {
+ old->group_sid = sd->group_sid;
+ }
+
+ break;
+
+ case SMB_ACL_ADD:
+ for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
+ add_ace(&old->dacl, &sd->dacl->aces[i]);
+ }
+ break;
+
+ case SMB_ACL_SET:
+ old = sd;
+ break;
+ }
+
+ /* Denied ACE entries must come before allowed ones */
+ sort_acl(old->dacl);
+
+ /* Create new security descriptor and set it */
+
+ /* We used to just have "WRITE_DAC_ACCESS" without WRITE_OWNER.
+ But if we're sending an owner, even if it's the same as the one
+ that already exists then W2K3 insists we open with WRITE_OWNER access.
+ I need to check that setting a SD with no owner set works against WNT
+ and W2K. JRA.
+ */
+
+ sd = make_sec_desc(talloc_tos(),old->revision, old->type,
+ old->owner_sid, old->group_sid,
+ NULL, old->dacl, &sd_size);
+
+ fnum = cli_nt_create(cli, filename, WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS);
+
+ if (fnum == -1) {
+ printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli));
+ return EXIT_FAILED;
+ }
+
+ if (!cli_set_secdesc(cli, fnum, sd)) {
+ printf("ERROR: secdesc set failed: %s\n", cli_errstr(cli));
+ result = EXIT_FAILED;
+ }
+
+ /* Clean up */
+
+ cli_close(cli, fnum);
+
+ return result;
+}
+
+
+/*****************************************************
+ Return a connection to a server.
+*******************************************************/
+static struct cli_state *connect_one(const char *server, const char *share)
+{
+ struct cli_state *c = NULL;
+ struct sockaddr_storage ss;
+ NTSTATUS nt_status;
+ uint32_t flags = 0;
+
+ zero_addr(&ss);
+
+ if (get_cmdline_auth_info_use_kerberos()) {
+ flags |= CLI_FULL_CONNECTION_USE_KERBEROS |
+ CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
+ }
+
+ if (get_cmdline_auth_info_use_machine_account() &&
+ !set_cmdline_auth_info_machine_account_creds()) {
+ return NULL;
+ }
+
+ if (!get_cmdline_auth_info_got_pass()) {
+ char *pass = getpass("Password: ");
+ if (pass) {
+ set_cmdline_auth_info_password(pass);
+ }
+ }
+
+ nt_status = cli_full_connection(&c, global_myname(), server,
+ &ss, 0,
+ share, "?????",
+ get_cmdline_auth_info_username(),
+ lp_workgroup(),
+ get_cmdline_auth_info_password(),
+ flags,
+ get_cmdline_auth_info_signing_state(),
+ NULL);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0,("cli_full_connection failed! (%s)\n", nt_errstr(nt_status)));
+ return NULL;
+ }
+
+ if (get_cmdline_auth_info_smb_encrypt()) {
+ nt_status = cli_cm_force_encryption(c,
+ get_cmdline_auth_info_username(),
+ get_cmdline_auth_info_password(),
+ lp_workgroup(),
+ share);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ cli_shutdown(c);
+ c = NULL;
+ }
+ }
+
+ return c;
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc, const char *argv[])
+{
+ char *share;
+ int opt;
+ enum acl_mode mode = SMB_ACL_SET;
+ static char *the_acl = NULL;
+ enum chown_mode change_mode = REQUEST_NONE;
+ int result;
+ char *path;
+ char *filename = NULL;
+ poptContext pc;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "delete", 'D', POPT_ARG_STRING, NULL, 'D', "Delete an acl", "ACL" },
+ { "modify", 'M', POPT_ARG_STRING, NULL, 'M', "Modify an acl", "ACL" },
+ { "add", 'a', POPT_ARG_STRING, NULL, 'a', "Add an acl", "ACL" },
+ { "set", 'S', POPT_ARG_STRING, NULL, 'S', "Set acls", "ACLS" },
+ { "chown", 'C', POPT_ARG_STRING, NULL, 'C', "Change ownership of a file", "USERNAME" },
+ { "chgrp", 'G', POPT_ARG_STRING, NULL, 'G', "Change group ownership of a file", "GROUPNAME" },
+ { "numeric", 0, POPT_ARG_NONE, &numeric, True, "Don't resolve sids or masks to names" },
+ { "test-args", 't', POPT_ARG_NONE, &test_args, True, "Test arguments"},
+ POPT_COMMON_SAMBA
+ POPT_COMMON_CONNECTION
+ POPT_COMMON_CREDENTIALS
+ POPT_TABLEEND
+ };
+
+ struct cli_state *cli;
+ TALLOC_CTX *frame = talloc_stackframe();
+ const char *owner_username = "";
+ char *server;
+
+ load_case_tables();
+
+
+ /* set default debug level to 1 regardless of what smb.conf sets */
+ setup_logging( "smbcacls", True );
+ DEBUGLEVEL_CLASS[DBGC_ALL] = 1;
+ dbf = x_stderr;
+ x_setbuf( x_stderr, NULL );
+
+ setlinebuf(stdout);
+
+ lp_load(get_dyn_CONFIGFILE(),True,False,False,True);
+ load_interfaces();
+
+ pc = poptGetContext("smbcacls", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "//server1/share1 filename\nACLs look like: "
+ "'ACL:user:[ALLOWED|DENIED]/flags/permissions'");
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'S':
+ the_acl = smb_xstrdup(poptGetOptArg(pc));
+ mode = SMB_ACL_SET;
+ break;
+
+ case 'D':
+ the_acl = smb_xstrdup(poptGetOptArg(pc));
+ mode = SMB_ACL_DELETE;
+ break;
+
+ case 'M':
+ the_acl = smb_xstrdup(poptGetOptArg(pc));
+ mode = SMB_ACL_MODIFY;
+ break;
+
+ case 'a':
+ the_acl = smb_xstrdup(poptGetOptArg(pc));
+ mode = SMB_ACL_ADD;
+ break;
+
+ case 'C':
+ owner_username = poptGetOptArg(pc);
+ change_mode = REQUEST_CHOWN;
+ break;
+
+ case 'G':
+ owner_username = poptGetOptArg(pc);
+ change_mode = REQUEST_CHGRP;
+ break;
+ }
+ }
+
+ /* Make connection to server */
+ if(!poptPeekArg(pc)) {
+ poptPrintUsage(pc, stderr, 0);
+ return -1;
+ }
+
+ path = talloc_strdup(frame, poptGetArg(pc));
+ if (!path) {
+ return -1;
+ }
+
+ if(!poptPeekArg(pc)) {
+ poptPrintUsage(pc, stderr, 0);
+ return -1;
+ }
+
+ filename = talloc_strdup(frame, poptGetArg(pc));
+ if (!filename) {
+ return -1;
+ }
+
+ string_replace(path,'/','\\');
+
+ server = talloc_strdup(frame, path+2);
+ if (!server) {
+ return -1;
+ }
+ share = strchr_m(server,'\\');
+ if (!share) {
+ printf("Invalid argument: %s\n", share);
+ return -1;
+ }
+
+ *share = 0;
+ share++;
+
+ if (!test_args) {
+ cli = connect_one(server, share);
+ if (!cli) {
+ exit(EXIT_FAILED);
+ }
+ } else {
+ exit(0);
+ }
+
+ string_replace(filename, '/', '\\');
+ if (filename[0] != '\\') {
+ filename = talloc_asprintf(frame,
+ "\\%s",
+ filename);
+ if (!filename) {
+ return -1;
+ }
+ }
+
+ /* Perform requested action */
+
+ if (change_mode != REQUEST_NONE) {
+ result = owner_set(cli, change_mode, filename, owner_username);
+ } else if (the_acl) {
+ result = cacl_set(cli, filename, the_acl, mode);
+ } else {
+ result = cacl_dump(cli, filename);
+ }
+
+ TALLOC_FREE(frame);
+
+ return result;
+}
diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c
new file mode 100644
index 0000000000..750030d916
--- /dev/null
+++ b/source3/utils/smbcontrol.c
@@ -0,0 +1,1401 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Send messages to other Samba daemons
+
+ Copyright (C) Tim Potter 2003
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Martin Pool 2001-2002
+ Copyright (C) Simo Sorce 2002
+ Copyright (C) James Peach 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#if HAVE_LIBUNWIND_H
+#include <libunwind.h>
+#endif
+
+#if HAVE_LIBUNWIND_PTRACE_H
+#include <libunwind-ptrace.h>
+#endif
+
+#if HAVE_SYS_PTRACE_H
+#include <sys/ptrace.h>
+#endif
+
+/* Default timeout value when waiting for replies (in seconds) */
+
+#define DEFAULT_TIMEOUT 10
+
+static int timeout = DEFAULT_TIMEOUT;
+static int num_replies; /* Used by message callback fns */
+
+/* Send a message to a destination pid. Zero means broadcast smbd. */
+
+static bool send_message(struct messaging_context *msg_ctx,
+ struct server_id pid, int msg_type,
+ const void *buf, int len)
+{
+ bool ret;
+ int n_sent = 0;
+
+ if (procid_to_pid(&pid) != 0)
+ return NT_STATUS_IS_OK(
+ messaging_send_buf(msg_ctx, pid, msg_type,
+ (uint8 *)buf, len));
+
+ ret = message_send_all(msg_ctx, msg_type, buf, len, &n_sent);
+ DEBUG(10,("smbcontrol/send_message: broadcast message to "
+ "%d processes\n", n_sent));
+
+ return ret;
+}
+
+static void timeout_handler(struct event_context *event_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ bool *timed_out = (bool *)private_data;
+ TALLOC_FREE(te);
+ *timed_out = True;
+}
+
+/* Wait for one or more reply messages */
+
+static void wait_replies(struct messaging_context *msg_ctx,
+ bool multiple_replies)
+{
+ struct timed_event *te;
+ bool timed_out = False;
+
+ if (!(te = event_add_timed(messaging_event_context(msg_ctx), NULL,
+ timeval_current_ofs(timeout, 0),
+ "smbcontrol_timeout",
+ timeout_handler, (void *)&timed_out))) {
+ DEBUG(0, ("event_add_timed failed\n"));
+ return;
+ }
+
+ while (!timed_out) {
+ message_dispatch(msg_ctx);
+ if (num_replies > 0 && !multiple_replies)
+ break;
+ event_loop_once(messaging_event_context(msg_ctx));
+ }
+}
+
+/* Message handler callback that displays the PID and a string on stdout */
+
+static void print_pid_string_cb(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id pid,
+ DATA_BLOB *data)
+{
+ printf("PID %u: %.*s", (unsigned int)procid_to_pid(&pid),
+ (int)data->length, (const char *)data->data);
+ num_replies++;
+}
+
+/* Message handler callback that displays a string on stdout */
+
+static void print_string_cb(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id pid,
+ DATA_BLOB *data)
+{
+ printf("%.*s", (int)data->length, (const char *)data->data);
+ num_replies++;
+}
+
+/* Send no message. Useful for testing. */
+
+static bool do_noop(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
+ return False;
+ }
+
+ /* Move along, nothing to see here */
+
+ return True;
+}
+
+/* Send a debug string */
+
+static bool do_debug(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 2) {
+ fprintf(stderr, "Usage: smbcontrol <dest> debug "
+ "<debug-string>\n");
+ return False;
+ }
+
+ return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
+ strlen(argv[1]) + 1);
+}
+
+#if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
+
+/* Return the name of a process given it's PID. This will only work on Linux,
+ * but that's probably moot since this whole stack tracing implementatino is
+ * Linux-specific anyway.
+ */
+static const char * procname(pid_t pid, char * buf, size_t bufsz)
+{
+ char path[64];
+ FILE * fp;
+
+ snprintf(path, sizeof(path), "/proc/%llu/cmdline",
+ (unsigned long long)pid);
+ if ((fp = fopen(path, "r")) == NULL) {
+ return NULL;
+ }
+
+ fgets(buf, bufsz, fp);
+
+ fclose(fp);
+ return buf;
+}
+
+static void print_stack_trace(pid_t pid, int * count)
+{
+ void * pinfo = NULL;
+ unw_addr_space_t aspace = NULL;
+ unw_cursor_t cursor;
+ unw_word_t ip, sp;
+
+ char nbuf[256];
+ unw_word_t off;
+
+ int ret;
+
+ if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
+ fprintf(stderr,
+ "Failed to attach to process %llu: %s\n",
+ (unsigned long long)pid, strerror(errno));
+ return;
+ }
+
+ /* Wait until the attach is complete. */
+ waitpid(pid, NULL, 0);
+
+ if (((pinfo = _UPT_create(pid)) == NULL) ||
+ ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
+ /* Probably out of memory. */
+ fprintf(stderr,
+ "Unable to initialize stack unwind for process %llu\n",
+ (unsigned long long)pid);
+ goto cleanup;
+ }
+
+ if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
+ fprintf(stderr,
+ "Unable to unwind stack for process %llu: %s\n",
+ (unsigned long long)pid, unw_strerror(ret));
+ goto cleanup;
+ }
+
+ if (*count > 0) {
+ printf("\n");
+ }
+
+ if (procname(pid, nbuf, sizeof(nbuf))) {
+ printf("Stack trace for process %llu (%s):\n",
+ (unsigned long long)pid, nbuf);
+ } else {
+ printf("Stack trace for process %llu:\n",
+ (unsigned long long)pid);
+ }
+
+ while (unw_step(&cursor) > 0) {
+ ip = sp = off = 0;
+ unw_get_reg(&cursor, UNW_REG_IP, &ip);
+ unw_get_reg(&cursor, UNW_REG_SP, &sp);
+
+ ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
+ if (ret != 0 && ret != -UNW_ENOMEM) {
+ snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
+ }
+ printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
+ nbuf, (long long)off, (long long)ip,
+ (long long)sp);
+ }
+
+ (*count)++;
+
+cleanup:
+ if (aspace) {
+ unw_destroy_addr_space(aspace);
+ }
+
+ if (pinfo) {
+ _UPT_destroy(pinfo);
+ }
+
+ ptrace(PTRACE_DETACH, pid, NULL, NULL);
+}
+
+static int stack_trace_connection(struct db_record *rec,
+ const struct connections_key *key,
+ const struct connections_data *crec,
+ void *priv)
+{
+ print_stack_trace(procid_to_pid(&crec->pid), (int *)priv);
+
+ return 0;
+}
+
+static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ pid_t dest;
+ int count = 0;
+
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
+ return False;
+ }
+
+ dest = procid_to_pid(&pid);
+
+ if (dest != 0) {
+ /* It would be nice to be able to make sure that this PID is
+ * the PID of a smbd/winbind/nmbd process, not some random PID
+ * the user liked the look of. It doesn't seem like it's worth
+ * the effort at the moment, however.
+ */
+ print_stack_trace(dest, &count);
+ } else {
+ connections_forall(stack_trace_connection, &count);
+ }
+
+ return True;
+}
+
+#else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
+
+static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ fprintf(stderr,
+ "Daemon stack tracing is not supported on this platform\n");
+ return False;
+}
+
+#endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
+
+/* Inject a fault (fatal signal) into a running smbd */
+
+static bool do_inject_fault(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 2) {
+ fprintf(stderr, "Usage: smbcontrol <dest> inject "
+ "<bus|hup|term|internal|segv>\n");
+ return False;
+ }
+
+#ifndef DEVELOPER
+ fprintf(stderr, "Fault injection is only available in "
+ "developer builds\n");
+ return False;
+#else /* DEVELOPER */
+ {
+ int sig = 0;
+
+ if (strcmp(argv[1], "bus") == 0) {
+ sig = SIGBUS;
+ } else if (strcmp(argv[1], "hup") == 0) {
+ sig = SIGHUP;
+ } else if (strcmp(argv[1], "term") == 0) {
+ sig = SIGTERM;
+ } else if (strcmp(argv[1], "segv") == 0) {
+ sig = SIGSEGV;
+ } else if (strcmp(argv[1], "internal") == 0) {
+ /* Force an internal error, ie. an unclean exit. */
+ sig = -1;
+ } else {
+ fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
+ return False;
+ }
+
+ return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
+ &sig, sizeof(int));
+ }
+#endif /* DEVELOPER */
+}
+
+/* Force a browser election */
+
+static bool do_election(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
+ return False;
+ }
+
+ return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
+}
+
+/* Ping a samba daemon process */
+
+static void pong_cb(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id pid,
+ DATA_BLOB *data)
+{
+ char *src_string = procid_str(NULL, &pid);
+ printf("PONG from pid %s\n", src_string);
+ TALLOC_FREE(src_string);
+ num_replies++;
+}
+
+static bool do_ping(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
+ return False;
+ }
+
+ /* Send a message and register our interest in a reply */
+
+ if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
+ return False;
+
+ messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
+
+ wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
+
+ /* No replies were received within the timeout period */
+
+ if (num_replies == 0)
+ printf("No replies received\n");
+
+ messaging_deregister(msg_ctx, MSG_PONG, NULL);
+
+ return num_replies;
+}
+
+/* Set profiling options */
+
+static bool do_profile(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ int v;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: smbcontrol <dest> profile "
+ "<off|count|on|flush>\n");
+ return False;
+ }
+
+ if (strcmp(argv[1], "off") == 0) {
+ v = 0;
+ } else if (strcmp(argv[1], "count") == 0) {
+ v = 1;
+ } else if (strcmp(argv[1], "on") == 0) {
+ v = 2;
+ } else if (strcmp(argv[1], "flush") == 0) {
+ v = 3;
+ } else {
+ fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
+ return False;
+ }
+
+ return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
+}
+
+/* Return the profiling level */
+
+static void profilelevel_cb(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id pid,
+ DATA_BLOB *data)
+{
+ int level;
+ const char *s;
+
+ num_replies++;
+
+ if (data->length != sizeof(int)) {
+ fprintf(stderr, "invalid message length %ld returned\n",
+ (unsigned long)data->length);
+ return;
+ }
+
+ memcpy(&level, data->data, sizeof(int));
+
+ switch (level) {
+ case 0:
+ s = "not enabled";
+ break;
+ case 1:
+ s = "off";
+ break;
+ case 3:
+ s = "count only";
+ break;
+ case 7:
+ s = "count and time";
+ break;
+ default:
+ s = "BOGUS";
+ break;
+ }
+
+ printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
+}
+
+static void profilelevel_rqst(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id pid,
+ DATA_BLOB *data)
+{
+ int v = 0;
+
+ /* Send back a dummy reply */
+
+ send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
+}
+
+static bool do_profilelevel(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
+ return False;
+ }
+
+ /* Send a message and register our interest in a reply */
+
+ if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
+ return False;
+
+ messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
+ messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
+ profilelevel_rqst);
+
+ wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
+
+ /* No replies were received within the timeout period */
+
+ if (num_replies == 0)
+ printf("No replies received\n");
+
+ messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
+
+ return num_replies;
+}
+
+/* Display debug level settings */
+
+static bool do_debuglevel(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
+ return False;
+ }
+
+ /* Send a message and register our interest in a reply */
+
+ if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
+ return False;
+
+ messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
+
+ wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
+
+ /* No replies were received within the timeout period */
+
+ if (num_replies == 0)
+ printf("No replies received\n");
+
+ messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
+
+ return num_replies;
+}
+
+/* Send a print notify message */
+
+static bool do_printnotify(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ const char *cmd;
+
+ /* Check for subcommand */
+
+ if (argc == 1) {
+ fprintf(stderr, "Must specify subcommand:\n");
+ fprintf(stderr, "\tqueuepause <printername>\n");
+ fprintf(stderr, "\tqueueresume <printername>\n");
+ fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
+ fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
+ fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
+ fprintf(stderr, "\tprinter <printername> <comment|port|"
+ "driver> <value>\n");
+
+ return False;
+ }
+
+ cmd = argv[1];
+
+ if (strcmp(cmd, "queuepause") == 0) {
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
+ " queuepause <printername>\n");
+ return False;
+ }
+
+ notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
+
+ goto send;
+
+ } else if (strcmp(cmd, "queueresume") == 0) {
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
+ " queuereume <printername>\n");
+ return False;
+ }
+
+ notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
+
+ goto send;
+
+ } else if (strcmp(cmd, "jobpause") == 0) {
+ int jobid;
+
+ if (argc != 4) {
+ fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
+ " jobpause <printername> <unix-jobid>\n");
+ return False;
+ }
+
+ jobid = atoi(argv[3]);
+
+ notify_job_status_byname(
+ argv[2], jobid, JOB_STATUS_PAUSED,
+ SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
+
+ goto send;
+
+ } else if (strcmp(cmd, "jobresume") == 0) {
+ int jobid;
+
+ if (argc != 4) {
+ fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
+ " jobpause <printername> <unix-jobid>\n");
+ return False;
+ }
+
+ jobid = atoi(argv[3]);
+
+ notify_job_status_byname(
+ argv[2], jobid, JOB_STATUS_QUEUED,
+ SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
+
+ goto send;
+
+ } else if (strcmp(cmd, "jobdelete") == 0) {
+ int jobid;
+
+ if (argc != 4) {
+ fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
+ " jobpause <printername> <unix-jobid>\n");
+ return False;
+ }
+
+ jobid = atoi(argv[3]);
+
+ notify_job_status_byname(
+ argv[2], jobid, JOB_STATUS_DELETING,
+ SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
+
+ notify_job_status_byname(
+ argv[2], jobid, JOB_STATUS_DELETING|
+ JOB_STATUS_DELETED,
+ SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
+
+ goto send;
+
+ } else if (strcmp(cmd, "printer") == 0) {
+ uint32 attribute;
+
+ if (argc != 5) {
+ fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
+ "printer <printername> <comment|port|driver> "
+ "<value>\n");
+ return False;
+ }
+
+ if (strcmp(argv[3], "comment") == 0) {
+ attribute = PRINTER_NOTIFY_COMMENT;
+ } else if (strcmp(argv[3], "port") == 0) {
+ attribute = PRINTER_NOTIFY_PORT_NAME;
+ } else if (strcmp(argv[3], "driver") == 0) {
+ attribute = PRINTER_NOTIFY_DRIVER_NAME;
+ } else {
+ fprintf(stderr, "Invalid printer command '%s'\n",
+ argv[3]);
+ return False;
+ }
+
+ notify_printer_byname(argv[2], attribute,
+ CONST_DISCARD(char *, argv[4]));
+
+ goto send;
+ }
+
+ fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
+ return False;
+
+send:
+ print_notify_send_messages(msg_ctx, 0);
+ return True;
+}
+
+/* Close a share */
+
+static bool do_closeshare(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 2) {
+ fprintf(stderr, "Usage: smbcontrol <dest> close-share "
+ "<sharename>\n");
+ return False;
+ }
+
+ return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
+ strlen(argv[1]) + 1);
+}
+
+/* force a blocking lock retry */
+
+static bool do_lockretry(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
+ return False;
+ }
+
+ return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
+}
+
+/* force a validation of all brl entries, including re-sends. */
+
+static bool do_brl_revalidate(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
+ return False;
+ }
+
+ return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
+}
+
+/* Force a SAM synchronisation */
+
+static bool do_samsync(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
+ return False;
+ }
+
+ return send_message(msg_ctx, pid, MSG_SMB_SAM_SYNC, NULL, 0);
+}
+
+/* Force a SAM replication */
+
+static bool do_samrepl(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
+ return False;
+ }
+
+ return send_message(msg_ctx, pid, MSG_SMB_SAM_REPL, NULL, 0);
+}
+
+/* Display talloc pool usage */
+
+static bool do_poolusage(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
+ return False;
+ }
+
+ messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
+
+ /* Send a message and register our interest in a reply */
+
+ if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
+ return False;
+
+ wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
+
+ /* No replies were received within the timeout period */
+
+ if (num_replies == 0)
+ printf("No replies received\n");
+
+ messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
+
+ return num_replies;
+}
+
+/* Perform a dmalloc mark */
+
+static bool do_dmalloc_mark(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
+ return False;
+ }
+
+ return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
+}
+
+/* Perform a dmalloc changed */
+
+static bool do_dmalloc_changed(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol <dest> "
+ "dmalloc-log-changed\n");
+ return False;
+ }
+
+ return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
+ NULL, 0);
+}
+
+/* Shutdown a server process */
+
+static bool do_shutdown(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
+ return False;
+ }
+
+ return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
+}
+
+/* Notify a driver upgrade */
+
+static bool do_drvupgrade(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 2) {
+ fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
+ "<driver-name>\n");
+ return False;
+ }
+
+ return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
+ strlen(argv[1]) + 1);
+}
+
+static bool do_winbind_online(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ TDB_CONTEXT *tdb;
+
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol winbindd online\n");
+ return False;
+ }
+
+ /* Remove the entry in the winbindd_cache tdb to tell a later
+ starting winbindd that we're online. */
+
+ tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
+ if (!tdb) {
+ fprintf(stderr, "Cannot open the tdb %s for writing.\n",
+ lock_path("winbindd_cache.tdb"));
+ return False;
+ }
+
+ tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
+ tdb_close(tdb);
+
+ return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
+}
+
+static bool do_winbind_offline(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ TDB_CONTEXT *tdb;
+ bool ret = False;
+ int retry = 0;
+
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
+ return False;
+ }
+
+ /* Create an entry in the winbindd_cache tdb to tell a later
+ starting winbindd that we're offline. We may actually create
+ it here... */
+
+ tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
+ WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
+ TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
+
+ if (!tdb) {
+ fprintf(stderr, "Cannot open the tdb %s for writing.\n",
+ lock_path("winbindd_cache.tdb"));
+ return False;
+ }
+
+ /* There's a potential race condition that if a child
+ winbindd detects a domain is online at the same time
+ we're trying to tell it to go offline that it might
+ delete the record we add between us adding it and
+ sending the message. Minimize this by retrying up to
+ 5 times. */
+
+ for (retry = 0; retry < 5; retry++) {
+ TDB_DATA d;
+ uint8 buf[4];
+
+ ZERO_STRUCT(d);
+
+ SIVAL(buf, 0, time(NULL));
+ d.dptr = buf;
+ d.dsize = 4;
+
+ tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
+
+ ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
+ NULL, 0);
+
+ /* Check that the entry "WINBINDD_OFFLINE" still exists. */
+ d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
+
+ if (!d.dptr || d.dsize != 4) {
+ SAFE_FREE(d.dptr);
+ DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
+ } else {
+ SAFE_FREE(d.dptr);
+ break;
+ }
+ }
+
+ tdb_close(tdb);
+ return ret;
+}
+
+static bool do_winbind_onlinestatus(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ struct server_id myid;
+
+ myid = pid_to_procid(sys_getpid());
+
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
+ return False;
+ }
+
+ messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
+ print_pid_string_cb);
+
+ if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
+ sizeof(myid)))
+ return False;
+
+ wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
+
+ /* No replies were received within the timeout period */
+
+ if (num_replies == 0)
+ printf("No replies received\n");
+
+ messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
+
+ return num_replies;
+}
+
+static bool do_dump_event_list(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ struct server_id myid;
+
+ myid = pid_to_procid(sys_getpid());
+
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
+ return False;
+ }
+
+ return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
+}
+
+static bool do_winbind_dump_domain_list(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ const char *domain = NULL;
+ int domain_len = 0;
+ struct server_id myid;
+ uint8_t *buf = NULL;
+ int buf_len = 0;
+
+ myid = pid_to_procid(sys_getpid());
+
+ if (argc < 1 || argc > 2) {
+ fprintf(stderr, "Usage: smbcontrol <dest> dump_domain_list "
+ "<domain>\n");
+ return false;
+ }
+
+ if (argc == 2) {
+ domain = argv[1];
+ domain_len = strlen(argv[1]) + 1;
+ }
+
+ messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
+ print_pid_string_cb);
+
+ buf_len = sizeof(myid)+domain_len;
+ buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
+ if (!buf) {
+ return false;
+ }
+
+ memcpy(buf, &myid, sizeof(myid));
+ memcpy(&buf[sizeof(myid)], domain, domain_len);
+
+ if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
+ buf, buf_len))
+ {
+ SAFE_FREE(buf);
+ return false;
+ }
+
+ wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
+
+ /* No replies were received within the timeout period */
+
+ SAFE_FREE(buf);
+ if (num_replies == 0) {
+ printf("No replies received\n");
+ }
+
+ messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
+
+ return num_replies;
+}
+
+static void winbind_validate_cache_cb(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id pid,
+ DATA_BLOB *data)
+{
+ char *src_string = procid_str(NULL, &pid);
+ printf("Winbindd cache is %svalid. (answer from pid %s)\n",
+ (*(data->data) == 0 ? "" : "NOT "), src_string);
+ TALLOC_FREE(src_string);
+ num_replies++;
+}
+
+static bool do_winbind_validate_cache(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ struct server_id myid = pid_to_procid(sys_getpid());
+
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
+ return False;
+ }
+
+ messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
+ winbind_validate_cache_cb);
+
+ if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
+ sizeof(myid))) {
+ return False;
+ }
+
+ wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
+
+ if (num_replies == 0) {
+ printf("No replies received\n");
+ }
+
+ messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
+
+ return num_replies;
+}
+
+static bool do_reload_config(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ if (argc != 1) {
+ fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
+ return False;
+ }
+
+ return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
+}
+
+static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
+{
+ fstring unix_name;
+ memset( (char *)n, '\0', sizeof(struct nmb_name) );
+ fstrcpy(unix_name, name);
+ strupper_m(unix_name);
+ push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
+ n->name_type = (unsigned int)type & 0xFF;
+ push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
+}
+
+static bool do_nodestatus(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv)
+{
+ struct packet_struct p;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
+ return False;
+ }
+
+ ZERO_STRUCT(p);
+
+ (void)interpret_addr2(&p.ip, argv[1]);
+ p.port = 137;
+ p.packet_type = NMB_PACKET;
+
+ p.packet.nmb.header.name_trn_id = 10;
+ p.packet.nmb.header.opcode = 0;
+ p.packet.nmb.header.response = False;
+ p.packet.nmb.header.nm_flags.bcast = False;
+ p.packet.nmb.header.nm_flags.recursion_available = False;
+ p.packet.nmb.header.nm_flags.recursion_desired = False;
+ p.packet.nmb.header.nm_flags.trunc = False;
+ p.packet.nmb.header.nm_flags.authoritative = False;
+ p.packet.nmb.header.rcode = 0;
+ p.packet.nmb.header.qdcount = 1;
+ p.packet.nmb.header.ancount = 0;
+ p.packet.nmb.header.nscount = 0;
+ p.packet.nmb.header.arcount = 0;
+ my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
+ p.packet.nmb.question.question_type = 0x21;
+ p.packet.nmb.question.question_class = 0x1;
+
+ return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
+}
+
+/* A list of message type supported */
+
+static const struct {
+ const char *name; /* Option name */
+ bool (*fn)(struct messaging_context *msg_ctx,
+ const struct server_id pid,
+ const int argc, const char **argv);
+ const char *help; /* Short help text */
+} msg_types[] = {
+ { "debug", do_debug, "Set debuglevel" },
+ { "force-election", do_election,
+ "Force a browse election" },
+ { "ping", do_ping, "Elicit a response" },
+ { "profile", do_profile, "" },
+ { "inject", do_inject_fault,
+ "Inject a fatal signal into a running smbd"},
+ { "stacktrace", do_daemon_stack_trace,
+ "Display a stack trace of a daemon" },
+ { "profilelevel", do_profilelevel, "" },
+ { "debuglevel", do_debuglevel, "Display current debuglevels" },
+ { "printnotify", do_printnotify, "Send a print notify message" },
+ { "close-share", do_closeshare, "Forcibly disconnect a share" },
+ { "lockretry", do_lockretry, "Force a blocking lock retry" },
+ { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
+ { "samsync", do_samsync, "Initiate SAM synchronisation" },
+ { "samrepl", do_samrepl, "Initiate SAM replication" },
+ { "pool-usage", do_poolusage, "Display talloc memory usage" },
+ { "dmalloc-mark", do_dmalloc_mark, "" },
+ { "dmalloc-log-changed", do_dmalloc_changed, "" },
+ { "shutdown", do_shutdown, "Shut down daemon" },
+ { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
+ { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
+ { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
+ { "online", do_winbind_online, "Ask winbind to go into online state"},
+ { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
+ { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
+ { "dump-event-list", do_dump_event_list, "Dump event list"},
+ { "validate-cache" , do_winbind_validate_cache,
+ "Validate winbind's credential cache" },
+ { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
+ { "noop", do_noop, "Do nothing" },
+ { NULL }
+};
+
+/* Display usage information */
+
+static void usage(poptContext pc)
+{
+ int i;
+
+ poptPrintHelp(pc, stderr, 0);
+
+ fprintf(stderr, "\n");
+ fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
+ "process ID\n");
+
+ fprintf(stderr, "\n");
+ fprintf(stderr, "<message-type> is one of:\n");
+
+ for (i = 0; msg_types[i].name; i++)
+ fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
+ msg_types[i].help);
+
+ fprintf(stderr, "\n");
+
+ exit(1);
+}
+
+/* Return the pid number for a string destination */
+
+static struct server_id parse_dest(const char *dest)
+{
+ struct server_id result = {-1};
+ pid_t pid;
+
+ /* Zero is a special return value for broadcast to all processes */
+
+ if (strequal(dest, "all")) {
+ return interpret_pid(MSG_BROADCAST_PID_STR);
+ }
+
+ /* Try self - useful for testing */
+
+ if (strequal(dest, "self")) {
+ return pid_to_procid(sys_getpid());
+ }
+
+ /* Fix winbind typo. */
+ if (strequal(dest, "winbind")) {
+ dest = "winbindd";
+ }
+
+ if (!(strequal(dest, "winbindd") || strequal(dest, "nmbd"))) {
+ /* Check for numeric pid number */
+
+ result = interpret_pid(dest);
+
+ /* Zero isn't valid if not smbd. */
+ if (result.pid && procid_valid(&result)) {
+ return result;
+ }
+ }
+
+ /* Look up other destinations in pidfile directory */
+
+ if ((pid = pidfile_pid(dest)) != 0) {
+ return pid_to_procid(pid);
+ }
+
+ fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
+
+ return result;
+}
+
+/* Execute smbcontrol command */
+
+static bool do_command(struct messaging_context *msg_ctx,
+ int argc, const char **argv)
+{
+ const char *dest = argv[0], *command = argv[1];
+ struct server_id pid;
+ int i;
+
+ /* Check destination */
+
+ pid = parse_dest(dest);
+ if (!procid_valid(&pid)) {
+ return False;
+ }
+
+ /* Check command */
+
+ for (i = 0; msg_types[i].name; i++) {
+ if (strequal(command, msg_types[i].name))
+ return msg_types[i].fn(msg_ctx, pid,
+ argc - 1, argv + 1);
+ }
+
+ fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
+
+ return False;
+}
+
+static void smbcontrol_help(poptContext pc,
+ enum poptCallbackReason preason,
+ struct poptOption * poption,
+ const char * parg,
+ void * pdata)
+{
+ if (poption->shortName != '?') {
+ poptPrintUsage(pc, stdout, 0);
+ } else {
+ usage(pc);
+ }
+
+ exit(0);
+}
+
+struct poptOption help_options[] = {
+ { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
+ NULL, NULL },
+ { "help", '?', 0, NULL, '?', "Show this help message", NULL },
+ { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
+ { NULL }
+} ;
+
+/* Main program */
+
+int main(int argc, const char **argv)
+{
+ poptContext pc;
+ int opt;
+ struct event_context *evt_ctx;
+ struct messaging_context *msg_ctx;
+
+ static struct poptOption long_options[] = {
+ /* POPT_AUTOHELP */
+ { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
+ 0, "Help options:", NULL },
+ { "timeout", 't', POPT_ARG_INT, &timeout, 't',
+ "Set timeout value in seconds", "TIMEOUT" },
+
+ POPT_COMMON_SAMBA
+ POPT_TABLEEND
+ };
+ TALLOC_CTX *frame = talloc_stackframe();
+ int ret = 0;
+
+ load_case_tables();
+
+ setup_logging(argv[0],True);
+
+ /* Parse command line arguments using popt */
+
+ pc = poptGetContext(
+ "smbcontrol", argc, (const char **)argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
+ "<parameters>");
+
+ if (argc == 1)
+ usage(pc);
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch(opt) {
+ case 't': /* --timeout */
+ break;
+ default:
+ fprintf(stderr, "Invalid option\n");
+ poptPrintHelp(pc, stderr, 0);
+ break;
+ }
+ }
+
+ /* We should now have the remaining command line arguments in
+ argv. The argc parameter should have been decremented to the
+ correct value in the above switch statement. */
+
+ argv = (const char **)poptGetArgs(pc);
+ argc = 0;
+ if (argv != NULL) {
+ while (argv[argc] != NULL) {
+ argc++;
+ }
+ }
+
+ if (argc <= 1)
+ usage(pc);
+
+ lp_load(get_dyn_CONFIGFILE(),False,False,False,True);
+
+ /* Need to invert sense of return code -- samba
+ * routines mostly return True==1 for success, but
+ * shell needs 0. */
+
+ if (!(evt_ctx = event_context_init(NULL)) ||
+ !(msg_ctx = messaging_init(NULL, server_id_self(), evt_ctx))) {
+ fprintf(stderr, "could not init messaging context\n");
+ TALLOC_FREE(frame);
+ exit(1);
+ }
+
+ ret = !do_command(msg_ctx, argc, argv);
+ TALLOC_FREE(frame);
+ return ret;
+}
diff --git a/source3/utils/smbcquotas.c b/source3/utils/smbcquotas.c
new file mode 100644
index 0000000000..11f8776a0e
--- /dev/null
+++ b/source3/utils/smbcquotas.c
@@ -0,0 +1,619 @@
+/*
+ Unix SMB/CIFS implementation.
+ QUOTA get/set utility
+
+ Copyright (C) Andrew Tridgell 2000
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Jeremy Allison 2000
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static char *server;
+
+/* numeric is set when the user wants numeric SIDs and ACEs rather
+ than going via LSA calls to resolve them */
+static bool numeric;
+static bool verbose;
+
+enum todo_values {NOOP_QUOTA=0,FS_QUOTA,USER_QUOTA,LIST_QUOTA,SET_QUOTA};
+enum exit_values {EXIT_OK, EXIT_FAILED, EXIT_PARSE_ERROR};
+
+static struct cli_state *cli_ipc;
+static struct rpc_pipe_client *global_pipe_hnd;
+static POLICY_HND pol;
+static bool got_policy_hnd;
+
+static struct cli_state *connect_one(const char *share);
+
+/* Open cli connection and policy handle */
+
+static bool cli_open_policy_hnd(void)
+{
+ /* Initialise cli LSA connection */
+
+ if (!cli_ipc) {
+ NTSTATUS ret;
+ cli_ipc = connect_one("IPC$");
+ ret = cli_rpc_pipe_open_noauth(cli_ipc,
+ &ndr_table_lsarpc.syntax_id,
+ &global_pipe_hnd);
+ if (!NT_STATUS_IS_OK(ret)) {
+ return False;
+ }
+ }
+
+ /* Open policy handle */
+
+ if (!got_policy_hnd) {
+
+ /* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED,
+ but NT sends 0x2000000 so we might as well do it too. */
+
+ if (!NT_STATUS_IS_OK(rpccli_lsa_open_policy(global_pipe_hnd, talloc_tos(), True,
+ GENERIC_EXECUTE_ACCESS, &pol))) {
+ return False;
+ }
+
+ got_policy_hnd = True;
+ }
+
+ return True;
+}
+
+/* convert a SID to a string, either numeric or username/group */
+static void SidToString(fstring str, DOM_SID *sid, bool _numeric)
+{
+ char **domains = NULL;
+ char **names = NULL;
+ enum lsa_SidType *types = NULL;
+
+ sid_to_fstring(str, sid);
+
+ if (_numeric) return;
+
+ /* Ask LSA to convert the sid to a name */
+
+ if (!cli_open_policy_hnd() ||
+ !NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(global_pipe_hnd, talloc_tos(),
+ &pol, 1, sid, &domains,
+ &names, &types)) ||
+ !domains || !domains[0] || !names || !names[0]) {
+ return;
+ }
+
+ /* Converted OK */
+
+ slprintf(str, sizeof(fstring) - 1, "%s%s%s",
+ domains[0], lp_winbind_separator(),
+ names[0]);
+
+}
+
+/* convert a string to a SID, either numeric or username/group */
+static bool StringToSid(DOM_SID *sid, const char *str)
+{
+ enum lsa_SidType *types = NULL;
+ DOM_SID *sids = NULL;
+ bool result = True;
+
+ if (strncmp(str, "S-", 2) == 0) {
+ return string_to_sid(sid, str);
+ }
+
+ if (!cli_open_policy_hnd() ||
+ !NT_STATUS_IS_OK(rpccli_lsa_lookup_names(global_pipe_hnd, talloc_tos(),
+ &pol, 1, &str, NULL, 1, &sids,
+ &types))) {
+ result = False;
+ goto done;
+ }
+
+ sid_copy(sid, &sids[0]);
+ done:
+
+ return result;
+}
+
+#define QUOTA_GET 1
+#define QUOTA_SETLIM 2
+#define QUOTA_SETFLAGS 3
+#define QUOTA_LIST 4
+
+enum {PARSE_FLAGS,PARSE_LIM};
+
+static int parse_quota_set(TALLOC_CTX *ctx,
+ char *set_str,
+ char **pp_username_str,
+ enum SMB_QUOTA_TYPE *qtype,
+ int *cmd,
+ SMB_NTQUOTA_STRUCT *pqt)
+{
+ char *p = set_str,*p2;
+ int todo;
+ bool stop = False;
+ bool enable = False;
+ bool deny = False;
+
+ *pp_username_str = NULL;
+ if (strnequal(set_str,"UQLIM:",6)) {
+ p += 6;
+ *qtype = SMB_USER_QUOTA_TYPE;
+ *cmd = QUOTA_SETLIM;
+ todo = PARSE_LIM;
+ if ((p2=strstr(p,":"))==NULL) {
+ return -1;
+ }
+
+ *p2 = '\0';
+ p2++;
+
+ *pp_username_str = talloc_strdup(ctx, p);
+ p = p2;
+ } else if (strnequal(set_str,"FSQLIM:",7)) {
+ p +=7;
+ *qtype = SMB_USER_FS_QUOTA_TYPE;
+ *cmd = QUOTA_SETLIM;
+ todo = PARSE_LIM;
+ } else if (strnequal(set_str,"FSQFLAGS:",9)) {
+ p +=9;
+ todo = PARSE_FLAGS;
+ *qtype = SMB_USER_FS_QUOTA_TYPE;
+ *cmd = QUOTA_SETFLAGS;
+ } else {
+ return -1;
+ }
+
+ switch (todo) {
+ case PARSE_LIM:
+#if defined(HAVE_LONGLONG)
+ if (sscanf(p,"%llu/%llu",&pqt->softlim,&pqt->hardlim)!=2) {
+#else
+ if (sscanf(p,"%lu/%lu",&pqt->softlim,&pqt->hardlim)!=2) {
+#endif
+ return -1;
+ }
+
+ break;
+ case PARSE_FLAGS:
+ while (!stop) {
+
+ if ((p2=strstr(p,"/"))==NULL) {
+ stop = True;
+ } else {
+ *p2 = '\0';
+ p2++;
+ }
+
+ if (strnequal(p,"QUOTA_ENABLED",13)) {
+ enable = True;
+ } else if (strnequal(p,"DENY_DISK",9)) {
+ deny = True;
+ } else if (strnequal(p,"LOG_SOFTLIMIT",13)) {
+ pqt->qflags |= QUOTAS_LOG_THRESHOLD;
+ } else if (strnequal(p,"LOG_HARDLIMIT",13)) {
+ pqt->qflags |= QUOTAS_LOG_LIMIT;
+ } else {
+ return -1;
+ }
+
+ p=p2;
+ }
+
+ if (deny) {
+ pqt->qflags |= QUOTAS_DENY_DISK;
+ } else if (enable) {
+ pqt->qflags |= QUOTAS_ENABLED;
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
+static int do_quota(struct cli_state *cli,
+ enum SMB_QUOTA_TYPE qtype,
+ uint16 cmd,
+ const char *username_str,
+ SMB_NTQUOTA_STRUCT *pqt)
+{
+ uint32 fs_attrs = 0;
+ int quota_fnum = 0;
+ SMB_NTQUOTA_LIST *qtl = NULL;
+ SMB_NTQUOTA_STRUCT qt;
+ ZERO_STRUCT(qt);
+
+ if (!cli_get_fs_attr_info(cli, &fs_attrs)) {
+ d_printf("Failed to get the filesystem attributes %s.\n",
+ cli_errstr(cli));
+ return -1;
+ }
+
+ if (!(fs_attrs & FILE_VOLUME_QUOTAS)) {
+ d_printf("Quotas are not supported by the server.\n");
+ return 0;
+ }
+
+ if (!cli_get_quota_handle(cli, &quota_fnum)) {
+ d_printf("Quotas are not enabled on this share.\n");
+ d_printf("Failed to open %s %s.\n",
+ FAKE_FILE_NAME_QUOTA_WIN32,cli_errstr(cli));
+ return -1;
+ }
+
+ switch(qtype) {
+ case SMB_USER_QUOTA_TYPE:
+ if (!StringToSid(&qt.sid, username_str)) {
+ d_printf("StringToSid() failed for [%s]\n",username_str);
+ return -1;
+ }
+
+ switch(cmd) {
+ case QUOTA_GET:
+ if (!cli_get_user_quota(cli, quota_fnum, &qt)) {
+ d_printf("%s cli_get_user_quota %s\n",
+ cli_errstr(cli),username_str);
+ return -1;
+ }
+ dump_ntquota(&qt,verbose,numeric,SidToString);
+ break;
+ case QUOTA_SETLIM:
+ pqt->sid = qt.sid;
+ if (!cli_set_user_quota(cli, quota_fnum, pqt)) {
+ d_printf("%s cli_set_user_quota %s\n",
+ cli_errstr(cli),username_str);
+ return -1;
+ }
+ if (!cli_get_user_quota(cli, quota_fnum, &qt)) {
+ d_printf("%s cli_get_user_quota %s\n",
+ cli_errstr(cli),username_str);
+ return -1;
+ }
+ dump_ntquota(&qt,verbose,numeric,SidToString);
+ break;
+ case QUOTA_LIST:
+ if (!cli_list_user_quota(cli, quota_fnum, &qtl)) {
+ d_printf("%s cli_set_user_quota %s\n",
+ cli_errstr(cli),username_str);
+ return -1;
+ }
+ dump_ntquota_list(&qtl,verbose,numeric,SidToString);
+ free_ntquota_list(&qtl);
+ break;
+ default:
+ d_printf("Unknown Error\n");
+ return -1;
+ }
+ break;
+ case SMB_USER_FS_QUOTA_TYPE:
+ switch(cmd) {
+ case QUOTA_GET:
+ if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
+ d_printf("%s cli_get_fs_quota_info\n",
+ cli_errstr(cli));
+ return -1;
+ }
+ dump_ntquota(&qt,True,numeric,NULL);
+ break;
+ case QUOTA_SETLIM:
+ if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
+ d_printf("%s cli_get_fs_quota_info\n",
+ cli_errstr(cli));
+ return -1;
+ }
+ qt.softlim = pqt->softlim;
+ qt.hardlim = pqt->hardlim;
+ if (!cli_set_fs_quota_info(cli, quota_fnum, &qt)) {
+ d_printf("%s cli_set_fs_quota_info\n",
+ cli_errstr(cli));
+ return -1;
+ }
+ if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
+ d_printf("%s cli_get_fs_quota_info\n",
+ cli_errstr(cli));
+ return -1;
+ }
+ dump_ntquota(&qt,True,numeric,NULL);
+ break;
+ case QUOTA_SETFLAGS:
+ if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
+ d_printf("%s cli_get_fs_quota_info\n",
+ cli_errstr(cli));
+ return -1;
+ }
+ qt.qflags = pqt->qflags;
+ if (!cli_set_fs_quota_info(cli, quota_fnum, &qt)) {
+ d_printf("%s cli_set_fs_quota_info\n",
+ cli_errstr(cli));
+ return -1;
+ }
+ if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
+ d_printf("%s cli_get_fs_quota_info\n",
+ cli_errstr(cli));
+ return -1;
+ }
+ dump_ntquota(&qt,True,numeric,NULL);
+ break;
+ default:
+ d_printf("Unknown Error\n");
+ return -1;
+ }
+ break;
+ default:
+ d_printf("Unknown Error\n");
+ return -1;
+ }
+
+ cli_close(cli, quota_fnum);
+
+ return 0;
+}
+
+/*****************************************************
+ Return a connection to a server.
+*******************************************************/
+
+static struct cli_state *connect_one(const char *share)
+{
+ struct cli_state *c;
+ struct sockaddr_storage ss;
+ NTSTATUS nt_status;
+ uint32_t flags = 0;
+
+ zero_addr(&ss);
+
+ if (get_cmdline_auth_info_use_machine_account() &&
+ !set_cmdline_auth_info_machine_account_creds()) {
+ return NULL;
+ }
+
+ if (get_cmdline_auth_info_use_kerberos()) {
+ flags |= CLI_FULL_CONNECTION_USE_KERBEROS |
+ CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
+
+ }
+
+ if (!get_cmdline_auth_info_got_pass()) {
+ char *pass = getpass("Password: ");
+ if (pass) {
+ set_cmdline_auth_info_password(pass);
+ }
+ }
+
+ nt_status = cli_full_connection(&c, global_myname(), server,
+ &ss, 0,
+ share, "?????",
+ get_cmdline_auth_info_username(),
+ lp_workgroup(),
+ get_cmdline_auth_info_password(),
+ flags,
+ get_cmdline_auth_info_signing_state(),
+ NULL);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0,("cli_full_connection failed! (%s)\n", nt_errstr(nt_status)));
+ return NULL;
+ }
+
+ if (get_cmdline_auth_info_smb_encrypt()) {
+ nt_status = cli_cm_force_encryption(c,
+ get_cmdline_auth_info_username(),
+ get_cmdline_auth_info_password(),
+ lp_workgroup(),
+ share);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ cli_shutdown(c);
+ return NULL;
+ }
+ }
+
+ return c;
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc, const char *argv[])
+{
+ char *share;
+ int opt;
+ int result;
+ int todo = 0;
+ char *username_str = NULL;
+ char *path = NULL;
+ char *set_str = NULL;
+ enum SMB_QUOTA_TYPE qtype = SMB_INVALID_QUOTA_TYPE;
+ int cmd = 0;
+ static bool test_args = False;
+ struct cli_state *cli;
+ bool fix_user = False;
+ SMB_NTQUOTA_STRUCT qt;
+ TALLOC_CTX *frame = talloc_stackframe();
+ poptContext pc;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "user", 'u', POPT_ARG_STRING, NULL, 'u', "Show quotas for user", "user" },
+ { "list", 'L', POPT_ARG_NONE, NULL, 'L', "List user quotas" },
+ { "fs", 'F', POPT_ARG_NONE, NULL, 'F', "Show filesystem quotas" },
+ { "set", 'S', POPT_ARG_STRING, NULL, 'S', "Set acls\n\
+SETSTRING:\n\
+UQLIM:<username>/<softlimit>/<hardlimit> for user quotas\n\
+FSQLIM:<softlimit>/<hardlimit> for filesystem defaults\n\
+FSQFLAGS:QUOTA_ENABLED/DENY_DISK/LOG_SOFTLIMIT/LOG_HARD_LIMIT", "SETSTRING" },
+ { "numeric", 'n', POPT_ARG_NONE, NULL, 'n', "Don't resolve sids or limits to names" },
+ { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "be verbose" },
+ { "test-args", 't', POPT_ARG_NONE, NULL, 'r', "Test arguments"},
+ POPT_COMMON_SAMBA
+ POPT_COMMON_CREDENTIALS
+ { NULL }
+ };
+
+ load_case_tables();
+
+ ZERO_STRUCT(qt);
+
+ /* set default debug level to 1 regardless of what smb.conf sets */
+ setup_logging( "smbcquotas", True );
+ DEBUGLEVEL_CLASS[DBGC_ALL] = 1;
+ dbf = x_stderr;
+ x_setbuf( x_stderr, NULL );
+
+ setlinebuf(stdout);
+
+ fault_setup(NULL);
+
+ lp_load(get_dyn_CONFIGFILE(),True,False,False,True);
+ load_interfaces();
+
+ pc = poptGetContext("smbcquotas", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "//server1/share1");
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'n':
+ numeric = true;
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 't':
+ test_args = true;
+ break;
+ case 'L':
+ if (todo != 0) {
+ d_printf("Please specify only one option of <-L|-F|-S|-u>\n");
+ exit(EXIT_PARSE_ERROR);
+ }
+ todo = LIST_QUOTA;
+ break;
+
+ case 'F':
+ if (todo != 0) {
+ d_printf("Please specify only one option of <-L|-F|-S|-u>\n");
+ exit(EXIT_PARSE_ERROR);
+ }
+ todo = FS_QUOTA;
+ break;
+
+ case 'u':
+ if (todo != 0) {
+ d_printf("Please specify only one option of <-L|-F|-S|-u>\n");
+ exit(EXIT_PARSE_ERROR);
+ }
+ username_str = talloc_strdup(frame, poptGetOptArg(pc));
+ if (!username_str) {
+ exit(EXIT_PARSE_ERROR);
+ }
+ todo = USER_QUOTA;
+ fix_user = True;
+ break;
+
+ case 'S':
+ if (todo != 0) {
+ d_printf("Please specify only one option of <-L|-F|-S|-u>\n");
+ exit(EXIT_PARSE_ERROR);
+ }
+ set_str = talloc_strdup(frame, poptGetOptArg(pc));
+ if (!set_str) {
+ exit(EXIT_PARSE_ERROR);
+ }
+ todo = SET_QUOTA;
+ break;
+ }
+ }
+
+ if (todo == 0)
+ todo = USER_QUOTA;
+
+ if (!fix_user) {
+ username_str = talloc_strdup(frame, get_cmdline_auth_info_username());
+ if (!username_str) {
+ exit(EXIT_PARSE_ERROR);
+ }
+ }
+
+ /* Make connection to server */
+ if(!poptPeekArg(pc)) {
+ poptPrintUsage(pc, stderr, 0);
+ exit(EXIT_PARSE_ERROR);
+ }
+
+ path = talloc_strdup(frame, poptGetArg(pc));
+ if (!path) {
+ printf("Out of memory\n");
+ exit(EXIT_PARSE_ERROR);
+ }
+
+ string_replace(path, '/', '\\');
+
+ server = SMB_STRDUP(path+2);
+ if (!server) {
+ printf("Out of memory\n");
+ exit(EXIT_PARSE_ERROR);
+ }
+ share = strchr_m(server,'\\');
+ if (!share) {
+ printf("Invalid argument: %s\n", share);
+ exit(EXIT_PARSE_ERROR);
+ }
+
+ *share = 0;
+ share++;
+
+ if (todo == SET_QUOTA) {
+ if (parse_quota_set(talloc_tos(), set_str, &username_str, &qtype, &cmd, &qt)) {
+ printf("Invalid argument: -S %s\n", set_str);
+ exit(EXIT_PARSE_ERROR);
+ }
+ }
+
+ if (!test_args) {
+ cli = connect_one(share);
+ if (!cli) {
+ exit(EXIT_FAILED);
+ }
+ } else {
+ exit(EXIT_OK);
+ }
+
+
+ /* Perform requested action */
+
+ switch (todo) {
+ case FS_QUOTA:
+ result = do_quota(cli,SMB_USER_FS_QUOTA_TYPE, QUOTA_GET, username_str, NULL);
+ break;
+ case LIST_QUOTA:
+ result = do_quota(cli,SMB_USER_QUOTA_TYPE, QUOTA_LIST, username_str, NULL);
+ break;
+ case USER_QUOTA:
+ result = do_quota(cli,SMB_USER_QUOTA_TYPE, QUOTA_GET, username_str, NULL);
+ break;
+ case SET_QUOTA:
+ result = do_quota(cli, qtype, cmd, username_str, &qt);
+ break;
+ default:
+
+ result = EXIT_FAILED;
+ break;
+ }
+
+ talloc_free(frame);
+
+ return result;
+}
diff --git a/source3/utils/smbfilter.c b/source3/utils/smbfilter.c
new file mode 100644
index 0000000000..d274e09299
--- /dev/null
+++ b/source3/utils/smbfilter.c
@@ -0,0 +1,287 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB filter/socket plugin
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#define SECURITY_MASK 0
+#define SECURITY_SET 0
+
+/* this forces non-unicode */
+#define CAPABILITY_MASK 0
+#define CAPABILITY_SET 0
+
+/* and non-unicode for the client too */
+#define CLI_CAPABILITY_MASK 0
+#define CLI_CAPABILITY_SET 0
+
+static char *netbiosname;
+static char packet[BUFFER_SIZE];
+
+static void save_file(const char *fname, void *ppacket, size_t length)
+{
+ int fd;
+ fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (fd == -1) {
+ perror(fname);
+ return;
+ }
+ if (write(fd, ppacket, length) != length) {
+ fprintf(stderr,"Failed to write %s\n", fname);
+ return;
+ }
+ close(fd);
+ printf("Wrote %ld bytes to %s\n", (unsigned long)length, fname);
+}
+
+static void filter_reply(char *buf)
+{
+ int msg_type = CVAL(buf,0);
+ int type = CVAL(buf,smb_com);
+ unsigned x;
+
+ if (msg_type) return;
+
+ switch (type) {
+
+ case SMBnegprot:
+ /* force the security bits */
+ x = CVAL(buf, smb_vwv1);
+ x = (x | SECURITY_SET) & ~SECURITY_MASK;
+ SCVAL(buf, smb_vwv1, x);
+
+ /* force the capabilities */
+ x = IVAL(buf,smb_vwv9+1);
+ x = (x | CAPABILITY_SET) & ~CAPABILITY_MASK;
+ SIVAL(buf, smb_vwv9+1, x);
+ break;
+
+ }
+}
+
+static void filter_request(char *buf)
+{
+ int msg_type = CVAL(buf,0);
+ int type = CVAL(buf,smb_com);
+ fstring name1,name2;
+ unsigned x;
+
+ if (msg_type) {
+ /* it's a netbios special */
+ switch (msg_type) {
+ case 0x81:
+ /* session request */
+ name_extract(buf,4,name1);
+ name_extract(buf,4 + name_len(buf + 4),name2);
+ d_printf("sesion_request: %s -> %s\n",
+ name1, name2);
+ if (netbiosname) {
+ /* replace the destination netbios name */
+ name_mangle(netbiosname, buf+4, 0x20);
+ }
+ }
+ return;
+ }
+
+ /* it's an ordinary SMB request */
+ switch (type) {
+ case SMBsesssetupX:
+ /* force the client capabilities */
+ x = IVAL(buf,smb_vwv11);
+ d_printf("SMBsesssetupX cap=0x%08x\n", x);
+ d_printf("pwlen=%d/%d\n", SVAL(buf, smb_vwv7), SVAL(buf, smb_vwv8));
+ system("mv sessionsetup.dat sessionsetup1.dat");
+ save_file("sessionsetup.dat", smb_buf(buf), SVAL(buf, smb_vwv7));
+ x = (x | CLI_CAPABILITY_SET) & ~CLI_CAPABILITY_MASK;
+ SIVAL(buf, smb_vwv11, x);
+ break;
+ }
+
+}
+
+/****************************************************************************
+ Send an smb to a fd.
+****************************************************************************/
+
+static bool send_smb(int fd, char *buffer)
+{
+ size_t len;
+ size_t nwritten=0;
+ ssize_t ret;
+
+ len = smb_len(buffer) + 4;
+
+ while (nwritten < len) {
+ ret = write_data(fd,buffer+nwritten,len - nwritten);
+ if (ret <= 0) {
+ DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n",
+ (int)len,(int)ret, strerror(errno) ));
+ return false;
+ }
+ nwritten += ret;
+ }
+
+ return true;
+}
+
+static void filter_child(int c, struct sockaddr_storage *dest_ss)
+{
+ int s;
+
+ /* we have a connection from a new client, now connect to the server */
+ s = open_socket_out(SOCK_STREAM, dest_ss, 445, LONG_CONNECT_TIMEOUT);
+
+ if (s == -1) {
+ char addr[INET6_ADDRSTRLEN];
+ if (dest_ss) {
+ print_sockaddr(addr, sizeof(addr), dest_ss);
+ }
+
+ d_printf("Unable to connect to %s (%s)\n",
+ dest_ss?addr:"NULL",strerror(errno));
+ exit(1);
+ }
+
+ while (c != -1 || s != -1) {
+ fd_set fds;
+ int num;
+
+ FD_ZERO(&fds);
+ if (s != -1) FD_SET(s, &fds);
+ if (c != -1) FD_SET(c, &fds);
+
+ num = sys_select_intr(MAX(s+1, c+1),&fds,NULL,NULL,NULL);
+ if (num <= 0) continue;
+
+ if (c != -1 && FD_ISSET(c, &fds)) {
+ size_t len;
+ if (!NT_STATUS_IS_OK(receive_smb_raw(
+ c, packet, sizeof(packet),
+ 0, 0, &len))) {
+ d_printf("client closed connection\n");
+ exit(0);
+ }
+ filter_request(packet);
+ if (!send_smb(s, packet)) {
+ d_printf("server is dead\n");
+ exit(1);
+ }
+ }
+ if (s != -1 && FD_ISSET(s, &fds)) {
+ size_t len;
+ if (!NT_STATUS_IS_OK(receive_smb_raw(
+ s, packet, sizeof(packet),
+ 0, 0, &len))) {
+ d_printf("server closed connection\n");
+ exit(0);
+ }
+ filter_reply(packet);
+ if (!send_smb(c, packet)) {
+ d_printf("client is dead\n");
+ exit(1);
+ }
+ }
+ }
+ d_printf("Connection closed\n");
+ exit(0);
+}
+
+
+static void start_filter(char *desthost)
+{
+ int s, c;
+ struct sockaddr_storage dest_ss;
+ struct sockaddr_storage my_ss;
+
+ CatchChild();
+
+ /* start listening on port 445 locally */
+
+ zero_addr(&my_ss);
+ s = open_socket_in(SOCK_STREAM, 445, 0, &my_ss, True);
+
+ if (s == -1) {
+ d_printf("bind failed\n");
+ exit(1);
+ }
+
+ if (listen(s, 5) == -1) {
+ d_printf("listen failed\n");
+ }
+
+ if (!resolve_name(desthost, &dest_ss, 0x20)) {
+ d_printf("Unable to resolve host %s\n", desthost);
+ exit(1);
+ }
+
+ while (1) {
+ fd_set fds;
+ int num;
+ struct sockaddr_storage ss;
+ socklen_t in_addrlen = sizeof(ss);
+
+ FD_ZERO(&fds);
+ FD_SET(s, &fds);
+
+ num = sys_select_intr(s+1,&fds,NULL,NULL,NULL);
+ if (num > 0) {
+ c = accept(s, (struct sockaddr *)&ss, &in_addrlen);
+ if (c != -1) {
+ if (fork() == 0) {
+ close(s);
+ filter_child(c, &dest_ss);
+ exit(0);
+ } else {
+ close(c);
+ }
+ }
+ }
+ }
+}
+
+
+int main(int argc, char *argv[])
+{
+ char *desthost;
+ const char *configfile;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ load_case_tables();
+
+ setup_logging(argv[0],True);
+
+ configfile = get_dyn_CONFIGFILE();
+
+ if (argc < 2) {
+ fprintf(stderr,"smbfilter <desthost> <netbiosname>\n");
+ exit(1);
+ }
+
+ desthost = argv[1];
+ if (argc > 2) {
+ netbiosname = argv[2];
+ }
+
+ if (!lp_load(configfile,True,False,False,True)) {
+ d_printf("Unable to load config file\n");
+ }
+
+ start_filter(desthost);
+ TALLOC_FREE(frame);
+ return 0;
+}
diff --git a/source3/utils/smbget.c b/source3/utils/smbget.c
new file mode 100644
index 0000000000..3d4a71b71d
--- /dev/null
+++ b/source3/utils/smbget.c
@@ -0,0 +1,644 @@
+/*
+ smbget: a wget-like utility with support for recursive downloading and
+ smb:// urls
+ Copyright (C) 2003-2004 Jelmer Vernooij <jelmer@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "includes.h"
+#include "libsmbclient.h"
+
+#if _FILE_OFFSET_BITS==64
+#define OFF_T_FORMAT "%lld"
+#define OFF_T_FORMAT_CAST long long
+#else
+#define OFF_T_FORMAT "%ld"
+#define OFF_T_FORMAT_CAST long
+#endif
+
+static int columns = 0;
+
+static int debuglevel, update;
+static char *outputfile;
+
+
+static time_t total_start_time = 0;
+static off_t total_bytes = 0;
+
+#define SMB_MAXPATHLEN MAXPATHLEN
+
+/* Number of bytes to read when checking whether local and remote file are really the same file */
+#define RESUME_CHECK_SIZE 512
+#define RESUME_DOWNLOAD_OFFSET 1024
+#define RESUME_CHECK_OFFSET RESUME_DOWNLOAD_OFFSET+RESUME_CHECK_SIZE
+/* Number of bytes to read at once */
+#define SMB_DEFAULT_BLOCKSIZE 64000
+
+static const char *username = NULL, *password = NULL, *workgroup = NULL;
+static int nonprompt = 0, quiet = 0, dots = 0, keep_permissions = 0, verbose = 0, send_stdout = 0;
+static int blocksize = SMB_DEFAULT_BLOCKSIZE;
+
+static int smb_download_file(const char *base, const char *name, int recursive, int resume, char *outfile);
+
+static int get_num_cols(void)
+{
+#ifdef TIOCGWINSZ
+ struct winsize ws;
+ if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0) {
+ return 0;
+ }
+ return ws.ws_col;
+#else
+#warning No support for TIOCGWINSZ
+ char *cols = getenv("COLUMNS");
+ if(!cols) return 0;
+ return atoi(cols);
+#endif
+}
+
+static void change_columns(int sig)
+{
+ columns = get_num_cols();
+}
+
+static void human_readable(off_t s, char *buffer, int l)
+{
+ if(s > 1024 * 1024 * 1024) snprintf(buffer, l, "%.2fGb", 1.0 * s / (1024 * 1024 * 1024));
+ else if(s > 1024 * 1024) snprintf(buffer, l, "%.2fMb", 1.0 * s / (1024 * 1024));
+ else if(s > 1024) snprintf(buffer, l, "%.2fkb", 1.0 * s / 1024);
+ else snprintf(buffer, l, OFF_T_FORMAT"b", (OFF_T_FORMAT_CAST)s);
+}
+
+static void get_auth_data(const char *srv, const char *shr, char *wg, int wglen, char *un, int unlen, char *pw, int pwlen)
+{
+ static char hasasked = 0;
+ char *wgtmp, *usertmp;
+ char tmp[128];
+
+ if(hasasked) return;
+ hasasked = 1;
+
+ if(!nonprompt && !username) {
+ printf("Username for %s at %s [guest] ", shr, srv);
+ fgets(tmp, sizeof(tmp), stdin);
+ if(tmp[strlen(tmp)-1] == '\n')tmp[strlen(tmp)-1] = '\0';
+ strncpy(un, tmp, unlen-1);
+ } else if(username) strncpy(un, username, unlen-1);
+
+ if(!nonprompt && !password) {
+ char *prompt, *pass;
+ asprintf(&prompt, "Password for %s at %s: ", shr, srv);
+ pass = getpass(prompt);
+ free(prompt);
+ strncpy(pw, pass, pwlen-1);
+ } else if(password) strncpy(pw, password, pwlen-1);
+
+ if(workgroup)strncpy(wg, workgroup, wglen-1);
+
+ wgtmp = SMB_STRNDUP(wg, wglen);
+ usertmp = SMB_STRNDUP(un, unlen);
+ if(!quiet)printf("Using workgroup %s, %s%s\n", wgtmp, *usertmp?"user ":"guest user", usertmp);
+ free(wgtmp); free(usertmp);
+}
+
+static int smb_download_dir(const char *base, const char *name, int resume)
+{
+ char path[SMB_MAXPATHLEN];
+ int dirhandle;
+ struct smbc_dirent *dirent;
+ const char *relname = name;
+ char *tmpname;
+ struct stat remotestat;
+ snprintf(path, SMB_MAXPATHLEN-1, "%s%s%s", base, (base[0] && name[0] && name[0] != '/' && base[strlen(base)-1] != '/')?"/":"", name);
+
+ /* List files in directory and call smb_download_file on them */
+ dirhandle = smbc_opendir(path);
+ if(dirhandle < 1) {
+ if(errno == ENOTDIR) return smb_download_file(base, name, 1, resume, NULL);
+ fprintf(stderr, "Can't open directory %s: %s\n", path, strerror(errno));
+ return 0;
+ }
+
+ while(*relname == '/')relname++;
+ mkdir(relname, 0755);
+
+ tmpname = SMB_STRDUP(name);
+
+ while((dirent = smbc_readdir(dirhandle))) {
+ char *newname;
+ if(!strcmp(dirent->name, ".") || !strcmp(dirent->name, ".."))continue;
+ asprintf(&newname, "%s/%s", tmpname, dirent->name);
+ switch(dirent->smbc_type) {
+ case SMBC_DIR:
+ smb_download_dir(base, newname, resume);
+ break;
+
+ case SMBC_WORKGROUP:
+ smb_download_dir("smb://", dirent->name, resume);
+ break;
+
+ case SMBC_SERVER:
+ smb_download_dir("smb://", dirent->name, resume);
+ break;
+
+ case SMBC_FILE:
+ smb_download_file(base, newname, 1, resume, NULL);
+ break;
+
+ case SMBC_FILE_SHARE:
+ smb_download_dir(base, newname, resume);
+ break;
+
+ case SMBC_PRINTER_SHARE:
+ if(!quiet)printf("Ignoring printer share %s\n", dirent->name);
+ break;
+
+ case SMBC_COMMS_SHARE:
+ if(!quiet)printf("Ignoring comms share %s\n", dirent->name);
+ break;
+
+ case SMBC_IPC_SHARE:
+ if(!quiet)printf("Ignoring ipc$ share %s\n", dirent->name);
+ break;
+
+ default:
+ fprintf(stderr, "Ignoring file '%s' of type '%d'\n", newname, dirent->smbc_type);
+ break;
+ }
+ free(newname);
+ }
+ free(tmpname);
+
+ if(keep_permissions) {
+ if(smbc_fstat(dirhandle, &remotestat) < 0) {
+ fprintf(stderr, "Unable to get stats on %s on remote server\n", path);
+ smbc_closedir(dirhandle);
+ return 0;
+ }
+
+ if(chmod(relname, remotestat.st_mode) < 0) {
+ fprintf(stderr, "Unable to change mode of local dir %s to %o\n", relname, remotestat.st_mode);
+ smbc_closedir(dirhandle);
+ return 0;
+ }
+ }
+
+ smbc_closedir(dirhandle);
+ return 1;
+}
+
+static char *print_time(long t)
+{
+ static char buffer[100];
+ int secs, mins, hours;
+ if(t < -1) {
+ strncpy(buffer, "Unknown", sizeof(buffer));
+ return buffer;
+ }
+
+ secs = (int)t % 60;
+ mins = (int)t / 60 % 60;
+ hours = (int)t / (60 * 60);
+ snprintf(buffer, sizeof(buffer)-1, "%02d:%02d:%02d", hours, mins, secs);
+ return buffer;
+}
+
+static void print_progress(const char *name, time_t start, time_t now, off_t start_pos, off_t pos, off_t total)
+{
+ double avg = 0.0;
+ long eta = -1;
+ double prcnt = 0.0;
+ char hpos[20], htotal[20], havg[20];
+ char *status, *filename;
+ int len;
+ if(now - start)avg = 1.0 * (pos - start_pos) / (now - start);
+ eta = (total - pos) / avg;
+ if(total)prcnt = 100.0 * pos / total;
+
+ human_readable(pos, hpos, sizeof(hpos));
+ human_readable(total, htotal, sizeof(htotal));
+ human_readable(avg, havg, sizeof(havg));
+
+ len = asprintf(&status, "%s of %s (%.2f%%) at %s/s ETA: %s", hpos, htotal, prcnt, havg, print_time(eta));
+
+ if(columns) {
+ int required = strlen(name), available = columns - len - strlen("[] ");
+ if(required > available) asprintf(&filename, "...%s", name + required - available + 3);
+ else filename = SMB_STRNDUP(name, available);
+ } else filename = SMB_STRDUP(name);
+
+ fprintf(stderr, "\r[%s] %s", filename, status);
+
+ free(filename); free(status);
+}
+
+static int smb_download_file(const char *base, const char *name, int recursive, int resume, char *outfile) {
+ int remotehandle, localhandle;
+ time_t start_time = time(NULL);
+ const char *newpath;
+ char path[SMB_MAXPATHLEN];
+ char checkbuf[2][RESUME_CHECK_SIZE];
+ char *readbuf = NULL;
+ off_t offset_download = 0, offset_check = 0, curpos = 0, start_offset = 0;
+ struct stat localstat, remotestat;
+
+ snprintf(path, SMB_MAXPATHLEN-1, "%s%s%s", base, (*base && *name && name[0] != '/' && base[strlen(base)-1] != '/')?"/":"", name);
+
+ remotehandle = smbc_open(path, O_RDONLY, 0755);
+
+ if(remotehandle < 0) {
+ switch(errno) {
+ case EISDIR:
+ if(!recursive) {
+ fprintf(stderr, "%s is a directory. Specify -R to download recursively\n", path);
+ return 0;
+ }
+ smb_download_dir(base, name, resume);
+ return 0;
+
+ case ENOENT:
+ fprintf(stderr, "%s can't be found on the remote server\n", path);
+ return 0;
+
+ case ENOMEM:
+ fprintf(stderr, "Not enough memory\n");
+ exit(1);
+ return 0;
+
+ case ENODEV:
+ fprintf(stderr, "The share name used in %s does not exist\n", path);
+ return 0;
+
+ case EACCES:
+ fprintf(stderr, "You don't have enough permissions to access %s\n", path);
+ return 0;
+
+ default:
+ perror("smbc_open");
+ return 0;
+ }
+ }
+
+ if(smbc_fstat(remotehandle, &remotestat) < 0) {
+ fprintf(stderr, "Can't stat %s: %s\n", path, strerror(errno));
+ return 0;
+ }
+
+ if(outfile) newpath = outfile;
+ else if(!name[0]) {
+ newpath = strrchr(base, '/');
+ if(newpath)newpath++; else newpath = base;
+ } else newpath = name;
+
+ if(newpath[0] == '/')newpath++;
+
+ /* Open local file according to the mode */
+ if(update) {
+ /* if it is up-to-date, skip */
+ if(stat(newpath, &localstat) == 0 &&
+ localstat.st_mtime >= remotestat.st_mtime) {
+ if(verbose)
+ printf("%s is up-to-date, skipping\n", newpath);
+ smbc_close(remotehandle);
+ return 0;
+ }
+ /* else open it for writing and truncate if it exists */
+ localhandle = open(newpath, O_CREAT | O_NONBLOCK | O_RDWR | O_TRUNC, 0775);
+ if(localhandle < 0) {
+ fprintf(stderr, "Can't open %s : %s\n", newpath,
+ strerror(errno));
+ smbc_close(remotehandle);
+ return 0;
+ }
+ /* no offset */
+ } else if(!send_stdout) {
+ localhandle = open(newpath, O_CREAT | O_NONBLOCK | O_RDWR | (!resume?O_EXCL:0), 0755);
+ if(localhandle < 0) {
+ fprintf(stderr, "Can't open %s: %s\n", newpath, strerror(errno));
+ smbc_close(remotehandle);
+ return 0;
+ }
+
+ if (fstat(localhandle, &localstat) != 0) {
+ fprintf(stderr, "Can't fstat %s: %s\n", newpath, strerror(errno));
+ smbc_close(remotehandle);
+ close(localhandle);
+ return 0;
+ }
+
+ start_offset = localstat.st_size;
+
+ if(localstat.st_size && localstat.st_size == remotestat.st_size) {
+ if(verbose)fprintf(stderr, "%s is already downloaded completely.\n", path);
+ else if(!quiet)fprintf(stderr, "%s\n", path);
+ smbc_close(remotehandle);
+ close(localhandle);
+ return 1;
+ }
+
+ if(localstat.st_size > RESUME_CHECK_OFFSET && remotestat.st_size > RESUME_CHECK_OFFSET) {
+ offset_download = localstat.st_size - RESUME_DOWNLOAD_OFFSET;
+ offset_check = localstat.st_size - RESUME_CHECK_OFFSET;
+ if(verbose)printf("Trying to start resume of %s at "OFF_T_FORMAT"\n"
+ "At the moment "OFF_T_FORMAT" of "OFF_T_FORMAT" bytes have been retrieved\n",
+ newpath, (OFF_T_FORMAT_CAST)offset_check,
+ (OFF_T_FORMAT_CAST)localstat.st_size,
+ (OFF_T_FORMAT_CAST)remotestat.st_size);
+ }
+
+ if(offset_check) {
+ off_t off1, off2;
+ /* First, check all bytes from offset_check to offset_download */
+ off1 = lseek(localhandle, offset_check, SEEK_SET);
+ if(off1 < 0) {
+ fprintf(stderr, "Can't seek to "OFF_T_FORMAT" in local file %s\n",
+ (OFF_T_FORMAT_CAST)offset_check, newpath);
+ smbc_close(remotehandle); close(localhandle);
+ return 0;
+ }
+
+ off2 = smbc_lseek(remotehandle, offset_check, SEEK_SET);
+ if(off2 < 0) {
+ fprintf(stderr, "Can't seek to "OFF_T_FORMAT" in remote file %s\n",
+ (OFF_T_FORMAT_CAST)offset_check, newpath);
+ smbc_close(remotehandle); close(localhandle);
+ return 0;
+ }
+
+ if(off1 != off2) {
+ fprintf(stderr, "Offset in local and remote files is different (local: "OFF_T_FORMAT", remote: "OFF_T_FORMAT")\n",
+ (OFF_T_FORMAT_CAST)off1,
+ (OFF_T_FORMAT_CAST)off2);
+ return 0;
+ }
+
+ if(smbc_read(remotehandle, checkbuf[0], RESUME_CHECK_SIZE) != RESUME_CHECK_SIZE) {
+ fprintf(stderr, "Can't read %d bytes from remote file %s\n", RESUME_CHECK_SIZE, path);
+ smbc_close(remotehandle); close(localhandle);
+ return 0;
+ }
+
+ if(read(localhandle, checkbuf[1], RESUME_CHECK_SIZE) != RESUME_CHECK_SIZE) {
+ fprintf(stderr, "Can't read %d bytes from local file %s\n", RESUME_CHECK_SIZE, name);
+ smbc_close(remotehandle); close(localhandle);
+ return 0;
+ }
+
+ if(memcmp(checkbuf[0], checkbuf[1], RESUME_CHECK_SIZE) == 0) {
+ if(verbose)printf("Current local and remote file appear to be the same. Starting download from offset "OFF_T_FORMAT"\n", (OFF_T_FORMAT_CAST)offset_download);
+ } else {
+ fprintf(stderr, "Local and remote file appear to be different, not doing resume for %s\n", path);
+ smbc_close(remotehandle); close(localhandle);
+ return 0;
+ }
+ }
+ } else {
+ localhandle = STDOUT_FILENO;
+ start_offset = 0;
+ offset_download = 0;
+ offset_check = 0;
+ }
+
+ readbuf = (char *)SMB_MALLOC(blocksize);
+
+ /* Now, download all bytes from offset_download to the end */
+ for(curpos = offset_download; curpos < remotestat.st_size; curpos+=blocksize) {
+ ssize_t bytesread = smbc_read(remotehandle, readbuf, blocksize);
+ if(bytesread < 0) {
+ fprintf(stderr, "Can't read %u bytes at offset "OFF_T_FORMAT", file %s\n", (unsigned int)blocksize, (OFF_T_FORMAT_CAST)curpos, path);
+ smbc_close(remotehandle);
+ if (localhandle != STDOUT_FILENO) close(localhandle);
+ free(readbuf);
+ return 0;
+ }
+
+ total_bytes += bytesread;
+
+ if(write(localhandle, readbuf, bytesread) < 0) {
+ fprintf(stderr, "Can't write %u bytes to local file %s at offset "OFF_T_FORMAT"\n", (unsigned int)bytesread, path, (OFF_T_FORMAT_CAST)curpos);
+ free(readbuf);
+ smbc_close(remotehandle);
+ if (localhandle != STDOUT_FILENO) close(localhandle);
+ return 0;
+ }
+
+ if(dots)fputc('.', stderr);
+ else if(!quiet) {
+ print_progress(newpath, start_time, time(NULL), start_offset, curpos, remotestat.st_size);
+ }
+ }
+
+ free(readbuf);
+
+ if(dots){
+ fputc('\n', stderr);
+ printf("%s downloaded\n", path);
+ } else if(!quiet) {
+ int i;
+ fprintf(stderr, "\r%s", path);
+ if(columns) {
+ for(i = strlen(path); i < columns; i++) {
+ fputc(' ', stderr);
+ }
+ }
+ fputc('\n', stderr);
+ }
+
+ if(keep_permissions && !send_stdout) {
+ if(fchmod(localhandle, remotestat.st_mode) < 0) {
+ fprintf(stderr, "Unable to change mode of local file %s to %o\n", path, remotestat.st_mode);
+ smbc_close(remotehandle);
+ close(localhandle);
+ return 0;
+ }
+ }
+
+ smbc_close(remotehandle);
+ if (localhandle != STDOUT_FILENO) close(localhandle);
+ return 1;
+}
+
+static void clean_exit(void)
+{
+ char bs[100];
+ human_readable(total_bytes, bs, sizeof(bs));
+ if(!quiet)fprintf(stderr, "Downloaded %s in %lu seconds\n", bs, time(NULL) - total_start_time);
+ exit(0);
+}
+
+static void signal_quit(int v)
+{
+ clean_exit();
+}
+
+static int readrcfile(const char *name, const struct poptOption long_options[])
+{
+ FILE *fd = fopen(name, "r");
+ int lineno = 0, i;
+ char var[101], val[101];
+ char found;
+ int *intdata; char **stringdata;
+ if(!fd) {
+ fprintf(stderr, "Can't open RC file %s\n", name);
+ return 1;
+ }
+
+ while(!feof(fd)) {
+ lineno++;
+ if(fscanf(fd, "%100s %100s\n", var, val) < 2) {
+ fprintf(stderr, "Can't parse line %d of %s, ignoring.\n", lineno, name);
+ continue;
+ }
+
+ found = 0;
+
+ for(i = 0; long_options[i].shortName; i++) {
+ if(!long_options[i].longName)continue;
+ if(strcmp(long_options[i].longName, var)) continue;
+ if(!long_options[i].arg)continue;
+
+ switch(long_options[i].argInfo) {
+ case POPT_ARG_NONE:
+ intdata = (int *)long_options[i].arg;
+ if(!strcmp(val, "on")) *intdata = 1;
+ else if(!strcmp(val, "off")) *intdata = 0;
+ else fprintf(stderr, "Illegal value %s for %s at line %d in %s\n", val, var, lineno, name);
+ break;
+ case POPT_ARG_INT:
+ intdata = (int *)long_options[i].arg;
+ *intdata = atoi(val);
+ break;
+ case POPT_ARG_STRING:
+ stringdata = (char **)long_options[i].arg;
+ *stringdata = SMB_STRDUP(val);
+ break;
+ default:
+ fprintf(stderr, "Invalid variable %s at line %d in %s\n", var, lineno, name);
+ break;
+ }
+
+ found = 1;
+ }
+ if(!found) {
+ fprintf(stderr, "Invalid variable %s at line %d in %s\n", var, lineno, name);
+ }
+ }
+
+ fclose(fd);
+ return 0;
+}
+
+int main(int argc, const char **argv)
+{
+ int c = 0;
+ const char *file = NULL;
+ char *rcfile = NULL;
+ bool smb_encrypt = false;
+ int resume = 0, recursive = 0;
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct poptOption long_options[] = {
+ {"guest", 'a', POPT_ARG_NONE, NULL, 'a', "Work as user guest" },
+ {"encrypt", 'e', POPT_ARG_NONE, NULL, 'e', "Encrypt SMB transport (UNIX extended servers only)" },
+ {"resume", 'r', POPT_ARG_NONE, &resume, 0, "Automatically resume aborted files" },
+ {"update", 'U', POPT_ARG_NONE, &update, 0, "Download only when remote file is newer than local file or local file is missing"},
+ {"recursive", 'R', POPT_ARG_NONE, &recursive, 0, "Recursively download files" },
+ {"username", 'u', POPT_ARG_STRING, &username, 'u', "Username to use" },
+ {"password", 'p', POPT_ARG_STRING, &password, 'p', "Password to use" },
+ {"workgroup", 'w', POPT_ARG_STRING, &workgroup, 'w', "Workgroup to use (optional)" },
+ {"nonprompt", 'n', POPT_ARG_NONE, &nonprompt, 'n', "Don't ask anything (non-interactive)" },
+ {"debuglevel", 'd', POPT_ARG_INT, &debuglevel, 'd', "Debuglevel to use" },
+ {"outputfile", 'o', POPT_ARG_STRING, &outputfile, 'o', "Write downloaded data to specified file" },
+ {"stdout", 'O', POPT_ARG_NONE, &send_stdout, 'O', "Write data to stdout" },
+ {"dots", 'D', POPT_ARG_NONE, &dots, 'D', "Show dots as progress indication" },
+ {"quiet", 'q', POPT_ARG_NONE, &quiet, 'q', "Be quiet" },
+ {"verbose", 'v', POPT_ARG_NONE, &verbose, 'v', "Be verbose" },
+ {"keep-permissions", 'P', POPT_ARG_NONE, &keep_permissions, 'P', "Keep permissions" },
+ {"blocksize", 'b', POPT_ARG_INT, &blocksize, 'b', "Change number of bytes in a block"},
+ {"rcfile", 'f', POPT_ARG_STRING, NULL, 0, "Use specified rc file"},
+ POPT_AUTOHELP
+ POPT_TABLEEND
+ };
+ poptContext pc;
+
+ load_case_tables();
+
+ /* only read rcfile if it exists */
+ asprintf(&rcfile, "%s/.smbgetrc", getenv("HOME"));
+ if(access(rcfile, F_OK) == 0)
+ readrcfile(rcfile, long_options);
+ free(rcfile);
+
+#ifdef SIGWINCH
+ signal(SIGWINCH, change_columns);
+#endif
+ signal(SIGINT, signal_quit);
+ signal(SIGTERM, signal_quit);
+
+ pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+
+ while((c = poptGetNextOpt(pc)) >= 0) {
+ switch(c) {
+ case 'f':
+ readrcfile(poptGetOptArg(pc), long_options);
+ break;
+ case 'a':
+ username = ""; password = "";
+ break;
+ case 'e':
+ smb_encrypt = true;
+ break;
+ }
+ }
+
+ if((send_stdout || resume || outputfile) && update) {
+ fprintf(stderr, "The -o, -R or -O and -U options can not be used together.\n");
+ return 1;
+ }
+ if((send_stdout || outputfile) && recursive) {
+ fprintf(stderr, "The -o or -O and -R options can not be used together.\n");
+ return 1;
+ }
+
+ if(outputfile && send_stdout) {
+ fprintf(stderr, "The -o and -O options cannot be used together.\n");
+ return 1;
+ }
+
+ if(smbc_init(get_auth_data, debuglevel) < 0) {
+ fprintf(stderr, "Unable to initialize libsmbclient\n");
+ return 1;
+ }
+
+ if (smb_encrypt) {
+ SMBCCTX *smb_ctx = smbc_set_context(NULL);
+ smbc_option_set(smb_ctx,
+ CONST_DISCARD(char *, "smb_encrypt_level"),
+ "require");
+ }
+
+ columns = get_num_cols();
+
+ total_start_time = time(NULL);
+
+ while ( (file = poptGetArg(pc)) ) {
+ if (!recursive)
+ return smb_download_file(file, "", recursive, resume, outputfile);
+ else
+ return smb_download_dir(file, "", resume);
+ }
+
+ clean_exit();
+ TALLOC_FREE(frame);
+ return 0;
+}
diff --git a/source3/utils/smbpasswd.c b/source3/utils/smbpasswd.c
new file mode 100644
index 0000000000..600fe52f0d
--- /dev/null
+++ b/source3/utils/smbpasswd.c
@@ -0,0 +1,603 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Jeremy Allison 1995-1998
+ * Copyright (C) Tim Potter 2001
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>. */
+
+#include "includes.h"
+
+extern bool AllowDebugChange;
+
+/*
+ * Next two lines needed for SunOS and don't
+ * hurt anything else...
+ */
+extern char *optarg;
+extern int optind;
+
+/* forced running in root-mode */
+static bool got_username = False;
+static bool stdin_passwd_get = False;
+static fstring user_name;
+static char *new_passwd = NULL;
+static const char *remote_machine = NULL;
+
+static fstring ldap_secret;
+
+
+/*********************************************************
+ Print command usage on stderr and die.
+**********************************************************/
+static void usage(void)
+{
+ printf("When run by root:\n");
+ printf(" smbpasswd [options] [username]\n");
+ printf("otherwise:\n");
+ printf(" smbpasswd [options]\n\n");
+
+ printf("options:\n");
+ printf(" -L local mode (must be first option)\n");
+ printf(" -h print this usage message\n");
+ printf(" -s use stdin for password prompt\n");
+ printf(" -c smb.conf file Use the given path to the smb.conf file\n");
+ printf(" -D LEVEL debug level\n");
+ printf(" -r MACHINE remote machine\n");
+ printf(" -U USER remote username\n");
+
+ printf("extra options when run by root or in local mode:\n");
+ printf(" -a add user\n");
+ printf(" -d disable user\n");
+ printf(" -e enable user\n");
+ printf(" -i interdomain trust account\n");
+ printf(" -m machine trust account\n");
+ printf(" -n set no password\n");
+ printf(" -W use stdin ldap admin password\n");
+ printf(" -w PASSWORD ldap admin password\n");
+ printf(" -x delete user\n");
+ printf(" -R ORDER name resolve order\n");
+
+ exit(1);
+}
+
+static void set_line_buffering(FILE *f)
+{
+ setvbuf(f, NULL, _IOLBF, 0);
+}
+
+/*******************************************************************
+ Process command line options
+ ******************************************************************/
+
+static int process_options(int argc, char **argv, int local_flags)
+{
+ int ch;
+ const char *configfile = get_dyn_CONFIGFILE();
+
+ local_flags |= LOCAL_SET_PASSWORD;
+
+ ZERO_STRUCT(user_name);
+
+ user_name[0] = '\0';
+
+ while ((ch = getopt(argc, argv, "c:axdehminjr:sw:R:D:U:LW")) != EOF) {
+ switch(ch) {
+ case 'L':
+#if !defined(NSS_WRAPPER)
+ if (getuid() != 0) {
+ fprintf(stderr, "smbpasswd -L can only be used by root.\n");
+ exit(1);
+ }
+#endif
+ local_flags |= LOCAL_AM_ROOT;
+ break;
+ case 'c':
+ configfile = optarg;
+ break;
+ case 'a':
+ local_flags |= LOCAL_ADD_USER;
+ break;
+ case 'x':
+ local_flags |= LOCAL_DELETE_USER;
+ local_flags &= ~LOCAL_SET_PASSWORD;
+ break;
+ case 'd':
+ local_flags |= LOCAL_DISABLE_USER;
+ local_flags &= ~LOCAL_SET_PASSWORD;
+ break;
+ case 'e':
+ local_flags |= LOCAL_ENABLE_USER;
+ local_flags &= ~LOCAL_SET_PASSWORD;
+ break;
+ case 'm':
+ local_flags |= LOCAL_TRUST_ACCOUNT;
+ break;
+ case 'i':
+ local_flags |= LOCAL_INTERDOM_ACCOUNT;
+ break;
+ case 'j':
+ d_printf("See 'net join' for this functionality\n");
+ exit(1);
+ break;
+ case 'n':
+ local_flags |= LOCAL_SET_NO_PASSWORD;
+ local_flags &= ~LOCAL_SET_PASSWORD;
+ new_passwd = smb_xstrdup("NO PASSWORD");
+ break;
+ case 'r':
+ remote_machine = optarg;
+ break;
+ case 's':
+ set_line_buffering(stdin);
+ set_line_buffering(stdout);
+ set_line_buffering(stderr);
+ stdin_passwd_get = True;
+ break;
+ case 'w':
+ local_flags |= LOCAL_SET_LDAP_ADMIN_PW;
+ fstrcpy(ldap_secret, optarg);
+ break;
+ case 'R':
+ lp_set_name_resolve_order(optarg);
+ break;
+ case 'D':
+ DEBUGLEVEL = atoi(optarg);
+ break;
+ case 'U': {
+ got_username = True;
+ fstrcpy(user_name, optarg);
+ break;
+ case 'W':
+ local_flags |= LOCAL_SET_LDAP_ADMIN_PW;
+ *ldap_secret = '\0';
+ break;
+ }
+ case 'h':
+ default:
+ usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ switch(argc) {
+ case 0:
+ if (!got_username)
+ fstrcpy(user_name, "");
+ break;
+ case 1:
+ if (!(local_flags & LOCAL_AM_ROOT)) {
+ usage();
+ } else {
+ if (got_username) {
+ usage();
+ } else {
+ fstrcpy(user_name, argv[0]);
+ }
+ }
+ break;
+ default:
+ usage();
+ }
+
+ if (!lp_load(configfile,True,False,False,True)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n",
+ configfile);
+ exit(1);
+ }
+
+ return local_flags;
+}
+
+/*************************************************************
+ Utility function to prompt for new password.
+*************************************************************/
+static char *prompt_for_new_password(bool stdin_get)
+{
+ char *p;
+ fstring new_pw;
+
+ ZERO_ARRAY(new_pw);
+
+ p = get_pass("New SMB password:", stdin_get);
+
+ fstrcpy(new_pw, p);
+ SAFE_FREE(p);
+
+ p = get_pass("Retype new SMB password:", stdin_get);
+
+ if (strcmp(p, new_pw)) {
+ fprintf(stderr, "Mismatch - password unchanged.\n");
+ ZERO_ARRAY(new_pw);
+ SAFE_FREE(p);
+ return NULL;
+ }
+
+ return p;
+}
+
+
+/*************************************************************
+ Change a password either locally or remotely.
+*************************************************************/
+
+static NTSTATUS password_change(const char *remote_mach, char *username,
+ char *old_passwd, char *new_pw,
+ int local_flags)
+{
+ NTSTATUS ret;
+ char *err_str = NULL;
+ char *msg_str = NULL;
+
+ if (remote_mach != NULL) {
+ if (local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|
+ LOCAL_TRUST_ACCOUNT|LOCAL_SET_NO_PASSWORD)) {
+ /* these things can't be done remotely yet */
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ ret = remote_password_change(remote_mach, username,
+ old_passwd, new_pw, &err_str);
+ if (err_str != NULL)
+ fprintf(stderr, "%s", err_str);
+ SAFE_FREE(err_str);
+ return ret;
+ }
+
+ ret = local_password_change(username, local_flags, new_pw,
+ &err_str, &msg_str);
+
+ if(msg_str)
+ printf("%s", msg_str);
+ if(err_str)
+ fprintf(stderr, "%s", err_str);
+
+ SAFE_FREE(msg_str);
+ SAFE_FREE(err_str);
+ return ret;
+}
+
+/*******************************************************************
+ Store the LDAP admin password in secrets.tdb
+ ******************************************************************/
+static bool store_ldap_admin_pw (char* pw)
+{
+ if (!pw)
+ return False;
+
+ if (!secrets_init())
+ return False;
+
+ return secrets_store_ldap_pw(lp_ldap_admin_dn(), pw);
+}
+
+
+/*************************************************************
+ Handle password changing for root.
+*************************************************************/
+
+static int process_root(int local_flags)
+{
+ struct passwd *pwd;
+ int result = 0;
+ char *old_passwd = NULL;
+
+ if (local_flags & LOCAL_SET_LDAP_ADMIN_PW) {
+ char *ldap_admin_dn = lp_ldap_admin_dn();
+ if ( ! *ldap_admin_dn ) {
+ DEBUG(0,("ERROR: 'ldap admin dn' not defined! Please check your smb.conf\n"));
+ goto done;
+ }
+
+ printf("Setting stored password for \"%s\" in secrets.tdb\n", ldap_admin_dn);
+ if ( ! *ldap_secret ) {
+ new_passwd = prompt_for_new_password(stdin_passwd_get);
+ fstrcpy(ldap_secret, new_passwd);
+ }
+ if (!store_ldap_admin_pw(ldap_secret)) {
+ DEBUG(0,("ERROR: Failed to store the ldap admin password!\n"));
+ }
+ goto done;
+ }
+
+ /* Ensure passdb startup(). */
+ if(!initialize_password_db(False, NULL)) {
+ DEBUG(0, ("Failed to open passdb!\n"));
+ exit(1);
+ }
+
+ /* Ensure we have a SAM sid. */
+ get_global_sam_sid();
+
+ /*
+ * Ensure both add/delete user are not set
+ * Ensure add/delete user and either remote machine or join domain are
+ * not both set.
+ */
+ if(((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) == (LOCAL_ADD_USER|LOCAL_DELETE_USER)) ||
+ ((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) &&
+ (remote_machine != NULL))) {
+ usage();
+ }
+
+ /* Only load interfaces if we are doing network operations. */
+
+ if (remote_machine) {
+ load_interfaces();
+ }
+
+ if (!user_name[0] && (pwd = getpwuid_alloc(NULL, geteuid()))) {
+ fstrcpy(user_name, pwd->pw_name);
+ TALLOC_FREE(pwd);
+ }
+
+ if (!user_name[0]) {
+ fprintf(stderr,"You must specify a username\n");
+ exit(1);
+ }
+
+ if (local_flags & LOCAL_TRUST_ACCOUNT) {
+ /* add the $ automatically */
+ static fstring buf;
+
+ /*
+ * Remove any trailing '$' before we
+ * generate the initial machine password.
+ */
+
+ if (user_name[strlen(user_name)-1] == '$') {
+ user_name[strlen(user_name)-1] = 0;
+ }
+
+ if (local_flags & LOCAL_ADD_USER) {
+ SAFE_FREE(new_passwd);
+ new_passwd = smb_xstrdup(user_name);
+ strlower_m(new_passwd);
+ }
+
+ /*
+ * Now ensure the username ends in '$' for
+ * the machine add.
+ */
+
+ slprintf(buf, sizeof(buf)-1, "%s$", user_name);
+ fstrcpy(user_name, buf);
+ } else if (local_flags & LOCAL_INTERDOM_ACCOUNT) {
+ static fstring buf;
+
+ if ((local_flags & LOCAL_ADD_USER) && (new_passwd == NULL)) {
+ /*
+ * Prompt for trusting domain's account password
+ */
+ new_passwd = prompt_for_new_password(stdin_passwd_get);
+ if(!new_passwd) {
+ fprintf(stderr, "Unable to get newpassword.\n");
+ exit(1);
+ }
+ }
+
+ /* prepare uppercased and '$' terminated username */
+ slprintf(buf, sizeof(buf) - 1, "%s$", user_name);
+ fstrcpy(user_name, buf);
+
+ } else {
+
+ if (remote_machine != NULL) {
+ old_passwd = get_pass("Old SMB password:",stdin_passwd_get);
+ }
+
+ if (!(local_flags & LOCAL_SET_PASSWORD)) {
+
+ /*
+ * If we are trying to enable a user, first we need to find out
+ * if they are using a modern version of the smbpasswd file that
+ * disables a user by just writing a flag into the file. If so
+ * then we can re-enable a user without prompting for a new
+ * password. If not (ie. they have a no stored password in the
+ * smbpasswd file) then we need to prompt for a new password.
+ */
+
+ if(local_flags & LOCAL_ENABLE_USER) {
+ struct samu *sampass = NULL;
+
+ sampass = samu_new( NULL );
+ if (!sampass) {
+ fprintf(stderr, "talloc fail for struct samu.\n");
+ exit(1);
+ }
+ if (!pdb_getsampwnam(sampass, user_name)) {
+ fprintf(stderr, "Failed to find user %s in passdb backend.\n",
+ user_name );
+ exit(1);
+ }
+
+ if(pdb_get_nt_passwd(sampass) == NULL) {
+ local_flags |= LOCAL_SET_PASSWORD;
+ }
+ TALLOC_FREE(sampass);
+ }
+ }
+
+ if((local_flags & LOCAL_SET_PASSWORD) && (new_passwd == NULL)) {
+ new_passwd = prompt_for_new_password(stdin_passwd_get);
+
+ if(!new_passwd) {
+ fprintf(stderr, "Unable to get new password.\n");
+ exit(1);
+ }
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(password_change(remote_machine, user_name,
+ old_passwd, new_passwd,
+ local_flags))) {
+ fprintf(stderr,"Failed to modify password entry for user %s\n", user_name);
+ result = 1;
+ goto done;
+ }
+
+ if(remote_machine) {
+ printf("Password changed for user %s on %s.\n", user_name, remote_machine );
+ } else if(!(local_flags & (LOCAL_ADD_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|LOCAL_DELETE_USER|LOCAL_SET_NO_PASSWORD|LOCAL_SET_PASSWORD))) {
+ struct samu *sampass = NULL;
+
+ sampass = samu_new( NULL );
+ if (!sampass) {
+ fprintf(stderr, "talloc fail for struct samu.\n");
+ exit(1);
+ }
+
+ if (!pdb_getsampwnam(sampass, user_name)) {
+ fprintf(stderr, "Failed to find user %s in passdb backend.\n",
+ user_name );
+ exit(1);
+ }
+
+ printf("Password changed for user %s.", user_name );
+ if(pdb_get_acct_ctrl(sampass)&ACB_DISABLED) {
+ printf(" User has disabled flag set.");
+ }
+ if(pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ) {
+ printf(" User has no password flag set.");
+ }
+ printf("\n");
+ TALLOC_FREE(sampass);
+ }
+
+ done:
+ SAFE_FREE(new_passwd);
+ return result;
+}
+
+
+/*************************************************************
+ Handle password changing for non-root.
+*************************************************************/
+
+static int process_nonroot(int local_flags)
+{
+ struct passwd *pwd = NULL;
+ int result = 0;
+ char *old_pw = NULL;
+ char *new_pw = NULL;
+
+ if (local_flags & ~(LOCAL_AM_ROOT | LOCAL_SET_PASSWORD)) {
+ /* Extra flags that we can't honor non-root */
+ usage();
+ }
+
+ if (!user_name[0]) {
+ pwd = getpwuid_alloc(NULL, getuid());
+ if (pwd) {
+ fstrcpy(user_name,pwd->pw_name);
+ TALLOC_FREE(pwd);
+ } else {
+ fprintf(stderr, "smbpasswd: cannot lookup user name for uid %u\n", (unsigned int)getuid());
+ exit(1);
+ }
+ }
+
+ /*
+ * A non-root user is always setting a password
+ * via a remote machine (even if that machine is
+ * localhost).
+ */
+
+ load_interfaces(); /* Delayed from main() */
+
+ if (remote_machine == NULL) {
+ remote_machine = "127.0.0.1";
+ }
+
+ if (remote_machine != NULL) {
+ old_pw = get_pass("Old SMB password:",stdin_passwd_get);
+ }
+
+ if (!new_passwd) {
+ new_pw = prompt_for_new_password(stdin_passwd_get);
+ }
+ else
+ new_pw = smb_xstrdup(new_passwd);
+
+ if (!new_pw) {
+ fprintf(stderr, "Unable to get new password.\n");
+ exit(1);
+ }
+
+ if (!NT_STATUS_IS_OK(password_change(remote_machine, user_name, old_pw,
+ new_pw, 0))) {
+ fprintf(stderr,"Failed to change password for %s\n", user_name);
+ result = 1;
+ goto done;
+ }
+
+ printf("Password changed for user %s\n", user_name);
+
+ done:
+ SAFE_FREE(old_pw);
+ SAFE_FREE(new_pw);
+
+ return result;
+}
+
+
+
+/*********************************************************
+ Start here.
+**********************************************************/
+int main(int argc, char **argv)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ int local_flags = 0;
+ int ret;
+
+ AllowDebugChange = False;
+
+#if defined(HAVE_SET_AUTH_PARAMETERS)
+ set_auth_parameters(argc, argv);
+#endif /* HAVE_SET_AUTH_PARAMETERS */
+
+ if (getuid() == 0) {
+ local_flags = LOCAL_AM_ROOT;
+ }
+
+ load_case_tables();
+
+ local_flags = process_options(argc, argv, local_flags);
+
+ setup_logging("smbpasswd", True);
+
+ /*
+ * Set the machine NETBIOS name if not already
+ * set from the config file.
+ */
+
+ if (!init_names())
+ return 1;
+
+ /* Check the effective uid - make sure we are not setuid */
+ if (is_setuid_root()) {
+ fprintf(stderr, "smbpasswd must *NOT* be setuid root.\n");
+ exit(1);
+ }
+
+ if (local_flags & LOCAL_AM_ROOT) {
+ secrets_init();
+ return process_root(local_flags);
+ }
+
+ ret = process_nonroot(local_flags);
+ TALLOC_FREE(frame);
+ return ret;
+}
diff --git a/source3/utils/smbtree.c b/source3/utils/smbtree.c
new file mode 100644
index 0000000000..ce2de4d7fe
--- /dev/null
+++ b/source3/utils/smbtree.c
@@ -0,0 +1,332 @@
+/*
+ Unix SMB/CIFS implementation.
+ Network neighbourhood browser.
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Jelmer Vernooij 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+static int use_bcast;
+
+/* How low can we go? */
+
+enum tree_level {LEV_WORKGROUP, LEV_SERVER, LEV_SHARE};
+static enum tree_level level = LEV_SHARE;
+
+/* Holds a list of workgroups or servers */
+
+struct name_list {
+ struct name_list *prev, *next;
+ char *name, *comment;
+ uint32 server_type;
+};
+
+static struct name_list *workgroups, *servers, *shares;
+
+static void free_name_list(struct name_list *list)
+{
+ while(list)
+ DLIST_REMOVE(list, list);
+}
+
+static void add_name(const char *machine_name, uint32 server_type,
+ const char *comment, void *state)
+{
+ struct name_list **name_list = (struct name_list **)state;
+ struct name_list *new_name;
+
+ new_name = SMB_MALLOC_P(struct name_list);
+
+ if (!new_name)
+ return;
+
+ ZERO_STRUCTP(new_name);
+
+ new_name->name = SMB_STRDUP(machine_name);
+ new_name->comment = SMB_STRDUP(comment);
+ new_name->server_type = server_type;
+
+ if (!new_name->name || !new_name->comment) {
+ SAFE_FREE(new_name->name);
+ SAFE_FREE(new_name->comment);
+ SAFE_FREE(new_name);
+ return;
+ }
+
+ DLIST_ADD(*name_list, new_name);
+}
+
+/****************************************************************************
+ display tree of smb workgroups, servers and shares
+****************************************************************************/
+static bool get_workgroups(struct user_auth_info *user_info)
+{
+ struct cli_state *cli;
+ struct sockaddr_storage server_ss;
+ TALLOC_CTX *ctx = talloc_tos();
+ char *master_workgroup = NULL;
+
+ /* Try to connect to a #1d name of our current workgroup. If that
+ doesn't work broadcast for a master browser and then jump off
+ that workgroup. */
+
+ master_workgroup = talloc_strdup(ctx, lp_workgroup());
+ if (!master_workgroup) {
+ return false;
+ }
+
+ if (!use_bcast && !find_master_ip(lp_workgroup(), &server_ss)) {
+ DEBUG(4, ("Unable to find master browser for workgroup %s, falling back to broadcast\n",
+ master_workgroup));
+ use_bcast = True;
+ } else if(!use_bcast) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr), &server_ss);
+ if (!(cli = get_ipc_connect(addr, &server_ss, user_info)))
+ return False;
+ }
+
+ if (!(cli = get_ipc_connect_master_ip_bcast(talloc_tos(),
+ user_info,
+ &master_workgroup))) {
+ DEBUG(4, ("Unable to find master browser by "
+ "broadcast\n"));
+ return False;
+ }
+
+ if (!cli_NetServerEnum(cli, master_workgroup,
+ SV_TYPE_DOMAIN_ENUM, add_name, &workgroups))
+ return False;
+
+ return True;
+}
+
+/* Retrieve the list of servers for a given workgroup */
+
+static bool get_servers(char *workgroup, struct user_auth_info *user_info)
+{
+ struct cli_state *cli;
+ struct sockaddr_storage server_ss;
+ char addr[INET6_ADDRSTRLEN];
+
+ /* Open an IPC$ connection to the master browser for the workgroup */
+
+ if (!find_master_ip(workgroup, &server_ss)) {
+ DEBUG(4, ("Cannot find master browser for workgroup %s\n",
+ workgroup));
+ return False;
+ }
+
+ print_sockaddr(addr, sizeof(addr), &server_ss);
+ if (!(cli = get_ipc_connect(addr, &server_ss, user_info)))
+ return False;
+
+ if (!cli_NetServerEnum(cli, workgroup, SV_TYPE_ALL, add_name,
+ &servers))
+ return False;
+
+ return True;
+}
+
+static bool get_rpc_shares(struct cli_state *cli,
+ void (*fn)(const char *, uint32, const char *, void *),
+ void *state)
+{
+ NTSTATUS status;
+ struct rpc_pipe_client *pipe_hnd;
+ TALLOC_CTX *mem_ctx;
+ WERROR werr;
+ struct srvsvc_NetShareInfoCtr info_ctr;
+ struct srvsvc_NetShareCtr1 ctr1;
+ int i;
+ uint32_t resume_handle = 0;
+ uint32_t total_entries = 0;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return False;
+ }
+
+ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc.syntax_id,
+ &pipe_hnd);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Could not connect to srvsvc pipe: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(mem_ctx);
+ return False;
+ }
+
+ ZERO_STRUCT(info_ctr);
+ ZERO_STRUCT(ctr1);
+
+ info_ctr.level = 1;
+ info_ctr.ctr.ctr1 = &ctr1;
+
+ status = rpccli_srvsvc_NetShareEnumAll(pipe_hnd, mem_ctx,
+ pipe_hnd->desthost,
+ &info_ctr,
+ 0xffffffff,
+ &total_entries,
+ &resume_handle,
+ &werr);
+
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(werr)) {
+ TALLOC_FREE(mem_ctx);
+ TALLOC_FREE(pipe_hnd);
+ return False;
+ }
+
+ for (i=0; i<total_entries; i++) {
+ struct srvsvc_NetShareInfo1 info = info_ctr.ctr.ctr1->array[i];
+ fn(info.name, info.type, info.comment, state);
+ }
+
+ TALLOC_FREE(mem_ctx);
+ TALLOC_FREE(pipe_hnd);
+ return True;
+}
+
+
+static bool get_shares(char *server_name, struct user_auth_info *user_info)
+{
+ struct cli_state *cli;
+
+ if (!(cli = get_ipc_connect(server_name, NULL, user_info)))
+ return False;
+
+ if (get_rpc_shares(cli, add_name, &shares))
+ return True;
+
+ if (!cli_RNetShareEnum(cli, add_name, &shares))
+ return False;
+
+ return True;
+}
+
+static bool print_tree(struct user_auth_info *user_info)
+{
+ struct name_list *wg, *sv, *sh;
+
+ /* List workgroups */
+
+ if (!get_workgroups(user_info))
+ return False;
+
+ for (wg = workgroups; wg; wg = wg->next) {
+
+ printf("%s\n", wg->name);
+
+ /* List servers */
+
+ free_name_list(servers);
+ servers = NULL;
+
+ if (level == LEV_WORKGROUP ||
+ !get_servers(wg->name, user_info))
+ continue;
+
+ for (sv = servers; sv; sv = sv->next) {
+
+ printf("\t\\\\%-15s\t\t%s\n",
+ sv->name, sv->comment);
+
+ /* List shares */
+
+ free_name_list(shares);
+ shares = NULL;
+
+ if (level == LEV_SERVER ||
+ !get_shares(sv->name, user_info))
+ continue;
+
+ for (sh = shares; sh; sh = sh->next) {
+ printf("\t\t\\\\%s\\%-15s\t%s\n",
+ sv->name, sh->name, sh->comment);
+ }
+ }
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct user_auth_info local_auth_info;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "broadcast", 'b', POPT_ARG_VAL, &use_bcast, True, "Use broadcast instead of using the master browser" },
+ { "domains", 'D', POPT_ARG_VAL, &level, LEV_WORKGROUP, "List only domains (workgroups) of tree" },
+ { "servers", 'S', POPT_ARG_VAL, &level, LEV_SERVER, "List domains(workgroups) and servers of tree" },
+ POPT_COMMON_SAMBA
+ POPT_COMMON_CREDENTIALS
+ POPT_TABLEEND
+ };
+ poptContext pc;
+
+ /* Initialise samba stuff */
+ load_case_tables();
+
+ setlinebuf(stdout);
+
+ dbf = x_stderr;
+
+ setup_logging(argv[0],True);
+
+ pc = poptGetContext("smbtree", argc, (const char **)argv, long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+ while(poptGetNextOpt(pc) != -1);
+ poptFreeContext(pc);
+
+ lp_load(get_dyn_CONFIGFILE(),True,False,False,True);
+ load_interfaces();
+
+ /* Parse command line args */
+
+ if (get_cmdline_auth_info_use_machine_account() &&
+ !set_cmdline_auth_info_machine_account_creds()) {
+ TALLOC_FREE(frame);
+ return 1;
+ }
+
+ if (!get_cmdline_auth_info_got_pass()) {
+ char *pass = getpass("Password: ");
+ if (pass) {
+ set_cmdline_auth_info_password(pass);
+ }
+ }
+
+ /* Now do our stuff */
+
+ if (!get_cmdline_auth_info_copy(&local_auth_info)) {
+ return 1;
+ }
+
+ if (!print_tree(&local_auth_info)) {
+ TALLOC_FREE(frame);
+ return 1;
+ }
+
+ TALLOC_FREE(frame);
+ return 0;
+}
diff --git a/source3/utils/smbw_sample.c b/source3/utils/smbw_sample.c
new file mode 100644
index 0000000000..eface2fc46
--- /dev/null
+++ b/source3/utils/smbw_sample.c
@@ -0,0 +1,96 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+static void usage(void)
+{
+ printf("
+smbw_sample - a sample program that uses smbw
+
+smbw_sample <options> path
+
+ options:
+ -W workgroup
+ -l logfile
+ -P prefix
+ -d debuglevel
+ -U username%%password
+ -R resolve order
+
+note that path must start with /smb/
+");
+}
+
+int main(int argc, char *argv[])
+{
+ DIR *dir;
+ struct dirent *dent;
+ int opt;
+ char *p;
+ extern char *optarg;
+ extern int optind;
+ char *path;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ lp_load(get_dyn_CONFIGFILE(),1,0,0,1);
+ smbw_setup_shared();
+
+ while ((opt = getopt(argc, argv, "W:U:R:d:P:l:hL:")) != EOF) {
+ switch (opt) {
+ case 'W':
+ smbw_setshared("WORKGROUP", optarg);
+ break;
+ case 'l':
+ smbw_setshared("LOGFILE", optarg);
+ break;
+ case 'P':
+ smbw_setshared("PREFIX", optarg);
+ break;
+ case 'd':
+ smbw_setshared("DEBUG", optarg);
+ break;
+ case 'U':
+ p = strchr_m(optarg,'%');
+ if (p) {
+ *p=0;
+ smbw_setshared("PASSWORD",p+1);
+ }
+ smbw_setshared("USER", optarg);
+ break;
+ case 'R':
+ smbw_setshared("RESOLVE_ORDER",optarg);
+ break;
+ case 'h':
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ usage();
+ exit(1);
+ }
+
+ path = argv[0];
+
+ smbw_init();
+
+ dir = smbw_opendir(path);
+ if (!dir) {
+ printf("failed to open %s\n", path);
+ exit(1);
+ }
+
+ while ((dent = smbw_readdir(dir))) {
+ printf("%s\n", dent->d_name);
+ }
+ smbw_closedir(dir);
+ TALLOC_FREE(frame);
+ return 0;
+}
diff --git a/source3/utils/status.c b/source3/utils/status.c
new file mode 100644
index 0000000000..1a66af949a
--- /dev/null
+++ b/source3/utils/status.c
@@ -0,0 +1,485 @@
+/*
+ Unix SMB/CIFS implementation.
+ status reporting
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ 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
+ */
+
+#include "includes.h"
+
+#define SMB_MAXPIDS 2048
+static uid_t Ucrit_uid = 0; /* added by OH */
+static struct server_id Ucrit_pid[SMB_MAXPIDS]; /* Ugly !!! */ /* added by OH */
+static int Ucrit_MaxPid=0; /* added by OH */
+static unsigned int Ucrit_IsActive = 0; /* added by OH */
+
+static bool verbose, brief;
+static bool shares_only; /* Added by RJS */
+static bool locks_only; /* Added by RJS */
+static bool processes_only;
+static bool show_brl;
+static bool numeric_only;
+
+const char *username = NULL;
+
+extern bool status_profile_dump(bool be_verbose);
+extern bool status_profile_rates(bool be_verbose);
+
+/* added by OH */
+static void Ucrit_addUid(uid_t uid)
+{
+ Ucrit_uid = uid;
+ Ucrit_IsActive = 1;
+}
+
+static unsigned int Ucrit_checkUid(uid_t uid)
+{
+ if ( !Ucrit_IsActive )
+ return 1;
+
+ if ( uid == Ucrit_uid )
+ return 1;
+
+ return 0;
+}
+
+static unsigned int Ucrit_checkPid(struct server_id pid)
+{
+ int i;
+
+ if ( !Ucrit_IsActive )
+ return 1;
+
+ for (i=0;i<Ucrit_MaxPid;i++) {
+ if (cluster_id_equal(&pid, &Ucrit_pid[i]))
+ return 1;
+ }
+
+ return 0;
+}
+
+static bool Ucrit_addPid( struct server_id pid )
+{
+ if ( !Ucrit_IsActive )
+ return True;
+
+ if ( Ucrit_MaxPid >= SMB_MAXPIDS ) {
+ d_printf("ERROR: More than %d pids for user %s!\n",
+ SMB_MAXPIDS, uidtoname(Ucrit_uid));
+
+ return False;
+ }
+
+ Ucrit_pid[Ucrit_MaxPid++] = pid;
+
+ return True;
+}
+
+static void print_share_mode(const struct share_mode_entry *e,
+ const char *sharepath,
+ const char *fname,
+ void *dummy)
+{
+ static int count;
+
+ if (!is_valid_share_mode_entry(e)) {
+ return;
+ }
+
+ if (!process_exists(e->pid)) {
+ return;
+ }
+
+ if (count==0) {
+ d_printf("Locked files:\n");
+ d_printf("Pid Uid DenyMode Access R/W Oplock SharePath Name Time\n");
+ d_printf("--------------------------------------------------------------------------------------------------\n");
+ }
+ count++;
+
+ if (Ucrit_checkPid(e->pid)) {
+ d_printf("%-11s ",procid_str_static(&e->pid));
+ d_printf("%-9u ", (unsigned int)e->uid);
+ switch (map_share_mode_to_deny_mode(e->share_access,
+ e->private_options)) {
+ case DENY_NONE: d_printf("DENY_NONE "); break;
+ case DENY_ALL: d_printf("DENY_ALL "); break;
+ case DENY_DOS: d_printf("DENY_DOS "); break;
+ case DENY_READ: d_printf("DENY_READ "); break;
+ case DENY_WRITE:printf("DENY_WRITE "); break;
+ case DENY_FCB: d_printf("DENY_FCB "); break;
+ default: {
+ d_printf("unknown-please report ! "
+ "e->share_access = 0x%x, "
+ "e->private_options = 0x%x\n",
+ (unsigned int)e->share_access,
+ (unsigned int)e->private_options );
+ break;
+ }
+ }
+ d_printf("0x%-8x ",(unsigned int)e->access_mask);
+ if ((e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))==
+ (FILE_READ_DATA|FILE_WRITE_DATA)) {
+ d_printf("RDWR ");
+ } else if (e->access_mask & FILE_WRITE_DATA) {
+ d_printf("WRONLY ");
+ } else {
+ d_printf("RDONLY ");
+ }
+
+ if((e->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) ==
+ (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) {
+ d_printf("EXCLUSIVE+BATCH ");
+ } else if (e->op_type & EXCLUSIVE_OPLOCK) {
+ d_printf("EXCLUSIVE ");
+ } else if (e->op_type & BATCH_OPLOCK) {
+ d_printf("BATCH ");
+ } else if (e->op_type & LEVEL_II_OPLOCK) {
+ d_printf("LEVEL_II ");
+ } else {
+ d_printf("NONE ");
+ }
+
+ d_printf(" %s %s %s",sharepath, fname, time_to_asc((time_t)e->time.tv_sec));
+ }
+}
+
+static void print_brl(struct file_id id,
+ struct server_id pid,
+ enum brl_type lock_type,
+ enum brl_flavour lock_flav,
+ br_off start,
+ br_off size,
+ void *private_data)
+{
+ static int count;
+ int i;
+ static const struct {
+ enum brl_type lock_type;
+ const char *desc;
+ } lock_types[] = {
+ { READ_LOCK, "R" },
+ { WRITE_LOCK, "W" },
+ { PENDING_READ_LOCK, "PR" },
+ { PENDING_WRITE_LOCK, "PW" },
+ { UNLOCK_LOCK, "U" }
+ };
+ const char *desc="X";
+ const char *sharepath = "";
+ const char *fname = "";
+ struct share_mode_lock *share_mode;
+
+ if (count==0) {
+ d_printf("Byte range locks:\n");
+ d_printf("Pid dev:inode R/W start size SharePath Name\n");
+ d_printf("--------------------------------------------------------------------------------\n");
+ }
+ count++;
+
+ share_mode = fetch_share_mode_unlocked(NULL, id, "__unspecified__", "__unspecified__");
+ if (share_mode) {
+ sharepath = share_mode->servicepath;
+ fname = share_mode->filename;
+ }
+
+ for (i=0;i<ARRAY_SIZE(lock_types);i++) {
+ if (lock_type == lock_types[i].lock_type) {
+ desc = lock_types[i].desc;
+ }
+ }
+
+ d_printf("%-10s %-15s %-4s %-9.0f %-9.0f %-24s %-24s\n",
+ procid_str_static(&pid), file_id_string_tos(&id),
+ desc,
+ (double)start, (double)size,
+ sharepath, fname);
+
+ TALLOC_FREE(share_mode);
+}
+
+static int traverse_fn1(struct db_record *rec,
+ const struct connections_key *key,
+ const struct connections_data *crec,
+ void *state)
+{
+ if (crec->cnum == -1)
+ return 0;
+
+ if (!process_exists(crec->pid) || !Ucrit_checkUid(crec->uid)) {
+ return 0;
+ }
+
+ d_printf("%-10s %s %-12s %s",
+ crec->servicename,procid_str_static(&crec->pid),
+ crec->machine,
+ time_to_asc(crec->start));
+
+ return 0;
+}
+
+static int traverse_sessionid(struct db_record *db, void *state)
+{
+ struct sessionid sessionid;
+ fstring uid_str, gid_str;
+
+ if (db->value.dsize != sizeof(sessionid))
+ return 0;
+
+ memcpy(&sessionid, db->value.dptr, sizeof(sessionid));
+
+ if (!process_exists(sessionid.pid) || !Ucrit_checkUid(sessionid.uid)) {
+ return 0;
+ }
+
+ Ucrit_addPid( sessionid.pid );
+
+ fstr_sprintf(uid_str, "%d", sessionid.uid);
+ fstr_sprintf(gid_str, "%d", sessionid.gid);
+
+ d_printf("%-7s %-12s %-12s %-12s (%s)\n",
+ procid_str_static(&sessionid.pid),
+ numeric_only ? uid_str : uidtoname(sessionid.uid),
+ numeric_only ? gid_str : gidtoname(sessionid.gid),
+ sessionid.remote_machine, sessionid.hostname);
+
+ return 0;
+}
+
+
+
+
+ int main(int argc, char *argv[])
+{
+ int c;
+ int profile_only = 0;
+ bool show_processes, show_locks, show_shares;
+ poptContext pc;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"processes", 'p', POPT_ARG_NONE, NULL, 'p', "Show processes only" },
+ {"verbose", 'v', POPT_ARG_NONE, NULL, 'v', "Be verbose" },
+ {"locks", 'L', POPT_ARG_NONE, NULL, 'L', "Show locks only" },
+ {"shares", 'S', POPT_ARG_NONE, NULL, 'S', "Show shares only" },
+ {"user", 'u', POPT_ARG_STRING, &username, 'u', "Switch to user" },
+ {"brief", 'b', POPT_ARG_NONE, NULL, 'b', "Be brief" },
+ {"profile", 'P', POPT_ARG_NONE, NULL, 'P', "Do profiling" },
+ {"profile-rates", 'R', POPT_ARG_NONE, NULL, 'R', "Show call rates" },
+ {"byterange", 'B', POPT_ARG_NONE, NULL, 'B', "Include byte range locks"},
+ {"numeric", 'n', POPT_ARG_NONE, NULL, 'n', "Numeric uid/gid"},
+ POPT_COMMON_SAMBA
+ POPT_TABLEEND
+ };
+ TALLOC_CTX *frame = talloc_stackframe();
+ int ret = 0;
+ struct messaging_context *msg_ctx;
+
+ sec_init();
+ load_case_tables();
+
+ setup_logging(argv[0],True);
+
+ dbf = x_stderr;
+
+ if (getuid() != geteuid()) {
+ d_printf("smbstatus should not be run setuid\n");
+ ret = 1;
+ goto done;
+ }
+
+ pc = poptGetContext(NULL, argc, (const char **) argv, long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+
+ while ((c = poptGetNextOpt(pc)) != -1) {
+ switch (c) {
+ case 'p':
+ processes_only = true;
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 'L':
+ locks_only = true;
+ break;
+ case 'S':
+ shares_only = true;
+ break;
+ case 'b':
+ brief = true;
+ break;
+ case 'u':
+ Ucrit_addUid(nametouid(poptGetOptArg(pc)));
+ break;
+ case 'P':
+ case 'R':
+ profile_only = c;
+ break;
+ case 'B':
+ show_brl = true;
+ break;
+ case 'n':
+ numeric_only = true;
+ break;
+ }
+ }
+
+ /* setup the flags based on the possible combincations */
+
+ show_processes = !(shares_only || locks_only || profile_only) || processes_only;
+ show_locks = !(shares_only || processes_only || profile_only) || locks_only;
+ show_shares = !(processes_only || locks_only || profile_only) || shares_only;
+
+ if ( username )
+ Ucrit_addUid( nametouid(username) );
+
+ if (verbose) {
+ d_printf("using configfile = %s\n", get_dyn_CONFIGFILE());
+ }
+
+ if (!lp_load_initial_only(get_dyn_CONFIGFILE())) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n",
+ get_dyn_CONFIGFILE());
+ ret = -1;
+ goto done;
+ }
+
+ /*
+ * This implicitly initializes the global ctdbd connection, usable by
+ * the db_open() calls further down.
+ */
+
+ msg_ctx = messaging_init(NULL, procid_self(),
+ event_context_init(NULL));
+
+ if (msg_ctx == NULL) {
+ fprintf(stderr, "messaging_init failed\n");
+ ret = -1;
+ goto done;
+ }
+
+ if (!lp_load(get_dyn_CONFIGFILE(),False,False,False,True)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n",
+ get_dyn_CONFIGFILE());
+ ret = -1;
+ goto done;
+ }
+
+ switch (profile_only) {
+ case 'P':
+ /* Dump profile data */
+ return status_profile_dump(verbose);
+ case 'R':
+ /* Continuously display rate-converted data */
+ return status_profile_rates(verbose);
+ default:
+ break;
+ }
+
+ if ( show_processes ) {
+ struct db_context *db;
+ db = db_open(NULL, lock_path("sessionid.tdb"), 0,
+ TDB_CLEAR_IF_FIRST, O_RDONLY, 0644);
+ if (!db) {
+ d_printf("sessionid.tdb not initialised\n");
+ } else {
+ d_printf("\nSamba version %s\n",SAMBA_VERSION_STRING);
+ d_printf("PID Username Group Machine \n");
+ d_printf("-------------------------------------------------------------------\n");
+
+ db->traverse_read(db, traverse_sessionid, NULL);
+ TALLOC_FREE(db);
+ }
+
+ if (processes_only) {
+ goto done;
+ }
+ }
+
+ if ( show_shares ) {
+ if (verbose) {
+ d_printf("Opened %s\n", lock_path("connections.tdb"));
+ }
+
+ if (brief) {
+ goto done;
+ }
+
+ d_printf("\nService pid machine Connected at\n");
+ d_printf("-------------------------------------------------------\n");
+
+ connections_forall(traverse_fn1, NULL);
+
+ d_printf("\n");
+
+ if ( shares_only ) {
+ goto done;
+ }
+ }
+
+ if ( show_locks ) {
+ int result;
+ struct db_context *db;
+ db = db_open(NULL, lock_path("locking.tdb"), 0,
+ TDB_CLEAR_IF_FIRST, O_RDONLY, 0);
+
+ if (!db) {
+ d_printf("%s not initialised\n",
+ lock_path("locking.tdb"));
+ d_printf("This is normal if an SMB client has never "
+ "connected to your server.\n");
+ exit(0);
+ } else {
+ TALLOC_FREE(db);
+ }
+
+ if (!locking_init_readonly()) {
+ d_printf("Can't initialise locking module - exiting\n");
+ ret = 1;
+ goto done;
+ }
+
+ result = share_mode_forall(print_share_mode, NULL);
+
+ if (result == 0) {
+ d_printf("No locked files\n");
+ } else if (result == -1) {
+ d_printf("locked file list truncated\n");
+ }
+
+ d_printf("\n");
+
+ if (show_brl) {
+ brl_forall(print_brl, NULL);
+ }
+
+ locking_end();
+ }
+
+done:
+ TALLOC_FREE(frame);
+ return ret;
+}
diff --git a/source3/utils/status_profile.c b/source3/utils/status_profile.c
new file mode 100644
index 0000000000..48814fedea
--- /dev/null
+++ b/source3/utils/status_profile.c
@@ -0,0 +1,541 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * status reporting
+ * Copyright (C) Andrew Tridgell 1994-1998
+ * Copyright (C) James Peach 2005-2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+bool status_profile_dump(bool be_verbose);
+bool status_profile_rates(bool be_verbose);
+
+#ifdef WITH_PROFILE
+static void profile_separator(const char * title)
+{
+ char line[79 + 1];
+ char * end;
+
+ snprintf(line, sizeof(line), "**** %s ", title);
+
+ for (end = line + strlen(line); end < &line[sizeof(line) -1]; ++end) {
+ *end = '*';
+ }
+
+ line[sizeof(line) - 1] = '\0';
+ d_printf("%s\n", line);
+}
+#endif
+
+/*******************************************************************
+ dump the elements of the profile structure
+ ******************************************************************/
+bool status_profile_dump(bool verbose)
+{
+#ifdef WITH_PROFILE
+ if (!profile_setup(NULL, True)) {
+ fprintf(stderr,"Failed to initialise profile memory\n");
+ return False;
+ }
+
+ d_printf("smb_count: %u\n", profile_p->smb_count);
+ d_printf("uid_changes: %u\n", profile_p->uid_changes);
+
+ profile_separator("System Calls");
+ d_printf("opendir_count: %u\n", profile_p->syscall_opendir_count);
+ d_printf("opendir_time: %u\n", profile_p->syscall_opendir_time);
+ d_printf("readdir_count: %u\n", profile_p->syscall_readdir_count);
+ d_printf("readdir_time: %u\n", profile_p->syscall_readdir_time);
+ d_printf("mkdir_count: %u\n", profile_p->syscall_mkdir_count);
+ d_printf("mkdir_time: %u\n", profile_p->syscall_mkdir_time);
+ d_printf("rmdir_count: %u\n", profile_p->syscall_rmdir_count);
+ d_printf("rmdir_time: %u\n", profile_p->syscall_rmdir_time);
+ d_printf("closedir_count: %u\n", profile_p->syscall_closedir_count);
+ d_printf("closedir_time: %u\n", profile_p->syscall_closedir_time);
+ d_printf("open_count: %u\n", profile_p->syscall_open_count);
+ d_printf("open_time: %u\n", profile_p->syscall_open_time);
+ d_printf("close_count: %u\n", profile_p->syscall_close_count);
+ d_printf("close_time: %u\n", profile_p->syscall_close_time);
+ d_printf("read_count: %u\n", profile_p->syscall_read_count);
+ d_printf("read_time: %u\n", profile_p->syscall_read_time);
+ d_printf("read_bytes: %u\n", profile_p->syscall_read_bytes);
+ d_printf("write_count: %u\n", profile_p->syscall_write_count);
+ d_printf("write_time: %u\n", profile_p->syscall_write_time);
+ d_printf("write_bytes: %u\n", profile_p->syscall_write_bytes);
+ d_printf("pread_count: %u\n", profile_p->syscall_pread_count);
+ d_printf("pread_time: %u\n", profile_p->syscall_pread_time);
+ d_printf("pread_bytes: %u\n", profile_p->syscall_pread_bytes);
+ d_printf("pwrite_count: %u\n", profile_p->syscall_pwrite_count);
+ d_printf("pwrite_time: %u\n", profile_p->syscall_pwrite_time);
+ d_printf("pwrite_bytes: %u\n", profile_p->syscall_pwrite_bytes);
+#ifdef WITH_SENDFILE
+ d_printf("sendfile_count: %u\n", profile_p->syscall_sendfile_count);
+ d_printf("sendfile_time: %u\n", profile_p->syscall_sendfile_time);
+ d_printf("sendfile_bytes: %u\n", profile_p->syscall_sendfile_bytes);
+#endif
+ d_printf("lseek_count: %u\n", profile_p->syscall_lseek_count);
+ d_printf("lseek_time: %u\n", profile_p->syscall_lseek_time);
+ d_printf("rename_count: %u\n", profile_p->syscall_rename_count);
+ d_printf("rename_time: %u\n", profile_p->syscall_rename_time);
+ d_printf("fsync_count: %u\n", profile_p->syscall_fsync_count);
+ d_printf("fsync_time: %u\n", profile_p->syscall_fsync_time);
+ d_printf("stat_count: %u\n", profile_p->syscall_stat_count);
+ d_printf("stat_time: %u\n", profile_p->syscall_stat_time);
+ d_printf("fstat_count: %u\n", profile_p->syscall_fstat_count);
+ d_printf("fstat_time: %u\n", profile_p->syscall_fstat_time);
+ d_printf("lstat_count: %u\n", profile_p->syscall_lstat_count);
+ d_printf("lstat_time: %u\n", profile_p->syscall_lstat_time);
+ d_printf("unlink_count: %u\n", profile_p->syscall_unlink_count);
+ d_printf("unlink_time: %u\n", profile_p->syscall_unlink_time);
+ d_printf("chmod_count: %u\n", profile_p->syscall_chmod_count);
+ d_printf("chmod_time: %u\n", profile_p->syscall_chmod_time);
+ d_printf("fchmod_count: %u\n", profile_p->syscall_fchmod_count);
+ d_printf("fchmod_time: %u\n", profile_p->syscall_fchmod_time);
+ d_printf("chown_count: %u\n", profile_p->syscall_chown_count);
+ d_printf("chown_time: %u\n", profile_p->syscall_chown_time);
+ d_printf("fchown_count: %u\n", profile_p->syscall_fchown_count);
+ d_printf("fchown_time: %u\n", profile_p->syscall_fchown_time);
+ d_printf("chdir_count: %u\n", profile_p->syscall_chdir_count);
+ d_printf("chdir_time: %u\n", profile_p->syscall_chdir_time);
+ d_printf("getwd_count: %u\n", profile_p->syscall_getwd_count);
+ d_printf("getwd_time: %u\n", profile_p->syscall_getwd_time);
+ d_printf("ntimes_count: %u\n", profile_p->syscall_ntimes_count);
+ d_printf("ntimes_time: %u\n", profile_p->syscall_ntimes_time);
+ d_printf("ftruncate_count: %u\n", profile_p->syscall_ftruncate_count);
+ d_printf("ftruncate_time: %u\n", profile_p->syscall_ftruncate_time);
+ d_printf("fcntl_lock_count: %u\n", profile_p->syscall_fcntl_lock_count);
+ d_printf("fcntl_lock_time: %u\n", profile_p->syscall_fcntl_lock_time);
+ d_printf("readlink_count: %u\n", profile_p->syscall_readlink_count);
+ d_printf("readlink_time: %u\n", profile_p->syscall_readlink_time);
+ d_printf("symlink_count: %u\n", profile_p->syscall_symlink_count);
+ d_printf("symlink_time: %u\n", profile_p->syscall_symlink_time);
+
+ profile_separator("Stat Cache");
+ d_printf("lookups: %u\n", profile_p->statcache_lookups);
+ d_printf("misses: %u\n", profile_p->statcache_misses);
+ d_printf("hits: %u\n", profile_p->statcache_hits);
+
+ profile_separator("Write Cache");
+ d_printf("read_hits: %u\n", profile_p->writecache_read_hits);
+ d_printf("abutted_writes: %u\n", profile_p->writecache_abutted_writes);
+ d_printf("total_writes: %u\n", profile_p->writecache_total_writes);
+ d_printf("non_oplock_writes: %u\n", profile_p->writecache_non_oplock_writes);
+ d_printf("direct_writes: %u\n", profile_p->writecache_direct_writes);
+ d_printf("init_writes: %u\n", profile_p->writecache_init_writes);
+ d_printf("flushed_writes[SEEK]: %u\n", profile_p->writecache_flushed_writes[SEEK_FLUSH]);
+ d_printf("flushed_writes[READ]: %u\n", profile_p->writecache_flushed_writes[READ_FLUSH]);
+ d_printf("flushed_writes[WRITE]: %u\n", profile_p->writecache_flushed_writes[WRITE_FLUSH]);
+ d_printf("flushed_writes[READRAW]: %u\n", profile_p->writecache_flushed_writes[READRAW_FLUSH]);
+ d_printf("flushed_writes[OPLOCK_RELEASE]: %u\n", profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH]);
+ d_printf("flushed_writes[CLOSE]: %u\n", profile_p->writecache_flushed_writes[CLOSE_FLUSH]);
+ d_printf("flushed_writes[SYNC]: %u\n", profile_p->writecache_flushed_writes[SYNC_FLUSH]);
+ d_printf("flushed_writes[SIZECHANGE]: %u\n", profile_p->writecache_flushed_writes[SIZECHANGE_FLUSH]);
+ d_printf("num_perfect_writes: %u\n", profile_p->writecache_num_perfect_writes);
+ d_printf("num_write_caches: %u\n", profile_p->writecache_num_write_caches);
+ d_printf("allocated_write_caches: %u\n", profile_p->writecache_allocated_write_caches);
+
+ profile_separator("SMB Calls");
+ d_printf("mkdir_count: %u\n", profile_p->SMBmkdir_count);
+ d_printf("mkdir_time: %u\n", profile_p->SMBmkdir_time);
+ d_printf("rmdir_count: %u\n", profile_p->SMBrmdir_count);
+ d_printf("rmdir_time: %u\n", profile_p->SMBrmdir_time);
+ d_printf("open_count: %u\n", profile_p->SMBopen_count);
+ d_printf("open_time: %u\n", profile_p->SMBopen_time);
+ d_printf("create_count: %u\n", profile_p->SMBcreate_count);
+ d_printf("create_time: %u\n", profile_p->SMBcreate_time);
+ d_printf("close_count: %u\n", profile_p->SMBclose_count);
+ d_printf("close_time: %u\n", profile_p->SMBclose_time);
+ d_printf("flush_count: %u\n", profile_p->SMBflush_count);
+ d_printf("flush_time: %u\n", profile_p->SMBflush_time);
+ d_printf("unlink_count: %u\n", profile_p->SMBunlink_count);
+ d_printf("unlink_time: %u\n", profile_p->SMBunlink_time);
+ d_printf("mv_count: %u\n", profile_p->SMBmv_count);
+ d_printf("mv_time: %u\n", profile_p->SMBmv_time);
+ d_printf("getatr_count: %u\n", profile_p->SMBgetatr_count);
+ d_printf("getatr_time: %u\n", profile_p->SMBgetatr_time);
+ d_printf("setatr_count: %u\n", profile_p->SMBsetatr_count);
+ d_printf("setatr_time: %u\n", profile_p->SMBsetatr_time);
+ d_printf("read_count: %u\n", profile_p->SMBread_count);
+ d_printf("read_time: %u\n", profile_p->SMBread_time);
+ d_printf("write_count: %u\n", profile_p->SMBwrite_count);
+ d_printf("write_time: %u\n", profile_p->SMBwrite_time);
+ d_printf("lock_count: %u\n", profile_p->SMBlock_count);
+ d_printf("lock_time: %u\n", profile_p->SMBlock_time);
+ d_printf("unlock_count: %u\n", profile_p->SMBunlock_count);
+ d_printf("unlock_time: %u\n", profile_p->SMBunlock_time);
+ d_printf("ctemp_count: %u\n", profile_p->SMBctemp_count);
+ d_printf("ctemp_time: %u\n", profile_p->SMBctemp_time);
+ d_printf("mknew_count: %u\n", profile_p->SMBmknew_count);
+ d_printf("mknew_time: %u\n", profile_p->SMBmknew_time);
+ d_printf("checkpath_count: %u\n", profile_p->SMBcheckpath_count);
+ d_printf("checkpath_time: %u\n", profile_p->SMBcheckpath_time);
+ d_printf("exit_count: %u\n", profile_p->SMBexit_count);
+ d_printf("exit_time: %u\n", profile_p->SMBexit_time);
+ d_printf("lseek_count: %u\n", profile_p->SMBlseek_count);
+ d_printf("lseek_time: %u\n", profile_p->SMBlseek_time);
+ d_printf("lockread_count: %u\n", profile_p->SMBlockread_count);
+ d_printf("lockread_time: %u\n", profile_p->SMBlockread_time);
+ d_printf("writeunlock_count: %u\n", profile_p->SMBwriteunlock_count);
+ d_printf("writeunlock_time: %u\n", profile_p->SMBwriteunlock_time);
+ d_printf("readbraw_count: %u\n", profile_p->SMBreadbraw_count);
+ d_printf("readbraw_time: %u\n", profile_p->SMBreadbraw_time);
+ d_printf("readBmpx_count: %u\n", profile_p->SMBreadBmpx_count);
+ d_printf("readBmpx_time: %u\n", profile_p->SMBreadBmpx_time);
+ d_printf("readBs_count: %u\n", profile_p->SMBreadBs_count);
+ d_printf("readBs_time: %u\n", profile_p->SMBreadBs_time);
+ d_printf("writebraw_count: %u\n", profile_p->SMBwritebraw_count);
+ d_printf("writebraw_time: %u\n", profile_p->SMBwritebraw_time);
+ d_printf("writeBmpx_count: %u\n", profile_p->SMBwriteBmpx_count);
+ d_printf("writeBmpx_time: %u\n", profile_p->SMBwriteBmpx_time);
+ d_printf("writeBs_count: %u\n", profile_p->SMBwriteBs_count);
+ d_printf("writeBs_time: %u\n", profile_p->SMBwriteBs_time);
+ d_printf("writec_count: %u\n", profile_p->SMBwritec_count);
+ d_printf("writec_time: %u\n", profile_p->SMBwritec_time);
+ d_printf("setattrE_count: %u\n", profile_p->SMBsetattrE_count);
+ d_printf("setattrE_time: %u\n", profile_p->SMBsetattrE_time);
+ d_printf("getattrE_count: %u\n", profile_p->SMBgetattrE_count);
+ d_printf("getattrE_time: %u\n", profile_p->SMBgetattrE_time);
+ d_printf("lockingX_count: %u\n", profile_p->SMBlockingX_count);
+ d_printf("lockingX_time: %u\n", profile_p->SMBlockingX_time);
+ d_printf("trans_count: %u\n", profile_p->SMBtrans_count);
+ d_printf("trans_time: %u\n", profile_p->SMBtrans_time);
+ d_printf("transs_count: %u\n", profile_p->SMBtranss_count);
+ d_printf("transs_time: %u\n", profile_p->SMBtranss_time);
+ d_printf("ioctl_count: %u\n", profile_p->SMBioctl_count);
+ d_printf("ioctl_time: %u\n", profile_p->SMBioctl_time);
+ d_printf("ioctls_count: %u\n", profile_p->SMBioctls_count);
+ d_printf("ioctls_time: %u\n", profile_p->SMBioctls_time);
+ d_printf("copy_count: %u\n", profile_p->SMBcopy_count);
+ d_printf("copy_time: %u\n", profile_p->SMBcopy_time);
+ d_printf("move_count: %u\n", profile_p->SMBmove_count);
+ d_printf("move_time: %u\n", profile_p->SMBmove_time);
+ d_printf("echo_count: %u\n", profile_p->SMBecho_count);
+ d_printf("echo_time: %u\n", profile_p->SMBecho_time);
+ d_printf("writeclose_count: %u\n", profile_p->SMBwriteclose_count);
+ d_printf("writeclose_time: %u\n", profile_p->SMBwriteclose_time);
+ d_printf("openX_count: %u\n", profile_p->SMBopenX_count);
+ d_printf("openX_time: %u\n", profile_p->SMBopenX_time);
+ d_printf("readX_count: %u\n", profile_p->SMBreadX_count);
+ d_printf("readX_time: %u\n", profile_p->SMBreadX_time);
+ d_printf("writeX_count: %u\n", profile_p->SMBwriteX_count);
+ d_printf("writeX_time: %u\n", profile_p->SMBwriteX_time);
+ d_printf("trans2_count: %u\n", profile_p->SMBtrans2_count);
+ d_printf("trans2_time: %u\n", profile_p->SMBtrans2_time);
+ d_printf("transs2_count: %u\n", profile_p->SMBtranss2_count);
+ d_printf("transs2_time: %u\n", profile_p->SMBtranss2_time);
+ d_printf("findclose_count: %u\n", profile_p->SMBfindclose_count);
+ d_printf("findclose_time: %u\n", profile_p->SMBfindclose_time);
+ d_printf("findnclose_count: %u\n", profile_p->SMBfindnclose_count);
+ d_printf("findnclose_time: %u\n", profile_p->SMBfindnclose_time);
+ d_printf("tcon_count: %u\n", profile_p->SMBtcon_count);
+ d_printf("tcon_time: %u\n", profile_p->SMBtcon_time);
+ d_printf("tdis_count: %u\n", profile_p->SMBtdis_count);
+ d_printf("tdis_time: %u\n", profile_p->SMBtdis_time);
+ d_printf("negprot_count: %u\n", profile_p->SMBnegprot_count);
+ d_printf("negprot_time: %u\n", profile_p->SMBnegprot_time);
+ d_printf("sesssetupX_count: %u\n", profile_p->SMBsesssetupX_count);
+ d_printf("sesssetupX_time: %u\n", profile_p->SMBsesssetupX_time);
+ d_printf("ulogoffX_count: %u\n", profile_p->SMBulogoffX_count);
+ d_printf("ulogoffX_time: %u\n", profile_p->SMBulogoffX_time);
+ d_printf("tconX_count: %u\n", profile_p->SMBtconX_count);
+ d_printf("tconX_time: %u\n", profile_p->SMBtconX_time);
+ d_printf("dskattr_count: %u\n", profile_p->SMBdskattr_count);
+ d_printf("dskattr_time: %u\n", profile_p->SMBdskattr_time);
+ d_printf("search_count: %u\n", profile_p->SMBsearch_count);
+ d_printf("search_time: %u\n", profile_p->SMBsearch_time);
+ d_printf("ffirst_count: %u\n", profile_p->SMBffirst_count);
+ d_printf("ffirst_time: %u\n", profile_p->SMBffirst_time);
+ d_printf("funique_count: %u\n", profile_p->SMBfunique_count);
+ d_printf("funique_time: %u\n", profile_p->SMBfunique_time);
+ d_printf("fclose_count: %u\n", profile_p->SMBfclose_count);
+ d_printf("fclose_time: %u\n", profile_p->SMBfclose_time);
+ d_printf("nttrans_count: %u\n", profile_p->SMBnttrans_count);
+ d_printf("nttrans_time: %u\n", profile_p->SMBnttrans_time);
+ d_printf("nttranss_count: %u\n", profile_p->SMBnttranss_count);
+ d_printf("nttranss_time: %u\n", profile_p->SMBnttranss_time);
+ d_printf("ntcreateX_count: %u\n", profile_p->SMBntcreateX_count);
+ d_printf("ntcreateX_time: %u\n", profile_p->SMBntcreateX_time);
+ d_printf("ntcancel_count: %u\n", profile_p->SMBntcancel_count);
+ d_printf("ntcancel_time: %u\n", profile_p->SMBntcancel_time);
+ d_printf("splopen_count: %u\n", profile_p->SMBsplopen_count);
+ d_printf("splopen_time: %u\n", profile_p->SMBsplopen_time);
+ d_printf("splwr_count: %u\n", profile_p->SMBsplwr_count);
+ d_printf("splwr_time: %u\n", profile_p->SMBsplwr_time);
+ d_printf("splclose_count: %u\n", profile_p->SMBsplclose_count);
+ d_printf("splclose_time: %u\n", profile_p->SMBsplclose_time);
+ d_printf("splretq_count: %u\n", profile_p->SMBsplretq_count);
+ d_printf("splretq_time: %u\n", profile_p->SMBsplretq_time);
+ d_printf("sends_count: %u\n", profile_p->SMBsends_count);
+ d_printf("sends_time: %u\n", profile_p->SMBsends_time);
+ d_printf("sendb_count: %u\n", profile_p->SMBsendb_count);
+ d_printf("sendb_time: %u\n", profile_p->SMBsendb_time);
+ d_printf("fwdname_count: %u\n", profile_p->SMBfwdname_count);
+ d_printf("fwdname_time: %u\n", profile_p->SMBfwdname_time);
+ d_printf("cancelf_count: %u\n", profile_p->SMBcancelf_count);
+ d_printf("cancelf_time: %u\n", profile_p->SMBcancelf_time);
+ d_printf("getmac_count: %u\n", profile_p->SMBgetmac_count);
+ d_printf("getmac_time: %u\n", profile_p->SMBgetmac_time);
+ d_printf("sendstrt_count: %u\n", profile_p->SMBsendstrt_count);
+ d_printf("sendstrt_time: %u\n", profile_p->SMBsendstrt_time);
+ d_printf("sendend_count: %u\n", profile_p->SMBsendend_count);
+ d_printf("sendend_time: %u\n", profile_p->SMBsendend_time);
+ d_printf("sendtxt_count: %u\n", profile_p->SMBsendtxt_count);
+ d_printf("sendtxt_time: %u\n", profile_p->SMBsendtxt_time);
+ d_printf("invalid_count: %u\n", profile_p->SMBinvalid_count);
+ d_printf("invalid_time: %u\n", profile_p->SMBinvalid_time);
+
+ profile_separator("Pathworks Calls");
+ d_printf("setdir_count: %u\n", profile_p->pathworks_setdir_count);
+ d_printf("setdir_time: %u\n", profile_p->pathworks_setdir_time);
+
+ profile_separator("Trans2 Calls");
+ d_printf("open_count: %u\n", profile_p->Trans2_open_count);
+ d_printf("open_time: %u\n", profile_p->Trans2_open_time);
+ d_printf("findfirst_count: %u\n", profile_p->Trans2_findfirst_count);
+ d_printf("findfirst_time: %u\n", profile_p->Trans2_findfirst_time);
+ d_printf("findnext_count: %u\n", profile_p->Trans2_findnext_count);
+ d_printf("findnext_time: %u\n", profile_p->Trans2_findnext_time);
+ d_printf("qfsinfo_count: %u\n", profile_p->Trans2_qfsinfo_count);
+ d_printf("qfsinfo_time: %u\n", profile_p->Trans2_qfsinfo_time);
+ d_printf("setfsinfo_count: %u\n", profile_p->Trans2_setfsinfo_count);
+ d_printf("setfsinfo_time: %u\n", profile_p->Trans2_setfsinfo_time);
+ d_printf("qpathinfo_count: %u\n", profile_p->Trans2_qpathinfo_count);
+ d_printf("qpathinfo_time: %u\n", profile_p->Trans2_qpathinfo_time);
+ d_printf("setpathinfo_count: %u\n", profile_p->Trans2_setpathinfo_count);
+ d_printf("setpathinfo_time: %u\n", profile_p->Trans2_setpathinfo_time);
+ d_printf("qfileinfo_count: %u\n", profile_p->Trans2_qfileinfo_count);
+ d_printf("qfileinfo_time: %u\n", profile_p->Trans2_qfileinfo_time);
+ d_printf("setfileinfo_count: %u\n", profile_p->Trans2_setfileinfo_count);
+ d_printf("setfileinfo_time: %u\n", profile_p->Trans2_setfileinfo_time);
+ d_printf("fsctl_count: %u\n", profile_p->Trans2_fsctl_count);
+ d_printf("fsctl_time: %u\n", profile_p->Trans2_fsctl_time);
+ d_printf("ioctl_count: %u\n", profile_p->Trans2_ioctl_count);
+ d_printf("ioctl_time: %u\n", profile_p->Trans2_ioctl_time);
+ d_printf("findnotifyfirst_count: %u\n", profile_p->Trans2_findnotifyfirst_count);
+ d_printf("findnotifyfirst_time: %u\n", profile_p->Trans2_findnotifyfirst_time);
+ d_printf("findnotifynext_count: %u\n", profile_p->Trans2_findnotifynext_count);
+ d_printf("findnotifynext_time: %u\n", profile_p->Trans2_findnotifynext_time);
+ d_printf("mkdir_count: %u\n", profile_p->Trans2_mkdir_count);
+ d_printf("mkdir_time: %u\n", profile_p->Trans2_mkdir_time);
+ d_printf("session_setup_count: %u\n", profile_p->Trans2_session_setup_count);
+ d_printf("session_setup_time: %u\n", profile_p->Trans2_session_setup_time);
+ d_printf("get_dfs_referral_count: %u\n", profile_p->Trans2_get_dfs_referral_count);
+ d_printf("get_dfs_referral_time: %u\n", profile_p->Trans2_get_dfs_referral_time);
+ d_printf("report_dfs_inconsistancy_count: %u\n", profile_p->Trans2_report_dfs_inconsistancy_count);
+ d_printf("report_dfs_inconsistancy_time: %u\n", profile_p->Trans2_report_dfs_inconsistancy_time);
+
+ profile_separator("NT Transact Calls");
+ d_printf("create_count: %u\n", profile_p->NT_transact_create_count);
+ d_printf("create_time: %u\n", profile_p->NT_transact_create_time);
+ d_printf("ioctl_count: %u\n", profile_p->NT_transact_ioctl_count);
+ d_printf("ioctl_time: %u\n", profile_p->NT_transact_ioctl_time);
+ d_printf("set_security_desc_count: %u\n", profile_p->NT_transact_set_security_desc_count);
+ d_printf("set_security_desc_time: %u\n", profile_p->NT_transact_set_security_desc_time);
+ d_printf("notify_change_count: %u\n", profile_p->NT_transact_notify_change_count);
+ d_printf("notify_change_time: %u\n", profile_p->NT_transact_notify_change_time);
+ d_printf("rename_count: %u\n", profile_p->NT_transact_rename_count);
+ d_printf("rename_time: %u\n", profile_p->NT_transact_rename_time);
+ d_printf("query_security_desc_count: %u\n", profile_p->NT_transact_query_security_desc_count);
+ d_printf("query_security_desc_time: %u\n", profile_p->NT_transact_query_security_desc_time);
+
+ profile_separator("ACL Calls");
+ d_printf("get_nt_acl_count: %u\n", profile_p->get_nt_acl_count);
+ d_printf("get_nt_acl_time: %u\n", profile_p->get_nt_acl_time);
+ d_printf("fget_nt_acl_count: %u\n", profile_p->fget_nt_acl_count);
+ d_printf("fget_nt_acl_time: %u\n", profile_p->fget_nt_acl_time);
+ d_printf("fset_nt_acl_count: %u\n", profile_p->fset_nt_acl_count);
+ d_printf("fset_nt_acl_time: %u\n", profile_p->fset_nt_acl_time);
+ d_printf("chmod_acl_count: %u\n", profile_p->chmod_acl_count);
+ d_printf("chmod_acl_time: %u\n", profile_p->chmod_acl_time);
+ d_printf("fchmod_acl_count: %u\n", profile_p->fchmod_acl_count);
+ d_printf("fchmod_acl_time: %u\n", profile_p->fchmod_acl_time);
+
+ profile_separator("NMBD Calls");
+ d_printf("name_release_count: %u\n", profile_p->name_release_count);
+ d_printf("name_release_time: %u\n", profile_p->name_release_time);
+ d_printf("name_refresh_count: %u\n", profile_p->name_refresh_count);
+ d_printf("name_refresh_time: %u\n", profile_p->name_refresh_time);
+ d_printf("name_registration_count: %u\n", profile_p->name_registration_count);
+ d_printf("name_registration_time: %u\n", profile_p->name_registration_time);
+ d_printf("node_status_count: %u\n", profile_p->node_status_count);
+ d_printf("node_status_time: %u\n", profile_p->node_status_time);
+ d_printf("name_query_count: %u\n", profile_p->name_query_count);
+ d_printf("name_query_time: %u\n", profile_p->name_query_time);
+ d_printf("host_announce_count: %u\n", profile_p->host_announce_count);
+ d_printf("host_announce_time: %u\n", profile_p->host_announce_time);
+ d_printf("workgroup_announce_count: %u\n", profile_p->workgroup_announce_count);
+ d_printf("workgroup_announce_time: %u\n", profile_p->workgroup_announce_time);
+ d_printf("local_master_announce_count: %u\n", profile_p->local_master_announce_count);
+ d_printf("local_master_announce_time: %u\n", profile_p->local_master_announce_time);
+ d_printf("master_browser_announce_count: %u\n", profile_p->master_browser_announce_count);
+ d_printf("master_browser_announce_time: %u\n", profile_p->master_browser_announce_time);
+ d_printf("lm_host_announce_count: %u\n", profile_p->lm_host_announce_count);
+ d_printf("lm_host_announce_time: %u\n", profile_p->lm_host_announce_time);
+ d_printf("get_backup_list_count: %u\n", profile_p->get_backup_list_count);
+ d_printf("get_backup_list_time: %u\n", profile_p->get_backup_list_time);
+ d_printf("reset_browser_count: %u\n", profile_p->reset_browser_count);
+ d_printf("reset_browser_time: %u\n", profile_p->reset_browser_time);
+ d_printf("announce_request_count: %u\n", profile_p->announce_request_count);
+ d_printf("announce_request_time: %u\n", profile_p->announce_request_time);
+ d_printf("lm_announce_request_count: %u\n", profile_p->lm_announce_request_count);
+ d_printf("lm_announce_request_time: %u\n", profile_p->lm_announce_request_time);
+ d_printf("domain_logon_count: %u\n", profile_p->domain_logon_count);
+ d_printf("domain_logon_time: %u\n", profile_p->domain_logon_time);
+ d_printf("sync_browse_lists_count: %u\n", profile_p->sync_browse_lists_count);
+ d_printf("sync_browse_lists_time: %u\n", profile_p->sync_browse_lists_time);
+ d_printf("run_elections_count: %u\n", profile_p->run_elections_count);
+ d_printf("run_elections_time: %u\n", profile_p->run_elections_time);
+ d_printf("election_count: %u\n", profile_p->election_count);
+ d_printf("election_time: %u\n", profile_p->election_time);
+#else /* WITH_PROFILE */
+ fprintf(stderr, "Profile data unavailable\n");
+#endif /* WITH_PROFILE */
+
+ return True;
+}
+
+#ifdef WITH_PROFILE
+
+/* Convert microseconds to milliseconds. */
+#define usec_to_msec(s) ((s) / 1000)
+/* Convert microseconds to seconds. */
+#define usec_to_sec(s) ((s) / 1000000)
+/* One second in microseconds. */
+#define one_second_usec (1000000)
+
+#define sample_interval_usec one_second_usec
+
+#define percent_time(used, period) ((double)(used) / (double)(period) * 100.0 )
+
+static int print_count_samples(
+ const struct profile_stats * const current,
+ const struct profile_stats * const last,
+ SMB_BIG_UINT delta_usec)
+{
+ int i;
+ int count = 0;
+ unsigned step;
+ SMB_BIG_UINT spent;
+ int delta_sec;
+ const char * name;
+ char buf[40];
+
+ if (delta_usec == 0) {
+ return 0;
+ }
+
+ buf[0] = '\0';
+ delta_sec = usec_to_sec(delta_usec);
+
+ for (i = 0; i < PR_VALUE_MAX; ++i) {
+ step = current->count[i] - last->count[i];
+ spent = current->time[i] - last->time[i];
+
+ if (step) {
+ ++count;
+
+ name = profile_value_name(i);
+
+ if (buf[0] == '\0') {
+ snprintf(buf, sizeof(buf),
+ "%s %d/sec (%.2f%%)",
+ name, step / delta_sec,
+ percent_time(spent, delta_usec));
+ } else {
+ printf("%-40s %s %d/sec (%.2f%%)\n",
+ buf, name, step / delta_sec,
+ percent_time(spent, delta_usec));
+ buf[0] = '\0';
+ }
+ }
+ }
+
+ return count;
+}
+
+static struct profile_stats sample_data[2];
+static SMB_BIG_UINT sample_time[2];
+
+bool status_profile_rates(bool verbose)
+{
+ SMB_BIG_UINT remain_usec;
+ SMB_BIG_UINT next_usec;
+ SMB_BIG_UINT delta_usec;
+
+ int last = 0;
+ int current = 1;
+ int tmp;
+
+ if (verbose) {
+ fprintf(stderr, "Sampling stats at %d sec intervals\n",
+ usec_to_sec(sample_interval_usec));
+ }
+
+ if (!profile_setup(NULL, True)) {
+ fprintf(stderr,"Failed to initialise profile memory\n");
+ return False;
+ }
+
+ memcpy(&sample_data[last], profile_p, sizeof(*profile_p));
+ for (;;) {
+ sample_time[current] = profile_timestamp();
+ next_usec = sample_time[current] + sample_interval_usec;
+
+ /* Take a sample. */
+ memcpy(&sample_data[current], profile_p, sizeof(*profile_p));
+
+ /* Rate convert some values and print results. */
+ delta_usec = sample_time[current] - sample_time[last];
+
+ if (print_count_samples(&sample_data[current],
+ &sample_data[last], delta_usec)) {
+ printf("\n");
+ }
+
+ /* Swap sampling buffers. */
+ tmp = last;
+ last = current;
+ current = tmp;
+
+ /* Delay until next sample time. */
+ remain_usec = next_usec - profile_timestamp();
+ if (remain_usec > sample_interval_usec) {
+ fprintf(stderr, "eek! falling behind sampling rate!\n");
+ } else {
+ if (verbose) {
+ fprintf(stderr,
+ "delaying for %lu msec\n",
+ (unsigned long )usec_to_msec(remain_usec));
+ }
+
+ sys_usleep(remain_usec);
+ }
+
+ }
+
+ return True;
+}
+
+#else /* WITH_PROFILE */
+
+bool status_profile_rates(bool verbose)
+{
+ fprintf(stderr, "Profile data unavailable\n");
+ return False;
+}
+
+#endif /* WITH_PROFILE */
+
diff --git a/source3/utils/testparm.c b/source3/utils/testparm.c
new file mode 100644
index 0000000000..527db2d805
--- /dev/null
+++ b/source3/utils/testparm.c
@@ -0,0 +1,434 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test validity of smb.conf
+ Copyright (C) Karl Auer 1993, 1994-1998
+
+ Extensively modified by Andrew Tridgell, 1995
+ Converted to popt by Jelmer Vernooij (jelmer@nl.linux.org), 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Testbed for loadparm.c/params.c
+ *
+ * This module simply loads a specified configuration file and
+ * if successful, dumps it's contents to stdout. Note that the
+ * operation is performed with DEBUGLEVEL at 3.
+ *
+ * Useful for a quick 'syntax check' of a configuration file.
+ *
+ */
+
+#include "includes.h"
+
+extern bool AllowDebugChange;
+
+/***********************************************
+ Here we do a set of 'hard coded' checks for bad
+ configuration settings.
+************************************************/
+
+static int do_global_checks(void)
+{
+ int ret = 0;
+ SMB_STRUCT_STAT st;
+
+ if (lp_security() >= SEC_DOMAIN && !lp_encrypted_passwords()) {
+ fprintf(stderr, "ERROR: in 'security=domain' mode the 'encrypt passwords' parameter must always be set to 'true'.\n");
+ ret = 1;
+ }
+
+ if (lp_wins_support() && lp_wins_server_list()) {
+ fprintf(stderr, "ERROR: both 'wins support = true' and 'wins server = <server list>' \
+cannot be set in the smb.conf file. nmbd will abort with this setting.\n");
+ ret = 1;
+ }
+
+ if (!directory_exist(lp_lockdir(), &st)) {
+ fprintf(stderr, "ERROR: lock directory %s does not exist\n",
+ lp_lockdir());
+ ret = 1;
+ } else if ((st.st_mode & 0777) != 0755) {
+ fprintf(stderr, "WARNING: lock directory %s should have permissions 0755 for browsing to work\n",
+ lp_lockdir());
+ ret = 1;
+ }
+
+ if (!directory_exist(lp_piddir(), &st)) {
+ fprintf(stderr, "ERROR: pid directory %s does not exist\n",
+ lp_piddir());
+ ret = 1;
+ }
+
+ if (lp_passdb_expand_explicit()) {
+ fprintf(stderr, "WARNING: passdb expand explicit = yes is "
+ "deprecated\n");
+ }
+
+ /*
+ * Password server sanity checks.
+ */
+
+ if((lp_security() == SEC_SERVER || lp_security() >= SEC_DOMAIN) && !lp_passwordserver()) {
+ const char *sec_setting;
+ if(lp_security() == SEC_SERVER)
+ sec_setting = "server";
+ else if(lp_security() == SEC_DOMAIN)
+ sec_setting = "domain";
+ else
+ sec_setting = "";
+
+ fprintf(stderr, "ERROR: The setting 'security=%s' requires the 'password server' parameter be set \
+to a valid password server.\n", sec_setting );
+ ret = 1;
+ }
+
+ /*
+ * Password chat sanity checks.
+ */
+
+ if(lp_security() == SEC_USER && lp_unix_password_sync()) {
+
+ /*
+ * Check that we have a valid lp_passwd_program() if not using pam.
+ */
+
+#ifdef WITH_PAM
+ if (!lp_pam_password_change()) {
+#endif
+
+ if((lp_passwd_program() == NULL) ||
+ (strlen(lp_passwd_program()) == 0))
+ {
+ fprintf( stderr, "ERROR: the 'unix password sync' parameter is set and there is no valid 'passwd program' \
+parameter.\n" );
+ ret = 1;
+ } else {
+ const char *passwd_prog;
+ char *truncated_prog = NULL;
+ const char *p;
+
+ passwd_prog = lp_passwd_program();
+ p = passwd_prog;
+ next_token_talloc(talloc_tos(),
+ &p,
+ &truncated_prog, NULL);
+ if (truncated_prog && access(truncated_prog, F_OK) == -1) {
+ fprintf(stderr, "ERROR: the 'unix password sync' parameter is set and the 'passwd program' (%s) \
+cannot be executed (error was %s).\n", truncated_prog, strerror(errno) );
+ ret = 1;
+ }
+ }
+
+#ifdef WITH_PAM
+ }
+#endif
+
+ if(lp_passwd_chat() == NULL) {
+ fprintf(stderr, "ERROR: the 'unix password sync' parameter is set and there is no valid 'passwd chat' \
+parameter.\n");
+ ret = 1;
+ }
+
+ if ((lp_passwd_program() != NULL) &&
+ (strlen(lp_passwd_program()) > 0))
+ {
+ /* check if there's a %u parameter present */
+ if(strstr_m(lp_passwd_program(), "%u") == NULL) {
+ fprintf(stderr, "ERROR: the 'passwd program' (%s) requires a '%%u' parameter.\n", lp_passwd_program());
+ ret = 1;
+ }
+ }
+
+ /*
+ * Check that we have a valid script and that it hasn't
+ * been written to expect the old password.
+ */
+
+ if(lp_encrypted_passwords()) {
+ if(strstr_m( lp_passwd_chat(), "%o")!=NULL) {
+ fprintf(stderr, "ERROR: the 'passwd chat' script [%s] expects to use the old plaintext password \
+via the %%o substitution. With encrypted passwords this is not possible.\n", lp_passwd_chat() );
+ ret = 1;
+ }
+ }
+ }
+
+ if (strlen(lp_winbind_separator()) != 1) {
+ fprintf(stderr,"ERROR: the 'winbind separator' parameter must be a single character.\n");
+ ret = 1;
+ }
+
+ if (*lp_winbind_separator() == '+') {
+ fprintf(stderr,"'winbind separator = +' might cause problems with group membership.\n");
+ }
+
+ if (lp_algorithmic_rid_base() < BASE_RID) {
+ /* Try to prevent admin foot-shooting, we can't put algorithmic
+ rids below 1000, that's the 'well known RIDs' on NT */
+ fprintf(stderr,"'algorithmic rid base' must be equal to or above %lu\n", BASE_RID);
+ }
+
+ if (lp_algorithmic_rid_base() & 1) {
+ fprintf(stderr,"'algorithmic rid base' must be even.\n");
+ }
+
+#ifndef HAVE_DLOPEN
+ if (lp_preload_modules()) {
+ fprintf(stderr,"WARNING: 'preload modules = ' set while loading plugins not supported.\n");
+ }
+#endif
+
+ if (!lp_passdb_backend()) {
+ fprintf(stderr,"ERROR: passdb backend must have a value or be left out\n");
+ }
+
+ if (lp_os_level() > 255) {
+ fprintf(stderr,"WARNING: Maximum value for 'os level' is 255!\n");
+ }
+
+ return ret;
+}
+
+/**
+ * per-share logic tests
+ */
+static void do_per_share_checks(int s)
+{
+ const char **deny_list = lp_hostsdeny(s);
+ const char **allow_list = lp_hostsallow(s);
+ int i;
+
+ if(deny_list) {
+ for (i=0; deny_list[i]; i++) {
+ char *hasstar = strchr_m(deny_list[i], '*');
+ char *hasquery = strchr_m(deny_list[i], '?');
+ if(hasstar || hasquery) {
+ fprintf(stderr,"Invalid character %c in hosts deny list (%s) for service %s.\n",
+ hasstar ? *hasstar : *hasquery, deny_list[i], lp_servicename(s) );
+ }
+ }
+ }
+
+ if(allow_list) {
+ for (i=0; allow_list[i]; i++) {
+ char *hasstar = strchr_m(allow_list[i], '*');
+ char *hasquery = strchr_m(allow_list[i], '?');
+ if(hasstar || hasquery) {
+ fprintf(stderr,"Invalid character %c in hosts allow list (%s) for service %s.\n",
+ hasstar ? *hasstar : *hasquery, allow_list[i], lp_servicename(s) );
+ }
+ }
+ }
+
+ if(lp_level2_oplocks(s) && !lp_oplocks(s)) {
+ fprintf(stderr,"Invalid combination of parameters for service %s. \
+ Level II oplocks can only be set if oplocks are also set.\n",
+ lp_servicename(s) );
+ }
+
+ if (lp_map_hidden(s) && !(lp_create_mask(s) & S_IXOTH)) {
+ fprintf(stderr,"Invalid combination of parameters for service %s. \
+ Map hidden can only work if create mask includes octal 01 (S_IXOTH).\n",
+ lp_servicename(s) );
+ }
+ if (lp_map_hidden(s) && (lp_force_create_mode(s) & S_IXOTH)) {
+ fprintf(stderr,"Invalid combination of parameters for service %s. \
+ Map hidden can only work if force create mode excludes octal 01 (S_IXOTH).\n",
+ lp_servicename(s) );
+ }
+ if (lp_map_system(s) && !(lp_create_mask(s) & S_IXGRP)) {
+ fprintf(stderr,"Invalid combination of parameters for service %s. \
+ Map system can only work if create mask includes octal 010 (S_IXGRP).\n",
+ lp_servicename(s) );
+ }
+ if (lp_map_system(s) && (lp_force_create_mode(s) & S_IXGRP)) {
+ fprintf(stderr,"Invalid combination of parameters for service %s. \
+ Map system can only work if force create mode excludes octal 010 (S_IXGRP).\n",
+ lp_servicename(s) );
+ }
+#ifdef HAVE_CUPS
+ if (lp_printing(s) == PRINT_CUPS && *(lp_printcommand(s)) != '\0') {
+ fprintf(stderr,"Warning: Service %s defines a print command, but \
+rameter is ignored when using CUPS libraries.\n",
+ lp_servicename(s) );
+ }
+#endif
+}
+
+ int main(int argc, const char *argv[])
+{
+ const char *config_file = get_dyn_CONFIGFILE();
+ int s;
+ static int silent_mode = False;
+ static int show_all_parameters = False;
+ int ret = 0;
+ poptContext pc;
+ static const char *term_code = "";
+ static char *parameter_name = NULL;
+ static const char *section_name = NULL;
+ static char *new_local_machine = NULL;
+ const char *cname;
+ const char *caddr;
+ static int show_defaults;
+ static int skip_logic_checks = 0;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"suppress-prompt", 's', POPT_ARG_VAL, &silent_mode, 1, "Suppress prompt for enter"},
+ {"verbose", 'v', POPT_ARG_NONE, &show_defaults, 1, "Show default options too"},
+ {"server", 'L',POPT_ARG_STRING, &new_local_machine, 0, "Set %%L macro to servername\n"},
+ {"encoding", 't', POPT_ARG_STRING, &term_code, 0, "Print parameters with encoding"},
+ {"skip-logic-checks", 'l', POPT_ARG_NONE, &skip_logic_checks, 1, "Skip the global checks"},
+ {"show-all-parameters", '\0', POPT_ARG_VAL, &show_all_parameters, True, "Show the parameters, type, possible values" },
+ {"parameter-name", '\0', POPT_ARG_STRING, &parameter_name, 0, "Limit testparm to a named parameter" },
+ {"section-name", '\0', POPT_ARG_STRING, &section_name, 0, "Limit testparm to a named section" },
+ POPT_COMMON_VERSION
+ POPT_COMMON_DEBUGLEVEL
+ POPT_TABLEEND
+ };
+
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ load_case_tables();
+ /*
+ * Set the default debug level to 2.
+ * Allow it to be overridden by the command line,
+ * not by smb.conf.
+ */
+ DEBUGLEVEL_CLASS[DBGC_ALL] = 2;
+
+ pc = poptGetContext(NULL, argc, argv, long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+ poptSetOtherOptionHelp(pc, "[OPTION...] <config-file> [host-name] [host-ip]");
+
+ while(poptGetNextOpt(pc) != -1);
+
+ if (show_all_parameters) {
+ show_parameter_list();
+ exit(0);
+ }
+
+ setup_logging(poptGetArg(pc), True);
+
+ if (poptPeekArg(pc))
+ config_file = poptGetArg(pc);
+
+ cname = poptGetArg(pc);
+ caddr = poptGetArg(pc);
+
+ if ( cname && ! caddr ) {
+ printf ( "ERROR: You must specify both a machine name and an IP address.\n" );
+ return(1);
+ }
+
+ if (new_local_machine) {
+ set_local_machine_name(new_local_machine, True);
+ }
+
+ dbf = x_stderr;
+ /* Don't let the debuglevel be changed by smb.conf. */
+ AllowDebugChange = False;
+
+ fprintf(stderr,"Load smb config files from %s\n",config_file);
+
+ if (!lp_load_with_registry_shares(config_file,False,True,False,True)) {
+ fprintf(stderr,"Error loading services.\n");
+ return(1);
+ }
+
+ fprintf(stderr,"Loaded services file OK.\n");
+
+ if (skip_logic_checks == 0) {
+ ret = do_global_checks();
+ }
+
+ for (s=0;s<1000;s++) {
+ if (VALID_SNUM(s))
+ if (strlen(lp_servicename(s)) > 12) {
+ fprintf(stderr, "WARNING: You have some share names that are longer than 12 characters.\n" );
+ fprintf(stderr, "These may not be accessible to some older clients.\n" );
+ fprintf(stderr, "(Eg. Windows9x, WindowsMe, and smbclient prior to Samba 3.0.)\n" );
+ break;
+ }
+ }
+
+ for (s=0;s<1000;s++) {
+ if (VALID_SNUM(s) && (skip_logic_checks == 0)) {
+ do_per_share_checks(s);
+ }
+ }
+
+
+ if (!section_name && !parameter_name) {
+ fprintf(stderr,"Server role: %s\n", server_role_str(lp_server_role()));
+ }
+
+ if (!cname) {
+ if (!silent_mode) {
+ fprintf(stderr,"Press enter to see a dump of your service definitions\n");
+ fflush(stdout);
+ getc(stdin);
+ }
+ if (parameter_name || section_name) {
+ bool isGlobal = False;
+ s = GLOBAL_SECTION_SNUM;
+
+ if (!section_name) {
+ section_name = GLOBAL_NAME;
+ isGlobal = True;
+ } else if ((isGlobal=!strwicmp(section_name, GLOBAL_NAME)) == 0 &&
+ (s=lp_servicenumber(section_name)) == -1) {
+ fprintf(stderr,"Unknown section %s\n",
+ section_name);
+ return(1);
+ }
+ if (parameter_name) {
+ if (!dump_a_parameter( s, parameter_name, stdout, isGlobal)) {
+ fprintf(stderr,"Parameter %s unknown for section %s\n",
+ parameter_name, section_name);
+ return(1);
+ }
+ } else {
+ if (isGlobal == True)
+ lp_dump(stdout, show_defaults, 0);
+ else
+ lp_dump_one(stdout, show_defaults, s);
+ }
+ return(ret);
+ }
+
+ lp_dump(stdout, show_defaults, lp_numservices());
+ }
+
+ if(cname && caddr){
+ /* this is totally ugly, a real `quick' hack */
+ for (s=0;s<1000;s++) {
+ if (VALID_SNUM(s)) {
+ if (allow_access(lp_hostsdeny(-1), lp_hostsallow(-1), cname, caddr)
+ && allow_access(lp_hostsdeny(s), lp_hostsallow(s), cname, caddr)) {
+ fprintf(stderr,"Allow connection from %s (%s) to %s\n",
+ cname,caddr,lp_servicename(s));
+ } else {
+ fprintf(stderr,"Deny connection from %s (%s) to %s\n",
+ cname,caddr,lp_servicename(s));
+ }
+ }
+ }
+ }
+ TALLOC_FREE(frame);
+ return(ret);
+}
+
diff --git a/source3/web/cgi.c b/source3/web/cgi.c
new file mode 100644
index 0000000000..070e80cf91
--- /dev/null
+++ b/source3/web/cgi.c
@@ -0,0 +1,672 @@
+/*
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+#include "web/swat_proto.h"
+
+#define MAX_VARIABLES 10000
+
+/* set the expiry on fixed pages */
+#define EXPIRY_TIME (60*60*24*7)
+
+#ifdef DEBUG_COMMENTS
+extern void print_title(char *fmt, ...);
+#endif
+
+struct cgi_var {
+ char *name;
+ char *value;
+};
+
+static struct cgi_var variables[MAX_VARIABLES];
+static int num_variables;
+static int content_length;
+static int request_post;
+static char *query_string;
+static const char *baseurl;
+static char *pathinfo;
+static char *C_user;
+static bool inetd_server;
+static bool got_request;
+
+static char *grab_line(FILE *f, int *cl)
+{
+ char *ret = NULL;
+ int i = 0;
+ int len = 0;
+
+ while ((*cl)) {
+ int c;
+
+ if (i == len) {
+ char *ret2;
+ if (len == 0) len = 1024;
+ else len *= 2;
+ ret2 = (char *)SMB_REALLOC_KEEP_OLD_ON_ERROR(ret, len);
+ if (!ret2) return ret;
+ ret = ret2;
+ }
+
+ c = fgetc(f);
+ (*cl)--;
+
+ if (c == EOF) {
+ (*cl) = 0;
+ break;
+ }
+
+ if (c == '\r') continue;
+
+ if (strchr_m("\n&", c)) break;
+
+ ret[i++] = c;
+
+ }
+
+ if (ret) {
+ ret[i] = 0;
+ }
+ return ret;
+}
+
+/**
+ URL encoded strings can have a '+', which should be replaced with a space
+
+ (This was in rfc1738_unescape(), but that broke the squid helper)
+**/
+
+static void plus_to_space_unescape(char *buf)
+{
+ char *p=buf;
+
+ while ((p=strchr_m(p,'+')))
+ *p = ' ';
+}
+
+/***************************************************************************
+ load all the variables passed to the CGI program. May have multiple variables
+ with the same name and the same or different values. Takes a file parameter
+ for simulating CGI invocation eg loading saved preferences.
+ ***************************************************************************/
+void cgi_load_variables(void)
+{
+ static char *line;
+ char *p, *s, *tok;
+ int len, i;
+ FILE *f = stdin;
+
+#ifdef DEBUG_COMMENTS
+ char dummy[100]="";
+ print_title(dummy);
+ d_printf("<!== Start dump in cgi_load_variables() %s ==>\n",__FILE__);
+#endif
+
+ if (!content_length) {
+ p = getenv("CONTENT_LENGTH");
+ len = p?atoi(p):0;
+ } else {
+ len = content_length;
+ }
+
+
+ if (len > 0 &&
+ (request_post ||
+ ((s=getenv("REQUEST_METHOD")) &&
+ strequal(s,"POST")))) {
+ while (len && (line=grab_line(f, &len))) {
+ p = strchr_m(line,'=');
+ if (!p) continue;
+
+ *p = 0;
+
+ variables[num_variables].name = SMB_STRDUP(line);
+ variables[num_variables].value = SMB_STRDUP(p+1);
+
+ SAFE_FREE(line);
+
+ if (!variables[num_variables].name ||
+ !variables[num_variables].value)
+ continue;
+
+ plus_to_space_unescape(variables[num_variables].value);
+ rfc1738_unescape(variables[num_variables].value);
+ plus_to_space_unescape(variables[num_variables].name);
+ rfc1738_unescape(variables[num_variables].name);
+
+#ifdef DEBUG_COMMENTS
+ printf("<!== POST var %s has value \"%s\" ==>\n",
+ variables[num_variables].name,
+ variables[num_variables].value);
+#endif
+
+ num_variables++;
+ if (num_variables == MAX_VARIABLES) break;
+ }
+ }
+
+ fclose(stdin);
+ open("/dev/null", O_RDWR);
+
+ if ((s=query_string) || (s=getenv("QUERY_STRING"))) {
+ char *saveptr;
+ for (tok=strtok_r(s, "&;", &saveptr); tok;
+ tok=strtok_r(NULL, "&;", &saveptr)) {
+ p = strchr_m(tok,'=');
+ if (!p) continue;
+
+ *p = 0;
+
+ variables[num_variables].name = SMB_STRDUP(tok);
+ variables[num_variables].value = SMB_STRDUP(p+1);
+
+ if (!variables[num_variables].name ||
+ !variables[num_variables].value)
+ continue;
+
+ plus_to_space_unescape(variables[num_variables].value);
+ rfc1738_unescape(variables[num_variables].value);
+ plus_to_space_unescape(variables[num_variables].name);
+ rfc1738_unescape(variables[num_variables].name);
+
+#ifdef DEBUG_COMMENTS
+ printf("<!== Commandline var %s has value \"%s\" ==>\n",
+ variables[num_variables].name,
+ variables[num_variables].value);
+#endif
+ num_variables++;
+ if (num_variables == MAX_VARIABLES) break;
+ }
+
+ }
+#ifdef DEBUG_COMMENTS
+ printf("<!== End dump in cgi_load_variables() ==>\n");
+#endif
+
+ /* variables from the client are in UTF-8 - convert them
+ to our internal unix charset before use */
+ for (i=0;i<num_variables;i++) {
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *dest = NULL;
+ size_t dest_len;
+
+ convert_string_allocate(frame, CH_UTF8, CH_UNIX,
+ variables[i].name, strlen(variables[i].name),
+ &dest, &dest_len, True);
+ SAFE_FREE(variables[i].name);
+ variables[i].name = SMB_STRDUP(dest ? dest : "");
+
+ dest = NULL;
+ convert_string_allocate(frame, CH_UTF8, CH_UNIX,
+ variables[i].value, strlen(variables[i].value),
+ &dest, &dest_len, True);
+ SAFE_FREE(variables[i].value);
+ variables[i].value = SMB_STRDUP(dest ? dest : "");
+ TALLOC_FREE(frame);
+ }
+}
+
+
+/***************************************************************************
+ 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.
+ ***************************************************************************/
+
+const char *cgi_variable(const char *name)
+{
+ int i;
+
+ for (i=0;i<num_variables;i++)
+ if (strcmp(variables[i].name, name) == 0)
+ return variables[i].value;
+ return NULL;
+}
+
+/***************************************************************************
+ Version of the above that can't return a NULL pointer.
+***************************************************************************/
+
+const char *cgi_variable_nonull(const char *name)
+{
+ const char *var = cgi_variable(name);
+ if (var) {
+ return var;
+ } else {
+ return "";
+ }
+}
+
+/***************************************************************************
+tell a browser about a fatal error in the http processing
+ ***************************************************************************/
+static void cgi_setup_error(const char *err, const char *header, const char *info)
+{
+ if (!got_request) {
+ /* damn browsers don't like getting cut off before they give a request */
+ char line[1024];
+ while (fgets(line, sizeof(line)-1, stdin)) {
+ if (strnequal(line,"GET ", 4) ||
+ strnequal(line,"POST ", 5) ||
+ strnequal(line,"PUT ", 4)) {
+ break;
+ }
+ }
+ }
+
+ d_printf("HTTP/1.0 %s\r\n%sConnection: close\r\nContent-Type: text/html\r\n\r\n<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><H1>%s</H1>%s<p></BODY></HTML>\r\n\r\n", err, header, err, err, info);
+ fclose(stdin);
+ fclose(stdout);
+ exit(0);
+}
+
+
+/***************************************************************************
+tell a browser about a fatal authentication error
+ ***************************************************************************/
+static void cgi_auth_error(void)
+{
+ if (inetd_server) {
+ cgi_setup_error("401 Authorization Required",
+ "WWW-Authenticate: Basic realm=\"SWAT\"\r\n",
+ "You must be authenticated to use this service");
+ } else {
+ printf("Content-Type: text/html\r\n");
+
+ printf("\r\n<HTML><HEAD><TITLE>SWAT</TITLE></HEAD>\n");
+ printf("<BODY><H1>Installation Error</H1>\n");
+ printf("SWAT must be installed via inetd. It cannot be run as a CGI script<p>\n");
+ printf("</BODY></HTML>\r\n");
+ }
+ exit(0);
+}
+
+/***************************************************************************
+authenticate when we are running as a CGI
+ ***************************************************************************/
+static void cgi_web_auth(void)
+{
+ const char *user = getenv("REMOTE_USER");
+ struct passwd *pwd;
+ const char *head = "Content-Type: text/html\r\n\r\n<HTML><BODY><H1>SWAT installation Error</H1>\n";
+ const char *tail = "</BODY></HTML>\r\n";
+
+ if (!user) {
+ printf("%sREMOTE_USER not set. Not authenticated by web server.<br>%s\n",
+ head, tail);
+ exit(0);
+ }
+
+ pwd = getpwnam_alloc(NULL, user);
+ if (!pwd) {
+ printf("%sCannot find user %s<br>%s\n", head, user, tail);
+ exit(0);
+ }
+
+ setuid(0);
+ setuid(pwd->pw_uid);
+ if (geteuid() != pwd->pw_uid || getuid() != pwd->pw_uid) {
+ printf("%sFailed to become user %s - uid=%d/%d<br>%s\n",
+ head, user, (int)geteuid(), (int)getuid(), tail);
+ exit(0);
+ }
+ TALLOC_FREE(pwd);
+}
+
+
+/***************************************************************************
+handle a http authentication line
+ ***************************************************************************/
+static bool cgi_handle_authorization(char *line)
+{
+ char *p;
+ fstring user, user_pass;
+ struct passwd *pass = NULL;
+
+ if (!strnequal(line,"Basic ", 6)) {
+ goto err;
+ }
+ line += 6;
+ while (line[0] == ' ') line++;
+ base64_decode_inplace(line);
+ if (!(p=strchr_m(line,':'))) {
+ /*
+ * Always give the same error so a cracker
+ * cannot tell why we fail.
+ */
+ goto err;
+ }
+ *p = 0;
+
+ convert_string(CH_UTF8, CH_UNIX,
+ line, -1,
+ user, sizeof(user), True);
+
+ convert_string(CH_UTF8, CH_UNIX,
+ p+1, -1,
+ user_pass, sizeof(user_pass), True);
+
+ /*
+ * Try and get the user from the UNIX password file.
+ */
+
+ pass = getpwnam_alloc(NULL, user);
+
+ /*
+ * Validate the password they have given.
+ */
+
+ if NT_STATUS_IS_OK(pass_check(pass, user, user_pass,
+ strlen(user_pass), NULL, False)) {
+
+ if (pass) {
+ /*
+ * Password was ok.
+ */
+
+ if ( initgroups(pass->pw_name, pass->pw_gid) != 0 )
+ goto err;
+
+ become_user_permanently(pass->pw_uid, pass->pw_gid);
+
+ /* Save the users name */
+ C_user = SMB_STRDUP(user);
+ TALLOC_FREE(pass);
+ return True;
+ }
+ }
+
+err:
+ cgi_setup_error("401 Bad Authorization",
+ "WWW-Authenticate: Basic realm=\"SWAT\"\r\n",
+ "username or password incorrect");
+
+ TALLOC_FREE(pass);
+ return False;
+}
+
+/***************************************************************************
+is this root?
+ ***************************************************************************/
+bool am_root(void)
+{
+ if (geteuid() == 0) {
+ return( True);
+ } else {
+ return( False);
+ }
+}
+
+/***************************************************************************
+return a ptr to the users name
+ ***************************************************************************/
+char *cgi_user_name(void)
+{
+ return(C_user);
+}
+
+
+/***************************************************************************
+handle a file download
+ ***************************************************************************/
+static void cgi_download(char *file)
+{
+ SMB_STRUCT_STAT st;
+ char buf[1024];
+ int fd, l, i;
+ char *p;
+ char *lang;
+
+ /* sanitise the filename */
+ for (i=0;file[i];i++) {
+ if (!isalnum((int)file[i]) && !strchr_m("/.-_", file[i])) {
+ cgi_setup_error("404 File Not Found","",
+ "Illegal character in filename");
+ }
+ }
+
+ if (sys_stat(file, &st) != 0)
+ {
+ cgi_setup_error("404 File Not Found","",
+ "The requested file was not found");
+ }
+
+ if (S_ISDIR(st.st_mode))
+ {
+ snprintf(buf, sizeof(buf), "%s/index.html", file);
+ if (!file_exist(buf, &st) || !S_ISREG(st.st_mode))
+ {
+ cgi_setup_error("404 File Not Found","",
+ "The requested file was not found");
+ }
+ }
+ else if (S_ISREG(st.st_mode))
+ {
+ snprintf(buf, sizeof(buf), "%s", file);
+ }
+ else
+ {
+ cgi_setup_error("404 File Not Found","",
+ "The requested file was not found");
+ }
+
+ fd = web_open(buf,O_RDONLY,0);
+ if (fd == -1) {
+ cgi_setup_error("404 File Not Found","",
+ "The requested file was not found");
+ }
+ printf("HTTP/1.0 200 OK\r\n");
+ if ((p=strrchr_m(buf, '.'))) {
+ if (strcmp(p,".gif")==0) {
+ printf("Content-Type: image/gif\r\n");
+ } else if (strcmp(p,".jpg")==0) {
+ printf("Content-Type: image/jpeg\r\n");
+ } else if (strcmp(p,".png")==0) {
+ printf("Content-Type: image/png\r\n");
+ } else if (strcmp(p,".css")==0) {
+ printf("Content-Type: text/css\r\n");
+ } else if (strcmp(p,".txt")==0) {
+ printf("Content-Type: text/plain\r\n");
+ } else {
+ printf("Content-Type: text/html\r\n");
+ }
+ }
+ printf("Expires: %s\r\n", http_timestring(time(NULL)+EXPIRY_TIME));
+
+ lang = lang_tdb_current();
+ if (lang) {
+ printf("Content-Language: %s\r\n", lang);
+ }
+
+ printf("Content-Length: %d\r\n\r\n", (int)st.st_size);
+ while ((l=read(fd,buf,sizeof(buf)))>0) {
+ fwrite(buf, 1, l, stdout);
+ }
+ close(fd);
+ exit(0);
+}
+
+
+
+
+/**
+ * @brief Setup the CGI framework.
+ *
+ * Setup the cgi framework, handling the possibility that this program
+ * is either run as a true CGI program with a gateway to a web server, or
+ * is itself a mini web server.
+ **/
+void cgi_setup(const char *rootdir, int auth_required)
+{
+ bool authenticated = False;
+ char line[1024];
+ char *url=NULL;
+ char *p;
+ char *lang;
+
+ if (chdir(rootdir)) {
+ cgi_setup_error("500 Server Error", "",
+ "chdir failed - the server is not configured correctly");
+ }
+
+ /* Handle the possibility we might be running as non-root */
+ sec_init();
+
+ if ((lang=getenv("HTTP_ACCEPT_LANGUAGE"))) {
+ /* if running as a cgi program */
+ web_set_lang(lang);
+ }
+
+ /* maybe we are running under a web server */
+ if (getenv("CONTENT_LENGTH") || getenv("REQUEST_METHOD")) {
+ if (auth_required) {
+ cgi_web_auth();
+ }
+ return;
+ }
+
+ inetd_server = True;
+
+ if (!check_access(1, lp_hostsallow(-1), lp_hostsdeny(-1))) {
+ cgi_setup_error("403 Forbidden", "",
+ "Samba is configured to deny access from this client\n<br>Check your \"hosts allow\" and \"hosts deny\" options in smb.conf ");
+ }
+
+ /* we are a mini-web server. We need to read the request from stdin
+ and handle authentication etc */
+ while (fgets(line, sizeof(line)-1, stdin)) {
+ if (line[0] == '\r' || line[0] == '\n') break;
+ if (strnequal(line,"GET ", 4)) {
+ got_request = True;
+ url = SMB_STRDUP(&line[4]);
+ } else if (strnequal(line,"POST ", 5)) {
+ got_request = True;
+ request_post = 1;
+ url = SMB_STRDUP(&line[5]);
+ } else if (strnequal(line,"PUT ", 4)) {
+ got_request = True;
+ cgi_setup_error("400 Bad Request", "",
+ "This server does not accept PUT requests");
+ } else if (strnequal(line,"Authorization: ", 15)) {
+ authenticated = cgi_handle_authorization(&line[15]);
+ } else if (strnequal(line,"Content-Length: ", 16)) {
+ content_length = atoi(&line[16]);
+ } else if (strnequal(line,"Accept-Language: ", 17)) {
+ web_set_lang(&line[17]);
+ }
+ /* ignore all other requests! */
+ }
+
+ if (auth_required && !authenticated) {
+ cgi_auth_error();
+ }
+
+ if (!url) {
+ cgi_setup_error("400 Bad Request", "",
+ "You must specify a GET or POST request");
+ }
+
+ /* trim the URL */
+ if ((p = strchr_m(url,' ')) || (p=strchr_m(url,'\t'))) {
+ *p = 0;
+ }
+ while (*url && strchr_m("\r\n",url[strlen(url)-1])) {
+ url[strlen(url)-1] = 0;
+ }
+
+ /* anything following a ? in the URL is part of the query string */
+ if ((p=strchr_m(url,'?'))) {
+ query_string = p+1;
+ *p = 0;
+ }
+
+ string_sub(url, "/swat/", "", 0);
+
+ if (url[0] != '/' && strstr(url,"..")==0) {
+ cgi_download(url);
+ }
+
+ printf("HTTP/1.0 200 OK\r\nConnection: close\r\n");
+ printf("Date: %s\r\n", http_timestring(time(NULL)));
+ baseurl = "";
+ pathinfo = url+1;
+}
+
+
+/***************************************************************************
+return the current pages URL
+ ***************************************************************************/
+const char *cgi_baseurl(void)
+{
+ if (inetd_server) {
+ return baseurl;
+ }
+ return getenv("SCRIPT_NAME");
+}
+
+/***************************************************************************
+return the current pages path info
+ ***************************************************************************/
+const char *cgi_pathinfo(void)
+{
+ char *r;
+ if (inetd_server) {
+ return pathinfo;
+ }
+ r = getenv("PATH_INFO");
+ if (!r) return "";
+ if (*r == '/') r++;
+ return r;
+}
+
+/***************************************************************************
+return the hostname of the client
+ ***************************************************************************/
+const char *cgi_remote_host(void)
+{
+ if (inetd_server) {
+ return get_peer_name(1,False);
+ }
+ return getenv("REMOTE_HOST");
+}
+
+/***************************************************************************
+return the hostname of the client
+ ***************************************************************************/
+const char *cgi_remote_addr(void)
+{
+ if (inetd_server) {
+ char addr[INET6_ADDRSTRLEN];
+ return get_peer_addr(1,addr,sizeof(addr));
+ }
+ return getenv("REMOTE_ADDR");
+}
+
+
+/***************************************************************************
+return True if the request was a POST
+ ***************************************************************************/
+bool cgi_waspost(void)
+{
+ if (inetd_server) {
+ return request_post;
+ }
+ return strequal(getenv("REQUEST_METHOD"), "POST");
+}
diff --git a/source3/web/diagnose.c b/source3/web/diagnose.c
new file mode 100644
index 0000000000..221ce83f82
--- /dev/null
+++ b/source3/web/diagnose.c
@@ -0,0 +1,84 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "web/swat_proto.h"
+
+#ifdef WITH_WINBIND
+
+/* check to see if winbind is running by pinging it */
+
+bool winbindd_running(void)
+{
+ return winbind_ping();
+}
+#endif
+
+/* check to see if nmbd is running on localhost by looking for a __SAMBA__
+ response */
+bool nmbd_running(void)
+{
+ struct in_addr loopback_ip;
+ int fd, count, flags;
+ struct sockaddr_storage *ss_list;
+ struct sockaddr_storage ss;
+
+ loopback_ip.s_addr = htonl(INADDR_LOOPBACK);
+ in_addr_to_sockaddr_storage(&ss, loopback_ip);
+
+ if ((fd = open_socket_in(SOCK_DGRAM, 0, 3,
+ &ss, True)) != -1) {
+ if ((ss_list = name_query(fd, "__SAMBA__", 0,
+ True, True, &ss,
+ &count, &flags, NULL)) != NULL) {
+ SAFE_FREE(ss_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)
+{
+ struct in_addr loopback_ip;
+ NTSTATUS status;
+ struct cli_state *cli;
+ struct sockaddr_storage ss;
+
+ loopback_ip.s_addr = htonl(INADDR_LOOPBACK);
+ in_addr_to_sockaddr_storage(&ss, loopback_ip);
+
+ if ((cli = cli_initialise()) == NULL)
+ return False;
+
+ status = cli_connect(cli, global_myname(), &ss);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_shutdown(cli);
+ return False;
+ }
+
+ cli_shutdown(cli);
+ return True;
+}
diff --git a/source3/web/neg_lang.c b/source3/web/neg_lang.c
new file mode 100644
index 0000000000..82411000cd
--- /dev/null
+++ b/source3/web/neg_lang.c
@@ -0,0 +1,120 @@
+/*
+ Unix SMB/CIFS implementation.
+ SWAT language handling
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Created by Ryo Kawahara <rkawa@lbe.co.jp>
+*/
+
+#include "includes.h"
+#include "web/swat_proto.h"
+
+/*
+ during a file download we first check to see if there is a language
+ specific file available. If there is then use that, otherwise
+ just open the specified file
+*/
+int web_open(const char *fname, int flags, mode_t mode)
+{
+ char *p = NULL;
+ char *lang = lang_tdb_current();
+ int fd;
+ if (lang) {
+ asprintf(&p, "lang/%s/%s", lang, fname);
+ if (p) {
+ fd = sys_open(p, flags, mode);
+ free(p);
+ if (fd != -1) {
+ return fd;
+ }
+ }
+ }
+
+ /* fall through to default name */
+ return sys_open(fname, flags, mode);
+}
+
+
+struct pri_list {
+ float pri;
+ char *string;
+};
+
+static int qsort_cmp_list(const void *x, const void *y) {
+ struct pri_list *a = (struct pri_list *)x;
+ struct pri_list *b = (struct pri_list *)y;
+ if (a->pri > b->pri) return -1;
+ if (a->pri < b->pri) return 1;
+ return 0;
+}
+
+/*
+ choose from a list of languages. The list can be comma or space
+ separated
+ Keep choosing until we get a hit
+ Changed to habdle priority -- Simo
+*/
+
+void web_set_lang(const char *lang_string)
+{
+ char **lang_list, **count;
+ struct pri_list *pl;
+ int lang_num, i;
+
+ /* build the lang list */
+ lang_list = str_list_make(talloc_tos(), lang_string, ", \t\r\n");
+ if (!lang_list) return;
+
+ /* sort the list by priority */
+ lang_num = 0;
+ count = lang_list;
+ while (*count && **count) {
+ count++;
+ lang_num++;
+ }
+ pl = SMB_MALLOC_ARRAY(struct pri_list, lang_num);
+ if (!pl) {
+ return;
+ }
+
+ for (i = 0; i < lang_num; i++) {
+ char *pri_code;
+ if ((pri_code=strstr(lang_list[i], ";q="))) {
+ *pri_code = '\0';
+ pri_code += 3;
+ sscanf(pri_code, "%f", &(pl[i].pri));
+ } else {
+ pl[i].pri = 1;
+ }
+ pl[i].string = SMB_STRDUP(lang_list[i]);
+ }
+ TALLOC_FREE(lang_list);
+
+ qsort(pl, lang_num, sizeof(struct pri_list), &qsort_cmp_list);
+
+ /* it's not an error to not initialise - we just fall back to
+ the default */
+
+ for (i = 0; i < lang_num; i++) {
+ if (lang_tdb_init(pl[i].string)) break;
+ }
+
+ for (i = 0; i < lang_num; i++) {
+ SAFE_FREE(pl[i].string);
+ }
+ SAFE_FREE(pl);
+
+ return;
+}
diff --git a/source3/web/startstop.c b/source3/web/startstop.c
new file mode 100644
index 0000000000..b24410a89f
--- /dev/null
+++ b/source3/web/startstop.c
@@ -0,0 +1,130 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "web/swat_proto.h"
+#include "dynconfig.h"
+
+
+/** Startup smbd from web interface. */
+void start_smbd(void)
+{
+ char *binfile = NULL;
+
+ if (geteuid() != 0) {
+ return;
+ }
+
+ if (fork()) {
+ return;
+ }
+
+ if (asprintf(&binfile, "%s/smbd", get_dyn_SBINDIR()) > 0) {
+ become_daemon(true, false);
+ execl(binfile, binfile, "-D", NULL);
+ }
+ exit(0);
+}
+
+/* startup nmbd */
+void start_nmbd(void)
+{
+ char *binfile = NULL;
+
+ if (geteuid() != 0) {
+ return;
+ }
+
+ if (fork()) {
+ return;
+ }
+
+ if (asprintf(&binfile, "%s/nmbd", get_dyn_SBINDIR()) > 0) {
+ become_daemon(true, false);
+ execl(binfile, binfile, "-D", NULL);
+ }
+ exit(0);
+}
+
+/** Startup winbindd from web interface. */
+void start_winbindd(void)
+{
+ char *binfile = NULL;
+
+ if (geteuid() != 0) {
+ return;
+ }
+
+ if (fork()) {
+ return;
+ }
+
+ if (asprintf(&binfile, "%s/winbindd", get_dyn_SBINDIR()) > 0) {
+ become_daemon(true, false);
+ execl(binfile, binfile, 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);
+}
+#ifdef WITH_WINBIND
+/* stop winbindd */
+void stop_winbindd(void)
+{
+ pid_t pid = pidfile_pid("winbindd");
+
+ if (geteuid() != 0) return;
+
+ if (pid <= 0) return;
+
+ kill(pid, SIGTERM);
+}
+#endif
+/* kill a specified process */
+void kill_pid(struct server_id pid)
+{
+ if (geteuid() != 0) return;
+
+ if (procid_to_pid(&pid) <= 0) return;
+
+ kill(procid_to_pid(&pid), SIGTERM);
+}
diff --git a/source3/web/statuspage.c b/source3/web/statuspage.c
new file mode 100644
index 0000000000..ce24c7cddd
--- /dev/null
+++ b/source3/web/statuspage.c
@@ -0,0 +1,453 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "web/swat_proto.h"
+
+#define _(x) lang_msg_rotate(talloc_tos(),x)
+
+#define PIDMAP struct PidMap
+
+/* how long to wait for start/stops to take effect */
+#define SLEEP_TIME 3
+
+PIDMAP {
+ PIDMAP *next, *prev;
+ struct server_id pid;
+ char *machine;
+};
+
+static PIDMAP *pidmap;
+static int PID_or_Machine; /* 0 = show PID, else show Machine name */
+
+static struct server_id smbd_pid;
+
+/* from 2nd call on, remove old list */
+static void initPid2Machine (void)
+{
+ /* show machine name rather PID on table "Open Files"? */
+ if (PID_or_Machine) {
+ PIDMAP *p;
+
+ for (p = pidmap; p != NULL; ) {
+ DLIST_REMOVE(pidmap, p);
+ SAFE_FREE(p->machine);
+ SAFE_FREE(p);
+ }
+
+ pidmap = NULL;
+ }
+}
+
+/* add new PID <-> Machine name mapping */
+static void addPid2Machine (struct server_id pid, const char *machine)
+{
+ /* show machine name rather PID on table "Open Files"? */
+ if (PID_or_Machine) {
+ PIDMAP *newmap;
+
+ if ((newmap = SMB_MALLOC_P(PIDMAP)) == NULL) {
+ /* XXX need error message for this?
+ if malloc fails, PID is always shown */
+ return;
+ }
+
+ newmap->pid = pid;
+ newmap->machine = SMB_STRDUP(machine);
+
+ DLIST_ADD(pidmap, newmap);
+ }
+}
+
+/* lookup PID <-> Machine name mapping */
+static char *mapPid2Machine (struct server_id pid)
+{
+ static char pidbuf [64];
+ PIDMAP *map;
+
+ /* show machine name rather PID on table "Open Files"? */
+ if (PID_or_Machine) {
+ for (map = pidmap; map != NULL; map = map->next) {
+ if (procid_equal(&pid, &map->pid)) {
+ if (map->machine == NULL) /* no machine name */
+ break; /* show PID */
+
+ return map->machine;
+ }
+ }
+ }
+
+ /* PID not in list or machine name NULL? return pid as string */
+ snprintf (pidbuf, sizeof (pidbuf) - 1, "%s",
+ procid_str_static(&pid));
+ return pidbuf;
+}
+
+static const char *tstring(TALLOC_CTX *ctx, time_t t)
+{
+ char *buf;
+ buf = talloc_strdup(ctx, time_to_asc(t));
+ if (!buf) {
+ return "";
+ }
+ buf = talloc_all_string_sub(ctx,
+ buf,
+ " ",
+ "&nbsp;");
+ if (!buf) {
+ return "";
+ }
+ return buf;
+}
+
+static void print_share_mode(const struct share_mode_entry *e,
+ const char *sharepath,
+ const char *fname,
+ void *dummy)
+{
+ char *utf8_fname;
+ int deny_mode;
+ size_t converted_size;
+
+ if (!is_valid_share_mode_entry(e)) {
+ return;
+ }
+
+ deny_mode = map_share_mode_to_deny_mode(e->share_access,
+ e->private_options);
+
+ printf("<tr><td>%s</td>",_(mapPid2Machine(e->pid)));
+ printf("<td>%u</td>",(unsigned int)e->uid);
+ printf("<td>");
+ switch ((deny_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_FCB: printf("DENY_FCB "); break;
+ case DENY_READ: printf("DENY_READ "); break;
+ case DENY_WRITE:printf("DENY_WRITE "); break;
+ }
+ printf("</td>");
+
+ printf("<td>");
+ if (e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA)) {
+ printf("%s", _("RDWR "));
+ } else if (e->access_mask & FILE_WRITE_DATA) {
+ printf("%s", _("WRONLY "));
+ } else {
+ printf("%s", _("RDONLY "));
+ }
+ 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 if (e->op_type & LEVEL_II_OPLOCK)
+ printf("LEVEL_II ");
+ else
+ printf("NONE ");
+ printf("</td>");
+
+ push_utf8_allocate(&utf8_fname, fname, &converted_size);
+ printf("<td>%s</td><td>%s</td></tr>\n",
+ utf8_fname,tstring(talloc_tos(),e->time.tv_sec));
+ SAFE_FREE(utf8_fname);
+}
+
+
+/* kill off any connections chosen by the user */
+static int traverse_fn1(struct db_record *rec,
+ const struct connections_key *key,
+ const struct connections_data *crec,
+ void *private_data)
+{
+ if (crec->cnum == -1 && process_exists(crec->pid)) {
+ char buf[30];
+ slprintf(buf,sizeof(buf)-1,"kill_%s", procid_str_static(&crec->pid));
+ if (cgi_variable(buf)) {
+ kill_pid(crec->pid);
+ sleep(SLEEP_TIME);
+ }
+ }
+ return 0;
+}
+
+/* traversal fn for showing machine connections */
+static int traverse_fn2(struct db_record *rec,
+ const struct connections_key *key,
+ const struct connections_data *crec,
+ void *private_data)
+{
+ if (crec->cnum == -1 || !process_exists(crec->pid) ||
+ procid_equal(&crec->pid, &smbd_pid))
+ return 0;
+
+ addPid2Machine (crec->pid, crec->machine);
+
+ printf("<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td>\n",
+ procid_str_static(&crec->pid),
+ crec->machine, crec->addr,
+ tstring(talloc_tos(),crec->start));
+ if (geteuid() == 0) {
+ printf("<td><input type=submit value=\"X\" name=\"kill_%s\"></td>\n",
+ procid_str_static(&crec->pid));
+ }
+ printf("</tr>\n");
+
+ return 0;
+}
+
+/* traversal fn for showing share connections */
+static int traverse_fn3(struct db_record *rec,
+ const struct connections_key *key,
+ const struct connections_data *crec,
+ void *private_data)
+{
+ if (crec->cnum == -1 || !process_exists(crec->pid))
+ return 0;
+
+ printf("<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n",
+ crec->servicename, uidtoname(crec->uid),
+ gidtoname(crec->gid),procid_str_static(&crec->pid),
+ crec->machine,
+ tstring(talloc_tos(),crec->start));
+ return 0;
+}
+
+
+/* show the current server status */
+void status_page(void)
+{
+ const char *v;
+ int autorefresh=0;
+ int refresh_interval=30;
+ int nr_running=0;
+ bool waitup = False;
+ TALLOC_CTX *ctx = talloc_stackframe();
+
+ smbd_pid = pid_to_procid(pidfile_pid("smbd"));
+
+ if (cgi_variable("smbd_restart") || cgi_variable("all_restart")) {
+ stop_smbd();
+ start_smbd();
+ waitup=True;
+ }
+
+ if (cgi_variable("smbd_start") || cgi_variable("all_start")) {
+ start_smbd();
+ waitup=True;
+ }
+
+ if (cgi_variable("smbd_stop") || cgi_variable("all_stop")) {
+ stop_smbd();
+ waitup=True;
+ }
+
+ if (cgi_variable("nmbd_restart") || cgi_variable("all_restart")) {
+ stop_nmbd();
+ start_nmbd();
+ waitup=True;
+ }
+ if (cgi_variable("nmbd_start") || cgi_variable("all_start")) {
+ start_nmbd();
+ waitup=True;
+ }
+
+ if (cgi_variable("nmbd_stop")|| cgi_variable("all_stop")) {
+ stop_nmbd();
+ waitup=True;
+ }
+
+#ifdef WITH_WINBIND
+ if (cgi_variable("winbindd_restart") || cgi_variable("all_restart")) {
+ stop_winbindd();
+ start_winbindd();
+ waitup=True;
+ }
+
+ if (cgi_variable("winbindd_start") || cgi_variable("all_start")) {
+ start_winbindd();
+ waitup=True;
+ }
+
+ if (cgi_variable("winbindd_stop") || cgi_variable("all_stop")) {
+ stop_winbindd();
+ waitup=True;
+ }
+#endif
+ /* wait for daemons to start/stop */
+ if (waitup)
+ sleep(SLEEP_TIME);
+
+ if (cgi_variable("autorefresh")) {
+ autorefresh = 1;
+ } else if (cgi_variable("norefresh")) {
+ autorefresh = 0;
+ } else if (cgi_variable("refresh")) {
+ autorefresh = 1;
+ }
+
+ if ((v=cgi_variable("refresh_interval"))) {
+ refresh_interval = atoi(v);
+ }
+
+ if (cgi_variable("show_client_in_col_1")) {
+ PID_or_Machine = 1;
+ }
+
+ if (cgi_variable("show_pid_in_col_1")) {
+ PID_or_Machine = 0;
+ }
+
+ connections_forall(traverse_fn1, NULL);
+
+ initPid2Machine ();
+
+ printf("<H2>%s</H2>\n", _("Server Status"));
+
+ printf("<FORM method=post>\n");
+
+ if (!autorefresh) {
+ printf("<input type=submit value=\"%s\" name=\"autorefresh\">\n", _("Auto Refresh"));
+ printf("<br>%s", _("Refresh Interval: "));
+ printf("<input type=text size=2 name=\"refresh_interval\" value=\"%d\">\n",
+ refresh_interval);
+ } else {
+ printf("<input type=submit value=\"%s\" name=\"norefresh\">\n", _("Stop Refreshing"));
+ printf("<br>%s%d\n", _("Refresh Interval: "), refresh_interval);
+ printf("<input type=hidden name=\"refresh\" value=\"1\">\n");
+ }
+
+ printf("<p>\n");
+
+ printf("<table>\n");
+
+ printf("<tr><td>%s</td><td>%s</td></tr>", _("version:"), SAMBA_VERSION_STRING);
+
+ fflush(stdout);
+ printf("<tr><td>%s</td><td>%s</td>\n", _("smbd:"), smbd_running()?_("running"):_("not running"));
+ if (geteuid() == 0) {
+ if (smbd_running()) {
+ nr_running++;
+ printf("<td><input type=submit name=\"smbd_stop\" value=\"%s\"></td>\n", _("Stop smbd"));
+ } else {
+ printf("<td><input type=submit name=\"smbd_start\" value=\"%s\"></td>\n", _("Start smbd"));
+ }
+ printf("<td><input type=submit name=\"smbd_restart\" value=\"%s\"></td>\n", _("Restart smbd"));
+ }
+ printf("</tr>\n");
+
+ fflush(stdout);
+ printf("<tr><td>%s</td><td>%s</td>\n", _("nmbd:"), nmbd_running()?_("running"):_("not running"));
+ if (geteuid() == 0) {
+ if (nmbd_running()) {
+ nr_running++;
+ printf("<td><input type=submit name=\"nmbd_stop\" value=\"%s\"></td>\n", _("Stop nmbd"));
+ } else {
+ printf("<td><input type=submit name=\"nmbd_start\" value=\"%s\"></td>\n", _("Start nmbd"));
+ }
+ printf("<td><input type=submit name=\"nmbd_restart\" value=\"%s\"></td>\n", _("Restart nmbd"));
+ }
+ printf("</tr>\n");
+
+#ifdef WITH_WINBIND
+ fflush(stdout);
+ printf("<tr><td>%s</td><td>%s</td>\n", _("winbindd:"), winbindd_running()?_("running"):_("not running"));
+ if (geteuid() == 0) {
+ if (winbindd_running()) {
+ nr_running++;
+ printf("<td><input type=submit name=\"winbindd_stop\" value=\"%s\"></td>\n", _("Stop winbindd"));
+ } else {
+ printf("<td><input type=submit name=\"winbindd_start\" value=\"%s\"></td>\n", _("Start winbindd"));
+ }
+ printf("<td><input type=submit name=\"winbindd_restart\" value=\"%s\"></td>\n", _("Restart winbindd"));
+ }
+ printf("</tr>\n");
+#endif
+
+ if (geteuid() == 0) {
+ printf("<tr><td></td><td></td>\n");
+ if (nr_running >= 1) {
+ /* stop, restart all */
+ printf("<td><input type=submit name=\"all_stop\" value=\"%s\"></td>\n", _("Stop All"));
+ printf("<td><input type=submit name=\"all_restart\" value=\"%s\"></td>\n", _("Restart All"));
+ }
+ else if (nr_running == 0) {
+ /* start all */
+ printf("<td><input type=submit name=\"all_start\" value=\"%s\"></td>\n", _("Start All"));
+ }
+ printf("</tr>\n");
+ }
+ printf("</table>\n");
+ fflush(stdout);
+
+ printf("<p><h3>%s</h3>\n", _("Active Connections"));
+ printf("<table border=1>\n");
+ printf("<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th>\n", _("PID"), _("Client"), _("IP address"), _("Date"));
+ if (geteuid() == 0) {
+ printf("<th>%s</th>\n", _("Kill"));
+ }
+ printf("</tr>\n");
+
+ connections_forall(traverse_fn2, NULL);
+
+ printf("</table><p>\n");
+
+ printf("<p><h3>%s</h3>\n", _("Active Shares"));
+ printf("<table border=1>\n");
+ printf("<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n\n",
+ _("Share"), _("User"), _("Group"), _("PID"), _("Client"), _("Date"));
+
+ connections_forall(traverse_fn3, NULL);
+
+ printf("</table><p>\n");
+
+ printf("<h3>%s</h3>\n", _("Open Files"));
+ printf("<table border=1>\n");
+ printf("<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n", _("PID"), _("Sharing"), _("R/W"), _("Oplock"), _("File"), _("Date"));
+
+ locking_init_readonly();
+ share_mode_forall(print_share_mode, NULL);
+ locking_end();
+ printf("</table>\n");
+
+ printf("<br><input type=submit name=\"show_client_in_col_1\" value=\"%s\">\n", _("Show Client in col 1"));
+ printf("<input type=submit name=\"show_pid_in_col_1\" value=\"%s\">\n", _("Show PID in col 1"));
+
+ 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");
+ }
+ TALLOC_FREE(ctx);
+}
diff --git a/source3/web/swat.c b/source3/web/swat.c
new file mode 100644
index 0000000000..1502c5bc2f
--- /dev/null
+++ b/source3/web/swat.c
@@ -0,0 +1,1488 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba Web Administration Tool
+ Version 3.0.0
+ Copyright (C) Andrew Tridgell 1997-2002
+ Copyright (C) John H Terpstra 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @defgroup swat SWAT - Samba Web Administration Tool
+ * @{
+ * @file swat.c
+ *
+ * @brief Samba Web Administration Tool.
+ **/
+
+#include "includes.h"
+#include "web/swat_proto.h"
+
+static int demo_mode = False;
+static int passwd_only = False;
+static bool have_write_access = False;
+static bool have_read_access = False;
+static int iNumNonAutoPrintServices = 0;
+
+/*
+ * Password Management Globals
+ */
+#define SWAT_USER "username"
+#define OLD_PSWD "old_passwd"
+#define NEW_PSWD "new_passwd"
+#define NEW2_PSWD "new2_passwd"
+#define CHG_S_PASSWD_FLAG "chg_s_passwd_flag"
+#define CHG_R_PASSWD_FLAG "chg_r_passwd_flag"
+#define ADD_USER_FLAG "add_user_flag"
+#define DELETE_USER_FLAG "delete_user_flag"
+#define DISABLE_USER_FLAG "disable_user_flag"
+#define ENABLE_USER_FLAG "enable_user_flag"
+#define RHOST "remote_host"
+
+#define _(x) lang_msg_rotate(talloc_tos(),x)
+
+/****************************************************************************
+****************************************************************************/
+static int enum_index(int value, const 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(const char *str)
+{
+ static char newstring[1024];
+ char *p = newstring;
+
+ while (*str) {
+ if (*str == '\\') {*p++ = '\\';*p++ = '\\';}
+ else *p++ = *str;
+ ++str;
+ }
+ *p = '\0';
+ return newstring;
+}
+
+static const char *fix_quotes(TALLOC_CTX *ctx, const char *str)
+{
+ char *newstring = NULL;
+ char *p = NULL;
+ size_t newstring_len;
+ int quote_len = strlen("&quot;");
+
+ /* Count the number of quotes. */
+ newstring_len = 1;
+ p = (char *) str;
+ while (*p) {
+ if ( *p == '\"') {
+ newstring_len += quote_len;
+ } else {
+ newstring_len++;
+ }
+ ++p;
+ }
+ newstring = TALLOC_ARRAY(ctx, char, newstring_len);
+ if (!newstring) {
+ return "";
+ }
+ for (p = newstring; *str; str++) {
+ if ( *str == '\"') {
+ strncpy( p, "&quot;", quote_len);
+ p += quote_len;
+ } else {
+ *p++ = *str;
+ }
+ }
+ *p = '\0';
+ return newstring;
+}
+
+static char *stripspaceupper(const char *str)
+{
+ static char newstring[1024];
+ char *p = newstring;
+
+ while (*str) {
+ if (*str != ' ') *p++ = toupper_ascii(*str);
+ ++str;
+ }
+ *p = '\0';
+ return newstring;
+}
+
+static char *make_parm_name(const 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(const char *fname)
+{
+ int fd;
+ char buf[1024];
+ int ret;
+
+ fd = web_open(fname, O_RDONLY, 0);
+
+ if (fd == -1) {
+ printf(_("ERROR: Can't open %s"), fname);
+ printf("\n");
+ return 0;
+ }
+
+ while ((ret = read(fd, buf, sizeof(buf))) > 0) {
+ write(1, buf, ret);
+ }
+
+ close(fd);
+ return 1;
+}
+
+/****************************************************************************
+ start the page with standard stuff
+****************************************************************************/
+static void print_header(void)
+{
+ if (!cgi_waspost()) {
+ 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");
+ }
+}
+
+/* *******************************************************************
+ show parameter label with translated name in the following form
+ because showing original and translated label in one line looks
+ too long, and showing translated label only is unusable for
+ heavy users.
+ -------------------------------
+ HELP security [combo box][button]
+ SECURITY
+ -------------------------------
+ (capital words are translated by gettext.)
+ if no translation is available, then same form as original is
+ used.
+ "i18n_translated_parm" class is used to change the color of the
+ translated parameter with CSS.
+ **************************************************************** */
+static const char *get_parm_translated(TALLOC_CTX *ctx,
+ const char* pAnchor, const char* pHelp, const char* pLabel)
+{
+ const char *pTranslated = _(pLabel);
+ char *output;
+ if(strcmp(pLabel, pTranslated) != 0) {
+ output = talloc_asprintf(ctx,
+ "<A HREF=\"/swat/help/manpages/smb.conf.5.html#%s\" target=\"docs\"> %s</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %s <br><span class=\"i18n_translated_parm\">%s</span>",
+ pAnchor, pHelp, pLabel, pTranslated);
+ return output;
+ }
+ output = talloc_asprintf(ctx,
+ "<A HREF=\"/swat/help/manpages/smb.conf.5.html#%s\" target=\"docs\"> %s</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %s",
+ pAnchor, pHelp, pLabel);
+ return output;
+}
+/****************************************************************************
+ finish off the page
+****************************************************************************/
+static void print_footer(void)
+{
+ if (!include_html("include/footer.html")) {
+ 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;
+ char *utf8_s1, *utf8_s2;
+ size_t converted_size;
+ TALLOC_CTX *ctx = talloc_stackframe();
+
+ if (parm->p_class == P_LOCAL && snum >= 0) {
+ ptr = lp_local_ptr(snum, ptr);
+ }
+
+ printf("<tr><td>%s</td><td>", get_parm_translated(ctx,
+ stripspaceupper(parm->label), _("Help"), 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=\"%s\" onClick=\"swatform.parm_%s.value=\'%c\'\">",
+ _("Set Default"), make_parm_name(parm->label),(char)(parm->def.cvalue));
+ break;
+
+ case P_LIST:
+ printf("<input type=text size=40 name=\"parm_%s\" value=\"",
+ make_parm_name(parm->label));
+ if ((char ***)ptr && *(char ***)ptr && **(char ***)ptr) {
+ char **list = *(char ***)ptr;
+ for (;*list;list++) {
+ /* enclose in HTML encoded quotes if the string contains a space */
+ if ( strchr_m(*list, ' ') ) {
+ push_utf8_allocate(&utf8_s1, *list, &converted_size);
+ push_utf8_allocate(&utf8_s2, ((*(list+1))?", ":""), &converted_size);
+ printf("&quot;%s&quot;%s", utf8_s1, utf8_s2);
+ } else {
+ push_utf8_allocate(&utf8_s1, *list, &converted_size);
+ push_utf8_allocate(&utf8_s2, ((*(list+1))?", ":""), &converted_size);
+ printf("%s%s", utf8_s1, utf8_s2);
+ }
+ SAFE_FREE(utf8_s1);
+ SAFE_FREE(utf8_s2);
+ }
+ }
+ printf("\">");
+ printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'",
+ _("Set Default"), make_parm_name(parm->label));
+ if (parm->def.lvalue) {
+ char **list = (char **)(parm->def.lvalue);
+ for (; *list; list++) {
+ /* enclose in HTML encoded quotes if the string contains a space */
+ if ( strchr_m(*list, ' ') )
+ printf("&quot;%s&quot;%s", *list, ((*(list+1))?", ":""));
+ else
+ printf("%s%s", *list, ((*(list+1))?", ":""));
+ }
+ }
+ printf("\'\">");
+ break;
+
+ case P_STRING:
+ case P_USTRING:
+ push_utf8_allocate(&utf8_s1, *(char **)ptr, &converted_size);
+ printf("<input type=text size=40 name=\"parm_%s\" value=\"%s\">",
+ make_parm_name(parm->label), fix_quotes(ctx, utf8_s1));
+ SAFE_FREE(utf8_s1);
+ printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%s\'\">",
+ _("Set Default"), make_parm_name(parm->label),fix_backslash((char *)(parm->def.svalue)));
+ break;
+
+ case P_BOOL:
+ 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=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
+ _("Set Default"), 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=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
+ _("Set Default"), 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=\"%s\" onClick=\"swatform.parm_%s.value=\'%d\'\">",
+ _("Set Default"), make_parm_name(parm->label),(int)(parm->def.ivalue));
+ break;
+
+ case P_OCTAL: {
+ char *o;
+ o = octal_string(*(int *)ptr);
+ printf("<input type=text size=8 name=\"parm_%s\" value=%s>",
+ make_parm_name(parm->label), o);
+ TALLOC_FREE(o);
+ o = octal_string((int)(parm->def.ivalue));
+ printf("<input type=button value=\"%s\" "
+ "onClick=\"swatform.parm_%s.value=\'%s\'\">",
+ _("Set Default"), make_parm_name(parm->label), o);
+ TALLOC_FREE(o);
+ break;
+ }
+
+ case P_ENUM:
+ printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
+ for (i=0;parm->enum_list[i].name;i++) {
+ if (i == 0 || parm->enum_list[i].value != parm->enum_list[i-1].value) {
+ printf("<option %s>%s",(*(int *)ptr)==parm->enum_list[i].value?"selected":"",parm->enum_list[i].name);
+ }
+ }
+ printf("</select>");
+ printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
+ _("Set Default"), make_parm_name(parm->label),enum_index((int)(parm->def.ivalue),parm->enum_list));
+ break;
+ case P_SEP:
+ break;
+ }
+ printf("</td></tr>\n");
+ TALLOC_FREE(ctx);
+}
+
+/****************************************************************************
+ display a set of parameters for a service
+****************************************************************************/
+static void show_parameters(int snum, int allparameters, unsigned int parm_filter, int printers)
+{
+ int i = 0;
+ struct parm_struct *parm;
+ const char *heading = NULL;
+ const char *last_heading = NULL;
+
+ while ((parm = lp_next_parameter(snum, &i, allparameters))) {
+ if (snum < 0 && parm->p_class == P_LOCAL && !(parm->flags & FLAG_GLOBAL))
+ continue;
+ if (parm->p_class == P_SEPARATOR) {
+ heading = parm->label;
+ continue;
+ }
+ if (parm->flags & FLAG_HIDE) continue;
+ if (snum >= 0) {
+ if (printers & !(parm->flags & FLAG_PRINT)) continue;
+ if (!printers & !(parm->flags & FLAG_SHARE)) continue;
+ }
+
+ if (!( parm_filter & FLAG_ADVANCED )) {
+ if (!(parm->flags & FLAG_BASIC)) {
+ void *ptr = parm->ptr;
+
+ if (parm->p_class == P_LOCAL && snum >= 0) {
+ ptr = lp_local_ptr(snum, ptr);
+ }
+
+ switch (parm->type) {
+ case P_CHAR:
+ if (*(char *)ptr == (char)(parm->def.cvalue)) continue;
+ break;
+
+ case P_LIST:
+ if (!str_list_compare(*(char ***)ptr, (char **)(parm->def.lvalue))) continue;
+ break;
+
+ case P_STRING:
+ case P_USTRING:
+ if (!strcmp(*(char **)ptr,(char *)(parm->def.svalue))) continue;
+ break;
+
+ case P_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 ((parm_filter & FLAG_WIZARD) && !(parm->flags & FLAG_WIZARD)) continue;
+
+ if ((parm_filter & FLAG_ADVANCED) && !(parm->flags & FLAG_ADVANCED)) 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);
+ }
+}
+
+/****************************************************************************
+ load the smb.conf file into loadparm.
+****************************************************************************/
+static bool load_config(bool save_def)
+{
+ return lp_load(get_dyn_CONFIGFILE(),False,save_def,False,True);
+}
+
+/****************************************************************************
+ write a config file
+****************************************************************************/
+static void write_config(FILE *f, bool show_defaults)
+{
+ TALLOC_CTX *ctx = talloc_stackframe();
+
+ 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", current_timestring(ctx, False));
+
+ lp_dump(f, show_defaults, iNumNonAutoPrintServices);
+
+ TALLOC_FREE(ctx);
+}
+
+/****************************************************************************
+ save and reload the smb.conf config file
+****************************************************************************/
+static int save_reload(int snum)
+{
+ FILE *f;
+ struct stat st;
+
+ f = sys_fopen(get_dyn_CONFIGFILE(),"w");
+ if (!f) {
+ printf(_("failed to open %s for writing"), get_dyn_CONFIGFILE());
+ printf("\n");
+ return 0;
+ }
+
+ /* just in case they have used the buggy xinetd to create the file */
+ if (fstat(fileno(f), &st) == 0 &&
+ (st.st_mode & S_IWOTH)) {
+#if defined HAVE_FCHMOD
+ fchmod(fileno(f), S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
+#else
+ chmod(get_dyn_CONFIGFILE(), S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
+#endif
+ }
+
+ write_config(f, False);
+ if (snum)
+ lp_dump_one(f, False, snum);
+ fclose(f);
+
+ lp_kill_all_services();
+
+ if (!load_config(False)) {
+ printf(_("Can't reload %s"), get_dyn_CONFIGFILE());
+ printf("\n");
+ return 0;
+ }
+ iNumNonAutoPrintServices = lp_numservices();
+ load_printers();
+
+ return 1;
+}
+
+/****************************************************************************
+ commit one parameter
+****************************************************************************/
+static void commit_parameter(int snum, struct parm_struct *parm, const char *v)
+{
+ int i;
+ char *s;
+
+ if (snum < 0 && parm->p_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;
+ char *label;
+ const char *v;
+
+ while ((parm = lp_next_parameter(snum, &i, 1))) {
+ if (asprintf(&label, "parm_%s", make_parm_name(parm->label)) > 0) {
+ if ((v = cgi_variable(label)) != NULL) {
+ if (parm->flags & FLAG_HIDE)
+ continue;
+ commit_parameter(snum, parm, v);
+ }
+ SAFE_FREE(label);
+ }
+ }
+}
+
+/****************************************************************************
+ spit out the html for a link with an image
+****************************************************************************/
+static void image_link(const char *name, const char *hlink, const char *src)
+{
+ printf("<A HREF=\"%s/%s\"><img border=\"0\" src=\"/swat/%s\" alt=\"%s\"></A>\n",
+ cgi_baseurl(), hlink, src, name);
+}
+
+/****************************************************************************
+ display the main navigation controls at the top of each page along
+ with a title
+****************************************************************************/
+static void show_main_buttons(void)
+{
+ char *p;
+
+ if ((p = cgi_user_name()) && strcmp(p, "root")) {
+ printf(_("Logged in as <b>%s</b>"), p);
+ printf("<p>\n");
+ }
+
+ image_link(_("Home"), "", "images/home.gif");
+ if (have_write_access) {
+ image_link(_("Globals"), "globals", "images/globals.gif");
+ image_link(_("Shares"), "shares", "images/shares.gif");
+ image_link(_("Printers"), "printers", "images/printers.gif");
+ image_link(_("Wizard"), "wizard", "images/wizard.gif");
+ }
+ /* root always gets all buttons, otherwise look for -P */
+ if ( have_write_access || (!passwd_only && have_read_access) ) {
+ image_link(_("Status"), "status", "images/status.gif");
+ image_link(_("View Config"), "viewconfig", "images/viewconfig.gif");
+ }
+ image_link(_("Password Management"), "passwd", "images/passwd.gif");
+
+ printf("<HR>\n");
+}
+
+/****************************************************************************
+ * Handle Display/Edit Mode CGI
+ ****************************************************************************/
+static void ViewModeBoxes(int mode)
+{
+ printf("<p>%s:&nbsp;\n", _("Current View Is"));
+ printf("<input type=radio name=\"ViewMode\" value=0 %s>%s\n", ((mode == 0) ? "checked" : ""), _("Basic"));
+ printf("<input type=radio name=\"ViewMode\" value=1 %s>%s\n", ((mode == 1) ? "checked" : ""), _("Advanced"));
+ printf("<br>%s:&nbsp;\n", _("Change View To"));
+ printf("<input type=submit name=\"BasicMode\" value=\"%s\">\n", _("Basic"));
+ printf("<input type=submit name=\"AdvMode\" value=\"%s\">\n", _("Advanced"));
+ printf("</p><br>\n");
+}
+
+/****************************************************************************
+ display a welcome page
+****************************************************************************/
+static void welcome_page(void)
+{
+ if (file_exist("help/welcome.html", NULL)) {
+ include_html("help/welcome.html");
+ } else {
+ include_html("help/welcome-no-samba-doc.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>%s</H2>\n", _("Current Config"));
+ printf("<form method=post>\n");
+
+ if (full_view) {
+ printf("<input type=submit name=\"normal_view\" value=\"%s\">\n", _("Normal View"));
+ } else {
+ printf("<input type=submit name=\"full_view\" value=\"%s\">\n", _("Full View"));
+ }
+
+ printf("<p><pre>");
+ write_config(stdout, full_view);
+ printf("</pre>");
+ printf("</form>\n");
+}
+
+/****************************************************************************
+ second screen of the wizard ... Fetch Configuration Parameters
+****************************************************************************/
+static void wizard_params_page(void)
+{
+ unsigned int parm_filter = FLAG_WIZARD;
+
+ /* Here we first set and commit all the parameters that were selected
+ in the previous screen. */
+
+ printf("<H2>%s</H2>\n", _("Wizard Parameter Edit Page"));
+
+ if (cgi_variable("Commit")) {
+ commit_parameters(GLOBAL_SECTION_SNUM);
+ save_reload(0);
+ }
+
+ printf("<form name=\"swatform\" method=post action=wizard_params>\n");
+
+ if (have_write_access) {
+ printf("<input type=submit name=\"Commit\" value=\"Commit Changes\">\n");
+ }
+
+ printf("<input type=reset name=\"Reset Values\" value=\"Reset\">\n");
+ printf("<p>\n");
+
+ printf("<table>\n");
+ show_parameters(GLOBAL_SECTION_SNUM, 1, parm_filter, 0);
+ printf("</table>\n");
+ printf("</form>\n");
+}
+
+/****************************************************************************
+ Utility to just rewrite the smb.conf file - effectively just cleans it up
+****************************************************************************/
+static void rewritecfg_file(void)
+{
+ commit_parameters(GLOBAL_SECTION_SNUM);
+ save_reload(0);
+ printf("<H2>%s</H2>\n", _("Note: smb.conf file has been read and rewritten"));
+}
+
+/****************************************************************************
+ wizard to create/modify the smb.conf file
+****************************************************************************/
+static void wizard_page(void)
+{
+ /* Set some variables to collect data from smb.conf */
+ int role = 0;
+ int winstype = 0;
+ int have_home = -1;
+ int HomeExpo = 0;
+ int SerType = 0;
+
+ if (cgi_variable("Rewrite")) {
+ (void) rewritecfg_file();
+ return;
+ }
+
+ if (cgi_variable("GetWizardParams")){
+ (void) wizard_params_page();
+ return;
+ }
+
+ if (cgi_variable("Commit")){
+ SerType = atoi(cgi_variable_nonull("ServerType"));
+ winstype = atoi(cgi_variable_nonull("WINSType"));
+ have_home = lp_servicenumber(HOMES_NAME);
+ HomeExpo = atoi(cgi_variable_nonull("HomeExpo"));
+
+ /* Plain text passwords are too badly broken - use encrypted passwords only */
+ lp_do_parameter( GLOBAL_SECTION_SNUM, "encrypt passwords", "Yes");
+
+ switch ( SerType ){
+ case 0:
+ /* Stand-alone Server */
+ lp_do_parameter( GLOBAL_SECTION_SNUM, "security", "USER" );
+ lp_do_parameter( GLOBAL_SECTION_SNUM, "domain logons", "No" );
+ break;
+ case 1:
+ /* Domain Member */
+ lp_do_parameter( GLOBAL_SECTION_SNUM, "security", "DOMAIN" );
+ lp_do_parameter( GLOBAL_SECTION_SNUM, "domain logons", "No" );
+ break;
+ case 2:
+ /* Domain Controller */
+ lp_do_parameter( GLOBAL_SECTION_SNUM, "security", "USER" );
+ lp_do_parameter( GLOBAL_SECTION_SNUM, "domain logons", "Yes" );
+ break;
+ }
+ switch ( winstype ) {
+ case 0:
+ lp_do_parameter( GLOBAL_SECTION_SNUM, "wins support", "No" );
+ lp_do_parameter( GLOBAL_SECTION_SNUM, "wins server", "" );
+ break;
+ case 1:
+ lp_do_parameter( GLOBAL_SECTION_SNUM, "wins support", "Yes" );
+ lp_do_parameter( GLOBAL_SECTION_SNUM, "wins server", "" );
+ break;
+ case 2:
+ lp_do_parameter( GLOBAL_SECTION_SNUM, "wins support", "No" );
+ lp_do_parameter( GLOBAL_SECTION_SNUM, "wins server", cgi_variable_nonull("WINSAddr"));
+ break;
+ }
+
+ /* Have to create Homes share? */
+ if ((HomeExpo == 1) && (have_home == -1)) {
+ const char *unix_share = HOMES_NAME;
+
+ load_config(False);
+ lp_copy_service(GLOBAL_SECTION_SNUM, unix_share);
+ have_home = lp_servicenumber(HOMES_NAME);
+ lp_do_parameter( have_home, "read only", "No");
+ lp_do_parameter( have_home, "valid users", "%S");
+ lp_do_parameter( have_home, "browseable", "No");
+ commit_parameters(have_home);
+ save_reload(have_home);
+ }
+
+ /* Need to Delete Homes share? */
+ if ((HomeExpo == 0) && (have_home != -1)) {
+ lp_remove_service(have_home);
+ have_home = -1;
+ }
+
+ commit_parameters(GLOBAL_SECTION_SNUM);
+ save_reload(0);
+ }
+ else
+ {
+ /* Now determine smb.conf WINS settings */
+ if (lp_wins_support())
+ winstype = 1;
+ if (lp_wins_server_list() && strlen(*lp_wins_server_list()))
+ winstype = 2;
+
+ /* Do we have a homes share? */
+ have_home = lp_servicenumber(HOMES_NAME);
+ }
+ if ((winstype == 2) && lp_wins_support())
+ winstype = 3;
+
+ role = lp_server_role();
+
+ /* Here we go ... */
+ printf("<H2>%s</H2>\n", _("Samba Configuration Wizard"));
+ printf("<form method=post action=wizard>\n");
+
+ if (have_write_access) {
+ printf("%s\n", _("The \"Rewrite smb.conf file\" button will clear the smb.conf file of all default values and of comments."));
+ printf("%s", _("The same will happen if you press the commit button."));
+ printf("<br><br>\n");
+ printf("<center>");
+ printf("<input type=submit name=\"Rewrite\" value=\"%s\"> &nbsp;&nbsp;",_("Rewrite smb.conf file"));
+ printf("<input type=submit name=\"Commit\" value=\"%s\"> &nbsp;&nbsp;",_("Commit"));
+ printf("<input type=submit name=\"GetWizardParams\" value=\"%s\">", _("Edit Parameter Values"));
+ printf("</center>\n");
+ }
+
+ printf("<hr>");
+ printf("<center><table border=0>");
+ printf("<tr><td><b>%s:&nbsp;</b></td>\n", _("Server Type"));
+ printf("<td><input type=radio name=\"ServerType\" value=\"0\" %s> %s&nbsp;</td>", ((role == ROLE_STANDALONE) ? "checked" : ""), _("Stand Alone"));
+ printf("<td><input type=radio name=\"ServerType\" value=\"1\" %s> %s&nbsp;</td>", ((role == ROLE_DOMAIN_MEMBER) ? "checked" : ""), _("Domain Member"));
+ printf("<td><input type=radio name=\"ServerType\" value=\"2\" %s> %s&nbsp;</td>", ((role == ROLE_DOMAIN_PDC) ? "checked" : ""), _("Domain Controller"));
+ printf("</tr>\n");
+ if (role == ROLE_DOMAIN_BDC) {
+ printf("<tr><td></td><td colspan=3><font color=\"#ff0000\">%s</font></td></tr>\n", _("Unusual Type in smb.conf - Please Select New Mode"));
+ }
+ printf("<tr><td><b>%s:&nbsp;</b></td>\n", _("Configure WINS As"));
+ printf("<td><input type=radio name=\"WINSType\" value=\"0\" %s> %s&nbsp;</td>", ((winstype == 0) ? "checked" : ""), _("Not Used"));
+ printf("<td><input type=radio name=\"WINSType\" value=\"1\" %s> %s&nbsp;</td>", ((winstype == 1) ? "checked" : ""), _("Server for client use"));
+ printf("<td><input type=radio name=\"WINSType\" value=\"2\" %s> %s&nbsp;</td>", ((winstype == 2) ? "checked" : ""), _("Client of another WINS server"));
+ printf("</tr>\n");
+ printf("<tr><td></td><td></td><td></td><td>%s&nbsp;<input type=text size=\"16\" name=\"WINSAddr\" value=\"", _("Remote WINS Server"));
+
+ /* Print out the list of wins servers */
+ if(lp_wins_server_list()) {
+ int i;
+ const char **wins_servers = lp_wins_server_list();
+ for(i = 0; wins_servers[i]; i++) printf("%s ", wins_servers[i]);
+ }
+
+ printf("\"></td></tr>\n");
+ if (winstype == 3) {
+ printf("<tr><td></td><td colspan=3><font color=\"#ff0000\">%s</font></td></tr>\n", _("Error: WINS Server Mode and WINS Support both set in smb.conf"));
+ printf("<tr><td></td><td colspan=3><font color=\"#ff0000\">%s</font></td></tr>\n", _("Please Select desired WINS mode above."));
+ }
+ printf("<tr><td><b>%s:&nbsp;</b></td>\n", _("Expose Home Directories"));
+ printf("<td><input type=radio name=\"HomeExpo\" value=\"1\" %s> Yes</td>", (have_home == -1) ? "" : "checked ");
+ printf("<td><input type=radio name=\"HomeExpo\" value=\"0\" %s> No</td>", (have_home == -1 ) ? "checked" : "");
+ printf("<td></td></tr>\n");
+
+ /* Enable this when we are ready ....
+ * printf("<tr><td><b>%s:&nbsp;</b></td>\n", _("Is Print Server"));
+ * printf("<td><input type=radio name=\"PtrSvr\" value=\"1\" %s> Yes</td>");
+ * printf("<td><input type=radio name=\"PtrSvr\" value=\"0\" %s> No</td>");
+ * printf("<td></td></tr>\n");
+ */
+
+ printf("</table></center>");
+ printf("<hr>");
+
+ printf("%s\n", _("The above configuration options will set multiple parameters and will generally assist with rapid Samba deployment."));
+ printf("</form>\n");
+}
+
+
+/****************************************************************************
+ display a globals editing page
+****************************************************************************/
+static void globals_page(void)
+{
+ unsigned int parm_filter = FLAG_BASIC;
+ int mode = 0;
+
+ printf("<H2>%s</H2>\n", _("Global Parameters"));
+
+ if (cgi_variable("Commit")) {
+ commit_parameters(GLOBAL_SECTION_SNUM);
+ save_reload(0);
+ }
+
+ if ( cgi_variable("ViewMode") )
+ mode = atoi(cgi_variable_nonull("ViewMode"));
+ if ( cgi_variable("BasicMode"))
+ mode = 0;
+ if ( cgi_variable("AdvMode"))
+ mode = 1;
+
+ printf("<form name=\"swatform\" method=post action=globals>\n");
+
+ ViewModeBoxes( mode );
+ switch ( mode ) {
+ case 0:
+ parm_filter = FLAG_BASIC;
+ break;
+ case 1:
+ parm_filter = FLAG_ADVANCED;
+ break;
+ }
+ printf("<br>\n");
+ if (have_write_access) {
+ printf("<input type=submit name=\"Commit\" value=\"%s\">\n",
+ _("Commit Changes"));
+ }
+
+ printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n",
+ _("Reset Values"));
+
+ printf("<p>\n");
+ printf("<table>\n");
+ show_parameters(GLOBAL_SECTION_SNUM, 1, parm_filter, 0);
+ printf("</table>\n");
+ printf("</form>\n");
+}
+
+/****************************************************************************
+ display a shares editing page. share is in unix codepage,
+****************************************************************************/
+static void shares_page(void)
+{
+ const char *share = cgi_variable("share");
+ char *s;
+ char *utf8_s;
+ int snum = -1;
+ int i;
+ int mode = 0;
+ unsigned int parm_filter = FLAG_BASIC;
+ size_t converted_size;
+
+ if (share)
+ snum = lp_servicenumber(share);
+
+ printf("<H2>%s</H2>\n", _("Share Parameters"));
+
+ if (cgi_variable("Commit") && snum >= 0) {
+ commit_parameters(snum);
+ save_reload(0);
+ snum = lp_servicenumber(share);
+ }
+
+ if (cgi_variable("Delete") && snum >= 0) {
+ lp_remove_service(snum);
+ save_reload(0);
+ share = NULL;
+ snum = -1;
+ }
+
+ if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
+ snum = lp_servicenumber(share);
+ if (snum < 0) {
+ load_config(False);
+ lp_copy_service(GLOBAL_SECTION_SNUM, share);
+ snum = lp_servicenumber(share);
+ save_reload(snum);
+ snum = lp_servicenumber(share);
+ }
+ }
+
+ printf("<FORM name=\"swatform\" method=post>\n");
+
+ printf("<table>\n");
+
+ if ( cgi_variable("ViewMode") )
+ mode = atoi(cgi_variable_nonull("ViewMode"));
+ if ( cgi_variable("BasicMode"))
+ mode = 0;
+ if ( cgi_variable("AdvMode"))
+ mode = 1;
+
+ ViewModeBoxes( mode );
+ switch ( mode ) {
+ case 0:
+ parm_filter = FLAG_BASIC;
+ break;
+ case 1:
+ parm_filter = FLAG_ADVANCED;
+ break;
+ }
+ printf("<br><tr>\n");
+ printf("<td><input type=submit name=selectshare value=\"%s\"></td>\n", _("Choose Share"));
+ 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)) {
+ push_utf8_allocate(&utf8_s, s, &converted_size);
+ printf("<option %s value=\"%s\">%s\n",
+ (share && strcmp(share,s)==0)?"SELECTED":"",
+ utf8_s, utf8_s);
+ SAFE_FREE(utf8_s);
+ }
+ }
+ printf("</select></td>\n");
+ if (have_write_access) {
+ printf("<td><input type=submit name=\"Delete\" value=\"%s\"></td>\n", _("Delete Share"));
+ }
+ printf("</tr>\n");
+ printf("</table>");
+ printf("<table>");
+ if (have_write_access) {
+ printf("<tr>\n");
+ printf("<td><input type=submit name=createshare value=\"%s\"></td>\n", _("Create Share"));
+ printf("<td><input type=text size=30 name=newshare></td></tr>\n");
+ }
+ printf("</table>");
+
+
+ if (snum >= 0) {
+ if (have_write_access) {
+ printf("<input type=submit name=\"Commit\" value=\"%s\">\n", _("Commit Changes"));
+ }
+
+ printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n", _("Reset Values"));
+ printf("<p>\n");
+ }
+
+ if (snum >= 0) {
+ printf("<table>\n");
+ show_parameters(snum, 1, parm_filter, 0);
+ printf("</table>\n");
+ }
+
+ printf("</FORM>\n");
+}
+
+/*************************************************************
+change a password either locally or remotely
+*************************************************************/
+static bool change_password(const char *remote_machine, const char *user_name,
+ const char *old_passwd, const char *new_passwd,
+ int local_flags)
+{
+ NTSTATUS ret;
+ char *err_str = NULL;
+ char *msg_str = NULL;
+
+ if (demo_mode) {
+ printf("%s\n<p>", _("password change in demo mode rejected"));
+ return False;
+ }
+
+ if (remote_machine != NULL) {
+ ret = remote_password_change(remote_machine, user_name,
+ old_passwd, new_passwd, &err_str);
+ if (err_str != NULL)
+ printf("%s\n<p>", err_str);
+ SAFE_FREE(err_str);
+ return NT_STATUS_IS_OK(ret);
+ }
+
+ if(!initialize_password_db(True, NULL)) {
+ printf("%s\n<p>", _("Can't setup password database vectors."));
+ return False;
+ }
+
+ ret = local_password_change(user_name, local_flags, new_passwd,
+ &err_str, &msg_str);
+
+ if(msg_str)
+ printf("%s\n<p>", msg_str);
+ if(err_str)
+ printf("%s\n<p>", err_str);
+
+ SAFE_FREE(msg_str);
+ SAFE_FREE(err_str);
+ return NT_STATUS_IS_OK(ret);
+}
+
+/****************************************************************************
+ do the stuff required to add or change a password
+****************************************************************************/
+static void chg_passwd(void)
+{
+ const char *host;
+ bool rslt;
+ int local_flags = 0;
+
+ /* Make sure users name has been specified */
+ if (strlen(cgi_variable_nonull(SWAT_USER)) == 0) {
+ printf("<p>%s\n", _(" Must specify \"User Name\" "));
+ return;
+ }
+
+ /*
+ * smbpasswd doesn't require anything but the users name to delete, disable or enable the user,
+ * so if that's what we're doing, skip the rest of the checks
+ */
+ if (!cgi_variable(DISABLE_USER_FLAG) && !cgi_variable(ENABLE_USER_FLAG) && !cgi_variable(DELETE_USER_FLAG)) {
+
+ /*
+ * If current user is not root, make sure old password has been specified
+ * If REMOTE change, even root must provide old password
+ */
+ if (((!am_root()) && (strlen( cgi_variable_nonull(OLD_PSWD)) <= 0)) ||
+ ((cgi_variable(CHG_R_PASSWD_FLAG)) && (strlen( cgi_variable_nonull(OLD_PSWD)) <= 0))) {
+ printf("<p>%s\n", _(" Must specify \"Old Password\" "));
+ return;
+ }
+
+ /* If changing a users password on a remote hosts we have to know what host */
+ if ((cgi_variable(CHG_R_PASSWD_FLAG)) && (strlen( cgi_variable_nonull(RHOST)) <= 0)) {
+ printf("<p>%s\n", _(" Must specify \"Remote Machine\" "));
+ return;
+ }
+
+ /* Make sure new passwords have been specified */
+ if ((strlen( cgi_variable_nonull(NEW_PSWD)) <= 0) ||
+ (strlen( cgi_variable_nonull(NEW2_PSWD)) <= 0)) {
+ printf("<p>%s\n", _(" Must specify \"New, and Re-typed Passwords\" "));
+ return;
+ }
+
+ /* Make sure new passwords was typed correctly twice */
+ if (strcmp(cgi_variable_nonull(NEW_PSWD), cgi_variable_nonull(NEW2_PSWD)) != 0) {
+ printf("<p>%s\n", _(" Re-typed password didn't match new password "));
+ return;
+ }
+ }
+
+ if (cgi_variable(CHG_R_PASSWD_FLAG)) {
+ host = cgi_variable(RHOST);
+ } else if (am_root()) {
+ host = NULL;
+ } else {
+ host = "127.0.0.1";
+ }
+
+ /*
+ * Set up the local flags.
+ */
+
+ local_flags |= (cgi_variable(ADD_USER_FLAG) ? LOCAL_ADD_USER : 0);
+ local_flags |= (cgi_variable(ADD_USER_FLAG) ? LOCAL_SET_PASSWORD : 0);
+ local_flags |= (cgi_variable(CHG_S_PASSWD_FLAG) ? LOCAL_SET_PASSWORD : 0);
+ local_flags |= (cgi_variable(DELETE_USER_FLAG) ? LOCAL_DELETE_USER : 0);
+ local_flags |= (cgi_variable(ENABLE_USER_FLAG) ? LOCAL_ENABLE_USER : 0);
+ local_flags |= (cgi_variable(DISABLE_USER_FLAG) ? LOCAL_DISABLE_USER : 0);
+
+
+ rslt = change_password(host,
+ cgi_variable_nonull(SWAT_USER),
+ cgi_variable_nonull(OLD_PSWD), cgi_variable_nonull(NEW_PSWD),
+ local_flags);
+
+ if(cgi_variable(CHG_S_PASSWD_FLAG)) {
+ printf("<p>");
+ if (rslt == True) {
+ printf(_(" The passwd for '%s' has been changed."), cgi_variable_nonull(SWAT_USER));
+ printf("\n");
+ } else {
+ printf(_(" The passwd for '%s' has NOT been changed."), cgi_variable_nonull(SWAT_USER));
+ printf("\n");
+ }
+ }
+
+ return;
+}
+
+/****************************************************************************
+ display a password editing page
+****************************************************************************/
+static void passwd_page(void)
+{
+ const char *new_name = cgi_user_name();
+
+ /*
+ * After the first time through here be nice. If the user
+ * changed the User box text to another users name, remember it.
+ */
+ if (cgi_variable(SWAT_USER)) {
+ new_name = cgi_variable_nonull(SWAT_USER);
+ }
+
+ if (!new_name) new_name = "";
+
+ printf("<H2>%s</H2>\n", _("Server Password Management"));
+
+ printf("<FORM name=\"swatform\" method=post>\n");
+
+ printf("<table>\n");
+
+ /*
+ * Create all the dialog boxes for data collection
+ */
+ printf("<tr><td> %s : </td>\n", _("User Name"));
+ printf("<td><input type=text size=30 name=%s value=%s></td></tr> \n", SWAT_USER, new_name);
+ if (!am_root()) {
+ printf("<tr><td> %s : </td>\n", _("Old Password"));
+ printf("<td><input type=password size=30 name=%s></td></tr> \n",OLD_PSWD);
+ }
+ printf("<tr><td> %s : </td>\n", _("New Password"));
+ printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW_PSWD);
+ printf("<tr><td> %s : </td>\n", _("Re-type New Password"));
+ printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW2_PSWD);
+ printf("</table>\n");
+
+ /*
+ * Create all the control buttons for requesting action
+ */
+ printf("<input type=submit name=%s value=\"%s\">\n",
+ CHG_S_PASSWD_FLAG, _("Change Password"));
+ if (demo_mode || am_root()) {
+ printf("<input type=submit name=%s value=\"%s\">\n",
+ ADD_USER_FLAG, _("Add New User"));
+ printf("<input type=submit name=%s value=\"%s\">\n",
+ DELETE_USER_FLAG, _("Delete User"));
+ printf("<input type=submit name=%s value=\"%s\">\n",
+ DISABLE_USER_FLAG, _("Disable User"));
+ printf("<input type=submit name=%s value=\"%s\">\n",
+ ENABLE_USER_FLAG, _("Enable User"));
+ }
+ printf("<p></FORM>\n");
+
+ /*
+ * Do some work if change, add, disable or enable was
+ * requested. It could be this is the first time through this
+ * code, so there isn't anything to do. */
+ if ((cgi_variable(CHG_S_PASSWD_FLAG)) || (cgi_variable(ADD_USER_FLAG)) || (cgi_variable(DELETE_USER_FLAG)) ||
+ (cgi_variable(DISABLE_USER_FLAG)) || (cgi_variable(ENABLE_USER_FLAG))) {
+ chg_passwd();
+ }
+
+ printf("<H2>%s</H2>\n", _("Client/Server Password Management"));
+
+ printf("<FORM name=\"swatform\" method=post>\n");
+
+ printf("<table>\n");
+
+ /*
+ * Create all the dialog boxes for data collection
+ */
+ printf("<tr><td> %s : </td>\n", _("User Name"));
+ printf("<td><input type=text size=30 name=%s value=%s></td></tr>\n",SWAT_USER, new_name);
+ printf("<tr><td> %s : </td>\n", _("Old Password"));
+ printf("<td><input type=password size=30 name=%s></td></tr>\n",OLD_PSWD);
+ printf("<tr><td> %s : </td>\n", _("New Password"));
+ printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW_PSWD);
+ printf("<tr><td> %s : </td>\n", _("Re-type New Password"));
+ printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW2_PSWD);
+ printf("<tr><td> %s : </td>\n", _("Remote Machine"));
+ printf("<td><input type=text size=30 name=%s></td></tr>\n",RHOST);
+
+ printf("</table>");
+
+ /*
+ * Create all the control buttons for requesting action
+ */
+ printf("<input type=submit name=%s value=\"%s\">",
+ CHG_R_PASSWD_FLAG, _("Change Password"));
+
+ printf("<p></FORM>\n");
+
+ /*
+ * Do some work if a request has been made to change the
+ * password somewhere other than the server. It could be this
+ * is the first time through this code, so there isn't
+ * anything to do. */
+ if (cgi_variable(CHG_R_PASSWD_FLAG)) {
+ chg_passwd();
+ }
+
+}
+
+/****************************************************************************
+ display a printers editing page
+****************************************************************************/
+static void printers_page(void)
+{
+ const char *share = cgi_variable("share");
+ char *s;
+ int snum=-1;
+ int i;
+ int mode = 0;
+ unsigned int parm_filter = FLAG_BASIC;
+
+ if (share)
+ snum = lp_servicenumber(share);
+
+ printf("<H2>%s</H2>\n", _("Printer Parameters"));
+
+ printf("<H3>%s</H3>\n", _("Important Note:"));
+ printf(_("Printer names marked with [*] in the Choose Printer drop-down box "));
+ printf(_("are autoloaded printers from "));
+ printf("<A HREF=\"/swat/help/smb.conf.5.html#printcapname\" target=\"docs\">%s</A>\n", _("Printcap Name"));
+ printf("%s\n", _("Attempting to delete these printers from SWAT will have no effect."));
+
+ if (cgi_variable("Commit") && snum >= 0) {
+ commit_parameters(snum);
+ if (snum >= iNumNonAutoPrintServices)
+ save_reload(snum);
+ else
+ save_reload(0);
+ snum = lp_servicenumber(share);
+ }
+
+ if (cgi_variable("Delete") && snum >= 0) {
+ lp_remove_service(snum);
+ save_reload(0);
+ share = NULL;
+ snum = -1;
+ }
+
+ if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
+ snum = lp_servicenumber(share);
+ if (snum < 0 || snum >= iNumNonAutoPrintServices) {
+ load_config(False);
+ lp_copy_service(GLOBAL_SECTION_SNUM, share);
+ snum = lp_servicenumber(share);
+ lp_do_parameter(snum, "print ok", "Yes");
+ save_reload(snum);
+ snum = lp_servicenumber(share);
+ }
+ }
+
+ printf("<FORM name=\"swatform\" method=post>\n");
+
+ if ( cgi_variable("ViewMode") )
+ mode = atoi(cgi_variable_nonull("ViewMode"));
+ if ( cgi_variable("BasicMode"))
+ mode = 0;
+ if ( cgi_variable("AdvMode"))
+ mode = 1;
+
+ ViewModeBoxes( mode );
+ switch ( mode ) {
+ case 0:
+ parm_filter = FLAG_BASIC;
+ break;
+ case 1:
+ parm_filter = FLAG_ADVANCED;
+ break;
+ }
+ printf("<table>\n");
+ printf("<tr><td><input type=submit name=\"selectshare\" value=\"%s\"></td>\n", _("Choose Printer"));
+ 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)) {
+ if (i >= iNumNonAutoPrintServices)
+ printf("<option %s value=\"%s\">[*]%s\n",
+ (share && strcmp(share,s)==0)?"SELECTED":"",
+ s, s);
+ else
+ printf("<option %s value=\"%s\">%s\n",
+ (share && strcmp(share,s)==0)?"SELECTED":"",
+ s, s);
+ }
+ }
+ printf("</select></td>");
+ if (have_write_access) {
+ printf("<td><input type=submit name=\"Delete\" value=\"%s\"></td>\n", _("Delete Printer"));
+ }
+ printf("</tr>");
+ printf("</table>\n");
+
+ if (have_write_access) {
+ printf("<table>\n");
+ printf("<tr><td><input type=submit name=\"createshare\" value=\"%s\"></td>\n", _("Create Printer"));
+ printf("<td><input type=text size=30 name=\"newshare\"></td></tr>\n");
+ printf("</table>");
+ }
+
+
+ if (snum >= 0) {
+ if (have_write_access) {
+ printf("<input type=submit name=\"Commit\" value=\"%s\">\n", _("Commit Changes"));
+ }
+ printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n", _("Reset Values"));
+ printf("<p>\n");
+ }
+
+ if (snum >= 0) {
+ printf("<table>\n");
+ show_parameters(snum, 1, parm_filter, 1);
+ printf("</table>\n");
+ }
+ printf("</FORM>\n");
+}
+
+/*
+ when the _() translation macro is used there is no obvious place to free
+ the resulting string and there is no easy way to give a static pointer.
+ All we can do is rotate between some static buffers and hope a single d_printf()
+ doesn't have more calls to _() than the number of buffers
+*/
+
+const char *lang_msg_rotate(TALLOC_CTX *ctx, const char *msgid)
+{
+ const char *msgstr;
+ const char *ret;
+
+ msgstr = lang_msg(msgid);
+ if (!msgstr) {
+ return msgid;
+ }
+
+ ret = talloc_strdup(ctx, msgstr);
+
+ lang_msg_free(msgstr);
+ if (!ret) {
+ return msgid;
+ }
+
+ return ret;
+}
+
+/**
+ * main function for SWAT.
+ **/
+ int main(int argc, char *argv[])
+{
+ const char *page;
+ poptContext pc;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "disable-authentication", 'a', POPT_ARG_VAL, &demo_mode, True, "Disable authentication (demo mode)" },
+ { "password-menu-only", 'P', POPT_ARG_VAL, &passwd_only, True, "Show only change password menu" },
+ POPT_COMMON_SAMBA
+ POPT_TABLEEND
+ };
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ fault_setup(NULL);
+ umask(S_IWGRP | S_IWOTH);
+
+#if defined(HAVE_SET_AUTH_PARAMETERS)
+ set_auth_parameters(argc, argv);
+#endif /* HAVE_SET_AUTH_PARAMETERS */
+
+ /* just in case it goes wild ... */
+ alarm(300);
+
+ setlinebuf(stdout);
+
+ /* we don't want any SIGPIPE messages */
+ BlockSignals(True,SIGPIPE);
+
+ dbf = x_fopen("/dev/null", O_WRONLY, 0);
+ if (!dbf) dbf = x_stderr;
+
+ /* we don't want stderr screwing us up */
+ close(2);
+ open("/dev/null", O_WRONLY);
+
+ pc = poptGetContext("swat", argc, (const char **) argv, long_options, 0);
+
+ /* Parse command line options */
+
+ while(poptGetNextOpt(pc) != -1) { }
+
+ poptFreeContext(pc);
+
+ load_case_tables();
+
+ setup_logging(argv[0],False);
+ load_config(True);
+ load_interfaces();
+ iNumNonAutoPrintServices = lp_numservices();
+ load_printers();
+
+ cgi_setup(get_dyn_SWATDIR(), !demo_mode);
+
+ print_header();
+
+ cgi_load_variables();
+
+ if (!file_exist(get_dyn_CONFIGFILE(), NULL)) {
+ have_read_access = True;
+ have_write_access = True;
+ } else {
+ /* check if the authenticated user has write access - if not then
+ don't show write options */
+ have_write_access = (access(get_dyn_CONFIGFILE(),W_OK) == 0);
+
+ /* if the user doesn't have read access to smb.conf then
+ don't let them view it */
+ have_read_access = (access(get_dyn_CONFIGFILE(),R_OK) == 0);
+ }
+
+ show_main_buttons();
+
+ page = cgi_pathinfo();
+
+ /* Root gets full functionality */
+ if (have_read_access && strcmp(page, "globals")==0) {
+ globals_page();
+ } else if (have_read_access && strcmp(page,"shares")==0) {
+ shares_page();
+ } else if (have_read_access && strcmp(page,"printers")==0) {
+ printers_page();
+ } else if (have_read_access && strcmp(page,"status")==0) {
+ status_page();
+ } else if (have_read_access && strcmp(page,"viewconfig")==0) {
+ viewconfig_page();
+ } else if (strcmp(page,"passwd")==0) {
+ passwd_page();
+ } else if (have_read_access && strcmp(page,"wizard")==0) {
+ wizard_page();
+ } else if (have_read_access && strcmp(page,"wizard_params")==0) {
+ wizard_params_page();
+ } else if (have_read_access && strcmp(page,"rewritecfg")==0) {
+ rewritecfg_file();
+ } else {
+ welcome_page();
+ }
+
+ print_footer();
+
+ TALLOC_FREE(frame);
+ return 0;
+}
+
+/** @} **/
diff --git a/source3/web/swat_proto.h b/source3/web/swat_proto.h
new file mode 100644
index 0000000000..0f84e4f4ce
--- /dev/null
+++ b/source3/web/swat_proto.h
@@ -0,0 +1,70 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * collected prototypes header
+ *
+ * frozen from "make proto" in May 2008
+ *
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SWAT_PROTO_H_
+#define _SWAT_PROTO_H_
+
+
+/* The following definitions come from web/cgi.c */
+
+void cgi_load_variables(void);
+const char *cgi_variable(const char *name);
+const char *cgi_variable_nonull(const char *name);
+bool am_root(void);
+char *cgi_user_name(void);
+void cgi_setup(const char *rootdir, int auth_required);
+const char *cgi_baseurl(void);
+const char *cgi_pathinfo(void);
+const char *cgi_remote_host(void);
+const char *cgi_remote_addr(void);
+bool cgi_waspost(void);
+
+/* The following definitions come from web/diagnose.c */
+
+bool winbindd_running(void);
+bool nmbd_running(void);
+bool smbd_running(void);
+
+/* The following definitions come from web/neg_lang.c */
+
+int web_open(const char *fname, int flags, mode_t mode);
+void web_set_lang(const char *lang_string);
+
+/* The following definitions come from web/startstop.c */
+
+void start_smbd(void);
+void start_nmbd(void);
+void start_winbindd(void);
+void stop_smbd(void);
+void stop_nmbd(void);
+void stop_winbindd(void);
+void kill_pid(struct server_id pid);
+
+/* The following definitions come from web/statuspage.c */
+
+void status_page(void);
+
+/* The following definitions come from web/swat.c */
+
+const char *lang_msg_rotate(TALLOC_CTX *ctx, const char *msgid);
+
+#endif /* _SWAT_PROTO_H_ */
diff --git a/source3/winbindd/idmap.c b/source3/winbindd/idmap.c
new file mode 100644
index 0000000000..cfc5597f42
--- /dev/null
+++ b/source3/winbindd/idmap.c
@@ -0,0 +1,790 @@
+/*
+ Unix SMB/CIFS implementation.
+ ID Mapping
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+ Copyright (C) Simo Sorce 2003-2007
+ Copyright (C) Jeremy Allison 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_IDMAP
+
+static_decl_idmap;
+
+/**
+ * Pointer to the backend methods. Modules register themselves here via
+ * smb_register_idmap.
+ */
+
+struct idmap_backend {
+ const char *name;
+ struct idmap_methods *methods;
+ struct idmap_backend *prev, *next;
+};
+static struct idmap_backend *backends = NULL;
+
+/**
+ * Pointer to the alloc backend methods. Modules register themselves here via
+ * smb_register_idmap_alloc.
+ */
+struct idmap_alloc_backend {
+ const char *name;
+ struct idmap_alloc_methods *methods;
+ struct idmap_alloc_backend *prev, *next;
+};
+static struct idmap_alloc_backend *alloc_backends = NULL;
+
+/**
+ * The idmap alloc context that is configured via "idmap alloc
+ * backend". Defaults to "idmap backend" in case the module (tdb, ldap) also
+ * provides alloc methods.
+ */
+struct idmap_alloc_context {
+ struct idmap_alloc_methods *methods;
+};
+static struct idmap_alloc_context *idmap_alloc_ctx = NULL;
+
+/**
+ * Default idmap domain configured via "idmap backend".
+ */
+static struct idmap_domain *default_idmap_domain;
+
+/**
+ * Passdb idmap domain, not configurable. winbind must always give passdb a
+ * chance to map ids.
+ */
+static struct idmap_domain *passdb_idmap_domain;
+
+/**
+ * List of specially configured idmap domains. This list is filled on demand
+ * in the winbind idmap child when the parent winbind figures out via the
+ * special range parameter or via the domain SID that a special "idmap config
+ * domain" configuration is present.
+ */
+static struct idmap_domain **idmap_domains = NULL;
+static int num_domains = 0;
+
+static struct idmap_methods *get_methods(const char *name)
+{
+ struct idmap_backend *b;
+
+ for (b = backends; b; b = b->next) {
+ if (strequal(b->name, name)) {
+ return b->methods;
+ }
+ }
+
+ return NULL;
+}
+
+static struct idmap_alloc_methods *get_alloc_methods(const char *name)
+{
+ struct idmap_alloc_backend *b;
+
+ for (b = alloc_backends; b; b = b->next) {
+ if (strequal(b->name, name)) {
+ return b->methods;
+ }
+ }
+
+ return NULL;
+}
+
+bool idmap_is_offline(void)
+{
+ return ( lp_winbind_offline_logon() &&
+ get_global_winbindd_state_offline() );
+}
+
+bool idmap_is_online(void)
+{
+ return !idmap_is_offline();
+}
+
+/**********************************************************************
+ Allow a module to register itself as a method.
+**********************************************************************/
+
+NTSTATUS smb_register_idmap(int version, const char *name,
+ struct idmap_methods *methods)
+{
+ struct idmap_backend *entry;
+
+ if ((version != SMB_IDMAP_INTERFACE_VERSION)) {
+ DEBUG(0, ("Failed to register idmap module.\n"
+ "The module was compiled against "
+ "SMB_IDMAP_INTERFACE_VERSION %d,\n"
+ "current SMB_IDMAP_INTERFACE_VERSION is %d.\n"
+ "Please recompile against the current version "
+ "of samba!\n",
+ version, SMB_IDMAP_INTERFACE_VERSION));
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ if (!name || !name[0] || !methods) {
+ DEBUG(0,("Called with NULL pointer or empty name!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ for (entry = backends; entry != NULL; entry = entry->next) {
+ if (strequal(entry->name, name)) {
+ DEBUG(0,("Idmap module %s already registered!\n",
+ name));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+ }
+
+ entry = talloc(NULL, struct idmap_backend);
+ if ( ! entry) {
+ DEBUG(0,("Out of memory!\n"));
+ TALLOC_FREE(entry);
+ return NT_STATUS_NO_MEMORY;
+ }
+ entry->name = talloc_strdup(entry, name);
+ if ( ! entry->name) {
+ DEBUG(0,("Out of memory!\n"));
+ TALLOC_FREE(entry);
+ return NT_STATUS_NO_MEMORY;
+ }
+ entry->methods = methods;
+
+ DLIST_ADD(backends, entry);
+ DEBUG(5, ("Successfully added idmap backend '%s'\n", name));
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Allow a module to register itself as an alloc method.
+**********************************************************************/
+
+NTSTATUS smb_register_idmap_alloc(int version, const char *name,
+ struct idmap_alloc_methods *methods)
+{
+ struct idmap_alloc_methods *test;
+ struct idmap_alloc_backend *entry;
+
+ if ((version != SMB_IDMAP_INTERFACE_VERSION)) {
+ DEBUG(0, ("Failed to register idmap alloc module.\n"
+ "The module was compiled against "
+ "SMB_IDMAP_INTERFACE_VERSION %d,\n"
+ "current SMB_IDMAP_INTERFACE_VERSION is %d.\n"
+ "Please recompile against the current version "
+ "of samba!\n",
+ version, SMB_IDMAP_INTERFACE_VERSION));
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ if (!name || !name[0] || !methods) {
+ DEBUG(0,("Called with NULL pointer or empty name!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ test = get_alloc_methods(name);
+ if (test) {
+ DEBUG(0,("idmap_alloc module %s already registered!\n", name));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ entry = talloc(NULL, struct idmap_alloc_backend);
+ if ( ! entry) {
+ DEBUG(0,("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ entry->name = talloc_strdup(entry, name);
+ if ( ! entry->name) {
+ DEBUG(0,("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ entry->methods = methods;
+
+ DLIST_ADD(alloc_backends, entry);
+ DEBUG(5, ("Successfully added idmap alloc backend '%s'\n", name));
+ return NT_STATUS_OK;
+}
+
+static int close_domain_destructor(struct idmap_domain *dom)
+{
+ NTSTATUS ret;
+
+ ret = dom->methods->close_fn(dom);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(3, ("Failed to close idmap domain [%s]!\n", dom->name));
+ }
+
+ return 0;
+}
+
+static bool parse_idmap_module(TALLOC_CTX *mem_ctx, const char *param,
+ char **pmodulename, char **pargs)
+{
+ char *modulename;
+ char *args;
+
+ if (strncmp(param, "idmap_", 6) == 0) {
+ param += 6;
+ DEBUG(1, ("idmap_init: idmap backend uses deprecated "
+ "'idmap_' prefix. Please replace 'idmap_%s' by "
+ "'%s'\n", param, param));
+ }
+
+ modulename = talloc_strdup(mem_ctx, param);
+ if (modulename == NULL) {
+ return false;
+ }
+
+ args = strchr(modulename, ':');
+ if (args == NULL) {
+ *pmodulename = modulename;
+ *pargs = NULL;
+ return true;
+ }
+
+ *args = '\0';
+
+ args = talloc_strdup(mem_ctx, args+1);
+ if (args == NULL) {
+ TALLOC_FREE(modulename);
+ return false;
+ }
+
+ *pmodulename = modulename;
+ *pargs = args;
+ return true;
+}
+
+/**
+ * Initialize a domain structure
+ * @param[in] mem_ctx memory context for the result
+ * @param[in] domainname which domain is this for
+ * @param[in] modulename which backend module
+ * @param[in] params parameter to pass to the init function
+ * @result The initialized structure
+ */
+static struct idmap_domain *idmap_init_domain(TALLOC_CTX *mem_ctx,
+ const char *domainname,
+ const char *modulename,
+ const char *params)
+{
+ struct idmap_domain *result;
+ NTSTATUS status;
+
+ result = talloc_zero(mem_ctx, struct idmap_domain);
+ if (result == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ result->name = talloc_strdup(result, domainname);
+ if (result->name == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ goto fail;
+ }
+
+ result->methods = get_methods(modulename);
+ if (result->methods == NULL) {
+ DEBUG(3, ("idmap backend %s not found\n", modulename));
+
+ status = smb_probe_module("idmap", modulename);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Could not probe idmap module %s\n",
+ modulename));
+ goto fail;
+ }
+
+ result->methods = get_methods(modulename);
+ }
+ if (result->methods == NULL) {
+ DEBUG(1, ("idmap backend %s not found\n", modulename));
+ goto fail;
+ }
+
+ status = result->methods->init(result, params);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("idmap initialization returned %s\n",
+ nt_errstr(status)));
+ goto fail;
+ }
+
+ talloc_set_destructor(result, close_domain_destructor);
+
+ return result;
+
+fail:
+ TALLOC_FREE(result);
+ return NULL;
+}
+
+/**
+ * Initialize the default domain structure
+ * @param[in] mem_ctx memory context for the result
+ * @result The default domain structure
+ *
+ * This routine takes the module name from the "idmap backend" parameter,
+ * passing a possible parameter like ldap:ldap://ldap-url/ to the module.
+ */
+
+static struct idmap_domain *idmap_init_default_domain(TALLOC_CTX *mem_ctx)
+{
+ struct idmap_domain *result;
+ char *modulename;
+ char *params;
+
+ DEBUG(10, ("idmap_init_default_domain: calling static_init_idmap\n"));
+
+ static_init_idmap;
+
+ if (!parse_idmap_module(talloc_tos(), lp_idmap_backend(), &modulename,
+ &params)) {
+ DEBUG(1, ("parse_idmap_module failed\n"));
+ return NULL;
+ }
+
+ DEBUG(3, ("idmap_init: using '%s' as remote backend\n", modulename));
+
+ result = idmap_init_domain(mem_ctx, "*", modulename, params);
+ if (result == NULL) {
+ goto fail;
+ }
+
+ TALLOC_FREE(modulename);
+ TALLOC_FREE(params);
+ return result;
+
+fail:
+ TALLOC_FREE(modulename);
+ TALLOC_FREE(params);
+ TALLOC_FREE(result);
+ return NULL;
+}
+
+/**
+ * Initialize a named domain structure
+ * @param[in] mem_ctx memory context for the result
+ * @param[in] domname the domain name
+ * @result The default domain structure
+ *
+ * This routine looks at the "idmap config <domname>" parameters to figure out
+ * the configuration.
+ */
+
+static struct idmap_domain *idmap_init_named_domain(TALLOC_CTX *mem_ctx,
+ const char *domname)
+{
+ struct idmap_domain *result = NULL;
+ char *config_option;
+ const char *backend;
+
+ config_option = talloc_asprintf(talloc_tos(), "idmap config %s",
+ domname);
+ if (config_option == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ goto fail;
+ }
+
+ backend = lp_parm_const_string(-1, config_option, "backend", NULL);
+ if (backend == NULL) {
+ DEBUG(1, ("no backend defined for %s\n", config_option));
+ goto fail;
+ }
+
+ result = idmap_init_domain(mem_ctx, domname, backend, NULL);
+ if (result == NULL) {
+ goto fail;
+ }
+
+ TALLOC_FREE(config_option);
+ return result;
+
+fail:
+ TALLOC_FREE(config_option);
+ TALLOC_FREE(result);
+ return NULL;
+}
+
+/**
+ * Initialize the passdb domain structure
+ * @param[in] mem_ctx memory context for the result
+ * @result The default domain structure
+ *
+ * No config, passdb has its own configuration.
+ */
+
+static struct idmap_domain *idmap_init_passdb_domain(TALLOC_CTX *mem_ctx)
+{
+ if (passdb_idmap_domain != NULL) {
+ return passdb_idmap_domain;
+ }
+
+ passdb_idmap_domain = idmap_init_domain(NULL, get_global_sam_name(),
+ "passdb", NULL);
+ if (passdb_idmap_domain == NULL) {
+ DEBUG(1, ("Could not init passdb idmap domain\n"));
+ }
+
+ return passdb_idmap_domain;
+}
+
+/**
+ * Find a domain struct according to a domain name
+ * @param[in] domname Domain name to get the config for
+ * @result The default domain structure that fits
+ *
+ * This is the central routine in the winbindd-idmap child to pick the correct
+ * domain for looking up IDs. If domname is NULL or empty, we use the default
+ * domain. If it contains something, we try to use idmap_init_named_domain()
+ * to fetch the correct backend.
+ *
+ * The choice about "domname" is being made by the winbind parent, look at the
+ * "have_idmap_config" of "struct winbindd_domain" which is set in
+ * add_trusted_domain.
+ */
+
+static struct idmap_domain *idmap_find_domain(const char *domname)
+{
+ struct idmap_domain *result;
+ int i;
+
+ /*
+ * Always init the default domain, we can't go without one
+ */
+ if (default_idmap_domain == NULL) {
+ default_idmap_domain = idmap_init_default_domain(NULL);
+ }
+ if (default_idmap_domain == NULL) {
+ return NULL;
+ }
+
+ if ((domname == NULL) || (domname[0] == '\0')) {
+ return default_idmap_domain;
+ }
+
+ for (i=0; i<num_domains; i++) {
+ if (strequal(idmap_domains[i]->name, domname)) {
+ return idmap_domains[i];
+ }
+ }
+
+ if (idmap_domains == NULL) {
+ /*
+ * talloc context for all idmap domains
+ */
+ idmap_domains = TALLOC_ARRAY(NULL, struct idmap_domain *, 1);
+ }
+
+ if (idmap_domains == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ result = idmap_init_named_domain(idmap_domains, domname);
+ if (result == NULL) {
+ /*
+ * Could not init that domain -- try the default one
+ */
+ return default_idmap_domain;
+ }
+
+ ADD_TO_ARRAY(idmap_domains, struct idmap_domain *, result,
+ &idmap_domains, &num_domains);
+ return result;
+}
+
+void idmap_close(void)
+{
+ if (idmap_alloc_ctx) {
+ idmap_alloc_ctx->methods->close_fn();
+ idmap_alloc_ctx->methods = NULL;
+ }
+ alloc_backends = NULL;
+ TALLOC_FREE(default_idmap_domain);
+ TALLOC_FREE(passdb_idmap_domain);
+ TALLOC_FREE(idmap_domains);
+ num_domains = 0;
+}
+
+/**
+ * Initialize the idmap alloc backend
+ * @param[out] ctx Where to put the alloc_ctx?
+ * @result Did it work fine?
+ *
+ * This routine first looks at "idmap alloc backend" and if that is not
+ * defined, it uses "idmap backend" for the module name.
+ */
+static NTSTATUS idmap_alloc_init(struct idmap_alloc_context **ctx)
+{
+ const char *backend;
+ char *modulename, *params;
+ NTSTATUS ret = NT_STATUS_NO_MEMORY;;
+
+ if (idmap_alloc_ctx != NULL) {
+ *ctx = idmap_alloc_ctx;
+ return NT_STATUS_OK;
+ }
+
+ idmap_alloc_ctx = talloc(NULL, struct idmap_alloc_context);
+ if (idmap_alloc_ctx == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ goto fail;
+ }
+
+ backend = lp_idmap_alloc_backend();
+ if ((backend == NULL) || (backend[0] == '\0')) {
+ backend = lp_idmap_backend();
+ }
+
+ if (backend == NULL) {
+ DEBUG(3, ("no idmap alloc backend defined\n"));
+ ret = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ if (!parse_idmap_module(idmap_alloc_ctx, backend, &modulename,
+ &params)) {
+ DEBUG(1, ("parse_idmap_module %s failed\n", backend));
+ goto fail;
+ }
+
+ idmap_alloc_ctx->methods = get_alloc_methods(modulename);
+
+ if (idmap_alloc_ctx->methods == NULL) {
+ ret = smb_probe_module("idmap", modulename);
+ if (NT_STATUS_IS_OK(ret)) {
+ idmap_alloc_ctx->methods =
+ get_alloc_methods(modulename);
+ }
+ }
+
+ if (idmap_alloc_ctx->methods == NULL) {
+ DEBUG(1, ("could not find idmap alloc module %s\n", backend));
+ ret = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ ret = idmap_alloc_ctx->methods->init(params);
+
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(0, ("ERROR: Initialization failed for alloc "
+ "backend, deferred!\n"));
+ goto fail;
+ }
+
+ TALLOC_FREE(modulename);
+ TALLOC_FREE(params);
+
+ *ctx = idmap_alloc_ctx;
+ return NT_STATUS_OK;
+
+fail:
+ TALLOC_FREE(idmap_alloc_ctx);
+ return ret;
+}
+
+/**************************************************************************
+ idmap allocator interface functions
+**************************************************************************/
+
+NTSTATUS idmap_allocate_uid(struct unixid *id)
+{
+ struct idmap_alloc_context *ctx;
+ NTSTATUS ret;
+
+ if (!NT_STATUS_IS_OK(ret = idmap_alloc_init(&ctx))) {
+ return ret;
+ }
+
+ id->type = ID_TYPE_UID;
+ return ctx->methods->allocate_id(id);
+}
+
+NTSTATUS idmap_allocate_gid(struct unixid *id)
+{
+ struct idmap_alloc_context *ctx;
+ NTSTATUS ret;
+
+ if (!NT_STATUS_IS_OK(ret = idmap_alloc_init(&ctx))) {
+ return ret;
+ }
+
+ id->type = ID_TYPE_GID;
+ return ctx->methods->allocate_id(id);
+}
+
+NTSTATUS idmap_set_uid_hwm(struct unixid *id)
+{
+ struct idmap_alloc_context *ctx;
+ NTSTATUS ret;
+
+ if (!NT_STATUS_IS_OK(ret = idmap_alloc_init(&ctx))) {
+ return ret;
+ }
+
+ id->type = ID_TYPE_UID;
+ return ctx->methods->set_id_hwm(id);
+}
+
+NTSTATUS idmap_set_gid_hwm(struct unixid *id)
+{
+ struct idmap_alloc_context *ctx;
+ NTSTATUS ret;
+
+ if (!NT_STATUS_IS_OK(ret = idmap_alloc_init(&ctx))) {
+ return ret;
+ }
+
+ id->type = ID_TYPE_GID;
+ return ctx->methods->set_id_hwm(id);
+}
+
+NTSTATUS idmap_new_mapping(const struct dom_sid *psid, enum id_type type,
+ struct unixid *pxid)
+{
+ struct dom_sid sid;
+ struct idmap_domain *dom;
+ struct id_map map;
+ NTSTATUS status;
+
+ dom = idmap_find_domain(NULL);
+ if (dom == NULL) {
+ DEBUG(3, ("no default domain, no place to write\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ if (dom->methods->set_mapping == NULL) {
+ DEBUG(3, ("default domain not writable\n"));
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+ }
+
+ sid_copy(&sid, psid);
+ map.sid = &sid;
+ map.xid.type = type;
+
+ switch (type) {
+ case ID_TYPE_UID:
+ status = idmap_allocate_uid(&map.xid);
+ break;
+ case ID_TYPE_GID:
+ status = idmap_allocate_gid(&map.xid);
+ break;
+ default:
+ status = NT_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Could not allocate id: %s\n", nt_errstr(status)));
+ return status;
+ }
+
+ map.status = ID_MAPPED;
+
+ DEBUG(10, ("Setting mapping: %s <-> %s %lu\n",
+ sid_string_dbg(map.sid),
+ (map.xid.type == ID_TYPE_UID) ? "UID" : "GID",
+ (unsigned long)map.xid.id));
+
+ status = dom->methods->set_mapping(dom, &map);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+ struct id_map *ids[2];
+ DEBUG(5, ("Mapping for %s exists - retrying to map sid\n",
+ sid_string_dbg(map.sid)));
+ ids[0] = &map;
+ ids[1] = NULL;
+ status = dom->methods->sids_to_unixids(dom, ids);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Could not store the new mapping: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ *pxid = map.xid;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS idmap_backends_unixid_to_sid(const char *domname, struct id_map *id)
+{
+ struct idmap_domain *dom;
+ struct id_map *maps[2];
+
+ maps[0] = id;
+ maps[1] = NULL;
+
+ /*
+ * Always give passdb a chance first
+ */
+
+ dom = idmap_init_passdb_domain(NULL);
+ if ((dom != NULL)
+ && NT_STATUS_IS_OK(dom->methods->unixids_to_sids(dom, maps))) {
+ return NT_STATUS_OK;
+ }
+
+ dom = idmap_find_domain(domname);
+ if (dom == NULL) {
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ return dom->methods->unixids_to_sids(dom, maps);
+}
+
+NTSTATUS idmap_backends_sid_to_unixid(const char *domain, struct id_map *id)
+{
+ struct idmap_domain *dom;
+ struct id_map *maps[2];
+
+ maps[0] = id;
+ maps[1] = NULL;
+
+ if (sid_check_is_in_builtin(id->sid)
+ || (sid_check_is_in_our_domain(id->sid))) {
+
+ dom = idmap_init_passdb_domain(NULL);
+ if (dom == NULL) {
+ return NT_STATUS_NONE_MAPPED;
+ }
+ return dom->methods->sids_to_unixids(dom, maps);
+ }
+
+ dom = idmap_find_domain(domain);
+ if (dom == NULL) {
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ return dom->methods->sids_to_unixids(dom, maps);
+}
+
+NTSTATUS idmap_set_mapping(const struct id_map *map)
+{
+ struct idmap_domain *dom;
+
+ dom = idmap_find_domain(NULL);
+ if (dom == NULL) {
+ DEBUG(3, ("no default domain, no place to write\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ if (dom->methods->set_mapping == NULL) {
+ DEBUG(3, ("default domain not writable\n"));
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+ }
+
+ return dom->methods->set_mapping(dom, map);
+}
diff --git a/source3/winbindd/idmap_ad.c b/source3/winbindd/idmap_ad.c
new file mode 100644
index 0000000000..9fefb1bba7
--- /dev/null
+++ b/source3/winbindd/idmap_ad.c
@@ -0,0 +1,852 @@
+/*
+ * idmap_ad: map between Active Directory and RFC 2307 or "Services for Unix" (SFU) Accounts
+ *
+ * Unix SMB/CIFS implementation.
+ *
+ * Winbind ADS backend functions
+ *
+ * Copyright (C) Andrew Tridgell 2001
+ * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
+ * Copyright (C) Gerald (Jerry) Carter 2004-2007
+ * Copyright (C) Luke Howard 2001-2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_IDMAP
+
+#define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
+
+#define IDMAP_AD_MAX_IDS 30
+#define CHECK_ALLOC_DONE(mem) do { \
+ if (!mem) { \
+ DEBUG(0, ("Out of memory!\n")); \
+ ret = NT_STATUS_NO_MEMORY; \
+ goto done; \
+ } \
+} while (0)
+
+struct idmap_ad_context {
+ uint32_t filter_low_id;
+ uint32_t filter_high_id;
+};
+
+NTSTATUS init_module(void);
+
+static ADS_STRUCT *ad_idmap_ads = NULL;
+static struct posix_schema *ad_schema = NULL;
+static enum wb_posix_mapping ad_map_type = WB_POSIX_MAP_UNKNOWN;
+
+/************************************************************************
+ ***********************************************************************/
+
+static ADS_STRUCT *ad_idmap_cached_connection_internal(void)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ bool local = False;
+ fstring dc_name;
+ struct sockaddr_storage dc_ip;
+
+ if (ad_idmap_ads != NULL) {
+
+ time_t expire;
+ time_t now = time(NULL);
+
+ ads = ad_idmap_ads;
+
+ expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
+
+ /* check for a valid structure */
+ DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
+ (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
+
+ if ( ads->config.realm && (expire > time(NULL))) {
+ return ads;
+ } else {
+ /* we own this ADS_STRUCT so make sure it goes away */
+ DEBUG(7,("Deleting expired krb5 credential cache\n"));
+ ads->is_mine = True;
+ ads_destroy( &ads );
+ ads_kdestroy(WINBIND_CCACHE_NAME);
+ ad_idmap_ads = NULL;
+ TALLOC_FREE( ad_schema );
+ }
+ }
+
+ if (!local) {
+ /* we don't want this to affect the users ccache */
+ setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
+ }
+
+ if ( (ads = ads_init(lp_realm(), lp_workgroup(), NULL)) == NULL ) {
+ DEBUG(1,("ads_init failed\n"));
+ return NULL;
+ }
+
+ /* the machine acct password might have change - fetch it every time */
+ SAFE_FREE(ads->auth.password);
+ ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
+
+ SAFE_FREE(ads->auth.realm);
+ ads->auth.realm = SMB_STRDUP(lp_realm());
+
+ /* setup server affinity */
+
+ get_dc_name( NULL, ads->auth.realm, dc_name, &dc_ip );
+
+ status = ads_connect(ads);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(1, ("ad_idmap_init: failed to connect to AD\n"));
+ ads_destroy(&ads);
+ return NULL;
+ }
+
+ ads->is_mine = False;
+
+ ad_idmap_ads = ads;
+
+ return ads;
+}
+
+/************************************************************************
+ ***********************************************************************/
+
+static ADS_STRUCT *ad_idmap_cached_connection(void)
+{
+ ADS_STRUCT *ads = ad_idmap_cached_connection_internal();
+
+ if ( !ads )
+ return NULL;
+
+ /* if we have a valid ADS_STRUCT and the schema model is
+ defined, then we can return here. */
+
+ if ( ad_schema )
+ return ads;
+
+ /* Otherwise, set the schema model */
+
+ if ( (ad_map_type == WB_POSIX_MAP_SFU) ||
+ (ad_map_type == WB_POSIX_MAP_SFU20) ||
+ (ad_map_type == WB_POSIX_MAP_RFC2307) )
+ {
+ ADS_STATUS schema_status;
+
+ schema_status = ads_check_posix_schema_mapping( NULL, ads, ad_map_type, &ad_schema);
+ if ( !ADS_ERR_OK(schema_status) ) {
+ DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n"));
+ return NULL;
+ }
+ }
+
+ return ads;
+}
+
+/************************************************************************
+ ***********************************************************************/
+
+static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom,
+ const char *params)
+{
+ struct idmap_ad_context *ctx;
+ char *config_option;
+ const char *range = NULL;
+ const char *schema_mode = NULL;
+
+ if ( (ctx = TALLOC_ZERO_P(dom, struct idmap_ad_context)) == NULL ) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( (config_option = talloc_asprintf(ctx, "idmap config %s", dom->name)) == NULL ) {
+ DEBUG(0, ("Out of memory!\n"));
+ talloc_free(ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* load ranges */
+ range = lp_parm_const_string(-1, config_option, "range", NULL);
+ if (range && range[0]) {
+ if ((sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2) ||
+ (ctx->filter_low_id > ctx->filter_high_id)) {
+ DEBUG(1, ("ERROR: invalid filter range [%s]", range));
+ ctx->filter_low_id = 0;
+ ctx->filter_high_id = 0;
+ }
+ }
+
+ /* schema mode */
+ if ( ad_map_type == WB_POSIX_MAP_UNKNOWN )
+ ad_map_type = WB_POSIX_MAP_RFC2307;
+ schema_mode = lp_parm_const_string(-1, config_option, "schema_mode", NULL);
+ if ( schema_mode && schema_mode[0] ) {
+ if ( strequal(schema_mode, "sfu") )
+ ad_map_type = WB_POSIX_MAP_SFU;
+ else if ( strequal(schema_mode, "sfu20" ) )
+ ad_map_type = WB_POSIX_MAP_SFU20;
+ else if ( strequal(schema_mode, "rfc2307" ) )
+ ad_map_type = WB_POSIX_MAP_RFC2307;
+ else
+ DEBUG(0,("idmap_ad_initialize: Unknown schema_mode (%s)\n",
+ schema_mode));
+ }
+
+ dom->private_data = ctx;
+
+ talloc_free(config_option);
+
+ return NT_STATUS_OK;
+}
+
+/************************************************************************
+ Search up to IDMAP_AD_MAX_IDS entries in maps for a match.
+ ***********************************************************************/
+
+static struct id_map *find_map_by_id(struct id_map **maps, enum id_type type, uint32_t id)
+{
+ int i;
+
+ for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
+ if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
+ return maps[i];
+ }
+ }
+
+ return NULL;
+}
+
+/************************************************************************
+ Search up to IDMAP_AD_MAX_IDS entries in maps for a match
+ ***********************************************************************/
+
+static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
+{
+ int i;
+
+ for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
+ if (sid_equal(maps[i]->sid, sid)) {
+ return maps[i];
+ }
+ }
+
+ return NULL;
+}
+
+/************************************************************************
+ ***********************************************************************/
+
+static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
+{
+ NTSTATUS ret;
+ TALLOC_CTX *memctx;
+ struct idmap_ad_context *ctx;
+ ADS_STATUS rc;
+ ADS_STRUCT *ads;
+ const char *attrs[] = { "sAMAccountType",
+ "objectSid",
+ NULL, /* uidnumber */
+ NULL, /* gidnumber */
+ NULL };
+ LDAPMessage *res = NULL;
+ LDAPMessage *entry = NULL;
+ char *filter = NULL;
+ int idx = 0;
+ int bidx = 0;
+ int count;
+ int i;
+ char *u_filter = NULL;
+ char *g_filter = NULL;
+
+ /* Only do query if we are online */
+ if (idmap_is_offline()) {
+ return NT_STATUS_FILE_IS_OFFLINE;
+ }
+
+ ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
+
+ if ( (memctx = talloc_new(ctx)) == NULL ) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( (ads = ad_idmap_cached_connection()) == NULL ) {
+ DEBUG(1, ("ADS uninitialized\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ attrs[2] = ad_schema->posix_uidnumber_attr;
+ attrs[3] = ad_schema->posix_gidnumber_attr;
+
+again:
+ bidx = idx;
+ for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
+ switch (ids[idx]->xid.type) {
+ case ID_TYPE_UID:
+ if ( ! u_filter) {
+ u_filter = talloc_asprintf(memctx, "(&(|"
+ "(sAMAccountType=%d)"
+ "(sAMAccountType=%d)"
+ "(sAMAccountType=%d))(|",
+ ATYPE_NORMAL_ACCOUNT,
+ ATYPE_WORKSTATION_TRUST,
+ ATYPE_INTERDOMAIN_TRUST);
+ }
+ u_filter = talloc_asprintf_append_buffer(u_filter, "(%s=%lu)",
+ ad_schema->posix_uidnumber_attr,
+ (unsigned long)ids[idx]->xid.id);
+ CHECK_ALLOC_DONE(u_filter);
+ break;
+
+ case ID_TYPE_GID:
+ if ( ! g_filter) {
+ g_filter = talloc_asprintf(memctx, "(&(|"
+ "(sAMAccountType=%d)"
+ "(sAMAccountType=%d))(|",
+ ATYPE_SECURITY_GLOBAL_GROUP,
+ ATYPE_SECURITY_LOCAL_GROUP);
+ }
+ g_filter = talloc_asprintf_append_buffer(g_filter, "(%s=%lu)",
+ ad_schema->posix_gidnumber_attr,
+ (unsigned long)ids[idx]->xid.id);
+ CHECK_ALLOC_DONE(g_filter);
+ break;
+
+ default:
+ DEBUG(3, ("Error: mapping requested but Unknown ID type\n"));
+ ids[idx]->status = ID_UNKNOWN;
+ continue;
+ }
+ }
+ filter = talloc_asprintf(memctx, "(|");
+ CHECK_ALLOC_DONE(filter);
+ if ( u_filter) {
+ filter = talloc_asprintf_append_buffer(filter, "%s))", u_filter);
+ CHECK_ALLOC_DONE(filter);
+ TALLOC_FREE(u_filter);
+ }
+ if ( g_filter) {
+ filter = talloc_asprintf_append_buffer(filter, "%s))", g_filter);
+ CHECK_ALLOC_DONE(filter);
+ TALLOC_FREE(g_filter);
+ }
+ filter = talloc_asprintf_append_buffer(filter, ")");
+ CHECK_ALLOC_DONE(filter);
+
+ rc = ads_search_retry(ads, &res, filter, attrs);
+ if (!ADS_ERR_OK(rc)) {
+ DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if ( (count = ads_count_replies(ads, res)) == 0 ) {
+ DEBUG(10, ("No IDs found\n"));
+ }
+
+ entry = res;
+ for (i = 0; (i < count) && entry; i++) {
+ DOM_SID sid;
+ enum id_type type;
+ struct id_map *map;
+ uint32_t id;
+ uint32_t atype;
+
+ if (i == 0) { /* first entry */
+ entry = ads_first_entry(ads, entry);
+ } else { /* following ones */
+ entry = ads_next_entry(ads, entry);
+ }
+
+ if ( !entry ) {
+ DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
+ break;
+ }
+
+ /* first check if the SID is present */
+ if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
+ DEBUG(2, ("Could not retrieve SID from entry\n"));
+ continue;
+ }
+
+ /* get type */
+ if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
+ DEBUG(1, ("could not get SAM account type\n"));
+ continue;
+ }
+
+ switch (atype & 0xF0000000) {
+ case ATYPE_SECURITY_GLOBAL_GROUP:
+ case ATYPE_SECURITY_LOCAL_GROUP:
+ type = ID_TYPE_GID;
+ break;
+ case ATYPE_NORMAL_ACCOUNT:
+ case ATYPE_WORKSTATION_TRUST:
+ case ATYPE_INTERDOMAIN_TRUST:
+ type = ID_TYPE_UID;
+ break;
+ default:
+ DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
+ continue;
+ }
+
+ if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID) ?
+ ad_schema->posix_uidnumber_attr :
+ ad_schema->posix_gidnumber_attr,
+ &id))
+ {
+ DEBUG(1, ("Could not get unix ID\n"));
+ continue;
+ }
+
+ if ((id == 0) ||
+ (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
+ (ctx->filter_high_id && (id > ctx->filter_high_id))) {
+ DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
+ id, ctx->filter_low_id, ctx->filter_high_id));
+ continue;
+ }
+
+ map = find_map_by_id(&ids[bidx], type, id);
+ if (!map) {
+ DEBUG(2, ("WARNING: couldn't match result with requested ID\n"));
+ continue;
+ }
+
+ sid_copy(map->sid, &sid);
+
+ /* mapped */
+ map->status = ID_MAPPED;
+
+ DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
+ (unsigned long)map->xid.id,
+ map->xid.type));
+ }
+
+ if (res) {
+ ads_msgfree(ads, res);
+ }
+
+ if (ids[idx]) { /* still some values to map */
+ goto again;
+ }
+
+ ret = NT_STATUS_OK;
+
+ /* mark all unknown/expired ones as unmapped */
+ for (i = 0; ids[i]; i++) {
+ if (ids[i]->status != ID_MAPPED)
+ ids[i]->status = ID_UNMAPPED;
+ }
+
+done:
+ talloc_free(memctx);
+ return ret;
+}
+
+/************************************************************************
+ ***********************************************************************/
+
+static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
+{
+ NTSTATUS ret;
+ TALLOC_CTX *memctx;
+ struct idmap_ad_context *ctx;
+ ADS_STATUS rc;
+ ADS_STRUCT *ads;
+ const char *attrs[] = { "sAMAccountType",
+ "objectSid",
+ NULL, /* attr_uidnumber */
+ NULL, /* attr_gidnumber */
+ NULL };
+ LDAPMessage *res = NULL;
+ LDAPMessage *entry = NULL;
+ char *filter = NULL;
+ int idx = 0;
+ int bidx = 0;
+ int count;
+ int i;
+ char *sidstr;
+
+ /* Only do query if we are online */
+ if (idmap_is_offline()) {
+ return NT_STATUS_FILE_IS_OFFLINE;
+ }
+
+ ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
+
+ if ( (memctx = talloc_new(ctx)) == NULL ) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( (ads = ad_idmap_cached_connection()) == NULL ) {
+ DEBUG(1, ("ADS uninitialized\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ attrs[2] = ad_schema->posix_uidnumber_attr;
+ attrs[3] = ad_schema->posix_gidnumber_attr;
+
+again:
+ filter = talloc_asprintf(memctx, "(&(|"
+ "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
+ "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
+ ")(|",
+ ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
+ ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
+
+ CHECK_ALLOC_DONE(filter);
+
+ bidx = idx;
+ for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
+
+ sidstr = sid_binstring(ids[idx]->sid);
+ filter = talloc_asprintf_append_buffer(filter, "(objectSid=%s)", sidstr);
+
+ free(sidstr);
+ CHECK_ALLOC_DONE(filter);
+ }
+ filter = talloc_asprintf_append_buffer(filter, "))");
+ CHECK_ALLOC_DONE(filter);
+ DEBUG(10, ("Filter: [%s]\n", filter));
+
+ rc = ads_search_retry(ads, &res, filter, attrs);
+ if (!ADS_ERR_OK(rc)) {
+ DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if ( (count = ads_count_replies(ads, res)) == 0 ) {
+ DEBUG(10, ("No IDs found\n"));
+ }
+
+ entry = res;
+ for (i = 0; (i < count) && entry; i++) {
+ DOM_SID sid;
+ enum id_type type;
+ struct id_map *map;
+ uint32_t id;
+ uint32_t atype;
+
+ if (i == 0) { /* first entry */
+ entry = ads_first_entry(ads, entry);
+ } else { /* following ones */
+ entry = ads_next_entry(ads, entry);
+ }
+
+ if ( !entry ) {
+ DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
+ break;
+ }
+
+ /* first check if the SID is present */
+ if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
+ DEBUG(2, ("Could not retrieve SID from entry\n"));
+ continue;
+ }
+
+ map = find_map_by_sid(&ids[bidx], &sid);
+ if (!map) {
+ DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
+ continue;
+ }
+
+ /* get type */
+ if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
+ DEBUG(1, ("could not get SAM account type\n"));
+ continue;
+ }
+
+ switch (atype & 0xF0000000) {
+ case ATYPE_SECURITY_GLOBAL_GROUP:
+ case ATYPE_SECURITY_LOCAL_GROUP:
+ type = ID_TYPE_GID;
+ break;
+ case ATYPE_NORMAL_ACCOUNT:
+ case ATYPE_WORKSTATION_TRUST:
+ case ATYPE_INTERDOMAIN_TRUST:
+ type = ID_TYPE_UID;
+ break;
+ default:
+ DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
+ continue;
+ }
+
+ if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID) ?
+ ad_schema->posix_uidnumber_attr :
+ ad_schema->posix_gidnumber_attr,
+ &id))
+ {
+ DEBUG(1, ("Could not get unix ID\n"));
+ continue;
+ }
+ if ((id == 0) ||
+ (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
+ (ctx->filter_high_id && (id > ctx->filter_high_id))) {
+ DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
+ id, ctx->filter_low_id, ctx->filter_high_id));
+ continue;
+ }
+
+ /* mapped */
+ map->xid.type = type;
+ map->xid.id = id;
+ map->status = ID_MAPPED;
+
+ DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
+ (unsigned long)map->xid.id,
+ map->xid.type));
+ }
+
+ if (res) {
+ ads_msgfree(ads, res);
+ }
+
+ if (ids[idx]) { /* still some values to map */
+ goto again;
+ }
+
+ ret = NT_STATUS_OK;
+
+ /* mark all unknwoni/expired ones as unmapped */
+ for (i = 0; ids[i]; i++) {
+ if (ids[i]->status != ID_MAPPED)
+ ids[i]->status = ID_UNMAPPED;
+ }
+
+done:
+ talloc_free(memctx);
+ return ret;
+}
+
+/************************************************************************
+ ***********************************************************************/
+
+static NTSTATUS idmap_ad_close(struct idmap_domain *dom)
+{
+ ADS_STRUCT *ads = ad_idmap_ads;
+
+ if (ads != NULL) {
+ /* we own this ADS_STRUCT so make sure it goes away */
+ ads->is_mine = True;
+ ads_destroy( &ads );
+ ad_idmap_ads = NULL;
+ }
+
+ TALLOC_FREE( ad_schema );
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * nss_info_{sfu,sfu20,rfc2307}
+ */
+
+/************************************************************************
+ Initialize the {sfu,sfu20,rfc2307} state
+ ***********************************************************************/
+
+static NTSTATUS nss_sfu_init( struct nss_domain_entry *e )
+{
+ /* Sanity check if we have previously been called with a
+ different schema model */
+
+ if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
+ (ad_map_type != WB_POSIX_MAP_SFU) )
+ {
+ DEBUG(0,("nss_sfu_init: Posix Map type has already been set. "
+ "Mixed schema models not supported!\n"));
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ ad_map_type = WB_POSIX_MAP_SFU;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS nss_sfu20_init( struct nss_domain_entry *e )
+{
+ /* Sanity check if we have previously been called with a
+ different schema model */
+
+ if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
+ (ad_map_type != WB_POSIX_MAP_SFU20) )
+ {
+ DEBUG(0,("nss_sfu20_init: Posix Map type has already been set. "
+ "Mixed schema models not supported!\n"));
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ ad_map_type = WB_POSIX_MAP_SFU20;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e )
+{
+ /* Sanity check if we have previously been called with a
+ different schema model */
+
+ if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
+ (ad_map_type != WB_POSIX_MAP_RFC2307) )
+ {
+ DEBUG(0,("nss_rfc2307_init: Posix Map type has already been set. "
+ "Mixed schema models not supported!\n"));
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ ad_map_type = WB_POSIX_MAP_RFC2307;
+
+ return NT_STATUS_OK;
+}
+
+
+/************************************************************************
+ ***********************************************************************/
+static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e,
+ const DOM_SID *sid,
+ TALLOC_CTX *ctx,
+ ADS_STRUCT *ads,
+ LDAPMessage *msg,
+ char **homedir,
+ char **shell,
+ char **gecos,
+ uint32 *gid )
+{
+ ADS_STRUCT *ads_internal = NULL;
+
+ /* Only do query if we are online */
+ if (idmap_is_offline()) {
+ return NT_STATUS_FILE_IS_OFFLINE;
+ }
+
+ /* We are assuming that the internal ADS_STRUCT is for the
+ same forest as the incoming *ads pointer */
+
+ ads_internal = ad_idmap_cached_connection();
+
+ if ( !ads_internal || !ad_schema )
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ if ( !homedir || !shell || !gecos )
+ return NT_STATUS_INVALID_PARAMETER;
+
+ *homedir = ads_pull_string( ads, ctx, msg, ad_schema->posix_homedir_attr );
+ *shell = ads_pull_string( ads, ctx, msg, ad_schema->posix_shell_attr );
+ *gecos = ads_pull_string( ads, ctx, msg, ad_schema->posix_gecos_attr );
+
+ if ( gid ) {
+ if ( !ads_pull_uint32(ads, msg, ad_schema->posix_gidnumber_attr, gid ) )
+ *gid = (uint32)-1;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/************************************************************************
+ ***********************************************************************/
+
+static NTSTATUS nss_ad_close( void )
+{
+ /* nothing to do. All memory is free()'d by the idmap close_fn() */
+
+ return NT_STATUS_OK;
+}
+
+/************************************************************************
+ Function dispatch tables for the idmap and nss plugins
+ ***********************************************************************/
+
+static struct idmap_methods ad_methods = {
+ .init = idmap_ad_initialize,
+ .unixids_to_sids = idmap_ad_unixids_to_sids,
+ .sids_to_unixids = idmap_ad_sids_to_unixids,
+ .close_fn = idmap_ad_close
+};
+
+/* The SFU and RFC2307 NSS plugins share everything but the init
+ function which sets the intended schema model to use */
+
+static struct nss_info_methods nss_rfc2307_methods = {
+ .init = nss_rfc2307_init,
+ .get_nss_info = nss_ad_get_info,
+ .close_fn = nss_ad_close
+};
+
+static struct nss_info_methods nss_sfu_methods = {
+ .init = nss_sfu_init,
+ .get_nss_info = nss_ad_get_info,
+ .close_fn = nss_ad_close
+};
+
+static struct nss_info_methods nss_sfu20_methods = {
+ .init = nss_sfu20_init,
+ .get_nss_info = nss_ad_get_info,
+ .close_fn = nss_ad_close
+};
+
+
+
+/************************************************************************
+ Initialize the plugins
+ ***********************************************************************/
+
+NTSTATUS idmap_ad_init(void)
+{
+ static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL;
+ static NTSTATUS status_nss_rfc2307 = NT_STATUS_UNSUCCESSFUL;
+ static NTSTATUS status_nss_sfu = NT_STATUS_UNSUCCESSFUL;
+ static NTSTATUS status_nss_sfu20 = NT_STATUS_UNSUCCESSFUL;
+
+ /* Always register the AD method first in order to get the
+ idmap_domain interface called */
+
+ if ( !NT_STATUS_IS_OK(status_idmap_ad) ) {
+ status_idmap_ad = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
+ "ad", &ad_methods);
+ if ( !NT_STATUS_IS_OK(status_idmap_ad) )
+ return status_idmap_ad;
+ }
+
+ if ( !NT_STATUS_IS_OK( status_nss_rfc2307 ) ) {
+ status_nss_rfc2307 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
+ "rfc2307", &nss_rfc2307_methods );
+ if ( !NT_STATUS_IS_OK(status_nss_rfc2307) )
+ return status_nss_rfc2307;
+ }
+
+ if ( !NT_STATUS_IS_OK( status_nss_sfu ) ) {
+ status_nss_sfu = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
+ "sfu", &nss_sfu_methods );
+ if ( !NT_STATUS_IS_OK(status_nss_sfu) )
+ return status_nss_sfu;
+ }
+
+ if ( !NT_STATUS_IS_OK( status_nss_sfu20 ) ) {
+ status_nss_sfu20 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
+ "sfu20", &nss_sfu20_methods );
+ if ( !NT_STATUS_IS_OK(status_nss_sfu20) )
+ return status_nss_sfu20;
+ }
+
+ return NT_STATUS_OK;
+}
+
diff --git a/source3/winbindd/idmap_ldap.c b/source3/winbindd/idmap_ldap.c
new file mode 100644
index 0000000000..c86a5023d0
--- /dev/null
+++ b/source3/winbindd/idmap_ldap.c
@@ -0,0 +1,1480 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ idmap LDAP backend
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+ Copyright (C) Gerald Carter 2003
+ Copyright (C) Simo Sorce 2003-2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_IDMAP
+
+#include <lber.h>
+#include <ldap.h>
+
+#include "smbldap.h"
+
+static char *idmap_fetch_secret(const char *backend, bool alloc,
+ const char *domain, const char *identity)
+{
+ char *tmp, *ret;
+ int r;
+
+ if (alloc) {
+ r = asprintf(&tmp, "IDMAP_ALLOC_%s", backend);
+ } else {
+ r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain);
+ }
+
+ if (r < 0)
+ return NULL;
+
+ strupper_m(tmp); /* make sure the key is case insensitive */
+ ret = secrets_fetch_generic(tmp, identity);
+
+ SAFE_FREE(tmp);
+
+ return ret;
+}
+
+struct idmap_ldap_context {
+ struct smbldap_state *smbldap_state;
+ char *url;
+ char *suffix;
+ char *user_dn;
+ uint32_t filter_low_id, filter_high_id; /* Filter range */
+ bool anon;
+};
+
+struct idmap_ldap_alloc_context {
+ struct smbldap_state *smbldap_state;
+ char *url;
+ char *suffix;
+ char *user_dn;
+ uid_t low_uid, high_uid; /* Range of uids */
+ gid_t low_gid, high_gid; /* Range of gids */
+
+};
+
+#define CHECK_ALLOC_DONE(mem) do { \
+ if (!mem) { \
+ DEBUG(0, ("Out of memory!\n")); \
+ ret = NT_STATUS_NO_MEMORY; \
+ goto done; \
+ } } while (0)
+
+/**********************************************************************
+ IDMAP ALLOC TDB BACKEND
+**********************************************************************/
+
+static struct idmap_ldap_alloc_context *idmap_alloc_ldap;
+
+/*********************************************************************
+ ********************************************************************/
+
+static NTSTATUS get_credentials( TALLOC_CTX *mem_ctx,
+ struct smbldap_state *ldap_state,
+ const char *config_option,
+ struct idmap_domain *dom,
+ char **dn )
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ char *secret = NULL;
+ const char *tmp = NULL;
+ char *user_dn = NULL;
+ bool anon = False;
+
+ /* assume anonymous if we don't have a specified user */
+
+ tmp = lp_parm_const_string(-1, config_option, "ldap_user_dn", NULL);
+
+ if ( tmp ) {
+ if (!dom) {
+ /* only the alloc backend can pass in a NULL dom */
+ secret = idmap_fetch_secret("ldap", True,
+ NULL, tmp);
+ } else {
+ secret = idmap_fetch_secret("ldap", False,
+ dom->name, tmp);
+ }
+
+ if (!secret) {
+ DEBUG(0, ("get_credentials: Unable to fetch "
+ "auth credentials for %s in %s\n",
+ tmp, (dom==NULL)?"ALLOC":dom->name));
+ ret = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+ *dn = talloc_strdup(mem_ctx, tmp);
+ CHECK_ALLOC_DONE(*dn);
+ } else {
+ if (!fetch_ldap_pw(&user_dn, &secret)) {
+ DEBUG(2, ("get_credentials: Failed to lookup ldap "
+ "bind creds. Using anonymous connection.\n"));
+ anon = True;
+ } else {
+ *dn = talloc_strdup(mem_ctx, user_dn);
+ SAFE_FREE( user_dn );
+ CHECK_ALLOC_DONE(*dn);
+ }
+ }
+
+ smbldap_set_creds(ldap_state, anon, *dn, secret);
+ ret = NT_STATUS_OK;
+
+done:
+ SAFE_FREE(secret);
+
+ return ret;
+}
+
+
+/**********************************************************************
+ Verify the sambaUnixIdPool entry in the directory.
+**********************************************************************/
+
+static NTSTATUS verify_idpool(void)
+{
+ NTSTATUS ret;
+ TALLOC_CTX *ctx;
+ LDAPMessage *result = NULL;
+ LDAPMod **mods = NULL;
+ const char **attr_list;
+ char *filter;
+ int count;
+ int rc;
+
+ if ( ! idmap_alloc_ldap) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ctx = talloc_new(idmap_alloc_ldap);
+ if ( ! ctx) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ filter = talloc_asprintf(ctx, "(objectclass=%s)", LDAP_OBJ_IDPOOL);
+ CHECK_ALLOC_DONE(filter);
+
+ attr_list = get_attr_list(ctx, idpool_attr_list);
+ CHECK_ALLOC_DONE(attr_list);
+
+ rc = smbldap_search(idmap_alloc_ldap->smbldap_state,
+ idmap_alloc_ldap->suffix,
+ LDAP_SCOPE_SUBTREE,
+ filter,
+ attr_list,
+ 0,
+ &result);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(1, ("Unable to verify the idpool, "
+ "cannot continue initialization!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct,
+ result);
+
+ ldap_msgfree(result);
+
+ if ( count > 1 ) {
+ DEBUG(0,("Multiple entries returned from %s (base == %s)\n",
+ filter, idmap_alloc_ldap->suffix));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ else if (count == 0) {
+ char *uid_str, *gid_str;
+
+ uid_str = talloc_asprintf(ctx, "%lu",
+ (unsigned long)idmap_alloc_ldap->low_uid);
+ gid_str = talloc_asprintf(ctx, "%lu",
+ (unsigned long)idmap_alloc_ldap->low_gid);
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD,
+ "objectClass", LDAP_OBJ_IDPOOL);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD,
+ get_attr_key2string(idpool_attr_list,
+ LDAP_ATTR_UIDNUMBER),
+ uid_str);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD,
+ get_attr_key2string(idpool_attr_list,
+ LDAP_ATTR_GIDNUMBER),
+ gid_str);
+ if (mods) {
+ rc = smbldap_modify(idmap_alloc_ldap->smbldap_state,
+ idmap_alloc_ldap->suffix,
+ mods);
+ ldap_mods_free(mods, True);
+ } else {
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ }
+
+ ret = (rc == LDAP_SUCCESS)?NT_STATUS_OK:NT_STATUS_UNSUCCESSFUL;
+done:
+ talloc_free(ctx);
+ return ret;
+}
+
+/*****************************************************************************
+ Initialise idmap database.
+*****************************************************************************/
+
+static NTSTATUS idmap_ldap_alloc_init(const char *params)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ const char *tmp;
+ uid_t low_uid = 0;
+ uid_t high_uid = 0;
+ gid_t low_gid = 0;
+ gid_t high_gid = 0;
+
+ /* Only do init if we are online */
+ if (idmap_is_offline()) {
+ return NT_STATUS_FILE_IS_OFFLINE;
+ }
+
+ idmap_alloc_ldap = TALLOC_ZERO_P(NULL, struct idmap_ldap_alloc_context);
+ CHECK_ALLOC_DONE( idmap_alloc_ldap );
+
+ /* load ranges */
+
+ if (!lp_idmap_uid(&low_uid, &high_uid)
+ || !lp_idmap_gid(&low_gid, &high_gid)) {
+ DEBUG(1, ("idmap uid or idmap gid missing\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ idmap_alloc_ldap->low_uid = low_uid;
+ idmap_alloc_ldap->high_uid = high_uid;
+ idmap_alloc_ldap->low_gid = low_gid;
+ idmap_alloc_ldap->high_gid= high_gid;
+
+ if (idmap_alloc_ldap->high_uid <= idmap_alloc_ldap->low_uid) {
+ DEBUG(1, ("idmap uid range invalid\n"));
+ DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (idmap_alloc_ldap->high_gid <= idmap_alloc_ldap->low_gid) {
+ DEBUG(1, ("idmap gid range invalid\n"));
+ DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (params && *params) {
+ /* assume location is the only parameter */
+ idmap_alloc_ldap->url = talloc_strdup(idmap_alloc_ldap, params);
+ } else {
+ tmp = lp_parm_const_string(-1, "idmap alloc config",
+ "ldap_url", NULL);
+
+ if ( ! tmp) {
+ DEBUG(1, ("ERROR: missing idmap ldap url\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ idmap_alloc_ldap->url = talloc_strdup(idmap_alloc_ldap, tmp);
+ }
+ CHECK_ALLOC_DONE( idmap_alloc_ldap->url );
+
+ tmp = lp_parm_const_string(-1, "idmap alloc config",
+ "ldap_base_dn", NULL);
+ if ( ! tmp || ! *tmp) {
+ tmp = lp_ldap_idmap_suffix();
+ if ( ! tmp) {
+ DEBUG(1, ("ERROR: missing idmap ldap suffix\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ }
+
+ idmap_alloc_ldap->suffix = talloc_strdup(idmap_alloc_ldap, tmp);
+ CHECK_ALLOC_DONE( idmap_alloc_ldap->suffix );
+
+ ret = smbldap_init(idmap_alloc_ldap, winbind_event_context(),
+ idmap_alloc_ldap->url,
+ &idmap_alloc_ldap->smbldap_state);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n",
+ idmap_alloc_ldap->url));
+ goto done;
+ }
+
+ ret = get_credentials( idmap_alloc_ldap,
+ idmap_alloc_ldap->smbldap_state,
+ "idmap alloc config", NULL,
+ &idmap_alloc_ldap->user_dn );
+ if ( !NT_STATUS_IS_OK(ret) ) {
+ DEBUG(1,("idmap_ldap_alloc_init: Failed to get connection "
+ "credentials (%s)\n", nt_errstr(ret)));
+ goto done;
+ }
+
+ /* see if the idmap suffix and sub entries exists */
+
+ ret = verify_idpool();
+
+ done:
+ if ( !NT_STATUS_IS_OK( ret ) )
+ TALLOC_FREE( idmap_alloc_ldap );
+
+ return ret;
+}
+
+/********************************
+ Allocate a new uid or gid
+********************************/
+
+static NTSTATUS idmap_ldap_allocate_id(struct unixid *xid)
+{
+ TALLOC_CTX *ctx;
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ int rc = LDAP_SERVER_DOWN;
+ int count = 0;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ LDAPMod **mods = NULL;
+ char *id_str;
+ char *new_id_str;
+ char *filter = NULL;
+ const char *dn = NULL;
+ const char **attr_list;
+ const char *type;
+
+ /* Only do query if we are online */
+ if (idmap_is_offline()) {
+ return NT_STATUS_FILE_IS_OFFLINE;
+ }
+
+ if ( ! idmap_alloc_ldap) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ctx = talloc_new(idmap_alloc_ldap);
+ if ( ! ctx) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* get type */
+ switch (xid->type) {
+
+ case ID_TYPE_UID:
+ type = get_attr_key2string(idpool_attr_list,
+ LDAP_ATTR_UIDNUMBER);
+ break;
+
+ case ID_TYPE_GID:
+ type = get_attr_key2string(idpool_attr_list,
+ LDAP_ATTR_GIDNUMBER);
+ break;
+
+ default:
+ DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ filter = talloc_asprintf(ctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
+ CHECK_ALLOC_DONE(filter);
+
+ attr_list = get_attr_list(ctx, idpool_attr_list);
+ CHECK_ALLOC_DONE(attr_list);
+
+ DEBUG(10, ("Search of the id pool (filter: %s)\n", filter));
+
+ rc = smbldap_search(idmap_alloc_ldap->smbldap_state,
+ idmap_alloc_ldap->suffix,
+ LDAP_SCOPE_SUBTREE, filter,
+ attr_list, 0, &result);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("%s object not found\n", LDAP_OBJ_IDPOOL));
+ goto done;
+ }
+
+ talloc_autofree_ldapmsg(ctx, result);
+
+ count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct,
+ result);
+ if (count != 1) {
+ DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL));
+ goto done;
+ }
+
+ entry = ldap_first_entry(idmap_alloc_ldap->smbldap_state->ldap_struct,
+ result);
+
+ dn = smbldap_talloc_dn(ctx,
+ idmap_alloc_ldap->smbldap_state->ldap_struct,
+ entry);
+ if ( ! dn) {
+ goto done;
+ }
+
+ if ( ! (id_str = smbldap_talloc_single_attribute(idmap_alloc_ldap->smbldap_state->ldap_struct,
+ entry, type, ctx))) {
+ DEBUG(0,("%s attribute not found\n", type));
+ goto done;
+ }
+ if ( ! id_str) {
+ DEBUG(0,("Out of memory\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ xid->id = strtoul(id_str, NULL, 10);
+
+ /* make sure we still have room to grow */
+
+ switch (xid->type) {
+ case ID_TYPE_UID:
+ if (xid->id > idmap_alloc_ldap->high_uid) {
+ DEBUG(0,("Cannot allocate uid above %lu!\n",
+ (unsigned long)idmap_alloc_ldap->high_uid));
+ goto done;
+ }
+ break;
+
+ case ID_TYPE_GID:
+ if (xid->id > idmap_alloc_ldap->high_gid) {
+ DEBUG(0,("Cannot allocate gid above %lu!\n",
+ (unsigned long)idmap_alloc_ldap->high_uid));
+ goto done;
+ }
+ break;
+
+ default:
+ /* impossible */
+ goto done;
+ }
+
+ new_id_str = talloc_asprintf(ctx, "%lu", (unsigned long)xid->id + 1);
+ if ( ! new_id_str) {
+ DEBUG(0,("Out of memory\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ smbldap_set_mod(&mods, LDAP_MOD_DELETE, type, id_str);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, type, new_id_str);
+
+ if (mods == NULL) {
+ DEBUG(0,("smbldap_set_mod() failed.\n"));
+ goto done;
+ }
+
+ DEBUG(10, ("Try to atomically increment the id (%s -> %s)\n",
+ id_str, new_id_str));
+
+ rc = smbldap_modify(idmap_alloc_ldap->smbldap_state, dn, mods);
+
+ ldap_mods_free(mods, True);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(1,("Failed to allocate new %s. "
+ "smbldap_modify() failed.\n", type));
+ goto done;
+ }
+
+ ret = NT_STATUS_OK;
+
+done:
+ talloc_free(ctx);
+ return ret;
+}
+
+/**********************************
+ Get current highest id.
+**********************************/
+
+static NTSTATUS idmap_ldap_get_hwm(struct unixid *xid)
+{
+ TALLOC_CTX *memctx;
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ int rc = LDAP_SERVER_DOWN;
+ int count = 0;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ char *id_str;
+ char *filter = NULL;
+ const char **attr_list;
+ const char *type;
+
+ /* Only do query if we are online */
+ if (idmap_is_offline()) {
+ return NT_STATUS_FILE_IS_OFFLINE;
+ }
+
+ if ( ! idmap_alloc_ldap) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ memctx = talloc_new(idmap_alloc_ldap);
+ if ( ! memctx) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* get type */
+ switch (xid->type) {
+
+ case ID_TYPE_UID:
+ type = get_attr_key2string(idpool_attr_list,
+ LDAP_ATTR_UIDNUMBER);
+ break;
+
+ case ID_TYPE_GID:
+ type = get_attr_key2string(idpool_attr_list,
+ LDAP_ATTR_GIDNUMBER);
+ break;
+
+ default:
+ DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ filter = talloc_asprintf(memctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
+ CHECK_ALLOC_DONE(filter);
+
+ attr_list = get_attr_list(memctx, idpool_attr_list);
+ CHECK_ALLOC_DONE(attr_list);
+
+ rc = smbldap_search(idmap_alloc_ldap->smbldap_state,
+ idmap_alloc_ldap->suffix,
+ LDAP_SCOPE_SUBTREE, filter,
+ attr_list, 0, &result);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("%s object not found\n", LDAP_OBJ_IDPOOL));
+ goto done;
+ }
+
+ talloc_autofree_ldapmsg(memctx, result);
+
+ count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct,
+ result);
+ if (count != 1) {
+ DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL));
+ goto done;
+ }
+
+ entry = ldap_first_entry(idmap_alloc_ldap->smbldap_state->ldap_struct,
+ result);
+
+ id_str = smbldap_talloc_single_attribute(idmap_alloc_ldap->smbldap_state->ldap_struct,
+ entry, type, memctx);
+ if ( ! id_str) {
+ DEBUG(0,("%s attribute not found\n", type));
+ goto done;
+ }
+ if ( ! id_str) {
+ DEBUG(0,("Out of memory\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ xid->id = strtoul(id_str, NULL, 10);
+
+ ret = NT_STATUS_OK;
+done:
+ talloc_free(memctx);
+ return ret;
+}
+/**********************************
+ Set highest id.
+**********************************/
+
+static NTSTATUS idmap_ldap_set_hwm(struct unixid *xid)
+{
+ TALLOC_CTX *ctx;
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ int rc = LDAP_SERVER_DOWN;
+ int count = 0;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ LDAPMod **mods = NULL;
+ char *new_id_str;
+ char *filter = NULL;
+ const char *dn = NULL;
+ const char **attr_list;
+ const char *type;
+
+ /* Only do query if we are online */
+ if (idmap_is_offline()) {
+ return NT_STATUS_FILE_IS_OFFLINE;
+ }
+
+ if ( ! idmap_alloc_ldap) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ctx = talloc_new(idmap_alloc_ldap);
+ if ( ! ctx) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* get type */
+ switch (xid->type) {
+
+ case ID_TYPE_UID:
+ type = get_attr_key2string(idpool_attr_list,
+ LDAP_ATTR_UIDNUMBER);
+ break;
+
+ case ID_TYPE_GID:
+ type = get_attr_key2string(idpool_attr_list,
+ LDAP_ATTR_GIDNUMBER);
+ break;
+
+ default:
+ DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ filter = talloc_asprintf(ctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
+ CHECK_ALLOC_DONE(filter);
+
+ attr_list = get_attr_list(ctx, idpool_attr_list);
+ CHECK_ALLOC_DONE(attr_list);
+
+ rc = smbldap_search(idmap_alloc_ldap->smbldap_state,
+ idmap_alloc_ldap->suffix,
+ LDAP_SCOPE_SUBTREE, filter,
+ attr_list, 0, &result);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("%s object not found\n", LDAP_OBJ_IDPOOL));
+ goto done;
+ }
+
+ talloc_autofree_ldapmsg(ctx, result);
+
+ count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct,
+ result);
+ if (count != 1) {
+ DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL));
+ goto done;
+ }
+
+ entry = ldap_first_entry(idmap_alloc_ldap->smbldap_state->ldap_struct,
+ result);
+
+ dn = smbldap_talloc_dn(ctx,
+ idmap_alloc_ldap->smbldap_state->ldap_struct,
+ entry);
+ if ( ! dn) {
+ goto done;
+ }
+
+ new_id_str = talloc_asprintf(ctx, "%lu", (unsigned long)xid->id);
+ if ( ! new_id_str) {
+ DEBUG(0,("Out of memory\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ smbldap_set_mod(&mods, LDAP_MOD_REPLACE, type, new_id_str);
+
+ if (mods == NULL) {
+ DEBUG(0,("smbldap_set_mod() failed.\n"));
+ goto done;
+ }
+
+ rc = smbldap_modify(idmap_alloc_ldap->smbldap_state, dn, mods);
+
+ ldap_mods_free(mods, True);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(1,("Failed to allocate new %s. "
+ "smbldap_modify() failed.\n", type));
+ goto done;
+ }
+
+ ret = NT_STATUS_OK;
+
+done:
+ talloc_free(ctx);
+ return ret;
+}
+
+/**********************************
+ Close idmap ldap alloc
+**********************************/
+
+static NTSTATUS idmap_ldap_alloc_close(void)
+{
+ if (idmap_alloc_ldap) {
+ smbldap_free_struct(&idmap_alloc_ldap->smbldap_state);
+ DEBUG(5,("The connection to the LDAP server was closed\n"));
+ /* maybe free the results here --metze */
+ TALLOC_FREE(idmap_alloc_ldap);
+ }
+ return NT_STATUS_OK;
+}
+
+
+/**********************************************************************
+ IDMAP MAPPING LDAP BACKEND
+**********************************************************************/
+
+static int idmap_ldap_close_destructor(struct idmap_ldap_context *ctx)
+{
+ smbldap_free_struct(&ctx->smbldap_state);
+ DEBUG(5,("The connection to the LDAP server was closed\n"));
+ /* maybe free the results here --metze */
+
+ return 0;
+}
+
+/********************************
+ Initialise idmap database.
+********************************/
+
+static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom,
+ const char *params)
+{
+ NTSTATUS ret;
+ struct idmap_ldap_context *ctx = NULL;
+ char *config_option = NULL;
+ const char *range = NULL;
+ const char *tmp = NULL;
+
+ /* Only do init if we are online */
+ if (idmap_is_offline()) {
+ return NT_STATUS_FILE_IS_OFFLINE;
+ }
+
+ ctx = TALLOC_ZERO_P(dom, struct idmap_ldap_context);
+ if ( ! ctx) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
+ if ( ! config_option) {
+ DEBUG(0, ("Out of memory!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ /* load ranges */
+ range = lp_parm_const_string(-1, config_option, "range", NULL);
+ if (range && range[0]) {
+ if ((sscanf(range, "%u - %u", &ctx->filter_low_id,
+ &ctx->filter_high_id) != 2) ||
+ (ctx->filter_low_id > ctx->filter_high_id)) {
+ DEBUG(1, ("ERROR: invalid filter range [%s]", range));
+ ctx->filter_low_id = 0;
+ ctx->filter_high_id = 0;
+ }
+ }
+
+ if (params != NULL) {
+ /* assume location is the only parameter */
+ ctx->url = talloc_strdup(ctx, params);
+ } else {
+ tmp = lp_parm_const_string(-1, config_option, "ldap_url", NULL);
+
+ if ( ! tmp) {
+ DEBUG(1, ("ERROR: missing idmap ldap url\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ ctx->url = talloc_strdup(ctx, tmp);
+ }
+ CHECK_ALLOC_DONE(ctx->url);
+
+ tmp = lp_parm_const_string(-1, config_option, "ldap_base_dn", NULL);
+ if ( ! tmp || ! *tmp) {
+ tmp = lp_ldap_idmap_suffix();
+ if ( ! tmp) {
+ DEBUG(1, ("ERROR: missing idmap ldap suffix\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ }
+
+ ctx->suffix = talloc_strdup(ctx, tmp);
+ CHECK_ALLOC_DONE(ctx->suffix);
+
+ ret = smbldap_init(ctx, winbind_event_context(), ctx->url,
+ &ctx->smbldap_state);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", ctx->url));
+ goto done;
+ }
+
+ ret = get_credentials( ctx, ctx->smbldap_state, config_option,
+ dom, &ctx->user_dn );
+ if ( !NT_STATUS_IS_OK(ret) ) {
+ DEBUG(1,("idmap_ldap_db_init: Failed to get connection "
+ "credentials (%s)\n", nt_errstr(ret)));
+ goto done;
+ }
+
+ /* set the destructor on the context, so that resource are properly
+ freed if the contexts is released */
+
+ talloc_set_destructor(ctx, idmap_ldap_close_destructor);
+
+ dom->private_data = ctx;
+
+ talloc_free(config_option);
+ return NT_STATUS_OK;
+
+/*failed */
+done:
+ talloc_free(ctx);
+ return ret;
+}
+
+/* max number of ids requested per batch query */
+#define IDMAP_LDAP_MAX_IDS 30
+
+/**********************************
+ lookup a set of unix ids.
+**********************************/
+
+/* this function searches up to IDMAP_LDAP_MAX_IDS entries
+ * in maps for a match */
+static struct id_map *find_map_by_id(struct id_map **maps,
+ enum id_type type,
+ uint32_t id)
+{
+ int i;
+
+ for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
+ if (maps[i] == NULL) { /* end of the run */
+ return NULL;
+ }
+ if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
+ return maps[i];
+ }
+ }
+
+ return NULL;
+}
+
+static NTSTATUS idmap_ldap_unixids_to_sids(struct idmap_domain *dom,
+ struct id_map **ids)
+{
+ NTSTATUS ret;
+ TALLOC_CTX *memctx;
+ struct idmap_ldap_context *ctx;
+ LDAPMessage *result = NULL;
+ const char *uidNumber;
+ const char *gidNumber;
+ const char **attr_list;
+ char *filter = NULL;
+ bool multi = False;
+ int idx = 0;
+ int bidx = 0;
+ int count;
+ int rc;
+ int i;
+
+ /* Only do query if we are online */
+ if (idmap_is_offline()) {
+ return NT_STATUS_FILE_IS_OFFLINE;
+ }
+
+ ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
+
+ memctx = talloc_new(ctx);
+ if ( ! memctx) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ uidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER);
+ gidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER);
+
+ attr_list = get_attr_list(memctx, sidmap_attr_list);
+
+ if ( ! ids[1]) {
+ /* if we are requested just one mapping use the simple filter */
+
+ filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%lu))",
+ LDAP_OBJ_IDMAP_ENTRY,
+ (ids[0]->xid.type==ID_TYPE_UID)?uidNumber:gidNumber,
+ (unsigned long)ids[0]->xid.id);
+ CHECK_ALLOC_DONE(filter);
+ DEBUG(10, ("Filter: [%s]\n", filter));
+ } else {
+ /* multiple mappings */
+ multi = True;
+ }
+
+again:
+ if (multi) {
+
+ talloc_free(filter);
+ filter = talloc_asprintf(memctx,
+ "(&(objectClass=%s)(|",
+ LDAP_OBJ_IDMAP_ENTRY);
+ CHECK_ALLOC_DONE(filter);
+
+ bidx = idx;
+ for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
+ filter = talloc_asprintf_append_buffer(filter, "(%s=%lu)",
+ (ids[idx]->xid.type==ID_TYPE_UID)?uidNumber:gidNumber,
+ (unsigned long)ids[idx]->xid.id);
+ CHECK_ALLOC_DONE(filter);
+ }
+ filter = talloc_asprintf_append_buffer(filter, "))");
+ CHECK_ALLOC_DONE(filter);
+ DEBUG(10, ("Filter: [%s]\n", filter));
+ } else {
+ bidx = 0;
+ idx = 1;
+ }
+
+ rc = smbldap_search(ctx->smbldap_state, ctx->suffix, LDAP_SCOPE_SUBTREE,
+ filter, attr_list, 0, &result);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(3,("Failure looking up ids (%s)\n", ldap_err2string(rc)));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
+
+ if (count == 0) {
+ DEBUG(10, ("NO SIDs found\n"));
+ }
+
+ for (i = 0; i < count; i++) {
+ LDAPMessage *entry = NULL;
+ char *sidstr = NULL;
+ char *tmp = NULL;
+ enum id_type type;
+ struct id_map *map;
+ uint32_t id;
+
+ if (i == 0) { /* first entry */
+ entry = ldap_first_entry(ctx->smbldap_state->ldap_struct,
+ result);
+ } else { /* following ones */
+ entry = ldap_next_entry(ctx->smbldap_state->ldap_struct,
+ entry);
+ }
+ if ( ! entry) {
+ DEBUG(2, ("ERROR: Unable to fetch ldap entries "
+ "from results\n"));
+ break;
+ }
+
+ /* first check if the SID is present */
+ sidstr = smbldap_talloc_single_attribute(
+ ctx->smbldap_state->ldap_struct,
+ entry, LDAP_ATTRIBUTE_SID, memctx);
+ if ( ! sidstr) { /* no sid, skip entry */
+ DEBUG(2, ("WARNING SID not found on entry\n"));
+ continue;
+ }
+
+ /* now try to see if it is a uid, if not try with a gid
+ * (gid is more common, but in case both uidNumber and
+ * gidNumber are returned the SID is mapped to the uid
+ *not the gid) */
+ type = ID_TYPE_UID;
+ tmp = smbldap_talloc_single_attribute(
+ ctx->smbldap_state->ldap_struct,
+ entry, uidNumber, memctx);
+ if ( ! tmp) {
+ type = ID_TYPE_GID;
+ tmp = smbldap_talloc_single_attribute(
+ ctx->smbldap_state->ldap_struct,
+ entry, gidNumber, memctx);
+ }
+ if ( ! tmp) { /* wow very strange entry, how did it match ? */
+ DEBUG(5, ("Unprobable match on (%s), no uidNumber, "
+ "nor gidNumber returned\n", sidstr));
+ TALLOC_FREE(sidstr);
+ continue;
+ }
+
+ id = strtoul(tmp, NULL, 10);
+ if ((id == 0) ||
+ (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
+ (ctx->filter_high_id && (id > ctx->filter_high_id))) {
+ DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
+ "Filtered!\n", id,
+ ctx->filter_low_id, ctx->filter_high_id));
+ TALLOC_FREE(sidstr);
+ TALLOC_FREE(tmp);
+ continue;
+ }
+ TALLOC_FREE(tmp);
+
+ map = find_map_by_id(&ids[bidx], type, id);
+ if (!map) {
+ DEBUG(2, ("WARNING: couldn't match sid (%s) "
+ "with requested ids\n", sidstr));
+ TALLOC_FREE(sidstr);
+ continue;
+ }
+
+ if ( ! string_to_sid(map->sid, sidstr)) {
+ DEBUG(2, ("ERROR: Invalid SID on entry\n"));
+ TALLOC_FREE(sidstr);
+ continue;
+ }
+ TALLOC_FREE(sidstr);
+
+ /* mapped */
+ map->status = ID_MAPPED;
+
+ DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
+ (unsigned long)map->xid.id, map->xid.type));
+ }
+
+ /* free the ldap results */
+ if (result) {
+ ldap_msgfree(result);
+ result = NULL;
+ }
+
+ if (multi && ids[idx]) { /* still some values to map */
+ goto again;
+ }
+
+ ret = NT_STATUS_OK;
+
+ /* mark all unknwon/expired ones as unmapped */
+ for (i = 0; ids[i]; i++) {
+ if (ids[i]->status != ID_MAPPED)
+ ids[i]->status = ID_UNMAPPED;
+ }
+
+done:
+ talloc_free(memctx);
+ return ret;
+}
+
+/**********************************
+ lookup a set of sids.
+**********************************/
+
+/* this function searches up to IDMAP_LDAP_MAX_IDS entries
+ * in maps for a match */
+static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
+{
+ int i;
+
+ for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
+ if (maps[i] == NULL) { /* end of the run */
+ return NULL;
+ }
+ if (sid_equal(maps[i]->sid, sid)) {
+ return maps[i];
+ }
+ }
+
+ return NULL;
+}
+
+static NTSTATUS idmap_ldap_sids_to_unixids(struct idmap_domain *dom,
+ struct id_map **ids)
+{
+ LDAPMessage *entry = NULL;
+ NTSTATUS ret;
+ TALLOC_CTX *memctx;
+ struct idmap_ldap_context *ctx;
+ LDAPMessage *result = NULL;
+ const char *uidNumber;
+ const char *gidNumber;
+ const char **attr_list;
+ char *filter = NULL;
+ bool multi = False;
+ int idx = 0;
+ int bidx = 0;
+ int count;
+ int rc;
+ int i;
+
+ /* Only do query if we are online */
+ if (idmap_is_offline()) {
+ return NT_STATUS_FILE_IS_OFFLINE;
+ }
+
+ ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
+
+ memctx = talloc_new(ctx);
+ if ( ! memctx) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ uidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER);
+ gidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER);
+
+ attr_list = get_attr_list(memctx, sidmap_attr_list);
+
+ if ( ! ids[1]) {
+ /* if we are requested just one mapping use the simple filter */
+
+ filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%s))",
+ LDAP_OBJ_IDMAP_ENTRY,
+ LDAP_ATTRIBUTE_SID,
+ sid_string_talloc(memctx, ids[0]->sid));
+ CHECK_ALLOC_DONE(filter);
+ DEBUG(10, ("Filter: [%s]\n", filter));
+ } else {
+ /* multiple mappings */
+ multi = True;
+ }
+
+again:
+ if (multi) {
+
+ TALLOC_FREE(filter);
+ filter = talloc_asprintf(memctx,
+ "(&(objectClass=%s)(|",
+ LDAP_OBJ_IDMAP_ENTRY);
+ CHECK_ALLOC_DONE(filter);
+
+ bidx = idx;
+ for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
+ filter = talloc_asprintf_append_buffer(filter, "(%s=%s)",
+ LDAP_ATTRIBUTE_SID,
+ sid_string_talloc(memctx,
+ ids[idx]->sid));
+ CHECK_ALLOC_DONE(filter);
+ }
+ filter = talloc_asprintf_append_buffer(filter, "))");
+ CHECK_ALLOC_DONE(filter);
+ DEBUG(10, ("Filter: [%s]", filter));
+ } else {
+ bidx = 0;
+ idx = 1;
+ }
+
+ rc = smbldap_search(ctx->smbldap_state, ctx->suffix, LDAP_SCOPE_SUBTREE,
+ filter, attr_list, 0, &result);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(3,("Failure looking up sids (%s)\n",
+ ldap_err2string(rc)));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
+
+ if (count == 0) {
+ DEBUG(10, ("NO SIDs found\n"));
+ }
+
+ for (i = 0; i < count; i++) {
+ char *sidstr = NULL;
+ char *tmp = NULL;
+ enum id_type type;
+ struct id_map *map;
+ DOM_SID sid;
+ uint32_t id;
+
+ if (i == 0) { /* first entry */
+ entry = ldap_first_entry(ctx->smbldap_state->ldap_struct,
+ result);
+ } else { /* following ones */
+ entry = ldap_next_entry(ctx->smbldap_state->ldap_struct,
+ entry);
+ }
+ if ( ! entry) {
+ DEBUG(2, ("ERROR: Unable to fetch ldap entries "
+ "from results\n"));
+ break;
+ }
+
+ /* first check if the SID is present */
+ sidstr = smbldap_talloc_single_attribute(
+ ctx->smbldap_state->ldap_struct,
+ entry, LDAP_ATTRIBUTE_SID, memctx);
+ if ( ! sidstr) { /* no sid ??, skip entry */
+ DEBUG(2, ("WARNING SID not found on entry\n"));
+ continue;
+ }
+
+ if ( ! string_to_sid(&sid, sidstr)) {
+ DEBUG(2, ("ERROR: Invalid SID on entry\n"));
+ TALLOC_FREE(sidstr);
+ continue;
+ }
+
+ map = find_map_by_sid(&ids[bidx], &sid);
+ if (!map) {
+ DEBUG(2, ("WARNING: couldn't find entry sid (%s) "
+ "in ids", sidstr));
+ TALLOC_FREE(sidstr);
+ continue;
+ }
+
+ TALLOC_FREE(sidstr);
+
+ /* now try to see if it is a uid, if not try with a gid
+ * (gid is more common, but in case both uidNumber and
+ * gidNumber are returned the SID is mapped to the uid
+ * not the gid) */
+ type = ID_TYPE_UID;
+ tmp = smbldap_talloc_single_attribute(
+ ctx->smbldap_state->ldap_struct,
+ entry, uidNumber, memctx);
+ if ( ! tmp) {
+ type = ID_TYPE_GID;
+ tmp = smbldap_talloc_single_attribute(
+ ctx->smbldap_state->ldap_struct,
+ entry, gidNumber, memctx);
+ }
+ if ( ! tmp) { /* no ids ?? */
+ DEBUG(5, ("no uidNumber, "
+ "nor gidNumber attributes found\n"));
+ continue;
+ }
+
+ id = strtoul(tmp, NULL, 10);
+ if ((id == 0) ||
+ (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
+ (ctx->filter_high_id && (id > ctx->filter_high_id))) {
+ DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
+ "Filtered!\n", id,
+ ctx->filter_low_id, ctx->filter_high_id));
+ TALLOC_FREE(tmp);
+ continue;
+ }
+ TALLOC_FREE(tmp);
+
+ /* mapped */
+ map->xid.type = type;
+ map->xid.id = id;
+ map->status = ID_MAPPED;
+
+ DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
+ (unsigned long)map->xid.id, map->xid.type));
+ }
+
+ /* free the ldap results */
+ if (result) {
+ ldap_msgfree(result);
+ result = NULL;
+ }
+
+ if (multi && ids[idx]) { /* still some values to map */
+ goto again;
+ }
+
+ ret = NT_STATUS_OK;
+
+ /* mark all unknwon/expired ones as unmapped */
+ for (i = 0; ids[i]; i++) {
+ if (ids[i]->status != ID_MAPPED)
+ ids[i]->status = ID_UNMAPPED;
+ }
+
+done:
+ talloc_free(memctx);
+ return ret;
+}
+
+/**********************************
+ set a mapping.
+**********************************/
+
+/* TODO: change this: This function cannot be called to modify a mapping,
+ * only set a new one */
+
+static NTSTATUS idmap_ldap_set_mapping(struct idmap_domain *dom,
+ const struct id_map *map)
+{
+ NTSTATUS ret;
+ TALLOC_CTX *memctx;
+ struct idmap_ldap_context *ctx;
+ LDAPMessage *entry = NULL;
+ LDAPMod **mods = NULL;
+ const char *type;
+ char *id_str;
+ char *sid;
+ char *dn;
+ int rc = -1;
+
+ /* Only do query if we are online */
+ if (idmap_is_offline()) {
+ return NT_STATUS_FILE_IS_OFFLINE;
+ }
+
+ ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
+
+ switch(map->xid.type) {
+ case ID_TYPE_UID:
+ type = get_attr_key2string(sidmap_attr_list,
+ LDAP_ATTR_UIDNUMBER);
+ break;
+
+ case ID_TYPE_GID:
+ type = get_attr_key2string(sidmap_attr_list,
+ LDAP_ATTR_GIDNUMBER);
+ break;
+
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ memctx = talloc_new(ctx);
+ if ( ! memctx) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ id_str = talloc_asprintf(memctx, "%lu", (unsigned long)map->xid.id);
+ CHECK_ALLOC_DONE(id_str);
+
+ sid = talloc_strdup(memctx, sid_string_talloc(memctx, map->sid));
+ CHECK_ALLOC_DONE(sid);
+
+ dn = talloc_asprintf(memctx, "%s=%s,%s",
+ get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
+ sid,
+ ctx->suffix);
+ CHECK_ALLOC_DONE(dn);
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD,
+ "objectClass", LDAP_OBJ_IDMAP_ENTRY);
+
+ smbldap_make_mod(ctx->smbldap_state->ldap_struct,
+ entry, &mods, type, id_str);
+
+ smbldap_make_mod(ctx->smbldap_state->ldap_struct, entry, &mods,
+ get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
+ sid);
+
+ if ( ! mods) {
+ DEBUG(2, ("ERROR: No mods?\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* TODO: remove conflicting mappings! */
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY);
+
+ DEBUG(10, ("Set DN %s (%s -> %s)\n", dn, sid, id_str));
+
+ rc = smbldap_add(ctx->smbldap_state, dn, mods);
+ ldap_mods_free(mods, True);
+
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ ldap_get_option(ctx->smbldap_state->ldap_struct,
+ LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(0,("ldap_set_mapping_internals: Failed to add %s to %lu "
+ "mapping [%s]\n", sid,
+ (unsigned long)map->xid.id, type));
+ DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n",
+ ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
+ if (ld_error) {
+ ldap_memfree(ld_error);
+ }
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to "
+ "%lu [%s]\n", sid, (unsigned long)map->xid.id, type));
+
+ ret = NT_STATUS_OK;
+
+done:
+ talloc_free(memctx);
+ return ret;
+}
+
+/**********************************
+ Close the idmap ldap instance
+**********************************/
+
+static NTSTATUS idmap_ldap_close(struct idmap_domain *dom)
+{
+ struct idmap_ldap_context *ctx;
+
+ if (dom->private_data) {
+ ctx = talloc_get_type(dom->private_data,
+ struct idmap_ldap_context);
+
+ talloc_free(ctx);
+ dom->private_data = NULL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static struct idmap_methods idmap_ldap_methods = {
+
+ .init = idmap_ldap_db_init,
+ .unixids_to_sids = idmap_ldap_unixids_to_sids,
+ .sids_to_unixids = idmap_ldap_sids_to_unixids,
+ .set_mapping = idmap_ldap_set_mapping,
+ .close_fn = idmap_ldap_close
+};
+
+static struct idmap_alloc_methods idmap_ldap_alloc_methods = {
+
+ .init = idmap_ldap_alloc_init,
+ .allocate_id = idmap_ldap_allocate_id,
+ .get_id_hwm = idmap_ldap_get_hwm,
+ .set_id_hwm = idmap_ldap_set_hwm,
+ .close_fn = idmap_ldap_alloc_close,
+ /* .dump_data = TODO */
+};
+
+static NTSTATUS idmap_alloc_ldap_init(void)
+{
+ return smb_register_idmap_alloc(SMB_IDMAP_INTERFACE_VERSION, "ldap",
+ &idmap_ldap_alloc_methods);
+}
+
+NTSTATUS idmap_ldap_init(void);
+NTSTATUS idmap_ldap_init(void)
+{
+ NTSTATUS ret;
+
+ /* FIXME: bad hack to actually register also the alloc_ldap module
+ * without changining configure.in */
+ ret = idmap_alloc_ldap_init();
+ if (! NT_STATUS_IS_OK(ret)) {
+ return ret;
+ }
+ return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap",
+ &idmap_ldap_methods);
+}
+
diff --git a/source3/winbindd/idmap_nss.c b/source3/winbindd/idmap_nss.c
new file mode 100644
index 0000000000..156fdc7cc9
--- /dev/null
+++ b/source3/winbindd/idmap_nss.c
@@ -0,0 +1,217 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ idmap PASSDB backend
+
+ Copyright (C) Simo Sorce 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_IDMAP
+
+/*****************************
+ Initialise idmap database.
+*****************************/
+
+static NTSTATUS idmap_nss_int_init(struct idmap_domain *dom,
+ const char *params)
+{
+ return NT_STATUS_OK;
+}
+
+/**********************************
+ lookup a set of unix ids.
+**********************************/
+
+static NTSTATUS idmap_nss_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
+{
+ TALLOC_CTX *ctx;
+ int i;
+
+ ctx = talloc_new(dom);
+ if ( ! ctx) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; ids[i]; i++) {
+ struct passwd *pw;
+ struct group *gr;
+ const char *name;
+ enum lsa_SidType type;
+ bool ret;
+
+ switch (ids[i]->xid.type) {
+ case ID_TYPE_UID:
+ pw = getpwuid((uid_t)ids[i]->xid.id);
+
+ if (!pw) {
+ ids[i]->status = ID_UNMAPPED;
+ continue;
+ }
+ name = pw->pw_name;
+ break;
+ case ID_TYPE_GID:
+ gr = getgrgid((gid_t)ids[i]->xid.id);
+
+ if (!gr) {
+ ids[i]->status = ID_UNMAPPED;
+ continue;
+ }
+ name = gr->gr_name;
+ break;
+ default: /* ?? */
+ ids[i]->status = ID_UNKNOWN;
+ continue;
+ }
+
+ /* by default calls to winbindd are disabled
+ the following call will not recurse so this is safe */
+ (void)winbind_on();
+ /* Lookup name from PDC using lsa_lookup_names() */
+ ret = winbind_lookup_name(dom->name, name, ids[i]->sid, &type);
+ (void)winbind_off();
+
+ if (!ret) {
+ /* TODO: how do we know if the name is really not mapped,
+ * or something just failed ? */
+ ids[i]->status = ID_UNMAPPED;
+ continue;
+ }
+
+ switch (type) {
+ case SID_NAME_USER:
+ if (ids[i]->xid.type == ID_TYPE_UID) {
+ ids[i]->status = ID_MAPPED;
+ }
+ break;
+
+ case SID_NAME_DOM_GRP:
+ case SID_NAME_ALIAS:
+ case SID_NAME_WKN_GRP:
+ if (ids[i]->xid.type == ID_TYPE_GID) {
+ ids[i]->status = ID_MAPPED;
+ }
+ break;
+
+ default:
+ ids[i]->status = ID_UNKNOWN;
+ break;
+ }
+ }
+
+
+ talloc_free(ctx);
+ return NT_STATUS_OK;
+}
+
+/**********************************
+ lookup a set of sids.
+**********************************/
+
+static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
+{
+ TALLOC_CTX *ctx;
+ int i;
+
+ ctx = talloc_new(dom);
+ if ( ! ctx) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; ids[i]; i++) {
+ struct group *gr;
+ enum lsa_SidType type;
+ const char *dom_name = NULL;
+ const char *name = NULL;
+ bool ret;
+
+ /* by default calls to winbindd are disabled
+ the following call will not recurse so this is safe */
+ (void)winbind_on();
+ ret = winbind_lookup_sid(ctx, ids[i]->sid, &dom_name, &name, &type);
+ (void)winbind_off();
+
+ if (!ret) {
+ /* TODO: how do we know if the name is really not mapped,
+ * or something just failed ? */
+ ids[i]->status = ID_UNMAPPED;
+ continue;
+ }
+
+ switch (type) {
+ case SID_NAME_USER: {
+ struct passwd *pw;
+
+ /* this will find also all lower case name and use username level */
+
+ pw = Get_Pwnam_alloc(talloc_tos(), name);
+ if (pw) {
+ ids[i]->xid.id = pw->pw_uid;
+ ids[i]->xid.type = ID_TYPE_UID;
+ ids[i]->status = ID_MAPPED;
+ }
+ TALLOC_FREE(pw);
+ break;
+ }
+
+ case SID_NAME_DOM_GRP:
+ case SID_NAME_ALIAS:
+ case SID_NAME_WKN_GRP:
+
+ gr = getgrnam(name);
+ if (gr) {
+ ids[i]->xid.id = gr->gr_gid;
+ ids[i]->xid.type = ID_TYPE_GID;
+ ids[i]->status = ID_MAPPED;
+ }
+ break;
+
+ default:
+ ids[i]->status = ID_UNKNOWN;
+ break;
+ }
+ }
+
+ talloc_free(ctx);
+ return NT_STATUS_OK;
+}
+
+/**********************************
+ Close the idmap tdb instance
+**********************************/
+
+static NTSTATUS idmap_nss_close(struct idmap_domain *dom)
+{
+ return NT_STATUS_OK;
+}
+
+static struct idmap_methods nss_methods = {
+
+ .init = idmap_nss_int_init,
+ .unixids_to_sids = idmap_nss_unixids_to_sids,
+ .sids_to_unixids = idmap_nss_sids_to_unixids,
+ .close_fn = idmap_nss_close
+};
+
+NTSTATUS idmap_nss_init(void)
+{
+ return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "nss", &nss_methods);
+}
diff --git a/source3/winbindd/idmap_passdb.c b/source3/winbindd/idmap_passdb.c
new file mode 100644
index 0000000000..4dcf74416c
--- /dev/null
+++ b/source3/winbindd/idmap_passdb.c
@@ -0,0 +1,130 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ idmap PASSDB backend
+
+ Copyright (C) Simo Sorce 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_IDMAP
+
+/*****************************
+ Initialise idmap database.
+*****************************/
+
+static NTSTATUS idmap_pdb_init(struct idmap_domain *dom, const char *params)
+{
+ return NT_STATUS_OK;
+}
+
+/**********************************
+ lookup a set of unix ids.
+**********************************/
+
+static NTSTATUS idmap_pdb_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
+{
+ int i;
+
+ for (i = 0; ids[i]; i++) {
+
+ /* unmapped by default */
+ ids[i]->status = ID_UNMAPPED;
+
+ switch (ids[i]->xid.type) {
+ case ID_TYPE_UID:
+ if (pdb_uid_to_sid((uid_t)ids[i]->xid.id, ids[i]->sid)) {
+ ids[i]->status = ID_MAPPED;
+ }
+ break;
+ case ID_TYPE_GID:
+ if (pdb_gid_to_sid((gid_t)ids[i]->xid.id, ids[i]->sid)) {
+ ids[i]->status = ID_MAPPED;
+ }
+ break;
+ default: /* ?? */
+ ids[i]->status = ID_UNKNOWN;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**********************************
+ lookup a set of sids.
+**********************************/
+
+static NTSTATUS idmap_pdb_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
+{
+ int i;
+
+ for (i = 0; ids[i]; i++) {
+ enum lsa_SidType type;
+ union unid_t id;
+
+ if (pdb_sid_to_id(ids[i]->sid, &id, &type)) {
+ switch (type) {
+ case SID_NAME_USER:
+ ids[i]->xid.id = id.uid;
+ ids[i]->xid.type = ID_TYPE_UID;
+ ids[i]->status = ID_MAPPED;
+ break;
+
+ case SID_NAME_DOM_GRP:
+ case SID_NAME_ALIAS:
+ case SID_NAME_WKN_GRP:
+ ids[i]->xid.id = id.gid;
+ ids[i]->xid.type = ID_TYPE_GID;
+ ids[i]->status = ID_MAPPED;
+ break;
+
+ default: /* ?? */
+ /* make sure it is marked as unmapped */
+ ids[i]->status = ID_UNKNOWN;
+ break;
+ }
+ } else {
+ /* Query Failed */
+ ids[i]->status = ID_UNMAPPED;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**********************************
+ Close the idmap tdb instance
+**********************************/
+
+static NTSTATUS idmap_pdb_close(struct idmap_domain *dom)
+{
+ return NT_STATUS_OK;
+}
+
+static struct idmap_methods passdb_methods = {
+
+ .init = idmap_pdb_init,
+ .unixids_to_sids = idmap_pdb_unixids_to_sids,
+ .sids_to_unixids = idmap_pdb_sids_to_unixids,
+ .close_fn =idmap_pdb_close
+};
+
+NTSTATUS idmap_passdb_init(void)
+{
+ return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "passdb", &passdb_methods);
+}
diff --git a/source3/winbindd/idmap_rid.c b/source3/winbindd/idmap_rid.c
new file mode 100644
index 0000000000..9d1898708c
--- /dev/null
+++ b/source3/winbindd/idmap_rid.c
@@ -0,0 +1,251 @@
+/*
+ * idmap_rid: static map between Active Directory/NT RIDs and RFC 2307 accounts
+ * Copyright (C) Guenther Deschner, 2004
+ * Copyright (C) Sumit Bose, 2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_IDMAP
+
+struct idmap_rid_context {
+ const char *domain_name;
+ uint32_t low_id;
+ uint32_t high_id;
+ uint32_t base_rid;
+};
+
+/******************************************************************************
+ compat params can't be used because of the completely different way
+ we support multiple domains in the new idmap
+ *****************************************************************************/
+
+static NTSTATUS idmap_rid_initialize(struct idmap_domain *dom,
+ const char *params)
+{
+ NTSTATUS ret;
+ struct idmap_rid_context *ctx;
+ char *config_option = NULL;
+ const char *range;
+ uid_t low_uid = 0;
+ uid_t high_uid = 0;
+ gid_t low_gid = 0;
+ gid_t high_gid = 0;
+
+ if ( (ctx = TALLOC_ZERO_P(dom, struct idmap_rid_context)) == NULL ) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
+ if ( ! config_option) {
+ DEBUG(0, ("Out of memory!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ range = lp_parm_const_string(-1, config_option, "range", NULL);
+ if ( !range ||
+ (sscanf(range, "%u - %u", &ctx->low_id, &ctx->high_id) != 2) ||
+ (ctx->low_id > ctx->high_id))
+ {
+ ctx->low_id = 0;
+ ctx->high_id = 0;
+ }
+
+ /* lets see if the range is defined by the old idmap uid/idmap gid */
+ if (!ctx->low_id && !ctx->high_id) {
+ if (lp_idmap_uid(&low_uid, &high_uid)) {
+ ctx->low_id = low_uid;
+ ctx->high_id = high_uid;
+ }
+
+ if (lp_idmap_gid(&low_gid, &high_gid)) {
+ if ((ctx->low_id != low_gid) ||
+ (ctx->high_id != high_uid)) {
+ DEBUG(1, ("ERROR: idmap uid range must match idmap gid range\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto failed;
+ }
+ }
+ }
+
+ if (!ctx->low_id || !ctx->high_id) {
+ DEBUG(1, ("ERROR: Invalid configuration, ID range missing or invalid\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto failed;
+ }
+
+ ctx->base_rid = lp_parm_int(-1, config_option, "base_rid", 0);
+ ctx->domain_name = talloc_strdup( ctx, dom->name );
+
+ dom->private_data = ctx;
+
+ talloc_free(config_option);
+ return NT_STATUS_OK;
+
+failed:
+ talloc_free(ctx);
+ return ret;
+}
+
+static NTSTATUS idmap_rid_id_to_sid(TALLOC_CTX *memctx, struct idmap_rid_context *ctx, struct id_map *map)
+{
+ struct winbindd_domain *domain;
+
+ /* apply filters before checking */
+ if ((map->xid.id < ctx->low_id) || (map->xid.id > ctx->high_id)) {
+ DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
+ map->xid.id, ctx->low_id, ctx->high_id));
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ if ( (domain = find_domain_from_name_noinit(ctx->domain_name)) == NULL ) {
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
+ sid_compose(map->sid, &domain->sid, map->xid.id - ctx->low_id + ctx->base_rid);
+
+ /* We **really** should have some way of validating
+ the SID exists and is the correct type here. But
+ that is a deficiency in the idmap_rid design. */
+
+ map->status = ID_MAPPED;
+
+ return NT_STATUS_OK;
+}
+
+/**********************************
+ Single sid to id lookup function.
+**********************************/
+
+static NTSTATUS idmap_rid_sid_to_id(TALLOC_CTX *memctx, struct idmap_rid_context *ctx, struct id_map *map)
+{
+ uint32_t rid;
+
+ sid_peek_rid(map->sid, &rid);
+ map->xid.id = rid - ctx->base_rid + ctx->low_id;
+
+ /* apply filters before returning result */
+
+ if ((map->xid.id < ctx->low_id) || (map->xid.id > ctx->high_id)) {
+ DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
+ map->xid.id, ctx->low_id, ctx->high_id));
+ map->status = ID_UNMAPPED;
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ /* We **really** should have some way of validating
+ the SID exists and is the correct type here. But
+ that is a deficiency in the idmap_rid design. */
+
+ map->status = ID_MAPPED;
+
+ return NT_STATUS_OK;
+}
+
+/**********************************
+ lookup a set of unix ids.
+**********************************/
+
+static NTSTATUS idmap_rid_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
+{
+ struct idmap_rid_context *ridctx;
+ TALLOC_CTX *ctx;
+ NTSTATUS ret;
+ int i;
+
+ ridctx = talloc_get_type(dom->private_data, struct idmap_rid_context);
+
+ ctx = talloc_new(dom);
+ if ( ! ctx) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; ids[i]; i++) {
+
+ ret = idmap_rid_id_to_sid(ctx, ridctx, ids[i]);
+
+ if (( ! NT_STATUS_IS_OK(ret)) &&
+ ( ! NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED))) {
+ /* some fatal error occurred, log it */
+ DEBUG(3, ("Unexpected error resolving an ID (%d)\n", ids[i]->xid.id));
+ }
+ }
+
+ talloc_free(ctx);
+ return NT_STATUS_OK;
+}
+
+/**********************************
+ lookup a set of sids.
+**********************************/
+
+static NTSTATUS idmap_rid_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
+{
+ struct idmap_rid_context *ridctx;
+ TALLOC_CTX *ctx;
+ NTSTATUS ret;
+ int i;
+
+ ridctx = talloc_get_type(dom->private_data, struct idmap_rid_context);
+
+ ctx = talloc_new(dom);
+ if ( ! ctx) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; ids[i]; i++) {
+
+ ret = idmap_rid_sid_to_id(ctx, ridctx, ids[i]);
+
+ if (( ! NT_STATUS_IS_OK(ret)) &&
+ ( ! NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED))) {
+ /* some fatal error occurred, log it */
+ DEBUG(3, ("Unexpected error resolving a SID (%s)\n",
+ sid_string_dbg(ids[i]->sid)));
+ }
+ }
+
+ talloc_free(ctx);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS idmap_rid_close(struct idmap_domain *dom)
+{
+ if (dom->private_data) {
+ TALLOC_FREE(dom->private_data);
+ }
+ return NT_STATUS_OK;
+}
+
+static struct idmap_methods rid_methods = {
+ .init = idmap_rid_initialize,
+ .unixids_to_sids = idmap_rid_unixids_to_sids,
+ .sids_to_unixids = idmap_rid_sids_to_unixids,
+ .close_fn = idmap_rid_close
+};
+
+NTSTATUS idmap_rid_init(void)
+{
+ return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "rid", &rid_methods);
+}
+
diff --git a/source3/winbindd/idmap_tdb.c b/source3/winbindd/idmap_tdb.c
new file mode 100644
index 0000000000..9e66eed0c8
--- /dev/null
+++ b/source3/winbindd/idmap_tdb.c
@@ -0,0 +1,1179 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ idmap TDB backend
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+ Copyright (C) Jeremy Allison 2006
+ Copyright (C) Simo Sorce 2003-2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_IDMAP
+
+/* High water mark keys */
+#define HWM_GROUP "GROUP HWM"
+#define HWM_USER "USER HWM"
+
+static struct idmap_tdb_state {
+
+ /* User and group id pool */
+ uid_t low_uid, high_uid; /* Range of uids to allocate */
+ gid_t low_gid, high_gid; /* Range of gids to allocate */
+
+} idmap_tdb_state;
+
+/*****************************************************************************
+ For idmap conversion: convert one record to new format
+ Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
+ instead of the SID.
+*****************************************************************************/
+static int convert_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *state)
+{
+ struct winbindd_domain *domain;
+ char *p;
+ DOM_SID sid;
+ uint32 rid;
+ fstring keystr;
+ fstring dom_name;
+ TDB_DATA key2;
+ bool *failed = (bool *)state;
+
+ DEBUG(10,("Converting %s\n", (const char *)key.dptr));
+
+ p = strchr((const char *)key.dptr, '/');
+ if (!p)
+ return 0;
+
+ *p = 0;
+ fstrcpy(dom_name, (const char *)key.dptr);
+ *p++ = '/';
+
+ domain = find_domain_from_name(dom_name);
+ if (domain == NULL) {
+ /* We must delete the old record. */
+ DEBUG(0,("Unable to find domain %s\n", dom_name ));
+ DEBUG(0,("deleting record %s\n", (const char *)key.dptr ));
+
+ if (tdb_delete(tdb, key) != 0) {
+ DEBUG(0, ("Unable to delete record %s\n", (const char *)key.dptr));
+ *failed = True;
+ return -1;
+ }
+
+ return 0;
+ }
+
+ rid = atoi(p);
+
+ sid_copy(&sid, &domain->sid);
+ sid_append_rid(&sid, rid);
+
+ sid_to_fstring(keystr, &sid);
+ key2 = string_term_tdb_data(keystr);
+
+ if (tdb_store(tdb, key2, data, TDB_INSERT) != 0) {
+ DEBUG(0,("Unable to add record %s\n", (const char *)key2.dptr ));
+ *failed = True;
+ return -1;
+ }
+
+ if (tdb_store(tdb, data, key2, TDB_REPLACE) != 0) {
+ DEBUG(0,("Unable to update record %s\n", (const char *)data.dptr ));
+ *failed = True;
+ return -1;
+ }
+
+ if (tdb_delete(tdb, key) != 0) {
+ DEBUG(0,("Unable to delete record %s\n", (const char *)key.dptr ));
+ *failed = True;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ Convert the idmap database from an older version.
+*****************************************************************************/
+
+static bool idmap_tdb_upgrade(const char *idmap_name)
+{
+ int32 vers;
+ bool bigendianheader;
+ bool failed = False;
+ TDB_CONTEXT *idmap_tdb;
+
+ DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n"));
+
+ if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
+ TDB_DEFAULT, O_RDWR,
+ 0600))) {
+ DEBUG(0, ("Unable to open idmap database\n"));
+ return False;
+ }
+
+ bigendianheader = (tdb_get_flags(idmap_tdb) & TDB_BIGENDIAN) ? True : False;
+
+ vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
+
+ if (((vers == -1) && bigendianheader) || (IREV(vers) == IDMAP_VERSION)) {
+ /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
+ /*
+ * high and low records were created on a
+ * big endian machine and will need byte-reversing.
+ */
+
+ int32 wm;
+
+ wm = tdb_fetch_int32(idmap_tdb, HWM_USER);
+
+ if (wm != -1) {
+ wm = IREV(wm);
+ } else {
+ wm = idmap_tdb_state.low_uid;
+ }
+
+ if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) {
+ DEBUG(0, ("Unable to byteswap user hwm in idmap database\n"));
+ tdb_close(idmap_tdb);
+ return False;
+ }
+
+ wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP);
+ if (wm != -1) {
+ wm = IREV(wm);
+ } else {
+ wm = idmap_tdb_state.low_gid;
+ }
+
+ if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) {
+ DEBUG(0, ("Unable to byteswap group hwm in idmap database\n"));
+ tdb_close(idmap_tdb);
+ return False;
+ }
+ }
+
+ /* the old format stored as DOMAIN/rid - now we store the SID direct */
+ tdb_traverse(idmap_tdb, convert_fn, &failed);
+
+ if (failed) {
+ DEBUG(0, ("Problem during conversion\n"));
+ tdb_close(idmap_tdb);
+ return False;
+ }
+
+ if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) {
+ DEBUG(0, ("Unable to dtore idmap version in databse\n"));
+ tdb_close(idmap_tdb);
+ return False;
+ }
+
+ tdb_close(idmap_tdb);
+ return True;
+}
+
+/* WARNING: We can't open a tdb twice inthe same process, for that reason
+ * I'm going to use a hack with open ref counts to open the winbindd_idmap.tdb
+ * only once. We will later decide whether to split the db in multiple files
+ * or come up with a better solution to share them. */
+
+static TDB_CONTEXT *idmap_tdb_common_ctx;
+static int idmap_tdb_open_ref_count = 0;
+
+static NTSTATUS idmap_tdb_open_db(TALLOC_CTX *memctx, TDB_CONTEXT **tdbctx)
+{
+ NTSTATUS ret;
+ TALLOC_CTX *ctx;
+ SMB_STRUCT_STAT stbuf;
+ char *tdbfile = NULL;
+ int32 version;
+ bool tdb_is_new = False;
+
+ if (idmap_tdb_open_ref_count) { /* the tdb has already been opened */
+ idmap_tdb_open_ref_count++;
+ *tdbctx = idmap_tdb_common_ctx;
+ return NT_STATUS_OK;
+ }
+
+ /* use our own context here */
+ ctx = talloc_new(memctx);
+ if (!ctx) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* use the old database if present */
+ tdbfile = talloc_strdup(ctx, state_path("winbindd_idmap.tdb"));
+ if (!tdbfile) {
+ DEBUG(0, ("Out of memory!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if (!file_exist(tdbfile, &stbuf)) {
+ tdb_is_new = True;
+ }
+
+ DEBUG(10,("Opening tdbfile %s\n", tdbfile ));
+
+ /* Open idmap repository */
+ if (!(idmap_tdb_common_ctx = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644))) {
+ DEBUG(0, ("Unable to open idmap database\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (tdb_is_new) {
+ /* the file didn't existed before opening it, let's
+ * store idmap version as nobody else yet opened and
+ * stored it. I do not like this method but didn't
+ * found a way to understand if an opened tdb have
+ * been just created or not --- SSS */
+ tdb_store_int32(idmap_tdb_common_ctx, "IDMAP_VERSION", IDMAP_VERSION);
+ }
+
+ /* check against earlier versions */
+ version = tdb_fetch_int32(idmap_tdb_common_ctx, "IDMAP_VERSION");
+ if (version != IDMAP_VERSION) {
+
+ /* backup_tdb expects the tdb not to be open */
+ tdb_close(idmap_tdb_common_ctx);
+
+ if ( ! idmap_tdb_upgrade(tdbfile)) {
+
+ DEBUG(0, ("Unable to open idmap database, it's in an old formati, and upgrade failed!\n"));
+ ret = NT_STATUS_INTERNAL_DB_ERROR;
+ goto done;
+ }
+
+ /* Re-Open idmap repository */
+ if (!(idmap_tdb_common_ctx = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644))) {
+ DEBUG(0, ("Unable to open idmap database\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ }
+
+ *tdbctx = idmap_tdb_common_ctx;
+ idmap_tdb_open_ref_count++;
+ ret = NT_STATUS_OK;
+
+done:
+ talloc_free(ctx);
+ return ret;
+}
+
+ /* NEVER use tdb_close() except for the conversion routines that are guaranteed
+ * to run only when the database is opened the first time, always use this function. */
+
+bool idmap_tdb_tdb_close(TDB_CONTEXT *tdbctx)
+{
+ if (tdbctx != idmap_tdb_common_ctx) {
+ DEBUG(0, ("ERROR: Invalid tdb context!"));
+ return False;
+ }
+
+ idmap_tdb_open_ref_count--;
+ if (idmap_tdb_open_ref_count) {
+ return True;
+ }
+
+ return tdb_close(idmap_tdb_common_ctx);
+}
+
+/**********************************************************************
+ IDMAP ALLOC TDB BACKEND
+**********************************************************************/
+
+static TDB_CONTEXT *idmap_alloc_tdb;
+
+/**********************************
+ Initialise idmap alloc database.
+**********************************/
+
+static NTSTATUS idmap_tdb_alloc_init( const char *params )
+{
+ NTSTATUS ret;
+ TALLOC_CTX *ctx;
+ uid_t low_uid = 0;
+ uid_t high_uid = 0;
+ gid_t low_gid = 0;
+ gid_t high_gid = 0;
+ uint32_t low_id;
+
+ /* use our own context here */
+ ctx = talloc_new(NULL);
+ if (!ctx) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ret = idmap_tdb_open_db(ctx, &idmap_alloc_tdb);
+ if ( ! NT_STATUS_IS_OK(ret)) {
+ talloc_free(ctx);
+ return ret;
+ }
+
+ talloc_free(ctx);
+
+ /* load ranges */
+
+ if (!lp_idmap_uid(&low_uid, &high_uid)
+ || !lp_idmap_gid(&low_gid, &high_gid)) {
+ DEBUG(1, ("idmap uid or idmap gid missing\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ idmap_tdb_state.low_uid = low_uid;
+ idmap_tdb_state.high_uid = high_uid;
+ idmap_tdb_state.low_gid = low_gid;
+ idmap_tdb_state.high_gid = high_gid;
+
+ if (idmap_tdb_state.high_uid <= idmap_tdb_state.low_uid) {
+ DEBUG(1, ("idmap uid range missing or invalid\n"));
+ DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (idmap_tdb_state.high_gid <= idmap_tdb_state.low_gid) {
+ DEBUG(1, ("idmap gid range missing or invalid\n"));
+ DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (((low_id = tdb_fetch_int32(idmap_alloc_tdb, HWM_USER)) == -1) ||
+ (low_id < idmap_tdb_state.low_uid)) {
+ if (tdb_store_int32(idmap_alloc_tdb, HWM_USER,
+ idmap_tdb_state.low_uid) == -1) {
+ DEBUG(0, ("Unable to initialise user hwm in idmap "
+ "database\n"));
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+ }
+
+ if (((low_id = tdb_fetch_int32(idmap_alloc_tdb, HWM_GROUP)) == -1) ||
+ (low_id < idmap_tdb_state.low_gid)) {
+ if (tdb_store_int32(idmap_alloc_tdb, HWM_GROUP,
+ idmap_tdb_state.low_gid) == -1) {
+ DEBUG(0, ("Unable to initialise group hwm in idmap "
+ "database\n"));
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**********************************
+ Allocate a new id.
+**********************************/
+
+static NTSTATUS idmap_tdb_allocate_id(struct unixid *xid)
+{
+ bool ret;
+ const char *hwmkey;
+ const char *hwmtype;
+ uint32_t high_hwm;
+ uint32_t hwm;
+
+ /* Get current high water mark */
+ switch (xid->type) {
+
+ case ID_TYPE_UID:
+ hwmkey = HWM_USER;
+ hwmtype = "UID";
+ high_hwm = idmap_tdb_state.high_uid;
+ break;
+
+ case ID_TYPE_GID:
+ hwmkey = HWM_GROUP;
+ hwmtype = "GID";
+ high_hwm = idmap_tdb_state.high_gid;
+ break;
+
+ default:
+ DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if ((hwm = tdb_fetch_int32(idmap_alloc_tdb, hwmkey)) == -1) {
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ /* check it is in the range */
+ if (hwm > high_hwm) {
+ DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n",
+ hwmtype, (unsigned long)high_hwm));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* fetch a new id and increment it */
+ ret = tdb_change_uint32_atomic(idmap_alloc_tdb, hwmkey, &hwm, 1);
+ if (!ret) {
+ DEBUG(1, ("Fatal error while fetching a new %s value\n!", hwmtype));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* recheck it is in the range */
+ if (hwm > high_hwm) {
+ DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n",
+ hwmtype, (unsigned long)high_hwm));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ xid->id = hwm;
+ DEBUG(10,("New %s = %d\n", hwmtype, hwm));
+
+ return NT_STATUS_OK;
+}
+
+/**********************************
+ Get current highest id.
+**********************************/
+
+static NTSTATUS idmap_tdb_get_hwm(struct unixid *xid)
+{
+ const char *hwmkey;
+ const char *hwmtype;
+ uint32_t hwm;
+ uint32_t high_hwm;
+
+ /* Get current high water mark */
+ switch (xid->type) {
+
+ case ID_TYPE_UID:
+ hwmkey = HWM_USER;
+ hwmtype = "UID";
+ high_hwm = idmap_tdb_state.high_uid;
+ break;
+
+ case ID_TYPE_GID:
+ hwmkey = HWM_GROUP;
+ hwmtype = "GID";
+ high_hwm = idmap_tdb_state.high_gid;
+ break;
+
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if ((hwm = tdb_fetch_int32(idmap_alloc_tdb, hwmkey)) == -1) {
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ xid->id = hwm;
+
+ /* Warn if it is out of range */
+ if (hwm >= high_hwm) {
+ DEBUG(0, ("Warning: %s range full!! (max: %lu)\n",
+ hwmtype, (unsigned long)high_hwm));
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**********************************
+ Set high id.
+**********************************/
+
+static NTSTATUS idmap_tdb_set_hwm(struct unixid *xid)
+{
+ const char *hwmkey;
+ const char *hwmtype;
+ uint32_t hwm;
+ uint32_t high_hwm;
+
+ /* Get current high water mark */
+ switch (xid->type) {
+
+ case ID_TYPE_UID:
+ hwmkey = HWM_USER;
+ hwmtype = "UID";
+ high_hwm = idmap_tdb_state.high_uid;
+ break;
+
+ case ID_TYPE_GID:
+ hwmkey = HWM_GROUP;
+ hwmtype = "GID";
+ high_hwm = idmap_tdb_state.high_gid;
+ break;
+
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ hwm = xid->id;
+
+ if ((hwm = tdb_store_int32(idmap_alloc_tdb, hwmkey, hwm)) == -1) {
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ /* Warn if it is out of range */
+ if (hwm >= high_hwm) {
+ DEBUG(0, ("Warning: %s range full!! (max: %lu)\n",
+ hwmtype, (unsigned long)high_hwm));
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**********************************
+ Close the alloc tdb
+**********************************/
+
+static NTSTATUS idmap_tdb_alloc_close(void)
+{
+ if (idmap_alloc_tdb) {
+ if (idmap_tdb_tdb_close(idmap_alloc_tdb) == 0) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ IDMAP MAPPING TDB BACKEND
+**********************************************************************/
+
+struct idmap_tdb_context {
+ TDB_CONTEXT *tdb;
+ uint32_t filter_low_id;
+ uint32_t filter_high_id;
+};
+
+/*****************************
+ Initialise idmap database.
+*****************************/
+
+static NTSTATUS idmap_tdb_db_init(struct idmap_domain *dom, const char *params)
+{
+ NTSTATUS ret;
+ struct idmap_tdb_context *ctx;
+ char *config_option = NULL;
+ const char *range;
+
+ ctx = talloc(dom, struct idmap_tdb_context);
+ if ( ! ctx) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
+ if ( ! config_option) {
+ DEBUG(0, ("Out of memory!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ ret = idmap_tdb_open_db(ctx, &ctx->tdb);
+ if ( ! NT_STATUS_IS_OK(ret)) {
+ goto failed;
+ }
+
+ range = lp_parm_const_string(-1, config_option, "range", NULL);
+ if (( ! range) ||
+ (sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2) ||
+ (ctx->filter_low_id > ctx->filter_high_id)) {
+ ctx->filter_low_id = 0;
+ ctx->filter_high_id = 0;
+ }
+
+ dom->private_data = ctx;
+
+ talloc_free(config_option);
+ return NT_STATUS_OK;
+
+failed:
+ talloc_free(ctx);
+ return ret;
+}
+
+/**********************************
+ Single id to sid lookup function.
+**********************************/
+
+static NTSTATUS idmap_tdb_id_to_sid(struct idmap_tdb_context *ctx, struct id_map *map)
+{
+ NTSTATUS ret;
+ TDB_DATA data;
+ char *keystr;
+
+ if (!ctx || !map) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* apply filters before checking */
+ if ((ctx->filter_low_id && (map->xid.id < ctx->filter_low_id)) ||
+ (ctx->filter_high_id && (map->xid.id > ctx->filter_high_id))) {
+ DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
+ map->xid.id, ctx->filter_low_id, ctx->filter_high_id));
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ switch (map->xid.type) {
+
+ case ID_TYPE_UID:
+ keystr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
+ break;
+
+ case ID_TYPE_GID:
+ keystr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
+ break;
+
+ default:
+ DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* final SAFE_FREE safe */
+ data.dptr = NULL;
+
+ if (keystr == NULL) {
+ DEBUG(0, ("Out of memory!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ DEBUG(10,("Fetching record %s\n", keystr));
+
+ /* Check if the mapping exists */
+ data = tdb_fetch_bystring(ctx->tdb, keystr);
+
+ if (!data.dptr) {
+ DEBUG(10,("Record %s not found\n", keystr));
+ ret = NT_STATUS_NONE_MAPPED;
+ goto done;
+ }
+
+ if (!string_to_sid(map->sid, (const char *)data.dptr)) {
+ DEBUG(10,("INVALID SID (%s) in record %s\n",
+ (const char *)data.dptr, keystr));
+ ret = NT_STATUS_INTERNAL_DB_ERROR;
+ goto done;
+ }
+
+ DEBUG(10,("Found record %s -> %s\n", keystr, (const char *)data.dptr));
+ ret = NT_STATUS_OK;
+
+done:
+ SAFE_FREE(data.dptr);
+ talloc_free(keystr);
+ return ret;
+}
+
+/**********************************
+ Single sid to id lookup function.
+**********************************/
+
+static NTSTATUS idmap_tdb_sid_to_id(struct idmap_tdb_context *ctx, struct id_map *map)
+{
+ NTSTATUS ret;
+ TDB_DATA data;
+ char *keystr;
+ unsigned long rec_id = 0;
+ fstring tmp;
+
+ if ((keystr = talloc_asprintf(
+ ctx, "%s", sid_to_fstring(tmp, map->sid))) == NULL) {
+ DEBUG(0, ("Out of memory!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ DEBUG(10,("Fetching record %s\n", keystr));
+
+ /* Check if sid is present in database */
+ data = tdb_fetch_bystring(ctx->tdb, keystr);
+ if (!data.dptr) {
+ DEBUG(10,("Record %s not found\n", keystr));
+ ret = NT_STATUS_NONE_MAPPED;
+ goto done;
+ }
+
+ /* What type of record is this ? */
+ if (sscanf((const char *)data.dptr, "UID %lu", &rec_id) == 1) { /* Try a UID record. */
+ map->xid.id = rec_id;
+ map->xid.type = ID_TYPE_UID;
+ DEBUG(10,("Found uid record %s -> %s \n", keystr, (const char *)data.dptr ));
+ ret = NT_STATUS_OK;
+
+ } else if (sscanf((const char *)data.dptr, "GID %lu", &rec_id) == 1) { /* Try a GID record. */
+ map->xid.id = rec_id;
+ map->xid.type = ID_TYPE_GID;
+ DEBUG(10,("Found gid record %s -> %s \n", keystr, (const char *)data.dptr ));
+ ret = NT_STATUS_OK;
+
+ } else { /* Unknown record type ! */
+ DEBUG(2, ("Found INVALID record %s -> %s\n", keystr, (const char *)data.dptr));
+ ret = NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ SAFE_FREE(data.dptr);
+
+ /* apply filters before returning result */
+ if ((ctx->filter_low_id && (map->xid.id < ctx->filter_low_id)) ||
+ (ctx->filter_high_id && (map->xid.id > ctx->filter_high_id))) {
+ DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
+ map->xid.id, ctx->filter_low_id, ctx->filter_high_id));
+ ret = NT_STATUS_NONE_MAPPED;
+ }
+
+done:
+ talloc_free(keystr);
+ return ret;
+}
+
+/**********************************
+ lookup a set of unix ids.
+**********************************/
+
+static NTSTATUS idmap_tdb_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
+{
+ struct idmap_tdb_context *ctx;
+ NTSTATUS ret;
+ int i;
+
+ ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
+
+ for (i = 0; ids[i]; i++) {
+ ret = idmap_tdb_id_to_sid(ctx, ids[i]);
+ if ( ! NT_STATUS_IS_OK(ret)) {
+
+ /* if it is just a failed mapping continue */
+ if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
+
+ /* make sure it is marked as unmapped */
+ ids[i]->status = ID_UNMAPPED;
+ continue;
+ }
+
+ /* some fatal error occurred, return immediately */
+ goto done;
+ }
+
+ /* all ok, id is mapped */
+ ids[i]->status = ID_MAPPED;
+ }
+
+ ret = NT_STATUS_OK;
+
+done:
+ return ret;
+}
+
+/**********************************
+ lookup a set of sids.
+**********************************/
+
+static NTSTATUS idmap_tdb_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
+{
+ struct idmap_tdb_context *ctx;
+ NTSTATUS ret;
+ int i;
+
+ ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
+
+ for (i = 0; ids[i]; i++) {
+ ret = idmap_tdb_sid_to_id(ctx, ids[i]);
+ if ( ! NT_STATUS_IS_OK(ret)) {
+
+ /* if it is just a failed mapping continue */
+ if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
+
+ /* make sure it is marked as unmapped */
+ ids[i]->status = ID_UNMAPPED;
+ continue;
+ }
+
+ /* some fatal error occurred, return immediately */
+ goto done;
+ }
+
+ /* all ok, id is mapped */
+ ids[i]->status = ID_MAPPED;
+ }
+
+ ret = NT_STATUS_OK;
+
+done:
+ return ret;
+}
+
+/**********************************
+ set a mapping.
+**********************************/
+
+static NTSTATUS idmap_tdb_set_mapping(struct idmap_domain *dom, const struct id_map *map)
+{
+ struct idmap_tdb_context *ctx;
+ NTSTATUS ret;
+ TDB_DATA ksid, kid, data;
+ char *ksidstr, *kidstr;
+ fstring tmp;
+
+ if (!map || !map->sid) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ksidstr = kidstr = NULL;
+ data.dptr = NULL;
+
+ /* TODO: should we filter a set_mapping using low/high filters ? */
+
+ ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
+
+ switch (map->xid.type) {
+
+ case ID_TYPE_UID:
+ kidstr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
+ break;
+
+ case ID_TYPE_GID:
+ kidstr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
+ break;
+
+ default:
+ DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (kidstr == NULL) {
+ DEBUG(0, ("ERROR: Out of memory!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if ((ksidstr = talloc_asprintf(
+ ctx, "%s", sid_to_fstring(tmp, map->sid))) == NULL) {
+ DEBUG(0, ("Out of memory!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ DEBUG(10, ("Storing %s <-> %s map\n", ksidstr, kidstr));
+ kid = string_term_tdb_data(kidstr);
+ ksid = string_term_tdb_data(ksidstr);
+
+ /* *DELETE* previous mappings if any.
+ * This is done both SID and [U|G]ID passed in */
+
+ /* Lock the record for this SID. */
+ if (tdb_chainlock(ctx->tdb, ksid) != 0) {
+ DEBUG(10,("Failed to lock record %s. Error %s\n",
+ ksidstr, tdb_errorstr(ctx->tdb) ));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ data = tdb_fetch(ctx->tdb, ksid);
+ if (data.dptr) {
+ DEBUG(10, ("Deleting existing mapping %s <-> %s\n", (const char *)data.dptr, ksidstr ));
+ tdb_delete(ctx->tdb, data);
+ tdb_delete(ctx->tdb, ksid);
+ SAFE_FREE(data.dptr);
+ }
+
+ data = tdb_fetch(ctx->tdb, kid);
+ if (data.dptr) {
+ DEBUG(10,("Deleting existing mapping %s <-> %s\n", (const char *)data.dptr, kidstr ));
+ tdb_delete(ctx->tdb, data);
+ tdb_delete(ctx->tdb, kid);
+ SAFE_FREE(data.dptr);
+ }
+
+ if (tdb_store(ctx->tdb, ksid, kid, TDB_INSERT) == -1) {
+ DEBUG(0, ("Error storing SID -> ID: %s\n", tdb_errorstr(ctx->tdb)));
+ tdb_chainunlock(ctx->tdb, ksid);
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ if (tdb_store(ctx->tdb, kid, ksid, TDB_INSERT) == -1) {
+ DEBUG(0, ("Error stroing ID -> SID: %s\n", tdb_errorstr(ctx->tdb)));
+ /* try to remove the previous stored SID -> ID map */
+ tdb_delete(ctx->tdb, ksid);
+ tdb_chainunlock(ctx->tdb, ksid);
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ tdb_chainunlock(ctx->tdb, ksid);
+ DEBUG(10,("Stored %s <-> %s\n", ksidstr, kidstr));
+ ret = NT_STATUS_OK;
+
+done:
+ talloc_free(ksidstr);
+ talloc_free(kidstr);
+ SAFE_FREE(data.dptr);
+ return ret;
+}
+
+/**********************************
+ remove a mapping.
+**********************************/
+
+static NTSTATUS idmap_tdb_remove_mapping(struct idmap_domain *dom, const struct id_map *map)
+{
+ struct idmap_tdb_context *ctx;
+ NTSTATUS ret;
+ TDB_DATA ksid, kid, data;
+ char *ksidstr, *kidstr;
+ fstring tmp;
+
+ if (!map || !map->sid) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ksidstr = kidstr = NULL;
+ data.dptr = NULL;
+
+ /* TODO: should we filter a remove_mapping using low/high filters ? */
+
+ ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
+
+ switch (map->xid.type) {
+
+ case ID_TYPE_UID:
+ kidstr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
+ break;
+
+ case ID_TYPE_GID:
+ kidstr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
+ break;
+
+ default:
+ DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (kidstr == NULL) {
+ DEBUG(0, ("ERROR: Out of memory!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if ((ksidstr = talloc_asprintf(
+ ctx, "%s", sid_to_fstring(tmp, map->sid))) == NULL) {
+ DEBUG(0, ("Out of memory!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ DEBUG(10, ("Checking %s <-> %s map\n", ksidstr, kidstr));
+ ksid = string_term_tdb_data(ksidstr);
+ kid = string_term_tdb_data(kidstr);
+
+ /* Lock the record for this SID. */
+ if (tdb_chainlock(ctx->tdb, ksid) != 0) {
+ DEBUG(10,("Failed to lock record %s. Error %s\n",
+ ksidstr, tdb_errorstr(ctx->tdb) ));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* Check if sid is present in database */
+ data = tdb_fetch(ctx->tdb, ksid);
+ if (!data.dptr) {
+ DEBUG(10,("Record %s not found\n", ksidstr));
+ tdb_chainunlock(ctx->tdb, ksid);
+ ret = NT_STATUS_NONE_MAPPED;
+ goto done;
+ }
+
+ /* Check if sid is mapped to the specified ID */
+ if ((data.dsize != kid.dsize) ||
+ (memcmp(data.dptr, kid.dptr, data.dsize) != 0)) {
+ DEBUG(10,("Specified SID does not map to specified ID\n"));
+ DEBUGADD(10,("Actual mapping is %s -> %s\n", ksidstr, (const char *)data.dptr));
+ tdb_chainunlock(ctx->tdb, ksid);
+ ret = NT_STATUS_NONE_MAPPED;
+ goto done;
+ }
+
+ DEBUG(10, ("Removing %s <-> %s map\n", ksidstr, kidstr));
+
+ /* Delete previous mappings. */
+
+ DEBUG(10, ("Deleting existing mapping %s -> %s\n", ksidstr, kidstr ));
+ tdb_delete(ctx->tdb, ksid);
+
+ DEBUG(10,("Deleting existing mapping %s -> %s\n", kidstr, ksidstr ));
+ tdb_delete(ctx->tdb, kid);
+
+ tdb_chainunlock(ctx->tdb, ksid);
+ ret = NT_STATUS_OK;
+
+done:
+ talloc_free(ksidstr);
+ talloc_free(kidstr);
+ SAFE_FREE(data.dptr);
+ return ret;
+}
+
+/**********************************
+ Close the idmap tdb instance
+**********************************/
+
+static NTSTATUS idmap_tdb_close(struct idmap_domain *dom)
+{
+ struct idmap_tdb_context *ctx;
+
+ if (dom->private_data) {
+ ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
+
+ if (idmap_tdb_tdb_close(ctx->tdb) == 0) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
+struct dump_data {
+ TALLOC_CTX *memctx;
+ struct id_map **maps;
+ int *num_maps;
+ NTSTATUS ret;
+};
+
+static int idmap_tdb_dump_one_entry(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value, void *pdata)
+{
+ struct dump_data *data = talloc_get_type(pdata, struct dump_data);
+ struct id_map *maps;
+ int num_maps = *data->num_maps;
+
+ /* ignore any record but the ones with a SID as key */
+ if (strncmp((const char *)key.dptr, "S-", 2) == 0) {
+
+ maps = talloc_realloc(NULL, *data->maps, struct id_map, num_maps+1);
+ if ( ! maps) {
+ DEBUG(0, ("Out of memory!\n"));
+ data->ret = NT_STATUS_NO_MEMORY;
+ return -1;
+ }
+ *data->maps = maps;
+ maps[num_maps].sid = talloc(maps, DOM_SID);
+ if ( ! maps[num_maps].sid) {
+ DEBUG(0, ("Out of memory!\n"));
+ data->ret = NT_STATUS_NO_MEMORY;
+ return -1;
+ }
+
+ if (!string_to_sid(maps[num_maps].sid, (const char *)key.dptr)) {
+ DEBUG(10,("INVALID record %s\n", (const char *)key.dptr));
+ /* continue even with errors */
+ return 0;
+ }
+
+ /* Try a UID record. */
+ if (sscanf((const char *)value.dptr, "UID %u", &(maps[num_maps].xid.id)) == 1) {
+ maps[num_maps].xid.type = ID_TYPE_UID;
+ maps[num_maps].status = ID_MAPPED;
+ *data->num_maps = num_maps + 1;
+
+ /* Try a GID record. */
+ } else
+ if (sscanf((const char *)value.dptr, "GID %u", &(maps[num_maps].xid.id)) == 1) {
+ maps[num_maps].xid.type = ID_TYPE_GID;
+ maps[num_maps].status = ID_MAPPED;
+ *data->num_maps = num_maps + 1;
+
+ /* Unknown record type ! */
+ } else {
+ maps[num_maps].status = ID_UNKNOWN;
+ DEBUG(2, ("Found INVALID record %s -> %s\n",
+ (const char *)key.dptr, (const char *)value.dptr));
+ /* do not increment num_maps */
+ }
+ }
+
+ return 0;
+}
+
+/**********************************
+ Dump all mappings out
+**********************************/
+
+static NTSTATUS idmap_tdb_dump_data(struct idmap_domain *dom, struct id_map **maps, int *num_maps)
+{
+ struct idmap_tdb_context *ctx;
+ struct dump_data *data;
+ NTSTATUS ret = NT_STATUS_OK;
+
+ ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
+
+ data = TALLOC_ZERO_P(ctx, struct dump_data);
+ if ( ! data) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ data->maps = maps;
+ data->num_maps = num_maps;
+ data->ret = NT_STATUS_OK;
+
+ tdb_traverse(ctx->tdb, idmap_tdb_dump_one_entry, data);
+
+ if ( ! NT_STATUS_IS_OK(data->ret)) {
+ ret = data->ret;
+ }
+
+ talloc_free(data);
+ return ret;
+}
+
+static struct idmap_methods db_methods = {
+
+ .init = idmap_tdb_db_init,
+ .unixids_to_sids = idmap_tdb_unixids_to_sids,
+ .sids_to_unixids = idmap_tdb_sids_to_unixids,
+ .set_mapping = idmap_tdb_set_mapping,
+ .remove_mapping = idmap_tdb_remove_mapping,
+ .dump_data = idmap_tdb_dump_data,
+ .close_fn = idmap_tdb_close
+};
+
+static struct idmap_alloc_methods db_alloc_methods = {
+
+ .init = idmap_tdb_alloc_init,
+ .allocate_id = idmap_tdb_allocate_id,
+ .get_id_hwm = idmap_tdb_get_hwm,
+ .set_id_hwm = idmap_tdb_set_hwm,
+ .close_fn = idmap_tdb_alloc_close
+};
+
+NTSTATUS idmap_alloc_tdb_init(void)
+{
+ return smb_register_idmap_alloc(SMB_IDMAP_INTERFACE_VERSION, "tdb", &db_alloc_methods);
+}
+
+NTSTATUS idmap_tdb_init(void)
+{
+ NTSTATUS ret;
+
+ DEBUG(10, ("calling idmap_tdb_init\n"));
+
+ /* FIXME: bad hack to actually register also the alloc_tdb module without changining configure.in */
+ ret = idmap_alloc_tdb_init();
+ if (! NT_STATUS_IS_OK(ret)) {
+ return ret;
+ }
+ return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "tdb", &db_methods);
+}
diff --git a/source3/winbindd/idmap_tdb2.c b/source3/winbindd/idmap_tdb2.c
new file mode 100644
index 0000000000..3066db6f3b
--- /dev/null
+++ b/source3/winbindd/idmap_tdb2.c
@@ -0,0 +1,856 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ idmap TDB2 backend, used for clustered Samba setups.
+
+ This uses dbwrap to access tdb files. The location can be set
+ using tdb:idmap2.tdb =" in smb.conf
+
+ Copyright (C) Andrew Tridgell 2007
+
+ This is heavily based upon idmap_tdb.c, which is:
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+ Copyright (C) Jeremy Allison 2006
+ Copyright (C) Simo Sorce 2003-2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_IDMAP
+
+/* High water mark keys */
+#define HWM_GROUP "GROUP HWM"
+#define HWM_USER "USER HWM"
+
+static struct idmap_tdb2_state {
+ /* User and group id pool */
+ uid_t low_uid, high_uid; /* Range of uids to allocate */
+ gid_t low_gid, high_gid; /* Range of gids to allocate */
+ const char *idmap_script;
+} idmap_tdb2_state;
+
+
+
+/* handle to the permanent tdb */
+static struct db_context *idmap_tdb2;
+
+static NTSTATUS idmap_tdb2_alloc_load(void);
+
+/*
+ open the permanent tdb
+ */
+static NTSTATUS idmap_tdb2_open_db(void)
+{
+ char *db_path;
+
+ if (idmap_tdb2) {
+ /* its already open */
+ return NT_STATUS_OK;
+ }
+
+ db_path = lp_parm_talloc_string(-1, "tdb", "idmap2.tdb", NULL);
+ if (db_path == NULL) {
+ /* fall back to the private directory, which, despite
+ its name, is usually on shared storage */
+ db_path = talloc_asprintf(NULL, "%s/idmap2.tdb", lp_private_dir());
+ }
+ NT_STATUS_HAVE_NO_MEMORY(db_path);
+
+ /* Open idmap repository */
+ idmap_tdb2 = db_open(NULL, db_path, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0644);
+ TALLOC_FREE(db_path);
+
+ if (idmap_tdb2 == NULL) {
+ DEBUG(0, ("Unable to open idmap_tdb2 database '%s'\n",
+ db_path));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* load the ranges and high/low water marks */
+ return idmap_tdb2_alloc_load();
+}
+
+
+/*
+ load the idmap allocation ranges and high/low water marks
+*/
+static NTSTATUS idmap_tdb2_alloc_load(void)
+{
+ const char *range;
+ uid_t low_uid = 0;
+ uid_t high_uid = 0;
+ gid_t low_gid = 0;
+ gid_t high_gid = 0;
+ uint32 low_id, high_id;
+
+ /* see if a idmap script is configured */
+ idmap_tdb2_state.idmap_script = lp_parm_const_string(-1, "idmap",
+ "script", NULL);
+
+ if (idmap_tdb2_state.idmap_script) {
+ DEBUG(1, ("using idmap script '%s'\n",
+ idmap_tdb2_state.idmap_script));
+ }
+
+ /* load ranges */
+
+ /* Create high water marks for group and user id */
+ if (!lp_idmap_uid(&low_uid, &high_uid)
+ || !lp_idmap_gid(&low_gid, &high_gid)) {
+ DEBUG(1, ("idmap uid or idmap gid missing\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ idmap_tdb2_state.low_uid = low_uid;
+ idmap_tdb2_state.high_uid = high_uid;
+ idmap_tdb2_state.low_gid = low_gid;
+ idmap_tdb2_state.high_gid = high_gid;
+
+ if (idmap_tdb2_state.high_uid <= idmap_tdb2_state.low_uid) {
+ DEBUG(1, ("idmap uid range missing or invalid\n"));
+ DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (((low_id = dbwrap_fetch_int32(idmap_tdb2,
+ HWM_USER)) == -1) ||
+ (low_id < idmap_tdb2_state.low_uid)) {
+ if (!NT_STATUS_IS_OK(dbwrap_trans_store_int32(
+ idmap_tdb2, HWM_USER,
+ idmap_tdb2_state.low_uid))) {
+ DEBUG(0, ("Unable to initialise user hwm in idmap "
+ "database\n"));
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+ }
+
+ if (idmap_tdb2_state.high_gid <= idmap_tdb2_state.low_gid) {
+ DEBUG(1, ("idmap gid range missing or invalid\n"));
+ DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (((low_id = dbwrap_fetch_int32(idmap_tdb2,
+ HWM_GROUP)) == -1) ||
+ (low_id < idmap_tdb2_state.low_gid)) {
+ if (!NT_STATUS_IS_OK(dbwrap_trans_store_int32(
+ idmap_tdb2, HWM_GROUP,
+ idmap_tdb2_state.low_gid))) {
+ DEBUG(0, ("Unable to initialise group hwm in idmap "
+ "database\n"));
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ Initialise idmap alloc database.
+*/
+static NTSTATUS idmap_tdb2_alloc_init(const char *params)
+{
+ /* nothing to do - we want to avoid opening the permanent
+ database if possible. Instead we load the params when we
+ first need it. */
+ return NT_STATUS_OK;
+}
+
+
+/*
+ Allocate a new id.
+*/
+static NTSTATUS idmap_tdb2_allocate_id(struct unixid *xid)
+{
+ bool ret;
+ const char *hwmkey;
+ const char *hwmtype;
+ uint32_t high_hwm;
+ uint32_t hwm;
+ int res;
+
+ /* Get current high water mark */
+ switch (xid->type) {
+
+ case ID_TYPE_UID:
+ hwmkey = HWM_USER;
+ hwmtype = "UID";
+ high_hwm = idmap_tdb2_state.high_uid;
+ break;
+
+ case ID_TYPE_GID:
+ hwmkey = HWM_GROUP;
+ hwmtype = "GID";
+ high_hwm = idmap_tdb2_state.high_gid;
+ break;
+
+ default:
+ DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ res = idmap_tdb2->transaction_start(idmap_tdb2);
+ if (res != 0) {
+ DEBUG(1,(__location__ " Failed to start transaction\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if ((hwm = dbwrap_fetch_int32(idmap_tdb2, hwmkey)) == -1) {
+ idmap_tdb2->transaction_cancel(idmap_tdb2);
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ /* check it is in the range */
+ if (hwm > high_hwm) {
+ DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n",
+ hwmtype, (unsigned long)high_hwm));
+ idmap_tdb2->transaction_cancel(idmap_tdb2);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* fetch a new id and increment it */
+ ret = dbwrap_change_uint32_atomic(idmap_tdb2, hwmkey, &hwm, 1);
+ if (ret == -1) {
+ DEBUG(1, ("Fatal error while fetching a new %s value\n!", hwmtype));
+ idmap_tdb2->transaction_cancel(idmap_tdb2);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* recheck it is in the range */
+ if (hwm > high_hwm) {
+ DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n",
+ hwmtype, (unsigned long)high_hwm));
+ idmap_tdb2->transaction_cancel(idmap_tdb2);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ res = idmap_tdb2->transaction_commit(idmap_tdb2);
+ if (res != 0) {
+ DEBUG(1,(__location__ " Failed to commit transaction\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ xid->id = hwm;
+ DEBUG(10,("New %s = %d\n", hwmtype, hwm));
+
+ return NT_STATUS_OK;
+}
+
+/*
+ Get current highest id.
+*/
+static NTSTATUS idmap_tdb2_get_hwm(struct unixid *xid)
+{
+ const char *hwmkey;
+ const char *hwmtype;
+ uint32_t hwm;
+ uint32_t high_hwm;
+
+ /* Get current high water mark */
+ switch (xid->type) {
+
+ case ID_TYPE_UID:
+ hwmkey = HWM_USER;
+ hwmtype = "UID";
+ high_hwm = idmap_tdb2_state.high_uid;
+ break;
+
+ case ID_TYPE_GID:
+ hwmkey = HWM_GROUP;
+ hwmtype = "GID";
+ high_hwm = idmap_tdb2_state.high_gid;
+ break;
+
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if ((hwm = dbwrap_fetch_int32(idmap_tdb2, hwmkey)) == -1) {
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ xid->id = hwm;
+
+ /* Warn if it is out of range */
+ if (hwm >= high_hwm) {
+ DEBUG(0, ("Warning: %s range full!! (max: %lu)\n",
+ hwmtype, (unsigned long)high_hwm));
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ Set high id.
+*/
+static NTSTATUS idmap_tdb2_set_hwm(struct unixid *xid)
+{
+ /* not supported, or we would invalidate the cache tdb on
+ other nodes */
+ DEBUG(0,("idmap_tdb2_set_hwm not supported\n"));
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+/*
+ Close the alloc tdb
+*/
+static NTSTATUS idmap_tdb2_alloc_close(void)
+{
+ /* don't actually close it */
+ return NT_STATUS_OK;
+}
+
+/*
+ IDMAP MAPPING TDB BACKEND
+*/
+struct idmap_tdb2_context {
+ uint32_t filter_low_id;
+ uint32_t filter_high_id;
+};
+
+/*
+ Initialise idmap database.
+*/
+static NTSTATUS idmap_tdb2_db_init(struct idmap_domain *dom,
+ const char *params)
+{
+ NTSTATUS ret;
+ struct idmap_tdb2_context *ctx;
+ char *config_option = NULL;
+ const char *range;
+ NTSTATUS status;
+
+ status = idmap_tdb2_open_db();
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ ctx = talloc(dom, struct idmap_tdb2_context);
+ if ( ! ctx) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
+ if ( ! config_option) {
+ DEBUG(0, ("Out of memory!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ range = lp_parm_const_string(-1, config_option, "range", NULL);
+ if (( ! range) ||
+ (sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2) ||
+ (ctx->filter_low_id > ctx->filter_high_id)) {
+ ctx->filter_low_id = 0;
+ ctx->filter_high_id = 0;
+ }
+
+ dom->private_data = ctx;
+
+ talloc_free(config_option);
+ return NT_STATUS_OK;
+
+failed:
+ talloc_free(ctx);
+ return ret;
+}
+
+
+/*
+ run a script to perform a mapping
+
+ The script should the following command lines:
+
+ SIDTOID S-1-xxxx
+ IDTOSID UID xxxx
+ IDTOSID GID xxxx
+
+ and should return one of the following as a single line of text
+ UID:xxxx
+ GID:xxxx
+ SID:xxxx
+ ERR:xxxx
+ */
+static NTSTATUS idmap_tdb2_script(struct idmap_tdb2_context *ctx, struct id_map *map,
+ const char *fmt, ...)
+{
+ va_list ap;
+ char *cmd;
+ FILE *p;
+ char line[64];
+ unsigned long v;
+
+ cmd = talloc_asprintf(ctx, "%s ", idmap_tdb2_state.idmap_script);
+ NT_STATUS_HAVE_NO_MEMORY(cmd);
+
+ va_start(ap, fmt);
+ cmd = talloc_vasprintf_append(cmd, fmt, ap);
+ va_end(ap);
+ NT_STATUS_HAVE_NO_MEMORY(cmd);
+
+ p = popen(cmd, "r");
+ talloc_free(cmd);
+ if (p == NULL) {
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ if (fgets(line, sizeof(line)-1, p) == NULL) {
+ pclose(p);
+ return NT_STATUS_NONE_MAPPED;
+ }
+ pclose(p);
+
+ DEBUG(10,("idmap script gave: %s\n", line));
+
+ if (sscanf(line, "UID:%lu", &v) == 1) {
+ map->xid.id = v;
+ map->xid.type = ID_TYPE_UID;
+ } else if (sscanf(line, "GID:%lu", &v) == 1) {
+ map->xid.id = v;
+ map->xid.type = ID_TYPE_GID;
+ } else if (strncmp(line, "SID:S-", 6) == 0) {
+ if (!string_to_sid(map->sid, &line[4])) {
+ DEBUG(0,("Bad SID in '%s' from idmap script %s\n",
+ line, idmap_tdb2_state.idmap_script));
+ return NT_STATUS_NONE_MAPPED;
+ }
+ } else {
+ DEBUG(0,("Bad reply '%s' from idmap script %s\n",
+ line, idmap_tdb2_state.idmap_script));
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+
+/*
+ Single id to sid lookup function.
+*/
+static NTSTATUS idmap_tdb2_id_to_sid(struct idmap_tdb2_context *ctx, struct id_map *map)
+{
+ NTSTATUS ret;
+ TDB_DATA data;
+ char *keystr;
+
+ if (!ctx || !map) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* apply filters before checking */
+ if ((ctx->filter_low_id && (map->xid.id < ctx->filter_low_id)) ||
+ (ctx->filter_high_id && (map->xid.id > ctx->filter_high_id))) {
+ DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
+ map->xid.id, ctx->filter_low_id, ctx->filter_high_id));
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ switch (map->xid.type) {
+
+ case ID_TYPE_UID:
+ keystr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
+ break;
+
+ case ID_TYPE_GID:
+ keystr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
+ break;
+
+ default:
+ DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* final SAFE_FREE safe */
+ data.dptr = NULL;
+
+ if (keystr == NULL) {
+ DEBUG(0, ("Out of memory!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ DEBUG(10,("Fetching record %s\n", keystr));
+
+ /* Check if the mapping exists */
+ data = dbwrap_fetch_bystring(idmap_tdb2, keystr, keystr);
+
+ if (!data.dptr) {
+ fstring sidstr;
+
+ DEBUG(10,("Record %s not found\n", keystr));
+ if (idmap_tdb2_state.idmap_script == NULL) {
+ ret = NT_STATUS_NONE_MAPPED;
+ goto done;
+ }
+
+ ret = idmap_tdb2_script(ctx, map, "IDTOSID %s", keystr);
+
+ /* store it on shared storage */
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto done;
+ }
+
+ if (sid_to_fstring(sidstr, map->sid)) {
+ /* both forward and reverse mappings */
+ dbwrap_store_bystring(idmap_tdb2, keystr,
+ string_term_tdb_data(sidstr),
+ TDB_REPLACE);
+ dbwrap_store_bystring(idmap_tdb2, sidstr,
+ string_term_tdb_data(keystr),
+ TDB_REPLACE);
+ }
+ goto done;
+ }
+
+ if (!string_to_sid(map->sid, (const char *)data.dptr)) {
+ DEBUG(10,("INVALID SID (%s) in record %s\n",
+ (const char *)data.dptr, keystr));
+ ret = NT_STATUS_INTERNAL_DB_ERROR;
+ goto done;
+ }
+
+ DEBUG(10,("Found record %s -> %s\n", keystr, (const char *)data.dptr));
+ ret = NT_STATUS_OK;
+
+done:
+ talloc_free(keystr);
+ return ret;
+}
+
+
+/*
+ Single sid to id lookup function.
+*/
+static NTSTATUS idmap_tdb2_sid_to_id(struct idmap_tdb2_context *ctx, struct id_map *map)
+{
+ NTSTATUS ret;
+ TDB_DATA data;
+ char *keystr;
+ unsigned long rec_id = 0;
+
+ if ((keystr = sid_string_talloc(ctx, map->sid)) == NULL) {
+ DEBUG(0, ("Out of memory!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ DEBUG(10,("Fetching record %s\n", keystr));
+
+ /* Check if sid is present in database */
+ data = dbwrap_fetch_bystring(idmap_tdb2, keystr, keystr);
+ if (!data.dptr) {
+ fstring idstr;
+
+ DEBUG(10,(__location__ " Record %s not found\n", keystr));
+
+ if (idmap_tdb2_state.idmap_script == NULL) {
+ ret = NT_STATUS_NONE_MAPPED;
+ goto done;
+ }
+
+ ret = idmap_tdb2_script(ctx, map, "SIDTOID %s", keystr);
+ /* store it on shared storage */
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto done;
+ }
+
+ snprintf(idstr, sizeof(idstr), "%cID %lu",
+ map->xid.type == ID_TYPE_UID?'U':'G',
+ (unsigned long)map->xid.id);
+ /* store both forward and reverse mappings */
+ dbwrap_store_bystring(idmap_tdb2, keystr, string_term_tdb_data(idstr),
+ TDB_REPLACE);
+ dbwrap_store_bystring(idmap_tdb2, idstr, string_term_tdb_data(keystr),
+ TDB_REPLACE);
+ goto done;
+ }
+
+ /* What type of record is this ? */
+ if (sscanf((const char *)data.dptr, "UID %lu", &rec_id) == 1) { /* Try a UID record. */
+ map->xid.id = rec_id;
+ map->xid.type = ID_TYPE_UID;
+ DEBUG(10,("Found uid record %s -> %s \n", keystr, (const char *)data.dptr ));
+ ret = NT_STATUS_OK;
+
+ } else if (sscanf((const char *)data.dptr, "GID %lu", &rec_id) == 1) { /* Try a GID record. */
+ map->xid.id = rec_id;
+ map->xid.type = ID_TYPE_GID;
+ DEBUG(10,("Found gid record %s -> %s \n", keystr, (const char *)data.dptr ));
+ ret = NT_STATUS_OK;
+
+ } else { /* Unknown record type ! */
+ DEBUG(2, ("Found INVALID record %s -> %s\n", keystr, (const char *)data.dptr));
+ ret = NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ /* apply filters before returning result */
+ if ((ctx->filter_low_id && (map->xid.id < ctx->filter_low_id)) ||
+ (ctx->filter_high_id && (map->xid.id > ctx->filter_high_id))) {
+ DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
+ map->xid.id, ctx->filter_low_id, ctx->filter_high_id));
+ ret = NT_STATUS_NONE_MAPPED;
+ }
+
+done:
+ talloc_free(keystr);
+ return ret;
+}
+
+/*
+ lookup a set of unix ids.
+*/
+static NTSTATUS idmap_tdb2_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
+{
+ struct idmap_tdb2_context *ctx;
+ NTSTATUS ret;
+ int i;
+
+ ctx = talloc_get_type(dom->private_data, struct idmap_tdb2_context);
+
+ for (i = 0; ids[i]; i++) {
+ ret = idmap_tdb2_id_to_sid(ctx, ids[i]);
+ if ( ! NT_STATUS_IS_OK(ret)) {
+
+ /* if it is just a failed mapping continue */
+ if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
+
+ /* make sure it is marked as unmapped */
+ ids[i]->status = ID_UNMAPPED;
+ continue;
+ }
+
+ /* some fatal error occurred, return immediately */
+ goto done;
+ }
+
+ /* all ok, id is mapped */
+ ids[i]->status = ID_MAPPED;
+ }
+
+ ret = NT_STATUS_OK;
+
+done:
+ return ret;
+}
+
+/*
+ lookup a set of sids.
+*/
+static NTSTATUS idmap_tdb2_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
+{
+ struct idmap_tdb2_context *ctx;
+ NTSTATUS ret;
+ int i;
+
+ ctx = talloc_get_type(dom->private_data, struct idmap_tdb2_context);
+
+ for (i = 0; ids[i]; i++) {
+ ret = idmap_tdb2_sid_to_id(ctx, ids[i]);
+ if ( ! NT_STATUS_IS_OK(ret)) {
+
+ /* if it is just a failed mapping continue */
+ if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
+
+ /* make sure it is marked as unmapped */
+ ids[i]->status = ID_UNMAPPED;
+ continue;
+ }
+
+ /* some fatal error occurred, return immediately */
+ goto done;
+ }
+
+ /* all ok, id is mapped */
+ ids[i]->status = ID_MAPPED;
+ }
+
+ ret = NT_STATUS_OK;
+
+done:
+ return ret;
+}
+
+
+/*
+ set a mapping.
+*/
+static NTSTATUS idmap_tdb2_set_mapping(struct idmap_domain *dom, const struct id_map *map)
+{
+ struct idmap_tdb2_context *ctx;
+ NTSTATUS ret;
+ TDB_DATA data;
+ char *ksidstr, *kidstr;
+ int res;
+ bool started_transaction = false;
+
+ if (!map || !map->sid) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ksidstr = kidstr = NULL;
+
+ /* TODO: should we filter a set_mapping using low/high filters ? */
+
+ ctx = talloc_get_type(dom->private_data, struct idmap_tdb2_context);
+
+ switch (map->xid.type) {
+
+ case ID_TYPE_UID:
+ kidstr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
+ break;
+
+ case ID_TYPE_GID:
+ kidstr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
+ break;
+
+ default:
+ DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (kidstr == NULL) {
+ DEBUG(0, ("ERROR: Out of memory!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if (!(ksidstr = sid_string_talloc(ctx, map->sid))) {
+ DEBUG(0, ("Out of memory!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ DEBUG(10, ("Storing %s <-> %s map\n", ksidstr, kidstr));
+
+ res = idmap_tdb2->transaction_start(idmap_tdb2);
+ if (res != 0) {
+ DEBUG(1,(__location__ " Failed to start transaction\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ started_transaction = true;
+
+ /* check wheter sid mapping is already present in db */
+ data = dbwrap_fetch_bystring(idmap_tdb2, ksidstr, ksidstr);
+ if (data.dptr) {
+ ret = NT_STATUS_OBJECT_NAME_COLLISION;
+ goto done;
+ }
+
+ ret = dbwrap_store_bystring(idmap_tdb2, ksidstr, string_term_tdb_data(kidstr),
+ TDB_INSERT);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(0, ("Error storing SID -> ID: %s\n", nt_errstr(ret)));
+ goto done;
+ }
+ ret = dbwrap_store_bystring(idmap_tdb2, kidstr, string_term_tdb_data(ksidstr),
+ TDB_INSERT);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(0, ("Error storing ID -> SID: %s\n", nt_errstr(ret)));
+ /* try to remove the previous stored SID -> ID map */
+ dbwrap_delete_bystring(idmap_tdb2, ksidstr);
+ goto done;
+ }
+
+ started_transaction = false;
+
+ res = idmap_tdb2->transaction_commit(idmap_tdb2);
+ if (res != 0) {
+ DEBUG(1,(__location__ " Failed to commit transaction\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ DEBUG(10,("Stored %s <-> %s\n", ksidstr, kidstr));
+ ret = NT_STATUS_OK;
+
+done:
+ if (started_transaction) {
+ idmap_tdb2->transaction_cancel(idmap_tdb2);
+ }
+ talloc_free(ksidstr);
+ talloc_free(kidstr);
+ return ret;
+}
+
+/*
+ remove a mapping.
+*/
+static NTSTATUS idmap_tdb2_remove_mapping(struct idmap_domain *dom, const struct id_map *map)
+{
+ /* not supported as it would invalidate the cache tdb on other
+ nodes */
+ DEBUG(0,("idmap_tdb2_remove_mapping not supported\n"));
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+/*
+ Close the idmap tdb instance
+*/
+static NTSTATUS idmap_tdb2_close(struct idmap_domain *dom)
+{
+ /* don't do anything */
+ return NT_STATUS_OK;
+}
+
+
+/*
+ Dump all mappings out
+*/
+static NTSTATUS idmap_tdb2_dump_data(struct idmap_domain *dom, struct id_map **maps, int *num_maps)
+{
+ DEBUG(0,("idmap_tdb2_dump_data not supported\n"));
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+static struct idmap_methods db_methods = {
+ .init = idmap_tdb2_db_init,
+ .unixids_to_sids = idmap_tdb2_unixids_to_sids,
+ .sids_to_unixids = idmap_tdb2_sids_to_unixids,
+ .set_mapping = idmap_tdb2_set_mapping,
+ .remove_mapping = idmap_tdb2_remove_mapping,
+ .dump_data = idmap_tdb2_dump_data,
+ .close_fn = idmap_tdb2_close
+};
+
+static struct idmap_alloc_methods db_alloc_methods = {
+ .init = idmap_tdb2_alloc_init,
+ .allocate_id = idmap_tdb2_allocate_id,
+ .get_id_hwm = idmap_tdb2_get_hwm,
+ .set_id_hwm = idmap_tdb2_set_hwm,
+ .close_fn = idmap_tdb2_alloc_close
+};
+
+NTSTATUS idmap_tdb2_init(void)
+{
+ NTSTATUS ret;
+
+ /* register both backends */
+ ret = smb_register_idmap_alloc(SMB_IDMAP_INTERFACE_VERSION, "tdb2", &db_alloc_methods);
+ if (! NT_STATUS_IS_OK(ret)) {
+ DEBUG(0, ("Unable to register idmap alloc tdb2 module: %s\n", get_friendly_nt_error_msg(ret)));
+ return ret;
+ }
+
+ return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "tdb2", &db_methods);
+}
diff --git a/source3/winbindd/idmap_util.c b/source3/winbindd/idmap_util.c
new file mode 100644
index 0000000000..b10a1a4ba9
--- /dev/null
+++ b/source3/winbindd/idmap_util.c
@@ -0,0 +1,270 @@
+/*
+ Unix SMB/CIFS implementation.
+ ID Mapping
+ Copyright (C) Simo Sorce 2003
+ Copyright (C) Jeremy Allison 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_IDMAP
+
+/*****************************************************************
+ Returns the SID mapped to the given UID.
+ If mapping is not possible returns an error.
+*****************************************************************/
+
+NTSTATUS idmap_uid_to_sid(const char *domname, DOM_SID *sid, uid_t uid)
+{
+ NTSTATUS ret;
+ struct id_map map;
+ bool expired;
+
+ DEBUG(10,("uid = [%lu]\n", (unsigned long)uid));
+
+ if (idmap_cache_find_uid2sid(uid, sid, &expired)) {
+ DEBUG(10, ("idmap_cache_find_uid2sid found %d%s\n", uid,
+ expired ? " (expired)": ""));
+ if (expired && idmap_is_online()) {
+ DEBUG(10, ("revalidating expired entry\n"));
+ goto backend;
+ }
+ if (is_null_sid(sid)) {
+ DEBUG(10, ("Returning negative cache entry\n"));
+ return NT_STATUS_NONE_MAPPED;
+ }
+ DEBUG(10, ("Returning positive cache entry\n"));
+ return NT_STATUS_OK;
+ }
+
+backend:
+ map.sid = sid;
+ map.xid.type = ID_TYPE_UID;
+ map.xid.id = uid;
+
+ ret = idmap_backends_unixid_to_sid(domname, &map);
+ if ( ! NT_STATUS_IS_OK(ret)) {
+ DEBUG(10, ("error mapping uid [%lu]\n", (unsigned long)uid));
+ return ret;
+ }
+
+ if (map.status != ID_MAPPED) {
+ struct dom_sid null_sid;
+ ZERO_STRUCT(null_sid);
+ idmap_cache_set_sid2uid(&null_sid, uid);
+ DEBUG(10, ("uid [%lu] not mapped\n", (unsigned long)uid));
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ idmap_cache_set_sid2uid(sid, uid);
+
+ return NT_STATUS_OK;
+}
+
+/*****************************************************************
+ Returns SID mapped to the given GID.
+ If mapping is not possible returns an error.
+*****************************************************************/
+
+NTSTATUS idmap_gid_to_sid(const char *domname, DOM_SID *sid, gid_t gid)
+{
+ NTSTATUS ret;
+ struct id_map map;
+ bool expired;
+
+ DEBUG(10,("gid = [%lu]\n", (unsigned long)gid));
+
+ if (idmap_cache_find_gid2sid(gid, sid, &expired)) {
+ DEBUG(10, ("idmap_cache_find_gid2sid found %d%s\n", gid,
+ expired ? " (expired)": ""));
+ if (expired && idmap_is_online()) {
+ DEBUG(10, ("revalidating expired entry\n"));
+ goto backend;
+ }
+ if (is_null_sid(sid)) {
+ DEBUG(10, ("Returning negative cache entry\n"));
+ return NT_STATUS_NONE_MAPPED;
+ }
+ DEBUG(10, ("Returning positive cache entry\n"));
+ return NT_STATUS_OK;
+ }
+
+backend:
+ map.sid = sid;
+ map.xid.type = ID_TYPE_GID;
+ map.xid.id = gid;
+
+ ret = idmap_backends_unixid_to_sid(domname, &map);
+ if ( ! NT_STATUS_IS_OK(ret)) {
+ DEBUG(10, ("error mapping gid [%lu]\n", (unsigned long)gid));
+ return ret;
+ }
+
+ if (map.status != ID_MAPPED) {
+ struct dom_sid null_sid;
+ ZERO_STRUCT(null_sid);
+ idmap_cache_set_sid2uid(&null_sid, gid);
+ DEBUG(10, ("gid [%lu] not mapped\n", (unsigned long)gid));
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ idmap_cache_set_sid2uid(sid, gid);
+
+ return NT_STATUS_OK;
+}
+
+/*****************************************************************
+ Returns the UID mapped to the given SID.
+ If mapping is not possible or SID maps to a GID returns an error.
+*****************************************************************/
+
+NTSTATUS idmap_sid_to_uid(const char *dom_name, DOM_SID *sid, uid_t *uid)
+{
+ NTSTATUS ret;
+ struct id_map map;
+ bool expired;
+
+ DEBUG(10,("idmap_sid_to_uid: sid = [%s]\n", sid_string_dbg(sid)));
+
+ if (idmap_cache_find_sid2uid(sid, uid, &expired)) {
+ DEBUG(10, ("idmap_cache_find_sid2uid found %d%s\n",
+ (int)(*uid), expired ? " (expired)": ""));
+ if (expired && idmap_is_online()) {
+ DEBUG(10, ("revalidating expired entry\n"));
+ goto backend;
+ }
+ if ((*uid) == -1) {
+ DEBUG(10, ("Returning negative cache entry\n"));
+ return NT_STATUS_NONE_MAPPED;
+ }
+ DEBUG(10, ("Returning positive cache entry\n"));
+ return NT_STATUS_OK;
+ }
+
+backend:
+ map.sid = sid;
+ map.xid.type = ID_TYPE_UID;
+
+ ret = idmap_backends_sid_to_unixid(dom_name, &map);
+
+ if (NT_STATUS_IS_OK(ret) && (map.status == ID_MAPPED)) {
+ if (map.xid.type != ID_TYPE_UID) {
+ DEBUG(10, ("sid [%s] not mapped to a uid "
+ "[%u,%u,%u]\n",
+ sid_string_dbg(sid),
+ map.status,
+ map.xid.type,
+ map.xid.id));
+ idmap_cache_set_sid2uid(sid, -1);
+ return NT_STATUS_NONE_MAPPED;
+ }
+ goto done;
+ }
+
+ if (dom_name[0] != '\0') {
+ /*
+ * We had the task to go to a specific domain which
+ * could not answer our request. Fail.
+ */
+ idmap_cache_set_sid2uid(sid, -1);
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ ret = idmap_new_mapping(sid, ID_TYPE_UID, &map.xid);
+
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(10, ("idmap_new_mapping failed: %s\n",
+ nt_errstr(ret)));
+ idmap_cache_set_sid2uid(sid, -1);
+ return ret;
+ }
+
+done:
+ *uid = (uid_t)map.xid.id;
+ idmap_cache_set_sid2uid(sid, *uid);
+ return NT_STATUS_OK;
+}
+
+/*****************************************************************
+ Returns the GID mapped to the given SID.
+ If mapping is not possible or SID maps to a UID returns an error.
+*****************************************************************/
+
+NTSTATUS idmap_sid_to_gid(const char *domname, DOM_SID *sid, gid_t *gid)
+{
+ NTSTATUS ret;
+ struct id_map map;
+ bool expired;
+
+ DEBUG(10,("idmap_sid_to_gid: sid = [%s]\n", sid_string_dbg(sid)));
+
+ if (idmap_cache_find_sid2gid(sid, gid, &expired)) {
+ DEBUG(10, ("idmap_cache_find_sid2gid found %d%s\n",
+ (int)(*gid), expired ? " (expired)": ""));
+ if (expired && idmap_is_online()) {
+ DEBUG(10, ("revalidating expired entry\n"));
+ goto backend;
+ }
+ if ((*gid) == -1) {
+ DEBUG(10, ("Returning negative cache entry\n"));
+ return NT_STATUS_NONE_MAPPED;
+ }
+ DEBUG(10, ("Returning positive cache entry\n"));
+ return NT_STATUS_OK;
+ }
+
+backend:
+ map.sid = sid;
+ map.xid.type = ID_TYPE_GID;
+
+ ret = idmap_backends_sid_to_unixid(domname, &map);
+ if (NT_STATUS_IS_OK(ret) && (map.status == ID_MAPPED)) {
+ if (map.xid.type != ID_TYPE_GID) {
+ DEBUG(10, ("sid [%s] not mapped to a gid "
+ "[%u,%u,%u]\n",
+ sid_string_dbg(sid),
+ map.status,
+ map.xid.type,
+ map.xid.id));
+ idmap_cache_set_sid2gid(sid, -1);
+ return NT_STATUS_NONE_MAPPED;
+ }
+ goto done;
+ }
+
+ if (domname[0] != '\0') {
+ /*
+ * We had the task to go to a specific domain which
+ * could not answer our request. Fail.
+ */
+ idmap_cache_set_sid2uid(sid, -1);
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ ret = idmap_new_mapping(sid, ID_TYPE_GID, &map.xid);
+
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(10, ("idmap_new_mapping failed: %s\n",
+ nt_errstr(ret)));
+ idmap_cache_set_sid2gid(sid, -1);
+ return ret;
+ }
+
+done:
+ *gid = map.xid.id;
+ idmap_cache_set_sid2gid(sid, *gid);
+ return NT_STATUS_OK;
+}
diff --git a/source3/winbindd/nss_info.c b/source3/winbindd/nss_info.c
new file mode 100644
index 0000000000..daa3dd037d
--- /dev/null
+++ b/source3/winbindd/nss_info.c
@@ -0,0 +1,301 @@
+/*
+ Unix SMB/CIFS implementation.
+ Idmap NSS headers
+
+ Copyright (C) Gerald Carter 2006
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "nss_info.h"
+
+static struct nss_function_entry *backends = NULL;
+static struct nss_domain_entry *nss_domain_list = NULL;
+
+/**********************************************************************
+ Get idmap nss methods.
+**********************************************************************/
+
+static struct nss_function_entry *nss_get_backend(const char *name )
+{
+ struct nss_function_entry *entry = backends;
+
+ for(entry = backends; entry; entry = entry->next) {
+ if ( strequal(entry->name, name) )
+ return entry;
+ }
+
+ return NULL;
+}
+
+/*********************************************************************
+ Allow a module to register itself as a backend.
+**********************************************************************/
+
+ NTSTATUS smb_register_idmap_nss(int version, const char *name, struct nss_info_methods *methods)
+{
+ struct nss_function_entry *entry;
+
+ if ((version != SMB_NSS_INFO_INTERFACE_VERSION)) {
+ DEBUG(0, ("smb_register_idmap_nss: Failed to register idmap_nss module.\n"
+ "The module was compiled against SMB_NSS_INFO_INTERFACE_VERSION %d,\n"
+ "current SMB_NSS_INFO_INTERFACE_VERSION is %d.\n"
+ "Please recompile against the current version of samba!\n",
+ version, SMB_NSS_INFO_INTERFACE_VERSION));
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ if (!name || !name[0] || !methods) {
+ DEBUG(0,("smb_register_idmap_nss: called with NULL pointer or empty name!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if ( nss_get_backend(name) ) {
+ DEBUG(0,("smb_register_idmap_nss: idmap module %s "
+ "already registered!\n", name));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ entry = SMB_XMALLOC_P(struct nss_function_entry);
+ entry->name = smb_xstrdup(name);
+ entry->methods = methods;
+
+ DLIST_ADD(backends, entry);
+ DEBUG(5, ("smb_register_idmap_nss: Successfully added idmap "
+ "nss backend '%s'\n", name));
+
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+ *******************************************************************/
+
+static bool parse_nss_parm( const char *config, char **backend, char **domain )
+{
+ char *p;
+ char *q;
+ int len;
+
+ *backend = *domain = NULL;
+
+ if ( !config )
+ return False;
+
+ p = strchr( config, ':' );
+
+ /* if no : then the string must be the backend name only */
+
+ if ( !p ) {
+ *backend = SMB_STRDUP( config );
+ return (*backend != NULL);
+ }
+
+ /* split the string and return the two parts */
+
+ if ( strlen(p+1) > 0 ) {
+ *domain = SMB_STRDUP( p+1 );
+ }
+
+ len = PTR_DIFF(p,config)+1;
+ if ( (q = SMB_MALLOC_ARRAY( char, len )) == NULL ) {
+ SAFE_FREE( *backend );
+ return False;
+ }
+
+ StrnCpy( q, config, len-1);
+ q[len-1] = '\0';
+ *backend = q;
+
+ return True;
+}
+
+/********************************************************************
+ Each nss backend must not store global state, but rather be able
+ to initialize the state on a per domain basis.
+ *******************************************************************/
+
+ NTSTATUS nss_init( const char **nss_list )
+{
+ NTSTATUS status;
+ static NTSTATUS nss_initialized = NT_STATUS_UNSUCCESSFUL;
+ int i;
+ char *backend, *domain;
+ struct nss_function_entry *nss_backend;
+ struct nss_domain_entry *nss_domain;
+
+ /* check for previous successful initializations */
+
+ if ( NT_STATUS_IS_OK(nss_initialized) )
+ return NT_STATUS_OK;
+
+ /* The "template" backend should alqays be registered as it
+ is a static module */
+
+ if ( (nss_backend = nss_get_backend( "template" )) == NULL ) {
+ static_init_nss_info;
+ }
+
+ /* Create the list of nss_domains (loading any shared plugins
+ as necessary) */
+
+ for ( i=0; nss_list && nss_list[i]; i++ ) {
+
+ if ( !parse_nss_parm(nss_list[i], &backend, &domain) ) {
+ DEBUG(0,("nss_init: failed to parse \"%s\"!\n",
+ nss_list[i]));
+ continue;
+ }
+
+ /* validate the backend */
+
+ if ( (nss_backend = nss_get_backend( backend )) == NULL ) {
+ /* attempt to register the backend */
+ status = smb_probe_module( "nss_info", backend );
+ if ( !NT_STATUS_IS_OK(status) ) {
+ continue;
+ }
+
+ /* try again */
+ if ( (nss_backend = nss_get_backend( backend )) == NULL ) {
+ DEBUG(0,("nss_init: unregistered backend %s!. Skipping\n",
+ backend));
+ continue;
+ }
+
+ }
+
+ /* fill in the nss_domain_entry and add it to the
+ list of domains */
+
+ nss_domain = TALLOC_ZERO_P( nss_domain_list, struct nss_domain_entry );
+ if ( !nss_domain ) {
+ DEBUG(0,("nss_init: talloc() failure!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ nss_domain->backend = nss_backend;
+ nss_domain->domain = talloc_strdup( nss_domain, domain );
+
+ /* Try to init and ave the result */
+
+ nss_domain->init_status = nss_domain->backend->methods->init( nss_domain );
+ DLIST_ADD( nss_domain_list, nss_domain );
+ if ( !NT_STATUS_IS_OK(nss_domain->init_status) ) {
+ DEBUG(0,("nss_init: Failed to init backend for %s domain!\n",
+ nss_domain->domain));
+ }
+
+ /* cleanup */
+
+ SAFE_FREE( backend );
+ SAFE_FREE( domain );
+ }
+
+ if ( !nss_domain_list ) {
+ DEBUG(3,("nss_init: no nss backends configured. "
+ "Defaulting to \"template\".\n"));
+
+
+ /* we shouild default to use template here */
+ }
+
+
+ nss_initialized = NT_STATUS_OK;
+
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+ *******************************************************************/
+
+static struct nss_domain_entry *find_nss_domain( const char *domain )
+{
+ NTSTATUS status;
+ struct nss_domain_entry *p;
+
+ status = nss_init( lp_winbind_nss_info() );
+ if ( !NT_STATUS_IS_OK(status) ) {
+ DEBUG(4,("nss_get_info: Failed to init nss_info API (%s)!\n",
+ nt_errstr(status)));
+ return NULL;
+ }
+
+ for ( p=nss_domain_list; p; p=p->next ) {
+ if ( strequal( p->domain, domain ) )
+ break;
+ }
+
+ /* If we didn't find a match, then use the default nss info */
+
+ if ( !p ) {
+ if ( !nss_domain_list ) {
+ return NULL;
+ }
+
+ p = nss_domain_list;
+ }
+
+ if ( !NT_STATUS_IS_OK( p->init_status ) ) {
+ p->init_status = p->backend->methods->init( p );
+ }
+
+ return p;
+}
+
+/********************************************************************
+ *******************************************************************/
+
+ NTSTATUS nss_get_info( const char *domain, const DOM_SID *user_sid,
+ TALLOC_CTX *ctx,
+ ADS_STRUCT *ads, LDAPMessage *msg,
+ char **homedir, char **shell, char **gecos,
+ gid_t *p_gid)
+{
+ struct nss_domain_entry *p;
+ struct nss_info_methods *m;
+
+ if ( (p = find_nss_domain( domain )) == NULL ) {
+ DEBUG(4,("nss_get_info: Failed to find nss domain pointer for %s\n",
+ domain ));
+ return NT_STATUS_NOT_FOUND;
+ }
+
+ m = p->backend->methods;
+
+ return m->get_nss_info( p, user_sid, ctx, ads, msg,
+ homedir, shell, gecos, p_gid );
+}
+
+/********************************************************************
+ *******************************************************************/
+
+ NTSTATUS nss_close( const char *parameters )
+{
+ struct nss_domain_entry *p = nss_domain_list;
+ struct nss_domain_entry *q;
+
+ while ( p && p->backend && p->backend->methods ) {
+ /* close the backend */
+ p->backend->methods->close_fn();
+
+ /* free the memory */
+ q = p;
+ p = p->next;
+ TALLOC_FREE( q );
+ }
+
+ return NT_STATUS_OK;
+}
+
diff --git a/source3/winbindd/nss_info_template.c b/source3/winbindd/nss_info_template.c
new file mode 100644
index 0000000000..aaf02e4abe
--- /dev/null
+++ b/source3/winbindd/nss_info_template.c
@@ -0,0 +1,83 @@
+/*
+ Unix SMB/CIFS implementation.
+ idMap nss template plugin
+
+ Copyright (C) Gerald Carter 2006
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "nss_info.h"
+
+/************************************************************************
+ ***********************************************************************/
+
+static NTSTATUS nss_template_init( struct nss_domain_entry *e )
+{
+ return NT_STATUS_OK;
+}
+
+/************************************************************************
+ ***********************************************************************/
+
+static NTSTATUS nss_template_get_info( struct nss_domain_entry *e,
+ const DOM_SID *sid,
+ TALLOC_CTX *ctx,
+ ADS_STRUCT *ads,
+ LDAPMessage *msg,
+ char **homedir,
+ char **shell,
+ char **gecos,
+ gid_t *gid )
+{
+ if ( !homedir || !shell || !gecos )
+ return NT_STATUS_INVALID_PARAMETER;
+
+ *homedir = talloc_strdup( ctx, lp_template_homedir() );
+ *shell = talloc_strdup( ctx, lp_template_shell() );
+ *gecos = NULL;
+
+ if ( !*homedir || !*shell ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/************************************************************************
+ ***********************************************************************/
+
+static NTSTATUS nss_template_close( void )
+{
+ return NT_STATUS_OK;
+}
+
+
+/************************************************************************
+ ***********************************************************************/
+
+static struct nss_info_methods nss_template_methods = {
+ .init = nss_template_init,
+ .get_nss_info = nss_template_get_info,
+ .close_fn = nss_template_close
+};
+
+NTSTATUS nss_info_template_init( void )
+{
+ return smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
+ "template",
+ &nss_template_methods);
+}
+
diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c
new file mode 100644
index 0000000000..44b5415726
--- /dev/null
+++ b/source3/winbindd/winbindd.c
@@ -0,0 +1,1257 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon for ntdom nss module
+
+ Copyright (C) by Tim Potter 2000-2002
+ Copyright (C) Andrew Tridgell 2002
+ Copyright (C) Jelmer Vernooij 2003
+ Copyright (C) Volker Lendecke 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+bool opt_nocache = False;
+static bool interactive = False;
+
+extern bool override_logfile;
+
+struct event_context *winbind_event_context(void)
+{
+ static struct event_context *ctx;
+
+ if (!ctx && !(ctx = event_context_init(NULL))) {
+ smb_panic("Could not init winbind event context");
+ }
+ return ctx;
+}
+
+struct messaging_context *winbind_messaging_context(void)
+{
+ static struct messaging_context *ctx;
+
+ if (ctx == NULL) {
+ ctx = messaging_init(NULL, server_id_self(),
+ winbind_event_context());
+ }
+ if (ctx == NULL) {
+ DEBUG(0, ("Could not init winbind messaging context.\n"));
+ }
+ return ctx;
+}
+
+/* Reload configuration */
+
+static bool reload_services_file(const char *logfile)
+{
+ bool ret;
+
+ if (lp_loaded()) {
+ const char *fname = lp_configfile();
+
+ if (file_exist(fname,NULL) && !strcsequal(fname,get_dyn_CONFIGFILE())) {
+ set_dyn_CONFIGFILE(fname);
+ }
+ }
+
+ /* if this is a child, restore the logfile to the special
+ name - <domain>, idmap, etc. */
+ if (logfile && *logfile) {
+ lp_set_logfile(logfile);
+ }
+
+ reopen_logs();
+ ret = lp_load(get_dyn_CONFIGFILE(),False,False,True,True);
+
+ reopen_logs();
+ load_interfaces();
+
+ return(ret);
+}
+
+
+/**************************************************************************** **
+ Handle a fault..
+ **************************************************************************** */
+
+static void fault_quit(void)
+{
+ dump_core();
+}
+
+static void winbindd_status(void)
+{
+ struct winbindd_cli_state *tmp;
+
+ DEBUG(0, ("winbindd status:\n"));
+
+ /* Print client state information */
+
+ DEBUG(0, ("\t%d clients currently active\n", winbindd_num_clients()));
+
+ if (DEBUGLEVEL >= 2 && winbindd_num_clients()) {
+ DEBUG(2, ("\tclient list:\n"));
+ for(tmp = winbindd_client_list(); tmp; tmp = tmp->next) {
+ DEBUGADD(2, ("\t\tpid %lu, sock %d\n",
+ (unsigned long)tmp->pid, tmp->sock));
+ }
+ }
+}
+
+/* Print winbindd status to log file */
+
+static void print_winbindd_status(void)
+{
+ winbindd_status();
+}
+
+/* Flush client cache */
+
+static void flush_caches(void)
+{
+ /* We need to invalidate cached user list entries on a SIGHUP
+ otherwise cached access denied errors due to restrict anonymous
+ hang around until the sequence number changes. */
+
+ if (!wcache_invalidate_cache()) {
+ DEBUG(0, ("invalidating the cache failed; revalidate the cache\n"));
+ if (!winbindd_cache_validate_and_initialize()) {
+ exit(1);
+ }
+ }
+}
+
+/* Handle the signal by unlinking socket and exiting */
+
+static void terminate(bool is_parent)
+{
+ if (is_parent) {
+ /* When parent goes away we should
+ * remove the socket file. Not so
+ * when children terminate.
+ */
+ char *path = NULL;
+
+ if (asprintf(&path, "%s/%s",
+ get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME) > 0) {
+ unlink(path);
+ SAFE_FREE(path);
+ }
+ }
+
+ idmap_close();
+
+ trustdom_cache_shutdown();
+
+#if 0
+ if (interactive) {
+ TALLOC_CTX *mem_ctx = talloc_init("end_description");
+ char *description = talloc_describe_all(mem_ctx);
+
+ DEBUG(3, ("tallocs left:\n%s\n", description));
+ talloc_destroy(mem_ctx);
+ }
+#endif
+
+ exit(0);
+}
+
+static bool do_sigterm;
+
+static void termination_handler(int signum)
+{
+ do_sigterm = True;
+ sys_select_signal(signum);
+}
+
+static bool do_sigusr2;
+
+static void sigusr2_handler(int signum)
+{
+ do_sigusr2 = True;
+ sys_select_signal(SIGUSR2);
+}
+
+static bool do_sighup;
+
+static void sighup_handler(int signum)
+{
+ do_sighup = True;
+ sys_select_signal(SIGHUP);
+}
+
+static bool do_sigchld;
+
+static void sigchld_handler(int signum)
+{
+ do_sigchld = True;
+ sys_select_signal(SIGCHLD);
+}
+
+/* React on 'smbcontrol winbindd reload-config' in the same way as on SIGHUP*/
+static void msg_reload_services(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ /* Flush various caches */
+ flush_caches();
+ reload_services_file((const char *) private_data);
+}
+
+/* React on 'smbcontrol winbindd shutdown' in the same way as on SIGTERM*/
+static void msg_shutdown(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ do_sigterm = True;
+}
+
+
+static void winbind_msg_validate_cache(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ uint8 ret;
+ pid_t child_pid;
+ struct sigaction act;
+ struct sigaction oldact;
+
+ DEBUG(10, ("winbindd_msg_validate_cache: got validate-cache "
+ "message.\n"));
+
+ /*
+ * call the validation code from a child:
+ * so we don't block the main winbindd and the validation
+ * code can safely use fork/waitpid...
+ */
+ CatchChild();
+ child_pid = sys_fork();
+
+ if (child_pid == -1) {
+ DEBUG(1, ("winbind_msg_validate_cache: Could not fork: %s\n",
+ strerror(errno)));
+ return;
+ }
+
+ if (child_pid != 0) {
+ /* parent */
+ DEBUG(5, ("winbind_msg_validate_cache: child created with "
+ "pid %d.\n", child_pid));
+ return;
+ }
+
+ /* child */
+
+ /* install default SIGCHLD handler: validation code uses fork/waitpid */
+ ZERO_STRUCT(act);
+ act.sa_handler = SIG_DFL;
+#ifdef SA_RESTART
+ /* We *want* SIGALRM to interrupt a system call. */
+ act.sa_flags = SA_RESTART;
+#endif
+ sigemptyset(&act.sa_mask);
+ sigaddset(&act.sa_mask,SIGCHLD);
+ sigaction(SIGCHLD,&act,&oldact);
+
+ ret = (uint8)winbindd_validate_cache_nobackup();
+ DEBUG(10, ("winbindd_msg_validata_cache: got return value %d\n", ret));
+ messaging_send_buf(msg_ctx, server_id, MSG_WINBIND_VALIDATE_CACHE, &ret,
+ (size_t)1);
+ _exit(0);
+}
+
+static struct winbindd_dispatch_table {
+ enum winbindd_cmd cmd;
+ void (*fn)(struct winbindd_cli_state *state);
+ const char *winbindd_cmd_name;
+} dispatch_table[] = {
+
+ /* User functions */
+
+ { WINBINDD_GETPWNAM, winbindd_getpwnam, "GETPWNAM" },
+ { WINBINDD_GETPWUID, winbindd_getpwuid, "GETPWUID" },
+
+ { WINBINDD_SETPWENT, winbindd_setpwent, "SETPWENT" },
+ { WINBINDD_ENDPWENT, winbindd_endpwent, "ENDPWENT" },
+ { WINBINDD_GETPWENT, winbindd_getpwent, "GETPWENT" },
+
+ { WINBINDD_GETGROUPS, winbindd_getgroups, "GETGROUPS" },
+ { WINBINDD_GETUSERSIDS, winbindd_getusersids, "GETUSERSIDS" },
+ { WINBINDD_GETUSERDOMGROUPS, winbindd_getuserdomgroups,
+ "GETUSERDOMGROUPS" },
+
+ /* Group functions */
+
+ { WINBINDD_GETGRNAM, winbindd_getgrnam, "GETGRNAM" },
+ { WINBINDD_GETGRGID, winbindd_getgrgid, "GETGRGID" },
+ { WINBINDD_SETGRENT, winbindd_setgrent, "SETGRENT" },
+ { WINBINDD_ENDGRENT, winbindd_endgrent, "ENDGRENT" },
+ { WINBINDD_GETGRENT, winbindd_getgrent, "GETGRENT" },
+ { WINBINDD_GETGRLST, winbindd_getgrent, "GETGRLST" },
+
+ /* PAM auth functions */
+
+ { WINBINDD_PAM_AUTH, winbindd_pam_auth, "PAM_AUTH" },
+ { WINBINDD_PAM_AUTH_CRAP, winbindd_pam_auth_crap, "AUTH_CRAP" },
+ { WINBINDD_PAM_CHAUTHTOK, winbindd_pam_chauthtok, "CHAUTHTOK" },
+ { WINBINDD_PAM_LOGOFF, winbindd_pam_logoff, "PAM_LOGOFF" },
+ { WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, winbindd_pam_chng_pswd_auth_crap, "CHNG_PSWD_AUTH_CRAP" },
+
+ /* Enumeration functions */
+
+ { WINBINDD_LIST_USERS, winbindd_list_users, "LIST_USERS" },
+ { WINBINDD_LIST_GROUPS, winbindd_list_groups, "LIST_GROUPS" },
+ { WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains,
+ "LIST_TRUSTDOM" },
+ { WINBINDD_SHOW_SEQUENCE, winbindd_show_sequence, "SHOW_SEQUENCE" },
+
+ /* SID related functions */
+
+ { WINBINDD_LOOKUPSID, winbindd_lookupsid, "LOOKUPSID" },
+ { WINBINDD_LOOKUPNAME, winbindd_lookupname, "LOOKUPNAME" },
+ { WINBINDD_LOOKUPRIDS, winbindd_lookuprids, "LOOKUPRIDS" },
+
+ /* Lookup related functions */
+
+ { WINBINDD_SID_TO_UID, winbindd_sid_to_uid, "SID_TO_UID" },
+ { WINBINDD_SID_TO_GID, winbindd_sid_to_gid, "SID_TO_GID" },
+ { WINBINDD_UID_TO_SID, winbindd_uid_to_sid, "UID_TO_SID" },
+ { WINBINDD_GID_TO_SID, winbindd_gid_to_sid, "GID_TO_SID" },
+ { WINBINDD_ALLOCATE_UID, winbindd_allocate_uid, "ALLOCATE_UID" },
+ { WINBINDD_ALLOCATE_GID, winbindd_allocate_gid, "ALLOCATE_GID" },
+ { WINBINDD_SET_MAPPING, winbindd_set_mapping, "SET_MAPPING" },
+ { WINBINDD_SET_HWM, winbindd_set_hwm, "SET_HWMS" },
+
+ /* Miscellaneous */
+
+ { WINBINDD_CHECK_MACHACC, winbindd_check_machine_acct, "CHECK_MACHACC" },
+ { WINBINDD_PING, winbindd_ping, "PING" },
+ { WINBINDD_INFO, winbindd_info, "INFO" },
+ { WINBINDD_INTERFACE_VERSION, winbindd_interface_version,
+ "INTERFACE_VERSION" },
+ { WINBINDD_DOMAIN_NAME, winbindd_domain_name, "DOMAIN_NAME" },
+ { WINBINDD_DOMAIN_INFO, winbindd_domain_info, "DOMAIN_INFO" },
+ { WINBINDD_NETBIOS_NAME, winbindd_netbios_name, "NETBIOS_NAME" },
+ { WINBINDD_PRIV_PIPE_DIR, winbindd_priv_pipe_dir,
+ "WINBINDD_PRIV_PIPE_DIR" },
+ { WINBINDD_GETDCNAME, winbindd_getdcname, "GETDCNAME" },
+ { WINBINDD_DSGETDCNAME, winbindd_dsgetdcname, "DSGETDCNAME" },
+
+ /* Credential cache access */
+ { WINBINDD_CCACHE_NTLMAUTH, winbindd_ccache_ntlm_auth, "NTLMAUTH" },
+
+ /* WINS functions */
+
+ { WINBINDD_WINS_BYNAME, winbindd_wins_byname, "WINS_BYNAME" },
+ { WINBINDD_WINS_BYIP, winbindd_wins_byip, "WINS_BYIP" },
+
+ /* End of list */
+
+ { WINBINDD_NUM_CMDS, NULL, "NONE" }
+};
+
+static void process_request(struct winbindd_cli_state *state)
+{
+ struct winbindd_dispatch_table *table = dispatch_table;
+
+ /* Free response data - we may be interrupted and receive another
+ command before being able to send this data off. */
+
+ SAFE_FREE(state->response.extra_data.data);
+
+ ZERO_STRUCT(state->response);
+
+ state->response.result = WINBINDD_PENDING;
+ state->response.length = sizeof(struct winbindd_response);
+
+ state->mem_ctx = talloc_init("winbind request");
+ if (state->mem_ctx == NULL)
+ return;
+
+ /* Remember who asked us. */
+ state->pid = state->request.pid;
+
+ /* Process command */
+
+ for (table = dispatch_table; table->fn; table++) {
+ if (state->request.cmd == table->cmd) {
+ DEBUG(10,("process_request: request fn %s\n",
+ table->winbindd_cmd_name ));
+ table->fn(state);
+ break;
+ }
+ }
+
+ if (!table->fn) {
+ DEBUG(10,("process_request: unknown request fn number %d\n",
+ (int)state->request.cmd ));
+ request_error(state);
+ }
+}
+
+/*
+ * A list of file descriptors being monitored by select in the main processing
+ * loop. fd_event->handler is called whenever the socket is readable/writable.
+ */
+
+static struct fd_event *fd_events = NULL;
+
+void add_fd_event(struct fd_event *ev)
+{
+ struct fd_event *match;
+
+ /* only add unique fd_event structs */
+
+ for (match=fd_events; match; match=match->next ) {
+#ifdef DEVELOPER
+ SMB_ASSERT( match != ev );
+#else
+ if ( match == ev )
+ return;
+#endif
+ }
+
+ DLIST_ADD(fd_events, ev);
+}
+
+void remove_fd_event(struct fd_event *ev)
+{
+ DLIST_REMOVE(fd_events, ev);
+}
+
+/*
+ * Handler for fd_events to complete a read/write request, set up by
+ * setup_async_read/setup_async_write.
+ */
+
+static void rw_callback(struct fd_event *event, int flags)
+{
+ size_t todo;
+ ssize_t done = 0;
+
+ todo = event->length - event->done;
+
+ if (event->flags & EVENT_FD_WRITE) {
+ SMB_ASSERT(flags == EVENT_FD_WRITE);
+ done = sys_write(event->fd,
+ &((char *)event->data)[event->done],
+ todo);
+
+ if (done <= 0) {
+ event->flags = 0;
+ event->finished(event->private_data, False);
+ return;
+ }
+ }
+
+ if (event->flags & EVENT_FD_READ) {
+ SMB_ASSERT(flags == EVENT_FD_READ);
+ done = sys_read(event->fd, &((char *)event->data)[event->done],
+ todo);
+
+ if (done <= 0) {
+ event->flags = 0;
+ event->finished(event->private_data, False);
+ return;
+ }
+ }
+
+ event->done += done;
+
+ if (event->done == event->length) {
+ event->flags = 0;
+ event->finished(event->private_data, True);
+ }
+}
+
+/*
+ * Request an async read/write on a fd_event structure. (*finished) is called
+ * when the request is completed or an error had occurred.
+ */
+
+void setup_async_read(struct fd_event *event, void *data, size_t length,
+ void (*finished)(void *private_data, bool success),
+ void *private_data)
+{
+ SMB_ASSERT(event->flags == 0);
+ event->data = data;
+ event->length = length;
+ event->done = 0;
+ event->handler = rw_callback;
+ event->finished = finished;
+ event->private_data = private_data;
+ event->flags = EVENT_FD_READ;
+}
+
+void setup_async_write(struct fd_event *event, void *data, size_t length,
+ void (*finished)(void *private_data, bool success),
+ void *private_data)
+{
+ SMB_ASSERT(event->flags == 0);
+ event->data = data;
+ event->length = length;
+ event->done = 0;
+ event->handler = rw_callback;
+ event->finished = finished;
+ event->private_data = private_data;
+ event->flags = EVENT_FD_WRITE;
+}
+
+/*
+ * This is the main event loop of winbind requests. It goes through a
+ * state-machine of 3 read/write requests, 4 if you have extra data to send.
+ *
+ * An idle winbind client has a read request of 4 bytes outstanding,
+ * finalizing function is request_len_recv, checking the length. request_recv
+ * then processes the packet. The processing function then at some point has
+ * to call request_finished which schedules sending the response.
+ */
+
+static void request_len_recv(void *private_data, bool success);
+static void request_recv(void *private_data, bool success);
+static void request_main_recv(void *private_data, bool success);
+static void request_finished(struct winbindd_cli_state *state);
+static void response_main_sent(void *private_data, bool success);
+static void response_extra_sent(void *private_data, bool success);
+
+static void response_extra_sent(void *private_data, bool success)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private_data, struct winbindd_cli_state);
+
+ TALLOC_FREE(state->mem_ctx);
+
+ if (!success) {
+ state->finished = True;
+ return;
+ }
+
+ SAFE_FREE(state->response.extra_data.data);
+
+ setup_async_read(&state->fd_event, &state->request, sizeof(uint32),
+ request_len_recv, state);
+}
+
+static void response_main_sent(void *private_data, bool success)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private_data, struct winbindd_cli_state);
+
+ if (!success) {
+ state->finished = True;
+ return;
+ }
+
+ if (state->response.length == sizeof(state->response)) {
+ TALLOC_FREE(state->mem_ctx);
+
+ setup_async_read(&state->fd_event, &state->request,
+ sizeof(uint32), request_len_recv, state);
+ return;
+ }
+
+ setup_async_write(&state->fd_event, state->response.extra_data.data,
+ state->response.length - sizeof(state->response),
+ response_extra_sent, state);
+}
+
+static void request_finished(struct winbindd_cli_state *state)
+{
+ /* Make sure request.extra_data is freed when finish processing a request */
+ SAFE_FREE(state->request.extra_data.data);
+ setup_async_write(&state->fd_event, &state->response,
+ sizeof(state->response), response_main_sent, state);
+}
+
+void request_error(struct winbindd_cli_state *state)
+{
+ SMB_ASSERT(state->response.result == WINBINDD_PENDING);
+ state->response.result = WINBINDD_ERROR;
+ request_finished(state);
+}
+
+void request_ok(struct winbindd_cli_state *state)
+{
+ SMB_ASSERT(state->response.result == WINBINDD_PENDING);
+ state->response.result = WINBINDD_OK;
+ request_finished(state);
+}
+
+static void request_len_recv(void *private_data, bool success)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private_data, struct winbindd_cli_state);
+
+ if (!success) {
+ state->finished = True;
+ return;
+ }
+
+ if (*(uint32 *)(&state->request) != sizeof(state->request)) {
+ DEBUG(0,("request_len_recv: Invalid request size received: %d (expected %u)\n",
+ *(uint32_t *)(&state->request), (uint32_t)sizeof(state->request)));
+ state->finished = True;
+ return;
+ }
+
+ setup_async_read(&state->fd_event, (uint32 *)(&state->request)+1,
+ sizeof(state->request) - sizeof(uint32),
+ request_main_recv, state);
+}
+
+static void request_main_recv(void *private_data, bool success)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private_data, struct winbindd_cli_state);
+
+ if (!success) {
+ state->finished = True;
+ return;
+ }
+
+ if (state->request.extra_len == 0) {
+ state->request.extra_data.data = NULL;
+ request_recv(state, True);
+ return;
+ }
+
+ if ((!state->privileged) &&
+ (state->request.extra_len > WINBINDD_MAX_EXTRA_DATA)) {
+ DEBUG(3, ("Got request with %d bytes extra data on "
+ "unprivileged socket\n", (int)state->request.extra_len));
+ state->request.extra_data.data = NULL;
+ state->finished = True;
+ return;
+ }
+
+ state->request.extra_data.data =
+ SMB_MALLOC_ARRAY(char, state->request.extra_len + 1);
+
+ if (state->request.extra_data.data == NULL) {
+ DEBUG(0, ("malloc failed\n"));
+ state->finished = True;
+ return;
+ }
+
+ /* Ensure null termination */
+ state->request.extra_data.data[state->request.extra_len] = '\0';
+
+ setup_async_read(&state->fd_event, state->request.extra_data.data,
+ state->request.extra_len, request_recv, state);
+}
+
+static void request_recv(void *private_data, bool success)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private_data, struct winbindd_cli_state);
+
+ if (!success) {
+ state->finished = True;
+ return;
+ }
+
+ process_request(state);
+}
+
+/* Process a new connection by adding it to the client connection list */
+
+static void new_connection(int listen_sock, bool privileged)
+{
+ struct sockaddr_un sunaddr;
+ struct winbindd_cli_state *state;
+ socklen_t len;
+ int sock;
+
+ /* Accept connection */
+
+ len = sizeof(sunaddr);
+
+ do {
+ sock = accept(listen_sock, (struct sockaddr *)&sunaddr, &len);
+ } while (sock == -1 && errno == EINTR);
+
+ if (sock == -1)
+ return;
+
+ DEBUG(6,("accepted socket %d\n", sock));
+
+ /* Create new connection structure */
+
+ if ((state = TALLOC_ZERO_P(NULL, struct winbindd_cli_state)) == NULL) {
+ close(sock);
+ return;
+ }
+
+ state->sock = sock;
+
+ state->last_access = time(NULL);
+
+ state->privileged = privileged;
+
+ state->fd_event.fd = state->sock;
+ state->fd_event.flags = 0;
+ add_fd_event(&state->fd_event);
+
+ setup_async_read(&state->fd_event, &state->request, sizeof(uint32),
+ request_len_recv, state);
+
+ /* Add to connection list */
+
+ winbindd_add_client(state);
+}
+
+/* Remove a client connection from client connection list */
+
+static void remove_client(struct winbindd_cli_state *state)
+{
+ /* It's a dead client - hold a funeral */
+
+ if (state == NULL) {
+ return;
+ }
+
+ /* Close socket */
+
+ close(state->sock);
+
+ /* Free any getent state */
+
+ free_getent_state(state->getpwent_state);
+ free_getent_state(state->getgrent_state);
+
+ /* We may have some extra data that was not freed if the client was
+ killed unexpectedly */
+
+ SAFE_FREE(state->response.extra_data.data);
+
+ TALLOC_FREE(state->mem_ctx);
+
+ remove_fd_event(&state->fd_event);
+
+ /* Remove from list and free */
+
+ winbindd_remove_client(state);
+ TALLOC_FREE(state);
+}
+
+/* Shutdown client connection which has been idle for the longest time */
+
+static bool remove_idle_client(void)
+{
+ struct winbindd_cli_state *state, *remove_state = NULL;
+ time_t last_access = 0;
+ int nidle = 0;
+
+ for (state = winbindd_client_list(); state; state = state->next) {
+ if (state->response.result != WINBINDD_PENDING &&
+ !state->getpwent_state && !state->getgrent_state) {
+ nidle++;
+ if (!last_access || state->last_access < last_access) {
+ last_access = state->last_access;
+ remove_state = state;
+ }
+ }
+ }
+
+ if (remove_state) {
+ DEBUG(5,("Found %d idle client connections, shutting down sock %d, pid %u\n",
+ nidle, remove_state->sock, (unsigned int)remove_state->pid));
+ remove_client(remove_state);
+ return True;
+ }
+
+ return False;
+}
+
+/* check if HUP has been received and reload files */
+void winbind_check_sighup(const char *logfile)
+{
+ if (do_sighup) {
+
+ DEBUG(3, ("got SIGHUP\n"));
+
+ flush_caches();
+ reload_services_file(logfile);
+
+ do_sighup = False;
+ }
+}
+
+/* check if TERM has been received */
+void winbind_check_sigterm(bool is_parent)
+{
+ if (do_sigterm)
+ terminate(is_parent);
+}
+
+/* Process incoming clients on listen_sock. We use a tricky non-blocking,
+ non-forking, non-threaded model which allows us to handle many
+ simultaneous connections while remaining impervious to many denial of
+ service attacks. */
+
+static void process_loop(void)
+{
+ struct winbindd_cli_state *state;
+ struct fd_event *ev;
+ fd_set r_fds, w_fds;
+ int maxfd, listen_sock, listen_priv_sock, selret;
+ struct timeval timeout, ev_timeout;
+
+ /* Open Sockets here to get stuff going ASAP */
+ listen_sock = open_winbindd_socket();
+ listen_priv_sock = open_winbindd_priv_socket();
+
+ if (listen_sock == -1 || listen_priv_sock == -1) {
+ perror("open_winbind_socket");
+ exit(1);
+ }
+
+ /* We'll be doing this a lot */
+
+ /* Handle messages */
+
+ message_dispatch(winbind_messaging_context());
+
+ run_events(winbind_event_context(), 0, NULL, NULL);
+
+ /* refresh the trusted domain cache */
+
+ rescan_trusted_domains();
+
+ /* Initialise fd lists for select() */
+
+ maxfd = MAX(listen_sock, listen_priv_sock);
+
+ FD_ZERO(&r_fds);
+ FD_ZERO(&w_fds);
+ FD_SET(listen_sock, &r_fds);
+ FD_SET(listen_priv_sock, &r_fds);
+
+ timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
+ timeout.tv_usec = 0;
+
+ /* Check for any event timeouts. */
+ if (get_timed_events_timeout(winbind_event_context(), &ev_timeout)) {
+ timeout = timeval_min(&timeout, &ev_timeout);
+ }
+
+ /* Set up client readers and writers */
+
+ state = winbindd_client_list();
+
+ while (state) {
+
+ struct winbindd_cli_state *next = state->next;
+
+ /* Dispose of client connection if it is marked as
+ finished */
+
+ if (state->finished)
+ remove_client(state);
+
+ state = next;
+ }
+
+ for (ev = fd_events; ev; ev = ev->next) {
+ if (ev->flags & EVENT_FD_READ) {
+ FD_SET(ev->fd, &r_fds);
+ maxfd = MAX(ev->fd, maxfd);
+ }
+ if (ev->flags & EVENT_FD_WRITE) {
+ FD_SET(ev->fd, &w_fds);
+ maxfd = MAX(ev->fd, maxfd);
+ }
+ }
+
+ /* Call select */
+
+ selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
+
+ if (selret == 0) {
+ goto no_fds_ready;
+ }
+
+ if (selret == -1) {
+ if (errno == EINTR) {
+ goto no_fds_ready;
+ }
+
+ /* Select error, something is badly wrong */
+
+ perror("select");
+ exit(1);
+ }
+
+ /* selret > 0 */
+
+ ev = fd_events;
+ while (ev != NULL) {
+ struct fd_event *next = ev->next;
+ int flags = 0;
+ if (FD_ISSET(ev->fd, &r_fds))
+ flags |= EVENT_FD_READ;
+ if (FD_ISSET(ev->fd, &w_fds))
+ flags |= EVENT_FD_WRITE;
+ if (flags)
+ ev->handler(ev, flags);
+ ev = next;
+ }
+
+ if (FD_ISSET(listen_sock, &r_fds)) {
+ while (winbindd_num_clients() >
+ WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
+ DEBUG(5,("winbindd: Exceeding %d client "
+ "connections, removing idle "
+ "connection.\n",
+ WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
+ if (!remove_idle_client()) {
+ DEBUG(0,("winbindd: Exceeding %d "
+ "client connections, no idle "
+ "connection found\n",
+ WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
+ break;
+ }
+ }
+ /* new, non-privileged connection */
+ new_connection(listen_sock, False);
+ }
+
+ if (FD_ISSET(listen_priv_sock, &r_fds)) {
+ while (winbindd_num_clients() >
+ WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
+ DEBUG(5,("winbindd: Exceeding %d client "
+ "connections, removing idle "
+ "connection.\n",
+ WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
+ if (!remove_idle_client()) {
+ DEBUG(0,("winbindd: Exceeding %d "
+ "client connections, no idle "
+ "connection found\n",
+ WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
+ break;
+ }
+ }
+ /* new, privileged connection */
+ new_connection(listen_priv_sock, True);
+ }
+
+ no_fds_ready:
+
+#if 0
+ winbindd_check_cache_size(time(NULL));
+#endif
+
+ /* Check signal handling things */
+
+ winbind_check_sigterm(true);
+ winbind_check_sighup(NULL);
+
+ if (do_sigusr2) {
+ print_winbindd_status();
+ do_sigusr2 = False;
+ }
+
+ if (do_sigchld) {
+ pid_t pid;
+
+ do_sigchld = False;
+
+ while ((pid = sys_waitpid(-1, NULL, WNOHANG)) > 0) {
+ winbind_child_died(pid);
+ }
+ }
+}
+
+/* Main function */
+
+int main(int argc, char **argv, char **envp)
+{
+ static bool is_daemon = False;
+ static bool Fork = True;
+ static bool log_stdout = False;
+ static bool no_process_group = False;
+ enum {
+ OPT_DAEMON = 1000,
+ OPT_FORK,
+ OPT_NO_PROCESS_GROUP,
+ OPT_LOG_STDOUT
+ };
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "stdout", 'S', POPT_ARG_NONE, NULL, OPT_LOG_STDOUT, "Log to stdout" },
+ { "foreground", 'F', POPT_ARG_NONE, NULL, OPT_FORK, "Daemon in foreground mode" },
+ { "no-process-group", 0, POPT_ARG_NONE, NULL, OPT_NO_PROCESS_GROUP, "Don't create a new process group" },
+ { "daemon", 'D', POPT_ARG_NONE, NULL, OPT_DAEMON, "Become a daemon (default)" },
+ { "interactive", 'i', POPT_ARG_NONE, NULL, 'i', "Interactive mode" },
+ { "no-caching", 'n', POPT_ARG_NONE, NULL, 'n', "Disable caching" },
+ POPT_COMMON_SAMBA
+ POPT_TABLEEND
+ };
+ poptContext pc;
+ int opt;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ /* glibc (?) likes to print "User defined signal 1" and exit if a
+ SIGUSR[12] is received before a handler is installed */
+
+ CatchSignal(SIGUSR1, SIG_IGN);
+ CatchSignal(SIGUSR2, SIG_IGN);
+
+ fault_setup((void (*)(void *))fault_quit );
+ dump_core_setup("winbindd");
+
+ load_case_tables();
+
+ /* Initialise for running in non-root mode */
+
+ sec_init();
+
+ set_remote_machine_name("winbindd", False);
+
+ /* Set environment variable so we don't recursively call ourselves.
+ This may also be useful interactively. */
+
+ if ( !winbind_off() ) {
+ DEBUG(0,("Failed to disable recusive winbindd calls. Exiting.\n"));
+ exit(1);
+ }
+
+ /* Initialise samba/rpc client stuff */
+
+ pc = poptGetContext("winbindd", argc, (const char **)argv, long_options, 0);
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ /* Don't become a daemon */
+ case OPT_DAEMON:
+ is_daemon = True;
+ break;
+ case 'i':
+ interactive = True;
+ log_stdout = True;
+ Fork = False;
+ break;
+ case OPT_FORK:
+ Fork = false;
+ break;
+ case OPT_NO_PROCESS_GROUP:
+ no_process_group = true;
+ break;
+ case OPT_LOG_STDOUT:
+ log_stdout = true;
+ break;
+ case 'n':
+ opt_nocache = true;
+ break;
+ default:
+ d_fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+ }
+
+ if (is_daemon && interactive) {
+ d_fprintf(stderr,"\nERROR: "
+ "Option -i|--interactive is not allowed together with -D|--daemon\n\n");
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+
+ if (log_stdout && Fork) {
+ d_fprintf(stderr, "\nERROR: "
+ "Can't log to stdout (-S) unless daemon is in foreground +(-F) or interactive (-i)\n\n");
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+
+ poptFreeContext(pc);
+
+ if (!override_logfile) {
+ char *logfile = NULL;
+ if (asprintf(&logfile,"%s/log.winbindd",
+ get_dyn_LOGFILEBASE()) > 0) {
+ lp_set_logfile(logfile);
+ SAFE_FREE(logfile);
+ }
+ }
+ setup_logging("winbindd", log_stdout);
+ reopen_logs();
+
+ DEBUG(0,("winbindd version %s started.\n", SAMBA_VERSION_STRING));
+ DEBUGADD(0,("%s\n", COPYRIGHT_STARTUP_MESSAGE));
+
+ if (!lp_load_initial_only(get_dyn_CONFIGFILE())) {
+ DEBUG(0, ("error opening config file\n"));
+ exit(1);
+ }
+
+ /* Initialise messaging system */
+
+ if (winbind_messaging_context() == NULL) {
+ exit(1);
+ }
+
+ if (!reload_services_file(NULL)) {
+ DEBUG(0, ("error opening config file\n"));
+ exit(1);
+ }
+
+ if (!directory_exist(lp_lockdir(), NULL)) {
+ mkdir(lp_lockdir(), 0755);
+ }
+
+ /* Setup names. */
+
+ if (!init_names())
+ exit(1);
+
+ load_interfaces();
+
+ if (!secrets_init()) {
+
+ DEBUG(0,("Could not initialize domain trust account secrets. Giving up\n"));
+ return False;
+ }
+
+ /* Enable netbios namecache */
+
+ namecache_enable();
+
+ /* Unblock all signals we are interested in as they may have been
+ blocked by the parent process. */
+
+ BlockSignals(False, SIGINT);
+ BlockSignals(False, SIGQUIT);
+ BlockSignals(False, SIGTERM);
+ BlockSignals(False, SIGUSR1);
+ BlockSignals(False, SIGUSR2);
+ BlockSignals(False, SIGHUP);
+ BlockSignals(False, SIGCHLD);
+
+ /* Setup signal handlers */
+
+ CatchSignal(SIGINT, termination_handler); /* Exit on these sigs */
+ CatchSignal(SIGQUIT, termination_handler);
+ CatchSignal(SIGTERM, termination_handler);
+ CatchSignal(SIGCHLD, sigchld_handler);
+
+ CatchSignal(SIGPIPE, SIG_IGN); /* Ignore sigpipe */
+
+ CatchSignal(SIGUSR2, sigusr2_handler); /* Debugging sigs */
+ CatchSignal(SIGHUP, sighup_handler);
+
+ if (!interactive)
+ become_daemon(Fork, no_process_group);
+
+ pidfile_create("winbindd");
+
+#if HAVE_SETPGID
+ /*
+ * If we're interactive we want to set our own process group for
+ * signal management.
+ */
+ if (interactive && !no_process_group)
+ setpgid( (pid_t)0, (pid_t)0);
+#endif
+
+ TimeInit();
+
+ if (!reinit_after_fork(winbind_messaging_context(), false)) {
+ DEBUG(0,("reinit_after_fork() failed\n"));
+ exit(1);
+ }
+
+ /*
+ * Ensure all cache and idmap caches are consistent
+ * and initialized before we startup.
+ */
+ if (!winbindd_cache_validate_and_initialize()) {
+ exit(1);
+ }
+
+ /* get broadcast messages */
+ claim_connection(NULL,"",FLAG_MSG_GENERAL|FLAG_MSG_DBWRAP);
+
+ /* React on 'smbcontrol winbindd reload-config' in the same way
+ as to SIGHUP signal */
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_SMB_CONF_UPDATED, msg_reload_services);
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_SHUTDOWN, msg_shutdown);
+
+ /* Handle online/offline messages. */
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_WINBIND_OFFLINE, winbind_msg_offline);
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_WINBIND_ONLINE, winbind_msg_online);
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_WINBIND_ONLINESTATUS, winbind_msg_onlinestatus);
+
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_DUMP_EVENT_LIST, winbind_msg_dump_event_list);
+
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_WINBIND_VALIDATE_CACHE,
+ winbind_msg_validate_cache);
+
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_WINBIND_DUMP_DOMAIN_LIST,
+ winbind_msg_dump_domain_list);
+
+ /* Register handler for MSG_DEBUG. */
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_DEBUG,
+ winbind_msg_debug);
+
+ netsamlogon_cache_init(); /* Non-critical */
+
+ /* clear the cached list of trusted domains */
+
+ wcache_tdc_clear();
+
+ if (!init_domain_list()) {
+ DEBUG(0,("unable to initialize domain list\n"));
+ exit(1);
+ }
+
+ init_idmap_child();
+ init_locator_child();
+
+ smb_nscd_flush_user_cache();
+ smb_nscd_flush_group_cache();
+
+ /* Loop waiting for requests */
+
+ TALLOC_FREE(frame);
+ while (1) {
+ frame = talloc_stackframe();
+ process_loop();
+ TALLOC_FREE(frame);
+ }
+
+ return 0;
+}
diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h
new file mode 100644
index 0000000000..04b0b39f81
--- /dev/null
+++ b/source3/winbindd/winbindd.h
@@ -0,0 +1,393 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon for ntdom nss module
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _WINBINDD_H
+#define _WINBINDD_H
+
+#include "nsswitch/winbind_struct_protocol.h"
+#include "nsswitch/libwbclient/wbclient.h"
+
+#ifdef HAVE_LIBNSCD
+#include <libnscd.h>
+#endif
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+#define WB_REPLACE_CHAR '_'
+
+/* bits for fd_event.flags */
+#define EVENT_FD_READ 1
+#define EVENT_FD_WRITE 2
+
+struct fd_event {
+ struct fd_event *next, *prev;
+ int fd;
+ int flags; /* see EVENT_FD_* flags */
+ void (*handler)(struct fd_event *fde, int flags);
+ void *data;
+ size_t length, done;
+ void (*finished)(void *private_data, bool success);
+ void *private_data;
+};
+
+struct sid_ctr {
+ DOM_SID *sid;
+ bool finished;
+ const char *domain;
+ const char *name;
+ enum lsa_SidType type;
+};
+
+struct winbindd_cli_state {
+ struct winbindd_cli_state *prev, *next; /* Linked list pointers */
+ int sock; /* Open socket from client */
+ struct fd_event fd_event;
+ pid_t pid; /* pid of client */
+ bool finished; /* Can delete from list */
+ bool write_extra_data; /* Write extra_data field */
+ time_t last_access; /* Time of last access (read or write) */
+ bool privileged; /* Is the client 'privileged' */
+
+ TALLOC_CTX *mem_ctx; /* memory per request */
+ struct winbindd_request request; /* Request from client */
+ struct winbindd_response response; /* Respose to client */
+ bool getpwent_initialized; /* Has getpwent_state been
+ * initialized? */
+ bool getgrent_initialized; /* Has getgrent_state been
+ * initialized? */
+ struct getent_state *getpwent_state; /* State for getpwent() */
+ struct getent_state *getgrent_state; /* State for getgrent() */
+};
+
+/* State between get{pw,gr}ent() calls */
+
+struct getent_state {
+ struct getent_state *prev, *next;
+ void *sam_entries;
+ uint32 sam_entry_index, num_sam_entries;
+ bool got_sam_entries;
+ fstring domain_name;
+};
+
+/* Storage for cached getpwent() user entries */
+
+struct getpwent_user {
+ fstring name; /* Account name */
+ fstring gecos; /* User information */
+ fstring homedir; /* User Home Directory */
+ fstring shell; /* User Login Shell */
+ DOM_SID user_sid; /* NT user and primary group SIDs */
+ DOM_SID group_sid;
+};
+
+/* Server state structure */
+
+typedef struct {
+ char *acct_name;
+ char *full_name;
+ char *homedir;
+ char *shell;
+ gid_t primary_gid; /* allow the nss_info
+ backend to set the primary group */
+ DOM_SID user_sid; /* NT user and primary group SIDs */
+ DOM_SID group_sid;
+} WINBIND_USERINFO;
+
+/* Our connection to the DC */
+
+struct winbindd_cm_conn {
+ struct cli_state *cli;
+
+ struct rpc_pipe_client *samr_pipe;
+ POLICY_HND sam_connect_handle, sam_domain_handle;
+
+ struct rpc_pipe_client *lsa_pipe;
+ POLICY_HND lsa_policy;
+
+ struct rpc_pipe_client *netlogon_pipe;
+};
+
+struct winbindd_async_request;
+
+/* Async child */
+
+struct winbindd_domain;
+
+struct winbindd_child_dispatch_table {
+ const char *name;
+ enum winbindd_cmd struct_cmd;
+ enum winbindd_result (*struct_fn)(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+};
+
+struct winbindd_child {
+ struct winbindd_child *next, *prev;
+
+ pid_t pid;
+ struct winbindd_domain *domain;
+ char *logfilename;
+
+ struct fd_event event;
+ struct timed_event *lockout_policy_event;
+ struct timed_event *machine_password_change_event;
+ struct winbindd_async_request *requests;
+
+ const struct winbindd_child_dispatch_table *table;
+};
+
+/* Structures to hold per domain information */
+
+struct winbindd_domain {
+ fstring name; /* Domain name (NetBIOS) */
+ fstring alt_name; /* alt Domain name, if any (FQDN for ADS) */
+ fstring forest_name; /* Name of the AD forest we're in */
+ DOM_SID sid; /* SID for this domain */
+ uint32 domain_flags; /* Domain flags from netlogon.h */
+ uint32 domain_type; /* Domain type from netlogon.h */
+ uint32 domain_trust_attribs; /* Trust attribs from netlogon.h */
+ bool initialized; /* Did we already ask for the domain mode? */
+ bool native_mode; /* is this a win2k domain in native mode ? */
+ bool active_directory; /* is this a win2k active directory ? */
+ bool primary; /* is this our primary domain ? */
+ bool internal; /* BUILTIN and member SAM */
+ bool online; /* is this domain available ? */
+ time_t startup_time; /* When we set "startup" true. */
+ bool startup; /* are we in the first 30 seconds after startup_time ? */
+
+ bool can_do_samlogon_ex; /* Due to the lack of finer control what type
+ * of DC we have, let us try to do a
+ * credential-chain less samlogon_ex call
+ * with AD and schannel. If this fails with
+ * DCERPC_FAULT_OP_RNG_ERROR, then set this
+ * to False. This variable is around so that
+ * we don't have to try _ex every time. */
+
+ /* Lookup methods for this domain (LDAP or RPC) */
+ struct winbindd_methods *methods;
+
+ /* the backend methods are used by the cache layer to find the right
+ backend */
+ struct winbindd_methods *backend;
+
+ /* Private data for the backends (used for connection cache) */
+
+ void *private_data;
+
+ /*
+ * idmap config settings, used to tell the idmap child which
+ * special domain config to use for a mapping
+ */
+ bool have_idmap_config;
+ uint32_t id_range_low, id_range_high;
+
+ /* A working DC */
+ pid_t dc_probe_pid; /* Child we're using to detect the DC. */
+ fstring dcname;
+ struct sockaddr_storage dcaddr;
+
+ /* Sequence number stuff */
+
+ time_t last_seq_check;
+ uint32 sequence_number;
+ NTSTATUS last_status;
+
+ /* The smb connection */
+
+ struct winbindd_cm_conn conn;
+
+ /* The child pid we're talking to */
+
+ struct winbindd_child child;
+
+ /* Callback we use to try put us back online. */
+
+ uint32 check_online_timeout;
+ struct timed_event *check_online_event;
+
+ /* Linked list info */
+
+ struct winbindd_domain *prev, *next;
+};
+
+/* per-domain methods. This is how LDAP vs RPC is selected
+ */
+struct winbindd_methods {
+ /* does this backend provide a consistent view of the data? (ie. is the primary group
+ always correct) */
+ bool consistent;
+
+ /* get a list of users, returning a WINBIND_USERINFO for each one */
+ NTSTATUS (*query_user_list)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ WINBIND_USERINFO **info);
+
+ /* get a list of domain groups */
+ NTSTATUS (*enum_dom_groups)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info);
+
+ /* get a list of domain local groups */
+ NTSTATUS (*enum_local_groups)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info);
+
+ /* convert one user or group name to a sid */
+ NTSTATUS (*name_to_sid)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ enum winbindd_cmd orig_cmd,
+ const char *domain_name,
+ const char *name,
+ DOM_SID *sid,
+ enum lsa_SidType *type);
+
+ /* convert a sid to a user or group name */
+ NTSTATUS (*sid_to_name)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ char **domain_name,
+ char **name,
+ enum lsa_SidType *type);
+
+ NTSTATUS (*rids_to_names)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *domain_sid,
+ uint32 *rids,
+ size_t num_rids,
+ char **domain_name,
+ char ***names,
+ enum lsa_SidType **types);
+
+ /* lookup user info for a given SID */
+ NTSTATUS (*query_user)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ WINBIND_USERINFO *user_info);
+
+ /* lookup all groups that a user is a member of. The backend
+ can also choose to lookup by username or rid for this
+ function */
+ NTSTATUS (*lookup_usergroups)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ uint32 *num_groups, DOM_SID **user_gids);
+
+ /* Lookup all aliases that the sids delivered are member of. This is
+ * to implement 'domain local groups' correctly */
+ NTSTATUS (*lookup_useraliases)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 num_sids,
+ const DOM_SID *sids,
+ uint32 *num_aliases,
+ uint32 **alias_rids);
+
+ /* find all members of the group with the specified group_rid */
+ NTSTATUS (*lookup_groupmem)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group_sid,
+ uint32 *num_names,
+ DOM_SID **sid_mem, char ***names,
+ uint32 **name_types);
+
+ /* return the current global sequence number */
+ NTSTATUS (*sequence_number)(struct winbindd_domain *domain, uint32 *seq);
+
+ /* return the lockout policy */
+ NTSTATUS (*lockout_policy)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ struct samr_DomInfo12 *lockout_policy);
+
+ /* return the lockout policy */
+ NTSTATUS (*password_policy)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ struct samr_DomInfo1 *password_policy);
+
+ /* enumerate trusted domains */
+ NTSTATUS (*trusted_domains)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_domains,
+ char ***names,
+ char ***alt_names,
+ DOM_SID **dom_sids);
+};
+
+/* Used to glue a policy handle and cli_state together */
+
+typedef struct {
+ struct cli_state *cli;
+ POLICY_HND pol;
+} CLI_POLICY_HND;
+
+/* Filled out by IDMAP backends */
+struct winbindd_idmap_methods {
+ /* Called when backend is first loaded */
+ bool (*init)(void);
+
+ bool (*get_sid_from_uid)(uid_t uid, DOM_SID *sid);
+ bool (*get_sid_from_gid)(gid_t gid, DOM_SID *sid);
+
+ bool (*get_uid_from_sid)(DOM_SID *sid, uid_t *uid);
+ bool (*get_gid_from_sid)(DOM_SID *sid, gid_t *gid);
+
+ /* Called when backend is unloaded */
+ bool (*close)(void);
+ /* Called to dump backend status */
+ void (*status)(void);
+};
+
+/* Data structures for dealing with the trusted domain cache */
+
+struct winbindd_tdc_domain {
+ const char *domain_name;
+ const char *dns_name;
+ DOM_SID sid;
+ uint32 trust_flags;
+ uint32 trust_attribs;
+ uint32 trust_type;
+};
+
+/* Switch for listing users or groups */
+enum ent_type {
+ LIST_USERS = 0,
+ LIST_GROUPS,
+};
+
+#include "winbindd/winbindd_proto.h"
+
+#define WINBINDD_ESTABLISH_LOOP 30
+#define WINBINDD_RESCAN_FREQ lp_winbind_cache_time()
+#define WINBINDD_PAM_AUTH_KRB5_RENEW_TIME 2592000 /* one month */
+#define DOM_SEQUENCE_NONE ((uint32)-1)
+
+#define IS_DOMAIN_OFFLINE(x) ( lp_winbind_offline_logon() && \
+ ( get_global_winbindd_state_offline() \
+ || !(x)->online ) )
+#define IS_DOMAIN_ONLINE(x) (!IS_DOMAIN_OFFLINE(x))
+
+#endif /* _WINBINDD_H */
diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c
new file mode 100644
index 0000000000..894e7866b3
--- /dev/null
+++ b/source3/winbindd/winbindd_ads.c
@@ -0,0 +1,1354 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind ADS backend functions
+
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
+ Copyright (C) Gerald (Jerry) Carter 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#ifdef HAVE_ADS
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+extern struct winbindd_methods reconnect_methods;
+
+/*
+ return our ads connections structure for a domain. We keep the connection
+ open to make things faster
+*/
+static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ fstring dc_name;
+ struct sockaddr_storage dc_ss;
+
+ DEBUG(10,("ads_cached_connection\n"));
+
+ if (domain->private_data) {
+
+ time_t expire;
+ time_t now = time(NULL);
+
+ /* check for a valid structure */
+ ads = (ADS_STRUCT *)domain->private_data;
+
+ expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
+
+ DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
+ (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
+
+ if ( ads->config.realm && (expire > now)) {
+ return ads;
+ } else {
+ /* we own this ADS_STRUCT so make sure it goes away */
+ DEBUG(7,("Deleting expired krb5 credential cache\n"));
+ ads->is_mine = True;
+ ads_destroy( &ads );
+ ads_kdestroy("MEMORY:winbind_ccache");
+ domain->private_data = NULL;
+ }
+ }
+
+ /* we don't want this to affect the users ccache */
+ setenv("KRB5CCNAME", "MEMORY:winbind_ccache", 1);
+
+ ads = ads_init(domain->alt_name, domain->name, NULL);
+ if (!ads) {
+ DEBUG(1,("ads_init for domain %s failed\n", domain->name));
+ return NULL;
+ }
+
+ /* the machine acct password might have change - fetch it every time */
+
+ SAFE_FREE(ads->auth.password);
+ SAFE_FREE(ads->auth.realm);
+
+ if ( IS_DC ) {
+ DOM_SID sid;
+ time_t last_set_time;
+
+ if ( !pdb_get_trusteddom_pw( domain->name, &ads->auth.password, &sid, &last_set_time ) ) {
+ ads_destroy( &ads );
+ return NULL;
+ }
+ ads->auth.realm = SMB_STRDUP( ads->server.realm );
+ strupper_m( ads->auth.realm );
+ }
+ else {
+ struct winbindd_domain *our_domain = domain;
+
+ ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
+
+ /* always give preference to the alt_name in our
+ primary domain if possible */
+
+ if ( !domain->primary )
+ our_domain = find_our_domain();
+
+ if ( our_domain->alt_name[0] != '\0' ) {
+ ads->auth.realm = SMB_STRDUP( our_domain->alt_name );
+ strupper_m( ads->auth.realm );
+ }
+ else
+ ads->auth.realm = SMB_STRDUP( lp_realm() );
+ }
+
+ ads->auth.renewable = WINBINDD_PAM_AUTH_KRB5_RENEW_TIME;
+
+ /* Setup the server affinity cache. We don't reaally care
+ about the name. Just setup affinity and the KRB5_CONFIG
+ file. */
+
+ get_dc_name( ads->server.workgroup, ads->server.realm, dc_name, &dc_ss );
+
+ status = ads_connect(ads);
+ if (!ADS_ERR_OK(status) || !ads->config.realm) {
+ DEBUG(1,("ads_connect for domain %s failed: %s\n",
+ domain->name, ads_errstr(status)));
+ ads_destroy(&ads);
+
+ /* if we get ECONNREFUSED then it might be a NT4
+ server, fall back to MSRPC */
+ if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
+ status.err.rc == ECONNREFUSED) {
+ /* 'reconnect_methods' is the MS-RPC backend. */
+ DEBUG(1,("Trying MSRPC methods\n"));
+ domain->backend = &reconnect_methods;
+ }
+ return NULL;
+ }
+
+ /* set the flag that says we don't own the memory even
+ though we do so that ads_destroy() won't destroy the
+ structure we pass back by reference */
+
+ ads->is_mine = False;
+
+ domain->private_data = (void *)ads;
+ return ads;
+}
+
+
+/* Query display info for a realm. This is the basic user list fn */
+static NTSTATUS query_user_list(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ WINBIND_USERINFO **info)
+{
+ ADS_STRUCT *ads = NULL;
+ const char *attrs[] = { "*", NULL };
+ int i, count;
+ ADS_STATUS rc;
+ LDAPMessage *res = NULL;
+ LDAPMessage *msg = NULL;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+ *num_entries = 0;
+
+ DEBUG(3,("ads: query_user_list\n"));
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
+ domain->name));
+ return NT_STATUS_OK;
+ }
+
+ ads = ads_cached_connection(domain);
+
+ if (!ads) {
+ domain->last_status = NT_STATUS_SERVER_DISABLED;
+ goto done;
+ }
+
+ rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
+ if (!ADS_ERR_OK(rc) || !res) {
+ DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
+ goto done;
+ }
+
+ count = ads_count_replies(ads, res);
+ if (count == 0) {
+ DEBUG(1,("query_user_list: No users found\n"));
+ goto done;
+ }
+
+ (*info) = TALLOC_ZERO_ARRAY(mem_ctx, WINBIND_USERINFO, count);
+ if (!*info) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ i = 0;
+
+ for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
+ char *name, *gecos = NULL;
+ char *homedir = NULL;
+ char *shell = NULL;
+ uint32 group;
+ uint32 atype;
+ DOM_SID user_sid;
+ gid_t primary_gid = (gid_t)-1;
+
+ if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
+ ads_atype_map(atype) != SID_NAME_USER) {
+ DEBUG(1,("Not a user account? atype=0x%x\n", atype));
+ continue;
+ }
+
+ name = ads_pull_username(ads, mem_ctx, msg);
+
+ if ( ads_pull_sid( ads, msg, "objectSid", &user_sid ) ) {
+ status = nss_get_info_cached( domain, &user_sid, mem_ctx,
+ ads, msg, &homedir, &shell, &gecos,
+ &primary_gid );
+ }
+
+ if (gecos == NULL) {
+ gecos = ads_pull_string(ads, mem_ctx, msg, "name");
+ }
+
+ if (!ads_pull_sid(ads, msg, "objectSid",
+ &(*info)[i].user_sid)) {
+ DEBUG(1,("No sid for %s !?\n", name));
+ continue;
+ }
+ if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
+ DEBUG(1,("No primary group for %s !?\n", name));
+ continue;
+ }
+
+ (*info)[i].acct_name = name;
+ (*info)[i].full_name = gecos;
+ (*info)[i].homedir = homedir;
+ (*info)[i].shell = shell;
+ (*info)[i].primary_gid = primary_gid;
+ sid_compose(&(*info)[i].group_sid, &domain->sid, group);
+ i++;
+ }
+
+ (*num_entries) = i;
+ status = NT_STATUS_OK;
+
+ DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
+
+done:
+ if (res)
+ ads_msgfree(ads, res);
+
+ return status;
+}
+
+/* list all domain groups */
+static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ ADS_STRUCT *ads = NULL;
+ const char *attrs[] = {"userPrincipalName", "sAMAccountName",
+ "name", "objectSid", NULL};
+ int i, count;
+ ADS_STATUS rc;
+ LDAPMessage *res = NULL;
+ LDAPMessage *msg = NULL;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ const char *filter;
+ bool enum_dom_local_groups = False;
+
+ *num_entries = 0;
+
+ DEBUG(3,("ads: enum_dom_groups\n"));
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
+ domain->name));
+ return NT_STATUS_OK;
+ }
+
+ /* only grab domain local groups for our domain */
+ if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
+ enum_dom_local_groups = True;
+ }
+
+ /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
+ * rollup-fixes:
+ *
+ * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
+ * default value, it MUST be absent. In case of extensible matching the
+ * "dnattr" boolean defaults to FALSE and so it must be only be present
+ * when set to TRUE.
+ *
+ * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
+ * filter using bitwise matching rule then the buggy AD fails to decode
+ * the extensible match. As a workaround set it to TRUE and thereby add
+ * the dnAttributes "dn" field to cope with those older AD versions.
+ * It should not harm and won't put any additional load on the AD since
+ * none of the dn components have a bitmask-attribute.
+ *
+ * Thanks to Ralf Haferkamp for input and testing - Guenther */
+
+ filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
+ ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
+ ADS_LDAP_MATCHING_RULE_BIT_AND,
+ enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
+
+ if (filter == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ ads = ads_cached_connection(domain);
+
+ if (!ads) {
+ domain->last_status = NT_STATUS_SERVER_DISABLED;
+ goto done;
+ }
+
+ rc = ads_search_retry(ads, &res, filter, attrs);
+ if (!ADS_ERR_OK(rc) || !res) {
+ DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
+ goto done;
+ }
+
+ count = ads_count_replies(ads, res);
+ if (count == 0) {
+ DEBUG(1,("enum_dom_groups: No groups found\n"));
+ goto done;
+ }
+
+ (*info) = TALLOC_ZERO_ARRAY(mem_ctx, struct acct_info, count);
+ if (!*info) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ i = 0;
+
+ for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
+ char *name, *gecos;
+ DOM_SID sid;
+ uint32 rid;
+
+ name = ads_pull_username(ads, mem_ctx, msg);
+ gecos = ads_pull_string(ads, mem_ctx, msg, "name");
+ if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
+ DEBUG(1,("No sid for %s !?\n", name));
+ continue;
+ }
+
+ if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
+ DEBUG(1,("No rid for %s !?\n", name));
+ continue;
+ }
+
+ fstrcpy((*info)[i].acct_name, name);
+ fstrcpy((*info)[i].acct_desc, gecos);
+ (*info)[i].rid = rid;
+ i++;
+ }
+
+ (*num_entries) = i;
+
+ status = NT_STATUS_OK;
+
+ DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
+
+done:
+ if (res)
+ ads_msgfree(ads, res);
+
+ return status;
+}
+
+/* list all domain local groups */
+static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ /*
+ * This is a stub function only as we returned the domain
+ * local groups in enum_dom_groups() if the domain->native field
+ * was true. This is a simple performance optimization when
+ * using LDAP.
+ *
+ * if we ever need to enumerate domain local groups separately,
+ * then this optimization in enum_dom_groups() will need
+ * to be split out
+ */
+ *num_entries = 0;
+
+ return NT_STATUS_OK;
+}
+
+/* If you are looking for "dn_lookup": Yes, it used to be here!
+ * It has gone now since it was a major speed bottleneck in
+ * lookup_groupmem (its only use). It has been replaced by
+ * an rpc lookup sids call... R.I.P. */
+
+/* Lookup user information from a rid */
+static NTSTATUS query_user(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ WINBIND_USERINFO *info)
+{
+ ADS_STRUCT *ads = NULL;
+ const char *attrs[] = { "*", NULL };
+ ADS_STATUS rc;
+ int count;
+ LDAPMessage *msg = NULL;
+ char *ldap_exp;
+ char *sidstr;
+ uint32 group_rid;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ struct netr_SamInfo3 *user = NULL;
+
+ DEBUG(3,("ads: query_user\n"));
+
+ info->homedir = NULL;
+ info->shell = NULL;
+ info->primary_gid = (gid_t)-1;
+
+ /* try netsamlogon cache first */
+
+ if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL )
+ {
+
+ DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
+ sid_string_dbg(sid)));
+
+ sid_compose(&info->user_sid, &domain->sid, user->base.rid);
+ sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);
+
+ info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
+ info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);
+
+ nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL,
+ &info->homedir, &info->shell, &info->full_name,
+ &info->primary_gid );
+
+ TALLOC_FREE(user);
+
+ return NT_STATUS_OK;
+ }
+
+ if ( !winbindd_can_contact_domain(domain)) {
+ DEBUG(8,("query_user: No incoming trust from domain %s\n",
+ domain->name));
+
+ /* We still need to generate some basic information
+ about the user even if we cannot contact the
+ domain. Most of this stuff we can deduce. */
+
+ sid_copy( &info->user_sid, sid );
+
+ /* Assume "Domain Users" for the primary group */
+
+ sid_compose(&info->group_sid, &domain->sid, DOMAIN_GROUP_RID_USERS );
+
+ /* Try to fill in what the nss_info backend can do */
+
+ nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL,
+ &info->homedir, &info->shell, &info->full_name,
+ &info->primary_gid );
+
+ status = NT_STATUS_OK;
+ goto done;
+ }
+
+ /* no cache...do the query */
+
+ if ( (ads = ads_cached_connection(domain)) == NULL ) {
+ domain->last_status = NT_STATUS_SERVER_DISABLED;
+ goto done;
+ }
+
+ sidstr = sid_binstring(sid);
+ asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
+ rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
+ free(ldap_exp);
+ free(sidstr);
+ if (!ADS_ERR_OK(rc) || !msg) {
+ DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
+ sid_string_dbg(sid), ads_errstr(rc)));
+ goto done;
+ }
+
+ count = ads_count_replies(ads, msg);
+ if (count != 1) {
+ DEBUG(1,("query_user(sid=%s): Not found\n",
+ sid_string_dbg(sid)));
+ goto done;
+ }
+
+ info->acct_name = ads_pull_username(ads, mem_ctx, msg);
+
+ nss_get_info_cached( domain, sid, mem_ctx, ads, msg,
+ &info->homedir, &info->shell, &info->full_name,
+ &info->primary_gid );
+
+ if (info->full_name == NULL) {
+ info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
+ }
+
+ if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
+ DEBUG(1,("No primary group for %s !?\n",
+ sid_string_dbg(sid)));
+ goto done;
+ }
+
+ sid_copy(&info->user_sid, sid);
+ sid_compose(&info->group_sid, &domain->sid, group_rid);
+
+ status = NT_STATUS_OK;
+
+ DEBUG(3,("ads query_user gave %s\n", info->acct_name));
+done:
+ if (msg)
+ ads_msgfree(ads, msg);
+
+ return status;
+}
+
+/* Lookup groups a user is a member of - alternate method, for when
+ tokenGroups are not available. */
+static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const char *user_dn,
+ DOM_SID *primary_group,
+ size_t *p_num_groups, DOM_SID **user_sids)
+{
+ ADS_STATUS rc;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ int count;
+ LDAPMessage *res = NULL;
+ LDAPMessage *msg = NULL;
+ char *ldap_exp;
+ ADS_STRUCT *ads;
+ const char *group_attrs[] = {"objectSid", NULL};
+ char *escaped_dn;
+ size_t num_groups = 0;
+
+ DEBUG(3,("ads: lookup_usergroups_member\n"));
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
+ domain->name));
+ return NT_STATUS_OK;
+ }
+
+ ads = ads_cached_connection(domain);
+
+ if (!ads) {
+ domain->last_status = NT_STATUS_SERVER_DISABLED;
+ goto done;
+ }
+
+ if (!(escaped_dn = escape_ldap_string_alloc(user_dn))) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ ldap_exp = talloc_asprintf(mem_ctx,
+ "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
+ escaped_dn,
+ ADS_LDAP_MATCHING_RULE_BIT_AND,
+ GROUP_TYPE_SECURITY_ENABLED);
+ if (!ldap_exp) {
+ DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
+ SAFE_FREE(escaped_dn);
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ SAFE_FREE(escaped_dn);
+
+ rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
+
+ if (!ADS_ERR_OK(rc) || !res) {
+ DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
+ return ads_ntstatus(rc);
+ }
+
+ count = ads_count_replies(ads, res);
+
+ *user_sids = NULL;
+ num_groups = 0;
+
+ /* always add the primary group to the sid array */
+ status = add_sid_to_array(mem_ctx, primary_group, user_sids,
+ &num_groups);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (count > 0) {
+ for (msg = ads_first_entry(ads, res); msg;
+ msg = ads_next_entry(ads, msg)) {
+ DOM_SID group_sid;
+
+ if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
+ DEBUG(1,("No sid for this group ?!?\n"));
+ continue;
+ }
+
+ /* ignore Builtin groups from ADS - Guenther */
+ if (sid_check_is_in_builtin(&group_sid)) {
+ continue;
+ }
+
+ status = add_sid_to_array(mem_ctx, &group_sid,
+ user_sids, &num_groups);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ }
+
+ }
+
+ *p_num_groups = num_groups;
+ status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
+
+ DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
+done:
+ if (res)
+ ads_msgfree(ads, res);
+
+ return status;
+}
+
+/* Lookup groups a user is a member of - alternate method, for when
+ tokenGroups are not available. */
+static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const char *user_dn,
+ DOM_SID *primary_group,
+ size_t *p_num_groups, DOM_SID **user_sids)
+{
+ ADS_STATUS rc;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ ADS_STRUCT *ads;
+ const char *attrs[] = {"memberOf", NULL};
+ size_t num_groups = 0;
+ DOM_SID *group_sids = NULL;
+ int i;
+ char **strings;
+ size_t num_strings = 0;
+
+
+ DEBUG(3,("ads: lookup_usergroups_memberof\n"));
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("lookup_usergroups_memberof: No incoming trust for domain %s\n",
+ domain->name));
+ return NT_STATUS_OK;
+ }
+
+ ads = ads_cached_connection(domain);
+
+ if (!ads) {
+ domain->last_status = NT_STATUS_SERVER_DISABLED;
+ goto done;
+ }
+
+ rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
+ ADS_EXTENDED_DN_HEX_STRING,
+ &strings, &num_strings);
+
+ if (!ADS_ERR_OK(rc)) {
+ DEBUG(1,("lookup_usergroups_memberof ads_search member=%s: %s\n",
+ user_dn, ads_errstr(rc)));
+ return ads_ntstatus(rc);
+ }
+
+ *user_sids = NULL;
+ num_groups = 0;
+
+ /* always add the primary group to the sid array */
+ status = add_sid_to_array(mem_ctx, primary_group, user_sids,
+ &num_groups);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ group_sids = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_strings + 1);
+ if (!group_sids) {
+ TALLOC_FREE(strings);
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i=0; i<num_strings; i++) {
+
+ if (!ads_get_sid_from_extended_dn(mem_ctx, strings[i],
+ ADS_EXTENDED_DN_HEX_STRING,
+ &(group_sids)[i])) {
+ TALLOC_FREE(group_sids);
+ TALLOC_FREE(strings);
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ }
+
+ if (i == 0) {
+ DEBUG(1,("No memberOf for this user?!?\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i=0; i<num_strings; i++) {
+
+ /* ignore Builtin groups from ADS - Guenther */
+ if (sid_check_is_in_builtin(&group_sids[i])) {
+ continue;
+ }
+
+ status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
+ &num_groups);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ }
+
+ *p_num_groups = num_groups;
+ status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
+
+ DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n", user_dn));
+done:
+ TALLOC_FREE(group_sids);
+
+ return status;
+}
+
+
+/* Lookup groups a user is a member of. */
+static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ uint32 *p_num_groups, DOM_SID **user_sids)
+{
+ ADS_STRUCT *ads = NULL;
+ const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
+ ADS_STATUS rc;
+ int count;
+ LDAPMessage *msg = NULL;
+ char *user_dn = NULL;
+ DOM_SID *sids;
+ int i;
+ DOM_SID primary_group;
+ uint32 primary_group_rid;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ size_t num_groups = 0;
+
+ DEBUG(3,("ads: lookup_usergroups\n"));
+ *p_num_groups = 0;
+
+ status = lookup_usergroups_cached(domain, mem_ctx, sid,
+ p_num_groups, user_sids);
+ if (NT_STATUS_IS_OK(status)) {
+ return NT_STATUS_OK;
+ }
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
+ domain->name));
+
+ /* Tell the cache manager not to remember this one */
+
+ return NT_STATUS_SYNCHRONIZATION_REQUIRED;
+ }
+
+ ads = ads_cached_connection(domain);
+
+ if (!ads) {
+ domain->last_status = NT_STATUS_SERVER_DISABLED;
+ status = NT_STATUS_SERVER_DISABLED;
+ goto done;
+ }
+
+ rc = ads_search_retry_sid(ads, &msg, sid, attrs);
+
+ if (!ADS_ERR_OK(rc)) {
+ status = ads_ntstatus(rc);
+ DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
+ "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
+ goto done;
+ }
+
+ count = ads_count_replies(ads, msg);
+ if (count != 1) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
+ "invalid number of results (count=%d)\n",
+ sid_string_dbg(sid), count));
+ goto done;
+ }
+
+ if (!msg) {
+ DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
+ sid_string_dbg(sid)));
+ status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ user_dn = ads_get_dn(ads, msg);
+ if (user_dn == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
+ DEBUG(1,("%s: No primary group for sid=%s !?\n",
+ domain->name, sid_string_dbg(sid)));
+ goto done;
+ }
+
+ sid_copy(&primary_group, &domain->sid);
+ sid_append_rid(&primary_group, primary_group_rid);
+
+ count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
+
+ /* there must always be at least one group in the token,
+ unless we are talking to a buggy Win2k server */
+
+ /* actually this only happens when the machine account has no read
+ * permissions on the tokenGroup attribute - gd */
+
+ if (count == 0) {
+
+ /* no tokenGroups */
+
+ /* lookup what groups this user is a member of by DN search on
+ * "memberOf" */
+
+ status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
+ &primary_group,
+ &num_groups, user_sids);
+ *p_num_groups = (uint32)num_groups;
+ if (NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ /* lookup what groups this user is a member of by DN search on
+ * "member" */
+
+ status = lookup_usergroups_member(domain, mem_ctx, user_dn,
+ &primary_group,
+ &num_groups, user_sids);
+ *p_num_groups = (uint32)num_groups;
+ goto done;
+ }
+
+ *user_sids = NULL;
+ num_groups = 0;
+
+ status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
+ &num_groups);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ for (i=0;i<count;i++) {
+
+ /* ignore Builtin groups from ADS - Guenther */
+ if (sid_check_is_in_builtin(&sids[i])) {
+ continue;
+ }
+
+ status = add_sid_to_array_unique(mem_ctx, &sids[i],
+ user_sids, &num_groups);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ }
+
+ *p_num_groups = (uint32)num_groups;
+ status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
+
+ DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
+ sid_string_dbg(sid)));
+done:
+ ads_memfree(ads, user_dn);
+ ads_msgfree(ads, msg);
+ return status;
+}
+
+/*
+ find the members of a group, given a group rid and domain
+ */
+static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group_sid, uint32 *num_names,
+ DOM_SID **sid_mem, char ***names,
+ uint32 **name_types)
+{
+ ADS_STATUS rc;
+ ADS_STRUCT *ads = NULL;
+ char *ldap_exp;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ char *sidbinstr;
+ char **members = NULL;
+ int i;
+ size_t num_members = 0;
+ ads_control args;
+ struct rpc_pipe_client *cli;
+ POLICY_HND lsa_policy;
+ DOM_SID *sid_mem_nocache = NULL;
+ char **names_nocache = NULL;
+ enum lsa_SidType *name_types_nocache = NULL;
+ char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
+ uint32 num_nocache = 0;
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
+ sid_string_dbg(group_sid)));
+
+ *num_names = 0;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (!tmp_ctx) {
+ DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
+ domain->name));
+ return NT_STATUS_OK;
+ }
+
+ ads = ads_cached_connection(domain);
+
+ if (!ads) {
+ domain->last_status = NT_STATUS_SERVER_DISABLED;
+ goto done;
+ }
+
+ if ((sidbinstr = sid_binstring(group_sid)) == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ /* search for all members of the group */
+ if (!(ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)",
+ sidbinstr)))
+ {
+ SAFE_FREE(sidbinstr);
+ DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ SAFE_FREE(sidbinstr);
+
+ args.control = ADS_EXTENDED_DN_OID;
+ args.val = ADS_EXTENDED_DN_HEX_STRING;
+ args.critical = True;
+
+ rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
+ ldap_exp, &args, "member", &members, &num_members);
+
+ if (!ADS_ERR_OK(rc)) {
+ DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
+ status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
+
+ /* Now that we have a list of sids, we need to get the
+ * lists of names and name_types belonging to these sids.
+ * even though conceptually not quite clean, we use the
+ * RPC call lsa_lookup_sids for this since it can handle a
+ * list of sids. ldap calls can just resolve one sid at a time.
+ *
+ * At this stage, the sids are still hidden in the exetended dn
+ * member output format. We actually do a little better than
+ * stated above: In extracting the sids from the member strings,
+ * we try to resolve as many sids as possible from the
+ * cache. Only the rest is passed to the lsa_lookup_sids call. */
+
+ if (num_members) {
+ (*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_members);
+ (*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_members);
+ (*name_types) = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_members);
+ (sid_mem_nocache) = TALLOC_ZERO_ARRAY(tmp_ctx, DOM_SID, num_members);
+
+ if ((members == NULL) || (*sid_mem == NULL) ||
+ (*names == NULL) || (*name_types == NULL) ||
+ (sid_mem_nocache == NULL))
+ {
+ DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ }
+ else {
+ (*sid_mem) = NULL;
+ (*names) = NULL;
+ (*name_types) = NULL;
+ }
+
+ for (i=0; i<num_members; i++) {
+ enum lsa_SidType name_type;
+ char *name, *domain_name;
+ DOM_SID sid;
+
+ if (!ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val, &sid)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+ if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name, &name_type)) {
+ DEBUG(10,("ads: lookup_groupmem: got sid %s from "
+ "cache\n", sid_string_dbg(&sid)));
+ sid_copy(&(*sid_mem)[*num_names], &sid);
+ (*names)[*num_names] = talloc_asprintf(*names, "%s%c%s",
+ domain_name,
+ *lp_winbind_separator(),
+ name );
+
+ (*name_types)[*num_names] = name_type;
+ (*num_names)++;
+ }
+ else {
+ DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
+ "cache\n", sid_string_dbg(&sid)));
+ sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
+ num_nocache++;
+ }
+ }
+
+ DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
+ "%d left for lsa_lookupsids\n", *num_names, num_nocache));
+
+ /* handle sids not resolved from cache by lsa_lookup_sids */
+ if (num_nocache > 0) {
+
+ status = cm_connect_lsa(domain, tmp_ctx, &cli, &lsa_policy);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = rpccli_lsa_lookup_sids(cli, tmp_ctx,
+ &lsa_policy,
+ num_nocache,
+ sid_mem_nocache,
+ &domains_nocache,
+ &names_nocache,
+ &name_types_nocache);
+
+ if (NT_STATUS_IS_OK(status) ||
+ NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
+ {
+ /* Copy the entries over from the "_nocache" arrays
+ * to the result arrays, skipping the gaps the
+ * lookup_sids call left. */
+ for (i=0; i < num_nocache; i++) {
+ if (((names_nocache)[i] != NULL) &&
+ ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
+ {
+ sid_copy(&(*sid_mem)[*num_names],
+ &sid_mem_nocache[i]);
+ (*names)[*num_names] = talloc_asprintf( *names,
+ "%s%c%s",
+ domains_nocache[i],
+ *lp_winbind_separator(),
+ names_nocache[i] );
+ (*name_types)[*num_names] = name_types_nocache[i];
+ (*num_names)++;
+ }
+ }
+ }
+ else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
+ DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
+ "not map any SIDs at all.\n"));
+ /* Don't handle this as an error here.
+ * There is nothing left to do with respect to the
+ * overall result... */
+ }
+ else if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("lookup_groupmem: Error looking up %d "
+ "sids via rpc_lsa_lookup_sids: %s\n",
+ (int)num_members, nt_errstr(status)));
+ goto done;
+ }
+ }
+
+ status = NT_STATUS_OK;
+ DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
+ sid_string_dbg(group_sid)));
+
+done:
+
+ TALLOC_FREE(tmp_ctx);
+
+ return status;
+}
+
+/* find the sequence number for a domain */
+static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
+{
+ ADS_STRUCT *ads = NULL;
+ ADS_STATUS rc;
+
+ DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("sequence: No incoming trust for domain %s\n",
+ domain->name));
+ *seq = time(NULL);
+ return NT_STATUS_OK;
+ }
+
+ *seq = DOM_SEQUENCE_NONE;
+
+ ads = ads_cached_connection(domain);
+
+ if (!ads) {
+ domain->last_status = NT_STATUS_SERVER_DISABLED;
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ rc = ads_USN(ads, seq);
+
+ if (!ADS_ERR_OK(rc)) {
+
+ /* its a dead connection, destroy it */
+
+ if (domain->private_data) {
+ ads = (ADS_STRUCT *)domain->private_data;
+ ads->is_mine = True;
+ ads_destroy(&ads);
+ ads_kdestroy("MEMORY:winbind_ccache");
+ domain->private_data = NULL;
+ }
+ }
+ return ads_ntstatus(rc);
+}
+
+/* get a list of trusted domains */
+static NTSTATUS trusted_domains(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_domains,
+ char ***names,
+ char ***alt_names,
+ DOM_SID **dom_sids)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct netr_DomainTrustList trusts;
+ int i;
+ uint32 flags;
+ struct rpc_pipe_client *cli;
+ uint32 fr_flags = (NETR_TRUST_FLAG_IN_FOREST | NETR_TRUST_FLAG_TREEROOT);
+ int ret_count;
+
+ DEBUG(3,("ads: trusted_domains\n"));
+
+ *num_domains = 0;
+ *alt_names = NULL;
+ *names = NULL;
+ *dom_sids = NULL;
+
+ /* If this is our primary domain or a root in our forest,
+ query for all trusts. If not, then just look for domain
+ trusts in the target forest */
+
+ if ( domain->primary ||
+ ((domain->domain_flags&fr_flags) == fr_flags) )
+ {
+ flags = NETR_TRUST_FLAG_OUTBOUND |
+ NETR_TRUST_FLAG_INBOUND |
+ NETR_TRUST_FLAG_IN_FOREST;
+ } else {
+ flags = NETR_TRUST_FLAG_IN_FOREST;
+ }
+
+ result = cm_connect_netlogon(domain, &cli);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(5, ("trusted_domains: Could not open a connection to %s "
+ "for PIPE_NETLOGON (%s)\n",
+ domain->name, nt_errstr(result)));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ result = rpccli_netr_DsrEnumerateDomainTrusts(cli, mem_ctx,
+ cli->desthost,
+ flags,
+ &trusts,
+ NULL);
+ if ( NT_STATUS_IS_OK(result) && trusts.count) {
+
+ /* Allocate memory for trusted domain names and sids */
+
+ if ( !(*names = TALLOC_ARRAY(mem_ctx, char *, trusts.count)) ) {
+ DEBUG(0, ("trusted_domains: out of memory\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( !(*alt_names = TALLOC_ARRAY(mem_ctx, char *, trusts.count)) ) {
+ DEBUG(0, ("trusted_domains: out of memory\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( !(*dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, trusts.count)) ) {
+ DEBUG(0, ("trusted_domains: out of memory\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Copy across names and sids */
+
+
+ ret_count = 0;
+ for (i = 0; i < trusts.count; i++) {
+ struct winbindd_domain d;
+
+ ZERO_STRUCT(d);
+
+ /* drop external trusts if this is not our primary
+ domain. This means that the returned number of
+ domains may be less that the ones actually trusted
+ by the DC. */
+
+ if ( (trusts.array[i].trust_attributes == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
+ !domain->primary )
+ {
+ DEBUG(10,("trusted_domains: Skipping external trusted domain "
+ "%s because it is outside of our primary domain\n",
+ trusts.array[i].netbios_name));
+ continue;
+ }
+
+ (*names)[ret_count] = CONST_DISCARD(char *, trusts.array[i].netbios_name);
+ (*alt_names)[ret_count] = CONST_DISCARD(char *, trusts.array[i].dns_name);
+ if (trusts.array[i].sid) {
+ sid_copy(&(*dom_sids)[ret_count], trusts.array[i].sid);
+ } else {
+ sid_copy(&(*dom_sids)[ret_count], &global_sid_NULL);
+ }
+
+ /* add to the trusted domain cache */
+
+ fstrcpy( d.name, trusts.array[i].netbios_name);
+ fstrcpy( d.alt_name, trusts.array[i].dns_name);
+ if (trusts.array[i].sid) {
+ sid_copy( &d.sid, trusts.array[i].sid);
+ } else {
+ sid_copy(&d.sid, &global_sid_NULL);
+ }
+
+ if ( domain->primary ) {
+ DEBUG(10,("trusted_domains(ads): Searching "
+ "trusted domain list of %s and storing "
+ "trust flags for domain %s\n",
+ domain->name, d.alt_name));
+
+ d.domain_flags = trusts.array[i].trust_flags;
+ d.domain_type = trusts.array[i].trust_type;
+ d.domain_trust_attribs = trusts.array[i].trust_attributes;
+
+ wcache_tdc_add_domain( &d );
+ ret_count++;
+ } else if ( (domain->domain_flags&fr_flags) == fr_flags ) {
+ /* Check if we already have this record. If
+ * we are following our forest root that is not
+ * our primary domain, we want to keep trust
+ * flags from the perspective of our primary
+ * domain not our forest root. */
+ struct winbindd_tdc_domain *exist = NULL;
+
+ exist =
+ wcache_tdc_fetch_domain(NULL, trusts.array[i].netbios_name);
+ if (!exist) {
+ DEBUG(10,("trusted_domains(ads): Searching "
+ "trusted domain list of %s and storing "
+ "trust flags for domain %s\n",
+ domain->name, d.alt_name));
+ d.domain_flags = trusts.array[i].trust_flags;
+ d.domain_type = trusts.array[i].trust_type;
+ d.domain_trust_attribs = trusts.array[i].trust_attributes;
+
+ wcache_tdc_add_domain( &d );
+ ret_count++;
+ }
+ TALLOC_FREE(exist);
+ } else {
+ /* This gets a little tricky. If we are
+ following a transitive forest trust, then
+ innerit the flags, type, and attribs from
+ the domain we queried to make sure we don't
+ record the view of the trust from the wrong
+ side. Always view it from the side of our
+ primary domain. --jerry */
+ struct winbindd_tdc_domain *parent = NULL;
+
+ DEBUG(10,("trusted_domains(ads): Searching "
+ "trusted domain list of %s and inheriting "
+ "trust flags for domain %s\n",
+ domain->name, d.alt_name));
+
+ parent = wcache_tdc_fetch_domain(NULL, domain->name);
+ if (parent) {
+ d.domain_flags = parent->trust_flags;
+ d.domain_type = parent->trust_type;
+ d.domain_trust_attribs = parent->trust_attribs;
+ } else {
+ d.domain_flags = domain->domain_flags;
+ d.domain_type = domain->domain_type;
+ d.domain_trust_attribs = domain->domain_trust_attribs;
+ }
+ TALLOC_FREE(parent);
+
+ wcache_tdc_add_domain( &d );
+ ret_count++;
+ }
+ }
+
+ *num_domains = ret_count;
+ }
+
+ return result;
+}
+
+/* the ADS backend methods are exposed via this structure */
+struct winbindd_methods ads_methods = {
+ True,
+ query_user_list,
+ enum_dom_groups,
+ enum_local_groups,
+ msrpc_name_to_sid,
+ msrpc_sid_to_name,
+ msrpc_rids_to_names,
+ query_user,
+ lookup_usergroups,
+ msrpc_lookup_useraliases,
+ lookup_groupmem,
+ sequence_number,
+ msrpc_lockout_policy,
+ msrpc_password_policy,
+ trusted_domains,
+};
+
+#endif
diff --git a/source3/winbindd/winbindd_async.c b/source3/winbindd/winbindd_async.c
new file mode 100644
index 0000000000..1481aed8e1
--- /dev/null
+++ b/source3/winbindd/winbindd_async.c
@@ -0,0 +1,1125 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Async helpers for blocking functions
+
+ Copyright (C) Volker Lendecke 2005
+ Copyright (C) Gerald Carter 2006
+
+ The helpers always consist of three functions:
+
+ * A request setup function that takes the necessary parameters together
+ with a continuation function that is to be called upon completion
+
+ * A private continuation function that is internal only. This is to be
+ called by the lower-level functions in do_async(). Its only task is to
+ properly call the continuation function named above.
+
+ * A worker function that is called inside the appropriate child process.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+struct do_async_state {
+ TALLOC_CTX *mem_ctx;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ void (*cont)(TALLOC_CTX *mem_ctx,
+ bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data);
+ void *c, *private_data;
+};
+
+static void do_async_recv(void *private_data, bool success)
+{
+ struct do_async_state *state =
+ talloc_get_type_abort(private_data, struct do_async_state);
+
+ state->cont(state->mem_ctx, success, &state->response,
+ state->c, state->private_data);
+}
+
+void do_async(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
+ const struct winbindd_request *request,
+ void (*cont)(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data),
+ void *c, void *private_data)
+{
+ struct do_async_state *state;
+
+ state = TALLOC_ZERO_P(mem_ctx, struct do_async_state);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ cont(mem_ctx, False, NULL, c, private_data);
+ return;
+ }
+
+ state->mem_ctx = mem_ctx;
+ state->request = *request;
+ state->request.length = sizeof(state->request);
+ state->cont = cont;
+ state->c = c;
+ state->private_data = private_data;
+
+ async_request(mem_ctx, child, &state->request,
+ &state->response, do_async_recv, state);
+}
+
+void do_async_domain(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
+ const struct winbindd_request *request,
+ void (*cont)(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data),
+ void *c, void *private_data)
+{
+ struct do_async_state *state;
+
+ state = TALLOC_ZERO_P(mem_ctx, struct do_async_state);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ cont(mem_ctx, False, NULL, c, private_data);
+ return;
+ }
+
+ state->mem_ctx = mem_ctx;
+ state->request = *request;
+ state->request.length = sizeof(state->request);
+ state->cont = cont;
+ state->c = c;
+ state->private_data = private_data;
+
+ async_domain_request(mem_ctx, domain, &state->request,
+ &state->response, do_async_recv, state);
+}
+
+struct lookupsid_state {
+ DOM_SID sid;
+ void *caller_private_data;
+};
+
+
+static void lookupsid_recv2(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data)
+{
+ void (*cont)(void *priv, bool succ, const char *dom_name,
+ const char *name, enum lsa_SidType type) =
+ (void (*)(void *, bool, const char *, const char *,
+ enum lsa_SidType))c;
+ struct lookupsid_state *s = talloc_get_type_abort(private_data,
+ struct lookupsid_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger lookupsid\n"));
+ cont(s->caller_private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("lookupsid (forest root) returned an error\n"));
+ cont(s->caller_private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ cont(s->caller_private_data, True, response->data.name.dom_name,
+ response->data.name.name,
+ (enum lsa_SidType)response->data.name.type);
+}
+
+static void lookupsid_recv(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data)
+{
+ void (*cont)(void *priv, bool succ, const char *dom_name,
+ const char *name, enum lsa_SidType type) =
+ (void (*)(void *, bool, const char *, const char *,
+ enum lsa_SidType))c;
+ struct lookupsid_state *s = talloc_get_type_abort(private_data,
+ struct lookupsid_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger lookupsid\n"));
+ cont(s->caller_private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ /* Try again using the forest root */
+ struct winbindd_domain *root_domain = find_root_domain();
+ struct winbindd_request request;
+
+ if ( !root_domain ) {
+ DEBUG(5,("lookupsid_recv: unable to determine forest root\n"));
+ cont(s->caller_private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_LOOKUPSID;
+ sid_to_fstring(request.data.sid, &s->sid);
+
+ do_async_domain(mem_ctx, root_domain, &request, lookupsid_recv2,
+ (void *)cont, s);
+
+ return;
+ }
+
+ cont(s->caller_private_data, True, response->data.name.dom_name,
+ response->data.name.name,
+ (enum lsa_SidType)response->data.name.type);
+}
+
+void winbindd_lookupsid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ void (*cont)(void *private_data, bool success,
+ const char *dom_name,
+ const char *name,
+ enum lsa_SidType type),
+ void *private_data)
+{
+ struct winbindd_domain *domain;
+ struct winbindd_request request;
+ struct lookupsid_state *s;
+
+ domain = find_lookup_domain_from_sid(sid);
+ if (domain == NULL) {
+ DEBUG(5, ("Could not find domain for sid %s\n",
+ sid_string_dbg(sid)));
+ cont(private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_LOOKUPSID;
+ sid_to_fstring(request.data.sid, sid);
+
+ if ( (s = TALLOC_ZERO_P(mem_ctx, struct lookupsid_state)) == NULL ) {
+ DEBUG(0, ("winbindd_lookupsid_async: talloc failed\n"));
+ cont(private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ sid_copy( &s->sid, sid );
+ s->caller_private_data = private_data;
+
+ do_async_domain(mem_ctx, domain, &request, lookupsid_recv,
+ (void *)cont, s);
+}
+
+enum winbindd_result winbindd_dual_lookupsid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ enum lsa_SidType type;
+ DOM_SID sid;
+ char *name;
+ char *dom_name;
+
+ /* Ensure null termination */
+ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+ DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
+ state->request.data.sid));
+
+ /* Lookup sid from PDC using lsa_lookup_sids() */
+
+ if (!string_to_sid(&sid, state->request.data.sid)) {
+ DEBUG(5, ("%s not a SID\n", state->request.data.sid));
+ return WINBINDD_ERROR;
+ }
+
+ /* Lookup the sid */
+
+ if (!winbindd_lookup_name_by_sid(state->mem_ctx, domain, &sid,
+ &dom_name, &name, &type))
+ {
+ TALLOC_FREE(dom_name);
+ TALLOC_FREE(name);
+ return WINBINDD_ERROR;
+ }
+
+ fstrcpy(state->response.data.name.dom_name, dom_name);
+ fstrcpy(state->response.data.name.name, name);
+ state->response.data.name.type = type;
+
+ TALLOC_FREE(dom_name);
+ TALLOC_FREE(name);
+ return WINBINDD_OK;
+}
+
+/********************************************************************
+ This is the second callback after contacting the forest root
+********************************************************************/
+
+struct lookupname_state {
+ char *dom_name;
+ char *name;
+ void *caller_private_data;
+};
+
+
+static void lookupname_recv2(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data)
+{
+ void (*cont)(void *priv, bool succ, const DOM_SID *sid,
+ enum lsa_SidType type) =
+ (void (*)(void *, bool, const DOM_SID *, enum lsa_SidType))c;
+ DOM_SID sid;
+ struct lookupname_state *s = talloc_get_type_abort( private_data,
+ struct lookupname_state );
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger lookup_name\n"));
+ cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("lookup_name returned an error\n"));
+ cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ if (!string_to_sid(&sid, response->data.sid.sid)) {
+ DEBUG(0, ("Could not convert string %s to sid\n",
+ response->data.sid.sid));
+ cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ cont(s->caller_private_data, True, &sid,
+ (enum lsa_SidType)response->data.sid.type);
+}
+
+/********************************************************************
+ This is the first callback after contacting our own domain
+********************************************************************/
+
+static void lookupname_recv(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data)
+{
+ void (*cont)(void *priv, bool succ, const DOM_SID *sid,
+ enum lsa_SidType type) =
+ (void (*)(void *, bool, const DOM_SID *, enum lsa_SidType))c;
+ DOM_SID sid;
+ struct lookupname_state *s = talloc_get_type_abort( private_data,
+ struct lookupname_state );
+
+ if (!success) {
+ DEBUG(5, ("lookupname_recv: lookup_name() failed!\n"));
+ cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ /* Try again using the forest root */
+ struct winbindd_domain *root_domain = find_root_domain();
+ struct winbindd_request request;
+
+ if ( !root_domain ) {
+ DEBUG(5,("lookupname_recv: unable to determine forest root\n"));
+ cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_LOOKUPNAME;
+
+ fstrcpy( request.data.name.dom_name, s->dom_name );
+ fstrcpy( request.data.name.name, s->name );
+
+ do_async_domain(mem_ctx, root_domain, &request, lookupname_recv2,
+ (void *)cont, s);
+
+ return;
+ }
+
+ if (!string_to_sid(&sid, response->data.sid.sid)) {
+ DEBUG(0, ("Could not convert string %s to sid\n",
+ response->data.sid.sid));
+ cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ cont(s->caller_private_data, True, &sid,
+ (enum lsa_SidType)response->data.sid.type);
+}
+
+/********************************************************************
+ The lookup name call first contacts a DC in its own domain
+ and fallbacks to contact a DC in the forest in our domain doesn't
+ know the name.
+********************************************************************/
+
+void winbindd_lookupname_async(TALLOC_CTX *mem_ctx,
+ const char *dom_name, const char *name,
+ void (*cont)(void *private_data, bool success,
+ const DOM_SID *sid,
+ enum lsa_SidType type),
+ enum winbindd_cmd orig_cmd,
+ void *private_data)
+{
+ struct winbindd_request request;
+ struct winbindd_domain *domain;
+ struct lookupname_state *s;
+
+ if ( (domain = find_lookup_domain_from_name(dom_name)) == NULL ) {
+ DEBUG(5, ("Could not find domain for name '%s'\n", dom_name));
+ cont(private_data, False, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_LOOKUPNAME;
+ request.original_cmd = orig_cmd;
+ fstrcpy(request.data.name.dom_name, dom_name);
+ fstrcpy(request.data.name.name, name);
+
+ if ( (s = TALLOC_ZERO_P(mem_ctx, struct lookupname_state)) == NULL ) {
+ DEBUG(0, ("winbindd_lookupname_async: talloc failed\n"));
+ cont(private_data, False, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ s->dom_name = talloc_strdup( s, dom_name );
+ s->name = talloc_strdup( s, name );
+ if (!s->dom_name || !s->name) {
+ cont(private_data, False, NULL, SID_NAME_UNKNOWN);
+ return;
+ }
+
+ s->caller_private_data = private_data;
+
+ do_async_domain(mem_ctx, domain, &request, lookupname_recv,
+ (void *)cont, s);
+}
+
+enum winbindd_result winbindd_dual_lookupname(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ enum lsa_SidType type;
+ char *name_domain, *name_user;
+ DOM_SID sid;
+ char *p;
+
+ /* Ensure null termination */
+ state->request.data.name.dom_name[sizeof(state->request.data.name.dom_name)-1]='\0';
+
+ /* Ensure null termination */
+ state->request.data.name.name[sizeof(state->request.data.name.name)-1]='\0';
+
+ /* cope with the name being a fully qualified name */
+ p = strstr(state->request.data.name.name, lp_winbind_separator());
+ if (p) {
+ *p = 0;
+ name_domain = state->request.data.name.name;
+ name_user = p+1;
+ } else {
+ name_domain = state->request.data.name.dom_name;
+ name_user = state->request.data.name.name;
+ }
+
+ DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid,
+ name_domain, lp_winbind_separator(), name_user));
+
+ /* Lookup name from DC using lsa_lookup_names() */
+ if (!winbindd_lookup_sid_by_name(state->mem_ctx, state->request.original_cmd, domain, name_domain,
+ name_user, &sid, &type)) {
+ return WINBINDD_ERROR;
+ }
+
+ sid_to_fstring(state->response.data.sid.sid, &sid);
+ state->response.data.sid.type = type;
+
+ return WINBINDD_OK;
+}
+
+/* This is the first callback after enumerating users/groups from a domain */
+static void listent_recv(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data)
+{
+ void (*cont)(void *priv, bool succ, fstring dom_name, char *data) =
+ (void (*)(void *, bool, fstring, char*))c;
+
+ if (!success || response->result != WINBINDD_OK) {
+ DEBUG(5, ("list_ent() failed!\n"));
+ cont(private_data, False, response->data.name.dom_name, NULL);
+ return;
+ }
+
+ cont(private_data, True, response->data.name.dom_name,
+ (char *)response->extra_data.data);
+
+ SAFE_FREE(response->extra_data.data);
+}
+
+/* Request the name of all users/groups in a single domain */
+void winbindd_listent_async(TALLOC_CTX *mem_ctx,
+ struct winbindd_domain *domain,
+ void (*cont)(void *private_data, bool success,
+ fstring dom_name, char* extra_data),
+ void *private_data, enum ent_type type)
+{
+ struct winbindd_request request;
+
+ ZERO_STRUCT(request);
+ if (type == LIST_USERS)
+ request.cmd = WINBINDD_LIST_USERS;
+ else if (type == LIST_GROUPS)
+ request.cmd = WINBINDD_LIST_GROUPS;
+
+ do_async_domain(mem_ctx, domain, &request, listent_recv,
+ (void *)cont, private_data);
+}
+
+enum winbindd_result winbindd_dual_list_users(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ WINBIND_USERINFO *info;
+ NTSTATUS status;
+ struct winbindd_methods *methods;
+ uint32 num_entries = 0;
+ char *extra_data = NULL;
+ uint32_t extra_data_len = 0, i;
+
+ /* Must copy domain into response first for debugging in parent */
+ fstrcpy(state->response.data.name.dom_name, domain->name);
+
+ /* Query user info */
+ methods = domain->methods;
+ status = methods->query_user_list(domain, state->mem_ctx,
+ &num_entries, &info);
+
+ if (!NT_STATUS_IS_OK(status))
+ return WINBINDD_ERROR;
+
+ if (num_entries == 0)
+ return WINBINDD_OK;
+
+ /* Allocate some memory for extra data. Note that we limit
+ account names to sizeof(fstring) = 256 characters.
+ +1 for the ',' between group names */
+ extra_data = (char *)SMB_REALLOC(extra_data,
+ (sizeof(fstring) + 1) * num_entries);
+
+ if (!extra_data) {
+ DEBUG(0,("failed to enlarge buffer!\n"));
+ return WINBINDD_ERROR;
+ }
+
+ /* Pack user list into extra data fields */
+ for (i = 0; i < num_entries; i++) {
+ fstring acct_name, name;
+
+ if (info[i].acct_name == NULL)
+ fstrcpy(acct_name, "");
+ else
+ fstrcpy(acct_name, info[i].acct_name);
+
+ fill_domain_username(name, domain->name, acct_name, True);
+ /* Append to extra data */
+ memcpy(&extra_data[extra_data_len], name, strlen(name));
+ extra_data_len += strlen(name);
+ extra_data[extra_data_len++] = ',';
+ }
+
+ /* Assign extra_data fields in response structure */
+ if (extra_data) {
+ /* remove trailing ',' */
+ extra_data[extra_data_len - 1] = '\0';
+ state->response.extra_data.data = extra_data;
+ state->response.length += extra_data_len;
+ }
+
+ return WINBINDD_OK;
+}
+
+enum winbindd_result winbindd_dual_list_groups(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ struct getent_state groups;
+ char *extra_data = NULL;
+ uint32_t extra_data_len = 0, i;
+
+ ZERO_STRUCT(groups);
+
+ /* Must copy domain into response first for debugging in parent */
+ fstrcpy(state->response.data.name.dom_name, domain->name);
+ fstrcpy(groups.domain_name, domain->name);
+
+ /* Get list of sam groups */
+ if (!get_sam_group_entries(&groups)) {
+ /* this domain is empty or in an error state */
+ return WINBINDD_ERROR;
+ }
+
+ /* Allocate some memory for extra data. Note that we limit
+ account names to sizeof(fstring) = 256 characters.
+ +1 for the ',' between group names */
+ extra_data = (char *)SMB_REALLOC(extra_data,
+ (sizeof(fstring) + 1) * groups.num_sam_entries);
+
+ if (!extra_data) {
+ DEBUG(0,("failed to enlarge buffer!\n"));
+ SAFE_FREE(groups.sam_entries);
+ return WINBINDD_ERROR;
+ }
+
+ /* Pack group list into extra data fields */
+ for (i = 0; i < groups.num_sam_entries; i++) {
+ char *group_name = ((struct acct_info *)
+ groups.sam_entries)[i].acct_name;
+ fstring name;
+
+ fill_domain_username(name, domain->name, group_name, True);
+ /* Append to extra data */
+ memcpy(&extra_data[extra_data_len], name, strlen(name));
+ extra_data_len += strlen(name);
+ extra_data[extra_data_len++] = ',';
+ }
+
+ SAFE_FREE(groups.sam_entries);
+
+ /* Assign extra_data fields in response structure */
+ if (extra_data) {
+ /* remove trailing ',' */
+ extra_data[extra_data_len - 1] = '\0';
+ state->response.extra_data.data = extra_data;
+ state->response.length += extra_data_len;
+ }
+
+ return WINBINDD_OK;
+}
+
+bool print_sidlist(TALLOC_CTX *mem_ctx, const DOM_SID *sids,
+ size_t num_sids, char **result, ssize_t *len)
+{
+ size_t i;
+ size_t buflen = 0;
+
+ *len = 0;
+ *result = NULL;
+ for (i=0; i<num_sids; i++) {
+ fstring tmp;
+ sprintf_append(mem_ctx, result, len, &buflen,
+ "%s\n", sid_to_fstring(tmp, &sids[i]));
+ }
+
+ if ((num_sids != 0) && (*result == NULL)) {
+ return False;
+ }
+
+ return True;
+}
+
+static bool parse_sidlist(TALLOC_CTX *mem_ctx, char *sidstr,
+ DOM_SID **sids, size_t *num_sids)
+{
+ char *p, *q;
+
+ p = sidstr;
+ if (p == NULL)
+ return False;
+
+ while (p[0] != '\0') {
+ DOM_SID sid;
+ q = strchr(p, '\n');
+ if (q == NULL) {
+ DEBUG(0, ("Got invalid sidstr: %s\n", p));
+ return False;
+ }
+ *q = '\0';
+ q += 1;
+ if (!string_to_sid(&sid, p)) {
+ DEBUG(0, ("Could not parse sid %s\n", p));
+ return False;
+ }
+ if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
+ num_sids)))
+ {
+ return False;
+ }
+ p = q;
+ }
+ return True;
+}
+
+static bool parse_ridlist(TALLOC_CTX *mem_ctx, char *ridstr,
+ uint32 **rids, size_t *num_rids)
+{
+ char *p;
+
+ p = ridstr;
+ if (p == NULL)
+ return False;
+
+ while (p[0] != '\0') {
+ uint32 rid;
+ char *q;
+ rid = strtoul(p, &q, 10);
+ if (*q != '\n') {
+ DEBUG(0, ("Got invalid ridstr: %s\n", p));
+ return False;
+ }
+ p = q+1;
+ ADD_TO_ARRAY(mem_ctx, uint32, rid, rids, num_rids);
+ }
+ return True;
+}
+
+enum winbindd_result winbindd_dual_lookuprids(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ uint32 *rids = NULL;
+ size_t i, buflen, num_rids = 0;
+ ssize_t len;
+ DOM_SID domain_sid;
+ char *domain_name;
+ char **names;
+ enum lsa_SidType *types;
+ NTSTATUS status;
+ char *result;
+
+ DEBUG(10, ("Looking up RIDs for domain %s (%s)\n",
+ state->request.domain_name,
+ state->request.data.sid));
+
+ if (!parse_ridlist(state->mem_ctx, state->request.extra_data.data,
+ &rids, &num_rids)) {
+ DEBUG(5, ("Could not parse ridlist\n"));
+ return WINBINDD_ERROR;
+ }
+
+ if (!string_to_sid(&domain_sid, state->request.data.sid)) {
+ DEBUG(5, ("Could not parse domain sid %s\n",
+ state->request.data.sid));
+ return WINBINDD_ERROR;
+ }
+
+ status = domain->methods->rids_to_names(domain, state->mem_ctx,
+ &domain_sid, rids, num_rids,
+ &domain_name,
+ &names, &types);
+
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
+ return WINBINDD_ERROR;
+ }
+
+ len = 0;
+ buflen = 0;
+ result = NULL;
+
+ for (i=0; i<num_rids; i++) {
+ sprintf_append(state->mem_ctx, &result, &len, &buflen,
+ "%d %s\n", types[i], names[i]);
+ }
+
+ fstrcpy(state->response.data.domain_name, domain_name);
+
+ if (result != NULL) {
+ state->response.extra_data.data = SMB_STRDUP(result);
+ if (!state->response.extra_data.data) {
+ return WINBINDD_ERROR;
+ }
+ state->response.length += len+1;
+ }
+
+ return WINBINDD_OK;
+}
+
+static void getsidaliases_recv(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data)
+{
+ void (*cont)(void *priv, bool succ,
+ DOM_SID *aliases, size_t num_aliases) =
+ (void (*)(void *, bool, DOM_SID *, size_t))c;
+ char *aliases_str;
+ DOM_SID *sids = NULL;
+ size_t num_sids = 0;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger getsidaliases\n"));
+ cont(private_data, success, NULL, 0);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("getsidaliases returned an error\n"));
+ cont(private_data, False, NULL, 0);
+ return;
+ }
+
+ aliases_str = (char *)response->extra_data.data;
+
+ if (aliases_str == NULL) {
+ DEBUG(10, ("getsidaliases return 0 SIDs\n"));
+ cont(private_data, True, NULL, 0);
+ return;
+ }
+
+ if (!parse_sidlist(mem_ctx, aliases_str, &sids, &num_sids)) {
+ DEBUG(0, ("Could not parse sids\n"));
+ cont(private_data, False, NULL, 0);
+ return;
+ }
+
+ SAFE_FREE(response->extra_data.data);
+
+ cont(private_data, True, sids, num_sids);
+}
+
+void winbindd_getsidaliases_async(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sids, size_t num_sids,
+ void (*cont)(void *private_data,
+ bool success,
+ const DOM_SID *aliases,
+ size_t num_aliases),
+ void *private_data)
+{
+ struct winbindd_request request;
+ char *sidstr = NULL;
+ ssize_t len;
+
+ if (num_sids == 0) {
+ cont(private_data, True, NULL, 0);
+ return;
+ }
+
+ if (!print_sidlist(mem_ctx, sids, num_sids, &sidstr, &len)) {
+ cont(private_data, False, NULL, 0);
+ return;
+ }
+
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_GETSIDALIASES;
+ request.extra_len = len;
+ request.extra_data.data = sidstr;
+
+ do_async_domain(mem_ctx, domain, &request, getsidaliases_recv,
+ (void *)cont, private_data);
+}
+
+enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ DOM_SID *sids = NULL;
+ size_t num_sids = 0;
+ char *sidstr = NULL;
+ ssize_t len;
+ size_t i;
+ uint32 num_aliases;
+ uint32 *alias_rids;
+ NTSTATUS result;
+
+ DEBUG(3, ("[%5lu]: getsidaliases\n", (unsigned long)state->pid));
+
+ sidstr = state->request.extra_data.data;
+ if (sidstr == NULL) {
+ sidstr = talloc_strdup(state->mem_ctx, "\n"); /* No SID */
+ if (!sidstr) {
+ DEBUG(0, ("Out of memory\n"));
+ return WINBINDD_ERROR;
+ }
+ }
+
+ DEBUG(10, ("Sidlist: %s\n", sidstr));
+
+ if (!parse_sidlist(state->mem_ctx, sidstr, &sids, &num_sids)) {
+ DEBUG(0, ("Could not parse SID list: %s\n", sidstr));
+ return WINBINDD_ERROR;
+ }
+
+ num_aliases = 0;
+ alias_rids = NULL;
+
+ result = domain->methods->lookup_useraliases(domain,
+ state->mem_ctx,
+ num_sids, sids,
+ &num_aliases,
+ &alias_rids);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3, ("Could not lookup_useraliases: %s\n",
+ nt_errstr(result)));
+ return WINBINDD_ERROR;
+ }
+
+ num_sids = 0;
+ sids = NULL;
+ sidstr = NULL;
+
+ DEBUG(10, ("Got %d aliases\n", num_aliases));
+
+ for (i=0; i<num_aliases; i++) {
+ DOM_SID sid;
+ DEBUGADD(10, (" rid %d\n", alias_rids[i]));
+ sid_copy(&sid, &domain->sid);
+ sid_append_rid(&sid, alias_rids[i]);
+ result = add_sid_to_array(state->mem_ctx, &sid, &sids,
+ &num_sids);
+ if (!NT_STATUS_IS_OK(result)) {
+ return WINBINDD_ERROR;
+ }
+ }
+
+
+ if (!print_sidlist(state->mem_ctx, sids, num_sids, &sidstr, &len)) {
+ DEBUG(0, ("Could not print_sidlist\n"));
+ state->response.extra_data.data = NULL;
+ return WINBINDD_ERROR;
+ }
+
+ state->response.extra_data.data = NULL;
+
+ if (sidstr) {
+ state->response.extra_data.data = SMB_STRDUP(sidstr);
+ if (!state->response.extra_data.data) {
+ DEBUG(0, ("Out of memory\n"));
+ return WINBINDD_ERROR;
+ }
+ DEBUG(10, ("aliases_list: %s\n",
+ (char *)state->response.extra_data.data));
+ state->response.length += len+1;
+ }
+
+ return WINBINDD_OK;
+}
+
+struct gettoken_state {
+ TALLOC_CTX *mem_ctx;
+ DOM_SID user_sid;
+ struct winbindd_domain *alias_domain;
+ struct winbindd_domain *local_alias_domain;
+ struct winbindd_domain *builtin_domain;
+ DOM_SID *sids;
+ size_t num_sids;
+ void (*cont)(void *private_data, bool success, DOM_SID *sids, size_t num_sids);
+ void *private_data;
+};
+
+static void gettoken_recvdomgroups(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data);
+static void gettoken_recvaliases(void *private_data, bool success,
+ const DOM_SID *aliases,
+ size_t num_aliases);
+
+
+void winbindd_gettoken_async(TALLOC_CTX *mem_ctx, const DOM_SID *user_sid,
+ void (*cont)(void *private_data, bool success,
+ DOM_SID *sids, size_t num_sids),
+ void *private_data)
+{
+ struct winbindd_domain *domain;
+ struct winbindd_request request;
+ struct gettoken_state *state;
+
+ state = TALLOC_ZERO_P(mem_ctx, struct gettoken_state);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ cont(private_data, False, NULL, 0);
+ return;
+ }
+
+ state->mem_ctx = mem_ctx;
+ sid_copy(&state->user_sid, user_sid);
+ state->alias_domain = find_our_domain();
+ state->local_alias_domain = find_domain_from_name( get_global_sam_name() );
+ state->builtin_domain = find_builtin_domain();
+ state->cont = cont;
+ state->private_data = private_data;
+
+ domain = find_domain_from_sid_noinit(user_sid);
+ if (domain == NULL) {
+ DEBUG(5, ("Could not find domain from SID %s\n",
+ sid_string_dbg(user_sid)));
+ cont(private_data, False, NULL, 0);
+ return;
+ }
+
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_GETUSERDOMGROUPS;
+ sid_to_fstring(request.data.sid, user_sid);
+
+ do_async_domain(mem_ctx, domain, &request, gettoken_recvdomgroups,
+ NULL, state);
+}
+
+static void gettoken_recvdomgroups(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data)
+{
+ struct gettoken_state *state =
+ talloc_get_type_abort(private_data, struct gettoken_state);
+ char *sids_str;
+
+ if (!success) {
+ DEBUG(10, ("Could not get domain groups\n"));
+ state->cont(state->private_data, False, NULL, 0);
+ return;
+ }
+
+ sids_str = (char *)response->extra_data.data;
+
+ if (sids_str == NULL) {
+ /* This could be normal if we are dealing with a
+ local user and local groups */
+
+ if ( !sid_check_is_in_our_domain( &state->user_sid ) ) {
+ DEBUG(10, ("Received no domain groups\n"));
+ state->cont(state->private_data, True, NULL, 0);
+ return;
+ }
+ }
+
+ state->sids = NULL;
+ state->num_sids = 0;
+
+ if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &state->user_sid,
+ &state->sids, &state->num_sids)))
+ {
+ DEBUG(0, ("Out of memory\n"));
+ state->cont(state->private_data, False, NULL, 0);
+ return;
+ }
+
+ if (sids_str && !parse_sidlist(mem_ctx, sids_str, &state->sids,
+ &state->num_sids)) {
+ DEBUG(0, ("Could not parse sids\n"));
+ state->cont(state->private_data, False, NULL, 0);
+ return;
+ }
+
+ SAFE_FREE(response->extra_data.data);
+
+ if (state->alias_domain == NULL) {
+ DEBUG(10, ("Don't expand domain local groups\n"));
+ state->cont(state->private_data, True, state->sids,
+ state->num_sids);
+ return;
+ }
+
+ winbindd_getsidaliases_async(state->alias_domain, mem_ctx,
+ state->sids, state->num_sids,
+ gettoken_recvaliases, state);
+}
+
+static void gettoken_recvaliases(void *private_data, bool success,
+ const DOM_SID *aliases,
+ size_t num_aliases)
+{
+ struct gettoken_state *state = (struct gettoken_state *)private_data;
+ size_t i;
+
+ if (!success) {
+ DEBUG(10, ("Could not receive domain local groups\n"));
+ state->cont(state->private_data, False, NULL, 0);
+ return;
+ }
+
+ for (i=0; i<num_aliases; i++) {
+ if (!NT_STATUS_IS_OK(add_sid_to_array(state->mem_ctx,
+ &aliases[i],
+ &state->sids,
+ &state->num_sids)))
+ {
+ DEBUG(0, ("Out of memory\n"));
+ state->cont(state->private_data, False, NULL, 0);
+ return;
+ }
+ }
+
+ if (state->local_alias_domain != NULL) {
+ struct winbindd_domain *local_domain = state->local_alias_domain;
+ DEBUG(10, ("Expanding our own local groups\n"));
+ state->local_alias_domain = NULL;
+ winbindd_getsidaliases_async(local_domain, state->mem_ctx,
+ state->sids, state->num_sids,
+ gettoken_recvaliases, state);
+ return;
+ }
+
+ if (state->builtin_domain != NULL) {
+ struct winbindd_domain *builtin_domain = state->builtin_domain;
+ DEBUG(10, ("Expanding our own BUILTIN groups\n"));
+ state->builtin_domain = NULL;
+ winbindd_getsidaliases_async(builtin_domain, state->mem_ctx,
+ state->sids, state->num_sids,
+ gettoken_recvaliases, state);
+ return;
+ }
+
+ state->cont(state->private_data, True, state->sids, state->num_sids);
+}
+
+static void query_user_recv(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data)
+{
+ void (*cont)(void *priv, bool succ, const char *acct_name,
+ const char *full_name, const char *homedir,
+ const char *shell, uint32 gid, uint32 group_rid) =
+ (void (*)(void *, bool, const char *, const char *,
+ const char *, const char *, uint32, uint32))c;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger query_user\n"));
+ cont(private_data, False, NULL, NULL, NULL, NULL, -1, -1);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("query_user returned an error\n"));
+ cont(private_data, False, NULL, NULL, NULL, NULL, -1, -1);
+ return;
+ }
+
+ cont(private_data, True, response->data.user_info.acct_name,
+ response->data.user_info.full_name,
+ response->data.user_info.homedir,
+ response->data.user_info.shell,
+ response->data.user_info.primary_gid,
+ response->data.user_info.group_rid);
+}
+
+void query_user_async(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
+ const DOM_SID *sid,
+ void (*cont)(void *private_data, bool success,
+ const char *acct_name,
+ const char *full_name,
+ const char *homedir,
+ const char *shell,
+ gid_t gid,
+ uint32 group_rid),
+ void *private_data)
+{
+ struct winbindd_request request;
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_USERINFO;
+ sid_to_fstring(request.data.sid, sid);
+ do_async_domain(mem_ctx, domain, &request, query_user_recv,
+ (void *)cont, private_data);
+}
diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c
new file mode 100644
index 0000000000..2fbb01b623
--- /dev/null
+++ b/source3/winbindd/winbindd_cache.c
@@ -0,0 +1,4008 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind cache backend functions
+
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Gerald Carter 2003-2007
+ Copyright (C) Volker Lendecke 2005
+ Copyright (C) Guenther Deschner 2005
+ Copyright (C) Michael Adam 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+#define WINBINDD_CACHE_VERSION 1
+#define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
+
+extern struct winbindd_methods reconnect_methods;
+extern bool opt_nocache;
+#ifdef HAVE_ADS
+extern struct winbindd_methods ads_methods;
+#endif
+extern struct winbindd_methods builtin_passdb_methods;
+
+/*
+ * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
+ * Here are the list of entry types that are *not* stored
+ * as form struct cache_entry in the cache.
+ */
+
+static const char *non_centry_keys[] = {
+ "SEQNUM/",
+ "DR/",
+ "DE/",
+ "WINBINDD_OFFLINE",
+ WINBINDD_CACHE_VERSION_KEYSTR,
+ NULL
+};
+
+/************************************************************************
+ Is this key a non-centry type ?
+************************************************************************/
+
+static bool is_non_centry_key(TDB_DATA kbuf)
+{
+ int i;
+
+ if (kbuf.dptr == NULL || kbuf.dsize == 0) {
+ return false;
+ }
+ for (i = 0; non_centry_keys[i] != NULL; i++) {
+ size_t namelen = strlen(non_centry_keys[i]);
+ if (kbuf.dsize < namelen) {
+ continue;
+ }
+ if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Global online/offline state - False when online. winbindd starts up online
+ and sets this to true if the first query fails and there's an entry in
+ the cache tdb telling us to stay offline. */
+
+static bool global_winbindd_offline_state;
+
+struct winbind_cache {
+ TDB_CONTEXT *tdb;
+};
+
+struct cache_entry {
+ NTSTATUS status;
+ uint32 sequence_number;
+ uint8 *data;
+ uint32 len, ofs;
+};
+
+void (*smb_panic_fn)(const char *const why) = smb_panic;
+
+#define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
+
+static struct winbind_cache *wcache;
+
+void winbindd_check_cache_size(time_t t)
+{
+ static time_t last_check_time;
+ struct stat st;
+
+ if (last_check_time == (time_t)0)
+ last_check_time = t;
+
+ if (t - last_check_time < 60 && t - last_check_time > 0)
+ return;
+
+ if (wcache == NULL || wcache->tdb == NULL) {
+ DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
+ return;
+ }
+
+ if (fstat(tdb_fd(wcache->tdb), &st) == -1) {
+ DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
+ return;
+ }
+
+ if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
+ DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
+ (unsigned long)st.st_size,
+ (unsigned long)WINBINDD_MAX_CACHE_SIZE));
+ wcache_flush_cache();
+ }
+}
+
+/* get the winbind_cache structure */
+static struct winbind_cache *get_cache(struct winbindd_domain *domain)
+{
+ struct winbind_cache *ret = wcache;
+
+ /* We have to know what type of domain we are dealing with first. */
+
+ if (domain->internal) {
+ domain->backend = &builtin_passdb_methods;
+ domain->initialized = True;
+ }
+ if ( !domain->initialized ) {
+ init_dc_connection( domain );
+ }
+
+ /*
+ OK. listen up becasue I'm only going to say this once.
+ We have the following scenarios to consider
+ (a) trusted AD domains on a Samba DC,
+ (b) trusted AD domains and we are joined to a non-kerberos domain
+ (c) trusted AD domains and we are joined to a kerberos (AD) domain
+
+ For (a) we can always contact the trusted domain using krb5
+ since we have the domain trust account password
+
+ For (b) we can only use RPC since we have no way of
+ getting a krb5 ticket in our own domain
+
+ For (c) we can always use krb5 since we have a kerberos trust
+
+ --jerry
+ */
+
+ if (!domain->backend) {
+#ifdef HAVE_ADS
+ struct winbindd_domain *our_domain = domain;
+
+ /* find our domain first so we can figure out if we
+ are joined to a kerberized domain */
+
+ if ( !domain->primary )
+ our_domain = find_our_domain();
+
+ if ((our_domain->active_directory || IS_DC)
+ && domain->active_directory
+ && !lp_winbind_rpc_only()) {
+ DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
+ domain->backend = &ads_methods;
+ } else {
+#endif /* HAVE_ADS */
+ DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
+ domain->backend = &reconnect_methods;
+#ifdef HAVE_ADS
+ }
+#endif /* HAVE_ADS */
+ }
+
+ if (ret)
+ return ret;
+
+ ret = SMB_XMALLOC_P(struct winbind_cache);
+ ZERO_STRUCTP(ret);
+
+ wcache = ret;
+ wcache_flush_cache();
+
+ return ret;
+}
+
+/*
+ free a centry structure
+*/
+static void centry_free(struct cache_entry *centry)
+{
+ if (!centry)
+ return;
+ SAFE_FREE(centry->data);
+ free(centry);
+}
+
+static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
+{
+ if (centry->len - centry->ofs < nbytes) {
+ DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
+ (unsigned int)nbytes,
+ centry->len - centry->ofs));
+ return false;
+ }
+ return true;
+}
+
+/*
+ pull a uint32 from a cache entry
+*/
+static uint32 centry_uint32(struct cache_entry *centry)
+{
+ uint32 ret;
+
+ if (!centry_check_bytes(centry, 4)) {
+ smb_panic_fn("centry_uint32");
+ }
+ ret = IVAL(centry->data, centry->ofs);
+ centry->ofs += 4;
+ return ret;
+}
+
+/*
+ pull a uint16 from a cache entry
+*/
+static uint16 centry_uint16(struct cache_entry *centry)
+{
+ uint16 ret;
+ if (!centry_check_bytes(centry, 2)) {
+ smb_panic_fn("centry_uint16");
+ }
+ ret = CVAL(centry->data, centry->ofs);
+ centry->ofs += 2;
+ return ret;
+}
+
+/*
+ pull a uint8 from a cache entry
+*/
+static uint8 centry_uint8(struct cache_entry *centry)
+{
+ uint8 ret;
+ if (!centry_check_bytes(centry, 1)) {
+ smb_panic_fn("centry_uint8");
+ }
+ ret = CVAL(centry->data, centry->ofs);
+ centry->ofs += 1;
+ return ret;
+}
+
+/*
+ pull a NTTIME from a cache entry
+*/
+static NTTIME centry_nttime(struct cache_entry *centry)
+{
+ NTTIME ret;
+ if (!centry_check_bytes(centry, 8)) {
+ smb_panic_fn("centry_nttime");
+ }
+ ret = IVAL(centry->data, centry->ofs);
+ centry->ofs += 4;
+ ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
+ centry->ofs += 4;
+ return ret;
+}
+
+/*
+ pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
+*/
+static time_t centry_time(struct cache_entry *centry)
+{
+ return (time_t)centry_nttime(centry);
+}
+
+/* pull a string from a cache entry, using the supplied
+ talloc context
+*/
+static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
+{
+ uint32 len;
+ char *ret;
+
+ len = centry_uint8(centry);
+
+ if (len == 0xFF) {
+ /* a deliberate NULL string */
+ return NULL;
+ }
+
+ if (!centry_check_bytes(centry, (size_t)len)) {
+ smb_panic_fn("centry_string");
+ }
+
+ ret = TALLOC_ARRAY(mem_ctx, char, len+1);
+ if (!ret) {
+ smb_panic_fn("centry_string out of memory\n");
+ }
+ memcpy(ret,centry->data + centry->ofs, len);
+ ret[len] = 0;
+ centry->ofs += len;
+ return ret;
+}
+
+/* pull a hash16 from a cache entry, using the supplied
+ talloc context
+*/
+static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
+{
+ uint32 len;
+ char *ret;
+
+ len = centry_uint8(centry);
+
+ if (len != 16) {
+ DEBUG(0,("centry corruption? hash len (%u) != 16\n",
+ len ));
+ return NULL;
+ }
+
+ if (!centry_check_bytes(centry, 16)) {
+ return NULL;
+ }
+
+ ret = TALLOC_ARRAY(mem_ctx, char, 16);
+ if (!ret) {
+ smb_panic_fn("centry_hash out of memory\n");
+ }
+ memcpy(ret,centry->data + centry->ofs, 16);
+ centry->ofs += 16;
+ return ret;
+}
+
+/* pull a sid from a cache entry, using the supplied
+ talloc context
+*/
+static bool centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx, DOM_SID *sid)
+{
+ char *sid_string;
+ sid_string = centry_string(centry, mem_ctx);
+ if ((sid_string == NULL) || (!string_to_sid(sid, sid_string))) {
+ return false;
+ }
+ return true;
+}
+
+
+/*
+ pull a NTSTATUS from a cache entry
+*/
+static NTSTATUS centry_ntstatus(struct cache_entry *centry)
+{
+ NTSTATUS status;
+
+ status = NT_STATUS(centry_uint32(centry));
+ return status;
+}
+
+
+/* the server is considered down if it can't give us a sequence number */
+static bool wcache_server_down(struct winbindd_domain *domain)
+{
+ bool ret;
+
+ if (!wcache->tdb)
+ return false;
+
+ ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
+
+ if (ret)
+ DEBUG(10,("wcache_server_down: server for Domain %s down\n",
+ domain->name ));
+ return ret;
+}
+
+static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
+{
+ TDB_DATA data;
+ fstring key;
+ uint32 time_diff;
+
+ if (!wcache->tdb) {
+ DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ fstr_sprintf( key, "SEQNUM/%s", domain->name );
+
+ data = tdb_fetch_bystring( wcache->tdb, key );
+ if ( !data.dptr || data.dsize!=8 ) {
+ DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key ));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ domain->sequence_number = IVAL(data.dptr, 0);
+ domain->last_seq_check = IVAL(data.dptr, 4);
+
+ SAFE_FREE(data.dptr);
+
+ /* have we expired? */
+
+ time_diff = now - domain->last_seq_check;
+ if ( time_diff > lp_winbind_cache_time() ) {
+ DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
+ domain->name, domain->sequence_number,
+ (uint32)domain->last_seq_check));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
+ domain->name, domain->sequence_number,
+ (uint32)domain->last_seq_check));
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS store_cache_seqnum( struct winbindd_domain *domain )
+{
+ TDB_DATA data;
+ fstring key_str;
+ uint8 buf[8];
+
+ if (!wcache->tdb) {
+ DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ fstr_sprintf( key_str, "SEQNUM/%s", domain->name );
+
+ SIVAL(buf, 0, domain->sequence_number);
+ SIVAL(buf, 4, domain->last_seq_check);
+ data.dptr = buf;
+ data.dsize = 8;
+
+ if ( tdb_store_bystring( wcache->tdb, key_str, data, TDB_REPLACE) == -1 ) {
+ DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str ));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
+ domain->name, domain->sequence_number,
+ (uint32)domain->last_seq_check));
+
+ return NT_STATUS_OK;
+}
+
+/*
+ refresh the domain sequence number. If force is true
+ then always refresh it, no matter how recently we fetched it
+*/
+
+static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
+{
+ NTSTATUS status;
+ unsigned time_diff;
+ time_t t = time(NULL);
+ unsigned cache_time = lp_winbind_cache_time();
+
+ if ( IS_DOMAIN_OFFLINE(domain) ) {
+ return;
+ }
+
+ get_cache( domain );
+
+#if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
+ /* trying to reconnect is expensive, don't do it too often */
+ if (domain->sequence_number == DOM_SEQUENCE_NONE) {
+ cache_time *= 8;
+ }
+#endif
+
+ time_diff = t - domain->last_seq_check;
+
+ /* see if we have to refetch the domain sequence number */
+ if (!force && (time_diff < cache_time)) {
+ DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
+ goto done;
+ }
+
+ /* try to get the sequence number from the tdb cache first */
+ /* this will update the timestamp as well */
+
+ status = fetch_cache_seqnum( domain, t );
+ if ( NT_STATUS_IS_OK(status) )
+ goto done;
+
+ /* important! make sure that we know if this is a native
+ mode domain or not. And that we can contact it. */
+
+ if ( winbindd_can_contact_domain( domain ) ) {
+ status = domain->backend->sequence_number(domain,
+ &domain->sequence_number);
+ } else {
+ /* just use the current time */
+ status = NT_STATUS_OK;
+ domain->sequence_number = time(NULL);
+ }
+
+
+ /* the above call could have set our domain->backend to NULL when
+ * coming from offline to online mode, make sure to reinitialize the
+ * backend - Guenther */
+ get_cache( domain );
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
+ domain->sequence_number = DOM_SEQUENCE_NONE;
+ }
+
+ domain->last_status = status;
+ domain->last_seq_check = time(NULL);
+
+ /* save the new sequence number in the cache */
+ store_cache_seqnum( domain );
+
+done:
+ DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
+ domain->name, domain->sequence_number));
+
+ return;
+}
+
+/*
+ decide if a cache entry has expired
+*/
+static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
+{
+ /* If we've been told to be offline - stay in that state... */
+ if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
+ DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
+ keystr, domain->name ));
+ return false;
+ }
+
+ /* when the domain is offline return the cached entry.
+ * This deals with transient offline states... */
+
+ if (!domain->online) {
+ DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
+ keystr, domain->name ));
+ return false;
+ }
+
+ /* if the server is OK and our cache entry came from when it was down then
+ the entry is invalid */
+ if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
+ (centry->sequence_number == DOM_SEQUENCE_NONE)) {
+ DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
+ keystr, domain->name ));
+ return true;
+ }
+
+ /* if the server is down or the cache entry is not older than the
+ current sequence number then it is OK */
+ if (wcache_server_down(domain) ||
+ centry->sequence_number == domain->sequence_number) {
+ DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
+ keystr, domain->name ));
+ return false;
+ }
+
+ DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
+ keystr, domain->name ));
+
+ /* it's expired */
+ return true;
+}
+
+static struct cache_entry *wcache_fetch_raw(char *kstr)
+{
+ TDB_DATA data;
+ struct cache_entry *centry;
+ TDB_DATA key;
+
+ key = string_tdb_data(kstr);
+ data = tdb_fetch(wcache->tdb, key);
+ if (!data.dptr) {
+ /* a cache miss */
+ return NULL;
+ }
+
+ centry = SMB_XMALLOC_P(struct cache_entry);
+ centry->data = (unsigned char *)data.dptr;
+ centry->len = data.dsize;
+ centry->ofs = 0;
+
+ if (centry->len < 8) {
+ /* huh? corrupt cache? */
+ DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
+ centry_free(centry);
+ return NULL;
+ }
+
+ centry->status = centry_ntstatus(centry);
+ centry->sequence_number = centry_uint32(centry);
+
+ return centry;
+}
+
+/*
+ fetch an entry from the cache, with a varargs key. auto-fetch the sequence
+ number and return status
+*/
+static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
+ struct winbindd_domain *domain,
+ const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
+ struct winbindd_domain *domain,
+ const char *format, ...)
+{
+ va_list ap;
+ char *kstr;
+ struct cache_entry *centry;
+
+ if (opt_nocache) {
+ return NULL;
+ }
+
+ refresh_sequence_number(domain, false);
+
+ va_start(ap, format);
+ smb_xvasprintf(&kstr, format, ap);
+ va_end(ap);
+
+ centry = wcache_fetch_raw(kstr);
+ if (centry == NULL) {
+ free(kstr);
+ return NULL;
+ }
+
+ if (centry_expired(domain, kstr, centry)) {
+
+ DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
+ kstr, domain->name ));
+
+ centry_free(centry);
+ free(kstr);
+ return NULL;
+ }
+
+ DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
+ kstr, domain->name ));
+
+ free(kstr);
+ return centry;
+}
+
+static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
+static void wcache_delete(const char *format, ...)
+{
+ va_list ap;
+ char *kstr;
+ TDB_DATA key;
+
+ va_start(ap, format);
+ smb_xvasprintf(&kstr, format, ap);
+ va_end(ap);
+
+ key = string_tdb_data(kstr);
+
+ tdb_delete(wcache->tdb, key);
+ free(kstr);
+}
+
+/*
+ make sure we have at least len bytes available in a centry
+*/
+static void centry_expand(struct cache_entry *centry, uint32 len)
+{
+ if (centry->len - centry->ofs >= len)
+ return;
+ centry->len *= 2;
+ centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
+ centry->len);
+ if (!centry->data) {
+ DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
+ smb_panic_fn("out of memory in centry_expand");
+ }
+}
+
+/*
+ push a uint32 into a centry
+*/
+static void centry_put_uint32(struct cache_entry *centry, uint32 v)
+{
+ centry_expand(centry, 4);
+ SIVAL(centry->data, centry->ofs, v);
+ centry->ofs += 4;
+}
+
+/*
+ push a uint16 into a centry
+*/
+static void centry_put_uint16(struct cache_entry *centry, uint16 v)
+{
+ centry_expand(centry, 2);
+ SIVAL(centry->data, centry->ofs, v);
+ centry->ofs += 2;
+}
+
+/*
+ push a uint8 into a centry
+*/
+static void centry_put_uint8(struct cache_entry *centry, uint8 v)
+{
+ centry_expand(centry, 1);
+ SCVAL(centry->data, centry->ofs, v);
+ centry->ofs += 1;
+}
+
+/*
+ push a string into a centry
+ */
+static void centry_put_string(struct cache_entry *centry, const char *s)
+{
+ int len;
+
+ if (!s) {
+ /* null strings are marked as len 0xFFFF */
+ centry_put_uint8(centry, 0xFF);
+ return;
+ }
+
+ len = strlen(s);
+ /* can't handle more than 254 char strings. Truncating is probably best */
+ if (len > 254) {
+ DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
+ len = 254;
+ }
+ centry_put_uint8(centry, len);
+ centry_expand(centry, len);
+ memcpy(centry->data + centry->ofs, s, len);
+ centry->ofs += len;
+}
+
+/*
+ push a 16 byte hash into a centry - treat as 16 byte string.
+ */
+static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
+{
+ centry_put_uint8(centry, 16);
+ centry_expand(centry, 16);
+ memcpy(centry->data + centry->ofs, val, 16);
+ centry->ofs += 16;
+}
+
+static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid)
+{
+ fstring sid_string;
+ centry_put_string(centry, sid_to_fstring(sid_string, sid));
+}
+
+
+/*
+ put NTSTATUS into a centry
+*/
+static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
+{
+ uint32 status_value = NT_STATUS_V(status);
+ centry_put_uint32(centry, status_value);
+}
+
+
+/*
+ push a NTTIME into a centry
+*/
+static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
+{
+ centry_expand(centry, 8);
+ SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
+ centry->ofs += 4;
+ SIVAL(centry->data, centry->ofs, nt >> 32);
+ centry->ofs += 4;
+}
+
+/*
+ push a time_t into a centry - use a 64 bit size.
+ NTTIME here is being used as a convenient 64-bit size.
+*/
+static void centry_put_time(struct cache_entry *centry, time_t t)
+{
+ NTTIME nt = (NTTIME)t;
+ centry_put_nttime(centry, nt);
+}
+
+/*
+ start a centry for output. When finished, call centry_end()
+*/
+struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
+{
+ struct cache_entry *centry;
+
+ if (!wcache->tdb)
+ return NULL;
+
+ centry = SMB_XMALLOC_P(struct cache_entry);
+
+ centry->len = 8192; /* reasonable default */
+ centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
+ centry->ofs = 0;
+ centry->sequence_number = domain->sequence_number;
+ centry_put_ntstatus(centry, status);
+ centry_put_uint32(centry, centry->sequence_number);
+ return centry;
+}
+
+/*
+ finish a centry and write it to the tdb
+*/
+static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
+static void centry_end(struct cache_entry *centry, const char *format, ...)
+{
+ va_list ap;
+ char *kstr;
+ TDB_DATA key, data;
+
+ if (opt_nocache) {
+ return;
+ }
+
+ va_start(ap, format);
+ smb_xvasprintf(&kstr, format, ap);
+ va_end(ap);
+
+ key = string_tdb_data(kstr);
+ data.dptr = centry->data;
+ data.dsize = centry->ofs;
+
+ tdb_store(wcache->tdb, key, data, TDB_REPLACE);
+ free(kstr);
+}
+
+static void wcache_save_name_to_sid(struct winbindd_domain *domain,
+ NTSTATUS status, const char *domain_name,
+ const char *name, const DOM_SID *sid,
+ enum lsa_SidType type)
+{
+ struct cache_entry *centry;
+ fstring uname;
+
+ centry = centry_start(domain, status);
+ if (!centry)
+ return;
+ centry_put_uint32(centry, type);
+ centry_put_sid(centry, sid);
+ fstrcpy(uname, name);
+ strupper_m(uname);
+ centry_end(centry, "NS/%s/%s", domain_name, uname);
+ DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
+ uname, sid_string_dbg(sid), nt_errstr(status)));
+ centry_free(centry);
+}
+
+static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
+ const DOM_SID *sid, const char *domain_name, const char *name, enum lsa_SidType type)
+{
+ struct cache_entry *centry;
+ fstring sid_string;
+
+ centry = centry_start(domain, status);
+ if (!centry)
+ return;
+
+ if (NT_STATUS_IS_OK(status)) {
+ centry_put_uint32(centry, type);
+ centry_put_string(centry, domain_name);
+ centry_put_string(centry, name);
+ }
+
+ centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
+ DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string,
+ name, nt_errstr(status)));
+ centry_free(centry);
+}
+
+
+static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info)
+{
+ struct cache_entry *centry;
+ fstring sid_string;
+
+ if (is_null_sid(&info->user_sid)) {
+ return;
+ }
+
+ centry = centry_start(domain, status);
+ if (!centry)
+ return;
+ centry_put_string(centry, info->acct_name);
+ centry_put_string(centry, info->full_name);
+ centry_put_string(centry, info->homedir);
+ centry_put_string(centry, info->shell);
+ centry_put_uint32(centry, info->primary_gid);
+ centry_put_sid(centry, &info->user_sid);
+ centry_put_sid(centry, &info->group_sid);
+ centry_end(centry, "U/%s", sid_to_fstring(sid_string,
+ &info->user_sid));
+ DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
+ centry_free(centry);
+}
+
+static void wcache_save_lockout_policy(struct winbindd_domain *domain,
+ NTSTATUS status,
+ struct samr_DomInfo12 *lockout_policy)
+{
+ struct cache_entry *centry;
+
+ centry = centry_start(domain, status);
+ if (!centry)
+ return;
+
+ centry_put_nttime(centry, lockout_policy->lockout_duration);
+ centry_put_nttime(centry, lockout_policy->lockout_window);
+ centry_put_uint16(centry, lockout_policy->lockout_threshold);
+
+ centry_end(centry, "LOC_POL/%s", domain->name);
+
+ DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
+
+ centry_free(centry);
+}
+
+static void wcache_save_password_policy(struct winbindd_domain *domain,
+ NTSTATUS status,
+ struct samr_DomInfo1 *policy)
+{
+ struct cache_entry *centry;
+
+ centry = centry_start(domain, status);
+ if (!centry)
+ return;
+
+ centry_put_uint16(centry, policy->min_password_length);
+ centry_put_uint16(centry, policy->password_history_length);
+ centry_put_uint32(centry, policy->password_properties);
+ centry_put_nttime(centry, policy->max_password_age);
+ centry_put_nttime(centry, policy->min_password_age);
+
+ centry_end(centry, "PWD_POL/%s", domain->name);
+
+ DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
+
+ centry_free(centry);
+}
+
+NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ TDB_DATA data;
+ fstring key_str, tmp;
+ uint32 rid;
+
+ if (!cache->tdb) {
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ if (is_null_sid(sid)) {
+ return NT_STATUS_INVALID_SID;
+ }
+
+ if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
+ return NT_STATUS_INVALID_SID;
+ }
+
+ fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
+
+ data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
+ if (!data.dptr) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ SAFE_FREE(data.dptr);
+ return NT_STATUS_OK;
+}
+
+/* Lookup creds for a SID - copes with old (unsalted) creds as well
+ as new salted ones. */
+
+NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ const uint8 **cached_nt_pass,
+ const uint8 **cached_salt)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ time_t t;
+ uint32 rid;
+ fstring tmp;
+
+ if (!cache->tdb) {
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ if (is_null_sid(sid)) {
+ return NT_STATUS_INVALID_SID;
+ }
+
+ if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
+ return NT_STATUS_INVALID_SID;
+ }
+
+ /* Try and get a salted cred first. If we can't
+ fall back to an unsalted cred. */
+
+ centry = wcache_fetch(cache, domain, "CRED/%s",
+ sid_to_fstring(tmp, sid));
+ if (!centry) {
+ DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
+ sid_string_dbg(sid)));
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ t = centry_time(centry);
+
+ /* In the salted case this isn't actually the nt_hash itself,
+ but the MD5 of the salt + nt_hash. Let the caller
+ sort this out. It can tell as we only return the cached_salt
+ if we are returning a salted cred. */
+
+ *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
+ if (*cached_nt_pass == NULL) {
+ fstring sidstr;
+
+ sid_to_fstring(sidstr, sid);
+
+ /* Bad (old) cred cache. Delete and pretend we
+ don't have it. */
+ DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
+ sidstr));
+ wcache_delete("CRED/%s", sidstr);
+ centry_free(centry);
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ /* We only have 17 bytes more data in the salted cred case. */
+ if (centry->len - centry->ofs == 17) {
+ *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
+ } else {
+ *cached_salt = NULL;
+ }
+
+ dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
+ if (*cached_salt) {
+ dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
+ }
+
+ status = centry->status;
+
+ DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
+ sid_string_dbg(sid), nt_errstr(status) ));
+
+ centry_free(centry);
+ return status;
+}
+
+/* Store creds for a SID - only writes out new salted ones. */
+
+NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ const uint8 nt_pass[NT_HASH_LEN])
+{
+ struct cache_entry *centry;
+ fstring sid_string;
+ uint32 rid;
+ uint8 cred_salt[NT_HASH_LEN];
+ uint8 salted_hash[NT_HASH_LEN];
+
+ if (is_null_sid(sid)) {
+ return NT_STATUS_INVALID_SID;
+ }
+
+ if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
+ return NT_STATUS_INVALID_SID;
+ }
+
+ centry = centry_start(domain, NT_STATUS_OK);
+ if (!centry) {
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
+
+ centry_put_time(centry, time(NULL));
+
+ /* Create a salt and then salt the hash. */
+ generate_random_buffer(cred_salt, NT_HASH_LEN);
+ E_md5hash(cred_salt, nt_pass, salted_hash);
+
+ centry_put_hash16(centry, salted_hash);
+ centry_put_hash16(centry, cred_salt);
+ centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
+
+ DEBUG(10,("wcache_save_creds: %s\n", sid_string));
+
+ centry_free(centry);
+
+ return NT_STATUS_OK;
+}
+
+
+/* Query display info. This is the basic user list fn */
+static NTSTATUS query_user_list(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ WINBIND_USERINFO **info)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ unsigned int i, retry;
+
+ if (!cache->tdb)
+ goto do_query;
+
+ centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
+ if (!centry)
+ goto do_query;
+
+ *num_entries = centry_uint32(centry);
+
+ if (*num_entries == 0)
+ goto do_cached;
+
+ (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
+ if (! (*info)) {
+ smb_panic_fn("query_user_list out of memory");
+ }
+ for (i=0; i<(*num_entries); i++) {
+ (*info)[i].acct_name = centry_string(centry, mem_ctx);
+ (*info)[i].full_name = centry_string(centry, mem_ctx);
+ (*info)[i].homedir = centry_string(centry, mem_ctx);
+ (*info)[i].shell = centry_string(centry, mem_ctx);
+ centry_sid(centry, mem_ctx, &(*info)[i].user_sid);
+ centry_sid(centry, mem_ctx, &(*info)[i].group_sid);
+ }
+
+do_cached:
+ status = centry->status;
+
+ DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
+ domain->name, nt_errstr(status) ));
+
+ centry_free(centry);
+ return status;
+
+do_query:
+ *num_entries = 0;
+ *info = NULL;
+
+ /* Return status value returned by seq number check */
+
+ if (!NT_STATUS_IS_OK(domain->last_status))
+ return domain->last_status;
+
+ /* Put the query_user_list() in a retry loop. There appears to be
+ * some bug either with Windows 2000 or Samba's handling of large
+ * rpc replies. This manifests itself as sudden disconnection
+ * at a random point in the enumeration of a large (60k) user list.
+ * The retry loop simply tries the operation again. )-: It's not
+ * pretty but an acceptable workaround until we work out what the
+ * real problem is. */
+
+ retry = 0;
+ do {
+
+ DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("query_user_list: returned 0x%08x, "
+ "retrying\n", NT_STATUS_V(status)));
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
+ DEBUG(3, ("query_user_list: flushing "
+ "connection cache\n"));
+ invalidate_cm_connection(&domain->conn);
+ }
+
+ } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
+ (retry++ < 5));
+
+ /* and save it */
+ refresh_sequence_number(domain, false);
+ centry = centry_start(domain, status);
+ if (!centry)
+ goto skip_save;
+ centry_put_uint32(centry, *num_entries);
+ for (i=0; i<(*num_entries); i++) {
+ centry_put_string(centry, (*info)[i].acct_name);
+ centry_put_string(centry, (*info)[i].full_name);
+ centry_put_string(centry, (*info)[i].homedir);
+ centry_put_string(centry, (*info)[i].shell);
+ centry_put_sid(centry, &(*info)[i].user_sid);
+ centry_put_sid(centry, &(*info)[i].group_sid);
+ if (domain->backend && domain->backend->consistent) {
+ /* when the backend is consistent we can pre-prime some mappings */
+ wcache_save_name_to_sid(domain, NT_STATUS_OK,
+ domain->name,
+ (*info)[i].acct_name,
+ &(*info)[i].user_sid,
+ SID_NAME_USER);
+ wcache_save_sid_to_name(domain, NT_STATUS_OK,
+ &(*info)[i].user_sid,
+ domain->name,
+ (*info)[i].acct_name,
+ SID_NAME_USER);
+ wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
+ }
+ }
+ centry_end(centry, "UL/%s", domain->name);
+ centry_free(centry);
+
+skip_save:
+ return status;
+}
+
+/* list all domain groups */
+static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ unsigned int i;
+
+ if (!cache->tdb)
+ goto do_query;
+
+ centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
+ if (!centry)
+ goto do_query;
+
+ *num_entries = centry_uint32(centry);
+
+ if (*num_entries == 0)
+ goto do_cached;
+
+ (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
+ if (! (*info)) {
+ smb_panic_fn("enum_dom_groups out of memory");
+ }
+ for (i=0; i<(*num_entries); i++) {
+ fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
+ fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
+ (*info)[i].rid = centry_uint32(centry);
+ }
+
+do_cached:
+ status = centry->status;
+
+ DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
+ domain->name, nt_errstr(status) ));
+
+ centry_free(centry);
+ return status;
+
+do_query:
+ *num_entries = 0;
+ *info = NULL;
+
+ /* Return status value returned by seq number check */
+
+ if (!NT_STATUS_IS_OK(domain->last_status))
+ return domain->last_status;
+
+ DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
+
+ /* and save it */
+ refresh_sequence_number(domain, false);
+ centry = centry_start(domain, status);
+ if (!centry)
+ goto skip_save;
+ centry_put_uint32(centry, *num_entries);
+ for (i=0; i<(*num_entries); i++) {
+ centry_put_string(centry, (*info)[i].acct_name);
+ centry_put_string(centry, (*info)[i].acct_desc);
+ centry_put_uint32(centry, (*info)[i].rid);
+ }
+ centry_end(centry, "GL/%s/domain", domain->name);
+ centry_free(centry);
+
+skip_save:
+ return status;
+}
+
+/* list all domain groups */
+static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ unsigned int i;
+
+ if (!cache->tdb)
+ goto do_query;
+
+ centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
+ if (!centry)
+ goto do_query;
+
+ *num_entries = centry_uint32(centry);
+
+ if (*num_entries == 0)
+ goto do_cached;
+
+ (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
+ if (! (*info)) {
+ smb_panic_fn("enum_dom_groups out of memory");
+ }
+ for (i=0; i<(*num_entries); i++) {
+ fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
+ fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
+ (*info)[i].rid = centry_uint32(centry);
+ }
+
+do_cached:
+
+ /* If we are returning cached data and the domain controller
+ is down then we don't know whether the data is up to date
+ or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
+ indicate this. */
+
+ if (wcache_server_down(domain)) {
+ DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
+ status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+ } else
+ status = centry->status;
+
+ DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
+ domain->name, nt_errstr(status) ));
+
+ centry_free(centry);
+ return status;
+
+do_query:
+ *num_entries = 0;
+ *info = NULL;
+
+ /* Return status value returned by seq number check */
+
+ if (!NT_STATUS_IS_OK(domain->last_status))
+ return domain->last_status;
+
+ DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
+
+ /* and save it */
+ refresh_sequence_number(domain, false);
+ centry = centry_start(domain, status);
+ if (!centry)
+ goto skip_save;
+ centry_put_uint32(centry, *num_entries);
+ for (i=0; i<(*num_entries); i++) {
+ centry_put_string(centry, (*info)[i].acct_name);
+ centry_put_string(centry, (*info)[i].acct_desc);
+ centry_put_uint32(centry, (*info)[i].rid);
+ }
+ centry_end(centry, "GL/%s/local", domain->name);
+ centry_free(centry);
+
+skip_save:
+ return status;
+}
+
+/* convert a single name to a sid in a domain */
+static NTSTATUS name_to_sid(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ enum winbindd_cmd orig_cmd,
+ const char *domain_name,
+ const char *name,
+ DOM_SID *sid,
+ enum lsa_SidType *type)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ fstring uname;
+
+ if (!cache->tdb)
+ goto do_query;
+
+ fstrcpy(uname, name);
+ strupper_m(uname);
+ centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
+ if (!centry)
+ goto do_query;
+
+ status = centry->status;
+ if (NT_STATUS_IS_OK(status)) {
+ *type = (enum lsa_SidType)centry_uint32(centry);
+ centry_sid(centry, mem_ctx, sid);
+ }
+
+ DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
+ domain->name, nt_errstr(status) ));
+
+ centry_free(centry);
+ return status;
+
+do_query:
+ ZERO_STRUCTP(sid);
+
+ /* If the seq number check indicated that there is a problem
+ * with this DC, then return that status... except for
+ * access_denied. This is special because the dc may be in
+ * "restrict anonymous = 1" mode, in which case it will deny
+ * most unauthenticated operations, but *will* allow the LSA
+ * name-to-sid that we try as a fallback. */
+
+ if (!(NT_STATUS_IS_OK(domain->last_status)
+ || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
+ return domain->last_status;
+
+ DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->name_to_sid(domain, mem_ctx, orig_cmd,
+ domain_name, name, sid, type);
+
+ /* and save it */
+ refresh_sequence_number(domain, false);
+
+ if (domain->online &&
+ (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
+ wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
+
+ /* Only save the reverse mapping if this was not a UPN */
+ if (!strchr(name, '@')) {
+ strupper_m(CONST_DISCARD(char *,domain_name));
+ strlower_m(CONST_DISCARD(char *,name));
+ wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
+ }
+ }
+
+ return status;
+}
+
+/* convert a sid to a user or group name. The sid is guaranteed to be in the domain
+ given */
+static NTSTATUS sid_to_name(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ char **domain_name,
+ char **name,
+ enum lsa_SidType *type)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ fstring sid_string;
+
+ if (!cache->tdb)
+ goto do_query;
+
+ centry = wcache_fetch(cache, domain, "SN/%s",
+ sid_to_fstring(sid_string, sid));
+ if (!centry)
+ goto do_query;
+
+ status = centry->status;
+ if (NT_STATUS_IS_OK(status)) {
+ *type = (enum lsa_SidType)centry_uint32(centry);
+ *domain_name = centry_string(centry, mem_ctx);
+ *name = centry_string(centry, mem_ctx);
+ }
+
+ DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
+ domain->name, nt_errstr(status) ));
+
+ centry_free(centry);
+ return status;
+
+do_query:
+ *name = NULL;
+ *domain_name = NULL;
+
+ /* If the seq number check indicated that there is a problem
+ * with this DC, then return that status... except for
+ * access_denied. This is special because the dc may be in
+ * "restrict anonymous = 1" mode, in which case it will deny
+ * most unauthenticated operations, but *will* allow the LSA
+ * sid-to-name that we try as a fallback. */
+
+ if (!(NT_STATUS_IS_OK(domain->last_status)
+ || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
+ return domain->last_status;
+
+ DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
+
+ /* and save it */
+ refresh_sequence_number(domain, false);
+ wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
+
+ /* We can't save the name to sid mapping here, as with sid history a
+ * later name2sid would give the wrong sid. */
+
+ return status;
+}
+
+static NTSTATUS rids_to_names(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *domain_sid,
+ uint32 *rids,
+ size_t num_rids,
+ char **domain_name,
+ char ***names,
+ enum lsa_SidType **types)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ size_t i;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ bool have_mapped;
+ bool have_unmapped;
+
+ *domain_name = NULL;
+ *names = NULL;
+ *types = NULL;
+
+ if (!cache->tdb) {
+ goto do_query;
+ }
+
+ if (num_rids == 0) {
+ return NT_STATUS_OK;
+ }
+
+ *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
+ *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
+
+ if ((*names == NULL) || (*types == NULL)) {
+ result = NT_STATUS_NO_MEMORY;
+ goto error;
+ }
+
+ have_mapped = have_unmapped = false;
+
+ for (i=0; i<num_rids; i++) {
+ DOM_SID sid;
+ struct cache_entry *centry;
+ fstring tmp;
+
+ if (!sid_compose(&sid, domain_sid, rids[i])) {
+ result = NT_STATUS_INTERNAL_ERROR;
+ goto error;
+ }
+
+ centry = wcache_fetch(cache, domain, "SN/%s",
+ sid_to_fstring(tmp, &sid));
+ if (!centry) {
+ goto do_query;
+ }
+
+ (*types)[i] = SID_NAME_UNKNOWN;
+ (*names)[i] = talloc_strdup(*names, "");
+
+ if (NT_STATUS_IS_OK(centry->status)) {
+ char *dom;
+ have_mapped = true;
+ (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
+
+ dom = centry_string(centry, mem_ctx);
+ if (*domain_name == NULL) {
+ *domain_name = dom;
+ } else {
+ talloc_free(dom);
+ }
+
+ (*names)[i] = centry_string(centry, *names);
+
+ } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
+ have_unmapped = true;
+
+ } else {
+ /* something's definitely wrong */
+ result = centry->status;
+ goto error;
+ }
+
+ centry_free(centry);
+ }
+
+ if (!have_mapped) {
+ return NT_STATUS_NONE_MAPPED;
+ }
+ if (!have_unmapped) {
+ return NT_STATUS_OK;
+ }
+ return STATUS_SOME_UNMAPPED;
+
+ do_query:
+
+ TALLOC_FREE(*names);
+ TALLOC_FREE(*types);
+
+ result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
+ rids, num_rids, domain_name,
+ names, types);
+
+ /*
+ None of the queried rids has been found so save all negative entries
+ */
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
+ for (i = 0; i < num_rids; i++) {
+ DOM_SID sid;
+ const char *name = "";
+ const enum lsa_SidType type = SID_NAME_UNKNOWN;
+ NTSTATUS status = NT_STATUS_NONE_MAPPED;
+
+ if (!sid_compose(&sid, domain_sid, rids[i])) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ wcache_save_sid_to_name(domain, status, &sid, *domain_name,
+ name, type);
+ }
+
+ return result;
+ }
+
+ /*
+ Some or all of the queried rids have been found.
+ */
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
+ return result;
+ }
+
+ refresh_sequence_number(domain, false);
+
+ for (i=0; i<num_rids; i++) {
+ DOM_SID sid;
+ NTSTATUS status;
+
+ if (!sid_compose(&sid, domain_sid, rids[i])) {
+ result = NT_STATUS_INTERNAL_ERROR;
+ goto error;
+ }
+
+ status = (*types)[i] == SID_NAME_UNKNOWN ?
+ NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
+
+ wcache_save_sid_to_name(domain, status, &sid, *domain_name,
+ (*names)[i], (*types)[i]);
+ }
+
+ return result;
+
+ error:
+
+ TALLOC_FREE(*names);
+ TALLOC_FREE(*types);
+ return result;
+}
+
+/* Lookup user information from a rid */
+static NTSTATUS query_user(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ WINBIND_USERINFO *info)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ fstring tmp;
+
+ if (!cache->tdb)
+ goto do_query;
+
+ centry = wcache_fetch(cache, domain, "U/%s",
+ sid_to_fstring(tmp, user_sid));
+
+ /* If we have an access denied cache entry and a cached info3 in the
+ samlogon cache then do a query. This will force the rpc back end
+ to return the info3 data. */
+
+ if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
+ netsamlogon_cache_have(user_sid)) {
+ DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
+ domain->last_status = NT_STATUS_OK;
+ centry_free(centry);
+ goto do_query;
+ }
+
+ if (!centry)
+ goto do_query;
+
+ /* if status is not ok then this is a negative hit
+ and the rest of the data doesn't matter */
+ status = centry->status;
+ if (NT_STATUS_IS_OK(status)) {
+ info->acct_name = centry_string(centry, mem_ctx);
+ info->full_name = centry_string(centry, mem_ctx);
+ info->homedir = centry_string(centry, mem_ctx);
+ info->shell = centry_string(centry, mem_ctx);
+ info->primary_gid = centry_uint32(centry);
+ centry_sid(centry, mem_ctx, &info->user_sid);
+ centry_sid(centry, mem_ctx, &info->group_sid);
+ }
+
+ DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
+ domain->name, nt_errstr(status) ));
+
+ centry_free(centry);
+ return status;
+
+do_query:
+ ZERO_STRUCTP(info);
+
+ /* Return status value returned by seq number check */
+
+ if (!NT_STATUS_IS_OK(domain->last_status))
+ return domain->last_status;
+
+ DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
+
+ /* and save it */
+ refresh_sequence_number(domain, false);
+ wcache_save_user(domain, status, info);
+
+ return status;
+}
+
+
+/* Lookup groups a user is a member of. */
+static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ uint32 *num_groups, DOM_SID **user_gids)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ unsigned int i;
+ fstring sid_string;
+
+ if (!cache->tdb)
+ goto do_query;
+
+ centry = wcache_fetch(cache, domain, "UG/%s",
+ sid_to_fstring(sid_string, user_sid));
+
+ /* If we have an access denied cache entry and a cached info3 in the
+ samlogon cache then do a query. This will force the rpc back end
+ to return the info3 data. */
+
+ if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
+ netsamlogon_cache_have(user_sid)) {
+ DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
+ domain->last_status = NT_STATUS_OK;
+ centry_free(centry);
+ goto do_query;
+ }
+
+ if (!centry)
+ goto do_query;
+
+ *num_groups = centry_uint32(centry);
+
+ if (*num_groups == 0)
+ goto do_cached;
+
+ (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
+ if (! (*user_gids)) {
+ smb_panic_fn("lookup_usergroups out of memory");
+ }
+ for (i=0; i<(*num_groups); i++) {
+ centry_sid(centry, mem_ctx, &(*user_gids)[i]);
+ }
+
+do_cached:
+ status = centry->status;
+
+ DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
+ domain->name, nt_errstr(status) ));
+
+ centry_free(centry);
+ return status;
+
+do_query:
+ (*num_groups) = 0;
+ (*user_gids) = NULL;
+
+ /* Return status value returned by seq number check */
+
+ if (!NT_STATUS_IS_OK(domain->last_status))
+ return domain->last_status;
+
+ DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
+
+ if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
+ goto skip_save;
+
+ /* and save it */
+ refresh_sequence_number(domain, false);
+ centry = centry_start(domain, status);
+ if (!centry)
+ goto skip_save;
+
+ centry_put_uint32(centry, *num_groups);
+ for (i=0; i<(*num_groups); i++) {
+ centry_put_sid(centry, &(*user_gids)[i]);
+ }
+
+ centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
+ centry_free(centry);
+
+skip_save:
+ return status;
+}
+
+static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 num_sids, const DOM_SID *sids,
+ uint32 *num_aliases, uint32 **alias_rids)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ char *sidlist = talloc_strdup(mem_ctx, "");
+ int i;
+
+ if (!cache->tdb)
+ goto do_query;
+
+ if (num_sids == 0) {
+ *num_aliases = 0;
+ *alias_rids = NULL;
+ return NT_STATUS_OK;
+ }
+
+ /* We need to cache indexed by the whole list of SIDs, the aliases
+ * resulting might come from any of the SIDs. */
+
+ for (i=0; i<num_sids; i++) {
+ fstring tmp;
+ sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
+ sid_to_fstring(tmp, &sids[i]));
+ if (sidlist == NULL)
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ centry = wcache_fetch(cache, domain, "UA%s", sidlist);
+
+ if (!centry)
+ goto do_query;
+
+ *num_aliases = centry_uint32(centry);
+ *alias_rids = NULL;
+
+ if (*num_aliases) {
+ (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
+
+ if ((*alias_rids) == NULL) {
+ centry_free(centry);
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ (*alias_rids) = NULL;
+ }
+
+ for (i=0; i<(*num_aliases); i++)
+ (*alias_rids)[i] = centry_uint32(centry);
+
+ status = centry->status;
+
+ DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
+ "status %s\n", domain->name, nt_errstr(status)));
+
+ centry_free(centry);
+ return status;
+
+ do_query:
+ (*num_aliases) = 0;
+ (*alias_rids) = NULL;
+
+ if (!NT_STATUS_IS_OK(domain->last_status))
+ return domain->last_status;
+
+ DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
+ "for domain %s\n", domain->name ));
+
+ status = domain->backend->lookup_useraliases(domain, mem_ctx,
+ num_sids, sids,
+ num_aliases, alias_rids);
+
+ /* and save it */
+ refresh_sequence_number(domain, false);
+ centry = centry_start(domain, status);
+ if (!centry)
+ goto skip_save;
+ centry_put_uint32(centry, *num_aliases);
+ for (i=0; i<(*num_aliases); i++)
+ centry_put_uint32(centry, (*alias_rids)[i]);
+ centry_end(centry, "UA%s", sidlist);
+ centry_free(centry);
+
+ skip_save:
+ return status;
+}
+
+
+static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group_sid, uint32 *num_names,
+ DOM_SID **sid_mem, char ***names,
+ uint32 **name_types)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ unsigned int i;
+ fstring sid_string;
+
+ if (!cache->tdb)
+ goto do_query;
+
+ centry = wcache_fetch(cache, domain, "GM/%s",
+ sid_to_fstring(sid_string, group_sid));
+ if (!centry)
+ goto do_query;
+
+ *num_names = centry_uint32(centry);
+
+ if (*num_names == 0)
+ goto do_cached;
+
+ (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
+ (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
+ (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
+
+ if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
+ smb_panic_fn("lookup_groupmem out of memory");
+ }
+
+ for (i=0; i<(*num_names); i++) {
+ centry_sid(centry, mem_ctx, &(*sid_mem)[i]);
+ (*names)[i] = centry_string(centry, mem_ctx);
+ (*name_types)[i] = centry_uint32(centry);
+ }
+
+do_cached:
+ status = centry->status;
+
+ DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
+ domain->name, nt_errstr(status)));
+
+ centry_free(centry);
+ return status;
+
+do_query:
+ (*num_names) = 0;
+ (*sid_mem) = NULL;
+ (*names) = NULL;
+ (*name_types) = NULL;
+
+ /* Return status value returned by seq number check */
+
+ if (!NT_STATUS_IS_OK(domain->last_status))
+ return domain->last_status;
+
+ DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
+ sid_mem, names, name_types);
+
+ /* and save it */
+ refresh_sequence_number(domain, false);
+ centry = centry_start(domain, status);
+ if (!centry)
+ goto skip_save;
+ centry_put_uint32(centry, *num_names);
+ for (i=0; i<(*num_names); i++) {
+ centry_put_sid(centry, &(*sid_mem)[i]);
+ centry_put_string(centry, (*names)[i]);
+ centry_put_uint32(centry, (*name_types)[i]);
+ }
+ centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
+ centry_free(centry);
+
+skip_save:
+ return status;
+}
+
+/* find the sequence number for a domain */
+static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
+{
+ refresh_sequence_number(domain, false);
+
+ *seq = domain->sequence_number;
+
+ return NT_STATUS_OK;
+}
+
+/* enumerate trusted domains
+ * (we need to have the list of trustdoms in the cache when we go offline) -
+ * Guenther */
+static NTSTATUS trusted_domains(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_domains,
+ char ***names,
+ char ***alt_names,
+ DOM_SID **dom_sids)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ int i;
+
+ if (!cache->tdb)
+ goto do_query;
+
+ centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
+
+ if (!centry) {
+ goto do_query;
+ }
+
+ *num_domains = centry_uint32(centry);
+
+ if (*num_domains) {
+ (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
+ (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
+ (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
+
+ if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
+ smb_panic_fn("trusted_domains out of memory");
+ }
+ } else {
+ (*names) = NULL;
+ (*alt_names) = NULL;
+ (*dom_sids) = NULL;
+ }
+
+ for (i=0; i<(*num_domains); i++) {
+ (*names)[i] = centry_string(centry, mem_ctx);
+ (*alt_names)[i] = centry_string(centry, mem_ctx);
+ if (!centry_sid(centry, mem_ctx, &(*dom_sids)[i])) {
+ sid_copy(&(*dom_sids)[i], &global_sid_NULL);
+ }
+ }
+
+ status = centry->status;
+
+ DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
+ domain->name, *num_domains, nt_errstr(status) ));
+
+ centry_free(centry);
+ return status;
+
+do_query:
+ (*num_domains) = 0;
+ (*dom_sids) = NULL;
+ (*names) = NULL;
+ (*alt_names) = NULL;
+
+ /* Return status value returned by seq number check */
+
+ if (!NT_STATUS_IS_OK(domain->last_status))
+ return domain->last_status;
+
+ DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
+ names, alt_names, dom_sids);
+
+ /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
+ * so that the generic centry handling still applies correctly -
+ * Guenther*/
+
+ if (!NT_STATUS_IS_ERR(status)) {
+ status = NT_STATUS_OK;
+ }
+
+
+#if 0 /* Disabled as we want the trust dom list to be managed by
+ the main parent and always to make the query. --jerry */
+
+ /* and save it */
+ refresh_sequence_number(domain, false);
+
+ centry = centry_start(domain, status);
+ if (!centry)
+ goto skip_save;
+
+ centry_put_uint32(centry, *num_domains);
+
+ for (i=0; i<(*num_domains); i++) {
+ centry_put_string(centry, (*names)[i]);
+ centry_put_string(centry, (*alt_names)[i]);
+ centry_put_sid(centry, &(*dom_sids)[i]);
+ }
+
+ centry_end(centry, "TRUSTDOMS/%s", domain->name);
+
+ centry_free(centry);
+
+skip_save:
+#endif
+
+ return status;
+}
+
+/* get lockout policy */
+static NTSTATUS lockout_policy(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ struct samr_DomInfo12 *policy)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+
+ if (!cache->tdb)
+ goto do_query;
+
+ centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
+
+ if (!centry)
+ goto do_query;
+
+ policy->lockout_duration = centry_nttime(centry);
+ policy->lockout_window = centry_nttime(centry);
+ policy->lockout_threshold = centry_uint16(centry);
+
+ status = centry->status;
+
+ DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
+ domain->name, nt_errstr(status) ));
+
+ centry_free(centry);
+ return status;
+
+do_query:
+ ZERO_STRUCTP(policy);
+
+ /* Return status value returned by seq number check */
+
+ if (!NT_STATUS_IS_OK(domain->last_status))
+ return domain->last_status;
+
+ DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->lockout_policy(domain, mem_ctx, policy);
+
+ /* and save it */
+ refresh_sequence_number(domain, false);
+ wcache_save_lockout_policy(domain, status, policy);
+
+ return status;
+}
+
+/* get password policy */
+static NTSTATUS password_policy(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ struct samr_DomInfo1 *policy)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+
+ if (!cache->tdb)
+ goto do_query;
+
+ centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
+
+ if (!centry)
+ goto do_query;
+
+ policy->min_password_length = centry_uint16(centry);
+ policy->password_history_length = centry_uint16(centry);
+ policy->password_properties = centry_uint32(centry);
+ policy->max_password_age = centry_nttime(centry);
+ policy->min_password_age = centry_nttime(centry);
+
+ status = centry->status;
+
+ DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
+ domain->name, nt_errstr(status) ));
+
+ centry_free(centry);
+ return status;
+
+do_query:
+ ZERO_STRUCTP(policy);
+
+ /* Return status value returned by seq number check */
+
+ if (!NT_STATUS_IS_OK(domain->last_status))
+ return domain->last_status;
+
+ DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->password_policy(domain, mem_ctx, policy);
+
+ /* and save it */
+ refresh_sequence_number(domain, false);
+ if (NT_STATUS_IS_OK(status)) {
+ wcache_save_password_policy(domain, status, policy);
+ }
+
+ return status;
+}
+
+
+/* Invalidate cached user and group lists coherently */
+
+static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
+ void *state)
+{
+ if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
+ strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
+ tdb_delete(the_tdb, kbuf);
+
+ return 0;
+}
+
+/* Invalidate the getpwnam and getgroups entries for a winbindd domain */
+
+void wcache_invalidate_samlogon(struct winbindd_domain *domain,
+ struct netr_SamInfo3 *info3)
+{
+ DOM_SID sid;
+ fstring key_str, sid_string;
+ struct winbind_cache *cache;
+
+ /* dont clear cached U/SID and UG/SID entries when we want to logon
+ * offline - gd */
+
+ if (lp_winbind_offline_logon()) {
+ return;
+ }
+
+ if (!domain)
+ return;
+
+ cache = get_cache(domain);
+
+ if (!cache->tdb) {
+ return;
+ }
+
+ sid_copy(&sid, info3->base.domain_sid);
+ sid_append_rid(&sid, info3->base.rid);
+
+ /* Clear U/SID cache entry */
+ fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
+ DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
+ tdb_delete(cache->tdb, string_tdb_data(key_str));
+
+ /* Clear UG/SID cache entry */
+ fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
+ DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
+ tdb_delete(cache->tdb, string_tdb_data(key_str));
+
+ /* Samba/winbindd never needs this. */
+ netsamlogon_clear_cached_user(info3);
+}
+
+bool wcache_invalidate_cache(void)
+{
+ struct winbindd_domain *domain;
+
+ for (domain = domain_list(); domain; domain = domain->next) {
+ struct winbind_cache *cache = get_cache(domain);
+
+ DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
+ "entries for %s\n", domain->name));
+ if (cache) {
+ if (cache->tdb) {
+ tdb_traverse(cache->tdb, traverse_fn, NULL);
+ } else {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool init_wcache(void)
+{
+ if (wcache == NULL) {
+ wcache = SMB_XMALLOC_P(struct winbind_cache);
+ ZERO_STRUCTP(wcache);
+ }
+
+ if (wcache->tdb != NULL)
+ return true;
+
+ /* when working offline we must not clear the cache on restart */
+ wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
+ WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
+ lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
+ O_RDWR|O_CREAT, 0600);
+
+ if (wcache->tdb == NULL) {
+ DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
+ return false;
+ }
+
+ return true;
+}
+
+/************************************************************************
+ This is called by the parent to initialize the cache file.
+ We don't need sophisticated locking here as we know we're the
+ only opener.
+************************************************************************/
+
+bool initialize_winbindd_cache(void)
+{
+ bool cache_bad = true;
+ uint32 vers;
+
+ if (!init_wcache()) {
+ DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
+ return false;
+ }
+
+ /* Check version number. */
+ if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
+ vers == WINBINDD_CACHE_VERSION) {
+ cache_bad = false;
+ }
+
+ if (cache_bad) {
+ DEBUG(0,("initialize_winbindd_cache: clearing cache "
+ "and re-creating with version number %d\n",
+ WINBINDD_CACHE_VERSION ));
+
+ tdb_close(wcache->tdb);
+ wcache->tdb = NULL;
+
+ if (unlink(lock_path("winbindd_cache.tdb")) == -1) {
+ DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
+ lock_path("winbindd_cache.tdb"),
+ strerror(errno) ));
+ return false;
+ }
+ if (!init_wcache()) {
+ DEBUG(0,("initialize_winbindd_cache: re-initialization "
+ "init_wcache failed.\n"));
+ return false;
+ }
+
+ /* Write the version. */
+ if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
+ DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
+ tdb_errorstr(wcache->tdb) ));
+ return false;
+ }
+ }
+
+ tdb_close(wcache->tdb);
+ wcache->tdb = NULL;
+ return true;
+}
+
+void close_winbindd_cache(void)
+{
+ if (!wcache) {
+ return;
+ }
+ if (wcache->tdb) {
+ tdb_close(wcache->tdb);
+ wcache->tdb = NULL;
+ }
+}
+
+void cache_store_response(pid_t pid, struct winbindd_response *response)
+{
+ fstring key_str;
+
+ if (!init_wcache())
+ return;
+
+ DEBUG(10, ("Storing response for pid %d, len %d\n",
+ pid, response->length));
+
+ fstr_sprintf(key_str, "DR/%d", pid);
+ if (tdb_store(wcache->tdb, string_tdb_data(key_str),
+ make_tdb_data((uint8 *)response, sizeof(*response)),
+ TDB_REPLACE) == -1)
+ return;
+
+ if (response->length == sizeof(*response))
+ return;
+
+ /* There's extra data */
+
+ DEBUG(10, ("Storing extra data: len=%d\n",
+ (int)(response->length - sizeof(*response))));
+
+ fstr_sprintf(key_str, "DE/%d", pid);
+ if (tdb_store(wcache->tdb, string_tdb_data(key_str),
+ make_tdb_data((uint8 *)response->extra_data.data,
+ response->length - sizeof(*response)),
+ TDB_REPLACE) == 0)
+ return;
+
+ /* We could not store the extra data, make sure the tdb does not
+ * contain a main record with wrong dangling extra data */
+
+ fstr_sprintf(key_str, "DR/%d", pid);
+ tdb_delete(wcache->tdb, string_tdb_data(key_str));
+
+ return;
+}
+
+bool cache_retrieve_response(pid_t pid, struct winbindd_response * response)
+{
+ TDB_DATA data;
+ fstring key_str;
+
+ if (!init_wcache())
+ return false;
+
+ DEBUG(10, ("Retrieving response for pid %d\n", pid));
+
+ fstr_sprintf(key_str, "DR/%d", pid);
+ data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
+
+ if (data.dptr == NULL)
+ return false;
+
+ if (data.dsize != sizeof(*response))
+ return false;
+
+ memcpy(response, data.dptr, data.dsize);
+ SAFE_FREE(data.dptr);
+
+ if (response->length == sizeof(*response)) {
+ response->extra_data.data = NULL;
+ return true;
+ }
+
+ /* There's extra data */
+
+ DEBUG(10, ("Retrieving extra data length=%d\n",
+ (int)(response->length - sizeof(*response))));
+
+ fstr_sprintf(key_str, "DE/%d", pid);
+ data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
+
+ if (data.dptr == NULL) {
+ DEBUG(0, ("Did not find extra data\n"));
+ return false;
+ }
+
+ if (data.dsize != (response->length - sizeof(*response))) {
+ DEBUG(0, ("Invalid extra data length: %d\n", (int)data.dsize));
+ SAFE_FREE(data.dptr);
+ return false;
+ }
+
+ dump_data(11, (uint8 *)data.dptr, data.dsize);
+
+ response->extra_data.data = data.dptr;
+ return true;
+}
+
+void cache_cleanup_response(pid_t pid)
+{
+ fstring key_str;
+
+ if (!init_wcache())
+ return;
+
+ fstr_sprintf(key_str, "DR/%d", pid);
+ tdb_delete(wcache->tdb, string_tdb_data(key_str));
+
+ fstr_sprintf(key_str, "DE/%d", pid);
+ tdb_delete(wcache->tdb, string_tdb_data(key_str));
+
+ return;
+}
+
+
+bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ char **domain_name, char **name,
+ enum lsa_SidType *type)
+{
+ struct winbindd_domain *domain;
+ struct winbind_cache *cache;
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ fstring tmp;
+
+ domain = find_lookup_domain_from_sid(sid);
+ if (domain == NULL) {
+ return false;
+ }
+
+ cache = get_cache(domain);
+
+ if (cache->tdb == NULL) {
+ return false;
+ }
+
+ centry = wcache_fetch(cache, domain, "SN/%s",
+ sid_to_fstring(tmp, sid));
+ if (centry == NULL) {
+ return false;
+ }
+
+ if (NT_STATUS_IS_OK(centry->status)) {
+ *type = (enum lsa_SidType)centry_uint32(centry);
+ *domain_name = centry_string(centry, mem_ctx);
+ *name = centry_string(centry, mem_ctx);
+ }
+
+ status = centry->status;
+ centry_free(centry);
+ return NT_STATUS_IS_OK(status);
+}
+
+bool lookup_cached_name(TALLOC_CTX *mem_ctx,
+ const char *domain_name,
+ const char *name,
+ DOM_SID *sid,
+ enum lsa_SidType *type)
+{
+ struct winbindd_domain *domain;
+ struct winbind_cache *cache;
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ fstring uname;
+ bool original_online_state;
+
+ domain = find_lookup_domain_from_name(domain_name);
+ if (domain == NULL) {
+ return false;
+ }
+
+ cache = get_cache(domain);
+
+ if (cache->tdb == NULL) {
+ return false;
+ }
+
+ fstrcpy(uname, name);
+ strupper_m(uname);
+
+ /* If we are doing a cached logon, temporarily set the domain
+ offline so the cache won't expire the entry */
+
+ original_online_state = domain->online;
+ domain->online = false;
+ centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
+ domain->online = original_online_state;
+
+ if (centry == NULL) {
+ return false;
+ }
+
+ if (NT_STATUS_IS_OK(centry->status)) {
+ *type = (enum lsa_SidType)centry_uint32(centry);
+ centry_sid(centry, mem_ctx, sid);
+ }
+
+ status = centry->status;
+ centry_free(centry);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+void cache_name2sid(struct winbindd_domain *domain,
+ const char *domain_name, const char *name,
+ enum lsa_SidType type, const DOM_SID *sid)
+{
+ refresh_sequence_number(domain, false);
+ wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
+ sid, type);
+}
+
+/*
+ * The original idea that this cache only contains centries has
+ * been blurred - now other stuff gets put in here. Ensure we
+ * ignore these things on cleanup.
+ */
+
+static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
+ TDB_DATA dbuf, void *state)
+{
+ struct cache_entry *centry;
+
+ if (is_non_centry_key(kbuf)) {
+ return 0;
+ }
+
+ centry = wcache_fetch_raw((char *)kbuf.dptr);
+ if (!centry) {
+ return 0;
+ }
+
+ if (!NT_STATUS_IS_OK(centry->status)) {
+ DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
+ tdb_delete(the_tdb, kbuf);
+ }
+
+ centry_free(centry);
+ return 0;
+}
+
+/* flush the cache */
+void wcache_flush_cache(void)
+{
+ if (!wcache)
+ return;
+ if (wcache->tdb) {
+ tdb_close(wcache->tdb);
+ wcache->tdb = NULL;
+ }
+ if (opt_nocache)
+ return;
+
+ /* when working offline we must not clear the cache on restart */
+ wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
+ WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
+ lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
+ O_RDWR|O_CREAT, 0600);
+
+ if (!wcache->tdb) {
+ DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
+ return;
+ }
+
+ tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
+
+ DEBUG(10,("wcache_flush_cache success\n"));
+}
+
+/* Count cached creds */
+
+static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
+ void *state)
+{
+ int *cred_count = (int*)state;
+
+ if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
+ (*cred_count)++;
+ }
+ return 0;
+}
+
+NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
+{
+ struct winbind_cache *cache = get_cache(domain);
+
+ *count = 0;
+
+ if (!cache->tdb) {
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
+
+ return NT_STATUS_OK;
+}
+
+struct cred_list {
+ struct cred_list *prev, *next;
+ TDB_DATA key;
+ fstring name;
+ time_t created;
+};
+static struct cred_list *wcache_cred_list;
+
+static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
+ void *state)
+{
+ struct cred_list *cred;
+
+ if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
+
+ cred = SMB_MALLOC_P(struct cred_list);
+ if (cred == NULL) {
+ DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
+ return -1;
+ }
+
+ ZERO_STRUCTP(cred);
+
+ /* save a copy of the key */
+
+ fstrcpy(cred->name, (const char *)kbuf.dptr);
+ DLIST_ADD(wcache_cred_list, cred);
+ }
+
+ return 0;
+}
+
+NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ NTSTATUS status;
+ int ret;
+ struct cred_list *cred, *oldest = NULL;
+
+ if (!cache->tdb) {
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ /* we possibly already have an entry */
+ if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
+
+ fstring key_str, tmp;
+
+ DEBUG(11,("we already have an entry, deleting that\n"));
+
+ fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
+
+ tdb_delete(cache->tdb, string_tdb_data(key_str));
+
+ return NT_STATUS_OK;
+ }
+
+ ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
+ if (ret == 0) {
+ return NT_STATUS_OK;
+ } else if ((ret == -1) || (wcache_cred_list == NULL)) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ ZERO_STRUCTP(oldest);
+
+ for (cred = wcache_cred_list; cred; cred = cred->next) {
+
+ TDB_DATA data;
+ time_t t;
+
+ data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
+ if (!data.dptr) {
+ DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
+ cred->name));
+ status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ goto done;
+ }
+
+ t = IVAL(data.dptr, 0);
+ SAFE_FREE(data.dptr);
+
+ if (!oldest) {
+ oldest = SMB_MALLOC_P(struct cred_list);
+ if (oldest == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ fstrcpy(oldest->name, cred->name);
+ oldest->created = t;
+ continue;
+ }
+
+ if (t < oldest->created) {
+ fstrcpy(oldest->name, cred->name);
+ oldest->created = t;
+ }
+ }
+
+ if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
+ status = NT_STATUS_OK;
+ } else {
+ status = NT_STATUS_UNSUCCESSFUL;
+ }
+done:
+ SAFE_FREE(wcache_cred_list);
+ SAFE_FREE(oldest);
+
+ return status;
+}
+
+/* Change the global online/offline state. */
+bool set_global_winbindd_state_offline(void)
+{
+ TDB_DATA data;
+
+ DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
+
+ /* Only go offline if someone has created
+ the key "WINBINDD_OFFLINE" in the cache tdb. */
+
+ if (wcache == NULL || wcache->tdb == NULL) {
+ DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
+ return false;
+ }
+
+ if (!lp_winbind_offline_logon()) {
+ DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
+ return false;
+ }
+
+ if (global_winbindd_offline_state) {
+ /* Already offline. */
+ return true;
+ }
+
+ data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
+
+ if (!data.dptr || data.dsize != 4) {
+ DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
+ SAFE_FREE(data.dptr);
+ return false;
+ } else {
+ DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
+ global_winbindd_offline_state = true;
+ SAFE_FREE(data.dptr);
+ return true;
+ }
+}
+
+void set_global_winbindd_state_online(void)
+{
+ DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
+
+ if (!lp_winbind_offline_logon()) {
+ DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
+ return;
+ }
+
+ if (!global_winbindd_offline_state) {
+ /* Already online. */
+ return;
+ }
+ global_winbindd_offline_state = false;
+
+ if (!wcache->tdb) {
+ return;
+ }
+
+ /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
+ tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
+}
+
+bool get_global_winbindd_state_offline(void)
+{
+ return global_winbindd_offline_state;
+}
+
+/***********************************************************************
+ Validate functions for all possible cache tdb keys.
+***********************************************************************/
+
+static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
+ struct tdb_validation_status *state)
+{
+ struct cache_entry *centry;
+
+ centry = SMB_XMALLOC_P(struct cache_entry);
+ centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
+ if (!centry->data) {
+ SAFE_FREE(centry);
+ return NULL;
+ }
+ centry->len = data.dsize;
+ centry->ofs = 0;
+
+ if (centry->len < 8) {
+ /* huh? corrupt cache? */
+ DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
+ centry_free(centry);
+ state->bad_entry = true;
+ state->success = false;
+ return NULL;
+ }
+
+ centry->status = NT_STATUS(centry_uint32(centry));
+ centry->sequence_number = centry_uint32(centry);
+ return centry;
+}
+
+static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ if (dbuf.dsize != 8) {
+ DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
+ keystr, (unsigned int)dbuf.dsize ));
+ state->bad_entry = true;
+ return 1;
+ }
+ return 0;
+}
+
+static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
+ if (!centry) {
+ return 1;
+ }
+
+ (void)centry_uint32(centry);
+ if (NT_STATUS_IS_OK(centry->status)) {
+ DOM_SID sid;
+ (void)centry_sid(centry, mem_ctx, &sid);
+ }
+
+ centry_free(centry);
+
+ if (!(state->success)) {
+ return 1;
+ }
+ DEBUG(10,("validate_ns: %s ok\n", keystr));
+ return 0;
+}
+
+static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
+ if (!centry) {
+ return 1;
+ }
+
+ if (NT_STATUS_IS_OK(centry->status)) {
+ (void)centry_uint32(centry);
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_string(centry, mem_ctx);
+ }
+
+ centry_free(centry);
+
+ if (!(state->success)) {
+ return 1;
+ }
+ DEBUG(10,("validate_sn: %s ok\n", keystr));
+ return 0;
+}
+
+static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
+ DOM_SID sid;
+
+ if (!centry) {
+ return 1;
+ }
+
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_uint32(centry);
+ (void)centry_sid(centry, mem_ctx, &sid);
+ (void)centry_sid(centry, mem_ctx, &sid);
+
+ centry_free(centry);
+
+ if (!(state->success)) {
+ return 1;
+ }
+ DEBUG(10,("validate_u: %s ok\n", keystr));
+ return 0;
+}
+
+static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
+
+ if (!centry) {
+ return 1;
+ }
+
+ (void)centry_nttime(centry);
+ (void)centry_nttime(centry);
+ (void)centry_uint16(centry);
+
+ centry_free(centry);
+
+ if (!(state->success)) {
+ return 1;
+ }
+ DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
+ return 0;
+}
+
+static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
+
+ if (!centry) {
+ return 1;
+ }
+
+ (void)centry_uint16(centry);
+ (void)centry_uint16(centry);
+ (void)centry_uint32(centry);
+ (void)centry_nttime(centry);
+ (void)centry_nttime(centry);
+
+ centry_free(centry);
+
+ if (!(state->success)) {
+ return 1;
+ }
+ DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
+ return 0;
+}
+
+static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
+
+ if (!centry) {
+ return 1;
+ }
+
+ (void)centry_time(centry);
+ (void)centry_hash16(centry, mem_ctx);
+
+ /* We only have 17 bytes more data in the salted cred case. */
+ if (centry->len - centry->ofs == 17) {
+ (void)centry_hash16(centry, mem_ctx);
+ }
+
+ centry_free(centry);
+
+ if (!(state->success)) {
+ return 1;
+ }
+ DEBUG(10,("validate_cred: %s ok\n", keystr));
+ return 0;
+}
+
+static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
+ int32 num_entries, i;
+
+ if (!centry) {
+ return 1;
+ }
+
+ num_entries = (int32)centry_uint32(centry);
+
+ for (i=0; i< num_entries; i++) {
+ DOM_SID sid;
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_sid(centry, mem_ctx, &sid);
+ (void)centry_sid(centry, mem_ctx, &sid);
+ }
+
+ centry_free(centry);
+
+ if (!(state->success)) {
+ return 1;
+ }
+ DEBUG(10,("validate_ul: %s ok\n", keystr));
+ return 0;
+}
+
+static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
+ int32 num_entries, i;
+
+ if (!centry) {
+ return 1;
+ }
+
+ num_entries = centry_uint32(centry);
+
+ for (i=0; i< num_entries; i++) {
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_uint32(centry);
+ }
+
+ centry_free(centry);
+
+ if (!(state->success)) {
+ return 1;
+ }
+ DEBUG(10,("validate_gl: %s ok\n", keystr));
+ return 0;
+}
+
+static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
+ int32 num_groups, i;
+
+ if (!centry) {
+ return 1;
+ }
+
+ num_groups = centry_uint32(centry);
+
+ for (i=0; i< num_groups; i++) {
+ DOM_SID sid;
+ centry_sid(centry, mem_ctx, &sid);
+ }
+
+ centry_free(centry);
+
+ if (!(state->success)) {
+ return 1;
+ }
+ DEBUG(10,("validate_ug: %s ok\n", keystr));
+ return 0;
+}
+
+static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
+ int32 num_aliases, i;
+
+ if (!centry) {
+ return 1;
+ }
+
+ num_aliases = centry_uint32(centry);
+
+ for (i=0; i < num_aliases; i++) {
+ (void)centry_uint32(centry);
+ }
+
+ centry_free(centry);
+
+ if (!(state->success)) {
+ return 1;
+ }
+ DEBUG(10,("validate_ua: %s ok\n", keystr));
+ return 0;
+}
+
+static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
+ int32 num_names, i;
+
+ if (!centry) {
+ return 1;
+ }
+
+ num_names = centry_uint32(centry);
+
+ for (i=0; i< num_names; i++) {
+ DOM_SID sid;
+ centry_sid(centry, mem_ctx, &sid);
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_uint32(centry);
+ }
+
+ centry_free(centry);
+
+ if (!(state->success)) {
+ return 1;
+ }
+ DEBUG(10,("validate_gm: %s ok\n", keystr));
+ return 0;
+}
+
+static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ /* Can't say anything about this other than must be nonzero. */
+ if (dbuf.dsize == 0) {
+ DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
+ keystr));
+ state->bad_entry = true;
+ state->success = false;
+ return 1;
+ }
+
+ DEBUG(10,("validate_dr: %s ok\n", keystr));
+ return 0;
+}
+
+static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ /* Can't say anything about this other than must be nonzero. */
+ if (dbuf.dsize == 0) {
+ DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
+ keystr));
+ state->bad_entry = true;
+ state->success = false;
+ return 1;
+ }
+
+ DEBUG(10,("validate_de: %s ok\n", keystr));
+ return 0;
+}
+
+static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
+ TDB_DATA dbuf, struct tdb_validation_status *state)
+{
+ struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
+
+ if (!centry) {
+ return 1;
+ }
+
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_uint32(centry);
+
+ centry_free(centry);
+
+ if (!(state->success)) {
+ return 1;
+ }
+ DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
+ return 0;
+}
+
+static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
+ int32 num_domains, i;
+
+ if (!centry) {
+ return 1;
+ }
+
+ num_domains = centry_uint32(centry);
+
+ for (i=0; i< num_domains; i++) {
+ DOM_SID sid;
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_string(centry, mem_ctx);
+ (void)centry_sid(centry, mem_ctx, &sid);
+ }
+
+ centry_free(centry);
+
+ if (!(state->success)) {
+ return 1;
+ }
+ DEBUG(10,("validate_trustdoms: %s ok\n", keystr));
+ return 0;
+}
+
+static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
+ TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ if (dbuf.dsize == 0) {
+ DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
+ "key %s (len ==0) ?\n", keystr));
+ state->bad_entry = true;
+ state->success = false;
+ return 1;
+ }
+
+ DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
+ DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
+ return 0;
+}
+
+static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ if (dbuf.dsize != 4) {
+ DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
+ keystr, (unsigned int)dbuf.dsize ));
+ state->bad_entry = true;
+ state->success = false;
+ return 1;
+ }
+ DEBUG(10,("validate_offline: %s ok\n", keystr));
+ return 0;
+}
+
+static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
+ struct tdb_validation_status *state)
+{
+ if (dbuf.dsize != 4) {
+ DEBUG(0, ("validate_cache_version: Corrupt cache for "
+ "key %s (len %u != 4) ?\n",
+ keystr, (unsigned int)dbuf.dsize));
+ state->bad_entry = true;
+ state->success = false;
+ return 1;
+ }
+
+ DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
+ return 0;
+}
+
+/***********************************************************************
+ A list of all possible cache tdb keys with associated validation
+ functions.
+***********************************************************************/
+
+struct key_val_struct {
+ const char *keyname;
+ int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
+} key_val[] = {
+ {"SEQNUM/", validate_seqnum},
+ {"NS/", validate_ns},
+ {"SN/", validate_sn},
+ {"U/", validate_u},
+ {"LOC_POL/", validate_loc_pol},
+ {"PWD_POL/", validate_pwd_pol},
+ {"CRED/", validate_cred},
+ {"UL/", validate_ul},
+ {"GL/", validate_gl},
+ {"UG/", validate_ug},
+ {"UA", validate_ua},
+ {"GM/", validate_gm},
+ {"DR/", validate_dr},
+ {"DE/", validate_de},
+ {"NSS/PWINFO/", validate_pwinfo},
+ {"TRUSTDOMS/", validate_trustdoms},
+ {"TRUSTDOMCACHE/", validate_trustdomcache},
+ {"WINBINDD_OFFLINE", validate_offline},
+ {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
+ {NULL, NULL}
+};
+
+/***********************************************************************
+ Function to look at every entry in the tdb and validate it as far as
+ possible.
+***********************************************************************/
+
+static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ int i;
+ unsigned int max_key_len = 1024;
+ struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
+
+ /* Paranoia check. */
+ if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
+ max_key_len = 1024 * 1024;
+ }
+ if (kbuf.dsize > max_key_len) {
+ DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
+ "(%u) > (%u)\n\n",
+ (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
+ return 1;
+ }
+
+ for (i = 0; key_val[i].keyname; i++) {
+ size_t namelen = strlen(key_val[i].keyname);
+ if (kbuf.dsize >= namelen && (
+ strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
+ TALLOC_CTX *mem_ctx;
+ char *keystr;
+ int ret;
+
+ keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
+ if (!keystr) {
+ return 1;
+ }
+ memcpy(keystr, kbuf.dptr, kbuf.dsize);
+ keystr[kbuf.dsize] = '\0';
+
+ mem_ctx = talloc_init("validate_ctx");
+ if (!mem_ctx) {
+ SAFE_FREE(keystr);
+ return 1;
+ }
+
+ ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
+ v_state);
+
+ SAFE_FREE(keystr);
+ talloc_destroy(mem_ctx);
+ return ret;
+ }
+ }
+
+ DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
+ dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
+ DEBUG(0,("data :\n"));
+ dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
+ v_state->unknown_key = true;
+ v_state->success = false;
+ return 1; /* terminate. */
+}
+
+static void validate_panic(const char *const why)
+{
+ DEBUG(0,("validating cache: would panic %s\n", why ));
+ DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
+ exit(47);
+}
+
+/***********************************************************************
+ Try and validate every entry in the winbindd cache. If we fail here,
+ delete the cache tdb and return non-zero.
+***********************************************************************/
+
+int winbindd_validate_cache(void)
+{
+ int ret = -1;
+ const char *tdb_path = lock_path("winbindd_cache.tdb");
+ TDB_CONTEXT *tdb = NULL;
+
+ DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
+ smb_panic_fn = validate_panic;
+
+
+ tdb = tdb_open_log(tdb_path,
+ WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
+ ( lp_winbind_offline_logon()
+ ? TDB_DEFAULT
+ : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
+ O_RDWR|O_CREAT,
+ 0600);
+ if (!tdb) {
+ DEBUG(0, ("winbindd_validate_cache: "
+ "error opening/initializing tdb\n"));
+ goto done;
+ }
+ tdb_close(tdb);
+
+ ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
+
+ if (ret != 0) {
+ DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
+ DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
+ unlink(tdb_path);
+ }
+
+done:
+ DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
+ smb_panic_fn = smb_panic;
+ return ret;
+}
+
+/***********************************************************************
+ Try and validate every entry in the winbindd cache.
+***********************************************************************/
+
+int winbindd_validate_cache_nobackup(void)
+{
+ int ret = -1;
+ const char *tdb_path = lock_path("winbindd_cache.tdb");
+
+ DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
+ smb_panic_fn = validate_panic;
+
+
+ if (wcache == NULL || wcache->tdb == NULL) {
+ ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
+ } else {
+ ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
+ }
+
+ if (ret != 0) {
+ DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
+ "successful.\n"));
+ }
+
+ DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
+ "function\n"));
+ smb_panic_fn = smb_panic;
+ return ret;
+}
+
+bool winbindd_cache_validate_and_initialize(void)
+{
+ close_winbindd_cache();
+
+ if (lp_winbind_offline_logon()) {
+ if (winbindd_validate_cache() < 0) {
+ DEBUG(0, ("winbindd cache tdb corrupt and no backup "
+ "could be restored.\n"));
+ }
+ }
+
+ return initialize_winbindd_cache();
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
+ struct winbindd_tdc_domain **domains,
+ size_t *num_domains )
+{
+ struct winbindd_tdc_domain *list = NULL;
+ size_t idx;
+ int i;
+ bool set_only = false;
+
+ /* don't allow duplicates */
+
+ idx = *num_domains;
+ list = *domains;
+
+ for ( i=0; i< (*num_domains); i++ ) {
+ if ( strequal( new_dom->name, list[i].domain_name ) ) {
+ DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
+ new_dom->name));
+ idx = i;
+ set_only = true;
+
+ break;
+ }
+ }
+
+ if ( !set_only ) {
+ if ( !*domains ) {
+ list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
+ idx = 0;
+ } else {
+ list = TALLOC_REALLOC_ARRAY( *domains, *domains,
+ struct winbindd_tdc_domain,
+ (*num_domains)+1);
+ idx = *num_domains;
+ }
+
+ ZERO_STRUCT( list[idx] );
+ }
+
+ if ( !list )
+ return false;
+
+ list[idx].domain_name = talloc_strdup( list, new_dom->name );
+ list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
+
+ if ( !is_null_sid( &new_dom->sid ) ) {
+ sid_copy( &list[idx].sid, &new_dom->sid );
+ } else {
+ sid_copy(&list[idx].sid, &global_sid_NULL);
+ }
+
+ if ( new_dom->domain_flags != 0x0 )
+ list[idx].trust_flags = new_dom->domain_flags;
+
+ if ( new_dom->domain_type != 0x0 )
+ list[idx].trust_type = new_dom->domain_type;
+
+ if ( new_dom->domain_trust_attribs != 0x0 )
+ list[idx].trust_attribs = new_dom->domain_trust_attribs;
+
+ if ( !set_only ) {
+ *domains = list;
+ *num_domains = idx + 1;
+ }
+
+ return true;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+static TDB_DATA make_tdc_key( const char *domain_name )
+{
+ char *keystr = NULL;
+ TDB_DATA key = { NULL, 0 };
+
+ if ( !domain_name ) {
+ DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
+ return key;
+ }
+
+
+ asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name );
+ key = string_term_tdb_data(keystr);
+
+ return key;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
+ size_t num_domains,
+ unsigned char **buf )
+{
+ unsigned char *buffer = NULL;
+ int len = 0;
+ int buflen = 0;
+ int i = 0;
+
+ DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
+ (int)num_domains));
+
+ buflen = 0;
+
+ again:
+ len = 0;
+
+ /* Store the number of array items first */
+ len += tdb_pack( buffer+len, buflen-len, "d",
+ num_domains );
+
+ /* now pack each domain trust record */
+ for ( i=0; i<num_domains; i++ ) {
+
+ fstring tmp;
+
+ if ( buflen > 0 ) {
+ DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
+ domains[i].domain_name,
+ domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
+ }
+
+ len += tdb_pack( buffer+len, buflen-len, "fffddd",
+ domains[i].domain_name,
+ domains[i].dns_name,
+ sid_to_fstring(tmp, &domains[i].sid),
+ domains[i].trust_flags,
+ domains[i].trust_attribs,
+ domains[i].trust_type );
+ }
+
+ if ( buflen < len ) {
+ SAFE_FREE(buffer);
+ if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
+ DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
+ buflen = -1;
+ goto done;
+ }
+ buflen = len;
+ goto again;
+ }
+
+ *buf = buffer;
+
+ done:
+ return buflen;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
+ struct winbindd_tdc_domain **domains )
+{
+ fstring domain_name, dns_name, sid_string;
+ uint32 type, attribs, flags;
+ int num_domains;
+ int len = 0;
+ int i;
+ struct winbindd_tdc_domain *list = NULL;
+
+ /* get the number of domains */
+ len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
+ if ( len == -1 ) {
+ DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
+ return 0;
+ }
+
+ list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
+ if ( !list ) {
+ DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
+ return 0;
+ }
+
+ for ( i=0; i<num_domains; i++ ) {
+ len += tdb_unpack( buf+len, buflen-len, "fffddd",
+ domain_name,
+ dns_name,
+ sid_string,
+ &flags,
+ &attribs,
+ &type );
+
+ if ( len == -1 ) {
+ DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
+ TALLOC_FREE( list );
+ return 0;
+ }
+
+ DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
+ "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
+ domain_name, dns_name, sid_string,
+ flags, attribs, type));
+
+ list[i].domain_name = talloc_strdup( list, domain_name );
+ list[i].dns_name = talloc_strdup( list, dns_name );
+ if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
+ DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
+ domain_name));
+ }
+ list[i].trust_flags = flags;
+ list[i].trust_attribs = attribs;
+ list[i].trust_type = type;
+ }
+
+ *domains = list;
+
+ return num_domains;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
+{
+ TDB_DATA key = make_tdc_key( lp_workgroup() );
+ TDB_DATA data = { NULL, 0 };
+ int ret;
+
+ if ( !key.dptr )
+ return false;
+
+ /* See if we were asked to delete the cache entry */
+
+ if ( !domains ) {
+ ret = tdb_delete( wcache->tdb, key );
+ goto done;
+ }
+
+ data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
+
+ if ( !data.dptr ) {
+ ret = -1;
+ goto done;
+ }
+
+ ret = tdb_store( wcache->tdb, key, data, 0 );
+
+ done:
+ SAFE_FREE( data.dptr );
+ SAFE_FREE( key.dptr );
+
+ return ( ret != -1 );
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
+{
+ TDB_DATA key = make_tdc_key( lp_workgroup() );
+ TDB_DATA data = { NULL, 0 };
+
+ *domains = NULL;
+ *num_domains = 0;
+
+ if ( !key.dptr )
+ return false;
+
+ data = tdb_fetch( wcache->tdb, key );
+
+ SAFE_FREE( key.dptr );
+
+ if ( !data.dptr )
+ return false;
+
+ *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
+
+ SAFE_FREE( data.dptr );
+
+ if ( !*domains )
+ return false;
+
+ return true;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+bool wcache_tdc_add_domain( struct winbindd_domain *domain )
+{
+ struct winbindd_tdc_domain *dom_list = NULL;
+ size_t num_domains = 0;
+ bool ret = false;
+
+ DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
+ "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
+ domain->name, domain->alt_name,
+ sid_string_dbg(&domain->sid),
+ domain->domain_flags,
+ domain->domain_trust_attribs,
+ domain->domain_type));
+
+ if ( !init_wcache() ) {
+ return false;
+ }
+
+ /* fetch the list */
+
+ wcache_tdc_fetch_list( &dom_list, &num_domains );
+
+ /* add the new domain */
+
+ if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
+ goto done;
+ }
+
+ /* pack the domain */
+
+ if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
+ goto done;
+ }
+
+ /* Success */
+
+ ret = true;
+ done:
+ TALLOC_FREE( dom_list );
+
+ return ret;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
+{
+ struct winbindd_tdc_domain *dom_list = NULL;
+ size_t num_domains = 0;
+ int i;
+ struct winbindd_tdc_domain *d = NULL;
+
+ DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
+
+ if ( !init_wcache() ) {
+ return false;
+ }
+
+ /* fetch the list */
+
+ wcache_tdc_fetch_list( &dom_list, &num_domains );
+
+ for ( i=0; i<num_domains; i++ ) {
+ if ( strequal(name, dom_list[i].domain_name) ||
+ strequal(name, dom_list[i].dns_name) )
+ {
+ DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
+ name));
+
+ d = TALLOC_P( ctx, struct winbindd_tdc_domain );
+ if ( !d )
+ break;
+
+ d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
+ d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
+ sid_copy( &d->sid, &dom_list[i].sid );
+ d->trust_flags = dom_list[i].trust_flags;
+ d->trust_type = dom_list[i].trust_type;
+ d->trust_attribs = dom_list[i].trust_attribs;
+
+ break;
+ }
+ }
+
+ TALLOC_FREE( dom_list );
+
+ return d;
+}
+
+
+/*********************************************************************
+ ********************************************************************/
+
+void wcache_tdc_clear( void )
+{
+ if ( !init_wcache() )
+ return;
+
+ wcache_tdc_store_list( NULL, 0 );
+
+ return;
+}
+
+
+/*********************************************************************
+ ********************************************************************/
+
+static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
+ NTSTATUS status,
+ const DOM_SID *user_sid,
+ const char *homedir,
+ const char *shell,
+ const char *gecos,
+ uint32 gid)
+{
+ struct cache_entry *centry;
+ fstring tmp;
+
+ if ( (centry = centry_start(domain, status)) == NULL )
+ return;
+
+ centry_put_string( centry, homedir );
+ centry_put_string( centry, shell );
+ centry_put_string( centry, gecos );
+ centry_put_uint32( centry, gid );
+
+ centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
+
+ DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
+
+ centry_free(centry);
+}
+
+NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
+ const DOM_SID *user_sid,
+ TALLOC_CTX *ctx,
+ ADS_STRUCT *ads, LDAPMessage *msg,
+ char **homedir, char **shell, char **gecos,
+ gid_t *p_gid)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS nt_status;
+ fstring tmp;
+
+ if (!cache->tdb)
+ goto do_query;
+
+ centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
+ sid_to_fstring(tmp, user_sid));
+
+ if (!centry)
+ goto do_query;
+
+ *homedir = centry_string( centry, ctx );
+ *shell = centry_string( centry, ctx );
+ *gecos = centry_string( centry, ctx );
+ *p_gid = centry_uint32( centry );
+
+ centry_free(centry);
+
+ DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
+ sid_string_dbg(user_sid)));
+
+ return NT_STATUS_OK;
+
+do_query:
+
+ nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
+ homedir, shell, gecos, p_gid );
+
+ if ( NT_STATUS_IS_OK(nt_status) ) {
+ wcache_save_user_pwinfo( domain, nt_status, user_sid,
+ *homedir, *shell, *gecos, *p_gid );
+ }
+
+ if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
+ DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
+ domain->name ));
+ set_domain_offline( domain );
+ }
+
+ return nt_status;
+}
+
+
+/* the cache backend methods are exposed via this structure */
+struct winbindd_methods cache_methods = {
+ true,
+ query_user_list,
+ enum_dom_groups,
+ enum_local_groups,
+ name_to_sid,
+ sid_to_name,
+ rids_to_names,
+ query_user,
+ lookup_usergroups,
+ lookup_useraliases,
+ lookup_groupmem,
+ sequence_number,
+ lockout_policy,
+ password_policy,
+ trusted_domains
+};
diff --git a/source3/winbindd/winbindd_ccache_access.c b/source3/winbindd/winbindd_ccache_access.c
new file mode 100644
index 0000000000..a696db1031
--- /dev/null
+++ b/source3/winbindd/winbindd_ccache_access.c
@@ -0,0 +1,283 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon - cached credentials funcions
+
+ Copyright (C) Robert O'Callahan 2006
+ Copyright (C) Jeremy Allison 2006 (minor fixes to fit into Samba and
+ protect against integer wrap).
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+static bool client_can_access_ccache_entry(uid_t client_uid,
+ struct WINBINDD_MEMORY_CREDS *entry)
+{
+ if (client_uid == entry->uid || client_uid == 0) {
+ DEBUG(10, ("Access granted to uid %d\n", client_uid));
+ return True;
+ }
+
+ DEBUG(1, ("Access denied to uid %d (expected %d)\n", client_uid, entry->uid));
+ return False;
+}
+
+static NTSTATUS do_ntlm_auth_with_hashes(const char *username,
+ const char *domain,
+ const unsigned char lm_hash[LM_HASH_LEN],
+ const unsigned char nt_hash[NT_HASH_LEN],
+ const DATA_BLOB initial_msg,
+ const DATA_BLOB challenge_msg,
+ DATA_BLOB *auth_msg)
+{
+ NTSTATUS status;
+ NTLMSSP_STATE *ntlmssp_state = NULL;
+ DATA_BLOB dummy_msg, reply;
+
+ status = ntlmssp_client_start(&ntlmssp_state);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Could not start NTLMSSP client: %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ status = ntlmssp_set_username(ntlmssp_state, username);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Could not set username: %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ status = ntlmssp_set_domain(ntlmssp_state, domain);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Could not set domain: %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ status = ntlmssp_set_hashes(ntlmssp_state, lm_hash, nt_hash);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Could not set hashes: %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ /* We need to get our protocol handler into the right state. So first
+ we ask it to generate the initial message. Actually the client has already
+ sent its own initial message, so we're going to drop this one on the floor.
+ The client might have sent a different message, for example with different
+ negotiation options, but as far as I can tell this won't hurt us. (Unless
+ the client sent a different username or domain, in which case that's their
+ problem for telling us the wrong username or domain.)
+ Since we have a copy of the initial message that the client sent, we could
+ resolve any discrepancies if we had to.
+ */
+ dummy_msg = data_blob_null;
+ reply = data_blob_null;
+ status = ntlmssp_update(ntlmssp_state, dummy_msg, &reply);
+ data_blob_free(&dummy_msg);
+ data_blob_free(&reply);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DEBUG(1, ("Failed to create initial message! [%s]\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ /* Now we are ready to handle the server's actual response. */
+ status = ntlmssp_update(ntlmssp_state, challenge_msg, &reply);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ DEBUG(1, ("We didn't get a response to the challenge! [%s]\n",
+ nt_errstr(status)));
+ data_blob_free(&reply);
+ goto done;
+ }
+ *auth_msg = reply;
+ status = NT_STATUS_OK;
+
+done:
+ ntlmssp_end(&ntlmssp_state);
+ return status;
+}
+
+static bool check_client_uid(struct winbindd_cli_state *state, uid_t uid)
+{
+ int ret;
+ uid_t ret_uid;
+
+ ret_uid = (uid_t)-1;
+
+ ret = sys_getpeereid(state->sock, &ret_uid);
+ if (ret != 0) {
+ DEBUG(1, ("check_client_uid: Could not get socket peer uid: %s; "
+ "denying access\n", strerror(errno)));
+ return False;
+ }
+
+ if (uid != ret_uid) {
+ DEBUG(1, ("check_client_uid: Client lied about its uid: said %d, "
+ "actually was %d; denying access\n",
+ uid, ret_uid));
+ return False;
+ }
+
+ return True;
+}
+
+void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+ fstring name_domain, name_user;
+
+ /* Ensure null termination */
+ state->request.data.ccache_ntlm_auth.user[
+ sizeof(state->request.data.ccache_ntlm_auth.user)-1]='\0';
+
+ DEBUG(3, ("[%5lu]: perform NTLM auth on behalf of user %s\n", (unsigned long)state->pid,
+ state->request.data.ccache_ntlm_auth.user));
+
+ /* Parse domain and username */
+
+ if (!canonicalize_username(state->request.data.ccache_ntlm_auth.user,
+ name_domain, name_user)) {
+ DEBUG(5,("winbindd_ccache_ntlm_auth: cannot parse domain and user from name [%s]\n",
+ state->request.data.ccache_ntlm_auth.user));
+ request_error(state);
+ return;
+ }
+
+ domain = find_auth_domain(state, name_domain);
+
+ if (domain == NULL) {
+ DEBUG(5,("winbindd_ccache_ntlm_auth: can't get domain [%s]\n",
+ name_domain));
+ request_error(state);
+ return;
+ }
+
+ if (!check_client_uid(state, state->request.data.ccache_ntlm_auth.uid)) {
+ request_error(state);
+ return;
+ }
+
+ sendto_domain(state, domain);
+}
+
+enum winbindd_result winbindd_dual_ccache_ntlm_auth(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
+ struct WINBINDD_MEMORY_CREDS *entry;
+ DATA_BLOB initial, challenge, auth;
+ fstring name_domain, name_user;
+ uint32 initial_blob_len, challenge_blob_len, extra_len;
+
+ /* Ensure null termination */
+ state->request.data.ccache_ntlm_auth.user[
+ sizeof(state->request.data.ccache_ntlm_auth.user)-1]='\0';
+
+ DEBUG(3, ("winbindd_dual_ccache_ntlm_auth: [%5lu]: perform NTLM auth on "
+ "behalf of user %s (dual)\n", (unsigned long)state->pid,
+ state->request.data.ccache_ntlm_auth.user));
+
+ /* validate blob lengths */
+ initial_blob_len = state->request.data.ccache_ntlm_auth.initial_blob_len;
+ challenge_blob_len = state->request.data.ccache_ntlm_auth.challenge_blob_len;
+ extra_len = state->request.extra_len;
+
+ if (initial_blob_len > extra_len || challenge_blob_len > extra_len ||
+ initial_blob_len + challenge_blob_len > extra_len ||
+ initial_blob_len + challenge_blob_len < initial_blob_len ||
+ initial_blob_len + challenge_blob_len < challenge_blob_len) {
+
+ DEBUG(10,("winbindd_dual_ccache_ntlm_auth: blob lengths overrun "
+ "or wrap. Buffer [%d+%d > %d]\n",
+ initial_blob_len,
+ challenge_blob_len,
+ extra_len));
+ goto process_result;
+ }
+
+ /* Parse domain and username */
+ if (!parse_domain_user(state->request.data.ccache_ntlm_auth.user, name_domain, name_user)) {
+ DEBUG(10,("winbindd_dual_ccache_ntlm_auth: cannot parse "
+ "domain and user from name [%s]\n",
+ state->request.data.ccache_ntlm_auth.user));
+ goto process_result;
+ }
+
+ entry = find_memory_creds_by_name(state->request.data.ccache_ntlm_auth.user);
+ if (entry == NULL || entry->nt_hash == NULL || entry->lm_hash == NULL) {
+ DEBUG(10,("winbindd_dual_ccache_ntlm_auth: could not find "
+ "credentials for user %s\n",
+ state->request.data.ccache_ntlm_auth.user));
+ goto process_result;
+ }
+
+ DEBUG(10,("winbindd_dual_ccache_ntlm_auth: found ccache [%s]\n", entry->username));
+
+ if (!client_can_access_ccache_entry(state->request.data.ccache_ntlm_auth.uid, entry)) {
+ goto process_result;
+ }
+
+ if (initial_blob_len == 0 && challenge_blob_len == 0) {
+ /* this is just a probe to see if credentials are available. */
+ result = NT_STATUS_OK;
+ state->response.data.ccache_ntlm_auth.auth_blob_len = 0;
+ goto process_result;
+ }
+
+ initial = data_blob(state->request.extra_data.data, initial_blob_len);
+ challenge = data_blob(state->request.extra_data.data + initial_blob_len,
+ state->request.data.ccache_ntlm_auth.challenge_blob_len);
+
+ if (!initial.data || !challenge.data) {
+ result = NT_STATUS_NO_MEMORY;
+ } else {
+ result = do_ntlm_auth_with_hashes(name_user, name_domain,
+ entry->lm_hash, entry->nt_hash,
+ initial, challenge, &auth);
+ }
+
+ data_blob_free(&initial);
+ data_blob_free(&challenge);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto process_result;
+ }
+
+ state->response.extra_data.data = smb_xmemdup(auth.data, auth.length);
+ if (!state->response.extra_data.data) {
+ result = NT_STATUS_NO_MEMORY;
+ goto process_result;
+ }
+ state->response.length += auth.length;
+ state->response.data.ccache_ntlm_auth.auth_blob_len = auth.length;
+
+ data_blob_free(&auth);
+
+ process_result:
+ return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
new file mode 100644
index 0000000000..ce851649ba
--- /dev/null
+++ b/source3/winbindd/winbindd_cm.c
@@ -0,0 +1,2399 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon connection manager
+
+ Copyright (C) Tim Potter 2001
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Gerald (Jerry) Carter 2003-2005.
+ Copyright (C) Volker Lendecke 2004-2005
+ Copyright (C) Jeremy Allison 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ We need to manage connections to domain controllers without having to
+ mess up the main winbindd code with other issues. The aim of the
+ connection manager is to:
+
+ - make connections to domain controllers and cache them
+ - re-establish connections when networks or servers go down
+ - centralise the policy on connection timeouts, domain controller
+ selection etc
+ - manage re-entrancy for when winbindd becomes able to handle
+ multiple outstanding rpc requests
+
+ Why not have connection management as part of the rpc layer like tng?
+ Good question. This code may morph into libsmb/rpc_cache.c or something
+ like that but at the moment it's simply staying as part of winbind. I
+ think the TNG architecture of forcing every user of the rpc layer to use
+ the connection caching system is a bad idea. It should be an optional
+ method of using the routines.
+
+ The TNG design is quite good but I disagree with some aspects of the
+ implementation. -tpot
+
+ */
+
+/*
+ TODO:
+
+ - I'm pretty annoyed by all the make_nmb_name() stuff. It should be
+ moved down into another function.
+
+ - Take care when destroying cli_structs as they can be shared between
+ various sam handles.
+
+ */
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+struct dc_name_ip {
+ fstring name;
+ struct sockaddr_storage ss;
+};
+
+extern struct winbindd_methods reconnect_methods;
+extern bool override_logfile;
+
+static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain);
+static void set_dc_type_and_flags( struct winbindd_domain *domain );
+static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
+ struct dc_name_ip **dcs, int *num_dcs);
+
+/****************************************************************
+ Child failed to find DC's. Reschedule check.
+****************************************************************/
+
+static void msg_failed_to_go_online(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct winbindd_domain *domain;
+ const char *domainname = (const char *)data->data;
+
+ if (data->data == NULL || data->length == 0) {
+ return;
+ }
+
+ DEBUG(5,("msg_fail_to_go_online: received for domain %s.\n", domainname));
+
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->internal) {
+ continue;
+ }
+
+ if (strequal(domain->name, domainname)) {
+ if (domain->online) {
+ /* We're already online, ignore. */
+ DEBUG(5,("msg_fail_to_go_online: domain %s "
+ "already online.\n", domainname));
+ continue;
+ }
+
+ /* Reschedule the online check. */
+ set_domain_offline(domain);
+ break;
+ }
+ }
+}
+
+/****************************************************************
+ Actually cause a reconnect from a message.
+****************************************************************/
+
+static void msg_try_to_go_online(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct winbindd_domain *domain;
+ const char *domainname = (const char *)data->data;
+
+ if (data->data == NULL || data->length == 0) {
+ return;
+ }
+
+ DEBUG(5,("msg_try_to_go_online: received for domain %s.\n", domainname));
+
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->internal) {
+ continue;
+ }
+
+ if (strequal(domain->name, domainname)) {
+
+ if (domain->online) {
+ /* We're already online, ignore. */
+ DEBUG(5,("msg_try_to_go_online: domain %s "
+ "already online.\n", domainname));
+ continue;
+ }
+
+ /* This call takes care of setting the online
+ flag to true if we connected, or re-adding
+ the offline handler if false. Bypasses online
+ check so always does network calls. */
+
+ init_dc_connection_network(domain);
+ break;
+ }
+ }
+}
+
+/****************************************************************
+ Fork a child to try and contact a DC. Do this as contacting a
+ DC requires blocking lookups and we don't want to block our
+ parent.
+****************************************************************/
+
+static bool fork_child_dc_connect(struct winbindd_domain *domain)
+{
+ struct dc_name_ip *dcs = NULL;
+ int num_dcs = 0;
+ TALLOC_CTX *mem_ctx = NULL;
+ pid_t parent_pid = sys_getpid();
+
+ /* Stop zombies */
+ CatchChild();
+
+ if (domain->dc_probe_pid != (pid_t)-1) {
+ /*
+ * We might already have a DC probe
+ * child working, check.
+ */
+ if (process_exists_by_pid(domain->dc_probe_pid)) {
+ DEBUG(10,("fork_child_dc_connect: pid %u already "
+ "checking for DC's.\n",
+ (unsigned int)domain->dc_probe_pid));
+ return true;
+ }
+ domain->dc_probe_pid = (pid_t)-1;
+ }
+
+ domain->dc_probe_pid = sys_fork();
+
+ if (domain->dc_probe_pid == (pid_t)-1) {
+ DEBUG(0, ("fork_child_dc_connect: Could not fork: %s\n", strerror(errno)));
+ return False;
+ }
+
+ if (domain->dc_probe_pid != (pid_t)0) {
+ /* Parent */
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_WINBIND_TRY_TO_GO_ONLINE,
+ msg_try_to_go_online);
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_WINBIND_FAILED_TO_GO_ONLINE,
+ msg_failed_to_go_online);
+ return True;
+ }
+
+ /* Child. */
+
+ /* Leave messages blocked - we will never process one. */
+
+ if (!reinit_after_fork(winbind_messaging_context(), true)) {
+ DEBUG(0,("reinit_after_fork() failed\n"));
+ messaging_send_buf(winbind_messaging_context(),
+ pid_to_procid(parent_pid),
+ MSG_WINBIND_FAILED_TO_GO_ONLINE,
+ (uint8 *)domain->name,
+ strlen(domain->name)+1);
+ _exit(0);
+ }
+
+ close_conns_after_fork();
+
+ if (!override_logfile) {
+ char *logfile;
+ if (asprintf(&logfile, "%s/log.winbindd-dc-connect", get_dyn_LOGFILEBASE()) > 0) {
+ lp_set_logfile(logfile);
+ SAFE_FREE(logfile);
+ reopen_logs();
+ }
+ }
+
+ mem_ctx = talloc_init("fork_child_dc_connect");
+ if (!mem_ctx) {
+ DEBUG(0,("talloc_init failed.\n"));
+ messaging_send_buf(winbind_messaging_context(),
+ pid_to_procid(parent_pid),
+ MSG_WINBIND_FAILED_TO_GO_ONLINE,
+ (uint8 *)domain->name,
+ strlen(domain->name)+1);
+ _exit(0);
+ }
+
+ if ((!get_dcs(mem_ctx, domain, &dcs, &num_dcs)) || (num_dcs == 0)) {
+ /* Still offline ? Can't find DC's. */
+ messaging_send_buf(winbind_messaging_context(),
+ pid_to_procid(parent_pid),
+ MSG_WINBIND_FAILED_TO_GO_ONLINE,
+ (uint8 *)domain->name,
+ strlen(domain->name)+1);
+ _exit(0);
+ }
+
+ /* We got a DC. Send a message to our parent to get it to
+ try and do the same. */
+
+ messaging_send_buf(winbind_messaging_context(),
+ pid_to_procid(parent_pid),
+ MSG_WINBIND_TRY_TO_GO_ONLINE,
+ (uint8 *)domain->name,
+ strlen(domain->name)+1);
+ _exit(0);
+}
+
+/****************************************************************
+ Handler triggered if we're offline to try and detect a DC.
+****************************************************************/
+
+static void check_domain_online_handler(struct event_context *ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ struct winbindd_domain *domain =
+ (struct winbindd_domain *)private_data;
+
+ DEBUG(10,("check_domain_online_handler: called for domain "
+ "%s (online = %s)\n", domain->name,
+ domain->online ? "True" : "False" ));
+
+ TALLOC_FREE(domain->check_online_event);
+
+ /* Are we still in "startup" mode ? */
+
+ if (domain->startup && (now->tv_sec > domain->startup_time + 30)) {
+ /* No longer in "startup" mode. */
+ DEBUG(10,("check_domain_online_handler: domain %s no longer in 'startup' mode.\n",
+ domain->name ));
+ domain->startup = False;
+ }
+
+ /* We've been told to stay offline, so stay
+ that way. */
+
+ if (get_global_winbindd_state_offline()) {
+ DEBUG(10,("check_domain_online_handler: domain %s remaining globally offline\n",
+ domain->name ));
+ return;
+ }
+
+ /* Fork a child to test if it can contact a DC.
+ If it can then send ourselves a message to
+ cause a reconnect. */
+
+ fork_child_dc_connect(domain);
+}
+
+/****************************************************************
+ If we're still offline setup the timeout check.
+****************************************************************/
+
+static void calc_new_online_timeout_check(struct winbindd_domain *domain)
+{
+ int wbr = lp_winbind_reconnect_delay();
+
+ if (domain->startup) {
+ domain->check_online_timeout = 10;
+ } else if (domain->check_online_timeout < wbr) {
+ domain->check_online_timeout = wbr;
+ }
+}
+
+/****************************************************************
+ Set domain offline and also add handler to put us back online
+ if we detect a DC.
+****************************************************************/
+
+void set_domain_offline(struct winbindd_domain *domain)
+{
+ DEBUG(10,("set_domain_offline: called for domain %s\n",
+ domain->name ));
+
+ TALLOC_FREE(domain->check_online_event);
+
+ if (domain->internal) {
+ DEBUG(3,("set_domain_offline: domain %s is internal - logic error.\n",
+ domain->name ));
+ return;
+ }
+
+ domain->online = False;
+
+ /* Offline domains are always initialized. They're
+ re-initialized when they go back online. */
+
+ domain->initialized = True;
+
+ /* We only add the timeout handler that checks and
+ allows us to go back online when we've not
+ been told to remain offline. */
+
+ if (get_global_winbindd_state_offline()) {
+ DEBUG(10,("set_domain_offline: domain %s remaining globally offline\n",
+ domain->name ));
+ return;
+ }
+
+ /* If we're in statup mode, check again in 10 seconds, not in
+ lp_winbind_reconnect_delay() seconds (which is 30 seconds by default). */
+
+ calc_new_online_timeout_check(domain);
+
+ domain->check_online_event = event_add_timed(winbind_event_context(),
+ NULL,
+ timeval_current_ofs(domain->check_online_timeout,0),
+ "check_domain_online_handler",
+ check_domain_online_handler,
+ domain);
+
+ /* The above *has* to succeed for winbindd to work. */
+ if (!domain->check_online_event) {
+ smb_panic("set_domain_offline: failed to add online handler");
+ }
+
+ DEBUG(10,("set_domain_offline: added event handler for domain %s\n",
+ domain->name ));
+
+ /* Send an offline message to the idmap child when our
+ primary domain goes offline */
+
+ if ( domain->primary ) {
+ struct winbindd_child *idmap = idmap_child();
+
+ if ( idmap->pid != 0 ) {
+ messaging_send_buf(winbind_messaging_context(),
+ pid_to_procid(idmap->pid),
+ MSG_WINBIND_OFFLINE,
+ (uint8 *)domain->name,
+ strlen(domain->name)+1);
+ }
+ }
+
+ return;
+}
+
+/****************************************************************
+ Set domain online - if allowed.
+****************************************************************/
+
+static void set_domain_online(struct winbindd_domain *domain)
+{
+ struct timeval now;
+
+ DEBUG(10,("set_domain_online: called for domain %s\n",
+ domain->name ));
+
+ if (domain->internal) {
+ DEBUG(3,("set_domain_online: domain %s is internal - logic error.\n",
+ domain->name ));
+ return;
+ }
+
+ if (get_global_winbindd_state_offline()) {
+ DEBUG(10,("set_domain_online: domain %s remaining globally offline\n",
+ domain->name ));
+ return;
+ }
+
+ winbindd_set_locator_kdc_envs(domain);
+
+ /* If we are waiting to get a krb5 ticket, trigger immediately. */
+ GetTimeOfDay(&now);
+ set_event_dispatch_time(winbind_event_context(),
+ "krb5_ticket_gain_handler", now);
+
+ /* Ok, we're out of any startup mode now... */
+ domain->startup = False;
+
+ if (domain->online == False) {
+ /* We were offline - now we're online. We default to
+ using the MS-RPC backend if we started offline,
+ and if we're going online for the first time we
+ should really re-initialize the backends and the
+ checks to see if we're talking to an AD or NT domain.
+ */
+
+ domain->initialized = False;
+
+ /* 'reconnect_methods' is the MS-RPC backend. */
+ if (domain->backend == &reconnect_methods) {
+ domain->backend = NULL;
+ }
+ }
+
+ /* Ensure we have no online timeout checks. */
+ domain->check_online_timeout = 0;
+ TALLOC_FREE(domain->check_online_event);
+
+ /* Ensure we ignore any pending child messages. */
+ messaging_deregister(winbind_messaging_context(),
+ MSG_WINBIND_TRY_TO_GO_ONLINE, NULL);
+ messaging_deregister(winbind_messaging_context(),
+ MSG_WINBIND_FAILED_TO_GO_ONLINE, NULL);
+
+ domain->online = True;
+
+ /* Send an online message to the idmap child when our
+ primary domain comes online */
+
+ if ( domain->primary ) {
+ struct winbindd_child *idmap = idmap_child();
+
+ if ( idmap->pid != 0 ) {
+ messaging_send_buf(winbind_messaging_context(),
+ pid_to_procid(idmap->pid),
+ MSG_WINBIND_ONLINE,
+ (uint8 *)domain->name,
+ strlen(domain->name)+1);
+ }
+ }
+
+ return;
+}
+
+/****************************************************************
+ Requested to set a domain online.
+****************************************************************/
+
+void set_domain_online_request(struct winbindd_domain *domain)
+{
+ struct timeval tev;
+
+ DEBUG(10,("set_domain_online_request: called for domain %s\n",
+ domain->name ));
+
+ if (get_global_winbindd_state_offline()) {
+ DEBUG(10,("set_domain_online_request: domain %s remaining globally offline\n",
+ domain->name ));
+ return;
+ }
+
+ /* We've been told it's safe to go online and
+ try and connect to a DC. But I don't believe it
+ because network manager seems to lie.
+ Wait at least 5 seconds. Heuristics suck... */
+
+ if (!domain->check_online_event) {
+ /* If we've come from being globally offline we
+ don't have a check online event handler set.
+ We need to add one now we're trying to go
+ back online. */
+
+ DEBUG(10,("set_domain_online_request: domain %s was globally offline.\n",
+ domain->name ));
+
+ domain->check_online_event = event_add_timed(winbind_event_context(),
+ NULL,
+ timeval_current_ofs(5, 0),
+ "check_domain_online_handler",
+ check_domain_online_handler,
+ domain);
+
+ /* The above *has* to succeed for winbindd to work. */
+ if (!domain->check_online_event) {
+ smb_panic("set_domain_online_request: failed to add online handler");
+ }
+ }
+
+ GetTimeOfDay(&tev);
+
+ /* Go into "startup" mode again. */
+ domain->startup_time = tev.tv_sec;
+ domain->startup = True;
+
+ tev.tv_sec += 5;
+
+ set_event_dispatch_time(winbind_event_context(), "check_domain_online_handler", tev);
+}
+
+/****************************************************************
+ Add -ve connection cache entries for domain and realm.
+****************************************************************/
+
+void winbind_add_failed_connection_entry(const struct winbindd_domain *domain,
+ const char *server,
+ NTSTATUS result)
+{
+ add_failed_connection_entry(domain->name, server, result);
+ /* If this was the saf name for the last thing we talked to,
+ remove it. */
+ saf_delete(domain->name);
+ if (*domain->alt_name) {
+ add_failed_connection_entry(domain->alt_name, server, result);
+ saf_delete(domain->alt_name);
+ }
+ winbindd_unset_locator_kdc_env(domain);
+}
+
+/* Choose between anonymous or authenticated connections. We need to use
+ an authenticated connection if DCs have the RestrictAnonymous registry
+ entry set > 0, or the "Additional restrictions for anonymous
+ connections" set in the win2k Local Security Policy.
+
+ Caller to free() result in domain, username, password
+*/
+
+static void cm_get_ipc_userpass(char **username, char **domain, char **password)
+{
+ *username = (char *)secrets_fetch(SECRETS_AUTH_USER, NULL);
+ *domain = (char *)secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
+ *password = (char *)secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
+
+ if (*username && **username) {
+
+ if (!*domain || !**domain)
+ *domain = smb_xstrdup(lp_workgroup());
+
+ if (!*password || !**password)
+ *password = smb_xstrdup("");
+
+ DEBUG(3, ("cm_get_ipc_userpass: Retrieved auth-user from secrets.tdb [%s\\%s]\n",
+ *domain, *username));
+
+ } else {
+ DEBUG(3, ("cm_get_ipc_userpass: No auth-user defined\n"));
+ *username = smb_xstrdup("");
+ *domain = smb_xstrdup("");
+ *password = smb_xstrdup("");
+ }
+}
+
+static bool get_dc_name_via_netlogon(struct winbindd_domain *domain,
+ fstring dcname,
+ struct sockaddr_storage *dc_ss)
+{
+ struct winbindd_domain *our_domain = NULL;
+ struct rpc_pipe_client *netlogon_pipe = NULL;
+ NTSTATUS result;
+ WERROR werr;
+ TALLOC_CTX *mem_ctx;
+ unsigned int orig_timeout;
+ const char *tmp = NULL;
+ const char *p;
+
+ /* Hmmmm. We can only open one connection to the NETLOGON pipe at the
+ * moment.... */
+
+ if (IS_DC) {
+ return False;
+ }
+
+ if (domain->primary) {
+ return False;
+ }
+
+ our_domain = find_our_domain();
+
+ if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL) {
+ return False;
+ }
+
+ result = cm_connect_netlogon(our_domain, &netlogon_pipe);
+ if (!NT_STATUS_IS_OK(result)) {
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ /* This call can take a long time - allow the server to time out.
+ 35 seconds should do it. */
+
+ orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
+
+ if (our_domain->active_directory) {
+ struct netr_DsRGetDCNameInfo *domain_info = NULL;
+
+ result = rpccli_netr_DsRGetDCName(netlogon_pipe,
+ mem_ctx,
+ our_domain->dcname,
+ domain->name,
+ NULL,
+ NULL,
+ DS_RETURN_DNS_NAME,
+ &domain_info,
+ &werr);
+ if (W_ERROR_IS_OK(werr)) {
+ tmp = talloc_strdup(
+ mem_ctx, domain_info->dc_unc);
+ if (tmp == NULL) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ talloc_destroy(mem_ctx);
+ return false;
+ }
+ if (strlen(domain->alt_name) == 0) {
+ fstrcpy(domain->alt_name,
+ domain_info->domain_name);
+ }
+ if (strlen(domain->forest_name) == 0) {
+ fstrcpy(domain->forest_name,
+ domain_info->forest_name);
+ }
+ }
+ } else {
+ result = rpccli_netr_GetAnyDCName(netlogon_pipe, mem_ctx,
+ our_domain->dcname,
+ domain->name,
+ &tmp,
+ &werr);
+ }
+
+ /* And restore our original timeout. */
+ rpccli_set_timeout(netlogon_pipe, orig_timeout);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("rpccli_netr_GetAnyDCName failed: %s\n",
+ nt_errstr(result)));
+ talloc_destroy(mem_ctx);
+ return false;
+ }
+
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(10,("rpccli_netr_GetAnyDCName failed: %s\n",
+ dos_errstr(werr)));
+ talloc_destroy(mem_ctx);
+ return false;
+ }
+
+ /* rpccli_netr_GetAnyDCName gives us a name with \\ */
+ p = strip_hostname(tmp);
+
+ fstrcpy(dcname, p);
+
+ talloc_destroy(mem_ctx);
+
+ DEBUG(10,("rpccli_netr_GetAnyDCName returned %s\n", dcname));
+
+ if (!resolve_name(dcname, dc_ss, 0x20)) {
+ return False;
+ }
+
+ return True;
+}
+
+/**
+ * Helper function to assemble trust password and account name
+ */
+static NTSTATUS get_trust_creds(const struct winbindd_domain *domain,
+ char **machine_password,
+ char **machine_account,
+ char **machine_krb5_principal)
+{
+ const char *account_name;
+ const char *name = NULL;
+
+ /* If we are a DC and this is not our own domain */
+
+ if (IS_DC) {
+ name = domain->name;
+ } else {
+ struct winbindd_domain *our_domain = find_our_domain();
+
+ if (!our_domain)
+ return NT_STATUS_INVALID_SERVER_STATE;
+
+ name = our_domain->name;
+ }
+
+ if (!get_trust_pw_clear(name, machine_password,
+ &account_name, NULL))
+ {
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ if ((machine_account != NULL) &&
+ (asprintf(machine_account, "%s$", account_name) == -1))
+ {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* For now assume our machine account only exists in our domain */
+
+ if (machine_krb5_principal != NULL)
+ {
+ struct winbindd_domain *our_domain = find_our_domain();
+
+ if (!our_domain) {
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ if (asprintf(machine_krb5_principal, "%s$@%s",
+ account_name, our_domain->alt_name) == -1)
+ {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ strupper_m(*machine_krb5_principal);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/************************************************************************
+ Given a fd with a just-connected TCP connection to a DC, open a connection
+ to the pipe.
+************************************************************************/
+
+static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
+ const int sockfd,
+ const char *controller,
+ struct cli_state **cli,
+ bool *retry)
+{
+ char *machine_password = NULL;
+ char *machine_krb5_principal = NULL;
+ char *machine_account = NULL;
+ char *ipc_username = NULL;
+ char *ipc_domain = NULL;
+ char *ipc_password = NULL;
+
+ struct named_mutex *mutex;
+
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ struct sockaddr peeraddr;
+ socklen_t peeraddr_len;
+
+ struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr;
+
+ DEBUG(10,("cm_prepare_connection: connecting to DC %s for domain %s\n",
+ controller, domain->name ));
+
+ *retry = True;
+
+ mutex = grab_named_mutex(talloc_tos(), controller,
+ WINBIND_SERVER_MUTEX_WAIT_TIME);
+ if (mutex == NULL) {
+ DEBUG(0,("cm_prepare_connection: mutex grab failed for %s\n",
+ controller));
+ result = NT_STATUS_POSSIBLE_DEADLOCK;
+ goto done;
+ }
+
+ if ((*cli = cli_initialise()) == NULL) {
+ DEBUG(1, ("Could not cli_initialize\n"));
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ (*cli)->timeout = 10000; /* 10 seconds */
+ (*cli)->fd = sockfd;
+ fstrcpy((*cli)->desthost, controller);
+ (*cli)->use_kerberos = True;
+
+ peeraddr_len = sizeof(peeraddr);
+
+ if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) ||
+ (peeraddr_len != sizeof(struct sockaddr_in)) ||
+ (peeraddr_in->sin_family != PF_INET))
+ {
+ DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno)));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (ntohs(peeraddr_in->sin_port) == 139) {
+ struct nmb_name calling;
+ struct nmb_name called;
+
+ make_nmb_name(&calling, global_myname(), 0x0);
+ make_nmb_name(&called, "*SMBSERVER", 0x20);
+
+ if (!cli_session_request(*cli, &calling, &called)) {
+ DEBUG(8, ("cli_session_request failed for %s\n",
+ controller));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ }
+
+ cli_setup_signing_state(*cli, Undefined);
+
+ if (!cli_negprot(*cli)) {
+ DEBUG(1, ("cli_negprot failed\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!is_dc_trusted_domain_situation(domain->name) &&
+ (*cli)->protocol >= PROTOCOL_NT1 &&
+ (*cli)->capabilities & CAP_EXTENDED_SECURITY)
+ {
+ ADS_STATUS ads_status;
+
+ result = get_trust_creds(domain, &machine_password,
+ &machine_account,
+ &machine_krb5_principal);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto anon_fallback;
+ }
+
+ if (lp_security() == SEC_ADS) {
+
+ /* Try a krb5 session */
+
+ (*cli)->use_kerberos = True;
+ DEBUG(5, ("connecting to %s from %s with kerberos principal "
+ "[%s] and realm [%s]\n", controller, global_myname(),
+ machine_krb5_principal, domain->alt_name));
+
+ winbindd_set_locator_kdc_envs(domain);
+
+ ads_status = cli_session_setup_spnego(*cli,
+ machine_krb5_principal,
+ machine_password,
+ lp_workgroup(),
+ domain->name);
+
+ if (!ADS_ERR_OK(ads_status)) {
+ DEBUG(4,("failed kerberos session setup with %s\n",
+ ads_errstr(ads_status)));
+ }
+
+ result = ads_ntstatus(ads_status);
+ if (NT_STATUS_IS_OK(result)) {
+ /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
+ cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password);
+ goto session_setup_done;
+ }
+ }
+
+ /* Fall back to non-kerberos session setup using NTLMSSP SPNEGO with the machine account. */
+ (*cli)->use_kerberos = False;
+
+ DEBUG(5, ("connecting to %s from %s with username "
+ "[%s]\\[%s]\n", controller, global_myname(),
+ lp_workgroup(), machine_account));
+
+ ads_status = cli_session_setup_spnego(*cli,
+ machine_account,
+ machine_password,
+ lp_workgroup(),
+ NULL);
+ if (!ADS_ERR_OK(ads_status)) {
+ DEBUG(4, ("authenticated session setup failed with %s\n",
+ ads_errstr(ads_status)));
+ }
+
+ result = ads_ntstatus(ads_status);
+ if (NT_STATUS_IS_OK(result)) {
+ /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
+ cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password);
+ goto session_setup_done;
+ }
+ }
+
+ /* Fall back to non-kerberos session setup with auth_user */
+
+ (*cli)->use_kerberos = False;
+
+ cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
+
+ if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
+ (strlen(ipc_username) > 0)) {
+
+ /* Only try authenticated if we have a username */
+
+ DEBUG(5, ("connecting to %s from %s with username "
+ "[%s]\\[%s]\n", controller, global_myname(),
+ ipc_domain, ipc_username));
+
+ if (NT_STATUS_IS_OK(cli_session_setup(
+ *cli, ipc_username,
+ ipc_password, strlen(ipc_password)+1,
+ ipc_password, strlen(ipc_password)+1,
+ ipc_domain))) {
+ /* Successful logon with given username. */
+ cli_init_creds(*cli, ipc_username, ipc_domain, ipc_password);
+ goto session_setup_done;
+ } else {
+ DEBUG(4, ("authenticated session setup with user %s\\%s failed.\n",
+ ipc_domain, ipc_username ));
+ }
+ }
+
+ anon_fallback:
+
+ /* Fall back to anonymous connection, this might fail later */
+ DEBUG(10,("cm_prepare_connection: falling back to anonymous "
+ "connection for DC %s\n",
+ controller ));
+
+ if (NT_STATUS_IS_OK(cli_session_setup(*cli, "", NULL, 0,
+ NULL, 0, ""))) {
+ DEBUG(5, ("Connected anonymously\n"));
+ cli_init_creds(*cli, "", "", "");
+ goto session_setup_done;
+ }
+
+ result = cli_nt_error(*cli);
+
+ if (NT_STATUS_IS_OK(result))
+ result = NT_STATUS_UNSUCCESSFUL;
+
+ /* We can't session setup */
+
+ goto done;
+
+ session_setup_done:
+
+ /* cache the server name for later connections */
+
+ saf_store( domain->name, (*cli)->desthost );
+ if (domain->alt_name && (*cli)->use_kerberos) {
+ saf_store( domain->alt_name, (*cli)->desthost );
+ }
+
+ winbindd_set_locator_kdc_envs(domain);
+
+ if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
+
+ result = cli_nt_error(*cli);
+
+ DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
+
+ if (NT_STATUS_IS_OK(result))
+ result = NT_STATUS_UNSUCCESSFUL;
+
+ goto done;
+ }
+
+ TALLOC_FREE(mutex);
+ *retry = False;
+
+ /* set the domain if empty; needed for schannel connections */
+ if ( !*(*cli)->domain ) {
+ fstrcpy( (*cli)->domain, domain->name );
+ }
+
+ result = NT_STATUS_OK;
+
+ done:
+ TALLOC_FREE(mutex);
+ SAFE_FREE(machine_account);
+ SAFE_FREE(machine_password);
+ SAFE_FREE(machine_krb5_principal);
+ SAFE_FREE(ipc_username);
+ SAFE_FREE(ipc_domain);
+ SAFE_FREE(ipc_password);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ winbind_add_failed_connection_entry(domain, controller, result);
+ if ((*cli) != NULL) {
+ cli_shutdown(*cli);
+ *cli = NULL;
+ }
+ }
+
+ return result;
+}
+
+/*******************************************************************
+ Add a dcname and sockaddr_storage pair to the end of a dc_name_ip
+ array.
+
+ Keeps the list unique by not adding duplicate entries.
+
+ @param[in] mem_ctx talloc memory context to allocate from
+ @param[in] domain_name domain of the DC
+ @param[in] dcname name of the DC to add to the list
+ @param[in] pss Internet address and port pair to add to the list
+ @param[in,out] dcs array of dc_name_ip structures to add to
+ @param[in,out] num_dcs number of dcs returned in the dcs array
+ @return true if the list was added to, false otherwise
+*******************************************************************/
+
+static bool add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
+ const char *dcname, struct sockaddr_storage *pss,
+ struct dc_name_ip **dcs, int *num)
+{
+ int i = 0;
+
+ if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname))) {
+ DEBUG(10, ("DC %s was in the negative conn cache\n", dcname));
+ return False;
+ }
+
+ /* Make sure there's no duplicates in the list */
+ for (i=0; i<*num; i++)
+ if (addr_equal(&(*dcs)[i].ss, pss))
+ return False;
+
+ *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
+
+ if (*dcs == NULL)
+ return False;
+
+ fstrcpy((*dcs)[*num].name, dcname);
+ (*dcs)[*num].ss = *pss;
+ *num += 1;
+ return True;
+}
+
+static bool add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
+ struct sockaddr_storage *pss, uint16 port,
+ struct sockaddr_storage **addrs, int *num)
+{
+ *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_storage, (*num)+1);
+
+ if (*addrs == NULL) {
+ *num = 0;
+ return False;
+ }
+
+ (*addrs)[*num] = *pss;
+ set_sockaddr_port(&(*addrs)[*num], port);
+
+ *num += 1;
+ return True;
+}
+
+/*******************************************************************
+ convert an ip to a name
+*******************************************************************/
+
+static bool dcip_to_name(TALLOC_CTX *mem_ctx,
+ const struct winbindd_domain *domain,
+ struct sockaddr_storage *pss,
+ fstring name )
+{
+ struct ip_service ip_list;
+ uint32_t nt_version = NETLOGON_VERSION_1;
+
+ ip_list.ss = *pss;
+ ip_list.port = 0;
+
+#ifdef WITH_ADS
+ /* For active directory servers, try to get the ldap server name.
+ None of these failures should be considered critical for now */
+
+ if (lp_security() == SEC_ADS) {
+ ADS_STRUCT *ads;
+ ADS_STATUS ads_status;
+ char addr[INET6_ADDRSTRLEN];
+
+ print_sockaddr(addr, sizeof(addr), pss);
+
+ ads = ads_init(domain->alt_name, domain->name, addr);
+ ads->auth.flags |= ADS_AUTH_NO_BIND;
+
+ ads_status = ads_connect(ads);
+ if (ADS_ERR_OK(ads_status)) {
+ /* We got a cldap packet. */
+ fstrcpy(name, ads->config.ldap_server_name);
+ namecache_store(name, 0x20, 1, &ip_list);
+
+ DEBUG(10,("dcip_to_name: flags = 0x%x\n", (unsigned int)ads->config.flags));
+
+ if (domain->primary && (ads->config.flags & NBT_SERVER_KDC)) {
+ if (ads_closest_dc(ads)) {
+ char *sitename = sitename_fetch(ads->config.realm);
+
+ /* We're going to use this KDC for this realm/domain.
+ If we are using sites, then force the krb5 libs
+ to use this KDC. */
+
+ create_local_private_krb5_conf_for_domain(domain->alt_name,
+ domain->name,
+ sitename,
+ pss);
+
+ SAFE_FREE(sitename);
+ } else {
+ /* use an off site KDC */
+ create_local_private_krb5_conf_for_domain(domain->alt_name,
+ domain->name,
+ NULL,
+ pss);
+ }
+ winbindd_set_locator_kdc_envs(domain);
+
+ /* Ensure we contact this DC also. */
+ saf_store( domain->name, name);
+ saf_store( domain->alt_name, name);
+ }
+
+ ads_destroy( &ads );
+ return True;
+ }
+
+ ads_destroy( &ads );
+ }
+#endif
+
+ /* try GETDC requests next */
+
+ if (send_getdc_request(mem_ctx, winbind_messaging_context(),
+ pss, domain->name, &domain->sid,
+ nt_version)) {
+ const char *dc_name = NULL;
+ int i;
+ smb_msleep(100);
+ for (i=0; i<5; i++) {
+ if (receive_getdc_response(mem_ctx, pss, domain->name,
+ &nt_version,
+ &dc_name, NULL)) {
+ fstrcpy(name, dc_name);
+ namecache_store(name, 0x20, 1, &ip_list);
+ return True;
+ }
+ smb_msleep(500);
+ }
+ }
+
+ /* try node status request */
+
+ if ( name_status_find(domain->name, 0x1c, 0x20, pss, name) ) {
+ namecache_store(name, 0x20, 1, &ip_list);
+ return True;
+ }
+ return False;
+}
+
+/*******************************************************************
+ Retrieve a list of IP addresses for domain controllers.
+
+ The array is sorted in the preferred connection order.
+
+ @param[in] mem_ctx talloc memory context to allocate from
+ @param[in] domain domain to retrieve DCs for
+ @param[out] dcs array of dcs that will be returned
+ @param[out] num_dcs number of dcs returned in the dcs array
+ @return always true
+*******************************************************************/
+
+static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
+ struct dc_name_ip **dcs, int *num_dcs)
+{
+ fstring dcname;
+ struct sockaddr_storage ss;
+ struct ip_service *ip_list = NULL;
+ int iplist_size = 0;
+ int i;
+ bool is_our_domain;
+ enum security_types sec = (enum security_types)lp_security();
+
+ is_our_domain = strequal(domain->name, lp_workgroup());
+
+ /* If not our domain, get the preferred DC, by asking our primary DC */
+ if ( !is_our_domain
+ && get_dc_name_via_netlogon(domain, dcname, &ss)
+ && add_one_dc_unique(mem_ctx, domain->name, dcname, &ss, dcs,
+ num_dcs) )
+ {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr), &ss);
+ DEBUG(10, ("Retrieved DC %s at %s via netlogon\n",
+ dcname, addr));
+ return True;
+ }
+
+ if (sec == SEC_ADS) {
+ char *sitename = NULL;
+
+ /* We need to make sure we know the local site before
+ doing any DNS queries, as this will restrict the
+ get_sorted_dc_list() call below to only fetching
+ DNS records for the correct site. */
+
+ /* Find any DC to get the site record.
+ We deliberately don't care about the
+ return here. */
+
+ get_dc_name(domain->name, domain->alt_name, dcname, &ss);
+
+ sitename = sitename_fetch(domain->alt_name);
+ if (sitename) {
+
+ /* Do the site-specific AD dns lookup first. */
+ get_sorted_dc_list(domain->alt_name, sitename, &ip_list,
+ &iplist_size, True);
+
+ /* Add ips to the DC array. We don't look up the name
+ of the DC in this function, but we fill in the char*
+ of the ip now to make the failed connection cache
+ work */
+ for ( i=0; i<iplist_size; i++ ) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr),
+ &ip_list[i].ss);
+ add_one_dc_unique(mem_ctx,
+ domain->name,
+ addr,
+ &ip_list[i].ss,
+ dcs,
+ num_dcs);
+ }
+
+ SAFE_FREE(ip_list);
+ SAFE_FREE(sitename);
+ iplist_size = 0;
+ }
+
+ /* Now we add DCs from the main AD DNS lookup. */
+ get_sorted_dc_list(domain->alt_name, NULL, &ip_list,
+ &iplist_size, True);
+
+ for ( i=0; i<iplist_size; i++ ) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr),
+ &ip_list[i].ss);
+ add_one_dc_unique(mem_ctx,
+ domain->name,
+ addr,
+ &ip_list[i].ss,
+ dcs,
+ num_dcs);
+ }
+
+ SAFE_FREE(ip_list);
+ iplist_size = 0;
+ }
+
+ /* Try standard netbios queries if no ADS */
+ if (*num_dcs == 0) {
+ get_sorted_dc_list(domain->name, NULL, &ip_list, &iplist_size,
+ False);
+
+ for ( i=0; i<iplist_size; i++ ) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr),
+ &ip_list[i].ss);
+ add_one_dc_unique(mem_ctx,
+ domain->name,
+ addr,
+ &ip_list[i].ss,
+ dcs,
+ num_dcs);
+ }
+
+ SAFE_FREE(ip_list);
+ iplist_size = 0;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Find and make a connection to a DC in the given domain.
+
+ @param[in] mem_ctx talloc memory context to allocate from
+ @param[in] domain domain to find a dc in
+ @param[out] dcname NetBIOS or FQDN of DC that's connected to
+ @param[out] pss DC Internet address and port
+ @param[out] fd fd of the open socket connected to the newly found dc
+ @return true when a DC connection is made, false otherwise
+*******************************************************************/
+
+static bool find_new_dc(TALLOC_CTX *mem_ctx,
+ struct winbindd_domain *domain,
+ fstring dcname, struct sockaddr_storage *pss, int *fd)
+{
+ struct dc_name_ip *dcs = NULL;
+ int num_dcs = 0;
+
+ const char **dcnames = NULL;
+ int num_dcnames = 0;
+
+ struct sockaddr_storage *addrs = NULL;
+ int num_addrs = 0;
+
+ int i, fd_index;
+
+ *fd = -1;
+
+ again:
+ if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
+ return False;
+
+ for (i=0; i<num_dcs; i++) {
+
+ if (!add_string_to_array(mem_ctx, dcs[i].name,
+ &dcnames, &num_dcnames)) {
+ return False;
+ }
+ if (!add_sockaddr_to_array(mem_ctx, &dcs[i].ss, 445,
+ &addrs, &num_addrs)) {
+ return False;
+ }
+
+ if (!add_string_to_array(mem_ctx, dcs[i].name,
+ &dcnames, &num_dcnames)) {
+ return False;
+ }
+ if (!add_sockaddr_to_array(mem_ctx, &dcs[i].ss, 139,
+ &addrs, &num_addrs)) {
+ return False;
+ }
+ }
+
+ if ((num_dcnames == 0) || (num_dcnames != num_addrs))
+ return False;
+
+ if ((addrs == NULL) || (dcnames == NULL))
+ return False;
+
+ /* 5 second timeout. */
+ if (!open_any_socket_out(addrs, num_addrs, 5000, &fd_index, fd) ) {
+ for (i=0; i<num_dcs; i++) {
+ char ab[INET6_ADDRSTRLEN];
+ print_sockaddr(ab, sizeof(ab), &dcs[i].ss);
+ DEBUG(10, ("find_new_dc: open_any_socket_out failed for "
+ "domain %s address %s. Error was %s\n",
+ domain->name, ab, strerror(errno) ));
+ winbind_add_failed_connection_entry(domain,
+ dcs[i].name, NT_STATUS_UNSUCCESSFUL);
+ }
+ return False;
+ }
+
+ *pss = addrs[fd_index];
+
+ if (*dcnames[fd_index] != '\0' && !is_ipaddress(dcnames[fd_index])) {
+ /* Ok, we've got a name for the DC */
+ fstrcpy(dcname, dcnames[fd_index]);
+ return True;
+ }
+
+ /* Try to figure out the name */
+ if (dcip_to_name(mem_ctx, domain, pss, dcname)) {
+ return True;
+ }
+
+ /* We can not continue without the DC's name */
+ winbind_add_failed_connection_entry(domain, dcs[fd_index].name,
+ NT_STATUS_UNSUCCESSFUL);
+
+ /* Throw away all arrays as we're doing this again. */
+ TALLOC_FREE(dcs);
+ num_dcs = 0;
+
+ TALLOC_FREE(dcnames);
+ num_dcnames = 0;
+
+ TALLOC_FREE(addrs);
+ num_addrs = 0;
+
+ close(*fd);
+ *fd = -1;
+
+ goto again;
+}
+
+static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
+ struct winbindd_cm_conn *new_conn)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS result;
+ char *saf_servername = saf_fetch( domain->name );
+ int retries;
+
+ if ((mem_ctx = talloc_init("cm_open_connection")) == NULL) {
+ SAFE_FREE(saf_servername);
+ set_domain_offline(domain);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* we have to check the server affinity cache here since
+ later we selecte a DC based on response time and not preference */
+
+ /* Check the negative connection cache
+ before talking to it. It going down may have
+ triggered the reconnection. */
+
+ if ( saf_servername && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, saf_servername))) {
+
+ DEBUG(10,("cm_open_connection: saf_servername is '%s' for domain %s\n",
+ saf_servername, domain->name ));
+
+ /* convert an ip address to a name */
+ if (is_ipaddress( saf_servername ) ) {
+ fstring saf_name;
+ struct sockaddr_storage ss;
+
+ if (!interpret_string_addr(&ss, saf_servername,
+ AI_NUMERICHOST)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ if (dcip_to_name(mem_ctx, domain, &ss, saf_name )) {
+ fstrcpy( domain->dcname, saf_name );
+ } else {
+ winbind_add_failed_connection_entry(
+ domain, saf_servername,
+ NT_STATUS_UNSUCCESSFUL);
+ }
+ } else {
+ fstrcpy( domain->dcname, saf_servername );
+ }
+
+ SAFE_FREE( saf_servername );
+ }
+
+ for (retries = 0; retries < 3; retries++) {
+ int fd = -1;
+ bool retry = False;
+
+ result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+
+ DEBUG(10,("cm_open_connection: dcname is '%s' for domain %s\n",
+ domain->dcname, domain->name ));
+
+ if (*domain->dcname
+ && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname))
+ && (resolve_name(domain->dcname, &domain->dcaddr, 0x20)))
+ {
+ struct sockaddr_storage *addrs = NULL;
+ int num_addrs = 0;
+ int dummy = 0;
+
+ if (!add_sockaddr_to_array(mem_ctx, &domain->dcaddr, 445, &addrs, &num_addrs)) {
+ set_domain_offline(domain);
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (!add_sockaddr_to_array(mem_ctx, &domain->dcaddr, 139, &addrs, &num_addrs)) {
+ set_domain_offline(domain);
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* 5 second timeout. */
+ if (!open_any_socket_out(addrs, num_addrs, 5000, &dummy, &fd)) {
+ fd = -1;
+ }
+ }
+
+ if ((fd == -1)
+ && !find_new_dc(mem_ctx, domain, domain->dcname, &domain->dcaddr, &fd))
+ {
+ /* This is the one place where we will
+ set the global winbindd offline state
+ to true, if a "WINBINDD_OFFLINE" entry
+ is found in the winbindd cache. */
+ set_global_winbindd_state_offline();
+ break;
+ }
+
+ new_conn->cli = NULL;
+
+ result = cm_prepare_connection(domain, fd, domain->dcname,
+ &new_conn->cli, &retry);
+
+ if (!retry)
+ break;
+ }
+
+ if (NT_STATUS_IS_OK(result)) {
+
+ winbindd_set_locator_kdc_envs(domain);
+
+ if (domain->online == False) {
+ /* We're changing state from offline to online. */
+ set_global_winbindd_state_online();
+ }
+ set_domain_online(domain);
+ } else {
+ /* Ensure we setup the retry handler. */
+ set_domain_offline(domain);
+ }
+
+ talloc_destroy(mem_ctx);
+ return result;
+}
+
+/* Close down all open pipes on a connection. */
+
+void invalidate_cm_connection(struct winbindd_cm_conn *conn)
+{
+ /* We're closing down a possibly dead
+ connection. Don't have impossibly long (10s) timeouts. */
+
+ if (conn->cli) {
+ cli_set_timeout(conn->cli, 1000); /* 1 second. */
+ }
+
+ if (conn->samr_pipe != NULL) {
+ TALLOC_FREE(conn->samr_pipe);
+ /* Ok, it must be dead. Drop timeout to 0.5 sec. */
+ if (conn->cli) {
+ cli_set_timeout(conn->cli, 500);
+ }
+ }
+
+ if (conn->lsa_pipe != NULL) {
+ TALLOC_FREE(conn->lsa_pipe);
+ /* Ok, it must be dead. Drop timeout to 0.5 sec. */
+ if (conn->cli) {
+ cli_set_timeout(conn->cli, 500);
+ }
+ }
+
+ if (conn->netlogon_pipe != NULL) {
+ TALLOC_FREE(conn->netlogon_pipe);
+ /* Ok, it must be dead. Drop timeout to 0.5 sec. */
+ if (conn->cli) {
+ cli_set_timeout(conn->cli, 500);
+ }
+ }
+
+ if (conn->cli) {
+ cli_shutdown(conn->cli);
+ }
+
+ conn->cli = NULL;
+}
+
+void close_conns_after_fork(void)
+{
+ struct winbindd_domain *domain;
+
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->conn.cli == NULL)
+ continue;
+
+ if (domain->conn.cli->fd == -1)
+ continue;
+
+ close(domain->conn.cli->fd);
+ domain->conn.cli->fd = -1;
+ }
+}
+
+static bool connection_ok(struct winbindd_domain *domain)
+{
+ if (domain->conn.cli == NULL) {
+ DEBUG(8, ("connection_ok: Connection to %s for domain %s has NULL "
+ "cli!\n", domain->dcname, domain->name));
+ return False;
+ }
+
+ if (!domain->conn.cli->initialised) {
+ DEBUG(3, ("connection_ok: Connection to %s for domain %s was never "
+ "initialised!\n", domain->dcname, domain->name));
+ return False;
+ }
+
+ if (domain->conn.cli->fd == -1) {
+ DEBUG(3, ("connection_ok: Connection to %s for domain %s has died or was "
+ "never started (fd == -1)\n",
+ domain->dcname, domain->name));
+ return False;
+ }
+
+ if (domain->online == False) {
+ DEBUG(3, ("connection_ok: Domain %s is offline\n", domain->name));
+ return False;
+ }
+
+ return True;
+}
+
+/* Initialize a new connection up to the RPC BIND.
+ Bypass online status check so always does network calls. */
+
+static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain)
+{
+ NTSTATUS result;
+
+ /* Internal connections never use the network. */
+ if (domain->internal) {
+ domain->initialized = True;
+ return NT_STATUS_OK;
+ }
+
+ if (connection_ok(domain)) {
+ if (!domain->initialized) {
+ set_dc_type_and_flags(domain);
+ }
+ return NT_STATUS_OK;
+ }
+
+ invalidate_cm_connection(&domain->conn);
+
+ result = cm_open_connection(domain, &domain->conn);
+
+ if (NT_STATUS_IS_OK(result) && !domain->initialized) {
+ set_dc_type_and_flags(domain);
+ }
+
+ return result;
+}
+
+NTSTATUS init_dc_connection(struct winbindd_domain *domain)
+{
+ if (domain->initialized && !domain->online) {
+ /* We check for online status elsewhere. */
+ return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+ }
+
+ return init_dc_connection_network(domain);
+}
+
+/******************************************************************************
+ Set the trust flags (direction and forest location) for a domain
+******************************************************************************/
+
+static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain )
+{
+ struct winbindd_domain *our_domain;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct netr_DomainTrustList trusts;
+ int i;
+ uint32 flags = (NETR_TRUST_FLAG_IN_FOREST |
+ NETR_TRUST_FLAG_OUTBOUND |
+ NETR_TRUST_FLAG_INBOUND);
+ struct rpc_pipe_client *cli;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ DEBUG(5, ("set_dc_type_and_flags_trustinfo: domain %s\n", domain->name ));
+
+ /* Our primary domain doesn't need to worry about trust flags.
+ Force it to go through the network setup */
+ if ( domain->primary ) {
+ return False;
+ }
+
+ our_domain = find_our_domain();
+
+ if ( !connection_ok(our_domain) ) {
+ DEBUG(3,("set_dc_type_and_flags_trustinfo: No connection to our domain!\n"));
+ return False;
+ }
+
+ /* This won't work unless our domain is AD */
+
+ if ( !our_domain->active_directory ) {
+ return False;
+ }
+
+ /* Use DsEnumerateDomainTrusts to get us the trust direction
+ and type */
+
+ result = cm_connect_netlogon(our_domain, &cli);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(5, ("set_dc_type_and_flags_trustinfo: Could not open "
+ "a connection to %s for PIPE_NETLOGON (%s)\n",
+ domain->name, nt_errstr(result)));
+ return False;
+ }
+
+ if ( (mem_ctx = talloc_init("set_dc_type_and_flags_trustinfo")) == NULL ) {
+ DEBUG(0,("set_dc_type_and_flags_trustinfo: talloc_init() failed!\n"));
+ return False;
+ }
+
+ result = rpccli_netr_DsrEnumerateDomainTrusts(cli, mem_ctx,
+ cli->desthost,
+ flags,
+ &trusts,
+ NULL);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("set_dc_type_and_flags_trustinfo: "
+ "failed to query trusted domain list: %s\n",
+ nt_errstr(result)));
+ talloc_destroy(mem_ctx);
+ return false;
+ }
+
+ /* Now find the domain name and get the flags */
+
+ for ( i=0; i<trusts.count; i++ ) {
+ if ( strequal( domain->name, trusts.array[i].netbios_name) ) {
+ domain->domain_flags = trusts.array[i].trust_flags;
+ domain->domain_type = trusts.array[i].trust_type;
+ domain->domain_trust_attribs = trusts.array[i].trust_attributes;
+
+ if ( domain->domain_type == NETR_TRUST_TYPE_UPLEVEL )
+ domain->active_directory = True;
+
+ /* This flag is only set if the domain is *our*
+ primary domain and the primary domain is in
+ native mode */
+
+ domain->native_mode = (domain->domain_flags & NETR_TRUST_FLAG_NATIVE);
+
+ DEBUG(5, ("set_dc_type_and_flags_trustinfo: domain %s is %sin "
+ "native mode.\n", domain->name,
+ domain->native_mode ? "" : "NOT "));
+
+ DEBUG(5,("set_dc_type_and_flags_trustinfo: domain %s is %s"
+ "running active directory.\n", domain->name,
+ domain->active_directory ? "" : "NOT "));
+
+
+ domain->initialized = True;
+
+ if ( !winbindd_can_contact_domain( domain) )
+ domain->internal = True;
+
+ break;
+ }
+ }
+
+ talloc_destroy( mem_ctx );
+
+ return domain->initialized;
+}
+
+/******************************************************************************
+ We can 'sense' certain things about the DC by it's replies to certain
+ questions.
+
+ This tells us if this particular remote server is Active Directory, and if it
+ is native mode.
+******************************************************************************/
+
+static void set_dc_type_and_flags_connect( struct winbindd_domain *domain )
+{
+ NTSTATUS result;
+ WERROR werr;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct rpc_pipe_client *cli;
+ POLICY_HND pol;
+ union dssetup_DsRoleInfo info;
+ union lsa_PolicyInformation *lsa_info = NULL;
+
+ if (!connection_ok(domain)) {
+ return;
+ }
+
+ mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n",
+ domain->name);
+ if (!mem_ctx) {
+ DEBUG(1, ("set_dc_type_and_flags_connect: talloc_init() failed\n"));
+ return;
+ }
+
+ DEBUG(5, ("set_dc_type_and_flags_connect: domain %s\n", domain->name ));
+
+ result = cli_rpc_pipe_open_noauth(domain->conn.cli,
+ &ndr_table_dssetup.syntax_id,
+ &cli);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
+ "PI_DSSETUP on domain %s: (%s)\n",
+ domain->name, nt_errstr(result)));
+
+ /* if this is just a non-AD domain we need to continue
+ * identifying so that we can in the end return with
+ * domain->initialized = True - gd */
+
+ goto no_dssetup;
+ }
+
+ result = rpccli_dssetup_DsRoleGetPrimaryDomainInformation(cli, mem_ctx,
+ DS_ROLE_BASIC_INFORMATION,
+ &info,
+ &werr);
+ TALLOC_FREE(cli);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(5, ("set_dc_type_and_flags_connect: rpccli_ds_getprimarydominfo "
+ "on domain %s failed: (%s)\n",
+ domain->name, nt_errstr(result)));
+
+ /* older samba3 DCs will return DCERPC_FAULT_OP_RNG_ERROR for
+ * every opcode on the DSSETUP pipe, continue with
+ * no_dssetup mode here as well to get domain->initialized
+ * set - gd */
+
+ if (NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR) {
+ goto no_dssetup;
+ }
+
+ TALLOC_FREE(mem_ctx);
+ return;
+ }
+
+ if ((info.basic.flags & DS_ROLE_PRIMARY_DS_RUNNING) &&
+ !(info.basic.flags & DS_ROLE_PRIMARY_DS_MIXED_MODE)) {
+ domain->native_mode = True;
+ } else {
+ domain->native_mode = False;
+ }
+
+no_dssetup:
+ result = cli_rpc_pipe_open_noauth(domain->conn.cli,
+ &ndr_table_lsarpc.syntax_id, &cli);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
+ "PI_LSARPC on domain %s: (%s)\n",
+ domain->name, nt_errstr(result)));
+ TALLOC_FREE(cli);
+ TALLOC_FREE(mem_ctx);
+ return;
+ }
+
+ result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, &pol);
+
+ if (NT_STATUS_IS_OK(result)) {
+ /* This particular query is exactly what Win2k clients use
+ to determine that the DC is active directory */
+ result = rpccli_lsa_QueryInfoPolicy2(cli, mem_ctx,
+ &pol,
+ LSA_POLICY_INFO_DNS,
+ &lsa_info);
+ }
+
+ if (NT_STATUS_IS_OK(result)) {
+ domain->active_directory = True;
+
+ if (lsa_info->dns.name.string) {
+ fstrcpy(domain->name, lsa_info->dns.name.string);
+ }
+
+ if (lsa_info->dns.dns_domain.string) {
+ fstrcpy(domain->alt_name,
+ lsa_info->dns.dns_domain.string);
+ }
+
+ /* See if we can set some domain trust flags about
+ ourself */
+
+ if (lsa_info->dns.dns_forest.string) {
+ fstrcpy(domain->forest_name,
+ lsa_info->dns.dns_forest.string);
+
+ if (strequal(domain->forest_name, domain->alt_name)) {
+ domain->domain_flags |= NETR_TRUST_FLAG_TREEROOT;
+ }
+ }
+
+ if (lsa_info->dns.sid) {
+ sid_copy(&domain->sid, lsa_info->dns.sid);
+ }
+ } else {
+ domain->active_directory = False;
+
+ result = rpccli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_lsa_QueryInfoPolicy(cli, mem_ctx,
+ &pol,
+ LSA_POLICY_INFO_ACCOUNT_DOMAIN,
+ &lsa_info);
+
+ if (NT_STATUS_IS_OK(result)) {
+
+ if (lsa_info->account_domain.name.string) {
+ fstrcpy(domain->name,
+ lsa_info->account_domain.name.string);
+ }
+
+ if (lsa_info->account_domain.sid) {
+ sid_copy(&domain->sid, lsa_info->account_domain.sid);
+ }
+ }
+ }
+done:
+
+ DEBUG(5, ("set_dc_type_and_flags_connect: domain %s is %sin native mode.\n",
+ domain->name, domain->native_mode ? "" : "NOT "));
+
+ DEBUG(5,("set_dc_type_and_flags_connect: domain %s is %srunning active directory.\n",
+ domain->name, domain->active_directory ? "" : "NOT "));
+
+ TALLOC_FREE(cli);
+
+ TALLOC_FREE(mem_ctx);
+
+ domain->initialized = True;
+}
+
+/**********************************************************************
+ Set the domain_flags (trust attributes, domain operating modes, etc...
+***********************************************************************/
+
+static void set_dc_type_and_flags( struct winbindd_domain *domain )
+{
+ /* we always have to contact our primary domain */
+
+ if ( domain->primary ) {
+ DEBUG(10,("set_dc_type_and_flags: setting up flags for "
+ "primary domain\n"));
+ set_dc_type_and_flags_connect( domain );
+ return;
+ }
+
+ /* Use our DC to get the information if possible */
+
+ if ( !set_dc_type_and_flags_trustinfo( domain ) ) {
+ /* Otherwise, fallback to contacting the
+ domain directly */
+ set_dc_type_and_flags_connect( domain );
+ }
+
+ return;
+}
+
+
+
+/**********************************************************************
+***********************************************************************/
+
+static bool cm_get_schannel_dcinfo(struct winbindd_domain *domain,
+ struct dcinfo **ppdc)
+{
+ NTSTATUS result;
+ struct rpc_pipe_client *netlogon_pipe;
+
+ if (lp_client_schannel() == False) {
+ return False;
+ }
+
+ result = cm_connect_netlogon(domain, &netlogon_pipe);
+ if (!NT_STATUS_IS_OK(result)) {
+ return False;
+ }
+
+ /* Return a pointer to the struct dcinfo from the
+ netlogon pipe. */
+
+ if (!domain->conn.netlogon_pipe->dc) {
+ return false;
+ }
+
+ *ppdc = domain->conn.netlogon_pipe->dc;
+ return True;
+}
+
+NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client **cli, POLICY_HND *sam_handle)
+{
+ struct winbindd_cm_conn *conn;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ fstring conn_pwd;
+ struct dcinfo *p_dcinfo;
+ char *machine_password = NULL;
+ char *machine_account = NULL;
+ char *domain_name = NULL;
+
+ result = init_dc_connection(domain);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ conn = &domain->conn;
+
+ if (conn->samr_pipe != NULL) {
+ goto done;
+ }
+
+
+ /*
+ * No SAMR pipe yet. Attempt to get an NTLMSSP SPNEGO authenticated
+ * sign and sealed pipe using the machine account password by
+ * preference. If we can't - try schannel, if that fails, try
+ * anonymous.
+ */
+
+ pwd_get_cleartext(&conn->cli->pwd, conn_pwd);
+ if ((conn->cli->user_name[0] == '\0') ||
+ (conn->cli->domain[0] == '\0') ||
+ (conn_pwd[0] == '\0'))
+ {
+ result = get_trust_creds(domain, &machine_password,
+ &machine_account, NULL);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10, ("cm_connect_sam: No no user available for "
+ "domain %s, trying schannel\n", conn->cli->domain));
+ goto schannel;
+ }
+ domain_name = domain->name;
+ } else {
+ machine_password = SMB_STRDUP(conn_pwd);
+ machine_account = SMB_STRDUP(conn->cli->user_name);
+ domain_name = conn->cli->domain;
+ }
+
+ if (!machine_password || !machine_account) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ /* We have an authenticated connection. Use a NTLMSSP SPNEGO
+ authenticated SAMR pipe with sign & seal. */
+ result = cli_rpc_pipe_open_spnego_ntlmssp(conn->cli,
+ &ndr_table_samr.syntax_id,
+ PIPE_AUTH_LEVEL_PRIVACY,
+ domain_name,
+ machine_account,
+ machine_password,
+ &conn->samr_pipe);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("cm_connect_sam: failed to connect to SAMR "
+ "pipe for domain %s using NTLMSSP "
+ "authenticated pipe: user %s\\%s. Error was "
+ "%s\n", domain->name, domain_name,
+ machine_account, nt_errstr(result)));
+ goto schannel;
+ }
+
+ DEBUG(10,("cm_connect_sam: connected to SAMR pipe for "
+ "domain %s using NTLMSSP authenticated "
+ "pipe: user %s\\%s\n", domain->name,
+ domain_name, machine_account));
+
+ result = rpccli_samr_Connect2(conn->samr_pipe, mem_ctx,
+ conn->samr_pipe->desthost,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &conn->sam_connect_handle);
+ if (NT_STATUS_IS_OK(result)) {
+ goto open_domain;
+ }
+ DEBUG(10,("cm_connect_sam: ntlmssp-sealed rpccli_samr_Connect2 "
+ "failed for domain %s, error was %s. Trying schannel\n",
+ domain->name, nt_errstr(result) ));
+ TALLOC_FREE(conn->samr_pipe);
+
+ schannel:
+
+ /* Fall back to schannel if it's a W2K pre-SP1 box. */
+
+ if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
+ /* If this call fails - conn->cli can now be NULL ! */
+ DEBUG(10, ("cm_connect_sam: Could not get schannel auth info "
+ "for domain %s, trying anon\n", domain->name));
+ goto anonymous;
+ }
+ result = cli_rpc_pipe_open_schannel_with_key
+ (conn->cli, &ndr_table_samr.syntax_id, PIPE_AUTH_LEVEL_PRIVACY,
+ domain->name, p_dcinfo, &conn->samr_pipe);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("cm_connect_sam: failed to connect to SAMR pipe for "
+ "domain %s using schannel. Error was %s\n",
+ domain->name, nt_errstr(result) ));
+ goto anonymous;
+ }
+ DEBUG(10,("cm_connect_sam: connected to SAMR pipe for domain %s using "
+ "schannel.\n", domain->name ));
+
+ result = rpccli_samr_Connect2(conn->samr_pipe, mem_ctx,
+ conn->samr_pipe->desthost,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &conn->sam_connect_handle);
+ if (NT_STATUS_IS_OK(result)) {
+ goto open_domain;
+ }
+ DEBUG(10,("cm_connect_sam: schannel-sealed rpccli_samr_Connect2 failed "
+ "for domain %s, error was %s. Trying anonymous\n",
+ domain->name, nt_errstr(result) ));
+ TALLOC_FREE(conn->samr_pipe);
+
+ anonymous:
+
+ /* Finally fall back to anonymous. */
+ result = cli_rpc_pipe_open_noauth(conn->cli, &ndr_table_samr.syntax_id,
+ &conn->samr_pipe);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_samr_Connect2(conn->samr_pipe, mem_ctx,
+ conn->samr_pipe->desthost,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &conn->sam_connect_handle);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("cm_connect_sam: rpccli_samr_Connect2 failed "
+ "for domain %s Error was %s\n",
+ domain->name, nt_errstr(result) ));
+ goto done;
+ }
+
+ open_domain:
+ result = rpccli_samr_OpenDomain(conn->samr_pipe,
+ mem_ctx,
+ &conn->sam_connect_handle,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &domain->sid,
+ &conn->sam_domain_handle);
+
+ done:
+
+ if (!NT_STATUS_IS_OK(result)) {
+ invalidate_cm_connection(conn);
+ return result;
+ }
+
+ *cli = conn->samr_pipe;
+ *sam_handle = conn->sam_domain_handle;
+ SAFE_FREE(machine_password);
+ SAFE_FREE(machine_account);
+ return result;
+}
+
+NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client **cli, POLICY_HND *lsa_policy)
+{
+ struct winbindd_cm_conn *conn;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ fstring conn_pwd;
+ struct dcinfo *p_dcinfo;
+
+ result = init_dc_connection(domain);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ conn = &domain->conn;
+
+ if (conn->lsa_pipe != NULL) {
+ goto done;
+ }
+
+ pwd_get_cleartext(&conn->cli->pwd, conn_pwd);
+ if ((conn->cli->user_name[0] == '\0') ||
+ (conn->cli->domain[0] == '\0') ||
+ (conn_pwd[0] == '\0')) {
+ DEBUG(10, ("cm_connect_lsa: No no user available for "
+ "domain %s, trying schannel\n", conn->cli->domain));
+ goto schannel;
+ }
+
+ /* We have an authenticated connection. Use a NTLMSSP SPNEGO
+ * authenticated LSA pipe with sign & seal. */
+ result = cli_rpc_pipe_open_spnego_ntlmssp
+ (conn->cli, &ndr_table_lsarpc.syntax_id,
+ PIPE_AUTH_LEVEL_PRIVACY,
+ conn->cli->domain, conn->cli->user_name, conn_pwd,
+ &conn->lsa_pipe);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
+ "domain %s using NTLMSSP authenticated pipe: user "
+ "%s\\%s. Error was %s. Trying schannel.\n",
+ domain->name, conn->cli->domain,
+ conn->cli->user_name, nt_errstr(result)));
+ goto schannel;
+ }
+
+ DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
+ "NTLMSSP authenticated pipe: user %s\\%s\n",
+ domain->name, conn->cli->domain, conn->cli->user_name ));
+
+ result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &conn->lsa_policy);
+ if (NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
+ "schannel\n"));
+
+ TALLOC_FREE(conn->lsa_pipe);
+
+ schannel:
+
+ /* Fall back to schannel if it's a W2K pre-SP1 box. */
+
+ if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
+ /* If this call fails - conn->cli can now be NULL ! */
+ DEBUG(10, ("cm_connect_lsa: Could not get schannel auth info "
+ "for domain %s, trying anon\n", domain->name));
+ goto anonymous;
+ }
+ result = cli_rpc_pipe_open_schannel_with_key
+ (conn->cli, &ndr_table_lsarpc.syntax_id,
+ PIPE_AUTH_LEVEL_PRIVACY,
+ domain->name, p_dcinfo, &conn->lsa_pipe);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
+ "domain %s using schannel. Error was %s\n",
+ domain->name, nt_errstr(result) ));
+ goto anonymous;
+ }
+ DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
+ "schannel.\n", domain->name ));
+
+ result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &conn->lsa_policy);
+ if (NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
+ "anonymous\n"));
+
+ TALLOC_FREE(conn->lsa_pipe);
+
+ anonymous:
+
+ result = cli_rpc_pipe_open_noauth(conn->cli,
+ &ndr_table_lsarpc.syntax_id,
+ &conn->lsa_pipe);
+ if (!NT_STATUS_IS_OK(result)) {
+ result = NT_STATUS_PIPE_NOT_AVAILABLE;
+ goto done;
+ }
+
+ result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &conn->lsa_policy);
+ done:
+ if (!NT_STATUS_IS_OK(result)) {
+ invalidate_cm_connection(conn);
+ return result;
+ }
+
+ *cli = conn->lsa_pipe;
+ *lsa_policy = conn->lsa_policy;
+ return result;
+}
+
+/****************************************************************************
+ Open the netlogon pipe to this DC. Use schannel if specified in client conf.
+ session key stored in conn->netlogon_pipe->dc->sess_key.
+****************************************************************************/
+
+NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
+ struct rpc_pipe_client **cli)
+{
+ struct winbindd_cm_conn *conn;
+ NTSTATUS result;
+
+ uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+ uint8 mach_pwd[16];
+ uint32 sec_chan_type;
+ const char *account_name;
+ struct rpc_pipe_client *netlogon_pipe = NULL;
+
+ *cli = NULL;
+
+ result = init_dc_connection(domain);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ conn = &domain->conn;
+
+ if (conn->netlogon_pipe != NULL) {
+ *cli = conn->netlogon_pipe;
+ return NT_STATUS_OK;
+ }
+
+ result = cli_rpc_pipe_open_noauth(conn->cli,
+ &ndr_table_netlogon.syntax_id,
+ &netlogon_pipe);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ if ((!IS_DC) && (!domain->primary)) {
+ /* Clear the schannel request bit and drop down */
+ neg_flags &= ~NETLOGON_NEG_SCHANNEL;
+ goto no_schannel;
+ }
+
+ if (lp_client_schannel() != False) {
+ neg_flags |= NETLOGON_NEG_SCHANNEL;
+ }
+
+ if (!get_trust_pw_hash(domain->name, mach_pwd, &account_name,
+ &sec_chan_type))
+ {
+ TALLOC_FREE(netlogon_pipe);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ result = rpccli_netlogon_setup_creds(
+ netlogon_pipe,
+ domain->dcname, /* server name. */
+ domain->name, /* domain name */
+ global_myname(), /* client name */
+ account_name, /* machine account */
+ mach_pwd, /* machine password */
+ sec_chan_type, /* from get_trust_pw */
+ &neg_flags);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ TALLOC_FREE(netlogon_pipe);
+ return result;
+ }
+
+ if ((lp_client_schannel() == True) &&
+ ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
+ DEBUG(3, ("Server did not offer schannel\n"));
+ TALLOC_FREE(netlogon_pipe);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ no_schannel:
+ if ((lp_client_schannel() == False) ||
+ ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
+ /*
+ * NetSamLogonEx only works for schannel
+ */
+ domain->can_do_samlogon_ex = False;
+
+ /* We're done - just keep the existing connection to NETLOGON
+ * open */
+ conn->netlogon_pipe = netlogon_pipe;
+ *cli = conn->netlogon_pipe;
+ return NT_STATUS_OK;
+ }
+
+ /* Using the credentials from the first pipe, open a signed and sealed
+ second netlogon pipe. The session key is stored in the schannel
+ part of the new pipe auth struct.
+ */
+
+ result = cli_rpc_pipe_open_schannel_with_key(
+ conn->cli, &ndr_table_netlogon.syntax_id,
+ PIPE_AUTH_LEVEL_PRIVACY, domain->name, netlogon_pipe->dc,
+ &conn->netlogon_pipe);
+
+ /* We can now close the initial netlogon pipe. */
+ TALLOC_FREE(netlogon_pipe);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
+ "was %s\n", nt_errstr(result)));
+
+ /* make sure we return something besides OK */
+ return !NT_STATUS_IS_OK(result) ? result : NT_STATUS_PIPE_NOT_AVAILABLE;
+ }
+
+ /*
+ * Try NetSamLogonEx for AD domains
+ */
+ domain->can_do_samlogon_ex = domain->active_directory;
+
+ *cli = conn->netlogon_pipe;
+ return NT_STATUS_OK;
+}
diff --git a/source3/winbindd/winbindd_cred_cache.c b/source3/winbindd/winbindd_cred_cache.c
new file mode 100644
index 0000000000..311b1d1822
--- /dev/null
+++ b/source3/winbindd/winbindd_cred_cache.c
@@ -0,0 +1,802 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon - krb5 credential cache functions
+ and in-memory cache functions.
+
+ Copyright (C) Guenther Deschner 2005-2006
+ Copyright (C) Jeremy Allison 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+/* uncomment this to do fast debugging on the krb5 ticket renewal event */
+#ifdef DEBUG_KRB5_TKT_RENEWAL
+#undef DEBUG_KRB5_TKT_RENEWAL
+#endif
+
+#define MAX_CCACHES 100
+
+static struct WINBINDD_CCACHE_ENTRY *ccache_list;
+
+/* The Krb5 ticket refresh handler should be scheduled
+ at one-half of the period from now till the tkt
+ expiration */
+#define KRB5_EVENT_REFRESH_TIME(x) ((x) - (((x) - time(NULL))/2))
+
+/****************************************************************
+ Find an entry by name.
+****************************************************************/
+
+static struct WINBINDD_CCACHE_ENTRY *get_ccache_by_username(const char *username)
+{
+ struct WINBINDD_CCACHE_ENTRY *entry;
+
+ for (entry = ccache_list; entry; entry = entry->next) {
+ if (strequal(entry->username, username)) {
+ return entry;
+ }
+ }
+ return NULL;
+}
+
+/****************************************************************
+ How many do we have ?
+****************************************************************/
+
+static int ccache_entry_count(void)
+{
+ struct WINBINDD_CCACHE_ENTRY *entry;
+ int i = 0;
+
+ for (entry = ccache_list; entry; entry = entry->next) {
+ i++;
+ }
+ return i;
+}
+
+/****************************************************************
+ Do the work of refreshing the ticket.
+****************************************************************/
+
+static void krb5_ticket_refresh_handler(struct event_context *event_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ struct WINBINDD_CCACHE_ENTRY *entry =
+ talloc_get_type_abort(private_data, struct WINBINDD_CCACHE_ENTRY);
+#ifdef HAVE_KRB5
+ int ret;
+ time_t new_start;
+ struct WINBINDD_MEMORY_CREDS *cred_ptr = entry->cred_ptr;
+#endif
+
+ DEBUG(10,("krb5_ticket_refresh_handler called\n"));
+ DEBUGADD(10,("event called for: %s, %s\n",
+ entry->ccname, entry->username));
+
+ TALLOC_FREE(entry->event);
+
+#ifdef HAVE_KRB5
+
+ /* Kinit again if we have the user password and we can't renew the old
+ * tgt anymore */
+
+ if ((entry->renew_until < time(NULL)) && cred_ptr && cred_ptr->pass) {
+
+ set_effective_uid(entry->uid);
+
+ ret = kerberos_kinit_password_ext(entry->principal_name,
+ cred_ptr->pass,
+ 0, /* hm, can we do time correction here ? */
+ &entry->refresh_time,
+ &entry->renew_until,
+ entry->ccname,
+ False, /* no PAC required anymore */
+ True,
+ WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
+ NULL);
+ gain_root_privilege();
+
+ if (ret) {
+ DEBUG(3,("krb5_ticket_refresh_handler: "
+ "could not re-kinit: %s\n",
+ error_message(ret)));
+ TALLOC_FREE(entry->event);
+ return;
+ }
+
+ DEBUG(10,("krb5_ticket_refresh_handler: successful re-kinit "
+ "for: %s in ccache: %s\n",
+ entry->principal_name, entry->ccname));
+
+#if defined(DEBUG_KRB5_TKT_RENEWAL)
+ new_start = time(NULL) + 30;
+#else
+ /* The tkt should be refreshed at one-half the period
+ from now to the expiration time */
+ new_start = KRB5_EVENT_REFRESH_TIME(entry->refresh_time);
+#endif
+ goto done;
+ }
+
+ set_effective_uid(entry->uid);
+
+ ret = smb_krb5_renew_ticket(entry->ccname,
+ entry->principal_name,
+ entry->service,
+ &new_start);
+#if defined(DEBUG_KRB5_TKT_RENEWAL)
+ new_start = time(NULL) + 30;
+#else
+ new_start = KRB5_EVENT_REFRESH_TIME(new_start);
+#endif
+
+ gain_root_privilege();
+
+ if (ret) {
+ DEBUG(3,("krb5_ticket_refresh_handler: "
+ "could not renew tickets: %s\n",
+ error_message(ret)));
+ /* maybe we are beyond the renewing window */
+
+ /* avoid breaking the renewal chain: retry in
+ * lp_winbind_cache_time() seconds when the KDC was not
+ * available right now. */
+
+ if (ret == KRB5_KDC_UNREACH) {
+ new_start = time(NULL) +
+ MAX(30, lp_winbind_cache_time());
+ goto done;
+ }
+
+ return;
+ }
+
+done:
+
+ entry->event = event_add_timed(winbind_event_context(), entry,
+ timeval_set(new_start, 0),
+ "krb5_ticket_refresh_handler",
+ krb5_ticket_refresh_handler,
+ entry);
+
+#endif
+}
+
+/****************************************************************
+ Do the work of regaining a ticket when coming from offline auth.
+****************************************************************/
+
+static void krb5_ticket_gain_handler(struct event_context *event_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ struct WINBINDD_CCACHE_ENTRY *entry =
+ talloc_get_type_abort(private_data, struct WINBINDD_CCACHE_ENTRY);
+#ifdef HAVE_KRB5
+ int ret;
+ struct timeval t;
+ struct WINBINDD_MEMORY_CREDS *cred_ptr = entry->cred_ptr;
+ struct winbindd_domain *domain = NULL;
+#endif
+
+ DEBUG(10,("krb5_ticket_gain_handler called\n"));
+ DEBUGADD(10,("event called for: %s, %s\n",
+ entry->ccname, entry->username));
+
+ TALLOC_FREE(entry->event);
+
+#ifdef HAVE_KRB5
+
+ if (!cred_ptr || !cred_ptr->pass) {
+ DEBUG(10,("krb5_ticket_gain_handler: no memory creds\n"));
+ return;
+ }
+
+ if ((domain = find_domain_from_name(entry->realm)) == NULL) {
+ DEBUG(0,("krb5_ticket_gain_handler: unknown domain\n"));
+ return;
+ }
+
+ if (!domain->online) {
+ goto retry_later;
+ }
+
+ set_effective_uid(entry->uid);
+
+ ret = kerberos_kinit_password_ext(entry->principal_name,
+ cred_ptr->pass,
+ 0, /* hm, can we do time correction here ? */
+ &entry->refresh_time,
+ &entry->renew_until,
+ entry->ccname,
+ False, /* no PAC required anymore */
+ True,
+ WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
+ NULL);
+ gain_root_privilege();
+
+ if (ret) {
+ DEBUG(3,("krb5_ticket_gain_handler: "
+ "could not kinit: %s\n",
+ error_message(ret)));
+ goto retry_later;
+ }
+
+ DEBUG(10,("krb5_ticket_gain_handler: "
+ "successful kinit for: %s in ccache: %s\n",
+ entry->principal_name, entry->ccname));
+
+ goto got_ticket;
+
+ retry_later:
+
+ t = timeval_current_ofs(MAX(30, lp_winbind_cache_time()), 0);
+
+ entry->event = event_add_timed(winbind_event_context(),
+ entry,
+ t,
+ "krb5_ticket_gain_handler",
+ krb5_ticket_gain_handler,
+ entry);
+
+ return;
+
+ got_ticket:
+
+#if defined(DEBUG_KRB5_TKT_RENEWAL)
+ t = timeval_set(time(NULL) + 30, 0);
+#else
+ t = timeval_set(KRB5_EVENT_REFRESH_TIME(entry->refresh_time), 0);
+#endif
+
+ entry->event = event_add_timed(winbind_event_context(),
+ entry,
+ t,
+ "krb5_ticket_refresh_handler",
+ krb5_ticket_refresh_handler,
+ entry);
+
+ return;
+#endif
+}
+
+/****************************************************************
+ Check if an ccache entry exists.
+****************************************************************/
+
+bool ccache_entry_exists(const char *username)
+{
+ struct WINBINDD_CCACHE_ENTRY *entry = get_ccache_by_username(username);
+ return (entry != NULL);
+}
+
+/****************************************************************
+ Ensure we're changing the correct entry.
+****************************************************************/
+
+bool ccache_entry_identical(const char *username,
+ uid_t uid,
+ const char *ccname)
+{
+ struct WINBINDD_CCACHE_ENTRY *entry = get_ccache_by_username(username);
+
+ if (!entry) {
+ return False;
+ }
+
+ if (entry->uid != uid) {
+ DEBUG(0,("cache_entry_identical: uid's differ: %u != %u\n",
+ (unsigned int)entry->uid, (unsigned int)uid));
+ return False;
+ }
+ if (!strcsequal(entry->ccname, ccname)) {
+ DEBUG(0,("cache_entry_identical: "
+ "ccnames differ: (cache) %s != (client) %s\n",
+ entry->ccname, ccname));
+ return False;
+ }
+ return True;
+}
+
+NTSTATUS add_ccache_to_list(const char *princ_name,
+ const char *ccname,
+ const char *service,
+ const char *username,
+ const char *realm,
+ uid_t uid,
+ time_t create_time,
+ time_t ticket_end,
+ time_t renew_until,
+ bool postponed_request)
+{
+ struct WINBINDD_CCACHE_ENTRY *entry = NULL;
+ struct timeval t;
+
+ if ((username == NULL && princ_name == NULL) ||
+ ccname == NULL || uid < 0) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (ccache_entry_count() + 1 > MAX_CCACHES) {
+ DEBUG(10,("add_ccache_to_list: "
+ "max number of ccaches reached\n"));
+ return NT_STATUS_NO_MORE_ENTRIES;
+ }
+
+ /* Reference count old entries */
+ entry = get_ccache_by_username(username);
+ if (entry) {
+ /* Check cached entries are identical. */
+ if (!ccache_entry_identical(username, uid, ccname)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ entry->ref_count++;
+ DEBUG(10,("add_ccache_to_list: "
+ "ref count on entry %s is now %d\n",
+ username, entry->ref_count));
+ /* FIXME: in this case we still might want to have a krb5 cred
+ * event handler created - gd*/
+ return NT_STATUS_OK;
+ }
+
+ entry = TALLOC_P(NULL, struct WINBINDD_CCACHE_ENTRY);
+ if (!entry) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCTP(entry);
+
+ if (username) {
+ entry->username = talloc_strdup(entry, username);
+ if (!entry->username) {
+ goto no_mem;
+ }
+ }
+ if (princ_name) {
+ entry->principal_name = talloc_strdup(entry, princ_name);
+ if (!entry->principal_name) {
+ goto no_mem;
+ }
+ }
+ if (service) {
+ entry->service = talloc_strdup(entry, service);
+ if (!entry->service) {
+ goto no_mem;
+ }
+ }
+
+ entry->ccname = talloc_strdup(entry, ccname);
+ if (!entry->ccname) {
+ goto no_mem;
+ }
+
+ entry->realm = talloc_strdup(entry, realm);
+ if (!entry->realm) {
+ goto no_mem;
+ }
+
+ entry->create_time = create_time;
+ entry->renew_until = renew_until;
+ entry->uid = uid;
+ entry->ref_count = 1;
+
+ if (!lp_winbind_refresh_tickets() || renew_until <= 0) {
+ goto add_entry;
+ }
+
+ if (postponed_request) {
+ t = timeval_current_ofs(MAX(30, lp_winbind_cache_time()), 0);
+ entry->event = event_add_timed(winbind_event_context(),
+ entry,
+ t,
+ "krb5_ticket_gain_handler",
+ krb5_ticket_gain_handler,
+ entry);
+ } else {
+ /* Renew at 1/2 the ticket expiration time */
+#if defined(DEBUG_KRB5_TKT_RENEWAL)
+ t = timeval_set(time(NULL)+30, 0);
+#else
+ t = timeval_set(KRB5_EVENT_REFRESH_TIME(ticket_end), 0);
+#endif
+ entry->event = event_add_timed(winbind_event_context(),
+ entry,
+ t,
+ "krb5_ticket_refresh_handler",
+ krb5_ticket_refresh_handler,
+ entry);
+ }
+
+ if (!entry->event) {
+ goto no_mem;
+ }
+
+ DEBUG(10,("add_ccache_to_list: added krb5_ticket handler\n"));
+
+ add_entry:
+
+ DLIST_ADD(ccache_list, entry);
+
+ DEBUG(10,("add_ccache_to_list: "
+ "added ccache [%s] for user [%s] to the list\n",
+ ccname, username));
+
+ return NT_STATUS_OK;
+
+ no_mem:
+
+ TALLOC_FREE(entry);
+ return NT_STATUS_NO_MEMORY;
+}
+
+/*******************************************************************
+ Remove a WINBINDD_CCACHE_ENTRY entry and the krb5 ccache if no longer
+ referenced.
+ *******************************************************************/
+
+NTSTATUS remove_ccache(const char *username)
+{
+ struct WINBINDD_CCACHE_ENTRY *entry = get_ccache_by_username(username);
+ NTSTATUS status = NT_STATUS_OK;
+ #ifdef HAVE_KRB5
+ krb5_error_code ret;
+#endif
+
+ if (!entry) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (entry->ref_count <= 0) {
+ DEBUG(0,("remove_ccache: logic error. "
+ "ref count for user %s = %d\n",
+ username, entry->ref_count));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ entry->ref_count--;
+
+ if (entry->ref_count > 0) {
+ DEBUG(10,("remove_ccache: entry %s ref count now %d\n",
+ username, entry->ref_count));
+ return NT_STATUS_OK;
+ }
+
+ /* no references any more */
+
+ DLIST_REMOVE(ccache_list, entry);
+ TALLOC_FREE(entry->event); /* unregisters events */
+
+#ifdef HAVE_KRB5
+ ret = ads_kdestroy(entry->ccname);
+
+ /* we ignore the error when there has been no credential cache */
+ if (ret == KRB5_FCC_NOFILE) {
+ ret = 0;
+ } else if (ret) {
+ DEBUG(0,("remove_ccache: "
+ "failed to destroy user krb5 ccache %s with: %s\n",
+ entry->ccname, error_message(ret)));
+ } else {
+ DEBUG(10,("remove_ccache: "
+ "successfully destroyed krb5 ccache %s for user %s\n",
+ entry->ccname, username));
+ }
+ status = krb5_to_nt_status(ret);
+#endif
+
+ TALLOC_FREE(entry);
+ DEBUG(10,("remove_ccache: removed ccache for user %s\n", username));
+
+ return status;
+}
+
+/*******************************************************************
+ In memory credentials cache code.
+*******************************************************************/
+
+static struct WINBINDD_MEMORY_CREDS *memory_creds_list;
+
+/***********************************************************
+ Find an entry on the list by name.
+***********************************************************/
+
+struct WINBINDD_MEMORY_CREDS *find_memory_creds_by_name(const char *username)
+{
+ struct WINBINDD_MEMORY_CREDS *p;
+
+ for (p = memory_creds_list; p; p = p->next) {
+ if (strequal(p->username, username)) {
+ return p;
+ }
+ }
+ return NULL;
+}
+
+/***********************************************************
+ Store the required creds and mlock them.
+***********************************************************/
+
+static NTSTATUS store_memory_creds(struct WINBINDD_MEMORY_CREDS *memcredp,
+ const char *pass)
+{
+#if !defined(HAVE_MLOCK)
+ return NT_STATUS_OK;
+#else
+ /* new_entry->nt_hash is the base pointer for the block
+ of memory pointed into by new_entry->lm_hash and
+ new_entry->pass (if we're storing plaintext). */
+
+ memcredp->len = NT_HASH_LEN + LM_HASH_LEN;
+ if (pass) {
+ memcredp->len += strlen(pass)+1;
+ }
+
+
+#if defined(LINUX)
+ /* aligning the memory on on x86_64 and compiling
+ with gcc 4.1 using -O2 causes a segv in the
+ next memset() --jerry */
+ memcredp->nt_hash = SMB_MALLOC_ARRAY(unsigned char, memcredp->len);
+#else
+ /* On non-linux platforms, mlock()'d memory must be aligned */
+ memcredp->nt_hash = SMB_MEMALIGN_ARRAY(unsigned char,
+ getpagesize(), memcredp->len);
+#endif
+ if (!memcredp->nt_hash) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ memset(memcredp->nt_hash, 0x0, memcredp->len);
+
+ memcredp->lm_hash = memcredp->nt_hash + NT_HASH_LEN;
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(10,("mlocking memory: %p\n", memcredp->nt_hash));
+#endif
+ if ((mlock(memcredp->nt_hash, memcredp->len)) == -1) {
+ DEBUG(0,("failed to mlock memory: %s (%d)\n",
+ strerror(errno), errno));
+ SAFE_FREE(memcredp->nt_hash);
+ return map_nt_error_from_unix(errno);
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(10,("mlocked memory: %p\n", memcredp->nt_hash));
+#endif
+
+ /* Create and store the password hashes. */
+ E_md4hash(pass, memcredp->nt_hash);
+ E_deshash(pass, memcredp->lm_hash);
+
+ if (pass) {
+ memcredp->pass = (char *)memcredp->lm_hash + LM_HASH_LEN;
+ memcpy(memcredp->pass, pass,
+ memcredp->len - NT_HASH_LEN - LM_HASH_LEN);
+ }
+
+ return NT_STATUS_OK;
+#endif
+}
+
+/***********************************************************
+ Destroy existing creds.
+***********************************************************/
+
+static NTSTATUS delete_memory_creds(struct WINBINDD_MEMORY_CREDS *memcredp)
+{
+#if !defined(HAVE_MUNLOCK)
+ return NT_STATUS_OK;
+#else
+ if (munlock(memcredp->nt_hash, memcredp->len) == -1) {
+ DEBUG(0,("failed to munlock memory: %s (%d)\n",
+ strerror(errno), errno));
+ return map_nt_error_from_unix(errno);
+ }
+ memset(memcredp->nt_hash, '\0', memcredp->len);
+ SAFE_FREE(memcredp->nt_hash);
+ memcredp->nt_hash = NULL;
+ memcredp->lm_hash = NULL;
+ memcredp->pass = NULL;
+ memcredp->len = 0;
+ return NT_STATUS_OK;
+#endif
+}
+
+/***********************************************************
+ Replace the required creds with new ones (password change).
+***********************************************************/
+
+static NTSTATUS winbindd_replace_memory_creds_internal(struct WINBINDD_MEMORY_CREDS *memcredp,
+ const char *pass)
+{
+ NTSTATUS status = delete_memory_creds(memcredp);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ return store_memory_creds(memcredp, pass);
+}
+
+/*************************************************************
+ Store credentials in memory in a list.
+*************************************************************/
+
+static NTSTATUS winbindd_add_memory_creds_internal(const char *username,
+ uid_t uid,
+ const char *pass)
+{
+ /* Shortcut to ensure we don't store if no mlock. */
+#if !defined(HAVE_MLOCK) || !defined(HAVE_MUNLOCK)
+ return NT_STATUS_OK;
+#else
+ NTSTATUS status;
+ struct WINBINDD_MEMORY_CREDS *memcredp = NULL;
+
+ memcredp = find_memory_creds_by_name(username);
+ if (uid == (uid_t)-1) {
+ DEBUG(0,("winbindd_add_memory_creds_internal: "
+ "invalid uid for user %s.\n", username));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (memcredp) {
+ /* Already exists. Increment the reference count and replace stored creds. */
+ if (uid != memcredp->uid) {
+ DEBUG(0,("winbindd_add_memory_creds_internal: "
+ "uid %u for user %s doesn't "
+ "match stored uid %u. Replacing.\n",
+ (unsigned int)uid, username,
+ (unsigned int)memcredp->uid));
+ memcredp->uid = uid;
+ }
+ memcredp->ref_count++;
+ DEBUG(10,("winbindd_add_memory_creds_internal: "
+ "ref count for user %s is now %d\n",
+ username, memcredp->ref_count));
+ return winbindd_replace_memory_creds_internal(memcredp, pass);
+ }
+
+ memcredp = TALLOC_ZERO_P(NULL, struct WINBINDD_MEMORY_CREDS);
+ if (!memcredp) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ memcredp->username = talloc_strdup(memcredp, username);
+ if (!memcredp->username) {
+ talloc_destroy(memcredp);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = store_memory_creds(memcredp, pass);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_destroy(memcredp);
+ return status;
+ }
+
+ memcredp->uid = uid;
+ memcredp->ref_count = 1;
+ DLIST_ADD(memory_creds_list, memcredp);
+
+ DEBUG(10,("winbindd_add_memory_creds_internal: "
+ "added entry for user %s\n", username));
+
+ return NT_STATUS_OK;
+#endif
+}
+
+/*************************************************************
+ Store users credentials in memory. If we also have a
+ struct WINBINDD_CCACHE_ENTRY for this username with a
+ refresh timer, then store the plaintext of the password
+ and associate the new credentials with the struct WINBINDD_CCACHE_ENTRY.
+*************************************************************/
+
+NTSTATUS winbindd_add_memory_creds(const char *username,
+ uid_t uid,
+ const char *pass)
+{
+ struct WINBINDD_CCACHE_ENTRY *entry = get_ccache_by_username(username);
+ NTSTATUS status;
+
+ status = winbindd_add_memory_creds_internal(username, uid, pass);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (entry) {
+ struct WINBINDD_MEMORY_CREDS *memcredp = NULL;
+ memcredp = find_memory_creds_by_name(username);
+ if (memcredp) {
+ entry->cred_ptr = memcredp;
+ }
+ }
+
+ return status;
+}
+
+/*************************************************************
+ Decrement the in-memory ref count - delete if zero.
+*************************************************************/
+
+NTSTATUS winbindd_delete_memory_creds(const char *username)
+{
+ struct WINBINDD_MEMORY_CREDS *memcredp = NULL;
+ struct WINBINDD_CCACHE_ENTRY *entry = NULL;
+ NTSTATUS status = NT_STATUS_OK;
+
+ memcredp = find_memory_creds_by_name(username);
+ entry = get_ccache_by_username(username);
+
+ if (!memcredp) {
+ DEBUG(10,("winbindd_delete_memory_creds: unknown user %s\n",
+ username));
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (memcredp->ref_count <= 0) {
+ DEBUG(0,("winbindd_delete_memory_creds: logic error. "
+ "ref count for user %s = %d\n",
+ username, memcredp->ref_count));
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ memcredp->ref_count--;
+ if (memcredp->ref_count <= 0) {
+ delete_memory_creds(memcredp);
+ DLIST_REMOVE(memory_creds_list, memcredp);
+ talloc_destroy(memcredp);
+ DEBUG(10,("winbindd_delete_memory_creds: "
+ "deleted entry for user %s\n",
+ username));
+ } else {
+ DEBUG(10,("winbindd_delete_memory_creds: "
+ "entry for user %s ref_count now %d\n",
+ username, memcredp->ref_count));
+ }
+
+ if (entry) {
+ /* Ensure we have no dangling references to this. */
+ entry->cred_ptr = NULL;
+ }
+
+ return status;
+}
+
+/***********************************************************
+ Replace the required creds with new ones (password change).
+***********************************************************/
+
+NTSTATUS winbindd_replace_memory_creds(const char *username,
+ const char *pass)
+{
+ struct WINBINDD_MEMORY_CREDS *memcredp = NULL;
+
+ memcredp = find_memory_creds_by_name(username);
+ if (!memcredp) {
+ DEBUG(10,("winbindd_replace_memory_creds: unknown user %s\n",
+ username));
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ DEBUG(10,("winbindd_replace_memory_creds: replaced creds for user %s\n",
+ username));
+
+ return winbindd_replace_memory_creds_internal(memcredp, pass);
+}
diff --git a/source3/winbindd/winbindd_creds.c b/source3/winbindd/winbindd_creds.c
new file mode 100644
index 0000000000..9c7acd64e6
--- /dev/null
+++ b/source3/winbindd/winbindd_creds.c
@@ -0,0 +1,162 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon - cached credentials funcions
+
+ Copyright (C) Guenther Deschner 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+#define MAX_CACHED_LOGINS 10
+
+NTSTATUS winbindd_get_creds(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ struct netr_SamInfo3 **info3,
+ const uint8 *cached_nt_pass[NT_HASH_LEN],
+ const uint8 *cred_salt[NT_HASH_LEN])
+{
+ struct netr_SamInfo3 *info;
+ NTSTATUS status;
+
+ status = wcache_get_creds(domain, mem_ctx, sid, cached_nt_pass, cred_salt);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ info = netsamlogon_cache_get(mem_ctx, sid);
+ if (info == NULL) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ *info3 = info;
+
+ return NT_STATUS_OK;
+}
+
+
+NTSTATUS winbindd_store_creds(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const char *user,
+ const char *pass,
+ struct netr_SamInfo3 *info3,
+ const DOM_SID *user_sid)
+{
+ NTSTATUS status;
+ uchar nt_pass[NT_HASH_LEN];
+ DOM_SID cred_sid;
+
+ if (info3 != NULL) {
+
+ DOM_SID sid;
+ sid_copy(&sid, info3->base.domain_sid);
+ sid_append_rid(&sid, info3->base.rid);
+ sid_copy(&cred_sid, &sid);
+ info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
+
+ } else if (user_sid != NULL) {
+
+ sid_copy(&cred_sid, user_sid);
+
+ } else if (user != NULL) {
+
+ /* do lookup ourself */
+
+ enum lsa_SidType type;
+
+ if (!lookup_cached_name(mem_ctx,
+ domain->name,
+ user,
+ &cred_sid,
+ &type)) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+ } else {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (pass) {
+
+ int count = 0;
+
+ status = wcache_count_cached_creds(domain, &count);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(11,("we have %d cached creds\n", count));
+
+ if (count + 1 > MAX_CACHED_LOGINS) {
+
+ DEBUG(10,("need to delete the oldest cached login\n"));
+
+ status = wcache_remove_oldest_cached_creds(domain, &cred_sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("failed to remove oldest cached cred: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+ }
+
+ E_md4hash(pass, nt_pass);
+
+ dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
+
+ status = wcache_save_creds(domain, mem_ctx, &cred_sid, nt_pass);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ if (info3 != NULL && user != NULL) {
+ if (!netsamlogon_cache_store(user, info3)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS winbindd_update_creds_by_info3(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const char *user,
+ const char *pass,
+ struct netr_SamInfo3 *info3)
+{
+ return winbindd_store_creds(domain, mem_ctx, user, pass, info3, NULL);
+}
+
+NTSTATUS winbindd_update_creds_by_sid(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ const char *pass)
+{
+ return winbindd_store_creds(domain, mem_ctx, NULL, pass, NULL, sid);
+}
+
+NTSTATUS winbindd_update_creds_by_name(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const char *user,
+ const char *pass)
+{
+ return winbindd_store_creds(domain, mem_ctx, user, pass, NULL, NULL);
+}
+
+
diff --git a/source3/winbindd/winbindd_domain.c b/source3/winbindd/winbindd_domain.c
new file mode 100644
index 0000000000..2e8c6175ca
--- /dev/null
+++ b/source3/winbindd/winbindd_domain.c
@@ -0,0 +1,119 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind domain child functions
+
+ Copyright (C) Stefan Metzmacher 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+static const struct winbindd_child_dispatch_table domain_dispatch_table[];
+
+void setup_domain_child(struct winbindd_domain *domain,
+ struct winbindd_child *child)
+{
+ setup_child(child, domain_dispatch_table,
+ "log.wb", domain->name);
+
+ child->domain = domain;
+}
+
+static const struct winbindd_child_dispatch_table domain_dispatch_table[] = {
+ {
+ .name = "LOOKUPSID",
+ .struct_cmd = WINBINDD_LOOKUPSID,
+ .struct_fn = winbindd_dual_lookupsid,
+ },{
+ .name = "LOOKUPNAME",
+ .struct_cmd = WINBINDD_LOOKUPNAME,
+ .struct_fn = winbindd_dual_lookupname,
+ },{
+ .name = "LOOKUPRIDS",
+ .struct_cmd = WINBINDD_LOOKUPRIDS,
+ .struct_fn = winbindd_dual_lookuprids,
+ },{
+ .name = "LIST_USERS",
+ .struct_cmd = WINBINDD_LIST_USERS,
+ .struct_fn = winbindd_dual_list_users,
+ },{
+ .name = "LIST_GROUPS",
+ .struct_cmd = WINBINDD_LIST_GROUPS,
+ .struct_fn = winbindd_dual_list_groups,
+ },{
+ .name = "LIST_TRUSTDOM",
+ .struct_cmd = WINBINDD_LIST_TRUSTDOM,
+ .struct_fn = winbindd_dual_list_trusted_domains,
+ },{
+ .name = "INIT_CONNECTION",
+ .struct_cmd = WINBINDD_INIT_CONNECTION,
+ .struct_fn = winbindd_dual_init_connection,
+ },{
+ .name = "GETDCNAME",
+ .struct_cmd = WINBINDD_GETDCNAME,
+ .struct_fn = winbindd_dual_getdcname,
+ },{
+ .name = "SHOW_SEQUENCE",
+ .struct_cmd = WINBINDD_SHOW_SEQUENCE,
+ .struct_fn = winbindd_dual_show_sequence,
+ },{
+ .name = "PAM_AUTH",
+ .struct_cmd = WINBINDD_PAM_AUTH,
+ .struct_fn = winbindd_dual_pam_auth,
+ },{
+ .name = "AUTH_CRAP",
+ .struct_cmd = WINBINDD_PAM_AUTH_CRAP,
+ .struct_fn = winbindd_dual_pam_auth_crap,
+ },{
+ .name = "PAM_LOGOFF",
+ .struct_cmd = WINBINDD_PAM_LOGOFF,
+ .struct_fn = winbindd_dual_pam_logoff,
+ },{
+ .name = "CHNG_PSWD_AUTH_CRAP",
+ .struct_cmd = WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP,
+ .struct_fn = winbindd_dual_pam_chng_pswd_auth_crap,
+ },{
+ .name = "PAM_CHAUTHTOK",
+ .struct_cmd = WINBINDD_PAM_CHAUTHTOK,
+ .struct_fn = winbindd_dual_pam_chauthtok,
+ },{
+ .name = "CHECK_MACHACC",
+ .struct_cmd = WINBINDD_CHECK_MACHACC,
+ .struct_fn = winbindd_dual_check_machine_acct,
+ },{
+ .name = "DUAL_USERINFO",
+ .struct_cmd = WINBINDD_DUAL_USERINFO,
+ .struct_fn = winbindd_dual_userinfo,
+ },{
+ .name = "GETUSERDOMGROUPS",
+ .struct_cmd = WINBINDD_GETUSERDOMGROUPS,
+ .struct_fn = winbindd_dual_getuserdomgroups,
+ },{
+ .name = "GETSIDALIASES",
+ .struct_cmd = WINBINDD_DUAL_GETSIDALIASES,
+ .struct_fn = winbindd_dual_getsidaliases,
+ },{
+ .name = "CCACHE_NTLM_AUTH",
+ .struct_cmd = WINBINDD_CCACHE_NTLMAUTH,
+ .struct_fn = winbindd_dual_ccache_ntlm_auth,
+ },{
+ .name = NULL,
+ }
+};
diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c
new file mode 100644
index 0000000000..63ce0e8d7f
--- /dev/null
+++ b/source3/winbindd/winbindd_dual.c
@@ -0,0 +1,1358 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind child daemons
+
+ Copyright (C) Andrew Tridgell 2002
+ Copyright (C) Volker Lendecke 2004,2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * We fork a child per domain to be able to act non-blocking in the main
+ * winbind daemon. A domain controller thousands of miles away being being
+ * slow replying with a 10.000 user list should not hold up netlogon calls
+ * that can be handled locally.
+ */
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+extern bool override_logfile;
+extern struct winbindd_methods cache_methods;
+
+/* Read some data from a client connection */
+
+static void child_read_request(struct winbindd_cli_state *state)
+{
+ NTSTATUS status;
+
+ /* Read data */
+
+ status = read_data(state->sock, (char *)&state->request,
+ sizeof(state->request));
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("child_read_request: read_data failed: %s\n",
+ nt_errstr(status)));
+ state->finished = True;
+ return;
+ }
+
+ if (state->request.extra_len == 0) {
+ state->request.extra_data.data = NULL;
+ return;
+ }
+
+ DEBUG(10, ("Need to read %d extra bytes\n", (int)state->request.extra_len));
+
+ state->request.extra_data.data =
+ SMB_MALLOC_ARRAY(char, state->request.extra_len + 1);
+
+ if (state->request.extra_data.data == NULL) {
+ DEBUG(0, ("malloc failed\n"));
+ state->finished = True;
+ return;
+ }
+
+ /* Ensure null termination */
+ state->request.extra_data.data[state->request.extra_len] = '\0';
+
+ status= read_data(state->sock, state->request.extra_data.data,
+ state->request.extra_len);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Could not read extra data: %s\n",
+ nt_errstr(status)));
+ state->finished = True;
+ return;
+ }
+}
+
+/*
+ * Machinery for async requests sent to children. You set up a
+ * winbindd_request, select a child to query, and issue a async_request
+ * call. When the request is completed, the callback function you specified is
+ * called back with the private pointer you gave to async_request.
+ */
+
+struct winbindd_async_request {
+ struct winbindd_async_request *next, *prev;
+ TALLOC_CTX *mem_ctx;
+ struct winbindd_child *child;
+ struct winbindd_request *request;
+ struct winbindd_response *response;
+ void (*continuation)(void *private_data, bool success);
+ struct timed_event *reply_timeout_event;
+ pid_t child_pid; /* pid of the child we're waiting on. Used to detect
+ a restart of the child (child->pid != child_pid). */
+ void *private_data;
+};
+
+static void async_request_fail(struct winbindd_async_request *state);
+static void async_main_request_sent(void *private_data, bool success);
+static void async_request_sent(void *private_data, bool success);
+static void async_reply_recv(void *private_data, bool success);
+static void schedule_async_request(struct winbindd_child *child);
+
+void async_request(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
+ struct winbindd_request *request,
+ struct winbindd_response *response,
+ void (*continuation)(void *private_data, bool success),
+ void *private_data)
+{
+ struct winbindd_async_request *state;
+
+ SMB_ASSERT(continuation != NULL);
+
+ state = TALLOC_P(mem_ctx, struct winbindd_async_request);
+
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ continuation(private_data, False);
+ return;
+ }
+
+ state->mem_ctx = mem_ctx;
+ state->child = child;
+ state->reply_timeout_event = NULL;
+ state->request = request;
+ state->response = response;
+ state->continuation = continuation;
+ state->private_data = private_data;
+
+ DLIST_ADD_END(child->requests, state, struct winbindd_async_request *);
+
+ schedule_async_request(child);
+
+ return;
+}
+
+static void async_main_request_sent(void *private_data, bool success)
+{
+ struct winbindd_async_request *state =
+ talloc_get_type_abort(private_data, struct winbindd_async_request);
+
+ if (!success) {
+ DEBUG(5, ("Could not send async request\n"));
+ async_request_fail(state);
+ return;
+ }
+
+ if (state->request->extra_len == 0) {
+ async_request_sent(private_data, True);
+ return;
+ }
+
+ setup_async_write(&state->child->event, state->request->extra_data.data,
+ state->request->extra_len,
+ async_request_sent, state);
+}
+
+/****************************************************************
+ Handler triggered if the child winbindd doesn't respond within
+ a given timeout.
+****************************************************************/
+
+static void async_request_timeout_handler(struct event_context *ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ struct winbindd_async_request *state =
+ talloc_get_type_abort(private_data, struct winbindd_async_request);
+
+ DEBUG(0,("async_request_timeout_handler: child pid %u is not responding. "
+ "Closing connection to it.\n",
+ state->child_pid ));
+
+ /* Deal with the reply - set to error. */
+ async_reply_recv(private_data, False);
+}
+
+/**************************************************************
+ Common function called on both async send and recv fail.
+ Cleans up the child and schedules the next request.
+**************************************************************/
+
+static void async_request_fail(struct winbindd_async_request *state)
+{
+ DLIST_REMOVE(state->child->requests, state);
+
+ TALLOC_FREE(state->reply_timeout_event);
+
+ SMB_ASSERT(state->child_pid != (pid_t)0);
+
+ /* If not already reaped, send kill signal to child. */
+ if (state->child->pid == state->child_pid) {
+ kill(state->child_pid, SIGTERM);
+
+ /*
+ * Close the socket to the child.
+ */
+ winbind_child_died(state->child_pid);
+ }
+
+ state->response->length = sizeof(struct winbindd_response);
+ state->response->result = WINBINDD_ERROR;
+ state->continuation(state->private_data, False);
+}
+
+static void async_request_sent(void *private_data_data, bool success)
+{
+ struct winbindd_async_request *state =
+ talloc_get_type_abort(private_data_data, struct winbindd_async_request);
+
+ if (!success) {
+ DEBUG(5, ("Could not send async request to child pid %u\n",
+ (unsigned int)state->child_pid ));
+ async_request_fail(state);
+ return;
+ }
+
+ /* Request successfully sent to the child, setup the wait for reply */
+
+ setup_async_read(&state->child->event,
+ &state->response->result,
+ sizeof(state->response->result),
+ async_reply_recv, state);
+
+ /*
+ * Set up a timeout of 300 seconds for the response.
+ * If we don't get it close the child socket and
+ * report failure.
+ */
+
+ state->reply_timeout_event = event_add_timed(winbind_event_context(),
+ NULL,
+ timeval_current_ofs(300,0),
+ "async_request_timeout",
+ async_request_timeout_handler,
+ state);
+ if (!state->reply_timeout_event) {
+ smb_panic("async_request_sent: failed to add timeout handler.\n");
+ }
+}
+
+static void async_reply_recv(void *private_data, bool success)
+{
+ struct winbindd_async_request *state =
+ talloc_get_type_abort(private_data, struct winbindd_async_request);
+ struct winbindd_child *child = state->child;
+
+ TALLOC_FREE(state->reply_timeout_event);
+
+ state->response->length = sizeof(struct winbindd_response);
+
+ if (!success) {
+ DEBUG(5, ("Could not receive async reply from child pid %u\n",
+ (unsigned int)state->child_pid ));
+
+ cache_cleanup_response(state->child_pid);
+ async_request_fail(state);
+ return;
+ }
+
+ SMB_ASSERT(cache_retrieve_response(state->child_pid,
+ state->response));
+
+ cache_cleanup_response(state->child_pid);
+
+ DLIST_REMOVE(child->requests, state);
+
+ schedule_async_request(child);
+
+ state->continuation(state->private_data, True);
+}
+
+static bool fork_domain_child(struct winbindd_child *child);
+
+static void schedule_async_request(struct winbindd_child *child)
+{
+ struct winbindd_async_request *request = child->requests;
+
+ if (request == NULL) {
+ return;
+ }
+
+ if (child->event.flags != 0) {
+ return; /* Busy */
+ }
+
+ if ((child->pid == 0) && (!fork_domain_child(child))) {
+ /* Cancel all outstanding requests */
+
+ while (request != NULL) {
+ /* request might be free'd in the continuation */
+ struct winbindd_async_request *next = request->next;
+ request->continuation(request->private_data, False);
+ request = next;
+ }
+ return;
+ }
+
+ /* Now we know who we're sending to - remember the pid. */
+ request->child_pid = child->pid;
+
+ setup_async_write(&child->event, request->request,
+ sizeof(*request->request),
+ async_main_request_sent, request);
+
+ return;
+}
+
+struct domain_request_state {
+ TALLOC_CTX *mem_ctx;
+ struct winbindd_domain *domain;
+ struct winbindd_request *request;
+ struct winbindd_response *response;
+ void (*continuation)(void *private_data_data, bool success);
+ void *private_data_data;
+};
+
+static void domain_init_recv(void *private_data_data, bool success);
+
+void async_domain_request(TALLOC_CTX *mem_ctx,
+ struct winbindd_domain *domain,
+ struct winbindd_request *request,
+ struct winbindd_response *response,
+ void (*continuation)(void *private_data_data, bool success),
+ void *private_data_data)
+{
+ struct domain_request_state *state;
+
+ if (domain->initialized) {
+ async_request(mem_ctx, &domain->child, request, response,
+ continuation, private_data_data);
+ return;
+ }
+
+ state = TALLOC_P(mem_ctx, struct domain_request_state);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ continuation(private_data_data, False);
+ return;
+ }
+
+ state->mem_ctx = mem_ctx;
+ state->domain = domain;
+ state->request = request;
+ state->response = response;
+ state->continuation = continuation;
+ state->private_data_data = private_data_data;
+
+ init_child_connection(domain, domain_init_recv, state);
+}
+
+static void domain_init_recv(void *private_data_data, bool success)
+{
+ struct domain_request_state *state =
+ talloc_get_type_abort(private_data_data, struct domain_request_state);
+
+ if (!success) {
+ DEBUG(5, ("Domain init returned an error\n"));
+ state->continuation(state->private_data_data, False);
+ return;
+ }
+
+ async_request(state->mem_ctx, &state->domain->child,
+ state->request, state->response,
+ state->continuation, state->private_data_data);
+}
+
+static void recvfrom_child(void *private_data_data, bool success)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private_data_data, struct winbindd_cli_state);
+ enum winbindd_result result = state->response.result;
+
+ /* This is an optimization: The child has written directly to the
+ * response buffer. The request itself is still in pending state,
+ * state that in the result code. */
+
+ state->response.result = WINBINDD_PENDING;
+
+ if ((!success) || (result != WINBINDD_OK)) {
+ request_error(state);
+ return;
+ }
+
+ request_ok(state);
+}
+
+void sendto_child(struct winbindd_cli_state *state,
+ struct winbindd_child *child)
+{
+ async_request(state->mem_ctx, child, &state->request,
+ &state->response, recvfrom_child, state);
+}
+
+void sendto_domain(struct winbindd_cli_state *state,
+ struct winbindd_domain *domain)
+{
+ async_domain_request(state->mem_ctx, domain,
+ &state->request, &state->response,
+ recvfrom_child, state);
+}
+
+static void child_process_request(struct winbindd_child *child,
+ struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain = child->domain;
+ const struct winbindd_child_dispatch_table *table = child->table;
+
+ /* Free response data - we may be interrupted and receive another
+ command before being able to send this data off. */
+
+ state->response.result = WINBINDD_ERROR;
+ state->response.length = sizeof(struct winbindd_response);
+
+ /* as all requests in the child are sync, we can use talloc_tos() */
+ state->mem_ctx = talloc_tos();
+
+ /* Process command */
+
+ for (; table->name; table++) {
+ if (state->request.cmd == table->struct_cmd) {
+ DEBUG(10,("child_process_request: request fn %s\n",
+ table->name));
+ state->response.result = table->struct_fn(domain, state);
+ return;
+ }
+ }
+
+ DEBUG(1 ,("child_process_request: unknown request fn number %d\n",
+ (int)state->request.cmd));
+ state->response.result = WINBINDD_ERROR;
+}
+
+void setup_child(struct winbindd_child *child,
+ const struct winbindd_child_dispatch_table *table,
+ const char *logprefix,
+ const char *logname)
+{
+ if (logprefix && logname) {
+ if (asprintf(&child->logfilename, "%s/%s-%s",
+ get_dyn_LOGFILEBASE(), logprefix, logname) < 0) {
+ smb_panic("Internal error: asprintf failed");
+ }
+ } else {
+ smb_panic("Internal error: logprefix == NULL && "
+ "logname == NULL");
+ }
+
+ child->domain = NULL;
+ child->table = table;
+}
+
+struct winbindd_child *children = NULL;
+
+void winbind_child_died(pid_t pid)
+{
+ struct winbindd_child *child;
+
+ for (child = children; child != NULL; child = child->next) {
+ if (child->pid == pid) {
+ break;
+ }
+ }
+
+ if (child == NULL) {
+ DEBUG(5, ("Already reaped child %u died\n", (unsigned int)pid));
+ return;
+ }
+
+ /* This will be re-added in fork_domain_child() */
+
+ DLIST_REMOVE(children, child);
+
+ remove_fd_event(&child->event);
+ close(child->event.fd);
+ child->event.fd = 0;
+ child->event.flags = 0;
+ child->pid = 0;
+
+ schedule_async_request(child);
+}
+
+/* Ensure any negative cache entries with the netbios or realm names are removed. */
+
+void winbindd_flush_negative_conn_cache(struct winbindd_domain *domain)
+{
+ flush_negative_conn_cache_for_domain(domain->name);
+ if (*domain->alt_name) {
+ flush_negative_conn_cache_for_domain(domain->alt_name);
+ }
+}
+
+/*
+ * Parent winbindd process sets its own debug level first and then
+ * sends a message to all the winbindd children to adjust their debug
+ * level to that of parents.
+ */
+
+void winbind_msg_debug(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct winbindd_child *child;
+
+ DEBUG(10,("winbind_msg_debug: got debug message.\n"));
+
+ debug_message(msg_ctx, private_data, MSG_DEBUG, server_id, data);
+
+ for (child = children; child != NULL; child = child->next) {
+
+ DEBUG(10,("winbind_msg_debug: sending message to pid %u.\n",
+ (unsigned int)child->pid));
+
+ messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
+ MSG_DEBUG,
+ data->data,
+ strlen((char *) data->data) + 1);
+ }
+}
+
+/* Set our domains as offline and forward the offline message to our children. */
+
+void winbind_msg_offline(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct winbindd_child *child;
+ struct winbindd_domain *domain;
+
+ DEBUG(10,("winbind_msg_offline: got offline message.\n"));
+
+ if (!lp_winbind_offline_logon()) {
+ DEBUG(10,("winbind_msg_offline: rejecting offline message.\n"));
+ return;
+ }
+
+ /* Set our global state as offline. */
+ if (!set_global_winbindd_state_offline()) {
+ DEBUG(10,("winbind_msg_offline: offline request failed.\n"));
+ return;
+ }
+
+ /* Set all our domains as offline. */
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->internal) {
+ continue;
+ }
+ DEBUG(5,("winbind_msg_offline: marking %s offline.\n", domain->name));
+ set_domain_offline(domain);
+ }
+
+ for (child = children; child != NULL; child = child->next) {
+ /* Don't send message to internal childs. We've already
+ done so above. */
+ if (!child->domain || winbindd_internal_child(child)) {
+ continue;
+ }
+
+ /* Or internal domains (this should not be possible....) */
+ if (child->domain->internal) {
+ continue;
+ }
+
+ /* Each winbindd child should only process requests for one domain - make sure
+ we only set it online / offline for that domain. */
+
+ DEBUG(10,("winbind_msg_offline: sending message to pid %u for domain %s.\n",
+ (unsigned int)child->pid, domain->name ));
+
+ messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
+ MSG_WINBIND_OFFLINE,
+ (uint8 *)child->domain->name,
+ strlen(child->domain->name)+1);
+ }
+}
+
+/* Set our domains as online and forward the online message to our children. */
+
+void winbind_msg_online(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct winbindd_child *child;
+ struct winbindd_domain *domain;
+
+ DEBUG(10,("winbind_msg_online: got online message.\n"));
+
+ if (!lp_winbind_offline_logon()) {
+ DEBUG(10,("winbind_msg_online: rejecting online message.\n"));
+ return;
+ }
+
+ /* Set our global state as online. */
+ set_global_winbindd_state_online();
+
+ smb_nscd_flush_user_cache();
+ smb_nscd_flush_group_cache();
+
+ /* Set all our domains as online. */
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->internal) {
+ continue;
+ }
+ DEBUG(5,("winbind_msg_online: requesting %s to go online.\n", domain->name));
+
+ winbindd_flush_negative_conn_cache(domain);
+ set_domain_online_request(domain);
+
+ /* Send an online message to the idmap child when our
+ primary domain comes back online */
+
+ if ( domain->primary ) {
+ struct winbindd_child *idmap = idmap_child();
+
+ if ( idmap->pid != 0 ) {
+ messaging_send_buf(msg_ctx,
+ pid_to_procid(idmap->pid),
+ MSG_WINBIND_ONLINE,
+ (uint8 *)domain->name,
+ strlen(domain->name)+1);
+ }
+
+ }
+ }
+
+ for (child = children; child != NULL; child = child->next) {
+ /* Don't send message to internal childs. */
+ if (!child->domain || winbindd_internal_child(child)) {
+ continue;
+ }
+
+ /* Or internal domains (this should not be possible....) */
+ if (child->domain->internal) {
+ continue;
+ }
+
+ /* Each winbindd child should only process requests for one domain - make sure
+ we only set it online / offline for that domain. */
+
+ DEBUG(10,("winbind_msg_online: sending message to pid %u for domain %s.\n",
+ (unsigned int)child->pid, child->domain->name ));
+
+ messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
+ MSG_WINBIND_ONLINE,
+ (uint8 *)child->domain->name,
+ strlen(child->domain->name)+1);
+ }
+}
+
+/* Forward the online/offline messages to our children. */
+void winbind_msg_onlinestatus(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct winbindd_child *child;
+
+ DEBUG(10,("winbind_msg_onlinestatus: got onlinestatus message.\n"));
+
+ for (child = children; child != NULL; child = child->next) {
+ if (child->domain && child->domain->primary) {
+ DEBUG(10,("winbind_msg_onlinestatus: "
+ "sending message to pid %u of primary domain.\n",
+ (unsigned int)child->pid));
+ messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
+ MSG_WINBIND_ONLINESTATUS,
+ (uint8 *)data->data,
+ data->length);
+ break;
+ }
+ }
+}
+
+void winbind_msg_dump_event_list(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct winbindd_child *child;
+
+ DEBUG(10,("winbind_msg_dump_event_list received\n"));
+
+ dump_event_list(winbind_event_context());
+
+ for (child = children; child != NULL; child = child->next) {
+
+ DEBUG(10,("winbind_msg_dump_event_list: sending message to pid %u\n",
+ (unsigned int)child->pid));
+
+ messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
+ MSG_DUMP_EVENT_LIST,
+ NULL, 0);
+ }
+
+}
+
+void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ TALLOC_CTX *mem_ctx;
+ const char *message = NULL;
+ struct server_id *sender = NULL;
+ const char *domain = NULL;
+ char *s = NULL;
+ NTSTATUS status;
+ struct winbindd_domain *dom = NULL;
+
+ DEBUG(5,("winbind_msg_dump_domain_list received.\n"));
+
+ if (!data || !data->data) {
+ return;
+ }
+
+ if (data->length < sizeof(struct server_id)) {
+ return;
+ }
+
+ mem_ctx = talloc_init("winbind_msg_dump_domain_list");
+ if (!mem_ctx) {
+ return;
+ }
+
+ sender = (struct server_id *)data->data;
+ if (data->length > sizeof(struct server_id)) {
+ domain = (const char *)data->data+sizeof(struct server_id);
+ }
+
+ if (domain) {
+
+ DEBUG(5,("winbind_msg_dump_domain_list for domain: %s\n",
+ domain));
+
+ message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain,
+ find_domain_from_name_noinit(domain));
+ if (!message) {
+ talloc_destroy(mem_ctx);
+ return;
+ }
+
+ messaging_send_buf(msg_ctx, *sender,
+ MSG_WINBIND_DUMP_DOMAIN_LIST,
+ (uint8_t *)message, strlen(message) + 1);
+
+ talloc_destroy(mem_ctx);
+
+ return;
+ }
+
+ DEBUG(5,("winbind_msg_dump_domain_list all domains\n"));
+
+ for (dom = domain_list(); dom; dom=dom->next) {
+ message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain, dom);
+ if (!message) {
+ talloc_destroy(mem_ctx);
+ return;
+ }
+
+ s = talloc_asprintf_append(s, "%s\n", message);
+ if (!s) {
+ talloc_destroy(mem_ctx);
+ return;
+ }
+ }
+
+ status = messaging_send_buf(msg_ctx, *sender,
+ MSG_WINBIND_DUMP_DOMAIN_LIST,
+ (uint8_t *)s, strlen(s) + 1);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("failed to send message: %s\n",
+ nt_errstr(status)));
+ }
+
+ talloc_destroy(mem_ctx);
+}
+
+static void account_lockout_policy_handler(struct event_context *ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ struct winbindd_child *child =
+ (struct winbindd_child *)private_data;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct winbindd_methods *methods;
+ struct samr_DomInfo12 lockout_policy;
+ NTSTATUS result;
+
+ DEBUG(10,("account_lockout_policy_handler called\n"));
+
+ TALLOC_FREE(child->lockout_policy_event);
+
+ if ( !winbindd_can_contact_domain( child->domain ) ) {
+ DEBUG(10,("account_lockout_policy_handler: Removing myself since I "
+ "do not have an incoming trust to domain %s\n",
+ child->domain->name));
+
+ return;
+ }
+
+ methods = child->domain->methods;
+
+ mem_ctx = talloc_init("account_lockout_policy_handler ctx");
+ if (!mem_ctx) {
+ result = NT_STATUS_NO_MEMORY;
+ } else {
+ result = methods->lockout_policy(child->domain, mem_ctx, &lockout_policy);
+ }
+ TALLOC_FREE(mem_ctx);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("account_lockout_policy_handler: lockout_policy failed error %s\n",
+ nt_errstr(result)));
+ }
+
+ child->lockout_policy_event = event_add_timed(winbind_event_context(), NULL,
+ timeval_current_ofs(3600, 0),
+ "account_lockout_policy_handler",
+ account_lockout_policy_handler,
+ child);
+}
+
+static time_t get_machine_password_timeout(void)
+{
+ /* until we have gpo support use lp setting */
+ return lp_machine_password_timeout();
+}
+
+static bool calculate_next_machine_pwd_change(const char *domain,
+ struct timeval *t)
+{
+ time_t pass_last_set_time;
+ time_t timeout;
+ time_t next_change;
+ char *pw;
+
+ pw = secrets_fetch_machine_password(domain,
+ &pass_last_set_time,
+ NULL);
+
+ if (pw == NULL) {
+ DEBUG(0,("cannot fetch own machine password ????"));
+ return false;
+ }
+
+ SAFE_FREE(pw);
+
+ timeout = get_machine_password_timeout();
+ if (timeout == 0) {
+ DEBUG(10,("machine password never expires\n"));
+ return false;
+ }
+
+ if (time(NULL) < (pass_last_set_time + timeout)) {
+ next_change = pass_last_set_time + timeout;
+ DEBUG(10,("machine password still valid until: %s\n",
+ http_timestring(next_change)));
+ *t = timeval_set(next_change, 0);
+ return true;
+ }
+
+ DEBUG(10,("machine password expired, needs immediate change\n"));
+
+ *t = timeval_zero();
+
+ return true;
+}
+
+static void machine_password_change_handler(struct event_context *ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ struct winbindd_child *child =
+ (struct winbindd_child *)private_data;
+ struct rpc_pipe_client *netlogon_pipe = NULL;
+ TALLOC_CTX *frame;
+ NTSTATUS result;
+ struct timeval next_change;
+
+ DEBUG(10,("machine_password_change_handler called\n"));
+
+ TALLOC_FREE(child->machine_password_change_event);
+
+ if (!calculate_next_machine_pwd_change(child->domain->name,
+ &next_change)) {
+ return;
+ }
+
+ if (!winbindd_can_contact_domain(child->domain)) {
+ DEBUG(10,("machine_password_change_handler: Removing myself since I "
+ "do not have an incoming trust to domain %s\n",
+ child->domain->name));
+ return;
+ }
+
+ result = cm_connect_netlogon(child->domain, &netlogon_pipe);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("machine_password_change_handler: "
+ "failed to connect netlogon pipe: %s\n",
+ nt_errstr(result)));
+ return;
+ }
+
+ frame = talloc_stackframe();
+
+ result = trust_pw_find_change_and_store_it(netlogon_pipe,
+ frame,
+ child->domain->name);
+ TALLOC_FREE(frame);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("machine_password_change_handler: "
+ "failed to change machine password: %s\n",
+ nt_errstr(result)));
+ } else {
+ DEBUG(10,("machine_password_change_handler: "
+ "successfully changed machine password\n"));
+ }
+
+ child->machine_password_change_event = event_add_timed(winbind_event_context(), NULL,
+ next_change,
+ "machine_password_change_handler",
+ machine_password_change_handler,
+ child);
+}
+
+/* Deal with a request to go offline. */
+
+static void child_msg_offline(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct winbindd_domain *domain;
+ const char *domainname = (const char *)data->data;
+
+ if (data->data == NULL || data->length == 0) {
+ return;
+ }
+
+ DEBUG(5,("child_msg_offline received for domain %s.\n", domainname));
+
+ if (!lp_winbind_offline_logon()) {
+ DEBUG(10,("child_msg_offline: rejecting offline message.\n"));
+ return;
+ }
+
+ /* Mark the requested domain offline. */
+
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->internal) {
+ continue;
+ }
+ if (strequal(domain->name, domainname)) {
+ DEBUG(5,("child_msg_offline: marking %s offline.\n", domain->name));
+ set_domain_offline(domain);
+ }
+ }
+}
+
+/* Deal with a request to go online. */
+
+static void child_msg_online(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct winbindd_domain *domain;
+ const char *domainname = (const char *)data->data;
+
+ if (data->data == NULL || data->length == 0) {
+ return;
+ }
+
+ DEBUG(5,("child_msg_online received for domain %s.\n", domainname));
+
+ if (!lp_winbind_offline_logon()) {
+ DEBUG(10,("child_msg_online: rejecting online message.\n"));
+ return;
+ }
+
+ /* Set our global state as online. */
+ set_global_winbindd_state_online();
+
+ /* Try and mark everything online - delete any negative cache entries
+ to force a reconnect now. */
+
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->internal) {
+ continue;
+ }
+ if (strequal(domain->name, domainname)) {
+ DEBUG(5,("child_msg_online: requesting %s to go online.\n", domain->name));
+ winbindd_flush_negative_conn_cache(domain);
+ set_domain_online_request(domain);
+ }
+ }
+}
+
+static const char *collect_onlinestatus(TALLOC_CTX *mem_ctx)
+{
+ struct winbindd_domain *domain;
+ char *buf = NULL;
+
+ if ((buf = talloc_asprintf(mem_ctx, "global:%s ",
+ get_global_winbindd_state_offline() ?
+ "Offline":"Online")) == NULL) {
+ return NULL;
+ }
+
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if ((buf = talloc_asprintf_append_buffer(buf, "%s:%s ",
+ domain->name,
+ domain->online ?
+ "Online":"Offline")) == NULL) {
+ return NULL;
+ }
+ }
+
+ buf = talloc_asprintf_append_buffer(buf, "\n");
+
+ DEBUG(5,("collect_onlinestatus: %s", buf));
+
+ return buf;
+}
+
+static void child_msg_onlinestatus(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ TALLOC_CTX *mem_ctx;
+ const char *message;
+ struct server_id *sender;
+
+ DEBUG(5,("winbind_msg_onlinestatus received.\n"));
+
+ if (!data->data) {
+ return;
+ }
+
+ sender = (struct server_id *)data->data;
+
+ mem_ctx = talloc_init("winbind_msg_onlinestatus");
+ if (mem_ctx == NULL) {
+ return;
+ }
+
+ message = collect_onlinestatus(mem_ctx);
+ if (message == NULL) {
+ talloc_destroy(mem_ctx);
+ return;
+ }
+
+ messaging_send_buf(msg_ctx, *sender, MSG_WINBIND_ONLINESTATUS,
+ (uint8 *)message, strlen(message) + 1);
+
+ talloc_destroy(mem_ctx);
+}
+
+static void child_msg_dump_event_list(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ DEBUG(5,("child_msg_dump_event_list received\n"));
+
+ dump_event_list(winbind_event_context());
+}
+
+
+static bool fork_domain_child(struct winbindd_child *child)
+{
+ int fdpair[2];
+ struct winbindd_cli_state state;
+ struct winbindd_domain *domain;
+ struct winbindd_domain *primary_domain = NULL;
+
+ if (child->domain) {
+ DEBUG(10, ("fork_domain_child called for domain '%s'\n",
+ child->domain->name));
+ } else {
+ DEBUG(10, ("fork_domain_child called without domain.\n"));
+ }
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) != 0) {
+ DEBUG(0, ("Could not open child pipe: %s\n",
+ strerror(errno)));
+ return False;
+ }
+
+ ZERO_STRUCT(state);
+ state.pid = sys_getpid();
+
+ child->pid = sys_fork();
+
+ if (child->pid == -1) {
+ DEBUG(0, ("Could not fork: %s\n", strerror(errno)));
+ return False;
+ }
+
+ if (child->pid != 0) {
+ /* Parent */
+ close(fdpair[0]);
+ child->next = child->prev = NULL;
+ DLIST_ADD(children, child);
+ child->event.fd = fdpair[1];
+ child->event.flags = 0;
+ child->requests = NULL;
+ add_fd_event(&child->event);
+ return True;
+ }
+
+ /* Child */
+
+ DEBUG(10, ("Child process %d\n", (int)sys_getpid()));
+
+ /* Stop zombies in children */
+ CatchChild();
+
+ state.sock = fdpair[0];
+ close(fdpair[1]);
+
+ if (!reinit_after_fork(winbind_messaging_context(), true)) {
+ DEBUG(0,("reinit_after_fork() failed\n"));
+ _exit(0);
+ }
+
+ close_conns_after_fork();
+
+ if (!override_logfile) {
+ lp_set_logfile(child->logfilename);
+ reopen_logs();
+ }
+
+ /*
+ * For clustering, we need to re-init our ctdbd connection after the
+ * fork
+ */
+ if (!NT_STATUS_IS_OK(messaging_reinit(winbind_messaging_context())))
+ exit(1);
+
+ /* Don't handle the same messages as our parent. */
+ messaging_deregister(winbind_messaging_context(),
+ MSG_SMB_CONF_UPDATED, NULL);
+ messaging_deregister(winbind_messaging_context(),
+ MSG_SHUTDOWN, NULL);
+ messaging_deregister(winbind_messaging_context(),
+ MSG_WINBIND_OFFLINE, NULL);
+ messaging_deregister(winbind_messaging_context(),
+ MSG_WINBIND_ONLINE, NULL);
+ messaging_deregister(winbind_messaging_context(),
+ MSG_WINBIND_ONLINESTATUS, NULL);
+ messaging_deregister(winbind_messaging_context(),
+ MSG_DUMP_EVENT_LIST, NULL);
+ messaging_deregister(winbind_messaging_context(),
+ MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
+ messaging_deregister(winbind_messaging_context(),
+ MSG_DEBUG, NULL);
+
+ /* Handle online/offline messages. */
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_WINBIND_OFFLINE, child_msg_offline);
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_WINBIND_ONLINE, child_msg_online);
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_WINBIND_ONLINESTATUS, child_msg_onlinestatus);
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_DUMP_EVENT_LIST, child_msg_dump_event_list);
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_DEBUG, debug_message);
+
+ if ( child->domain ) {
+ child->domain->startup = True;
+ child->domain->startup_time = time(NULL);
+ }
+
+ /* Ensure we have no pending check_online events other
+ than one for this domain or the primary domain. */
+
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->primary) {
+ primary_domain = domain;
+ }
+ if ((domain != child->domain) && !domain->primary) {
+ TALLOC_FREE(domain->check_online_event);
+ }
+ }
+
+ if (primary_domain == NULL) {
+ smb_panic("no primary domain found");
+ }
+
+ /* Ensure we're not handling an event inherited from
+ our parent. */
+
+ cancel_named_event(winbind_event_context(),
+ "krb5_ticket_refresh_handler");
+
+ /* We might be in the idmap child...*/
+ if (child->domain && !(child->domain->internal) &&
+ lp_winbind_offline_logon()) {
+
+ set_domain_online_request(child->domain);
+
+ if (primary_domain != child->domain) {
+ /* We need to talk to the primary
+ * domain as well as the trusted
+ * domain inside a trusted domain
+ * child.
+ * See the code in :
+ * set_dc_type_and_flags_trustinfo()
+ * for details.
+ */
+ set_domain_online_request(primary_domain);
+ }
+
+ child->lockout_policy_event = event_add_timed(
+ winbind_event_context(), NULL, timeval_zero(),
+ "account_lockout_policy_handler",
+ account_lockout_policy_handler,
+ child);
+ }
+
+ if (child->domain && child->domain->primary &&
+ lp_server_role() == ROLE_DOMAIN_MEMBER) {
+
+ struct timeval next_change;
+
+ if (calculate_next_machine_pwd_change(child->domain->name,
+ &next_change)) {
+ child->machine_password_change_event = event_add_timed(
+ winbind_event_context(), NULL, next_change,
+ "machine_password_change_handler",
+ machine_password_change_handler,
+ child);
+ }
+ }
+
+ while (1) {
+
+ int ret;
+ fd_set read_fds;
+ struct timeval t;
+ struct timeval *tp;
+ struct timeval now;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ /* check for signals */
+ winbind_check_sigterm(false);
+ winbind_check_sighup(override_logfile ? NULL :
+ child->logfilename);
+
+ run_events(winbind_event_context(), 0, NULL, NULL);
+
+ GetTimeOfDay(&now);
+
+ if (child->domain && child->domain->startup &&
+ (now.tv_sec > child->domain->startup_time + 30)) {
+ /* No longer in "startup" mode. */
+ DEBUG(10,("fork_domain_child: domain %s no longer in 'startup' mode.\n",
+ child->domain->name ));
+ child->domain->startup = False;
+ }
+
+ tp = get_timed_events_timeout(winbind_event_context(), &t);
+ if (tp) {
+ DEBUG(11,("select will use timeout of %u.%u seconds\n",
+ (unsigned int)tp->tv_sec, (unsigned int)tp->tv_usec ));
+ }
+
+ /* Handle messages */
+
+ message_dispatch(winbind_messaging_context());
+
+ FD_ZERO(&read_fds);
+ FD_SET(state.sock, &read_fds);
+
+ ret = sys_select(state.sock + 1, &read_fds, NULL, NULL, tp);
+
+ if (ret == 0) {
+ DEBUG(11,("nothing is ready yet, continue\n"));
+ TALLOC_FREE(frame);
+ continue;
+ }
+
+ if (ret == -1 && errno == EINTR) {
+ /* We got a signal - continue. */
+ TALLOC_FREE(frame);
+ continue;
+ }
+
+ if (ret == -1 && errno != EINTR) {
+ DEBUG(0,("select error occured\n"));
+ TALLOC_FREE(frame);
+ perror("select");
+ return False;
+ }
+
+ /* fetch a request from the main daemon */
+ child_read_request(&state);
+
+ if (state.finished) {
+ /* we lost contact with our parent */
+ exit(0);
+ }
+
+ DEBUG(4,("child daemon request %d\n", (int)state.request.cmd));
+
+ ZERO_STRUCT(state.response);
+ state.request.null_term = '\0';
+ child_process_request(child, &state);
+
+ SAFE_FREE(state.request.extra_data.data);
+
+ cache_store_response(sys_getpid(), &state.response);
+
+ SAFE_FREE(state.response.extra_data.data);
+
+ /* We just send the result code back, the result
+ * structure needs to be fetched via the
+ * winbindd_cache. Hmm. That needs fixing... */
+
+ if (write_data(state.sock,
+ (const char *)&state.response.result,
+ sizeof(state.response.result)) !=
+ sizeof(state.response.result)) {
+ DEBUG(0, ("Could not write result\n"));
+ exit(1);
+ }
+ TALLOC_FREE(frame);
+ }
+}
diff --git a/source3/winbindd/winbindd_group.c b/source3/winbindd/winbindd_group.c
new file mode 100644
index 0000000000..4d5026d158
--- /dev/null
+++ b/source3/winbindd/winbindd_group.c
@@ -0,0 +1,1728 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon for ntdom nss module
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Jeremy Allison 2001.
+ Copyright (C) Gerald (Jerry) Carter 2003.
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+extern bool opt_nocache;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+static void add_member(const char *domain, const char *user,
+ char **pp_members, size_t *p_num_members)
+{
+ fstring name;
+
+ fill_domain_username(name, domain, user, True);
+ safe_strcat(name, ",", sizeof(name)-1);
+ string_append(pp_members, name);
+ *p_num_members += 1;
+}
+
+/**********************************************************************
+ Add member users resulting from sid. Expand if it is a domain group.
+**********************************************************************/
+
+static void add_expanded_sid(const DOM_SID *sid,
+ char **pp_members,
+ size_t *p_num_members)
+{
+ DOM_SID dom_sid;
+ uint32 rid;
+ struct winbindd_domain *domain;
+ size_t i;
+
+ char *domain_name = NULL;
+ char *name = NULL;
+ enum lsa_SidType type;
+
+ uint32 num_names;
+ DOM_SID *sid_mem;
+ char **names;
+ uint32 *types;
+
+ NTSTATUS result;
+
+ TALLOC_CTX *mem_ctx = talloc_init("add_expanded_sid");
+
+ if (mem_ctx == NULL) {
+ DEBUG(1, ("talloc_init failed\n"));
+ return;
+ }
+
+ sid_copy(&dom_sid, sid);
+ sid_split_rid(&dom_sid, &rid);
+
+ domain = find_lookup_domain_from_sid(sid);
+
+ if (domain == NULL) {
+ DEBUG(3, ("Could not find domain for sid %s\n",
+ sid_string_dbg(sid)));
+ goto done;
+ }
+
+ result = domain->methods->sid_to_name(domain, mem_ctx, sid,
+ &domain_name, &name, &type);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3, ("sid_to_name failed for sid %s\n",
+ sid_string_dbg(sid)));
+ goto done;
+ }
+
+ DEBUG(10, ("Found name %s, type %d\n", name, type));
+
+ if (type == SID_NAME_USER) {
+ add_member(domain_name, name, pp_members, p_num_members);
+ goto done;
+ }
+
+ if (type != SID_NAME_DOM_GRP) {
+ DEBUG(10, ("Alias member %s neither user nor group, ignore\n",
+ name));
+ goto done;
+ }
+
+ /* Expand the domain group, this must be done via the target domain */
+
+ domain = find_domain_from_sid(sid);
+
+ if (domain == NULL) {
+ DEBUG(3, ("Could not find domain from SID %s\n",
+ sid_string_dbg(sid)));
+ goto done;
+ }
+
+ result = domain->methods->lookup_groupmem(domain, mem_ctx,
+ sid, &num_names,
+ &sid_mem, &names,
+ &types);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10, ("Could not lookup group members for %s: %s\n",
+ name, nt_errstr(result)));
+ goto done;
+ }
+
+ for (i=0; i<num_names; i++) {
+ DEBUG(10, ("Adding group member SID %s\n",
+ sid_string_dbg(&sid_mem[i])));
+
+ if (types[i] != SID_NAME_USER) {
+ DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
+ "Ignoring.\n", names[i], name));
+ continue;
+ }
+
+ add_member(domain->name, names[i], pp_members, p_num_members);
+ }
+
+ done:
+ talloc_destroy(mem_ctx);
+ return;
+}
+
+static bool fill_passdb_alias_grmem(struct winbindd_domain *domain,
+ DOM_SID *group_sid, size_t *num_gr_mem,
+ char **gr_mem, size_t *gr_mem_len)
+{
+ DOM_SID *members;
+ size_t i, num_members;
+
+ *num_gr_mem = 0;
+ *gr_mem = NULL;
+ *gr_mem_len = 0;
+
+ if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(group_sid, &members,
+ &num_members)))
+ return True;
+
+ for (i=0; i<num_members; i++) {
+ add_expanded_sid(&members[i], gr_mem, num_gr_mem);
+ }
+
+ TALLOC_FREE(members);
+
+ if (*gr_mem != NULL) {
+ size_t len;
+
+ /* We have at least one member, strip off the last "," */
+ len = strlen(*gr_mem);
+ (*gr_mem)[len-1] = '\0';
+ *gr_mem_len = len;
+ }
+
+ return True;
+}
+
+/* Fill a grent structure from various other information */
+
+static bool fill_grent(struct winbindd_gr *gr, const char *dom_name,
+ const char *gr_name, gid_t unix_gid)
+{
+ fstring full_group_name;
+
+ fill_domain_username( full_group_name, dom_name, gr_name, True );
+
+ gr->gr_gid = unix_gid;
+
+ /* Group name and password */
+
+ safe_strcpy(gr->gr_name, full_group_name, sizeof(gr->gr_name) - 1);
+ safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
+
+ return True;
+}
+
+/***********************************************************************
+ If "enum users" is set to false, and the group being looked
+ up is the Domain Users SID: S-1-5-domain-513, then for the
+ list of members check if the querying user is in that group,
+ and if so only return that user as the gr_mem array.
+ We can change this to a different parameter than "enum users"
+ if neccessaey, or parameterize the group list we do this for.
+***********************************************************************/
+
+static bool fill_grent_mem_domusers( TALLOC_CTX *mem_ctx,
+ struct winbindd_domain *domain,
+ struct winbindd_cli_state *state,
+ DOM_SID *group_sid,
+ enum lsa_SidType group_name_type,
+ size_t *num_gr_mem, char **gr_mem,
+ size_t *gr_mem_len)
+{
+ DOM_SID querying_user_sid;
+ DOM_SID *pquerying_user_sid = NULL;
+ uint32 num_groups = 0;
+ DOM_SID *user_sids = NULL;
+ bool u_in_group = False;
+ NTSTATUS status;
+ int i;
+ unsigned int buf_len = 0;
+ char *buf = NULL;
+
+ DEBUG(10,("fill_grent_mem_domain_users: domain %s\n",
+ domain->name ));
+
+ if (state) {
+ uid_t ret_uid = (uid_t)-1;
+ if (sys_getpeereid(state->sock, &ret_uid)==0) {
+ /* We know who's asking - look up their SID if
+ it's one we've mapped before. */
+ status = idmap_uid_to_sid(domain->name,
+ &querying_user_sid, ret_uid);
+ if (NT_STATUS_IS_OK(status)) {
+ pquerying_user_sid = &querying_user_sid;
+ DEBUG(10,("fill_grent_mem_domain_users: "
+ "querying uid %u -> %s\n",
+ (unsigned int)ret_uid,
+ sid_string_dbg(pquerying_user_sid)));
+ }
+ }
+ }
+
+ /* Only look up if it was a winbindd user in this domain. */
+ if (pquerying_user_sid &&
+ (sid_compare_domain(pquerying_user_sid, &domain->sid) == 0)) {
+
+ DEBUG(10,("fill_grent_mem_domain_users: querying user = %s\n",
+ sid_string_dbg(pquerying_user_sid) ));
+
+ status = domain->methods->lookup_usergroups(domain,
+ mem_ctx,
+ pquerying_user_sid,
+ &num_groups,
+ &user_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("fill_grent_mem_domain_users: "
+ "lookup_usergroups failed "
+ "for sid %s in domain %s (error: %s)\n",
+ sid_string_dbg(pquerying_user_sid),
+ domain->name,
+ nt_errstr(status)));
+ return False;
+ }
+
+ for (i = 0; i < num_groups; i++) {
+ if (sid_equal(group_sid, &user_sids[i])) {
+ /* User is in Domain Users, add their name
+ as the only group member. */
+ u_in_group = True;
+ break;
+ }
+ }
+ }
+
+ if (u_in_group) {
+ size_t len = 0;
+ char *domainname = NULL;
+ char *username = NULL;
+ fstring name;
+ enum lsa_SidType type;
+
+ DEBUG(10,("fill_grent_mem_domain_users: "
+ "sid %s in 'Domain Users' in domain %s\n",
+ sid_string_dbg(pquerying_user_sid),
+ domain->name ));
+
+ status = domain->methods->sid_to_name(domain, mem_ctx,
+ pquerying_user_sid,
+ &domainname,
+ &username,
+ &type);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("could not lookup username for user "
+ "sid %s in domain %s (error: %s)\n",
+ sid_string_dbg(pquerying_user_sid),
+ domain->name,
+ nt_errstr(status)));
+ return False;
+ }
+ fill_domain_username(name, domain->name, username, True);
+ len = strlen(name);
+ buf_len = len + 1;
+ if (!(buf = (char *)SMB_MALLOC(buf_len))) {
+ DEBUG(1, ("out of memory\n"));
+ return False;
+ }
+ memcpy(buf, name, buf_len);
+
+ DEBUG(10,("fill_grent_mem_domain_users: user %s in "
+ "'Domain Users' in domain %s\n",
+ name, domain->name ));
+
+ /* user is the only member */
+ *num_gr_mem = 1;
+ }
+
+ *gr_mem = buf;
+ *gr_mem_len = buf_len;
+
+ DEBUG(10, ("fill_grent_mem_domain_users: "
+ "num_mem = %u, len = %u, mem = %s\n",
+ (unsigned int)*num_gr_mem,
+ (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
+
+ return True;
+}
+
+/***********************************************************************
+ Add names to a list. Assumes a canonical version of the string
+ in DOMAIN\user
+***********************************************************************/
+
+static int namecmp( const void *a, const void *b )
+{
+ return StrCaseCmp( * (char * const *) a, * (char * const *) b);
+}
+
+static NTSTATUS add_names_to_list( TALLOC_CTX *ctx,
+ char ***list, uint32 *n_list,
+ char **names, uint32 n_names )
+{
+ char **new_list = NULL;
+ uint32 n_new_list = 0;
+ int i, j;
+
+ if ( !names || (n_names == 0) )
+ return NT_STATUS_OK;
+
+ /* Alloc the maximum size we'll need */
+
+ if ( *list == NULL ) {
+ if ((new_list = TALLOC_ARRAY(ctx, char *, n_names)) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ n_new_list = n_names;
+ } else {
+ new_list = TALLOC_REALLOC_ARRAY( ctx, *list, char *,
+ (*n_list) + n_names );
+ if ( !new_list )
+ return NT_STATUS_NO_MEMORY;
+ n_new_list = (*n_list) + n_names;
+ }
+
+ /* Add all names */
+
+ for ( i=*n_list, j=0; i<n_new_list; i++, j++ ) {
+ new_list[i] = talloc_strdup( new_list, names[j] );
+ }
+
+ /* search for duplicates for sorting and looking for matching
+ neighbors */
+
+ qsort( new_list, n_new_list, sizeof(char*), QSORT_CAST namecmp );
+
+ for ( i=1; i<n_new_list; i++ ) {
+ if ( strcmp( new_list[i-1], new_list[i] ) == 0 ) {
+ memmove( &new_list[i-1], &new_list[i],
+ sizeof(char*)*(n_new_list-i) );
+ n_new_list--;
+ }
+ }
+
+ *list = new_list;
+ *n_list = n_new_list;
+
+ return NT_STATUS_OK;
+}
+
+/***********************************************************************
+***********************************************************************/
+
+static NTSTATUS expand_groups( TALLOC_CTX *ctx,
+ struct winbindd_domain *d,
+ DOM_SID *glist, uint32 n_glist,
+ DOM_SID **new_glist, uint32 *n_new_glist,
+ char ***members, uint32 *n_members )
+{
+ int i, j;
+ NTSTATUS status = NT_STATUS_OK;
+ uint32 num_names = 0;
+ uint32 *name_types = NULL;
+ char **names = NULL;
+ DOM_SID *sid_mem = NULL;
+ TALLOC_CTX *tmp_ctx = NULL;
+ DOM_SID *new_groups = NULL;
+ size_t new_groups_size = 0;
+
+ *members = NULL;
+ *n_members = 0;
+ *new_glist = NULL;
+ *n_new_glist = 0;
+
+ for ( i=0; i<n_glist; i++ ) {
+ tmp_ctx = talloc_new( ctx );
+
+ /* Lookup the group membership */
+
+ status = d->methods->lookup_groupmem(d, tmp_ctx,
+ &glist[i], &num_names,
+ &sid_mem, &names,
+ &name_types);
+ if ( !NT_STATUS_IS_OK(status) )
+ goto out;
+
+ /* Separate users and groups into two lists */
+
+ for ( j=0; j<num_names; j++ ) {
+
+ /* Users */
+ if ( name_types[j] == SID_NAME_USER ||
+ name_types[j] == SID_NAME_COMPUTER )
+ {
+ status = add_names_to_list( ctx, members,
+ n_members,
+ names+j, 1 );
+ if ( !NT_STATUS_IS_OK(status) )
+ goto out;
+
+ continue;
+ }
+
+ /* Groups */
+ if ( name_types[j] == SID_NAME_DOM_GRP ||
+ name_types[j] == SID_NAME_ALIAS )
+ {
+ status = add_sid_to_array_unique(ctx,
+ &sid_mem[j],
+ &new_groups,
+ &new_groups_size);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ continue;
+ }
+ }
+
+ TALLOC_FREE( tmp_ctx );
+ }
+
+ *new_glist = new_groups;
+ *n_new_glist = (uint32)new_groups_size;
+
+ out:
+ TALLOC_FREE( tmp_ctx );
+
+ return status;
+}
+
+/***********************************************************************
+ Fill in the group membership field of a NT group given by group_sid
+***********************************************************************/
+
+static bool fill_grent_mem(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state,
+ DOM_SID *group_sid,
+ enum lsa_SidType group_name_type,
+ size_t *num_gr_mem, char **gr_mem,
+ size_t *gr_mem_len)
+{
+ uint32 num_names = 0;
+ unsigned int buf_len = 0, buf_ndx = 0, i;
+ char **names = NULL, *buf = NULL;
+ bool result = False;
+ TALLOC_CTX *mem_ctx;
+ uint32 group_rid;
+ DOM_SID *glist = NULL;
+ DOM_SID *new_glist = NULL;
+ uint32 n_glist, n_new_glist;
+ int max_depth = lp_winbind_expand_groups();
+
+ if (!(mem_ctx = talloc_init("fill_grent_mem(%s)", domain->name)))
+ return False;
+
+ DEBUG(10, ("group SID %s\n", sid_string_dbg(group_sid)));
+
+ /* Initialize with no members */
+
+ *num_gr_mem = 0;
+
+ /* HACK ALERT!! This whole routine does not cope with group members
+ * from more than one domain, ie aliases. Thus we have to work it out
+ * ourselves in a special routine. */
+
+ if (domain->internal) {
+ result = fill_passdb_alias_grmem(domain, group_sid,
+ num_gr_mem,
+ gr_mem, gr_mem_len);
+ goto done;
+ }
+
+ /* Verify name type */
+
+ if ( !((group_name_type==SID_NAME_DOM_GRP) ||
+ ((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
+ {
+ DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n",
+ sid_string_dbg(group_sid),
+ domain->name, group_name_type));
+ goto done;
+ }
+
+ /* OPTIMIZATION / HACK. See comment in
+ fill_grent_mem_domusers() */
+
+ sid_peek_rid( group_sid, &group_rid );
+ if (!lp_winbind_enum_users() && group_rid == DOMAIN_GROUP_RID_USERS) {
+ result = fill_grent_mem_domusers( mem_ctx, domain, state,
+ group_sid, group_name_type,
+ num_gr_mem, gr_mem,
+ gr_mem_len );
+ goto done;
+ }
+
+ /* Real work goes here. Create a list of group names to
+ expand startign with the initial one. Pass that to
+ expand_groups() which returns a list of more group names
+ to expand. Do this up to the max search depth. */
+
+ if ( (glist = TALLOC_ARRAY(mem_ctx, DOM_SID, 1 )) == NULL ) {
+ result = False;
+ DEBUG(0,("fill_grent_mem: talloc failure!\n"));
+ goto done;
+ }
+ sid_copy( &glist[0], group_sid );
+ n_glist = 1;
+
+ for ( i=0; i<max_depth && glist; i++ ) {
+ uint32 n_members = 0;
+ char **members = NULL;
+ NTSTATUS nt_status;
+
+ nt_status = expand_groups( mem_ctx, domain,
+ glist, n_glist,
+ &new_glist, &n_new_glist,
+ &members, &n_members);
+ if ( !NT_STATUS_IS_OK(nt_status) ) {
+ result = False;
+ goto done;
+ }
+
+ /* Add new group members to list */
+
+ nt_status = add_names_to_list( mem_ctx, &names, &num_names,
+ members, n_members );
+ if ( !NT_STATUS_IS_OK(nt_status) ) {
+ result = False;
+ goto done;
+ }
+
+ TALLOC_FREE( members );
+
+ /* If we have no more groups to expand, break out
+ early */
+
+ if (new_glist == NULL)
+ break;
+
+ /* One more round */
+ TALLOC_FREE(glist);
+ glist = new_glist;
+ n_glist = n_new_glist;
+ }
+ TALLOC_FREE( glist );
+
+ DEBUG(10, ("looked up %d names\n", num_names));
+
+ again:
+ /* Add members to list */
+
+ for (i = 0; i < num_names; i++) {
+ int len;
+
+ DEBUG(10, ("processing name %s\n", names[i]));
+
+ len = strlen(names[i]);
+
+ /* Add to list or calculate buffer length */
+
+ if (!buf) {
+ buf_len += len + 1; /* List is comma separated */
+ (*num_gr_mem)++;
+ DEBUG(10, ("buf_len + %d = %d\n", len + 1, buf_len));
+ } else {
+ DEBUG(10, ("appending %s at ndx %d\n",
+ names[i], buf_ndx));
+ parse_add_domuser(&buf[buf_ndx], names[i], &len);
+ buf_ndx += len;
+ buf[buf_ndx] = ',';
+ buf_ndx++;
+ }
+ }
+
+ /* Allocate buffer */
+
+ if (!buf && buf_len != 0) {
+ if (!(buf = (char *)SMB_MALLOC(buf_len))) {
+ DEBUG(1, ("out of memory\n"));
+ result = False;
+ goto done;
+ }
+ memset(buf, 0, buf_len);
+ goto again;
+ }
+
+ /* Now we're done */
+
+ if (buf && buf_ndx > 0) {
+ buf[buf_ndx - 1] = '\0';
+ }
+
+ *gr_mem = buf;
+ *gr_mem_len = buf_len;
+
+ DEBUG(10, ("num_mem = %u, len = %u, mem = %s\n",
+ (unsigned int)*num_gr_mem,
+ (unsigned int)buf_len, *num_gr_mem ? buf : "NULL"));
+ result = True;
+
+done:
+
+ talloc_destroy(mem_ctx);
+
+ DEBUG(10, ("fill_grent_mem returning %d\n", result));
+
+ return result;
+}
+
+static void winbindd_getgrsid(struct winbindd_cli_state *state, DOM_SID group_sid);
+
+static void getgrnam_recv( void *private_data, bool success, const DOM_SID *sid,
+ enum lsa_SidType type )
+{
+ struct winbindd_cli_state *state = (struct winbindd_cli_state*)private_data;
+
+ if (!success) {
+ DEBUG(5,("getgrnam_recv: lookupname failed!\n"));
+ request_error(state);
+ return;
+ }
+
+ if ( (type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) ) {
+ DEBUG(5,("getgrnam_recv: not a group!\n"));
+ request_error(state);
+ return;
+ }
+
+ winbindd_getgrsid( state, *sid );
+}
+
+
+/* Return a group structure from a group name */
+
+void winbindd_getgrnam(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+ fstring name_domain, name_group;
+ char *tmp;
+
+ /* Ensure null termination */
+ state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
+
+ DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid,
+ state->request.data.groupname));
+
+ /* Parse domain and groupname */
+
+ memset(name_group, 0, sizeof(fstring));
+
+ tmp = state->request.data.groupname;
+
+ name_domain[0] = '\0';
+ name_group[0] = '\0';
+
+ parse_domain_user(tmp, name_domain, name_group);
+
+ /* if no domain or our local domain and no local tdb group, default to
+ * our local domain for aliases */
+
+ if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
+ fstrcpy(name_domain, get_global_sam_name());
+ }
+
+ /* Get info for the domain */
+
+ if ((domain = find_domain_from_name(name_domain)) == NULL) {
+ DEBUG(3, ("could not get domain sid for domain %s\n",
+ name_domain));
+ request_error(state);
+ return;
+ }
+ /* should we deal with users for our domain? */
+
+ if ( lp_winbind_trusted_domains_only() && domain->primary) {
+ DEBUG(7,("winbindd_getgrnam: My domain -- rejecting "
+ "getgrnam() for %s\\%s.\n", name_domain, name_group));
+ request_error(state);
+ return;
+ }
+
+ /* Get rid and name type from name */
+
+ ws_name_replace( name_group, WB_REPLACE_CHAR );
+
+ winbindd_lookupname_async( state->mem_ctx, domain->name, name_group,
+ getgrnam_recv, WINBINDD_GETGRNAM, state );
+}
+
+struct getgrsid_state {
+ struct winbindd_cli_state *state;
+ struct winbindd_domain *domain;
+ char *group_name;
+ enum lsa_SidType group_type;
+ uid_t gid;
+ DOM_SID group_sid;
+};
+
+static void getgrsid_sid2gid_recv(void *private_data, bool success, gid_t gid)
+ {
+ struct getgrsid_state *s =
+ (struct getgrsid_state *)private_data;
+ struct winbindd_domain *domain;
+ size_t gr_mem_len;
+ size_t num_gr_mem;
+ char *gr_mem;
+ fstring dom_name, group_name;
+
+ if (!success) {
+ DEBUG(5,("getgrsid_sid2gid_recv: sid2gid failed!\n"));
+ request_error(s->state);
+ return;
+ }
+
+ s->gid = gid;
+
+ if ( !parse_domain_user( s->group_name, dom_name, group_name ) ) {
+ DEBUG(5,("getgrsid_sid2gid_recv: parse_domain_user() failed!\n"));
+ request_error(s->state);
+ return;
+ }
+
+
+ /* Fill in group structure */
+
+ if ( (domain = find_domain_from_name_noinit(dom_name)) == NULL ) {
+ DEBUG(1,("Can't find domain from name (%s)\n", dom_name));
+ request_error(s->state);
+ return;
+ }
+
+ if (!fill_grent(&s->state->response.data.gr, dom_name, group_name, gid) ||
+ !fill_grent_mem(domain, s->state, &s->group_sid, s->group_type,
+ &num_gr_mem, &gr_mem, &gr_mem_len))
+ {
+ request_error(s->state);
+ return;
+ }
+
+ s->state->response.data.gr.num_gr_mem = (uint32)num_gr_mem;
+
+ /* Group membership lives at start of extra data */
+
+ s->state->response.data.gr.gr_mem_ofs = 0;
+
+ s->state->response.length += gr_mem_len;
+ s->state->response.extra_data.data = gr_mem;
+
+ request_ok(s->state);
+ }
+
+static void getgrsid_lookupsid_recv( void *private_data, bool success,
+ const char *dom_name, const char *name,
+ enum lsa_SidType name_type )
+{
+ struct getgrsid_state *s = (struct getgrsid_state *)private_data;
+
+ if (!success) {
+ DEBUG(5,("getgrsid_lookupsid_recv: lookupsid failed!\n"));
+ request_error(s->state);
+ return;
+ }
+
+ /* either it's a domain group, a domain local group, or a
+ local group in an internal domain */
+
+ if ( !( (name_type==SID_NAME_DOM_GRP) ||
+ ((name_type==SID_NAME_ALIAS) &&
+ (s->domain->primary || s->domain->internal)) ) )
+ {
+ DEBUG(1, ("name '%s\\%s' is not a local or domain group: %d\n",
+ dom_name, name, name_type));
+ request_error(s->state);
+ return;
+}
+
+ if ( (s->group_name = talloc_asprintf( s->state->mem_ctx,
+ "%s%c%s",
+ dom_name,
+ *lp_winbind_separator(),
+ name)) == NULL )
+{
+ DEBUG(1, ("getgrsid_lookupsid_recv: talloc_asprintf() Failed!\n"));
+ request_error(s->state);
+ return;
+ }
+
+ s->group_type = name_type;
+
+ winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
+ getgrsid_sid2gid_recv, s);
+ }
+
+static void winbindd_getgrsid( struct winbindd_cli_state *state, const DOM_SID group_sid )
+ {
+ struct getgrsid_state *s;
+
+ if ( (s = TALLOC_ZERO_P(state->mem_ctx, struct getgrsid_state)) == NULL ) {
+ DEBUG(0, ("talloc failed\n"));
+ request_error(state);
+ return;
+ }
+
+ s->state = state;
+
+ if ( (s->domain = find_domain_from_sid_noinit(&group_sid)) == NULL ) {
+ DEBUG(3, ("Could not find domain for sid %s\n",
+ sid_string_dbg(&group_sid)));
+ request_error(state);
+ return;
+ }
+
+ sid_copy(&s->group_sid, &group_sid);
+
+ winbindd_lookupsid_async( s->state->mem_ctx, &group_sid,
+ getgrsid_lookupsid_recv, s );
+}
+
+
+static void getgrgid_recv(void *private_data, bool success, const char *sid)
+{
+ struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state);
+ enum lsa_SidType name_type;
+ DOM_SID group_sid;
+
+ if (success) {
+ DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n",
+ (unsigned long)(state->request.data.gid), sid));
+
+ string_to_sid(&group_sid, sid);
+ winbindd_getgrsid(state, group_sid);
+ return;
+ }
+
+ /* Ok, this might be "ours", i.e. an alias */
+ if (pdb_gid_to_sid(state->request.data.gid, &group_sid) &&
+ lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) &&
+ (name_type == SID_NAME_ALIAS)) {
+ /* Hey, got an alias */
+ DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n",
+ (unsigned long)(state->request.data.gid), sid));
+ winbindd_getgrsid(state, group_sid);
+ return;
+ }
+
+ DEBUG(1, ("could not convert gid %lu to sid\n",
+ (unsigned long)state->request.data.gid));
+ request_error(state);
+}
+
+/* Return a group structure from a gid number */
+void winbindd_getgrgid(struct winbindd_cli_state *state)
+{
+ gid_t gid = state->request.data.gid;
+
+ DEBUG(3, ("[%5lu]: getgrgid %lu\n",
+ (unsigned long)state->pid,
+ (unsigned long)gid));
+
+ /* always use the async interface */
+ winbindd_gid2sid_async(state->mem_ctx, gid, getgrgid_recv, state);
+}
+
+/*
+ * set/get/endgrent functions
+ */
+
+/* "Rewind" file pointer for group database enumeration */
+
+static bool winbindd_setgrent_internal(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+
+ DEBUG(3, ("[%5lu]: setgrent\n", (unsigned long)state->pid));
+
+ /* Check user has enabled this */
+
+ if (!lp_winbind_enum_groups()) {
+ return False;
+ }
+
+ /* Free old static data if it exists */
+
+ if (state->getgrent_state != NULL) {
+ free_getent_state(state->getgrent_state);
+ state->getgrent_state = NULL;
+ }
+
+ /* Create sam pipes for each domain we know about */
+
+ for (domain = domain_list(); domain != NULL; domain = domain->next) {
+ struct getent_state *domain_state;
+
+ /* Create a state record for this domain */
+
+ /* don't add our domaina if we are a PDC or if we
+ are a member of a Samba domain */
+
+ if ( lp_winbind_trusted_domains_only() && domain->primary )
+ {
+ continue;
+ }
+
+ domain_state = SMB_MALLOC_P(struct getent_state);
+ if (!domain_state) {
+ DEBUG(1, ("winbindd_setgrent: "
+ "malloc failed for domain_state!\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(domain_state);
+
+ fstrcpy(domain_state->domain_name, domain->name);
+
+ /* Add to list of open domains */
+
+ DLIST_ADD(state->getgrent_state, domain_state);
+ }
+
+ state->getgrent_initialized = True;
+ return True;
+}
+
+void winbindd_setgrent(struct winbindd_cli_state *state)
+{
+ if (winbindd_setgrent_internal(state)) {
+ request_ok(state);
+ } else {
+ request_error(state);
+ }
+}
+
+/* Close file pointer to ntdom group database */
+
+void winbindd_endgrent(struct winbindd_cli_state *state)
+{
+ DEBUG(3, ("[%5lu]: endgrent\n", (unsigned long)state->pid));
+
+ free_getent_state(state->getgrent_state);
+ state->getgrent_initialized = False;
+ state->getgrent_state = NULL;
+ request_ok(state);
+}
+
+/* Get the list of domain groups and domain aliases for a domain. We fill in
+ the sam_entries and num_sam_entries fields with domain group information.
+ Return True if some groups were returned, False otherwise. */
+
+bool get_sam_group_entries(struct getent_state *ent)
+{
+ NTSTATUS status;
+ uint32 num_entries;
+ struct acct_info *name_list = NULL;
+ TALLOC_CTX *mem_ctx;
+ bool result = False;
+ struct acct_info *sam_grp_entries = NULL;
+ struct winbindd_domain *domain;
+
+ if (ent->got_sam_entries)
+ return False;
+
+ if (!(mem_ctx = talloc_init("get_sam_group_entries(%s)",
+ ent->domain_name))) {
+ DEBUG(1, ("get_sam_group_entries: "
+ "could not create talloc context!\n"));
+ return False;
+ }
+
+ /* Free any existing group info */
+
+ SAFE_FREE(ent->sam_entries);
+ ent->num_sam_entries = 0;
+ ent->got_sam_entries = True;
+
+ /* Enumerate domain groups */
+
+ num_entries = 0;
+
+ if (!(domain = find_domain_from_name(ent->domain_name))) {
+ DEBUG(3, ("no such domain %s in get_sam_group_entries\n",
+ ent->domain_name));
+ goto done;
+ }
+
+ /* always get the domain global groups */
+
+ status = domain->methods->enum_dom_groups(domain, mem_ctx, &num_entries,
+ &sam_grp_entries);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("get_sam_group_entries: "
+ "could not enumerate domain groups! Error: %s\n",
+ nt_errstr(status)));
+ result = False;
+ goto done;
+ }
+
+ /* Copy entries into return buffer */
+
+ if (num_entries) {
+ name_list = SMB_MALLOC_ARRAY(struct acct_info, num_entries);
+ if (!name_list) {
+ DEBUG(0,("get_sam_group_entries: Failed to malloc "
+ "memory for %d domain groups!\n",
+ num_entries));
+ result = False;
+ goto done;
+ }
+ memcpy(name_list, sam_grp_entries,
+ num_entries * sizeof(struct acct_info));
+ }
+
+ ent->num_sam_entries = num_entries;
+
+ /* get the domain local groups if we are a member of a native win2k
+ * domain and are not using LDAP to get the groups */
+
+ if ( ( lp_security() != SEC_ADS && domain->native_mode
+ && domain->primary) || domain->internal )
+ {
+ DEBUG(4,("get_sam_group_entries: %s domain; "
+ "enumerating local groups as well\n",
+ domain->native_mode ? "Native Mode 2k":
+ "BUILTIN or local"));
+
+ status = domain->methods->enum_local_groups(domain, mem_ctx,
+ &num_entries,
+ &sam_grp_entries);
+
+ if ( !NT_STATUS_IS_OK(status) ) {
+ DEBUG(3,("get_sam_group_entries: "
+ "Failed to enumerate "
+ "domain local groups with error %s!\n",
+ nt_errstr(status)));
+ num_entries = 0;
+ }
+ else
+ DEBUG(4,("get_sam_group_entries: "
+ "Returned %d local groups\n",
+ num_entries));
+
+ /* Copy entries into return buffer */
+
+ if ( num_entries ) {
+ name_list = SMB_REALLOC_ARRAY(name_list,
+ struct acct_info,
+ ent->num_sam_entries+
+ num_entries);
+ if (!name_list) {
+ DEBUG(0,("get_sam_group_entries: "
+ "Failed to realloc more memory "
+ "for %d local groups!\n",
+ num_entries));
+ result = False;
+ goto done;
+ }
+
+ memcpy(&name_list[ent->num_sam_entries],
+ sam_grp_entries,
+ num_entries * sizeof(struct acct_info));
+ }
+
+ ent->num_sam_entries += num_entries;
+ }
+
+
+ /* Fill in remaining fields */
+
+ ent->sam_entries = name_list;
+ ent->sam_entry_index = 0;
+
+ result = (ent->num_sam_entries > 0);
+
+ done:
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
+
+/* Fetch next group entry from ntdom database */
+
+#define MAX_GETGRENT_GROUPS 500
+
+void winbindd_getgrent(struct winbindd_cli_state *state)
+{
+ struct getent_state *ent;
+ struct winbindd_gr *group_list = NULL;
+ int num_groups, group_list_ndx, gr_mem_list_len = 0;
+ char *gr_mem_list = NULL;
+
+ DEBUG(3, ("[%5lu]: getgrent\n", (unsigned long)state->pid));
+
+ /* Check user has enabled this */
+
+ if (!lp_winbind_enum_groups()) {
+ request_error(state);
+ return;
+ }
+
+ num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
+
+ if (num_groups == 0) {
+ request_error(state);
+ return;
+ }
+
+ group_list = SMB_MALLOC_ARRAY(struct winbindd_gr, num_groups);
+ if (!group_list) {
+ request_error(state);
+ return;
+ }
+ /* will be freed by process_request() */
+ state->response.extra_data.data = group_list;
+
+ memset(state->response.extra_data.data, '\0',
+ num_groups * sizeof(struct winbindd_gr) );
+
+ state->response.data.num_entries = 0;
+
+ if (!state->getgrent_initialized)
+ winbindd_setgrent_internal(state);
+
+ if (!(ent = state->getgrent_state)) {
+ request_error(state);
+ return;
+ }
+
+ /* Start sending back groups */
+
+ for (group_list_ndx = 0; group_list_ndx < num_groups; ) {
+ struct acct_info *name_list = NULL;
+ fstring domain_group_name;
+ uint32 result;
+ gid_t group_gid;
+ size_t gr_mem_len;
+ char *gr_mem;
+ DOM_SID group_sid;
+ struct winbindd_domain *domain;
+
+ /* Do we need to fetch another chunk of groups? */
+
+ tryagain:
+
+ DEBUG(10, ("entry_index = %d, num_entries = %d\n",
+ ent->sam_entry_index, ent->num_sam_entries));
+
+ if (ent->num_sam_entries == ent->sam_entry_index) {
+
+ while(ent && !get_sam_group_entries(ent)) {
+ struct getent_state *next_ent;
+
+ DEBUG(10, ("freeing state info for domain %s\n",
+ ent->domain_name));
+
+ /* Free state information for this domain */
+
+ SAFE_FREE(ent->sam_entries);
+
+ next_ent = ent->next;
+ DLIST_REMOVE(state->getgrent_state, ent);
+
+ SAFE_FREE(ent);
+ ent = next_ent;
+ }
+
+ /* No more domains */
+
+ if (!ent)
+ break;
+ }
+
+ name_list = (struct acct_info *)ent->sam_entries;
+
+ if (!(domain = find_domain_from_name(ent->domain_name))) {
+ DEBUG(3, ("No such domain %s in winbindd_getgrent\n",
+ ent->domain_name));
+ result = False;
+ goto done;
+ }
+
+ /* Lookup group info */
+
+ sid_copy(&group_sid, &domain->sid);
+ sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
+
+ if (!NT_STATUS_IS_OK(idmap_sid_to_gid(domain->name, &group_sid,
+ &group_gid))) {
+ union unid_t id;
+ enum lsa_SidType type;
+
+ DEBUG(10, ("SID %s not in idmap\n",
+ sid_string_dbg(&group_sid)));
+
+ if (!pdb_sid_to_id(&group_sid, &id, &type)) {
+ DEBUG(1,("could not look up gid for group %s\n",
+ name_list[ent->sam_entry_index].acct_name));
+ ent->sam_entry_index++;
+ goto tryagain;
+ }
+
+ if ((type != SID_NAME_DOM_GRP) &&
+ (type != SID_NAME_ALIAS) &&
+ (type != SID_NAME_WKN_GRP)) {
+ DEBUG(1, ("Group %s is a %s, not a group\n",
+ sid_type_lookup(type),
+ name_list[ent->sam_entry_index].acct_name));
+ ent->sam_entry_index++;
+ goto tryagain;
+ }
+ group_gid = id.gid;
+ }
+
+ DEBUG(10, ("got gid %lu for group %lu\n",
+ (unsigned long)group_gid,
+ (unsigned long)name_list[ent->sam_entry_index].rid));
+
+ /* Fill in group entry */
+
+ fill_domain_username(domain_group_name, ent->domain_name,
+ name_list[ent->sam_entry_index].acct_name, True);
+
+ result = fill_grent(&group_list[group_list_ndx],
+ ent->domain_name,
+ name_list[ent->sam_entry_index].acct_name,
+ group_gid);
+
+ /* Fill in group membership entry */
+
+ if (result) {
+ size_t num_gr_mem = 0;
+ DOM_SID member_sid;
+ group_list[group_list_ndx].num_gr_mem = 0;
+ gr_mem = NULL;
+ gr_mem_len = 0;
+
+ /* Get group membership */
+ if (state->request.cmd == WINBINDD_GETGRLST) {
+ result = True;
+ } else {
+ sid_copy(&member_sid, &domain->sid);
+ sid_append_rid(&member_sid, name_list[ent->sam_entry_index].rid);
+ result = fill_grent_mem(
+ domain,
+ NULL,
+ &member_sid,
+ SID_NAME_DOM_GRP,
+ &num_gr_mem,
+ &gr_mem, &gr_mem_len);
+
+ group_list[group_list_ndx].num_gr_mem = (uint32)num_gr_mem;
+ }
+ }
+
+ if (result) {
+ /* Append to group membership list */
+ gr_mem_list = (char *)SMB_REALLOC(
+ gr_mem_list, gr_mem_list_len + gr_mem_len);
+
+ if (!gr_mem_list &&
+ (group_list[group_list_ndx].num_gr_mem != 0)) {
+ DEBUG(0, ("out of memory\n"));
+ gr_mem_list_len = 0;
+ break;
+ }
+
+ DEBUG(10, ("list_len = %d, mem_len = %u\n",
+ gr_mem_list_len, (unsigned int)gr_mem_len));
+
+ memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
+ gr_mem_len);
+
+ SAFE_FREE(gr_mem);
+
+ group_list[group_list_ndx].gr_mem_ofs =
+ gr_mem_list_len;
+
+ gr_mem_list_len += gr_mem_len;
+ }
+
+ ent->sam_entry_index++;
+
+ /* Add group to return list */
+
+ if (result) {
+
+ DEBUG(10, ("adding group num_entries = %d\n",
+ state->response.data.num_entries));
+
+ group_list_ndx++;
+ state->response.data.num_entries++;
+
+ state->response.length +=
+ sizeof(struct winbindd_gr);
+
+ } else {
+ DEBUG(0, ("could not lookup domain group %s\n",
+ domain_group_name));
+ }
+ }
+
+ /* Copy the list of group memberships to the end of the extra data */
+
+ if (group_list_ndx == 0)
+ goto done;
+
+ state->response.extra_data.data = SMB_REALLOC(
+ state->response.extra_data.data,
+ group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
+
+ if (!state->response.extra_data.data) {
+ DEBUG(0, ("out of memory\n"));
+ group_list_ndx = 0;
+ SAFE_FREE(gr_mem_list);
+ request_error(state);
+ return;
+ }
+
+ memcpy(&((char *)state->response.extra_data.data)
+ [group_list_ndx * sizeof(struct winbindd_gr)],
+ gr_mem_list, gr_mem_list_len);
+
+ state->response.length += gr_mem_list_len;
+
+ DEBUG(10, ("returning %d groups, length = %d\n",
+ group_list_ndx, gr_mem_list_len));
+
+ /* Out of domains */
+
+ done:
+
+ SAFE_FREE(gr_mem_list);
+
+ if (group_list_ndx > 0)
+ request_ok(state);
+ else
+ request_error(state);
+}
+
+/* List domain groups without mapping to unix ids */
+void winbindd_list_groups(struct winbindd_cli_state *state)
+{
+ winbindd_list_ent(state, LIST_GROUPS);
+}
+
+/* Get user supplementary groups. This is much quicker than trying to
+ invert the groups database. We merge the groups from the gids and
+ other_sids info3 fields as trusted domain, universal group
+ memberships, and nested groups (win2k native mode only) are not
+ returned by the getgroups RPC call but are present in the info3. */
+
+struct getgroups_state {
+ struct winbindd_cli_state *state;
+ struct winbindd_domain *domain;
+ char *domname;
+ char *username;
+ DOM_SID user_sid;
+
+ const DOM_SID *token_sids;
+ size_t i, num_token_sids;
+
+ gid_t *token_gids;
+ size_t num_token_gids;
+};
+
+static void getgroups_usersid_recv(void *private_data, bool success,
+ const DOM_SID *sid, enum lsa_SidType type);
+static void getgroups_tokensids_recv(void *private_data, bool success,
+ DOM_SID *token_sids, size_t num_token_sids);
+static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid);
+
+void winbindd_getgroups(struct winbindd_cli_state *state)
+{
+ struct getgroups_state *s;
+
+ /* Ensure null termination */
+ state->request.data.username
+ [sizeof(state->request.data.username)-1]='\0';
+
+ DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
+ state->request.data.username));
+
+ /* Parse domain and username */
+
+ s = TALLOC_P(state->mem_ctx, struct getgroups_state);
+ if (s == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ request_error(state);
+ return;
+ }
+
+ s->state = state;
+
+ ws_name_return( state->request.data.username, WB_REPLACE_CHAR );
+
+ if (!parse_domain_user_talloc(state->mem_ctx,
+ state->request.data.username,
+ &s->domname, &s->username)) {
+ DEBUG(5, ("Could not parse domain user: %s\n",
+ state->request.data.username));
+
+ /* error out if we do not have nested group support */
+
+ if ( !lp_winbind_nested_groups() ) {
+ request_error(state);
+ return;
+ }
+
+ s->domname = talloc_strdup(state->mem_ctx,
+ get_global_sam_name());
+ s->username = talloc_strdup(state->mem_ctx,
+ state->request.data.username);
+ }
+
+ /* Get info for the domain (either by short domain name or
+ DNS name in the case of a UPN) */
+
+ s->domain = find_domain_from_name_noinit(s->domname);
+ if (!s->domain) {
+ char *p = strchr(s->username, '@');
+
+ if (p) {
+ s->domain = find_domain_from_name_noinit(p+1);
+ }
+
+ }
+
+ if (s->domain == NULL) {
+ DEBUG(7, ("could not find domain entry for domain %s\n",
+ s->domname));
+ request_error(state);
+ return;
+ }
+
+ if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
+ DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
+ "getgroups() for %s\\%s.\n", s->domname,
+ s->username));
+ request_error(state);
+ return;
+ }
+
+ /* Get rid and name type from name. The following costs 1 packet */
+
+ winbindd_lookupname_async(state->mem_ctx,
+ s->domname, s->username,
+ getgroups_usersid_recv,
+ WINBINDD_GETGROUPS, s);
+}
+
+static void getgroups_usersid_recv(void *private_data, bool success,
+ const DOM_SID *sid, enum lsa_SidType type)
+{
+ struct getgroups_state *s =
+ (struct getgroups_state *)private_data;
+
+ if ((!success) ||
+ ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
+ request_error(s->state);
+ return;
+ }
+
+ sid_copy(&s->user_sid, sid);
+
+ winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
+ getgroups_tokensids_recv, s);
+}
+
+static void getgroups_tokensids_recv(void *private_data, bool success,
+ DOM_SID *token_sids, size_t num_token_sids)
+{
+ struct getgroups_state *s =
+ (struct getgroups_state *)private_data;
+
+ /* We need at least the user sid and the primary group in the token,
+ * otherwise it's an error */
+
+ if ((!success) || (num_token_sids < 2)) {
+ request_error(s->state);
+ return;
+ }
+
+ s->token_sids = token_sids;
+ s->num_token_sids = num_token_sids;
+ s->i = 0;
+
+ s->token_gids = NULL;
+ s->num_token_gids = 0;
+
+ getgroups_sid2gid_recv(s, False, 0);
+}
+
+static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid)
+{
+ struct getgroups_state *s =
+ (struct getgroups_state *)private_data;
+
+ if (success) {
+ if (!add_gid_to_array_unique(s->state->mem_ctx, gid,
+ &s->token_gids,
+ &s->num_token_gids)) {
+ return;
+ }
+ }
+
+ if (s->i < s->num_token_sids) {
+ const DOM_SID *sid = &s->token_sids[s->i];
+ s->i += 1;
+
+ if (sid_equal(sid, &s->user_sid)) {
+ getgroups_sid2gid_recv(s, False, 0);
+ return;
+ }
+
+ winbindd_sid2gid_async(s->state->mem_ctx, sid,
+ getgroups_sid2gid_recv, s);
+ return;
+ }
+
+ s->state->response.data.num_entries = s->num_token_gids;
+ if (s->num_token_gids) {
+ /* s->token_gids are talloced */
+ s->state->response.extra_data.data =
+ smb_xmemdup(s->token_gids,
+ s->num_token_gids * sizeof(gid_t));
+ s->state->response.length += s->num_token_gids * sizeof(gid_t);
+ }
+ request_ok(s->state);
+}
+
+/* Get user supplementary sids. This is equivalent to the
+ winbindd_getgroups() function but it involves a SID->SIDs mapping
+ rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid
+ idmap. This call is designed to be used with applications that need
+ to do ACL evaluation themselves. Note that the cached info3 data is
+ not used
+
+ this function assumes that the SID that comes in is a user SID. If
+ you pass in another type of SID then you may get unpredictable
+ results.
+*/
+
+static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
+ size_t num_sids);
+
+void winbindd_getusersids(struct winbindd_cli_state *state)
+{
+ DOM_SID *user_sid;
+
+ /* Ensure null termination */
+ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+ user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
+ if (user_sid == NULL) {
+ DEBUG(1, ("talloc failed\n"));
+ request_error(state);
+ return;
+ }
+
+ if (!string_to_sid(user_sid, state->request.data.sid)) {
+ DEBUG(1, ("Could not get convert sid %s from string\n",
+ state->request.data.sid));
+ request_error(state);
+ return;
+ }
+
+ winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
+ state);
+}
+
+static void getusersids_recv(void *private_data, bool success, DOM_SID *sids,
+ size_t num_sids)
+{
+ struct winbindd_cli_state *state =
+ (struct winbindd_cli_state *)private_data;
+ char *ret = NULL;
+ unsigned ofs, ret_size = 0;
+ size_t i;
+
+ if (!success) {
+ request_error(state);
+ return;
+ }
+
+ /* work out the response size */
+ for (i = 0; i < num_sids; i++) {
+ fstring s;
+ sid_to_fstring(s, &sids[i]);
+ ret_size += strlen(s) + 1;
+ }
+
+ /* build the reply */
+ ret = (char *)SMB_MALLOC(ret_size);
+ if (!ret) {
+ DEBUG(0, ("malloc failed\n"));
+ request_error(state);
+ return;
+ }
+ ofs = 0;
+ for (i = 0; i < num_sids; i++) {
+ fstring s;
+ sid_to_fstring(s, &sids[i]);
+ safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
+ ofs += strlen(ret+ofs) + 1;
+ }
+
+ /* Send data back to client */
+ state->response.data.num_entries = num_sids;
+ state->response.extra_data.data = ret;
+ state->response.length += ret_size;
+ request_ok(state);
+}
+
+void winbindd_getuserdomgroups(struct winbindd_cli_state *state)
+{
+ DOM_SID user_sid;
+ struct winbindd_domain *domain;
+
+ /* Ensure null termination */
+ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+ if (!string_to_sid(&user_sid, state->request.data.sid)) {
+ DEBUG(1, ("Could not get convert sid %s from string\n",
+ state->request.data.sid));
+ request_error(state);
+ return;
+ }
+
+ /* Get info for the domain */
+ if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
+ DEBUG(0,("could not find domain entry for sid %s\n",
+ sid_string_dbg(&user_sid)));
+ request_error(state);
+ return;
+ }
+
+ sendto_domain(state, domain);
+}
+
+enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ DOM_SID user_sid;
+ NTSTATUS status;
+
+ char *sidstring;
+ ssize_t len;
+ DOM_SID *groups;
+ uint32 num_groups;
+
+ /* Ensure null termination */
+ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+ if (!string_to_sid(&user_sid, state->request.data.sid)) {
+ DEBUG(1, ("Could not get convert sid %s from string\n",
+ state->request.data.sid));
+ return WINBINDD_ERROR;
+ }
+
+ status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
+ &user_sid, &num_groups,
+ &groups);
+ if (!NT_STATUS_IS_OK(status))
+ return WINBINDD_ERROR;
+
+ if (num_groups == 0) {
+ state->response.data.num_entries = 0;
+ state->response.extra_data.data = NULL;
+ return WINBINDD_OK;
+ }
+
+ if (!print_sidlist(state->mem_ctx,
+ groups, num_groups,
+ &sidstring, &len)) {
+ DEBUG(0, ("talloc failed\n"));
+ return WINBINDD_ERROR;
+ }
+
+ state->response.extra_data.data = SMB_STRDUP(sidstring);
+ if (!state->response.extra_data.data) {
+ return WINBINDD_ERROR;
+ }
+ state->response.length += len+1;
+ state->response.data.num_entries = num_groups;
+
+ return WINBINDD_OK;
+}
diff --git a/source3/winbindd/winbindd_idmap.c b/source3/winbindd/winbindd_idmap.c
new file mode 100644
index 0000000000..d8c67dc21c
--- /dev/null
+++ b/source3/winbindd/winbindd_idmap.c
@@ -0,0 +1,503 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Async helpers for blocking functions
+
+ Copyright (C) Volker Lendecke 2005
+ Copyright (C) Gerald Carter 2006
+ Copyright (C) Simo Sorce 2007
+
+ The helpers always consist of three functions:
+
+ * A request setup function that takes the necessary parameters together
+ with a continuation function that is to be called upon completion
+
+ * A private continuation function that is internal only. This is to be
+ called by the lower-level functions in do_async(). Its only task is to
+ properly call the continuation function named above.
+
+ * A worker function that is called inside the appropriate child process.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+static const struct winbindd_child_dispatch_table idmap_dispatch_table[];
+
+static struct winbindd_child static_idmap_child;
+
+void init_idmap_child(void)
+{
+ setup_child(&static_idmap_child,
+ idmap_dispatch_table,
+ "log.winbindd", "idmap");
+}
+
+struct winbindd_child *idmap_child(void)
+{
+ return &static_idmap_child;
+}
+
+static void winbindd_set_mapping_recv(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data)
+{
+ void (*cont)(void *priv, bool succ) = (void (*)(void *, bool))c;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger idmap_set_mapping\n"));
+ cont(private_data, False);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("idmap_set_mapping returned an error\n"));
+ cont(private_data, False);
+ return;
+ }
+
+ cont(private_data, True);
+}
+
+void winbindd_set_mapping_async(TALLOC_CTX *mem_ctx, const struct id_map *map,
+ void (*cont)(void *private_data, bool success),
+ void *private_data)
+{
+ struct winbindd_request request;
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_SET_MAPPING;
+ request.data.dual_idmapset.id = map->xid.id;
+ request.data.dual_idmapset.type = map->xid.type;
+ sid_to_fstring(request.data.dual_idmapset.sid, map->sid);
+
+ do_async(mem_ctx, idmap_child(), &request, winbindd_set_mapping_recv,
+ (void *)cont, private_data);
+}
+
+enum winbindd_result winbindd_dual_set_mapping(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ struct id_map map;
+ DOM_SID sid;
+ NTSTATUS result;
+
+ DEBUG(3, ("[%5lu]: dual_idmapset\n", (unsigned long)state->pid));
+
+ if (!string_to_sid(&sid, state->request.data.dual_idmapset.sid))
+ return WINBINDD_ERROR;
+
+ map.sid = &sid;
+ map.xid.id = state->request.data.dual_idmapset.id;
+ map.xid.type = state->request.data.dual_idmapset.type;
+ map.status = ID_MAPPED;
+
+ result = idmap_set_mapping(&map);
+ return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+static void winbindd_set_hwm_recv(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data)
+{
+ void (*cont)(void *priv, bool succ) = (void (*)(void *, bool))c;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger idmap_set_hwm\n"));
+ cont(private_data, False);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("idmap_set_hwm returned an error\n"));
+ cont(private_data, False);
+ return;
+ }
+
+ cont(private_data, True);
+}
+
+void winbindd_set_hwm_async(TALLOC_CTX *mem_ctx, const struct unixid *xid,
+ void (*cont)(void *private_data, bool success),
+ void *private_data)
+{
+ struct winbindd_request request;
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_SET_HWM;
+ request.data.dual_idmapset.id = xid->id;
+ request.data.dual_idmapset.type = xid->type;
+
+ do_async(mem_ctx, idmap_child(), &request, winbindd_set_hwm_recv,
+ (void *)cont, private_data);
+}
+
+enum winbindd_result winbindd_dual_set_hwm(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ struct unixid xid;
+ NTSTATUS result;
+
+ DEBUG(3, ("[%5lu]: dual_set_hwm\n", (unsigned long)state->pid));
+
+ xid.id = state->request.data.dual_idmapset.id;
+ xid.type = state->request.data.dual_idmapset.type;
+
+ switch (xid.type) {
+ case ID_TYPE_UID:
+ result = idmap_set_uid_hwm(&xid);
+ break;
+ case ID_TYPE_GID:
+ result = idmap_set_gid_hwm(&xid);
+ break;
+ default:
+ return WINBINDD_ERROR;
+ }
+ return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+static void winbindd_sid2uid_recv(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data)
+{
+ void (*cont)(void *priv, bool succ, uid_t uid) =
+ (void (*)(void *, bool, uid_t))c;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger sid2uid\n"));
+ cont(private_data, False, 0);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("sid2uid returned an error\n"));
+ cont(private_data, False, 0);
+ return;
+ }
+
+ cont(private_data, True, response->data.uid);
+}
+
+void winbindd_sid2uid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ void (*cont)(void *private_data, bool success, uid_t uid),
+ void *private_data)
+{
+ struct winbindd_request request;
+ struct winbindd_domain *domain;
+
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_SID2UID;
+
+ domain = find_domain_from_sid(sid);
+
+ if (domain != NULL) {
+ DEBUG(10, ("winbindd_sid2uid_async found domain %s, "
+ "have_idmap_config = %d\n", domain->name,
+ (int)domain->have_idmap_config));
+
+ }
+ else {
+ DEBUG(10, ("winbindd_sid2uid_async did not find a domain for "
+ "%s\n", sid_string_dbg(sid)));
+ }
+
+ if ((domain != NULL) && (domain->have_idmap_config)) {
+ fstrcpy(request.domain_name, domain->name);
+ }
+
+ sid_to_fstring(request.data.dual_sid2id.sid, sid);
+ do_async(mem_ctx, idmap_child(), &request, winbindd_sid2uid_recv,
+ (void *)cont, private_data);
+}
+
+enum winbindd_result winbindd_dual_sid2uid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ NTSTATUS result;
+
+ DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
+ state->request.data.dual_sid2id.sid));
+
+ if (!string_to_sid(&sid, state->request.data.dual_sid2id.sid)) {
+ DEBUG(1, ("Could not get convert sid %s from string\n",
+ state->request.data.dual_sid2id.sid));
+ return WINBINDD_ERROR;
+ }
+
+ result = idmap_sid_to_uid(state->request.domain_name, &sid,
+ &state->response.data.uid);
+
+ DEBUG(10, ("winbindd_dual_sid2uid: 0x%08x - %s - %u\n",
+ NT_STATUS_V(result), sid_string_dbg(&sid),
+ state->response.data.uid));
+
+ return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+static void winbindd_sid2gid_recv(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data)
+{
+ void (*cont)(void *priv, bool succ, gid_t gid) =
+ (void (*)(void *, bool, gid_t))c;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger sid2gid\n"));
+ cont(private_data, False, 0);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("sid2gid returned an error\n"));
+ cont(private_data, False, 0);
+ return;
+ }
+
+ cont(private_data, True, response->data.gid);
+}
+
+void winbindd_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ void (*cont)(void *private_data, bool success, gid_t gid),
+ void *private_data)
+{
+ struct winbindd_request request;
+ struct winbindd_domain *domain;
+
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_SID2GID;
+
+ domain = find_domain_from_sid(sid);
+ if ((domain != NULL) && (domain->have_idmap_config)) {
+ fstrcpy(request.domain_name, domain->name);
+ }
+
+ sid_to_fstring(request.data.dual_sid2id.sid, sid);
+
+ DEBUG(7,("winbindd_sid2gid_async: Resolving %s to a gid\n",
+ request.data.dual_sid2id.sid));
+
+ do_async(mem_ctx, idmap_child(), &request, winbindd_sid2gid_recv,
+ (void *)cont, private_data);
+}
+
+enum winbindd_result winbindd_dual_sid2gid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ NTSTATUS result;
+
+ DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
+ state->request.data.dual_sid2id.sid));
+
+ if (!string_to_sid(&sid, state->request.data.dual_sid2id.sid)) {
+ DEBUG(1, ("Could not get convert sid %s from string\n",
+ state->request.data.dual_sid2id.sid));
+ return WINBINDD_ERROR;
+ }
+
+ /* Find gid for this sid and return it, possibly ask the slow remote idmap */
+
+ result = idmap_sid_to_gid(state->request.domain_name, &sid,
+ &state->response.data.gid);
+
+ DEBUG(10, ("winbindd_dual_sid2gid: 0x%08x - %s - %u\n",
+ NT_STATUS_V(result), sid_string_dbg(&sid),
+ state->response.data.gid));
+
+ return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+/* The following uid2sid/gid2sid functions has been contributed by
+ * Keith Reynolds <Keith.Reynolds@centrify.com> */
+
+static void winbindd_uid2sid_recv(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data)
+{
+ void (*cont)(void *priv, bool succ, const char *sid) =
+ (void (*)(void *, bool, const char *))c;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger uid2sid\n"));
+ cont(private_data, False, NULL);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("uid2sid returned an error\n"));
+ cont(private_data, False, NULL);
+ return;
+ }
+
+ cont(private_data, True, response->data.sid.sid);
+}
+
+void winbindd_uid2sid_async(TALLOC_CTX *mem_ctx, uid_t uid,
+ void (*cont)(void *private_data, bool success, const char *sid),
+ void *private_data)
+{
+ struct winbindd_domain *domain;
+ struct winbindd_request request;
+
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_UID2SID;
+ request.data.uid = uid;
+
+ for (domain = domain_list(); domain != NULL; domain = domain->next) {
+ if (domain->have_idmap_config
+ && (uid >= domain->id_range_low)
+ && (uid <= domain->id_range_high)) {
+ fstrcpy(request.domain_name, domain->name);
+ }
+ }
+
+ do_async(mem_ctx, idmap_child(), &request, winbindd_uid2sid_recv,
+ (void *)cont, private_data);
+}
+
+enum winbindd_result winbindd_dual_uid2sid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ NTSTATUS result;
+
+ DEBUG(3,("[%5lu]: uid to sid %lu\n",
+ (unsigned long)state->pid,
+ (unsigned long) state->request.data.uid));
+
+ /* Find sid for this uid and return it, possibly ask the slow remote idmap */
+ result = idmap_uid_to_sid(state->request.domain_name, &sid,
+ state->request.data.uid);
+
+ if (NT_STATUS_IS_OK(result)) {
+ sid_to_fstring(state->response.data.sid.sid, &sid);
+ state->response.data.sid.type = SID_NAME_USER;
+ return WINBINDD_OK;
+ }
+
+ return WINBINDD_ERROR;
+}
+
+static void winbindd_gid2sid_recv(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data)
+{
+ void (*cont)(void *priv, bool succ, const char *sid) =
+ (void (*)(void *, bool, const char *))c;
+
+ if (!success) {
+ DEBUG(5, ("Could not trigger gid2sid\n"));
+ cont(private_data, False, NULL);
+ return;
+ }
+
+ if (response->result != WINBINDD_OK) {
+ DEBUG(5, ("gid2sid returned an error\n"));
+ cont(private_data, False, NULL);
+ return;
+ }
+
+ cont(private_data, True, response->data.sid.sid);
+}
+
+void winbindd_gid2sid_async(TALLOC_CTX *mem_ctx, gid_t gid,
+ void (*cont)(void *private_data, bool success, const char *sid),
+ void *private_data)
+{
+ struct winbindd_domain *domain;
+ struct winbindd_request request;
+
+ ZERO_STRUCT(request);
+ request.cmd = WINBINDD_DUAL_GID2SID;
+ request.data.gid = gid;
+
+ for (domain = domain_list(); domain != NULL; domain = domain->next) {
+ if (domain->have_idmap_config
+ && (gid >= domain->id_range_low)
+ && (gid <= domain->id_range_high)) {
+ fstrcpy(request.domain_name, domain->name);
+ }
+ }
+
+ do_async(mem_ctx, idmap_child(), &request, winbindd_gid2sid_recv,
+ (void *)cont, private_data);
+}
+
+enum winbindd_result winbindd_dual_gid2sid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ NTSTATUS result;
+
+ DEBUG(3,("[%5lu]: gid %lu to sid\n",
+ (unsigned long)state->pid,
+ (unsigned long) state->request.data.gid));
+
+ /* Find sid for this gid and return it, possibly ask the slow remote idmap */
+ result = idmap_gid_to_sid(state->request.domain_name, &sid,
+ state->request.data.gid);
+
+ if (NT_STATUS_IS_OK(result)) {
+ sid_to_fstring(state->response.data.sid.sid, &sid);
+ DEBUG(10, ("[%5lu]: retrieved sid: %s\n",
+ (unsigned long)state->pid,
+ state->response.data.sid.sid));
+ state->response.data.sid.type = SID_NAME_DOM_GRP;
+ return WINBINDD_OK;
+ }
+
+ return WINBINDD_ERROR;
+}
+
+static const struct winbindd_child_dispatch_table idmap_dispatch_table[] = {
+ {
+ .name = "DUAL_SID2UID",
+ .struct_cmd = WINBINDD_DUAL_SID2UID,
+ .struct_fn = winbindd_dual_sid2uid,
+ },{
+ .name = "DUAL_SID2GID",
+ .struct_cmd = WINBINDD_DUAL_SID2GID,
+ .struct_fn = winbindd_dual_sid2gid,
+ },{
+ .name = "DUAL_UID2SID",
+ .struct_cmd = WINBINDD_DUAL_UID2SID,
+ .struct_fn = winbindd_dual_uid2sid,
+ },{
+ .name = "DUAL_GID2SID",
+ .struct_cmd = WINBINDD_DUAL_GID2SID,
+ .struct_fn = winbindd_dual_gid2sid,
+ },{
+ .name = "DUAL_SET_MAPPING",
+ .struct_cmd = WINBINDD_DUAL_SET_MAPPING,
+ .struct_fn = winbindd_dual_set_mapping,
+ },{
+ .name = "DUAL_SET_HWMS",
+ .struct_cmd = WINBINDD_DUAL_SET_HWM,
+ .struct_fn = winbindd_dual_set_hwm,
+ },{
+ .name = "ALLOCATE_UID",
+ .struct_cmd = WINBINDD_ALLOCATE_UID,
+ .struct_fn = winbindd_dual_allocate_uid,
+ },{
+ .name = "ALLOCATE_GID",
+ .struct_cmd = WINBINDD_ALLOCATE_GID,
+ .struct_fn = winbindd_dual_allocate_gid,
+ },{
+ .name = NULL,
+ }
+};
diff --git a/source3/winbindd/winbindd_locator.c b/source3/winbindd/winbindd_locator.c
new file mode 100644
index 0000000000..b2a8bd7e30
--- /dev/null
+++ b/source3/winbindd/winbindd_locator.c
@@ -0,0 +1,147 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon - miscellaneous other functions
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Andrew Bartlett 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+
+static const struct winbindd_child_dispatch_table locator_dispatch_table[];
+
+static struct winbindd_child static_locator_child;
+
+void init_locator_child(void)
+{
+ setup_child(&static_locator_child,
+ locator_dispatch_table,
+ "log.winbindd", "locator");
+}
+
+struct winbindd_child *locator_child(void)
+{
+ return &static_locator_child;
+}
+
+void winbindd_dsgetdcname(struct winbindd_cli_state *state)
+{
+ state->request.domain_name
+ [sizeof(state->request.domain_name)-1] = '\0';
+
+ DEBUG(3, ("[%5lu]: dsgetdcname for %s\n", (unsigned long)state->pid,
+ state->request.domain_name));
+
+ sendto_child(state, locator_child());
+}
+
+struct wbc_flag_map {
+ uint32_t wbc_dc_flag;
+ uint32_t ds_dc_flags;
+};
+
+static uint32_t get_dsgetdc_flags(uint32_t wbc_flags)
+{
+ struct wbc_flag_map lookup_dc_flags[] = {
+ { WBC_LOOKUP_DC_FORCE_REDISCOVERY, DS_FORCE_REDISCOVERY },
+ { WBC_LOOKUP_DC_DS_REQUIRED, DS_DIRECTORY_SERVICE_REQUIRED },
+ { WBC_LOOKUP_DC_DS_PREFERRED, DS_DIRECTORY_SERVICE_PREFERRED},
+ { WBC_LOOKUP_DC_GC_SERVER_REQUIRED, DS_GC_SERVER_REQUIRED },
+ { WBC_LOOKUP_DC_PDC_REQUIRED, DS_PDC_REQUIRED},
+ { WBC_LOOKUP_DC_BACKGROUND_ONLY, DS_BACKGROUND_ONLY },
+ { WBC_LOOKUP_DC_IP_REQUIRED, DS_IP_REQUIRED },
+ { WBC_LOOKUP_DC_KDC_REQUIRED, DS_KDC_REQUIRED },
+ { WBC_LOOKUP_DC_TIMESERV_REQUIRED, DS_TIMESERV_REQUIRED },
+ { WBC_LOOKUP_DC_WRITABLE_REQUIRED, DS_WRITABLE_REQUIRED },
+ { WBC_LOOKUP_DC_GOOD_TIMESERV_PREFERRED, DS_GOOD_TIMESERV_PREFERRED },
+ { WBC_LOOKUP_DC_AVOID_SELF, DS_AVOID_SELF },
+ { WBC_LOOKUP_DC_ONLY_LDAP_NEEDED, DS_ONLY_LDAP_NEEDED },
+ { WBC_LOOKUP_DC_IS_FLAT_NAME, DS_IS_FLAT_NAME },
+ { WBC_LOOKUP_DC_IS_DNS_NAME, DS_IS_DNS_NAME },
+ { WBC_LOOKUP_DC_TRY_NEXTCLOSEST_SITE, DS_TRY_NEXTCLOSEST_SITE },
+ { WBC_LOOKUP_DC_DS_6_REQUIRED, DS_DIRECTORY_SERVICE_6_REQUIRED },
+ { WBC_LOOKUP_DC_RETURN_DNS_NAME, DS_RETURN_DNS_NAME },
+ { WBC_LOOKUP_DC_RETURN_FLAT_NAME, DS_RETURN_FLAT_NAME }
+ };
+ uint32_t ds_flags = 0;
+ int i = 0 ;
+ int num_entries = sizeof(lookup_dc_flags) / sizeof(struct wbc_flag_map);
+
+ for (i=0; i<num_entries; i++) {
+ if (wbc_flags & lookup_dc_flags[i].wbc_dc_flag)
+ ds_flags |= lookup_dc_flags[i].ds_dc_flags;
+ }
+
+ return ds_flags;
+}
+
+
+static enum winbindd_result dual_dsgetdcname(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ NTSTATUS result;
+ struct netr_DsRGetDCNameInfo *info = NULL;
+ const char *dc = NULL;
+ uint32_t ds_flags = 0;
+
+ state->request.domain_name
+ [sizeof(state->request.domain_name)-1] = '\0';
+
+ DEBUG(3, ("[%5lu]: dsgetdcname for %s\n", (unsigned long)state->pid,
+ state->request.domain_name));
+
+ ds_flags = get_dsgetdc_flags(state->request.flags);
+
+ result = dsgetdcname(state->mem_ctx, winbind_messaging_context(),
+ state->request.domain_name,
+ NULL, NULL, ds_flags, &info);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ return WINBINDD_ERROR;
+ }
+
+ if (info->dc_address) {
+ dc = strip_hostname(info->dc_address);
+ }
+
+ if ((!dc || !is_ipaddress_v4(dc)) && info->dc_unc) {
+ dc = strip_hostname(info->dc_unc);
+ }
+
+ if (!dc || !*dc) {
+ return WINBINDD_ERROR;
+ }
+
+ fstrcpy(state->response.data.dc_name, dc);
+
+ return WINBINDD_OK;
+}
+
+static const struct winbindd_child_dispatch_table locator_dispatch_table[] = {
+ {
+ .name = "DSGETDCNAME",
+ .struct_cmd = WINBINDD_DSGETDCNAME,
+ .struct_fn = dual_dsgetdcname,
+ },{
+ .name = NULL,
+ }
+};
diff --git a/source3/winbindd/winbindd_misc.c b/source3/winbindd/winbindd_misc.c
new file mode 100644
index 0000000000..50936c01a3
--- /dev/null
+++ b/source3/winbindd/winbindd_misc.c
@@ -0,0 +1,802 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon - miscellaneous other functions
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Andrew Bartlett 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+/* Check the machine account password is valid */
+
+void winbindd_check_machine_acct(struct winbindd_cli_state *state)
+{
+ DEBUG(3, ("[%5lu]: check machine account\n",
+ (unsigned long)state->pid));
+
+ sendto_domain(state, find_our_domain());
+}
+
+enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ int num_retries = 0;
+ struct winbindd_domain *contact_domain;
+
+ DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid));
+
+ /* Get trust account password */
+
+ again:
+
+ contact_domain = find_our_domain();
+
+ /* This call does a cli_nt_setup_creds() which implicitly checks
+ the trust account password. */
+
+ invalidate_cm_connection(&contact_domain->conn);
+
+ {
+ struct rpc_pipe_client *netlogon_pipe;
+ result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
+ }
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
+ goto done;
+ }
+
+ /* There is a race condition between fetching the trust account
+ password and the periodic machine password change. So it's
+ possible that the trust account password has been changed on us.
+ We are returned NT_STATUS_ACCESS_DENIED if this happens. */
+
+#define MAX_RETRIES 8
+
+ if ((num_retries < MAX_RETRIES) &&
+ NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) {
+ num_retries++;
+ goto again;
+ }
+
+ /* Pass back result code - zero for success, other values for
+ specific failures. */
+
+ DEBUG(3, ("secret is %s\n", NT_STATUS_IS_OK(result) ?
+ "good" : "bad"));
+
+ done:
+ set_auth_errors(&state->response, result);
+
+ DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Checking the trust account password returned %s\n",
+ state->response.data.auth.nt_status_string));
+
+ return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+/* Helpers for listing user and group names */
+
+const char *ent_type_strings[] = {"users",
+ "groups"};
+
+static const char *get_ent_type_string(enum ent_type type)
+{
+ return ent_type_strings[type];
+}
+
+struct listent_state {
+ TALLOC_CTX *mem_ctx;
+ struct winbindd_cli_state *cli_state;
+ enum ent_type type;
+ int domain_count;
+ char *extra_data;
+ uint32_t extra_data_len;
+};
+
+static void listent_recv(void *private_data, bool success, fstring dom_name,
+ char *extra_data);
+
+/* List domain users/groups without mapping to unix ids */
+void winbindd_list_ent(struct winbindd_cli_state *state, enum ent_type type)
+{
+ struct winbindd_domain *domain;
+ const char *which_domain;
+ struct listent_state *ent_state;
+
+ DEBUG(3, ("[%5lu]: list %s\n", (unsigned long)state->pid,
+ get_ent_type_string(type)));
+
+ /* Ensure null termination */
+ state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
+ which_domain = state->request.domain_name;
+
+ /* Initialize listent_state */
+ ent_state = TALLOC_P(state->mem_ctx, struct listent_state);
+ if (ent_state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ request_error(state);
+ return;
+ }
+
+ ent_state->mem_ctx = state->mem_ctx;
+ ent_state->cli_state = state;
+ ent_state->type = type;
+ ent_state->domain_count = 0;
+ ent_state->extra_data = NULL;
+ ent_state->extra_data_len = 0;
+
+ /* Must count the full list of expected domains before we request data
+ * from any of them. Otherwise it's possible for a connection to the
+ * first domain to fail, call listent_recv(), and return to the
+ * client without checking any other domains. */
+ for (domain = domain_list(); domain; domain = domain->next) {
+ /* if we have a domain name restricting the request and this
+ one in the list doesn't match, then just bypass the remainder
+ of the loop */
+ if ( *which_domain && !strequal(which_domain, domain->name) )
+ continue;
+
+ ent_state->domain_count++;
+ }
+
+ /* Make sure we're enumerating at least one domain */
+ if (!ent_state->domain_count) {
+ request_ok(state);
+ return;
+ }
+
+ /* Enumerate list of trusted domains and request user/group list from
+ * each */
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if ( *which_domain && !strequal(which_domain, domain->name) )
+ continue;
+
+ winbindd_listent_async(state->mem_ctx, domain,
+ listent_recv, ent_state, type);
+ }
+}
+
+static void listent_recv(void *private_data, bool success, fstring dom_name,
+ char *extra_data)
+{
+ /* extra_data comes to us as a '\0' terminated string of comma
+ separated users or groups */
+ struct listent_state *state = talloc_get_type_abort(
+ private_data, struct listent_state);
+
+ /* Append users/groups from one domain onto the whole list */
+ if (extra_data) {
+ DEBUG(5, ("listent_recv: %s returned %s.\n",
+ dom_name, get_ent_type_string(state->type)));
+ if (!state->extra_data)
+ state->extra_data = talloc_asprintf(state->mem_ctx,
+ "%s", extra_data);
+ else
+ state->extra_data = talloc_asprintf_append(
+ state->extra_data,
+ ",%s", extra_data);
+ /* Add one for the '\0' and each additional ',' */
+ state->extra_data_len += strlen(extra_data) + 1;
+ }
+ else {
+ DEBUG(5, ("listent_recv: %s returned no %s.\n",
+ dom_name, get_ent_type_string(state->type)));
+ }
+
+ if (--state->domain_count)
+ /* Still waiting for some child domains to return */
+ return;
+
+ /* Return list of all users/groups to the client */
+ if (state->extra_data) {
+ state->cli_state->response.extra_data.data =
+ SMB_STRDUP(state->extra_data);
+ state->cli_state->response.length += state->extra_data_len;
+ }
+
+ request_ok(state->cli_state);
+}
+
+/* Constants and helper functions for determining domain trust types */
+
+enum trust_type {
+ EXTERNAL = 0,
+ FOREST,
+ IN_FOREST,
+ NONE,
+};
+
+const char *trust_type_strings[] = {"External",
+ "Forest",
+ "In Forest",
+ "None"};
+
+static enum trust_type get_trust_type(struct winbindd_tdc_domain *domain)
+{
+ if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN)
+ return EXTERNAL;
+ else if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)
+ return FOREST;
+ else if (((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) == NETR_TRUST_FLAG_IN_FOREST) &&
+ ((domain->trust_flags & NETR_TRUST_FLAG_PRIMARY) == 0x0))
+ return IN_FOREST;
+ return NONE;
+}
+
+static const char *get_trust_type_string(struct winbindd_tdc_domain *domain)
+{
+ return trust_type_strings[get_trust_type(domain)];
+}
+
+static bool trust_is_inbound(struct winbindd_tdc_domain *domain)
+{
+ return (domain->trust_flags == 0x0) ||
+ ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
+ NETR_TRUST_FLAG_IN_FOREST) ||
+ ((domain->trust_flags & NETR_TRUST_FLAG_INBOUND) ==
+ NETR_TRUST_FLAG_INBOUND);
+}
+
+static bool trust_is_outbound(struct winbindd_tdc_domain *domain)
+{
+ return (domain->trust_flags == 0x0) ||
+ ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
+ NETR_TRUST_FLAG_IN_FOREST) ||
+ ((domain->trust_flags & NETR_TRUST_FLAG_OUTBOUND) ==
+ NETR_TRUST_FLAG_OUTBOUND);
+}
+
+static bool trust_is_transitive(struct winbindd_tdc_domain *domain)
+{
+ if ((domain->trust_attribs == NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE) ||
+ (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) ||
+ (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL))
+ return False;
+ return True;
+}
+
+void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
+{
+ struct winbindd_tdc_domain *dom_list = NULL;
+ struct winbindd_tdc_domain *d = NULL;
+ size_t num_domains = 0;
+ int extra_data_len = 0;
+ char *extra_data = NULL;
+ int i = 0;
+
+ DEBUG(3, ("[%5lu]: list trusted domains\n",
+ (unsigned long)state->pid));
+
+ if( !wcache_tdc_fetch_list( &dom_list, &num_domains )) {
+ request_error(state);
+ goto done;
+ }
+
+ for ( i = 0; i < num_domains; i++ ) {
+ struct winbindd_domain *domain;
+ bool is_online = true;
+
+ d = &dom_list[i];
+ domain = find_domain_from_name_noinit(d->domain_name);
+ if (domain) {
+ is_online = domain->online;
+ }
+
+ if ( !extra_data ) {
+ extra_data = talloc_asprintf(state->mem_ctx,
+ "%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
+ d->domain_name,
+ d->dns_name ? d->dns_name : d->domain_name,
+ sid_string_talloc(state->mem_ctx, &d->sid),
+ get_trust_type_string(d),
+ trust_is_transitive(d) ? "Yes" : "No",
+ trust_is_inbound(d) ? "Yes" : "No",
+ trust_is_outbound(d) ? "Yes" : "No",
+ is_online ? "Online" : "Offline" );
+ } else {
+ extra_data = talloc_asprintf(state->mem_ctx,
+ "%s\n%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
+ extra_data,
+ d->domain_name,
+ d->dns_name ? d->dns_name : d->domain_name,
+ sid_string_talloc(state->mem_ctx, &d->sid),
+ get_trust_type_string(d),
+ trust_is_transitive(d) ? "Yes" : "No",
+ trust_is_inbound(d) ? "Yes" : "No",
+ trust_is_outbound(d) ? "Yes" : "No",
+ is_online ? "Online" : "Offline" );
+ }
+ }
+
+ extra_data_len = 0;
+ if (extra_data != NULL) {
+ extra_data_len = strlen(extra_data);
+ }
+
+ if (extra_data_len > 0) {
+ state->response.extra_data.data = SMB_STRDUP(extra_data);
+ state->response.length += extra_data_len+1;
+ }
+
+ request_ok(state);
+done:
+ TALLOC_FREE( dom_list );
+ TALLOC_FREE( extra_data );
+}
+
+enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ uint32 i, num_domains;
+ char **names, **alt_names;
+ DOM_SID *sids;
+ int extra_data_len = 0;
+ char *extra_data;
+ NTSTATUS result;
+ bool have_own_domain = False;
+
+ DEBUG(3, ("[%5lu]: list trusted domains\n",
+ (unsigned long)state->pid));
+
+ result = domain->methods->trusted_domains(domain, state->mem_ctx,
+ &num_domains, &names,
+ &alt_names, &sids);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
+ nt_errstr(result) ));
+ return WINBINDD_ERROR;
+ }
+
+ extra_data = talloc_strdup(state->mem_ctx, "");
+
+ if (num_domains > 0)
+ extra_data = talloc_asprintf(
+ state->mem_ctx, "%s\\%s\\%s",
+ names[0], alt_names[0] ? alt_names[0] : names[0],
+ sid_string_talloc(state->mem_ctx, &sids[0]));
+
+ for (i=1; i<num_domains; i++)
+ extra_data = talloc_asprintf(
+ state->mem_ctx, "%s\n%s\\%s\\%s",
+ extra_data, names[i],
+ alt_names[i] ? alt_names[i] : names[i],
+ sid_string_talloc(state->mem_ctx, &sids[i]));
+
+ /* add our primary domain */
+
+ for (i=0; i<num_domains; i++) {
+ if (strequal(names[i], domain->name)) {
+ have_own_domain = True;
+ break;
+ }
+ }
+
+ if (state->request.data.list_all_domains && !have_own_domain) {
+ extra_data = talloc_asprintf(
+ state->mem_ctx, "%s\n%s\\%s\\%s",
+ extra_data, domain->name,
+ domain->alt_name ? domain->alt_name : domain->name,
+ sid_string_talloc(state->mem_ctx, &domain->sid));
+ }
+
+ /* This is a bit excessive, but the extra data sooner or later will be
+ talloc'ed */
+
+ extra_data_len = 0;
+ if (extra_data != NULL) {
+ extra_data_len = strlen(extra_data);
+ }
+
+ if (extra_data_len > 0) {
+ state->response.extra_data.data = SMB_STRDUP(extra_data);
+ state->response.length += extra_data_len+1;
+ }
+
+ return WINBINDD_OK;
+}
+
+void winbindd_getdcname(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+
+ state->request.domain_name
+ [sizeof(state->request.domain_name)-1] = '\0';
+
+ DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
+ state->request.domain_name));
+
+ domain = find_domain_from_name_noinit(state->request.domain_name);
+ if (domain && domain->internal) {
+ fstrcpy(state->response.data.dc_name, global_myname());
+ request_ok(state);
+ return;
+ }
+
+ sendto_domain(state, find_our_domain());
+}
+
+enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ const char *dcname_slash = NULL;
+ const char *p;
+ struct rpc_pipe_client *netlogon_pipe;
+ NTSTATUS result;
+ WERROR werr;
+ unsigned int orig_timeout;
+ struct winbindd_domain *req_domain;
+
+ state->request.domain_name
+ [sizeof(state->request.domain_name)-1] = '\0';
+
+ DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
+ state->request.domain_name));
+
+ result = cm_connect_netlogon(domain, &netlogon_pipe);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
+ return WINBINDD_ERROR;
+ }
+
+ /* This call can take a long time - allow the server to time out.
+ 35 seconds should do it. */
+
+ orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
+
+ req_domain = find_domain_from_name_noinit(state->request.domain_name);
+ if (req_domain == domain) {
+ result = rpccli_netr_GetDcName(netlogon_pipe,
+ state->mem_ctx,
+ domain->dcname,
+ state->request.domain_name,
+ &dcname_slash,
+ &werr);
+ } else {
+ result = rpccli_netr_GetAnyDCName(netlogon_pipe,
+ state->mem_ctx,
+ domain->dcname,
+ state->request.domain_name,
+ &dcname_slash,
+ &werr);
+ }
+ /* And restore our original timeout. */
+ rpccli_set_timeout(netlogon_pipe, orig_timeout);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(5,("Error requesting DCname for domain %s: %s\n",
+ state->request.domain_name, nt_errstr(result)));
+ return WINBINDD_ERROR;
+ }
+
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
+ state->request.domain_name, dos_errstr(werr)));
+ return WINBINDD_ERROR;
+ }
+
+ p = dcname_slash;
+ if (*p == '\\') {
+ p+=1;
+ }
+ if (*p == '\\') {
+ p+=1;
+ }
+
+ fstrcpy(state->response.data.dc_name, p);
+ return WINBINDD_OK;
+}
+
+struct sequence_state {
+ TALLOC_CTX *mem_ctx;
+ struct winbindd_cli_state *cli_state;
+ struct winbindd_domain *domain;
+ struct winbindd_request *request;
+ struct winbindd_response *response;
+ char *extra_data;
+};
+
+static void sequence_recv(void *private_data, bool success);
+
+void winbindd_show_sequence(struct winbindd_cli_state *state)
+{
+ struct sequence_state *seq;
+
+ /* Ensure null termination */
+ state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
+
+ if (strlen(state->request.domain_name) > 0) {
+ struct winbindd_domain *domain;
+ domain = find_domain_from_name_noinit(
+ state->request.domain_name);
+ if (domain == NULL) {
+ request_error(state);
+ return;
+ }
+ sendto_domain(state, domain);
+ return;
+ }
+
+ /* Ask all domains in sequence, collect the results in sequence_recv */
+
+ seq = TALLOC_P(state->mem_ctx, struct sequence_state);
+ if (seq == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ request_error(state);
+ return;
+ }
+
+ seq->mem_ctx = state->mem_ctx;
+ seq->cli_state = state;
+ seq->domain = domain_list();
+ if (seq->domain == NULL) {
+ DEBUG(0, ("domain list empty\n"));
+ request_error(state);
+ return;
+ }
+ seq->request = TALLOC_ZERO_P(state->mem_ctx,
+ struct winbindd_request);
+ seq->response = TALLOC_ZERO_P(state->mem_ctx,
+ struct winbindd_response);
+ seq->extra_data = talloc_strdup(state->mem_ctx, "");
+
+ if ((seq->request == NULL) || (seq->response == NULL) ||
+ (seq->extra_data == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ request_error(state);
+ return;
+ }
+
+ seq->request->length = sizeof(*seq->request);
+ seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
+ fstrcpy(seq->request->domain_name, seq->domain->name);
+
+ async_domain_request(state->mem_ctx, seq->domain,
+ seq->request, seq->response,
+ sequence_recv, seq);
+}
+
+static void sequence_recv(void *private_data, bool success)
+{
+ struct sequence_state *state =
+ (struct sequence_state *)private_data;
+ uint32 seq = DOM_SEQUENCE_NONE;
+
+ if ((success) && (state->response->result == WINBINDD_OK))
+ seq = state->response->data.sequence_number;
+
+ if (seq == DOM_SEQUENCE_NONE) {
+ state->extra_data = talloc_asprintf(state->mem_ctx,
+ "%s%s : DISCONNECTED\n",
+ state->extra_data,
+ state->domain->name);
+ } else {
+ state->extra_data = talloc_asprintf(state->mem_ctx,
+ "%s%s : %d\n",
+ state->extra_data,
+ state->domain->name, seq);
+ }
+
+ state->domain->sequence_number = seq;
+
+ state->domain = state->domain->next;
+
+ if (state->domain == NULL) {
+ struct winbindd_cli_state *cli_state = state->cli_state;
+ cli_state->response.length =
+ sizeof(cli_state->response) +
+ strlen(state->extra_data) + 1;
+ cli_state->response.extra_data.data =
+ SMB_STRDUP(state->extra_data);
+ request_ok(cli_state);
+ return;
+ }
+
+ /* Ask the next domain */
+ fstrcpy(state->request->domain_name, state->domain->name);
+ async_domain_request(state->mem_ctx, state->domain,
+ state->request, state->response,
+ sequence_recv, state);
+}
+
+/* This is the child-only version of --sequence. It only allows for a single
+ * domain (ie "our" one) to be displayed. */
+
+enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
+
+ /* Ensure null termination */
+ state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
+
+ domain->methods->sequence_number(domain, &domain->sequence_number);
+
+ state->response.data.sequence_number =
+ domain->sequence_number;
+
+ return WINBINDD_OK;
+}
+
+struct domain_info_state {
+ struct winbindd_domain *domain;
+ struct winbindd_cli_state *cli_state;
+};
+
+static void domain_info_init_recv(void *private_data, bool success);
+
+void winbindd_domain_info(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+
+ DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
+ state->request.domain_name));
+
+ domain = find_domain_from_name_noinit(state->request.domain_name);
+
+ if (domain == NULL) {
+ DEBUG(3, ("Did not find domain [%s]\n",
+ state->request.domain_name));
+ request_error(state);
+ return;
+ }
+
+ if (!domain->initialized) {
+ struct domain_info_state *istate;
+
+ istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
+ if (istate == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ request_error(state);
+ return;
+ }
+
+ istate->cli_state = state;
+ istate->domain = domain;
+
+ init_child_connection(domain, domain_info_init_recv, istate);
+
+ return;
+ }
+
+ fstrcpy(state->response.data.domain_info.name,
+ domain->name);
+ fstrcpy(state->response.data.domain_info.alt_name,
+ domain->alt_name);
+ sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
+
+ state->response.data.domain_info.native_mode =
+ domain->native_mode;
+ state->response.data.domain_info.active_directory =
+ domain->active_directory;
+ state->response.data.domain_info.primary =
+ domain->primary;
+
+ request_ok(state);
+}
+
+static void domain_info_init_recv(void *private_data, bool success)
+{
+ struct domain_info_state *istate =
+ (struct domain_info_state *)private_data;
+ struct winbindd_cli_state *state = istate->cli_state;
+ struct winbindd_domain *domain = istate->domain;
+
+ DEBUG(10, ("Got back from child init: %d\n", success));
+
+ if ((!success) || (!domain->initialized)) {
+ DEBUG(5, ("Could not init child for domain %s\n",
+ domain->name));
+ request_error(state);
+ return;
+ }
+
+ fstrcpy(state->response.data.domain_info.name,
+ domain->name);
+ fstrcpy(state->response.data.domain_info.alt_name,
+ domain->alt_name);
+ sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
+
+ state->response.data.domain_info.native_mode =
+ domain->native_mode;
+ state->response.data.domain_info.active_directory =
+ domain->active_directory;
+ state->response.data.domain_info.primary =
+ domain->primary;
+
+ request_ok(state);
+}
+
+void winbindd_ping(struct winbindd_cli_state *state)
+{
+ DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
+ request_ok(state);
+}
+
+/* List various tidbits of information */
+
+void winbindd_info(struct winbindd_cli_state *state)
+{
+
+ DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
+
+ state->response.data.info.winbind_separator = *lp_winbind_separator();
+ fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
+ request_ok(state);
+}
+
+/* Tell the client the current interface version */
+
+void winbindd_interface_version(struct winbindd_cli_state *state)
+{
+ DEBUG(3, ("[%5lu]: request interface version\n",
+ (unsigned long)state->pid));
+
+ state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
+ request_ok(state);
+}
+
+/* What domain are we a member of? */
+
+void winbindd_domain_name(struct winbindd_cli_state *state)
+{
+ DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
+
+ fstrcpy(state->response.data.domain_name, lp_workgroup());
+ request_ok(state);
+}
+
+/* What's my name again? */
+
+void winbindd_netbios_name(struct winbindd_cli_state *state)
+{
+ DEBUG(3, ("[%5lu]: request netbios name\n",
+ (unsigned long)state->pid));
+
+ fstrcpy(state->response.data.netbios_name, global_myname());
+ request_ok(state);
+}
+
+/* Where can I find the privilaged pipe? */
+
+void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
+{
+
+ DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
+ (unsigned long)state->pid));
+
+ state->response.extra_data.data = SMB_STRDUP(get_winbind_priv_pipe_dir());
+ if (!state->response.extra_data.data) {
+ DEBUG(0, ("malloc failed\n"));
+ request_error(state);
+ return;
+ }
+
+ /* must add one to length to copy the 0 for string termination */
+ state->response.length +=
+ strlen((char *)state->response.extra_data.data) + 1;
+
+ request_ok(state);
+}
+
diff --git a/source3/winbindd/winbindd_ndr.c b/source3/winbindd/winbindd_ndr.c
new file mode 100644
index 0000000000..3e3ca3225c
--- /dev/null
+++ b/source3/winbindd/winbindd_ndr.c
@@ -0,0 +1,156 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * winbindd debug helper
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+/****************************************************************
+****************************************************************/
+
+void ndr_print_winbindd_child(struct ndr_print *ndr,
+ const char *name,
+ const struct winbindd_child *r)
+{
+ ndr_print_struct(ndr, name, "winbindd_child");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "next", r->next);
+ ndr_print_ptr(ndr, "prev", r->prev);
+ ndr_print_uint32(ndr, "pid", (uint32_t)r->pid);
+#if 0
+ ndr_print_winbindd_domain(ndr, "domain", r->domain);
+#else
+ ndr_print_ptr(ndr, "domain", r->domain);
+#endif
+ ndr_print_string(ndr, "logfilename", r->logfilename);
+ /* struct fd_event event; */
+ ndr_print_ptr(ndr, "lockout_policy_event", r->lockout_policy_event);
+ ndr_print_ptr(ndr, "requests", r->requests);
+ ndr_print_ptr(ndr, "table", r->table);
+ ndr->depth--;
+}
+
+/****************************************************************
+****************************************************************/
+
+void ndr_print_winbindd_cm_conn(struct ndr_print *ndr,
+ const char *name,
+ const struct winbindd_cm_conn *r)
+{
+ ndr_print_struct(ndr, name, "winbindd_cm_conn");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "cli", r->cli);
+ ndr_print_ptr(ndr, "samr_pipe", r->samr_pipe);
+ ndr_print_policy_handle(ndr, "sam_connect_handle", &r->sam_connect_handle);
+ ndr_print_policy_handle(ndr, "sam_domain_handle", &r->sam_domain_handle);
+ ndr_print_ptr(ndr, "lsa_pipe", r->lsa_pipe);
+ ndr_print_policy_handle(ndr, "lsa_policy", &r->lsa_policy);
+ ndr_print_ptr(ndr, "netlogon_pipe", r->netlogon_pipe);
+ ndr->depth--;
+}
+
+/****************************************************************
+****************************************************************/
+
+#ifdef HAVE_ADS
+extern struct winbindd_methods ads_methods;
+#endif
+extern struct winbindd_methods msrpc_methods;
+extern struct winbindd_methods builtin_passdb_methods;
+extern struct winbindd_methods sam_passdb_methods;
+extern struct winbindd_methods reconnect_methods;
+extern struct winbindd_methods cache_methods;
+
+void ndr_print_winbindd_methods(struct ndr_print *ndr,
+ const char *name,
+ const struct winbindd_methods *r)
+{
+ ndr_print_struct(ndr, name, "winbindd_methods");
+ ndr->depth++;
+
+ if (r == NULL) {
+ ndr_print_string(ndr, name, "(NULL)");
+ ndr->depth--;
+ return;
+ }
+
+ if (r == &msrpc_methods) {
+ ndr_print_string(ndr, name, "msrpc_methods");
+#ifdef HAVE_ADS
+ } else if (r == &ads_methods) {
+ ndr_print_string(ndr, name, "ads_methods");
+#endif
+ } else if (r == &builtin_passdb_methods) {
+ ndr_print_string(ndr, name, "builtin_passdb_methods");
+ } else if (r == &sam_passdb_methods) {
+ ndr_print_string(ndr, name, "sam_passdb_methods");
+ } else if (r == &reconnect_methods) {
+ ndr_print_string(ndr, name, "reconnect_methods");
+ } else if (r == &cache_methods) {
+ ndr_print_string(ndr, name, "cache_methods");
+ } else {
+ ndr_print_string(ndr, name, "UNKNOWN");
+ }
+ ndr->depth--;
+}
+
+/****************************************************************
+****************************************************************/
+
+void ndr_print_winbindd_domain(struct ndr_print *ndr,
+ const char *name,
+ const struct winbindd_domain *r)
+{
+ if (!r) {
+ return;
+ }
+
+ ndr_print_struct(ndr, name, "winbindd_domain");
+ ndr->depth++;
+ ndr_print_string(ndr, "name", r->name);
+ ndr_print_string(ndr, "alt_name", r->alt_name);
+ ndr_print_string(ndr, "forest_name", r->forest_name);
+ ndr_print_dom_sid(ndr, "sid", &r->sid);
+ ndr_print_netr_TrustFlags(ndr, "domain_flags", r->domain_flags);
+ ndr_print_netr_TrustType(ndr, "domain_type", r->domain_type);
+ ndr_print_netr_TrustAttributes(ndr, "domain_trust_attribs", r->domain_trust_attribs);
+ ndr_print_bool(ndr, "initialized", r->initialized);
+ ndr_print_bool(ndr, "native_mode", r->native_mode);
+ ndr_print_bool(ndr, "active_directory", r->active_directory);
+ ndr_print_bool(ndr, "primary", r->primary);
+ ndr_print_bool(ndr, "internal", r->internal);
+ ndr_print_bool(ndr, "online", r->online);
+ ndr_print_time_t(ndr, "startup_time", r->startup_time);
+ ndr_print_bool(ndr, "startup", r->startup);
+ ndr_print_winbindd_methods(ndr, "methods", r->methods);
+ ndr_print_winbindd_methods(ndr, "backend", r->backend);
+ ndr_print_ptr(ndr, "private_data", r->private_data);
+ ndr_print_string(ndr, "dcname", r->dcname);
+ ndr_print_sockaddr_storage(ndr, "dcaddr", &r->dcaddr);
+ ndr_print_time_t(ndr, "last_seq_check", r->last_seq_check);
+ ndr_print_uint32(ndr, "sequence_number", r->sequence_number);
+ ndr_print_NTSTATUS(ndr, "last_status", r->last_status);
+ ndr_print_winbindd_cm_conn(ndr, "conn", &r->conn);
+ ndr_print_winbindd_child(ndr, "child", &r->child);
+ ndr_print_uint32(ndr, "check_online_timeout", r->check_online_timeout);
+ ndr_print_ptr(ndr, "check_online_event", r->check_online_event);
+ ndr->depth--;
+}
diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
new file mode 100644
index 0000000000..d4a2e3ed79
--- /dev/null
+++ b/source3/winbindd/winbindd_pam.c
@@ -0,0 +1,2431 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon - pam auth funcions
+
+ Copyright (C) Andrew Tridgell 2000
+ Copyright (C) Tim Potter 2001
+ Copyright (C) Andrew Bartlett 2001-2002
+ Copyright (C) Guenther Deschner 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+#define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
+
+static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
+ struct winbindd_cli_state *state,
+ struct netr_SamInfo3 *info3)
+{
+ char *ex;
+ size_t size;
+ uint32_t i;
+
+ state->response.data.auth.info3.logon_time =
+ nt_time_to_unix(info3->base.last_logon);
+ state->response.data.auth.info3.logoff_time =
+ nt_time_to_unix(info3->base.last_logoff);
+ state->response.data.auth.info3.kickoff_time =
+ nt_time_to_unix(info3->base.acct_expiry);
+ state->response.data.auth.info3.pass_last_set_time =
+ nt_time_to_unix(info3->base.last_password_change);
+ state->response.data.auth.info3.pass_can_change_time =
+ nt_time_to_unix(info3->base.allow_password_change);
+ state->response.data.auth.info3.pass_must_change_time =
+ nt_time_to_unix(info3->base.force_password_change);
+
+ state->response.data.auth.info3.logon_count = info3->base.logon_count;
+ state->response.data.auth.info3.bad_pw_count = info3->base.bad_password_count;
+
+ state->response.data.auth.info3.user_rid = info3->base.rid;
+ state->response.data.auth.info3.group_rid = info3->base.primary_gid;
+ sid_to_fstring(state->response.data.auth.info3.dom_sid, info3->base.domain_sid);
+
+ state->response.data.auth.info3.num_groups = info3->base.groups.count;
+ state->response.data.auth.info3.user_flgs = info3->base.user_flags;
+
+ state->response.data.auth.info3.acct_flags = info3->base.acct_flags;
+ state->response.data.auth.info3.num_other_sids = info3->sidcount;
+
+ fstrcpy(state->response.data.auth.info3.user_name,
+ info3->base.account_name.string);
+ fstrcpy(state->response.data.auth.info3.full_name,
+ info3->base.full_name.string);
+ fstrcpy(state->response.data.auth.info3.logon_script,
+ info3->base.logon_script.string);
+ fstrcpy(state->response.data.auth.info3.profile_path,
+ info3->base.profile_path.string);
+ fstrcpy(state->response.data.auth.info3.home_dir,
+ info3->base.home_directory.string);
+ fstrcpy(state->response.data.auth.info3.dir_drive,
+ info3->base.home_drive.string);
+
+ fstrcpy(state->response.data.auth.info3.logon_srv,
+ info3->base.logon_server.string);
+ fstrcpy(state->response.data.auth.info3.logon_dom,
+ info3->base.domain.string);
+
+ ex = talloc_strdup(mem_ctx, "");
+ NT_STATUS_HAVE_NO_MEMORY(ex);
+
+ for (i=0; i < info3->base.groups.count; i++) {
+ ex = talloc_asprintf_append_buffer(ex, "0x%08X:0x%08X\n",
+ info3->base.groups.rids[i].rid,
+ info3->base.groups.rids[i].attributes);
+ NT_STATUS_HAVE_NO_MEMORY(ex);
+ }
+
+ for (i=0; i < info3->sidcount; i++) {
+ char *sid;
+
+ sid = dom_sid_string(mem_ctx, info3->sids[i].sid);
+ NT_STATUS_HAVE_NO_MEMORY(sid);
+
+ ex = talloc_asprintf_append_buffer(ex, "%s:0x%08X\n",
+ sid,
+ info3->sids[i].attributes);
+ NT_STATUS_HAVE_NO_MEMORY(ex);
+
+ talloc_free(sid);
+ }
+
+ size = talloc_get_size(ex);
+
+ SAFE_FREE(state->response.extra_data.data);
+ state->response.extra_data.data = SMB_MALLOC(size);
+ if (!state->response.extra_data.data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ memcpy(state->response.extra_data.data, ex, size);
+ talloc_free(ex);
+
+ state->response.length += size;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx,
+ struct winbindd_cli_state *state,
+ struct netr_SamInfo3 *info3)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_push_struct_blob(&blob, mem_ctx, info3,
+ (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0,("append_info3_as_ndr: failed to append\n"));
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ SAFE_FREE(state->response.extra_data.data);
+ state->response.extra_data.data = SMB_MALLOC(blob.length);
+ if (!state->response.extra_data.data) {
+ data_blob_free(&blob);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ memset(state->response.extra_data.data, '\0', blob.length);
+ memcpy(state->response.extra_data.data, blob.data, blob.length);
+ state->response.length += blob.length;
+
+ data_blob_free(&blob);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS append_unix_username(TALLOC_CTX *mem_ctx,
+ struct winbindd_cli_state *state,
+ const struct netr_SamInfo3 *info3,
+ const char *name_domain,
+ const char *name_user)
+{
+ /* We've been asked to return the unix username, per
+ 'winbind use default domain' settings and the like */
+
+ const char *nt_username, *nt_domain;
+
+ nt_domain = talloc_strdup(mem_ctx, info3->base.domain.string);
+ if (!nt_domain) {
+ /* If the server didn't give us one, just use the one
+ * we sent them */
+ nt_domain = name_domain;
+ }
+
+ nt_username = talloc_strdup(mem_ctx, info3->base.account_name.string);
+ if (!nt_username) {
+ /* If the server didn't give us one, just use the one
+ * we sent them */
+ nt_username = name_user;
+ }
+
+ fill_domain_username(state->response.data.auth.unix_username,
+ nt_domain, nt_username, true);
+
+ DEBUG(5,("Setting unix username to [%s]\n",
+ state->response.data.auth.unix_username));
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS append_afs_token(TALLOC_CTX *mem_ctx,
+ struct winbindd_cli_state *state,
+ const struct netr_SamInfo3 *info3,
+ const char *name_domain,
+ const char *name_user)
+{
+ char *afsname = NULL;
+ char *cell;
+
+ afsname = talloc_strdup(mem_ctx, lp_afs_username_map());
+ if (afsname == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ afsname = talloc_string_sub(mem_ctx,
+ lp_afs_username_map(),
+ "%D", name_domain);
+ afsname = talloc_string_sub(mem_ctx, afsname,
+ "%u", name_user);
+ afsname = talloc_string_sub(mem_ctx, afsname,
+ "%U", name_user);
+
+ {
+ DOM_SID user_sid;
+ fstring sidstr;
+
+ sid_copy(&user_sid, info3->base.domain_sid);
+ sid_append_rid(&user_sid, info3->base.rid);
+ sid_to_fstring(sidstr, &user_sid);
+ afsname = talloc_string_sub(mem_ctx, afsname,
+ "%s", sidstr);
+ }
+
+ if (afsname == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ strlower_m(afsname);
+
+ DEBUG(10, ("Generating token for user %s\n", afsname));
+
+ cell = strchr(afsname, '@');
+
+ if (cell == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *cell = '\0';
+ cell += 1;
+
+ /* Append an AFS token string */
+ SAFE_FREE(state->response.extra_data.data);
+ state->response.extra_data.data =
+ afs_createtoken_str(afsname, cell);
+
+ if (state->response.extra_data.data != NULL) {
+ state->response.length +=
+ strlen((const char *)state->response.extra_data.data)+1;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS check_info3_in_group(TALLOC_CTX *mem_ctx,
+ struct netr_SamInfo3 *info3,
+ const char *group_sid)
+/**
+ * Check whether a user belongs to a group or list of groups.
+ *
+ * @param mem_ctx talloc memory context.
+ * @param info3 user information, including group membership info.
+ * @param group_sid One or more groups , separated by commas.
+ *
+ * @return NT_STATUS_OK on success,
+ * NT_STATUS_LOGON_FAILURE if the user does not belong,
+ * or other NT_STATUS_IS_ERR(status) for other kinds of failure.
+ */
+{
+ DOM_SID *require_membership_of_sid;
+ size_t num_require_membership_of_sid;
+ char *req_sid;
+ const char *p;
+ DOM_SID sid;
+ size_t i;
+ struct nt_user_token *token;
+ TALLOC_CTX *frame = NULL;
+ NTSTATUS status;
+
+ /* Parse the 'required group' SID */
+
+ if (!group_sid || !group_sid[0]) {
+ /* NO sid supplied, all users may access */
+ return NT_STATUS_OK;
+ }
+
+ if (!(token = TALLOC_ZERO_P(mem_ctx, struct nt_user_token))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ num_require_membership_of_sid = 0;
+ require_membership_of_sid = NULL;
+
+ p = group_sid;
+
+ frame = talloc_stackframe();
+ while (next_token_talloc(frame, &p, &req_sid, ",")) {
+ if (!string_to_sid(&sid, req_sid)) {
+ DEBUG(0, ("check_info3_in_group: could not parse %s "
+ "as a SID!", req_sid));
+ TALLOC_FREE(frame);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = add_sid_to_array(mem_ctx, &sid,
+ &require_membership_of_sid,
+ &num_require_membership_of_sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("add_sid_to_array failed\n"));
+ TALLOC_FREE(frame);
+ return status;
+ }
+ }
+
+ TALLOC_FREE(frame);
+
+ status = sid_array_from_info3(mem_ctx, info3,
+ &token->user_sids,
+ &token->num_sids,
+ true, false);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (!NT_STATUS_IS_OK(status = add_aliases(get_global_sam_sid(),
+ token))
+ || !NT_STATUS_IS_OK(status = add_aliases(&global_sid_Builtin,
+ token))) {
+ DEBUG(3, ("could not add aliases: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ debug_nt_user_token(DBGC_CLASS, 10, token);
+
+ for (i=0; i<num_require_membership_of_sid; i++) {
+ DEBUG(10, ("Checking SID %s\n", sid_string_dbg(
+ &require_membership_of_sid[i])));
+ if (nt_token_check_sid(&require_membership_of_sid[i],
+ token)) {
+ DEBUG(10, ("Access ok\n"));
+ return NT_STATUS_OK;
+ }
+ }
+
+ /* Do not distinguish this error from a wrong username/pw */
+
+ return NT_STATUS_LOGON_FAILURE;
+}
+
+struct winbindd_domain *find_auth_domain(struct winbindd_cli_state *state,
+ const char *domain_name)
+{
+ struct winbindd_domain *domain;
+
+ if (IS_DC) {
+ domain = find_domain_from_name_noinit(domain_name);
+ if (domain == NULL) {
+ DEBUG(3, ("Authentication for domain [%s] refused "
+ "as it is not a trusted domain\n",
+ domain_name));
+ }
+ return domain;
+ }
+
+ if (is_myname(domain_name)) {
+ DEBUG(3, ("Authentication for domain %s (local domain "
+ "to this server) not supported at this "
+ "stage\n", domain_name));
+ return NULL;
+ }
+
+ /* we can auth against trusted domains */
+ if (state->request.flags & WBFLAG_PAM_CONTACT_TRUSTDOM) {
+ domain = find_domain_from_name_noinit(domain_name);
+ if (domain == NULL) {
+ DEBUG(3, ("Authentication for domain [%s] skipped "
+ "as it is not a trusted domain\n",
+ domain_name));
+ } else {
+ return domain;
+ }
+ }
+
+ return find_our_domain();
+}
+
+static void fill_in_password_policy(struct winbindd_response *r,
+ const struct samr_DomInfo1 *p)
+{
+ r->data.auth.policy.min_length_password =
+ p->min_password_length;
+ r->data.auth.policy.password_history =
+ p->password_history_length;
+ r->data.auth.policy.password_properties =
+ p->password_properties;
+ r->data.auth.policy.expire =
+ nt_time_to_unix_abs((NTTIME *)&(p->max_password_age));
+ r->data.auth.policy.min_passwordage =
+ nt_time_to_unix_abs((NTTIME *)&(p->min_password_age));
+}
+
+static NTSTATUS fillup_password_policy(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ struct winbindd_methods *methods;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ struct samr_DomInfo1 password_policy;
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(5,("fillup_password_policy: No inbound trust to "
+ "contact domain %s\n", domain->name));
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ methods = domain->methods;
+
+ status = methods->password_policy(domain, state->mem_ctx, &password_policy);
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ fill_in_password_policy(&state->response, &password_policy);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS get_max_bad_attempts_from_lockout_policy(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint16 *lockout_threshold)
+{
+ struct winbindd_methods *methods;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ struct samr_DomInfo12 lockout_policy;
+
+ *lockout_threshold = 0;
+
+ methods = domain->methods;
+
+ status = methods->lockout_policy(domain, mem_ctx, &lockout_policy);
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ *lockout_threshold = lockout_policy.lockout_threshold;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS get_pwd_properties(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *password_properties)
+{
+ struct winbindd_methods *methods;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ struct samr_DomInfo1 password_policy;
+
+ *password_properties = 0;
+
+ methods = domain->methods;
+
+ status = methods->password_policy(domain, mem_ctx, &password_policy);
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ *password_properties = password_policy.password_properties;
+
+ return NT_STATUS_OK;
+}
+
+#ifdef HAVE_KRB5
+
+static const char *generate_krb5_ccache(TALLOC_CTX *mem_ctx,
+ const char *type,
+ uid_t uid,
+ bool *internal_ccache)
+{
+ /* accept FILE and WRFILE as krb5_cc_type from the client and then
+ * build the full ccname string based on the user's uid here -
+ * Guenther*/
+
+ const char *gen_cc = NULL;
+
+ *internal_ccache = true;
+
+ if (uid == -1) {
+ goto memory_ccache;
+ }
+
+ if (!type || type[0] == '\0') {
+ goto memory_ccache;
+ }
+
+ if (strequal(type, "FILE")) {
+ gen_cc = talloc_asprintf(mem_ctx, "FILE:/tmp/krb5cc_%d", uid);
+ } else if (strequal(type, "WRFILE")) {
+ gen_cc = talloc_asprintf(mem_ctx, "WRFILE:/tmp/krb5cc_%d", uid);
+ } else {
+ DEBUG(10,("we don't allow to set a %s type ccache\n", type));
+ goto memory_ccache;
+ }
+
+ *internal_ccache = false;
+ goto done;
+
+ memory_ccache:
+ gen_cc = talloc_strdup(mem_ctx, "MEMORY:winbindd_pam_ccache");
+
+ done:
+ if (gen_cc == NULL) {
+ DEBUG(0,("out of memory\n"));
+ return NULL;
+ }
+
+ DEBUG(10,("using ccache: %s %s\n", gen_cc, *internal_ccache ? "(internal)":""));
+
+ return gen_cc;
+}
+
+static void setup_return_cc_name(struct winbindd_cli_state *state, const char *cc)
+{
+ const char *type = state->request.data.auth.krb5_cc_type;
+
+ state->response.data.auth.krb5ccname[0] = '\0';
+
+ if (type[0] == '\0') {
+ return;
+ }
+
+ if (!strequal(type, "FILE") &&
+ !strequal(type, "WRFILE")) {
+ DEBUG(10,("won't return krbccname for a %s type ccache\n",
+ type));
+ return;
+ }
+
+ fstrcpy(state->response.data.auth.krb5ccname, cc);
+}
+
+#endif
+
+static uid_t get_uid_from_state(struct winbindd_cli_state *state)
+{
+ uid_t uid = -1;
+
+ uid = state->request.data.auth.uid;
+
+ if (uid < 0) {
+ DEBUG(1,("invalid uid: '%d'\n", uid));
+ return -1;
+ }
+ return uid;
+}
+
+/**********************************************************************
+ Authenticate a user with a clear text password using Kerberos and fill up
+ ccache if required
+ **********************************************************************/
+
+static NTSTATUS winbindd_raw_kerberos_login(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state,
+ struct netr_SamInfo3 **info3)
+{
+#ifdef HAVE_KRB5
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ krb5_error_code krb5_ret;
+ const char *cc = NULL;
+ const char *principal_s = NULL;
+ const char *service = NULL;
+ char *realm = NULL;
+ fstring name_domain, name_user;
+ time_t ticket_lifetime = 0;
+ time_t renewal_until = 0;
+ uid_t uid = -1;
+ ADS_STRUCT *ads;
+ time_t time_offset = 0;
+ bool internal_ccache = true;
+
+ ZERO_STRUCTP(info3);
+
+ *info3 = NULL;
+
+ /* 1st step:
+ * prepare a krb5_cc_cache string for the user */
+
+ uid = get_uid_from_state(state);
+ if (uid == -1) {
+ DEBUG(0,("no valid uid\n"));
+ }
+
+ cc = generate_krb5_ccache(state->mem_ctx,
+ state->request.data.auth.krb5_cc_type,
+ state->request.data.auth.uid,
+ &internal_ccache);
+ if (cc == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+
+ /* 2nd step:
+ * get kerberos properties */
+
+ if (domain->private_data) {
+ ads = (ADS_STRUCT *)domain->private_data;
+ time_offset = ads->auth.time_offset;
+ }
+
+
+ /* 3rd step:
+ * do kerberos auth and setup ccache as the user */
+
+ parse_domain_user(state->request.data.auth.user, name_domain, name_user);
+
+ realm = domain->alt_name;
+ strupper_m(realm);
+
+ principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
+ if (principal_s == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
+ if (service == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* if this is a user ccache, we need to act as the user to let the krb5
+ * library handle the chown, etc. */
+
+ /************************ ENTERING NON-ROOT **********************/
+
+ if (!internal_ccache) {
+ set_effective_uid(uid);
+ DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid));
+ }
+
+ result = kerberos_return_info3_from_pac(state->mem_ctx,
+ principal_s,
+ state->request.data.auth.pass,
+ time_offset,
+ &ticket_lifetime,
+ &renewal_until,
+ cc,
+ true,
+ true,
+ WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
+ info3);
+ if (!internal_ccache) {
+ gain_root_privilege();
+ }
+
+ /************************ RETURNED TO ROOT **********************/
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto failed;
+ }
+
+ DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
+ principal_s));
+
+ /* if we had a user's ccache then return that string for the pam
+ * environment */
+
+ if (!internal_ccache) {
+
+ setup_return_cc_name(state, cc);
+
+ result = add_ccache_to_list(principal_s,
+ cc,
+ service,
+ state->request.data.auth.user,
+ realm,
+ uid,
+ time(NULL),
+ ticket_lifetime,
+ renewal_until,
+ false);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
+ nt_errstr(result)));
+ }
+ } else {
+
+ /* need to delete the memory cred cache, it is not used anymore */
+
+ krb5_ret = ads_kdestroy(cc);
+ if (krb5_ret) {
+ DEBUG(3,("winbindd_raw_kerberos_login: "
+ "could not destroy krb5 credential cache: "
+ "%s\n", error_message(krb5_ret)));
+ }
+
+ }
+
+ return NT_STATUS_OK;
+
+failed:
+
+ /* we could have created a new credential cache with a valid tgt in it
+ * but we werent able to get or verify the service ticket for this
+ * local host and therefor didn't get the PAC, we need to remove that
+ * cache entirely now */
+
+ krb5_ret = ads_kdestroy(cc);
+ if (krb5_ret) {
+ DEBUG(3,("winbindd_raw_kerberos_login: "
+ "could not destroy krb5 credential cache: "
+ "%s\n", error_message(krb5_ret)));
+ }
+
+ if (!NT_STATUS_IS_OK(remove_ccache(state->request.data.auth.user))) {
+ DEBUG(3,("winbindd_raw_kerberos_login: "
+ "could not remove ccache for user %s\n",
+ state->request.data.auth.user));
+ }
+
+ return result;
+#else
+ return NT_STATUS_NOT_SUPPORTED;
+#endif /* HAVE_KRB5 */
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool check_request_flags(uint32_t flags)
+{
+ uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
+ WBFLAG_PAM_INFO3_TEXT |
+ WBFLAG_PAM_INFO3_NDR;
+
+ if ( ( (flags & flags_edata) == WBFLAG_PAM_AFS_TOKEN) ||
+ ( (flags & flags_edata) == WBFLAG_PAM_INFO3_NDR) ||
+ ( (flags & flags_edata) == WBFLAG_PAM_INFO3_TEXT)||
+ !(flags & flags_edata) ) {
+ return true;
+ }
+
+ DEBUG(1,("check_request_flags: invalid request flags[0x%08X]\n",flags));
+
+ return false;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS append_data(struct winbindd_cli_state *state,
+ struct netr_SamInfo3 *info3,
+ const char *name_domain,
+ const char *name_user)
+{
+ NTSTATUS result;
+ uint32_t flags = state->request.flags;
+
+ if (flags & WBFLAG_PAM_USER_SESSION_KEY) {
+ memcpy(state->response.data.auth.user_session_key,
+ info3->base.key.key,
+ sizeof(state->response.data.auth.user_session_key)
+ /* 16 */);
+ }
+
+ if (flags & WBFLAG_PAM_LMKEY) {
+ memcpy(state->response.data.auth.first_8_lm_hash,
+ info3->base.LMSessKey.key,
+ sizeof(state->response.data.auth.first_8_lm_hash)
+ /* 8 */);
+ }
+
+ if (flags & WBFLAG_PAM_INFO3_TEXT) {
+ result = append_info3_as_txt(state->mem_ctx, state, info3);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
+ nt_errstr(result)));
+ return result;
+ }
+ }
+
+ /* currently, anything from here on potentially overwrites extra_data. */
+
+ if (flags & WBFLAG_PAM_INFO3_NDR) {
+ result = append_info3_as_ndr(state->mem_ctx, state, info3);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
+ nt_errstr(result)));
+ return result;
+ }
+ }
+
+ if (flags & WBFLAG_PAM_UNIX_NAME) {
+ result = append_unix_username(state->mem_ctx, state, info3,
+ name_domain, name_user);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("Failed to append Unix Username: %s\n",
+ nt_errstr(result)));
+ return result;
+ }
+ }
+
+ if (flags & WBFLAG_PAM_AFS_TOKEN) {
+ result = append_afs_token(state->mem_ctx, state, info3,
+ name_domain, name_user);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("Failed to append AFS token: %s\n",
+ nt_errstr(result)));
+ return result;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+void winbindd_pam_auth(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+ fstring name_domain, name_user;
+ NTSTATUS result;
+
+ /* Ensure null termination */
+ state->request.data.auth.user
+ [sizeof(state->request.data.auth.user)-1]='\0';
+
+ /* Ensure null termination */
+ state->request.data.auth.pass
+ [sizeof(state->request.data.auth.pass)-1]='\0';
+
+ DEBUG(3, ("[%5lu]: pam auth %s\n", (unsigned long)state->pid,
+ state->request.data.auth.user));
+
+ if (!check_request_flags(state->request.flags)) {
+ result = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto done;
+ }
+
+ /* Parse domain and username */
+
+ ws_name_return( state->request.data.auth.user, WB_REPLACE_CHAR );
+
+ if (!canonicalize_username(state->request.data.auth.user,
+ name_domain, name_user)) {
+ result = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ }
+
+ domain = find_auth_domain(state, name_domain);
+
+ if (domain == NULL) {
+ result = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ }
+
+ sendto_domain(state, domain);
+ return;
+ done:
+ set_auth_errors(&state->response, result);
+ DEBUG(5, ("Plain text authentication for %s returned %s "
+ "(PAM: %d)\n",
+ state->request.data.auth.user,
+ state->response.data.auth.nt_status_string,
+ state->response.data.auth.pam_error));
+ request_error(state);
+}
+
+NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state,
+ struct netr_SamInfo3 **info3)
+{
+ NTSTATUS result = NT_STATUS_LOGON_FAILURE;
+ uint16 max_allowed_bad_attempts;
+ fstring name_domain, name_user;
+ DOM_SID sid;
+ enum lsa_SidType type;
+ uchar new_nt_pass[NT_HASH_LEN];
+ const uint8 *cached_nt_pass;
+ const uint8 *cached_salt;
+ struct netr_SamInfo3 *my_info3;
+ time_t kickoff_time, must_change_time;
+ bool password_good = false;
+#ifdef HAVE_KRB5
+ struct winbindd_tdc_domain *tdc_domain = NULL;
+#endif
+
+ *info3 = NULL;
+
+ ZERO_STRUCTP(info3);
+
+ DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
+
+ /* Parse domain and username */
+
+ parse_domain_user(state->request.data.auth.user, name_domain, name_user);
+
+
+ if (!lookup_cached_name(state->mem_ctx,
+ name_domain,
+ name_user,
+ &sid,
+ &type)) {
+ DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (type != SID_NAME_USER) {
+ DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type)));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ result = winbindd_get_creds(domain,
+ state->mem_ctx,
+ &sid,
+ &my_info3,
+ &cached_nt_pass,
+ &cached_salt);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
+ return result;
+ }
+
+ *info3 = my_info3;
+
+ E_md4hash(state->request.data.auth.pass, new_nt_pass);
+
+ dump_data_pw("new_nt_pass", new_nt_pass, NT_HASH_LEN);
+ dump_data_pw("cached_nt_pass", cached_nt_pass, NT_HASH_LEN);
+ if (cached_salt) {
+ dump_data_pw("cached_salt", cached_salt, NT_HASH_LEN);
+ }
+
+ if (cached_salt) {
+ /* In this case we didn't store the nt_hash itself,
+ but the MD5 combination of salt + nt_hash. */
+ uchar salted_hash[NT_HASH_LEN];
+ E_md5hash(cached_salt, new_nt_pass, salted_hash);
+
+ password_good = (memcmp(cached_nt_pass, salted_hash, NT_HASH_LEN) == 0) ?
+ true : false;
+ } else {
+ /* Old cached cred - direct store of nt_hash (bad bad bad !). */
+ password_good = (memcmp(cached_nt_pass, new_nt_pass, NT_HASH_LEN) == 0) ?
+ true : false;
+ }
+
+ if (password_good) {
+
+ /* User *DOES* know the password, update logon_time and reset
+ * bad_pw_count */
+
+ my_info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
+
+ if (my_info3->base.acct_flags & ACB_AUTOLOCK) {
+ return NT_STATUS_ACCOUNT_LOCKED_OUT;
+ }
+
+ if (my_info3->base.acct_flags & ACB_DISABLED) {
+ return NT_STATUS_ACCOUNT_DISABLED;
+ }
+
+ if (my_info3->base.acct_flags & ACB_WSTRUST) {
+ return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
+ }
+
+ if (my_info3->base.acct_flags & ACB_SVRTRUST) {
+ return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
+ }
+
+ if (my_info3->base.acct_flags & ACB_DOMTRUST) {
+ return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
+ }
+
+ if (!(my_info3->base.acct_flags & ACB_NORMAL)) {
+ DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
+ my_info3->base.acct_flags));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ kickoff_time = nt_time_to_unix(my_info3->base.acct_expiry);
+ if (kickoff_time != 0 && time(NULL) > kickoff_time) {
+ return NT_STATUS_ACCOUNT_EXPIRED;
+ }
+
+ must_change_time = nt_time_to_unix(my_info3->base.force_password_change);
+ if (must_change_time != 0 && must_change_time < time(NULL)) {
+ /* we allow grace logons when the password has expired */
+ my_info3->base.user_flags |= NETLOGON_GRACE_LOGON;
+ /* return NT_STATUS_PASSWORD_EXPIRED; */
+ goto success;
+ }
+
+#ifdef HAVE_KRB5
+ if ((state->request.flags & WBFLAG_PAM_KRB5) &&
+ ((tdc_domain = wcache_tdc_fetch_domain(state->mem_ctx, name_domain)) != NULL) &&
+ (tdc_domain->trust_type & NETR_TRUST_TYPE_UPLEVEL)) {
+
+ uid_t uid = -1;
+ const char *cc = NULL;
+ char *realm = NULL;
+ const char *principal_s = NULL;
+ const char *service = NULL;
+ bool internal_ccache = false;
+
+ uid = get_uid_from_state(state);
+ if (uid == -1) {
+ DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ cc = generate_krb5_ccache(state->mem_ctx,
+ state->request.data.auth.krb5_cc_type,
+ state->request.data.auth.uid,
+ &internal_ccache);
+ if (cc == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ realm = domain->alt_name;
+ strupper_m(realm);
+
+ principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
+ if (principal_s == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
+ if (service == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!internal_ccache) {
+
+ setup_return_cc_name(state, cc);
+
+ result = add_ccache_to_list(principal_s,
+ cc,
+ service,
+ state->request.data.auth.user,
+ domain->alt_name,
+ uid,
+ time(NULL),
+ time(NULL) + lp_winbind_cache_time(),
+ time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
+ true);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
+ "to add ccache to list: %s\n",
+ nt_errstr(result)));
+ }
+ }
+ }
+#endif /* HAVE_KRB5 */
+ success:
+ /* FIXME: we possibly should handle logon hours as well (does xp when
+ * offline?) see auth/auth_sam.c:sam_account_ok for details */
+
+ unix_to_nt_time(&my_info3->base.last_logon, time(NULL));
+ my_info3->base.bad_password_count = 0;
+
+ result = winbindd_update_creds_by_info3(domain,
+ state->mem_ctx,
+ state->request.data.auth.user,
+ state->request.data.auth.pass,
+ my_info3);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
+ nt_errstr(result)));
+ return result;
+ }
+
+ return NT_STATUS_OK;
+
+ }
+
+ /* User does *NOT* know the correct password, modify info3 accordingly */
+
+ /* failure of this is not critical */
+ result = get_max_bad_attempts_from_lockout_policy(domain, state->mem_ctx, &max_allowed_bad_attempts);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
+ "Won't be able to honour account lockout policies\n"));
+ }
+
+ /* increase counter */
+ my_info3->base.bad_password_count++;
+
+ if (max_allowed_bad_attempts == 0) {
+ goto failed;
+ }
+
+ /* lockout user */
+ if (my_info3->base.bad_password_count >= max_allowed_bad_attempts) {
+
+ uint32 password_properties;
+
+ result = get_pwd_properties(domain, state->mem_ctx, &password_properties);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
+ }
+
+ if ((my_info3->base.rid != DOMAIN_USER_RID_ADMIN) ||
+ (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
+ my_info3->base.acct_flags |= ACB_AUTOLOCK;
+ }
+ }
+
+failed:
+ result = winbindd_update_creds_by_info3(domain,
+ state->mem_ctx,
+ state->request.data.auth.user,
+ NULL,
+ my_info3);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
+ nt_errstr(result)));
+ }
+
+ return NT_STATUS_LOGON_FAILURE;
+}
+
+NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state,
+ struct netr_SamInfo3 **info3)
+{
+ struct winbindd_domain *contact_domain;
+ fstring name_domain, name_user;
+ NTSTATUS result;
+
+ DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
+
+ /* Parse domain and username */
+
+ parse_domain_user(state->request.data.auth.user, name_domain, name_user);
+
+ /* what domain should we contact? */
+
+ if ( IS_DC ) {
+ if (!(contact_domain = find_domain_from_name(name_domain))) {
+ DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
+ state->request.data.auth.user, name_domain, name_user, name_domain));
+ result = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ }
+
+ } else {
+ if (is_myname(name_domain)) {
+ DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
+ result = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ }
+
+ contact_domain = find_domain_from_name(name_domain);
+ if (contact_domain == NULL) {
+ DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
+ state->request.data.auth.user, name_domain, name_user, name_domain));
+
+ contact_domain = find_our_domain();
+ }
+ }
+
+ if (contact_domain->initialized &&
+ contact_domain->active_directory) {
+ goto try_login;
+ }
+
+ if (!contact_domain->initialized) {
+ init_dc_connection(contact_domain);
+ }
+
+ if (!contact_domain->active_directory) {
+ DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
+ return NT_STATUS_INVALID_LOGON_TYPE;
+ }
+try_login:
+ result = winbindd_raw_kerberos_login(contact_domain, state, info3);
+done:
+ return result;
+}
+
+typedef NTSTATUS (*netlogon_fn_t)(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 logon_parameters,
+ const char *server,
+ const char *username,
+ const char *domain,
+ const char *workstation,
+ const uint8 chal[8],
+ DATA_BLOB lm_response,
+ DATA_BLOB nt_response,
+ struct netr_SamInfo3 **info3);
+
+NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state,
+ struct netr_SamInfo3 **info3)
+{
+
+ struct rpc_pipe_client *netlogon_pipe;
+ uchar chal[8];
+ DATA_BLOB lm_resp;
+ DATA_BLOB nt_resp;
+ int attempts = 0;
+ unsigned char local_lm_response[24];
+ unsigned char local_nt_response[24];
+ struct winbindd_domain *contact_domain;
+ fstring name_domain, name_user;
+ bool retry;
+ NTSTATUS result;
+ struct netr_SamInfo3 *my_info3 = NULL;
+
+ *info3 = NULL;
+
+ DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
+
+ /* Parse domain and username */
+
+ parse_domain_user(state->request.data.auth.user, name_domain, name_user);
+
+ /* do password magic */
+
+
+ generate_random_buffer(chal, 8);
+ if (lp_client_ntlmv2_auth()) {
+ DATA_BLOB server_chal;
+ DATA_BLOB names_blob;
+ DATA_BLOB nt_response;
+ DATA_BLOB lm_response;
+ server_chal = data_blob_talloc(state->mem_ctx, chal, 8);
+
+ /* note that the 'workgroup' here is a best guess - we don't know
+ the server's domain at this point. The 'server name' is also
+ dodgy...
+ */
+ names_blob = NTLMv2_generate_names_blob(global_myname(), lp_workgroup());
+
+ if (!SMBNTLMv2encrypt(name_user, name_domain,
+ state->request.data.auth.pass,
+ &server_chal,
+ &names_blob,
+ &lm_response, &nt_response, NULL)) {
+ data_blob_free(&names_blob);
+ data_blob_free(&server_chal);
+ DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ data_blob_free(&names_blob);
+ data_blob_free(&server_chal);
+ lm_resp = data_blob_talloc(state->mem_ctx, lm_response.data,
+ lm_response.length);
+ nt_resp = data_blob_talloc(state->mem_ctx, nt_response.data,
+ nt_response.length);
+ data_blob_free(&lm_response);
+ data_blob_free(&nt_response);
+
+ } else {
+ if (lp_client_lanman_auth()
+ && SMBencrypt(state->request.data.auth.pass,
+ chal,
+ local_lm_response)) {
+ lm_resp = data_blob_talloc(state->mem_ctx,
+ local_lm_response,
+ sizeof(local_lm_response));
+ } else {
+ lm_resp = data_blob_null;
+ }
+ SMBNTencrypt(state->request.data.auth.pass,
+ chal,
+ local_nt_response);
+
+ nt_resp = data_blob_talloc(state->mem_ctx,
+ local_nt_response,
+ sizeof(local_nt_response));
+ }
+
+ /* what domain should we contact? */
+
+ if ( IS_DC ) {
+ if (!(contact_domain = find_domain_from_name(name_domain))) {
+ DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
+ state->request.data.auth.user, name_domain, name_user, name_domain));
+ result = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ }
+
+ } else {
+ if (is_myname(name_domain)) {
+ DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
+ result = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ }
+
+ contact_domain = find_our_domain();
+ }
+
+ /* check authentication loop */
+
+ do {
+ netlogon_fn_t logon_fn;
+
+ ZERO_STRUCTP(my_info3);
+ retry = false;
+
+ result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
+ goto done;
+ }
+
+ /* It is really important to try SamLogonEx here,
+ * because in a clustered environment, we want to use
+ * one machine account from multiple physical
+ * computers.
+ *
+ * With a normal SamLogon call, we must keep the
+ * credentials chain updated and intact between all
+ * users of the machine account (which would imply
+ * cross-node communication for every NTLM logon).
+ *
+ * (The credentials chain is not per NETLOGON pipe
+ * connection, but globally on the server/client pair
+ * by machine name).
+ *
+ * When using SamLogonEx, the credentials are not
+ * supplied, but the session key is implied by the
+ * wrapping SamLogon context.
+ *
+ * -- abartlet 21 April 2008
+ */
+
+ logon_fn = contact_domain->can_do_samlogon_ex
+ ? rpccli_netlogon_sam_network_logon_ex
+ : rpccli_netlogon_sam_network_logon;
+
+ result = logon_fn(netlogon_pipe,
+ state->mem_ctx,
+ 0,
+ contact_domain->dcname, /* server name */
+ name_user, /* user name */
+ name_domain, /* target domain */
+ global_myname(), /* workstation */
+ chal,
+ lm_resp,
+ nt_resp,
+ &my_info3);
+ attempts += 1;
+
+ if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
+ && contact_domain->can_do_samlogon_ex) {
+ DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
+ "retrying with NetSamLogon\n"));
+ contact_domain->can_do_samlogon_ex = false;
+ retry = true;
+ continue;
+ }
+
+ /* We have to try a second time as cm_connect_netlogon
+ might not yet have noticed that the DC has killed
+ our connection. */
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
+ retry = true;
+ continue;
+ }
+
+ /* if we get access denied, a possible cause was that we had
+ and open connection to the DC, but someone changed our
+ machine account password out from underneath us using 'net
+ rpc changetrustpw' */
+
+ if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
+ DEBUG(3,("winbindd_pam_auth: sam_logon returned "
+ "ACCESS_DENIED. Maybe the trust account "
+ "password was changed and we didn't know it. "
+ "Killing connections to domain %s\n",
+ name_domain));
+ invalidate_cm_connection(&contact_domain->conn);
+ retry = true;
+ }
+
+ } while ( (attempts < 2) && retry );
+
+ /* handle the case where a NT4 DC does not fill in the acct_flags in
+ * the samlogon reply info3. When accurate info3 is required by the
+ * caller, we look up the account flags ourselve - gd */
+
+ if ((state->request.flags & WBFLAG_PAM_INFO3_TEXT) &&
+ NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
+
+ struct rpc_pipe_client *samr_pipe;
+ POLICY_HND samr_domain_handle, user_pol;
+ union samr_UserInfo *info = NULL;
+ NTSTATUS status_tmp;
+ uint32 acct_flags;
+
+ status_tmp = cm_connect_sam(contact_domain, state->mem_ctx,
+ &samr_pipe, &samr_domain_handle);
+
+ if (!NT_STATUS_IS_OK(status_tmp)) {
+ DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
+ nt_errstr(status_tmp)));
+ goto done;
+ }
+
+ status_tmp = rpccli_samr_OpenUser(samr_pipe, state->mem_ctx,
+ &samr_domain_handle,
+ MAXIMUM_ALLOWED_ACCESS,
+ my_info3->base.rid,
+ &user_pol);
+
+ if (!NT_STATUS_IS_OK(status_tmp)) {
+ DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
+ nt_errstr(status_tmp)));
+ goto done;
+ }
+
+ status_tmp = rpccli_samr_QueryUserInfo(samr_pipe, state->mem_ctx,
+ &user_pol,
+ 16,
+ &info);
+
+ if (!NT_STATUS_IS_OK(status_tmp)) {
+ DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
+ nt_errstr(status_tmp)));
+ rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
+ goto done;
+ }
+
+ acct_flags = info->info16.acct_flags;
+
+ if (acct_flags == 0) {
+ rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
+ goto done;
+ }
+
+ my_info3->base.acct_flags = acct_flags;
+
+ DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
+
+ rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
+ }
+
+ *info3 = my_info3;
+done:
+ return result;
+}
+
+enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ NTSTATUS result = NT_STATUS_LOGON_FAILURE;
+ NTSTATUS krb5_result = NT_STATUS_OK;
+ fstring name_domain, name_user;
+ struct netr_SamInfo3 *info3 = NULL;
+
+ /* Ensure null termination */
+ state->request.data.auth.user[sizeof(state->request.data.auth.user)-1]='\0';
+
+ /* Ensure null termination */
+ state->request.data.auth.pass[sizeof(state->request.data.auth.pass)-1]='\0';
+
+ DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
+ state->request.data.auth.user));
+
+ if (!check_request_flags(state->request.flags)) {
+ result = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto done;
+ }
+
+ /* Parse domain and username */
+
+ ws_name_return( state->request.data.auth.user, WB_REPLACE_CHAR );
+
+ parse_domain_user(state->request.data.auth.user, name_domain, name_user);
+
+ if (domain->online == false) {
+ result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+ if (domain->startup) {
+ /* Logons are very important to users. If we're offline and
+ we get a request within the first 30 seconds of startup,
+ try very hard to find a DC and go online. */
+
+ DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
+ "request in startup mode.\n", domain->name ));
+
+ winbindd_flush_negative_conn_cache(domain);
+ result = init_dc_connection(domain);
+ }
+ }
+
+ DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
+
+ /* Check for Kerberos authentication */
+ if (domain->online && (state->request.flags & WBFLAG_PAM_KRB5)) {
+
+ result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
+ /* save for later */
+ krb5_result = result;
+
+
+ if (NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
+ goto process_result;
+ } else {
+ DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
+ }
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
+ DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
+ set_domain_offline( domain );
+ goto cached_logon;
+ }
+
+ /* there are quite some NT_STATUS errors where there is no
+ * point in retrying with a samlogon, we explictly have to take
+ * care not to increase the bad logon counter on the DC */
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
+ goto process_result;
+ }
+
+ if (state->request.flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
+ DEBUG(3,("falling back to samlogon\n"));
+ goto sam_logon;
+ } else {
+ goto cached_logon;
+ }
+ }
+
+sam_logon:
+ /* Check for Samlogon authentication */
+ if (domain->online) {
+ result = winbindd_dual_pam_auth_samlogon(domain, state, &info3);
+
+ if (NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
+ /* add the Krb5 err if we have one */
+ if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
+ info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
+ }
+ goto process_result;
+ }
+
+ DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
+ nt_errstr(result)));
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
+ {
+ DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
+ set_domain_offline( domain );
+ goto cached_logon;
+ }
+
+ if (domain->online) {
+ /* We're still online - fail. */
+ goto done;
+ }
+ }
+
+cached_logon:
+ /* Check for Cached logons */
+ if (!domain->online && (state->request.flags & WBFLAG_PAM_CACHED_LOGIN) &&
+ lp_winbind_offline_logon()) {
+
+ result = winbindd_dual_pam_auth_cached(domain, state, &info3);
+
+ if (NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
+ goto process_result;
+ } else {
+ DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
+ goto done;
+ }
+ }
+
+process_result:
+
+ if (NT_STATUS_IS_OK(result)) {
+
+ DOM_SID user_sid;
+
+ /* In all codepaths where result == NT_STATUS_OK info3 must have
+ been initialized. */
+ if (!info3) {
+ result = NT_STATUS_INTERNAL_ERROR;
+ goto done;
+ }
+
+ wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
+ netsamlogon_cache_store(name_user, info3);
+
+ /* save name_to_sid info as early as possible (only if
+ this is our primary domain so we don't invalidate
+ the cache entry by storing the seq_num for the wrong
+ domain). */
+ if ( domain->primary ) {
+ sid_compose(&user_sid, info3->base.domain_sid,
+ info3->base.rid);
+ cache_name2sid(domain, name_domain, name_user,
+ SID_NAME_USER, &user_sid);
+ }
+
+ /* Check if the user is in the right group */
+
+ if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, info3,
+ state->request.data.auth.require_membership_of_sid))) {
+ DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
+ state->request.data.auth.user,
+ state->request.data.auth.require_membership_of_sid));
+ goto done;
+ }
+
+ result = append_data(state, info3, name_domain, name_user);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ if ((state->request.flags & WBFLAG_PAM_CACHED_LOGIN)) {
+
+ /* Store in-memory creds for single-signon using ntlm_auth. */
+ result = winbindd_add_memory_creds(state->request.data.auth.user,
+ get_uid_from_state(state),
+ state->request.data.auth.pass);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("Failed to store memory creds: %s\n", nt_errstr(result)));
+ goto done;
+ }
+
+ if (lp_winbind_offline_logon()) {
+ result = winbindd_store_creds(domain,
+ state->mem_ctx,
+ state->request.data.auth.user,
+ state->request.data.auth.pass,
+ info3, NULL);
+ if (!NT_STATUS_IS_OK(result)) {
+
+ /* Release refcount. */
+ winbindd_delete_memory_creds(state->request.data.auth.user);
+
+ DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result)));
+ goto done;
+ }
+ }
+ }
+
+
+ if (state->request.flags & WBFLAG_PAM_GET_PWD_POLICY) {
+ struct winbindd_domain *our_domain = find_our_domain();
+
+ /* This is not entirely correct I believe, but it is
+ consistent. Only apply the password policy settings
+ too warn users for our own domain. Cannot obtain these
+ from trusted DCs all the time so don't do it at all.
+ -- jerry */
+
+ result = NT_STATUS_NOT_SUPPORTED;
+ if (our_domain == domain ) {
+ result = fillup_password_policy(our_domain, state);
+ }
+
+ if (!NT_STATUS_IS_OK(result)
+ && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
+ {
+ DEBUG(10,("Failed to get password policies for domain %s: %s\n",
+ domain->name, nt_errstr(result)));
+ goto done;
+ }
+ }
+
+ result = NT_STATUS_OK;
+ }
+
+done:
+ /* give us a more useful (more correct?) error code */
+ if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
+ (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
+ result = NT_STATUS_NO_LOGON_SERVERS;
+ }
+
+ set_auth_errors(&state->response, result);
+
+ DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
+ state->request.data.auth.user,
+ state->response.data.auth.nt_status_string,
+ state->response.data.auth.pam_error));
+
+ return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+
+/**********************************************************************
+ Challenge Response Authentication Protocol
+**********************************************************************/
+
+void winbindd_pam_auth_crap(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain = NULL;
+ const char *domain_name = NULL;
+ NTSTATUS result;
+
+ if (!check_request_flags(state->request.flags)) {
+ result = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto done;
+ }
+
+ if (!state->privileged) {
+ char *error_string = NULL;
+ DEBUG(2, ("winbindd_pam_auth_crap: non-privileged access "
+ "denied. !\n"));
+ DEBUGADD(2, ("winbindd_pam_auth_crap: Ensure permissions "
+ "on %s are set correctly.\n",
+ get_winbind_priv_pipe_dir()));
+ /* send a better message than ACCESS_DENIED */
+ error_string = talloc_asprintf(state->mem_ctx,
+ "winbind client not authorized "
+ "to use winbindd_pam_auth_crap."
+ " Ensure permissions on %s "
+ "are set correctly.",
+ get_winbind_priv_pipe_dir());
+ fstrcpy(state->response.data.auth.error_string, error_string);
+ result = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+
+ /* Ensure null termination */
+ state->request.data.auth_crap.user
+ [sizeof(state->request.data.auth_crap.user)-1]=0;
+ state->request.data.auth_crap.domain
+ [sizeof(state->request.data.auth_crap.domain)-1]=0;
+
+ DEBUG(3, ("[%5lu]: pam auth crap domain: [%s] user: %s\n",
+ (unsigned long)state->pid,
+ state->request.data.auth_crap.domain,
+ state->request.data.auth_crap.user));
+
+ if (*state->request.data.auth_crap.domain != '\0') {
+ domain_name = state->request.data.auth_crap.domain;
+ } else if (lp_winbind_use_default_domain()) {
+ domain_name = lp_workgroup();
+ }
+
+ if (domain_name != NULL)
+ domain = find_auth_domain(state, domain_name);
+
+ if (domain != NULL) {
+ sendto_domain(state, domain);
+ return;
+ }
+
+ result = NT_STATUS_NO_SUCH_USER;
+
+ done:
+ set_auth_errors(&state->response, result);
+ DEBUG(5, ("CRAP authentication for %s\\%s returned %s (PAM: %d)\n",
+ state->request.data.auth_crap.domain,
+ state->request.data.auth_crap.user,
+ state->response.data.auth.nt_status_string,
+ state->response.data.auth.pam_error));
+ request_error(state);
+ return;
+}
+
+
+enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ NTSTATUS result;
+ struct netr_SamInfo3 *info3 = NULL;
+ struct rpc_pipe_client *netlogon_pipe;
+ const char *name_user = NULL;
+ const char *name_domain = NULL;
+ const char *workstation;
+ struct winbindd_domain *contact_domain;
+ int attempts = 0;
+ bool retry;
+
+ DATA_BLOB lm_resp, nt_resp;
+
+ /* This is child-only, so no check for privileged access is needed
+ anymore */
+
+ /* Ensure null termination */
+ state->request.data.auth_crap.user[sizeof(state->request.data.auth_crap.user)-1]=0;
+ state->request.data.auth_crap.domain[sizeof(state->request.data.auth_crap.domain)-1]=0;
+
+ if (!check_request_flags(state->request.flags)) {
+ result = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto done;
+ }
+
+ name_user = state->request.data.auth_crap.user;
+
+ if (*state->request.data.auth_crap.domain) {
+ name_domain = state->request.data.auth_crap.domain;
+ } else if (lp_winbind_use_default_domain()) {
+ name_domain = lp_workgroup();
+ } else {
+ DEBUG(5,("no domain specified with username (%s) - failing auth\n",
+ name_user));
+ result = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ }
+
+ DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
+ name_domain, name_user));
+
+ if (*state->request.data.auth_crap.workstation) {
+ workstation = state->request.data.auth_crap.workstation;
+ } else {
+ workstation = global_myname();
+ }
+
+ if (state->request.data.auth_crap.lm_resp_len > sizeof(state->request.data.auth_crap.lm_resp)
+ || state->request.data.auth_crap.nt_resp_len > sizeof(state->request.data.auth_crap.nt_resp)) {
+ DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
+ state->request.data.auth_crap.lm_resp_len,
+ state->request.data.auth_crap.nt_resp_len));
+ result = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ lm_resp = data_blob_talloc(state->mem_ctx, state->request.data.auth_crap.lm_resp,
+ state->request.data.auth_crap.lm_resp_len);
+ nt_resp = data_blob_talloc(state->mem_ctx, state->request.data.auth_crap.nt_resp,
+ state->request.data.auth_crap.nt_resp_len);
+
+ /* what domain should we contact? */
+
+ if ( IS_DC ) {
+ if (!(contact_domain = find_domain_from_name(name_domain))) {
+ DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
+ state->request.data.auth_crap.user, name_domain, name_user, name_domain));
+ result = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ }
+ } else {
+ if (is_myname(name_domain)) {
+ DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
+ result = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ }
+ contact_domain = find_our_domain();
+ }
+
+ do {
+ netlogon_fn_t logon_fn;
+
+ retry = false;
+
+ netlogon_pipe = NULL;
+ result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n",
+ nt_errstr(result)));
+ goto done;
+ }
+
+ logon_fn = contact_domain->can_do_samlogon_ex
+ ? rpccli_netlogon_sam_network_logon_ex
+ : rpccli_netlogon_sam_network_logon;
+
+ result = logon_fn(netlogon_pipe,
+ state->mem_ctx,
+ state->request.data.auth_crap.logon_parameters,
+ contact_domain->dcname,
+ name_user,
+ name_domain,
+ /* Bug #3248 - found by Stefan Burkei. */
+ workstation, /* We carefully set this above so use it... */
+ state->request.data.auth_crap.chal,
+ lm_resp,
+ nt_resp,
+ &info3);
+
+ if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
+ && contact_domain->can_do_samlogon_ex) {
+ DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
+ "retrying with NetSamLogon\n"));
+ contact_domain->can_do_samlogon_ex = false;
+ retry = true;
+ continue;
+ }
+
+ attempts += 1;
+
+ /* We have to try a second time as cm_connect_netlogon
+ might not yet have noticed that the DC has killed
+ our connection. */
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
+ retry = true;
+ continue;
+ }
+
+ /* if we get access denied, a possible cause was that we had and open
+ connection to the DC, but someone changed our machine account password
+ out from underneath us using 'net rpc changetrustpw' */
+
+ if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
+ DEBUG(3,("winbindd_pam_auth: sam_logon returned "
+ "ACCESS_DENIED. Maybe the trust account "
+ "password was changed and we didn't know it. "
+ "Killing connections to domain %s\n",
+ name_domain));
+ invalidate_cm_connection(&contact_domain->conn);
+ retry = true;
+ }
+
+ } while ( (attempts < 2) && retry );
+
+ if (NT_STATUS_IS_OK(result)) {
+
+ wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
+ netsamlogon_cache_store(name_user, info3);
+
+ /* Check if the user is in the right group */
+
+ if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, info3,
+ state->request.data.auth_crap.require_membership_of_sid))) {
+ DEBUG(3, ("User %s is not in the required group (%s), so "
+ "crap authentication is rejected\n",
+ state->request.data.auth_crap.user,
+ state->request.data.auth_crap.require_membership_of_sid));
+ goto done;
+ }
+
+ result = append_data(state, info3, name_domain, name_user);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+ }
+
+done:
+
+ /* give us a more useful (more correct?) error code */
+ if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
+ (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
+ result = NT_STATUS_NO_LOGON_SERVERS;
+ }
+
+ if (state->request.flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
+ result = nt_status_squash(result);
+ }
+
+ set_auth_errors(&state->response, result);
+
+ DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
+ ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
+ name_domain,
+ name_user,
+ state->response.data.auth.nt_status_string,
+ state->response.data.auth.pam_error));
+
+ return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+/* Change a user password */
+
+void winbindd_pam_chauthtok(struct winbindd_cli_state *state)
+{
+ fstring domain, user;
+ struct winbindd_domain *contact_domain;
+
+ DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid,
+ state->request.data.chauthtok.user));
+
+ /* Setup crap */
+
+ ws_name_return( state->request.data.auth.user, WB_REPLACE_CHAR );
+
+ if (!canonicalize_username(state->request.data.chauthtok.user, domain, user)) {
+ set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
+ DEBUG(5, ("winbindd_pam_chauthtok: canonicalize_username %s failed with %s"
+ "(PAM: %d)\n",
+ state->request.data.auth.user,
+ state->response.data.auth.nt_status_string,
+ state->response.data.auth.pam_error));
+ request_error(state);
+ return;
+ }
+
+ contact_domain = find_domain_from_name(domain);
+ if (!contact_domain) {
+ set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
+ DEBUG(3, ("Cannot change password for [%s] -> [%s]\\[%s] as %s is not a trusted domain\n",
+ state->request.data.chauthtok.user, domain, user, domain));
+ request_error(state);
+ return;
+ }
+
+ sendto_domain(state, contact_domain);
+}
+
+enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
+ struct winbindd_cli_state *state)
+{
+ char *oldpass;
+ char *newpass = NULL;
+ POLICY_HND dom_pol;
+ struct rpc_pipe_client *cli;
+ bool got_info = false;
+ struct samr_DomInfo1 *info = NULL;
+ struct samr_ChangeReject *reject = NULL;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ fstring domain, user;
+
+ DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
+ state->request.data.auth.user));
+
+ if (!parse_domain_user(state->request.data.chauthtok.user, domain, user)) {
+ goto done;
+ }
+
+ /* Change password */
+
+ oldpass = state->request.data.chauthtok.oldpass;
+ newpass = state->request.data.chauthtok.newpass;
+
+ /* Initialize reject reason */
+ state->response.data.auth.reject_reason = Undefined;
+
+ /* Get sam handle */
+
+ result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
+ &dom_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
+ goto done;
+ }
+
+ result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
+ user,
+ newpass,
+ oldpass,
+ &info,
+ &reject);
+
+ /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
+
+ fill_in_password_policy(&state->response, info);
+
+ state->response.data.auth.reject_reason =
+ reject->reason;
+
+ got_info = true;
+ }
+
+ /* only fallback when the chgpasswd_user3 call is not supported */
+ if ((NT_STATUS_EQUAL(result, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR))) ||
+ (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) ||
+ (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED))) {
+
+ DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
+ nt_errstr(result)));
+
+ result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
+
+ /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
+ Map to the same status code as Windows 2003. */
+
+ if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
+ result = NT_STATUS_PASSWORD_RESTRICTION;
+ }
+ }
+
+done:
+
+ if (NT_STATUS_IS_OK(result) && (state->request.flags & WBFLAG_PAM_CACHED_LOGIN)) {
+
+ /* Update the single sign-on memory creds. */
+ result = winbindd_replace_memory_creds(state->request.data.chauthtok.user,
+ newpass);
+
+ /* When we login from gdm or xdm and password expires,
+ * we change password, but there are no memory crendentials
+ * So, winbindd_replace_memory_creds() returns
+ * NT_STATUS_OBJECT_NAME_NOT_FOUND. This is not a failure.
+ * --- BoYang
+ * */
+ if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ result = NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("Failed to replace memory creds: %s\n", nt_errstr(result)));
+ goto process_result;
+ }
+
+ if (lp_winbind_offline_logon()) {
+ result = winbindd_update_creds_by_name(contact_domain,
+ state->mem_ctx, user,
+ newpass);
+ /* Again, this happens when we login from gdm or xdm
+ * and the password expires, *BUT* cached crendentials
+ * doesn't exist. winbindd_update_creds_by_name()
+ * returns NT_STATUS_NO_SUCH_USER.
+ * This is not a failure.
+ * --- BoYang
+ * */
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
+ result = NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result)));
+ goto process_result;
+ }
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
+
+ NTSTATUS policy_ret;
+
+ policy_ret = fillup_password_policy(contact_domain, state);
+
+ /* failure of this is non critical, it will just provide no
+ * additional information to the client why the change has
+ * failed - Guenther */
+
+ if (!NT_STATUS_IS_OK(policy_ret)) {
+ DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
+ goto process_result;
+ }
+ }
+
+process_result:
+
+ set_auth_errors(&state->response, result);
+
+ DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
+ ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
+ domain,
+ user,
+ state->response.data.auth.nt_status_string,
+ state->response.data.auth.pam_error));
+
+ return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+void winbindd_pam_logoff(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+ fstring name_domain, user;
+ uid_t caller_uid = (uid_t)-1;
+ uid_t request_uid = state->request.data.logoff.uid;
+
+ DEBUG(3, ("[%5lu]: pam logoff %s\n", (unsigned long)state->pid,
+ state->request.data.logoff.user));
+
+ /* Ensure null termination */
+ state->request.data.logoff.user
+ [sizeof(state->request.data.logoff.user)-1]='\0';
+
+ state->request.data.logoff.krb5ccname
+ [sizeof(state->request.data.logoff.krb5ccname)-1]='\0';
+
+ if (request_uid == (gid_t)-1) {
+ goto failed;
+ }
+
+ if (!canonicalize_username(state->request.data.logoff.user, name_domain, user)) {
+ goto failed;
+ }
+
+ if ((domain = find_auth_domain(state, name_domain)) == NULL) {
+ goto failed;
+ }
+
+ if ((sys_getpeereid(state->sock, &caller_uid)) != 0) {
+ DEBUG(1,("winbindd_pam_logoff: failed to check peerid: %s\n",
+ strerror(errno)));
+ goto failed;
+ }
+
+ switch (caller_uid) {
+ case -1:
+ goto failed;
+ case 0:
+ /* root must be able to logoff any user - gd */
+ state->request.data.logoff.uid = request_uid;
+ break;
+ default:
+ if (caller_uid != request_uid) {
+ DEBUG(1,("winbindd_pam_logoff: caller requested invalid uid\n"));
+ goto failed;
+ }
+ state->request.data.logoff.uid = caller_uid;
+ break;
+ }
+
+ sendto_domain(state, domain);
+ return;
+
+ failed:
+ set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
+ DEBUG(5, ("Pam Logoff for %s returned %s "
+ "(PAM: %d)\n",
+ state->request.data.logoff.user,
+ state->response.data.auth.nt_status_string,
+ state->response.data.auth.pam_error));
+ request_error(state);
+ return;
+}
+
+enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
+
+ DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
+ state->request.data.logoff.user));
+
+ if (!(state->request.flags & WBFLAG_PAM_KRB5)) {
+ result = NT_STATUS_OK;
+ goto process_result;
+ }
+
+ if (state->request.data.logoff.krb5ccname[0] == '\0') {
+ result = NT_STATUS_OK;
+ goto process_result;
+ }
+
+#ifdef HAVE_KRB5
+
+ if (state->request.data.logoff.uid < 0) {
+ DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
+ goto process_result;
+ }
+
+ /* what we need here is to find the corresponding krb5 ccache name *we*
+ * created for a given username and destroy it */
+
+ if (!ccache_entry_exists(state->request.data.logoff.user)) {
+ result = NT_STATUS_OK;
+ DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
+ goto process_result;
+ }
+
+ if (!ccache_entry_identical(state->request.data.logoff.user,
+ state->request.data.logoff.uid,
+ state->request.data.logoff.krb5ccname)) {
+ DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
+ goto process_result;
+ }
+
+ result = remove_ccache(state->request.data.logoff.user);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
+ nt_errstr(result)));
+ goto process_result;
+ }
+
+#else
+ result = NT_STATUS_NOT_SUPPORTED;
+#endif
+
+process_result:
+
+ winbindd_delete_memory_creds(state->request.data.logoff.user);
+
+ set_auth_errors(&state->response, result);
+
+ return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+/* Change user password with auth crap*/
+
+void winbindd_pam_chng_pswd_auth_crap(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain = NULL;
+ const char *domain_name = NULL;
+
+ /* Ensure null termination */
+ state->request.data.chng_pswd_auth_crap.user[
+ sizeof(state->request.data.chng_pswd_auth_crap.user)-1]=0;
+ state->request.data.chng_pswd_auth_crap.domain[
+ sizeof(state->request.data.chng_pswd_auth_crap.domain)-1]=0;
+
+ DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
+ (unsigned long)state->pid,
+ state->request.data.chng_pswd_auth_crap.domain,
+ state->request.data.chng_pswd_auth_crap.user));
+
+ if (*state->request.data.chng_pswd_auth_crap.domain != '\0') {
+ domain_name = state->request.data.chng_pswd_auth_crap.domain;
+ } else if (lp_winbind_use_default_domain()) {
+ domain_name = lp_workgroup();
+ }
+
+ if (domain_name != NULL)
+ domain = find_domain_from_name(domain_name);
+
+ if (domain != NULL) {
+ DEBUG(7, ("[%5lu]: pam auth crap changing pswd in domain: "
+ "%s\n", (unsigned long)state->pid,domain->name));
+ sendto_domain(state, domain);
+ return;
+ }
+
+ set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
+ DEBUG(5, ("CRAP change password for %s\\%s returned %s (PAM: %d)\n",
+ state->request.data.chng_pswd_auth_crap.domain,
+ state->request.data.chng_pswd_auth_crap.user,
+ state->response.data.auth.nt_status_string,
+ state->response.data.auth.pam_error));
+ request_error(state);
+ return;
+}
+
+enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
+{
+ NTSTATUS result;
+ DATA_BLOB new_nt_password;
+ DATA_BLOB old_nt_hash_enc;
+ DATA_BLOB new_lm_password;
+ DATA_BLOB old_lm_hash_enc;
+ fstring domain,user;
+ POLICY_HND dom_pol;
+ struct winbindd_domain *contact_domain = domainSt;
+ struct rpc_pipe_client *cli;
+
+ /* Ensure null termination */
+ state->request.data.chng_pswd_auth_crap.user[
+ sizeof(state->request.data.chng_pswd_auth_crap.user)-1]=0;
+ state->request.data.chng_pswd_auth_crap.domain[
+ sizeof(state->request.data.chng_pswd_auth_crap.domain)-1]=0;
+ *domain = 0;
+ *user = 0;
+
+ DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
+ (unsigned long)state->pid,
+ state->request.data.chng_pswd_auth_crap.domain,
+ state->request.data.chng_pswd_auth_crap.user));
+
+ if (lp_winbind_offline_logon()) {
+ DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
+ DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
+ result = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+
+ if (*state->request.data.chng_pswd_auth_crap.domain) {
+ fstrcpy(domain,state->request.data.chng_pswd_auth_crap.domain);
+ } else {
+ parse_domain_user(state->request.data.chng_pswd_auth_crap.user,
+ domain, user);
+
+ if(!*domain) {
+ DEBUG(3,("no domain specified with username (%s) - "
+ "failing auth\n",
+ state->request.data.chng_pswd_auth_crap.user));
+ result = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ }
+ }
+
+ if (!*domain && lp_winbind_use_default_domain()) {
+ fstrcpy(domain,(char *)lp_workgroup());
+ }
+
+ if(!*user) {
+ fstrcpy(user, state->request.data.chng_pswd_auth_crap.user);
+ }
+
+ DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
+ (unsigned long)state->pid, domain, user));
+
+ /* Change password */
+ new_nt_password = data_blob_talloc(
+ state->mem_ctx,
+ state->request.data.chng_pswd_auth_crap.new_nt_pswd,
+ state->request.data.chng_pswd_auth_crap.new_nt_pswd_len);
+
+ old_nt_hash_enc = data_blob_talloc(
+ state->mem_ctx,
+ state->request.data.chng_pswd_auth_crap.old_nt_hash_enc,
+ state->request.data.chng_pswd_auth_crap.old_nt_hash_enc_len);
+
+ if(state->request.data.chng_pswd_auth_crap.new_lm_pswd_len > 0) {
+ new_lm_password = data_blob_talloc(
+ state->mem_ctx,
+ state->request.data.chng_pswd_auth_crap.new_lm_pswd,
+ state->request.data.chng_pswd_auth_crap.new_lm_pswd_len);
+
+ old_lm_hash_enc = data_blob_talloc(
+ state->mem_ctx,
+ state->request.data.chng_pswd_auth_crap.old_lm_hash_enc,
+ state->request.data.chng_pswd_auth_crap.old_lm_hash_enc_len);
+ } else {
+ new_lm_password.length = 0;
+ old_lm_hash_enc.length = 0;
+ }
+
+ /* Get sam handle */
+
+ result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
+ goto done;
+ }
+
+ result = rpccli_samr_chng_pswd_auth_crap(
+ cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
+ new_lm_password, old_lm_hash_enc);
+
+ done:
+
+ set_auth_errors(&state->response, result);
+
+ DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
+ ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
+ domain, user,
+ state->response.data.auth.nt_status_string,
+ state->response.data.auth.pam_error));
+
+ return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
diff --git a/source3/winbindd/winbindd_passdb.c b/source3/winbindd/winbindd_passdb.c
new file mode 100644
index 0000000000..5677c01be1
--- /dev/null
+++ b/source3/winbindd/winbindd_passdb.c
@@ -0,0 +1,751 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind rpc backend functions
+
+ Copyright (C) Tim Potter 2000-2001,2003
+ Copyright (C) Simo Sorce 2003
+ Copyright (C) Volker Lendecke 2004
+ Copyright (C) Jeremy Allison 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+static NTSTATUS enum_groups_internal(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info,
+ enum lsa_SidType sidtype)
+{
+ struct pdb_search *search;
+ struct samr_displayentry *entries;
+ int i;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ if (sidtype == SID_NAME_ALIAS) {
+ search = pdb_search_aliases(&domain->sid);
+ } else {
+ search = pdb_search_groups();
+ }
+
+ if (search == NULL) goto done;
+
+ *num_entries = pdb_search_entries(search, 0, 0xffffffff, &entries);
+ if (*num_entries == 0) {
+ /* Zero entries isn't an error */
+ result = NT_STATUS_OK;
+ goto done;
+ }
+
+ *info = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
+ if (*info == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i=0; i<*num_entries; i++) {
+ fstrcpy((*info)[i].acct_name, entries[i].account_name);
+ fstrcpy((*info)[i].acct_desc, entries[i].description);
+ (*info)[i].rid = entries[i].rid;
+ }
+
+ result = NT_STATUS_OK;
+ done:
+ pdb_search_destroy(search);
+ return result;
+}
+
+/* List all local groups (aliases) */
+static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ return enum_groups_internal(domain,
+ mem_ctx,
+ num_entries,
+ info,
+ SID_NAME_ALIAS);
+}
+
+/* convert a single name to a sid in a domain */
+static NTSTATUS name_to_sid(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ enum winbindd_cmd original_cmd,
+ const char *domain_name,
+ const char *name,
+ DOM_SID *sid,
+ enum lsa_SidType *type)
+{
+ const char *fullname;
+ uint32 flags = LOOKUP_NAME_ALL;
+
+ switch ( original_cmd ) {
+ case WINBINDD_LOOKUPNAME:
+ /* This call is ok */
+ break;
+ default:
+ /* Avoid any NSS calls in the lookup_name by default */
+ flags |= LOOKUP_NAME_EXPLICIT;
+ DEBUG(10,("winbindd_passdb: limiting name_to_sid() to explicit mappings\n"));
+ break;
+ }
+
+ if (domain_name && domain_name[0] && strchr_m(name, '\\') == NULL) {
+ fullname = talloc_asprintf(mem_ctx, "%s\\%s",
+ domain_name, name);
+ if (fullname == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ fullname = name;
+ }
+
+ DEBUG(10, ("Finding fullname %s\n", fullname));
+
+ if ( !lookup_name( mem_ctx, fullname, flags, NULL, NULL, sid, type ) ) {
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ DEBUG(10, ("name_to_sid for %s returned %s (%s)\n",
+ fullname,
+ sid_string_dbg(sid),
+ sid_type_lookup((uint32)*type)));
+
+ return NT_STATUS_OK;
+}
+
+/*
+ convert a domain SID to a user or group name
+*/
+static NTSTATUS sid_to_name(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ char **domain_name,
+ char **name,
+ enum lsa_SidType *type)
+{
+ const char *dom, *nam;
+
+ DEBUG(10, ("Converting SID %s\n", sid_string_dbg(sid)));
+
+ /* Paranoia check */
+ if (!sid_check_is_in_builtin(sid) &&
+ !sid_check_is_in_our_domain(sid) &&
+ !sid_check_is_in_unix_users(sid) &&
+ !sid_check_is_unix_users(sid) &&
+ !sid_check_is_in_unix_groups(sid) &&
+ !sid_check_is_unix_groups(sid) &&
+ !sid_check_is_in_wellknown_domain(sid))
+ {
+ DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
+ "passdb backend\n", sid_string_dbg(sid)));
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ if (!lookup_sid(mem_ctx, sid, &dom, &nam, type)) {
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ *domain_name = talloc_strdup(mem_ctx, dom);
+ *name = talloc_strdup(mem_ctx, nam);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS rids_to_names(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ uint32 *rids,
+ size_t num_rids,
+ char **domain_name,
+ char ***names,
+ enum lsa_SidType **types)
+{
+ size_t i;
+ bool have_mapped;
+ bool have_unmapped;
+
+ *domain_name = NULL;
+ *names = NULL;
+ *types = NULL;
+
+ if (!num_rids) {
+ return NT_STATUS_OK;
+ }
+
+ /* Paranoia check */
+ if (!sid_check_is_in_builtin(sid) &&
+ !sid_check_is_in_our_domain(sid) &&
+ !sid_check_is_in_unix_users(sid) &&
+ !sid_check_is_unix_users(sid) &&
+ !sid_check_is_in_unix_groups(sid) &&
+ !sid_check_is_unix_groups(sid) &&
+ !sid_check_is_in_wellknown_domain(sid))
+ {
+ DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
+ "passdb backend\n", sid_string_dbg(sid)));
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
+ *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
+
+ if ((*names == NULL) || (*types == NULL)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ have_mapped = have_unmapped = false;
+
+ for (i=0; i<num_rids; i++) {
+ DOM_SID lsid;
+ const char *dom = NULL, *nam = NULL;
+ enum lsa_SidType type = SID_NAME_UNKNOWN;
+
+ if (!sid_compose(&lsid, sid, rids[i])) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (!lookup_sid(mem_ctx, &lsid, &dom, &nam, &type)) {
+ have_unmapped = true;
+ (*types)[i] = SID_NAME_UNKNOWN;
+ (*names)[i] = talloc_strdup(mem_ctx, "");
+ } else {
+ have_mapped = true;
+ (*types)[i] = type;
+ (*names)[i] = CONST_DISCARD(char *, nam);
+ }
+
+ if (*domain_name == NULL) {
+ *domain_name = CONST_DISCARD(char *, dom);
+ } else {
+ char *dname = CONST_DISCARD(char *, dom);
+ TALLOC_FREE(dname);
+ }
+ }
+
+ if (!have_mapped) {
+ return NT_STATUS_NONE_MAPPED;
+ }
+ if (!have_unmapped) {
+ return NT_STATUS_OK;
+ }
+ return STATUS_SOME_UNMAPPED;
+}
+
+/* Lookup groups a user is a member of. I wish Unix had a call like this! */
+static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ uint32 *num_groups, DOM_SID **user_gids)
+{
+ NTSTATUS result;
+ DOM_SID *groups = NULL;
+ gid_t *gids = NULL;
+ size_t ngroups = 0;
+ struct samu *user;
+
+ if ( (user = samu_new(mem_ctx)) == NULL ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( !pdb_getsampwsid( user, user_sid ) ) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ result = pdb_enum_group_memberships( mem_ctx, user, &groups, &gids, &ngroups );
+
+ TALLOC_FREE( user );
+
+ *num_groups = (uint32)ngroups;
+ *user_gids = groups;
+
+ return result;
+}
+
+static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 num_sids, const DOM_SID *sids,
+ uint32 *p_num_aliases, uint32 **rids)
+{
+ NTSTATUS result;
+ size_t num_aliases = 0;
+
+ result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
+ sids, num_sids, rids, &num_aliases);
+
+ *p_num_aliases = num_aliases;
+ return result;
+}
+
+/* find the sequence number for a domain */
+static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
+{
+ bool result;
+ time_t seq_num;
+
+ result = pdb_get_seq_num(&seq_num);
+ if (!result) {
+ *seq = 1;
+ }
+
+ *seq = (int) seq_num;
+ /* *seq = 1; */
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS lockout_policy(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ struct samr_DomInfo12 *policy)
+{
+ /* actually we have that */
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS password_policy(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ struct samr_DomInfo1 *policy)
+{
+ uint32 min_pass_len,pass_hist,password_properties;
+ time_t u_expire, u_min_age;
+ NTTIME nt_expire, nt_min_age;
+ uint32 account_policy_temp;
+
+ if ((policy = TALLOC_ZERO_P(mem_ctx, struct samr_DomInfo1)) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &account_policy_temp)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ min_pass_len = account_policy_temp;
+
+ if (!pdb_get_account_policy(AP_PASSWORD_HISTORY, &account_policy_temp)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ pass_hist = account_policy_temp;
+
+ if (!pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ password_properties = account_policy_temp;
+
+ if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ u_expire = account_policy_temp;
+
+ if (!pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &account_policy_temp)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ u_min_age = account_policy_temp;
+
+ unix_to_nt_time_abs(&nt_expire, u_expire);
+ unix_to_nt_time_abs(&nt_min_age, u_min_age);
+
+ init_samr_DomInfo1(policy,
+ (uint16)min_pass_len,
+ (uint16)pass_hist,
+ password_properties,
+ nt_expire,
+ nt_min_age);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ BUILTIN specific functions.
+*********************************************************************/
+
+/* list all domain groups */
+static NTSTATUS builtin_enum_dom_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ /* BUILTIN doesn't have domain groups */
+ *num_entries = 0;
+ *info = NULL;
+ return NT_STATUS_OK;
+}
+
+/* Query display info for a domain. This returns enough information plus a
+ bit extra to give an overview of domain users for the User Manager
+ application. */
+static NTSTATUS builtin_query_user_list(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ WINBIND_USERINFO **info)
+{
+ /* We don't have users */
+ *num_entries = 0;
+ *info = NULL;
+ return NT_STATUS_OK;
+}
+
+/* Lookup user information from a rid or username. */
+static NTSTATUS builtin_query_user(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ WINBIND_USERINFO *user_info)
+{
+ return NT_STATUS_NO_SUCH_USER;
+}
+
+static NTSTATUS builtin_lookup_groupmem(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group_sid, uint32 *num_names,
+ DOM_SID **sid_mem, char ***names,
+ uint32 **name_types)
+{
+ *num_names = 0;
+ *sid_mem = NULL;
+ *names = NULL;
+ *name_types = 0;
+ return NT_STATUS_NO_SUCH_GROUP;
+}
+
+/* get a list of trusted domains - builtin domain */
+static NTSTATUS builtin_trusted_domains(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_domains,
+ char ***names,
+ char ***alt_names,
+ DOM_SID **dom_sids)
+{
+ *num_domains = 0;
+ *names = NULL;
+ *alt_names = NULL;
+ *dom_sids = NULL;
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ SAM specific functions.
+*********************************************************************/
+
+/* list all domain groups */
+static NTSTATUS sam_enum_dom_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ return enum_groups_internal(domain,
+ mem_ctx,
+ num_entries,
+ info,
+ SID_NAME_DOM_GRP);
+}
+
+static NTSTATUS sam_query_user_list(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ WINBIND_USERINFO **info)
+{
+ struct pdb_search *ps = pdb_search_users(ACB_NORMAL);
+ struct samr_displayentry *entries = NULL;
+ uint32 i;
+
+ *num_entries = 0;
+ *info = NULL;
+
+ if (!ps) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *num_entries = pdb_search_entries(ps,
+ 1, 0xffffffff,
+ &entries);
+
+ *info = TALLOC_ZERO_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
+ if (!(*info)) {
+ pdb_search_destroy(ps);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < *num_entries; i++) {
+ struct samr_displayentry *e = &entries[i];
+
+ (*info)[i].acct_name = talloc_strdup(mem_ctx, e->account_name );
+ (*info)[i].full_name = talloc_strdup(mem_ctx, e->fullname );
+ (*info)[i].homedir = NULL;
+ (*info)[i].shell = NULL;
+ sid_compose(&(*info)[i].user_sid, &domain->sid, e->rid);
+
+ /* For the moment we set the primary group for
+ every user to be the Domain Users group.
+ There are serious problems with determining
+ the actual primary group for large domains.
+ This should really be made into a 'winbind
+ force group' smb.conf parameter or
+ something like that. */
+
+ sid_compose(&(*info)[i].group_sid, &domain->sid,
+ DOMAIN_GROUP_RID_USERS);
+ }
+
+ pdb_search_destroy(ps);
+ return NT_STATUS_OK;
+}
+
+/* Lookup user information from a rid or username. */
+static NTSTATUS sam_query_user(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ WINBIND_USERINFO *user_info)
+{
+ struct samu *sampass = NULL;
+
+ ZERO_STRUCTP(user_info);
+
+ if (!sid_check_is_in_our_domain(user_sid)) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ DEBUG(10,("sam_query_user: getting samu info for sid %s\n",
+ sid_string_dbg(user_sid) ));
+
+ if (!(sampass = samu_new(mem_ctx))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_getsampwsid(sampass, user_sid)) {
+ TALLOC_FREE(sampass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (pdb_get_group_sid(sampass) == NULL) {
+ TALLOC_FREE(sampass);
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ DEBUG(10,("sam_query_user: group sid %s\n",
+ sid_string_dbg(sampass->group_sid) ));
+
+ sid_copy(&user_info->user_sid, user_sid);
+ sid_copy(&user_info->group_sid, sampass->group_sid);
+
+ user_info->acct_name = talloc_strdup(mem_ctx, sampass->username ?
+ sampass->username : "");
+ user_info->full_name = talloc_strdup(mem_ctx, sampass->full_name ?
+ sampass->full_name : "");
+ user_info->homedir = talloc_strdup(mem_ctx, sampass->home_dir ?
+ sampass->home_dir : "");
+ if (sampass->unix_pw && sampass->unix_pw->pw_shell) {
+ user_info->shell = talloc_strdup(mem_ctx, sampass->unix_pw->pw_shell);
+ } else {
+ user_info->shell = talloc_strdup(mem_ctx, "");
+ }
+ user_info->primary_gid = sampass->unix_pw ? sampass->unix_pw->pw_gid : (gid_t)-1;
+
+ TALLOC_FREE(sampass);
+ return NT_STATUS_OK;
+}
+
+/* Lookup group membership given a rid. */
+static NTSTATUS sam_lookup_groupmem(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group_sid, uint32 *num_names,
+ DOM_SID **sid_mem, char ***names,
+ uint32 **name_types)
+{
+ size_t i, num_members, num_mapped;
+ uint32 *rids;
+ NTSTATUS result;
+ const DOM_SID **sids;
+ struct lsa_dom_info *lsa_domains;
+ struct lsa_name_info *lsa_names;
+ TALLOC_CTX *tmp_ctx;
+
+ if (!sid_check_is_in_our_domain(group_sid)) {
+ /* There's no groups, only aliases in BUILTIN */
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ if (!(tmp_ctx = talloc_init("lookup_groupmem"))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result = pdb_enum_group_members(tmp_ctx, group_sid, &rids,
+ &num_members);
+ if (!NT_STATUS_IS_OK(result)) {
+ TALLOC_FREE(tmp_ctx);
+ return result;
+ }
+
+ if (num_members == 0) {
+ *num_names = 0;
+ *sid_mem = NULL;
+ *names = NULL;
+ *name_types = NULL;
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_OK;
+ }
+
+ *sid_mem = TALLOC_ARRAY(mem_ctx, DOM_SID, num_members);
+ *names = TALLOC_ARRAY(mem_ctx, char *, num_members);
+ *name_types = TALLOC_ARRAY(mem_ctx, uint32, num_members);
+ sids = TALLOC_ARRAY(tmp_ctx, const DOM_SID *, num_members);
+
+ if (((*sid_mem) == NULL) || ((*names) == NULL) ||
+ ((*name_types) == NULL) || (sids == NULL)) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * Prepare an array of sid pointers for the lookup_sids calling
+ * convention.
+ */
+
+ for (i=0; i<num_members; i++) {
+ DOM_SID *sid = &((*sid_mem)[i]);
+ if (!sid_compose(sid, &domain->sid, rids[i])) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ sids[i] = sid;
+ }
+
+ result = lookup_sids(tmp_ctx, num_members, sids, 1,
+ &lsa_domains, &lsa_names);
+ if (!NT_STATUS_IS_OK(result)) {
+ TALLOC_FREE(tmp_ctx);
+ return result;
+ }
+
+ num_mapped = 0;
+ for (i=0; i<num_members; i++) {
+ if (lsa_names[i].type != SID_NAME_USER) {
+ DEBUG(2, ("Got %s as group member -- ignoring\n",
+ sid_type_lookup(lsa_names[i].type)));
+ continue;
+ }
+ if (!((*names)[i] = talloc_strdup((*names),
+ lsa_names[i].name))) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*name_types)[i] = lsa_names[i].type;
+
+ num_mapped += 1;
+ }
+
+ *num_names = num_mapped;
+
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+/* get a list of trusted domains */
+static NTSTATUS sam_trusted_domains(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_domains,
+ char ***names,
+ char ***alt_names,
+ DOM_SID **dom_sids)
+{
+ NTSTATUS nt_status;
+ struct trustdom_info **domains;
+ int i;
+ TALLOC_CTX *tmp_ctx;
+
+ *num_domains = 0;
+ *names = NULL;
+ *alt_names = NULL;
+ *dom_sids = NULL;
+
+ if (!(tmp_ctx = talloc_init("trusted_domains"))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ nt_status = pdb_enum_trusteddoms(tmp_ctx, num_domains, &domains);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ TALLOC_FREE(tmp_ctx);
+ return nt_status;
+ }
+
+ if (*num_domains) {
+ *names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
+ *alt_names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
+ *dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
+
+ if ((*alt_names == NULL) || (*names == NULL) || (*dom_sids == NULL)) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ *names = NULL;
+ *alt_names = NULL;
+ *dom_sids = NULL;
+ }
+
+ for (i=0; i<*num_domains; i++) {
+ (*alt_names)[i] = NULL;
+ if (!((*names)[i] = talloc_strdup((*names),
+ domains[i]->name))) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ sid_copy(&(*dom_sids)[i], &domains[i]->sid);
+ }
+
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+/* the rpc backend methods are exposed via this structure */
+struct winbindd_methods builtin_passdb_methods = {
+ false,
+ builtin_query_user_list,
+ builtin_enum_dom_groups,
+ enum_local_groups,
+ name_to_sid,
+ sid_to_name,
+ rids_to_names,
+ builtin_query_user,
+ lookup_usergroups,
+ lookup_useraliases,
+ builtin_lookup_groupmem,
+ sequence_number,
+ lockout_policy,
+ password_policy,
+ builtin_trusted_domains,
+};
+
+/* the rpc backend methods are exposed via this structure */
+struct winbindd_methods sam_passdb_methods = {
+ false,
+ sam_query_user_list,
+ sam_enum_dom_groups,
+ enum_local_groups,
+ name_to_sid,
+ sid_to_name,
+ rids_to_names,
+ sam_query_user,
+ lookup_usergroups,
+ lookup_useraliases,
+ sam_lookup_groupmem,
+ sequence_number,
+ lockout_policy,
+ password_policy,
+ sam_trusted_domains,
+};
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
new file mode 100644
index 0000000000..e0fc073a0a
--- /dev/null
+++ b/source3/winbindd/winbindd_proto.h
@@ -0,0 +1,601 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * collected prototypes header
+ *
+ * frozen from "make proto" in May 2008
+ *
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _WINBINDD_PROTO_H_
+#define _WINBINDD_PROTO_H_
+
+
+/* The following definitions come from auth/token_util.c */
+
+bool nt_token_check_sid ( const DOM_SID *sid, const NT_USER_TOKEN *token );
+bool nt_token_check_domain_rid( NT_USER_TOKEN *token, uint32 rid );
+NT_USER_TOKEN *get_root_nt_token( void );
+NTSTATUS add_aliases(const DOM_SID *domain_sid,
+ struct nt_user_token *token);
+struct nt_user_token *create_local_nt_token(TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ bool is_guest,
+ int num_groupsids,
+ const DOM_SID *groupsids);
+void debug_nt_user_token(int dbg_class, int dbg_lev, NT_USER_TOKEN *token);
+void debug_unix_user_token(int dbg_class, int dbg_lev, uid_t uid, gid_t gid,
+ int n_groups, gid_t *groups);
+
+/* The following definitions come from smbd/connection.c */
+
+bool yield_connection(connection_struct *conn, const char *name);
+int count_current_connections( const char *sharename, bool clear );
+int count_all_current_connections(void);
+bool claim_connection(connection_struct *conn, const char *name,
+ uint32 msg_flags);
+bool register_message_flags(bool doreg, uint32 msg_flags);
+bool store_pipe_opendb( smb_np_struct *p );
+bool delete_pipe_opendb( smb_np_struct *p );
+
+/* The following definitions come from winbindd/winbindd.c */
+
+struct event_context *winbind_event_context(void);
+struct messaging_context *winbind_messaging_context(void);
+void add_fd_event(struct fd_event *ev);
+void remove_fd_event(struct fd_event *ev);
+void setup_async_read(struct fd_event *event, void *data, size_t length,
+ void (*finished)(void *private_data, bool success),
+ void *private_data);
+void setup_async_write(struct fd_event *event, void *data, size_t length,
+ void (*finished)(void *private_data, bool success),
+ void *private_data);
+void request_error(struct winbindd_cli_state *state);
+void request_ok(struct winbindd_cli_state *state);
+void winbind_check_sighup(const char *logfile);
+void winbind_check_sigterm(bool in_parent);
+int main(int argc, char **argv, char **envp);
+
+/* The following definitions come from winbindd/winbindd_ads.c */
+
+
+/* The following definitions come from winbindd/winbindd_async.c */
+
+void do_async(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
+ const struct winbindd_request *request,
+ void (*cont)(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data),
+ void *c, void *private_data);
+void do_async_domain(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
+ const struct winbindd_request *request,
+ void (*cont)(TALLOC_CTX *mem_ctx, bool success,
+ struct winbindd_response *response,
+ void *c, void *private_data),
+ void *c, void *private_data);
+void winbindd_lookupsid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ void (*cont)(void *private_data, bool success,
+ const char *dom_name,
+ const char *name,
+ enum lsa_SidType type),
+ void *private_data);
+enum winbindd_result winbindd_dual_lookupsid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+void winbindd_lookupname_async(TALLOC_CTX *mem_ctx,
+ const char *dom_name, const char *name,
+ void (*cont)(void *private_data, bool success,
+ const DOM_SID *sid,
+ enum lsa_SidType type),
+ enum winbindd_cmd orig_cmd,
+ void *private_data);
+enum winbindd_result winbindd_dual_lookupname(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+void winbindd_listent_async(TALLOC_CTX *mem_ctx,
+ struct winbindd_domain *domain,
+ void (*cont)(void *private_data, bool success,
+ fstring dom_name, char* extra_data),
+ void *private_data, enum ent_type type);
+enum winbindd_result winbindd_dual_list_users(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+enum winbindd_result winbindd_dual_list_groups(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+bool print_sidlist(TALLOC_CTX *mem_ctx, const DOM_SID *sids,
+ size_t num_sids, char **result, ssize_t *len);
+enum winbindd_result winbindd_dual_lookuprids(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+void winbindd_getsidaliases_async(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sids, size_t num_sids,
+ void (*cont)(void *private_data,
+ bool success,
+ const DOM_SID *aliases,
+ size_t num_aliases),
+ void *private_data);
+enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+void winbindd_gettoken_async(TALLOC_CTX *mem_ctx, const DOM_SID *user_sid,
+ void (*cont)(void *private_data, bool success,
+ DOM_SID *sids, size_t num_sids),
+ void *private_data);
+void query_user_async(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
+ const DOM_SID *sid,
+ void (*cont)(void *private_data, bool success,
+ const char *acct_name,
+ const char *full_name,
+ const char *homedir,
+ const char *shell,
+ gid_t gid,
+ uint32 group_rid),
+ void *private_data);
+
+/* The following definitions come from winbindd/winbindd_cache.c */
+
+void winbindd_check_cache_size(time_t t);
+struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status);
+NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid);
+NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ const uint8 **cached_nt_pass,
+ const uint8 **cached_salt);
+NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ const uint8 nt_pass[NT_HASH_LEN]);
+void wcache_invalidate_samlogon(struct winbindd_domain *domain,
+ struct netr_SamInfo3 *info3);
+bool wcache_invalidate_cache(void);
+bool init_wcache(void);
+bool initialize_winbindd_cache(void);
+void close_winbindd_cache(void);
+void cache_store_response(pid_t pid, struct winbindd_response *response);
+bool cache_retrieve_response(pid_t pid, struct winbindd_response * response);
+void cache_cleanup_response(pid_t pid);
+bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ char **domain_name, char **name,
+ enum lsa_SidType *type);
+bool lookup_cached_name(TALLOC_CTX *mem_ctx,
+ const char *domain_name,
+ const char *name,
+ DOM_SID *sid,
+ enum lsa_SidType *type);
+void cache_name2sid(struct winbindd_domain *domain,
+ const char *domain_name, const char *name,
+ enum lsa_SidType type, const DOM_SID *sid);
+void wcache_flush_cache(void);
+NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count);
+NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid) ;
+bool set_global_winbindd_state_offline(void);
+void set_global_winbindd_state_online(void);
+bool get_global_winbindd_state_offline(void);
+int winbindd_validate_cache(void);
+int winbindd_validate_cache_nobackup(void);
+bool winbindd_cache_validate_and_initialize(void);
+bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains );
+bool wcache_tdc_add_domain( struct winbindd_domain *domain );
+struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name );
+void wcache_tdc_clear( void );
+NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
+ const DOM_SID *user_sid,
+ TALLOC_CTX *ctx,
+ ADS_STRUCT *ads, LDAPMessage *msg,
+ char **homedir, char **shell, char **gecos,
+ gid_t *p_gid);
+
+/* The following definitions come from winbindd/winbindd_ccache_access.c */
+
+void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_dual_ccache_ntlm_auth(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+
+/* The following definitions come from winbindd/winbindd_cm.c */
+
+void set_domain_offline(struct winbindd_domain *domain);
+void set_domain_online_request(struct winbindd_domain *domain);
+void winbind_add_failed_connection_entry(const struct winbindd_domain *domain,
+ const char *server,
+ NTSTATUS result);
+void invalidate_cm_connection(struct winbindd_cm_conn *conn);
+void close_conns_after_fork(void);
+NTSTATUS init_dc_connection(struct winbindd_domain *domain);
+NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client **cli, POLICY_HND *sam_handle);
+NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client **cli, POLICY_HND *lsa_policy);
+NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
+ struct rpc_pipe_client **cli);
+
+/* The following definitions come from winbindd/winbindd_cred_cache.c */
+
+bool ccache_entry_exists(const char *username);
+bool ccache_entry_identical(const char *username,
+ uid_t uid,
+ const char *ccname);
+NTSTATUS add_ccache_to_list(const char *princ_name,
+ const char *ccname,
+ const char *service,
+ const char *username,
+ const char *realm,
+ uid_t uid,
+ time_t create_time,
+ time_t ticket_end,
+ time_t renew_until,
+ bool postponed_request);
+NTSTATUS remove_ccache(const char *username);
+struct WINBINDD_MEMORY_CREDS *find_memory_creds_by_name(const char *username);
+NTSTATUS winbindd_add_memory_creds(const char *username,
+ uid_t uid,
+ const char *pass);
+NTSTATUS winbindd_delete_memory_creds(const char *username);
+NTSTATUS winbindd_replace_memory_creds(const char *username,
+ const char *pass);
+
+/* The following definitions come from winbindd/winbindd_creds.c */
+
+NTSTATUS winbindd_get_creds(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ struct netr_SamInfo3 **info3,
+ const uint8 *cached_nt_pass[NT_HASH_LEN],
+ const uint8 *cred_salt[NT_HASH_LEN]);
+NTSTATUS winbindd_store_creds(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const char *user,
+ const char *pass,
+ struct netr_SamInfo3 *info3,
+ const DOM_SID *user_sid);
+NTSTATUS winbindd_update_creds_by_info3(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const char *user,
+ const char *pass,
+ struct netr_SamInfo3 *info3);
+NTSTATUS winbindd_update_creds_by_sid(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ const char *pass);
+NTSTATUS winbindd_update_creds_by_name(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const char *user,
+ const char *pass);
+
+/* The following definitions come from winbindd/winbindd_domain.c */
+
+void setup_domain_child(struct winbindd_domain *domain,
+ struct winbindd_child *child);
+
+/* The following definitions come from winbindd/winbindd_dual.c */
+
+void async_request(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
+ struct winbindd_request *request,
+ struct winbindd_response *response,
+ void (*continuation)(void *private_data, bool success),
+ void *private_data);
+void async_domain_request(TALLOC_CTX *mem_ctx,
+ struct winbindd_domain *domain,
+ struct winbindd_request *request,
+ struct winbindd_response *response,
+ void (*continuation)(void *private_data_data, bool success),
+ void *private_data_data);
+void sendto_child(struct winbindd_cli_state *state,
+ struct winbindd_child *child);
+void sendto_domain(struct winbindd_cli_state *state,
+ struct winbindd_domain *domain);
+void setup_child(struct winbindd_child *child,
+ const struct winbindd_child_dispatch_table *table,
+ const char *logprefix,
+ const char *logname);
+void winbind_child_died(pid_t pid);
+void winbindd_flush_negative_conn_cache(struct winbindd_domain *domain);
+void winbind_msg_debug(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data);
+void winbind_msg_offline(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data);
+void winbind_msg_online(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data);
+void winbind_msg_onlinestatus(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data);
+void winbind_msg_dump_event_list(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data);
+void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data);
+
+/* The following definitions come from winbindd/winbindd_group.c */
+
+void winbindd_getgrnam(struct winbindd_cli_state *state);
+void winbindd_getgrgid(struct winbindd_cli_state *state);
+void winbindd_setgrent(struct winbindd_cli_state *state);
+void winbindd_endgrent(struct winbindd_cli_state *state);
+void winbindd_getgrent(struct winbindd_cli_state *state);
+void winbindd_list_groups(struct winbindd_cli_state *state);
+void winbindd_getgroups(struct winbindd_cli_state *state);
+void winbindd_getusersids(struct winbindd_cli_state *state);
+void winbindd_getuserdomgroups(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+bool get_sam_group_entries(struct getent_state *ent);
+
+
+/* The following definitions come from winbindd/winbindd_idmap.c */
+
+void init_idmap_child(void);
+struct winbindd_child *idmap_child(void);
+void winbindd_set_mapping_async(TALLOC_CTX *mem_ctx, const struct id_map *map,
+ void (*cont)(void *private_data, bool success),
+ void *private_data);
+enum winbindd_result winbindd_dual_set_mapping(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+void winbindd_set_hwm_async(TALLOC_CTX *mem_ctx, const struct unixid *xid,
+ void (*cont)(void *private_data, bool success),
+ void *private_data);
+enum winbindd_result winbindd_dual_set_hwm(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+void winbindd_sids2xids_async(TALLOC_CTX *mem_ctx, void *sids, int size,
+ void (*cont)(void *private_data, bool success, void *data, int len),
+ void *private_data);
+enum winbindd_result winbindd_dual_sids2xids(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+void winbindd_sid2uid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ void (*cont)(void *private_data, bool success, uid_t uid),
+ void *private_data);
+enum winbindd_result winbindd_dual_sid2uid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+void winbindd_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ void (*cont)(void *private_data, bool success, gid_t gid),
+ void *private_data);
+enum winbindd_result winbindd_dual_sid2gid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+void winbindd_uid2sid_async(TALLOC_CTX *mem_ctx, uid_t uid,
+ void (*cont)(void *private_data, bool success, const char *sid),
+ void *private_data);
+enum winbindd_result winbindd_dual_uid2sid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+void winbindd_gid2sid_async(TALLOC_CTX *mem_ctx, gid_t gid,
+ void (*cont)(void *private_data, bool success, const char *sid),
+ void *private_data);
+enum winbindd_result winbindd_dual_gid2sid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+
+/* The following definitions come from winbindd/winbindd_locator.c */
+
+void init_locator_child(void);
+struct winbindd_child *locator_child(void);
+void winbindd_dsgetdcname(struct winbindd_cli_state *state);
+
+/* The following definitions come from winbindd/winbindd_misc.c */
+
+void winbindd_check_machine_acct(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+void winbindd_list_ent(struct winbindd_cli_state *state, enum ent_type type);
+void winbindd_list_trusted_domains(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+void winbindd_getdcname(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+void winbindd_show_sequence(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+void winbindd_domain_info(struct winbindd_cli_state *state);
+void winbindd_ping(struct winbindd_cli_state *state);
+void winbindd_info(struct winbindd_cli_state *state);
+void winbindd_interface_version(struct winbindd_cli_state *state);
+void winbindd_domain_name(struct winbindd_cli_state *state);
+void winbindd_netbios_name(struct winbindd_cli_state *state);
+void winbindd_priv_pipe_dir(struct winbindd_cli_state *state);
+
+/* The following definitions come from winbindd/winbindd_ndr.c */
+
+void ndr_print_winbindd_child(struct ndr_print *ndr,
+ const char *name,
+ const struct winbindd_child *r);
+void ndr_print_winbindd_cm_conn(struct ndr_print *ndr,
+ const char *name,
+ const struct winbindd_cm_conn *r);
+void ndr_print_winbindd_methods(struct ndr_print *ndr,
+ const char *name,
+ const struct winbindd_methods *r);
+void ndr_print_winbindd_domain(struct ndr_print *ndr,
+ const char *name,
+ const struct winbindd_domain *r);
+
+/* The following definitions come from winbindd/winbindd_pam.c */
+
+struct winbindd_domain *find_auth_domain(struct winbindd_cli_state *state,
+ const char *domain_name);
+void winbindd_pam_auth(struct winbindd_cli_state *state);
+NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state,
+ struct netr_SamInfo3 **info3);
+NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state,
+ struct netr_SamInfo3 **info3);
+NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state,
+ struct netr_SamInfo3 **info3);
+enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state) ;
+void winbindd_pam_auth_crap(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state) ;
+void winbindd_pam_chauthtok(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
+ struct winbindd_cli_state *state);
+void winbindd_pam_logoff(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state) ;
+void winbindd_pam_chng_pswd_auth_crap(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state);
+
+/* The following definitions come from winbindd/winbindd_passdb.c */
+
+
+/* The following definitions come from winbindd/winbindd_reconnect.c */
+
+
+/* The following definitions come from winbindd/winbindd_rpc.c */
+
+NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ enum winbindd_cmd original_cmd,
+ const char *domain_name,
+ const char *name,
+ DOM_SID *sid,
+ enum lsa_SidType *type);
+NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ char **domain_name,
+ char **name,
+ enum lsa_SidType *type);
+NTSTATUS msrpc_rids_to_names(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ uint32 *rids,
+ size_t num_rids,
+ char **domain_name,
+ char ***names,
+ enum lsa_SidType **types);
+NTSTATUS msrpc_lookup_useraliases(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 num_sids, const DOM_SID *sids,
+ uint32 *num_aliases, uint32 **alias_rids);
+NTSTATUS msrpc_lockout_policy(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ struct samr_DomInfo12 *lockout_policy);
+NTSTATUS msrpc_password_policy(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ struct samr_DomInfo1 *password_policy);
+
+/* The following definitions come from winbindd/winbindd_sid.c */
+
+void winbindd_lookupsid(struct winbindd_cli_state *state);
+void winbindd_lookupname(struct winbindd_cli_state *state);
+void winbindd_lookuprids(struct winbindd_cli_state *state);
+void winbindd_sid_to_uid(struct winbindd_cli_state *state);
+void winbindd_sid_to_gid(struct winbindd_cli_state *state);
+void winbindd_sids_to_unixids(struct winbindd_cli_state *state);
+void winbindd_set_mapping(struct winbindd_cli_state *state);
+void winbindd_set_hwm(struct winbindd_cli_state *state);
+void winbindd_uid_to_sid(struct winbindd_cli_state *state);
+void winbindd_gid_to_sid(struct winbindd_cli_state *state);
+void winbindd_allocate_uid(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_dual_allocate_uid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+void winbindd_allocate_gid(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_dual_allocate_gid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+
+/* The following definitions come from winbindd/winbindd_user.c */
+
+enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+void winbindd_getpwnam(struct winbindd_cli_state *state);
+void winbindd_getpwuid(struct winbindd_cli_state *state);
+void winbindd_setpwent(struct winbindd_cli_state *state);
+void winbindd_endpwent(struct winbindd_cli_state *state);
+void winbindd_getpwent(struct winbindd_cli_state *state);
+void winbindd_list_users(struct winbindd_cli_state *state);
+
+/* The following definitions come from winbindd/winbindd_util.c */
+
+struct winbindd_domain *domain_list(void);
+void free_domain_list(void);
+void rescan_trusted_domains( void );
+enum winbindd_result init_child_connection(struct winbindd_domain *domain,
+ void (*continuation)(void *private_data,
+ bool success),
+ void *private_data);
+enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state);
+bool init_domain_list(void);
+void check_domain_trusted( const char *name, const DOM_SID *user_sid );
+struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name);
+struct winbindd_domain *find_domain_from_name(const char *domain_name);
+struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid);
+struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid);
+struct winbindd_domain *find_our_domain(void);
+struct winbindd_domain *find_root_domain(void);
+struct winbindd_domain *find_builtin_domain(void);
+struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid);
+struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name);
+bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
+ enum winbindd_cmd orig_cmd,
+ struct winbindd_domain *domain,
+ const char *domain_name,
+ const char *name, DOM_SID *sid,
+ enum lsa_SidType *type);
+bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
+ struct winbindd_domain *domain,
+ DOM_SID *sid,
+ char **dom_name,
+ char **name,
+ enum lsa_SidType *type);
+void free_getent_state(struct getent_state *state);
+bool parse_domain_user(const char *domuser, fstring domain, fstring user);
+bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
+ char **domain, char **user);
+void parse_add_domuser(void *buf, char *domuser, int *len);
+bool canonicalize_username(fstring username_inout, fstring domain, fstring user);
+void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume);
+const char *get_winbind_pipe_dir(void) ;
+char *get_winbind_priv_pipe_dir(void) ;
+int open_winbindd_socket(void);
+int open_winbindd_priv_socket(void);
+void close_winbindd_socket(void);
+struct winbindd_cli_state *winbindd_client_list(void);
+void winbindd_add_client(struct winbindd_cli_state *cli);
+void winbindd_remove_client(struct winbindd_cli_state *cli);
+void winbindd_kill_all_clients(void);
+int winbindd_num_clients(void);
+NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ uint32 *p_num_groups, DOM_SID **user_sids);
+void ws_name_replace( char *name, char replace );
+void ws_name_return( char *name, char replace );
+bool winbindd_can_contact_domain(struct winbindd_domain *domain);
+bool winbindd_internal_child(struct winbindd_child *child);
+void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain);
+void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain);
+void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain);
+void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain);
+void set_auth_errors(struct winbindd_response *resp, NTSTATUS result);
+
+/* The following definitions come from winbindd/winbindd_wins.c */
+
+void winbindd_wins_byip(struct winbindd_cli_state *state);
+void winbindd_wins_byname(struct winbindd_cli_state *state);
+
+#endif /* _WINBINDD_PROTO_H_ */
diff --git a/source3/winbindd/winbindd_reconnect.c b/source3/winbindd/winbindd_reconnect.c
new file mode 100644
index 0000000000..25debccc5a
--- /dev/null
+++ b/source3/winbindd/winbindd_reconnect.c
@@ -0,0 +1,316 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Wrapper around winbindd_rpc.c to centralize retry logic.
+
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+extern struct winbindd_methods msrpc_methods;
+
+/* List all users */
+static NTSTATUS query_user_list(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ WINBIND_USERINFO **info)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.query_user_list(domain, mem_ctx,
+ num_entries, info);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.query_user_list(domain, mem_ctx,
+ num_entries, info);
+ return result;
+}
+
+/* list all domain groups */
+static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.enum_dom_groups(domain, mem_ctx,
+ num_entries, info);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.enum_dom_groups(domain, mem_ctx,
+ num_entries, info);
+ return result;
+}
+
+/* List all domain groups */
+
+static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.enum_local_groups(domain, mem_ctx,
+ num_entries, info);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.enum_local_groups(domain, mem_ctx,
+ num_entries, info);
+
+ return result;
+}
+
+/* convert a single name to a sid in a domain */
+static NTSTATUS name_to_sid(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ enum winbindd_cmd orig_cmd,
+ const char *domain_name,
+ const char *name,
+ DOM_SID *sid,
+ enum lsa_SidType *type)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.name_to_sid(domain, mem_ctx, orig_cmd,
+ domain_name, name,
+ sid, type);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.name_to_sid(domain, mem_ctx, orig_cmd,
+ domain_name, name,
+ sid, type);
+
+ return result;
+}
+
+/*
+ convert a domain SID to a user or group name
+*/
+static NTSTATUS sid_to_name(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ char **domain_name,
+ char **name,
+ enum lsa_SidType *type)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.sid_to_name(domain, mem_ctx, sid,
+ domain_name, name, type);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.sid_to_name(domain, mem_ctx, sid,
+ domain_name, name, type);
+
+ return result;
+}
+
+static NTSTATUS rids_to_names(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ uint32 *rids,
+ size_t num_rids,
+ char **domain_name,
+ char ***names,
+ enum lsa_SidType **types)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.rids_to_names(domain, mem_ctx, sid,
+ rids, num_rids,
+ domain_name, names, types);
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
+ result = msrpc_methods.rids_to_names(domain, mem_ctx, sid,
+ rids, num_rids,
+ domain_name, names,
+ types);
+ }
+
+ return result;
+}
+
+/* Lookup user information from a rid or username. */
+static NTSTATUS query_user(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ WINBIND_USERINFO *user_info)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.query_user(domain, mem_ctx, user_sid,
+ user_info);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.query_user(domain, mem_ctx, user_sid,
+ user_info);
+
+ return result;
+}
+
+/* Lookup groups a user is a member of. I wish Unix had a call like this! */
+static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ uint32 *num_groups, DOM_SID **user_gids)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.lookup_usergroups(domain, mem_ctx,
+ user_sid, num_groups,
+ user_gids);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.lookup_usergroups(domain, mem_ctx,
+ user_sid, num_groups,
+ user_gids);
+
+ return result;
+}
+
+static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 num_sids, const DOM_SID *sids,
+ uint32 *num_aliases, uint32 **alias_rids)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.lookup_useraliases(domain, mem_ctx,
+ num_sids, sids,
+ num_aliases,
+ alias_rids);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.lookup_useraliases(domain, mem_ctx,
+ num_sids, sids,
+ num_aliases,
+ alias_rids);
+
+ return result;
+}
+
+/* Lookup group membership given a rid. */
+static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group_sid, uint32 *num_names,
+ DOM_SID **sid_mem, char ***names,
+ uint32 **name_types)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.lookup_groupmem(domain, mem_ctx,
+ group_sid, num_names,
+ sid_mem, names,
+ name_types);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.lookup_groupmem(domain, mem_ctx,
+ group_sid, num_names,
+ sid_mem, names,
+ name_types);
+
+ return result;
+}
+
+/* find the sequence number for a domain */
+static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.sequence_number(domain, seq);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.sequence_number(domain, seq);
+
+ return result;
+}
+
+/* find the lockout policy of a domain */
+static NTSTATUS lockout_policy(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ struct samr_DomInfo12 *policy)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.lockout_policy(domain, mem_ctx, policy);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.lockout_policy(domain, mem_ctx, policy);
+
+ return result;
+}
+
+/* find the password policy of a domain */
+static NTSTATUS password_policy(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ struct samr_DomInfo1 *policy)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.password_policy(domain, mem_ctx, policy);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.password_policy(domain, mem_ctx, policy);
+
+ return result;
+}
+
+/* get a list of trusted domains */
+static NTSTATUS trusted_domains(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_domains,
+ char ***names,
+ char ***alt_names,
+ DOM_SID **dom_sids)
+{
+ NTSTATUS result;
+
+ result = msrpc_methods.trusted_domains(domain, mem_ctx,
+ num_domains, names,
+ alt_names, dom_sids);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+ result = msrpc_methods.trusted_domains(domain, mem_ctx,
+ num_domains, names,
+ alt_names, dom_sids);
+
+ return result;
+}
+
+/* the rpc backend methods are exposed via this structure */
+struct winbindd_methods reconnect_methods = {
+ False,
+ query_user_list,
+ enum_dom_groups,
+ enum_local_groups,
+ name_to_sid,
+ sid_to_name,
+ rids_to_names,
+ query_user,
+ lookup_usergroups,
+ lookup_useraliases,
+ lookup_groupmem,
+ sequence_number,
+ lockout_policy,
+ password_policy,
+ trusted_domains,
+};
diff --git a/source3/winbindd/winbindd_rpc.c b/source3/winbindd/winbindd_rpc.c
new file mode 100644
index 0000000000..bb79d7ec12
--- /dev/null
+++ b/source3/winbindd/winbindd_rpc.c
@@ -0,0 +1,1167 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind rpc backend functions
+
+ Copyright (C) Tim Potter 2000-2001,2003
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Volker Lendecke 2005
+ Copyright (C) Guenther Deschner 2008 (pidl conversion)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+
+/* Query display info for a domain. This returns enough information plus a
+ bit extra to give an overview of domain users for the User Manager
+ application. */
+static NTSTATUS query_user_list(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ WINBIND_USERINFO **info)
+{
+ NTSTATUS result;
+ POLICY_HND dom_pol;
+ unsigned int i, start_idx;
+ uint32 loop_count;
+ struct rpc_pipe_client *cli;
+
+ DEBUG(3,("rpc: query_user_list\n"));
+
+ *num_entries = 0;
+ *info = NULL;
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
+ domain->name));
+ return NT_STATUS_OK;
+ }
+
+ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ i = start_idx = 0;
+ loop_count = 0;
+
+ do {
+ uint32 num_dom_users, j;
+ uint32 max_entries, max_size;
+ uint32_t total_size, returned_size;
+
+ union samr_DispInfo disp_info;
+
+ /* this next bit is copied from net_user_list_internal() */
+
+ get_query_dispinfo_params(loop_count, &max_entries,
+ &max_size);
+
+ result = rpccli_samr_QueryDisplayInfo(cli, mem_ctx,
+ &dom_pol,
+ 1,
+ start_idx,
+ max_entries,
+ max_size,
+ &total_size,
+ &returned_size,
+ &disp_info);
+ num_dom_users = disp_info.info1.count;
+ start_idx += disp_info.info1.count;
+ loop_count++;
+
+ *num_entries += num_dom_users;
+
+ *info = TALLOC_REALLOC_ARRAY(mem_ctx, *info, WINBIND_USERINFO,
+ *num_entries);
+
+ if (!(*info)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (j = 0; j < num_dom_users; i++, j++) {
+
+ uint32_t rid = disp_info.info1.entries[j].rid;
+
+ (*info)[i].acct_name = talloc_strdup(mem_ctx,
+ disp_info.info1.entries[j].account_name.string);
+ (*info)[i].full_name = talloc_strdup(mem_ctx,
+ disp_info.info1.entries[j].full_name.string);
+ (*info)[i].homedir = NULL;
+ (*info)[i].shell = NULL;
+ sid_compose(&(*info)[i].user_sid, &domain->sid, rid);
+
+ /* For the moment we set the primary group for
+ every user to be the Domain Users group.
+ There are serious problems with determining
+ the actual primary group for large domains.
+ This should really be made into a 'winbind
+ force group' smb.conf parameter or
+ something like that. */
+
+ sid_compose(&(*info)[i].group_sid, &domain->sid,
+ DOMAIN_GROUP_RID_USERS);
+ }
+
+ } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
+
+ return result;
+}
+
+/* list all domain groups */
+static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ POLICY_HND dom_pol;
+ NTSTATUS status;
+ uint32 start = 0;
+ struct rpc_pipe_client *cli;
+
+ *num_entries = 0;
+ *info = NULL;
+
+ DEBUG(3,("rpc: enum_dom_groups\n"));
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("enum_domain_groups: No incoming trust for domain %s\n",
+ domain->name));
+ return NT_STATUS_OK;
+ }
+
+ status = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+ if (!NT_STATUS_IS_OK(status))
+ return status;
+
+ do {
+ struct samr_SamArray *sam_array = NULL;
+ uint32 count = 0;
+ TALLOC_CTX *mem_ctx2;
+ int g;
+
+ mem_ctx2 = talloc_init("enum_dom_groups[rpc]");
+
+ /* start is updated by this call. */
+ status = rpccli_samr_EnumDomainGroups(cli, mem_ctx2,
+ &dom_pol,
+ &start,
+ &sam_array,
+ 0xFFFF, /* buffer size? */
+ &count);
+
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+ talloc_destroy(mem_ctx2);
+ break;
+ }
+
+ (*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info,
+ struct acct_info,
+ (*num_entries) + count);
+ if (! *info) {
+ talloc_destroy(mem_ctx2);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (g=0; g < count; g++) {
+
+ fstrcpy((*info)[*num_entries + g].acct_name,
+ sam_array->entries[g].name.string);
+ (*info)[*num_entries + g].rid = sam_array->entries[g].idx;
+ }
+
+ (*num_entries) += count;
+ talloc_destroy(mem_ctx2);
+ } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
+
+ return NT_STATUS_OK;
+}
+
+/* List all domain groups */
+
+static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ POLICY_HND dom_pol;
+ NTSTATUS result;
+ struct rpc_pipe_client *cli;
+
+ *num_entries = 0;
+ *info = NULL;
+
+ DEBUG(3,("rpc: enum_local_groups\n"));
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("enum_local_groups: No incoming trust for domain %s\n",
+ domain->name));
+ return NT_STATUS_OK;
+ }
+
+ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ do {
+ struct samr_SamArray *sam_array = NULL;
+ uint32 count = 0, start = *num_entries;
+ TALLOC_CTX *mem_ctx2;
+ int g;
+
+ mem_ctx2 = talloc_init("enum_dom_local_groups[rpc]");
+
+ result = rpccli_samr_EnumDomainAliases(cli, mem_ctx2,
+ &dom_pol,
+ &start,
+ &sam_array,
+ 0xFFFF, /* buffer size? */
+ &count);
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES) )
+ {
+ talloc_destroy(mem_ctx2);
+ return result;
+ }
+
+ (*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info,
+ struct acct_info,
+ (*num_entries) + count);
+ if (! *info) {
+ talloc_destroy(mem_ctx2);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (g=0; g < count; g++) {
+
+ fstrcpy((*info)[*num_entries + g].acct_name,
+ sam_array->entries[g].name.string);
+ (*info)[*num_entries + g].rid = sam_array->entries[g].idx;
+ }
+
+ (*num_entries) += count;
+ talloc_destroy(mem_ctx2);
+
+ } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
+
+ return NT_STATUS_OK;
+}
+
+/* convert a single name to a sid in a domain */
+NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ enum winbindd_cmd original_cmd,
+ const char *domain_name,
+ const char *name,
+ DOM_SID *sid,
+ enum lsa_SidType *type)
+{
+ NTSTATUS result;
+ DOM_SID *sids = NULL;
+ enum lsa_SidType *types = NULL;
+ char *full_name = NULL;
+ struct rpc_pipe_client *cli;
+ POLICY_HND lsa_policy;
+
+ if (name == NULL || *name=='\0') {
+ full_name = talloc_asprintf(mem_ctx, "%s", domain_name);
+ } else if (domain_name == NULL || *domain_name == '\0') {
+ full_name = talloc_asprintf(mem_ctx, "%s", name);
+ } else {
+ full_name = talloc_asprintf(mem_ctx, "%s\\%s", domain_name, name);
+ }
+ if (!full_name) {
+ DEBUG(0, ("talloc_asprintf failed!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(3,("rpc: name_to_sid name=%s\n", full_name));
+
+ ws_name_return( full_name, WB_REPLACE_CHAR );
+
+ DEBUG(3,("name_to_sid [rpc] %s for domain %s\n", full_name?full_name:"", domain_name ));
+
+ result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ result = rpccli_lsa_lookup_names(cli, mem_ctx, &lsa_policy, 1,
+ (const char**) &full_name, NULL, 1, &sids, &types);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ /* Return rid and type if lookup successful */
+
+ sid_copy(sid, &sids[0]);
+ *type = types[0];
+
+ return NT_STATUS_OK;
+}
+
+/*
+ convert a domain SID to a user or group name
+*/
+NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ char **domain_name,
+ char **name,
+ enum lsa_SidType *type)
+{
+ char **domains;
+ char **names;
+ enum lsa_SidType *types = NULL;
+ NTSTATUS result;
+ struct rpc_pipe_client *cli;
+ POLICY_HND lsa_policy;
+
+ DEBUG(3,("sid_to_name [rpc] %s for domain %s\n", sid_string_dbg(sid),
+ domain->name ));
+
+ result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(2,("msrpc_sid_to_name: cm_connect_lsa() failed (%s)\n",
+ nt_errstr(result)));
+ return result;
+ }
+
+
+ result = rpccli_lsa_lookup_sids(cli, mem_ctx, &lsa_policy,
+ 1, sid, &domains, &names, &types);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(2,("msrpc_sid_to_name: rpccli_lsa_lookup_sids() failed (%s)\n",
+ nt_errstr(result)));
+ return result;
+ }
+
+ *type = (enum lsa_SidType)types[0];
+ *domain_name = domains[0];
+ *name = names[0];
+
+ ws_name_replace( *name, WB_REPLACE_CHAR );
+
+ DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
+ return NT_STATUS_OK;
+}
+
+NTSTATUS msrpc_rids_to_names(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ uint32 *rids,
+ size_t num_rids,
+ char **domain_name,
+ char ***names,
+ enum lsa_SidType **types)
+{
+ char **domains;
+ NTSTATUS result;
+ struct rpc_pipe_client *cli;
+ POLICY_HND lsa_policy;
+ DOM_SID *sids;
+ size_t i;
+ char **ret_names;
+
+ DEBUG(3, ("rids_to_names [rpc] for domain %s\n", domain->name ));
+
+ if (num_rids) {
+ sids = TALLOC_ARRAY(mem_ctx, DOM_SID, num_rids);
+ if (sids == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ sids = NULL;
+ }
+
+ for (i=0; i<num_rids; i++) {
+ if (!sid_compose(&sids[i], sid, rids[i])) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ }
+
+ result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ result = rpccli_lsa_lookup_sids(cli, mem_ctx, &lsa_policy,
+ num_rids, sids, &domains,
+ names, types);
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
+ return result;
+ }
+
+ ret_names = *names;
+ for (i=0; i<num_rids; i++) {
+ if ((*types)[i] != SID_NAME_UNKNOWN) {
+ ws_name_replace( ret_names[i], WB_REPLACE_CHAR );
+ *domain_name = domains[i];
+ }
+ }
+
+ return result;
+}
+
+/* Lookup user information from a rid or username. */
+static NTSTATUS query_user(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ WINBIND_USERINFO *user_info)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ POLICY_HND dom_pol, user_pol;
+ union samr_UserInfo *info = NULL;
+ uint32 user_rid;
+ struct netr_SamInfo3 *user;
+ struct rpc_pipe_client *cli;
+
+ DEBUG(3,("rpc: query_user sid=%s\n", sid_string_dbg(user_sid)));
+
+ if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ user_info->homedir = NULL;
+ user_info->shell = NULL;
+ user_info->primary_gid = (gid_t)-1;
+
+ /* try netsamlogon cache first */
+
+ if ( (user = netsamlogon_cache_get( mem_ctx, user_sid )) != NULL )
+ {
+
+ DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
+ sid_string_dbg(user_sid)));
+
+ sid_compose(&user_info->user_sid, &domain->sid, user->base.rid);
+ sid_compose(&user_info->group_sid, &domain->sid,
+ user->base.primary_gid);
+
+ user_info->acct_name = talloc_strdup(mem_ctx,
+ user->base.account_name.string);
+ user_info->full_name = talloc_strdup(mem_ctx,
+ user->base.full_name.string);
+
+ TALLOC_FREE(user);
+
+ return NT_STATUS_OK;
+ }
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("query_user: No incoming trust for domain %s\n",
+ domain->name));
+ return NT_STATUS_OK;
+ }
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("query_user: No incoming trust for domain %s\n",
+ domain->name));
+ return NT_STATUS_OK;
+ }
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("query_user: No incoming trust for domain %s\n",
+ domain->name));
+ return NT_STATUS_OK;
+ }
+
+ /* no cache; hit the wire */
+
+ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ /* Get user handle */
+ result = rpccli_samr_OpenUser(cli, mem_ctx,
+ &dom_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ user_rid,
+ &user_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ /* Get user info */
+ result = rpccli_samr_QueryUserInfo(cli, mem_ctx,
+ &user_pol,
+ 0x15,
+ &info);
+
+ rpccli_samr_Close(cli, mem_ctx, &user_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ sid_compose(&user_info->user_sid, &domain->sid, user_rid);
+ sid_compose(&user_info->group_sid, &domain->sid,
+ info->info21.primary_gid);
+ user_info->acct_name = talloc_strdup(mem_ctx,
+ info->info21.account_name.string);
+ user_info->full_name = talloc_strdup(mem_ctx,
+ info->info21.full_name.string);
+ user_info->homedir = NULL;
+ user_info->shell = NULL;
+ user_info->primary_gid = (gid_t)-1;
+
+ return NT_STATUS_OK;
+}
+
+/* Lookup groups a user is a member of. I wish Unix had a call like this! */
+static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ uint32 *num_groups, DOM_SID **user_grpsids)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ POLICY_HND dom_pol, user_pol;
+ uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+ struct samr_RidWithAttributeArray *rid_array = NULL;
+ unsigned int i;
+ uint32 user_rid;
+ struct rpc_pipe_client *cli;
+
+ DEBUG(3,("rpc: lookup_usergroups sid=%s\n", sid_string_dbg(user_sid)));
+
+ if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ *num_groups = 0;
+ *user_grpsids = NULL;
+
+ /* so lets see if we have a cached user_info_3 */
+ result = lookup_usergroups_cached(domain, mem_ctx, user_sid,
+ num_groups, user_grpsids);
+
+ if (NT_STATUS_IS_OK(result)) {
+ return NT_STATUS_OK;
+ }
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
+ domain->name));
+
+ /* Tell the cache manager not to remember this one */
+
+ return NT_STATUS_SYNCHRONIZATION_REQUIRED;
+ }
+
+ /* no cache; hit the wire */
+
+ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ /* Get user handle */
+ result = rpccli_samr_OpenUser(cli, mem_ctx,
+ &dom_pol,
+ des_access,
+ user_rid,
+ &user_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ /* Query user rids */
+ result = rpccli_samr_GetGroupsForUser(cli, mem_ctx,
+ &user_pol,
+ &rid_array);
+ *num_groups = rid_array->count;
+
+ rpccli_samr_Close(cli, mem_ctx, &user_pol);
+
+ if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
+ return result;
+
+ (*user_grpsids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
+ if (!(*user_grpsids))
+ return NT_STATUS_NO_MEMORY;
+
+ for (i=0;i<(*num_groups);i++) {
+ sid_copy(&((*user_grpsids)[i]), &domain->sid);
+ sid_append_rid(&((*user_grpsids)[i]),
+ rid_array->rids[i].rid);
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS msrpc_lookup_useraliases(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 num_sids, const DOM_SID *sids,
+ uint32 *num_aliases, uint32 **alias_rids)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ POLICY_HND dom_pol;
+ uint32 num_query_sids = 0;
+ int i;
+ struct rpc_pipe_client *cli;
+ struct samr_Ids alias_rids_query;
+ int rangesize = MAX_SAM_ENTRIES_W2K;
+ uint32 total_sids = 0;
+ int num_queries = 1;
+
+ *num_aliases = 0;
+ *alias_rids = NULL;
+
+ DEBUG(3,("rpc: lookup_useraliases\n"));
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("msrpc_lookup_useraliases: No incoming trust for domain %s\n",
+ domain->name));
+ return NT_STATUS_OK;
+ }
+
+ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ do {
+ /* prepare query */
+ struct lsa_SidArray sid_array;
+
+ ZERO_STRUCT(sid_array);
+
+ num_query_sids = MIN(num_sids - total_sids, rangesize);
+
+ DEBUG(10,("rpc: lookup_useraliases: entering query %d for %d sids\n",
+ num_queries, num_query_sids));
+
+ if (num_query_sids) {
+ sid_array.sids = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_SidPtr, num_query_sids);
+ if (sid_array.sids == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ sid_array.sids = NULL;
+ }
+
+ for (i=0; i<num_query_sids; i++) {
+ sid_array.sids[i].sid = sid_dup_talloc(mem_ctx, &sids[total_sids++]);
+ if (!sid_array.sids[i].sid) {
+ TALLOC_FREE(sid_array.sids);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ sid_array.num_sids = num_query_sids;
+
+ /* do request */
+ result = rpccli_samr_GetAliasMembership(cli, mem_ctx,
+ &dom_pol,
+ &sid_array,
+ &alias_rids_query);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ *num_aliases = 0;
+ *alias_rids = NULL;
+ TALLOC_FREE(sid_array.sids);
+ goto done;
+ }
+
+ /* process output */
+
+ for (i=0; i<alias_rids_query.count; i++) {
+ size_t na = *num_aliases;
+ if (!add_rid_to_array_unique(mem_ctx, alias_rids_query.ids[i],
+ alias_rids, &na)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ *num_aliases = na;
+ }
+
+ TALLOC_FREE(sid_array.sids);
+
+ num_queries++;
+
+ } while (total_sids < num_sids);
+
+ done:
+ DEBUG(10,("rpc: lookup_useraliases: got %d aliases in %d queries "
+ "(rangesize: %d)\n", *num_aliases, num_queries, rangesize));
+
+ return result;
+}
+
+
+/* Lookup group membership given a rid. */
+static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group_sid, uint32 *num_names,
+ DOM_SID **sid_mem, char ***names,
+ uint32 **name_types)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 i, total_names = 0;
+ POLICY_HND dom_pol, group_pol;
+ uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+ uint32 *rid_mem = NULL;
+ uint32 group_rid;
+ unsigned int j, r;
+ struct rpc_pipe_client *cli;
+ unsigned int orig_timeout;
+ struct samr_RidTypeArray *rids = NULL;
+
+ DEBUG(10,("rpc: lookup_groupmem %s sid=%s\n", domain->name,
+ sid_string_dbg(group_sid)));
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
+ domain->name));
+ return NT_STATUS_OK;
+ }
+
+ if (!sid_peek_check_rid(&domain->sid, group_sid, &group_rid))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ *num_names = 0;
+
+ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ result = rpccli_samr_OpenGroup(cli, mem_ctx,
+ &dom_pol,
+ des_access,
+ group_rid,
+ &group_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ /* Step #1: Get a list of user rids that are the members of the
+ group. */
+
+ /* This call can take a long time - allow the server to time out.
+ 35 seconds should do it. */
+
+ orig_timeout = rpccli_set_timeout(cli, 35000);
+
+ result = rpccli_samr_QueryGroupMember(cli, mem_ctx,
+ &group_pol,
+ &rids);
+
+ /* And restore our original timeout. */
+ rpccli_set_timeout(cli, orig_timeout);
+
+ rpccli_samr_Close(cli, mem_ctx, &group_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ *num_names = rids->count;
+ rid_mem = rids->rids;
+
+ if (!*num_names) {
+ names = NULL;
+ name_types = NULL;
+ sid_mem = NULL;
+ return NT_STATUS_OK;
+ }
+
+ /* Step #2: Convert list of rids into list of usernames. Do this
+ in bunches of ~1000 to avoid crashing NT4. It looks like there
+ is a buffer overflow or something like that lurking around
+ somewhere. */
+
+#define MAX_LOOKUP_RIDS 900
+
+ *names = TALLOC_ZERO_ARRAY(mem_ctx, char *, *num_names);
+ *name_types = TALLOC_ZERO_ARRAY(mem_ctx, uint32, *num_names);
+ *sid_mem = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, *num_names);
+
+ for (j=0;j<(*num_names);j++)
+ sid_compose(&(*sid_mem)[j], &domain->sid, rid_mem[j]);
+
+ if (*num_names>0 && (!*names || !*name_types))
+ return NT_STATUS_NO_MEMORY;
+
+ for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
+ int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
+ struct lsa_Strings tmp_names;
+ struct samr_Ids tmp_types;
+
+ /* Lookup a chunk of rids */
+
+ result = rpccli_samr_LookupRids(cli, mem_ctx,
+ &dom_pol,
+ num_lookup_rids,
+ &rid_mem[i],
+ &tmp_names,
+ &tmp_types);
+
+ /* see if we have a real error (and yes the
+ STATUS_SOME_UNMAPPED is the one returned from 2k) */
+
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED))
+ return result;
+
+ /* Copy result into array. The talloc system will take
+ care of freeing the temporary arrays later on. */
+
+ if (tmp_names.count != tmp_types.count) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ for (r=0; r<tmp_names.count; r++) {
+ (*names)[i+r] = CONST_DISCARD(char *, tmp_names.names[r].string);
+ (*name_types)[i+r] = tmp_types.ids[r];
+ }
+
+ total_names += tmp_names.count;
+ }
+
+ *num_names = total_names;
+
+ return NT_STATUS_OK;
+}
+
+#ifdef HAVE_LDAP
+
+#include <ldap.h>
+
+static int get_ldap_seq(const char *server, int port, uint32 *seq)
+{
+ int ret = -1;
+ struct timeval to;
+ const char *attrs[] = {"highestCommittedUSN", NULL};
+ LDAPMessage *res = NULL;
+ char **values = NULL;
+ LDAP *ldp = NULL;
+
+ *seq = DOM_SEQUENCE_NONE;
+
+ /*
+ * Parameterised (5) second timeout on open. This is needed as the
+ * search timeout doesn't seem to apply to doing an open as well. JRA.
+ */
+
+ ldp = ldap_open_with_timeout(server, port, lp_ldap_timeout());
+ if (ldp == NULL)
+ return -1;
+
+ /* Timeout if no response within 20 seconds. */
+ to.tv_sec = 10;
+ to.tv_usec = 0;
+
+ if (ldap_search_st(ldp, "", LDAP_SCOPE_BASE, "(objectclass=*)",
+ CONST_DISCARD(char **, attrs), 0, &to, &res))
+ goto done;
+
+ if (ldap_count_entries(ldp, res) != 1)
+ goto done;
+
+ values = ldap_get_values(ldp, res, "highestCommittedUSN");
+ if (!values || !values[0])
+ goto done;
+
+ *seq = atoi(values[0]);
+ ret = 0;
+
+ done:
+
+ if (values)
+ ldap_value_free(values);
+ if (res)
+ ldap_msgfree(res);
+ if (ldp)
+ ldap_unbind(ldp);
+ return ret;
+}
+
+/**********************************************************************
+ Get the sequence number for a Windows AD native mode domain using
+ LDAP queries.
+**********************************************************************/
+
+static int get_ldap_sequence_number(struct winbindd_domain *domain, uint32 *seq)
+{
+ int ret = -1;
+ char addr[INET6_ADDRSTRLEN];
+
+ print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
+ if ((ret = get_ldap_seq(addr, LDAP_PORT, seq)) == 0) {
+ DEBUG(3, ("get_ldap_sequence_number: Retrieved sequence "
+ "number for Domain (%s) from DC (%s)\n",
+ domain->name, addr));
+ }
+ return ret;
+}
+
+#endif /* HAVE_LDAP */
+
+/* find the sequence number for a domain */
+static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
+{
+ TALLOC_CTX *mem_ctx;
+ union samr_DomainInfo *info = NULL;
+ NTSTATUS result;
+ POLICY_HND dom_pol;
+ bool got_seq_num = False;
+ struct rpc_pipe_client *cli;
+
+ DEBUG(10,("rpc: fetch sequence_number for %s\n", domain->name));
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("sequence_number: No incoming trust for domain %s\n",
+ domain->name));
+ *seq = time(NULL);
+ return NT_STATUS_OK;
+ }
+
+ *seq = DOM_SEQUENCE_NONE;
+
+ if (!(mem_ctx = talloc_init("sequence_number[rpc]")))
+ return NT_STATUS_NO_MEMORY;
+
+#ifdef HAVE_LDAP
+ if ( domain->active_directory )
+ {
+ int res;
+
+ DEBUG(8,("using get_ldap_seq() to retrieve the "
+ "sequence number\n"));
+
+ res = get_ldap_sequence_number( domain, seq );
+ if (res == 0)
+ {
+ result = NT_STATUS_OK;
+ DEBUG(10,("domain_sequence_number: LDAP for "
+ "domain %s is %u\n",
+ domain->name, *seq));
+ goto done;
+ }
+
+ DEBUG(10,("domain_sequence_number: failed to get LDAP "
+ "sequence number for domain %s\n",
+ domain->name ));
+ }
+#endif /* HAVE_LDAP */
+
+ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Query domain info */
+
+ result = rpccli_samr_QueryDomainInfo(cli, mem_ctx,
+ &dom_pol,
+ 8,
+ &info);
+
+ if (NT_STATUS_IS_OK(result)) {
+ *seq = info->info8.sequence_num;
+ got_seq_num = True;
+ goto seq_num;
+ }
+
+ /* retry with info-level 2 in case the dc does not support info-level 8
+ * (like all older samba2 and samba3 dc's) - Guenther */
+
+ result = rpccli_samr_QueryDomainInfo(cli, mem_ctx,
+ &dom_pol,
+ 2,
+ &info);
+
+ if (NT_STATUS_IS_OK(result)) {
+ *seq = info->info2.sequence_num;
+ got_seq_num = True;
+ }
+
+ seq_num:
+ if (got_seq_num) {
+ DEBUG(10,("domain_sequence_number: for domain %s is %u\n",
+ domain->name, (unsigned)*seq));
+ } else {
+ DEBUG(10,("domain_sequence_number: failed to get sequence "
+ "number (%u) for domain %s\n",
+ (unsigned)*seq, domain->name ));
+ }
+
+ done:
+
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
+
+/* get a list of trusted domains */
+static NTSTATUS trusted_domains(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_domains,
+ char ***names,
+ char ***alt_names,
+ DOM_SID **dom_sids)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 enum_ctx = 0;
+ struct rpc_pipe_client *cli;
+ POLICY_HND lsa_policy;
+
+ DEBUG(3,("rpc: trusted_domains\n"));
+
+ *num_domains = 0;
+ *names = NULL;
+ *alt_names = NULL;
+ *dom_sids = NULL;
+
+ result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ result = STATUS_MORE_ENTRIES;
+
+ while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) {
+ uint32 start_idx;
+ int i;
+ struct lsa_DomainList dom_list;
+
+ result = rpccli_lsa_EnumTrustDom(cli, mem_ctx,
+ &lsa_policy,
+ &enum_ctx,
+ &dom_list,
+ (uint32_t)-1);
+
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
+ break;
+
+ start_idx = *num_domains;
+ *num_domains += dom_list.count;
+ *names = TALLOC_REALLOC_ARRAY(mem_ctx, *names,
+ char *, *num_domains);
+ *dom_sids = TALLOC_REALLOC_ARRAY(mem_ctx, *dom_sids,
+ DOM_SID, *num_domains);
+ *alt_names = TALLOC_REALLOC_ARRAY(mem_ctx, *alt_names,
+ char *, *num_domains);
+ if ((*names == NULL) || (*dom_sids == NULL) ||
+ (*alt_names == NULL))
+ return NT_STATUS_NO_MEMORY;
+
+ for (i=0; i<dom_list.count; i++) {
+ (*names)[start_idx+i] = CONST_DISCARD(char *, dom_list.domains[i].name.string);
+ (*dom_sids)[start_idx+i] = *dom_list.domains[i].sid;
+ (*alt_names)[start_idx+i] = talloc_strdup(mem_ctx, "");
+ }
+ }
+ return result;
+}
+
+/* find the lockout policy for a domain */
+NTSTATUS msrpc_lockout_policy(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ struct samr_DomInfo12 *lockout_policy)
+{
+ NTSTATUS result;
+ struct rpc_pipe_client *cli;
+ POLICY_HND dom_pol;
+ union samr_DomainInfo *info = NULL;
+
+ DEBUG(10,("rpc: fetch lockout policy for %s\n", domain->name));
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("msrpc_lockout_policy: No incoming trust for domain %s\n",
+ domain->name));
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_samr_QueryDomainInfo(cli, mem_ctx,
+ &dom_pol,
+ 12,
+ &info);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ *lockout_policy = info->info12;
+
+ DEBUG(10,("msrpc_lockout_policy: lockout_threshold %d\n",
+ info->info12.lockout_threshold));
+
+ done:
+
+ return result;
+}
+
+/* find the password policy for a domain */
+NTSTATUS msrpc_password_policy(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ struct samr_DomInfo1 *password_policy)
+{
+ NTSTATUS result;
+ struct rpc_pipe_client *cli;
+ POLICY_HND dom_pol;
+ union samr_DomainInfo *info = NULL;
+
+ DEBUG(10,("rpc: fetch password policy for %s\n", domain->name));
+
+ if ( !winbindd_can_contact_domain( domain ) ) {
+ DEBUG(10,("msrpc_password_policy: No incoming trust for domain %s\n",
+ domain->name));
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = rpccli_samr_QueryDomainInfo(cli, mem_ctx,
+ &dom_pol,
+ 1,
+ &info);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ *password_policy = info->info1;
+
+ DEBUG(10,("msrpc_password_policy: min_length_password %d\n",
+ info->info1.min_password_length));
+
+ done:
+
+ return result;
+}
+
+
+/* the rpc backend methods are exposed via this structure */
+struct winbindd_methods msrpc_methods = {
+ False,
+ query_user_list,
+ enum_dom_groups,
+ enum_local_groups,
+ msrpc_name_to_sid,
+ msrpc_sid_to_name,
+ msrpc_rids_to_names,
+ query_user,
+ lookup_usergroups,
+ msrpc_lookup_useraliases,
+ lookup_groupmem,
+ sequence_number,
+ msrpc_lockout_policy,
+ msrpc_password_policy,
+ trusted_domains,
+};
diff --git a/source3/winbindd/winbindd_sid.c b/source3/winbindd/winbindd_sid.c
new file mode 100644
index 0000000000..274786fa63
--- /dev/null
+++ b/source3/winbindd/winbindd_sid.c
@@ -0,0 +1,612 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon - sid related functions
+
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+/* Convert a string */
+
+static void lookupsid_recv(void *private_data, bool success,
+ const char *dom_name, const char *name,
+ enum lsa_SidType type);
+
+void winbindd_lookupsid(struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+
+ /* Ensure null termination */
+ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+ DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
+ state->request.data.sid));
+
+ if (!string_to_sid(&sid, state->request.data.sid)) {
+ DEBUG(5, ("%s not a SID\n", state->request.data.sid));
+ request_error(state);
+ return;
+ }
+
+ winbindd_lookupsid_async(state->mem_ctx, &sid, lookupsid_recv, state);
+}
+
+static void lookupsid_recv(void *private_data, bool success,
+ const char *dom_name, const char *name,
+ enum lsa_SidType type)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private_data, struct winbindd_cli_state);
+
+ if (!success) {
+ DEBUG(5, ("lookupsid returned an error\n"));
+ request_error(state);
+ return;
+ }
+
+ fstrcpy(state->response.data.name.dom_name, dom_name);
+ fstrcpy(state->response.data.name.name, name);
+ state->response.data.name.type = type;
+ request_ok(state);
+}
+
+/**
+ * Look up the SID for a qualified name.
+ **/
+
+static void lookupname_recv(void *private_data, bool success,
+ const DOM_SID *sid, enum lsa_SidType type);
+
+void winbindd_lookupname(struct winbindd_cli_state *state)
+{
+ char *name_domain, *name_user;
+ char *p;
+
+ /* Ensure null termination */
+ state->request.data.name.dom_name[sizeof(state->request.data.name.dom_name)-1]='\0';
+
+ /* Ensure null termination */
+ state->request.data.name.name[sizeof(state->request.data.name.name)-1]='\0';
+
+ /* cope with the name being a fully qualified name */
+ p = strstr(state->request.data.name.name, lp_winbind_separator());
+ if (p) {
+ *p = 0;
+ name_domain = state->request.data.name.name;
+ name_user = p+1;
+ } else {
+ name_domain = state->request.data.name.dom_name;
+ name_user = state->request.data.name.name;
+ }
+
+ DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid,
+ name_domain, lp_winbind_separator(), name_user));
+
+ winbindd_lookupname_async(state->mem_ctx, name_domain, name_user,
+ lookupname_recv, WINBINDD_LOOKUPNAME,
+ state);
+}
+
+static void lookupname_recv(void *private_data, bool success,
+ const DOM_SID *sid, enum lsa_SidType type)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private_data, struct winbindd_cli_state);
+
+ if (!success) {
+ DEBUG(5, ("lookupname returned an error\n"));
+ request_error(state);
+ return;
+ }
+
+ sid_to_fstring(state->response.data.sid.sid, sid);
+ state->response.data.sid.type = type;
+ request_ok(state);
+ return;
+}
+
+void winbindd_lookuprids(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+ DOM_SID domain_sid;
+
+ /* Ensure null termination */
+ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+ DEBUG(10, ("lookup_rids: %s\n", state->request.data.sid));
+
+ if (!string_to_sid(&domain_sid, state->request.data.sid)) {
+ DEBUG(5, ("Could not convert %s to SID\n",
+ state->request.data.sid));
+ request_error(state);
+ return;
+ }
+
+ domain = find_lookup_domain_from_sid(&domain_sid);
+ if (domain == NULL) {
+ DEBUG(10, ("Could not find domain for name %s\n",
+ state->request.domain_name));
+ request_error(state);
+ return;
+ }
+
+ sendto_domain(state, domain);
+}
+
+/* Convert a sid to a uid. We assume we only have one rid attached to the
+ sid. */
+
+static void sid2uid_recv(void *private_data, bool success, uid_t uid)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private_data, struct winbindd_cli_state);
+ struct dom_sid sid;
+
+ string_to_sid(&sid, state->request.data.sid);
+
+ if (!success) {
+ DEBUG(5, ("Could not convert sid %s\n",
+ state->request.data.sid));
+ request_error(state);
+ return;
+ }
+
+ state->response.data.uid = uid;
+ request_ok(state);
+}
+
+static void sid2uid_lookupsid_recv( void *private_data, bool success,
+ const char *domain_name,
+ const char *name,
+ enum lsa_SidType type)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private_data, struct winbindd_cli_state);
+ DOM_SID sid;
+
+ if (!string_to_sid(&sid, state->request.data.sid)) {
+ DEBUG(1, ("sid2uid_lookupsid_recv: Could not get convert sid "
+ "%s from string\n", state->request.data.sid));
+ request_error(state);
+ return;
+ }
+
+ if (!success) {
+ DEBUG(5, ("sid2uid_lookupsid_recv Could not convert get sid type for %s\n",
+ state->request.data.sid));
+ goto fail;
+ }
+
+ if ( (type!=SID_NAME_USER) && (type!=SID_NAME_COMPUTER) ) {
+ DEBUG(5,("sid2uid_lookupsid_recv: Sid %s is not a user or a computer.\n",
+ state->request.data.sid));
+ goto fail;
+ }
+
+ /* always use the async interface (may block) */
+ winbindd_sid2uid_async(state->mem_ctx, &sid, sid2uid_recv, state);
+ return;
+
+ fail:
+ /*
+ * We have to set the cache ourselves here, the child which is
+ * normally responsible was not queried yet.
+ */
+ idmap_cache_set_sid2uid(&sid, -1);
+ request_error(state);
+ return;
+}
+
+void winbindd_sid_to_uid(struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ uid_t uid;
+ bool expired;
+
+ /* Ensure null termination */
+ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+ DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
+ state->request.data.sid));
+
+ if (!string_to_sid(&sid, state->request.data.sid)) {
+ DEBUG(1, ("Could not get convert sid %s from string\n",
+ state->request.data.sid));
+ request_error(state);
+ return;
+ }
+
+ if (idmap_cache_find_sid2uid(&sid, &uid, &expired)) {
+ DEBUG(10, ("idmap_cache_find_sid2uid found %d%s\n",
+ (int)uid, expired ? " (expired)": ""));
+ if (expired && IS_DOMAIN_ONLINE(find_our_domain())) {
+ DEBUG(10, ("revalidating expired entry\n"));
+ goto backend;
+ }
+ if (uid == -1) {
+ DEBUG(10, ("Returning negative cache entry\n"));
+ request_error(state);
+ return;
+ }
+ DEBUG(10, ("Returning positive cache entry\n"));
+ state->response.data.uid = uid;
+ request_ok(state);
+ return;
+ }
+
+ /* Validate the SID as a user. Hopefully this will hit cache.
+ Needed to prevent DoS by exhausting the uid allocation
+ range from random SIDs. */
+
+ backend:
+ winbindd_lookupsid_async( state->mem_ctx, &sid, sid2uid_lookupsid_recv, state );
+}
+
+/* Convert a sid to a gid. We assume we only have one rid attached to the
+ sid.*/
+
+static void sid2gid_recv(void *private_data, bool success, gid_t gid)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private_data, struct winbindd_cli_state);
+ struct dom_sid sid;
+
+ string_to_sid(&sid, state->request.data.sid);
+
+ if (!success) {
+ DEBUG(5, ("Could not convert sid %s\n",
+ state->request.data.sid));
+ request_error(state);
+ return;
+ }
+
+ state->response.data.gid = gid;
+ request_ok(state);
+}
+
+static void sid2gid_lookupsid_recv( void *private_data, bool success,
+ const char *domain_name,
+ const char *name,
+ enum lsa_SidType type)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private_data, struct winbindd_cli_state);
+ DOM_SID sid;
+
+ if (!string_to_sid(&sid, state->request.data.sid)) {
+ DEBUG(1, ("sid2gid_lookupsid_recv: Could not get convert sid "
+ "%s from string\n", state->request.data.sid));
+ request_error(state);
+ return;
+ }
+
+ if (!success) {
+ DEBUG(5, ("sid2gid_lookupsid_recv: Could not get sid type for %s\n",
+ state->request.data.sid));
+ goto fail;
+ }
+
+ if ( (type!=SID_NAME_DOM_GRP) &&
+ (type!=SID_NAME_ALIAS) &&
+ (type!=SID_NAME_WKN_GRP) )
+ {
+ DEBUG(5,("sid2gid_lookupsid_recv: Sid %s is not a group.\n",
+ state->request.data.sid));
+ goto fail;
+ }
+
+ /* always use the async interface (may block) */
+ winbindd_sid2gid_async(state->mem_ctx, &sid, sid2gid_recv, state);
+ return;
+
+ fail:
+ /*
+ * We have to set the cache ourselves here, the child which is
+ * normally responsible was not queried yet.
+ */
+ idmap_cache_set_sid2gid(&sid, -1);
+ request_error(state);
+ return;
+}
+
+void winbindd_sid_to_gid(struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ gid_t gid;
+ bool expired;
+
+ /* Ensure null termination */
+ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+ DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
+ state->request.data.sid));
+
+ if (!string_to_sid(&sid, state->request.data.sid)) {
+ DEBUG(1, ("Could not get convert sid %s from string\n",
+ state->request.data.sid));
+ request_error(state);
+ return;
+ }
+
+ if (idmap_cache_find_sid2gid(&sid, &gid, &expired)) {
+ DEBUG(10, ("idmap_cache_find_sid2gid found %d%s\n",
+ (int)gid, expired ? " (expired)": ""));
+ if (expired && IS_DOMAIN_ONLINE(find_our_domain())) {
+ DEBUG(10, ("revalidating expired entry\n"));
+ goto backend;
+ }
+ if (gid == -1) {
+ DEBUG(10, ("Returning negative cache entry\n"));
+ request_error(state);
+ return;
+ }
+ DEBUG(10, ("Returning positive cache entry\n"));
+ state->response.data.gid = gid;
+ request_ok(state);
+ return;
+ }
+
+ /* Validate the SID as a group. Hopefully this will hit cache.
+ Needed to prevent DoS by exhausting the uid allocation
+ range from random SIDs. */
+
+ backend:
+ winbindd_lookupsid_async( state->mem_ctx, &sid, sid2gid_lookupsid_recv, state );
+}
+
+static void set_mapping_recv(void *private_data, bool success)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private_data, struct winbindd_cli_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not set sid mapping\n"));
+ request_error(state);
+ return;
+ }
+
+ request_ok(state);
+}
+
+void winbindd_set_mapping(struct winbindd_cli_state *state)
+{
+ struct id_map map;
+ DOM_SID sid;
+
+ DEBUG(3, ("[%5lu]: set id map\n", (unsigned long)state->pid));
+
+ if ( ! state->privileged) {
+ DEBUG(0, ("Only root is allowed to set mappings!\n"));
+ request_error(state);
+ return;
+ }
+
+ if (!string_to_sid(&sid, state->request.data.dual_idmapset.sid)) {
+ DEBUG(1, ("Could not get convert sid %s from string\n",
+ state->request.data.sid));
+ request_error(state);
+ return;
+ }
+
+ map.sid = &sid;
+ map.xid.id = state->request.data.dual_idmapset.id;
+ map.xid.type = state->request.data.dual_idmapset.type;
+
+ winbindd_set_mapping_async(state->mem_ctx, &map,
+ set_mapping_recv, state);
+}
+
+static void set_hwm_recv(void *private_data, bool success)
+{
+ struct winbindd_cli_state *state =
+ talloc_get_type_abort(private_data, struct winbindd_cli_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not set sid mapping\n"));
+ request_error(state);
+ return;
+ }
+
+ request_ok(state);
+}
+
+void winbindd_set_hwm(struct winbindd_cli_state *state)
+{
+ struct unixid xid;
+
+ DEBUG(3, ("[%5lu]: set hwm\n", (unsigned long)state->pid));
+
+ if ( ! state->privileged) {
+ DEBUG(0, ("Only root is allowed to set mappings!\n"));
+ request_error(state);
+ return;
+ }
+
+ xid.id = state->request.data.dual_idmapset.id;
+ xid.type = state->request.data.dual_idmapset.type;
+
+ winbindd_set_hwm_async(state->mem_ctx, &xid, set_hwm_recv, state);
+}
+
+/* Convert a uid to a sid */
+
+static void uid2sid_recv(void *private_data, bool success, const char *sidstr)
+{
+ struct winbindd_cli_state *state =
+ (struct winbindd_cli_state *)private_data;
+ struct dom_sid sid;
+
+ if (!success || !string_to_sid(&sid, sidstr)) {
+ ZERO_STRUCT(sid);
+ idmap_cache_set_sid2uid(&sid, state->request.data.uid);
+ request_error(state);
+ return;
+ }
+
+ DEBUG(10,("uid2sid: uid %lu has sid %s\n",
+ (unsigned long)(state->request.data.uid), sidstr));
+
+ idmap_cache_set_sid2uid(&sid, state->request.data.uid);
+ fstrcpy(state->response.data.sid.sid, sidstr);
+ state->response.data.sid.type = SID_NAME_USER;
+ request_ok(state);
+ return;
+}
+
+void winbindd_uid_to_sid(struct winbindd_cli_state *state)
+{
+ struct dom_sid sid;
+ bool expired;
+
+ DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid,
+ (unsigned long)state->request.data.uid));
+
+ if (idmap_cache_find_uid2sid(state->request.data.uid, &sid,
+ &expired)) {
+ DEBUG(10, ("idmap_cache_find_uid2sid found %d%s\n",
+ (int)state->request.data.uid,
+ expired ? " (expired)": ""));
+ if (expired && IS_DOMAIN_ONLINE(find_our_domain())) {
+ DEBUG(10, ("revalidating expired entry\n"));
+ goto backend;
+ }
+ if (is_null_sid(&sid)) {
+ DEBUG(10, ("Returning negative cache entry\n"));
+ request_error(state);
+ return;
+ }
+ DEBUG(10, ("Returning positive cache entry\n"));
+ sid_to_fstring(state->response.data.sid.sid, &sid);
+ request_ok(state);
+ return;
+ }
+
+ /* always go via the async interface (may block) */
+ backend:
+ winbindd_uid2sid_async(state->mem_ctx, state->request.data.uid, uid2sid_recv, state);
+}
+
+/* Convert a gid to a sid */
+
+static void gid2sid_recv(void *private_data, bool success, const char *sidstr)
+{
+ struct winbindd_cli_state *state =
+ (struct winbindd_cli_state *)private_data;
+ struct dom_sid sid;
+
+ if (!success || !string_to_sid(&sid, sidstr)) {
+ ZERO_STRUCT(sid);
+ idmap_cache_set_sid2gid(&sid, state->request.data.gid);
+ request_error(state);
+ return;
+ }
+ DEBUG(10,("gid2sid: gid %lu has sid %s\n",
+ (unsigned long)(state->request.data.gid), sidstr));
+
+ idmap_cache_set_sid2gid(&sid, state->request.data.gid);
+ fstrcpy(state->response.data.sid.sid, sidstr);
+ state->response.data.sid.type = SID_NAME_DOM_GRP;
+ request_ok(state);
+ return;
+}
+
+
+void winbindd_gid_to_sid(struct winbindd_cli_state *state)
+{
+ struct dom_sid sid;
+ bool expired;
+
+ DEBUG(3, ("[%5lu]: gid to sid %lu\n", (unsigned long)state->pid,
+ (unsigned long)state->request.data.gid));
+
+ if (idmap_cache_find_gid2sid(state->request.data.gid, &sid,
+ &expired)) {
+ DEBUG(10, ("idmap_cache_find_gid2sid found %d%s\n",
+ (int)state->request.data.gid,
+ expired ? " (expired)": ""));
+ if (expired && IS_DOMAIN_ONLINE(find_our_domain())) {
+ DEBUG(10, ("revalidating expired entry\n"));
+ goto backend;
+ }
+ if (is_null_sid(&sid)) {
+ DEBUG(10, ("Returning negative cache entry\n"));
+ request_error(state);
+ return;
+ }
+ DEBUG(10, ("Returning positive cache entry\n"));
+ sid_to_fstring(state->response.data.sid.sid, &sid);
+ request_ok(state);
+ return;
+ }
+
+ /* always use async calls (may block) */
+ backend:
+ winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, gid2sid_recv, state);
+}
+
+void winbindd_allocate_uid(struct winbindd_cli_state *state)
+{
+ if ( !state->privileged ) {
+ DEBUG(2, ("winbindd_allocate_uid: non-privileged access "
+ "denied!\n"));
+ request_error(state);
+ return;
+ }
+
+ sendto_child(state, idmap_child());
+}
+
+enum winbindd_result winbindd_dual_allocate_uid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ struct unixid xid;
+
+ if (!NT_STATUS_IS_OK(idmap_allocate_uid(&xid))) {
+ return WINBINDD_ERROR;
+ }
+ state->response.data.uid = xid.id;
+ return WINBINDD_OK;
+}
+
+void winbindd_allocate_gid(struct winbindd_cli_state *state)
+{
+ if ( !state->privileged ) {
+ DEBUG(2, ("winbindd_allocate_gid: non-privileged access "
+ "denied!\n"));
+ request_error(state);
+ return;
+ }
+
+ sendto_child(state, idmap_child());
+}
+
+enum winbindd_result winbindd_dual_allocate_gid(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ struct unixid xid;
+
+ if (!NT_STATUS_IS_OK(idmap_allocate_gid(&xid))) {
+ return WINBINDD_ERROR;
+ }
+ state->response.data.gid = xid.id;
+ return WINBINDD_OK;
+}
diff --git a/source3/winbindd/winbindd_user.c b/source3/winbindd/winbindd_user.c
new file mode 100644
index 0000000000..3b6dfdda1c
--- /dev/null
+++ b/source3/winbindd/winbindd_user.c
@@ -0,0 +1,783 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon - user related functions
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Jeremy Allison 2001.
+ Copyright (C) Gerald (Jerry) Carter 2003.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+static bool fillup_pw_field(const char *lp_template,
+ const char *username,
+ const char *domname,
+ uid_t uid,
+ gid_t gid,
+ const char *in,
+ fstring out)
+{
+ char *templ;
+
+ if (out == NULL)
+ return False;
+
+ /* The substitution of %U and %D in the 'template
+ homedir' is done by talloc_sub_specified() below.
+ If we have an in string (which means the value has already
+ been set in the nss_info backend), then use that.
+ Otherwise use the template value passed in. */
+
+ if ( in && !strequal(in,"") && lp_security() == SEC_ADS ) {
+ templ = talloc_sub_specified(NULL, in,
+ username, domname,
+ uid, gid);
+ } else {
+ templ = talloc_sub_specified(NULL, lp_template,
+ username, domname,
+ uid, gid);
+ }
+
+ if (!templ)
+ return False;
+
+ safe_strcpy(out, templ, sizeof(fstring) - 1);
+ TALLOC_FREE(templ);
+
+ return True;
+
+}
+/* Fill a pwent structure with information we have obtained */
+
+static bool winbindd_fill_pwent(char *dom_name, char *user_name,
+ DOM_SID *user_sid, DOM_SID *group_sid,
+ char *full_name, char *homedir, char *shell,
+ struct winbindd_pw *pw)
+{
+ fstring output_username;
+
+ if (!pw || !dom_name || !user_name)
+ return False;
+
+ /* Resolve the uid number */
+
+ if (!NT_STATUS_IS_OK(idmap_sid_to_uid(dom_name, user_sid,
+ &pw->pw_uid))) {
+ DEBUG(1, ("error getting user id for sid %s\n",
+ sid_string_dbg(user_sid)));
+ return False;
+ }
+
+ /* Resolve the gid number */
+
+ if (!NT_STATUS_IS_OK(idmap_sid_to_gid(dom_name, group_sid,
+ &pw->pw_gid))) {
+ DEBUG(1, ("error getting group id for sid %s\n",
+ sid_string_dbg(group_sid)));
+ return False;
+ }
+
+ strlower_m(user_name);
+
+ /* Username */
+
+ fill_domain_username(output_username, dom_name, user_name, True);
+
+ safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
+
+ /* Full name (gecos) */
+
+ safe_strcpy(pw->pw_gecos, full_name, sizeof(pw->pw_gecos) - 1);
+
+ /* Home directory and shell */
+
+ if (!fillup_pw_field(lp_template_homedir(), user_name, dom_name,
+ pw->pw_uid, pw->pw_gid, homedir, pw->pw_dir))
+ return False;
+
+ if (!fillup_pw_field(lp_template_shell(), user_name, dom_name,
+ pw->pw_uid, pw->pw_gid, shell, pw->pw_shell))
+ return False;
+
+ /* Password - set to "*" as we can't generate anything useful here.
+ Authentication can be done using the pam_winbind module. */
+
+ safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
+
+ return True;
+}
+
+/* Wrapper for domain->methods->query_user, only on the parent->child pipe */
+
+enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ WINBIND_USERINFO user_info;
+ NTSTATUS status;
+
+ /* Ensure null termination */
+ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+ DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
+ state->request.data.sid));
+
+ if (!string_to_sid(&sid, state->request.data.sid)) {
+ DEBUG(5, ("%s not a SID\n", state->request.data.sid));
+ return WINBINDD_ERROR;
+ }
+
+ status = domain->methods->query_user(domain, state->mem_ctx,
+ &sid, &user_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("error getting user info for sid %s\n",
+ sid_string_dbg(&sid)));
+ return WINBINDD_ERROR;
+ }
+
+ fstrcpy(state->response.data.user_info.acct_name, user_info.acct_name);
+ fstrcpy(state->response.data.user_info.full_name, user_info.full_name);
+ fstrcpy(state->response.data.user_info.homedir, user_info.homedir);
+ fstrcpy(state->response.data.user_info.shell, user_info.shell);
+ state->response.data.user_info.primary_gid = user_info.primary_gid;
+ if (!sid_peek_check_rid(&domain->sid, &user_info.group_sid,
+ &state->response.data.user_info.group_rid)) {
+ DEBUG(1, ("Could not extract group rid out of %s\n",
+ sid_string_dbg(&sid)));
+ return WINBINDD_ERROR;
+ }
+
+ return WINBINDD_OK;
+}
+
+struct getpwsid_state {
+ struct winbindd_cli_state *state;
+ struct winbindd_domain *domain;
+ char *username;
+ char *fullname;
+ char *homedir;
+ char *shell;
+ DOM_SID user_sid;
+ uid_t uid;
+ DOM_SID group_sid;
+ gid_t gid;
+};
+
+static void getpwsid_queryuser_recv(void *private_data, bool success,
+ const char *acct_name,
+ const char *full_name,
+ const char *homedir,
+ const char *shell,
+ gid_t gid,
+ uint32 group_rid);
+static void getpwsid_sid2uid_recv(void *private_data, bool success, uid_t uid);
+static void getpwsid_sid2gid_recv(void *private_data, bool success, gid_t gid);
+
+static void winbindd_getpwsid(struct winbindd_cli_state *state,
+ const DOM_SID *sid)
+{
+ struct getpwsid_state *s;
+
+ s = TALLOC_ZERO_P(state->mem_ctx, struct getpwsid_state);
+ if (s == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ goto error;
+ }
+
+ s->state = state;
+ s->domain = find_domain_from_sid_noinit(sid);
+ if (s->domain == NULL) {
+ DEBUG(3, ("Could not find domain for sid %s\n",
+ sid_string_dbg(sid)));
+ goto error;
+ }
+
+ sid_copy(&s->user_sid, sid);
+
+ query_user_async(s->state->mem_ctx, s->domain, sid,
+ getpwsid_queryuser_recv, s);
+ return;
+
+ error:
+ request_error(state);
+}
+
+static void getpwsid_queryuser_recv(void *private_data, bool success,
+ const char *acct_name,
+ const char *full_name,
+ const char *homedir,
+ const char *shell,
+ gid_t gid,
+ uint32 group_rid)
+{
+ fstring username;
+ struct getpwsid_state *s =
+ talloc_get_type_abort(private_data, struct getpwsid_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not query domain %s SID %s\n",
+ s->domain->name, sid_string_dbg(&s->user_sid)));
+ request_error(s->state);
+ return;
+ }
+
+ if ( acct_name && *acct_name ) {
+ fstrcpy( username, acct_name );
+ } else {
+ char *domain_name = NULL;
+ enum lsa_SidType type;
+ char *user_name = NULL;
+ struct winbindd_domain *domain = NULL;
+
+ domain = find_lookup_domain_from_sid(&s->user_sid);
+ if (domain == NULL) {
+ DEBUG(5, ("find_lookup_domain_from_sid(%s) failed\n",
+ sid_string_dbg(&s->user_sid)));
+ request_error(s->state);
+ return;
+ }
+ winbindd_lookup_name_by_sid(s->state->mem_ctx, domain,
+ &s->user_sid, &domain_name,
+ &user_name, &type );
+
+ /* If this still fails we ar4e done. Just error out */
+ if ( !user_name ) {
+ DEBUG(5,("Could not obtain a name for SID %s\n",
+ sid_string_dbg(&s->user_sid)));
+ request_error(s->state);
+ return;
+ }
+
+ fstrcpy( username, user_name );
+ }
+
+ strlower_m( username );
+ s->username = talloc_strdup(s->state->mem_ctx, username);
+
+ ws_name_replace( s->username, WB_REPLACE_CHAR );
+
+ s->fullname = talloc_strdup(s->state->mem_ctx, full_name);
+ s->homedir = talloc_strdup(s->state->mem_ctx, homedir);
+ s->shell = talloc_strdup(s->state->mem_ctx, shell);
+ s->gid = gid;
+ sid_copy(&s->group_sid, &s->domain->sid);
+ sid_append_rid(&s->group_sid, group_rid);
+
+ winbindd_sid2uid_async(s->state->mem_ctx, &s->user_sid,
+ getpwsid_sid2uid_recv, s);
+}
+
+static void getpwsid_sid2uid_recv(void *private_data, bool success, uid_t uid)
+{
+ struct getpwsid_state *s =
+ talloc_get_type_abort(private_data, struct getpwsid_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not query uid for user %s\\%s\n",
+ s->domain->name, s->username));
+ request_error(s->state);
+ return;
+ }
+
+ s->uid = uid;
+ winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
+ getpwsid_sid2gid_recv, s);
+}
+
+static void getpwsid_sid2gid_recv(void *private_data, bool success, gid_t gid)
+{
+ struct getpwsid_state *s =
+ talloc_get_type_abort(private_data, struct getpwsid_state);
+ struct winbindd_pw *pw;
+ fstring output_username;
+
+ /* allow the nss backend to override the primary group ID.
+ If the gid has already been set, then keep it.
+ This makes me feel dirty. If the nss backend already
+ gave us a gid, we don't really care whether the sid2gid()
+ call worked or not. --jerry */
+
+ if ( s->gid == (gid_t)-1 ) {
+
+ if (!success) {
+ DEBUG(5, ("Could not query gid for user %s\\%s\n",
+ s->domain->name, s->username));
+ goto failed;
+ }
+
+ /* take what the sid2gid() call gave us */
+ s->gid = gid;
+ }
+
+ pw = &s->state->response.data.pw;
+ pw->pw_uid = s->uid;
+ pw->pw_gid = s->gid;
+ fill_domain_username(output_username, s->domain->name,
+ s->username, True);
+ safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
+ safe_strcpy(pw->pw_gecos, s->fullname, sizeof(pw->pw_gecos) - 1);
+
+ if (!fillup_pw_field(lp_template_homedir(), s->username,
+ s->domain->name, pw->pw_uid, pw->pw_gid,
+ s->homedir, pw->pw_dir)) {
+ DEBUG(5, ("Could not compose homedir\n"));
+ goto failed;
+ }
+
+ if (!fillup_pw_field(lp_template_shell(), s->username,
+ s->domain->name, pw->pw_uid, pw->pw_gid,
+ s->shell, pw->pw_shell)) {
+ DEBUG(5, ("Could not compose shell\n"));
+ goto failed;
+ }
+
+ /* Password - set to "*" as we can't generate anything useful here.
+ Authentication can be done using the pam_winbind module. */
+
+ safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
+
+ request_ok(s->state);
+ return;
+
+ failed:
+ request_error(s->state);
+}
+
+/* Return a password structure from a username. */
+
+static void getpwnam_name2sid_recv(void *private_data, bool success,
+ const DOM_SID *sid, enum lsa_SidType type);
+
+void winbindd_getpwnam(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+ fstring domname, username;
+ char *domuser;
+ size_t dusize;
+
+ domuser = state->request.data.username;
+ dusize = sizeof(state->request.data.username);
+
+ /* Ensure null termination (it's an fstring) */
+ domuser[dusize-1] = '\0';
+
+ DEBUG(3, ("[%5lu]: getpwnam %s\n",
+ (unsigned long)state->pid,
+ domuser));
+
+ ws_name_return(domuser, WB_REPLACE_CHAR);
+
+ if (!parse_domain_user(domuser, domname, username)) {
+ DEBUG(5, ("Could not parse domain user: %s\n", domuser));
+ request_error(state);
+ return;
+ }
+
+ /* Get info for the domain */
+
+ domain = find_domain_from_name(domname);
+
+ if (domain == NULL) {
+ DEBUG(7, ("could not find domain entry for domain %s. "
+ "Using primary domain\n", domname));
+ if ( (domain = find_our_domain()) == NULL ) {
+ DEBUG(0,("Cannot find my primary domain structure!\n"));
+ request_error(state);
+ return;
+ }
+ }
+
+ if (strequal(domname, lp_workgroup()) &&
+ lp_winbind_trusted_domains_only() ) {
+ DEBUG(7,("winbindd_getpwnam: My domain -- "
+ "rejecting getpwnam() for %s\\%s.\n",
+ domname, username));
+ request_error(state);
+ return;
+ }
+
+ /* Get rid and name type from name. The following costs 1 packet */
+
+ winbindd_lookupname_async(state->mem_ctx, domname, username,
+ getpwnam_name2sid_recv, WINBINDD_GETPWNAM,
+ state);
+}
+
+static void getpwnam_name2sid_recv(void *private_data, bool success,
+ const DOM_SID *sid, enum lsa_SidType type)
+{
+ struct winbindd_cli_state *state =
+ (struct winbindd_cli_state *)private_data;
+ fstring domname, username;
+ char *domuser = state->request.data.username;
+
+ if (!success) {
+ DEBUG(5, ("Could not lookup name for user %s\n", domuser));
+ request_error(state);
+ return;
+ }
+
+ if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) {
+ DEBUG(5, ("%s is not a user\n", domuser));
+ request_error(state);
+ return;
+ }
+
+ if (parse_domain_user(domuser, domname, username)) {
+ check_domain_trusted(domname, sid);
+ }
+
+ winbindd_getpwsid(state, sid);
+}
+
+static void getpwuid_recv(void *private_data, bool success, const char *sid)
+{
+ struct winbindd_cli_state *state =
+ (struct winbindd_cli_state *)private_data;
+ DOM_SID user_sid;
+
+ if (!success) {
+ DEBUG(10,("uid2sid_recv: uid [%lu] to sid mapping failed\n.",
+ (unsigned long)(state->request.data.uid)));
+ request_error(state);
+ return;
+ }
+
+ DEBUG(10,("uid2sid_recv: uid %lu has sid %s\n",
+ (unsigned long)(state->request.data.uid), sid));
+
+ string_to_sid(&user_sid, sid);
+ winbindd_getpwsid(state, &user_sid);
+}
+
+/* Return a password structure given a uid number */
+void winbindd_getpwuid(struct winbindd_cli_state *state)
+{
+ uid_t uid = state->request.data.uid;
+
+ DEBUG(3, ("[%5lu]: getpwuid %lu\n",
+ (unsigned long)state->pid,
+ (unsigned long)uid));
+
+ /* always query idmap via the async interface */
+ /* if this turns to be too slow we will add here
+ * a direct query to the cache */
+ winbindd_uid2sid_async(state->mem_ctx, uid, getpwuid_recv, state);
+}
+
+/*
+ * set/get/endpwent functions
+ */
+
+/* Rewind file pointer for ntdom passwd database */
+
+static bool winbindd_setpwent_internal(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+
+ DEBUG(3, ("[%5lu]: setpwent\n", (unsigned long)state->pid));
+
+ /* Check user has enabled this */
+
+ if (!lp_winbind_enum_users()) {
+ return False;
+ }
+
+ /* Free old static data if it exists */
+
+ if (state->getpwent_state != NULL) {
+ free_getent_state(state->getpwent_state);
+ state->getpwent_state = NULL;
+ }
+
+ /* Create sam pipes for each domain we know about */
+
+ for(domain = domain_list(); domain != NULL; domain = domain->next) {
+ struct getent_state *domain_state;
+
+
+ /* don't add our domaina if we are a PDC or if we
+ are a member of a Samba domain */
+
+ if ((IS_DC || lp_winbind_trusted_domains_only())
+ && strequal(domain->name, lp_workgroup())) {
+ continue;
+ }
+
+ /* Create a state record for this domain */
+
+ domain_state = SMB_MALLOC_P(struct getent_state);
+ if (!domain_state) {
+ DEBUG(0, ("malloc failed\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(domain_state);
+
+ fstrcpy(domain_state->domain_name, domain->name);
+
+ /* Add to list of open domains */
+
+ DLIST_ADD(state->getpwent_state, domain_state);
+ }
+
+ state->getpwent_initialized = True;
+ return True;
+}
+
+void winbindd_setpwent(struct winbindd_cli_state *state)
+{
+ if (winbindd_setpwent_internal(state)) {
+ request_ok(state);
+ } else {
+ request_error(state);
+ }
+}
+
+/* Close file pointer to ntdom passwd database */
+
+void winbindd_endpwent(struct winbindd_cli_state *state)
+{
+ DEBUG(3, ("[%5lu]: endpwent\n", (unsigned long)state->pid));
+
+ free_getent_state(state->getpwent_state);
+ state->getpwent_initialized = False;
+ state->getpwent_state = NULL;
+ request_ok(state);
+}
+
+/* Get partial list of domain users for a domain. We fill in the sam_entries,
+ and num_sam_entries fields with domain user information. The dispinfo_ndx
+ field is incremented to the index of the next user to fetch. Return True if
+ some users were returned, False otherwise. */
+
+static bool get_sam_user_entries(struct getent_state *ent, TALLOC_CTX *mem_ctx)
+{
+ NTSTATUS status;
+ uint32 num_entries;
+ WINBIND_USERINFO *info;
+ struct getpwent_user *name_list = NULL;
+ struct winbindd_domain *domain;
+ struct winbindd_methods *methods;
+ unsigned int i;
+
+ if (ent->num_sam_entries)
+ return False;
+
+ if (!(domain = find_domain_from_name(ent->domain_name))) {
+ DEBUG(3, ("no such domain %s in get_sam_user_entries\n",
+ ent->domain_name));
+ return False;
+ }
+
+ methods = domain->methods;
+
+ /* Free any existing user info */
+
+ SAFE_FREE(ent->sam_entries);
+ ent->num_sam_entries = 0;
+
+ /* Call query_user_list to get a list of usernames and user rids */
+
+ num_entries = 0;
+
+ status = methods->query_user_list(domain, mem_ctx, &num_entries, &info);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("get_sam_user_entries: "
+ "query_user_list failed with %s\n",
+ nt_errstr(status)));
+ return False;
+ }
+
+ if (num_entries) {
+ name_list = SMB_REALLOC_ARRAY(name_list, struct getpwent_user,
+ ent->num_sam_entries + num_entries);
+ if (!name_list) {
+ DEBUG(0,("get_sam_user_entries realloc failed.\n"));
+ return False;
+ }
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ /* Store account name and gecos */
+ if (!info[i].acct_name) {
+ fstrcpy(name_list[ent->num_sam_entries + i].name, "");
+ } else {
+ fstrcpy(name_list[ent->num_sam_entries + i].name,
+ info[i].acct_name);
+ }
+ if (!info[i].full_name) {
+ fstrcpy(name_list[ent->num_sam_entries + i].gecos, "");
+ } else {
+ fstrcpy(name_list[ent->num_sam_entries + i].gecos,
+ info[i].full_name);
+ }
+ if (!info[i].homedir) {
+ fstrcpy(name_list[ent->num_sam_entries + i].homedir,"");
+ } else {
+ fstrcpy(name_list[ent->num_sam_entries + i].homedir,
+ info[i].homedir);
+ }
+ if (!info[i].shell) {
+ fstrcpy(name_list[ent->num_sam_entries + i].shell, "");
+ } else {
+ fstrcpy(name_list[ent->num_sam_entries + i].shell,
+ info[i].shell);
+ }
+
+
+ /* User and group ids */
+ sid_copy(&name_list[ent->num_sam_entries+i].user_sid,
+ &info[i].user_sid);
+ sid_copy(&name_list[ent->num_sam_entries+i].group_sid,
+ &info[i].group_sid);
+ }
+
+ ent->num_sam_entries += num_entries;
+
+ /* Fill in remaining fields */
+
+ ent->sam_entries = name_list;
+ ent->sam_entry_index = 0;
+ return ent->num_sam_entries > 0;
+}
+
+/* Fetch next passwd entry from ntdom database */
+
+#define MAX_GETPWENT_USERS 500
+
+void winbindd_getpwent(struct winbindd_cli_state *state)
+{
+ struct getent_state *ent;
+ struct winbindd_pw *user_list;
+ int num_users, user_list_ndx;
+
+ DEBUG(3, ("[%5lu]: getpwent\n", (unsigned long)state->pid));
+
+ /* Check user has enabled this */
+
+ if (!lp_winbind_enum_users()) {
+ request_error(state);
+ return;
+ }
+
+ /* Allocate space for returning a chunk of users */
+
+ num_users = MIN(MAX_GETPWENT_USERS, state->request.data.num_entries);
+
+ if (num_users == 0) {
+ request_error(state);
+ return;
+ }
+
+ user_list = SMB_MALLOC_ARRAY(struct winbindd_pw, num_users);
+ if (!user_list) {
+ request_error(state);
+ return;
+ }
+ /* will be freed by process_request() */
+ state->response.extra_data.data = user_list;
+
+ memset(user_list, 0, num_users * sizeof(struct winbindd_pw));
+
+ if (!state->getpwent_initialized)
+ winbindd_setpwent_internal(state);
+
+ if (!(ent = state->getpwent_state)) {
+ request_error(state);
+ return;
+ }
+
+ /* Start sending back users */
+
+ for (user_list_ndx = 0; user_list_ndx < num_users; ) {
+ struct getpwent_user *name_list = NULL;
+ uint32 result;
+
+ /* Do we need to fetch another chunk of users? */
+
+ if (ent->num_sam_entries == ent->sam_entry_index) {
+
+ while(ent &&
+ !get_sam_user_entries(ent, state->mem_ctx)) {
+ struct getent_state *next_ent;
+
+ /* Free state information for this domain */
+
+ SAFE_FREE(ent->sam_entries);
+
+ next_ent = ent->next;
+ DLIST_REMOVE(state->getpwent_state, ent);
+
+ SAFE_FREE(ent);
+ ent = next_ent;
+ }
+
+ /* No more domains */
+
+ if (!ent)
+ break;
+ }
+
+ name_list = (struct getpwent_user *)ent->sam_entries;
+
+ /* Lookup user info */
+
+ result = winbindd_fill_pwent(
+ ent->domain_name,
+ name_list[ent->sam_entry_index].name,
+ &name_list[ent->sam_entry_index].user_sid,
+ &name_list[ent->sam_entry_index].group_sid,
+ name_list[ent->sam_entry_index].gecos,
+ name_list[ent->sam_entry_index].homedir,
+ name_list[ent->sam_entry_index].shell,
+ &user_list[user_list_ndx]);
+
+ /* Add user to return list */
+
+ if (result) {
+
+ user_list_ndx++;
+ state->response.data.num_entries++;
+ state->response.length += sizeof(struct winbindd_pw);
+
+ } else
+ DEBUG(1, ("could not lookup domain user %s\n",
+ name_list[ent->sam_entry_index].name));
+
+ ent->sam_entry_index++;
+
+ }
+
+ /* Out of domains */
+
+ if (user_list_ndx > 0)
+ request_ok(state);
+ else
+ request_error(state);
+}
+
+/* List domain users without mapping to unix ids */
+void winbindd_list_users(struct winbindd_cli_state *state)
+{
+ winbindd_list_ent(state, LIST_USERS);
+}
diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
new file mode 100644
index 0000000000..132c96f1ee
--- /dev/null
+++ b/source3/winbindd/winbindd_util.c
@@ -0,0 +1,1583 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon for ntdom nss module
+
+ Copyright (C) Tim Potter 2000-2001
+ Copyright (C) 2001 by Martin Pool <mbp@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+extern struct winbindd_methods cache_methods;
+extern struct winbindd_methods builtin_passdb_methods;
+extern struct winbindd_methods sam_passdb_methods;
+
+
+/**
+ * @file winbindd_util.c
+ *
+ * Winbind daemon for NT domain authentication nss module.
+ **/
+
+
+/* The list of trusted domains. Note that the list can be deleted and
+ recreated using the init_domain_list() function so pointers to
+ individual winbindd_domain structures cannot be made. Keep a copy of
+ the domain name instead. */
+
+static struct winbindd_domain *_domain_list = NULL;
+
+/**
+ When was the last scan of trusted domains done?
+
+ 0 == not ever
+*/
+
+static time_t last_trustdom_scan;
+
+struct winbindd_domain *domain_list(void)
+{
+ /* Initialise list */
+
+ if ((!_domain_list) && (!init_domain_list())) {
+ smb_panic("Init_domain_list failed");
+ }
+
+ return _domain_list;
+}
+
+/* Free all entries in the trusted domain list */
+
+void free_domain_list(void)
+{
+ struct winbindd_domain *domain = _domain_list;
+
+ while(domain) {
+ struct winbindd_domain *next = domain->next;
+
+ DLIST_REMOVE(_domain_list, domain);
+ SAFE_FREE(domain);
+ domain = next;
+ }
+}
+
+static bool is_internal_domain(const DOM_SID *sid)
+{
+ if (sid == NULL)
+ return False;
+
+ if ( IS_DC )
+ return sid_check_is_builtin(sid);
+
+ return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
+}
+
+static bool is_in_internal_domain(const DOM_SID *sid)
+{
+ if (sid == NULL)
+ return False;
+
+ if ( IS_DC )
+ return sid_check_is_in_builtin(sid);
+
+ return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
+}
+
+
+/* Add a trusted domain to our list of domains */
+static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
+ struct winbindd_methods *methods,
+ const DOM_SID *sid)
+{
+ struct winbindd_domain *domain;
+ const char *alternative_name = NULL;
+ char *idmap_config_option;
+ const char *param;
+
+ /* ignore alt_name if we are not in an AD domain */
+
+ if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
+ alternative_name = alt_name;
+ }
+
+ /* We can't call domain_list() as this function is called from
+ init_domain_list() and we'll get stuck in a loop. */
+ for (domain = _domain_list; domain; domain = domain->next) {
+ if (strequal(domain_name, domain->name) ||
+ strequal(domain_name, domain->alt_name))
+ {
+ break;
+ }
+
+ if (alternative_name && *alternative_name)
+ {
+ if (strequal(alternative_name, domain->name) ||
+ strequal(alternative_name, domain->alt_name))
+ {
+ break;
+ }
+ }
+
+ if (sid)
+ {
+ if (is_null_sid(sid)) {
+ continue;
+ }
+
+ if (sid_equal(sid, &domain->sid)) {
+ break;
+ }
+ }
+ }
+
+ /* See if we found a match. Check if we need to update the
+ SID. */
+
+ if ( domain && sid) {
+ if ( sid_equal( &domain->sid, &global_sid_NULL ) )
+ sid_copy( &domain->sid, sid );
+
+ return domain;
+ }
+
+ /* Create new domain entry */
+
+ if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
+ return NULL;
+
+ /* Fill in fields */
+
+ ZERO_STRUCTP(domain);
+
+ fstrcpy(domain->name, domain_name);
+ if (alternative_name) {
+ fstrcpy(domain->alt_name, alternative_name);
+ }
+
+ domain->methods = methods;
+ domain->backend = NULL;
+ domain->internal = is_internal_domain(sid);
+ domain->sequence_number = DOM_SEQUENCE_NONE;
+ domain->last_seq_check = 0;
+ domain->initialized = False;
+ domain->online = is_internal_domain(sid);
+ domain->check_online_timeout = 0;
+ domain->dc_probe_pid = (pid_t)-1;
+ if (sid) {
+ sid_copy(&domain->sid, sid);
+ }
+
+ /* Link to domain list */
+ DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);
+
+ wcache_tdc_add_domain( domain );
+
+ idmap_config_option = talloc_asprintf(talloc_tos(), "idmap config %s",
+ domain->name);
+ if (idmap_config_option == NULL) {
+ DEBUG(0, ("talloc failed, not looking for idmap config\n"));
+ goto done;
+ }
+
+ param = lp_parm_const_string(-1, idmap_config_option, "range", NULL);
+
+ DEBUG(10, ("%s : range = %s\n", idmap_config_option,
+ param ? param : "not defined"));
+
+ if (param != NULL) {
+ unsigned low_id, high_id;
+ if (sscanf(param, "%u - %u", &low_id, &high_id) != 2) {
+ DEBUG(1, ("invalid range syntax in %s: %s\n",
+ idmap_config_option, param));
+ goto done;
+ }
+ if (low_id > high_id) {
+ DEBUG(1, ("invalid range in %s: %s\n",
+ idmap_config_option, param));
+ goto done;
+ }
+ domain->have_idmap_config = true;
+ domain->id_range_low = low_id;
+ domain->id_range_high = high_id;
+ }
+
+done:
+
+ DEBUG(2,("Added domain %s %s %s\n",
+ domain->name, domain->alt_name,
+ &domain->sid?sid_string_dbg(&domain->sid):""));
+
+ return domain;
+}
+
+/********************************************************************
+ rescan our domains looking for new trusted domains
+********************************************************************/
+
+struct trustdom_state {
+ TALLOC_CTX *mem_ctx;
+ bool primary;
+ bool forest_root;
+ struct winbindd_response *response;
+};
+
+static void trustdom_recv(void *private_data, bool success);
+static void rescan_forest_root_trusts( void );
+static void rescan_forest_trusts( void );
+
+static void add_trusted_domains( struct winbindd_domain *domain )
+{
+ TALLOC_CTX *mem_ctx;
+ struct winbindd_request *request;
+ struct winbindd_response *response;
+ uint32 fr_flags = (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
+
+ struct trustdom_state *state;
+
+ mem_ctx = talloc_init("add_trusted_domains");
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_init failed\n"));
+ return;
+ }
+
+ request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
+ response = TALLOC_P(mem_ctx, struct winbindd_response);
+ state = TALLOC_P(mem_ctx, struct trustdom_state);
+
+ if ((request == NULL) || (response == NULL) || (state == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ talloc_destroy(mem_ctx);
+ return;
+ }
+
+ state->mem_ctx = mem_ctx;
+ state->response = response;
+
+ /* Flags used to know how to continue the forest trust search */
+
+ state->primary = domain->primary;
+ state->forest_root = ((domain->domain_flags & fr_flags) == fr_flags );
+
+ request->length = sizeof(*request);
+ request->cmd = WINBINDD_LIST_TRUSTDOM;
+
+ async_domain_request(mem_ctx, domain, request, response,
+ trustdom_recv, state);
+}
+
+static void trustdom_recv(void *private_data, bool success)
+{
+ struct trustdom_state *state =
+ talloc_get_type_abort(private_data, struct trustdom_state);
+ struct winbindd_response *response = state->response;
+ char *p;
+
+ if ((!success) || (response->result != WINBINDD_OK)) {
+ DEBUG(1, ("Could not receive trustdoms\n"));
+ talloc_destroy(state->mem_ctx);
+ return;
+ }
+
+ p = (char *)response->extra_data.data;
+
+ while ((p != NULL) && (*p != '\0')) {
+ char *q, *sidstr, *alt_name;
+ DOM_SID sid;
+ struct winbindd_domain *domain;
+ char *alternate_name = NULL;
+
+ alt_name = strchr(p, '\\');
+ if (alt_name == NULL) {
+ DEBUG(0, ("Got invalid trustdom response\n"));
+ break;
+ }
+
+ *alt_name = '\0';
+ alt_name += 1;
+
+ sidstr = strchr(alt_name, '\\');
+ if (sidstr == NULL) {
+ DEBUG(0, ("Got invalid trustdom response\n"));
+ break;
+ }
+
+ *sidstr = '\0';
+ sidstr += 1;
+
+ q = strchr(sidstr, '\n');
+ if (q != NULL)
+ *q = '\0';
+
+ if (!string_to_sid(&sid, sidstr)) {
+ /* Allow NULL sid for sibling domains */
+ if ( strcmp(sidstr,"S-0-0") == 0) {
+ sid_copy( &sid, &global_sid_NULL);
+ } else {
+ DEBUG(0, ("Got invalid trustdom response\n"));
+ break;
+ }
+ }
+
+ /* use the real alt_name if we have one, else pass in NULL */
+
+ if ( !strequal( alt_name, "(null)" ) )
+ alternate_name = alt_name;
+
+ /* If we have an existing domain structure, calling
+ add_trusted_domain() will update the SID if
+ necessary. This is important because we need the
+ SID for sibling domains */
+
+ if ( find_domain_from_name_noinit(p) != NULL ) {
+ domain = add_trusted_domain(p, alternate_name,
+ &cache_methods,
+ &sid);
+ } else {
+ domain = add_trusted_domain(p, alternate_name,
+ &cache_methods,
+ &sid);
+ if (domain) {
+ setup_domain_child(domain,
+ &domain->child);
+ }
+ }
+ p=q;
+ if (p != NULL)
+ p += 1;
+ }
+
+ SAFE_FREE(response->extra_data.data);
+
+ /*
+ Cases to consider when scanning trusts:
+ (a) we are calling from a child domain (primary && !forest_root)
+ (b) we are calling from the root of the forest (primary && forest_root)
+ (c) we are calling from a trusted forest domain (!primary
+ && !forest_root)
+ */
+
+ if ( state->primary ) {
+ /* If this is our primary domain and we are not in the
+ forest root, we have to scan the root trusts first */
+
+ if ( !state->forest_root )
+ rescan_forest_root_trusts();
+ else
+ rescan_forest_trusts();
+
+ } else if ( state->forest_root ) {
+ /* Once we have done root forest trust search, we can
+ go on to search the trusted forests */
+
+ rescan_forest_trusts();
+ }
+
+ talloc_destroy(state->mem_ctx);
+
+ return;
+}
+
+/********************************************************************
+ Scan the trusts of our forest root
+********************************************************************/
+
+static void rescan_forest_root_trusts( void )
+{
+ struct winbindd_tdc_domain *dom_list = NULL;
+ size_t num_trusts = 0;
+ int i;
+
+ /* The only transitive trusts supported by Windows 2003 AD are
+ (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
+ first two are handled in forest and listed by
+ DsEnumerateDomainTrusts(). Forest trusts are not so we
+ have to do that ourselves. */
+
+ if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
+ return;
+
+ for ( i=0; i<num_trusts; i++ ) {
+ struct winbindd_domain *d = NULL;
+
+ /* Find the forest root. Don't necessarily trust
+ the domain_list() as our primary domain may not
+ have been initialized. */
+
+ if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
+ continue;
+ }
+
+ /* Here's the forest root */
+
+ d = find_domain_from_name_noinit( dom_list[i].domain_name );
+
+ if ( !d ) {
+ d = add_trusted_domain( dom_list[i].domain_name,
+ dom_list[i].dns_name,
+ &cache_methods,
+ &dom_list[i].sid );
+ }
+
+ DEBUG(10,("rescan_forest_root_trusts: Following trust path "
+ "for domain tree root %s (%s)\n",
+ d->name, d->alt_name ));
+
+ d->domain_flags = dom_list[i].trust_flags;
+ d->domain_type = dom_list[i].trust_type;
+ d->domain_trust_attribs = dom_list[i].trust_attribs;
+
+ add_trusted_domains( d );
+
+ break;
+ }
+
+ TALLOC_FREE( dom_list );
+
+ return;
+}
+
+/********************************************************************
+ scan the transitive forest trusts (not our own)
+********************************************************************/
+
+
+static void rescan_forest_trusts( void )
+{
+ struct winbindd_domain *d = NULL;
+ struct winbindd_tdc_domain *dom_list = NULL;
+ size_t num_trusts = 0;
+ int i;
+
+ /* The only transitive trusts supported by Windows 2003 AD are
+ (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
+ first two are handled in forest and listed by
+ DsEnumerateDomainTrusts(). Forest trusts are not so we
+ have to do that ourselves. */
+
+ if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
+ return;
+
+ for ( i=0; i<num_trusts; i++ ) {
+ uint32 flags = dom_list[i].trust_flags;
+ uint32 type = dom_list[i].trust_type;
+ uint32 attribs = dom_list[i].trust_attribs;
+
+ d = find_domain_from_name_noinit( dom_list[i].domain_name );
+
+ /* ignore our primary and internal domains */
+
+ if ( d && (d->internal || d->primary ) )
+ continue;
+
+ if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
+ (type == NETR_TRUST_TYPE_UPLEVEL) &&
+ (attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
+ {
+ /* add the trusted domain if we don't know
+ about it */
+
+ if ( !d ) {
+ d = add_trusted_domain( dom_list[i].domain_name,
+ dom_list[i].dns_name,
+ &cache_methods,
+ &dom_list[i].sid );
+ }
+
+ DEBUG(10,("Following trust path for domain %s (%s)\n",
+ d->name, d->alt_name ));
+ add_trusted_domains( d );
+ }
+ }
+
+ TALLOC_FREE( dom_list );
+
+ return;
+}
+
+/*********************************************************************
+ The process of updating the trusted domain list is a three step
+ async process:
+ (a) ask our domain
+ (b) ask the root domain in our forest
+ (c) ask the a DC in any Win2003 trusted forests
+*********************************************************************/
+
+void rescan_trusted_domains( void )
+{
+ time_t now = time(NULL);
+
+ /* see if the time has come... */
+
+ if ((now >= last_trustdom_scan) &&
+ ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
+ return;
+
+ /* I use to clear the cache here and start over but that
+ caused problems in child processes that needed the
+ trust dom list early on. Removing it means we
+ could have some trusted domains listed that have been
+ removed from our primary domain's DC until a full
+ restart. This should be ok since I think this is what
+ Windows does as well. */
+
+ /* this will only add new domains we didn't already know about
+ in the domain_list()*/
+
+ add_trusted_domains( find_our_domain() );
+
+ last_trustdom_scan = now;
+
+ return;
+}
+
+struct init_child_state {
+ TALLOC_CTX *mem_ctx;
+ struct winbindd_domain *domain;
+ struct winbindd_request *request;
+ struct winbindd_response *response;
+ void (*continuation)(void *private_data, bool success);
+ void *private_data;
+};
+
+static void init_child_recv(void *private_data, bool success);
+static void init_child_getdc_recv(void *private_data, bool success);
+
+enum winbindd_result init_child_connection(struct winbindd_domain *domain,
+ void (*continuation)(void *private_data,
+ bool success),
+ void *private_data)
+{
+ TALLOC_CTX *mem_ctx;
+ struct winbindd_request *request;
+ struct winbindd_response *response;
+ struct init_child_state *state;
+ struct winbindd_domain *request_domain;
+
+ mem_ctx = talloc_init("init_child_connection");
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_init failed\n"));
+ return WINBINDD_ERROR;
+ }
+
+ request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
+ response = TALLOC_P(mem_ctx, struct winbindd_response);
+ state = TALLOC_P(mem_ctx, struct init_child_state);
+
+ if ((request == NULL) || (response == NULL) || (state == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(mem_ctx);
+ continuation(private_data, False);
+ return WINBINDD_ERROR;
+ }
+
+ request->length = sizeof(*request);
+
+ state->mem_ctx = mem_ctx;
+ state->domain = domain;
+ state->request = request;
+ state->response = response;
+ state->continuation = continuation;
+ state->private_data = private_data;
+
+ if (IS_DC || domain->primary || domain->internal ) {
+ /* The primary domain has to find the DC name itself */
+ request->cmd = WINBINDD_INIT_CONNECTION;
+ fstrcpy(request->domain_name, domain->name);
+ request->data.init_conn.is_primary = domain->primary ? true : false;
+ fstrcpy(request->data.init_conn.dcname, "");
+ async_request(mem_ctx, &domain->child, request, response,
+ init_child_recv, state);
+ return WINBINDD_PENDING;
+ }
+
+ /* This is *not* the primary domain, let's ask our DC about a DC
+ * name */
+
+ request->cmd = WINBINDD_GETDCNAME;
+ fstrcpy(request->domain_name, domain->name);
+
+ request_domain = find_our_domain();
+ async_domain_request(mem_ctx, request_domain, request, response,
+ init_child_getdc_recv, state);
+ return WINBINDD_PENDING;
+}
+
+static void init_child_getdc_recv(void *private_data, bool success)
+{
+ struct init_child_state *state =
+ talloc_get_type_abort(private_data, struct init_child_state);
+ const char *dcname = "";
+
+ DEBUG(10, ("Received getdcname response\n"));
+
+ if (success && (state->response->result == WINBINDD_OK)) {
+ dcname = state->response->data.dc_name;
+ }
+
+ state->request->cmd = WINBINDD_INIT_CONNECTION;
+ fstrcpy(state->request->domain_name, state->domain->name);
+ state->request->data.init_conn.is_primary = False;
+ fstrcpy(state->request->data.init_conn.dcname, dcname);
+
+ async_request(state->mem_ctx, &state->domain->child,
+ state->request, state->response,
+ init_child_recv, state);
+}
+
+static void init_child_recv(void *private_data, bool success)
+{
+ struct init_child_state *state =
+ talloc_get_type_abort(private_data, struct init_child_state);
+
+ DEBUG(5, ("Received child initialization response for domain %s\n",
+ state->domain->name));
+
+ if ((!success) || (state->response->result != WINBINDD_OK)) {
+ DEBUG(3, ("Could not init child\n"));
+ state->continuation(state->private_data, False);
+ talloc_destroy(state->mem_ctx);
+ return;
+ }
+
+ fstrcpy(state->domain->name,
+ state->response->data.domain_info.name);
+ fstrcpy(state->domain->alt_name,
+ state->response->data.domain_info.alt_name);
+ string_to_sid(&state->domain->sid,
+ state->response->data.domain_info.sid);
+ state->domain->native_mode =
+ state->response->data.domain_info.native_mode;
+ state->domain->active_directory =
+ state->response->data.domain_info.active_directory;
+
+ init_dc_connection(state->domain);
+
+ if (state->continuation != NULL)
+ state->continuation(state->private_data, True);
+ talloc_destroy(state->mem_ctx);
+}
+
+enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
+{
+ /* Ensure null termination */
+ state->request.domain_name
+ [sizeof(state->request.domain_name)-1]='\0';
+ state->request.data.init_conn.dcname
+ [sizeof(state->request.data.init_conn.dcname)-1]='\0';
+
+ if (strlen(state->request.data.init_conn.dcname) > 0) {
+ fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
+ }
+
+ init_dc_connection(domain);
+
+ if (!domain->initialized) {
+ /* If we return error here we can't do any cached authentication,
+ but we may be in disconnected mode and can't initialize correctly.
+ Do what the previous code did and just return without initialization,
+ once we go online we'll re-initialize.
+ */
+ DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
+ "online = %d\n", domain->name, (int)domain->online ));
+ }
+
+ fstrcpy(state->response.data.domain_info.name, domain->name);
+ fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
+ sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
+
+ state->response.data.domain_info.native_mode
+ = domain->native_mode;
+ state->response.data.domain_info.active_directory
+ = domain->active_directory;
+ state->response.data.domain_info.primary
+ = domain->primary;
+
+ return WINBINDD_OK;
+}
+
+/* Look up global info for the winbind daemon */
+bool init_domain_list(void)
+{
+ struct winbindd_domain *domain;
+ int role = lp_server_role();
+
+ /* Free existing list */
+ free_domain_list();
+
+ /* BUILTIN domain */
+
+ domain = add_trusted_domain("BUILTIN", NULL, &builtin_passdb_methods,
+ &global_sid_Builtin);
+ if (domain) {
+ setup_domain_child(domain,
+ &domain->child);
+ }
+
+ /* Local SAM */
+
+ domain = add_trusted_domain(get_global_sam_name(), NULL,
+ &sam_passdb_methods, get_global_sam_sid());
+ if (domain) {
+ if ( role != ROLE_DOMAIN_MEMBER ) {
+ domain->primary = True;
+ }
+ setup_domain_child(domain,
+ &domain->child);
+ }
+
+ /* Add ourselves as the first entry. */
+
+ if ( role == ROLE_DOMAIN_MEMBER ) {
+ DOM_SID our_sid;
+
+ if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
+ DEBUG(0, ("Could not fetch our SID - did we join?\n"));
+ return False;
+ }
+
+ domain = add_trusted_domain( lp_workgroup(), lp_realm(),
+ &cache_methods, &our_sid);
+ if (domain) {
+ domain->primary = True;
+ setup_domain_child(domain,
+ &domain->child);
+
+ /* Even in the parent winbindd we'll need to
+ talk to the DC, so try and see if we can
+ contact it. Theoretically this isn't neccessary
+ as the init_dc_connection() in init_child_recv()
+ will do this, but we can start detecting the DC
+ early here. */
+ set_domain_online_request(domain);
+ }
+ }
+
+ return True;
+}
+
+void check_domain_trusted( const char *name, const DOM_SID *user_sid )
+{
+ struct winbindd_domain *domain;
+ DOM_SID dom_sid;
+ uint32 rid;
+
+ domain = find_domain_from_name_noinit( name );
+ if ( domain )
+ return;
+
+ sid_copy( &dom_sid, user_sid );
+ if ( !sid_split_rid( &dom_sid, &rid ) )
+ return;
+
+ /* add the newly discovered trusted domain */
+
+ domain = add_trusted_domain( name, NULL, &cache_methods,
+ &dom_sid);
+
+ if ( !domain )
+ return;
+
+ /* assume this is a trust from a one-way transitive
+ forest trust */
+
+ domain->active_directory = True;
+ domain->domain_flags = NETR_TRUST_FLAG_OUTBOUND;
+ domain->domain_type = NETR_TRUST_TYPE_UPLEVEL;
+ domain->internal = False;
+ domain->online = True;
+
+ setup_domain_child(domain,
+ &domain->child);
+
+ wcache_tdc_add_domain( domain );
+
+ return;
+}
+
+/**
+ * Given a domain name, return the struct winbindd domain info for it
+ *
+ * @note Do *not* pass lp_workgroup() to this function. domain_list
+ * may modify it's value, and free that pointer. Instead, our local
+ * domain may be found by calling find_our_domain().
+ * directly.
+ *
+ *
+ * @return The domain structure for the named domain, if it is working.
+ */
+
+struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
+{
+ struct winbindd_domain *domain;
+
+ /* Search through list */
+
+ for (domain = domain_list(); domain != NULL; domain = domain->next) {
+ if (strequal(domain_name, domain->name) ||
+ (domain->alt_name[0] &&
+ strequal(domain_name, domain->alt_name))) {
+ return domain;
+ }
+ }
+
+ /* Not found */
+
+ return NULL;
+}
+
+struct winbindd_domain *find_domain_from_name(const char *domain_name)
+{
+ struct winbindd_domain *domain;
+
+ domain = find_domain_from_name_noinit(domain_name);
+
+ if (domain == NULL)
+ return NULL;
+
+ if (!domain->initialized)
+ init_dc_connection(domain);
+
+ return domain;
+}
+
+/* Given a domain sid, return the struct winbindd domain info for it */
+
+struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
+{
+ struct winbindd_domain *domain;
+
+ /* Search through list */
+
+ for (domain = domain_list(); domain != NULL; domain = domain->next) {
+ if (sid_compare_domain(sid, &domain->sid) == 0)
+ return domain;
+ }
+
+ /* Not found */
+
+ return NULL;
+}
+
+/* Given a domain sid, return the struct winbindd domain info for it */
+
+struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
+{
+ struct winbindd_domain *domain;
+
+ domain = find_domain_from_sid_noinit(sid);
+
+ if (domain == NULL)
+ return NULL;
+
+ if (!domain->initialized)
+ init_dc_connection(domain);
+
+ return domain;
+}
+
+struct winbindd_domain *find_our_domain(void)
+{
+ struct winbindd_domain *domain;
+
+ /* Search through list */
+
+ for (domain = domain_list(); domain != NULL; domain = domain->next) {
+ if (domain->primary)
+ return domain;
+ }
+
+ smb_panic("Could not find our domain");
+ return NULL;
+}
+
+struct winbindd_domain *find_root_domain(void)
+{
+ struct winbindd_domain *ours = find_our_domain();
+
+ if ( !ours )
+ return NULL;
+
+ if ( strlen(ours->forest_name) == 0 )
+ return NULL;
+
+ return find_domain_from_name( ours->forest_name );
+}
+
+struct winbindd_domain *find_builtin_domain(void)
+{
+ DOM_SID sid;
+ struct winbindd_domain *domain;
+
+ string_to_sid(&sid, "S-1-5-32");
+ domain = find_domain_from_sid(&sid);
+
+ if (domain == NULL) {
+ smb_panic("Could not find BUILTIN domain");
+ }
+
+ return domain;
+}
+
+/* Find the appropriate domain to lookup a name or SID */
+
+struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
+{
+ /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
+
+ if ( sid_check_is_in_unix_groups(sid) ||
+ sid_check_is_unix_groups(sid) ||
+ sid_check_is_in_unix_users(sid) ||
+ sid_check_is_unix_users(sid) )
+ {
+ return find_domain_from_sid(get_global_sam_sid());
+ }
+
+ /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
+ * one to contact the external DC's. On member servers the internal
+ * domains are different: These are part of the local SAM. */
+
+ DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
+
+ if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
+ DEBUG(10, ("calling find_domain_from_sid\n"));
+ return find_domain_from_sid(sid);
+ }
+
+ /* On a member server a query for SID or name can always go to our
+ * primary DC. */
+
+ DEBUG(10, ("calling find_our_domain\n"));
+ return find_our_domain();
+}
+
+struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
+{
+ if ( strequal(domain_name, unix_users_domain_name() ) ||
+ strequal(domain_name, unix_groups_domain_name() ) )
+ {
+ return find_domain_from_name_noinit( get_global_sam_name() );
+ }
+
+ if (IS_DC || strequal(domain_name, "BUILTIN") ||
+ strequal(domain_name, get_global_sam_name()))
+ return find_domain_from_name_noinit(domain_name);
+
+ /* The "Unix User" and "Unix Group" domain our handled by passdb */
+
+ return find_our_domain();
+}
+
+/* Lookup a sid in a domain from a name */
+
+bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
+ enum winbindd_cmd orig_cmd,
+ struct winbindd_domain *domain,
+ const char *domain_name,
+ const char *name, DOM_SID *sid,
+ enum lsa_SidType *type)
+{
+ NTSTATUS result;
+
+ /* Lookup name */
+ result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
+ domain_name, name, sid, type);
+
+ /* Return sid and type if lookup successful */
+ if (!NT_STATUS_IS_OK(result)) {
+ *type = SID_NAME_UNKNOWN;
+ }
+
+ return NT_STATUS_IS_OK(result);
+}
+
+/**
+ * @brief Lookup a name in a domain from a sid.
+ *
+ * @param sid Security ID you want to look up.
+ * @param name On success, set to the name corresponding to @p sid.
+ * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
+ * @param type On success, contains the type of name: alias, group or
+ * user.
+ * @retval True if the name exists, in which case @p name and @p type
+ * are set, otherwise False.
+ **/
+bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
+ struct winbindd_domain *domain,
+ DOM_SID *sid,
+ char **dom_name,
+ char **name,
+ enum lsa_SidType *type)
+{
+ NTSTATUS result;
+
+ *dom_name = NULL;
+ *name = NULL;
+
+ /* Lookup name */
+
+ result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
+
+ /* Return name and type if successful */
+
+ if (NT_STATUS_IS_OK(result)) {
+ return True;
+ }
+
+ *type = SID_NAME_UNKNOWN;
+
+ return False;
+}
+
+/* Free state information held for {set,get,end}{pw,gr}ent() functions */
+
+void free_getent_state(struct getent_state *state)
+{
+ struct getent_state *temp;
+
+ /* Iterate over state list */
+
+ temp = state;
+
+ while(temp != NULL) {
+ struct getent_state *next;
+
+ /* Free sam entries then list entry */
+
+ SAFE_FREE(state->sam_entries);
+ DLIST_REMOVE(state, state);
+ next = temp->next;
+
+ SAFE_FREE(temp);
+ temp = next;
+ }
+}
+
+/* Is this a domain which we may assume no DOMAIN\ prefix? */
+
+static bool assume_domain(const char *domain)
+{
+ /* never assume the domain on a standalone server */
+
+ if ( lp_server_role() == ROLE_STANDALONE )
+ return False;
+
+ /* domain member servers may possibly assume for the domain name */
+
+ if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
+ if ( !strequal(lp_workgroup(), domain) )
+ return False;
+
+ if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
+ return True;
+ }
+
+ /* only left with a domain controller */
+
+ if ( strequal(get_global_sam_name(), domain) ) {
+ return True;
+ }
+
+ return False;
+}
+
+/* Parse a string of the form DOMAIN\user into a domain and a user */
+
+bool parse_domain_user(const char *domuser, fstring domain, fstring user)
+{
+ char *p = strchr(domuser,*lp_winbind_separator());
+
+ if ( !p ) {
+ fstrcpy(user, domuser);
+
+ if ( assume_domain(lp_workgroup())) {
+ fstrcpy(domain, lp_workgroup());
+ } else if ((p = strchr(domuser, '@')) != NULL) {
+ fstrcpy(domain, "");
+ } else {
+ return False;
+ }
+ } else {
+ fstrcpy(user, p+1);
+ fstrcpy(domain, domuser);
+ domain[PTR_DIFF(p, domuser)] = 0;
+ }
+
+ strupper_m(domain);
+
+ return True;
+}
+
+bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
+ char **domain, char **user)
+{
+ fstring fstr_domain, fstr_user;
+ if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
+ return False;
+ }
+ *domain = talloc_strdup(mem_ctx, fstr_domain);
+ *user = talloc_strdup(mem_ctx, fstr_user);
+ return ((*domain != NULL) && (*user != NULL));
+}
+
+/* add a domain user name to a buffer */
+void parse_add_domuser(void *buf, char *domuser, int *len)
+{
+ fstring domain;
+ char *p, *user;
+
+ user = domuser;
+ p = strchr(domuser, *lp_winbind_separator());
+
+ if (p) {
+
+ fstrcpy(domain, domuser);
+ domain[PTR_DIFF(p, domuser)] = 0;
+ p++;
+
+ if (assume_domain(domain)) {
+
+ user = p;
+ *len -= (PTR_DIFF(p, domuser));
+ }
+ }
+
+ safe_strcpy(buf, user, *len);
+}
+
+/* Ensure an incoming username from NSS is fully qualified. Replace the
+ incoming fstring with DOMAIN <separator> user. Returns the same
+ values as parse_domain_user() but also replaces the incoming username.
+ Used to ensure all names are fully qualified within winbindd.
+ Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
+ The protocol definitions of auth_crap, chng_pswd_auth_crap
+ really should be changed to use this instead of doing things
+ by hand. JRA. */
+
+bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
+{
+ if (!parse_domain_user(username_inout, domain, user)) {
+ return False;
+ }
+ slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
+ domain, *lp_winbind_separator(),
+ user);
+ return True;
+}
+
+/*
+ Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
+ 'winbind separator' options.
+ This means:
+ - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
+ lp_workgroup()
+
+ If we are a PDC or BDC, and this is for our domain, do likewise.
+
+ Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
+ username is then unqualified in unix
+
+ We always canonicalize as UPPERCASE DOMAIN, lowercase username.
+*/
+void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
+{
+ fstring tmp_user;
+
+ fstrcpy(tmp_user, user);
+ strlower_m(tmp_user);
+
+ if (can_assume && assume_domain(domain)) {
+ strlcpy(name, tmp_user, sizeof(fstring));
+ } else {
+ slprintf(name, sizeof(fstring) - 1, "%s%c%s",
+ domain, *lp_winbind_separator(),
+ tmp_user);
+ }
+}
+
+/*
+ * Winbindd socket accessor functions
+ */
+
+const char *get_winbind_pipe_dir(void)
+{
+ return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR);
+}
+
+char *get_winbind_priv_pipe_dir(void)
+{
+ return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
+}
+
+/* Open the winbindd socket */
+
+static int _winbindd_socket = -1;
+static int _winbindd_priv_socket = -1;
+
+int open_winbindd_socket(void)
+{
+ if (_winbindd_socket == -1) {
+ _winbindd_socket = create_pipe_sock(
+ get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755);
+ DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
+ _winbindd_socket));
+ }
+
+ return _winbindd_socket;
+}
+
+int open_winbindd_priv_socket(void)
+{
+ if (_winbindd_priv_socket == -1) {
+ _winbindd_priv_socket = create_pipe_sock(
+ get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
+ DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
+ _winbindd_priv_socket));
+ }
+
+ return _winbindd_priv_socket;
+}
+
+/* Close the winbindd socket */
+
+void close_winbindd_socket(void)
+{
+ if (_winbindd_socket != -1) {
+ DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
+ _winbindd_socket));
+ close(_winbindd_socket);
+ _winbindd_socket = -1;
+ }
+ if (_winbindd_priv_socket != -1) {
+ DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
+ _winbindd_priv_socket));
+ close(_winbindd_priv_socket);
+ _winbindd_priv_socket = -1;
+ }
+}
+
+/*
+ * Client list accessor functions
+ */
+
+static struct winbindd_cli_state *_client_list;
+static int _num_clients;
+
+/* Return list of all connected clients */
+
+struct winbindd_cli_state *winbindd_client_list(void)
+{
+ return _client_list;
+}
+
+/* Add a connection to the list */
+
+void winbindd_add_client(struct winbindd_cli_state *cli)
+{
+ DLIST_ADD(_client_list, cli);
+ _num_clients++;
+}
+
+/* Remove a client from the list */
+
+void winbindd_remove_client(struct winbindd_cli_state *cli)
+{
+ DLIST_REMOVE(_client_list, cli);
+ _num_clients--;
+}
+
+/* Close all open clients */
+
+void winbindd_kill_all_clients(void)
+{
+ struct winbindd_cli_state *cl = winbindd_client_list();
+
+ DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
+
+ while (cl) {
+ struct winbindd_cli_state *next;
+
+ next = cl->next;
+ winbindd_remove_client(cl);
+ cl = next;
+ }
+}
+
+/* Return number of open clients */
+
+int winbindd_num_clients(void)
+{
+ return _num_clients;
+}
+
+NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ uint32 *p_num_groups, DOM_SID **user_sids)
+{
+ struct netr_SamInfo3 *info3 = NULL;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+ size_t num_groups = 0;
+
+ DEBUG(3,(": lookup_usergroups_cached\n"));
+
+ *user_sids = NULL;
+ *p_num_groups = 0;
+
+ info3 = netsamlogon_cache_get(mem_ctx, user_sid);
+
+ if (info3 == NULL) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (info3->base.groups.count == 0) {
+ TALLOC_FREE(info3);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* Skip Domain local groups outside our domain.
+ We'll get these from the getsidaliases() RPC call. */
+ status = sid_array_from_info3(mem_ctx, info3,
+ user_sids,
+ &num_groups,
+ false, true);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(info3);
+ return status;
+ }
+
+ TALLOC_FREE(info3);
+ *p_num_groups = num_groups;
+ status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
+
+ DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
+
+ return status;
+}
+
+/*********************************************************************
+ We use this to remove spaces from user and group names
+********************************************************************/
+
+void ws_name_replace( char *name, char replace )
+{
+ char replace_char[2] = { 0x0, 0x0 };
+
+ if ( !lp_winbind_normalize_names() || (replace == '\0') )
+ return;
+
+ replace_char[0] = replace;
+ all_string_sub( name, " ", replace_char, 0 );
+
+ return;
+}
+
+/*********************************************************************
+ We use this to do the inverse of ws_name_replace()
+********************************************************************/
+
+void ws_name_return( char *name, char replace )
+{
+ char replace_char[2] = { 0x0, 0x0 };
+
+ if ( !lp_winbind_normalize_names() || (replace == '\0') )
+ return;
+
+ replace_char[0] = replace;
+ all_string_sub( name, replace_char, " ", 0 );
+
+ return;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+bool winbindd_can_contact_domain(struct winbindd_domain *domain)
+{
+ struct winbindd_tdc_domain *tdc = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+ bool ret = false;
+
+ /* We can contact the domain if it is our primary domain */
+
+ if (domain->primary) {
+ return true;
+ }
+
+ /* Trust the TDC cache and not the winbindd_domain flags */
+
+ if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
+ DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
+ domain->name));
+ return false;
+ }
+
+ /* Can always contact a domain that is in out forest */
+
+ if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
+ ret = true;
+ goto done;
+ }
+
+ /*
+ * On a _member_ server, we cannot contact the domain if it
+ * is running AD and we have no inbound trust.
+ */
+
+ if (!IS_DC &&
+ domain->active_directory &&
+ ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
+ {
+ DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
+ "and we have no inbound trust.\n", domain->name));
+ goto done;
+ }
+
+ /* Assume everything else is ok (probably not true but what
+ can you do?) */
+
+ ret = true;
+
+done:
+ talloc_destroy(frame);
+
+ return ret;
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+bool winbindd_internal_child(struct winbindd_child *child)
+{
+ if ((child == idmap_child()) || (child == locator_child())) {
+ return True;
+ }
+
+ return False;
+}
+
+#ifdef HAVE_KRB5_LOCATE_PLUGIN_H
+
+/*********************************************************************
+ ********************************************************************/
+
+static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
+{
+ char *var = NULL;
+ char addr[INET6_ADDRSTRLEN];
+ const char *kdc = NULL;
+ int lvl = 11;
+
+ if (!domain || !domain->alt_name || !*domain->alt_name) {
+ return;
+ }
+
+ if (domain->initialized && !domain->active_directory) {
+ DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
+ domain->alt_name));
+ return;
+ }
+
+ print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
+ kdc = addr;
+ if (!*kdc) {
+ DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
+ domain->alt_name));
+ kdc = domain->dcname;
+ }
+
+ if (!kdc || !*kdc) {
+ DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
+ domain->alt_name));
+ return;
+ }
+
+ if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
+ domain->alt_name) == -1) {
+ return;
+ }
+
+ DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
+ var, kdc));
+
+ setenv(var, kdc, 1);
+ free(var);
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
+{
+ struct winbindd_domain *our_dom = find_our_domain();
+
+ winbindd_set_locator_kdc_env(domain);
+
+ if (domain != our_dom) {
+ winbindd_set_locator_kdc_env(our_dom);
+ }
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
+{
+ char *var = NULL;
+
+ if (!domain || !domain->alt_name || !*domain->alt_name) {
+ return;
+ }
+
+ if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
+ domain->alt_name) == -1) {
+ return;
+ }
+
+ unsetenv(var);
+ free(var);
+}
+#else
+
+void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
+{
+ return;
+}
+
+void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
+{
+ return;
+}
+
+#endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
+
+void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
+{
+ resp->data.auth.nt_status = NT_STATUS_V(result);
+ fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
+
+ /* we might have given a more useful error above */
+ if (*resp->data.auth.error_string == '\0')
+ fstrcpy(resp->data.auth.error_string,
+ get_friendly_nt_error_msg(result));
+ resp->data.auth.pam_error = nt_status_to_pam(result);
+}
diff --git a/source3/winbindd/winbindd_wins.c b/source3/winbindd/winbindd_wins.c
new file mode 100644
index 0000000000..4a3d2682b6
--- /dev/null
+++ b/source3/winbindd/winbindd_wins.c
@@ -0,0 +1,241 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon - WINS related functions
+
+ Copyright (C) Andrew Tridgell 1999
+ Copyright (C) Herb Lewis 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+/* Use our own create socket code so we don't recurse.... */
+
+static int wins_lookup_open_socket_in(void)
+{
+ struct sockaddr_in sock;
+ int val=1;
+ int res;
+
+ memset((char *)&sock,'\0',sizeof(sock));
+
+#ifdef HAVE_SOCK_SIN_LEN
+ sock.sin_len = sizeof(sock);
+#endif
+ sock.sin_port = 0;
+ sock.sin_family = AF_INET;
+ sock.sin_addr.s_addr = interpret_addr("0.0.0.0");
+ res = socket(AF_INET, SOCK_DGRAM, 0);
+ if (res == -1)
+ return -1;
+
+ setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val));
+#ifdef SO_REUSEPORT
+ setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val));
+#endif /* SO_REUSEPORT */
+
+ /* now we've got a socket - we need to bind it */
+
+ if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) {
+ close(res);
+ return(-1);
+ }
+
+ set_socket_options(res,"SO_BROADCAST");
+
+ return res;
+}
+
+
+static NODE_STATUS_STRUCT *lookup_byaddr_backend(const char *addr, int *count)
+{
+ int fd;
+ struct sockaddr_storage ss;
+ struct nmb_name nname;
+ NODE_STATUS_STRUCT *status;
+
+ fd = wins_lookup_open_socket_in();
+ if (fd == -1)
+ return NULL;
+
+ make_nmb_name(&nname, "*", 0);
+ if (!interpret_string_addr(&ss, addr, AI_NUMERICHOST)) {
+ return NULL;
+ }
+ status = node_status_query(fd, &nname, &ss, count, NULL);
+
+ close(fd);
+ return status;
+}
+
+static struct sockaddr_storage *lookup_byname_backend(const char *name,
+ int *count)
+{
+ int fd;
+ struct ip_service *ret = NULL;
+ struct sockaddr_storage *return_ss = NULL;
+ int j, i, flags = 0;
+
+ *count = 0;
+
+ /* always try with wins first */
+ if (NT_STATUS_IS_OK(resolve_wins(name,0x20,&ret,count))) {
+ if ( *count == 0 )
+ return NULL;
+ if ( (return_ss = SMB_MALLOC_ARRAY(struct sockaddr_storage, *count)) == NULL ) {
+ free( ret );
+ return NULL;
+ }
+
+ /* copy the IP addresses */
+ for ( i=0; i<(*count); i++ )
+ return_ss[i] = ret[i].ss;
+
+ free( ret );
+ return return_ss;
+ }
+
+ fd = wins_lookup_open_socket_in();
+ if (fd == -1) {
+ return NULL;
+ }
+
+ /* uggh, we have to broadcast to each interface in turn */
+ for (j=iface_count() - 1;
+ j >= 0;
+ j--) {
+ const struct sockaddr_storage *bcast_ss = iface_n_bcast(j);
+ if (!bcast_ss) {
+ continue;
+ }
+ return_ss = name_query(fd,name,0x20,True,True,bcast_ss,count, &flags, NULL);
+ if (return_ss) {
+ break;
+ }
+ }
+
+ close(fd);
+ return return_ss;
+}
+
+/* Get hostname from IP */
+
+void winbindd_wins_byip(struct winbindd_cli_state *state)
+{
+ fstring response;
+ int i, count, maxlen, size;
+ NODE_STATUS_STRUCT *status;
+
+ /* Ensure null termination */
+ state->request.data.winsreq[sizeof(state->request.data.winsreq)-1]='\0';
+
+ DEBUG(3, ("[%5lu]: wins_byip %s\n", (unsigned long)state->pid,
+ state->request.data.winsreq));
+
+ *response = '\0';
+ maxlen = sizeof(response) - 1;
+
+ if ((status = lookup_byaddr_backend(state->request.data.winsreq, &count))){
+ size = strlen(state->request.data.winsreq);
+ if (size > maxlen) {
+ SAFE_FREE(status);
+ request_error(state);
+ return;
+ }
+ fstrcat(response,state->request.data.winsreq);
+ fstrcat(response,"\t");
+ for (i = 0; i < count; i++) {
+ /* ignore group names */
+ if (status[i].flags & 0x80) continue;
+ if (status[i].type == 0x20) {
+ size = sizeof(status[i].name) + strlen(response);
+ if (size > maxlen) {
+ SAFE_FREE(status);
+ request_error(state);
+ return;
+ }
+ fstrcat(response, status[i].name);
+ fstrcat(response, " ");
+ }
+ }
+ /* make last character a newline */
+ response[strlen(response)-1] = '\n';
+ SAFE_FREE(status);
+ }
+ fstrcpy(state->response.data.winsresp,response);
+ request_ok(state);
+}
+
+/* Get IP from hostname */
+
+void winbindd_wins_byname(struct winbindd_cli_state *state)
+{
+ struct sockaddr_storage *ip_list = NULL;
+ int i, count, maxlen, size;
+ fstring response;
+ char addr[INET6_ADDRSTRLEN];
+
+ /* Ensure null termination */
+ state->request.data.winsreq[sizeof(state->request.data.winsreq)-1]='\0';
+
+ DEBUG(3, ("[%5lu]: wins_byname %s\n", (unsigned long)state->pid,
+ state->request.data.winsreq));
+
+ *response = '\0';
+ maxlen = sizeof(response) - 1;
+
+ if ((ip_list = lookup_byname_backend(state->request.data.winsreq,&count))){
+ for (i = count; i ; i--) {
+ print_sockaddr(addr, sizeof(addr), &ip_list[i-1]);
+ size = strlen(addr);
+ if (size > maxlen) {
+ SAFE_FREE(ip_list);
+ request_error(state);
+ return;
+ }
+ if (i != 0) {
+ /* Clear out the newline character */
+ /* But only if there is something in there,
+ otherwise we clobber something in the stack */
+ if (strlen(response)) {
+ response[strlen(response)-1] = ' ';
+ }
+ }
+ fstrcat(response,addr);
+ fstrcat(response,"\t");
+ }
+ size = strlen(state->request.data.winsreq) + strlen(response);
+ if (size > maxlen) {
+ SAFE_FREE(ip_list);
+ request_error(state);
+ return;
+ }
+ fstrcat(response,state->request.data.winsreq);
+ fstrcat(response,"\n");
+ SAFE_FREE(ip_list);
+ } else {
+ request_error(state);
+ return;
+ }
+
+ fstrcpy(state->response.data.winsresp,response);
+
+ request_ok(state);
+}